diff --git a/.cmake-format.py b/.cmake-format.py index 414a8b9870ddb..9827eecd329c4 100644 --- a/.cmake-format.py +++ b/.cmake-format.py @@ -85,12 +85,9 @@ "DESTINATION": '*', } }, - "o2_add_test_wrapper": { - "flags": ["DONT_FAIL_ON_TIMEOUT", "NON_FATAL"], + "o2_add_test_command": { "kwargs": { "COMMAND": '*', - "NO_BOOST_TEST": '*', - "MAX_ATTEMPTS": '*', "TIMEOUT": '*', "NAME": '*', "WORKING_DIRECTORY": '*', @@ -104,9 +101,7 @@ "kwargs": { "INSTALL": '*', "NO_BOOST_TEST": '*', - "NON_FATAL": '*', "COMPONENT_NAME": '*', - "MAX_ATTEMPTS": '*', "TIMEOUT": '*', "WORKING_DIRECTORY": '*', "SOURCES": '*', @@ -117,10 +112,11 @@ } }, "o2_add_test_root_macro": { - "flags": ["NON_FATAL", "LOAD_ONLY"], + "flags": ["COMPILE","COMPILE_ONLY"], "kwargs": { "ENVIRONMENT": '*', "PUBLIC_LINK_LIBRARIES": '*', + "PUBLIC_INCLUDE_DIRECTORIES": '*', "LABELS": '*', } }, diff --git a/.github/workflows/clean-test.yml b/.github/workflows/clean-test.yml index 69b73d51ab3d5..de59435a9a34a 100644 --- a/.github/workflows/clean-test.yml +++ b/.github/workflows/clean-test.yml @@ -8,7 +8,7 @@ on: checks: description: Checks to be cleaned required: true - default: 'build/O2/o2,build/O2/gpu,build/AliceO2/O2/o2/macOS,build/o2checkcode/o2' + default: 'build/O2/o2,build/AliceO2/O2/o2/macOS,build/O2/fullCI,build/O2/o2-cs8,build/O2/o2-dataflow,build/O2/o2-dataflow-cs8' owner: description: Organization required: true @@ -28,7 +28,8 @@ jobs: python-version: 3.7 - name: Install ali-bot run: | - sudo apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev + sudo apt-get update -y + sudo apt-get install -y libsasl2-dev python-dev libldap2-dev libssl-dev python -m pip install --upgrade pip pip install git+https://github.com/alisw/ali-bot@master - uses: octokit/graphql-action@v2.x diff --git a/.github/workflows/code-formatting.yml b/.github/workflows/code-formatting.yml index d663eac1a2fae..9ed7d01b9cae5 100644 --- a/.github/workflows/code-formatting.yml +++ b/.github/workflows/code-formatting.yml @@ -4,7 +4,8 @@ on: [pull_request_target] jobs: build: - runs-on: ubuntu-latest + # We need at least 20.04 to install clang-format-11. + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -15,6 +16,16 @@ jobs: # diverged. We're fetching everything here, as we don't know how many # commits back that point is. fetch-depth: 0 + + - name: Install prerequisites + env: + DEBIAN_FRONTEND: noninteractive + run: | + sudo apt update -y + sudo apt install -y clang-format-11 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-11 100 + sudo update-alternatives --install /usr/bin/git-clang-format git-clang-format /usr/bin/git-clang-format-11 100 + - name: Run clang format id: clang_format env: @@ -22,8 +33,8 @@ jobs: run: | set -x # We need to fetch the other commit. - git fetch origin ${{ github.event.pull_request.base.ref }} - git fetch origin pull/${{ github.event.pull_request.number }}/head:${{ github.event.pull_request.head.ref }} + git fetch origin ${{ github.event.pull_request.base.ref }} \ + pull/${{ github.event.pull_request.number }}/head:${{ github.event.pull_request.head.ref }} # We create a new branch which we will use for the eventual PR. git config --global user.email "alibuild@cern.ch" @@ -35,40 +46,32 @@ jobs: # that, we need to find the latest common ancestor between the PR and # the branch we are merging into. BASE_COMMIT=$(git merge-base HEAD ${{ github.event.pull_request.base.sha }}) - echo "Running clang-format-8 against branch ${{ github.event.pull_request.base.ref }} , with hash ${{ github.event.pull_request.base.sha }}" - COMMIT_FILES=$(git diff --name-only $BASE_COMMIT | grep -ivE 'LinkDef|Utilities/PCG/') - RESULT_OUTPUT="$(git-clang-format-8 --commit $BASE_COMMIT --diff --binary `which clang-format-8` $COMMIT_FILES)" + echo "Running clang-format against branch ${{ github.event.pull_request.base.ref }}, with hash ${{ github.event.pull_request.base.sha }}" + COMMIT_FILES=$(git diff --diff-filter d --name-only $BASE_COMMIT | grep -ivE 'LinkDef|Utilities/PCG/') + [ "X$COMMIT_FILES" = X ] && { echo "No files to check" ; exit 0; } + RESULT_OUTPUT="$(git-clang-format --commit $BASE_COMMIT --diff --style file $COMMIT_FILES)" for x in $COMMIT_FILES; do case $x in - # *.h|*.cxx) - # We remove the header from the diff as it contains +++ then - # we only select the added lines to check for the long ones. - # We do not need to check for the lines which have been removed - # and we do not want to check for the lines which were not changed - # to avoid extra work. - # 120 characters are allowed, meaning the error should start with 122, - # to allow for the starting + at the end of the line. - # Disabled for now, since people don't like the convention. - # git diff $BASE_COMMIT $x | tail -n +6 | grep -e '^+' | grep '.\{122,\}' && { echo "Line longer than 120 chars in $x." && exit 1; } || true ;; *.hxx|*.cc|*.hpp) echo "$x uses non-allowed extension." && exit 1 ;; *) ;; esac done - if [ "$RESULT_OUTPUT" == "no modified files to format" ] \ - || [ "$RESULT_OUTPUT" == "clang-format did not modify any files" ] ; then + if [ "$RESULT_OUTPUT" == 'no modified files to format' ] || + [ "$RESULT_OUTPUT" == 'clang-format did not modify any files' ] + then echo "clang-format passed." git push --set-upstream https://alibuild:$ALIBUILD_GITHUB_TOKEN@github.com/alibuild/AliceO2.git :alibot-cleanup-${{ github.event.pull_request.number }} -f || true echo ::set-output name=clean::true else - git-clang-format-8 --commit $BASE_COMMIT \ - --diff --binary `which \ - clang-format-8` $COMMIT_FILES | patch -p1 + git-clang-format --diff --commit $BASE_COMMIT --style file $COMMIT_FILES | + patch -p1 echo "clang-format failed." echo "To reproduce it locally please run" - echo -e "\tgit checkout $TRAVIS_BRANCH" - echo -e "\tgit-clang-format --commit $BASE_COMMIT --diff --binary $(which clang-format)" + echo -e "\tgit checkout ${{ github.event.pull_request.head.ref }}" + echo -e "\tgit-clang-format --commit $BASE_COMMIT --diff --style file" + echo "Note: using clang-format version $(clang-format --version)" echo "Opening a PR to your branch with the fixes" git commit -m "Please consider the following formatting changes" -a git show | cat @@ -81,7 +84,7 @@ jobs: uses: alisw/pull-request@master with: source_branch: 'alibuild:alibot-cleanup-${{ github.event.pull_request.number }}' - destination_branch: '${{ github.event.pull_request.user.login }}:${{ github.event.pull_request.head.ref }}' + destination_branch: '${{ github.event.pull_request.head.label }}' github_token: ${{ secrets.ALIBUILD_GITHUB_TOKEN }} pr_title: "Please consider the following formatting changes to #${{ github.event.pull_request.number }}" pr_body: | diff --git a/.github/workflows/datamodel-doc.yml b/.github/workflows/datamodel-doc.yml new file mode 100644 index 0000000000000..778985692a2de --- /dev/null +++ b/.github/workflows/datamodel-doc.yml @@ -0,0 +1,75 @@ +name: Rebuild data model documentation +on: + workflow_dispatch: + schedule: + - cron: '17 1 * * *' # 01:17 every night +jobs: + datamodel-doc: + runs-on: ubuntu-latest + if: github.repository == 'AliceO2Group/AliceO2' + steps: + + - name: Checkout O2 + uses: actions/checkout@v2 + with: + path: O2 + persist-credentials: false + + - name: Checkout O2Physics + uses: actions/checkout@v2 + with: + repository: AliceO2Group/O2Physics + path: O2Physics + persist-credentials: false + + - name: Checkout documentation + uses: actions/checkout@v2 + with: + repository: AliceO2Group/analysis-framework + path: analysis-framework + persist-credentials: false + # To push the updated branch, we need a non-shallow clone. + fetch-depth: 0 + + - name: Create PR branch in docs + working-directory: analysis-framework + run: | + git config --global user.email 'alibuild@cern.ch' + git config --global user.name 'ALICE Action Bot' + # Overwrite branch, creating a new one based on HEAD + git checkout -B auto-datamodel-doc + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Install prerequisites + run: | + python3 -m pip install --user -U numpy nltk + python3 -m nltk.downloader -d ~/nltk_data punkt + + - name: Generate documentation + run: exec bash -eo pipefail O2/scripts/datamodel-doc/update-datamodel.sh + + - name: Send pull request with updated docs + env: + GITHUB_TOKEN: ${{ secrets.ALIBUILD_GITHUB_TOKEN }} + working-directory: analysis-framework/docs/datamodel + run: | + # git diff --quiet exits with 1 if any tracked files have changed, and + # with 0 otherwise. + if git diff --quiet; then + exit # Nothing has changed, so no need to send a PR. + fi + git add ao2dTables.md helperTaskTables.md joinsAndIterators.md + git commit -m 'Automatic data model update' + git remote set-url origin "https://alibuild:$GITHUB_TOKEN@github.com/alibuild/analysis-framework" + git push -f origin auto-datamodel-doc + + # Send pull request + # We need to use "hub" ourselves because alisw/pull-request gets + # confused when multiple repos are checked out. + hub pull-request -b AliceO2Group:master -h alibuild:auto-datamodel-doc \ + --no-edit --no-maintainer-edits -m 'Automatic data model update' \ + -m "This update to the data model documentation was automatically created from tonight's O2 dev branch." diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml new file mode 100644 index 0000000000000..5cd4f583d275c --- /dev/null +++ b/.github/workflows/doxygen.yml @@ -0,0 +1,31 @@ +name: Build Documentation + +on: + push: + branches: + - 'dev' + workflow_dispatch: +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install doxygen + run: | + sudo apt-get update -y + sudo apt-get install -y doxygen doxygen-doc doxygen-latex doxygen-gui graphviz cmake + - uses: actions/checkout@v2 + with: + ref: "dev" + - name: Install doxygen + run: | + cat > CMakeLists.txt <<\EOF + add_subdirectory(doc) + EOF + cmake . + make doc + git add doc/html + git config --global user.email "github-action-bot@example.com" + git config --global user.name "GitHub Action Bot" + git commit -m "Updated README" -a || echo "No changes to commit" + git push origin `git subtree split --prefix doc/html dev`:refs/heads/gh-pages --force + diff --git a/.github/workflows/pragmaonce.yml b/.github/workflows/pragmaonce.yml new file mode 100644 index 0000000000000..574d41aeb4b57 --- /dev/null +++ b/.github/workflows/pragmaonce.yml @@ -0,0 +1,18 @@ +name: pragma-once checker + +on: [pull_request_target] + +jobs: + build: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - name: Run pragma check + id: pragma_check + run: | + git --no-pager grep -l '#pragma once' -- '*.h' && exit 1 || exit 0 diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml new file mode 100644 index 0000000000000..bf7347464476e --- /dev/null +++ b/.github/workflows/reports.yml @@ -0,0 +1,137 @@ +name: Automatically create CHANGELOG for O2 releases + +on: + push: + workflow_dispatch: + inputs: + LAST_RELEASE_DATE: + description: 'Time of the last release' + required: true + default: '' + schedule: + - cron: '0 0 * * *' + +jobs: + build: + runs-on: macOS-latest + if: github.repository == 'AliceO2Group/AliceO2' + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - uses: actions/cache@v2 + name: Configure pip caching + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - uses: octokit/graphql-action@v2.x + id: get_latest_o2_releases + with: + query: | + { + repository(name: "AliceO2", owner: "AliceO2Group") { + releases(last:14) { + edges { + node { + tagName + publishedAt + } + } + } + } + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: octokit/graphql-action@v2.x + id: get_latest_o2_prs + with: + query: | + { + repository(name: "AliceO2", owner: "AliceO2Group") { + pullRequests(last: 100) { + edges { + node { + state + mergedAt + title + number + author { + login + } + files(last: 100) { + edges { + node { + path + } + } + } + } + } + } + } + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Update Changelog + run: | + set -x + mkdir -p doc/data + # We create new files once per month, mostly so that + # we can keep the query results small. It does not + # matter if we get results from different months, + # as what matters is how we merge them. + CURRENT_MONTH=`date +%Y-%m` + cat <<\EOF > doc/data/${CURRENT_MONTH}-o2_releases.json + ${{ steps.get_latest_o2_releases.outputs.data }} + EOF + cat <<\EOF > doc/data/${CURRENT_MONTH}-o2_prs.json + ${{ steps.get_latest_o2_prs.outputs.data }} + EOF + # FIXME: this should really be one second after the last release + # being published + LAST_RELEASE="${{ github.event.inputs.LAST_RELEASE_DATE }}" + MERGED_AFTER=${LAST_RELEASE:-$(date -v -14d +%Y-%m-%d)} + + # Here we convert all the json files to per subsystem + # logs, using the MERGED_AFTER date to further filter them. + # Notice we can have duplicates in each file, + # as they will be removed in the next iteration. + # FIXME: it's probably enough to iterate on the last two + # months, at least for bi-weekly releases. + for f in doc/data/*_prs.json; do + for x in Algorithm Analysis Common DataFormats Detectors EventVisualisation Examples Framework Generators Steer Testing Utilities; do + cat $f | jq ".repository.pullRequests.edges[].node | select(.files.edges[].node.path | test(\"$x\")) | del(.files) | select(.state == \"MERGED\" and .mergedAt >= \"${MERGED_AFTER}\")" > /tmp/${x}_prs.json + if [ ! X`jq -s length /tmp/${x}_prs.json` = X0 ]; then + cat /tmp/${x}_prs.json | jq -r '"- [#\(.number)](https://github.com/AliceO2Group/AliceO2/pull/\(.number)) \(.mergedAt | split("T")[0]): \(.title) by [@\(.author.login)](https://github.com/\(.author.login))"' | sort -u >> /tmp/${x}_prs.md + fi + done + done + # Here we do the merging by iterating on the subsystems adding + # an header for each and removing the duplicates. + printf "# Changes since ${MERGED_AFTER}\n\n" > CHANGELOG.md + for x in Algorithm Analysis Common DataFormats Detectors EventVisualisation Examples Framework Generators Steer Testing Utilities; do + [ ! -f /tmp/${x}_prs.md ] && continue + printf "## Changes in $x\n\n" >> CHANGELOG.md + cat /tmp/${x}_prs.md | sort -k3 | uniq >> CHANGELOG.md + done + - name: Commit and push if changed + run: |- + git add CHANGELOG.md doc/data + git diff + git config --global user.email "github-action-bot@example.com" + git config --global user.name "GitHub Action Bot" + git commit -m "Updated README" -a || echo "No changes to commit" + git push origin HEAD:changelog -f + GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \ + hub pull-request -f -b dev -h changelog \ + --no-edit --no-maintainer-edits \ + 'Auto-generated changelog' \ + -m 'The following changelog has been automatically generated.' || + # If the PR already exists, the force-push will have updated it. + # It's fine if this step fails. + true diff --git a/.github/workflows/space-checker.yml b/.github/workflows/space-checker.yml new file mode 100644 index 0000000000000..d7eb91329fc91 --- /dev/null +++ b/.github/workflows/space-checker.yml @@ -0,0 +1,62 @@ +# Find bad spacing in modified text files +name: Space checker +on: [push, pull_request_target] +env: + MAIN_BRANCH: dev +jobs: + build: + name: Space checker + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v2 + with: + fetch-depth: 0 # needed to get the full history + - name: Fetch upstream + run: | + # Fetch the main upstream branch to find the common ancestor + git config --global user.name "Nemo" # required on some servers + git remote add upstream https://github.com/AliceO2Group/AliceO2.git || exit 1 + git fetch upstream ${{ env.MAIN_BRANCH }} || exit 1 + - name: Find bad spacing + run: | + # Find tabs and trailing whitespaces in modified text files and show where they are + status_tab=0 + status_trail=0 + # Get the common ancestor of the current branch and the main upstream branch + BASE_COMMIT=$(git merge-base HEAD upstream/${{ env.MAIN_BRANCH }}) + echo "Diffing against: $BASE_COMMIT" + # loop over changed files + for f in $(git diff --diff-filter d --name-only $BASE_COMMIT); do + # ignore binary files + file -bi "$f" | grep -q "charset=binary" && continue + echo "Scanning file: $f" + # find tabs + if grep -q -P "\t" "$f"; then + status_tab=1 + echo "::error::Found some tabs:" + # print out where they are + #grep -P -n "\t" "$f" + awk 'i=index($0, "\t") {printf "%i (col. %i): %s\n", NR, i, $0}' "$f" + fi + # find trailing whitespaces + if grep -q " $" "$f"; then + status_trail=2 + echo "::error::Found some trailing whitespaces:" + # print out where they are + grep -n " $" "$f" + fi + done + status=$((status_tab + status_trail)) + if [ "$status" -ne 0 ]; then + echo "::warning::Fix the errors in your editor (or with a command) + Command tips: + - Get list of files you changed: git diff --diff-filter d --name-only \$(git merge-base HEAD upstream/${{ env.MAIN_BRANCH }}) + - Replace each tab with two spaces: sed -i 's/\t/ /g' + - Remove trailing whitespaces: sed -i 's/[[:space:]]*$//' " + echo "::warning::To avoid these errors, configure your editor to: + - Emit spaces when the Tab key is pressed. + - Display whitespace characters. + - Replace tabs with spaces and remove trailing whitespaces when a file is saved." + fi + exit $status diff --git a/.gitignore b/.gitignore index ff8b7c86c8974..e9d377a557f4e 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ xbuild/ # common editor backups *.swp *~ +\#*\# # doxygen stuff html-doc/ @@ -53,7 +54,9 @@ cmake_install.cmake compile_commands.json # IDEs files +.cache .cproject +.devcontainer* .project .idea .settings diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0616499ab1d76..0000000000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -sudo: false -matrix: - fast_finish: true - # Note: Workaround travis-ci/travis-ci#4681 - # Exclude default job which lacks our included environment variables. - exclude: - - os: linux - - env: - include: - - os: linux - dist: bionic - env: JOB=doxygen - addons: - apt: - packages: - - doxygen - - doxygen-doc - - doxygen-latex - - doxygen-gui - - graphviz - - cmake - script: | - cat > CMakeLists.txt <<\EOF - add_subdirectory(doc) - EOF - cmake . - make doc - deploy: - provider: pages - skip_cleanup: true - github_token: $GITHUB_API_TOKEN # Set in travis-ci.org dashboard - local_dir: doc/html - on: - branch: dev diff --git a/Algorithm/CMakeLists.txt b/Algorithm/CMakeLists.txt index f4eb38fe1989a..b245562c7cc93 100644 --- a/Algorithm/CMakeLists.txt +++ b/Algorithm/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(Algorithm INTERFACE_LINK_LIBRARIES O2::Headers) diff --git a/Algorithm/include/Algorithm/BitstreamReader.h b/Algorithm/include/Algorithm/BitstreamReader.h index 24df5966bfdd7..0a112183ab5ef 100644 --- a/Algorithm/include/Algorithm/BitstreamReader.h +++ b/Algorithm/include/Algorithm/BitstreamReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/FlattenRestore.h b/Algorithm/include/Algorithm/FlattenRestore.h index 83f071ff437c9..a039a897a191c 100644 --- a/Algorithm/include/Algorithm/FlattenRestore.h +++ b/Algorithm/include/Algorithm/FlattenRestore.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/HeaderStack.h b/Algorithm/include/Algorithm/HeaderStack.h index 1af452d51d2b6..a5029228969ef 100644 --- a/Algorithm/include/Algorithm/HeaderStack.h +++ b/Algorithm/include/Algorithm/HeaderStack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/O2FormatParser.h b/Algorithm/include/Algorithm/O2FormatParser.h index a75d98ae43025..d0d820391a331 100644 --- a/Algorithm/include/Algorithm/O2FormatParser.h +++ b/Algorithm/include/Algorithm/O2FormatParser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/PageParser.h b/Algorithm/include/Algorithm/PageParser.h index 9fde7d473173a..df1033d7711ea 100644 --- a/Algorithm/include/Algorithm/PageParser.h +++ b/Algorithm/include/Algorithm/PageParser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/Parser.h b/Algorithm/include/Algorithm/Parser.h index 43ec4daa90aec..a2a7468621b4c 100644 --- a/Algorithm/include/Algorithm/Parser.h +++ b/Algorithm/include/Algorithm/Parser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/RangeTokenizer.h b/Algorithm/include/Algorithm/RangeTokenizer.h index 38c481792ff5e..e256794ea53e8 100644 --- a/Algorithm/include/Algorithm/RangeTokenizer.h +++ b/Algorithm/include/Algorithm/RangeTokenizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/include/Algorithm/TableView.h b/Algorithm/include/Algorithm/TableView.h index 462a5ef74d74c..36980e64d1bc9 100644 --- a/Algorithm/include/Algorithm/TableView.h +++ b/Algorithm/include/Algorithm/TableView.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -79,7 +80,7 @@ class TableView /// descriptor pointing to payload of one frame struct FrameData { - const byte* buffer = nullptr; + const std::byte* buffer = nullptr; size_t size = 0; }; @@ -94,7 +95,7 @@ class TableView * @param seqSize Length of sequence * @return number of inserted elements */ - size_t addRow(RowDescType rowData, byte* seqData, size_t seqSize) + size_t addRow(RowDescType rowData, std::byte* seqData, size_t seqSize) { unsigned nFrames = mFrames.size(); unsigned currentRow = mRowData.size(); @@ -118,7 +119,7 @@ class TableView // insert frame descriptor under key composed from header and row auto result = mFrames.emplace(FrameIndex{*entry.header, currentRow}, - FrameData{entry.payload, entry.length}); + FrameData{(std::byte*)entry.payload, entry.length}); return result.second; }); auto insertedFrames = mFrames.size() - nFrames; diff --git a/Algorithm/include/Algorithm/mpl_tools.h b/Algorithm/include/Algorithm/mpl_tools.h index fb549b335ec64..19566ac036a44 100644 --- a/Algorithm/include/Algorithm/mpl_tools.h +++ b/Algorithm/include/Algorithm/mpl_tools.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/StaticSequenceAllocator.h b/Algorithm/test/StaticSequenceAllocator.h index 3b4b3ba04754b..8a684159afdb9 100644 --- a/Algorithm/test/StaticSequenceAllocator.h +++ b/Algorithm/test/StaticSequenceAllocator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/headerstack.cxx b/Algorithm/test/headerstack.cxx index 103b5d5e1e5ae..62d877763a63b 100644 --- a/Algorithm/test/headerstack.cxx +++ b/Algorithm/test/headerstack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/o2formatparser.cxx b/Algorithm/test/o2formatparser.cxx index a5ce2e10c3e0c..2896631ebc5b8 100644 --- a/Algorithm/test/o2formatparser.cxx +++ b/Algorithm/test/o2formatparser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/pageparser.cxx b/Algorithm/test/pageparser.cxx index a7b03ecb36816..14b24c670cfd6 100644 --- a/Algorithm/test/pageparser.cxx +++ b/Algorithm/test/pageparser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/parser.cxx b/Algorithm/test/parser.cxx index e8d962716f656..f4f7fefe3aace 100644 --- a/Algorithm/test/parser.cxx +++ b/Algorithm/test/parser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/tableview.cxx b/Algorithm/test/tableview.cxx index 9be76a92bcfb3..c303d531b541e 100644 --- a/Algorithm/test/tableview.cxx +++ b/Algorithm/test/tableview.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -78,8 +79,8 @@ BOOST_AUTO_TEST_CASE(test_tableview_reverse) dh2.subSpecification = 0xdeadbeef; dh2.payloadSize = 0; - heartbeatview.addRow(dh1, tf1.buffer.get(), tf1.size()); - heartbeatview.addRow(dh2, tf2.buffer.get(), tf2.size()); + heartbeatview.addRow(dh1, (std::byte*)tf1.buffer.get(), tf1.size()); + heartbeatview.addRow(dh2, (std::byte*)tf2.buffer.get(), tf2.size()); std::cout << "slots: " << heartbeatview.getNRows() << " columns: " << heartbeatview.getNColumns() @@ -145,7 +146,7 @@ BOOST_AUTO_TEST_CASE(test_tableview_formaterror) dh.subSpecification = 0; dh.payloadSize = 0; - heartbeatview.addRow(dh, tf1.buffer.get(), tf1.size()); + heartbeatview.addRow(dh, (std::byte*)tf1.buffer.get(), tf1.size()); BOOST_CHECK(heartbeatview.getNRows() == 0); BOOST_CHECK(heartbeatview.getNColumns() == 0); diff --git a/Algorithm/test/test_BitstreamReader.cxx b/Algorithm/test/test_BitstreamReader.cxx index d47cd13edd54d..41e3b47f5f276 100644 --- a/Algorithm/test/test_BitstreamReader.cxx +++ b/Algorithm/test/test_BitstreamReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/test_FlattenRestore.cxx b/Algorithm/test/test_FlattenRestore.cxx index 311b03c355322..98f5f30393e41 100644 --- a/Algorithm/test/test_FlattenRestore.cxx +++ b/Algorithm/test/test_FlattenRestore.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/test_RangeTokenizer.cxx b/Algorithm/test/test_RangeTokenizer.cxx index e0032dd92aa0a..2583b52159b5f 100644 --- a/Algorithm/test/test_RangeTokenizer.cxx +++ b/Algorithm/test/test_RangeTokenizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Algorithm/test/test_mpl_tools.cxx b/Algorithm/test/test_mpl_tools.cxx index 422445af1205d..e3f1b640b7ca1 100644 --- a/Algorithm/test/test_mpl_tools.cxx +++ b/Algorithm/test/test_mpl_tools.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Analysis/CMakeLists.txt b/Analysis/CMakeLists.txt deleted file mode 100644 index 5f5ec9b76515e..0000000000000 --- a/Analysis/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -add_subdirectory(Core) -add_subdirectory(DataModel) -add_subdirectory(Tasks) -add_subdirectory(Tutorials) diff --git a/Analysis/Core/CMakeLists.txt b/Analysis/Core/CMakeLists.txt deleted file mode 100644 index 63d608698c184..0000000000000 --- a/Analysis/Core/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(AnalysisCore - SOURCES src/CorrelationContainer.cxx - src/TrackSelection.cxx - src/VarManager.cxx - src/HistogramManager.cxx - src/AnalysisCut.cxx - src/AnalysisCompositeCut.cxx - src/TriggerAliases.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisTools) - -o2_target_root_dictionary(AnalysisCore - HEADERS include/Analysis/CorrelationContainer.h - include/Analysis/TrackSelection.h - include/Analysis/TrackSelectionDefaults.h - include/Analysis/VarManager.h - include/Analysis/HistogramManager.h - include/Analysis/AnalysisCut.h - include/Analysis/AnalysisCompositeCut.h - include/Analysis/TriggerAliases.h - include/Analysis/MC.h - LINKDEF src/AnalysisCoreLinkDef.h) - -if(FastJet_FOUND) -o2_add_library(AnalysisJets - SOURCES src/JetFinder.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisCore FastJet::FastJet FastJet::Contrib) - -o2_target_root_dictionary(AnalysisJets - HEADERS include/Analysis/JetFinder.h - LINKDEF src/AnalysisJetsLinkDef.h) -endif() diff --git a/Analysis/Core/include/Analysis/AnalysisCompositeCut.h b/Analysis/Core/include/Analysis/AnalysisCompositeCut.h deleted file mode 100644 index d794179a394dc..0000000000000 --- a/Analysis/Core/include/Analysis/AnalysisCompositeCut.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -// Cut class manipulating groups of cuts -// - -#ifndef AnalysisCompositeCut_H -#define AnalysisCompositeCut_H - -#include "Analysis/AnalysisCut.h" -#include - -//_________________________________________________________________________ -class AnalysisCompositeCut : public AnalysisCut -{ - public: - AnalysisCompositeCut(bool useAND = kTRUE); - AnalysisCompositeCut(const char* name, const char* title, bool useAND = kTRUE); - AnalysisCompositeCut(const AnalysisCompositeCut& c) = default; - AnalysisCompositeCut& operator=(const AnalysisCompositeCut& c) = default; - ~AnalysisCompositeCut() override; - - void AddCut(AnalysisCut* cut) { fCutList.push_back(*cut); }; - - bool GetUseAND() const { return fOptionUseAND; } - int GetNCuts() const { return fCutList.size(); } - - bool IsSelected(float* values) override; - - protected: - bool fOptionUseAND; // true (default): apply AND on all cuts; false: use OR - std::vector fCutList; // list of cuts - - ClassDef(AnalysisCompositeCut, 1); -}; - -#endif diff --git a/Analysis/Core/include/Analysis/AnalysisCut.h b/Analysis/Core/include/Analysis/AnalysisCut.h deleted file mode 100644 index d094e0d6cffe8..0000000000000 --- a/Analysis/Core/include/Analysis/AnalysisCut.h +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -// Class for analysis cuts applied on the variables defined in the VarManager -// - -#ifndef AnalysisCut_H -#define AnalysisCut_H - -#include -#include - -//_________________________________________________________________________ -class AnalysisCut : public TNamed -{ - public: - AnalysisCut() = default; - AnalysisCut(const char* name, const char* title); - AnalysisCut(const AnalysisCut& c) = default; - AnalysisCut& operator=(const AnalysisCut& c); - ~AnalysisCut() override; - - // NOTE: Apply a selection on variable "var" to be in the range [cutLow,cutHigh] or outside this range if "exclude" is set to true - // NOTE: If a dependent variable is specified, then the selection is applied only if the dependent variable is in the range [depCutLow,depCutHigh] - // NOTE: or outside if "depCutExclude" is true - template - void AddCut(int var, T1 cutLow, T2 cutHigh, bool exclude = false, - int dependentVar = -1, float depCutLow = 0., float depCutHigh = 0., bool depCutExclude = false, - int dependentVar2 = -1, float depCut2Low = 0., float depCut2High = 0., bool depCut2Exclude = false); - - virtual bool IsSelected(float* values); - - static std::vector fgUsedVars; //! vector of used variables - - struct CutContainer { - short fVar; // variable to be cut upon - float fLow; // lower limit for the var - float fHigh; // upper limit for the var - bool fExclude; // if true, use the selection range for exclusion - - short fDepVar; // first (optional) variable on which the cut depends - float fDepLow; // lower limit for the first dependent var - float fDepHigh; // upper limit for the first dependent var - bool fDepExclude; // if true, then use the dependent variable range as exclusion - - short fDepVar2; // second (optional) variable on which the cut depends - float fDep2Low; // lower limit for the second dependent var - float fDep2High; // upper limit for the second dependent var - bool fDep2Exclude; // if true, then use the dependent variable range as exclusion - - TF1* fFuncLow; // function for the lower limit cut - TF1* fFuncHigh; // function for the upper limit cut - }; - - protected: - std::vector fCuts; - - ClassDef(AnalysisCut, 1); -}; - -//____________________________________________________________________________ -template -void AnalysisCut::AddCut(int var, T1 cutLow, T2 cutHigh, bool exclude, - int dependentVar, float depCutLow, float depCutHigh, bool depCutExclude, - int dependentVar2, float depCut2Low, float depCut2High, bool depCut2Exclude) -{ - // - // Add a cut - // - CutContainer cut = {}; - - if constexpr (std::is_same_v) { - if (dependentVar < 0) { - return; - } - cut.fFuncLow = cutLow; - cut.fLow = -9999.0; - } else { - cut.fFuncLow = nullptr; - cut.fLow = cutLow; - } - if constexpr (std::is_same_v) { - if (dependentVar < 0) { - return; - } - cut.fFuncHigh = cutHigh; - cut.fHigh = -9999.0; - } else { - cut.fFuncHigh = nullptr; - cut.fHigh = cutHigh; - } - cut.fVar = var; - cut.fExclude = exclude; - fgUsedVars.push_back(var); - - cut.fDepVar = dependentVar; - cut.fDepLow = depCutLow; - cut.fDepHigh = depCutHigh; - cut.fDepExclude = depCutExclude; - if (dependentVar != -1) { - fgUsedVars.push_back(dependentVar); - } - - cut.fDepVar2 = dependentVar2; - cut.fDep2Low = depCut2Low; - cut.fDep2High = depCut2High; - cut.fDep2Exclude = depCut2Exclude; - if (dependentVar2 != -1) { - fgUsedVars.push_back(dependentVar2); - } - - fCuts.push_back(cut); -} - -//____________________________________________________________________________ -inline bool AnalysisCut::IsSelected(float* values) -{ - // - // apply the configured cuts - // - // iterate over cuts - for (std::vector::iterator it = fCuts.begin(); it != fCuts.end(); ++it) { - // check whether a dependent variables were enabled and if they are in the requested range - if ((*it).fDepVar != -1) { - bool inRange = (values[(*it).fDepVar] > (*it).fDepLow && values[(*it).fDepVar] <= (*it).fDepHigh); - if (!inRange && !((*it).fDepExclude)) { - continue; - } - if (inRange && (*it).fDepExclude) { - continue; - } - } - if ((*it).fDepVar2 != -1) { - bool inRange = (values[(*it).fDepVar2] > (*it).fDep2Low && values[(*it).fDepVar2] <= (*it).fDep2High); - if (!inRange && !((*it).fDep2Exclude)) { - continue; - } - if (inRange && (*it).fDep2Exclude) { - continue; - } - } - // obtain the low and high cut values (either directly as a value or from a function) - float cutLow, cutHigh; - if ((*it).fFuncLow) { - cutLow = ((*it).fFuncLow)->Eval(values[(*it).fDepVar]); - } else { - cutLow = ((*it).fLow); - } - if ((*it).fFuncHigh) { - cutHigh = ((*it).fFuncHigh)->Eval(values[(*it).fDepVar]); - } else { - cutHigh = ((*it).fHigh); - } - // apply the cut and return the decision - bool inRange = (values[(*it).fVar] >= cutLow && values[(*it).fVar] <= cutHigh); - if (!inRange && !((*it).fExclude)) { - return false; - } - if (inRange && ((*it).fExclude)) { - return false; - } - } - - return true; -} - -#endif diff --git a/Analysis/Core/include/Analysis/CorrelationContainer.h b/Analysis/Core/include/Analysis/CorrelationContainer.h deleted file mode 100644 index 5591193f104df..0000000000000 --- a/Analysis/Core/include/Analysis/CorrelationContainer.h +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef CorrelationContainer_H -#define CorrelationContainer_H - -// encapsulate histogram and corrections for correlation analysis - -#include "TNamed.h" -#include "TString.h" - -class TH1; -class TH1F; -class TH3; -class TH3F; -class TH2F; -class TH1D; -class TH2; -class TH2D; -class TCollection; -class THnSparse; -class THnBase; -class StepTHn; - -class CorrelationContainer : public TNamed -{ - public: - CorrelationContainer(); - CorrelationContainer(const char* name, const char* objTitle, const char* reqHist = "", const char* binning = nullptr); - virtual ~CorrelationContainer(); // NOLINT: Making this override breaks compilation for unknown reason - - static const Int_t fgkCFSteps; - enum CFStep { kCFStepAll = 0, - kCFStepTriggered, - kCFStepVertex, - kCFStepAnaTopology, - kCFStepTrackedOnlyPrim, - kCFStepTracked, - kCFStepReconstructed, - kCFStepRealLeading, - kCFStepBiasStudy, - kCFStepBiasStudy2, - kCFStepCorrected }; - - const char* getStepTitle(CFStep step); - - StepTHn* getPairHist() { return mPairHist; } - StepTHn* getTriggerHist() { return mTriggerHist; } - StepTHn* getTrackHistEfficiency() { return mTrackHistEfficiency; } - TH2F* getEventCount() { return mEventCount; } - - void setPairHist(StepTHn* hist) { mPairHist = hist; } - void setTriggerHist(StepTHn* hist) { mTriggerHist = hist; } - void setTrackHistEfficiency(StepTHn* hist) { mTrackHistEfficiency = hist; } - - void deepCopy(CorrelationContainer* from); - - void getHistsZVtxMult(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, THnBase** trackHist, TH2** eventHist); - TH2* getPerTriggerYield(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, Bool_t normalizePerTrigger = kTRUE); - TH2* getSumOfRatios(CorrelationContainer* mixed, CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, Bool_t normalizePerTrigger = kTRUE, Int_t stepForMixed = -1, Int_t* trigger = nullptr); - TH1* getTriggersAsFunctionOfMultiplicity(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax); - - TH1* getTrackEfficiency(CFStep step1, CFStep step2, Int_t axis1, Int_t axis2 = -1, Int_t source = 1, Int_t axis3 = -1); - THnBase* getTrackEfficiencyND(CFStep step1, CFStep step2); - TH1* getEventEfficiency(CFStep step1, CFStep step2, Int_t axis1, Int_t axis2 = -1, Float_t ptTriggerMin = -1, Float_t ptTriggerMax = -1); - TH1* getBias(CFStep step1, CFStep step2, const char* axis, Float_t leadPtMin = 0, Float_t leadPtMax = -1, Int_t weighting = 0); - - TH1D* getTrackingEfficiency(Int_t axis); - TH2D* getTrackingEfficiency(); - TH2D* getTrackingEfficiencyCentrality(); - - TH2D* getFakeRate(); - TH1D* getFakeRate(Int_t axis); - - TH1D* getTrackingContamination(Int_t axis); - TH2D* getTrackingContamination(); - TH2D* getTrackingContaminationCentrality(); - - TH1D* getTrackingCorrection(Int_t axis); - TH2D* getTrackingCorrection(); - - TH1D* getTrackingEfficiencyCorrection(Int_t axis); - TH2D* getTrackingEfficiencyCorrection(); - TH2D* getTrackingEfficiencyCorrectionCentrality(); - - void fillEvent(Float_t centrality, CFStep step); - - void extendTrackingEfficiency(Bool_t verbose = kFALSE); - - void setEtaRange(Float_t etaMin, Float_t etaMax) - { - mEtaMin = etaMin; - mEtaMax = etaMax; - } - void setPtRange(Float_t ptMin, Float_t ptMax) - { - mPtMin = ptMin; - mPtMax = ptMax; - } - void setPartSpecies(Int_t species) { mPartSpecies = species; } - void setCentralityRange(Float_t min, Float_t max) - { - mCentralityMin = min; - mCentralityMax = max; - } - void setZVtxRange(Float_t min, Float_t max) - { - mZVtxMin = min; - mZVtxMax = max; - } - void setPt2Min(Float_t ptMin) { mPt2Min = ptMin; } - void setPt2Max(Float_t ptMin) { mPt2Max = ptMin; } - - Float_t getTrackEtaCut() { return mTrackEtaCut; } - void setTrackEtaCut(Float_t value) { mTrackEtaCut = value; } - void setWeightPerEvent(Bool_t flag) { mWeightPerEvent = flag; } - void setSkipScaleMixedEvent(Bool_t flag) { mSkipScaleMixedEvent = flag; } - - void setHistogramType(const char* histogramType) { mHistogramType = histogramType; } - - void countEmptyBins(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax); - void symmetrizepTBins(); - - void setBinLimits(THnBase* grid); - void resetBinLimits(THnBase* grid); - - void setGetMultCache(Bool_t flag = kTRUE) { mGetMultCacheOn = flag; } - - CorrelationContainer(const CorrelationContainer& c); - CorrelationContainer& operator=(const CorrelationContainer& corr); - virtual void Copy(TObject& c) const; // NOLINT: Making this override breaks compilation for unknown reason - - virtual Long64_t Merge(TCollection* list); - //void Scale(Double_t factor); - void Reset(); - THnBase* changeToThn(THnBase* sparse); - - static TString combineBinning(TString defaultBinning, TString customBinning); - - protected: - std::vector getBinning(const char* configuration, const char* tag, Int_t& nBins); - void weightHistogram(TH3* hist1, TH1* hist2); - void multiplyHistograms(THnBase* grid, THnBase* target, TH1* histogram, Int_t var1, Int_t var2); - - StepTHn* mPairHist; // container for pair level distributions at all analysis steps - StepTHn* mTriggerHist; // container for "trigger" particle (single-particle) level distribution at all analysis steps - StepTHn* mTrackHistEfficiency; // container for tracking efficiency and contamination (all particles filled including leading one): axes: eta, pT, particle species - - TH2F* mEventCount; // event count as function of step, (for pp: event type (plus additional step -1 for all events without vertex range even in MC)) (for PbPb: centrality) - - Float_t mEtaMin; // eta min for projections - Float_t mEtaMax; // eta max for projections - Float_t mPtMin; // pT min for projections (for track pT, not pT,lead) - Float_t mPtMax; // pT max for projections (for track pT, not pT,lead) - Int_t mPartSpecies; // Particle species for projections - Float_t mCentralityMin; // centrality min for projections - Float_t mCentralityMax; // centrality max for projections - Float_t mZVtxMin; // z vtx min for projections - Float_t mZVtxMax; // z vtx max for projections - Float_t mPt2Min; // pT min for projections (for pT,2 (only 2+1 corr case)) - Float_t mPt2Max; // pT max for projections (for pT,2 (only 2+1 corr case)) - - Float_t mTrackEtaCut; // cut used during production of histograms (needed for finite bin correction in getSumOfRatios) - Bool_t mWeightPerEvent; // weight with the number of trigger particles per event - Bool_t mSkipScaleMixedEvent; // scale the mixed event with (0, 0) plus finite bin correction (default: kTRUE) - - StepTHn* mCache; //! cache variable for getTrackEfficiency - - Bool_t mGetMultCacheOn; //! cache for getHistsZVtxMult function active - THnBase* mGetMultCache; //! cache for getHistsZVtxMult function - - TString mHistogramType; // what is stored in this histogram - - ClassDef(CorrelationContainer, 1) // underlying event histogram container -}; - -#endif diff --git a/Analysis/Core/include/Analysis/HistHelpers.h b/Analysis/Core/include/Analysis/HistHelpers.h deleted file mode 100644 index f9481876c3cd7..0000000000000 --- a/Analysis/Core/include/Analysis/HistHelpers.h +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Mario Krueger -// -// Some helper templates to simplify working with histograms -// - -#ifndef HistHelpers_H -#define HistHelpers_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Framework/Logger.h" - -namespace o2::experimental::histhelpers -{ - -template -struct is_shared_ptr : std::false_type { -}; -template -struct is_shared_ptr> : std::true_type { -}; - -//************************************************************************************************** -/** - * Container class for storing and saving root histograms of any type. - * RootContainer (TObjArray, TList or TFolder) inheritance is used to interface with O2 file writing functionality. - */ -//************************************************************************************************** -template -class HistContainer : private RootContainer -{ - public: - HistContainer(const std::string& name) : RootContainer() - { - RootContainer::SetOwner(false); // let container handle object deletion - RootContainer::SetName(name.data()); - } - HistContainer(const HistContainer& other) - { - // pseudo copy ctor to move around empty collection on construction (e.g. when put in OutputObj) - // this is needed to make HistContainer also work with TLists since these dont have a copy constructor (as opposed to TObjArrays) - RootContainer::SetOwner(false); - RootContainer::SetName(other.GetName()); - } - - using HistType = std::variant, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr>; - - template - void Add(T&& hist) - { - if (mHistos.find(histID) != mHistos.end()) { - LOGF(WARNING, "HistContainer %s already holds a histogram at histID = %d. Overriding it now...", RootContainer::GetName(), histID); - TObject* oldPtr = nullptr; - std::visit([&](const auto& sharedPtr) { oldPtr = sharedPtr.get(); }, mHistos[histID]); - RootContainer::Remove(oldPtr); - } - // if shared pointers or rvalue raw pointers are provided as argument, the existing object is used - // otherwise the existing object is copied - std::optional histVariant{}; - if constexpr (is_shared_ptr::type>::value) { - histVariant = GetHistVariant(hist); - } else if constexpr (std::is_pointer_v && std::is_rvalue_reference_v(hist))>) { - histVariant = GetHistVariant(std::shared_ptr>(hist)); - } else { - histVariant = GetHistVariant(std::make_shared(hist)); - } - if (histVariant) { - mHistos[histID] = *histVariant; - TObject* rawPtr = nullptr; - std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mHistos[histID]); - RootContainer::Add(rawPtr); - } else { - LOGF(FATAL, "Could not create histogram."); - } - } - - // gets the underlying histogram pointer - // we cannot automatically infer type here so it has to be explicitly specified - // -> Get(), Get(), Get(), Get(), Get(), Get(), Get(), Get() - template - std::shared_ptr Get(uint8_t histID) - { - return *std::get_if>(&mHistos[histID]); - } - - // fill histogram or profile with arguments x,y,z,... and weight if requested - template - void Fill(Ts&&... position) - { - std::visit([this, &position...](auto&& hist) { GenericFill(hist, std::forward(position)...); }, mHistos[histID]); - } - template - void FillWeight(Ts&&... positionAndWeight) - { - Fill(std::forward(positionAndWeight)...); - } - - // make accessible only the RootContainer functions needed for writing to file - using RootContainer::Class; - using RootContainer::GetName; - - private: - // FIXME: map is most likely not the fastest -> array? - std::map mHistos; - - template - void GenericFill(std::shared_ptr hist, const Ts&... position) - { - // filling with weights requires one additional argument - constexpr bool isTH3 = (std::is_same_v && sizeof...(Ts) == 3 + fillWeight); - constexpr bool isTH2 = (std::is_same_v && sizeof...(Ts) == 2 + fillWeight); - constexpr bool isTH1 = (std::is_same_v && sizeof...(Ts) == 1 + fillWeight); - constexpr bool isTProfile3D = (std::is_same_v && sizeof...(Ts) == 4 + fillWeight); - constexpr bool isTProfile2D = (std::is_same_v && sizeof...(Ts) == 3 + fillWeight); - constexpr bool isTProfile = (std::is_same_v && sizeof...(Ts) == 2 + fillWeight); - - constexpr bool isValidPrimitive = isTH1 || isTH2 || isTH3 || isTProfile || isTProfile2D || isTProfile3D; - // unfortunately we dont know at compile the dimension of THn(Sparse) - constexpr bool isValidComplex = std::is_base_of_v; - - if constexpr (isValidPrimitive) { - hist->Fill(static_cast(position)...); - } else if constexpr (isValidComplex) { - // savety check for n dimensional histograms (runtime overhead) - // if (hist->GetNdimensions() != sizeof...(position) - fillWeight) return; - double tempArray[] = {static_cast(position)...}; - if constexpr (fillWeight) { - hist->Fill(tempArray, tempArray[sizeof...(Ts) - 1]); - } else { - hist->Fill(tempArray); - } - } - } - - template - std::optional GetHistVariant(std::shared_ptr obj) - { - if (obj->InheritsFrom(T::Class())) { - return std::static_pointer_cast(obj); - } - return std::nullopt; - } - template - std::optional GetHistVariant(std::shared_ptr obj) - { - if (auto hist = GetHistVariant(obj)) { - return hist; - } - return GetHistVariant(obj); - } - std::optional GetHistVariant(std::shared_ptr obj) - { - if (obj) { - // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 - return GetHistVariant(obj); - } - return std::nullopt; - } -}; - -//************************************************************************************************** -using HistFolder = HistContainer; -using HistArray = HistContainer; -using HistList = HistContainer; -//************************************************************************************************** - -//************************************************************************************************** -/** - * Helper class to build all kinds of root histograms with a streamlined user interface. - */ -//************************************************************************************************** - -struct Axis { - std::string name{}; - std::string title{}; - std::vector binEdges{}; - std::optional nBins{}; -}; - -class Hist -{ - public: - Hist() : mAxes{} {} - Hist(const std::vector& axes) : mAxes{axes} {} - - void AddAxis(const Axis& axis) - { - mAxes.push_back(axis); - } - - void AddAxis(const std::string& name, const std::string& title, const int nBins, - const double lowerEdge, const double upperEdge) - { - mAxes.push_back({name, title, {lowerEdge, upperEdge}, nBins}); - } - - void AddAxis(const std::string& name, const std::string& title, - const std::vector& binEdges) - { - mAxes.push_back({name, title, binEdges}); - } - - void AddAxes(const std::vector& axes) - { - mAxes.insert(mAxes.end(), axes.begin(), axes.end()); - } - - // add axes defined in other Hist object - void AddAxes(const Hist& other) - { - mAxes.insert(mAxes.end(), other.GetAxes().begin(), other.GetAxes().end()); - } - - void Reset() - { - mAxes.clear(); - } - - // create histogram with the defined axes - template - std::shared_ptr Create(const std::string& name, bool useWeights = false) - { - const std::size_t MAX_DIM{10}; - const std::size_t nAxes{mAxes.size()}; - if (nAxes == 0 || nAxes > MAX_DIM) { - return nullptr; - } - - int nBins[MAX_DIM]{0}; - double lowerBounds[MAX_DIM]{0.}; - double upperBounds[MAX_DIM]{0.}; - - // first figure out number of bins and dimensions - std::string title = "[ "; - for (std::size_t i = 0; i < nAxes; i++) { - nBins[i] = (mAxes[i].nBins) ? *mAxes[i].nBins : mAxes[i].binEdges.size() - 1; - lowerBounds[i] = mAxes[i].binEdges.front(); - upperBounds[i] = mAxes[i].binEdges.back(); - title += mAxes[i].name; - if (i < nAxes - 1) { - title += " : "; - } else { - title += " ]"; - } - } - - // create histogram - std::shared_ptr hist(HistFactory(name, title, nAxes, nBins, lowerBounds, upperBounds)); - - if (!hist) { - LOGF(FATAL, "The number of specified dimensions does not match the type."); - return nullptr; - } - - // set axis properties - for (std::size_t i = 0; i < nAxes; i++) { - TAxis* axis{GetAxis(i, hist)}; - if (axis) { - axis->SetTitle(mAxes[i].title.data()); - if constexpr (std::is_base_of_v) { - axis->SetName((std::to_string(i) + "-" + mAxes[i].name).data()); - } - - // move the bin edges in case a variable binning was requested - if (!mAxes[i].nBins) { - if (!std::is_sorted(std::begin(mAxes[i].binEdges), std::end(mAxes[i].binEdges))) { - LOGF(FATAL, "The bin edges specified for axis %s in histogram %s are not in increasing order!", mAxes[i].name, name); - return nullptr; - } - axis->Set(nBins[i], mAxes[i].binEdges.data()); - } - } - } - if (useWeights) { - hist->Sumw2(); - } - return hist; - } - - const std::vector& GetAxes() const { return mAxes; }; - - private: - std::vector mAxes; - - template - RootHistType* HistFactory(const std::string& name, const std::string& title, const std::size_t nDim, - const int nBins[], const double lowerBounds[], const double upperBounds[]) - { - if constexpr (std::is_base_of_v) { - return new RootHistType(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v) { - return (nDim != 3) ? nullptr - : new RootHistType(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], - nBins[2], lowerBounds[2], upperBounds[2]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 2) ? nullptr - : new RootHistType(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 1) - ? nullptr - : new RootHistType(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); - } - return nullptr; - } - - template - TAxis* GetAxis(const int i, std::shared_ptr hist) - { - if constexpr (std::is_base_of_v) { - return hist->GetAxis(i); - } else { - return (i == 0) ? hist->GetXaxis() - : (i == 1) ? hist->GetYaxis() : (i == 2) ? hist->GetZaxis() : nullptr; - } - } -}; - -} // namespace o2::experimental::histhelpers - -#endif diff --git a/Analysis/Core/include/Analysis/HistogramManager.h b/Analysis/Core/include/Analysis/HistogramManager.h deleted file mode 100644 index 893b5cc755132..0000000000000 --- a/Analysis/Core/include/Analysis/HistogramManager.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -// Class to define and fill histograms -// - -#ifndef HistogramManager_H -#define HistogramManager_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -class HistogramManager : public TNamed -{ - - public: - HistogramManager(); - HistogramManager(const char* name, const char* title, const int maxNVars); - ~HistogramManager() override; - - enum Constants { - kNothing = -1 - }; - - void SetMainHistogramList(THashList* list) - { - if (fMainList) { - delete fMainList; - } - fMainList = list; - } - - // Create a new histogram class - void AddHistClass(const char* histClass); - // Create a new histogram in the class with name and title - // The type of histogram is deduced from the parameters specified by the user - // The binning for at least one dimension needs to be specified, namely: nXbins, xmin, xmax, varX which will result in a TH1F histogram - // If the value for a variable is left as -1 then that is considered to not be used - // Up to 3 dimensional histograms can be defined with this function - // If isProfile = true, the last specified variable is the one being averaged - // For the case of TProfile3D, the user must use the varT to specify the averaged variable - // If specified, varW will be used as weight in the TH1::Fill() functions. - // If specified, the xLabels, yLabels, zLabels will be used to set the labels of the x,y,z axes, respectively. - // The axis titles will be set by default, if those were specified (e.g. taken from a Variable Manager) - // Otherwise these can be specified in the title string by separating them with semi-colons ";" - void AddHistogram(const char* histClass, const char* name, const char* title, bool isProfile, - int nXbins, double xmin, double xmax, int varX, - int nYbins = 0, double ymin = 0, double ymax = 0, int varY = -1, - int nZbins = 0, double zmin = 0, double zmax = 0, int varZ = -1, - const char* xLabels = "", const char* yLabels = "", const char* zLabels = "", - int varT = -1, int varW = -1); - // Similar to the above function, with the difference that the user can specify non-equidistant binning - void AddHistogram(const char* histClass, const char* name, const char* title, bool isProfile, - int nXbins, double* xbins, int varX, - int nYbins = 0, double* ybins = nullptr, int varY = -1, - int nZbins = 0, double* zbins = nullptr, int varZ = -1, - const char* xLabels = "", const char* yLabels = "", const char* zLabels = "", - int varT = -1, int varW = -1); - // Create a THn histogram (either THnF or THnSparse) with equidistant binning - void AddHistogram(const char* histClass, const char* name, const char* title, - int nDimensions, int* vars, int* nBins, double* xmin, double* xmax, - TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE); - // Create a THn histogram (either THnF or THnSparse) with non-equidistant binning - void AddHistogram(const char* histClass, const char* name, const char* title, - int nDimensions, int* vars, TArrayD* binLimits, - TString* axLabels = nullptr, int varW = -1, bool useSparse = kFALSE); - - void FillHistClass(const char* className, float* values); - - void SetUseDefaultVariableNames(bool flag) { fUseDefaultVariableNames = flag; }; - void SetDefaultVarNames(TString* vars, TString* units); - const bool* GetUsedVars() const { return fUsedVars; } - - THashList* GetMainHistogramList() { return fMainList; } // get a histogram list - - unsigned long int GetAllocatedBins() const { return fBinsAllocated; } - void Print(Option_t*) const override; - - private: - THashList* fMainList; // master histogram list - int fNVars; // number of variables handled (tipically from the Variable Manager) - - bool* fUsedVars; //! flags of used variables - std::map<std::string, std::list<std::vector<int>>> fVariablesMap; //! map holding identifiers for all variables needed by histograms - - // various - bool fUseDefaultVariableNames; //! toggle the usage of default variable names and units - unsigned long int fBinsAllocated; //! number of allocated bins - TString* fVariableNames; //! variable names - TString* fVariableUnits; //! variable units - - void MakeAxisLabels(TAxis* ax, const char* labels); - - HistogramManager& operator=(const HistogramManager& c); - HistogramManager(const HistogramManager& c); - - ClassDef(HistogramManager, 1) -}; - -#endif diff --git a/Analysis/Core/include/Analysis/JetFinder.h b/Analysis/Core/include/Analysis/JetFinder.h deleted file mode 100644 index 486d11daedf5e..0000000000000 --- a/Analysis/Core/include/Analysis/JetFinder.h +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet finder task -// -// Authors: Nima Zardoshti, Jochen Klein - -#ifndef O2_ANALYSIS_JETFINDER_H -#define O2_ANALYSIS_JETFINDER_H - -#include <TDatabasePDG.h> -#include <TPDGCode.h> -#include <TMath.h> - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" -#include "fastjet/AreaDefinition.hh" -#include "fastjet/JetDefinition.hh" -#include "fastjet/tools/JetMedianBackgroundEstimator.hh" -#include "fastjet/tools/Subtractor.hh" -#include "fastjet/contrib/ConstituentSubtractor.hh" - -#include <vector> - -class JetFinder -{ - - public: - enum class BkgSubMode { none, - rhoAreaSub, - constSub }; - BkgSubMode bkgSubMode; - - void setBkgSubMode(BkgSubMode bSM) { bkgSubMode = bSM; } - - /// Performs jet finding - /// \note the input particle and jet lists are passed by reference - /// \param inputParticles vector of input particles/tracks - /// \param jets veector of jets to be filled - /// \return ClusterSequenceArea object needed to access constituents - // fastjet::ClusterSequenceArea findJets(std::vector<fastjet::PseudoJet> &inputParticles, std::vector<fastjet::PseudoJet> &jets); - - static constexpr float mPion = 0.139; // TDatabasePDG::Instance()->GetParticle(211)->Mass(); //can be removed when pion mass becomes default for unidentified tracks - - float phiMin; - float phiMax; - float etaMin; - float etaMax; - - float jetR; - float jetPtMin; - float jetPtMax; - float jetPhiMin; - float jetPhiMax; - float jetEtaMin; - float jetEtaMax; - - float ghostEtaMin; - float ghostEtaMax; - float ghostArea; - int ghostRepeatN; - double ghostktMean; - float gridScatter; - float ktScatter; - - float jetBkgR; - float bkgPhiMin; - float bkgPhiMax; - float bkgEtaMin; - float bkgEtaMax; - - float constSubAlpha; - float constSubRMax; - - bool isReclustering; - - fastjet::JetAlgorithm algorithm; - fastjet::RecombinationScheme recombScheme; - fastjet::Strategy strategy; - fastjet::AreaType areaType; - fastjet::GhostedAreaSpec ghostAreaSpec; - fastjet::JetDefinition jetDef; - fastjet::AreaDefinition areaDef; - fastjet::Selector selJets; - fastjet::Selector selGhosts; - - fastjet::JetAlgorithm algorithmBkg; - fastjet::RecombinationScheme recombSchemeBkg; - fastjet::Strategy strategyBkg; - fastjet::AreaType areaTypeBkg; - fastjet::JetDefinition jetDefBkg; - fastjet::AreaDefinition areaDefBkg; - fastjet::Selector selRho; - - /// Default constructor - JetFinder(float eta_Min = -0.9, float eta_Max = 0.9, float phi_Min = 0.0, float phi_Max = 2 * TMath::Pi()) : phiMin(phi_Min), - phiMax(phi_Max), - etaMin(eta_Min), - etaMax(eta_Max), - jetR(0.4), - jetPtMin(0.0), - jetPtMax(1000.0), - jetPhiMin(phi_Min), - jetPhiMax(phi_Max), - jetEtaMin(eta_Min), - jetEtaMax(eta_Max), - ghostEtaMin(eta_Min), - ghostEtaMax(eta_Max), - ghostArea(0.005), - ghostRepeatN(1), - ghostktMean(1e-100), //is float precise enough? - gridScatter(1.0), - ktScatter(0.1), - jetBkgR(0.2), - bkgPhiMin(phi_Min), - bkgPhiMax(phi_Max), - bkgEtaMin(eta_Min), - bkgEtaMax(eta_Max), - algorithm(fastjet::antikt_algorithm), - recombScheme(fastjet::E_scheme), - strategy(fastjet::Best), - areaType(fastjet::active_area), - algorithmBkg(fastjet::JetAlgorithm(fastjet::kt_algorithm)), - recombSchemeBkg(fastjet::RecombinationScheme(fastjet::E_scheme)), - strategyBkg(fastjet::Best), - areaTypeBkg(fastjet::active_area), - bkgSubMode(BkgSubMode::none), - constSubAlpha(1.0), - constSubRMax(0.6), - isReclustering(false) - - { - - //default constructor - } - - /// Default destructor - ~JetFinder() = default; - - /// Sets the jet finding parameters - void setParams(); - - /// Sets the background subtraction estimater pointer - void setBkgE(); - - /// Sets the background subtraction pointer - void setSub(); - - /// Performs jet finding - /// \note the input particle and jet lists are passed by reference - /// \param inputParticles vector of input particles/tracks - /// \param jets veector of jets to be filled - /// \return ClusterSequenceArea object needed to access constituents - fastjet::ClusterSequenceArea findJets(std::vector<fastjet::PseudoJet>& inputParticles, std::vector<fastjet::PseudoJet>& jets); //ideally find a way of passing the cluster sequence as a reeference - - private: - //void setParams(); - //void setBkgSub(); - std::unique_ptr<fastjet::BackgroundEstimatorBase> bkgE; - std::unique_ptr<fastjet::Subtractor> sub; - std::unique_ptr<fastjet::contrib::ConstituentSubtractor> constituentSub; - - ClassDef(JetFinder, 1); -}; - -//does this belong here? -template <typename T> -void fillConstituents(const T& constituent, std::vector<fastjet::PseudoJet>& constituents) -{ - - auto energy = std::sqrt(constituent.p() * constituent.p() + JetFinder::mPion * JetFinder::mPion); - constituents.emplace_back(constituent.px(), constituent.py(), constituent.pz(), energy); -} - -#endif diff --git a/Analysis/Core/include/Analysis/MC.h b/Analysis/Core/include/Analysis/MC.h deleted file mode 100644 index aa400966f5d69..0000000000000 --- a/Analysis/Core/include/Analysis/MC.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef MC_H -#define MC_H - -#include "Framework/Logger.h" - -#include "TPDGCode.h" - -namespace MC -{ -bool isStable(int pdg) -{ - // Decide whether particle (pdg) is stable - - // All ions/nucleons are considered as stable - // Nuclear code is 10LZZZAAAI - if (pdg > 1000000000) { - return true; - } - - constexpr int kNstable = 18; - int pdgStable[kNstable] = { - kGamma, // Photon - kElectron, // Electron - kMuonPlus, // Muon - kPiPlus, // Pion - kKPlus, // Kaon - kK0Short, // K0s - kK0Long, // K0l - kProton, // Proton - kNeutron, // Neutron - kLambda0, // Lambda_0 - kSigmaMinus, // Sigma Minus - kSigmaPlus, // Sigma Plus - 3312, // Xsi Minus - 3322, // Xsi - 3334, // Omega - kNuE, // Electron Neutrino - kNuMu, // Muon Neutrino - kNuTau // Tau Neutrino - }; - - for (int i = 0; i < kNstable; i++) { - if (pdg == std::abs(pdgStable[i])) { - return true; - } - } - - return false; -} - -// Ported from AliRoot AliStack::IsPhysicalPrimary -template <typename TMCParticle, typename TMCParticles> -bool isPhysicalPrimary(TMCParticles& mcParticles, TMCParticle const& particle) -{ - // Test if a particle is a physical primary according to the following definition: - // Particles produced in the collision including products of strong and - // electromagnetic decay and excluding feed-down from weak decays of strange - // particles. - - LOGF(debug, "isPhysicalPrimary for %d", particle.index()); - - const int ist = particle.statusCode(); - const int pdg = std::abs(particle.pdgCode()); - - // Initial state particle - // Solution for K0L decayed by Pythia6 - // -> - if ((ist > 1) && (pdg != 130) && particle.producedByGenerator()) { - return false; - } - if ((ist > 1) && !particle.producedByGenerator()) { - return false; - } - // <- - - if (!isStable(pdg)) { - return false; - } - - if (particle.producedByGenerator()) { - // Solution for K0L decayed by Pythia6 - // -> - if (particle.mother0() != -1) { - auto mother = mcParticles.iteratorAt(particle.mother0()); - if (std::abs(mother.pdgCode()) == 130) { - return false; - } - } - // <- - // check for direct photon in parton shower - // -> - if (pdg == 22 && particle.daughter0() != -1) { - LOGF(debug, "D %d", particle.daughter0()); - auto daughter = mcParticles.iteratorAt(particle.daughter0()); - if (daughter.pdgCode() == 22) { - return false; - } - } - // <- - return true; - } - - // Particle produced during transport - - LOGF(debug, "M0 %d %d", particle.producedByGenerator(), particle.mother0()); - auto mother = mcParticles.iteratorAt(particle.mother0()); - int mpdg = std::abs(mother.pdgCode()); - - // Check for Sigma0 - if ((mpdg == 3212) && mother.producedByGenerator()) { - return true; - } - - // Check if it comes from a pi0 decay - if ((mpdg == kPi0) && mother.producedByGenerator()) { - return true; - } - - // Check if this is a heavy flavor decay product - int mfl = int(mpdg / std::pow(10, int(std::log10(mpdg)))); - - // Light hadron - if (mfl < 4) { - return false; - } - - // Heavy flavor hadron produced by generator - if (mother.producedByGenerator()) { - return true; - } - - // To be sure that heavy flavor has not been produced in a secondary interaction - // Loop back to the generated mother - LOGF(debug, "M0 %d %d", mother.producedByGenerator(), mother.mother0()); - while (mother.mother0() != -1 && !mother.producedByGenerator()) { - mother = mcParticles.iteratorAt(mother.mother0()); - LOGF(debug, "M+ %d %d", mother.producedByGenerator(), mother.mother0()); - mpdg = std::abs(mother.pdgCode()); - mfl = int(mpdg / std::pow(10, int(std::log10(mpdg)))); - } - - if (mfl < 4) { - return false; - } else { - return true; - } -} - -}; // namespace MC - -#endif diff --git a/Analysis/Core/include/Analysis/PairCuts.h b/Analysis/Core/include/Analysis/PairCuts.h deleted file mode 100644 index f8918b3dcdf05..0000000000000 --- a/Analysis/Core/include/Analysis/PairCuts.h +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_ANALYSIS_PAIRCUTS_H -#define O2_ANALYSIS_PAIRCUTS_H - -#include <cmath> - -#include <TH2F.h> -#include <TH3F.h> - -#include "Framework/Logger.h" -#include "Framework/HistogramRegistry.h" - -// Functions which cut on particle pairs (decays, conversions, two-track cuts) -// -// Author: Jan Fiete Grosse-Oetringhaus - -using namespace o2; -using namespace o2::framework; - -class PairCuts -{ - public: - enum Particle { Photon = 0, - K0, - Lambda, - Phi, - Rho, - ParticlesLastEntry }; - - void SetHistogramRegistry(HistogramRegistry* registry) { histogramRegistry = registry; } - - void SetPairCut(Particle particle, float cut) - { - LOGF(info, "Enabled pair cut for %d with value %f", static_cast<int>(particle), cut); - mCuts[particle] = cut; - if (histogramRegistry != nullptr && histogramRegistry->contains("ControlConvResonances") == false) { - histogramRegistry->add("ControlConvResonances", "", {HistType::kTH2F, {{6, -0.5, 5.5, "id"}, {500, -0.5, 0.5, "delta mass"}}}); - } - } - - void SetTwoTrackCuts(float distance = 0.02f, float radius = 0.8f) - { - LOGF(info, "Enabled two-track cut with distance %f and radius %f", distance, radius); - mTwoTrackDistance = distance; - mTwoTrackRadius = radius; - - if (histogramRegistry != nullptr && histogramRegistry->contains("TwoTrackDistancePt_0") == false) { - histogramRegistry->add("TwoTrackDistancePt_0", "", {HistType::kTH3F, {{100, -0.15, 0.15, "#Delta#eta"}, {100, -0.05, 0.05, "#Delta#varphi^{*}_{min}"}, {20, 0, 10, "#Delta p_{T}"}}}); - histogramRegistry->addClone("TwoTrackDistancePt_0", "TwoTrackDistancePt_1"); - } - } - - template <typename T> - bool conversionCuts(T const& track1, T const& track2); - - template <typename T> - bool twoTrackCut(T const& track1, T const& track2, int bSign); - - protected: - float mCuts[ParticlesLastEntry] = {-1}; - float mTwoTrackDistance = -1; // distance below which the pair is flagged as to be removed - float mTwoTrackRadius = 0.8f; // radius at which the two track cuts are applied - - HistogramRegistry* histogramRegistry = nullptr; // if set, control histograms are stored here - - template <typename T> - bool conversionCut(T const& track1, T const& track2, Particle conv, double cut); - - template <typename T> - double getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2); - - template <typename T> - double getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2); - - template <typename T> - float getDPhiStar(T const& track1, T const& track2, float radius, float bSign); -}; - -template <typename T> -bool PairCuts::conversionCuts(T const& track1, T const& track2) -{ - // skip if like sign - if (track1.charge() * track2.charge() > 0) { - return false; - } - - for (int i = 0; i < static_cast<int>(ParticlesLastEntry); i++) { - Particle particle = static_cast<Particle>(i); - if (mCuts[i] > 0) { - if (conversionCut(track1, track2, particle, mCuts[i])) { - return true; - } - if (particle == Lambda) { - if (conversionCut(track2, track1, particle, mCuts[i])) { - return true; - } - } - } - } - - return false; -} - -template <typename T> -bool PairCuts::twoTrackCut(T const& track1, T const& track2, int bSign) -{ - // the variables & cut have been developed in Run 1 by the CF - HBT group - // - // Parameters: - // bSign: sign of B field - - auto deta = track1.eta() - track2.eta(); - - // optimization - if (TMath::Abs(deta) < mTwoTrackDistance * 2.5 * 3) { - // check first boundaries to see if is worth to loop and find the minimum - float dphistar1 = getDPhiStar(track1, track2, mTwoTrackRadius, bSign); - float dphistar2 = getDPhiStar(track1, track2, 2.5, bSign); - - const float kLimit = mTwoTrackDistance * 3; - - if (TMath::Abs(dphistar1) < kLimit || TMath::Abs(dphistar2) < kLimit || dphistar1 * dphistar2 < 0) { - float dphistarminabs = 1e5; - float dphistarmin = 1e5; - for (Double_t rad = mTwoTrackRadius; rad < 2.51; rad += 0.01) { - float dphistar = getDPhiStar(track1, track2, rad, bSign); - - float dphistarabs = TMath::Abs(dphistar); - - if (dphistarabs < dphistarminabs) { - dphistarmin = dphistar; - dphistarminabs = dphistarabs; - } - } - - if (histogramRegistry != nullptr) { - histogramRegistry->fill("TwoTrackDistancePt_0", deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - } - - if (dphistarminabs < mTwoTrackDistance && TMath::Abs(deta) < mTwoTrackDistance) { - //LOGF(debug, "Removed track pair %ld %ld with %f %f %f %f %d %f %f %d %d", track1.index(), track2.index(), deta, dphistarminabs, track1.phi2(), track1.pt(), track1.charge(), track2.phi2(), track2.pt(), track2.charge(), bSign); - return true; - } - - if (histogramRegistry != nullptr) { - histogramRegistry->fill("TwoTrackDistancePt_1", deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - } - } - } - - return false; -} - -template <typename T> -bool PairCuts::conversionCut(T const& track1, T const& track2, Particle conv, double cut) -{ - //LOGF(info, "pt is %f %f", track1.pt(), track2.pt()); - - if (cut < 0) { - return false; - } - - double massD1, massD2, massM; - - switch (conv) { - case Photon: - massD1 = 0.51e-3; - massD2 = 0.51e-3; - massM = 0; - break; - case K0: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.4976; - break; - case Lambda: - massD1 = 0.9383; - massD2 = 0.1396; - massM = 1.115; - break; - case Phi: - massD1 = 0.4937; - massD2 = 0.4937; - massM = 1.019; - break; - case Rho: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.770; - break; - default: - LOGF(fatal, "Particle now known"); - return false; - break; - } - - auto massC = getInvMassSquaredFast(track1, massD1, track2, massD2); - - if (TMath::Abs(massC - massM * massM) > cut * 5) { - return false; - } - - massC = getInvMassSquared(track1, massD1, track2, massD2); - - if (histogramRegistry != nullptr) { - histogramRegistry->fill("ControlConvResonances", static_cast<int>(conv), massC - massM * massM); - } - - if (massC > (massM - cut) * (massM - cut) && massC < (massM + cut) * (massM + cut)) { - return true; - } - - return false; -} - -template <typename T> -double PairCuts::getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2) -{ - // calculate inv mass squared - // same can be achieved, but with more computing time with - /*TLorentzVector photon, p1, p2; - p1.SetPtEtaPhiM(triggerParticle->Pt(), triggerEta, triggerParticle->Phi(), 0.510e-3); - p2.SetPtEtaPhiM(particle->Pt(), eta[j], particle->Phi(), 0.510e-3); - photon = p1+p2; - photon.M()*/ - - float tantheta1 = 1e10; - - if (track1.eta() < -1e-10 || track1.eta() > 1e-10) { - float expTmp = TMath::Exp(-track1.eta()); - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (track2.eta() < -1e-10 || track2.eta() > 1e-10) { - float expTmp = TMath::Exp(-track2.eta()); - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + track1.pt() * track1.pt() * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + track2.pt() * track2.pt() * (1.0 + 1.0 / tantheta2 / tantheta2); - - float mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (track1.pt() * track2.pt() * (TMath::Cos(track1.phi() - track2.phi()) + 1.0 / tantheta1 / tantheta2))); - - // LOGF(debug, "%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2); - - return mass2; -} - -template <typename T> -double PairCuts::getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2) -{ - // calculate inv mass squared approximately - - const float eta1 = track1.eta(); - const float eta2 = track2.eta(); - const float phi1 = track1.phi(); - const float phi2 = track2.phi(); - const float pt1 = track1.pt(); - const float pt2 = track2.pt(); - - float tantheta1 = 1e10; - - if (eta1 < -1e-10 || eta1 > 1e-10) { - float expTmp = 1.0 - eta1 + eta1 * eta1 / 2 - eta1 * eta1 * eta1 / 6 + eta1 * eta1 * eta1 * eta1 / 24; - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (eta2 < -1e-10 || eta2 > 1e-10) { - float expTmp = 1.0 - eta2 + eta2 * eta2 / 2 - eta2 * eta2 * eta2 / 6 + eta2 * eta2 * eta2 * eta2 / 24; - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + pt1 * pt1 * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + pt2 * pt2 * (1.0 + 1.0 / tantheta2 / tantheta2); - - // fold onto 0...pi - float deltaPhi = TMath::Abs(phi1 - phi2); - while (deltaPhi > M_PI * 2) { - deltaPhi -= M_PI * 2; - } - if (deltaPhi > M_PI) { - deltaPhi = M_PI * 2 - deltaPhi; - } - - float cosDeltaPhi = 0; - if (deltaPhi < M_PI / 3) { - cosDeltaPhi = 1.0 - deltaPhi * deltaPhi / 2 + deltaPhi * deltaPhi * deltaPhi * deltaPhi / 24; - } else if (deltaPhi < 2 * M_PI / 3) { - cosDeltaPhi = -(deltaPhi - M_PI / 2) + 1.0 / 6 * TMath::Power((deltaPhi - M_PI / 2), 3); - } else { - cosDeltaPhi = -1.0 + 1.0 / 2.0 * (deltaPhi - M_PI) * (deltaPhi - M_PI) - 1.0 / 24.0 * TMath::Power(deltaPhi - M_PI, 4); - } - - double mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (pt1 * pt2 * (cosDeltaPhi + 1.0 / tantheta1 / tantheta2))); - - //LOGF(debug, "%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2); - - return mass2; -} - -template <typename T> -float PairCuts::getDPhiStar(T const& track1, T const& track2, float radius, float bSign) -{ - // - // calculates dphistar - // - - auto phi1 = track1.phi(); - auto pt1 = track1.pt(); - auto charge1 = track1.charge(); - - auto phi2 = track2.phi(); - auto pt2 = track2.pt(); - auto charge2 = track2.charge(); - - float dphistar = phi1 - phi2 - charge1 * bSign * TMath::ASin(0.075 * radius / pt1) + charge2 * bSign * TMath::ASin(0.075 * radius / pt2); - - if (dphistar > M_PI) { - dphistar = M_PI * 2 - dphistar; - } - if (dphistar < -M_PI) { - dphistar = -M_PI * 2 - dphistar; - } - if (dphistar > M_PI) { // might look funny but is needed - dphistar = M_PI * 2 - dphistar; - } - - return dphistar; -} - -#endif diff --git a/Analysis/Core/include/Analysis/RecoDecay.h b/Analysis/Core/include/Analysis/RecoDecay.h deleted file mode 100644 index 530b920724d08..0000000000000 --- a/Analysis/Core/include/Analysis/RecoDecay.h +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file RecoDecay.h -/// \brief Implementation of the RecoDecay class. -/// -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#ifndef O2_ANALYSIS_RECODECAY_H_ -#define O2_ANALYSIS_RECODECAY_H_ - -#include <tuple> -#include <vector> -#include <array> -#include <cmath> - -#include <TDatabasePDG.h> -#include <TPDGCode.h> - -#include "CommonConstants/MathConstants.h" -#include "Framework/Logger.h" - -using std::array; -using namespace o2::constants::math; - -/// Base class for calculating properties of reconstructed decays. - -class RecoDecay -{ - public: - /// Default constructor - RecoDecay() = default; - - /// Default destructor - ~RecoDecay() = default; - - // Auxiliary functions - - /// Sums numbers. - /// \param args arbitrary number of numbers of arbitrary types - /// \return sum of numbers - template <typename... T> - static auto sum(const T&... args) - { - return (args + ...); - } - - /// Squares a number. - /// \note Promotes number to double before squaring to avoid precision loss in float multiplication. - /// \param num a number of arbitrary type - /// \return number squared - template <typename T> - static double sq(T num) - { - return (double)num * (double)num; - } - - /// Sums squares of numbers. - /// \note Promotes numbers to double before squaring to avoid precision loss in float multiplication. - /// \param args arbitrary number of numbers of arbitrary types - /// \return sum of squares of numbers - template <typename... T> - static double sumOfSquares(const T&... args) - { - return (((double)args * (double)args) + ...); - } - - /// Calculates square root of a sum of squares of numbers. - /// \param args arbitrary number of numbers of arbitrary types - /// \return square root of sum of squares of numbers - template <typename... T> - static double sqrtSumOfSquares(const T&... args) - { - return std::sqrt(sumOfSquares(args...)); - } - - /// Sums i-th elements of containers. - /// \param index element index - /// \param args pack of containers of elements accessible by index - /// \return sum of i-th elements - template <typename... T> - static auto getElement(int index, const T&... args) - { - return (args[index] + ...); - } - - /// Sums 3-vectors. - /// \param args pack of 3-vector arrays - /// \return sum of vectors - template <typename... T> - static auto sumOfVec(const array<T, 3>&... args) - { - return array{getElement(0, args...), getElement(1, args...), getElement(2, args...)}; - } - - /// Calculates scalar product of vectors. - /// \note Promotes numbers to double before squaring to avoid precision loss in float multiplication. - /// \param N dimension - /// \param vec1,vec2 vectors - /// \return scalar product - template <std::size_t N, typename T, typename U> - static double dotProd(const array<T, N>& vec1, const array<U, N>& vec2) - { - double res{0}; - for (auto iDim = 0; iDim < N; ++iDim) { - res += (double)vec1[iDim] * (double)vec2[iDim]; - } - return res; - } - - /// Calculates magnitude squared of a vector. - /// \param N dimension - /// \param vec vector - /// \return magnitude squared - template <std::size_t N, typename T> - static double mag2(const array<T, N>& vec) - { - return dotProd(vec, vec); - } - - /// Calculates 3D distance between two points. - /// \param point1,point2 {x, y, z} coordinates of points - /// \return 3D distance between two points - template <typename T, typename U> - static double distance(const T& point1, const U& point2) - { - return sqrtSumOfSquares(point1[0] - point2[0], point1[1] - point2[1], point1[2] - point2[2]); - } - - /// Calculates 2D {x, y} distance between two points. - /// \param point1,point2 {x, y, z} or {x, y} coordinates of points - /// \return 2D {x, y} distance between two points - template <typename T, typename U> - static double distanceXY(const T& point1, const U& point2) - { - return sqrtSumOfSquares(point1[0] - point2[0], point1[1] - point2[1]); - } - - // Calculation of kinematic quantities - - /// Calculates pseudorapidity. - /// \param mom 3-momentum array - /// \return pseudorapidity - template <typename T> - static double Eta(const array<T, 3>& mom) - { - // eta = arctanh(pz/p) - if (std::abs(mom[0]) < Almost0 && std::abs(mom[1]) < Almost0) { // very small px and py - return (double)(mom[2] > 0 ? VeryBig : -VeryBig); - } - return (double)(std::atanh(mom[2] / P(mom))); - } - - /// Calculates rapidity. - /// \param mom 3-momentum array - /// \param mass mass - /// \return rapidity - template <typename T, typename U> - static double Y(const array<T, 3>& mom, U mass) - { - // y = arctanh(pz/E) - return std::atanh(mom[2] / E(mom, mass)); - } - - /// Calculates cosine of pointing angle. - /// \param posPV {x, y, z} position of the primary vertex - /// \param posSV {x, y, z} position of the secondary vertex - /// \param mom 3-momentum array - /// \return cosine of pointing angle - template <typename T, typename U, typename V> - static double CPA(const T& posPV, const U& posSV, const array<V, 3>& mom) - { - // CPA = (l . p)/(|l| |p|) - auto lineDecay = array{posSV[0] - posPV[0], posSV[1] - posPV[1], posSV[2] - posPV[2]}; - auto cos = dotProd(lineDecay, mom) / std::sqrt(mag2(lineDecay) * mag2(mom)); - if (cos < -1.) { - return -1.; - } - if (cos > 1.) { - return 1.; - } - return cos; - } - - /// Calculates cosine of pointing angle in the {x, y} plane. - /// \param posPV {x, y, z} or {x, y} position of the primary vertex - /// \param posSV {x, y, z} or {x, y} position of the secondary vertex - /// \param mom {x, y, z} or {x, y} momentum array - /// \return cosine of pointing angle in {x, y} - template <std::size_t N, typename T, typename U, typename V> - static double CPAXY(const T& posPV, const U& posSV, const array<V, N>& mom) - { - // CPAXY = (r . pT)/(|r| |pT|) - auto lineDecay = array{posSV[0] - posPV[0], posSV[1] - posPV[1]}; - auto momXY = array{mom[0], mom[1]}; - auto cos = dotProd(lineDecay, momXY) / std::sqrt(mag2(lineDecay) * mag2(momXY)); - if (cos < -1.) { - return -1.; - } - if (cos > 1.) { - return 1.; - } - return cos; - } - - /// Calculates proper lifetime times c. - /// \note Promotes numbers to double before squaring to avoid precision loss in float multiplication. - /// \param mom 3-momentum array - /// \param mass mass - /// \param length decay length - /// \return proper lifetime times c - template <typename T, typename U, typename V> - static double Ct(const array<T, 3>& mom, U length, V mass) - { - // c t = l m c^2/(p c) - return (double)length * (double)mass / P(mom); - } - - /// Calculates cosine of θ* (theta star). - /// \note Implemented for 2 prongs only. - /// \param arrMom array of two 3-momentum arrays - /// \param arrMass array of two masses (in the same order as arrMom) - /// \param mTot assumed mass of mother particle - /// \param iProng index of the prong - /// \return cosine of θ* of the i-th prong under the assumption of the invariant mass - template <typename T, typename U, typename V> - static double CosThetaStar(const array<array<T, 3>, 2>& arrMom, const array<U, 2>& arrMass, V mTot, int iProng) - { - auto pVecTot = PVec(arrMom[0], arrMom[1]); // momentum of the mother particle - auto pTot = P(pVecTot); // magnitude of the momentum of the mother particle - auto eTot = E(pTot, mTot); // energy of the mother particle - auto gamma = eTot / mTot; // γ, Lorentz gamma factor of the mother particle - auto beta = pTot / eTot; // β, velocity of the mother particle - auto pStar = std::sqrt(sq(sq(mTot) - sq(arrMass[0]) - sq(arrMass[1])) - sq(2 * arrMass[0] * arrMass[1])) / (2 * mTot); // p*, prong momentum in the rest frame of the mother particle - // p* = √[(M^2 - m1^2 - m2^2)^2 - 4 m1^2 m2^2]/2M - // Lorentz transformation of the longitudinal momentum of the prong into the detector frame: - // p_L,i = γ (p*_L,i + β E*_i) - // p*_L,i = p_L,i/γ - β E*_i - // cos(θ*_i) = (p_L,i/γ - β E*_i)/p* - return (dotProd(arrMom[iProng], pVecTot) / (pTot * gamma) - beta * E(pStar, arrMass[iProng])) / pStar; - } - - /// Sums 3-momenta. - /// \param args pack of 3-momentum arrays - /// \return total 3-momentum array - template <typename... T> - static auto PVec(const array<T, 3>&... args) - { - return sumOfVec(args...); - } - - /// Calculates momentum squared from momentum components. - /// \param px,py,pz {x, y, z} momentum components - /// \return momentum squared - static double P2(double px, double py, double pz) - { - return sumOfSquares(px, py, pz); - } - - /// Calculates total momentum squared of a sum of 3-momenta. - /// \param args pack of 3-momentum arrays - /// \return total momentum squared - template <typename... T> - static double P2(const array<T, 3>&... args) - { - return sumOfSquares(getElement(0, args...), getElement(1, args...), getElement(2, args...)); - } - - /// Calculates (total) momentum magnitude. - /// \param args {x, y, z} momentum components or pack of 3-momentum arrays - /// \return (total) momentum magnitude - template <typename... T> - static double P(const T&... args) - { - return std::sqrt(P2(args...)); - } - - /// Calculates transverse momentum squared from momentum components. - /// \param px,py {x, y} momentum components - /// \return transverse momentum squared - static double Pt2(double px, double py) - { - return sumOfSquares(px, py); - } - - /// Calculates total transverse momentum squared of a sum of 3-(or 2-)momenta. - /// \param args pack of 3-(or 2-)momentum arrays - /// \return total transverse momentum squared - template <std::size_t N, typename... T> - static double Pt2(const array<T, N>&... args) - { - return sumOfSquares(getElement(0, args...), getElement(1, args...)); - } - - /// Calculates (total) transverse momentum. - /// \param args {x, y} momentum components or pack of 3-momentum arrays - /// \return (total) transverse momentum - template <typename... T> - static double Pt(const T&... args) - { - return std::sqrt(Pt2(args...)); - } - - /// Calculates energy squared from momentum and mass. - /// \param args momentum magnitude, mass - /// \param args {x, y, z} momentum components, mass - /// \return energy squared - template <typename... T> - static double E2(T... args) - { - return sumOfSquares(args...); - } - - /// Calculates energy squared from momentum vector and mass. - /// \param mom 3-momentum array - /// \param mass mass - /// \return energy squared - template <typename T, typename U> - static double E2(const array<T, 3>& mom, U mass) - { - return E2(mom[0], mom[1], mom[2], mass); - } - - /// Calculates energy from momentum and mass. - /// \param args momentum magnitude, mass - /// \param args {x, y, z} momentum components, mass - /// \param args 3-momentum array, mass - /// \return energy - template <typename... T> - static double E(const T&... args) - { - return std::sqrt(E2(args...)); - } - - /// Calculates invariant mass squared from momentum magnitude and energy. - /// \param mom momentum magnitude - /// \param energy energy - /// \return invariant mass squared - static double M2(double mom, double energy) - { - return energy * energy - mom * mom; - } - - /// Calculates invariant mass squared from momentum aray and energy. - /// \param mom 3-momentum array - /// \param energy energy - /// \return invariant mass squared - template <typename T> - static double M2(const array<T, 3>& mom, double energy) - { - return energy * energy - P2(mom); - } - - /// Calculates invariant mass squared from momenta and masses of several particles (prongs). - /// \param N number of prongs - /// \param arrMom array of N 3-momentum arrays - /// \param arrMass array of N masses (in the same order as arrMom) - /// \return invariant mass squared - template <std::size_t N, typename T, typename U> - static double M2(const array<array<T, 3>, N>& arrMom, const array<U, N>& arrMass) - { - array<double, 3> momTotal{0., 0., 0.}; // candidate momentum vector - double energyTot{0.}; // candidate energy - for (auto iProng = 0; iProng < N; ++iProng) { - for (auto iMom = 0; iMom < 3; ++iMom) { - momTotal[iMom] += arrMom[iProng][iMom]; - } // loop over momentum components - energyTot += E(arrMom[iProng], arrMass[iProng]); - } // loop over prongs - return energyTot * energyTot - P2(momTotal); - } - - /// Calculates invariant mass. - /// \param args momentum magnitude, energy - /// \param args 3-momentum array, energy - /// \param args array of momenta, array of masses - /// \return invariant mass - template <typename... T> - static double M(const T&... args) - { - return std::sqrt(M2(args...)); - } - - /// Returns particle mass based on PDG code. - /// \param pdg PDG code - /// \return particle mass - static double getMassPDG(int pdg) - { - // Try to get the particle mass from the list first. - for (const auto& particle : mListMass) { - if (std::get<0>(particle) == pdg) { - return std::get<1>(particle); - } - } - // Get the mass of the new particle and add it in the list. - auto newMass = TDatabasePDG::Instance()->GetParticle(pdg)->Mass(); - mListMass.push_back(std::make_tuple(pdg, newMass)); - return newMass; - } - - /// Check whether the reconstructed decay candidate is the expected decay. - /// \param particlesMC table with MC particles - /// \param arrDaughters array of candidate daughters - /// \param PDGMother expected mother PDG code - /// \param arrPDGDaughters array of expected daughter PDG codes - /// \param acceptAntiParticles switch to accept the antiparticle version of the expected decay - /// \return true if PDG codes of the mother and daughters are correct, false otherwise - template <std::size_t N, typename T, typename U> - static bool isMCMatchedDecayRec(const T& particlesMC, const array<U, N>& arrDaughters, int PDGMother, array<int, N> arrPDGDaughters, bool acceptAntiParticles = false) - { - //Printf("MC Rec.: Expected mother PDG: %d", PDGMother); - int sgn = 1; // 1 if the expected mother is particle, -1 if antiparticle - int indexMother = -1; // index of the mother particle - int indexDaughterFirst = -1; // index of the first daughter - int indexDaughterLast = -1; // index of the last daughter - array<int, N> arrDaughtersIndex; // array of daughter indices - // loop over daughter particles - for (auto iProng = 0; iProng < N; ++iProng) { - auto particleI = arrDaughters[iProng].label(); // ith daughter particle - arrDaughtersIndex[iProng] = particleI.globalIndex(); - auto indexParticleIMother = particleI.mother0(); - if (indexParticleIMother == -1) { - //Printf("MC Rec. rejected: bad mother index: %d", indexParticleIMother); - return false; - } - // Get the mother. - auto particleIMother = particlesMC.iteratorAt(indexParticleIMother); - // Check mother's PDG code. - auto PDGParticleIMother = particleIMother.pdgCode(); // PDG code of the mother of the ith daughter - //Printf("MC Rec.: Daughter %d mother PDG: %d", iProng, PDGParticleIMother); - if (PDGParticleIMother != sgn * PDGMother) { - if (acceptAntiParticles && iProng == 0 && PDGParticleIMother == -PDGMother) { - sgn = -1; // PDG code of the first daughter's mother determines whether the expected mother is a particle or antiparticle. - } else { - //Printf("MC Rec. rejected: bad mother PDG: %s%d != %d", acceptAntiParticles ? "abs " : "", PDGParticleIMother, sgn * PDGMother); - return false; - } - } - // Check that all daughters have the same mother. - if (iProng == 0) { - indexMother = indexParticleIMother; - } else if (indexParticleIMother != indexMother) { - //Printf("MC Rec. rejected: different mothers: %d %d", indexMother, indexParticleIMother); - return false; - } - // Set the range of expected daughter indices. - if (iProng == 0) { - indexDaughterFirst = particleIMother.daughter0(); - indexDaughterLast = particleIMother.daughter1(); - // Check the daughter indices. - // Daughter indices are supposed to be consecutive. - if (indexDaughterLast <= indexDaughterFirst || indexDaughterFirst == -1 || indexDaughterLast == -1) { - //Printf("MC Rec. rejected: bad daughter index range: %d-%d", indexDaughterFirst, indexDaughterLast); - return false; - } - // Check the number of daughters. - if (indexDaughterLast - indexDaughterFirst + 1 != N) { - //Printf("MC Rec. rejected: incorrect number of daughters: %d", indexDaughterLast - indexDaughterFirst + 1); - return false; - } - } - // Check that the daughter is not a stepdaughter. - if (arrDaughtersIndex[iProng] < indexDaughterFirst || arrDaughtersIndex[iProng] > indexDaughterLast) { - //Printf("MC Rec. rejected: stepdaughter: %d outside %d-%d", arrDaughtersIndex[iProng], indexDaughterFirst, indexDaughterLast); - return false; - } - // Check that the daughter is not a twin. - for (auto jProng = 0; jProng < iProng; ++jProng) { - if (arrDaughtersIndex[iProng] == arrDaughtersIndex[jProng]) { - //Printf("MC Rec. rejected: twin daughter: %d", arrDaughtersIndex[iProng]); - return false; - } - } - // Check daughter's PDG code. - auto PDGParticleI = particleI.pdgCode(); // PDG code of the ith daughter - //Printf("MC Rec: Daughter %d PDG: %d", iProng, PDGParticleI); - bool PDGFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? - for (auto iProngCp = 0; iProngCp < N; ++iProngCp) { - if (PDGParticleI == sgn * arrPDGDaughters[iProngCp]) { - arrPDGDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. - PDGFound = true; - break; - } - } - if (!PDGFound) { - //Printf("MC Rec. rejected: bad daughter PDG: %d", PDGParticleI); - return false; - } - } - //Printf("MC Rec. accepted: m: %d, d: %d-%d", indexMother, indexDaughterFirst, indexDaughterLast); - return true; - } - - /// Check whether the MC particle is the expected one. - /// \param particlesMC table with MC particles - /// \param candidate candidate MC particle - /// \param PDGParticle expected particle PDG code - /// \param acceptAntiParticles switch to accept the antiparticle - /// \return true if PDG code of the particle is correct, false otherwise - template <typename T, typename U> - static bool isMCMatchedDecayGen(const T& particlesMC, const U& candidate, int PDGParticle, bool acceptAntiParticles = false) - { - return isMCMatchedDecayGen(particlesMC, candidate, PDGParticle, array{0}, acceptAntiParticles); - } - - /// Check whether the MC particle is the expected one and whether it decayed via the expected decay channel. - /// \param particlesMC table with MC particles - /// \param candidate candidate MC particle - /// \param PDGParticle expected particle PDG code - /// \param arrPDGDaughters array of expected PDG codes of daughters - /// \param acceptAntiParticles switch to accept the antiparticle - /// \return true if PDG codes of the particle and its daughters are correct, false otherwise - template <std::size_t N, typename T, typename U> - static bool isMCMatchedDecayGen(const T& particlesMC, const U& candidate, int PDGParticle, array<int, N> arrPDGDaughters, bool acceptAntiParticles = false) - { - //Printf("MC Gen.: Expected particle PDG: %d", PDGParticle); - int sgn = 1; // 1 if the expected mother is particle, -1 if antiparticle - int indexDaughterFirst = 0; // index of the first daughter - int indexDaughterLast = 0; // index of the last daughter - // Check the PDG code of the particle. - auto PDGCandidate = candidate.pdgCode(); - //Printf("MC Gen.: Candidate PDG: %d", PDGCandidate); - if (PDGCandidate != PDGParticle) { - if (acceptAntiParticles && PDGCandidate == -PDGParticle) { - sgn = -1; - } else { - //Printf("MC Gen. rejected: bad particle PDG: %s%d != %d", acceptAntiParticles ? "abs " : "", PDGCandidate, sgn * PDGParticle); - return false; - } - } - // Check the PDG codes of the decay products. - if (N > 1) { - //Printf("MC Gen.: Checking %d daughters", N); - // Set the range of expected daughter indices. - indexDaughterFirst = candidate.daughter0(); - indexDaughterLast = candidate.daughter1(); - // Check the daughter indices. - // Daughter indices are supposed to be consecutive. - if (indexDaughterLast <= indexDaughterFirst || indexDaughterFirst == -1 || indexDaughterLast == -1) { - //Printf("MC Gen. rejected: bad daughter index range: %d-%d", indexDaughterFirst, indexDaughterLast); - return false; - } - // Check the number of daughters. - if (indexDaughterLast - indexDaughterFirst + 1 != N) { - //Printf("MC Gen. rejected: incorrect number of daughters: %d", indexDaughterLast - indexDaughterFirst + 1); - return false; - } - // Check daughters' PDG codes. - for (auto indexDaughterI = indexDaughterFirst; indexDaughterI <= indexDaughterLast; ++indexDaughterI) { - auto candidateDaughterI = particlesMC.iteratorAt(indexDaughterI); // ith daughter particle - auto PDGCandidateDaughterI = candidateDaughterI.pdgCode(); // PDG code of the ith daughter - //Printf("MC Gen.: Daughter %d PDG: %d", indexDaughterI, PDGCandidateDaughterI); - bool PDGFound = false; // Is the PDG code of this daughter among the remaining expected PDG codes? - for (auto iProngCp = 0; iProngCp < N; ++iProngCp) { - if (PDGCandidateDaughterI == sgn * arrPDGDaughters[iProngCp]) { - arrPDGDaughters[iProngCp] = 0; // Remove this PDG code from the array of expected ones. - PDGFound = true; - break; - } - } - if (!PDGFound) { - //Printf("MC Gen. rejected: bad daughter PDG: %d", PDGCandidateDaughterI); - return false; - } - } - } - //Printf("MC Gen. accepted: m: %d, d: %d-%d", candidate.globalIndex(), indexDaughterFirst, indexDaughterLast); - return true; - } - - private: - static std::vector<std::tuple<int, double>> mListMass; ///< list of particle masses in form (PDG code, mass) -}; - -std::vector<std::tuple<int, double>> RecoDecay::mListMass; - -#endif // O2_ANALYSIS_RECODECAY_H_ diff --git a/Analysis/Core/include/Analysis/TrackSelection.h b/Analysis/Core/include/Analysis/TrackSelection.h deleted file mode 100644 index f4e6edf67c985..0000000000000 --- a/Analysis/Core/include/Analysis/TrackSelection.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Class for track selection -// - -#ifndef TrackSelection_H -#define TrackSelection_H - -#include "Framework/Logger.h" -#include "Framework/DataTypes.h" -#include <set> -#include <vector> -#include "Rtypes.h" - -class TrackSelection -{ - public: - TrackSelection() = default; - - enum class TrackCuts : int { - kTrackType = 0, - kPtRange, - kEtaRange, - kTPCNCls, - kTPCCrossedRows, - kTPCCrossedRowsOverNCls, - kTPCChi2NDF, - kTPCRefit, - kITSNCls, - kITSChi2NDF, - kITSRefit, - kITSHits, - kGoldenChi2, - kDCAxy, - kDCAz, - kNCuts - }; - - static const std::string mCutNames[static_cast<int>(TrackCuts::kNCuts)]; - - // Temporary function to check if track passes selection criteria. To be replaced by framework filters. - template <typename T> - bool IsSelected(T const& track) - { - if (track.trackType() == mTrackType && - track.pt() >= mMinPt && track.pt() <= mMaxPt && - track.eta() >= mMinEta && track.eta() <= mMaxEta && - track.tpcNClsFound() >= mMinNClustersTPC && - track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC && - track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC && - (track.itsNCls() >= mMinNClustersITS) && - (track.itsChi2NCl() <= mMaxChi2PerClusterITS) && - (track.tpcChi2NCl() <= mMaxChi2PerClusterTPC) && - ((mRequireITSRefit) ? (track.flags() & o2::aod::track::ITSrefit) : true) && - ((mRequireTPCRefit) ? (track.flags() & o2::aod::track::TPCrefit) : true) && - ((mRequireGoldenChi2) ? (track.flags() & o2::aod::track::GoldenChi2) : true) && - FulfillsITSHitRequirements(track.itsClusterMap()) && - abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY) && - abs(track.dcaZ()) <= mMaxDcaZ) { - return true; - } else { - return false; - } - } - - // Temporary function to check if track passes a given selection criteria. To be replaced by framework filters. - template <typename T> - bool IsSelected(T const& track, const TrackCuts& cut) - { - switch (cut) { - case TrackCuts::kTrackType: - return track.trackType() == mTrackType; - case TrackCuts::kPtRange: - return track.pt() >= mMinPt && track.pt() <= mMaxPt; - case TrackCuts::kEtaRange: - return track.eta() >= mMinEta && track.eta() <= mMaxEta; - case TrackCuts::kTPCNCls: - return track.tpcNClsFound() >= mMinNClustersTPC; - case TrackCuts::kTPCCrossedRows: - return track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC; - case TrackCuts::kTPCCrossedRowsOverNCls: - return track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC; - case TrackCuts::kTPCChi2NDF: - return track.itsNCls() >= mMinNClustersITS; - case TrackCuts::kTPCRefit: - return track.itsChi2NCl() <= mMaxChi2PerClusterITS; - case TrackCuts::kITSNCls: - return track.tpcChi2NCl() <= mMaxChi2PerClusterTPC; - case TrackCuts::kITSChi2NDF: - return (mRequireITSRefit) ? (track.flags() & o2::aod::track::ITSrefit) : true; - case TrackCuts::kITSRefit: - return (mRequireTPCRefit) ? (track.flags() & o2::aod::track::TPCrefit) : true; - case TrackCuts::kITSHits: - return (mRequireGoldenChi2) ? (track.flags() & o2::aod::track::GoldenChi2) : true; - case TrackCuts::kGoldenChi2: - return FulfillsITSHitRequirements(track.itsClusterMap()); - case TrackCuts::kDCAxy: - return abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); - case TrackCuts::kDCAz: - return abs(track.dcaZ()) <= mMaxDcaZ; - default: - return false; - } - } - - void SetTrackType(o2::aod::track::TrackTypeEnum trackType) { mTrackType = trackType; } - void SetPtRange(float minPt = 0.f, float maxPt = 1e10f) - { - mMinPt = minPt; - mMaxPt = maxPt; - } - void SetEtaRange(float minEta = -1e10f, float maxEta = 1e10f) - { - mMinEta = minEta; - mMaxEta = maxEta; - } - void SetRequireITSRefit(bool requireITSRefit = true) - { - mRequireITSRefit = requireITSRefit; - } - void SetRequireTPCRefit(bool requireTPCRefit = true) - { - mRequireTPCRefit = requireTPCRefit; - } - void SetRequireGoldenChi2(bool requireGoldenChi2 = true) - { - mRequireGoldenChi2 = requireGoldenChi2; - } - void SetMinNClustersTPC(int minNClustersTPC) - { - mMinNClustersTPC = minNClustersTPC; - } - void SetMinNCrossedRowsTPC(int minNCrossedRowsTPC) - { - mMinNCrossedRowsTPC = minNCrossedRowsTPC; - } - void SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC) - { - mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; - } - void SetMinNClustersITS(int minNClustersITS) - { - mMinNClustersITS = minNClustersITS; - } - void SetMaxChi2PerClusterTPC(float maxChi2PerClusterTPC) - { - mMaxChi2PerClusterTPC = maxChi2PerClusterTPC; - } - void SetMaxChi2PerClusterITS(float maxChi2PerClusterITS) - { - mMaxChi2PerClusterITS = maxChi2PerClusterITS; - } - void SetMaxDcaXY(float maxDcaXY) { mMaxDcaXY = maxDcaXY; } - void SetMaxDcaZ(float maxDcaZ) { mMaxDcaZ = maxDcaZ; } - - void SetMaxDcaXYPtDep(std::function<float(float)> ptDepCut) - { - mMaxDcaXYPtDep = ptDepCut; - } - void SetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set<uint8_t> requiredLayers) - { - // layer 0 corresponds to the the innermost ITS layer - if (minNRequiredHits > requiredLayers.size()) { - LOGF(FATAL, "More ITS hits required than layers specified."); - } else { - mRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); - } - } - void SetRequireNoHitsInITSLayers(std::set<uint8_t> excludedLayers) - { - mRequiredITSHits.push_back(std::make_pair(-1, excludedLayers)); - } - void ResetITSRequirements() { mRequiredITSHits.clear(); } - - private: - bool FulfillsITSHitRequirements(uint8_t itsClusterMap); - - o2::aod::track::TrackTypeEnum mTrackType{o2::aod::track::TrackTypeEnum::GlobalTrack}; - - // kinematic cuts - float mMinPt{0.f}, mMaxPt{1e10f}; // range in pT - float mMinEta{-1e10f}, mMaxEta{1e10f}; // range in eta - - // track quality cuts - int mMinNClustersTPC{0}; // min number of TPC clusters - int mMinNCrossedRowsTPC{0}; // min number of crossed rows in TPC - int mMinNClustersITS{0}; // min number of ITS clusters - float mMaxChi2PerClusterTPC{1e10f}; // max tpc fit chi2 per TPC cluster - float mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster - float mMinNCrossedRowsOverFindableClustersTPC{0.f}; // min ratio crossed rows / findable clusters - - float mMaxDcaXY{1e10f}; // max dca in xy plane - float mMaxDcaZ{1e10f}; // max dca in z direction - std::function<float(float)> mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT - - bool mRequireITSRefit{false}; // require refit in ITS - bool mRequireTPCRefit{false}; // require refit in TPC - bool mRequireGoldenChi2{false}; // require golden chi2 cut (Run 2 only) - - // vector of ITS requirements (minNRequiredHits in specific requiredLayers) - std::vector<std::pair<int8_t, std::set<uint8_t>>> mRequiredITSHits{}; - - ClassDef(TrackSelection, 1); -}; - -#endif diff --git a/Analysis/Core/include/Analysis/TrackSelectionDefaults.h b/Analysis/Core/include/Analysis/TrackSelectionDefaults.h deleted file mode 100644 index bddbf5c560141..0000000000000 --- a/Analysis/Core/include/Analysis/TrackSelectionDefaults.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file TrackSelectionDefaults.h -/// \brief Class for the definition of standard track selection objects -/// \since 20-10-2020 -/// - -#ifndef TrackSelectionDefaults_H -#define TrackSelectionDefaults_H - -#include "Framework/DataTypes.h" - -// Default track selection requiring one hit in the SPD -TrackSelection getGlobalTrackSelection() -{ - TrackSelection selectedTracks; - selectedTracks.SetTrackType(o2::aod::track::Run2GlobalTrack); - selectedTracks.SetPtRange(0.1f, 1e10f); - selectedTracks.SetEtaRange(-0.8f, 0.8f); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); - selectedTracks.SetRequireGoldenChi2(true); - selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); - selectedTracks.SetMaxChi2PerClusterTPC(4.f); - selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); // one hit in any SPD layer - selectedTracks.SetMaxChi2PerClusterITS(36.f); - selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); - selectedTracks.SetMaxDcaZ(2.f); - return selectedTracks; -} - -// Default track selection requiring no hit in the SPD and one in the innermost -// SDD -> complementary tracks to global selection -TrackSelection getGlobalTrackSelectionSDD() -{ - TrackSelection selectedTracks = getGlobalTrackSelection(); - selectedTracks.ResetITSRequirements(); - selectedTracks.SetRequireNoHitsInITSLayers({0, 1}); // no hit in SPD layers - selectedTracks.SetRequireHitsInITSLayers(1, {2}); // one hit in first SDD layer - return selectedTracks; -} - -#endif diff --git a/Analysis/Core/include/Analysis/TriggerAliases.h b/Analysis/Core/include/Analysis/TriggerAliases.h deleted file mode 100644 index 9a7e9e9cbd35f..0000000000000 --- a/Analysis/Core/include/Analysis/TriggerAliases.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef TriggerAliases_H -#define TriggerAliases_H - -#include <map> -#include <string> -#include <vector> -#include <Rtypes.h> - -enum triggerAliases { - kINT7 = 0, - kEMC7, - kINT7inMUON, - kMuonSingleLowPt7, - kMuonUnlikeLowPt7, - kMuonLikeLowPt7, - kCUP8, - kCUP9, - kMUP10, - kMUP11, - kNaliases -}; - -class TriggerAliases -{ - public: - TriggerAliases() = default; - ~TriggerAliases() = default; - void AddAlias(int aliasId, std::string classNames) { mAliases[aliasId] = classNames; } - void AddClassIdToAlias(int aliasId, int classId) { mAliasToClassIds[aliasId].push_back(classId); } - const std::map<int, std::vector<int>>& GetAliasToClassIdsMap() const { return mAliasToClassIds; } - void Print(); - - private: - std::map<int, std::string> mAliases; - std::map<int, std::vector<int>> mAliasToClassIds; - ClassDefNV(TriggerAliases, 1) -}; - -#endif diff --git a/Analysis/Core/include/Analysis/VarManager.h b/Analysis/Core/include/Analysis/VarManager.h deleted file mode 100644 index ebe8127dec4c7..0000000000000 --- a/Analysis/Core/include/Analysis/VarManager.h +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -// Class to handle analysis variables -// - -#ifndef VarManager_H -#define VarManager_H - -#include <TObject.h> -#include <TString.h> -#include <Math/Vector4D.h> -#include <TMath.h> - -#include <vector> -#include <map> -#include <cmath> - -#include "Framework/DataTypes.h" -#include "Analysis/TriggerAliases.h" - -// TODO: create an array holding these constants for all needed particles or check for a place where these are already defined -static const float fgkElectronMass = 0.000511; // GeV -static const float fgkMuonMass = 0.105; // GeV - -//_________________________________________________________________________ -class VarManager : public TObject -{ - public: - // map the information contained in the objects passed to the Fill functions - enum ObjTypes { - BC = BIT(0), - Collision = BIT(1), - CollisionCent = BIT(2), - ReducedEvent = BIT(3), - ReducedEventExtended = BIT(4), - ReducedEventVtxCov = BIT(5), - Track = BIT(0), - TrackCov = BIT(1), - TrackExtra = BIT(2), - TrackPID = BIT(3), - TrackDCA = BIT(4), - TrackSelection = BIT(5), - // TODO: Central model MUON variables to be added - ReducedTrack = BIT(6), - ReducedTrackBarrel = BIT(7), - ReducedTrackBarrelCov = BIT(8), - ReducedTrackBarrelPID = BIT(9), - ReducedTrackMuon = BIT(10), - Pair = BIT(11) - }; - - public: - enum Variables { - kNothing = -1, - // Run wise variables - kRunNo = 0, - kRunId, - kNRunWiseVariables, - - // Event wise variables // Daria: imedjat ai ziua mja - kCollisionTime, - kBC, - kIsPhysicsSelection, - kIsINT7, - kIsEMC7, - kIsINT7inMUON, - kIsMuonSingleLowPt7, - kIsMuonUnlikeLowPt7, - kIsMuonLikeLowPt7, - kVtxX, - kVtxY, - kVtxZ, - kVtxNcontrib, - kVtxCovXX, - kVtxCovXY, - kVtxCovXZ, - kVtxCovYY, - kVtxCovYZ, - kVtxCovZZ, - kVtxChi2, - kCentVZERO, - kNEventWiseVariables, - - // Basic track(pair) wise variables - kPt, - kEta, - kPhi, - kP, - kPx, - kPy, - kPz, - kRap, - kMass, - kCharge, - kNBasicTrackVariables, - - // Barrel track variables - kPin, - kIsGlobalTrack, - kIsGlobalTrackSDD, - kIsITSrefit, - kIsSPDany, - kIsSPDfirst, - kIsSPDboth, - kITSncls, - kITSchi2, - kITSlayerHit, - kIsTPCrefit, - kTPCncls, - kTPCchi2, - kTPCsignal, - kTRDsignal, - kTOFsignal, - kTOFbeta, - kTrackLength, - kTrackDCAxy, - kTrackDCAz, - kTrackCYY, - kTrackCZZ, - kTrackCSnpSnp, - kTrackCTglTgl, - kTrackC1Pt21Pt2, - kTPCnSigmaEl, - kTPCnSigmaMu, - kTPCnSigmaPi, - kTPCnSigmaKa, - kTPCnSigmaPr, - kTOFnSigmaEl, - kTOFnSigmaMu, - kTOFnSigmaPi, - kTOFnSigmaKa, - kTOFnSigmaPr, - kNBarrelTrackVariables, - - // Muon track variables - kMuonInvBendingMomentum, - kMuonThetaX, - kMuonThetaY, - kMuonZMu, - kMuonBendingCoor, - kMuonNonBendingCoor, - kMuonRAtAbsorberEnd, - kMuonPDca, - kMuonChi2, - kMuonChi2MatchTrigger, - kNMuonTrackVariables, - - // Pair variables - kCandidateId, - kPairType, - kPairLxy, - kNPairVariables, - - // Candidate-track correlation variables - kPairMass, - kPairPt, - kPairEta, - kPairPhi, - kDeltaEta, - kDeltaPhi, - kDeltaPhiSym, - kNCorrelationVariables, - - kNVars - }; // end of Variables enumeration - - static TString fgVariableNames[kNVars]; // variable names - static TString fgVariableUnits[kNVars]; // variable units - static void SetDefaultVarNames(); - - static void SetUseVariable(int var) - { - if (var >= 0 && var < kNVars) { - fgUsedVars[var] = kTRUE; - } - SetVariableDependencies(); - } - static void SetUseVars(const bool* usedVars) - { - for (int i = 0; i < kNVars; ++i) { - if (usedVars[i]) { - fgUsedVars[i] = true; // overwrite only the variables that are being used since there are more channels to modify the used variables array, independently - } - } - SetVariableDependencies(); - } - static void SetUseVars(const std::vector<int> usedVars) - { - for (auto& var : usedVars) { - fgUsedVars[var] = true; - } - } - static bool GetUsedVar(int var) - { - if (var >= 0 && var < kNVars) { - return fgUsedVars[var]; - } - return false; - } - - static void SetRunNumbers(int n, int* runs); - - template <uint32_t fillMap, typename T> - static void FillEvent(T const& event, float* values = nullptr); - template <uint32_t fillMap, typename T> - static void FillTrack(T const& track, float* values = nullptr); - template <typename T> - static void FillPair(T const& t1, T const& t2, float* values = nullptr); - template <typename T1, typename T2> - static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); - - public: - VarManager(); - ~VarManager() override; - - static float fgValues[kNVars]; // array holding all variables computed during analysis - static void ResetValues(int startValue = 0, int endValue = kNVars, float* values = nullptr); - - private: - static bool fgUsedVars[kNVars]; // holds flags for when the corresponding variable is needed (e.g., in the histogram manager, in cuts, mixing handler, etc.) - static void SetVariableDependencies(); // toggle those variables on which other used variables might depend - - static std::map<int, int> fgRunMap; // map of runs to be used in histogram axes - - static void FillEventDerived(float* values = nullptr); - static void FillTrackDerived(float* values = nullptr); - - VarManager& operator=(const VarManager& c); - VarManager(const VarManager& c); - - ClassDef(VarManager, 1) -}; - -template <uint32_t fillMap, typename T> -void VarManager::FillEvent(T const& event, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & BC) > 0) { - values[kRunNo] = event.bc().runNumber(); // accessed via Collisions table - values[kBC] = event.bc().globalBC(); - } - - if constexpr ((fillMap & Collision) > 0) { - if (fgUsedVars[kIsINT7]) { - values[kIsINT7] = (event.alias()[kINT7] > 0); - } - if (fgUsedVars[kIsEMC7]) { - values[kIsEMC7] = (event.alias()[kEMC7] > 0); - } - if (fgUsedVars[kIsINT7inMUON]) { - values[kIsINT7inMUON] = (event.alias()[kINT7inMUON] > 0); - } - if (fgUsedVars[kIsMuonSingleLowPt7]) { - values[kIsMuonSingleLowPt7] = (event.alias()[kMuonSingleLowPt7] > 0); - } - if (fgUsedVars[kIsMuonUnlikeLowPt7]) { - values[kIsMuonUnlikeLowPt7] = (event.alias()[kMuonUnlikeLowPt7] > 0); - } - if (fgUsedVars[kIsMuonLikeLowPt7]) { - values[kIsMuonLikeLowPt7] = (event.alias()[kMuonLikeLowPt7] > 0); - } - values[kVtxX] = event.posX(); - values[kVtxY] = event.posY(); - values[kVtxZ] = event.posZ(); - values[kVtxNcontrib] = event.numContrib(); - values[kCollisionTime] = event.collisionTime(); - values[kVtxCovXX] = event.covXX(); - values[kVtxCovXY] = event.covXY(); - values[kVtxCovXZ] = event.covXZ(); - values[kVtxCovYY] = event.covYY(); - values[kVtxCovYZ] = event.covYZ(); - values[kVtxCovZZ] = event.covZZ(); - values[kVtxChi2] = event.chi2(); - } - - if constexpr ((fillMap & CollisionCent) > 0) { - values[kCentVZERO] = event.centV0M(); - } - - // TODO: need to add EvSels and Cents tables, etc. in case of the central data model - - if constexpr ((fillMap & ReducedEvent) > 0) { - values[kRunNo] = event.runNumber(); - values[kVtxX] = event.posX(); - values[kVtxY] = event.posY(); - values[kVtxZ] = event.posZ(); - values[kVtxNcontrib] = event.numContrib(); - } - - if constexpr ((fillMap & ReducedEventExtended) > 0) { - values[kBC] = event.globalBC(); - values[kCentVZERO] = event.centV0M(); - if (fgUsedVars[kIsINT7]) { - values[kIsINT7] = (event.triggerAlias() & (uint32_t(1) << kINT7)) > 0; - } - if (fgUsedVars[kIsEMC7]) { - values[kIsEMC7] = (event.triggerAlias() & (uint32_t(1) << kEMC7)) > 0; - } - if (fgUsedVars[kIsINT7inMUON]) { - values[kIsINT7inMUON] = (event.triggerAlias() & (uint32_t(1) << kINT7inMUON)) > 0; - } - if (fgUsedVars[kIsMuonSingleLowPt7]) { - values[kIsMuonSingleLowPt7] = (event.triggerAlias() & (uint32_t(1) << kMuonSingleLowPt7)) > 0; - } - if (fgUsedVars[kIsMuonUnlikeLowPt7]) { - values[kIsMuonUnlikeLowPt7] = (event.triggerAlias() & (uint32_t(1) << kMuonUnlikeLowPt7)) > 0; - } - if (fgUsedVars[kIsMuonLikeLowPt7]) { - values[kIsMuonLikeLowPt7] = (event.triggerAlias() & (uint32_t(1) << kMuonLikeLowPt7)) > 0; - } - } - - if constexpr ((fillMap & ReducedEventVtxCov) > 0) { - values[kVtxCovXX] = event.covXX(); - values[kVtxCovXY] = event.covXY(); - values[kVtxCovXZ] = event.covXZ(); - values[kVtxCovYY] = event.covYY(); - values[kVtxCovYZ] = event.covYZ(); - values[kVtxCovZZ] = event.covZZ(); - values[kVtxChi2] = event.chi2(); - } - - FillEventDerived(values); -} - -template <uint32_t fillMap, typename T> -void VarManager::FillTrack(T const& track, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & Track) > 0 || (fillMap & ReducedTrack) > 0) { - values[kPt] = track.pt(); - if (fgUsedVars[kPx]) { - values[kPx] = track.px(); - } - if (fgUsedVars[kPy]) { - values[kPy] = track.py(); - } - if (fgUsedVars[kPz]) { - values[kPz] = track.pz(); - } - values[kEta] = track.eta(); - values[kPhi] = track.phi(); - values[kCharge] = track.charge(); - } - - if constexpr ((fillMap & TrackExtra) > 0 || (fillMap & ReducedTrackBarrel) > 0) { - values[kPin] = track.tpcInnerParam(); - if (fgUsedVars[kIsITSrefit]) { - values[kIsITSrefit] = (track.flags() & (uint32_t(1) << 0)) > 0; - } - if (fgUsedVars[kIsTPCrefit]) { - values[kIsTPCrefit] = (track.flags() & (uint32_t(1) << 1)) > 0; - } - if (fgUsedVars[kIsSPDfirst]) { - values[kIsSPDfirst] = (track.itsClusterMap() & uint8_t(1)) > 0; - } - if (fgUsedVars[kIsSPDboth]) { - values[kIsSPDboth] = (track.itsClusterMap() & uint8_t(3)) > 0; - } - if (fgUsedVars[kIsSPDany]) { - values[kIsSPDany] = (track.itsClusterMap() & uint8_t(1)) || (track.itsClusterMap() & uint8_t(2)); - } - values[kITSchi2] = track.itsChi2NCl(); - values[kTPCncls] = track.tpcNClsFound(); - values[kTPCchi2] = track.tpcChi2NCl(); - values[kTrackLength] = track.length(); - - if constexpr ((fillMap & TrackExtra) > 0) { - if (fgUsedVars[kITSncls]) { - values[kITSncls] = track.itsNCls(); // dynamic column - } - } - if constexpr ((fillMap & ReducedTrackBarrel) > 0) { - if (fgUsedVars[kITSncls]) { - values[kITSncls] = 0.0; - for (int i = 0; i < 6; ++i) { - values[kITSncls] += ((track.itsClusterMap() & (1 << i)) ? 1 : 0); - } - } - values[kTrackDCAxy] = track.dcaXY(); - values[kTrackDCAz] = track.dcaZ(); - } - } - - if constexpr ((fillMap & TrackDCA) > 0) { - values[kTrackDCAxy] = track.dcaXY(); - values[kTrackDCAz] = track.dcaZ(); - } - - if constexpr ((fillMap & TrackSelection) > 0) { - values[kIsGlobalTrack] = track.isGlobalTrack(); - values[kIsGlobalTrackSDD] = track.isGlobalTrackSDD(); - } - - if constexpr ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0) { - values[kTrackCYY] = track.cYY(); - values[kTrackCZZ] = track.cZZ(); - values[kTrackCSnpSnp] = track.cSnpSnp(); - values[kTrackCTglTgl] = track.cTglTgl(); - values[kTrackC1Pt21Pt2] = track.c1Pt21Pt2(); - } - - if constexpr ((fillMap & TrackPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { - values[kTPCnSigmaEl] = track.tpcNSigmaEl(); - values[kTPCnSigmaMu] = track.tpcNSigmaMu(); - values[kTPCnSigmaPi] = track.tpcNSigmaPi(); - values[kTPCnSigmaKa] = track.tpcNSigmaKa(); - values[kTPCnSigmaPr] = track.tpcNSigmaPr(); - values[kTOFnSigmaEl] = track.tofNSigmaEl(); - values[kTOFnSigmaMu] = track.tofNSigmaMu(); - values[kTOFnSigmaPi] = track.tofNSigmaPi(); - values[kTOFnSigmaKa] = track.tofNSigmaKa(); - values[kTOFnSigmaPr] = track.tofNSigmaPr(); - values[kTPCsignal] = track.tpcSignal(); - values[kTRDsignal] = track.trdSignal(); - values[kTOFsignal] = track.tofSignal(); - values[kTOFbeta] = track.beta(); - } - - if constexpr ((fillMap & ReducedTrackMuon) > 0) { - values[kMuonInvBendingMomentum] = track.inverseBendingMomentum(); - values[kMuonThetaX] = track.thetaX(); - values[kMuonThetaY] = track.thetaY(); - values[kMuonZMu] = track.zMu(); - values[kMuonBendingCoor] = track.bendingCoor(); - values[kMuonNonBendingCoor] = track.nonBendingCoor(); - values[kMuonRAtAbsorberEnd] = track.rAtAbsorberEnd(); - values[kMuonPDca] = track.pDca(); - values[kMuonChi2] = track.chi2(); - values[kMuonChi2MatchTrigger] = track.chi2MatchTrigger(); - } - - if constexpr ((fillMap & Pair) > 0) { - values[kMass] = track.mass(); - } - - FillTrackDerived(values); -} - -template <typename T> -void VarManager::FillPair(T const& t1, T const& t2, float* values) -{ - if (!values) { - values = fgValues; - } - - float mass1 = fgkElectronMass; - float mass2 = fgkElectronMass; - - bool isMuon1 = t1.filteringFlags() & (1 << 0); - bool isMuon2 = t2.filteringFlags() & (1 << 0); - - if (isMuon1) { - mass1 = fgkMuonMass; - } else { - mass1 = fgkElectronMass; - } - - if (isMuon2) { - mass2 = fgkMuonMass; - } else { - mass2 = fgkElectronMass; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), mass1); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), mass2); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); - values[kRap] = -v12.Rapidity(); -} - -template <typename T1, typename T2> -void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values, float hadronMass) -{ - if (!values) { - values = fgValues; - } - - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi]) { - ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); - ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - values[kPairMass] = v12.M(); - values[kPairPt] = v12.Pt(); - values[kPairEta] = v12.Eta(); - values[kPairPhi] = v12.Phi(); - } - if (fgUsedVars[kDeltaPhi]) { - double delta = dilepton.phi() - hadron.phi(); - if (delta > 3.0 / 2.0 * TMath::Pi()) { - delta -= 2.0 * TMath::Pi(); - } - if (delta < -0.5 * TMath::Pi()) { - delta += 2.0 * TMath::Pi(); - } - values[kDeltaPhi] = delta; - } - if (fgUsedVars[kDeltaPhiSym]) { - double delta = TMath::Abs(dilepton.phi() - hadron.phi()); - if (delta > TMath::Pi()) { - delta = 2 * TMath::Pi() - delta; - } - values[kDeltaPhiSym] = delta; - } - if (fgUsedVars[kDeltaEta]) { - values[kDeltaEta] = dilepton.eta() - hadron.eta(); - } -} - -#endif diff --git a/Analysis/Core/include/Analysis/trackUtilities.h b/Analysis/Core/include/Analysis/trackUtilities.h deleted file mode 100644 index 83d38ab54d47b..0000000000000 --- a/Analysis/Core/include/Analysis/trackUtilities.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file trackUtilities.h -/// \brief Utilities for manipulating parameters of tracks and vertices -/// -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#ifndef O2_ANALYSIS_TRACKUTILITIES_H_ -#define O2_ANALYSIS_TRACKUTILITIES_H_ - -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "Analysis/RecoDecay.h" - -/// Extracts track parameters from a track. -template <typename T> -o2::track::TrackPar getTrackPar(const T& track) -{ - std::array<float, 5> arraypar = {track.y(), track.z(), track.snp(), - track.tgl(), track.signed1Pt()}; - return o2::track::TrackPar(track.x(), track.alpha(), std::move(arraypar)); -} - -/// Extracts track parameters and covariance matrix from a track. -template <typename T> -o2::track::TrackParCov getTrackParCov(const T& track) -{ - std::array<float, 5> arraypar = {track.y(), track.z(), track.snp(), - track.tgl(), track.signed1Pt()}; - std::array<float, 15> covpar = {track.cYY(), track.cZY(), track.cZZ(), - track.cSnpY(), track.cSnpZ(), - track.cSnpSnp(), track.cTglY(), track.cTglZ(), - track.cTglSnp(), track.cTglTgl(), - track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), - track.c1PtTgl(), track.c1Pt21Pt2()}; - return o2::track::TrackParCov(track.x(), track.alpha(), std::move(arraypar), std::move(covpar)); -} - -/// Extracts primary vertex position and covariance matrix from a collision. -template <typename T> -o2::dataformats::VertexBase getPrimaryVertex(const T& collision) -{ - o2::math_utils::Point3D<float> vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - std::array<float, 6> vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; - return o2::dataformats::VertexBase{std::move(vtxXYZ), std::move(vtxCov)}; -} - -/// Calculates direction of one point w.r.t another point. -/// \param point1,point2 points with {x, y, z} coordinates accessible by index -/// \param phi azimuth angle in the {x, y} plane (taken w.r.t. the x-axis towards the y-axis) -/// \param theta angle w.r.t the {x, y} plane towards the z-axis -/// \return phi,theta of point2 w.r.t. point1 -template <typename T, typename U, typename V, typename W> -void getPointDirection(const T& point1, const U& point2, V& phi, W& theta) -{ - phi = std::atan2(point2[1] - point1[1], point2[0] - point1[0]); - //auto x1 = point1[0] * std::cos(phi) + point1[1] * std::sin(phi); - //auto x2 = point2[0] * std::cos(phi) + point2[1] * std::sin(phi); - //theta = std::atan2(point2[2] - point1[2], x2 - x1); - theta = std::atan2(point2[2] - point1[2], RecoDecay::distanceXY(point1, point2)); -} - -/// Calculates the XX element of a XYZ covariance matrix after rotation of the coordinate system -/// by phi around the z-axis and by minus theta around the new y-axis. -/// \param matrix matrix -/// \param phi azimuth angle in the {x, y} plane (taken w.r.t. the x-axis towards the y-axis) -/// \param theta angle w.r.t the {x, y} plane towards the z-axis -/// \return XX element of the rotated covariance matrix -template <typename T, typename U, typename V> -auto getRotatedCovMatrixXX(const T& matrix, U phi, V theta) -{ - auto cp = std::cos(phi); - auto sp = std::sin(phi); - auto ct = std::cos(theta); - auto st = std::sin(theta); - return matrix[0] * cp * cp * ct * ct // covXX - + matrix[1] * 2. * cp * sp * ct * ct // covXY - + matrix[2] * sp * sp * ct * ct // covYY - + matrix[3] * 2. * cp * ct * st // covXZ - + matrix[4] * 2. * sp * ct * st // covYZ - + matrix[5] * st * st; // covZZ -} - -#endif // O2_ANALYSIS_TRACKUTILITIES_H_ diff --git a/Analysis/Core/src/AnalysisCompositeCut.cxx b/Analysis/Core/src/AnalysisCompositeCut.cxx deleted file mode 100644 index 9acd248e173af..0000000000000 --- a/Analysis/Core/src/AnalysisCompositeCut.cxx +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/AnalysisCompositeCut.h" - -ClassImp(AnalysisCompositeCut) - - //____________________________________________________________________________ - AnalysisCompositeCut::AnalysisCompositeCut(bool useAND) : AnalysisCut(), - fOptionUseAND(useAND), - fCutList() -{ - // - // default constructor - // -} - -//____________________________________________________________________________ -AnalysisCompositeCut::AnalysisCompositeCut(const char* name, const char* title, bool useAND) : AnalysisCut(name, title), - fOptionUseAND(useAND), - fCutList() -{ - // - // named constructor - // -} - -//____________________________________________________________________________ -AnalysisCompositeCut::~AnalysisCompositeCut() = default; - -//____________________________________________________________________________ -bool AnalysisCompositeCut::IsSelected(float* values) -{ - // - // apply cuts - // - for (std::vector<AnalysisCut>::iterator it = fCutList.begin(); it < fCutList.end(); ++it) { - if (fOptionUseAND && !(*it).IsSelected(values)) { - return false; - } - if (!fOptionUseAND && (*it).IsSelected(values)) { - return true; - } - } - - if (fOptionUseAND) { - return true; - } else { - return false; - } -} diff --git a/Analysis/Core/src/AnalysisCoreLinkDef.h b/Analysis/Core/src/AnalysisCoreLinkDef.h deleted file mode 100644 index ed2833df8a9f0..0000000000000 --- a/Analysis/Core/src/AnalysisCoreLinkDef.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class CorrelationContainer + ; -#pragma link C++ class TrackSelection + ; -#pragma link C++ class TriggerAliases + ; - -#pragma link C++ class VarManager + ; -#pragma link C++ class HistogramManager + ; -#pragma link C++ class AnalysisCut + ; -#pragma link C++ class AnalysisCompositeCut + ; diff --git a/Analysis/Core/src/AnalysisCut.cxx b/Analysis/Core/src/AnalysisCut.cxx deleted file mode 100644 index 659b9e6c4c7dd..0000000000000 --- a/Analysis/Core/src/AnalysisCut.cxx +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/AnalysisCut.h" - -#include <iostream> -using std::cout; -using std::endl; - -ClassImp(AnalysisCut); - -std::vector<int> AnalysisCut::fgUsedVars = {}; - -//____________________________________________________________________________ -AnalysisCut::AnalysisCut(const char* name, const char* title) : TNamed(name, title), - fCuts() -{ - // - // named constructor - // -} - -//____________________________________________________________________________ -AnalysisCut& AnalysisCut::operator=(const AnalysisCut& c) -{ - // - // assignment - // - if (this != &c) { - TNamed::operator=(c); - fCuts = c.fCuts; - } - return (*this); -} - -//____________________________________________________________________________ -AnalysisCut::~AnalysisCut() = default; diff --git a/Analysis/Core/src/AnalysisJetsLinkDef.h b/Analysis/Core/src/AnalysisJetsLinkDef.h deleted file mode 100644 index 8de8bce16da64..0000000000000 --- a/Analysis/Core/src/AnalysisJetsLinkDef.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class JetFinder + ; diff --git a/Analysis/Core/src/CorrelationContainer.cxx b/Analysis/Core/src/CorrelationContainer.cxx deleted file mode 100644 index 76940b51aa043..0000000000000 --- a/Analysis/Core/src/CorrelationContainer.cxx +++ /dev/null @@ -1,1993 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// encapsulate histogram and corrections for correlation analysis -// -// Author: Jan Fiete Grosse-Oetringhaus - -#include "Analysis/CorrelationContainer.h" -#include "Framework/StepTHn.h" -#include "Framework/Logger.h" -#include "THnSparse.h" -#include "TMath.h" -#include "TList.h" -#include "TCollection.h" -#include "TH1D.h" -#include "TH2D.h" -#include "TH3D.h" -#include "TCanvas.h" -#include "TF1.h" -#include "THn.h" - -ClassImp(CorrelationContainer) - - const Int_t CorrelationContainer::fgkCFSteps = 11; - -CorrelationContainer::CorrelationContainer() : TNamed(), - mPairHist(nullptr), - mTriggerHist(nullptr), - mTrackHistEfficiency(nullptr), - mEventCount(nullptr), - mEtaMin(0), - mEtaMax(0), - mPtMin(0), - mPtMax(0), - mPartSpecies(-1), - mCentralityMin(0), - mCentralityMax(0), - mZVtxMin(0), - mZVtxMax(0), - mPt2Min(0), - mPt2Max(0), - mTrackEtaCut(0), - mWeightPerEvent(0), - mSkipScaleMixedEvent(kFALSE), - mCache(nullptr), - mGetMultCacheOn(kFALSE), - mGetMultCache(nullptr), - mHistogramType() -{ - // Default constructor -} - -CorrelationContainer::CorrelationContainer(const char* name, const char* objTitle, const char* reqHist, const char* binning) : TNamed(name, objTitle), - mPairHist(nullptr), - mTriggerHist(nullptr), - mTrackHistEfficiency(nullptr), - mEventCount(nullptr), - mEtaMin(0), - mEtaMax(0), - mPtMin(0), - mPtMax(0), - mPartSpecies(-1), - mCentralityMin(0), - mCentralityMax(0), - mZVtxMin(0), - mZVtxMax(0), - mPt2Min(0), - mPt2Max(0), - mTrackEtaCut(0), - mWeightPerEvent(0), - mSkipScaleMixedEvent(kFALSE), - mCache(nullptr), - mGetMultCacheOn(kFALSE), - mGetMultCache(nullptr), - mHistogramType(reqHist) -{ - // Constructor - - using BinList = std::vector<Double_t>; - - if (strlen(reqHist) == 0) { - return; - } - - LOGF(info, "Creating CorrelationContainer with %s (binning: %s)", reqHist, binning); - - const char* title = ""; - - // track level - Int_t nTrackVars = 4; // eta vs pT vs pT,lead (vs delta phi) vs multiplicity - Int_t iTrackBin[7]; - BinList trackBins[7]; - const char* trackAxisTitle[7]; - - // eta - Int_t nEtaBins = -1; - BinList etaBins = getBinning(binning, "eta", nEtaBins); - const char* etaTitle = "#eta"; - - iTrackBin[0] = nEtaBins; - trackBins[0] = etaBins; - trackAxisTitle[0] = etaTitle; - - // delta eta - Int_t nDeltaEtaBins = -1; - BinList deltaEtaBins = getBinning(binning, "delta_eta", nDeltaEtaBins); - - // pT - trackBins[1] = getBinning(binning, "p_t_assoc", iTrackBin[1]); - trackAxisTitle[1] = "p_{T} (GeV/c)"; - - // pT, fine - Int_t npTBinsFine = -1; - BinList pTBinsFine = getBinning(binning, "p_t_eff", npTBinsFine); - - // pT,lead binning 1 - Int_t nLeadingpTBins = -1; - BinList leadingpTBins = getBinning(binning, "p_t_leading", nLeadingpTBins); - - // pT,lead binning 2 - Int_t nLeadingpTBins2 = -1; - BinList leadingpTBins2 = getBinning(binning, "p_t_leading_course", nLeadingpTBins2); - - // phi,lead - Int_t nLeadingPhiBins = -1; - BinList leadingPhiBins = getBinning(binning, "delta_phi", nLeadingPhiBins); - - trackBins[3] = getBinning(binning, "multiplicity", iTrackBin[3]); - trackAxisTitle[3] = "multiplicity"; - - // particle species - const Int_t kNSpeciesBins = 4; // pi, K, p, rest - BinList speciesBins = {-0.5, 0.5, 1.5, 2.5, 3.5}; - - // vtx-z axis - const char* vertexTitle = "z-vtx (cm)"; - Int_t nVertexBins = -1; - BinList vertexBins = getBinning(binning, "vertex", nVertexBins); - Int_t nVertexBinsEff = -1; - BinList vertexBinsEff = getBinning(binning, "vertex_eff", nVertexBinsEff); - - Int_t useVtxAxis = 0; - Int_t useAliTHn = 1; // 0 = don't use | 1 = with float | 2 = with double - - if (TString(reqHist).Contains("Sparse")) { - useAliTHn = 0; - } - if (TString(reqHist).Contains("Double")) { - useAliTHn = 2; - } - - // selection depending on requested histogram - Int_t axis = -1; // 0 = pT,lead, 1 = phi,lead - if (strcmp(reqHist, "NumberDensitypT") == 0) { - axis = 0; - title = "d^{2}N_{ch}/d#varphid#eta"; - } else if (strcmp(reqHist, "NumberDensityPhi") == 0) { - axis = 1; - title = "d^{2}N_{ch}/d#varphid#eta"; - } else if (TString(reqHist).BeginsWith("NumberDensityPhiCentrality")) { - if (TString(reqHist).Contains("Vtx")) { - useVtxAxis = 1; - } - - reqHist = "NumberDensityPhiCentrality"; - mHistogramType = reqHist; - axis = 2; - title = "d^{2}N_{ch}/d#varphid#eta"; - } else if (strcmp(reqHist, "SumpT") == 0) { - axis = 0; - title = "d^{2}#Sigma p_{T}/d#varphid#eta"; - } else if (TString(reqHist).BeginsWith("TwoPlusOne")) { - useVtxAxis = 1; - - reqHist = "TwoPlusOne"; - mHistogramType = reqHist; - axis = 3; - title = "d^{2}N_{ch}/d#varphid#eta"; - } else { - LOGF(fatal, "Invalid histogram requested: %s", reqHist); - } - - UInt_t nSteps = fgkCFSteps; - - if (axis == 0) { - trackBins[2] = leadingpTBins; - iTrackBin[2] = nLeadingpTBins; - trackAxisTitle[2] = "leading p_{T} (GeV/c)"; - - } else if (axis == 1) { - nTrackVars = 5; - - iTrackBin[2] = nLeadingpTBins2; - trackBins[2] = leadingpTBins2; - trackAxisTitle[2] = "leading p_{T} (GeV/c)"; - - iTrackBin[4] = nLeadingPhiBins; - trackBins[4] = leadingPhiBins; - trackAxisTitle[4] = "#Delta #varphi w.r.t. leading track"; - } else if (axis == 2) { - nTrackVars = 5; - - iTrackBin[0] = nDeltaEtaBins; - trackBins[0] = deltaEtaBins; - trackAxisTitle[0] = "#Delta#eta"; - - iTrackBin[2] = nLeadingpTBins2; - trackBins[2] = leadingpTBins2; - trackAxisTitle[2] = "leading p_{T} (GeV/c)"; - - trackAxisTitle[3] = "centrality"; - - iTrackBin[4] = nLeadingPhiBins; - trackBins[4] = leadingPhiBins; - trackAxisTitle[4] = "#Delta#varphi (rad)"; - - if (useVtxAxis > 0) { - nTrackVars = 6; - iTrackBin[5] = nVertexBins; - trackBins[5] = vertexBins; - trackAxisTitle[5] = vertexTitle; - } - } else if (axis == 3) { - nTrackVars = 7; - nSteps = 15; - - iTrackBin[0] = nDeltaEtaBins; - trackBins[0] = deltaEtaBins; - trackAxisTitle[0] = "#Delta#eta"; - - iTrackBin[2] = nLeadingpTBins; - trackBins[2] = leadingpTBins; - trackAxisTitle[2] = "Trigger 1 p_{T} (GeV/c)"; - - trackAxisTitle[3] = "centrality"; - - iTrackBin[4] = nLeadingPhiBins; - trackBins[4] = leadingPhiBins; - trackAxisTitle[4] = "#Delta#varphi (rad)"; - - iTrackBin[5] = nVertexBins; - trackBins[5] = vertexBins; - trackAxisTitle[5] = vertexTitle; - - iTrackBin[6] = nLeadingpTBins2; - trackBins[6] = leadingpTBins2; - trackAxisTitle[6] = "Trigger 2 p_{T} (GeV/c)"; - } - - if (axis >= 2 && useAliTHn == 1) { - mPairHist = new StepTHnF("mPairHist", title, nSteps, nTrackVars, iTrackBin, trackBins, trackAxisTitle); - } else if (axis >= 2 && useAliTHn == 2) { - mPairHist = new StepTHnD("mPairHist", title, nSteps, nTrackVars, iTrackBin, trackBins, trackAxisTitle); - } - - // event level - Int_t nEventVars = 2; - Int_t iEventBin[4] = {0}; - BinList eventBins[4]; - const char* eventAxisTitle[4] = {nullptr}; - - // track 3rd and 4th axis --> event 1st and 2nd axis - iEventBin[0] = iTrackBin[2]; - eventBins[0] = trackBins[2]; - eventAxisTitle[0] = trackAxisTitle[2]; - - iEventBin[1] = iTrackBin[3]; - eventBins[1] = trackBins[3]; - eventAxisTitle[1] = trackAxisTitle[3]; - - // plus track 5th axis (in certain cases) - if (axis >= 2 && useVtxAxis) { - nEventVars = 3; - iEventBin[2] = iTrackBin[5]; - eventBins[2] = trackBins[5]; - eventAxisTitle[2] = trackAxisTitle[5]; - } - if (axis >= 3) { - nEventVars = 4; - iEventBin[3] = iTrackBin[6]; - eventBins[3] = trackBins[6]; - eventAxisTitle[3] = trackAxisTitle[6]; - } - mTriggerHist = new StepTHnF("mTriggerHist", title, nSteps, nEventVars, iEventBin, eventBins, eventAxisTitle); - - // Efficiency histogram - - iTrackBin[0] = nEtaBins; - trackBins[0] = etaBins; - trackAxisTitle[0] = etaTitle; - - iTrackBin[1] = npTBinsFine; - trackBins[1] = pTBinsFine; - //trackAxisTitle[1] = trackAxisTitle[1]; - - iTrackBin[2] = kNSpeciesBins; - trackBins[2] = speciesBins; - trackAxisTitle[2] = "particle species"; - - iTrackBin[4] = nVertexBinsEff; - trackBins[4] = vertexBinsEff; - trackAxisTitle[4] = vertexTitle; - - mTrackHistEfficiency = new StepTHnD("mTrackHistEfficiency", "Tracking efficiency", 6, 5, iTrackBin, trackBins, trackAxisTitle); - - mEventCount = new TH2F("mEventCount", ";step;centrality;count", fgkCFSteps + 2, -2.5, -0.5 + fgkCFSteps, iEventBin[1], &(eventBins[1])[0]); -} - -TString CorrelationContainer::combineBinning(TString defaultBinning, TString customBinning) -{ - // combine default binning with custom binning - // replaces binnings in default binning if it is defined in custom binning - - TString binningStr; - - TObjArray* lines = defaultBinning.Tokenize("\n"); - for (Int_t i = 0; i < lines->GetEntriesFast(); i++) { - TString line(lines->At(i)->GetName()); - TString tag = line(0, line.Index(":") + 1); - if (!customBinning.BeginsWith(tag) && !customBinning.Contains(TString("\n") + tag)) { - binningStr += line + "\n"; - } else { - LOGF(info, "Using custom binning for %s", tag.Data()); - } - } - delete lines; - binningStr += customBinning; - - return binningStr; -} - -std::vector<Double_t> CorrelationContainer::getBinning(const char* configuration, const char* tag, Int_t& nBins) -{ - // takes the binning from <configuration> identified by <tag> - // configuration syntax example: - // equidistant binning: - // eta: 48 | -2.4, 2.4 - // variable-width binning: - // eta: -2.4, -2.3, -2.2, -2.1, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4 - // - // returns bin edges which have to be deleted by the caller - - std::vector<Double_t> bins; - TString config(configuration); - TObjArray* lines = config.Tokenize("\n"); - for (Int_t i = 0; i < lines->GetEntriesFast(); i++) { - TString line(lines->At(i)->GetName()); - if (line.BeginsWith(TString(tag) + ":")) { - line.Remove(0, strlen(tag) + 1); - line.ReplaceAll(" ", ""); - if (line.Contains("|")) { - // equidistant binning - nBins = TString(line(0, line.Index("|"))).Atoi(); - line.Remove(0, line.Index("|") + 1); - } else { - // variable-width binning - nBins = line.CountChar(','); - } - TObjArray* binning = line.Tokenize(","); - //Double_t* bins = new Double_t[binning->GetEntriesFast()]; - for (Int_t j = 0; j < binning->GetEntriesFast(); j++) { - bins.push_back(TString(binning->At(j)->GetName()).Atof()); - } - delete binning; - delete lines; - return bins; - } - } - - delete lines; - LOGF(fatal, "Tag %s not found in %s", tag, configuration); - return bins; -} - -//_____________________________________________________________________________ -CorrelationContainer::CorrelationContainer(const CorrelationContainer& c) : TNamed(c), - mPairHist(nullptr), - mTriggerHist(nullptr), - mTrackHistEfficiency(nullptr), - mEtaMin(0), - mEtaMax(0), - mPtMin(0), - mPtMax(0), - mPartSpecies(-1), - mCentralityMin(0), - mCentralityMax(0), - mZVtxMin(0), - mZVtxMax(0), - mPt2Min(0), - mPt2Max(0), - mTrackEtaCut(0), - mWeightPerEvent(0), - mSkipScaleMixedEvent(kFALSE), - mCache(nullptr), - mGetMultCacheOn(kFALSE), - mGetMultCache(nullptr), - mHistogramType() -{ - // - // CorrelationContainer copy constructor - // - - ((CorrelationContainer&)c).Copy(*this); -} - -//____________________________________________________________________ -CorrelationContainer::~CorrelationContainer() -{ - // Destructor - - if (mPairHist) { - delete mPairHist; - mPairHist = nullptr; - } - - if (mTriggerHist) { - delete mTriggerHist; - mTriggerHist = nullptr; - } - - if (mTrackHistEfficiency) { - delete mTrackHistEfficiency; - mTrackHistEfficiency = nullptr; - } - - if (mCache) { - delete mCache; - mCache = nullptr; - } -} - -//____________________________________________________________________ -CorrelationContainer& CorrelationContainer::operator=(const CorrelationContainer& c) -{ - // assigment operator - - if (this != &c) { - ((CorrelationContainer&)c).Copy(*this); - } - - return *this; -} - -//____________________________________________________________________ -void CorrelationContainer::Copy(TObject& c) const -{ - // copy function - - CorrelationContainer& target = (CorrelationContainer&)c; - - if (mPairHist) { - target.mPairHist = dynamic_cast<StepTHn*>(mPairHist->Clone()); - } - - if (mTriggerHist) { - target.mTriggerHist = dynamic_cast<StepTHn*>(mTriggerHist->Clone()); - } - - if (mTrackHistEfficiency) { - target.mTrackHistEfficiency = dynamic_cast<StepTHn*>(mTrackHistEfficiency->Clone()); - } - - target.mEtaMin = mEtaMin; - target.mEtaMax = mEtaMax; - target.mPtMin = mPtMin; - target.mPtMax = mPtMax; - target.mPartSpecies = mPartSpecies; - target.mCentralityMin = mCentralityMin; - target.mCentralityMax = mCentralityMax; - target.mZVtxMin = mZVtxMin; - target.mZVtxMax = mZVtxMax; - target.mPt2Min = mPt2Min; - target.mPt2Max = mPt2Max; - target.mTrackEtaCut = mTrackEtaCut; - target.mWeightPerEvent = mWeightPerEvent; - target.mSkipScaleMixedEvent = mSkipScaleMixedEvent; - target.mHistogramType = mHistogramType; -} - -//____________________________________________________________________ -Long64_t CorrelationContainer::Merge(TCollection* list) -{ - // Merge a list of CorrelationContainer objects with this (needed for - // PROOF). - // Returns the number of merged objects (including this). - - if (!list) { - return 0; - } - - if (list->IsEmpty()) { - return 1; - } - - TIterator* iter = list->MakeIterator(); - TObject* obj = nullptr; - - // collections of objects - const UInt_t kMaxLists = 4; - TList** lists = new TList*[kMaxLists]; - - for (UInt_t i = 0; i < kMaxLists; i++) { - lists[i] = new TList; - } - - Int_t count = 0; - while ((obj = iter->Next())) { - - CorrelationContainer* entry = dynamic_cast<CorrelationContainer*>(obj); - if (entry == nullptr) { - continue; - } - - if (entry->mPairHist) { - lists[0]->Add(entry->mPairHist); - } - - lists[1]->Add(entry->mTriggerHist); - lists[2]->Add(entry->mTrackHistEfficiency); - lists[3]->Add(entry->mEventCount); - - count++; - } - if (mPairHist) { - mPairHist->Merge(lists[0]); - } - - mTriggerHist->Merge(lists[1]); - mTrackHistEfficiency->Merge(lists[2]); - mEventCount->Merge(lists[3]); - - for (UInt_t i = 0; i < kMaxLists; i++) { - delete lists[i]; - } - - delete[] lists; - - return count + 1; -} - -//____________________________________________________________________ -void CorrelationContainer::setBinLimits(THnBase* grid) -{ - // sets the bin limits in eta and pT defined by mEtaMin/Max, mPtMin/Max - - if (mEtaMax > mEtaMin) { - grid->GetAxis(0)->SetRangeUser(mEtaMin, mEtaMax); - } - if (mPtMax > mPtMin) { - grid->GetAxis(1)->SetRangeUser(mPtMin, mPtMax); - } - if (mPt2Min > 0 && mPt2Max > 0) { - grid->GetAxis(6)->SetRangeUser(mPt2Min, mPt2Max); - } else if (mPt2Min > 0) { - grid->GetAxis(6)->SetRangeUser(mPt2Min, grid->GetAxis(6)->GetXmax() - 0.01); - } -} - -//____________________________________________________________________ -void CorrelationContainer::resetBinLimits(THnBase* grid) -{ - // resets all bin limits - - for (Int_t i = 0; i < grid->GetNdimensions(); i++) { - if (grid->GetAxis(i)->TestBit(TAxis::kAxisRange)) { - grid->GetAxis(i)->SetRangeUser(0, -1); - } - } -} - -//____________________________________________________________________ -void CorrelationContainer::countEmptyBins(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax) -{ - // prints the number of empty bins in the track end event histograms in the given step - - Int_t binBegin[4]; - Int_t binEnd[4]; - - for (Int_t i = 0; i < 4; i++) { - binBegin[i] = 1; - binEnd[i] = mPairHist->getTHn(step)->GetAxis(i)->GetNbins(); - } - - if (mEtaMax > mEtaMin) { - binBegin[0] = mPairHist->getTHn(step)->GetAxis(0)->FindBin(mEtaMin); - binEnd[0] = mPairHist->getTHn(step)->GetAxis(0)->FindBin(mEtaMax); - } - - if (mPtMax > mPtMin) { - binBegin[1] = mPairHist->getTHn(step)->GetAxis(1)->FindBin(mPtMin); - binEnd[1] = mPairHist->getTHn(step)->GetAxis(1)->FindBin(mPtMax); - } - - if (ptTriggerMax > ptTriggerMin) { - binBegin[2] = mPairHist->getTHn(step)->GetAxis(2)->FindBin(ptTriggerMin); - binEnd[2] = mPairHist->getTHn(step)->GetAxis(2)->FindBin(ptTriggerMax); - } - - // start from multiplicity 1 - binBegin[3] = mPairHist->getTHn(step)->GetAxis(3)->FindBin(1); - - Int_t total = 0; - Int_t count = 0; - Int_t vars[4]; - - for (Int_t i = 0; i < 4; i++) { - vars[i] = binBegin[i]; - } - - THnBase* grid = mPairHist->getTHn(step); - while (1) { - if (grid->GetBin(vars) == 0) { - LOGF(warning, "Empty bin at eta=%.2f pt=%.2f pt_lead=%.2f mult=%.1f", - grid->GetAxis(0)->GetBinCenter(vars[0]), - grid->GetAxis(1)->GetBinCenter(vars[1]), - grid->GetAxis(2)->GetBinCenter(vars[2]), - grid->GetAxis(3)->GetBinCenter(vars[3])); - count++; - } - - vars[3]++; - for (Int_t i = 3; i > 0; i--) { - if (vars[i] == binEnd[i] + 1) { - vars[i] = binBegin[i]; - vars[i - 1]++; - } - } - - if (vars[0] == binEnd[0] + 1) { - break; - } - total++; - } - - LOGF(info, "Has %d empty bins (out of %d bins)", count, total); -} - -//____________________________________________________________________ -void CorrelationContainer::getHistsZVtxMult(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, THnBase** trackHist, TH2** eventHist) -{ - // Calculates a 4d histogram with deltaphi, deltaeta, zvtx, multiplicity on track level and - // a 2d histogram on event level (as fct of zvtx, multiplicity) - // Histograms has to be deleted by the caller of the function - - THnBase* sparse = mPairHist->getTHn(step); - if (mGetMultCacheOn) { - if (!mGetMultCache) { - mGetMultCache = changeToThn(sparse); - // should work but causes SEGV in ProjectionND below - } - sparse = mGetMultCache; - } - - // unzoom all axes - resetBinLimits(sparse); - resetBinLimits(mTriggerHist->getTHn(step)); - - setBinLimits(sparse); - - Int_t firstBin = sparse->GetAxis(2)->FindBin(ptTriggerMin); - Int_t lastBin = sparse->GetAxis(2)->FindBin(ptTriggerMax); - LOGF(info, "Using trigger pT range %d --> %d", firstBin, lastBin); - sparse->GetAxis(2)->SetRange(firstBin, lastBin); - mTriggerHist->getTHn(step)->GetAxis(0)->SetRange(firstBin, lastBin); - - // cut on the second trigger particle if there is a minimum set - if (mPt2Min > 0) { - Int_t firstBinPt2 = sparse->GetAxis(6)->FindBin(mPt2Min); - Int_t lastBinPt2 = sparse->GetAxis(6)->GetNbins(); - if (mPt2Max > 0) { - lastBinPt2 = sparse->GetAxis(6)->FindBin(mPt2Max); - } - - mTriggerHist->getTHn(step)->GetAxis(3)->SetRange(firstBinPt2, lastBinPt2); - } - - Bool_t hasVertex = kTRUE; - if (!mPairHist->getTHn(step)->GetAxis(5)) { - hasVertex = kFALSE; - } - - if (hasVertex) { - Int_t dimensions[] = {4, 0, 5, 3}; - THnBase* tmpTrackHist = sparse->ProjectionND(4, dimensions, "E"); - *eventHist = (TH2*)mTriggerHist->getTHn(step)->Projection(2, 1); - // convert to THn - *trackHist = changeToThn(tmpTrackHist); - delete tmpTrackHist; - } else { - Int_t dimensions[] = {4, 0, 3}; - THnBase* tmpTrackHist = sparse->ProjectionND(3, dimensions, "E"); - - // add dummy vertex axis, so that the extraction code can work as usual - Int_t nBins[] = {tmpTrackHist->GetAxis(0)->GetNbins(), tmpTrackHist->GetAxis(1)->GetNbins(), 1, tmpTrackHist->GetAxis(2)->GetNbins()}; - Double_t vtxAxis[] = {-100, 100}; - - *trackHist = new THnF(Form("%s_thn", tmpTrackHist->GetName()), tmpTrackHist->GetTitle(), 4, nBins, nullptr, nullptr); - - for (int i = 0; i < 3; i++) { - int j = i; - if (i == 2) { - j = 3; - } - - (*trackHist)->SetBinEdges(j, tmpTrackHist->GetAxis(i)->GetXbins()->GetArray()); - (*trackHist)->GetAxis(j)->SetTitle(tmpTrackHist->GetAxis(i)->GetTitle()); - } - - (*trackHist)->SetBinEdges(2, vtxAxis); - (*trackHist)->GetAxis(2)->SetTitle("dummy z-vtx"); - - // bin by bin copy... - Int_t bins[4]; - for (Int_t binIdx = 0; binIdx < tmpTrackHist->GetNbins(); binIdx++) { - Double_t value = tmpTrackHist->GetBinContent(binIdx, bins); - Double_t error = tmpTrackHist->GetBinError(binIdx); - - // move third to fourth axis - bins[3] = bins[2]; - bins[2] = 1; - - (*trackHist)->SetBinContent(bins, value); - (*trackHist)->SetBinError(bins, error); - } - - delete tmpTrackHist; - - TH1* projEventHist = (TH1*)mTriggerHist->getTHn(step)->Projection(1); - *eventHist = new TH2F(Form("%s_vtx", projEventHist->GetName()), projEventHist->GetTitle(), 1, vtxAxis, projEventHist->GetNbinsX(), projEventHist->GetXaxis()->GetXbins()->GetArray()); - for (Int_t binIdx = 1; binIdx <= projEventHist->GetNbinsX(); binIdx++) { - (*eventHist)->SetBinContent(1, binIdx, projEventHist->GetBinContent(binIdx)); - (*eventHist)->SetBinError(1, binIdx, projEventHist->GetBinError(binIdx)); - } - - delete projEventHist; - } - - resetBinLimits(sparse); - resetBinLimits(mTriggerHist->getTHn(step)); -} - -TH2* CorrelationContainer::getPerTriggerYield(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, Bool_t normalizePerTrigger) -{ - // Calculate per trigger yield without considering mixed event - // Sums over all vertex bins, and respects the pT and centrality limits set in the class - // - // returns a 2D histogram: deltaphi, deltaeta - // - // Parameters: - // step: Step for which the histogram is received - // ptTriggerMin, ptTriggerMax: trigger pT range - // normalizePerTrigger: divide through number of triggers - - THnBase* trackSameAll = nullptr; - TH2* eventSameAll = nullptr; - - Long64_t totalEvents = 0; - Int_t nCorrelationFunctions = 0; - - getHistsZVtxMult(step, ptTriggerMin, ptTriggerMax, &trackSameAll, &eventSameAll); - - TAxis* multAxis = trackSameAll->GetAxis(3); - int multBinBegin = 1; - int multBinEnd = multAxis->GetNbins(); - if (mCentralityMin < mCentralityMax) { - multBinBegin = multAxis->FindBin(mCentralityMin + 1e-4); - multBinEnd = multAxis->FindBin(mCentralityMax - 1e-4); - LOGF(info, "Using multiplicity range %d --> %d", multBinBegin, multBinEnd); - - trackSameAll->GetAxis(3)->SetRange(multBinBegin, multBinEnd); - } - - TAxis* vertexAxis = trackSameAll->GetAxis(2); - int vertexBinBegin = 1; - int vertexBinEnd = vertexAxis->GetNbins(); - if (mZVtxMax > mZVtxMin) { - vertexBinBegin = vertexAxis->FindBin(mZVtxMin); - vertexBinEnd = vertexAxis->FindBin(mZVtxMax); - LOGF(info, "Using vertex range %d --> %d", vertexBinBegin, vertexBinEnd); - - trackSameAll->GetAxis(2)->SetRange(vertexBinBegin, vertexBinEnd); - } - - TH2* yield = trackSameAll->Projection(1, 0, "E"); - Float_t triggers = eventSameAll->Integral(multBinBegin, multBinEnd, vertexBinBegin, vertexBinEnd); - - if (normalizePerTrigger) { - LOGF(info, "Dividing %f tracks by %f triggers", yield->Integral(), triggers); - if (triggers > 0) { - yield->Scale(1.0 / triggers); - } - } - - // normalizate to dphi width - Float_t normalization = yield->GetXaxis()->GetBinWidth(1); - yield->Scale(1.0 / normalization); - - delete trackSameAll; - delete eventSameAll; - - return yield; -} - -TH2* CorrelationContainer::getSumOfRatios(CorrelationContainer* mixed, CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax, Bool_t normalizePerTrigger, Int_t stepForMixed, Int_t* trigger) -{ - // Extract 2D per trigger yield with mixed event correction. The quantity is calculated for *each* vertex bin and multiplicity bin and then a sum of ratios is performed: - // 1_N [ (same/mixed)_1 + (same/mixed)_2 + (same/mixed)_3 + ... ] - // where N is the total number of events/trigger particles and the subscript is the vertex/multiplicity bin - // where mixed is normalized such that the information about the number of pairs in same is kept - // - // returns a 2D histogram: deltaphi, deltaeta - // - // Parameters: - // mixed: CorrelationContainer containing mixed event corresponding to this object (the histograms are taken from step <stepForMixed> if defined otherwise from step <step>) - // step: Step for which the histogram is received - // ptTriggerMin, ptTriggerMax: trigger pT range - // normalizePerTrigger: divide through number of triggers - - // do not add this hists to the directory - Bool_t oldStatus = TH1::AddDirectoryStatus(); - TH1::AddDirectory(kFALSE); - - TH2* totalTracks = nullptr; - - THnBase* trackSameAll = nullptr; - THnBase* trackMixedAll = nullptr; - THnBase* trackMixedAllStep6 = nullptr; - TH2* eventSameAll = nullptr; - TH2* eventMixedAll = nullptr; - TH2* eventMixedAllStep6 = nullptr; - - Long64_t totalEvents = 0; - Int_t nCorrelationFunctions = 0; - - getHistsZVtxMult(step, ptTriggerMin, ptTriggerMax, &trackSameAll, &eventSameAll); - mixed->getHistsZVtxMult((stepForMixed == -1) ? step : (CFStep)stepForMixed, ptTriggerMin, ptTriggerMax, &trackMixedAll, &eventMixedAll); - - // If we ask for histograms from step8 (TTR cut applied) there is a hole at 0,0; so this cannot be used for the - // mixed-event normalization. If step6 is available, the normalization factor is read out from that one. - // If step6 is not available we fallback to taking the normalization along all delta phi (WARNING requires a - // flat delta phi distribution) - if (stepForMixed == -1 && step == kCFStepBiasStudy && mixed->mTriggerHist->getTHn(kCFStepReconstructed)->GetEntries() > 0 && !mSkipScaleMixedEvent) { - LOGF(info, "Using mixed-event normalization factors from step %d", kCFStepReconstructed); - mixed->getHistsZVtxMult(kCFStepReconstructed, ptTriggerMin, ptTriggerMax, &trackMixedAllStep6, &eventMixedAllStep6); - } - - // Printf("%f %f %f %f", trackSameAll->GetEntries(), eventSameAll->GetEntries(), trackMixedAll->GetEntries(), eventMixedAll->GetEntries()); - - // TH1* normParameters = new TH1F("normParameters", "", 100, 0, 2); - - // trackSameAll->Dump(); - - TAxis* multAxis = trackSameAll->GetAxis(3); - - int multBinBegin = 1; - int multBinEnd = multAxis->GetNbins(); - if (mCentralityMin < mCentralityMax) { - multBinBegin = multAxis->FindBin(mCentralityMin); - multBinEnd = multAxis->FindBin(mCentralityMax); - } - - for (Int_t multBin = TMath::Max(1, multBinBegin); multBin <= TMath::Min(multAxis->GetNbins(), multBinEnd); multBin++) { - trackSameAll->GetAxis(3)->SetRange(multBin, multBin); - trackMixedAll->GetAxis(3)->SetRange(multBin, multBin); - if (trackMixedAllStep6) { - trackMixedAllStep6->GetAxis(3)->SetRange(multBin, multBin); - } - - Double_t mixedNorm = 1; - Double_t mixedNormError = 0; - - if (!mSkipScaleMixedEvent) { - // get mixed normalization correction factor: is independent of vertex bin if scaled with number of triggers - TH2* tracksMixed = nullptr; - if (trackMixedAllStep6) { - trackMixedAllStep6->GetAxis(2)->SetRange(0, -1); - tracksMixed = trackMixedAllStep6->Projection(1, 0, "E"); - } else { - trackMixedAll->GetAxis(2)->SetRange(0, -1); - tracksMixed = trackMixedAll->Projection(1, 0, "E"); - } - // Printf("%f", tracksMixed->Integral()); - Float_t binWidthEta = tracksMixed->GetYaxis()->GetBinWidth(1); - - if (stepForMixed == -1 && step == kCFStepBiasStudy && !trackMixedAllStep6) { - // get mixed event normalization by assuming full acceptance at deta at 0 (integrate over dphi), excluding (0, 0) - Float_t phiExclude = 0.41; - mixedNorm = tracksMixed->IntegralAndError(1, tracksMixed->GetXaxis()->FindBin(-phiExclude) - 1, tracksMixed->GetYaxis()->FindBin(-0.01), tracksMixed->GetYaxis()->FindBin(0.01), mixedNormError); - Double_t mixedNormError2 = 0; - Double_t mixedNorm2 = tracksMixed->IntegralAndError(tracksMixed->GetXaxis()->FindBin(phiExclude) + 1, tracksMixed->GetNbinsX(), tracksMixed->GetYaxis()->FindBin(-0.01), tracksMixed->GetYaxis()->FindBin(0.01), mixedNormError2); - - if (mixedNormError == 0 || mixedNormError2 == 0) { - LOGF(error, "ERROR: Skipping multiplicity %d because mixed event is empty %f %f %f %f", multBin, mixedNorm, mixedNormError, mixedNorm2, mixedNormError2); - continue; - } - - Int_t nBinsMixedNorm = (tracksMixed->GetXaxis()->FindBin(-phiExclude) - 1 - 1 + 1) * (tracksMixed->GetYaxis()->FindBin(0.01) - tracksMixed->GetYaxis()->FindBin(-0.01) + 1); - mixedNorm /= nBinsMixedNorm; - mixedNormError /= nBinsMixedNorm; - - Int_t nBinsMixedNorm2 = (tracksMixed->GetNbinsX() - tracksMixed->GetXaxis()->FindBin(phiExclude) - 1 + 1) * (tracksMixed->GetYaxis()->FindBin(0.01) - tracksMixed->GetYaxis()->FindBin(-0.01) + 1); - mixedNorm2 /= nBinsMixedNorm2; - mixedNormError2 /= nBinsMixedNorm2; - - mixedNorm = mixedNorm / mixedNormError / mixedNormError + mixedNorm2 / mixedNormError2 / mixedNormError2; - mixedNormError = TMath::Sqrt(1.0 / (1.0 / mixedNormError / mixedNormError + 1.0 / mixedNormError2 / mixedNormError2)); - mixedNorm *= mixedNormError * mixedNormError; - } else { - // get mixed event normalization at (0,0) - - // NOTE if variable bin size is used around (0,0) to reduce two-track effect to limited bins, the normalization gets a bit tricky here (finite bin correction and normalization are made only for fixed size bins). - // The normalization factor has to determined in a bin as large as the normal bin size, as a proxy the bin with index (1, 1) is used - Float_t binWidthPhi = tracksMixed->GetXaxis()->GetBinWidth(1); - - mixedNorm = tracksMixed->IntegralAndError(tracksMixed->GetXaxis()->FindBin(-binWidthPhi + 1e-4), tracksMixed->GetXaxis()->FindBin(binWidthPhi - 1e-4), tracksMixed->GetYaxis()->FindBin(-binWidthEta + 1e-4), tracksMixed->GetYaxis()->FindBin(binWidthEta - 1e-4), mixedNormError); - Int_t nBinsMixedNorm = 4; // NOTE this is fixed on purpose, even if binning is made finer around (0,0), this corresponds to the equivalent of four "large" bins around (0,0) - mixedNorm /= nBinsMixedNorm; - mixedNormError /= nBinsMixedNorm; - - if (mixedNormError == 0) { - LOGF(error, "ERROR: Skipping multiplicity %d because mixed event is empty %f %f", multBin, mixedNorm, mixedNormError); - continue; - } - } - - // finite bin correction - if (mTrackEtaCut > 0) { - Double_t finiteBinCorrection = -1.0 / (2 * mTrackEtaCut) * binWidthEta / 2 + 1; - LOGF(info, "Finite bin correction: %f", finiteBinCorrection); - mixedNorm /= finiteBinCorrection; - mixedNormError /= finiteBinCorrection; - } else { - LOGF(error, "ERROR: mTrackEtaCut not set. Finite bin correction cannot be applied. Continuing anyway..."); - } - - Float_t triggers = eventMixedAll->Integral(1, eventMixedAll->GetNbinsX(), multBin, multBin); - // Printf("%f +- %f | %f | %f", mixedNorm, mixedNormError, triggers, mixedNorm / triggers); - if (triggers <= 0) { - LOGF(error, "ERROR: Skipping multiplicity %d because mixed event is empty", multBin); - continue; - } - - mixedNorm /= triggers; - mixedNormError /= triggers; - - delete tracksMixed; - } else { - LOGF(warning, "WARNING: Skipping mixed-event scaling! mSkipScaleMixedEvent IS set!"); - } - - if (mixedNorm <= 0) { - LOGF(error, "ERROR: Skipping multiplicity %d because mixed event is empty at (0,0)", multBin); - continue; - } - - // Printf("Norm: %f +- %f", mixedNorm, mixedNormError); - - // normParameters->Fill(mixedNorm); - - TAxis* vertexAxis = trackSameAll->GetAxis(2); - Int_t vertexBinBegin = 1; - Int_t vertexBinEnd = vertexAxis->GetNbins(); - - if (mZVtxMax > mZVtxMin) { - vertexBinBegin = vertexAxis->FindBin(mZVtxMin); - vertexBinEnd = vertexAxis->FindBin(mZVtxMax); - } - - for (Int_t vertexBin = vertexBinBegin; vertexBin <= vertexBinEnd; vertexBin++) { - trackSameAll->GetAxis(2)->SetRange(vertexBin, vertexBin); - trackMixedAll->GetAxis(2)->SetRange(vertexBin, vertexBin); - - TH2* tracksSame = trackSameAll->Projection(1, 0, "E"); - TH2* tracksMixed = trackMixedAll->Projection(1, 0, "E"); - - // asssume flat in dphi, gain in statistics - // TH1* histMixedproj = mixedTwoD->ProjectionY(); - // histMixedproj->Scale(1.0 / mixedTwoD->GetNbinsX()); - // - // for (Int_t x=1; x<=mixedTwoD->GetNbinsX(); x++) - // for (Int_t y=1; y<=mixedTwoD->GetNbinsY(); y++) - // mixedTwoD->SetBinContent(x, y, histMixedproj->GetBinContent(y)); - - // delete histMixedproj; - - Float_t triggers2 = eventMixedAll->Integral(vertexBin, vertexBin, multBin, multBin); - if (triggers2 <= 0) { - LOGF(error, "ERROR: Skipping multiplicity %d vertex bin %d because mixed event is empty", multBin, vertexBin); - } else { - if (!mSkipScaleMixedEvent) { - tracksMixed->Scale(1.0 / triggers2 / mixedNorm); - } else if (tracksMixed->Integral() > 0) { - tracksMixed->Scale(1.0 / tracksMixed->Integral()); - } - // tracksSame->Scale(tracksMixed->Integral() / tracksSame->Integral()); - - // new TCanvas; tracksSame->DrawClone("SURF1"); - // new TCanvas; tracksMixed->DrawClone("SURF1"); - - // some code to judge the relative contribution of the different correlation functions to the overall uncertainty - Double_t sums[] = {0, 0, 0}; - Double_t errors[] = {0, 0, 0}; - - for (Int_t x = 1; x <= tracksSame->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tracksSame->GetNbinsY(); y++) { - sums[0] += tracksSame->GetBinContent(x, y); - errors[0] += tracksSame->GetBinError(x, y); - sums[1] += tracksMixed->GetBinContent(x, y); - errors[1] += tracksMixed->GetBinError(x, y); - } - } - - tracksSame->Divide(tracksMixed); - - for (Int_t x = 1; x <= tracksSame->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tracksSame->GetNbinsY(); y++) { - sums[2] += tracksSame->GetBinContent(x, y); - errors[2] += tracksSame->GetBinError(x, y); - } - } - - for (Int_t x = 0; x < 3; x++) { - if (sums[x] > 0) { - errors[x] /= sums[x]; - } - } - - LOGF(info, "The correlation function %d %d has uncertainties %f %f %f (Ratio S/M %f)", multBin, vertexBin, errors[0], errors[1], errors[2], (errors[1] > 0) ? errors[0] / errors[1] : -1); - // code to draw contributions - /* - TH1* proj = tracksSame->ProjectionX("projx", tracksSame->GetYaxis()->FindBin(-1.59), tracksSame->GetYaxis()->FindBin(1.59)); - proj->SetTitle(Form("Bin %d", vertexBin)); - proj->SetLineColor(vertexBin); - proj->DrawCopy((vertexBin > 1) ? "SAME" : ""); - */ - - if (!totalTracks) { - totalTracks = (TH2*)tracksSame->Clone("totalTracks"); - } else { - totalTracks->Add(tracksSame); - } - - totalEvents += eventSameAll->GetBinContent(vertexBin, multBin); - - // new TCanvas; tracksMixed->DrawCopy("SURF1"); - } - - delete tracksSame; - delete tracksMixed; - - nCorrelationFunctions++; - } - } - - if (totalTracks) { - Double_t sums[] = {0, 0, 0}; - Double_t errors[] = {0, 0, 0}; - - for (Int_t x = 1; x <= totalTracks->GetNbinsX(); x++) { - for (Int_t y = 1; y <= totalTracks->GetNbinsY(); y++) { - sums[0] += totalTracks->GetBinContent(x, y); - errors[0] += totalTracks->GetBinError(x, y); - } - } - if (sums[0] > 0) { - errors[0] /= sums[0]; - } - - if (normalizePerTrigger) { - LOGF(info, "Dividing %f tracks by %lld events (%d correlation function(s)) (error %f)", totalTracks->Integral(), totalEvents, nCorrelationFunctions, errors[0]); - if (totalEvents > 0) { - totalTracks->Scale(1.0 / totalEvents); - } - } - if (trigger != nullptr) { - *trigger = (Int_t)totalEvents; - } - - // normalizate to dphi width - Float_t normalization = totalTracks->GetXaxis()->GetBinWidth(1); - totalTracks->Scale(1.0 / normalization); - } - - delete trackSameAll; - delete trackMixedAll; - delete trackMixedAllStep6; - delete eventSameAll; - delete eventMixedAll; - delete eventMixedAllStep6; - - // new TCanvas; normParameters->Draw(); - - TH1::AddDirectory(oldStatus); - - return totalTracks; -} - -TH1* CorrelationContainer::getTriggersAsFunctionOfMultiplicity(CorrelationContainer::CFStep step, Float_t ptTriggerMin, Float_t ptTriggerMax) -{ - // returns the distribution of triggers as function of centrality/multiplicity - - resetBinLimits(mTriggerHist->getTHn(step)); - - Int_t firstBin = mTriggerHist->getTHn(step)->GetAxis(0)->FindBin(ptTriggerMin); - Int_t lastBin = mTriggerHist->getTHn(step)->GetAxis(0)->FindBin(ptTriggerMax); - LOGF(info, "Using pT range %d --> %d", firstBin, lastBin); - mTriggerHist->getTHn(step)->GetAxis(0)->SetRange(firstBin, lastBin); - - if (mZVtxMax > mZVtxMin) { - mTriggerHist->getTHn(step)->GetAxis(2)->SetRangeUser(mZVtxMin, mZVtxMax); - LOGF(info, "Restricting z-vtx: %f-%f", mZVtxMin, mZVtxMax); - } - - TH1* eventHist = mTriggerHist->getTHn(step)->Projection(1); - - resetBinLimits(mTriggerHist->getTHn(step)); - - return eventHist; -} - -THnBase* CorrelationContainer::getTrackEfficiencyND(CFStep step1, CFStep step2) -{ - // creates a track-level efficiency by dividing step2 by step1 - // in all dimensions but the particle species one - - StepTHn* sourceContainer = mTrackHistEfficiency; - // step offset because we start with kCFStepAnaTopology - step1 = (CFStep)((Int_t)step1 - (Int_t)kCFStepAnaTopology); - step2 = (CFStep)((Int_t)step2 - (Int_t)kCFStepAnaTopology); - - resetBinLimits(sourceContainer->getTHn(step1)); - resetBinLimits(sourceContainer->getTHn(step2)); - - if (mEtaMax > mEtaMin) { - LOGF(info, "Restricted eta-range to %f %f", mEtaMin, mEtaMax); - sourceContainer->getTHn(step1)->GetAxis(0)->SetRangeUser(mEtaMin, mEtaMax); - sourceContainer->getTHn(step2)->GetAxis(0)->SetRangeUser(mEtaMin, mEtaMax); - } - - Int_t dimensions[] = {0, 1, 3, 4}; - THnBase* generated = sourceContainer->getTHn(step1)->ProjectionND(4, dimensions); - THnBase* measured = sourceContainer->getTHn(step2)->ProjectionND(4, dimensions); - - // Printf("%d %d %f %f", step1, step2, generated->GetEntries(), measured->GetEntries()); - - resetBinLimits(sourceContainer->getTHn(step1)); - resetBinLimits(sourceContainer->getTHn(step2)); - - THnBase* clone = (THnBase*)measured->Clone(); - - clone->Divide(measured, generated, 1, 1, "B"); - - delete generated; - delete measured; - - return clone; -} - -//____________________________________________________________________ -TH1* CorrelationContainer::getTrackEfficiency(CFStep step1, CFStep step2, Int_t axis1, Int_t axis2, Int_t source, Int_t axis3) -{ - // creates a track-level efficiency by dividing step2 by step1 - // projected to axis1 and axis2 (optional if >= 0) - // - // source: 0 = mTrackHist; 1 = mTrackHistEfficiency; 2 = mTrackHistEfficiency rebinned for pT,T / pT,lead binning - - // cache it for efficiency (usually more than one efficiency is requested) - - StepTHn* sourceContainer = nullptr; - - if (source == 0) { - return nullptr; - } else if (source == 1 || source == 2) { - sourceContainer = mTrackHistEfficiency; - // step offset because we start with kCFStepAnaTopology - step1 = (CFStep)((Int_t)step1 - (Int_t)kCFStepAnaTopology); - step2 = (CFStep)((Int_t)step2 - (Int_t)kCFStepAnaTopology); - } else { - return nullptr; - } - - // reset all limits and set the right ones except those in axis1, axis2 and axis3 - resetBinLimits(sourceContainer->getTHn(step1)); - resetBinLimits(sourceContainer->getTHn(step2)); - if (mEtaMax > mEtaMin && axis1 != 0 && axis2 != 0 && axis3 != 0) { - LOGF(info, "Restricted eta-range to %f %f", mEtaMin, mEtaMax); - sourceContainer->getTHn(step1)->GetAxis(0)->SetRangeUser(mEtaMin, mEtaMax); - sourceContainer->getTHn(step2)->GetAxis(0)->SetRangeUser(mEtaMin, mEtaMax); - } - if (mPtMax > mPtMin && axis1 != 1 && axis2 != 1 && axis3 != 1) { - LOGF(info, "Restricted pt-range to %f %f", mPtMin, mPtMax); - sourceContainer->getTHn(step1)->GetAxis(1)->SetRangeUser(mPtMin, mPtMax); - sourceContainer->getTHn(step2)->GetAxis(1)->SetRangeUser(mPtMin, mPtMax); - } - if (mPartSpecies != -1 && axis1 != 2 && axis2 != 2 && axis3 != 2) { - LOGF(info, "Restricted to particle species %d", mPartSpecies); - sourceContainer->getTHn(step1)->GetAxis(2)->SetRangeUser(mPartSpecies, mPartSpecies); - sourceContainer->getTHn(step2)->GetAxis(2)->SetRangeUser(mPartSpecies, mPartSpecies); - } - if (mCentralityMax > mCentralityMin && axis1 != 3 && axis2 != 3 && axis3 != 3) { - LOGF(info, "Restricted centrality range to %f %f", mCentralityMin, mCentralityMax); - sourceContainer->getTHn(step1)->GetAxis(3)->SetRangeUser(mCentralityMin, mCentralityMax); - sourceContainer->getTHn(step2)->GetAxis(3)->SetRangeUser(mCentralityMin, mCentralityMax); - } - if (mZVtxMax > mZVtxMin && axis1 != 4 && axis2 != 4 && axis3 != 4) { - LOGF(info, "Restricted z-vtx range to %f %f", mZVtxMin, mZVtxMax); - sourceContainer->getTHn(step1)->GetAxis(4)->SetRangeUser(mZVtxMin, mZVtxMax); - sourceContainer->getTHn(step2)->GetAxis(4)->SetRangeUser(mZVtxMin, mZVtxMax); - } - - TH1* measured = nullptr; - TH1* generated = nullptr; - - if (axis3 >= 0) { - generated = sourceContainer->getTHn(step1)->Projection(axis1, axis2, axis3); - measured = sourceContainer->getTHn(step2)->Projection(axis1, axis2, axis3); - } else if (axis2 >= 0) { - generated = sourceContainer->getTHn(step1)->Projection(axis1, axis2); - measured = sourceContainer->getTHn(step2)->Projection(axis1, axis2); - } else { - generated = sourceContainer->getTHn(step1)->Projection(axis1); - measured = sourceContainer->getTHn(step2)->Projection(axis1); - } - - // check for bins with less than 50 entries, print warning - Int_t binBegin[3]; - Int_t binEnd[3]; - - binBegin[0] = 1; - binBegin[1] = 1; - binBegin[2] = 1; - - binEnd[0] = generated->GetNbinsX(); - binEnd[1] = generated->GetNbinsY(); - binEnd[2] = generated->GetNbinsZ(); - - if (mEtaMax > mEtaMin) { - if (axis1 == 0) { - binBegin[0] = generated->GetXaxis()->FindBin(mEtaMin); - binEnd[0] = generated->GetXaxis()->FindBin(mEtaMax); - } - if (axis2 == 0) { - binBegin[1] = generated->GetYaxis()->FindBin(mEtaMin); - binEnd[1] = generated->GetYaxis()->FindBin(mEtaMax); - } - if (axis3 == 0) { - binBegin[2] = generated->GetZaxis()->FindBin(mEtaMin); - binEnd[2] = generated->GetZaxis()->FindBin(mEtaMax); - } - } - - if (mPtMax > mPtMin) { - // TODO this is just checking up to 15 for now - Float_t ptMax = TMath::Min((Float_t)15., mPtMax); - if (axis1 == 1) { - binBegin[0] = generated->GetXaxis()->FindBin(mPtMin); - binEnd[0] = generated->GetXaxis()->FindBin(ptMax); - } - if (axis2 == 1) { - binBegin[1] = generated->GetYaxis()->FindBin(mPtMin); - binEnd[1] = generated->GetYaxis()->FindBin(ptMax); - } - if (axis3 == 1) { - binBegin[2] = generated->GetZaxis()->FindBin(mPtMin); - binEnd[2] = generated->GetZaxis()->FindBin(ptMax); - } - } - - Int_t total = 0; - Int_t count = 0; - Int_t vars[3]; - - for (Int_t i = 0; i < 3; i++) { - vars[i] = binBegin[i]; - } - - const Int_t limit = 50; - while (1) { - if (generated->GetDimension() == 1 && generated->GetBinContent(vars[0]) < limit) { - LOGF(info, "Empty bin at %s=%.2f (%.2f entries)", generated->GetXaxis()->GetTitle(), generated->GetXaxis()->GetBinCenter(vars[0]), generated->GetBinContent(vars[0])); - count++; - } else if (generated->GetDimension() == 2 && generated->GetBinContent(vars[0], vars[1]) < limit) { - LOGF(info, "Empty bin at %s=%.2f %s=%.2f (%.2f entries)", - generated->GetXaxis()->GetTitle(), generated->GetXaxis()->GetBinCenter(vars[0]), - generated->GetYaxis()->GetTitle(), generated->GetYaxis()->GetBinCenter(vars[1]), - generated->GetBinContent(vars[0], vars[1])); - count++; - } else if (generated->GetDimension() == 3 && generated->GetBinContent(vars[0], vars[1], vars[2]) < limit) { - LOGF(info, "Empty bin at %s=%.2f %s=%.2f %s=%.2f (%.2f entries)", - generated->GetXaxis()->GetTitle(), generated->GetXaxis()->GetBinCenter(vars[0]), - generated->GetYaxis()->GetTitle(), generated->GetYaxis()->GetBinCenter(vars[1]), - generated->GetZaxis()->GetTitle(), generated->GetZaxis()->GetBinCenter(vars[2]), - generated->GetBinContent(vars[0], vars[1], vars[2])); - count++; - } - - vars[2]++; - if (vars[2] == binEnd[2] + 1) { - vars[2] = binBegin[2]; - vars[1]++; - } - - if (vars[1] == binEnd[1] + 1) { - vars[1] = binBegin[1]; - vars[0]++; - } - - if (vars[0] == binEnd[0] + 1) { - break; - } - total++; - } - - LOGF(info, "Correction has %d empty bins (out of %d bins)", count, total); - - // rebin if required - if (source == 2) { - TAxis* axis = mTriggerHist->getTHn(0)->GetAxis(0); - - if (axis->GetNbins() < measured->GetNbinsX()) { - if (axis2 != -1) { - // 2d rebin with variable axis does not exist in root - - TH1* tmp = measured; - measured = new TH2D(Form("%s_rebinned", tmp->GetName()), tmp->GetTitle(), axis->GetNbins(), axis->GetXbins()->GetArray(), tmp->GetNbinsY(), tmp->GetYaxis()->GetXbins()->GetArray()); - for (Int_t x = 1; x <= tmp->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tmp->GetNbinsY(); y++) { - ((TH2*)measured)->Fill(tmp->GetXaxis()->GetBinCenter(x), tmp->GetYaxis()->GetBinCenter(y), tmp->GetBinContent(x, y)); - measured->SetBinError(x, y, 0); // cannot trust bin error, set to 0 - } - } - delete tmp; - - tmp = generated; - generated = new TH2D(Form("%s_rebinned", tmp->GetName()), tmp->GetTitle(), axis->GetNbins(), axis->GetXbins()->GetArray(), tmp->GetNbinsY(), tmp->GetYaxis()->GetXbins()->GetArray()); - for (Int_t x = 1; x <= tmp->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tmp->GetNbinsY(); y++) { - ((TH2*)generated)->Fill(tmp->GetXaxis()->GetBinCenter(x), tmp->GetYaxis()->GetBinCenter(y), tmp->GetBinContent(x, y)); - generated->SetBinError(x, y, 0); // cannot trust bin error, set to 0 - } - } - delete tmp; - } else { - TH1* tmp = measured; - measured = tmp->Rebin(axis->GetNbins(), Form("%s_rebinned", tmp->GetName()), axis->GetXbins()->GetArray()); - delete tmp; - - tmp = generated; - generated = tmp->Rebin(axis->GetNbins(), Form("%s_rebinned", tmp->GetName()), axis->GetXbins()->GetArray()); - delete tmp; - } - } else if (axis->GetNbins() > measured->GetNbinsX()) { - if (axis2 != -1) { - LOGF(fatal, "Rebinning only works for 1d at present"); - } - - // this is an unfortunate case where the number of bins has to be increased in principle - // there is a region where the binning is finner in one histogram and a region where it is the other way round - // this cannot be resolved in principle, but as we only calculate the ratio the bin in the second region get the same entries - // only a certain binning is supported here - if (axis->GetNbins() != 100 || measured->GetNbinsX() != 39) { - LOGF(fatal, "Invalid binning --> %d %d", axis->GetNbins(), measured->GetNbinsX()); - } - - Double_t newBins[] = {0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 100.0}; - - // reduce binning below 5 GeV/c - TH1* tmp = measured; - measured = tmp->Rebin(27, Form("%s_rebinned", tmp->GetName()), newBins); - delete tmp; - - // increase binning above 5 GeV/c - tmp = measured; - measured = new TH1F(Form("%s_rebinned2", tmp->GetName()), tmp->GetTitle(), axis->GetNbins(), axis->GetBinLowEdge(1), axis->GetBinUpEdge(axis->GetNbins())); - for (Int_t bin = 1; bin <= measured->GetNbinsX(); bin++) { - measured->SetBinContent(bin, tmp->GetBinContent(tmp->FindBin(measured->GetBinCenter(bin)))); - measured->SetBinError(bin, tmp->GetBinError(tmp->FindBin(measured->GetBinCenter(bin)))); - } - delete tmp; - - // reduce binning below 5 GeV/c - tmp = generated; - generated = tmp->Rebin(27, Form("%s_rebinned", tmp->GetName()), newBins); - delete tmp; - - // increase binning above 5 GeV/c - tmp = generated; - generated = new TH1F(Form("%s_rebinned2", tmp->GetName()), tmp->GetTitle(), axis->GetNbins(), axis->GetBinLowEdge(1), axis->GetBinUpEdge(axis->GetNbins())); - for (Int_t bin = 1; bin <= generated->GetNbinsX(); bin++) { - generated->SetBinContent(bin, tmp->GetBinContent(tmp->FindBin(generated->GetBinCenter(bin)))); - generated->SetBinError(bin, tmp->GetBinError(tmp->FindBin(generated->GetBinCenter(bin)))); - } - delete tmp; - } - } - - measured->Divide(measured, generated, 1, 1, "B"); - - delete generated; - - resetBinLimits(sourceContainer->getTHn(step1)); - resetBinLimits(sourceContainer->getTHn(step2)); - - return measured; -} - -//____________________________________________________________________ -TH1* CorrelationContainer::getEventEfficiency(CFStep step1, CFStep step2, Int_t axis1, Int_t axis2, Float_t ptTriggerMin, Float_t ptTriggerMax) -{ - // creates a event-level efficiency by dividing step2 by step1 - // projected to axis1 and axis2 (optional if >= 0) - - if (ptTriggerMax > ptTriggerMin) { - mTriggerHist->getTHn(step1)->GetAxis(0)->SetRangeUser(ptTriggerMin, ptTriggerMax); - mTriggerHist->getTHn(step2)->GetAxis(0)->SetRangeUser(ptTriggerMin, ptTriggerMax); - } - - TH1* measured = nullptr; - TH1* generated = nullptr; - - if (axis2 >= 0) { - generated = mTriggerHist->getTHn(step1)->Projection(axis1, axis2); - measured = mTriggerHist->getTHn(step2)->Projection(axis1, axis2); - } else { - generated = mTriggerHist->getTHn(step1)->Projection(axis1); - measured = mTriggerHist->getTHn(step2)->Projection(axis1); - } - - measured->Divide(measured, generated, 1, 1, "B"); - - delete generated; - - if (ptTriggerMax > ptTriggerMin) { - mTriggerHist->getTHn(step1)->GetAxis(0)->SetRangeUser(0, -1); - mTriggerHist->getTHn(step2)->GetAxis(0)->SetRangeUser(0, -1); - } - - return measured; -} - -//____________________________________________________________________ -void CorrelationContainer::weightHistogram(TH3* hist1, TH1* hist2) -{ - // weights each entry of the 3d histogram hist1 with the 1d histogram hist2 - // where the matching is done of the z axis of hist1 with the x axis of hist2 - - if (hist1->GetNbinsZ() != hist2->GetNbinsX()) { - LOGF(fatal, "Inconsistent binning %d %d", hist1->GetNbinsZ(), hist2->GetNbinsX()); - } - - for (Int_t x = 1; x <= hist1->GetNbinsX(); x++) { - for (Int_t y = 1; y <= hist1->GetNbinsY(); y++) { - for (Int_t z = 1; z <= hist1->GetNbinsZ(); z++) { - if (hist2->GetBinContent(z) > 0) { - hist1->SetBinContent(x, y, z, hist1->GetBinContent(x, y, z) / hist2->GetBinContent(z)); - hist1->SetBinError(x, y, z, hist1->GetBinError(x, y, z) / hist2->GetBinContent(z)); - } else { - hist1->SetBinContent(x, y, z, 0); - hist1->SetBinError(x, y, z, 0); - } - } - } - } -} - -//____________________________________________________________________ -TH1* CorrelationContainer::getBias(CFStep step1, CFStep step2, const char* axis, Float_t leadPtMin, Float_t leadPtMax, Int_t weighting) -{ - // extracts the track-level bias (integrating out the multiplicity) between two steps (dividing step2 by step1) - // done by weighting the track-level distribution with the number of events as function of leading pT - // and then calculating the ratio between the distributions - // projected to axis which is a TH3::Project3D string, e.g. "x", or "yx" - // no projection is done if axis == 0 - // weighting: 0 = tracks weighted with events (as discussed above) - // 1 = only track bias is returned - // 2 = only event bias is returned - - StepTHn* tmp = mPairHist; - - resetBinLimits(tmp->getTHn(step1)); - resetBinLimits(mTriggerHist->getTHn(step1)); - setBinLimits(tmp->getTHn(step1)); - - resetBinLimits(tmp->getTHn(step2)); - resetBinLimits(mTriggerHist->getTHn(step2)); - setBinLimits(tmp->getTHn(step2)); - - TH1D* events1 = (TH1D*)mTriggerHist->getTHn(step1)->Projection(0); - TH3D* hist1 = (TH3D*)tmp->getTHn(step1)->Projection(0, tmp->getNVar() - 1, 2); - if (weighting == 0) { - weightHistogram(hist1, events1); - } - - TH1D* events2 = (TH1D*)mTriggerHist->getTHn(step2)->Projection(0); - TH3D* hist2 = (TH3D*)tmp->getTHn(step2)->Projection(0, tmp->getNVar() - 1, 2); - if (weighting == 0) { - weightHistogram(hist2, events2); - } - - TH1* generated = hist1; - TH1* measured = hist2; - - if (weighting == 0 || weighting == 1) { - if (axis) { - if (leadPtMax > leadPtMin) { - hist1->GetZaxis()->SetRangeUser(leadPtMin, leadPtMax); - hist2->GetZaxis()->SetRangeUser(leadPtMin, leadPtMax); - } - - if (mEtaMax > mEtaMin && !TString(axis).Contains("x")) { - hist1->GetXaxis()->SetRangeUser(mEtaMin, mEtaMax); - hist2->GetXaxis()->SetRangeUser(mEtaMin, mEtaMax); - } - - generated = hist1->Project3D(axis); - measured = hist2->Project3D(axis); - - // delete hists here if projection has been done - delete hist1; - delete hist2; - } - delete events1; - delete events2; - } else if (weighting == 2) { - delete hist1; - delete hist2; - generated = events1; - measured = events2; - } - - measured->Divide(generated); - - delete generated; - - resetBinLimits(tmp->getTHn(step1)); - resetBinLimits(tmp->getTHn(step2)); - - return measured; -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingEfficiency() -{ - // extracts the tracking efficiency by calculating the efficiency from step kCFStepAnaTopology to kCFStepTrackedOnlyPrim - // integrates over the regions and all other variables than pT and eta to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepAnaTopology, kCFStepTrackedOnlyPrim, 0, 1)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getFakeRate() -{ - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTracked, (CFStep)(kCFStepTracked + 3), 0, 1)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingEfficiencyCentrality() -{ - // extracts the tracking efficiency by calculating the efficiency from step kCFStepAnaTopology to kCFStepTrackedOnlyPrim - // integrates over the regions and all other variables than pT, centrality to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepAnaTopology, kCFStepTrackedOnlyPrim, 1, 3)); -} - -//____________________________________________________________________ -TH1D* CorrelationContainer::getTrackingEfficiency(Int_t axis) -{ - // extracts the tracking efficiency by calculating the efficiency from step kCFStepAnaTopology to kCFStepTrackedOnlyPrim - // integrates over the regions and all other variables than pT (axis == 0) and eta (axis == 1) to increase the statistics - - return dynamic_cast<TH1D*>(getTrackEfficiency(kCFStepAnaTopology, kCFStepTrackedOnlyPrim, axis)); -} - -//____________________________________________________________________ -TH1D* CorrelationContainer::getFakeRate(Int_t axis) -{ - return dynamic_cast<TH1D*>(getTrackEfficiency(kCFStepTracked, (CFStep)(kCFStepTracked + 3), axis)); -} -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingCorrection() -{ - // extracts the tracking correction by calculating the efficiency from step kCFStepAnaTopology to kCFStepTracked - // integrates over the regions and all other variables than pT and eta to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTracked, kCFStepAnaTopology, 0, 1)); -} - -//____________________________________________________________________ -TH1D* CorrelationContainer::getTrackingCorrection(Int_t axis) -{ - // extracts the tracking correction by calculating the efficiency from step kCFStepAnaTopology to kCFStepTracked - // integrates over the regions and all other variables than pT (axis == 0) and eta (axis == 1) to increase the statistics - - return dynamic_cast<TH1D*>(getTrackEfficiency(kCFStepTracked, kCFStepAnaTopology, axis)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingEfficiencyCorrection() -{ - // extracts the tracking correction by calculating the efficiency from step kCFStepAnaTopology to kCFStepTracked - // integrates over the regions and all other variables than pT and eta to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTrackedOnlyPrim, kCFStepAnaTopology, 0, 1)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingEfficiencyCorrectionCentrality() -{ - // extracts the tracking correction by calculating the efficiency from step kCFStepAnaTopology to kCFStepTracked - // integrates over the regions and all other variables than pT and centrality to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTrackedOnlyPrim, kCFStepAnaTopology, 1, 3)); -} - -//____________________________________________________________________ -TH1D* CorrelationContainer::getTrackingEfficiencyCorrection(Int_t axis) -{ - // extracts the tracking correction by calculating the efficiency from step kCFStepAnaTopology to kCFStepTracked - // integrates over the regions and all other variables than pT (axis == 0) and eta (axis == 1) to increase the statistics - - return dynamic_cast<TH1D*>(getTrackEfficiency(kCFStepTrackedOnlyPrim, kCFStepAnaTopology, axis)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingContamination() -{ - // extracts the tracking contamination by secondaries by calculating the efficiency from step kCFStepTrackedOnlyPrim to kCFStepTracked - // integrates over the regions and all other variables than pT and eta to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTracked, kCFStepTrackedOnlyPrim, 0, 1)); -} - -//____________________________________________________________________ -TH2D* CorrelationContainer::getTrackingContaminationCentrality() -{ - // extracts the tracking contamination by secondaries by calculating the efficiency from step kCFStepTrackedOnlyPrim to kCFStepTracked - // integrates over the regions and all other variables than pT and centrality to increase the statistics - // - // returned histogram has to be deleted by the user - - return dynamic_cast<TH2D*>(getTrackEfficiency(kCFStepTracked, kCFStepTrackedOnlyPrim, 1, 3)); -} - -//____________________________________________________________________ -TH1D* CorrelationContainer::getTrackingContamination(Int_t axis) -{ - // extracts the tracking contamination by secondaries by calculating the efficiency from step kCFStepTrackedOnlyPrim to kCFStepTracked - // integrates over the regions and all other variables than pT (axis == 0) and eta (axis == 1) to increase the statistics - - return dynamic_cast<TH1D*>(getTrackEfficiency(kCFStepTracked, kCFStepTrackedOnlyPrim, axis)); -} - -//____________________________________________________________________ -const char* CorrelationContainer::getStepTitle(CFStep step) -{ - // returns the name of the given step - - switch (step) { - case kCFStepAll: - return "All events"; - case kCFStepTriggered: - return "Triggered"; - case kCFStepVertex: - return "Primary Vertex"; - case kCFStepAnaTopology: - return "Required analysis topology"; - case kCFStepTrackedOnlyPrim: - return "Tracked (matched MC, only primaries)"; - case kCFStepTracked: - return "Tracked (matched MC, all)"; - case kCFStepReconstructed: - return "Reconstructed"; - case kCFStepRealLeading: - return "Correct leading particle identified"; - case kCFStepBiasStudy: - return "Bias study applying tracking efficiency"; - case kCFStepBiasStudy2: - return "Bias study applying tracking efficiency in two steps"; - case kCFStepCorrected: - return "Corrected for efficiency on-the-fly"; - } - - return ""; -} - -void CorrelationContainer::deepCopy(CorrelationContainer* from) -{ - // copies the entries of this object's members from the object <from> to this object - // fills using the fill function and thus allows that the objects have different binning - - for (Int_t step = 0; step < mPairHist->getNSteps(); step++) { - LOGF(info, "Copying step %d", step); - THnBase* target = mPairHist->getTHn(step); - THnBase* source = from->mPairHist->getTHn(step); - - target->Reset(); - target->RebinnedAdd(source); - } - - for (Int_t step = 0; step < mTriggerHist->getNSteps(); step++) { - LOGF(info, "Ev: Copying step %d", step); - THnBase* target = mTriggerHist->getTHn(step); - THnBase* source = from->mTriggerHist->getTHn(step); - - target->Reset(); - target->RebinnedAdd(source); - } - - for (Int_t step = 0; step < TMath::Min(mTrackHistEfficiency->getNSteps(), from->mTrackHistEfficiency->getNSteps()); step++) { - if (!from->mTrackHistEfficiency->getTHn(step)) { - continue; - } - - LOGF(info, "Eff: Copying step %d", step); - THnBase* target = mTrackHistEfficiency->getTHn(step); - THnBase* source = from->mTrackHistEfficiency->getTHn(step); - - target->Reset(); - target->RebinnedAdd(source); - } -} - -void CorrelationContainer::symmetrizepTBins() -{ - // copy pt,a < pt,t bins to pt,a > pt,t (inverting deltaphi and delta eta as it should be) including symmetric bins - - for (Int_t step = 0; step < mPairHist->getNSteps(); step++) { - LOGF(info, "Copying step %d", step); - THnBase* target = mPairHist->getTHn(step); - if (target->GetEntries() == 0) { - continue; - } - - // for symmetric bins - THnBase* source = (THnBase*)target->Clone(); - - Int_t zVtxBins = 1; - if (target->GetNdimensions() > 5) { - zVtxBins = target->GetAxis(5)->GetNbins(); - } - - // axes: 0 delta eta; 1 pT,a; 2 pT,t; 3 centrality; 4 delta phi; 5 vtx-z - for (Int_t i3 = 1; i3 <= target->GetAxis(3)->GetNbins(); i3++) { - for (Int_t i5 = 1; i5 <= zVtxBins; i5++) { - for (Int_t i1 = 1; i1 <= target->GetAxis(1)->GetNbins(); i1++) { - for (Int_t i2 = 1; i2 <= target->GetAxis(2)->GetNbins(); i2++) { - // find source bin - Int_t binA = target->GetAxis(1)->FindBin(target->GetAxis(2)->GetBinCenter(i2)); - Int_t binT = target->GetAxis(2)->FindBin(target->GetAxis(1)->GetBinCenter(i1)); - - LOGF(info, "(%d %d) Copying from %d %d to %d %d", i3, i5, binA, binT, i1, i2); - - for (Int_t i0 = 1; i0 <= target->GetAxis(0)->GetNbins(); i0++) { - for (Int_t i4 = 1; i4 <= target->GetAxis(4)->GetNbins(); i4++) { - Int_t binEta = target->GetAxis(0)->FindBin(-target->GetAxis(0)->GetBinCenter(i0)); - Double_t phi = -target->GetAxis(4)->GetBinCenter(i4); - if (phi < -TMath::Pi() / 2) { - phi += TMath::TwoPi(); - } - Int_t binPhi = target->GetAxis(4)->FindBin(phi); - - Int_t binSource[] = {binEta, binA, binT, i3, binPhi, i5}; - Int_t binTarget[] = {i0, i1, i2, i3, i4, i5}; - - Double_t value = source->GetBinContent(binSource); - Double_t error = source->GetBinError(binSource); - - if (error == 0) { - continue; - } - - Double_t value2 = target->GetBinContent(binTarget); - Double_t error2 = target->GetBinError(binTarget); - - Double_t sum = value; - Double_t err = error; - - if (error2 > 0) { - sum = value + value2; - err = TMath::Sqrt(error * error + error2 * error2); - } - - // Printf(" Values: %f +- %f; %f +- %f --> %f +- %f", value, error, value2, error2, sum, err); - - target->SetBinContent(binTarget, sum); - target->SetBinError(binTarget, err); - } - } - } - } - } - } - - delete source; - } -} - -//____________________________________________________________________ -void CorrelationContainer::extendTrackingEfficiency(Bool_t verbose) -{ - // fits the tracking efficiency at high pT with a constant and fills all bins with this tracking efficiency - - Float_t fitRangeBegin = 5.01; - Float_t fitRangeEnd = 14.99; - Float_t extendRangeBegin = 10.01; - - if (mTrackHistEfficiency->getNVar() == 3) { - TH1* obj = getTrackingEfficiency(1); - - if (verbose) { - new TCanvas; - obj->Draw(); - } - - obj->Fit("pol0", (verbose) ? "+" : "0+", "SAME", fitRangeBegin, fitRangeEnd); - - Float_t trackingEff = obj->GetFunction("pol0")->GetParameter(0); - - obj = getTrackingContamination(1); - - if (verbose) { - new TCanvas; - obj->Draw(); - } - - obj->Fit("pol0", (verbose) ? "+" : "0+", "SAME", fitRangeBegin, fitRangeEnd); - - Float_t trackingCont = obj->GetFunction("pol0")->GetParameter(0); - - LOGF(info, "CorrelationContainer::extendTrackingEfficiency: Fitted efficiency between %f and %f and got %f tracking efficiency and %f tracking contamination correction. Extending from %f onwards (within %f < eta < %f)", fitRangeBegin, fitRangeEnd, trackingEff, trackingCont, extendRangeBegin, mEtaMin, mEtaMax); - - // extend for full pT range - for (Int_t x = mTrackHistEfficiency->getTHn(0)->GetAxis(0)->FindBin(mEtaMin); x <= mTrackHistEfficiency->getTHn(0)->GetAxis(0)->FindBin(mEtaMax); x++) { - for (Int_t y = mTrackHistEfficiency->getTHn(0)->GetAxis(1)->FindBin(extendRangeBegin); y <= mTrackHistEfficiency->getTHn(0)->GetAxis(1)->GetNbins(); y++) { - for (Int_t z = 1; z <= mTrackHistEfficiency->getTHn(0)->GetAxis(2)->GetNbins(); z++) // particle type axis - { - - Int_t bins[3]; - bins[0] = x; - bins[1] = y; - bins[2] = z; - - mTrackHistEfficiency->getTHn(0)->SetBinContent(bins, 100); - mTrackHistEfficiency->getTHn(1)->SetBinContent(bins, 100.0 * trackingEff); - mTrackHistEfficiency->getTHn(2)->SetBinContent(bins, 100.0 * trackingEff / trackingCont); - } - } - } - } else if (mTrackHistEfficiency->getNVar() == 4) { - // fit in centrality intervals of 20% for efficiency, one bin for contamination - Float_t* trackingEff = nullptr; - Float_t* trackingCont = nullptr; - Float_t centralityBins[] = {0, 10, 20, 40, 60, 100}; - Int_t nCentralityBins = 5; - - LOGF(info, "CorrelationContainer::extendTrackingEfficiency: Fitting efficiencies between %f and %f. Extending from %f onwards (within %f < eta < %f)", fitRangeBegin, fitRangeEnd, extendRangeBegin, mEtaMin, mEtaMax); - - // 0 = eff; 1 = cont - for (Int_t caseNo = 0; caseNo < 2; caseNo++) { - Float_t* target = nullptr; - Int_t centralityBinsLocal = nCentralityBins; - - if (caseNo == 0) { - trackingEff = new Float_t[centralityBinsLocal]; - target = trackingEff; - } else { - centralityBinsLocal = 1; - trackingCont = new Float_t[centralityBinsLocal]; - target = trackingCont; - } - - for (Int_t i = 0; i < centralityBinsLocal; i++) { - if (centralityBinsLocal == 1) { - setCentralityRange(centralityBins[0] + 0.1, centralityBins[nCentralityBins] - 0.1); - } else { - setCentralityRange(centralityBins[i] + 0.1, centralityBins[i + 1] - 0.1); - } - TH1* proj = (caseNo == 0) ? getTrackingEfficiency(1) : getTrackingContamination(1); - if (verbose) { - new TCanvas; - proj->DrawCopy(); - } - if ((Int_t)proj->Fit("pol0", (verbose) ? "+" : "Q0+", "SAME", fitRangeBegin, fitRangeEnd) == 0) { - target[i] = proj->GetFunction("pol0")->GetParameter(0); - } else { - target[i] = 0; - } - LOGF(info, "CorrelationContainer::extendTrackingEfficiency: case %d, centrality %d, eff %f", caseNo, i, target[i]); - } - } - - // extend for full pT range - for (Int_t x = mTrackHistEfficiency->getTHn(0)->GetAxis(0)->FindBin(mEtaMin); x <= mTrackHistEfficiency->getTHn(0)->GetAxis(0)->FindBin(mEtaMax); x++) { - for (Int_t y = mTrackHistEfficiency->getTHn(0)->GetAxis(1)->FindBin(extendRangeBegin); y <= mTrackHistEfficiency->getTHn(0)->GetAxis(1)->GetNbins(); y++) { - for (Int_t z = 1; z <= mTrackHistEfficiency->getTHn(0)->GetAxis(2)->GetNbins(); z++) // particle type axis - { - for (Int_t z2 = 1; z2 <= mTrackHistEfficiency->getTHn(0)->GetAxis(3)->GetNbins(); z2++) // centrality axis - { - - Int_t bins[4]; - bins[0] = x; - bins[1] = y; - bins[2] = z; - bins[3] = z2; - - Int_t z2Bin = 0; - while (centralityBins[z2Bin + 1] < mTrackHistEfficiency->getTHn(0)->GetAxis(3)->GetBinCenter(z2)) { - z2Bin++; - } - - //Printf("%d %d", z2, z2Bin); - - mTrackHistEfficiency->getTHn(0)->SetBinContent(bins, 100); - mTrackHistEfficiency->getTHn(1)->SetBinContent(bins, 100.0 * trackingEff[z2Bin]); - if (trackingCont[0] > 0) { - mTrackHistEfficiency->getTHn(2)->SetBinContent(bins, 100.0 * trackingEff[z2Bin] / trackingCont[0]); - } else { - mTrackHistEfficiency->getTHn(2)->SetBinContent(bins, 0); - } - } - } - } - } - - delete[] trackingEff; - delete[] trackingCont; - } - - setCentralityRange(0, 0); -} - -/* -void CorrelationContainer::Scale(Double_t factor) -{ - // scales all contained histograms by the given factor - - for (Int_t i=0; i<4; i++) - if (mTrackHist[i]) - mTrackHist[i]->Scale(factor); - - mEventHist->Scale(factor); - mTrackHistEfficiency->Scale(factor); -}*/ - -void CorrelationContainer::Reset() -{ - // resets all contained histograms - - for (Int_t step = 0; step < mPairHist->getNSteps(); step++) { - mPairHist->getTHn(step)->Reset(); - } - - for (Int_t step = 0; step < mTriggerHist->getNSteps(); step++) { - mTriggerHist->getTHn(step)->Reset(); - } - - for (Int_t step = 0; step < mTrackHistEfficiency->getNSteps(); step++) { - mTrackHistEfficiency->getTHn(step)->Reset(); - } -} - -THnBase* CorrelationContainer::changeToThn(THnBase* sparse) -{ - // change the object to THn for faster processing - - return THn::CreateHn(Form("%s_thn", sparse->GetName()), sparse->GetTitle(), sparse); -} - -void CorrelationContainer::fillEvent(Float_t centrality, CFStep step) -{ - // Fill per-event information - mEventCount->Fill(step, centrality); -} diff --git a/Analysis/Core/src/HistogramManager.cxx b/Analysis/Core/src/HistogramManager.cxx deleted file mode 100644 index f92ec71d19c80..0000000000000 --- a/Analysis/Core/src/HistogramManager.cxx +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/HistogramManager.h" - -#include <iostream> -#include <fstream> -using namespace std; - -#include <TObject.h> -#include <TObjArray.h> -#include <THashList.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TH3F.h> -#include <TProfile.h> -#include <TProfile2D.h> -#include <TProfile3D.h> -#include <THn.h> -#include <THnSparse.h> -#include <TIterator.h> -#include <TClass.h> - -ClassImp(HistogramManager); - -//_______________________________________________________________________________ -HistogramManager::HistogramManager() : TNamed("", ""), - fMainList(nullptr), - fNVars(0), - fUsedVars(nullptr), - fVariablesMap(), - fUseDefaultVariableNames(false), - fBinsAllocated(0), - fVariableNames(nullptr), - fVariableUnits(nullptr) -{ - // - // Constructor - // -} - -//_______________________________________________________________________________ -HistogramManager::HistogramManager(const char* name, const char* title, const int maxNVars) : TNamed(name, title), - fMainList(), - fNVars(maxNVars), - fUsedVars(), - fVariablesMap(), - fUseDefaultVariableNames(kFALSE), - fBinsAllocated(0), - fVariableNames(), - fVariableUnits() -{ - // - // Constructor - // - fMainList = new THashList; - fMainList->SetOwner(kTRUE); - fMainList->SetName(name); - fUsedVars = new bool[maxNVars]; - fVariableNames = new TString[maxNVars]; - fVariableUnits = new TString[maxNVars]; -} - -//_______________________________________________________________________________ -HistogramManager::~HistogramManager() -{ - // - // De-constructor - // - delete fMainList; - delete fUsedVars; -} - -//_______________________________________________________________________________ -void HistogramManager::SetDefaultVarNames(TString* vars, TString* units) -{ - // - // Set default variable names - // - for (int i = 0; i < fNVars; ++i) { - fVariableNames[i] = vars[i]; - fVariableUnits[i] = units[i]; - } -}; - -//__________________________________________________________________ -void HistogramManager::AddHistClass(const char* histClass) -{ - // - // Add a new histogram list - // - if (fMainList->FindObject(histClass)) { - cout << "Warning in HistogramManager::AddHistClass(): Cannot add histogram class " << histClass - << " because it already exists." << endl; - return; - } - TList* hList = new TList; - hList->SetOwner(kTRUE); - hList->SetName(histClass); - fMainList->Add(hList); - std::list<std::vector<int>> varList; - fVariablesMap[histClass] = varList; - cout << "Adding histogram class " << histClass << endl; - cout << "Variable map size :: " << fVariablesMap.size() << endl; -} - -//_________________________________________________________________ -void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, bool isProfile, - int nXbins, double xmin, double xmax, int varX, - int nYbins, double ymin, double ymax, int varY, - int nZbins, double zmin, double zmax, int varZ, - const char* xLabels, const char* yLabels, const char* zLabels, - int varT, int varW) -{ - // - // add a histogram (this function can define TH1F,TH2F,TH3F,TProfile,TProfile2D, and TProfile3D) - // - // TODO: replace the cout warning messages with LOG (same for all the other functions) - - // get the list to which the histogram should be added - TList* hList = (TList*)fMainList->FindObject(histClass); - if (!hList) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram list " << histClass << " not found!" << endl; - cout << " Histogram not created" << endl; - return; - } - // check whether this histogram name was used before - if (hList->FindObject(hname)) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram " << hname << " already exists" << endl; - return; - } - - // deduce the dimension of the histogram from parameters - // NOTE: in case of profile histograms, one extra variable is needed - int dimension = 1; - if (varY > kNothing) { - dimension = 2; - } - if (varZ > kNothing) { - dimension = 3; - } - - // tokenize the title string; the user may include in it axis titles which will overwrite the defaults - TString titleStr(title); - TObjArray* arr = titleStr.Tokenize(";"); - // mark required variables as being used - if (varX > kNothing) { - fUsedVars[varX] = kTRUE; - } - if (varY > kNothing) { - fUsedVars[varY] = kTRUE; - } - if (varZ > kNothing) { - fUsedVars[varZ] = kTRUE; - } - if (varT > kNothing) { - fUsedVars[varT] = kTRUE; - } - if (varW > kNothing) { - fUsedVars[varW] = kTRUE; - } - - // encode needed variable identifiers in a vector and push it to the std::list corresponding to the current histogram list - std::vector<int> varVector; - varVector.push_back(isProfile ? 1 : 0); // whether the histogram is a profile - varVector.push_back(0); // whether it is a THn - varVector.push_back(varW); // variable used for weighting - varVector.push_back(varX); // variables on each axis - varVector.push_back(varY); - varVector.push_back(varZ); - varVector.push_back(varT); // variable used for profiling in case of TProfile3D - std::list varList = fVariablesMap[histClass]; - varList.push_back(varVector); - cout << "Adding histogram " << hname << endl; - cout << "size of array :: " << varList.size() << endl; - fVariablesMap[histClass] = varList; - - // create and configure histograms according to required options - TH1* h = nullptr; - switch (dimension) { - case 1: // TH1F - h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax); - fBinsAllocated += nXbins + 2; - // TODO: possibly make the call of Sumw2() optional for all histograms - h->Sumw2(); - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s %s", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - hList->Add(h); - h->SetDirectory(nullptr); - break; - - case 2: // either TH2F or TProfile - if (isProfile) { - h = new TProfile(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax); - fBinsAllocated += nXbins + 2; - h->Sumw2(); - // if requested, build the profile using the profile widths instead of stat errors - // TODO: make this option more transparent to the user ? - if (titleStr.Contains("--s--")) { - ((TProfile*)h)->BuildOptions(0., 0., "s"); - } - } else { - h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax); - fBinsAllocated += (nXbins + 2) * (nYbins + 2); - h->Sumw2(); - } - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s %s", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - - if (fVariableNames[varY][0]) { - h->GetYaxis()->SetTitle(Form("%s %s", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - if (fVariableNames[varY][0] && isProfile) { - h->GetYaxis()->SetTitle(Form("<%s> %s", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - if (arr->At(2)) { - h->GetYaxis()->SetTitle(arr->At(2)->GetName()); - } - if (yLabels[0] != '\0') { - MakeAxisLabels(h->GetYaxis(), yLabels); - } - hList->Add(h); - h->SetDirectory(nullptr); - break; - - case 3: // TH3F, TProfile2D or TProfile3D - if (isProfile) { - if (varT > kNothing) { // TProfile3D - h = new TProfile3D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax, nZbins, zmin, zmax); - fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); - h->Sumw2(); - if (titleStr.Contains("--s--")) { - ((TProfile3D*)h)->BuildOptions(0., 0., "s"); - } - } else { // TProfile2D - h = new TProfile2D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax); - fBinsAllocated += (nXbins + 2) * (nYbins + 2); - h->Sumw2(); - if (titleStr.Contains("--s--")) { - ((TProfile2D*)h)->BuildOptions(0., 0., "s"); - } - } - } else { // TH3F - h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xmin, xmax, nYbins, ymin, ymax, nZbins, zmin, zmax); - fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); - h->Sumw2(); - } - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s %s", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - if (fVariableNames[varY][0]) { - h->GetYaxis()->SetTitle(Form("%s %s", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - if (arr->At(2)) { - h->GetYaxis()->SetTitle(arr->At(2)->GetName()); - } - if (yLabels[0] != '\0') { - MakeAxisLabels(h->GetYaxis(), yLabels); - } - if (fVariableNames[varZ][0]) { - h->GetZaxis()->SetTitle(Form("%s %s", fVariableNames[varZ].Data(), - (fVariableUnits[varZ][0] ? Form("(%s)", fVariableUnits[varZ].Data()) : ""))); - } - if (fVariableNames[varZ][0] && isProfile && varT < 0) { // for TProfile2D - h->GetZaxis()->SetTitle(Form("<%s> %s", fVariableNames[varZ].Data(), - (fVariableUnits[varZ][0] ? Form("(%s)", fVariableUnits[varZ].Data()) : ""))); - } - if (arr->At(3)) { - h->GetZaxis()->SetTitle(arr->At(3)->GetName()); - } - if (zLabels[0] != '\0') { - MakeAxisLabels(h->GetZaxis(), zLabels); - } - h->SetDirectory(nullptr); - hList->Add(h); - break; - } // end switch -} - -//_________________________________________________________________ -void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, bool isProfile, - int nXbins, double* xbins, int varX, - int nYbins, double* ybins, int varY, - int nZbins, double* zbins, int varZ, - const char* xLabels, const char* yLabels, const char* zLabels, - int varT, int varW) -{ - // - // add a histogram - // - - // get the list to which the histogram should be added - TList* hList = (TList*)fMainList->FindObject(histClass); - if (!hList) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram list " << histClass << " not found!" << endl; - cout << " Histogram not created" << endl; - return; - } - // check whether this histogram name was used before - if (hList->FindObject(hname)) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram " << hname << " already exists" << endl; - return; - } - - // deduce the dimension of the histogram from parameters - // NOTE: in case of profile histograms, one extra variable is needed - int dimension = 1; - if (varY > kNothing) { - dimension = 2; - } - if (varZ > kNothing) { - dimension = 3; - } - - // mark required variables as being used - if (varX > kNothing) { - fUsedVars[varX] = kTRUE; - } - if (varY > kNothing) { - fUsedVars[varY] = kTRUE; - } - if (varZ > kNothing) { - fUsedVars[varZ] = kTRUE; - } - if (varT > kNothing) { - fUsedVars[varT] = kTRUE; - } - if (varW > kNothing) { - fUsedVars[varW] = kTRUE; - } - - // tokenize the title string; the user may include in it axis titles which will overwrite the defaults - TString titleStr(title); - TObjArray* arr = titleStr.Tokenize(";"); - - // encode needed variable identifiers in a vector and push it to the std::list corresponding to the current histogram list - std::vector<int> varVector; - varVector.push_back(isProfile ? 1 : 0); // whether the histogram is a profile - varVector.push_back(0); // whether it is a THn - varVector.push_back(varW); // variable used for weighting - varVector.push_back(varX); // variables on each axis - varVector.push_back(varY); - varVector.push_back(varZ); - varVector.push_back(varT); // variable used for profiling in case of TProfile3D - std::list varList = fVariablesMap[histClass]; - varList.push_back(varVector); - cout << "Adding histogram " << hname << endl; - cout << "size of array :: " << varList.size() << endl; - fVariablesMap[histClass] = varList; - - TH1* h = nullptr; - switch (dimension) { - case 1: - h = new TH1F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins); - fBinsAllocated += nXbins + 2; - h->Sumw2(); - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s %s", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - h->SetDirectory(nullptr); - hList->Add(h); - break; - - case 2: - if (isProfile) { - h = new TProfile(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins); - fBinsAllocated += nXbins + 2; - h->Sumw2(); - if (titleStr.Contains("--s--")) { - ((TProfile*)h)->BuildOptions(0., 0., "s"); - } - } else { - h = new TH2F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins); - fBinsAllocated += (nXbins + 2) * (nYbins + 2); - h->Sumw2(); - } - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s (%s)", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - if (fVariableNames[varY][0]) { - h->GetYaxis()->SetTitle(Form("%s (%s)", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - if (fVariableNames[varY][0] && isProfile) { - h->GetYaxis()->SetTitle(Form("<%s> (%s)", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - - if (arr->At(2)) { - h->GetYaxis()->SetTitle(arr->At(2)->GetName()); - } - if (yLabels[0] != '\0') { - MakeAxisLabels(h->GetYaxis(), yLabels); - } - h->SetDirectory(nullptr); - hList->Add(h); - break; - - case 3: - if (isProfile) { - if (varT > kNothing) { - h = new TProfile3D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins, nZbins, zbins); - fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); - h->Sumw2(); - if (titleStr.Contains("--s--")) { - ((TProfile3D*)h)->BuildOptions(0., 0., "s"); - } - } else { - h = new TProfile2D(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins); - fBinsAllocated += (nXbins + 2) * (nYbins + 2); - h->Sumw2(); - if (titleStr.Contains("--s--")) { - ((TProfile2D*)h)->BuildOptions(0., 0., "s"); - } - } - } else { - h = new TH3F(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nXbins, xbins, nYbins, ybins, nZbins, zbins); - fBinsAllocated += (nXbins + 2) * (nYbins + 2) * (nZbins + 2); - h->Sumw2(); - } - if (fVariableNames[varX][0]) { - h->GetXaxis()->SetTitle(Form("%s %s", fVariableNames[varX].Data(), - (fVariableUnits[varX][0] ? Form("(%s)", fVariableUnits[varX].Data()) : ""))); - } - if (arr->At(1)) { - h->GetXaxis()->SetTitle(arr->At(1)->GetName()); - } - if (xLabels[0] != '\0') { - MakeAxisLabels(h->GetXaxis(), xLabels); - } - if (fVariableNames[varY][0]) { - h->GetYaxis()->SetTitle(Form("%s %s", fVariableNames[varY].Data(), - (fVariableUnits[varY][0] ? Form("(%s)", fVariableUnits[varY].Data()) : ""))); - } - if (arr->At(2)) { - h->GetYaxis()->SetTitle(arr->At(2)->GetName()); - } - if (yLabels[0] != '\0') { - MakeAxisLabels(h->GetYaxis(), yLabels); - } - if (fVariableNames[varZ][0]) { - h->GetZaxis()->SetTitle(Form("%s %s", fVariableNames[varZ].Data(), - (fVariableUnits[varZ][0] ? Form("(%s)", fVariableUnits[varZ].Data()) : ""))); - } - if (fVariableNames[varZ][0] && isProfile && varT < 0) { // TProfile2D - h->GetZaxis()->SetTitle(Form("<%s> %s", fVariableNames[varZ].Data(), - (fVariableUnits[varZ][0] ? Form("(%s)", fVariableUnits[varZ].Data()) : ""))); - } - - if (arr->At(3)) { - h->GetZaxis()->SetTitle(arr->At(3)->GetName()); - } - if (zLabels[0] != '\0') { - MakeAxisLabels(h->GetZaxis(), zLabels); - } - hList->Add(h); - break; - } // end switch(dimension) -} - -//_________________________________________________________________ -void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, - int nDimensions, int* vars, int* nBins, double* xmin, double* xmax, - TString* axLabels, int varW, bool useSparse) -{ - // - // add a multi-dimensional histogram THnF or THnFSparseF - // - - // get the list to which the histogram should be added - TList* hList = (TList*)fMainList->FindObject(histClass); - if (!hList) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram list " << histClass << " not found!" << endl; - cout << " Histogram not created" << endl; - return; - } - // check whether this histogram name was used before - if (hList->FindObject(hname)) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram " << hname << " already exists" << endl; - return; - } - - // tokenize the title string; the user may include in it axis titles which will overwrite the defaults - TString titleStr(title); - TObjArray* arr = titleStr.Tokenize(";"); - - if (varW > kNothing) { - fUsedVars[varW] = kTRUE; - } - - // encode needed variable identifiers in a vector and push it to the std::list corresponding to the current histogram list - std::vector<int> varVector; - varVector.push_back(0); // whether the histogram is a profile - varVector.push_back(nDimensions); // number of dimensions - varVector.push_back(varW); // variable used for weighting - for (int idim = 0; idim < nDimensions; ++idim) { - varVector.push_back(vars[idim]); // axes variables - } - std::list varList = fVariablesMap[histClass]; - varList.push_back(varVector); - cout << "Adding histogram " << hname << endl; - cout << "size of array :: " << varList.size() << endl; - fVariablesMap[histClass] = varList; - - unsigned long int nbins = 1; - THnBase* h = nullptr; - if (useSparse) { - h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); - } else { - h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); - } - h->Sumw2(); - - // configure the THn histogram and count the allocated bins - for (int idim = 0; idim < nDimensions; ++idim) { - nbins *= (nBins[idim] + 2); - TAxis* axis = h->GetAxis(idim); - if (fVariableNames[vars[idim]][0]) { - axis->SetTitle(Form("%s %s", fVariableNames[vars[idim]].Data(), - (fVariableUnits[vars[idim]][0] ? Form("(%s)", fVariableUnits[vars[idim]].Data()) : ""))); - } - if (arr->At(1 + idim)) { - axis->SetTitle(arr->At(1 + idim)->GetName()); - } - if (axLabels && !axLabels[idim].IsNull()) { - MakeAxisLabels(axis, axLabels[idim].Data()); - } - - fUsedVars[vars[idim]] = kTRUE; - } - if (useSparse) { - hList->Add((THnSparseF*)h); - } else { - hList->Add((THnF*)h); - } - - fBinsAllocated += nbins; -} - -//_________________________________________________________________ -void HistogramManager::AddHistogram(const char* histClass, const char* hname, const char* title, - int nDimensions, int* vars, TArrayD* binLimits, - TString* axLabels, int varW, bool useSparse) -{ - // - // add a multi-dimensional histogram THnF or THnSparseF with equal or variable bin widths - // - - // get the list to which the histogram should be added - TList* hList = (TList*)fMainList->FindObject(histClass); - if (!hList) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram list " << histClass << " not found!" << endl; - cout << " Histogram not created" << endl; - return; - } - // check whether this histogram name was used before - if (hList->FindObject(hname)) { - cout << "Warning in HistogramManager::AddHistogram(): Histogram " << hname << " already exists" << endl; - return; - } - - // tokenize the title string; the user may include in it axis titles which will overwrite the defaults - TString titleStr(title); - TObjArray* arr = titleStr.Tokenize(";"); - - if (varW > kNothing) { - fUsedVars[varW] = kTRUE; - } - - // encode needed variable identifiers in a vector and push it to the std::list corresponding to the current histogram list - std::vector<int> varVector; - varVector.push_back(0); // whether the histogram is a profile - varVector.push_back(nDimensions); // number of dimensions - varVector.push_back(varW); // variable used for weighting - for (int idim = 0; idim < nDimensions; ++idim) { - varVector.push_back(vars[idim]); // axes variables - } - std::list varList = fVariablesMap[histClass]; - varList.push_back(varVector); - cout << "Adding histogram " << hname << endl; - cout << "size of array :: " << varList.size() << endl; - fVariablesMap[histClass] = varList; - - // get the min and max for each axis - double* xmin = new double[nDimensions]; - double* xmax = new double[nDimensions]; - int* nBins = new int[nDimensions]; - for (int idim = 0; idim < nDimensions; ++idim) { - nBins[idim] = binLimits[idim].GetSize() - 1; - xmin[idim] = binLimits[idim][0]; - xmax[idim] = binLimits[idim][nBins[idim]]; - } - - // initialize the THn with equal spaced bins - THnBase* h = nullptr; - if (useSparse) { - h = new THnSparseF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); - } else { - h = new THnF(hname, (arr->At(0) ? arr->At(0)->GetName() : ""), nDimensions, nBins, xmin, xmax); - } - // rebin the axes according to the user requested binning - for (int idim = 0; idim < nDimensions; ++idim) { - TAxis* axis = h->GetAxis(idim); - axis->Set(nBins[idim], binLimits[idim].GetArray()); - } - h->Sumw2(); - - unsigned long int bins = 1; - for (int idim = 0; idim < nDimensions; ++idim) { - bins *= (nBins[idim] + 2); - TAxis* axis = h->GetAxis(idim); - if (fVariableNames[vars[idim]][0]) { - axis->SetTitle(Form("%s %s", fVariableNames[vars[idim]].Data(), - (fVariableUnits[vars[idim]][0] ? Form("(%s)", fVariableUnits[vars[idim]].Data()) : ""))); - } - if (arr->At(1 + idim)) { - axis->SetTitle(arr->At(1 + idim)->GetName()); - } - if (axLabels && !axLabels[idim].IsNull()) { - MakeAxisLabels(axis, axLabels[idim].Data()); - } - fUsedVars[vars[idim]] = kTRUE; - } - if (useSparse) { - hList->Add((THnSparseF*)h); - } else { - hList->Add((THnF*)h); - } - fBinsAllocated += bins; -} - -//__________________________________________________________________ -void HistogramManager::FillHistClass(const char* className, Float_t* values) -{ - // - // fill a class of histograms - // - - // get the needed histogram list - TList* hList = (TList*)fMainList->FindObject(className); - if (!hList) { - // TODO: add some meaningfull error message - /*cout << "Warning in HistogramManager::FillHistClass(): Histogram list " << className << " not found!" << endl; - cout << " Histogram list not filled" << endl; */ - return; - } - - // get the corresponding std::list containng identifiers to the needed variables to be filled - list varList = fVariablesMap[className]; - - TIter next(hList); - auto varIter = varList.begin(); - - TObject* h = nullptr; - bool isProfile; - bool isTHn; - int dimension = 0; - bool isSparse = kFALSE; - // TODO: At the moment, maximum 20 dimensions are foreseen for the THn histograms. We should make this more dynamic - // But maybe its better to have it like to avoid dynamically allocating this array in the histogram loop - double fillValues[20] = {0.0}; - int varX = -1, varY = -1, varZ = -1, varT = -1, varW = -1; - - // loop over the histogram and std::list - // NOTE: these two should contain the same number of elements and be synchronized, otherwise its a mess - for (auto varIter = varList.begin(); varIter != varList.end(); varIter++) { - h = next(); // get the histogram - // decode information from the vector of indices - isProfile = (varIter->at(0) == 1 ? true : false); - isTHn = (varIter->at(1) > 0 ? true : false); - if (isTHn) { - dimension = varIter->at(1); - } else { - dimension = ((TH1*)h)->GetDimension(); - } - - // get the various variable indices - varW = varIter->at(2); - if (isTHn) { - for (int i = 0; i < dimension; i++) { - fillValues[i] = values[varIter->at(3 + i)]; - } - } else { - varX = varIter->at(3); - varY = varIter->at(4); - varZ = varIter->at(5); - varT = varIter->at(6); - } - - if (!isTHn) { - switch (dimension) { - case 1: - if (isProfile) { - if (varW > kNothing) { - ((TProfile*)h)->Fill(values[varX], values[varY], values[varW]); - } else { - ((TProfile*)h)->Fill(values[varX], values[varY]); - } - } else { - if (varW > kNothing) { - ((TH1F*)h)->Fill(values[varX], values[varW]); - } else { - ((TH1F*)h)->Fill(values[varX]); - } - } - break; - case 2: - if (isProfile) { - if (varW > kNothing) { - ((TProfile2D*)h)->Fill(values[varX], values[varY], values[varZ], values[varW]); - } else { - ((TProfile2D*)h)->Fill(values[varX], values[varY], values[varZ]); - } - } else { - if (varW > kNothing) { - ((TH2F*)h)->Fill(values[varX], values[varY], values[varW]); - } else { - ((TH2F*)h)->Fill(values[varX], values[varY]); - } - } - break; - case 3: - if (isProfile) { - if (varW > kNothing) { - ((TProfile3D*)h)->Fill(values[varX], values[varY], values[varZ], values[varT], values[varW]); - } else { - ((TProfile3D*)h)->Fill(values[varX], values[varY], values[varZ], values[varT]); - } - } else { - if (varW > kNothing) { - ((TH3F*)h)->Fill(values[varX], values[varY], values[varZ], values[varW]); - } else { - ((TH3F*)h)->Fill(values[varX], values[varY], values[varZ]); - } - } - break; - - default: - break; - } // end switch - } // end if(!isTHn) - else { - if (varW > kNothing) { - if (isSparse) { - ((THnSparseF*)h)->Fill(fillValues, values[varW]); - } else { - ((THnF*)h)->Fill(fillValues, values[varW]); - } - } else { - if (isSparse) { - ((THnSparseF*)h)->Fill(fillValues); - } else { - ((THnF*)h)->Fill(fillValues); - } - } - } // end else - } // end loop over histograms -} - -//____________________________________________________________________________________ -void HistogramManager::MakeAxisLabels(TAxis* ax, const char* labels) -{ - // - // add bin labels to an axis - // - TString labelsStr(labels); - TObjArray* arr = labelsStr.Tokenize(";"); - for (int ib = 1; ib <= ax->GetNbins(); ++ib) { - if (ib >= arr->GetEntries() + 1) { - break; - } - ax->SetBinLabel(ib, arr->At(ib - 1)->GetName()); - } -} - -//____________________________________________________________________________________ -void HistogramManager::Print(Option_t*) const -{ - // - // Print the defined histograms - // - cout << "###################################################################" << endl; - cout << "HistogramManager:: " << fMainList->GetName() << endl; - for (int i = 0; i < fMainList->GetEntries(); ++i) { - TList* list = (TList*)fMainList->At(i); - cout << "************** List " << list->GetName() << endl; - for (int j = 0; j < list->GetEntries(); ++j) { - TObject* obj = list->At(j); - cout << obj->GetName() << ": " << obj->IsA()->GetName() << endl; - } - } -} diff --git a/Analysis/Core/src/JetFinder.cxx b/Analysis/Core/src/JetFinder.cxx deleted file mode 100644 index bb9304213b828..0000000000000 --- a/Analysis/Core/src/JetFinder.cxx +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet finder task -// -// Author: Jochen Klein, Nima Zardoshti -#include "Analysis/JetFinder.h" -#include "Framework/AnalysisTask.h" - -/// Sets the jet finding parameters -void JetFinder::setParams() -{ - - if (!isReclustering) { - jetEtaMin = etaMin + jetR; //in aliphysics this was (-etaMax + 0.95*jetR) - jetEtaMax = etaMax - jetR; - } - - //selGhosts =fastjet::SelectorRapRange(ghostEtaMin,ghostEtaMax) && fastjet::SelectorPhiRange(phiMin,phiMax); - //ghostAreaSpec=fastjet::GhostedAreaSpec(selGhosts,ghostRepeatN,ghostArea,gridScatter,ktScatter,ghostktMean); - ghostAreaSpec = fastjet::GhostedAreaSpec(ghostEtaMax, ghostRepeatN, ghostArea, gridScatter, ktScatter, ghostktMean); //the first argument is rapidity not pseudorapidity, to be checked - jetDef = fastjet::JetDefinition(algorithm, jetR, recombScheme, strategy); - areaDef = fastjet::AreaDefinition(areaType, ghostAreaSpec); - selJets = fastjet::SelectorPtRange(jetPtMin, jetPtMax) && fastjet::SelectorEtaRange(jetEtaMin, jetEtaMax) && fastjet::SelectorPhiRange(jetPhiMin, jetPhiMax); - jetDefBkg = fastjet::JetDefinition(algorithmBkg, jetBkgR, recombSchemeBkg, strategyBkg); - areaDefBkg = fastjet::AreaDefinition(areaTypeBkg, ghostAreaSpec); - selRho = fastjet::SelectorRapRange(bkgEtaMin, bkgEtaMax) && fastjet::SelectorPhiRange(bkgPhiMin, bkgPhiMax); //&& !fastjet::SelectorNHardest(2) //here we have to put rap range, to be checked! -} - -/// Sets the background subtraction estimater pointer -void JetFinder::setBkgE() -{ - if (bkgSubMode == BkgSubMode::rhoAreaSub || bkgSubMode == BkgSubMode::constSub) { - bkgE = decltype(bkgE)(new fastjet::JetMedianBackgroundEstimator(selRho, jetDefBkg, areaDefBkg)); - } else { - if (bkgSubMode != BkgSubMode::none) { - LOGF(ERROR, "requested subtraction mode not implemented!"); - } - } -} - -/// Sets the background subtraction pointer -void JetFinder::setSub() -{ - //if rho < 1e-6 it is set to 1e-6 in AliPhysics - if (bkgSubMode == BkgSubMode::rhoAreaSub) { - sub = decltype(sub){new fastjet::Subtractor{bkgE.get()}}; - } else if (bkgSubMode == BkgSubMode::constSub) { //event or jetwise - constituentSub = decltype(constituentSub){new fastjet::contrib::ConstituentSubtractor{bkgE.get()}}; - constituentSub->set_distance_type(fastjet::contrib::ConstituentSubtractor::deltaR); - constituentSub->set_max_distance(constSubRMax); - constituentSub->set_alpha(constSubAlpha); - constituentSub->set_ghost_area(ghostArea); - constituentSub->set_max_eta(bkgEtaMax); - constituentSub->set_background_estimator(bkgE.get()); //what about rho_m - } else { - if (bkgSubMode != BkgSubMode::none) { - LOGF(ERROR, "requested subtraction mode not implemented!"); - } - } -} - -/// Performs jet finding -/// \note the input particle and jet lists are passed by reference -/// \param inputParticles vector of input particles/tracks -/// \param jets veector of jets to be filled -/// \return ClusterSequenceArea object needed to access constituents -fastjet::ClusterSequenceArea JetFinder::findJets(std::vector<fastjet::PseudoJet>& inputParticles, std::vector<fastjet::PseudoJet>& jets) //ideally find a way of passing the cluster sequence as a reeference -{ - setParams(); - setBkgE(); - jets.clear(); - - if (bkgE) { - bkgE->set_particles(inputParticles); - setSub(); - } - if (constituentSub) { - inputParticles = constituentSub->subtract_event(inputParticles); - } - fastjet::ClusterSequenceArea clusterSeq(inputParticles, jetDef, areaDef); - jets = sub ? (*sub)(clusterSeq.inclusive_jets()) : clusterSeq.inclusive_jets(); - jets = selJets(jets); - return clusterSeq; -} diff --git a/Analysis/Core/src/TrackSelection.cxx b/Analysis/Core/src/TrackSelection.cxx deleted file mode 100644 index 5e7ff6fa41fd0..0000000000000 --- a/Analysis/Core/src/TrackSelection.cxx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Class for track selection -// - -#include "Analysis/TrackSelection.h" - -bool TrackSelection::FulfillsITSHitRequirements(uint8_t itsClusterMap) -{ - constexpr uint8_t bit = 1; - for (auto& itsRequirement : mRequiredITSHits) { - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (bit << requiredLayer); }); - if ((itsRequirement.first == -1) && (hits > 0)) { - return false; // no hits were required in specified layers - } else if (hits < itsRequirement.first) { - return false; // not enough hits found in specified layers - } - } - return true; -} - -const std::string TrackSelection::mCutNames[static_cast<int>(TrackSelection::TrackCuts::kNCuts)] = {"TrackType", "PtRange", "EtaRange", "TPCNCls", "TPCCrossedRows", "TPCCrossedRowsOverNCls", "TPCChi2NDF", "TPCRefit", "ITSNCls", "ITSChi2NDF", "ITSRefit", "ITSHits", "GoldenChi2", "DCAxy", "DCAz"}; diff --git a/Analysis/Core/src/TriggerAliases.cxx b/Analysis/Core/src/TriggerAliases.cxx deleted file mode 100644 index d5b69e9bc9a0a..0000000000000 --- a/Analysis/Core/src/TriggerAliases.cxx +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/TriggerAliases.h" - -void TriggerAliases::Print() -{ - for (auto& al : GetAliasToClassIdsMap()) { - printf("%d", al.first); - for (auto& classIndex : al.second) { - printf(" %d", classIndex); - } - printf("\n"); - } -} diff --git a/Analysis/Core/src/VarManager.cxx b/Analysis/Core/src/VarManager.cxx deleted file mode 100644 index 211e3a33fb6de..0000000000000 --- a/Analysis/Core/src/VarManager.cxx +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/VarManager.h" - -#include <TMath.h> - -ClassImp(VarManager); - -TString VarManager::fgVariableNames[VarManager::kNVars] = {""}; -TString VarManager::fgVariableUnits[VarManager::kNVars] = {""}; -bool VarManager::fgUsedVars[VarManager::kNVars] = {kFALSE}; -float VarManager::fgValues[VarManager::kNVars] = {0.0}; -std::map<int, int> VarManager::fgRunMap; - -//__________________________________________________________________ -VarManager::VarManager() : TObject() -{ - // - // constructor - // - SetDefaultVarNames(); -} - -//__________________________________________________________________ -VarManager::~VarManager() = default; - -//__________________________________________________________________ -void VarManager::SetVariableDependencies() -{ - // - // Set as used variables on which other variables calculation depends - // - if (fgUsedVars[kP]) { - fgUsedVars[kPt] = kTRUE; - fgUsedVars[kEta] = kTRUE; - } -} - -//__________________________________________________________________ -void VarManager::ResetValues(int startValue, int endValue, float* values) -{ - // - // reset all variables to an "innocent" value - // NOTE: here we use -9999.0 as a neutral value, but depending on situation, this may not be the case - if (!values) { - values = fgValues; - } - for (Int_t i = startValue; i < endValue; ++i) { - values[i] = -9999.; - } -} - -//__________________________________________________________________ -void VarManager::SetRunNumbers(int n, int* runs) -{ - // - // maps the list of runs such that one can plot the list of runs nicely in a histogram axis - // - for (int i = 0; i < n; ++i) { - fgRunMap[runs[i]] = i + 1; - } -} - -//__________________________________________________________________ -void VarManager::FillEventDerived(float* values) -{ - // - // Fill event-wise derived quantities (these are all quantities which can be computed just based on the values already filled in the FillEvent() function) - // - if (fgUsedVars[kRunId]) { - values[kRunId] = (fgRunMap.size() > 0 ? fgRunMap[int(values[kRunNo])] : 0); - } -} - -//__________________________________________________________________ -void VarManager::FillTrackDerived(float* values) -{ - // - // Fill track-wise derived quantities (these are all quantities which can be computed just based on the values already filled in the FillTrack() function) - // - if (fgUsedVars[kP]) { - values[kP] = values[kPt] * TMath::CosH(values[kEta]); - } -} - -//__________________________________________________________________ -void VarManager::SetDefaultVarNames() -{ - // - // Set default variable names - // - for (Int_t ivar = 0; ivar < kNVars; ++ivar) { - fgVariableNames[ivar] = "DEFAULT NOT DEFINED"; - fgVariableUnits[ivar] = "n/a"; - } - - fgVariableNames[kRunNo] = "Run number"; - fgVariableUnits[kRunNo] = ""; - fgVariableNames[kRunId] = "Run number"; - fgVariableUnits[kRunId] = ""; - fgVariableNames[kCollisionTime] = "collision time"; - fgVariableUnits[kCollisionTime] = ""; - fgVariableNames[kBC] = "Bunch crossing"; - fgVariableUnits[kBC] = ""; - fgVariableNames[kIsPhysicsSelection] = "Physics selection"; - fgVariableUnits[kIsPhysicsSelection] = ""; - fgVariableNames[kVtxX] = "Vtx X "; - fgVariableUnits[kVtxX] = "cm"; - fgVariableNames[kVtxY] = "Vtx Y "; - fgVariableUnits[kVtxY] = "cm"; - fgVariableNames[kVtxZ] = "Vtx Z "; - fgVariableUnits[kVtxZ] = "cm"; - fgVariableNames[kVtxNcontrib] = "Vtx contrib."; - fgVariableUnits[kVtxNcontrib] = ""; - fgVariableNames[kVtxCovXX] = "Vtx covXX"; - fgVariableUnits[kVtxCovXX] = "cm"; - fgVariableNames[kVtxCovXY] = "Vtx covXY"; - fgVariableUnits[kVtxCovXY] = "cm"; - fgVariableNames[kVtxCovXZ] = "Vtx covXZ"; - fgVariableUnits[kVtxCovXZ] = "cm"; - fgVariableNames[kVtxCovYY] = "Vtx covYY"; - fgVariableUnits[kVtxCovYY] = "cm"; - fgVariableNames[kVtxCovYZ] = "Vtx covYZ"; - fgVariableUnits[kVtxCovYZ] = "cm"; - fgVariableNames[kVtxCovZZ] = "Vtx covZZ"; - fgVariableUnits[kVtxCovZZ] = "cm"; - fgVariableNames[kVtxChi2] = "Vtx chi2"; - fgVariableUnits[kVtxChi2] = ""; - fgVariableNames[kCentVZERO] = "Centrality VZERO"; - fgVariableUnits[kCentVZERO] = "%"; - fgVariableNames[kPt] = "p_{T}"; - fgVariableUnits[kPt] = "GeV/c"; - fgVariableNames[kP] = "p"; - fgVariableUnits[kP] = "GeV/c"; - fgVariableNames[kPx] = "p_{x}"; - fgVariableUnits[kPy] = "GeV/c"; - fgVariableNames[kPy] = "p_{y}"; - fgVariableUnits[kPz] = "GeV/c"; - fgVariableNames[kPz] = "p_{z}"; - fgVariableUnits[kPx] = "GeV/c"; - fgVariableNames[kEta] = "#eta"; - fgVariableUnits[kEta] = ""; - fgVariableNames[kPhi] = "#varphi"; - fgVariableUnits[kPhi] = "rad."; - fgVariableNames[kRap] = "y"; - fgVariableUnits[kRap] = ""; - fgVariableNames[kMass] = "mass"; - fgVariableUnits[kMass] = "GeV/c2"; - fgVariableNames[kCharge] = "charge"; - fgVariableUnits[kCharge] = ""; - fgVariableNames[kPin] = "p_{IN}"; - fgVariableUnits[kPin] = "GeV/c"; - fgVariableNames[kITSncls] = "ITS #cls"; - fgVariableUnits[kITSncls] = ""; - fgVariableNames[kITSchi2] = "ITS chi2"; - fgVariableUnits[kITSchi2] = ""; - fgVariableNames[kITSlayerHit] = "ITS layer"; - fgVariableUnits[kITSlayerHit] = ""; - fgVariableNames[kTPCncls] = "TPC #cls"; - fgVariableUnits[kTPCncls] = ""; - fgVariableNames[kTPCchi2] = "TPC chi2"; - fgVariableUnits[kTPCchi2] = ""; - fgVariableNames[kTPCsignal] = "TPC dE/dx"; - fgVariableUnits[kTPCsignal] = ""; - fgVariableNames[kTRDsignal] = "TRD dE/dx"; - fgVariableUnits[kTRDsignal] = ""; - fgVariableNames[kTOFsignal] = "TOF signal"; - fgVariableUnits[kTOFsignal] = ""; - fgVariableNames[kTOFbeta] = "TOF #beta"; - fgVariableUnits[kTOFbeta] = ""; - fgVariableNames[kTrackLength] = "track length"; - fgVariableUnits[kTrackLength] = "cm"; - fgVariableNames[kTrackDCAxy] = "DCA_{xy}"; - fgVariableUnits[kTrackDCAxy] = "cm"; - fgVariableNames[kTrackDCAz] = "DCA_{z}"; - fgVariableUnits[kTrackDCAz] = "cm"; - fgVariableNames[kTPCnSigmaEl] = "n #sigma_{e}^{TPC}"; - fgVariableUnits[kTPCnSigmaEl] = ""; - fgVariableNames[kTPCnSigmaMu] = "n #sigma_{#mu}^{TPC}"; - fgVariableUnits[kTPCnSigmaMu] = ""; - fgVariableNames[kTPCnSigmaPi] = "n #sigma_{#pi}^{TPC}"; - fgVariableUnits[kTPCnSigmaPi] = ""; - fgVariableNames[kTPCnSigmaKa] = "n #sigma_{K}^{TPC}"; - fgVariableUnits[kTPCnSigmaKa] = ""; - fgVariableNames[kTPCnSigmaPr] = "n #sigma_{p}^{TPC}"; - fgVariableUnits[kTPCnSigmaPr] = ""; - fgVariableNames[kTOFnSigmaEl] = "n #sigma_{e}^{TOF}"; - fgVariableUnits[kTOFnSigmaEl] = ""; - fgVariableNames[kTOFnSigmaMu] = "n #sigma_{#mu}^{TOF}"; - fgVariableUnits[kTOFnSigmaMu] = ""; - fgVariableNames[kTOFnSigmaPi] = "n #sigma_{#pi}^{TOF}"; - fgVariableUnits[kTOFnSigmaPi] = ""; - fgVariableNames[kTOFnSigmaKa] = "n #sigma_{K}^{TOF}"; - fgVariableUnits[kTOFnSigmaKa] = ""; - fgVariableNames[kTOFnSigmaPr] = "n #sigma_{p}^{TOF}"; - fgVariableUnits[kTOFnSigmaPr] = ""; - fgVariableNames[kMuonInvBendingMomentum] = "Inverse bending mom."; - fgVariableUnits[kMuonInvBendingMomentum] = "1/(GeV/c)"; - fgVariableNames[kMuonThetaX] = "theta X"; - fgVariableUnits[kMuonThetaX] = ""; - fgVariableNames[kMuonThetaY] = "theta Y"; - fgVariableUnits[kMuonThetaY] = ""; - fgVariableNames[kMuonZMu] = "ZMu"; - fgVariableUnits[kMuonZMu] = ""; - fgVariableNames[kMuonBendingCoor] = "bending coor."; - fgVariableUnits[kMuonBendingCoor] = ""; - fgVariableNames[kMuonNonBendingCoor] = "non-bending coor."; - fgVariableUnits[kMuonNonBendingCoor] = ""; - fgVariableNames[kMuonRAtAbsorberEnd] = "R at the end of the absorber"; - fgVariableUnits[kMuonRAtAbsorberEnd] = ""; - fgVariableNames[kMuonPDca] = "p x dca"; - fgVariableUnits[kMuonPDca] = "cm x GeV/c"; - fgVariableNames[kMuonChi2] = "#chi 2"; - fgVariableUnits[kMuonChi2] = ""; - fgVariableNames[kMuonChi2MatchTrigger] = "#chi 2 trigger match"; - fgVariableUnits[kMuonChi2MatchTrigger] = ""; - fgVariableNames[kCandidateId] = ""; - fgVariableUnits[kCandidateId] = ""; - fgVariableNames[kPairType] = "Pair type"; - fgVariableUnits[kPairType] = ""; - fgVariableNames[kPairLxy] = "Pair Lxy"; - fgVariableUnits[kPairLxy] = "cm"; - fgVariableNames[kPairMass] = "mass"; - fgVariableUnits[kPairMass] = "GeV/c2"; - fgVariableNames[kPairPt] = "p_{T}"; - fgVariableUnits[kPairPt] = "GeV/c"; - fgVariableNames[kPairEta] = "#eta"; - fgVariableUnits[kPairEta] = ""; - fgVariableNames[kPairPhi] = "#varphi"; - fgVariableUnits[kPairPhi] = "rad."; - fgVariableNames[kDeltaEta] = "#Delta#eta"; - fgVariableUnits[kDeltaEta] = ""; - fgVariableNames[kDeltaPhi] = "#Delta#phi"; - fgVariableUnits[kDeltaPhi] = "rad."; - fgVariableNames[kDeltaPhiSym] = "#Delta#phi"; - fgVariableUnits[kDeltaPhiSym] = "rad."; -} diff --git a/Analysis/DataModel/CMakeLists.txt b/Analysis/DataModel/CMakeLists.txt deleted file mode 100644 index bf3f50c8a30a6..0000000000000 --- a/Analysis/DataModel/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(AnalysisDataModel - SOURCES src/ParamBase.cxx - PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/src - PUBLIC_LINK_LIBRARIES O2::Framework O2::ReconstructionDataFormats O2::TPCSimulation - ) - - -o2_target_root_dictionary(AnalysisDataModel - HEADERS include/PIDBase/ParamBase.h - include/PIDBase/DetectorResponse.h - include/PID/PIDTOF.h - include/PID/TOFReso.h - include/PID/PIDTPC.h - include/PID/BetheBloch.h - include/PID/TPCReso.h - LINKDEF src/AnalysisDataModelLinkDef.h - ) - -install(FILES - include/PIDBase/ParamBase.h - include/PIDBase/DetectorResponse.h - DESTINATION - include/PIDBase) - -install(FILES - include/PID/PIDTOF.h - include/PID/TOFReso.h - include/PID/PIDTPC.h - include/PID/BetheBloch.h - include/PID/TPCReso.h - DESTINATION - include/PID) - -o2_add_executable(aod-data-model-graph - SOURCES src/aodDataModelGraph.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - ) - -o2_add_executable(pidparam-tpc-bethe-bloch - SOURCES src/handleParamTPCBetheBloch.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel - ) - -o2_add_executable(pidparam-tof-reso - SOURCES src/handleParamTOFReso.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel - ) diff --git a/Analysis/DataModel/include/Analysis/CFDerived.h b/Analysis/DataModel/include/Analysis/CFDerived.h deleted file mode 100644 index 78fdcdfee505c..0000000000000 --- a/Analysis/DataModel/include/Analysis/CFDerived.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_CFDERIVED_H -#define O2_ANALYSIS_CFDERIVED_H - -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/Centrality.h" - -namespace o2::aod -{ -DECLARE_SOA_TABLE(CFCollisions, "AOD", "CFCOLLISION", o2::soa::Index<>, - o2::aod::bc::RunNumber, o2::aod::collision::PosZ, o2::aod::cent::CentV0M); -using CFCollision = CFCollisions::iterator; - -namespace cftrack -{ -DECLARE_SOA_INDEX_COLUMN(CFCollision, cfCollision); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int8_t); -} // namespace cftrack -DECLARE_SOA_TABLE(CFTracks, "AOD", "CFTRACK", o2::soa::Index<>, - cftrack::CFCollisionId, - cftrack::Pt, cftrack::Eta, cftrack::Phi, - cftrack::Charge, track::TrackType); -using CFTrack = CFTracks::iterator; -} // namespace o2::aod - -#endif // O2_ANALYSIS_CFDERIVED_H diff --git a/Analysis/DataModel/include/Analysis/Centrality.h b/Analysis/DataModel/include/Analysis/Centrality.h deleted file mode 100644 index 2dff05cde076a..0000000000000 --- a/Analysis/DataModel/include/Analysis/Centrality.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_CENTRALITY_H_ -#define O2_ANALYSIS_CENTRALITY_H_ - -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace cent -{ -DECLARE_SOA_COLUMN(CentV0M, centV0M, float); -} // namespace cent -DECLARE_SOA_TABLE(Cents, "AOD", "CENT", cent::CentV0M); -using Cent = Cents::iterator; -} // namespace o2::aod - -#endif // O2_ANALYSIS_CENTRALITY_H_ diff --git a/Analysis/DataModel/include/Analysis/EventSelection.h b/Analysis/DataModel/include/Analysis/EventSelection.h deleted file mode 100644 index 198db13e00b7a..0000000000000 --- a/Analysis/DataModel/include/Analysis/EventSelection.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_EVENTSELECTION_H_ -#define O2_ANALYSIS_EVENTSELECTION_H_ - -#include "Framework/AnalysisDataModel.h" -#include "Analysis/TriggerAliases.h" - -namespace o2::aod -{ -namespace evsel -{ -// TODO bool arrays are not supported? Storing in int32 for the moment -DECLARE_SOA_COLUMN(Alias, alias, int32_t[kNaliases]); -DECLARE_SOA_COLUMN(BBT0A, bbT0A, bool); // beam-beam time in T0A -DECLARE_SOA_COLUMN(BBT0C, bbT0C, bool); // beam-beam time in T0C -DECLARE_SOA_COLUMN(BBV0A, bbV0A, bool); // beam-beam time in V0A -DECLARE_SOA_COLUMN(BBV0C, bbV0C, bool); // beam-beam time in V0C -DECLARE_SOA_COLUMN(BGV0A, bgV0A, bool); // beam-gas time in V0A -DECLARE_SOA_COLUMN(BGV0C, bgV0C, bool); // beam-gas time in V0C -DECLARE_SOA_COLUMN(BBZNA, bbZNA, bool); // beam-beam time in ZNA -DECLARE_SOA_COLUMN(BBZNC, bbZNC, bool); // beam-beam time in ZNC -DECLARE_SOA_COLUMN(BBFDA, bbFDA, bool); // beam-beam time in FDA -DECLARE_SOA_COLUMN(BBFDC, bbFDC, bool); // beam-beam time in FDC -DECLARE_SOA_COLUMN(BGFDA, bgFDA, bool); // beam-gas time in FDA -DECLARE_SOA_COLUMN(BGFDC, bgFDC, bool); // beam-gas time in FDC -DECLARE_SOA_DYNAMIC_COLUMN(SEL7, sel7, [](bool bbV0A, bool bbV0C, bool bbZNA, bool bbZNC) -> bool { return bbV0A && bbV0C && bbZNA && bbZNC; }); -DECLARE_SOA_DYNAMIC_COLUMN(SEL8, sel8, [](bool bbT0A, bool bbT0C, bool bbZNA, bool bbZNC) -> bool { return bbT0A && bbT0C && bbZNA && bbZNC; }); -} // namespace evsel -DECLARE_SOA_TABLE(EvSels, "AOD", "EVSEL", - evsel::Alias, - evsel::BBT0A, evsel::BBT0C, - evsel::BBV0A, evsel::BBV0C, evsel::BGV0A, evsel::BGV0C, evsel::BBZNA, evsel::BBZNC, - evsel::BBFDA, evsel::BBFDC, evsel::BGFDA, evsel::BGFDC, - evsel::SEL7<evsel::BBV0A, evsel::BBV0C, evsel::BBZNA, evsel::BBZNC>); -using EvSel = EvSels::iterator; -} // namespace o2::aod - -#endif // O2_ANALYSIS_EVENTSELECTION_H_ diff --git a/Analysis/DataModel/include/Analysis/HFCandidateSelectionTables.h b/Analysis/DataModel/include/Analysis/HFCandidateSelectionTables.h deleted file mode 100644 index c8d231a401fae..0000000000000 --- a/Analysis/DataModel/include/Analysis/HFCandidateSelectionTables.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_ANALYSIS_HFCANDIDATESELECTIONTABLES_H_ -#define O2_ANALYSIS_HFCANDIDATESELECTIONTABLES_H_ - -namespace o2::aod -{ -namespace hf_selcandidate_d0 -{ -DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int); -DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int); -} // namespace hf_selcandidate_d0 -DECLARE_SOA_TABLE(HFSelD0Candidate, "AOD", "HFSELD0CAND", hf_selcandidate_d0::IsSelD0, hf_selcandidate_d0::IsSelD0bar); -} // namespace o2::aod - -namespace o2::aod -{ -namespace hf_selcandidate_lc -{ -DECLARE_SOA_COLUMN(IsSelLc, isSelLc, int); -} // namespace hf_selcandidate_lc -DECLARE_SOA_TABLE(HFSelLcCandidate, "AOD", "HFSELLCCAND", hf_selcandidate_lc::IsSelLc); -} // namespace o2::aod - -#endif // O2_ANALYSIS_HFCANDIDATESELECTIONTABLES_H_ diff --git a/Analysis/DataModel/include/Analysis/HFSecondaryVertex.h b/Analysis/DataModel/include/Analysis/HFSecondaryVertex.h deleted file mode 100644 index 8ee186e65b55d..0000000000000 --- a/Analysis/DataModel/include/Analysis/HFSecondaryVertex.h +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFSecondaryVertex.h -/// \brief Definitions of tables of heavy-flavour decay candidates. -/// -/// \author Gian Michele Innocenti <gian.michele.innocenti@cern.ch>, CERN -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#ifndef O2_ANALYSIS_HFSECONDARYVERTEX_H_ -#define O2_ANALYSIS_HFSECONDARYVERTEX_H_ - -#include "Framework/AnalysisDataModel.h" -#include "Analysis/RecoDecay.h" -#include "PID/PIDResponse.h" - -namespace o2::aod -{ -namespace hf_seltrack -{ -DECLARE_SOA_COLUMN(IsSel2Prong, isSel2Prong, int); -DECLARE_SOA_COLUMN(IsSel3Prong, isSel3Prong, int); -DECLARE_SOA_COLUMN(DCAPrim0, dcaPrim0, float); -DECLARE_SOA_COLUMN(DCAPrim1, dcaPrim1, float); -} // namespace hf_seltrack - -DECLARE_SOA_TABLE(HFSelTrack, "AOD", "HFSELTRACK", - hf_seltrack::IsSel2Prong, - hf_seltrack::IsSel3Prong, - hf_seltrack::DCAPrim0, - hf_seltrack::DCAPrim1); - -using BigTracks = soa::Join<Tracks, TracksCov, TracksExtra, HFSelTrack>; -using BigTracksMC = soa::Join<BigTracks, McTrackLabels>; -using BigTracksPID = soa::Join<BigTracks, pidRespTPC, pidRespTOF>; - -// FIXME: this is a workaround until we get the index columns to work with joins. - -namespace hf_track_index -{ -DECLARE_SOA_INDEX_COLUMN_FULL(Index0, index0, int, BigTracks, "fIndex0"); -DECLARE_SOA_INDEX_COLUMN_FULL(Index1, index1, int, BigTracks, "fIndex1"); -DECLARE_SOA_INDEX_COLUMN_FULL(Index2, index2, int, BigTracks, "fIndex2"); -DECLARE_SOA_INDEX_COLUMN_FULL(Index3, index3, int, BigTracks, "fIndex3"); -DECLARE_SOA_COLUMN(HFflag, hfflag, uint8_t); -} // namespace hf_track_index - -DECLARE_SOA_TABLE(HfTrackIndexProng2, "AOD", "HFTRACKIDXP2", - hf_track_index::Index0Id, - hf_track_index::Index1Id, - hf_track_index::HFflag); - -DECLARE_SOA_TABLE(HfTrackIndexProng3, "AOD", "HFTRACKIDXP3", - hf_track_index::Index0Id, - hf_track_index::Index1Id, - hf_track_index::Index2Id, - hf_track_index::HFflag); - -// general decay properties -namespace hf_cand -{ -// secondary vertex -DECLARE_SOA_COLUMN(XSecondaryVertex, xSecondaryVertex, float); -DECLARE_SOA_COLUMN(YSecondaryVertex, ySecondaryVertex, float); -DECLARE_SOA_COLUMN(ZSecondaryVertex, zSecondaryVertex, float); -DECLARE_SOA_DYNAMIC_COLUMN(RSecondaryVertex, rSecondaryVertex, [](float xVtxS, float yVtxS) { return RecoDecay::sqrtSumOfSquares(xVtxS, yVtxS); }); -DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); // sum of (non-weighted) distances of the secondary vertex to its prongs -// prong properties -DECLARE_SOA_COLUMN(PxProng0, pxProng0, float); -DECLARE_SOA_COLUMN(PyProng0, pyProng0, float); -DECLARE_SOA_COLUMN(PzProng0, pzProng0, float); -DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, [](float px, float py) { return RecoDecay::Pt(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong0, pt2Prong0, [](float px, float py) { return RecoDecay::Pt2(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng0, pVectorProng0, [](float px, float py, float pz) { return array{px, py, pz}; }); -DECLARE_SOA_COLUMN(ImpactParameter0, impactParameter0, float); -DECLARE_SOA_COLUMN(ErrorImpactParameter0, errorImpactParameter0, float); -DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, [](float dca, float err) { return dca / err; }); -DECLARE_SOA_COLUMN(PxProng1, pxProng1, float); -DECLARE_SOA_COLUMN(PyProng1, pyProng1, float); -DECLARE_SOA_COLUMN(PzProng1, pzProng1, float); -DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, [](float px, float py) { return RecoDecay::Pt(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong1, pt2Prong1, [](float px, float py) { return RecoDecay::Pt2(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng1, pVectorProng1, [](float px, float py, float pz) { return array{px, py, pz}; }); -DECLARE_SOA_COLUMN(ImpactParameter1, impactParameter1, float); -DECLARE_SOA_COLUMN(ErrorImpactParameter1, errorImpactParameter1, float); -DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, [](float dca, float err) { return dca / err; }); -DECLARE_SOA_COLUMN(PxProng2, pxProng2, float); -DECLARE_SOA_COLUMN(PyProng2, pyProng2, float); -DECLARE_SOA_COLUMN(PzProng2, pzProng2, float); -DECLARE_SOA_DYNAMIC_COLUMN(PtProng2, ptProng2, [](float px, float py) { return RecoDecay::Pt(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong2, pt2Prong2, [](float px, float py) { return RecoDecay::Pt2(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng2, pVectorProng2, [](float px, float py, float pz) { return array{px, py, pz}; }); -DECLARE_SOA_COLUMN(ImpactParameter2, impactParameter2, float); -DECLARE_SOA_COLUMN(ErrorImpactParameter2, errorImpactParameter2, float); -DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, [](float dca, float err) { return dca / err; }); -// candidate properties -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) { return RecoDecay::Pt(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt2, pt2, [](float px, float py) { return RecoDecay::Pt2(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) { return RecoDecay::P(px, py, pz); }); -DECLARE_SOA_DYNAMIC_COLUMN(P2, p2, [](float px, float py, float pz) { return RecoDecay::P2(px, py, pz); }); -DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, [](float px, float py, float pz) { return array{px, py, pz}; }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) { return RecoDecay::Eta(array{px, py, pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Y, y, [](float px, float py, float pz, double m) { return RecoDecay::Y(array{px, py, pz}, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(E, e, [](float px, float py, float pz, double m) { return RecoDecay::E(px, py, pz, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(E2, e2, [](float px, float py, float pz, double m) { return RecoDecay::E2(px, py, pz, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(DecayLength, decayLength, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS) { return RecoDecay::distance(array{xVtxP, yVtxP, zVtxP}, array{xVtxS, yVtxS, zVtxS}); }); -DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXY, decayLengthXY, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS) { return RecoDecay::distanceXY(array{xVtxP, yVtxP}, array{xVtxS, yVtxS}); }); -DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthNormalised, decayLengthNormalised, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float err) { return RecoDecay::distance(array{xVtxP, yVtxP, zVtxP}, array{xVtxS, yVtxS, zVtxS}) / err; }); -DECLARE_SOA_DYNAMIC_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float err) { return RecoDecay::distanceXY(array{xVtxP, yVtxP}, array{xVtxS, yVtxS}) / err; }); -DECLARE_SOA_COLUMN(ErrorDecayLength, errorDecayLength, float); -DECLARE_SOA_COLUMN(ErrorDecayLengthXY, errorDecayLengthXY, float); -DECLARE_SOA_DYNAMIC_COLUMN(CPA, cpa, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz) { return RecoDecay::CPA(array{xVtxP, yVtxP, zVtxP}, array{xVtxS, yVtxS, zVtxS}, array{px, py, pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(CPAXY, cpaXY, [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float px, float py) { return RecoDecay::CPAXY(array{xVtxP, yVtxP}, array{xVtxS, yVtxS}, array{px, py}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Ct, ct, [](float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float px, float py, float pz, double m) { return RecoDecay::Ct(array{px, py, pz}, RecoDecay::distance(array{xVtxP, yVtxP, zVtxP}, array{xVtxS, yVtxS, zVtxS}), m); }); -} // namespace hf_cand - -// specific 2-prong decay properties -namespace hf_cand_prong2 -{ -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, float, 1.f * aod::hf_cand::pxProng0 + 1.f * aod::hf_cand::pxProng1); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, float, 1.f * aod::hf_cand::pyProng0 + 1.f * aod::hf_cand::pyProng1); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, float, 1.f * aod::hf_cand::pzProng0 + 1.f * aod::hf_cand::pzProng1); -DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProduct, impactParameterProduct, [](float dca1, float dca2) { return dca1 * dca2; }); -DECLARE_SOA_DYNAMIC_COLUMN(M, m, [](float px0, float py0, float pz0, float px1, float py1, float pz1, const array<double, 2>& m) { return RecoDecay::M(array{array{px0, py0, pz0}, array{px1, py1, pz1}}, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(M2, m2, [](float px0, float py0, float pz0, float px1, float py1, float pz1, const array<double, 2>& m) { return RecoDecay::M2(array{array{px0, py0, pz0}, array{px1, py1, pz1}}, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(CosThetaStar, cosThetaStar, [](float px0, float py0, float pz0, float px1, float py1, float pz1, const array<double, 2>& m, double mTot, int iProng) { return RecoDecay::CosThetaStar(array{array{px0, py0, pz0}, array{px1, py1, pz1}}, m, mTot, iProng); }); -// MC matching result: -// - bit 0: D0(bar) → π± K∓ -DECLARE_SOA_COLUMN(FlagMCMatchRec, flagMCMatchRec, uint8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMCMatchGen, flagMCMatchGen, uint8_t); // generator level - -// functions for specific particles - -// D0(bar) → π± K∓ - -template <typename T> -auto CtD0(const T& candidate) -{ - return candidate.ct(RecoDecay::getMassPDG(421)); -} - -template <typename T> -auto YD0(const T& candidate) -{ - return candidate.y(RecoDecay::getMassPDG(421)); -} - -template <typename T> -auto ED0(const T& candidate) -{ - return candidate.e(RecoDecay::getMassPDG(421)); -} - -template <typename T> -auto InvMassD0(const T& candidate) -{ - return candidate.m(array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kKPlus)}); -} - -template <typename T> -auto InvMassD0bar(const T& candidate) -{ - return candidate.m(array{RecoDecay::getMassPDG(kKPlus), RecoDecay::getMassPDG(kPiPlus)}); -} - -template <typename T> -auto CosThetaStarD0(const T& candidate) -{ - return candidate.cosThetaStar(array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kKPlus)}, RecoDecay::getMassPDG(421), 1); -} - -template <typename T> -auto CosThetaStarD0bar(const T& candidate) -{ - return candidate.cosThetaStar(array{RecoDecay::getMassPDG(kKPlus), RecoDecay::getMassPDG(kPiPlus)}, RecoDecay::getMassPDG(421), 0); -} -} // namespace hf_cand_prong2 - -// general columns -#define HFCAND_COLUMNS \ - collision::PosX, collision::PosY, collision::PosZ, \ - hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, \ - hf_cand::ErrorDecayLength, hf_cand::ErrorDecayLengthXY, \ - hf_cand::Chi2PCA, \ - /* dynamic columns */ hf_cand::RSecondaryVertex<hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex>, \ - hf_cand::DecayLength<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex>, \ - hf_cand::DecayLengthXY<collision::PosX, collision::PosY, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex>, \ - hf_cand::DecayLengthNormalised<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, hf_cand::ErrorDecayLength>, \ - hf_cand::DecayLengthXYNormalised<collision::PosX, collision::PosY, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ErrorDecayLengthXY>, \ - /* prong 0 */ hf_cand::ImpactParameterNormalised0<hf_cand::ImpactParameter0, hf_cand::ErrorImpactParameter0>, \ - hf_cand::PtProng0<hf_cand::PxProng0, hf_cand::PyProng0>, \ - hf_cand::Pt2Prong0<hf_cand::PxProng0, hf_cand::PyProng0>, \ - hf_cand::PVectorProng0<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0>, \ - /* prong 1 */ hf_cand::ImpactParameterNormalised1<hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter1>, \ - hf_cand::PtProng1<hf_cand::PxProng1, hf_cand::PyProng1>, \ - hf_cand::Pt2Prong1<hf_cand::PxProng1, hf_cand::PyProng1>, \ - hf_cand::PVectorProng1<hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1> - -// 2-prong decay candidate table -DECLARE_SOA_TABLE(HfCandProng2Base, "AOD", "HFCANDP2BASE", - // general columns - HFCAND_COLUMNS, - // 2-prong specific columns - hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, - hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, - hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, - hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - hf_track_index::Index0Id, hf_track_index::Index1Id, - /* dynamic columns */ - hf_cand_prong2::M<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1>, - hf_cand_prong2::M2<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1>, - hf_cand_prong2::ImpactParameterProduct<hf_cand::ImpactParameter0, hf_cand::ImpactParameter1>, - hf_cand_prong2::CosThetaStar<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1>, - /* dynamic columns that use candidate momentum components */ - hf_cand::Pt<hf_cand_prong2::Px, hf_cand_prong2::Py>, - hf_cand::Pt2<hf_cand_prong2::Px, hf_cand_prong2::Py>, - hf_cand::P<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::P2<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::PVector<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::CPA<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::CPAXY<collision::PosX, collision::PosY, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand_prong2::Px, hf_cand_prong2::Py>, - hf_cand::Ct<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::Eta<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::Y<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::E<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>, - hf_cand::E2<hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz>); - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(HfCandProng2Ext, HfCandProng2Base, "HFCANDP2EXT", - hf_cand_prong2::Px, hf_cand_prong2::Py, hf_cand_prong2::Pz); - -using HfCandProng2 = HfCandProng2Ext; - -// table with results of reconstruction level MC matching -DECLARE_SOA_TABLE(HfCandProng2MCRec, "AOD", "HFCANDP2MCREC", - hf_cand_prong2::FlagMCMatchRec); - -// table with results of generator level MC matching -DECLARE_SOA_TABLE(HfCandProng2MCGen, "AOD", "HFCANDP2MCGEN", - hf_cand_prong2::FlagMCMatchGen); - -// specific 3-prong decay properties -namespace hf_cand_prong3 -{ -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, float, 1.f * aod::hf_cand::pxProng0 + 1.f * aod::hf_cand::pxProng1 + 1.f * aod::hf_cand::pxProng2); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, float, 1.f * aod::hf_cand::pyProng0 + 1.f * aod::hf_cand::pyProng1 + 1.f * aod::hf_cand::pyProng2); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, float, 1.f * aod::hf_cand::pzProng0 + 1.f * aod::hf_cand::pzProng1 + 1.f * aod::hf_cand::pzProng2); -DECLARE_SOA_DYNAMIC_COLUMN(M, m, [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, const array<double, 3>& m) { return RecoDecay::M(array{array{px0, py0, pz0}, array{px1, py1, pz1}, array{px2, py2, pz2}}, m); }); -DECLARE_SOA_DYNAMIC_COLUMN(M2, m2, [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, const array<double, 3>& m) { return RecoDecay::M2(array{array{px0, py0, pz0}, array{px1, py1, pz1}, array{px2, py2, pz2}}, m); }); -// MC matching result: -// - bit 0: D± → π± K∓ π± -// - bit 1: Lc± → p± K∓ π± -DECLARE_SOA_COLUMN(FlagMCMatchRec, flagMCMatchRec, uint8_t); // reconstruction level -DECLARE_SOA_COLUMN(FlagMCMatchGen, flagMCMatchGen, uint8_t); // generator level - -// functions for specific particles - -// D± → π± K∓ π± - -template <typename T> -auto CtDPlus(const T& candidate) -{ - return candidate.ct(RecoDecay::getMassPDG(411)); -} - -template <typename T> -auto YDPlus(const T& candidate) -{ - return candidate.y(RecoDecay::getMassPDG(411)); -} - -template <typename T> -auto EDPlus(const T& candidate) -{ - return candidate.e(RecoDecay::getMassPDG(411)); -} - -template <typename T> -auto InvMassDPlus(const T& candidate) -{ - return candidate.m(array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kKPlus), RecoDecay::getMassPDG(kPiPlus)}); -} - -// Lc± → p± K∓ π± - -template <typename T> -auto CtLc(const T& candidate) -{ - return candidate.ct(RecoDecay::getMassPDG(4122)); -} - -template <typename T> -auto YLc(const T& candidate) -{ - return candidate.y(RecoDecay::getMassPDG(4122)); -} - -template <typename T> -auto ELc(const T& candidate) -{ - return candidate.e(RecoDecay::getMassPDG(4122)); -} - -template <typename T> -auto InvMassLc(const T& candidate) -{ - return candidate.m(array{RecoDecay::getMassPDG(kProton), RecoDecay::getMassPDG(kKPlus), RecoDecay::getMassPDG(kPiPlus)}); -} -} // namespace hf_cand_prong3 - -// 3-prong decay candidate table -DECLARE_SOA_TABLE(HfCandProng3Base, "AOD", "HFCANDP3BASE", - // general columns - HFCAND_COLUMNS, - // 3-prong specific columns - hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, - hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, - hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2, - hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ImpactParameter2, - hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, hf_cand::ErrorImpactParameter2, - hf_track_index::Index0Id, hf_track_index::Index1Id, hf_track_index::Index2Id, - /* dynamic columns */ - hf_cand_prong3::M<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2>, - hf_cand_prong3::M2<hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2>, - /* prong 2 */ - hf_cand::ImpactParameterNormalised2<hf_cand::ImpactParameter2, hf_cand::ErrorImpactParameter2>, - hf_cand::PtProng2<hf_cand::PxProng2, hf_cand::PyProng2>, - hf_cand::Pt2Prong2<hf_cand::PxProng2, hf_cand::PyProng2>, - hf_cand::PVectorProng2<hf_cand::PxProng2, hf_cand::PyProng2, hf_cand::PzProng2>, - /* dynamic columns that use candidate momentum components */ - hf_cand::Pt<hf_cand_prong3::Px, hf_cand_prong3::Py>, - hf_cand::Pt2<hf_cand_prong3::Px, hf_cand_prong3::Py>, - hf_cand::P<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::P2<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::PVector<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::CPA<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::CPAXY<collision::PosX, collision::PosY, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand_prong3::Px, hf_cand_prong3::Py>, - hf_cand::Ct<collision::PosX, collision::PosY, collision::PosZ, hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::Eta<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::Y<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::E<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>, - hf_cand::E2<hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz>); - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(HfCandProng3Ext, HfCandProng3Base, "HFCANDP3EXT", - hf_cand_prong3::Px, hf_cand_prong3::Py, hf_cand_prong3::Pz); - -using HfCandProng3 = HfCandProng3Ext; - -// table with results of reconstruction level MC matching -DECLARE_SOA_TABLE(HfCandProng3MCRec, "AOD", "HFCANDP3MCREC", - hf_cand_prong3::FlagMCMatchRec); - -// table with results of generator level MC matching -DECLARE_SOA_TABLE(HfCandProng3MCGen, "AOD", "HFCANDP3MCGEN", - hf_cand_prong3::FlagMCMatchGen); - -} // namespace o2::aod - -#endif // O2_ANALYSIS_HFSECONDARYVERTEX_H_ diff --git a/Analysis/DataModel/include/Analysis/Jet.h b/Analysis/DataModel/include/Analysis/Jet.h deleted file mode 100644 index 6f36198fb58af..0000000000000 --- a/Analysis/DataModel/include/Analysis/Jet.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// table definitions for jets -// -// Author: Jochen Klein, Nima Zardoshti - -#pragma once - -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace jet -{ -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Energy, energy, float); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(Area, area, float); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) { return pt * TMath::Cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) { return pt * TMath::Sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) { return pt * TMath::SinH(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) { return pt * TMath::CosH(eta); }); //absolute p -} // namespace jet - -DECLARE_SOA_TABLE(Jets, "AOD", "JET", - o2::soa::Index<>, - jet::CollisionId, - jet::Pt, - jet::Eta, - jet::Phi, - jet::Energy, - jet::Mass, - jet::Area, - jet::Px<jet::Pt, jet::Phi>, - jet::Py<jet::Pt, jet::Phi>, - jet::Pz<jet::Pt, jet::Eta>, - jet::P<jet::Pt, jet::Eta>); - -using Jet = Jets::iterator; - -// TODO: absorb in jet table -// when list of references available -namespace constituents -{ -DECLARE_SOA_INDEX_COLUMN(Jet, jet); -DECLARE_SOA_INDEX_COLUMN(Track, track); -} // namespace constituents - -DECLARE_SOA_TABLE(JetConstituents, "AOD", "CONSTITUENTS", - constituents::JetId, - constituents::TrackId); - -using JetConstituent = JetConstituents::iterator; - -namespace constituentssub -{ -DECLARE_SOA_INDEX_COLUMN(Jet, jet); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Energy, energy, float); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) { return pt * TMath::Cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) { return pt * TMath::Sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) { return pt * TMath::SinH(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) { return pt * TMath::CosH(eta); }); //absolute p -} //namespace constituentssub -DECLARE_SOA_TABLE(JetConstituentsSub, "AOD", "CONSTITUENTSSUB", - constituentssub::JetId, - constituentssub::Pt, - constituentssub::Eta, - constituentssub::Phi, - constituentssub::Energy, - constituentssub::Mass, - constituentssub::Px<constituentssub::Pt, constituentssub::Phi>, - constituentssub::Py<constituentssub::Pt, constituentssub::Phi>, - constituentssub::Pz<constituentssub::Pt, constituentssub::Eta>, - constituentssub::P<constituentssub::Pt, constituentssub::Eta>); -using JetConstituentSub = JetConstituentsSub::iterator; - -} // namespace o2::aod diff --git a/Analysis/DataModel/include/Analysis/Multiplicity.h b/Analysis/DataModel/include/Analysis/Multiplicity.h deleted file mode 100644 index bb4b4aadccf51..0000000000000 --- a/Analysis/DataModel/include/Analysis/Multiplicity.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_MULTIPLICITY_H_ -#define O2_ANALYSIS_MULTIPLICITY_H_ - -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace mult -{ -DECLARE_SOA_COLUMN(MultV0A, multV0A, float); -DECLARE_SOA_COLUMN(MultV0C, multV0C, float); -DECLARE_SOA_COLUMN(MultT0A, multT0A, float); -DECLARE_SOA_COLUMN(MultT0C, multT0C, float); -DECLARE_SOA_COLUMN(MultZNA, multZNA, float); -DECLARE_SOA_COLUMN(MultZNC, multZNC, float); -DECLARE_SOA_DYNAMIC_COLUMN(MultV0M, multV0M, [](float multV0A, float multV0C) -> float { return multV0A + multV0C; }); -DECLARE_SOA_DYNAMIC_COLUMN(MultT0M, multT0M, [](float multT0A, float multT0C) -> float { return multT0A + multT0C; }); -DECLARE_SOA_COLUMN(MultTracklets, multTracklets, int); - -} // namespace mult -DECLARE_SOA_TABLE(Mults, "AOD", "MULT", mult::MultV0A, mult::MultV0C, mult::MultT0A, mult::MultT0C, mult::MultZNA, mult::MultZNC, mult::MultV0M<mult::MultV0A, mult::MultV0C>, mult::MultT0M<mult::MultT0A, mult::MultT0C>, mult::MultTracklets); -using Mult = Mults::iterator; -} // namespace o2::aod - -#endif // O2_ANALYSIS_MULTIPLICITY_H_ diff --git a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h b/Analysis/DataModel/include/Analysis/ReducedInfoTables.h deleted file mode 100644 index 2bb1e7d4f617d..0000000000000 --- a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// - -#ifndef O2_Analysis_ReducedInfoTables_H_ -#define O2_Analysis_ReducedInfoTables_H_ - -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/Centrality.h" -#include "Analysis/EventSelection.h" -#include "PID/PIDResponse.h" -#include "MathUtils/Utils.h" -#include <cmath> - -namespace o2::aod -{ -namespace reducedevent -{ - -// basic event information -DECLARE_SOA_COLUMN(Tag, tag, uint64_t); -DECLARE_SOA_COLUMN(TriggerAlias, triggerAlias, uint32_t); - -} // namespace reducedevent - -DECLARE_SOA_TABLE(ReducedEvents, "AOD", "REDUCEDEVENT", o2::soa::Index<>, - reducedevent::Tag, bc::RunNumber, - collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib); - -DECLARE_SOA_TABLE(ReducedEventsExtended, "AOD", "REEXTENDED", - bc::GlobalBC, bc::TriggerMask, reducedevent::TriggerAlias, cent::CentV0M); - -DECLARE_SOA_TABLE(ReducedEventsVtxCov, "AOD", "REVTXCOV", - collision::CovXX, collision::CovXY, collision::CovXZ, - collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2); - -using ReducedEvent = ReducedEvents::iterator; -using ReducedEventExtended = ReducedEventsExtended::iterator; -using ReducedEventVtxCov = ReducedEventsVtxCov::iterator; - -namespace reducedtrack -{ -// basic track information -DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); -DECLARE_SOA_COLUMN(Index, index, uint16_t); -// ---- flags reserved for storing various information during filtering -DECLARE_SOA_COLUMN(FilteringFlags, filteringFlags, uint64_t); -// BIT 0: track is from MUON arm (if not toggled then this is a barrel track) -// ----------------------------------------------------- -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); -DECLARE_SOA_COLUMN(DcaZ, dcaZ, float); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); - -} //namespace reducedtrack - -// basic track information -DECLARE_SOA_TABLE(ReducedTracks, "AOD", "REDUCEDTRACK", - o2::soa::Index<>, reducedtrack::ReducedEventId, reducedtrack::Index, reducedtrack::FilteringFlags, - reducedtrack::Pt, reducedtrack::Eta, reducedtrack::Phi, reducedtrack::Charge, - reducedtrack::Px<reducedtrack::Pt, reducedtrack::Phi>, - reducedtrack::Py<reducedtrack::Pt, reducedtrack::Phi>, - reducedtrack::Pz<reducedtrack::Pt, reducedtrack::Eta>, - reducedtrack::Pmom<reducedtrack::Pt, reducedtrack::Eta>); - -// barrel track information -DECLARE_SOA_TABLE(ReducedTracksBarrel, "AOD", "RTBARREL", - track::TPCInnerParam, track::Flags, // tracking status flags - track::ITSClusterMap, track::ITSChi2NCl, - track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, - track::TPCNClsShared, track::TPCChi2NCl, - track::TRDChi2, track::TOFChi2, track::Length, reducedtrack::DcaXY, reducedtrack::DcaZ, - track::TPCNClsFound<track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, - track::TPCNClsCrossedRows<track::TPCNClsFindable, track::TPCNClsFindableMinusCrossedRows>); - -// barrel covariance matrix -DECLARE_SOA_TABLE(ReducedTracksBarrelCov, "AOD", "RTBARRELCOV", - track::CYY, track::CZZ, track::CSnpSnp, - track::CTglTgl, track::C1Pt21Pt2); - -// barrel PID information -DECLARE_SOA_TABLE(ReducedTracksBarrelPID, "AOD", "RTBARRELPID", - track::TPCSignal, - pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaMu, - pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, - pidtpc::TPCNSigmaDe, pidtpc::TPCNSigmaTr, pidtpc::TPCNSigmaHe, pidtpc::TPCNSigmaAl, - track::TOFSignal, pidtofbeta::Beta, - pidtof::TOFNSigmaEl, pidtof::TOFNSigmaMu, - pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, - pidtof::TOFNSigmaDe, pidtof::TOFNSigmaTr, pidtof::TOFNSigmaHe, pidtof::TOFNSigmaAl, - track::TRDSignal); - -// muon quantities -namespace reducedmuon -{ -DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); -DECLARE_SOA_COLUMN(FilteringFlags, filteringFlags, uint64_t); -// the (pt,eta,phi,charge) will be computed in the skimming task -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); -} // namespace reducedmuon - -DECLARE_SOA_TABLE(ReducedMuons, "AOD", "RTMUON", - o2::soa::Index<>, reducedmuon::ReducedEventId, reducedmuon::FilteringFlags, - reducedmuon::Pt, reducedmuon::Eta, reducedmuon::Phi, reducedmuon::Charge, - reducedmuon::Px<reducedmuon::Pt, reducedmuon::Phi>, - reducedmuon::Py<reducedmuon::Pt, reducedmuon::Phi>, - reducedmuon::Pz<reducedmuon::Pt, reducedmuon::Eta>, - reducedmuon::Pmom<reducedmuon::Pt, reducedmuon::Eta>); - -DECLARE_SOA_TABLE(ReducedMuonsExtended, "AOD", "RTMUONEXTENDED", - muon::InverseBendingMomentum, - muon::ThetaX, muon::ThetaY, muon::ZMu, - muon::BendingCoor, muon::NonBendingCoor, - muon::Chi2, muon::Chi2MatchTrigger, - muon::RAtAbsorberEnd<muon::BendingCoor, muon::NonBendingCoor, muon::ThetaX, muon::ThetaY, muon::ZMu>, - muon::PDca<muon::InverseBendingMomentum, muon::ThetaX, muon::ThetaY, muon::BendingCoor, muon::NonBendingCoor, muon::ZMu>); - -// iterators -using ReducedTrack = ReducedTracks::iterator; -using ReducedTrackBarrel = ReducedTracksBarrel::iterator; -using ReducedTrackBarrelCov = ReducedTracksBarrelCov::iterator; -using ReducedTrackBarrelPID = ReducedTracksBarrelPID::iterator; -using ReducedMuon = ReducedMuons::iterator; -using ReducedMuonExtended = ReducedMuonsExtended::iterator; -} // namespace o2::aod - -#endif // O2_Analysis_ReducedInfoTables_H_ diff --git a/Analysis/DataModel/include/Analysis/StrangenessTables.h b/Analysis/DataModel/include/Analysis/StrangenessTables.h deleted file mode 100644 index c5983b6fbe335..0000000000000 --- a/Analysis/DataModel/include/Analysis/StrangenessTables.h +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_STRANGENESSTABLES_H_ -#define O2_ANALYSIS_STRANGENESSTABLES_H_ - -#include "Framework/AnalysisDataModel.h" -#include "Analysis/RecoDecay.h" - -namespace o2::aod -{ -namespace v0data -{ -//General V0 properties: position, momentum -DECLARE_SOA_COLUMN(PxPos, pxpos, float); -DECLARE_SOA_COLUMN(PyPos, pypos, float); -DECLARE_SOA_COLUMN(PzPos, pzpos, float); -DECLARE_SOA_COLUMN(PxNeg, pxneg, float); -DECLARE_SOA_COLUMN(PyNeg, pyneg, float); -DECLARE_SOA_COLUMN(PzNeg, pzneg, float); -DECLARE_SOA_COLUMN(X, x, float); -DECLARE_SOA_COLUMN(Y, y, float); -DECLARE_SOA_COLUMN(Z, z, float); - -//Saved from finding: DCAs -DECLARE_SOA_COLUMN(DCAV0Daughters, dcaV0daughters, float); -DECLARE_SOA_COLUMN(DCAPosToPV, dcapostopv, float); -DECLARE_SOA_COLUMN(DCANegToPV, dcanegtopv, float); - -//Derived expressions -//Momenta -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float pxpos, float pypos, float pxneg, float pyneg) { return RecoDecay::sqrtSumOfSquares(pxpos + pxneg, pypos + pyneg); }); - -//Length quantities -DECLARE_SOA_DYNAMIC_COLUMN(V0Radius, v0radius, [](float x, float y) { return RecoDecay::sqrtSumOfSquares(x, y); }); - -//CosPA -DECLARE_SOA_DYNAMIC_COLUMN(V0CosPA, v0cosPA, [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return RecoDecay::CPA(array{pvX, pvY, pvZ}, array{X, Y, Z}, array{Px, Py, Pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(DCAV0ToPV, dcav0topv, [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return TMath::Sqrt((TMath::Power((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + TMath::Power((pvX - X) * Pz - (pvZ - Z) * Px, 2) + TMath::Power((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); }); - -//Calculated on the fly with mass assumption + dynamic tables -DECLARE_SOA_DYNAMIC_COLUMN(MLambda, mLambda, [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { return RecoDecay::M(array{array{pxpos, pypos, pzpos}, array{pxneg, pyneg, pzneg}}, array{RecoDecay::getMassPDG(kProton), RecoDecay::getMassPDG(kPiPlus)}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MAntiLambda, mAntiLambda, [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { return RecoDecay::M(array{array{pxpos, pypos, pzpos}, array{pxneg, pyneg, pzneg}}, array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kProton)}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MK0Short, mK0Short, [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { return RecoDecay::M(array{array{pxpos, pypos, pzpos}, array{pxneg, pyneg, pzneg}}, array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kPiPlus)}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(YK0Short, yK0Short, [](float Px, float Py, float Pz) { return RecoDecay::Y(array{Px, Py, Pz}, RecoDecay::getMassPDG(kK0)); }); -DECLARE_SOA_DYNAMIC_COLUMN(YLambda, yLambda, [](float Px, float Py, float Pz) { return RecoDecay::Y(array{Px, Py, Pz}, RecoDecay::getMassPDG(kLambda0)); }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float Px, float Py, float Pz) { return RecoDecay::Eta(array{Px, Py, Pz}); }); -} // namespace v0data - -namespace v0dataext -{ -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, float, 1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, float, 1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, float, 1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg); -} // namespace v0dataext - -DECLARE_SOA_TABLE(V0Data, "AOD", "V0DATA", - v0data::X, v0data::Y, v0data::Z, - v0data::PxPos, v0data::PyPos, v0data::PzPos, - v0data::PxNeg, v0data::PyNeg, v0data::PzNeg, - v0data::DCAV0Daughters, v0data::DCAPosToPV, v0data::DCANegToPV, - - //Dynamic columns - v0data::Pt<v0data::PxPos, v0data::PyPos, v0data::PxNeg, v0data::PyNeg>, - v0data::V0Radius<v0data::X, v0data::Y>, - v0data::V0CosPA<v0data::X, v0data::Y, v0data::Z, v0dataext::Px, v0dataext::Py, v0dataext::Pz>, - v0data::DCAV0ToPV<v0data::X, v0data::Y, v0data::Z, v0dataext::Px, v0dataext::Py, v0dataext::Pz>, - - //Invariant masses - v0data::MLambda<v0data::PxPos, v0data::PyPos, v0data::PzPos, v0data::PxNeg, v0data::PyNeg, v0data::PzNeg>, - v0data::MAntiLambda<v0data::PxPos, v0data::PyPos, v0data::PzPos, v0data::PxNeg, v0data::PyNeg, v0data::PzNeg>, - v0data::MK0Short<v0data::PxPos, v0data::PyPos, v0data::PzPos, v0data::PxNeg, v0data::PyNeg, v0data::PzNeg>, - - //Longitudinal - v0data::YK0Short<v0dataext::Px, v0dataext::Py, v0dataext::Pz>, - v0data::YLambda<v0dataext::Px, v0dataext::Py, v0dataext::Pz>, - v0data::Eta<v0dataext::Px, v0dataext::Py, v0dataext::Pz>); - -using V0DataOrigin = V0Data; - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(V0DataExt, V0DataOrigin, "V0DATAEXT", - v0dataext::Px, v0dataext::Py, v0dataext::Pz); - -using V0DataFull = V0DataExt; - -namespace v0finderdata -{ -DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, FullTracks, "fPosTrackID"); -DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, FullTracks, "fNegTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0finderdata -DECLARE_SOA_TABLE(V0FinderData, "AOD", "V0FINDERDATA", o2::soa::Index<>, v0finderdata::PosTrackId, v0finderdata::NegTrackId, v0finderdata::CollisionId); - -namespace cascdata -{ -//General V0 properties: position, momentum -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_COLUMN(PxPos, pxpos, float); -DECLARE_SOA_COLUMN(PyPos, pypos, float); -DECLARE_SOA_COLUMN(PzPos, pzpos, float); -DECLARE_SOA_COLUMN(PxNeg, pxneg, float); -DECLARE_SOA_COLUMN(PyNeg, pyneg, float); -DECLARE_SOA_COLUMN(PzNeg, pzneg, float); -DECLARE_SOA_COLUMN(PxBach, pxbach, float); -DECLARE_SOA_COLUMN(PyBach, pybach, float); -DECLARE_SOA_COLUMN(PzBach, pzbach, float); -DECLARE_SOA_COLUMN(X, x, float); -DECLARE_SOA_COLUMN(Y, y, float); -DECLARE_SOA_COLUMN(Z, z, float); -DECLARE_SOA_COLUMN(Xlambda, xlambda, float); -DECLARE_SOA_COLUMN(Ylambda, ylambda, float); -DECLARE_SOA_COLUMN(Zlambda, zlambda, float); - -//Saved from finding: DCAs -DECLARE_SOA_COLUMN(DCAV0Daughters, dcaV0daughters, float); -DECLARE_SOA_COLUMN(DCACascDaughters, dcacascdaughters, float); -DECLARE_SOA_COLUMN(DCAPosToPV, dcapostopv, float); -DECLARE_SOA_COLUMN(DCANegToPV, dcanegtopv, float); -DECLARE_SOA_COLUMN(DCABachToPV, dcabachtopv, float); - -//Derived expressions -//Momenta -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float Px, float Py) { return RecoDecay::sqrtSumOfSquares(Px, Py); }); - -//Length quantities -DECLARE_SOA_DYNAMIC_COLUMN(V0Radius, v0radius, [](float xlambda, float ylambda) { return RecoDecay::sqrtSumOfSquares(xlambda, ylambda); }); -DECLARE_SOA_DYNAMIC_COLUMN(CascRadius, cascradius, [](float x, float y) { return RecoDecay::sqrtSumOfSquares(x, y); }); - -//CosPAs -DECLARE_SOA_DYNAMIC_COLUMN(V0CosPA, v0cosPA, [](float Xlambda, float Ylambda, float Zlambda, float PxLambda, float PyLambda, float PzLambda, float pvX, float pvY, float pvZ) { return RecoDecay::CPA(array{pvX, pvY, pvZ}, array{Xlambda, Ylambda, Zlambda}, array{PxLambda, PyLambda, PzLambda}); }); -DECLARE_SOA_DYNAMIC_COLUMN(CascCosPA, casccosPA, [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return RecoDecay::CPA(array{pvX, pvY, pvZ}, array{X, Y, Z}, array{Px, Py, Pz}); }); -DECLARE_SOA_DYNAMIC_COLUMN(DCAV0ToPV, dcav0topv, [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return TMath::Sqrt((TMath::Power((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + TMath::Power((pvX - X) * Pz - (pvZ - Z) * Px, 2) + TMath::Power((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); }); -DECLARE_SOA_DYNAMIC_COLUMN(DCACascToPV, dcacasctopv, [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { return TMath::Sqrt((TMath::Power((pvY - Y) * Pz - (pvZ - Z) * Py, 2) + TMath::Power((pvX - X) * Pz - (pvZ - Z) * Px, 2) + TMath::Power((pvX - X) * Py - (pvY - Y) * Px, 2)) / (Px * Px + Py * Py + Pz * Pz)); }); - -//Calculated on the fly with mass assumption + dynamic tables -DECLARE_SOA_DYNAMIC_COLUMN(MLambda, mLambda, [](int charge, float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { return RecoDecay::M(array{array{pxpos, pypos, pzpos}, array{pxneg, pyneg, pzneg}}, charge < 0 ? array{RecoDecay::getMassPDG(kProton), RecoDecay::getMassPDG(kPiPlus)} : array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kProton)}); }); -//Calculated on the fly with mass assumption + dynamic tables - -DECLARE_SOA_DYNAMIC_COLUMN(MXi, mXi, [](float pxbach, float pybach, float pzbach, float PxLambda, float PyLambda, float PzLambda) { return RecoDecay::M(array{array{pxbach, pybach, pzbach}, array{PxLambda, PyLambda, PzLambda}}, array{RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kLambda0)}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MOmega, mOmega, [](float pxbach, float pybach, float pzbach, float PxLambda, float PyLambda, float PzLambda) { return RecoDecay::M(array{array{pxbach, pybach, pzbach}, array{PxLambda, PyLambda, PzLambda}}, array{RecoDecay::getMassPDG(kKPlus), RecoDecay::getMassPDG(kLambda0)}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(YXi, yXi, [](float Px, float Py, float Pz) { return RecoDecay::Y(array{Px, Py, Pz}, 1.32171); }); -DECLARE_SOA_DYNAMIC_COLUMN(YOmega, yOmega, [](float Px, float Py, float Pz) { return RecoDecay::Y(array{Px, Py, Pz}, 1.67245); }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float Px, float Py, float Pz) { return RecoDecay::Eta(array{Px, Py, Pz}); }); -} // namespace cascdata - -namespace cascdataext -{ -DECLARE_SOA_EXPRESSION_COLUMN(PxLambda, pxlambda, float, 1.f * aod::cascdata::pxpos + 1.f * aod::cascdata::pxneg); -DECLARE_SOA_EXPRESSION_COLUMN(PyLambda, pylambda, float, 1.f * aod::cascdata::pypos + 1.f * aod::cascdata::pyneg); -DECLARE_SOA_EXPRESSION_COLUMN(PzLambda, pzlambda, float, 1.f * aod::cascdata::pzpos + 1.f * aod::cascdata::pzneg); -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, float, 1.f * aod::cascdata::pxpos + 1.f * aod::cascdata::pxneg + 1.f * aod::cascdata::pxbach); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, float, 1.f * aod::cascdata::pypos + 1.f * aod::cascdata::pyneg + 1.f * aod::cascdata::pybach); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, float, 1.f * aod::cascdata::pzpos + 1.f * aod::cascdata::pzneg + 1.f * aod::cascdata::pzbach); -} // namespace cascdataext - -DECLARE_SOA_TABLE(CascData, "AOD", "CASCDATA", - cascdata::Charge, - cascdata::X, cascdata::Y, cascdata::Z, - cascdata::Xlambda, cascdata::Ylambda, cascdata::Zlambda, - cascdata::PxPos, cascdata::PyPos, cascdata::PzPos, - cascdata::PxNeg, cascdata::PyNeg, cascdata::PzNeg, - cascdata::PxBach, cascdata::PyBach, cascdata::PzBach, - cascdata::DCAV0Daughters, cascdata::DCACascDaughters, - cascdata::DCAPosToPV, cascdata::DCANegToPV, cascdata::DCABachToPV, - - //Dynamic columns - cascdata::Pt<cascdataext::Px, cascdataext::Py>, - cascdata::V0Radius<cascdata::Xlambda, cascdata::Ylambda>, - cascdata::CascRadius<cascdata::X, cascdata::Y>, - cascdata::V0CosPA<cascdata::Xlambda, cascdata::Ylambda, cascdata::Zlambda, cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda>, - cascdata::CascCosPA<cascdata::X, cascdata::Y, cascdata::Z, cascdataext::Px, cascdataext::Py, cascdataext::Pz>, - cascdata::DCAV0ToPV<cascdata::Xlambda, cascdata::Ylambda, cascdata::Zlambda, cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda>, - cascdata::DCACascToPV<cascdata::X, cascdata::Y, cascdata::Z, cascdataext::Px, cascdataext::Py, cascdataext::Pz>, - - //Invariant masses - cascdata::MLambda<cascdata::Charge, cascdata::PxPos, cascdata::PyPos, cascdata::PzPos, cascdata::PxNeg, cascdata::PyNeg, cascdata::PzNeg>, - cascdata::MXi<cascdata::PxBach, cascdata::PyBach, cascdata::PzBach, cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda>, - cascdata::MOmega<cascdata::PxBach, cascdata::PyBach, cascdata::PzBach, cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda>, - //Longitudinal - cascdata::YXi<cascdataext::Px, cascdataext::Py, cascdataext::Pz>, - cascdata::YOmega<cascdataext::Px, cascdataext::Py, cascdataext::Pz>, - cascdata::Eta<cascdataext::Px, cascdataext::Py, cascdataext::Pz>); - -using CascDataOrigin = CascData; - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(CascDataExt, CascDataOrigin, "CascDATAEXT", - cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda, - cascdataext::Px, cascdataext::Py, cascdataext::Pz); - -using CascDataFull = CascDataExt; - -namespace cascfinderdata -{ -DECLARE_SOA_INDEX_COLUMN_FULL(V0, v0, int, V0FinderData, "fV0ID"); -DECLARE_SOA_INDEX_COLUMN_FULL(BachTrack, bachTrack, int, FullTracks, "fBachTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace cascfinderdata -DECLARE_SOA_TABLE(CascFinderData, "AOD", "CASCFINDERDATA", o2::soa::Index<>, cascfinderdata::V0Id, cascfinderdata::BachTrackId, cascfinderdata::CollisionId); -} // namespace o2::aod - -#endif // O2_ANALYSIS_STRANGENESSTABLES_H_ diff --git a/Analysis/DataModel/include/Analysis/TrackSelectionTables.h b/Analysis/DataModel/include/Analysis/TrackSelectionTables.h deleted file mode 100644 index 4d3dcacf6b707..0000000000000 --- a/Analysis/DataModel/include/Analysis/TrackSelectionTables.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_ANALYSIS_TRACKSELECTIONTABLES_H_ -#define O2_ANALYSIS_TRACKSELECTIONTABLES_H_ - -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace track -{ -// Columns to store the DCA to the primary vertex -DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); -DECLARE_SOA_COLUMN(DcaZ, dcaZ, float); - -// Columns to store track filter decisions -DECLARE_SOA_COLUMN(IsGlobalTrack, isGlobalTrack, bool); -DECLARE_SOA_COLUMN(IsGlobalTrackSDD, isGlobalTrackSDD, bool); - -} // namespace track -DECLARE_SOA_TABLE(TracksExtended, "AOD", "TRACKEXTENDED", track::DcaXY, - track::DcaZ); - -DECLARE_SOA_TABLE(TrackSelection, "AOD", "TRACKSELECTION", track::IsGlobalTrack, - track::IsGlobalTrackSDD); -} // namespace o2::aod - -#endif // O2_ANALYSIS_TRACKSELECTIONTABLES_H_ diff --git a/Analysis/DataModel/include/PID/BetheBloch.h b/Analysis/DataModel/include/PID/BetheBloch.h deleted file mode 100644 index 63f670e2bd265..0000000000000 --- a/Analysis/DataModel/include/PID/BetheBloch.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file BetheBloch.h -/// \author Nicolo' Jacazio -/// \since 07/08/2020 -/// \brief Implementation for the TPC PID response of the BB parametrization -/// - -#ifndef O2_ANALYSIS_PID_BETHEBLOCH_H_ -#define O2_ANALYSIS_PID_BETHEBLOCH_H_ - -#include "TPCSimulation/Detector.h" -#include "PIDBase/ParamBase.h" - -namespace o2::pid::tpc -{ - -class BetheBloch : public Parametrization -{ - public: - BetheBloch() : Parametrization("BetheBloch", 7){}; - ~BetheBloch() override = default; - float operator()(const float* x) const override - { - return mParameters[5] * o2::tpc::Detector::BetheBlochAleph(x[0], mParameters[0], mParameters[1], mParameters[2], mParameters[3], mParameters[4]) * TMath::Power(x[1], mParameters[6]); - } - ClassDef(BetheBloch, 1); -}; - -} // namespace o2::pid::tpc - -#endif diff --git a/Analysis/DataModel/include/PID/PIDResponse.h b/Analysis/DataModel/include/PID/PIDResponse.h deleted file mode 100644 index aaf6143cc35b7..0000000000000 --- a/Analysis/DataModel/include/PID/PIDResponse.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file PIDResponse.h -/// \author Nicolo' Jacazio -/// \brief Set of tables, tasks and utilities to provide the interface between -/// the analysis data model and the PID response -/// - -#ifndef O2_FRAMEWORK_PIDRESPONSE_H_ -#define O2_FRAMEWORK_PIDRESPONSE_H_ - -// O2 includes -#include "Framework/ASoA.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" - -namespace o2::aod -{ - -namespace pidtofbeta -{ -DECLARE_SOA_COLUMN(Beta, beta, float); -DECLARE_SOA_COLUMN(BetaError, betaerror, float); -// -DECLARE_SOA_COLUMN(ExpBetaEl, expbetael, float); -DECLARE_SOA_COLUMN(ExpBetaElError, expbetaelerror, float); -// -DECLARE_SOA_COLUMN(SeparationBetaEl, separationbetael, float); -DECLARE_SOA_DYNAMIC_COLUMN(DiffBetaEl, diffbetael, [](float beta, float expbetael) -> float { return beta - expbetael; }); -} // namespace pidtofbeta - -namespace pidtof -{ -// Expected times -DECLARE_SOA_COLUMN(TOFExpSignalEl, tofExpSignalEl, float); -DECLARE_SOA_COLUMN(TOFExpSignalMu, tofExpSignalMu, float); -DECLARE_SOA_COLUMN(TOFExpSignalPi, tofExpSignalPi, float); -DECLARE_SOA_COLUMN(TOFExpSignalKa, tofExpSignalKa, float); -DECLARE_SOA_COLUMN(TOFExpSignalPr, tofExpSignalPr, float); -DECLARE_SOA_COLUMN(TOFExpSignalDe, tofExpSignalDe, float); -DECLARE_SOA_COLUMN(TOFExpSignalTr, tofExpSignalTr, float); -DECLARE_SOA_COLUMN(TOFExpSignalHe, tofExpSignalHe, float); -DECLARE_SOA_COLUMN(TOFExpSignalAl, tofExpSignalAl, float); -// Expected sigma -DECLARE_SOA_COLUMN(TOFExpSigmaEl, tofExpSigmaEl, float); -DECLARE_SOA_COLUMN(TOFExpSigmaMu, tofExpSigmaMu, float); -DECLARE_SOA_COLUMN(TOFExpSigmaPi, tofExpSigmaPi, float); -DECLARE_SOA_COLUMN(TOFExpSigmaKa, tofExpSigmaKa, float); -DECLARE_SOA_COLUMN(TOFExpSigmaPr, tofExpSigmaPr, float); -DECLARE_SOA_COLUMN(TOFExpSigmaDe, tofExpSigmaDe, float); -DECLARE_SOA_COLUMN(TOFExpSigmaTr, tofExpSigmaTr, float); -DECLARE_SOA_COLUMN(TOFExpSigmaHe, tofExpSigmaHe, float); -DECLARE_SOA_COLUMN(TOFExpSigmaAl, tofExpSigmaAl, float); -// NSigma -DECLARE_SOA_COLUMN(TOFNSigmaEl, tofNSigmaEl, float); -DECLARE_SOA_COLUMN(TOFNSigmaMu, tofNSigmaMu, float); -DECLARE_SOA_COLUMN(TOFNSigmaPi, tofNSigmaPi, float); -DECLARE_SOA_COLUMN(TOFNSigmaKa, tofNSigmaKa, float); -DECLARE_SOA_COLUMN(TOFNSigmaPr, tofNSigmaPr, float); -DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); -DECLARE_SOA_COLUMN(TOFNSigmaTr, tofNSigmaTr, float); -DECLARE_SOA_COLUMN(TOFNSigmaHe, tofNSigmaHe, float); -DECLARE_SOA_COLUMN(TOFNSigmaAl, tofNSigmaAl, float); -} // namespace pidtof - -using namespace pidtofbeta; -DECLARE_SOA_TABLE(pidRespTOFbeta, "AOD", "pidRespTOFbeta", - Beta, BetaError, - ExpBetaEl, ExpBetaElError, - SeparationBetaEl, - DiffBetaEl<Beta, ExpBetaEl>); -using namespace pidtof; -DECLARE_SOA_TABLE(pidRespTOF, "AOD", "pidRespTOF", - TOFExpSignalEl, TOFExpSignalMu, TOFExpSignalPi, TOFExpSignalKa, TOFExpSignalPr, TOFExpSignalDe, TOFExpSignalTr, TOFExpSignalHe, TOFExpSignalAl, - TOFExpSigmaEl, TOFExpSigmaMu, TOFExpSigmaPi, TOFExpSigmaKa, TOFExpSigmaPr, TOFExpSigmaDe, TOFExpSigmaTr, TOFExpSigmaHe, TOFExpSigmaAl, - TOFNSigmaEl, TOFNSigmaMu, TOFNSigmaPi, TOFNSigmaKa, TOFNSigmaPr, TOFNSigmaDe, TOFNSigmaTr, TOFNSigmaHe, TOFNSigmaAl); - -namespace pidtpc -{ -// Expected signals -DECLARE_SOA_COLUMN(TPCExpSignalEl, tpcExpSignalEl, float); -DECLARE_SOA_COLUMN(TPCExpSignalMu, tpcExpSignalMu, float); -DECLARE_SOA_COLUMN(TPCExpSignalPi, tpcExpSignalPi, float); -DECLARE_SOA_COLUMN(TPCExpSignalKa, tpcExpSignalKa, float); -DECLARE_SOA_COLUMN(TPCExpSignalPr, tpcExpSignalPr, float); -DECLARE_SOA_COLUMN(TPCExpSignalDe, tpcExpSignalDe, float); -DECLARE_SOA_COLUMN(TPCExpSignalTr, tpcExpSignalTr, float); -DECLARE_SOA_COLUMN(TPCExpSignalHe, tpcExpSignalHe, float); -DECLARE_SOA_COLUMN(TPCExpSignalAl, tpcExpSignalAl, float); -// Expected sigma -DECLARE_SOA_COLUMN(TPCExpSigmaEl, tpcExpSigmaEl, float); -DECLARE_SOA_COLUMN(TPCExpSigmaMu, tpcExpSigmaMu, float); -DECLARE_SOA_COLUMN(TPCExpSigmaPi, tpcExpSigmaPi, float); -DECLARE_SOA_COLUMN(TPCExpSigmaKa, tpcExpSigmaKa, float); -DECLARE_SOA_COLUMN(TPCExpSigmaPr, tpcExpSigmaPr, float); -DECLARE_SOA_COLUMN(TPCExpSigmaDe, tpcExpSigmaDe, float); -DECLARE_SOA_COLUMN(TPCExpSigmaTr, tpcExpSigmaTr, float); -DECLARE_SOA_COLUMN(TPCExpSigmaHe, tpcExpSigmaHe, float); -DECLARE_SOA_COLUMN(TPCExpSigmaAl, tpcExpSigmaAl, float); -// NSigma -DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, float); -DECLARE_SOA_COLUMN(TPCNSigmaMu, tpcNSigmaMu, float); -DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); -DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, float); -DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); -DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNSigmaDe, float); -DECLARE_SOA_COLUMN(TPCNSigmaTr, tpcNSigmaTr, float); -DECLARE_SOA_COLUMN(TPCNSigmaHe, tpcNSigmaHe, float); -DECLARE_SOA_COLUMN(TPCNSigmaAl, tpcNSigmaAl, float); -} // namespace pidtpc - -using namespace pidtpc; -DECLARE_SOA_TABLE(pidRespTPC, "AOD", "pidRespTPC", - TPCExpSignalEl, TPCExpSignalMu, TPCExpSignalPi, TPCExpSignalKa, TPCExpSignalPr, TPCExpSignalDe, TPCExpSignalTr, TPCExpSignalHe, TPCExpSignalAl, - TPCExpSigmaEl, TPCExpSigmaMu, TPCExpSigmaPi, TPCExpSigmaKa, TPCExpSigmaPr, TPCExpSigmaDe, TPCExpSigmaTr, TPCExpSigmaHe, TPCExpSigmaAl, - TPCNSigmaEl, TPCNSigmaMu, TPCNSigmaPi, TPCNSigmaKa, TPCNSigmaPr, TPCNSigmaDe, TPCNSigmaTr, TPCNSigmaHe, TPCNSigmaAl); - -} // namespace o2::aod - -#endif // O2_FRAMEWORK_PIDRESPONSE_H_ diff --git a/Analysis/DataModel/include/PID/PIDTOF.h b/Analysis/DataModel/include/PID/PIDTOF.h deleted file mode 100644 index 59a007641476c..0000000000000 --- a/Analysis/DataModel/include/PID/PIDTOF.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file PIDTOF.h -/// \author Nicolo' Jacazio -/// \since 02/07/2020 -/// \brief Implementation of the TOF detector response for PID -/// - -#ifndef O2_FRAMEWORK_PIDTOF_H_ -#define O2_FRAMEWORK_PIDTOF_H_ - -// ROOT includes -#include "Rtypes.h" -#include "TMath.h" - -// O2 includes -#include "Framework/Logger.h" -#include "ReconstructionDataFormats/PID.h" -#include "PIDBase/DetectorResponse.h" - -namespace o2::pid::tof -{ - -// Utility values -static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; /// Speed of light in TOF units (cm/ps) - -/// \brief Class to handle the the TOF detector response for the TOF beta measurement -template <typename Coll, typename Trck, o2::track::PID::ID id> -class Beta -{ - public: - Beta() = default; - ~Beta() = default; - - /// Computes the beta of a track given a length, a time measurement and an event time - static float GetBeta(const float length, const float tofSignal, const float collisionTime); - - /// Gets the beta for the track of interest - float GetBeta(const Coll& col, const Trck& trk) const { return GetBeta(trk.length(), trk.tofSignal(), col.collisionTime()); } - - /// Computes the expected uncertainty on the beta measurement - static float GetExpectedSigma(const float& length, const float& tofSignal, const float& collisionTime, const float& time_reso); - - /// Gets the expected uncertainty on the beta measurement of the track of interest - float GetExpectedSigma(const Coll& col, const Trck& trk) const { return GetExpectedSigma(trk.length(), trk.tofSignal(), col.collisionTime(), mExpectedResolution); } - - /// Gets the expected beta for a given mass hypothesis (no energy loss taken into account) - static float GetExpectedSignal(const float& mom, const float& mass); - - /// Gets the expected beta given the particle index (no energy loss taken into account) - float GetExpectedSignal(const Coll& col, const Trck& trk) const { return GetExpectedSignal(trk.p(), o2::track::PID::getMass2Z(id)); } - - /// Gets the number of sigmas with respect the approximate beta (no energy loss taken into account) - float GetSeparation(const Coll& col, const Trck& trk) const { return (GetBeta(col, trk) - GetExpectedSignal(col, trk)) / GetExpectedSigma(col, trk); } - - float mExpectedResolution = 80; /// Expected time resolution -}; - -//_________________________________________________________________________ -template <typename Coll, typename Trck, o2::track::PID::ID id> -float Beta<Coll, Trck, id>::GetBeta(const float length, const float tofSignal, const float collisionTime) -{ - if (tofSignal <= 0) { - return -999.f; - } - return length / (tofSignal - collisionTime) / kCSPEED; -} - -//_________________________________________________________________________ -template <typename Coll, typename Trck, o2::track::PID::ID id> -float Beta<Coll, Trck, id>::GetExpectedSigma(const float& length, const float& tofSignal, const float& collisionTime, const float& time_reso) -{ - if (tofSignal <= 0) { - return -999.f; - } - return GetBeta(length, tofSignal, collisionTime) / (tofSignal - collisionTime) * time_reso; -} - -//_________________________________________________________________________ -template <typename Coll, typename Trck, o2::track::PID::ID id> -float Beta<Coll, Trck, id>::GetExpectedSignal(const float& mom, const float& mass) -{ - if (mom > 0) { - return mom / TMath::Sqrt(mom * mom + mass * mass); - } - return 0; -} - -/// \brief Class to handle the the TOF detector response for the expected time -template <typename Coll, typename Trck, o2::track::PID::ID id> -class ExpTimes -{ - public: - ExpTimes() = default; - ~ExpTimes() = default; - - /// Computes the expected time of a track, given it TOF expected momentum - static float ComputeExpectedTime(const float& tofExpMom, const float& length, const float& massZ); - - /// Gets the expected signal of the track of interest under the PID assumption - float GetExpectedSignal(const Coll& col, const Trck& trk) const { return ComputeExpectedTime(trk.tofExpMom() / kCSPEED, trk.length(), o2::track::PID::getMass2Z(id)); } - - /// Gets the expected resolution of the measurement - float GetExpectedSigma(const DetectorResponse& response, const Coll& col, const Trck& trk) const; - - /// Gets the number of sigmas with respect the expected time - float GetSeparation(const DetectorResponse& response, const Coll& col, const Trck& trk) const { return (trk.tofSignal() - col.collisionTime() - GetExpectedSignal(col, trk)) / GetExpectedSigma(response, col, trk); } -}; - -//_________________________________________________________________________ -template <typename Coll, typename Trck, o2::track::PID::ID id> -float ExpTimes<Coll, Trck, id>::ComputeExpectedTime(const float& tofExpMom, const float& length, const float& massZ) -{ - const float energy = sqrt((massZ * massZ) + (tofExpMom * tofExpMom)); - return length * energy / (kCSPEED * tofExpMom); -} - -//_________________________________________________________________________ -template <typename Coll, typename Trck, o2::track::PID::ID id> -float ExpTimes<Coll, Trck, id>::GetExpectedSigma(const DetectorResponse& response, const Coll& col, const Trck& trk) const -{ - if (trk.tofSignal() <= 0) { - return -999.f; - } - const float x[4] = {trk.p(), trk.tofSignal(), col.collisionTimeRes(), o2::track::PID::getMass2Z(id)}; - return response(response.kSigma, x); - // return response(response.kSigma, const Coll& col, const Trck& trk, id); -} - -} // namespace o2::pid::tof - -#endif // O2_FRAMEWORK_PIDTOF_H_ diff --git a/Analysis/DataModel/include/PID/PIDTPC.h b/Analysis/DataModel/include/PID/PIDTPC.h deleted file mode 100644 index bee121f4bc9d7..0000000000000 --- a/Analysis/DataModel/include/PID/PIDTPC.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file PIDTPC.h -/// \author Nicolo' Jacazio -/// \since 2020-07-24 -/// \brief Implementation of the TPC detector response for PID -/// - -#ifndef O2_FRAMEWORK_PIDTPC_H_ -#define O2_FRAMEWORK_PIDTPC_H_ - -// ROOT includes -#include "Rtypes.h" -#include "TMath.h" - -// O2 includes -#include "Framework/Logger.h" -#include "ReconstructionDataFormats/PID.h" -#include "PIDBase/DetectorResponse.h" - -namespace o2::pid::tpc -{ - -/// \brief Class to handle the the TPC detector response -template <typename Coll, typename Trck, o2::track::PID::ID id> -class ELoss -{ - public: - ELoss() = default; - ~ELoss() = default; - - /// Gets the expected signal of the measurement - float GetExpectedSignal(DetectorResponse& response, const Coll& col, const Trck& trk) const; - - /// Gets the expected resolution of the measurement - float GetExpectedSigma(DetectorResponse& response, const Coll& col, const Trck& trk) const; - - /// Gets the number of sigmas with respect the expected value - float GetSeparation(DetectorResponse& response, const Coll& col, const Trck& trk) const { return (trk.tpcSignal() - GetExpectedSignal(response, col, trk)) / GetExpectedSigma(response, col, trk); } -}; - -template <typename Coll, typename Trck, o2::track::PID::ID id> -float ELoss<Coll, Trck, id>::GetExpectedSignal(DetectorResponse& response, const Coll& col, const Trck& trk) const -{ - const float x[2] = {trk.tpcInnerParam() / o2::track::PID::getMass(id), (float)o2::track::PID::getCharge(id)}; - return response(DetectorResponse::kSignal, x); -} - -template <typename Coll, typename Trck, o2::track::PID::ID id> -float ELoss<Coll, Trck, id>::GetExpectedSigma(DetectorResponse& response, const Coll& col, const Trck& trk) const -{ - const float x[2] = {trk.tpcSignal(), (float)trk.tpcNClsFound()}; - return response(DetectorResponse::kSigma, x); -} - -} // namespace o2::pid::tpc - -#endif // O2_FRAMEWORK_PIDTPC_H_ diff --git a/Analysis/DataModel/include/PID/TOFReso.h b/Analysis/DataModel/include/PID/TOFReso.h deleted file mode 100644 index 7cb8745c3e7f3..0000000000000 --- a/Analysis/DataModel/include/PID/TOFReso.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file TOFReso.h -/// \author Nicolo' Jacazio -/// \since 07/08/2020 -/// \brief Implementation for the TOF PID response of the expected times resolution -/// - -#ifndef O2_ANALYSIS_PID_TOFRESO_H_ -#define O2_ANALYSIS_PID_TOFRESO_H_ - -// Root includes -#include "TMath.h" -// O2 includes -#include "PIDBase/ParamBase.h" - -namespace o2::pid::tof -{ - -class TOFReso : public Parametrization -{ - public: - TOFReso() : Parametrization("TOFReso", 5){}; - ~TOFReso() override = default; - float operator()(const float* x) const override - { - const float mom = abs(x[0]); - if (mom <= 0) { - return -999; - } - const float time = x[1]; - const float evtimereso = x[2]; - const float mass = x[3]; - const float dpp = mParameters[0] + mParameters[1] * mom + mParameters[2] * mass / mom; // mean relative pt resolution; - const float sigma = dpp * time / (1. + mom * mom / (mass * mass)); - return TMath::Sqrt(sigma * sigma + mParameters[3] * mParameters[3] / mom / mom + mParameters[4] * mParameters[4] + evtimereso * evtimereso); - } - ClassDef(TOFReso, 1); -}; - -} // namespace o2::pid::tof - -#endif diff --git a/Analysis/DataModel/include/PID/TPCReso.h b/Analysis/DataModel/include/PID/TPCReso.h deleted file mode 100644 index 7ffc1a7f8e3d0..0000000000000 --- a/Analysis/DataModel/include/PID/TPCReso.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file TPCReso.h -/// \author Nicolo' Jacazio -/// \since 07/08/2020 -/// \brief Implementation for the TPC PID response of the BB resolution -/// - -#ifndef O2_ANALYSIS_PID_TPCRESO_H_ -#define O2_ANALYSIS_PID_TPCRESO_H_ - -#include "PIDBase/ParamBase.h" - -namespace o2::pid::tpc -{ - -class TPCReso : public Parametrization -{ - public: - TPCReso() : Parametrization("TPCReso", 2){}; - ~TPCReso() override = default; - float operator()(const float* x) const override - { - // relative dEdx resolution rel sigma = fRes0*sqrt(1+fResN2/npoint) - return x[0] * mParameters[0] * (x[1] > 0 ? sqrt(1. + mParameters[1] / x[1]) : 1.f); - } - ClassDef(TPCReso, 1); -}; - -} // namespace o2::pid::tpc - -#endif diff --git a/Analysis/DataModel/include/PIDBase/DetectorResponse.h b/Analysis/DataModel/include/PIDBase/DetectorResponse.h deleted file mode 100644 index b5f3fb3a55a00..0000000000000 --- a/Analysis/DataModel/include/PIDBase/DetectorResponse.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file DetectorResponse.h -/// \author Nicolo' Jacazio -/// \since 2020-07-30 -/// \brief Handler for any detector (or other entity) response. -/// This provides the basic quantities computed by any response i.e. expected values, resolutions and Nsigmas -/// - -#ifndef O2_ANALYSIS_PID_DETECTORRESPONSE_H_ -#define O2_ANALYSIS_PID_DETECTORRESPONSE_H_ - -#include <array> -#include <vector> -#include "Framework/Logger.h" -// ROOT includes -#include "Rtypes.h" -#include "TMath.h" -#include "TFile.h" - -// O2 includes -#include "ReconstructionDataFormats/PID.h" -#include "PIDBase/ParamBase.h" - -namespace o2::pid -{ -/// \brief Class to handle the general detector response -class DetectorResponse -{ - public: - DetectorResponse() = default; - virtual ~DetectorResponse() = default; - - /// Enumeration of the different types of parametrizations - enum Param_t { kSignal, - kSigma, - kNParams }; - - static constexpr std::array<char const*, kNParams> ParamName = {{"Signal", "Sigma"}}; - - /// Setter for the parametrization from input TFile - /// \param fname File name used for input - /// \param pname Name of the parametrization in the file - /// \param ptype Type of the parametrization - void LoadParamFromFile(const TString fname, const TString pname, const Param_t ptype); - - /// Setter for the parametrization - /// \param ptype Type of the parametrization - /// \param param Parametrization - void LoadParam(const Param_t ptype, Parametrization* param) { mParam[ptype] = param; } - - /// Getter for the parametrizations - Parametrization* GetParam(const Param_t ptype) const { return mParam[ptype]; } - - /// Setter for the parametrizations parameters, if the parametrization is not yet initialized a new parametrization is created without any implementation and just parameters - /// \param ptype parametrization type - /// \param p vector with parameters - void SetParameters(const Param_t ptype, std::vector<pidvar_t> p); - - /// Getter for the value of the parametrization - /// \param ptype parametrization type - /// \param x array with parameters - virtual pidvar_t operator()(const Param_t ptype, const pidvar_t* x) const { return mParam[ptype]->operator()(x); } - - private: - /// Parametrizations for the expected signal and sigma - std::array<Parametrization*, kNParams> mParam; -}; - -inline void DetectorResponse::LoadParamFromFile(const TString fname, const TString pname, const Param_t ptype) -{ - TFile f(fname, "READ"); - if (!f.Get(pname)) { - LOG(fatal) << "Did not find parametrization " << pname << " in file " << fname; - } - LOG(info) << "Loading parametrization " << pname << " from TFile " << fname; - f.GetObject(pname, mParam[ptype]); - f.Close(); - mParam[ptype]->Print(); - mParam[ptype]->PrintParametrization(); -} - -inline void DetectorResponse::SetParameters(const DetectorResponse::Param_t ptype, std::vector<pidvar_t> p) -{ - if (!mParam[ptype]) { - const std::string pname = std::string(ParamName[ptype]) + "_default_param"; - LOG(info) << "Creating new parametrization " << pname << " of size " << p.size(); - mParam[ptype] = new Parametrization(pname, p.size()); - mParam[ptype]->Print(); - } - mParam[ptype]->SetParameters(p); -} - -} // namespace o2::pid - -#endif // O2_ANALYSIS_PID_DETECTORRESPONSE_H_ diff --git a/Analysis/DataModel/include/PIDBase/ParamBase.h b/Analysis/DataModel/include/PIDBase/ParamBase.h deleted file mode 100644 index 9681800e7dc39..0000000000000 --- a/Analysis/DataModel/include/PIDBase/ParamBase.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file ParamBase.h -/// \author Nicolo' Jacazio -/// -/// \brief Set of utilities to handle the parametrization of the PID response for each detector -/// These are the basic storage elements to be kept in the CCDB -/// - -#ifndef O2_FRAMEWORK_PARAMBASE_H_ -#define O2_FRAMEWORK_PARAMBASE_H_ - -// ROOT includes -#include "TNamed.h" - -namespace o2::pid -{ -/// Variable to use for the pid input/output i.e. float, double et cetera -using pidvar_t = float; - -/// \brief Class to handle the parameters of a given detector response -class Parameters : public TObject -{ - public: - /// Default constructor - Parameters() = default; - - /// Parametric constructor - /// \param npar Number of parameters in the container - Parameters(unsigned int npar) : mPar(std::vector<pidvar_t>(npar)){}; - - /// Parametric constructor - /// \param params Parameters to initialize the container - Parameters(const std::vector<pidvar_t> params) : mPar{} { SetParameters(params); }; - - /// Default destructor - ~Parameters() override = default; - - /// Setter for the parameter at position iparam - /// \param iparam index in the array of the parameters - /// \param value value of the parameter at position iparam - void SetParameter(const unsigned int iparam, const pidvar_t value) { mPar[iparam] = value; } - - /// Setter for the parameter, using an array - /// \param param array with parameters - void SetParameters(const pidvar_t* params) { std::copy(params, params + mPar.size(), mPar.begin()); } - - /// Setter for the parameter, using an array - /// \param params array with parameters - void SetParameters(const std::vector<pidvar_t> params); - - /// Printer of the parameter values - void PrintParameters() const; - - /// Getter for the parameters - /// \return returns an array of parameters - const pidvar_t* GetParameters() const { return mPar.data(); } - - /// Getter for the size of the parameter - /// \return returns the size of the parameter array - unsigned int size() const { return mPar.size(); } - - /// Getter of the parameter at position i - /// \param i index of the parameter to get - /// \return returns the parameter value at position i - pidvar_t operator[](unsigned int i) const { return mPar[i]; } - - private: - /// Vector of the parameter - std::vector<pidvar_t> mPar; - - ClassDef(Parameters, 1); // Container for parameter of parametrizations -}; - -/// \brief Class to handle the parameters and the parametrization of a given detector response -class Parametrization : public TNamed -{ - public: - /// Default constructor - Parametrization() : TNamed("DefaultParametrization", "DefaultParametrization"), mParameters{0} {}; - - /// Parametric constructor - /// \param name Name (and title) of the parametrization - /// \param size Number of parameters of the parametrization - Parametrization(TString name, unsigned int size) : TNamed(name, name), mParameters{size} {}; - - /// Parametric constructor - /// \param name Name (and title) of the parametrization - /// \param params Parameters of the parametrization - Parametrization(TString name, const std::vector<pidvar_t> params) : TNamed(name, name), mParameters{params} {}; - - /// Default destructor - ~Parametrization() override = default; - - /// Getter for parametrization values, to be reimplemented in the custom parametrization of the user - /// \param x array of variables to use in order to compute the return value - virtual pidvar_t operator()(const pidvar_t* x) const; - - /// Printer for parameters - void PrintParametrization() const; - - /// Setter for the parameter at position iparam - /// \param iparam index in the array of the parameters - /// \param value value of the parameter at position iparam - void SetParameter(const unsigned int iparam, const pidvar_t value) { mParameters.SetParameter(iparam, value); } - - /// Setter for the parameter, using an array - /// \param params array with parameters - void SetParameters(const std::vector<pidvar_t> params) { mParameters.SetParameters(params); } - - /// Getter for the parameters - Parameters GetParameters() const { return mParameters; } - - protected: - /// Parameters of the parametrization - Parameters mParameters; - - ClassDef(Parametrization, 1); // Container for the parametrization of the response function -}; - -} // namespace o2::pid - -#endif // O2_FRAMEWORK_PARAMBASE_H_ diff --git a/Analysis/DataModel/src/AnalysisDataModelLinkDef.h b/Analysis/DataModel/src/AnalysisDataModelLinkDef.h deleted file mode 100644 index 5db890293367e..0000000000000 --- a/Analysis/DataModel/src/AnalysisDataModelLinkDef.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::pid::Parameters + ; -#pragma link C++ class o2::pid::Parametrization + ; - -#pragma link C++ class o2::pid::tof::TOFReso + ; - -#pragma link C++ class o2::pid::tpc::BetheBloch + ; -#pragma link C++ class o2::pid::tpc::TPCReso + ; diff --git a/Analysis/DataModel/src/ParamBase.cxx b/Analysis/DataModel/src/ParamBase.cxx deleted file mode 100644 index a4267eedfcd87..0000000000000 --- a/Analysis/DataModel/src/ParamBase.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file ParamBase.cxx -/// \author Nicolo' Jacazio -/// \since 07/08/2020 -/// \brief Set of utilities to handle the parametrization of the PID response for each detector -/// These are the basic storage elements to be kept in the CCDB -/// - -#include "PIDBase/ParamBase.h" -#include "Framework/Logger.h" - -namespace o2::pid -{ - -void Parameters::SetParameters(const std::vector<pidvar_t> params) -{ - if (mPar.size() != params.size()) { - LOG(fatal) << "Updating parametrization size!"; - } - mPar.assign(params.begin(), params.end()); -} - -void Parameters::PrintParameters() const -{ - for (unsigned int i = 0; i < size(); i++) { - LOG(info) << "Parameter " << i << "/" << size() - 1 << " is " << mPar[i]; - } -}; - -pidvar_t Parametrization::operator()(const pidvar_t* x) const -{ - LOG(fatal) << "Parametrization " << fName << " is not implemented!"; - return -999.999f; -} - -void Parametrization::PrintParametrization() const -{ - LOG(info) << "Parametrization " << fName; - mParameters.PrintParameters(); -}; - -} // namespace o2::pid \ No newline at end of file diff --git a/Analysis/DataModel/src/aodDataModelGraph.cxx b/Analysis/DataModel/src/aodDataModelGraph.cxx deleted file mode 100644 index 49454df0cd62a..0000000000000 --- a/Analysis/DataModel/src/aodDataModelGraph.cxx +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/AnalysisDataModel.h" -#include "Analysis/HFSecondaryVertex.h" -#include "PID/PIDResponse.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/Centrality.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/Jet.h" -#include "Analysis/StrangenessTables.h" -#include <fmt/printf.h> -#include <map> - -using namespace o2::framework; -using namespace o2::aod; -using namespace o2::soa; - -static int count = 0; -static int width = 10; -static int height = 10; - -void inline graphSize() -{ - fmt::printf( - R"( -size="%d,%d"; -)", - width, height); -} - -struct Style { - const char* color; - const char* background; - const char* fontcolor; - const char* headerfontcolor; - const char* headerbgcolor; - const char* methodcolor; - const char* methodbgcolor; - const char* indexcolor; - const char* indexbgcolor; -}; - -static Style styles[] = { - {"black", "gray80", "black", "black", "gray70", "black", "gray60", "black", "gray50"}, - {"/reds9/2", "/reds9/4", "white", "white", "/reds9/7", "black", "/reds9/6", "/reds9/1", "/reds9/5"}, - {"/greens9/2", "/greens9/4", "white", "white", "/greens9/7", "black", "/greens9/6", "/greens9/1", "/greens9/5"}, - {"/blues9/2", "/blues9/4", "white", "white", "/blues9/7", "black", "/blues9/6", "/blues9/1", "/blues9/5"}, -}; - -Style const& getDefaultStyle() -{ - return styles[0]; -} - -enum StyleType : int { - DEFAULT = 0, - RED = 1, - GREEN = 2, - BLUE = 3, -}; - -static std::vector<std::pair<std::string, StyleType>> tableStyles = { - {"HfTrackIndexProng", StyleType::GREEN}, - {"pidResp", StyleType::GREEN}, - {"Mults", StyleType::GREEN}, - {"Cents", StyleType::GREEN}, - {"Jet", StyleType::BLUE}, - {"Mc", StyleType::RED}, - {"V0Data", StyleType::GREEN}, - {"CascData", StyleType::GREEN}}; - -template <typename T> -Style getStyleFor() -{ - auto label = MetadataTrait<T>::metadata::tableLabel(); - auto entry = std::find_if(tableStyles.begin(), tableStyles.end(), [&](auto&& x) { if (std::string(label).find(x.first) != std::string::npos) { return true; - -}return false; }); - if (entry != tableStyles.end()) { - auto value = *entry; - return styles[value.second]; - } - return styles[StyleType::DEFAULT]; -} - -void inline nodeEmpty() -{ - fmt::printf( - R"(node[shape=none,height=0,width=0,label=""])"); -} - -void inline nodeNormal() -{ - fmt::printf( - R"(node[shape=plain,style=filled,fillcolor=gray95])"); -} - -void inline graphHeader(char const* type, char const* name) -{ - fmt::printf(R"(%s %s { -edge[dir=back, arrowtail=empty] -)", - type, name); - nodeNormal(); -} - -void inline graphFooter() -{ - fmt::printf("}\n"); -} - -template <typename T> -void displayEntity(); - -template <typename... Ts> -void displayOriginals(pack<Ts...>) -{ - graphHeader("subgraph", fmt::format("cluster_{}", count++).c_str()); - fmt::printf("label = %s;\n", MetadataTrait<pack_element_t<1, pack<Ts...>>>::metadata::tableLabel()); - (..., displayEntity<Ts>()); - graphFooter(); -} - -template <typename C> -void printColumn(char const* fg, char const* bg) -{ - if constexpr (!is_index_column_v<C>) { - fmt::printf("<TR><TD color='%s' bgcolor='%s'>%s</TD></TR>", fg, bg, C::columnLabel()); - } -} - -template <typename C> -void printIndexColumn(char const* fg, char const* bg) -{ - if constexpr (is_index_column_v<C>) { - fmt::printf("<TR><TD color='%s' bgcolor='%s'>%s</TD></TR>", fg, bg, C::columnLabel()); - } -} - -template <typename... C> -void displayColumns(pack<C...>, const char* fg, const char* bg) -{ - (printColumn<C>(fg, bg), ...); - fmt::printf("%s", "\n"); -} - -template <typename... C> -void displayIndexColumns(pack<C...>, char const* fg, char const* bg) -{ - (printIndexColumn<C>(fg, bg), ...); - fmt::printf("%s", "\n"); -} - -template <typename C, typename T> -void printIndex() -{ - if constexpr (!is_type_with_originals_v<typename C::binding_t>) { - auto a = MetadataTrait<typename C::binding_t>::metadata::tableLabel(); - auto b = MetadataTrait<T>::metadata::tableLabel(); - fmt::printf("%s -> %s []\n", a, b); - } else { - using main_original = pack_element_t<1, typename C::binding_t::originals>; - auto a = MetadataTrait<main_original>::metadata::tableLabel(); - auto b = MetadataTrait<T>::metadata::tableLabel(); - fmt::printf("%s -> %s []\n", a, b); - } -} - -template <typename T, typename... C> -void dumpIndex(pack<C...>) -{ - (printIndex<C, T>(), ...); - fmt::printf("%s", "\n"); -} - -template <typename T> -void displayTable() -{ - auto style = getStyleFor<T>(); - auto label = MetadataTrait<T>::metadata::tableLabel(); - fmt::printf(R"(%s[color="%s" cellpadding="0" fillcolor="%s" fontcolor="%s" label = < -<TABLE cellpadding='2' cellspacing='0' cellborder='0' ><TH cellpadding='0' bgcolor="black"><TD bgcolor="%s"><font color="%s">%s</font></TD></TH>)", - label, style.color, style.background, style.fontcolor, style.headerbgcolor, style.headerfontcolor, label); - if (pack_size(typename T::iterator::persistent_columns_t{}) - - pack_size(typename T::iterator::external_index_columns_t{}) > - 0) { - displayColumns(typename T::iterator::persistent_columns_t{}, style.color, style.background); - fmt::printf("%s", "HR"); - } - if (pack_size(typename T::iterator::dynamic_columns_t{})) { - displayColumns(typename T::iterator::dynamic_columns_t{}, style.methodcolor, style.methodbgcolor); - fmt::printf("%s", "HR"); - } - displayIndexColumns(typename T::iterator::external_index_columns_t{}, style.indexcolor, style.indexbgcolor); - fmt::printf("%s", "</TABLE>\n>]\n"); - dumpIndex<T>(typename T::iterator::external_index_columns_t{}); -} - -template <typename T> -void displayEntity() -{ - if constexpr (is_soa_join_t<T>::value) { - displayOriginals(typename T::originals{}); - } else { - displayTable<T>(); - } -} - -template <typename... T> -void displayEntities() -{ - graphHeader("subgraph", fmt::format("cluster_{}", count++).c_str()); - (..., displayEntity<T>()); - graphFooter(); -} - -int main(int, char**) -{ - graphHeader("digraph", "hierarchy"); - graphSize(); - fmt::printf(R"(compound = true; -)"); - - displayEntity<BCs>(); - /// rank trick to avoid BCs moving - nodeEmpty(); - fmt::printf(R"({rank = same; BCs -> root[style=invis];};)"); - nodeNormal(); - - displayEntity<Zdcs>(); - displayEntity<FT0s>(); - displayEntity<FV0As>(); - displayEntity<FDDs>(); - - displayEntities<Collisions, Cents, Mults, Timestamps>(); - displayEntity<McCollisions>(); - displayEntity<McCollisionLabels>(); - - displayEntity<Calos>(); - displayEntity<CaloTriggers>(); - displayEntity<McCaloLabels>(); - - displayEntity<FV0Cs>(); - - displayEntities<Tracks, TracksCov, TracksExtra, TracksExtended, TrackSelection, pidRespTOF, pidRespTPC>(); - displayEntity<UnassignedTracks>(); - - displayEntity<McParticles>(); - displayEntity<McTrackLabels>(); - - displayEntity<HfTrackIndexProng2>(); - displayEntity<HfTrackIndexProng3>(); - - displayEntity<Jets>(); - displayEntity<JetConstituents>(); - - displayEntities<V0s, V0DataFull>(); - displayEntity<V0FinderData>(); - - displayEntities<Cascades, CascDataFull>(); - - displayEntity<Muons>(); - displayEntity<MuonClusters>(); - - graphFooter(); - return 0; -} diff --git a/Analysis/DataModel/src/handleParamTOFReso.cxx b/Analysis/DataModel/src/handleParamTOFReso.cxx deleted file mode 100644 index e7ca0b6b7dcc2..0000000000000 --- a/Analysis/DataModel/src/handleParamTOFReso.cxx +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file handleParamTOFBetheBloch.cxx -/// \author Nicolo' Jacazio -/// \since 2020-06-22 -/// \brief A simple tool to produce Bethe Bloch parametrization objects for the TOF PID Response -/// - -#include "CCDB/CcdbApi.h" -#include <boost/program_options.hpp> -#include <FairLogger.h> -#include "TFile.h" -#include "PID/TOFReso.h" - -using namespace o2::pid::tof; -namespace bpo = boost::program_options; - -bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) -{ - options.add_options()( - "url,u", bpo::value<std::string>()->default_value("http://ccdb-test.cern.ch:8080"), "URL of the CCDB database")( - "start,s", bpo::value<long>()->default_value(0), "Start timestamp of object validity")( - "stop,S", bpo::value<long>()->default_value(4108971600000), "Stop timestamp of object validity")( - "delete_previous,d", bpo::value<int>()->default_value(0), "Flag to delete previous versions of converter objects in the CCDB before uploading the new one so as to avoid proliferation on CCDB")( - "file,f", bpo::value<std::string>()->default_value(""), "Option to save parametrization to file instead of uploading to ccdb")( - "mode,m", bpo::value<unsigned int>()->default_value(0), "Working mode: 0 push 1 pull and test")( - "verbose,v", bpo::value<int>()->default_value(0), "Verbose level 0, 1")( - "help,h", "Produce help message."); - try { - bpo::store(parse_command_line(argc, argv, options), vm); - - // help - if (vm.count("help")) { - LOG(INFO) << options; - return false; - } - - bpo::notify(vm); - } catch (const bpo::error& e) { - LOG(ERROR) << e.what() << "\n"; - LOG(ERROR) << "Error parsing command line arguments; Available options:"; - LOG(ERROR) << options; - return false; - } - return true; -} - -int main(int argc, char* argv[]) -{ - bpo::options_description options("Allowed options"); - bpo::variables_map vm; - if (!initOptionsAndParse(options, argc, argv, vm)) { - return 1; - } - - const unsigned int mode = vm["mode"].as<unsigned int>(); - const std::string path = "Analysis/PID/TOF"; - std::map<std::string, std::string> metadata; - std::map<std::string, std::string>* headers; - o2::ccdb::CcdbApi api; - const std::string url = vm["url"].as<std::string>(); - api.init(url); - if (!api.isHostReachable()) { - LOG(WARNING) << "CCDB host " << url << " is not reacheable, cannot go forward"; - return 1; - } - if (mode == 0) { // Push mode - const std::vector<float> resoparams = {0.008, 0.008, 0.002, 40.0, 60.f}; - TOFReso reso; - reso.SetParameters(resoparams); - const std::string fname = vm["file"].as<std::string>(); - if (!fname.empty()) { // Saving it to file - TFile f(fname.data(), "RECREATE"); - reso.Write(); - f.ls(); - f.Close(); - } else { // Saving it to CCDB - - long start = vm["start"].as<long>(); - long stop = vm["stop"].as<long>(); - - if (vm["delete_previous"].as<int>()) { - api.truncate(path); - } - api.storeAsTFileAny(&reso, path + "/TOFReso", metadata, start, stop); - } - } else { // Pull and test mode - const float x[2] = {1, 1}; - TOFReso* reso = api.retrieveFromTFileAny<TOFReso>(path + "/TOFReso", metadata, -1, headers); - reso->PrintParametrization(); - LOG(INFO) << "TOFReso " << reso->operator()(x); - } - - return 0; -} diff --git a/Analysis/DataModel/src/handleParamTPCBetheBloch.cxx b/Analysis/DataModel/src/handleParamTPCBetheBloch.cxx deleted file mode 100644 index 3e542a744f116..0000000000000 --- a/Analysis/DataModel/src/handleParamTPCBetheBloch.cxx +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file handleParamTPCBetheBloch.cxx -/// \author Nicolo' Jacazio -/// \since 2020-06-22 -/// \brief A simple tool to produce Bethe Bloch parametrization objects for the TPC PID Response -/// - -#include "CCDB/CcdbApi.h" -#include <boost/program_options.hpp> -#include <FairLogger.h> -#include "TFile.h" -#include "PID/BetheBloch.h" -#include "PID/TPCReso.h" - -using namespace o2::pid::tpc; -namespace bpo = boost::program_options; - -bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) -{ - options.add_options()( - "url,u", bpo::value<std::string>()->default_value("http://ccdb-test.cern.ch:8080"), "URL of the CCDB database")( - "start,s", bpo::value<long>()->default_value(0), "Start timestamp of object validity")( - "stop,S", bpo::value<long>()->default_value(4108971600000), "Stop timestamp of object validity")( - "delete-previous,d", bpo::value<int>()->default_value(0), "Flag to delete previous versions of converter objects in the CCDB before uploading the new one so as to avoid proliferation on CCDB")( - "save-to-file,f", bpo::value<std::string>()->default_value(""), "Option to save parametrization to file instead of uploading to ccdb")( - "read-from-file", bpo::value<std::string>()->default_value(""), "Option to get parametrization from a file")( - "mode,m", bpo::value<unsigned int>()->default_value(0), "Working mode: 0 push 1 pull and test")( - "verbose,v", bpo::value<int>()->default_value(0), "Verbose level 0, 1")( - "help,h", "Produce help message."); - try { - bpo::store(parse_command_line(argc, argv, options), vm); - - // help - if (vm.count("help")) { - LOG(INFO) << options; - return false; - } - - bpo::notify(vm); - } catch (const bpo::error& e) { - LOG(ERROR) << e.what() << "\n"; - LOG(ERROR) << "Error parsing command line arguments; Available options:"; - LOG(ERROR) << options; - return false; - } - return true; -} - -int main(int argc, char* argv[]) -{ - bpo::options_description options("Allowed options"); - bpo::variables_map vm; - if (!initOptionsAndParse(options, argc, argv, vm)) { - return 1; - } - - const unsigned int mode = vm["mode"].as<unsigned int>(); - const std::string path = "Analysis/PID/TPC"; - std::map<std::string, std::string> metadata; - std::map<std::string, std::string>* headers; - o2::ccdb::CcdbApi api; - const std::string url = vm["url"].as<std::string>(); - api.init(url); - if (!api.isHostReachable()) { - LOG(WARNING) << "CCDB host " << url << " is not reacheable, cannot go forward"; - return 1; - } - if (mode == 0) { // Push mode - BetheBloch* bb = nullptr; - TPCReso* reso = nullptr; - const std::string input_file_name = vm["read-from-file"].as<std::string>(); - - if (!input_file_name.empty()) { - TFile f(input_file_name.data(), "READ"); - if (!f.IsOpen()) { - LOG(WARNING) << "Input file " << input_file_name << " is not reacheable, cannot get param from file"; - } - f.GetObject("BetheBloch", bb); - f.GetObject("TPCReso", reso); - f.Close(); - } - if (!bb) { - bb = new BetheBloch(); - const std::vector<float> bbparams = {0.0320981, 19.9768, 2.52666e-16, 2.72123, 6.08092, 50.f, 2.3}; - bb->SetParameters(bbparams); - } - if (!reso) { - reso = new TPCReso(); - const std::vector<float> resoparams = {0.07, 0.0}; - reso->SetParameters(resoparams); - } - const std::string fname = vm["save-to-file"].as<std::string>(); - if (!fname.empty()) { // Saving it to file - TFile f(fname.data(), "RECREATE"); - bb->Write(); - reso->Write(); - f.ls(); - f.Close(); - } else { // Saving it to CCDB - - long start = vm["start"].as<long>(); - long stop = vm["stop"].as<long>(); - - if (vm["delete-previous"].as<int>()) { - api.truncate(path); - } - api.storeAsTFileAny(bb, path + "/BetheBloch", metadata, start, stop); - api.storeAsTFileAny(reso, path + "/TPCReso", metadata, start, stop); - } - } else { // Pull and test mode - const float x[2] = {1, 1}; - BetheBloch* bb = api.retrieveFromTFileAny<BetheBloch>(path + "/BetheBloch", metadata, -1, headers); - bb->PrintParametrization(); - LOG(INFO) << "BetheBloch " << bb->operator()(x); - TPCReso* reso = api.retrieveFromTFileAny<TPCReso>(path + "/TPCReso", metadata, -1, headers); - reso->PrintParametrization(); - LOG(INFO) << "TPCReso " << reso->operator()(x); - } - - return 0; -} diff --git a/Analysis/Scripts/update_ccdb.py b/Analysis/Scripts/update_ccdb.py deleted file mode 100755 index a3cd525175908..0000000000000 --- a/Analysis/Scripts/update_ccdb.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization -# or submit itself to any jurisdiction. - -""" -Script to update the CCDB with timestamp non-overlapping objects. -If an object is found in the range specified, the object is split into two. -If the requested range was overlapping three objects are uploaded on CCDB: -1) latest object with requested timestamp validity -2) old object with validity [old_lower_validity-requested_lower_bound] -3) old object with validity [requested_upper_bound, old_upper_validity] -Author: Nicolo' Jacazio on 2020-06-22 -TODO add support for 3 files update -""" - -import subprocess -from datetime import datetime -import matplotlib.pyplot as plt -import argparse - - -def convert_timestamp(ts): - """ - Converts the timestamp in milliseconds in human readable format - """ - return datetime.utcfromtimestamp(ts/1000).strftime('%Y-%m-%d %H:%M:%S') - - -def get_ccdb_obj(path, timestamp, dest="/tmp/", verbose=0): - """ - Gets the ccdb object from 'path' and 'timestamp' and downloads it into 'dest' - """ - if verbose: - print("Getting obj", path, "with timestamp", - timestamp, convert_timestamp(timestamp)) - cmd = f"o2-ccdb-downloadccdbfile --path {path} --dest {dest} --timestamp {timestamp}" - subprocess.run(cmd.split()) - - -def get_ccdb_obj_validity(path, dest="/tmp/", verbose=0): - """ - Gets the timestamp validity for an object downloaded from CCDB. - Returns a list with the initial and end timestamps. - """ - cmd = f"o2-ccdb-inspectccdbfile {dest}{path}/snapshot.root" - process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - output = output.decode("utf-8").split("\n") - error = error.decode("utf-8").split("\n") if error is not None else error - if verbose: - print("out:") - print(*output, "\n") - print("err:") - print(error) - result = list(filter(lambda x: x.startswith('Valid-'), output)) - ValidFrom = result[0].split() - ValidUntil = result[1].split() - return [int(ValidFrom[-1]), int(ValidUntil[-1])] - - -def upload_ccdb_obj(path, timestamp_from, timestamp_until, dest="/tmp/", meta=""): - """ - Uploads a new object to CCDB in the 'path' using the validity timestamp specified - """ - print("Uploading obj", path, "with timestamp", [timestamp_from, timestamp_until], - convert_timestamp(timestamp_from), convert_timestamp(timestamp_until)) - key = path.split("/")[-1] - cmd = f"o2-ccdb-upload -f {dest}{path}/snapshot.root " - cmd += f"--key {key} --path {path} " - cmd += f"--starttimestamp {timestamp_from} --endtimestamp {timestamp_until} --meta \"{meta}\"" - subprocess.run(cmd.split()) - - -def main(path, timestamp_from, timestamp_until, verbose=0, show=False): - """ - Used to upload a new object to CCDB in 'path' valid from 'timestamp_from' to 'timestamp_until' - Gets the object from CCDB specified in 'path' and for 'timestamp_from-1' - Gets the object from CCDB specified in 'path' and for 'timestamp_until+1' - If required plots the situation before and after the update - """ - get_ccdb_obj(path, timestamp_from-1) - val_before = get_ccdb_obj_validity(path, verbose=verbose) - get_ccdb_obj(path, timestamp_until+1) - val_after = get_ccdb_obj_validity(path, verbose=verbose) - overlap_before = val_before[1] > timestamp_from - overlap_after = val_after[0] < timestamp_until - if verbose: - if overlap_before: - print("Previous objects overalps") - if overlap_after: - print("Next objects overalps") - trimmed_before = val_before if not overlap_before else [ - val_before[0], timestamp_from - 1] - trimmed_after = val_after if not overlap_after else [ - timestamp_until+1, val_after[1]] - if show: - fig, ax = plt.subplots() - fig - - def bef_af(v, y): - return [v[0] - 1] + v + [v[1] + 1], [0, y, y, 0] - if True: - ax.plot(*bef_af(val_before, 0.95), label='before') - ax.plot(*bef_af(val_after, 1.05), label='after') - if False: - ax.plot(*bef_af(trimmed_before, 0.9), label='trimmed before') - ax.plot(*bef_af(trimmed_after, 1.1), label='trimmed after') - ax.plot(*bef_af([timestamp_from, timestamp_until], 1), label='object') - xlim = 10000000 - plt.xlim([timestamp_from-xlim, timestamp_until+xlim]) - plt.ylim(0, 2) - plt.xlabel('Timestamp') - plt.ylabel('Validity') - plt.legend() - plt.show() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Uploads timestamp non overlapping objects to CCDB." - "Basic example: `./update_ccdb.py qc/TOF/TOFTaskCompressed/hDiagnostic 1588956517161 1588986517161 --show --verbose`") - parser.add_argument('path', metavar='path_to_object', type=str, - help='Path of the object in the CCDB repository') - parser.add_argument('timestamp_from', metavar='from_timestamp', type=int, - help='Timestamp of start for the new object to use') - parser.add_argument('timestamp_until', metavar='until_timestamp', type=int, - help='Timestamp of stop for the new object to use') - parser.add_argument('--verbose', '-v', action='count', default=0) - parser.add_argument('--show', '-s', action='count', default=0) - - args = parser.parse_args() - main(path=args.path, - timestamp_from=args.timestamp_from, - timestamp_until=args.timestamp_until, - verbose=args.verbose, - show=args.show) diff --git a/Analysis/Tasks/ALICE3/CMakeLists.txt b/Analysis/Tasks/ALICE3/CMakeLists.txt deleted file mode 100644 index 7734d35e2289b..0000000000000 --- a/Analysis/Tasks/ALICE3/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_dpl_workflow(alice3-trackselection - SOURCES alice3-trackselection.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - - diff --git a/Analysis/Tasks/ALICE3/alice3-trackselection.cxx b/Analysis/Tasks/ALICE3/alice3-trackselection.cxx deleted file mode 100644 index 53928e1e4523f..0000000000000 --- a/Analysis/Tasks/ALICE3/alice3-trackselection.cxx +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Task performing basic track selection. -// - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/trackUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -//**************************************************************************************** -/** - * Produce track filter table. - */ -//**************************************************************************************** -struct TrackSelectionTask { - Produces<aod::TrackSelection> filterTable; - - void init(InitContext&) - { - } - - void process(soa::Join<aod::FullTracks, aod::TracksExtended> const& tracks) - { - for (auto& track : tracks) { - filterTable(kTRUE, - kTRUE); - } - } -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask<TrackSelectionTask>("track-selection")}; - return workflow; -} diff --git a/Analysis/Tasks/CMakeLists.txt b/Analysis/Tasks/CMakeLists.txt deleted file mode 100644 index 44ce185982209..0000000000000 --- a/Analysis/Tasks/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -add_subdirectory(PWGCF) -add_subdirectory(PWGDQ) -add_subdirectory(PWGHF) -add_subdirectory(PWGJE) -add_subdirectory(PWGLF) -add_subdirectory(PWGUD) -add_subdirectory(ALICE3) - - -o2_add_dpl_workflow(trackextension - SOURCES trackextension.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(trackselection - SOURCES trackselection.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(trackqa - SOURCES trackqa.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(qatask - SOURCES qaTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(pid-tof - SOURCES pidTOF.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(pid-tpc - SOURCES pidTPC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(validation - SOURCES validation.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(event-selection - SOURCES eventSelection.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase O2::CCDB - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(event-selection-qa - SOURCES eventSelectionQa.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(multiplicity-table - SOURCES multiplicityTable.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(multiplicity-qa - SOURCES multiplicityQa.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(centrality-table - SOURCES centralityTable.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase O2::CCDB - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(centrality-qa - SOURCES centralityQa.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(timestamp - SOURCES timestamp.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::DetectorsRaw O2::AnalysisCore O2::CommonDataFormat O2::CCDB - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(weak-decay-indices - SOURCES weakDecayIndices.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel - COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.cxx b/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.cxx deleted file mode 100644 index e0f9ff79899eb..0000000000000 --- a/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.cxx +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "AnalysisConfigurableCuts.h" - -using namespace o2::analysis; - -ClassImp(SimpleInclusiveCut); - -SimpleInclusiveCut::SimpleInclusiveCut() : TNamed(), - mX(0), - mY(0.0) -{ - // - // default constructor - // -} - -SimpleInclusiveCut::SimpleInclusiveCut(const char* name, int _x, float _y) : TNamed(name, name), - mX(_x), - mY(_y) -{ - // - // explicit constructor - // -} - -SimpleInclusiveCut& SimpleInclusiveCut::operator=(const SimpleInclusiveCut& sic) -{ - // - // assignment operator - // - if (this != &sic) { - TNamed::operator=(sic); - mX = sic.mX; - mY = sic.mY; - } - return (*this); -} diff --git a/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.h b/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.h deleted file mode 100644 index 9c916039f9542..0000000000000 --- a/Analysis/Tasks/PWGCF/AnalysisConfigurableCuts.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef ANALYSIS_CONFIGURABLE_CUTS_CLASSES_H -#define ANALYSIS_CONFIGURABLE_CUTS_CLASSES_H - -#include <Rtypes.h> -#include <TObject.h> -#include <TNamed.h> -#include <TMath.h> - -namespace o2 -{ -namespace analysis -{ -/// \class EventSelectionCuts -/// \brief Class which implements configurable event selection cuts -/// -class EventSelectionCuts -{ - public: - int mOfflinetrigger = 1; ///< offline trigger, default MB = 1 - std::string mCentmultestmator = "V0M"; ///< centrality / multiplicity estimation, default V0M - int mRemovepileupcode = 1; ///< Procedure for pile-up removal, default V0M vs TPCout tracks = 1 - std::string mRemovepileupfn = "-2500+5.0*x"; ///< function for pile-up removal, procedure dependent, defaul V0M vs TPCout tracks for LHC15o HIR - - private: - ClassDefNV(EventSelectionCuts, 1); -}; - -/// \class DptDptBinningCuts -/// \brief Class which implements configurable acceptance cuts -/// -class DptDptBinningCuts -{ - public: - int mZVtxbins = 28; ///< the number of z_vtx bins default 28 - float mZVtxmin = -7.0; ///< the minimum z_vtx value, default -7.0 cm - float mZVtxmax = 7.0; ///< the maximum z_vtx value, default 7.0 cm - int mPTbins = 18; ///< the number of pT bins, default 18 - float mPTmin = 0.2; ///< the minimum pT value, default 0.2 GeV - float mPTmax = 2.0; ///< the maximum pT value, default 2.0 GeV - int mEtabins = 16; ///< the number of eta bins default 16 - float mEtamin = -0.8; ///< the minimum eta value, default -0.8 - float mEtamax = 0.8; ///< the maximum eta value, default 0.8 - int mPhibins = 72; ///< the number of phi bins, default 72 - float mPhibinshift = 0.5; ///< the shift in the azimuthal origen, defoult 0.5, i.e half a bin - - private: - ClassDefNV(DptDptBinningCuts, 1); -}; - -class SimpleInclusiveCut : public TNamed -{ - public: - int mX = 1; - float mY = 2.f; - SimpleInclusiveCut(); - SimpleInclusiveCut(const char*, int, float); - SimpleInclusiveCut(const SimpleInclusiveCut&) = default; - ~SimpleInclusiveCut() override = default; - - SimpleInclusiveCut& operator=(const SimpleInclusiveCut&); - - private: - ClassDef(SimpleInclusiveCut, 1); -}; - -} // namespace analysis -} // namespace o2 -#endif // ANALYSIS_CONFIGURABLE_CUTS_CLASSES_H diff --git a/Analysis/Tasks/PWGCF/CMakeLists.txt b/Analysis/Tasks/PWGCF/CMakeLists.txt deleted file mode 100644 index e7eb33cb131ab..0000000000000 --- a/Analysis/Tasks/PWGCF/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(PWGCFCore - SOURCES AnalysisConfigurableCuts.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel) - -o2_target_root_dictionary(PWGCFCore - HEADERS AnalysisConfigurableCuts.h - LINKDEF PWGCFCoreLinkDef.h) - -o2_add_dpl_workflow(dptdptcorrelations - SOURCES dptdptcorrelations.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel O2::PWGCFCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(correlations - SOURCES correlations.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(correlations-mixed - SOURCES correlationsMixed.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(filter-cf - SOURCES filterCF.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(correlations-filtered - SOURCES correlationsFiltered.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore - COMPONENT_NAME Analysis) - diff --git a/Analysis/Tasks/PWGCF/PWGCFCoreLinkDef.h b/Analysis/Tasks/PWGCF/PWGCFCoreLinkDef.h deleted file mode 100644 index 9a46f9dc8e5da..0000000000000 --- a/Analysis/Tasks/PWGCF/PWGCFCoreLinkDef.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::analysis::EventSelectionCuts + ; -#pragma link C++ class o2::analysis::DptDptBinningCuts + ; -#pragma link C++ class o2::analysis::SimpleInclusiveCut + ; diff --git a/Analysis/Tasks/PWGCF/correlations.cxx b/Analysis/Tasks/PWGCF/correlations.cxx deleted file mode 100644 index 21ba374fe4870..0000000000000 --- a/Analysis/Tasks/PWGCF/correlations.cxx +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include <CCDB/BasicCCDBManager.h> -#include "Framework/StepTHn.h" -#include "Framework/HistogramRegistry.h" - -#include "Analysis/EventSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/Centrality.h" -#include "Analysis/CorrelationContainer.h" -#include "Analysis/PairCuts.h" - -#include <TH1F.h> -#include <cmath> -#include <TDirectory.h> -#include <THn.h> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP}; - -struct CorrelationTask { - - // Configuration - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - - O2_DEFINE_CONFIGURABLE(cfgPtOrder, int, 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)"); - O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgPairCharge, int, 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"); - - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCut, float, -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"); - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCutMinRadius, float, 0.8f, "Two track cut: radius in m from which two track cuts are applied"); - - O2_DEFINE_CONFIGURABLE(cfgPairCutPhoton, float, -1, "Pair cut on photons: -1 = off; >0 otherwise distance value (suggested: 0.004)") - O2_DEFINE_CONFIGURABLE(cfgPairCutK0, float, -1, "Pair cut on K0s: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutLambda, float, -1, "Pair cut on Lambda: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutPhi, float, -1, "Pair cut on Phi: -1 = off; >0 otherwise distance value") - O2_DEFINE_CONFIGURABLE(cfgPairCutRho, float, -1, "Pair cut on Rho: -1 = off; >0 otherwise distance value") - - O2_DEFINE_CONFIGURABLE(cfgEfficiencyTrigger, std::string, "", "CCDB path to efficiency object for trigger particles") - O2_DEFINE_CONFIGURABLE(cfgEfficiencyAssociated, std::string, "", "CCDB path to efficiency object for associated particles") - - // Filters and input definitions - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt) && ((aod::track::isGlobalTrack == true) || (aod::track::isGlobalTrackSDD == true)); - using myTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection>>; - - // Output definitions - OutputObj<CorrelationContainer> same{"sameEvent"}; - OutputObj<CorrelationContainer> mixed{"mixedEvent"}; - - struct Config { - bool mPairCuts = false; - THn* mEfficiencyTrigger = nullptr; - THn* mEfficiencyAssociated = nullptr; - } cfg; - - HistogramRegistry registry{"registry", { - {"yields", "centrality vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}}, // - {"etaphi", "centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"}}}} // - }}; - - PairCuts mPairCuts; - - Service<o2::ccdb::BasicCCDBManager> ccdb; - - void init(o2::framework::InitContext&) - { - // --- CONFIGURATION --- - const char* binning = - "vertex: 7 | -7, 7\n" - "delta_phi: 72 | -1.570796, 4.712389\n" - "delta_eta: 40 | -2.0, 2.0\n" - "p_t_assoc: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0\n" - "p_t_trigger: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0\n" - "multiplicity: 0, 5, 10, 20, 30, 40, 50, 100.1\n" - "eta: 20 | -1.0, 1.0\n" - "p_t_leading: 100 | 0.0, 50.0\n" - "p_t_leading_course: 0.5, 1.0, 2.0, 3.0, 4.0, 6.0, 8.0\n" - "p_t_eff: 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0\n" - "vertex_eff: 10 | -10, 10\n"; - - mPairCuts.SetHistogramRegistry(®istry); - - if (cfgPairCutPhoton > 0 || cfgPairCutK0 > 0 || cfgPairCutLambda > 0 || cfgPairCutPhi > 0 || cfgPairCutRho > 0) { - mPairCuts.SetPairCut(PairCuts::Photon, cfgPairCutPhoton); - mPairCuts.SetPairCut(PairCuts::K0, cfgPairCutK0); - mPairCuts.SetPairCut(PairCuts::Lambda, cfgPairCutLambda); - mPairCuts.SetPairCut(PairCuts::Phi, cfgPairCutPhi); - mPairCuts.SetPairCut(PairCuts::Rho, cfgPairCutRho); - cfg.mPairCuts = true; - } - - if (cfgTwoTrackCut > 0) { - mPairCuts.SetTwoTrackCuts(cfgTwoTrackCut, cfgTwoTrackCutMinRadius); - } - - // --- OBJECT INIT --- - same.setObject(new CorrelationContainer("sameEvent", "sameEvent", "NumberDensityPhiCentralityVtx", binning)); - mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", "NumberDensityPhiCentralityVtx", binning)); - - // o2-ccdb-upload -p Users/jgrosseo/correlations/LHC15o -f /tmp/correction_2011_global.root -k correction - - ccdb->setURL("http://ccdb-test.cern.ch:8080"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - - long now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); - ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time - - if (cfgEfficiencyTrigger.value.empty() == false) { - cfg.mEfficiencyTrigger = ccdb->getForTimeStamp<THnT<float>>(cfgEfficiencyTrigger, now); - LOGF(info, "Loaded efficiency histogram for trigger particles from %s (%p)", cfgEfficiencyTrigger.value.c_str(), (void*)cfg.mEfficiencyTrigger); - } - if (cfgEfficiencyAssociated.value.empty() == false) { - cfg.mEfficiencyAssociated = ccdb->getForTimeStamp<THnT<float>>(cfgEfficiencyAssociated, now); - LOGF(info, "Loaded efficiency histogram for associated particles from %s (%p)", cfgEfficiencyAssociated.value.c_str(), (void*)cfg.mEfficiencyAssociated); - } - } - - // Version with explicit nested loop - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::Cents>>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) - { - auto bc = collision.bc_as<aod::BCsWithTimestamps>(); - if (cfgEfficiencyTrigger.value.empty() == false) { - cfg.mEfficiencyTrigger = ccdb->getForTimeStamp<THnT<float>>(cfgEfficiencyTrigger, bc.timestamp()); - LOGF(info, "Loaded efficiency histogram for trigger particles from %s (%p)", cfgEfficiencyTrigger.value.c_str(), (void*)cfg.mEfficiencyTrigger); - } - if (cfgEfficiencyAssociated.value.empty() == false) { - cfg.mEfficiencyAssociated = ccdb->getForTimeStamp<THnT<float>>(cfgEfficiencyAssociated, bc.timestamp()); - LOGF(info, "Loaded efficiency histogram for associated particles from %s (%p)", cfgEfficiencyAssociated.value.c_str(), (void*)cfg.mEfficiencyAssociated); - } - - LOGF(info, "Tracks for collision: %d | Vertex: %.1f | INT7: %d | V0M: %.1f", tracks.size(), collision.posZ(), collision.sel7(), collision.centV0M()); - - const auto centrality = collision.centV0M(); - - same->fillEvent(centrality, CorrelationContainer::kCFStepAll); - - if (!collision.sel7()) { - return; - } - - same->fillEvent(centrality, CorrelationContainer::kCFStepTriggered); - - // vertex already checked as filter - same->fillEvent(centrality, CorrelationContainer::kCFStepVertex); - - same->fillEvent(centrality, CorrelationContainer::kCFStepReconstructed); - - int bSign = 1; // TODO magnetic field from CCDB - - // Cache efficiency for particles (too many FindBin lookups) - float* efficiencyAssociated = nullptr; - if (cfg.mEfficiencyAssociated) { - efficiencyAssociated = new float[tracks.size()]; - int i = 0; - for (auto& track1 : tracks) { - efficiencyAssociated[i++] = getEfficiency(cfg.mEfficiencyAssociated, track1.eta(), track1.pt(), centrality, collision.posZ()); - } - } - - for (auto& track1 : tracks) { - - // LOGF(info, "Track %f | %f | %f %d %d", track1.eta(), track1.phi(), track1.pt(), track1.isGlobalTrack(), track1.isGlobalTrackSDD()); - - registry.fill("yields", centrality, track1.pt(), track1.eta()); - registry.fill("etaphi", centrality, track1.eta(), track1.phi()); - - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.charge() < 0) { - continue; - } - - float triggerWeight = 1.0; - if (cfg.mEfficiencyTrigger) { - triggerWeight = getEfficiency(cfg.mEfficiencyTrigger, track1.eta(), track1.pt(), centrality, collision.posZ()); - } - - same->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), centrality, collision.posZ(), triggerWeight); - //mixed->getTriggerHist()->Fill(eventValues, CorrelationContainer::kCFStepReconstructed); - - int i = -1; - for (auto& track2 : tracks) { - i++; // HACK - if (track1 == track2) { - continue; - } - - if (cfgPtOrder != 0 && track2.pt() >= track1.pt()) { - continue; - } - - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.charge() < 0) { - continue; - } - if (cfgPairCharge != 0 && cfgPairCharge * track1.charge() * track2.charge() < 0) { - continue; - } - - if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { - continue; - } - - if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, bSign)) { - continue; - } - - float associatedWeight = 1.0; - if (cfg.mEfficiencyAssociated) { - associatedWeight = efficiencyAssociated[i]; - } - - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5 * TMath::Pi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi < -0.5 * TMath::Pi()) { - deltaPhi += TMath::TwoPi(); - } - - same->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - track1.eta() - track2.eta(), track2.pt(), track1.pt(), centrality, deltaPhi, collision.posZ(), - triggerWeight * associatedWeight); - //mixed->getPairHist()->Fill(values, CorrelationContainer::kCFStepReconstructed); - } - } - - delete[] efficiencyAssociated; - } - - // Version with combinations - void process2(soa::Join<aod::Collisions, aod::Cents>::iterator const& collision, soa::Filtered<aod::Tracks> const& tracks) - { - LOGF(info, "Tracks for collision (Combination run): %d", tracks.size()); - - const auto centrality = collision.centV0M(); - - int bSign = 1; // TODO magnetic field from CCDB - - for (auto track1 = tracks.begin(); track1 != tracks.end(); ++track1) { - - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.charge() < 0) { - continue; - } - - // LOGF(info, "TRACK %f %f | %f %f | %f %f", track1.eta(), track1.eta(), track1.phi(), track1.phi2(), track1.pt(), track1.pt()); - - same->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), centrality, collision.posZ()); - //mixed->getTriggerHist()->Fill(eventValues, CorrelationContainer::kCFStepReconstructed); - } - - for (auto& [track1, track2] : combinations(tracks, tracks)) { - //LOGF(info, "Combination %d %d", track1.index(), track2.index()); - - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.charge() < 0) { - continue; - } - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.charge() < 0) { - continue; - } - if (cfgPairCharge != 0 && cfgPairCharge * track1.charge() * track2.charge() < 0) { - continue; - } - - if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { - continue; - } - - if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, bSign)) { - continue; - } - - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5 * TMath::Pi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi < -0.5 * TMath::Pi()) { - deltaPhi += TMath::TwoPi(); - } - - same->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - track1.eta() - track2.eta(), track2.pt(), track1.pt(), centrality, deltaPhi, collision.posZ()); - //mixed->getPairHist()->Fill(values, CorrelationContainer::kCFStepReconstructed); - } - } - - double getEfficiency(THn* eff, float eta, float pt, float centrality, float posZ) - { - int effVars[4]; - effVars[0] = eff->GetAxis(0)->FindBin(eta); - effVars[1] = eff->GetAxis(1)->FindBin(pt); - effVars[2] = eff->GetAxis(2)->FindBin(centrality); - effVars[3] = eff->GetAxis(3)->FindBin(posZ); - return eff->GetBinContent(effVars); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<CorrelationTask>("correlation-task")}; -} diff --git a/Analysis/Tasks/PWGCF/correlationsFiltered.cxx b/Analysis/Tasks/PWGCF/correlationsFiltered.cxx deleted file mode 100644 index 6b901f88915e5..0000000000000 --- a/Analysis/Tasks/PWGCF/correlationsFiltered.cxx +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/StepTHn.h" - -#include "Analysis/EventSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/Centrality.h" -#include "Analysis/CorrelationContainer.h" -#include "Analysis/CFDerived.h" - -#include <TH1F.h> -#include <cmath> -#include <TDirectory.h> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP}; - -struct CorrelationTask { - - // Configuration - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - - O2_DEFINE_CONFIGURABLE(cfgPtOrder, int, 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)"); - O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgPairCharge, int, 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"); - - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCut, float, -1, "Two track cut: -1 = off; >0 otherwise distance value"); - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCutMinRadius, float, 0.8f, "Two track cut: radius in m from which two track cuts are applied"); - - O2_DEFINE_CONFIGURABLE(cfgPairCutPhoton, float, -1, "Pair cut on photons: -1 = off; >0 otherwise distance value (suggested: 0.004)") - O2_DEFINE_CONFIGURABLE(cfgPairCutK0, float, -1, "Pair cut on K0s: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutLambda, float, -1, "Pair cut on Lambda: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutPhi, float, -1, "Pair cut on Phi: -1 = off; >0 otherwise distance value") - O2_DEFINE_CONFIGURABLE(cfgPairCutRho, float, -1, "Pair cut on Rho: -1 = off; >0 otherwise distance value") - - // Filters and input definitions - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::cftrack::eta) < cfgCutEta) && (aod::cftrack::pt > cfgCutPt); - - // Output definitions - OutputObj<CorrelationContainer> same{"sameEvent"}; - OutputObj<CorrelationContainer> mixed{"mixedEvent"}; - //OutputObj<TDirectory> qaOutput{"qa"}; - - enum PairCuts { Photon = 0, - K0, - Lambda, - Phi, - Rho }; - struct Config { - bool mPairCuts = false; - //THn* mEfficiencyTrigger = nullptr; - //THn* mEfficiencyAssociated = nullptr; - } cfg; - - struct QA { - TH3F* mTwoTrackDistancePt[2] = {nullptr}; // control histograms for two-track efficiency study: dphi*_min vs deta (0 = before cut, 1 = after cut) - TH2F* mControlConvResoncances = nullptr; // control histograms for cuts on conversions and resonances - } qa; - - // HistogramRegistry registry{"qa", true, { - // {"yields", "centrality vs pT vs eta", {HistogramType::kTH3F, { {100, 0, 100, "centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"} }}}, - // {"etaphi", "centrality vs eta vs phi", {HistogramType::kTH3F, { {100, 0, 100, "centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"} }}} - // }}; - - OutputObj<TH3F> yields{TH3F("yields", "centrality vs pT vs eta", 100, 0, 100, 40, 0, 20, 100, -2, 2)}; - OutputObj<TH3F> etaphi{TH3F("etaphi", "centrality vs eta vs phi", 100, 0, 100, 100, -2, 2, 200, 0, 2 * M_PI)}; - - void init(o2::framework::InitContext&) - { - // --- CONFIGURATION --- - const char* binning = - "vertex: 7 | -7, 7\n" - "delta_phi: 72 | -1.570796, 4.712389\n" - "delta_eta: 40 | -2.0, 2.0\n" - "p_t_assoc: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0\n" - "p_t_trigger: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0\n" - "multiplicity: 0, 5, 10, 20, 30, 40, 50, 100.1\n" - "eta: 20 | -1.0, 1.0\n" - "p_t_leading: 100 | 0.0, 50.0\n" - "p_t_leading_course: 0.5, 1.0, 2.0, 3.0, 4.0, 6.0, 8.0\n" - "p_t_eff: 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0\n" - "vertex_eff: 10 | -10, 10\n"; - - if (cfgPairCutPhoton > 0 || cfgPairCutK0 > 0 || cfgPairCutLambda > 0 || cfgPairCutPhi > 0 || cfgPairCutRho > 0) { - cfg.mPairCuts = true; - } - - // --- OBJECT INIT --- - same.setObject(new CorrelationContainer("sameEvent", "sameEvent", "NumberDensityPhiCentralityVtx", binning)); - mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", "NumberDensityPhiCentralityVtx", binning)); - //qaOutput.setObject(new TDirectory("qa", "qa")); - - if (cfgTwoTrackCut > 0) { - qa.mTwoTrackDistancePt[0] = new TH3F("TwoTrackDistancePt[0]", ";#Delta#eta;#Delta#varphi^{*}_{min};#Delta p_{T}", 100, -0.15, 0.15, 100, -0.05, 0.05, 20, 0, 10); - qa.mTwoTrackDistancePt[1] = (TH3F*)qa.mTwoTrackDistancePt[0]->Clone("TwoTrackDistancePt[1]"); - //qaOutput->Add(qa.mTwoTrackDistancePt[0]); - //qaOutput->Add(qa.mTwoTrackDistancePt[1]); - } - - if (cfg.mPairCuts) { - qa.mControlConvResoncances = new TH2F("ControlConvResoncances", ";id;delta mass", 6, -0.5, 5.5, 500, -0.5, 0.5); - //qaOutput->Add(qa.mControlConvResoncances); - } - } - - // Version with explicit nested loop - void process(soa::Filtered<aod::CFCollisions>::iterator const& collision, soa::Filtered<aod::CFTracks> const& tracks) - { - LOGF(info, "Tracks for collision: %d | Vertex: %.1f | V0M: %.1f", tracks.size(), collision.posZ(), collision.centV0M()); - - const auto centrality = collision.centV0M(); - - same->fillEvent(centrality, CorrelationContainer::kCFStepReconstructed); - - int bSign = 1; // TODO magnetic field from CCDB - - for (auto& track1 : tracks) { - - // LOGF(info, "Track %f | %f | %f %d %d", track1.eta(), track1.phi(), track1.pt(), track1.isGlobalTrack(), track1.isGlobalTrackSDD()); - - // control histograms - // ((TH3*) (registry.get("yields").get()))->Fill(centrality, track1.pt(), track1.eta()); - // ((TH3*) (registry.get("etaphi").get()))->Fill(centrality, track1.eta(), track1.phi()); - yields->Fill(centrality, track1.pt(), track1.eta()); - etaphi->Fill(centrality, track1.eta(), track1.phi()); - - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.charge() < 0) { - continue; - } - - same->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), centrality, collision.posZ()); - //mixed->getTriggerHist()->Fill(eventValues, CorrelationContainer::kCFStepReconstructed); - - for (auto& track2 : tracks) { - if (track1 == track2) { - continue; - } - - if (cfgPtOrder != 0 && track2.pt() >= track1.pt()) { - continue; - } - - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.charge() < 0) { - continue; - } - if (cfgPairCharge != 0 && cfgPairCharge * track1.charge() * track2.charge() < 0) { - continue; - } - - if (cfg.mPairCuts && conversionCuts(track1, track2)) { - continue; - } - - if (cfgTwoTrackCut > 0 && twoTrackCut(track1, track2, bSign)) { - continue; - } - - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5 * TMath::Pi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi < -0.5 * TMath::Pi()) { - deltaPhi += TMath::TwoPi(); - } - - same->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - track1.eta() - track2.eta(), track2.pt(), track1.pt(), centrality, deltaPhi, collision.posZ()); - //mixed->getPairHist()->Fill(values, CorrelationContainer::kCFStepReconstructed); - } - } - } - - template <typename T> - bool conversionCuts(T const& track1, T const& track2) - { - // skip if like sign - if (track1.charge() * track2.charge() > 0) { - return false; - } - - bool decision = false; - - if (conversionCut(track1, track2, Photon, cfgPairCutPhoton)) { - decision = true; - } - if (conversionCut(track1, track2, K0, cfgPairCutK0)) { - decision = true; - } - if (conversionCut(track1, track2, Lambda, cfgPairCutLambda)) { - decision = true; - } - if (conversionCut(track2, track1, Lambda, cfgPairCutLambda)) { - decision = true; - } - if (conversionCut(track1, track2, Phi, cfgPairCutPhi)) { - decision = true; - } - if (conversionCut(track1, track2, Rho, cfgPairCutRho)) { - decision = true; - } - - return decision; - } - - template <typename T> - bool conversionCut(T const& track1, T const& track2, PairCuts conv, double cut) - { - //LOGF(info, "pt is %f %f", track1.pt(), track2.pt()); - - if (cut < 0) { - return false; - } - - double massD1, massD2, massM; - - switch (conv) { - case Photon: - massD1 = 0.51e-3; - massD2 = 0.51e-3; - massM = 0; - break; - case K0: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.4976; - break; - case Lambda: - massD1 = 0.9383; - massD2 = 0.1396; - massM = 1.115; - break; - case Phi: - massD1 = 0.4937; - massD2 = 0.4937; - massM = 1.019; - break; - case Rho: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.770; - break; - } - - auto massC = getInvMassSquaredFast(track1, massD1, track2, massD2); - - if (TMath::Abs(massC - massM * massM) > cut * 5) { - return false; - } - - massC = getInvMassSquared(track1, massD1, track2, massD2); - qa.mControlConvResoncances->Fill(static_cast<int>(conv), massC - massM * massM); - if (massC > (massM - cut) * (massM - cut) && massC < (massM + cut) * (massM + cut)) { - return true; - } - - return false; - } - - template <typename T> - double getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2) - { - // calculate inv mass squared - // same can be achieved, but with more computing time with - /*TLorentzVector photon, p1, p2; - p1.SetPtEtaPhiM(triggerParticle->Pt(), triggerEta, triggerParticle->Phi(), 0.510e-3); - p2.SetPtEtaPhiM(particle->Pt(), eta[j], particle->Phi(), 0.510e-3); - photon = p1+p2; - photon.M()*/ - - float tantheta1 = 1e10; - - if (track1.eta() < -1e-10 || track1.eta() > 1e-10) { - float expTmp = TMath::Exp(-track1.eta()); - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (track2.eta() < -1e-10 || track2.eta() > 1e-10) { - float expTmp = TMath::Exp(-track2.eta()); - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + track1.pt() * track1.pt() * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + track2.pt() * track2.pt() * (1.0 + 1.0 / tantheta2 / tantheta2); - - float mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (track1.pt() * track2.pt() * (TMath::Cos(track1.phi() - track2.phi()) + 1.0 / tantheta1 / tantheta2))); - - // Printf(Form("%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2)); - - return mass2; - } - - template <typename T> - double getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2) - { - // calculate inv mass squared approximately - - const float eta1 = track1.eta(); - const float eta2 = track2.eta(); - const float phi1 = track1.phi(); - const float phi2 = track2.phi(); - const float pt1 = track1.pt(); - const float pt2 = track2.pt(); - - float tantheta1 = 1e10; - - if (eta1 < -1e-10 || eta1 > 1e-10) { - float expTmp = 1.0 - eta1 + eta1 * eta1 / 2 - eta1 * eta1 * eta1 / 6 + eta1 * eta1 * eta1 * eta1 / 24; - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (eta2 < -1e-10 || eta2 > 1e-10) { - float expTmp = 1.0 - eta2 + eta2 * eta2 / 2 - eta2 * eta2 * eta2 / 6 + eta2 * eta2 * eta2 * eta2 / 24; - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + pt1 * pt1 * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + pt2 * pt2 * (1.0 + 1.0 / tantheta2 / tantheta2); - - // fold onto 0...pi - float deltaPhi = TMath::Abs(phi1 - phi2); - while (deltaPhi > TMath::TwoPi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi > TMath::Pi()) { - deltaPhi = TMath::TwoPi() - deltaPhi; - } - - float cosDeltaPhi = 0; - if (deltaPhi < TMath::Pi() / 3) { - cosDeltaPhi = 1.0 - deltaPhi * deltaPhi / 2 + deltaPhi * deltaPhi * deltaPhi * deltaPhi / 24; - } else if (deltaPhi < 2 * TMath::Pi() / 3) { - cosDeltaPhi = -(deltaPhi - TMath::Pi() / 2) + 1.0 / 6 * TMath::Power((deltaPhi - TMath::Pi() / 2), 3); - } else { - cosDeltaPhi = -1.0 + 1.0 / 2.0 * (deltaPhi - TMath::Pi()) * (deltaPhi - TMath::Pi()) - 1.0 / 24.0 * TMath::Power(deltaPhi - TMath::Pi(), 4); - } - - double mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (pt1 * pt2 * (cosDeltaPhi + 1.0 / tantheta1 / tantheta2))); - - // Printf(Form("%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2)); - - return mass2; - } - - template <typename T> - bool twoTrackCut(T const& track1, T const& track2, int bSign) - { - // the variables & cuthave been developed by the HBT group - // see e.g. https://indico.cern.ch/materialDisplay.py?contribId=36&sessionId=6&materialId=slides&confId=142700 - - auto deta = track1.eta() - track2.eta(); - - // optimization - if (TMath::Abs(deta) < cfgTwoTrackCut * 2.5 * 3) { - // check first boundaries to see if is worth to loop and find the minimum - float dphistar1 = getDPhiStar(track1, track2, cfgTwoTrackCutMinRadius, bSign); - float dphistar2 = getDPhiStar(track1, track2, 2.5, bSign); - - const float kLimit = cfgTwoTrackCut * 3; - - if (TMath::Abs(dphistar1) < kLimit || TMath::Abs(dphistar2) < kLimit || dphistar1 * dphistar2 < 0) { - float dphistarminabs = 1e5; - float dphistarmin = 1e5; - for (Double_t rad = cfgTwoTrackCutMinRadius; rad < 2.51; rad += 0.01) { - float dphistar = getDPhiStar(track1, track2, rad, bSign); - - float dphistarabs = TMath::Abs(dphistar); - - if (dphistarabs < dphistarminabs) { - dphistarmin = dphistar; - dphistarminabs = dphistarabs; - } - } - - qa.mTwoTrackDistancePt[0]->Fill(deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - - if (dphistarminabs < cfgTwoTrackCut && TMath::Abs(deta) < cfgTwoTrackCut) { - //Printf("Removed track pair %ld %ld with %f %f %f %f %d %f %f %d %d", track1.index(), track2.index(), deta, dphistarminabs, track1.phi2(), track1.pt(), track1.charge(), track2.phi2(), track2.pt(), track2.charge(), bSign); - return true; - } - - qa.mTwoTrackDistancePt[1]->Fill(deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - } - } - - return false; - } - - template <typename T> - float getDPhiStar(T const& track1, T const& track2, float radius, float bSign) - { - // - // calculates dphistar - // - - auto phi1 = track1.phi(); - auto pt1 = track1.pt(); - auto charge1 = track1.charge(); - - auto phi2 = track2.phi(); - auto pt2 = track2.pt(); - auto charge2 = track2.charge(); - - float dphistar = phi1 - phi2 - charge1 * bSign * TMath::ASin(0.075 * radius / pt1) + charge2 * bSign * TMath::ASin(0.075 * radius / pt2); - - static const Double_t kPi = TMath::Pi(); - - if (dphistar > kPi) { - dphistar = kPi * 2 - dphistar; - } - if (dphistar < -kPi) { - dphistar = -kPi * 2 - dphistar; - } - if (dphistar > kPi) { // might look funny but is needed - dphistar = kPi * 2 - dphistar; - } - - return dphistar; - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<CorrelationTask>("correlation-task")}; -} diff --git a/Analysis/Tasks/PWGCF/correlationsMixed.cxx b/Analysis/Tasks/PWGCF/correlationsMixed.cxx deleted file mode 100644 index 529dd9eba04fa..0000000000000 --- a/Analysis/Tasks/PWGCF/correlationsMixed.cxx +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/StepTHn.h" - -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "Analysis/CorrelationContainer.h" -#include "Analysis/TrackSelectionTables.h" - -#include <TH1F.h> -#include <cmath> -#include <TDirectory.h> - -namespace o2::aod -{ -namespace hash -{ -DECLARE_SOA_COLUMN(Bin, bin, int); -} // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); - -using Hash = Hashes::iterator; -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct HashTask { - std::vector<float> vtxBins{-7.0f, -5.0f, -3.0f, -1.0f, 1.0f, 3.0f, 5.0f, 7.0f}; - std::vector<float> multBins{0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f}; - Produces<aod::Hashes> hashes; - - // Calculate hash for an element based on 2 properties and their bins. - int getHash(std::vector<float> const& vtxBins, std::vector<float> const& multBins, float vtx, float mult) - { - // underflow - if (vtx < vtxBins[0]) { - return -1; - } - if (mult < multBins[0]) { - return -1; - } - - for (int i = 1; i < vtxBins.size(); i++) { - if (vtx < vtxBins[i]) { - for (int j = 1; j < multBins.size(); j++) { - if (mult < multBins[j]) { - return i + j * (vtxBins.size() + 1); - } - } - } - } - // overflow - return -1; - } - - void process(soa::Join<aod::Collisions, aod::Cents> const& collisions) - { - for (auto& collision : collisions) { - int hash = getHash(vtxBins, multBins, collision.posZ(), collision.centV0M()); - LOGF(info, "Collision: %d (%f, %f) hash: %d", collision.index(), collision.posZ(), collision.centV0M(), hash); - hashes(hash); - } - } -}; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP}; - -struct CorrelationTask { - - // Input definitions - using myTracks = soa::Filtered<aod::Tracks>; - - // Filters - Filter trackFilter = (aod::track::eta > -0.8f) && (aod::track::eta < 0.8f) && (aod::track::pt > 1.0f); - - // Output definitions - OutputObj<CorrelationContainer> same{"sameEvent"}; - OutputObj<CorrelationContainer> mixed{"mixedEvent"}; - //OutputObj<TDirectory> qaOutput{"qa"}; - - // Configuration - O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all; 1 = positive; -1 = negative"); - O2_DEFINE_CONFIGURABLE(cfgPairCharge, int, 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"); - - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCut, float, -1, "Two track cut: -1 = off; >0 otherwise distance value"); - O2_DEFINE_CONFIGURABLE(cfgTwoTrackCutMinRadius, float, 0.8f, "Two track cut: radius in m from which two track cuts are applied"); - - O2_DEFINE_CONFIGURABLE(cfgPairCutPhoton, float, -1, "Pair cut on photons: -1 = off; >0 otherwise distance value (suggested: 0.004)") - O2_DEFINE_CONFIGURABLE(cfgPairCutK0, float, -1, "Pair cut on K0s: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutLambda, float, -1, "Pair cut on Lambda: -1 = off; >0 otherwise distance value (suggested: 0.005)") - O2_DEFINE_CONFIGURABLE(cfgPairCutPhi, float, -1, "Pair cut on Phi: -1 = off; >0 otherwise distance value") - O2_DEFINE_CONFIGURABLE(cfgPairCutRho, float, -1, "Pair cut on Rho: -1 = off; >0 otherwise distance value") - - enum PairCuts { Photon = 0, - K0, - Lambda, - Phi, - Rho }; - struct Config { - bool mPairCuts = false; - //THn* mEfficiencyTrigger = nullptr; - //THn* mEfficiencyAssociated = nullptr; - } cfg; - - struct QA { - TH3F* mTwoTrackDistancePt[2] = {nullptr}; // control histograms for two-track efficiency study: dphi*_min vs deta (0 = before cut, 1 = after cut) - TH2F* mControlConvResoncances = nullptr; // control histograms for cuts on conversions and resonances - } qa; - - void init(o2::framework::InitContext&) - { - // --- CONFIGURATION --- - const char* binning = - "vertex: -7, -5, -3, -1, 1, 3, 5, 7\n" - "delta_phi: -1.570796, -1.483530, -1.396263, -1.308997, -1.221730, -1.134464, -1.047198, -0.959931, -0.872665, -0.785398, -0.698132, -0.610865, -0.523599, -0.436332, -0.349066, -0.261799, -0.174533, -0.087266, 0.0, 0.087266, 0.174533, 0.261799, 0.349066, 0.436332, 0.523599, 0.610865, 0.698132, 0.785398, 0.872665, 0.959931, 1.047198, 1.134464, 1.221730, 1.308997, 1.396263, 1.483530, 1.570796, 1.658063, 1.745329, 1.832596, 1.919862, 2.007129, 2.094395, 2.181662, 2.268928, 2.356194, 2.443461, 2.530727, 2.617994, 2.705260, 2.792527, 2.879793, 2.967060, 3.054326, 3.141593, 3.228859, 3.316126, 3.403392, 3.490659, 3.577925, 3.665191, 3.752458, 3.839724, 3.926991, 4.014257, 4.101524, 4.188790, 4.276057, 4.363323, 4.450590, 4.537856, 4.625123, 4.712389\n" - "delta_eta: -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0\n" - "p_t_assoc: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0\n" - "p_t_trigger: 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0\n" - "multiplicity: 0, 5, 10, 20, 30, 40, 50, 100.1\n" - "eta: -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0\n" - "p_t_leading: 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5, 25.0, 25.5, 26.0, 26.5, 27.0, 27.5, 28.0, 28.5, 29.0, 29.5, 30.0, 30.5, 31.0, 31.5, 32.0, 32.5, 33.0, 33.5, 34.0, 34.5, 35.0, 35.5, 36.0, 36.5, 37.0, 37.5, 38.0, 38.5, 39.0, 39.5, 40.0, 40.5, 41.0, 41.5, 42.0, 42.5, 43.0, 43.5, 44.0, 44.5, 45.0, 45.5, 46.0, 46.5, 47.0, 47.5, 48.0, 48.5, 49.0, 49.5, 50.0\n" - "p_t_leading_course: 0.5, 1.0, 2.0, 3.0, 4.0, 6.0, 8.0\n" - "p_t_eff: 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0\n" - "vertex_eff: -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10\n"; - - if (cfgPairCutPhoton > 0 || cfgPairCutK0 > 0 || cfgPairCutLambda > 0 || cfgPairCutPhi > 0 || cfgPairCutRho > 0) { - cfg.mPairCuts = true; - } - - // --- OBJECT INIT --- - same.setObject(new CorrelationContainer("sameEvent", "sameEvent", "NumberDensityPhiCentrality", binning)); - mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", "NumberDensityPhiCentrality", binning)); - //qaOutput.setObject(new TDirectory("qa", "qa")); - - if (cfgTwoTrackCut > 0) { - qa.mTwoTrackDistancePt[0] = new TH3F("TwoTrackDistancePt[0]", ";#Delta#eta;#Delta#varphi^{*}_{min};#Delta p_{T}", 100, -0.15, 0.15, 100, -0.05, 0.05, 20, 0, 10); - qa.mTwoTrackDistancePt[1] = (TH3F*)qa.mTwoTrackDistancePt[0]->Clone("TwoTrackDistancePt[1]"); - //qaOutput->Add(qa.mTwoTrackDistancePt[0]); - //qaOutput->Add(qa.mTwoTrackDistancePt[1]); - } - - if (cfg.mPairCuts) { - qa.mControlConvResoncances = new TH2F("ControlConvResoncances", ";id;delta mass", 6, -0.5, 5.5, 500, -0.5, 0.5); - //qaOutput->Add(qa.mControlConvResoncances); - } - } - - void process(soa::Join<aod::Collisions, aod::Hashes, aod::EvSels, aod::Cents>& collisions, myTracks const& tracks) - { - int bSign = 1; // TODO magnetic field from CCDB - const float pTCut = 2.0; - - collisions.bindExternalIndices(&tracks); - auto tracksTuple = std::make_tuple(tracks); - AnalysisDataProcessorBuilder::GroupSlicer slicer(collisions, tracksTuple); - - // Strictly upper categorised collisions, for 5 combinations per bin, skipping those in entry -1 - for (auto& [collision1, collision2] : selfCombinations("fBin", 5, -1, collisions, collisions)) { - - LOGF(info, "Collisions bin: %d pair: %d (%f), %d (%f)", collision1.bin(), collision1.index(), collision1.posZ(), collision2.index(), collision2.posZ()); - - auto it1 = slicer.begin(); - auto it2 = slicer.begin(); - for (auto& slice : slicer) { - if (slice.groupingElement().index() == collision1.index()) { - it1 = slice; - break; - } - } - for (auto& slice : slicer) { - if (slice.groupingElement().index() == collision2.index()) { - it2 = slice; - break; - } - } - - auto tracks1 = std::get<myTracks>(it1.associatedTables()); - tracks1.bindExternalIndices(&collisions); - auto tracks2 = std::get<myTracks>(it2.associatedTables()); - tracks2.bindExternalIndices(&collisions); - - // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); - - for (auto& track1 : tracks1) { - - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.charge() < 0) { - continue; - } - - //LOGF(info, "TRACK %f %f | %f %f | %f %f", track1.eta(), track1.eta(), track1.phi(), track1.phi(), track1.pt(), track1.pt()); - - mixed->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), collision1.centV0M(), collision1.posZ()); - - for (auto& track2 : tracks2) { - - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.charge() < 0) { - continue; - } - if (cfgPairCharge != 0 && cfgPairCharge * track1.charge() * track2.charge() < 0) { - continue; - } - - if (cfg.mPairCuts && conversionCuts(track1, track2)) { - continue; - } - - if (cfgTwoTrackCut > 0 && twoTrackCut(track1, track2, bSign)) { - continue; - } - - float deltaPhi = track1.phi() - track2.phi(); - if (deltaPhi > 1.5 * TMath::Pi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi < -0.5 * TMath::Pi()) { - deltaPhi += TMath::TwoPi(); - } - - mixed->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - track1.eta() - track2.eta(), track2.pt(), track1.pt(), collision1.centV0M(), deltaPhi, collision1.posZ()); - } - } - } - } - - template <typename T> - bool conversionCuts(T const& track1, T const& track2) - { - // skip if like sign - if (track1.charge() * track2.charge() > 0) { - return false; - } - - bool decision = false; - - if (conversionCut(track1, track2, Photon, cfgPairCutPhoton)) { - decision = true; - } - if (conversionCut(track1, track2, K0, cfgPairCutK0)) { - decision = true; - } - if (conversionCut(track1, track2, Lambda, cfgPairCutLambda)) { - decision = true; - } - if (conversionCut(track2, track1, Lambda, cfgPairCutLambda)) { - decision = true; - } - if (conversionCut(track1, track2, Phi, cfgPairCutPhi)) { - decision = true; - } - if (conversionCut(track1, track2, Rho, cfgPairCutRho)) { - decision = true; - } - - return decision; - } - - template <typename T> - bool conversionCut(T const& track1, T const& track2, PairCuts conv, double cut) - { - //LOGF(info, "pt is %f %f", track1.pt(), track2.pt()); - - if (cut < 0) { - return false; - } - - double massD1, massD2, massM; - - switch (conv) { - case Photon: - massD1 = 0.51e-3; - massD2 = 0.51e-3; - massM = 0; - break; - case K0: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.4976; - break; - case Lambda: - massD1 = 0.9383; - massD2 = 0.1396; - massM = 1.115; - break; - case Phi: - massD1 = 0.4937; - massD2 = 0.4937; - massM = 1.019; - break; - case Rho: - massD1 = 0.1396; - massD2 = 0.1396; - massM = 0.770; - break; - } - - auto massC = getInvMassSquaredFast(track1, massD1, track2, massD2); - - if (TMath::Abs(massC - massM * massM) > cut * 5) { - return false; - } - - massC = getInvMassSquared(track1, massD1, track2, massD2); - qa.mControlConvResoncances->Fill(static_cast<int>(conv), massC - massM * massM); - if (massC > (massM - cut) * (massM - cut) && massC < (massM + cut) * (massM + cut)) { - return true; - } - - return false; - } - - template <typename T> - double getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2) - { - // calculate inv mass squared - // same can be achieved, but with more computing time with - /*TLorentzVector photon, p1, p2; - p1.SetPtEtaPhiM(triggerParticle->Pt(), triggerEta, triggerParticle->Phi(), 0.510e-3); - p2.SetPtEtaPhiM(particle->Pt(), eta[j], particle->Phi(), 0.510e-3); - photon = p1+p2; - photon.M()*/ - - float tantheta1 = 1e10; - - if (track1.eta() < -1e-10 || track1.eta() > 1e-10) { - float expTmp = TMath::Exp(-track1.eta()); - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (track2.eta() < -1e-10 || track2.eta() > 1e-10) { - float expTmp = TMath::Exp(-track2.eta()); - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + track1.pt() * track1.pt() * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + track2.pt() * track2.pt() * (1.0 + 1.0 / tantheta2 / tantheta2); - - float mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (track1.pt() * track2.pt() * (TMath::Cos(track1.phi() - track2.phi()) + 1.0 / tantheta1 / tantheta2))); - - // Printf(Form("%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2)); - - return mass2; - } - - template <typename T> - double getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2) - { - // calculate inv mass squared approximately - - const float eta1 = track1.eta(); - const float eta2 = track2.eta(); - const float phi1 = track1.phi(); - const float phi2 = track2.phi(); - const float pt1 = track1.pt(); - const float pt2 = track2.pt(); - - float tantheta1 = 1e10; - - if (eta1 < -1e-10 || eta1 > 1e-10) { - float expTmp = 1.0 - eta1 + eta1 * eta1 / 2 - eta1 * eta1 * eta1 / 6 + eta1 * eta1 * eta1 * eta1 / 24; - tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float tantheta2 = 1e10; - if (eta2 < -1e-10 || eta2 > 1e-10) { - float expTmp = 1.0 - eta2 + eta2 * eta2 / 2 - eta2 * eta2 * eta2 / 6 + eta2 * eta2 * eta2 * eta2 / 24; - tantheta2 = 2.0 * expTmp / (1.0 - expTmp * expTmp); - } - - float e1squ = m0_1 * m0_1 + pt1 * pt1 * (1.0 + 1.0 / tantheta1 / tantheta1); - float e2squ = m0_2 * m0_2 + pt2 * pt2 * (1.0 + 1.0 / tantheta2 / tantheta2); - - // fold onto 0...pi - float deltaPhi = TMath::Abs(phi1 - phi2); - while (deltaPhi > TMath::TwoPi()) { - deltaPhi -= TMath::TwoPi(); - } - if (deltaPhi > TMath::Pi()) { - deltaPhi = TMath::TwoPi() - deltaPhi; - } - - float cosDeltaPhi = 0; - if (deltaPhi < TMath::Pi() / 3) { - cosDeltaPhi = 1.0 - deltaPhi * deltaPhi / 2 + deltaPhi * deltaPhi * deltaPhi * deltaPhi / 24; - } else if (deltaPhi < 2 * TMath::Pi() / 3) { - cosDeltaPhi = -(deltaPhi - TMath::Pi() / 2) + 1.0 / 6 * TMath::Power((deltaPhi - TMath::Pi() / 2), 3); - } else { - cosDeltaPhi = -1.0 + 1.0 / 2.0 * (deltaPhi - TMath::Pi()) * (deltaPhi - TMath::Pi()) - 1.0 / 24.0 * TMath::Power(deltaPhi - TMath::Pi(), 4); - } - - double mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2 * (TMath::Sqrt(e1squ * e2squ) - (pt1 * pt2 * (cosDeltaPhi + 1.0 / tantheta1 / tantheta2))); - - // Printf(Form("%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2)); - - return mass2; - } - - template <typename T> - bool twoTrackCut(T const& track1, T const& track2, int bSign) - { - // the variables & cuthave been developed by the HBT group - // see e.g. https://indico.cern.ch/materialDisplay.py?contribId=36&sessionId=6&materialId=slides&confId=142700 - - auto deta = track1.eta() - track2.eta(); - - // optimization - if (TMath::Abs(deta) < cfgTwoTrackCut * 2.5 * 3) { - // check first boundaries to see if is worth to loop and find the minimum - float dphistar1 = getDPhiStar(track1, track2, cfgTwoTrackCutMinRadius, bSign); - float dphistar2 = getDPhiStar(track1, track2, 2.5, bSign); - - const float kLimit = cfgTwoTrackCut * 3; - - if (TMath::Abs(dphistar1) < kLimit || TMath::Abs(dphistar2) < kLimit || dphistar1 * dphistar2 < 0) { - float dphistarminabs = 1e5; - float dphistarmin = 1e5; - for (Double_t rad = cfgTwoTrackCutMinRadius; rad < 2.51; rad += 0.01) { - float dphistar = getDPhiStar(track1, track2, rad, bSign); - - float dphistarabs = TMath::Abs(dphistar); - - if (dphistarabs < dphistarminabs) { - dphistarmin = dphistar; - dphistarminabs = dphistarabs; - } - } - - qa.mTwoTrackDistancePt[0]->Fill(deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - - if (dphistarminabs < cfgTwoTrackCut && TMath::Abs(deta) < cfgTwoTrackCut) { - //Printf("Removed track pair %ld %ld with %f %f %f %f %d %f %f %d %d", track1.index(), track2.index(), deta, dphistarminabs, track1.phi(), track1.pt(), track1.charge(), track2.phi(), track2.pt(), track2.charge(), bSign); - return true; - } - - qa.mTwoTrackDistancePt[1]->Fill(deta, dphistarmin, TMath::Abs(track1.pt() - track2.pt())); - } - } - - return false; - } - - template <typename T> - float getDPhiStar(T const& track1, T const& track2, float radius, float bSign) - { - // - // calculates dphistar - // - - auto phi1 = track1.phi(); - auto pt1 = track1.pt(); - auto charge1 = track1.charge(); - - auto phi2 = track2.phi(); - auto pt2 = track2.pt(); - auto charge2 = track2.charge(); - - float dphistar = phi1 - phi2 - charge1 * bSign * TMath::ASin(0.075 * radius / pt1) + charge2 * bSign * TMath::ASin(0.075 * radius / pt2); - - static const Double_t kPi = TMath::Pi(); - - if (dphistar > kPi) { - dphistar = kPi * 2 - dphistar; - } - if (dphistar < -kPi) { - dphistar = -kPi * 2 - dphistar; - } - if (dphistar > kPi) { // might look funny but is needed - dphistar = kPi * 2 - dphistar; - } - - return dphistar; - } - - // template<typename... Ts> - // unsigned int getFilterBit(soa::Table<Ts...>::iterator const& track) - // { - // if constexpr(!has_type_v<aod::track::X, pack<Ts...>>) - // static_assert("Need to pass aod::track"); - // - // - // // LOGF(info, "pt %f", track1.pt()); - // return false; - // } - - // float getInvMassSquared(float pt1, float eta1, float phi1, float pt2, float eta2, float phi2, float m0_1, float m0_2) -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HashTask>("produce-hashes"), - adaptAnalysisTask<CorrelationTask>("correlation-task")}; -} diff --git a/Analysis/Tasks/PWGCF/dptdptcorrelations.cxx b/Analysis/Tasks/PWGCF/dptdptcorrelations.cxx deleted file mode 100644 index 327802d5bdadf..0000000000000 --- a/Analysis/Tasks/PWGCF/dptdptcorrelations.cxx +++ /dev/null @@ -1,857 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "Analysis/TrackSelection.h" -#include "AnalysisConfigurableCuts.h" -#include "Analysis/TrackSelectionTables.h" -#include <TROOT.h> -#include <TParameter.h> -#include <TList.h> -#include <TDirectory.h> -#include <TH1.h> -#include <TH2.h> -#include <TH3.h> -#include <TProfile3D.h> - -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; -using namespace o2::framework::expressions; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - ConfigParamSpec centspec = {"centralities", - VariantType::String, - "00-05,05-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80", - {"Centrality/multiplicity ranges in min-max separated by commas"}}; - workflowOptions.push_back(centspec); -} - -#include "Framework/runDataProcessing.h" - -namespace o2 -{ -namespace aod -{ -/* we have to change from int to bool when bool columns work properly */ -namespace dptdptcorrelations -{ -DECLARE_SOA_COLUMN(EventAccepted, eventaccepted, uint8_t); -DECLARE_SOA_COLUMN(EventCentMult, centmult, float); -DECLARE_SOA_COLUMN(TrackacceptedAsOne, trackacceptedasone, uint8_t); -DECLARE_SOA_COLUMN(TrackacceptedAsTwo, trackacceptedastwo, uint8_t); -} // namespace dptdptcorrelations -DECLARE_SOA_TABLE(AcceptedEvents, "AOD", "ACCEPTEDEVENTS", dptdptcorrelations::EventAccepted, dptdptcorrelations::EventCentMult); -DECLARE_SOA_TABLE(ScannedTracks, "AOD", "SCANNEDTRACKS", dptdptcorrelations::TrackacceptedAsOne, dptdptcorrelations::TrackacceptedAsTwo); - -using CollisionEvSelCent = soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator; -using TrackData = soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra, aod::TracksExtended, aod::TrackSelection>::iterator; -using FilteredTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksExtended, aod::ScannedTracks>>; -using FilteredTrackData = Partition<aod::FilteredTracks>::filtered_iterator; -} // namespace aod -} // namespace o2 - -namespace dptdptcorrelations -{ -/* all this is made configurable */ -int ptbins = 18; -float ptlow = 0.2, ptup = 2.0; -int etabins = 16; -float etalow = -0.8, etaup = 0.8; -int zvtxbins = 40; -float zvtxlow = -10.0, zvtxup = 10.0; -int phibins = 72; -float philow = 0.0; -float phiup = TMath::TwoPi(); -float phibinshift = 0.5; -float etabinwidth = (etaup - etalow) / float(etabins); -float phibinwidth = (phiup - philow) / float(phibins); -int tracktype = 1; -int trackonecharge = 1; -int tracktwocharge = -1; -bool processpairs = false; -std::string fTaskConfigurationString = "PendingToConfigure"; - -/* while we don't have proper bool columnst */ -uint8_t DPTDPT_TRUE = 1; -uint8_t DPTDPT_FALSE = 0; - -/// \enum SystemType -/// \brief The type of the system under analysis -enum SystemType { - kNoSystem = 0, ///< no system defined - kpp, ///< **p-p** system - kpPb, ///< **p-Pb** system - kPbp, ///< **Pb-p** system - kPbPb, ///< **Pb-Pb** system - kXeXe, ///< **Xe-Xe** system - knSystems ///< number of handled systems -}; - -/// \enum CentMultEstimatorType -/// \brief The detector used to estimate centrality/multiplicity -enum CentMultEstimatorType { - kV0M = 0, ///< V0M centrality/multiplicity estimator - kV0A, ///< V0A centrality/multiplicity estimator - kV0C, ///< V0C centrality/multiplicity estimator - kCL0, ///< CL0 centrality/multiplicity estimator - kCL1, ///< CL1 centrality/multiplicity estimator - knCentMultEstimators ///< number of centrality/mutiplicity estimator -}; - -namespace filteranalyistask -{ -//============================================================================================ -// The DptDptCorrelationsFilterAnalysisTask output objects -//============================================================================================ -SystemType fSystem = kNoSystem; -CentMultEstimatorType fCentMultEstimator = kV0M; -TH1F* fhCentMultB = nullptr; -TH1F* fhCentMultA = nullptr; -TH1F* fhVertexZB = nullptr; -TH1F* fhVertexZA = nullptr; -TH1F* fhPtB = nullptr; -TH1F* fhPtA = nullptr; -TH1F* fhPtPosB = nullptr; -TH1F* fhPtPosA = nullptr; -TH1F* fhPtNegB = nullptr; -TH1F* fhPtNegA = nullptr; - -TH1F* fhEtaB = nullptr; -TH1F* fhEtaA = nullptr; - -TH1F* fhPhiB = nullptr; -TH1F* fhPhiA = nullptr; - -TH2F* fhEtaVsPhiB = nullptr; -TH2F* fhEtaVsPhiA = nullptr; - -TH2F* fhPtVsEtaB = nullptr; -TH2F* fhPtVsEtaA = nullptr; -} // namespace filteranalyistask - -namespace correlationstask -{ -//============================================================================================ -// The DptDptCorrelationsAnalysisTask output objects -//============================================================================================ -/* histograms */ -TH1F* fhN1_1_vsPt; //!<! track 1 weighted single particle distribution vs \f$p_T\f$ -TH2F* fhN1_1_vsEtaPhi; //!<! track 1 weighted single particle distribution vs \f$\eta,\;\phi\f$ -TH2F* fhSum1Pt_1_vsEtaPhi; //!<! track 1 accumulated sum of weighted \f$p_T\f$ vs \f$\eta,\;\phi\f$ -TH3F* fhN1_1_vsZEtaPhiPt; //!<! track 1 single particle distribution vs \f$\mbox{vtx}_z,\; \eta,\;\phi,\;p_T\f$ -TH1F* fhN1_2_vsPt; //!<! track 2 weighted single particle distribution vs \f$p_T\f$ -TH2F* fhN1_2_vsEtaPhi; //!<! track 2 weighted single particle distribution vs \f$\eta,\;\phi\f$ -TH2F* fhSum1Pt_2_vsEtaPhi; //!<! track 2 accumulated sum of weighted \f$p_T\f$ vs \f$\eta,\;\phi\f$ -TH3F* fhN1_2_vsZEtaPhiPt; //!<! track 2 single particle distribution vs \f$\mbox{vtx}_z,\;\eta,\;\phi,\;p_T\f$ -TH2F* fhN2_12_vsPtPt; //!<! track 1 and 2 weighted two particle distribution vs \f${p_T}_1, {p_T}_2\f$ -TH1F* fhN2_12_vsEtaPhi; //!<! track 1 and 2 weighted two particle distribution vs \f$\eta,\;\phi\f$ -TH1F* fhSum2PtPt_12_vsEtaPhi; //!<! track 1 and 2 weighted accumulated \f${p_T}_1 {p_T}_2\f$ distribution vs \f$\eta,\;\phi\f$ -TH1F* fhSum2PtN_12_vsEtaPhi; //!<! track 1 and 2 weighted accumulated \f${p_T}_1 n_2\f$ distribution vs \f$\eta,\;\phi\f$ -TH1F* fhSum2NPt_12_vsEtaPhi; //!<! track 1 and 2 weighted accumulated \f$n_1 {p_T}_2\f$ distribution vs \f$\eta,\;\phi\f$ -/* versus centrality/multiplicity profiles */ -TProfile* fhN1_1_vsC; //!<! track 1 weighted single particle distribution vs event centrality -TProfile* fhSum1Pt_1_vsC; //!<! track 1 accumulated sum of weighted \f$p_T\f$ vs event centrality -TProfile* fhN1nw_1_vsC; //!<! track 1 un-weighted single particle distribution vs event centrality -TProfile* fhSum1Ptnw_1_vsC; //!<! track 1 accumulated sum of un-weighted \f$p_T\f$ vs event centrality -TProfile* fhN1_2_vsC; //!<! track 2 weighted single particle distribution vs event centrality -TProfile* fhSum1Pt_2_vsC; //!<! track 2 accumulated sum of weighted \f$p_T\f$ vs event centrality -TProfile* fhN1nw_2_vsC; //!<! track 2 un-weighted single particle distribution vs event centrality -TProfile* fhSum1Ptnw_2_vsC; //!<! track 2 accumulated sum of un-weighted \f$p_T\f$ vs event centrality -TProfile* fhN2_12_vsC; //!<! track 1 and 2 weighted two particle distribution vs event centrality -TProfile* fhSum2PtPt_12_vsC; //!<! track 1 and 2 weighted accumulated \f${p_T}_1 {p_T}_2\f$ distribution vs event centrality -TProfile* fhSum2PtN_12_vsC; //!<! track 1 and 2 weighted accumulated \f${p_T}_1 n_2\f$ distribution vs event centrality -TProfile* fhSum2NPt_12_vsC; //!<! track 1 and 2 weighted accumulated \f$n_1 {p_T}_2\f$ distribution vs event centrality -TProfile* fhN2nw_12_vsC; //!<! track 1 and 2 un-weighted two particle distribution vs event centrality -TProfile* fhSum2PtPtnw_12_vsC; //!<! track 1 and 2 un-weighted accumulated \f${p_T}_1 {p_T}_2\f$ distribution vs event centrality -TProfile* fhSum2PtNnw_12_vsC; //!<! track 1 and 2 un-weighted accumulated \f${p_T}_1 n_2\f$ distribution vs event centrality -TProfile* fhSum2NPtnw_12_vsC; //!<! track 1 and 2 un-weighted accumulated \f$n_1 {p_T}_2\f$ distribution vs event centrality -} // namespace correlationstask - -SystemType getSystemType() -{ - /* we have to figure out how extract the system type */ - return kPbPb; -} - -bool IsEvtSelected(aod::CollisionEvSelCent const& collision, float& centormult) -{ - using namespace filteranalyistask; - - if (collision.alias()[kINT7]) { - if (collision.sel7()) { - /* TODO: vertex quality checks */ - if (zvtxlow < collision.posZ() and collision.posZ() < zvtxup) { - switch (fCentMultEstimator) { - case kV0M: - if (collision.centV0M() < 100 and 0 < collision.centV0M()) { - centormult = collision.centV0M(); - return true; - } - break; - default: - break; - } - return false; - } - return false; - } - } - return false; -} - -bool matchTrackType(aod::TrackData const& track) -{ - switch (tracktype) { - case 1: - if (track.isGlobalTrack() != 0 || track.isGlobalTrackSDD() != 0) { - return true; - } else { - return false; - } - break; - default: - return false; - } -} - -inline void AcceptTrack(aod::TrackData const& track, uint8_t& asone, uint8_t& astwo) -{ - - asone = DPTDPT_FALSE; - astwo = DPTDPT_FALSE; - - /* TODO: incorporate a mask in the scanned tracks table for the rejecting track reason */ - if (matchTrackType(track)) { - if (ptlow < track.pt() and track.pt() < ptup and etalow < track.eta() and track.eta() < etaup) { - if (((track.charge() > 0) and (trackonecharge > 0)) or ((track.charge() < 0) and (trackonecharge < 0))) { - asone = DPTDPT_TRUE; - } - if (((track.charge() > 0) and (tracktwocharge > 0)) or ((track.charge() < 0) and (tracktwocharge < 0))) { - astwo = DPTDPT_TRUE; - } - } - } -} - -/// \brief Returns the potentially phi origin shifted phi -/// \param phi the track azimuthal angle -/// \return the track phi origin shifted azimuthal angle -inline float GetShiftedPhi(float phi) -{ - if (not(phi < phiup)) { - return phi - TMath::TwoPi(); - } else { - return phi; - } -} - -/// \brief Returns the zero based bin index of the eta phi passed track -/// \param t the intended track -/// \return the zero based bin index -/// -/// According to the bining structure, to the track eta will correspond -/// a zero based bin index and similarlly for the track phi -/// The returned index is the composition of both considering eta as -/// the first index component -/// WARNING: for performance reasons no checks are done about the consistency -/// of track's eta and phin with the corresponding ranges so, it is suppossed -/// the track has been accepted and it is within that ranges -/// IF THAT IS NOT THE CASE THE ROUTINE WILL PRODUCE NONSENSE RESULTS -inline int GetEtaPhiIndex(aod::FilteredTrackData const& t) -{ - int etaix = int((t.eta() - etalow) / etabinwidth); - /* consider a potential phi origin shift */ - float phi = GetShiftedPhi(t.phi()); - int phiix = int((phi - philow) / phibinwidth); - return etaix * phibins + phiix; -} -} /* end namespace dptdptcorrelations */ - -// Task for <dpt,dpt> correlations analysis -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that - -using namespace dptdptcorrelations; - -struct DptDptCorrelationsFilterAnalysisTask { - - Configurable<int> cfgTrackType{"trktype", 1, "Type of selected tracks: 0 = no selection, 1 = global tracks FB96"}; - Configurable<int> cfgTrackOneCharge{"trk1charge", -1, "Trakc one charge: 1 = positive, -1 = negative"}; - Configurable<int> cfgTrackTwoCharge{"trk2charge", -1, "Trakc two charge: 1 = positive, -1 = negative"}; - Configurable<bool> cfgProcessPairs{"processpairs", true, "Process pairs: false = no, just singles, true = yes, process pairs"}; - Configurable<std::string> cfgCentMultEstimator{"centmultestimator", "V0M", "Centrality/multiplicity estimator detector: default V0M"}; - - Configurable<o2::analysis::DptDptBinningCuts> cfgBinning{"binning", - {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, - "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - - OutputObj<TList> fOutput{"DptDptCorrelationsGlobalInfo", OutputObjHandlingPolicy::AnalysisObject}; - - Produces<aod::AcceptedEvents> acceptedevents; - Produces<aod::ScannedTracks> scannedtracks; - - void init(InitContext const&) - { - using namespace filteranalyistask; - - /* update with the configurable values */ - /* the binning */ - ptbins = cfgBinning->mPTbins; - ptlow = cfgBinning->mPTmin; - ptup = cfgBinning->mPTmax; - etabins = cfgBinning->mEtabins; - etalow = cfgBinning->mEtamin; - etaup = cfgBinning->mEtamax; - zvtxbins = cfgBinning->mZVtxbins; - zvtxlow = cfgBinning->mZVtxmin; - zvtxup = cfgBinning->mZVtxmax; - /* the track types and combinations */ - tracktype = cfgTrackType.value; - trackonecharge = cfgTrackOneCharge.value; - tracktwocharge = cfgTrackTwoCharge.value; - /* the centrality/multiplicity estimation */ - if (cfgCentMultEstimator->compare("V0M") == 0) { - fCentMultEstimator = kV0M; - } else { - LOGF(FATAL, "Centrality/Multiplicity estimator %s not supported yet", cfgCentMultEstimator->c_str()); - } - - /* if the system type is not known at this time, we have to put the initalization somewhere else */ - fSystem = getSystemType(); - - /* create the output list which will own the task histograms */ - TList* fOutputList = new TList(); - fOutputList->SetOwner(true); - fOutput.setObject(fOutputList); - - /* incorporate configuration parameters to the output */ - fOutputList->Add(new TParameter<Int_t>("TrackType", cfgTrackType, 'f')); - fOutputList->Add(new TParameter<Int_t>("TrackOneCharge", cfgTrackOneCharge, 'f')); - fOutputList->Add(new TParameter<Int_t>("TrackTwoCharge", cfgTrackTwoCharge, 'f')); - - /* create the histograms */ - if (fSystem > kPbp) { - fhCentMultB = new TH1F("CentralityB", "Centrality before cut; centrality (%)", 100, 0, 100); - fhCentMultA = new TH1F("CentralityA", "Centrality; centrality (%)", 100, 0, 100); - } else { - /* for pp, pPb and Pbp systems use multiplicity instead */ - fhCentMultB = new TH1F("MultiplicityB", "Multiplicity before cut; multiplicity (%)", 100, 0, 100); - fhCentMultA = new TH1F("MultiplicityA", "Multiplicity; multiplicity (%)", 100, 0, 100); - } - - fhVertexZB = new TH1F("VertexZB", "Vertex Z; z_{vtx}", 60, -15, 15); - fhVertexZA = new TH1F("VertexZA", "Vertex Z; z_{vtx}", zvtxbins, zvtxlow, zvtxup); - - fhPtB = new TH1F("fHistPtB", "p_{T} distribution for reconstructed before;p_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); - fhPtA = new TH1F("fHistPtA", "p_{T} distribution for reconstructed;p_{T} (GeV/c);dN/dP_{T} (c/GeV)", ptbins, ptlow, ptup); - fhPtPosB = new TH1F("fHistPtPosB", "P_{T} distribution for reconstructed (#{+}) before;P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); - fhPtPosA = new TH1F("fHistPtPosA", "P_{T} distribution for reconstructed (#{+});P_{T} (GeV/c);dN/dP_{T} (c/GeV)", ptbins, ptlow, ptup); - fhPtNegB = new TH1F("fHistPtNegB", "P_{T} distribution for reconstructed (#{-}) before;P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); - fhPtNegA = new TH1F("fHistPtNegA", "P_{T} distribution for reconstructed (#{-});P_{T} (GeV/c);dN/dP_{T} (c/GeV)", ptbins, ptlow, ptup); - fhEtaB = new TH1F("fHistEtaB", "#eta distribution for reconstructed before;#eta;counts", 40, -2.0, 2.0); - fhEtaA = new TH1F("fHistEtaA", "#eta distribution for reconstructed;#eta;counts", etabins, etalow, etaup); - fhPhiB = new TH1F("fHistPhiB", "#phi distribution for reconstructed before;#phi;counts", 360, 0.0, 2 * M_PI); - fhPhiA = new TH1F("fHistPhiA", "#phi distribution for reconstructed;#phi;counts", 360, 0.0, 2 * M_PI); - fhEtaVsPhiB = new TH2F(TString::Format("CSTaskEtaVsPhiB_%s", fTaskConfigurationString.c_str()), "#eta vs #phi before;#phi;#eta", 360, 0.0, 2 * M_PI, 100, -2.0, 2.0); - fhEtaVsPhiA = new TH2F(TString::Format("CSTaskEtaVsPhiA_%s", fTaskConfigurationString.c_str()), "#eta vs #phi;#phi;#eta", 360, 0.0, 2 * M_PI, etabins, etalow, etaup); - fhPtVsEtaB = new TH2F(TString::Format("fhPtVsEtaB_%s", fTaskConfigurationString.c_str()), "p_{T} vs #eta before;#eta;p_{T} (GeV/c)", etabins, etalow, etaup, 100, 0.0, 15.0); - fhPtVsEtaA = new TH2F(TString::Format("fhPtVsEtaA_%s", fTaskConfigurationString.c_str()), "p_{T} vs #eta;#eta;p_{T} (GeV/c)", etabins, etalow, etaup, ptbins, ptlow, ptup); - - /* add the hstograms to the output list */ - fOutputList->Add(fhCentMultB); - fOutputList->Add(fhCentMultA); - fOutputList->Add(fhVertexZB); - fOutputList->Add(fhVertexZA); - fOutputList->Add(fhPtB); - fOutputList->Add(fhPtA); - fOutputList->Add(fhPtPosB); - fOutputList->Add(fhPtPosA); - fOutputList->Add(fhPtNegB); - fOutputList->Add(fhPtNegA); - fOutputList->Add(fhEtaB); - fOutputList->Add(fhEtaA); - fOutputList->Add(fhPhiB); - fOutputList->Add(fhPhiA); - fOutputList->Add(fhEtaVsPhiB); - fOutputList->Add(fhEtaVsPhiA); - fOutputList->Add(fhPtVsEtaB); - fOutputList->Add(fhPtVsEtaA); - } - - void process(aod::CollisionEvSelCent const& collision, soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra, aod::TracksExtended, aod::TrackSelection> const& ftracks) - { - using namespace filteranalyistask; - - // LOGF(INFO,"New collision with %d filtered tracks", ftracks.size()); - fhCentMultB->Fill(collision.centV0M()); - fhVertexZB->Fill(collision.posZ()); - int acceptedevent = DPTDPT_FALSE; - float centormult = -100.0; - if (IsEvtSelected(collision, centormult)) { - acceptedevent = DPTDPT_TRUE; - fhCentMultA->Fill(collision.centV0M()); - fhVertexZA->Fill(collision.posZ()); - // LOGF(INFO,"New accepted collision with %d filtered tracks", ftracks.size()); - - for (auto& track : ftracks) { - /* before track selection */ - fhPtB->Fill(track.pt()); - fhEtaB->Fill(track.eta()); - fhPhiB->Fill(track.phi()); - fhEtaVsPhiB->Fill(track.phi(), track.eta()); - fhPtVsEtaB->Fill(track.eta(), track.pt()); - if (track.charge() > 0) { - fhPtPosB->Fill(track.pt()); - } else { - fhPtNegB->Fill(track.pt()); - } - - /* track selection */ - /* tricky because the boolean columns issue */ - uint8_t asone, astwo; - AcceptTrack(track, asone, astwo); - if ((asone == DPTDPT_TRUE) or (astwo == DPTDPT_TRUE)) { - /* the track has been accepted */ - fhPtA->Fill(track.pt()); - fhEtaA->Fill(track.eta()); - fhPhiA->Fill(track.phi()); - fhEtaVsPhiA->Fill(track.phi(), track.eta()); - fhPtVsEtaA->Fill(track.eta(), track.pt()); - if (track.charge() > 0) { - fhPtPosA->Fill(track.pt()); - } else { - fhPtNegA->Fill(track.pt()); - } - } - scannedtracks(asone, astwo); - } - } else { - for (auto& track : ftracks) { - scannedtracks(DPTDPT_FALSE, DPTDPT_FALSE); - } - } - acceptedevents(acceptedevent, centormult); - } -}; - -// Task for building <dpt,dpt> correlations -struct DptDptCorrelationsTask { - /* the data memebers for this task */ - /* the centrality / multiplicity limits for collecting data in this task instance */ - float fCentMultMin; - float fCentMultMax; - - Configurable<bool> cfgProcessPairs{"processpairs", false, "Process pairs: false = no, just singles, true = yes, process pairs"}; - - Configurable<o2::analysis::DptDptBinningCuts> cfgBinning{"binning", - {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, - "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}; - - OutputObj<TList> fOutput{"DptDptCorrelationsData", OutputObjHandlingPolicy::AnalysisObject}; - - Filter onlyacceptedevents = (aod::dptdptcorrelations::eventaccepted == DPTDPT_TRUE); - Filter onlyacceptedtracks = ((aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE) or (aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE)); - - Partition<aod::FilteredTracks> Tracks1 = aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE; - Partition<aod::FilteredTracks> Tracks2 = aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE; - - DptDptCorrelationsTask(float cmmin, - float cmmax, - Configurable<bool> _cfgProcessPairs = {"processpairs", false, "Process pairs: false = no, just singles, true = yes, process pairs"}, - Configurable<o2::analysis::DptDptBinningCuts> _cfgBinning = {"binning", - {28, -7.0, 7.0, 18, 0.2, 2.0, 16, -0.8, 0.8, 72, 0.5}, - "triplets - nbins, min, max - for z_vtx, pT, eta and phi, binning plus bin fraction of phi origin shift"}, - OutputObj<TList> _fOutput = {"DptDptCorrelationsData", OutputObjHandlingPolicy::AnalysisObject}, - Filter _onlyacceptedevents = (aod::dptdptcorrelations::eventaccepted == DPTDPT_TRUE), - Filter _onlyacceptedtracks = ((aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE) or (aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE)), - Partition<aod::FilteredTracks> _Tracks1 = aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE, - Partition<aod::FilteredTracks> _Tracks2 = aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE) - : fCentMultMin(cmmin), - fCentMultMax(cmmax), - cfgProcessPairs(_cfgProcessPairs), - cfgBinning(_cfgBinning), - fOutput(_fOutput), - onlyacceptedevents((aod::dptdptcorrelations::eventaccepted == DPTDPT_TRUE) and (aod::dptdptcorrelations::centmult > fCentMultMin) and (aod::dptdptcorrelations::centmult < fCentMultMax)), - onlyacceptedtracks((aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE) or (aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE)), - Tracks1(aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE), - Tracks2(aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE) - { - } - - void init(InitContext const&) - { - using namespace correlationstask; - - /* update with the configurable values */ - ptbins = cfgBinning->mPTbins; - ptlow = cfgBinning->mPTmin; - ptup = cfgBinning->mPTmax; - etabins = cfgBinning->mEtabins; - etalow = cfgBinning->mEtamin; - etaup = cfgBinning->mEtamax; - zvtxbins = cfgBinning->mZVtxbins; - zvtxlow = cfgBinning->mZVtxmin; - zvtxup = cfgBinning->mZVtxmax; - phibins = cfgBinning->mPhibins; - philow = 0.0f; - phiup = TMath::TwoPi(); - phibinshift = cfgBinning->mPhibinshift; - processpairs = cfgProcessPairs.value; - /* update the potential binning change */ - etabinwidth = (etaup - etalow) / float(etabins); - phibinwidth = (phiup - philow) / float(phibins); - - /* create the output list which will own the task histograms */ - TList* fOutputList = new TList(); - fOutputList->SetOwner(true); - fOutput.setObject(fOutputList); - - /* incorporate configuration parameters to the output */ - fOutputList->Add(new TParameter<Int_t>("NoBinsVertexZ", zvtxbins, 'f')); - fOutputList->Add(new TParameter<Int_t>("NoBinsPt", ptbins, 'f')); - fOutputList->Add(new TParameter<Int_t>("NoBinsEta", etabins, 'f')); - fOutputList->Add(new TParameter<Int_t>("NoBinsPhi", phibins, 'f')); - fOutputList->Add(new TParameter<Double_t>("MinVertexZ", zvtxlow, 'f')); - fOutputList->Add(new TParameter<Double_t>("MaxVertexZ", zvtxup, 'f')); - fOutputList->Add(new TParameter<Double_t>("MinPt", ptlow, 'f')); - fOutputList->Add(new TParameter<Double_t>("MaxPt", ptup, 'f')); - fOutputList->Add(new TParameter<Double_t>("MinEta", etalow, 'f')); - fOutputList->Add(new TParameter<Double_t>("MaxEta", etaup, 'f')); - fOutputList->Add(new TParameter<Double_t>("MinPhi", philow, 'f')); - fOutputList->Add(new TParameter<Double_t>("MaxPhi", phiup, 'f')); - fOutputList->Add(new TParameter<Double_t>("PhiBinShift", phibinshift, 'f')); - - /* after the parameters dump the proper phi limits are set according to the phi shift */ - phiup = phiup - phibinwidth * phibinshift; - philow = philow - phibinwidth * phibinshift; - - /* create the histograms */ - Bool_t oldstatus = TH1::AddDirectoryStatus(); - TH1::AddDirectory(kFALSE); - - if (!processpairs) { - fhN1_1_vsPt = new TH1F("n1_1_vsPt", "#LT n_{1} #GT;p_{t,1} (GeV/c);#LT n_{1} #GT", ptbins, ptlow, ptup); - fhN1_2_vsPt = new TH1F("n1_2_vsPt", "#LT n_{1} #GT;p_{t,2} (GeV/c);#LT n_{1} #GT", ptbins, ptlow, ptup); - /* we don't want the Sumw2 structure being created here */ - bool defSumw2 = TH1::GetDefaultSumw2(); - TH1::SetDefaultSumw2(false); - fhN1_1_vsZEtaPhiPt = new TH3F("n1_1_vsZ_vsEtaPhi_vsPt", "#LT n_{1} #GT;vtx_{z};#eta_{1}#times#varphi_{1};p_{t,1} (GeV/c)", - zvtxbins, zvtxlow, zvtxup, etabins * phibins, 0.0, double(etabins * phibins), ptbins, ptlow, ptup); - - fhN1_2_vsZEtaPhiPt = new TH3F("n1_2_vsZ_vsEtaPhi_vsPt", "#LT n_{2} #GT;vtx_{z};#eta_{2}#times#varphi_{2};p_{t,2} (GeV/c)", - zvtxbins, zvtxlow, zvtxup, etabins * phibins, 0.0, double(etabins * phibins), ptbins, ptlow, ptup); - /* we return it back to previuos state */ - TH1::SetDefaultSumw2(defSumw2); - - /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ - fhN1_1_vsZEtaPhiPt->SetBit(TH1::kIsNotW); - fhN1_1_vsZEtaPhiPt->Sumw2(false); - fhN1_2_vsZEtaPhiPt->SetBit(TH1::kIsNotW); - fhN1_2_vsZEtaPhiPt->Sumw2(false); - - fOutputList->Add(fhN1_1_vsPt); - fOutputList->Add(fhN1_1_vsZEtaPhiPt); - fOutputList->Add(fhN1_2_vsPt); - fOutputList->Add(fhN1_2_vsZEtaPhiPt); - } else { - fhN1_1_vsEtaPhi = new TH2F("n1_1_vsEtaPhi", "#LT n_{1} #GT;#eta_{1};#varphi_{1} (radian);#LT n_{1} #GT", - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_1_vsEtaPhi = new TH2F("sumPt_1_vsEtaPhi", "#LT #Sigma p_{t,1} #GT;#eta_{1};#varphi_{1} (radian);#LT #Sigma p_{t,1} #GT (GeV/c)", - etabins, etalow, etaup, phibins, philow, phiup); - fhN1_1_vsC = new TProfile("n1_1_vsM", "#LT n_{1} #GT (weighted);Centrality (%);#LT n_{1} #GT", 100, 0.0, 100.0); - fhSum1Pt_1_vsC = new TProfile("sumPt_1_vsM", "#LT #Sigma p_{t,1} #GT (weighted);Centrality (%);#LT #Sigma p_{t,1} #GT (GeV/c)", 100, 0.0, 100.0); - fhN1nw_1_vsC = new TProfile("n1Nw_1_vsM", "#LT n_{1} #GT;Centrality (%);#LT n_{1} #GT", 100, 0.0, 100.0); - fhSum1Ptnw_1_vsC = new TProfile("sumPtNw_1_vsM", "#LT #Sigma p_{t,1} #GT;Centrality (%);#LT #Sigma p_{t,1} #GT (GeV/c)", 100, 0.0, 100.0); - - fhN1_2_vsEtaPhi = new TH2F("n1_2_vsEtaPhi", "#LT n_{1} #GT;#eta_{2};#varphi_{2} (radian);#LT n_{1} #GT", - etabins, etalow, etaup, phibins, philow, phiup); - fhSum1Pt_2_vsEtaPhi = new TH2F("sumPt_2_vsEtaPhi", "#LT #Sigma p_{t,2} #GT;#eta_{2};#varphi_{2} (radian);#LT #Sigma p_{t,2} #GT (GeV/c)", - etabins, etalow, etaup, phibins, philow, phiup); - fhN1_2_vsC = new TProfile("n1_2_vsM", "#LT n_{1} #GT (weighted);Centrality (%);#LT n_{1} #GT", 100, 0.0, 100.0); - fhSum1Pt_2_vsC = new TProfile("sumPt_2_vsM", "#LT #Sigma p_{t,1} #GT (weighted);Centrality (%);#LT #Sigma p_{t,1} #GT (GeV/c)", 100, 0.0, 100.0); - fhN1nw_2_vsC = new TProfile("n1Nw_2_vsM", "#LT n_{1} #GT;Centrality (%);#LT n_{1} #GT", 100, 0.0, 100.0); - fhSum1Ptnw_2_vsC = new TProfile("sumPtNw_2_vsM", "#LT #Sigma p_{t,1} #GT;Centrality (%);#LT #Sigma p_{t,1} #GT (GeV/c)", 100, 0.0, 100.0); - - /* we don't want the Sumw2 structure being created here */ - bool defSumw2 = TH1::GetDefaultSumw2(); - TH1::SetDefaultSumw2(false); - fhN2_12_vsEtaPhi = new TH1F("n2_12_vsEtaPhi", "#LT n_{2} #GT;#eta_{1}#times#varphi_{1}#times#eta_{2}#times#varphi_{2};#LT n_{2} #GT", - etabins * phibins * etabins * phibins, 0., double(etabins * phibins * etabins * phibins)); - fhSum2PtPt_12_vsEtaPhi = new TH1F("sumPtPt_12_vsEtaPhi", "#LT #Sigma p_{t,1}p_{t,2} #GT;#eta_{1}#times#varphi_{1}#times#eta_{2}#times#varphi_{2};#LT #Sigma p_{t,1}p_{t,2} #GT (GeV)^{2}", - etabins * phibins * etabins * phibins, 0., double(etabins * phibins * etabins * phibins)); - fhSum2PtN_12_vsEtaPhi = new TH1F("sumPtN_12_vsEtaPhi", "#LT #Sigma p_{t,1}N #GT;#eta_{1}#times#varphi_{1}#times#eta_{2}#times#varphi_{2};#LT #Sigma p_{t,1}N #GT (GeV)", - etabins * phibins * etabins * phibins, 0., double(etabins * phibins * etabins * phibins)); - fhSum2NPt_12_vsEtaPhi = new TH1F("sumNPt_12_vsEtaPhi", "#LT N#Sigma p_{t,2} #GT;#eta_{1}#times#varphi_{1}#times#eta_{2}#times#varphi_{2};#LT N#Sigma p_{t,2} #GT (GeV)", - etabins * phibins * etabins * phibins, 0., double(etabins * phibins * etabins * phibins)); - /* we return it back to previuos state */ - TH1::SetDefaultSumw2(defSumw2); - - fhN2_12_vsPtPt = new TH2F("n2_12_vsPtVsPt", "#LT n_{2} #GT;p_{t,1} (GeV/c);p_{t,2} (GeV/c);#LT n_{2} #GT", - ptbins, ptlow, ptup, ptbins, ptlow, ptup); - fhN2_12_vsC = new TProfile("n2_12_vsM", "#LT n_{2} #GT (weighted);Centrality (%);#LT n_{2} #GT", 100, 0.0, 100.0); - fhSum2PtPt_12_vsC = new TProfile("sumPtPt_12_vsM", "#LT #Sigma p_{t,1}p_{t,2} #GT (weighted);Centrality (%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV)^{2}", 100, 0.0, 100.0); - fhSum2PtN_12_vsC = new TProfile("sumPtN_12_vsM", "#LT #Sigma p_{t,1}N #GT (weighted);Centrality (%);#LT #Sigma p_{t,1}N #GT (GeV)", 100, 0.0, 100.0); - fhSum2NPt_12_vsC = new TProfile("sumNPt_12_vsM", "#LT N#Sigma p_{t,2} #GT (weighted);Centrality (%);#LT N#Sigma p_{t,2} #GT (GeV)", 100, 0.0, 100.0); - fhN2nw_12_vsC = new TProfile("n2Nw_12_vsM", "#LT n_{2} #GT;Centrality (%);#LT n_{2} #GT", 100, 0.0, 100.0); - fhSum2PtPtnw_12_vsC = new TProfile("sumPtPtNw_12_vsM", "#LT #Sigma p_{t,1}p_{t,2} #GT;Centrality (%);#LT #Sigma p_{t,1}p_{t,2} #GT (GeV)^{2}", 100, 0.0, 100.0); - fhSum2PtNnw_12_vsC = new TProfile("sumPtNNw_12_vsM", "#LT #Sigma p_{t,1}N #GT;Centrality (%);#LT #Sigma p_{t,1}N #GT (GeV)", 100, 0.0, 100.0); - fhSum2NPtnw_12_vsC = new TProfile("sumNPtNw_12_vsM", "#LT N#Sigma p_{t,2} #GT;Centrality (%);#LT N#Sigma p_{t,2} #GT (GeV)", 100, 0.0, 100.0); - - /* the statistical uncertainties will be estimated by the subsamples method so let's get rid of the error tracking */ - fhN2_12_vsEtaPhi->SetBit(TH1::kIsNotW); - fhN2_12_vsEtaPhi->Sumw2(false); - fhSum2PtPt_12_vsEtaPhi->SetBit(TH1::kIsNotW); - fhSum2PtPt_12_vsEtaPhi->Sumw2(false); - fhSum2PtN_12_vsEtaPhi->SetBit(TH1::kIsNotW); - fhSum2PtN_12_vsEtaPhi->Sumw2(false); - fhSum2NPt_12_vsEtaPhi->SetBit(TH1::kIsNotW); - fhSum2NPt_12_vsEtaPhi->Sumw2(false); - - fOutputList->Add(fhN1_1_vsEtaPhi); - fOutputList->Add(fhSum1Pt_1_vsEtaPhi); - fOutputList->Add(fhN1_1_vsC); - fOutputList->Add(fhSum1Pt_1_vsC); - fOutputList->Add(fhN1nw_1_vsC); - fOutputList->Add(fhSum1Ptnw_1_vsC); - fOutputList->Add(fhN1_2_vsEtaPhi); - fOutputList->Add(fhSum1Pt_2_vsEtaPhi); - fOutputList->Add(fhN1_2_vsC); - fOutputList->Add(fhSum1Pt_2_vsC); - fOutputList->Add(fhN1nw_2_vsC); - fOutputList->Add(fhSum1Ptnw_2_vsC); - - fOutputList->Add(fhN2_12_vsEtaPhi); - fOutputList->Add(fhSum2PtPt_12_vsEtaPhi); - fOutputList->Add(fhSum2PtN_12_vsEtaPhi); - fOutputList->Add(fhSum2NPt_12_vsEtaPhi); - fOutputList->Add(fhN2_12_vsPtPt); - fOutputList->Add(fhN2_12_vsC); - fOutputList->Add(fhSum2PtPt_12_vsC); - fOutputList->Add(fhSum2PtN_12_vsC); - fOutputList->Add(fhSum2NPt_12_vsC); - fOutputList->Add(fhN2nw_12_vsC); - fOutputList->Add(fhSum2PtPtnw_12_vsC); - fOutputList->Add(fhSum2PtNnw_12_vsC); - fOutputList->Add(fhSum2NPtnw_12_vsC); - } - - TH1::AddDirectory(oldstatus); - } - - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::Cents, aod::AcceptedEvents>>::iterator const& collision, - aod::FilteredTracks const& tracks) - { - using namespace correlationstask; - - if (not processpairs) { - /* process single tracks */ - for (auto& track1 : Tracks1) { - double corr = 1.0; /* TODO: track correction weights */ - fhN1_1_vsPt->Fill(track1.pt(), corr); - fhN1_1_vsZEtaPhiPt->Fill(collision.posZ(), GetEtaPhiIndex(track1) + 0.5, track1.pt(), corr); - } - for (auto& track2 : Tracks2) { - double corr = 1.0; /* TODO: track correction weights */ - fhN1_2_vsPt->Fill(track2.pt(), corr); - fhN1_2_vsZEtaPhiPt->Fill(collision.posZ(), GetEtaPhiIndex(track2) + 0.5, track2.pt(), corr); - } - } else { - { - /* process track one magnitudes */ - double n1_1 = 0; ///< weighted number of track 1 tracks for current collision - double sum1Pt_1 = 0; ///< accumulated sum of weighted track 1 \f$p_T\f$ for current collision - double n1nw_1 = 0; ///< not weighted number of track 1 tracks for current collision - double sum1Ptnw_1 = 0; ///< accumulated sum of not weighted track 1 \f$p_T\f$ for current collision - for (auto& track1 : Tracks1) { - double corr = 1.0; /* TODO: track correction weights */ - n1_1 += corr; - sum1Pt_1 += track1.pt() * corr; - n1nw_1 += 1; - sum1Ptnw_1 += track1.pt(); - - fhN1_1_vsEtaPhi->Fill(track1.eta(), GetShiftedPhi(track1.phi()), corr); - fhSum1Pt_1_vsEtaPhi->Fill(track1.eta(), GetShiftedPhi(track1.phi()), track1.pt() * corr); - } - /* TODO: the centrality should be chosen non detector dependent */ - fhN1_1_vsC->Fill(collision.centmult(), n1_1); - fhSum1Pt_1_vsC->Fill(collision.centmult(), sum1Pt_1); - fhN1nw_1_vsC->Fill(collision.centmult(), n1nw_1); - fhSum1Ptnw_1_vsC->Fill(collision.centmult(), sum1Ptnw_1); - } - { - /* process track two magnitudes */ - double n1_2 = 0; ///< weighted number of track 2 tracks for current collisiont - double sum1Pt_2 = 0; ///< accumulated sum of weighted track 2 \f$p_T\f$ for current collision - double n1nw_2 = 0; ///< not weighted number of track 2 tracks for current collision - double sum1Ptnw_2 = 0; ///< accumulated sum of not weighted track 2 \f$p_T\f$ for current collision - for (auto& track2 : Tracks2) { - double corr = 1.0; /* TODO: track correction weights */ - n1_2 += corr; - sum1Pt_2 += track2.pt() * corr; - n1nw_2 += 1; - sum1Ptnw_2 += track2.pt(); - - fhN1_2_vsEtaPhi->Fill(track2.eta(), GetShiftedPhi(track2.phi()), corr); - fhSum1Pt_2_vsEtaPhi->Fill(track2.eta(), GetShiftedPhi(track2.phi()), track2.pt() * corr); - } - /* TODO: the centrality should be chosen non detector dependent */ - fhN1_2_vsC->Fill(collision.centmult(), n1_2); - fhSum1Pt_2_vsC->Fill(collision.centmult(), sum1Pt_2); - fhN1nw_2_vsC->Fill(collision.centmult(), n1nw_2); - fhSum1Ptnw_2_vsC->Fill(collision.centmult(), sum1Ptnw_2); - } - /* process pairs of tracks */ - // this will be desireable - // for (auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(Tracks1, Tracks2))) { - /* process pair magnitudes */ - double n2_12 = 0; ///< weighted number of track 1 track 2 pairs for current collision - double sum2PtPt_12 = 0; ///< accumulated sum of weighted track 1 track 2 \f${p_T}_1 {p_T}_2\f$ for current collision - double sum2NPt_12 = 0; ///< accumulated sum of weighted number of track 1 tracks times weighted track 2 \f$p_T\f$ for current collision - double sum2PtN_12 = 0; ///< accumulated sum of weighted track 1 \f$p_T\f$ times weighted number of track 2 tracks for current collision - double n2nw_12 = 0; ///< not weighted number of track1 track 2 pairs for current collision - double sum2PtPtnw_12 = 0; ///< accumulated sum of not weighted track 1 track 2 \f${p_T}_1 {p_T}_2\f$ for current collision - double sum2NPtnw_12 = 0; ///< accumulated sum of not weighted number of track 1 tracks times not weighted track 2 \f$p_T\f$ for current collision - double sum2PtNnw_12 = 0; ///< accumulated sum of not weighted track 1 \f$p_T\f$ times not weighted number of track tracks for current collision - for (auto& track1 : Tracks1) { - for (auto& track2 : Tracks2) { - /* checkiing the same track id condition */ - if (track1.index() == track2.index()) { - /* exclude autocorrelations */ - } else { - /* process pair magnitudes */ - double corr1 = 1.0; /* TODO: track correction weights */ - double corr2 = 1.0; /* TODO: track correction weights */ - double corr = corr1 * corr2; - n2_12 += corr; - sum2PtPt_12 += track1.pt() * track2.pt() * corr; - sum2NPt_12 += corr * track2.pt(); - sum2PtN_12 += track1.pt() * corr; - n2nw_12 += 1; - sum2PtPtnw_12 += track1.pt() * track2.pt(); - sum2NPtnw_12 += track2.pt(); - sum2PtNnw_12 += track1.pt(); - /* we already know the bin in the flattened histograms, let's use it to update them */ - fhN2_12_vsEtaPhi->AddBinContent(GetEtaPhiIndex(track1) * etabins * phibins + GetEtaPhiIndex(track2) + 1, corr); - fhSum2NPt_12_vsEtaPhi->AddBinContent(GetEtaPhiIndex(track1) * etabins * phibins + GetEtaPhiIndex(track2) + 1, corr * track2.pt()); - fhSum2PtN_12_vsEtaPhi->AddBinContent(GetEtaPhiIndex(track1) * etabins * phibins + GetEtaPhiIndex(track2) + 1, track1.pt() * corr); - fhSum2PtPt_12_vsEtaPhi->AddBinContent(GetEtaPhiIndex(track1) * etabins * phibins + GetEtaPhiIndex(track2) + 1, track1.pt() * track2.pt() * corr); - fhN2_12_vsPtPt->Fill(track1.pt(), track2.pt(), corr); - } - } - } - fhN2_12_vsC->Fill(collision.centmult(), n2_12); - fhSum2PtPt_12_vsC->Fill(collision.centmult(), sum2PtPt_12); - fhSum2PtN_12_vsC->Fill(collision.centmult(), sum2PtN_12); - fhSum2NPt_12_vsC->Fill(collision.centmult(), sum2NPt_12); - fhN2nw_12_vsC->Fill(collision.centmult(), n2nw_12); - fhSum2PtPtnw_12_vsC->Fill(collision.centmult(), sum2PtPtnw_12); - fhSum2PtNnw_12_vsC->Fill(collision.centmult(), sum2PtNnw_12); - fhSum2NPtnw_12_vsC->Fill(collision.centmult(), sum2NPtnw_12); - /* let's also update the number of entries in the flattened histograms */ - fhN2_12_vsEtaPhi->SetEntries(fhN2_12_vsEtaPhi->GetEntries() + n2nw_12); - fhSum2NPt_12_vsEtaPhi->SetEntries(fhSum2NPt_12_vsEtaPhi->GetEntries() + n2nw_12); - fhSum2PtN_12_vsEtaPhi->SetEntries(fhSum2PtN_12_vsEtaPhi->GetEntries() + n2nw_12); - fhSum2PtPt_12_vsEtaPhi->SetEntries(fhSum2PtPt_12_vsEtaPhi->GetEntries() + n2nw_12); - } - } -}; - -// Task for building <dpt,dpt> correlations -struct TracksAndEventClassificationQA { - - Configurable<o2::analysis::SimpleInclusiveCut> cfg{"mycfg", {"mycfg", 3, 2.0f}, "A Configurable Object, default mycfg.x=3, mycfg.y=2.0"}; - - OutputObj<TH1F> fTracksOne{TH1F("TracksOne", "Tracks as track one;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksTwo{TH1F("TracksTwo", "Tracks as track two;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksOneAndTwo{TH1F("TracksOneAndTwo", "Tracks as track one and as track two;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksNone{TH1F("TracksNone", "Not selected tracks;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksOneUnsel{TH1F("TracksOneUnsel", "Tracks as track one;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksTwoUnsel{TH1F("TracksTwoUnsel", "Tracks as track two;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksOneAndTwoUnsel{TH1F("TracksOneAndTwoUnsel", "Tracks as track one and as track two;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fTracksNoneUnsel{TH1F("TracksNoneUnsel", "Not selected tracks;number of tracks;events", 1500, 0.0, 1500.0)}; - OutputObj<TH1F> fSelectedEvents{TH1F("SelectedEvents", "Selected events;;events", 2, 0.0, 2.0)}; - - void init(InitContext const&) - { - fSelectedEvents->GetXaxis()->SetBinLabel(1, "Not selected events"); - fSelectedEvents->GetXaxis()->SetBinLabel(2, "Selected events"); - } - - Filter onlyacceptedevents = (aod::dptdptcorrelations::eventaccepted == DPTDPT_TRUE); - Filter onlyacceptedtracks = ((aod::dptdptcorrelations::trackacceptedasone == DPTDPT_TRUE) or (aod::dptdptcorrelations::trackacceptedastwo == DPTDPT_TRUE)); - - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::Cents, aod::AcceptedEvents>>::iterator const& collision, - soa::Filtered<soa::Join<aod::Tracks, aod::ScannedTracks>> const& tracks) - { - if (collision.eventaccepted() != DPTDPT_TRUE) { - fSelectedEvents->Fill(0.5); - } else { - fSelectedEvents->Fill(1.5); - } - - int ntracks_one = 0; - int ntracks_two = 0; - int ntracks_one_and_two = 0; - int ntracks_none = 0; - for (auto& track : tracks) { - if ((track.trackacceptedasone() != DPTDPT_TRUE) and (track.trackacceptedastwo() != DPTDPT_TRUE)) { - ntracks_none++; - } - if ((track.trackacceptedasone() == DPTDPT_TRUE) and (track.trackacceptedastwo() == DPTDPT_TRUE)) { - ntracks_one_and_two++; - } - if (track.trackacceptedasone() == DPTDPT_TRUE) { - ntracks_one++; - } - if (track.trackacceptedastwo() == DPTDPT_TRUE) { - ntracks_two++; - } - } - if (collision.eventaccepted() != DPTDPT_TRUE) { - /* control for non selected events */ - fTracksOneUnsel->Fill(ntracks_one); - fTracksTwoUnsel->Fill(ntracks_two); - fTracksNoneUnsel->Fill(ntracks_none); - fTracksOneAndTwoUnsel->Fill(ntracks_one_and_two); - } else { - fTracksOne->Fill(ntracks_one); - fTracksTwo->Fill(ntracks_two); - fTracksNone->Fill(ntracks_none); - fTracksOneAndTwo->Fill(ntracks_one_and_two); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::string myoptcentralities = cfgc.options().get<std::string>("centralities"); - TObjArray* tokens = TString(myoptcentralities.c_str()).Tokenize(","); - int nranges = tokens->GetEntries(); - - WorkflowSpec workflow{ - adaptAnalysisTask<DptDptCorrelationsFilterAnalysisTask>("DptDptCorrelationsFilterAnalysisTask"), - adaptAnalysisTask<TracksAndEventClassificationQA>("TracksAndEventClassificationQA")}; - for (int i = 0; i < nranges; ++i) { - float cmmin = 0.0f; - float cmmax = 0.0f; - sscanf(tokens->At(i)->GetName(), "%f-%f", &cmmin, &cmmax); - workflow.push_back(adaptAnalysisTask<DptDptCorrelationsTask>(Form("DptDptCorrelationsTask-%s", tokens->At(i)->GetName()), cmmin, cmmax)); - } - delete tokens; - return workflow; -} diff --git a/Analysis/Tasks/PWGCF/filterCF.cxx b/Analysis/Tasks/PWGCF/filterCF.cxx deleted file mode 100644 index 05ef5f3860c83..0000000000000 --- a/Analysis/Tasks/PWGCF/filterCF.cxx +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" - -#include "Analysis/CFDerived.h" -#include "Analysis/EventSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/Centrality.h" - -#include <TH3F.h> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP}; - -struct FilterCF { - - // Configuration - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - - // Filters and input definitions - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex && aod::cent::centV0M <= 80.0f; - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt) && ((aod::track::isGlobalTrack == true) || (aod::track::isGlobalTrackSDD == true)); - - OutputObj<TH3F> yields{TH3F("yields", "centrality vs pT vs eta", 100, 0, 100, 40, 0, 20, 100, -2, 2)}; - OutputObj<TH3F> etaphi{TH3F("etaphi", "centrality vs eta vs phi", 100, 0, 100, 100, -2, 2, 200, 0, 2 * M_PI)}; - - Produces<aod::CFCollisions> outputCollisions; - Produces<aod::CFTracks> outputTracks; - - void init(o2::framework::InitContext&) - { - } - - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::Cents>>::iterator const& collision, aod::BCs const&, soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection>> const& tracks) - { - LOGF(info, "Tracks for collision: %d | Vertex: %.1f | INT7: %d | V0M: %.1f", tracks.size(), collision.posZ(), collision.sel7(), collision.centV0M()); - - if (!collision.sel7()) { - return; - } - - outputCollisions(collision.bc().runNumber(), collision.posZ(), collision.centV0M()); - - for (auto& track : tracks) { - uint8_t trackType = 0; - if (track.isGlobalTrack()) { - trackType = 1; - } else if (track.isGlobalTrackSDD()) { - trackType = 2; - } - - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.charge(), trackType); - - yields->Fill(collision.centV0M(), track.pt(), track.eta()); - etaphi->Fill(collision.centV0M(), track.eta(), track.phi()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<FilterCF>("filter-cf")}; -} diff --git a/Analysis/Tasks/PWGDQ/CMakeLists.txt b/Analysis/Tasks/PWGDQ/CMakeLists.txt deleted file mode 100644 index 866d28ff3c8f1..0000000000000 --- a/Analysis/Tasks/PWGDQ/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -o2_add_dpl_workflow(table-maker - SOURCES tableMaker.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(table-reader - SOURCES tableReader.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(dilepton-ee - SOURCES dileptonEE.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(dilepton-mumu - SOURCES dileptonMuMu.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(table-maker-pp - SOURCES tableMaker_pp.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore - COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGDQ/dileptonEE.cxx b/Analysis/Tasks/PWGDQ/dileptonEE.cxx deleted file mode 100644 index eaeb00d4575c0..0000000000000 --- a/Analysis/Tasks/PWGDQ/dileptonEE.cxx +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/ReducedInfoTables.h" -#include "Analysis/VarManager.h" -#include "Analysis/HistogramManager.h" -#include "Analysis/AnalysisCut.h" -#include "Analysis/AnalysisCompositeCut.h" -#include <TH1F.h> -#include <TMath.h> -#include <THashList.h> -#include <TString.h> -#include <iostream> - -using std::cout; -using std::endl; - -using namespace o2; -using namespace o2::framework; -//using namespace o2::framework::expressions; -using namespace o2::aod; - -// Some definitions -namespace o2::aod -{ -namespace reducedtrack -{ -DECLARE_SOA_COLUMN(IsBarrelSelected, isBarrelSelected, int); -} // namespace reducedtrack -namespace reducedpair -{ -DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); -} // namespace reducedpair - -DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "BARRELTRACKCUTS", reducedtrack::IsBarrelSelected); -} // namespace o2::aod - -using MyEvent = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended>::iterator; -using MyEventVtxCov = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::ReducedEventsVtxCov>::iterator; -using MyBarrelTracks = soa::Join<aod::ReducedTracks, aod::ReducedTracksBarrel, aod::ReducedTracksBarrelCov, aod::ReducedTracksBarrelPID>; -using MyBarrelTracksSelected = soa::Join<aod::ReducedTracks, aod::ReducedTracksBarrel, aod::ReducedTracksBarrelCov, aod::ReducedTracksBarrelPID, aod::BarrelTrackCuts>; - -void DefineHistograms(o2::framework::OutputObj<HistogramManager> histMan, TString histClasses); - -// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions -// a constexpr static bit map must be defined and sent as template argument -// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes -// Additionally, one should make sure that the requested tables are actually provided in the process() function, -// otherwise a compile time error will be thrown. -// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible -// to automatically detect the object types transmitted to the VarManager -constexpr static uint32_t fgEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; -constexpr static uint32_t fgTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; - -struct BarrelTrackSelection { - Produces<aod::BarrelTrackCuts> trackSel; - OutputObj<HistogramManager> fHistMan{"output"}; - AnalysisCompositeCut* fTrackCut; - - float* fValues; // array to be used by the VarManager - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - - DefineCuts(); - } - - void DefineCuts() - { - fTrackCut = new AnalysisCompositeCut(true); // true: use AND - AnalysisCut* cut1 = new AnalysisCut(); - cut1->AddCut(VarManager::kPt, 0.2, 10.0); - cut1->AddCut(VarManager::kEta, -0.8, 0.8); - cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); - cut1->AddCut(VarManager::kITSchi2, 0.0, 5.0); - cut1->AddCut(VarManager::kITSncls, 3.5, 7.5); - cut1->AddCut(VarManager::kTPCncls, 69.5, 159.5); - cut1->AddCut(VarManager::kTrackDCAxy, -1.0, +1.0); - cut1->AddCut(VarManager::kTrackDCAz, -3.0, +3.0); - - cut1->AddCut(VarManager::kTPCsignal, 70, 90, false); //exclude = false - cut1->AddCut(VarManager::kTPCsignal, 75, 90, false, VarManager::kPin, 2.0, 1e+10); //exclude = false - //cut1->AddCut(VarManager::kTOFnSigmaEl, -3, +3, false); //exclude = false - //fTrackCut->AddCut(cut1); - - AnalysisCompositeCut* pidcut = new AnalysisCompositeCut(false); // false : use OR - AnalysisCut* pidcut_high = new AnalysisCut("pidcut_high", "e high"); - pidcut_high->AddCut(VarManager::kTPCsignal, 75, 90, false, VarManager::kPin, 2.0, 1e+10, false); //exclude = false - pidcut_high->AddCut(VarManager::kTPCsignal, 70, 90, false); //exclude = false - - AnalysisCut* pidcut_rejPr = new AnalysisCut("pidcut_rejPr", "proton rejection"); - TF1* f1minPr = new TF1("f1minPr", "[0]+[1]*x", 0, 10); - f1minPr->SetParameters(170, -100); - TF1* f1maxPr = new TF1("f1maxPr", "[0]+[1]*x", 0, 10); - f1maxPr->SetParameters(175, -75); - pidcut_rejPr->AddCut(VarManager::kTPCsignal, f1minPr, f1maxPr, true, VarManager::kPin, 0.8, 1.4, false); //exclude = false - - AnalysisCut* pidcut_rejKa = new AnalysisCut("pidcut_rejKa", "kaon rejection"); - TF1* f1minKa = new TF1("f1minKa", "[0]+[1]*x", 0, 10); - f1minKa->SetParameters(220, -300); - TF1* f1maxKa = new TF1("f1maxKa", "[0]+[1]*x", 0, 10); - f1maxKa->SetParameters(182.5, -150); - pidcut_rejKa->AddCut(VarManager::kTPCsignal, f1minKa, f1maxKa, true, VarManager::kPin, 0.4, 0.8, false); //exclude = false - - AnalysisCut* pidcut_rejPi = new AnalysisCut("pidcut_rejPi", "pion rejection"); - TF1* f1maxPi = new TF1("f1maxPi", "[0]+[1]*x", 0, 10); - f1maxPi->SetParameters(85, -50); - pidcut_rejPi->AddCut(VarManager::kTPCsignal, 70, f1maxPi, true, VarManager::kPin, 0.0, 0.4, false); //exclude = false - - cut1->AddCut(VarManager::kTPCsignal, f1minPr, f1maxPr, true, VarManager::kPin, 0.8, 1.4, false); //exclude = false - cut1->AddCut(VarManager::kTPCsignal, f1minKa, f1maxKa, true, VarManager::kPin, 0.4, 0.8, false); //exclude = false - cut1->AddCut(VarManager::kTPCsignal, 70, f1maxPi, true, VarManager::kPin, 0.0, 0.4, false); //exclude = false - - //pidcut->AddCut(pidcut_high); - //pidcut->AddCut(pidcut_rejPr); - //pidcut->AddCut(pidcut_rejKa); - //pidcut->AddCut(pidcut_rejPi); - //fTrackCut->AddCut(pidcut); - - fTrackCut->AddCut(cut1); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEvent event, MyBarrelTracks const& tracks) - { - for (int i = 0; i < VarManager::kNVars; ++i) { - fValues[i] = -9999.0f; - } - // fill event information which might be needed in histograms that combine track and event properties - VarManager::FillEvent<fgEventFillMap>(event, fValues); - - for (auto& track : tracks) { - for (int i = VarManager::kNEventWiseVariables; i < VarManager::kNMuonTrackVariables; ++i) { - fValues[i] = -9999.0f; - } - VarManager::FillTrack<fgTrackFillMap>(track, fValues); - fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); - - if (fTrackCut->IsSelected(fValues) && - (track.flags() & (uint64_t(1) << 2)) && // kITSrefit - (track.flags() & (uint64_t(1) << 6)) && // kTPCrefit - ((track.itsClusterMap() & (uint8_t(1) << 0))) // SPD first - ) { - trackSel(1); - fHistMan->FillHistClass("TrackBarrel_AfterCuts", fValues); - } else { - trackSel(0); - } - } - } -}; - -struct DileptonEE { - OutputObj<HistogramManager> fHistMan{"output"}; - AnalysisCompositeCut* fEventCut; - //NOTE: one could define also a dilepton cut, but for now basic selections can be supported using Partition - - Partition<MyBarrelTracksSelected> posTracks = aod::reducedtrack::charge > 0 && aod::reducedtrack::isBarrelSelected == 1; - Partition<MyBarrelTracksSelected> negTracks = aod::reducedtrack::charge < 0 && aod::reducedtrack::isBarrelSelected == 1; - - void init(o2::framework::InitContext&) - { - VarManager::SetDefaultVarNames(); - fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;PairsBarrelULS;PairsBarrelLSpp;PairsBarrelLSnn;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - - DefineCuts(); - } - - void DefineCuts() - { - fEventCut = new AnalysisCompositeCut(true); - - AnalysisCut* varCut = new AnalysisCut(); - varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - varCut->AddCut(VarManager::kVtxNcontrib, 0.5, 1e+10); - fEventCut->AddCut(varCut); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEventVtxCov event, MyBarrelTracksSelected const& tracks) - { - // Reset the VarManager::fgValues array - // The reset can be done selectively, using arguments in the ResetValues() function - VarManager::ResetValues(); - - VarManager::FillEvent<fgEventFillMap>(event); - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event - if (!fEventCut->IsSelected(VarManager::fgValues)) { - return; - } - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); - - // Run the same event pairing for barrel tracks - // TODO: Use combinations() when this will work for Partitions - /* e.g. - * for (auto& [tpos, tneg] : combinations(posTracks, negTracks)) { - VarManager::FillPair(tpos, tneg); - fHistMan->FillHistClass("PairsBarrelULS", VarManager::fgValues); - } - */ - - for (auto tpos : posTracks) { - for (auto tneg : negTracks) { // +- pairs - VarManager::FillPair(tpos, tneg); - fHistMan->FillHistClass("PairsBarrelULS", VarManager::fgValues); - } - for (auto tpos2 = tpos + 1; tpos2 != posTracks.end(); ++tpos2) { // ++ pairs - VarManager::FillPair(tpos, tpos2); - fHistMan->FillHistClass("PairsBarrelLSpp", VarManager::fgValues); - } - } - for (auto tneg : negTracks) { // -- pairs - for (auto tneg2 = tneg + 1; tneg2 != negTracks.end(); ++tneg2) { - VarManager::FillPair(tneg, tneg2); - fHistMan->FillHistClass("PairsBarrelLSnn", VarManager::fgValues); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<BarrelTrackSelection>("barrel-track-selection"), - adaptAnalysisTask<DileptonEE>("dilepton-ee")}; -} - -void DefineHistograms(o2::framework::OutputObj<HistogramManager> histMan, TString histClasses) -{ - // - // Define here the histograms for all the classes required in analysis. - // The histogram classes are provided in the histClasses string, separated by semicolon ";" - // The histogram classes and their components histograms are defined below depending on the name of the histogram class - // - const int kNRuns = 2; - int runs[kNRuns] = {244918, 244919}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) { - runsStr += Form("%d;", runs[i]); - } - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, - kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram - histMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram - histMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram - histMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, - 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, - "", "", "", VarManager::kVtxNcontrib); // TProfile3D - - double vtxXbinLims[10] = {0.055, 0.06, 0.062, 0.064, 0.066, 0.068, 0.070, 0.072, 0.074, 0.08}; - double vtxYbinLims[7] = {0.31, 0.32, 0.325, 0.33, 0.335, 0.34, 0.35}; - double vtxZbinLims[13] = {-15.0, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 15.0}; - double nContribbinLims[9] = {0.0, 100.0, 200.0, 400.0, 600.0, 1000.0, 1500.0, 2000.0, 4000.0}; - - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_nonEqualBinning", "Vtx X vs Vtx Y", false, 9, vtxXbinLims, VarManager::kVtxX, 6, vtxYbinLims, VarManager::kVtxY); // THnF histogram with custom non-equal binning - - histMan->AddHistogram(classStr.Data(), "VtxZ_weights", "Vtx Z", false, - 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, 10, 0., 0., VarManager::kNothing, - "", "", "", VarManager::kNothing, VarManager::kVtxNcontrib); // TH1F histogram, filled with weights using the vtx n-contributors - - Int_t vars[4] = {VarManager::kVtxX, VarManager::kVtxY, VarManager::kVtxZ, VarManager::kVtxNcontrib}; - TArrayD binLimits[4]; - binLimits[0] = TArrayD(10, vtxXbinLims); - binLimits[1] = TArrayD(7, vtxYbinLims); - binLimits[2] = TArrayD(13, vtxZbinLims); - binLimits[3] = TArrayD(9, nContribbinLims); - histMan->AddHistogram(classStr.Data(), "vtxHisto", "n contrib vs (x,y,z)", 4, vars, binLimits); - - histMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram - - histMan->AddHistogram(classStr.Data(), "VtxChi2", "Vtx chi2", false, 100, 0.0, 100.0, VarManager::kVtxChi2); // TH1F histogram - - continue; - } // end if(Event) - - if (classStr.Contains("Track")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 100, 0.0, 10.0, VarManager::kPt); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 200, -1.0, 1.0, VarManager::kEta); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -1.0, 1.0, VarManager::kEta, 72, 0, TMath::TwoPi(), VarManager::kPhi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "P", "p distribution", false, 200, 0.0, 20.0, VarManager::kP); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); - histMan->AddHistogram(classStr.Data(), "Py", "p_{y} distribution", false, 200, 0.0, 20.0, VarManager::kPy); - histMan->AddHistogram(classStr.Data(), "Pz", "p_{z} distribution", false, 400, -20.0, 20.0, VarManager::kPz); - histMan->AddHistogram(classStr.Data(), "DCAxy_DCAz", "DCA_{xy} vs DCA_{z}", false, 100, -5.0, 5.0, VarManager::kTrackDCAxy, 100, -5.0, 5.0, VarManager::kTrackDCAz); // TH2F histogram - - if (classStr.Contains("Barrel")) { - histMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram - //for TPC PID - histMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 1000, 0.0, 10.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_pIN", "TPC dE/dx n#sigma_{e} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_Eta", "TPC dE/dx n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_pIN", "TPC dE/dx n#sigma_{#pi} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_Eta", "TPC dE/dx n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_pIN", "TPC dE/dx n#sigma_{K} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_Eta", "TPC dE/dx n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_pIN", "TPC dE/dx n#sigma_{p} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_Eta", "TPC dE/dx n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram - - //for TOF PID - histMan->AddHistogram(classStr.Data(), "TOFbeta_pIN", "TOF #beta vs pIN", false, 1000, 0.0, 10.0, VarManager::kPin, 120, 0.0, 1.2, VarManager::kTOFbeta); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_pIN", "TOF #beta n#sigma_{e} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_Eta", "TOF #beta n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_pIN", "TOF #beta n#sigma_{#pi} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_Eta", "TOF #beta n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_pIN", "TOF #beta n#sigma_{K} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_Eta", "TOF #beta n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_pIN", "TOF #beta n#sigma_{p} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_Eta", "TOF #beta n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram - - histMan->AddHistogram(classStr.Data(), "Cov1Pt_Pt", "cov(1/pt,1/pt) vs p_{T} distribution", false, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, 1.0, VarManager::kTrackC1Pt21Pt2); // TH2F histogram - } - } - - if (classStr.Contains("Pairs")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 200, 0.0, 20.0, VarManager::kPt); - } - - } // end loop over histogram classes -} diff --git a/Analysis/Tasks/PWGDQ/dileptonMuMu.cxx b/Analysis/Tasks/PWGDQ/dileptonMuMu.cxx deleted file mode 100644 index 07e0865fa411e..0000000000000 --- a/Analysis/Tasks/PWGDQ/dileptonMuMu.cxx +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/ReducedInfoTables.h" -#include "Analysis/VarManager.h" -#include "Analysis/HistogramManager.h" -#include "Analysis/AnalysisCut.h" -#include "Analysis/AnalysisCompositeCut.h" -#include <TH1F.h> -#include <TMath.h> -#include <THashList.h> -#include <TString.h> -#include <iostream> -#include <vector> - -using std::cout; -using std::endl; - -using namespace o2; -using namespace o2::framework; -//using namespace o2::framework::expressions; -using namespace o2::aod; - -// Some definitions -namespace o2::aod -{ - -namespace reducedevent -{ -DECLARE_SOA_COLUMN(Category, category, int); -DECLARE_SOA_COLUMN(IsEventSelected, isEventSelected, int); -} // namespace reducedevent - -namespace reducedtrack -{ -DECLARE_SOA_COLUMN(IsMuonSelected, isMuonSelected, int); -} // namespace reducedtrack -namespace reducedpair -{ -DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Rap, rap, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); -} // namespace reducedpair - -DECLARE_SOA_TABLE(EventCuts, "AOD", "EVENTCUTS", reducedevent::IsEventSelected); -DECLARE_SOA_TABLE(EventCategories, "AOD", "EVENTCATEGORIES", reducedevent::Category); -DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "MUONTRACKCUTS", reducedtrack::IsMuonSelected); -} // namespace o2::aod - -using MyEvents = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended>; -using MyEventsSelected = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::EventCuts>; -using MyEventsVtxCov = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::ReducedEventsVtxCov>; -using MyEventsVtxCovSelected = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::ReducedEventsVtxCov, aod::EventCuts>; -using MyMuonTracks = soa::Join<aod::ReducedMuons, aod::ReducedMuonsExtended>; -using MyMuonTracksSelected = soa::Join<aod::ReducedMuons, aod::ReducedMuonsExtended, aod::MuonTrackCuts>; - -void DefineHistograms(HistogramManager* histMan, TString histClasses); - -// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions -// a constexpr static bit map must be defined and sent as template argument -// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes -// Additionally, one should make sure that the requested tables are actually provided in the process() function, -// otherwise a compile time error will be thrown. -// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible -// to automatically detect the object types transmitted to the VarManager -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; -constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackMuon; - -struct EventSelection { - Produces<aod::EventCuts> eventSel; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fEventCut; - - float* fValues; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - - DefineCuts(); - } - - void DefineCuts() - { - fEventCut = new AnalysisCompositeCut(true); - - AnalysisCut* varCut = new AnalysisCut(); - varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - varCut->AddCut(VarManager::kIsMuonSingleLowPt7, 0.5, 1.5); - - fEventCut->AddCut(varCut); - // TODO: Add more cuts, also enable cuts which are not easily possible via the VarManager (e.g. trigger selections) - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEvents::iterator const& event) - { - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNEventWiseVariables, fValues); - - VarManager::FillEvent<gkEventFillMap>(event, fValues); - fHistMan->FillHistClass("Event_BeforeCuts", fValues); // automatically fill all the histograms in the class Event - if (fEventCut->IsSelected(fValues)) { - fHistMan->FillHistClass("Event_AfterCuts", fValues); - eventSel(1); - } else { - eventSel(0); - } - } -}; - -struct MuonTrackSelection { - Produces<aod::MuonTrackCuts> trackSel; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fMuonCut23; - AnalysisCompositeCut* fMuonCut310; - - float* fValues; // array to be used by the VarManager - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "TrackMuon_BeforeCuts;TrackMuon_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); // provide the list of required variables so that VarManager knows what to fill - - DefineCuts(); - } - - void DefineCuts() - { - fMuonCut23 = new AnalysisCompositeCut(true); - AnalysisCut kineMuonCut23; - kineMuonCut23.AddCut(VarManager::kPt, 1.0, 20); - kineMuonCut23.AddCut(VarManager::kEta, -4.0, -2.5); - kineMuonCut23.AddCut(VarManager::kMuonChi2, 0.0, 1e6); - // The value of sigma_PDCA depends on the postion w.r.t the absorber. For 17.6 < RAbs < 26.5cm, sigma_PDCA = 99 cmxGeV/c. For 26.5 < RAbs < 89.5 cm, sigma_PDCA = 54 - // temporarily not applied - // kineMuonCut23.AddCut(VarManager::kMuonRAtAbsorberEnd, 17.6, 26.5); - // kineMuonCut23.AddCut(VarManager::kMuonPDca, 0.0, 594); // Cut is pDCA < 6*sigma_PDCA - fMuonCut23->AddCut(&kineMuonCut23); - - fMuonCut310 = new AnalysisCompositeCut(true); - AnalysisCut kineMuonCut310; - kineMuonCut310.AddCut(VarManager::kPt, 1.0, 20); - kineMuonCut310.AddCut(VarManager::kEta, -4.0, -2.5); - kineMuonCut310.AddCut(VarManager::kMuonChi2, 0.0, 1e6); - // The value of sigma_PDCA depends on the postion w.r.t the absorber. For 17.6 < RAbs < 26.5cm, sigma_PDCA = 99 cmxGeV/c. For 26.5 < RAbs < 89.5 cm, sigma_PDCA = 54 - // temporarily not applied - // kineMuonCut310.AddCut(VarManager::kMuonRAtAbsorberEnd, 26.5, 89.5); - // kineMuonCut310.AddCut(VarManager::kMuonPDca, 0.0, 324); // Cut is pDCA < 6*sigma_PDCA - fMuonCut310->AddCut(&kineMuonCut310); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEventsSelected::iterator const& event, MyMuonTracks const& muons) - { - VarManager::ResetValues(0, VarManager::kNMuonTrackVariables, fValues); - VarManager::FillEvent<gkEventFillMap>(event, fValues); - - for (auto& muon : muons) { - //VarManager::ResetValues(VarManager::kNBarrelTrackVariables, VarManager::kNMuonTrackVariables, fValues); - VarManager::FillTrack<gkMuonFillMap>(muon, fValues); - fHistMan->FillHistClass("TrackMuon_BeforeCuts", fValues); - - if (fMuonCut23->IsSelected(fValues)) { - trackSel(1); - fHistMan->FillHistClass("TrackMuon_AfterCuts", fValues); - } else if (fMuonCut310->IsSelected(fValues)) { - trackSel(1); - fHistMan->FillHistClass("TrackMuon_AfterCuts", fValues); - } else { - trackSel(0); - } - } - } -}; - -struct DileptonMuMu { - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fDiMuonCut; - //NOTE: one could define also a dilepton cut, but for now basic selections can be supported using Partition - // NOTE TO THE NOTE: a dimuon cut is needed on the rapidity of the pair. So I added one. Hopefully this works - - float* fValues; - - Partition<MyMuonTracksSelected> posMuons = aod::reducedtrack::charge > 0 && aod::reducedtrack::isMuonSelected == 1; - Partition<MyMuonTracksSelected> negMuons = aod::reducedtrack::charge < 0 && aod::reducedtrack::isMuonSelected == 1; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "PairsMuonULS;PairsMuonLSpp;PairsMuonLSnn;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - - DefineCuts(); - } - - void DefineCuts() - { - fDiMuonCut = new AnalysisCompositeCut(true); - AnalysisCut* diMuonCut = new AnalysisCut(); - diMuonCut->AddCut(VarManager::kRap, 2.5, 4.0); - fDiMuonCut->AddCut(diMuonCut); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEventsVtxCovSelected::iterator const& event, MyMuonTracksSelected const& tracks) - { - if (!event.isEventSelected()) { - return; - } - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNVars, fValues); - - VarManager::FillEvent<gkEventFillMap>(event, fValues); - - // same event pairing for muons - for (auto& tpos : posMuons) { - for (auto& tneg : negMuons) { - //dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], 1); - VarManager::FillPair(tpos, tneg); - if (!fDiMuonCut->IsSelected(VarManager::fgValues)) { - return; - } - fHistMan->FillHistClass("PairsMuonULS", VarManager::fgValues); - } - for (auto tpos2 = tpos + 1; tpos2 != posMuons.end(); ++tpos2) { // ++ pairs - VarManager::FillPair(tpos, tpos2); - if (!fDiMuonCut->IsSelected(VarManager::fgValues)) { - return; - } - fHistMan->FillHistClass("PairsMuonLSpp", VarManager::fgValues); - } - } - for (auto tneg : negMuons) { // -- pairs - for (auto tneg2 = tneg + 1; tneg2 != negMuons.end(); ++tneg2) { - VarManager::FillPair(tneg, tneg2); - if (!fDiMuonCut->IsSelected(VarManager::fgValues)) { - return; - } - fHistMan->FillHistClass("PairsMuonLSnn", VarManager::fgValues); - } - } - } -}; - -void DefineHistograms(HistogramManager* histMan, TString histClasses) -{ - // - // Define here the histograms for all the classes required in analysis. - // The histogram classes are provided in the histClasses string, separated by semicolon ";" - // The histogram classes and their components histograms are defined below depending on the name of the histogram class - // - const int kNRuns = 2; - int runs[kNRuns] = {244918, 244919}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) { - runsStr += Form("%d;", runs[i]); - } - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, - kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram - histMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram - histMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram - histMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, - 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, - "", "", "", VarManager::kVtxNcontrib); // TProfile3D - - double vtxXbinLims[10] = {0.055, 0.06, 0.062, 0.064, 0.066, 0.068, 0.070, 0.072, 0.074, 0.08}; - double vtxYbinLims[7] = {0.31, 0.32, 0.325, 0.33, 0.335, 0.34, 0.35}; - double vtxZbinLims[13] = {-15.0, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 15.0}; - double nContribbinLims[9] = {0.0, 100.0, 200.0, 400.0, 600.0, 1000.0, 1500.0, 2000.0, 4000.0}; - - histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_nonEqualBinning", "Vtx X vs Vtx Y", false, 9, vtxXbinLims, VarManager::kVtxX, 6, vtxYbinLims, VarManager::kVtxY); // THnF histogram with custom non-equal binning - - histMan->AddHistogram(classStr.Data(), "VtxZ_weights", "Vtx Z", false, - 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, 10, 0., 0., VarManager::kNothing, - "", "", "", VarManager::kNothing, VarManager::kVtxNcontrib); // TH1F histogram, filled with weights using the vtx n-contributors - - Int_t vars[4] = {VarManager::kVtxX, VarManager::kVtxY, VarManager::kVtxZ, VarManager::kVtxNcontrib}; - TArrayD binLimits[4]; - binLimits[0] = TArrayD(10, vtxXbinLims); - binLimits[1] = TArrayD(7, vtxYbinLims); - binLimits[2] = TArrayD(13, vtxZbinLims); - binLimits[3] = TArrayD(9, nContribbinLims); - histMan->AddHistogram(classStr.Data(), "vtxHisto", "n contrib vs (x,y,z)", 4, vars, binLimits); - - histMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram - - histMan->AddHistogram(classStr.Data(), "VtxChi2", "Vtx chi2", false, 100, 0.0, 100.0, VarManager::kVtxChi2); // TH1F histogram - - continue; - } // end if(Event) - - if (classStr.Contains("Track")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 19, -4.2, -2.3, VarManager::kEta); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "P", "p distribution", false, 200, 0.0, 20.0, VarManager::kP); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); - histMan->AddHistogram(classStr.Data(), "Py", "p_{y} distribution", false, 200, 0.0, 20.0, VarManager::kPy); - histMan->AddHistogram(classStr.Data(), "Pz", "p_{z} distribution", false, 400, -20.0, 20.0, VarManager::kPz); - - if (classStr.Contains("Muon")) { - histMan->AddHistogram(classStr.Data(), "InvBendingMom", "", false, 100, 0.0, 1.0, VarManager::kMuonInvBendingMomentum); - histMan->AddHistogram(classStr.Data(), "ThetaX", "", false, 100, -1.0, 1.0, VarManager::kMuonThetaX); - histMan->AddHistogram(classStr.Data(), "ThetaY", "", false, 100, -2.0, 2.0, VarManager::kMuonThetaY); - histMan->AddHistogram(classStr.Data(), "ZMu", "", false, 100, -30.0, 30.0, VarManager::kMuonZMu); - histMan->AddHistogram(classStr.Data(), "BendingCoor", "", false, 100, 0.32, 0.35, VarManager::kMuonBendingCoor); - histMan->AddHistogram(classStr.Data(), "NonBendingCoor", "", false, 100, 0.065, 0.07, VarManager::kMuonNonBendingCoor); - histMan->AddHistogram(classStr.Data(), "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); - histMan->AddHistogram(classStr.Data(), "Chi2MatchTrigger", "", false, 100, 0.0, 20.0, VarManager::kMuonChi2MatchTrigger); - histMan->AddHistogram(classStr.Data(), "RAtAbsorberEnd", "", false, 140, 10, 150, VarManager::kMuonRAtAbsorberEnd); - histMan->AddHistogram(classStr.Data(), "p x dca", "", false, 700, 0.0, 700, VarManager::kMuonRAtAbsorberEnd); - } - } - - if (classStr.Contains("Pairs")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass", "", false, 100, 2.0, 12, VarManager::kMass); - histMan->AddHistogram(classStr.Data(), "Pt", "", false, 200, 0.0, 20.0, VarManager::kPt); - histMan->AddHistogram(classStr.Data(), "Rapidity", "", false, 19, 2.0, 4.3, VarManager::kRap); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "mass vs p_{T} distribution", false, 100, 0.0, 20.0, VarManager::kMass, 200, 0.0, 20.0, VarManager::kPt); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "Mass_Y", "mass vs y distribution", false, 100, 0.0, 20.0, VarManager::kMass, 19, 2.0, 4.3, VarManager::kRap); // TH2F histogram - } - } // end loop over histogram classes -} - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<EventSelection>("my-event-selection"), - adaptAnalysisTask<MuonTrackSelection>("muon-track-selection"), - adaptAnalysisTask<DileptonMuMu>("dilepton-mumu")}; -} diff --git a/Analysis/Tasks/PWGDQ/tableMaker.cxx b/Analysis/Tasks/PWGDQ/tableMaker.cxx deleted file mode 100644 index d65a471e422fb..0000000000000 --- a/Analysis/Tasks/PWGDQ/tableMaker.cxx +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "Analysis/TriggerAliases.h" -#include "Analysis/ReducedInfoTables.h" -#include "Analysis/VarManager.h" -#include "Analysis/HistogramManager.h" -#include "Analysis/AnalysisCut.h" -#include "Analysis/AnalysisCompositeCut.h" -#include "PID/PIDResponse.h" -#include "Analysis/TrackSelectionTables.h" -#include <iostream> - -using std::cout; -using std::endl; - -using namespace o2; -using namespace o2::framework; -//using namespace o2::framework::expressions; -using namespace o2::aod; - -using MyEvents = soa::Join<aod::Collisions, aod::EvSels, aod::Cents>; -using MyBarrelTracks = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksCov, aod::TracksExtended, aod::TrackSelection, aod::pidRespTPC, aod::pidRespTOF, aod::pidRespTOFbeta>; - -// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions -// a constexpr static bit map must be defined and sent as template argument -// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes -// Additionally, one should make sure that the requested tables are actually provided in the process() function, -// otherwise a compile time error will be thrown. -// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible -// to automatically detect the object types transmitted to the VarManager -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; - -struct TableMaker { - - Produces<ReducedEvents> event; - Produces<ReducedEventsExtended> eventExtended; - Produces<ReducedEventsVtxCov> eventVtxCov; - Produces<ReducedTracks> trackBasic; - Produces<ReducedTracksBarrel> trackBarrel; - Produces<ReducedTracksBarrelCov> trackBarrelCov; - Produces<ReducedTracksBarrelPID> trackBarrelPID; - Produces<ReducedMuons> muonBasic; - Produces<ReducedMuonsExtended> muonExtended; - - float* fValues; - - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - - // TODO: Filters should be used to make lowest level selection. The additional more restrictive cuts should be defined via the AnalysisCuts - // TODO: Multiple event selections can be applied and decisions stored in the reducedevent::tag - AnalysisCompositeCut* fEventCut; - // TODO: Multiple track selections can be applied and decisions stored in the reducedtrack::filteringFlags - // Cuts should be defined using Configurables (prepare cut libraries, as discussed in O2 DQ meetings) - AnalysisCompositeCut* fTrackCut; - - // Partition will select fast a group of tracks with basic requirements - // If some of the cuts cannot be included in the Partition expression, add them via AnalysisCut(s) - Partition<MyBarrelTracks> barrelSelectedTracks = o2::aod::track::pt >= 1.0f && nabs(o2::aod::track::eta) <= 0.9f && o2::aod::track::tpcSignal >= 70.0f && o2::aod::track::tpcSignal <= 100.0f && o2::aod::track::tpcChi2NCl < 4.0f && o2::aod::track::itsChi2NCl < 36.0f; - - // TODO a few of the important muon variables in the central data model are dynamic columns so not usable in expressions (e.g. eta, phi) - // Update the data model to have them as expression columns - Partition<aod::Muons> muonSelectedTracks = o2::aod::muon::pt >= 1.0f; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms("Event_BeforeCuts;Event_AfterCuts;TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - DefineCuts(); - } - - void DefineCuts() - { - fEventCut = new AnalysisCompositeCut(true); - AnalysisCut* eventVarCut = new AnalysisCut(); - eventVarCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - eventVarCut->AddCut(VarManager::kIsINT7, 0.5, 1.5); // require kINT7 - fEventCut->AddCut(eventVarCut); - - fTrackCut = new AnalysisCompositeCut(true); - AnalysisCut* trackVarCut = new AnalysisCut(); - //trackVarCut->AddCut(VarManager::kPt, 1.0, 1000.0); - //trackVarCut->AddCut(VarManager::kEta, -0.9, 0.9); - //trackVarCut->AddCut(VarManager::kTPCsignal, 70.0, 100.0); - trackVarCut->AddCut(VarManager::kIsITSrefit, 0.5, 1.5); - trackVarCut->AddCut(VarManager::kIsTPCrefit, 0.5, 1.5); - //trackVarCut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); - //trackVarCut->AddCut(VarManager::kITSchi2, 0.1, 36.0); - trackVarCut->AddCut(VarManager::kTPCncls, 100.0, 161.); - - AnalysisCut* pidCut1 = new AnalysisCut(); - TF1* cutLow1 = new TF1("cutLow1", "pol1", 0., 10.); - cutLow1->SetParameters(130., -40.0); - pidCut1->AddCut(VarManager::kTPCsignal, cutLow1, 100.0, false, VarManager::kPin, 0.5, 3.0); - - fTrackCut->AddCut(trackVarCut); - fTrackCut->AddCut(pidCut1); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEvents::iterator const& collision, aod::MuonClusters const& clustersMuon, aod::Muons const& tracksMuon, aod::BCs const& bcs, MyBarrelTracks const& tracksBarrel) - { - uint64_t tag = 0; - uint32_t triggerAliases = 0; - for (int i = 0; i < kNaliases; i++) { - if (collision.alias()[i] > 0) { - triggerAliases |= (uint32_t(1) << i); - } - } - - VarManager::ResetValues(0, VarManager::kNEventWiseVariables, fValues); - VarManager::FillEvent<gkEventFillMap>(collision, fValues); // extract event information and place it in the fgValues array - fHistMan->FillHistClass("Event_BeforeCuts", fValues); // automatically fill all the histograms in the class Event - - if (!fEventCut->IsSelected(fValues)) { - return; - } - - fHistMan->FillHistClass("Event_AfterCuts", fValues); - - event(tag, collision.bc().runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib()); - eventExtended(collision.bc().globalBC(), collision.bc().triggerMask(), triggerAliases, collision.centV0M()); - eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); - - uint64_t trackFilteringTag = 0; - trackBasic.reserve(barrelSelectedTracks.size()); - trackBarrel.reserve(barrelSelectedTracks.size()); - trackBarrelCov.reserve(barrelSelectedTracks.size()); - trackBarrelPID.reserve(barrelSelectedTracks.size()); - - for (auto& track : barrelSelectedTracks) { - VarManager::FillTrack<gkTrackFillMap>(track, fValues); - fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); - if (!fTrackCut->IsSelected(fValues)) { - continue; - } - fHistMan->FillHistClass("TrackBarrel_AfterCuts", fValues); - - if (track.isGlobalTrack()) { - trackFilteringTag |= (uint64_t(1) << 0); - } - if (track.isGlobalTrackSDD()) { - trackFilteringTag |= (uint64_t(1) << 1); - } - trackBasic(event.lastIndex(), track.globalIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.charge()); - trackBarrel(track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcNClsShared(), track.tpcChi2NCl(), - track.trdChi2(), track.tofChi2(), - track.length(), track.dcaXY(), track.dcaZ()); - trackBarrelCov(track.cYY(), track.cZZ(), track.cSnpSnp(), track.cTglTgl(), track.c1Pt21Pt2()); - trackBarrelPID(track.tpcSignal(), - track.tpcNSigmaEl(), track.tpcNSigmaMu(), - track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.tpcNSigmaDe(), track.tpcNSigmaTr(), track.tpcNSigmaHe(), track.tpcNSigmaAl(), - track.tofSignal(), track.beta(), - track.tofNSigmaEl(), track.tofNSigmaMu(), - track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.tofNSigmaDe(), track.tofNSigmaTr(), track.tofNSigmaHe(), track.tofNSigmaAl(), - track.trdSignal()); - } - - muonBasic.reserve(muonSelectedTracks.size()); - muonExtended.reserve(muonSelectedTracks.size()); - for (auto& muon : muonSelectedTracks) { - // TODO: add proper information for muon tracks - if (muon.bcId() != collision.bcId()) { - continue; - } - // TODO: the trackFilteringTag will not be needed to encode whether the track is a muon since there is a dedicated table for muons - trackFilteringTag |= (uint64_t(1) << 0); // this is a MUON arm track - muonBasic(event.lastIndex(), trackFilteringTag, muon.pt(), muon.eta(), muon.phi(), muon.charge()); - muonExtended(muon.inverseBendingMomentum(), muon.thetaX(), muon.thetaY(), muon.zMu(), muon.bendingCoor(), muon.nonBendingCoor(), muon.chi2(), muon.chi2MatchTrigger()); - } - } - - void DefineHistograms(TString histClasses) - { - const int kNRuns = 2; - int runs[kNRuns] = {244918, 244919}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) { - runsStr += Form("%d;", runs[i]); - } - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, - kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "CentVZERO", "Centrality VZERO", false, 100, 0.0, 100.0, VarManager::kCentVZERO); // TH1F histogram - } - - if (classStr.Contains("Track")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram - - if (classStr.Contains("Barrel")) { - fHistMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCncls_Run", "Number of cluster in TPC", true, kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, - 10, -0.5, 159.5, VarManager::kTPCncls, 10, 0., 1., VarManager::kNothing, runsStr.Data()); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram - //for TPC PID - fHistMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "DCAxy", "DCAxy", false, 100, -3.0, 3.0, VarManager::kTrackDCAxy); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "DCAz", "DCAz", false, 100, -5.0, 5.0, VarManager::kTrackDCAz); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "IsGlobalTrack", "IsGlobalTrack", false, 2, -0.5, 1.5, VarManager::kIsGlobalTrack); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "IsGlobalTrackSDD", "IsGlobalTrackSDD", false, 2, -0.5, 1.5, VarManager::kIsGlobalTrackSDD); // TH1F histogram - } - } - } // end loop over histogram classes - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<TableMaker>("table-maker")}; -} diff --git a/Analysis/Tasks/PWGDQ/tableMaker_pp.cxx b/Analysis/Tasks/PWGDQ/tableMaker_pp.cxx deleted file mode 100644 index e7df44d1ec1d4..0000000000000 --- a/Analysis/Tasks/PWGDQ/tableMaker_pp.cxx +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "Analysis/TriggerAliases.h" -#include "Analysis/ReducedInfoTables.h" -#include "Analysis/VarManager.h" -#include "Analysis/HistogramManager.h" -#include "Analysis/AnalysisCut.h" -#include "Analysis/AnalysisCompositeCut.h" -#include "PID/PIDResponse.h" -#include "Analysis/TrackSelectionTables.h" -#include <iostream> - -using std::cout; -using std::endl; - -using namespace o2; -using namespace o2::framework; -//using namespace o2::framework::expressions; -using namespace o2::aod; - -using MyEvents = soa::Join<aod::Collisions, aod::EvSels>; -using MyBarrelTracks = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksCov, aod::TracksExtended, aod::TrackSelection, aod::pidRespTPC, aod::pidRespTOF, aod::pidRespTOFbeta>; - -// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions -// a constexpr static bit map must be defined and sent as template argument -// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes -// Additionally, one should make sure that the requested tables are actually provided in the process() function, -// otherwise a compile time error will be thrown. -// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible -// to automatically detect the object types transmitted to the VarManager -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; - -struct TableMaker_pp { - - Produces<ReducedEvents> event; - Produces<ReducedEventsExtended> eventExtended; - Produces<ReducedEventsVtxCov> eventVtxCov; - Produces<ReducedTracks> trackBasic; - Produces<ReducedTracksBarrel> trackBarrel; - Produces<ReducedTracksBarrelCov> trackBarrelCov; - Produces<ReducedTracksBarrelPID> trackBarrelPID; - Produces<ReducedMuons> muonBasic; - Produces<ReducedMuonsExtended> muonExtended; - - float* fValues; - - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - - // TODO: Filters should be used to make lowest level selection. The additional more restrictive cuts should be defined via the AnalysisCuts - // TODO: Multiple event selections can be applied and decisions stored in the reducedevent::tag - AnalysisCompositeCut* fEventCut; - // TODO: Multiple track selections can be applied and decisions stored in the reducedtrack::filteringFlags - // Cuts should be defined using Configurables (prepare cut libraries, as discussed in O2 DQ meetings) - AnalysisCompositeCut* fTrackCut; - - // Partition will select fast a group of tracks with basic requirements - // If some of the cuts cannot be included in the Partition expression, add them via AnalysisCut(s) - Partition<MyBarrelTracks> barrelSelectedTracks = o2::aod::track::pt >= 1.0f && nabs(o2::aod::track::eta) <= 0.9f && o2::aod::track::tpcSignal >= 70.0f && o2::aod::track::tpcSignal <= 100.0f && o2::aod::track::tpcChi2NCl < 4.0f && o2::aod::track::itsChi2NCl < 36.0f; - - // TODO a few of the important muon variables in the central data model are dynamic columns so not usable in expressions (e.g. eta, phi) - // Update the data model to have them as expression columns - Partition<aod::Muons> muonSelectedTracks = o2::aod::muon::pt >= 0.5f; // For pp collisions a 0.5 GeV/c pp cuts is defined - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms("Event_BeforeCuts;Event_AfterCuts;TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - DefineCuts(); - } - - void DefineCuts() - { - fEventCut = new AnalysisCompositeCut(true); - AnalysisCut* eventVarCut = new AnalysisCut(); - eventVarCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - eventVarCut->AddCut(VarManager::kIsINT7, 0.5, 1.5); // require kINT7 - fEventCut->AddCut(eventVarCut); - - fTrackCut = new AnalysisCompositeCut(true); - AnalysisCut* trackVarCut = new AnalysisCut(); - //trackVarCut->AddCut(VarManager::kPt, 1.0, 1000.0); - //trackVarCut->AddCut(VarManager::kEta, -0.9, 0.9); - //trackVarCut->AddCut(VarManager::kTPCsignal, 70.0, 100.0); - trackVarCut->AddCut(VarManager::kIsITSrefit, 0.5, 1.5); - trackVarCut->AddCut(VarManager::kIsTPCrefit, 0.5, 1.5); - //trackVarCut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); - //trackVarCut->AddCut(VarManager::kITSchi2, 0.1, 36.0); - trackVarCut->AddCut(VarManager::kTPCncls, 100.0, 161.); - - AnalysisCut* pidCut1 = new AnalysisCut(); - TF1* cutLow1 = new TF1("cutLow1", "pol1", 0., 10.); - cutLow1->SetParameters(130., -40.0); - pidCut1->AddCut(VarManager::kTPCsignal, cutLow1, 100.0, false, VarManager::kPin, 0.5, 3.0); - - fTrackCut->AddCut(trackVarCut); - fTrackCut->AddCut(pidCut1); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEvents::iterator const& collision, aod::MuonClusters const& clustersMuon, aod::Muons const& tracksMuon, aod::BCs const& bcs, MyBarrelTracks const& tracksBarrel) - { - uint64_t tag = 0; - uint32_t triggerAliases = 0; - for (int i = 0; i < kNaliases; i++) { - if (collision.alias()[i] > 0) { - triggerAliases |= (uint32_t(1) << i); - } - } - - VarManager::ResetValues(0, VarManager::kNEventWiseVariables, fValues); - VarManager::FillEvent<gkEventFillMap>(collision, fValues); // extract event information and place it in the fgValues array - fHistMan->FillHistClass("Event_BeforeCuts", fValues); // automatically fill all the histograms in the class Event - - if (!fEventCut->IsSelected(fValues)) { - return; - } - - fHistMan->FillHistClass("Event_AfterCuts", fValues); - - event(tag, collision.bc().runNumber(), collision.posX(), collision.posY(), collision.posZ(), collision.numContrib()); - eventExtended(collision.bc().globalBC(), collision.bc().triggerMask(), triggerAliases, 0.0f); - eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); - - uint64_t trackFilteringTag = 0; - trackBasic.reserve(barrelSelectedTracks.size()); - trackBarrel.reserve(barrelSelectedTracks.size()); - trackBarrelCov.reserve(barrelSelectedTracks.size()); - trackBarrelPID.reserve(barrelSelectedTracks.size()); - - for (auto& track : barrelSelectedTracks) { - VarManager::FillTrack<gkTrackFillMap>(track, fValues); - fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); - if (!fTrackCut->IsSelected(fValues)) { - continue; - } - fHistMan->FillHistClass("TrackBarrel_AfterCuts", fValues); - - if (track.isGlobalTrack()) { - trackFilteringTag |= (uint64_t(1) << 0); - } - if (track.isGlobalTrackSDD()) { - trackFilteringTag |= (uint64_t(1) << 1); - } - trackBasic(event.lastIndex(), track.globalIndex(), trackFilteringTag, track.pt(), track.eta(), track.phi(), track.charge()); - trackBarrel(track.tpcInnerParam(), track.flags(), track.itsClusterMap(), track.itsChi2NCl(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcNClsShared(), track.tpcChi2NCl(), - track.trdChi2(), track.tofChi2(), - track.length(), track.dcaXY(), track.dcaZ()); - trackBarrelCov(track.cYY(), track.cZZ(), track.cSnpSnp(), track.cTglTgl(), track.c1Pt21Pt2()); - trackBarrelPID(track.tpcSignal(), - track.tpcNSigmaEl(), track.tpcNSigmaMu(), - track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.tpcNSigmaDe(), track.tpcNSigmaTr(), track.tpcNSigmaHe(), track.tpcNSigmaAl(), - track.tofSignal(), track.beta(), - track.tofNSigmaEl(), track.tofNSigmaMu(), - track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.tofNSigmaDe(), track.tofNSigmaTr(), track.tofNSigmaHe(), track.tofNSigmaAl(), - track.trdSignal()); - } - - muonBasic.reserve(muonSelectedTracks.size()); - muonExtended.reserve(muonSelectedTracks.size()); - for (auto& muon : muonSelectedTracks) { - // TODO: add proper information for muon tracks - if (muon.bcId() != collision.bcId()) { - continue; - } - // TODO: the trackFilteringTag will not be needed to encode whether the track is a muon since there is a dedicated table for muons - trackFilteringTag |= (uint64_t(1) << 0); // this is a MUON arm track - muonBasic(event.lastIndex(), trackFilteringTag, muon.pt(), muon.eta(), muon.phi(), muon.charge()); - muonExtended(muon.inverseBendingMomentum(), muon.thetaX(), muon.thetaY(), muon.zMu(), muon.bendingCoor(), muon.nonBendingCoor(), muon.chi2(), muon.chi2MatchTrigger()); - } - } - - void DefineHistograms(TString histClasses) - { - const int kNRuns = 2; - int runs[kNRuns] = {244918, 244919}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) { - runsStr += Form("%d;", runs[i]); - } - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, - kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram - fHistMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram - fHistMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram - fHistMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, - 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, - "", "", "", VarManager::kVtxNcontrib); // TProfile3D - } - - if (classStr.Contains("Track")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram - - if (classStr.Contains("Barrel")) { - fHistMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCncls_Run", "Number of cluster in TPC", true, kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, - 10, -0.5, 159.5, VarManager::kTPCncls, 10, 0., 1., VarManager::kNothing, runsStr.Data()); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram - //for TPC PID - fHistMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "DCAxy", "DCAxy", false, 100, -3.0, 3.0, VarManager::kTrackDCAxy); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "DCAz", "DCAz", false, 100, -5.0, 5.0, VarManager::kTrackDCAz); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "IsGlobalTrack", "IsGlobalTrack", false, 2, -0.5, 1.5, VarManager::kIsGlobalTrack); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "IsGlobalTrackSDD", "IsGlobalTrackSDD", false, 2, -0.5, 1.5, VarManager::kIsGlobalTrackSDD); // TH1F histogram - } - } - } // end loop over histogram classes - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<TableMaker_pp>("table-maker-pp")}; -} diff --git a/Analysis/Tasks/PWGDQ/tableReader.cxx b/Analysis/Tasks/PWGDQ/tableReader.cxx deleted file mode 100644 index acd92db6fdea5..0000000000000 --- a/Analysis/Tasks/PWGDQ/tableReader.cxx +++ /dev/null @@ -1,627 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/ReducedInfoTables.h" -#include "Analysis/VarManager.h" -#include "Analysis/HistogramManager.h" -#include "Analysis/AnalysisCut.h" -#include "Analysis/AnalysisCompositeCut.h" -#include <TH1F.h> -#include <TMath.h> -#include <THashList.h> -#include <TString.h> -#include <iostream> -#include <vector> - -using std::cout; -using std::endl; - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::aod; - -// Some definitions -namespace o2::aod -{ - -namespace reducedevent -{ -DECLARE_SOA_COLUMN(Category, category, int); -DECLARE_SOA_COLUMN(IsEventSelected, isEventSelected, int); -} // namespace reducedevent - -namespace reducedtrack -{ -DECLARE_SOA_COLUMN(IsBarrelSelected, isBarrelSelected, uint8_t); -DECLARE_SOA_COLUMN(IsMuonSelected, isMuonSelected, int); -} // namespace reducedtrack - -namespace reducedpair -{ -DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, int); -DECLARE_SOA_COLUMN(FilterMap, filterMap, uint8_t); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); -} // namespace reducedpair - -DECLARE_SOA_TABLE(EventCuts, "AOD", "EVENTCUTS", reducedevent::IsEventSelected); -DECLARE_SOA_TABLE(EventCategories, "AOD", "EVENTCATEGORIES", reducedevent::Category); -DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "BARRELTRACKCUTS", reducedtrack::IsBarrelSelected); -DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "MUONTRACKCUTS", reducedtrack::IsMuonSelected); -DECLARE_SOA_TABLE(Dileptons, "AOD", "DILEPTON", reducedpair::ReducedEventId, reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Charge, reducedpair::FilterMap, - reducedpair::Px<reducedpair::Pt, reducedpair::Phi>, reducedpair::Py<reducedpair::Pt, reducedpair::Phi>, - reducedpair::Pz<reducedpair::Pt, reducedpair::Eta>, reducedpair::Pmom<reducedpair::Pt, reducedpair::Eta>); -using Dilepton = Dileptons::iterator; -} // namespace o2::aod - -using MyEvents = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended>; -using MyEventsSelected = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::EventCuts>; -using MyEventsVtxCov = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::ReducedEventsVtxCov>; -using MyEventsVtxCovSelected = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::ReducedEventsVtxCov, aod::EventCuts>; -using MyBarrelTracks = soa::Join<aod::ReducedTracks, aod::ReducedTracksBarrel, aod::ReducedTracksBarrelCov, aod::ReducedTracksBarrelPID>; -using MyBarrelTracksSelected = soa::Join<aod::ReducedTracks, aod::ReducedTracksBarrel, aod::ReducedTracksBarrelCov, aod::ReducedTracksBarrelPID, aod::BarrelTrackCuts>; -using MyMuonTracks = soa::Join<aod::ReducedMuons, aod::ReducedMuonsExtended>; -using MyMuonTracksSelected = soa::Join<aod::ReducedMuons, aod::ReducedMuonsExtended, aod::MuonTrackCuts>; - -void DefineHistograms(HistogramManager* histMan, TString histClasses); - -// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions -// a constexpr static bit map must be defined and sent as template argument -// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes -// Additionally, one should make sure that the requested tables are actually provided in the process() function, -// otherwise a compile time error will be thrown. -// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible -// to automatically detect the object types transmitted to the VarManager -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; -constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackMuon; - -int gNTrackCuts = 2; - -struct EventSelection { - Produces<aod::EventCuts> eventSel; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fEventCut; - - float* fValues; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - - DefineCuts(); - } - - void DefineCuts() - { - fEventCut = new AnalysisCompositeCut(true); - - AnalysisCut* varCut = new AnalysisCut(); - varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - varCut->AddCut(VarManager::kIsINT7, 0.5, 1.5); - varCut->AddCut(VarManager::kCentVZERO, 0.0, 10.0); - - fEventCut->AddCut(varCut); - // TODO: Add more cuts, also enable cuts which are not easily possible via the VarManager (e.g. trigger selections) - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEvents::iterator const& event) - { - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNEventWiseVariables, fValues); - - VarManager::FillEvent<gkEventFillMap>(event, fValues); - fHistMan->FillHistClass("Event_BeforeCuts", fValues); // automatically fill all the histograms in the class Event - if (fEventCut->IsSelected(fValues)) { - fHistMan->FillHistClass("Event_AfterCuts", fValues); - eventSel(1); - } else { - eventSel(0); - } - } -}; - -struct BarrelTrackSelection { - Produces<aod::BarrelTrackCuts> trackSel; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - std::vector<AnalysisCompositeCut> fTrackCuts; - - float* fValues; // array to be used by the VarManager - - void init(o2::framework::InitContext&) - { - DefineCuts(); - - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - TString cutNames = "TrackBarrel_BeforeCuts;"; - for (int i = 0; i < gNTrackCuts; i++) { - cutNames += Form("TrackBarrel_%s;", fTrackCuts[i].GetName()); - } - - DefineHistograms(fHistMan, cutNames.Data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - void DefineCuts() - { - AnalysisCut* commonCuts = new AnalysisCut(); - commonCuts->AddCut(VarManager::kPt, 1.0, 20.0); - commonCuts->AddCut(VarManager::kTPCsignal, 70.0, 100.0); - commonCuts->AddCut(VarManager::kEta, -0.9, 0.9); - commonCuts->AddCut(VarManager::kIsSPDany, 0.5, 1.5); - commonCuts->AddCut(VarManager::kIsITSrefit, 0.5, 1.5); - commonCuts->AddCut(VarManager::kIsTPCrefit, 0.5, 1.5); - commonCuts->AddCut(VarManager::kTPCchi2, 0.0, 4.0); - commonCuts->AddCut(VarManager::kITSchi2, 0.1, 36.0); - commonCuts->AddCut(VarManager::kTPCncls, 100.0, 161.); - commonCuts->AddCut(VarManager::kTrackDCAxy, -1.0, 1.0); - commonCuts->AddCut(VarManager::kTrackDCAz, -3.0, 3.0); - - AnalysisCut* pidCut1 = new AnalysisCut(); - TF1* cutLow1 = new TF1("cutLow1", "pol1", 0., 10.); - cutLow1->SetParameters(130., -40.0); - pidCut1->AddCut(VarManager::kTPCsignal, cutLow1, 100.0, false, VarManager::kPin, 0.5, 3.0); - - AnalysisCut* pidCut2 = new AnalysisCut(); - pidCut2->AddCut(VarManager::kTPCsignal, 73.0, 100.0); - - AnalysisCompositeCut trackCut1("cut1", "cut1", true); // true: use AND - trackCut1.AddCut(commonCuts); - trackCut1.AddCut(pidCut1); - - AnalysisCompositeCut trackCut2("cut2", "cut2", true); // true: use AND - trackCut2.AddCut(commonCuts); - trackCut2.AddCut(pidCut1); - trackCut2.AddCut(pidCut2); - - fTrackCuts.push_back(trackCut1); - fTrackCuts.push_back(trackCut2); - - //gNTrackCuts = fTrackCuts.size(); - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEventsSelected::iterator const& event, MyBarrelTracks const& tracks) - { - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables, fValues); - // fill event information which might be needed in histograms that combine track and event properties - VarManager::FillEvent<gkEventFillMap>(event, fValues); - - uint8_t filterMap = uint8_t(0); - - trackSel.reserve(tracks.size()); - - for (auto& track : tracks) { - filterMap = uint8_t(0); - VarManager::FillTrack<gkTrackFillMap>(track, fValues); - if (event.isEventSelected()) { - fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); - } - - int i = 0; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { - if ((*cut).IsSelected(fValues)) { - filterMap |= (uint8_t(1) << i); - fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut).GetName()), fValues); - } - } - trackSel(filterMap); - } - } -}; - -struct MuonTrackSelection { - Produces<aod::MuonTrackCuts> trackSel; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fTrackCut; - - float* fValues; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "TrackMuon_BeforeCuts;TrackMuon_AfterCuts;"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - - DefineCuts(); - } - - void DefineCuts() - { - fTrackCut = new AnalysisCompositeCut(true); - AnalysisCut kineMuonCut; - kineMuonCut.AddCut(VarManager::kPt, 1.5, 10.0); - fTrackCut->AddCut(&kineMuonCut); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(MyEventsSelected::iterator const& event, MyMuonTracks const& muons) - { - VarManager::ResetValues(0, VarManager::kNMuonTrackVariables, fValues); - VarManager::FillEvent<gkEventFillMap>(event, fValues); - - for (auto& muon : muons) { - //VarManager::ResetValues(VarManager::kNBarrelTrackVariables, VarManager::kNMuonTrackVariables, fValues); - VarManager::FillTrack<gkMuonFillMap>(muon, fValues); - //if(event.isEventSelected()) - fHistMan->FillHistClass("TrackMuon_BeforeCuts", fValues); - - if (fTrackCut->IsSelected(fValues)) { - trackSel(1); - //if(event.isEventSelected()) - fHistMan->FillHistClass("TrackMuon_AfterCuts", fValues); - } else { - trackSel(0); - } - } - } -}; - -struct TableReader { - Produces<aod::Dileptons> dileptonList; - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - //NOTE: one could define also a dilepton cut, but for now basic selections can be supported using Partition - - float* fValues; - - Partition<MyBarrelTracksSelected> posTracks = aod::reducedtrack::charge > 0 && aod::reducedtrack::isBarrelSelected > uint8_t(0); - Partition<MyBarrelTracksSelected> negTracks = aod::reducedtrack::charge < 0 && aod::reducedtrack::isBarrelSelected > uint8_t(0); - Partition<MyMuonTracksSelected> posMuons = aod::reducedtrack::charge > 0 && aod::reducedtrack::isMuonSelected == 1; - Partition<MyMuonTracksSelected> negMuons = aod::reducedtrack::charge < 0 && aod::reducedtrack::isMuonSelected == 1; - - void init(o2::framework::InitContext&) - { - fValues = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - TString histNames = ""; - for (int i = 0; i < gNTrackCuts; i++) { - histNames += Form("PairsBarrelPM_cut%d;PairsBarrelPP_cut%d;PairsBarrelMM_cut%d;", i + 1, i + 1, i + 1); - } - - DefineHistograms(fHistMan, histNames.Data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - //void process(soa::Filtered<MyEventsVtxCovSelected>::iterator const& event, MyBarrelTracksSelected const& tracks, MyMuonTracksSelected const& muons) - void process(MyEventsVtxCovSelected::iterator const& event, MyBarrelTracksSelected const& tracks, MyMuonTracksSelected const& muons) - { - if (!event.isEventSelected()) { - return; - } - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNVars, fValues); - - VarManager::FillEvent<gkEventFillMap>(event, fValues); - - // Run the same event pairing for barrel tracks - // TODO: Use combinations() when this will work for Partitions - /* e.g. - * for (auto& [tpos, tneg] : combinations(posTracks, negTracks)) { - VarManager::FillPair(tpos, tneg); - fHistMan->FillHistClass("PairsBarrelPM", VarManager::fgValues); - } - */ - uint8_t filter = 0; - for (auto tpos : posTracks) { - for (auto tneg : negTracks) { // +- pairs - filter = tpos.isBarrelSelected() & tneg.isBarrelSelected(); - if (!filter) { // the tracks must have at least one filter bit in common to continue - continue; - } - VarManager::FillPair(tpos, tneg, fValues); - dileptonList(event, fValues[VarManager::kMass], fValues[VarManager::kPt], fValues[VarManager::kEta], fValues[VarManager::kPhi], 0, filter); - for (int i = 0; i < gNTrackCuts; ++i) { - if (filter & (uint8_t(1) << i)) { - fHistMan->FillHistClass(Form("PairsBarrelPM_cut%d", i + 1), fValues); - } - } - } - for (auto tpos2 = tpos + 1; tpos2 != posTracks.end(); ++tpos2) { // ++ pairs - filter = tpos.isBarrelSelected() & tpos2.isBarrelSelected(); - if (!filter) { // the tracks must have at least one filter bit in common to continue - continue; - } - VarManager::FillPair(tpos, tpos2, fValues); - dileptonList(event, fValues[VarManager::kMass], fValues[VarManager::kPt], fValues[VarManager::kEta], fValues[VarManager::kPhi], 2, filter); - for (int i = 0; i < gNTrackCuts; ++i) { - if (filter & (uint8_t(1) << i)) { - fHistMan->FillHistClass(Form("PairsBarrelPP_cut%d", i + 1), fValues); - } - } - } - } - for (auto tneg : negTracks) { // -- pairs - for (auto tneg2 = tneg + 1; tneg2 != negTracks.end(); ++tneg2) { - filter = tneg.isBarrelSelected() & tneg2.isBarrelSelected(); - if (!filter) { // the tracks must have at least one filter bit in common to continue - continue; - } - VarManager::FillPair(tneg, tneg2, fValues); - dileptonList(event, fValues[VarManager::kMass], fValues[VarManager::kPt], fValues[VarManager::kEta], fValues[VarManager::kPhi], -2, filter); - for (int i = 0; i < gNTrackCuts; ++i) { - if (filter & (uint8_t(1) << i)) { - fHistMan->FillHistClass(Form("PairsBarrelMM_cut%d", i + 1), fValues); - } - } - } - } - - // same event pairing for muons - for (auto& tpos : posMuons) { - for (auto& tneg : negMuons) { - //dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], 1); - VarManager::FillPair(tpos, tneg, fValues); - fHistMan->FillHistClass("PairsMuon", fValues); - } - } - } -}; - -struct DileptonHadronAnalysis { - // - // This task combines dilepton candidates with a track and could be used for example - // in analyses with the dilepton as one of the decay products of a higher mass resonance (e.g. B0 -> Jpsi + K) - // or in dilepton + hadron correlations, etc. - // It requires the TableReader task to be in the workflow and produce the dilepton table - // - OutputObj<THashList> fOutputList{"output"}; - HistogramManager* fHistMan; - AnalysisCompositeCut* fHadronCut; // TODO: this cut will be moved into the barrel/muon track selection task - //NOTE: no cut has been included for dileptons because that can be controlled via the TableReader task and the partition below - - // use two values array to avoid mixing up the quantities - float* fValuesDilepton; - float* fValuesHadron; - - Filter eventFilter = aod::reducedevent::isEventSelected == 1; - - Partition<aod::Dileptons> selDileptons = aod::reducedpair::charge == 0 && aod::reducedpair::mass > 2.92f && aod::reducedpair::mass<3.16f && aod::reducedpair::pt> 5.0f; - - constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; - - void init(o2::framework::InitContext&) - { - fValuesDilepton = new float[VarManager::kNVars]; - fValuesHadron = new float[VarManager::kNVars]; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - DefineHistograms(fHistMan, "DileptonsSelected;HadronsSelected;DileptonHadronInvMass;DileptonHadronCorrelation"); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); - fOutputList.setObject(fHistMan->GetMainHistogramList()); - - DefineCuts(); - } - - void DefineCuts() - { - fHadronCut = new AnalysisCompositeCut(true); // true: use AND - AnalysisCut* cut1 = new AnalysisCut(); - cut1->AddCut(VarManager::kPt, 4.0, 20.0); - cut1->AddCut(VarManager::kEta, -0.9, 0.9); - cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); - cut1->AddCut(VarManager::kITSchi2, 0.1, 36.0); - cut1->AddCut(VarManager::kITSncls, 2.5, 7.5); - cut1->AddCut(VarManager::kTPCncls, 69.5, 159.5); - fHadronCut->AddCut(cut1); - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - } - - void process(soa::Filtered<MyEventsVtxCovSelected>::iterator const& event, MyBarrelTracks const& hadrons, aod::Dileptons const& dileptons) - { - VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); - // fill event information which might be needed in histograms that combine track/pair and event properties - VarManager::FillEvent<gkEventFillMap>(event, fValuesHadron); - VarManager::FillEvent<gkEventFillMap>(event, fValuesDilepton); // TODO: check if needed (just for dilepton QA which might be depending on event wise variables) - - // loop once over dileptons for QA purposes - for (auto dilepton : selDileptons) { - VarManager::FillTrack<fgDileptonFillMap>(dilepton, fValuesDilepton); - fHistMan->FillHistClass("DileptonsSelected", fValuesDilepton); - } - - // loop over hadrons - for (auto& hadron : hadrons) { - VarManager::FillTrack<gkTrackFillMap>(hadron, fValuesHadron); - if (!fHadronCut->IsSelected(fValuesHadron)) { // TODO: this will be moved to a partition when the selection will be done in the barrel/muon track selection - continue; - } - - fHistMan->FillHistClass("HadronsSelected", fValuesHadron); - - for (auto dilepton : selDileptons) { - // TODO: At the moment there is no check on whether this hadron is one of the dilepton daughters! - VarManager::FillDileptonHadron(dilepton, hadron, fValuesHadron); - fHistMan->FillHistClass("DileptonHadronInvMass", fValuesHadron); - fHistMan->FillHistClass("DileptonHadronCorrelation", fValuesHadron); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<EventSelection>("my-event-selection"), - adaptAnalysisTask<BarrelTrackSelection>("barrel-track-selection"), - adaptAnalysisTask<MuonTrackSelection>("muon-track-selection"), - adaptAnalysisTask<TableReader>("table-reader"), - adaptAnalysisTask<DileptonHadronAnalysis>("dilepton-hadron") - - }; -} - -void DefineHistograms(HistogramManager* histMan, TString histClasses) -{ - // - // Define here the histograms for all the classes required in analysis. - // The histogram classes are provided in the histClasses string, separated by semicolon ";" - // The histogram classes and their components histograms are defined below depending on the name of the histogram class - // - const int kNRuns = 135; - int runs[kNRuns] = { - 244917, 244918, 244975, 244980, 244982, 244983, 245064, 245066, 245068, 245145, - 245146, 245151, 245152, 245231, 245232, 245259, 245343, 245345, 245346, 245347, - 245349, 245353, 245396, 245397, 245401, 245407, 245409, 245411, 245439, 245441, - 245446, 245450, 245452, 245454, 245496, 245497, 245501, 245504, 245505, 245507, - 245535, 245540, 245542, 245543, 245544, 245545, 245554, 245683, 245692, 245700, - 245702, 245705, 245829, 245831, 245833, 245923, 245949, 245952, 245954, 245963, - 246001, 246003, 246012, 246036, 246037, 246042, 246048, 246049, 246052, 246053, - 246087, 246089, 246113, 246115, 246148, 246151, 246152, 246153, 246178, 246180, - 246181, 246182, 246185, 246217, 246222, 246225, 246271, 246272, 246275, 246276, - 246391, 246392, 246424, 246428, 246431, 246434, 246487, 246488, 246493, 246495, - 246675, 246676, 246750, 246751, 246757, 246758, 246759, 246760, 246763, 246765, - 246766, 246804, 246805, 246807, 246808, 246809, 246810, 246844, 246845, 246846, - 246847, 246851, 246865, 246867, 246870, 246871, 246928, 246945, 246948, 246980, - 246982, 246984, 246989, 246991, 246994}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) { - runsStr += Form("%d;", runs[i]); - } - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram - continue; - } // end if(Event) - - if (classStr.Contains("Track")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram - - if (classStr.Contains("Barrel")) { - histMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "TPCncls_Run", "Number of cluster in TPC", true, kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, - 10, -0.5, 159.5, VarManager::kTPCncls, 10, 0., 1., VarManager::kNothing, runsStr.Data()); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "ITSchi2", "ITS chi2", false, 100, 0.0, 50.0, VarManager::kITSchi2); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "IsITSrefit", "", false, 2, -0.5, 1.5, VarManager::kIsITSrefit); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "IsTPCrefit", "", false, 2, -0.5, 1.5, VarManager::kIsTPCrefit); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "IsSPDany", "", false, 2, -0.5, 1.5, VarManager::kIsSPDany); // TH1F histogram - //for TPC PID - histMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram - histMan->AddHistogram(classStr.Data(), "TPCchi2", "TPC chi2", false, 100, 0.0, 10.0, VarManager::kTPCchi2); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "DCAxy", "DCAxy", false, 100, -3.0, 3.0, VarManager::kTrackDCAxy); // TH1F histogram - histMan->AddHistogram(classStr.Data(), "DCAz", "DCAz", false, 100, -5.0, 5.0, VarManager::kTrackDCAz); // TH1F histogram - } - - if (classStr.Contains("Muon")) { - histMan->AddHistogram(classStr.Data(), "InvBendingMom", "", false, 100, 0.0, 1.0, VarManager::kMuonInvBendingMomentum); - histMan->AddHistogram(classStr.Data(), "ThetaX", "", false, 100, -1.0, 1.0, VarManager::kMuonThetaX); - histMan->AddHistogram(classStr.Data(), "ThetaY", "", false, 100, -2.0, 2.0, VarManager::kMuonThetaY); - histMan->AddHistogram(classStr.Data(), "ZMu", "", false, 100, -30.0, 30.0, VarManager::kMuonZMu); - histMan->AddHistogram(classStr.Data(), "BendingCoor", "", false, 100, 0.32, 0.35, VarManager::kMuonBendingCoor); - histMan->AddHistogram(classStr.Data(), "NonBendingCoor", "", false, 100, 0.065, 0.07, VarManager::kMuonNonBendingCoor); - histMan->AddHistogram(classStr.Data(), "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); - histMan->AddHistogram(classStr.Data(), "Chi2MatchTrigger", "", false, 100, 0.0, 20.0, VarManager::kMuonChi2MatchTrigger); - } - } - - if (classStr.Contains("DileptonsSelected")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 100, 0.0, 5.0, VarManager::kMass, 100, 0.0, 20.0, VarManager::kPt); - } - - if (classStr.Contains("HadronsSelected")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Eta_Pt", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, 0.0, 20.0, VarManager::kPt); - histMan->AddHistogram(classStr.Data(), "Eta_Phi", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, -8.0, 8.0, VarManager::kPhi); - } - - if (classStr.Contains("DileptonsSelected")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 100, 0.0, 5.0, VarManager::kMass, 100, 0.0, 20.0, VarManager::kPt); - } - - if (classStr.Contains("HadronsSelected")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Eta_Pt", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, 0.0, 20.0, VarManager::kPt); - histMan->AddHistogram(classStr.Data(), "Eta_Phi", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, -8.0, 8.0, VarManager::kPhi); - } - - if (classStr.Contains("Pairs")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass_Pt_Cent", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 20.0, VarManager::kPt, 10, 0.0, 100.0, VarManager::kCentVZERO); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 100, 0.0, 20.0, VarManager::kPt); - histMan->AddHistogram(classStr.Data(), "Mass", "", false, 125, 0.0, 5.0, VarManager::kMass); - histMan->AddHistogram(classStr.Data(), "Mass_Run", "", true, kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 10, 0.0, 5.0, VarManager::kMass, - 10, 0., 1., VarManager::kNothing, runsStr.Data()); - } - - if (classStr.Contains("DileptonHadronInvMass")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 40, 0.0, 20.0, VarManager::kPairMass, 40, 0.0, 20.0, VarManager::kPairPt); - } - - if (classStr.Contains("DileptonHadronCorrelation")) { - histMan->AddHistClass(classStr.Data()); - histMan->AddHistogram(classStr.Data(), "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); - histMan->AddHistogram(classStr.Data(), "DeltaEta_DeltaPhiSym", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhiSym); - } - } // end loop over histogram classes -} diff --git a/Analysis/Tasks/PWGHF/CMakeLists.txt b/Analysis/Tasks/PWGHF/CMakeLists.txt deleted file mode 100644 index 934b0800e2bb2..0000000000000 --- a/Analysis/Tasks/PWGHF/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_dpl_workflow(hf-track-index-skims-creator - SOURCES HFTrackIndexSkimsCreator.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing ROOT::EG - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-candidate-creator-2prong - SOURCES HFCandidateCreator2Prong.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing ROOT::EG - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-candidate-creator-3prong - SOURCES HFCandidateCreator3Prong.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing ROOT::EG - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-d0-candidate-selector - SOURCES HFD0CandidateSelector.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-lc-candidate-selector - SOURCES HFLcCandidateSelector.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-task-d0 - SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-task-dplus - SOURCES taskDPlus.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(hf-task-lc - SOURCES taskLc.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx b/Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx deleted file mode 100644 index bf7b6ee5a4da1..0000000000000 --- a/Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFCandidateCreator2Prong.cxx -/// \brief Reconstruction of heavy-flavour 2-prong decay candidates -/// -/// \author Gian Michele Innocenti <gian.michele.innocenti@cern.ch>, CERN -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/AnalysisTask.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" - -using namespace o2; -using namespace o2::framework; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, false, {"Perform MC matching."}}; - workflowOptions.push_back(optionDoMC); -} - -#include "Framework/runDataProcessing.h" - -/// Reconstruction of heavy-flavour 2-prong decay candidates -struct HFCandidateCreator2Prong { - Produces<aod::HfCandProng2Base> rowCandidateBase; - - Configurable<double> magneticField{"d_bz", 5., "magnetic field"}; - Configurable<bool> b_propdca{"b_propdca", true, "create tracks version propagated to PCA"}; - Configurable<double> d_maxr{"d_maxr", 200., "reject PCA's above this radius"}; - Configurable<double> d_maxdzini{"d_maxdzini", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable<double> d_minparamchange{"d_minparamchange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable<double> d_minrelchi2change{"d_minrelchi2change", 0.9, "stop iterations is chi2/chi2old > this"}; - Configurable<bool> b_dovalplots{"b_dovalplots", true, "do validation plots"}; - - OutputObj<TH1F> hmass2{TH1F("hmass2", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; - OutputObj<TH1F> hCovPVXX{TH1F("hCovPVXX", "2-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; - OutputObj<TH1F> hCovSVXX{TH1F("hCovSVXX", "2-prong candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; - - double massPi = RecoDecay::getMassPDG(kPiPlus); - double massK = RecoDecay::getMassPDG(kKPlus); - double massPiK{0.}; - double massKPi{0.}; - - void process(aod::Collisions const& collisions, - aod::HfTrackIndexProng2 const& rowsTrackIndexProng2, - aod::BigTracks const& tracks) - { - // 2-prong vertex fitter - o2::vertexing::DCAFitterN<2> df; - df.setBz(magneticField); - df.setPropagateToPCA(b_propdca); - df.setMaxR(d_maxr); - df.setMaxDZIni(d_maxdzini); - df.setMinParamChange(d_minparamchange); - df.setMinRelChi2Change(d_minrelchi2change); - df.setUseAbsDCA(true); - - // loop over pairs of track indeces - for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { - auto trackParVarPos1 = getTrackParCov(rowTrackIndexProng2.index0()); - auto trackParVarNeg1 = getTrackParCov(rowTrackIndexProng2.index1()); - auto collision = rowTrackIndexProng2.index0().collision(); - - // reconstruct the 2-prong secondary vertex - if (df.process(trackParVarPos1, trackParVarNeg1) == 0) { - continue; - } - const auto& secondaryVertex = df.getPCACandidate(); - auto chi2PCA = df.getChi2AtPCACandidate(); - auto covMatrixPCA = df.calcPCACovMatrix().Array(); - hCovSVXX->Fill(covMatrixPCA[0]); // FIXME: Calculation of errorDecayLength(XY) gives wrong values without this line. - auto trackParVar0 = df.getTrack(0); - auto trackParVar1 = df.getTrack(1); - - // get track momenta - array<float, 3> pvec0; - array<float, 3> pvec1; - trackParVar0.getPxPyPzGlo(pvec0); - trackParVar1.getPxPyPzGlo(pvec1); - - // get track impact parameters - // This modifies track momenta! - auto primaryVertex = getPrimaryVertex(collision); - auto covMatrixPV = primaryVertex.getCov(); - hCovPVXX->Fill(covMatrixPV[0]); - o2::dataformats::DCA impactParameter0; - o2::dataformats::DCA impactParameter1; - trackParVar0.propagateToDCA(primaryVertex, magneticField, &impactParameter0); - trackParVar1.propagateToDCA(primaryVertex, magneticField, &impactParameter1); - - // get uncertainty of the decay length - double phi, theta; - getPointDirection(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex, phi, theta); - auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - - // fill candidate table rows - rowCandidateBase(collision.posX(), collision.posY(), collision.posZ(), - secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], - errorDecayLength, errorDecayLengthXY, - chi2PCA, - pvec0[0], pvec0[1], pvec0[2], - pvec1[0], pvec1[1], pvec1[2], - impactParameter0.getY(), impactParameter1.getY(), - std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), - rowTrackIndexProng2.index0Id(), rowTrackIndexProng2.index1Id()); - - // fill histograms - if (b_dovalplots) { - // calculate invariant masses - auto arrayMomenta = array{pvec0, pvec1}; - massPiK = RecoDecay::M(arrayMomenta, array{massPi, massK}); - massKPi = RecoDecay::M(arrayMomenta, array{massK, massPi}); - hmass2->Fill(massPiK); - hmass2->Fill(massKPi); - } - } - } -}; - -/// Extends the base table with expression columns. -struct HFCandidateCreator2ProngExpressions { - Spawns<aod::HfCandProng2Ext> rowCandidateProng2; - void init(InitContext const&) {} -}; - -/// Performs MC matching. -struct HFCandidateCreator2ProngMC { - Produces<aod::HfCandProng2MCRec> rowMCMatchRec; - Produces<aod::HfCandProng2MCGen> rowMCMatchGen; - - void process(aod::HfCandProng2 const& candidates, - aod::BigTracksMC const& tracks, - aod::McParticles const& particlesMC) - { - // Match reconstructed candidates. - for (auto& candidate : candidates) { - // D0(bar) → π± K∓ - auto isMatchedRecD0 = RecoDecay::isMCMatchedDecayRec( - particlesMC, array{candidate.index0_as<aod::BigTracksMC>(), candidate.index1_as<aod::BigTracksMC>()}, - 421, array{+kPiPlus, -kKPlus}, true); - rowMCMatchRec(uint8_t(isMatchedRecD0)); - } - - // Match generated particles. - for (auto& particle : particlesMC) { - // D0(bar) → π± K∓ - auto isMatchedGenD0 = RecoDecay::isMCMatchedDecayGen(particlesMC, particle, 421, array{+kPiPlus, -kKPlus}, true); - rowMCMatchGen(uint8_t(isMatchedGenD0)); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{ - adaptAnalysisTask<HFCandidateCreator2Prong>("hf-cand-creator-2prong"), - adaptAnalysisTask<HFCandidateCreator2ProngExpressions>("hf-cand-creator-2prong-expressions")}; - const bool doMC = cfgc.options().get<bool>("doMC"); - if (doMC) { - workflow.push_back(adaptAnalysisTask<HFCandidateCreator2ProngMC>("hf-cand-creator-2prong-mc")); - } - return workflow; -} diff --git a/Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx b/Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx deleted file mode 100644 index 70fc45df35242..0000000000000 --- a/Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFCandidateCreator3Prong.cxx -/// \brief Reconstruction of heavy-flavour 3-prong decay candidates -/// \note Extended from HFCandidateCreator2Prong -/// -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/AnalysisTask.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" - -using namespace o2; -using namespace o2::framework; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, false, {"Perform MC matching."}}; - workflowOptions.push_back(optionDoMC); -} - -#include "Framework/runDataProcessing.h" - -/// Reconstruction of heavy-flavour 3-prong decay candidates -struct HFCandidateCreator3Prong { - Produces<aod::HfCandProng3Base> rowCandidateBase; - - Configurable<double> magneticField{"d_bz", 5., "magnetic field"}; - Configurable<bool> b_propdca{"b_propdca", true, "create tracks version propagated to PCA"}; - Configurable<double> d_maxr{"d_maxr", 200., "reject PCA's above this radius"}; - Configurable<double> d_maxdzini{"d_maxdzini", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable<double> d_minparamchange{"d_minparamchange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable<double> d_minrelchi2change{"d_minrelchi2change", 0.9, "stop iterations is chi2/chi2old > this"}; - Configurable<bool> b_dovalplots{"b_dovalplots", true, "do validation plots"}; - - OutputObj<TH1F> hmass3{TH1F("hmass3", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", 500, 1.6, 2.1)}; - OutputObj<TH1F> hCovPVXX{TH1F("hCovPVXX", "3-prong candidates;XX element of cov. matrix of prim. vtx position (cm^{2});entries", 100, 0., 1.e-4)}; - OutputObj<TH1F> hCovSVXX{TH1F("hCovSVXX", "3-prong candidates;XX element of cov. matrix of sec. vtx position (cm^{2});entries", 100, 0., 0.2)}; - - double massPi = RecoDecay::getMassPDG(kPiPlus); - double massK = RecoDecay::getMassPDG(kKPlus); - double massPiKPi{0.}; - - void process(aod::Collisions const& collisions, - aod::HfTrackIndexProng3 const& rowsTrackIndexProng3, - aod::BigTracks const& tracks) - { - // 3-prong vertex fitter - o2::vertexing::DCAFitterN<3> df; - df.setBz(magneticField); - df.setPropagateToPCA(b_propdca); - df.setMaxR(d_maxr); - df.setMaxDZIni(d_maxdzini); - df.setMinParamChange(d_minparamchange); - df.setMinRelChi2Change(d_minrelchi2change); - df.setUseAbsDCA(true); - - // loop over pairs of track indeces - for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { - auto trackParVar0 = getTrackParCov(rowTrackIndexProng3.index0()); - auto trackParVar1 = getTrackParCov(rowTrackIndexProng3.index1()); - auto trackParVar2 = getTrackParCov(rowTrackIndexProng3.index2()); - auto collision = rowTrackIndexProng3.index0().collision(); - - // reconstruct the 3-prong secondary vertex - if (df.process(trackParVar0, trackParVar1, trackParVar2) == 0) { - continue; - } - const auto& secondaryVertex = df.getPCACandidate(); - auto chi2PCA = df.getChi2AtPCACandidate(); - auto covMatrixPCA = df.calcPCACovMatrix().Array(); - hCovSVXX->Fill(covMatrixPCA[0]); // FIXME: Calculation of errorDecayLength(XY) gives wrong values without this line. - trackParVar0 = df.getTrack(0); - trackParVar1 = df.getTrack(1); - trackParVar2 = df.getTrack(2); - - // get track momenta - array<float, 3> pvec0; - array<float, 3> pvec1; - array<float, 3> pvec2; - trackParVar0.getPxPyPzGlo(pvec0); - trackParVar1.getPxPyPzGlo(pvec1); - trackParVar2.getPxPyPzGlo(pvec2); - - // get track impact parameters - // This modifies track momenta! - auto primaryVertex = getPrimaryVertex(collision); - auto covMatrixPV = primaryVertex.getCov(); - hCovPVXX->Fill(covMatrixPV[0]); - o2::dataformats::DCA impactParameter0; - o2::dataformats::DCA impactParameter1; - o2::dataformats::DCA impactParameter2; - trackParVar0.propagateToDCA(primaryVertex, magneticField, &impactParameter0); - trackParVar1.propagateToDCA(primaryVertex, magneticField, &impactParameter1); - trackParVar2.propagateToDCA(primaryVertex, magneticField, &impactParameter2); - - // get uncertainty of the decay length - double phi, theta; - getPointDirection(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex, phi, theta); - auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - - // fill candidate table rows - rowCandidateBase(collision.posX(), collision.posY(), collision.posZ(), - secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], - errorDecayLength, errorDecayLengthXY, - chi2PCA, - pvec0[0], pvec0[1], pvec0[2], - pvec1[0], pvec1[1], pvec1[2], - pvec2[0], pvec2[1], pvec2[2], - impactParameter0.getY(), impactParameter1.getY(), impactParameter2.getY(), - std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), std::sqrt(impactParameter2.getSigmaY2()), - rowTrackIndexProng3.index0Id(), rowTrackIndexProng3.index1Id(), rowTrackIndexProng3.index2Id()); - - // fill histograms - if (b_dovalplots) { - // calculate invariant mass - auto arrayMomenta = array{pvec0, pvec1, pvec2}; - massPiKPi = RecoDecay::M(std::move(arrayMomenta), array{massPi, massK, massPi}); - hmass3->Fill(massPiKPi); - } - } - } -}; - -/// Extends the base table with expression columns. -struct HFCandidateCreator3ProngExpressions { - Spawns<aod::HfCandProng3Ext> rowCandidateProng3; - void init(InitContext const&) {} -}; - -/// Performs MC matching. -struct HFCandidateCreator3ProngMC { - Produces<aod::HfCandProng3MCRec> rowMCMatchRec; - Produces<aod::HfCandProng3MCGen> rowMCMatchGen; - - void process(aod::HfCandProng3 const& candidates, - aod::BigTracksMC const& tracks, - aod::McParticles const& particlesMC) - { - // Match reconstructed candidates. - for (auto& candidate : candidates) { - auto arrayDaughters = array{candidate.index0_as<aod::BigTracksMC>(), candidate.index1_as<aod::BigTracksMC>(), candidate.index2_as<aod::BigTracksMC>()}; - // D± → π± K∓ π± - auto isMatchedRecDPlus = RecoDecay::isMCMatchedDecayRec(particlesMC, arrayDaughters, 411, array{+kPiPlus, -kKPlus, +kPiPlus}, true); - // Lc± → p± K∓ π± - auto isMatchedRecLc = RecoDecay::isMCMatchedDecayRec(particlesMC, std::move(arrayDaughters), 4122, array{+kProton, -kKPlus, +kPiPlus}, true); - rowMCMatchRec(uint8_t(isMatchedRecDPlus + 2 * isMatchedRecLc)); - } - - // Match generated particles. - for (auto& particle : particlesMC) { - // D± → π± K∓ π± - auto isMatchedGenDPlus = RecoDecay::isMCMatchedDecayGen(particlesMC, particle, 411, array{+kPiPlus, -kKPlus, +kPiPlus}, true); - // Lc± → p± K∓ π± - auto isMatchedGenLc = RecoDecay::isMCMatchedDecayGen(particlesMC, particle, 4122, array{+kProton, -kKPlus, +kPiPlus}, true); - rowMCMatchGen(uint8_t(isMatchedGenDPlus + 2 * isMatchedGenLc)); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{ - adaptAnalysisTask<HFCandidateCreator3Prong>("hf-cand-creator-3prong"), - adaptAnalysisTask<HFCandidateCreator3ProngExpressions>("hf-cand-creator-3prong-expressions")}; - const bool doMC = cfgc.options().get<bool>("doMC"); - if (doMC) { - workflow.push_back(adaptAnalysisTask<HFCandidateCreator3ProngMC>("hf-cand-creator-3prong-mc")); - } - return workflow; -} diff --git a/Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx b/Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx deleted file mode 100644 index 6d50a5f9d73bf..0000000000000 --- a/Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFD0CandidateSelector.cxx -/// \brief D0 selection task. -/// -/// \author Nima Zardoshti <nima.zardoshti@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::aod::hf_cand_prong2; - -static const int npTBins = 25; -static const int nCutVars = 11; -//temporary until 2D array in configurable is solved - then move to json -//m dca cost* ptk ptpi d0k d0pi d0d0 cosp cosxy normdxy -constexpr double cuts[npTBins][nCutVars] = {{0.400, 350. * 1E-4, 0.8, 0.5, 0.5, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.80, 0., 0.}, /* pt<0.5*/ - {0.400, 350. * 1E-4, 0.8, 0.5, 0.5, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.80, 0., 0.}, /* 0.5<pt<1*/ - {0.400, 300. * 1E-4, 0.8, 0.4, 0.4, 1000. * 1E-4, 1000. * 1E-4, -25000. * 1E-8, 0.80, 0., 0.}, /* 1<pt<1.5 */ - {0.400, 300. * 1E-4, 0.8, 0.4, 0.4, 1000. * 1E-4, 1000. * 1E-4, -25000. * 1E-8, 0.80, 0., 0.}, /* 1.5<pt<2 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -20000. * 1E-8, 0.90, 0., 0.}, /* 2<pt<2.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -20000. * 1E-8, 0.90, 0., 0.}, /* 2.5<pt<3 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -12000. * 1E-8, 0.85, 0., 0.}, /* 3<pt<3.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -12000. * 1E-8, 0.85, 0., 0.}, /* 3.5<pt<4 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 4<pt<4.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 4.5<pt<5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 5<pt<5.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 5.5<pt<6 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 6<pt<6.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -8000. * 1E-8, 0.85, 0., 0.}, /* 6.5<pt<7 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -7000. * 1E-8, 0.85, 0., 0.}, /* 7<pt<7.5 */ - {0.400, 300. * 1E-4, 0.8, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -7000. * 1E-8, 0.85, 0., 0.}, /* 7.5<pt<8 */ - {0.400, 300. * 1E-4, 0.9, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.85, 0., 0.}, /* 8<pt<9 */ - {0.400, 300. * 1E-4, 0.9, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.85, 0., 0.}, /* 9<pt<10 */ - {0.400, 300. * 1E-4, 0.9, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, -5000. * 1E-8, 0.85, 0., 0.}, /* 10<pt<12 */ - {0.400, 300. * 1E-4, 1.0, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, 10000. * 1E-8, 0.85, 0., 0.}, /* 12<pt<16 */ - {0.400, 300. * 1E-4, 1.0, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, 999999. * 1E-8, 0.85, 0., 0.}, /* 16<pt<20 */ - {0.400, 300. * 1E-4, 1.0, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, 999999. * 1E-8, 0.85, 0., 0.}, /* 20<pt<24 */ - {0.400, 300. * 1E-4, 1.0, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, 999999. * 1E-8, 0.85, 0., 0.}, /* 24<pt<36 */ - {0.400, 300. * 1E-4, 1.0, 0.7, 0.7, 1000. * 1E-4, 1000. * 1E-4, 999999. * 1E-8, 0.85, 0., 0.}, /* 36<pt<50 */ - {0.400, 300. * 1E-4, 1.0, 0.6, 0.6, 1000. * 1E-4, 1000. * 1E-4, 999999. * 1E-8, 0.80, 0., 0.}}; /* pt>50 */ - -/// Struct for applying D0 selection cuts - -struct HFD0CandidateSelector { - - Produces<aod::HFSelD0Candidate> hfSelD0Candidate; - - Configurable<double> d_pTCandMin{"d_pTCandMin", 0., "Lower bound of candidate pT"}; - Configurable<double> d_pTCandMax{"d_pTCandMax", 50., "Upper bound of candidate pT"}; - - Configurable<double> d_pidTPCMinpT{"d_pidTPCMinpT", 0.15, "Lower bound of track pT for TPC PID"}; - Configurable<double> d_pidTPCMaxpT{"d_pidTPCMaxpT", 5., "Upper bound of track pT for TPC PID"}; - Configurable<double> d_pidTOFMinpT{"d_pidTOFMinpT", 0.15, "Lower bound of track pT for TOF PID"}; - Configurable<double> d_pidTOFMaxpT{"d_pidTOFMaxpT", 5., "Upper bound of track pT for TOF PID"}; - - Configurable<double> d_TPCNClsFindablePIDCut{"d_TPCNClsFindablePIDCut", 50., "Lower bound of TPC findable clusters for good PID"}; - Configurable<double> d_nSigmaTPC{"d_nSigmaTPC", 3., "Nsigma cut on TPC only"}; - Configurable<double> d_nSigmaTPCCombined{"d_nSigmaTPCCombined", 5., "Nsigma cut on TPC combined with TOF"}; - Configurable<double> d_nSigmaTOF{"d_nSigmaTOF", 3., "Nsigma cut on TOF only"}; - Configurable<double> d_nSigmaTOFCombined{"d_nSigmaTOFCombined", 5., "Nsigma cut on TOF combined with TPC"}; - - /// Gets corresponding pT bin from cut file array - /// \param candpT is the pT of the candidate - /// \return corresponding bin number of array - template <typename T> - int getpTBin(T candpT) - { - double pTBins[npTBins + 1] = {0, 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 9., 10., 12., 16., 20., 24., 36., 50., 100.}; - if (candpT < pTBins[0] || candpT >= pTBins[npTBins]) { - return -1; - } - for (int i = 0; i < npTBins; i++) { - if (candpT < pTBins[i + 1]) { - return i; - } - } - return -1; - } - - /// Selection on goodness of daughter tracks - /// \note should be applied at candidate selection - /// \param track is daughter track - /// \return true if track is good - template <typename T> - bool daughterSelection(const T& track) - { - if (track.charge() == 0) { - return false; - } - if (track.tpcNClsFound() == 0) { - return false; //is it clusters findable or found - need to check - } - return true; - } - - /// Conjugate independent toplogical cuts - /// \param hfCandProng2 is candidate - /// \return true if candidate passes all cuts - template <typename T> - bool selectionTopol(const T& hfCandProng2) - { - auto candpT = hfCandProng2.pt(); - int pTBin = getpTBin(candpT); - if (pTBin == -1) { - return false; - } - - if (candpT < d_pTCandMin || candpT >= d_pTCandMax) { - return false; //check that the candidate pT is within the analysis range - } - if (hfCandProng2.impactParameterProduct() > cuts[pTBin][7]) { - return false; //product of daughter impact parameters - } - if (hfCandProng2.cpa() < cuts[pTBin][8]) { - return false; //cosine of pointing angle - } - if (hfCandProng2.cpaXY() < cuts[pTBin][9]) { - return false; //cosine of pointing angle XY - } - if (hfCandProng2.decayLengthXYNormalised() < cuts[pTBin][10]) { - return false; //normalised decay length in XY plane - } - // if (hfCandProng2.dca() > cuts[pTBin][1]) return false; //candidate DCA - //if (hfCandProng2.chi2PCA() > cuts[pTBin][1]) return false; //candidate DCA - - //decay exponentail law, with tau = beta*gamma*ctau - //decay length > ctau retains (1-1/e) - double decayLengthCut = TMath::Min((hfCandProng2.p() * 0.0066) + 0.01, 0.06); - if (TMath::Abs(hfCandProng2.impactParameterNormalised0()) < 0.5 || TMath::Abs(hfCandProng2.impactParameterNormalised1()) < 0.5) { - return false; - } - if (hfCandProng2.decayLength() * hfCandProng2.decayLength() < decayLengthCut * decayLengthCut) { - return false; - } - if (hfCandProng2.decayLengthNormalised() * hfCandProng2.decayLengthNormalised() < 1.0) { - //return false; //add back when getter fixed - } - return true; - } - - /// Conjugate dependent toplogical cuts - /// \param hfCandProng2 is candidate - /// \param trackPion is the track with the pion hypothesis - /// \param trackKaon is the track with the kaon hypothesis - /// \note trackPion = positive and trackKaon = negative for D0 selection and inverse for D0bar - /// \return true if candidate passes all cuts for the given Conjugate - template <typename T1, typename T2> - bool selectionTopolConjugate(const T1& hfCandProng2, const T2& trackPion, const T2& trackKaon) - { - - auto candpT = hfCandProng2.pt(); - int pTBin = getpTBin(candpT); - if (pTBin == -1) { - return false; - } - - if (trackPion.charge() > 0) { //invariant mass cut - if (TMath::Abs(InvMassD0(hfCandProng2) - RecoDecay::getMassPDG(421)) > cuts[pTBin][0]) { - return false; - } - } else { - if (TMath::Abs(InvMassD0bar(hfCandProng2) - RecoDecay::getMassPDG(421)) > cuts[pTBin][0]) { - return false; - } - } - - if (TMath::Abs(trackPion.pt()) < TMath::Abs(cuts[pTBin][4]) || TMath::Abs(trackKaon.pt()) < TMath::Abs(cuts[pTBin][3])) { - return false; //cut on daughter pT - } - if (TMath::Abs(trackPion.dcaPrim0()) > cuts[pTBin][6] || TMath::Abs(trackKaon.dcaPrim0()) > cuts[pTBin][5]) { - return false; //cut on daughter dca - need to add secondary vertex constraint here - } - - if (trackPion.charge() > 0) { //cut on cos(theta *) - if (TMath::Abs(CosThetaStarD0(hfCandProng2)) > cuts[pTBin][2]) { - return false; - } - } else { - if (TMath::Abs(CosThetaStarD0bar(hfCandProng2)) > cuts[pTBin][2]) { - return false; - } - } - - return true; - } - - /// Check if track is ok for TPC PID - /// \param track is the track - /// \note function to be expanded - /// \return true if track is ok for TPC PID - template <typename T> - bool validTPCPID(const T& track) - { - if (TMath::Abs(track.pt()) < d_pidTPCMinpT || TMath::Abs(track.pt()) >= d_pidTPCMaxpT) { - return false; - } - //if (track.TPCNClsFindable() < d_TPCNClsFindablePIDCut) return false; - return true; - } - - /// Check if track is ok for TOF PID - /// \param track is the track - /// \note function to be expanded - /// \return true if track is ok for TOF PID - template <typename T> - bool validTOFPID(const T& track) - { - if (TMath::Abs(track.pt()) < d_pidTOFMinpT || TMath::Abs(track.pt()) >= d_pidTOFMaxpT) { - return false; - } - return true; - } - - /// Check if track is compatible with given TPC Nsigma cut for a given flavour hypothesis - /// \param track is the track - /// \param nPDG is the flavour hypothesis PDG number - /// \param nSigmaCut is the nsigma threshold to test against - /// \note nPDG=211 pion nPDG=321 kaon - /// \return true if track satisfies TPC PID hypothesis for given Nsigma cut - template <typename T> - bool selectionPIDTPC(const T& track, int nPDG, int nSigmaCut) - { - double nSigma = 100.0; //arbitarily large value - nPDG = TMath::Abs(nPDG); - if (nPDG == 111) { - nSigma = track.tpcNSigmaPi(); - } else if (nPDG == 321) { - nSigma = track.tpcNSigmaKa(); - } else { - return false; - } - return nSigma < nSigmaCut; - } - - /// Check if track is compatible with given TOF NSigma cut for a given flavour hypothesis - /// \param track is the track - /// \param nPDG is the flavour hypothesis PDG number - /// \param nSigmaCut is the nSigma threshold to test against - /// \note nPDG=211 pion nPDG=321 kaon - /// \return true if track satisfies TOF PID hypothesis for given NSigma cut - template <typename T> - bool selectionPIDTOF(const T& track, int nPDG, int nSigmaCut) - { - double nSigma = 100.0; //arbitarily large value - nPDG = TMath::Abs(nPDG); - if (nPDG == 111) { - nSigma = track.tofNSigmaPi(); - } else if (nPDG == 321) { - nSigma = track.tofNSigmaKa(); - } else { - return false; - } - return nSigma < nSigmaCut; - } - - /// PID selection on daughter track - /// \param track is the daughter track - /// \param nPDG is the PDG code of the flavour hypothesis - /// \note nPDG=211 pion nPDG=321 kaon - /// \return 1 if successful PID match, 0 if successful PID rejection, -1 if no PID info - template <typename T> - int selectionPID(const T& track, int nPDG) - { - int statusTPC = -1; - int statusTOF = -1; - - if (validTPCPID(track)) { - if (!selectionPIDTPC(track, nPDG, d_nSigmaTPC)) { - if (!selectionPIDTPC(track, nPDG, d_nSigmaTPCCombined)) { - statusTPC = 0; //rejected by PID - } else { - statusTPC = 1; //potential to be acceepted if combined with TOF - } - } else { - statusTPC = 2; //positive PID - } - } else { - statusTPC = -1; //no PID info - } - - if (validTOFPID(track)) { - if (!selectionPIDTOF(track, nPDG, d_nSigmaTOF)) { - if (!selectionPIDTOF(track, nPDG, d_nSigmaTOFCombined)) { - statusTOF = 0; //rejected by PID - } else { - statusTOF = 1; //potential to be acceepted if combined with TOF - } - } else { - statusTOF = 2; //positive PID - } - } else { - statusTOF = -1; //no PID info - } - - if (statusTPC == 2 || statusTOF == 2) { - return 1; //what if we have 2 && 0 ? - } else if (statusTPC == 1 && statusTOF == 1) { - return 1; - } else if (statusTPC == 0 || statusTOF == 0) { - return 0; - } else { - return -1; - } - } - - void process(aod::HfCandProng2 const& hfCandProng2s, aod::BigTracksPID const& tracks) - { - int statusD0, statusD0bar; // final selection flag : 0-rejected 1-accepted - bool topolD0, topolD0bar; - int pidD0, pidD0bar, pionPlus, pionMinus, kaonPlus, kaonMinus; - - for (auto& hfCandProng2 : hfCandProng2s) { //looping over 2 prong candidates - - auto trackPos = hfCandProng2.index0_as<aod::BigTracksPID>(); //positive daughter - auto trackNeg = hfCandProng2.index1_as<aod::BigTracksPID>(); //negative daughter - - statusD0 = 0; - statusD0bar = 0; - topolD0 = true; - topolD0bar = true; - pidD0 = -1; - pidD0bar = -1; - pionPlus = -1; - pionMinus = -1; - kaonPlus = -1; - kaonMinus = -1; - - // daughter track validity selection - if (!daughterSelection(trackPos) || !daughterSelection(trackNeg)) { - hfSelD0Candidate(statusD0, statusD0bar); - continue; - } - - //implement filter bit 4 cut - should be done before this task at the track selection level - //need to add special cuts (additional cuts on decay length and d0 norm) - - //conjugate independent topological selection - if (!selectionTopol(hfCandProng2)) { - hfSelD0Candidate(statusD0, statusD0bar); - continue; - } - - //conjugate dependent toplogical selection for D0 - topolD0 = selectionTopolConjugate(hfCandProng2, trackPos, trackNeg); - //conjugate dependent toplogical selection for D0bar - topolD0bar = selectionTopolConjugate(hfCandProng2, trackNeg, trackPos); - - if (!topolD0 && !topolD0bar) { - hfSelD0Candidate(statusD0, statusD0bar); - continue; - } - - pionPlus = selectionPID(trackPos, 211); - kaonMinus = selectionPID(trackNeg, 321); - pionMinus = selectionPID(trackNeg, 211); - kaonPlus = selectionPID(trackPos, 321); - - if (pionPlus == 0 || kaonMinus == 0 || pionMinus == 1 || kaonPlus == 1) { - pidD0 = 0; //exclude D0 - } - if (pionPlus == 1 || kaonMinus == 1 || pionMinus == 0 || kaonPlus == 0) { - pidD0bar = 0; //exclude D0bar - } - if (pionPlus == 1 && kaonMinus == 1) { - pidD0 = 1; //accept D0 - } - if (pionMinus == 1 && kaonPlus == 1) { - pidD0bar = 1; //accept D0bar - } - - if (pidD0 == 0 && pidD0bar == 0) { - hfSelD0Candidate(statusD0, statusD0bar); - continue; - } - - if ((pidD0 == -1 || pidD0 == 1) && topolD0) { - statusD0 = 1; //identified as D0 - } - if ((pidD0bar == -1 || pidD0bar == 1) && topolD0bar) { - statusD0bar = 1; //identified as D0bar - } - - hfSelD0Candidate(statusD0, statusD0bar); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HFD0CandidateSelector>("hf-d0-candidate-selector")}; -} diff --git a/Analysis/Tasks/PWGHF/HFLcCandidateSelector.cxx b/Analysis/Tasks/PWGHF/HFLcCandidateSelector.cxx deleted file mode 100644 index fbdb2edb72c57..0000000000000 --- a/Analysis/Tasks/PWGHF/HFLcCandidateSelector.cxx +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFD0CandidateSelector.cxx -/// \brief Lc->pKpi selection task. -/// -/// \author Luigi Dello Stritto <luigi.dellostritto@cern.ch>, CERN -/// \author Nima Zardoshti <nima.zardoshti@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::aod::hf_cand_prong3; - -static const int npTBins = 10; -static const int nCutVars = 8; -//temporary until 2D array in configurable is solved - then move to json -//m ptp ptk ptpi DCA sigmavtx dlenght cosp -constexpr double cuts[npTBins][nCutVars] = {{0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* pt<1 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 1<pt<2 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 2<pt<3 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 3<pt<4 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 4<pt<5 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 5<pt<6 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 6<pt<8 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 8<pt<12 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}, /* 12<pt<24 */ - {0.5, 0.2, 0.2, 0.2, 0.05, 0.09, 0.005, 0.}}; /* 24<pt<36 */ - -/// Struct for applying Lc selection cuts - -struct HFLcCandidateSelector { - - Produces<aod::HFSelLcCandidate> hfSelLcCandidate; - - Configurable<double> d_pTCandMin{"d_pTCandMin", 0., "Lower bound of candidate pT"}; - Configurable<double> d_pTCandMax{"d_pTCandMax", 36., "Upper bound of candidate pT"}; - - Configurable<double> d_pidTPCMinpT{"d_pidTPCMinpT", 0.15, "Lower bound of track pT for TPC PID"}; - Configurable<double> d_pidTPCMaxpT{"d_pidTPCMaxpT", 1., "Upper bound of track pT for TPC PID"}; - Configurable<double> d_pidTOFMinpT{"d_pidTOFMinpT", 0.5, "Lower bound of track pT for TOF PID"}; - Configurable<double> d_pidTOFMaxpT{"d_pidTOFMaxpT", 4., "Upper bound of track pT for TOF PID"}; - - Configurable<double> d_TPCNClsFindablePIDCut{"d_TPCNClsFindablePIDCut", 70., "Lower bound of TPC findable clusters for good PID"}; - Configurable<double> d_nSigmaTPC{"d_nSigmaTPC", 3., "Nsigma cut on TPC only"}; - Configurable<double> d_nSigmaTPCCombined{"d_nSigmaTPCCombined", 5., "Nsigma cut on TPC combined with TOF"}; - Configurable<double> d_nSigmaTOF{"d_nSigmaTOF", 3., "Nsigma cut on TOF only"}; - Configurable<double> d_nSigmaTOFCombined{"d_nSigmaTOFCombined", 5., "Nsigma cut on TOF combined with TPC"}; - - /// Gets corresponding pT bin from cut file array - /// \param candpT is the pT of the candidate - /// \return corresponding bin number of array - template <typename T> - int getpTBin(T candpT) - { - double pTBins[npTBins + 1] = {0, 1., 2., 3., 4., 5., 6., 8., 12., 24., 36.}; - if (candpT < pTBins[0] || candpT >= pTBins[npTBins]) { - return -1; - } - for (int i = 0; i < npTBins; i++) { - if (candpT < pTBins[i + 1]) { - return i; - } - } - return -1; - } - - /// Selection on goodness of daughter tracks - /// \note should be applied at candidate selection - /// \param track is daughter track - /// \return true if track is good - template <typename T> - bool daughterSelection(const T& track) - { - if (track.charge() == 0) { - return false; - } - if (track.tpcNClsFound() == 0) { - return false; //is it clusters findable or found - need to check - } - return true; - } - - /// Conjugate independent toplogical cuts - /// \param hfCandProng3 is candidate - /// \return true if candidate passes all cuts - template <typename T> - bool selectionTopol(const T& hfCandProng3) - { - auto candpT = hfCandProng3.pt(); - int pTBin = getpTBin(candpT); - if (pTBin == -1) { - return false; - } - - if (candpT < d_pTCandMin || candpT >= d_pTCandMax) { - return false; //check that the candidate pT is within the analysis range - } - if (hfCandProng3.cpa() <= cuts[pTBin][7]) { - return false; //cosine of pointing angle - } - // if (hfCandProng3.dca() > cuts[pTBin][4]) return false; //candidate DCA - if (hfCandProng3.chi2PCA() > cuts[pTBin][5]) { //candidate DCA - return false; - } - - if (hfCandProng3.decayLength() * hfCandProng3.decayLength() < cuts[pTBin][6] * cuts[pTBin][6]) { - return false; - } - return true; - } - - /// Conjugate dependent toplogical cuts - /// \param hfCandProng3 is candidate - /// \param trackProton is the track with the proton hypothesis - /// \param trackPion is the track with the pion hypothesis - /// \param trackKaon is the track with the kaon hypothesis - /// \note trackPion = positive and trackKaon = negative for D0 selection and inverse for D0bar - /// \return true if candidate passes all cuts for the given Conjugate - template <typename T1, typename T2> - bool selectionTopolConjugate(const T1& hfCandProng3, const T2& trackProton, const T2& trackKaon, const T2& trackPion) - { - - auto candpT = hfCandProng3.pt(); - int pTBin = getpTBin(candpT); - if (pTBin == -1) { - return false; - } - - //invariant mass cut - if (TMath::Abs(InvMassLc(hfCandProng3) - RecoDecay::getMassPDG(4122)) > cuts[pTBin][0]) { - return false; - } - - if (TMath::Abs(trackProton.pt()) < TMath::Abs(cuts[pTBin][1]) || TMath::Abs(trackKaon.pt()) < TMath::Abs(cuts[pTBin][2]) || TMath::Abs(trackPion.pt()) < TMath::Abs(cuts[pTBin][3])) { - return false; //cut on daughter pT - } - - /* if (TMath::Sqrt( trackProton.dcaPrim0()*trackProton.dcaPrim0() + trackKaon.dcaPrim0()*trackKaon.dcaPrim0() + trackPion.dcaPrim0()*trackPion.dcaPrim0() ) > cuts[pTBin][5]) { - return false; //cut on daughter dca - need to add secondary vertex constraint here - }*/ - - return true; - } - - /// Check if track is ok for TPC PID - /// \param track is the track - /// \note function to be expanded - /// \return true if track is ok for TPC PID - template <typename T> - bool validTPCPID(const T& track) - { - if (TMath::Abs(track.pt()) < d_pidTPCMinpT || TMath::Abs(track.pt()) >= d_pidTPCMaxpT) { - return false; - } - //if (track.TPCNClsFindable() < d_TPCNClsFindablePIDCut) return false; - return true; - } - - /// Check if track is ok for TOF PID - /// \param track is the track - /// \note function to be expanded - /// \return true if track is ok for TOF PID - template <typename T> - bool validTOFPID(const T& track) - { - if (TMath::Abs(track.pt()) < d_pidTOFMinpT || TMath::Abs(track.pt()) >= d_pidTOFMaxpT) { - return false; - } - return true; - } - - /// Check if track is compatible with given TPC Nsigma cut for a given flavour hypothesis - /// \param track is the track - /// \param nPDG is the flavour hypothesis PDG number - /// \param nSigmaCut is the nsigma threshold to test against - /// \note nPDG=2212 proton nPDG=211 pion nPDG=321 kaon - /// \return true if track satisfies TPC PID hypothesis for given Nsigma cut - template <typename T> - bool selectionPIDTPC(const T& track, int nPDG, int nSigmaCut) - { - double nSigma = 100.0; //arbitarily large value - nPDG = TMath::Abs(nPDG); - if (nPDG == 2212) { - nSigma = track.tpcNSigmaPr(); - } else if (nPDG == 321) { - nSigma = track.tpcNSigmaKa(); - } else if (nPDG == 111) { - nSigma = track.tpcNSigmaPi(); - } else { - return false; - } - return nSigma < nSigmaCut; - } - - /// Check if track is compatible with given TOF NSigma cut for a given flavour hypothesis - /// \param track is the track - /// \param nPDG is the flavour hypothesis PDG number - /// \param nSigmaCut is the nSigma threshold to test against - /// \note nPDG=2212 proton nPDG=211 pion nPDG=321 kaon - /// \return true if track satisfies TOF PID hypothesis for given NSigma cut - template <typename T> - bool selectionPIDTOF(const T& track, int nPDG, int nSigmaCut) - { - double nSigma = 100.0; //arbitarily large value - nPDG = TMath::Abs(nPDG); - if (nPDG == 2212) { - nSigma = track.tofNSigmaPr(); - } else if (nPDG == 321) { - nSigma = track.tofNSigmaKa(); - } else if (nPDG == 321) { - nSigma = track.tofNSigmaPi(); - } else { - return false; - } - return nSigma < nSigmaCut; - } - - /// PID selection on daughter track - /// \param track is the daughter track - /// \param nPDG is the PDG code of the flavour hypothesis - /// \note nPDG=2212 nPDG=211 pion nPDG=321 kaon - /// \return 1 if successful PID match, 0 if successful PID rejection, -1 if no PID info - template <typename T> - int selectionPID(const T& track, int nPDG) - { - int statusTPC = -1; - int statusTOF = -1; - - if (validTPCPID(track)) { - if (!selectionPIDTPC(track, nPDG, d_nSigmaTPC)) { - if (!selectionPIDTPC(track, nPDG, d_nSigmaTPCCombined)) { - statusTPC = 0; //rejected by PID - } else { - statusTPC = 1; //potential to be acceepted if combined with TOF - } - } else { - statusTPC = 2; //positive PID - } - } else { - statusTPC = -1; //no PID info - } - - if (validTOFPID(track)) { - if (!selectionPIDTOF(track, nPDG, d_nSigmaTOF)) { - if (!selectionPIDTOF(track, nPDG, d_nSigmaTOFCombined)) { - statusTOF = 0; //rejected by PID - } else { - statusTOF = 1; //potential to be acceepted if combined with TOF - } - } else { - statusTOF = 2; //positive PID - } - } else { - statusTOF = -1; //no PID info - } - - if (statusTPC == 2 || statusTOF == 2) { - return 1; //what if we have 2 && 0 ? - } else if (statusTPC == 1 && statusTOF == 1) { - return 1; - } else if (statusTPC == 0 || statusTOF == 0) { - return 0; - } else { - return -1; - } - } - - void process(aod::HfCandProng3 const& hfCandProng3s, aod::BigTracksPID const& tracks) - { - int statusLc; // final selection flag : 0-rejected 1-accepted - bool topolLc; - int pidLc, proton, kaonMinus, pionPlus; - - for (auto& hfCandProng3 : hfCandProng3s) { //looping over 3 prong candidates - - auto trackPos1 = hfCandProng3.index0_as<aod::BigTracksPID>(); //positive daughter - auto trackNeg1 = hfCandProng3.index1_as<aod::BigTracksPID>(); //negative daughter - auto trackPos2 = hfCandProng3.index2_as<aod::BigTracksPID>(); //positive daughter - - statusLc = 0; - topolLc = true; - pidLc = -1; - proton = -1; - kaonMinus = -1; - pionPlus = -1; - - // daughter track validity selection - if (!daughterSelection(trackPos1) || !daughterSelection(trackNeg1) || !daughterSelection(trackPos2)) { - hfSelLcCandidate(statusLc); - continue; - } - - //implement filter bit 4 cut - should be done before this task at the track selection level - - //conjugate independent topological selection - if (!selectionTopol(hfCandProng3)) { - hfSelLcCandidate(statusLc); - continue; - } - - //conjugate dependent toplogical selection for Lc - topolLc = selectionTopolConjugate(hfCandProng3, trackPos1, trackNeg1, trackPos2); - - if (!topolLc) { - hfSelLcCandidate(statusLc); - continue; - } - - proton = selectionPID(trackPos1, 2212); - kaonMinus = selectionPID(trackNeg1, 321); - pionPlus = selectionPID(trackPos2, 211); - - if (proton == 0 || kaonMinus == 0 || pionPlus == 0) { - pidLc = 0; //exclude Lc - } - if (proton == 1 && kaonMinus == 1 && pionPlus == 1) { - pidLc = 1; //accept Lc - } - - if (pidLc == 0) { - hfSelLcCandidate(statusLc); - continue; - } - - if ((pidLc == -1 || pidLc == 1) && topolLc) { - statusLc = 1; //identified as Lc - } - - hfSelLcCandidate(statusLc); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HFLcCandidateSelector>("hf-lc-candidate-selector")}; -} diff --git a/Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx b/Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx deleted file mode 100644 index f203f9c6e9d17..0000000000000 --- a/Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HFTrackIndexSkimsCreator.cxx -/// \brief Pre-selection of 2-prong and 3-prong secondary vertices of heavy-flavour decay candidates -/// -/// \author Gian Michele Innocenti <gian.michele.innocenti@cern.ch>, CERN -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/trackUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -/// Track selection -struct SelectTracks { - Produces<aod::HFSelTrack> rowSelectedTrack; - - Configurable<bool> b_dovalplots{"b_dovalplots", true, "fill histograms"}; - Configurable<double> d_bz{"d_bz", 5., "bz field"}; - // quality cut - Configurable<bool> doCutQuality{"doCutQuality", true, "apply quality cuts"}; - Configurable<int> d_tpcnclsfound{"d_tpcnclsfound", 70, "min. number of TPC clusters"}; - // 2-prong cuts - Configurable<double> ptmintrack_2prong{"ptmintrack_2prong", -1., "min. track pT"}; - Configurable<double> dcatoprimxymin_2prong{"dcatoprimxymin_2prong", 0., "min. DCAXY to prim. vtx."}; - Configurable<double> etamax_2prong{"etamax_2prong", 999., "max. pseudorapidity"}; - // 3-prong cuts - Configurable<double> ptmintrack_3prong{"ptmintrack_3prong", -1., "min. track pT"}; - Configurable<double> dcatoprimxymin_3prong{"dcatoprimxymin_3prong", 0., "min. DCAXY to prim. vtx."}; - Configurable<double> etamax_3prong{"etamax_3prong", 999., "max. pseudorapidity"}; - - OutputObj<TH1F> hpt_nocuts{TH1F("hpt_nocuts", "all tracks;#it{p}_{T}^{track} (GeV/#it{c});entries", 100, 0., 10.)}; - // 2-prong histograms - OutputObj<TH1F> hpt_cuts_2prong{TH1F("hpt_cuts_2prong", "tracks selected for 2-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hdcatoprimxy_cuts_2prong{TH1F("hdcatoprimxy_cuts_2prong", "tracks selected for 2-prong vertexing;DCAxy to prim. vtx. (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> heta_cuts_2prong{TH1F("heta_cuts_2prong", "tracks selected for 2-prong vertexing;#it{#eta};entries", 100, -1., 1.)}; - // 3-prong histograms - OutputObj<TH1F> hpt_cuts_3prong{TH1F("hpt_cuts_3prong", "tracks selected for 3-prong vertexing;#it{p}_{T}^{track} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hdcatoprimxy_cuts_3prong{TH1F("hdcatoprimxy_cuts_3prong", "tracks selected for 3-prong vertexing;DCAxy to prim. vtx. (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> heta_cuts_3prong{TH1F("heta_cuts_3prong", "tracks selected for 3-prong vertexing;#it{#eta};entries", 100, -1., 1.)}; - - void process(aod::Collision const& collision, - soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra> const& tracks) - { - math_utils::Point3D<float> vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - for (auto& track : tracks) { - int status_2prong = 1; // selection flag - int status_3prong = 1; // selection flag - - if (b_dovalplots) { - hpt_nocuts->Fill(track.pt()); - } - - // pT cut - if (track.pt() < ptmintrack_2prong) { - status_2prong = 0; - } - if (track.pt() < ptmintrack_3prong) { - status_3prong = 0; - } - - // eta cut - if (status_2prong && abs(track.eta()) > etamax_2prong) { - status_2prong = 0; - } - if (status_3prong && abs(track.eta()) > etamax_3prong) { - status_3prong = 0; - } - - // quality cut - if (doCutQuality && (status_2prong || status_3prong)) { - UChar_t clustermap = track.itsClusterMap(); - bool isselected = track.tpcNClsFound() >= d_tpcnclsfound && - track.flags() & o2::aod::track::ITSrefit && - (TESTBIT(clustermap, 0) || TESTBIT(clustermap, 1)); - if (!isselected) { - status_2prong = 0; - status_3prong = 0; - } - } - - // DCA cut - array<float, 2> dca; - if (status_2prong || status_3prong) { - auto trackparvar0 = getTrackParCov(track); - bool isprop = trackparvar0.propagateParamToDCA(vtxXYZ, d_bz, &dca, 100.); // get impact parameters - if (!isprop) { - status_2prong = 0; - status_3prong = 0; - } - if (status_2prong && abs(dca[0]) < dcatoprimxymin_2prong) { - status_2prong = 0; - } - if (status_3prong && abs(dca[0]) < dcatoprimxymin_3prong) { - status_3prong = 0; - } - } - - // fill histograms - if (b_dovalplots) { - if (status_2prong == 1) { - hpt_cuts_2prong->Fill(track.pt()); - hdcatoprimxy_cuts_2prong->Fill(dca[0]); - heta_cuts_2prong->Fill(track.eta()); - } - if (status_3prong == 1) { - hpt_cuts_3prong->Fill(track.pt()); - hdcatoprimxy_cuts_3prong->Fill(dca[0]); - heta_cuts_3prong->Fill(track.eta()); - } - } - - // fill table row - rowSelectedTrack(status_2prong, status_3prong, dca[0], dca[1]); - } - } -}; - -/// Pre-selection of 2-prong and 3-prong secondary vertices -struct HFTrackIndexSkimsCreator { - Produces<aod::HfTrackIndexProng2> rowTrackIndexProng2; - Produces<aod::HfTrackIndexProng3> rowTrackIndexProng3; - - Configurable<bool> b_dovalplots{"b_dovalplots", true, "fill histograms"}; - Configurable<int> do3prong{"do3prong", 0, "do 3 prong"}; - // event selection - Configurable<int> triggerindex{"triggerindex", -1, "trigger index"}; - // vertexing parameters - Configurable<double> d_bz{"d_bz", 5., "magnetic field"}; - Configurable<bool> b_propdca{"b_propdca", true, "create tracks version propagated to PCA"}; - Configurable<double> d_maxr{"d_maxr", 200., "reject PCA's above this radius"}; - Configurable<double> d_maxdzini{"d_maxdzini", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; - Configurable<double> d_minparamchange{"d_minparamchange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; - Configurable<double> d_minrelchi2change{"d_minrelchi2change", 0.9, "stop iterations if chi2/chi2old > this"}; - // 2-prong cuts - Configurable<double> cut2ProngPtCandMin{"cut2ProngPtCandMin", -1., "min. pT of the 2-prong candidate"}; - Configurable<double> cut2ProngInvMassD0Min{"cut2ProngInvMassD0Min", -1., "min. D0 candidate invariant mass"}; - Configurable<double> cut2ProngInvMassD0Max{"cut2ProngInvMassD0Max", -1., "max. D0 candidate invariant mass"}; - Configurable<double> cut2ProngCPAMin{"cut2ProngCPAMin", -2., "min. cosine of pointing angle"}; - Configurable<double> cut2ProngImpParProductMax{"cut2ProngImpParProductMax", 100., "max. product of imp. par. of D0 candidate prongs"}; - // 3-prong cuts - Configurable<double> cut3ProngPtCandMin{"cut3ProngPtCandMin", -1., "min. pT of the 3-prong candidate"}; - Configurable<double> cut3ProngInvMassDPlusMin{"cut3ProngInvMassDPlusMin", 1.5, "min. D+ candidate invariant mass"}; - Configurable<double> cut3ProngInvMassDPlusMax{"cut3ProngInvMassDPlusMax", 2.1, "min. D+ candidate invariant mass"}; - Configurable<double> cut3ProngCPAMin{"cut3ProngCPAMin", -2., "min. cosine of pointing angle"}; - Configurable<double> cut3ProngDecLenMin{"cut3ProngDecLenMin", -1., "min. decay length"}; - - // 2-prong histograms - OutputObj<TH1F> hvtx2_x{TH1F("hvtx2_x", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", 1000, -2., 2.)}; - OutputObj<TH1F> hvtx2_y{TH1F("hvtx2_y", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", 1000, -2., 2.)}; - OutputObj<TH1F> hvtx2_z{TH1F("hvtx2_z", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", 1000, -20., 20.)}; - OutputObj<TH1F> hmass2{TH1F("hmass2", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; - // 3-prong histograms - OutputObj<TH1F> hvtx3_x{TH1F("hvtx3_x", "3-prong candidates;#it{x}_{sec. vtx.} (cm);entries", 1000, -2., 2.)}; - OutputObj<TH1F> hvtx3_y{TH1F("hvtx3_y", "3-prong candidates;#it{y}_{sec. vtx.} (cm);entries", 1000, -2., 2.)}; - OutputObj<TH1F> hvtx3_z{TH1F("hvtx3_z", "3-prong candidates;#it{z}_{sec. vtx.} (cm);entries", 1000, -20., 20.)}; - OutputObj<TH1F> hmass3{TH1F("hmass3", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", 500, 1.6, 2.1)}; - - /* - // Counter histograms - OutputObj<TH2F> hNCand2ProngVsNTracks{TH2F("hNCand2ProngVsNTracks", "2-prong candidates;# of tracks;# of candidates;entries", 1000, 0., 1000., 1000, 0., 10000.)}; - OutputObj<TH2F> hNCand3ProngVsNTracks{TH2F("hNCand3ProngVsNTracks", "3-prong candidates;# of tracks;# of candidates;entries", 1000, 0., 1000., 1000, 0., 10000.)}; - OutputObj<TH1F> hNCand2Prong{TH1F("hNCand2Prong", "2-prong candidates;# of candidates;entries", 1000, 0., 10000.)}; - OutputObj<TH1F> hNCand3Prong{TH1F("hNCand3Prong", "3-prong candidates;# of candidates;entries", 1000, 0., 10000.)}; - OutputObj<TH1F> hNTracks{TH1F("hNTracks", ";# of tracks;entries", 1000, 0., 1000.)}; - */ - - Filter filterSelectTracks = (aod::hf_seltrack::isSel2Prong == 1); - using SelectedTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra, aod::HFSelTrack>>; - // FIXME - //Partition<SelectedTracks> tracksPos = aod::track::signed1Pt > 0.f; - //Partition<SelectedTracks> tracksNeg = aod::track::signed1Pt < 0.f; - - double massPi = RecoDecay::getMassPDG(kPiPlus); - double massK = RecoDecay::getMassPDG(kKPlus); - double mass2PiK{0.}; - double mass2KPi{0.}; - double mass3PiKPi{0.}; - - void process(aod::Collision const& collision, - aod::BCs const& bcs, - SelectedTracks const& tracks) - { - int trigindex = int{triggerindex}; - if (trigindex != -1) { - uint64_t triggerMask = collision.bc().triggerMask(); - bool isTriggerClassFired = triggerMask & 1ul << (trigindex - 1); - if (!isTriggerClassFired) { - return; - } - } - - // 2-prong vertex fitter - o2::vertexing::DCAFitterN<2> df2; - df2.setBz(d_bz); - df2.setPropagateToPCA(b_propdca); - df2.setMaxR(d_maxr); - df2.setMaxDZIni(d_maxdzini); - df2.setMinParamChange(d_minparamchange); - df2.setMinRelChi2Change(d_minrelchi2change); - df2.setUseAbsDCA(true); - - // 3-prong vertex fitter - o2::vertexing::DCAFitterN<3> df3; - df3.setBz(d_bz); - df3.setPropagateToPCA(b_propdca); - df3.setMaxR(d_maxr); - df3.setMaxDZIni(d_maxdzini); - df3.setMinParamChange(d_minparamchange); - df3.setMinRelChi2Change(d_minrelchi2change); - df3.setUseAbsDCA(true); - - //auto nCand2 = rowTrackIndexProng2.lastIndex(); - //auto nCand3 = rowTrackIndexProng3.lastIndex(); - - // first loop over positive tracks - //for (auto trackPos1 = tracksPos.begin(); trackPos1 != tracksPos.end(); ++trackPos1) { - for (auto trackPos1 = tracks.begin(); trackPos1 != tracks.end(); ++trackPos1) { - if (trackPos1.signed1Pt() < 0) { - continue; - } - - auto trackParVarPos1 = getTrackParCov(trackPos1); - - // first loop over negative tracks - //for (auto trackNeg1 = tracksNeg.begin(); trackNeg1 != tracksNeg.end(); ++trackNeg1) { - for (auto trackNeg1 = tracks.begin(); trackNeg1 != tracks.end(); ++trackNeg1) { - if (trackNeg1.signed1Pt() > 0) { - continue; - } - - auto trackParVarNeg1 = getTrackParCov(trackNeg1); - auto pVecCandProng2 = array{trackPos1.px() + trackNeg1.px(), - trackPos1.py() + trackNeg1.py(), - trackPos1.pz() + trackNeg1.pz()}; - bool isSelectedCand2Prong = true; - - // candidate pT cut - if (RecoDecay::Pt(pVecCandProng2) < cut2ProngPtCandMin) { - isSelectedCand2Prong = false; - } - - if (isSelectedCand2Prong) { - // reconstruct the 2-prong secondary vertex - if (df2.process(trackParVarPos1, trackParVarNeg1) == 0) { - continue; - } - - // imp. par. product cut - if (isSelectedCand2Prong && cut2ProngImpParProductMax < 100.) { - if (trackPos1.dcaPrim0() * trackNeg1.dcaPrim0() > cut2ProngImpParProductMax) { - isSelectedCand2Prong = false; - } - } - - // get secondary vertex - const auto& secondaryVertex2 = df2.getPCACandidate(); - // get track momenta - array<float, 3> pvec0; - array<float, 3> pvec1; - df2.getTrack(0).getPxPyPzGlo(pvec0); - df2.getTrack(1).getPxPyPzGlo(pvec1); - - // CPA cut - if (isSelectedCand2Prong && cut2ProngCPAMin > -2.) { - pVecCandProng2 = RecoDecay::PVec(pvec0, pvec1); - auto cpa = RecoDecay::CPA(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex2, pVecCandProng2); - if (cpa < cut2ProngCPAMin) { - isSelectedCand2Prong = false; - } - } - - if (isSelectedCand2Prong) { - // calculate invariant masses - auto arrMom = array{pvec0, pvec1}; - mass2PiK = RecoDecay::M(arrMom, array{massPi, massK}); - mass2KPi = RecoDecay::M(arrMom, array{massK, massPi}); - } - - // invariant-mass cut - if (isSelectedCand2Prong && cut2ProngInvMassD0Min >= 0. && cut2ProngInvMassD0Max > 0.) { - if ((mass2PiK < cut2ProngInvMassD0Min || mass2PiK > cut2ProngInvMassD0Max) && - (mass2KPi < cut2ProngInvMassD0Min || mass2KPi > cut2ProngInvMassD0Max)) { - isSelectedCand2Prong = false; - } - } - - if (isSelectedCand2Prong) { - // fill table row - rowTrackIndexProng2(trackPos1.globalIndex(), - trackNeg1.globalIndex(), 1); - - // fill histograms - if (b_dovalplots) { - hvtx2_x->Fill(secondaryVertex2[0]); - hvtx2_y->Fill(secondaryVertex2[1]); - hvtx2_z->Fill(secondaryVertex2[2]); - hmass2->Fill(mass2PiK); - hmass2->Fill(mass2KPi); - } - } - } - - // 3-prong vertex reconstruction - if (do3prong == 1) { - if (trackPos1.isSel3Prong() == 0) { - continue; - } - if (trackNeg1.isSel3Prong() == 0) { - continue; - } - - // second loop over positive tracks - //for (auto trackPos2 = trackPos1 + 1; trackPos2 != tracksPos.end(); ++trackPos2) { - for (auto trackPos2 = trackPos1 + 1; trackPos2 != tracks.end(); ++trackPos2) { - if (trackPos2.signed1Pt() < 0) { - continue; - } - if (trackPos2.isSel3Prong() == 0) { - continue; - } - - auto pVecCandProng3Pos = RecoDecay::PVec(pVecCandProng2, array{trackPos2.px(), trackPos2.py(), trackPos2.pz()}); - - // candidate pT cut - if (RecoDecay::Pt(pVecCandProng3Pos) < cut3ProngPtCandMin) { - continue; - } - - // invariant-mass cut - if (cut3ProngInvMassDPlusMin >= 0. && cut3ProngInvMassDPlusMax > 0.) { - // calculate invariant mass - auto arr3Mom = array{ - array{trackPos1.px(), trackPos1.py(), trackPos1.pz()}, - array{trackNeg1.px(), trackNeg1.py(), trackNeg1.pz()}, - array{trackPos2.px(), trackPos2.py(), trackPos2.pz()}}; - mass3PiKPi = RecoDecay::M(std::move(arr3Mom), array{massPi, massK, massPi}); - if (mass3PiKPi < cut3ProngInvMassDPlusMin || mass3PiKPi > cut3ProngInvMassDPlusMax) { - continue; - } - } - - // reconstruct the 3-prong secondary vertex - auto trackParVarPos2 = getTrackParCov(trackPos2); - if (df3.process(trackParVarPos1, trackParVarNeg1, trackParVarPos2) == 0) { - continue; - } - - // get secondary vertex - const auto& secondaryVertex3 = df3.getPCACandidate(); - // get track momenta - array<float, 3> pvec0; - array<float, 3> pvec1; - array<float, 3> pvec2; - df3.getTrack(0).getPxPyPzGlo(pvec0); - df3.getTrack(1).getPxPyPzGlo(pvec1); - df3.getTrack(2).getPxPyPzGlo(pvec2); - - // CPA cut - if (cut3ProngCPAMin > -2.) { - pVecCandProng3Pos = RecoDecay::PVec(pvec0, pvec1, pvec2); - auto cpa = RecoDecay::CPA(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex3, pVecCandProng3Pos); - if (cpa < cut3ProngCPAMin) { - continue; - } - } - - // decay length cut - if (cut3ProngDecLenMin > 0.) { - auto decayLength = RecoDecay::distance(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex3); - if (decayLength < cut3ProngDecLenMin) { - continue; - } - } - - // fill table row - rowTrackIndexProng3(trackPos1.globalIndex(), - trackNeg1.globalIndex(), - trackPos2.globalIndex(), 2); - - // fill histograms - if (b_dovalplots) { - hvtx3_x->Fill(secondaryVertex3[0]); - hvtx3_y->Fill(secondaryVertex3[1]); - hvtx3_z->Fill(secondaryVertex3[2]); - - // calculate invariant mass - hmass3->Fill(RecoDecay::M(array{pvec0, pvec1, pvec2}, array{massPi, massK, massPi})); - } - } - - // second loop over negative tracks - //for (auto trackNeg2 = trackNeg1 + 1; trackNeg2 != tracksNeg.end(); ++trackNeg2) { - for (auto trackNeg2 = trackNeg1 + 1; trackNeg2 != tracks.end(); ++trackNeg2) { - if (trackNeg2.signed1Pt() > 0) { - continue; - } - if (trackNeg2.isSel3Prong() == 0) { - continue; - } - - auto pVecCandProng3Neg = RecoDecay::PVec(pVecCandProng2, array{trackNeg2.px(), trackNeg2.py(), trackNeg2.pz()}); - - // candidate pT cut - if (RecoDecay::Pt(pVecCandProng3Neg) < cut3ProngPtCandMin) { - continue; - } - - // invariant-mass cut - if (cut3ProngInvMassDPlusMin >= 0. && cut3ProngInvMassDPlusMax > 0.) { - // calculate invariant mass - auto arr3Mom = array{ - array{trackNeg1.px(), trackNeg1.py(), trackNeg1.pz()}, - array{trackPos1.px(), trackPos1.py(), trackPos1.pz()}, - array{trackNeg2.px(), trackNeg2.py(), trackNeg2.pz()}}; - mass3PiKPi = RecoDecay::M(std::move(arr3Mom), array{massPi, massK, massPi}); - if (mass3PiKPi < cut3ProngInvMassDPlusMin || mass3PiKPi > cut3ProngInvMassDPlusMax) { - continue; - } - } - - // reconstruct the 3-prong secondary vertex - auto trackParVarNeg2 = getTrackParCov(trackNeg2); - if (df3.process(trackParVarNeg1, trackParVarPos1, trackParVarNeg2) == 0) { - continue; - } - - // get secondary vertex - const auto& secondaryVertex3 = df3.getPCACandidate(); - // get track momenta - array<float, 3> pvec0; - array<float, 3> pvec1; - array<float, 3> pvec2; - df3.getTrack(0).getPxPyPzGlo(pvec0); - df3.getTrack(1).getPxPyPzGlo(pvec1); - df3.getTrack(2).getPxPyPzGlo(pvec2); - - // CPA cut - if (cut3ProngCPAMin > -2.) { - pVecCandProng3Neg = RecoDecay::PVec(pvec0, pvec1, pvec2); - auto cpa = RecoDecay::CPA(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex3, pVecCandProng3Neg); - if (cpa < cut3ProngCPAMin) { - continue; - } - } - - // decay length cut - if (cut3ProngDecLenMin > 0.) { - auto decayLength = RecoDecay::distance(array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex3); - if (decayLength < cut3ProngDecLenMin) { - continue; - } - } - - // fill table row - rowTrackIndexProng3(trackNeg1.globalIndex(), - trackPos1.globalIndex(), - trackNeg2.globalIndex(), 2); - - // fill histograms - if (b_dovalplots) { - hvtx3_x->Fill(secondaryVertex3[0]); - hvtx3_y->Fill(secondaryVertex3[1]); - hvtx3_z->Fill(secondaryVertex3[2]); - - // calculate invariant mass - hmass3->Fill(RecoDecay::M(array{pvec0, pvec1, pvec2}, array{massPi, massK, massPi})); - } - } - } - } - } - /* - auto nTracks = tracks.size(); // number of tracks in this collision - nCand2 = rowTrackIndexProng2.lastIndex() - nCand2; // number of 2-prong candidates in this collision - nCand3 = rowTrackIndexProng3.lastIndex() - nCand3; // number of 3-prong candidates in this collision - hNTracks->Fill(nTracks); - hNCand2Prong->Fill(nCand2); - hNCand3Prong->Fill(nCand3); - hNCand2ProngVsNTracks->Fill(nTracks, nCand2); - hNCand3ProngVsNTracks->Fill(nTracks, nCand3); - */ - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<SelectTracks>("hf-produce-sel-track"), - adaptAnalysisTask<HFTrackIndexSkimsCreator>("hf-track-index-skims-creator")}; -} diff --git a/Analysis/Tasks/PWGHF/taskD0.cxx b/Analysis/Tasks/PWGHF/taskD0.cxx deleted file mode 100644 index 2ebaedb605b11..0000000000000 --- a/Analysis/Tasks/PWGHF/taskD0.cxx +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file taskD0.cxx -/// \brief D0 analysis task -/// -/// \author Gian Michele Innocenti <gian.michele.innocenti@cern.ch>, CERN -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::aod::hf_cand_prong2; -using namespace o2::framework::expressions; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, false, {"Fill MC histograms."}}; - workflowOptions.push_back(optionDoMC); -} - -#include "Framework/runDataProcessing.h" - -/// D0 analysis task -struct TaskD0 { - HistogramRegistry registry{ - "registry", - {{"hmass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}}, - {"hptcand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hptprong0", "2-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hptprong1", "2-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hdeclength", "2-prong candidates;decay length (cm);entries", {HistType::kTH1F, {{200, 0., 2.}}}}, - {"hdeclengthxy", "2-prong candidates;decay length xy (cm);entries", {HistType::kTH1F, {{200, 0., 2.}}}}, - {"hd0Prong0", "2-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"hd0Prong1", "2-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"hd0d0", "2-prong candidates;product of DCAxy to prim. vertex (cm^{2});entries", {HistType::kTH1F, {{500, -1., 1.}}}}, - {"hCTS", "2-prong candidates;cos #it{#theta}* (D^{0});entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"hCt", "2-prong candidates;proper lifetime (D^{0}) * #it{c} (cm);entries", {HistType::kTH1F, {{120, -20., 100.}}}}, - {"hCPA", "2-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"hEta", "2-prong candidates;candidate #it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"hselectionstatus", "2-prong candidates;selection status;entries", {HistType::kTH1F, {{5, -0.5, 4.5}}}}, - {"hImpParErr", "2-prong candidates;impact parameter error (cm);entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"hDecLenErr", "2-prong candidates;decay length error (cm);entries", {HistType::kTH1F, {{100, 0., 1.}}}}, - {"hDecLenXYErr", "2-prong candidates;decay length xy error (cm);entries", {HistType::kTH1F, {{100, 0., 1.}}}}}}; - - Configurable<int> d_selectionFlagD0{"d_selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable<int> d_selectionFlagD0bar{"d_selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable<double> cutEtaCandMax{"cutEtaCandMax", -1., "max. cand. pseudorapidity"}; - - Filter filterSelectCandidates = (aod::hf_selcandidate_d0::isSelD0 >= d_selectionFlagD0 || aod::hf_selcandidate_d0::isSelD0bar >= d_selectionFlagD0bar); - - void process(soa::Filtered<soa::Join<aod::HfCandProng2, aod::HFSelD0Candidate>> const& candidates) - { - //Printf("Candidates: %d", candidates.size()); - for (auto& candidate : candidates) { - if (cutEtaCandMax >= 0. && std::abs(candidate.eta()) > cutEtaCandMax) { - //Printf("Candidate: eta rejection: %g", candidate.eta()); - continue; - } - if (candidate.isSelD0() >= d_selectionFlagD0) { - registry.get<TH1>("hmass")->Fill(InvMassD0(candidate)); - } - if (candidate.isSelD0bar() >= d_selectionFlagD0bar) { - registry.get<TH1>("hmass")->Fill(InvMassD0bar(candidate)); - } - registry.get<TH1>("hptcand")->Fill(candidate.pt()); - registry.get<TH1>("hptprong0")->Fill(candidate.ptProng0()); - registry.get<TH1>("hptprong1")->Fill(candidate.ptProng1()); - registry.get<TH1>("hdeclength")->Fill(candidate.decayLength()); - registry.get<TH1>("hdeclengthxy")->Fill(candidate.decayLengthXY()); - registry.get<TH1>("hd0Prong0")->Fill(candidate.impactParameter0()); - registry.get<TH1>("hd0Prong1")->Fill(candidate.impactParameter1()); - registry.get<TH1>("hd0d0")->Fill(candidate.impactParameterProduct()); - registry.get<TH1>("hCTS")->Fill(CosThetaStarD0(candidate)); - registry.get<TH1>("hCt")->Fill(CtD0(candidate)); - registry.get<TH1>("hCPA")->Fill(candidate.cpa()); - registry.get<TH1>("hEta")->Fill(candidate.eta()); - registry.get<TH1>("hselectionstatus")->Fill(candidate.isSelD0() + (candidate.isSelD0bar() * 2)); - registry.get<TH1>("hImpParErr")->Fill(candidate.errorImpactParameter0()); - registry.get<TH1>("hImpParErr")->Fill(candidate.errorImpactParameter1()); - registry.get<TH1>("hDecLenErr")->Fill(candidate.errorDecayLength()); - registry.get<TH1>("hDecLenXYErr")->Fill(candidate.errorDecayLengthXY()); - } - } -}; - -/// Fills MC histograms. -struct TaskD0MC { - HistogramRegistry registry{ - "registry", - {{"hPtRecSig", "2-prong candidates (rec. matched);#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hPtRecBg", "2-prong candidates (rec. unmatched);#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hPtGen", "2-prong candidates (gen. matched);#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"hCPARecSig", "2-prong candidates (rec. matched);cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"hCPARecBg", "2-prong candidates (rec. unmatched);cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"hEtaRecSig", "2-prong candidates (rec. matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"hEtaRecBg", "2-prong candidates (rec. unmatched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"hEtaGen", "2-prong candidates (gen. matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}}}; - - Configurable<int> d_selectionFlagD0{"d_selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable<int> d_selectionFlagD0bar{"d_selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable<double> cutEtaCandMax{"cutEtaCandMax", -1., "max. cand. pseudorapidity"}; - - Filter filterSelectCandidates = (aod::hf_selcandidate_d0::isSelD0 >= d_selectionFlagD0 || aod::hf_selcandidate_d0::isSelD0bar >= d_selectionFlagD0bar); - - void process(soa::Filtered<soa::Join<aod::HfCandProng2, aod::HFSelD0Candidate, aod::HfCandProng2MCRec>> const& candidates, - soa::Join<aod::McParticles, aod::HfCandProng2MCGen> const& particlesMC) - { - // MC rec. - //Printf("MC Candidates: %d", candidates.size()); - for (auto& candidate : candidates) { - if (cutEtaCandMax >= 0. && std::abs(candidate.eta()) > cutEtaCandMax) { - //Printf("MC Rec.: eta rejection: %g", candidate.eta()); - continue; - } - if (candidate.flagMCMatchRec() == 1) { - registry.get<TH1>("hPtRecSig")->Fill(candidate.pt()); - registry.get<TH1>("hCPARecSig")->Fill(candidate.cpa()); - registry.get<TH1>("hEtaRecSig")->Fill(candidate.eta()); - } else { - registry.get<TH1>("hPtRecBg")->Fill(candidate.pt()); - registry.get<TH1>("hCPARecBg")->Fill(candidate.cpa()); - registry.get<TH1>("hEtaRecBg")->Fill(candidate.eta()); - } - } - // MC gen. - //Printf("MC Particles: %d", particlesMC.size()); - for (auto& particle : particlesMC) { - if (cutEtaCandMax >= 0. && std::abs(particle.eta()) > cutEtaCandMax) { - //Printf("MC Gen.: eta rejection: %g", particle.eta()); - continue; - } - if (particle.flagMCMatchGen() == 1) { - registry.get<TH1>("hPtGen")->Fill(particle.pt()); - registry.get<TH1>("hEtaGen")->Fill(particle.eta()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{ - adaptAnalysisTask<TaskD0>("hf-task-d0")}; - const bool doMC = cfgc.options().get<bool>("doMC"); - if (doMC) { - workflow.push_back(adaptAnalysisTask<TaskD0MC>("hf-task-d0-mc")); - } - return workflow; -} diff --git a/Analysis/Tasks/PWGHF/taskDPlus.cxx b/Analysis/Tasks/PWGHF/taskDPlus.cxx deleted file mode 100644 index e422476a556f0..0000000000000 --- a/Analysis/Tasks/PWGHF/taskDPlus.cxx +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file taskDPlus.cxx -/// \brief D± analysis task -/// \note Extended from taskD0 -/// -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::aod::hf_cand_prong3; -//using namespace o2::framework::expressions; - -/// D± analysis task -struct TaskDPlus { - OutputObj<TH1F> hmass{TH1F("hmass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", 500, 1.6, 2.1)}; - OutputObj<TH1F> hptcand{TH1F("hptcand", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong0{TH1F("hptprong0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong1{TH1F("hptprong1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong2{TH1F("hptprong2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hdeclength{TH1F("declength", "3-prong candidates;decay length (cm);entries", 200, 0., 2.)}; - OutputObj<TH1F> hdeclengthxy{TH1F("declengthxy", "3-prong candidates;decay length xy (cm);entries", 200, 0., 2.)}; - OutputObj<TH1F> hd0Prong0{TH1F("hd0Prong0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hd0Prong1{TH1F("hd0Prong1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hd0Prong2{TH1F("hd0Prong2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hCt{TH1F("hCt", "3-prong candidates;proper lifetime (D^{#pm}) * #it{c} (cm);entries", 120, -20., 100.)}; - OutputObj<TH1F> hCPA{TH1F("hCPA", "3-prong candidates;cosine of pointing angle;entries", 110, -1.1, 1.1)}; - OutputObj<TH1F> hEta{TH1F("hEta", "3-prong candidates;candidate #it{#eta};entries", 100, -2., 2.)}; - //OutputObj<TH1F> hselectionstatus{TH1F("selectionstatus", "3-prong candidates;selection status;entries", 5, -0.5, 4.5)}; - OutputObj<TH1F> hImpParErr{TH1F("hImpParErr", "3-prong candidates;impact parameter error (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hDecLenErr{TH1F("hDecLenErr", "3-prong candidates;decay length error (cm);entries", 100, 0., 1.)}; - OutputObj<TH1F> hDecLenXYErr{TH1F("hDecLenXYErr", "3-prong candidates;decay length xy error (cm);entries", 100, 0., 1.)}; - - Configurable<int> d_selectionFlagDPlus{"d_selectionFlagDPlus", 1, "Selection Flag for DPlus"}; - - //Filter filterSelectCandidates = (aod::hf_selcandidate::isSelDPlus >= d_selectionFlagDPlus); - - //void process(soa::Filtered<soa::Join<aod::HfCandProng3, aod::HFSelDPlusCandidate>> const& candidates) - void process(aod::HfCandProng3 const& candidates) - { - for (auto& candidate : candidates) { - hmass->Fill(InvMassDPlus(candidate)); - hptcand->Fill(candidate.pt()); - hptprong0->Fill(candidate.ptProng0()); - hptprong1->Fill(candidate.ptProng1()); - hptprong2->Fill(candidate.ptProng2()); - hdeclength->Fill(candidate.decayLength()); - hdeclengthxy->Fill(candidate.decayLengthXY()); - hd0Prong0->Fill(candidate.impactParameter0()); - hd0Prong1->Fill(candidate.impactParameter1()); - hd0Prong2->Fill(candidate.impactParameter2()); - hCt->Fill(CtDPlus(candidate)); - hCPA->Fill(candidate.cpa()); - hEta->Fill(candidate.eta()); - //hselectionstatus->Fill(candidate.isSelDPlus()); - hImpParErr->Fill(candidate.errorImpactParameter0()); - hImpParErr->Fill(candidate.errorImpactParameter1()); - hImpParErr->Fill(candidate.errorImpactParameter2()); - hDecLenErr->Fill(candidate.errorDecayLength()); - hDecLenXYErr->Fill(candidate.errorDecayLengthXY()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<TaskDPlus>("hf-task-dplus")}; -} diff --git a/Analysis/Tasks/PWGHF/taskLc.cxx b/Analysis/Tasks/PWGHF/taskLc.cxx deleted file mode 100644 index ca721dbc97e9e..0000000000000 --- a/Analysis/Tasks/PWGHF/taskLc.cxx +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file taskDPlus.cxx -/// \brief D± analysis task -/// \note Extended from taskD0 -/// -/// \author Vít Kučera <vit.kucera@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::aod::hf_cand_prong3; -using namespace o2::framework::expressions; - -/// Lc+ analysis task -struct TaskLc { - OutputObj<TH1F> hmass{TH1F("hmass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", 500, 1.6, 3.1)}; - OutputObj<TH1F> hptcand{TH1F("hptcand", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong0{TH1F("hptprong0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong1{TH1F("hptprong1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hptprong2{TH1F("hptprong2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)}; - OutputObj<TH1F> hdeclength{TH1F("declength", "3-prong candidates;decay length (cm);entries", 200, 0., 2.)}; - OutputObj<TH1F> hd0Prong0{TH1F("hd0Prong0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hd0Prong1{TH1F("hd0Prong1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hd0Prong2{TH1F("hd0Prong2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hCt{TH1F("hCt", "3-prong candidates;proper lifetime (D^{#pm}) * #it{c} (cm);entries", 120, -20., 100.)}; - OutputObj<TH1F> hCPA{TH1F("hCPA", "3-prong candidates;cosine of pointing angle;entries", 110, -1.1, 1.1)}; - OutputObj<TH1F> hEta{TH1F("hEta", "3-prong candidates;candidate #it{#eta};entries", 100, -2., 2.)}; - //OutputObj<TH1F> hselectionstatus{TH1F("selectionstatus", "3-prong candidates;selection status;entries", 5, -0.5, 4.5)}; - OutputObj<TH1F> hImpParErr{TH1F("hImpParErr", "3-prong candidates;impact parameter error (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hDecLenErr{TH1F("hDecLenErr", "3-prong candidates;decay length error (cm);entries", 100, 0., 1.)}; - //OutputObj<TH1F> hdca{TH1F("hdca", "3-prong candidates;prongs DCA to prim. vertex (cm);entries", 100, -1., 1.)}; - OutputObj<TH1F> hdca2{TH1F("hdca2", "3-prong candidates;prongs DCA to sec. vertex (cm);entries", 100, 0., 1.)}; - - Configurable<int> d_selectionFlagLc{"d_selectionFlagLc", 1, "Selection Flag for Lc"}; - - Filter filterSelectCandidates = (aod::hf_selcandidate_lc::isSelLc >= d_selectionFlagLc); - - //void process(aod::HfCandProng3 const& candidates) - void process(soa::Filtered<soa::Join<aod::HfCandProng3, aod::HFSelLcCandidate>> const& candidates) - { - for (auto& candidate : candidates) { - if (candidate.isSelLc() >= d_selectionFlagLc) { - hmass->Fill(InvMassLc(candidate)); - } - hptcand->Fill(candidate.pt()); - hptprong0->Fill(candidate.ptProng0()); - hptprong1->Fill(candidate.ptProng1()); - hptprong2->Fill(candidate.ptProng2()); - hdeclength->Fill(candidate.decayLength()); - hd0Prong0->Fill(candidate.impactParameter0()); - hd0Prong1->Fill(candidate.impactParameter1()); - hd0Prong2->Fill(candidate.impactParameter2()); - hCt->Fill(CtLc(candidate)); - hCPA->Fill(candidate.cpa()); - hEta->Fill(candidate.eta()); - //hselectionstatus->Fill(candidate.isSelLc()); - hImpParErr->Fill(candidate.errorImpactParameter0()); - hImpParErr->Fill(candidate.errorImpactParameter1()); - hImpParErr->Fill(candidate.errorImpactParameter2()); - hDecLenErr->Fill(candidate.errorDecayLength()); - // hdca->Fill(candidate.dca()); - hdca2->Fill(candidate.chi2PCA()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<TaskLc>("hf-task-lc")}; -} diff --git a/Analysis/Tasks/PWGJE/CMakeLists.txt b/Analysis/Tasks/PWGJE/CMakeLists.txt deleted file mode 100644 index d0afc844d3375..0000000000000 --- a/Analysis/Tasks/PWGJE/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - - -if(FastJet_FOUND) -o2_add_dpl_workflow(jet-finder - SOURCES jetfinder.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisJets O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(jet-finder-hf - SOURCES jetfinderhf.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisJets O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(jet-finder-hadron-recoil - SOURCES jetfinderhadronrecoil.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisJets O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(jet-substructure - SOURCES jetsubstructure.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisJets O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(jet-skimmer - SOURCES jetskimming.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisJets O2::AnalysisDataModel - COMPONENT_NAME Analysis) -endif() - diff --git a/Analysis/Tasks/PWGJE/jetfinder.cxx b/Analysis/Tasks/PWGJE/jetfinder.cxx deleted file mode 100644 index c5acbad3493a0..0000000000000 --- a/Analysis/Tasks/PWGJE/jetfinder.cxx +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet finder task -// -// Author: Jochen Klein, Nima Zardoshti - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "Analysis/Jet.h" -#include "Analysis/JetFinder.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetFinderTask { - Produces<o2::aod::Jets> jetsTable; - Produces<o2::aod::JetConstituents> constituentsTable; - Produces<o2::aod::JetConstituentsSub> constituentsSubTable; - OutputObj<TH1F> hJetPt{"h_jet_pt"}; - OutputObj<TH1F> hJetPhi{"h_jet_phi"}; - OutputObj<TH1F> hJetEta{"h_jet_eta"}; - OutputObj<TH1F> hJetN{"h_jet_n"}; - - Configurable<bool> b_DoRhoAreaSub{"b_DoRhoAreaSub", false, "do rho area subtraction"}; - Configurable<bool> b_DoConstSub{"b_DoConstSub", false, "do constituent subtraction"}; - - Filter trackCuts = aod::track::pt >= 0.15f && aod::track::eta >= -0.9f && aod::track::eta <= 0.9f; - - std::vector<fastjet::PseudoJet> jets; - std::vector<fastjet::PseudoJet> inputParticles; - JetFinder jetFinder; - - void init(InitContext const&) - { - hJetPt.setObject(new TH1F("h_jet_pt", "jet p_{T};p_{T} (GeV/#it{c})", - 100, 0., 100.)); - hJetPhi.setObject(new TH1F("h_jet_phi", "jet #phi;#phi", - 80, -1., 7.)); - hJetEta.setObject(new TH1F("h_jet_eta", "jet #eta;#eta", - 70, -0.7, 0.7)); - hJetN.setObject(new TH1F("h_jet_n", "jet n;n constituents", - 30, 0., 30.)); - if (b_DoRhoAreaSub) { - jetFinder.setBkgSubMode(JetFinder::BkgSubMode::rhoAreaSub); - } - if (b_DoConstSub) { - jetFinder.setBkgSubMode(JetFinder::BkgSubMode::constSub); - } - } - - void process(aod::Collision const& collision, - soa::Filtered<aod::Tracks> const& tracks) - { - - jets.clear(); - inputParticles.clear(); - - for (auto& track : tracks) { - /* auto energy = std::sqrt(track.p() * track.p() + mPion*mPion); - inputParticles.emplace_back(track.px(), track.py(), track.pz(), energy); - inputParticles.back().set_user_index(track.globalIndex());*/ - fillConstituents(track, inputParticles); - inputParticles.back().set_user_index(track.globalIndex()); - } - - fastjet::ClusterSequenceArea clusterSeq(jetFinder.findJets(inputParticles, jets)); - - for (const auto& jet : jets) { - jetsTable(collision, jet.pt(), jet.eta(), jet.phi(), - jet.E(), jet.m(), jet.area()); - hJetPt->Fill(jet.pt()); - hJetPhi->Fill(jet.phi()); - hJetEta->Fill(jet.eta()); - hJetN->Fill(jet.constituents().size()); - for (const auto& constituent : jet.constituents()) { //event or jetwise - if (b_DoConstSub) { - constituentsSubTable(jetsTable.lastIndex(), constituent.pt(), constituent.eta(), constituent.phi(), - constituent.E(), constituent.m()); - } - constituentsTable(jetsTable.lastIndex(), constituent.user_index()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetFinderTask>("jet-finder")}; -} diff --git a/Analysis/Tasks/PWGJE/jetfinderhadronrecoil.cxx b/Analysis/Tasks/PWGJE/jetfinderhadronrecoil.cxx deleted file mode 100644 index 6e163be961b05..0000000000000 --- a/Analysis/Tasks/PWGJE/jetfinderhadronrecoil.cxx +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet finder task -// -// Author: Nima Zardoshti - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "Analysis/Jet.h" -#include "Analysis/JetFinder.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetFinderHadronRecoilTask { - OutputObj<TH1F> hJetPt{"h_jet_pt"}; - OutputObj<TH1F> hHadronPt{"h_hadron_pt"}; - OutputObj<TH1F> hJetHadronDeltaPhi{"h_jet_hadron_deltaphi"}; - - Configurable<float> f_trackTTMin{"f_trackTTMin", 8.0, "TT hadron min pT"}; - Configurable<float> f_trackTTMax{"f_trackTTMax", 9.0, "TT hadron max pT"}; - Configurable<float> f_recoilWindow{"f_recoilWindow", 0.6, "jet finding phi window reecoilling from hadron"}; - - Filter trackCuts = aod::track::pt >= 0.15f && aod::track::eta > -0.9f && aod::track::eta < 0.9f; - int collisionSplit = 0; //can we partition the collisions? - //can we also directly filter the collision based on the max track::pt? - - std::vector<float> trackTTPt; - std::vector<fastjet::PseudoJet> jets; - std::vector<fastjet::PseudoJet> inputParticles; - JetFinder jetFinder; - - template <typename T> - T relativePhi(T phi1, T phi2) - { - if (phi1 < -TMath::Pi()) { - phi1 += (2 * TMath::Pi()); - } else if (phi1 > TMath::Pi()) { - phi1 -= (2 * TMath::Pi()); - } - if (phi2 < -TMath::Pi()) { - phi2 += (2 * TMath::Pi()); - } else if (phi2 > TMath::Pi()) { - phi2 -= (2 * TMath::Pi()); - } - T deltaPhi = phi2 - phi1; - if (deltaPhi < -TMath::Pi()) { - deltaPhi += (2 * TMath::Pi()); - } else if (deltaPhi > TMath::Pi()) { - deltaPhi -= (2 * TMath::Pi()); - } - return deltaPhi; - } - - void init(InitContext const&) - { - hJetPt.setObject(new TH1F("h_jet_pt", "jet p_{T};jet p_{T} (GeV/#it{c})", - 100, 0., 100.)); - hHadronPt.setObject(new TH1F("h_hadron_pt", "hadron p_{T};hadron p_{T} (GeV/#it{c})", - 120, 0., 60.)); - hJetHadronDeltaPhi.setObject(new TH1F("h_jet_hadron_deltaphi", "jet #eta;#eta", - 40, 0.0, 4.)); - } - - void process(aod::Collision const& collision, - soa::Filtered<aod::Tracks> const& tracks) - { - - jets.clear(); - inputParticles.clear(); - auto trackTTPhi = 0.0; - auto trackTTPt = 0.0; - auto comparisonPt = 0.0; - bool isTT = false; - for (auto& track : tracks) { - if (track.pt() >= f_trackTTMin && track.pt() < f_trackTTMax) { //can this also go into a partition? - isTT = true; - if (track.pt() >= comparisonPt) { //currently take highest pT but later to randomise - comparisonPt = track.pt(); - trackTTPt = track.pt(); - trackTTPhi = track.phi(); - } - } - auto energy = std::sqrt(track.p() * track.p() + JetFinder::mPion * JetFinder::mPion); - inputParticles.emplace_back(track.px(), track.py(), track.pz(), energy); - inputParticles.back().set_user_index(track.globalIndex()); - } - if (!isTT) { - return; - } - hHadronPt->Fill(trackTTPt); - - // you can set phi selector here for jets - fastjet::ClusterSequenceArea clusterSeq(jetFinder.findJets(inputParticles, jets)); - - for (const auto& jet : jets) { - auto deltaPhi = TMath::Abs(relativePhi(jet.phi(), trackTTPhi)); - if (deltaPhi >= (TMath::Pi() - f_recoilWindow)) { - hJetPt->Fill(jet.pt()); - } - if (deltaPhi >= TMath::Pi() / 2.0 && deltaPhi <= TMath::Pi()) { - hJetHadronDeltaPhi->Fill(deltaPhi); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetFinderHadronRecoilTask>("jet-finder-hadron-recoil")}; -} diff --git a/Analysis/Tasks/PWGJE/jetfinderhf.cxx b/Analysis/Tasks/PWGJE/jetfinderhf.cxx deleted file mode 100644 index 5f6bc347f7528..0000000000000 --- a/Analysis/Tasks/PWGJE/jetfinderhf.cxx +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet finder task -// -// Author: Nima Zardoshti - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "Analysis/HFSecondaryVertex.h" -#include "Analysis/HFCandidateSelectionTables.h" - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" - -#include "Analysis/Jet.h" -#include "Analysis/JetFinder.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetFinderHFTask { - Produces<o2::aod::Jets> jetsTable; - Produces<o2::aod::JetConstituents> constituents; - OutputObj<TH1F> hJetPt{"h_jet_pt"}; - OutputObj<TH1F> hD0Pt{"h_D0_pt"}; - - std::vector<fastjet::PseudoJet> jets; - std::vector<fastjet::PseudoJet> inputParticles; - JetFinder jetFinder; - - void init(InitContext const&) - { - hJetPt.setObject(new TH1F("h_jet_pt", "jet p_{T};p_{T} (GeV/#it{c})", - 100, 0., 100.)); - hD0Pt.setObject(new TH1F("h_D0_pt", "jet p_{T,D};p_{T,D} (GeV/#it{c})", - 60, 0., 60.)); - } - - Configurable<int> d_selectionFlagD0{"d_selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable<int> d_selectionFlagD0bar{"d_selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - - //need enum as configurable - enum pdgCode { pdgD0 = 421 }; - - Filter trackCuts = (aod::track::pt > 0.15f && aod::track::eta > -0.9f && aod::track::eta < 0.9f); - Filter seltrack = (aod::hf_selcandidate_d0::isSelD0 >= d_selectionFlagD0 || aod::hf_selcandidate_d0::isSelD0bar >= d_selectionFlagD0bar); - - void process(aod::Collision const& collision, - soa::Filtered<aod::Tracks> const& tracks, - soa::Filtered<soa::Join<aod::HfCandProng2, aod::HFSelD0Candidate>> const& candidates) - { - std::cout << "Per Event" << std::endl; - // TODO: retrieve pion mass from somewhere - bool isHFJet; - - //this loop should be made more efficient - for (auto& candidate : candidates) { - jets.clear(); - inputParticles.clear(); - for (auto& track : tracks) { - auto energy = std::sqrt(track.p() * track.p() + JetFinder::mPion * JetFinder::mPion); - if (candidate.index0().globalIndex() == track.globalIndex() || candidate.index1().globalIndex() == track.globalIndex()) { //is it global index? - continue; - } - inputParticles.emplace_back(track.px(), track.py(), track.pz(), energy); - inputParticles.back().set_user_index(track.globalIndex()); - } - inputParticles.emplace_back(candidate.px(), candidate.py(), candidate.pz(), candidate.e(RecoDecay::getMassPDG(pdgD0))); - inputParticles.back().set_user_index(1); - - fastjet::ClusterSequenceArea clusterSeq(jetFinder.findJets(inputParticles, jets)); - - for (const auto& jet : jets) { - isHFJet = false; - for (const auto& constituent : jet.constituents()) { - if (constituent.user_index() == 1 && (candidate.isSelD0() == 1 || candidate.isSelD0bar() == 1)) { - isHFJet = true; - break; - } - } - if (isHFJet) { - jetsTable(collision, jet.eta(), jet.phi(), jet.pt(), - jet.area(), jet.E(), jet.m()); - for (const auto& constituent : jet.constituents()) { - constituents(jetsTable.lastIndex(), constituent.user_index()); - } - hJetPt->Fill(jet.pt()); - std::cout << "Filling" << std::endl; - hD0Pt->Fill(candidate.pt()); - break; - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetFinderHFTask>("jet-finder-hf")}; -} diff --git a/Analysis/Tasks/PWGJE/jetskimming.cxx b/Analysis/Tasks/PWGJE/jetskimming.cxx deleted file mode 100644 index 490ce1e284e3b..0000000000000 --- a/Analysis/Tasks/PWGJE/jetskimming.cxx +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet skimming task -// -// Author: Nima Zardoshti - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -namespace o2::aod -{ -namespace jetskim -{ -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Energy, energy, float); -} // namespace jetskim -DECLARE_SOA_TABLE(JetSkim, "AOD", "JETSKIM1", - jetskim::CollisionId, - jetskim::Pt, jetskim::Eta, jetskim::Phi, jetskim::Energy); -} // namespace o2::aod - -struct JetSkimmingTask1 { - Produces<o2::aod::JetSkim> skim; - - Filter trackCuts = aod::track::pt > 0.15f; - float mPionSquared = 0.139 * 0.139; - - void process(aod::Collision const& collision, - soa::Filtered<aod::Tracks> const& tracks) - { - for (auto& track : tracks) { - float energy = std::sqrt(track.p() * track.p() + mPionSquared); - skim(collision, track.pt(), track.eta(), track.phi(), energy); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetSkimmingTask1>("jet-skimmer")}; -} diff --git a/Analysis/Tasks/PWGJE/jetsubstructure.cxx b/Analysis/Tasks/PWGJE/jetsubstructure.cxx deleted file mode 100644 index d50ea4a07c79f..0000000000000 --- a/Analysis/Tasks/PWGJE/jetsubstructure.cxx +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet analysis tasks (subscribing to jet finder task) -// -// Author: Nima Zardoshti -// - -#include "TH1F.h" -#include "TTree.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "Analysis/Jet.h" -#include "Analysis/JetFinder.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -namespace o2::aod -{ -namespace jetsubstructure -{ -DECLARE_SOA_COLUMN(Zg, zg, float); -DECLARE_SOA_COLUMN(Rg, rg, float); -DECLARE_SOA_COLUMN(Nsd, nsd, float); -} // namespace jetsubstructure -DECLARE_SOA_TABLE(JetSubtructure, "AOD", "JETSUBSTRUCTURE", jetsubstructure::Zg, jetsubstructure::Rg, jetsubstructure::Nsd); -} // namespace o2::aod - -struct JetSubstructure { - Produces<aod::JetSubtructure> jetSubstructure; - OutputObj<TH1F> hZg{"h_jet_zg"}; - OutputObj<TH1F> hRg{"h_jet_rg"}; - OutputObj<TH1F> hNsd{"h_jet_nsd"}; - - Configurable<float> f_jetPtMin{"f_jetPtMin", 0.0, "minimum jet pT cut"}; - Configurable<float> f_zCut{"f_zCut", 0.1, "soft drop z cut"}; - Configurable<float> f_beta{"f_beta", 0.0, "soft drop beta"}; - Configurable<float> f_jetR{"f_jetR", 0.4, "jer resolution parameter"}; //possible to get configurable from another task? jetR - Configurable<bool> b_DoConstSub{"b_DoConstSub", false, "do constituent subtraction"}; - - std::vector<fastjet::PseudoJet> jetConstituents; - std::vector<fastjet::PseudoJet> jetReclustered; - JetFinder jetReclusterer; - - void init(InitContext const&) - { - hZg.setObject(new TH1F("h_jet_zg", "zg ;zg", - 10, 0.0, 0.5)); - hRg.setObject(new TH1F("h_jet_rg", "rg ;rg", - 10, 0.0, 0.5)); - hNsd.setObject(new TH1F("h_jet_nsd", "nsd ;nsd", - 7, -0.5, 6.5)); - jetReclusterer.isReclustering = true; - jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; - jetReclusterer.jetR = f_jetR * 2.5; - } - - //Filter jetCuts = aod::jet::pt > f_jetPtMin; //how does this work? - - void process(aod::Jet const& jet, - aod::Tracks const& tracks, - aod::JetConstituents const& constituents, - aod::JetConstituentsSub const& constituentsSub) - { - jetConstituents.clear(); - jetReclustered.clear(); - if (b_DoConstSub) { - for (const auto constituent : constituentsSub) { - fillConstituents(constituent, jetConstituents); - } - } else { - for (const auto constituentIndex : constituents) { - auto constituent = constituentIndex.track(); - fillConstituents(constituent, jetConstituents); - } - } - fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); - jetReclustered = sorted_by_pt(jetReclustered); - fastjet::PseudoJet daughterSubJet = jetReclustered[0]; - fastjet::PseudoJet parentSubJet1; - fastjet::PseudoJet parentSubJet2; - bool softDropped = false; - int nsd = 0.0; - auto zg = -1.0; - auto rg = -1.0; - while (daughterSubJet.has_parents(parentSubJet1, parentSubJet2)) { - if (parentSubJet1.perp() < parentSubJet2.perp()) { - std::swap(parentSubJet1, parentSubJet2); - } - auto z = parentSubJet2.perp() / (parentSubJet1.perp() + parentSubJet2.perp()); - auto r = parentSubJet1.delta_R(parentSubJet2); - if (z >= f_zCut * TMath::Power(r / f_jetR, f_beta)) { - if (!softDropped) { - zg = z; - rg = r; - hZg->Fill(zg); - hRg->Fill(rg); - softDropped = true; - } - nsd++; - } - daughterSubJet = parentSubJet1; - } - hNsd->Fill(nsd); - jetSubstructure(zg, rg, nsd); - } -}; -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetSubstructure>("jet-substructure")}; -} diff --git a/Analysis/Tasks/PWGLF/CMakeLists.txt b/Analysis/Tasks/PWGLF/CMakeLists.txt deleted file mode 100644 index 6b1d703be7636..0000000000000 --- a/Analysis/Tasks/PWGLF/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_dpl_workflow(mc-spectra-efficiency - SOURCES mcspectraefficiency.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(spectra-tof - SOURCES spectraTOF.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(spectra-tpc - SOURCES spectraTPC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(nuclei-spectra - SOURCES NucleiSpectraTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(lambdakzeroproducer - SOURCES lambdakzeroproducer - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(lambdakzeroconsumer - SOURCES lambdakzeroconsumer - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(lambdakzerofinder - SOURCES lambdakzerofinder - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(cascadeproducer - SOURCES cascadeproducer - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(cascadeconsumer - SOURCES cascadeconsumer - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(cascadefinder - SOURCES cascadefinder - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsVertexing - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(raacharged - SOURCES raacharged.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME Analysis) - -o2_add_dpl_workflow(track-checks - SOURCES trackchecks.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - - diff --git a/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx b/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx deleted file mode 100644 index c95d2d798d03f..0000000000000 --- a/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -#include "PID/PIDResponse.h" - -#include <TH1F.h> -#include <TH2F.h> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct NucleiSpecraTask { - - OutputObj<TH2F> hTPCsignal{TH2F("hTPCsignal", ";#it{p} (GeV/#it{c}); d#it{E} / d#it{X} (a. u.)", 600, 0., 3, 1400, 0, 1400)}; - OutputObj<TH1F> hMomentum{TH1F("hMomentum", ";#it{p} (GeV/#it{c});", 600, 0., 3.)}; - - Configurable<float> absEtaMax{"absEtaMax", 0.8, "pseudo-rapidity edges"}; - Configurable<float> absYmax{"absYmax", 0.5, "rapidity edges"}; - Configurable<float> beamRapidity{"yBeam", 0., "beam rapidity"}; - Configurable<float> chi2TPCperNDF{"chi2TPCperNDF", 4., "chi2 per NDF in TPC"}; - Configurable<float> foundFractionTPC{"foundFractionTPC", 0., "TPC clusters / TPC crossed rows"}; - Configurable<int> recPointsTPC{"recPointsTPC", 0, "clusters in TPC"}; - Configurable<int> signalClustersTPC{"signalClustersTPC", 70, "clusters with PID in TPC"}; - Configurable<float> minEnergyLoss{"minEnergyLoss", 0., "energy loss in TPC"}; - Configurable<int> recPointsITS{"recPointsITS", 2, "number of ITS points"}; - Configurable<int> recPointsITSInnerBarrel{"recPointsITSInnerBarrel", 1, "number of points in ITS Inner Barrel"}; - - Filter etaFilter = aod::track::eta > -1 * absEtaMax&& aod::track::eta < absEtaMax; - Filter chi2Filter = aod::track::tpcChi2NCl < chi2TPCperNDF; - - void process(soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra>> const& tracks) - { - for (auto& track : tracks) { - // Part not covered by filters - if (track.tpcNClsFound() < recPointsTPC) { - continue; - } - if (track.itsNCls() < recPointsITS) { - continue; - } - if (track.itsNClsInnerBarrel() < recPointsITSInnerBarrel) { - continue; - } - - hTPCsignal->Fill(track.tpcInnerParam(), track.tpcSignal()); - hMomentum->Fill(track.p()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<NucleiSpecraTask>("nuclei-spectra")}; -} diff --git a/Analysis/Tasks/PWGLF/cascadeconsumer.cxx b/Analysis/Tasks/PWGLF/cascadeconsumer.cxx deleted file mode 100644 index 20f4696379910..0000000000000 --- a/Analysis/Tasks/PWGLF/cascadeconsumer.cxx +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "Analysis/StrangenessTables.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" - -#include <TFile.h> -#include <TH2F.h> -#include <TProfile.h> -#include <TLorentzVector.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> -#include "PID/PIDResponse.h" -#include "Framework/ASoAHelpers.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -struct cascadeQA { - //Basic checks - OutputObj<TH1F> hMassXiMinus{TH1F("hMassXiMinus", "", 3000, 0.0, 3.0)}; - OutputObj<TH1F> hMassXiPlus{TH1F("hMassXiPlus", "", 3000, 0.0, 3.0)}; - OutputObj<TH1F> hMassOmegaMinus{TH1F("hMassOmegaMinus", "", 3000, 0.0, 3.0)}; - OutputObj<TH1F> hMassOmegaPlus{TH1F("hMassOmegaPlus", "", 3000, 0.0, 3.0)}; - - OutputObj<TH1F> hV0Radius{TH1F("hV0Radius", "", 1000, 0.0, 100)}; - OutputObj<TH1F> hCascRadius{TH1F("hCascRadius", "", 1000, 0.0, 100)}; - OutputObj<TH1F> hV0CosPA{TH1F("hV0CosPA", "", 1000, 0.95, 1.0)}; - OutputObj<TH1F> hCascCosPA{TH1F("hCascCosPA", "", 1000, 0.95, 1.0)}; - OutputObj<TH1F> hDCAPosToPV{TH1F("hDCAPosToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCANegToPV{TH1F("hDCANegToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCABachToPV{TH1F("hDCABachToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCAV0ToPV{TH1F("hDCAV0ToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCAV0Dau{TH1F("hDCAV0Dau", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCACascDau{TH1F("hDCACascDau", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hLambdaMass{TH1F("hLambdaMass", "", 1000, 0.0, 10.0)}; - - void process(aod::Collision const& collision, soa::Join<aod::Cascades, aod::CascDataExt> const& Cascades) - { - for (auto& casc : Cascades) { - if (casc.charge() < 0) { //FIXME: could be done better... - hMassXiMinus->Fill(casc.mXi()); - hMassOmegaMinus->Fill(casc.mOmega()); - } else { - hMassXiPlus->Fill(casc.mXi()); - hMassOmegaPlus->Fill(casc.mOmega()); - } - //The basic eleven! - hV0Radius->Fill(casc.v0radius()); - hCascRadius->Fill(casc.cascradius()); - hV0CosPA->Fill(casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); - hCascCosPA->Fill(casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - hDCAPosToPV->Fill(casc.dcapostopv()); - hDCANegToPV->Fill(casc.dcanegtopv()); - hDCABachToPV->Fill(casc.dcabachtopv()); - hDCAV0ToPV->Fill(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); - hDCAV0Dau->Fill(casc.dcaV0daughters()); - hDCACascDau->Fill(casc.dcacascdaughters()); - hLambdaMass->Fill(casc.mLambda()); - } - } -}; - -struct cascadeconsumer { - OutputObj<TH3F> h3dMassXiMinus{TH3F("h3dMassXiMinus", "", 20, 0, 100, 200, 0, 10, 200, 1.322 - 0.100, 1.322 + 0.100)}; - OutputObj<TH3F> h3dMassXiPlus{TH3F("h3dMassXiPlus", "", 20, 0, 100, 200, 0, 10, 200, 1.322 - 0.100, 1.322 + 0.100)}; - OutputObj<TH3F> h3dMassOmegaMinus{TH3F("h3dMassOmegaMinus", "", 20, 0, 100, 200, 0, 10, 200, 1.672 - 0.100, 1.672 + 0.100)}; - OutputObj<TH3F> h3dMassOmegaPlus{TH3F("h3dMassOmegaPlus", "", 20, 0, 100, 200, 0, 10, 200, 1.672 - 0.100, 1.672 + 0.100)}; - - //Selection criteria - Configurable<double> v0cospa{"v0cospa", 0.999, "V0 CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<double> casccospa{"casccospa", 0.999, "Casc CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; - Configurable<float> dcacascdau{"dcacascdau", .3, "DCA Casc Daughters"}; - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - Configurable<float> dcabachtopv{"dcabachtopv", .1, "DCA Bach To PV"}; - Configurable<float> dcav0topv{"dcav0topv", .1, "DCA V0 To PV"}; - Configurable<float> v0radius{"v0radius", 2.0, "v0radius"}; - Configurable<float> cascradius{"cascradius", 1.0, "cascradius"}; - Configurable<float> v0masswindow{"v0masswindow", 0.008, "v0masswindow"}; - - Filter preFilterV0 = - aod::cascdata::dcapostopv > dcapostopv&& aod::cascdata::dcanegtopv > dcanegtopv&& - aod::cascdata::dcabachtopv > dcabachtopv&& - aod::cascdata::dcaV0daughters < dcav0dau&& aod::cascdata::dcacascdaughters < dcacascdau; - - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator const& collision, soa::Filtered<soa::Join<aod::Cascades, aod::CascDataExt>> const& Cascades) - { - if (!collision.alias()[kINT7]) { - return; - } - if (!collision.sel7()) { - return; - } - for (auto& casc : Cascades) { - //FIXME: dynamic columns cannot be filtered on? - if (casc.v0radius() > v0radius && - casc.cascradius() > cascradius && - casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > v0cospa && - casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospa && - casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) { - if (casc.charge() < 0) { //FIXME: could be done better... - if (TMath::Abs(casc.yXi()) < 0.5) { - h3dMassXiMinus->Fill(collision.centV0M(), casc.pt(), casc.mXi()); - } - if (TMath::Abs(casc.yOmega()) < 0.5) { - h3dMassOmegaMinus->Fill(collision.centV0M(), casc.pt(), casc.mOmega()); - } - } else { - if (TMath::Abs(casc.yXi()) < 0.5) { - h3dMassXiPlus->Fill(collision.centV0M(), casc.pt(), casc.mXi()); - } - if (TMath::Abs(casc.yOmega()) < 0.5) { - h3dMassOmegaPlus->Fill(collision.centV0M(), casc.pt(), casc.mOmega()); - } - } - } - } - } -}; - -/// Extends the v0data table with expression columns -struct cascadeinitializer { - Spawns<aod::CascDataExt> cascdataext; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<cascadeconsumer>("lf-cascadeconsumer"), - adaptAnalysisTask<cascadeQA>("lf-cascadeQA"), - adaptAnalysisTask<cascadeinitializer>("lf-cascadeinitializer")}; -} diff --git a/Analysis/Tasks/PWGLF/cascadefinder.cxx b/Analysis/Tasks/PWGLF/cascadefinder.cxx deleted file mode 100644 index fe786ab62a778..0000000000000 --- a/Analysis/Tasks/PWGLF/cascadefinder.cxx +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// This task re-reconstructs the V0s and cascades - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/HFSecondaryVertex.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "PID/PIDResponse.h" -#include "Analysis/StrangenessTables.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" - -#include <TFile.h> -#include <TLorentzVector.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TProfile.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; -using namespace ROOT::Math; - -namespace o2::aod -{ - -using V0FinderFull = soa::Join<aod::V0FinderData, aod::V0DataExt>; - -namespace cascgoodpostracks -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodPosTrack, goodPosTrack, int, FullTracks, "fGoodPosTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); -} // namespace cascgoodpostracks -DECLARE_SOA_TABLE(CascGoodPosTracks, "AOD", "CASCGOODPTRACKS", o2::soa::Index<>, cascgoodpostracks::GoodPosTrackId, cascgoodpostracks::CollisionId, cascgoodpostracks::DCAXY); -namespace cascgoodnegtracks -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodNegTrack, goodNegTrack, int, FullTracks, "fGoodNegTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); -} // namespace cascgoodnegtracks -DECLARE_SOA_TABLE(CascGoodNegTracks, "AOD", "CASCGOODNTRACKS", o2::soa::Index<>, cascgoodnegtracks::GoodNegTrackId, cascgoodnegtracks::CollisionId, cascgoodnegtracks::DCAXY); -namespace cascgoodlambdas -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodLambda, goodLambda, int, V0FinderFull, "fGoodLambdaId"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace cascgoodlambdas -DECLARE_SOA_TABLE(CascGoodLambdas, "AOD", "CASCGOODLAM", o2::soa::Index<>, cascgoodlambdas::GoodLambdaId, cascgoodlambdas::CollisionId); -namespace cascgoodantilambdas -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodAntiLambda, goodAntiLambda, int, V0FinderFull, "fGoodAntiLambdaId"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace cascgoodantilambdas -DECLARE_SOA_TABLE(CascGoodAntiLambdas, "AOD", "CASCGOODALAM", o2::soa::Index<>, cascgoodantilambdas::GoodAntiLambdaId, cascgoodantilambdas::CollisionId); -} // namespace o2::aod - -struct cascadeprefilter { - Configurable<float> dcabachtopv{"dcabachtopv", .1, "DCA Bach To PV"}; - Configurable<int> mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; - Configurable<float> dcav0topv{"dcav0topv", .1, "DCA V0 To PV"}; - Configurable<double> cospaV0{"cospaV0", .98, "CosPA V0"}; - Configurable<float> lambdamasswindow{"lambdamasswindow", .006, "Distance from Lambda mass"}; - Configurable<float> dcav0dau{"dcav0dau", .6, "DCA V0 Daughters"}; - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - - Produces<aod::CascGoodLambdas> cascGoodLambdas; - Produces<aod::CascGoodAntiLambdas> cascGoodAntiLambdas; - Produces<aod::CascGoodPosTracks> cascGoodPosTracks; - Produces<aod::CascGoodNegTracks> cascGoodNegTracks; - - Partition<soa::Join<aod::FullTracks, aod::TracksExtended>> goodPosTracks = aod::track::signed1Pt > 0.0f && aod::track::dcaXY > dcabachtopv; - Partition<soa::Join<aod::FullTracks, aod::TracksExtended>> goodNegTracks = aod::track::signed1Pt < 0.0f && aod::track::dcaXY < -dcabachtopv; - - Partition<soa::Join<aod::V0FinderData, aod::V0DataExt>> goodV0s = aod::v0data::dcapostopv > dcapostopv&& aod::v0data::dcanegtopv > dcanegtopv&& aod::v0data::dcaV0daughters < dcav0dau; - - void process(aod::Collision const& collision, - soa::Join<aod::FullTracks, aod::TracksExtended> const& tracks, - soa::Join<aod::V0FinderData, aod::V0DataExt> const& V0s) - { - for (auto& t0 : goodPosTracks) { - if (!(t0.flags() & 0x40)) { - continue; //TPC refit - } - if (t0.tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - cascGoodPosTracks(t0.globalIndex(), t0.collisionId(), t0.dcaXY()); - } - for (auto& t0 : goodNegTracks) { - if (!(t0.flags() & 0x40)) { - continue; //TPC refit - } - if (t0.tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - cascGoodNegTracks(t0.globalIndex(), t0.collisionId(), -t0.dcaXY()); - } - for (auto& v0 : goodV0s) { - if (v0.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cospaV0) { - continue; - } - if (v0.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < dcav0topv) { - continue; - } - - if (fabs(v0.mLambda() - 1.116) < lambdamasswindow) { - cascGoodLambdas(v0.globalIndex(), v0.collisionId()); - } - if (fabs(v0.mAntiLambda() - 1.116) < lambdamasswindow) { - cascGoodAntiLambdas(v0.globalIndex(), v0.collisionId()); - } - } - } -}; - -struct cascadefinder { - Produces<aod::CascData> cascdata; - Produces<aod::CascFinderData> cascfinderdata; - - OutputObj<TH1F> hCandPerEvent{TH1F("hCandPerEvent", "", 100, 0, 100)}; - - //Configurables - Configurable<double> d_bz{"d_bz", +5.0, "bz field"}; - Configurable<double> d_UseAbsDCA{"d_UseAbsDCA", kTRUE, "Use Abs DCAs"}; - - //Selection criteria - Configurable<double> v0cospa{"casccospa", 0.998, "Casc CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcacascdau", 1.0, "DCA Casc Daughters"}; - Configurable<float> v0radius{"cascradius", 1.0, "cascradius"}; - - //Process: subscribes to a lot of things! - void process(aod::Collision const& collision, - aod::FullTracks const& tracks, - soa::Join<aod::V0FinderData, aod::V0DataExt> const& V0s, - aod::CascGoodLambdas const& lambdas, - aod::CascGoodAntiLambdas const& antiLambdas, - aod::CascGoodPosTracks const& pBachtracks, - aod::CascGoodNegTracks const& nBachtracks) - { - //Define o2 fitter, 2-prong - o2::vertexing::DCAFitterN<2> fitterV0, fitterCasc; - fitterV0.setBz(d_bz); - fitterV0.setPropagateToPCA(true); - fitterV0.setMaxR(200.); - fitterV0.setMinParamChange(1e-3); - fitterV0.setMinRelChi2Change(0.9); - fitterV0.setMaxDZIni(1e9); - fitterV0.setMaxChi2(1e9); - fitterV0.setUseAbsDCA(d_UseAbsDCA); - - fitterCasc.setBz(d_bz); - fitterCasc.setPropagateToPCA(true); - fitterCasc.setMaxR(200.); - fitterCasc.setMinParamChange(1e-3); - fitterCasc.setMinRelChi2Change(0.9); - fitterCasc.setMaxDZIni(1e9); - fitterCasc.setMaxChi2(1e9); - fitterCasc.setUseAbsDCA(d_UseAbsDCA); - - Long_t lNCand = 0; - - std::array<float, 3> pVtx = {collision.posX(), collision.posY(), collision.posZ()}; - std::array<float, 3> pos = {0.}; - std::array<float, 3> posXi = {0.}; - std::array<float, 3> pvecpos = {0.}; - std::array<float, 3> pvecneg = {0.}; - std::array<float, 3> pvecbach = {0.}; - - //Cascades first - for (auto& v0id : lambdas) { - //required: de-reference the tracks for cascade building - auto v0 = v0id.goodLambda(); - auto pTrack = getTrackParCov(v0.posTrack()); - auto nTrack = getTrackParCov(v0.negTrack()); - //Let's do the slow part first: the V0 recalculation from scratch - int nCand = fitterV0.process(pTrack, nTrack); - if (nCand != 0) { - fitterV0.propagateTracksToVertex(); - const auto& v0vtx = fitterV0.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = v0vtx[i]; - } - - std::array<float, 21> cov0 = {0}; - std::array<float, 21> cov1 = {0}; - std::array<float, 21> covV0 = {0}; - - //Covariance matrix calculation - const int momInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - fitterV0.getTrack(0).getPxPyPzGlo(pvecpos); - fitterV0.getTrack(1).getPxPyPzGlo(pvecneg); - fitterV0.getTrack(0).getCovXYZPxPyPzGlo(cov0); - fitterV0.getTrack(1).getCovXYZPxPyPzGlo(cov1); - for (int i = 0; i < 6; i++) { - int j = momInd[i]; - covV0[j] = cov0[j] + cov1[j]; - } - auto covVtxV0 = fitterV0.calcPCACovMatrix(); - covV0[0] = covVtxV0(0, 0); - covV0[1] = covVtxV0(1, 0); - covV0[2] = covVtxV0(1, 1); - covV0[3] = covVtxV0(2, 0); - covV0[4] = covVtxV0(2, 1); - covV0[5] = covVtxV0(2, 2); - - const std::array<float, 3> vertex = {(float)v0vtx[0], (float)v0vtx[1], (float)v0vtx[2]}; - const std::array<float, 3> momentum = {pvecpos[0] + pvecneg[0], pvecpos[1] + pvecneg[1], pvecpos[2] + pvecneg[2]}; - - auto tV0 = o2::track::TrackParCov(vertex, momentum, covV0, 0); - tV0.setQ2Pt(0); //No bending, please - - for (auto& t0id : nBachtracks) { - auto t0 = t0id.goodNegTrack(); - auto bTrack = getTrackParCov(t0); - - int nCand2 = fitterCasc.process(tV0, bTrack); - if (nCand2 != 0) { - fitterCasc.propagateTracksToVertex(); - const auto& cascvtx = fitterCasc.getPCACandidate(); - for (int i = 0; i < 3; i++) { - posXi[i] = cascvtx[i]; - } - fitterCasc.getTrack(1).getPxPyPzGlo(pvecbach); - - lNCand++; - //If we got here, it means this is a good candidate! - cascfinderdata(v0.globalIndex(), t0.globalIndex(), t0.collisionId()); - cascdata(-1, posXi[0], posXi[1], posXi[2], pos[0], pos[1], pos[2], - pvecpos[0], pvecpos[1], pvecpos[2], - pvecneg[0], pvecneg[1], pvecneg[2], - pvecbach[0], pvecbach[1], pvecbach[2], - fitterV0.getChi2AtPCACandidate(), fitterCasc.getChi2AtPCACandidate(), - v0.dcapostopv(), - v0.dcanegtopv(), - t0id.dcaXY()); - } //end if cascade recoed - } //end loop over bachelor - } //end if v0 recoed - } //end loop over cascades - - //Anticascades - for (auto& v0id : antiLambdas) { - //required: de-reference the tracks for cascade building - auto v0 = v0id.goodAntiLambda(); - auto pTrack = getTrackParCov(v0.posTrack()); - auto nTrack = getTrackParCov(v0.negTrack()); - //Let's do the slow part first: the V0 recalculation from scratch - int nCand = fitterV0.process(pTrack, nTrack); - if (nCand != 0) { - fitterV0.propagateTracksToVertex(); - const auto& v0vtx = fitterV0.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = v0vtx[i]; - } - - std::array<float, 21> cov0 = {0}; - std::array<float, 21> cov1 = {0}; - std::array<float, 21> covV0 = {0}; - - //Covariance matrix calculation - const int momInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - fitterV0.getTrack(0).getPxPyPzGlo(pvecpos); - fitterV0.getTrack(1).getPxPyPzGlo(pvecneg); - fitterV0.getTrack(0).getCovXYZPxPyPzGlo(cov0); - fitterV0.getTrack(1).getCovXYZPxPyPzGlo(cov1); - for (int i = 0; i < 6; i++) { - int j = momInd[i]; - covV0[j] = cov0[j] + cov1[j]; - } - auto covVtxV0 = fitterV0.calcPCACovMatrix(); - covV0[0] = covVtxV0(0, 0); - covV0[1] = covVtxV0(1, 0); - covV0[2] = covVtxV0(1, 1); - covV0[3] = covVtxV0(2, 0); - covV0[4] = covVtxV0(2, 1); - covV0[5] = covVtxV0(2, 2); - - const std::array<float, 3> vertex = {(float)v0vtx[0], (float)v0vtx[1], (float)v0vtx[2]}; - const std::array<float, 3> momentum = {pvecpos[0] + pvecneg[0], pvecpos[1] + pvecneg[1], pvecpos[2] + pvecneg[2]}; - - auto tV0 = o2::track::TrackParCov(vertex, momentum, covV0, 0); - tV0.setQ2Pt(0); //No bending, please - - for (auto& t0id : pBachtracks) { - auto t0 = t0id.goodPosTrack(); - auto bTrack = getTrackParCov(t0); - - int nCand2 = fitterCasc.process(tV0, bTrack); - if (nCand2 != 0) { - fitterCasc.propagateTracksToVertex(); - const auto& cascvtx = fitterCasc.getPCACandidate(); - for (int i = 0; i < 3; i++) { - posXi[i] = cascvtx[i]; - } - fitterCasc.getTrack(1).getPxPyPzGlo(pvecbach); - - lNCand++; - //If we got here, it means this is a good candidate! - cascfinderdata(v0.globalIndex(), t0.globalIndex(), t0.collisionId()); - cascdata(+1, posXi[0], posXi[1], posXi[2], pos[0], pos[1], pos[2], - pvecpos[0], pvecpos[1], pvecpos[2], - pvecneg[0], pvecneg[1], pvecneg[2], - pvecbach[0], pvecbach[1], pvecbach[2], - fitterV0.getChi2AtPCACandidate(), fitterCasc.getChi2AtPCACandidate(), - v0.dcapostopv(), - v0.dcanegtopv(), - t0id.dcaXY()); - } //end if cascade recoed - } //end loop over bachelor - } //end if v0 recoed - } //end loop over anticascades - - hCandPerEvent->Fill(lNCand); - } -}; - -struct cascadefinderQA { - //Basic checks - OutputObj<TH3F> h3dMassXiMinus{TH3F("h3dMassXiMinus", "", 20, 0, 100, 200, 0, 10, 200, 1.322 - 0.100, 1.322 + 0.100)}; - OutputObj<TH3F> h3dMassXiPlus{TH3F("h3dMassXiPlus", "", 20, 0, 100, 200, 0, 10, 200, 1.322 - 0.100, 1.322 + 0.100)}; - OutputObj<TH3F> h3dMassOmegaMinus{TH3F("h3dMassOmegaMinus", "", 20, 0, 100, 200, 0, 10, 200, 1.672 - 0.100, 1.672 + 0.100)}; - OutputObj<TH3F> h3dMassOmegaPlus{TH3F("h3dMassOmegaPlus", "", 20, 0, 100, 200, 0, 10, 200, 1.672 - 0.100, 1.672 + 0.100)}; - - //Selection criteria - Configurable<double> v0cospa{"v0cospa", 0.999, "V0 CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<double> casccospa{"casccospa", 0.999, "Casc CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; - Configurable<float> dcacascdau{"dcacascdau", .3, "DCA Casc Daughters"}; - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - Configurable<float> dcabachtopv{"dcabachtopv", .1, "DCA Bach To PV"}; - Configurable<float> dcav0topv{"dcav0topv", .1, "DCA V0 To PV"}; - Configurable<float> v0radius{"v0radius", 2.0, "v0radius"}; - Configurable<float> cascradius{"cascradius", 1.0, "cascradius"}; - Configurable<float> v0masswindow{"v0masswindow", 0.008, "v0masswindow"}; - - Filter preFilterV0 = - aod::cascdata::dcapostopv > dcapostopv&& aod::cascdata::dcanegtopv > dcanegtopv&& - aod::cascdata::dcabachtopv > dcabachtopv&& - aod::cascdata::dcaV0daughters < dcav0dau&& aod::cascdata::dcacascdaughters < dcacascdau; - - ///Connect to CascFinderData: newly indexed, note: CascDataExt table incompatible with standard V0 table! - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator const& collision, soa::Filtered<soa::Join<aod::CascFinderData, aod::CascDataExt>> const& Cascades) - { - if (!collision.alias()[kINT7]) { - return; - } - if (!collision.sel7()) { - return; - } - for (auto& casc : Cascades) { - //FIXME: dynamic columns cannot be filtered on? - if (casc.v0radius() > v0radius && - casc.cascradius() > cascradius && - casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > v0cospa && - casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > casccospa && - casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) > dcav0topv) { - if (casc.charge() < 0) { //FIXME: could be done better... - if (TMath::Abs(casc.yXi()) < 0.5) { - h3dMassXiMinus->Fill(collision.centV0M(), casc.pt(), casc.mXi()); - } - if (TMath::Abs(casc.yOmega()) < 0.5) { - h3dMassOmegaMinus->Fill(collision.centV0M(), casc.pt(), casc.mOmega()); - } - } else { - if (TMath::Abs(casc.yXi()) < 0.5) { - h3dMassXiPlus->Fill(collision.centV0M(), casc.pt(), casc.mXi()); - } - if (TMath::Abs(casc.yOmega()) < 0.5) { - h3dMassOmegaPlus->Fill(collision.centV0M(), casc.pt(), casc.mOmega()); - } - } - } - } - } -}; - -/// Extends the v0data table with expression columns -struct cascadeinitializer { - Spawns<aod::CascDataExt> cascdataext; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<cascadeprefilter>("lf-cascadeprefilter"), - adaptAnalysisTask<cascadefinder>("lf-cascadefinder"), - adaptAnalysisTask<cascadeinitializer>("lf-cascadeinitializer"), - adaptAnalysisTask<cascadefinderQA>("lf-cascadefinderQA")}; -} diff --git a/Analysis/Tasks/PWGLF/cascadeproducer.cxx b/Analysis/Tasks/PWGLF/cascadeproducer.cxx deleted file mode 100644 index 90343a61e9d4c..0000000000000 --- a/Analysis/Tasks/PWGLF/cascadeproducer.cxx +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/HFSecondaryVertex.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "Analysis/StrangenessTables.h" - -#include <TFile.h> -#include <TH2F.h> -#include <TProfile.h> -#include <TLorentzVector.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> -#include "PID/PIDResponse.h" -#include "Framework/ASoAHelpers.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -/// Cascade builder task: rebuilds cascades -struct cascadeproducer { - Produces<aod::CascData> cascdata; - - OutputObj<TH1F> hEventCounter{TH1F("hEventCounter", "", 1, 0, 1)}; - OutputObj<TH1F> hCascCandidate{TH1F("hCascCandidate", "", 10, 0, 10)}; - - //Configurables - Configurable<double> d_bz{"d_bz", -5.0, "bz field"}; - Configurable<double> d_UseAbsDCA{"d_UseAbsDCA", kTRUE, "Use Abs DCAs"}; - - /// Extracts dca in the XY plane - /// \return dcaXY - template <typename T, typename U> - auto getdcaXY(const T& track, const U& coll) - { - //Calculate DCAs - auto sinAlpha = sin(track.alpha()); - auto cosAlpha = cos(track.alpha()); - auto globalX = track.x() * cosAlpha - track.y() * sinAlpha; - auto globalY = track.x() * sinAlpha + track.y() * cosAlpha; - return sqrt(pow((globalX - coll[0]), 2) + - pow((globalY - coll[1]), 2)); - } - - void process(aod::Collision const& collision, aod::V0s const& V0s, aod::Cascades const& Cascades, aod::FullTracks const& trackss) - { - //Define o2 fitter, 2-prong - o2::vertexing::DCAFitterN<2> fitterV0, fitterCasc; - fitterV0.setBz(d_bz); - fitterV0.setPropagateToPCA(true); - fitterV0.setMaxR(200.); - fitterV0.setMinParamChange(1e-3); - fitterV0.setMinRelChi2Change(0.9); - fitterV0.setMaxDZIni(1e9); - fitterV0.setMaxChi2(1e9); - fitterV0.setUseAbsDCA(d_UseAbsDCA); - - fitterCasc.setBz(d_bz); - fitterCasc.setPropagateToPCA(true); - fitterCasc.setMaxR(200.); - fitterCasc.setMinParamChange(1e-3); - fitterCasc.setMinRelChi2Change(0.9); - fitterCasc.setMaxDZIni(1e9); - fitterCasc.setMaxChi2(1e9); - fitterCasc.setUseAbsDCA(d_UseAbsDCA); - - hEventCounter->Fill(0.5); - std::array<float, 3> pVtx = {collision.posX(), collision.posY(), collision.posZ()}; - - for (auto& casc : Cascades) { - auto charge = -1; - std::array<float, 3> pos = {0.}; - std::array<float, 3> posXi = {0.}; - std::array<float, 3> pvecpos = {0.}; - std::array<float, 3> pvecneg = {0.}; - std::array<float, 3> pvecbach = {0.}; - - hCascCandidate->Fill(0.5); - - //Acquire basic tracks - auto pTrack = getTrackParCov(casc.v0().posTrack()); - auto nTrack = getTrackParCov(casc.v0().negTrack()); - auto bTrack = getTrackParCov(casc.bachelor()); - if (casc.bachelor().signed1Pt() > 0) { - charge = +1; - } - - int nCand = fitterV0.process(pTrack, nTrack); - if (nCand != 0) { - fitterV0.propagateTracksToVertex(); - hCascCandidate->Fill(1.5); - const auto& v0vtx = fitterV0.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = v0vtx[i]; - } - - std::array<float, 21> cov0 = {0}; - std::array<float, 21> cov1 = {0}; - std::array<float, 21> covV0 = {0}; - - //Covariance matrix calculation - const int momInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component - fitterV0.getTrack(0).getPxPyPzGlo(pvecpos); - fitterV0.getTrack(1).getPxPyPzGlo(pvecneg); - fitterV0.getTrack(0).getCovXYZPxPyPzGlo(cov0); - fitterV0.getTrack(1).getCovXYZPxPyPzGlo(cov1); - for (int i = 0; i < 6; i++) { - int j = momInd[i]; - covV0[j] = cov0[j] + cov1[j]; - } - auto covVtxV0 = fitterV0.calcPCACovMatrix(); - covV0[0] = covVtxV0(0, 0); - covV0[1] = covVtxV0(1, 0); - covV0[2] = covVtxV0(1, 1); - covV0[3] = covVtxV0(2, 0); - covV0[4] = covVtxV0(2, 1); - covV0[5] = covVtxV0(2, 2); - - const std::array<float, 3> vertex = {(float)v0vtx[0], (float)v0vtx[1], (float)v0vtx[2]}; - const std::array<float, 3> momentum = {pvecpos[0] + pvecneg[0], pvecpos[1] + pvecneg[1], pvecpos[2] + pvecneg[2]}; - - auto tV0 = o2::track::TrackParCov(vertex, momentum, covV0, 0); - tV0.setQ2Pt(0); //No bending, please - int nCand2 = fitterCasc.process(tV0, bTrack); - if (nCand2 != 0) { - fitterCasc.propagateTracksToVertex(); - hCascCandidate->Fill(2.5); - const auto& cascvtx = fitterCasc.getPCACandidate(); - for (int i = 0; i < 3; i++) { - posXi[i] = cascvtx[i]; - } - fitterCasc.getTrack(1).getPxPyPzGlo(pvecbach); - } //end if cascade recoed - } //end if v0 recoed - //Fill table, please - cascdata(charge, posXi[0], posXi[1], posXi[2], pos[0], pos[1], pos[2], - pvecpos[0], pvecpos[1], pvecpos[2], - pvecneg[0], pvecneg[1], pvecneg[2], - pvecbach[0], pvecbach[1], pvecbach[2], - fitterV0.getChi2AtPCACandidate(), fitterCasc.getChi2AtPCACandidate(), - getdcaXY(casc.v0().posTrack(), pVtx), - getdcaXY(casc.v0().negTrack(), pVtx), - getdcaXY(casc.bachelor(), pVtx)); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<cascadeproducer>("lf-cascadeproducer")}; -} diff --git a/Analysis/Tasks/PWGLF/lambdakzeroconsumer.cxx b/Analysis/Tasks/PWGLF/lambdakzeroconsumer.cxx deleted file mode 100644 index cd1b7ed42787a..0000000000000 --- a/Analysis/Tasks/PWGLF/lambdakzeroconsumer.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "Analysis/StrangenessTables.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" - -#include <TFile.h> -#include <TH2F.h> -#include <TProfile.h> -#include <TLorentzVector.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> -#include "PID/PIDResponse.h" -#include "Framework/ASoAHelpers.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -struct lambdakzeroQA { - //Basic checks - OutputObj<TH1F> hMassK0Short{TH1F("hMassK0Short", "", 3000, 0.0, 3.0)}; - OutputObj<TH1F> hMassLambda{TH1F("hMassLambda", "", 3000, 0.0, 3.0)}; - OutputObj<TH1F> hMassAntiLambda{TH1F("hMassAntiLambda", "", 3000, 0.0, 3.0)}; - - OutputObj<TH1F> hV0Radius{TH1F("hV0Radius", "", 1000, 0.0, 100)}; - OutputObj<TH1F> hV0CosPA{TH1F("hV0CosPA", "", 1000, 0.95, 1.0)}; - OutputObj<TH1F> hDCAPosToPV{TH1F("hDCAPosToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCANegToPV{TH1F("hDCANegToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCAV0Dau{TH1F("hDCAV0Dau", "", 1000, 0.0, 10.0)}; - - void process(aod::Collision const& collision, soa::Join<aod::V0s, aod::V0DataExt> const& fullV0s) - { - for (auto& v0 : fullV0s) { - hMassLambda->Fill(v0.mLambda()); - hMassAntiLambda->Fill(v0.mAntiLambda()); - hMassK0Short->Fill(v0.mK0Short()); - - hV0Radius->Fill(v0.v0radius()); - hV0CosPA->Fill(v0.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); - - hDCAPosToPV->Fill(v0.dcapostopv()); - hDCANegToPV->Fill(v0.dcanegtopv()); - hDCAV0Dau->Fill(v0.dcaV0daughters()); - } - } -}; - -struct lambdakzeroconsumer { - OutputObj<TH3F> h3dMassK0Short{TH3F("h3dMassK0Short", "", 20, 0, 100, 200, 0, 10, 200, 0.450, 0.550)}; - OutputObj<TH3F> h3dMassLambda{TH3F("h3dMassLambda", "", 20, 0, 100, 200, 0, 10, 200, 1.115 - 0.100, 1.115 + 0.100)}; - OutputObj<TH3F> h3dMassAntiLambda{TH3F("h3dMassAntiLambda", "", 20, 0, 100, 200, 0, 10, 200, 1.115 - 0.100, 1.115 + 0.100)}; - - //Selection criteria - Configurable<double> v0cospa{"v0cospa", 0.995, "V0 CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - Configurable<float> v0radius{"v0radius", 5.0, "v0radius"}; - - Filter preFilterV0 = aod::v0data::dcapostopv > dcapostopv&& - aod::v0data::dcanegtopv > dcanegtopv&& aod::v0data::dcaV0daughters < dcav0dau; - - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator const& collision, soa::Filtered<soa::Join<aod::V0s, aod::V0DataExt>> const& fullV0s) - { - if (!collision.alias()[kINT7]) { - return; - } - if (!collision.sel7()) { - return; - } - - for (auto& v0 : fullV0s) { - //FIXME: could not find out how to filter cosPA and radius variables (dynamic columns) - if (v0.v0radius() > v0radius && v0.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > v0cospa) { - if (TMath::Abs(v0.yLambda()) < 0.5) { - h3dMassLambda->Fill(collision.centV0M(), v0.pt(), v0.mLambda()); - h3dMassAntiLambda->Fill(collision.centV0M(), v0.pt(), v0.mAntiLambda()); - } - if (TMath::Abs(v0.yK0Short()) < 0.5) { - h3dMassK0Short->Fill(collision.centV0M(), v0.pt(), v0.mK0Short()); - } - } - } - } -}; - -/// Extends the v0data table with expression columns -struct lambdakzeroinitializer { - Spawns<aod::V0DataExt> v0dataext; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<lambdakzeroconsumer>("lf-lambdakzeroconsumer"), - adaptAnalysisTask<lambdakzeroQA>("lf-lambdakzeroQA"), - adaptAnalysisTask<lambdakzeroinitializer>("lf-lambdakzeroinitializer")}; -} diff --git a/Analysis/Tasks/PWGLF/lambdakzerofinder.cxx b/Analysis/Tasks/PWGLF/lambdakzerofinder.cxx deleted file mode 100644 index c2d6c0f7455d5..0000000000000 --- a/Analysis/Tasks/PWGLF/lambdakzerofinder.cxx +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// This task re-reconstructs the V0s and cascades - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/HFSecondaryVertex.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "PID/PIDResponse.h" -#include "Analysis/StrangenessTables.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" - -#include <TFile.h> -#include <TLorentzVector.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TProfile.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; -using namespace ROOT::Math; - -namespace o2::aod -{ -namespace v0goodpostracks -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, FullTracks, "fGoodTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); -} // namespace v0goodpostracks -DECLARE_SOA_TABLE(V0GoodPosTracks, "AOD", "V0GOODPOSTRACKS", o2::soa::Index<>, v0goodpostracks::GoodTrackId, v0goodpostracks::CollisionId, v0goodpostracks::DCAXY); -namespace v0goodnegtracks -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, FullTracks, "fGoodTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(DCAXY, dcaXY, float); -} // namespace v0goodnegtracks -DECLARE_SOA_TABLE(V0GoodNegTracks, "AOD", "V0GOODNEGTRACKS", o2::soa::Index<>, v0goodnegtracks::GoodTrackId, v0goodnegtracks::CollisionId, v0goodnegtracks::DCAXY); -} // namespace o2::aod - -struct lambdakzeroprefilter { - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - Configurable<int> mincrossedrows{"mincrossedrows", 70, "min crossed rows"}; - - Produces<aod::V0GoodPosTracks> v0GoodPosTracks; - Produces<aod::V0GoodNegTracks> v0GoodNegTracks; - - Partition<soa::Join<aod::FullTracks, aod::TracksExtended>> goodPosTracks = aod::track::signed1Pt > 0.0f && aod::track::dcaXY > dcapostopv; - Partition<soa::Join<aod::FullTracks, aod::TracksExtended>> goodNegTracks = aod::track::signed1Pt < 0.0f && aod::track::dcaXY < -dcanegtopv; - - void process(aod::Collision const& collision, - soa::Join<aod::FullTracks, aod::TracksExtended> const& tracks) - { - for (auto& t0 : goodPosTracks) { - if (!(t0.flags() & 0x40)) { - continue; //TPC refit - } - if (t0.tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - v0GoodPosTracks(t0.globalIndex(), t0.collisionId(), t0.dcaXY()); - } - for (auto& t0 : goodNegTracks) { - if (!(t0.flags() & 0x40)) { - continue; //TPC refit - } - if (t0.tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - v0GoodNegTracks(t0.globalIndex(), t0.collisionId(), -t0.dcaXY()); - } - } -}; - -struct lambdakzerofinder { - Produces<aod::V0Data> v0data; - Produces<aod::V0FinderData> v0finderdata; - - OutputObj<TH1F> hCandPerEvent{TH1F("hCandPerEvent", "", 1000, 0, 1000)}; - - //Configurables - Configurable<double> d_bz{"d_bz", +5.0, "bz field"}; - Configurable<double> d_UseAbsDCA{"d_UseAbsDCA", kTRUE, "Use Abs DCAs"}; - - //Selection criteria - Configurable<double> v0cospa{"v0cospa", 0.995, "V0 CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; - Configurable<float> v0radius{"v0radius", 5.0, "v0radius"}; - - void process(aod::Collision const& collision, aod::FullTracks const& tracks, - aod::V0GoodPosTracks const& ptracks, aod::V0GoodNegTracks const& ntracks) - { - //Define o2 fitter, 2-prong - o2::vertexing::DCAFitterN<2> fitter; - fitter.setBz(d_bz); - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(d_UseAbsDCA); - - Long_t lNCand = 0; - - std::array<float, 3> pVtx = {collision.posX(), collision.posY(), collision.posZ()}; - - for (auto& t0id : ptracks) { //FIXME: turn into combination(...) - auto t0 = t0id.goodTrack(); - auto Track1 = getTrackParCov(t0); - for (auto& t1id : ntracks) { - auto t1 = t1id.goodTrack(); - auto Track2 = getTrackParCov(t1); - - //Try to progate to dca - int nCand = fitter.process(Track1, Track2); - if (nCand == 0) { - continue; - } - const auto& vtx = fitter.getPCACandidate(); - - //Fiducial: min radius - auto thisv0radius = TMath::Sqrt(TMath::Power(vtx[0], 2) + TMath::Power(vtx[1], 2)); - if (thisv0radius < v0radius) { - continue; - } - - //DCA V0 daughters - auto thisdcav0dau = fitter.getChi2AtPCACandidate(); - if (thisdcav0dau > dcav0dau) { - continue; - } - - std::array<float, 3> pos = {0.}; - std::array<float, 3> pvec0; - std::array<float, 3> pvec1; - for (int i = 0; i < 3; i++) { - pos[i] = vtx[i]; - } - fitter.getTrack(0).getPxPyPzGlo(pvec0); - fitter.getTrack(1).getPxPyPzGlo(pvec1); - - auto thisv0cospa = RecoDecay::CPA(array{collision.posX(), collision.posY(), collision.posZ()}, - array{vtx[0], vtx[1], vtx[2]}, array{pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}); - if (thisv0cospa < v0cospa) { - continue; - } - - lNCand++; - v0finderdata(t0.globalIndex(), t1.globalIndex(), t0.collisionId()); - v0data(pos[0], pos[1], pos[2], - pvec0[0], pvec0[1], pvec0[2], - pvec1[0], pvec1[1], pvec1[2], - fitter.getChi2AtPCACandidate(), - t0id.dcaXY(), t1id.dcaXY()); - } - } - hCandPerEvent->Fill(lNCand); - } -}; - -struct lambdakzerofinderQA { - //Basic checks - //Selection criteria - Configurable<double> v0cospa{"v0cospa", 0.998, "V0 CosPA"}; //double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable<float> dcav0dau{"dcav0dau", .6, "DCA V0 Daughters"}; - Configurable<float> dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; - Configurable<float> dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; - Configurable<float> v0radius{"v0radius", 5.0, "v0radius"}; - - OutputObj<TH1F> hCandPerEvent{TH1F("hCandPerEvent", "", 1000, 0, 1000)}; - - OutputObj<TH1F> hV0Radius{TH1F("hV0Radius", "", 1000, 0.0, 100)}; - OutputObj<TH1F> hV0CosPA{TH1F("hV0CosPA", "", 1000, 0.95, 1.0)}; - OutputObj<TH1F> hDCAPosToPV{TH1F("hDCAPosToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCANegToPV{TH1F("hDCANegToPV", "", 1000, 0.0, 10.0)}; - OutputObj<TH1F> hDCAV0Dau{TH1F("hDCAV0Dau", "", 1000, 0.0, 10.0)}; - - OutputObj<TH3F> h3dMassK0Short{TH3F("h3dMassK0Short", "", 20, 0, 100, 200, 0, 10, 200, 0.450, 0.550)}; - OutputObj<TH3F> h3dMassLambda{TH3F("h3dMassLambda", "", 20, 0, 100, 200, 0, 10, 200, 1.115 - 0.100, 1.115 + 0.100)}; - OutputObj<TH3F> h3dMassAntiLambda{TH3F("h3dMassAntiLambda", "", 20, 0, 100, 200, 0, 10, 200, 1.115 - 0.100, 1.115 + 0.100)}; - - //FIXME: figure out why this does not work? - //Filter preFilter1 = aod::v0data::dcapostopv > dcapostopv; - //Filter preFilter2 = aod::v0data::dcanegtopv > dcanegtopv; - //Filter preFilter3 = aod::v0data::dcaV0daughters < dcav0dau; - - ///Connect to V0FinderData: newly indexed, note: V0DataExt table incompatible with standard V0 table! - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator const& collision, - // soa::Filtered<soa::Join<aod::V0FinderData, aod::V0DataExt>> const& fullV0s) - soa::Join<aod::V0FinderData, aod::V0DataExt> const& fullV0s) - { - if (!collision.alias()[kINT7]) { - return; - } - if (!collision.sel7()) { - return; - } - - Long_t lNCand = 0; - for (auto& v0 : fullV0s) { - if (v0.v0radius() > v0radius && v0.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > v0cospa && v0.dcapostopv() > dcapostopv && v0.dcanegtopv() > dcanegtopv && v0.dcaV0daughters() > dcav0dau) { - hV0Radius->Fill(v0.v0radius()); - hV0CosPA->Fill(v0.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); - hDCAPosToPV->Fill(v0.dcapostopv()); - hDCANegToPV->Fill(v0.dcanegtopv()); - hDCAV0Dau->Fill(v0.dcaV0daughters()); - - if (TMath::Abs(v0.yLambda()) < 0.5) { - h3dMassLambda->Fill(collision.centV0M(), v0.pt(), v0.mLambda()); - h3dMassAntiLambda->Fill(collision.centV0M(), v0.pt(), v0.mAntiLambda()); - } - if (TMath::Abs(v0.yK0Short()) < 0.5) { - h3dMassK0Short->Fill(collision.centV0M(), v0.pt(), v0.mK0Short()); - } - lNCand++; - } - } - hCandPerEvent->Fill(lNCand); - } -}; - -/// Extends the v0data table with expression columns -struct lambdakzeroinitializer { - Spawns<aod::V0DataExt> v0dataext; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<lambdakzeroprefilter>("lf-lambdakzeroprefilter"), - adaptAnalysisTask<lambdakzerofinder>("lf-lambdakzerofinder"), - adaptAnalysisTask<lambdakzeroinitializer>("lf-lambdakzeroinitializer"), - adaptAnalysisTask<lambdakzerofinderQA>("lf-lambdakzerofinderQA")}; -} diff --git a/Analysis/Tasks/PWGLF/lambdakzeroproducer.cxx b/Analysis/Tasks/PWGLF/lambdakzeroproducer.cxx deleted file mode 100644 index 7bb8ccd925a67..0000000000000 --- a/Analysis/Tasks/PWGLF/lambdakzeroproducer.cxx +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/HFSecondaryVertex.h" -#include "DetectorsVertexing/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Analysis/RecoDecay.h" -#include "Analysis/trackUtilities.h" -#include "Analysis/StrangenessTables.h" - -#include <TFile.h> -#include <TH2F.h> -#include <TProfile.h> -#include <TLorentzVector.h> -#include <Math/Vector4D.h> -#include <TPDGCode.h> -#include <TDatabasePDG.h> -#include <cmath> -#include <array> -#include <cstdlib> -#include "PID/PIDResponse.h" -#include "Framework/ASoAHelpers.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -/// Cascade builder task: rebuilds cascades -struct lambdakzeroproducer { - - Produces<aod::V0Data> v0data; - - OutputObj<TH1F> hEventCounter{TH1F("hEventCounter", "", 1, 0, 1)}; - OutputObj<TH1F> hCascCandidate{TH1F("hCascCandidate", "", 10, 0, 10)}; - - //Configurables - Configurable<double> d_bz{"d_bz", -5.0, "bz field"}; - Configurable<double> d_UseAbsDCA{"d_UseAbsDCA", kTRUE, "Use Abs DCAs"}; - - double massPi = TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(); - double massKa = TDatabasePDG::Instance()->GetParticle(kKPlus)->Mass(); - double massPr = TDatabasePDG::Instance()->GetParticle(kProton)->Mass(); - - /// Extracts dca in the XY plane - /// \return dcaXY - template <typename T, typename U> - auto getdcaXY(const T& track, const U& coll) - { - //Calculate DCAs - auto sinAlpha = sin(track.alpha()); - auto cosAlpha = cos(track.alpha()); - auto globalX = track.x() * cosAlpha - track.y() * sinAlpha; - auto globalY = track.x() * sinAlpha + track.y() * cosAlpha; - return sqrt(pow((globalX - coll[0]), 2) + - pow((globalY - coll[1]), 2)); - } - - void process(aod::Collision const& collision, aod::V0s const& V0s, aod::FullTracks const& tracks) - { - //Define o2 fitter, 2-prong - o2::vertexing::DCAFitterN<2> fitter; - fitter.setBz(d_bz); - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(d_UseAbsDCA); - - hEventCounter->Fill(0.5); - std::array<float, 3> pVtx = {collision.posX(), collision.posY(), collision.posZ()}; - - for (auto& V0 : V0s) { - std::array<float, 3> pos = {0.}; - std::array<float, 3> pvec0 = {0.}; - std::array<float, 3> pvec1 = {0.}; - - hCascCandidate->Fill(0.5); - auto pTrack = getTrackParCov(V0.posTrack()); - auto nTrack = getTrackParCov(V0.negTrack()); - int nCand = fitter.process(pTrack, nTrack); - if (nCand != 0) { - fitter.propagateTracksToVertex(); - hCascCandidate->Fill(2.5); - const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = vtx[i]; - } - fitter.getTrack(0).getPxPyPzGlo(pvec0); - fitter.getTrack(1).getPxPyPzGlo(pvec1); - } - - v0data(pos[0], pos[1], pos[2], - pvec0[0], pvec0[1], pvec0[2], - pvec1[0], pvec1[1], pvec1[2], - fitter.getChi2AtPCACandidate(), - getdcaXY(V0.posTrack(), pVtx), - getdcaXY(V0.negTrack(), pVtx)); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<lambdakzeroproducer>("lf-lambdakzeroproducer")}; -} diff --git a/Analysis/Tasks/PWGLF/mcspectraefficiency.cxx b/Analysis/Tasks/PWGLF/mcspectraefficiency.cxx deleted file mode 100644 index 76ed9f2e9e12b..0000000000000 --- a/Analysis/Tasks/PWGLF/mcspectraefficiency.cxx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/MC.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/TrackSelectionTables.h" - -// ROOT includes -#include <TH1F.h> -#include "TPDGCode.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace MC; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"add-vertex", VariantType::Int, 1, {"Vertex plots"}}, - {"add-gen", VariantType::Int, 1, {"Generated plots"}}, - {"add-reco", VariantType::Int, 1, {"Reconstructed plots"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -#define PDGBINNING 100, 0, 100 - -// Simple access to collision -struct VertexTask { - OutputObj<TH1F> vertex{TH1F("vertex", "vertex", 100, -10, 10)}; - - void process(aod::McCollision const& mcCollision) - { - LOGF(info, "MC. vtx-z = %f", mcCollision.posZ()); - vertex->Fill(mcCollision.posZ()); - } -}; - -// Grouping between MC particles and collisions -struct GeneratedTask { - OutputObj<TH2F> phiH{TH2F("phi", "phi;#phi;PDG code", 100, 0., 2. * M_PI, PDGBINNING)}; - OutputObj<TH2F> etaH{TH2F("eta", "eta;#eta;PDG code", 102, -2.01, 2.01, PDGBINNING)}; - OutputObj<TH2F> ptH{TH2F("pt", "pt;#it{p}_{T} (GeV/#it{c});PDG code", 500, 0, 20, PDGBINNING)}; - OutputObj<TH2F> pH{TH2F("p", "p;#it{p} (GeV/#it{c});PDG code", 500, 0, 20, PDGBINNING)}; - OutputObj<TH1F> pdgH{TH1F("pdg", "pdg;PDG code", PDGBINNING)}; - - int events = 0; - int particles = 0; - int primaryparticles = 0; - - void process(aod::McCollision const& mcCollision, aod::McParticles& mcParticles) - { - LOGF(info, "MC. vtx-z = %f", mcCollision.posZ()); - for (auto& mcParticle : mcParticles) { - if (abs(mcParticle.eta()) > 0.8) { - continue; - } - if (isPhysicalPrimary(mcParticles, mcParticle)) { - const auto pdg = Form("%i", mcParticle.pdgCode()); - pdgH->Fill(pdg, 1); - const float pdgbin = pdgH->GetXaxis()->GetBinCenter(pdgH->GetXaxis()->FindBin(pdg)); - phiH->Fill(mcParticle.phi(), pdgbin); - etaH->Fill(mcParticle.eta(), pdgbin); - pH->Fill(sqrt(mcParticle.px() * mcParticle.px() + mcParticle.py() * mcParticle.py() + mcParticle.pz() * mcParticle.pz()), pdgbin); - ptH->Fill(mcParticle.pt(), pdgbin); - primaryparticles++; - } - particles++; - } - LOGF(info, "Events %i", events++ + 1); - LOGF(info, "Particles %i", particles); - LOGF(info, "Primaries %i", primaryparticles); - } -}; - -// Access from tracks to MC particle -struct ReconstructedTask { - OutputObj<TH2F> phiH{TH2F("phi", "phi;#phi;PDG code", 100, 0., 2. * M_PI, PDGBINNING)}; - OutputObj<TH2F> etaH{TH2F("eta", "eta;#eta;PDG code", 102, -2.01, 2.01, PDGBINNING)}; - OutputObj<TH2F> ptH{TH2F("pt", "pt;#it{p}_{T} (GeV/#it{c})", 500, 0, 20, PDGBINNING)}; - OutputObj<TH2F> pH{TH2F("p", "p;#it{p} (GeV/#it{c})", 500, 0, 20, PDGBINNING)}; - OutputObj<TH2F> dcaxyH{TH2F("dcaxy", "dcaxy;DCA_{xy} (cm)", 500, -10, 10, PDGBINNING)}; - OutputObj<TH2F> dcazH{TH2F("dcaz", "dcaz;DCA_{z} (cm)", 500, -10, 10, PDGBINNING)}; - OutputObj<TH1F> pdgH{TH1F("pdg", "pdg;PDG code", PDGBINNING)}; - OutputObj<TH2F> dcaxysecH{TH2F("dcaxysec", "dcaxysec;DCA_{xy} (cm)", 500, -10, 10, PDGBINNING)}; - OutputObj<TH2F> dcazsecH{TH2F("dcazsec", "dcazsec;DCA_{z} (cm)", 500, -10, 10, PDGBINNING)}; - OutputObj<TH1F> pdgsecH{TH1F("pdgsec", "pdgsec;PDG code", PDGBINNING)}; - - OutputObj<TH2F> phiDiff{TH2F("phiDiff", ";phi_{MC} - phi_{Rec}", 100, -M_PI, M_PI, PDGBINNING)}; - OutputObj<TH2F> etaDiff{TH2F("etaDiff", ";eta_{MC} - eta_{Rec}", 100, -2, 2, PDGBINNING)}; - OutputObj<TH2F> ptDiff{TH2F("ptDiff", "ptDiff;#it{p}_{T}_{MC} #it{p}_{T}_{Rec} (GeV/#it{c})", 500, -2, 2, PDGBINNING)}; - OutputObj<TH2F> pDiff{TH2F("pDiff", "pDiff;#it{p}_{MC} #it{p}_{Rec} (GeV/#it{c})", 500, -2, 2, PDGBINNING)}; - - Filter trackAcceptance = (nabs(aod::track::eta) < 0.8f); - Filter trackCuts = ((aod::track::isGlobalTrack == true) || (aod::track::isGlobalTrackSDD == true)); - - void process(soa::Join<aod::Collisions, aod::McCollisionLabels>::iterator const& collision, - soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksExtended, aod::McTrackLabels, aod::TrackSelection>> const& tracks, - aod::McParticles& mcParticles, aod::McCollisions const& mcCollisions) - { - LOGF(info, "vtx-z (data) = %f | vtx-z (MC) = %f", collision.posZ(), collision.label().posZ()); - for (auto& track : tracks) { - const auto pdg = Form("%i", track.label().pdgCode()); - if (!isPhysicalPrimary(mcParticles, track.label())) { - pdgsecH->Fill(pdg, 1); - const float pdgbinsec = pdgH->GetXaxis()->GetBinCenter(pdgsecH->GetXaxis()->FindBin(pdg)); - dcaxysecH->Fill(track.dcaXY(), pdgbinsec); - dcazsecH->Fill(track.dcaZ(), pdgbinsec); - continue; - } - pdgH->Fill(pdg, 1); // Filling the first bin and check its bin - const float pdgbin = pdgH->GetXaxis()->GetBinCenter(pdgH->GetXaxis()->FindBin(pdg)); - phiH->Fill(track.phi(), pdgbin); - etaH->Fill(track.eta(), pdgbin); - pH->Fill(track.p(), pdgbin); - ptH->Fill(track.pt(), pdgbin); - dcaxyH->Fill(track.dcaXY(), pdgbin); - dcazH->Fill(track.dcaZ(), pdgbin); - - etaDiff->Fill(track.label().eta() - track.eta(), pdgbin); - auto delta = track.label().phi() - track.phi(); - if (delta > M_PI) { - delta -= 2 * M_PI; - } - if (delta < -M_PI) { - delta += 2 * M_PI; - } - phiDiff->Fill(delta, pdgbin); - pDiff->Fill(sqrt(track.label().px() * track.label().px() + track.label().py() * track.label().py() + track.label().pz() * track.label().pz()) - track.p(), pdgbin); - ptDiff->Fill(track.label().pt() - track.pt(), pdgbin); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - const bool vertex = cfgc.options().get<int>("add-vertex"); - const bool gen = cfgc.options().get<int>("add-gen"); - const bool reco = cfgc.options().get<int>("add-reco"); - WorkflowSpec workflow{}; - if (vertex) { - workflow.push_back(adaptAnalysisTask<VertexTask>("vertex-histogram")); - } - if (gen) { - workflow.push_back(adaptAnalysisTask<GeneratedTask>("generator-histogram")); - } - if (reco) { - workflow.push_back(adaptAnalysisTask<ReconstructedTask>("reconstructed-histogram")); - } - return workflow; -} diff --git a/Analysis/Tasks/PWGLF/raacharged.cxx b/Analysis/Tasks/PWGLF/raacharged.cxx deleted file mode 100644 index 9f60a86a520bb..0000000000000 --- a/Analysis/Tasks/PWGLF/raacharged.cxx +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/MC.h" -#include <TH1F.h> -#include <TParticlePDG.h> -#include <TDatabasePDG.h> -#include <cmath> - -using namespace o2; -using namespace o2::framework; - -struct raacharged { - // data members - OutputObj<THnF> fHistTrack{"fHistTrack"}; - OutputObj<THnF> fHistEvent{"fHistEvent"}; - OutputObj<THnF> fHistMC{"fHistMC"}; - Configurable<int> selectedTracks{"select", 1, "Choice of track selection. 0 = no selection, 1 = globalTracks, 2 = globalTracksSDD"}; - // member functions - void init(InitContext const&) - { - constexpr Int_t nbinsMultCent = 11; - constexpr Int_t nnAcc = 54; - constexpr Int_t nbinspT = 82; - constexpr Int_t nChargeBins = 7; - - Double_t MultCent[] = {0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100}; - Double_t nAccbins[55]; //mult6kcoarse option in AlidNdPtTools - nAccbins[0] = -0.5; - int i = 0; - for (; i <= 10; i++) { - nAccbins[i + 1] = nAccbins[i] + 1; - } - for (; i <= 10 + 9; i++) { - nAccbins[i + 1] = nAccbins[i] + 10; - } - for (; i <= 10 + 9 + 9; i++) { - nAccbins[i + 1] = nAccbins[i] + 100; - } - for (; i <= 10 + 9 + 9 + 25; i++) { - nAccbins[i + 1] = nAccbins[i] + 200; - } - Double_t pTBins[] = {0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 180.0, 200.0}; - Double_t ChargeBins[] = {-2.5, -1.5, -0.5, 0., 0.5, 1.5, 2.5}; - - Int_t nBinsTrack[4] = {nbinsMultCent - 1, nnAcc - 1, nbinspT - 1, nChargeBins - 1}; - Double_t minTrack[4] = {MultCent[0], nAccbins[0], pTBins[0], ChargeBins[0]}; - Double_t maxTrack[4] = {MultCent[nbinsMultCent - 1], nAccbins[nnAcc - 1], pTBins[nbinspT - 1], ChargeBins[nChargeBins - 1]}; - - fHistTrack.setObject(new THnF("fHistTrack", "Hist. for tracks", 4, nBinsTrack, minTrack, maxTrack)); - fHistTrack->SetBinEdges(0, MultCent); - fHistTrack->SetBinEdges(1, nAccbins); - fHistTrack->SetBinEdges(2, pTBins); - fHistTrack->SetBinEdges(3, ChargeBins); - fHistTrack->GetAxis(0)->SetTitle("cent"); - fHistTrack->GetAxis(1)->SetTitle("nAcc"); - fHistTrack->GetAxis(2)->SetTitle("p_{T} (GeV/c)"); - fHistTrack->GetAxis(3)->SetTitle("Q"); - - constexpr Int_t nbinszV = 13; - Double_t ZvBins[] = {-30., -25., -20., -15., -10., -5., 0., 5., 10., 15., 20., 25., 30.}; - - Int_t nBinsEvent[3] = {nbinsMultCent - 1, nnAcc - 1, nbinszV - 1}; - Double_t minEvent[3] = {MultCent[0], nAccbins[0], ZvBins[0]}; - Double_t maxEvent[3] = {MultCent[nbinsMultCent - 1], nAccbins[nnAcc - 1], ZvBins[nbinszV - 1]}; - - fHistEvent.setObject(new THnF("fHistEvent", "Histogram for Events", 3, nBinsEvent, minEvent, maxEvent)); - fHistEvent->SetBinEdges(0, MultCent); - fHistEvent->SetBinEdges(1, nAccbins); - fHistEvent->SetBinEdges(2, ZvBins); - fHistEvent->GetAxis(0)->SetTitle("cent"); - fHistEvent->GetAxis(1)->SetTitle("nAcc"); - fHistEvent->GetAxis(2)->SetTitle("Zv (cm)"); - - constexpr Int_t nParTypeBins = 11; - constexpr Int_t nMCinfo = 4; - - Double_t ParTypeBins[11] = {-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5}; // 0=e, 1=mu, 2=pi, 3=K, 4=p, 6=sigmaP, 7=sigmaM, 8=xi, 9=omega, 5=other - Double_t MCinfoBins[4] = {-0.5, 0.5, 1.5, 2.5}; // 0=prim, 1=sec.(decays) 2=genprim , sec. from material not considered - - Int_t nBinsMC[5] = {nbinspT - 1, nParTypeBins - 1, nMCinfo - 1, nChargeBins - 1}; - Double_t minMC[5] = {pTBins[0], ParTypeBins[0], MCinfoBins[0], ChargeBins[0]}; - Double_t maxMC[5] = {pTBins[nbinspT - 1], ParTypeBins[nParTypeBins - 1], MCinfoBins[nMCinfo - 1], ChargeBins[nChargeBins - 1]}; - - fHistMC.setObject(new THnF("fHistMC", "Hist. for MC Info", 4, nBinsMC, minMC, maxMC)); - fHistMC->SetBinEdges(0, pTBins); - fHistMC->SetBinEdges(1, ParTypeBins); - fHistMC->SetBinEdges(2, MCinfoBins); - fHistMC->SetBinEdges(3, ChargeBins); - fHistMC->GetAxis(0)->SetTitle("MCp_{T} (GeV/c)"); - fHistMC->GetAxis(1)->SetTitle("Particle Type"); - fHistMC->GetAxis(2)->SetTitle("MCinfo"); - fHistMC->GetAxis(3)->SetTitle("Q"); - } - - Int_t WhichParticle(Int_t pdgCode) - { //see in AlidNdPtTools - if (pdgCode == 0) { - return -1; - } - if (pdgCode == std::abs(211)) { - return 0; //pi+, pi- - } - if (pdgCode == std::abs(321)) { - return 1; //K+, K- - } - if (pdgCode == std::abs(2212)) { - return 2; //p, pbar - } - if (pdgCode == 3222 || pdgCode == -3112) { - return 3; //sigmaPlus, SigmaBarMinus - } - if (pdgCode == 3112 || pdgCode == -3222) { - return 4; //sigmaMinus, SigmaBarPlus - } - if (pdgCode == std::abs(11)) { - return 5; //e-, e+ - } - if (pdgCode == std::abs(3312)) { - return 6; //XiP, XiM - } - if (pdgCode == std::abs(13)) { - return 7; //mu,antimu - } - if (pdgCode == std::abs(3334)) { - return 8; //OmegaP, OmegaM - } - - return 9; //other - } - Double_t MCCharge(Int_t pdgCode) - { - TParticlePDG* par = TDatabasePDG::Instance()->GetParticle(pdgCode); - Double_t charge = par->Charge() / 3.0; - return charge; - } - - Configurable<bool> isMC{"isMC", 1, "0 - data, 1 - MC"}; - - void process(soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels, aod::Cents>::iterator const& collision, soa::Join<aod::Tracks, aod::McTrackLabels, aod::TrackSelection> const& tracks, aod::McParticles& mcParticles) - { - if (!collision.alias()[kINT7]) { - return; - } - if (!collision.sel7()) { - return; - } - - Double_t eventValues[3] = {0.0, 0.0, collision.posZ()}; - fHistEvent->Fill(eventValues); - - for (auto& track : tracks) { - if (selectedTracks == 1 && !track.isGlobalTrack()) { - continue; - } else if (selectedTracks == 2 && !track.isGlobalTrackSDD()) { - continue; - } - - Double_t trackValues[4] = {0.0, 0.0, track.pt(), (Double_t)track.charge()}; - fHistTrack->Fill(trackValues); - - Double_t mcInfoVal; - if (!isMC) { - continue; - } - if (MC::isPhysicalPrimary(mcParticles, track.label())) { - mcInfoVal = 0.0; - } else { - mcInfoVal = 1.0; - } - - Double_t MCpt = track.label().pt(); - Double_t parType = (Double_t)WhichParticle(track.label().pdgCode()); - Double_t MCcharge = (Double_t)track.charge(); - Double_t MCvalues[4] = {MCpt, parType, mcInfoVal, MCcharge}; - - fHistMC->Fill(MCvalues); - } - if (isMC) { - for (auto& mcParticle : mcParticles) { - - if (abs(mcParticle.eta()) > 0.8) { - continue; - } - if (!MC::isPhysicalPrimary(mcParticles, mcParticle)) { - continue; - } - - Double_t MCpt = mcParticle.pt(); - Double_t parType = (Double_t)WhichParticle(mcParticle.pdgCode()); - Int_t pdg = (Int_t)mcParticle.pdgCode(); - Double_t MCcharge = MCCharge(pdg); - - if (MCcharge == 0.0) { - continue; - } - Double_t MCvalues[4] = {MCpt, parType, 2.0, MCcharge}; - fHistMC->Fill(MCvalues); - } - } - } -}; - -//-------------------------------------------------------------------- -// Workflow definition -//-------------------------------------------------------------------- -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<raacharged>("raa-charged")}; -} diff --git a/Analysis/Tasks/PWGLF/spectraTOF.cxx b/Analysis/Tasks/PWGLF/spectraTOF.cxx deleted file mode 100644 index 73a12607a8f96..0000000000000 --- a/Analysis/Tasks/PWGLF/spectraTOF.cxx +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "PID/PIDResponse.h" -#include "Analysis/TrackSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct TOFSpectraTask { - static constexpr int Np = 9; - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr const char* hp[Np] = {"p/El", "p/Mu", "p/Pi", "p/Ka", "p/Pr", "p/De", "p/Tr", "p/He", "p/Al"}; - static constexpr const char* hpt[Np] = {"pt/El", "pt/Mu", "pt/Pi", "pt/Ka", "pt/Pr", "pt/De", "pt/Tr", "pt/He", "pt/Al"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2::framework::InitContext&) - { - histos.add("p/Unselected", "Unselected;#it{p} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - histos.add("pt/Unselected", "Unselected;#it{p}_{T} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - for (int i = 0; i < Np; i++) { - histos.add(hp[i], Form("%s;#it{p} (GeV/#it{c})", pT[i]), kTH1F, {{100, 0, 20}}); - histos.add(hpt[i], Form("%s;#it{p}_{T} (GeV/#it{c})", pT[i]), kTH1F, {{100, 0, 20}}); - } - histos.add("electronbeta/hp_El", ";#it{p} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - histos.add("electronbeta/hpt_El", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - histos.add("electronbeta/hlength_El", ";Track Length (cm);Tracks", kTH1D, {{100, 0, 1000}}); - histos.add("electronbeta/htime_El", ";TOF Time (ns);Tracks", kTH1D, {{1000, 0, 600}}); - histos.add("electronbeta/hp_beta_El", ";#it{p} (GeV/#it{c});#beta - #beta_{e};Tracks", kTH2D, {{100, 0, 20}, {100, -0.01, 0.01}}); - histos.add("electronbeta/hp_betasigma_El", ";#it{p} (GeV/#it{c});(#beta - #beta_{e})/#sigma;Tracks", kTH2D, {{100, 0, 20}, {100, -5, 5}}); - } - - Configurable<float> cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable<float> cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; - Configurable<float> nsigmacut{"nsigmacut", 3, "Value of the Nsigma cut"}; - - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::isGlobalTrack == true) && (aod::track::tofSignal > 0.f); - using TrackCandidates = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::pidRespTOF, aod::pidRespTOFbeta, aod::TrackSelection>>; - void process(TrackCandidates::iterator const& track) - { - const float nsigma[Np] = {track.tofNSigmaEl(), track.tofNSigmaMu(), track.tofNSigmaPi(), - track.tofNSigmaKa(), track.tofNSigmaPr(), track.tofNSigmaDe(), - track.tofNSigmaTr(), track.tofNSigmaHe(), track.tofNSigmaAl()}; - histos.fill("p/Unselected", track.p()); - histos.fill("pt/Unselected", track.pt()); - for (int i = 0; i < Np; i++) { - if (abs(nsigma[i]) > nsigmacut.value) { - continue; - } - histos.fill(hp[i], track.p()); - histos.fill(hpt[i], track.pt()); - } - // - if (TMath::Abs(track.separationbetael() < 1.f)) { - histos.fill("electronbeta/hp_El", track.p()); - histos.fill("electronbeta/hpt_El", track.pt()); - histos.fill("electronbeta/hlength_El", track.length()); - histos.fill("electronbeta/htime_El", track.tofSignal() / 1000); - histos.fill("electronbeta/hp_beta_El", track.p(), track.diffbetael()); - histos.fill("electronbeta/hp_betasigma_El", track.p(), track.separationbetael()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - WorkflowSpec workflow{adaptAnalysisTask<TOFSpectraTask>("tofspectra-task")}; - return workflow; -} diff --git a/Analysis/Tasks/PWGLF/spectraTPC.cxx b/Analysis/Tasks/PWGLF/spectraTPC.cxx deleted file mode 100644 index f112b42012af1..0000000000000 --- a/Analysis/Tasks/PWGLF/spectraTPC.cxx +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "PID/PIDResponse.h" -#include "Analysis/TrackSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"add-tof-histos", VariantType::Int, 0, {"Generate TPC with TOF histograms"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -#define CANDIDATE_SELECTION \ - Configurable<float> cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; \ - Configurable<float> cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; \ - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; \ - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::isGlobalTrack == true); - -#define makelogaxis(h) \ - { \ - const Int_t nbins = h->GetNbinsX(); \ - double binp[nbins + 1]; \ - double max = h->GetXaxis()->GetBinUpEdge(nbins); \ - double min = h->GetXaxis()->GetBinLowEdge(1); \ - double lmin = TMath::Log10(min); \ - double ldelta = (TMath::Log10(max) - lmin) / ((double)nbins); \ - for (int i = 0; i < nbins; i++) { \ - binp[i] = TMath::Exp(TMath::Log(10) * (lmin + i * ldelta)); \ - } \ - binp[nbins] = max + 1; \ - h->GetXaxis()->Set(nbins, binp); \ - } - -constexpr int Np = 9; -struct TPCSpectraTask { - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr const char* hp[Np] = {"p/El", "p/Mu", "p/Pi", "p/Ka", "p/Pr", "p/De", "p/Tr", "p/He", "p/Al"}; - static constexpr const char* hpt[Np] = {"pt/El", "pt/Mu", "pt/Pi", "pt/Ka", "pt/Pr", "pt/De", "pt/Tr", "pt/He", "pt/Al"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2::framework::InitContext&) - { - histos.add("p/Unselected", "Unselected;#it{p} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - histos.add("pt/Unselected", "Unselected;#it{p}_{T} (GeV/#it{c})", kTH1F, {{100, 0, 20}}); - for (int i = 0; i < Np; i++) { - histos.add(hp[i], Form("%s;#it{p} (GeV/#it{c})", pT[i]), kTH1F, {{100, 0, 20}}); - histos.add(hpt[i], Form("%s;#it{p}_{T} (GeV/#it{c})", pT[i]), kTH1F, {{100, 0, 20}}); - } - } - - //Defining filters and input - CANDIDATE_SELECTION - - Configurable<float> nsigmacut{"nsigmacut", 3, "Value of the Nsigma cut"}; - - using TrackCandidates = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::pidRespTPC, aod::TrackSelection>>; - void process(TrackCandidates::iterator const& track) - { - const float nsigma[Np] = {track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), - track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.tpcNSigmaDe(), - track.tpcNSigmaTr(), track.tpcNSigmaHe(), track.tpcNSigmaAl()}; - histos.fill("p/Unselected", track.p()); - histos.fill("pt/Unselected", track.pt()); - for (int i = 0; i < Np; i++) { - if (abs(nsigma[i]) > nsigmacut.value) { - continue; - } - histos.fill(hp[i], track.p()); - histos.fill(hpt[i], track.pt()); - } - } -}; - -struct TPCPIDQASignalwTOFTask { - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr const char* htpcsignal[Np] = {"tpcsignal/El", "tpcsignal/Mu", "tpcsignal/Pi", - "tpcsignal/Ka", "tpcsignal/Pr", "tpcsignal/De", - "tpcsignal/Tr", "tpcsignal/He", "tpcsignal/Al"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2::framework::InitContext&) - { - for (int i = 0; i < Np; i++) { - histos.add(htpcsignal[i], Form(";#it{p} (GeV/#it{c});TPC Signal;N_{#sigma}^{TPC}(%s)", pT[i]), kTH3D, {{1000, 0.001, 20}, {1000, 0, 1000}, {20, -10, 10}}); - makelogaxis(histos.get<TH3>(htpcsignal[i])); - } - } - - // Filters - CANDIDATE_SELECTION - - Filter trackFilterTOF = (aod::track::tofSignal > 0.f); // Skip tracks without TOF - using TrackCandidates = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::pidRespTPC, aod::pidRespTOF, aod::TrackSelection>>; - void process(TrackCandidates::iterator const& track) - { - // const float mom = track.p(); - const float mom = track.tpcInnerParam(); - histos.fill(htpcsignal[0], mom, track.tpcSignal(), track.tofNSigmaEl()); - histos.fill(htpcsignal[1], mom, track.tpcSignal(), track.tofNSigmaMu()); - histos.fill(htpcsignal[2], mom, track.tpcSignal(), track.tofNSigmaPi()); - histos.fill(htpcsignal[3], mom, track.tpcSignal(), track.tofNSigmaKa()); - histos.fill(htpcsignal[4], mom, track.tpcSignal(), track.tofNSigmaPr()); - histos.fill(htpcsignal[5], mom, track.tpcSignal(), track.tofNSigmaDe()); - histos.fill(htpcsignal[6], mom, track.tpcSignal(), track.tofNSigmaTr()); - histos.fill(htpcsignal[7], mom, track.tpcSignal(), track.tofNSigmaHe()); - histos.fill(htpcsignal[8], mom, track.tpcSignal(), track.tofNSigmaAl()); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - int TPCwTOF = cfgc.options().get<int>("add-tof-histos"); - WorkflowSpec workflow{adaptAnalysisTask<TPCSpectraTask>("tpcspectra-task")}; - if (TPCwTOF) { - workflow.push_back(adaptAnalysisTask<TPCPIDQASignalwTOFTask>("TPCpidqa-signalwTOF-task")); - } - return workflow; -} diff --git a/Analysis/Tasks/PWGLF/trackchecks.cxx b/Analysis/Tasks/PWGLF/trackchecks.cxx deleted file mode 100644 index b8230dec9f549..0000000000000 --- a/Analysis/Tasks/PWGLF/trackchecks.cxx +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" -#include "Analysis/MC.h" -#include "Analysis/HistHelpers.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" - -#include <cmath> -#include <array> -#include <utility> - -#include <TH1.h> -#include <TH2.h> -#include <TF1.h> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::experimental::histhelpers; -using namespace std; - -#define NPTBINS 53 -#define NPARTICLES 5 -const double pt_bins[NPTBINS + 1] = {0.0, 0.05, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, - 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, - 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, - 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 10.0, 20.0}; -const double mass[NPARTICLES] = {0.000510999, 0.139570, 0.493677, 0.938272, 1.87561}; -enum PType : uint8_t { - kEl, - kPi, - kKa, - kPr, - kDe, - kNull -}; - -//function to convert eta to y -double eta2y(double pt, double m, double eta) -{ - double mt = sqrt(m * m + pt * pt); - return asinh(pt / mt * sinh(eta)); -} - -int getparticleint(int pdgcode) -{ - if (pdgcode == 11) { - return kEl; - } else if (pdgcode == 211) { - return kPi; - } else if (pdgcode == 321) { - return kKa; - } else if (pdgcode == 2212) { - return kPr; - } else if (pdgcode == 1000010020) { - return kDe; - } else { - return kNull; - } -} - -//No track selection --> only event selection here -struct TrackCheckTaskEvSel { - - Configurable<bool> isMC{"isMC", false, "option to flag mc"}; - Configurable<double> cfgCutY{"cfgCutY", 0.5, "option to configure rapidity cut"}; - Configurable<float> cfgCutVZ{"cfgCutVZ", 10.f, "option to configure z-vertex cut"}; - OutputObj<TH1F> hTrkPrimAftEvSel{TH1F("hTrkPrimAftEvSel", - "Reco Prim tracks AftEvSel (charged); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)}; - OutputObj<HistArray> hTrkPrimAftEvSel_truepid{HistArray("hTrkPrimAftEvSel_truepid"), - OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext&) - { - hTrkPrimAftEvSel_truepid->Add<kEl>(TH1F("hTrkPrimAftEvSel_truepid_el", - "Gen tracks aft. ev. sel. (true El); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimAftEvSel_truepid->Add<kPi>(TH1F("hTrkPrimAftEvSel_truepid_pi", - "Gen tracks aft. ev. sel. (true Pi); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimAftEvSel_truepid->Add<kKa>(TH1F("hTrkPrimAftEvSel_truepid_ka", - "Gen. tracks aft. ev. sel. (true Ka); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimAftEvSel_truepid->Add<kPr>(TH1F("hTrkPrimAftEvSel_truepid_pr", - "Gen tracks aft. ev. sel. (true Pr); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimAftEvSel_truepid->Add<kDe>(TH1F("hTrkPrimAftEvSel_truepid_de", - "Gen tracks aft. ev. sel. (true De); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - } //init - - //Filters - Filter collfilter = nabs(aod::collision::posZ) < cfgCutVZ; - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels>>::iterator const& col, - soa::Join<aod::Tracks, aod::TracksExtra, aod::McTrackLabels>& tracks, aod::McParticles& mcParticles) - { - - //event selection - if (!isMC && !col.alias()[kINT7]) { // trigger (should be skipped in MC) - return; - } - if (!col.sel7()) { //additional cuts - return; - } - - //Loop on tracks - for (auto& track : tracks) { - double y = -999.; - bool isPrimary = false; - - if (isMC) { //determine particle species base on MC truth and if it is primary or not - int pdgcode = track.label().pdgCode(); - - if (MC::isPhysicalPrimary(mcParticles, track.label())) { //is primary? - isPrimary = true; - } - - //calculate rapidity - int pint = getparticleint(pdgcode); - if (pint == kNull) { - y = (double)kNull; - } else { - y = eta2y(track.pt(), mass[pint], track.eta()); - } - - if (isPrimary && abs(y) < cfgCutY) { - //histograms with generated distribution (after event selection) - if (pdgcode == 11) { - hTrkPrimAftEvSel_truepid->Fill<kEl>(track.pt()); - } else if (pdgcode == 211) { - hTrkPrimAftEvSel_truepid->Fill<kPi>(track.pt()); - } else if (pdgcode == 321) { - hTrkPrimAftEvSel_truepid->Fill<kKa>(track.pt()); - } else if (pdgcode == 2212) { - hTrkPrimAftEvSel_truepid->Fill<kPr>(track.pt()); - } else if (pdgcode == 1000010020) { - hTrkPrimAftEvSel_truepid->Fill<kDe>(track.pt()); - } - - hTrkPrimAftEvSel->Fill(track.pt()); //charged particles - } - } - } // end loop on tracks - } //end of process -}; //end struct TrackCheckTaskEvSel - -//event selection + track selection here -struct TrackCheckTaskEvSelTrackSel { - - Configurable<bool> isMC{"isMC", false, "option to flag mc"}; - Configurable<double> cfgCutY{"cfgCutY", 0.5, "option to configure rapidity cut"}; - Configurable<float> cfgCutVZ{"cfgCutVZ", 10.f, "option to configure z-vertex cut"}; - OutputObj<TH1F> hTrkPrimReco{TH1F("hTrkPrimReco", "Reco Prim tracks (charged); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)}; - OutputObj<HistArray> hTrkPrimReco_truepid{HistArray("hTrkPrimReco_truepid"), - OutputObjHandlingPolicy::AnalysisObject}; - OutputObj<HistArray> hDCAxyReco_truepid{HistArray("hDCAxyReco_truepid"), OutputObjHandlingPolicy::AnalysisObject}; - OutputObj<HistArray> hDCAxyPrim_truepid{HistArray("hDCAxyPrim_truepid"), OutputObjHandlingPolicy::AnalysisObject}; - OutputObj<HistArray> hDCAxySeco_truepid{HistArray("hDCAxySeco_truepid"), OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext&) - { - hTrkPrimReco_truepid->Add<kEl>(TH1F("hTrkPrimReco_truepid_el", - "Primary Reco tracks (true El); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimReco_truepid->Add<kPi>(TH1F("hTrkPrimReco_truepid_pi", - "Primary Reco tracks (true Pi); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimReco_truepid->Add<kKa>(TH1F("hTrkPrimReco_truepid_ka", - "Primary Reco tracks (true Ka); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimReco_truepid->Add<kPr>(TH1F("hTrkPrimReco_truepid_pr", - "Primary Reco tracks (true Pr); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - hTrkPrimReco_truepid->Add<kDe>(TH1F("hTrkPrimReco_truepid_de", - "Primary Reco tracks (true De); #it{p}_{T} (GeV/#it{c}); Counts", - NPTBINS, pt_bins)); - - hDCAxyReco_truepid->Add<kEl>(TH2F("hDCAxyReco_truepid_el", - "DCAxy reco (true El); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyReco_truepid->Add<kPi>(TH2F("hDCAxyReco_truepid_pi", - "DCAxy reco (true Pi); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyReco_truepid->Add<kKa>(TH2F("hDCAxyReco_truepid_ka", - "DCAxy reco (true Ka); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyReco_truepid->Add<kPr>(TH2F("hDCAxyReco_truepid_pr", - "DCAxy reco (true Pr); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyReco_truepid->Add<kDe>(TH2F("hDCAxyReco_truepid_de", - "DCAxy reco (true De); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - - hDCAxyPrim_truepid->Add<kEl>(TH2F("hDCAxyPrim_truepid_el", - "DCAxy primaries (true El); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyPrim_truepid->Add<kPi>(TH2F("hDCAxyPrim_truepid_pi", - "DCAxy primaries (true Pi); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyPrim_truepid->Add<kKa>(TH2F("hDCAxyPrim_truepid_ka", - "DCAxy primaries (true Ka); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyPrim_truepid->Add<kPr>(TH2F("hDCAxyPrim_truepid_pr", - "DCAxy primaries (true Pr); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxyPrim_truepid->Add<kDe>(TH2F("hDCAxyPrim_truepid_de", - "DCAxy primaries (true De); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - - hDCAxySeco_truepid->Add<kEl>(TH2F("hDCAxySeco_truepid_el", - "DCAxy secondaries (true El); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxySeco_truepid->Add<kPi>(TH2F("hDCAxySeco_truepid_pi", - "DCAxy secondaries (true Pi); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxySeco_truepid->Add<kKa>(TH2F("hDCAxySeco_truepid_ka", - "DCAxy secondaries (true Ka); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxySeco_truepid->Add<kPr>(TH2F("hDCAxySeco_truepid_pr", - "DCAxy secondaries (true Pr); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - hDCAxySeco_truepid->Add<kDe>(TH2F("hDCAxySeco_truepid_de", - "DCAxy secondaries (true De); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", - NPTBINS, pt_bins, 800, -4., 4.)); - - } //init - - //Filters - Filter collfilter = nabs(aod::collision::posZ) < cfgCutVZ; - Filter trackfilter = aod::track::isGlobalTrack == true; - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels>>::iterator const& col, - soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksExtended, - aod::TrackSelection, aod::McTrackLabels>>& tracks, - aod::McParticles& mcParticles) - { - - //event selection - if (!isMC && !col.alias()[kINT7]) { // trigger (should be skipped in MC) - return; - } - if (!col.sel7()) { //additional cuts - return; - } - - //Loop on tracks - for (auto& track : tracks) { - double y = -999.; - bool isPrimary = false; - - if (isMC) { //determine particle species base on MC truth and if it is primary or not - int pdgcode = track.label().pdgCode(); - - if (MC::isPhysicalPrimary(mcParticles, track.label())) { //is primary? - isPrimary = true; - } - //Calculate y - int pint = getparticleint(pdgcode); - if (pint == kNull) { - y = (double)kNull; - } else { - y = eta2y(track.pt(), mass[pint], track.eta()); - } - - //DCAxy distributions for reco, primary, secondaries (= not primary) - // + distributions for reco primaries (MC truth) - if (abs(y) < cfgCutY) { - if (pdgcode == 11) { - hDCAxyReco_truepid->Fill<kEl>(track.pt(), track.dcaXY()); - if (isPrimary) { - hDCAxyPrim_truepid->Fill<kEl>(track.pt(), track.dcaXY()); - hTrkPrimReco_truepid->Fill<kEl>(track.pt()); - } else { - hDCAxySeco_truepid->Fill<kEl>(track.pt(), track.dcaXY()); - } - } else if (pdgcode == 211) { - hDCAxyReco_truepid->Fill<kPi>(track.pt(), track.dcaXY()); - if (isPrimary) { - hDCAxyPrim_truepid->Fill<kPi>(track.pt(), track.dcaXY()); - hTrkPrimReco_truepid->Fill<kPi>(track.pt()); - } else { - hDCAxySeco_truepid->Fill<kPi>(track.pt(), track.dcaXY()); - } - } else if (pdgcode == 321) { - hDCAxyReco_truepid->Fill<kKa>(track.pt(), track.dcaXY()); - if (isPrimary) { - hDCAxyPrim_truepid->Fill<kKa>(track.pt(), track.dcaXY()); - hTrkPrimReco_truepid->Fill<kKa>(track.pt()); - } else { - hDCAxySeco_truepid->Fill<kKa>(track.pt(), track.dcaXY()); - } - } else if (pdgcode == 2212) { - hDCAxyReco_truepid->Fill<kPr>(track.pt(), track.dcaXY()); - if (isPrimary) { - hDCAxyPrim_truepid->Fill<kPr>(track.pt(), track.dcaXY()); - hTrkPrimReco_truepid->Fill<kPr>(track.pt()); - } else { - hDCAxySeco_truepid->Fill<kPr>(track.pt(), track.dcaXY()); - } - } else if (pdgcode == 1000010020) { - hDCAxyReco_truepid->Fill<kDe>(track.pt(), track.dcaXY()); - if (isPrimary) { - hDCAxyPrim_truepid->Fill<kDe>(track.pt(), track.dcaXY()); - hTrkPrimReco_truepid->Fill<kDe>(track.pt()); - } else { - hDCAxySeco_truepid->Fill<kDe>(track.pt(), track.dcaXY()); - } - } - } - - //reco histos (charged particles) - if (isPrimary && abs(y) < cfgCutY) { - hTrkPrimReco->Fill(track.pt()); //charged particles - } - } - } // end loop on tracks - } -}; // struct TrackCheckTask1 - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<TrackCheckTaskEvSel>("track-histos-evsel"), - adaptAnalysisTask<TrackCheckTaskEvSelTrackSel>("track-histos-evsel-trksel")}; -} diff --git a/Analysis/Tasks/PWGMM/CMakeLists.txt b/Analysis/Tasks/PWGMM/CMakeLists.txt deleted file mode 100644 index b0a6b6fadcc0f..0000000000000 --- a/Analysis/Tasks/PWGMM/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_dpl_workflow(dNdetaRun2Tracklets-analysis - SOURCES dNdetaRun2Tracklets.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx b/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx deleted file mode 100644 index ac949f823fcb5..0000000000000 --- a/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include <TH1F.h> -#include <TH2F.h> -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct PseudorapidityDensity { - - Configurable<double> etaBinWidth{"etaBinWidth", 0.1, "eta bin width"}; - Configurable<float> etaMax{"etaMax", 1.5, "max eta value"}; - Configurable<float> etaMin{"etaMin", -1.5, "min eta value"}; - Configurable<float> vtxZMax{"vtxZMax", 10, "max z vertex"}; - Configurable<float> vtxZMin{"vtxZMin", -10, "min z vertex"}; - int etaBins = TMath::Nint((etaMax - etaMin) / etaBinWidth); - int vtxZBins = TMath::Nint(vtxZMax - vtxZMin); - - OutputObj<TH1F> hStat{TH1F("hStat", "TotalEvents", 1, 0.5, 1.5)}; - OutputObj<TH1F> hdNdeta{TH1F("hdNdeta", "dNdeta", 50, -2.5, 2.5)}; - OutputObj<TH2F> vtxZEta{TH2F("vtxZEta", ";#eta;vtxZ", 50, -2.5, 2.5, 60, -30, 30)}; - OutputObj<TH2F> phiEta{TH2F("phiEta", ";#eta;#varphi", 50, -2.5, 2.5, 200, 0., 2 * TMath::Pi())}; - - // TODO remove static casts for configurables when fixed - Filter etaFilter = (aod::track::eta < (float)etaMax) && (aod::track::eta > (float)etaMin); - Filter trackTypeFilter = (aod::track::trackType == static_cast<uint8_t>(aod::track::TrackTypeEnum::Run2Tracklet)); - Filter posZFilter = (aod::collision::posZ < (float)vtxZMax) && (aod::collision::posZ > (float)vtxZMin); - - void process(soa::Filtered<soa::Join<aod::Collisions, aod::EvSels>>::iterator const& collisions, soa::Filtered<aod::Tracks> const& tracklets) - { - // TODO change to sel7 filter expression when implemented - if (!collisions.sel7()) - return; - hStat->Fill(collisions.size()); - auto vtxZ = collisions.posZ(); - for (auto& track : tracklets) { - vtxZEta->Fill(track.eta(), vtxZ); - phiEta->Fill(track.eta(), track.phi()); - hdNdeta->Fill(track.eta()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<PseudorapidityDensity>("dNdetaRun2Tracklets-analysis")}; -} diff --git a/Analysis/Tasks/PWGUD/CMakeLists.txt b/Analysis/Tasks/PWGUD/CMakeLists.txt deleted file mode 100644 index ab3c773a4ce99..0000000000000 --- a/Analysis/Tasks/PWGUD/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_dpl_workflow(upc-an - SOURCES upcAnalysis.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGUD/upcAnalysis.cxx b/Analysis/Tasks/PWGUD/upcAnalysis.cxx deleted file mode 100644 index 151d220c485c5..0000000000000 --- a/Analysis/Tasks/PWGUD/upcAnalysis.cxx +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/EventSelection.h" -#include <TH1D.h> -#include <TH2D.h> -#include <cmath> -#include <vector> -#include "TLorentzVector.h" -#include "TVector3.h" - -using namespace o2; -using namespace o2::framework; - -#define mpion 0.13957 - -struct UPCAnalysis { - OutputObj<TH1D> hMass{TH1D("hMass", ";#it{m_{#pi#pi}}, GeV/c^{2};", 500, 0.55, 1.4)}; - OutputObj<TH1D> hPt{TH1D("hPt", ";#it{p_{T}}, GeV/c;", 500, 0., 1.)}; - OutputObj<TH2D> hSignalTPC1vsSignalTPC2{TH2D("hSignalTPC1vsSignalTPC2", ";TPC Signal 1;TPC Signal 2", 1000, 0., 200., 1000, 0., 200.)}; - - void process(soa::Join<aod::Collisions, aod::EvSels>::iterator const& col, soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection> const& tracks) - { - bool checkV0 = col.bbV0A() || col.bbV0C() || col.bgV0A() || col.bgV0C(); - if (checkV0) { - return; - } - bool checkFDD = col.bbFDA() || col.bbFDC() || col.bgFDA() || col.bgFDC(); - if (checkFDD) { - return; - } - if (!col.alias()[kCUP9]) { - return; - } - std::vector<soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection>::iterator> selTracks; - for (auto track : tracks) { - if (!track.isGlobalTrack()) { - continue; - } - selTracks.push_back(track); - if (selTracks.size() > 2) { - break; - } - } - if (selTracks.size() != 2) { - return; - } - if (selTracks[0].charge() * selTracks[1].charge() >= 0) { - return; - } - UChar_t clustermap1 = selTracks[0].itsClusterMap(); - UChar_t clustermap2 = selTracks[1].itsClusterMap(); - bool checkClusMap = TESTBIT(clustermap1, 0) && TESTBIT(clustermap1, 1) && TESTBIT(clustermap2, 0) && TESTBIT(clustermap2, 1); - if (!checkClusMap) { - return; - } - TLorentzVector p1, p2, p; - p1.SetXYZM(selTracks[0].px(), selTracks[0].py(), selTracks[0].pz(), mpion); - p2.SetXYZM(selTracks[1].px(), selTracks[1].py(), selTracks[1].pz(), mpion); - p = p1 + p2; - hPt->Fill(p.Pt()); - float signalTPC1 = selTracks[0].tpcSignal(); - float signalTPC2 = selTracks[1].tpcSignal(); - hSignalTPC1vsSignalTPC2->Fill(signalTPC1, signalTPC2); - if ((p.Pt() < 0.1) && (signalTPC1 + signalTPC2 < 140.)) { - hMass->Fill(p.M()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<UPCAnalysis>("upc-an")}; -} diff --git a/Analysis/Tasks/centralityQa.cxx b/Analysis/Tasks/centralityQa.cxx deleted file mode 100644 index 7871c2bea6378..0000000000000 --- a/Analysis/Tasks/centralityQa.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include "TH1F.h" - -using namespace o2; -using namespace o2::framework; - -struct CentralityQaTask { - OutputObj<TH1F> hCentV0M{TH1F("hCentV0M", "", 21, 0, 105.)}; - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator const& col) - { - if (!col.alias()[kINT7]) { - return; - } - if (!col.sel7()) { - return; - } - - LOGF(debug, "centV0M=%.0f", col.centV0M()); - // fill centrality histos - hCentV0M->Fill(col.centV0M()); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<CentralityQaTask>("centrality-qa")}; -} diff --git a/Analysis/Tasks/centralityTable.cxx b/Analysis/Tasks/centralityTable.cxx deleted file mode 100644 index 19dac63be3746..0000000000000 --- a/Analysis/Tasks/centralityTable.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/Centrality.h" -#include <CCDB/BasicCCDBManager.h> -#include "TH1F.h" - -using namespace o2; -using namespace o2::framework; - -struct CentralityTableTask { - Produces<aod::Cents> cent; - Service<o2::ccdb::BasicCCDBManager> ccdb; - - void init(InitContext&) - { - ccdb->setURL("http://ccdb-test.cern.ch:8080"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - } - - void process(soa::Join<aod::Collisions, aod::Mults>::iterator const& collision, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as<aod::BCsWithTimestamps>(); - LOGF(debug, "timestamp=%llu", bc.timestamp()); - TH1F* hCumMultV0M = ccdb->getForTimeStamp<TH1F>("Multiplicity/CumMultV0M", bc.timestamp()); - if (!hCumMultV0M) { - LOGF(fatal, "V0M centrality calibration is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); - } - float centV0M = hCumMultV0M->GetBinContent(hCumMultV0M->FindFixBin(collision.multV0M())); - - LOGF(debug, "centV0M=%.0f", centV0M); - // fill centrality columns - cent(centV0M); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<CentralityTableTask>("centrality-table")}; -} diff --git a/Analysis/Tasks/eventSelection.cxx b/Analysis/Tasks/eventSelection.cxx deleted file mode 100644 index 084ec4dc02404..0000000000000 --- a/Analysis/Tasks/eventSelection.cxx +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" -#include "Analysis/TriggerAliases.h" -#include <CCDB/BasicCCDBManager.h> - -using namespace o2; -using namespace o2::framework; - -struct EvSelParameters { - // time-of-flight offset - float fV0ADist = 329.00 / TMath::Ccgs() * 1e9; // ns - float fV0CDist = 87.15 / TMath::Ccgs() * 1e9; // ns - - float fFDADist = (1695.30 + 1698.04) / TMath::Ccgs() * 1e9; // ns - float fFDCDist = (1952.90 + 1955.90) / TMath::Ccgs() * 1e9; // ns - - // beam-beam and beam-gas windows - float fV0ABBlower = +fV0ADist - 9.5; // ns - float fV0ABBupper = +fV0ADist + 22.5; // ns - float fV0ABGlower = -fV0ADist - 2.5; // ns - float fV0ABGupper = -fV0ADist + 5.0; // ns - float fV0CBBlower = +fV0CDist - 2.5; // ns - float fV0CBBupper = +fV0CDist + 22.5; // ns - float fV0CBGlower = -fV0CDist - 2.5; // ns - float fV0CBGupper = -fV0CDist + 2.5; // ns - - float fFDABBlower = +fFDADist - 2.5; // ns - float fFDABBupper = +fFDADist + 2.5; // ns - float fFDABGlower = -fFDADist - 4.0; // ns - float fFDABGupper = -fFDADist + 4.0; // ns - - float fFDCBBlower = +fFDCDist - 1.5; // ns - float fFDCBBupper = +fFDCDist + 1.5; // ns - float fFDCBGlower = -fFDCDist - 2.0; // ns - float fFDCBGupper = -fFDCDist + 2.0; // ns - - float fZNABBlower = -2.0; // ns - float fZNABBupper = 2.0; // ns - float fZNCBBlower = -2.0; // ns - float fZNCBBupper = 2.0; // ns - - // TODO rough cuts to be adjusted - float fT0ABBlower = -2.0; // ns - float fT0ABBupper = 2.0; // ns - float fT0CBBlower = -2.0; // ns - float fT0CBBupper = 2.0; // ns -}; - -struct EventSelectionTask { - Produces<aod::EvSels> evsel; - Service<o2::ccdb::BasicCCDBManager> ccdb; - Configurable<bool> isMC{"isMC", 0, "0 - data, 1 - MC"}; - - EvSelParameters par; - - void init(InitContext&) - { - ccdb->setURL("http://ccdb-test.cern.ch:8080"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - } - - void process(aod::Run2MatchedSparse::iterator const& collision, aod::BCsWithTimestamps const&, aod::Zdcs const& zdcs, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::FT0s const& ft0s, aod::FDDs const& fdds) - { - auto bc = collision.bc_as<aod::BCsWithTimestamps>(); - LOGF(debug, "timestamp=%llu", bc.timestamp()); - TriggerAliases* aliases = ccdb->getForTimeStamp<TriggerAliases>("Trigger/TriggerAliases", bc.timestamp()); - if (!aliases) { - LOGF(fatal, "Trigger aliases are not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); - } - uint64_t triggerMask = bc.triggerMask(); - LOGF(debug, "triggerMask=%llu", triggerMask); - - // fill fired aliases - int32_t alias[kNaliases] = {0}; - for (auto& al : aliases->GetAliasToClassIdsMap()) { - for (auto& classIndex : al.second) { - alias[al.first] |= (triggerMask & (1ull << classIndex)) > 0; - } - } - - float timeZNA = collision.has_zdc() ? collision.zdc().timeZNA() : -999.f; - float timeZNC = collision.has_zdc() ? collision.zdc().timeZNC() : -999.f; - float timeV0A = collision.has_fv0a() ? collision.fv0a().time() : -999.f; - float timeV0C = collision.has_fv0c() ? collision.fv0c().time() : -999.f; - float timeT0A = collision.has_ft0() ? collision.ft0().timeA() : -999.f; - float timeT0C = collision.has_ft0() ? collision.ft0().timeC() : -999.f; - float timeFDA = collision.has_fdd() ? collision.fdd().timeA() : -999.f; - float timeFDC = collision.has_fdd() ? collision.fdd().timeC() : -999.f; - - LOGF(debug, "timeZNA=%f timeZNC=%f", timeZNA, timeZNC); - LOGF(debug, "timeV0A=%f timeV0C=%f", timeV0A, timeV0C); - LOGF(debug, "timeFDA=%f timeFDC=%f", timeFDA, timeFDC); - LOGF(debug, "timeT0A=%f timeT0C=%f", timeT0A, timeT0C); - - bool bbZNA = timeZNA > par.fZNABBlower && timeZNA < par.fZNABBupper; - bool bbZNC = timeZNC > par.fZNCBBlower && timeZNC < par.fZNCBBupper; - bool bbV0A = timeV0A > par.fV0ABBlower && timeV0A < par.fV0ABBupper; - bool bbV0C = timeV0C > par.fV0CBBlower && timeV0C < par.fV0CBBupper; - bool bgV0A = timeV0A > par.fV0ABGlower && timeV0A < par.fV0ABGupper; - bool bgV0C = timeV0C > par.fV0CBGlower && timeV0C < par.fV0CBGupper; - bool bbFDA = timeFDA > par.fFDABBlower && timeFDA < par.fFDABBupper; - bool bbFDC = timeFDC > par.fFDCBBlower && timeFDC < par.fFDCBBupper; - bool bgFDA = timeFDA > par.fFDABGlower && timeFDA < par.fFDABGupper; - bool bgFDC = timeFDC > par.fFDCBGlower && timeFDC < par.fFDCBGupper; - bool bbT0A = timeT0A > par.fT0ABBlower && timeT0A < par.fT0ABBupper; - bool bbT0C = timeT0C > par.fT0CBBlower && timeT0C < par.fT0CBBupper; - - if (isMC) { - bbZNA = 1; - bbZNC = 1; - } - - // Fill event selection columns - evsel(alias, bbT0A, bbT0C, bbV0A, bbV0C, bgV0A, bgV0C, bbZNA, bbZNC, bbFDA, bbFDC, bgFDA, bgFDC); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<EventSelectionTask>("event-selection")}; -} diff --git a/Analysis/Tasks/eventSelectionQa.cxx b/Analysis/Tasks/eventSelectionQa.cxx deleted file mode 100644 index 3b629d5f95d58..0000000000000 --- a/Analysis/Tasks/eventSelectionQa.cxx +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" - -using namespace o2; -using namespace o2::framework; - -struct EventSelectionTask { - aod::FV0A getVZeroA(aod::BC const& bc, aod::FV0As const& vzeros) - { - for (auto& vzero : vzeros) { - if (vzero.bc() == bc) { - return vzero; - } - } - aod::FV0A dummy; - return dummy; - } - - aod::FV0C getVZeroC(aod::BC const& bc, aod::FV0Cs const& vzeros) - { - for (auto& vzero : vzeros) { - if (vzero.bc() == bc) { - return vzero; - } - } - aod::FV0C dummy; - return dummy; - } - - aod::Zdc getZdc(aod::BC const& bc, aod::Zdcs const& zdcs) - { - for (auto& zdc : zdcs) { - if (zdc.bc() == bc) { - return zdc; - } - } - aod::Zdc dummy; - return dummy; - } - - aod::FT0 getFT0(aod::BC const& bc, aod::FT0s const& ft0s) - { - for (auto& ft0 : ft0s) { - if (ft0.bc() == bc) { - return ft0; - } - } - aod::FT0 dummy; - return dummy; - } - - aod::FDD getFDD(aod::BC const& bc, aod::FDDs const& fdds) - { - for (auto& fdd : fdds) { - if (fdd.bc() == bc) { - return fdd; - } - } - aod::FDD dummy; - return dummy; - } - - OutputObj<TH1F> hTimeV0Aall{TH1F("hTimeV0Aall", "", 200, -50., 50.)}; - OutputObj<TH1F> hTimeV0Call{TH1F("hTimeV0Call", "", 200, -50., 50.)}; - OutputObj<TH1F> hTimeZNAall{TH1F("hTimeZNAall", "", 250, -25., 25.)}; - OutputObj<TH1F> hTimeZNCall{TH1F("hTimeZNCall", "", 250, -25., 25.)}; - OutputObj<TH1F> hTimeT0Aall{TH1F("hTimeT0Aall", "", 200, -10., 10.)}; - OutputObj<TH1F> hTimeT0Call{TH1F("hTimeT0Call", "", 200, -10., 10.)}; - OutputObj<TH1F> hTimeFDAall{TH1F("hTimeFDAall", "", 1000, -100., 100.)}; - OutputObj<TH1F> hTimeFDCall{TH1F("hTimeFDCall", "", 1000, -100., 100.)}; - OutputObj<TH1F> hTimeV0Aacc{TH1F("hTimeV0Aacc", "", 200, -50., 50.)}; - OutputObj<TH1F> hTimeV0Cacc{TH1F("hTimeV0Cacc", "", 200, -50., 50.)}; - OutputObj<TH1F> hTimeZNAacc{TH1F("hTimeZNAacc", "", 250, -25., 25.)}; - OutputObj<TH1F> hTimeZNCacc{TH1F("hTimeZNCacc", "", 250, -25., 25.)}; - OutputObj<TH1F> hTimeT0Aacc{TH1F("hTimeT0Aacc", "", 200, -10., 10.)}; - OutputObj<TH1F> hTimeT0Cacc{TH1F("hTimeT0Cacc", "", 200, -10., 10.)}; - OutputObj<TH1F> hTimeFDAacc{TH1F("hTimeFDAacc", "", 1000, -100., 100.)}; - OutputObj<TH1F> hTimeFDCacc{TH1F("hTimeFDCacc", "", 1000, -100., 100.)}; - - Configurable<bool> isMC{"isMC", 0, "0 - data, 1 - MC"}; - - void process(soa::Join<aod::Collisions, aod::EvSels>::iterator const& col, aod::BCs const& bcs, aod::Zdcs const& zdcs, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::FT0s ft0s, aod::FDDs fdds) - { - if (!isMC && !col.alias()[kINT7]) { - return; - } - - auto fv0a = getVZeroA(col.bc(), fv0as); - auto fv0c = getVZeroC(col.bc(), fv0cs); - hTimeV0Aall->Fill(fv0a.time()); - hTimeV0Call->Fill(fv0c.time()); - - auto zdc = getZdc(col.bc(), zdcs); - hTimeZNAall->Fill(zdc.timeZNA()); - hTimeZNCall->Fill(zdc.timeZNC()); - - auto ft0 = getFT0(col.bc(), ft0s); - hTimeT0Aall->Fill(ft0.timeA()); - hTimeT0Call->Fill(ft0.timeC()); - - auto fdd = getFDD(col.bc(), fdds); - hTimeFDAall->Fill(fdd.timeA()); - hTimeFDCall->Fill(fdd.timeC()); - - if (!col.sel7()) { - return; - } - - hTimeV0Aacc->Fill(fv0a.time()); - hTimeV0Cacc->Fill(fv0c.time()); - hTimeZNAacc->Fill(zdc.timeZNA()); - hTimeZNCacc->Fill(zdc.timeZNC()); - hTimeT0Aacc->Fill(ft0.timeA()); - hTimeT0Cacc->Fill(ft0.timeC()); - hTimeFDAacc->Fill(fdd.timeA()); - hTimeFDCacc->Fill(fdd.timeC()); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<EventSelectionTask>("event-selection-qa")}; -} diff --git a/Analysis/Tasks/multiplicityQa.cxx b/Analysis/Tasks/multiplicityQa.cxx deleted file mode 100644 index c3332b31d505e..0000000000000 --- a/Analysis/Tasks/multiplicityQa.cxx +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/EventSelection.h" -#include "TH1F.h" -#include "TH2F.h" - -using namespace o2; -using namespace o2::framework; - -struct MultiplicityQaTask { - OutputObj<TH1F> hMultV0M{TH1F("hMultV0M", "", 50000, 0., 50000.)}; - OutputObj<TH1F> hMultT0M{TH1F("hMultT0M", "", 10000, 0., 200000.)}; - OutputObj<TH1F> hMultZNA{TH1F("hMultZNA", "", 600, 0., 240000.)}; - OutputObj<TH1F> hMultZNC{TH1F("hMultZNC", "", 600, 0., 240000.)}; - OutputObj<TH2F> hMultV0MvsT0M{TH2F("hMultV0MvsT0M", ";V0M;T0M", 200, 0., 50000., 200, 0., 200000.)}; - - OutputObj<TProfile> hMultNtrackletsVsV0M{TProfile("hMultNtrackletsVsV0M", "", 50000, 0., 50000.)}; - - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Mults>::iterator const& col) - { - if (!col.alias()[kINT7]) { - return; - } - if (!col.sel7()) { - return; - } - - LOGF(debug, "multV0A=%5.0f multV0C=%5.0f multV0M=%5.0f multT0A=%5.0f multT0C=%5.0f multT0M=%5.0f", col.multV0A(), col.multV0C(), col.multV0M(), col.multT0A(), col.multT0C(), col.multT0M()); - // fill calibration histos - hMultV0M->Fill(col.multV0M()); - hMultT0M->Fill(col.multT0M()); - hMultZNA->Fill(col.multZNA()); - hMultZNC->Fill(col.multZNC()); - hMultV0MvsT0M->Fill(col.multV0M(), col.multT0M()); - hMultNtrackletsVsV0M->Fill(col.multV0M(), col.multTracklets()); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<MultiplicityQaTask>("multiplicity-qa")}; -} diff --git a/Analysis/Tasks/multiplicityTable.cxx b/Analysis/Tasks/multiplicityTable.cxx deleted file mode 100644 index e79d2f70e21a6..0000000000000 --- a/Analysis/Tasks/multiplicityTable.cxx +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Multiplicity.h" -#include "iostream" -using namespace o2; -using namespace o2::framework; - -struct MultiplicityTableTaskIndexed { - Produces<aod::Mults> mult; - Partition<aod::Tracks> tracklets = (aod::track::trackType == static_cast<uint8_t>(o2::aod::track::TrackTypeEnum::Run2Tracklet)); - - void process(aod::Run2MatchedSparse::iterator const& collision, aod::Tracks const& tracks, aod::BCs const&, aod::Zdcs const&, aod::FV0As const& fv0as, aod::FV0Cs const& fv0cs, aod::FT0s const& ft0s) - { - float multV0A = -1.f; - float multV0C = -1.f; - float multT0A = -1.f; - float multT0C = -1.f; - float multZNA = -1.f; - float multZNC = -1.f; - int multTracklets = tracklets.size(); - - if (collision.has_fv0a()) { - auto v0a = collision.fv0a(); - for (int i = 0; i < 48; i++) { - multV0A += v0a.amplitude()[i]; - } - } - if (collision.has_fv0c()) { - auto v0c = collision.fv0c(); - for (int i = 0; i < 32; i++) { - multV0C += v0c.amplitude()[i]; - } - } - if (collision.has_ft0()) { - auto ft0 = collision.ft0(); - for (int i = 0; i < 96; i++) { - multT0A += ft0.amplitudeA()[i]; - } - for (int i = 0; i < 112; i++) { - multT0C += ft0.amplitudeC()[i]; - } - } - if (collision.has_zdc()) { - auto zdc = collision.zdc(); - multZNA = zdc.energyCommonZNA(); - multZNC = zdc.energyCommonZNC(); - } - LOGF(debug, "multV0A=%5.0f multV0C=%5.0f multT0A=%5.0f multT0C=%5.0f multZNA=%6.0f multZNC=%6.0f multTracklets=%i", multV0A, multV0C, multT0A, multT0C, multZNA, multZNC, multTracklets); - mult(multV0A, multV0C, multT0A, multT0C, multZNA, multZNC, multTracklets); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<MultiplicityTableTaskIndexed>("multiplicity-table")}; -} diff --git a/Analysis/Tasks/pidTOF.cxx b/Analysis/Tasks/pidTOF.cxx deleted file mode 100644 index 665f9217f0942..0000000000000 --- a/Analysis/Tasks/pidTOF.cxx +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "ReconstructionDataFormats/Track.h" -#include <CCDB/BasicCCDBManager.h> -#include "PID/PIDResponse.h" -#include "PID/PIDTOF.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::pid; -using namespace o2::framework::expressions; -using namespace o2::track; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"add-qa", VariantType::Int, 0, {"Produce TOF PID QA histograms"}}, - {"add-beta", VariantType::Int, 0, {"Produce TOF Beta table"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -struct pidTOFTask { - using Trks = soa::Join<aod::Tracks, aod::TracksExtra>; - using Coll = aod::Collision; - Produces<aod::pidRespTOF> tofpid; - DetectorResponse resp; - Service<o2::ccdb::BasicCCDBManager> ccdb; - Configurable<std::string> paramfile{"param-file", "", "Path to the parametrization object, if emtpy the parametrization is not taken from file"}; - Configurable<std::string> sigmaname{"param-sigma", "TOFReso", "Name of the parametrization for the expected sigma, used in both file and CCDB mode"}; - Configurable<std::string> url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; - Configurable<long> timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - - void init(o2::framework::InitContext&) - { - ccdb->setURL(url.value); - ccdb->setTimestamp(timestamp.value); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - // Not later than now objects - ccdb->setCreatedNotAfter(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()); - // - const std::vector<float> p = {0.008, 0.008, 0.002, 40.0}; - resp.SetParameters(DetectorResponse::kSigma, p); - const std::string fname = paramfile.value; - if (!fname.empty()) { // Loading the parametrization from file - resp.LoadParamFromFile(fname.data(), sigmaname.value, DetectorResponse::kSigma); - } else { // Loading it from CCDB - const std::string path = "Analysis/PID/TOF"; - resp.LoadParam(DetectorResponse::kSigma, ccdb->getForTimeStamp<Parametrization>(path + "/" + sigmaname.value, timestamp.value)); - } - } - - void process(Coll const& collision, Trks const& tracks) - { - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Electron> resp_Electron = tof::ExpTimes<Coll, Trks::iterator, PID::Electron>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Muon> resp_Muon = tof::ExpTimes<Coll, Trks::iterator, PID::Muon>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Pion> resp_Pion = tof::ExpTimes<Coll, Trks::iterator, PID::Pion>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Kaon> resp_Kaon = tof::ExpTimes<Coll, Trks::iterator, PID::Kaon>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Proton> resp_Proton = tof::ExpTimes<Coll, Trks::iterator, PID::Proton>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Deuteron> resp_Deuteron = tof::ExpTimes<Coll, Trks::iterator, PID::Deuteron>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Triton> resp_Triton = tof::ExpTimes<Coll, Trks::iterator, PID::Triton>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Helium3> resp_Helium3 = tof::ExpTimes<Coll, Trks::iterator, PID::Helium3>(); - constexpr tof::ExpTimes<Coll, Trks::iterator, PID::Alpha> resp_Alpha = tof::ExpTimes<Coll, Trks::iterator, PID::Alpha>(); - - tofpid.reserve(tracks.size()); - for (auto const& trk : tracks) { - tofpid(resp_Electron.GetExpectedSignal(collision, trk), - resp_Muon.GetExpectedSignal(collision, trk), - resp_Pion.GetExpectedSignal(collision, trk), - resp_Kaon.GetExpectedSignal(collision, trk), - resp_Proton.GetExpectedSignal(collision, trk), - resp_Deuteron.GetExpectedSignal(collision, trk), - resp_Triton.GetExpectedSignal(collision, trk), - resp_Helium3.GetExpectedSignal(collision, trk), - resp_Alpha.GetExpectedSignal(collision, trk), - resp_Electron.GetExpectedSigma(resp, collision, trk), - resp_Muon.GetExpectedSigma(resp, collision, trk), - resp_Pion.GetExpectedSigma(resp, collision, trk), - resp_Kaon.GetExpectedSigma(resp, collision, trk), - resp_Proton.GetExpectedSigma(resp, collision, trk), - resp_Deuteron.GetExpectedSigma(resp, collision, trk), - resp_Triton.GetExpectedSigma(resp, collision, trk), - resp_Helium3.GetExpectedSigma(resp, collision, trk), - resp_Alpha.GetExpectedSigma(resp, collision, trk), - resp_Electron.GetSeparation(resp, collision, trk), - resp_Muon.GetSeparation(resp, collision, trk), - resp_Pion.GetSeparation(resp, collision, trk), - resp_Kaon.GetSeparation(resp, collision, trk), - resp_Proton.GetSeparation(resp, collision, trk), - resp_Deuteron.GetSeparation(resp, collision, trk), - resp_Triton.GetSeparation(resp, collision, trk), - resp_Helium3.GetSeparation(resp, collision, trk), - resp_Alpha.GetSeparation(resp, collision, trk)); - } - } -}; - -struct pidTOFTaskBeta { - using Trks = soa::Join<aod::Tracks, aod::TracksExtra>; - using Coll = aod::Collision; - Produces<aod::pidRespTOFbeta> tofpidbeta; - tof::Beta<Coll, Trks::iterator, PID::Electron> resp_Electron; - Configurable<float> expreso{"tof-expreso", 80, "Expected resolution for the computation of the expected beta"}; - - void init(o2::framework::InitContext&) - { - resp_Electron.mExpectedResolution = expreso.value; - } - - void process(Coll const& collision, Trks const& tracks) - { - tofpidbeta.reserve(tracks.size()); - for (auto const& trk : tracks) { - tofpidbeta(resp_Electron.GetBeta(collision, trk), - resp_Electron.GetExpectedSigma(collision, trk), - resp_Electron.GetExpectedSignal(collision, trk), - resp_Electron.GetExpectedSigma(collision, trk), - resp_Electron.GetSeparation(collision, trk)); - } - } -}; - -struct pidTOFTaskQA { - static constexpr int Np = 9; - static constexpr const char* hexpected[Np] = {"expected/El", "expected/Mu", "expected/Pi", - "expected/Ka", "expected/Pr", "expected/De", - "expected/Tr", "expected/He", "expected/Al"}; - static constexpr const char* hexpected_diff[Np] = {"expected_diff/El", "expected_diff/Mu", "expected_diff/Pi", - "expected_diff/Ka", "expected_diff/Pr", "expected_diff/De", - "expected_diff/Tr", "expected_diff/He", "expected_diff/Al"}; - static constexpr const char* hnsigma[Np] = {"nsigma/El", "nsigma/Mu", "nsigma/Pi", - "nsigma/Ka", "nsigma/Pr", "nsigma/De", - "nsigma/Tr", "nsigma/He", "nsigma/Al"}; - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::QAObject}; - - Configurable<int> nBinsP{"nBinsP", 400, "Number of bins for the momentum"}; - Configurable<float> MinP{"MinP", 0.1, "Minimum momentum in range"}; - Configurable<float> MaxP{"MaxP", 5, "Maximum momentum in range"}; - -#define makelogaxis(h) \ - { \ - const Int_t nbins = h->GetNbinsX(); \ - double binp[nbins + 1]; \ - double max = h->GetXaxis()->GetBinUpEdge(nbins); \ - double min = h->GetXaxis()->GetBinLowEdge(1); \ - if (min <= 0) \ - min = 0.00001; \ - double lmin = TMath::Log10(min); \ - double ldelta = (TMath::Log10(max) - lmin) / ((double)nbins); \ - for (int i = 0; i < nbins; i++) { \ - binp[i] = TMath::Exp(TMath::Log(10) * (lmin + i * ldelta)); \ - } \ - binp[nbins] = max + 1; \ - h->GetXaxis()->Set(nbins, binp); \ - } - - void init(o2::framework::InitContext&) - { - // Event properties - histos.add("event/vertexz", ";Vtx_{z} (cm);Entries", HistType::kTH1F, {{100, -20, 20}}); - histos.add("event/colltime", ";Collision time (ps);Entries", HistType::kTH1F, {{100, -2000, 2000}}); - histos.add("event/tofsignal", ";#it{p} (GeV/#it{c});TOF Signal", HistType::kTH2F, {{nBinsP, MinP, MaxP}, {10000, 0, 2e6}}); - makelogaxis(histos.get<TH2>("event/tofsignal")); - histos.add("event/tofbeta", ";#it{p} (GeV/#it{c});TOF #beta", HistType::kTH2F, {{nBinsP, MinP, MaxP}, {1000, 0, 2}}); - makelogaxis(histos.get<TH2>("event/tofbeta")); - for (int i = 0; i < Np; i++) { - // Exp signal - histos.add(hexpected[i], Form(";#it{p} (GeV/#it{c});t_{exp}(%s)", pT[i]), HistType::kTH2F, {{nBinsP, MinP, MaxP}, {1000, 0, 2e6}}); - makelogaxis(histos.get<TH2>(hexpected[i])); - // T-Texp - histos.add(hexpected_diff[i], Form(";#it{p} (GeV/#it{c});(t-t_{evt}-t_{exp}(%s))", pT[i]), HistType::kTH2F, {{nBinsP, MinP, MaxP}, {100, -1000, 1000}}); - makelogaxis(histos.get<TH2>(hexpected_diff[i])); - // NSigma - histos.add(hnsigma[i], Form(";#it{p} (GeV/#it{c});N_{#sigma}^{TOF}(%s)", pT[i]), HistType::kTH2F, {{nBinsP, MinP, MaxP}, {200, -10, 10}}); - makelogaxis(histos.get<TH2>(hnsigma[i])); - } - } -#undef makelogaxis - - void process(aod::Collision const& collision, soa::Join<aod::Tracks, aod::TracksExtra, aod::pidRespTOF, aod::pidRespTOFbeta> const& tracks) - { - histos.fill("event/vertexz", collision.posZ()); - histos.fill("event/colltime", collision.collisionTime()); - - for (auto t : tracks) { - // - if (t.tofSignal() < 0) { // Skipping tracks without TOF - continue; - } - const float tof = t.tofSignal() - collision.collisionTime(); - // - histos.fill("event/tofsignal", t.p(), t.tofSignal()); - histos.fill("event/tofbeta", t.p(), t.beta()); - // - const float exp[Np] = {t.tofExpSignalEl(), t.tofExpSignalMu(), t.tofExpSignalPi(), - t.tofExpSignalKa(), t.tofExpSignalPr(), t.tofExpSignalDe(), - t.tofExpSignalTr(), t.tofExpSignalHe(), t.tofExpSignalAl()}; - for (int i = 0; i < Np; i++) { - histos.fill(hexpected[i], t.p(), exp[i]); - histos.fill(hexpected_diff[i], t.p(), tof - exp[i]); - } - // - const float nsigma[Np] = {t.tofNSigmaEl(), t.tofNSigmaMu(), t.tofNSigmaPi(), - t.tofNSigmaKa(), t.tofNSigmaPr(), t.tofNSigmaDe(), - t.tofNSigmaTr(), t.tofNSigmaHe(), t.tofNSigmaAl()}; - for (int i = 0; i < Np; i++) { - histos.fill(hnsigma[i], t.p(), nsigma[i]); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - auto workflow = WorkflowSpec{adaptAnalysisTask<pidTOFTask>("pidTOF-task")}; - const int add_beta = cfgc.options().get<int>("add-beta"); - const int add_qa = cfgc.options().get<int>("add-qa"); - if (add_beta || add_qa) { - workflow.push_back(adaptAnalysisTask<pidTOFTaskBeta>("pidTOFBeta-task")); - } - if (add_qa) { - workflow.push_back(adaptAnalysisTask<pidTOFTaskQA>("pidTOFQA-task")); - } - return workflow; -} diff --git a/Analysis/Tasks/pidTPC.cxx b/Analysis/Tasks/pidTPC.cxx deleted file mode 100644 index b3a8191c022d6..0000000000000 --- a/Analysis/Tasks/pidTPC.cxx +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "ReconstructionDataFormats/Track.h" -#include <CCDB/BasicCCDBManager.h> -#include "PID/PIDResponse.h" -#include "PID/PIDTPC.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::pid; -using namespace o2::framework::expressions; -using namespace o2::track; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"add-qa", VariantType::Int, 0, {"Produce TOF PID QA histograms"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -struct pidTPCTask { - using Trks = soa::Join<aod::Tracks, aod::TracksExtra>; - using Coll = aod::Collision; - Produces<aod::pidRespTPC> tpcpid; - DetectorResponse resp; - Service<o2::ccdb::BasicCCDBManager> ccdb; - Configurable<std::string> paramfile{"param-file", "", "Path to the parametrization object, if emtpy the parametrization is not taken from file"}; - Configurable<std::string> signalname{"param-signal", "BetheBloch", "Name of the parametrization for the expected signal, used in both file and CCDB mode"}; - Configurable<std::string> sigmaname{"param-sigma", "TPCReso", "Name of the parametrization for the expected sigma, used in both file and CCDB mode"}; - Configurable<std::string> url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; - Configurable<long> timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - - void init(o2::framework::InitContext&) - { - ccdb->setURL(url.value); - ccdb->setTimestamp(timestamp.value); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - // Not later than now objects - ccdb->setCreatedNotAfter(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()); - // - const std::string fname = paramfile.value; - if (!fname.empty()) { // Loading the parametrization from file - resp.LoadParamFromFile(fname.data(), signalname.value, DetectorResponse::kSignal); - resp.LoadParamFromFile(fname.data(), sigmaname.value, DetectorResponse::kSigma); - } else { // Loading it from CCDB - const std::string path = "Analysis/PID/TPC"; - resp.LoadParam(DetectorResponse::kSignal, ccdb->getForTimeStamp<Parametrization>(path + "/" + signalname.value, timestamp.value)); - resp.LoadParam(DetectorResponse::kSigma, ccdb->getForTimeStamp<Parametrization>(path + "/" + sigmaname.value, timestamp.value)); - } - } - - void process(Coll const& collision, Trks const& tracks) - { - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Electron> resp_Electron = tpc::ELoss<Coll, Trks::iterator, PID::Electron>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Muon> resp_Muon = tpc::ELoss<Coll, Trks::iterator, PID::Muon>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Pion> resp_Pion = tpc::ELoss<Coll, Trks::iterator, PID::Pion>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Kaon> resp_Kaon = tpc::ELoss<Coll, Trks::iterator, PID::Kaon>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Proton> resp_Proton = tpc::ELoss<Coll, Trks::iterator, PID::Proton>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Deuteron> resp_Deuteron = tpc::ELoss<Coll, Trks::iterator, PID::Deuteron>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Triton> resp_Triton = tpc::ELoss<Coll, Trks::iterator, PID::Triton>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Helium3> resp_Helium3 = tpc::ELoss<Coll, Trks::iterator, PID::Helium3>(); - constexpr tpc::ELoss<Coll, Trks::iterator, PID::Alpha> resp_Alpha = tpc::ELoss<Coll, Trks::iterator, PID::Alpha>(); - - tpcpid.reserve(tracks.size()); - for (auto const& trk : tracks) { - tpcpid( - resp_Electron.GetExpectedSignal(resp, collision, trk), - resp_Muon.GetExpectedSignal(resp, collision, trk), - resp_Pion.GetExpectedSignal(resp, collision, trk), - resp_Kaon.GetExpectedSignal(resp, collision, trk), - resp_Proton.GetExpectedSignal(resp, collision, trk), - resp_Deuteron.GetExpectedSignal(resp, collision, trk), - resp_Triton.GetExpectedSignal(resp, collision, trk), - resp_Helium3.GetExpectedSignal(resp, collision, trk), - resp_Alpha.GetExpectedSignal(resp, collision, trk), - resp_Electron.GetExpectedSigma(resp, collision, trk), - resp_Muon.GetExpectedSigma(resp, collision, trk), - resp_Pion.GetExpectedSigma(resp, collision, trk), - resp_Kaon.GetExpectedSigma(resp, collision, trk), - resp_Proton.GetExpectedSigma(resp, collision, trk), - resp_Deuteron.GetExpectedSigma(resp, collision, trk), - resp_Triton.GetExpectedSigma(resp, collision, trk), - resp_Helium3.GetExpectedSigma(resp, collision, trk), - resp_Alpha.GetExpectedSigma(resp, collision, trk), - resp_Electron.GetSeparation(resp, collision, trk), - resp_Muon.GetSeparation(resp, collision, trk), - resp_Pion.GetSeparation(resp, collision, trk), - resp_Kaon.GetSeparation(resp, collision, trk), - resp_Proton.GetSeparation(resp, collision, trk), - resp_Deuteron.GetSeparation(resp, collision, trk), - resp_Triton.GetSeparation(resp, collision, trk), - resp_Helium3.GetSeparation(resp, collision, trk), - resp_Alpha.GetSeparation(resp, collision, trk)); - } - } -}; - -struct pidTPCTaskQA { - static constexpr int Np = 9; - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr const char* hexpected[Np] = {"expected/El", "expected/Mu", "expected/Pi", - "expected/Ka", "expected/Pr", "expected/De", - "expected/Tr", "expected/He", "expected/Al"}; - static constexpr const char* hexpected_diff[Np] = {"expected_diff/El", "expected_diff/Mu", "expected_diff/Pi", - "expected_diff/Ka", "expected_diff/Pr", "expected_diff/De", - "expected_diff/Tr", "expected_diff/He", "expected_diff/Al"}; - static constexpr const char* hnsigma[Np] = {"nsigma/El", "nsigma/Mu", "nsigma/Pi", - "nsigma/Ka", "nsigma/Pr", "nsigma/De", - "nsigma/Tr", "nsigma/He", "nsigma/Al"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::QAObject}; - - Configurable<int> nBinsP{"nBinsP", 400, "Number of bins for the momentum"}; - Configurable<float> MinP{"MinP", 0, "Minimum momentum in range"}; - Configurable<float> MaxP{"MaxP", 20, "Maximum momentum in range"}; - - void init(o2::framework::InitContext&) - { - -#define makelogaxis(h) \ - { \ - const Int_t nbins = h->GetNbinsX(); \ - double binp[nbins + 1]; \ - double max = h->GetXaxis()->GetBinUpEdge(nbins); \ - double min = h->GetXaxis()->GetBinLowEdge(1); \ - if (min <= 0) \ - min = 0.00001; \ - double lmin = TMath::Log10(min); \ - double ldelta = (TMath::Log10(max) - lmin) / ((double)nbins); \ - for (int i = 0; i < nbins; i++) { \ - binp[i] = TMath::Exp(TMath::Log(10) * (lmin + i * ldelta)); \ - } \ - binp[nbins] = max + 1; \ - h->GetXaxis()->Set(nbins, binp); \ - } - - // Event properties - histos.add("event/vertexz", ";Vtx_{z} (cm);Entries", kTH1F, {{100, -20, 20}}); - histos.add("event/tpcsignal", ";#it{p} (GeV/#it{c});TPC Signal", kTH2F, {{nBinsP, MinP, MaxP}, {1000, 0, 1000}}); - makelogaxis(histos.get<TH2>("event/tpcsignal")); - for (int i = 0; i < Np; i++) { - // Exp signal - histos.add(hexpected[i], Form(";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_(%s)", pT[i]), kTH2F, {{nBinsP, MinP, MaxP}, {1000, 0, 1000}}); - makelogaxis(histos.get<TH2>(hexpected[i])); - // Signal - Expected signal - histos.add(hexpected_diff[i], Form(";#it{p} (GeV/#it{c});;d#it{E}/d#it{x} - d#it{E}/d#it{x}(%s)", pT[i]), kTH2F, {{nBinsP, MinP, MaxP}, {1000, -500, 500}}); - makelogaxis(histos.get<TH2>(hexpected_diff[i])); - // NSigma - histos.add(hnsigma[i], Form(";#it{p} (GeV/#it{c});N_{#sigma}^{TPC}(%s)", pT[i]), kTH2F, {{nBinsP, MinP, MaxP}, {200, -10, 10}}); - makelogaxis(histos.get<TH2>(hnsigma[i])); - } -#undef makelogaxis - } - void process(aod::Collision const& collision, soa::Join<aod::Tracks, aod::TracksExtra, aod::pidRespTPC> const& tracks) - { - histos.fill("event/vertexz", collision.posZ()); - - for (auto t : tracks) { - // const float mom = t.p(); - const float mom = t.tpcInnerParam(); - histos.fill("event/tpcsignal", mom, t.tpcSignal()); - // - const float exp[Np] = {t.tpcExpSignalEl(), t.tpcExpSignalMu(), t.tpcExpSignalPi(), - t.tpcExpSignalKa(), t.tpcExpSignalPr(), t.tpcExpSignalDe(), - t.tpcExpSignalTr(), t.tpcExpSignalHe(), t.tpcExpSignalAl()}; - for (int i = 0; i < Np; i++) { - histos.fill(hexpected[i], mom, exp[i]); - histos.fill(hexpected_diff[i], mom, t.tpcSignal() - exp[i]); - } - // - const float nsigma[Np] = {t.tpcNSigmaEl(), t.tpcNSigmaMu(), t.tpcNSigmaPi(), - t.tpcNSigmaKa(), t.tpcNSigmaPr(), t.tpcNSigmaDe(), - t.tpcNSigmaTr(), t.tpcNSigmaHe(), t.tpcNSigmaAl()}; - for (int i = 0; i < Np; i++) { - histos.fill(hnsigma[i], t.p(), nsigma[i]); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - auto workflow = WorkflowSpec{adaptAnalysisTask<pidTPCTask>("pidTPC-task")}; - if (cfgc.options().get<int>("add-qa")) { - workflow.push_back(adaptAnalysisTask<pidTPCTaskQA>("pidTPCQA-task")); - } - return workflow; -} diff --git a/Analysis/Tasks/qaTask.cxx b/Analysis/Tasks/qaTask.cxx deleted file mode 100644 index b6c2b0a641a16..0000000000000 --- a/Analysis/Tasks/qaTask.cxx +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// \author Peter Hristov <Peter.Hristov@cern.ch>, CERN -/// \author Gian Michele Innocenti <gian.michele.innocenti@cern.ch>, CERN -/// \author Henrique J C Zanoli <henrique.zanoli@cern.ch>, Utrecht University -/// \author Nicolo' Jacazio <nicolo.jacazio@cern.ch>, CERN - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Analysis/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "Analysis/MC.h" - -#include <TH1F.h> -#include <TH2F.h> -#include <cmath> - -namespace o2fw = o2::framework; -namespace o2exp = o2::framework::expressions; -namespace o2df = o2::dataformats; - -namespace track_utils -{ -/// Converts a angle phi to the -pi to pi range. -double ConvertPhiRange(double phi) -{ - if (phi > M_PI) { - phi -= 2 * M_PI; - } else if (phi < -M_PI) { - phi += 2 * M_PI; - } - - return phi; -} - -/// Determines the impact parameter and its error for a given track. -/// \param track the track to get the impact parameter from. -/// \param primaryVertex the primary vertex of th collision. -/// \param impactParameter variable to save the impact parameter in micrometers. -/// \param impactParameterError variable to save the impact parameter error in micrometers. -template <typename Track> -bool GetImpactParameterAndError(const Track& track, const o2df::VertexBase& primaryVertex, double& impactParameter, - double& impactParameterError) -{ - impactParameter = -999.; - impactParameterError = -999.; - - o2df::DCA dca; - // FIXME: get this from CCDB - constexpr float magneticField{5.0}; // in kG - auto trackParameter = getTrackParCov(track); - bool propagate = trackParameter.propagateToDCA(primaryVertex, magneticField, &dca); - - if (propagate) { - impactParameter = 1000 * dca.getY(); - impactParameterError = 1000 * std::sqrt(dca.getSigmaY2()); - } - return propagate; -} -} // namespace track_utils - -/// Task to QA global observables of the event -struct QAGlobalObservables { - std::array<float, 2> collisionPositionRange = {-20., 20.}; - std::array<float, 2> numberOfTracksRange = {0, 2000}; - - o2fw::Configurable<int> nBinsNumberOfTracks{"nBinsNumberOfTracks", 2000, "Number of bins fot the Number of Tracks"}; - - o2fw::Configurable<int> nBinsVertexPosition{"nBinsPt", 100, "Number of bins for the Vertex Position"}; - - o2fw::OutputObj<TH1F> hCollisionX{ - TH1F("collisionX", "; X [cm];Counts", nBinsVertexPosition, collisionPositionRange[0], collisionPositionRange[1])}; - - o2fw::OutputObj<TH1F> hCollisionY{ - TH1F("collisionY", "; Y [cm];Counts", nBinsVertexPosition, collisionPositionRange[0], collisionPositionRange[1])}; - - o2fw::OutputObj<TH1F> hCollisionZ{ - TH1F("collisionZ", "; Z [cm];Counts", nBinsVertexPosition, collisionPositionRange[0], collisionPositionRange[1])}; - - o2fw::OutputObj<TH1F> hNumberOfTracks{TH1F("NumberOfTracks", "; Number of Tracks;Counts", nBinsNumberOfTracks, - numberOfTracksRange[0], numberOfTracksRange[1])}; - - void process(const o2::aod::Collision& collision, const o2::aod::Tracks& tracks) - { - hCollisionX->Fill(collision.posX()); - hCollisionY->Fill(collision.posY()); - hCollisionZ->Fill(collision.posZ()); - - int nTracks(0); - for (const auto& track : tracks) { - nTracks++; - } - hNumberOfTracks->Fill(nTracks); - } -}; - -/// Task to QA the kinematic properties of the tracks -struct QATrackingKine { - o2fw::Configurable<int> nBinsPt{"nBinsPt", 100, "Number of bins for Pt"}; - std::array<double, 2> ptRange = {0, 10.}; - o2fw::Configurable<int> nBinsPhi{"nBinsPhi", 100, "Number of bins for Phi"}; - o2fw::Configurable<int> nBinsEta{"nBinsEta", 100, "Number of bins for the eta histogram."}; - std::array<double, 2> etaRange = {-6, 6}; - - o2fw::OutputObj<TH1F> hPt{TH1F("pt", ";p_{T} [GeV];Counts", nBinsPt, ptRange[0], ptRange[1])}; - o2fw::OutputObj<TH1F> hEta{TH1F("eta", ";#eta;Counts", nBinsEta, etaRange[0], etaRange[1])}; - o2fw::OutputObj<TH1F> hPhi{TH1F("phi", ";#varphi [rad];Counts", nBinsPhi, 0, 2 * M_PI)}; - - void process(const o2::aod::Track& track) - { - hEta->Fill(track.eta()); - hPhi->Fill(track.phi()); - hPt->Fill(track.pt()); - } -}; - -/// Task to evaluate the tracking resolution (Pt, Eta, Phi and impact parameter) -struct QATrackingResolution { - o2fw::Configurable<int> nBinsPtTrack{"nBinsPtTrack", 100, "Number of bins for the transverse momentum"}; - std::array<double, 2> ptRange = {0, 10.}; - - o2fw::Configurable<int> nBinsEta{"nBinsEta", 400, "Number of bins for the pseudorapidity"}; - std::array<double, 2> etaRange = {-6, 6}; - - o2fw::Configurable<int> nBinsDeltaPt{"nBinsDeltaPt", 400, "Number of bins for the transverse momentum differences"}; - - o2fw::Configurable<int> nBinsDeltaPhi{"nBinsPhi", 100, "Number of bins for the azimuthal angle differences"}; - - o2fw::Configurable<int> nBinsDeltaEta{"nBinsDeltaEta", 100, "Number of bins for the pseudorapidity differences"}; - - o2fw::Configurable<int> nBinsImpactParameter{"nBinsImpactParameter", 1000, "Number of bins for the Impact parameter"}; - - std::array<double, 2> impactParameterRange = {-1500, 1500}; // micrometer - std::array<double, 2> impactParameterResolutionRange = {0, 1000}; // micrometer - - // Registry of histograms - o2fw::HistogramRegistry histos{"Histos", {}, o2fw::OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2fw::InitContext&) - { - // Eta - histos.add("Eta/etaDiffMCReco", ";#eta_{MC} - #eta_{Rec}", o2fw::kTH1F, - {{nBinsDeltaEta, -2, 2}}); - histos.add("Eta/etaDiffMCRecoVsEtaMC", ";#eta_{MC} - #eta_{Rec};#eta_{MC}", o2fw::kTH2F, - {{nBinsDeltaEta, -2, 2}, {nBinsEta, etaRange[0], etaRange[1]}}); - histos.add("Eta/etaDiffMCRecoVsEtaReco", ";#eta_{MC} - #eta_{Rec};#eta_{Rec}", o2fw::kTH2F, - {{nBinsDeltaEta, -2, 2}, {nBinsEta, etaRange[0], etaRange[1]}}); - // Phi - histos.add("Phi/phiDiffMCRec", ";#varphi_{MC} - #varphi_{Rec} [rad]", o2fw::kTH1F, - {{nBinsDeltaPhi, -M_PI, M_PI}}); - // Pt - histos.add("Pt/ptDiffMCRec", ";p_{T}_{MC} - p_{T}_{Rec} [GeV/c]", o2fw::kTH1F, - {{nBinsDeltaPt, -2., 2.}}); - histos.add("Pt/ptResolution", ";(p_{T}_{MC} - p_{T}_{Rec})/(p_{T}_{Rec})", o2fw::kTH1F, - {{nBinsDeltaPt, -2., 2.}}); - histos.add("Pt/ptResolutionVsPt", ";p_{T} [GeV/c];(p_{T}_{MC} - p_{T}_{Rec})/(p_{T}_{Rec})", o2fw::kTH2F, - {{nBinsPtTrack, ptRange[0], ptRange[1]}, {nBinsDeltaPt, 0, 2.}}); - histos.add("Pt/ptResolutionVsEta", ";#eta;(p_{T}_{MC} - p_{T}_{Rec})/(p_{T}_{Rec})", o2fw::kTH2F, - {{nBinsEta, -4., 4.}, {nBinsDeltaPt, -2., 2.}}); - // Impact parameters - histos.add("ImpactParameter/impactParameterVsPt", ";p_{T} [GeV/c];Impact Parameter [{#mu}m]", o2fw::kTH2F, - {{nBinsPtTrack, ptRange[0], ptRange[1]}, {nBinsImpactParameter, impactParameterRange[0], impactParameterRange[1]}}); - histos.add("ImpactParameter/impactParameterVsEta", "#eta;Impact Parameter [{#mu}m]", o2fw::kTH2F, - {{nBinsEta, etaRange[0], etaRange[1]}, {nBinsImpactParameter, impactParameterRange[0], impactParameterRange[1]}}); - histos.add("ImpactParameter/impactParameterErrorVsPt", ";p_{T} [GeV/c];Impact Parameter Error [#mum]", o2fw::kTH2F, - {{nBinsPtTrack, ptRange[0], ptRange[1]}, {nBinsImpactParameter, impactParameterRange[0], impactParameterRange[1]}}); - histos.add("ImpactParameter/impactParameterErrorVsEta", ";#eta;Impact Parameter Error [#mum]", o2fw::kTH2F, - {{nBinsEta, etaRange[0], etaRange[1]}, {nBinsImpactParameter, 0, impactParameterRange[1]}}); - } - - void process(const o2::soa::Join<o2::aod::Collisions, o2::aod::McCollisionLabels>::iterator& collision, - const o2::soa::Join<o2::aod::Tracks, o2::aod::TracksCov, o2::aod::McTrackLabels>& tracks, - const o2::aod::McParticles& mcParticles, const o2::aod::McCollisions& mcCollisions) - { - const o2df::VertexBase primaryVertex = getPrimaryVertex(collision); - - for (const auto& track : tracks) { - const double deltaPt = track.label().pt() - track.pt(); - histos.fill("Pt/ptDiffMCRec", deltaPt); - - const double deltaPtOverPt = deltaPt / track.pt(); - histos.fill("Pt/ptResolution", deltaPtOverPt); - histos.fill("Pt/ptResolutionVsPt", track.pt(), abs(deltaPtOverPt)); - histos.fill("Pt/ptResolutionVsEta", track.eta(), abs(deltaPtOverPt)); - - const double deltaEta = track.label().eta() - track.eta(); - histos.fill("Eta/etaDiffMCReco", deltaEta); - histos.fill("Eta/etaDiffMCRecoVsEtaMC", deltaEta, track.label().eta()); - histos.fill("Eta/etaDiffMCRecoVsEtaReco", deltaEta, track.eta()); - - const auto deltaPhi = track_utils::ConvertPhiRange(track.label().phi() - track.phi()); - histos.fill("Phi/phiDiffMCRec", deltaPhi); - - double impactParameter{-999.}; - double impactParameterError{-999.}; - - const bool propagate = - track_utils::GetImpactParameterAndError(track, primaryVertex, impactParameter, impactParameterError); - - if (propagate) { - histos.fill("ImpactParameter/impactParameterVsPt", track.pt(), impactParameter); - histos.fill("ImpactParameter/impactParameterVsEta", track.eta(), impactParameter); - histos.fill("ImpactParameter/impactParameterErrorVsPt", track.pt(), impactParameterError); - histos.fill("ImpactParameter/impactParameterErrorVsEta", track.eta(), impactParameterError); - } - } - } -}; - -o2fw::WorkflowSpec defineDataProcessing(o2fw::ConfigContext const&) -{ - return o2fw::WorkflowSpec{o2fw::adaptAnalysisTask<QAGlobalObservables>("qa-global-observables"), - o2fw::adaptAnalysisTask<QATrackingKine>("qa-tracking-kine"), - o2fw::adaptAnalysisTask<QATrackingResolution>("qa-tracking-resolution")}; -} diff --git a/Analysis/Tasks/reducedEventAnalysis.cxx b/Analysis/Tasks/reducedEventAnalysis.cxx deleted file mode 100644 index 7403df356a15f..0000000000000 --- a/Analysis/Tasks/reducedEventAnalysis.cxx +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Analysis/Multiplicity.h" -#include "Analysis/EventSelection.h" -#include "Analysis/Centrality.h" -#include <TH1F.h> -#include <TH2F.h> -#include <TMath.h> -#include "TVector3.h" -#include "TLorentzVector.h" -#include <cmath> -#include <vector> - -const float gkMass = 0.0005; - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This is a very simple example showing how to create an histogram -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that - -struct InvMassAnalysis { - // needs to be initialized with a label or an obj - // when adding an object to OutputObj later, the object name will be - // *reset* to OutputObj label - needed for correct placement in the output file - OutputObj<TH1F> centV0M{TH1F("centV0M", "centrality V0", 100, 0.0, 100.0)}; - OutputObj<TH1F> vtxZ{TH1F("vtxZ", "vtx Z", 200, -20.0, 20.0)}; - - OutputObj<TH1F> ptH{TH1F("pt", "pt", 100, -0.01, 10.01)}; - OutputObj<TH2F> ptCorr{TH2F("ptToPt", "ptToPt", 100, -0.01, 10.01, 100, -0.01, 10.01)}; - OutputObj<TH2F> tpcDedx{TH2F("tpcDedx", "TPC de/dx", 100, 0.0, 10.0, 100, 0.0, 200.0)}; - OutputObj<TH1I> itsHits{TH1I("itsHits", "ITS hits per layer", 6, -0.5, 5.5)}; - OutputObj<TH2I> itsHitsVsPt{TH2I("itsHitsVsPt", "ITS hits per layer", 6, -0.5, 5.5, 100, 0.0, 10.0)}; - OutputObj<TH1I> itsChi2{TH1I("itsChi2", "ITS chi2", 100, 0.0, 20.0)}; - OutputObj<TH1I> tpcChi2{TH1I("tpcChi2", "TPC chi2", 100, 0.0, 10.0)}; - OutputObj<TH1I> tpcCls{TH1I("tpcCls", "TPC clusters", 160, 0.0, 160.0)}; - OutputObj<TH1I> flagsHist{TH1I("flagsHist", "Flags", 64, -0.5, 63.5)}; - OutputObj<TH1F> invMassPM{TH1F("invMassPM", "Invariant mass, SEPM", 125, 0.0, 5.0)}; - OutputObj<TH1F> invMassPP{TH1F("invMassPP", "Invariant mass, SEPP", 125, 0.0, 5.0)}; - OutputObj<TH1F> invMassMM{TH1F("invMassMM", "Invariant mass, SEMM", 125, 0.0, 5.0)}; - OutputObj<TH2F> invMassVsPt{TH2F("invMassVsPt", "Invariant mass", 125, 0.0, 5.0, 10, 0.0, 10.0)}; - OutputObj<TH2F> invMassVsCentrality{TH2F("invMassVsCentrality", "Invariant mass", 125, 0.0, 5.0, 10, 0.0, 100.0)}; - OutputObj<TH1F> trZ{"trZ", OutputObjHandlingPolicy::QAObject}; - //Configurable<float> ptlow{"ptlow", 1.0f, "Lower pT limit"}; - //Configurable<float> pthigh{"pthigh", 1.0f, "Higher pT limit"}; - - float ptlow = 1.0; - float pthigh = 5.0; - Filter ptFilter = ((1.0f / aod::track::signed1Pt > ptlow) && (1.0f / aod::track::signed1Pt < pthigh)) || ((1.0f / aod::track::signed1Pt > -1.0f * pthigh) && (1.0f / aod::track::signed1Pt < -1.0f * ptlow)); - //Filter spdAnyFilter = (aod::track::itsClusterMap & (uint8_t(1)<<0)) || (aod::track::itsClusterMap & (uint8_t(1)<<1)); - float dedxLow = 75.0; - float dedxHigh = 90.0; - Filter dedxFilter = (aod::track::tpcSignal > dedxLow) && (aod::track::tpcSignal < dedxHigh); - float tpcChi2Max = 4.0; - float itsChi2Max = 36; - Filter qualityFilter = (aod::track::tpcChi2NCl < tpcChi2Max) && (aod::track::itsChi2NCl < itsChi2Max); - - void init(InitContext const&) - { - trZ.setObject(new TH1F("Z", "Z", 100, -10., 10.)); - } - - void process(soa::Join<aod::Collisions, aod::EvSels, aod::Cents>::iterator collision, soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra>> const& tracks) - { - - if (!collision.sel7()) - return; - - centV0M->Fill(collision.centV0M()); - vtxZ->Fill(collision.posZ()); - - for (auto& track : tracks) { - //if (track.pt() < ptlow) - // continue; - ptH->Fill(track.pt()); - trZ->Fill(track.z()); - itsChi2->Fill(track.itsChi2NCl()); - for (int i = 0; i < 6; i++) { - if (track.itsClusterMap() & (uint8_t(1) << i)) - itsHits->Fill(i); - if (track.itsClusterMap() & (uint8_t(1) << i)) - itsHitsVsPt->Fill(i, track.pt()); - } - tpcDedx->Fill(track.tpcInnerParam(), track.tpcSignal()); - tpcChi2->Fill(track.tpcChi2NCl()); - tpcCls->Fill(track.tpcNClsFound()); - for (int i = 0; i < 64; i++) { - if (track.flags() & (uint64_t(1) << i)) - flagsHist->Fill(i); - } - } - for (auto& [t0, t1] : combinations(tracks, tracks)) { - ptCorr->Fill(t0.pt(), t1.pt()); - if (!((t0.itsClusterMap() & (uint8_t(1) << 0)) || (t0.itsClusterMap() & (uint8_t(1) << 1)))) - continue; - if (!((t1.itsClusterMap() & (uint8_t(1) << 0)) || (t1.itsClusterMap() & (uint8_t(1) << 1)))) - continue; - - TLorentzVector p1, p2, p; - p1.SetXYZM(t0.px(), t0.py(), t0.pz(), gkMass); - p2.SetXYZM(t1.px(), t1.py(), t1.pz(), gkMass); - p = p1 + p2; - - if (t0.charge() * t1.charge() < 0) { - invMassPM->Fill(p.M()); - invMassVsPt->Fill(p.M(), p.Pt()); - invMassVsCentrality->Fill(p.M(), collision.centV0M()); - } else { - if (t0.charge() > 0) - invMassPP->Fill(p.M()); - if (t0.charge() < 0) - invMassMM->Fill(p.M()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<InvMassAnalysis>("InvMassAnalysis")}; -} diff --git a/Analysis/Tasks/timestamp.cxx b/Analysis/Tasks/timestamp.cxx deleted file mode 100644 index f13501cbdca7b..0000000000000 --- a/Analysis/Tasks/timestamp.cxx +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// A task to fill the timestamp table from run number. -// Uses headers from CCDB -// -// Author: Nicolo' Jacazio on 2020-06-22 - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include <CCDB/BasicCCDBManager.h> -#include "CommonDataFormat/InteractionRecord.h" -#include "DetectorsRaw/HBFUtils.h" -#include <map> - -using namespace o2::framework; -using namespace o2::header; -using namespace o2; - -struct TimestampTask { - Produces<aod::Timestamps> ts_table; /// Table with SOR timestamps produced by the task - Service<o2::ccdb::BasicCCDBManager> ccdb; /// Object manager in CCDB - o2::ccdb::CcdbApi ccdb_api; /// API to access CCDB - std::map<int, int>* mapStartOrbit = nullptr; /// Map of the starting orbit for the run - std::pair<int, long> lastCall; /// Last run number processed and its timestamp, needed for caching - std::map<int, long> mapRunToTimestamp; /// Cache of processed run numbers - - // Configurables - Configurable<bool> verbose{"verbose", false, "verbose mode"}; - Configurable<std::string> rct_path{"rct-path", "RCT/RunInformation/", "path to the ccdb RCT objects for the SOR timestamps"}; - Configurable<std::string> start_orbit_path{"start-orbit-path", "Trigger/StartOrbit", "path to the ccdb SOR orbit objects"}; - Configurable<std::string> url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "URL of the CCDB database"}; - Configurable<bool> isMC{"isMC", 0, "0 - data, 1 - MC"}; - - void init(o2::framework::InitContext&) - { - LOGF(info, "Initializing TimestampTask"); - ccdb->setURL(url.value); // Setting URL of CCDB manager from configuration - LOGF(debug, "Getting SOR orbit map from CCDB url '%s' path '%s'", url.value, start_orbit_path.value); - mapStartOrbit = ccdb->get<std::map<int, int>>(start_orbit_path.value); - if (!mapStartOrbit) { - LOGF(fatal, "Cannot find map of SOR orbits in CCDB in path %s", start_orbit_path.value.data()); - } - ccdb_api.init(url.value); - if (!ccdb_api.isHostReachable()) { - LOGF(fatal, "CCDB host %s is not reacheable, cannot go forward", url.value.data()); - } - } - - void process(aod::BC const& bc) - { - long ts = 0; - if (bc.runNumber() == lastCall.first) { // The run number coincides to the last run processed - LOGF(debug, "Getting timestamp from last call"); - ts = lastCall.second; - } else if (mapRunToTimestamp.count(bc.runNumber())) { // The run number was already requested before: getting it from cache! - LOGF(debug, "Getting timestamp from cache"); - ts = mapRunToTimestamp[bc.runNumber()]; - } else { // The run was not requested before: need to acccess CCDB! - LOGF(debug, "Getting timestamp from CCDB"); - std::map<std::string, std::string> metadata, headers; - const std::string run_path = Form("%s/%i", rct_path.value.data(), bc.runNumber()); - headers = ccdb_api.retrieveHeaders(run_path, metadata, -1); - if (headers.count("SOR") == 0) { - LOGF(fatal, "Cannot find run-number to timestamp in path '%s'.", run_path.data()); - } - ts = atol(headers["SOR"].c_str()); // timestamp of the SOR in ms - - // Adding the timestamp to the cache map - std::pair<std::map<int, long>::iterator, bool> check; - check = mapRunToTimestamp.insert(std::pair<int, long>(bc.runNumber(), ts)); - if (!check.second) { - LOGF(fatal, "Run number %i already existed with a timestamp of %llu", bc.runNumber(), check.first->second); - } - LOGF(info, "Add new run %i with timestamp %llu to cache", bc.runNumber(), ts); - } - - // Setting latest run information - lastCall = std::make_pair(bc.runNumber(), ts); - - if (verbose.value) { - LOGF(info, "Run-number to timestamp found! %i %llu ms", bc.runNumber(), ts); - } - const uint16_t initialBC = 0; // exact bc number not relevant due to ms precision of timestamps - if (!mapStartOrbit->count(bc.runNumber())) { - LOGF(fatal, "Cannot find run %i in mapStartOrbit map", bc.runNumber()); - } - const uint32_t initialOrbit = mapStartOrbit->at(bc.runNumber()); - const uint16_t currentBC = isMC ? initialBC : bc.globalBC() % o2::constants::lhc::LHCMaxBunches; - const uint32_t currentOrbit = isMC ? initialOrbit : bc.globalBC() / o2::constants::lhc::LHCMaxBunches; - const InteractionRecord current(currentBC, currentOrbit); - const InteractionRecord initial(initialBC, initialOrbit); - ts += (current - initial).bc2ns() / 1000000; - ts_table(ts); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{adaptAnalysisTask<TimestampTask>("TimestampTask")}; -} diff --git a/Analysis/Tasks/trackextension.cxx b/Analysis/Tasks/trackextension.cxx deleted file mode 100644 index 1be057fff8e3b..0000000000000 --- a/Analysis/Tasks/trackextension.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Task performing basic track selection. -// - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/trackUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -//**************************************************************************************** -/** - * Produce the more complicated derived track quantities needed for track selection. - * FIXME: we shall run this only if all other selections are passed to avoid - * FIXME: computing overhead and errors in calculations - */ -//**************************************************************************************** -struct TrackExtensionTask { - - Produces<aod::TracksExtended> extendedTrackQuantities; - - void process(aod::Collision const& collision, aod::FullTracks const& tracks) - { - for (auto& track : tracks) { - - std::array<float, 2> dca{1e10f, 1e10f}; - // FIXME: temporary solution to remove tracks that should not be there after conversion - if (track.trackType() == o2::aod::track::TrackTypeEnum::Run2GlobalTrack && track.itsChi2NCl() != 0.f && track.tpcChi2NCl() != 0.f && std::abs(track.x()) < 10.f) { - float magField = 5.0; // in kG (FIXME: get this from CCDB) - auto trackPar = getTrackPar(track); - trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, magField, &dca); - } - extendedTrackQuantities(dca[0], dca[1]); - - // TODO: add realtive pt resolution sigma(pt)/pt \approx pt * sigma(1/pt) - // TODO: add geometrical length / fiducial volume - } - } -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask<TrackExtensionTask>("track-extension")}; - return workflow; -} diff --git a/Analysis/Tasks/trackqa.cxx b/Analysis/Tasks/trackqa.cxx deleted file mode 100644 index 6fa1fbc1a935f..0000000000000 --- a/Analysis/Tasks/trackqa.cxx +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Task producing basic tracking qa histograms -// - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Analysis/MC.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionDefaults.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"mc", VariantType::Bool, false, {"Add MC QA histograms."}}, - {"add-cut-qa", VariantType::Int, 0, {"Add track cut QA histograms."}}}; - std::swap(workflowOptions, options); -} -#include "Framework/runDataProcessing.h" - -//**************************************************************************************** -/** - * QA histograms for track quantities. - */ -//**************************************************************************************** -struct TrackQATask { - - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::QAObject}; - - Configurable<int> selectedTracks{"select", 1, "Choice of track selection. 0 = no selection, 1 = globalTracks, 2 = globalTracksSDD"}; - - Filter trackFilter = aod::track::isGlobalTrack == true; - - void init(o2::framework::InitContext&) - { - std::vector<double> ptBinning = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, - 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}; - - // kine histograms - histos.add("Kine/pt", "#it{p}_{T};#it{p}_{T} [GeV/c]", kTH1D, {{ptBinning}}); - histos.add("Kine/eta", "#eta;#eta", kTH1D, {{180, -0.9, 0.9}}); - histos.add("Kine/phi", "#phi;#phi [rad]", kTH1D, {{180, 0., 2 * M_PI}}); - - // track histograms - histos.add("TrackPar/x", "track #it{x} position at dca in local coordinate system;#it{x} [cm]", kTH1D, {{200, -0.36, 0.36}}); - histos.add("TrackPar/y", "track #it{y} position at dca in local coordinate system;#it{y} [cm]", kTH1D, {{200, -0.5, 0.5}}); - histos.add("TrackPar/z", "track #it{z} position at dca in local coordinate system;#it{z} [cm]", kTH1D, {{200, -11., 11.}}); - histos.add("TrackPar/alpha", "rotation angle of local wrt. global coordinate system;#alpha [rad]", kTH1D, {{36, -M_PI, M_PI}}); - histos.add("TrackPar/signed1Pt", "track signed 1/#it{p}_{T};#it{q}/#it{p}_{T}", kTH1D, {{200, -8, 8}}); - histos.add("TrackPar/snp", "sinus of track momentum azimuthal angle;snp", kTH1D, {{11, -0.1, 0.1}}); - histos.add("TrackPar/tgl", "tangent of the track momentum dip angle;tgl;", kTH1D, {{200, -1., 1.}}); - histos.add("TrackPar/flags", "track flag;flag bit", kTH1D, {{64, -0.5, 63.5}}); - histos.add("TrackPar/dcaXY", "distance of closest approach in #it{xy} plane;#it{dcaXY} [cm];", kTH1D, {{200, -0.15, 0.15}}); - histos.add("TrackPar/dcaZ", "distance of closest approach in #it{z};#it{dcaZ} [cm];", kTH1D, {{200, -0.15, 0.15}}); - histos.add("TrackPar/length", "track length in cm;#it{Length} [cm];", kTH1D, {{400, 0, 1000}}); - - // its histograms - histos.add("ITS/itsNCls", "number of found ITS clusters;# clusters ITS", kTH1D, {{8, -0.5, 7.5}}); - histos.add("ITS/itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {{100, 0, 40}}); - histos.add("ITS/itsHits", "hitmap ITS;layer ITS", kTH1D, {{7, -0.5, 6.5}}); - - // tpc histograms - histos.add("TPC/tpcNClsFindable", "number of findable TPC clusters;# findable clusters TPC", kTH1D, {{165, -0.5, 164.5}}); - histos.add("TPC/tpcNClsFound", "number of found TPC clusters;# clusters TPC", kTH1D, {{165, -0.5, 164.5}}); - histos.add("TPC/tpcNClsShared", "number of shared TPC clusters;# shared clusters TPC", kTH1D, {{165, -0.5, 164.5}}); - histos.add("TPC/tpcNClsCrossedRows", "number of crossed TPC rows;# crossed rows TPC", kTH1D, {{165, -0.5, 164.5}}); - histos.add("TPC/tpcFractionSharedCls", "fraction of shared TPC clusters;fraction shared clusters TPC", kTH1D, {{100, 0., 1.}}); - histos.add("TPC/tpcCrossedRowsOverFindableCls", "crossed TPC rows over findable clusters;crossed rows / findable clusters TPC", kTH1D, {{120, 0.0, 1.2}}); - histos.add("TPC/tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {{100, 0, 10}}); - - histos.print(); - } - - void process(soa::Filtered<soa::Join<aod::FullTracks, aod::TracksExtended, aod::TrackSelection>>::iterator const& track) - { - // fill kinematic variables - histos.fill("Kine/pt", track.pt()); - histos.fill("Kine/eta", track.eta()); - histos.fill("Kine/phi", track.phi()); - - // fill track parameters - histos.fill("TrackPar/alpha", track.alpha()); - histos.fill("TrackPar/x", track.x()); - histos.fill("TrackPar/y", track.y()); - histos.fill("TrackPar/z", track.z()); - histos.fill("TrackPar/signed1Pt", track.signed1Pt()); - histos.fill("TrackPar/snp", track.snp()); - histos.fill("TrackPar/tgl", track.tgl()); - for (unsigned int i = 0; i < 64; i++) { - if (track.flags() & (1 << i)) { - histos.fill("TrackPar/flags", i); - } - } - histos.fill("TrackPar/dcaXY", track.dcaXY()); - histos.fill("TrackPar/dcaZ", track.dcaZ()); - histos.fill("TrackPar/length", track.length()); - - // fill ITS variables - histos.fill("ITS/itsNCls", track.itsNCls()); - histos.fill("ITS/itsChi2NCl", track.itsChi2NCl()); - for (unsigned int i = 0; i < 7; i++) { - if (track.itsClusterMap() & (1 << i)) { - histos.fill("ITS/itsHits", i); - } - } - - // fill TPC variables - histos.fill("TPC/tpcNClsFindable", track.tpcNClsFindable()); - histos.fill("TPC/tpcNClsFound", track.tpcNClsFound()); - histos.fill("TPC/tpcNClsShared", track.tpcNClsShared()); - histos.fill("TPC/tpcNClsCrossedRows", track.tpcNClsCrossedRows()); - histos.fill("TPC/tpcCrossedRowsOverFindableCls", track.tpcCrossedRowsOverFindableCls()); - histos.fill("TPC/tpcFractionSharedCls", track.tpcFractionSharedCls()); - histos.fill("TPC/tpcChi2NCl", track.tpcChi2NCl()); - } -}; - -struct TrackCutQATask { - HistogramRegistry cuts{"Cuts", {}, OutputObjHandlingPolicy::QAObject}; - TrackSelection selectedTracks = getGlobalTrackSelection(); - static constexpr int ncuts = static_cast<int>(TrackSelection::TrackCuts::kNCuts); - void init(InitContext&) - { - cuts.add("single_cut", ";Cut;Tracks", kTH1D, {{ncuts, 0, ncuts}}); - for (int i = 0; i < ncuts; i++) { - cuts.get<TH1>("single_cut")->GetXaxis()->SetBinLabel(1 + i, TrackSelection::mCutNames[i].data()); - } - } - - void process(soa::Join<aod::FullTracks, aod::TracksExtended>::iterator const& track) - { - for (int i = 0; i < ncuts; i++) { - if (selectedTracks.IsSelected(track, static_cast<TrackSelection::TrackCuts>(i))) { - cuts.fill("single_cut", i); - } - } - } -}; - -//**************************************************************************************** -/** - * QA task including MC truth info. - */ -//**************************************************************************************** -struct TrackQATaskMC { - - HistogramRegistry resolution{"Resolution", {}, OutputObjHandlingPolicy::QAObject}; - - void init(o2::framework::InitContext&){ - - }; - - void process(soa::Join<aod::FullTracks, aod::McTrackLabels>::iterator const& track){ - - }; -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - const bool isMC = cfgc.options().get<bool>("mc"); - const int add_cut_qa = cfgc.options().get<int>("add-cut-qa"); - - WorkflowSpec workflow; - workflow.push_back(adaptAnalysisTask<TrackQATask>("track-qa-histograms")); - if (add_cut_qa) { - workflow.push_back(adaptAnalysisTask<TrackCutQATask>("track-cut-qa-histograms")); - } - if (isMC) { - workflow.push_back(adaptAnalysisTask<TrackQATaskMC>("track-qa-histograms-mc")); - } - return workflow; -} diff --git a/Analysis/Tasks/trackselection.cxx b/Analysis/Tasks/trackselection.cxx deleted file mode 100644 index a8425576eaaff..0000000000000 --- a/Analysis/Tasks/trackselection.cxx +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Task performing basic track selection. -// - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionDefaults.h" -#include "Analysis/TrackSelectionTables.h" -#include "Analysis/trackUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -//**************************************************************************************** -/** - * Produce track filter table. - */ -//**************************************************************************************** -struct TrackSelectionTask { - Produces<aod::TrackSelection> filterTable; - - TrackSelection globalTracks; - TrackSelection globalTracksSDD; - - void init(InitContext&) - { - globalTracks = getGlobalTrackSelection(); - globalTracksSDD = getGlobalTrackSelectionSDD(); - } - - void process(soa::Join<aod::FullTracks, aod::TracksExtended> const& tracks) - { - for (auto& track : tracks) { - filterTable(globalTracks.IsSelected(track), - globalTracksSDD.IsSelected(track)); - } - } -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask<TrackSelectionTask>("track-selection")}; - return workflow; -} diff --git a/Analysis/Tasks/validation.cxx b/Analysis/Tasks/validation.cxx deleted file mode 100644 index 1a6f6dafdee25..0000000000000 --- a/Analysis/Tasks/validation.cxx +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "DetectorsBase/DCAFitter.h" -#include "ReconstructionDataFormats/Track.h" - -#include <TFile.h> -#include <TH1F.h> -#include <cmath> -#include <array> -namespace o2::aod -{ -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -struct ValidationTask { - OutputObj<TH1F> hpt_nocuts{TH1F("hpt_nocuts", "pt tracks (#GeV)", 100, 0., 10.)}; - OutputObj<TH1F> hrun_number{TH1F("hrun_number", "run number", 1000, 0., 1000000.)}; - OutputObj<TH1F> hfCYY{TH1F("hfCYY", "cYY", 1000, 0., 150.)}; - OutputObj<TH1F> hfCZY{TH1F("hfCZY", "cZY", 1000, -40., 10.)}; - OutputObj<TH1F> hfCZZ{TH1F("hfCZZ", "cZZ", 1000, 0., 150.)}; - OutputObj<TH1F> hfCSnpY{TH1F("hfCSnpY", "cSnpY", 1000, -2.5, 1.)}; - OutputObj<TH1F> hfCSnpZ{TH1F("hfCSnpZ", "cSnpZ", 1000, -2.5, 1.)}; - OutputObj<TH1F> hfCSnpSnp{TH1F("hfCSnpSnp", "cSnpSnp", 1000, 0., 0.1)}; - OutputObj<TH1F> hfCTglY{TH1F("hfCTglY", "cTglY", 1000, -0.1, 0.3)}; - OutputObj<TH1F> hfCTglZ{TH1F("hfCTglZ", "cTglZ", 1000, -3., 3.)}; - OutputObj<TH1F> hfCTglSnp{TH1F("hfCTglSnp", "cTglSnp", 1000, -0.01, 0.01)}; - OutputObj<TH1F> hfCTglTgl{TH1F("hfCTglTgl", "cTglTgl", 1000, 0., 0.2)}; - OutputObj<TH1F> hfC1PtY{TH1F("hfC1PtY", "c1PtY", 1000, 0., 30.)}; - OutputObj<TH1F> hfC1PtZ{TH1F("hfC1PtZ", "c1PtZ", 1000, -9., 3.)}; - OutputObj<TH1F> hfC1PtSnp{TH1F("hfC1PtSnp", "c1PtSnp", 1000, -0.8, 1.)}; - OutputObj<TH1F> hfC1PtTgl{TH1F("hfC1PtTgl", "c1PtTgl", 1000, -0.3, 0.1)}; - OutputObj<TH1F> hfC1Pt21Pt2{TH1F("hfC1Pt21Pt2", "c1Pt21Pt2", 1000, -0.3, 0.1)}; - - void process(aod::Collision const& collision, aod::BCs const& bcs, soa::Join<aod::Tracks, aod::TracksCov> const& tracks) - { - hrun_number->Fill(collision.bc().runNumber()); - LOGF(info, "Tracks for collision: %d", tracks.size()); - for (auto& track : tracks) { - hpt_nocuts->Fill(track.pt()); - hfCYY->Fill(track.cYY()); - hfCZY->Fill(track.cZY()); - hfCZZ->Fill(track.cZZ()); - hfCSnpY->Fill(track.cSnpY()); - hfCSnpZ->Fill(track.cSnpZ()); - hfCSnpSnp->Fill(track.cSnpSnp()); - hfCTglY->Fill(track.cTglY()); - hfCTglZ->Fill(track.cTglZ()); - hfCTglSnp->Fill(track.cTglSnp()); - hfCTglTgl->Fill(track.cTglTgl()); - hfC1PtY->Fill(track.c1PtY()); - hfC1PtZ->Fill(track.c1PtZ()); - hfC1PtSnp->Fill(track.c1PtSnp()); - hfC1PtTgl->Fill(track.c1PtTgl()); - hfC1Pt21Pt2->Fill(track.c1Pt21Pt2()); - LOGF(info, "track tgl ss s%f", track.tgl()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ValidationTask>("validation-qa")}; -} diff --git a/Analysis/Tasks/weakDecayIndices.cxx b/Analysis/Tasks/weakDecayIndices.cxx deleted file mode 100644 index 10890bea7bf09..0000000000000 --- a/Analysis/Tasks/weakDecayIndices.cxx +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -using namespace o2; -using namespace o2::framework; - -// Tasks to build transient indices to group V0s and cascades to collisions - -struct IndexV0s { - Produces<aod::TransientV0s> transientV0s; - - void process(aod::StoredV0s const& v0s, aod::FullTracks const& tracks) - { - for (auto& v0 : v0s) { - if (v0.posTrack().collisionId() != v0.negTrack().collisionId()) { - LOGF(WARNING, "V0 %d has inconsistent collision information (%d, %d)", v0.globalIndex(), v0.posTrack().collisionId(), v0.negTrack().collisionId()); - } - transientV0s(v0.posTrack().collisionId()); - } - } -}; - -// NOTE These tasks have to be split because for the cascades, V0s and not StoredV0s are needed -struct IndexCascades { - Produces<aod::TransientCascades> transientCascades; - - void process(aod::V0s const& v0s, aod::StoredCascades const& cascades, aod::FullTracks const& tracks) - { - for (auto& cascade : cascades) { - if (cascade.bachelor().collisionId() != cascade.v0().posTrack().collisionId() || cascade.v0().posTrack().collisionId() != cascade.v0().negTrack().collisionId()) { - LOGF(WARNING, "Cascade %d has inconsistent collision information (%d, %d, %d)", cascade.globalIndex(), cascade.bachelor().collisionId(), cascade.v0().posTrack().collisionId(), cascade.v0().negTrack().collisionId()); - } - transientCascades(cascade.bachelor().collisionId()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<IndexV0s>("weak-decay-indices-v0"), - adaptAnalysisTask<IndexCascades>("weak-decay-indices-cascades"), - }; -} diff --git a/Analysis/Tutorials/CMakeLists.txt b/Analysis/Tutorials/CMakeLists.txt deleted file mode 100644 index d5689d3068466..0000000000000 --- a/Analysis/Tutorials/CMakeLists.txt +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -# FIXME Is this one supposed to be a header only library (in which case the .h -# to be installed should be in include/TestWorkflows) or not a library at all ? -# o2_add_library(TestWorkflows SOURCES src/dummy.cxx -# -# set(HEADERS src/o2_sim_its_ALP3.h src/o2_sim_tpc.h ) -# - -o2_add_dpl_workflow(histogram-track-selection - SOURCES src/histogramTrackSelection.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(track-collection-iteration - SOURCES src/trackCollectionIteration.cxx - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(track-iteration - SOURCES src/trackIteration.cxx - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(full-track-iteration - SOURCES src/fullTrackIteration.cxx - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(collision-tracks-iteration - SOURCES src/collisionTracksIteration.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(new-collections - SOURCES src/newCollections.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(associated-derived - SOURCES src/associatedExample.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(dynamic-columns - SOURCES src/dynamicColumns.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(histograms - SOURCES src/histograms.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(histograms-full-tracks - SOURCES src/histogramsFullTracks.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(filters - SOURCES src/filters.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(partitions - SOURCES src/partitions.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(aodwriter - SOURCES src/aodwriter.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(aodreader - SOURCES src/aodreader.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(outputs - SOURCES src/outputs.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(jet-analysis - SOURCES src/jetAnalysis.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(tracks-combinations - SOURCES src/tracksCombinations.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(event-mixing - SOURCES src/eventMixing.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(mc-histograms - SOURCES src/mcHistograms.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(ccdbaccess - SOURCES src/ccdbaccess.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisCore O2::CCDB O2::Framework O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(weak-decay-iteration - SOURCES src/weakDecayIteration.cxx - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(extended-columns - SOURCES src/extendedColumns.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(zdc-vzero-iteration - SOURCES src/ZDCVZeroIteration.cxx - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(hist-helpers-test - SOURCES src/histHelpersTest.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisDataModel O2::AnalysisCore - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(histogram-registry - SOURCES src/histogramRegistry.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_library(ConfigurableCut - SOURCES src/configurableCut.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisCore) - -o2_target_root_dictionary(ConfigurableCut - HEADERS include/Analysis/configurableCut.h - LINKDEF src/ConfigurableCutLinkDef.h) - -o2_add_dpl_workflow(configurable-objects - SOURCES src/configurableObjects.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::ConfigurableCut - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(muon-iteration - SOURCES src/muonIteration.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(schema-evolution - SOURCES src/schemaEvolution.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(efficiency-per-run - SOURCES src/efficiencyPerRun.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) - -o2_add_dpl_workflow(efficiency-global - SOURCES src/efficiencyGlobal.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel - COMPONENT_NAME AnalysisTutorial) diff --git a/Analysis/Tutorials/include/Analysis/configurableCut.h b/Analysis/Tutorials/include/Analysis/configurableCut.h deleted file mode 100644 index 76ab55847b0b6..0000000000000 --- a/Analysis/Tutorials/include/Analysis/configurableCut.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef CONFIGURABLECUT_H -#define CONFIGURABLECUT_H - -#include <iosfwd> -#include <Rtypes.h> -#include <TMath.h> - -class configurableCut -{ - public: - configurableCut(float cut_ = 2., int state_ = 1, bool option_ = true) - : cut{cut_}, state{state_}, option{option_} - { - } - - bool method(float arg) const; - - void setCut(float cut_); - float getCut() const; - - void setState(int state_); - int getState() const; - - void setOption(bool option_); - bool getOption() const; - - private: - float cut; - int state; - bool option; - - ClassDef(configurableCut, 3); -}; - -std::ostream& operator<<(std::ostream& os, configurableCut const& c); - -#endif // CONFIGURABLECUT_H diff --git a/Analysis/Tutorials/src/ConfigurableCutLinkDef.h b/Analysis/Tutorials/src/ConfigurableCutLinkDef.h deleted file mode 100644 index 0760e732fb45f..0000000000000 --- a/Analysis/Tutorials/src/ConfigurableCutLinkDef.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class configurableCut + ; diff --git a/Analysis/Tutorials/src/ZDCVZeroIteration.cxx b/Analysis/Tutorials/src/ZDCVZeroIteration.cxx deleted file mode 100644 index fc89aca047b3c..0000000000000 --- a/Analysis/Tutorials/src/ZDCVZeroIteration.cxx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This task shows how to access the ZDC and FV0A information which belongs to a collision -// The association is made through the BC column (and in Run 3 may not be unique!) - -// This example access the collisions and the related FV0A information. -// Note that one has to subscribe to aod::Collisions const& and aod::FV0As const& to load -// the relevant data even if you access the data itself through m.collision() and m.fv0a() -// Here the "sparse" matcher is used which means, there can be collisions without FV0A information -// To find out, m.has_fv0a() has to be called. Otherwise m.fv0a() will fail. -struct IterateV0 { - void process(aod::Run2MatchedSparse::iterator const& m, aod::Collisions const&, aod::FV0As const&) - { - LOGF(INFO, "Vertex = %f", m.collision().posZ()); - if (m.has_fv0a()) { - auto v0a = m.fv0a(); - LOGF(info, "V0A: %f %f", v0a.amplitude()[0], v0a.amplitude()[1]); - } else { - LOGF(INFO, "No V0A info"); - } - } -}; - -// This example is identical to IterateV0, but uses the exclusive match. This means that lines where any -// of the tables asked for in Run2MatchedExclusive (see AnalysisDataModel.h) are missing are not listed. -// Only to be used if one is sure that all your events have the desired information -struct IterateV0Exclusive { - void process(aod::Run2MatchedExclusive::iterator const& m, aod::Collisions const&, aod::FV0As const&) - { - LOGF(INFO, "Vertex = %f", m.collision().posZ()); - auto v0a = m.fv0a(); - LOGF(info, "V0: %f %f", v0a.amplitude()[0], v0a.amplitude()[1]); - } -}; - -// This example builds on IterateV0 and in addition accesses also the tracks grouped to the specific collision. -// The tracks are directly access through its pointer. -struct IterateV0Tracks { - void process(aod::Run2MatchedSparse::iterator const& m, aod::Collisions const&, aod::FV0As const&, aod::Tracks const& tracks) - { - LOGF(INFO, "Vertex = %f. %d tracks", m.collision().posZ(), tracks.size()); - if (m.has_fv0a()) { - auto v0a = m.fv0a(); - LOGF(info, "V0A: %f %f", v0a.amplitude()[0], v0a.amplitude()[1]); - } else { - LOGF(INFO, "No V0A info"); - } - } -}; - -// IterateV0Tracks with join. Desired version for good readability -// using CollisionMatchedRun2Sparse = soa::Join<aod::Run2MatchedSparse, aod::Collisions>::iterator; -// struct IterateV0Tracks2 { -// void process(CollisionMatchedRun2Sparse const& m, aod::FV0As const&, aod::Tracks const& tracks) -// { -// LOGF(INFO, "Vertex = %f. %d tracks", m.posZ(), tracks.size()); -// LOGF(INFO, "Vertex = %f. %d tracks", m.collision().posZ(), tracks.size()); -// if (m.has_fv0a()) { -// auto v0a = m.fv0a(); -// LOGF(info, "V0A: %f %f", v0a.amplitude()[0], v0a.amplitude()[1]); -// } else { -// LOGF(INFO, "No V0A info"); -// } -// } -// }; - -// This example accesses V0 and ZDC information -struct IterateV0ZDC { - void process(aod::Run2MatchedSparse::iterator const& m, aod::Collisions const&, aod::FV0As const&, aod::Zdcs const&) - { - LOGF(INFO, "Vertex = %f", m.collision().posZ()); - if (m.has_fv0a()) { - auto v0a = m.fv0a(); - LOGF(info, "V0A: %f %f", v0a.amplitude()[0], v0a.amplitude()[1]); - } else { - LOGF(INFO, "No V0A info"); - } - if (m.has_zdc()) { - LOGF(INFO, "ZDC: E1 = %.3f; E2 = %.3f", m.zdc().energyZEM1(), m.zdc().energyZEM2()); - } else { - LOGF(INFO, "No ZDC info"); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<IterateV0>("iterate-v0"), - adaptAnalysisTask<IterateV0Exclusive>("iterate-v0-exclusive"), - adaptAnalysisTask<IterateV0Tracks>("iterate-v0-tracks"), - // adaptAnalysisTask<IterateV0Tracks2>("iterate-v0-tracks2"), - adaptAnalysisTask<IterateV0ZDC>("iterate-v0-zdc"), - }; -} diff --git a/Analysis/Tutorials/src/aodreader.cxx b/Analysis/Tutorials/src/aodreader.cxx deleted file mode 100644 index 8881517e88051..0000000000000 --- a/Analysis/Tutorials/src/aodreader.cxx +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -/// This example is to be used together with the aodwriter example. -/// aodwriter creates three tables and writes them to two sets of files. -/// aodreader reads these files and creates related tables. aodwriter takes an -/// aod file with tracks as input. -/// -/// USAGE: -/// -/// o2-analysistutorial-aodwriter --aod-file AO2D_ppK0starToyMC_v3.root --json-file writerConfiguration.json -/// ls -1 treResults*.root > resultFiles.txt -/// ls -1 unodueResults*.root >> resultFiles.txt -/// o2-analysistutorial-aodreader --json-file readerConfiguration.json -/// -/// writerConfiguration.json: -/// { -/// "OutputDirector": { -/// "debugmode": true, -/// "resfile": "unodueResults", -/// "resfilemode": "RECREATE", -/// "ntfmerge": 1, -/// "OutputDescriptors": [ -/// { -/// "table": "AOD/UNO/0", -/// "treename": "unotree" -/// }, -/// { -/// "table": "AOD/DUE/0", -/// "columns": [ -/// "due_1", -/// "due_3", -/// "due_5" -/// ], -/// "treename": "duetree" -/// }, -/// { -/// "table": "AOD/TRE/0", -/// "filename": "treResults" -/// } -/// ] -/// } -/// } -/// -/// readerConfiguration.json: -/// { -/// "InputDirector": { -/// "debugmode": true, -/// "resfiles": "@resultFiles.txt", -/// "fileregex": "(unodue)(.*)", -/// "InputDescriptors": [ -/// { -/// "table": "AOD/EINS/0", -/// "treename": "unotree" -/// }, -/// { -/// "table": "AOD/ZWEI/0", -/// "treename": "duetree" -/// }, -/// { -/// "table": "AOD/DREI/0", -/// "treename": "TRE", -/// "fileregex": "(treResults)(.*)" -/// } -/// ] -/// } -/// } - -namespace o2::aod -{ -namespace eins -{ -DECLARE_SOA_COLUMN_FULL(Eta, eta, float, "uno_1"); -DECLARE_SOA_COLUMN_FULL(Mom, mom, double, "uno_3"); -} // namespace eins - -DECLARE_SOA_TABLE(Eins, "AOD", "EINS", - eins::Eta, eins::Mom); - -namespace zwei -{ -DECLARE_SOA_COLUMN_FULL(Ok, ok, bool, "due_1"); -DECLARE_SOA_COLUMN_FULL(Phi, phi, float, "due_3"); -DECLARE_SOA_COLUMN_FULL(Pt, pt, double, "due_5"); -} // namespace zwei - -DECLARE_SOA_TABLE(Zwei, "AOD", "ZWEI", - zwei::Ok, zwei::Phi, zwei::Pt); - -namespace drei -{ -DECLARE_SOA_COLUMN_FULL(Eta, eta, float, "tre_1"); -DECLARE_SOA_COLUMN_FULL(Phi, phi, float, "tre_2"); -DECLARE_SOA_COLUMN_FULL(Mom, mom, double, "tre_3"); -} // namespace drei - -DECLARE_SOA_TABLE(Drei, "AOD", "DREI", - drei::Eta, drei::Phi, drei::Mom); - -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -struct ATask { - void process(aod::Eins const& unos, aod::Zwei const& dues, aod::Drei const& tres) - { - int cnt = 0; - for (auto& uno : unos) { - auto eta = uno.eta(); - auto mom = uno.mom(); - - cnt++; - LOGF(INFO, "Eins (%i): (%f, %f)", cnt, eta, mom); - } - LOGF(INFO, "ATask Processed %i data points from Eins", cnt); - - cnt = 0; - for (auto& due : dues) { - auto ok = due.ok(); - auto phi = due.phi(); - auto pt = due.pt(); - - cnt++; - LOGF(INFO, "Zwei (%i): (%i, %f, %f)", cnt, ok, phi, pt); - } - LOGF(INFO, "ATask Processed %i data points from Zwei", cnt); - - cnt = 0; - for (auto& tre : tres) { - auto eta = tre.eta(); - auto phi = tre.phi(); - auto mom = tre.mom(); - - cnt++; - LOGF(INFO, "Drei (%i): (%f, %f, %f)", cnt, eta, phi, mom); - } - LOGF(INFO, "ATask Processed %i data points from Drei", cnt); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("process-unoduetre")}; -} diff --git a/Analysis/Tutorials/src/aodwriter.cxx b/Analysis/Tutorials/src/aodwriter.cxx deleted file mode 100644 index 72df95cc46cf5..0000000000000 --- a/Analysis/Tutorials/src/aodwriter.cxx +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -/// This example is to be used together with the aodreader example. -/// aodwriter creates three tables and writes them to two sets of files. -/// aodreader reads these files and creates related tables. aodwriter takes an -/// aod file with tracks as input. -/// -/// USAGE: -/// -/// o2-analysistutorial-aodwriter --aod-file AO2D_ppK0starToyMC_v3.root --json-file writerConfiguration.json -/// ls -1 treResults*.root > resultFiles.txt -/// ls -1 unodueResults*.root >> resultFiles.txt -/// o2-analysistutorial-aodreader --json-file readerConfiguration.json -/// -/// writerConfiguration.json: -/// { -/// "OutputDirector": { -/// "debugmode": true, -/// "resfile": "unodueResults", -/// "resfilemode": "RECREATE", -/// "ntfmerge": 1, -/// "OutputDescriptors": [ -/// { -/// "table": "AOD/UNO/0", -/// "treename": "unotree" -/// }, -/// { -/// "table": "AOD/DUE/0", -/// "columns": [ -/// "due_1", -/// "due_3", -/// "due_5" -/// ], -/// "treename": "duetree" -/// }, -/// { -/// "table": "AOD/TRE/0", -/// "filename": "treResults" -/// } -/// ] -/// } -/// } -/// -/// readerConfiguration.json: -/// { -/// "InputDirector": { -/// "debugmode": true, -/// "resfiles": "@resultFiles.txt", -/// "fileregex": "(unodue)(.*)", -/// "InputDescriptors": [ -/// { -/// "table": "AOD/EINS/0", -/// "treename": "unotree" -/// }, -/// { -/// "table": "AOD/ZWEI/0", -/// "treename": "duetree" -/// }, -/// { -/// "table": "AOD/DREI/0", -/// "treename": "TRE", -/// "fileregex": "(treResults)(.*)" -/// } -/// ] -/// } -/// } - -namespace o2::aod -{ -namespace uno -{ -DECLARE_SOA_COLUMN_FULL(Eta, eta, float, "uno_1"); -DECLARE_SOA_COLUMN_FULL(Phi, phi, float, "uno_2"); -DECLARE_SOA_COLUMN_FULL(Mom, mom, double, "uno_3"); -} // namespace uno - -DECLARE_SOA_TABLE(Uno, "AOD", "UNO", - uno::Eta, uno::Phi, uno::Mom); - -namespace due -{ -DECLARE_SOA_COLUMN_FULL(Ok, ok, bool, "due_1"); -DECLARE_SOA_COLUMN_FULL(Eta, eta, float, "due_2"); -DECLARE_SOA_COLUMN_FULL(Phi, phi, float, "due_3"); -DECLARE_SOA_COLUMN_FULL(Mom, mom, double, "due_4"); -DECLARE_SOA_COLUMN_FULL(Pt, pt, double, "due_5"); -} // namespace due - -DECLARE_SOA_TABLE(Due, "AOD", "DUE", - due::Ok, due::Eta, due::Phi, due::Mom, due::Pt); - -namespace tre -{ -DECLARE_SOA_COLUMN_FULL(Eta, eta, float, "tre_1"); -DECLARE_SOA_COLUMN_FULL(Phi, phi, float, "tre_2"); -DECLARE_SOA_COLUMN_FULL(Mom, mom, double, "tre_3"); -DECLARE_SOA_COLUMN_FULL(Id, id, int, "tre_4"); -} // namespace tre - -DECLARE_SOA_TABLE(Tre, "AOD", "TRE", - tre::Eta, tre::Phi, tre::Mom, tre::Id); - -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -struct ATask { - Produces<aod::Uno> table_uno; - Produces<aod::Due> table_due; - Produces<aod::Tre> table_tre; - - void init(InitContext&) - { - cnt = 0; - } - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - bool ok = (cnt % 2) == 0; - float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl()))); - float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI); - double mom = track.tgl(); - double pt = track.signed1Pt(); - int id = (int)cnt; - - table_uno(phi, eta, mom); - table_due(ok, phi, eta, mom, pt); - table_tre(phi, eta, mom, id); - //LOGF(INFO, "Values (%i): (%i %f, %f, %f, %f, %i)", cnt, ok, eta, phi, mom, pt, id); - cnt++; - } - - LOGF(INFO, "ATask Processed %i data points from Tracks", cnt); - } - - size_t cnt = 0; -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("produce-unoduetre")}; -} diff --git a/Analysis/Tutorials/src/associatedExample.cxx b/Analysis/Tutorials/src/associatedExample.cxx deleted file mode 100644 index 6ac8e1225467c..0000000000000 --- a/Analysis/Tutorials/src/associatedExample.cxx +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace etaphi -{ -DECLARE_SOA_COLUMN(AEta, etas, float); -DECLARE_SOA_COLUMN(APhi, phis, float); -DECLARE_SOA_COLUMN(APt, pts, float); -} // namespace etaphi - -DECLARE_SOA_TABLE(EtaPhi, "AOD", "ETAPHI", - etaphi::AEta, etaphi::APhi); - -namespace collision -{ -DECLARE_SOA_COLUMN(Mult, mult, int32_t); -} // namespace collision - -DECLARE_SOA_TABLE(CollisionsExtra, "AOD", "COLEXTRA", - collision::Mult); -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -// This is a very simple example showing how to iterate over tracks -// and create a new collection for them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - Produces<aod::EtaPhi> etaphi; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI); - float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl()))); - etaphi(eta, phi); - } - } -}; - -struct MTask { - Produces<aod::CollisionsExtra> colextra; - - void process(aod::Collision const&, aod::Tracks const& tracks) - { - colextra(tracks.size()); - } -}; - -struct BTask { - void process(aod::Collision const& collision, soa::Join<aod::Tracks, aod::EtaPhi> const& extTracks) - { - LOGF(INFO, "ID: %d", collision.globalIndex()); - LOGF(INFO, "Tracks: %d", extTracks.size()); - for (auto& track : extTracks) { - LOGF(INFO, "(%f, %f) - (%f, %f)", track.eta(), track.phiraw(), track.etas(), track.phis()); - } - } -}; - -struct TTask { - using myCol = soa::Join<aod::Collisions, aod::CollisionsExtra>; - expressions::Filter multfilter = aod::collision::mult > 10; - void process(soa::Filtered<soa::Join<aod::Collisions, aod::CollisionsExtra>>::iterator const& col, aod::Tracks const& tracks) - { - LOGF(INFO, "[direct] ID: %d; %d == %d", col.globalIndex(), col.mult(), tracks.size()); - if (tracks.size() > 0) { - auto track0 = tracks.begin(); - LOGF(INFO, "[index ] ID: %d; %d == %d", track0.collision_as<myCol>().globalIndex(), track0.collision_as<myCol>().mult(), tracks.size()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("produce-etaphi"), - adaptAnalysisTask<BTask>("consume-etaphi"), - adaptAnalysisTask<MTask>("produce-mult"), - adaptAnalysisTask<TTask>("consume-mult")}; -} diff --git a/Analysis/Tutorials/src/ccdbaccess.cxx b/Analysis/Tutorials/src/ccdbaccess.cxx deleted file mode 100644 index 0d2718e50eac6..0000000000000 --- a/Analysis/Tutorials/src/ccdbaccess.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \brief A tutorial task to retrieve objects from CCDB given a run number. -/// The tutorial shows also how to use timestamps in your analysis. -/// This task requires to access the timestamp table in order to be working. -/// Currently this is done by adding `o2-analysis-timestamp` to the workflow -/// \author Nicolo' Jacazio -/// \since 2020-06-22 -/// - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <CCDB/BasicCCDBManager.h> -#include "CommonDataFormat/InteractionRecord.h" - -#include <chrono> - -using namespace o2::framework; -using namespace o2::header; -using namespace o2; - -struct TimestampUserTask { - Service<o2::ccdb::BasicCCDBManager> ccdb; - Configurable<std::string> path{"ccdb-path", "qc/TOF/TOFTaskCompressed/hDiagnostic", "path to the ccdb object"}; - Configurable<std::string> url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; - Configurable<long> nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - - void init(o2::framework::InitContext&) - { - // Set CCDB url - ccdb->setURL(url.value); - // Enabling object caching - ccdb->setCaching(true); - // Not later than now objects - ccdb->setCreatedNotAfter(nolaterthan.value); - } - - void process(aod::Collision const& collision, aod::BCsWithTimestamps const& /*bc*/) - { - auto bc = collision.bc_as<aod::BCsWithTimestamps>(); - LOGF(info, "Getting object %s for run number %i from timestamp=%llu", path.value.data(), bc.runNumber(), bc.timestamp()); - auto obj = ccdb->getForTimeStamp<TH2F>(path.value, bc.timestamp()); - if (obj) { - LOGF(info, "Found object!"); - obj->Print("all"); - } else { - LOGF(warning, "Object not found!"); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{adaptAnalysisTask<TimestampUserTask>("TimestampUserTask")}; -} diff --git a/Analysis/Tutorials/src/collisionTracksIteration.cxx b/Analysis/Tutorials/src/collisionTracksIteration.cxx deleted file mode 100644 index e2d1f8a07efe3..0000000000000 --- a/Analysis/Tutorials/src/collisionTracksIteration.cxx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" - -#include <TFile.h> -#include <TH1F.h> - -using namespace o2; -using namespace o2::framework; - -// This is a very simple example showing how to iterate over tracks -// and operate on them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - void process(aod::Collision const&, aod::Tracks const& tracks) - { - LOGF(info, "Tracks for collision: %d", tracks.size()); - for (auto& track : tracks) { - LOGF(info, "This track has pT = %f GeV/c", track.pt()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("collision-tracks-iteration-tutorial")}; -} diff --git a/Analysis/Tutorials/src/configurableCut.cxx b/Analysis/Tutorials/src/configurableCut.cxx deleted file mode 100644 index 1b52790828268..0000000000000 --- a/Analysis/Tutorials/src/configurableCut.cxx +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Analysis/configurableCut.h" -#include <iostream> - -bool configurableCut::method(float arg) const -{ - return arg > cut; -} - -void configurableCut::setCut(float cut_) -{ - cut = cut_; -} - -float configurableCut::getCut() const -{ - return cut; -} - -std::ostream& operator<<(std::ostream& os, configurableCut const& c) -{ - os << "Cut value: " << c.getCut() << "; state: " << c.getState(); - return os; -} - -void configurableCut::setState(int state_) -{ - state = state_; -} - -int configurableCut::getState() const -{ - return state; -} - -void configurableCut::setOption(bool option_) -{ - option = option_; -} - -bool configurableCut::getOption() const -{ - return option; -} diff --git a/Analysis/Tutorials/src/configurableCut.json b/Analysis/Tutorials/src/configurableCut.json deleted file mode 100644 index 33d4294b13286..0000000000000 --- a/Analysis/Tutorials/src/configurableCut.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "internal-dpl-clock": "", - "internal-dpl-aod-reader": { - "aod-file": "aod.root", - "time-limit": "0", - "start-value-enumeration": "0", - "end-value-enumeration": "-1", - "step-value-enumeration": "1" - }, - "internal-dpl-aod-spawner": "", - "configurable-demo": { - "cut": { - "cut": "0.1", - "state": "1" - }, - "mutable_cut": { - "cut": "0.2", - "state": "-1" - } - } -} diff --git a/Analysis/Tutorials/src/configurableObjects.cxx b/Analysis/Tutorials/src/configurableObjects.cxx deleted file mode 100644 index 2cf3dbb035672..0000000000000 --- a/Analysis/Tutorials/src/configurableObjects.cxx +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/configurableCut.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -/// This task demonstrates how to use configurable to wrap classes -/// use it with supplied configuration: "configurableObject.json" - -struct ConfigurableObjectDemo { - Configurable<configurableCut> cut{"cut", {0.5, 1, true}, "generic cut"}; - MutableConfigurable<configurableCut> mutable_cut{"mutable_cut", {1., 2, false}, "generic cut"}; - void init(InitContext const&){}; - void process(aod::Collision const&, aod::Tracks const& tracks) - { - LOGF(INFO, "Cut1: %.3f; Cut2: %.3f", cut, mutable_cut); - for (auto& track : tracks) { - if (track.globalIndex() % 500 == 0) { - std::string decision1; - std::string decision2; - if (cut->method(std::abs(track.eta()))) { - decision1 = "true"; - } else { - decision1 = "false"; - } - if (mutable_cut->method(std::abs(track.eta()))) { - decision2 = "true"; - } else { - decision2 = "false"; - } - LOGF(INFO, "Cut1: %s; Cut2: %s", decision1, decision2); - if (decision2 == "false") { - mutable_cut->setState(-1); - } else { - mutable_cut->setState(1); - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ConfigurableObjectDemo>("configurable-demo")}; -} diff --git a/Analysis/Tutorials/src/dynamicColumns.cxx b/Analysis/Tutorials/src/dynamicColumns.cxx deleted file mode 100644 index a4c2492d7f443..0000000000000 --- a/Analysis/Tutorials/src/dynamicColumns.cxx +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace extension -{ -DECLARE_SOA_DYNAMIC_COLUMN(P2, p2, [](float p) { return p * p; }); -} // namespace etaphi -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -struct ATask { - void process(aod::Collision const&, aod::Tracks const& tracks) - { - auto table_with_extra_dynamic_columns = soa::Attach<aod::Tracks, aod::extension::P2<aod::track::P>>(tracks); - for (auto& row : table_with_extra_dynamic_columns) { - if (row.trackType() != 3) { - if (row.index() % 100 == 0) { - LOGF(info, "P^2 = %.3f", row.p2()); - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - // create and use table - return WorkflowSpec{ - adaptAnalysisTask<ATask>("attach-showcase")}; -} diff --git a/Analysis/Tutorials/src/efficiencyGlobal.cxx b/Analysis/Tutorials/src/efficiencyGlobal.cxx deleted file mode 100644 index 7f742ca493c2d..0000000000000 --- a/Analysis/Tutorials/src/efficiencyGlobal.cxx +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \brief This example demonstrates how the CCDB can be used to store an efficiency object which is valid for a full train run -/// The objects are uploaded with -/// The objects are uploaded with https://alimonitor.cern.ch/ccdb/upload.jsp -/// A sufficiently large time stamp interval should be given to span all runs under consideration -/// NOTE If an efficiency object per run is needed, please check the example efficiencyPerRun.cxx -/// - -#include <chrono> - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <CCDB/BasicCCDBManager.h> - -using namespace o2::framework; -using namespace o2; - -struct EfficiencyGlobal { - Service<ccdb::BasicCCDBManager> ccdb; - Configurable<std::string> path{"ccdb-path", "Users/j/jgrosseo/tutorial/efficiency/simple", "base path to the ccdb object"}; - Configurable<std::string> url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable<long> nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - - OutputObj<TH1F> pt{TH1F("pt", "pt", 20, 0., 10.)}; - - TH1F* efficiency = nullptr; - - void init(InitContext&) - { - ccdb->setURL(url.value); - // Enabling object caching, otherwise each call goes to the CCDB server - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - // Not later than now, will be replaced by the value of the train creation - // This avoids that users can replace objects **while** a train is running - ccdb->setCreatedNotAfter(nolaterthan.value); - LOGF(info, "Getting object %s", path.value.data()); - efficiency = ccdb->getForTimeStamp<TH1F>(path.value, nolaterthan.value); - if (!efficiency) { - LOGF(fatal, "Efficiency object not found!"); - } - } - - void process(aod::Collision const& collision, aod::Tracks const& tracks) - { - for (auto& track : tracks) { - pt->Fill(track.pt(), efficiency->GetBinContent(efficiency->FindBin(track.pt()))); - //LOGF(info, "Efficiency %f for pt %f", efficiency->GetBinContent(efficiency->FindBin(track.pt())), track.pt()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{adaptAnalysisTask<EfficiencyGlobal>("EfficiencyGlobal")}; -} diff --git a/Analysis/Tutorials/src/efficiencyPerRun.cxx b/Analysis/Tutorials/src/efficiencyPerRun.cxx deleted file mode 100644 index 72636d35c6f77..0000000000000 --- a/Analysis/Tutorials/src/efficiencyPerRun.cxx +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \brief A tutorial task to retrieve objects from CCDB given a run number. -/// This example demonstrates how the CCDB can be used to store an efficiency object which is valid only for a specific time -/// interval (e.g. for a run) -/// The objects are uploaded with https://alimonitor.cern.ch/ccdb/upload.jsp -/// Different timestamps intervals can be given. -/// You need to run this with the o2-analysis-timestamp task -/// NOTE If only one efficiency object for all runs is needed, this code is not optimal. In this case please check the example: -/// efficiencyGlobal.cxx -/// - -#include <chrono> - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <CCDB/BasicCCDBManager.h> - -using namespace o2::framework; -using namespace o2; - -struct EfficiencyPerRun { - Service<ccdb::BasicCCDBManager> ccdb; - Configurable<std::string> path{"ccdb-path", "Users/j/jgrosseo/tutorial/efficiency/simple", "base path to the ccdb object"}; - Configurable<std::string> url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable<long> nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - - OutputObj<TH1F> pt{TH1F("pt", "pt", 20, 0., 10.)}; - - void init(InitContext&) - { - ccdb->setURL(url.value); - // Enabling object caching, otherwise each call goes to the CCDB server - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - // Not later than now, will be replaced by the value of the train creation - // This avoids that users can replace objects **while** a train is running - ccdb->setCreatedNotAfter(nolaterthan.value); - } - - void process(aod::Collision const& collision, aod::BCsWithTimestamps const&, aod::Tracks const& tracks) - { - auto bc = collision.bc_as<aod::BCsWithTimestamps>(); - LOGF(info, "Getting object %s for run number %i from timestamp=%llu", path.value.data(), bc.runNumber(), bc.timestamp()); - auto efficiency = ccdb->getForTimeStamp<TH1F>(path.value, bc.timestamp()); - if (!efficiency) { - LOGF(fatal, "Efficiency object not found!"); - } - - for (auto& track : tracks) { - pt->Fill(track.pt(), efficiency->GetBinContent(efficiency->FindBin(track.pt()))); - //LOGF(info, "Efficiency %f for pt %f", efficiency->GetBinContent(efficiency->FindBin(track.pt())), track.pt()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{adaptAnalysisTask<EfficiencyPerRun>("EfficiencyPerRun")}; -} diff --git a/Analysis/Tutorials/src/eventMixing.cxx b/Analysis/Tutorials/src/eventMixing.cxx deleted file mode 100644 index 44930c57029a9..0000000000000 --- a/Analysis/Tutorials/src/eventMixing.cxx +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" - -namespace o2::aod -{ -namespace hash -{ -DECLARE_SOA_COLUMN(Bin, bin, int); -} // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); - -using Hash = Hashes::iterator; -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; - -// This is a tentative workflow to get mixed-event tracks -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that - -struct HashTask { - std::vector<float> xBins{-1.5f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 1.5f}; - std::vector<float> yBins{-1.5f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 1.5f}; - Produces<aod::Hashes> hashes; - - // Calculate hash for an element based on 2 properties and their bins. - int getHash(std::vector<float> const& xBins, std::vector<float> const& yBins, float colX, float colY) - { - if (colX < xBins[0] || colY < yBins[0]) { - return -1; - } - for (int i = 1; i < xBins.size(); i++) { - if (colX < xBins[i]) { - for (int j = 1; j < yBins.size(); j++) { - if (colY < yBins[j]) { - return i + j * (xBins.size() + 1); - } - } - return -1; - } - } - - return -1; - } - - void process(aod::Collisions const& collisions) - { - for (auto& collision : collisions) { - int hash = getHash(xBins, yBins, collision.posX(), collision.posY()); - LOGF(info, "Collision: %d (%f, %f, %f) hash: %d", collision.index(), collision.posX(), collision.posY(), collision.posZ(), hash); - hashes(hash); - } - } -}; - -// Version 1: Using categorised combinations -struct CollisionsCombinationsTask { - o2::framework::expressions::Filter trackFilter = (aod::track::x > -0.8f) && (aod::track::x < 0.8f) && (aod::track::y > 1.0f); - - void process(aod::Hashes const& hashes, aod::Collisions& collisions, soa::Filtered<aod::Tracks>& tracks) - { - collisions.bindExternalIndices(&tracks); - auto tracksTuple = std::make_tuple(tracks); - AnalysisDataProcessorBuilder::GroupSlicer slicer(collisions, tracksTuple); - - // Strictly upper categorised collisions - for (auto& [c1, c2] : selfCombinations("fBin", 5, -1, join(hashes, collisions), join(hashes, collisions))) { - LOGF(info, "Collisions bin: %d pair: %d (%f, %f, %f), %d (%f, %f, %f)", c1.bin(), c1.index(), c1.posX(), c1.posY(), c1.posZ(), c2.index(), c2.posX(), c2.posY(), c2.posZ()); - - auto it1 = slicer.begin(); - auto it2 = slicer.begin(); - for (auto& slice : slicer) { - if (slice.groupingElement().index() == c1.index()) { - it1 = slice; - break; - } - } - for (auto& slice : slicer) { - if (slice.groupingElement().index() == c2.index()) { - it2 = slice; - break; - } - } - auto tracks1 = std::get<soa::Filtered<aod::Tracks>>(it1.associatedTables()); - tracks1.bindExternalIndices(&collisions); - auto tracks2 = std::get<soa::Filtered<aod::Tracks>>(it2.associatedTables()); - tracks2.bindExternalIndices(&collisions); - - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index()); - } - } - } -}; - -// Version 2: Filtering instead of combinations -// Possible only after filters & grouping upgrades -// struct CollisionsFilteringTask { -// Alternatively: filter/partition directly on collisions -// expressions::Filter aod::hash::bin{0} == aod::hash::bin{1}; - -// Currently multiple grouping and grouping by Joins is not possible -// void process(soa::Filtered<soa::Join<aod::Hashes, aod::Collisions>>::iterator const& hashedCol1, aod::Tracks const& tracks1, -// soa::Filtered<soa::Join<aod::Hashes, aod::Collisions>>::iterator const& hashedCol2, aod::Tracks const& tracks2) -//{ -// for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { -// LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), hashedCol1.index(), hashedCol2.index()); -// } -//} -// }; - -// What we would like to have -struct MixedEventsTask { - void process(aod::Collision const& col1, aod::Tracks const& tracks1, aod::Collision const& col2, aod::Tracks const& tracks2) - { - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), col1.index(), col2.index()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HashTask>("collisions-hashed"), - adaptAnalysisTask<CollisionsCombinationsTask>("mixed-event-tracks")}; -} diff --git a/Analysis/Tutorials/src/extendedColumns.cxx b/Analysis/Tutorials/src/extendedColumns.cxx deleted file mode 100644 index 7d1ec1185ac41..0000000000000 --- a/Analysis/Tutorials/src/extendedColumns.cxx +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace extension -{ -DECLARE_SOA_EXPRESSION_COLUMN(P2, p2, float, track::p* track::p); -} // namespace extension -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -struct ATask { - void process(aod::Collision const&, aod::Tracks const& tracks) - { - auto table_extension = soa::Extend<aod::Tracks, aod::extension::P2>(tracks); - for (auto& row : table_extension) { - if (row.trackType() != 3) { - if (row.index() % 100 == 0) { - LOGF(info, "P^2 = %.3f", row.p2()); - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - // create and use table - return WorkflowSpec{ - adaptAnalysisTask<ATask>("extend-showcase")}; -} diff --git a/Analysis/Tutorials/src/filters.cxx b/Analysis/Tutorials/src/filters.cxx deleted file mode 100644 index 3df02db0427ae..0000000000000 --- a/Analysis/Tutorials/src/filters.cxx +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace etaphi -{ -DECLARE_SOA_COLUMN(NPhi, nphi, float); -DECLARE_SOA_EXPRESSION_COLUMN(CosPhi, cosphi, float, ncos(aod::etaphi::nphi)); -} // namespace etaphi -namespace track -{ -DECLARE_SOA_EXPRESSION_COLUMN(SPt, spt, float, nabs(aod::track::sigma1Pt / aod::track::signed1Pt)); -} -DECLARE_SOA_TABLE(TPhi, "AOD", "TPHI", - etaphi::NPhi); -DECLARE_SOA_EXTENDED_TABLE_USER(EPhi, TPhi, "EPHI", aod::etaphi::CosPhi); -using etracks = soa::Join<aod::Tracks, aod::TracksCov>; -DECLARE_SOA_EXTENDED_TABLE_USER(MTracks, etracks, "MTRACK", aod::track::SPt); -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This is a very simple example showing how to iterate over tracks -// and create a new collection for them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - Produces<aod::TPhi> tphi; - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - tphi(track.phi()); - } - } -}; - -struct BTask { - Spawns<aod::EPhi> ephi; - Spawns<aod::MTracks> mtrk; - - float fPI = static_cast<float>(M_PI); - float ptlow = 0.5f; - float ptup = 2.0f; - Filter ptFilter_a = aod::track::pt > ptlow; - Filter ptFilter_b = aod::track::pt < ptup; - - float etalow = -1.0f; - float etaup = 1.0f; - Filter etafilter = (aod::track::eta < etaup) && (aod::track::eta > etalow); - - float philow = 1.0f; - float phiup = 2.0f; - Filter phifilter = (aod::etaphi::nphi < phiup) && (aod::etaphi::nphi > philow); - - Filter posZfilter = nabs(aod::collision::posZ) < 10.0f; - - void process(soa::Filtered<aod::Collisions>::iterator const& collision, soa::Filtered<soa::Join<aod::Tracks, aod::TPhi>> const& tracks) - { - LOGF(INFO, "Collision: %d [N = %d out of %d], -10 < %.3f < 10", - collision.globalIndex(), tracks.size(), tracks.tableSize(), collision.posZ()); - for (auto& track : tracks) { - LOGF(INFO, "id = %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), etalow, track.eta(), etaup, philow, track.nphi(), phiup, ptlow, track.pt(), ptup); - } - } -}; - -struct CTask { - void process(aod::Collision const&, soa::Join<aod::Tracks, aod::EPhi> const& tracks) - { - for (auto& track : tracks) { - LOGF(INFO, "%.3f == %.3f", track.cosphi(), std::cos(track.phi())); - } - } -}; - -struct DTask { - Filter notTracklet = aod::track::trackType != static_cast<uint8_t>(aod::track::TrackTypeEnum::Run2Tracklet); - void process(aod::Collision const&, soa::Filtered<aod::MTracks> const& tracks) - { - for (auto& track : tracks) { - LOGF(INFO, "%.3f == %.3f", track.spt(), std::abs(track.sigma1Pt() / track.signed1Pt())); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("produce-normalizedphi"), - adaptAnalysisTask<BTask>("consume-normalizedphi"), - adaptAnalysisTask<CTask>("consume-spawned-ephi"), - adaptAnalysisTask<DTask>("consume-spawned-mtracks")}; -} diff --git a/Analysis/Tutorials/src/fullTrackIteration.cxx b/Analysis/Tutorials/src/fullTrackIteration.cxx deleted file mode 100644 index bc1cd00cc4e4d..0000000000000 --- a/Analysis/Tutorials/src/fullTrackIteration.cxx +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" - -#include <TFile.h> -#include <TH1F.h> - -using namespace o2; -using namespace o2::framework; - -// Another example -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - void init(InitContext&) - { - count = 0; - } - - void process(soa::Join<aod::Tracks, aod::TracksExtra> const& fullTracks) - { - for (auto& track : fullTracks) { - LOGF(info, "%d, %f %f", count, track.alpha(), track.tpcSignal()); - count++; - } - } - - size_t count = 2016927; -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("track-iteration-tutorial")}; -} diff --git a/Analysis/Tutorials/src/histHelpersTest.cxx b/Analysis/Tutorials/src/histHelpersTest.cxx deleted file mode 100644 index 8037582e52ccc..0000000000000 --- a/Analysis/Tutorials/src/histHelpersTest.cxx +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/AnalysisTask.h" -#include "Analysis/HistHelpers.h" - -#include "Framework/AnalysisDataModel.h" -#include "Framework/runDataProcessing.h" -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::experimental::histhelpers; - -struct HistHelpersTest { - - // some unique names for the histograms - enum HistNamesTest : uint8_t { - test_1d_TH1D, - test_2d_TH2F, - test_3d_TH3I, - test_1d_TH1D_Weight, - test_2d_TH2F_VarBinningY, - - test_3d_THnI, - test_5d_THnSparseI, - - test_1d_TProfile, - test_1d_TProfile_Weight, - test_2d_TProfile2D, - test_3d_TProfile3D, - - test_7d_THnF_first, - test_7d_THnF_second, - test_8d_THnC_third, - }; - enum HistNamesKine : uint8_t { - pt, - eta, - phi, - }; - enum HistNamesTPC : uint8_t { - tpcNClsFound, - tpcNClsCrossedRows, - tpcChi2NCl, - }; - enum HistNamesITS : uint8_t { - itsChi2NCl, - }; - - OutputObj<HistArray> test{HistArray("Test"), OutputObjHandlingPolicy::QAObject}; - OutputObj<HistArray> kine{HistArray("Kine"), OutputObjHandlingPolicy::QAObject}; - OutputObj<HistFolder> tpc{HistFolder("TPC"), OutputObjHandlingPolicy::QAObject}; - OutputObj<HistList> its{HistList("ITS"), OutputObjHandlingPolicy::QAObject}; - - OutputObj<THnF> standaloneHist{"standaloneHist", OutputObjHandlingPolicy::QAObject}; - - void init(o2::framework::InitContext&) - { - // add some plain and simple histograms - test->Add<test_1d_TH1D>(new TH1D("test_1d_TH1D", ";x", 100, 0., 50.)); - test->Add<test_2d_TH2F>(new TH2F("test_2d_TH2F", ";x;y", 100, -0.5, 0.5, 100, -0.5, 0.5)); - test->Add<test_3d_TH3I>(new TH3I("test_3d_TH3I", ";x;y;z", 100, 0., 20., 100, 0., 20., 100, 0., 20.)); - - // alternatively use Hist to generate the histogram and add it to container afterwards - Hist sameAsBefore; - sameAsBefore.AddAxis("x", "x", 100, 0., 50.); - // via Hist::Create() we can generate the actual root histogram with the requested axes - // Parameters: the name and optionally the decision wether to call SumW2 in case we want to fill this histogram with weights - test->Add<test_1d_TH1D_Weight>(sameAsBefore.Create<TH1D>("test_1d_TH1D_Weight", true)); - - // this helper enables us to have combinations of flexible + fixed binning in 2d or 3d histograms - // (which are not available via default root constructors) - Hist sameButDifferent; - sameButDifferent.AddAxis("x", "x", 100, -0.5, 0.5); - sameButDifferent.AddAxis("y", "y", {-0.5, -0.48, -0.3, 0.4, 0.5}); // use variable binning for y axsis this time - test->Add<test_2d_TH2F_VarBinningY>(sameButDifferent.Create<TH2F>("test_2d_TH2F_VarBinningY")); - - // also for n dimensional histograms things become much simpler: - std::vector<double> ptBins = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, - 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}; - std::vector<double> centBins = {0., 30., 60., 90.}; - - // varaiable binning - Axis ptAxis = {"pt", "#it{p}_{T} (GeV/c)", ptBins}; - Axis centAxis = {"cent", "centrality", centBins}; - // equidistant binning - Axis etaAxis = {"eta", "#eta", {-0.8, 0.8}, 5}; - Axis phiAxis = {"phi", "#phi", {0., 2. * M_PI}, 4}; // 36 to see tpc sectors - const int nCuts = 5; - Axis cutAxis = {"cut", "cut setting", {-0.5, nCuts - 0.5}, nCuts}; - - Hist myHistogram({ptAxis, etaAxis, {"signed1Pt", "q/p_{T}", {-8, 8}, 200}}); - test->Add<test_3d_THnI>(myHistogram.Create<THnI>("test_3d_THnI")); - - Hist testSparseHist({ptAxis, etaAxis, phiAxis, centAxis, cutAxis}); - test->Add<test_5d_THnSparseI>(testSparseHist.Create<THnSparseI>("test_5d_THnSparseI")); - - Hist testProfile({ptAxis}); - test->Add<test_1d_TProfile>(testProfile.Create<TProfile>("test_1d_TProfile")); - test->Get<TProfile>(test_1d_TProfile)->GetYaxis()->SetTitle("eta profile"); - - // now add same histogram but intended for weighted filling - test->Add<test_1d_TProfile_Weight>(testProfile.Create<TProfile>("test_1d_TProfile_Weight", true)); - - Hist testProfile2d; - testProfile2d.AddAxis(ptAxis); - testProfile2d.AddAxis(etaAxis); - test->Add<test_2d_TProfile2D>(testProfile2d.Create<TProfile2D>("test_2d_TProfile2D")); - - Hist testProfile3d; - testProfile3d.AddAxis(ptAxis); - testProfile3d.AddAxis(etaAxis); - testProfile3d.AddAxis(phiAxis); - test->Add<test_3d_TProfile3D>(testProfile3d.Create<TProfile3D>("test_3d_TProfile3D")); - - // we can also re-use axis definitions in case they are similar in many histograms: - Hist baseDimensions({ptAxis, etaAxis, phiAxis, centAxis, cutAxis, centAxis}); - - Hist firstHist{baseDimensions}; - firstHist.AddAxis("something", "v (m/s)", 10, -1, 1); - test->Add<test_7d_THnF_first>(firstHist.Create<THnF>("test_7d_THnF_first")); - - Hist secondHist{baseDimensions}; - secondHist.AddAxis("somethingElse", "a (m/(s*s))", 10, -1, 1); - test->Add<test_7d_THnF_second>(secondHist.Create<THnF>("test_7d_THnF_second")); - - // or if we want to have the baseDimensions somewhere in between: - Hist thirdHist; - thirdHist.AddAxis("myFirstDimension", "a (m/(s*s))", 10, -1, 1); - thirdHist.AddAxes(baseDimensions); - thirdHist.AddAxis("myLastDimension", "a (m/(s*s))", 10, -1, 1); - test->Add<test_8d_THnC_third>(thirdHist.Create<THnC>("test_8d_THnC_third")); - - // we can also use the Hist helper tool independent of the HistCollections: - Hist myHist; - myHist.AddAxis(ptAxis); - myHist.AddAxis(etaAxis); - myHist.AddAxis(phiAxis); - standaloneHist.setObject(myHist.Create<THnF>("standaloneHist")); - - // now add some more useful histograms - kine->Add<pt>(new TH1F("pt", "p_{T};p_{T} [GeV/c]", 100, 0., 5.)); - kine->Add<eta>(new TH1F("eta", "#eta;#eta", 101, -1.0, 1.0)); - kine->Add<phi>(new TH1F("phi", "#phi;#phi [rad]", 100, 0., 2 * M_PI)); - - tpc->Add<tpcNClsFound>(new TH1F("tpcNClsFound", "number of found TPC clusters;# clusters TPC", 165, -0.5, 164.5)); - tpc->Add<tpcNClsCrossedRows>(new TH1F("tpcNClsCrossedRows", "number of crossed TPC rows;# crossed rows TPC", 165, -0.5, 164.5)); - tpc->Add<tpcChi2NCl>(new TH1F("tpcChi2NCl", "chi2 per cluster in TPC;chi2 / cluster TPC", 100, 0, 10)); - - its->Add<itsChi2NCl>(new TH1F("itsChi2NCl", "chi2 per ITS cluster;chi2 / cluster ITS", 100, 0, 40)); - } - - void process(soa::Join<aod::Tracks, aod::TracksExtra>::iterator const& track) - { - test->Fill<test_1d_TH1D>(20.); - test->Fill<test_2d_TH2F>(0.1, 0.3); - test->Fill<test_3d_TH3I>(10, 10, 15.5); - - // this time fill the 1d histogram with weight of 10: - test->FillWeight<test_1d_TH1D_Weight>(20., 10.); - - test->Fill<test_2d_TH2F_VarBinningY>(0.1, 0.3); - - test->Fill<test_3d_THnI>(1., 0., 1.5); - test->Fill<test_5d_THnSparseI>(1., 0., 1.5, 30, 1); - - // we can also directly access to the underlying histogram - // for this the correct type has to be known (TH1, TH2, TH3, THn, THnSparse, TProfile, TProfile2D or TProfile3D) - test->Get<TH2>(test_2d_TH2F)->Fill(0.2, 0.2); - - test->Fill<test_1d_TProfile>(track.pt(), track.eta()); - // now fill same histogram, but with random weight - test->FillWeight<test_1d_TProfile_Weight>(track.pt(), track.eta(), std::rand()); - test->Fill<test_2d_TProfile2D>(track.pt(), track.eta(), track.phi()); - test->Fill<test_3d_TProfile3D>(track.pt(), track.eta(), track.phi(), track.tpcNClsFound()); - - kine->Fill<pt>(track.pt()); - kine->Fill<eta>(track.eta()); - kine->Fill<phi>(track.phi()); - - tpc->Fill<tpcNClsFound>(track.tpcNClsFound()); - tpc->Fill<tpcNClsCrossedRows>(track.tpcNClsCrossedRows()); - tpc->Fill<tpcChi2NCl>(track.tpcChi2NCl()); - - its->Fill<itsChi2NCl>(track.itsChi2NCl()); - - double dummyArray[] = {track.pt(), track.eta(), track.phi()}; - standaloneHist->Fill(dummyArray); - } -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HistHelpersTest>("hist-helpers-test")}; -} diff --git a/Analysis/Tutorials/src/histogramRegistry.cxx b/Analysis/Tutorials/src/histogramRegistry.cxx deleted file mode 100644 index fdecd0a8596c3..0000000000000 --- a/Analysis/Tutorials/src/histogramRegistry.cxx +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include <TH1F.h> - -#include <cmath> - -using namespace o2; -using namespace o2::framework; - -// This is a very simple example showing how to create an histogram -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - /// Construct a registry object with direct declaration - HistogramRegistry registry{ - "registry", - { - {"eta", "#eta", {HistType::kTH1F, {{102, -2.01, 2.01}}}}, // - {"phi", "#varphi", {HistType::kTH1F, {{100, 0., 2. * M_PI}}}} // - } // - }; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - registry.get<TH1>("eta")->Fill(track.eta()); - registry.get<TH1>("phi")->Fill(track.phi()); - } - } -}; - -struct BTask { - /// Construct a registry object with direct declaration - HistogramRegistry registry{ - "registry", - { - {"eta", "#eta", {HistType::kTH1F, {{102, -2.01, 2.01}}}}, // - {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // - } // - }; - - void process(aod::Tracks const& tracks) - { - registry.fill<aod::track::Eta>("eta", tracks, aod::track::eta > 0.0f); - registry.fill<aod::track::Pt, aod::track::Pt>("ptToPt", tracks, aod::track::pt < 5.0f); - } -}; - -struct CTask { - - HistogramRegistry registry{ - "registry", - { - {"1d", "test 1d", {HistType::kTH1I, {{100, -10.0f, 10.0f}}}}, // - {"2d", "test 2d", {HistType::kTH2F, {{100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}}}, // - {"3d", "test 3d", {HistType::kTH3D, {{100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}}}, // - {"4d", "test 4d", {HistType::kTHnC, {{100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}}}, // - {"5d", "test 5d", {HistType::kTHnSparseL, {{10, -10.0f, 10.01f}, {10, -10.0f, 10.01f}, {10, -10.0f, 10.01f}, {10, -10.0f, 10.01f}, {10, -10.0f, 10.01f}}}}, // - }, - OutputObjHandlingPolicy::AnalysisObject, - true // - }; - - void init(o2::framework::InitContext&) - { - registry.add("7d", "test 7d", {HistType::kTHnC, {{3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}}}); - - registry.add("6d", "test 6d", {HistType::kTHnC, {{3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}, {3, -10.0f, 10.01f}}}); - - registry.add("1d-profile", "test 1d profile", {HistType::kTProfile, {{20, 0.0f, 10.01f}}}); - registry.add("2d-profile", "test 2d profile", {HistType::kTProfile2D, {{20, 0.0f, 10.01f}, {20, 0.0f, 10.01f}}}); - registry.add("3d-profile", "test 3d profile", {HistType::kTProfile3D, {{20, 0.0f, 10.01f}, {20, 0.0f, 10.01f}, {20, 0.0f, 10.01f}}}); - - registry.add("2d-weight", "test 2d weight", {HistType::kTH2C, {{2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}}}, true); - - registry.add("3d-weight", "test 3d weight", {HistType::kTH3C, {{2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}}}, true); - - registry.add("4d-weight", "test 4d weight", {HistType::kTHnC, {{2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}}, true); - - registry.add("1d-profile-weight", "test 1d profile weight", {HistType::kTProfile, {{2, -10.0f, 10.01f}}}, true); - registry.add("2d-profile-weight", "test 2d profile weight", {HistType::kTProfile2D, {{2, -10.0f, 10.01f}, {2, -10.0f, 10.01f}}}, true); - } - - void process(aod::Tracks const& tracks) - { - using namespace aod::track; - // does not work with dynamic columns (e.g. Charge, NormalizedPhi) - registry.fill<Eta>("1d", tracks, eta > -0.7f); - registry.fill<Pt, Eta, RawPhi>("3d", tracks, eta > 0.f); - registry.fill<Pt, Eta, RawPhi, P, X>("5d", tracks, pt > 0.15f); - registry.fill<Pt, Eta, RawPhi, P, X, Y, Z>("7d", tracks, pt > 0.15f); - registry.fill<Pt, Eta, RawPhi>("2d-profile", tracks, eta > -0.5f); - - // fill 4d histogram with weight (column X) - registry.fill<Pt, Eta, RawPhi, Z, X>("4d-weight", tracks, eta > 0.f); - - registry.fill<Pt, Eta, RawPhi>("2d-weight", tracks, eta > 0.f); - - registry.fill<Pt, Eta, RawPhi>("1d-profile-weight", tracks, eta > 0.f); - - for (auto& track : tracks) { - registry.fill("2d", track.eta(), track.pt()); - registry.fill("4d", track.pt(), track.eta(), track.phi(), track.signed1Pt()); - registry.fill("6d", track.pt(), track.eta(), track.phi(), track.snp(), track.tgl(), track.alpha()); - registry.fill("1d-profile", track.pt(), track.eta()); - registry.fill("3d-profile", track.pt(), track.eta(), track.phi(), track.snp()); - - // fill 3d histogram with weight (2.) - registry.fill("3d-weight", track.pt(), track.eta(), track.phi(), 2.); - - registry.fill("2d-profile-weight", track.pt(), track.eta(), track.phi(), 5.); - } - } -}; - -struct DTask { - HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry etaStudy{"etaStudy", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - void init(o2::framework::InitContext&) - { - std::vector<double> ptBinning = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, - 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}; - std::vector<double> centBinning = {0., 30., 60., 90.}; - - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/c)"}; - AxisSpec centAxis = {centBinning, "centrality"}; - AxisSpec etaAxis = {5, -0.8, 0.8, "#eta"}; - AxisSpec phiAxis = {4, 0., 2. * M_PI, "#phi"}; - const int nCuts = 5; - AxisSpec cutAxis = {nCuts, -0.5, nCuts - 0.5, "cut setting"}; - - HistogramConfigSpec defaultParticleHist({HistType::kTHnF, {ptAxis, etaAxis, centAxis, cutAxis}}); - - spectra.add("myControlHist", "a", kTH2F, {ptAxis, etaAxis}); - spectra.get<TH2>("myControlHist")->GetYaxis()->SetTitle("my-y-axis"); - spectra.get<TH2>("myControlHist")->SetTitle("something meaningful"); - - spectra.add("charged/pions", "Pions", defaultParticleHist); - spectra.add("neutral/pions", "Pions", defaultParticleHist); - spectra.add("one/two/three/four/kaons", "Kaons", defaultParticleHist); - spectra.add("sigmas", "Sigmas", defaultParticleHist); - spectra.add("lambdas", "Lambd", defaultParticleHist); - - spectra.get<THn>("lambdas")->SetTitle("Lambdas"); - - etaStudy.add("positive", "A side spectra", kTH1I, {ptAxis}); - etaStudy.add("negative", "C side spectra", kTH1I, {ptAxis}); - - spectra.add("before_cuts/hist1", "asdf", defaultParticleHist); - spectra.add("before_cuts/hist2", "asdf", defaultParticleHist); - spectra.add("before_cuts/hist3", "asdf", defaultParticleHist); - spectra.add("before_cuts/hist4", "asdf", defaultParticleHist); - spectra.add("before_cuts/hist5", "asdf", defaultParticleHist); - - // clone whole category / group - spectra.addClone("before_cuts/", "after_cuts/"); - - // clone single histograms - spectra.addClone("sigmas", "cascades"); - spectra.addClone("neutral/pions", "strange/funny/particles"); - } - - void process(aod::Tracks const& tracks) - { - using namespace aod::track; - - etaStudy.fill<Pt>("positive", tracks, eta > 0.f); - etaStudy.fill<Pt>("negative", tracks, eta < 0.f); - - for (auto& track : tracks) { - spectra.fill("myControlHist", track.pt(), track.eta()); - spectra.fill("charged/pions", track.pt(), track.eta(), 50., 0.); - spectra.fill("charged/pions", track.pt(), track.eta(), 50., 0.); - spectra.fill("neutral/pions", track.pt(), track.eta(), 50., 0.); - spectra.fill("one/two/three/four/kaons", track.pt(), track.eta(), 50., 0.); - spectra.fill("sigmas", track.pt(), track.eta(), 50., 0.); - spectra.fill("lambdas", track.pt(), track.eta(), 50., 0.); - - spectra.fill("before_cuts/hist2", track.pt(), track.eta(), 50., 0.); - spectra.fill("before_cuts/hist2", track.pt(), track.eta(), 50., 0.); - - spectra.fill("after_cuts/hist2", track.pt(), track.eta(), 50., 0.); - - spectra.fill("cascades", track.pt(), track.eta(), 50., 0.); - spectra.fill("strange/funny/particles", track.pt(), track.eta(), 50., 0.); - } - } -}; - -struct ETask { - OutputObj<TH1F> phiH{TH1F("phi", "phi", 100, 0., 2. * M_PI)}; - OutputObj<TH1F> etaH{TH1F("eta", "eta", 102, -2.01, 2.01)}; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - phiH->Fill(track.phi()); - etaH->Fill(track.eta()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ETask>("output-obj-test"), - adaptAnalysisTask<ATask>("eta-and-phi-histograms"), - adaptAnalysisTask<BTask>("filtered-histograms"), - adaptAnalysisTask<CTask>("dimension-test"), - adaptAnalysisTask<DTask>("realistic-example")}; -} diff --git a/Analysis/Tutorials/src/histogramTrackSelection.cxx b/Analysis/Tutorials/src/histogramTrackSelection.cxx deleted file mode 100644 index ff9430ac962b0..0000000000000 --- a/Analysis/Tutorials/src/histogramTrackSelection.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include <TH1F.h> - -#include <cmath> - -#include "Analysis/TrackSelection.h" -#include "Analysis/TrackSelectionTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -//-------------------------------------------------------------------- -// Task generating pT spectrum of charged particles -//-------------------------------------------------------------------- -struct HistogramTrackSelection { - - Configurable<int> selectedTracks{"select", 1, "Choice of track selection. 0 = no selection, 1 = globalTracks, 2 = globalTracksSDD"}; - - OutputObj<TH1F> pt{TH1F("pt", "pt", 100, 0., 50.)}; - - void init(o2::framework::InitContext&) {} - - void process(aod::Collision const& collision, - soa::Join<aod::Tracks, aod::TrackSelection> const& tracks) - { - for (auto& track : tracks) { - - if (selectedTracks == 1 && !track.isGlobalTrack()) { - continue; - } else if (selectedTracks == 2 && !track.isGlobalTrackSDD()) { - continue; - } - - pt->Fill(track.pt()); - } - } -}; - -//-------------------------------------------------------------------- -// Workflow definition -//-------------------------------------------------------------------- -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<HistogramTrackSelection>("histogram-track-selection")}; -} diff --git a/Analysis/Tutorials/src/histograms.cxx b/Analysis/Tutorials/src/histograms.cxx deleted file mode 100644 index 4b8bf0bac23a5..0000000000000 --- a/Analysis/Tutorials/src/histograms.cxx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <TH1F.h> - -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This is a very simple example showing how to create an histogram -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - OutputObj<TH1F> phiH{TH1F("phi", "phi", 100, 0., 2. * M_PI)}; - OutputObj<TH1F> etaH{TH1F("eta", "eta", 102, -2.01, 2.01)}; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - phiH->Fill(track.phi()); - etaH->Fill(track.eta()); - } - } -}; - -struct BTask { - OutputObj<TH2F> etaphiH{TH2F("etaphi", "etaphi", 100, 0., 2. * M_PI, 102, -2.01, 2.01)}; - // Create a configurable which can be used inside the process method. - Configurable<float> phiCut{"phiCut", 6.29f, "A cut on phi"}; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - // FIXME: this is until we have configurables which - // can be used in expressions. - if (track.phi() < phiCut) { - etaphiH->Fill(track.phi(), track.eta()); - } - } - } -}; - -struct CTask { - // needs to be initialized with a label or an obj - // when adding an object to OutputObj later, the object name will be - // *reset* to OutputObj label - needed for correct placement in the output file - OutputObj<TH1F> ptH{TH1F("pt", "pt", 100, -0.01, 10.01)}; - OutputObj<TH1F> trZ{"trZ", OutputObjHandlingPolicy::QAObject}; - Configurable<float> pTCut{"pTCut", 0.5f, "Lower pT limit"}; - - Filter ptfilter = aod::track::pt > pTCut; - - void init(InitContext const&) - { - trZ.setObject(new TH1F("Z", "Z", 100, -10., 10.)); - // other options: - // TH1F* t = new TH1F(); trZ.setObject(t); <- resets content! - // TH1F t(); trZ.setObject(t) <- makes a copy - // trZ.setObject({"Z","Z",100,-10.,10.}); <- creates new - } - - void process(soa::Filtered<aod::Tracks> const& tracks) - { - for (auto& track : tracks) { - ptH->Fill(track.pt()); - trZ->Fill(track.z()); - } - } -}; - -struct DTask { - OutputObj<TList> list{"list"}; - - void init(InitContext const&) - { - list.setObject(new TList); - list->Add(new TH1F("pHist", "", 100, 0, 10)); - list->Add(new TH1F("etaHist", "", 102, -2.01, 2.01)); - } - - void process(aod::Track const& track) - { - auto pHist = dynamic_cast<TH1F*>(list->At(0)); - auto etaHist = dynamic_cast<TH1F*>(list->At(1)); - - pHist->Fill(track.p()); - etaHist->Fill(track.eta()); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("eta-and-phi-histograms"), - adaptAnalysisTask<BTask>("etaphi-histogram"), - adaptAnalysisTask<CTask>("pt-histogram"), - adaptAnalysisTask<DTask>("output-wrapper"), - }; -} diff --git a/Analysis/Tutorials/src/histogramsFullTracks.cxx b/Analysis/Tutorials/src/histogramsFullTracks.cxx deleted file mode 100644 index 3dab7398facdf..0000000000000 --- a/Analysis/Tutorials/src/histogramsFullTracks.cxx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <TH2F.h> - -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct ATask { - OutputObj<TH2F> etaClsH{TH2F("eta_vs_cls", "eta_vs_cls", 102, -2.01, 2.01, 160, -0.5, 159.5)}; - - void process(aod::FullTracks const& tracks) - { - for (auto& track : tracks) { - etaClsH->Fill(track.eta(), track.tpcNClsFindable()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("eta-and-cls-histograms"), - }; -} diff --git a/Analysis/Tutorials/src/jetAnalysis.cxx b/Analysis/Tutorials/src/jetAnalysis.cxx deleted file mode 100644 index bc42f586fa14b..0000000000000 --- a/Analysis/Tutorials/src/jetAnalysis.cxx +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// jet analysis tasks (subscribing to jet finder task) -// -// Author: Jochen Klein -// -// o2-analysis-jetfinder --aod-file <aod> -b | o2-analysistutorial-jet-analysis -b - -#include "TH1F.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "Analysis/Jet.h" - -using namespace o2; -using namespace o2::framework; - -struct JetAnalysis { - OutputObj<TH1F> hJetPt{"jetPt"}; - OutputObj<TH1F> hConstPt{"constPt"}; - - void init(InitContext const&) - { - hJetPt.setObject(new TH1F("jetPt", "jet p_{T};p_{T} (GeV/#it{c})", - 100, 0., 100.)); - hConstPt.setObject(new TH1F("constPt", "constituent p_{T};p_{T} (GeV/#it{c})", - 100, 0., 100.)); - } - - void process(aod::Jet const& jet, - aod::JetConstituents const& constituents, aod::Tracks const& tracks) - { - hJetPt->Fill(jet.pt()); - for (const auto c : constituents) { - LOGF(DEBUG, "jet %d: track id %d, track pt %g", jet.index(), c.trackId(), c.track().pt()); - hConstPt->Fill(c.track().pt()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<JetAnalysis>("jet-analysis")}; -} diff --git a/Analysis/Tutorials/src/mcHistograms.cxx b/Analysis/Tutorials/src/mcHistograms.cxx deleted file mode 100644 index 0f5521a9739ae..0000000000000 --- a/Analysis/Tutorials/src/mcHistograms.cxx +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Analysis/MC.h" - -#include <TH1F.h> -#include <cmath> - -using namespace o2; -using namespace o2::framework; - -// Simple access to collision -struct ATask { - OutputObj<TH1F> vertex{TH1F("vertex", "vertex", 100, -10, 10)}; - - void process(aod::McCollision const& mcCollision) - { - LOGF(info, "MC. vtx-z = %f", mcCollision.posZ()); - vertex->Fill(mcCollision.posZ()); - } -}; - -// Grouping between MC particles and collisions -struct BTask { - OutputObj<TH1F> phiH{TH1F("phi", "phi", 100, 0., 2. * M_PI)}; - OutputObj<TH1F> etaH{TH1F("eta", "eta", 102, -2.01, 2.01)}; - - // void process(aod::McCollision const& mcCollision, aod::McParticles& mcParticles) - void process(aod::McParticles& mcParticles) - { - //LOGF(info, "MC. vtx-z = %f", mcCollision.posZ()); - LOGF(info, "First: %d | Length: %d", mcParticles.begin().index(), mcParticles.size()); - LOGF(info, "Particles mother: %d", (mcParticles.begin() + 1000).mother0()); - for (auto& mcParticle : mcParticles) { - if (MC::isPhysicalPrimary(mcParticles, mcParticle)) { - phiH->Fill(mcParticle.phi()); - etaH->Fill(mcParticle.eta()); - } - } - } -}; - -// Access from tracks to MC particle -struct CTask { - OutputObj<TH1F> etaDiff{TH1F("etaDiff", ";eta_{MC} - eta_{Rec}", 100, -2, 2)}; - OutputObj<TH1F> phiDiff{TH1F("phiDiff", ";phi_{MC} - phi_{Rec}", 100, -M_PI, M_PI)}; - - void process(soa::Join<aod::Collisions, aod::McCollisionLabels>::iterator const& collision, soa::Join<aod::Tracks, aod::McTrackLabels> const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcCollisions) - { - LOGF(info, "vtx-z (data) = %f | vtx-z (MC) = %f", collision.posZ(), collision.label().posZ()); - for (auto& track : tracks) { - //if (track.trackType() != 0) - // continue; - //if (track.labelMask() != 0) - // continue; - etaDiff->Fill(track.label().eta() - track.eta()); - auto delta = track.label().phi() - track.phi(); - if (delta > M_PI) { - delta -= 2 * M_PI; - } - if (delta < -M_PI) { - delta += 2 * M_PI; - } - phiDiff->Fill(delta); - //LOGF(info, "eta: %.2f %.2f \t phi: %.2f %.2f | %d", track.label().eta(), track.eta(), track.label().phi(), track.phi(), track.label().index()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("vertex-histogram"), - adaptAnalysisTask<BTask>("etaphi-histogram"), - adaptAnalysisTask<CTask>("eta-resolution-histogram"), - }; -} diff --git a/Analysis/Tutorials/src/muonIteration.cxx b/Analysis/Tutorials/src/muonIteration.cxx deleted file mode 100644 index 509fdb88b6ea4..0000000000000 --- a/Analysis/Tutorials/src/muonIteration.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This task shows how to access the Muons belong to a collision -// The association is made through the BC column (and in Run 3 may not be unique!) -// To run this workflow, the o2-analysis-run(2,3)-matcher has to be run as well. -// Example: o2-analysis-run2-matcher --aod-file AO2D.root | o2-analysistutorial-muon-iteration -// -// Note that one has to subscribe to aod::Collisions const& to load -// the relevant data even if you access the data itself through m.collision() -// This uses the exclusive matcher, so you only get BCs which have a collision -// If you want also BCs without collision, see the example IterateMuonsSparse below -struct IterateMuons { - void process(aod::BCCollisionsExclusive::iterator const& m, aod::Collisions const&, aod::Muons const& muons) - { - LOGF(INFO, "Vertex = %f has %d muons", m.collision().posZ(), muons.size()); - for (auto& muon : muons) { - LOGF(info, " pT = %.2f", muon.pt()); - } - } -}; - -// This uses the sparase matcher, so you also get BCs without a collision. -// You need to check with m.has_collision() -struct IterateMuonsSparse { - void process(aod::BCCollisionsSparse::iterator const& m, aod::Collisions const&, aod::Muons const& muons) - { - if (m.has_collision()) { - LOGF(INFO, "Vertex = %f has %d muons", m.collision().posZ(), muons.size()); - } else { - LOGF(INFO, "BC without collision has %d muons", muons.size()); - } - for (auto& muon : muons) { - LOGF(info, " pT = %.2f", muon.pt()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<IterateMuons>("iterate-muons"), - adaptAnalysisTask<IterateMuonsSparse>("iterate-muons-sparse"), - }; -} diff --git a/Analysis/Tutorials/src/newCollections.cxx b/Analysis/Tutorials/src/newCollections.cxx deleted file mode 100644 index 90d0fc684d94a..0000000000000 --- a/Analysis/Tutorials/src/newCollections.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2::aod -{ -namespace etaphi -{ -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -} // namespace etaphi -DECLARE_SOA_TABLE(EtaPhi, "AOD", "ETAPHI", - etaphi::Eta, etaphi::Phi); -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -// This is a very simple example showing how to iterate over tracks -// and create a new collection for them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - Produces<aod::EtaPhi> etaphi; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI); - float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl()))); - - etaphi(phi, eta); - } - } -}; - -struct BTask { - void process(aod::EtaPhi const& etaPhis) - { - for (auto& etaPhi : etaPhis) { - LOGF(INFO, "(%f, %f)", etaPhi.eta(), etaPhi.phi()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("produce-etaphi"), - adaptAnalysisTask<BTask>("consume-etaphi")}; -} diff --git a/Analysis/Tutorials/src/outputs.cxx b/Analysis/Tutorials/src/outputs.cxx deleted file mode 100644 index 6ea86ddd6b0df..0000000000000 --- a/Analysis/Tutorials/src/outputs.cxx +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// -// Task performing basic track selection -// - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include <TH1F.h> - -#include <cmath> - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct DummyTask { - OutputObj<TH1F> pt1{TH1F("pt1________0123456789", "pt task1", 100, 0., 50.)}; - OutputObj<TH1F> pt2{TH1F("pt2________0123456789", "pt task1", 100, 0., 50.)}; - OutputObj<TH1F> pt3{TH1F("pt3________0123456789", "pt task1", 100, 0., 50.)}; - - void process(aod::Track const& track) - { - auto pt = track.pt(); - pt1->Fill(pt); - pt2->Fill(pt); - pt3->Fill(pt); - } -}; - -struct DummyTask2 { - OutputObj<TH1F> pt1{TH1F("pt1________0123456789", "pt task2", 100, 0., 50.)}; - OutputObj<TH1F> pt2{TH1F("pt2________0123456789", "pt task2", 100, 0., 50.)}; - OutputObj<TH1F> pt3{TH1F("pt3________0123456789", "pt task2", 100, 0., 50.)}; - - void process(aod::Track const& track) - { - auto pt = track.pt(); - pt1->Fill(pt); - pt2->Fill(pt); - pt3->Fill(pt); - } -}; - -struct DummyTask3 { - OutputObj<TH1F> pt1{TH1F("pt1________0123456789", "pt task3", 100, 0., 50.)}; - OutputObj<TH1F> pt2{TH1F("pt2________0123456789", "pt task3", 100, 0., 50.)}; - OutputObj<TH1F> pt3{TH1F("pt3________0123456789", "pt task3", 100, 0., 50.)}; - void process(aod::Track const& track) - { - auto pt = track.pt(); - pt1->Fill(pt); - pt2->Fill(pt); - pt3->Fill(pt); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<DummyTask>("task1"), - adaptAnalysisTask<DummyTask2>("task2"), - adaptAnalysisTask<DummyTask3>("task3")}; -} diff --git a/Analysis/Tutorials/src/partitions.cxx b/Analysis/Tutorials/src/partitions.cxx deleted file mode 100644 index 6479356a48cfa..0000000000000 --- a/Analysis/Tutorials/src/partitions.cxx +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// This is a very simple example showing how to iterate over tracks -// and create a new collection for them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - float fPI = static_cast<float>(M_PI); - Configurable<float> ptlow{"pTlow", 0.5f, "Lowest pT"}; - Configurable<float> ptup{"pTup", 2.0f, "highest pT"}; - Filter ptFilter_a = aod::track::pt > ptlow; - Filter ptFilter_b = aod::track::pt < ptup; - - Configurable<float> etalow{"etaLow", -1.0f, "lowest eta"}; - Configurable<float> etaup{"etaUp", 1.0f, "highest eta"}; - Filter etafilter = (aod::track::eta < etaup) && (aod::track::eta > etalow); - - Configurable<float> philow{"phiLow", 1.0f, "lowest phi"}; - Configurable<float> phiup{"phiUp", 2.0f, "highest phi"}; - - using myTracks = soa::Filtered<aod::Tracks>; - - Partition<myTracks> leftPhi = aod::track::phiraw < philow; - Partition<myTracks> midPhi = aod::track::phiraw >= philow && aod::track::phiraw < phiup; - Partition<myTracks> rightPhi = aod::track::phiraw >= phiup; - - void process(aod::Collision const& collision, myTracks const& tracks) - { - LOGF(INFO, "Collision: %d [N = %d] [left phis = %d] [mid phis = %d] [right phis = %d]", - collision.globalIndex(), tracks.size(), leftPhi.size(), midPhi.size(), rightPhi.size()); - - for (auto& track : leftPhi) { - LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, track.phiraw(), (float)philow, (float)ptlow, track.pt(), (float)ptup); - } - for (auto& track : midPhi) { - LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f <= %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, (float)philow, track.phiraw(), (float)phiup, (float)ptlow, track.pt(), (float)ptup); - } - for (auto& track : rightPhi) { - LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, (float)phiup, track.phiraw(), (float)ptlow, track.pt(), (float)ptup); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("consume-tracks")}; -} diff --git a/Analysis/Tutorials/src/schemaEvolution.cxx b/Analysis/Tutorials/src/schemaEvolution.cxx deleted file mode 100644 index 8d126b86f34cb..0000000000000 --- a/Analysis/Tutorials/src/schemaEvolution.cxx +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -// This example shows how schema evolution of tables can be implemented -// Here two tables are defined, EtaPhiV2 has an additional member compared to EtaPhiV1 -// It is shown how an example task can use a template, and can be instantiated to work -// on both. - -namespace o2::aod -{ -namespace etaphi -{ -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(AbsEta, absEta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -} // namespace etaphi -DECLARE_SOA_TABLE(EtaPhiV1, "AOD", "ETAPHI", etaphi::Eta, etaphi::Phi); -DECLARE_SOA_TABLE(EtaPhiV2, "AOD", "ETAPHIV2", etaphi::Eta, etaphi::AbsEta, etaphi::Phi); -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; - -// Producer of EtaPhiV1 -struct ATask { - Produces<aod::EtaPhiV1> etaphi; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI); - float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl()))); - - etaphi(eta, phi); - } - } -}; - -// Producer of EtaPhiV2 -struct BTask { - Produces<aod::EtaPhiV2> etaphi; - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI); - float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl()))); - - etaphi(eta, std::abs(eta), phi); - } - } -}; - -// Consumper of both EtaPhiV1 and EtaPhiV2 -// InputTable is a template which is then specified below when the workflow is defined -template <typename InputTable> -struct CTask { - void process(InputTable const& etaPhis) - { - constexpr bool isV2 = std::is_same<InputTable, aod::EtaPhiV2>::value; - for (auto& etaPhi : etaPhis) { - LOGF(info, "(%f, %f)", etaPhi.eta(), etaPhi.phi()); - if constexpr (isV2) { - // This line is only compiled if this is templated with EtaPhiV2 - LOGF(info, "We have the new data model (%f)", etaPhi.absEta()); - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("produce-etaphi-v1"), - adaptAnalysisTask<BTask>("produce-etaphi-v2"), - adaptAnalysisTask<CTask<aod::EtaPhiV1>>("consume-etaphi-v1"), // here CTask is added with EtaPhiV1 input - adaptAnalysisTask<CTask<aod::EtaPhiV2>>("consume-etaphi-v2"), // here CTask is added with EtaPhiV2 input - }; -} diff --git a/Analysis/Tutorials/src/trackCollectionIteration.cxx b/Analysis/Tutorials/src/trackCollectionIteration.cxx deleted file mode 100644 index 887f1241faea3..0000000000000 --- a/Analysis/Tutorials/src/trackCollectionIteration.cxx +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" - -#include <TFile.h> -#include <TH1F.h> - -using namespace o2; -using namespace o2::framework; - -// This is a very simple example showing how to iterate over tracks -// and operate on them. -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - void process(aod::Tracks const& tracks) - { - // FIXME: to see some output, we create the histogram - // for every timeframe. In general this is not the way it - // should be done. - auto hPhi = new TH1F("phi", "Phi", 100, 0, 2 * M_PI); - auto hEta = new TH1F("eta", "Eta", 100, 0, 2 * M_PI); - for (auto& track : tracks) { - auto phi = asin(track.snp()) + track.alpha() + M_PI; - auto eta = log(tan(0.25 * M_PI - 0.5 * atan(track.tgl()))); - hPhi->Fill(phi); - hEta->Fill(eta); - } - TFile f("result1.root", "RECREATE"); - hPhi->SetName("Phi"); - hPhi->Write(); - hEta->SetName("Eta"); - hEta->Write(); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("track-collection-iteration-tutorial")}; -} diff --git a/Analysis/Tutorials/src/trackIteration.cxx b/Analysis/Tutorials/src/trackIteration.cxx deleted file mode 100644 index 12b5c363956d0..0000000000000 --- a/Analysis/Tutorials/src/trackIteration.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" - -#include <TFile.h> -#include <TH1F.h> - -using namespace o2; -using namespace o2::framework; - -// Another example -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - void init(InitContext&) - { - count = 0; - } - - void process(aod::Track const& track) - { - LOGF(info, "%d, %f", count, track.alpha()); - count++; - } - - size_t count = 2016927; -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("track-iteration-tutorial")}; -} diff --git a/Analysis/Tutorials/src/tracksCombinations.cxx b/Analysis/Tutorials/src/tracksCombinations.cxx deleted file mode 100644 index 43229c7923334..0000000000000 --- a/Analysis/Tutorials/src/tracksCombinations.cxx +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" - -namespace o2::aod -{ -namespace hash -{ -DECLARE_SOA_COLUMN(Bin, bin, int); -} // namespace hash -DECLARE_SOA_TABLE(Hashes, "AOD", "HASH", hash::Bin); - -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; - -// This is a very simple example showing how to iterate over -// tuples of tracks -// FIXME: this should really inherit from AnalysisTask but -// we need GCC 7.4+ for that -struct ATask { - void process(aod::Tracks const& tracks) - { - // Strictly upper tracks - for (auto& [t0, t1] : combinations(tracks, tracks)) { - LOGF(info, "Tracks pair: %d %d", t0.index(), t1.index()); - } - } -}; - -struct HashTask { - std::vector<float> xBins{-1.5f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 1.5f}; - std::vector<float> yBins{-1.5f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 1.5f}; - Produces<aod::Hashes> hashes; - - // Calculate hash for an element based on 2 properties and their bins. - int getHash(const std::vector<float>& xBins, const std::vector<float>& yBins, float colX, float colY) - { - for (int i = 0; i < xBins.size(); i++) { - if (colX < xBins[i]) { - for (int j = 0; j < yBins.size(); j++) { - if (colY < yBins[j]) { - return i + j * (xBins.size() + 1); - } - } - // overflow for yBins only - return i + yBins.size() * (xBins.size() + 1); - } - } - - // overflow for xBins only - for (int j = 0; j < yBins.size(); j++) { - if (colY < yBins[j]) { - return xBins.size() + j * (xBins.size() + 1); - } - } - - // overflow for both bins - return (yBins.size() + 1) * (xBins.size() + 1) - 1; - } - - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - int hash = getHash(xBins, yBins, track.x(), track.y()); - LOGF(info, "Track: %d (%f, %f, %f) hash: %d", track.index(), track.x(), track.y(), track.z(), hash); - hashes(hash); - } - } -}; - -struct BTask { - void process(soa::Join<aod::Hashes, aod::Tracks> const& hashedTracks) - { - // Strictly upper categorised tracks - for (auto& [t0, t1] : selfCombinations("fBin", 5, -1, hashedTracks, hashedTracks)) { - LOGF(info, "Tracks bin: %d pair: %d (%f, %f, %f), %d (%f, %f, %f)", t0.bin(), t0.index(), t0.x(), t0.y(), t0.z(), t1.index(), t1.x(), t1.y(), t1.z()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<ATask>("tracks-pairs"), - adaptAnalysisTask<HashTask>("tracks-hashed"), - adaptAnalysisTask<BTask>("tracks-pairs-categorised")}; -} diff --git a/Analysis/Tutorials/src/weakDecayIteration.cxx b/Analysis/Tutorials/src/weakDecayIteration.cxx deleted file mode 100644 index ad350d7407c80..0000000000000 --- a/Analysis/Tutorials/src/weakDecayIteration.cxx +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -// Example how to enumerate V0s and cascades -// Needs weak-decay-indices in the workflow -// Example usage: o2-analysis-weak-decay-indices --aod-file AO2D.root | o2-analysistutorial-weak-decay-iteration - -using namespace o2; -using namespace o2::framework; - -struct BTask { - void process(aod::V0s const& v0s, aod::FullTracks const& tracks) - { - for (auto& v0 : v0s) { - LOGF(DEBUG, "V0 (%d, %d, %d)", v0.posTrack().collisionId(), v0.negTrack().collisionId(), v0.collisionId()); - } - } -}; - -struct CTask { - void process(aod::Cascades const& cascades, aod::V0s const& v0s, aod::FullTracks const& tracks) - { - for (auto& cascade : cascades) { - LOGF(DEBUG, "Cascade %d (%d, %d, %d, %d)", cascade.globalIndex(), cascade.bachelor().collisionId(), cascade.v0().posTrack().collisionId(), cascade.v0().negTrack().collisionId(), cascade.collisionId()); - } - } -}; - -// Grouping V0s -struct DTask { - void process(aod::Collision const& collision, aod::V0s const& v0s, aod::FullTracks const& tracks) - { - LOGF(INFO, "Collision %d has %d V0s", collision.globalIndex(), v0s.size()); - - for (auto& v0 : v0s) { - LOGF(DEBUG, "Collision %d V0 %d (%d, %d)", collision.globalIndex(), v0.globalIndex(), v0.posTrackId(), v0.negTrackId()); - } - } -}; - -// Grouping V0s and cascades -// NOTE that you need to subscribe to V0s even if you only process cascades -struct ETask { - void process(aod::Collision const& collision, aod::V0s const& v0s, aod::Cascades const& cascades, aod::FullTracks const& tracks) - { - LOGF(INFO, "Collision %d has %d cascades (%d tracks)", collision.globalIndex(), cascades.size(), tracks.size()); - - for (auto& cascade : cascades) { - LOGF(INFO, "Collision %d Cascade %d (%d, %d, %d)", collision.globalIndex(), cascade.globalIndex(), cascade.v0().posTrackId(), cascade.v0().negTrackId(), cascade.bachelorId()); - LOGF(INFO, " IDs: %d %d %d", cascade.v0().posTrack().collisionId(), cascade.v0().negTrack().collisionId(), cascade.bachelor().collisionId()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - adaptAnalysisTask<BTask>("consume-v0s"), - adaptAnalysisTask<CTask>("consume-cascades"), - adaptAnalysisTask<DTask>("consume-grouped-v0s"), - adaptAnalysisTask<ETask>("consume-grouped-cascades"), - }; -} diff --git a/CCDB/CMakeLists.txt b/CCDB/CMakeLists.txt index a91a3aa31347e..318ebe2d986d4 100644 --- a/CCDB/CMakeLists.txt +++ b/CCDB/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CCDB SOURCES src/CcdbApi.cxx @@ -18,6 +19,7 @@ o2_add_library(CCDB ROOT::Hist O2::CommonUtils FairMQ::FairMQ + libjalien::libjalienO2 TARGETVARNAME targetName) o2_target_root_dictionary(CCDB @@ -51,6 +53,13 @@ o2_add_test(CcdbApi PUBLIC_LINK_LIBRARIES O2::CCDB LABELS ccdb) +o2_add_test(CcdbApiConfigParam + SOURCES test/testCcdbApi_ConfigParam.cxx + COMPONENT_NAME ccdb + PUBLIC_LINK_LIBRARIES O2::CCDB O2::DetectorsVertexing + LABELS ccdb) + + o2_add_test(CcdbApi-Alien SOURCES test/testCcdbApi_alien.cxx COMPONENT_NAME ccdb diff --git a/CCDB/include/CCDB/BasicCCDBManager.h b/CCDB/include/CCDB/BasicCCDBManager.h index 2a6a85b840981..f870100bd7320 100644 --- a/CCDB/include/CCDB/BasicCCDBManager.h +++ b/CCDB/include/CCDB/BasicCCDBManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,9 +27,17 @@ namespace o2::ccdb { -/// A simple (singleton) class offering simplified access to CCDB (mainly for MC simulation) +/// A simple class offering simplified access to CCDB (mainly for MC simulation) /// The class encapsulates timestamp and URL and is easily usable from detector code. -class BasicCCDBManager +/// +/// The CDBManager allowing caching of retrieved objects is by definition not thread safe, +/// therefore, to provide a possibility of multithread processing, one should foresee possibility +/// of multiple instances of the manager. CCDBManagerInstance serves to this purpose +/// +/// In cases where caching is not needed or just 1 instance of the manager is enough, one case use +/// a singleton version BasicCCDBManager + +class CCDBManagerInstance { struct CachedObject { std::shared_ptr<void> objPtr; @@ -39,11 +48,9 @@ class BasicCCDBManager }; public: - static BasicCCDBManager& instance() + CCDBManagerInstance(std::string const& path) : mCCDBAccessor{} { - const std::string ccdbUrl{"http://ccdb-test.cern.ch:8080"}; - static BasicCCDBManager inst{ccdbUrl}; - return inst; + mCCDBAccessor.init(path); } /// set a URL to query from @@ -67,6 +74,15 @@ class BasicCCDBManager template <typename T> T* getForTimeStamp(std::string const& path, long timestamp); + /// retrieve an object of type T from CCDB as stored under path, timestamp and metaData + template <typename T> + T* getSpecific(std::string const& path, long timestamp = -1, std::map<std::string, std::string> metaData = std::map<std::string, std::string>()) + { + // TODO: add some error info/handling when failing + mMetaData = metaData; + return getForTimeStamp<T>(path, timestamp); + } + /// retrieve an object of type T from CCDB as stored under path; will use the timestamp member template <typename T> T* get(std::string const& path) @@ -120,11 +136,6 @@ class BasicCCDBManager void resetCreatedNotBefore() { mCreatedNotBefore = 0; } private: - BasicCCDBManager(std::string const& path) : mCCDBAccessor{} - { - mCCDBAccessor.init(path); - } - // we access the CCDB via the CURL based C++ API o2::ccdb::CcdbApi mCCDBAccessor; std::unordered_map<std::string, CachedObject> mCache; //! map for {path, CachedObject} associations @@ -139,7 +150,7 @@ class BasicCCDBManager }; template <typename T> -T* BasicCCDBManager::getForTimeStamp(std::string const& path, long timestamp) +T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) { if (!isCachingEnabled()) { return mCCDBAccessor.retrieveFromTFileAny<T>(path, mMetaData, timestamp, nullptr, "", @@ -165,9 +176,24 @@ T* BasicCCDBManager::getForTimeStamp(std::string const& path, long timestamp) ptr = reinterpret_cast<T*>(cached.objPtr.get()); } mHeaders.clear(); + mMetaData.clear(); return ptr; } +class BasicCCDBManager : public CCDBManagerInstance +{ + public: + static BasicCCDBManager& instance() + { + const std::string ccdbUrl{"http://ccdb-test.cern.ch:8080"}; + static BasicCCDBManager inst{ccdbUrl}; + return inst; + } + + private: + using CCDBManagerInstance::CCDBManagerInstance; +}; + } // namespace o2::ccdb #endif //O2_BASICCCDBMANAGER_H diff --git a/CCDB/include/CCDB/CCDBQuery.h b/CCDB/include/CCDB/CCDBQuery.h index f2848c6a0e556..3b94b9576c261 100644 --- a/CCDB/include/CCDB/CCDBQuery.h +++ b/CCDB/include/CCDB/CCDBQuery.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/include/CCDB/CCDBTimeStampUtils.h b/CCDB/include/CCDB/CCDBTimeStampUtils.h index 358901d91a95e..e61dcf072d076 100644 --- a/CCDB/include/CCDB/CCDBTimeStampUtils.h +++ b/CCDB/include/CCDB/CCDBTimeStampUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 9b7612caab445..41237ef7fb01b 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,14 @@ #include <TObject.h> #include <TMessage.h> #include "CCDB/CcdbObjectInfo.h" +#include <CommonUtils/ConfigurableParam.h> +#include <type_traits> + +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) +#include <TJAlienCredentials.h> +#else +class TJAlienCredentials; +#endif class TFile; class TGrid; @@ -130,35 +139,6 @@ class CcdbApi //: public DatabaseInterface storeAsTFile(rootobj, path, metadata, startValidityTimestamp, endValidityTimestamp); } - /** - * Retrieve object at the given path for the given timestamp. - * - * @param path The path where the object is to be found. - * @param metadata Key-values representing the metadata to filter out objects. - * @param timestamp Timestamp of the object to retrieve. If omitted, current timestamp is used. - * @return the object, or nullptr if none were found. - * @deprecated in favour of retrieveFromTFileAny - */ - TObject* retrieve(std::string const& path, std::map<std::string, std::string> const& metadata, - long timestamp = -1) const; - - /** - * Retrieve object at the given path for the given timestamp. - * - * @param path The path where the object is to be found. - * @param metadata Key-values representing the metadata to filter out objects. - * @param timestamp Timestamp of the object to retrieve. If omitted, current timestamp is used. - * @param headers Map to be populated with the headers we received, if it is not null. - * @param optional etag from previous call - * @param optional createdNotAfter upper time limit for the object creation timestamp (TimeMachine mode) - * @param optional createdNotBefore lower time limit for the object creation timestamp (TimeMachine mode) - * @return the object, or nullptr if none were found. - * @deprecated in favour of retrieveFromTFileAny as it is not limited to TObjects. - */ - TObject* retrieveFromTFile(std::string const& path, std::map<std::string, std::string> const& metadata, - long timestamp = -1, std::map<std::string, std::string>* headers = nullptr, std::string const& etag = "", - const std::string& createdNotAfter = "", const std::string& createdNotBefore = "") const; - /** * Retrieve object at the given path for the given timestamp. * @@ -172,9 +152,16 @@ class CcdbApi //: public DatabaseInterface * @return the object, or nullptr if none were found or type does not match serialized type. */ template <typename T> - T* retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, - long timestamp = -1, std::map<std::string, std::string>* headers = nullptr, std::string const& etag = "", - const std::string& createdNotAfter = "", const std::string& createdNotBefore = "") const; + typename std::enable_if<!std::is_base_of<o2::conf::ConfigurableParam, T>::value, T*>::type + retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, + long timestamp = -1, std::map<std::string, std::string>* headers = nullptr, std::string const& etag = "", + const std::string& createdNotAfter = "", const std::string& createdNotBefore = "") const; + + template <typename T> + typename std::enable_if<std::is_base_of<o2::conf::ConfigurableParam, T>::value, T*>::type + retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, + long timestamp = -1, std::map<std::string, std::string>* headers = nullptr, std::string const& etag = "", + const std::string& createdNotAfter = "", const std::string& createdNotBefore = "") const; /** * Delete all versions of the object at this path. @@ -305,6 +292,19 @@ class CcdbApi //: public DatabaseInterface constexpr static const char* CCDBMETA_ENTRY = "ccdb_meta"; constexpr static const char* CCDBOBJECT_ENTRY = "ccdb_object"; + /** + * Set curl SSL options. The client still will be able to connect to non-ssl endpoints + * @param curl curl handler + * @return + */ + static void curlSetSSLOptions(CURL* curl); + + TObject* retrieve(std::string const& path, std::map<std::string, std::string> const& metadata, long timestamp) const; + + TObject* retrieveFromTFile(std::string const& path, std::map<std::string, std::string> const& metadata, long timestamp, + std::map<std::string, std::string>* headers, std::string const& etag, + const std::string& createdNotAfter, const std::string& createdNotBefore) const; + private: /** * Initialize in local mode; Objects will be retrieved from snapshot @@ -362,7 +362,6 @@ class CcdbApi //: public DatabaseInterface void storeAsTFile_impl(const void* obj1, std::type_info const& info, std::string const& path, std::map<std::string, std::string> const& metadata, long startValidityTimestamp = -1, long endValidityTimestamp = -1) const; - private: /** * A generic helper implementation to query obj whose type is given by a std::type_info */ @@ -370,13 +369,14 @@ class CcdbApi //: public DatabaseInterface long timestamp = -1, std::map<std::string, std::string>* headers = nullptr, std::string const& etag = "", const std::string& createdNotAfter = "", const std::string& createdNotBefore = "") const; + private: /** * A helper function to extract object from a local ROOT file * @param filename name of ROOT file * @param cl The TClass object describing the serialized type - * @return raw pointer to created object + * @return raw pointer to created object (and headers of answer) */ - void* extractFromLocalFile(std::string const& filename, TClass const* cl) const; + void* extractFromLocalFile(std::string const& filename, std::type_info const& tinfo, std::map<std::string, std::string>* headers) const; /** * Helper function to download binary content from alien:// storage @@ -384,7 +384,7 @@ class CcdbApi //: public DatabaseInterface * @param tcl The TClass object describing the serialized type * @return raw pointer to created object */ - void* downloadAlienContent(std::string const& fullUrl, TClass* tcl) const; + void* downloadAlienContent(std::string const& fullUrl, std::type_info const& tinfo) const; // initialize the TGrid (Alien connection) bool initTGrid() const; @@ -392,37 +392,52 @@ class CcdbApi //: public DatabaseInterface bool checkAlienToken() const; /// Queries the CCDB server and navigates through possible redirects until binary content is found; Retrieves content as instance - /// given by TClass if that is possible. Returns nullptr if something fails... - void* navigateURLsAndRetrieveContent(CURL*, std::string const& url, TClass* cl, std::map<std::string, std::string>* headers) const; + /// given by tinfo if that is possible. Returns nullptr if something fails... + void* navigateURLsAndRetrieveContent(CURL*, std::string const& url, std::type_info const& tinfo, std::map<std::string, std::string>* headers) const; // helper that interprets a content chunk as TMemFile and extracts the object therefrom - void* interpretAsTMemFileAndExtract(char* contentptr, size_t contentsize, TClass* cl) const; + void* interpretAsTMemFileAndExtract(char* contentptr, size_t contentsize, std::type_info const& tinfo) const; /** * Initialization of CURL */ void curlInit(); + // convert type_info to TClass, throw on failure + static TClass* tinfo2TClass(std::type_info const& tinfo); + /// Base URL of the CCDB (with port) std::string mUrl{}; std::string mSnapshotTopPath{}; bool mInSnapshotMode = false; - mutable std::multimap<std::string, std::string> mHeaderData; //! a "global" internal data structure that can be filled with HTTP header information - // (without need to recreate this structure locally each time) - mutable TGrid* mAlienInstance = nullptr; // a cached connection to TGrid (needed for Alien locations) - bool mHaveAlienToken = false; // stores if an alien token is available + mutable TGrid* mAlienInstance = nullptr; // a cached connection to TGrid (needed for Alien locations) + bool mHaveAlienToken = false; // stores if an alien token is available + static std::unique_ptr<TJAlienCredentials> mJAlienCredentials; // access JAliEn credentials ClassDefNV(CcdbApi, 1); }; template <typename T> -T* CcdbApi::retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, - long timestamp, std::map<std::string, std::string>* headers, std::string const& etag, - const std::string& createdNotAfter, const std::string& createdNotBefore) const +typename std::enable_if<!std::is_base_of<o2::conf::ConfigurableParam, T>::value, T*>::type + CcdbApi::retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, + long timestamp, std::map<std::string, std::string>* headers, std::string const& etag, + const std::string& createdNotAfter, const std::string& createdNotBefore) const { return static_cast<T*>(retrieveFromTFile(typeid(T), path, metadata, timestamp, headers, etag, createdNotAfter, createdNotBefore)); } +template <typename T> +typename std::enable_if<std::is_base_of<o2::conf::ConfigurableParam, T>::value, T*>::type + CcdbApi::retrieveFromTFileAny(std::string const& path, std::map<std::string, std::string> const& metadata, + long timestamp, std::map<std::string, std::string>* headers, std::string const& etag, + const std::string& createdNotAfter, const std::string& createdNotBefore) const +{ + auto obj = retrieveFromTFile(typeid(T), path, metadata, timestamp, headers, etag, createdNotAfter, createdNotBefore); + auto& param = const_cast<typename std::remove_const<T&>::type>(T::Instance()); + param.syncCCDBandRegistry(obj); + return ¶m; +} + } // namespace ccdb } // namespace o2 diff --git a/CCDB/include/CCDB/CcdbObjectInfo.h b/CCDB/include/CCDB/CcdbObjectInfo.h index 2dced89d769b8..fd5540bace02a 100644 --- a/CCDB/include/CCDB/CcdbObjectInfo.h +++ b/CCDB/include/CCDB/CcdbObjectInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/include/CCDB/IdPath.h b/CCDB/include/CCDB/IdPath.h index dd9544bcb8e9c..f8dd555bc3275 100644 --- a/CCDB/include/CCDB/IdPath.h +++ b/CCDB/include/CCDB/IdPath.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/include/CCDB/TObjectWrapper.h b/CCDB/include/CCDB/TObjectWrapper.h index 3c11cee3ae44f..10f463d1fbb17 100644 --- a/CCDB/include/CCDB/TObjectWrapper.h +++ b/CCDB/include/CCDB/TObjectWrapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/BasicCCDBManager.cxx b/CCDB/src/BasicCCDBManager.cxx index 7e4de611f2dd8..d4731d376cc65 100644 --- a/CCDB/src/BasicCCDBManager.cxx +++ b/CCDB/src/BasicCCDBManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ namespace o2 namespace ccdb { -void BasicCCDBManager::setURL(std::string const& url) +void CCDBManagerInstance::setURL(std::string const& url) { mCCDBAccessor.init(url); } diff --git a/CCDB/src/CCDBLinkDef.h b/CCDB/src/CCDBLinkDef.h index 1a71710b00bd8..f04d9f0a7fdd5 100644 --- a/CCDB/src/CCDBLinkDef.h +++ b/CCDB/src/CCDBLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/CCDBQuery.cxx b/CCDB/src/CCDBQuery.cxx index 8320e4ea3b6d5..d608870c97ba3 100644 --- a/CCDB/src/CCDBQuery.cxx +++ b/CCDB/src/CCDBQuery.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/CCDBTimeStampUtils.cxx b/CCDB/src/CCDBTimeStampUtils.cxx index 69809e77ac524..993eb1f2065bd 100644 --- a/CCDB/src/CCDBTimeStampUtils.cxx +++ b/CCDB/src/CCDBTimeStampUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 52e61710d0775..878ca1b3ab7f8 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,17 +18,13 @@ #include "CCDB/CCDBQuery.h" #include "CommonUtils/StringUtils.h" #include "CommonUtils/MemFileHelper.h" -#include <regex> #include <chrono> -#include <TMessage.h> #include <sstream> #include <TFile.h> #include <TGrid.h> #include <TSystem.h> #include <TStreamerInfo.h> #include <TMemFile.h> -#include <TBufferFile.h> -#include <TWebFile.h> #include <TH1F.h> #include <TTree.h> #include <FairLogger.h> @@ -35,9 +32,11 @@ #include <TClass.h> #include <CCDB/CCDBTimeStampUtils.h> #include <algorithm> -#include <boost/filesystem.hpp> +#include <filesystem> #include <boost/algorithm/string.hpp> #include <iostream> +#include <mutex> +#include <boost/interprocess/sync/named_semaphore.hpp> namespace o2 { @@ -46,6 +45,9 @@ namespace ccdb using namespace std; +std::mutex gIOMutex; // to protect TMemFile IO operations +unique_ptr<TJAlienCredentials> CcdbApi::mJAlienCredentials = nullptr; + CcdbApi::~CcdbApi() { curl_global_cleanup(); @@ -55,6 +57,9 @@ void CcdbApi::curlInit() { // todo : are there other things to initialize globally for curl ? curl_global_init(CURL_GLOBAL_DEFAULT); + CcdbApi::mJAlienCredentials.reset(new TJAlienCredentials()); + CcdbApi::mJAlienCredentials->loadCredentials(); + CcdbApi::mJAlienCredentials->selectPreferedCredentials(); } void CcdbApi::init(std::string const& host) @@ -74,9 +79,7 @@ void CcdbApi::init(std::string const& host) // find out if we can can in principle connect to Alien mHaveAlienToken = checkAlienToken(); - if (!mHaveAlienToken) { - LOG(WARN) << "CCDB: Did not find an alien token; Cannot serve objects located on alien://"; - } + LOG(INFO) << "Is alien token present?: " << mHaveAlienToken; } /** @@ -97,6 +100,7 @@ std::unique_ptr<std::vector<char>> CcdbApi::createObjectImage(const void* obj, s { // Create a binary image of the object, if CcdbObjectInfo pointer is provided, register there // the assigned object class name and the filename + std::lock_guard<std::mutex> guard(gIOMutex); std::string className = o2::utils::MemFileHelper::getClassName(tinfo); std::string tmpFileName = generateFileName(className); if (info) { @@ -116,6 +120,7 @@ std::unique_ptr<std::vector<char>> CcdbApi::createObjectImage(const TObject* roo info->setFileName(tmpFileName); info->setObjectType("TObject"); // why TObject and not the actual name? } + std::lock_guard<std::mutex> guard(gIOMutex); return o2::utils::MemFileHelper::createFileImage(*rootObject, tmpFileName, CCDBOBJECT_ENTRY); } @@ -166,11 +171,14 @@ void CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::stri headerlist = curl_slist_append(headerlist, buf); if (curl != nullptr) { string fullUrl = getFullUrlForStorage(curl, path, objectType, metadata, sanitizedStartValidityTimestamp, sanitizedEndValidityTimestamp); - LOG(DEBUG) << "Full URL Encoded: " << fullUrl; + LOG(debug3) << "Full URL Encoded: " << fullUrl; /* what URL that receives this POST */ curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + curlSetSSLOptions(curl); /* Perform the request, res will get the return code */ CURLcode res = curl_easy_perform(curl); @@ -229,12 +237,16 @@ string CcdbApi::getFullUrlForStorage(CURL* curl, const string& path, const strin return fullUrl; } +std::string getSnapshotPath(std::string const& topdir, const string& path) +{ + return topdir + "/" + path + "/snapshot.root"; +} + // todo make a single method of the one above and below string CcdbApi::getFullUrlForRetrieval(CURL* curl, const string& path, const map<string, string>& metadata, long timestamp) const { if (mInSnapshotMode) { - string snapshotPath = mSnapshotTopPath + "/" + path + "/snapshot.root"; - return snapshotPath; + return getSnapshotPath(mSnapshotTopPath, path); } // Prepare timestamps @@ -298,6 +310,8 @@ static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, voi * @param nmemb * @param userp a MemoryStruct where data is stored. * @return the size of the data we received and stored at userp. + * If an error is returned no attempt to establish a connection is made + * and the perform operation will return the callback's error code */ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) { @@ -305,6 +319,56 @@ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* st return written; } +/** + * Callback to load credentials and CA's + * @param curl curl handler + * @param ssl_ctx SSL context that will be modified + * @param parm + * @return + */ +static CURLcode ssl_ctx_callback(CURL* curl, void* ssl_ctx, void* parm) +{ + std::string msg((const char*)parm); + int start = 0, end = msg.find('\n'); + + if (msg.length() > 0 && end == -1) { + LOG(WARN) << msg; + } else if (end > 0) { + while (end > 0) { + LOG(WARN) << msg.substr(start, end - start); + start = end + 1; + end = msg.find('\n', start); + } + } + return CURLE_OK; +} + +void CcdbApi::curlSetSSLOptions(CURL* curl_handle) +{ + CredentialsKind cmk = mJAlienCredentials->getPreferedCredentials(); + + /* NOTE: return early, the warning should be printed on SSL callback if needed */ + if (cmk == cNOT_FOUND) { + return; + } + + TJAlienCredentialsObject cmo = mJAlienCredentials->get(cmk); + + char* CAPath = getenv("X509_CERT_DIR"); + if (CAPath) { + curl_easy_setopt(curl_handle, CURLOPT_CAPATH, CAPath); + } + curl_easy_setopt(curl_handle, CURLOPT_CAINFO, nullptr); + curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, cmo.certpath.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, cmo.keypath.c_str()); + + // NOTE: for lazy logging only + curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback); + curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_DATA, mJAlienCredentials->getMessages().c_str()); + + // CURLcode ret = curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, *ssl_ctx_callback); +} + TObject* CcdbApi::retrieve(std::string const& path, std::map<std::string, std::string> const& metadata, long timestamp) const { @@ -319,6 +383,8 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map<std::string, std::s }; TObject* result = nullptr; + curlSetSSLOptions(curl_handle); + /* init the curl session */ curl_handle = curl_easy_init(); @@ -340,6 +406,8 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map<std::string, std::s /* if redirected , we tell libcurl to follow redirection */ curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curlSetSSLOptions(curl_handle); + /* get it! */ res = curl_easy_perform(curl_handle); @@ -358,6 +426,7 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map<std::string, std::s long response_code; res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code); if ((res == CURLE_OK) && (response_code != 404)) { + std::lock_guard<std::mutex> guard(gIOMutex); TMessage mess(kMESS_OBJECT); mess.SetBuffer(chunk.memory, chunk.size, kFALSE); mess.SetReadMode(); @@ -474,6 +543,8 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map<std::strin curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list); } + curlSetSSLOptions(curl_handle); + /* get it! */ res = curl_easy_perform(curl_handle); std::string errStr; @@ -484,12 +555,13 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map<std::strin if ((res == CURLE_OK) && (response_code != 404)) { Int_t previousErrorLevel = gErrorIgnoreLevel; gErrorIgnoreLevel = kFatal; + std::lock_guard<std::mutex> guard(gIOMutex); TMemFile memFile("name", chunk.memory, chunk.size, "READ"); gErrorIgnoreLevel = previousErrorLevel; if (!memFile.IsZombie()) { result = (TObject*)extractFromTFile(memFile, TClass::GetClass("TObject")); if (result == nullptr) { - errStr = o2::utils::concat_string("Couldn't retrieve the object ", path); + errStr = o2::utils::Str::concat_string("Couldn't retrieve the object ", path); LOG(ERROR) << errStr; } memFile.Close(); @@ -497,11 +569,11 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map<std::strin LOG(DEBUG) << "Object " << path << " is stored in a TMemFile"; } } else { - errStr = o2::utils::concat_string("Invalid URL : ", fullUrl); + errStr = o2::utils::Str::concat_string("Invalid URL : ", fullUrl); LOG(ERROR) << errStr; } } else { - errStr = o2::utils::concat_string("curl_easy_perform() failed: ", curl_easy_strerror(res)); + errStr = o2::utils::Str::concat_string("curl_easy_perform() failed: ", curl_easy_strerror(res)); fprintf(stderr, "%s", errStr.c_str()); } @@ -520,8 +592,8 @@ void CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir // we setup the target path for this blob std::string fulltargetdir = targetdir + '/' + path; - if (!boost::filesystem::exists(fulltargetdir)) { - if (!boost::filesystem::create_directories(fulltargetdir)) { + if (!std::filesystem::exists(fulltargetdir)) { + if (!std::filesystem::create_directories(fulltargetdir)) { std::cerr << "Could not create target directory " << fulltargetdir << "\n"; } } @@ -558,6 +630,8 @@ void CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir /* if redirected , we tell libcurl to follow redirection */ curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curlSetSSLOptions(curl_handle); + /* get it! */ res = curl_easy_perform(curl_handle); @@ -584,14 +658,13 @@ void CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir if (success) { // trying to append metadata to the file so that it can be inspected WHERE/HOW/WHAT IT corresponds to // Just a demonstrator for the moment - TFile snapshotfile(targetpath.c_str(), "UPDATE"); CCDBQuery querysummary(path, metadata, timestamp); - snapshotfile.WriteObjectAny(&querysummary, TClass::GetClass(typeid(querysummary)), CCDBQUERY_ENTRY); - // retrieveHeaders auto headers = retrieveHeaders(path, metadata, timestamp); + std::lock_guard<std::mutex> guard(gIOMutex); + TFile snapshotfile(targetpath.c_str(), "UPDATE"); + snapshotfile.WriteObjectAny(&querysummary, TClass::GetClass(typeid(querysummary)), CCDBQUERY_ENTRY); snapshotfile.WriteObjectAny(&headers, TClass::GetClass(typeid(metadata)), CCDBMETA_ENTRY); - snapshotfile.Close(); } } @@ -616,7 +689,7 @@ void* CcdbApi::extractFromTFile(TFile& file, TClass const* cl) // it could be that object was stored with previous convention // where the classname was taken as key std::string objectName(cl->GetName()); - utils::trim(objectName); + o2::utils::Str::trim(objectName); object = file.GetObjectChecked(objectName.c_str(), cl); LOG(WARN) << "Did not find object under expected name " << CCDBOBJECT_ENTRY; if (!object) { @@ -641,22 +714,43 @@ void* CcdbApi::extractFromTFile(TFile& file, TClass const* cl) return result; } -void* CcdbApi::extractFromLocalFile(std::string const& filename, TClass const* tcl) const +void* CcdbApi::extractFromLocalFile(std::string const& filename, std::type_info const& tinfo, std::map<std::string, std::string>* headers) const { - if (!boost::filesystem::exists(filename)) { - LOG(INFO) << "Local snapshot " << filename << " not found \n"; + if (!std::filesystem::exists(filename)) { + LOG(ERROR) << "Local snapshot " << filename << " not found \n"; return nullptr; } + std::lock_guard<std::mutex> guard(gIOMutex); + auto tcl = tinfo2TClass(tinfo); TFile f(filename.c_str(), "READ"); + if (headers) { + auto storedmeta = retrieveMetaInfo(f); + if (storedmeta) { + *headers = *storedmeta; // do a simple deep copy + delete storedmeta; + } + } return extractFromTFile(f, tcl); } bool CcdbApi::checkAlienToken() const { +#ifdef __APPLE__ + // not checking for token on Mac because + // a) we have seen problems where system call below hangs in some cases + // b) not the production plattform where the token would be beneficial + return false; +#endif // a somewhat weird construction to programmatically find out if we // have a GRID token; Can be replaced with something more elegant once // alien-token-info does not ask for passwords interactively - auto returncode = system("timeout 1s timeout 1s alien-token-info &> /dev/null"); + if (getenv("JALIEN_TOKEN_CERT")) { + return true; + } + auto returncode = system("alien-token-info > /dev/null 2> /dev/null"); + if (returncode == -1) { + LOG(ERROR) << "system(\"alien-token-info\") call failed with internal fork/wait error"; + } return returncode == 0; } @@ -665,18 +759,22 @@ bool CcdbApi::initTGrid() const if (!mAlienInstance) { if (mHaveAlienToken) { mAlienInstance = TGrid::Connect("alien"); + } else { + LOG(WARN) << "CCDB: Did not find an alien token; Cannot serve objects located on alien://"; } } return mAlienInstance != nullptr; } -void* CcdbApi::downloadAlienContent(std::string const& url, TClass* cl) const +void* CcdbApi::downloadAlienContent(std::string const& url, std::type_info const& tinfo) const { if (!initTGrid()) { return nullptr; } + std::lock_guard<std::mutex> guard(gIOMutex); auto memfile = TMemFile::Open(url.c_str(), "OPEN"); if (memfile) { + auto cl = tinfo2TClass(tinfo); auto content = extractFromTFile(*memfile, cl); delete memfile; return content; @@ -684,17 +782,19 @@ void* CcdbApi::downloadAlienContent(std::string const& url, TClass* cl) const return nullptr; } -void* CcdbApi::interpretAsTMemFileAndExtract(char* contentptr, size_t contentsize, TClass* tcl) const +void* CcdbApi::interpretAsTMemFileAndExtract(char* contentptr, size_t contentsize, std::type_info const& tinfo) const { void* result = nullptr; Int_t previousErrorLevel = gErrorIgnoreLevel; gErrorIgnoreLevel = kFatal; + std::lock_guard<std::mutex> guard(gIOMutex); TMemFile memFile("name", contentptr, contentsize, "READ"); gErrorIgnoreLevel = previousErrorLevel; if (!memFile.IsZombie()) { + auto tcl = tinfo2TClass(tinfo); result = extractFromTFile(memFile, tcl); if (!result) { - LOG(ERROR) << o2::utils::concat_string("Couldn't retrieve object corresponding to ", tcl->GetName(), " from TFile"); + LOG(ERROR) << o2::utils::Str::concat_string("Couldn't retrieve object corresponding to ", tcl->GetName(), " from TFile"); } memFile.Close(); } @@ -702,11 +802,16 @@ void* CcdbApi::interpretAsTMemFileAndExtract(char* contentptr, size_t contentsiz } // navigate sequence of URLs until TFile content is found; object is extracted and returned -void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string const& url, TClass* cl, std::map<string, string>* headers) const +void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string const& url, std::type_info const& tinfo, std::map<string, string>* headers) const { + // a global internal data structure that can be filled with HTTP header information + // static --> to avoid frequent alloc/dealloc as optimization + // not sure if thread_local takes away that benefit + static thread_local std::multimap<std::string, std::string> headerData; + // let's see first of all if the url is something specific that curl cannot handle if (url.find("alien:/", 0) != std::string::npos) { - return downloadAlienContent(url, cl); + return downloadAlienContent(url, tinfo); } // add other final cases here // example root:// @@ -719,15 +824,16 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // if redirected , we tell libcurl NOT to follow redirection curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 0L); - curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_map_callback<decltype(mHeaderData)>); - mHeaderData.clear(); - curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void*)&mHeaderData); + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_map_callback<decltype(headerData)>); + headerData.clear(); + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void*)&headerData); MemoryStruct chunk{(char*)malloc(1), 0}; // send all data to this function curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void*)&chunk); + curlSetSSLOptions(curl_handle); auto res = curl_easy_perform(curl_handle); long response_code = -1; @@ -736,13 +842,13 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con bool cachingflag = false; if (res == CURLE_OK && curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) { if (headers) { - for (auto& p : mHeaderData) { + for (auto& p : headerData) { (*headers)[p.first] = p.second; } } if (200 <= response_code && response_code < 300) { // good response and the content is directly provided and should have been dumped into "chunk" - content = interpretAsTMemFileAndExtract(chunk.memory, chunk.size, cl); + content = interpretAsTMemFileAndExtract(chunk.memory, chunk.size, tinfo); } else if (response_code == 304) { // this means the object exist but I am not serving // it since it's already in your possession @@ -754,23 +860,43 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con else if (300 <= response_code && response_code < 400) { // we try content locations in order of appearance until one succeeds // 1st: The "Location" field - // 2nd: Possible "Content-Location" fields - auto tryLocations = [this, &curl_handle, &content, cl](auto range) { + // 2nd: Possible "Content-Location" fields - Location field + + // some locations are relative to the main server so we need to fix/complement them + auto complement_Location = [this](std::string const& loc) { + if (loc[0] == '/') { + // if it's just a path (noticed by trailing '/' we prepend the server url + return getURL() + loc; + } + return loc; + }; + + std::vector<std::string> locs; + auto iter = headerData.find("Location"); + if (iter != headerData.end()) { + locs.push_back(complement_Location(iter->second)); + } + // add alternative locations (not yet included) + auto iter2 = headerData.find("Content-Location"); + if (iter2 != headerData.end()) { + auto range = headerData.equal_range("Content-Location"); for (auto it = range.first; it != range.second; ++it) { - auto nextlocation = it->second; - LOG(DEBUG) << "Trying content location " << nextlocation; - content = navigateURLsAndRetrieveContent(curl_handle, nextlocation, cl, nullptr); + if (std::find(locs.begin(), locs.end(), it->second) == locs.end()) { + locs.push_back(complement_Location(it->second)); + } + } + } + for (auto& l : locs) { + if (l.size() > 0) { + LOG(DEBUG) << "Trying content location " << l; + content = navigateURLsAndRetrieveContent(curl_handle, l, tinfo, nullptr); if (content /* or other success marker in future */) { break; } } - }; - tryLocations(mHeaderData.equal_range("Location")); - if (content == nullptr) { - tryLocations(mHeaderData.equal_range("Content-Location")); } } else if (response_code == 404) { - LOG(ERROR) << "Requested resource does not exist"; + LOG(ERROR) << "Requested resource does not exist: " << url; errorflag = true; } else { errorflag = true; @@ -795,18 +921,66 @@ void* CcdbApi::retrieveFromTFile(std::type_info const& tinfo, std::string const& std::map<std::string, std::string>* headers, std::string const& etag, const std::string& createdNotAfter, const std::string& createdNotBefore) const { - // We need the TClass for this type; will verify if dictionary exists - auto tcl = TClass::GetClass(tinfo); - if (!tcl) { - std::cerr << "Could not retrieve ROOT dictionary for type " << tinfo.name() << " aborting to read from CCDB\n"; - return nullptr; + // The environment option ALICEO2_CCDB_LOCALCACHE allows + // to reduce the number of queries to the server, by collecting the objects in a local + // cache folder, and serving from this folder for repeated queries. + // This is useful for instance for MC GRID productions in which we spawn + // many isolated processes, all querying the CCDB (for potentially the same objects and same timestamp). + // In addition, we can monitor exactly which objects are fetched and what is their content. + // One can also distribute so obtained caches to sites without network access. + auto cachedir = getenv("ALICEO2_CCDB_LOCALCACHE"); + if (cachedir) { + // protect this sensitive section by a multi-process named semaphore + bool use_sema = false; + boost::interprocess::named_semaphore* sem = nullptr; + std::hash<std::string> hasher; + const auto semhashedstring = "aliceccdb" + std::to_string(hasher(std::string(cachedir) + path)).substr(0, 16); + try { + sem = new boost::interprocess::named_semaphore(boost::interprocess::open_or_create_t{}, semhashedstring.c_str(), 1); + } catch (std::exception e) { + LOG(WARN) << "Exception occurred during CCDB (cache) semaphore setup; Continuing without"; + sem = nullptr; + } + if (sem) { + sem->wait(); // wait until we can enter (no one else there) + } + if (!std::filesystem::exists(cachedir)) { + if (!std::filesystem::create_directories(cachedir)) { + LOG(ERROR) << "Could not create local snapshot cache directory " << cachedir << "\n"; + } + } + std::string logfile = std::string(cachedir) + "/log"; + std::fstream out(logfile, ios_base::out | ios_base::app); + if (out.is_open()) { + out << "CCDB-access[" << getpid() << "] to " << path << " timestamp " << timestamp << "\n"; + } + auto snapshotfile = getSnapshotPath(cachedir, path); + std::filesystem::exists(snapshotfile); + if (!std::filesystem::exists(snapshotfile)) { + out << "CCDB-access[" << getpid() << "] ... downloading to snapshot " << snapshotfile << "\n"; + // if file not already here and valid --> snapshot it + retrieveBlob(path, cachedir, metadata, timestamp); + } else { + out << "CCDB-access[" << getpid() << "] ... serving from local snapshot " << snapshotfile << "\n"; + } + if (sem) { + sem->post(); + if (sem->try_wait()) { + // if nobody else is waiting remove the semaphore resource + sem->post(); + boost::interprocess::named_semaphore::remove(semhashedstring.c_str()); + } + } + return extractFromLocalFile(snapshotfile, tinfo, headers); } + // normal mode follows + CURL* curl_handle = curl_easy_init(); string fullUrl = getFullUrlForRetrieval(curl_handle, path, metadata, timestamp); // if we are in snapshot mode we can simply open the file; extract the object and return if (mInSnapshotMode) { - return extractFromLocalFile(fullUrl, tcl); + return extractFromLocalFile(fullUrl, tinfo, headers); } // add some global options to the curl query @@ -825,7 +999,7 @@ void* CcdbApi::retrieveFromTFile(std::type_info const& tinfo, std::string const& } curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list); - auto content = navigateURLsAndRetrieveContent(curl_handle, fullUrl, tcl, headers); + auto content = navigateURLsAndRetrieveContent(curl_handle, fullUrl, tinfo, headers); curl_easy_cleanup(curl_handle); return content; } @@ -866,6 +1040,8 @@ std::string CcdbApi::list(std::string const& path, bool latestOnly, std::string headers = curl_slist_append(headers, (string("Content-Type: ") + returnFormat).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curlSetSSLOptions(curl); + // Perform the request, res will get the return code res = curl_easy_perform(curl); if (res != CURLE_OK) { @@ -899,6 +1075,8 @@ void CcdbApi::deleteObject(std::string const& path, long timestamp) const curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_easy_setopt(curl, CURLOPT_URL, fullUrl.str().c_str()); + curlSetSSLOptions(curl); + // Perform the request, res will get the return code res = curl_easy_perform(curl); if (res != CURLE_OK) { @@ -919,6 +1097,8 @@ void CcdbApi::truncate(std::string const& path) const if (curl != nullptr) { curl_easy_setopt(curl, CURLOPT_URL, fullUrl.str().c_str()); + curlSetSSLOptions(curl); + // Perform the request, res will get the return code res = curl_easy_perform(curl); if (res != CURLE_OK) { @@ -943,6 +1123,7 @@ bool CcdbApi::isHostReachable() const if (curl) { curl_easy_setopt(curl, CURLOPT_URL, mUrl.data()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curlSetSSLOptions(curl); res = curl_easy_perform(curl); result = (res == CURLE_OK); @@ -1009,6 +1190,8 @@ std::map<std::string, std::string> CcdbApi::retrieveHeaders(std::string const& p curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_map_callback<>); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers); + curlSetSSLOptions(curl); + // Perform the request, res will get the return code res = curl_easy_perform(curl); if (res != CURLE_OK) { @@ -1046,6 +1229,8 @@ bool CcdbApi::getCCDBEntryHeaders(std::string const& url, std::string const& eta curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers); + curlSetSSLOptions(curl); + /* Perform the request */ curl_easy_perform(curl); long http_code = 0; @@ -1114,5 +1299,15 @@ std::vector<std::string> CcdbApi::getAllFolders(std::string const& top) const return folders; } +TClass* CcdbApi::tinfo2TClass(std::type_info const& tinfo) +{ + TClass* cl = TClass::GetClass(tinfo); + if (!cl) { + throw std::runtime_error(fmt::format("Could not retrieve ROOT dictionary for type {}, aborting", tinfo.name())); + return nullptr; + } + return cl; +} + } // namespace ccdb } // namespace o2 diff --git a/CCDB/src/DownloadCCDBFile.cxx b/CCDB/src/DownloadCCDBFile.cxx index 7df14bfe6b3f9..21d966d5209fe 100644 --- a/CCDB/src/DownloadCCDBFile.cxx +++ b/CCDB/src/DownloadCCDBFile.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/IdPath.cxx b/CCDB/src/IdPath.cxx index 8a838cedc3157..d27ee7249d215 100644 --- a/CCDB/src/IdPath.cxx +++ b/CCDB/src/IdPath.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/InspectCCDBFile.cxx b/CCDB/src/InspectCCDBFile.cxx index 78f76257e35bc..46dc5d0706bab 100644 --- a/CCDB/src/InspectCCDBFile.cxx +++ b/CCDB/src/InspectCCDBFile.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/src/UploadTool.cxx b/CCDB/src/UploadTool.cxx index 2e62ec28ce278..3b3e7aedcb4de 100644 --- a/CCDB/src/UploadTool.cxx +++ b/CCDB/src/UploadTool.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/test/testBasicCCDBManager.cxx b/CCDB/test/testBasicCCDBManager.cxx index 3a49d56172c7f..e91f4e6ac4545 100644 --- a/CCDB/test/testBasicCCDBManager.cxx +++ b/CCDB/test/testBasicCCDBManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CCDB/test/testCcdbApi.cxx b/CCDB/test/testCcdbApi.cxx index 40b51774c9f49..b9ffe59c19500 100644 --- a/CCDB/test/testCcdbApi.cxx +++ b/CCDB/test/testCcdbApi.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,8 @@ #include "CommonUtils/RootChain.h" // just as test object #include "CCDB/CCDBTimeStampUtils.h" #include <boost/test/unit_test.hpp> -#include <boost/filesystem.hpp> +#include <filesystem> +#include <cstdio> #include <cassert> #include <iostream> #include <cstdio> @@ -179,14 +181,15 @@ BOOST_AUTO_TEST_CASE(store_retrieve_TMemFile_templated_test, *utf::precondition( // test the snapshot mechanism // --------------------------- // a) create a local snapshot of the Test folder - auto ph = boost::filesystem::unique_path(); - boost::filesystem::create_directories(ph); - f.api.snapshot(basePath, ph.string(), o2::ccdb::getCurrentTimestamp()); - std::cout << "Creating snapshot at " << ph.string() << "\n"; + // std::filesystem does not yet provide boost::filesystem::unique_path() equivalent, and usin tmpnam generate a warning + auto ph = o2::utils::Str::create_unique_path(std::filesystem::temp_directory_path().native()); + std::filesystem::create_directories(ph); + f.api.snapshot(basePath, ph, o2::ccdb::getCurrentTimestamp()); + std::cout << "Creating snapshot at " << ph << "\n"; // b) init a new instance from the snapshot and query something from it o2::ccdb::CcdbApi snapshot; - snapshot.init("file://" + ph.string()); + snapshot.init(o2::utils::Str::concat_string("file://", ph)); // c) query from the snapshot BOOST_CHECK(snapshot.retrieveFromTFileAny<o2::ccdb::IdPath>(basePath + "CCDBPath", f.metadata) != nullptr); @@ -199,8 +202,8 @@ BOOST_AUTO_TEST_CASE(store_retrieve_TMemFile_templated_test, *utf::precondition( } // d) cleanup local snapshot - if (boost::filesystem::exists(ph)) { - boost::filesystem::remove_all(ph); + if (std::filesystem::exists(ph)) { + std::filesystem::remove_all(ph); } } @@ -264,7 +267,7 @@ BOOST_AUTO_TEST_CASE(retrieveTMemFile_test, *utf::precondition(if_reachable())) { test_fixture f; - TObject* obj = f.api.retrieveFromTFile(basePath + "th1", f.metadata); + TObject* obj = f.api.retrieveFromTFileAny<TObject>(basePath + "th1", f.metadata); BOOST_CHECK_NE(obj, nullptr); BOOST_CHECK_EQUAL(obj->ClassName(), "TH1F"); auto h1 = dynamic_cast<TH1F*>(obj); @@ -272,7 +275,7 @@ BOOST_AUTO_TEST_CASE(retrieveTMemFile_test, *utf::precondition(if_reachable())) BOOST_CHECK_EQUAL(obj->GetName(), "th1name"); delete obj; - obj = f.api.retrieveFromTFile(basePath + "graph", f.metadata); + obj = f.api.retrieveFromTFileAny<TObject>(basePath + "graph", f.metadata); BOOST_CHECK_NE(obj, nullptr); BOOST_CHECK_EQUAL(obj->ClassName(), "TGraph"); auto graph = dynamic_cast<TGraph*>(obj); @@ -285,7 +288,7 @@ BOOST_AUTO_TEST_CASE(retrieveTMemFile_test, *utf::precondition(if_reachable())) delete graph; std::map<std::string, std::string> headers; - obj = f.api.retrieveFromTFile(basePath + "tree", f.metadata, -1, &headers); + obj = f.api.retrieveFromTFileAny<TObject>(basePath + "tree", f.metadata, -1, &headers); BOOST_CHECK_NE(obj, nullptr); BOOST_CHECK_EQUAL(obj->ClassName(), "TTree"); auto tree = dynamic_cast<TTree*>(obj); @@ -297,7 +300,7 @@ BOOST_AUTO_TEST_CASE(retrieveTMemFile_test, *utf::precondition(if_reachable())) BOOST_CHECK_EQUAL(headers["Hello"], "World"); // wrong url - obj = f.api.retrieveFromTFile("Wrong/wrong", f.metadata); + obj = f.api.retrieveFromTFileAny<TObject>("Wrong/wrong", f.metadata); BOOST_CHECK_EQUAL(obj, nullptr); } @@ -307,10 +310,10 @@ BOOST_AUTO_TEST_CASE(truncate_test, *utf::precondition(if_reachable())) TH1F h("object1", "object1", 100, 0, 99); f.api.storeAsTFile(&h, basePath + "Detector", f.metadata); // test with explicit dates - auto h1 = f.api.retrieveFromTFile(basePath + "Detector", f.metadata); + auto h1 = f.api.retrieveFromTFileAny<TH1F>(basePath + "Detector", f.metadata); BOOST_CHECK(h1 != nullptr); f.api.truncate(basePath + "Detector"); - h1 = f.api.retrieveFromTFile(basePath + "Detector", f.metadata); + h1 = f.api.retrieveFromTFileAny<TH1F>(basePath + "Detector", f.metadata); BOOST_CHECK(h1 == nullptr); } @@ -322,10 +325,10 @@ BOOST_AUTO_TEST_CASE(delete_test, *utf::precondition(if_reachable())) long from = o2::ccdb::getCurrentTimestamp(); long to = o2::ccdb::getFutureTimestamp(60 * 60 * 24 * 365 * 10); f.api.storeAsTFile(&h1, basePath + "Detector", f.metadata, from, to); // test with explicit dates - auto h2 = f.api.retrieveFromTFile(basePath + "Detector", f.metadata); + auto h2 = f.api.retrieveFromTFileAny<TH1F>(basePath + "Detector", f.metadata); BOOST_CHECK(h2 != nullptr); f.api.deleteObject(basePath + "Detector"); - h2 = f.api.retrieveFromTFile(basePath + "Detector", f.metadata); + h2 = f.api.retrieveFromTFileAny<TH1F>(basePath + "Detector", f.metadata); BOOST_CHECK(h2 == nullptr); } diff --git a/CCDB/test/testCcdbApi_ConfigParam.cxx b/CCDB/test/testCcdbApi_ConfigParam.cxx new file mode 100644 index 0000000000000..57335505cfab6 --- /dev/null +++ b/CCDB/test/testCcdbApi_ConfigParam.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file testCcdbApi_ConfigParam.cxx +/// \author Sandro Wenzel +/// + +#define BOOST_TEST_MODULE CCDB +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include "CCDB/CcdbApi.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsVertexing/PVertexerParams.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include <boost/test/unit_test.hpp> +#include <filesystem> +#include <cstdio> +#include <cassert> +#include <iostream> +#include <cstdio> +#include <curl/curl.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <chrono> +#include <CommonUtils/StringUtils.h> +#include <sys/types.h> +#include <unistd.h> + +#include <boost/property_tree/json_parser.hpp> +#include <boost/property_tree/ptree.hpp> +#include <boost/foreach.hpp> +#include <boost/optional/optional.hpp> + +using namespace std; +using namespace o2::ccdb; +namespace utf = boost::unit_test; +namespace tt = boost::test_tools; + +static string ccdbUrl; +static string basePath; +bool hostReachable = false; + +/** + * Global fixture, ie general setup and teardown + */ +struct Fixture { + Fixture() + { + CcdbApi api; + ccdbUrl = "http://ccdb-test.cern.ch:8080"; + api.init(ccdbUrl); + cout << "ccdb url: " << ccdbUrl << endl; + hostReachable = api.isHostReachable(); + cout << "Is host reachable ? --> " << hostReachable << endl; + basePath = string("Test/pid") + getpid() + "/"; + cout << "Path we will use in this test suite : " + basePath << endl; + } + ~Fixture() + { + if (hostReachable) { + CcdbApi api; + map<string, string> metadata; + api.init(ccdbUrl); + api.truncate(basePath + "*"); + cout << "Test data truncated (" << basePath << ")" << endl; + } + } +}; +BOOST_GLOBAL_FIXTURE(Fixture); + +/** + * Just an accessor to the hostReachable variable to be used to determine whether tests can be ran or not. + */ +struct if_reachable { + tt::assertion_result operator()(utf::test_unit_id) + { + return hostReachable; + } +}; + +/** + * Fixture for the tests, i.e. code is ran in every test that uses it, i.e. it is like a setup and teardown for tests. + */ +struct test_fixture { + test_fixture() + { + api.init(ccdbUrl); + metadata["Hello"] = "World"; + std::cout << "*** " << boost::unit_test::framework::current_test_case().p_name << " ***" << std::endl; + } + ~test_fixture() = default; + + CcdbApi api; + map<string, string> metadata; +}; + +BOOST_AUTO_TEST_CASE(testConfigParamRetrieval, *utf::precondition(if_reachable())) +{ + test_fixture f; + + // We'd like to demonstrate the following: + // GIVEN: + // - user modifies field in a config param from command line (RT) + // - user fetches config param from CCDB + // + // WE'D LIKE TO ARRIVE AT A STATE with + // - the returned object from CCDB gets syncs with the config param registry + // - everything is consistent + + // fetch the default instance + auto& p1 = o2::vertexing::PVertexerParams::Instance(); + + // update the config system with some runtime keys + o2::conf::ConfigurableParam::updateFromString("pvertexer.dbscanDeltaT=-3."); + + std::map<std::string, std::string> headers; + std::map<std::string, std::string> meta; + long from = o2::ccdb::getCurrentTimestamp(); + auto* object = f.api.retrieveFromTFileAny<o2::vertexing::PVertexerParams>("GLO/Config/PVertexer", meta, from + 1, &headers); + BOOST_CHECK(object != nullptr); + BOOST_CHECK(object->getMemberProvenance("dbscanDeltaT") == o2::conf::ConfigurableParam::EParamProvenance::kRT); + BOOST_CHECK(object->getMemberProvenance("useMeanVertexConstraint") == o2::conf::ConfigurableParam::EParamProvenance::kCCDB); + BOOST_CHECK(p1.getMemberProvenance("dbscanDeltaT") == o2::conf::ConfigurableParam::EParamProvenance::kRT); + BOOST_CHECK(p1.getMemberProvenance("useMeanVertexConstraint") == o2::conf::ConfigurableParam::EParamProvenance::kCCDB); + BOOST_CHECK(object == &p1); +} \ No newline at end of file diff --git a/CCDB/test/testCcdbApi_alien.cxx b/CCDB/test/testCcdbApi_alien.cxx index b97b477aa9248..35d91baf42b56 100644 --- a/CCDB/test/testCcdbApi_alien.cxx +++ b/CCDB/test/testCcdbApi_alien.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000..5ea8370c209c8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,98 @@ +# Changes since 2021-02-23 + +## Changes in Analysis + +- [#5581](https://github.com/AliceO2Group/AliceO2/pull/5581) 2021-02-27: PWGHF: Revert "Add flag to switch off TPC cluster selection" by [@ginnocen](https://github.com/ginnocen) +- [#5595](https://github.com/AliceO2Group/AliceO2/pull/5595) 2021-03-02: Remove non-templated DCAFitter (overridden by DCAFitterN) by [@shahor02](https://github.com/shahor02) +- [#5610](https://github.com/AliceO2Group/AliceO2/pull/5610) 2021-03-04: Better message by [@jgrosseo](https://github.com/jgrosseo) +- [#5601](https://github.com/AliceO2Group/AliceO2/pull/5601) 2021-03-04: DPL: simplify method analysis task introspection by [@alibuild](https://github.com/alibuild) +- [#5599](https://github.com/AliceO2Group/AliceO2/pull/5599) 2021-03-04: Fix for sparse index builder skipping entries by [@aalkin](https://github.com/aalkin) +- [#5566](https://github.com/AliceO2Group/AliceO2/pull/5566) 2021-03-04: Renaming index columns for TF merging by [@jgrosseo](https://github.com/jgrosseo) +- [#5558](https://github.com/AliceO2Group/AliceO2/pull/5558) 2021-03-04: [DPL Analysis] Simple workflow suffix solution by [@saganatt](https://github.com/saganatt) +- [#5631](https://github.com/AliceO2Group/AliceO2/pull/5631) 2021-03-05: PWGHF: fix wrong casting of track index by [@aalkin](https://github.com/aalkin) +- [#5611](https://github.com/AliceO2Group/AliceO2/pull/5611) 2021-03-05: Renaming charge() to sign() by [@jgrosseo](https://github.com/jgrosseo) +- [#5633](https://github.com/AliceO2Group/AliceO2/pull/5633) 2021-03-09: Adapting to updated vertex selection in converter by [@jgrosseo](https://github.com/jgrosseo) +- [#5623](https://github.com/AliceO2Group/AliceO2/pull/5623) 2021-03-09: Adding Forward (MFT+Muon) tables by [@jgrosseo](https://github.com/jgrosseo) +- [#5640](https://github.com/AliceO2Group/AliceO2/pull/5640) 2021-03-09: [DPL Analysis] Canonical task names by [@saganatt](https://github.com/saganatt) +## Changes in Common + +- [#5560](https://github.com/AliceO2Group/AliceO2/pull/5560) 2021-02-26: Fix some codechecker violations by [@davidrohr](https://github.com/davidrohr) +- [#5578](https://github.com/AliceO2Group/AliceO2/pull/5578) 2021-02-27: Misc fixes in propagator by [@shahor02](https://github.com/shahor02) +- [#5583](https://github.com/AliceO2Group/AliceO2/pull/5583) 2021-03-01: Track source masks + possibility to select sources for p.vertexing and cosmics workflows by [@shahor02](https://github.com/shahor02) +- [#5586](https://github.com/AliceO2Group/AliceO2/pull/5586) 2021-03-01: o2-sim: Provide standalone MC header information by [@sawenzel](https://github.com/sawenzel) +## Changes in DataFormats + +- [#5569](https://github.com/AliceO2Group/AliceO2/pull/5569) 2021-02-26: Modifications to auto-detect and decode link-base zero suppression by [@wiechula](https://github.com/wiechula) +- [#5590](https://github.com/AliceO2Group/AliceO2/pull/5590) 2021-03-01: Additional documentation and cleanup for TRAPsim by [@martenole](https://github.com/martenole) +- [#5583](https://github.com/AliceO2Group/AliceO2/pull/5583) 2021-03-01: Track source masks + possibility to select sources for p.vertexing and cosmics workflows by [@shahor02](https://github.com/shahor02) +- [#5586](https://github.com/AliceO2Group/AliceO2/pull/5586) 2021-03-01: o2-sim: Provide standalone MC header information by [@sawenzel](https://github.com/sawenzel) +- [#5598](https://github.com/AliceO2Group/AliceO2/pull/5598) 2021-03-04: Couple of GPU developments by [@davidrohr](https://github.com/davidrohr) +- [#5585](https://github.com/AliceO2Group/AliceO2/pull/5585) 2021-03-05: Raw to digits by [@cortesep](https://github.com/cortesep) +- [#5641](https://github.com/AliceO2Group/AliceO2/pull/5641) 2021-03-06: Complete ZDC CTF content and encoding/decoding workflows by [@shahor02](https://github.com/shahor02) +- [#5597](https://github.com/AliceO2Group/AliceO2/pull/5597) 2021-03-08: add tool for processing cosmics in real time with TOF by [@noferini](https://github.com/noferini) +## Changes in Detectors + +- [#5557](https://github.com/AliceO2Group/AliceO2/pull/5557) 2021-02-26: Compilation fixes by [@davidrohr](https://github.com/davidrohr) +- [#5570](https://github.com/AliceO2Group/AliceO2/pull/5570) 2021-02-26: Fix for the out_of_range exception and small clean-ups by [@nburmaso](https://github.com/nburmaso) +- [#5560](https://github.com/AliceO2Group/AliceO2/pull/5560) 2021-02-26: Fix some codechecker violations by [@davidrohr](https://github.com/davidrohr) +- [#5574](https://github.com/AliceO2Group/AliceO2/pull/5574) 2021-02-26: Fix: MID digi2raw must read configKeyValues by [@shahor02](https://github.com/shahor02) +- [#5569](https://github.com/AliceO2Group/AliceO2/pull/5569) 2021-02-26: Modifications to auto-detect and decode link-base zero suppression by [@wiechula](https://github.com/wiechula) +- [#5578](https://github.com/AliceO2Group/AliceO2/pull/5578) 2021-02-27: Misc fixes in propagator by [@shahor02](https://github.com/shahor02) +- [#5577](https://github.com/AliceO2Group/AliceO2/pull/5577) 2021-02-27: Option to detect TF from orbit and SOX info instead of TType by [@shahor02](https://github.com/shahor02) +- [#5590](https://github.com/AliceO2Group/AliceO2/pull/5590) 2021-03-01: Additional documentation and cleanup for TRAPsim by [@martenole](https://github.com/martenole) +- [#5572](https://github.com/AliceO2Group/AliceO2/pull/5572) 2021-03-01: Fix number of foam wedges at 90deg, add carbon fleece with glue by [@mario6829](https://github.com/mario6829) +- [#5584](https://github.com/AliceO2Group/AliceO2/pull/5584) 2021-03-01: Including Rtypes.h by [@pzhristov](https://github.com/pzhristov) +- [#5583](https://github.com/AliceO2Group/AliceO2/pull/5583) 2021-03-01: Track source masks + possibility to select sources for p.vertexing and cosmics workflows by [@shahor02](https://github.com/shahor02) +- [#5576](https://github.com/AliceO2Group/AliceO2/pull/5576) 2021-03-01: [EMCAL-684] Add mapping for FEC index by [@mfasDa](https://github.com/mfasDa) +- [#5586](https://github.com/AliceO2Group/AliceO2/pull/5586) 2021-03-01: o2-sim: Provide standalone MC header information by [@sawenzel](https://github.com/sawenzel) +- [#5559](https://github.com/AliceO2Group/AliceO2/pull/5559) 2021-03-02: A and C side cables by [@AllaMaevskaya](https://github.com/AllaMaevskaya) +- [#5591](https://github.com/AliceO2Group/AliceO2/pull/5591) 2021-03-02: Fix ITS tracking: async/sync settings swapping, not vertexing in cosmics by [@shahor02](https://github.com/shahor02) +- [#5595](https://github.com/AliceO2Group/AliceO2/pull/5595) 2021-03-02: Remove non-templated DCAFitter (overridden by DCAFitterN) by [@shahor02](https://github.com/shahor02) +- [#5598](https://github.com/AliceO2Group/AliceO2/pull/5598) 2021-03-04: Couple of GPU developments by [@davidrohr](https://github.com/davidrohr) +- [#5613](https://github.com/AliceO2Group/AliceO2/pull/5613) 2021-03-04: Fix delay in raw file reader workflow by [@davidrohr](https://github.com/davidrohr) +- [#5566](https://github.com/AliceO2Group/AliceO2/pull/5566) 2021-03-04: Renaming index columns for TF merging by [@jgrosseo](https://github.com/jgrosseo) +- [#5609](https://github.com/AliceO2Group/AliceO2/pull/5609) 2021-03-04: Upgrade: fix duplicate guard. by [@ktf](https://github.com/ktf) +- [#5585](https://github.com/AliceO2Group/AliceO2/pull/5585) 2021-03-05: Raw to digits by [@cortesep](https://github.com/cortesep) +- [#5614](https://github.com/AliceO2Group/AliceO2/pull/5614) 2021-03-05: Removed overlaps in cdrum by [@MarekKowalski1504](https://github.com/MarekKowalski1504) +- [#5628](https://github.com/AliceO2Group/AliceO2/pull/5628) 2021-03-05: Split tracks table into three tables by [@nburmaso](https://github.com/nburmaso) +- [#5612](https://github.com/AliceO2Group/AliceO2/pull/5612) 2021-03-05: Suppress some info output at higher logging severities by [@davidrohr](https://github.com/davidrohr) +- [#5641](https://github.com/AliceO2Group/AliceO2/pull/5641) 2021-03-06: Complete ZDC CTF content and encoding/decoding workflows by [@shahor02](https://github.com/shahor02) +- [#5639](https://github.com/AliceO2Group/AliceO2/pull/5639) 2021-03-06: RawFileWriter::addData optionally transfers detectoField to RDH by [@shahor02](https://github.com/shahor02) +- [#5644](https://github.com/AliceO2Group/AliceO2/pull/5644) 2021-03-07: Do not limit number of entries RootTreeWriter can store by [@shahor02](https://github.com/shahor02) +- [#5648](https://github.com/AliceO2Group/AliceO2/pull/5648) 2021-03-08: [R3C-469] [MCH] Update Electronic Mapping from Pt2 by [@aphecetche](https://github.com/aphecetche) +- [#5597](https://github.com/AliceO2Group/AliceO2/pull/5597) 2021-03-08: add tool for processing cosmics in real time with TOF by [@noferini](https://github.com/noferini) +## Changes in Examples + +- [#5634](https://github.com/AliceO2Group/AliceO2/pull/5634) 2021-03-08: Added macro to read event info from a Pythia8 heavy-ion simulation he… by [@preghenella](https://github.com/preghenella) +## Changes in Framework + +- [#5563](https://github.com/AliceO2Group/AliceO2/pull/5563) 2021-02-25: DPL: fix memory leak in ws:// driver. by [@ktf](https://github.com/ktf) +- [#5567](https://github.com/AliceO2Group/AliceO2/pull/5567) 2021-02-25: DPL: switch to ws:// as default client for self hosted by [@ktf](https://github.com/ktf) +- [#5561](https://github.com/AliceO2Group/AliceO2/pull/5561) 2021-02-25: Revert "DPL: switch to ws:// as default client for self hosted" by [@ktf](https://github.com/ktf) +- [#5582](https://github.com/AliceO2Group/AliceO2/pull/5582) 2021-02-28: DPL: improve message when driver client is not yet connected by [@ktf](https://github.com/ktf) +- [#5580](https://github.com/AliceO2Group/AliceO2/pull/5580) 2021-03-01: DPL: move can_assign helper to the only used place by [@ktf](https://github.com/ktf) +- [#5587](https://github.com/AliceO2Group/AliceO2/pull/5587) 2021-03-01: DPL: require --aod-writer-keep to be homogeneous by [@ktf](https://github.com/ktf) +- [#5603](https://github.com/AliceO2Group/AliceO2/pull/5603) 2021-03-03: DPL: do not use --driver-client-backend when dumping DDS config by [@alibuild](https://github.com/alibuild) +- [#5596](https://github.com/AliceO2Group/AliceO2/pull/5596) 2021-03-03: Revert "DPL: add wildcards when creating matchers via DataDescriptorQueryBuilder::parse" by [@ktf](https://github.com/ktf) +- [#5610](https://github.com/AliceO2Group/AliceO2/pull/5610) 2021-03-04: Better message by [@jgrosseo](https://github.com/jgrosseo) +- [#5602](https://github.com/AliceO2Group/AliceO2/pull/5602) 2021-03-04: DPL: simplify TableBuilder API by [@alibuild](https://github.com/alibuild) +- [#5601](https://github.com/AliceO2Group/AliceO2/pull/5601) 2021-03-04: DPL: simplify method analysis task introspection by [@alibuild](https://github.com/alibuild) +- [#5599](https://github.com/AliceO2Group/AliceO2/pull/5599) 2021-03-04: Fix for sparse index builder skipping entries by [@aalkin](https://github.com/aalkin) +- [#5566](https://github.com/AliceO2Group/AliceO2/pull/5566) 2021-03-04: Renaming index columns for TF merging by [@jgrosseo](https://github.com/jgrosseo) +- [#5558](https://github.com/AliceO2Group/AliceO2/pull/5558) 2021-03-04: [DPL Analysis] Simple workflow suffix solution by [@saganatt](https://github.com/saganatt) +- [#5611](https://github.com/AliceO2Group/AliceO2/pull/5611) 2021-03-05: Renaming charge() to sign() by [@jgrosseo](https://github.com/jgrosseo) +- [#5633](https://github.com/AliceO2Group/AliceO2/pull/5633) 2021-03-09: Adapting to updated vertex selection in converter by [@jgrosseo](https://github.com/jgrosseo) +- [#5623](https://github.com/AliceO2Group/AliceO2/pull/5623) 2021-03-09: Adding Forward (MFT+Muon) tables by [@jgrosseo](https://github.com/jgrosseo) +- [#5649](https://github.com/AliceO2Group/AliceO2/pull/5649) 2021-03-09: DPL Analysis: avoid std::function in literal node by [@ktf](https://github.com/ktf) +- [#5651](https://github.com/AliceO2Group/AliceO2/pull/5651) 2021-03-09: DPL: proper redirection to --forwarding-destination none by [@ktf](https://github.com/ktf) +- [#5655](https://github.com/AliceO2Group/AliceO2/pull/5655) 2021-03-09: Protect cpuid.h, it cannot be used on Mac M1 by [@pzhristov](https://github.com/pzhristov) +- [#5640](https://github.com/AliceO2Group/AliceO2/pull/5640) 2021-03-09: [DPL Analysis] Canonical task names by [@saganatt](https://github.com/saganatt) +## Changes in Steer + +- [#5575](https://github.com/AliceO2Group/AliceO2/pull/5575) 2021-02-27: MCKinematicsReader: adding destructor by [@matthias-kleiner](https://github.com/matthias-kleiner) +- [#5585](https://github.com/AliceO2Group/AliceO2/pull/5585) 2021-03-05: Raw to digits by [@cortesep](https://github.com/cortesep) +- [#5654](https://github.com/AliceO2Group/AliceO2/pull/5654) 2021-03-09: MCReader: release early by [@sawenzel](https://github.com/sawenzel) +## Changes in Utilities + +- [#5604](https://github.com/AliceO2Group/AliceO2/pull/5604) 2021-03-03: less verbose output from jobutils by [@sawenzel](https://github.com/sawenzel) +- [#5615](https://github.com/AliceO2Group/AliceO2/pull/5615) 2021-03-04: Use o2_add_executable for Data Sampling benchmark workflow by [@knopers8](https://github.com/knopers8) diff --git a/CMakeLists.txt b/CMakeLists.txt index f989fdf44cb9f..aeeef78db4b85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Preamble -cmake_minimum_required(VERSION 3.17 FATAL_ERROR) +cmake_minimum_required(VERSION 3.19 FATAL_ERROR) # it's important to specify accurately the list of languages. for instance C and # C++ as we _do_ have some C files to compile explicitely as C (e.g. gl3w.c) @@ -25,6 +26,15 @@ set(ALIGPU_BUILD_TYPE "O2") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY REPORT_UNDEFINED_PROPERTIES) + +cmake_host_system_information(RESULT _totalmem QUERY TOTAL_PHYSICAL_MEMORY) +math(EXPR _total_analysis_jobs "(${_totalmem}-4096)/10240") +if(_total_analysis_jobs LESS_EQUAL 0) + set(_total_analysis_jobs 1) +endif() +set(ANALYSIS_COMPILE_POOL ${_total_analysis_jobs} CACHE STRING "How many parallel analysis compilation jobs") +set_property(GLOBAL PROPERTY JOB_POOLS analysis=${ANALYSIS_COMPILE_POOL}) + include(O2BuildSanityChecks) o2_build_sanity_checks() set(CMAKE_CXX_STANDARD 17) @@ -39,6 +49,8 @@ if (ENABLE_UPGRADES) add_definitions(-DENABLE_UPGRADES) endif() +add_subdirectory(version) + include(O2DefineOutputPaths) o2_define_output_paths() @@ -84,7 +96,6 @@ add_subdirectory(EventVisualisation) add_subdirectory(Generators) add_subdirectory(Steer) # consider building this only for simulation ? add_subdirectory(prodtests) -add_subdirectory(Analysis) add_subdirectory(scripts) if(BUILD_EXAMPLES) diff --git a/CODEOWNERS b/CODEOWNERS index 33ab2dfb99c6d..b6a00102f5193 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -7,15 +7,11 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence. -# **DO NOT USE** @AliceO2Group/core for anything else. +# **DO NOT USE** @AliceO2Group/core for anything else. * @AliceO2Group/core /Algorithm @matthiasrichter -/Analysis @jgrosseo @iarsene -/Analysis/Tasks/ALICE3 @ginnocen -/Analysis/Tasks/PWGHF @ginnocen - /CCDB @costing @Barthelemy @sawenzel @AliceO2Group/framework-admins /Common @AliceO2Group/framework-admins @@ -29,57 +25,63 @@ #/Common/maps /DataFormats @AliceO2Group/framework-admins +/DataFormats/Detectors/Common @shahor02 /DataFormats/Detectors/CPV @peressounko @kharlov +/DataFormats/Detectors/CTP @lietava /DataFormats/Detectors/EMCAL @mfasDa /DataFormats/Detectors/FIT @AllaMaevskaya @jotwinow @mslupeck /DataFormats/Detectors/GlobalTracking @shahor02 /DataFormats/Detectors/GlobalTrackingWorkflow @shahor02 /DataFormats/Detectors/HMPID @gvolpe79 -/DataFormats/Detectors/ITSMFT @iouribelikov @bovulpes +/DataFormats/Detectors/ITSMFT @iouribelikov @bovulpes @rpezzi /DataFormats/Detectors/MUON @aphecetche /DataFormats/Detectors/PHOS @peressounko @kharlov /DataFormats/Detectors/Passive @sawenzel -/DataFormats/Detectors/TOF @noferini +/DataFormats/Detectors/TOF @noferini /DataFormats/Detectors/TPC @davidrohr @wiechula @shahor02 -/DataFormats/Detectors/TRD @jolopezl @bazinski @tdietel -/DataFormats/Detectors/Upgrades @qgp @marcovanleeuwen +/DataFormats/Detectors/TRD @jolopezl @bazinski @tdietel @martenole +/DataFormats/Detectors/Upgrades @qgp @marcovanleeuwen @mconcas /DataFormats/Detectors/ZDC @coppedis #/DataFormats/Headers #/DataFormats/Legacy #/DataFormats/MemoryResources /DataFormats/Parameters @shahor02 +/DataFormats/QualityControl @knopers8 @Barthelemy @chiarazampolli /DataFormats/Reconstruction @shahor02 #/DataFormats/TimeFrame /DataFormats/common @shahor02 /DataFormats/simulation @sawenzel /Detectors/Base @sawenzel @shahor02 -/Detectors/Geometry @sawenzel @shahor02 +/Detectors/Calibration @chiarazampolli @shahor02 /Detectors/CPV @peressounko @kharlov /Detectors/EMCAL @mfasDa /Detectors/FIT @AllaMaevskaya @jotwinow @mslupeck +/Detectors/Geometry @sawenzel @shahor02 /Detectors/GlobalTracking @shahor02 /Detectors/GlobalTrackingWorkflow @shahor02 /Detectors/HMPID @gvolpe79 -/Detectors/ITSMFT @iouribelikov @bovulpes +/Detectors/ITSMFT @iouribelikov @bovulpes @rpezzi /Detectors/MUON @aphecetche /Detectors/PHOS @peressounko @kharlov /Detectors/Passive @sawenzel -/Detectors/TOF @noferini +/Detectors/TOF @noferini /Detectors/TPC @davidrohr @wiechula @shahor02 -/Detectors/TRD @jolopezl @bazinski @tdietel -/Detectors/Upgrades @qgp @marcovanleeuwen +/Detectors/TRD @jolopezl @bazinski @tdietel @martenole +/Detectors/Upgrades @qgp @marcovanleeuwen @mconcas /Detectors/ZDC @coppedis +/Detectors/CTF @shahor02 +/Detectors/Raw @shahor02 -/EventVisualisation @jmyrcha @AliceO2Group/framework-admins +/EventVisualisation @jmyrcha #/EventVisualisation/Base #/EventVisualisation/DataConverter #/EventVisualisation/Detectors #/EventVisualisation/View #/EventVisualisation/o2eve_config -/Examples +/Examples #/Examples/Ex1 #/Examples/Ex2 #/Examples/Ex3 @@ -109,7 +111,7 @@ /Generators @sawenzel -/Steer @sawenzel @shahor02 @AliceO2Group/framework-admins +/Steer @sawenzel @shahor02 /Testing @@ -119,11 +121,7 @@ #/Utilities/DataCompression #/Utilities/DataFlow #/Utilities/MCStepLogger -#/Utilities/O2Device -#/Utilities/O2MessageMonitor #/Utilities/PCG -#/Utilities/Publishers #/Utilities/Tools -#/Utilities/aliceHLTwrapper #/Utilities/hough /Utilities/rANS @shahor02 @MichaelLettrich diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index af6a678c979a3..bfb4a24ff3bc9 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Constants) add_subdirectory(MathUtils) diff --git a/Common/Constants/CMakeLists.txt b/Common/Constants/CMakeLists.txt index 40fd739c7ecf1..ced8bb7895f95 100644 --- a/Common/Constants/CMakeLists.txt +++ b/Common/Constants/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(CommonConstants) diff --git a/Common/Constants/include/CommonConstants/GeomConstants.h b/Common/Constants/include/CommonConstants/GeomConstants.h new file mode 100644 index 0000000000000..760862384b0f5 --- /dev/null +++ b/Common/Constants/include/CommonConstants/GeomConstants.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GeomConstants.h +/// @brief Some ALICE geometry constants of common interest + +/// @author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_GEOMCONSTANTS_H_ +#define ALICEO2_GEOMCONSTANTS_H_ + +namespace o2 +{ +namespace constants +{ +namespace geom +{ +constexpr float XTPCInnerRef = 83.0; ///< reference radius at which TPC provides the tracks +constexpr float XTPCOuterRef = 255.0; ///< reference radius to propagate outer TPC track +} // namespace geom +} // namespace constants +} // namespace o2 + +#endif diff --git a/Common/Constants/include/CommonConstants/LHCConstants.h b/Common/Constants/include/CommonConstants/LHCConstants.h index ba3cc93331a5a..f831c111da634 100644 --- a/Common/Constants/include/CommonConstants/LHCConstants.h +++ b/Common/Constants/include/CommonConstants/LHCConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,15 +26,31 @@ namespace lhc enum BeamDirection : int { BeamClockWise, BeamAntiClockWise, NBeamDirections }; -static constexpr int LHCMaxBunches = 3564; // max N bunches -static constexpr double LHCRFFreq = 400.789e6; // LHC RF frequency in Hz -static constexpr double LHCBunchSpacingNS = 10 * 1.e9 / LHCRFFreq; // bunch spacing in ns (10 RFbuckets) -static constexpr double LHCOrbitNS = LHCMaxBunches * LHCBunchSpacingNS; // orbit duration in ns -static constexpr double LHCRevFreq = 1.e9 / LHCOrbitNS; // revolution frequency -static constexpr double LHCBunchSpacingMS = LHCBunchSpacingNS * 1e-3; // bunch spacing in ms (10 RFbuckets) -static constexpr double LHCOrbitMS = LHCOrbitNS * 1e-3; // orbit duration in ms - -static constexpr unsigned int MaxNOrbits = 0xffffffff; +constexpr int LHCMaxBunches = 3564; // max N bunches +constexpr double LHCRFFreq = 400.789e6; // LHC RF frequency in Hz +constexpr double LHCBunchSpacingNS = 10 * 1.e9 / LHCRFFreq; // bunch spacing in ns (10 RFbuckets) +constexpr double LHCOrbitNS = LHCMaxBunches * LHCBunchSpacingNS; // orbit duration in ns +constexpr double LHCRevFreq = 1.e9 / LHCOrbitNS; // revolution frequency +constexpr double LHCBunchSpacingMUS = LHCBunchSpacingNS * 1e-3; // bunch spacing in \mus (10 RFbuckets) +constexpr double LHCOrbitMUS = LHCOrbitNS * 1e-3; // orbit duration in \mus +constexpr unsigned int MaxNOrbits = 0xffffffff; + +// Offsets of clockwise and anticlockwise beam bunches at P2 +constexpr int BunchOffsetsP2[2] = {346, 3019}; + +// convert LHC bunch ID to BC for 2 beam directions +constexpr int LHCBunch2P2BC(int bunch, BeamDirection dir) +{ + return (bunch + BunchOffsetsP2[int(dir)]) % LHCMaxBunches; +} + +// convert BC at P2 to LHC bunch ID for 2 beam directions +constexpr int P2BC2LHCBunch(int bc, BeamDirection dir) +{ + int bunch = bc - BunchOffsetsP2[int(dir)]; + return bunch < 0 ? bunch + LHCMaxBunches : bunch; +} + } // namespace lhc } // namespace constants } // namespace o2 diff --git a/Common/Constants/include/CommonConstants/MathConstants.h b/Common/Constants/include/CommonConstants/MathConstants.h index 30c1a7cf436bf..5c3f2ecea6b99 100644 --- a/Common/Constants/include/CommonConstants/MathConstants.h +++ b/Common/Constants/include/CommonConstants/MathConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Constants/include/CommonConstants/PhysicsConstants.h b/Common/Constants/include/CommonConstants/PhysicsConstants.h index b303ec049f90e..4a80c238e391f 100644 --- a/Common/Constants/include/CommonConstants/PhysicsConstants.h +++ b/Common/Constants/include/CommonConstants/PhysicsConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,6 +37,8 @@ constexpr float MassTriton = 2.8089211; constexpr float MassHelium3 = 2.8083916; constexpr float MassAlpha = 3.7273794; constexpr float MassHyperTriton = 2.992; +constexpr float MassXiMinus = 1.32171; +constexpr float MassOmegaMinus = 1.67245; constexpr float LightSpeedCm2S = 299792458.e2; // C in cm/s constexpr float LightSpeedCm2NS = LightSpeedCm2S * 1e-9; // C in cm/ns diff --git a/Common/Constants/include/CommonConstants/Triggers.h b/Common/Constants/include/CommonConstants/Triggers.h index 4b5bb49e94040..1c5702dd3b584 100644 --- a/Common/Constants/include/CommonConstants/Triggers.h +++ b/Common/Constants/include/CommonConstants/Triggers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/CMakeLists.txt b/Common/Field/CMakeLists.txt index 6687f10d7daec..5531132eb9a59 100644 --- a/Common/Field/CMakeLists.txt +++ b/Common/Field/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Field SOURCES src/MagFieldContFact.cxx diff --git a/Common/Field/include/Field/MagFieldContFact.h b/Common/Field/include/Field/MagFieldContFact.h index ca9db4e19fad8..7cfdae740e657 100644 --- a/Common/Field/include/Field/MagFieldContFact.h +++ b/Common/Field/include/Field/MagFieldContFact.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/include/Field/MagFieldFact.h b/Common/Field/include/Field/MagFieldFact.h index d34877b70a28d..bc0b548c36a85 100644 --- a/Common/Field/include/Field/MagFieldFact.h +++ b/Common/Field/include/Field/MagFieldFact.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/include/Field/MagFieldFast.h b/Common/Field/include/Field/MagFieldFast.h index 4d904e7adc464..acff8f528ad06 100644 --- a/Common/Field/include/Field/MagFieldFast.h +++ b/Common/Field/include/Field/MagFieldFast.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -53,6 +54,7 @@ class MagFieldFast bool Field(const double xyz[3], double bxyz[3]) const; bool Field(const float xyz[3], float bxyz[3]) const; bool Field(const math_utils::Point3D<float> xyz, float bxyz[3]) const; + bool Field(const math_utils::Point3D<double> xyz, double bxyz[3]) const; bool GetBcomp(EDim comp, const double xyz[3], double& b) const; bool GetBcomp(EDim comp, const float xyz[3], float& b) const; bool GetBcomp(EDim comp, const math_utils::Point3D<float> xyz, double& b) const; @@ -84,7 +86,7 @@ class MagFieldFast float mFactorSol; // scaling factor SolParam mSolPar[kNSolRRanges][kNSolZRanges][kNQuadrants]; - ClassDef(MagFieldFast, 1); + ClassDefNV(MagFieldFast, 1); }; inline float MagFieldFast::CalcPol(const float* cf, float x, float y, float z) const diff --git a/Common/Field/include/Field/MagFieldParam.h b/Common/Field/include/Field/MagFieldParam.h index 37b3f0a0e99ac..166a8e7296dcc 100644 --- a/Common/Field/include/Field/MagFieldParam.h +++ b/Common/Field/include/Field/MagFieldParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/include/Field/MagneticField.h b/Common/Field/include/Field/MagneticField.h index d4241fe49c498..9496045fd2512 100644 --- a/Common/Field/include/Field/MagneticField.h +++ b/Common/Field/include/Field/MagneticField.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -69,7 +70,7 @@ class MagneticField : public FairField ~MagneticField() override = default; /// create field from rounded value, i.e. +-5 or +-2 kGauss - static MagneticField* createNominalField(int fld); + static MagneticField* createNominalField(int fld, bool uniform = false); /// real field creation is here void CreateField(); @@ -77,6 +78,11 @@ class MagneticField : public FairField /// allow fast field param void AllowFastField(bool v = true); + bool fastFieldExists() const + { + return !(mMapType == MagFieldParam::k5kGUniform || mDipoleOnOffFlag == true); + } + /// Virtual methods from FairField /// X component, avoid using since slow @@ -106,6 +112,35 @@ class MagneticField : public FairField /// Main interface from TVirtualMagField used in simulation void Field(const Double_t* __restrict__ point, Double_t* __restrict__ bField) override; + void field(const math_utils::Point3D<float> xyz, float bxyz[3]) + { + double xyzd[3] = {xyz.X(), xyz.Y(), xyz.Z()}, bxyzd[3] = {0}; + Field(xyzd, bxyzd); + bxyz[0] = bxyzd[0]; + bxyz[1] = bxyzd[1]; + bxyz[2] = bxyzd[2]; + } + + void field(const math_utils::Point3D<double> xyz, double bxyz[3]) + { + double xyzd[3] = {xyz.X(), xyz.Y(), xyz.Z()}; + Field(xyzd, bxyz); + } + + void field(const double* __restrict__ point, double* __restrict__ bField) + { + Field(point, bField); + } + + void field(const float* __restrict__ point, float* __restrict__ bField) + { + double xyz[3] = {point[0], point[1], point[2]}, bxyz[3] = {0}; + Field(xyz, bxyz); + bField[0] = bxyz[0]; + bField[1] = bxyz[1]; + bField[2] = bxyz[2]; + } + /// 3d field query alias for Alias Method to calculate the field at point xyz void GetBxyz(const Double_t p[3], Double_t* b) override { MagneticField::Field(p, b); } diff --git a/Common/Field/include/Field/MagneticWrapperChebyshev.h b/Common/Field/include/Field/MagneticWrapperChebyshev.h index 4f3bd67fc6df0..2e7dea8ab2aad 100644 --- a/Common/Field/include/Field/MagneticWrapperChebyshev.h +++ b/Common/Field/include/Field/MagneticWrapperChebyshev.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/src/FieldLinkDef.h b/Common/Field/src/FieldLinkDef.h index 71f16d0a29f8b..737a73180af76 100644 --- a/Common/Field/src/FieldLinkDef.h +++ b/Common/Field/src/FieldLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/src/MagFieldContFact.cxx b/Common/Field/src/MagFieldContFact.cxx index f280101c20943..bc347adc392af 100644 --- a/Common/Field/src/MagFieldContFact.cxx +++ b/Common/Field/src/MagFieldContFact.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/src/MagFieldFact.cxx b/Common/Field/src/MagFieldFact.cxx index 6f5cfe565382b..a3547987a0766 100644 --- a/Common/Field/src/MagFieldFact.cxx +++ b/Common/Field/src/MagFieldFact.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/src/MagFieldFast.cxx b/Common/Field/src/MagFieldFast.cxx index 34eeadfc3b59c..4d8d1f08e595f 100644 --- a/Common/Field/src/MagFieldFast.cxx +++ b/Common/Field/src/MagFieldFast.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -217,6 +218,22 @@ bool MagFieldFast::Field(const math_utils::Point3D<float> xyz, float bxyz[3]) co return true; } +//_______________________________________________________________________ +bool MagFieldFast::Field(const math_utils::Point3D<double> xyz, double bxyz[3]) const +{ + // get field + int zSeg, rSeg, quadrant; + if (!GetSegment(xyz.X(), xyz.Y(), xyz.Z(), zSeg, rSeg, quadrant)) { + return false; + } + const SolParam* par = &mSolPar[rSeg][zSeg][quadrant]; + bxyz[kX] = CalcPol(par->parBxyz[kX], xyz.X(), xyz.Y(), xyz.Z()) * mFactorSol; + bxyz[kY] = CalcPol(par->parBxyz[kY], xyz.X(), xyz.Y(), xyz.Z()) * mFactorSol; + bxyz[kZ] = CalcPol(par->parBxyz[kZ], xyz.X(), xyz.Y(), xyz.Z()) * mFactorSol; + // + return true; +} + //_______________________________________________________________________ bool MagFieldFast::GetSegment(float x, float y, float z, int& zSeg, int& rSeg, int& quadrant) const { diff --git a/Common/Field/src/MagFieldParam.cxx b/Common/Field/src/MagFieldParam.cxx index dd7fb68978c7f..9af35904c38e7 100644 --- a/Common/Field/src/MagFieldParam.cxx +++ b/Common/Field/src/MagFieldParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/src/MagneticField.cxx b/Common/Field/src/MagneticField.cxx index 3afabde8a0bbb..5d050b724cbde 100644 --- a/Common/Field/src/MagneticField.cxx +++ b/Common/Field/src/MagneticField.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -148,27 +149,33 @@ MagneticField::MagneticField(const MagFieldParam& param) CreateField(); } -MagneticField* MagneticField::createNominalField(int fld) +MagneticField* MagneticField::createNominalField(int fld, bool uniform) { - float fldCoeff; + float fldCoeffL3, fldCoeffDip; o2::field::MagFieldParam::BMap_t fldType; - switch (std::abs(fld)) { - case 5: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - case 0: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = 0; - break; - case 2: - fldType = o2::field::MagFieldParam::k2kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - default: - LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0"; - }; - return new o2::field::MagneticField("Maps", "Maps", fldCoeff, fldCoeff, fldType); + if (uniform) { + fldCoeffL3 = float(fld) / 5.; + fldCoeffDip = fld > 0 ? 1. : -1; + fldType = o2::field::MagFieldParam::k5kGUniform; + } else { + switch (std::abs(fld)) { + case 5: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1; + break; + case 0: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeffL3 = fldCoeffDip = 0; + break; + case 2: + fldType = o2::field::MagFieldParam::k2kG; + fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1; + break; + default: + LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0 or <int_kilogauss>U"; + }; + } + return new o2::field::MagneticField("Maps", "Maps", fldCoeffL3, fldCoeffDip, fldType); } void MagneticField::CreateField() diff --git a/Common/Field/src/MagneticWrapperChebyshev.cxx b/Common/Field/src/MagneticWrapperChebyshev.cxx index db73f2bf7ce45..56442ae8d5fe2 100644 --- a/Common/Field/src/MagneticWrapperChebyshev.cxx +++ b/Common/Field/src/MagneticWrapperChebyshev.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Field/test/testMagneticField.cxx b/Common/Field/test/testMagneticField.cxx index 7a1935d9fb0a1..f5b5dbad8eb2d 100644 --- a/Common/Field/test/testMagneticField.cxx +++ b/Common/Field/test/testMagneticField.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/CMakeLists.txt b/Common/MathUtils/CMakeLists.txt index 0fa418fb1c385..5b24fcfcdf7c3 100644 --- a/Common/MathUtils/CMakeLists.txt +++ b/Common/MathUtils/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( MathUtils @@ -33,7 +34,8 @@ o2_target_root_dictionary( include/MathUtils/CartesianGPU.h include/MathUtils/CachingTF1.h include/MathUtils/RandomRing.h - include/MathUtils/Primitive2D.h) + include/MathUtils/Primitive2D.h + include/MathUtils/SMatrixGPU.h) o2_add_test( CachingTF1 diff --git a/Common/MathUtils/include/MathUtils/CachingTF1.h b/Common/MathUtils/include/MathUtils/CachingTF1.h index 4c3b64915b250..1ab656b7fa92e 100644 --- a/Common/MathUtils/include/MathUtils/CachingTF1.h +++ b/Common/MathUtils/include/MathUtils/CachingTF1.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/include/MathUtils/Cartesian.h b/Common/MathUtils/include/MathUtils/Cartesian.h index 82f9acfdd1aaf..14509def6efb1 100644 --- a/Common/MathUtils/include/MathUtils/Cartesian.h +++ b/Common/MathUtils/include/MathUtils/Cartesian.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,9 @@ #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" -#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) +#if (!defined(GPUCA_STANDALONE) || !defined(DGPUCA_NO_ROOT)) && !defined(GPUCA_GPUCODE) && !defined(GPUCOMMONRTYPES_H_ACTIVE) +#include <Math/SMatrix.h> +#include <Math/SVector.h> #include <Math/GenVector/DisplacementVector3D.h> #include <Math/GenVector/PositionVector3D.h> #include <Math/GenVector/Rotation3D.h> @@ -30,8 +33,11 @@ #else #include "GPUCommonMath.h" #include "CartesianGPU.h" +#include "SMatrixGPU.h" + #endif #include "GPUROOTCartesianFwd.h" +#include "GPUROOTSMatrixFwd.h" namespace o2 { @@ -145,7 +151,7 @@ class Rotation2D using Rotation2Df_t = Rotation2D<float>; using Rotation2Dd_t = Rotation2D<double>; -#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_ALIGPUCODE) +#if (!defined(GPUCA_STANDALONE) || !defined(DGPUCA_NO_ROOT)) && !defined(GPUCA_GPUCODE) && !defined(GPUCOMMONRTYPES_H_ACTIVE) class Transform3D : public ROOT::Math::Transform3D { @@ -244,7 +250,7 @@ class Transform3D : public ROOT::Math::Transform3D } // namespace math_utils } // namespace o2 -#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_ALIGPUCODE) +#if (!defined(GPUCA_STANDALONE) || !defined(DGPUCA_NO_ROOT)) && !defined(GPUCA_GPUCODE) && !defined(GPUCOMMONRTYPES_H_ACTIVE) std::ostream& operator<<(std::ostream& os, const o2::math_utils::Rotation2Df_t& t); std::ostream& operator<<(std::ostream& os, const o2::math_utils::Rotation2Dd_t& t); diff --git a/Common/MathUtils/include/MathUtils/CartesianGPU.h b/Common/MathUtils/include/MathUtils/CartesianGPU.h index 93cc00633dd2d..dbde12d7e9ea9 100644 --- a/Common/MathUtils/include/MathUtils/CartesianGPU.h +++ b/Common/MathUtils/include/MathUtils/CartesianGPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,8 @@ #ifndef ALICEO2_CARTESIANGPU_H #define ALICEO2_CARTESIANGPU_H +#include "GPUCommonDef.h" + namespace o2::math_utils { @@ -21,25 +24,25 @@ namespace detail { template <typename T, int I> struct GPUPoint2D { - GPUPoint2D() = default; - GPUPoint2D(T a, T b) : xx(a), yy(b) {} + GPUdDefault() GPUPoint2D() = default; + GPUd() GPUPoint2D(T a, T b) : xx(a), yy(b) {} + GPUd() float X() const { return xx; } + GPUd() float Y() const { return yy; } + GPUd() float R() const { return o2::gpu::CAMath::Sqrt(xx * xx + yy * yy); } + GPUd() void SetX(float v) { xx = v; } + GPUd() void SetY(float v) { yy = v; } T xx; T yy; - float X() const { return xx; } - float Y() const { return yy; } - float R() const { return o2::gpu::CAMath::Sqrt(xx * xx + yy * yy); } - void SetX(float v) { xx = v; } - void SetY(float v) { yy = v; } }; template <typename T, int I> struct GPUPoint3D : public GPUPoint2D<T, I> { - GPUPoint3D() = default; - GPUPoint3D(T a, T b, T c) : GPUPoint2D<T, I>(a, b), zz(c) {} + GPUdDefault() GPUPoint3D() = default; + GPUd() GPUPoint3D(T a, T b, T c) : GPUPoint2D<T, I>(a, b), zz(c) {} + GPUd() float Z() const { return zz; } + GPUd() float R() const { return o2::gpu::CAMath::Sqrt(GPUPoint2D<T, I>::xx * GPUPoint2D<T, I>::xx + GPUPoint2D<T, I>::yy * GPUPoint2D<T, I>::yy + zz * zz); } + GPUd() void SetZ(float v) { zz = v; } T zz; - float Z() const { return zz; } - float R() const { return o2::gpu::CAMath::Sqrt(GPUPoint2D<T, I>::xx * GPUPoint2D<T, I>::xx + GPUPoint2D<T, I>::yy * GPUPoint2D<T, I>::yy + zz * zz); } - void SetZ(float v) { zz = v; } }; } // namespace detail diff --git a/Common/MathUtils/include/MathUtils/Chebyshev3D.h b/Common/MathUtils/include/MathUtils/Chebyshev3D.h index 7fcbd52f0e18f..3ffdf3abc328f 100644 --- a/Common/MathUtils/include/MathUtils/Chebyshev3D.h +++ b/Common/MathUtils/include/MathUtils/Chebyshev3D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/include/MathUtils/Chebyshev3DCalc.h b/Common/MathUtils/include/MathUtils/Chebyshev3DCalc.h index 6696f7be41852..0db2ec49ef752 100644 --- a/Common/MathUtils/include/MathUtils/Chebyshev3DCalc.h +++ b/Common/MathUtils/include/MathUtils/Chebyshev3DCalc.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/include/MathUtils/Primitive2D.h b/Common/MathUtils/include/MathUtils/Primitive2D.h index 1d69fda1f8710..052926d111594 100644 --- a/Common/MathUtils/include/MathUtils/Primitive2D.h +++ b/Common/MathUtils/include/MathUtils/Primitive2D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/include/MathUtils/RandomRing.h b/Common/MathUtils/include/MathUtils/RandomRing.h index 37ed564772e54..59825f0a0ce09 100644 --- a/Common/MathUtils/include/MathUtils/RandomRing.h +++ b/Common/MathUtils/include/MathUtils/RandomRing.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,21 +29,19 @@ #ifndef ALICEO2_MATHUTILS_RANDOMRING_H_ #define ALICEO2_MATHUTILS_RANDOMRING_H_ -#include "Vc/Vc" #include <array> #include "TF1.h" #include "TRandom.h" #include <functional> -using float_v = Vc::float_v; namespace o2 { namespace math_utils { -template <size_t N = float_v::size() * 100000> +template <size_t N = 4 * 100000> class RandomRing { public: @@ -92,10 +91,15 @@ class RandomRing /// used for vectorised programming and increases the buffer /// position by the size of the vector /// @return vector with random values - float_v getNextValueVc() + template <typename VcType> + VcType getNextValueVc() { - const float_v value = float_v(&mRandomNumbers[mRingPosition]); - mRingPosition += float_v::size(); + // This function is templated so that we don't need to include the <Vc/Vc> header + // within this header file (to reduce memory problems during compilation). + // The hope is that the calling user calls this with a + // correct Vc type (Vc::float_v) in a source file. + const VcType value = VcType(&mRandomNumbers[mRingPosition]); + mRingPosition += VcType::size(); if (mRingPosition >= mRandomNumbers.size()) { mRingPosition = 0; } diff --git a/Common/MathUtils/include/MathUtils/SMatrixGPU.h b/Common/MathUtils/include/MathUtils/SMatrixGPU.h new file mode 100644 index 0000000000000..2faaf118d1daa --- /dev/null +++ b/Common/MathUtils/include/MathUtils/SMatrixGPU.h @@ -0,0 +1,1471 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SMatrixGPU.h +/// \author Matteo Concas mconcas@cern.ch +/// \brief This is a close porting of the SMatrix and SVectorGPU ROOT interfaces. +/// Only parts strictly requiring STD library have been changed. +/// Also some utilities to have basic checks and printouts working on GPUs have been rewritten. +/// +/// Notably only templated implementation of +/// row_offsets_utils::make and row_offsets_utils::do_make +/// has been reworked to support gpustd::array as backend. +/// +/// Other than that, the author is not taking any credit on the methodologies implemented +/// which have been taken straight from root source code +/// +/// Original sources are on the official website: +/// - https://root.cern.ch + +#ifndef ALICEO2_SMATRIX_GPU_H +#define ALICEO2_SMATRIX_GPU_H + +#include "GPUCommonDef.h" +#include "GPUCommonArray.h" +#include "GPUCommonMath.h" +#include "GPUCommonAlgorithm.h" + +namespace o2::math_utils +{ +template <bool> +struct Check { + GPUd() Check(void*) {} +}; +template <> +struct Check<false> { +}; + +#define GPU_STATIC_CHECK(expr, msg) \ + { \ + class ERROR_##msg \ + { \ + }; \ + ERROR_##msg e; \ + (void)(Check<(expr) != 0>(&e)); \ + } + +template <typename T, unsigned int N> +class SVectorGPU +{ + public: + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + GPUd() iterator begin(); + GPUd() iterator end(); + GPUd() const_iterator begin() const; + GPUd() const_iterator end() const; + GPUd() SVectorGPU(); + GPUd() SVectorGPU(const SVectorGPU<T, N>& rhs); + + GPUd() const T& operator[](unsigned int i) const; + GPUd() const T& operator()(unsigned int i) const; + GPUd() T& operator[](unsigned int i); + GPUd() T& operator()(unsigned int i); + GPUd() const T* Array() const; + GPUd() T* Array(); + GPUd() T apply(unsigned int i) const; + + // Operators + GPUd() SVectorGPU<T, N>& operator-=(const SVectorGPU<T, N>& rhs); + GPUd() SVectorGPU<T, N>& operator+=(const SVectorGPU<T, N>& rhs); + + enum { + kSize = N + }; + + GPUdi() static unsigned int Dim() { return N; } + + private: + T mArray[N]; +}; + +template <class T, unsigned int D> +GPUdi() T* SVectorGPU<T, D>::begin() +{ + return mArray; +} + +template <class T, unsigned int D> +GPUdi() const T* SVectorGPU<T, D>::begin() const +{ + return mArray; +} + +template <class T, unsigned int D> +GPUdi() T* SVectorGPU<T, D>::end() +{ + return mArray + Dim(); +} + +template <class T, unsigned int D> +GPUdi() const T* SVectorGPU<T, D>::end() const +{ + return mArray + Dim(); +} +template <class T, unsigned int N> + +GPUdi() const T& SVectorGPU<T, N>::operator[](unsigned int i) const +{ + return mArray[i]; +} + +template <class T, unsigned int N> +GPUdi() const T& SVectorGPU<T, N>::operator()(unsigned int i) const +{ + return mArray[i]; +} + +template <class T, unsigned int N> +GPUdi() T& SVectorGPU<T, N>::operator[](unsigned int i) +{ + return mArray[i]; +} + +template <class T, unsigned int N> +GPUdi() T& SVectorGPU<T, N>::operator()(unsigned int i) +{ + return mArray[i]; +} + +template <class T, unsigned int N> +GPUd() SVectorGPU<T, N>::SVectorGPU() +{ + for (unsigned int i = 0; i < N; ++i) { + mArray[i] = 7; + } +} + +template <class T, unsigned int N> +GPUd() SVectorGPU<T, N>::SVectorGPU(const SVectorGPU<T, N>& rhs) +{ + for (unsigned int i = 0; i < N; ++i) { + mArray[i] = rhs.mArray[i]; + } +} + +template <class T, unsigned int D> +GPUdi() T SVectorGPU<T, D>::apply(unsigned int i) const +{ + return mArray[i]; +} + +template <class T, unsigned int D> +GPUdi() const T* SVectorGPU<T, D>::Array() const +{ + return mArray; +} + +template <class T, unsigned int D> +GPUdi() T* SVectorGPU<T, D>::Array() +{ + return mArray; +} + +template <unsigned int I> +struct meta_dot { + template <class A, class B, class T> + static GPUdi() T f(const A& lhs, const B& rhs, const T& x) + { + return lhs.apply(I) * rhs.apply(I) + meta_dot<I - 1>::f(lhs, rhs, x); + } +}; + +template <> +struct meta_dot<0> { + template <class A, class B, class T> + static GPUdi() T f(const A& lhs, const B& rhs, const T& /*x */) + { + return lhs.apply(0) * rhs.apply(0); + } +}; + +template <class T, unsigned int D> +GPUdi() T Dot(const SVectorGPU<T, D>& lhs, const SVectorGPU<T, D>& rhs) +{ + return meta_dot<D - 1>::f(lhs, rhs, T()); +} + +template <class T, unsigned int D> +GPUdi() SVectorGPU<T, D>& SVectorGPU<T, D>::operator-=(const SVectorGPU<T, D>& rhs) +{ + for (unsigned int i = 0; i < D; ++i) { + mArray[i] -= rhs.apply(i); + } + return *this; +} + +template <class T, unsigned int D> +GPUd() SVectorGPU<T, D>& SVectorGPU<T, D>::operator+=(const SVectorGPU<T, D>& rhs) +{ + for (unsigned int i = 0; i < D; ++i) { + mArray[i] += rhs.apply(i); + } + return *this; +} + +template <unsigned int I> +struct meta_matrix_dot { + + template <class MatrixA, class MatrixB> + static GPUdi() typename MatrixA::value_type f(const MatrixA& lhs, + const MatrixB& rhs, + const unsigned int offset) + { + return lhs.apply(offset / MatrixB::kCols * MatrixA::kCols + I) * + rhs.apply(MatrixB::kCols * I + offset % MatrixB::kCols) + + meta_matrix_dot<I - 1>::f(lhs, rhs, offset); + } + + template <class MatrixA, class MatrixB> + static GPUdi() typename MatrixA::value_type g(const MatrixA& lhs, + const MatrixB& rhs, + unsigned int i, + unsigned int j) + { + return lhs(i, I) * rhs(I, j) + + meta_matrix_dot<I - 1>::g(lhs, rhs, i, j); + } +}; + +template <> +struct meta_matrix_dot<0> { + + template <class MatrixA, class MatrixB> + static GPUdi() typename MatrixA::value_type f(const MatrixA& lhs, + const MatrixB& rhs, + const unsigned int offset) + { + return lhs.apply(offset / MatrixB::kCols * MatrixA::kCols) * + rhs.apply(offset % MatrixB::kCols); + } + + // multiplication using i and j + template <class MatrixA, class MatrixB> + static GPUdi() typename MatrixA::value_type g(const MatrixA& lhs, + const MatrixB& rhs, + unsigned int i, unsigned int j) + { + return lhs(i, 0) * rhs(0, j); + } +}; + +namespace row_offsets_utils +{ +template <int...> +struct indices { +}; + +template <int I, class IndexTuple, int N> +struct make_indices_impl; + +template <int I, int... Indices, int N> +struct make_indices_impl<I, indices<Indices...>, N> { + typedef typename make_indices_impl<I + 1, indices<Indices..., I>, + N>::type type; +}; + +template <int N, int... Indices> +struct make_indices_impl<N, indices<Indices...>, N> { + typedef indices<Indices...> type; +}; + +template <int N> +struct make_indices : make_indices_impl<0, indices<>, N> { +}; + +template <int I0, class F, int... I> +constexpr auto do_make(F f, indices<I...>) -> gpu::gpustd::array<int, sizeof...(I)> +{ + gpu::gpustd::array<int, sizeof...(I)> retarr = {f(I0 + I)...}; + return retarr; +} + +template <int N, int I0 = 0, class F> +constexpr auto make(F f) -> gpu::gpustd::array<int, N> +{ + return do_make<I0>(f, typename make_indices<N>::type()); +} +} // namespace row_offsets_utils + +// Symm representation +template <class T, unsigned int D> +class MatRepSymGPU +{ + public: + typedef T value_type; + GPUdDefault() MatRepSymGPU() = default; + GPUdi() T& operator()(unsigned int i, unsigned int j) + { + return mArray[offset(i, j)]; + } + + GPUdi() T const& operator()(unsigned int i, unsigned int j) const + { + return mArray[offset(i, j)]; + } + + GPUdi() T& operator[](unsigned int i) + { + return mArray[off(i)]; + } + + GPUdi() T const& operator[](unsigned int i) const + { + return mArray[off(i)]; + } + + GPUdi() T apply(unsigned int i) const + { + return mArray[off(i)]; + } + + GPUdi() T* Array() { return mArray; } + + GPUdi() const T* Array() const { return mArray; } + + // assignment: only symmetric to symmetric allowed + template <class R> + GPUdi() MatRepSymGPU<T, D>& operator=(const R&) + { + GPU_STATIC_CHECK(0 == 1, Check_symmetric_matrices_equivalence); + return *this; + } + + GPUdi() MatRepSymGPU<T, D>& operator=(const MatRepSymGPU& rhs) + { + for (unsigned int i = 0; i < kSize; ++i) { + mArray[i] = rhs.Array()[i]; + } + return *this; + } + + enum { + kRows = D, // rows + kCols = D, // columns + kSize = D * (D + 1) / 2 // rows*columns + }; + + static constexpr int off0(int i) { return i == 0 ? 0 : off0(i - 1) + i; } + static constexpr int off2(int i, int j) { return j < i ? off0(i) + j : off0(j) + i; } + static constexpr int off1(int i) { return off2(i / D, i % D); } + + static GPUdi() int off(int i) + { + static constexpr auto v = row_offsets_utils::make<D * D>(off1); + return v[i]; + } + + static GPUdi() constexpr unsigned int offset(unsigned int i, unsigned int j) + { + return off(i * D + j); + } + + private: + T mArray[kSize]; +}; + +/// SMatReprStd starting port here +template <class T, unsigned int D1, unsigned int D2 = D1> +class MatRepStdGPU +{ + public: + typedef T value_type; + GPUdDefault() MatRepStdGPU() = default; + GPUdi() const T& operator()(unsigned int i, unsigned int j) const + { + return mArray[i * D2 + j]; + } + GPUdi() T& operator()(unsigned int i, unsigned int j) + { + return mArray[i * D2 + j]; + } + GPUdi() T& operator[](unsigned int i) { return mArray[i]; } + GPUdi() const T& operator[](unsigned int i) const { return mArray[i]; } + GPUdi() T apply(unsigned int i) const { return mArray[i]; } + GPUdi() T* Array() { return mArray; } + GPUdi() const T* Array() const { return mArray; } + + template <class R> + GPUdi() MatRepStdGPU<T, D1, D2>& operator=(const R& rhs) + { + for (unsigned int i = 0; i < kSize; ++i) { + mArray[i] = rhs[i]; + } + return *this; + } + template <class R> + GPUdi() bool operator==(const R& rhs) const + { + bool rc = true; + for (unsigned int i = 0; i < kSize; ++i) { + rc = rc && (mArray[i] == rhs[i]); + } + return rc; + } + enum { + kRows = D1, // rows + kCols = D2, // columns + kSize = D1 * D2 // rows*columns + }; + + private: + T mArray[kSize]; +}; + +/// SMatrixGPU starting port here +struct SMatrixIdentity { +}; +struct SMatrixNoInit { +}; + +// Expression utility to describe operations +template <class ExprType, class T, unsigned int D, unsigned int D2 = 1, class R1 = MatRepStdGPU<T, D, D2>> +class Expr +{ + public: + typedef T value_type; + GPUd() Expr(const ExprType& rhs) : mRhs(rhs) {} // NOLINT: False positive + GPUdDefault() ~Expr() = default; + GPUdi() T apply(unsigned int i) const + { + return mRhs.apply(i); + } + GPUdi() T operator()(unsigned int i, unsigned j) const + { + return mRhs(i, j); + } + GPUdi() bool IsInUse(const T* p) const + { + return mRhs.IsInUse(p); + } + + enum { + kRows = D, + kCols = D2 + }; + + private: + ExprType mRhs; +}; + +template <class T, unsigned int D1, unsigned int D2 = D1, class R = MatRepStdGPU<T, D1, D2>> +class SMatrixGPU +{ + public: + typedef T value_type; + typedef R rep_type; + typedef T* iterator; + typedef const T* const_iterator; + GPUdDefault() SMatrixGPU() = default; + GPUdi() SMatrixGPU(SMatrixNoInit) {} + GPUd() SMatrixGPU(SMatrixIdentity); + GPUd() SMatrixGPU(const SMatrixGPU<T, D1, D2, R>& rhs); + template <class A, class R2> + GPUd() SMatrixGPU(const Expr<A, T, D1, D2, R2>& rhs); + template <class M> + GPUd() SMatrixGPU<T, D1, D2, R>& operator=(const M& rhs); + template <class A, class R2> + GPUd() SMatrixGPU<T, D1, D2, R>& operator=(const Expr<A, T, D1, D2, R2>& rhs); + enum { + kRows = D1, // rows + kCols = D2, // columns + kSize = D1 * D2 // rows*columns + }; + GPUd() T apply(unsigned int i) const; + GPUd() const T* Array() const; + GPUd() T* Array(); + GPUd() iterator begin(); + GPUd() iterator end(); + GPUd() const T& operator()(unsigned int i, unsigned int j) const; + GPUd() T& operator()(unsigned int i, unsigned int j); + + class SMatrixRowGPU + { + public: + GPUd() SMatrixRowGPU(SMatrixGPU<T, D1, D2, R>& rhs, unsigned int i) : mMat(&rhs), mRow(i) + { + } + GPUd() T& operator[](int j) { return (*mMat)(mRow, j); } + // + private: + SMatrixGPU<T, D1, D2, R>* mMat; + unsigned int mRow; + }; + + class SMatrixRowGPUconst + { + public: + GPUd() SMatrixRowGPUconst(const SMatrixGPU<T, D1, D2, R>& rhs, unsigned int i) : mMat(&rhs), mRow(i) + { + } + // + GPUd() const T& operator[](int j) const { return (*mMat)(mRow, j); } + // + private: + const SMatrixGPU<T, D1, D2, R>* mMat; + unsigned int mRow; + }; + + GPUd() SMatrixRowGPUconst operator[](unsigned int i) const { return SMatrixRowGPUconst(*this, i); } + GPUd() SMatrixRowGPU operator[](unsigned int i) { return SMatrixRowGPU(*this, i); } + GPUd() bool Invert(); + GPUd() bool IsInUse(const T* p) const; + + public: + R mRep; +}; + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() SMatrixGPU<T, D1, D2, R>::SMatrixGPU(SMatrixIdentity) +{ + for (unsigned int i = 0; i < R::kSize; ++i) { + mRep.Array()[i] = 0; + } + if (D1 <= D2) { + for (unsigned int i = 0; i < D1; ++i) { + mRep[i * D2 + i] = 1; + } + } else { + for (unsigned int i = 0; i < D2; ++i) { + mRep[i * D2 + i] = 1; + } + } +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() SMatrixGPU<T, D1, D2, R>::SMatrixGPU(const SMatrixGPU<T, D1, D2, R>& rhs) +{ + mRep = rhs.mRep; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() T* SMatrixGPU<T, D1, D2, R>::begin() +{ + return mRep.Array(); +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() T* SMatrixGPU<T, D1, D2, R>::end() +{ + return mRep.Array() + R::kSize; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() bool SMatrixGPU<T, D1, D2, R>::IsInUse(const T* p) const +{ + return p == mRep.Array(); +} + +template <class T, unsigned int D1, unsigned int D2, class A, class R1, class R2> +struct Assign { + // Evaluate the expression from general to general matrices. + GPUd() static void Evaluate(SMatrixGPU<T, D1, D2, R1>& lhs, const Expr<A, T, D1, D2, R2>& rhs) + { + if (!rhs.IsInUse(lhs.begin())) { + unsigned int l = 0; + for (unsigned int i = 0; i < D1; ++i) { + for (unsigned int j = 0; j < D2; ++j) { + lhs.mRep[l] = rhs(i, j); + l++; + } + } + } else { + T tmp[D1 * D2]; + unsigned int l = 0; + for (unsigned int i = 0; i < D1; ++i) { + for (unsigned int j = 0; j < D2; ++j) { + tmp[l] = rhs(i, j); + l++; + } + } + + for (unsigned int i = 0; i < D1 * D2; ++i) { + lhs.mRep[i] = tmp[i]; + } + } + } +}; + +template <class T, unsigned int D1, unsigned int D2, class A> +struct Assign<T, D1, D2, A, MatRepSymGPU<T, D1>, MatRepSymGPU<T, D1>> { + // Evaluate the expression from symmetric to symmetric matrices. + GPUd() static void Evaluate(SMatrixGPU<T, D1, D2, MatRepSymGPU<T, D1>>& lhs, + const Expr<A, T, D1, D2, MatRepSymGPU<T, D1>>& rhs) + { + if (!rhs.IsInUse(lhs.begin())) { + unsigned int l = 0; + for (unsigned int i = 0; i < D1; ++i) { + // storage of symmetric matrix is in lower block + for (unsigned int j = 0; j <= i; ++j) { + lhs.mRep.Array()[l] = rhs(i, j); + l++; + } + } + } else { + T tmp[MatRepSymGPU<T, D1>::kSize]; + unsigned int l = 0; + for (unsigned int i = 0; i < D1; ++i) { + for (unsigned int j = 0; j <= i; ++j) { + tmp[l] = rhs(i, j); + l++; + } + } + for (unsigned int i = 0; i < MatRepSymGPU<T, D1>::kSize; ++i) { + lhs.mRep.Array()[i] = tmp[i]; + } + } + } +}; + +// avoid assigment from expression based on a general matrix to a symmetric matrix +template <class T, unsigned int D1, unsigned int D2, class A> +struct Assign<T, D1, D2, A, MatRepSymGPU<T, D1>, MatRepStdGPU<T, D1, D2>> { + GPUd() static void Evaluate(SMatrixGPU<T, D1, D2, MatRepSymGPU<T, D1>>&, + const Expr<A, T, D1, D2, MatRepStdGPU<T, D1, D2>>&) + { + GPU_STATIC_CHECK(0 == 1, Check_general_to_symmetric_matrix_assignment); + } +}; + +// Force Expression evaluation from general to symmetric +struct AssignSym { + // assign a symmetric matrix from an expression + template <class T, unsigned int D, class A, class R> + GPUd() static void Evaluate(SMatrixGPU<T, D, D, MatRepSymGPU<T, D>>& lhs, const Expr<A, T, D, D, R>& rhs) + { + unsigned int l = 0; + for (unsigned int i = 0; i < D; ++i) { + for (unsigned int j = 0; j <= i; ++j) { + lhs.mRep.Array()[l] = rhs(i, j); + l++; + } + } + } + + // assign the symmetric matrix from a general matrix + template <class T, unsigned int D, class R> + GPUd() static void Evaluate(SMatrixGPU<T, D, D, MatRepSymGPU<T, D>>& lhs, const SMatrixGPU<T, D, D, R>& rhs) + { + unsigned int l = 0; + for (unsigned int i = 0; i < D; ++i) { + for (unsigned int j = 0; j <= i; ++j) { + lhs.mRep.Array()[l] = rhs(i, j); + l++; + } + } + } +}; + +template <class T, unsigned int D1, unsigned int D2, class R> +template <class A, class R2> +GPUdi() SMatrixGPU<T, D1, D2, R>& SMatrixGPU<T, D1, D2, R>::operator=(const Expr<A, T, D1, D2, R2>& rhs) +{ + Assign<T, D1, D2, A, R, R2>::Evaluate(*this, rhs); + return *this; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +template <class M> +GPUdi() SMatrixGPU<T, D1, D2, R>& SMatrixGPU<T, D1, D2, R>::operator=(const M& rhs) +{ + mRep = rhs.mRep; + return *this; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +template <class A, class R2> +GPUdi() SMatrixGPU<T, D1, D2, R>::SMatrixGPU(const Expr<A, T, D1, D2, R2>& rhs) +{ + operator=(rhs); +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() const T& SMatrixGPU<T, D1, D2, R>::operator()(unsigned int i, unsigned int j) const +{ + return mRep(i, j); +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() T& SMatrixGPU<T, D1, D2, R>::operator()(unsigned int i, unsigned int j) +{ + return mRep(i, j); +} + +template <class T, class R1, class R2> +struct MultPolicyGPU { + enum { + N1 = R1::kRows, + N2 = R2::kCols + }; + typedef MatRepStdGPU<T, N1, N2> RepType; +}; + +template <class MatrixA, class MatrixB, class T, unsigned int D> +class MatrixMulOpGPU +{ + public: + GPUd() MatrixMulOpGPU(const MatrixA& lhs, const MatrixB& rhs) : lhs_(lhs), rhs_(rhs) {} + GPUdDefault() ~MatrixMulOpGPU() = default; + GPUdi() T apply(unsigned int i) const + { + return meta_matrix_dot<D - 1>::f(lhs_, rhs_, i); + } + + GPUdi() T operator()(unsigned int i, unsigned int j) const + { + return meta_matrix_dot<D - 1>::g(lhs_, rhs_, i, j); + } + + GPUdi() bool IsInUse(const T* p) const + { + return lhs_.IsInUse(p) || rhs_.IsInUse(p); + } + + protected: + const MatrixA& lhs_; + const MatrixB& rhs_; +}; + +template <class T, unsigned int D1, unsigned int D, unsigned int D2, class R1, class R2> +GPUdi() Expr<MatrixMulOpGPU<SMatrixGPU<T, D1, D, R1>, SMatrixGPU<T, D, D2, R2>, T, D>, T, D1, D2, typename MultPolicyGPU<T, R1, R2>::RepType> + operator*(const SMatrixGPU<T, D1, D, R1>& lhs, const SMatrixGPU<T, D, D2, R2>& rhs) +{ + typedef MatrixMulOpGPU<SMatrixGPU<T, D1, D, R1>, SMatrixGPU<T, D, D2, R2>, T, D> MatMulOp; + return Expr<MatMulOp, T, D1, D2, + typename MultPolicyGPU<T, R1, R2>::RepType>(MatMulOp(lhs, rhs)); +} + +/// Inversion +template <unsigned int D, unsigned int N = D> +class Inverter +{ + public: + // generic square matrix using LU factorization + template <class MatrixRep> + GPUd() static bool Dinv(MatrixRep& rhs) + { + unsigned int work[N + 1] = {0}; + typename MatrixRep::value_type det(0.0); + + if (DfactMatrix(rhs, det, work) != 0) { + return false; + } + + int ifail = DfinvMatrix(rhs, work); + if (ifail == 0) { + return true; + } + return false; + } + + // symmetric matrix inversion (Bunch-kaufman pivoting) + template <class T> + GPUd() static bool Dinv(MatRepSymGPU<T, D>& rhs) + { + int ifail{0}; + InvertBunchKaufman(rhs, ifail); + if (!ifail) { + return true; + } + return false; + } + + // LU Factorization method for inversion of general square matrices + template <class T> + GPUd() static int DfactMatrix(MatRepStdGPU<T, D, N>& rhs, T& det, unsigned int* work); + + // LU inversion of general square matrices. To be called after DFactMatrix + template <class T> + GPUd() static int DfinvMatrix(MatRepStdGPU<T, D, N>& rhs, unsigned int* work); + + // Bunch-Kaufman method for inversion of symmetric matrices + template <class T> + GPUd() static void InvertBunchKaufman(MatRepSymGPU<T, D>& rhs, int& ifail); +}; + +template <unsigned int D, unsigned int N> +template <class T> +GPUdi() void Inverter<D, N>::InvertBunchKaufman(MatRepSymGPU<T, D>& rhs, int& ifail) +{ + typedef T value_type; + int i, j, k, s; + int pivrow; + const int nrow = MatRepSymGPU<T, D>::kRows; + + SVectorGPU<T, MatRepSymGPU<T, D>::kRows> xvec; + SVectorGPU<int, MatRepSymGPU<T, D>::kRows> pivv; + + typedef int* pivIter; + typedef T* mIter; + + mIter x = xvec.begin(); + // x[i] is used as helper storage, needs to have at least size nrow. + pivIter piv = pivv.begin(); + // piv[i] is used to store details of exchanges + + value_type temp1, temp2; + mIter ip, mjj, iq; + value_type lambda, sigma; + const value_type alpha = .6404; // = (1+sqrt(17))/8 + // LM (04/2009) remove this useless check (it is not in LAPACK) which fails inversion of + // a matrix with values < epsilon in the diagonal + // + // const double epsilon = 32*std::numeric_limits<T>::epsilon(); + // whenever a sum of two doubles is below or equal to epsilon + // it is set to zero. + // this constant could be set to zero but then the algorithm + // doesn't neccessarily detect that a matrix is singular + + for (i = 0; i < nrow; i++) { + piv[i] = i + 1; + } + + ifail = 0; + + // compute the factorization P*A*P^T = L * D * L^T + // L is unit lower triangular, D is direct sum of 1x1 and 2x2 matrices + // L and D^-1 are stored in A = *this, P is stored in piv[] + + for (j = 1; j < nrow; j += s) // main loop over columns + { + mjj = rhs.Array() + j * (j - 1) / 2 + j - 1; + lambda = 0; // compute lambda = max of A(j+1:n,j) + pivrow = j + 1; + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (i = j + 1; i <= nrow; ip += i++) { + if (o2::gpu::GPUCommonMath::Abs(*ip) > lambda) { + lambda = o2::gpu::GPUCommonMath::Abs(*ip); + pivrow = i; + } + } + + if (lambda == 0) { + if (*mjj == 0) { + ifail = 1; + return; + } + s = 1; + *mjj = 1.0f / *mjj; + } else { + if (o2::gpu::GPUCommonMath::Abs(*mjj) >= lambda * alpha) { + s = 1; + pivrow = j; + } else { + sigma = 0; // compute sigma = max A(pivrow, j:pivrow-1) + ip = rhs.Array() + pivrow * (pivrow - 1) / 2 + j - 1; + for (k = j; k < pivrow; k++) { + if (o2::gpu::GPUCommonMath::Abs(*ip) > sigma) { + sigma = o2::gpu::GPUCommonMath::Abs(*ip); + } + ip++; + } + // sigma cannot be zero because it is at least lambda which is not zero + if (o2::gpu::GPUCommonMath::Abs(*mjj) >= alpha * lambda * (lambda / sigma)) { + s = 1; + pivrow = j; + } else if (o2::gpu::GPUCommonMath::Abs(*(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1)) >= alpha * sigma) { + s = 1; + } else { + s = 2; + } + } + if (pivrow == j) // no permutation neccessary + { + piv[j - 1] = pivrow; + if (*mjj == 0) { + ifail = 1; + return; + } + temp2 = *mjj = 1.0f / *mjj; // invert D(j,j) + + // update A(j+1:n, j+1,n) + for (i = j + 1; i <= nrow; i++) { + temp1 = *(rhs.Array() + i * (i - 1) / 2 + j - 1) * temp2; + ip = rhs.Array() + i * (i - 1) / 2 + j; + for (k = j + 1; k <= i; k++) { + *ip -= static_cast<T>(temp1 * *(rhs.Array() + k * (k - 1) / 2 + j - 1)); + // if (o2::gpu::GPUCommonMath::Abs(*ip) <= epsilon) + // *ip=0; + ip++; + } + } + // update L + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (i = j + 1; i <= nrow; ip += i++) { + *ip *= static_cast<T>(temp2); + } + } else if (s == 1) // 1x1 pivot + { + piv[j - 1] = pivrow; + + // interchange rows and columns j and pivrow in + // submatrix (j:n,j:n) + ip = rhs.Array() + pivrow * (pivrow - 1) / 2 + j; + for (i = j + 1; i < pivrow; i++, ip++) { + temp1 = *(rhs.Array() + i * (i - 1) / 2 + j - 1); + *(rhs.Array() + i * (i - 1) / 2 + j - 1) = *ip; + *ip = static_cast<T>(temp1); + } + temp1 = *mjj; + *mjj = *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1); + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1) = static_cast<T>(temp1); + ip = rhs.Array() + (pivrow + 1) * pivrow / 2 + j - 1; + iq = ip + pivrow - j; + for (i = pivrow + 1; i <= nrow; ip += i, iq += i++) { + temp1 = *iq; + *iq = *ip; + *ip = static_cast<T>(temp1); + } + + if (*mjj == 0) { + ifail = 1; + return; + } + temp2 = *mjj = 1.0f / *mjj; // invert D(j,j) + + // update A(j+1:n, j+1:n) + for (i = j + 1; i <= nrow; i++) { + temp1 = *(rhs.Array() + i * (i - 1) / 2 + j - 1) * temp2; + ip = rhs.Array() + i * (i - 1) / 2 + j; + for (k = j + 1; k <= i; k++) { + *ip -= static_cast<T>(temp1 * *(rhs.Array() + k * (k - 1) / 2 + j - 1)); + // if (o2::gpu::GPUCommonMath::Abs(*ip) <= epsilon) + // *ip=0; + ip++; + } + } + // update L + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (i = j + 1; i <= nrow; ip += i++) { + *ip *= static_cast<T>(temp2); + } + } else // s=2, ie use a 2x2 pivot + { + piv[j - 1] = -pivrow; + piv[j] = 0; // that means this is the second row of a 2x2 pivot + + if (j + 1 != pivrow) { + // interchange rows and columns j+1 and pivrow in + // submatrix (j:n,j:n) + ip = rhs.Array() + pivrow * (pivrow - 1) / 2 + j + 1; + for (i = j + 2; i < pivrow; i++, ip++) { + temp1 = *(rhs.Array() + i * (i - 1) / 2 + j); + *(rhs.Array() + i * (i - 1) / 2 + j) = *ip; + *ip = static_cast<T>(temp1); + } + temp1 = *(mjj + j + 1); + *(mjj + j + 1) = + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1); + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1) = static_cast<T>(temp1); + temp1 = *(mjj + j); + *(mjj + j) = *(rhs.Array() + pivrow * (pivrow - 1) / 2 + j - 1); + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + j - 1) = static_cast<T>(temp1); + ip = rhs.Array() + (pivrow + 1) * pivrow / 2 + j; + iq = ip + pivrow - (j + 1); + for (i = pivrow + 1; i <= nrow; ip += i, iq += i++) { + temp1 = *iq; + *iq = *ip; + *ip = static_cast<T>(temp1); + } + } + // invert D(j:j+1,j:j+1) + temp2 = *mjj * *(mjj + j + 1) - *(mjj + j) * *(mjj + j); + if (temp2 == 0) { + printf("SymMatrix::bunch_invert: error in pivot choice"); + } + temp2 = 1. / temp2; + // this quotient is guaranteed to exist by the choice + // of the pivot + temp1 = *mjj; + *mjj = static_cast<T>(*(mjj + j + 1) * temp2); + *(mjj + j + 1) = static_cast<T>(temp1 * temp2); + *(mjj + j) = static_cast<T>(-*(mjj + j) * temp2); + + if (j < nrow - 1) // otherwise do nothing + { + // update A(j+2:n, j+2:n) + for (i = j + 2; i <= nrow; i++) { + ip = rhs.Array() + i * (i - 1) / 2 + j - 1; + temp1 = *ip * *mjj + *(ip + 1) * *(mjj + j); + // if (o2::gpu::GPUCommonMath::Abs(temp1 ) <= epsilon) + // temp1 = 0; + temp2 = *ip * *(mjj + j) + *(ip + 1) * *(mjj + j + 1); + // if (o2::gpu::GPUCommonMath::Abs(temp2 ) <= epsilon) + // temp2 = 0; + for (k = j + 2; k <= i; k++) { + ip = rhs.Array() + i * (i - 1) / 2 + k - 1; + iq = rhs.Array() + k * (k - 1) / 2 + j - 1; + *ip -= static_cast<T>(temp1 * *iq + temp2 * *(iq + 1)); + // if (o2::gpu::GPUCommonMath::Abs(*ip) <= epsilon) + // *ip = 0; + } + } + // update L + for (i = j + 2; i <= nrow; i++) { + ip = rhs.Array() + i * (i - 1) / 2 + j - 1; + temp1 = *ip * *mjj + *(ip + 1) * *(mjj + j); + // if (o2::gpu::GPUCommonMath::Abs(temp1) <= epsilon) + // temp1 = 0; + *(ip + 1) = *ip * *(mjj + j) + *(ip + 1) * *(mjj + j + 1); + // if (o2::gpu::GPUCommonMath::Abs(*(ip+1)) <= epsilon) + // *(ip+1) = 0; + *ip = static_cast<T>(temp1); + } + } + } + } + } // end of main loop over columns + + if (j == nrow) // the the last pivot is 1x1 + { + mjj = rhs.Array() + j * (j - 1) / 2 + j - 1; + if (*mjj == 0) { + ifail = 1; + return; + } else { + *mjj = 1.0f / *mjj; + } + } // end of last pivot code + + // computing the inverse from the factorization + + for (j = nrow; j >= 1; j -= s) // loop over columns + { + mjj = rhs.Array() + j * (j - 1) / 2 + j - 1; + if (piv[j - 1] > 0) // 1x1 pivot, compute column j of inverse + { + s = 1; + if (j < nrow) { + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (i = 0; i < nrow - j; ip += 1 + j + i++) { + x[i] = *ip; + } + for (i = j + 1; i <= nrow; i++) { + temp2 = 0; + ip = rhs.Array() + i * (i - 1) / 2 + j; + for (k = 0; k <= i - j - 1; k++) { + temp2 += *ip++ * x[k]; + } + for (ip += i - 1; k < nrow - j; ip += 1 + j + k++) { + temp2 += *ip * x[k]; + } + *(rhs.Array() + i * (i - 1) / 2 + j - 1) = static_cast<T>(-temp2); + } + temp2 = 0; + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (k = 0; k < nrow - j; ip += 1 + j + k++) { + temp2 += x[k] * *ip; + } + *mjj -= static_cast<T>(temp2); + } + } else //2x2 pivot, compute columns j and j-1 of the inverse + { + if (piv[j - 1] != 0) { + printf("error in piv %lf \n", piv[j - 1]); + } + s = 2; + if (j < nrow) { + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (i = 0; i < nrow - j; ip += 1 + j + i++) { + x[i] = *ip; + } + for (i = j + 1; i <= nrow; i++) { + temp2 = 0; + ip = rhs.Array() + i * (i - 1) / 2 + j; + for (k = 0; k <= i - j - 1; k++) { + temp2 += *ip++ * x[k]; + } + for (ip += i - 1; k < nrow - j; ip += 1 + j + k++) { + temp2 += *ip * x[k]; + } + *(rhs.Array() + i * (i - 1) / 2 + j - 1) = static_cast<T>(-temp2); + } + temp2 = 0; + ip = rhs.Array() + (j + 1) * j / 2 + j - 1; + for (k = 0; k < nrow - j; ip += 1 + j + k++) { + temp2 += x[k] * *ip; + } + *mjj -= static_cast<T>(temp2); + temp2 = 0; + ip = rhs.Array() + (j + 1) * j / 2 + j - 2; + for (i = j + 1; i <= nrow; ip += i++) { + temp2 += *ip * *(ip + 1); + } + *(mjj - 1) -= static_cast<T>(temp2); + ip = rhs.Array() + (j + 1) * j / 2 + j - 2; + for (i = 0; i < nrow - j; ip += 1 + j + i++) { + x[i] = *ip; + } + for (i = j + 1; i <= nrow; i++) { + temp2 = 0; + ip = rhs.Array() + i * (i - 1) / 2 + j; + for (k = 0; k <= i - j - 1; k++) { + temp2 += *ip++ * x[k]; + } + for (ip += i - 1; k < nrow - j; ip += 1 + j + k++) { + temp2 += *ip * x[k]; + } + *(rhs.Array() + i * (i - 1) / 2 + j - 2) = static_cast<T>(-temp2); + } + temp2 = 0; + ip = rhs.Array() + (j + 1) * j / 2 + j - 2; + for (k = 0; k < nrow - j; ip += 1 + j + k++) { + temp2 += x[k] * *ip; + } + *(mjj - j) -= static_cast<T>(temp2); + } + } + + // interchange rows and columns j and piv[j-1] + // or rows and columns j and -piv[j-2] + + pivrow = (piv[j - 1] == 0) ? -piv[j - 2] : piv[j - 1]; + ip = rhs.Array() + pivrow * (pivrow - 1) / 2 + j; + for (i = j + 1; i < pivrow; i++, ip++) { + temp1 = *(rhs.Array() + i * (i - 1) / 2 + j - 1); + *(rhs.Array() + i * (i - 1) / 2 + j - 1) = *ip; + *ip = static_cast<T>(temp1); + } + temp1 = *mjj; + *mjj = *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1); + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + pivrow - 1) = static_cast<T>(temp1); + if (s == 2) { + temp1 = *(mjj - 1); + *(mjj - 1) = *(rhs.Array() + pivrow * (pivrow - 1) / 2 + j - 2); + *(rhs.Array() + pivrow * (pivrow - 1) / 2 + j - 2) = static_cast<T>(temp1); + } + + ip = rhs.Array() + (pivrow + 1) * pivrow / 2 + j - 1; // &A(i,j) + iq = ip + pivrow - j; + for (i = pivrow + 1; i <= nrow; ip += i, iq += i++) { + temp1 = *iq; + *iq = *ip; + *ip = static_cast<T>(temp1); + } + } // end of loop over columns (in computing inverse from factorization) + + return; // inversion successful +} + +// LU factorization +template <unsigned int D, unsigned int n> +template <class T> +GPUdi() int Inverter<D, n>::DfactMatrix(MatRepStdGPU<T, D, n>& rhs, T& det, unsigned int* ir) +{ + if (D != n) { + return -1; + } + + int ifail, jfail; + typedef T* mIter; + + typedef T value_type; + + value_type tf; + value_type g1 = 1.0e-19, g2 = 1.0e19; + + value_type p, q, t; + value_type s11, s12; + + // LM (04.09) : remove useless check on epsilon and set it to zero + const value_type epsilon = 0.0; + // double epsilon = 8*std::numeric_limits<T>::epsilon(); + // could be set to zero (like it was before) + // but then the algorithm often doesn't detect + // that a matrix is singular + + int normal = 0, imposs = -1; + int jrange = 0, jover = 1, junder = -1; + ifail = normal; + jfail = jrange; + int nxch = 0; + det = 1.0; + mIter mj = rhs.Array(); + mIter mjj = mj; + for (unsigned int j = 1; j <= n; j++) { + unsigned int k = j; + p = (o2::gpu::GPUCommonMath::Abs(*mjj)); + if (j != n) { + mIter mij = mj + n + j - 1; + for (unsigned int i = j + 1; i <= n; i++) { + q = (o2::gpu::GPUCommonMath::Abs(*(mij))); + if (q > p) { + k = i; + p = q; + } + mij += n; + } + if (k == j) { + if (p <= epsilon) { + det = 0; + ifail = imposs; + jfail = jrange; + return ifail; + } + det = -det; // in this case the sign of the determinant + // must not change. So I change it twice. + } + mIter mjl = mj; + mIter mkl = rhs.Array() + (k - 1) * n; + for (unsigned int l = 1; l <= n; l++) { + tf = *mjl; + *(mjl++) = *mkl; + *(mkl++) = static_cast<T>(tf); + } + nxch = nxch + 1; // this makes the determinant change its sign + ir[nxch] = (((j) << 12) + (k)); + } else { + if (p <= epsilon) { + det = 0.0; + ifail = imposs; + jfail = jrange; + return ifail; + } + } + det *= *mjj; + *mjj = 1.0f / *mjj; + t = (o2::gpu::GPUCommonMath::Abs(det)); + if (t < g1) { + det = 0.0; + if (jfail == jrange) { + jfail = junder; + } + } else if (t > g2) { + det = 1.0; + if (jfail == jrange) { + jfail = jover; + } + } + if (j != n) { + mIter mk = mj + n; + mIter mkjp = mk + j; + mIter mjk = mj + j; + for (k = j + 1; k <= n; k++) { + s11 = -(*mjk); + s12 = -(*mkjp); + if (j != 1) { + mIter mik = rhs.Array() + k - 1; + mIter mijp = rhs.Array() + j; + mIter mki = mk; + mIter mji = mj; + for (unsigned int i = 1; i < j; i++) { + s11 += (*mik) * (*(mji++)); + s12 += (*mijp) * (*(mki++)); + mik += n; + mijp += n; + } + } + // cast to avoid warnings from double to float conversions + *(mjk++) = static_cast<T>(-s11 * (*mjj)); + *(mkjp) = static_cast<T>(-(((*(mjj + 1))) * ((*(mkjp - 1))) + (s12))); + mk += n; + mkjp += n; + } + } + mj += n; + mjj += (n + 1); + } + if (nxch % 2 == 1) { + det = -det; + } + if (jfail != jrange) { + det = 0.0; + } + ir[n] = nxch; + return 0; +} + +template <unsigned int D, unsigned int n> +template <class T> +GPUdi() int Inverter<D, n>::DfinvMatrix(MatRepStdGPU<T, D, n>& rhs, unsigned int* ir) +{ + typedef T* mIter; + typedef T value_type; + + if (D != n) { + return -1; + } + + value_type s31, s32; + value_type s33, s34; + + mIter m11 = rhs.Array(); + mIter m12 = m11 + 1; + mIter m21 = m11 + n; + mIter m22 = m12 + n; + *m21 = -(*m22) * (*m11) * (*m21); + *m12 = -(*m12); + if (n > 2) { + mIter mi = rhs.Array() + 2 * n; + mIter mii = rhs.Array() + 2 * n + 2; + mIter mimim = rhs.Array() + n + 1; + for (unsigned int i = 3; i <= n; i++) { + unsigned int im2 = i - 2; + mIter mj = rhs.Array(); + mIter mji = mj + i - 1; + mIter mij = mi; + for (unsigned int j = 1; j <= im2; j++) { + s31 = 0.0; + s32 = *mji; + mIter mkj = mj + j - 1; + mIter mik = mi + j - 1; + mIter mjkp = mj + j; + mIter mkpi = mj + n + i - 1; + for (unsigned int k = j; k <= im2; k++) { + s31 += (*mkj) * (*(mik++)); + s32 += (*(mjkp++)) * (*mkpi); + mkj += n; + mkpi += n; + } + *mij = static_cast<T>(-(*mii) * (((*(mij - n))) * ((*(mii - 1))) + (s31))); + *mji = static_cast<T>(-s32); + mj += n; + mji += n; + mij++; + } + *(mii - 1) = -(*mii) * (*mimim) * (*(mii - 1)); + *(mimim + 1) = -(*(mimim + 1)); + mi += n; + mimim += (n + 1); + mii += (n + 1); + } + } + mIter mi = rhs.Array(); + mIter mii = rhs.Array(); + for (unsigned int i = 1; i < n; i++) { + unsigned int ni = n - i; + mIter mij = mi; + //int j; + for (unsigned j = 1; j <= i; j++) { + s33 = *mij; + mIter mikj = mi + n + j - 1; + mIter miik = mii + 1; + mIter min_end = mi + n; + for (; miik < min_end;) { + s33 += (*mikj) * (*(miik++)); + mikj += n; + } + *(mij++) = static_cast<T>(s33); + } + for (unsigned j = 1; j <= ni; j++) { + s34 = 0.0; + mIter miik = mii + j; + mIter mikij = mii + j * n + j; + for (unsigned int k = j; k <= ni; k++) { + s34 += *mikij * (*(miik++)); + mikij += n; + } + *(mii + j) = s34; + } + mi += n; + mii += (n + 1); + } + unsigned int nxch = ir[n]; + if (nxch == 0) { + return 0; + } + for (unsigned int mm = 1; mm <= nxch; mm++) { + unsigned int k = nxch - mm + 1; + int ij = ir[k]; + int i = ij >> 12; + int j = ij % 4096; + mIter mki = rhs.Array() + i - 1; + mIter mkj = rhs.Array() + j - 1; + for (k = 1; k <= n; k++) { + T ti = *mki; + *mki = *mkj; + *mkj = ti; + mki += n; + mkj += n; + } + } + return 0; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() bool SMatrixGPU<T, D1, D2, R>::Invert() +{ + GPU_STATIC_CHECK(D1 == D2, SMatrixGPU_not_square); + return Inverter<D1, D2>::Dinv((*this).mRep); +} + +template <class T, unsigned int D1, unsigned int D2, class R> +struct TranspPolicyGPU { + enum { + N1 = R::kRows, + N2 = R::kCols + }; + typedef MatRepStdGPU<T, N2, N1> RepType; +}; + +template <class T, unsigned int D1, unsigned int D2> +struct TranspPolicyGPU<T, D1, D2, MatRepSymGPU<T, D1>> { + typedef MatRepSymGPU<T, D1> RepType; +}; + +template <class Matrix, class T, unsigned int D1, unsigned int D2 = D1> +class TransposeOpGPU +{ + public: + GPUd() TransposeOpGPU(const Matrix& rhs) : mRhs(rhs) {} + + GPUdDefault() ~TransposeOpGPU() = default; + + GPUdi() T apply(unsigned int i) const + { + return mRhs.apply((i % D1) * D2 + i / D1); + } + GPUdi() T operator()(unsigned int i, unsigned j) const + { + return mRhs(j, i); + } + + GPUdi() bool IsInUse(const T* p) const + { + return mRhs.IsInUse(p); + } + + protected: + const Matrix& mRhs; +}; + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() SVectorGPU<T, D1> operator*(const SMatrixGPU<T, D1, D2, R>& rhs, const SVectorGPU<T, D2>& lhs) +{ + SVectorGPU<T, D1> tmp; + for (unsigned int i = 0; i < D1; ++i) { + const unsigned int rpos = i * D2; + for (unsigned int j = 0; j < D2; ++j) { + tmp[i] += rhs.apply(rpos + j) * lhs.apply(j); + } + } + return tmp; +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() Expr<TransposeOpGPU<SMatrixGPU<T, D1, D2, R>, T, D1, D2>, T, D2, D1, typename TranspPolicyGPU<T, D1, D2, R>::RepType> Transpose(const SMatrixGPU<T, D1, D2, R>& rhs) +{ + typedef TransposeOpGPU<SMatrixGPU<T, D1, D2, R>, T, D1, D2> MatTrOp; + return Expr<MatTrOp, T, D2, D1, typename TranspPolicyGPU<T, D1, D2, R>::RepType>(MatTrOp(rhs)); +} + +template <class T, unsigned int D1, unsigned int D2, class R> +GPUdi() SMatrixGPU<T, D1, D1, MatRepSymGPU<T, D1>> Similarity(const SMatrixGPU<T, D1, D2, R>& lhs, const SMatrixGPU<T, D2, D2, MatRepSymGPU<T, D2>>& rhs) +{ + SMatrixGPU<T, D1, D2, MatRepStdGPU<T, D1, D2>> tmp = lhs * rhs; + typedef SMatrixGPU<T, D1, D1, MatRepSymGPU<T, D1>> SMatrixSym; + SMatrixSym mret; + AssignSym::Evaluate(mret, tmp * Transpose(lhs)); + return mret; +} +}; // namespace o2::math_utils +#endif diff --git a/Common/MathUtils/include/MathUtils/Utils.h b/Common/MathUtils/include/MathUtils/Utils.h index d8c4061b4667a..618d3e379f6d2 100644 --- a/Common/MathUtils/include/MathUtils/Utils.h +++ b/Common/MathUtils/include/MathUtils/Utils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,8 @@ #include "MathUtils/detail/bitOps.h" #include "MathUtils/detail/StatAccumulator.h" #include "MathUtils/detail/trigonometric.h" +#include "MathUtils/detail/TypeTruncation.h" +#include "MathUtils/detail/basicMath.h" namespace o2 { @@ -106,25 +109,26 @@ inline void bringToPMPid(double& phi) GPUdi() void sincos(float ang, float& s, float& c) { - detail::sincos(ang, s, c); + detail::sincos<float>(ang, s, c); } - +#ifndef __OPENCL__ GPUdi() void sincosd(double ang, double& s, double& c) { - detail::sincos(ang, s, c); + detail::sincos<double>(ang, s, c); } +#endif -#ifndef GPUCA_GPUCODE_DEVICE -inline void rotateZ(float xL, float yL, float& xG, float& yG, float snAlp, float csAlp) +GPUdi() void rotateZ(float xL, float yL, float& xG, float& yG, float snAlp, float csAlp) { return detail::rotateZ<float>(xL, yL, xG, yG, snAlp, csAlp); } -inline void rotateZd(double xL, double yL, double& xG, double& yG, double snAlp, double csAlp) +GPUdi() void rotateZd(double xL, double yL, double& xG, double& yG, double snAlp, double csAlp) { return detail::rotateZ<double>(xL, yL, xG, yG, snAlp, csAlp); } +#ifndef GPUCA_GPUCODE_DEVICE inline void rotateZInv(float xG, float yG, float& xL, float& yL, float snAlp, float csAlp) { detail::rotateZInv<float>(xG, yG, xL, yL, snAlp, csAlp); @@ -216,10 +220,173 @@ GPUhdi() double fastATan2d(double y, double x) return detail::fastATan2<double>(y, x); } +template <class T> +GPUhdi() T min(const T x, const T y) +{ + return detail::min<T>(x, y); +}; + +GPUhdi() double mind(const double x, const double y) +{ + return detail::min<double>(x, y); +}; + +template <class T> +GPUhdi() T max(const T x, const T y) +{ + return detail::max<T>(x, y); +}; + +GPUhdi() double maxd(const double x, const double y) +{ + return detail::max<double>(x, y); +}; + +GPUhdi() float sqrt(float x) +{ + return detail::sqrt<float>(x); +}; + +GPUhdi() double sqrtd(double x) +{ + return detail::sqrt<double>(x); +}; + +GPUhdi() float abs(float x) +{ + return detail::abs<float>(x); +}; + +GPUhdi() double absd(double x) +{ + return detail::abs<double>(x); +}; + +GPUdi() float asin(float x) +{ + return detail::asin<float>(x); +}; + +GPUdi() double asind(double x) +{ + return detail::asin<double>(x); +}; + +GPUdi() float atan(float x) +{ + return detail::atan<float>(x); +}; + +GPUdi() double atand(double x) +{ + return detail::atan<double>(x); +}; + +GPUdi() float atan2(float y, float x) +{ + return detail::atan2<float>(y, x); +}; + +GPUdi() double atan2d(double y, double x) +{ + return detail::atan2<double>(y, x); +}; + +GPUdi() float sin(float x) +{ + return detail::sin<float>(x); +}; + +GPUdi() double sind(double x) +{ + return detail::sin<double>(x); +}; + +GPUdi() float cos(float x) +{ + return detail::cos<float>(x); +}; + +GPUdi() double cosd(double x) +{ + return detail::cos<double>(x); +}; + +GPUdi() float tan(float x) +{ + return detail::tan<float>(x); +}; + +GPUdi() double tand(double x) +{ + return detail::tan<double>(x); +}; + +GPUdi() float twoPi() +{ + return detail::twoPi<float>(); +}; + +GPUdi() double twoPid() +{ + return detail::twoPi<double>(); +}; + +GPUdi() float pi() +{ + return detail::pi<float>(); +} + +GPUdi() double pid() +{ + return detail::pi<double>(); +} + +GPUdi() int nint(float x) +{ + return detail::nint<float>(x); +}; + +GPUdi() int nintd(double x) +{ + return detail::nint<double>(x); +}; + +GPUdi() bool finite(float x) +{ + return detail::finite<float>(x); +} + +GPUdi() bool finited(double x) +{ + return detail::finite<double>(x); +} + +GPUdi() unsigned int clz(unsigned int val) +{ + return detail::clz(val); +}; + +GPUdi() unsigned int popcount(unsigned int val) +{ + return detail::popcount(val); +}; + +GPUdi() float log(float x) +{ + return detail::log<float>(x); +}; + +GPUdi() double logd(double x) +{ + return detail::log<double>(x); +}; + using detail::StatAccumulator; using detail::bit2Mask; using detail::numberOfBitsSet; +using detail::truncateFloatFraction; } // namespace math_utils } // namespace o2 diff --git a/Common/MathUtils/include/MathUtils/detail/Bracket.h b/Common/MathUtils/include/MathUtils/detail/Bracket.h index 28c0f505ae13d..c52de5a0e15c4 100644 --- a/Common/MathUtils/include/MathUtils/detail/Bracket.h +++ b/Common/MathUtils/include/MathUtils/detail/Bracket.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,10 @@ #define ALICEO2_BRACKET_H #include <GPUCommonRtypes.h> +#ifndef GPUCA_ALIGPUCODE +#include <fmt/format.h> +#include <string> +#endif namespace o2 { @@ -59,11 +64,21 @@ class Bracket T getMin() const; T mean() const; T delta() const; + + Bracket getOverlap(const Bracket<T>& other) const; + + void scale(T c); + bool isZeroLength() const; bool isValid() const; bool isInvalid() const; void update(T v); Relation isOutside(const Bracket<T>& t) const; Relation isOutside(T t, T tErr) const; + Relation isOutside(T t) const; + +#ifndef GPUCA_ALIGPUCODE + std::string asString() const; +#endif private: T mMin{}; @@ -161,21 +176,31 @@ inline T Bracket<T>::mean() const { return (mMin + mMax) / 2; } + template <typename T> inline T Bracket<T>::delta() const { return mMax - mMin; } + template <typename T> inline bool Bracket<T>::isValid() const { return mMax >= mMin; } + template <typename T> inline bool Bracket<T>::isInvalid() const { return mMin > mMax; } + +template <typename T> +inline bool Bracket<T>::isZeroLength() const +{ + return mMin == mMax; +} + template <typename T> inline void Bracket<T>::update(T v) { @@ -188,12 +213,26 @@ inline void Bracket<T>::update(T v) } } +template <typename T> +inline void Bracket<T>::scale(T c) +{ + mMin *= c; + mMax *= c; +} + +template <typename T> +inline Bracket<T> Bracket<T>::getOverlap(const Bracket<T>& other) const +{ + return {getMin() > other.getMin() ? getMin() : other.getMin(), getMax() < other.getMax() ? getMax() : other.getMax()}; +} + template <typename T> inline typename Bracket<T>::Relation Bracket<T>::isOutside(const Bracket<T>& t) const { ///< check if provided bracket is outside of this bracket return t.mMax < mMin ? Below : (t.mMin > mMax ? Above : Inside); } + template <typename T> inline typename Bracket<T>::Relation Bracket<T>::isOutside(T t, T tErr) const { @@ -201,6 +240,21 @@ inline typename Bracket<T>::Relation Bracket<T>::isOutside(T t, T tErr) const return t + tErr < mMin ? Below : (t - tErr > mMax ? Above : Inside); } +template <typename T> +inline typename Bracket<T>::Relation Bracket<T>::isOutside(T t) const +{ + ///< check if provided point is outside of this bracket + return t < mMin ? Below : (t > mMax ? Above : Inside); +} + +#ifndef GPUCA_ALIGPUCODE +template <typename T> +std::string Bracket<T>::asString() const +{ + return fmt::format("[{}:{}]", getMin(), getMax()); +} +#endif + } // namespace detail } // namespace math_utils } // namespace o2 diff --git a/Common/MathUtils/include/MathUtils/detail/CircleXY.h b/Common/MathUtils/include/MathUtils/detail/CircleXY.h index f33f167df68e5..3a626dde0e872 100644 --- a/Common/MathUtils/include/MathUtils/detail/CircleXY.h +++ b/Common/MathUtils/include/MathUtils/detail/CircleXY.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_CIRCLEXY_H_ #define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_CIRCLEXY_H_ +#include "GPUCommonDef.h" #include "GPUCommonRtypes.h" namespace o2 @@ -32,18 +34,18 @@ struct CircleXY { T rC; // circle radius T xC; // x-center T yC; // y-center - CircleXY(T r = T(), T x = T(), T y = T()); - T getCenterD2() const; + GPUd() CircleXY(T r = T(), T x = T(), T y = T()); + GPUd() T getCenterD2() const; ClassDefNV(CircleXY, 2); }; template <typename T> -CircleXY<T>::CircleXY(T r, T x, T y) : rC(std::move(r)), xC(std::move(x)), yC(std::move(y)) +GPUdi() CircleXY<T>::CircleXY(T r, T x, T y) : rC(r), xC(x), yC(y) { } template <typename T> -inline T CircleXY<T>::getCenterD2() const +GPUdi() T CircleXY<T>::getCenterD2() const { return xC * xC + yC * yC; } diff --git a/Common/MathUtils/include/MathUtils/detail/IntervalXY.h b/Common/MathUtils/include/MathUtils/detail/IntervalXY.h index 67d8719a9d3aa..cdc1bc2e93db2 100644 --- a/Common/MathUtils/include/MathUtils/detail/IntervalXY.h +++ b/Common/MathUtils/include/MathUtils/detail/IntervalXY.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,13 @@ #ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_INTERVALXY_H_ #define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_INTERVALXY_H_ +#include "GPUCommonDef.h" #include "GPUCommonRtypes.h" +#include "GPUCommonMath.h" +#ifndef GPUCA_GPUCODE_DEVICE #include <cmath> #include <tuple> +#endif #include "MathUtils/detail/CircleXY.h" @@ -36,30 +41,32 @@ class IntervalXY using value_t = T; ///< 2D interval in lab frame defined by its one edge and signed projection lengths on X,Y axes - IntervalXY(T x = T(), T y = T(), T dx = T(), T dy = T()); - T getX0() const; - T getY0() const; - T& getX0(); - T& getY0(); - T getX1() const; - T getY1() const; - T getDX() const; - T getDY() const; - T& getDX(); - T& getDY(); - - void setX0(T x0); - void setY0(T y0); - void setX1(T x1); - void setY1(T y1); - void setDX(T dx); - void setDY(T dy); - void setEdges(T x0, T y0, T x1, T y1); - - void eval(T t, T& x, T& y) const; + GPUd() IntervalXY(T x = T(), T y = T(), T dx = T(), T dy = T()); + GPUd() T getX0() const; + GPUd() T getY0() const; + GPUd() T& getX0(); + GPUd() T& getY0(); + GPUd() T getX1() const; + GPUd() T getY1() const; + GPUd() T getDX() const; + GPUd() T getDY() const; + GPUd() T& getDX(); + GPUd() T& getDY(); + + GPUd() void setX0(T x0); + GPUd() void setY0(T y0); + GPUd() void setX1(T x1); + GPUd() void setY1(T y1); + GPUd() void setDX(T dx); + GPUd() void setDY(T dy); + GPUd() void setEdges(T x0, T y0, T x1, T y1); + + GPUd() void eval(T t, T& x, T& y) const; +#ifndef GPUCA_GPUCODE_DEVICE std::tuple<T, T> eval(T t) const; +#endif - void getLineCoefs(T& a, T& b, T& c) const; + GPUd() void getLineCoefs(T& a, T& b, T& c) const; /** check if XY interval is seen by the circle. * The tolerance parameter eps is interpreted as a fraction of the interval @@ -69,9 +76,9 @@ class IntervalXY * y = yc + dy*t * with 0<t<1., we acctually check the interval for -eps<t<1+eps */ - bool seenByCircle(const CircleXY<T>& circle, T eps) const; + GPUd() bool seenByCircle(const CircleXY<T>& circle, T eps) const; - bool circleCrossParam(const CircleXY<T>& circle, T& t) const; + GPUd() bool circleCrossParam(const CircleXY<T>& circle, T& t) const; /** * check if XY interval is seen by the line defined by other interval @@ -82,12 +89,12 @@ class IntervalXY * y = yc + dy*t * with 0<t<1., we acctually check the interval for -eps<t<1+eps */ - bool seenByLine(const IntervalXY<T>& other, T eps) const; + GPUd() bool seenByLine(const IntervalXY<T>& other, T eps) const; /** * get crossing parameter of 2 intervals */ - bool lineCrossParam(const IntervalXY<T>& other, T& t) const; + GPUd() bool lineCrossParam(const IntervalXY<T>& other, T& t) const; private: T mX, mY; ///< one of edges @@ -97,100 +104,100 @@ class IntervalXY }; template <typename T> -IntervalXY<T>::IntervalXY(T x, T y, T dx, T dy) : mX(std::move(x)), mY(std::move(y)), mDx(std::move(dx)), mDY(std::move(dy)) +GPUdi() IntervalXY<T>::IntervalXY(T x, T y, T dx, T dy) : mX(x), mY(y), mDx(dx), mDY(dy) { } template <typename T> -inline T IntervalXY<T>::getX0() const +GPUdi() T IntervalXY<T>::getX0() const { return mX; } template <typename T> -inline T IntervalXY<T>::getY0() const +GPUdi() T IntervalXY<T>::getY0() const { return mY; } template <typename T> -inline T& IntervalXY<T>::getX0() +GPUdi() T& IntervalXY<T>::getX0() { return mX; } template <typename T> -inline T& IntervalXY<T>::getY0() +GPUdi() T& IntervalXY<T>::getY0() { return mY; } template <typename T> -inline T IntervalXY<T>::getX1() const +GPUdi() T IntervalXY<T>::getX1() const { return mX + mDx; } template <typename T> -inline T IntervalXY<T>::getY1() const +GPUdi() T IntervalXY<T>::getY1() const { return mY + mDY; } template <typename T> -inline T IntervalXY<T>::getDX() const +GPUdi() T IntervalXY<T>::getDX() const { return mDx; } template <typename T> -inline T IntervalXY<T>::getDY() const +GPUdi() T IntervalXY<T>::getDY() const { return mDY; } template <typename T> -inline T& IntervalXY<T>::getDX() +GPUdi() T& IntervalXY<T>::getDX() { return mDx; } template <typename T> -inline T& IntervalXY<T>::getDY() +GPUdi() T& IntervalXY<T>::getDY() { return mDY; } template <typename T> -inline void IntervalXY<T>::setX0(T x0) +GPUdi() void IntervalXY<T>::setX0(T x0) { mX = x0; } template <typename T> -inline void IntervalXY<T>::setY0(T y0) +GPUdi() void IntervalXY<T>::setY0(T y0) { mY = y0; } template <typename T> -inline void IntervalXY<T>::setX1(T x1) +GPUdi() void IntervalXY<T>::setX1(T x1) { mDx = x1 - mX; } template <typename T> -inline void IntervalXY<T>::setY1(T y1) +GPUdi() void IntervalXY<T>::setY1(T y1) { mDY = y1 - mY; } template <typename T> -inline void IntervalXY<T>::setDX(T dx) +GPUdi() void IntervalXY<T>::setDX(T dx) { mDx = dx; } template <typename T> -inline void IntervalXY<T>::setDY(T dy) +GPUdi() void IntervalXY<T>::setDY(T dy) { mDY = dy; } template <typename T> -inline void IntervalXY<T>::setEdges(T x0, T y0, T x1, T y1) +GPUdi() void IntervalXY<T>::setEdges(T x0, T y0, T x1, T y1) { mX = x0; mY = y0; @@ -198,20 +205,23 @@ inline void IntervalXY<T>::setEdges(T x0, T y0, T x1, T y1) mDY = y1 - y0; } +#ifndef GPUCA_GPUCODE_DEVICE template <typename T> -inline std::tuple<T, T> IntervalXY<T>::eval(T t) const +std::tuple<T, T> IntervalXY<T>::eval(T t) const { return {mX + t * mDx, mY + t * mDY}; } +#endif template <typename T> -inline void IntervalXY<T>::eval(T t, T& x, T& y) const +GPUdi() void IntervalXY<T>::eval(T t, T& x, T& y) const { - std::tie(x, y) = eval(t); + x = mX + t * mDx; + y = mY + t * mDY; } template <typename T> -void IntervalXY<T>::getLineCoefs(T& a, T& b, T& c) const +GPUdi() void IntervalXY<T>::getLineCoefs(T& a, T& b, T& c) const { // convert to line parameters in canonical form: a*x+b*y+c = 0 c = mX * mDY - mY * mDx; @@ -230,7 +240,7 @@ void IntervalXY<T>::getLineCoefs(T& a, T& b, T& c) const } template <typename T> -bool IntervalXY<T>::seenByCircle(const CircleXY<T>& circle, T eps) const +GPUdi() bool IntervalXY<T>::seenByCircle(const CircleXY<T>& circle, T eps) const { T dx0 = mX - circle.xC; T dy0 = mY - circle.yC; @@ -251,7 +261,7 @@ bool IntervalXY<T>::seenByCircle(const CircleXY<T>& circle, T eps) const return (d02 - rC2) * (d12 - rC2) < 0; } template <typename T> -bool IntervalXY<T>::circleCrossParam(const CircleXY<T>& circle, T& t) const +GPUdi() bool IntervalXY<T>::circleCrossParam(const CircleXY<T>& circle, T& t) const { const T dx = mX - circle.xC; const T dy = mY - circle.yC; @@ -262,34 +272,35 @@ bool IntervalXY<T>::circleCrossParam(const CircleXY<T>& circle, T& t) const if (det < 0.f) { return false; } - det = std::sqrt(det); + det = gpu::CAMath::Sqrt(det); const T t0 = -b - det; const T t1 = -b + det; // select the one closer to [0:1] interval - t = (std::fabs(t0 - 0.5f) < std::fabs(t1 - 0.5f)) ? t0 : t1; + t = (gpu::CAMath::Abs(t0 - 0.5f) < gpu::CAMath::Abs(t1 - 0.5f)) ? t0 : t1; return true; } template <typename T> -bool IntervalXY<T>::seenByLine(const IntervalXY<T>& other, T eps) const +GPUdi() bool IntervalXY<T>::seenByLine(const IntervalXY<T>& other, T eps) const { T a, b, c; // find equation of the line a*x+b*y+c = 0 other.getLineCoefs(a, b, c); - const auto [x0, y0] = eval(-eps); - const auto [x1, y1] = eval(1.f + eps); + T x0, y0, x1, y1; + eval(-eps, x0, y0); + eval(1.f + eps, x1, y1); return (a * x0 + b * y0 + c) * (a * x1 + b * y1 + c) < 0; } template <typename T> -bool IntervalXY<T>::lineCrossParam(const IntervalXY<T>& other, T& t) const +GPUdi() bool IntervalXY<T>::lineCrossParam(const IntervalXY<T>& other, T& t) const { // tolerance constexpr float eps = 1.e-9f; const T dx = other.getX0() - mX; const T dy = other.getY0() - mY; const T det = -mDx * other.getY0() + mDY * other.getX0(); - if (std::fabs(det) < eps) { + if (gpu::CAMath::Abs(det) < eps) { return false; // parallel } t = (-dx * other.getY0() + dy * other.getX0()) / det; diff --git a/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h b/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h index 5ec3781de0d6d..50a09804da6ed 100644 --- a/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h +++ b/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/include/MathUtils/detail/TypeTruncation.h b/Common/MathUtils/include/MathUtils/detail/TypeTruncation.h new file mode 100644 index 0000000000000..9df6073f5de59 --- /dev/null +++ b/Common/MathUtils/include/MathUtils/detail/TypeTruncation.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TypeTruncation.h +/// \brief +/// \author Nima Zardoshti <nima.zardoshti@cern.ch>, CERN (copied from AliPhysics implementation by Peter Hristov) + +#ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TYPETRUNCATION_H_ +#define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TYPETRUNCATION_H_ + +#ifndef GPUCA_GPUCODE_DEVICE +#include <cstdint> +#endif + +namespace o2 +{ +namespace math_utils +{ +namespace detail +{ + +static float truncateFloatFraction(float x, uint32_t mask = 0xFFFFFF00) +{ + // Mask the less significant bits in the float fraction (1 bit sign, 8 bits exponent, 23 bits fraction), see + // https://en.wikipedia.org/wiki/Single-precision_floating-point_format + // mask 0xFFFFFF00 means 23 - 8 = 15 bits in the fraction + constexpr uint32_t ProtMask = ((0x1u << 9) - 1u) << 23; + union { + float y; + uint32_t iy; + } myu; + myu.y = x; + myu.iy &= (ProtMask | mask); + return myu.y; +} + +} // namespace detail +} // namespace math_utils +} // namespace o2 + +#endif /* MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TYPETRUNCATION_H_ */ diff --git a/Common/MathUtils/include/MathUtils/detail/basicMath.h b/Common/MathUtils/include/MathUtils/detail/basicMath.h new file mode 100644 index 0000000000000..5dd66182e47d8 --- /dev/null +++ b/Common/MathUtils/include/MathUtils/detail/basicMath.h @@ -0,0 +1,129 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file basicMath.h +/// \brief +/// \author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch + +#ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ +#define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ + +#ifndef GPUCA_GPUCODE_DEVICE +#include <cmath> +#include <tuple> +#endif +#include "GPUCommonArray.h" +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "CommonConstants/MathConstants.h" + +namespace o2 +{ +namespace math_utils +{ +namespace detail +{ + +template <typename T> +GPUhdi() T copysign(T x, T y) +{ + return o2::gpu::GPUCommonMath::Copysign(x, y); +} + +template <class T> +GPUhdi() T min(const T x, const T y) +{ + return o2::gpu::GPUCommonMath::Min(x, y); +}; + +template <class T> +GPUhdi() T max(const T x, const T y) +{ + return o2::gpu::GPUCommonMath::Max(x, y); +}; + +template <class T> +GPUhdi() T sqrt(T x) +{ + return o2::gpu::GPUCommonMath::Sqrt(x); +}; + +template <class T> +GPUhdi() T abs(T x) +{ + return o2::gpu::GPUCommonMath::Abs(x); +}; + +template <class T> +GPUdi() int nint(T x) +{ + return o2::gpu::GPUCommonMath::Nint(x); +}; + +template <class T> +GPUdi() bool finite(T x) +{ + return o2::gpu::GPUCommonMath::Finite(x); +} + +GPUdi() unsigned int clz(unsigned int val) +{ + return o2::gpu::GPUCommonMath::Clz(val); +}; + +GPUdi() unsigned int popcount(unsigned int val) +{ + return o2::gpu::GPUCommonMath::Popcount(val); +}; + +template <class T> +GPUdi() T log(T x) +{ + return o2::gpu::GPUCommonMath::Log(x); +}; + +#ifndef GPUCA_GPUCODE_DEVICE // Double overloads using std namespace not visible on GPU +template <> +GPUhdi() double copysign(double x, double y) +{ + return std::copysign(x, y); +} +template <> +GPUhdi() double sqrt(double x) +{ + return std::sqrt(x); +}; +GPUhdi() double abs(double x) +{ + return std::abs(x); +}; +template <> +GPUdi() int nint(double x) +{ + return std::nearbyint(x); +}; +template <> +GPUdi() bool finite(double x) +{ + return std::isfinite(x); +} +template <> +GPUdi() double log(double x) +{ + return std::log(x); +}; +#endif + +} // namespace detail +} // namespace math_utils +} // namespace o2 + +#endif /* MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ */ \ No newline at end of file diff --git a/Common/MathUtils/include/MathUtils/detail/bitOps.h b/Common/MathUtils/include/MathUtils/detail/bitOps.h index d272069baa660..a5f0fdc98ee77 100644 --- a/Common/MathUtils/include/MathUtils/detail/bitOps.h +++ b/Common/MathUtils/include/MathUtils/detail/bitOps.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,13 +37,13 @@ inline int numberOfBitsSet(uint32_t x) // recursive creation of bitmask template <typename T> -constexpr int bit2Mask(T v) +constexpr uint32_t bit2Mask(T v) { return 0x1 << v; } template <typename T, typename... Args> -constexpr int bit2Mask(T first, Args... args) +constexpr uint32_t bit2Mask(T first, Args... args) { return (0x1 << first) | bit2Mask(args...); } diff --git a/Common/MathUtils/include/MathUtils/detail/trigonometric.h b/Common/MathUtils/include/MathUtils/detail/trigonometric.h index 5ea0609af8634..d624ca5c6bd67 100644 --- a/Common/MathUtils/include/MathUtils/detail/trigonometric.h +++ b/Common/MathUtils/include/MathUtils/detail/trigonometric.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,13 +17,14 @@ #define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TRIGONOMETRIC_H_ #ifndef GPUCA_GPUCODE_DEVICE -#include <array> #include <cmath> #include <tuple> #endif +#include "GPUCommonArray.h" #include "GPUCommonDef.h" #include "GPUCommonMath.h" #include "CommonConstants/MathConstants.h" +#include "MathUtils/detail/basicMath.h" namespace o2 { @@ -32,7 +34,7 @@ namespace detail { template <typename T> -GPUdi() T to02Pi(T phi) +GPUhdi() T to02Pi(T phi) { T res = phi; // ensure angle in [0:2pi] for the input in [-pi:pi] or [0:pi] @@ -43,7 +45,7 @@ GPUdi() T to02Pi(T phi) } template <typename T> -GPUdi() void bringTo02Pi(T& phi) +GPUhdi() void bringTo02Pi(T& phi) { phi = to02Pi<T>(phi); } @@ -69,7 +71,7 @@ inline void bringTo02PiGen(T& phi) } template <typename T> -inline T toPMPi(T phi) +GPUhdi() T toPMPi(T phi) { T res = phi; // ensure angle in [-pi:pi] for the input in [-pi:pi] or [0:pi] @@ -82,7 +84,7 @@ inline T toPMPi(T phi) } template <typename T> -inline void bringToPMPi(T& phi) +GPUhdi() void bringToPMPi(T& phi) { phi = toPMPi<T>(phi); } @@ -107,15 +109,24 @@ inline void bringToPMPiGen(T& phi) phi = toPMPiGen<T>(phi); } -GPUdi() void sincos(float ang, float& s, float& c) +#ifdef __OPENCL__ // TODO: get rid of that stupid workaround for OpenCL template address spaces +template <typename T, typename S, typename U> +GPUhdi() void sincos(T ang, S& s, U& c) { - o2::gpu::GPUCommonMath::SinCos(ang, s, c); + return o2::gpu::GPUCommonMath::SinCos(ang, s, c); } - -GPUdi() void sincos(double ang, double& s, double& c) +#else +template <typename T> +GPUhdi() void sincos(T ang, T& s, T& c) +{ + return o2::gpu::GPUCommonMath::SinCos(ang, s, c); +} +template <> +GPUhdi() void sincos(double ang, double& s, double& c) { - o2::gpu::GPUCommonMath::SinCos(ang, s, c); + return o2::gpu::GPUCommonMath::SinCosd(ang, s, c); } +#endif #ifndef GPUCA_GPUCODE_DEVICE @@ -124,7 +135,7 @@ GPUhdi() std::tuple<T, T> sincos(T ang) { T sin = 0; T cos = 0; - o2::gpu::GPUCommonMath::SinCos(ang, sin, cos); + sincos<T>(ang, sin, cos); return std::make_tuple(sin, cos); } @@ -136,39 +147,43 @@ inline std::tuple<T, T> rotateZ(T xL, T yL, T snAlp, T csAlp) } template <typename T> -inline std::tuple<T, T> rotateZInv(T xG, T yG, T snAlp, T csAlp) +GPUhdi() std::tuple<T, T> rotateZInv(T xG, T yG, T snAlp, T csAlp) { // inverse 2D rotation of the point by angle alpha (global to local) return rotateZ<T>(xG, yG, -snAlp, csAlp); } -template <typename T> -inline void rotateZ(T xL, T yL, T& xG, T& yG, T snAlp, T csAlp) -{ - std::tie(xG, yG) = rotateZ<T>(xL, yL, snAlp, csAlp); -} +#endif template <typename T> -inline void rotateZ(std::array<T, 3>& xy, T alpha) +GPUhdi() void rotateZ(gpu::gpustd::array<T, 3>& xy, T alpha) { // transforms vector in tracking frame alpha to global frame - auto [sin, cos] = sincos<T>(alpha); + T sin, cos; + sincos<T>(alpha, sin, cos); const T x = xy[0]; xy[0] = x * cos - xy[1] * sin; xy[1] = x * sin + xy[1] * cos; } template <typename T> -inline void rotateZInv(T xG, T yG, T& xL, T& yL, T snAlp, T csAlp) +GPUhdi() void rotateZ(T xL, T yL, T& xG, T& yG, T snAlp, T csAlp) +{ + xG = xL * csAlp - yL * snAlp; + yG = xL * snAlp + yL * csAlp; + ; + // std::tie(xG, yG) = rotateZ<T>(xL, yL, snAlp, csAlp); // must not use std:: - versions on GPU +} + +template <typename T> +GPUhdi() void rotateZInv(T xG, T yG, T& xL, T& yL, T snAlp, T csAlp) { // inverse 2D rotation of the point by angle alpha (global to local) rotateZ<T>(xG, yG, xL, yL, -snAlp, csAlp); } -#endif - template <typename T> -inline int angle2Sector(T phi) +GPUhdi() int angle2Sector(T phi) { // convert angle to sector ID, phi can be either in 0:2pi or -pi:pi convention int sect = phi * o2::constants::math::Rad2Deg / o2::constants::math::SectorSpanDeg; @@ -179,7 +194,7 @@ inline int angle2Sector(T phi) } template <typename T> -inline T sector2Angle(int sect) +GPUhdi() T sector2Angle(int sect) { // convert sector to its angle center, in -pi:pi convention T ang = o2::constants::math::SectorSpanRad * (0.5f + sect); @@ -188,7 +203,7 @@ inline T sector2Angle(int sect) } template <typename T> -inline T angle2Alpha(T phi) +GPUhdi() T angle2Alpha(T phi) { // convert angle to its sector alpha return sector2Angle<T>(angle2Sector<T>(phi)); @@ -233,9 +248,113 @@ GPUhdi() T fastATan2(T y, T x) }; // fast atan2(y,x) for any angle [-Pi,Pi] - return o2::gpu::GPUCommonMath::Copysign(atan2P(o2::gpu::GPUCommonMath::Abs(y), x), y); + return copysign<T>(atan2P(o2::gpu::GPUCommonMath::Abs(y), x), y); } +template <class T> +GPUdi() T asin(T x) +{ + return o2::gpu::GPUCommonMath::ASin(x); +}; + +template <class T> +GPUdi() T acos(T x) +{ + return o2::gpu::GPUCommonMath::ACos(x); +}; + +template <class T> +GPUdi() T atan(T x) +{ + return o2::gpu::GPUCommonMath::ATan(x); +}; + +template <class T> +GPUdi() T atan2(T y, T x) +{ + return o2::gpu::GPUCommonMath::ATan2(y, x); +}; + +template <class T> +GPUdi() T sin(T x) +{ + return o2::gpu::GPUCommonMath::Sin(x); +}; + +template <class T> +GPUdi() T cos(T x) +{ + return o2::gpu::GPUCommonMath::Cos(x); +}; + +template <class T> +GPUdi() T tan(T x) +{ + return o2::gpu::GPUCommonMath::Tan(x); +}; + +template <class T> +GPUdi() T twoPi() +{ + return o2::gpu::GPUCommonMath::TwoPi(); +}; + +template <> +GPUdi() double twoPi() +{ + return o2::constants::math::TwoPI; +}; + +template <class T> +GPUdi() T pi() +{ + return o2::gpu::GPUCommonMath::Pi(); +} + +template <> +GPUdi() double pi() +{ + return o2::constants::math::PI; +} + +#ifndef GPUCA_GPUCODE_DEVICE +template <> +GPUdi() double tan(double x) +{ + return std::tan(x); +}; +template <> +GPUdi() double sin(double x) +{ + return std::sin(x); +}; +template <> +GPUdi() double atan2(double y, double x) +{ + return std::atan2(y, x); +}; +template <> +GPUdi() double atan(double x) +{ + return std::atan(x); +}; +template <> +GPUdi() double asin(double x) +{ + return std::asin(x); +}; +template <> +GPUdi() double acos(double x) +{ + return std::acos(x); +}; +template <> +GPUdi() double cos(double x) +{ + return std::cos(x); +}; +#endif + } // namespace detail } // namespace math_utils } // namespace o2 diff --git a/Common/MathUtils/include/MathUtils/fit.h b/Common/MathUtils/include/MathUtils/fit.h index ea7cc626ba0af..95a6cd52283cf 100644 --- a/Common/MathUtils/include/MathUtils/fit.h +++ b/Common/MathUtils/include/MathUtils/fit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,8 @@ #include "Fit/Fitter.h" #include "Fit/BinData.h" #include "Math/WrappedMultiTF1.h" - +#include <Math/SMatrix.h> +#include <Math/SVector.h> #include "Framework/Logger.h" namespace o2 @@ -116,6 +118,94 @@ TFitResultPtr fit(const size_t nBins, const T* arr, const T xMin, const T xMax, return TFitResultPtr(tfr); } +/// fast median estimate of gaussian parameters for histogrammed data +/// +/// \param[in] nbins size of the array and number of histogram bins +/// \param[in] arr array with elements +/// \param[in] xMin minimum range of the array +/// \param[in] xMax maximum range of the array +/// \param[out] param return paramters of the fit (0-Constant, 1-Mean, 2-Sigma) +/// +/// \return false on failure (empty data) + +template <typename T> +bool medmadGaus(size_t nBins, const T* arr, const T xMin, const T xMax, std::array<double, 3>& param) +{ + int bStart = 0, bEnd = -1, filled = 0; + double sum = 0, binW = double(xMax - xMin) / nBins, medVal = xMin; + for (int i = 0; i < (int)nBins; i++) { + auto v = arr[i]; + if (v) { + if (!sum) { + bStart = i; + } + sum += v; + bEnd = i; + } + } + if (bEnd < bStart) { + return false; + } + bEnd++; + double cum = 0, thresh = 0.5 * sum, frac0 = 0; + int bid = bStart, prevbid = bid; + while (bid < bEnd) { + if (arr[bid] > 0) { + cum += arr[bid]; + if (cum > thresh) { + frac0 = 1. + (thresh - cum) / float(arr[bid]); + medVal = xMin + binW * (bid + frac0); + int bdiff = bid - prevbid - 1; + if (bdiff > 0) { + medVal -= bdiff * binW * 0.5; // account for the gap + bid -= bdiff / 2; + } + break; + } + prevbid = bid; + } + bid++; + } + cum = 0.; + double edgeL = frac0 + bid, edgeR = edgeL, dist = 0., wL = 0, wR = 0; + while (1) { + float amp = 0.; + int bL = edgeL, bR = edgeR; // left and right bins + if (edgeL > bStart) { + wL = edgeL - bL; + amp += arr[bL]; + } else { + wL = 1.; + } + if (edgeR < bEnd) { + wR = 1. + bR - edgeR; + amp += arr[bR]; + } else { + wR = 1.; + } + auto wdt = std::min(wL, wR); + if (wdt < 1e-5) { + wdt = std::max(wL, wR); + } + if (amp > 0) { + amp *= wdt; + cum += amp; + if (cum >= thresh) { + dist += wdt * (cum - thresh) / amp * 0.5; + break; + } + } + dist += wdt; + edgeL -= wdt; + edgeR += wdt; + } + constexpr double SQRT2PI = 2.5066283; + param[1] = medVal; + param[2] = dist * binW * 1.4826; // MAD -> sigma + param[0] = sum * binW / (param[2] * SQRT2PI); + return true; +} + /// fast fit of an array with ranges (histogram) with gaussian function /// /// Fitting procedure: @@ -166,7 +256,7 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s param[2] = 0.; param[3] = 0.; - for (Int_t i = 0; i < nBins; i++) { + for (size_t i = 0; i < nBins; i++) { entries += arr[i]; if (arr[i] > 0) { nfilled++; @@ -188,7 +278,7 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s param[3] = entries; Int_t npoints = 0; - for (Int_t ibin = 0; ibin < nBins; ibin++) { + for (size_t ibin = 0; ibin < nBins; ibin++) { Float_t entriesI = arr[ibin]; if (entriesI > 1) { Double_t xcenter = xMin + (ibin + 0.5) * binWidth; @@ -232,7 +322,6 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s if (TMath::Abs(par[2]) < kTol) { return -4; } - param[1] = T(par[1] / (-2. * par[2])); param[2] = T(1. / TMath::Sqrt(TMath::Abs(-2. * par[2]))); Double_t lnparam0 = par[0] + par[1] * param[1] + par[2] * param[1] * param[1]; @@ -263,6 +352,103 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s return chi2; } +// more optimal implementation of guassian fit via log-normal fit, appropriate for MT calls +// Only bins with values above minVal will be accounted. +// If applyMAD is true, the fit is done whithin the nSigmaMAD range of the preliminary estimate by MAD +template <typename T> +double fitGaus(size_t nBins, const T* arr, const T xMin, const T xMax, std::array<double, 3>& param, + ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepSym<double, 3>>* covMat = nullptr, + int minVal = 2, bool applyMAD = true) +{ + double binW = double(xMax - xMin) / nBins, s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, sy0 = 0, sy1 = 0, sy2 = 0, syy = 0, sum = 0.; + int np = 0; + int bStart = 0, bEnd = (int)nBins; + const float nSigmaMAD = 2.; + if (applyMAD) { + std::array<double, 3> madPar; + if (!medmadGaus(nBins, arr, xMin, xMax, madPar)) { + return -10; + } + bStart = std::max(bStart, int((madPar[1] - nSigmaMAD * madPar[2] - xMin) / binW)); + bEnd = std::min(bEnd, 1 + int((madPar[1] + nSigmaMAD * madPar[2] - xMin) / binW)); + } + float x = xMin + (bStart - 0.5) * binW; + for (int i = bStart; i < bEnd; i++) { + x += binW; + auto v = arr[i]; + if (v < 0) { + throw std::runtime_error("Log-normal fit is possible only with non-negative data"); + } + if (v < minVal) { + continue; + } + double y = std::log(v), err2i = v, err2iX = err2i, err2iY = err2i * y; + s0 += err2iX; + s1 += (err2iX *= x); + s2 += (err2iX *= x); + s3 += (err2iX *= x); + s4 += (err2iX *= x); + sy0 += err2iY; + syy += err2iY * y; + sy1 += (err2iY *= x); + sy2 += (err2iY *= x); + np++; + } + if (np < 1) { + return -10; + } + auto recover = [¶m, binW, np, s0, s1, s2, sy0]() { + param[0] = std::exp(sy0 / s0); // recover center of gravity + param[1] = s1 / s0; // mean x; + param[2] = np == 1 ? binW / std::sqrt(12) : std::sqrt(std::abs(param[1] * param[1] - s2 / s0)); + }; + if (np < 3) { + recover(); + return -np; + } + ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepSym<double, 3>> m33{}; + ROOT::Math::SVector<double, 3> v3{sy0, sy1, sy2}; + m33(0, 0) = s0; + m33(1, 0) = s1; + m33(1, 1) = m33(2, 0) = s2; + m33(2, 1) = s3; + m33(2, 2) = s4; + int res = 0; + auto m33i = m33.Inverse(res); + if (res) { + recover(); + LOG(ERROR) << np << " points collected, matrix inversion failed " << m33; + return -10; + } + auto v = m33i * v3; + if (v(2) >= 0.) { // fit failed, use mean amd RMS + recover(); + return -3; + } + + double chi2 = v(0) * v(0) * s0 + v(1) * v(1) * s2 + v(2) * v(2) * s4 + syy + + 2. * (v(0) * v(1) * s1 + v(0) * v(2) * s2 + v(1) * v(2) * s3 - v(0) * sy0 - v(1) * sy1 - v(2) * sy2); + param[1] = -0.5 * v(1) / v(2); + param[2] = 1. / std::sqrt(-2. * v(2)); + param[0] = std::exp(v(0) - param[1] * param[1] * v(2)); + if (std::isnan(param[0]) || std::isnan(param[1]) || std::isnan(param[2])) { + recover(); + return -3; + } + if (covMat) { + // build jacobian of transformation from log-normal to normal params + ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepStd<double, 3, 3>> j33{}; + j33(0, 0) = param[0]; + j33(0, 1) = param[0] * param[1]; + j33(0, 2) = j33(0, 1) * param[1]; + j33(1, 1) = -0.5 / v(2); + j33(1, 2) = -param[1] / v(2); + j33(2, 2) = param[2] * j33(1, 1); + *covMat = ROOT::Math::Similarity(j33, m33i); + } + return np > 3 ? chi2 / (np - 3.) : 0.; +} + /// struct for returning statistical parameters /// /// \todo make type templated? diff --git a/Common/MathUtils/src/CachingTF1.cxx b/Common/MathUtils/src/CachingTF1.cxx index 1d3957a476bf2..faacbff755c4a 100644 --- a/Common/MathUtils/src/CachingTF1.cxx +++ b/Common/MathUtils/src/CachingTF1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/src/Cartesian.cxx b/Common/MathUtils/src/Cartesian.cxx index fc6e950f115bb..da7bad9035b7d 100644 --- a/Common/MathUtils/src/Cartesian.cxx +++ b/Common/MathUtils/src/Cartesian.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/src/Chebyshev3D.cxx b/Common/MathUtils/src/Chebyshev3D.cxx index 2fd984640b6af..10e0d228b2496 100644 --- a/Common/MathUtils/src/Chebyshev3D.cxx +++ b/Common/MathUtils/src/Chebyshev3D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/src/Chebyshev3DCalc.cxx b/Common/MathUtils/src/Chebyshev3DCalc.cxx index d9de88e2b61f9..7a402215a1cf3 100644 --- a/Common/MathUtils/src/Chebyshev3DCalc.cxx +++ b/Common/MathUtils/src/Chebyshev3DCalc.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/src/MathUtilsLinkDef.h b/Common/MathUtils/src/MathUtilsLinkDef.h index 59f6deb11b8e0..a0aa954172e27 100644 --- a/Common/MathUtils/src/MathUtilsLinkDef.h +++ b/Common/MathUtils/src/MathUtilsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/test/testCachingTF1.cxx b/Common/MathUtils/test/testCachingTF1.cxx index adab3ef589ca5..a947128e4cada 100644 --- a/Common/MathUtils/test/testCachingTF1.cxx +++ b/Common/MathUtils/test/testCachingTF1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/test/testCartesian.cxx b/Common/MathUtils/test/testCartesian.cxx index da17623d5fdc3..ec04c34670fc3 100644 --- a/Common/MathUtils/test/testCartesian.cxx +++ b/Common/MathUtils/test/testCartesian.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/MathUtils/test/testUtils.cxx b/Common/MathUtils/test/testUtils.cxx index 4bf03b94f8322..56199d5bce0ab 100644 --- a/Common/MathUtils/test/testUtils.cxx +++ b/Common/MathUtils/test/testUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/CMakeLists.txt b/Common/SimConfig/CMakeLists.txt index 557d364b9bd20..97f015023d230 100644 --- a/Common/SimConfig/CMakeLists.txt +++ b/Common/SimConfig/CMakeLists.txt @@ -1,28 +1,29 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(SimConfig - SOURCES src/SimConfig.cxx - src/SimCutParams.cxx - src/SimUserDecay.cxx + SOURCES src/SimConfig.cxx + src/SimParams.cxx + src/SimUserDecay.cxx src/DigiParams.cxx src/G4Params.cxx PUBLIC_LINK_LIBRARIES O2::CommonUtils O2::DetectorsCommonDataFormats - FairRoot::Base Boost::program_options - Boost::filesystem) + FairRoot::Base Boost::program_options) + o2_target_root_dictionary(SimConfig HEADERS include/SimConfig/SimConfig.h - include/SimConfig/SimCutParams.h + include/SimConfig/SimParams.h include/SimConfig/SimUserDecay.h - include/SimConfig/DigiParams.h + include/SimConfig/DigiParams.h include/SimConfig/G4Params.h) o2_add_test(Config diff --git a/Common/SimConfig/include/SimConfig/DigiParams.h b/Common/SimConfig/include/SimConfig/DigiParams.h index 112c57d80782a..5602e88012cab 100644 --- a/Common/SimConfig/include/SimConfig/DigiParams.h +++ b/Common/SimConfig/include/SimConfig/DigiParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/include/SimConfig/G4Params.h b/Common/SimConfig/include/SimConfig/G4Params.h index 0d6ee14106dcd..16547a685c6d4 100644 --- a/Common/SimConfig/include/SimConfig/G4Params.h +++ b/Common/SimConfig/include/SimConfig/G4Params.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index f510a91abcad1..74d328796a1c7 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,8 +49,10 @@ struct SimConfigData { std::string mCCDBUrl; // the URL where to find CCDB long mTimestamp; // timestamp to anchor transport simulation to int mField; // L3 field setting in kGauss: +-2,+-5 and 0 + bool mUniformField = false; // uniform magnetic field + bool mAsService = false; // if simulation should be run as service/deamon (does not exit after run) - ClassDefNV(SimConfigData, 3); + ClassDefNV(SimConfigData, 4); }; // A singleton class which can be used @@ -85,6 +88,7 @@ class SimConfig void resetFromConfigData(SimConfigData const& data) { mConfigData = data; } SimConfigData const& getConfigData() const { return mConfigData; } + SimConfigData& getConfigData() { return mConfigData; } // get MC engine std::string getMCEngine() const { return mConfigData.mMCEngine; } @@ -110,12 +114,46 @@ class SimConfig int getStartSeed() const { return mConfigData.mStartSeed; } int getNSimWorkers() const { return mConfigData.mSimWorkers; } bool isFilterOutNoHitEvents() const { return mConfigData.mFilterNoHitEvents; } + bool asService() const { return mConfigData.mAsService; } private: SimConfigData mConfigData; //! ClassDefNV(SimConfig, 1); }; + +// Configuration struct used for simulation reconfig (when processing +// in batches and in "deamonized" mode. Note that in comparison to SimConfig, +// fewer fields are offered (because many things are not easy to reconfigure). +//! TODO: Make this a base class of SimConfigData? + +struct SimReconfigData { + std::string generator; // chosen VMC generator + std::string trigger; // chosen VMC generator trigger + unsigned int nEvents; // number of events to be simulated + std::string extKinfileName; // file name of external kinematics file (needed for ext kinematics generator) + std::string embedIntoFileName; // filename containing the reference events to be used for the embedding + unsigned int startEvent = 0; // index of first event to be taken + float mBMax; // maximum for impact parameter sampling + std::string outputPrefix; // prefix to be used for output files + std::string outputDir; // output directory + std::string keyValueTokens; // a string holding arbitrary sequence of key-value tokens (for ConfigurableParams) + // ** WE NEED TO BE CAREFUL: NOT EVERYTHING MAY BE RECONFIGURABLE VIA PARAMETER CHANGE ** + // Foo.parameter1=x,Bar.parameter2=y,Baz.paramter3=hello + std::string configFile; // path to a JSON or INI config file (file extension is required to determine type). + // values within the config file will override values set in code by the param classes + // but will themselves be overridden by any values given in mKeyValueTokens. + unsigned int primaryChunkSize; // defining max granularity for input primaries of a sim job + int startSeed; // base for random number seeds + bool stop; // to shut down the service + + ClassDefNV(SimReconfigData, 1); +}; + +// construct reconfig struct given a configuration string (boost program options format) +// returns true if successful/ false otherwise +bool parseSimReconfigFromString(std::string const& argumentstring, SimReconfigData& config); + } // namespace conf } // namespace o2 diff --git a/Common/SimConfig/include/SimConfig/SimCutParams.h b/Common/SimConfig/include/SimConfig/SimCutParams.h deleted file mode 100644 index 695a56910ff30..0000000000000 --- a/Common/SimConfig/include/SimConfig/SimCutParams.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_SIMCONFIG_SIMCUTPARAM_H_ -#define O2_SIMCONFIG_SIMCUTPARAM_H_ - -#include "CommonUtils/ConfigurableParam.h" -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace conf -{ -// parameters to influence/set the tracking cuts in simulation -// (mostly used in O2MCApplication stepping) -struct SimCutParams : public o2::conf::ConfigurableParamHelper<SimCutParams> { - bool stepFiltering = true; // if we activate the step filtering in O2BaseMCApplication - bool trackSeed = false; // per track seeding for track-reproducible mode - - double maxRTracking = 1E20; // max R tracking cut in cm (in the VMC sense) -- applied in addition to cutting in the stepping function - double maxAbsZTracking = 1E20; // max |Z| tracking cut in cm (in the VMC sense) -- applied in addition to cutting in the stepping function - double ZmaxA = 1E20; // max Z tracking cut on A side in cm -- applied in the stepping function - double ZmaxC = 1E20; // max Z tracking cut on C side in cm -- applied in the stepping function - - O2ParamDef(SimCutParams, "SimCutParams"); -}; -} // namespace conf -} // namespace o2 - -#endif /* O2_SIMCONFIG_SIMCUTPARAM_H_ */ diff --git a/Common/SimConfig/include/SimConfig/SimParams.h b/Common/SimConfig/include/SimConfig/SimParams.h new file mode 100644 index 0000000000000..291e121ea149a --- /dev/null +++ b/Common/SimConfig/include/SimConfig/SimParams.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SIMCONFIG_SIMPARAM_H_ +#define O2_SIMCONFIG_SIMPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace conf +{ +// parameters to influence/set the tracking cuts in simulation +// (mostly used in O2MCApplication stepping) +struct SimCutParams : public o2::conf::ConfigurableParamHelper<SimCutParams> { + bool stepFiltering = true; // if we activate the step filtering in O2BaseMCApplication + bool trackSeed = false; // per track seeding for track-reproducible mode + + double maxRTracking = 1E20; // max R tracking cut in cm (in the VMC sense) -- applied in addition to cutting in the stepping function + double maxAbsZTracking = 1E20; // max |Z| tracking cut in cm (in the VMC sense) -- applied in addition to cutting in the stepping function + double ZmaxA = 1E20; // max Z tracking cut on A side in cm -- applied in our custom stepping function + double ZmaxC = 1E20; // max Z tracking cut on C side in cm -- applied in out custom stepping function + + float maxRTrackingZDC = 50; // R-cut applied in the tunnel leading to ZDC when z > beampipeZ (custom stepping function) + float tunnelZ = 1900; // Z-value from where we apply maxRTrackingZDC (default value taken from standard "hall" dimensions) + + float globalDensityFactor = 1.f; // global factor that scales all material densities for systematic studies + + O2ParamDef(SimCutParams, "SimCutParams"); +}; + +// parameter influencing material manager +struct SimMaterialParams : public o2::conf::ConfigurableParamHelper<SimMaterialParams> { + float globalDensityFactor = 1.f; + + O2ParamDef(SimMaterialParams, "SimMaterialParams"); +}; + +} // namespace conf +} // namespace o2 + +#endif /* O2_SIMCONFIG_SIMCUTPARAM_H_ */ diff --git a/Common/SimConfig/include/SimConfig/SimUserDecay.h b/Common/SimConfig/include/SimConfig/SimUserDecay.h index e1c2587b96413..cb145e0726335 100644 --- a/Common/SimConfig/include/SimConfig/SimUserDecay.h +++ b/Common/SimConfig/include/SimConfig/SimUserDecay.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/src/DigiParams.cxx b/Common/SimConfig/src/DigiParams.cxx index 6f85a746f645b..a9e70071eb8f0 100644 --- a/Common/SimConfig/src/DigiParams.cxx +++ b/Common/SimConfig/src/DigiParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/src/G4Params.cxx b/Common/SimConfig/src/G4Params.cxx index 74175dd34a276..5c5fe26751cd3 100644 --- a/Common/SimConfig/src/G4Params.cxx +++ b/Common/SimConfig/src/G4Params.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 6da06aff849a1..fc1c0a3f826f9 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,8 @@ void SimConfig::initOptions(boost::program_options::options_description& options "generator,g", bpo::value<std::string>()->default_value("boxgen"), "Event generator to be used.")( "trigger,t", bpo::value<std::string>()->default_value(""), "Event generator trigger to be used.")( "modules,m", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>({"all"}), "all modules"), "list of detectors")( - "skipModules", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>({""}), ""), "list of detectors to skip (precendence over -m")("nEvents,n", bpo::value<unsigned int>()->default_value(1), "number of events")( + "skipModules", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>({""}), ""), "list of detectors to skip (precendence over -m")( + "nEvents,n", bpo::value<unsigned int>()->default_value(1), "number of events")( "startEvent", bpo::value<unsigned int>()->default_value(0), "index of first event to be used (when applicable)")( "extKinFile", bpo::value<std::string>()->default_value("Kinematics.root"), "name of kinematics file for event generator from file (when applicable)")( @@ -43,11 +45,12 @@ void SimConfig::initOptions(boost::program_options::options_description& options "chunkSize", bpo::value<unsigned int>()->default_value(500), "max size of primary chunk (subevent) distributed by server")( "chunkSizeI", bpo::value<int>()->default_value(-1), "internalChunkSize")( "seed", bpo::value<int>()->default_value(-1), "initial seed (default: -1 random)")( - "field", bpo::value<int>()->default_value(-5), "L3 field rounded to kGauss, allowed values +-2,+-5 and 0")( + "field", bpo::value<std::string>()->default_value("-5"), "L3 field rounded to kGauss, allowed values +-2,+-5 and 0; +-<intKGaus>U for uniform field ")( "nworkers,j", bpo::value<int>()->default_value(nsimworkersdefault), "number of parallel simulation workers (only for parallel mode)")( "noemptyevents", "only writes events with at least one hit")( "CCDBUrl", bpo::value<std::string>()->default_value("ccdb-test.cern.ch:8080"), "URL for CCDB to be used.")( - "timestamp", bpo::value<long>()->default_value(-1), "global timestamp value (for anchoring) - default is now"); + "timestamp", bpo::value<long>()->default_value(-1), "global timestamp value (for anchoring) - default is now")( + "asservice", bpo::value<bool>()->default_value(false), "run in service/server mode"); } bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& vm) @@ -60,7 +63,7 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& active.clear(); for (int d = DetID::First; d <= DetID::Last; ++d) { #ifdef ENABLE_UPGRADES - if (d != DetID::IT3 && d != DetID::IT4) { + if (d != DetID::IT3 && d != DetID::TRK && d != DetID::FT3) { active.emplace_back(DetID::getName(d)); } #else @@ -105,10 +108,12 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& mConfigData.mSimWorkers = vm["nworkers"].as<int>(); mConfigData.mTimestamp = vm["timestamp"].as<long>(); mConfigData.mCCDBUrl = vm["CCDBUrl"].as<std::string>(); + mConfigData.mAsService = vm["asservice"].as<bool>(); if (vm.count("noemptyevents")) { mConfigData.mFilterNoHitEvents = true; } - mConfigData.mField = vm["field"].as<int>(); + mConfigData.mField = std::stoi((vm["field"].as<std::string>()).substr(0, (vm["field"].as<std::string>()).rfind("U"))); + mConfigData.mUniformField = (vm["field"].as<std::string>()).find("U") != std::string::npos; return true; } @@ -143,4 +148,49 @@ bool SimConfig::resetFromArguments(int argc, char* argv[]) return resetFromParsedMap(vm); } +namespace o2::conf +{ +// returns a reconfig struct given a configuration string (boost program options format) +bool parseSimReconfigFromString(std::string const& argumentstring, SimReconfigData& data) +{ + namespace bpo = boost::program_options; + + bpo::options_description options("Allowed options"); + + options.add_options()( + "nEvents,n", bpo::value<unsigned int>(&data.nEvents)->default_value(1), "number of events")( + "generator,g", bpo::value<std::string>(&data.generator)->default_value("boxgen"), "Event generator to be used.")( + "trigger,t", bpo::value<std::string>(&data.trigger)->default_value(""), "Event generator trigger to be used.")( + "startEvent", bpo::value<unsigned int>(&data.startEvent)->default_value(0), "index of first event to be used (when applicable)")( + "extKinFile", bpo::value<std::string>(&data.extKinfileName)->default_value("Kinematics.root"), + "name of kinematics file for event generator from file (when applicable)")( + "embedIntoFile", bpo::value<std::string>(&data.embedIntoFileName)->default_value(""), + "filename containing the reference events to be used for the embedding")( + "bMax,b", bpo::value<float>(&data.mBMax)->default_value(0.), "maximum value for impact parameter sampling (when applicable)")( + "outPrefix,o", bpo::value<std::string>(&data.outputPrefix)->default_value("o2sim"), "prefix of output files")( + "outDir,d", bpo::value<std::string>(&data.outputDir), "directory where to put simulation output (created when non-existant")( + "configKeyValues", bpo::value<std::string>(&data.keyValueTokens)->default_value(""), "semicolon separated key=value strings (e.g.: 'TPC.gasDensity=1;...")( + "configFile", bpo::value<std::string>(&data.configFile)->default_value(""), "Path to an INI or JSON configuration file")( + "chunkSize", bpo::value<unsigned int>(&data.primaryChunkSize)->default_value(500), "max size of primary chunk (subevent) distributed by server")( + "seed", bpo::value<int>(&data.startSeed)->default_value(-1), "initial seed (default: -1 random)")( + "stop", bpo::value<bool>(&data.stop)->default_value(false), "control command to shut down daemon"); + + bpo::variables_map vm; + try { + bpo::store(bpo::command_line_parser(bpo::split_unix(argumentstring)) + .options(options) + .run(), + vm); + bpo::notify(vm); + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing ReConfig data; Available options:\n"; + std::cerr << options << std::endl; + return false; + } + return true; +} + +} // namespace o2::conf + ClassImp(o2::conf::SimConfig); diff --git a/Common/SimConfig/src/SimConfigLinkDef.h b/Common/SimConfig/src/SimConfigLinkDef.h index bdc11be9af563..a850c57a3a21f 100644 --- a/Common/SimConfig/src/SimConfigLinkDef.h +++ b/Common/SimConfig/src/SimConfigLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,8 @@ #pragma link C++ class o2::conf::SimCutParams + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::SimCutParams> + ; +#pragma link C++ class o2::conf::SimMaterialParams + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::SimMaterialParams> + ; #pragma link C++ class o2::conf::SimUserDecay + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::SimUserDecay> + ; diff --git a/Common/SimConfig/src/SimCutParams.cxx b/Common/SimConfig/src/SimCutParams.cxx deleted file mode 100644 index 6a62be51909ca..0000000000000 --- a/Common/SimConfig/src/SimCutParams.cxx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/* - * SimCutParams.cxx - * - * Created on: Feb 18, 2019 - * Author: sandro - */ - -#include "SimConfig/SimCutParams.h" -O2ParamImpl(o2::conf::SimCutParams); diff --git a/Common/SimConfig/src/SimParams.cxx b/Common/SimConfig/src/SimParams.cxx new file mode 100644 index 0000000000000..11459a70144ad --- /dev/null +++ b/Common/SimConfig/src/SimParams.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/* + * SimCutParams.cxx + * + * Created on: Feb 18, 2019 + * Author: Sandro Wenzel + */ + +#include "SimConfig/SimParams.h" +O2ParamImpl(o2::conf::SimCutParams); +O2ParamImpl(o2::conf::SimMaterialParams); diff --git a/Common/SimConfig/src/SimUserDecay.cxx b/Common/SimConfig/src/SimUserDecay.cxx index 557f04a878dd6..1652729d15516 100644 --- a/Common/SimConfig/src/SimUserDecay.cxx +++ b/Common/SimConfig/src/SimUserDecay.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/test/TestConfig.cxx b/Common/SimConfig/test/TestConfig.cxx index 8605c6f6283a6..da7e780722497 100644 --- a/Common/SimConfig/test/TestConfig.cxx +++ b/Common/SimConfig/test/TestConfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/test/TestConfigurableParam.cxx b/Common/SimConfig/test/TestConfigurableParam.cxx index 1206295d0b7a7..7d099e54c5e1a 100644 --- a/Common/SimConfig/test/TestConfigurableParam.cxx +++ b/Common/SimConfig/test/TestConfigurableParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/SimConfig/test/testSimCutParam.cxx b/Common/SimConfig/test/testSimCutParam.cxx index 944617a59246f..7a17ae9d1f2cf 100644 --- a/Common/SimConfig/test/testSimCutParam.cxx +++ b/Common/SimConfig/test/testSimCutParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include "SimConfig/SimCutParams.h" +#include "SimConfig/SimParams.h" #include "CommonUtils/ConfigurableParam.h" using namespace o2::conf; diff --git a/Common/Types/CMakeLists.txt b/Common/Types/CMakeLists.txt index fa0bb8740f714..4dd6ad56e2458 100644 --- a/Common/Types/CMakeLists.txt +++ b/Common/Types/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(CommonTypes) diff --git a/Common/Types/include/CommonTypes/Units.h b/Common/Types/include/CommonTypes/Units.h index d8e9bffe483a5..9fdb0180081fd 100644 --- a/Common/Types/include/CommonTypes/Units.h +++ b/Common/Types/include/CommonTypes/Units.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/CMakeLists.txt b/Common/Utils/CMakeLists.txt index 2a1d6a4d1416a..e678031808d58 100644 --- a/Common/Utils/CMakeLists.txt +++ b/Common/Utils/CMakeLists.txt @@ -1,18 +1,24 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CommonUtils SOURCES src/TreeStream.cxx src/TreeStreamRedirector.cxx src/RootChain.cxx src/CompStream.cxx src/ShmManager.cxx - src/ValueMonitor.cxx - src/ConfigurableParamHelper.cxx src/ConfigurableParam.cxx + src/ValueMonitor.cxx + src/StringUtils.cxx + src/ConfigurableParamHelper.cxx src/ConfigurableParam.cxx src/RootSerializableKeyValueStore.cxx + src/KeyValParam.cxx + src/FileSystemUtils.cxx + src/FIFO.cxx + src/FileFetcher.cxx PUBLIC_LINK_LIBRARIES ROOT::Hist ROOT::Tree Boost::iostreams O2::CommonDataFormat O2::Headers FairLogger::FairLogger) @@ -25,9 +31,14 @@ o2_target_root_dictionary(CommonUtils include/CommonUtils/RngHelper.h include/CommonUtils/StringUtils.h include/CommonUtils/ValueMonitor.h - include/CommonUtils/MemFileHelper.h + include/CommonUtils/MemFileHelper.h include/CommonUtils/ConfigurableParam.h - include/CommonUtils/ConfigurableParamHelper.h) + include/CommonUtils/ConfigurableParamHelper.h + include/CommonUtils/ConfigurationMacroHelper.h + include/CommonUtils/RootSerializableKeyValueStore.h + include/CommonUtils/KeyValParam.h + include/CommonUtils/FileFetcher.h + ) o2_add_test(TreeStream COMPONENT_NAME CommonUtils @@ -45,7 +56,7 @@ o2_add_test(CompStream COMPONENT_NAME CommonUtils LABELS utils SOURCES test/testCompStream.cxx - PUBLIC_LINK_LIBRARIES O2::CommonUtils Boost::filesystem) + PUBLIC_LINK_LIBRARIES O2::CommonUtils) o2_add_test(ValueMonitor COMPONENT_NAME CommonUtils @@ -53,8 +64,19 @@ o2_add_test(ValueMonitor SOURCES test/testValueMonitor.cxx PUBLIC_LINK_LIBRARIES O2::CommonUtils) +o2_add_test(PropertyMapIO + COMPONENT_NAME CommonUtils + LABELS utils + SOURCES test/testRootSerializableKeyValueStore.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtils) + o2_add_test(MemFileHelper COMPONENT_NAME CommonUtils LABELS utils SOURCES test/testMemFileHelper.cxx PUBLIC_LINK_LIBRARIES O2::CommonUtils) + +o2_add_executable(treemergertool + COMPONENT_NAME CommonUtils + SOURCES src/TreeMergerTool.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtils Boost::program_options ROOT::Core) diff --git a/Common/Utils/include/CommonUtils/BoostHistogramUtils.h b/Common/Utils/include/CommonUtils/BoostHistogramUtils.h new file mode 100644 index 0000000000000..107162af49b48 --- /dev/null +++ b/Common/Utils/include/CommonUtils/BoostHistogramUtils.h @@ -0,0 +1,425 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file BoostHistogramUtils.h +/// \author Hannah Bossi, hannah.bossi@yale.edu + +#include <cmath> +#include <numeric> +#include <algorithm> +#include <vector> +#include <array> +#include <TH1.h> +#include <TH2.h> +#include <TFile.h> + +#include "Rtypes.h" +#include "TLinearFitter.h" +#include "TVectorD.h" +#include "TMath.h" +#include "TF1.h" +#include "Foption.h" +#include "HFitInterface.h" +#include "TFitResultPtr.h" +#include "TFitResult.h" +#include "Fit/Fitter.h" +#include "Fit/BinData.h" +#include "Math/WrappedMultiTF1.h" +#include <boost/histogram.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/format.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/accumulators/mean.hpp> + +namespace o2 +{ +namespace utils +{ + +/// \class BinCenterView +/// \brief Axis iterator over bin centers. +template <typename AxisIterator> +class BinCenterView +{ + public: + BinCenterView(AxisIterator iter) : mBaseIterator(iter) {} + ~BinCenterView() = default; + AxisIterator& + operator++() + { + ++mBaseIterator; + return mBaseIterator; + } + AxisIterator operator++(int) + { + AxisIterator result(mBaseIterator); + mBaseIterator++; + return result; + } + + decltype(auto) operator*() { return mBaseIterator->center(); } + + private: + AxisIterator mBaseIterator; +}; + +/// \class BinUpperView +/// \brief Axis iterator over bin upper edges. +template <typename AxisIterator> +class BinUpperView +{ + public: + BinUpperView(AxisIterator iter) : mBaseIterator(iter) {} + ~BinUpperView() = default; + AxisIterator& + operator++() + { + ++mBaseIterator; + return mBaseIterator; + } + AxisIterator operator++(int) + { + AxisIterator result(mBaseIterator); + mBaseIterator++; + return result; + } + + decltype(auto) operator*() { return mBaseIterator->upper(); } + + private: + AxisIterator mBaseIterator; +}; + +/// \class BinLowerView +/// \brief Axis iterator over bin lower edges. +template <typename AxisIterator> +class BinLowerView +{ + public: + BinLowerView(AxisIterator iter) : mBaseIterator(iter) {} + ~BinLowerView() = default; + AxisIterator& + operator++() + { + ++mBaseIterator; + return mBaseIterator; + } + AxisIterator operator++(int) + { + AxisIterator result(mBaseIterator); + mBaseIterator++; + return result; + } + + decltype(auto) operator*() { return mBaseIterator->lower(); } + + private: + AxisIterator mBaseIterator; +}; + +template <typename AxisIterator> +BinCenterView<AxisIterator> operator+(BinCenterView<AxisIterator> lhs, int n) +{ + BinCenterView<AxisIterator> result(lhs); + for (int i = 0; i < n; i++) { + ++result; + } + return result; +} + +template <typename AxisIterator> +BinUpperView<AxisIterator> operator+(BinUpperView<AxisIterator> lhs, int n) +{ + BinUpperView<AxisIterator> result(lhs); + for (int i = 0; i < n; i++) { + ++result; + } + return result; +} + +template <typename AxisIterator> +BinLowerView<AxisIterator> operator+(BinLowerView<AxisIterator> lhs, int n) +{ + BinLowerView<AxisIterator> result(lhs); + for (int i = 0; i < n; i++) { + ++result; + } + return result; +} + +template <typename T, int nparams> +class fitResult +{ + public: + fitResult() = default; + + fitResult(T chi2, const T (&list)[nparams]) : mChi2(chi2), + mFitParameters() + { + memcpy(mFitParameters.data(), list, sizeof(T) * nparams); + } + + /// \brief Get the paratmeters of a fit result. Ex: result.getParameter<1>(); + template <int index> + T getParameter() const + { + static_assert(index <= nparams, "Acessing invalid parameter"); + return mFitParameters[index]; + } + + /// \brief Set the paratmeters of a fit result. Ex: result.setParameter<1>(T(value))); + template <int index> + void setParameter(T parameter) + { + static_assert(index <= nparams, "Attempting to set invalid parameter"); + mFitParameters[index] = parameter; + } + + /// \brief Set the chi2 of the fit result. + void setChi2(double chi2In) + { + mChi2 = chi2In; + } + T getChi2() const { return mChi2; } + + private: + T mChi2; ///< chi2 of the fit + std::array<T, nparams> mFitParameters; ///< parameters of the fit (0-Constant, 1-Mean, 2-Sigma, 3-Sum) +}; + +/** + * \enum FitGausError_t + * \brief Error code for invalid result in the fitGaus process + */ +enum class FitGausError_t { + FIT_ERROR, ///< Fit procedure returned invalid result +}; + +/// \brief Printing an error message when then fit returns an invalid result +/// \param errorcode Error of the type FitGausError_t, thrown when fit result is invalid. +std::string createErrorMessage(FitGausError_t errorcode) +{ + return "[Error]: Fit return an invalid result."; +} + +/// \brief Function to fit histogram to a gaussian using iterators. +/// \param first begin iterator of the histogram +/// \param last end iterator of the histogram +/// \param axisFirst axis iterator over the bin centers +/// \return result +/// result is of the type fitResult, which contains 4 parameters (0-Constant, 1-Mean, 2-Sigma, 3-Sum) +/// +/// ** Temp Note: For now we forgo the templated struct in favor of a std::vector in order to +/// have this compile while we are working out the details +template <typename T, typename Iterator, typename BinCenterView> +std::vector<double> fitGaus(Iterator first, Iterator last, BinCenterView axisfirst) +{ + TLinearFitter fitter(3, "pol2"); + TMatrixD mat(3, 3); + Double_t kTol = mat.GetTol(); + fitter.StoreData(kFALSE); + fitter.ClearPoints(); + TVectorD par(3); + TVectorD sigma(3); + TMatrixD A(3, 3); + TMatrixD b(3, 1); + T rms = TMath::RMS(first, last); + // Markus: return type of std::max_element is an iterator, cannot cast implicitly to double + // better use auto + // pointer needs to be dereferenced afterwards + auto xMax = std::max_element(first, last); + auto xMin = std::min_element(first, last); + auto nbins = last - first; + const double binWidth = double(*xMax - *xMin) / double(nbins); + + Float_t meanCOG = 0; + Float_t rms2COG = 0; + Float_t sumCOG = 0; + + Float_t entries = 0; + Int_t nfilled = 0; + + for (auto iter = first; iter != last; iter++) { + entries += *iter; + if (*iter > 0) { + nfilled++; + } + } + + // TODO: Check why this is needed + if (*xMax < 4) { + throw FitGausError_t::FIT_ERROR; + } + if (entries < 12) { + throw FitGausError_t::FIT_ERROR; + } + + if (rms < kTol) { + throw FitGausError_t::FIT_ERROR; + } + + /* + fitResult<T, 4> result; + result.setParameter<3>(entries); + */ + // create the result, first fill it with all 0's + std::vector<double> result; + for (int r = 0; r < 5; r++) { + result.push_back(0); + } + // then set the third parameter to entries + result.at(3) = entries; + + int ibin = 0; + Int_t npoints = 0; + for (auto iter = first, axisiter = axisfirst; iter != last; iter++, axisiter++) { + if (nbins > 1) { + // Markus: For this we implemented the BinCenterView + double x = *axisfirst; + double y = *iter; + double ey = std::sqrt(y); + fitter.AddPoint(&x, y, ey); + if (npoints < 3) { + A(npoints, 0) = 1; + A(npoints, 1) = x; + A(npoints, 2) = x * x; + b(npoints, 0) = y; + meanCOG += x * nbins; + rms2COG += x * nbins * x; + sumCOG += nbins; + } + npoints++; + } + } + + Double_t chi2 = 0; + if (npoints >= 3) { + if (npoints == 3) { + //analytic calculation of the parameters for three points + A.Invert(); + TMatrixD res(1, 3); + res.Mult(A, b); + par[0] = res(0, 0); + par[1] = res(0, 1); + par[2] = res(0, 2); + chi2 = -3.; + } else { + // use fitter for more than three points + fitter.Eval(); + fitter.GetParameters(par); + fitter.GetCovarianceMatrix(mat); + //result.setChi2(fitter.GetChisquare() / Double_t(npoints)); + result.at(4) = (fitter.GetChisquare() / Double_t(npoints)); + } + if (TMath::Abs(par[1]) < kTol) { + throw FitGausError_t::FIT_ERROR; + ; + } + if (TMath::Abs(par[2]) < kTol) { + throw FitGausError_t::FIT_ERROR; + ; + } + + T param1 = T(par[1] / (-2. * par[2])); + //result.setParameter<1>(param1); + //result.setParameter<2>(T(1. / TMath::Sqrt(TMath::Abs(-2. * par[2])))); + result.at(1) = param1; + result.at(2) = T(1. / TMath::Sqrt(TMath::Abs(-2. * par[2]))); + auto lnparam0 = par[0] + par[1] * param1 + par[2] * param1 * param1; + if (lnparam0 > 307) { + throw FitGausError_t::FIT_ERROR; + ; + } + //result.setParameter<0>(TMath::Exp(lnparam0)); + result.at(0) = TMath::Exp(lnparam0); + return result; + } + + if (npoints == 2) { + //use center of gravity for 2 points + meanCOG /= sumCOG; + rms2COG /= sumCOG; + /* + result.setParameter<0>(xMax); + result.setParameter<1>(meanCOG); + result.setParameter<2>(TMath::Sqrt(TMath::Abs(meanCOG * meanCOG - rms2COG))); + result.setChi2(-2); + */ + result.at(0) = *xMax; + result.at(1) = meanCOG; + result.at(2) = TMath::Sqrt(TMath::Abs(meanCOG * meanCOG - rms2COG)); + result.at(4) = -2; + } + if (npoints == 1) { + meanCOG /= sumCOG; + /* + result.setParameter<0>(xMax); + result.setParameter<1>(meanCOG); + result.setParameter<2>(binWidth / TMath::Sqrt(12)); + result.setChi2(-1); + */ + result.at(0) = *xMax; + result.at(1) = meanCOG; + result.at(2) = binWidth / TMath::Sqrt(12); + result.at(4) = -1; + } + return result; +} + +template <typename valuetype, typename... axes> +std::vector<double> fitBoostHistoWithGaus(boost::histogram::histogram<axes...>& hist) +{ + return fitGaus<valuetype>(hist.begin(), hist.end(), BinCenterView(hist.axis(0).begin())); +} + +/// \brief Convert a 1D root histogram to a Boost histogram +auto boosthistoFromRoot_1D(TH1D* inHist1D) +{ + // first setup the proper boost histogram + int nBins = inHist1D->GetNbinsX(); + int xMin = inHist1D->GetXaxis()->GetXmin(); + int xMax = inHist1D->GetXaxis()->GetXmax(); + const char* title = inHist1D->GetXaxis()->GetTitle(); + auto mHisto = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nBins, xMin, xMax, title)); + + // trasfer the acutal values + for (Int_t x = 1; x < nBins + 1; x++) { + mHisto.at(x) = inHist1D->GetBinContent(x); + } + return mHisto; +} + +// \brief Convert a 2D root histogram to a Boost histogram +auto boostHistoFromRoot_2D(TH2D* inHist2D) +{ + // first setup the proper boost histogram + int nBinsX = inHist2D->GetNbinsX(); + int xMin = inHist2D->GetXaxis()->GetXmin(); + int xMax = inHist2D->GetXaxis()->GetXmax(); + const char* xTitle = inHist2D->GetXaxis()->GetTitle(); + int nBinsY = inHist2D->GetNbinsY(); + int yMin = inHist2D->GetYaxis()->GetXmin(); + int yMax = inHist2D->GetYaxis()->GetXmax(); + const char* yTitle = inHist2D->GetYaxis()->GetTitle(); + auto mHisto = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nBinsX, xMin, xMax, xTitle), boost::histogram::axis::regular<>(nBinsY, yMin, + yMax, yTitle)); + // trasfer the acutal values + for (Int_t x = 1; x < nBinsX + 1; x++) { + for (Int_t y = 1; y < nBinsY + 1; y++) { + mHisto.at(x, y) = inHist2D->GetBinContent(x, y); + } + } + return mHisto; +} + +} // end namespace utils +} // end namespace o2 diff --git a/Common/Utils/include/CommonUtils/BoostSerializer.h b/Common/Utils/include/CommonUtils/BoostSerializer.h index b1fd3dbb1cd2e..4c388a3daa8cc 100644 --- a/Common/Utils/include/CommonUtils/BoostSerializer.h +++ b/Common/Utils/include/CommonUtils/BoostSerializer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/CompStream.h b/Common/Utils/include/CommonUtils/CompStream.h index 7c2e704db3101..7bea9f40b6f3b 100644 --- a/Common/Utils/include/CommonUtils/CompStream.h +++ b/Common/Utils/include/CommonUtils/CompStream.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/ConfigurableParam.h b/Common/Utils/include/CommonUtils/ConfigurableParam.h index 9a7dcbb2d9c3b..6b53eb58de25e 100644 --- a/Common/Utils/include/CommonUtils/ConfigurableParam.h +++ b/Common/Utils/include/CommonUtils/ConfigurableParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -143,6 +144,12 @@ class ConfigurableParam /* can add more modes here */ }; + enum class EParamUpdateStatus { + Changed, // param was successfully changed + Unchanged, // param was not changed: new value is the same as previous + Failed // failed to update param + }; + static std::string toString(EParamProvenance p) { static std::array<std::string, 3> names = {"CODE", "CCDB", "RT"}; @@ -155,9 +162,20 @@ class ConfigurableParam // print the current keys and values to screen (optionally with provenance information) virtual void printKeyValues(bool showprov = true) const = 0; + // return the provenance of the member key + virtual EParamProvenance getMemberProvenance(const std::string& key) const = 0; + + static EParamProvenance getProvenance(const std::string& key); + static void printAllRegisteredParamNames(); static void printAllKeyValuePairs(); + static const std::string& getInputDir() { return sInputDir; } + static const std::string& getOutputDir() { return sOutputDir; } + + static void setInputDir(const std::string& d) { sInputDir = d; } + static void setOutputDir(const std::string& d) { sOutputDir = d; } + static boost::property_tree::ptree readINI(std::string const& filepath); static boost::property_tree::ptree readJSON(std::string const& filepath); static boost::property_tree::ptree readConfigFile(std::string const& filepath); @@ -189,7 +207,7 @@ class ConfigurableParam if (sPtree->get_optional<std::string>(key).is_initialized()) { sPtree->put(key, x); auto changed = updateThroughStorageMap(mainkey, subkey, typeid(T), (void*)&x); - if (changed) { + if (changed != EParamUpdateStatus::Failed) { sValueProvenanceMap->find(key)->second = kRT; // set to runtime } } @@ -210,7 +228,7 @@ class ConfigurableParam if (sPtree->get_optional<std::string>(key).is_initialized()) { sPtree->put(key, valuestring); auto changed = updateThroughStorageMapWithConversion(key, valuestring); - if (changed) { + if (changed != EParamUpdateStatus::Failed) { sValueProvenanceMap->find(key)->second = kRT; // set to runtime } } @@ -240,7 +258,13 @@ class ConfigurableParam static void updateFromString(std::string const&); // provide a path to a configuration file with ConfigurableParam key/values - static void updateFromFile(std::string const&); + // If nonempty comma-separated paramsList is provided, only those params will + // be updated, absence of data for any of requested params will lead to fatal + static void updateFromFile(std::string const&, std::string const& paramsList = "", bool unchangedOnly = false); + + // interface for use from the CCDB API; allows to sync objects read from CCDB with the information + // stored in the registry; modifies given object as well as registry + virtual void syncCCDBandRegistry(void* obj) = 0; protected: // constructor is doing nothing else but @@ -250,8 +274,8 @@ class ConfigurableParam friend std::ostream& operator<<(std::ostream& out, const ConfigurableParam& me); static void initPropertyTree(); - static bool updateThroughStorageMap(std::string, std::string, std::type_info const&, void*); - static bool updateThroughStorageMapWithConversion(std::string const&, std::string const&); + static EParamUpdateStatus updateThroughStorageMap(std::string, std::string, std::type_info const&, void*); + static EParamUpdateStatus updateThroughStorageMapWithConversion(std::string const&, std::string const&); virtual ~ConfigurableParam() = default; @@ -273,9 +297,13 @@ class ConfigurableParam // (stored as a vector of pairs <enumValueLabel, enumValueInt>) static EnumRegistry* sEnumRegistry; + static std::string sInputDir; + static std::string sOutputDir; + void setRegisterMode(bool b) { sRegisterMode = b; } bool isInitialized() const { return sIsFullyInitialized; } + // friend class o2::ccdb::CcdbApi; private: // static registry for implementations of this type static std::vector<ConfigurableParam*>* sRegisteredParamClasses; //! diff --git a/Common/Utils/include/CommonUtils/ConfigurableParamHelper.h b/Common/Utils/include/CommonUtils/ConfigurableParamHelper.h index 0a3ca1303af72..f52a9e0675363 100644 --- a/Common/Utils/include/CommonUtils/ConfigurableParamHelper.h +++ b/Common/Utils/include/CommonUtils/ConfigurableParamHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,6 +55,8 @@ class _ParamHelper static void assignmentImpl(std::string const& mainkey, TClass* cl, void* to, void* from, std::map<std::string, ConfigurableParam::EParamProvenance>* provmap); + static void syncCCDBandRegistry(std::string const& mainkey, TClass* cl, void* to, void* from, + std::map<std::string, ConfigurableParam::EParamProvenance>* provmap); static void outputMembersImpl(std::ostream& out, std::string const& mainkey, std::vector<ParamDataMember> const* members, bool showProv); static void printMembersImpl(std::string const& mainkey, std::vector<ParamDataMember> const* members, bool showProv); @@ -82,6 +85,13 @@ class ConfigurableParamHelper : virtual public ConfigurableParam return P::sKey; } + // ---------------------------------------------------------------- + // get the provenace of the member with given key + EParamProvenance getMemberProvenance(const std::string& key) const final + { + return getProvenance(getName() + '.' + key); + } + // ---------------------------------------------------------------- // one of the key methods, using introspection to print itself @@ -157,6 +167,22 @@ class ConfigurableParamHelper : virtual public ConfigurableParam // ---------------------------------------------------------------- + void syncCCDBandRegistry(void* externalobj) final + { + // We may be getting an external copy from CCDB which is passed as externalobj. + // The task of this function is to + // a) update the internal registry with fields coming from CCDB + // but only if keys have not been modified via RT == command line / ini file + // b) update the external object with with fields having RT provenance + // + setRegisterMode(false); + _ParamHelper::syncCCDBandRegistry(getName(), TClass::GetClass(typeid(P)), (void*)this, (void*)externalobj, + sValueProvenanceMap); + setRegisterMode(true); + } + + // ---------------------------------------------------------------- + void serializeTo(TFile* file) const final { file->WriteObjectAny((void*)this, TClass::GetClass(typeid(P)), getName().c_str()); diff --git a/Generators/include/Generators/ConfigurationMacroHelper.h b/Common/Utils/include/CommonUtils/ConfigurationMacroHelper.h similarity index 79% rename from Generators/include/Generators/ConfigurationMacroHelper.h rename to Common/Utils/include/CommonUtils/ConfigurationMacroHelper.h index cc34961d33445..333efe01a9f5f 100644 --- a/Generators/include/Generators/ConfigurationMacroHelper.h +++ b/Common/Utils/include/CommonUtils/ConfigurationMacroHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,8 +11,8 @@ /// \author R+Preghenella - February 2020 -#ifndef ALICEO2_EVENTGEN_CONFIGURATIONMACRO_H_ -#define ALICEO2_EVENTGEN_CONFIGURATIONMACRO_H_ +#ifndef ALICEO2_CONF_CONFIGURATIONMACRO_H_ +#define ALICEO2_CONF_CONFIGURATIONMACRO_H_ #include "FairLogger.h" #include "TROOT.h" @@ -22,7 +23,7 @@ namespace o2 { -namespace eventgen +namespace conf { template <typename T> @@ -67,7 +68,7 @@ T GetFromMacro(const std::string& file, const std::string& funcname, const std:: return *ptr; } -} // namespace eventgen +} // namespace conf } // namespace o2 -#endif /* ALICEO2_EVENTGEN_CONFIGURATIONMACRO_H_ */ +#endif /* ALICEO2_CONF_CONFIGURATIONMACRO_H_ */ diff --git a/Common/Utils/include/CommonUtils/FIFO.h b/Common/Utils/include/CommonUtils/FIFO.h new file mode 100644 index 0000000000000..94942277daa0a --- /dev/null +++ b/Common/Utils/include/CommonUtils/FIFO.h @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch +/// Thread-safe FIFO + +#ifndef ALICEO2_FIFOUTILS_H_ +#define ALICEO2_FIFOUTILS_H_ + +#include <deque> +#include <mutex> + +namespace o2 +{ +namespace utils +{ + +template <typename T> +class FIFO +{ + public: + size_t size() const + { + std::lock_guard<std::mutex> lock(mMutex); + return mQueue.size(); + } + + void clear() + { + std::lock_guard<std::mutex> lock(mMutex); + mQueue.clear(); + } + + bool empty() const + { + std::lock_guard<std::mutex> lock(mMutex); + return mQueue.empty(); + } + + template <typename... Args> + void push(Args&&... args) + { + std::lock_guard<std::mutex> lock(mMutex); + mQueue.emplace_back(std::forward<Args>(args)...); + } + + void pop() + { + std::lock_guard<std::mutex> lock(mMutex); + if (!mQueue.empty()) { + mQueue.pop_front(); + } + } + + const T& front() const + { + std::lock_guard<std::mutex> lock(mMutex); + if (mQueue.empty()) { + throw std::runtime_error("attempt to access front of empty queue"); + } + return mQueue.front(); + } + + T& front() + { + std::lock_guard<std::mutex> lock(mMutex); + if (mQueue.empty()) { + throw std::runtime_error("attempt to access front of empty queue"); + } + return mQueue.front(); + } + + const T* frontPtr() const + { + std::lock_guard<std::mutex> lock(mMutex); + if (mQueue.empty()) { + return nullptr; + } + return &mQueue.front(); + } + + T* frontPtr() + { + std::lock_guard<std::mutex> lock(mMutex); + if (mQueue.empty()) { + return nullptr; + } + return &mQueue.front(); + } + + auto& getQueue() const { return mQueue; } + + private: + mutable std::mutex mMutex; + std::deque<T> mQueue{}; +}; + +} // namespace utils +} // namespace o2 + +#endif diff --git a/Common/Utils/include/CommonUtils/FileFetcher.h b/Common/Utils/include/CommonUtils/FileFetcher.h new file mode 100644 index 0000000000000..83d77635eef7c --- /dev/null +++ b/Common/Utils/include/CommonUtils/FileFetcher.h @@ -0,0 +1,117 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch +/// Code mostly based on DataDistribution:SubTimeFrameFileSource by Gvozden Nescovic + +#ifndef ALICEO2_FILEFETCHER_H_ +#define ALICEO2_FILEFETCHER_H_ + +#include "CommonUtils/FIFO.h" +#include <unordered_map> +#include <string> +#include <thread> +#include <Rtypes.h> +#include <mutex> +#include <regex> + +namespace o2 +{ +namespace utils +{ + +class FileFetcher +{ + public: + struct FileRef { + std::string origName{}; + std::string localName{}; // local alias for for remote files + bool remote = false; + bool copied = false; + + const auto& getLocalName() const { return remote ? localName : origName; } + const auto& getOrigName() const { return origName; } + }; + + /* + * Create file fetcher with predefined cache and async copy of remote files + * + * @param input: comma-separated list of input data files and/or files with list of data files and/or directories + * @param selRegex: regex expression to select files needed for input + * @param remRegex: optional regex expression to recognize remote files + * @param copyCmd: optional command to copy remote files in format "<operation> ?src ?dst" + * @param copyCmd: base directory for copied remote files + */ + FileFetcher(const std::string& input, + const std::string& selRegex = "", + const std::string& remRegex = "", + const std::string& copyCmd = "", + const std::string& copyDir = "/tmp"); + ~FileFetcher(); + + const auto& getFileRef(size_t i) const { return mInputFiles[i]; } + + void setMaxFilesInQueue(size_t s) { mMaxInQueue = s > 0 ? s : 1; } + void setMaxLoops(size_t v) { mMaxLoops = v; } + bool isRunning() const { return mRunning; } + void start(); + void stop(); + void cleanup(); + size_t getNLoops() const { return mNLoops; } + size_t getNFilesProc() const { return mNFilesProc; } + size_t getNFilesProcOK() const { return mNFilesProcOK; } + size_t getMaxFilesInQueue() const { return mMaxInQueue; } + size_t getNRemoteFiles() const { return mNRemote; } + size_t getNFiles() const { return mInputFiles.size(); } + size_t popFromQueue(bool discard = false); + size_t getQueueSize() const { return mQueue.size(); } + std::string getNextFileInQueue() const; + void discardFile(const std::string& fname); + + private: + size_t nextInQueue() const; + void processInput(const std::string& input); + void processInput(const std::vector<std::string>& input); + void processDirectory(const std::string& name); + bool addInputFile(const std::string& fname); + std::string createCopyName(const std::string& fname) const; + bool copyFile(size_t id); + bool isRemote(const std::string& fname) const; + void fetcher(); + + private: + FIFO<size_t> mQueue{}; + std::string mCopyDirName{"/tmp"}; + std::string mCopyCmdLogFile{}; + std::string mCopyCmd{}; + std::unique_ptr<std::regex> mSelRegex; + std::unique_ptr<std::regex> mRemRegex; + std::unordered_map<std::string, size_t> mCopied{}; + std::vector<FileRef> mInputFiles{}; + size_t mNRemote{0}; + size_t mMaxInQueue{5}; + bool mRunning = false; + bool mNoRemoteCopy = false; + size_t mMaxLoops = 0; + size_t mNLoops = 0; + size_t mNFilesProc = 0; + size_t mNFilesProcOK = 0; + mutable std::mutex mMtx; + std::mutex mMtxStop; + std::thread mFetcherThread{}; + + ClassDefNV(FileFetcher, 1); +}; + +} // namespace utils +} // namespace o2 + +#endif diff --git a/Common/Utils/include/CommonUtils/FileSystemUtils.h b/Common/Utils/include/CommonUtils/FileSystemUtils.h new file mode 100644 index 0000000000000..6de418448b14e --- /dev/null +++ b/Common/Utils/include/CommonUtils/FileSystemUtils.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// A C++ way to list / iterate files with glob searches + +#ifndef O2_FILEITERATOR_H +#define O2_FILEITERATOR_H + +#include <vector> +#include <string> + +namespace o2::utils +{ + +// Return a vector of file names (not directories), with full path information, in a given directory "dir". +// If searchpattern is empty, all files will be returned. Otherwise +// searchpattern will be treated/parsed as a proper regular expression. +std::vector<std::string> listFiles(std::string const& dir, std::string const& searchpattern); + +// same in the current dir +std::vector<std::string> listFiles(std::string const& searchpattern); + +} // namespace o2::utils + +#endif //O2_FILEITERATOR_H diff --git a/Common/Utils/include/CommonUtils/KeyValParam.h b/Common/Utils/include/CommonUtils/KeyValParam.h new file mode 100644 index 0000000000000..11820be28b6f4 --- /dev/null +++ b/Common/Utils/include/CommonUtils/KeyValParam.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch +/// \brief params for ConfigurableParam + +#ifndef COMMON_CONFIGURABLE_KEYVAL_PARAM_H_ +#define COMMON_CONFIGURABLE_KEYVAL_PARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace conf +{ +struct KeyValParam : public o2::conf::ConfigurableParamHelper<KeyValParam> { + std::string input_dir = "none"; + std::string output_dir = "none"; + + O2ParamDef(KeyValParam, "keyval"); +}; +} // namespace conf +} // namespace o2 + +#endif diff --git a/Common/Utils/include/CommonUtils/MemFileHelper.h b/Common/Utils/include/CommonUtils/MemFileHelper.h index 87fa2ba896e81..fa7c61954a065 100644 --- a/Common/Utils/include/CommonUtils/MemFileHelper.h +++ b/Common/Utils/include/CommonUtils/MemFileHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -78,7 +79,7 @@ struct MemFileHelper { LOG(ERROR) << "Could not retrieve ROOT dictionary for type " << tinfo.name(); } else { clname = tcl->GetName(); - utils::trim(clname); + o2::utils::Str::trim(clname); } return clname; } diff --git a/Common/Utils/include/CommonUtils/RngHelper.h b/Common/Utils/include/CommonUtils/RngHelper.h index 25d01f3e445cc..162554138ad19 100644 --- a/Common/Utils/include/CommonUtils/RngHelper.h +++ b/Common/Utils/include/CommonUtils/RngHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/RootChain.h b/Common/Utils/include/CommonUtils/RootChain.h index 8e1887e966d8f..6dde8e3f422b9 100644 --- a/Common/Utils/include/CommonUtils/RootChain.h +++ b/Common/Utils/include/CommonUtils/RootChain.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h b/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h new file mode 100644 index 0000000000000..80545997af159 --- /dev/null +++ b/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h @@ -0,0 +1,261 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_ROOTSERKEYVALUESTORE_H +#define ALICEO2_ROOTSERKEYVALUESTORE_H + +#include <map> +#include <string> +#include <TClass.h> +#include <Rtypes.h> +#include <typeinfo> +#include <typeindex> +#include <TBufferFile.h> +#include <type_traits> +#include <cstring> + +namespace o2 +{ +namespace utils +{ + +/// A ROOT serializable container mapping a key (string) to an object of arbitrary type. +/// +/// The container allows to group objects in heterogeneous type in a key-value container. +/// The container can be ROOT serialized which adds on-top of existing solutions such as boost::property_tree. +/// This may be useful in various circumenstances, for +/// instance to assemble various CCDB objects into a single aggregate to reduce the number of CCDB files/entries. +class RootSerializableKeyValueStore +{ + public: + /// Structure encapsulating the stored information: raw buffers and attached type information (combination of type_index_hash and TClass information) + struct SerializedInfo { + SerializedInfo() = default; + SerializedInfo(void* o, int N, char* b, TClass* cl, std::string const& s) : objptr(o), N(N), bufferptr(b), cl(cl), typeinfo_name(s) {} + SerializedInfo(SerializedInfo const& other) + { + // we do a deep copy + N = other.N; + bufferptr = new char[N]; + std::memcpy(bufferptr, other.bufferptr, sizeof(char) * N); + objptr = nullptr; + cl = other.cl; + typeinfo_name = other.typeinfo_name; + } + SerializedInfo& operator=(SerializedInfo const& other) + { + SerializedInfo temp(other); + std::swap(*this, temp); + return *this; + } + + void* objptr = nullptr; //! pointer to existing object in memory + Int_t N = 0; + char* bufferptr = nullptr; //[N] pointer to serialized buffer + + // we use the TClass and/or the type_index_hash for type idendification + TClass* cl = nullptr; + std::string typeinfo_name; // typeinfo name that can be used to store type if TClass not available (for PODs!) + ClassDefNV(SerializedInfo, 1); + }; + + enum class GetState { + kOK = 0, + kNOSUCHKEY = 1, + kWRONGTYPE = 2, + kNOTCLASS = 3 + }; + + private: + static constexpr const char* GetStateString[4] = { + "ok", + "no such key", + "wrong type", + "no TClass"}; + + public: + static const char* getStateString(GetState state) + { + return (int)state < 4 ? GetStateString[(int)state] : nullptr; + }; + + RootSerializableKeyValueStore() = default; + + /// Putting a value (and overrides previous entries) + /// T needs to be trivial non-pointer type or a type having a ROOT TClass instance + template <typename T> + void put(std::string const& key, T const& value) + { + remove_entry(key); + GetState s; + return put_impl(key, value, s, int{}); + } + + /// returns object pointer for this key or nullptr if error or does not exist. + template <typename T> + const T* get(std::string const& key) const + { + GetState s; + return get_impl<T>(key, s, int{}); + } + + /// returns object pointer for this key or nullptr if error or does not exist; state is set with meaningful error code + template <typename T> + const T* get(std::string const& key, GetState& state) const + { + return get_impl<T>(key, state, int{}); + } + + /// get interface returning a const reference instead of pointer; Error handling/detection is done via the state argument; + /// Beware: In case of errors, a default object is returned. + template <typename T> + const T& getRef(std::string const& key, GetState& state) const + { + auto ptr = get_impl<T>(key, state, int{}); + if (ptr) { + return *ptr; + } else { + static T t = T(); + // in case of error we return a default object + return t; + } + } + + /// checks if a key exists + bool has(std::string const& key) const + { + return mStore.find(key) != mStore.end(); + } + + /// clear the store + void clear() + { + mStore.clear(); + } + + /// print list of keys and type information + void print() const; + + private: + std::map<std::string, SerializedInfo> mStore; + + // generic implementation for put relying on TClass + template <typename T> + void put_impl(std::string const& key, T const& value, GetState& state, ...) + { + // make sure we have a TClass for this + // if there is a TClass, we'll use ROOT serialization to encode into the buffer + auto ptr = new T(value); + auto cl = TClass::GetClass(typeid(value)); + if (!cl) { + state = GetState::kNOTCLASS; + return; + } + char* bufferptr = nullptr; + TBufferFile buff(TBuffer::kWrite); + buff.WriteObjectAny(ptr, cl); + int N = buff.Length(); + bufferptr = new char[N]; + memcpy(bufferptr, buff.Buffer(), sizeof(char) * N); + + auto name = std::type_index(typeid(value)).name(); + mStore.insert(std::pair<std::string, SerializedInfo>(key, SerializedInfo((void*)ptr, N, (char*)bufferptr, cl, name))); + } + + // implementation for put for trivial types + template <typename T, typename std::enable_if<std::is_trivial<T>::value, T>::type* = nullptr> + void put_impl(std::string const& key, T const& value, GetState& state, int) + { + // we forbid pointers + static_assert(!std::is_pointer<T>::value); + // serialization of trivial types is easy (not based on ROOT) + auto ptr = new T(value); + int N = sizeof(T); + auto bufferptr = new char[N]; + memcpy(bufferptr, (char*)ptr, sizeof(char) * N); + + auto name = std::type_index(typeid(value)).name(); + mStore.insert(std::pair<std::string, SerializedInfo>(key, SerializedInfo((void*)ptr, N, (char*)bufferptr, nullptr, name))); + } + + // generic implementation for get relying on TClass + template <typename T> + const T* get_impl(std::string const& key, GetState& state, ...) const + { + state = GetState::kOK; + auto iter = mStore.find(key); + if (iter != mStore.end()) { + auto& info = const_cast<SerializedInfo&>(iter->second); + auto cl = TClass::GetClass(typeid(T)); + if (!cl) { + state = GetState::kNOTCLASS; + return nullptr; + } + if (info.cl && strcmp(cl->GetName(), info.cl->GetName()) == 0) { + // if there is a (cached) object pointer ... we return it + if (info.objptr) { + return (T*)info.objptr; + } + // do this only once and cache instance into info.objptr + TBufferFile buff(TBuffer::kRead, info.N, info.bufferptr, false, nullptr); + buff.Reset(); + auto instance = (T*)buff.ReadObjectAny(cl); + info.objptr = instance; + return (T*)info.objptr; + } else { + state = GetState::kWRONGTYPE; + return nullptr; + } + } + state = GetState::kNOSUCHKEY; + return nullptr; + } + + // implementation for standard POD types + template <typename T, typename std::enable_if<std::is_trivial<T>::value, T>::type* = nullptr> + const T* get_impl(std::string const& key, GetState& state, int) const + { + state = GetState::kOK; + auto iter = mStore.find(key); + if (iter != mStore.end()) { + auto& info = const_cast<SerializedInfo&>(iter->second); + if (strcmp(std::type_index(typeid(T)).name(), info.typeinfo_name.c_str()) == 0) { + // if there is a (cached) object pointer ... we return it + if (info.objptr) { + return (T*)info.objptr; + } + info.objptr = (T*)info.bufferptr; + return (T*)info.objptr; + } else { + state = GetState::kWRONGTYPE; + return nullptr; + } + } + state = GetState::kNOSUCHKEY; + return nullptr; + } + + // removes a previous entry + void remove_entry(std::string const& key) + { + auto iter = mStore.find(key); + if (iter != mStore.end()) { + mStore.erase(iter); + } + } + + ClassDefNV(RootSerializableKeyValueStore, 2); +}; + +} // namespace utils +} // namespace o2 + +#endif diff --git a/Common/Utils/include/CommonUtils/ShmAllocator.h b/Common/Utils/include/CommonUtils/ShmAllocator.h index fbc3b62b77721..77841ecb025dc 100644 --- a/Common/Utils/include/CommonUtils/ShmAllocator.h +++ b/Common/Utils/include/CommonUtils/ShmAllocator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/ShmManager.h b/Common/Utils/include/CommonUtils/ShmManager.h index 72308780bff16..06dba283fec82 100644 --- a/Common/Utils/include/CommonUtils/ShmManager.h +++ b/Common/Utils/include/CommonUtils/ShmManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/StringUtils.h b/Common/Utils/include/CommonUtils/StringUtils.h index 998f5029f77f1..364ad6365c766 100644 --- a/Common/Utils/include/CommonUtils/StringUtils.h +++ b/Common/Utils/include/CommonUtils/StringUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,77 +18,122 @@ #define ALICEO2_STRINGUTILS_H #include <sstream> +#include <vector> +#include <algorithm> +#include <fmt/format.h> +#include <Rtypes.h> namespace o2 { namespace utils { -// Code for trimming coming from https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring +struct Str { -/** + // Code for trimming coming from https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring + + /** * Trim from start (in place) * @param s */ -static inline void ltrim(std::string& s) -{ - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); -} + static inline void ltrim(std::string& s) + { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); + } -/** Trim from end (in place) + /** Trim from end (in place) * * @param s */ -static inline void rtrim(std::string& s) -{ - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), - s.end()); -} + static inline void rtrim(std::string& s) + { + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); + } -/** + /** * Trim from both ends (in place) * @param s */ -static inline void trim(std::string& s) -{ - ltrim(s); - rtrim(s); -} + static inline void trim(std::string& s) + { + ltrim(s); + rtrim(s); + } -/** + /** * Trim from start (copying) * @param s * @return */ -static inline std::string ltrim_copy(std::string s) -{ - ltrim(s); - return s; -} + static inline std::string ltrim_copy(const std::string& s) + { + std::string ss = s; + ltrim(ss); + return ss; + } -/** + /** * Trim from end (copying) * @param s * @return */ -static inline std::string rtrim_copy(std::string s) -{ - rtrim(s); - return s; -} + static inline std::string rtrim_copy(const std::string& s) + { + std::string ss = s; + rtrim(ss); + return ss; + } -// concatenate arbitrary number of strings -template <typename... Ts> -std::string concat_string(Ts const&... ts) -{ - std::stringstream s; - (s << ... << ts); - return s.str(); -} + /** + * Trim from both sides (copying) + * @param s + * @return + */ + static inline std::string trim_copy(const std::string& s) + { + std::string ss = s; + rtrim(ss); + return ss; + } + + static inline bool endsWith(const std::string& s, const std::string& ending) + { + return (ending.size() > s.size()) ? false : std::equal(ending.rbegin(), ending.rend(), s.rbegin()); + } + + // return vector of tokens from the string with provided delimiter. If requested, trim the spaces from tokens + static std::vector<std::string> tokenize(const std::string& src, char delim, bool trimToken = true); + + // concatenate arbitrary number of strings + template <typename... Ts> + static std::string concat_string(Ts const&... ts) + { + std::stringstream s; + (s << ... << ts); + return s.str(); + } + + // generate random string of given length, suitable for file names + static std::string getRandomString(int length); + + // Check if the path exists + static bool pathExists(const std::string_view p); + + // Check if the path is a directory + static bool pathIsDirectory(const std::string_view p); + + // create full path + static std::string getFullPath(const std::string_view p); + + // rectify directory, applying convention "none"=="" + static std::string rectifyDirectory(const std::string_view p); + + // create unique non-existing path name starting with prefix. Loose equivalent of boost::filesystem::unique_path() + // in absence of such a function in std::filesystem + static std::string create_unique_path(const std::string_view prefix = "", int length = 16); + + ClassDefNV(Str, 1); +}; } // namespace utils } // namespace o2 diff --git a/Common/Utils/include/CommonUtils/TreeStream.h b/Common/Utils/include/CommonUtils/TreeStream.h index 6882176632d57..a5adeec810865 100644 --- a/Common/Utils/include/CommonUtils/TreeStream.h +++ b/Common/Utils/include/CommonUtils/TreeStream.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/TreeStreamRedirector.h b/Common/Utils/include/CommonUtils/TreeStreamRedirector.h index 75b3eeabf6e76..8199009df400d 100644 --- a/Common/Utils/include/CommonUtils/TreeStreamRedirector.h +++ b/Common/Utils/include/CommonUtils/TreeStreamRedirector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/include/CommonUtils/ValueMonitor.h b/Common/Utils/include/CommonUtils/ValueMonitor.h index c2168918d534f..ed7d314595773 100644 --- a/Common/Utils/include/CommonUtils/ValueMonitor.h +++ b/Common/Utils/include/CommonUtils/ValueMonitor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/CommonUtilsLinkDef.h b/Common/Utils/src/CommonUtilsLinkDef.h index 2dc1ac8ab97ec..aeae05ceb6ba3 100644 --- a/Common/Utils/src/CommonUtilsLinkDef.h +++ b/Common/Utils/src/CommonUtilsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,5 +20,15 @@ #pragma link C++ class o2::utils::RootChain + ; #pragma link C++ class o2::utils::RngHelper; #pragma link C++ class o2::utils::MemFileHelper + ; +#pragma link C++ class o2::utils::RootSerializableKeyValueStore::SerializedInfo + ; +#pragma link C++ class o2::utils::Str + ; +#pragma link C++ class o2::utils::FileFetcher + ; + +#pragma link C++ class pair < string, o2::utils::RootSerializableKeyValueStore::SerializedInfo> + ; +#pragma link C++ class map < string, o2::utils::RootSerializableKeyValueStore::SerializedInfo> + ; +#pragma link C++ class o2::utils::RootSerializableKeyValueStore + ; + +#pragma link C++ class o2::conf::KeyValParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::KeyValParam> + ; #endif diff --git a/Common/Utils/src/CompStream.cxx b/Common/Utils/src/CompStream.cxx index 8a39dc037a019..f40f3327364f3 100644 --- a/Common/Utils/src/CompStream.cxx +++ b/Common/Utils/src/CompStream.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/ConfigurableParam.cxx b/Common/Utils/src/ConfigurableParam.cxx index 73d32880ac5f0..89870b3747a06 100644 --- a/Common/Utils/src/ConfigurableParam.cxx +++ b/Common/Utils/src/ConfigurableParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,9 @@ //first version 8/2018, Sandro Wenzel #include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/StringUtils.h" +#include "CommonUtils/KeyValParam.h" #include <boost/algorithm/string/predicate.hpp> -#include <boost/filesystem.hpp> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/json_parser.hpp> @@ -34,6 +36,7 @@ #include "TFile.h" #include "TEnum.h" #include "TEnumConstant.h" +#include <filesystem> namespace o2 { @@ -43,6 +46,8 @@ std::vector<ConfigurableParam*>* ConfigurableParam::sRegisteredParamClasses = nu boost::property_tree::ptree* ConfigurableParam::sPtree = nullptr; std::map<std::string, std::pair<std::type_info const&, void*>>* ConfigurableParam::sKeyToStorageMap = nullptr; std::map<std::string, ConfigurableParam::EParamProvenance>* ConfigurableParam::sValueProvenanceMap = nullptr; +std::string ConfigurableParam::sInputDir = ""; +std::string ConfigurableParam::sOutputDir = ""; EnumRegistry* ConfigurableParam::sEnumRegistry = nullptr; bool ConfigurableParam::sIsFullyInitialized = false; @@ -56,46 +61,8 @@ std::ostream& operator<<(std::ostream& out, ConfigurableParam const& param) return out; } -// ------------------------------------------------------------------ - -// Remove leading whitespace -std::string ltrimSpace(std::string src) -{ - return src.erase(0, src.find_first_not_of(' ')); -} - -// Remove trailing whitespace -std::string rtrimSpace(std::string src) -{ - return src.erase(src.find_last_not_of(' ') + 1); -} - -// Remove leading/trailing whitespace -std::string trimSpace(std::string const& src) -{ - return ltrimSpace(rtrimSpace(src)); -} - -// Split a given string on a delim character, return vector of tokens -// If trim is true, then also remove leading/trailing whitespace of each token. -std::vector<std::string> splitString(const std::string& src, char delim, bool trim = false) -{ - std::stringstream ss(src); - std::string token; - std::vector<std::string> tokens; - - while (std::getline(ss, token, delim)) { - token = (trim ? trimSpace(token) : token); - if (!token.empty()) { - tokens.push_back(std::move(token)); - } - } - - return tokens; -} - // Does the given key exist in the boost property tree? -bool keyInTree(boost::property_tree::ptree* pt, std::string key) +bool keyInTree(boost::property_tree::ptree* pt, const std::string& key) { if (key.size() == 0 || pt == nullptr) { return false; @@ -203,17 +170,22 @@ int EnumLegalValues::getIntValue(const std::string& value) const void ConfigurableParam::writeINI(std::string const& filename, std::string const& keyOnly) { + if (sOutputDir == "/dev/null") { + LOG(INFO) << "ignoring writing of ini file " << filename; + return; + } + auto outfilename = o2::utils::Str::concat_string(sOutputDir, filename); initPropertyTree(); // update the boost tree before writing if (!keyOnly.empty()) { // write ini for selected key only try { boost::property_tree::ptree kTree; kTree.add_child(keyOnly, sPtree->get_child(keyOnly)); - boost::property_tree::write_ini(filename, kTree); + boost::property_tree::write_ini(outfilename, kTree); } catch (const boost::property_tree::ptree_bad_path& err) { LOG(FATAL) << "non-existing key " << keyOnly << " provided to writeINI"; } } else { - boost::property_tree::write_ini(filename, *sPtree); + boost::property_tree::write_ini(outfilename, *sPtree); } } @@ -221,16 +193,17 @@ void ConfigurableParam::writeINI(std::string const& filename, std::string const& boost::property_tree::ptree ConfigurableParam::readConfigFile(std::string const& filepath) { - if (!boost::filesystem::exists(filepath)) { - LOG(FATAL) << filepath << " : config file does not exist!"; + auto inpfilename = o2::utils::Str::concat_string(sInputDir, filepath); + if (!std::filesystem::exists(inpfilename)) { + LOG(FATAL) << inpfilename << " : config file does not exist!"; } boost::property_tree::ptree pt; - if (boost::iends_with(filepath, ".ini")) { - pt = readINI(filepath); - } else if (boost::iends_with(filepath, ".json")) { - pt = readJSON(filepath); + if (boost::iends_with(inpfilename, ".ini")) { + pt = readINI(inpfilename); + } else if (boost::iends_with(inpfilename, ".json")) { + pt = readJSON(inpfilename); } else { LOG(FATAL) << "Configuration file must have either .ini or .json extension"; } @@ -273,17 +246,22 @@ boost::property_tree::ptree ConfigurableParam::readJSON(std::string const& filep void ConfigurableParam::writeJSON(std::string const& filename, std::string const& keyOnly) { + if (sOutputDir == "/dev/null") { + LOG(INFO) << "ignoring writing of json file " << filename; + return; + } initPropertyTree(); // update the boost tree before writing + auto outfilename = o2::utils::Str::concat_string(sOutputDir, filename); if (!keyOnly.empty()) { // write ini for selected key only try { boost::property_tree::ptree kTree; kTree.add_child(keyOnly, sPtree->get_child(keyOnly)); - boost::property_tree::write_json(filename, kTree); + boost::property_tree::write_json(outfilename, kTree); } catch (const boost::property_tree::ptree_bad_path& err) { LOG(FATAL) << "non-existing key " << keyOnly << " provided to writeJSON"; } } else { - boost::property_tree::write_json(filename, *sPtree); + boost::property_tree::write_json(outfilename, *sPtree); } } @@ -313,6 +291,20 @@ void ConfigurableParam::printAllKeyValuePairs() // ------------------------------------------------------------------ +ConfigurableParam::EParamProvenance ConfigurableParam::getProvenance(const std::string& key) +{ + if (!sIsFullyInitialized) { + initialize(); + } + auto iter = sValueProvenanceMap->find(key); + if (iter == sValueProvenanceMap->end()) { + throw std::runtime_error(fmt::format("provenace of unknown {:s} parameter is requested", key)); + } + return iter->second; +} + +// ------------------------------------------------------------------ + // evidently this could be a local file or an OCDB server // ... we need to generalize this ... but ok for demonstration purposes void ConfigurableParam::toCCDB(std::string filename) @@ -393,13 +385,17 @@ void ConfigurableParam::printAllRegisteredParamNames() // Update the storage map of params from the given configuration file. // It can be in JSON or INI format. -void ConfigurableParam::updateFromFile(std::string const& configFile) +// If nonempty comma-separated paramsList is provided, only those params will +// be updated, absence of data for any of requested params will lead to fatal +// If unchangedOnly is true, then only those parameters whose provenance is kCODE will be updated +// (to allow prefernce of run-time settings) +void ConfigurableParam::updateFromFile(std::string const& configFile, std::string const& paramsList, bool unchangedOnly) { if (!sIsFullyInitialized) { initialize(); } - auto cfgfile = trimSpace(configFile); + auto cfgfile = o2::utils::Str::trim_copy(configFile); if (cfgfile.length() == 0) { return; @@ -408,16 +404,32 @@ void ConfigurableParam::updateFromFile(std::string const& configFile) boost::property_tree::ptree pt = readConfigFile(cfgfile); std::vector<std::pair<std::string, std::string>> keyValPairs; + auto request = o2::utils::Str::tokenize(paramsList, ',', true); + std::unordered_map<std::string, int> requestMap; + for (const auto& par : request) { + if (!par.empty()) { + requestMap[par] = 0; + } + } try { for (auto& section : pt) { std::string mainKey = section.first; + if (requestMap.size()) { + if (requestMap.find(mainKey) == requestMap.end()) { + continue; // if something was requested, ignore everything else + } else { + requestMap[mainKey] = 1; + } + } for (auto& subKey : section.second) { auto name = subKey.first; auto value = subKey.second.get_value<std::string>(); std::string key = mainKey + "." + name; - std::pair<std::string, std::string> pair = std::make_pair(key, trimSpace(value)); - keyValPairs.push_back(pair); + if (!unchangedOnly || getProvenance(key) == kCODE) { + std::pair<std::string, std::string> pair = std::make_pair(key, o2::utils::Str::trim_copy(value)); + keyValPairs.push_back(pair); + } } } } catch (std::exception const& error) { @@ -426,6 +438,13 @@ void ConfigurableParam::updateFromFile(std::string const& configFile) LOG(ERROR) << "Unknown while updating params "; } + // make sure all requested params were retrieved + for (const auto& req : requestMap) { + if (req.second == 0) { + throw std::runtime_error(fmt::format("Param {:s} was not found in {:s}", req.first, configFile)); + } + } + try { setValues(keyValPairs); } catch (std::exception const& error) { @@ -442,7 +461,7 @@ void ConfigurableParam::updateFromString(std::string const& configString) initialize(); } - auto cfgStr = trimSpace(configString); + auto cfgStr = o2::utils::Str::trim_copy(configString); if (cfgStr.length() == 0) { return; } @@ -453,13 +472,13 @@ void ConfigurableParam::updateFromString(std::string const& configString) std::vector<std::pair<std::string, std::string>> pairs; for (auto& token : tokens) { - auto keyval = splitString(token, '='); + auto keyval = o2::utils::Str::tokenize(token, '='); if (keyval.size() != 2) { LOG(FATAL) << "Illegal command-line key/value string: " << token; continue; } - std::pair<std::string, std::string> pair = std::make_pair(keyval[0], trimSpace(keyval[1])); + std::pair<std::string, std::string> pair = std::make_pair(keyval[0], o2::utils::Str::trim_copy(keyval[1])); pairs.push_back(pair); } @@ -486,12 +505,24 @@ void ConfigurableParam::updateFromString(std::string const& configString) // ---- end of helper functions -------------------- // Command-line string is a ;-separated list of key=value params - auto params = splitString(configString, ';', true); + auto params = o2::utils::Str::tokenize(configString, ';', true); // Now split each key=value string into its std::pair<key, value> parts auto keyValues = toKeyValPairs(params); setValues(keyValues); + + const auto& kv = o2::conf::KeyValParam::Instance(); + if (getProvenance("keyval.input_dir") != kCODE) { + sInputDir = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(kv.input_dir)); + } + if (getProvenance("keyval.output_dir") != kCODE) { + if (kv.output_dir == "/dev/null") { + sOutputDir = kv.output_dir; + } else { + sOutputDir = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(kv.output_dir)); + } + } } // setValues takes a vector of pairs where each pair is a key and value @@ -511,7 +542,7 @@ void ConfigurableParam::setValues(std::vector<std::pair<std::string, std::string // and also confirm that the value is in the list of legal values for (auto& keyValue : keyValues) { std::string key = keyValue.first; - std::string value = trimSpace(keyValue.second); + std::string value = o2::utils::Str::trim_copy(keyValue.second); if (!keyInTree(sPtree, key)) { LOG(FATAL) << "Inexistant ConfigurableParam key: " << key; @@ -543,7 +574,7 @@ void ConfigurableParam::setArrayValue(const std::string& key, const std::string& { // We remove the lead/trailing square bracket // value.erase(0, 1).pop_back(); - auto elems = splitString(value.substr(1, value.length() - 2), ',', true); + auto elems = o2::utils::Str::tokenize(value.substr(1, value.length() - 2), ',', true); // TODO: // 1. Should not assume each array element is a scalar/string. We may need to recurse. @@ -585,24 +616,24 @@ bool isMemblockDifferent(void const* block1, void const* block2) // copies data from one place to other and returns // true of data was actually changed template <typename T> -bool Copy(void const* addr, void* targetaddr) +ConfigurableParam::EParamUpdateStatus Copy(void const* addr, void* targetaddr) { if (isMemblockDifferent<T>(addr, targetaddr)) { std::memcpy(targetaddr, addr, sizeof(T)); - return true; + return ConfigurableParam::EParamUpdateStatus::Changed; } - return false; + return ConfigurableParam::EParamUpdateStatus::Unchanged; } -bool ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string subkey, std::type_info const& tinfo, - void* addr) +ConfigurableParam::EParamUpdateStatus ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string subkey, std::type_info const& tinfo, + void* addr) { // check if key_exists auto key = mainkey + "." + subkey; auto iter = sKeyToStorageMap->find(key); if (iter == sKeyToStorageMap->end()) { LOG(WARN) << "Cannot update parameter " << key << " not found"; - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } // the type we need to convert to @@ -611,7 +642,7 @@ bool ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string // check that type matches if (iter->second.first != tinfo) { LOG(WARN) << "Types do not match; cannot update value"; - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } auto targetaddress = iter->second.second; @@ -709,85 +740,87 @@ bool ConfigurableParam::updateThroughStorageMap(std::string mainkey, std::string break; } /* - case kDataTypeAliasSignedChar_t: { - unsupp(); - break; - } - case kNumDataTypes: { - unsupp(); - break; - }*/ + case kDataTypeAliasSignedChar_t: { + unsupp(); + break; + } + case kNumDataTypes: { + unsupp(); + break; + }*/ default: { unsupp(); break; } } - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } template <typename T> -bool ConvertAndCopy(std::string const& valuestring, void* targetaddr) +ConfigurableParam::EParamUpdateStatus ConvertAndCopy(std::string const& valuestring, void* targetaddr) { auto addr = boost::lexical_cast<T>(valuestring); if (isMemblockDifferent<T>(targetaddr, (void*)&addr)) { std::memcpy(targetaddr, (void*)&addr, sizeof(T)); - return true; + return ConfigurableParam::EParamUpdateStatus::Changed; } - return false; + return ConfigurableParam::EParamUpdateStatus::Unchanged; } + // special version for std::string template <> -bool ConvertAndCopy<std::string>(std::string const& valuestring, void* targetaddr) +ConfigurableParam::EParamUpdateStatus ConvertAndCopy<std::string>(std::string const& valuestring, void* targetaddr) { std::string& target = *((std::string*)targetaddr); if (target.compare(valuestring) != 0) { // the targetaddr is a std::string to which we can simply assign // and all the magic will happen internally target = valuestring; - return true; + return ConfigurableParam::EParamUpdateStatus::Changed; } - return false; + return ConfigurableParam::EParamUpdateStatus::Unchanged; } // special version for char and unsigned char since we are interested in the numeric // meaning of char as an 8-bit integer (boost lexical cast is assigning the string as a character i// nterpretation template <> -bool ConvertAndCopy<char>(std::string const& valuestring, void* targetaddr) +ConfigurableParam::EParamUpdateStatus ConvertAndCopy<char>(std::string const& valuestring, void* targetaddr) { int intvalue = boost::lexical_cast<int>(valuestring); if (intvalue > std::numeric_limits<char>::max() || intvalue < std::numeric_limits<char>::min()) { LOG(ERROR) << "Cannot assign " << valuestring << " to a char variable"; - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } char addr = intvalue; if (isMemblockDifferent<char>(targetaddr, (void*)&addr)) { std::memcpy(targetaddr, (void*)&addr, sizeof(char)); - return true; + return ConfigurableParam::EParamUpdateStatus::Changed; } - return false; + return ConfigurableParam::EParamUpdateStatus::Unchanged; } + template <> -bool ConvertAndCopy<unsigned char>(std::string const& valuestring, void* targetaddr) +ConfigurableParam::EParamUpdateStatus ConvertAndCopy<unsigned char>(std::string const& valuestring, void* targetaddr) { unsigned int intvalue = boost::lexical_cast<int>(valuestring); if (intvalue > std::numeric_limits<unsigned char>::max() || intvalue < std::numeric_limits<unsigned char>::min()) { LOG(ERROR) << "Cannot assign " << valuestring << " to an unsigned char variable"; - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } unsigned char addr = intvalue; if (isMemblockDifferent<unsigned char>(targetaddr, (void*)&addr)) { std::memcpy(targetaddr, (void*)&addr, sizeof(unsigned char)); - return true; + return ConfigurableParam::EParamUpdateStatus::Changed; } - return false; + return ConfigurableParam::EParamUpdateStatus::Unchanged; } -bool ConfigurableParam::updateThroughStorageMapWithConversion(std::string const& key, std::string const& valuestring) +ConfigurableParam::EParamUpdateStatus ConfigurableParam::updateThroughStorageMapWithConversion(std::string const& key, std::string const& valuestring) { // check if key_exists auto iter = sKeyToStorageMap->find(key); if (iter == sKeyToStorageMap->end()) { LOG(WARN) << "Cannot update parameter " << key << " (parameter not found) "; - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } auto targetaddress = iter->second.second; @@ -896,20 +929,20 @@ bool ConfigurableParam::updateThroughStorageMapWithConversion(std::string const& break; } /* - case kDataTypeAliasSignedChar_t: { - unsupp(); - break; - } - case kNumDataTypes: { - unsupp(); - break; - }*/ + case kDataTypeAliasSignedChar_t: { + unsupp(); + break; + } + case kNumDataTypes: { + unsupp(); + break; + }*/ default: { unsupp(); break; } } - return false; + return ConfigurableParam::EParamUpdateStatus::Failed; } } // namespace conf diff --git a/Common/Utils/src/ConfigurableParamHelper.cxx b/Common/Utils/src/ConfigurableParamHelper.cxx index f8fe1d16f570a..f46750658a100 100644 --- a/Common/Utils/src/ConfigurableParamHelper.cxx +++ b/Common/Utils/src/ConfigurableParamHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -138,11 +139,21 @@ size_t getSizeOfUnderlyingType(const TDataMember& dm) // ---------------------------------------------------------------------- -const char* asString(TDataMember const& dm, char* pointer) +std::string asString(TDataMember const& dm, char* pointer) { // first check if this is a basic data type, in which case // we let ROOT do the work if (auto dt = dm.GetDataType()) { + // we put the numeric interpration for char / unsigned char + // instead of the string one + if (dt->GetType() == EDataType::kChar_t) { + auto c = (char)(*pointer); + return std::to_string((int)c).c_str(); + } else if (dt->GetType() == EDataType::kUChar_t) { + auto u = (unsigned char)(*pointer); + return std::to_string((unsigned int)u).c_str(); + } + auto val = dt->AsString(pointer); // For enums we grab the string value of the member @@ -156,13 +167,13 @@ const char* asString(TDataMember const& dm, char* pointer) for (int i = 0; i < constantlist->GetEntries(); ++i) { const auto e = (TEnumConstant*)(constantlist->At(i)); if (val == std::to_string((int)e->GetValue())) { - return e->GetName(); + return std::string(e->GetName()); } } } } - return val; + return std::string(val); } // if data member is a std::string just return @@ -186,7 +197,7 @@ std::vector<ParamDataMember>* _ParamHelper::getDataMembersImpl(std::string const auto TS = getSizeOfUnderlyingType(*dm); char* pointer = ((char*)obj) + dm->GetOffset() + index * TS; const std::string name = getName(dm, index, size); - const char* value = asString(*dm, pointer); + auto value = asString(*dm, pointer); std::string prov = ""; auto iter = provmap->find(mainkey + "." + name); @@ -376,6 +387,51 @@ void _ParamHelper::assignmentImpl(std::string const& mainkey, TClass* cl, void* // ---------------------------------------------------------------------- +void _ParamHelper::syncCCDBandRegistry(const std::string& mainkey, TClass* cl, void* to, void* from, + std::map<std::string, ConfigurableParam::EParamProvenance>* provmap) +{ + auto sync = [to, from, &mainkey, provmap](const TDataMember* dm, int index, int size) { + const auto name = getName(dm, index, size); + auto dt = dm->GetDataType(); + auto TS = getSizeOfUnderlyingType(*dm); + char* pointerto = ((char*)to) + dm->GetOffset() + index * TS; + char* pointerfrom = ((char*)from) + dm->GetOffset() + index * TS; + + // check current provenance + auto key = mainkey + "." + name; + auto proviter = provmap->find(key); + bool isRT = proviter != provmap->end() && proviter->second == ConfigurableParam::EParamProvenance::kRT; + if (isRT) { + return; + } + // lambda to update the provenance + auto updateProv = [&proviter]() { + proviter->second = ConfigurableParam::EParamProvenance::kCCDB; + }; + + // test if a complicated case + if (isString(*dm)) { + std::string& target = *(std::string*)pointerto; + std::string const& origin = *(std::string*)pointerfrom; + // if (target.compare(origin) != 0) { + updateProv(); + target = origin; + // } + return; + } + + // + // if (!isMemblockDifferent(pointerto, pointerfrom, TS)) { + updateProv(); + // actually copy + std::memcpy(pointerto, pointerfrom, getSizeOfUnderlyingType(*dm)); + // } + }; + loopOverMembers(cl, to, sync); +} + +// ---------------------------------------------------------------------- + void _ParamHelper::printWarning(std::type_info const& tinfo) { LOG(WARNING) << "Registered parameter class with name " << tinfo.name() diff --git a/Common/Utils/src/FIFO.cxx b/Common/Utils/src/FIFO.cxx new file mode 100644 index 0000000000000..0ea5ef84d32df --- /dev/null +++ b/Common/Utils/src/FIFO.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch + +#include "CommonUtils/FIFO.h" + +using namespace o2::utils; diff --git a/Common/Utils/src/FileFetcher.cxx b/Common/Utils/src/FileFetcher.cxx new file mode 100644 index 0000000000000..9554cfbffb1cd --- /dev/null +++ b/Common/Utils/src/FileFetcher.cxx @@ -0,0 +1,315 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch +/// Code partially based on DataDistribution:SubTimeFrameFileSource by Gvozden Nescovic + +#include "CommonUtils/FileFetcher.h" +#include "CommonUtils/StringUtils.h" +#include "Framework/Logger.h" +#include <filesystem> +#include <fstream> +#include <memory> +#include <thread> +#include <chrono> +#include <cstdlib> +#include <locale> +#include <boost/process.hpp> + +using namespace o2::utils; +using namespace std::chrono_literals; +namespace fs = std::filesystem; +namespace bp = boost::process; + +//____________________________________________________________ +FileFetcher::FileFetcher(const std::string& input, const std::string& selRegex, const std::string& remRegex, + const std::string& copyCmd, const std::string& copyDir) + : mCopyCmd(copyCmd), mCopyDirName(copyDir) +{ + if (!selRegex.empty()) { + mSelRegex = std::make_unique<std::regex>(selRegex.c_str()); + } + if (!remRegex.empty()) { + mRemRegex = std::make_unique<std::regex>(remRegex); + } + mNoRemoteCopy = mCopyCmd == "no-copy"; + + // parse input list + mCopyDirName = o2::utils::Str::create_unique_path(mCopyDirName, 8); + processInput(input); + LOGP(INFO, "Input contains {} files, {} remote", getNFiles(), mNRemote); + if (mNRemote) { + if (mNoRemoteCopy) { // make sure the copy command is provided, unless copy was explicitly forbidden + LOGP(INFO, "... but their local copying is explicitly forbidden"); + } else { + if (mCopyCmd.find("?src") == std::string::npos || mCopyCmd.find("?dst") == std::string::npos) { + throw std::runtime_error(fmt::format("remote files asked but copy cmd \"{}\" is not valid", mCopyCmd)); + } + try { + fs::create_directories(mCopyDirName); + } catch (...) { + throw std::runtime_error(fmt::format("failed to create scratch directory {}", mCopyDirName)); + } + mCopyCmdLogFile = fmt::format("{}/{}", mCopyDirName, "copy-cmd.log"); + LOGP(INFO, "FileFetcher tmp scratch directory is set to {}", mCopyDirName); + } + } +} + +//____________________________________________________________ +FileFetcher::~FileFetcher() +{ + stop(); + cleanup(); +} + +//____________________________________________________________ +void FileFetcher::processInput(const std::string& input) +{ + auto ftokens = o2::utils::Str::tokenize(input, ',', true); // in case multiple inputs are provided + processInput(ftokens); +} + +//____________________________________________________________ +void FileFetcher::processInput(const std::vector<std::string>& input) +{ + for (auto inp : input) { + o2::utils::Str::trim(inp); + + if (fs::is_directory(inp)) { + processDirectory(inp); + } else if (mSelRegex && !std::regex_match(inp, *mSelRegex.get())) { // provided selector does not match, treat as a txt file with list + std::ifstream listFile(inp); + if (!listFile.good()) { + LOGP(ERROR, "file {} pretends to be a list of inputs but does not exist", inp); + continue; + } + std::string line; + std::vector<std::string> newInput; + while (getline(listFile, line)) { + o2::utils::Str::trim(line); + if (line[0] == '#') { // ignore commented file + continue; + } + newInput.push_back(line); + } + processInput(newInput); + } else { // should be local or remote data file + addInputFile(inp); + } + } +} + +//____________________________________________________________ +void FileFetcher::processDirectory(const std::string& name) +{ + std::vector<std::string> vs; + for (auto const& entry : fs::directory_iterator{name}) { + const auto& fnm = entry.path().native(); + if (fs::is_regular_file(fnm) && (!mSelRegex || std::regex_match(fnm, *mSelRegex.get()))) { + vs.push_back(fnm); + } + } + std::sort(vs.begin(), vs.end()); + for (const auto& s : vs) { + addInputFile(s); // local files only + } +} + +//____________________________________________________________ +bool FileFetcher::addInputFile(const std::string& fname) +{ + if (mRemRegex && std::regex_match(fname, *mRemRegex.get())) { + mInputFiles.emplace_back(FileRef{fname, mNoRemoteCopy ? fname : createCopyName(fname), true, false}); + mNRemote++; + } else if (fs::exists(fname)) { // local file + mInputFiles.emplace_back(FileRef{fname, "", false, false}); + } else { + LOGP(ERROR, "file {} pretends to be local but does not exist", fname); + return false; + } + return true; +} + +//____________________________________________________________ +std::string FileFetcher::createCopyName(const std::string& fname) const +{ + std::string cpnam{}, cpnamP = fname; + for (auto& c : cpnamP) { + if (!std::isalnum(c) && c != '.' && c != '-') { + c = '_'; + } + } + while (1) { + cpnam = fmt::format("{}/{}_{}", mCopyDirName, o2::utils::Str::getRandomString(12), cpnamP); + if (!fs::exists(cpnam)) { + break; + } + } + return cpnam; +} + +//____________________________________________________________ +size_t FileFetcher::popFromQueue(bool discard) +{ + // remove file from the queue, if requested and if it was copied, remove copy + std::lock_guard<std::mutex> lock(mMtx); + const auto* ptr = mQueue.frontPtr(); + if (mQueue.empty()) { + return -1ul; + } + auto id = mQueue.front(); + mQueue.pop(); + if (discard) { + discardFile(mInputFiles[id].getLocalName()); + } + return id; +} + +//____________________________________________________________ +size_t FileFetcher::nextInQueue() const +{ + return mQueue.empty() ? -1ul : mQueue.front(); +} + +//____________________________________________________________ +std::string FileFetcher::getNextFileInQueue() const +{ + if (mQueue.empty()) { + return {}; + } + return mQueue.empty() ? "" : mInputFiles[mQueue.front()].getLocalName(); +} + +//____________________________________________________________ +void FileFetcher::start() +{ + if (mRunning) { + return; + } + mRunning = true; + mFetcherThread = std::thread(&FileFetcher::fetcher, this); +} + +//____________________________________________________________ +void FileFetcher::stop() +{ + mRunning = false; + std::lock_guard<std::mutex> lock(mMtxStop); + if (mFetcherThread.joinable()) { + mFetcherThread.join(); + } +} + +//____________________________________________________________ +void FileFetcher::cleanup() +{ + if (mRunning) { + throw std::runtime_error("FileFetcher thread is still active, cannot cleanup"); + } + if (mNRemote && o2::utils::Str::pathExists(mCopyDirName)) { + try { + fs::remove_all(mCopyDirName); + } catch (...) { + LOGP(ERROR, "FileFetcher failed to remove sctrach directory {}", mCopyDirName); + } + } +} + +//____________________________________________________________ +void FileFetcher::fetcher() +{ + // data fetching/copying thread + size_t fileEntry = -1ul; + + if (!getNFiles()) { + mRunning = false; + return; + } + + // BOOST requires a locale set + try { + std::locale loc(""); + } catch (const std::exception& e) { + setenv("LC_ALL", "C", 1); + try { + std::locale loc(""); + LOG(INFO) << "Setting locale"; + } catch (const std::exception& e) { + LOG(INFO) << "Setting locale failed: " << e.what(); + return; + } + } + + while (mRunning) { + mNLoops = mNFilesProc / getNFiles(); + if (mNLoops > mMaxLoops) { + mNLoops--; + LOGP(INFO, "Finished file fetching: {} of {} files fetched successfully in {} loops", mNFilesProcOK, mNFilesProc, mMaxLoops); + mRunning = false; + break; + } + if (getQueueSize() >= mMaxInQueue) { + std::this_thread::sleep_for(5ms); + continue; + } + fileEntry = (fileEntry + 1) % getNFiles(); + if (fileEntry == 0 && mNLoops > 0) { + LOG(INFO) << "Fetcher starts new loop " << mNLoops; + } + mNFilesProc++; + auto& fileRef = mInputFiles[fileEntry]; + if (fileRef.copied || !fileRef.remote || mNoRemoteCopy) { + mQueue.push(fileEntry); + mNFilesProcOK++; + } else { // need to copy + if (copyFile(fileEntry)) { + fileRef.copied = true; + mQueue.push(fileEntry); + mNFilesProcOK++; + } + } + } +} + +//____________________________________________________________ +void FileFetcher::discardFile(const std::string& fname) +{ + // delete file if it is copied. + auto ent = mCopied.find(fname); + if (ent != mCopied.end()) { + mInputFiles[ent->second - 1].copied = false; + fs::remove(fname); + mCopied.erase(fname); + } +} + +//____________________________________________________________ +bool FileFetcher::copyFile(size_t id) +{ + // copy remote file to local setCopyDirName. Adaptation for Gvozden's code from SubTimeFrameFileSource::DataFetcherThread() + auto realCmd = std::regex_replace(std::regex_replace(mCopyCmd, std::regex("\\?src"), mInputFiles[id].getOrigName()), std::regex("\\?dst"), mInputFiles[id].getLocalName()); + std::vector<std::string> copyParams{"-c", realCmd}; + bp::child copyChild(bp::search_path("sh"), copyParams, bp::std_err > mCopyCmdLogFile, bp::std_out > mCopyCmdLogFile); + while (!copyChild.wait_for(5s)) { + LOGP(INFO, "FileFetcher: waiting for copy command. cmd={}", realCmd); + } + const auto sysRet = copyChild.exit_code(); + if (sysRet != 0) { + LOGP(WARNING, "FileFetcher: non-zero exit code {} for cmd={}", sysRet, realCmd); + } + if (!fs::is_regular_file(mInputFiles[id].getLocalName()) || fs::is_empty(mInputFiles[id].getLocalName())) { + LOGP(ERROR, "FileFetcher: failed for copy command {}", realCmd); + return false; + } + mCopied[mInputFiles[id].getLocalName()] = id + 1; + return true; +} diff --git a/Common/Utils/src/FileSystemUtils.cxx b/Common/Utils/src/FileSystemUtils.cxx new file mode 100644 index 0000000000000..e060f98d01702 --- /dev/null +++ b/Common/Utils/src/FileSystemUtils.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// +// Created by Sandro Wenzel on 04.06.21. +// + +#include <CommonUtils/FileSystemUtils.h> +#include <filesystem> +#include <vector> +#include <regex> +#include <iostream> + +namespace o2::utils +{ + +// Return a vector of file names in the current dir matching the search +// pattern. If searchpattern is empty, all files will be returned. Otherwise +// searchpattern will be treated/parsed as proper regular expression. +std::vector<std::string> listFiles(std::string const& dir, std::string const& searchpattern) +{ + std::vector<std::string> filenames; + std::string rs = searchpattern.empty() ? ".*" : searchpattern; + std::regex str_expr(rs); + + for (auto& p : std::filesystem::directory_iterator(dir)) { + if (!p.is_directory()) { + auto fn = p.path().filename().string(); + if (regex_match(fn, str_expr)) { + filenames.push_back(p.path().string()); + } + } + } + return filenames; +} + +std::vector<std::string> listFiles(std::string const& searchpattern) +{ + return listFiles("./", searchpattern); +} + +} // namespace o2::utils diff --git a/Common/Utils/src/KeyValParam.cxx b/Common/Utils/src/KeyValParam.cxx new file mode 100644 index 0000000000000..103d823e57710 --- /dev/null +++ b/Common/Utils/src/KeyValParam.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch +/// \brief params for ConfigurableParam + +#include "CommonUtils/KeyValParam.h" +O2ParamImpl(o2::conf::KeyValParam); diff --git a/Common/Utils/src/RootChain.cxx b/Common/Utils/src/RootChain.cxx index 02b1af002e702..fb34f173b35d6 100644 --- a/Common/Utils/src/RootChain.cxx +++ b/Common/Utils/src/RootChain.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/RootSerializableKeyValueStore.cxx b/Common/Utils/src/RootSerializableKeyValueStore.cxx new file mode 100644 index 0000000000000..7bc424300674e --- /dev/null +++ b/Common/Utils/src/RootSerializableKeyValueStore.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/RootSerializableKeyValueStore.h" +#include <iostream> + +using namespace o2::utils; + +void RootSerializableKeyValueStore::print() const +{ + for (auto& p : mStore) { + const auto& key = p.first; + const auto info = p.second; + std::cout << "key: " << key << " of-type: " << info.typeinfo_name << "\n"; + } +} diff --git a/Common/Utils/src/ShmManager.cxx b/Common/Utils/src/ShmManager.cxx index 7f0d9acc96f13..46bae37c3d5aa 100644 --- a/Common/Utils/src/ShmManager.cxx +++ b/Common/Utils/src/ShmManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/StringUtils.cxx b/Common/Utils/src/StringUtils.cxx new file mode 100644 index 0000000000000..9e96cad77d880 --- /dev/null +++ b/Common/Utils/src/StringUtils.cxx @@ -0,0 +1,91 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/StringUtils.h" +#include <cstdlib> +#include <filesystem> + +using namespace o2::utils; + +std::vector<std::string> Str::tokenize(const std::string& src, char delim, bool trimToken) +{ + std::stringstream ss(src); + std::string token; + std::vector<std::string> tokens; + + while (std::getline(ss, token, delim)) { + if (trimToken) { + trim(token); + } + if (!token.empty()) { + tokens.push_back(std::move(token)); + } + } + return tokens; +} + +// generate random string of given lenght, suitable for file names +std::string Str::getRandomString(int lenght) +{ + auto nextAllowed = []() { + constexpr char chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + constexpr size_t L = sizeof(chars) - 1; + return chars[std::rand() % L]; + }; + std::string str(lenght, 0); + std::generate_n(str.begin(), lenght, nextAllowed); + return str; +} + +bool Str::pathExists(const std::string_view p) +{ + return std::filesystem::exists(std::string{p}); +} + +bool Str::pathIsDirectory(const std::string_view p) +{ + return std::filesystem::is_directory(std::string{p}); +} + +std::string Str::getFullPath(const std::string_view p) +{ + return std::filesystem::canonical(std::string{p}).string(); +} + +std::string Str::rectifyDirectory(const std::string_view p) +{ + std::string dir(p); + if (dir.empty() || dir == "none") { + dir = ""; + } else { + dir = getFullPath(dir); + if (!pathIsDirectory(dir)) { + throw std::runtime_error(fmt::format("{:s} is not an accessible directory", dir)); + } else { + dir += '/'; + } + } + return dir; +} + +// Create unique non-existing path name starting with prefix. Loose equivalent of boost::filesystem::unique_path() +// The prefix can be either existing directory or just a string to add in front of the random part +// in absence of such a function in std::filesystem +std::string Str::create_unique_path(const std::string_view prefix, int length) +{ + std::string path; + bool needSlash = pathIsDirectory(prefix) && !prefix.empty() && prefix.back() != '/'; + do { + path = concat_string(prefix, needSlash ? "/" : "", getRandomString(length)); + } while (pathExists(path)); + + return path; +} diff --git a/Common/Utils/src/TreeMergerTool.cxx b/Common/Utils/src/TreeMergerTool.cxx new file mode 100644 index 0000000000000..265f088bd514e --- /dev/null +++ b/Common/Utils/src/TreeMergerTool.cxx @@ -0,0 +1,264 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// A utility for the purpose to produce a global merged TTree +// from multiple TTree (containing a subset of branches). +// A typical example is TPC clusterization/digitization: Clusters per TPC +// sector may sit in different files and we want to produce an aggregate TTree +// for further processing. The utility offers options to use TFriends or to make +// a deep copy. + +#include <TTree.h> +#include <TFile.h> +#include <boost/program_options.hpp> +#include <set> +#include <vector> +#include <iostream> + +struct Options { + std::vector<std::string> infilenames; + std::string treename; + std::string outfilename; + bool asfriend = false; +}; + +// just to make a protected interface accessible +class MyTTreeHelper : public TTree +{ + public: + TBranch* PublicBranchImp(const char* branchname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel) + { + return BranchImp(branchname, ptrClass, addobj, bufsize, splitlevel); + } +}; + +bool parseOptions(int argc, char* argv[], Options& optvalues) +{ + namespace bpo = boost::program_options; + bpo::options_description options( + "A tool to create a single TTree from a list of TTrees (each in its own file).\nMerging is " + "done vertically - over branches - instead over entries (like in a TChain).\nIt corresponds to the TFriend mechanism but makes a deep copy\n" + "(unless the friend is asked).\n\n" + "Allowed options"); + + options.add_options()( + "infiles,i", bpo::value<std::vector<std::string>>(&optvalues.infilenames)->multitoken(), "All input files to be merged")( + "treename,t", bpo::value<std::string>(&optvalues.treename), "Name of tree (assumed same in all files).")( + "outfile,o", bpo::value<std::string>(&optvalues.outfilename)->default_value(""), "Outfile to be created with merged tree.")( + "asfriend", "If merging is done using the friend mechanism."); + options.add_options()("help,h", "Produce help message."); + + bpo::variables_map vm; + try { + bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm); + bpo::notify(vm); + + // help + if (vm.count("help")) { + std::cout << options << std::endl; + return false; + } + if (vm.count("asfriend")) { + optvalues.asfriend = true; + } + + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing options; Available options:\n"; + std::cerr << options << std::endl; + return false; + } + return true; +} + +// Checks if all given files have a TTree of this name +// and if all entries are the same +// TODO: add more checks such as for non-overlapping branch names etc. +bool checkFiles(std::vector<std::string> const& filenames, std::string const& treename) +{ + bool ok = true; + int entries = -1; + for (auto& f : filenames) { + TFile _tmpfile(f.c_str(), "OPEN"); + auto tree = (TTree*)_tmpfile.Get(treename.c_str()); + if (tree == nullptr) { + ok = false; + std::cerr << "File " << f << " doesn't have a tree of name " << treename; + } else { + if (entries == -1) { + entries = tree->GetEntries(); + } else { + if (entries != tree->GetEntries()) { + std::cerr << "Trees have inconsistent number of entries "; + ok = false; + } + } + } + } + return ok; +} + +// a helper function taken from TTree.cxx +static char DataTypeToChar(EDataType datatype) +{ + // Return the leaflist 'char' for a given datatype. + + switch (datatype) { + case kChar_t: + return 'B'; + case kUChar_t: + return 'b'; + case kBool_t: + return 'O'; + case kShort_t: + return 'S'; + case kUShort_t: + return 's'; + case kCounter: + case kInt_t: + return 'I'; + case kUInt_t: + return 'i'; + case kDouble_t: + return 'D'; + case kDouble32_t: + return 'd'; + case kFloat_t: + return 'F'; + case kFloat16_t: + return 'f'; + case kLong_t: + return 'G'; + case kULong_t: + return 'g'; + case kchar: + return 0; // unsupported + case kLong64_t: + return 'L'; + case kULong64_t: + return 'l'; + + case kCharStar: + return 'C'; + case kBits: + return 0; //unsupported + + case kOther_t: + case kNoType_t: + default: + return 0; + } + return 0; +} + +void merge(Options const& options) +{ + if (options.asfriend) { + // open the output file + auto newfile = TFile::Open(options.outfilename.c_str(), "RECREATE"); + auto newtree = new TTree(options.treename.c_str(), ""); + // add remaining stuff as friend + for (int i = 0; i < options.infilenames.size(); ++i) { + newtree->AddFriend(options.treename.c_str(), options.infilenames[i].c_str()); + } + newfile->Write(); + newfile->Close(); + + // P. Canal suggests that this can be done in the following way to fix the branch names + // in the merged file and to keep only the final file: + //auto mainfile = TFile::Open(firsttreefilename, "UPDATE"); + //auto friendfile = TFile::Open(secondtreefilename, "READ"); + //auto friendtree = ffriendfile>Get<Tree>(secondtreename); + //mainfile->cd(); + //auto friendcopy = friendtree->CloneTree(-1, "fast"); + //auto maintree = mainfile->Get<TTree>(firsttreename); + //maintree->AddFriend(friendcopy); + //mainfile->Write(); + } else { + // a deep copy solution + + auto copyBranch = [](TTree* t, TBranch* br) -> bool { + // Get data from original branch and copy to new + // by using generic type/class information of old. + // We are using some internals of the TTree implementation. (Luckily these + // functions are not marked private ... so that we can still access them). + TClass* clptr = nullptr; + EDataType type; + if (br->GetExpectedType(clptr, type) == 0) { + char* data = nullptr; + TBranch* newbr = nullptr; + if (clptr != nullptr) { + newbr = ((MyTTreeHelper*)t)->PublicBranchImp(br->GetName(), clptr, &data, 32000, br->GetSplitLevel()); + } else if (type != EDataType::kOther_t) { + TString varname; + varname.Form("%s/%c", br->GetName(), DataTypeToChar(type)); + newbr = t->Branch(br->GetName(), &data, varname.Data()); + } else { + std::cerr << "Could not retrieve class/type information. Branch " << br->GetName() << "cannot be copied.\n"; + return false; + } + if (newbr) { + br->SetAddress(&data); + for (int e = 0; e < br->GetEntries(); ++e) { + auto size = br->GetEntry(e); + newbr->Fill(); + } + br->ResetAddress(); + br->DropBaskets("all"); + return true; + // TODO: data is leaking? (but deleting it here causes a crash) + } + } // end good + return false; + }; + + TFile outfile(options.outfilename.c_str(), "RECREATE"); + auto outtree = new TTree(options.treename.c_str(), options.treename.c_str()); + // iterate over files and branches + for (auto filename : options.infilenames) { + TFile _tmp(filename.c_str(), "OPEN"); + auto t = (TTree*)_tmp.Get(options.treename.c_str()); + auto brlist = t->GetListOfBranches(); + for (int i = 0; i < brlist->GetEntries(); ++i) { + auto br = (TBranch*)brlist->At(i); + if (!copyBranch(outtree, br)) { + std::cerr << "Error copying branch " << br->GetName() << "\n"; + } + } + outtree->SetEntries(t->GetEntries()); + } + outfile.Write(); + outfile.Close(); + } + + // Note: There is/was also an elegant solution based on RDataFrames (snapshot) as discussed here: + // https://root-forum.cern.ch/t/make-a-new-ttree-from-a-deep-vertical-union-of-existing-ttrees/44250 + // ... but this solution has problems since ROOT 6-24 since RDataFrame may change the internal type + // of std::vector<> using a non-default allocator which may cause problem when reading data back. +} + +int main(int argc, char* argv[]) +{ + Options optvalues; + if (!parseOptions(argc, argv, optvalues)) { + return 0; + } + + auto ok = checkFiles(optvalues.infilenames, optvalues.treename); + if (!ok) { + return 1; + } + + // merge files + merge(optvalues); + + return 0; +} diff --git a/Common/Utils/src/TreeStream.cxx b/Common/Utils/src/TreeStream.cxx index 24171ff647ad3..deebc4d3edb9f 100644 --- a/Common/Utils/src/TreeStream.cxx +++ b/Common/Utils/src/TreeStream.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/TreeStreamRedirector.cxx b/Common/Utils/src/TreeStreamRedirector.cxx index 6218c0998ce3d..86e0eb5a37552 100644 --- a/Common/Utils/src/TreeStreamRedirector.cxx +++ b/Common/Utils/src/TreeStreamRedirector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/src/ValueMonitor.cxx b/Common/Utils/src/ValueMonitor.cxx index 4f918feef381b..6e3351e0933fa 100644 --- a/Common/Utils/src/ValueMonitor.cxx +++ b/Common/Utils/src/ValueMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/test/testBoostSerializer.cxx b/Common/Utils/test/testBoostSerializer.cxx index ef862c9341b79..520bc7dda8b08 100644 --- a/Common/Utils/test/testBoostSerializer.cxx +++ b/Common/Utils/test/testBoostSerializer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/test/testCompStream.cxx b/Common/Utils/test/testCompStream.cxx index e0eb5d191ffe8..095320213bae1 100644 --- a/Common/Utils/test/testCompStream.cxx +++ b/Common/Utils/test/testCompStream.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,12 +15,12 @@ /// @brief unit tests for iostreams with compression filter #include "CommonUtils/CompStream.h" - +#include "CommonUtils/StringUtils.h" #define BOOST_TEST_MODULE CompStream unit test #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include <boost/filesystem.hpp> +#include <filesystem> #include <iostream> #include <iomanip> #include <sstream> @@ -28,8 +29,7 @@ BOOST_AUTO_TEST_CASE(test_compstream_filesink) { const int range = 100; std::stringstream filename; - filename << boost::filesystem::temp_directory_path().string() << "/" << boost::filesystem::unique_path().string() - << "_testCompStream.gz"; + filename << o2::utils::Str::create_unique_path(std::filesystem::temp_directory_path().native()) << "_testCompStream.gz"; { o2::io::ocomp_stream stream(filename.str().c_str(), o2::io::CompressionMethod::Gzip); for (int i = 0; i < range; i++) { @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(test_compstream_filesink) BOOST_CHECK(expected == range); } - boost::filesystem::remove(filename.str()); + std::filesystem::remove(filename.str()); } BOOST_AUTO_TEST_CASE(test_compstream_methods) diff --git a/Common/Utils/test/testMemFileHelper.cxx b/Common/Utils/test/testMemFileHelper.cxx index 204facc76ee6c..2a55d67b9884a 100644 --- a/Common/Utils/test/testMemFileHelper.cxx +++ b/Common/Utils/test/testMemFileHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include <boost/filesystem.hpp> +#include <filesystem> #include <cstdio> #include <vector> #include <TFile.h> diff --git a/Common/Utils/test/testRootSerializableKeyValueStore.cxx b/Common/Utils/test/testRootSerializableKeyValueStore.cxx new file mode 100644 index 0000000000000..8e1de1c4d6d52 --- /dev/null +++ b/Common/Utils/test/testRootSerializableKeyValueStore.cxx @@ -0,0 +1,119 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test RootSerKeyValueStore +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "CommonUtils/RootSerializableKeyValueStore.h" +#include <TMemFile.h> +#include <TH1F.h> +#include <vector> +#include <iostream> +#include <TClass.h> + +using namespace o2; +using namespace o2::utils; + +BOOST_AUTO_TEST_CASE(write_read_test) +{ + RootSerializableKeyValueStore s; + + // put POD some stuff + double x = 1.1; + s.put("x", x); + s.put("i", 110); + + // put some complex classes (need dictionary) + std::string str = "hello"; + s.put("str", str); + + // this should fail compiling: + // const char* text = "foo"; + // s.put("cstr", text); + + TH1F h1("th1name", "th1name", 100, 0, 99); + h1.FillRandom("gaus", 10000); + s.put("h1", h1); + + // check basic assumption that typeinfo name is unique for basic types + BOOST_CHECK(strcmp(std::type_index(typeid(double*)).name(), "Pd") == 0); + BOOST_CHECK(strcmp(std::type_index(typeid(int)).name(), "i") == 0); + BOOST_CHECK(strcmp(std::type_index(typeid(unsigned int)).name(), "j") == 0); + BOOST_CHECK(strcmp(std::type_index(typeid(char)).name(), "c") == 0); + BOOST_CHECK(strcmp(std::type_index(typeid(char*)).name(), "Pc") == 0); + BOOST_CHECK(strcmp(std::type_index(typeid(unsigned char)).name(), "h") == 0); + + // check assumption that for more complicated types the TClass name is unique + // (the std::type_index is not standardized) + BOOST_CHECK(strcmp(TClass::GetClass(typeid(std::vector<double>))->GetName(), "vector<double>") == 0); + + // retrieve + BOOST_CHECK(s.get<std::string>("str")->compare(str) == 0); + BOOST_CHECK(*(s.get<double>("x")) == x); + BOOST_CHECK(s.has("x")); + BOOST_CHECK(!s.has("x_does_not_exist")); + + // retrieve with state/error information + using ErrorState = RootSerializableKeyValueStore::GetState; + ErrorState state; + { + auto r1 = s.get<std::string>("str", state); + BOOST_CHECK(state == ErrorState::kOK); + auto returnedstring = s.getRef<std::string>("str", state); + BOOST_CHECK(state == ErrorState::kOK); + BOOST_CHECK(returnedstring.compare(str) == 0); + + auto r2 = s.get<int>("str", state); + BOOST_CHECK(r2 == nullptr); + BOOST_CHECK(state == ErrorState::kWRONGTYPE); + auto r3 = s.get<int>("str2", state); + BOOST_CHECK(state == ErrorState::kNOSUCHKEY); + BOOST_CHECK(r3 == nullptr); + + auto r4 = s.get<TH1F>("non-existend-histogram", state); + BOOST_CHECK(state == ErrorState::kNOSUCHKEY); + } + + // put something twice + s.put<int>("twice", 10); + s.put<int>("twice", 7); + BOOST_CHECK(*(s.get<int>("twice")) == 7); + + std::cerr << "TESTING FILE IO\n"; + TMemFile f("tmp.root", "RECREATE"); + f.WriteObject(&s, "map"); + + RootSerializableKeyValueStore* s2 = nullptr; + f.GetObject("map", s2); + BOOST_CHECK(s2 != nullptr); + if (s2) { + auto t1 = s2->get<double>("x"); + BOOST_CHECK(t1 != nullptr); + BOOST_CHECK(t1 && *(t1) == x); + + auto i1 = s2->get<int>("i"); + BOOST_CHECK(i1 != nullptr); + BOOST_CHECK(i1 && *(i1) == 110); + + auto t2 = s2->get<std::string>("str"); + BOOST_CHECK(t2 && t2->compare(str) == 0); + + auto t3 = s2->get<std::string>("str"); + BOOST_CHECK(t3 && t3->compare(str) == 0); + + auto histo = s2->get<TH1F>("h1"); + BOOST_CHECK(histo); + + s2->print(); + } + f.Close(); +} diff --git a/Common/Utils/test/testTreeStream.cxx b/Common/Utils/test/testTreeStream.cxx index d9a857ff091f6..af35d75ae3cd3 100644 --- a/Common/Utils/test/testTreeStream.cxx +++ b/Common/Utils/test/testTreeStream.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Common/Utils/test/testValueMonitor.cxx b/Common/Utils/test/testValueMonitor.cxx index 111893e3e7e50..7541ff9003874 100644 --- a/Common/Utils/test/testValueMonitor.cxx +++ b/Common/Utils/test/testValueMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/CMakeLists.txt b/DataFormats/CMakeLists.txt index b6b2899c4e56f..499528140b22f 100644 --- a/DataFormats/CMakeLists.txt +++ b/DataFormats/CMakeLists.txt @@ -7,4 +7,4 @@ add_subdirectory(simulation) add_subdirectory(TimeFrame) add_subdirectory(Parameters) add_subdirectory(Calibration) - +add_subdirectory(QualityControl) diff --git a/DataFormats/Calibration/CMakeLists.txt b/DataFormats/Calibration/CMakeLists.txt index c63199a6e02b8..189b613f12095 100644 --- a/DataFormats/Calibration/CMakeLists.txt +++ b/DataFormats/Calibration/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsCalibration SOURCES src/MeanVertexObject.cxx) diff --git a/DataFormats/Calibration/include/DataFormatsCalibration/MeanVertexObject.h b/DataFormats/Calibration/include/DataFormatsCalibration/MeanVertexObject.h index 245cdcb2fed24..2b13ccebda12d 100644 --- a/DataFormats/Calibration/include/DataFormatsCalibration/MeanVertexObject.h +++ b/DataFormats/Calibration/include/DataFormatsCalibration/MeanVertexObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Calibration/src/DataFormatsCalibrationLinkDef.h b/DataFormats/Calibration/src/DataFormatsCalibrationLinkDef.h index f364ef185a8dc..fa8a44a2f12fd 100644 --- a/DataFormats/Calibration/src/DataFormatsCalibrationLinkDef.h +++ b/DataFormats/Calibration/src/DataFormatsCalibrationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Calibration/src/MeanVertexObject.cxx b/DataFormats/Calibration/src/MeanVertexObject.cxx index c76593ac7908a..3a08d8eba108a 100644 --- a/DataFormats/Calibration/src/MeanVertexObject.cxx +++ b/DataFormats/Calibration/src/MeanVertexObject.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CMakeLists.txt b/DataFormats/Detectors/CMakeLists.txt index 18b0ed448459c..a93a1c8c11da0 100644 --- a/DataFormats/Detectors/CMakeLists.txt +++ b/DataFormats/Detectors/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # @brief cmake setup for the DataFormats module of AliceO2 @@ -16,12 +17,15 @@ add_subdirectory(ITSMFT) add_subdirectory(MUON) add_subdirectory(TOF) add_subdirectory(FIT) +add_subdirectory(HMPID) add_subdirectory(EMCAL) add_subdirectory(ZDC) add_subdirectory(TRD) add_subdirectory(PHOS) add_subdirectory(CPV) - +add_subdirectory(CTP) +add_subdirectory(GlobalTracking) +add_subdirectory(DCS) if(ENABLE_UPGRADES) add_subdirectory(Upgrades) else() diff --git a/DataFormats/Detectors/CPV/CMakeLists.txt b/DataFormats/Detectors/CPV/CMakeLists.txt index acd427dca151e..ee401c54b88fe 100644 --- a/DataFormats/Detectors/CPV/CMakeLists.txt +++ b/DataFormats/Detectors/CPV/CMakeLists.txt @@ -1,28 +1,39 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsCPV - SOURCES src/CPVBlockHeader.cxx - src/Digit.cxx - src/Cluster.cxx + SOURCES src/CPVBlockHeader.cxx + src/Hit.cxx + src/Digit.cxx + src/Cluster.cxx src/TriggerRecord.cxx - PUBLIC_LINK_LIBRARIES O2::CommonDataFormat - O2::Headers - O2::MathUtils - O2::DetectorsBase - O2::CPVBase + src/CTF.cxx + src/CalibParams.cxx + src/BadChannelMap.cxx + src/Pedestals.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::Headers + O2::MathUtils + O2::DetectorsBase + O2::CPVBase O2::SimulationDataFormat Boost::serialization) o2_target_root_dictionary(DataFormatsCPV HEADERS include/DataFormatsCPV/CPVBlockHeader.h + include/DataFormatsCPV/Hit.h include/DataFormatsCPV/Digit.h include/DataFormatsCPV/Cluster.h - include/DataFormatsCPV/TriggerRecord.h) + include/DataFormatsCPV/TriggerRecord.h + include/DataFormatsCPV/CTF.h + include/DataFormatsCPV/CalibParams.h + include/DataFormatsCPV/BadChannelMap.h + include/DataFormatsCPV/Pedestals.h) diff --git a/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/BadChannelMap.h similarity index 82% rename from Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h rename to DataFormats/Detectors/CPV/include/DataFormatsCPV/BadChannelMap.h index 54f69a0d0e596..7a29cda08161c 100644 --- a/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/BadChannelMap.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,7 +60,7 @@ class BadChannelMap BadChannelMap() = default; /// \brief Constructur used to build test bad map - BadChannelMap(int test); + BadChannelMap(short test); /// \brief Destructor ~BadChannelMap() = default; @@ -93,20 +94,30 @@ class BadChannelMap /// Only bad or warm cells are added to the container. In case /// the mask type is GOOD_CELL, the entry is removed from the /// container if present before, otherwise the cell is ignored. - void addBadChannel(short channelID) { mBadCells.set(channelID); } //set bit to true + void addBadChannel(unsigned short channelID) + { + if (channelID < NCHANNELS) { + mBadCells.set(channelID); + } + } //set bit to true /// \brief Mark channel as good /// \param channelID Absolute ID of the channel /// /// Setting channel as good. - void setChannelGood(short channelID) { mBadCells.set(channelID, false); } + void setChannelGood(unsigned short channelID) + { + if (channelID < NCHANNELS) { + mBadCells.set(channelID, false); + } + } /// \brief Get the status of a certain cell /// \param channelID channel for which to obtain the channel status /// \return true if good channel /// /// Provide the mask status of a cell. - bool isChannelGood(short channelID) const { return !mBadCells.test(channelID); } + bool isChannelGood(unsigned short channelID) const { return !mBadCells.test(channelID); } /// \brief Convert map into 2D histogram representation /// \param mod Module number @@ -117,7 +128,7 @@ class BadChannelMap /// - 0: GOOD_CELL /// - 1: BAD_CELL /// Attention: It is responsibility of user to create/delete histogram - void getHistogramRepresentation(char mod, TH2* h) const; + void getHistogramRepresentation(short mod, TH2* h) const; /// \brief Print bad channels on a given stream /// \param stream Stream on which the bad channel map is printed on @@ -131,8 +142,8 @@ class BadChannelMap void PrintStream(std::ostream& stream) const; private: - static constexpr short NCHANNELS = 28673; ///< Number of channels starting from 1 (4*128*56+1 - std::bitset<NCHANNELS> mBadCells; ///< Container for bad cells, 1 means bad sell + static constexpr unsigned short NCHANNELS = 23040; ///< Number of channels in modules 2-4 starting from 0 (3*128*60) + std::bitset<NCHANNELS> mBadCells; ///< Container for bad cells, 1 means bad sell ClassDefNV(BadChannelMap, 1); }; diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/CPVBlockHeader.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CPVBlockHeader.h index 102c50a1a6754..826ccc917b063 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/CPVBlockHeader.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CPVBlockHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/CTF.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CTF.h new file mode 100644 index 0000000000000..b1db64a872504 --- /dev/null +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CTF.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for CPV CTF data + +#ifndef O2_CPV_CTF_H +#define O2_CPV_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "DataFormatsCPV/Cluster.h" + +namespace o2 +{ +namespace cpv +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t nClusters = 0; /// number of referred cells + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded triggers and cells of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 7, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_entriesTrig, + BLC_posX, + BLC_posZ, + BLC_energy, + BLC_status + }; + ClassDefNV(CTF, 1); +}; + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/CalibParams.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CalibParams.h new file mode 100644 index 0000000000000..a3411601a05c0 --- /dev/null +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/CalibParams.h @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class CalibParams +/// \brief CCDB container for the full set of CPV calibration coefficients +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Aug. 1, 2019 +/// +/// + +#ifndef CPV_CALIBPARAMS_H +#define CPV_CALIBPARAMS_H + +#include <array> +#include "TObject.h" +#include "CPVBase/Geometry.h" + +class TH2; + +namespace o2 +{ + +namespace cpv +{ + +class CalibParams +{ + public: + /// \brief Constructor + CalibParams() = default; + + /// \brief Constructor for tests + CalibParams(short test); + + /// \brief Destructor + ~CalibParams() = default; + + /// \brief Get High Gain energy calibration coefficients + /// \param cellID Absolute ID of cell + /// \return high gain energy calibration coefficient of the cell + float getGain(unsigned short cellID) const { return mGainCalib[cellID]; } + + /// \brief Set High Gain energy calibration coefficient + /// \param cellID Absolute ID of cell + /// \param c is the calibration coefficient + void setGain(unsigned short cellID, float c) + { + if (cellID < o2::cpv::Geometry::kNCHANNELS) { + mGainCalib[cellID] = c; + } + } + + /// \brief Set High Gain energy calibration coefficients for one module in the form of 2D histogram + /// \param 2D(64,56) histogram with calibration coefficients + /// \param module number + /// \return Is successful + bool setGain(TH2* h, short module); + + private: + static constexpr short NCHANNELS = 23040; ///< Number of channels starting from 0 + std::array<float, NCHANNELS> mGainCalib; ///< Container for the gain calibration coefficients + ClassDefNV(CalibParams, 2); +}; + +} // namespace cpv + +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h index 1aa9908db17dc..6a2fe019ce4c8 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,11 +22,27 @@ class Geometry; /// \class Cluster /// \brief Contains CPV cluster parameters +constexpr float kMinX = -72.32; // Minimal coordinate in X direction +constexpr float kStepX = 0.0025; // digitization step in X direction +constexpr float kMinZ = -63.3; // Minimal coordinate in Z direction +constexpr float kStepZ = 0.002; // digitization step in Z direction +constexpr float kStepE = 1.; // Amplitude digitization step + class Cluster { + union CluStatus { + uint8_t mBits; + struct { + uint8_t multiplicity : 5; // Pad multiplicty, bits 0-4 + uint8_t module : 2; // module number, bits 5-6 + uint8_t unfolded : 1; // unfolded bit, bit 7 + }; + }; + public: Cluster() = default; + Cluster(unsigned char mult, char mod, char exMax, float x, float z, float e) : mMulDigit(mult), mModule(mod), mNExMax(exMax), mLocalPosX(x), mLocalPosZ(z), mEnergy(e) {} Cluster(const Cluster& clu) = default; ~Cluster() = default; @@ -42,13 +59,6 @@ class Cluster void setEnergy(float e) { mEnergy = e; } float getEnergy() const { return mEnergy; } - void getPosition(float& posX, float& posY, float& posZ) const - { - posX = mPosX; - posX = mPosY; - posZ = mPosZ; - } - void getLocalPosition(float& posX, float& posZ) const { posX = mLocalPosX; @@ -58,25 +68,52 @@ class Cluster // 0: was no unfolging, -1: unfolding failed char getModule() const { return mModule; } // CPV module of a current cluster - int getLabel() const { return mLabel; } //Index in MCContainer entry - void setLabel(int l) { mLabel = l; } - // 0: was no unfolging, -1: unfolding failed void setNExMax(char nmax = 1) { mNExMax = nmax; } char getNExMax() const { return mNExMax; } // Number of maxima found in cluster in unfolding: // 0: was no unfolging, -1: unfolding failed + // raw access for CTF encoding + uint16_t getPackedPosX() const { return uint16_t((mLocalPosX - kMinX) / kStepX); } + void setPackedPosX(uint16_t v) { mLocalPosX = kMinX + kStepX * v; } + + uint16_t getPackedPosZ() const { return uint16_t((mLocalPosZ - kMinZ) / kStepZ); } + void setPackedPosZ(uint16_t v) { mLocalPosZ = kMinZ + kStepZ * v; } + + uint8_t getPackedEnergy() const { return uint8_t(std::min(255, int(mEnergy / kStepE))); } + void setPackedEnergy(uint16_t v) { mEnergy = v * kStepE; } + + uint8_t getPackedClusterStatus() const + { + CluStatus s = {0}; + s.multiplicity = std::min(mMulDigit, static_cast<unsigned char>(31)); //5 bits available + s.module = mModule; + s.unfolded = mNExMax > 1; + return s.mBits; + } + void setPackedClusterStatus(uint8_t v) + { + CluStatus s = {v}; + mMulDigit = s.multiplicity; + mModule = s.module; + mNExMax = s.unfolded ? 1 : 2; + } + + void setPacked(uint16_t posX, uint16_t posZ, uint8_t en, uint8_t status) + { + setPackedPosX(posX); + setPackedPosZ(posZ); + setPackedEnergy(en); + setPackedClusterStatus(status); + } + protected: - char mMulDigit = 0; ///< Digit nultiplicity - char mModule = 0; ///< Module number - char mNExMax = -1; ///< number of (Ex-)maxima before unfolding - int mLabel = -1; ///< Ref to entry in MCTruthContainer with list of labels - float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) - float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) - float mPosX = 0.; ///< Center of gravity position in global coordinates - float mPosY = 0.; ///< Center of gravity position in global coordinates - float mPosZ = 0.; ///< Center of gravity position in global coordinates - float mEnergy = 0.; ///< full energy of a cluster + unsigned char mMulDigit = 0; ///< Digit nultiplicity + char mModule = 0; ///< Module number + char mNExMax = -1; ///< number of (Ex-)maxima before unfolding + float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) + float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) + float mEnergy = 0.; ///< full energy of a cluster ClassDefNV(Cluster, 1); }; diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h index 15eaf170e521b..f11ccff9c869d 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,20 +37,10 @@ class Digit : public DigitBase /// \brief Main Digit constructor /// \param cell absId of a cell, amplitude energy deposited in a cell, time time measured in cell, label label of a /// particle in case of MC \return constructed Digit - Digit(short cell, float amplitude, int label); - - /// \brief Digit constructor from Hit - /// \param CPV Hit - /// \return constructed Digit - Digit(const Hit& hit, int label); + Digit(unsigned short cell, float amplitude, int label); ~Digit() = default; // override - /// \brief Replace content of this digit with new one, from hit - /// \param CPV Hit - /// \return - void fillFromHit(const Hit& hit); - /// \brief Comparison oparator, based on time and absId /// \param another CPV Digit /// \return result of comparison: first time, if time same, then absId @@ -89,12 +80,12 @@ class Digit : public DigitBase bool canAdd(const Digit other) const; /// \brief if addable, adds energy and list of primaries. /// \param another CPV Digit - /// \return digit with sum of energies and longer list of primaries + /// \return digit with sum of energies Digit& operator+=(const Digit& other); // /// \brief Absolute sell id - short getAbsId() const { return mAbsId; } - void setAbsId(short cellId) { mAbsId = cellId; } + unsigned short getAbsId() const { return mAbsId; } + void setAbsId(unsigned short cellId) { mAbsId = cellId; } /// \brief Energy deposited in a cell float getAmplitude() const { return mAmplitude; } @@ -103,15 +94,24 @@ class Digit : public DigitBase /// \brief index of entry in MCLabels array /// \return ndex of entry in MCLabels array int getLabel() const { return mLabel; } + void setLabel(int l) { mLabel = l; } + + //put all parameters to default + void reset() + { + mAbsId = 0; + mLabel = -1; + mAmplitude = 0.; + } void PrintStream(std::ostream& stream) const; private: // friend class boost::serialization::access; - short mAbsId = 0; ///< pad index (absolute pad ID) - int mLabel = -1; ///< Index of the corresponding entry/entries in the MC label array - float mAmplitude = 0; ///< Amplitude + unsigned short mAbsId = 0; ///< pad index (absolute pad ID) + int mLabel = -1; ///< Index of the corresponding entry/entries in the MC label array + float mAmplitude = 0; ///< Amplitude ClassDefNV(Digit, 2); }; diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Hit.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Hit.h new file mode 100644 index 0000000000000..a9ed2c20ec5d6 --- /dev/null +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Hit.h @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_CPV_HIT_H +#define ALICEO2_CPV_HIT_H + +#include "SimulationDataFormat/BaseHits.h" +#include "CommonUtils/ShmAllocator.h" + +namespace o2 +{ +namespace cpv +{ +/// \class Hit +/// \brief CPV simulation hit information +class Hit : public o2::BasicXYZEHit<float> +{ + public: + /// \brief Default constructor + Hit() = default; + + /// \brief Hit constructor + /// + /// Fully defining information of the CPV Hit (position, + /// momentum, energy, track, ...) + /// + /// \param trackID Index of the track entered CPV + /// \param detID ID of the detector segment + /// \param pos Position vector of the Hit + /// \param mom Momentum vector for the particle at the Hit + /// \param initialEnergy Energy of the primary particle enering the EMCAL + /// \param tof Time of the hit + /// \param length Length of the segment + Hit(int trackID, int detID, const math_utils::Point3D<float>& pos, double tof, double qLoss) + : o2::BasicXYZEHit<float>(pos.X(), pos.Y(), pos.Z(), tof, qLoss, trackID, detID) + { + } + + Hit& operator=(const Hit& hit) = default; + + /// \brief Check whether the points are from the same SuperParent and in the same detector volume + /// \return True if points are the same (origin and detector), false otherwise + Bool_t operator==(const Hit& rhs) const; + + /// \brief Check whether the points are from the same SuperParent and in the same detector volume + /// \return True if points are the same (origin and detector), false otherwise + Bool_t operator=(const Hit& rhs) const; + + /// \brief Sorting points according to parent particle and detector volume + /// \return True if this Hit is smaller, false otherwise + Bool_t operator<(const Hit& rhs) const; + + /// \brief Adds energy loss from the other Hit to this Hit + /// \param rhs cpv::Hit to add to this Hit + /// \return This Hit with the summed energy loss + Hit& operator+=(const Hit& rhs); + + /// \brief Creates a new Hit based on this Hit but adding the energy loss of the right hand side + /// \param + /// \return New Hit based on this Hit + Hit operator+(const Hit& rhs) const; + + /// \brief Destructor + ~Hit() = default; + + void AddEnergyLoss(Double_t eloss) { SetEnergyLoss(GetEnergyLoss() + eloss); } + + /// \brief Writing Hit information to an output stream; + /// \param stream target output stream + void PrintStream(std::ostream& stream) const; + + private: + ClassDefNV(Hit, 1); +}; + +std::ostream& operator<<(std::ostream& stream, const Hit& point); +} // namespace cpv +} // namespace o2 + +#ifdef USESHM +namespace std +{ +template <> +class allocator<o2::cpv::Hit> : public o2::utils::ShmAllocator<o2::cpv::Hit> +{ +}; +} // namespace std +#endif + +#endif /* Hit_h */ diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Pedestals.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Pedestals.h new file mode 100644 index 0000000000000..11b2eb59bc57d --- /dev/null +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Pedestals.h @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class Pedestals +/// \brief CCDB container for the full set of CPV calibration coefficients +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Aug. 1, 2019 +/// +/// + +#ifndef CPV_PEDESTALS_H +#define CPV_PEDESTALS_H + +#include <array> +#include "TObject.h" + +class TH1; +class TH1F; + +namespace o2 +{ + +namespace cpv +{ + +class Pedestals +{ + public: + /// \brief Constructor + Pedestals() = default; + + /// \brief Constructor for tests + Pedestals(int test); + + /// \brief Destructor + ~Pedestals() = default; + + /// \brief Get pedestal + /// \param cellID Absolute ID of cell + /// \return pedestal for the cell + short getPedestal(short cellID) const { return mPedestals.at(cellID); } + float getPedSigma(short cellID) const { return mPedSigmas.at(cellID); } + + /// \brief Set pedestal + /// \param cellID Absolute ID of cell + /// \param c is the pedestal (expected to be in range <254) + void setPedestal(short cellID, short c) + { + if ((cellID >= 0) && (cellID < NCHANNELS)) { + mPedestals[cellID] = (c > 0 && c < 511) ? c : mPedestals[cellID]; + } + } + void setPedSigma(short cellID, float c) + { + if ((cellID >= 0) && (cellID < NCHANNELS)) { + mPedSigmas[cellID] = (c > 0) ? c : mPedSigmas[cellID]; + } + } + + /// \brief Set pedestals from 1D histogram with cell absId in x axis + /// \param 1D(NCHANNELS) histogram with calibration coefficients + /// \return Is successful + bool setPedestals(TH1* h); + bool setPedSigmas(TH1F* h); + + private: + static constexpr short NCHANNELS = 23040; ///< Number of channels in 3 modules starting from 0 + std::array<short, NCHANNELS> mPedestals; ///< Container for pedestals + std::array<float, NCHANNELS> mPedSigmas; ///< Container for pedestal sigmas + + ClassDefNV(Pedestals, 2); +}; + +} // namespace cpv + +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h new file mode 100644 index 0000000000000..4dc033e42544d --- /dev/null +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h @@ -0,0 +1,150 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_CPV_RAWFORMATS_H +#define ALICEO2_CPV_RAWFORMATS_H + +#include <cstdint> +#include "CommonDataFormat/InteractionRecord.h" + +namespace o2 +{ + +namespace cpv +{ + +//Pack information into 24 bit words +union PadWord { + uint32_t mDataWord; + struct { + uint32_t charge : 12; ///< Bits 0 - 11 : charge + uint32_t address : 6; ///< Bits 12 - 17 : address (0..47) + uint32_t gas : 3; ///< Bits 18 - 20 : gasiplex (1..10) + uint32_t dil : 2; ///< Bits 21 - 22 : dilogic (1..24) + uint32_t zero : 1; ///< Bits 23 - 23 : control bit (0 -> pad word, 1 -> FEE control word) + }; + char mBytes[4]; +}; + +class CpvWord +{ + public: + CpvWord() = default; + CpvWord(std::vector<char>::const_iterator b, std::vector<char>::const_iterator e) + { //Reading + //resposibility of coller to esure that + //array will not end while reading + for (int i = 0; i < 16 && b != e; i++, b++) { + mBytes[i] = *b; + } + } + ~CpvWord() = default; + bool isOK() const + { + return (mBytes[9] < static_cast<unsigned char>(24)) && + (mBytes[15] == 0) && (mBytes[14] == 0) && (mBytes[13] == 0) && (mBytes[12] == 0) && (mBytes[11] == 0) && (mBytes[10] == 0); + } + short ccId() const { return short(mBytes[9]); } + uint32_t cpvPadWord(int i) const + { + PadWord p = {0}; + p.mBytes[0] = mBytes[3 * i]; + p.mBytes[1] = mBytes[3 * i + 1]; + p.mBytes[2] = mBytes[3 * i + 2]; + return p.mDataWord; + } + + public: + unsigned char mBytes[16] = {0}; +}; + +class CpvHeader +{ + public: + CpvHeader() = default; + CpvHeader(std::vector<char>::const_iterator b, std::vector<char>::const_iterator e) + { //reading header from file + for (int i = 0; i < 16 && b != e; i++, b++) { //read up to 16 mBytes + mBytes[i] = *b; + } + } + CpvHeader(InteractionRecord orbitBC, bool isNoDataExpected, bool isDataContinued) + { //writing header + //header is 128-bit word. + //|127-120|119-112|111-104|103-96|95-88 |87-80 |79-72|71-64|63-56|55-48|47-40|39-32|31-24|23-16|15-8 |7-0 | + // byte15 byte14 byte13 byte12 byte11 byte10 byte9 byte8 byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0 + //byte = |76543210| + mBytes[0] = (0x010 & 0x0ff); //bits 11 - 0 trigger id (0x010 = physics trigger) + mBytes[1] = ((0x010 & 0xf00) >> 8) //bits 11 - 0 trigger id (0x010 = physics trigger) + + 0b00100000 * isNoDataExpected + 0b0100000 * isDataContinued; //bit 13 (no data for this trigger) + bit 14 (payload continues from previous page) + mBytes[2] = (orbitBC.bc & 0x00ff); //bits 27 - 16 bunch crossing + mBytes[3] = (orbitBC.bc & 0x0f00) >> 8; //bits 27 - 16 bunch crossing + mBytes[4] = (orbitBC.orbit & 0x000000ff); //bits 63 - 32 orbit + mBytes[5] = (orbitBC.orbit & 0x0000ff00) >> 8; //bits 63 - 32 orbit + mBytes[6] = (orbitBC.orbit & 0x00ff0000) >> 16; //bits 63 - 32 orbit + mBytes[7] = (orbitBC.orbit & 0xff000000) >> 24; //bits 63 - 32 orbit + mBytes[8] = 0x00; //bits 64-71 reserved + mBytes[9] = 0xe0; //word ID of cpv header (bits 79 - 72) + for (int i = 10; i < 16; i++) { + mBytes[i] = 0; //bits 127-80 must be zeros + } + } + ~CpvHeader() = default; + bool isOK() const { return (mBytes[9] == 0xe0) && (mBytes[10] == 0) && (mBytes[11] == 0) && (mBytes[12] == 0) && (mBytes[13] == 0) && (mBytes[14] == 0) && (mBytes[15] == 0); } + bool isNoDataExpected() const { return mBytes[1] & 0b00100000; } + bool isDataContinued() const { return mBytes[1] & 0b0100000; } + uint16_t bc() const { return static_cast<uint16_t>(mBytes[2]) + static_cast<uint16_t>((mBytes[3] & 0x0f) << 8); } + uint32_t orbit() const { return mBytes[4] + (mBytes[5] << 8) + (mBytes[6] << 16) + (mBytes[7] << 24); } + + public: + unsigned char mBytes[16] = {0}; //0 - 127 bits (16 bytes) +}; + +class CpvTrailer +{ + public: + CpvTrailer() = default; + CpvTrailer(std::vector<char>::const_iterator b, std::vector<char>::const_iterator e) + { //reading + for (int i = 0; i < 16 && b != e; i++, b++) { //read up to 16 mBytes + mBytes[i] = *b; + } + } + CpvTrailer(unsigned short wordCounter, uint16_t bunchCrossing, bool isAllDataSent) + { //writing + mBytes[0] = bunchCrossing & 0x00ff; //bits 11 - 0 bunch crossing + mBytes[1] = ((bunchCrossing & 0x0f00) >> 8) //bits 11 - 0 bunch crossing + + ((wordCounter & 0x0f) << 4); //bits 20 - 12 wordCounter + mBytes[2] = (wordCounter & 0b111110000) >> 4; //bits 20 - 12 wordCounter + for (int i = 3; i < 8; i++) { + mBytes[i] = 0; //bits 70 - 21 reserved + } + mBytes[8] = isAllDataSent * 0b10000000; //bit 71 all data is sent for current trigger + mBytes[9] = char(0xf0); //word ID of cpv trailer + for (int i = 10; i < 16; i++) { + mBytes[i] = 0; + } + } + ~CpvTrailer() = default; + bool isOK() const { return (mBytes[9] == 0xf0) && (mBytes[10] == 0) && (mBytes[11] == 0) && (mBytes[12] == 0) && (mBytes[13] == 0) && (mBytes[14] == 0) && (mBytes[15] == 0); } + uint16_t wordCounter() const { return (mBytes[1] >> 4) + ((mBytes[2] & 0b00011111) << 4); } + bool isAllDataSent() const { return (mBytes[8] & 0b10000000); } + uint16_t bc() const { return mBytes[0] + ((mBytes[1] & 0x0f) << 8); } + + public: + unsigned char mBytes[16] = {0}; +}; + +} // namespace cpv + +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/TriggerRecord.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/TriggerRecord.h index 7310498e6d921..d08cebd1a6e07 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/TriggerRecord.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/TriggerRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CPV/src/BadChannelMap.cxx b/DataFormats/Detectors/CPV/src/BadChannelMap.cxx new file mode 100644 index 0000000000000..c345448af28a3 --- /dev/null +++ b/DataFormats/Detectors/CPV/src/BadChannelMap.cxx @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVBase/Geometry.h" +#include "DataFormatsCPV/BadChannelMap.h" + +#include "FairLogger.h" + +#include <TH2.h> + +#include <iostream> + +using namespace o2::cpv; + +BadChannelMap::BadChannelMap(short test) +{ + //reset all channels to be good + mBadCells.reset(); + + if (test == 2) { + //Mark few channels as bad for test peurposes + for (short i = 0; i < 60; i++) { + //module 2 + unsigned short channelID = 3584 + i * 57; + mBadCells.set(channelID); + channelID = 3640 + i * 55; + mBadCells.set(channelID); + } + + for (short i = 0; i < 16; i++) { + //module 3 + unsigned short channelID = 8972 + i * 57; + mBadCells.set(channelID); + channelID = 8092 + i * 57; + mBadCells.set(channelID); + channelID = 8147 + i * 55; + mBadCells.set(channelID); + channelID = 9059 + i * 55; + mBadCells.set(channelID); + } + } +} + +void BadChannelMap::getHistogramRepresentation(short module, TH2* h) const +{ + if (!h) { + LOG(ERROR) << "provide histogram to be filled"; + } + + const short MAXX = 128, + MAXZ = 60; + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return; + } + + h->Reset(); + + short relid[3] = {module, 1, 1}; + unsigned short absId; + for (short ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (short iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + if (Geometry::relToAbsNumbering(relid, absId)) { + if (!isChannelGood(absId)) { + h->SetBinContent(ix, iz, 1); + } + } + } + } +} + +void BadChannelMap::PrintStream(std::ostream& stream) const +{ + // first sort bad channel IDs + stream << "Number of bad cells: " << mBadCells.count() << "\n"; + for (int cellID = 0; cellID < mBadCells.size(); cellID++) { + if (mBadCells.test(cellID)) { + stream << cellID << "\n"; + } + } +} + +std::ostream& o2::cpv::operator<<(std::ostream& stream, const BadChannelMap& bcm) +{ + bcm.PrintStream(stream); + return stream; +} diff --git a/DataFormats/Detectors/CPV/src/CPVBlockHeader.cxx b/DataFormats/Detectors/CPV/src/CPVBlockHeader.cxx index fd86dd60d15ea..12de54989fe74 100644 --- a/DataFormats/Detectors/CPV/src/CPVBlockHeader.cxx +++ b/DataFormats/Detectors/CPV/src/CPVBlockHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CPV/src/CTF.cxx b/DataFormats/Detectors/CPV/src/CTF.cxx new file mode 100644 index 0000000000000..14dcad0db9fb4 --- /dev/null +++ b/DataFormats/Detectors/CPV/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsCPV/CTF.h" + +using namespace o2::cpv; diff --git a/DataFormats/Detectors/CPV/src/CalibParams.cxx b/DataFormats/Detectors/CPV/src/CalibParams.cxx new file mode 100644 index 0000000000000..e86f36d2134a4 --- /dev/null +++ b/DataFormats/Detectors/CPV/src/CalibParams.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsCPV/CalibParams.h" +#include "CPVBase/Geometry.h" + +#include "FairLogger.h" + +#include <TH2.h> + +#include <iostream> + +using namespace o2::cpv; + +CalibParams::CalibParams(short /*dummy*/) +{ + //produce reasonable objest for test purposes + mGainCalib.fill(1.); +} + +bool CalibParams::setGain(TH2* h, short module) +{ + const short MAXX = 128, + MAXZ = 60; + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return false; + } + + short relid[3] = {module, 0, 0}; + unsigned short absId; + for (short ix = 1; ix <= MAXX; ix++) { + relid[1] = ix - 1; + for (short iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz - 1; + + if (Geometry::relToAbsNumbering(relid, absId)) { + mGainCalib[absId] = h->GetBinContent(ix, iz); + } + } + } + return true; +} diff --git a/DataFormats/Detectors/CPV/src/Cluster.cxx b/DataFormats/Detectors/CPV/src/Cluster.cxx index fc2b2f2f19021..eeeae9998d181 100644 --- a/DataFormats/Detectors/CPV/src/Cluster.cxx +++ b/DataFormats/Detectors/CPV/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CPV/src/DataFormatsCPVLinkDef.h b/DataFormats/Detectors/CPV/src/DataFormatsCPVLinkDef.h index 7b08dd67ba51f..253c21db079a0 100644 --- a/DataFormats/Detectors/CPV/src/DataFormatsCPVLinkDef.h +++ b/DataFormats/Detectors/CPV/src/DataFormatsCPVLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,12 +15,22 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::cpv::Hit + ; #pragma link C++ class o2::cpv::Digit + ; #pragma link C++ class o2::cpv::Cluster + ; #pragma link C++ class o2::cpv::TriggerRecord + ; +#pragma link C++ class vector < o2::cpv::Hit> + ; #pragma link C++ class std::vector < o2::cpv::Digit> + ; #pragma link C++ class std::vector < o2::cpv::Cluster> + ; #pragma link C++ class std::vector < o2::cpv::TriggerRecord> + ; +#pragma link C++ struct o2::cpv::CTFHeader + ; +#pragma link C++ struct o2::cpv::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::cpv::CTFHeader, 7, uint32_t> + ; + +#pragma link C++ class o2::cpv::BadChannelMap + ; +#pragma link C++ class o2::cpv::CalibParams + ; +#pragma link C++ class o2::cpv::Pedestals + ; + #endif diff --git a/DataFormats/Detectors/CPV/src/Digit.cxx b/DataFormats/Detectors/CPV/src/Digit.cxx index a2e211b167fda..8694187cd5ca1 100644 --- a/DataFormats/Detectors/CPV/src/Digit.cxx +++ b/DataFormats/Detectors/CPV/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,26 +11,17 @@ #include "FairLogger.h" #include "DataFormatsCPV/Digit.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" #include <iostream> using namespace o2::cpv; ClassImp(Digit); -Digit::Digit(short absId, float amplitude, int label) +Digit::Digit(unsigned short absId, float amplitude, int label) : DigitBase(0), mAmplitude(amplitude), mAbsId(absId), mLabel(label) { } -Digit::Digit(const Hit& hit, int label) : mAbsId(hit.GetDetectorID()), mAmplitude(hit.GetEnergyLoss()), mLabel(label) -{ -} -void Digit::fillFromHit(const Hit& hit) -{ - mAbsId = hit.GetDetectorID(); - mAmplitude = hit.GetEnergyLoss(); -} - bool Digit::canAdd(const Digit other) const { return (mAbsId == other.getAbsId() && fabs(getTimeStamp() - other.getTimeStamp()) <= kTimeGate); diff --git a/Detectors/CPV/base/src/Hit.cxx b/DataFormats/Detectors/CPV/src/Hit.cxx similarity index 79% rename from Detectors/CPV/base/src/Hit.cxx rename to DataFormats/Detectors/CPV/src/Hit.cxx index 9fbddd7e5fc7e..480470be75b90 100644 --- a/Detectors/CPV/base/src/Hit.cxx +++ b/DataFormats/Detectors/CPV/src/Hit.cxx @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" using namespace o2::cpv; diff --git a/DataFormats/Detectors/CPV/src/Pedestals.cxx b/DataFormats/Detectors/CPV/src/Pedestals.cxx new file mode 100644 index 0000000000000..93282441ddbf1 --- /dev/null +++ b/DataFormats/Detectors/CPV/src/Pedestals.cxx @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsCPV/Pedestals.h" +#include "FairLogger.h" +#include <TH1.h> +#include <TH1F.h> + +using namespace o2::cpv; + +Pedestals::Pedestals(int /*dummy*/) +{ + //produce reasonable objest for test purposes + mPedestals.fill(200); //typical pedestal value + mPedSigmas.fill(1.5); //typical pedestal sigma +} +//______________________________________________________________________________ +bool Pedestals::setPedestals(TH1* h) +{ + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != NCHANNELS) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << " instead of " << NCHANNELS; + return false; + } + + for (short i = 1; i <= NCHANNELS; i++) { + if (h->GetBinContent(i) > 511) { + LOG(ERROR) << "setPedestals : pedestal value = " << h->GetBinContent(i) + << " in channel " << i + << " exceeds max possible value 511 (limited by CPV electronics)"; + continue; + } + mPedestals[i - 1] = short(h->GetBinContent(i)); + } + return true; +} +//_______________________________________________________________________________ +bool Pedestals::setPedSigmas(TH1F* h) +{ + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != NCHANNELS) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << " instead of " << NCHANNELS; + return false; + } + + for (short i = 1; i <= NCHANNELS; i++) { + if (h->GetBinContent(i) < 0) { + LOG(ERROR) << "pedestal sigma = " << h->GetBinContent(i) + << " in channel " << i + << " cannot be less than 0"; + continue; + } + mPedSigmas[i - 1] = float(h->GetBinContent(i)); + } + return true; +} diff --git a/DataFormats/Detectors/CPV/src/TriggerRecord.cxx b/DataFormats/Detectors/CPV/src/TriggerRecord.cxx index a1eb865dc0e7b..e816afe01d10f 100644 --- a/DataFormats/Detectors/CPV/src/TriggerRecord.cxx +++ b/DataFormats/Detectors/CPV/src/TriggerRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/CTP/CMakeLists.txt b/DataFormats/Detectors/CTP/CMakeLists.txt new file mode 100644 index 0000000000000..437766a2397fe --- /dev/null +++ b/DataFormats/Detectors/CTP/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(DataFormatsCTP + SOURCES src/Digits.cxx + src/Configuration.cxx + src/Scalers.cxx + src/CTF.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::Headers + O2::SimulationDataFormat + O2::CommonConstants) +o2_target_root_dictionary(DataFormatsCTP + HEADERS include/DataFormatsCTP/Digits.h + include/DataFormatsCTP/Configuration.h + include/DataFormatsCTP/Scalers.h + include/DataFormatsCTP/CTF.h) + diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h new file mode 100644 index 0000000000000..3e42d9fe315ad --- /dev/null +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for CTP CTF data + +#ifndef O2_CTP_CTF_H +#define O2_CTP_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" + +namespace o2 +{ +namespace ctp +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + + ClassDefNV(CTFHeader, 1); +}; + +/// wrapper for the Entropy-encoded trigger inputs and classes of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 4, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_bytesInput, // bytes of the CTPInputMask bitset (6 bytes from lowest to highest) + BLC_bytesClass // bytes of the CTPClassMask bitset (8 bytes from lowest to highest) + }; + ClassDefNV(CTF, 1); +}; + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h new file mode 100644 index 0000000000000..1def89cfede30 --- /dev/null +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h @@ -0,0 +1,118 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Configuration.h +/// \brief definition of CTPConfiguration and related CTP structures +/// \author Roman Lietava + +#ifndef _CTP_CONFIGURATION_H_ +#define _CTP_CONFIGURATION_H_ +#include "DetectorsCommonDataFormats/DetID.h" +#include "CommonConstants/LHCConstants.h" +#include <string> +#include <vector> +#include <bitset> +#include <map> +namespace o2 +{ +namespace ctp +{ +/// Database constants +const std::string CCDBPathCTPConfig = "CTP/Config"; +/// +bool isDetector(o2::detectors::DetID& det); +/// CTP Config items +struct BCMask { + BCMask() = default; + std::string name; + std::bitset<o2::constants::lhc::LHCMaxBunches> BCmask; + void printStream(std::ostream& strem) const; + ClassDefNV(BCMask, 1); +}; +struct CTPInput { + CTPInput() = default; + std::string name; + std::string level; + std::uint64_t inputMask; + o2::detectors::DetID::ID detID; + std::string getInputDetName() const { return o2::detectors::DetID::getName(detID); } + void printStream(std::ostream& strem) const; + ClassDefNV(CTPInput, 2); +}; +struct CTPDescriptor { + CTPDescriptor() = default; + std::string name; + std::vector<CTPInput*> inputs; + std::uint64_t getInputsMask() const; + void printStream(std::ostream& strem) const; + ClassDefNV(CTPDescriptor, 2) +}; +/// The main part is Local Trigger Generator (LTG) +struct CTPDetector { + CTPDetector() = default; + o2::detectors::DetID::ID detID; + const char* getName() const { return o2::detectors::DetID::getName(detID); } + uint32_t HBaccepted; /// Number of HB frames in TF to be accepted + void printStream(std::ostream& strem) const; +}; +struct CTPCluster { + CTPCluster() = default; + std::string name; + o2::detectors::DetID::mask_t maskCluster; + std::string getClusterDetNames() const { return o2::detectors::DetID::getNames(maskCluster, ' '); } + void printStream(std::ostream& strem) const; + ClassDefNV(CTPCluster, 2) +}; +struct CTPClass { + CTPClass() = default; + std::string name; + std::uint64_t classMask; + CTPDescriptor const* descriptor; + CTPCluster const* cluster; + void printStream(std::ostream& strem) const; + ClassDefNV(CTPClass, 1); +}; +class CTPConfiguration +{ + public: + CTPConfiguration() = default; + bool isDetector(const o2::detectors::DetID& det); + int loadConfiguration(const std::string& ctpconfiguartion); + void addBCMask(const BCMask& bcmask); + void addCTPInput(const CTPInput& input); + void addCTPDescriptor(const CTPDescriptor& descriptor); + void addCTPDetector(const CTPDetector& detector); + void addCTPCluster(const CTPCluster& cluster); + void addCTPClass(const CTPClass& ctpclass); + void printStream(std::ostream& stream) const; + std::vector<CTPInput>& getCTPInputs() { return mInputs; } + std::vector<CTPClass>& getCTPClasses() { return mCTPClasses; } + uint64_t getInputMask(const std::string& name); + bool isMaskInInputs(const uint64_t& mask) const; + CTPInput* isInputInConfig(const std::string inpname); + uint64_t getDecrtiptorInputsMask(const std::string& name) const; + std::map<o2::detectors::DetID::ID, std::vector<CTPInput>> getDet2InputMap(); + + private: + std::string mName; + std::string mVersion; + std::vector<BCMask> mBCMasks; + std::vector<CTPInput> mInputs; + std::vector<CTPDescriptor> mDescriptors; + std::vector<CTPDetector> mDetectors; + std::vector<CTPCluster> mClusters; + std::vector<CTPClass> mCTPClasses; + int processConfigurationLine(std::string& line, int& level); + ClassDefNV(CTPConfiguration, 2); +}; +} // namespace ctp +} // namespace o2 +#endif //_CTP_CONFIGURATION_H_ diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h new file mode 100644 index 0000000000000..8c9b851e96b5a --- /dev/null +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Digits.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digits.h +/// \brief definition of CTPDigit, CTPInputDigit +/// \author Roman Lietava + +#ifndef _CTP_DIGITS_H_ +#define _CTP_DIGITS_H_ +#include "DetectorsCommonDataFormats/DetID.h" +#include "CommonDataFormat/InteractionRecord.h" +#include <bitset> +#include <iosfwd> + +namespace o2 +{ +namespace ctp +{ +/// CTP related constants +static constexpr uint32_t GBTLinkIDIntRec = 0; +static constexpr uint32_t NIntRecPayload = 48 + 12; +static constexpr uint32_t GBTLinkIDClassRec = 1; +static constexpr uint32_t NClassPayload = 64 + 12; +static constexpr uint32_t NGBT = 80; +static constexpr std::uint32_t NumOfHBInTF = 256; +typedef std::bitset<NGBT> gbtword80_t; +// +static constexpr std::uint32_t CTP_NINPUTS = 46; /// Max number of CTP inputs for all levels +static constexpr std::uint32_t CTP_NCLASSES = 64; /// Number of classes in hardware +static constexpr std::uint32_t CTP_MAXTRIGINPPERDET = 5; /// Max number of LM/L0inputs per detector +/// Positions of CTP Detector inputs in CTPInputMask: first=offset, second=mask +/// For digits input position is fixed +/// CTP hits are inputs. Digits are inputs collected from all detectors and CTP Class mask. +/// digits->raw: NO CTP Config to be used +/// raw->digits: NO CTP config to be used +/// Hits (CTP inputs) to CTP digits, i.e. inputs in correct position in mask nad CTP classes mask: CTP config to be used. +/// +/// +struct CTPDigit { + o2::InteractionRecord intRecord; + std::bitset<CTP_NINPUTS> CTPInputMask; + std::bitset<CTP_NCLASSES> CTPClassMask; + CTPDigit() = default; + void printStream(std::ostream& stream) const; + void setInputMask(gbtword80_t mask); + void setClassMask(gbtword80_t mask); + bool operator==(const CTPDigit& d) const + { + return intRecord == d.intRecord && CTPInputMask == d.CTPInputMask && CTPClassMask == d.CTPClassMask; + } + + ClassDefNV(CTPDigit, 2); +}; + +std::ostream& operator<<(std::ostream& os, const CTPDigit& d); + +struct CTPInputDigit { + o2::InteractionRecord intRecord; + std::bitset<CTP_MAXTRIGINPPERDET> inputsMask; + o2::detectors::DetID::ID detector; + CTPInputDigit() = default; + ClassDefNV(CTPInputDigit, 1) +}; +} // namespace ctp +} // namespace o2 +#endif //_CTP_DIGITS_H diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h new file mode 100644 index 0000000000000..c372a6f590c1a --- /dev/null +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Scalers.h +/// \brief definition of CTPScalerRaw, CTPScalerO2 +/// \author Roman Lietava + +#ifndef _CTP_SCALERS_H_ +#define _CTP_SCALERS_H_ +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsCTP/Digits.h" +#include <map> +#include <bitset> + +namespace o2 +{ +namespace ctp +{ +/// raw scalers produced by CTP and send to O2 either via +/// - ZeroMQ published at CTP control machine +/// - CTPreadout to FLP +struct CTPScalerRaw { + CTPScalerRaw() = default; + uint32_t classIndex; + uint32_t lmBefore; + uint32_t lmAfter; + uint32_t l0Before; + uint32_t l0After; + uint32_t l1Before; + uint32_t l1After; + void printStream(std::ostream& stream) const; + ClassDefNV(CTPScalerRaw, 1); +}; +/// Scalers produced from raw scalers corrected for overflow +struct CTPScalerO2 { + CTPScalerO2() = default; + void createCTPScalerO2FromRaw(const CTPScalerRaw& raw, const std::array<uint32_t, 6>& overfow); + uint32_t classIndex; + uint64_t lmBefore; + uint64_t lmAfter; + uint64_t l0Before; + uint64_t l0After; + uint64_t l1Before; + uint64_t l1After; + void printStream(std::ostream& stream) const; + ClassDefNV(CTPScalerO2, 1); +}; +struct CTPScalerRecordRaw { + CTPScalerRecordRaw() = default; + o2::InteractionRecord intRecord; + uint32_t seconds; + uint32_t microSeconds; + std::vector<CTPScalerRaw> scalers; + void printStream(std::ostream& stream) const; + ClassDefNV(CTPScalerRecordRaw, 1); +}; +struct CTPScalerRecordO2 { + CTPScalerRecordO2() = default; + o2::InteractionRecord intRecord; + uint32_t seconds; + uint32_t microSeconds; + std::vector<CTPScalerO2> scalers; + void printStream(std::ostream& stream) const; + ClassDefNV(CTPScalerRecordO2, 1); +}; +class CTPRunScalers +{ + public: + CTPRunScalers() = default; + void printStream(std::ostream& stream) const; + void printClasses(std::ostream& stream) const; + std::vector<uint32_t> getClassIndexes() const; + int readScalers(const std::string& rawscalers); + int convertRawToO2(); + int checkConsistency(const CTPScalerO2& scal0, const CTPScalerO2& scal1) const; + int checkConsistency(const CTPScalerRecordO2& rec0, const CTPScalerRecordO2& rec1) const; + + private: + // map from class index to overflow + // overflow counts how many time class scalerers overflowed + typedef std::map<uint32_t, std::array<uint32_t, 6>> overflows_t; + int mVersion; + uint32_t mRunNumber; + // using class mask for all class index related stuff + std::bitset<CTP_NCLASSES> mClassMask; + std::vector<CTPScalerRecordRaw> mScalerRecordRaw; + std::vector<CTPScalerRecordO2> mScalerRecordO2; + int processScalerLine(const std::string& line, int& level, int& nclasses); + int copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows); + int updateOverflows(const CTPScalerRecordRaw& rec0, const CTPScalerRecordRaw& rec1, overflows_t& classesoverflows) const; + int updateOverflows(const CTPScalerRaw& scal0, const CTPScalerRaw& scal1, std::array<uint32_t, 6>& overflow) const; + ClassDefNV(CTPRunScalers, 1); +}; +} // namespace ctp +} // namespace o2 +#endif //_CTP_SCALERS_H diff --git a/DataFormats/Detectors/CTP/src/CTF.cxx b/DataFormats/Detectors/CTP/src/CTF.cxx new file mode 100644 index 0000000000000..3616f6a387040 --- /dev/null +++ b/DataFormats/Detectors/CTP/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsCTP/CTF.h" + +using namespace o2::ctp; diff --git a/DataFormats/Detectors/CTP/src/Configuration.cxx b/DataFormats/Detectors/CTP/src/Configuration.cxx new file mode 100644 index 0000000000000..8375f157ef32a --- /dev/null +++ b/DataFormats/Detectors/CTP/src/Configuration.cxx @@ -0,0 +1,328 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Configuration.cxx +/// \author Roman Lietava + +#include "DataFormatsCTP/Configuration.h" +#include <iostream> +#include <sstream> +#include "CommonUtils/StringUtils.h" +#include "FairLogger.h" + +using namespace o2::ctp; +// +void BCMask::printStream(std::ostream& stream) const +{ + stream << "CTP BC mask:" << name << std::endl; + /// << ":" << BCmask << std::endl; +} +// +void CTPInput::printStream(std::ostream& stream) const +{ + stream << "CTP Input:" << name << " Detector:" << getInputDetName() << " Level:" << level << " Hardware mask:0x" << std::hex << inputMask << std::dec << std::endl; +} +// +std::uint64_t CTPDescriptor::getInputsMask() const +{ + uint64_t mask = 0; + for (const auto& inp : inputs) { + mask |= inp->inputMask; + } + return mask; +} +void CTPDescriptor::printStream(std::ostream& stream) const +{ + stream << "CTP Descriptor:" << name << " Inputs:"; + for (const auto& inp : inputs) { + stream << inp->name << " "; + } + stream << std::endl; +} +// +void CTPDetector::printStream(std::ostream& stream) const +{ + stream << "CTP Detector:" << getName() << " HBaccepted:" << HBaccepted << std::endl; +} + +void CTPCluster::printStream(std::ostream& stream) const +{ + stream << "CTP Cluster:" << name << getClusterDetNames(); + stream << " mask:0b" << std::hex << maskCluster << " " << std::dec; + stream << std::endl; +} +// +void CTPClass::printStream(std::ostream& stream) const +{ + stream << "CTP Class:" << name << " Hardware mask:" << classMask << " Descriptor:" << descriptor->name << " Cluster:" << cluster->name << std::endl; +} +/// CTP configuration +/// Assuming Run2 format + LTG +// +bool CTPConfiguration::isDetector(const o2::detectors::DetID& det) +{ + if (det.getID() >= det.getNDetectors()) { + LOG(FATAL) << " Detector does not exist: " << det.getName(); + return false; + } + return true; +} +int CTPConfiguration::loadConfiguration(const std::string& ctpconfiguration) +{ + LOG(INFO) << "Loading CTP configuration."; + std::istringstream iss(ctpconfiguration); + int ret = 0; + int level = 0; + std::string line; + while (std::getline(iss, line)) { + o2::utils::Str::trim(line); + if ((ret = processConfigurationLine(line, level)) != 0) { + return ret; + } + } + return ret; +} +int CTPConfiguration::processConfigurationLine(std::string& line, int& level) +{ + if (line.size() == 0) { + return 0; + } + if (line.at(0) == '#') { + return 0; + } + size_t first; + if ((first = line.find("PARTITION:")) != std::string::npos) { + mName = o2::utils::Str::trim_copy(line.erase(first, 10)); + return 0; + } + if ((first = line.find("VERSION:")) != std::string::npos) { + mVersion = o2::utils::Str::trim_copy(line.erase(first, 8)); + return 0; + } + if ((first = line.find("INPUTS:")) != std::string::npos) { + level = 1; + return 0; + } + if ((first = line.find("DESCRIPTORS:")) != std::string::npos) { + level = 3; + return 0; + } + if ((first = line.find("CLUSTERS:")) != std::string::npos) { + level = 4; + return 0; + } + if ((first = line.find("CLASSES:")) != std::string::npos) { + level = 7; + return 0; + } + /// Do parse levels + std::vector<std::string> tokens = o2::utils::Str::tokenize(line, ' '); + size_t ntokens = tokens.size(); + if (ntokens == 0) { + return 0; + } + switch (level) { + case 1: + /// INPUTS: name det level indexCTP<0:45> + { + if (ntokens != 4) { + LOG(FATAL) << "INPUTS syntax error in, wrong number of items, expected 4:" << line; + return level; + } + CTPInput inp; + inp.name = tokens[0]; + std::string detName = tokens[1]; + inp.level = tokens[2]; + o2::detectors::DetID det(detName.c_str()); + isDetector(det); + inp.detID = det.getID(); + //std::cout << "id:" << det.getID() << " ndets:" << det.getNDetectors() << std::endl; + try { + inp.inputMask = std::stoull(tokens[3], nullptr, 0); + } catch (...) { + LOG(FATAL) << "INPUTS syntax error in mask:" << line; + return level; + } + mInputs.push_back(inp); + break; + } + case 3: + /// Descriptors: name input1 , input2, ... + { + CTPDescriptor desc; + desc.name = tokens[0]; + tokens.erase(tokens.begin()); + for (auto& item : tokens) { + //CTPInput *inp = const_cast<CTPInput*> (isInputInConfig(item)); + CTPInput* inp = isInputInConfig(item); + if (inp == nullptr) { + LOG(FATAL) << "DESCRIPTOR: input not in INPUTS:" << item << " LINE:" << line; + } else { + desc.inputs.push_back(inp); + } + } + // Create inputs and mask + mDescriptors.push_back(desc); + break; + } + case 4: + /// Clusters: name det1 det2 ... det N + { + CTPCluster cluster; + cluster.name = tokens[0]; + tokens.erase(tokens.begin()); + o2::detectors::DetID::mask_t mask; + for (auto& item : tokens) { + o2::detectors::DetID det(item.c_str()); + isDetector(det); + mask |= det.getMask(); + } + cluster.maskCluster = mask; + mClusters.push_back(cluster); + break; + } + case 7: + /// CLASSES: name mask descriptor cluster LM L0 L1 + { + CTPClass cls; + if (ntokens != 4) { + LOG(FATAL) << "CLASSES syntax error, wrong number of items, expected 4:" << line; + return level; + } + cls.name = tokens[0]; + try { + cls.classMask = std::stoull(tokens[1]); + } catch (...) { + LOG(FATAL) << "CLASSES syntax error in mask:" << line; + return level; + } + std::string token = tokens[2]; + auto it = std::find_if(mDescriptors.begin(), mDescriptors.end(), [&token](const CTPDescriptor& obj) { return obj.name == token; }); + if (it != mDescriptors.end()) { + cls.descriptor = &*it; + } else { + ///Internal error + LOG(FATAL) << "CLASSES syntax error, descriptor not found:" << token; + } + /// + token = tokens[3]; + auto it2 = std::find_if(mClusters.begin(), mClusters.end(), [&token](const CTPCluster& obj) { return obj.name == token; }); + if (it2 != mClusters.end()) { + cls.cluster = &*it2; + } else { + ///Internal error + LOG(FATAL) << "CLASSES syntax error, cluster not found:" << token; + } + mCTPClasses.push_back(cls); + break; + } + default: { + LOG(FATAL) << "CTP Config parser Unknown level:" << level; + } + } + return 0; +} +void CTPConfiguration::addBCMask(const BCMask& bcmask) +{ + mBCMasks.push_back(bcmask); +} +void CTPConfiguration::addCTPInput(const CTPInput& input) +{ + mInputs.push_back(input); +} +void CTPConfiguration::addCTPDescriptor(const CTPDescriptor& descriptor) +{ + mDescriptors.push_back(descriptor); +} +void CTPConfiguration::addCTPDetector(const CTPDetector& detector) +{ + mDetectors.push_back(detector); +} +void CTPConfiguration::addCTPCluster(const CTPCluster& cluster) +{ + mClusters.push_back(cluster); +} +void CTPConfiguration::addCTPClass(const CTPClass& ctpclass) +{ + mCTPClasses.push_back(ctpclass); +} +void CTPConfiguration::printStream(std::ostream& stream) const +{ + stream << "Configuration:" << mName << "\n Version:" << mVersion << std::endl; + stream << "CTP BC masks:" << std::endl; + for (const auto& i : mBCMasks) { + i.printStream(stream); + } + stream << "CTP inputs:" << std::endl; + for (const auto& i : mInputs) { + i.printStream(stream); + } + stream << "CTP descriptors:" << std::endl; + for (const auto& i : mDescriptors) { + i.printStream(stream); + } + stream << "CTP detectors:" << std::endl; + for (const auto& i : mDetectors) { + i.printStream(stream); + } + stream << "CTP clusters:" << std::endl; + for (const auto& i : mClusters) { + i.printStream(stream); + } + stream << "CTP classes:" << std::endl; + for (const auto& i : mCTPClasses) { + i.printStream(stream); + } +} +uint64_t CTPConfiguration::getInputMask(const std::string& name) +{ + for (auto const& inp : mInputs) { + if (inp.name == name) { + return inp.inputMask; + } + } + return 0; +} +bool CTPConfiguration::isMaskInInputs(const uint64_t& mask) const +{ + for (auto const& inp : mInputs) { + if (inp.inputMask == mask) { + return true; + } + } + return false; +} +CTPInput* CTPConfiguration::isInputInConfig(const std::string inpname) +{ + for (auto& inp : mInputs) { + if (inp.name == inpname) { + return &inp; + } + } + return nullptr; +} +uint64_t CTPConfiguration::getDecrtiptorInputsMask(const std::string& name) const +{ + for (auto const& desc : mDescriptors) { + if (desc.name == name) { + return desc.getInputsMask(); + } + } + return 0xffffffff; +} +std::map<o2::detectors::DetID::ID, std::vector<CTPInput>> CTPConfiguration::getDet2InputMap() +{ + std::map<o2::detectors::DetID::ID, std::vector<CTPInput>> det2inp; + for (auto const& inp : mInputs) { + det2inp[inp.detID].push_back(inp); + } + return det2inp; +} diff --git a/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h b/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h new file mode 100644 index 0000000000000..47ea52e8f1d91 --- /dev/null +++ b/DataFormats/Detectors/CTP/src/DataFormatsCTPLinkDef.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class o2::ctp::CTPDigit + ; +#pragma link C++ class vector < o2::ctp::CTPDigit> + ; +#pragma link C++ class o2::ctp::CTPInputDigit + ; +#pragma link C++ class vector < o2::ctp::CTPInputDigit> + ; +#pragma link C++ class o2::ctp::BCMask + ; +#pragma link C++ class vector < o2::ctp::BCMask> + ; +#pragma link C++ class o2::ctp::CTPInput + ; +#pragma link C++ class vector < o2::ctp::CTPInput> + ; +#pragma link C++ class o2::ctp::CTPDescriptor + ; +#pragma link C++ class vector < o2::ctp::CTPDescriptor> + ; +#pragma link C++ class o2::ctp::CTPDetector + ; +#pragma link C++ class vector < o2::ctp::CTPDetector> + ; +#pragma link C++ class o2::ctp::CTPCluster + ; +#pragma link C++ class vector < o2::ctp::CTPCluster> + ; +#pragma link C++ class o2::ctp::CTPClass + ; +#pragma link C++ class vector < o2::ctp::CTPClass> + ; +#pragma link C++ class o2::ctp::CTPConfiguration + ; +#pragma link C++ class o2::ctp::CTPScalerRaw + ; +#pragma link C++ class vector < o2::ctp::CTPScalerRaw> + ; +#pragma link C++ class o2::ctp::CTPScalerO2 + ; +#pragma link C++ class vector < o2::ctp::CTPScalerO2> + ; +#pragma link C++ class o2::ctp::CTPScalerRecordRaw + ; +#pragma link C++ class vector < o2::ctp::CTPScalerRecordRaw> + ; +#pragma link C++ class o2::ctp::CTPScalerRecordO2 + ; +#pragma link C++ class vector < o2::ctp::CTPScalerRecordO2> + ; +#pragma link C++ class o2::ctp::CTPRunScalers + ; + +#pragma link C++ struct o2::ctp::CTFHeader + ; +#pragma link C++ struct o2::ctp::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::ctp::CTFHeader, 4, uint32_t> + ; + +#endif diff --git a/DataFormats/Detectors/CTP/src/Digits.cxx b/DataFormats/Detectors/CTP/src/Digits.cxx new file mode 100644 index 0000000000000..aa44216270721 --- /dev/null +++ b/DataFormats/Detectors/CTP/src/Digits.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digits.cxx +/// \author Roman Lietava + +#include "DataFormatsCTP/Digits.h" +#include <iostream> + +using namespace o2::ctp; + +std::ostream& o2::ctp::operator<<(std::ostream& os, const o2::ctp::CTPDigit& d) +{ + os << "CTP Digit: " << d.intRecord << " Input Mask: " << d.CTPInputMask << " Class Mask: " << d.CTPClassMask; + return os; +} + +void CTPDigit::printStream(std::ostream& stream) const +{ + stream << *this << std::endl; +} + +void CTPDigit::setInputMask(gbtword80_t mask) +{ + for (int i = 0; i < CTP_NINPUTS; i++) { + CTPInputMask[i] = mask[i]; + } +} +void CTPDigit::setClassMask(gbtword80_t mask) +{ + for (int i = 0; i < CTP_NCLASSES; i++) { + CTPClassMask[i] = mask[i]; + } +} diff --git a/DataFormats/Detectors/CTP/src/Scalers.cxx b/DataFormats/Detectors/CTP/src/Scalers.cxx new file mode 100644 index 0000000000000..8f6636185557f --- /dev/null +++ b/DataFormats/Detectors/CTP/src/Scalers.cxx @@ -0,0 +1,363 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Scalers.cxx +/// \author Roman Lietava + +#include "DataFormatsCTP/Scalers.h" +#include <iostream> +#include <iomanip> +#include "CommonUtils/StringUtils.h" +#include "FairLogger.h" + +using namespace o2::ctp; + +void CTPScalerRaw::printStream(std::ostream& stream) const +{ + stream << "Class:" << std::setw(2) << classIndex << " RAW"; + stream << " LMB:" << std::setw(10) << lmBefore << " LMA:" << std::setw(10) << lmAfter; + stream << " LOB:" << std::setw(10) << l0Before << " L0A:" << std::setw(10) << l0After; + stream << " L1B:" << std::setw(10) << l1Before << " L1A:" << std::setw(10) << l1After << std::endl; +} +// +void CTPScalerO2::createCTPScalerO2FromRaw(const CTPScalerRaw& raw, const std::array<uint32_t, 6>& overflow) +{ + classIndex = raw.classIndex; + lmBefore = (uint64_t)(raw.lmBefore) + 0xffffffffull * (uint64_t)(overflow[0]); + lmAfter = (uint64_t)(raw.lmAfter) + 0xffffffffull * (uint64_t)(overflow[1]); + l0Before = (uint64_t)(raw.l0Before) + 0xffffffffull * (uint64_t)(overflow[2]); + l0After = (uint64_t)(raw.l0After) + 0xffffffffull * (uint64_t)(overflow[3]); + l1Before = (uint64_t)(raw.l1Before) + 0xffffffffull * (uint64_t)(overflow[4]); + l1After = (uint64_t)(raw.l1After) + 0xffffffffull * (uint64_t)(overflow[5]); + //std::cout << "lmb overflow:" << overflow[0] << " lmb:" << lmBefore << " raw:" << raw.lmBefore << std::endl; +} +void CTPScalerO2::printStream(std::ostream& stream) const +{ + stream << "Class:" << std::setw(2) << classIndex << " O2"; + stream << " LMB:" << std::setw(10) << lmBefore << " LMA:" << std::setw(10) << lmAfter; + stream << " LOB:" << std::setw(10) << l0Before << " L0A:" << std::setw(10) << l0After; + stream << " L1B:" << std::setw(10) << l1Before << " L1A:" << std::setw(10) << l1After << std::endl; +} +void CTPScalerRecordRaw::printStream(std::ostream& stream) const +{ + stream << "Orbit:" << intRecord.orbit << " BC:" << intRecord.bc; + stream << " Seconds:" << seconds << " Microseconds:" << microSeconds << std::endl; + for (auto const& cnts : scalers) { + cnts.printStream(stream); + } +} +void CTPScalerRecordO2::printStream(std::ostream& stream) const +{ + stream << "Orbit:" << intRecord.orbit << " BC:" << intRecord.bc; + stream << " Seconds:" << seconds << " Microseconds:" << microSeconds << std::endl; + for (auto const& cnts : scalers) { + cnts.printStream(stream); + } +} +// +// CTPRunScalers +// +void CTPRunScalers::printStream(std::ostream& stream) const +{ + stream << "CTP Scalers (version:" << mVersion << ") Run:" << mRunNumber << std::endl; + printClasses(stream); + for (auto const& rec : mScalerRecordRaw) { + rec.printStream(stream); + } + stream << "O2 Counters:" << std::endl; + for (auto const& rec : mScalerRecordO2) { + rec.printStream(stream); + } +} +void CTPRunScalers::printClasses(std::ostream& stream) const +{ + stream << "CTP classes:"; + for (int i = 0; i < mClassMask.size(); i++) { + if (mClassMask[i]) { + stream << " " << i; + } + } + stream << std::endl; +} +std::vector<uint32_t> CTPRunScalers::getClassIndexes() const +{ + std::vector<uint32_t> indexes; + for (uint32_t i = 0; i < CTP_NCLASSES; i++) { + if (mClassMask[i]) { + indexes.push_back(i); + } + } + return indexes; +} +int CTPRunScalers::readScalers(const std::string& rawscalers) +{ + LOG(INFO) << "Loading CTP scalers."; + std::istringstream iss(rawscalers); + int ret = 0; + int level = 0; + std::string line; + int nclasses = 0; + int nlines = 0; + while (std::getline(iss, line)) { + o2::utils::Str::trim(line); + if ((ret = processScalerLine(line, level, nclasses)) != 0) { + return ret; + } + nlines++; + } + if (nlines < 4) { + LOG(ERROR) << "Input string seems too small:\n" + << rawscalers; + return 6; + } + if (nclasses != 0) { + LOG(ERROR) << "Wrong number of classes in final record"; + return 6; + } + return 0; +} +int CTPRunScalers::processScalerLine(const std::string& line, int& level, int& nclasses) +{ + //std::cout << "Processing line" << std::endl; + if (line.size() == 0) { + return 0; + } + if (line.at(0) == '#') { + return 0; + } + std::vector<std::string> tokens = o2::utils::Str::tokenize(line, ' '); + size_t ntokens = tokens.size(); + if (ntokens == 0) { + return 0; + } + //std::cout << line << " level in::" << level << std::endl; + // Version + if (level == 0) { + if (ntokens != 1) { + LOG(ERROR) << "Expected version in the first line"; + return 1; + } else { + mVersion = std::stoi(tokens[0]); + level = 1; + return 0; + } + } + // Run Number N Classes [class indexes] + if (level == 1) { + if (ntokens < 3) { + LOG(ERROR) << "Wrong syntax of second line in CTP scalers"; + return 2; + } else { + mRunNumber = std::stol(tokens[0]); + int numofclasses = std::stoi(tokens[1]); + if ((numofclasses + 2) != ntokens) { + LOG(ERROR) << "Wrong syntax of second line in CTP scalers"; + return 3; + } + mClassMask.reset(); + for (int i = 0; i < numofclasses; i++) { + int index = std::stoi(tokens[i + 2]); + mClassMask[index] = 1; + } + level = 2; + nclasses = 0; + return 0; + } + } + // Time stamp: orbit bcid linuxtime + if (level == 2) { + if (ntokens != 4) { + LOG(ERROR) << "Wrong syntax of time stamp line in CTP scalers"; + return 4; + } else { + CTPScalerRecordRaw rec; + rec.intRecord.orbit = std::stol(tokens[0]); + rec.intRecord.bc = std::stol(tokens[1]); + rec.seconds = std::stol(tokens[2]); + rec.microSeconds = std::stol(tokens[3]); + mScalerRecordRaw.push_back(rec); + level = 3; + return 0; + } + } + if (level == 3) { + if (ntokens != 6) { + LOG(ERROR) << "Wrong syntax of counters line in CTP scalers"; + return 5; + } else { + //std::cout << "nclasses:" << nclasses << std::endl; + CTPScalerRaw scaler; + scaler.classIndex = getClassIndexes()[nclasses]; + scaler.lmBefore = std::stol(tokens[0]); + scaler.lmAfter = std::stol(tokens[1]); + scaler.l0Before = std::stol(tokens[2]); + scaler.l0After = std::stol(tokens[3]); + scaler.l1Before = std::stol(tokens[4]); + scaler.l1After = std::stol(tokens[5]); + (mScalerRecordRaw.back()).scalers.push_back(scaler); + nclasses++; + if (nclasses >= mClassMask.count()) { + level = 2; + nclasses = 0; + } + return 0; + } + } + return 0; +} +/// Converts raw 32 bit scalers to O2 64 bit scalers correcting for overflow. +/// Consistency checks done. +int CTPRunScalers::convertRawToO2() +{ + //struct classScalersOverflows {uint32_t overflows[6];}; + overflows_t overflows; + for (uint32_t i = 0; i < mClassMask.size(); i++) { + if (mClassMask[i]) { + overflows[i] = {0, 0, 0, 0, 0, 0}; + } + } + // 1st o2 rec is just copy + CTPScalerRecordO2 o2rec; + copyRawToO2ScalerRecord(mScalerRecordRaw[0], o2rec, overflows); + mScalerRecordO2.push_back(o2rec); + for (uint32_t i = 1; i < mScalerRecordRaw.size(); i++) { + //update overflows + updateOverflows(mScalerRecordRaw[i - 1], mScalerRecordRaw[i], overflows); + // + CTPScalerRecordO2 o2rec; + copyRawToO2ScalerRecord(mScalerRecordRaw[i], o2rec, overflows); + mScalerRecordO2.push_back(o2rec); + // Check consistency + checkConsistency(mScalerRecordO2[i - 1], mScalerRecordO2[i]); + } + return 0; +} +int CTPRunScalers::copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows) +{ + if (rawrec.scalers.size() != (mClassMask.count())) { + LOG(ERROR) << "Inconsistent scaler record size:" << rawrec.scalers.size() << " Expected:" << mClassMask.count(); + return 1; + } + o2rec.scalers.clear(); + o2rec.intRecord = rawrec.intRecord; + o2rec.seconds = rawrec.seconds; + o2rec.microSeconds = rawrec.microSeconds; + for (uint32_t i = 0; i < rawrec.scalers.size(); i++) { + CTPScalerRaw rawscal = rawrec.scalers[i]; + CTPScalerO2 o2scal; + int k = (getClassIndexes())[i]; + o2scal.createCTPScalerO2FromRaw(rawscal, classesoverflows[k]); + o2rec.scalers.push_back(o2scal); + } + return 0; +} +int CTPRunScalers::checkConsistency(const CTPScalerO2& scal0, const CTPScalerO2& scal1) const +{ + int ret = 0; + // Scaler should never decrease + if (scal0.lmBefore > scal1.lmBefore) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmBefore 0:" << scal0.lmBefore << " lmBefore :" << scal1.lmBefore; + ret++; + } + if (scal0.l0Before > scal1.l0Before) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmBefore 0:" << scal0.l0Before << " lmBefore :" << scal1.l0Before; + ret++; + } + if (scal0.l1Before > scal1.l1Before) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmBefore 0:" << scal0.l1Before << " lmBefore :" << scal1.l1Before; + ret++; + } + if (scal0.lmAfter > scal1.lmAfter) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmAfter 0:" << scal0.lmAfter << " lmAfter :" << scal1.lmAfter; + ret++; + } + if (scal0.l0After > scal1.l0After) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmAfter 0:" << scal0.l0After << " lmAfter :" << scal1.l0After; + ret++; + } + if (scal0.l1After > scal1.l1After) { + LOG(ERROR) << "Scaler decreasing: Class:" << scal0.classIndex << " lmAfter 0:" << scal0.l1After << " lmAfter :" << scal1.l1After; + ret++; + } + // + // LMB >= LMA >= L0B >= L0A >= L1B >= L1A: 5 relations + // + if ((scal1.lmAfter - scal0.lmAfter) > (scal1.lmBefore - scal0.lmBefore)) { + LOG(ERROR) << "LMA > LMB eerror"; + ret++; + } + if ((scal1.l0After - scal0.l0After) > (scal1.l0Before - scal0.l0Before)) { + LOG(ERROR) << "L0A > L0B error"; + ret++; + } + if ((scal1.l1After - scal0.l1After) > (scal1.l1Before - scal0.l1Before)) { + LOG(ERROR) << "L1A > L1B error"; + ret++; + } + if ((scal1.l0Before - scal0.l0Before) > (scal1.lmAfter - scal0.lmAfter)) { + LOG(ERROR) << "L0B > LMA error."; + ret++; + } + if ((scal1.l1Before - scal0.l1Before) > (scal1.l0After - scal0.l0After)) { + LOG(ERROR) << "L1B > L0A Before error."; + ret++; + } + // + if (ret) { + scal0.printStream(std::cout); + scal1.printStream(std::cout); + } + return ret; +} +int CTPRunScalers::updateOverflows(const CTPScalerRecordRaw& rec0, const CTPScalerRecordRaw& rec1, overflows_t& classesoverflows) const +{ + if (rec1.scalers.size() != mClassMask.count()) { + LOG(ERROR) << "Inconsistent scaler record size:" << rec1.scalers.size() << " Expected:" << mClassMask.count(); + return 1; + } + for (int i = 0; i < rec0.scalers.size(); i++) { + int k = (getClassIndexes())[i]; + updateOverflows(rec0.scalers[i], rec1.scalers[i], classesoverflows[k]); + } + return 0; +} +int CTPRunScalers::checkConsistency(const CTPScalerRecordO2& rec0, const CTPScalerRecordO2& rec1) const +{ + for (int i = 0; i < rec0.scalers.size(); i++) { + checkConsistency(rec0.scalers[i], rec1.scalers[i]); + } + return 0; +} +int CTPRunScalers::updateOverflows(const CTPScalerRaw& scal0, const CTPScalerRaw& scal1, std::array<uint32_t, 6>& overflow) const +{ + if (scal0.lmBefore > scal1.lmBefore) { + overflow[0] += 1; + } + if (scal0.lmAfter > scal1.lmAfter) { + overflow[1] += 1; + } + if (scal0.l0Before > scal1.l0Before) { + overflow[2] += 1; + } + if (scal0.l0After > scal1.l0After) { + overflow[3] += 1; + } + if (scal0.l1Before > scal1.l1Before) { + overflow[4] += 1; + } + if (scal0.l1After > scal1.l1After) { + overflow[5] += 1; + } + //std::cout << "lmB0:" << scal0.lmBefore << " lmB1:" << scal1.lmBefore << " over:" << overflow[0] << std::endl; + //for(int i = 0; i < 6; i++)std::cout << overflow[i] << " "; + //std::cout << std::endl; + return 0; +} diff --git a/DataFormats/Detectors/Common/CMakeLists.txt b/DataFormats/Detectors/Common/CMakeLists.txt index f4a7b7d029a0a..90ff8ac9b021e 100644 --- a/DataFormats/Detectors/Common/CMakeLists.txt +++ b/DataFormats/Detectors/Common/CMakeLists.txt @@ -1,22 +1,26 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsCommonDataFormats SOURCES src/DetID.cxx src/AlignParam.cxx src/DetMatrixCache.cxx src/NameConf.cxx src/EncodedBlocks.cxx src/CTFHeader.cxx + src/CTFDictHeader.cxx + src/FileMetaData.cxx PUBLIC_LINK_LIBRARIES ROOT::Core ROOT::Geom O2::GPUCommon + O2::GPUUtils O2::MathUtils O2::FrameworkLogger O2::Headers @@ -31,8 +35,15 @@ o2_target_root_dictionary( include/DetectorsCommonDataFormats/NameConf.h include/DetectorsCommonDataFormats/EncodedBlocks.h include/DetectorsCommonDataFormats/CTFHeader.h + include/DetectorsCommonDataFormats/CTFDictHeader.h include/DetectorsCommonDataFormats/DetMatrixCache.h) +configure_file(UpgradesStatus.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/DetectorsCommonDataFormats/UpgradesStatus.h) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/DetectorsCommonDataFormats/UpgradesStatus.h + DESTINATION include/DetectorsCommonDataFormats) + o2_add_test(DetID SOURCES test/testDetID.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats diff --git a/DataFormats/Detectors/Common/UpgradesStatus.h.in b/DataFormats/Detectors/Common/UpgradesStatus.h.in new file mode 100644 index 0000000000000..94e8070c72409 --- /dev/null +++ b/DataFormats/Detectors/Common/UpgradesStatus.h.in @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_UPGRADES_STATUS_H +#define O2_UPGRADES_STATUS_H + +// cmake-generated define to make installed headers aware of what was used at build-time +#cmakedefine ENABLE_UPGRADES + +#endif diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h index 54231c02be77b..a6939fc7b430d 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,10 @@ #ifndef ALICEO2_BASE_ALIGNPARAM_H_ #define ALICEO2_BASE_ALIGNPARAM_H_ -#include <TGeoMatrix.h> -#include <TNamed.h> +class TGeoMatrix; +class TGeoHMatrix; + +#include <string> namespace o2 { @@ -25,47 +28,48 @@ namespace detectors { /// Base class for alignment parameters, containing global delta of rotation and translation /// For the detail of alignment framework check http://alice-offline.web.cern.ch/Activities/Alignment -/// Since some detectors may foresee to derive from this class to implement more complex alignment -/// objects (e.g. staves sagging for ITS), we define this class virtual and it should be stored in -/// the polymorphic container -class AlignParam : public TNamed + +class AlignParam { public: AlignParam() = default; - ~AlignParam() override = default; + ~AlignParam() = default; AlignParam(const char* symname, int algID, // volume symbolic name and its alignable ID double x, double y, double z, // delta translation double psi, double theta, double phi, // delta rotation - bool global); // global (preferable) or local delta definition + bool global = true); // global (preferable) or local delta definition /// return symbolic name of the volume - const char* getSymName() const { return GetName(); } - /// paramater's getters + const std::string& getSymName() const { return mSymName; } + /// iparamater's getters double getPhi() const { return mPhi; } double getPsi() const { return mPsi; } double getTheta() const { return mTheta; } double getX() const { return mX; } double getY() const { return mY; } double getZ() const { return mZ; } - /// apply object to geoemetry with optional check for the overlaps - bool applyToGeometry(bool ovlpcheck = false, double ovlToler = 1e-3); + + /// apply object to geoemetry + bool applyToGeometry() const; /// extract global delta matrix - virtual TGeoHMatrix createMatrix() const; + TGeoHMatrix createMatrix() const; /// extract local delta matrix - virtual bool createLocalMatrix(TGeoHMatrix& m) const; + bool createLocalMatrix(TGeoHMatrix& m) const; /// set symbolic name of the volume - void setSymName(const char* m) { return SetName(m); } + void setSymName(const char* m) { mSymName = m; } + /// return alignable entry ID int getAlignableID() const { return mAlignableID; } + /// set alignable entry ID void setAlignableID(int id) { mAlignableID = id; } - /// ================ methods for direct setting of global delta params + /// ================ methods for direct setting of delta params /// set parameters of global delta - void setParams(double x, double y, double z, double psi, double theta, double phi); + void setGlobalParams(double x, double y, double z, double psi, double theta, double phi); /// set global delta rotations angles in radian void setRotation(double psi, double theta, double phi); @@ -74,7 +78,7 @@ class AlignParam : public TNamed void setTranslation(double x, double y, double z); /// set params from the matrix of global delta - void setParams(const TGeoMatrix& m); + void setGlobalParams(const TGeoMatrix& m); /// set translation from the matrix of global delta void setTranslation(const TGeoMatrix& m); @@ -102,19 +106,19 @@ class AlignParam : public TNamed /// set the global delta rotation from rotation part of local delta matrix bool setLocalRotation(const TGeoMatrix& m); - /// method for sorting according to affected object depth - bool IsSortable() const override { return true; } - int Compare(const TObject* obj) const override; int getLevel() const; - void Print(const Option_t* opt = "") const override; + void print() const; protected: - bool matrixToAngles(const double* rot, double& psi, double& theta, double& phi); + bool matrixToAngles(const double* rot, double& psi, double& theta, double& phi) const; + void anglesToMatrix(double psi, double theta, double phi, double* rot) const; void setMatrixRotation(double psi, double theta, double phi, TGeoHMatrix& dest) const; void setMatrixTranslation(double x, double y, double z, TGeoHMatrix& dest) const; private: + std::string mSymName{}; + int mAlignableID = -1; /// alignable ID (set for sensors only) double mX = 0.; ///< X translation of global delta @@ -125,107 +129,10 @@ class AlignParam : public TNamed double mTheta = 0.; ///< "roll" : Euler angle of rotation around Y axis after 1st rotation (radians) double mPhi = 0.; ///< "yaw" : Euler angle of rotation around Z axis (radians) - ClassDefOverride(AlignParam, 1); + ClassDefNV(AlignParam, 1); }; -//_____________________________________________________________________________ -inline void AlignParam::setParams(double x, double y, double z, double psi, double theta, double phi) -{ - /// set parameters of global delta - setTranslation(x, y, z); - setRotation(psi, theta, phi); -} - -//_____________________________________________________________________________ -inline void AlignParam::setRotation(double psi, double theta, double phi) -{ - /// set global delta rotations angles in radian - mPsi = psi; - mTheta = theta; - mPhi = phi; -} - -//_____________________________________________________________________________ -inline void AlignParam::setTranslation(double x, double y, double z) -{ - /// set global delta displacements in cm - mX = x; - mY = y; - mZ = z; -} - -//_____________________________________________________________________________ -inline void AlignParam::setParams(const TGeoMatrix& m) -{ - /// set params from the matrix of global delta - setTranslation(m); - setRotation(m); -} - -//___________________________________________________ -inline void AlignParam::setMatrixTranslation(double x, double y, double z, TGeoHMatrix& dest) const -{ - /// apply translation to matrix - double tra[3] = {x, y, z}; - dest.SetTranslation(tra); -} - -//_____________________________________________________________________________ -inline bool AlignParam::setLocalTranslation(double x, double y, double z) -{ - /// Set the global delta transformation by passing the three shifts giving - /// the translation in the local reference system of the alignable - /// volume (known by TGeo geometry). - /// In case that the TGeo was not initialized or not closed, - /// returns false and the object parameters are not set. - - TGeoHMatrix m; - Double_t tr[3] = {x, y, z}; - m.SetTranslation(tr); - - return setLocalParams(m); } - -//_____________________________________________________________________________ -inline bool AlignParam::setLocalTranslation(const TGeoMatrix& m) -{ - /// Set the global delta transformation by passing the matrix of - /// the local delta transformation and taking its translational part - /// In case that the TGeo was not initialized or not closed, - /// returns false and the object parameters are not set. - - TGeoHMatrix mtr; - mtr.SetTranslation(m.GetTranslation()); - return setLocalParams(mtr); -} - -//_____________________________________________________________________________ -inline bool AlignParam::setLocalRotation(double psi, double theta, double phi) -{ - /// Set the global delta transformation by passing the three angles giving - /// the rotation in the local reference system of the alignable - /// volume (known by TGeo geometry). - /// In case that the TGeo was not initialized or not closed, - /// returns false and the object parameters are not set. - - TGeoHMatrix m; - setMatrixRotation(psi, theta, phi, m); - return setLocalParams(m); -} - -//_____________________________________________________________________________ -inline bool AlignParam::setLocalRotation(const TGeoMatrix& m) -{ - /// Set the global delta transformation by passing the matrix of - /// the local delta transformation and taking its rotational part - /// In case that the TGeo was not initialized or not closed, - /// returns false and the object parameters are not set. - - TGeoHMatrix rotm; - rotm.SetRotation(m.GetRotationMatrix()); - return setLocalParams(rotm); } -} // namespace detectors -} // namespace o2 #endif diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFDictHeader.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFDictHeader.h new file mode 100644 index 0000000000000..bff50fab5b8f2 --- /dev/null +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFDictHeader.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFDictHeader.h +/// \brief Header: timestamps and format version for detector CTF dictionary +/// \author ruben.shahoyan@cern.ch + +#ifndef _ALICEO2_CTFDICTHEADER_H +#define _ALICEO2_CTFDICTHEADER_H + +#include <Rtypes.h> +#include <string> + +namespace o2 +{ +namespace ctf +{ + +/// Detector header base +struct CTFDictHeader { + uint32_t dictTimeStamp = 0; // dictionary creation time (seconds since epoch) / hash + uint8_t majorVersion = 1; + uint8_t minorVersion = 0; + + bool isValidDictTimeStamp() const { return dictTimeStamp != 0; } + bool operator==(const CTFDictHeader& o) const + { + return dictTimeStamp == o.dictTimeStamp && majorVersion == o.majorVersion && minorVersion == o.minorVersion; + } + bool operator!=(const CTFDictHeader& o) const + { + return dictTimeStamp != o.dictTimeStamp || majorVersion != o.majorVersion || minorVersion != o.minorVersion; + } + std::string asString() const; + + ClassDefNV(CTFDictHeader, 1); +}; + +} // namespace ctf +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFHeader.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFHeader.h index a9aed41b83596..385ef667309b1 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFHeader.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/CTFHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ struct CTFHeader { std::string describe() const; void print() const; - ClassDefNV(CTFHeader, 1) + ClassDefNV(CTFHeader, 2) }; std::ostream& operator<<(std::ostream& stream, const CTFHeader& c); diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h index 39c915b270ec4..f88871bebb0ae 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,12 @@ #ifndef O2_BASE_DETID_ #define O2_BASE_DETID_ -#include <Rtypes.h> +#include "GPUCommonRtypes.h" +#include "GPUCommonBitSet.h" +#include "MathUtils/Utils.h" +#include "DetectorsCommonDataFormats/UpgradesStatus.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include "Headers/DataHeader.h" #include <array> #include <bitset> #include <cassert> @@ -35,11 +41,13 @@ #include <string_view> #include <string> #include <type_traits> -#include "MathUtils/Utils.h" -#include "Headers/DataHeader.h" +#endif namespace o2 { +namespace header +{ +} namespace detectors { @@ -50,7 +58,7 @@ class DetID { public: /// Detector identifiers: continuous, starting from 0 - typedef std::int32_t ID; + typedef int ID; static constexpr ID ITS = 0; static constexpr ID TPC = 1; @@ -68,100 +76,134 @@ class DetID static constexpr ID FV0 = 13; static constexpr ID FDD = 14; static constexpr ID ACO = 15; + static constexpr ID CTP = 16; #ifdef ENABLE_UPGRADES - static constexpr ID IT3 = 16; - static constexpr ID IT4 = 17; - static constexpr ID Last = IT4; + static constexpr ID IT3 = 17; + static constexpr ID TRK = 18; + static constexpr ID FT3 = 19; + static constexpr ID Last = FT3; #else - static constexpr ID Last = ACO; ///< if extra detectors added, update this !!! + static constexpr ID Last = CTP; ///< if extra detectors added, update this !!! #endif static constexpr ID First = ITS; static constexpr int nDetectors = Last + 1; ///< number of defined detectors + typedef o2::gpu::gpustd::bitset<32> mask_t; + static_assert(nDetectors <= 32, "bitset<32> insufficient"); - static constexpr std::string_view NONE{"none"}; ///< keywork for no-detector + static constexpr mask_t FullMask = (0x1u << nDetectors) - 1; - typedef std::bitset<nDetectors> mask_t; +#ifndef GPUCA_GPUCODE_DEVICE + static constexpr std::string_view NONE{"none"}; ///< keywork for no-detector + static constexpr std::string_view ALL{"all"}; ///< keywork for all detectors +#endif // GPUCA_GPUCODE_DEVICE - DetID(ID id) : mID(id) {} + GPUdi() DetID(ID id) : mID(id) + { + } DetID(const char* name); - DetID(const DetID& src) = default; - DetID& operator=(const DetID& src) = default; + GPUdDefault() DetID(const DetID& src) = default; + GPUdDefault() DetID& operator=(const DetID& src) = default; + // we need default c-tor only for root persistency, code must use c-tor with argument + DetID() : mID(First) {} /// get derector id - ID getID() const { return mID; } - /// get detector mask - mask_t getMask() const { return getMask(mID); } + GPUdi() ID getID() const { return mID; } /// get detector mask - o2h::DataOrigin getDataOrigin() const { return getDataOrigin(mID); } + GPUdi() mask_t getMask() const { return getMask(mID); } +#ifndef GPUCA_GPUCODE_DEVICE + /// get detector origin + GPUdi() o2h::DataOrigin getDataOrigin() const { return getDataOrigin(mID); } /// get detector name const char* getName() const { return getName(mID); } +#endif // GPUCA_GPUCODE_DEVICE /// conversion operator to int - operator int() const { return static_cast<int>(mID); } + GPUdi() operator int() const { return static_cast<int>(mID); } // ---------------- general static methods ----------------- /// get number of defined detectors - static constexpr int getNDetectors() { return nDetectors; } + GPUdi() static constexpr int getNDetectors() { return nDetectors; } + // detector ID to mask conversion + GPUd() static constexpr mask_t getMask(ID id); + +#ifndef GPUCA_GPUCODE_DEVICE /// names of defined detectors static constexpr const char* getName(ID id) { return sDetNames[id]; } - // detector ID to mask conversion - static constexpr mask_t getMask(ID id) { return sMasks[id]; } // detector ID to DataOrigin conversions static constexpr o2h::DataOrigin getDataOrigin(ID id) { return sOrigins[id]; } // detector masks from any non-alpha-num delimiter-separated list (empty if NONE is supplied) static mask_t getMask(const std::string_view detList); - static std::string getNames(mask_t mask); + static std::string getNames(mask_t mask, char delimiter = ','); - // we need default c-tor only for root persistency, code must use c-tor with argument - DetID() : mID(First) {} + inline static constexpr int nameToID(char const* name, int id = First) + { + return id > Last ? -1 : sameStr(name, sDetNames[id]) ? id + : nameToID(name, id + 1); + } - private: - // are 2 strings equal ? (trick from Giulio) - inline static constexpr bool sameStr(char const* x, char const* y) +#endif // GPUCA_GPUCODE_DEVICE + + static bool upgradesEnabled() { - return !*x && !*y ? true : /* default */ (*x == *y && sameStr(x + 1, y + 1)); +#ifdef ENABLE_UPGRADES + return true; +#else + return false; +#endif } - inline static constexpr int nameToID(char const* name, int id) + private: + // are 2 strings equal ? (trick from Giulio) + GPUdi() static constexpr bool sameStr(char const* x, char const* y) { - return id > Last ? id : sameStr(name, sDetNames[id]) ? id : nameToID(name, id + 1); + return !*x && !*y ? true : /* default */ (*x == *y && sameStr(x + 1, y + 1)); } ID mID = First; ///< detector ID +#ifndef GPUCA_GPUCODE_DEVICE + // detector names, will be defined in DataSources static constexpr const char* sDetNames[nDetectors + 1] = ///< defined detector names #ifdef ENABLE_UPGRADES - {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "ACO", "IT3", "IT4", nullptr}; + {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "ACO", "CTP", "IT3", "TRK", "FT3", nullptr}; #else - {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "ACO", nullptr}; + {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "ACO", "CTP", nullptr}; #endif - // detector names, will be defined in DataSources - static constexpr std::array<mask_t, nDetectors> sMasks = ///< detectot masks - {math_utils::bit2Mask(ITS), math_utils::bit2Mask(TPC), math_utils::bit2Mask(TRD), math_utils::bit2Mask(TOF), math_utils::bit2Mask(PHS), - math_utils::bit2Mask(CPV), math_utils::bit2Mask(EMC), math_utils::bit2Mask(HMP), math_utils::bit2Mask(MFT), math_utils::bit2Mask(MCH), - math_utils::bit2Mask(MID), math_utils::bit2Mask(ZDC), math_utils::bit2Mask(FT0), math_utils::bit2Mask(FV0), math_utils::bit2Mask(FDD), - math_utils::bit2Mask(ACO) -#ifdef ENABLE_UPGRADES - , - math_utils::bit2Mask(IT3), math_utils::bit2Mask(IT4) -#endif - }; static constexpr std::array<o2h::DataOrigin, nDetectors> sOrigins = ///< detector data origins {o2h::gDataOriginITS, o2h::gDataOriginTPC, o2h::gDataOriginTRD, o2h::gDataOriginTOF, o2h::gDataOriginPHS, o2h::gDataOriginCPV, o2h::gDataOriginEMC, o2h::gDataOriginHMP, o2h::gDataOriginMFT, o2h::gDataOriginMCH, - o2h::gDataOriginMID, o2h::gDataOriginZDC, o2h::gDataOriginFT0, o2h::gDataOriginFV0, o2h::gDataOriginFDD, o2h::gDataOriginACO + o2h::gDataOriginMID, o2h::gDataOriginZDC, o2h::gDataOriginFT0, o2h::gDataOriginFV0, o2h::gDataOriginFDD, + o2h::gDataOriginACO, o2h::gDataOriginCTP #ifdef ENABLE_UPGRADES , - o2h::gDataOriginIT3, o2h::gDataOriginIT4 + o2h::gDataOriginIT3, o2h::gDataOriginTRK, o2h::gDataOriginFT3 #endif }; +#endif // GPUCA_GPUCODE_DEVICE + + ClassDefNV(DetID, 3); +}; - ClassDefNV(DetID, 1); +namespace detid_internal +{ +// static constexpr array class members not possible on the GPU, thus we use this trick. +GPUconstexpr() DetID::mask_t sMasks[DetID::nDetectors] = ///< detectot masks + {DetID::mask_t(math_utils::bit2Mask(DetID::ITS)), DetID::mask_t(math_utils::bit2Mask(DetID::TPC)), DetID::mask_t(math_utils::bit2Mask(DetID::TRD)), DetID::mask_t(math_utils::bit2Mask(DetID::TOF)), DetID::mask_t(math_utils::bit2Mask(DetID::PHS)), + DetID::mask_t(math_utils::bit2Mask(DetID::CPV)), DetID::mask_t(math_utils::bit2Mask(DetID::EMC)), DetID::mask_t(math_utils::bit2Mask(DetID::HMP)), DetID::mask_t(math_utils::bit2Mask(DetID::MFT)), DetID::mask_t(math_utils::bit2Mask(DetID::MCH)), + DetID::mask_t(math_utils::bit2Mask(DetID::MID)), DetID::mask_t(math_utils::bit2Mask(DetID::ZDC)), DetID::mask_t(math_utils::bit2Mask(DetID::FT0)), DetID::mask_t(math_utils::bit2Mask(DetID::FV0)), DetID::mask_t(math_utils::bit2Mask(DetID::FDD)), + DetID::mask_t(math_utils::bit2Mask(DetID::ACO)), DetID::mask_t(math_utils::bit2Mask(DetID::CTP)) +#ifdef ENABLE_UPGRADES + , + DetID::mask_t(math_utils::bit2Mask(DetID::IT3)), DetID::mask_t(math_utils::bit2Mask(DetID::TRK)), DetID::mask_t(math_utils::bit2Mask(DetID::FT3)) +#endif }; +} // namespace detid_internal + +GPUdi() constexpr DetID::mask_t DetID::getMask(ID id) { return detid_internal::sMasks[id]; } } // namespace detectors } // namespace o2 diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetMatrixCache.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetMatrixCache.h index 38b10f1febcf3..6558572a46fe9 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetMatrixCache.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetMatrixCache.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index db9e0666e2866..b7b726b91ee9d 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,18 +16,40 @@ #ifndef ALICEO2_ENCODED_BLOCKS_H #define ALICEO2_ENCODED_BLOCKS_H - +#undef NDEBUG +#include <cassert> #include <type_traits> #include <Rtypes.h> #include "rANS/rans.h" +#include "rANS/utils.h" #include "TTree.h" #include "CommonUtils/StringUtils.h" #include "Framework/Logger.h" +#include "DetectorsCommonDataFormats/CTFDictHeader.h" namespace o2 { namespace ctf { + +namespace detail +{ + +template <class, class Enable = void> +struct is_iterator : std::false_type { +}; + +template <class T> +struct is_iterator<T, std::enable_if_t< + std::is_base_of_v<std::input_iterator_tag, typename std::iterator_traits<T>::iterator_category> || + std::is_same_v<std::output_iterator_tag, typename std::iterator_traits<T>::iterator_category>>> + : std::true_type { +}; + +template <class T> +inline constexpr bool is_iterator_v = is_iterator<T>::value; +} // namespace detail + using namespace o2::rans; constexpr size_t Alignment = 16; @@ -50,6 +73,23 @@ inline T* relocatePointer(const char* oldBase, char* newBase, const T* ptr) return (ptr != nullptr) ? reinterpret_cast<T*>(newBase + (reinterpret_cast<const char*>(ptr) - oldBase)) : nullptr; } +template <typename source_T, typename dest_T, std::enable_if_t<(sizeof(dest_T) >= sizeof(source_T)), bool> = true> +inline size_t calculateNDestTElements(size_t sourceElems) noexcept +{ + const size_t sizeOfSourceArray = sourceElems * sizeof(source_T); + return sizeOfSourceArray / sizeof(dest_T) + (sizeOfSourceArray % sizeof(dest_T) != 0); +}; + +template <typename source_T, typename dest_T, std::enable_if_t<(sizeof(dest_T) >= sizeof(source_T)), bool> = true> +inline size_t calculatePaddedSize(size_t nElems) noexcept +{ + const size_t sizeOfSourceT = sizeof(source_T); + const size_t sizeOfDestT = sizeof(dest_T); + + // this is equivalent to (sizeOfSourceT / sizeOfDestT) * std::ceil(sizeOfSourceArray/ sizeOfDestT) + return (sizeOfDestT / sizeOfSourceT) * calculateNDestTElements<source_T, dest_T>(nElems); +}; + ///>>======================== Auxiliary classes =======================>> struct ANSHeader { @@ -129,7 +169,8 @@ struct Block { W* payload = nullptr; //[nStored]; inline const W* getDict() const { return nDict ? payload : nullptr; } - inline const W* getData() const { return payload ? (payload + nDict) : nullptr; } + inline const W* getData() const { return nData ? (payload + nDict) : nullptr; } + inline const W* getDataPointer() const { return payload ? (payload + nDict) : nullptr; } // needed when nData is not set yet inline const W* getLiterals() const { return nLiterals ? (payload + nDict + nData) : nullptr; } inline W* getCreatePayload() { return payload ? payload : (registry ? (payload = reinterpret_cast<W*>(registry->getFreeBlockStart())) : nullptr); } @@ -352,8 +393,8 @@ class EncodedBlocks size_t getFreeSize() const { return mRegistry.getFreeSize(); } /// expand the storage to new size in bytes - template <typename VB> - static auto expand(VB& buffer, size_t newsizeBytes); + template <typename buffer_T> + static auto expand(buffer_T& buffer, size_t newsizeBytes); /// copy itself to flat buffer created on the fly from the vector template <typename V> @@ -363,7 +404,7 @@ class EncodedBlocks void copyToFlat(void* base) { fillFlatCopy(create(base, estimateSize())); } /// attach to tree - void appendToTree(TTree& tree, const std::string& name) const; + size_t appendToTree(TTree& tree, const std::string& name) const; /// read from tree to non-flat object void readFromTree(TTree& tree, const std::string& name, int ev = 0); @@ -373,23 +414,23 @@ class EncodedBlocks static void readFromTree(VD& vec, TTree& tree, const std::string& name, int ev = 0); /// encode vector src to bloc at provided slot - template <typename VE, typename VB> - inline void encode(const VE& src, int slot, uint8_t probabilityBits, Metadata::OptStore opt, VB* buffer = nullptr, const void* encoderExt = nullptr) + template <typename VE, typename buffer_T> + inline void encode(const VE& src, int slot, uint8_t symbolTablePrecision, Metadata::OptStore opt, buffer_T* buffer = nullptr, const void* encoderExt = nullptr) { - encode(&(*src.begin()), &(*src.end()), slot, probabilityBits, opt, buffer, encoderExt); + encode(std::begin(src), std::end(src), slot, symbolTablePrecision, opt, buffer, encoderExt); } /// encode vector src to bloc at provided slot - template <typename S_IT, typename VB> - void encode(const S_IT srcBegin, const S_IT srcEnd, int slot, uint8_t probabilityBits, Metadata::OptStore opt, VB* buffer = nullptr, const void* encoderExt = nullptr); + template <typename input_IT, typename buffer_T> + void encode(const input_IT srcBegin, const input_IT srcEnd, int slot, uint8_t symbolTablePrecision, Metadata::OptStore opt, buffer_T* buffer = nullptr, const void* encoderExt = nullptr); /// decode block at provided slot to destination vector (will be resized as needed) - template <typename VD> - void decode(VD& dest, int slot, const void* decoderExt = nullptr) const; + template <class container_T, class container_IT = typename container_T::iterator> + void decode(container_T& dest, int slot, const void* decoderExt = nullptr) const; /// decode block at provided slot to destination pointer, the needed space assumed to be available - template <typename D> - void decode(D* dest, int slot, const void* decoderExt = nullptr) const; + template <typename D_IT, std::enable_if_t<detail::is_iterator_v<D_IT>, bool> = true> + void decode(D_IT dest, int slot, const void* decoderExt = nullptr) const; /// create a special EncodedBlocks containing only dictionaries made from provided vector of frequency tables static std::vector<char> createDictionaryBlocks(const std::vector<o2::rans::FrequencyTable>& vfreq, const std::vector<Metadata>& prbits); @@ -427,7 +468,7 @@ class EncodedBlocks /// add and fill single branch template <typename D> - static void fillTreeBranch(TTree& tree, const std::string& brname, D& dt, int compLevel, int splitLevel = 99); + static size_t fillTreeBranch(TTree& tree, const std::string& brname, D& dt, int compLevel, int splitLevel = 99); /// read single branch template <typename D> @@ -441,9 +482,9 @@ class EncodedBlocks template <typename H, int N, typename W> void EncodedBlocks<H, N, W>::readFromTree(TTree& tree, const std::string& name, int ev) { - readTreeBranch(tree, o2::utils::concat_string(name, "_wrapper."), *this, ev); + readTreeBranch(tree, o2::utils::Str::concat_string(name, "_wrapper."), *this, ev); for (int i = 0; i < N; i++) { - readTreeBranch(tree, o2::utils::concat_string(name, "_block.", std::to_string(i), "."), mBlocks[i]); + readTreeBranch(tree, o2::utils::Str::concat_string(name, "_block.", std::to_string(i), "."), mBlocks[i], ev); } } @@ -454,11 +495,15 @@ template <typename VD> void EncodedBlocks<H, N, W>::readFromTree(VD& vec, TTree& tree, const std::string& name, int ev) { auto tmp = create(vec); - readTreeBranch(tree, o2::utils::concat_string(name, "_wrapper."), *tmp, ev); + readTreeBranch(tree, o2::utils::Str::concat_string(name, "_wrapper."), *tmp, ev); tmp = tmp->expand(vec, tmp->estimateSizeFromMetadata()); + const auto& meta = tmp->getMetadata(); for (int i = 0; i < N; i++) { Block<W> bl; - readTreeBranch(tree, o2::utils::concat_string(name, "_block.", std::to_string(i), "."), bl); + readTreeBranch(tree, o2::utils::Str::concat_string(name, "_block.", std::to_string(i), "."), bl, ev); + assert(meta[i].nDictWords == bl.getNDict()); + assert(meta[i].nDataWords == bl.getNData()); + assert(meta[i].nLiteralWords == bl.getNLiterals()); tmp->mBlocks[i].store(bl.getNDict(), bl.getNData(), bl.getNLiterals(), bl.getDict(), bl.getData(), bl.getLiterals()); } } @@ -466,14 +511,16 @@ void EncodedBlocks<H, N, W>::readFromTree(VD& vec, TTree& tree, const std::strin ///_____________________________________________________________________________ /// attach to tree template <typename H, int N, typename W> -void EncodedBlocks<H, N, W>::appendToTree(TTree& tree, const std::string& name) const +size_t EncodedBlocks<H, N, W>::appendToTree(TTree& tree, const std::string& name) const { - fillTreeBranch(tree, o2::utils::concat_string(name, "_wrapper."), const_cast<base&>(*this), WrappersCompressionLevel, WrappersSplitLevel); + long s = 0; + s += fillTreeBranch(tree, o2::utils::Str::concat_string(name, "_wrapper."), const_cast<base&>(*this), WrappersCompressionLevel, WrappersSplitLevel); for (int i = 0; i < N; i++) { int compression = mMetadata[i].opt == Metadata::OptStore::ROOTCompression ? 1 : 0; - fillTreeBranch(tree, o2::utils::concat_string(name, "_block.", std::to_string(i), "."), const_cast<Block<W>&>(mBlocks[i]), compression); + s += fillTreeBranch(tree, o2::utils::Str::concat_string(name, "_block.", std::to_string(i), "."), const_cast<Block<W>&>(mBlocks[i]), compression); } tree.SetEntries(tree.GetEntries() + 1); + return s; } ///_____________________________________________________________________________ @@ -494,11 +541,14 @@ inline void EncodedBlocks<H, N, W>::readTreeBranch(TTree& tree, const std::strin /// add and fill single branch template <typename H, int N, typename W> template <typename D> -inline void EncodedBlocks<H, N, W>::fillTreeBranch(TTree& tree, const std::string& brname, D& dt, int compLevel, int splitLevel) +inline size_t EncodedBlocks<H, N, W>::fillTreeBranch(TTree& tree, const std::string& brname, D& dt, int compLevel, int splitLevel) { - auto* br = tree.Branch(brname.c_str(), &dt, 512, splitLevel); - br->SetCompressionLevel(compLevel); - br->Fill(); + auto* br = tree.GetBranch(brname.c_str()); + if (!br) { + br = tree.Branch(brname.c_str(), &dt, 512, splitLevel); + br->SetCompressionLevel(compLevel); + } + return br->Fill(); } ///_____________________________________________________________________________ @@ -556,10 +606,9 @@ size_t EncodedBlocks<H, N, W>::estimateSizeFromMetadata() const ///_____________________________________________________________________________ /// expand the storage to new size in bytes template <typename H, int N, typename W> -template <typename VB> -auto EncodedBlocks<H, N, W>::expand(VB& buffer, size_t newsizeBytes) +template <typename buffer_T> +auto EncodedBlocks<H, N, W>::expand(buffer_T& buffer, size_t newsizeBytes) { - auto buftypesize = sizeof(typename std::remove_reference<decltype(buffer)>::type::value_type); auto* oldHead = get(buffer.data())->mRegistry.head; buffer.resize(alignSize(newsizeBytes) / buftypesize); @@ -666,19 +715,19 @@ void EncodedBlocks<H, N, W>::print(const std::string& prefix) const ///_____________________________________________________________________________ template <typename H, int N, typename W> -template <typename VD> -inline void EncodedBlocks<H, N, W>::decode(VD& dest, // destination container +template <class container_T, class container_IT> +inline void EncodedBlocks<H, N, W>::decode(container_T& dest, // destination container int slot, // slot of the block to decode const void* decoderExt) const // optional externally provided decoder { dest.resize(mMetadata[slot].messageLength); // allocate output buffer - decode(dest.data(), slot, decoderExt); + decode(std::begin(dest), slot, decoderExt); } ///_____________________________________________________________________________ template <typename H, int N, typename W> -template <typename D> -void EncodedBlocks<H, N, W>::decode(D* dest, // destination pointer +template <typename D_IT, std::enable_if_t<detail::is_iterator_v<D_IT>, bool>> +void EncodedBlocks<H, N, W>::decode(D_IT dest, // iterator to destination int slot, // slot of the block to decode const void* decoderExt) const // optional externally provided decoder { @@ -686,6 +735,8 @@ void EncodedBlocks<H, N, W>::decode(D* dest, // destination const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; + using dest_t = typename std::iterator_traits<D_IT>::value_type; + // decode if (block.getNStored()) { if (md.opt == Metadata::OptStore::EENCODE) { @@ -693,12 +744,12 @@ void EncodedBlocks<H, N, W>::decode(D* dest, // destination LOG(ERROR) << "Dictionaty is not saved for slot " << slot << " and no external decoder is provided"; throw std::runtime_error("Dictionary is not saved and no external decoder provided"); } - const o2::rans::LiteralDecoder64<D>* decoder = reinterpret_cast<const o2::rans::LiteralDecoder64<D>*>(decoderExt); - std::unique_ptr<o2::rans::LiteralDecoder64<D>> decoderLoc; + const o2::rans::LiteralDecoder64<dest_t>* decoder = reinterpret_cast<const o2::rans::LiteralDecoder64<dest_t>*>(decoderExt); + std::unique_ptr<o2::rans::LiteralDecoder64<dest_t>> decoderLoc; if (block.getNDict()) { // if dictionaty is saved, prefer it o2::rans::FrequencyTable frequencies; frequencies.addFrequencies(block.getDict(), block.getDict() + block.getNDict(), md.min, md.max); - decoderLoc = std::make_unique<o2::rans::LiteralDecoder64<D>>(frequencies, md.probabilityBits); + decoderLoc = std::make_unique<o2::rans::LiteralDecoder64<dest_t>>(frequencies, md.probabilityBits); decoder = decoderLoc.get(); } else { // verify that decoded corresponds to stored metadata if (md.min != decoder->getMinSymbol() || md.max != decoder->getMaxSymbol()) { @@ -708,37 +759,50 @@ void EncodedBlocks<H, N, W>::decode(D* dest, // destination } } // load incompressible symbols if they existed - std::vector<D> literals; + std::vector<dest_t> literals; if (block.getNLiterals()) { // note: here we have to use md.nLiterals (original number of literal words) rather than md.nLiteralWords == block.getNLiterals() // (number of W-words in the EncodedBlock occupied by literals) as we cast literals stored in W-word array // to D-word array - literals = std::vector<D>{reinterpret_cast<const D*>(block.getLiterals()), reinterpret_cast<const D*>(block.getLiterals()) + md.nLiterals}; + literals = std::vector<dest_t>{reinterpret_cast<const dest_t*>(block.getLiterals()), reinterpret_cast<const dest_t*>(block.getLiterals()) + md.nLiterals}; } - decoder->process(dest, block.getData() + block.getNData(), md.messageLength, literals); + decoder->process(block.getData() + block.getNData(), dest, md.messageLength, literals); } else { // data was stored as is - std::memcpy(dest, block.payload, md.messageLength * sizeof(D)); + using destPtr_t = typename std::iterator_traits<D_IT>::pointer; + destPtr_t srcBegin = reinterpret_cast<destPtr_t>(block.payload); + destPtr_t srcEnd = srcBegin + md.messageLength * sizeof(dest_t); + std::copy(srcBegin, srcEnd, dest); + //std::memcpy(dest, block.payload, md.messageLength * sizeof(dest_t)); } } } ///_____________________________________________________________________________ template <typename H, int N, typename W> -template <typename S_IT, typename VB> -void EncodedBlocks<H, N, W>::encode(const S_IT srcBegin, // iterator begin of source message - const S_IT srcEnd, // iterator end of source message - int slot, // slot in encoded data to fill - uint8_t probabilityBits, // encoding into - Metadata::OptStore opt, // option for data compression - VB* buffer, // optional buffer (vector) providing memory for encoded blocks - const void* encoderExt) // optional external encoder +template <typename input_IT, typename buffer_T> +void EncodedBlocks<H, N, W>::encode(const input_IT srcBegin, // iterator begin of source message + const input_IT srcEnd, // iterator end of source message + int slot, // slot in encoded data to fill + uint8_t symbolTablePrecision, // encoding into + Metadata::OptStore opt, // option for data compression + buffer_T* buffer, // optional buffer (vector) providing memory for encoded blocks + const void* encoderExt) // optional external encoder { + + using storageBuffer_t = W; + using input_t = typename std::iterator_traits<input_IT>::value_type; + using ransEncoder_t = typename rans::LiteralEncoder64<input_t>; + using ransState_t = typename ransEncoder_t::coder_t; + using ransStream_t = typename ransEncoder_t::stream_t; + + // assert at compile time that output types align so that padding is not necessary. + static_assert(std::is_same_v<storageBuffer_t, ransStream_t>); + static_assert(std::is_same_v<storageBuffer_t, typename rans::FrequencyTable::count_t>); + // fill a new block assert(slot == mRegistry.nFilledBlocks); mRegistry.nFilledBlocks++; - using STYP = typename std::iterator_traits<S_IT>::value_type; - using stream_t = typename o2::rans::Encoder64<STYP>::stream_t; - ; + const size_t messageLength = std::distance(srcBegin, srcEnd); // cover three cases: // * empty source message: no entropy coding @@ -747,25 +811,23 @@ void EncodedBlocks<H, N, W>::encode(const S_IT srcBegin, // iterator begin o // case 1: empty source message if (messageLength == 0) { - mMetadata[slot] = Metadata{0, 0, sizeof(uint64_t), sizeof(stream_t), probabilityBits, Metadata::OptStore::NODATA, 0, 0, 0, 0, 0}; + mMetadata[slot] = Metadata{0, 0, sizeof(ransState_t), sizeof(ransStream_t), symbolTablePrecision, Metadata::OptStore::NODATA, 0, 0, 0, 0, 0}; return; } - static_assert(std::is_same<W, stream_t>()); - Metadata md; - auto* bl = &mBlocks[slot]; - auto* meta = &mMetadata[slot]; + auto* thisBlock = &mBlocks[slot]; + auto* thisMetadata = &mMetadata[slot]; // resize underlying buffer of block if necessary and update all pointers. - auto expandStorage = [&](int nElems) { - auto eeb = get(bl->registry->head); // extract pointer from the block, as "this" might be invalid - auto szNeed = eeb->estimateBlockSize(nElems); // size in bytes!!! - if (szNeed >= bl->registry->getFreeSize()) { - LOG(INFO) << "Slot " << slot << ": free size: " << bl->registry->getFreeSize() << ", need " << szNeed << " for " << nElems << " words"; + auto expandStorage = [&](int additionalElements) { + auto* const blockHead = get(thisBlock->registry->head); // extract pointer from the block, as "this" might be invalid + const size_t additionalSize = blockHead->estimateBlockSize(additionalElements); // size in bytes!!! + if (additionalSize >= thisBlock->registry->getFreeSize()) { + LOG(INFO) << "Slot " << slot << ": free size: " << thisBlock->registry->getFreeSize() << ", need " << additionalSize << " for " << additionalElements << " words"; if (buffer) { - eeb->expand(*buffer, size() + (szNeed - getFreeSize())); - meta = &(get(buffer->data())->mMetadata[slot]); - bl = &(get(buffer->data())->mBlocks[slot]); // in case of resizing this and any this.xxx becomes invalid + blockHead->expand(*buffer, blockHead->size() + (additionalSize - blockHead->getFreeSize())); + thisMetadata = &(get(buffer->data())->mMetadata[slot]); + thisBlock = &(get(buffer->data())->mBlocks[slot]); // in case of resizing this and any this.xxx becomes invalid } else { throw std::runtime_error("no room for encoded block in provided container"); } @@ -775,58 +837,84 @@ void EncodedBlocks<H, N, W>::encode(const S_IT srcBegin, // iterator begin o // case 3: message where entropy coding should be applied if (opt == Metadata::OptStore::EENCODE) { // build symbol statistics - constexpr size_t SizeEstMargin = 1024; - const o2::rans::LiteralEncoder64<STYP>* encoder = reinterpret_cast<const o2::rans::LiteralEncoder64<STYP>*>(encoderExt); - std::unique_ptr<o2::rans::LiteralEncoder64<STYP>> encoderLoc; - std::unique_ptr<o2::rans::FrequencyTable> frequencies = nullptr; - int dictSize = 0; - if (!encoder) { // no external encoder provide, create one on spot - frequencies = std::make_unique<o2::rans::FrequencyTable>(); - frequencies->addSamples(srcBegin, srcEnd); - encoderLoc = std::make_unique<o2::rans::LiteralEncoder64<STYP>>(*frequencies, probabilityBits); - encoder = encoderLoc.get(); - dictSize = frequencies->size(); - } + constexpr size_t SizeEstMarginAbs = 10 * 1024; + constexpr float SizeEstMarginRel = 1.05; + + const auto [inplaceEncoder, frequencyTable] = [&]() { + if (encoderExt) { + return std::make_tuple(ransEncoder_t{}, rans::FrequencyTable{}); + } else { + rans::FrequencyTable frequencyTable{}; + frequencyTable.addSamples(srcBegin, srcEnd); + return std::make_tuple(ransEncoder_t{frequencyTable, symbolTablePrecision}, frequencyTable); + } + }(); + ransEncoder_t const* const encoder = encoderExt ? reinterpret_cast<ransEncoder_t const* const>(encoderExt) : &inplaceEncoder; // estimate size of encode buffer - int dataSize = rans::calculateMaxBufferSize(messageLength, encoder->getAlphabetRangeBits(), sizeof(STYP)); // size in bytes + int dataSize = rans::calculateMaxBufferSize(messageLength, encoder->getAlphabetRangeBits(), sizeof(input_t)); // size in bytes // preliminary expansion of storage based on dict size + estimated size of encode buffer - dataSize = SizeEstMargin + dataSize / sizeof(W) + (sizeof(STYP) < sizeof(W)); // size in words of output stream - expandStorage(dictSize + dataSize); + dataSize = SizeEstMarginAbs + int(SizeEstMarginRel * (dataSize / sizeof(storageBuffer_t))) + (sizeof(input_t) < sizeof(storageBuffer_t)); // size in words of output stream + expandStorage(frequencyTable.size() + dataSize); //store dictionary first - if (dictSize) { - bl->storeDict(dictSize, frequencies->data()); + if (frequencyTable.size()) { + thisBlock->storeDict(frequencyTable.size(), frequencyTable.data()); } // vector of incompressible literal symbols - std::vector<STYP> literals; + std::vector<input_t> literals; // directly encode source message into block buffer. - const auto encodedMessageEnd = encoder->process(bl->getCreateData(), bl->getCreateData() + dataSize, srcBegin, srcEnd, literals); - dataSize = encodedMessageEnd - bl->getData(); - bl->setNData(dataSize); - bl->realignBlock(); + storageBuffer_t* const blockBufferBegin = thisBlock->getCreateData(); + const size_t maxBufferSize = thisBlock->registry->getFreeSize(); // note: "this" might be not valid after expandStorage call!!! + const auto encodedMessageEnd = encoder->process(srcBegin, srcEnd, blockBufferBegin, literals); + rans::utils::checkBounds(encodedMessageEnd, blockBufferBegin + maxBufferSize); + dataSize = encodedMessageEnd - thisBlock->getDataPointer(); + thisBlock->setNData(dataSize); + thisBlock->realignBlock(); // update the size claimed by encode message directly inside the block - // store incompressible symbols if any - - int literalSize = 0; - if (literals.size()) { - literalSize = (literals.size() * sizeof(STYP)) / sizeof(stream_t) + (sizeof(STYP) < sizeof(stream_t)); - expandStorage(literalSize); - bl->storeLiterals(literalSize, reinterpret_cast<const stream_t*>(literals.data())); - } - *meta = Metadata{messageLength, literals.size(), sizeof(uint64_t), sizeof(stream_t), static_cast<uint8_t>(encoder->getProbabilityBits()), opt, - encoder->getMinSymbol(), encoder->getMaxSymbol(), dictSize, dataSize, literalSize}; + // store incompressible symbols if any + const size_t nLiteralSymbols = literals.size(); + const size_t nLiteralWords = [&]() { + if (!literals.empty()) { + const size_t nSymbols = literals.size(); + // introduce padding in case literals don't align; + const size_t nLiteralSymbolsPadded = calculatePaddedSize<input_t, storageBuffer_t>(nSymbols); + literals.resize(nLiteralSymbolsPadded, {}); + + const size_t nLiteralStorageElems = calculateNDestTElements<input_t, storageBuffer_t>(nSymbols); + expandStorage(nLiteralStorageElems); + thisBlock->storeLiterals(nLiteralStorageElems, reinterpret_cast<const storageBuffer_t*>(literals.data())); + return nLiteralStorageElems; + } + return size_t(0); + }(); + + *thisMetadata = Metadata{messageLength, + nLiteralSymbols, + sizeof(ransState_t), + sizeof(ransStream_t), + static_cast<uint8_t>(encoder->getSymbolTablePrecision()), + opt, + encoder->getMinSymbol(), + encoder->getMaxSymbol(), + static_cast<int32_t>(frequencyTable.size()), + dataSize, + static_cast<int32_t>(nLiteralWords)}; } else { // store original data w/o EEncoding - const size_t szb = messageLength * sizeof(STYP); - const int dataSize = szb / sizeof(stream_t) + (sizeof(STYP) < sizeof(stream_t)); - // no dictionary needed - expandStorage(dataSize); - *meta = Metadata{messageLength, 0, sizeof(uint64_t), sizeof(stream_t), probabilityBits, opt, 0, 0, 0, dataSize, 0}; + //FIXME(milettri): we should be able to do without an intermediate vector; // provided iterator is not necessarily pointer, need to use intermediate vector!!! - std::vector<STYP> vtmp(srcBegin, srcEnd); - bl->storeData(meta->nDataWords, reinterpret_cast<const W*>(vtmp.data())); + + // introduce padding in case literals don't align; + const size_t nSourceElemsPadded = calculatePaddedSize<input_t, storageBuffer_t>(messageLength); + std::vector<input_t> tmp(nSourceElemsPadded, {}); + std::copy(srcBegin, srcEnd, std::begin(tmp)); + + const size_t nBufferElems = calculateNDestTElements<input_t, storageBuffer_t>(messageLength); + expandStorage(nBufferElems); + thisBlock->storeData(thisMetadata->nDataWords, reinterpret_cast<const storageBuffer_t*>(tmp.data())); + + *thisMetadata = Metadata{messageLength, 0, sizeof(ransState_t), sizeof(storageBuffer_t), symbolTablePrecision, opt, 0, 0, 0, static_cast<int>(nBufferElems), 0}; } - // resize block if necessary } /// create a special EncodedBlocks containing only dictionaries made from provided vector of frequency tables @@ -834,7 +922,7 @@ template <typename H, int N, typename W> std::vector<char> EncodedBlocks<H, N, W>::createDictionaryBlocks(const std::vector<o2::rans::FrequencyTable>& vfreq, const std::vector<Metadata>& vmd) { if (vfreq.size() != N) { - throw std::runtime_error("mismatch between the size of frequencies vector and number of blocks"); + throw std::runtime_error(fmt::format("mismatch between the size of frequencies vector {} and number of blocks {}", vfreq.size(), N)); } size_t sz = alignSize(sizeof(EncodedBlocks<H, N, W>)); for (int ib = 0; ib < N; ib++) { diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/FileMetaData.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/FileMetaData.h new file mode 100644 index 0000000000000..cf1e8af7e4b8d --- /dev/null +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/FileMetaData.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @brief meta data of the file produced by O2 + +#ifndef _ALICEO2_FILE_METADATA_H +#define _ALICEO2_FILE_METADATA_H + +#include <string> + +namespace o2 +{ +namespace dataformats +{ + +struct FileMetaData { + std::string LHCPeriod{}; // 1, LHC data taking period + detector name, in case of individual detector data stream, required + std::string lurl{}; // 3, the local EPN path to the CTF or calibration file, required + std::string type{}; // 4, CTF or calibration; default is CTF, optional + std::string guid{}; // 7, default is auto-generated, optional + std::string surl{}; // 8, the remote storage path where we store the data file, optional + std::string curl{}; // 9, the Grid catalogue path, optional + std::string md5{}; //10, default the checksum of the lurl file; only filled after a successful transfer, if needed, optional + std::string xxhash{}; //11, default calculated from the lurl file, only filled after a successful transfer, if needed, optional + std::string seName{}; //12, default is taken from the configuration file + std::string seioDaemons{}; //13, default is taken from the configuration file + std::string priority{}; //14, low or high; default is low + long run{}; // 2, run number, required + long ctime{}; // 5, default the timestamp of the lurl file, optional + size_t size{}; // 6, default the size of the lurl file, optional + + bool fillFileData(const std::string& fname); + std::string asString() const; +}; + +std::ostream& operator<<(std::ostream& stream, const FileMetaData& m); + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h index e2eece219ebff..ad998115ea3a5 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/StringUtils.h" +#include "CommonUtils/ConfigurableParamHelper.h" #include <string_view> /// \file NameConf.h @@ -23,49 +25,56 @@ namespace base { // Class for standardization of the names for output files and trees -class NameConf +class NameConf : public o2::conf::ConfigurableParamHelper<NameConf> { using DId = o2::detectors::DetID; public: - // Check if the path exists - static bool pathExists(const std::string_view p); - - // Check if the path is a directory - static bool pathIsDirectory(const std::string_view p); - - // Expand to full path - static std::string getFullPath(const std::string_view p); // The Hits file name are generated by hardcoded schema, only prefix is mutable to allow the embedding static std::string getHitsFileName(o2::detectors::DetID d, const std::string_view prefix = STANDARDSIMPREFIX) { - return o2::utils::concat_string(prefix, "_", HITS_STRING, d.getName(), ".root"); + return o2::utils::Str::concat_string(prefix, "_", HITS_STRING, d.getName(), ".root"); } // The Digits file name are generated by hardcoded schema, only prefix is mutable to allow the embedding static std::string getDigitsFileName(o2::detectors::DetID d, const std::string_view prefix = STANDARDSIMPREFIX) { - return o2::utils::concat_string(prefix, "_", DIGITS_STRING, d.getName(), ".root"); + return o2::utils::Str::concat_string(prefix, "_", DIGITS_STRING, d.getName(), ".root"); } + // Filename of collision context + static std::string getCollisionContextFileName(const std::string_view prefix = ""); + + // Filename of general run parameters (GRP) + static std::string getGRPFileName(const std::string_view prefix = STANDARDSIMPREFIX); + // Filename to store kinematics + TrackRefs - static std::string getGRPFileName(const std::string_view prefix = STANDARDSIMPREFIX) + static std::string getMCKinematicsFileName(const std::string_view prefix = STANDARDSIMPREFIX) { - return o2::utils::concat_string(prefix, "_", GRP_STRING, ".root"); + return o2::utils::Str::concat_string(prefix, "_", KINE_STRING, ".root"); } // Filename to store kinematics + TrackRefs - static std::string getMCKinematicsFileName(const std::string_view prefix = STANDARDSIMPREFIX) + static std::string getMCHeadersFileName(const std::string_view prefix = STANDARDSIMPREFIX) { - return o2::utils::concat_string(prefix, "_", KINE_STRING, ".root"); + return o2::utils::Str::concat_string(prefix, "_", MCHEADER_STRING, ".root"); + } + + // Filename to store final MC configuration file + static std::string getMCConfigFileName(const std::string_view prefix = STANDARDSIMPREFIX) + { + return o2::utils::Str::concat_string(prefix, "_", CONFIG_STRING, ".ini"); } // Filename to store geometry file static std::string getGeomFileName(const std::string_view prefix = ""); // Filename to for decoding dictionaries - static std::string getDictionaryFileName(DId det, const std::string_view prefix = "", const std::string_view ext = ""); + static std::string getAlpideClusterDictionaryFileName(DId det, const std::string_view prefix = "", const std::string_view ext = ""); + + // Filename to for noise maps + static std::string getNoiseFileName(DId det, const std::string_view prefix = "", const std::string_view ext = ""); // Filename to store material LUT file static std::string getMatLUTFileName(const std::string_view prefix = ""); @@ -85,29 +94,51 @@ class NameConf // public standard CTF dictionary static constexpr std::string_view CTFDICT = "ctf_dictionary"; // hardcoded - // Block for ITS/TPC matching - static constexpr std::string_view TPCITS_TracksBranchName = "TPCITS"; ///< name of branch containing output matched tracks - static constexpr std::string_view TPCITS_TPCMCTruthBranchName = "MatchTPCMCTruth"; ///< name of branch for output matched tracks TPC MC - static constexpr std::string_view TPCITS_ITSMCTruthBranchName = "MatchITSMCTruth"; ///< name of branch for output matched tracks ITS MC - // CTF tree name static constexpr std::string_view CTFTREENAME = "ctf"; // hardcoded // CTF Filename - static std::string getCTFFileName(long id, const std::string_view prefix = "o2_ctf"); + static std::string getCTFFileName(uint32_t run, uint32_t orb, uint32_t id, const std::string_view prefix = "o2_ctf"); + + // CTF Dictionary + static std::string getCTFDictFileName(); + + // The alignment object path in CCDB + static std::string getAlignmentPath(o2::detectors::DetID d) + { + return o2::utils::Str::concat_string(d.getName(), "/", ALIGNPATH); + } private: + // helper method to build filenames + static std::string buildFileName(const std::string_view prefix, const std::string_view delimiter, const std::string_view defPrefix, const std::string_view defName, + const std::string_view extension, const std::string_view optDir = ""); + // unmodifiable constants used to construct filenames etc static constexpr std::string_view STANDARDSIMPREFIX = "o2sim"; static constexpr std::string_view HITS_STRING = "Hits"; // hardcoded static constexpr std::string_view DIGITS_STRING = "Digits"; // hardcoded static constexpr std::string_view GRP_STRING = "grp"; // hardcoded static constexpr std::string_view KINE_STRING = "Kine"; // hardcoded + static constexpr std::string_view MCHEADER_STRING = "MCHeader"; // hardcoded static constexpr std::string_view GEOM_FILE_STRING = "geometry"; static constexpr std::string_view CUT_FILE_STRING = "proc-cut"; - - static constexpr std::string_view DICTFILENAME = "dictionary"; + static constexpr std::string_view CONFIG_STRING = "configuration"; + static constexpr std::string_view ROOT_EXT_STRING = "root"; + static constexpr std::string_view DAT_EXT_STRING = "dat"; + static constexpr std::string_view ALPIDECLUSDICTFILENAME = "dictionary"; + static constexpr std::string_view NOISEFILENAME = "NoiseMap"; static constexpr std::string_view MATBUDLUT = "matbud"; + static constexpr std::string_view COLLISIONCONTEXT = "collisioncontext"; + static constexpr std::string_view ALIGNPATH = "Align"; + + // these are configurable paths for some commonly used files + std::string mDirGRP = "none"; // directory for GRP file ("none" == "") + std::string mDirGeom = "none"; // directory for geometry file + std::string mDirMatLUT = "none"; // directory for material LUT + std::string mDirCollContext = "none"; // directory for collision context + + O2ParamDef(NameConf, "NameConf"); }; } // namespace base diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h index 332f8a42010be..523d4e06ee94c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,8 +36,8 @@ class SimTraits // initialization fragile since depends on correct order. Can we do better? // clang-format off - static inline const std::array<std::vector<std::string>, DetID::nDetectors> DETECTORBRANCHNAMES = - { /*ITS*/ VS{ "ITSHit" }, + static inline const std::array<std::vector<std::string>, DetID::nDetectors> DETECTORBRANCHNAMES = + { /*ITS*/ VS{ "ITSHit" }, /*TPC*/ VS{ "TPCHitsShiftedSector0", "TPCHitsShiftedSector1", "TPCHitsShiftedSector2", @@ -86,18 +87,20 @@ class SimTraits /*FT0*/ VS{ "FT0Hit" }, /*FV0*/ VS{ "FV0Hit" }, /*FDD*/ VS{ "FDDHit" }, - /*ACO*/ VS{ "ACOHit" } + /*ACO*/ VS{ "ACOHit" }, + /*CTP*/ VS{ "CTPHit" } #ifdef ENABLE_UPGRADES , /*IT3*/ VS{ "IT3Hit" }, - /*IT4*/ VS{ "IT4Hit" } + /*TRK*/ VS{ "TRKHit" }, + /*FT3*/ VS{ "FT3Hit" } #endif }; // clang-format on // branches that are related to kinematics and general event information static inline const std::vector<std::string> KINEMATICSBRANCHES = - {"MCTrack", "MCEventHeader", "TrackRefs", "IndexedTrackRefs"}; + {"MCTrack", "MCEventHeader", "TrackRefs"}; ClassDefNV(SimTraits, 1); }; @@ -108,7 +111,7 @@ class SimTraits // forward declares the HitTypes namespace trd { -class HitType; +class Hit; } namespace itsmft { @@ -172,7 +175,7 @@ struct DetIDToHitTypes { // specialize for detectors template <> struct DetIDToHitTypes<o2::detectors::DetID::TRD> { - using HitType = o2::trd::HitType; + using HitType = o2::trd::Hit; }; template <> struct DetIDToHitTypes<o2::detectors::DetID::ITS> { @@ -227,9 +230,12 @@ template <> struct DetIDToHitTypes<o2::detectors::DetID::IT3> { using HitType = o2::itsmft::Hit; }; - template <> -struct DetIDToHitTypes<o2::detectors::DetID::IT4> { +struct DetIDToHitTypes<o2::detectors::DetID::TRK> { + using HitType = o2::itsmft::Hit; +}; +template <> +struct DetIDToHitTypes<o2::detectors::DetID::FT3> { using HitType = o2::itsmft::Hit; }; #endif diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/UpgradesStatus.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/UpgradesStatus.h new file mode 100644 index 0000000000000..b8e28831502bc --- /dev/null +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/UpgradesStatus.h @@ -0,0 +1,15 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_UPGRADES_STATUS_H +#define O2_UPGRADES_STATUS_H +#endif +// dummy header, will be regenerated and installed at built time from UpgradesStatus.h.in diff --git a/DataFormats/Detectors/Common/src/AlignParam.cxx b/DataFormats/Detectors/Common/src/AlignParam.cxx index 6b351549a812e..9ca5defe900fc 100644 --- a/DataFormats/Detectors/Common/src/AlignParam.cxx +++ b/DataFormats/Detectors/Common/src/AlignParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,7 @@ AlignParam::AlignParam(const char* symname, int algID, // volume symbolic double x, double y, double z, // delta translation double psi, double theta, double phi, // delta rotation bool global) // global (preferable) or local delta definition - : TNamed(symname, "") + : mSymName(symname), mAlignableID(algID) { /// standard constructor with 3 translation + 3 rotation parameters /// If the user explicitly sets the global variable to false then the @@ -34,12 +35,10 @@ AlignParam::AlignParam(const char* symname, int algID, // volume symbolic /// This requires to have a gGeoMenager active instance, otherwise the /// constructor will fail (no object created) - setAlignableID(algID); - if (global) { - setTranslation(x, y, z); - setRotation(psi, theta, phi); + setGlobalParams(x, y, z, psi, theta, phi); } else { + setLocalParams(x, y, z, psi, theta, phi); } } @@ -58,21 +57,7 @@ void AlignParam::setMatrixRotation(double psi, double theta, double phi, TGeoHMa { /// apply rotation to matrix double rot[9] = {}; - Double_t sinpsi = std::sin(psi); - Double_t cospsi = std::cos(psi); - Double_t sinthe = std::sin(theta); - Double_t costhe = std::cos(theta); - Double_t sinphi = std::sin(phi); - Double_t cosphi = std::cos(phi); - rot[0] = costhe * cosphi; - rot[1] = -costhe * sinphi; - rot[2] = sinthe; - rot[3] = sinpsi * sinthe * cosphi + cospsi * sinphi; - rot[4] = -sinpsi * sinthe * sinphi + cospsi * cosphi; - rot[5] = -costhe * sinpsi; - rot[6] = -cospsi * sinthe * cosphi + sinpsi * sinphi; - rot[7] = cospsi * sinthe * sinphi + sinpsi * cosphi; - rot[8] = costhe * cospsi; + anglesToMatrix(psi, theta, phi, rot); dest.SetRotation(rot); } @@ -112,7 +97,7 @@ bool AlignParam::setRotation(const TGeoMatrix& m) } //_____________________________________________________________________________ -bool AlignParam::matrixToAngles(const double* rot, double& psi, double& theta, double& phi) +bool AlignParam::matrixToAngles(const double* rot, double& psi, double& theta, double& phi) const { /// Calculates the Euler angles in "x y z" notation /// using the rotation matrix @@ -129,6 +114,30 @@ bool AlignParam::matrixToAngles(const double* rot, double& psi, double& theta, d return true; } +//_____________________________________________________________________________ +void AlignParam::anglesToMatrix(double psi, double theta, double phi, double* rot) const +{ + // Calculates the rotation matrix using the + // Euler angles in "x y z" notation + // + double sinpsi = std::sin(psi); + double cospsi = std::cos(psi); + double sinthe = std::sin(theta); + double costhe = std::cos(theta); + double sinphi = std::sin(phi); + double cosphi = std::cos(phi); + + rot[0] = costhe * cosphi; + rot[1] = -costhe * sinphi; + rot[2] = sinthe; + rot[3] = sinpsi * sinthe * cosphi + cospsi * sinphi; + rot[4] = -sinpsi * sinthe * sinphi + cospsi * cosphi; + rot[5] = -costhe * sinpsi; + rot[6] = -cospsi * sinthe * cosphi + sinpsi * sinphi; + rot[7] = cospsi * sinthe * sinphi + sinpsi * cosphi; + rot[8] = costhe * cospsi; +} + //_____________________________________________________________________________ bool AlignParam::setLocalParams(double x, double y, double z, double psi, double theta, double phi) { @@ -138,10 +147,9 @@ bool AlignParam::setLocalParams(double x, double y, double z, double psi, double /// returns false and the object parameters are not set. TGeoHMatrix m; - Double_t tr[3] = {x, y, z}; + double tr[3] = {x, y, z}; m.SetTranslation(tr); setMatrixRotation(psi, theta, phi, m); - return setLocalParams(m); } @@ -158,7 +166,7 @@ bool AlignParam::setLocalParams(const TGeoMatrix& m) return false; } - const char* symname = getSymName(); + const char* symname = getSymName().c_str(); TGeoHMatrix gprime, gprimeinv; TGeoPhysicalNode* pn = nullptr; TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname); @@ -190,7 +198,7 @@ bool AlignParam::setLocalParams(const TGeoMatrix& m) m1.Multiply(&gprimeinv); m1.MultiplyLeft(&gprime); - setParams(m1); + setGlobalParams(m1); return true; } @@ -206,7 +214,7 @@ bool AlignParam::createLocalMatrix(TGeoHMatrix& m) const return false; } - const char* symname = getSymName(); + const char* symname = getSymName().c_str(); TGeoPhysicalNode* node; TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname); if (pne) { @@ -236,7 +244,7 @@ bool AlignParam::createLocalMatrix(TGeoHMatrix& m) const } //_____________________________________________________________________________ -bool AlignParam::applyToGeometry(bool ovlpcheck, double ovlToler) +bool AlignParam::applyToGeometry() const { /// Apply the current alignment object to the TGeo geometry /// This method returns FALSE if the symname of the object was not @@ -252,7 +260,7 @@ bool AlignParam::applyToGeometry(bool ovlpcheck, double ovlToler) return false; } - const char* symname = getSymName(); + const char* symname = getSymName().c_str(); const char* path; TGeoPhysicalNode* node; TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname); @@ -279,7 +287,7 @@ bool AlignParam::applyToGeometry(bool ovlpcheck, double ovlToler) return false; } - // Double_t threshold = 0.001; + // double threshold = 0.001; TGeoHMatrix gprime = *node->GetMatrix(); TGeoHMatrix align = createMatrix(); @@ -291,40 +299,11 @@ bool AlignParam::applyToGeometry(bool ovlpcheck, double ovlToler) LOG(DEBUG) << "Aligning volume " << symname; - if (ovlpcheck) { - node->Align(ginv, nullptr, true, ovlToler); - TObjArray* ovlpArray = gGeoManager->GetListOfOverlaps(); - Int_t nOvlp = ovlpArray->GetEntriesFast(); - if (nOvlp) { - LOG(INFO) << "Misalignment of node " << node->GetName() << " generated the following " << nOvlp - << "overlaps/extrusions:"; - for (int i = 0; i < nOvlp; i++) { - ((TGeoOverlap*)ovlpArray->UncheckedAt(i))->PrintInfo(); - } - } - } else { - node->Align(ginv, nullptr, false, ovlToler); - } + node->Align(ginv); return true; } -//_____________________________________________________________________________ -int AlignParam::Compare(const TObject* obj) const -{ - /// Compare the levels of two alignment objects - /// Used in the sorting during the application of alignment - /// objects to the geometry - - int level = getLevel(); - int level2 = ((AlignParam*)obj)->getLevel(); - if (level == level2) { - return 0; - } else { - return ((level > level2) ? 1 : -1); - } -} - //_____________________________________________________________________________ int AlignParam::getLevel() const { @@ -336,7 +315,7 @@ int AlignParam::getLevel() const LOG(ERROR) << "gGeoManager doesn't exist or it is still open: unable to return meaningful level value."; return -1; } - const char* symname = getSymName(); + const char* symname = getSymName().c_str(); const char* path; TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname); if (pne) { @@ -351,9 +330,107 @@ int AlignParam::getLevel() const } //_____________________________________________________________________________ -void AlignParam::Print(const Option_t*) const +void AlignParam::print() const { // print parameters - printf("%s : %6d | X: %+e Y: %+e Z: %+e | pitch: %+e roll: %+e yaw: %e\n", getSymName(), getAlignableID(), getX(), + printf("%s : %6d | X: %+e Y: %+e Z: %+e | pitch: %+e roll: %+e yaw: %e\n", getSymName().c_str(), getAlignableID(), getX(), getY(), getZ(), getPsi(), getTheta(), getPhi()); } + +//_____________________________________________________________________________ +void AlignParam::setGlobalParams(double x, double y, double z, double psi, double theta, double phi) +{ + /// set parameters of global delta + setTranslation(x, y, z); + setRotation(psi, theta, phi); +} + +//_____________________________________________________________________________ +void AlignParam::setRotation(double psi, double theta, double phi) +{ + /// set global delta rotations angles in radian + mPsi = psi; + mTheta = theta; + mPhi = phi; +} + +//_____________________________________________________________________________ +void AlignParam::setTranslation(double x, double y, double z) +{ + /// set global delta displacements in cm + mX = x; + mY = y; + mZ = z; +} + +//_____________________________________________________________________________ +void AlignParam::setGlobalParams(const TGeoMatrix& m) +{ + /// set params from the matrix of global delta + setTranslation(m); + setRotation(m); +} + +//___________________________________________________ +void AlignParam::setMatrixTranslation(double x, double y, double z, TGeoHMatrix& dest) const +{ + /// apply translation to matrix + double tra[3] = {x, y, z}; + dest.SetTranslation(tra); +} + +//_____________________________________________________________________________ +bool AlignParam::setLocalTranslation(double x, double y, double z) +{ + /// Set the global delta transformation by passing the three shifts giving + /// the translation in the local reference system of the alignable + /// volume (known by TGeo geometry). + /// In case that the TGeo was not initialized or not closed, + /// returns false and the object parameters are not set. + + TGeoHMatrix m; + double tr[3] = {x, y, z}; + m.SetTranslation(tr); + + return setLocalParams(m); +} + +//_____________________________________________________________________________ +bool AlignParam::setLocalTranslation(const TGeoMatrix& m) +{ + /// Set the global delta transformation by passing the matrix of + /// the local delta transformation and taking its translational part + /// In case that the TGeo was not initialized or not closed, + /// returns false and the object parameters are not set. + + TGeoHMatrix mtr; + mtr.SetTranslation(m.GetTranslation()); + return setLocalParams(mtr); +} + +//_____________________________________________________________________________ +bool AlignParam::setLocalRotation(double psi, double theta, double phi) +{ + /// Set the global delta transformation by passing the three angles giving + /// the rotation in the local reference system of the alignable + /// volume (known by TGeo geometry). + /// In case that the TGeo was not initialized or not closed, + /// returns false and the object parameters are not set. + + TGeoHMatrix m; + setMatrixRotation(psi, theta, phi, m); + return setLocalParams(m); +} + +//_____________________________________________________________________________ +bool AlignParam::setLocalRotation(const TGeoMatrix& m) +{ + /// Set the global delta transformation by passing the matrix of + /// the local delta transformation and taking its rotational part + /// In case that the TGeo was not initialized or not closed, + /// returns false and the object parameters are not set. + + TGeoHMatrix rotm; + rotm.SetRotation(m.GetRotationMatrix()); + return setLocalParams(rotm); +} diff --git a/DataFormats/Detectors/Common/src/CTFDictHeader.cxx b/DataFormats/Detectors/Common/src/CTFDictHeader.cxx new file mode 100644 index 0000000000000..a07ef734a7f15 --- /dev/null +++ b/DataFormats/Detectors/Common/src/CTFDictHeader.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFDictHeader.cxx +/// \brief Header: timestamps and format version for detector CTF dictionary +/// \author ruben.shahoyan@cern.ch + +#include "DetectorsCommonDataFormats/CTFDictHeader.h" +#include <ctime> +#include <sstream> +#include <iomanip> + +using namespace o2::ctf; + +std::string CTFDictHeader::asString() const +{ + std::time_t temp = dictTimeStamp; + std::tm* t = std::gmtime(&temp); + std::stringstream ss; + ss << "Dict. v" << int(majorVersion) << '.' << int(minorVersion) << " from " << std::put_time(t, "%Y-%m-%d %I:%M:%S %p"); + return ss.str(); +} diff --git a/DataFormats/Detectors/Common/src/CTFHeader.cxx b/DataFormats/Detectors/Common/src/CTFHeader.cxx index 695c41385b035..03e28555d72a1 100644 --- a/DataFormats/Detectors/Common/src/CTFHeader.cxx +++ b/DataFormats/Detectors/Common/src/CTFHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/Common/src/DetID.cxx b/DataFormats/Detectors/Common/src/DetID.cxx index ac6cb80e7ba12..356d6e78fea5c 100644 --- a/DataFormats/Detectors/Common/src/DetID.cxx +++ b/DataFormats/Detectors/Common/src/DetID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ /// @brief detector ids, masks, names class implementation #include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/StringUtils.h" #include <cassert> #include <string> #include "FairLogger.h" @@ -22,15 +24,15 @@ using namespace o2::detectors; ClassImp(o2::detectors::DetID); constexpr const char* DetID::sDetNames[DetID::nDetectors + 1]; -constexpr std::array<DetID::mask_t, DetID::nDetectors> DetID::sMasks; // redundant declarations constexpr DetID::ID DetID::ITS, DetID::TPC, DetID::TRD, DetID::TOF, DetID::PHS, DetID::CPV, DetID::EMC, - DetID::HMP, DetID::MFT, DetID::MCH, DetID::MID, DetID::ZDC, DetID::FT0, DetID::FV0, DetID::FDD, DetID::ACO, DetID::First, DetID::Last; + DetID::HMP, DetID::MFT, DetID::MCH, DetID::MID, DetID::ZDC, DetID::FT0, DetID::FV0, DetID::FDD, DetID::ACO, DetID::CTP, DetID::First, DetID::Last; #ifdef ENABLE_UPGRADES constexpr DetID::ID DetID::IT3; -constexpr DetID::ID DetID::IT4; +constexpr DetID::ID DetID::TRK; +constexpr DetID::ID DetID::FT3; #endif constexpr int DetID::nDetectors; @@ -39,23 +41,23 @@ constexpr int DetID::nDetectors; DetID::mask_t DetID::getMask(const std::string_view detList) { DetID::mask_t mask; - std::string ss(detList); - auto pos = ss.find(NONE); - if (pos != std::string::npos) { - ss.replace(pos, NONE.size(), ""); - } else { - for (auto id = DetID::First; id <= DetID::Last; id++) { - auto pos = ss.find(DetID::getName(id)); - if (pos != std::string::npos) { - mask.set(id); - ss.replace(pos, strlen(DetID::getName(id)), ""); - } - } + std::string ss(detList), sname{}; + if (ss.find(NONE) != std::string::npos) { + return mask; } - // make sure that no names are left in the input strings - if (std::count_if(ss.begin(), ss.end(), [](unsigned char c) { return std::isalnum(c); })) { - LOG(ERROR) << "Ill-formed detectors list " << std::string(detList); - throw std::runtime_error("Ill-formed detectors list"); + if (ss.find(ALL) != std::string::npos) { + mask = FullMask; + return mask; + } + std::replace(ss.begin(), ss.end(), ' ', ','); + std::replace(ss.begin(), ss.end(), ';', ','); + auto dv = o2::utils::Str::tokenize(ss, ','); + for (auto& dname : dv) { + auto id = nameToID(dname.c_str()); + if (id < 0) { + throw std::runtime_error(fmt::format("Wrong entry {:s} in detectors list {:s}", dname, detList)); + } + mask |= 0x1u << id; } return mask; } @@ -68,14 +70,14 @@ DetID::DetID(const char* name) : mID(nameToID(name, First)) } //_______________________________ -std::string DetID::getNames(DetID::mask_t mask) +std::string DetID::getNames(DetID::mask_t mask, char delimiter) { // construct from the name std::string ns; for (auto id = DetID::First; id <= DetID::Last; id++) { if (mask[id]) { if (!ns.empty()) { - ns += ','; + ns += delimiter; } ns += getName(id); } diff --git a/DataFormats/Detectors/Common/src/DetMatrixCache.cxx b/DataFormats/Detectors/Common/src/DetMatrixCache.cxx index 387603bc74160..873ad4d94a093 100644 --- a/DataFormats/Detectors/Common/src/DetMatrixCache.cxx +++ b/DataFormats/Detectors/Common/src/DetMatrixCache.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/Common/src/DetectorsCommonDataFormatsLinkDef.h b/DataFormats/Detectors/Common/src/DetectorsCommonDataFormatsLinkDef.h index 019a2bca9499f..da8b38261320e 100644 --- a/DataFormats/Detectors/Common/src/DetectorsCommonDataFormatsLinkDef.h +++ b/DataFormats/Detectors/Common/src/DetectorsCommonDataFormatsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,8 +15,10 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::detectors::DetID + ; #pragma link C++ class o2::detectors::AlignParam + ; +#pragma link C++ class std::vector < o2::detectors::AlignParam> + ; + +#pragma link C++ class o2::detectors::DetID + ; #pragma link C++ class o2::detectors::MatrixCache < o2::math_utils::Transform3D> + ; #pragma link C++ class o2::detectors::MatrixCache < o2::math_utils::Rotation2Df_t> + ; #pragma link C++ class o2::detectors::DetMatrixCache + ; @@ -24,9 +27,11 @@ #pragma link C++ class o2::detectors::SimTraits + ; #pragma link C++ class o2::base::NameConf + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::base::NameConf> + ; #pragma link C++ class o2::ctf::CTFHeader + ; #pragma link C++ class o2::ctf::Registry + ; +#pragma link C++ class o2::ctf::CTFDictHeader + ; #pragma link C++ class o2::ctf::Block < uint32_t> + ; #pragma link C++ class o2::ctf::Block < uint16_t> + ; #pragma link C++ class o2::ctf::Block < uint8_t> + ; diff --git a/DataFormats/Detectors/Common/src/EncodedBlocks.cxx b/DataFormats/Detectors/Common/src/EncodedBlocks.cxx index 5320210d1e1ba..361d7e0b0635e 100644 --- a/DataFormats/Detectors/Common/src/EncodedBlocks.cxx +++ b/DataFormats/Detectors/Common/src/EncodedBlocks.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/Common/src/FileMetaData.cxx b/DataFormats/Detectors/Common/src/FileMetaData.cxx new file mode 100644 index 0000000000000..6a331899eadd5 --- /dev/null +++ b/DataFormats/Detectors/Common/src/FileMetaData.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @brief meta data of the file produced by O2 + +#include "DetectorsCommonDataFormats/FileMetaData.h" +#include <Framework/Logger.h> +#include <TMD5.h> +#include <filesystem> +#include <chrono> + +using namespace o2::dataformats; + +bool FileMetaData::fillFileData(const std::string& fname) +{ + try { + lurl = std::filesystem::canonical(fname).string(); + size = std::filesystem::file_size(lurl); + std::unique_ptr<TMD5> md5ptr{TMD5::FileChecksum(fname.c_str())}; + md5 = md5ptr->AsString(); + ctime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + } catch (std::exception const& e) { + LOG(ERROR) << "Failed to fill metadata for file " << fname << ", reason: " << e.what(); + return false; + } + return true; +} + +std::string FileMetaData::asString() const +{ + std::string ms; + + // obligatory part + ms += fmt::format("LHCPeriod: {}\n", LHCPeriod); + ms += fmt::format("run: {}\n", run); + ms += fmt::format("lurl: {}\n", lurl); + + // optional part + if (!type.empty()) { + ms += fmt::format("type: {}\n", type); + } + if (ctime) { + ms += fmt::format("ctime: {}\n", ctime); + } + if (size) { + ms += fmt::format("size: {}\n", size); + } + if (!guid.empty()) { + ms += fmt::format("guid: {}\n", guid); + } + if (!surl.empty()) { + ms += fmt::format("surl: {}\n", surl); + } + if (!curl.empty()) { + ms += fmt::format("curl: {}\n", curl); + } + if (!md5.empty()) { + ms += fmt::format("md5: {}\n", md5); + } + if (!xxhash.empty()) { + ms += fmt::format("xxhash: {}\n", xxhash); + } + if (!seName.empty()) { + ms += fmt::format("seName: {}\n", seName); + } + if (!seioDaemons.empty()) { + ms += fmt::format("seioDaemons: {}\n", seioDaemons); + } + if (!priority.empty()) { + ms += fmt::format("priority: {}\n", priority); + } + return ms; +} + +std::ostream& o2::dataformats::operator<<(std::ostream& stream, const FileMetaData& h) +{ + stream << h.asString(); + return stream; +} diff --git a/DataFormats/Detectors/Common/src/NameConf.cxx b/DataFormats/Detectors/Common/src/NameConf.cxx index 696b6b3ca5a0f..6fc949b742cce 100644 --- a/DataFormats/Detectors/Common/src/NameConf.cxx +++ b/DataFormats/Detectors/Common/src/NameConf.cxx @@ -1,91 +1,90 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "DetectorsCommonDataFormats/NameConf.h" -#include <sys/stat.h> -#include <cstdlib> #include <fmt/format.h> #include <memory> +O2ParamImpl(o2::base::NameConf); + using namespace o2::base; using DId = o2::detectors::DetID; -// Check if the path exists -bool NameConf::pathExists(const std::string_view p) +std::string NameConf::buildFileName(const std::string_view prefix, const std::string_view delimiter, const std::string_view defPrefix, const std::string_view defName, + const std::string_view extension, const std::string_view optDir) { - struct stat buffer; - return (stat(p.data(), &buffer) == 0); + if (o2::utils::Str::pathIsDirectory(prefix)) { // if path is directory, just add to default name, ignoring optional directory optDir argument + return o2::utils::Str::concat_string(prefix, "/", defPrefix, delimiter, defName, '.', extension); + } else if (!prefix.empty() && o2::utils::Str::pathExists(prefix)) { // explicit file path is provided, use it directly + return std::string(prefix); + } + auto dir = o2::utils::Str::rectifyDirectory(optDir); // directory might have been provided + // is the prefix really prefix or a file-name + if (!prefix.empty()) { + auto path = o2::utils::Str::concat_string(dir, prefix); + if (o2::utils::Str::pathExists(path)) { + return path; + } + } + return o2::utils::Str::concat_string(dir, prefix.empty() ? defPrefix : prefix, delimiter, defName, '.', extension); } -// Check if the path is a directory -bool NameConf::pathIsDirectory(const std::string_view p) +// Filename to store geometry file +std::string NameConf::getGeomFileName(const std::string_view prefix) { - struct stat buffer; - return (stat(p.data(), &buffer) == 0) && S_ISDIR(buffer.st_mode); + return buildFileName(prefix, "_", STANDARDSIMPREFIX, GEOM_FILE_STRING, ROOT_EXT_STRING, Instance().mDirGeom); } -std::string NameConf::getFullPath(const std::string_view p) +// Filename to store general run parameters (GRP) +std::string NameConf::getCollisionContextFileName(const std::string_view prefix) { - std::unique_ptr<char[]> real_path(realpath(p.data(), nullptr)); - return std::string(real_path.get()); + return buildFileName(prefix, "", "", COLLISIONCONTEXT, ROOT_EXT_STRING, Instance().mDirCollContext); } -// Filename to store geometry file -std::string NameConf::getGeomFileName(const std::string_view prefix) +// Filename to store general run parameters (GRP) +std::string NameConf::getGRPFileName(const std::string_view prefix) { - // check if the prefix is an existing path - if (pathIsDirectory(prefix)) { - return o2::utils::concat_string(prefix, "/", STANDARDSIMPREFIX, "_", GEOM_FILE_STRING, ".root"); - } else if (pathExists(prefix)) { - return std::string(prefix); // it is a full file - } - return o2::utils::concat_string(prefix.empty() ? STANDARDSIMPREFIX : prefix, "_", GEOM_FILE_STRING, ".root"); + return buildFileName(prefix, "_", STANDARDSIMPREFIX, GRP_STRING, ROOT_EXT_STRING, Instance().mDirGRP); } // Filename to store simulation cuts/process summary std::string NameConf::getCutProcFileName(std::string_view prefix) { - // check if the prefix is an existing path - if (pathIsDirectory(prefix)) { - return o2::utils::concat_string(prefix, "/", STANDARDSIMPREFIX, "_", CUT_FILE_STRING, ".dat"); - } else if (pathExists(prefix)) { - return std::string(prefix); // it is a full file - } - return o2::utils::concat_string(prefix.empty() ? STANDARDSIMPREFIX : prefix, "_", CUT_FILE_STRING, ".dat"); + return buildFileName(prefix, "_", STANDARDSIMPREFIX, CUT_FILE_STRING, DAT_EXT_STRING); } -// Filename to store ITSMFT dictionary -std::string NameConf::getDictionaryFileName(DId det, const std::string_view prefix, const std::string_view ext) +// Filename to store ITSMFT cluster dictionary +std::string NameConf::getAlpideClusterDictionaryFileName(DId det, const std::string_view prefix, const std::string_view ext) { - // check if the prefix is an existing path - if (pathIsDirectory(prefix)) { - return o2::utils::concat_string(prefix, "/", det.getName(), DICTFILENAME, ext); - } else if (pathExists(prefix)) { - return std::string(prefix); // it is a full file - } - return o2::utils::concat_string(prefix, det.getName(), DICTFILENAME, ext); + return buildFileName(prefix, "", det.getName(), ALPIDECLUSDICTFILENAME, ext); +} + +// Filename to store detector specific noise maps +std::string NameConf::getNoiseFileName(DId det, const std::string_view prefix, const std::string_view ext) +{ + return buildFileName(prefix, "", det.getName(), NOISEFILENAME, ext); } // Filename to store material LUT file std::string NameConf::getMatLUTFileName(const std::string_view prefix) { - // check if the prefix is an existing path - if (pathIsDirectory(prefix)) { - return o2::utils::concat_string(prefix, "/", MATBUDLUT, ".root"); - } else if (pathExists(prefix)) { - return std::string(prefix); // it is a full file - } - return o2::utils::concat_string(prefix, MATBUDLUT, ".root"); + return buildFileName(prefix, "", "", MATBUDLUT, ROOT_EXT_STRING, Instance().mDirMatLUT); +} + +std::string NameConf::getCTFFileName(uint32_t run, uint32_t orb, uint32_t id, const std::string_view prefix) +{ + return o2::utils::Str::concat_string(prefix, '_', fmt::format("run{:08d}_orbit{:010d}_tf{:010d}", run, orb, id), ".root"); } -std::string NameConf::getCTFFileName(long id, const std::string_view prefix) +std::string NameConf::getCTFDictFileName() { - return o2::utils::concat_string(prefix, "_", fmt::format("{:010d}", id), ".root"); + return o2::utils::Str::concat_string(CTFDICT, ".root"); } diff --git a/DataFormats/Detectors/Common/test/testDetID.cxx b/DataFormats/Detectors/Common/test/testDetID.cxx index f307b346e9be8..3ebcb344032f9 100644 --- a/DataFormats/Detectors/Common/test/testDetID.cxx +++ b/DataFormats/Detectors/Common/test/testDetID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/DCS/CMakeLists.txt b/DataFormats/Detectors/DCS/CMakeLists.txt new file mode 100644 index 0000000000000..685d6cbafc8e6 --- /dev/null +++ b/DataFormats/Detectors/DCS/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_header_only_library(DataFormatsDCS) diff --git a/DataFormats/Detectors/DCS/include/DataFormatsDCS/DCSConfigObject.h b/DataFormats/Detectors/DCS/include/DataFormatsDCS/DCSConfigObject.h new file mode 100644 index 0000000000000..0900c520f53cc --- /dev/null +++ b/DataFormats/Detectors/DCS/include/DataFormatsDCS/DCSConfigObject.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DCSConfigObject.h +/// \bried Data format to store DCS configurations + +#include <vector> +#include <string> +#include <iostream> +#include <iterator> +#include <regex> + +#include <TString.h> + +namespace o2 +{ +namespace dcs +{ + +typedef std::vector<char> DCSconfigObject_t; + +template <typename T> +inline void addConfigItem(DCSconfigObject_t& configVector, std::string key, const T value) +{ + std::string keyValue = key + ":" + std::to_string(value) + ","; + std::copy(keyValue.begin(), keyValue.end(), std::back_inserter(configVector)); +} + +// explicit specialization for std::string +template <> +inline void addConfigItem(DCSconfigObject_t& configVector, std::string key, const std::string value) +{ + std::string keyValue = key + ":" + value + ","; + std::copy(keyValue.begin(), keyValue.end(), std::back_inserter(configVector)); +} + +// explicit specialization for char +template <> +inline void addConfigItem(DCSconfigObject_t& configVector, std::string key, const char value) +{ + std::string keyValue = key + ":" + value + ","; + std::copy(keyValue.begin(), keyValue.end(), std::back_inserter(configVector)); +} + +// explicit specialization for char* +template <> +inline void addConfigItem(DCSconfigObject_t& configVector, std::string key, const char* value) +{ + std::string keyValue = key + ":" + value + ","; + std::copy(keyValue.begin(), keyValue.end(), std::back_inserter(configVector)); +} + +// explicit specialization for TString +template <> +inline void addConfigItem(DCSconfigObject_t& configVector, std::string key, const TString value) +{ + std::string keyValue = key + ":" + value.Data() + ","; + std::copy(keyValue.begin(), keyValue.end(), std::back_inserter(configVector)); +} + +inline void printDCSConfig(const DCSconfigObject_t& configVector) +{ + std::string sConfig(configVector.begin(), configVector.end()); + std::cout << "string " + << " --> " << sConfig << std::endl; + auto const re = std::regex{R"(,+)"}; + auto vecRe = std::vector<std::string>(std::sregex_token_iterator{begin(sConfig), end(sConfig), re, -1}, + std::sregex_token_iterator{}); + for (size_t i = 0; i < vecRe.size(); ++i) { + // vecRe[i].erase(vecRe[i].end() - 1); + std::cout << i << " --> " << vecRe[i] << std::endl; + } +} + +} // namespace dcs +} // namespace o2 diff --git a/DataFormats/Detectors/EMCAL/CMakeLists.txt b/DataFormats/Detectors/EMCAL/CMakeLists.txt index df6fd86c0205f..6e18044fb0b87 100644 --- a/DataFormats/Detectors/EMCAL/CMakeLists.txt +++ b/DataFormats/Detectors/EMCAL/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsEMCAL SOURCES src/EMCALBlockHeader.cxx @@ -18,6 +19,7 @@ o2_add_library(DataFormatsEMCAL src/Digit.cxx src/EventHandler.cxx src/CTF.cxx + src/ErrorTypeFEE.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::MathUtils @@ -35,7 +37,8 @@ o2_target_root_dictionary(DataFormatsEMCAL include/DataFormatsEMCAL/AnalysisCluster.h include/DataFormatsEMCAL/EventHandler.h include/DataFormatsEMCAL/MCLabel.h - include/DataFormatsEMCAL/CTF.h) + include/DataFormatsEMCAL/CTF.h + include/DataFormatsEMCAL/ErrorTypeFEE.h) o2_add_test(Cell SOURCES test/testCell.cxx diff --git a/DataFormats/Detectors/EMCAL/doxymodules.h b/DataFormats/Detectors/EMCAL/doxymodules.h index 6bd7566fb7215..ed9087569f8c7 100644 --- a/DataFormats/Detectors/EMCAL/doxymodules.h +++ b/DataFormats/Detectors/EMCAL/doxymodules.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h index eb65775919cba..52c1fa39d0be2 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CTF.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CTF.h index 283c98d52bed2..d9cb0a6ca2d3f 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CTF.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,13 +28,13 @@ namespace emcal { /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nTriggers = 0; /// number of triggers uint32_t nCells = 0; /// number of referred cells uint32_t firstOrbit = 0; /// orbit of 1st trigger uint16_t firstBC = 0; /// bc of 1st trigger - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// wrapper for the Entropy-encoded triggers and cells of the TF diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h index a9872a9039bd2..a3a67b88dd389 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cluster.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cluster.h index e3359cf127b33..f6e99983c3b83 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cluster.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h index b538c3a34fd58..065e3da897965 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Digit.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Digit.h index 9f8ee1b67e44c..13afd1ca1a2f4 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Digit.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALBlockHeader.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALBlockHeader.h index 0019cd22e758d..dbbb65b783315 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALBlockHeader.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALBlockHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h new file mode 100644 index 0000000000000..3c014d37e6f9e --- /dev/null +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EMCALChannelData.h +/// \brief + +/// \class EMCALChannelCalibrator +/// \brief Class to store the data format for calibraton of the EMCal +/// \author Hannah Bossi, Yale University +/// \ingroup DetectorEMCAL +/// \since Feb 11, 2021 + +#ifndef ALICEO2_EMCALCHANNELDATA_H +#define ALICEO2_EMCALCHANNELDATA_H + +#include "Rtypes.h" + +namespace o2 +{ +namespace dataformats +{ +class EMCALChannelData +{ + public: + EMCALChannelData(int cellID, int timestamp, int flags = 0, int events) : mEMCALCellID(cellID), mTimestamp(timestamp), mFlags(flags){}; + EMCALChannelData() = default; + ~EMCALChannelData() = default; + + void setEMCALCellID(int index) { mEMCALCellID = index; } + int getEMCALCellID() const { return mEMCALCellID; } + + void setTimestamp(int ts) { mTimestamp = ts; } + int getTimestamp() const { return mTimestamp; } + + void setFlags(int flags) { mFlags = flags; } + float getFlags() const { return mFlags; } + + private: + int mEMCALCellID; ///< EMCal Cell ID + int mTimestamp; ///< timestamp in seconds + unsigned char mFlags; ///< bit mask with quality flags (to be defined) + + ClassDefNV(EMCALChannelData, 1); +}; +} // namespace dataformats +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h new file mode 100644 index 0000000000000..a21abbc920161 --- /dev/null +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h @@ -0,0 +1,166 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_ERRORTYPEFEE_H +#define ALICEO2_EMCAL_ERRORTYPEFEE_H + +#include <iostream> +#include "Rtypes.h" + +namespace o2 +{ + +namespace emcal +{ + +/// \class ErrorTypeFEE +/// \brief Errors per FEE information +/// \author Hadi Hassan <hadi.hassan@cern.ch>, Oak Ridge National Laboratory +/// \since March 04, 2021 +/// \ingroup EMCALDataFormat +/// +/// # Container for errors in the raw decoding +/// +/// Various errors can happen during the raw decoding. In order not only to print +/// the errors in the output stream or infoLogger the ErrorTypeFEE can be used to +/// store the error type persistently or to send them to further components, i.e. +/// the QC for monitoring. Several error categories are supported: +/// +/// - PAGE_ERROR: This type handles all errors related to raw page decoding (not ALTRO payload) +/// - ALTRO_ERROR: This type handles all errors related to decoding of the ALTRO payload +/// - MINOR_ALTRO_ERROR: This type handles all errors related to decoding of the ALTRO payload +/// which are not considered as fatal +/// - FIT_ERROR: This type handles all error appearing during the raw fitting procedure +/// - GEOMETRY_ERROR: This type handles all errors related to the calculation of the module position +/// using the geometry +/// +/// In addition to the error type a numeric code to further distinguish the type of +/// the error within the category. A ErrorTypeFEE object can handle only one error, +/// in case multiple errors occur a separate object is needed for each error appearing. +class ErrorTypeFEE +{ + public: + /// \enum ErrorSource_t + /// \brief Source of the error + enum ErrorSource_t { + PAGE_ERROR, ///< Raw page decoding failed + ALTRO_ERROR, ///< Decoding of the ALTRO payload failed + MINOR_ALTRO_ERROR, ///< Non-fatal error in decoding of the ALTRO payload + FIT_ERROR, ///< Raw fit failed + GEOMETRY_ERROR, ///< Decoded position outside EMCAL + UNDEFINED ///< Error source undefined + }; + /// \brief Constructor + ErrorTypeFEE() = default; + + /// \brief Constructor initializing the object + /// \param FEEID ID of the FEE responsible for the error + /// \param errortype Type of the error + /// \param errorCode Error code for the given error type + ErrorTypeFEE(int FEEID, ErrorSource_t errortype, int errorCode) : mFEEID(FEEID), mErrorSource(errortype), mErrorCode(errorCode) {} + + /// \brief Destructor + ~ErrorTypeFEE() = default; + + /// \brief Set the ID of the FEE responsible for the error + /// \param feeid ID of the FEE + void setFEEID(int feeid) { mFEEID = feeid; } + + /// \brief Set the error as decoding error and store the error code + /// \param decodeError Error code of the decoding error + void setDecodeErrorType(int decodeError) { setError(ErrorSource_t::ALTRO_ERROR, decodeError); } + + /// \brief Set the error as minor (non-fatal) decoding error and store the error code + /// \param decodeError Error code of the decoding error + void setMinorDecodingErrorType(int decodeError) { setError(ErrorSource_t::MINOR_ALTRO_ERROR, decodeError); } + + /// \brief Set the error as raw fitter error and store the error code + /// \param rawfitterError Error code of the raw fitter error + void setRawFitErrorType(int rawfitterError) { setError(ErrorSource_t::FIT_ERROR, rawfitterError); } + + /// \brief Set the error as page parser error and store the error code + /// \param pageError Error code of the page parser error + void setPageErrorType(int pageError) { setError(ErrorSource_t::PAGE_ERROR, pageError); } + + /// \brief Set the error type of the object + /// \param errorsource Error type of the object + void setErrorType(ErrorSource_t errorsource) { mErrorSource = errorsource; } + + /// \brief Set the error code of the object + /// \param errorcode Error code of the object + void setErrorCode(int errorcode) { mErrorCode = errorcode; } + + /// \brief Set source and code of the error + /// \param errorsource Type of the error + /// \param errorcode Code of the error + void setError(ErrorSource_t errorsource, int errorcode) + { + setErrorType(errorsource); + setErrorCode(errorcode); + } + + /// \brief Get the FEE ID of the electronics responsible for the error + /// \return ID of the FEE component + int getFEEID() const { return mFEEID; } + + /// \brief Get the type of the error handled by the object + /// \return Error type + ErrorSource_t getErrorType() const { return mErrorSource; } + + /// \brief Get the error code of the object + /// \return Error code + int getErrorCode() const { return mErrorCode; } + + /// \brief Get the error code of the obect in case the object is a decoding error + /// \return Error code (-1 in case the object is not a decoding error) + int getDecodeErrorType() const { return getRawErrorForType(ErrorSource_t::ALTRO_ERROR); } + + /// \brief Get the error code of the obect in case the object is a decoding error + /// \return Error code (-1 in case the object is not a decoding error) + int getMinorDecodeErrorType() const { return getRawErrorForType(ErrorSource_t::MINOR_ALTRO_ERROR); } + + /// \brief Get the error code of the obect in case the object is a raw fitter error + /// \return Error code (-1 in case the object is not a raw fitter error) + int getRawFitErrorType() const { return getRawErrorForType(ErrorSource_t::FIT_ERROR); } + + /// \brief Get the error code of the obect in case the object is a page parsing error + /// \return Error code (-1 in case the object is not a page parsing error) + int getRawPageErrorType() const { return getRawErrorForType(ErrorSource_t::PAGE_ERROR); } + + /// \brief Printing information of the error type + /// \param stream Output stream where to print the error + /// + /// Helper function, called in the output stream operator for the ErrorTypeFEE + void PrintStream(std::ostream& stream) const; + + private: + /// \brief Helper function getting the error code under condition that the error is of a certain type + /// \return Error code (-1 in case the error handle by the object is not of the given type) + int getRawErrorForType(ErrorSource_t source) const { return mErrorSource == source ? mErrorCode : -1; } + + int mFEEID = -1; ///< FEE ID of the SM responsible for the error + ErrorSource_t mErrorSource = ErrorSource_t::UNDEFINED; ///< Source of the error + int mErrorCode = -1; ///< Raw page error type + + ClassDefNV(ErrorTypeFEE, 1); +}; + +/// \brief Stream operator for FEE and it errors +/// \param stream Stream where to print the fee and its errors +/// \param errorType error type to be printed +/// \return Stream after printing +std::ostream& operator<<(std::ostream& stream, const ErrorTypeFEE& errorType); + +} // namespace emcal + +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventData.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventData.h index 35f8ace46fdfd..1d6f961911947 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventData.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventHandler.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventHandler.h index f510f48915705..d39330f65363d 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventHandler.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EventHandler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/MCLabel.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/MCLabel.h index cb3bbf0f17aa2..ff851b2692edb 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/MCLabel.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h index e2656f6bcca71..67dc02a960744 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #ifndef ALICEO2_EMCAL_TRIGGERRECORD_H #define ALICEO2_EMCAL_TRIGGERRECORD_H +#include <cstdint> #include <iosfwd> #include "Rtypes.h" #include "CommonDataFormat/InteractionRecord.h" @@ -35,26 +37,30 @@ class TriggerRecord public: TriggerRecord() = default; - TriggerRecord(const BCData& bunchcrossing, int firstentry, int nentries) : mBCData(bunchcrossing), mDataRange(firstentry, nentries) {} + TriggerRecord(const BCData& bunchcrossing, int firstentry, int nentries) : mBCData(bunchcrossing), mDataRange(firstentry, nentries), mTriggerBits(0) {} + TriggerRecord(const BCData& bunchcrossing, uint32_t triggerbits, int firstentry, int nentries) : TriggerRecord(bunchcrossing, firstentry, nentries) { mTriggerBits = triggerbits; } ~TriggerRecord() = default; void setBCData(const BCData& data) { mBCData = data; } + void setTriggerBits(uint32_t triggerbits) { mTriggerBits = triggerbits; } void setDataRange(int firstentry, int nentries) { mDataRange.set(firstentry, nentries); } void setIndexFirstObject(int firstentry) { mDataRange.setFirstEntry(firstentry); } void setNumberOfObjects(int nentries) { mDataRange.setEntries(nentries); } const BCData& getBCData() const { return mBCData; } BCData& getBCData() { return mBCData; } + uint32_t getTriggerBits() const { return mTriggerBits; } int getNumberOfObjects() const { return mDataRange.getEntries(); } int getFirstEntry() const { return mDataRange.getFirstEntry(); } void printStream(std::ostream& stream) const; private: - BCData mBCData; /// Bunch crossing data of the trigger - DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) + BCData mBCData; /// Bunch crossing data of the trigger + DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) + uint32_t mTriggerBits; /// Trigger bits as from the Raw Data Header - ClassDefNV(TriggerRecord, 1); + ClassDefNV(TriggerRecord, 2); }; std::ostream& operator<<(std::ostream& stream, const TriggerRecord& trg); @@ -63,4 +69,4 @@ std::ostream& operator<<(std::ostream& stream, const TriggerRecord& trg); } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/DataFormats/Detectors/EMCAL/src/AnalysisCluster.cxx b/DataFormats/Detectors/EMCAL/src/AnalysisCluster.cxx index c106ad0ab646d..45108d1e739c2 100644 --- a/DataFormats/Detectors/EMCAL/src/AnalysisCluster.cxx +++ b/DataFormats/Detectors/EMCAL/src/AnalysisCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/CTF.cxx b/DataFormats/Detectors/EMCAL/src/CTF.cxx index 1f9b440e65ec2..1a897026f2e38 100644 --- a/DataFormats/Detectors/EMCAL/src/CTF.cxx +++ b/DataFormats/Detectors/EMCAL/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/Cell.cxx b/DataFormats/Detectors/EMCAL/src/Cell.cxx index b02533111c925..daf6b0103e43d 100644 --- a/DataFormats/Detectors/EMCAL/src/Cell.cxx +++ b/DataFormats/Detectors/EMCAL/src/Cell.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/Cluster.cxx b/DataFormats/Detectors/EMCAL/src/Cluster.cxx index cf6961d5829f9..4b9dc713b9b65 100644 --- a/DataFormats/Detectors/EMCAL/src/Cluster.cxx +++ b/DataFormats/Detectors/EMCAL/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/Constants.cxx b/DataFormats/Detectors/EMCAL/src/Constants.cxx index 620daf91e5d6d..0b9230ff07dbb 100644 --- a/DataFormats/Detectors/EMCAL/src/Constants.cxx +++ b/DataFormats/Detectors/EMCAL/src/Constants.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/DataFormatsEMCALLinkDef.h b/DataFormats/Detectors/EMCAL/src/DataFormatsEMCALLinkDef.h index 5f9bdd0c321cd..801a6ea6dbc96 100644 --- a/DataFormats/Detectors/EMCAL/src/DataFormatsEMCALLinkDef.h +++ b/DataFormats/Detectors/EMCAL/src/DataFormatsEMCALLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,12 +22,14 @@ #pragma link C++ class o2::emcal::Cluster + ; #pragma link C++ class o2::emcal::AnalysisCluster + ; #pragma link C++ class o2::emcal::MCLabel + ; +#pragma link C++ class o2::emcal::ErrorTypeFEE + ; #pragma link C++ class std::vector < o2::emcal::TriggerRecord> + ; #pragma link C++ class std::vector < o2::emcal::Cell> + ; #pragma link C++ class std::vector < o2::emcal::Digit> + ; #pragma link C++ class std::vector < o2::emcal::Cluster> + ; -#pragma link C++ class std::vector < o2::emcal::AnalysisCluster > + ; +#pragma link C++ class std::vector < o2::emcal::AnalysisCluster> + ; +#pragma link C++ class std::vector < o2::emcal::ErrorTypeFEE> + ; #include "SimulationDataFormat/MCTruthContainer.h" #pragma link C++ class o2::dataformats::MCTruthContainer < o2::emcal::MCLabel> + ; diff --git a/DataFormats/Detectors/EMCAL/src/Digit.cxx b/DataFormats/Detectors/EMCAL/src/Digit.cxx index e25d5082b1d8f..bd7d429aff308 100644 --- a/DataFormats/Detectors/EMCAL/src/Digit.cxx +++ b/DataFormats/Detectors/EMCAL/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/EMCALBlockHeader.cxx b/DataFormats/Detectors/EMCAL/src/EMCALBlockHeader.cxx index fd4d53a32eda8..6747c21eaad7f 100644 --- a/DataFormats/Detectors/EMCAL/src/EMCALBlockHeader.cxx +++ b/DataFormats/Detectors/EMCAL/src/EMCALBlockHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx b/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx new file mode 100644 index 0000000000000..8affa29259f7a --- /dev/null +++ b/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EMCALChannelData.cxx +/// \brief Class to store the data format for calibraton of the EMCal + +#include "DataFormatsEMCAL/EMCALChannelData.h" + +using namespace o2::dataformats; + +ClassImp(o2::dataformats::EMCALChannelData; diff --git a/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx b/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx new file mode 100644 index 0000000000000..493db1976a2ff --- /dev/null +++ b/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsEMCAL/ErrorTypeFEE.h" +#include <iostream> + +using namespace o2::emcal; + +void ErrorTypeFEE::PrintStream(std::ostream& stream) const +{ + std::string typestring; + switch (mErrorSource) { + case ErrorSource_t::ALTRO_ERROR: + typestring = "decode error"; + break; + case ErrorSource_t::MINOR_ALTRO_ERROR: + typestring = "decode error"; + break; + case ErrorSource_t::FIT_ERROR: + typestring = "fit error"; + break; + case ErrorSource_t::PAGE_ERROR: + typestring = "page error"; + break; + case ErrorSource_t::GEOMETRY_ERROR: + typestring = "geometry error"; + break; + case ErrorSource_t::UNDEFINED: + typestring = "unknown error"; + break; + default: + typestring = "unknown error"; + break; + }; + stream << "EMCAL SM: " << getFEEID() << ", " << typestring << " Type: " << getErrorCode(); +} + +std::ostream& operator<<(std::ostream& stream, const ErrorTypeFEE& error) +{ + error.PrintStream(stream); + return stream; +} diff --git a/DataFormats/Detectors/EMCAL/src/EventHandler.cxx b/DataFormats/Detectors/EMCAL/src/EventHandler.cxx index ab3f809f5ff73..978a56ed01ae7 100644 --- a/DataFormats/Detectors/EMCAL/src/EventHandler.cxx +++ b/DataFormats/Detectors/EMCAL/src/EventHandler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx b/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx index 2890cfb5ce185..ab35a382212a4 100644 --- a/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx +++ b/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx @@ -1,13 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include <bitset> #include <iostream> #include "DataFormatsEMCAL/TriggerRecord.h" @@ -19,7 +21,7 @@ namespace emcal void TriggerRecord::printStream(std::ostream& stream) const { - stream << "Data for bc " << getBCData().bc << ", orbit " << getBCData().orbit << ", starting from entry " << getFirstEntry() << " with " << getNumberOfObjects() << " objects"; + stream << "Data for bc " << getBCData().bc << ", orbit " << getBCData().orbit << ", Triggers " << std::bitset<sizeof(mTriggerBits) * 8>(mTriggerBits) << ", starting from entry " << getFirstEntry() << " with " << getNumberOfObjects() << " objects"; } std::ostream& operator<<(std::ostream& stream, const TriggerRecord& trg) diff --git a/DataFormats/Detectors/EMCAL/test/testCell.cxx b/DataFormats/Detectors/EMCAL/test/testCell.cxx index f98f0166066be..92fe8c04df768 100644 --- a/DataFormats/Detectors/EMCAL/test/testCell.cxx +++ b/DataFormats/Detectors/EMCAL/test/testCell.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/CMakeLists.txt b/DataFormats/Detectors/FIT/CMakeLists.txt index 0d49cc8ec0937..5facb351c3c45 100644 --- a/DataFormats/Detectors/FIT/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/CMakeLists.txt @@ -1,13 +1,15 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(FDD) add_subdirectory(FT0) add_subdirectory(FV0) +add_subdirectory(common) diff --git a/DataFormats/Detectors/FIT/FDD/CMakeLists.txt b/DataFormats/Detectors/FIT/FDD/CMakeLists.txt index 86c1eb28335e3..7ef1229e5595e 100644 --- a/DataFormats/Detectors/FIT/FDD/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FDD/CMakeLists.txt @@ -1,29 +1,28 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsFDD - SOURCES src/RawEventData.cxx - src/CTF.cxx + SOURCES src/RawEventData.cxx + src/CTF.cxx PUBLIC_LINK_LIBRARIES O2::FDDBase - O2::CommonDataFormat + O2::DataFormatsFIT + O2::CommonDataFormat O2::SimulationDataFormat) o2_target_root_dictionary(DataFormatsFDD HEADERS include/DataFormatsFDD/Digit.h - include/DataFormatsFDD/ChannelData.h - include/DataFormatsFDD/RecPoint.h + include/DataFormatsFDD/ChannelData.h + include/DataFormatsFDD/RecPoint.h include/DataFormatsFDD/MCLabel.h - include/DataFormatsFDD/Hit.h - include/DataFormatsFDD/RawEventData.h - include/DataFormatsFDD/LookUpTable.h - include/DataFormatsFDD/CTF.h) - - - + include/DataFormatsFDD/Hit.h + include/DataFormatsFDD/RawEventData.h + include/DataFormatsFDD/LookUpTable.h + include/DataFormatsFDD/CTF.h) \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/CTF.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/CTF.h index a199319242fa0..3c1df8d89ee4d 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/CTF.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,12 +26,12 @@ namespace fdd { /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nTriggers = 0; /// number of triggers in TF uint32_t firstOrbit = 0; /// 1st orbit of TF uint16_t firstBC = 0; /// 1st BC of TF - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// Intermediate, compressed but not yet entropy-encoded digits diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/ChannelData.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/ChannelData.h index 23a79376b7fe5..055bd1879b9c8 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/ChannelData.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/ChannelData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,9 +12,10 @@ #ifndef _FDD_CHANNEL_DATA_H_ #define _FDD_CHANNEL_DATA_H_ +#include <Framework/Logger.h> #include <array> #include <Rtypes.h> - +#include <tuple> /// \file ChannelData.h /// \brief Container class to store values of single FDD channel /// \author micha.broz@cern.ch @@ -24,12 +26,14 @@ namespace fdd { struct ChannelData { - - int mPMNumber = -1; // PhotoMultiplier number (0 to 16) - float mTime = -1024; // Time of Flight - short mChargeADC = -1024; // ADC sample - short mFEEBits = 0; //Bit information from FEE - enum Flags { Integrator = 0x1 << 0, + static constexpr char sChannelNameDPL[] = "DIGITSCH"; + static constexpr char sDigitName[] = "ChannelData"; + static constexpr char sDigitBranchName[] = "FDDDigitCh"; + uint8_t mPMNumber = -1; // PhotoMultiplier number (0 to 16) + int16_t mTime = -1024; // Time of Flight + int16_t mChargeADC = -1024; // ADC sample + uint8_t mFEEBits = 0; //Bit information from FEE + /* enum Flags { Integrator = 0x1 << 0, DoubleEvent = 0x1 << 1, Event1TimeLost = 0x1 << 2, Event2TimeLost = 0x1 << 3, @@ -37,14 +41,30 @@ struct ChannelData { TimeTooLate = 0x1 << 5, AmpTooHigh = 0x1 << 6, EventInTrigger = 0x1 << 7, - TimeLost = 0x1 << 8 }; + TimeLost = 0x1 << 8 };*/ + enum EEventDataBit { kNumberADC, + kIsDoubleEvent, + kIsTimeInfoNOTvalid, + kIsCFDinADCgate, + kIsTimeInfoLate, + kIsAmpHigh, + kIsEventInTVDC, + kIsTimeInfoLost + }; ChannelData() = default; - ChannelData(int channel, float time, short adc, short bits) : mPMNumber(channel), mTime(time), mChargeADC(adc), mFEEBits(bits) {} - + ChannelData(uint8_t channel, int time, int adc, uint8_t bits) : mPMNumber(channel), mTime(time), mChargeADC(adc), mFEEBits(bits) {} + uint8_t getChannelID() const { return mPMNumber; } void print() const; - - ClassDefNV(ChannelData, 2); + bool operator==(ChannelData const& other) const + { + return std::tie(mPMNumber, mTime, mChargeADC) == std::tie(other.mPMNumber, other.mTime, other.mChargeADC); + } + void printLog() const + { + LOG(INFO) << "ChId: " << static_cast<uint16_t>(mPMNumber) << " | FEE bits:" << static_cast<uint16_t>(mFEEBits) << " | Time: " << mTime << " | Charge: " << mChargeADC; + } + ClassDefNV(ChannelData, 3); }; } // namespace fdd } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h index 5f24c40b746e8..1c9f417b9d79f 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,11 +16,12 @@ #include "CommonDataFormat/InteractionRecord.h" #include "CommonDataFormat/TimeStamp.h" #include "DataFormatsFDD/ChannelData.h" +#include <Framework/Logger.h> #include <iosfwd> #include <Rtypes.h> #include <gsl/span> #include <bitset> - +#include <tuple> namespace o2 { namespace fdd @@ -28,13 +30,18 @@ namespace fdd class ChannelData; struct Triggers { + enum { bitA, + bitC, + bitVertex, + bitCen, + bitSCen }; uint8_t triggersignals = 0; // FDD trigger signals - int8_t nChanA = -1; // number of fired channels A side - int8_t nChanC = -1; // number of fired channels A side + int8_t nChanA = 0; // number of fired channels A side + int8_t nChanC = 0; // number of fired channels A side int32_t amplA = -1024; // sum amplitude A side int32_t amplC = -1024; // sum amplitude C side - int16_t timeA = -1024; // average time A side - int16_t timeC = -1024; // average time C side + int16_t timeA = 0; // average time A side + int16_t timeC = 0; // average time C side Triggers() = default; Triggers(uint8_t signals, int8_t chanA, int8_t chanC, int32_t aamplA, int32_t aamplC, int16_t atimeA, int16_t atimeC) { @@ -46,37 +53,112 @@ struct Triggers { timeA = atimeA; timeC = atimeC; } + + bool getOrA() const { return (triggersignals & (1 << bitA)) != 0; } + bool getOrC() const { return (triggersignals & (1 << bitC)) != 0; } + bool getVertex() const { return (triggersignals & (1 << bitVertex)) != 0; } + bool getCen() const { return (triggersignals & (1 << bitCen)) != 0; } + bool getSCen() const { return (triggersignals & (1 << bitSCen)) != 0; } + void cleanTriggers() { triggersignals = 0; - nChanA = nChanC = -1; - amplA = amplC = -1024; - timeA = timeC = -1024; + nChanA = nChanC = 0; + amplA = amplC = 0; + timeA = timeC = 0; } Triggers getTriggers(); - + bool operator==(Triggers const& other) const + { + return std::tie(triggersignals, nChanA, nChanC, amplA, amplC, timeA, timeC) == + std::tie(other.triggersignals, other.nChanA, other.nChanC, other.amplA, other.amplC, other.timeA, other.timeC); + } + void printLog() const + { + LOG(INFO) << "mTrigger: " << static_cast<uint16_t>(triggersignals); + LOG(INFO) << "nChanA: " << static_cast<uint16_t>(nChanA) << " | nChanC: " << static_cast<uint16_t>(nChanC); + LOG(INFO) << "amplA: " << amplA << " | amplC: " << amplC; + LOG(INFO) << "timeA: " << timeA << " | timeC: " << timeC; + } ClassDefNV(Triggers, 1); }; +struct DetTrigInput { + static constexpr char sChannelNameDPL[] = "TRIGGERINPUT"; + static constexpr char sDigitName[] = "DetTrigInput"; + static constexpr char sDigitBranchName[] = "FDDTRIGGERINPUT"; + o2::InteractionRecord mIntRecord; // bc/orbit of the intpur + std::bitset<5> mInputs; // pattern of inputs. + DetTrigInput() = default; + DetTrigInput(const o2::InteractionRecord& iRec, Bool_t isA, Bool_t isC, Bool_t isVrtx, Bool_t isCnt, Bool_t isSCnt) + : mIntRecord(iRec), + mInputs((isA << Triggers::bitA) | + (isC << Triggers::bitC) | + (isVrtx << Triggers::bitVertex) | + (isCnt << Triggers::bitCen) | + (isSCnt << Triggers::bitSCen)) + { + } + ClassDefNV(DetTrigInput, 1); +}; + struct Digit { + static constexpr char sChannelNameDPL[] = "DIGITSBC"; + static constexpr char sDigitName[] = "Digit"; + static constexpr char sDigitBranchName[] = "FDDDigit"; o2::dataformats::RangeRefComp<5> ref; - Triggers mTriggers; // pattern of triggers in this BC o2::InteractionRecord mIntRecord; // Interaction record (orbit, bc) - Digit() = default; Digit(int first, int ne, o2::InteractionRecord iRec, Triggers chTrig) : ref(first, ne), mIntRecord(iRec), mTriggers(chTrig) {} - + typedef DetTrigInput DetTrigInput_t; uint32_t getOrbit() const { return mIntRecord.orbit; } uint16_t getBC() const { return mIntRecord.bc; } o2::InteractionRecord getIntRecord() const { return mIntRecord; }; + void setIntRecord(const o2::InteractionRecord& intRec) { mIntRecord = intRec; } gsl::span<const ChannelData> getBunchChannelData(const gsl::span<const ChannelData> tfdata) const { return ref.getEntries() ? gsl::span<const ChannelData>(&tfdata[ref.getFirstEntry()], ref.getEntries()) : gsl::span<const ChannelData>(); } - + DetTrigInput makeTrgInput() const { return DetTrigInput{mIntRecord, mTriggers.getOrA(), mTriggers.getOrC(), mTriggers.getVertex(), mTriggers.getCen(), mTriggers.getSCen()}; } + void fillTrgInputVec(std::vector<DetTrigInput>& vecTrgInput) const + { + vecTrgInput.emplace_back(mIntRecord, mTriggers.getOrA(), mTriggers.getOrC(), mTriggers.getVertex(), mTriggers.getCen(), mTriggers.getSCen()); + } + bool operator==(const Digit& other) const + { + return std::tie(ref, mTriggers, mIntRecord) == std::tie(other.ref, other.mTriggers, other.mIntRecord); + } + void printLog() const + { + LOG(INFO) << "______________DIGIT DATA____________"; + LOG(INFO) << "BC: " << mIntRecord.bc << "| ORBIT: " << mIntRecord.orbit; + LOG(INFO) << "Ref first: " << ref.getFirstEntry() << "| Ref entries: " << ref.getEntries(); + mTriggers.printLog(); + } ClassDefNV(Digit, 3); }; +//For TCM extended mode (calibration mode), TCMdataExtended digit +struct TriggersExt { + static constexpr char sChannelNameDPL[] = "DIGITSTRGEXT"; + static constexpr char sDigitName[] = "TriggersExt"; + static constexpr char sDigitBranchName[] = "FDDDigitTrgExt"; + TriggersExt(std::array<uint32_t, 20> triggerWords) : mTriggerWords(triggerWords) {} + TriggersExt() = default; + o2::InteractionRecord mIntRecord; + void setTrgWord(uint32_t trgWord, std::size_t pos) { mTriggerWords[pos] = trgWord; } + std::array<uint32_t, 20> mTriggerWords; + void printLog() const + { + LOG(INFO) << "______________EXTENDED TRIGGERS____________"; + LOG(INFO) << "BC: " << mIntRecord.bc << "| ORBIT: " << mIntRecord.orbit; + for (int i = 0; i < 20; i++) { + LOG(INFO) << "N: " << i + 1 << " | TRG: " << mTriggerWords[i]; + } + } + ClassDefNV(TriggersExt, 1); +}; + } // namespace fdd } // namespace o2 #endif diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Hit.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Hit.h index d1cff06d612ee..8354a8923b9b4 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Hit.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/LookUpTable.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/LookUpTable.h index 6b5e6707e0e53..8f6d2ea0ae4bc 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/LookUpTable.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/LookUpTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ // Look Up Table FDD ////////////////////////////////////////////// +#include "DataFormatsFIT/LookUpTable.h" #include <Rtypes.h> #include <cassert> #include <iostream> @@ -74,27 +76,31 @@ class LookUpTable } } - int getChannel(int link, int mcp) const { return mInvTopo[getIdx(link, mcp)]; } + int getChannel(int link, int mcp, int ep = 0) const { return mInvTopo[getIdx(link, mcp)]; } int getLink(int channel) const { return mTopoVector[channel].modLink; } int getModChannel(int channel) const { return mTopoVector[channel].modCh; } int getTcmLink() const { return Nmodules; } + bool isTCM(int link, int ep) const { return link == 2 && ep == 0; } + Topo getTopoPM(int globalChannelID) const { return mTopoVector[globalChannelID]; } + Topo getTopoTCM() const { return Topo{getTcmLink(), 0}; } + std::size_t getNchannels() const { return mTopoVector.size(); } //get number of global PM channels void printFullMap() const { - std::cout << "o2::fdd::LookUpTable::printFullMap(): mTopoVector: [globalCh link modCh]" << std::endl; + LOG(INFO) << "o2::fdd::LookUpTable::printFullMap(): mTopoVector: [globalCh link modCh]"; for (size_t channel = 0; channel < mTopoVector.size(); ++channel) { - std::cout << " " << std::right << std::setw(2) << channel << " "; - std::cout << std::right << std::setw(2) << mTopoVector[channel].modLink << " "; - std::cout << std::right << std::setw(3) << mTopoVector[channel].modCh << std::endl; + LOG(INFO) << " " << channel << " " << mTopoVector[channel].modLink << " " << mTopoVector[channel].modCh; } - std::cout << "o2::fdd::LookUpTable::printFullMap(): mInvTopo: [idx globalCh link modCh]" << std::endl; + LOG(INFO) << "o2::fdd::LookUpTable::printFullMap(): mInvTopo: [idx globalCh link modCh]"; for (size_t idx = 0; idx < mInvTopo.size(); ++idx) { - std::cout << " " << std::right << std::setw(3) << idx << " "; - std::cout << std::right << std::setw(3) << mInvTopo[idx] << " "; - std::cout << std::right << std::setw(2) << getLinkFromIdx(mInvTopo[idx]) << " "; - std::cout << std::right << std::setw(2) << getModChannelFromIdx(mInvTopo[idx]) << std::endl; + LOG(INFO) << " " << idx << " " << mInvTopo[idx] << " " << getLinkFromIdx(mInvTopo[idx]) << " " << getModChannelFromIdx(mInvTopo[idx]); } } + static o2::fdd::LookUpTable linear() + { + return o2::fdd::LookUpTable{1}; + } + private: std::vector<Topo> mTopoVector; // iterator of each vector element gives the global channel number std::vector<int> mInvTopo; // each element is an iterator of mTopoVector @@ -110,6 +116,122 @@ class LookUpTable ClassDefNV(LookUpTable, 1); }; +namespace deprecated +{ +//Singleton for LookUpTable +class SingleLUT : public LookUpTable +{ + private: + SingleLUT() : LookUpTable(LookUpTable::linear()) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + typedef Topo Topo_t; + static constexpr char sDetectorName[] = "FDD"; + static SingleLUT& Instance() + { + static SingleLUT instanceLUT; + return instanceLUT; + } + //Temporary + //Making topo for FEE recognizing(Local channelID is supressed) + static Topo_t makeGlobalTopo(const Topo_t& topo) + { + return Topo_t{topo.modLink, 0}; + } + static int getLocalChannelID(const Topo_t& topo) + { + return topo.modCh; + } + //Prepare full map for FEE metadata + template <typename RDHtype, typename RDHhelper = void> + auto makeMapFEEmetadata() -> std::map<Topo_t, RDHtype> + { + std::map<Topo_t, RDHtype> mapResult; + const uint16_t cruID = 0; //constant + const uint32_t endPointID = 0; //constant + uint64_t feeID = 0; //increments + //PM + for (int iCh = 0; iCh < Instance().getNchannels(); iCh++) { + auto pairInserted = mapResult.insert({makeGlobalTopo(Instance().getTopoPM(iCh)), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.modLink; + rdhObj.endPointID = endPointID; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.modLink); + RDHhelper::setEndPointID(&rdhObj, endPointID); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + feeID++; + } + } + //TCM + { + auto pairInserted = mapResult.insert({makeGlobalTopo(Instance().getTopoTCM()), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.modLink; + rdhObj.endPointID = endPointID; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.modLink); + RDHhelper::setEndPointID(&rdhObj, endPointID); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + } else { + LOG(INFO) << "WARNING! CHECK LUT! TCM METADATA IS INCORRECT!"; + } + } + assert(mapResult.size() > 0); + return mapResult; + } +}; +} // namespace deprecated +namespace new_lut +{ +//Singleton for LookUpTable +template <typename LUT> +class SingleLUT : public LUT +{ + private: + SingleLUT(const std::string& ccdbPath, const std::string& ccdbPathToLUT) : LUT(ccdbPath, ccdbPathToLUT) {} + SingleLUT(const std::string& pathToFile) : LUT(pathToFile) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + static constexpr char sDetectorName[] = "FDD"; + static constexpr char sDefaultCCDBpath[] = "http://ccdb-test.cern.ch:8080/"; + static constexpr char sDefaultLUTpath[] = "FDD/LookUpTable"; + inline static std::string sCurrentCCDBpath = sDefaultCCDBpath; + inline static std::string sCurrentLUTpath = sDefaultLUTpath; + //Before instance() call, setup url and path + static void setCCDBurl(const std::string& url) { sCurrentCCDBpath = url; } + static void setLUTpath(const std::string& path) { sCurrentLUTpath = path; } + static SingleLUT& Instance() + { + static SingleLUT instanceLUT(sCurrentCCDBpath, sCurrentLUTpath); + return instanceLUT; + } +}; +} //namespace new_lut + +using SingleLUT = new_lut::SingleLUT<o2::fit::LookupTableBase<>>; +//using SingleLUT = deprecated::SingleLUT; + } // namespace fdd } // namespace o2 #endif diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/MCLabel.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/MCLabel.h index 181a7f25e9175..22a5360797d1e 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/MCLabel.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RawEventData.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RawEventData.h index 3f8220e4a8f06..cda571ca96fc8 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RawEventData.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RawEventData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,102 +17,32 @@ #define ALICEO2_FDD_RAWEVENTDATA_H_ #include "FDDBase/Constants.h" -#include "DataFormatsFDD/ChannelData.h" #include "Headers/RAWDataHeader.h" -#include "DataFormatsFDD/LookUpTable.h" +#include "DataFormatsFIT/RawEventData.h" #include <CommonDataFormat/InteractionRecord.h> #include <Framework/Logger.h> -#include <iostream> -#include <iomanip> #include <cstring> +#include <iomanip> #include "Rtypes.h" namespace o2 { namespace fdd { -struct EventHeader { - static constexpr int PayloadSize = 16; - union { - uint64_t word[2] = {}; - struct { - uint64_t bc : 12; - uint64_t orbit : 32; - uint64_t reservedField1 : 20; - uint64_t reservedField2 : 8; - uint64_t nGBTWords : 4; - uint64_t startDescriptor : 4; - uint64_t reservedField3 : 48; - }; - }; -}; -struct EventData { - union { - uint64_t word = {0}; - struct { - int64_t time : 12; - int64_t charge : 13; - uint64_t numberADC : 1, - isDoubleEvent : 1, - is1TimeLostEvent : 1, - is2TimeLostEvent : 1, - isADCinGate : 1, - isTimeInfoLate : 1, - isAmpHigh : 1, - isEventInTVDC : 1, - isTimeInfoLost : 1, - reservedField : 2, - channelID : 4; - }; - }; - uint64_t word_zeros = 0x0; - static const size_t PayloadSizeSecondWord = 11; - static const size_t PayloadSizeFirstWord = 5; - void generateFlags() - { - numberADC = std::rand() % 2; - isDoubleEvent = 0; - is1TimeLostEvent = 0; - is2TimeLostEvent = 1; - isADCinGate = 0; - isTimeInfoLate = 0; - isAmpHigh = 0; - isEventInTVDC = 1; - isTimeInfoLost = 0; - } -}; - -struct TCMdata { - static constexpr int PayloadSize = 16; - union { - uint64_t word[2] = {0}; - struct { - uint64_t orC : 1, - orA : 1, - sCen : 1, - cen : 1, - vertex : 1, - nChanA : 7, - nChanC : 7; - int64_t amplA : 18, - amplC : 18, - reservedField1 : 1, //56B, PayloadSize1stWord 6 - timeA : 9, - timeC : 9, - reservedField2 : 46; - }; - }; -}; +using EventHeader = o2::fit::EventHeader; +using EventData = o2::fit::EventData; +using TCMdata = o2::fit::TCMdata; +using TCMdataExtended = o2::fit::TCMdataExtended; class RawEventData { public: RawEventData() = default; EventHeader* getEventHeaderPtr() { return &mEventHeader; } EventData* getEventDataPtr() { return mEventData; } - void print(); - void printHexEventHeader(); - void printHexEventData(uint64_t i); + void print() const; + void printHexEventHeader() const; + void printHexEventData(uint64_t i) const; enum EEventDataBit { kNumberADC, kIsDoubleEvent, kIs1TimeLostEvent, @@ -122,7 +53,9 @@ class RawEventData kIsEventInTVDC, kIsTimeInfoLost }; const static int gStartDescriptor = 0x0000000f; - + static const size_t sPayloadSizeSecondWord = 11; + static const size_t sPayloadSizeFirstWord = 5; + static const size_t sPayloadSize = 16; int size() const { return 1 + mEventHeader.nGBTWords; // EventHeader + EventData size @@ -135,34 +68,34 @@ class RawEventData std::vector<char> result(size() * CRUWordSize); char* out = result.data(); if (!tcm) { - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << " Write PM header: nWords: " << (int)mEventHeader.nGBTWords << " orbit: " << int(mEventHeader.orbit) << " BC: " << int(mEventHeader.bc) << " size: " << result.size(); printHexEventHeader(); - out += CRUWordSize - EventHeader::PayloadSize; // Padding enabled + out += CRUWordSize - sPayloadSize; // Padding enabled for (uint64_t i = 0; i < mEventHeader.nGBTWords; ++i) { - std::memcpy(out, &mEventData[2 * i], EventData::PayloadSizeFirstWord); - out += EventData::PayloadSizeFirstWord; + std::memcpy(out, &mEventData[2 * i], sPayloadSizeFirstWord); + out += sPayloadSizeFirstWord; LOG(DEBUG) << " 1st word: Ch: " << std::setw(2) << mEventData[2 * i].channelID << " charge: " << std::setw(4) << mEventData[2 * i].charge << " time: " << std::setw(4) << mEventData[2 * i].time; - std::memcpy(out, &mEventData[2 * i + 1], EventData::PayloadSizeSecondWord); - out += EventData::PayloadSizeSecondWord; + std::memcpy(out, &mEventData[2 * i + 1], sPayloadSizeSecondWord); + out += sPayloadSizeSecondWord; LOG(DEBUG) << " 2nd word: Ch: " << std::setw(2) << mEventData[2 * i + 1].channelID << " charge: " << std::setw(4) << mEventData[2 * i + 1].charge << " time: " << std::setw(4) << mEventData[2 * i + 1].time; - out += CRUWordSize - EventData::PayloadSizeSecondWord - EventData::PayloadSizeFirstWord; + out += CRUWordSize - sPayloadSizeSecondWord - sPayloadSizeFirstWord; printHexEventData(i); } } else { // TCM data - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << " Write TCM header: nWords: " << (int)mEventHeader.nGBTWords << " orbit: " << int(mEventHeader.orbit) << " BC: " << int(mEventHeader.bc) @@ -175,9 +108,9 @@ class RawEventData } public: - EventHeader mEventHeader; - EventData mEventData[NChPerMod]; - TCMdata mTCMdata; + EventHeader mEventHeader; //! + EventData mEventData[NChPerMod]; //! + TCMdata mTCMdata; //! ClassDefNV(RawEventData, 1); }; diff --git a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RecPoint.h b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RecPoint.h index 90cb33caffb81..1dab8acf54b62 100644 --- a/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RecPoint.h +++ b/DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RecPoint.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,23 +15,77 @@ #define ALICEO2_FDD_RECPOINT_H #include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "DataFormatsFDD/ChannelData.h" +#include "CommonDataFormat/RangeReference.h" +#include "DataFormatsFDD/Digit.h" namespace o2 { namespace fdd { +struct ChannelDataFloat { + + int mPMNumber = -1; // channel Id + int adcId = -1; // QTC chain + double mTime = -20000; // time in ps, 0 at the LHC clk center + double mChargeADC = -20000; // charge [channels] -struct RecPoint { + ChannelDataFloat() = default; + ChannelDataFloat(int Channel, double Time, double Charge, int AdcId) + { + mPMNumber = Channel; + mTime = Time; + mChargeADC = Charge; + adcId = AdcId; + } - double mMeanTimeFDA = o2::InteractionRecord::DummyTime; - double mMeanTimeFDC = o2::InteractionRecord::DummyTime; + void print() const; + + ClassDefNV(ChannelDataFloat, 1); +}; - o2::InteractionRecord mIntRecord; // Interaction record (orbit, bc) from digits +class RecPoint +{ + public: + enum TimeTypeIndex : int { TimeA, + TimeC }; RecPoint() = default; - RecPoint(double timeA, double timeC, o2::InteractionRecord iRec) : mMeanTimeFDA(timeA), mMeanTimeFDC(timeC), mIntRecord(iRec) {} + RecPoint(const std::array<int, 2>& collisiontime, int first, int ne, + o2::InteractionRecord iRec, o2::fdd::Triggers triggers) + : mCollisionTimePs(collisiontime) + { + mRef.setFirstEntry(first); + mRef.setEntries(ne); + mIntRecord = iRec; + mTriggers = triggers; + } + ~RecPoint() = default; + + float getCollisionTime(TimeTypeIndex type) const { return mCollisionTimePs[type]; } + float getCollisionTimeA() const { return getCollisionTime(TimeA); } + float getCollisionTimeC() const { return getCollisionTime(TimeC); } + bool isValidTime(TimeTypeIndex type) const { return getCollisionTime(type) < sDummyCollissionTime; } + void setCollisionTime(Float_t time, TimeTypeIndex type) { mCollisionTimePs[type] = time; } + + const o2::fdd::Triggers getTrigger() const { return mTriggers; } + o2::InteractionRecord getInteractionRecord() const { return mIntRecord; }; + gsl::span<const ChannelDataFloat> getBunchChannelData(const gsl::span<const ChannelDataFloat> tfdata) const + { + // extract the span of channel data for this bunch from the whole TF data + return mRef.getEntries() ? gsl::span<const ChannelDataFloat>(tfdata).subspan(mRef.getFirstEntry(), mRef.getEntries()) : gsl::span<const ChannelDataFloat>(); + } + int static constexpr sDummyCollissionTime = -1024; + + private: + o2::dataformats::RangeReference<int, int> mRef; + o2::InteractionRecord mIntRecord; + o2::fdd::Triggers mTriggers; // pattern of triggers in this BC + std::array<int, 2> mCollisionTimePs = {sDummyCollissionTime, sDummyCollissionTime}; // in picoseconds - ClassDefNV(RecPoint, 2); + ClassDefNV(RecPoint, 3); }; } // namespace fdd } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FDD/src/CTF.cxx b/DataFormats/Detectors/FIT/FDD/src/CTF.cxx index 24724cce55852..1e0a90d15f71a 100644 --- a/DataFormats/Detectors/FIT/FDD/src/CTF.cxx +++ b/DataFormats/Detectors/FIT/FDD/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h b/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h index 6f4f3e9fe4554..6a83c4e9b033b 100644 --- a/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h +++ b/DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,8 @@ #pragma link C++ class vector < o2::fdd::ChannelData> + ; #pragma link C++ class o2::fdd::Triggers + ; #pragma link C++ class vector < o2::fdd::Triggers> + ; +#pragma link C++ class o2::fdd::DetTrigInput + ; +#pragma link C++ class vector < o2::fdd::DetTrigInput> + ; #pragma link C++ class o2::fdd::MCLabel + ; #pragma link C++ class vector < o2::fdd::MCLabel> + ; @@ -29,6 +32,8 @@ #pragma link C++ class o2::fdd::RecPoint + ; #pragma link C++ class vector < o2::fdd::RecPoint> + ; +#pragma link C++ class o2::fdd::ChannelDataFloat + ; +#pragma link C++ class vector < o2::fdd::ChannelDataFloat> + ; #pragma link C++ class o2::fdd::RawEventData + ; #pragma link C++ class o2::fdd::EventHeader + ; diff --git a/DataFormats/Detectors/FIT/FDD/src/RawEventData.cxx b/DataFormats/Detectors/FIT/FDD/src/RawEventData.cxx index 64c5872e9a0e1..f2f82e18eadbc 100644 --- a/DataFormats/Detectors/FIT/FDD/src/RawEventData.cxx +++ b/DataFormats/Detectors/FIT/FDD/src/RawEventData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,39 +11,10 @@ #include "DataFormatsFDD/RawEventData.h" #include <sstream> +#include <iostream> using namespace o2::fdd; - -ClassImp(RawEventData); - -void RawEventData::print() -{ - std::cout << "==================Raw event data==================" << std::endl; - std::cout << "##################Header##################" << std::endl; - std::cout << "startDescriptor: " << mEventHeader.startDescriptor << std::endl; - std::cout << "Nchannels: " << mEventHeader.nGBTWords * 2 << std::endl; - std::cout << "BC: " << mEventHeader.bc << std::endl; - std::cout << "Orbit: " << mEventHeader.orbit << std::endl; - std::cout << "##########################################" << std::endl; - std::cout << "###################DATA###################" << std::endl; - for (int iCh = 0; iCh < mEventHeader.nGBTWords * 2; iCh++) { - std::cout << "------------Channel " << mEventData[iCh].channelID << "------------" << std::endl; - std::cout << "Charge: " << mEventData[iCh].charge << std::endl; - std::cout << "Time: " << mEventData[iCh].time << std::endl; - std::cout << "1TimeLostEvent: " << mEventData[iCh].is1TimeLostEvent << std::endl; - std::cout << "2TimeLostEvent: " << mEventData[iCh].is2TimeLostEvent << std::endl; - std::cout << "ADCinGate: " << mEventData[iCh].isADCinGate << std::endl; - std::cout << "AmpHigh: " << mEventData[iCh].isAmpHigh << std::endl; - std::cout << "DoubleEvent: " << mEventData[iCh].isDoubleEvent << std::endl; - std::cout << "EventInTVDC: " << mEventData[iCh].isEventInTVDC << std::endl; - std::cout << "TimeInfoLate: " << mEventData[iCh].isTimeInfoLate << std::endl; - std::cout << "TimeInfoLost: " << mEventData[iCh].isTimeInfoLost << std::endl; - std::cout << "numberADC: " << mEventData[iCh].numberADC << std::endl; - } - std::cout << "##########################################" << std::endl; -} - -void RawEventData::printHexEventHeader() +void RawEventData::printHexEventHeader() const { std::stringstream ssheader; ssheader << std::setfill('0') << std::setw(16) << std::hex << mEventHeader.word[0] << " " << std::setw(16) << mEventHeader.word[1] << "\n "; @@ -56,7 +28,7 @@ void RawEventData::printHexEventHeader() LOG(DEBUG) << ssheader.str(); } -void RawEventData::printHexEventData(uint64_t i) +void RawEventData::printHexEventData(uint64_t i) const { std::stringstream ssdata; ssdata << "D0:0x "; diff --git a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt index 58699a2cd95a3..4a68d4e6c1c05 100644 --- a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsFT0 SOURCES src/Digit.cxx @@ -14,11 +15,17 @@ o2_add_library(DataFormatsFT0 SOURCES src/ChannelData.cxx SOURCES src/RecPoints.cxx SOURCES src/RawEventData.cxx - src/CTF.cxx + SOURCES src/CTF.cxx + SOURCES src/GlobalOffsetsCalibrationObject.cxx + SOURCES src/GlobalOffsetsContainer.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::SimulationDataFormat - O2::FT0Base) + O2::CCDB + O2::DetectorsCalibration + O2::FT0Base + O2::DataFormatsFIT + ) o2_target_root_dictionary(DataFormatsFT0 HEADERS include/DataFormatsFT0/Digit.h @@ -29,4 +36,7 @@ o2_target_root_dictionary(DataFormatsFT0 include/DataFormatsFT0/HitType.h include/DataFormatsFT0/RawEventData.h include/DataFormatsFT0/LookUpTable.h - include/DataFormatsFT0/CTF.h) + include/DataFormatsFT0/CTF.h + include/DataFormatsFT0/RecoCalibInfoObject.h + include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h + include/DataFormatsFT0/GlobalOffsetsContainer.h) diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/CTF.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/CTF.h index fdf54804c0d1a..2156041ddee9f 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/CTF.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,12 +26,12 @@ namespace ft0 { /// Header for a single CTF -struct CTFHeader { - uint32_t nTriggers = 0; /// number of triggers in TF - uint32_t firstOrbit = 0; /// 1st orbit of TF - uint16_t firstBC = 0; /// 1st BC of TF - - ClassDefNV(CTFHeader, 1); +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers in TF + uint32_t firstOrbit = 0; /// 1st orbit of TF + uint16_t firstBC = 0; /// 1st BC of TF + uint16_t triggerGate = 192; // trigger gate used at encoding + ClassDefNV(CTFHeader, 3); }; /// Intermediate, compressed but not yet entropy-encoded digits @@ -39,10 +40,10 @@ struct CompressedDigits { CTFHeader header; // trigger data - std::vector<uint8_t> trigger; // trigger bits - std::vector<uint16_t> bcInc; // increment in BC if the same orbit, otherwise abs bc - std::vector<uint32_t> orbitInc; // increment in orbit - std::vector<uint8_t> nChan; // number of fired channels + std::vector<uint8_t> trigger; // trigger bits + std::vector<uint16_t> bcInc; // increment in BC if the same orbit, otherwise abs bc + std::vector<uint32_t> orbitInc; // increment in orbit + std::vector<uint8_t> nChan; // number of fired channels std::vector<uint8_t> eventFlags; // special flags about event conditions: pile-up, not use for collision time, not use for event plane, etc. // channel data diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h index d42bad4cfef8e..67d915f3c102d 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,17 +17,23 @@ #define _FT0_CHANNELDATA_H_ #include <Rtypes.h> - +#include <tuple> namespace o2 { namespace ft0 { struct ChannelData { - - uint8_t ChId = 0xff; //channel Id - uint8_t ChainQTC = 0xff; //QTC chain - int16_t CFDTime = -1000; //time in #CFD channels, 0 at the LHC clk center - int16_t QTCAmpl = -1000; // Amplitude #channels + static constexpr char sChannelNameDPL[] = "DIGITSCH"; + static constexpr char sDigitName[] = "ChannelData"; + static constexpr char sDigitBranchName[] = "FT0DIGITSCH"; + static constexpr uint8_t DUMMY_CHANNEL_ID = 0xff; + static constexpr uint8_t DUMMY_CHAIN_QTC = 0xff; + static constexpr int16_t DUMMY_CFD_TIME = -5000; + static constexpr int16_t DUMMY_QTC_AMPL = -5000; + uint8_t ChId = DUMMY_CHANNEL_ID; //channel Id + uint8_t ChainQTC = DUMMY_CHAIN_QTC; //QTC chain + int16_t CFDTime = DUMMY_CFD_TIME; //time in #CFD channels, 0 at the LHC clk center + int16_t QTCAmpl = DUMMY_QTC_AMPL; // Amplitude #channels enum EEventDataBit { kNumberADC, kIsDoubleEvent, kIsTimeInfoNOTvalid, @@ -53,10 +60,18 @@ struct ChannelData { { ChainQTC |= (value << bitFlag); } - bool getFlag(EEventDataBit bitFlag) const { return bool(ChainQTC << bitFlag); } + bool getFlag(EEventDataBit bitFlag) const { return bool(ChainQTC & (1 << bitFlag)); } void print() const; + void printLog() const; + [[nodiscard]] uint8_t getChannelID() const { return ChId; } + [[nodiscard]] uint16_t getTime() const { return CFDTime; } + [[nodiscard]] uint16_t getAmp() const { return QTCAmpl; } - ClassDefNV(ChannelData, 2); + bool operator==(ChannelData const& other) const + { + return std::tie(ChId, CFDTime, QTCAmpl) == std::tie(other.ChId, other.CFDTime, other.QTCAmpl); + } + ClassDefNV(ChannelData, 4); }; } // namespace ft0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/Digit.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/Digit.h index 1abe2b60fe19d..f06a9b5bf01bb 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/Digit.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,8 @@ #include <bitset> #include <iostream> +#include <tuple> + namespace o2 { namespace ft0 @@ -35,14 +38,15 @@ struct Triggers { bitC, bitVertex, bitCen, - bitSCen }; + bitSCen, + bitLaser }; uint8_t triggersignals = 0; // T0 trigger signals int8_t nChanA = 0; // number of fired channels A side int8_t nChanC = 0; // number of fired channels A side - int32_t amplA = -1000; // sum amplitude A side - int32_t amplC = -1000; // sum amplitude C side - int16_t timeA = -1000; // average time A side - int16_t timeC = -1000; // average time C side + int32_t amplA = -5000; // sum amplitude A side + int32_t amplC = -5000; // sum amplitude C side + int16_t timeA = -5000; // average time A side + int16_t timeC = -5000; // average time C side uint8_t eventFlags = 0; // event conditions Triggers() = default; Triggers(uint8_t signals, int8_t chanA, int8_t chanC, int32_t aamplA, int32_t aamplC, int16_t atimeA, int16_t atimeC) @@ -60,11 +64,12 @@ struct Triggers { bool getVertex() const { return (triggersignals & (1 << bitVertex)) != 0; } bool getCen() const { return (triggersignals & (1 << bitCen)) != 0; } bool getSCen() const { return (triggersignals & (1 << bitSCen)) != 0; } + bool getLaserBit() const { return (triggersignals & (1 << bitLaser)) != 0; } void setTriggers(Bool_t isA, Bool_t isC, Bool_t isVrtx, Bool_t isCnt, Bool_t isSCnt, int8_t chanA, int8_t chanC, int32_t aamplA, - int32_t aamplC, int16_t atimeA, int16_t atimeC) + int32_t aamplC, int16_t atimeA, int16_t atimeC, Bool_t isLaser = kFALSE) { - triggersignals = (isA << bitA) | (isC << bitC) | (isVrtx << bitVertex) | (isCnt << bitCen) | (isSCnt << bitSCen); + triggersignals = (isA << bitA) | (isC << bitC) | (isVrtx << bitVertex) | (isCnt << bitCen) | (isSCnt << bitSCen) | (isLaser << bitLaser); nChanA = chanA; nChanC = chanC; amplA = aamplA; @@ -76,14 +81,41 @@ struct Triggers { { triggersignals = 0; nChanA = nChanC = 0; - amplA = amplC = -1000; - timeA = timeC = -1000; + amplA = amplC = -5000; + timeA = timeC = -5000; + } + bool operator==(Triggers const& other) const + { + return std::tie(triggersignals, nChanA, nChanC, amplA, amplC, timeA, timeC) == + std::tie(other.triggersignals, other.nChanA, other.nChanC, other.amplA, other.amplC, other.timeA, other.timeC); } + void printLog() const; + ClassDefNV(Triggers, 2); +}; - ClassDefNV(Triggers, 1); +struct DetTrigInput { + static constexpr char sChannelNameDPL[] = "TRIGGERINPUT"; + static constexpr char sDigitName[] = "DetTrigInput"; + static constexpr char sDigitBranchName[] = "FT0TRIGGERINPUT"; + o2::InteractionRecord mIntRecord; // bc/orbit of the intpur + std::bitset<5> mInputs; // pattern of inputs. + DetTrigInput() = default; + DetTrigInput(const o2::InteractionRecord& iRec, Bool_t isA, Bool_t isC, Bool_t isVrtx, Bool_t isCnt, Bool_t isSCnt) + : mIntRecord(iRec), + mInputs((isA << Triggers::bitA) | + (isC << Triggers::bitC) | + (isVrtx << Triggers::bitVertex) | + (isCnt << Triggers::bitCen) | + (isSCnt << Triggers::bitSCen)) + { + } + ClassDefNV(DetTrigInput, 1); }; struct Digit { + static constexpr char sChannelNameDPL[] = "DIGITSBC"; + static constexpr char sDigitName[] = "Digit"; + static constexpr char sDigitBranchName[] = "FT0DIGITSBC"; o2::dataformats::RangeReference<int, int> ref; Triggers mTriggers; // pattern of triggers in this BC uint8_t mEventStatus; //Status of event from FT0, such as Pileup , etc @@ -101,43 +133,45 @@ struct Digit { mTriggers = chTrig; mEventID = event; } + typedef DetTrigInput DetTrigInput_t; uint32_t getOrbit() const { return mIntRecord.orbit; } uint16_t getBC() const { return mIntRecord.bc; } Triggers getTriggers() const { return mTriggers; } int getEventID() const { return mEventID; } - o2::InteractionRecord getIntRecord() { return mIntRecord; }; + o2::InteractionRecord getIntRecord() const { return mIntRecord; }; + void setIntRecord(const o2::InteractionRecord& intRec) { mIntRecord = intRec; } gsl::span<const ChannelData> getBunchChannelData(const gsl::span<const ChannelData> tfdata) const; - + DetTrigInput makeTrgInput() const { return DetTrigInput{mIntRecord, mTriggers.getOrA(), mTriggers.getOrC(), mTriggers.getVertex(), mTriggers.getCen(), mTriggers.getSCen()}; } + void fillTrgInputVec(std::vector<DetTrigInput>& vecTrgInput) const + { + vecTrgInput.emplace_back(mIntRecord, mTriggers.getOrA(), mTriggers.getOrC(), mTriggers.getVertex(), mTriggers.getCen(), mTriggers.getSCen()); + } void printStream(std::ostream& stream) const; void setTriggers(Triggers trig) { mTriggers = trig; }; void setEventStatus(uint8_t stat) { mEventStatus = stat; }; void setStatusFlag(EEventStatus bit, bool value) { mEventStatus |= (value << bit); }; bool getStatusFlag(EEventStatus bit) const { return bool(mEventStatus << bit); } uint8_t getEventStatusWord() const { return mEventStatus; } - ClassDefNV(Digit, 5); + bool operator==(const Digit& other) const + { + return std::tie(ref, mTriggers, mIntRecord) == std::tie(other.ref, other.mTriggers, other.mIntRecord); + } + void printLog() const; + ClassDefNV(Digit, 6); }; //For TCM extended mode (calibration mode), TCMdataExtended digit struct TriggersExt { - TriggersExt(uint32_t triggerWord) - { - mTriggerWord = triggerWord; - } + static constexpr char sChannelNameDPL[] = "DIGITSTRGEXT"; + static constexpr char sDigitName[] = "TriggersExt"; + static constexpr char sDigitBranchName[] = "FT0DIGITSTRGEXT"; + TriggersExt(std::array<uint32_t, 20> triggerWords) : mTriggerWords(triggerWords) {} TriggersExt() = default; - uint32_t mTriggerWord; - ClassDefNV(TriggersExt, 1); -}; - -//For TCM extended mode (calibration mode) -struct DigitExt : Digit { - DigitExt(int first, int ne, int firstExt, int neExt, const o2::InteractionRecord& iRec, const Triggers& chTrig, int event) : Digit(first, ne, iRec, chTrig, event) - { - refExt.setFirstEntry(firstExt); - refExt.setEntries(neExt); - } - DigitExt() = default; - o2::dataformats::RangeReference<int, int> refExt; //range reference to container with TriggerExt objects - ClassDefNV(DigitExt, 1); + o2::InteractionRecord mIntRecord; + void setTrgWord(uint32_t trgWord, std::size_t pos) { mTriggerWords[pos] = trgWord; } + std::array<uint32_t, 20> mTriggerWords; + void printLog() const; + ClassDefNV(TriggersExt, 2); }; } // namespace ft0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/DigitsTemp.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/DigitsTemp.h index b7577ea8c00da..30bb1ce483bb7 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/DigitsTemp.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/DigitsTemp.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FT0ChannelTimeCalibrationObject.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FT0ChannelTimeCalibrationObject.h new file mode 100644 index 0000000000000..6246fc6186142 --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/FT0ChannelTimeCalibrationObject.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0CHANNELTIMECALIBRATIONOBJECT_H +#define O2_FT0CHANNELTIMECALIBRATIONOBJECT_H + +#include <array> +#include "Rtypes.h" +#include "DataFormatsFT0/RawEventData.h" + +namespace o2::ft0 +{ + +struct FT0ChannelTimeCalibrationObject { + + std::array<int16_t, o2::ft0::Nchannels_FT0> mTimeOffsets{}; + + ClassDefNV(FT0ChannelTimeCalibrationObject, 1); +}; + +class FT0ChannelTimeTimeSlotContainer; + +class FT0TimeChannelOffsetCalibrationObjectAlgorithm +{ + public: + [[nodiscard]] static FT0ChannelTimeCalibrationObject generateCalibrationObject(const FT0ChannelTimeTimeSlotContainer& container); +}; + +} // namespace o2::ft0 + +#endif //O2_FT0CHANNELTIMECALIBRATIONOBJECT_H diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h new file mode 100644 index 0000000000000..3bd0f1a885a1f --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GLOBALOFFSETSCALIBRATIONOBJECT_H +#define O2_GLOBALOFFSETSCALIBRATIONOBJECT_H + +#include <array> +#include "Rtypes.h" +#include "DataFormatsFT0/RecPoints.h" + +namespace o2::ft0 +{ + +struct GlobalOffsetsCalibrationObject { + + // T0A - 0; T0C -1 ; T0AC -2 + enum class Offset { T0A, + T0C, + T0AC }; + std::array<short, 3> mCollisionTimeOffsets{}; + + short getT0A() const + { + return mCollisionTimeOffsets[static_cast<short>(Offset::T0A)]; + } + + short getT0C() const + { + return mCollisionTimeOffsets[static_cast<short>(Offset::T0C)]; + } + + short getT0AC() const + { + return mCollisionTimeOffsets[static_cast<short>(Offset::T0AC)]; + } + + ClassDefNV(GlobalOffsetsCalibrationObject, 1); +}; + +class GlobalOffsetsContainer; + +class GlobalOffsetsCalibrationObjectAlgorithm +{ + public: + [[nodiscard]] static GlobalOffsetsCalibrationObject generateCalibrationObject(const o2::ft0::GlobalOffsetsContainer& container); +}; + +} // namespace o2::ft0 + +#endif //O2_GLOBALOFFSETSCALIBRATIONOBJECT_H diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsContainer.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsContainer.h new file mode 100644 index 0000000000000..74fa33f1e41de --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsContainer.h @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GLOBALOFFSETSCONTAINER_H +#define O2_GLOBALOFFSETSCONTAINER_H + +#include "DataFormatsFT0/RecoCalibInfoObject.h" +#include "DataFormatsFT0/GlobalOffsetsCalibrationObject.h" +#include "Rtypes.h" +#include <TH1F.h> +#include <array> +#include <vector> +#include <gsl/span> + +namespace o2::ft0 +{ +class GlobalOffsetsContainer final +{ + static constexpr int HISTOGRAM_RANGE = 1000; + static constexpr unsigned int NUMBER_OF_HISTOGRAM_BINS = 0.5 * HISTOGRAM_RANGE; + + public: + explicit GlobalOffsetsContainer(std::size_t minEntries); + bool hasEnoughEntries() const; + void fill(const gsl::span<const o2::ft0::RecoCalibInfoObject>& data); + short getMeanGaussianFitValue(std::size_t side) const; + void merge(GlobalOffsetsContainer* prev); + void print() const; + + private: + std::size_t mMinEntries; + std::array<uint64_t, 3> mEntriesCollTime{}; + TH1F* mHistogram[3]; + ClassDefNV(GlobalOffsetsContainer, 1); +}; + +} // namespace o2::ft0 + +#endif //O2_GLOBALOFFSETCONTAINER_H diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsInfoObject.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsInfoObject.h new file mode 100644 index 0000000000000..095349bc2dbce --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/GlobalOffsetsInfoObject.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GLOBALOFFSETSINFOOBJECT_H +#define O2_GLOBALOFFSETSINFOOBJECT_H + +#include "Rtypes.h" + +namespace o2 +{ +namespace ft0 +{ +class GlobalOffsetsInfoObject +{ + public: + GlobalOffsetsInfoObject(short t0A, short t0C, short t0AC) : mT0A(t0A), mT0C(t0C), mT0AC(t0AC); + GlobalOffsetsInfoObject() = default; + ~GlobalOffsetsInfoObject() = default; + + void setT0A(short t0A) { mT0A = t0A; } + short getT0A() const { return mT0A; } + void setT0C(short t0C) { mT0C = t0C; } + short getT0A() const { return mT0A; } + void setT0AC(short t0AC) { mT0AC = t0AC; } + short getT0AC() const { return mT0AC; } + + private: + short mT0A; + short mT0C; + short mT0AC; + + ClassDefNV(GlobalOffsetsInfoObject, 1); +}; +} // namespace ft0 +} // namespace o2 + +#endif //O2_GLOBALOFFSETSINFOOBJECT_H diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HitType.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HitType.h index b0ecbe521d505..6654561ee33a0 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HitType.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/HitType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/LookUpTable.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/LookUpTable.h index de6aeb8ae653e..b2f812a1d4f62 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/LookUpTable.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/LookUpTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,10 +20,23 @@ // Look Up Table FT0 ////////////////////////////////////////////// +#include "CCDB/BasicCCDBManager.h" +#include "FT0Base/Constants.h" +#include "DataFormatsFIT/LookUpTable.h" #include <Rtypes.h> #include <cassert> +#include <exception> #include <iostream> +#include <fstream> +#include <stdexcept> #include <tuple> +#include <TSystem.h> +#include <cstdlib> +#include <map> +#include <string_view> +#include <vector> +#include <cstdlib> + namespace o2 { namespace ft0 @@ -30,18 +44,73 @@ namespace ft0 struct Topo { int mPM = 0; int mMCP = 0; - ClassDefNV(Topo, 1); + int mEP = 0; + ClassDefNV(Topo, 2); +}; + +// enum class Side : char { A, C }; +// struct PM { +// Side side; +// uint8_t PM_num, PM_channel; +// }; + +struct HVchannel { + /* enum class HVBoard : uint8_t { NA, + A_out, + A_in, + C_up, + C_down, + C_mid };*/ + + uint8_t channel; + Topo pm; + std::string HV_board; + uint8_t HV_channel; + std::string MCP_SN; + std::string HV_cabel; + std::string signal_cable; + std::string EP; + + ClassDefNV(HVchannel, 2); }; inline bool operator<(Topo const& a, Topo const& b) { - return (a.mPM < b.mPM || (a.mPM == b.mPM && a.mMCP < b.mMCP)); + /* return (a.mPM < b.mPM || (a.mPM == b.mPM && a.mMCP < b.mMCP)); */ + auto t = [](Topo const& x) -> decltype(auto) { return std::tie(x.mPM, x.mMCP, x.mEP); }; + return t(a) < t(b); +} + +inline o2::ft0::Topo read_Topo(std::string_view str) +{ + assert(str.substr(0, 2) == "PM"); // && str[4] == '/' && str[5] == 'C' && str[6] == 'h'); + char side = str[2]; + char* ptr; + uint8_t pm_num = std::strtol(str.data() + 3, &ptr, 10); // = str[3] - '0'; + /* auto res = std::from_chars(str.data()+3, str.data()+3+str.size(), pm_num); */ + /* if (res.ec != std::errc() || res.ptr[0] != '/') */ + if (errno || ptr[0] != '/') { + throw std::invalid_argument("Cannot read pm_num"); + } + if (ptr[1] != 'C' || ptr[2] != 'h') { + throw std::invalid_argument("Expected 'Ch'"); + } + uint8_t pm_ch = std::strtol(ptr + 3, &ptr, 10); + uint8_t ep = side == 'C' ? 1 : 0; + if (errno) { + throw std::invalid_argument("Cannot read pm_ch"); + } + assert(side == 'A' || side == 'C'); + return Topo{pm_num, pm_ch, ep}; } class LookUpTable { - static constexpr int NUMBER_OF_MCPs = 12; - static constexpr int NUMBER_OF_PMs = 18; + using CcdbManager = o2::ccdb::BasicCCDBManager; + using CcdbApi = o2::ccdb::CcdbApi; + static constexpr int NUMBER_OF_MCPs = o2::ft0::Constants::sNCHANNELS_PER_PM; + static constexpr int NUMBER_OF_PMs = o2::ft0::Constants::sNTOTAL_PM; + static constexpr int TCM_channel = 228; public: /// @@ -51,34 +120,53 @@ class LookUpTable // LookUpTable() = default; explicit LookUpTable(std::vector<Topo> const& topoVector) - : mTopoVector(topoVector), mInvTopo(topoVector.size()) + : mTopoVector(topoVector), mInvTopo(NUMBER_OF_MCPs * 16 * 2) { for (size_t channel = 0; channel < mTopoVector.size(); ++channel) { - mInvTopo.at(getIdx(mTopoVector[channel].mPM, mTopoVector[channel].mMCP)) = + mInvTopo.at(getIdx(mTopoVector[channel].mPM, mTopoVector[channel].mMCP, mTopoVector[channel].mEP)) = channel; } } - + LookUpTable() = default; ~LookUpTable() = default; + + int getTCMchannel() const + { + return TCM_channel; + } + void printFullMap() const { for (size_t channel = 0; channel < mTopoVector.size(); ++channel) { - std::cout << channel << "\t : PM \t" << mTopoVector[channel].mPM - << " MCP \t" << mTopoVector[channel].mMCP << std::endl; - } - for (size_t idx = 0; idx < mInvTopo.size(); ++idx) { - std::cout << "PM \t" << getLinkFromIdx(mInvTopo[idx]) << " MCP \t" - << getMCPFromIdx(mInvTopo[idx]) << std::endl; + LOG(INFO) << channel << "\t : PM \t" << mTopoVector[channel].mPM + << " MCP \t" << mTopoVector[channel].mMCP << " EP \t " << mTopoVector[channel].mEP; } } - int getChannel(int link, int mcp) const + int getChannel(int link, int mcp, int ep) const { - return mInvTopo[getIdx(link, mcp)]; + if ((ep == 0 && (link > 7 && link < 11 && link != 9)) || + (ep == 1 && link == 8 && mcp > 8) || + (ep == 1 && link == 9 && mcp > 8)) { + LOG(INFO) << " channel is not conneted " + << " ep " << ep << " link " << link << " channel " << mcp; + } + return mInvTopo[getIdx(link, mcp, ep)]; } - int getLink(int channel) const { return mTopoVector[channel].mPM; } - int getMCP(int channel) const { return mTopoVector[channel].mMCP; } + int getLink(int channel) const + { + + return mTopoVector[channel].mPM; + } + int getMCP(int channel) const + { + return mTopoVector[channel].mMCP; + } + int getEP(int channel) const + { + return mTopoVector[channel].mEP; + } static o2::ft0::LookUpTable linear() { @@ -91,25 +179,215 @@ class LookUpTable return o2::ft0::LookUpTable{lut_data}; } + static o2::ft0::LookUpTable readTableFile() + { + std::string inputDir; + const char* aliceO2env = std::getenv("O2_ROOT"); + if (aliceO2env) { + inputDir = aliceO2env; + } + inputDir += "/share/Detectors/FT0/files/"; + + std::string lutPath = inputDir + "FT0ChannelsTable.txt"; + lutPath = gSystem->ExpandPathName(lutPath.data()); // Expand $(ALICE_ROOT) into real system path + + std::ifstream infile; + infile.open(lutPath.c_str()); + + std::vector<o2::ft0::Topo> lut_data(NUMBER_OF_MCPs * NUMBER_OF_PMs - 8); + std::string comment; // dummy, used just to read 4 first lines and move the cursor to the 5th, otherwise unused + if (!getline(infile, comment)) { // first comment line + /* std::cout << "Error opening ascii file (it is probably a folder!): " << filename.c_str() << std::endl; */ + throw std::runtime_error("Error reading lookup table"); + } + int channel; + std::string pm, pm_channel, hv_board, hv_channel, mcp_sn, hv_cable, signal_cable; + std::getline(infile, pm); // skip one line + std::string line; + while (std::getline(infile, line) && std::istringstream(line) >> channel >> pm >> pm_channel >> hv_board >> hv_channel >> mcp_sn >> hv_cable >> signal_cable) { + lut_data[channel] = read_Topo(pm_channel); + } + return o2::ft0::LookUpTable{lut_data}; + } + static o2::ft0::LookUpTable readTable() + { + + std::vector<o2::ft0::Topo> lut_data; + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL("http://ccdb-test.cern.ch:8080"); + auto hvch = mgr.get<std::vector<o2::ft0::HVchannel>>("FT0/LookUpTable"); + size_t max = 0; + for (auto const& chan : *hvch) { + if (max < chan.channel) { + max = chan.channel; + } + } + lut_data.resize(max + 1); + for (auto const& chan : *hvch) { + o2::ft0::Topo topo = chan.pm; + lut_data[chan.channel] = topo; + } + LOG(INFO) << "lut_data.size " << lut_data.size(); + return o2::ft0::LookUpTable{lut_data}; + } + bool isTCM(int link, int ep) const { return getChannel(link, 1, ep) == TCM_channel; } + Topo getTopoPM(int globalChannelID) const { return mTopoVector[globalChannelID]; } + Topo getTopoTCM() const { return mTopoVector[TCM_channel]; } + std::size_t getNchannels() const { return TCM_channel; } //get number of global PM channels private: std::vector<Topo> mTopoVector; std::vector<int> mInvTopo; - static int getIdx(int link, int mcp) + static int getIdx(int link, int mcp, int ep) + { + assert(mcp < NUMBER_OF_MCPs); + /* if ((ep == 0 && (link > 7 && link < 11)) || */ + /* (ep == 1 && link == 8 && mcp > 8) || */ + /* (ep == 1 && link == 9 && mcp > 8)) { */ + /* LOG(INFO)<<" channel is not conneted "<<" ep "<<ep<<" link "<<link<<" channel "<<mcp; */ + /* return 255; */ + /* } */ + return (link + ep * 16) * NUMBER_OF_MCPs + mcp; + } + static int getLinkFromIdx(int idx) { - if (mcp >= NUMBER_OF_MCPs) { - std::cout << " !!! MCP number > max NUMBER_OF_MCPs " << mcp << " data will be skipped " << std::endl; - return -1; + int link; + if (idx > 95) { + link = (idx - 96) / NUMBER_OF_MCPs; + } else { + link = idx / NUMBER_OF_MCPs; } - //assert(mcp < NUMBER_OF_MCPs); - return link * NUMBER_OF_MCPs + mcp; + return link; } - static int getLinkFromIdx(int idx) { return idx / NUMBER_OF_MCPs; } - static int getMCPFromIdx(int idx) { return idx % NUMBER_OF_MCPs; } + static int getEPFromIdx(int idx) + { + if (idx < 96 || idx > 215) { + return 0; + } else { + return 1; + } + } + + static int getMCPFromIdx(int idx) { return idx % NUMBER_OF_MCPs + 1; } - ClassDefNV(LookUpTable, 1); + ClassDefNV(LookUpTable, 2); +}; +namespace deprecated //keeping old LUT version +{ +//Singleton for LookUpTable +class SingleLUT : public LookUpTable +{ + private: + SingleLUT() : LookUpTable(LookUpTable::readTable()) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + typedef Topo Topo_t; + static constexpr char sDetectorName[] = "FT0"; + static SingleLUT& Instance() + { + static SingleLUT instanceLUT; + return instanceLUT; + } + //Temporary + //Making topo for FEE recognizing(Local channelID is supressed) + static Topo_t makeGlobalTopo(const Topo_t& topo) + { + return Topo_t{topo.mPM, 0, topo.mEP}; + } + static int getLocalChannelID(const Topo_t& topo) + { + return topo.mMCP; + } + //Prepare full map for FEE metadata + template <typename RDHtype, typename RDHhelper = void> + auto makeMapFEEmetadata() -> std::map<Topo_t, RDHtype> + { + std::map<Topo_t, RDHtype> mapResult; + const uint16_t cruID = 0; //constant + const uint32_t endPointID = 0; //constant + uint64_t feeID = 0; //increments + //PM + for (int iCh = 0; iCh < Instance().getNchannels(); iCh++) { + auto pairInserted = mapResult.insert({makeGlobalTopo(Instance().getTopoPM(iCh)), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.mPM; + rdhObj.endPointID = topoObj.mEP; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.mPM); + RDHhelper::setEndPointID(&rdhObj, topoObj.mEP); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + feeID++; + } + } + //TCM + { + auto pairInserted = mapResult.insert({Instance().getTopoTCM(), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.mPM; + rdhObj.endPointID = topoObj.mEP; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.mPM); + RDHhelper::setEndPointID(&rdhObj, topoObj.mEP); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + } else { + LOG(INFO) << "WARNING! CHECK LUT! TCM METADATA IS INCORRECT!"; + } + } + assert(mapResult.size() > 0); + return mapResult; + } +}; +} // namespace deprecated + +namespace new_lut +{ +//Singleton for LookUpTable +template <typename LUT> +class SingleLUT : public LUT +{ + private: + SingleLUT(const std::string& ccdbPath, const std::string& ccdbPathToLUT) : LUT(ccdbPath, ccdbPathToLUT) {} + SingleLUT(const std::string& pathToFile) : LUT(pathToFile) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + static constexpr char sDetectorName[] = "FT0"; + static constexpr char sDefaultCCDBpath[] = "http://ccdb-test.cern.ch:8080/"; + static constexpr char sDefaultLUTpath[] = "FT0/LookUpTableNew"; + inline static std::string sCurrentCCDBpath = sDefaultCCDBpath; + inline static std::string sCurrentLUTpath = sDefaultLUTpath; + //Before instance() call, setup url and path + static void setCCDBurl(const std::string& url) { sCurrentCCDBpath = url; } + static void setLUTpath(const std::string& path) { sCurrentLUTpath = path; } + static SingleLUT& Instance() + { + static SingleLUT instanceLUT(sCurrentCCDBpath, sCurrentLUTpath); + return instanceLUT; + } }; +} //namespace new_lut +using SingleLUT = new_lut::SingleLUT<o2::fit::LookupTableBase<>>; +//using SingleLUT = deprecated::SingleLUT; } // namespace ft0 } // namespace o2 #endif diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/MCLabel.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/MCLabel.h index ade298338db1f..713a31371a361 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/MCLabel.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RawEventData.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RawEventData.h index d163157e57ae1..6d26688ebd93f 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RawEventData.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RawEventData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,225 +13,40 @@ //Alla.Maevskaya@cern.ch // with Artur.Furs // -#ifndef ALICEO2_FIT_RAWEVENTDATA_H_ -#define ALICEO2_FIT_RAWEVENTDATA_H_ - -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" +#ifndef ALICEO2_FT0_RAWEVENTDATA_H_ +#define ALICEO2_FT0_RAWEVENTDATA_H_ #include "Headers/RAWDataHeader.h" -#include "DataFormatsFT0/LookUpTable.h" +#include "TList.h" //temporary for QC-FT0 (ChannelTimeCalibrationCheck.cxx), should be moved +#include "DataFormatsFIT/RawEventData.h" +#include "FT0Base/Geometry.h" +#include "FT0Base/Constants.h" #include <CommonDataFormat/InteractionRecord.h> #include <Framework/Logger.h> -#include <iostream> #include <utility> #include <cstring> +#include <iomanip> #include "Rtypes.h" + namespace o2 { namespace ft0 { -constexpr int Nchannels_FT0 = 208; -constexpr int Nchannels_PM = 12; -constexpr int NPMs = 19; -constexpr size_t sizeWord = 16; - -struct EventHeader { - static constexpr size_t PayloadSize = 16; //should be equal to 10 - static constexpr size_t PayloadPerGBTword = 16; //should be equal to 10 - static constexpr int MinNelements = 1; - static constexpr int MaxNelements = 1; - union { - uint64_t word[2] = {}; - struct { - uint64_t bc : 12; - uint64_t orbit : 32; - uint64_t phase : 3; - uint64_t errorPhase : 1; - uint64_t reservedField1 : 16; - uint64_t reservedField2 : 8; - uint64_t nGBTWords : 4; - uint64_t startDescriptor : 4; - uint64_t reservedField3 : 48; - }; - }; - InteractionRecord getIntRec() const { return InteractionRecord{(uint16_t)bc, (uint32_t)orbit}; } - - void print() const - { - std::cout << std::hex; - std::cout << "################EventHeader###############" << std::endl; - std::cout << "startDescriptor: " << startDescriptor << std::endl; - std::cout << "nGBTWords: " << nGBTWords << std::endl; - std::cout << "BC: " << bc << std::endl; - std::cout << "Orbit: " << orbit << std::endl; - std::cout << "##########################################" << std::endl; - std::cout << std::dec; - } -}; -struct EventData { - static constexpr size_t PayloadSize = 5; - static constexpr size_t PayloadPerGBTword = 10; - static constexpr int MinNelements = 1; //additional static field - static constexpr int MaxNelements = 12; - // - static constexpr int BitFlagPos = 25; // position of first bit flag(numberADC) - - union { - uint64_t word = {0}; - struct { - int64_t time : 12; - int64_t charge : 13; - uint64_t numberADC : 1, //25 bit - isDoubleEvent : 1, - isTimeInfoNOTvalid : 1, - isCFDinADCgate : 1, - isTimeInfoLate : 1, - isAmpHigh : 1, - isEventInTVDC : 1, - isTimeInfoLost : 1, - reservedField : 3, - channelID : 4; - }; - }; - void generateFlags() - { - numberADC = std::rand() % 2; - isDoubleEvent = 0; - isTimeInfoNOTvalid = 0; - isCFDinADCgate = 1; - isTimeInfoLate = 0; - isAmpHigh = 0; - isEventInTVDC = 1; - isTimeInfoLost = 0; - } - uint8_t getFlagWord() const - { - return uint8_t(word >> BitFlagPos); - } - void print() const - { - std::cout << std::hex; - std::cout << "###############EventData(PM)##############" << std::endl; - std::cout << "------------Channel " << channelID << "------------" << std::endl; - std::cout << "Charge: " << charge << std::endl; - std::cout << "Time: " << time << std::endl; - std::cout << "numberADC: " << numberADC << std::endl; - std::cout << "isDoubleEvent: " << isDoubleEvent << std::endl; - std::cout << "isTimeInfoNOTvalid: " << isTimeInfoNOTvalid << std::endl; - std::cout << "isCFDinADCgate: " << isCFDinADCgate << std::endl; - std::cout << "isTimeInfoLate: " << isTimeInfoLate << std::endl; - std::cout << "isAmpHigh: " << isAmpHigh << std::endl; - std::cout << "isEventInTVDC: " << isEventInTVDC << std::endl; - std::cout << "isTimeInfoLost: " << isTimeInfoLost << std::endl; - std::cout << "##########################################" << std::endl; - std::cout << std::dec; - } - - //temporary, this method should be in ChannelData struct, TODO - void fillChannelData(ChannelData& channelData) const - { - channelData.ChainQTC = getFlagWord(); - } - - uint64_t word_zeros = 0x0; //to remove - static const size_t PayloadSizeSecondWord = 11; //to remove - static const size_t PayloadSizeFirstWord = 5; //to remove -}; - -struct TCMdata { - static constexpr size_t PayloadSize = 16; //should be equal to 10 - static constexpr size_t PayloadPerGBTword = 16; //should be equal to 10 - static constexpr int MinNelements = 1; - static constexpr int MaxNelements = 1; - uint64_t orC : 1, // 0 bit (0 byte) - orA : 1, //1 bit - sCen : 1, //2 bit - cen : 1, //3 bit - vertex : 1, //4 bit - reservedField1 : 3, //5 bit - nChanA : 7, //8 bit(1 byte) - reservedField2 : 1, //15 bit - nChanC : 7, //16 bit(2 byte) - reservedField3 : 1; // 23 bit - int64_t amplA : 17, //24 bit (3 byte) - reservedField4 : 1, //41 bit - amplC : 17, //42 bit. - reservedField5 : 1, //59 bit. - //in standard case(without __atribute__((packed)) macros, or packing by using union) - //here will be empty 4 bits, end next field("timeA") will start from 64 bit. - timeA : 9, //60 bit - reservedField6 : 1, //69 bit - timeC : 9, //70 bit - reservedField7 : 1, //79 bit - reservedField8 : 48; //80 bit - - void print() const - { - std::cout << std::hex; - std::cout << "################TCMdata###################" << std::endl; - std::cout << "orC: " << orC << std::endl; - std::cout << "orA: " << orA << std::endl; - std::cout << "sCen: " << sCen << std::endl; - std::cout << "cen: " << cen << std::endl; - std::cout << "vertex: " << vertex << std::endl; - std::cout << "nChanA: " << nChanA << std::endl; - std::cout << "nChanC: " << nChanC << std::endl; - std::cout << "amplA: " << amplA << std::endl; - std::cout << "amplC: " << amplC << std::endl; - std::cout << "timeA: " << timeA << std::endl; - std::cout << "timeC: " << timeC << std::endl; - std::cout << "##########################################" << std::endl; - - std::cout << std::dec; - } - - //temporary, this method should be in Triggers struct, TODO - void fillTrigger(Triggers& trg) - { - trg.triggersignals = ((bool)orA << Triggers::bitA) | - ((bool)orC << Triggers::bitC) | - ((bool)vertex << Triggers::bitVertex) | - ((bool)cen << Triggers::bitCen) | - ((bool)sCen << Triggers::bitSCen); - trg.nChanA = (int8_t)nChanA; - trg.nChanC = (int8_t)nChanC; - trg.amplA = (int32_t)amplA; - trg.amplC = (int32_t)amplC; - trg.timeA = (int16_t)timeA; - trg.timeC = (int16_t)timeC; - } -} __attribute__((__packed__)); - -struct TCMdataExtended { - static constexpr size_t PayloadSize = 4; - static constexpr size_t PayloadPerGBTword = 10; - static constexpr int MinNelements = 0; - static constexpr int MaxNelements = 20; - union { - uint32_t word[1] = {}; - uint32_t triggerWord; - }; - - void print() const - { - - std::cout << std::hex; - std::cout << "############TCMdataExtended###############" << std::endl; - std::cout << "triggerWord: " << triggerWord << std::endl; - std::cout << "##########################################" << std::endl; - - std::cout << std::dec; - } -}; - +//constexpr int Nchannels_FT0 = o2::ft0::Geometry::Nchannels; +static constexpr int Nchannels_FT0 = o2::ft0::Constants::sNCHANNELS_PM; +using EventHeader = o2::fit::EventHeader; +using EventData = o2::fit::EventData; +using TCMdata = o2::fit::TCMdata; +using TCMdataExtended = o2::fit::TCMdataExtended; class RawEventData { public: RawEventData() = default; - void print(); + void print() const; const static int gStartDescriptor = 0x0000000f; - + static const size_t sPayloadSizeSecondWord = 11; + static const size_t sPayloadSizeFirstWord = 5; + static constexpr size_t sPayloadSize = 16; int size() const { return 1 // EventHeader @@ -245,27 +61,27 @@ class RawEventData std::vector<char> result(size() * CRUWordSize); char* out = result.data(); if (!tcm) { - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << "write header words " << (int)mEventHeader.nGBTWords << " orbit " << int(mEventHeader.orbit) << " bc " << int(mEventHeader.bc) << " out " << result.size(); if (mIsPadded) { - out += CRUWordSize - EventHeader::PayloadSize; + out += CRUWordSize - sPayloadSize; } for (int i = 0; i < mEventHeader.nGBTWords; ++i) { - std::memcpy(out, &mEventData[2 * i], EventData::PayloadSizeFirstWord); + std::memcpy(out, &mEventData[2 * i], sPayloadSizeFirstWord); LOG(DEBUG) << " 1st word " << mEventData[2 * i].channelID << " charge " << mEventData[2 * i].charge << " time " << mEventData[2 * i].time << " out " << result.size(); - out += EventData::PayloadSizeFirstWord; - std::memcpy(out, &mEventData[2 * i + 1], EventData::PayloadSizeSecondWord); - out += EventData::PayloadSizeSecondWord; + out += sPayloadSizeFirstWord; + std::memcpy(out, &mEventData[2 * i + 1], sPayloadSizeSecondWord); + out += sPayloadSizeSecondWord; LOG(DEBUG) << " 2nd word " << mEventData[2 * i + 1].channelID << " charge " << mEventData[2 * i + 1].charge << " time " << mEventData[2 * i + 1].time << " out " << result.size(); if (mIsPadded) { - out += CRUWordSize - EventData::PayloadSizeSecondWord - EventData::PayloadSizeFirstWord; + out += CRUWordSize - sPayloadSizeSecondWord - sPayloadSizeFirstWord; } } } else { // TCM data - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << "write TCM header words " << (int)mEventHeader.nGBTWords << " orbit " << int(mEventHeader.orbit) << " bc " << int(mEventHeader.bc) << " out " << result.size(); std::memcpy(out, &mTCMdata, sizeof(TCMdata)); out += sizeof(TCMdata); @@ -280,9 +96,9 @@ class RawEventData } public: - EventHeader mEventHeader; - EventData mEventData[Nchannels_PM]; - TCMdata mTCMdata; + EventHeader mEventHeader; //! + EventData mEventData[o2::ft0::Constants::sNCHANNELS_PER_PM]; //! + TCMdata mTCMdata; //! bool mIsPadded = true; ///////////////////////////////////////////////// ClassDefNV(RawEventData, 2); @@ -310,6 +126,7 @@ class DataPageWriter str.write(reinterpret_cast<const char*>(&mRDH), sizeof(mRDH)); str.write(mPages[page].data(), mPages[page].size()); mRDH.pageCnt++; + LOG(INFO) << " header " << mRDH.linkID << " end " << mRDH.endPointID; } if (!mPages.empty()) { mRDH.memorySize = mRDH.headerSize; diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecPoints.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecPoints.h index 27358c66afc33..a88b74962b844 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecPoints.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecPoints.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ /// \file RecPoints.h /// \brief Definition of the FIT RecPoints class + #ifndef ALICEO2_FT0_RECPOINTS_H #define ALICEO2_FT0_RECPOINTS_H @@ -27,15 +29,16 @@ namespace o2 { namespace ft0 { + struct ChannelDataFloat { int ChId = -1; //channel Id int ChainQTC = -1; //QTC chain - double CFDTime = -20000; //time in ps, 0 at the LHC clk center - double QTCAmpl = -20000; // Amplitude mV + float CFDTime = -20000; //time in ps, 0 at the LHC clk center + float QTCAmpl = -20000; // Amplitude mV ChannelDataFloat() = default; - ChannelDataFloat(int iPmt, double time, double charge, int chainQTC) + ChannelDataFloat(int iPmt, float time, float charge, int chainQTC) { ChId = iPmt; CFDTime = time; @@ -60,7 +63,7 @@ class RecPoints o2::dataformats::RangeReference<int, int> ref; o2::InteractionRecord mIntRecord; // Interaction record (orbit, bc) RecPoints() = default; - RecPoints(const std::array<Float_t, 4>& collisiontime, + RecPoints(const std::array<short, 4>& collisiontime, int first, int ne, o2::InteractionRecord iRec, o2::ft0::Triggers chTrig) : mCollisionTime(collisiontime) { @@ -73,34 +76,34 @@ class RecPoints void print() const; - o2::ft0::Triggers mTriggers; // pattern of triggers in this BC - - float getCollisionTime(int side) const { return mCollisionTime[side]; } - float getCollisionTimeMean() const { return getCollisionTime(TimeMean); } - float getCollisionTimeA() const { return getCollisionTime(TimeA); } - float getCollisionTimeC() const { return getCollisionTime(TimeC); } + short getCollisionTime(int side) const { return mCollisionTime[side]; } + short getCollisionTimeMean() const { return getCollisionTime(TimeMean); } + short getCollisionTimeA() const { return getCollisionTime(TimeA); } + short getCollisionTimeC() const { return getCollisionTime(TimeC); } bool isValidTime(int side) const { return getCollisionTime(side) < o2::InteractionRecord::DummyTime; } - void setCollisionTime(Float_t time, int side) { mCollisionTime[side] = time; } + void setCollisionTime(short time, int side) { mCollisionTime[side] = time; } - Float_t getVertex(Float_t vertex) const { return getCollisionTime(Vertex); } - void setVertex(Float_t vertex) { mCollisionTime[Vertex] = vertex; } + short getVertex() const { return getCollisionTime(Vertex); } + void setVertex(short vertex) { mCollisionTime[Vertex] = vertex; } o2::ft0::Triggers getTrigger() const { return mTriggers; } + void setTriggers(o2::ft0::Triggers trig) { mTriggers = trig; } o2::InteractionRecord getInteractionRecord() const { return mIntRecord; }; - void SetMgrEventTime(Double_t time) { mTimeStamp = time; } + // void SetMgrEventTime(Double_t time) { mTimeStamp = time; } gsl::span<const ChannelDataFloat> getBunchChannelData(const gsl::span<const ChannelDataFloat> tfdata) const; + short static constexpr sDummyCollissionTime = 32767; private: - std::array<Float_t, 4> mCollisionTime = {2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime}; - Double_t mTimeStamp = 2 * o2::InteractionRecord::DummyTime; //event time from Fair for continuous + std::array<short, 4> mCollisionTime = {sDummyCollissionTime, + sDummyCollissionTime, + sDummyCollissionTime, + sDummyCollissionTime}; + o2::ft0::Triggers mTriggers; // pattern of triggers in this BC - ClassDefNV(RecPoints, 2); + ClassDefNV(RecPoints, 3); }; } // namespace ft0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecoCalibInfoObject.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecoCalibInfoObject.h new file mode 100644 index 0000000000000..c4ae6d70e18e6 --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/RecoCalibInfoObject.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_RECOCALIBINFOOBJECT_H +#define O2_RECOCALIBINFOOBJECT_H + +#include "Rtypes.h" + +namespace o2 +{ +namespace ft0 +{ +class RecoCalibInfoObject +{ + public: + RecoCalibInfoObject(short t0a, short t0c, short t0ac) : mT0A(t0a), mT0C(t0c), mT0AC(t0ac){}; + RecoCalibInfoObject() = default; + ~RecoCalibInfoObject() = default; + + void setT0A(short time) { mT0A = time; } + void setT0C(short time) { mT0C = time; } + void setT0AC(short time) { mT0AC = time; } + [[nodiscard]] short getT0A() const { return mT0A; } + [[nodiscard]] short getT0C() const { return mT0C; } + [[nodiscard]] short getT0AC() const { return mT0AC; } + + private: + short mT0A; + short mT0C; + short mT0AC; + + ClassDefNV(RecoCalibInfoObject, 1); +}; +} // namespace ft0 +} // namespace o2 + +#endif //O2_RecoCalibINFOOBJECT_H diff --git a/DataFormats/Detectors/FIT/FT0/src/CTF.cxx b/DataFormats/Detectors/FIT/FT0/src/CTF.cxx index 7a8b5818d1d9f..52a565f60e1b2 100644 --- a/DataFormats/Detectors/FIT/FT0/src/CTF.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FT0/src/ChannelData.cxx b/DataFormats/Detectors/FIT/FT0/src/ChannelData.cxx index 8e6e43021be32..449d12ff42e69 100644 --- a/DataFormats/Detectors/FIT/FT0/src/ChannelData.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/ChannelData.cxx @@ -1,20 +1,25 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "DataFormatsFT0/ChannelData.h" +#include <Framework/Logger.h> #include <iostream> using namespace o2::ft0; void ChannelData::print() const { - printf(" ChID%d | CFDtime=%d | QTCampl=%d QTC chain %d\n", ChId, CFDTime, QTCAmpl, ChainQTC); } +void ChannelData::printLog() const +{ + LOG(INFO) << "ChId: " << static_cast<uint16_t>(ChId) << " | FEE bits:" << static_cast<uint16_t>(ChainQTC) << " | Time: " << CFDTime << " | Charge: " << QTCAmpl; +} diff --git a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h index 4ecf56013a65a..a19860cae34a7 100644 --- a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h +++ b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,16 +16,16 @@ #pragma link off all functions; #pragma link C++ class o2::ft0::Digit + ; -#pragma link C++ class o2::ft0::DigitExt + ; #pragma link C++ class o2::ft0::DigitsTemp + ; #pragma link C++ class o2::ft0::ChannelData + ; #pragma link C++ class o2::ft0::Triggers + ; +#pragma link C++ class o2::ft0::DetTrigInput + ; #pragma link C++ class o2::ft0::TriggersExt + ; #pragma link C++ class vector < o2::ft0::ChannelData> + ; #pragma link C++ class vector < o2::ft0::Digit> + ; -#pragma link C++ class vector < o2::ft0::DigitExt> + ; #pragma link C++ class vector < o2::ft0::DigitsTemp> + ; #pragma link C++ class vector < o2::ft0::Triggers> + ; +#pragma link C++ class vector < o2::ft0::DetTrigInput> + ; #pragma link C++ class vector < o2::ft0::TriggersExt> + ; #pragma link C++ class o2::ft0::RecPoints + ; @@ -33,19 +34,25 @@ #pragma link C++ class vector < o2::ft0::ChannelDataFloat> + ; #pragma link C++ class o2::ft0::MCLabel + ; +#include "SimulationDataFormat/MCTruthContainer.h" #pragma link C++ class o2::dataformats::MCTruthContainer < o2::ft0::MCLabel> + ; #pragma link C++ class o2::ft0::HitType + ; #pragma link C++ class vector < o2::ft0::HitType> + ; #pragma link C++ class o2::ft0::RawEventData + ; -#pragma link C++ class o2::ft0::EventHeader + ; -#pragma link C++ class o2::ft0::EventData + ; #pragma link C++ class o2::ft0::Topo + ; +#pragma link C++ class o2::ft0::HVchannel + ; +#pragma link C++ class vector < o2::ft0::HVchannel> + ; #pragma link C++ class o2::ft0::CTFHeader + ; #pragma link C++ class o2::ft0::CompressedDigits + ; #pragma link C++ class o2::ft0::CTF + ; -#pragma link C++ class o2::ctf::EncodedBlocks < o2::ft0::CTFHeader, 8, uint32_t> + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::ft0::CTFHeader, 9, uint32_t> + ; +#pragma link C++ class o2::ft0::GlobalOffsetsCalibrationObject + ; +#pragma link C++ class o2::ft0::GlobalOffsetsContainer + ; +#pragma link C++ class o2::ft0::RecoCalibInfoObject + ; +#include "DetectorsCalibration/TimeSlotCalibration.h" +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::RecoCalibInfoObject, o2::ft0::GlobalOffsetsContainer> + ; #endif diff --git a/DataFormats/Detectors/FIT/FT0/src/Digit.cxx b/DataFormats/Detectors/FIT/FT0/src/Digit.cxx index 70fddb74696d1..42a650513f1a3 100644 --- a/DataFormats/Detectors/FIT/FT0/src/Digit.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,12 +11,21 @@ #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" +#include <Framework/Logger.h> #include <iostream> #include <gsl/span> #include <bitset> using namespace o2::ft0; +void Triggers::printLog() const +{ + LOG(INFO) << "mTrigger: " << static_cast<uint16_t>(triggersignals); + LOG(INFO) << "nChanA: " << static_cast<uint16_t>(nChanA) << " | nChanC: " << static_cast<uint16_t>(nChanC); + LOG(INFO) << "amplA: " << amplA << " | amplC: " << amplC; + LOG(INFO) << "timeA: " << timeA << " | timeC: " << timeC; +} + gsl::span<const ChannelData> Digit::getBunchChannelData(const gsl::span<const ChannelData> tfdata) const { // extract the span of channel data for this bunch from the whole TF data @@ -33,3 +43,18 @@ std::ostream& operator<<(std::ostream& stream, const Digit& digi) digi.printStream(stream); return stream; } +void Digit::printLog() const +{ + LOG(INFO) << "______________DIGIT DATA____________"; + LOG(INFO) << "BC: " << mIntRecord.bc << "| ORBIT: " << mIntRecord.orbit; + LOG(INFO) << "Ref first: " << ref.getFirstEntry() << "| Ref entries: " << ref.getEntries(); + mTriggers.printLog(); +} +void TriggersExt::printLog() const +{ + LOG(INFO) << "______________EXTENDED TRIGGERS____________"; + LOG(INFO) << "BC: " << mIntRecord.bc << "| ORBIT: " << mIntRecord.orbit; + for (int i = 0; i < 20; i++) { + LOG(INFO) << "N: " << i + 1 << " | TRG: " << mTriggerWords[i]; + } +} \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/src/DigitsTemp.cxx b/DataFormats/Detectors/FIT/FT0/src/DigitsTemp.cxx index 10baf8fe41dc1..f27d81a83fe68 100644 --- a/DataFormats/Detectors/FIT/FT0/src/DigitsTemp.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/DigitsTemp.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FT0/src/FT0ChannelTimeCalibrationObject.cxx b/DataFormats/Detectors/FIT/FT0/src/FT0ChannelTimeCalibrationObject.cxx new file mode 100644 index 0000000000000..5806ed10d891c --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/src/FT0ChannelTimeCalibrationObject.cxx @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" + +using namespace o2::ft0; + +FT0ChannelTimeCalibrationObject FT0TimeChannelOffsetCalibrationObjectAlgorithm::generateCalibrationObject(const FT0ChannelTimeTimeSlotContainer& container) +{ + FT0ChannelTimeCalibrationObject calibrationObject; + + for (unsigned int iCh = 0; iCh < o2::ft0::Nchannels_FT0; ++iCh) { + calibrationObject.mTimeOffsets[iCh] = container.getMeanGaussianFitValue(iCh); + } + + return calibrationObject; +} diff --git a/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsCalibrationObject.cxx b/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsCalibrationObject.cxx new file mode 100644 index 0000000000000..df5f657e81933 --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsCalibrationObject.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsFT0/GlobalOffsetsCalibrationObject.h" +#include "DataFormatsFT0/GlobalOffsetsContainer.h" +#include "Framework/Logger.h" +#include <TString.h> +using namespace o2::ft0; + +GlobalOffsetsCalibrationObject GlobalOffsetsCalibrationObjectAlgorithm::generateCalibrationObject(const GlobalOffsetsContainer& container) +{ + GlobalOffsetsCalibrationObject calibrationObject; + TString side[3] = {"A", "C", "AC"}; + for (unsigned int iCh = 0; iCh < 3; ++iCh) { + calibrationObject.mCollisionTimeOffsets[iCh] = container.getMeanGaussianFitValue(iCh); + LOG(DEBUG) << "GlobalOffsetsCalibrationObjectAlgorithm generate CalibrationObject for T0" << side[iCh].Data() << " = " << calibrationObject.mCollisionTimeOffsets[iCh]; + } + + return calibrationObject; +} diff --git a/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsContainer.cxx b/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsContainer.cxx new file mode 100644 index 0000000000000..83490335d932e --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/src/GlobalOffsetsContainer.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsFT0/GlobalOffsetsContainer.h" +#include <numeric> +#include <algorithm> +#include "MathUtils/fit.h" +#include <TFitResult.h> +#include <gsl/span> + +using namespace o2::ft0; + +GlobalOffsetsContainer::GlobalOffsetsContainer(std::size_t minEntries) + : mMinEntries(minEntries) +{ + TString histnames[3] = {"hT0A", "hT0C", "hT0AC"}; + for (int ihist = 0; ihist < 3; ++ihist) { + mHistogram[ihist] = new TH1F(histnames[ihist].Data(), histnames[ihist].Data(), NUMBER_OF_HISTOGRAM_BINS, -HISTOGRAM_RANGE, HISTOGRAM_RANGE); + } +} + +bool GlobalOffsetsContainer::hasEnoughEntries() const +{ + LOG(DEBUG) << "@@@ GlobalOffsetsContainer::hasEnoughEntries " << *std::min_element(mEntriesCollTime.begin(), mEntriesCollTime.end()); + return *std::min_element(mEntriesCollTime.begin(), mEntriesCollTime.end()) > mMinEntries; +} +void GlobalOffsetsContainer::fill(const gsl::span<const o2::ft0::RecoCalibInfoObject>& data) +{ + for (auto& entry : data) { + if (std::abs(entry.getT0A()) < HISTOGRAM_RANGE && std::abs(entry.getT0C()) < HISTOGRAM_RANGE && std::abs(entry.getT0AC()) < HISTOGRAM_RANGE) { + mHistogram[0]->Fill(entry.getT0A()); + mHistogram[1]->Fill(entry.getT0C()); + mHistogram[2]->Fill(entry.getT0AC()); + ++mEntriesCollTime[0]; + ++mEntriesCollTime[1]; + ++mEntriesCollTime[2]; + } else { + LOG(DEBUG) << "empty data A " << entry.getT0A() << " C " << entry.getT0C(); + } + } +} + +void GlobalOffsetsContainer::merge(GlobalOffsetsContainer* prev) +{ + LOG(DEBUG) << "@@@ GlobalOffsetsContainer::merge"; + for (int ihist = 0; ihist < 3; ++ihist) { + mHistogram[ihist]->Add(prev->mHistogram[ihist], mHistogram[ihist], 1, 1); + } +} + +int16_t GlobalOffsetsContainer::getMeanGaussianFitValue(std::size_t side) const +{ + + // static constexpr size_t MEAN_VALUE_INDEX_IN_OUTPUT_VECTOR = 1; + + if (0 == mHistogram[side]->GetEntries()) { + return 0; + } + + TFitResultPtr returnCode = mHistogram[side]->Fit("gaus", "SQ"); + if (returnCode < 0) { + LOG(ERROR) << "Gaussian fit error!"; + return 0; + } + double meanfit = 0; + if ((Int_t)returnCode == 0) { + meanfit = returnCode->Parameter(1); + } + LOG(DEBUG) << " @@@ MeanGaussianFitValue " << meanfit; + return meanfit; +} + +void GlobalOffsetsContainer::print() const +{ + for (int ihist = 0; ihist < 3; ++ihist) { + LOG(INFO) << "Container keep data for global offsets calibration:"; + LOG(INFO) << "Gaussian mean time A side " << getMeanGaussianFitValue(0) << " based on" << mEntriesCollTime[0] << " entries"; + LOG(INFO) << "Gaussian mean time C side " << getMeanGaussianFitValue(1) << " based on" << mEntriesCollTime[1] << " entries"; + LOG(INFO) << "Gaussian mean time AC side " << getMeanGaussianFitValue(2) << " based on" << mEntriesCollTime[2] << " entries"; + } +} diff --git a/DataFormats/Detectors/FIT/FT0/src/RawEventData.cxx b/DataFormats/Detectors/FIT/FT0/src/RawEventData.cxx index 1ee3d9f348a03..a88b517791f7b 100644 --- a/DataFormats/Detectors/FIT/FT0/src/RawEventData.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/RawEventData.cxx @@ -1,18 +1,14 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "DataFormatsFT0/RawEventData.h" -#include <CommonDataFormat/InteractionRecord.h> -#include <Framework/Logger.h> -#include <iostream> using namespace o2::ft0; - -ClassImp(RawEventData); \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/src/RecPoints.cxx b/DataFormats/Detectors/FIT/FT0/src/RecPoints.cxx index 3248114dc7a4a..f580d0dd1ea8c 100644 --- a/DataFormats/Detectors/FIT/FT0/src/RecPoints.cxx +++ b/DataFormats/Detectors/FIT/FT0/src/RecPoints.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FV0/CMakeLists.txt b/DataFormats/Detectors/FIT/FV0/CMakeLists.txt index faa74c2eaccff..0ed3869a7a9fc 100644 --- a/DataFormats/Detectors/FIT/FV0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FV0/CMakeLists.txt @@ -1,29 +1,33 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsFV0 SOURCES src/Hit.cxx src/ChannelData.cxx src/BCData.cxx + src/RecPoints.cxx src/RawEventData.cxx src/CTF.cxx PUBLIC_LINK_LIBRARIES O2::FV0Base + O2::DataFormatsFIT O2::SimulationDataFormat O2::CommonDataFormat - ms_gsl::ms_gsl) + Microsoft.GSL::GSL) o2_target_root_dictionary(DataFormatsFV0 HEADERS include/DataFormatsFV0/Hit.h include/DataFormatsFV0/BCData.h include/DataFormatsFV0/MCLabel.h include/DataFormatsFV0/ChannelData.h + include/DataFormatsFV0/RecPoints.h include/DataFormatsFV0/RawEventData.h include/DataFormatsFV0/LookUpTable.h include/DataFormatsFV0/CTF.h) diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/BCData.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/BCData.h index 238ddf2551072..4ca9cbc3f1cf0 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/BCData.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/BCData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,9 @@ #include "CommonDataFormat/RangeReference.h" #include <Rtypes.h> #include <gsl/span> - +#include <bitset> +#include <vector> +#include <tuple> /// \file BCData.h /// \brief Class to describe fired triggered and/or stored channels for the BC and to refer to channel data /// \author ruben.shahoyan@cern.ch -> maciej.slupecki@cern.ch @@ -26,25 +29,116 @@ namespace fv0 { class ChannelData; +struct Triggers { + enum { + bitMinBias, + bitMinBiasInner, // experimental + bitMinBiasOuter, // experimental + bitHighMult, + bitDummy // non-defined yet, placeholder + }; + uint8_t triggerSignals = 0; // V0 trigger signals + int8_t nChanA = 0; // number of fired channels [A side] + int32_t amplA = -1000; // sum amplitude [A side] + Triggers() = default; + Triggers(uint8_t signals, int8_t chanA, int32_t amplASum) + { + triggerSignals = signals; + nChanA = chanA; + amplA = amplASum; + } + + bool getIsMinBias() const { return (triggerSignals & (1 << bitMinBias)) != 0; } + bool getIsMinBiasInner() const { return (triggerSignals & (1 << bitMinBiasInner)) != 0; } + bool getIsMinBiasOuter() const { return (triggerSignals & (1 << bitMinBiasOuter)) != 0; } + bool getIsHighMult() const { return (triggerSignals & (1 << bitHighMult)) != 0; } + bool getIsDummy() const { return (triggerSignals & (1 << bitDummy)) != 0; } + void setTriggers(Bool_t isMinBias, Bool_t isMinBiasInner, Bool_t isMinBiasOuter, Bool_t isHighMult, Bool_t isDummy, int8_t chanA, int32_t amplASum) + { + triggerSignals = (isMinBias << bitMinBias) | (isMinBiasInner << bitMinBiasInner) | (isMinBiasOuter << bitMinBiasOuter) | (isHighMult << bitHighMult) | (isDummy << bitDummy); + nChanA = chanA; + amplA = amplASum; + } + bool operator==(Triggers const& other) const + { + //Will be implemented later + //return std::tie(triggersignals, nChanA, nChanC, amplA, amplC, timeA, timeC) == + // std::tie(other.triggersignals, other.nChanA, other.nChanC, other.amplA, other.amplC, other.timeA, other.timeC); + return std::tie(triggerSignals, nChanA, amplA) == + std::tie(other.triggerSignals, other.nChanA, other.amplA); + } + void printLog() const; + ClassDefNV(Triggers, 1); +}; + +struct DetTrigInput { + static constexpr char sChannelNameDPL[] = "TRIGGERINPUT"; + static constexpr char sDigitName[] = "DetTrigInput"; + static constexpr char sDigitBranchName[] = "FV0TRIGGERINPUT"; + o2::InteractionRecord mIntRecord; // bc/orbit of the intpur + std::bitset<5> mInputs; // pattern of inputs. + DetTrigInput() = default; + DetTrigInput(const o2::InteractionRecord& iRec, Bool_t isMb, Bool_t isMbIn, Bool_t isMbOut, Bool_t isHm, Bool_t isDummy) + : mIntRecord(iRec), + mInputs((isMb << Triggers::bitMinBias) | + (isMbIn << Triggers::bitMinBiasInner) | + (isMbOut << Triggers::bitMinBiasOuter) | + (isHm << Triggers::bitHighMult) | + (isDummy << Triggers::bitDummy)) + { + } + ClassDefNV(DetTrigInput, 1); +}; + struct BCData { + static constexpr char sChannelNameDPL[] = "DIGITSBC"; + static constexpr char sDigitName[] = "BCData"; + static constexpr char sDigitBranchName[] = "FV0DigitBC"; /// we are going to refer to at most 48 channels, so 6 bits for the number of channels and 26 for the reference o2::dataformats::RangeRefComp<6> ref; - o2::InteractionRecord ir; - + o2::InteractionRecord ir; //FV0 is detected by using this field!!! + Triggers mTriggers; BCData() = default; - BCData(int first, int ne, o2::InteractionRecord iRec) + BCData(int first, int ne, o2::InteractionRecord iRec, const Triggers& chTrig) { ref.setFirstEntry(first); ref.setEntries(ne); ir = iRec; + mTriggers = chTrig; } - + typedef DetTrigInput DetTrigInput_t; gsl::span<const ChannelData> getBunchChannelData(const gsl::span<const ChannelData> tfdata) const; const o2::InteractionRecord& getIntRecord() const { return ir; }; + Triggers getTriggers() const { return mTriggers; } + void setIntRecord(const o2::InteractionRecord& intRec) { ir = intRec; } + void setTriggers(Triggers triggers) { mTriggers = triggers; }; void print() const; - + bool operator==(const BCData& other) const + { + return std::tie(ref, mTriggers, ir) == std::tie(other.ref, other.mTriggers, other.ir); + } + void printLog() const; + DetTrigInput makeTrgInput() const { return DetTrigInput{ir, mTriggers.getIsMinBias(), mTriggers.getIsMinBiasInner(), mTriggers.getIsMinBiasOuter(), mTriggers.getIsHighMult(), mTriggers.getIsDummy()}; } + void fillTrgInputVec(std::vector<DetTrigInput>& vecTrgInput) const + { + vecTrgInput.emplace_back(ir, mTriggers.getIsMinBias(), mTriggers.getIsMinBiasInner(), mTriggers.getIsMinBiasOuter(), mTriggers.getIsHighMult(), mTriggers.getIsDummy()); + } ClassDefNV(BCData, 1); }; + +//For TCM extended mode (calibration mode), TCMdataExtended digit +struct TriggersExt { + TriggersExt(std::array<uint32_t, 20> triggerWords) : mTriggerWords(triggerWords) {} + TriggersExt() = default; + static constexpr char sChannelNameDPL[] = "DIGITSTRGEXT"; + static constexpr char sDigitName[] = "TriggersExt"; + static constexpr char sDigitBranchName[] = "FV0DIGITSTRGEXT"; + o2::InteractionRecord mIntRecord; + void setTrgWord(uint32_t trgWord, std::size_t pos) { mTriggerWords[pos] = trgWord; } + std::array<uint32_t, 20> mTriggerWords; + void printLog() const; + ClassDefNV(TriggersExt, 1); +}; } // namespace fv0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/CTF.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/CTF.h index d2c7be2fb6d4d..d461a7e7710d6 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/CTF.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,12 +26,12 @@ namespace fv0 { /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nTriggers = 0; /// number of triggers in TF uint32_t firstOrbit = 0; /// 1st orbit of TF uint16_t firstBC = 0; /// 1st BC of TF - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// Intermediate, compressed but not yet entropy-encoded digits diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h index 5cda22e706ab8..32513f4b776e8 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,9 +12,10 @@ #ifndef _FV0_CHANNEL_DATA_H_ #define _FV0_CHANNEL_DATA_H_ +#include <Framework/Logger.h> #include <array> #include <Rtypes.h> - +#include <tuple> /// \file ChannelData.h /// \brief Container class to store time and charge values of single FV0 channel @@ -23,6 +25,9 @@ namespace fv0 { struct ChannelData { + static constexpr char sChannelNameDPL[] = "DIGITSCH"; + static constexpr char sDigitName[] = "ChannelData"; + static constexpr char sDigitBranchName[] = "FV0DigitCh"; Short_t pmtNumber = -1; // PhotoMultiplier number (0 to 47) Short_t time = -1; // [ns] Time associated with rising edge of the singal in a given channel Short_t chargeAdc = -1; // ADC sample as present in raw data @@ -34,9 +39,13 @@ struct ChannelData { time = t; chargeAdc = charge; } - + Short_t getChannelID() const { return pmtNumber; } void print() const; - + void printLog() const; + bool operator==(ChannelData const& other) const + { + return std::tie(pmtNumber, time, chargeAdc) == std::tie(other.pmtNumber, other.time, other.chargeAdc); + } ClassDefNV(ChannelData, 1); }; } // namespace fv0 diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/Hit.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/Hit.h index d15d8af19f7cc..4570caaa90a3e 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/Hit.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/LookUpTable.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/LookUpTable.h index d87375bacde84..9e7fcb50f5500 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/LookUpTable.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/LookUpTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ // Look Up Table FV0 ////////////////////////////////////////////// +#include "DataFormatsFIT/LookUpTable.h" #include <Rtypes.h> #include <cassert> #include <iostream> @@ -78,20 +80,19 @@ class LookUpTable int getLink(int channel) const { return mTopoVector[channel].pmLink; } int getPmChannel(int channel) const { return mTopoVector[channel].pmCh; } int getTcmLink() const { return mLinkTCM; } + bool isTCM(int link, int ep) const { return link == getTcmLink() && ep == 0; } + Topo getTopoPM(int globalChannelID) const { return mTopoVector[globalChannelID]; } + Topo getTopoTCM() const { return Topo{getTcmLink(), 0}; } + std::size_t getNchannels() const { return mTopoVector.size(); } //get number of global PM channels void printFullMap() const { - std::cout << "o2::fv0::LookUpTable::printFullMap(): mTopoVector: [globalCh link pmCh]" << std::endl; + LOG(INFO) << "o2::fv0::LookUpTable::printFullMap(): mTopoVector: [globalCh link pmCh]"; for (size_t channel = 0; channel < mTopoVector.size(); ++channel) { - std::cout << " " << std::right << std::setw(2) << channel << " "; - std::cout << std::right << std::setw(2) << mTopoVector[channel].pmLink << " "; - std::cout << std::right << std::setw(3) << mTopoVector[channel].pmCh << std::endl; + LOG(INFO) << channel << " " << mTopoVector[channel].pmLink << " " << mTopoVector[channel].pmCh; } - std::cout << "o2::fv0::LookUpTable::printFullMap(): mInvTopo: [idx globalCh link pmCh]" << std::endl; + LOG(INFO) << "o2::fv0::LookUpTable::printFullMap(): mInvTopo: [idx globalCh link pmCh]"; for (size_t idx = 0; idx < mInvTopo.size(); ++idx) { - std::cout << " " << std::right << std::setw(3) << idx << " "; - std::cout << std::right << std::setw(3) << mInvTopo[idx] << " "; - std::cout << std::right << std::setw(2) << getLinkFromIdx(mInvTopo[idx]) << " "; - std::cout << std::right << std::setw(2) << getPmChannelFromIdx(mInvTopo[idx]) << std::endl; + LOG(INFO) << idx << " " << mInvTopo[idx] << " " << getLinkFromIdx(mInvTopo[idx]) << " " << getPmChannelFromIdx(mInvTopo[idx]); } } @@ -110,6 +111,122 @@ class LookUpTable ClassDefNV(LookUpTable, 1); }; +namespace deprecated +{ +//Singleton for LookUpTable +class SingleLUT : public LookUpTable +{ + private: + SingleLUT() : LookUpTable(true) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + typedef Topo Topo_t; + static constexpr char sDetectorName[] = "FV0"; + static SingleLUT& Instance() + { + static SingleLUT instanceLUT; + return instanceLUT; + } + //Temporary + //Making Topo for FEE recognizing(Local channelID is supressed) + static Topo_t makeGlobalTopo(const Topo_t& topo) + { + return Topo_t{topo.pmLink, 0}; + } + static int getLocalChannelID(const Topo_t& topo) + { + return topo.pmCh; + } + //Prepare full map for FEE metadata + template <typename RDHtype, typename RDHhelper = void> + auto makeMapFEEmetadata() -> std::map<Topo_t, RDHtype> + { + std::map<Topo_t, RDHtype> mapResult; + const uint16_t cruID = 0; //constant + const uint32_t endPointID = 0; //constant + uint64_t feeID = 0; //increments + //PM + for (int iCh = 0; iCh < Instance().getNchannels(); iCh++) { + auto pairInserted = mapResult.insert({makeGlobalTopo(Instance().getTopoPM(iCh)), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.pmLink; + rdhObj.endPointID = endPointID; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.pmLink); + RDHhelper::setEndPointID(&rdhObj, endPointID); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + feeID++; + } + } + //TCM + { + auto pairInserted = mapResult.insert({makeGlobalTopo(Instance().getTopoTCM()), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.pmLink; + rdhObj.endPointID = endPointID; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.pmLink); + RDHhelper::setEndPointID(&rdhObj, endPointID); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + } else { + LOG(INFO) << "WARNING! CHECK LUT! TCM METADATA IS INCORRECT!"; + } + } + assert(mapResult.size() > 0); + return mapResult; + } +}; +} //namespace deprecated + +namespace new_lut +{ +//Singleton for LookUpTable +template <typename LUT> +class SingleLUT : public LUT +{ + private: + SingleLUT(const std::string& ccdbPath, const std::string& ccdbPathToLUT) : LUT(ccdbPath, ccdbPathToLUT) {} + SingleLUT(const std::string& pathToFile) : LUT(pathToFile) {} + SingleLUT(const SingleLUT&) = delete; + SingleLUT& operator=(SingleLUT&) = delete; + + public: + static constexpr char sDetectorName[] = "FV0"; + static constexpr char sDefaultCCDBpath[] = "http://ccdb-test.cern.ch:8080/"; + static constexpr char sDefaultLUTpath[] = "FV0/LookUpTable"; + inline static std::string sCurrentCCDBpath = sDefaultCCDBpath; + inline static std::string sCurrentLUTpath = sDefaultLUTpath; + //Before instance() call, setup url and path + static void setCCDBurl(const std::string& url) { sCurrentCCDBpath = url; } + static void setLUTpath(const std::string& path) { sCurrentLUTpath = path; } + static SingleLUT& Instance() + { + static SingleLUT instanceLUT(sCurrentCCDBpath, sCurrentLUTpath); + return instanceLUT; + } +}; +} //namespace new_lut + +using SingleLUT = new_lut::SingleLUT<o2::fit::LookupTableBase<>>; +//using SingleLUT = deprecated::SingleLUT; } // namespace fv0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/MCLabel.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/MCLabel.h index 1a89cfba5f514..c770634ce7297 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/MCLabel.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RawEventData.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RawEventData.h index 383f46e9fba07..ca61cd6aeab61 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RawEventData.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RawEventData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,102 +17,31 @@ #define ALICEO2_FV0_RAWEVENTDATA_H_ #include "FV0Base/Constants.h" -#include "DataFormatsFV0/ChannelData.h" #include "Headers/RAWDataHeader.h" -#include "DataFormatsFV0/LookUpTable.h" +#include "DataFormatsFIT/RawEventData.h" #include <CommonDataFormat/InteractionRecord.h> #include <Framework/Logger.h> -#include <iostream> -#include <iomanip> #include <cstring> +#include <iomanip> #include "Rtypes.h" namespace o2 { namespace fv0 { -struct EventHeader { - static constexpr int PayloadSize = 16; - union { - uint64_t word[2] = {}; - struct { - uint64_t bc : 12; - uint64_t orbit : 32; - uint64_t reservedField1 : 20; - uint64_t reservedField2 : 8; - uint64_t nGBTWords : 4; - uint64_t startDescriptor : 4; - uint64_t reservedField3 : 48; - }; - }; -}; -struct EventData { - union { - uint64_t word = {0}; - struct { - int64_t time : 12; - int64_t charge : 13; - uint64_t numberADC : 1, - isDoubleEvent : 1, - is1TimeLostEvent : 1, - is2TimeLostEvent : 1, - isADCinGate : 1, - isTimeInfoLate : 1, - isAmpHigh : 1, - isEventInTVDC : 1, - isTimeInfoLost : 1, - reservedField : 2, - channelID : 4; - }; - }; - uint64_t word_zeros = 0x0; - static const size_t PayloadSizeSecondWord = 11; - static const size_t PayloadSizeFirstWord = 5; - void generateFlags() - { - numberADC = std::rand() % 2; - isDoubleEvent = 0; - is1TimeLostEvent = 0; - is2TimeLostEvent = 1; - isADCinGate = 0; - isTimeInfoLate = 0; - isAmpHigh = 0; - isEventInTVDC = 1; - isTimeInfoLost = 0; - } -}; - -struct TCMdata { - static constexpr int PayloadSize = 16; - union { - uint64_t word[2] = {0}; - struct { - uint64_t orC : 1, - orA : 1, - sCen : 1, - cen : 1, - vertex : 1, - nChanA : 7, - nChanC : 7; - int64_t amplA : 18, - amplC : 18, - reservedField1 : 1, //56B, PayloadSize1stWord 6 - timeA : 9, - timeC : 9, - reservedField2 : 46; - }; - }; -}; - +using EventHeader = o2::fit::EventHeader; +using EventData = o2::fit::EventData; +using TCMdata = o2::fit::TCMdata; +using TCMdataExtended = o2::fit::TCMdataExtended; class RawEventData { public: RawEventData() = default; EventHeader* getEventHeaderPtr() { return &mEventHeader; } EventData* getEventDataPtr() { return mEventData; } - void print(); - void printHexEventHeader(); - void printHexEventData(uint64_t i); + void print() const; + void printHexEventHeader() const; + void printHexEventData(uint64_t i) const; enum EEventDataBit { kNumberADC, kIsDoubleEvent, kIs1TimeLostEvent, @@ -122,7 +52,9 @@ class RawEventData kIsEventInTVDC, kIsTimeInfoLost }; const static int gStartDescriptor = 0x0000000f; - + static const size_t sPayloadSizeSecondWord = 11; + static const size_t sPayloadSizeFirstWord = 5; + static constexpr size_t sPayloadSize = 16; int size() const { return 1 + mEventHeader.nGBTWords; // EventHeader + EventData size @@ -135,34 +67,34 @@ class RawEventData std::vector<char> result(size() * CRUWordSize); char* out = result.data(); if (!tcm) { - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << " Write PM header: nWords: " << (int)mEventHeader.nGBTWords << " orbit: " << int(mEventHeader.orbit) << " BC: " << int(mEventHeader.bc) << " size: " << result.size(); printHexEventHeader(); - out += CRUWordSize - EventHeader::PayloadSize; // Padding enabled + out += CRUWordSize - sPayloadSize; // Padding enabled for (uint64_t i = 0; i < mEventHeader.nGBTWords; ++i) { - std::memcpy(out, &mEventData[2 * i], EventData::PayloadSizeFirstWord); - out += EventData::PayloadSizeFirstWord; + std::memcpy(out, &mEventData[2 * i], sPayloadSizeFirstWord); + out += sPayloadSizeFirstWord; LOG(DEBUG) << " 1st word: Ch: " << std::setw(2) << mEventData[2 * i].channelID << " charge: " << std::setw(4) << mEventData[2 * i].charge << " time: " << std::setw(4) << mEventData[2 * i].time; - std::memcpy(out, &mEventData[2 * i + 1], EventData::PayloadSizeSecondWord); - out += EventData::PayloadSizeSecondWord; + std::memcpy(out, &mEventData[2 * i + 1], sPayloadSizeSecondWord); + out += sPayloadSizeSecondWord; LOG(DEBUG) << " 2nd word: Ch: " << std::setw(2) << mEventData[2 * i + 1].channelID << " charge: " << std::setw(4) << mEventData[2 * i + 1].charge << " time: " << std::setw(4) << mEventData[2 * i + 1].time; - out += CRUWordSize - EventData::PayloadSizeSecondWord - EventData::PayloadSizeFirstWord; + out += CRUWordSize - sPayloadSizeSecondWord - sPayloadSizeFirstWord; printHexEventData(i); } } else { // TCM data - std::memcpy(out, &mEventHeader, EventHeader::PayloadSize); - out += EventHeader::PayloadSize; + std::memcpy(out, &mEventHeader, sPayloadSize); + out += sPayloadSize; LOG(DEBUG) << " Write TCM header: nWords: " << (int)mEventHeader.nGBTWords << " orbit: " << int(mEventHeader.orbit) << " BC: " << int(mEventHeader.bc) @@ -175,9 +107,9 @@ class RawEventData } public: - EventHeader mEventHeader; - EventData mEventData[Constants::nChannelsPerPm]; - TCMdata mTCMdata; + EventHeader mEventHeader; //! + EventData mEventData[Constants::nChannelsPerPm]; //! + TCMdata mTCMdata; //! ClassDefNV(RawEventData, 1); }; diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h new file mode 100644 index 0000000000000..1f23c06d2a485 --- /dev/null +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecPoints.h +/// \brief Definition of the FV0 RecPoints class + +#ifndef ALICEO2_FV0_RECPOINTS_H +#define ALICEO2_FV0_RECPOINTS_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "DataFormatsFV0/ChannelData.h" +#include "CommonDataFormat/RangeReference.h" +#include "DataFormatsFV0/BCData.h" +#include <array> +#include "Rtypes.h" +#include <TObject.h> +#include <gsl/span> + +namespace o2 +{ +namespace fv0 +{ +struct ChannelDataFloat { + + int channel = -1; // channel Id + double time = -20000; // time in ps, 0 at the LHC clk center + double charge = -20000; // charge [channels] + int adcId = -1; // QTC chain + + ChannelDataFloat() = default; + ChannelDataFloat(int Channel, double Time, double Charge, int AdcId) + { + channel = Channel; + time = Time; + charge = Charge; + adcId = AdcId; + } + + void print() const; + + ClassDefNV(ChannelDataFloat, 1); +}; + +class RecPoints +{ + + public: + enum TimeTypeIndex : int { TimeFirst, + TimeGlobalMean, + TimeSelectedMean }; + RecPoints() = default; + RecPoints(const std::array<short, 3>& collisiontime, int first, int ne, + o2::InteractionRecord iRec, o2::fv0::Triggers triggers) + : mCollisionTimePs(collisiontime) + { + mRef.setFirstEntry(first); + mRef.setEntries(ne); + mIntRecord = iRec; + mTriggers = triggers; + } + ~RecPoints() = default; + + float getCollisionTime(TimeTypeIndex type) const { return mCollisionTimePs[type]; } + float getCollisionFirstTime() const { return getCollisionTime(TimeFirst); } + float getCollisionGlobalMeanTime() const { return getCollisionTime(TimeGlobalMean); } + float getCollisionSelectedMeanTime() const { return getCollisionTime(TimeSelectedMean); } + bool isValidTime(TimeTypeIndex type) const { return getCollisionTime(type) < sDummyCollissionTime; } + void setCollisionTime(Float_t time, TimeTypeIndex type) { mCollisionTimePs[type] = time; } + + o2::fv0::Triggers getTrigger() const { return mTriggers; } + o2::InteractionRecord getInteractionRecord() const { return mIntRecord; }; + gsl::span<const ChannelDataFloat> getBunchChannelData(const gsl::span<const ChannelDataFloat> tfdata) const; + short static constexpr sDummyCollissionTime = 32767; + + private: + o2::dataformats::RangeReference<int, int> mRef; + o2::InteractionRecord mIntRecord; + o2::fv0::Triggers mTriggers; // pattern of triggers in this BC + std::array<short, 3> mCollisionTimePs = {sDummyCollissionTime, sDummyCollissionTime, sDummyCollissionTime}; // in picoseconds + + ClassDefNV(RecPoints, 1); +}; +} // namespace fv0 +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/FIT/FV0/src/BCData.cxx b/DataFormats/Detectors/FIT/FV0/src/BCData.cxx index 090191ec28ebe..cbf0f46ad3581 100644 --- a/DataFormats/Detectors/FIT/FV0/src/BCData.cxx +++ b/DataFormats/Detectors/FIT/FV0/src/BCData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,14 @@ using namespace o2::fv0; +void Triggers::printLog() const +{ + LOG(INFO) << "mTrigger: " << static_cast<uint16_t>(triggerSignals); + LOG(INFO) << "nChanA: " << static_cast<uint16_t>(nChanA) /* << " | nChanC: " << static_cast<uint16_t>(nChanC)*/; + LOG(INFO) << "amplA: " << amplA /* << " | amplC: " << amplC*/; + // LOG(INFO) << "timeA: " << timeA << " | timeC: " << timeC; +} + void BCData::print() const { ir.print(); @@ -25,3 +34,18 @@ gsl::span<const ChannelData> BCData::getBunchChannelData(const gsl::span<const C // extract the span of channel data for this bunch from the whole TF data return ref.getEntries() ? gsl::span<const ChannelData>(&tfdata[ref.getFirstEntry()], ref.getEntries()) : gsl::span<const ChannelData>(); } +void BCData::printLog() const +{ + LOG(INFO) << "______________DIGIT DATA____________"; + LOG(INFO) << "BC: " << ir.bc << "| ORBIT: " << ir.orbit; + LOG(INFO) << "Ref first: " << ref.getFirstEntry() << "| Ref entries: " << ref.getEntries(); + mTriggers.printLog(); +} +void TriggersExt::printLog() const +{ + LOG(INFO) << "______________EXTENDED TRIGGERS____________"; + LOG(INFO) << "BC: " << mIntRecord.bc << "| ORBIT: " << mIntRecord.orbit; + for (int i = 0; i < 20; i++) { + LOG(INFO) << "N: " << i + 1 << " | TRG: " << mTriggerWords[i]; + } +} \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FV0/src/CTF.cxx b/DataFormats/Detectors/FIT/FV0/src/CTF.cxx index 8b85884c7e091..8d5cdeda5919b 100644 --- a/DataFormats/Detectors/FIT/FV0/src/CTF.cxx +++ b/DataFormats/Detectors/FIT/FV0/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/FIT/FV0/src/ChannelData.cxx b/DataFormats/Detectors/FIT/FV0/src/ChannelData.cxx index 7507b29c0f033..987b13c2208a4 100644 --- a/DataFormats/Detectors/FIT/FV0/src/ChannelData.cxx +++ b/DataFormats/Detectors/FIT/FV0/src/ChannelData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,3 +17,8 @@ void ChannelData::print() const { printf(" Pmt=%2d | time =%4d | charge =%6d\n", pmtNumber, time, chargeAdc); } + +void ChannelData::printLog() const +{ + LOG(INFO) << "ChId: " << static_cast<uint16_t>(pmtNumber) /*<< " | FEE bits:" << static_cast<uint16_t>(ChainQTC)*/ << " | Time: " << time << " | Charge: " << chargeAdc; +} \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h b/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h index baa12012401b6..2ea29e691773f 100644 --- a/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h +++ b/DataFormats/Detectors/FIT/FV0/src/DataFormatsFV0LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,17 +21,23 @@ #pragma link C++ class o2::fv0::ChannelData + ; #pragma link C++ class o2::fv0::BCData + ; +#pragma link C++ class o2::fv0::Triggers + ; +#pragma link C++ class o2::fv0::DetTrigInput + ; #pragma link C++ class std::vector < o2::fv0::ChannelData> + ; +#pragma link C++ class std::vector < o2::fv0::Triggers> + ; +#pragma link C++ class std::vector < o2::fv0::DetTrigInput> + ; #pragma link C++ class std::vector < o2::fv0::BCData> + ; #pragma link C++ class o2::fv0::RawEventData + ; -#pragma link C++ class o2::fv0::EventHeader + ; -#pragma link C++ class o2::fv0::EventData + ; -#pragma link C++ class o2::fv0::TCMdata + ; #pragma link C++ class o2::fv0::Topo + ; #pragma link C++ class o2::fv0::CTFHeader + ; #pragma link C++ class o2::fv0::CTF + ; #pragma link C++ class o2::ctf::EncodedBlocks < o2::fv0::CTFHeader, 6, uint32_t> + ; +#pragma link C++ class o2::fv0::RecPoints + ; +#pragma link C++ class vector < o2::fv0::RecPoints> + ; +#pragma link C++ class o2::fv0::ChannelDataFloat + ; +#pragma link C++ class vector < o2::fv0::ChannelDataFloat> + ; + #endif diff --git a/DataFormats/Detectors/FIT/FV0/src/Hit.cxx b/DataFormats/Detectors/FIT/FV0/src/Hit.cxx index e86ed0acb8d89..23b11573e5552 100644 --- a/DataFormats/Detectors/FIT/FV0/src/Hit.cxx +++ b/DataFormats/Detectors/FIT/FV0/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,17 +20,17 @@ ClassImp(o2::fv0::Hit); namespace o2 { - namespace fv0 - { +namespace fv0 +{ - void Hit::Print(const Option_t* opt) const - { - printf( - "Det: %5d Track: %6d E.loss: %.3e P: %+.3e %+.3e %+.3e\n" - "PosIn: %+.3e %+.3e %+.3e PosOut: %+.3e %+.3e %+.3e\n", - GetDetectorID(), GetTrackID(), GetEnergyLoss(), GetPx(), GetPy(), GetPz(), - GetStartX(), GetStartY(), GetStartZ(), GetX(), GetY(), GetZ()); - } +void Hit::Print(const Option_t* opt) const +{ + printf( + "Det: %5d Track: %6d E.loss: %.3e P: %+.3e %+.3e %+.3e\n" + "PosIn: %+.3e %+.3e %+.3e PosOut: %+.3e %+.3e %+.3e\n", + GetDetectorID(), GetTrackID(), GetEnergyLoss(), GetPx(), GetPy(), GetPz(), + GetStartX(), GetStartY(), GetStartZ(), GetX(), GetY(), GetZ()); +} - } // namespace fv0 +} // namespace fv0 } // namespace o2 diff --git a/DataFormats/Detectors/FIT/FV0/src/RawEventData.cxx b/DataFormats/Detectors/FIT/FV0/src/RawEventData.cxx index 022b003d0ab43..530e6f2bc1275 100644 --- a/DataFormats/Detectors/FIT/FV0/src/RawEventData.cxx +++ b/DataFormats/Detectors/FIT/FV0/src/RawEventData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,39 +11,12 @@ #include "DataFormatsFV0/RawEventData.h" #include <sstream> +#include <iostream> using namespace o2::fv0; ClassImp(RawEventData); - -void RawEventData::print() -{ - std::cout << "==================Raw event data==================" << std::endl; - std::cout << "##################Header##################" << std::endl; - std::cout << "startDescriptor: " << mEventHeader.startDescriptor << std::endl; - std::cout << "Nchannels: " << mEventHeader.nGBTWords * 2 << std::endl; - std::cout << "BC: " << mEventHeader.bc << std::endl; - std::cout << "Orbit: " << mEventHeader.orbit << std::endl; - std::cout << "##########################################" << std::endl; - std::cout << "###################DATA###################" << std::endl; - for (int iCh = 0; iCh < mEventHeader.nGBTWords * 2; iCh++) { - std::cout << "------------Channel " << mEventData[iCh].channelID << "------------" << std::endl; - std::cout << "Charge: " << mEventData[iCh].charge << std::endl; - std::cout << "Time: " << mEventData[iCh].time << std::endl; - std::cout << "1TimeLostEvent: " << mEventData[iCh].is1TimeLostEvent << std::endl; - std::cout << "2TimeLostEvent: " << mEventData[iCh].is2TimeLostEvent << std::endl; - std::cout << "ADCinGate: " << mEventData[iCh].isADCinGate << std::endl; - std::cout << "AmpHigh: " << mEventData[iCh].isAmpHigh << std::endl; - std::cout << "DoubleEvent: " << mEventData[iCh].isDoubleEvent << std::endl; - std::cout << "EventInTVDC: " << mEventData[iCh].isEventInTVDC << std::endl; - std::cout << "TimeInfoLate: " << mEventData[iCh].isTimeInfoLate << std::endl; - std::cout << "TimeInfoLost: " << mEventData[iCh].isTimeInfoLost << std::endl; - std::cout << "numberADC: " << mEventData[iCh].numberADC << std::endl; - } - std::cout << "##########################################" << std::endl; -} - -void RawEventData::printHexEventHeader() +void RawEventData::printHexEventHeader() const { std::stringstream ssheader; ssheader << std::setfill('0') << std::setw(16) << std::hex << mEventHeader.word[0] << " " << std::setw(16) << mEventHeader.word[1] << "\n "; @@ -56,7 +30,7 @@ void RawEventData::printHexEventHeader() LOG(DEBUG) << ssheader.str(); } -void RawEventData::printHexEventData(uint64_t i) +void RawEventData::printHexEventData(uint64_t i) const { std::stringstream ssdata; ssdata << "D0:0x "; diff --git a/DataFormats/Detectors/FIT/FV0/src/RecPoints.cxx b/DataFormats/Detectors/FIT/FV0/src/RecPoints.cxx new file mode 100644 index 0000000000000..562c7fa4d3509 --- /dev/null +++ b/DataFormats/Detectors/FIT/FV0/src/RecPoints.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsFV0/RecPoints.h" +#include <CommonDataFormat/InteractionRecord.h> +#include <Framework/Logger.h> + +using namespace o2::fv0; + +gsl::span<const ChannelDataFloat> RecPoints::getBunchChannelData(const gsl::span<const ChannelDataFloat> tfdata) const +{ + // extract the span of channel data for this bunch from the whole TF data + return mRef.getEntries() ? gsl::span<const ChannelDataFloat>(tfdata).subspan(mRef.getFirstEntry(), mRef.getEntries()) : gsl::span<const ChannelDataFloat>(); +} + +void ChannelDataFloat::print() const +{ + printf(" Channel=%d | time=%f | charge=%f | adcId=%d\n", channel, time, charge, adcId); +} diff --git a/DataFormats/Detectors/FIT/common/CMakeLists.txt b/DataFormats/Detectors/FIT/common/CMakeLists.txt new file mode 100644 index 0000000000000..fc31c450ebb59 --- /dev/null +++ b/DataFormats/Detectors/FIT/common/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(DataFormatsFIT + SOURCES src/RawEventData.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::CCDB) + +o2_target_root_dictionary(DataFormatsFIT + HEADERS include/DataFormatsFIT/LookUpTable.h) diff --git a/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/LookUpTable.h b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/LookUpTable.h new file mode 100644 index 0000000000000..2c808f44d5991 --- /dev/null +++ b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/LookUpTable.h @@ -0,0 +1,406 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_FIT_LOOKUPTABLE_H_ +#define ALICEO2_FIT_LOOKUPTABLE_H_ +//////////////////////////////////////////////// +// Look Up Table FIT +////////////////////////////////////////////// + +#include "CCDB/BasicCCDBManager.h" +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/json_parser.hpp> +#include <Rtypes.h> +#include <iostream> +#include <tuple> +#include <TSystem.h> +#include <map> +#include <string> +#include <vector> +#include <istream> +#include <ostream> +#include <algorithm> +namespace o2 +{ +namespace fit +{ +struct EntryCRU { //This is specific struct for CRU entry + int mLinkID; + int mEndPointID; + int mCRUID; + int mFEEID; + friend std::ostream& operator<<(std::ostream& os, const EntryCRU& entryCRU) + { + os << "LinkID: " << entryCRU.mLinkID << "|"; + os << "EndPointID: " << entryCRU.mEndPointID << "|"; + os << "CRUID: " << entryCRU.mCRUID << "|"; + os << "FEEID: " << entryCRU.mFEEID; + return os; + } + void parse(const boost::property_tree::ptree& propertyTree) + { + mLinkID = propertyTree.get<int>("LinkID"); + mEndPointID = propertyTree.get<int>("EndPointID"); + mCRUID = propertyTree.get<int>("CRUID"); + mFEEID = propertyTree.get<int>("FEEID"); + } + ClassDefNV(EntryCRU, 1); +}; + +struct HasherCRU { + // Hash-function without any collisions due to technical bit size of fields: + // RDH::EndPointID : 4 bits + // RDH::LinkID : 8 bits + std::size_t operator()(const EntryCRU& entryCRU) const + { + return (entryCRU.mLinkID << 4) | entryCRU.mEndPointID; + } +}; + +struct ComparerCRU { + bool operator()(const EntryCRU& entry1, const EntryCRU& entry2) const + { + return true; + // return entry1.mLinkID<entry2.mLinkID || entry1.mEndPointID<entry2.mEndPointID; + } +}; + +struct EntryPM { + EntryCRU mEntryCRU; + int mLocalChannelID = 0; + friend std::ostream& operator<<(std::ostream& os, const EntryPM& entryPM) + { + os << entryPM.mEntryCRU << "|"; + os << "LocalChID: " << entryPM.mLocalChannelID; + return os; + } + ClassDefNV(EntryPM, 1); +}; + +inline bool operator<(EntryPM const& entryPM1, EntryPM const& entryPM2) +{ + auto comparer = [](const EntryPM& entryPM) -> decltype(auto) { return std::tie(entryPM.mEntryCRU.mEndPointID, entryPM.mEntryCRU.mLinkID, entryPM.mLocalChannelID); }; + return comparer(entryPM1) < comparer(entryPM2); +} + +struct HasherPM { + // Hash-function without any collisions due to technical bit size of fields: + // RDH::EndPointID : 4 bits + // EventData::ChannelID : 4 bits + // RDH::LinkID : 8 bits + std::size_t operator()(const EntryPM& entryPM) const + { + return (entryPM.mEntryCRU.mLinkID << 8) | (entryPM.mLocalChannelID << 4) | (entryPM.mEntryCRU.mEndPointID); + } +}; + +struct ComparerPM { + //Always true due to perfect hasher + bool operator()(const EntryPM& entry1, const EntryPM& entry2) const + { + return true; + } +}; + +struct EntryFEE { + EntryCRU mEntryCRU; + std::string mChannelID; //ChannelID, string type because some entries containes N/A + std::string mLocalChannelID; //Local channelID, string type because some entries containes N/A + std::string mModuleType; //PM, PM-LCS, TCM + std::string mModuleName; + std::string mBoardHV; + std::string mChannelHV; + std::string mSerialNumberMCP; + std::string mCableHV; + std::string mCableSignal; + friend std::ostream& operator<<(std::ostream& os, const EntryFEE& entryFEE) + { + os << entryFEE.mEntryCRU << "|"; + os << "ChannelID: " << entryFEE.mChannelID << "|"; + os << "LocalChannelID: " << entryFEE.mLocalChannelID << "|"; + os << "ModuleType: " << entryFEE.mModuleType << "|"; + os << "ModuleName: " << entryFEE.mModuleName << "|"; + os << "HV board: " << entryFEE.mBoardHV << "|"; + os << "HV channel: " << entryFEE.mChannelHV << "|"; + os << "MCP S/N: " << entryFEE.mSerialNumberMCP << "|"; + os << "HV cable: " << entryFEE.mCableHV << "|"; + os << "signal cable: " << entryFEE.mCableSignal << "|"; + return os; + } + + void parse(const boost::property_tree::ptree& propertyTree) + { + mEntryCRU.parse(propertyTree); + mChannelID = propertyTree.get<std::string>("channel #"); + mLocalChannelID = propertyTree.get<std::string>("LocalChannelID"); + mModuleType = propertyTree.get<std::string>("ModuleType"); + mModuleName = propertyTree.get<std::string>("Module"); + mBoardHV = propertyTree.get<std::string>("HV board"); + mChannelHV = propertyTree.get<std::string>("HV channel"); + mSerialNumberMCP = propertyTree.get<std::string>("MCP S/N"); + mCableHV = propertyTree.get<std::string>("HV cable"); + mCableSignal = propertyTree.get<std::string>("signal cable"); + } + ClassDefNV(EntryFEE, 1); +}; +enum class EModuleType : int { kUnknown, + kPM, + kPM_LCS, + kTCM }; + +template <typename MapEntryCRU2ModuleType = std::unordered_map<EntryCRU, EModuleType, HasherCRU, ComparerCRU>, + typename MapEntryPM2ChannelID = std::unordered_map<EntryPM, int, HasherPM, ComparerPM>, + typename = typename std::enable_if_t<std::is_integral<typename MapEntryPM2ChannelID::mapped_type>::value>> +class LookupTableBase +{ + public: + LookupTableBase(const std::string& pathToFile) { initFromFile(pathToFile); } + LookupTableBase(const std::string& urlCCDB, const std::string& pathToStorageInCCDB) { initCCDB(urlCCDB, pathToStorageInCCDB); } + typedef MapEntryPM2ChannelID MapEntryPM2ChannelID_t; + typedef MapEntryCRU2ModuleType MapEntryCRU2ModuleType_t; + typedef typename MapEntryPM2ChannelID_t::key_type EntryPM_t; + typedef typename MapEntryCRU2ModuleType_t::key_type EntryCRU_t; + typedef typename MapEntryPM2ChannelID_t::mapped_type ChannelID_t; + typedef std::map<ChannelID_t, EntryPM_t> MapChannelID2EntryPM_t; // for digit2raw + typedef std::map<EModuleType, EntryCRU_t> MapModuleType2EntryCRU; // for digit2raw + typedef EntryPM_t Topo_t; //temporary for common interface + //Map of str module names -> enum types + const std::map<std::string, EModuleType> mMapModuleTypeStr2Enum = {{"PM", EModuleType::kPM}, {"PM-LCS", EModuleType::kPM_LCS}, {"TCM", EModuleType::kTCM}}; + //Warning! To exclude double mapping do not use isTCM and isPM in the same time + bool isTCM(int linkID, int epID) const + { + return mEntryCRU_TCM.mLinkID == linkID && mEntryCRU_TCM.mEndPointID == epID; + } + bool isTCM(const EntryCRU_t& entryCRU) const + { + if (getModuleType(entryCRU) == EModuleType::kTCM) { + return true; + } else { + return false; + } + } + bool isPM(const EntryCRU_t& entryCRU) const + { + if (getModuleType(entryCRU) == EModuleType::kPM || getModuleType(entryCRU) == EModuleType::kPM_LCS) { + return true; + } else { + return false; + } + } + EModuleType getModuleType(const EntryCRU_t& entryCRU) const + { + const auto& mapEntries = getMapEntryCRU2ModuleType(); + const auto& it = mapEntries.find(entryCRU); + if (it != mapEntries.end()) { + return it->second; + } else { + return EModuleType::kUnknown; + } + } + EModuleType getModuleType(const std::string& moduleType) + { + const auto& it = mMapModuleTypeStr2Enum.find(moduleType); + if (it != mMapModuleTypeStr2Enum.end()) { + return it->second; + } else { + return EModuleType::kUnknown; + } + } + void initFromFile(const std::string& pathToFile) + { + std::string filepath{}; + if (pathToFile == "") { + std::string inputDir; + const char* aliceO2env = std::getenv("O2_ROOT"); + if (aliceO2env) { + inputDir = aliceO2env; + } + inputDir += "/share/Detectors/FT0/files/"; + filepath = inputDir + "LookupTable_FT0.json"; + filepath = gSystem->ExpandPathName(filepath.data()); // Expand $(ALICE_ROOT) into real system path + } else { + filepath = pathToFile; + } + prepareEntriesFEE(filepath); + prepareLUT(); + } + void initCCDB(const std::string& urlCCDB, const std::string& pathToStorageInCCDB) + { + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(urlCCDB); + mVecEntryFEE = *(mgr.get<std::vector<EntryFEE>>(pathToStorageInCCDB)); + prepareLUT(); + } + ChannelID_t getGlobalChannelID(const EntryPM_t& entryPM, bool& isValid) const + { + const auto& it = mMapEntryPM2ChannelID.find(entryPM); + if (it != mMapEntryPM2ChannelID.end()) { + isValid = true; + return it->second; + } else { + isValid = false; + return -1; + } + } + ChannelID_t getChannel(int linkID, int chID, int ep = 0) + { + return mMapEntryPM2ChannelID.find(std::move(EntryPM_t{EntryCRU_t{linkID, ep, 0, 0}, chID}))->second; + } + ChannelID_t getChannel(int linkID, int ep, int chID, bool& isValid) + { + const auto& it = mMapEntryPM2ChannelID.find(std::move(EntryPM_t{EntryCRU_t{linkID, ep, 0, 0}, chID})); + if (it != mMapEntryPM2ChannelID.end()) { + isValid = true; + return it->second; + } else { + isValid = false; + return -1; + } + } + void prepareEntriesFEE(const std::string& pathToConfigFile) + { + boost::property_tree::ptree propertyTree; + boost::property_tree::read_json(pathToConfigFile.c_str(), propertyTree); + mVecEntryFEE = prepareEntriesFEE(propertyTree); + } + std::vector<EntryFEE> prepareEntriesFEE(const boost::property_tree::ptree& propertyTree) + { + std::vector<EntryFEE> vecEntryFEE; + for (const auto& pairEntry : propertyTree) { + const auto& propertyTreeSingle = pairEntry.second; + EntryFEE entryFEE{}; + entryFEE.parse(propertyTreeSingle); + vecEntryFEE.push_back(entryFEE); + } + return vecEntryFEE; + } + + void prepareLUT() + { + mMapEntryCRU2ModuleType.clear(); + mMapEntryPM2ChannelID.clear(); + const auto& vecEntryFEE = getVecMetadataFEE(); + for (const auto entryFEE : vecEntryFEE) { + EntryCRU_t entryCRU = entryFEE.mEntryCRU; + std::string strModuleType = entryFEE.mModuleType; + EModuleType moduleType = getModuleType(strModuleType); + if (moduleType != EModuleType::kUnknown) { + mMapEntryCRU2ModuleType.insert({entryCRU, moduleType}); + } + if (moduleType == EModuleType::kPM || moduleType == EModuleType::kPM_LCS) { + const std::string& strChannelID = entryFEE.mChannelID; + const std::string& strLocalChannelID = entryFEE.mLocalChannelID; + EntryPM_t entryPM{entryCRU, std::stoi(strLocalChannelID)}; + mMapEntryPM2ChannelID.insert({entryPM, std::stoi(strChannelID)}); + } + if (moduleType == EModuleType::kTCM) { + mEntryCRU_TCM = entryCRU; + } + } + } + void printFullMap() const + { + for (const auto& entry : mVecEntryFEE) { + LOG(INFO) << entry; + } + /* + std::cout<<std::endl<<"------------------------------------------------------------------------------"<<std::endl; + for(const auto &entry:mMapEntryPM2ChannelID) { + std::cout<<entry.first<<"| GlChID: "<<entry.second<<std::endl; + } + std::cout<<std::endl<<"------------------------------------------------------------------------------"<<std::endl; + for(const auto &entry:mMapEntryCRU2ModuleType) { + std::cout<<entry.first<<"| ModuleType: "<<static_cast<int>(entry.second)<<std::endl; + } + */ + } + const std::vector<EntryFEE>& getVecMetadataFEE() const { return mVecEntryFEE; } + const MapEntryCRU2ModuleType_t& getMapEntryCRU2ModuleType() const { return mMapEntryCRU2ModuleType; } + const MapEntryPM2ChannelID_t& getMapEntryPM2ChannelID() const { return mMapEntryPM2ChannelID; } + const EntryCRU_t& getEntryCRU_TCM() const { return mEntryCRU_TCM; } + //Temporary + //Making topo for FEE recognizing(Local channelID is supressed) + static Topo_t makeGlobalTopo(const Topo_t& topo) + { + return Topo_t{topo.mEntryCRU, 0}; + } + static int getLocalChannelID(const Topo_t& topo) + { + return topo.mLocalChannelID; + } + Topo_t getTopoPM(int globalChannelID) const + { + const auto& mapChannels = getMapEntryPM2ChannelID(); + auto findResult = std::find_if(mapChannels.begin(), mapChannels.end(), [&](const auto& pairEntry) { + return pairEntry.second == globalChannelID; + }); + return findResult->first; + } + Topo_t getTopoTCM() const + { + const auto& mapModuleType = getMapEntryCRU2ModuleType(); + auto findResult = std::find_if(mapModuleType.begin(), mapModuleType.end(), [&](const auto& pairEntry) { + return pairEntry.second == EModuleType::kTCM; + }); + return Topo_t{findResult->first, 0}; + } + //Prepare full map for FEE metadata(for digit2raw convertion) + template <typename RDHtype, typename RDHhelper = void> + auto makeMapFEEmetadata() -> std::map<Topo_t, RDHtype> + { + std::map<Topo_t, RDHtype> mapResult; + const uint16_t cruID = 0; //constant + uint64_t feeID = 0; //increments + const auto& mapEntryPM2ChannelID = getMapEntryPM2ChannelID(); + //Temporary for sorting FEEIDs without using them from LUT(for digit2raw convertion), and by using GlobalChannelID + std::map<int, Topo_t> mapBuf; + for (const auto& entry : mapEntryPM2ChannelID) { + mapBuf.insert({entry.second, entry.first}); + } + const auto& cru_tcm = getEntryCRU_TCM(); + mapBuf.insert({static_cast<int>(mapBuf.size()), Topo_t{cru_tcm, 0}}); + // + for (const auto& pairEntry : mapBuf) { + auto en = pairEntry.second; + auto pairInserted = mapResult.insert({makeGlobalTopo(en), RDHtype{}}); + if (pairInserted.second) { + auto& rdhObj = pairInserted.first->second; + const auto& topoObj = pairInserted.first->first; + if constexpr (std::is_same<RDHhelper, void>::value) { + rdhObj.linkID = topoObj.mEntryCRU.mLinkID; + rdhObj.endPointID = topoObj.mEntryCRU.mEndPointID; + rdhObj.feeId = feeID; + rdhObj.cruID = cruID; + } else //Using RDHUtils + { + RDHhelper::setLinkID(&rdhObj, topoObj.mEntryCRU.mLinkID); + RDHhelper::setEndPointID(&rdhObj, topoObj.mEntryCRU.mEndPointID); + RDHhelper::setFEEID(&rdhObj, feeID); + RDHhelper::setCRUID(&rdhObj, cruID); + } + feeID++; + } + } + for (const auto& entry : mapResult) { + std::cout << "\nTEST: " << entry.first << std::endl; + } + return mapResult; + } + + private: + EntryCRU_t mEntryCRU_TCM; + std::vector<EntryFEE> mVecEntryFEE; + MapEntryCRU2ModuleType_t mMapEntryCRU2ModuleType; + MapEntryPM2ChannelID_t mMapEntryPM2ChannelID; +}; +} // namespace fit +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/RawEventData.h b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/RawEventData.h new file mode 100644 index 0000000000000..737a8847157b3 --- /dev/null +++ b/DataFormats/Detectors/FIT/common/include/DataFormatsFIT/RawEventData.h @@ -0,0 +1,147 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawEventData.h class for RAW data format +//Alla.Maevskaya@cern.ch +// with Artur.Furs@cern.ch +// +#ifndef ALICEO2_FIT_RAWEVENTDATA_H_ +#define ALICEO2_FIT_RAWEVENTDATA_H_ + +#include <CommonDataFormat/InteractionRecord.h> +#include <Framework/Logger.h> + +namespace o2 +{ +namespace fit +{ + +struct EventHeader { + static constexpr size_t PayloadSize = 10; + static constexpr size_t PayloadPerGBTword = 10; + static constexpr size_t MinNelements = 1; + static constexpr size_t MaxNelements = 1; + union { + uint64_t word[2] = {}; + struct { + uint64_t bc : 12; + uint64_t orbit : 32; + uint64_t phase : 3; + uint64_t errorPhase : 1; + uint64_t reservedField1 : 16; + uint64_t reservedField2 : 8; + uint64_t nGBTWords : 4; + uint64_t startDescriptor : 4; + uint64_t reservedField3 : 48; + }; + }; + InteractionRecord getIntRec() const { return InteractionRecord{(uint16_t)bc, (uint32_t)orbit}; } + uint16_t getBC() const { return static_cast<uint16_t>(bc); } + uint32_t getOrbit() const { return static_cast<uint32_t>(orbit); } + void setIntRec(const InteractionRecord& intRec) + { + bc = intRec.bc; + orbit = intRec.orbit; + } + void print() const; +}; + +struct EventData { + static constexpr size_t PayloadSize = 5; + static constexpr size_t PayloadPerGBTword = 10; + static constexpr size_t MinNelements = 0; + static constexpr size_t MaxNelements = 12; + // + static constexpr int BitFlagPos = 25; // position of first bit flag(numberADC) + + union { + uint64_t word = {0}; + struct { + int64_t time : 12; + int64_t charge : 13; + uint64_t numberADC : 1, //25 bit + isDoubleEvent : 1, + isTimeInfoNOTvalid : 1, + isCFDinADCgate : 1, + isTimeInfoLate : 1, + isAmpHigh : 1, + isEventInTVDC : 1, + isTimeInfoLost : 1, + reservedField : 3, + channelID : 4; + }; + }; + void generateFlags() + { + numberADC = std::rand() % 2; + isDoubleEvent = 0; + isTimeInfoNOTvalid = 0; + isCFDinADCgate = 1; + isTimeInfoLate = 0; + isAmpHigh = 0; + isEventInTVDC = 1; + isTimeInfoLost = 0; + } + uint8_t getFlagWord() const + { + return uint8_t(word >> BitFlagPos); + } + void print() const; +}; + +struct TCMdata { + static constexpr size_t PayloadSize = 10; + static constexpr size_t PayloadPerGBTword = 10; + static constexpr size_t MinNelements = 1; + static constexpr size_t MaxNelements = 1; + uint64_t orA : 1, // 0 bit (0 byte) + orC : 1, //1 bit + sCen : 1, //2 bit + cen : 1, //3 bit + vertex : 1, //4 bit + laser : 1, //5 bit + outputsAreBlocked : 1, //6 bit + dataIsValid : 1, //7 bit + nChanA : 7, //8 bit(1 byte) + reservedField2 : 1, //15 bit + nChanC : 7, //16 bit(2 byte) + reservedField3 : 1; // 23 bit + int64_t amplA : 17, //24 bit (3 byte) + reservedField4 : 1, //41 bit + amplC : 17, //42 bit. + reservedField5 : 1, //59 bit. + //in standard case(without __atribute__((packed)) macros, or packing by using union) + //here will be empty 4 bits, end next field("timeA") will start from 64 bit. + timeA : 9, //60 bit + reservedField6 : 1, //69 bit + timeC : 9, //70 bit + reservedField7 : 1, //79 bit + reservedField8 : 48; //80 bit + + void print() const; +} __attribute__((__packed__)); + +struct TCMdataExtended { + static constexpr size_t PayloadSize = 4; + static constexpr size_t PayloadPerGBTword = 10; + static constexpr size_t MinNelements = 0; + static constexpr size_t MaxNelements = 20; + union { + uint32_t word[1] = {}; + uint32_t triggerWord; + }; + + void print() const; +}; + +} // namespace fit +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h b/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h new file mode 100644 index 0000000000000..668ef407309bd --- /dev/null +++ b/DataFormats/Detectors/FIT/common/src/DataFormatsFITLinkDef.h @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::fit::EntryCRU + ; +#pragma link C++ class o2::fit::EntryPM + ; +#pragma link C++ class o2::fit::EntryFEE + ; +#pragma link C++ class vector < o2::fit::EntryFEE> + ; + +#endif diff --git a/DataFormats/Detectors/FIT/common/src/RawEventData.cxx b/DataFormats/Detectors/FIT/common/src/RawEventData.cxx new file mode 100644 index 0000000000000..9b4c4449d31d3 --- /dev/null +++ b/DataFormats/Detectors/FIT/common/src/RawEventData.cxx @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsFIT/RawEventData.h" + +using namespace o2::fit; + +void EventHeader::print() const +{ + LOG(INFO) << std::hex; + LOG(INFO) << "################EventHeader###############"; + LOG(INFO) << "startDescriptor: " << startDescriptor; + LOG(INFO) << "nGBTWords: " << nGBTWords; + LOG(INFO) << "BC: " << bc; + LOG(INFO) << "Orbit: " << orbit; + LOG(INFO) << "##########################################"; + LOG(INFO) << std::dec; +} + +void EventData::print() const +{ + LOG(INFO) << std::hex; + LOG(INFO) << "###############EventData(PM)##############"; + LOG(INFO) << "------------Channel " << channelID << "------------"; + LOG(INFO) << "Charge: " << charge; + LOG(INFO) << "Time: " << time; + LOG(INFO) << "numberADC: " << numberADC; + LOG(INFO) << "isDoubleEvent: " << isDoubleEvent; + LOG(INFO) << "isTimeInfoNOTvalid: " << isTimeInfoNOTvalid; + LOG(INFO) << "isCFDinADCgate: " << isCFDinADCgate; + LOG(INFO) << "isTimeInfoLate: " << isTimeInfoLate; + LOG(INFO) << "isAmpHigh: " << isAmpHigh; + LOG(INFO) << "isEventInTVDC: " << isEventInTVDC; + LOG(INFO) << "isTimeInfoLost: " << isTimeInfoLost; + LOG(INFO) << "##########################################"; + LOG(INFO) << std::dec; +} + +void TCMdata::print() const +{ + LOG(INFO) << std::hex; + LOG(INFO) << "################TCMdata###################"; + LOG(INFO) << "orC: " << orC; + LOG(INFO) << "orA: " << orA; + LOG(INFO) << "sCen: " << sCen; + LOG(INFO) << "cen: " << cen; + LOG(INFO) << "vertex: " << vertex; + LOG(INFO) << "laser: " << laser; + LOG(INFO) << "outputsAreBlocked: " << outputsAreBlocked; + LOG(INFO) << "dataIsValid: " << dataIsValid; + LOG(INFO) << "nChanA: " << nChanA; + LOG(INFO) << "nChanC: " << nChanC; + LOG(INFO) << "amplA: " << amplA; + LOG(INFO) << "amplC: " << amplC; + LOG(INFO) << "timeA: " << timeA; + LOG(INFO) << "timeC: " << timeC; + LOG(INFO) << "##########################################"; + LOG(INFO) << std::dec; +} + +void TCMdataExtended::print() const +{ + LOG(INFO) << std::hex; + LOG(INFO) << "############TCMdataExtended###############"; + LOG(INFO) << "triggerWord: " << triggerWord; + LOG(INFO) << "##########################################"; + LOG(INFO) << std::dec; +} diff --git a/DataFormats/Detectors/GlobalTracking/CMakeLists.txt b/DataFormats/Detectors/GlobalTracking/CMakeLists.txt new file mode 100644 index 0000000000000..d37771a52389b --- /dev/null +++ b/DataFormats/Detectors/GlobalTracking/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + DataFormatsGlobalTracking + SOURCES src/RecoContainer.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsTPC + O2::DataFormatsITSMFT + O2::DataFormatsITS + O2::DataFormatsMFT + O2::DataFormatsMCH + O2::DataFormatsFT0 + O2::DataFormatsFV0 + O2::DataFormatsFDD + O2::DataFormatsZDC + O2::DataFormatsTOF + O2::ReconstructionDataFormats + O2::DataFormatsTRD + O2::GPUDataTypeHeaders + PRIVATE_LINK_LIBRARIES + O2::Framework) diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h new file mode 100644 index 0000000000000..6861cbd93d474 --- /dev/null +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h @@ -0,0 +1,544 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoContainer.h +/// \brief Wrapper container for different reconstructed object types +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_RECO_CONTAINER +#define ALICEO2_RECO_CONTAINER + +#include "CommonDataFormat/InteractionRecord.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "CommonDataFormat/RangeReference.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/MatchingType.h" +#include "CommonDataFormat/AbstractRefAccessor.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include <gsl/span> +#include <memory> + +// We forward declare the internal structures, to reduce header dependencies. +// Please include headers for TPC Hits or TRD tracklets directly (DataFormatsTPC/WorkflowHelper.h / DataFormatsTRD/RecoInputContainer.h) +namespace o2::tpc +{ +class TrackTPC; +using TPCClRefElem = uint32_t; +struct ClusterNativeAccess; +namespace internal +{ +struct getWorkflowTPCInput_ret; +} // namespace internal +} // namespace o2::tpc + +namespace o2::trd +{ +class Tracklet64; +class CalibratedTracklet; +class TriggerRecord; +class TrackTriggerRecord; +//class TrackTRD; +struct RecoInputContainer; +} // namespace o2::trd + +namespace o2::framework +{ +class ProcessingContext; +struct InputSpec; +} // namespace o2::framework + +namespace o2::its +{ +class TrackITS; +} + +namespace o2::mft +{ +class TrackMFT; +} + +namespace o2::mch +{ +class TrackMCH; +class ROFRecord; +class ClusterStruct; +} // namespace o2::mch + +namespace o2::itsmft +{ +class ROFRecord; +class CompClusterExt; +class TrkClusRef; +} // namespace o2::itsmft + +namespace o2::tof +{ +class Cluster; +} + +namespace o2::ft0 +{ +class RecPoints; +class ChannelDataFloat; +} // namespace o2::ft0 + +namespace o2::fv0 +{ +class RecPoints; +class ChannelDataFloat; +} // namespace o2::fv0 + +namespace o2::zdc +{ +class BCRecData; +class ZDCEnergy; +class ZDCTDCData; +} // namespace o2::zdc + +namespace o2::fdd +{ +class RecPoint; +class ChannelDataFloat; +} // namespace o2::fdd + +namespace o2::dataformats +{ +class TrackTPCITS; +class TrackTPCTOF; +class MatchInfoTOF; +class PrimaryVertex; +class VtxTrackIndex; +class VtxTrackRef; +class V0; +class Cascade; +class TrackCosmics; +class GlobalFwdTrack; +class IRFrame; +} // namespace o2::dataformats + +namespace o2 +{ +class MCEventLabel; +} + +namespace o2 +{ +namespace globaltracking +{ + +// helper class to request DPL input data from the processor specs definition +struct DataRequest { + std::vector<o2::framework::InputSpec> inputs; + std::unordered_map<std::string, bool> requestMap; + MatchingType matchingInputType = MatchingType::Standard; // use subspec = 0 for inputs + + auto getMatchingInputType() const { return matchingInputType; } + void setMatchingInputStrict() { matchingInputType = MatchingType::Strict; } + void setMatchingInputFull() { matchingInputType = MatchingType::Full; } + void setMatchingInputStandard() { matchingInputType = MatchingType::Standard; } + uint32_t getMatchingInputSubSpec() const { return getSubSpec(matchingInputType); } + + void addInput(const o2::framework::InputSpec&& isp); + + bool isRequested(const std::string& t) const { return !t.empty() && requestMap.find(t) != requestMap.end(); } + void requestTracks(o2::dataformats::GlobalTrackID::mask_t src, bool mc); + void requestClusters(o2::dataformats::GlobalTrackID::mask_t src, bool useMC); + + void requestITSTracks(bool mc); + void requestMFTTracks(bool mc); + void requestMCHTracks(bool mc); + void requestTPCTracks(bool mc); + void requestITSTPCTracks(bool mc); + void requestGlobalFwdTracks(bool mc); + void requestTPCTOFTracks(bool mc); + void requestITSTPCTRDTracks(bool mc); + void requestTPCTRDTracks(bool mc); + void requestTOFMatches(bool mc); + void requestFT0RecPoints(bool mc); + void requestFV0RecPoints(bool mc); + void requestFDDRecPoints(bool mc); + void requestZDCRecEvents(bool mc); + void requestITSClusters(bool mc); + void requestMFTClusters(bool mc); + void requestTPCClusters(bool mc); + void requestTOFClusters(bool mc); + void requestTRDTracklets(bool mc); + + void requestCoscmicTracks(bool mc); + + void requestPrimaryVertertices(bool mc); + void requestPrimaryVerterticesTMP(bool mc); + void requestSecondaryVertertices(bool mc); + + void requestIRFramesITS(); +}; + +// Helper class to requested data. +// Most common data have dedicated getters, some need to be called with returned typa as a template. +// In general on either gets a gsl::span<const Type> via getter like e.g. getITSTracks() +// of a reference to particular track, i.e. getITSTrack(GlobalTrackID id). +// Note that random access like getITSTracks()[i] has an overhead, since for every call a span is created. +// Therefore, for the random access better to use direct getter, i.e. auto& tr = getITSTrack(gid) +// while for looping over the whole span first create a span then iterate over it. + +struct RecoContainer { + RecoContainer(); + ~RecoContainer(); + + enum CommonSlots { + TRACKS, + MATCHES, + MATCHESEXTRA, + TRACKREFS, + CLUSREFS, + CLUSTERS, + PATTERNS, + INDICES, + MCLABELS, // track labels + MCLABELSEXTRA, // additonal labels, like TOF clusters matching label (not sure TOF really needs it) + VARIA, // misc data, which does not fit to other categories + NCOMMONSLOTS + }; + + // slots to register primary vertex data + enum PVTXSlots { PVTX, // Primary vertices + PVTX_TRMTC, // matched track indices + PVTX_TRMTCREFS, // PV -> matched tracks referencing object + PVTX_CONTID, // contributors indices + PVTX_CONTIDREFS, // PV -> contributors indices + PVTX_MCTR, // PV MC label + NPVTXSLOTS }; + + // slots to register secondary vertex data + enum SVTXSlots { V0S, // V0 objects + PVTX_V0REFS, // PV -> V0 references + CASCS, // Cascade objects + PVTX_CASCREFS, // PV -> Cascade reference + NSVTXSLOTS }; + + // slots for cosmics + enum CosmicsSlots { COSM_TRACKS, + COSM_TRACKS_MC, + NCOSMSLOTS }; + + using AccSlots = o2::dataformats::AbstractRefAccessor<int, NCOMMONSLOTS>; // int here is a dummy placeholder + using PVertexAccessor = o2::dataformats::AbstractRefAccessor<int, NPVTXSLOTS>; + using SVertexAccessor = o2::dataformats::AbstractRefAccessor<int, NSVTXSLOTS>; + using CosmicsAccessor = o2::dataformats::AbstractRefAccessor<int, NCOSMSLOTS>; + using GTrackID = o2::dataformats::GlobalTrackID; + using GlobalIDSet = std::array<GTrackID, GTrackID::NSources>; + + o2::InteractionRecord startIR; // TF start IR + + std::array<AccSlots, GTrackID::NSources> commonPool; + PVertexAccessor pvtxPool; // containers for primary vertex related objects + SVertexAccessor svtxPool; // containers for secondary vertex related objects + CosmicsAccessor cosmPool; // containers for cosmics track data + + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mcITSClusters; + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mcTOFClusters; + + gsl::span<const unsigned char> clusterShMapTPC; ///< externally set TPC clusters sharing map + + std::unique_ptr<o2::tpc::internal::getWorkflowTPCInput_ret> inputsTPCclusters; // special struct for TPC clusters access + std::unique_ptr<o2::trd::RecoInputContainer> inputsTRD; // special struct for TRD tracklets, trigger records + + void collectData(o2::framework::ProcessingContext& pc, const DataRequest& request); + void createTracks(std::function<bool(const o2::track::TrackParCov&, GTrackID)> const& creator) const; + template <class T> + void createTracksVariadic(T creator) const; + void fillTrackMCLabels(const gsl::span<GTrackID> gids, std::vector<o2::MCCompLabel>& mcinfo) const; + + void addITSTracks(o2::framework::ProcessingContext& pc, bool mc); + void addMFTTracks(o2::framework::ProcessingContext& pc, bool mc); + void addMCHTracks(o2::framework::ProcessingContext& pc, bool mc); + void addTPCTracks(o2::framework::ProcessingContext& pc, bool mc); + + void addITSTPCTRDTracks(o2::framework::ProcessingContext& pc, bool mc); + void addTPCTRDTracks(o2::framework::ProcessingContext& pc, bool mc); + void addITSTPCTracks(o2::framework::ProcessingContext& pc, bool mc); + void addGlobalFwdTracks(o2::framework::ProcessingContext& pc, bool mc); + void addTPCTOFTracks(o2::framework::ProcessingContext& pc, bool mc); + void addTOFMatches(o2::framework::ProcessingContext& pc, bool mc); + + void addITSClusters(o2::framework::ProcessingContext& pc, bool mc); + void addMFTClusters(o2::framework::ProcessingContext& pc, bool mc); + void addTPCClusters(o2::framework::ProcessingContext& pc, bool mc, bool shmap); + void addTOFClusters(o2::framework::ProcessingContext& pc, bool mc); + void addTRDTracklets(o2::framework::ProcessingContext& pc, bool mc); + + void addFT0RecPoints(o2::framework::ProcessingContext& pc, bool mc); + void addFV0RecPoints(o2::framework::ProcessingContext& pc, bool mc); + void addFDDRecPoints(o2::framework::ProcessingContext& pc, bool mc); + + void addZDCRecEvents(o2::framework::ProcessingContext& pc, bool mc); + + void addCosmicTracks(o2::framework::ProcessingContext& pc, bool mc); + + void addPVertices(o2::framework::ProcessingContext& pc, bool mc); + void addPVerticesTMP(o2::framework::ProcessingContext& pc, bool mc); + void addSVertices(o2::framework::ProcessingContext& pc, bool); + + void addIRFramesITS(o2::framework::ProcessingContext& pc); + + // custom getters + + // get contributors from single detectors: return array with sources set to all contributing GTrackIDs + GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const; + + // get contributing TPC GTrackID to the source. If source gidx is not contributed by TPC, + // returned GTrackID.isSourceSet()==false + GTrackID getTPCContributorGID(GTrackID source) const; + + // get contributing ITS GTrackID to the source. If source gidx is not contributed by ITS, + // returned GTrackID.isSourceSet()==false + GTrackID getITSContributorGID(GTrackID source) const; + + // check if track source attached + bool isTrackSourceLoaded(int src) const; + + // check if match source attached + bool isMatchSourceLoaded(int src) const { return commonPool[src].isLoaded(MATCHES); } + + // ------------------------------- + // generic getter for span + template <typename U> + gsl::span<const U> getSpan(int src, int slotID) const + { + return commonPool[src].getSpan<U>(slotID); + } + + // generic getter for an object in the attaches span + template <typename U> + const U& getObject(int src, int index, int slotID) const + { + return commonPool[src].get_as<U>(slotID, index); + } + template <typename U> + const U& getObject(GTrackID gid, int slotID) const + { + return getObject<U>(gid.getSource(), gid.getIndex(), slotID); + } + // <<TODO Make this private + + //------------------------- + // in general, U can be a TrackParCov or particular detector track, e.g. o2::its::TrackITS + template <typename U> + gsl::span<const U> getTracks(int src) const + { + return getSpan<U>(src, TRACKS); + } + + template <typename U> + const U& getTrack(int src, int id) const + { + return getObject<U>(src, id, TRACKS); + } + + template <typename U> + const U& getTrack(GTrackID gid) const + { + return getObject<U>(gid, TRACKS); + } + + o2::MCCompLabel getTrackMCLabel(GTrackID id) const + { + //RS FIXME: THIS IS TEMPORARY: some labels are still not implemented: in this case return dummy label + return commonPool[id.getSource()].getSize(MCLABELS) ? getObject<o2::MCCompLabel>(id, MCLABELS) : o2::MCCompLabel{}; + //return getObject<o2::MCCompLabel>(id, MCLABELS); + } + + //-------------------------------------------- + // fetch track param + const o2::track::TrackParCov& getTrackParam(GTrackID gidx) const; + // fetch outer param (not all track types might have it) + const o2::track::TrackParCov& getTrackParamOut(GTrackID gidx) const; + + //-------------------------------------------- + // ITS + const o2::its::TrackITS& getITSTrack(GTrackID gid) const { return getTrack<o2::its::TrackITS>(gid); } + auto getITSTracks() const { return getTracks<o2::its::TrackITS>(GTrackID::ITS); } + auto getITSTracksROFRecords() const { return getSpan<o2::itsmft::ROFRecord>(GTrackID::ITS, TRACKREFS); } + auto getITSTracksClusterRefs() const { return getSpan<int>(GTrackID::ITS, INDICES); } + auto getITSTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITS, MCLABELS); } + auto getITSABRefs() const { return getSpan<o2::itsmft::TrkClusRef>(GTrackID::ITSAB, TRACKREFS); } + const o2::itsmft::TrkClusRef& getITSABRef(GTrackID gid) const { return getObject<o2::itsmft::TrkClusRef>(gid, TRACKREFS); } + auto getITSABClusterRefs() const { return getSpan<int>(GTrackID::ITSAB, INDICES); } + auto getITSABMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSAB, MCLABELS); } + + // ITS clusters + auto getITSClustersROFRecords() const { return getSpan<o2::itsmft::ROFRecord>(GTrackID::ITS, CLUSREFS); } + auto getITSClusters() const { return getSpan<o2::itsmft::CompClusterExt>(GTrackID::ITS, CLUSTERS); } + auto getITSClustersPatterns() const { return getSpan<unsigned char>(GTrackID::ITS, PATTERNS); } + auto getITSClustersMCLabels() const { return mcITSClusters.get(); } + + // MFT + const o2::mft::TrackMFT& getMFTTrack(GTrackID gid) const { return getTrack<o2::mft::TrackMFT>(gid); } + auto getMFTTracks() const { return getTracks<o2::mft::TrackMFT>(GTrackID::MFT); } + auto getMFTTracksROFRecords() const { return getSpan<o2::itsmft::ROFRecord>(GTrackID::MFT, TRACKREFS); } + auto getMFTTracksClusterRefs() const { return getSpan<int>(GTrackID::MFT, INDICES); } + auto getMFTTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::MFT, MCLABELS); } + + // MFT clusters + auto getMFTClustersROFRecords() const { return getSpan<o2::itsmft::ROFRecord>(GTrackID::MFT, CLUSREFS); } + auto getMFTClusters() const { return getSpan<o2::itsmft::CompClusterExt>(GTrackID::MFT, CLUSTERS); } + auto getMFTClustersPatterns() const { return getSpan<unsigned char>(GTrackID::MFT, PATTERNS); } + + // MCH + const o2::mch::TrackMCH& getMCHTrack(GTrackID gid) const { return getTrack<o2::mch::TrackMCH>(gid); } + auto getMCHTracks() const { return getTracks<o2::mch::TrackMCH>(GTrackID::MCH); } + auto getMCHTracksROFRecords() const { return getSpan<o2::mch::ROFRecord>(GTrackID::MCH, TRACKREFS); } + auto getMCHTrackClusters() const { return getSpan<o2::mch::ClusterStruct>(GTrackID::MCH, CLUSREFS); } + auto getMCHTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::MCH, MCLABELS); } + // FIXME: add clusters + + // TPC + const o2::tpc::TrackTPC& getTPCTrack(GTrackID id) const { return getTrack<o2::tpc::TrackTPC>(id); } + auto getTPCTracks() const { return getTracks<o2::tpc::TrackTPC>(GTrackID::TPC); } + auto getTPCTracksClusterRefs() const { return getSpan<o2::tpc::TPCClRefElem>(GTrackID::TPC, INDICES); } + auto getTPCTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::TPC, MCLABELS); } + auto getTPCTrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELS); } + const o2::tpc::ClusterNativeAccess& getTPCClusters() const; + const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* getTPCClustersMCLabels() const; + + // ITS-TPC + const o2::dataformats::TrackTPCITS& getTPCITSTrack(GTrackID gid) const { return getTrack<o2::dataformats::TrackTPCITS>(gid); } + auto getTPCITSTracks() const { return getTracks<o2::dataformats::TrackTPCITS>(GTrackID::ITSTPC); } + auto getTPCITSTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSTPC, MCLABELS); } + auto getTPCITSTrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELS); } + + // MFT-MCH + const o2::dataformats::GlobalFwdTrack& getGlobalFwdTrack(GTrackID gid) const { return getTrack<o2::dataformats::GlobalFwdTrack>(gid); } + auto getGlobalFwdTracks() const { return getTracks<o2::dataformats::GlobalFwdTrack>(GTrackID::MFTMCH); } + auto getGlobalFwdTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::MFTMCH, MCLABELS); } + + // ITS-TPC-TRD, since the TrackTRD track is just an alias, forward-declaring it does not work, need to keep template + template <class U> + auto getITSTPCTRDTrack(GTrackID id) const + { + return getTrack<U>(id); + } + template <class U> + auto getITSTPCTRDTracks() const + { + return getTracks<U>(GTrackID::ITSTPCTRD); + } + auto getITSTPCTRDTriggers() const + { + return getSpan<o2::trd::TrackTriggerRecord>(GTrackID::ITSTPCTRD, TRACKREFS); + } + auto getITSTPCTRDTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSTPCTRD, MCLABELS); } + auto getITSTPCTRDTrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELS); } + auto getITSTPCTRDSATracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSTPCTRD, MCLABELSEXTRA); } + auto getITSTPCTRDSATrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELSEXTRA); } + + // TPC-TRD + template <class U> + auto getTPCTRDTrack(GTrackID id) const + { + return getTrack<U>(id); + } + template <class U> + auto getTPCTRDTracks() const + { + return getTracks<U>(GTrackID::TPCTRD); + } + auto getTPCTRDTriggers() const + { + return getSpan<o2::trd::TrackTriggerRecord>(GTrackID::TPCTRD, TRACKREFS); + } + auto getTPCTRDTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::TPCTRD, MCLABELS); } + auto getTPCTRDTrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELS); } + auto getTPCTRDSATracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::TPCTRD, MCLABELSEXTRA); } + auto getTPCTRDSATrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELSEXTRA); } + // TRD tracklets + gsl::span<const o2::trd::Tracklet64> getTRDTracklets() const; + gsl::span<const o2::trd::CalibratedTracklet> getTRDCalibratedTracklets() const; + gsl::span<const o2::trd::TriggerRecord> getTRDTriggerRecords() const; + const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* getTRDTrackletsMCLabels() const; + + // TOF + const o2::dataformats::MatchInfoTOF& getTOFMatch(GTrackID id) const { return getObject<o2::dataformats::MatchInfoTOF>(id, MATCHES); } // generic match getter + // TPC-TOF, made of refitted TPC track and separate matchInfo + const o2::dataformats::TrackTPCTOF& getTPCTOFTrack(GTrackID gid) const { return getTrack<o2::dataformats::TrackTPCTOF>(gid); } + const o2::dataformats::MatchInfoTOF& getTPCTOFMatch(GTrackID id) const { return getObject<o2::dataformats::MatchInfoTOF>(id, MATCHES); } + auto getTPCTOFTrackMCLabel(GTrackID id) const { return getObject<o2::MCCompLabel>(id, MCLABELS); } + auto getTPCTOFTracks() const { return getTracks<o2::dataformats::TrackTPCTOF>(GTrackID::TPCTOF); } + // TPC-TOF matches + auto getTPCTOFMatches() const { return getSpan<o2::dataformats::MatchInfoTOF>(GTrackID::TPCTOF, MATCHES); } + auto getTPCTOFTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::TPCTOF, MCLABELS); } + // TPC-TRD-TOF matches + auto getTPCTRDTOFMatches() const { return getSpan<o2::dataformats::MatchInfoTOF>(GTrackID::TPCTRDTOF, MATCHES); } + auto getTPCTRDTOFTracksMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::TPCTRDTOF, MCLABELS); } + // global ITS-TPC-TOF matches + const o2::dataformats::TrackTPCITS& getITSTPCTOFTrack(GTrackID id) const; // this is special since global TOF track is just a reference on TPCITS + auto getITSTPCTOFMatches() const { return getSpan<o2::dataformats::MatchInfoTOF>(GTrackID::ITSTPCTOF, MATCHES); } + auto getITSTPCTOFMatchesMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSTPCTOF, MCLABELS); } + // global ITS-TPC-TRD-TOF matches + // const o2::dataformats::TrackTPCITS& getITSTPCTRDTOFTrack(GTrackID id) const; // TODO this is special since global TOF track is just a reference on TPCITS + auto getITSTPCTRDTOFMatches() const { return getSpan<o2::dataformats::MatchInfoTOF>(GTrackID::ITSTPCTRDTOF, MATCHES); } + auto getITSTPCTRDTOFMatchesMCLabels() const { return getSpan<o2::MCCompLabel>(GTrackID::ITSTPCTRDTOF, MCLABELS); } + + // TOF clusters + auto getTOFClusters() const { return getSpan<o2::tof::Cluster>(GTrackID::TOF, CLUSTERS); } + auto getTOFClustersMCLabels() const { return mcTOFClusters.get(); } + + // FT0 + auto getFT0RecPoints() const { return getSpan<o2::ft0::RecPoints>(GTrackID::FT0, TRACKS); } + auto getFT0ChannelsData() const { return getSpan<o2::ft0::ChannelDataFloat>(GTrackID::FT0, CLUSTERS); } + + // FV0 + auto getFV0RecPoints() const { return getSpan<o2::fv0::RecPoints>(GTrackID::FV0, TRACKS); } + auto getFV0ChannelsData() const { return getSpan<o2::fv0::ChannelDataFloat>(GTrackID::FV0, CLUSTERS); } + + // FDD + auto getFDDRecPoints() const { return getSpan<o2::fdd::RecPoint>(GTrackID::FDD, TRACKS); } + auto getFDDChannelsData() const { return getSpan<o2::fdd::ChannelDataFloat>(GTrackID::FDD, CLUSTERS); } + + // ZDC + auto getZDCBCRecData() const { return getSpan<o2::zdc::BCRecData>(GTrackID::ZDC, MATCHES); } + auto getZDCEnergy() const { return getSpan<o2::zdc::ZDCEnergy>(GTrackID::ZDC, TRACKS); } + auto getZDCTDCData() const { return getSpan<o2::zdc::ZDCTDCData>(GTrackID::ZDC, CLUSTERS); } + auto getZDCInfo() const { return getSpan<uint16_t>(GTrackID::ZDC, PATTERNS); } + + // Primary vertices + const o2::dataformats::PrimaryVertex& getPrimaryVertex(int i) const { return pvtxPool.get_as<o2::dataformats::PrimaryVertex>(PVTX, i); } + const o2::MCEventLabel& getPrimaryVertexMCLabel(int i) const { return pvtxPool.get_as<o2::MCEventLabel>(PVTX_MCTR, i); } + auto getPrimaryVertices() const { return pvtxPool.getSpan<o2::dataformats::PrimaryVertex>(PVTX); } + auto getPrimaryVertexMatchedTracks() const { return pvtxPool.getSpan<o2::dataformats::VtxTrackIndex>(PVTX_TRMTC); } + auto getPrimaryVertexContributors() const { return pvtxPool.getSpan<o2::dataformats::VtxTrackIndex>(PVTX_CONTID); } + auto getPrimaryVertexMatchedTrackRefs() const { return pvtxPool.getSpan<o2::dataformats::VtxTrackRef>(PVTX_TRMTCREFS); } + auto getPrimaryVertexContributorsRefs() const { return pvtxPool.getSpan<o2::dataformats::VtxTrackRef>(PVTX_CONTIDREFS); } + auto getPrimaryVertexMCLabels() const { return pvtxPool.getSpan<o2::MCEventLabel>(PVTX_MCTR); } + + // Secondary vertices + const o2::dataformats::V0& getV0(int i) const { return svtxPool.get_as<o2::dataformats::V0>(V0S, i); } + const o2::dataformats::Cascade& getCascade(int i) const { return svtxPool.get_as<o2::dataformats::Cascade>(CASCS, i); } + auto getV0s() const { return svtxPool.getSpan<o2::dataformats::V0>(V0S); } + auto getPV2V0Refs() { return svtxPool.getSpan<o2::dataformats::RangeReference<int, int>>(PVTX_V0REFS); } + auto getCascades() const { return svtxPool.getSpan<o2::dataformats::Cascade>(CASCS); } + auto getPV2CascadesRefs() { return svtxPool.getSpan<o2::dataformats::RangeReference<int, int>>(PVTX_CASCREFS); } + + const o2::dataformats::TrackCosmics& getCosmicTrack(int i) const { return cosmPool.get_as<o2::dataformats::TrackCosmics>(COSM_TRACKS, i); } + auto getCosmicTrackMCLabel(int i) const { return cosmPool.get_as<o2::MCCompLabel>(COSM_TRACKS_MC, i); } + auto getCosmicTracks() const { return cosmPool.getSpan<o2::dataformats::TrackCosmics>(COSM_TRACKS); } + auto getCosmicTrackMCLabels() const { return cosmPool.getSpan<o2::MCCompLabel>(COSM_TRACKS_MC); } + + // IRFrames where ITS was reconstructed and tracks were seen (e.g. sync.w-flow mult. selection) + auto getIRFramesITS() const { return getSpan<o2::dataformats::IRFrame>(GTrackID::ITS, VARIA); } +}; + +} // namespace globaltracking +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h new file mode 100644 index 0000000000000..73782600cad69 --- /dev/null +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h @@ -0,0 +1,352 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoContainerCreateTracksVariadic.h +/// \brief Wrapper container for different reconstructed object types +/// \author ruben.shahoyan@cern.ch + +#include "Framework/ProcessingContext.h" +#include "Framework/InputSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsMFT/TrackMFT.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTOF/Cluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsFT0/RecPoints.h" +#include "DataFormatsFV0/RecPoints.h" +#include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/TrackTriggerRecord.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" + +//________________________________________________________ +template <class T> +void o2::globaltracking::RecoContainer::createTracksVariadic(T creator) const +{ + // We go from most complete tracks to least complete ones, taking into account that some track times + // do not bear their own kinematics but just constrain the time + // As we get more track types functional, this method should be completed + // If user provided function creator returns true, then the track is considered as consumed and its contributing + // simpler tracks will not be provided to the creator. If it returns false, the creator will be called also + // with this simpler contrubutors. + // The creator function is called with track kinematics, track GlobalTrackID and track timing information as 2 floats + // which depends on the track time: + // 1) For track types containing TimeStampWithError ts it is ts.getTimeStamp(), getTimeStampError() + // 2) For tracks with asymmetric time uncertainty, e.g. TPC: as mean time of t0-errBwd,t+errFwd and 0.5(errBwd+errFwd), all in TPC time bins + // 3) For tracks whose timing is provided as RO frame: as time in \mus for RO frame start since the start of TF, half-duration of RO window. + + auto start_time = std::chrono::high_resolution_clock::now(); + constexpr float PS2MUS = 1e-6; + std::array<std::vector<uint8_t>, GTrackID::NSources> usedData; + auto flagUsed2 = [&usedData](int idx, int src) { + if (!usedData[src].empty()) { + usedData[src][idx] = 1; + } + }; + auto flagUsed = [&usedData, &flagUsed2](const GTrackID gidx) { flagUsed2(gidx.getIndex(), gidx.getSource()); }; + auto isUsed2 = [&usedData](int idx, int src) { return (!usedData[src].empty()) && (usedData[src][idx] != 0); }; + auto isUsed = [&usedData, isUsed2](const GTrackID gidx) { return isUsed2(gidx.getIndex(), gidx.getSource()); }; + + // create only for those data types which are used + const auto tracksITS = getITSTracks(); + const auto trkITABRefs = getITSABRefs(); + const auto tracksMFT = getMFTTracks(); + const auto tracksMCH = getMCHTracks(); + const auto tracksTPC = getTPCTracks(); + const auto tracksTPCITS = getTPCITSTracks(); + const auto tracksMFTMCH = getGlobalFwdTracks(); + const auto tracksTPCTOF = getTPCTOFTracks(); // TOF-TPC tracks with refit + const auto matchesTPCTOF = getTPCTOFMatches(); // and corresponding matches + const auto tracksTPCTRD = getTPCTRDTracks<o2::trd::TrackTRD>(); + const auto matchesITSTPCTOF = getITSTPCTOFMatches(); // just matches, no refit done + const auto tofClusters = getTOFClusters(); + const auto tracksITSTPCTRD = getITSTPCTRDTracks<o2::trd::TrackTRD>(); + + const auto trigTPCTRD = getTPCTRDTriggers(); + + usedData[GTrackID::ITS].resize(tracksITS.size()); // to flag used ITS tracks + usedData[GTrackID::MCH].resize(tracksMCH.size()); // to flag used MCH tracks + usedData[GTrackID::MFT].resize(tracksMFT.size()); // to flag used MFT tracks + usedData[GTrackID::TPC].resize(tracksTPC.size()); // to flag used TPC tracks + usedData[GTrackID::ITSTPC].resize(tracksTPCITS.size()); // to flag used ITSTPC tracks + usedData[GTrackID::MFTMCH].resize(tracksMFTMCH.size()); // to flag used MFTMCH tracks + usedData[GTrackID::ITSTPCTRD].resize(tracksITSTPCTRD.size()); // to flag used ITSTPCTRD tracks + usedData[GTrackID::TPCTRD].resize(tracksTPCTRD.size()); // to flag used TPCTRD tracks + usedData[GTrackID::ITSTPCTOF].resize(getITSTPCTOFMatches().size()); // to flag used ITSTPC-TOF matches + + // ITS-TPC-TRD-TOF + // TODO, will flag used ITS-TPC-TRD + + // ITS-TPC-TRD + { + const auto trigITSTPCTRD = getITSTPCTRDTriggers(); + for (unsigned itr = 0; itr < trigITSTPCTRD.size(); itr++) { + const auto& trig = trigITSTPCTRD[itr]; + float t0 = trig.getBCData().differenceInBC(startIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + for (unsigned i = trig.getTrackRefs().getFirstEntry(); i < trig.getTrackRefs().getEntriesBound(); i++) { + const auto& trc = tracksITSTPCTRD[i]; + if (isUsed2(i, GTrackID::ITSTPCTRD)) { + flagUsed(trc.getRefGlobalTrackId()); // flag seeding ITS-TPC track + continue; + } + if (creator(trc, {i, GTrackID::ITSTPCTRD}, t0, 1e-3)) { // assign 1ns error to BC + flagUsed2(i, GTrackID::ITSTPCTRD); // flag itself (is it needed?) + flagUsed(trc.getRefGlobalTrackId()); // flag seeding ITS-TPC track + } + } + } + } + + // ITS-TPC-TOF matches, thes are just MatchInfoTOF objects, pointing on ITS-TPC match and TOF cl. + { + + if (matchesITSTPCTOF.size() && (!tofClusters.size() || !tracksTPCITS.size())) { + throw std::runtime_error(fmt::format("Global-TOF tracks ({}) require ITS-TPC tracks ({}) and TOF clusters ({})", + matchesITSTPCTOF.size(), tracksTPCITS.size(), tofClusters.size())); + } + for (unsigned i = 0; i < matchesITSTPCTOF.size(); i++) { + const auto& match = matchesITSTPCTOF[i]; + auto gidx = match.getTrackRef(); // this should be corresponding ITS-TPC track + if (isUsed(gidx)) { // RS FIXME: THIS IS TEMPORARY, until the TOF matching will use ITS-TPC-TRD as an input + continue; + } + // no need to check isUsed: by construction this ITS-TPC was not used elsewhere + const auto& tofCl = tofClusters[match.getTOFClIndex()]; + float timeTOFMUS = (tofCl.getTime() - match.getLTIntegralOut().getTOF(o2::track::PID::Pion)) * PS2MUS; // tof time in \mus, FIXME: account for time of flight to R TOF + const float timeErr = 0.010f; // assume 10 ns error FIXME + if (creator(tracksTPCITS[gidx.getIndex()], {i, GTrackID::ITSTPCTOF}, timeTOFMUS, timeErr)) { + //flagUsed2(i, GTrackID::TOF); // flag used TOF match // TODO might be not needed + flagUsed(gidx); // flag used ITS-TPC tracks + } + } + } + + // TPC-TRD + { + const auto trigTPCTRD = getTPCTRDTriggers(); + for (unsigned itr = 0; itr < trigTPCTRD.size(); itr++) { + const auto& trig = trigTPCTRD[itr]; + float t0 = trig.getBCData().differenceInBC(startIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + for (unsigned i = trig.getTrackRefs().getFirstEntry(); i < trig.getTrackRefs().getEntriesBound(); i++) { + const auto& trc = tracksTPCTRD[i]; + if (isUsed2(i, GTrackID::TPCTRD)) { + flagUsed(trc.getRefGlobalTrackId()); // flag seeding TPC track + continue; + } + if (creator(trc, {i, GTrackID::TPCTRD}, t0, 1e-3)) { // assign 1ns error to BC + flagUsed2(i, GTrackID::TPCTRD); // flag itself (is it needed?) + flagUsed(trc.getRefGlobalTrackId()); // flag seeding TPC track + } + } + } + } + + // ITS-TPC matches, may refer to ITS, TPC (TODO: something else?) tracks + { + for (unsigned i = 0; i < tracksTPCITS.size(); i++) { + const auto& matchTr = tracksTPCITS[i]; + if (isUsed2(i, GTrackID::ITSTPC)) { + flagUsed(matchTr.getRefITS()); // flag used ITS tracks or AB tracklets (though the latter is not really necessary) + flagUsed(matchTr.getRefTPC()); // flag used TPC tracks + continue; + } + if (creator(matchTr, {i, GTrackID::ITSTPC}, matchTr.getTimeMUS().getTimeStamp(), matchTr.getTimeMUS().getTimeStampError())) { + flagUsed2(i, GTrackID::ITSTPC); + flagUsed(matchTr.getRefITS()); // flag used ITS tracks or AB tracklets (though the latter is not really necessary) + flagUsed(matchTr.getRefTPC()); // flag used TPC tracks + } + } + } + + // TPC-TOF matches, may refer to TPC (TODO: something else?) tracks + { + if (matchesTPCTOF.size() && !tracksTPCTOF.size()) { + throw std::runtime_error(fmt::format("TPC-TOF matched tracks ({}) require TPCTOF matches ({}) and TPCTOF tracks ({})", + matchesTPCTOF.size(), tracksTPCTOF.size())); + } + for (unsigned i = 0; i < matchesTPCTOF.size(); i++) { + const auto& match = matchesTPCTOF[i]; + const auto& gidx = match.getTrackRef(); // TPC track global idx + if (isUsed(gidx)) { // is TPC track already used + continue; + } + const auto& trc = tracksTPCTOF[i]; + if (creator(trc, {i, GTrackID::TPCTOF}, trc.getTimeMUS().getTimeStamp(), trc.getTimeMUS().getTimeStampError())) { + flagUsed(gidx); // flag used TPC tracks + } + } + } + + // MFT-MCH tracks + { + for (unsigned i = 0; i < tracksMFTMCH.size(); i++) { + const auto& matchTr = tracksMFTMCH[i]; + if (creator(matchTr, {i, GTrackID::MFTMCH}, matchTr.getTimeMUS().getTimeStamp(), matchTr.getTimeMUS().getTimeStampError())) { + flagUsed2(i, GTrackID::MFTMCH); + } + } + } + + // TPC only tracks + { + int nacc = 0, noffer = 0; + for (unsigned i = 0; i < tracksTPC.size(); i++) { + if (isUsed2(i, GTrackID::TPC)) { // skip used tracks + continue; + } + const auto& trc = tracksTPC[i]; + if (creator(trc, {i, GTrackID::TPC}, trc.getTime0() + 0.5 * (trc.getDeltaTFwd() - trc.getDeltaTBwd()), 0.5 * (trc.getDeltaTFwd() + trc.getDeltaTBwd()))) { + flagUsed2(i, GTrackID::TPC); // flag used TPC tracks + } + } + } + + // ITS only tracks + { + const auto& rofrs = getITSTracksROFRecords(); + for (unsigned irof = 0; irof < rofrs.size(); irof++) { + const auto& rofRec = rofrs[irof]; + float t0 = rofRec.getBCData().differenceInBC(startIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + int trlim = rofRec.getFirstEntry() + rofRec.getNEntries(); + for (int it = rofRec.getFirstEntry(); it < trlim; it++) { + if (isUsed2(it, GTrackID::ITS)) { // skip used tracks + continue; + } + GTrackID gidITS(it, GTrackID::ITS); + const auto& trc = getTrack<o2::its::TrackITS>(gidITS); + if (creator(trc, gidITS, t0, 0.5)) { + flagUsed2(it, GTrackID::ITS); + } + } + } + } + + // MFT only tracks + { + const auto& rofrs = getMFTTracksROFRecords(); + for (unsigned irof = 0; irof < rofrs.size(); irof++) { + const auto& rofRec = rofrs[irof]; + float t0 = rofRec.getBCData().differenceInBC(startIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + int trlim = rofRec.getFirstEntry() + rofRec.getNEntries(); + for (int it = rofRec.getFirstEntry(); it < trlim; it++) { + + GTrackID gidMFT(it, GTrackID::MFT); + const auto& trc = getTrack<o2::mft::TrackMFT>(gidMFT); + if (creator(trc, gidMFT, t0, 0.5)) { + flagUsed2(it, GTrackID::MFT); + } + } + } + } + + // MCH standalone tracks + { + const auto& rofs = getMCHTracksROFRecords(); + constexpr float bc2ns = o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + for (const auto& rof : rofs) { + auto bcWidth = 56; + // FIXME (LA): should really be rof.getBCWidth() once + // getBCWidth is actually set to a meaningfull value. + // For now we hard-code a 1.4 microseconds window for all tracks + auto rofMeanBC = rof.getBCData().differenceInBC(startIR) + bcWidth / 2; + float t0 = rofMeanBC * bc2ns; + float t0err = bc2ns * bcWidth / 2; + for (int idx = rof.getFirstIdx(); idx <= rof.getLastIdx(); ++idx) { + GTrackID gidMCH(idx, GTrackID::MCH); + const auto& trc = getTrack<o2::mch::TrackMCH>(gidMCH); + if (creator(trc, gidMCH, t0, t0err)) { + flagUsed2(idx, GTrackID::MCH); + } + } + } + } + + auto current_time = std::chrono::high_resolution_clock::now(); + LOG(INFO) << "RecoContainer::createTracks took " << std::chrono::duration_cast<std::chrono::microseconds>(current_time - start_time).count() * 1e-6 << " CPU s."; +} + +template <class T> +inline constexpr auto isITSTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::its::TrackITS>; +} + +template <class T> +inline constexpr auto isITSABRef() +{ + return std::is_same_v<std::decay_t<T>, o2::itsmft::TrkClusRef>; +} + +template <class T> +inline constexpr auto isMFTTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::mft::TrackMFT>; +} + +template <class T> +inline constexpr auto isMCHTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::mch::TrackMCH>; +} + +template <class T> +inline constexpr auto isTPCTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::tpc::TrackTPC>; +} + +template <class T> +inline constexpr auto isTRDTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::trd::TrackTRD>; +} + +template <class T> +inline constexpr auto isTPCTOFTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::dataformats::TrackTPCTOF>; +} + +template <class T> +inline constexpr auto isTPCITSTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::dataformats::TrackTPCITS>; +} + +template <class T> +inline constexpr auto isGlobalFwdTrack() +{ + return std::is_same_v<std::decay_t<T>, o2::dataformats::GlobalFwdTrack>; +} + +template <class T> +inline constexpr auto isTPCTRDTOFTrack() +{ + return false; +} // to be implemented + +template <class T> +inline constexpr auto isITSTPCTRDTOFTrack() +{ + return false; +} // to be implemented diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx new file mode 100644 index 0000000000000..49ec1059fbca8 --- /dev/null +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -0,0 +1,923 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoContainer.cxx +/// \brief Wrapper container for different reconstructed object types +/// \author ruben.shahoyan@cern.ch + +#include <fmt/format.h> +#include <chrono> +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "CommonDataFormat/TimeStamp.h" +#include "CommonDataFormat/IRFrame.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "SimulationDataFormat/MCEventLabel.h" +#include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/Cascade.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "ReconstructionDataFormats/TrackCosmics.h" +#include "DataFormatsITSMFT/TrkClusRef.h" +// FIXME: ideally, the data formats definition should be independent of the framework +// collectData is using the input of ProcessingContext to extract the first valid +// header and the TF orbit from it +#include "Framework/ProcessingContext.h" +#include "Framework/DataRefUtils.h" + +using namespace o2::globaltracking; +using namespace o2::framework; +namespace o2d = o2::dataformats; + +using GTrackID = o2d::GlobalTrackID; +using DetID = o2::detectors::DetID; + +RecoContainer::RecoContainer() = default; +RecoContainer::~RecoContainer() = default; + +void DataRequest::addInput(const InputSpec&& isp) +{ + if (std::find(inputs.begin(), inputs.end(), isp) == inputs.end()) { + inputs.emplace_back(isp); + } +} + +void DataRequest::requestIRFramesITS() +{ + addInput({"IRFramesITS", "ITS", "IRFRAMES", 0, Lifetime::Timeframe}); + requestMap["IRFramesITS"] = false; +} + +void DataRequest::requestITSTracks(bool mc) +{ + addInput({"trackITS", "ITS", "TRACKS", 0, Lifetime::Timeframe}); + addInput({"trackITSROF", "ITS", "ITSTrackROF", 0, Lifetime::Timeframe}); + addInput({"trackClIdx", "ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trackITSMCTR", "ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}); + } + requestMap["trackITS"] = mc; +} + +void DataRequest::requestMFTTracks(bool mc) +{ + addInput({"trackMFT", "MFT", "TRACKS", 0, Lifetime::Timeframe}); + addInput({"trackMFTROF", "MFT", "MFTTrackROF", 0, Lifetime::Timeframe}); + addInput({"trackClIdx", "MFT", "TRACKCLSID", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trackMFTMCTR", "MFT", "TRACKSMCTR", 0, Lifetime::Timeframe}); + } + requestMap["trackMFT"] = mc; +} + +void DataRequest::requestMCHTracks(bool mc) +{ + addInput({"trackMCH", "MCH", "TRACKS", 0, Lifetime::Timeframe}); + addInput({"trackMCHROF", "MCH", "TRACKROFS", 0, Lifetime::Timeframe}); + addInput({"trackMCHTRACKCLUSTERS", "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trackMCHMCTR", "MCH", "TRACKLABELS", 0, Lifetime::Timeframe}); + } + requestMap["trackMCH"] = mc; +} + +void DataRequest::requestTPCTracks(bool mc) +{ + addInput({"trackTPC", "TPC", "TRACKS", 0, Lifetime::Timeframe}); + addInput({"trackTPCClRefs", "TPC", "CLUSREFS", 0, Lifetime::Timeframe}); + if (requestMap.find("clusTPC") != requestMap.end()) { + addInput({"clusTPCshmap", "TPC", "CLSHAREDMAP", 0, Lifetime::Timeframe}); + } + if (mc) { + addInput({"trackTPCMCTR", "TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe}); + } + requestMap["trackTPC"] = mc; +} + +void DataRequest::requestITSTPCTracks(bool mc) +{ + addInput({"trackITSTPC", "GLO", "TPCITS", 0, Lifetime::Timeframe}); + addInput({"trackITSTPCABREFS", "GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe}); + addInput({"trackITSTPCABCLID", "GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trackITSTPCMCTR", "GLO", "TPCITS_MC", 0, Lifetime::Timeframe}); + addInput({"trackITSTPCABMCTR", "GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe}); + } + requestMap["trackITSTPC"] = mc; +} + +void DataRequest::requestGlobalFwdTracks(bool mc) +{ + addInput({"fwdtracks", "GLO", "GLFWD", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"MCTruth", "GLO", "GLFWD_MC", 0, Lifetime::Timeframe}); + } + requestMap["fwdtracks"] = mc; +} + +void DataRequest::requestTPCTOFTracks(bool mc) +{ + auto ss = getMatchingInputSubSpec(); + addInput({"matchTPCTOF", "TOF", "MTC_TPC", ss, Lifetime::Timeframe}); + addInput({"trackTPCTOF", "TOF", "TOFTRACKS_TPC", ss, Lifetime::Timeframe}); + if (mc) { + addInput({"clsTOF_TPC_MCTR", "TOF", "MCMATCHTOF_TPC", ss, Lifetime::Timeframe}); + } + requestMap["trackTPCTOF"] = mc; +} + +void DataRequest::requestITSTPCTRDTracks(bool mc) +{ + addInput({"trackITSTPCTRD", "TRD", "MATCH_ITSTPC", 0, Lifetime::Timeframe}); + addInput({"trigITSTPCTRD", "TRD", "TRGREC_ITSTPC", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trackITSTPCTRDMCTR", "TRD", "MCLB_ITSTPC", 0, Lifetime::Timeframe}); + addInput({"trackITSTPCTRDSAMCTR", "TRD", "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe}); + } + requestMap["trackITSTPCTRD"] = mc; +} + +void DataRequest::requestTPCTRDTracks(bool mc) +{ + auto ss = getMatchingInputSubSpec(); + addInput({"trackTPCTRD", "TRD", "MATCH_TPC", ss, Lifetime::Timeframe}); + addInput({"trigTPCTRD", "TRD", "TRGREC_TPC", ss, Lifetime::Timeframe}); + if (mc) { + addInput({"trackTPCTRDMCTR", "TRD", "MCLB_TPC", ss, Lifetime::Timeframe}); + addInput({"trackTPCTRDSAMCTR", "TRD", "MCLB_TPC_TRD", ss, Lifetime::Timeframe}); + } + requestMap["trackTPCTRD"] = mc; +} + +void DataRequest::requestTOFMatches(bool mc) +{ + addInput({"matchITSTPCTOF", "TOF", "MTC_ITSTPC", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"clsTOF_GLO_MCTR", "TOF", "MCMATCHTOF", 0, Lifetime::Timeframe}); + } + requestMap["matchTOF"] = mc; +} + +void DataRequest::requestITSClusters(bool mc) +{ + addInput({"clusITS", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe}); + addInput({"clusITSPatt", "ITS", "PATTERNS", 0, Lifetime::Timeframe}); + addInput({"clusITSROF", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"clusITSMC", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe}); + } + requestMap["clusITS"] = mc; +} + +void DataRequest::requestMFTClusters(bool mc) +{ + addInput({"clusMFT", "MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe}); + addInput({"clusMFTPatt", "MFT", "PATTERNS", 0, Lifetime::Timeframe}); + addInput({"clusMFTROF", "MFT", "CLUSTERSROF", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"clusMFTMC", "MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe}); + } + requestMap["clusMFT"] = mc; +} + +void DataRequest::requestTPCClusters(bool mc) +{ + addInput({"clusTPC", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe}); + if (requestMap.find("trackTPC") != requestMap.end()) { + addInput({"clusTPCshmap", "TPC", "CLSHAREDMAP", 0, Lifetime::Timeframe}); + } + if (mc) { + addInput({"clusTPCMC", ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}, Lifetime::Timeframe}); + } + requestMap["clusTPC"] = mc; +} + +void DataRequest::requestTOFClusters(bool mc) +{ + addInput({"tofcluster", "TOF", "CLUSTERS", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"tofclusterlabel", "TOF", "CLUSTERSMCTR", 0, Lifetime::Timeframe}); + } + requestMap["clusTOF"] = mc; +} + +void DataRequest::requestTRDTracklets(bool mc) +{ + addInput({"trdtracklets", o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe}); + addInput({"trdctracklets", o2::header::gDataOriginTRD, "CTRACKLETS", 0, Lifetime::Timeframe}); + addInput({"trdtrigrecmask", o2::header::gDataOriginTRD, "TRIGRECMASK", 0, Lifetime::Timeframe}); + addInput({"trdtriggerrec", o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"trdtrackletlabels", o2::header::gDataOriginTRD, "TRKLABELS", 0, Lifetime::Timeframe}); + } + requestMap["trackletTRD"] = mc; +} + +void DataRequest::requestFT0RecPoints(bool mc) +{ + addInput({"ft0recpoints", "FT0", "RECPOINTS", 0, Lifetime::Timeframe}); + addInput({"ft0channels", "FT0", "RECCHDATA", 0, Lifetime::Timeframe}); + if (mc) { + LOG(ERROR) << "FT0 RecPoint does not support MC truth"; + } + requestMap["FT0"] = false; +} + +void DataRequest::requestFV0RecPoints(bool mc) +{ + addInput({"fv0recpoints", "FV0", "RECPOINTS", 0, Lifetime::Timeframe}); + addInput({"fv0channels", "FV0", "RECCHDATA", 0, Lifetime::Timeframe}); + if (mc) { + LOG(ERROR) << "FV0 RecPoint does not support MC truth"; + } + requestMap["FV0"] = false; +} + +void DataRequest::requestFDDRecPoints(bool mc) +{ + addInput({"fddrecpoints", "FDD", "RECPOINTS", 0, Lifetime::Timeframe}); + addInput({"fddchannels", "FDD", "RECCHDATA", 0, Lifetime::Timeframe}); + if (mc) { + LOG(ERROR) << "FDD RecPoint does not support MC truth"; + } + requestMap["FDD"] = false; +} + +void DataRequest::requestZDCRecEvents(bool mc) +{ + addInput({"zdcbcrec", "ZDC", "BCREC", 0, Lifetime::Timeframe}); + addInput({"zdcenergy", "ZDC", "ENERGY", 0, Lifetime::Timeframe}); + addInput({"zdctdcdata", "ZDC", "TDCDATA", 0, Lifetime::Timeframe}); + addInput({"zdcinfo", "ZDC", "INFO", 0, Lifetime::Timeframe}); + if (mc) { + LOG(ERROR) << "ZDC RecEvent does not support MC truth"; + } + requestMap["ZDC"] = false; +} + +void DataRequest::requestCoscmicTracks(bool mc) +{ + addInput({"cosmics", "GLO", "COSMICTRC", 0, Lifetime::Timeframe}); + if (mc) { + addInput({"cosmicsMC", "GLO", "COSMICTRC_MC", 0, Lifetime::Timeframe}); + } + requestMap["Cosmics"] = mc; +} + +void DataRequest::requestPrimaryVertertices(bool mc) +{ + addInput({"pvtx", "GLO", "PVTX", 0, Lifetime::Timeframe}); + addInput({"pvtx_trmtc", "GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe}); // global ids of associated tracks + addInput({"pvtx_tref", "GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe}); // vertex - trackID refs + if (mc) { + addInput({"pvtx_mc", "GLO", "PVTX_MCTR", 0, Lifetime::Timeframe}); + } + requestMap["PVertex"] = mc; +} + +void DataRequest::requestPrimaryVerterticesTMP(bool mc) // primary vertices before global vertex-track matching +{ + addInput({"pvtx", "GLO", "PVTX", 0, Lifetime::Timeframe}); + addInput({"pvtx_cont", "GLO", "PVTX_CONTID", 0, Lifetime::Timeframe}); // global ids of contributors + addInput({"pvtx_contref", "GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe}); // vertex - trackID refs of contributors + if (mc) { + addInput({"pvtx_mc", "GLO", "PVTX_MCTR", 0, Lifetime::Timeframe}); + } + requestMap["PVertexTMP"] = mc; +} + +void DataRequest::requestSecondaryVertertices(bool) +{ + addInput({"v0s", "GLO", "V0S", 0, Lifetime::Timeframe}); + addInput({"p2v0s", "GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe}); + addInput({"cascs", "GLO", "CASCS", 0, Lifetime::Timeframe}); + addInput({"p2cascs", "GLO", "PVTX_CASCREFS", 0, Lifetime::Timeframe}); + requestMap["SVertex"] = false; // no MC provided for secondary vertices +} + +void DataRequest::requestTracks(GTrackID::mask_t src, bool useMC) +{ + // request tracks for sources probided by the mask + if (src[GTrackID::ITS]) { + requestITSTracks(useMC); + } + if (src[GTrackID::MFT]) { + requestMFTTracks(useMC); + } + if (src[GTrackID::MCH]) { + requestMCHTracks(useMC); + } + if (src[GTrackID::TPC]) { + requestTPCTracks(useMC); + } + if (src[GTrackID::ITSTPC] || src[GTrackID::ITSTPCTOF]) { + requestITSTPCTracks(useMC); + } + if (src[GTrackID::MFTMCH]) { + requestGlobalFwdTracks(useMC); + } + if (src[GTrackID::TPCTOF]) { + requestTPCTOFTracks(useMC); + } + if (src[GTrackID::ITSTPCTOF]) { + requestTOFMatches(useMC); + requestTOFClusters(false); // RSTODO Needed just to set the time of ITSTPC track, consider moving to MatchInfoTOF + // NOTE: Getting TOF Clusters is carried over to InputHelper::addInputSpecs. If changed here, please fix there. + } + if (src[GTrackID::ITSTPCTRD]) { + requestITSTPCTRDTracks(useMC); + } + if (src[GTrackID::TPCTRD]) { + requestTPCTRDTracks(useMC); + } +} + +void DataRequest::requestClusters(GTrackID::mask_t src, bool useMC) +{ + // request clusters for detectors of the sources probided by the mask + + // clusters needed for refits + if (GTrackID::includesDet(DetID::ITS, src)) { + requestITSClusters(useMC); + } + if (GTrackID::includesDet(DetID::MFT, src)) { + requestMFTClusters(useMC); + } + if (GTrackID::includesDet(DetID::TPC, src)) { + requestTPCClusters(useMC); + } + if (GTrackID::includesDet(DetID::TOF, src)) { + requestTOFClusters(useMC); + } + if (GTrackID::includesDet(DetID::TRD, src)) { + requestTRDTracklets(useMC); + } +} + +//__________________________________________________________________ +void RecoContainer::collectData(ProcessingContext& pc, const DataRequest& requests) +{ + auto& reqMap = requests.requestMap; + + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + startIR = {0, dh->firstTForbit}; + + auto req = reqMap.find("trackITS"); + if (req != reqMap.end()) { + addITSTracks(pc, req->second); + } + + req = reqMap.find("trackMFT"); + if (req != reqMap.end()) { + addMFTTracks(pc, req->second); + } + + req = reqMap.find("trackMCH"); + if (req != reqMap.end()) { + addMCHTracks(pc, req->second); + } + + req = reqMap.find("trackTPC"); + if (req != reqMap.end()) { + addTPCTracks(pc, req->second); + } + + req = reqMap.find("trackITSTPC"); + if (req != reqMap.end()) { + addITSTPCTracks(pc, req->second); + } + + req = reqMap.find("fwdtracks"); + if (req != reqMap.end()) { + addGlobalFwdTracks(pc, req->second); + } + + req = reqMap.find("trackITSTPCTRD"); + if (req != reqMap.end()) { + addITSTPCTRDTracks(pc, req->second); + } + + req = reqMap.find("trackTPCTRD"); + if (req != reqMap.end()) { + addTPCTRDTracks(pc, req->second); + } + + req = reqMap.find("trackTPCTOF"); + if (req != reqMap.end()) { + addTPCTOFTracks(pc, req->second); + } + + req = reqMap.find("matchTOF"); + if (req != reqMap.end()) { + addTOFMatches(pc, req->second); + } + + req = reqMap.find("clusITS"); + if (req != reqMap.end()) { + addITSClusters(pc, req->second); + } + + req = reqMap.find("clusMFT"); + if (req != reqMap.end()) { + addMFTClusters(pc, req->second); + } + + req = reqMap.find("clusTPC"); + if (req != reqMap.end()) { + addTPCClusters(pc, req->second, reqMap.find("trackTPC") != reqMap.end()); + } + + req = reqMap.find("clusTOF"); + if (req != reqMap.end()) { + addTOFClusters(pc, req->second); + } + + req = reqMap.find("FT0"); + if (req != reqMap.end()) { + addFT0RecPoints(pc, req->second); + } + + req = reqMap.find("FV0"); + if (req != reqMap.end()) { + addFV0RecPoints(pc, req->second); + } + + req = reqMap.find("FDD"); + if (req != reqMap.end()) { + addFDDRecPoints(pc, req->second); + } + + req = reqMap.find("ZDC"); + if (req != reqMap.end()) { + addZDCRecEvents(pc, req->second); + } + + req = reqMap.find("trackletTRD"); + if (req != reqMap.end()) { + addTRDTracklets(pc, req->second); + } + + req = reqMap.find("Cosmics"); + if (req != reqMap.end()) { + addCosmicTracks(pc, req->second); + } + + req = reqMap.find("PVertex"); + if (req != reqMap.end()) { + addPVertices(pc, req->second); + } + + req = reqMap.find("PVertexTMP"); + if (req != reqMap.end()) { + addPVerticesTMP(pc, req->second); + } + + req = reqMap.find("SVertex"); + if (req != reqMap.end()) { + addSVertices(pc, req->second); + } + + req = reqMap.find("IRFramesITS"); + if (req != reqMap.end()) { + addIRFramesITS(pc); + } +} + +//____________________________________________________________ +void RecoContainer::addSVertices(ProcessingContext& pc, bool) +{ + svtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::V0>>("v0s"), V0S); + svtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::RangeReference<int, int>>>("p2v0s"), PVTX_V0REFS); + svtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::Cascade>>("cascs"), CASCS); + svtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::RangeReference<int, int>>>("p2cascs"), PVTX_CASCREFS); + // no mc +} + +//____________________________________________________________ +void RecoContainer::addPVertices(ProcessingContext& pc, bool mc) +{ + if (!pvtxPool.isLoaded(PVTX)) { // in case was loaded via addPVerticesTMP + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::PrimaryVertex>>("pvtx"), PVTX); + } + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::VtxTrackIndex>>("pvtx_trmtc"), PVTX_TRMTC); + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::VtxTrackRef>>("pvtx_tref"), PVTX_TRMTCREFS); + + if (mc && !pvtxPool.isLoaded(PVTX_MCTR)) { // in case was loaded via addPVerticesTMP + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::MCEventLabel>>("pvtx_mc"), PVTX_MCTR); + } +} + +//____________________________________________________________ +void RecoContainer::addPVerticesTMP(ProcessingContext& pc, bool mc) +{ + if (!pvtxPool.isLoaded(PVTX)) { // in case was loaded via addPVertices + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::PrimaryVertex>>("pvtx"), PVTX); + } + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::VtxTrackIndex>>("pvtx_cont"), PVTX_CONTID); + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::VtxTrackRef>>("pvtx_contref"), PVTX_CONTIDREFS); + + if (mc && !pvtxPool.isLoaded(PVTX_MCTR)) { // in case was loaded via addPVertices + pvtxPool.registerContainer(pc.inputs().get<gsl::span<o2::MCEventLabel>>("pvtx_mc"), PVTX_MCTR); + } +} + +//____________________________________________________________ +void RecoContainer::addCosmicTracks(ProcessingContext& pc, bool mc) +{ + cosmPool.registerContainer(pc.inputs().get<gsl::span<o2::dataformats::TrackCosmics>>("cosmics"), COSM_TRACKS); + if (mc) { + cosmPool.registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("cosmicsMC"), COSM_TRACKS_MC); + } +} + +//____________________________________________________________ +void RecoContainer::addITSTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::its::TrackITS>>("trackITS"), TRACKS); + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<int>>("trackClIdx"), INDICES); + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("trackITSROF"), TRACKREFS); + if (mc) { + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSMCTR"), MCLABELS); + } +} + +//____________________________________________________________ +void RecoContainer::addIRFramesITS(ProcessingContext& pc) +{ + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::dataformats::IRFrame>>("IRFramesITS"), VARIA); +} + +//____________________________________________________________ +void RecoContainer::addMFTTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<o2::mft::TrackMFT>>("trackMFT"), TRACKS); + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<int>>("trackClIdx"), INDICES); + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("trackMFTROF"), TRACKREFS); + if (mc) { + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackMFTMCTR"), MCLABELS); + } +} + +//____________________________________________________________ +void RecoContainer::addMCHTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::MCH].registerContainer(pc.inputs().get<gsl::span<o2::mch::TrackMCH>>("trackMCH"), TRACKS); + commonPool[GTrackID::MCH].registerContainer(pc.inputs().get<gsl::span<o2::mch::ROFRecord>>("trackMCHROF"), TRACKREFS); + commonPool[GTrackID::MCH].registerContainer(pc.inputs().get<gsl::span<o2::mch::ClusterStruct>>("trackMCHTRACKCLUSTERS"), CLUSREFS); + if (mc) { + commonPool[GTrackID::MCH].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackMCHMCTR"), MCLABELS); + } + // FIXME-LA : add track clusters +} + +//____________________________________________________________ +void RecoContainer::addTPCTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::TPC].registerContainer(pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("trackTPC"), TRACKS); + commonPool[GTrackID::TPC].registerContainer(pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs"), INDICES); + if (mc) { + commonPool[GTrackID::TPC].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackTPCMCTR"), MCLABELS); + } +} + +//__________________________________________________________ +void RecoContainer::addITSTPCTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ITSTPC].registerContainer(pc.inputs().get<gsl::span<o2d::TrackTPCITS>>("trackITSTPC"), TRACKS); + commonPool[GTrackID::ITSAB].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::TrkClusRef>>("trackITSTPCABREFS"), TRACKREFS); + commonPool[GTrackID::ITSAB].registerContainer(pc.inputs().get<gsl::span<int>>("trackITSTPCABCLID"), INDICES); + if (mc) { + commonPool[GTrackID::ITSTPC].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSTPCMCTR"), MCLABELS); + commonPool[GTrackID::ITSAB].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSTPCABMCTR"), MCLABELS); + } +} + +//__________________________________________________________ +void RecoContainer::addGlobalFwdTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::MFTMCH].registerContainer(pc.inputs().get<gsl::span<o2d::GlobalFwdTrack>>("fwdtracks"), TRACKS); + if (mc) { + commonPool[GTrackID::MFTMCH].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("MCTruth"), MCLABELS); + } +} + +//__________________________________________________________ +void RecoContainer::addITSTPCTRDTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ITSTPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::trd::TrackTRD>>("trackITSTPCTRD"), TRACKS); + commonPool[GTrackID::ITSTPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::trd::TrackTriggerRecord>>("trigITSTPCTRD"), TRACKREFS); + if (mc) { + commonPool[GTrackID::ITSTPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSTPCTRDMCTR"), MCLABELS); + commonPool[GTrackID::ITSTPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSTPCTRDSAMCTR"), MCLABELSEXTRA); + } +} + +//__________________________________________________________ +void RecoContainer::addTPCTRDTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::TPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::trd::TrackTRD>>("trackTPCTRD"), TRACKS); + commonPool[GTrackID::TPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::trd::TrackTriggerRecord>>("trigTPCTRD"), TRACKREFS); + if (mc) { + commonPool[GTrackID::TPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackTPCTRDMCTR"), MCLABELS); + commonPool[GTrackID::TPCTRD].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackTPCTRDSAMCTR"), MCLABELSEXTRA); + } +} + +//__________________________________________________________ +void RecoContainer::addTPCTOFTracks(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::TPCTOF].registerContainer(pc.inputs().get<gsl::span<o2d::TrackTPCTOF>>("trackTPCTOF"), TRACKS); + commonPool[GTrackID::TPCTOF].registerContainer(pc.inputs().get<gsl::span<o2d::MatchInfoTOF>>("matchTPCTOF"), MATCHES); + if (mc) { + commonPool[GTrackID::TPCTOF].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("clsTOF_TPC_MCTR"), MCLABELS); + } +} + +//__________________________________________________________ +void RecoContainer::addTOFMatches(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ITSTPCTOF].registerContainer(pc.inputs().get<gsl::span<o2d::MatchInfoTOF>>("matchITSTPCTOF"), MATCHES); //only ITS/TPC : TOF match info, no real tracks + if (mc) { + commonPool[GTrackID::ITSTPCTOF].registerContainer(pc.inputs().get<gsl::span<o2::MCCompLabel>>("clsTOF_GLO_MCTR"), MCLABELS); + } +} + +//__________________________________________________________ +void RecoContainer::addITSClusters(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("clusITSROF"), CLUSREFS); + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("clusITS"), CLUSTERS); + commonPool[GTrackID::ITS].registerContainer(pc.inputs().get<gsl::span<unsigned char>>("clusITSPatt"), PATTERNS); + if (mc) { + mcITSClusters = pc.inputs().get<const dataformats::MCTruthContainer<MCCompLabel>*>("clusITSMC"); + } +} + +//__________________________________________________________ +void RecoContainer::addMFTClusters(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("clusMFTROF"), CLUSREFS); + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("clusMFT"), CLUSTERS); + commonPool[GTrackID::MFT].registerContainer(pc.inputs().get<gsl::span<unsigned char>>("clusMFTPatt"), PATTERNS); +} + +//__________________________________________________________ +void RecoContainer::addTPCClusters(ProcessingContext& pc, bool mc, bool shmap) +{ + inputsTPCclusters = o2::tpc::getWorkflowTPCInput(pc, 0, mc); + if (shmap) { + clusterShMapTPC = pc.inputs().get<gsl::span<unsigned char>>("clusTPCshmap"); + } +} + +//__________________________________________________________ +void RecoContainer::addTRDTracklets(ProcessingContext& pc, bool mc) +{ + inputsTRD = o2::trd::getRecoInputContainer(pc, nullptr, this, mc); +} + +//__________________________________________________________ +void RecoContainer::addTOFClusters(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::TOF].registerContainer(pc.inputs().get<gsl::span<o2::tof::Cluster>>("tofcluster"), CLUSTERS); + if (mc) { + mcTOFClusters = pc.inputs().get<const dataformats::MCTruthContainer<MCCompLabel>*>("tofclusterlabel"); + } +} + +//__________________________________________________________ +void RecoContainer::addFT0RecPoints(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::FT0].registerContainer(pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("ft0recpoints"), TRACKS); + commonPool[GTrackID::FT0].registerContainer(pc.inputs().get<gsl::span<o2::ft0::ChannelDataFloat>>("ft0channels"), CLUSTERS); + + if (mc) { + LOG(ERROR) << "FT0 RecPoint does not support MC truth"; + } +} + +//__________________________________________________________ +void RecoContainer::addFV0RecPoints(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::FV0].registerContainer(pc.inputs().get<gsl::span<o2::fv0::RecPoints>>("fv0recpoints"), TRACKS); + commonPool[GTrackID::FV0].registerContainer(pc.inputs().get<gsl::span<o2::fv0::ChannelDataFloat>>("fv0channels"), CLUSTERS); + + if (mc) { + LOG(ERROR) << "FV0 RecPoint does not support MC truth"; + } +} + +//__________________________________________________________ +void RecoContainer::addFDDRecPoints(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::FDD].registerContainer(pc.inputs().get<gsl::span<o2::fdd::RecPoint>>("fddrecpoints"), TRACKS); + commonPool[GTrackID::FDD].registerContainer(pc.inputs().get<gsl::span<o2::fdd::ChannelDataFloat>>("fddchannels"), CLUSTERS); + + if (mc) { + LOG(ERROR) << "FDD RecPoint does not support MC truth"; + } +} + +//__________________________________________________________ +void RecoContainer::addZDCRecEvents(ProcessingContext& pc, bool mc) +{ + commonPool[GTrackID::ZDC].registerContainer(pc.inputs().get<gsl::span<o2::zdc::BCRecData>>("zdcbcrecdata"), MATCHES); + commonPool[GTrackID::ZDC].registerContainer(pc.inputs().get<gsl::span<o2::zdc::ZDCEnergy>>("zdcenergy"), TRACKS); + commonPool[GTrackID::ZDC].registerContainer(pc.inputs().get<gsl::span<o2::zdc::ZDCTDCData>>("zdctdcdata"), CLUSTERS); + commonPool[GTrackID::ZDC].registerContainer(pc.inputs().get<gsl::span<uint16_t>>("zdcinfo"), PATTERNS); + + if (mc) { + LOG(ERROR) << "ZDC RecEvent does not support MC truth"; + } +} + +const o2::tpc::ClusterNativeAccess& RecoContainer::getTPCClusters() const +{ + return inputsTPCclusters->clusterIndex; +} + +gsl::span<const o2::trd::Tracklet64> RecoContainer::getTRDTracklets() const +{ + return inputsTRD->mTracklets; +} + +gsl::span<const o2::trd::CalibratedTracklet> RecoContainer::getTRDCalibratedTracklets() const +{ + return inputsTRD->mSpacePoints; +} + +gsl::span<const o2::trd::TriggerRecord> RecoContainer::getTRDTriggerRecords() const +{ + return inputsTRD->mTriggerRecords; +} + +const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* RecoContainer::getTRDTrackletsMCLabels() const +{ + return inputsTRD->mTrackletLabels.get(); +} + +const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* RecoContainer::getTPCClustersMCLabels() const +{ + return inputsTPCclusters->clusterIndex.clustersMCTruth; +} + +//__________________________________________________________ +const o2::track::TrackParCov& RecoContainer::getTrackParamOut(GTrackID gidx) const +{ + // get outer param of track + auto trSrc = gidx.getSource(); + if (trSrc == GTrackID::ITSTPC) { + return getTrack<o2d::TrackTPCITS>(gidx).getParamOut(); + } else if (trSrc == GTrackID::ITSTPCTOF) { // the physical tracks are in ITS-TPC, need to get reference from match info + return getTrack<o2d::TrackTPCITS>(getTOFMatch(gidx).getTrackRef()).getParamOut(); + } else if (trSrc == GTrackID::TPCTOF) { + return getTrack<o2d::TrackTPCTOF>(gidx).getParamOut(); + } else if (trSrc == GTrackID::ITS) { + return getTrack<o2::its::TrackITS>(gidx).getParamOut(); + } else if (trSrc == GTrackID::TPC) { + return getTrack<o2::tpc::TrackTPC>(gidx).getParamOut(); + } else { + throw std::runtime_error(fmt::format("not defined for tracks of source {:d}", int(trSrc))); + } +} + +//__________________________________________________________ +bool RecoContainer::isTrackSourceLoaded(int src) const +{ + if (src == GTrackID::ITSTPCTOF) { + if (!isMatchSourceLoaded(src)) { // the physical tracks are in ITS-TPC, need to get reference from match info + return false; + } + src = GTrackID::ITSTPC; + } + return commonPool[src].isLoaded(TRACKS); +} + +//__________________________________________________________ +const o2::track::TrackParCov& RecoContainer::getTrackParam(GTrackID gidx) const +{ + // get base track + auto trSrc = gidx.getSource(); + if (trSrc == GTrackID::ITSTPCTOF) { // the physical tracks are in ITS-TPC, need to get reference from match info + gidx = getTOFMatch(gidx).getTrackRef(); + } + return getObject<o2::track::TrackParCov>(gidx, TRACKS); +} + +//__________________________________________________________ +const o2::dataformats::TrackTPCITS& RecoContainer::getITSTPCTOFTrack(GTrackID gidx) const +{ + // get ITS-TPC track pointed by global TOF match + return getTPCITSTrack(getTOFMatch(gidx).getTrackRef()); +} + +//________________________________________________________ +void RecoContainer::fillTrackMCLabels(const gsl::span<GTrackID> gids, std::vector<o2::MCCompLabel>& mcinfo) const +{ + // fills the MCLabels corresponding to gids to MC info + mcinfo.clear(); + mcinfo.reserve(gids.size()); + for (auto gid : gids) { + mcinfo.push_back(getTrackMCLabel(gid)); + } +} + +//________________________________________________________ +void o2::globaltracking::RecoContainer::createTracks(std::function<bool(const o2::track::TrackParCov&, o2::dataformats::GlobalTrackID)> const& creator) const +{ + createTracksVariadic([&creator](const auto& _tr, GTrackID _origID, float t0, float terr) { + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) { + return creator(_tr, _origID); + } else { + return false; + } + }); +} + +//________________________________________________________ +// get contributors from single detectors +RecoContainer::GlobalIDSet RecoContainer::getSingleDetectorRefs(GTrackID gidx) const +{ + GlobalIDSet table; + auto src = gidx.getSource(); + table[src] = gidx; + if (src == GTrackID::ITSTPCTRD) { + const auto& parent0 = getITSTPCTRDTrack<o2::trd::TrackTRD>(gidx); + const auto& parent1 = getTPCITSTrack(parent0.getRefGlobalTrackId()); + table[GTrackID::ITSTPC] = parent0.getRefGlobalTrackId(); + table[parent1.getRefITS().getSource()] = parent1.getRefITS(); + table[GTrackID::TPC] = parent1.getRefTPC(); + table[GTrackID::TRD] = gidx; // there is no standalone TRD track, so use the index for the ITSTPCTRD track array + } + if (src == GTrackID::ITSTPCTOF) { + const auto& parent0 = getTOFMatch(gidx); //ITS/TPC : TOF + const auto& parent1 = getTPCITSTrack(parent0.getTrackRef()); + table[GTrackID::ITSTPC] = parent0.getTrackRef(); + table[GTrackID::TOF] = {unsigned(parent0.getIdxTOFCl()), GTrackID::TOF}; + table[GTrackID::TPC] = parent1.getRefTPC(); + table[parent1.getRefITS().getSource()] = parent1.getRefITS(); // ITS source might be an ITS track or ITSAB tracklet + } else if (src == GTrackID::TPCTOF) { + const auto& parent0 = getTPCTOFMatch(gidx); //TPC : TOF + table[GTrackID::TOF] = {unsigned(parent0.getIdxTOFCl()), GTrackID::TOF}; + table[GTrackID::TPC] = parent0.getTrackRef(); + } else if (src == GTrackID::ITSTPC) { + const auto& parent0 = getTPCITSTrack(gidx); + table[GTrackID::TPC] = parent0.getRefTPC(); + table[parent0.getRefITS().getSource()] = parent0.getRefITS(); // ITS source might be an ITS track or ITSAB tracklet + } + return std::move(table); +} + +//________________________________________________________ +// get contributing TPC GTrackID to the source. If source gidx is not contributed by TPC, +// returned GTrackID.isSourceSet()==false +GTrackID RecoContainer::getTPCContributorGID(GTrackID gidx) const +{ + auto src = gidx.getSource(); + if (src == GTrackID::ITSTPCTRD) { + const auto& parent0 = getITSTPCTRDTrack<o2::trd::TrackTRD>(gidx); + const auto& parent1 = getTPCITSTrack(parent0.getRefGlobalTrackId()); + return parent1.getRefTPC(); + } else if (src == GTrackID::ITSTPCTOF) { + const auto& parent0 = getTOFMatch(gidx); //ITS/TPC : TOF + const auto& parent1 = getTPCITSTrack(parent0.getTrackRef()); + return parent1.getRefTPC(); + } else if (src == GTrackID::TPCTOF) { + const auto& parent0 = getTPCTOFMatch(gidx); //TPC : TOF + return parent0.getTrackRef(); + } else if (src == GTrackID::ITSTPC) { + const auto& parent0 = getTPCITSTrack(gidx); + return parent0.getRefTPC(); + } + return src == GTrackID::TPC ? gidx : GTrackID{}; +} + +//________________________________________________________ +// get contributing ITS GTrackID to the source. If source gidx is not contributed by TPC, +// returned GTrackID.isSourceSet()==false +GTrackID RecoContainer::getITSContributorGID(GTrackID gidx) const +{ + auto src = gidx.getSource(); + if (src == GTrackID::ITSTPCTRD) { + const auto& parent0 = getITSTPCTRDTrack<o2::trd::TrackTRD>(gidx); + const auto& parent1 = getTPCITSTrack(parent0.getRefGlobalTrackId()); + return parent1.getRefITS(); + } else if (src == GTrackID::ITSTPCTOF) { + const auto& parent0 = getTOFMatch(gidx); //ITS/TPC : TOF + const auto& parent1 = getTPCITSTrack(parent0.getTrackRef()); + return parent1.getRefITS(); + } else if (src == GTrackID::ITSTPC) { + const auto& parent0 = getTPCITSTrack(gidx); + return parent0.getRefITS(); + } + return src == GTrackID::ITS ? gidx : GTrackID{}; +} diff --git a/DataFormats/Detectors/HMPID/CMakeLists.txt b/DataFormats/Detectors/HMPID/CMakeLists.txt new file mode 100644 index 0000000000000..4e89c789c9407 --- /dev/null +++ b/DataFormats/Detectors/HMPID/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(DataFormatsHMP + SOURCES src/Digit.cxx + src/Cluster.cxx + src/Trigger.cxx + src/CTF.cxx + PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats + O2::HMPIDBase + O2::CommonDataFormat + O2::SimulationDataFormat) + +o2_target_root_dictionary(DataFormatsHMP + HEADERS include/DataFormatsHMP/DataFormat.h + include/DataFormatsHMP/Digit.h + include/DataFormatsHMP/Trigger.h + include/DataFormatsHMP/Cluster.h + include/DataFormatsHMP/Hit.h + include/DataFormatsHMP/CTF.h) diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/CTF.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/CTF.h new file mode 100644 index 0000000000000..b7f96e2827cfc --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/CTF.h @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for HMPID CTF data + +#ifndef O2_HMP_CTF_H +#define O2_HMP_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" + +namespace o2 +{ +namespace hmpid +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t nDigits = 0; /// number of digits + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded triggers and cells of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 8, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_entriesDig, + BLC_ChID, // digits sorted in ChamberID -> 1st entry of trigger keeps abs ChID, then increments + BLC_Q, + BLC_Ph, + BLC_X, + BLC_Y + }; + ClassDefNV(CTF, 1); +}; + +} // namespace hmpid +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Cluster.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Cluster.h new file mode 100644 index 0000000000000..05d5fdb741dbd --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Cluster.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_CLUSTER_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_CLUSTER_H_ + +namespace o2 +{ +namespace hmpid +{ +/// \class Cluster +/// \brief HMPID cluster implementation +class Cluster +{ + public: + Cluster() = default; + + Cluster(int chamber, int size, int NlocMax, float QRaw, float Q, float X, float Y); + ~Cluster() = default; + + int getCh() const { return mChamber; } + void setCh(int chamber) { mChamber = chamber; } + + int getSize() const { return mSize; } + void setSize(int size) { mSize = size; } + + int getQRaw() const { return mQRaw; } + void setQRaw(int QRaw) { mQRaw = QRaw; } + + int getQ() const { return mQ; } + void setQ(int Q) { mQ = Q; } + + int getX() const { return mX; } + void setX(int X) { mX = X; } + + int getY() const { return mY; } + void setY(int Y) { mY = Y; } + + protected: + int mChamber; /// chamber number + int mSize; /// size of the formed cluster from which this cluster deduced + int mNlocMax; /// number of local maxima in formed cluster + float mQRaw; /// QDC value of the raw cluster + float mQ; /// QDC value of the actual cluster + float mX; /// local x postion, [cm] + float mY; /// local y postion, [cm] + + ClassDefNV(Cluster, 1); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_CLUSTER_H_ */ diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/DataFormat.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/DataFormat.h new file mode 100644 index 0000000000000..cf9362ce80604 --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/DataFormat.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataFormat.h +/// \brief Definition of the HMPID raw data format + +#ifndef ALICEO2_HMP_DATAFORMAT_H +#define ALICEO2_HMP_DATAFORMAT_H + +#include <stdint.h> + +namespace o2 +{ +namespace hmpid +{ +namespace raw +{ + +/** generic word * + + struct Word_t { + uint32_t undefined : 31; + uint32_t wordType : 1; + }; + + union Union_t { + uint32_t data; + Word_t word; + CrateHeader_t crateHeader; + FrameHeader_t frameHeader; + PackedHit_t packedHit; + CrateTrailer_t crateTrailer; + }; +*/ +} // namespace raw +} // namespace hmpid +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Digit.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Digit.h new file mode 100644 index 0000000000000..926d5e9b7e1b6 --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Digit.h @@ -0,0 +1,157 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Digit.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 15/02/2021 + +// History +// 10/03/2021 Complete review + +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_DIGIT_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_DIGIT_H_ + +#include <iosfwd> +#include <vector> +#include "DataFormatsHMP/Hit.h" // for hit +#include "HMPIDBase/Param.h" // for param + +namespace o2 +{ +namespace hmpid +{ +/// \class Digit +/// \brief HMPID Digit declaration +class Digit +{ + public: + // Coordinates Conversion Functions + static inline uint32_t abs(int ch, int pc, int x, int y) { return ch << 24 | pc << 16 | x << 8 | y; } + static inline int ddl2C(int ddl) { return ddl >> 1; } //ddl -> chamber + static inline int a2C(uint32_t pad) { return (pad & 0xFF000000) >> 24; } //abs pad -> chamber + static inline int a2P(uint32_t pad) { return (pad & 0x00FF0000) >> 16; } //abs pad -> pc + static inline int a2X(uint32_t pad) { return (pad & 0x0000FF00) >> 8; } //abs pad -> pad X + static inline int a2Y(uint32_t pad) { return (pad & 0x000000FF); } //abs pad -> pad Y + static inline uint32_t photo2Pad(int ch, int pc, int x, int y) { return abs(ch, pc, x, y); } + static uint32_t equipment2Pad(int Equi, int Colu, int Dilo, int Chan); + static uint32_t absolute2Pad(int Module, int x, int y); + static void pad2Equipment(uint32_t pad, int* Equi, int* Colu, int* Dilo, int* Chan); + static void pad2Absolute(uint32_t pad, int* Module, int* x, int* y); + static void pad2Photo(uint32_t pad, uint8_t* chamber, uint8_t* photo, uint8_t* x, uint8_t* y); + static void absolute2Equipment(int Module, int x, int y, int* Equi, int* Colu, int* Dilo, int* Chan); + static void equipment2Absolute(int Equi, int Colu, int Dilo, int Chan, int* Module, int* x, int* y); + + // Trigger time Conversion Functions + // static inline uint64_t orbitBcToEventId(uint32_t Orbit, uint16_t BC) { return ((Orbit << 12) | (0x0FFF & BC)); }; + // static inline uint32_t eventIdToOrbit(uint64_t EventId) { return (EventId >> 12); }; + // static inline uint16_t EventIdToBc(uint64_t EventId) { return (EventId & 0x0FFF); }; + // static double OrbitBcToTimeNs(uint32_t Orbit, uint16_t BC); + // static uint32_t TimeNsToOrbit(double TimeNs); + // static uint16_t TimeNsToBc(double TimeNs); + // static void TimeNsToOrbitBc(double TimeNs, uint32_t& Orbit, uint16_t& Bc); + + // Operators definition ! + friend inline bool operator<(const Digit& l, const Digit& r) { return l.getPadID() < r.getPadID(); }; + friend inline bool operator==(const Digit& l, const Digit& r) { return l.getPadID() == r.getPadID(); }; + friend inline bool operator>(const Digit& l, const Digit& r) { return r < l; }; + friend inline bool operator<=(const Digit& l, const Digit& r) { return !(l > r); }; + friend inline bool operator>=(const Digit& l, const Digit& r) { return !(l < r); }; + friend inline bool operator!=(const Digit& l, const Digit& r) { return !(l == r); }; + + friend std::ostream& operator<<(std::ostream& os, const Digit& d); + + public: + Digit() = default; + Digit(int pad, uint16_t charge); + Digit(int chamber, int photo, int x, int y, uint16_t charge); + Digit(uint16_t charge, int equipment, int column, int dilogic, int channel); + Digit(uint16_t charge, int module, int x, int y); + + // Getter & Setters + uint16_t getCharge() const { return mQ; } + void setCharge(uint16_t Q) { mQ = Q; }; + + int getPadID() const { return mCh << 24 | mPh << 16 | mX << 8 | mY; } + void setPadID(uint32_t pad) + { + mCh = pad >> 24; + mPh = (pad & 0x00FF0000) >> 16; + mX = (pad & 0x0000FF00) >> 8; + mY = (pad & 0x000000FF); + }; + + bool isValid() { return (mCh == 0xFF ? true : false); }; + void setInvalid() + { + mCh = 0xFF; + return; + }; + + // // convenience wrapper function for conversion to x-y pad coordinates + // int getPx() const { return A2X(mPad); } + // int getPy() const { return A2Y(mPad); } + // int getPhC() const { return A2P(mPad); } + // int getCh() const { return A2C(mPad); } + + // Charge management functions + static void getPadAndTotalCharge(o2::hmpid::HitType const& hit, int& chamber, int& pc, int& px, int& py, float& totalcharge); + static float getFractionalContributionForPad(o2::hmpid::HitType const& hit, int somepad); + void addCharge(float q) + { + mQ += q; + if (mQ > 0x0FFF) { + mQ = 0x0FFF; + } + } + void subCharge(float q) { mQ -= q; } + + uint16_t getQ() const { return mQ; } + uint8_t getCh() const { return mCh; } + uint8_t getPh() const { return mPh; } + uint8_t getX() const { return mX; } + uint8_t getY() const { return mY; } + + public: + // Members + uint16_t mQ = 0; + uint8_t mCh = 0; // 0xFF indicates invalid digit + uint8_t mPh = 0; + uint8_t mX = 0; + uint8_t mY = 0; + + // The Pad Unique Id, code a pad inside one HMPID chamber. + // Bit Map : 0000.0000.cccc.pppp.xxxx.xxxx.yyyy.yyyy + // cccc := chamber [0..6] + // pppp := photo cathode [0..5] + // xxxx.xxxx := horizontal displacement [0..79] + // yyyy.yyyy := vertical displacement [0..47] + //uint32_t mPad = 0; // 0xFFFFFFFF indicates invalid digit + + // Get the Geometric center of the pad + static float lorsX(int pad) { return Param::lorsX(a2P(pad), a2X(pad)); } //center of the pad x, [cm] + static float lorsY(int pad) { return Param::lorsY(a2P(pad), a2Y(pad)); } //center of the pad y, [cm] + + // determines the total charge created by a hit + // might modify the localX, localY coordiates associated to the hit + static Double_t qdcTot(Double_t e, Double_t time, Int_t pc, Int_t px, Int_t py, Double_t& localX, Double_t& localY); + static Double_t intPartMathiX(Double_t x, Int_t pad); + static Double_t intPartMathiY(Double_t y, Int_t pad); + static Double_t inMathieson(Double_t localX, Double_t localY, int pad); + + ClassDefNV(Digit, 2); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_DIGIT_H_ */ diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Hit.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Hit.h new file mode 100644 index 0000000000000..86f60fbf89a21 --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Hit.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Digit.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 15/02/2021 + +// History +// +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_HIT_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_HIT_H_ + +#include "SimulationDataFormat/BaseHits.h" // for BasicXYZEHit +#include "CommonUtils/ShmAllocator.h" + +namespace o2 +{ +namespace hmpid +{ + +// define HMPID hit type +// class Hit : public o2::BasicXYZQHit<float> +class HitType : public o2::BasicXYZEHit<float> +{ + public: + using BasicXYZEHit<float>::BasicXYZEHit; + + ClassDefNV(HitType, 1); +}; + +} // namespace hmpid +} // namespace o2 + +#ifdef USESHM +namespace std +{ +template <> +class allocator<o2::hmpid::HitType> : public o2::utils::ShmAllocator<o2::hmpid::HitType> +{ +}; +} // namespace std +#endif + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDDATAFORMAT_HIT_H_ */ diff --git a/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Trigger.h b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Trigger.h new file mode 100644 index 0000000000000..09eaa6a431c0b --- /dev/null +++ b/DataFormats/Detectors/HMPID/include/DataFormatsHMP/Trigger.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Trigger.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 2/03/2021 + +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ + +#include <iosfwd> +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" + +namespace o2 +{ +namespace hmpid +{ +/// \class Trigger +/// \brief HMPID Trigger declaration +class Trigger +{ + using DataRange = o2::dataformats::RangeReference<int>; + + public: + static inline uint64_t getTriggerID(uint32_t Orbit, uint16_t BC) { return ((Orbit << 12) | (0x0FFF & BC)); }; + + public: + Trigger() = default; + Trigger(InteractionRecord ir, int32_t first, int32_t n) : mIr(ir), mDataRange(first, n) {} + + const InteractionRecord& getIr() const { return mIr; }; + uint32_t getOrbit() const { return mIr.orbit; }; + uint16_t getBc() const { return mIr.bc; }; + uint64_t getTriggerID() const { return ((mIr.orbit << 12) | (0x0FFF & mIr.bc)); }; + void setDataRange(int firstentry, int nentries) { mDataRange.set(firstentry, nentries); } + int getNumberOfObjects() const { return mDataRange.getEntries(); } + int getFirstEntry() const { return mDataRange.getFirstEntry(); } + int getLastEntry() const { return mDataRange.getFirstEntry() + mDataRange.getEntries() - 1; } + void setOrbit(uint32_t orbit) + { + mIr.orbit = orbit; + return; + } + void setBC(uint16_t bc) + { + mIr.bc = bc; + return; + } + void setTriggerID(uint64_t trigger) + { + mIr.orbit = (trigger >> 12); + mIr.bc = (trigger & 0x0FFF); + return; + } + + // Operators definition ! + friend inline bool operator<(const Trigger& l, const Trigger& r) { return l.getTriggerID() < r.getTriggerID(); }; + friend inline bool operator==(const Trigger& l, const Trigger& r) { return l.getTriggerID() == r.getTriggerID(); }; + friend inline bool operator>(const Trigger& l, const Trigger& r) { return r < l; }; + friend inline bool operator<=(const Trigger& l, const Trigger& r) { return !(l > r); }; + friend inline bool operator>=(const Trigger& l, const Trigger& r) { return !(l < r); }; + friend inline bool operator!=(const Trigger& l, const Trigger& r) { return !(l == r); }; + + // Digit ASCII format (Orbit,BunchCrossing)[LHC Time nSec] + friend std::ostream& operator<<(std::ostream& os, const Trigger& d); + + private: + // Members + InteractionRecord mIr; + DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) + + ClassDefNV(Trigger, 2); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ */ diff --git a/DataFormats/Detectors/HMPID/src/CTF.cxx b/DataFormats/Detectors/HMPID/src/CTF.cxx new file mode 100644 index 0000000000000..e4ca24b724387 --- /dev/null +++ b/DataFormats/Detectors/HMPID/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsHMP/CTF.h" + +using namespace o2::hmpid; diff --git a/DataFormats/Detectors/HMPID/src/Cluster.cxx b/DataFormats/Detectors/HMPID/src/Cluster.cxx new file mode 100644 index 0000000000000..56276549e9861 --- /dev/null +++ b/DataFormats/Detectors/HMPID/src/Cluster.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TRandom.h> +#include "DataFormatsHMP/Cluster.h" + +ClassImp(o2::hmpid::Cluster); + +namespace o2 +{ +namespace hmpid +{ + +Cluster::Cluster(int chamber, int size, int NlocMax, float QRaw, float Q, float X, float Y) + : mChamber(chamber), mSize(size), mNlocMax(NlocMax), mQRaw(QRaw), mQ(Q), mX(X), mY(Y) + + {}; + +} // namespace hmpid +} // namespace o2 diff --git a/DataFormats/Detectors/HMPID/src/DataFormatsHMPLinkDef.h b/DataFormats/Detectors/HMPID/src/DataFormatsHMPLinkDef.h new file mode 100644 index 0000000000000..3f247ae067ce8 --- /dev/null +++ b/DataFormats/Detectors/HMPID/src/DataFormatsHMPLinkDef.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::hmpid::Digit + ; +#pragma link C++ class vector < o2::hmpid::Digit> + ; +#pragma link C++ class o2::hmpid::HitType + ; +#pragma link C++ class vector < o2::hmpid::HitType> + ; +#pragma link C++ class o2::hmpid::Cluster + ; +#pragma link C++ class vector < o2::hmpid::Cluster> + ; +#pragma link C++ class o2::hmpid::Trigger + ; +#pragma link C++ class vector < o2::hmpid::Trigger> + ; + +#pragma link C++ struct o2::hmpid::CTFHeader + ; +#pragma link C++ struct o2::hmpid::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::hmpid::CTFHeader, 8, uint32_t> + ; + +#endif diff --git a/DataFormats/Detectors/HMPID/src/Digit.cxx b/DataFormats/Detectors/HMPID/src/Digit.cxx new file mode 100644 index 0000000000000..a654ea611ab7b --- /dev/null +++ b/DataFormats/Detectors/HMPID/src/Digit.cxx @@ -0,0 +1,475 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Digit.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to manage HMPID Digit data +/// \version 1.0 +/// \date 15/02/2021 + +/* ------ HISTORY --------- + 10/03/2021 / complete review + +*/ + +#include <iostream> +#include <TRandom.h> +#include "CommonConstants/LHCConstants.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDBase/Param.h" +#include "DataFormatsHMP/Digit.h" + +ClassImp(o2::hmpid::Digit); + +namespace o2 +{ +namespace hmpid +{ + +// ============= Digit Class implementation ======= +/// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) +/// The mapping of the digit is in the Photo Cathod coords +/// (Chamber, PhotoCathod, X, Y) +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @param[in] charge : the value of the charge [0 .. 2^12-1] +Digit::Digit(int pad, uint16_t charge) +{ + mQ = charge > 0x0FFF ? 0x0FFF : charge; + mCh = a2C(pad); + mPh = a2P(pad); + mX = a2X(pad); + mY = a2Y(pad); +} + +/// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) +/// The mapping of the digit is in the Photo Cathod coords +/// (Chamber, PhotoCathod, X, Y) +/// @param[in] chamber : the HMPID module [0 .. 6] +/// @param[in] photo : the photo cathode number [0 .. 5] (left-down to right-up) +/// @param[in] x : the horizontal in cathode displacement [0 .. 79] +/// @param[in] y : the vertical in cathode displacement [0 .. 47] +/// @param[in] charge : the value of the charge [0 .. 2^12-1] +Digit::Digit(int chamber, int photo, int x, int y, uint16_t charge) +{ + mQ = charge > 0x0FFF ? 0x0FFF : charge; + mCh = chamber; + mPh = photo; + mX = x; + mY = y; +} + +/// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) +/// The mapping of the digit is in the Hardware coords +/// (Equipment, Column, Dilogic, Channel) +/// @param[in] charge : the value of the charge [0 .. 2^12-1] +/// @param[in] equipment : the HMPID DDL link [0 .. 13] +/// @param[in] column : the readout column number [0 .. 23] +/// @param[in] dilogic : the displacement in the Dilogics chain [0 .. 9] +/// @param[in] channel : the number of gassiplexes channels [0 .. 47] +Digit::Digit(uint16_t charge, int equipment, int column, int dilogic, int channel) +{ + mQ = charge > 0x0FFF ? 0x0FFF : charge; + pad2Photo(equipment2Pad(equipment, column, dilogic, channel), &mCh, &mPh, &mX, &mY); +} + +/// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) +/// The mapping of the digit is in the Logical coords +/// (Module, X, Y) +/// @param[in] charge : the value of the charge [0 .. 2^12-1] +/// @param[in] module : the HMPID Module [0 .. 6] +/// @param[in] x : the horizontal in Module displacement [0 .. 159] +/// @param[in] y : the vertical in Module displacement [0 .. 143] +Digit::Digit(uint16_t charge, int module, int x, int y) +{ + mQ = charge > 0x0FFF ? 0x0FFF : charge; + pad2Photo(absolute2Pad(module, x, y), &mCh, &mPh, &mX, &mY); +} + +// Digit ASCCI format Dump := [Chamber,PhotoCathod,X,Y]@(Orbit,BunchCrossing)=Charge +std::ostream& operator<<(std::ostream& os, const o2::hmpid::Digit& d) +{ + os << "[" << (int)d.mCh << "," << (int)d.mPh << "," << (int)d.mX << "," << (int)d.mY << "]=" << d.mQ; + return os; +}; + +// ----- Coordinate Conversion ----- + +/// Equipment2Pad : Converts the coords from Hardware to Digit Unique Id +/// @param[in] Equi : the equipment [0 .. 13] +/// @param[in] Colu : the readout column number [0 .. 23] +/// @param[in] Dilo : the displacement in the Dilogics chain [0 .. 9] +/// @param[in] Chan : the number of gassiplexes channels [0 .. 47] +/// @return uint32_t : the Digit Unique Id [0x00CPXXYY] +uint32_t Digit::equipment2Pad(int Equi, int Colu, int Dilo, int Chan) +{ + // Check the input data + if (Equi < 0 || Equi >= Geo::MAXEQUIPMENTS || Colu < 0 || Colu >= Geo::N_COLUMNS || + Dilo < 0 || Dilo >= Geo::N_DILOGICS || Chan < 0 || Chan >= Geo::N_CHANNELS) { + return -1; + } + + int chan2y[6] = {3, 2, 4, 1, 5, 0}; // y coordinate translation for a channel address (index position) for even chamber + + bool isEven = (Equi % Geo::EQUIPMENTSPERMODULE) == 0 ? true : false; // Calculate the odd/even of geometry + int ch = Equi / Geo::EQUIPMENTSPERMODULE; // The Module + + // Calculate the x,y photo cathode relative coords For Odd equipment + int pc = (Colu / Geo::N_COLXSEGMENT) * 2 + 1; // col [0..23] -> [1,3,5] + int px = Geo::MAXXPHOTO - ((Dilo * Geo::DILOPADSROWS) + (Chan / Geo::DILOPADSCOLS)); + int py = (Colu % Geo::DILOPADSROWS) * Geo::DILOPADSCOLS + chan2y[Chan % Geo::DILOPADSCOLS]; + if (isEven) { + pc = 5 - pc; + py = Geo::MAXYPHOTO - py; + } + return abs(ch, pc, px, py); // Pack the coords into the PadID word +} + +/// Pad2Equipment : Converts the Digit Unique Id to Hardware coords +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @param[out] Equi : the equipment [0 .. 13] +/// @param[out] Colu : the readout column number [0 .. 23] +/// @param[out] Dilo : the displacement in the Dilogics chain [0 .. 9] +/// @param[out] Chan : the number of gassiplexes channels [0 .. 47] +void Digit::pad2Equipment(uint32_t pad, int* Equi, int* Colu, int* Dilo, int* Chan) +{ + uint8_t ch, ph, px, py; + int y2chan[6] = {5, 3, 1, 0, 2, 4}; + + pad2Photo(pad, &ch, &ph, &px, &py); // Unpak the pad ID in the photo cathode coords + + bool isEven = (ph % 2) == 0 ? true : false; + int eq = ch * Geo::EQUIPMENTSPERMODULE + 1; + px = Geo::MAXXPHOTO - px; // revert the X coord + if (isEven) { + eq--; // Correct the equipment number + py = Geo::MAXYPHOTO - py; // revert the Y coord + ph = 5 - ph; // revert the photo cathode index [0,2,4] -> [5,3,1] + } + *Dilo = px / Geo::DILOPADSROWS; // Calculate the Dilogic x [0..79] -> dil [0..9] + *Colu = ((ph / 2) * Geo::N_COLXSEGMENT) + (py / Geo::DILOPADSCOLS); // calculate the column (ph [1,3,5], y [0..47]) -> col [0..23] + *Chan = ((px % Geo::DILOPADSROWS) * Geo::DILOPADSCOLS) + y2chan[py % Geo::DILOPADSCOLS]; + *Equi = eq; + return; +} + +/// Absolute2Equipment : Converts the Module coords to Hardware coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] x : the horizontal displacement [0..159] +/// @param[in] y : the vertical displacement [0..143] +/// @param[out] Equi : the equipment [0 .. 13] +/// @param[out] Colu : the readout column number [0 .. 23] +/// @param[out] Dilo : the displacement in the Dilogics chain [0 .. 9] +/// @param[out] Chan : the number of gassiplexes channels [0 .. 47] +void Digit::absolute2Equipment(int Module, int x, int y, int* Equi, int* Colu, int* Dilo, int* Chan) +{ + uint32_t pad = absolute2Pad(Module, x, y); + pad2Equipment(pad, Equi, Colu, Dilo, Chan); + return; +} + +/// Equipment2Absolute : Converts the Module coords to Hardware coords +/// @param[in] Equi : the equipment [0 .. 13] +/// @param[in] Colu : the readout column number [0 .. 23] +/// @param[in] Dilo : the displacement in the Dilogics chain [0 .. 9] +/// @param[in] Chan : the number of gassiplexes channels [0 .. 47] +/// @param[out] Module : the HMPID Module number [0..6] +/// @param[out] x : the horizontal displacement [0..159] +/// @param[out] y : the vertical displacement [0..143] +void Digit::equipment2Absolute(int Equi, int Colu, int Dilo, int Chan, int* Module, int* x, int* y) +{ + uint32_t pad = equipment2Pad(Equi, Colu, Dilo, Chan); + pad2Absolute(pad, Module, x, y); + return; +} + +/// Absolute2Pad : Converts the Module coords in the Digit Unique Id +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] x : the horizontal displacement [0..159] +/// @param[in] y : the vertical displacement [0..143] +/// @return uint32_t : the Digit Unique Id [0x00CPXXYY] +uint32_t Digit::absolute2Pad(int Module, int x, int y) +{ + int ph = (y / Geo::N_PHOTOCATODSY) * 2 + ((x >= Geo::HALFXROWS) ? 1 : 0); + int px = x % Geo::HALFXROWS; + int py = y % Geo::N_PHOTOCATODSY; + return abs(Module, ph, px, py); +} + +/// Pad2Absolute : Converts the the Digit Unique Id to Module coords +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @param[out] Module : the HMPID Module number [0..6] +/// @param[out] x : the horizontal displacement [0..159] +/// @param[out] y : the vertical displacement [0..143] +void Digit::pad2Absolute(uint32_t pad, int* Module, int* x, int* y) +{ + *Module = a2C(pad); + int ph = a2P(pad); + int px = a2X(pad); + int py = a2Y(pad); + *x = px + ((ph % 2 == 1) ? Geo::HALFXROWS : 0); + *y = ((ph >> 1) * Geo::N_PHOTOCATODSY) + py; + return; +} + +/// Pad2Photo : Converts the the Digit Unique Id to Photo Cathode coords +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @param[out] chamber : the HMPID chamber number [0..6] +/// @param[out] photo : the photo cathode number [0..5] +/// @param[out] x : the horizontal displacement [0..79] +/// @param[out] y : the vertical displacement [0..47] +void Digit::pad2Photo(uint32_t pad, uint8_t* chamber, uint8_t* photo, uint8_t* x, uint8_t* y) +{ + *chamber = a2C(pad); + *photo = a2P(pad); + *x = a2X(pad); + *y = a2Y(pad); + return; +} + +/// getPadAndTotalCharge : Extract all the info from the Hit structure +/// and returns they in the Photo Cathode coords +/// @param[in] hit : the HMPID Hit +/// @param[out] chamber : the HMPID chamber number [0..6] +/// @param[out] pc : the photo cathode number [0..5] +/// @param[out] px : the horizontal displacement [0..79] +/// @param[out] py : the vertical displacement [0..47] +/// @param[out] totalcharge : the charge of the hit [0..2^12-1] +void Digit::getPadAndTotalCharge(HitType const& hit, int& chamber, int& pc, int& px, int& py, float& totalcharge) +{ + double localX; + double localY; + chamber = hit.GetDetectorID(); + double tmp[3] = {hit.GetX(), hit.GetY(), hit.GetZ()}; + Param::instance()->mars2Lors(chamber, tmp, localX, localY); + Param::lors2Pad(localX, localY, pc, px, py); + + totalcharge = Digit::qdcTot(hit.GetEnergyLoss(), hit.GetTime(), pc, px, py, localX, localY); + return; +} + +/// getFractionalContributionForPad : ... +/// +/// @param[in] hit : the HMPID Hit +/// @param[in] somepad : the Digit Unique Id [0x00CPXXYY] +/// @return : the fraction of the charge ... +float Digit::getFractionalContributionForPad(HitType const& hit, int somepad) +{ + double localX; + double localY; + + const auto chamber = hit.GetDetectorID(); // chamber number is in detID + double tmp[3] = {hit.GetX(), hit.GetY(), hit.GetZ()}; + // converting chamber id and hit coordiates to local coordinates + Param::instance()->mars2Lors(chamber, tmp, localX, localY); + // calculate charge fraction in given pad + return Digit::inMathieson(localX, localY, somepad); +} + +/// QdcTot : Samples total charge associated to a hit +/// +/// @param[in] e : hit energy [GeV] for mip Eloss for photon Etot +/// @param[in] time : ... +/// @param[in] pc : the photo cathode number [0..5] +/// @param[in] px : the horizontal displacement [0..79] +/// @param[in] py : the vertical displacement [0..47] +/// @param[out] localX : the horizontal displacement related to Anode Wires +/// @param[out] localY : the vertical displacement related to Anode Wires +/// @return : total QDC +Double_t Digit::qdcTot(Double_t e, Double_t time, Int_t pc, Int_t px, Int_t py, Double_t& localX, Double_t& localY) +{ + // + // Arguments: e- + // Returns: + double Q = 0; + if (time > 1.2e-6) { + Q = 0; + } + if (py < 0) { + return 0; + } else { + double y = Param::lorsY(pc, py); + localY = ((y - localY) > 0) ? y - 0.2 : y + 0.2; //shift to the nearest anod wire + + double x = (localX > 66.6) ? localX - 66.6 : localX; //sagita is for PC (0-64) and not for chamber + double qdcEle = 34.06311 + 0.2337070 * x + 5.807476e-3 * x * x - 2.956471e-04 * x * x * x + 2.310001e-06 * x * x * x * x; //reparametrised from DiMauro + + int iNele = int((e / 26e-9) * 0.8); + if (iNele < 1) { + iNele = 1; //number of electrons created by hit, if photon e=0 implies iNele=1 + } + for (Int_t i = 1; i <= iNele; i++) { + double rnd = gRandom->Rndm(); + if (rnd == 0) { + rnd = 1e-12; //1e-12 is a protection against 0 from rndm + } + Q -= qdcEle * TMath::Log(rnd); + } + } + return Q; +} + +/// IntPartMathiX : Integration of Mathieson. +/// This is the answer to electrostatic problem of charge distrubution in MWPC +/// described elsewhere. (NIM A370(1988)602-603) +/// +/// @param[in] x : position of the center of Mathieson distribution +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @return : a charge fraction [0-1] imposed into the pad +Double_t Digit::intPartMathiX(Double_t x, int pad) +{ + Double_t shift1 = -lorsX(pad) + 0.5 * o2::hmpid::Param::sizePadX(); + Double_t shift2 = -lorsX(pad) - 0.5 * o2::hmpid::Param::sizePadX(); + + Double_t ux1 = o2::hmpid::Param::sqrtK3x() * TMath::TanH(o2::hmpid::Param::k2x() * (x + shift1) / o2::hmpid::Param::pitchAnodeCathode()); + Double_t ux2 = o2::hmpid::Param::sqrtK3x() * TMath::TanH(o2::hmpid::Param::k2x() * (x + shift2) / o2::hmpid::Param::pitchAnodeCathode()); + + return o2::hmpid::Param::k4x() * (TMath::ATan(ux2) - TMath::ATan(ux1)); +} + +/// IntPartMathiY : Integration of Mathieson. +/// This is the answer to electrostatic problem of charge distrubution in MWPC +/// described elsewhere. (NIM A370(1988)602-603) +/// +/// @param[in] y : position of the center of Mathieson distribution +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @return : a charge fraction [0-1] imposed into the pad +Double_t Digit::intPartMathiY(Double_t y, int pad) +{ + Double_t shift1 = -lorsY(pad) + 0.5 * o2::hmpid::Param::sizePadY(); + Double_t shift2 = -lorsY(pad) - 0.5 * o2::hmpid::Param::sizePadY(); + + Double_t uy1 = o2::hmpid::Param::sqrtK3y() * TMath::TanH(o2::hmpid::Param::k2y() * (y + shift1) / o2::hmpid::Param::pitchAnodeCathode()); + Double_t uy2 = o2::hmpid::Param::sqrtK3y() * TMath::TanH(o2::hmpid::Param::k2y() * (y + shift2) / o2::hmpid::Param::pitchAnodeCathode()); + + return o2::hmpid::Param::k4y() * (TMath::ATan(uy2) - TMath::ATan(uy1)); +} + +/// InMathieson : Integration of Mathieson. +/// This is the answer to electrostatic problem of charge distrubution in MWPC +/// described elsewhere. (NIM A370(1988)602-603) +/// +/// @param[in] localX : X position of the center of Mathieson distribution +/// @param[in] localY : Y position of the center of Mathieson distribution +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @return : a charge fraction [0-1] imposed into the pad +Double_t Digit::inMathieson(Double_t localX, Double_t localY, Int_t pad) +{ + return 4. * intPartMathiX(localX, pad) * intPartMathiY(localY, pad); +} +/* +// ---- Time conversion functions ---- + +/// OrbitBcToTimeNs : Converts the Orbit,BC pair in absolute +/// nanoseconds time. +/// +/// @param[in] Orbit : the Orbit number [0..2^32-1] +/// @param[in] BC : the Bunch Crossing Number [0..2^12-1] +/// @return : the absolute time in nanoseconds +Double_t Digit::OrbitBcToTimeNs(uint32_t Orbit, uint16_t BC) +{ + return (BC * o2::constants::lhc::LHCBunchSpacingNS + Orbit * o2::constants::lhc::LHCOrbitNS); +} + +/// TimeNsToOrbit : Extracts the Orbit number from the absolute +/// nanoseconds time. +/// +/// @param[in] TimeNs : the absolute nanoseconds time +/// @return : the Orbit number [0..2^32-1] +uint32_t Digit::TimeNsToOrbit(Double_t TimeNs) +{ + return (uint32_t)(TimeNs / o2::constants::lhc::LHCOrbitNS); +} + +/// TimeNsToBc : Extracts the Bunch Crossing number from the absolute +/// nanoseconds time. +/// +/// @param[in] TimeNs : the absolute nanoseconds time +/// @return : the Bunch Crossing number [0..2^12-1] +uint16_t Digit::TimeNsToBc(Double_t TimeNs) +{ + return (uint16_t)(std::fmod(TimeNs, o2::constants::lhc::LHCOrbitNS) / o2::constants::lhc::LHCBunchSpacingNS); +} + +/// TimeNsToOrbitBc : Extracts the (Orbit,BC) pair from the absolute +/// nanoseconds time. +/// +/// @param[in] TimeNs : the absolute nanoseconds time +/// @param[out] Orbit : the Orbit number [0..2^32-1] +/// @param[out] Bc : the Bunch Crossing number [0..2^12-1] +void Digit::TimeNsToOrbitBc(double TimeNs, uint32_t& Orbit, uint16_t& Bc) +{ + Orbit = TimeNsToOrbit(TimeNs); + Bc = TimeNsToBc(TimeNs); + return; +} + + +// ---- Functions to manage Digit vectors ---- + +/// eventEquipPadsComp : Function for order digits (Event,Chamber,Photo,x,y) +/// to use in sort method function overload +/// @param[in] d1 : one Digit +/// @param[in] d2 : one Digit +/// @return : true if event of d1 comes before the event of d2, for +/// same events evaluates the position into the detector +bool Digit::eventEquipPadsComp(Digit& d1, Digit& d2) +{ + uint64_t t1, t2; + t1 = d1.getTriggerID(); + t2 = d2.getTriggerID(); + if (t1 < t2) { + return true; + } + if (t2 < t1) { + return false; + } + if (d1.getPadID() < d2.getPadID()) { + return true; + } + return false; +}; + + +/// extractDigitsPerEvent : Function for select a sub vector of Digits of the +/// same event +/// @param[in] Digits : one vector of Digits +/// @param[in] EventID : the Trigger ID [ 0000.0000.0000.0000.0000.oooo.oooo.oooo.oooo.oooo.oooo.oooo.oooo.bbbb.bbbb.bbbb ] +/// @return : the subvector of Digits that have the same EventID +std::vector<o2::hmpid::Digit>* Digit::extractDigitsPerEvent(std::vector<o2::hmpid::Digit>& Digits, uint64_t EventID) +{ + std::vector<o2::hmpid::Digit>* subVector = new std::vector<o2::hmpid::Digit>(); + for (const auto& digit : Digits) { + if (digit.getTriggerID() == EventID) { + subVector->push_back(digit); + } + } + return (subVector); +}; + +/// extractEvents : Function that returns the list of Event IDs from a +/// vector of Digits +/// @param[in] Digits : one vector of Digits +/// @return : the vector of Event IDs +std::vector<uint64_t>* Digit::extractEvents(std::vector<o2::hmpid::Digit>& Digits) +{ + std::vector<uint64_t>* eventIds = new std::vector<uint64_t>(); + for (const auto& digit : Digits) { + if (find(eventIds->begin(), eventIds->end(), digit.getTriggerID()) == eventIds->end()) { + eventIds->push_back(digit.getTriggerID()); + } + } + return (eventIds); +}; +*/ + +} // namespace hmpid +} // namespace o2 diff --git a/DataFormats/Detectors/HMPID/src/Trigger.cxx b/DataFormats/Detectors/HMPID/src/Trigger.cxx new file mode 100644 index 0000000000000..81f819d4ab88b --- /dev/null +++ b/DataFormats/Detectors/HMPID/src/Trigger.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Trigger.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to manage HMPID Trigger data +/// \version 1.0 +/// \date 6/04/2021 + +/* ------ HISTORY --------- + +*/ + +#include <iostream> +#include "DataFormatsHMP/Trigger.h" + +ClassImp(o2::hmpid::Trigger); + +namespace o2 +{ +namespace hmpid +{ + +// Digit ASCCI format Dump := (Orbit,BC @ LHCtime ns) [first_digit_idx .. last_digit_idx] +std::ostream& operator<<(std::ostream& os, const o2::hmpid::Trigger& d) +{ + os << "(" << d.mIr.orbit << "," << d.mIr.bc << " @ " << d.mIr.bc2ns() << " ns) [" << d.mDataRange.getFirstEntry() << "," << d.mDataRange.getEntries() << "]"; + return os; +}; + +} // namespace hmpid +} // namespace o2 diff --git a/DataFormats/Detectors/ITSMFT/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/CMakeLists.txt index 2d4bd7067fa3a..60adadd6778b4 100644 --- a/DataFormats/Detectors/ITSMFT/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/CMakeLists.txt @@ -1,13 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(common) add_subdirectory(ITS) add_subdirectory(MFT) +if(ENABLE_UPGRADES) + add_subdirectory(IT3) +endif() diff --git a/DataFormats/Detectors/ITSMFT/IT3/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/IT3/CMakeLists.txt new file mode 100644 index 0000000000000..944ca48df1191 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/IT3/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(DataFormatsITS3 + SOURCES src/CompCluster.cxx) + +o2_target_root_dictionary(DataFormatsITS3 + HEADERS include/DataFormatsITS3/CompCluster.h + LINKDEF src/ITS3DataFormatsLinkDef.h) diff --git a/DataFormats/Detectors/ITSMFT/IT3/include/DataFormatsITS3/CompCluster.h b/DataFormats/Detectors/ITSMFT/IT3/include/DataFormatsITS3/CompCluster.h new file mode 100644 index 0000000000000..03da492fd56c4 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/IT3/include/DataFormatsITS3/CompCluster.h @@ -0,0 +1,119 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CompCluster.h +/// \brief Definition of the ITS3 compact cluster +#ifndef ALICEO2_ITS3_COMPCLUSTER_H +#define ALICEO2_ITS3_COMPCLUSTER_H + +#include <Rtypes.h> + +namespace o2 +{ +namespace its3 +{ + +/// This is a version of the ALPIDE cluster represented by the pattern ID and the address of the +/// top-left (min row,col) pixel of the topololy bounding box + +class CompCluster +{ + public: + static constexpr int NBitsPattID = 11; // number of bits for the pattern ID + private: + static constexpr UShort_t PattIDMask = (0x1 << NBitsPattID) - 1; + static constexpr UShort_t FlagBit = 0x1 << (NBitsPattID); + // + ///< compactified data: bits [0:8] - row, [9-18] - col, [19-30] - pattern ID, bit 31 - special flag + UShort_t mRow; + UShort_t mCol; + UShort_t mPat; + + public: + static constexpr unsigned short InvalidPatternID = (0x1 << NBitsPattID) - 1; // All 11 bits of pattern ID are 1 + CompCluster(UShort_t row = 0, UShort_t col = 0, UShort_t patt = 0) + { + set(row, col, patt); + } + + void set(UShort_t row, UShort_t col, UShort_t patt) + { + setPatternID(patt); + mRow = row; + mCol = col; + } + + UShort_t getRow() const { return mRow; } + UShort_t getCol() const { return mCol; } + UShort_t getPatternID() const { return (mPat & PattIDMask); } + bool getFlag() const { return (mPat & FlagBit) == FlagBit; } + + void setRow(UShort_t r) + { + mRow = r; + } + void setCol(UShort_t c) + { + mCol = c; + }; + void setPatternID(UShort_t p) + { + mPat &= ~(PattIDMask); + mPat |= p; + } + void setFlag(bool v) + { + mPat &= ~FlagBit; + if (v) { + mPat |= FlagBit; + } + } + + void print() const; + + ClassDefNV(CompCluster, 1); +}; + +/// Extension of the compact cluster, augmented by the chipID +/// This is a TEMPORARY class, until we converge to more economical container +class CompClusterExt : public CompCluster +{ + private: + UShort_t mChipID; ///< chip id + + public: + CompClusterExt(UShort_t row = 0, UShort_t col = 0, UShort_t patt = 0, UShort_t chipID = 0) : CompCluster(row, col, patt), mChipID(chipID) + { + } + + void set(UShort_t row, UShort_t col, UShort_t patt, UShort_t chipID) + { + CompCluster::set(row, col, patt); + mChipID = chipID; + } + + UShort_t getChipID() const { return mChipID; } + UShort_t getSensorID() const { return mChipID; } // to have the same signature as BaseCluster + + void setChipID(UShort_t c) { mChipID = c; } + + void print() const; + + ClassDefNV(CompClusterExt, 1); +}; + +} // namespace its3 +} // namespace o2 + +std::ostream& operator<<(std::ostream& stream, const o2::its3::CompCluster& cl); +std::ostream& operator<<(std::ostream& stream, const o2::its3::CompClusterExt& cl); + +#endif /* ALICEO2_ITS3_COMPACTCLUSTER_H */ diff --git a/DataFormats/Detectors/ITSMFT/IT3/src/CompCluster.cxx b/DataFormats/Detectors/ITSMFT/IT3/src/CompCluster.cxx new file mode 100644 index 0000000000000..046a27be92919 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/IT3/src/CompCluster.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Cluster.cxx +/// \brief Implementation of the ITSMFT cluster + +#include "DataFormatsITS3/CompCluster.h" +#include <cassert> +#include <iostream> + +using namespace o2::its3; + +std::ostream& operator<<(std::ostream& stream, const CompCluster& cl) +{ + stream << " row: " << cl.getRow() << " col: " << cl.getCol() + << " pattID " << cl.getPatternID() << " [flag: " << cl.getFlag() << "] "; + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const CompClusterExt& cl) +{ + stream << " chip: " << cl.getChipID() << ((const CompCluster&)cl); + return stream; +} + +//______________________________________________________________________________ +void CompCluster::print() const +{ + // print itself + std::cout << *this << "\n"; +} + +//______________________________________________________________________________ +void CompClusterExt::print() const +{ + // print itself + std::cout << *this << "\n"; +} diff --git a/DataFormats/Detectors/ITSMFT/IT3/src/ITS3DataFormatsLinkDef.h b/DataFormats/Detectors/ITSMFT/IT3/src/ITS3DataFormatsLinkDef.h new file mode 100644 index 0000000000000..c139171540f18 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/IT3/src/ITS3DataFormatsLinkDef.h @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::its3::CompCluster + ; +#pragma link C++ class o2::its3::CompClusterExt + ; +#pragma link C++ class std::vector < o2::its3::CompCluster> + ; +#pragma link C++ class std::vector < o2::its3::CompClusterExt> + ; + +#endif diff --git a/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt index a52a870fb3c6d..5a353881e27ba 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsITS SOURCES src/TrackITS.cxx diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index a178a662b8796..34f0f79ccfdad 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include <vector> +#include "GPUCommonDef.h" #include "ReconstructionDataFormats/Track.h" #include "CommonDataFormat/RangeReference.h" @@ -32,20 +34,24 @@ namespace its class TrackITS : public o2::track::TrackParCov { + enum UserBits { + kNextROF = 1 + }; + using Cluster = o2::itsmft::Cluster; using ClusRefs = o2::dataformats::RangeRefComp<4>; public: using o2::track::TrackParCov::TrackParCov; // inherit base constructors - static constexpr int MaxClusters = 7; + static constexpr int MaxClusters = 16; - TrackITS() = default; - TrackITS(const TrackITS& t) = default; - TrackITS(const o2::track::TrackParCov& parcov) : o2::track::TrackParCov{parcov} {} - TrackITS(const o2::track::TrackParCov& parCov, float chi2, const o2::track::TrackParCov& outer) + GPUdDefault() TrackITS() = default; + GPUdDefault() TrackITS(const TrackITS& t) = default; + GPUd() TrackITS(const o2::track::TrackParCov& parcov) : o2::track::TrackParCov{parcov} {} + GPUd() TrackITS(const o2::track::TrackParCov& parCov, float chi2, const o2::track::TrackParCov& outer) : o2::track::TrackParCov{parCov}, mParamOut{outer}, mChi2{chi2} {} - TrackITS& operator=(const TrackITS& tr) = default; - ~TrackITS() = default; + GPUdDefault() TrackITS& operator=(const TrackITS& tr) = default; + GPUdDefault() ~TrackITS() = default; // These functions must be provided bool propagate(float alpha, float x, float bz); @@ -53,7 +59,8 @@ class TrackITS : public o2::track::TrackParCov // Other functions float getChi2() const { return mChi2; } - int getNumberOfClusters() const { return mClusRef.getEntries(); } + int getNClusters() const { return mClusRef.getEntries(); } + int getNumberOfClusters() const { return getNClusters(); } int getFirstClusterEntry() const { return mClusRef.getFirstEntry(); } int getClusterEntry(int i) const { return getFirstClusterEntry() + i; } void shiftFirstClusterEntry(int bias) @@ -87,33 +94,47 @@ class TrackITS : public o2::track::TrackParCov o2::track::TrackParCov& getParamOut() { return mParamOut; } const o2::track::TrackParCov& getParamOut() const { return mParamOut; } - void setPattern(uint8_t p) { mPattern = p; } - int getPattern() const { return mPattern; } + void setPattern(uint32_t p) { mPattern = p; } + uint32_t getPattern() const { return mPattern; } bool hasHitOnLayer(int i) { return mPattern & (0x1 << i); } + bool isFakeOnLayer(int i) { return !(mPattern & (0x1 << (16 + i))); } + int getNFakeClusters(); + + void setNextROFbit(bool toggle = true) { setUserField((getUserField() & ~kNextROF) | (-toggle & kNextROF)); } + bool hasHitInNextROF() const { return getUserField() & kNextROF; } private: o2::track::TrackParCov mParamOut; ///< parameter at largest radius ClusRefs mClusRef; ///< references on clusters float mChi2 = 0.; ///< Chi2 for this track - uint8_t mPattern = 0; ///< layers pattern + uint32_t mPattern = 0; ///< layers pattern - ClassDefNV(TrackITS, 4); + ClassDefNV(TrackITS, 5); }; class TrackITSExt : public TrackITS { ///< heavy version of TrackITS, with clusters embedded public: - static constexpr int MaxClusters = 7; - using TrackITS::TrackITS; // inherit base constructors + static constexpr int MaxClusters = 16; /// Prepare for overlaps and new detector configurations + using TrackITS::TrackITS; // inherit base constructors - TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, - o2::track::TrackParCov&& outer, std::array<int, MaxClusters> cls) + GPUd() TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, + o2::track::TrackParCov&& outer, std::array<int, MaxClusters> cls) : TrackITS(parCov, chi2, outer), mIndex{cls} { setNumberOfClusters(ncl); } + GPUd() TrackITSExt(o2::track::TrackParCov& parCov, short ncl, float chi2, std::uint32_t rof, + o2::track::TrackParCov& outer, std::array<int, MaxClusters> cls) + : TrackITS(parCov, chi2, outer), mIndex{cls} + { + setNumberOfClusters(ncl); + } + + GPUdDefault() TrackITSExt(const TrackITSExt& t) = default; + void setClusterIndex(int l, int i) { int ncl = getNumberOfClusters(); @@ -127,12 +148,20 @@ class TrackITSExt : public TrackITS { if (newCluster) { getClusterRefs().setEntries(getNumberOfClusters() + 1); + uint32_t pattern = getPattern(); + pattern |= 0x1 << layer; + setPattern(pattern); } mIndex[layer] = idx; } + std::array<int, MaxClusters>& getClusterIndexes() + { + return mIndex; + } + private: - std::array<int, MaxClusters> mIndex = {-1}; ///< Indices of associated clusters + std::array<int, MaxClusters> mIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ///< Indices of associated clusters ClassDefNV(TrackITSExt, 2); }; } // namespace its diff --git a/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h b/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h index c1489bc241a58..91a71847148fb 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h +++ b/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/ITS/src/TrackITS.cxx b/DataFormats/Detectors/ITSMFT/ITS/src/TrackITS.cxx index 9ab6eba05f784..6f0fb6256daf2 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/src/TrackITS.cxx +++ b/DataFormats/Detectors/ITSMFT/ITS/src/TrackITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -105,3 +106,14 @@ Bool_t TrackITS::isBetter(const TrackITS& best, Float_t maxChi2) const } return kFALSE; } + +int TrackITS::getNFakeClusters() +{ + int nFake{0}; + for (int iCl{0}; iCl < getNClusters(); ++iCl) { + if (hasHitOnLayer(iCl) && isFakeOnLayer(iCl)) { + ++nFake; + } + } + return nFake; +} \ No newline at end of file diff --git a/DataFormats/Detectors/ITSMFT/MFT/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/MFT/CMakeLists.txt index 7be046505dbac..db2f801c90ccf 100644 --- a/DataFormats/Detectors/ITSMFT/MFT/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/MFT/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsMFT SOURCES src/TrackMFT.cxx diff --git a/DataFormats/Detectors/ITSMFT/MFT/include/DataFormatsMFT/TrackMFT.h b/DataFormats/Detectors/ITSMFT/MFT/include/DataFormatsMFT/TrackMFT.h index bcd6cd04b77f5..8924016e13c6d 100644 --- a/DataFormats/Detectors/ITSMFT/MFT/include/DataFormatsMFT/TrackMFT.h +++ b/DataFormats/Detectors/ITSMFT/MFT/include/DataFormatsMFT/TrackMFT.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,8 +33,6 @@ namespace mft class TrackMFT : public o2::track::TrackParCovFwd { using ClusRefs = o2::dataformats::RangeRefComp<4>; - using SMatrix55 = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; - using SMatrix5 = ROOT::Math::SVector<Double_t, 5>; public: TrackMFT() = default; @@ -42,8 +41,8 @@ class TrackMFT : public o2::track::TrackParCovFwd // Track finding method void setCA(Bool_t method = true) { mIsCA = method; } - const Bool_t isCA() const { return mIsCA; } - const Bool_t isLTF() const { return !mIsCA; } + const Bool_t isCA() const { return mIsCA; } ///< Track found by CA algorithm + const Bool_t isLTF() const { return !mIsCA; } ///< Track found by Linear Track Finder // Tracking seed charge and momentum from Fast Circle Fit of clusters X,Y positions void setInvQPtSeed(Double_t invqpt) { mInvQPtSeed = invqpt; } @@ -53,36 +52,30 @@ class TrackMFT : public o2::track::TrackParCovFwd void setChi2QPtSeed(Double_t chi2) { mSeedinvQPtFitChi2 = chi2; } const Double_t getChi2QPtSeed() const { return mSeedinvQPtFitChi2; } - std::uint32_t getROFrame() const { return mROFrame; } - void setROFrame(std::uint32_t f) { mROFrame = f; } - - const int getNumberOfPoints() const { return mClusRef.getEntries(); } + const int getNumberOfPoints() const { return mClusRef.getEntries(); } //< Get number of clusters const int getExternalClusterIndexOffset() const { return mClusRef.getFirstEntry(); } void setExternalClusterIndexOffset(int offset = 0) { mClusRef.setFirstEntry(offset); } - void setNumberOfPoints(int n) { mClusRef.setEntries(n); } + void setNumberOfPoints(int n) { mClusRef.setEntries(n); } ///< Set number of clusters void print() const; - const o2::track::TrackParCovFwd& getOutParam() const { return mOutParameters; } - void setOutParam(const o2::track::TrackParCovFwd parcov) { mOutParameters = parcov; } + const o2::track::TrackParCovFwd& getOutParam() const { return mOutParameters; } ///< Returns track parameters fitted outwards + void setOutParam(const o2::track::TrackParCovFwd parcov) { mOutParameters = parcov; } ///< Set track out parameters private: - std::uint32_t mROFrame = 0; ///< RO Frame - Bool_t mIsCA = false; // Track finding method CA vs. LTF + Bool_t mIsCA = false; ///< Track finding method CA vs. LTF - ClusRefs mClusRef; ///< references on clusters + ClusRefs mClusRef; ///< Clusters references - // Outward parameters for MCH matching - o2::track::TrackParCovFwd mOutParameters; + o2::track::TrackParCovFwd mOutParameters; ///< Outward parameters for MCH matching - // Seed InveQPt and Chi2 from fitting clusters X,Y positions - Double_t mSeedinvQPtFitChi2 = 0.; - Double_t mInvQPtSeed; + Double_t mSeedinvQPtFitChi2 = 0.; ///< Seed InvQPt Chi2 from FCF clusters X,Y positions + Double_t mInvQPtSeed; ///< Seed InvQPt from FCF clusters X,Y positions - ClassDefNV(TrackMFT, 1); + ClassDefNV(TrackMFT, 2); }; class TrackMFTExt : public TrackMFT diff --git a/DataFormats/Detectors/ITSMFT/MFT/src/DataFormatsMFTLinkDef.h b/DataFormats/Detectors/ITSMFT/MFT/src/DataFormatsMFTLinkDef.h index 18d57d82ca120..6f9e96d2f6e0b 100644 --- a/DataFormats/Detectors/ITSMFT/MFT/src/DataFormatsMFTLinkDef.h +++ b/DataFormats/Detectors/ITSMFT/MFT/src/DataFormatsMFTLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/MFT/src/TrackMFT.cxx b/DataFormats/Detectors/ITSMFT/MFT/src/TrackMFT.cxx index 814329b02e3f3..2afec30405a92 100644 --- a/DataFormats/Detectors/ITSMFT/MFT/src/TrackMFT.cxx +++ b/DataFormats/Detectors/ITSMFT/MFT/src/TrackMFT.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,8 +24,6 @@ namespace o2 namespace mft { -using SMatrix55 = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; -using SMatrix5 = ROOT::Math::SVector<Double_t, 5>; //__________________________________________________________________________ void TrackMFT::print() const diff --git a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt index 01cd0301c980d..6edae6253c332 100644 --- a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsITSMFT SOURCES src/ROFRecord.cxx @@ -19,19 +20,21 @@ o2_add_library(DataFormatsITSMFT src/TopologyDictionary.cxx src/CTF.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTBase - O2::ReconstructionDataFormats - ms_gsl::ms_gsl) + O2::ReconstructionDataFormats + Microsoft.GSL::GSL) o2_target_root_dictionary(DataFormatsITSMFT HEADERS include/DataFormatsITSMFT/ROFRecord.h - include/DataFormatsITSMFT/Digit.h - include/DataFormatsITSMFT/NoiseMap.h + include/DataFormatsITSMFT/Digit.h + include/DataFormatsITSMFT/GBTCalibData.h + include/DataFormatsITSMFT/NoiseMap.h include/DataFormatsITSMFT/Cluster.h include/DataFormatsITSMFT/CompCluster.h include/DataFormatsITSMFT/ClusterPattern.h include/DataFormatsITSMFT/ClusterTopology.h include/DataFormatsITSMFT/TopologyDictionary.h include/DataFormatsITSMFT/CTF.h + include/DataFormatsITSMFT/TrkClusRef.h LINKDEF src/ITSMFTDataFormatsLinkDef.h) o2_add_test(Cluster diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h index 6002ca330189a..6ed01c5d849e3 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ class ROFRecord; class CompClusterExt; /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nROFs = 0; /// number of ROFrame in TF uint32_t nClusters = 0; /// number of clusters in TF uint32_t nChips = 0; /// number of fired chips in TF : this is for the version with chipInc stored once per new chip @@ -36,7 +37,7 @@ struct CTFHeader { uint32_t firstOrbit = 0; /// 1st orbit of TF uint16_t firstBC = 0; /// 1st BC of TF - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// Compressed but not yet entropy-encoded clusters diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Cluster.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Cluster.h index ad8e844236533..afbdce035d825 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Cluster.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterPattern.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterPattern.h index 3769e28ddf762..a88f2aa0045cd 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterPattern.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterPattern.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,9 +50,9 @@ class ClusterPattern ClusterPattern(); /// Standard constructor ClusterPattern(int nRow, int nCol, const unsigned char patt[MaxPatternBytes]); - /// Constructor from cluster patterns + template <class iterator> - ClusterPattern(iterator& pattIt) + void acquirePattern(iterator& pattIt) { mBitmap[0] = *pattIt++; mBitmap[1] = *pattIt++; @@ -63,10 +64,18 @@ class ClusterPattern memcpy(&mBitmap[2], &(*pattIt), nBytes); pattIt += nBytes; } + + /// Constructor from cluster patterns + template <class iterator> + ClusterPattern(iterator& pattIt) + { + acquirePattern(pattIt); + } + /// Maximum number of bytes for the cluster puttern + 2 bytes respectively for the number of rows and columns of the bounding box static constexpr int kExtendedPatternBytes = MaxPatternBytes + 2; /// Returns the pattern - std::array<unsigned char, kExtendedPatternBytes> getPattern() const { return mBitmap; } + const std::array<unsigned char, kExtendedPatternBytes>& getPattern() const { return mBitmap; } /// Returns a specific byte of the pattern unsigned char getByte(int n) const; /// Returns the number of rows @@ -75,6 +84,8 @@ class ClusterPattern int getColumnSpan() const { return (int)mBitmap[1]; } /// Returns the number of bytes used for the pattern int getUsedBytes() const; + /// Returns the number of fired pixels + int getNPixels() const; /// Prints the pattern friend std::ostream& operator<<(std::ostream& os, const ClusterPattern& top); /// Sets the pattern @@ -84,7 +95,35 @@ class ClusterPattern /// Static: Compute pattern's COG position. Returns the number of fired pixels static int getCOG(int rowSpan, int colSpan, const unsigned char patt[MaxPatternBytes], float& xCOG, float& zCOG); /// Compute pattern's COG position. Returns the number of fired pixels - int getCOG(float& xCOG, float& zCOG) const; + int getCOG(float& xCOG, float& zCOG) const { return ClusterPattern::getCOG(getRowSpan(), getColumnSpan(), mBitmap.data() + 2, xCOG, zCOG); } + + bool isSet(int row, int col) const + { + const auto bmap = mBitmap.data() + 2; + int pos = row * getColumnSpan() + col; + return pos < getColumnSpan() * getRowSpan() && (bmap[pos >> 3] & (0x1 << (7 - (pos % 8)))); + } + + void resetPixel(int row, int col) + { + const auto bmap = mBitmap.data() + 2; + int pos = row * getColumnSpan() + col; + if (pos < getColumnSpan() * getRowSpan()) { + bmap[pos >> 3] &= 0xff & ~(0x1 << (7 - (pos % 8))); + } + } + + void setPixel(int row, int col) + { + const auto bmap = mBitmap.data() + 2; + int pos = row * getColumnSpan() + col; + if (pos < getColumnSpan() * getRowSpan()) { + bmap[pos >> 3] |= 0x1 << (7 - (pos % 8)); + } + } + + template <typename Processor> + void process(Processor procRowCol); friend ClusterTopology; friend TopologyDictionary; @@ -103,6 +142,37 @@ class ClusterPattern ClassDefNV(ClusterPattern, 1); }; + +template <typename Processor> +void ClusterPattern::process(Processor procRowCol) +{ + auto cspan = getColumnSpan(), rspan = getRowSpan(); + uint32_t nBits = cspan * rspan; + uint32_t nBytes = (nBits >> 3) + (nBits % 8 != 0); + const auto bmap = mBitmap.data() + 2; + uint16_t ic = 0, ir = 0; + for (unsigned int i = 0; i < nBytes; i++) { + int s = 128; // 0b10000000 + while (s > 0) { + if ((bmap[i] & s) != 0) { + procRowCol(ir, ic); + } + ic++; + s >>= 1; + if (uint32_t(ir + 1) * ic == nBits) { + break; + } + if (ic == cspan) { + ic = 0; + ir++; + } + } + if (uint32_t(ir + 1) * ic == nBits) { + break; + } + } +} + } // namespace itsmft } // namespace o2 #endif /* ALICEO2_ITS_CLUSTERPATTERN_H */ diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterTopology.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterTopology.h index f25dab5768854..3ef5f717598e6 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterTopology.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterTopology.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,8 +44,8 @@ class ClusterTopology /// Returns a specific byte of the pattern unsigned char getByte(int n) const { return mPattern.getByte(n); } /// Returns the pattern - std::array<unsigned char, ClusterPattern::kExtendedPatternBytes> getPattern() const { return mPattern.getPattern(); } - ClusterPattern getClusterPattern() const { return mPattern; } + const std::array<unsigned char, ClusterPattern::kExtendedPatternBytes>& getPattern() const { return mPattern.getPattern(); } + const ClusterPattern& getClusterPattern() const { return mPattern; } /// Returns the number of rows int getRowSpan() const { return mPattern.getRowSpan(); } /// Returns the number of columns diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h index 6edf2aea3801f..772a9ae12a81a 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Digit.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Digit.h index 8d3ed17cf45ae..61dd63b143733 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Digit.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/GBTCalibData.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/GBTCalibData.h new file mode 100644 index 0000000000000..c0964c3eb4742 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/GBTCalibData.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GBTCalibData.h +/// \brief Calibration data from GBT data + +#ifndef ALICEO2_ITSMFT_GBTCALIBDATA_H_ +#define ALICEO2_ITSMFT_GBTCALIBDATA_H_ + +namespace o2 +{ +namespace itsmft +{ + +struct GBTCalibData { + uint64_t calibCounter = 0; // calibCounter from GBT calibration word + uint64_t calibUserField = 0; // calibUserField from GBT calibration word + + void clear() + { + calibCounter = calibUserField = 0; + } + + ClassDefNV(GBTCalibData, 1); +}; + +} // namespace itsmft +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/NoiseMap.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/NoiseMap.h index bc3f826145e91..688628a6da598 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/NoiseMap.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/NoiseMap.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,11 +20,16 @@ #include <vector> #include <map> +#include "gsl/span" + namespace o2 { namespace itsmft { + +class CompClusterExt; + /// \class NoiseMap /// \brief NoiseMap class for the ITS and MFT /// @@ -48,11 +54,10 @@ class NoiseMap /// Get the noise level for this pixels float getNoiseLevel(int chip, int row, int col) const { - if (chip > mNoisyPixels.size()) { + if (chip > (int)mNoisyPixels.size()) { return 0; } - auto key = row * 1024 + col; - const auto keyIt = mNoisyPixels[chip].find(key); + const auto keyIt = mNoisyPixels[chip].find(getKey(row, col)); if (keyIt != mNoisyPixels[chip].end()) { return keyIt->second; } @@ -61,11 +66,10 @@ class NoiseMap void increaseNoiseCount(int chip, int row, int col) { - if (chip > mNoisyPixels.size()) { + if (chip > (int)mNoisyPixels.size()) { return; } - auto key = row * 1024 + col; - mNoisyPixels[chip][key]++; + mNoisyPixels[chip][getKey(row, col)]++; } int dumpAboveThreshold(int t = 3) const @@ -80,8 +84,8 @@ class NoiseMap } n++; auto key = pair.first; - auto row = key / 1024; - auto col = key % 1024; + auto row = key2Row(key); + auto col = key2Col(key); std::cout << "chip, row, col, noise: " << chipID << ' ' << row << ' ' << col << ' ' << pair.second << '\n'; } } @@ -113,18 +117,22 @@ class NoiseMap bool isNoisy(int chip, int row, int col) const { - if (chip > mNoisyPixels.size()) { - return false; - } - auto key = row * 1024 + col; - const auto keyIt = mNoisyPixels[chip].find(key); - if (keyIt != mNoisyPixels[chip].end()) { - return true; - } - return false; + return chip < (int)mNoisyPixels.size() && (mNoisyPixels[chip].find(getKey(row, col)) != mNoisyPixels[chip].end()); } + bool isNoisy(int chip) const { return chip < (int)mNoisyPixels.size() && !mNoisyPixels[chip].empty(); } + + // Methods required by the calibration framework + void print(); + void fill(const gsl::span<const CompClusterExt> data); + void merge(const NoiseMap* prev) {} + const std::map<int, int>* getChipMap(int chip) const { return chip < (int)mNoisyPixels.size() ? &mNoisyPixels[chip] : nullptr; } + private: + static constexpr int SHIFT = 10, MASK = (0x1 << SHIFT) - 1; + int getKey(int row, int col) const { return (row << SHIFT) + col; } + int key2Row(int key) const { return key >> SHIFT; } + int key2Col(int key) const { return key & MASK; } std::vector<std::map<int, int>> mNoisyPixels; ///< Internal noise map representation long int mNumOfStrobes = 0; ///< Accumulated number of ALPIDE strobes float mProbThreshold = 0; ///< Probability threshold for noisy pixels diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ROFRecord.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ROFRecord.h index 9568b2abca15f..1f7ac73d0a131 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ROFRecord.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ROFRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TopologyDictionary.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TopologyDictionary.h index 8668075dc4302..554ed4a10316b 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TopologyDictionary.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TopologyDictionary.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -145,11 +146,12 @@ class TopologyDictionary return mVectorOfIDs[n].mIsGroup; } /// Returns the pattern of the topology - inline ClusterPattern getPattern(int n) const + inline const ClusterPattern& getPattern(int n) const { assert(n >= 0 || n < (int)mVectorOfIDs.size()); return mVectorOfIDs[n].mPattern; } + /// Fills a hostogram with the distribution of the IDs static void getTopologyDistribution(const TopologyDictionary& dict, TH1F*& histo, const char* histName); /// Returns the number of elements in the dicionary; diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h new file mode 100644 index 0000000000000..164fd850fd539 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrkClusRef.h +/// \brief Reference on ITS/MFT clusters set + +#ifndef ALICEO2_ITSMFT_TRKCLUSREF_H +#define ALICEO2_ITSMFT_TRKCLUSREF_H + +#include "CommonDataFormat/RangeReference.h" + +namespace o2 +{ +namespace itsmft +{ + +// can refer to max 15 indices in the vector of total length <268435456, i.e. 17895697 tracks in worst case +struct TrkClusRef : public o2::dataformats::RangeRefComp<4> { + using o2::dataformats::RangeRefComp<4>::RangeRefComp; + uint16_t pattern = 0; ///< layers pattern + + GPUd() int getNClusters() const { return getEntries(); } + bool hasHitOnLayer(int i) { return pattern & (0x1 << i); } + + ClassDefNV(TrkClusRef, 1); +}; + +} // namespace itsmft +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ITSMFT/common/src/CTF.cxx b/DataFormats/Detectors/ITSMFT/common/src/CTF.cxx index 4d4ea358b29b5..279778ff26376 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/CTF.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,6 +28,7 @@ void CompressedClusters::clear() row.clear(); colInc.clear(); chipInc.clear(); + chipMul.clear(); pattID.clear(); pattMap.clear(); } diff --git a/DataFormats/Detectors/ITSMFT/common/src/Cluster.cxx b/DataFormats/Detectors/ITSMFT/common/src/Cluster.cxx index bbbb7e7139185..968081aca8528 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/Cluster.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/src/ClusterPattern.cxx b/DataFormats/Detectors/ITSMFT/common/src/ClusterPattern.cxx index b7a531f8d2665..aa59dd81014a8 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ClusterPattern.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ClusterPattern.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -101,6 +102,22 @@ std::ostream& operator<<(std::ostream& os, const ClusterPattern& pattern) return os; } +int ClusterPattern::getNPixels() const +{ + int n = 0, nBytes = getUsedBytes(); + const auto* patt = mBitmap.data() + 2; + for (int i = 0; i < nBytes; i++) { + auto p = patt[i]; + if (p) { + p = ((p & 0xAA) >> 1) + (p & 0x55); + p = ((p & 0xCC) >> 2) + (p & 0x33); + p = ((p & 0xF0) >> 4) + (p & 0x0f); + n += p; + } + } + return n; +} + int ClusterPattern::getCOG(int rowSpan, int colSpan, const unsigned char patt[MaxPatternBytes], float& xCOG, float& zCOG) { int tempxCOG = 0, tempzCOG = 0, tempFiredPixels = 0, ic = 0, ir = 0; @@ -138,11 +155,5 @@ int ClusterPattern::getCOG(int rowSpan, int colSpan, const unsigned char patt[Ma return tempFiredPixels; } -int ClusterPattern::getCOG(float& xCOG, float& zCOG) const -{ - auto patt = getPattern(); - return ClusterPattern::getCOG(getRowSpan(), getColumnSpan(), &patt[2], xCOG, zCOG); -} - } // namespace itsmft } // namespace o2 diff --git a/DataFormats/Detectors/ITSMFT/common/src/ClusterTopology.cxx b/DataFormats/Detectors/ITSMFT/common/src/ClusterTopology.cxx index 8e7ece08643a5..a50e29f126486 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ClusterTopology.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ClusterTopology.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -126,7 +127,7 @@ unsigned long ClusterTopology::getCompleteHash(int nRow, int nCol, unsigned long ClusterTopology::getCompleteHash(const ClusterTopology& topology) { - auto patt = topology.getPattern(); + const auto& patt = topology.getPattern(); int nBytesUsed = topology.getUsedBytes(); unsigned long partialHash = (unsigned long)hashFunction(patt.data(), nBytesUsed); // The first four bytes are directly taken from partialHash diff --git a/DataFormats/Detectors/ITSMFT/common/src/CompCluster.cxx b/DataFormats/Detectors/ITSMFT/common/src/CompCluster.cxx index b6028ca2cf9f2..95ecd73f6e9d5 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/CompCluster.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/CompCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/src/Digit.cxx b/DataFormats/Detectors/ITSMFT/common/src/Digit.cxx index 278d91671784a..304a2dc3ae058 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/Digit.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h b/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h index 93d32c016b985..33e926c0bff9f 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h +++ b/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,9 @@ #pragma link C++ class o2::itsmft::NoiseMap + ; #pragma link C++ class std::vector < o2::itsmft::Digit> + ; +#pragma link C++ class o2::itsmft::GBTCalibData + ; +#pragma link C++ class std::vector < o2::itsmft::GBTCalibData> + ; + #pragma link C++ class o2::itsmft::ROFRecord + ; #pragma link C++ class std::vector < o2::itsmft::ROFRecord> + ; #pragma link C++ class o2::itsmft::MC2ROFRecord + ; @@ -34,6 +38,9 @@ #pragma link C++ class o2::itsmft::TopologyDictionary + ; #pragma link C++ class o2::itsmft::GroupStruct + ; +#pragma link C++ class o2::itsmft::TrkClusRef + ; +#pragma link C++ class std::vector < o2::itsmft::TrkClusRef> + ; + #pragma link C++ class o2::itsmft::CTFHeader + ; #pragma link C++ class o2::itsmft::CompressedClusters + ; #pragma link C++ class o2::itsmft::CTF + ; diff --git a/DataFormats/Detectors/ITSMFT/common/src/NoiseMap.cxx b/DataFormats/Detectors/ITSMFT/common/src/NoiseMap.cxx index a1c95abb6e37a..428d87db5e04f 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/NoiseMap.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/NoiseMap.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,5 +13,41 @@ /// \brief Implementation of the ITSMFT NoiseMap #include "DataFormatsITSMFT/NoiseMap.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "Framework/Logger.h" ClassImp(o2::itsmft::NoiseMap); + +using namespace o2::itsmft; + +void NoiseMap::print() +{ + int nc = 0, np = 0; + for (const auto& map : mNoisyPixels) { + if (!map.empty()) { + nc++; + } + np += map.size(); + } + LOG(INFO) << "Number of noisy chips: " << nc; + LOG(INFO) << "Number of noisy pixels: " << np; + LOG(INFO) << "Number of of strobes: " << mNumOfStrobes; + LOG(INFO) << "Probability threshold: " << mProbThreshold; +} + +void NoiseMap::fill(const gsl::span<const CompClusterExt> data) +{ + for (const auto& c : data) { + if (c.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) { + // For the noise calibration, we use "pass1" clusters... + continue; + } + + auto id = c.getSensorID(); + auto row = c.getRow(); + auto col = c.getCol(); + + // A simplified 1-pixel calibration + increaseNoiseCount(id, row, col); + } +} diff --git a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx index ddcd6bcc782d4..fcc86ac7e7dca 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/src/TopologyDictionary.cxx b/DataFormats/Detectors/ITSMFT/common/src/TopologyDictionary.cxx index 7a6cb413d671c..70c24bcfbaeab 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/TopologyDictionary.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/TopologyDictionary.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ITSMFT/common/test/test_Cluster.cxx b/DataFormats/Detectors/ITSMFT/common/test/test_Cluster.cxx index 01f05a54017e6..7b1e49661931e 100644 --- a/DataFormats/Detectors/ITSMFT/common/test/test_Cluster.cxx +++ b/DataFormats/Detectors/ITSMFT/common/test/test_Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/MUON/CMakeLists.txt b/DataFormats/Detectors/MUON/CMakeLists.txt index 497e1d502f36f..934d24d5de4cf 100644 --- a/DataFormats/Detectors/MUON/CMakeLists.txt +++ b/DataFormats/Detectors/MUON/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(MID) add_subdirectory(MCH) diff --git a/DataFormats/Detectors/MUON/MCH/CMakeLists.txt b/DataFormats/Detectors/MUON/MCH/CMakeLists.txt index d7f5190bed5b2..8ef090cc543be 100644 --- a/DataFormats/Detectors/MUON/MCH/CMakeLists.txt +++ b/DataFormats/Detectors/MUON/MCH/CMakeLists.txt @@ -1,16 +1,39 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsMCH SOURCES src/TrackMCH.cxx - PUBLIC_LINK_LIBRARIES O2::CommonDataFormat) + src/Digit.cxx + src/CTF.cxx + src/ROFRecord.cxx + src/ClusterBlock.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::DetectorsCommonDataFormats) o2_target_root_dictionary(DataFormatsMCH - HEADERS include/DataFormatsMCH/TrackMCH.h) + HEADERS include/DataFormatsMCH/Digit.h + include/DataFormatsMCH/DsChannelGroup.h + include/DataFormatsMCH/ROFRecord.h + include/DataFormatsMCH/TrackMCH.h + include/DataFormatsMCH/ClusterBlock.h + include/DataFormatsMCH/CTF.h) + +o2_add_executable(convert-bad-channels + SOURCES src/convert-bad-channels.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::DataFormatsMCH Boost::program_options) + +o2_add_test(digit + SOURCES src/testDigit.cxx + PUBLIC_LINK_LIBRARIES O2::MCHBase + COMPONENT_NAME mch + LABELS muon;mch) + diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/CTF.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/CTF.h new file mode 100644 index 0000000000000..2df0c1c67b040 --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/CTF.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for MCH CTF data + +#ifndef O2_MCH_CTF_H +#define O2_MCH_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" +#include <iosfwd> + +namespace o2 +{ +namespace mch +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nROFs = 0; /// number of ROFrames in TF + uint32_t nDigits = 0; /// number of digits in TF + uint32_t firstOrbit = 0; /// 1st orbit of TF + uint16_t firstBC = 0; /// 1st BC of TF + + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded clusters of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 9, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncROF, + BLC_orbitIncROF, + BLC_nDigitsROF, + BLC_tfTime, + BLC_nSamples, + BLC_isSaturated, + BLC_detID, + BLC_padID, + BLC_ADC }; + ClassDefNV(CTF, 1); +}; + +std::ostream& operator<<(std::ostream&, const CTFHeader&); + +} // namespace mch +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ClusterBlock.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ClusterBlock.h new file mode 100644 index 0000000000000..ac9150fa1a3f4 --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ClusterBlock.h @@ -0,0 +1,79 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ClusterBlock.h +/// \brief Definition of the MCH cluster minimal structure +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MCH_CLUSTERBLOCK_H_ +#define ALICEO2_MCH_CLUSTERBLOCK_H_ + +#include <iostream> +#include <stdexcept> +#include <Rtypes.h> + +namespace o2 +{ +namespace mch +{ + +/// cluster minimal structure +struct ClusterStruct { + float x; ///< cluster position along x + float y; ///< cluster position along y + float z; ///< cluster position along z + float ex; ///< cluster resolution along x + float ey; ///< cluster resolution along y + uint32_t uid; ///< cluster unique ID + uint32_t firstDigit; ///< index of first associated digit in the ordered vector of digits + uint32_t nDigits; ///< number of digits attached to this cluster + + /// Return the chamber ID (0..), part of the unique ID + int getChamberId() const { return getChamberId(uid); } + /// Return the detection element ID, part of the unique ID + int getDEId() const { return getDEId(uid); } + /// Return the index of this cluster (0..), part of the unique ID + int getClusterIndex() const { return getClusterIndex(uid); } + + /// Return the chamber ID of the cluster, part of its unique ID + static int getChamberId(uint32_t clusterId) { return (clusterId & 0xF0000000) >> 28; } + /// Return the detection element ID of the cluster, part of its unique ID + static int getDEId(uint32_t clusterId) { return (clusterId & 0x0FFE0000) >> 17; } + /// Return the index of the cluster, part of its unique ID + static int getClusterIndex(uint32_t clusterId) { return (clusterId & 0x0001FFFF); } + + /// Build the unique ID of the cluster from the chamber ID, detection element ID and cluster index + static uint32_t buildUniqueId(int chamberId, int deId, int clusterIndex) + { + if ((clusterIndex & 0x1FFFF) != clusterIndex) { + throw std::runtime_error("invalid cluster index. Cannot build unique ID"); + } + return (((chamberId & 0xF) << 28) | ((deId & 0x7FF) << 17) | clusterIndex); + } + + ClassDefNV(ClusterStruct, 1) +}; + +std::ostream& operator<<(std::ostream& stream, const ClusterStruct& cluster); +} // namespace mch +} // namespace o2 + +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::mch::ClusterStruct> : std::true_type { +}; +} // namespace framework + +#endif // ALICEO2_MCH_CLUSTERBLOCK_H_ diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h new file mode 100644 index 0000000000000..1a5e8d4fe2112 --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** @file Digit.h + * C++ simple Muon MCH digit. + * @author Michael Winn + */ + +#ifndef ALICEO2_MCH_BASE_DIGIT_H_ +#define ALICEO2_MCH_BASE_DIGIT_H_ + +#include "Rtypes.h" +#include <iosfwd> + +namespace o2 +{ +namespace mch +{ + +// \class Digit +/// \brief MCH digit implementation +class Digit +{ + public: + Digit() = default; + + Digit(int detid, int pad, uint32_t adc, int32_t time, uint16_t nSamples = 1, bool saturated = false); + ~Digit() = default; + + bool operator==(const Digit&) const; + + // time in bunch crossing units, relative to the beginning of the TimeFrame + void setTime(int32_t t) { mTFtime = t; } + int32_t getTime() const { return mTFtime; } + + void setNofSamples(uint16_t n); + uint16_t getNofSamples() const; + + void setSaturated(bool sat); + bool isSaturated() const; + + int getDetID() const { return mDetID; } + + int getPadID() const { return mPadID; } + void setPadID(int padID) { mPadID = padID; } + + uint32_t getADC() const { return mADC; } + void setADC(uint32_t adc) { mADC = adc; } + + private: + int32_t mTFtime; /// time since the beginning of the time frame, in bunch crossing units + uint16_t mNofSamples; /// number of samples in the signal + bool mIsSaturated; /// whether or not the digit amplitude is above saturation + int mDetID; /// ID of the Detection Element to which the digit corresponds to + int mPadID; /// PadIndex to which the digit corresponds to + uint32_t mADC; /// Amplitude of signal + + ClassDefNV(Digit, 4); +}; //class Digit + +std::ostream& operator<<(std::ostream& os, const Digit& d); + +} //namespace mch +} //namespace o2 +#endif // ALICEO2_MCH_DIGIT_H_ diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/DsChannelGroup.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/DsChannelGroup.h new file mode 100644 index 0000000000000..d6dd6c3d60128 --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/DsChannelGroup.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DsChannleGroup.h +/// \brief Implementation of a group of DualSampa channels +/// +/// \author Andrea Ferrero, CEA-Saclay + +#ifndef ALICEO2_MCH_DSCHANNELGROUP_H_ +#define ALICEO2_MCH_DSCHANNELGROUP_H_ + +#include <vector> +#include "Rtypes.h" + +namespace o2 +{ +namespace mch +{ + +/// Unique 32-bit identifier of a DulaSampa channel. The ID is generated from the following indexes: +/// - the unique ID of the corresponding solar board +/// - the index of the DulaSampa board within the Solar board, from 0 to 39 +/// - the channel number, from 0 to 63 +class DsChannelId +{ + public: + DsChannelId() = default; + DsChannelId(uint32_t channelId) : mChannelId(channelId) {} + DsChannelId(uint16_t solarId, uint8_t dsId, uint8_t channel) + { + set(solarId, dsId, channel); + } + + static uint32_t make(uint16_t solarId, uint8_t dsId, uint8_t channel) + { + uint32_t id = (static_cast<uint32_t>(solarId) << 16) + + (static_cast<uint32_t>(dsId) << 8) + channel; + return id; + } + + void set(uint16_t solarId, uint8_t dsId, uint8_t channel) + { + mChannelId = DsChannelId::make(solarId, dsId, channel); + } + + uint16_t getSolarId() const { return static_cast<uint16_t>((mChannelId >> 16) & 0xFFFF); } + uint8_t getDsId() const { return static_cast<uint8_t>((mChannelId >> 8) & 0xFF); } + uint8_t getChannel() const { return static_cast<uint8_t>(mChannelId & 0xFF); } + + private: + uint32_t mChannelId{0}; + + ClassDefNV(DsChannelId, 1); // class for MCH readout channel +}; + +/// A group of DualSampa channels, implemented as a vector of 32-bit channel identifiers +class DsChannelGroup +{ + public: + DsChannelGroup() = default; + + const std::vector<DsChannelId>& getChannels() const { return mChannels; } + std::vector<DsChannelId>& getChannels() { return mChannels; } + + void reset() { mChannels.clear(); } + + private: + std::vector<DsChannelId> mChannels; + + ClassDefNV(DsChannelGroup, 1); // class for MCH bad channels list +}; + +} // end namespace mch +} // end namespace o2 + +#endif /* ALICEO2_MCH_DSCHANNELGROUP_H_ */ diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h new file mode 100644 index 0000000000000..363467108088a --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ROFRecord.h +/// \brief Definition of the MCH ROFrame record +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MCH_ROFRECORD_H +#define ALICEO2_MCH_ROFRECORD_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" + +#include <iosfwd> + +namespace o2 +{ +namespace mch +{ + +/// ROFRecord class encodes the trigger interaction record of a given ROF and +/// the location of the associated objects (digit, cluster, etc) in the data container +class ROFRecord +{ + using BCData = o2::InteractionRecord; + using DataRef = o2::dataformats::RangeReference<int, int>; + + public: + ROFRecord() = default; + ROFRecord(const BCData& bc, int firstIdx, int nEntries) : mBCData(bc), mDataRef(firstIdx, nEntries) {} + ROFRecord(const BCData& bc, int firstIdx, int nEntries, int bcWidth) : mBCData(bc), mDataRef(firstIdx, nEntries), mBCWidth(bcWidth) {} + + /// get the interaction record + const BCData& getBCData() const { return mBCData; } + /// get the interaction record + BCData& getBCData() { return mBCData; } + /// set the interaction record + void setBCData(const BCData& bc) { mBCData = bc; } + + /// get the number of associated objects + int getNEntries() const { return mDataRef.getEntries(); } + /// get the index of the first associated object + int getFirstIdx() const { return mDataRef.getFirstEntry(); } + /// get the index of the last associated object + int getLastIdx() const { return mDataRef.getFirstEntry() + mDataRef.getEntries() - 1; } + /// set the number of associated objects and the index of the first one + void setDataRef(int firstIdx, int nEntries) { mDataRef.set(firstIdx, nEntries); } + + /// get the time span by this ROF, in BC unit + int getBCWidth() const { return mBCWidth; } + + bool operator==(const ROFRecord& other) const + { + return mBCData == other.mBCData && + mDataRef == other.mDataRef && + mBCWidth == other.mBCWidth; + } + bool operator<(const ROFRecord& other) const + { + if (mBCData == other.mBCData) { + if (mBCWidth == other.mBCWidth) { + return mDataRef.getFirstEntry() < other.mDataRef.getFirstEntry(); + } else { + return mBCWidth < other.mBCWidth; + } + } + return mBCData < other.mBCData; + } + + private: + BCData mBCData{}; ///< interaction record + DataRef mDataRef{}; ///< reference to the associated objects + int mBCWidth{4}; ///< time span of this ROF + + ClassDefNV(ROFRecord, 2); +}; + +std::ostream& operator<<(std::ostream& os, const ROFRecord& rof); + +} // namespace mch +} // namespace o2 + +#endif // ALICEO2_MCH_ROFRECORD_H diff --git a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h index becd8805e93f7..f5e3de63a7916 100644 --- a/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h +++ b/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #define ALICEO2_MCH_TRACKMCH_H_ #include <TMatrixD.h> +#include <iosfwd> #include "CommonDataFormat/RangeReference.h" @@ -32,7 +34,8 @@ class TrackMCH public: TrackMCH() = default; - TrackMCH(double z, const TMatrixD& param, const TMatrixD& cov, double chi2, int firstClIdx, int nClusters); + TrackMCH(double z, const TMatrixD& param, const TMatrixD& cov, double chi2, int firstClIdx, int nClusters, + double zAtMID, const TMatrixD& paramAtMID, const TMatrixD& covAtMID); ~TrackMCH() = default; TrackMCH(const TrackMCH& track) = default; @@ -66,8 +69,25 @@ class TrackMCH const double* getCovariances() const { return mCov; } /// get the covariance between track parameters i and j double getCovariance(int i, int j) const { return mCov[SCovIdx[i][j]]; } - // set the track parameter covariances - void setCovariances(const TMatrixD& cov); + /// set the track parameter covariances + void setCovariances(const TMatrixD& cov) { setCovariances(cov, mCov); } + + /// get the track z position on the MID side where the parameters are evaluated + double getZAtMID() const { return mZAtMID; } + /// set the track z position on the MID side where the parameters are evaluated + void setZAtMID(double z) { mZAtMID = z; } + + /// get the track parameters on the MID side + const double* getParametersAtMID() const { return mParamAtMID; } + /// set the track parameters on the MID side + void setParametersAtMID(const TMatrixD& param) { param.GetMatrix2Array(mParamAtMID); } + + /// get the track parameter covariances on the MID side + const double* getCovariancesAtMID() const { return mCovAtMID; } + /// get the covariance between track parameters i and j on the MID side + double getCovarianceAtMID(int i, int j) const { return mCovAtMID[SCovIdx[i][j]]; } + /// set the track parameter covariances on the MID side + void setCovariancesAtMID(const TMatrixD& cov) { setCovariances(cov, mCovAtMID); } /// get the track chi2 double getChi2() const { return mChi2; } @@ -97,6 +117,8 @@ class TrackMCH {6, 7, 8, 9, 13}, {10, 11, 12, 13, 14}}; + void setCovariances(const TMatrixD& src, double (&dest)[SCovSize]); + double mZ = 0.; ///< z position where the parameters are evaluated double mParam[SNParams] = {0.}; ///< 5 parameters: X (cm), SlopeX, Y (cm), SlopeY, q/pYZ ((GeV/c)^-1) /// reduced covariance matrix of track parameters, formated as follow: <pre> @@ -106,12 +128,22 @@ class TrackMCH /// [6] = <SlopeY,X> [7] = <SlopeY,SlopeX> [8] = <SlopeY,Y> [9] = <SlopeY,SlopeY> /// [10]= <q/pYZ,X> [11]= <q/pYZ,SlopeX> [12]= <q/pYZ,Y> [13]= <q/pYZ,SlopeY> [14]= <q/pYZ,q/pYZ> </pre> double mCov[SCovSize] = {0.}; - double mChi2 = 0.; ///< chi2 of track + + double mChi2 = 0.; ///< chi2 of track + ClusRef mClusRef{}; ///< reference to external cluster indices - ClassDefNV(TrackMCH, 1); + double mZAtMID = 0.; ///< z position on the MID side where the parameters are evaluated + double mParamAtMID[SNParams] = {0.}; ///< 5 parameters: X (cm), SlopeX, Y (cm), SlopeY, q/pYZ ((GeV/c)^-1) + double mCovAtMID[SCovSize] = {0.}; ///< reduced covariance matrix of track parameters, formated as above + + ClassDefNV(TrackMCH, 2); }; +std::ostream& operator<<(std::ostream& os, const TrackMCH& t); + +std::string asString(const o2::mch::TrackMCH& t); + } // namespace mch } // namespace o2 diff --git a/DataFormats/Detectors/MUON/MCH/src/CTF.cxx b/DataFormats/Detectors/MUON/MCH/src/CTF.cxx new file mode 100644 index 0000000000000..70c048e16384b --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/CTF.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsMCH/CTF.h" +#include <iostream> + +namespace o2::mch +{ +std::ostream& operator<<(std::ostream& os, const CTFHeader& ctf) +{ + os << fmt::format("nROFS {} nDigits {} firstOrbit {} firstBC {}", + ctf.nROFs, ctf.nDigits, ctf.firstOrbit, ctf.firstBC); + return os; +} +} // namespace o2::mch diff --git a/DataFormats/Detectors/MUON/MCH/src/ClusterBlock.cxx b/DataFormats/Detectors/MUON/MCH/src/ClusterBlock.cxx new file mode 100644 index 0000000000000..5ca1b9b3686be --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/ClusterBlock.cxx @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ClusterBlock.cxx +/// \brief Implementation of the MCH cluster minimal structure +/// +/// \author Philippe Pillot, Subatech + +#include "DataFormatsMCH/ClusterBlock.h" + +namespace o2 +{ +namespace mch +{ + +//_________________________________________________________________________ +std::ostream& operator<<(std::ostream& stream, const ClusterStruct& cluster) +{ + auto oldflags = stream.flags(); + stream << "{x = " << cluster.x << ", y = " << cluster.y << ", z = " << cluster.z << ", ex = " << cluster.ex + << ", ey = " << cluster.ey << ", uid = " << cluster.uid << "}"; + stream.flags(oldflags); + return stream; +} + +} // namespace mch +} // namespace o2 diff --git a/DataFormats/Detectors/MUON/MCH/src/DataFormatsMCHLinkDef.h b/DataFormats/Detectors/MUON/MCH/src/DataFormatsMCHLinkDef.h index 7784e087e6eb5..02d356ff7f5a7 100644 --- a/DataFormats/Detectors/MUON/MCH/src/DataFormatsMCHLinkDef.h +++ b/DataFormats/Detectors/MUON/MCH/src/DataFormatsMCHLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,5 +15,18 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::mch::ROFRecord + ; #pragma link C++ class o2::mch::TrackMCH + ; +#pragma link C++ class std::vector < o2::mch::TrackMCH> + ; +#pragma link C++ class o2::mch::ClusterStruct + ; +#pragma link C++ class std::vector < o2::mch::ClusterStruct> + ; +#pragma link C++ class o2::mch::DsChannelId + ; +#pragma link C++ class o2::mch::DsChannelGroup + ; +#pragma link C++ class o2::mch::Digit + ; +#pragma link C++ class std::vector < o2::mch::Digit> + ; +#pragma link C++ struct o2::mch::CTFHeader + ; +#pragma link C++ struct o2::mch::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::mch::CTFHeader, 9, uint32_t> + ; +#pragma link C++ class std::vector < o2::mch::ROFRecord> + ; + #endif diff --git a/DataFormats/Detectors/MUON/MCH/src/Digit.cxx b/DataFormats/Detectors/MUON/MCH/src/Digit.cxx new file mode 100644 index 0000000000000..459500f9bfa8e --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/Digit.cxx @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsMCH/Digit.h" +#include <cmath> +#include <fmt/format.h> +#include <iostream> + +namespace o2::mch +{ + +std::ostream& operator<<(std::ostream& os, const o2::mch::Digit& d) +{ + os << fmt::format("DetID {:4d} PadId {:6d} ADC {:10d} TFtime {:10d} NofSamples {:5d} {}", + d.getDetID(), d.getPadID(), d.getADC(), d.getTime(), d.getNofSamples(), + d.isSaturated() ? "(S)" : ""); + return os; +} + +bool closeEnough(double x, double y, double eps = 1E-6) +{ + return std::fabs(x - y) <= eps * std::max(1.0, std::max(std::fabs(x), std::fabs(y))); +} + +Digit::Digit(int detid, int pad, uint32_t adc, int32_t time, uint16_t nSamples, bool saturated) + : mTFtime(time), mNofSamples(nSamples), mIsSaturated(saturated), mDetID(detid), mPadID(pad), mADC(adc) +{ + setNofSamples(nSamples); +} + +uint16_t Digit::getNofSamples() const +{ + return mNofSamples; +} + +bool Digit::isSaturated() const +{ + return mIsSaturated; +} + +void Digit::setNofSamples(uint16_t n) +{ + constexpr uint64_t max10bits = (static_cast<uint64_t>(1) << 10); + if (static_cast<uint64_t>(n) >= max10bits) { + throw std::invalid_argument("mch digit nofsamples must fit within 10 bits"); + } + mNofSamples = n; +} + +void Digit::setSaturated(bool sat) +{ + mIsSaturated = sat; +} + +bool Digit::operator==(const Digit& other) const +{ + return mDetID == other.mDetID && + mPadID == other.mPadID && + mADC == other.mADC && + mTFtime == other.mTFtime && + mNofSamples == other.mNofSamples; +} + +} // namespace o2::mch diff --git a/DataFormats/Detectors/MUON/MCH/src/ROFRecord.cxx b/DataFormats/Detectors/MUON/MCH/src/ROFRecord.cxx new file mode 100644 index 0000000000000..c7f43329b241e --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/ROFRecord.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsMCH/ROFRecord.h" +#include <fmt/format.h> +#include <iostream> +#include <stdexcept> + +namespace o2::mch +{ +std::ostream& operator<<(std::ostream& os, const ROFRecord& rof) +{ + os << fmt::format("{} FirstIdx: {:5d} LastIdx: {:5d} Width: {:2d} BCs", + rof.getBCData().asString(), rof.getFirstIdx(), rof.getLastIdx(), + rof.getBCWidth()); + return os; +} + +} // namespace o2::mch diff --git a/DataFormats/Detectors/MUON/MCH/src/TrackMCH.cxx b/DataFormats/Detectors/MUON/MCH/src/TrackMCH.cxx index 80ef07470b556..7dcca9bc86e5e 100644 --- a/DataFormats/Detectors/MUON/MCH/src/TrackMCH.cxx +++ b/DataFormats/Detectors/MUON/MCH/src/TrackMCH.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,9 @@ #include <cmath> #include <limits> +#include <fmt/format.h> +#include <string> +#include <iostream> namespace o2 { @@ -24,12 +28,15 @@ namespace mch { //__________________________________________________________________________ -TrackMCH::TrackMCH(double z, const TMatrixD& param, const TMatrixD& cov, double chi2, int firstClIdx, int nClusters) - : mZ(z), mChi2(chi2), mClusRef(firstClIdx, nClusters) +TrackMCH::TrackMCH(double z, const TMatrixD& param, const TMatrixD& cov, double chi2, int firstClIdx, int nClusters, + double zAtMID, const TMatrixD& paramAtMID, const TMatrixD& covAtMID) + : mZ(z), mChi2(chi2), mClusRef(firstClIdx, nClusters), mZAtMID(zAtMID) { /// constructor setParameters(param); setCovariances(cov); + setParametersAtMID(paramAtMID); + setCovariancesAtMID(covAtMID); } //__________________________________________________________________________ @@ -70,15 +77,27 @@ double TrackMCH::getP() const } //__________________________________________________________________________ -void TrackMCH::setCovariances(const TMatrixD& cov) +void TrackMCH::setCovariances(const TMatrixD& src, double (&dest)[SCovSize]) { /// set the track parameter covariances for (int i = 0; i < SNParams; i++) { for (int j = 0; j <= i; j++) { - mCov[SCovIdx[i][j]] = cov(i, j); + dest[SCovIdx[i][j]] = src(i, j); } } } +std::ostream& operator<<(std::ostream& os, const o2::mch::TrackMCH& t) +{ + os << asString(t); + return os; +} + +std::string asString(const o2::mch::TrackMCH& t) +{ + auto pt = std::sqrt(t.getPx() * t.getPx() + t.getPy() * t.getPy()); + return fmt::format("({:s}) p {:7.2f} pt {:7.2f} nclusters: {} z: {:7.2f}", t.getSign() == -1 ? "-" : "+", t.getP(), pt, t.getNClusters(), t.getZ()); +} + } // namespace mch } // namespace o2 diff --git a/DataFormats/Detectors/MUON/MCH/src/convert-bad-channels.cxx b/DataFormats/Detectors/MUON/MCH/src/convert-bad-channels.cxx new file mode 100644 index 0000000000000..75adc0961bbaa --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/convert-bad-channels.cxx @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/program_options.hpp> +#include <stdexcept> +#include <TFile.h> +#include <string> +#include <iostream> +#include <fmt/format.h> +#include "DataFormatsMCH/DsChannelGroup.h" + +namespace po = boost::program_options; + +int convertRootToCSV(const std::string rootFileName) +{ + TFile* f = TFile::Open(rootFileName.c_str()); + if (f->IsZombie()) { + throw std::runtime_error("can not open " + rootFileName); + } + auto dsChannelGroup = reinterpret_cast<o2::mch::DsChannelGroup*>(f->Get("ccdb_object")); + auto channels = dsChannelGroup->getChannels(); + + std::cout << fmt::format("solarid,dsid,ch\n"); + + for (auto c : channels) { + std::cout << fmt::format("{},{},{}\n", + c.getSolarId(), c.getDsId(), c.getChannel()); + } + + delete f; + return 0; +} + +int main(int argc, char** argv) +{ + po::variables_map vm; + po::options_description options; + + // clang-format off + options.add_options() + ("help,h","help") + ("input",po::value<std::string>()->required(),"path to input root file to be converted to csv"); + // clang-format on + + po::options_description cmdline; + cmdline.add(options); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << R"( +This program converts a Root file containing bad channels information into the +same information in CSV format. + +The output file format is : + +solarid, dsid, ch + +where solarid, dsid and ch are integers. + +)"; + std::cout + << options << "\n"; + std::cout << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + std::cout << options << "\n"; + exit(1); + } + + return convertRootToCSV(vm["input"].as<std::string>()); +} diff --git a/DataFormats/Detectors/MUON/MCH/src/testDigit.cxx b/DataFormats/Detectors/MUON/MCH/src/testDigit.cxx new file mode 100644 index 0000000000000..6a0c1d916d1ce --- /dev/null +++ b/DataFormats/Detectors/MUON/MCH/src/testDigit.cxx @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/test/tools/old/interface.hpp> +#define BOOST_TEST_MODULE MCH Digit +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/data/test_case.hpp> +#include <boost/test/data/monomorphic.hpp> + +#include "DataFormatsMCH/Digit.h" + +int dummyDetId{712}; +int dummyPadId{0}; +unsigned long dummyADC{0}; +uint32_t dummyTime{0}; +uint16_t dummyNofSamples{0}; + +BOOST_AUTO_TEST_CASE(NofSamplesMustFitWithin10Bits) +{ + BOOST_CHECK_THROW(o2::mch::Digit d(dummyDetId, dummyPadId, dummyADC, dummyTime, 1025), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DefaultConstructorMakesNonSaturatedDigit) +{ + o2::mch::Digit d(dummyDetId, dummyPadId, dummyADC, dummyTime, dummyNofSamples); + BOOST_CHECK(d.isSaturated() == false); +} + +std::vector<uint16_t> nsamples{ + 1 << 0, + 1 << 1, + 1 << 2, + 1 << 3, + 1 << 4, + 1 << 5, + 1 << 6, + 1 << 7, + 1 << 8, + 1 << 9}; + +BOOST_DATA_TEST_CASE(DefaultConstructorNofSamplesIsInvariant, + boost::unit_test::data::make(nsamples), nofSamples) +{ + o2::mch::Digit d(dummyDetId, dummyPadId, dummyADC, dummyTime, nofSamples); + BOOST_CHECK_EQUAL(d.getNofSamples(), nofSamples); +} + +BOOST_DATA_TEST_CASE(SetSaturatedDoesNotAffectPublicNofSamples, + boost::unit_test::data::make(nsamples), nofSamples) +{ + o2::mch::Digit d(dummyDetId, dummyPadId, dummyADC, dummyTime, nofSamples); + + BOOST_TEST_INFO("setting saturation to true"); + d.setSaturated(true); + BOOST_CHECK_EQUAL(d.getNofSamples(), nofSamples); + + BOOST_TEST_INFO("setting saturation to false"); + d.setSaturated(false); + BOOST_CHECK_EQUAL(d.getNofSamples(), nofSamples); +} diff --git a/DataFormats/Detectors/MUON/MID/CMakeLists.txt b/DataFormats/Detectors/MUON/MID/CMakeLists.txt index e4379336070f1..fa8faccf63531 100644 --- a/DataFormats/Detectors/MUON/MID/CMakeLists.txt +++ b/DataFormats/Detectors/MUON/MID/CMakeLists.txt @@ -1,26 +1,27 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library(DataFormatsMID - SOURCES src/ColumnData.cxx - src/Track.cxx - src/CTF.cxx - PUBLIC_LINK_LIBRARIES Boost::serialization O2::MathUtils - O2::CommonDataFormat - O2::DetectorsCommonDataFormats - O2::ReconstructionDataFormats) +o2_add_library( + DataFormatsMID + SOURCES src/ColumnData.cxx src/CTF.cxx src/ROBoard.cxx src/Track.cxx + PUBLIC_LINK_LIBRARIES + Boost::serialization O2::MathUtils O2::CommonDataFormat + O2::DetectorsCommonDataFormats O2::ReconstructionDataFormats) -o2_target_root_dictionary(DataFormatsMID - HEADERS include/DataFormatsMID/Cluster2D.h - include/DataFormatsMID/Cluster3D.h - include/DataFormatsMID/ColumnData.h - include/DataFormatsMID/ROFRecord.h - include/DataFormatsMID/Track.h - include/DataFormatsMID/CTF.h) +o2_target_root_dictionary( + DataFormatsMID + HEADERS include/DataFormatsMID/Cluster2D.h + include/DataFormatsMID/Cluster3D.h + include/DataFormatsMID/ColumnData.h + include/DataFormatsMID/ROBoard.h + include/DataFormatsMID/ROFRecord.h + include/DataFormatsMID/Track.h + include/DataFormatsMID/CTF.h) diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/CTF.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/CTF.h index ed7d4b78ed539..bcfca4aca95de 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/CTF.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,13 +28,13 @@ namespace mid { /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nROFs = 0; /// number of ROFrames in TF uint32_t nColumns = 0; /// number of referred columns in TF uint32_t firstOrbit = 0; /// 1st orbit of TF uint16_t firstBC = 0; /// 1st BC of TF - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// wrapper for the Entropy-encoded clusters of the TF diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster2D.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster2D.h index 04d8591aaae1c..6b8921814f82f 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster2D.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster2D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,8 @@ #include <ostream> #include <cstdint> +#include "Rtypes.h" + namespace o2 { namespace mid @@ -30,6 +33,8 @@ struct Cluster2D { float yCoor; ///< Local y coordinate float sigmaX2; ///< Square of dispersion along x float sigmaY2; ///< Square of dispersion along y + + ClassDefNV(Cluster2D, 1); }; inline std::ostream& operator<<(std::ostream& os, const Cluster2D& data) diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster3D.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster3D.h index 34b3bbcc5fa9c..a8e9b0fd88bee 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster3D.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Cluster3D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,8 @@ #include <ostream> #include <cstdint> +#include "Rtypes.h" + namespace o2 { namespace mid @@ -31,6 +34,8 @@ struct Cluster3D { float zCoor; ///< z coordinate float sigmaX2; ///< Dispersion along x float sigmaY2; ///< Dispersion along y + + ClassDefNV(Cluster3D, 1); }; inline std::ostream& operator<<(std::ostream& os, const Cluster3D& data) diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ColumnData.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ColumnData.h index 1992e44b033c7..2f1b2be4e7609 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ColumnData.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ColumnData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,9 +27,9 @@ namespace mid { /// Column data structure for MID struct ColumnData { - uint8_t deId = 0; ///< Index of the detection element - uint8_t columnId = 0; ///< Column in DE - std::array<uint16_t, 5> patterns; ///< Strip patterns + uint8_t deId = 0; ///< Index of the detection element + uint8_t columnId = 0; ///< Column in DE + std::array<uint16_t, 5> patterns{}; ///< Strip patterns /// Sets the bending plane pattern void setBendPattern(uint16_t pattern, int line) { patterns[line] = pattern; } @@ -51,12 +52,18 @@ struct ColumnData { bool isBPStripFired(int istrip, int line) const { return patterns[line] & (1 << istrip); } bool isStripFired(int istrip, int cathode, int line) const; + + bool operator==(const ColumnData& right) const; + + bool isEmpty() const; }; ColumnData operator|(const ColumnData& col1, const ColumnData& col2); ColumnData& operator|=(ColumnData& col1, const ColumnData& col2); std::ostream& operator<<(std::ostream& os, const ColumnData& col); +/// Gets an unique ID for the ColumnData +inline uint16_t getColumnDataUniqueId(uint8_t deId, uint8_t columnId) { return (static_cast<uint16_t>(deId) << 4) | columnId; } } // namespace mid } // namespace o2 diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROBoard.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROBoard.h new file mode 100644 index 0000000000000..ea33b2125147c --- /dev/null +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROBoard.h @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataFormatsMID/ROBoard.h +/// \brief Structure to store the readout board information +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 19 November 2019 +#ifndef O2_MID_ROBOARD_H +#define O2_MID_ROBOARD_H + +#include <cstdint> +#include <array> +#include <iosfwd> + +namespace o2 +{ +namespace mid +{ +struct ROBoard { + uint8_t statusWord{0}; /// Status word + uint8_t triggerWord{0}; /// Trigger word + uint8_t boardId{0}; /// Board ID in crate + uint8_t firedChambers{0}; /// Fired chambers + std::array<uint16_t, 4> patternsBP{}; /// Bending plane pattern + std::array<uint16_t, 4> patternsNBP{}; /// Non-bending plane pattern +}; + +std::ostream& operator<<(std::ostream& os, const ROBoard& loc); + +namespace raw +{ + +static constexpr uint8_t sSTARTBIT = 1 << 7; +static constexpr uint8_t sCARDTYPE = 1 << 6; +static constexpr uint8_t sLOCALBUSY = 1 << 5; +static constexpr uint8_t sLOCALDECISION = 1 << 4; +static constexpr uint8_t sACTIVE = 1 << 3; +static constexpr uint8_t sREJECTING = 1 << 2; +static constexpr uint8_t sMASKED = 1 << 1; +static constexpr uint8_t sOVERWRITTEN = 1; + +static constexpr uint8_t sSOX = 1 << 7; +static constexpr uint8_t sEOX = 1 << 6; +static constexpr uint8_t sPAUSE = 1 << 5; +static constexpr uint8_t sRESUME = 1 << 4; +static constexpr uint8_t sCALIBRATE = 1 << 3; +static constexpr uint8_t sPHY = 1 << 2; +static constexpr uint8_t sRESET = 1 << 1; +static constexpr uint8_t sORB = 1; + +/// Tests the local card bit +inline bool isLoc(uint8_t statusWord) { return (statusWord >> 6) & 0x1; } +/// Tests the calibration bit of the card +inline bool isCalibration(uint8_t triggerWord) { return ((triggerWord & 0xc) == 0x8); } +/// Tests if this is a Front End Test event +inline bool isFET(uint8_t triggerWord) { return ((triggerWord & 0xc) == 0xc); } +/// Gets the crate ID from the absolute local board ID +inline uint8_t getCrateId(uint8_t uniqueLocId) { return (uniqueLocId >> 4) & 0xF; } +/// Gets the loc ID in the crate from the unique local board ID +inline uint8_t getLocId(uint8_t uniqueLocId) { return uniqueLocId & 0xF; } +/// Builds the unique loc ID from the crate ID and the loc ID in the crate +inline uint8_t makeUniqueLocID(uint8_t crateId, uint8_t locId) { return locId | (crateId << 4); } +} // namespace raw + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_ROBOARD_H */ diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROFRecord.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROFRecord.h index 368fc3173126c..6f3d0396339b7 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROFRecord.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROFRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,9 +26,10 @@ namespace mid enum class EventType { Standard = 0, - Noise = 1, - Dead = 2 + Calib = 1, + FET = 2 }; +constexpr uint32_t NEvTypes = 3; /// ROFRecord class encodes the trigger interaction record of given ROF and /// the reference on the 1st object (digit, cluster etc) of this ROF in the data tree @@ -40,6 +42,7 @@ struct ROFRecord { ROFRecord() = default; ROFRecord(const o2::InteractionRecord& intRecord, const EventType& evtType, size_t first, size_t nElements) : interactionRecord(intRecord), eventType(evtType), firstEntry(first), nEntries(nElements) {} ROFRecord(const ROFRecord& other, size_t first, size_t nElements) : interactionRecord(other.interactionRecord), eventType(other.eventType), firstEntry(first), nEntries(nElements) {} + size_t getEndIndex() const { return firstEntry + nEntries; } ClassDefNV(ROFRecord, 1); }; diff --git a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Track.h b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Track.h index 0e5a91ca92c4d..5f4fa508ddd3f 100644 --- a/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Track.h +++ b/DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Track.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,8 @@ #include <array> #include <ostream> +#include "Rtypes.h" + namespace o2 { namespace mid @@ -96,6 +99,8 @@ class Track std::array<int, 4> mClusterMatched = {}; ///< Matched cluster index float mChi2 = 0.; ///< Chi2 of track int mNDF = 0; ///< Number of chi2 degrees of freedom + + ClassDefNV(Track, 1); }; } // namespace mid } // namespace o2 diff --git a/DataFormats/Detectors/MUON/MID/src/CTF.cxx b/DataFormats/Detectors/MUON/MID/src/CTF.cxx index 9e3bdccc1f992..3f13cf7982dc9 100644 --- a/DataFormats/Detectors/MUON/MID/src/CTF.cxx +++ b/DataFormats/Detectors/MUON/MID/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/MUON/MID/src/ColumnData.cxx b/DataFormats/Detectors/MUON/MID/src/ColumnData.cxx index d0240c259b1d7..f5aebadde547b 100644 --- a/DataFormats/Detectors/MUON/MID/src/ColumnData.cxx +++ b/DataFormats/Detectors/MUON/MID/src/ColumnData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -51,6 +52,38 @@ bool ColumnData::isStripFired(int istrip, int cathode, int line) const return (cathode == 0) ? isBPStripFired(istrip, line) : isNBPStripFired(istrip); } +bool ColumnData::isEmpty() const +{ + /// Checks if the data is empty + /// Returns true if all patterns are 0 + if (patterns[4]) { + return false; + } + for (int iline = 0; iline < 4; ++iline) { + if (patterns[iline]) { + return false; + } + } + return true; +} + +bool ColumnData::operator==(const ColumnData& right) const +{ + /// Comparison operator + if (deId != right.deId) { + return false; + } + if (columnId != right.columnId) { + return false; + } + for (size_t ipat = 0; ipat < 5; ++ipat) { + if (patterns[ipat] != right.patterns[ipat]) { + return false; + } + } + return true; +} + ColumnData& operator|=(ColumnData& col1, const ColumnData& col2) { /// Merge operator for ColumnData diff --git a/DataFormats/Detectors/MUON/MID/src/DataFormatsMIDLinkDef.h b/DataFormats/Detectors/MUON/MID/src/DataFormatsMIDLinkDef.h index a4986e7abc4c8..302ad915fcb5f 100644 --- a/DataFormats/Detectors/MUON/MID/src/DataFormatsMIDLinkDef.h +++ b/DataFormats/Detectors/MUON/MID/src/DataFormatsMIDLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,12 +16,15 @@ #pragma link off all functions; #pragma link C++ struct o2::mid::Cluster2D + ; +#pragma link C++ class std::vector < o2::mid::Cluster2D> + ; #pragma link C++ struct o2::mid::Cluster3D + ; +#pragma link C++ class std::vector < o2::mid::Cluster3D> + ; #pragma link C++ struct o2::mid::ColumnData + ; // This is needed for the derived classes -#pragma link C++ class std::vector < o2::mid::ColumnData > +; // This is needed for the derived classes +#pragma link C++ class std::vector < o2::mid::ColumnData> + ; // This is needed for the derived classes #pragma link C++ struct o2::mid::ROFRecord + ; -#pragma link C++ class std::vector < o2::mid::ROFRecord > +; +#pragma link C++ class std::vector < o2::mid::ROFRecord> + ; #pragma link C++ struct o2::mid::Track + ; +#pragma link C++ class std::vector < o2::mid::Track> + ; #pragma link C++ struct o2::mid::CTFHeader + ; #pragma link C++ struct o2::mid::CTF + ; diff --git a/DataFormats/Detectors/MUON/MID/src/ROBoard.cxx b/DataFormats/Detectors/MUON/MID/src/ROBoard.cxx new file mode 100644 index 0000000000000..9312a13eac3fb --- /dev/null +++ b/DataFormats/Detectors/MUON/MID/src/ROBoard.cxx @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Raw/src/ROBoard.cxx +/// \brief Structure to store the readout board information +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 19 November 2019 + +#include "DataFormatsMID/ROBoard.h" + +#include <iostream> +#include "fmt/format.h" + +namespace o2 +{ +namespace mid +{ +std::ostream& operator<<(std::ostream& os, const ROBoard& loc) +{ + /// Stream operator for ROBoard + os << fmt::format("Crate ID: {:2d} {} ID: {:2d} status: 0x{:2x} trig: 0x{:2x} fired: 0x{:1x}", static_cast<int>(raw::getCrateId(loc.boardId)), (raw::isLoc(loc.statusWord) ? "Loc" : "Reg"), static_cast<int>(raw::getLocId(loc.boardId)), static_cast<int>(loc.statusWord), static_cast<int>(loc.triggerWord), static_cast<int>(loc.firedChambers)); + for (int ich = 0; ich < 4; ++ich) { + os << fmt::format(" X: 0x{:4x} Y: 0x{:4x}", loc.patternsBP[ich], loc.patternsNBP[ich]); + } + return os; +} + +} // namespace mid +} // namespace o2 \ No newline at end of file diff --git a/DataFormats/Detectors/MUON/MID/src/Track.cxx b/DataFormats/Detectors/MUON/MID/src/Track.cxx index c20392de12387..4c89f26c7546a 100644 --- a/DataFormats/Detectors/MUON/MID/src/Track.cxx +++ b/DataFormats/Detectors/MUON/MID/src/Track.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/CMakeLists.txt b/DataFormats/Detectors/PHOS/CMakeLists.txt index e38d682a52a4f..6361a3fd2e0a2 100644 --- a/DataFormats/Detectors/PHOS/CMakeLists.txt +++ b/DataFormats/Detectors/PHOS/CMakeLists.txt @@ -1,25 +1,32 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsPHOS - SOURCES src/PHOSBlockHeader.cxx - src/Cell.cxx - src/Digit.cxx - src/Cluster.cxx - src/MCLabel.cxx + SOURCES src/PHOSBlockHeader.cxx + src/Cell.cxx + src/Digit.cxx + src/Cluster.cxx + src/MCLabel.cxx src/TriggerRecord.cxx - PUBLIC_LINK_LIBRARIES O2::CommonDataFormat - O2::Headers - O2::MathUtils - O2::DetectorsBase - O2::PHOSBase + src/CTF.cxx + src/BadChannelsMap.cxx + src/CalibParams.cxx + src/Pedestals.cxx + src/TriggerMap.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::Headers + O2::CCDB + O2::MathUtils + O2::DetectorsBase + O2::PHOSBase O2::SimulationDataFormat Boost::serialization) @@ -29,7 +36,12 @@ o2_target_root_dictionary(DataFormatsPHOS include/DataFormatsPHOS/Digit.h include/DataFormatsPHOS/Cluster.h include/DataFormatsPHOS/MCLabel.h - include/DataFormatsPHOS/TriggerRecord.h) + include/DataFormatsPHOS/TriggerRecord.h + include/DataFormatsPHOS/CTF.h + include/DataFormatsPHOS/BadChannelsMap.h + include/DataFormatsPHOS/CalibParams.h + include/DataFormatsPHOS/Pedestals.h + include/DataFormatsPHOS/TriggerMap.h) o2_add_test(Cell SOURCES test/testCell.cxx COMPONENT_NAME DataFormats-PHOS diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/BadChannelsMap.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/BadChannelsMap.h new file mode 100644 index 0000000000000..f76d689bcbb65 --- /dev/null +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/BadChannelsMap.h @@ -0,0 +1,145 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_PHOS_PHOSBADCHANNELSMAP_H_ +#define O2_PHOS_PHOSBADCHANNELSMAP_H_ + +#include <iosfwd> +#include <bitset> +#include <Rtypes.h> + +class TH2; + +namespace o2 +{ + +namespace phos +{ + +/// \class BadChannelsMap +/// \brief CCDB container for bad (masked) channels in PHOS +/// \author Dmitri Peresunko, adopted from EMCAL (Markus Fasel) +/// \since Aug. 1, 2019 +/// +/// # The PHOS Bad Channel Map +/// +/// The bad channel map contains channels which are marked to be +/// bad and excluded from reonstruction: clusterization +/// or other analysis processes. +/// +/// Bad channels can be added via +/// bcm.addBadChannel(1234); +/// goodness of channel can be restored with +/// bcm.setChannelGood(1234) ; +/// +/// Reading the channel status is done via +/// bool status = bcm.isChannelGood(1234); +/// Calling isChannelGood for cells beyond PHOS +/// will return the status bad. +/// +/// For visualization a 2D histogram with the cell status as function of x(phi) vs z +/// for each module can be created on the fly from the bad channel map. As the histogram is +/// created dynamically from the absolute cell ID an instance of the PHOS Geometry +/// is required - otherwise an empty histogram is created. +/// +/// The bad channel map can be created from multiple bad channel +/// maps using the operator +=. This allows for the combination +/// of the bad channel map from multiple time slices. +class BadChannelsMap +{ + public: + /// \brief Constructor + BadChannelsMap() = default; + + /// \brief Constructur used to build test bad map + BadChannelsMap(int test); + + /// \brief Destructor + ~BadChannelsMap() = default; + + /// \brief Add bad channel map to this bad channel map + /// \param rhs Bad channel map to be added to this bad channel map + /// \return Reference to the combined bad channel map + /// + /// Adding bad channels of another bad channel map to this + /// bad channel map. + BadChannelsMap& operator+=(const BadChannelsMap& rhs) + { + mBadCells |= rhs.mBadCells; + return *this; + } + + /// \brief Comparison of two bad channel maps + /// \return true if the bad channel maps are identical, false otherwise + /// + /// Testing two bad channel maps for equalness. + bool operator==(const BadChannelsMap& other) const { return mBadCells == other.mBadCells; } + + /// \brief Add bad cell to the container + /// \param channelID Absolute ID of the bad channel + /// \param mask type of the bad channel + void addBadChannel(short channelID) { mBadCells.set(channelID - OFFSET); } //set bit to true + + /// \brief Mark channel as good + /// \param channelID Absolute ID of the channel + /// Setting channel as good. + void setChannelGood(short channelID) { mBadCells.set(channelID - OFFSET, false); } + + /// \brief Get the status of a certain cell + /// \param channelID channel for which to obtain the channel status + /// \return true if good channel + /// + /// Provide the mask status of a cell. + bool isChannelGood(short channelID) const { return !mBadCells.test(channelID - OFFSET); } + + /// \brief Convert map into 2D histogram representation + /// \param mod Module number + /// \param h Histogram of size 64*56 to be filled with the bad channel map. + /// + /// Convert bad channel map into a 2D map with phi(64) vs z(56) dimensions. + /// Entries in the histogram are: + /// - 0: GOOD_CELL + /// - 1: BAD_CELL + /// Attention: It is responsibility of user to create/delete histogram + void getHistogramRepresentation(char mod, TH2* h) const; + + /// \brief Print bad channels on a given stream + /// \param stream Stream on which the bad channel map is printed on + /// + /// Printing all bad channels store in the bad channel map + /// on the stream. + /// + /// The function is called in the operator<< providing direct access + /// to protected members. Explicit calls by the users is normally not + /// necessary. + void PrintStream(std::ostream& stream) const; + + private: + static constexpr short NCHANNELS = 14337; ///< Number of channels starting from 1 (4*64*56+1 + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*0.5+1 + std::bitset<NCHANNELS> mBadCells; ///< Container for bad cells, 1 means bad sell + + ClassDefNV(BadChannelsMap, 1); +}; + +/// \brief Printing bad channel map on the stream +/// \param in Stream where the bad channel map is printed on +/// \param bcm Bad channel map to be printed +/// \return Stream after printing the bad channel map +/// +/// Printing cellID of all bad channels stored in the bad channel map +/// on the stream. +std::ostream& operator<<(std::ostream& in, const BadChannelsMap& bcm); + +} // namespace phos + +} // namespace o2 + +#endif /* O2_PHOS_PHOSBADCHANNELSMAP_H_ */ diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CTF.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CTF.h new file mode 100644 index 0000000000000..87d51f5194234 --- /dev/null +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CTF.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for PHOS CTF data + +#ifndef O2_PHS_CTF_H +#define O2_PHS_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/Cell.h" + +namespace o2 +{ +namespace phos +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t nCells = 0; /// number of referred cells + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded triggers and cells of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 7, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_entriesTrig, + BLC_packedID, + BLC_time, + BLC_energy, + BLC_status + }; + ClassDefNV(CTF, 1); +}; + +} // namespace phos +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CalibParams.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CalibParams.h new file mode 100644 index 0000000000000..5870a0966dae6 --- /dev/null +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/CalibParams.h @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class CalibParams +/// \brief CCDB container for the full set of PHOS calibration coefficients +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Aug. 1, 2019 +/// +/// + +#ifndef PHOS_CALIBPARAMS_H +#define PHOS_CALIBPARAMS_H + +#include <array> +#include "TObject.h" + +class TH2; + +namespace o2 +{ + +namespace phos +{ + +class CalibParams +{ + public: + /// \brief Constructor + CalibParams() = default; + + /// \brief Constructor for tests + CalibParams(int test); + + CalibParams& operator=(const CalibParams& other) = default; + + /// \brief Destructor + ~CalibParams() = default; + + /// \brief Get High Gain energy calibration coefficients + /// \param cellID Absolute ID of cell + /// \return high gain energy calibration coefficient of the cell + float getGain(short cellID) const { return mGainCalib.at(cellID - OFFSET); } + + /// \brief Set High Gain energy calibration coefficient + /// \param cellID Absolute ID of cell + /// \param c is the calibration coefficient + void setGain(short cellID, float c) { mGainCalib.at(cellID - OFFSET) = c; } + + /// \brief Set High Gain energy calibration coefficients for one module in the form of 2D histogram + /// \param 2D(64,56) histogram with calibration coefficients + /// \param module number + /// \return Is successful + bool setGain(TH2* h, char module); + + /// \brief Get High Gain to Low Gain ratio calibration coefficients + /// \param cellID Absolute ID of cell + /// \return High Gain to Low Gain ratio of the cell + float getHGLGRatio(short cellID) const { return mHGLGRatio.at(cellID - OFFSET); } + + /// \brief Set High Gain to Low Gain ratio + /// \param cellID Absolute ID of cell + /// \param r is the calibration coefficient + void setHGLGRatio(short cellID, float r) { mHGLGRatio.at(cellID - OFFSET) = r; } + + /// \brief Set High Gain to Low Gain ratio for one module in the form of 2D histogram + /// \param 2D(64,56) histogram with High Gain to Low Gain ratio + /// \param module number + /// \return Is successful + bool setHGLGRatio(TH2* h, char module); + + /// \brief Get High Gain time calibration coefficients + /// \param cellID Absolute ID of cell + /// \return high gain time calibration coefficient of the cell + float getHGTimeCalib(short cellID) const { return mHGTimeCalib.at(cellID - OFFSET); } + + /// \brief Set High Gain time calibration coefficient + /// \param cellID Absolute ID of cell + /// \param t is the calibration coefficient + void setHGTimeCalib(short cellID, float t) { mHGTimeCalib.at(cellID - OFFSET) = t; } + + /// \brief Set High Gain time calibration coefficients for one module in the form of 2D histogram + /// \param 2D(64,56) histogram with calibration coefficients + /// \param module number + /// \return Is successful + bool setHGTimeCalib(TH2* h, char module); + + /// \brief Get Low Gain time calibration coefficient + /// \param cellID Absolute ID of cell + /// \return low gain time calibration coefficient of the cell + float getLGTimeCalib(short cellID) const { return mLGTimeCalib.at(cellID - OFFSET); } + + /// \brief Set time calibration coefficient + /// \param cellID Absolute ID of cell + /// \param t is the calibration coefficient + void setLGTimeCalib(short cellID, float t) { mLGTimeCalib.at(cellID - OFFSET) = t; } + + /// \brief Set Low Gain time calibration coefficients for one module in the form of 2D histogram + /// \param 2D(64,56) histogram with calibration coefficients + /// \param module number + /// \return Is successful + bool setLGTimeCalib(TH2* h, char module); + + private: + static constexpr short NCHANNELS = 12544; ///< Number of channels = 14336-1792 + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*0.5+1 + std::array<float, NCHANNELS> mGainCalib; ///< Container for the gain calibration coefficients + std::array<float, NCHANNELS> mHGLGRatio; ///< Container for the High Gain to Low Gain ratios + std::array<float, NCHANNELS> mHGTimeCalib; ///< Container for the High Gain time calibration coefficients + std::array<float, NCHANNELS> mLGTimeCalib; ///< Container for the Low Gain time calibration coefficients + + ClassDefNV(CalibParams, 1); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cell.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cell.h index 6069a6e1b2fc1..37c67cb89aef4 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cell.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cell.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,24 +17,25 @@ // Structure: // Bits 39: Cell type: 0=Low Gain, 1=High Gain -// Bits 24-38: Energy (input/output in GeV/c^2, resolution 1 ADC count) -// Bits 14-23: Time (ns) -// Bits 0-13: Address: absID or TRU address +// Bits 27-38: 12 bit, Amplitude (HG, resolution 0.25 ADC count, LG resolution 1 ADC count, dynamic range 4096) +// Bits 14-26: 13 bit, Time (ns) +// Bits 0-13: 14 bit, Address: absID or TRU address namespace o2 { namespace phos { -constexpr int kNmaxCell = 12545; //56*64*3.5 + 1 -constexpr float kEnergyConv = 0.005; //Energy digitization step -constexpr float kTimeAccuracy = 0.3e-9; //Time digitization step -constexpr float kTime0 = 150.e-9; //-Minimal time to be digitized +constexpr int kOffset = 1792; // offset due to missing half of module 1: 56*32 +constexpr int kNmaxCell = 14337; //56*64*4 + 1 - kOffset +constexpr float kTimeAccuracy = 0.25e-9; //Time digitization step +constexpr float kTime0 = -500.e-9; //Minimal time to be digitized with 13 bits -500,1548 ns enum ChannelType_t { - HIGH_GAIN, ///< High gain channel LOW_GAIN, ///< Low gain channel - TRU ///< TRU channel + HIGH_GAIN, ///< High gain channel + TRU2x2, ///< TRU channel, 2x2 trigger + TRU4x4 ///< TRU channel, 4x4 trigger }; class Cell @@ -46,12 +48,13 @@ class Cell void setAbsId(short absId); short getAbsId() const; - void setTRUId(short truId); + //return pure TRUid (absId with subtracted readout channels offset) short getTRUId() const; void setTime(float time); float getTime() const; + //make sure that type of Cell (HG/LG) set before filling energy: scale will be different! void setEnergy(float energy); float getEnergy() const; @@ -71,6 +74,24 @@ class Cell void PrintStream(std::ostream& stream) const; + // raw access for CTF encoding + uint16_t getPackedID() const { return getLong() & 0x3fff; } + void setPackedID(uint16_t v) { mBits = (getLong() & 0xffffffc000) + (v & 0x3fff); } + + uint16_t getPackedTime() const { return (getLong() >> 14) & 0x1fff; } + void setPackedTime(uint16_t v) { mBits = (getLong() & 0xfff8003fff) + (uint64_t(v & 0x1fff) << 14); } + + uint16_t getPackedEnergy() const { return (getLong() >> 27) & 0xfff; } + void setPackedEnergy(uint16_t v) { mBits = (getLong() & 0x8007ffffff) + (uint64_t(v & 0xfff) << 27); } + + uint8_t getPackedCellStatus() const { return mBits[39]; } + void setPackedCellStatus(uint8_t v) { mBits[39] = v ? true : false; } + + void setPacked(uint16_t id, uint16_t t, uint16_t en, uint16_t status) + { + mBits = uint64_t(id & 0x3fff) + (uint64_t(t & 0x1fff) << 14) + (uint64_t(en & 0xfff) << 27) + (uint64_t(status & 0x1) << 39); + } + private: std::bitset<40> mBits; diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cluster.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cluster.h index a843b230af88c..c9969ca12e4d9 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cluster.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,8 +11,8 @@ #ifndef ALICEO2_PHOS_CLUSTER_H_ #define ALICEO2_PHOS_CLUSTER_H_ - -#include "DataFormatsPHOS/Digit.h" +#include <vector> +#include <Rtypes.h> namespace o2 { @@ -21,6 +22,19 @@ class Geometry; /// \class Cluster /// \brief Contains PHOS cluster parameters +struct CluElement { + short absId = 0; + bool isHG = false; + int label = -1; + float energy = 0.; + float time = 0.; + float localX = 0.; + float localZ = 0.; + float fraction = 0.; + CluElement() = default; + CluElement(short a, bool hg, float e, float t, float x, float z, int lab, float fr) : absId(a), isHG(hg), energy(e), time(t), localX(x), localZ(z), label(lab), fraction(fr) {} +}; + class Cluster { @@ -39,50 +53,79 @@ class Cluster /// \return result of comparison: x and z coordinates bool operator>(const Cluster& other) const; - void setEnergy(float e) { mFullEnergy = e; } float getEnergy() const { return mFullEnergy; } + void setEnergy(float e) { mFullEnergy = e; } + float getCoreEnergy() const { return mCoreEnergy; } + void setCoreEnergy(float ec) { mCoreEnergy = ec; } + float getDispersion() const { return mDispersion; } + void setDispersion(float d) { mDispersion = d; } + float getDistanceToBadChannel() const { return mDistToBadChannel; } - void getElipsAxis(float* lambda) const + void getElipsAxis(float lambdaShort, float lambdaLong) const { - lambda[0] = mLambdaLong; - lambda[1] = mLambdaShort; + lambdaShort = mLambdaShort; + lambdaLong = mLambdaLong; + } + void setElipsAxis(float lambdaShort, float lambdaLong) + { + mLambdaShort = lambdaShort; + mLambdaLong = lambdaLong; } void getLocalPosition(float& posX, float& posZ) const { posX = mLocalPosX; posZ = mLocalPosZ; } - int getMultiplicity() const { return mMulDigit; } // gets the number of digits making this recpoint + void setLocalPosition(float posX, float posZ) + { + mLocalPosX = posX; + mLocalPosZ = posZ; + } + int getMultiplicity() const { return mLastCluElement - mFirstCluElement; } // gets the number of digits making this cluster // 0: was no unfolging, -1: unfolding failed void setNExMax(char nmax = 1) { mNExMax = nmax; } char getNExMax() const { return mNExMax; } // Number of maxima found in cluster in unfolding: // 0: was no unfolging, -1: unfolding failed - char getPHOSMod() const { return mModule; } // PHOS module of a current cluster + char module() const { return mModule; } // PHOS module of a current cluster + void setModule(char mod) { mModule = mod; } // set PHOS module of a current cluster float getTime() const { return mTime; } + void setTime(float t) { mTime = t; } - int getLabel() const { return mLabel; } //Index in MCContainer entry - void setLabel(int l) { mLabel = l; } + char firedTrigger() const { return mFiredTrigger; } + void setFiredTrigger(char t) { mFiredTrigger = t; } + + /// \brief Method to add digit to a cluster + void addDigit() { mLastCluElement++; } + + uint32_t getFirstCluEl() const { return mFirstCluElement; } + uint32_t getLastCluEl() const { return mLastCluElement; } + void setFirstCluEl(uint32_t first) { mFirstCluElement = first; } + void setLastCluEl(uint32_t last) { mLastCluElement = last; } + + // // Binary search implementation + // std::vector<Digit>::const_iterator BinarySearch(const std::vector<Digit>* container, Digit& element); protected: - char mMulDigit = 0; ///< Digit nultiplicity - char mModule = 0; ///< Module number - char mNExMax = -1; ///< number of (Ex-)maxima before unfolding - int mLabel = -1; ///< Ref to entry in MCTruthContainer with list of labels - float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) - float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) - float mFullEnergy = 0.; ///< full energy of a shower - float mCoreEnergy = 0.; ///< energy in a shower core - float mLambdaLong = 0.; ///< shower ellipse axes - float mLambdaShort = 0.; ///< shower ellipse axes - float mDispersion = 0.; ///< shower dispersion - float mTime = 0.; ///< Time of the digit with maximal energy deposition - float mDistToBadChannel = 999; ///< Distance to nearest bad crystal - - ClassDefNV(Cluster, 1); + char mModule = 0; ///< Module number + char mNExMax = -1; ///< number of (Ex-)maxima before unfolding + char mFiredTrigger = 0; ///< matched with PHOS trigger: 0 no match, bit 1 with 2x2, bit 2 with 4x4 + uint32_t mFirstCluElement = -1; ///< index of the first contributing CluElement in a list + uint32_t mLastCluElement = -1; ///< index of the last contributing CluElement in a list + float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) + float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) + float mFullEnergy = 0.; ///< full energy of a shower + float mCoreEnergy = 0.; ///< energy in a shower core + float mLambdaLong = 0.; ///< shower ellipse axes + float mLambdaShort = 0.; ///< shower ellipse axes + float mDispersion = 0.; ///< shower dispersion + float mTime = 0.; ///< Time of the digit with maximal energy deposition + float mDistToBadChannel = 999; ///< Distance to nearest bad crystal + + ClassDefNV(Cluster, 4); }; } // namespace phos } // namespace o2 diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h index 3eb61d9e5b837..c7686e272f18c 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,6 +39,10 @@ class Digit : public DigitBase /// particle in case of MC \return constructed Digit Digit(short cell, float amplitude, float time, int label); + /// \brief Contructor for TRU Digits + /// \param cell truId of a tile, amplitude energy deposited in a tile, time, triggerType 2x2 or 4x4, dummy label + Digit(short cell, float amplitude, float time, bool isTrigger2x2, int label); + /// \brief Digit constructor from Hit /// \param PHOS Hit /// \return constructed Digit @@ -92,10 +97,18 @@ class Digit : public DigitBase /// \return digit with sum of energies and longer list of primaries Digit& operator+=(const Digit& other); // + void addEnergyTime(float energy, float time); + + // true if tru and not readount digit + bool isTRU() const { return mAbsId >= NREADOUTCHANNELS; } + /// \brief Absolute sell id short getAbsId() const { return mAbsId; } void setAbsId(short cellId) { mAbsId = cellId; } + short getTRUId() const { return mAbsId - NREADOUTCHANNELS; } + void setTRUId(short cellId) { mAbsId = cellId + NREADOUTCHANNELS; } + /// \brief Energy deposited in a cell float getAmplitude() const { return mAmplitude; } void setAmplitude(float amplitude) { mAmplitude = amplitude; } @@ -108,14 +121,26 @@ class Digit : public DigitBase bool isHighGain() const { return mIsHighGain; } void setHighGain(Bool_t isHG) { mIsHighGain = isHG; } + bool is2x2Tile() { return isTRU() && isHighGain(); } + /// \brief index of entry in MCLabels array /// \return ndex of entry in MCLabels array int getLabel() const { return mLabel; } + void setLabel(int l) { mLabel = l; } + + void reset() + { + mIsHighGain = true; + mAbsId = 0; + mLabel = -1; + mAmplitude = 0; + mTime = 0; + } void PrintStream(std::ostream& stream) const; private: - // friend class boost::serialization::access; + static constexpr short NREADOUTCHANNELS = 14337; ///< Number of channels starting from 1 bool mIsHighGain = true; ///< High Gain or Low Gain channel (for calibration) short mAbsId = 0; ///< cell index (absolute cell ID) diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/MCLabel.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/MCLabel.h index cb0f51e912567..a9aaa30243c0a 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/MCLabel.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/PHOSBlockHeader.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/PHOSBlockHeader.h index dc7e514efa351..8a28477c7d74e 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/PHOSBlockHeader.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/PHOSBlockHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Pedestals.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Pedestals.h new file mode 100644 index 0000000000000..bcb991c79f7ec --- /dev/null +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Pedestals.h @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class Pedestals +/// \brief CCDB container for the full set of PHOS calibration coefficients +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Aug. 1, 2019 +/// +/// + +#ifndef PHOS_PEDESTALS_H +#define PHOS_PEDESTALS_H + +#include <array> +#include "TObject.h" + +class TH1; + +namespace o2 +{ + +namespace phos +{ + +class Pedestals +{ + public: + //numbering of PHOS channels described in Geometry, repeat it here + // module numbering: + // start from module 0 (non-existing), 1 (half-module), 2 (bottom),... 4(highest) + // absId: + // start from 1 till 5*64*56 =14336. Numbering in each module starts at bottom left and first go in z direction: + // 56 112 3584 + // ... ... ... + // 1 57 ...3529 + // relid[3]: (module number[0...4], iphi[1...64], iz[1...56]) + + /// \brief Constructor + Pedestals() = default; + + /// \brief Constructor for tests + Pedestals(int test); + + Pedestals& operator=(const Pedestals& other) = default; + + /// \brief Destructor + ~Pedestals() = default; + + /// \brief Get pedestal + /// \param cellID Absolute ID of cell + /// \return pedestal for the cell + short getHGPedestal(short cellID) const { return short(mHGPedestals[cellID - OFFSET]); } + + /// \brief Set pedestal + /// \param cellID Absolute ID of cell + /// \param c is the pedestal (expected to be in range <254) + void setHGPedestal(short cellID, short c) { mHGPedestals[cellID - OFFSET] = static_cast<unsigned char>(c); } + + /// \brief Get pedestal + /// \param cellID Absolute ID of cell + /// \return pedestal for the cell + short getLGPedestal(short cellID) const { return short(mLGPedestals[cellID - OFFSET]); } + + /// \brief Set pedestal + /// \param cellID Absolute ID of cell + /// \param c is the pedestal (expected to be in range <254) + void setLGPedestal(short cellID, short c) { mLGPedestals[cellID - OFFSET] = static_cast<unsigned char>(c); } + + /// \brief Set pedestals from 1D histogram with cell absId in x axis + /// \param 1D(NCHANNELS) histogram with calibration coefficients + /// \return Is successful + bool setHGPedestals(TH1* h); + + /// \brief Set pedestals from 1D histogram with cell absId in x axis + /// \param 1D(NCHANNELS) histogram with calibration coefficients + /// \return Is successful + bool setLGPedestals(TH1* h); + + /// \brief Get pedestal RMS + /// \param cellID Absolute ID of cell + /// \return pedestal RMS for the cell + float getHGRMS(short cellID) const { return float(mHGRMS[cellID - OFFSET]) / RMSCOMPRESS; } + + /// \brief Set pedestal RMS + /// \param cellID Absolute ID of cell + /// \param c is the pedestal RMS (expected to be in range 0..5, larger values=bad channel=overflow) + void setHGRMS(short cellID, float c) { mHGRMS[cellID - OFFSET] = static_cast<unsigned char>(c * RMSCOMPRESS); } + + /// \brief Get pedestal + /// \param cellID Absolute ID of cell + /// \return pedestal RMS for the LG cell + float getLGRMS(short cellID) const { return float(mLGRMS[cellID - OFFSET]) / RMSCOMPRESS; } + + /// \brief Set LG pedestal RMS + /// \param cellID Absolute ID of cell + /// \param c is the pedestal RMS (expected to be in range 0..5, larger values=bad channel=overflow) + void setLGRMS(short cellID, float c) { mLGRMS[cellID - OFFSET] = static_cast<unsigned char>(c * RMSCOMPRESS); } + + private: + static constexpr short NCHANNELS = 12544; ///< Number of channels = 14336-1792 + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*1.5+1 + static constexpr short RMSCOMPRESS = 50; ///< Conversion to store float RMS in range ~[0..5] in uchar + std::array<unsigned char, NCHANNELS> mHGPedestals; ///< Container for HG pedestals + std::array<unsigned char, NCHANNELS> mLGPedestals; ///< Container for LG pedestals + std::array<unsigned char, NCHANNELS> mHGRMS; ///< Container for RMS of HG pedestals + std::array<unsigned char, NCHANNELS> mLGRMS; ///< Container for RMS of LG pedestals + + ClassDefNV(Pedestals, 3); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerMap.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerMap.h new file mode 100644 index 0000000000000..61e7ef1cf1711 --- /dev/null +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerMap.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class TRIGGERMAP +/// \brief CCDB container for trigger bad map and turn-on curves +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since March 20, 2021 +/// +/// + +#ifndef PHOS_TRIGGERMAP_H +#define PHOS_TRIGGERMAP_H + +#include <array> +#include <bitset> +#include "TObject.h" + +class TH1; + +namespace o2 +{ + +namespace phos +{ + +class TriggerMap +{ + public: + /// \brief Constructor + TriggerMap() = default; + + /// \brief Constructor for tests + TriggerMap(int test); + + TriggerMap& operator=(const TriggerMap& other) = default; + + /// \brief Destructor + ~TriggerMap() = default; + + /// \brief tests if cell is in active trigger region + /// \param cellID Absolute ID of cell + /// \return true if cell is in active trigger region + bool isGood2x2(short cellID) const { return !mTrigger2x2Map.test(cellID); } + + /// \brief Add bad triger cell to the container + /// \param cellID Absolute ID of the bad channel + void addBad2x2Channel(short cellID) { mTrigger2x2Map.set(cellID); } //set bit to true + + /// \brief Mark trigger channel as good + /// \param cellID Absolute ID of the channel + void set2x2ChannelGood(short cellID) { mTrigger2x2Map.set(cellID, false); } + + /// \brief tests if cell is in active trigger region + /// \param cellID Absolute ID of cell + /// \return true if cell is in active trigger region + bool isGood4x4(short cellID) const { return !mTrigger4x4Map.test(cellID); } + + /// \brief Add bad triger cell to the container + /// \param cellID Absolute ID of the bad channel + void addBad4x4Channel(short cellID) { mTrigger4x4Map.set(cellID); } //set bit to true + + /// \brief Mark trigger channel as good + /// \param cellID Absolute ID of the channel + void set4x4ChannelGood(short cellID) { mTrigger2x2Map.set(cellID, false); } + + void setTurnOnCurvesVestion(int v = 0); + + /// \brief random return true with probability to fire trigger + /// \param a amplitude of trigger tile + /// \param iTRU,ix,iz coordinates of trigger tile + bool isFiredMC2x2(float a, short iTRU, short ix, short iz) const; + + /// \brief random return true with probability to fire trigger + /// \param a amplitude of trigger tile + /// \param iTRU,ix,iz coordinates of trigger tile + bool isFiredMC4x4(float a, short iTRU, short ix, short iz) const; + + bool try2x2(float a, short iTRU) const; + bool try4x4(float a, short iTRU) const; + + void addTurnOnCurvesParams(std::string_view versionName, std::array<std::array<float, 10>, 14>& params); + bool selectTurnOnCurvesParams(std::string_view versionName); + + float L0triggerProbability(float e, short ddl) const; + + private: + static constexpr short NCHANNELS = 3136; ///< Number of trigger channels + std::bitset<NCHANNELS> mTrigger2x2Map; ///< Container for bad trigger cells, 1 means bad sell + std::bitset<NCHANNELS> mTrigger4x4Map; ///< Container for bad trigger cells, 1 means bad sell + + short mVersion; //current parameterization of turn-on curves + static constexpr short NDDL = 14; ///< Non-existing channels 56*64*1.5+1 + static constexpr short NMAXPAR = 10; ///< Non-existing channels 56*64*1.5+1 + std::vector<std::string> mParamDescr; ///< Names of available parameterizations + std::vector<std::array<std::array<float, NMAXPAR>, NDDL>> mParamSets; + std::array<std::array<float, NMAXPAR>, NDDL> mCurrentSet; + + ClassDefNV(TriggerMap, 1); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerRecord.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerRecord.h index e936124af7f57..72e473202a853 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerRecord.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/TriggerRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/src/BadChannelsMap.cxx b/DataFormats/Detectors/PHOS/src/BadChannelsMap.cxx new file mode 100644 index 0000000000000..5202a79f002d8 --- /dev/null +++ b/DataFormats/Detectors/PHOS/src/BadChannelsMap.cxx @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSBase/Geometry.h" +#include "DataFormatsPHOS/BadChannelsMap.h" + +#include "FairLogger.h" + +#include <TH2.h> + +#include <iostream> + +using namespace o2::phos; + +BadChannelsMap::BadChannelsMap(int /*dummy*/) +{ + + //Mark few channels as bad for test peurposes + for (short i = 0; i < 56; i++) { + //module 2 + short channelID = 3584 + i * 57; + mBadCells.set(channelID - OFFSET); + channelID = 3640 + i * 55; + mBadCells.set(channelID - OFFSET); + } + + for (short i = 0; i < 16; i++) { + //module 3 + int channelID = 8972 + i * 57; + mBadCells.set(channelID - OFFSET); + channelID = 8092 + i * 57; + mBadCells.set(channelID - OFFSET); + channelID = 8147 + i * 55; + mBadCells.set(channelID - OFFSET); + channelID = 9059 + i * 55; + mBadCells.set(channelID - OFFSET); + } +} + +void BadChannelsMap::getHistogramRepresentation(char module, TH2* h) const +{ + const char MAXX = 64, + MAXZ = 56; + if (module < 1 || module > 4) { + LOG(ERROR) << "module " << module << "does not exist"; + return; + } + if (!h) { + LOG(ERROR) << "provide histogram to be filled"; + } + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return; + } + + h->Reset(); + char relid[3] = {module, 1, 1}; + short absId; + for (char ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (char iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + if (o2::phos::Geometry::relToAbsNumbering(relid, absId)) { + if (!isChannelGood(absId)) { + h->SetBinContent(ix, iz, 1); + } + } + } + } +} + +void BadChannelsMap::PrintStream(std::ostream& stream) const +{ + // first sort bad channel IDs + stream << "Number of bad cells: " << mBadCells.count() << "\n"; + for (int cellID = 0; cellID < mBadCells.size(); cellID++) { + if (mBadCells.test(cellID)) { + stream << cellID + OFFSET << "\n"; + } + } +} + +std::ostream& o2::phos::operator<<(std::ostream& stream, const BadChannelsMap& bcm) +{ + bcm.PrintStream(stream); + return stream; +} diff --git a/DataFormats/Detectors/PHOS/src/CTF.cxx b/DataFormats/Detectors/PHOS/src/CTF.cxx new file mode 100644 index 0000000000000..77a38978470a9 --- /dev/null +++ b/DataFormats/Detectors/PHOS/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsPHOS/CTF.h" + +using namespace o2::phos; diff --git a/DataFormats/Detectors/PHOS/src/CalibParams.cxx b/DataFormats/Detectors/PHOS/src/CalibParams.cxx new file mode 100644 index 0000000000000..b8707cfb548ad --- /dev/null +++ b/DataFormats/Detectors/PHOS/src/CalibParams.cxx @@ -0,0 +1,175 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsPHOS/CalibParams.h" +#include "PHOSBase/Geometry.h" + +#include "FairLogger.h" + +#include <TH2.h> + +#include <iostream> + +using namespace o2::phos; + +CalibParams::CalibParams(int /*dummy*/) +{ + //produce reasonable objest for test purposes + mGainCalib.fill(0.005); + mHGLGRatio.fill(16.); + mHGTimeCalib.fill(0.); + mLGTimeCalib.fill(0.); +} + +bool CalibParams::setGain(TH2* h, char module) +{ + const char MAXX = 64, + MAXZ = 56; + if (module < 1 || module > 4) { + LOG(ERROR) << "module " << module << "does not exist"; + return false; + } + + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return false; + } + + char relid[3] = {module, 1, 1}; + short absId; + for (char ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (char iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + + if (o2::phos::Geometry::relToAbsNumbering(relid, absId)) { + if (absId - OFFSET < 0) { //non-existing part of a module 1 + continue; + } + mGainCalib[absId - OFFSET] = h->GetBinContent(ix, iz); + } + } + } + return true; +} + +bool CalibParams::setHGLGRatio(TH2* h, char module) +{ + const char MAXX = 64, + MAXZ = 56; + if (module < 1 || module > 4) { + LOG(ERROR) << "module " << module << "does not exist"; + return false; + } + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return false; + } + + char relid[3] = {module, 1, 1}; + short absId; + for (char ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (char iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + + if (o2::phos::Geometry::relToAbsNumbering(relid, absId)) { + if (absId - OFFSET < 0) { //non-existing part of a module 1 + continue; + } + mHGLGRatio[absId - OFFSET] = h->GetBinContent(ix, iz); + } + } + } + return true; +} + +bool CalibParams::setHGTimeCalib(TH2* h, char module) +{ + const char MAXX = 64, + MAXZ = 56; + if (module < 1 || module > 4) { + LOG(ERROR) << "module " << module << "does not exist"; + return false; + } + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return false; + } + + char relid[3] = {module, 1, 1}; + short absId; + for (char ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (char iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + + if (o2::phos::Geometry::relToAbsNumbering(relid, absId)) { + if (absId - OFFSET < 0) { //non-existing part of a module 1 + continue; + } + mHGTimeCalib[absId - OFFSET] = h->GetBinContent(ix, iz); + } + } + } + return true; +} + +bool CalibParams::setLGTimeCalib(TH2* h, char module) +{ + const char MAXX = 64, + MAXZ = 56; + if (module < 1 || module > 4) { + LOG(ERROR) << "module " << module << "does not exist"; + return false; + } + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; + return false; + } + + char relid[3] = {module, 1, 1}; + short absId; + for (char ix = 1; ix <= MAXX; ix++) { + relid[1] = ix; + for (char iz = 1; iz <= MAXZ; iz++) { + relid[2] = iz; + + if (o2::phos::Geometry::relToAbsNumbering(relid, absId)) { + if (absId - OFFSET < 0) { //non-existing part of a module 1 + continue; + } + mLGTimeCalib[absId - OFFSET] = h->GetBinContent(ix, iz); + } + } + } + return true; +} diff --git a/DataFormats/Detectors/PHOS/src/Cell.cxx b/DataFormats/Detectors/PHOS/src/Cell.cxx index cebcb4f001a62..7a6bbb76000f9 100644 --- a/DataFormats/Detectors/PHOS/src/Cell.cxx +++ b/DataFormats/Detectors/PHOS/src/Cell.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,50 +16,34 @@ using namespace o2::phos; // split 40 bits as following: -// 14 bits: address, normal cells. starting from NmaxCell=3.5*56*64+1=12 544 will be TRU cells (3 136 addresses) +// 14 bits: address, normal cells. starting from NmaxCell=3.5*56*64+1=14 337 will be TRU cells (3 136 addresses) // 10 bits: time // 15 bits: Energy // 1 bit: High/low gain Cell::Cell(short absId, float energy, float time, ChannelType_t ctype) { - if (ctype == ChannelType_t::TRU) { - setTRUId(absId); - } else { - setAbsId(absId); - } + setAbsId(absId); setTime(time); - setEnergy(energy); setType(ctype); + setEnergy(energy); } void Cell::setAbsId(short absId) { //14 bits available - if (absId > kNmaxCell || absId < 0) { + if (absId < kOffset) { absId = kNmaxCell; } - ULong_t t = (ULong_t)absId; - - ULong_t b = getLong() & 0xffffffc000; // 1111 1111 1111 1111 1111 1111 1100 0000 0000 0000 - mBits = b + t; -} -void Cell::setTRUId(short absId) -{ - //14 bits available - absId += kNmaxCell + 1; - // if (absId > kNmaxCell || absId < 0) - // absId = kNmaxCell; - ULong_t t = (ULong_t)absId; + ULong_t t = (ULong_t)(absId - kOffset); ULong_t b = getLong() & 0xffffffc000; // 1111 1111 1111 1111 1111 1111 1100 0000 0000 0000 mBits = b + t; } - short Cell::getAbsId() const { ULong_t t = getLong() & 0x3fff; //14 bits - short a = (short)t; + short a = kOffset + (short)t; if (a <= kNmaxCell) { return a; } else { @@ -69,7 +54,7 @@ short Cell::getAbsId() const short Cell::getTRUId() const { ULong_t t = getLong() & 0x3fff; //14 bits - short a = (short)t; + short a = kOffset + (short)t; if (a > kNmaxCell) { return a - kNmaxCell - 1; } else { @@ -82,9 +67,9 @@ void Cell::setTime(float time) //10 bits available for time ULong_t t = 0; //Convert time to long - t = ULong_t((time + kTime0) / kTimeAccuracy); - if (t > 0x3ff) { - t = 0x3ff; + t = ULong_t((time - kTime0) / kTimeAccuracy); + if (t > 0x1fff) { + t = 0x1fff; } else { if (t < 0) { t = 0; @@ -92,46 +77,56 @@ void Cell::setTime(float time) } t <<= 14; - ULong_t b = getLong() & 0xffff003fff; // 1111 1111 1111 1111 0000 0000 0011 1111 1111 1111 + ULong_t b = getLong() & 0xfff8003fff; // 1111 1111 1111 1000 0000 0000 0011 1111 1111 1111 mBits = b + t; } - float Cell::getTime() const { ULong_t t = getLong(); t >>= 14; - t &= 0x3ff; + t &= 0x1fff; //Convert back long to float - return float(t * kTimeAccuracy) - kTime0; + return float(t * kTimeAccuracy) + kTime0; } -void Cell::setEnergy(float energy) +void Cell::setEnergy(float amp) { - //15 bits - ULong_t a = static_cast<ULong_t>(energy / kEnergyConv); - a = a & 0x7FFF; //15 bits + //12 bits + ULong_t a; + if (getType() == HIGH_GAIN) { + a = static_cast<ULong_t>(amp * 4); + } else { + a = static_cast<ULong_t>(amp); + } + a = a & 0xfff; //12 bits - a <<= 24; - ULong_t b = getLong() & 0x8000ffffff; // 1000 0000 0000 0000 1111 1111 1111 1111 1111 1111 + a <<= 27; + ULong_t b = getLong() & 0x8007ffffff; // 1000 0000 0000 0111 1111 1111 1111 1111 1111 1111 mBits = b + a; } float Cell::getEnergy() const { ULong_t a = getLong(); - a >>= 24; - a &= 0x7FFF; - return float(a * kEnergyConv); + a >>= 27; + a &= 0xfff; + if (getType() == HIGH_GAIN) { + return float(0.25 * a); + } else { + return float(a); + } } void Cell::setType(ChannelType_t ctype) { switch (ctype) { case ChannelType_t::HIGH_GAIN: + case ChannelType_t::TRU2x2: setHighGain(); break; case ChannelType_t::LOW_GAIN: + case ChannelType_t::TRU4x4: setLowGain(); break; default:; @@ -140,12 +135,19 @@ void Cell::setType(ChannelType_t ctype) ChannelType_t Cell::getType() const { - if (getHighGain()) { - return ChannelType_t::HIGH_GAIN; - } else if (getTRU()) { - return ChannelType_t::TRU; + if (getTRU()) { + if (getHighGain()) { + return ChannelType_t::TRU2x2; + } else { + return ChannelType_t::TRU4x4; + } + } else { + if (getHighGain()) { + return ChannelType_t::HIGH_GAIN; + } else { + return ChannelType_t::LOW_GAIN; + } } - return ChannelType_t::LOW_GAIN; } void Cell::setLowGain() @@ -182,7 +184,7 @@ Bool_t Cell::getTRU() const { ULong_t t = getLong(); t &= 0x3fff; //14 bits - int a = (int)t; + int a = kOffset + (int)t; return (a > kNmaxCell); //TRU addresses } diff --git a/DataFormats/Detectors/PHOS/src/Cluster.cxx b/DataFormats/Detectors/PHOS/src/Cluster.cxx index 7a5ceb413458a..32cc8f4778445 100644 --- a/DataFormats/Detectors/PHOS/src/Cluster.cxx +++ b/DataFormats/Detectors/PHOS/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,8 +22,8 @@ bool Cluster::operator<(const Cluster& other) const { // Compares two Clusters according to their position in the PHOS modules - char phosmod1 = getPHOSMod(); - char phosmod2 = other.getPHOSMod(); + char phosmod1 = module(); + char phosmod2 = other.module(); if (phosmod1 != phosmod2) { return phosmod1 < phosmod2; } @@ -47,8 +48,8 @@ bool Cluster::operator>(const Cluster& other) const { // Compares two Clusters according to their position in the PHOS modules - char phosmod1 = getPHOSMod(); - char phosmod2 = other.getPHOSMod(); + char phosmod1 = module(); + char phosmod2 = other.module(); if (phosmod1 != phosmod2) { return phosmod1 > phosmod2; } diff --git a/DataFormats/Detectors/PHOS/src/DataFormatsPHOSLinkDef.h b/DataFormats/Detectors/PHOS/src/DataFormatsPHOSLinkDef.h index d0cc6c80fb182..86e87eba56324 100644 --- a/DataFormats/Detectors/PHOS/src/DataFormatsPHOSLinkDef.h +++ b/DataFormats/Detectors/PHOS/src/DataFormatsPHOSLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,13 +21,23 @@ #pragma link C++ class o2::phos::MCLabel + ; #pragma link C++ class o2::phos::TriggerRecord + ; -#pragma link C++ class std::vector < o2::phos::Cell > +; -#pragma link C++ class std::vector < o2::phos::Digit > +; -#pragma link C++ class std::vector < o2::phos::Cluster > +; -#pragma link C++ class std::vector < o2::phos::TriggerRecord > +; +#pragma link C++ class std::vector < o2::phos::Cell> + ; +#pragma link C++ class std::vector < o2::phos::Digit> + ; +#pragma link C++ class std::vector < o2::phos::Cluster> + ; +#pragma link C++ class std::vector < o2::phos::CluElement> + ; +#pragma link C++ class std::vector < o2::phos::TriggerRecord> + ; #include "SimulationDataFormat/MCTruthContainer.h" #pragma link C++ class o2::dataformats::MCTruthContainer < o2::phos::MCLabel> + ; // For channel type in digits and cells #pragma link C++ enum o2::phos::ChannelType_t + ; +#pragma link C++ struct o2::phos::CTFHeader + ; +#pragma link C++ struct o2::phos::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::phos::CTFHeader, 7, uint32_t> + ; + +#pragma link C++ class o2::phos::BadChannelsMap + ; +#pragma link C++ class o2::phos::CalibParams + ; +#pragma link C++ class o2::phos::Pedestals + ; +#pragma link C++ class o2::phos::TriggerMap + ; + #endif diff --git a/DataFormats/Detectors/PHOS/src/Digit.cxx b/DataFormats/Detectors/PHOS/src/Digit.cxx index 794c139273510..213130c113253 100644 --- a/DataFormats/Detectors/PHOS/src/Digit.cxx +++ b/DataFormats/Detectors/PHOS/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,11 @@ Digit::Digit(short absId, float amplitude, float time, int label) : DigitBase(time), mAmplitude(amplitude), mTime(time), mAbsId(absId), mLabel(label) { } +Digit::Digit(short truId, float amplitude, float time, bool isTrigger2x2, int /*dummy*/) + : DigitBase(time), mAmplitude(amplitude), mTime(time), mAbsId(truId + NREADOUTCHANNELS), mLabel(-1) +{ + setHighGain(isTrigger2x2); +} Digit::Digit(const Hit& hit, int label) : mAbsId(hit.GetDetectorID()), mAmplitude(hit.GetEnergyLoss()), mTime(hit.GetTime()), mLabel(label) { } @@ -58,6 +64,15 @@ Digit& Digit::operator+=(const Digit& other) return *this; } +void Digit::addEnergyTime(float energy, float time) +{ + // Adds the amplitude of digits + // TODO: What about time? Should we assign time of more energetic digit? More complicated treatment? + if (mAmplitude < energy) { + mTime = time; + } + mAmplitude += energy; +} void Digit::PrintStream(std::ostream& stream) const { diff --git a/DataFormats/Detectors/PHOS/src/MCLabel.cxx b/DataFormats/Detectors/PHOS/src/MCLabel.cxx index ffb57f1bcf529..ed26982db8645 100644 --- a/DataFormats/Detectors/PHOS/src/MCLabel.cxx +++ b/DataFormats/Detectors/PHOS/src/MCLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/src/PHOSBlockHeader.cxx b/DataFormats/Detectors/PHOS/src/PHOSBlockHeader.cxx index ac2f0334b62af..46bda4b18538d 100644 --- a/DataFormats/Detectors/PHOS/src/PHOSBlockHeader.cxx +++ b/DataFormats/Detectors/PHOS/src/PHOSBlockHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/src/Pedestals.cxx b/DataFormats/Detectors/PHOS/src/Pedestals.cxx new file mode 100644 index 0000000000000..52111a2a16a6a --- /dev/null +++ b/DataFormats/Detectors/PHOS/src/Pedestals.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsPHOS/Pedestals.h" +#include "FairLogger.h" +#include <TH1.h> + +using namespace o2::phos; + +Pedestals::Pedestals(int /*dummy*/) +{ + //produce reasonable objest for test purposes + mHGPedestals.fill(40); + mLGPedestals.fill(35); +} + +bool Pedestals::setHGPedestals(TH1* h) +{ + //We assume that histogram if filled vs absId of channels + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != NCHANNELS + OFFSET) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << " instead of " << NCHANNELS + OFFSET; + return false; + } + + for (short i = 0; i < NCHANNELS; i++) { + if (h->GetBinContent(i + OFFSET) > 255) { + LOG(ERROR) << "pedestal value too large:" << h->GetBinContent(i + OFFSET) << "can not be stored in char"; + continue; + } + mHGPedestals[i] = static_cast<unsigned char>(h->GetBinContent(i + OFFSET)); + } + return true; +} +bool Pedestals::setLGPedestals(TH1* h) +{ + //We assume that histogram if filled vs absId of channels + if (!h) { + LOG(ERROR) << "no input histogam"; + return false; + } + + if (h->GetNbinsX() != NCHANNELS + OFFSET) { + LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << " instead of " << NCHANNELS + OFFSET; + return false; + } + + for (short i = 0; i < NCHANNELS; i++) { + if (h->GetBinContent(i + OFFSET) > 255) { + LOG(ERROR) << "pedestal value too large:" << h->GetBinContent(i + OFFSET) << "can not be stored in char"; + continue; + } + mLGPedestals[i] = static_cast<unsigned char>(h->GetBinContent(i + OFFSET)); + } + return true; +} diff --git a/DataFormats/Detectors/PHOS/src/TriggerMap.cxx b/DataFormats/Detectors/PHOS/src/TriggerMap.cxx new file mode 100644 index 0000000000000..9e7f889b52b7c --- /dev/null +++ b/DataFormats/Detectors/PHOS/src/TriggerMap.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSBase/Geometry.h" +#include "DataFormatsPHOS/TriggerMap.h" + +#include "FairLogger.h" + +#include <TH2.h> +#include <TRandom.h> + +#include <iostream> + +using namespace o2::phos; + +TriggerMap::TriggerMap(int param) : mVersion(param) +{ + // create default object + // empty (all channels good) bad maps and + // uniform turn-on curves for DDLs + mParamDescr.emplace_back("TestDefault"); + std::array<std::array<float, NMAXPAR>, NDDL> a; + for (int iDDL = 0; iDDL < NDDL; iDDL++) { + a[iDDL].fill(0); + a[iDDL][0] = 1.; //only one step + a[iDDL][1] = 4.; //threshold + a[iDDL][2] = 0.5; //width + } + mParamSets.emplace_back(a); + mCurrentSet = mParamSets[0]; + mVersion = 0; +} + +void TriggerMap::addTurnOnCurvesParams(std::string_view versionName, std::array<std::array<float, 10>, 14>& params) +{ + mParamDescr.emplace_back(versionName); + mParamSets.emplace_back(params); +} + +void TriggerMap::setTurnOnCurvesVestion(int v) +{ + if (v >= mParamDescr.size()) { + LOG(ERROR) << "impossible parameterization " << v; + LOG(ERROR) << "Available are:"; + for (int i = 0; i < mParamDescr.size(); i++) { + LOG(ERROR) << i << " : " << mParamDescr[i]; + } + LOG(ERROR) << " keep current " << mParamDescr[mVersion]; + return; + } + mVersion = v; + LOG(INFO) << "Will use parameterization " << mParamDescr[mVersion]; + mCurrentSet = mParamSets[mVersion]; +} + +bool TriggerMap::selectTurnOnCurvesParams(std::string_view versionName) +{ + mVersion = 0; + while (mVersion < mParamDescr.size()) { + if (versionName.compare(mParamDescr[mVersion]) == 0.) { + return true; + } + mVersion++; + } + mVersion = 0; + LOG(ERROR) << "Can not fine parameterization " << versionName; + LOG(ERROR) << "Available are:"; + for (int i = 0; i < mParamDescr.size(); i++) { + LOG(ERROR) << i << " : " << mParamDescr[i]; + } + return false; +} + +float TriggerMap::L0triggerProbability(float e, short ddl) const +{ + + if (mCurrentSet.size() == 0) { + LOG(ERROR) << "Parameteriztion not chosen"; + return 0; + } + if (mVersion == 0) { + return mCurrentSet[ddl][0] / (TMath::Exp((mCurrentSet[ddl][1] - e) / mCurrentSet[ddl][2]) + 1.) + + (1. - mCurrentSet[ddl][0]) / (TMath::Exp((mCurrentSet[ddl][3] - e) / mCurrentSet[ddl][4]) + 1.); + } else { + return 0; + } +} +bool TriggerMap::isFiredMC2x2(float a, short iTRU, short ix, short iz) const +{ + char truRelId[3] = {char(iTRU), char(ix), char(iz)}; + short tileId = Geometry::truRelToAbsNumbering(truRelId); + return isGood2x2(tileId) && try2x2(a, iTRU); +} + +bool TriggerMap::isFiredMC4x4(float a, short iTRU, short ix, short iz) const +{ + char truRelId[3] = {char(iTRU), char(ix), char(iz)}; + short tileId = Geometry::truRelToAbsNumbering(truRelId); + return isGood4x4(tileId) && try4x4(a, iTRU); +} +bool TriggerMap::try2x2(float a, short iTRU) const +{ + return gRandom->Uniform() < L0triggerProbability(a, iTRU); +} +bool TriggerMap::try4x4(float a, short iTRU) const +{ + return gRandom->Uniform() < L0triggerProbability(a, iTRU); +} diff --git a/DataFormats/Detectors/PHOS/src/TriggerRecord.cxx b/DataFormats/Detectors/PHOS/src/TriggerRecord.cxx index 3f42791d792f7..36d2b076a65c2 100644 --- a/DataFormats/Detectors/PHOS/src/TriggerRecord.cxx +++ b/DataFormats/Detectors/PHOS/src/TriggerRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/PHOS/test/testCell.cxx b/DataFormats/Detectors/PHOS/test/testCell.cxx index 2c23feca6120f..dc31bdd5ba587 100644 --- a/DataFormats/Detectors/PHOS/test/testCell.cxx +++ b/DataFormats/Detectors/PHOS/test/testCell.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,60 +30,60 @@ BOOST_AUTO_TEST_CASE(Cell_test) { Cell c; c.setTime(0.); - for (short j = 0; j < 12544; j++) { + for (short j = 1793; j < 14337; j++) { c.setAbsId(j); BOOST_CHECK_EQUAL(c.getAbsId(), j); BOOST_CHECK_EQUAL(c.getTRUId(), 0); BOOST_CHECK_SMALL(c.getTime() - float(0.), kTimeAccuracy); - BOOST_CHECK_SMALL(c.getEnergy() - 0, kEnergyConv); + BOOST_CHECK_SMALL(c.getEnergy() - 0, float(0.1)); BOOST_CHECK_EQUAL(c.getLowGain(), true); BOOST_CHECK_EQUAL(c.getTRU(), false); } for (short j = 0; j < 3136; j++) { //TRU - c.setTRUId(j); + c.setAbsId(14337 + 1 + j); BOOST_CHECK_EQUAL(c.getAbsId(), 0); BOOST_CHECK_EQUAL(c.getTRUId(), j); BOOST_CHECK_SMALL(c.getTime() - float(0.), kTimeAccuracy); - BOOST_CHECK_SMALL(c.getEnergy() - float(0), kEnergyConv); + BOOST_CHECK_SMALL(c.getEnergy() - float(0), float(0.1)); BOOST_CHECK_EQUAL(c.getTRU(), true); } - c.setAbsId(0); + c.setAbsId(1793); std::vector<float> times = {-150.e-9, -10.5e-9, -0.55e-9, 0.35e-9, 2.1e-9, 3.2e-9, 4.e-9, 5.e-9, 6.e-9, 7.e-9, 8.e-9, 9.e-9, 10.e-9, 20.e-9, 50.e-9, 100.e-9, 150.e-9}; for (float t : times) { c.setTime(t); - BOOST_CHECK_EQUAL(c.getAbsId(), 0); + BOOST_CHECK_EQUAL(c.getAbsId(), 1793); BOOST_CHECK_SMALL(c.getTime() - t, kTimeAccuracy); - BOOST_CHECK_SMALL(c.getEnergy() - float(0), kEnergyConv); + BOOST_CHECK_SMALL(c.getEnergy() - float(0), float(0.1)); BOOST_CHECK_EQUAL(c.getLowGain(), true); } c.setTime(0); - std::vector<float> energies = {0.010, 0.025, 1, 2, 5, 10, 20, 40, 60, 100, 150}; + std::vector<float> energies = {2., 5., 10., 50., 100., 200., 500., 900., 1200., 1600., 2000.}; for (float e : energies) { c.setEnergy(e); - BOOST_CHECK_EQUAL(c.getAbsId(), 0); + BOOST_CHECK_EQUAL(c.getAbsId(), 1793); BOOST_CHECK_SMALL(c.getTime() - float(0.), kTimeAccuracy); - BOOST_CHECK_SMALL(e - c.getEnergy(), kEnergyConv); // Require 5 MeV resolution + BOOST_CHECK_SMALL(e - c.getEnergy(), float(0.1)); BOOST_CHECK_EQUAL(c.getLowGain(), true); } c.setEnergy(0); c.setLowGain(); - BOOST_CHECK_EQUAL(c.getAbsId(), 0); + BOOST_CHECK_EQUAL(c.getAbsId(), 1793); BOOST_CHECK_SMALL(c.getTime() - float(0.), kTimeAccuracy); - BOOST_CHECK_SMALL(c.getEnergy() - float(0), kEnergyConv); + BOOST_CHECK_SMALL(c.getEnergy() - float(0), float(0.1)); BOOST_CHECK_EQUAL(c.getLowGain(), true); BOOST_CHECK_EQUAL(c.getHighGain(), false); BOOST_CHECK_EQUAL(c.getTRU(), false); c.setHighGain(); - BOOST_CHECK_EQUAL(c.getAbsId(), 0); + BOOST_CHECK_EQUAL(c.getAbsId(), 1793); BOOST_CHECK_SMALL(c.getTime() - float(0.), kTimeAccuracy); - BOOST_CHECK_SMALL(c.getEnergy() - float(0), kEnergyConv); + BOOST_CHECK_SMALL(c.getEnergy() - float(0), float(0.1)); BOOST_CHECK_EQUAL(c.getLowGain(), false); BOOST_CHECK_EQUAL(c.getHighGain(), true); BOOST_CHECK_EQUAL(c.getTRU(), false); diff --git a/DataFormats/Detectors/TOF/CMakeLists.txt b/DataFormats/Detectors/TOF/CMakeLists.txt index d92bfabaaed6a..487de05a283b7 100644 --- a/DataFormats/Detectors/TOF/CMakeLists.txt +++ b/DataFormats/Detectors/TOF/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsTOF SOURCES src/Cluster.cxx @@ -15,7 +16,11 @@ o2_add_library(DataFormatsTOF src/CalibLHCphaseTOF.cxx src/CalibTimeSlewingParamTOF.cxx src/CTF.cxx + src/CalibInfoCluster.cxx + src/CosmicInfo.cxx + src/Diagnostic.cxx PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats + O2::GPUCommon Boost::serialization) o2_target_root_dictionary(DataFormatsTOF @@ -27,4 +32,6 @@ o2_target_root_dictionary(DataFormatsTOF include/DataFormatsTOF/RawDataFormat.h include/DataFormatsTOF/CompressedDataFormat.h include/DataFormatsTOF/CTF.h - ) + include/DataFormatsTOF/CalibInfoCluster.h + include/DataFormatsTOF/CosmicInfo.h + include/DataFormatsTOF/Diagnostic.h) diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h index 75341a074681b..57d5784dc3b66 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,14 +29,14 @@ class ROFRecord; class CompClusterExt; /// Header for a single CTF -struct CTFHeader { +struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nROFs = 0; /// number of ROFrame in TF uint32_t nDigits = 0; /// number of digits in TF uint32_t nPatternBytes = 0; /// number of bytes for explict patterns uint32_t firstOrbit = 0; /// 1st orbit of TF uint16_t firstBC = 0; /// 1st BC of TF - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// Compressed but not yet entropy-encoded infos @@ -67,13 +68,13 @@ struct CompressedInfos { std::vector<uint16_t> stripID; /// increment of stripID wrt that of prev. strip std::vector<uint8_t> chanInStrip; /// channel in strip 0-95 (ordered in time) std::vector<uint16_t> tot; /// Time-Over-Threshold in TOF channel (about 48.8 ps) - std::vector<uint32_t> pattMap; /// explict patterns container + std::vector<uint8_t> pattMap; /// explict patterns container CompressedInfos() = default; void clear(); - ClassDefNV(CompressedInfos, 2); + ClassDefNV(CompressedInfos, 3); }; /// wrapper for the Entropy-encoded clusters of the TF diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoCluster.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoCluster.h new file mode 100644 index 0000000000000..83229cdf62a65 --- /dev/null +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoCluster.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Cluster.h +/// \brief Definition of the TOF cluster + +#ifndef ALICEO2_TOF_CLUSTERCALINFOCLASS_H +#define ALICEO2_TOF_CLUSTERCALINFOCLASS_H + +#include <vector> +#include "Rtypes.h" + +namespace o2 +{ +namespace tof +{ +/// \class CalibInfoCluster +/// \brief CalibInfoCluster for TOF +/// +class CalibInfoCluster +{ + int ch = 0; + int8_t deltach = 0; + float deltat = 0; + short tot1 = 0; + short tot2 = 0; + + public: + int getCH() const { return ch; } + int8_t getDCH() const { return deltach; } + float getDT() const { return deltat; } + short getTOT1() const { return tot1; } + short getTOT2() const { return tot2; } + + CalibInfoCluster() = default; + CalibInfoCluster(int ich, int8_t ideltach, float dt, short t1, short t2) : ch(ich), deltach(ideltach), deltat(dt), tot1(t1), tot2(t2) {} + ClassDefNV(CalibInfoCluster, 1); +}; +} // namespace tof + +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOF.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOF.h index 9fa941afc33ba..cbb8c0ae44d1d 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOF.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOFshort.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOFshort.h index 3f5579c0bc33a..a67866f3c501c 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOFshort.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoTOFshort.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibLHCphaseTOF.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibLHCphaseTOF.h index ba60077538b9f..221761ee01d0d 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibLHCphaseTOF.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibLHCphaseTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibTimeSlewingParamTOF.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibTimeSlewingParamTOF.h index 89d0da80cd279..99494ba4526dd 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibTimeSlewingParamTOF.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibTimeSlewingParamTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -82,11 +83,12 @@ class CalibTimeSlewingParamTOF private: // TOF channel calibrations std::array<std::array<int, NCHANNELXSECTOR>, NSECTORS> mChannelStart; ///< array with the index of the first element of a channel in the time slewing vector (per sector) + std::array<std::array<float, NCHANNELXSECTOR>, NSECTORS> mGlobalOffset; ///< array with the sigma of the peak std::array<std::vector<std::pair<unsigned short, short>>, NSECTORS> mTimeSlewing; ///< array of sector vectors; first element of the pair is TOT (in ps), second is t-texp_pi (in ps) std::array<std::array<float, NCHANNELXSECTOR>, NSECTORS> mFractionUnderPeak; ///< array with the fraction of entries below the peak std::array<std::array<float, NCHANNELXSECTOR>, NSECTORS> mSigmaPeak; ///< array with the sigma of the peak - ClassDefNV(CalibTimeSlewingParamTOF, 1); // class for TOF time slewing params + ClassDefNV(CalibTimeSlewingParamTOF, 2); // class for TOF time slewing params }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h index 35126f49cb32f..8c348b5aef867 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,11 +15,15 @@ #ifndef ALICEO2_TOF_CLUSTER_H #define ALICEO2_TOF_CLUSTER_H +#include "GPUCommonRtypes.h" +#include "GPUCommonMath.h" #include "ReconstructionDataFormats/BaseCluster.h" +#include "CommonConstants/LHCConstants.h" +#ifndef GPUCA_GPUCODE #include <boost/serialization/base_object.hpp> // for base_object -#include <TMath.h> #include <cstdlib> -#include "CommonConstants/LHCConstants.h" +#include <vector> +#endif namespace o2 { @@ -34,7 +39,7 @@ class Cluster : public o2::BaseCluster<float> static constexpr float PhiOutOfRange = 9999; // used to check if phi was already calculated or not static constexpr int NPADSXSECTOR = 8736; - static constexpr Double_t BC_TIME_INPS_INV = 1.E-3 / o2::constants::lhc::LHCBunchSpacingNS; + static constexpr double BC_TIME_INPS_INV = 1.E-3 / o2::constants::lhc::LHCBunchSpacingNS; public: enum { kUpLeft = 0, // 2^0, 1st bit @@ -73,7 +78,7 @@ class Cluster : public o2::BaseCluster<float> float getR() // Cluster Radius (it is the same in sector and global frame) { if (mR == RadiusOutOfRange) { - mR = TMath::Sqrt(getX() * getX() + getY() * getY() + getZ() * getZ()); + mR = o2::gpu::CAMath::Sqrt(getX() * getX() + getY() * getY() + getZ() * getZ()); } return mR; } @@ -81,7 +86,22 @@ class Cluster : public o2::BaseCluster<float> float getPhi() // Cluster Phi in sector frame { if (mPhi == PhiOutOfRange) { - mPhi = TMath::ATan2(getY(), getX()); + mPhi = o2::gpu::CAMath::ATan2(getY(), getX()); + } + return mPhi; + } + float getR() const // Cluster Radius (it is the same in sector and global frame) + { + if (mR == RadiusOutOfRange) { + return o2::gpu::CAMath::Sqrt(getX() * getX() + getY() * getY() + getZ() * getZ()); + } + return mR; + } + + float getPhi() const // Cluster Phi in sector frame + { + if (mPhi == PhiOutOfRange) { + return o2::gpu::CAMath::ATan2(getY(), getX()); } return mPhi; } @@ -110,6 +130,11 @@ class Cluster : public o2::BaseCluster<float> int getBC() const { return int(mTimeRaw * BC_TIME_INPS_INV); } + void setDigitInfo(int idig, int ch, double t, float tot); + int getDigitInfoCH(int idig) const { return mDigitInfoCh[idig]; } + double getDigitInfoT(int idig) const { return mDigitInfoT[idig]; } + float getDigitInfoTOT(int idig) const { return mDigitInfoTOT[idig]; } + private: friend class boost::serialization::access; @@ -123,10 +148,17 @@ class Cluster : public o2::BaseCluster<float> float mPhi = PhiOutOfRange; //! phi coordinate int mEntryInTree; //! index of the entry in the tree from which we read the cluster - ClassDefNV(Cluster, 3); + // add extra info to trace all digit infos (for commissioning phase) + int mDigitInfoCh[6] = {0, 0, 0, 0, 0, 0}; + double mDigitInfoT[6] = {0., 0., 0., 0., 0., 0.}; + float mDigitInfoTOT[6] = {0., 0., 0., 0., 0., 0.}; + + ClassDefNV(Cluster, 4); }; +#ifndef GPUCA_GPUCODE std::ostream& operator<<(std::ostream& os, Cluster& c); +#endif } // namespace tof /// Defining o2::tof::Cluster explicitly as messageable diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CompressedDataFormat.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CompressedDataFormat.h index ad00322500e81..a6e5b45d9b859 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CompressedDataFormat.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CompressedDataFormat.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CosmicInfo.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CosmicInfo.h new file mode 100644 index 0000000000000..2d33f7f47d73a --- /dev/null +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CosmicInfo.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CosmicInfo.h +/// \brief Info from cosmic + +#ifndef ALICEO2_TOF_COSMICINFO_H +#define ALICEO2_TOF_COSMICINFO_H + +#include <vector> +#include "Rtypes.h" + +namespace o2 +{ +namespace tof +{ +/// \class CalibInfoCluster +/// \brief CalibInfoCluster for TOF +/// +class CosmicInfo +{ + int mChan1; + int mChan2; + float mDtime; + float mTot1; + float mTot2; + float mL; + float mT1; + float mT2; + + public: + int getCH1() const { return mChan1; } + int getCH2() const { return mChan2; } + float getDeltaTime() const { return mDtime; } + float getTOT1() const { return mTot1; } + float getTOT2() const { return mTot2; } + float getL() const { return mL; } + float getT1() const { return mT1; } + float getT2() const { return mT2; } + + void setCH1(int ch) { mChan1 = ch; } + void setCH2(int ch) { mChan2 = ch; } + void setDeltaTime(float val) { mDtime = val; } + void setTOT1(float val) { mTot1 = val; } + void setTOT2(float val) { mTot2 = val; } + void setT1(float val) { mT1 = val; } + void setT2(float val) { mT2 = val; } + void setL(float val) { mL = val; } + + CosmicInfo(int ch1 = 0, int ch2 = 0, float dt = 0, float tot1 = 0, float tot2 = 0, float l = 0, float tm1 = 0, float tm2 = 0) : mChan1(ch1), mChan2(ch2), mDtime(dt), mTot1(tot1), mTot2(tot2), mL(l), mT1(tm1), mT2(tm2) {} + + ClassDefNV(CosmicInfo, 2); +}; + +class CalibInfoTrackCl +{ + int mCh = 0; + float mX = 0; + float mY = 0; + float mZ = 0; + float mT = 0; + short mTot = 0; + + public: + int getCH() const { return mCh; } + float getT() const { return mT; } + float getX() const { return mX; } + float getY() const { return mY; } + float getZ() const { return mZ; } + short getTOT() const { return mTot; } + + CalibInfoTrackCl() = default; + CalibInfoTrackCl(int ch, float x, float y, float z, float t, short tot) : mCh(ch), mX(x), mY(y), mZ(z), mT(t), mTot(tot) {} + ClassDefNV(CalibInfoTrackCl, 1); +}; + +} // namespace tof + +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h new file mode 100644 index 0000000000000..a4778e5efa859 --- /dev/null +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Diagnostic.h +/// \brief Definition of the TOF cluster + +#ifndef ALICEO2_TOF_DIAGNOSTIC_H +#define ALICEO2_TOF_DIAGNOSTIC_H + +#include <map> +#include <TObject.h> +#include <gsl/gsl> + +namespace o2 +{ +namespace tof +{ +/// \class Diagnostic +/// \brief Diagnostic class for TOF +/// + +class Diagnostic +{ + public: + Diagnostic() = default; + int fill(ULong64_t pattern); + int fill(ULong64_t pattern, int frequency); + int getFrequency(ULong64_t pattern); // Get frequency + int getFrequencyROW() { return getFrequency(0); } // Readout window frequency + int getFrequencyEmptyCrate(int crate) { return getFrequency(getEmptyCrateKey(crate)); } // empty crate frequency + int fillNoisy(int channel, int frequency = 1) { return fill(getNoisyChannelKey(channel), frequency); } + int fillROW() { return fill(0); } + int fillEmptyCrate(int crate, int frequency = 1) { return fill(getEmptyCrateKey(crate), frequency); } + static ULong64_t getEmptyCrateKey(int crate); + static ULong64_t getNoisyChannelKey(int channel); + void print() const; + void clear() { mVector.clear(); } + void fill(const Diagnostic& diag); // for calibration + void fill(const gsl::span<const o2::tof::Diagnostic>){}; // for calibration + void merge(const Diagnostic* prev); + + private: + std::map<ULong64_t, uint32_t> mVector; // diagnostic frequency vector (key/pattern , frequency) + + ClassDefNV(Diagnostic, 1); +}; + +} // namespace tof +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/RawDataFormat.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/RawDataFormat.h index 1e440307f2212..87a05b6ec3542 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/RawDataFormat.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/RawDataFormat.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/src/CTF.cxx b/DataFormats/Detectors/TOF/src/CTF.cxx index a1097f94efbae..62d4820a0b829 100644 --- a/DataFormats/Detectors/TOF/src/CTF.cxx +++ b/DataFormats/Detectors/TOF/src/CTF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/src/CalibInfoCluster.cxx b/DataFormats/Detectors/TOF/src/CalibInfoCluster.cxx new file mode 100644 index 0000000000000..6d0af8ac315d7 --- /dev/null +++ b/DataFormats/Detectors/TOF/src/CalibInfoCluster.cxx @@ -0,0 +1,17 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibInfoCluster.cxx +/// \brief Implementation of the TOF cluster calib info + +#include "DataFormatsTOF/CalibInfoCluster.h" + +ClassImp(o2::tof::CalibInfoCluster); diff --git a/DataFormats/Detectors/TOF/src/CalibInfoTOF.cxx b/DataFormats/Detectors/TOF/src/CalibInfoTOF.cxx index 9e08679b90da3..89858904b104b 100644 --- a/DataFormats/Detectors/TOF/src/CalibInfoTOF.cxx +++ b/DataFormats/Detectors/TOF/src/CalibInfoTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/src/CalibInfoTOFshort.cxx b/DataFormats/Detectors/TOF/src/CalibInfoTOFshort.cxx index bc680005fcd9b..b1bb966b123f6 100644 --- a/DataFormats/Detectors/TOF/src/CalibInfoTOFshort.cxx +++ b/DataFormats/Detectors/TOF/src/CalibInfoTOFshort.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/src/CalibLHCphaseTOF.cxx b/DataFormats/Detectors/TOF/src/CalibLHCphaseTOF.cxx index 8cab385255223..179faaabedce0 100644 --- a/DataFormats/Detectors/TOF/src/CalibLHCphaseTOF.cxx +++ b/DataFormats/Detectors/TOF/src/CalibLHCphaseTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TOF/src/CalibTimeSlewingParamTOF.cxx b/DataFormats/Detectors/TOF/src/CalibTimeSlewingParamTOF.cxx index 2e7980dd0d9f8..3fcf67eb9ca7c 100644 --- a/DataFormats/Detectors/TOF/src/CalibTimeSlewingParamTOF.cxx +++ b/DataFormats/Detectors/TOF/src/CalibTimeSlewingParamTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -64,7 +65,7 @@ float CalibTimeSlewingParamTOF::evalTimeSlewing(int channel, float totIn) const } if (totIn == 0) { - return (float)((mTimeSlewing[sector])[n].second); + return (float)((mTimeSlewing[sector])[n].second + mGlobalOffset[sector][channel]); } // we convert tot from ns to ps and to unsigned short @@ -80,13 +81,13 @@ float CalibTimeSlewingParamTOF::evalTimeSlewing(int channel, float totIn) const } if (n == nstop - 1) { - return (float)((mTimeSlewing[sector])[n].second); // use the last value stored for that channel + return (float)((mTimeSlewing[sector])[n].second + mGlobalOffset[sector][channel]); // use the last value stored for that channel } float w1 = (float)(tot - (mTimeSlewing[sector])[n].first); float w2 = (float)((mTimeSlewing[sector])[n + 1].first - tot); - return (float)(((mTimeSlewing[sector])[n].second * w2 + (mTimeSlewing[sector])[n + 1].second * w1) / ((mTimeSlewing[sector])[n + 1].first - (mTimeSlewing[sector])[n].first)); + return (float)(mGlobalOffset[sector][channel] + (((mTimeSlewing[sector])[n].second * w2 + (mTimeSlewing[sector])[n + 1].second * w1) / ((mTimeSlewing[sector])[n + 1].first - (mTimeSlewing[sector])[n].first))); } //______________________________________________ @@ -110,14 +111,15 @@ void CalibTimeSlewingParamTOF::addTimeSlewingInfo(int channel, float tot, float } int currentch = channel; - while (mChannelStart[sector][currentch] == -1 && currentch > -1) { + while (currentch > -1 && mChannelStart[sector][currentch] == -1) { // printf("DBG: fill channel %i\n",currentch); // set also all the previous ones which were not filled mChannelStart[sector][currentch] = (mTimeSlewing[sector]).size(); + mGlobalOffset[sector][currentch] = time; currentch--; } // printf("DBG: emplace back (%f,%f)\n",tot,time); - (mTimeSlewing[sector]).emplace_back((unsigned short)(tot * 1000), (short)time); + (mTimeSlewing[sector]).emplace_back((unsigned short)(tot * 1000), (short)(time - mGlobalOffset[sector][currentch])); } //______________________________________________ diff --git a/DataFormats/Detectors/TOF/src/Cluster.cxx b/DataFormats/Detectors/TOF/src/Cluster.cxx index f2a0b0ea67f13..8e688ee91e801 100644 --- a/DataFormats/Detectors/TOF/src/Cluster.cxx +++ b/DataFormats/Detectors/TOF/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,8 +27,8 @@ Cluster::Cluster(std::int16_t sensid, float x, float y, float z, float sy2, floa { // caching R and phi - mR = TMath::Sqrt(x * x + y * y); - mPhi = TMath::ATan2(y, x); + mR = o2::gpu::CAMath::Sqrt(x * x + y * y); + mPhi = o2::gpu::CAMath::ATan2(y, x); } //______________________________________________________________________ int Cluster::getNumOfContributingChannels() const @@ -72,3 +73,11 @@ std::ostream& operator<<(std::ostream& os, Cluster& c) os << " TOF cluster: raw time = " << std::scientific << c.getTimeRaw() << ", time = " << std::scientific << c.getTime() << ", Tot = " << std::scientific << c.getTot() << ", L0L1Latency = " << c.getL0L1Latency() << ", deltaBC = " << c.getDeltaBC() << ", R = " << c.getR() << ", mPhi = " << c.getPhi() << ", Number of contributingChannels = " << c.getNumOfContributingChannels() << "\n"; return os; } + +//______________________________________________________________________ +void Cluster::setDigitInfo(int idig, int ch, double t, float tot) +{ + mDigitInfoCh[idig] = ch; + mDigitInfoT[idig] = t; + mDigitInfoTOT[idig] = tot; +} diff --git a/DataFormats/Detectors/TOF/src/CosmicInfo.cxx b/DataFormats/Detectors/TOF/src/CosmicInfo.cxx new file mode 100644 index 0000000000000..35d783d4b3ba4 --- /dev/null +++ b/DataFormats/Detectors/TOF/src/CosmicInfo.cxx @@ -0,0 +1,17 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CosmicInfo.cxx +/// \brief Implementation of the TOF cluster calib info + +#include "DataFormatsTOF/CosmicInfo.h" + +ClassImp(o2::tof::CosmicInfo); diff --git a/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h b/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h index c6142bb3e8ec1..2112580cb6b6f 100644 --- a/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h +++ b/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,14 @@ #pragma link off all classes; #pragma link off all functions; #pragma link C++ class o2::tof::Cluster + ; +#pragma link C++ class o2::tof::CalibInfoCluster + ; +#pragma link C++ class o2::tof::CosmicInfo + ; +#pragma link C++ class o2::tof::CalibInfoTrackCl + ; +#pragma link C++ class o2::tof::Diagnostic + ; #pragma link C++ class std::vector < o2::tof::Cluster> + ; +#pragma link C++ class std::vector < o2::tof::CalibInfoCluster> + ; +#pragma link C++ class std::vector < o2::tof::CosmicInfo> + ; +#pragma link C++ class std::vector < o2::tof::CalibInfoTrackCl> + ; #pragma link C++ class o2::dataformats::CalibInfoTOFshort + ; #pragma link C++ class o2::dataformats::CalibInfoTOF + ; diff --git a/DataFormats/Detectors/TOF/src/Diagnostic.cxx b/DataFormats/Detectors/TOF/src/Diagnostic.cxx new file mode 100644 index 0000000000000..847d07a01554a --- /dev/null +++ b/DataFormats/Detectors/TOF/src/Diagnostic.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Diagnostic.cxx +/// \brief Implementation of the TOF cluster + +#include "DataFormatsTOF/Diagnostic.h" +#include <iostream> +#include "Framework/Logger.h" + +using namespace o2::tof; + +ClassImp(Diagnostic); + +int Diagnostic::fill(ULong64_t pattern) +{ + int frequency = 1; + + auto pairC = mVector.find(pattern); + + if (pairC != mVector.end()) { + frequency = (pairC->second)++; + } else { + mVector.emplace(std::make_pair(pattern, 1)); + } + + return frequency; +} + +int Diagnostic::fill(ULong64_t pattern, int frequency) +{ + auto pairC = mVector.find(pattern); + + if (pairC != mVector.end()) { + (pairC->second) += frequency; + frequency = (pairC->second); + } else { + mVector.emplace(std::make_pair(pattern, frequency)); + } + + return frequency; +} + +int Diagnostic::getFrequency(ULong64_t pattern) +{ + auto pairC = mVector.find(pattern); + if (pairC != mVector.end()) { + return (pairC->second); + } + + return 0; +} + +void Diagnostic::print() const +{ + LOG(INFO) << "Diagnostic patterns"; + for (const auto& [key, value] : mVector) { + std::cout << key << " = " << value << "; "; + } + std::cout << std::endl; +} + +ULong64_t Diagnostic::getEmptyCrateKey(int crate) +{ + ULong64_t key = (ULong64_t(11) << 32) + (ULong64_t(crate) << 36); // slot=11 means empty crate + return key; +} + +ULong64_t Diagnostic::getNoisyChannelKey(int channel) +{ + ULong64_t key = (ULong64_t(12) << 32) + channel; // slot=12 means noisy channels + return key; +} + +void Diagnostic::fill(const Diagnostic& diag) +{ + LOG(DEBUG) << "Filling diagnostic word"; + for (auto const& el : diag.mVector) { + LOG(DEBUG) << "Filling diagnostic pattern " << el.first << " adding " << el.second << " to " << getFrequency(el.first) << " --> " << el.second + getFrequency(el.first); + fill(el.first, el.second); + } +} + +void Diagnostic::merge(const Diagnostic* prev) +{ + LOG(DEBUG) << "Merging diagnostic words"; + for (auto const& el : prev->mVector) { + fill(el.first, el.second + getFrequency(el.first)); + } +} diff --git a/DataFormats/Detectors/TPC/CMakeLists.txt b/DataFormats/Detectors/TPC/CMakeLists.txt index 5665856a7b754..54929a265994c 100644 --- a/DataFormats/Detectors/TPC/CMakeLists.txt +++ b/DataFormats/Detectors/TPC/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Comments # @@ -23,7 +24,9 @@ o2_add_library( src/LaserTrack.cxx src/TPCSectorHeader.cxx src/ClusterNativeHelper.cxx + src/WorkflowHelper.cxx src/CompressedClusters.cxx + src/TrackCuts.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon O2::SimulationDataFormat O2::CommonDataFormat @@ -38,6 +41,7 @@ o2_target_root_dictionary( include/DataFormatsTPC/ClusterHardware.h include/DataFormatsTPC/Digit.h include/DataFormatsTPC/Helpers.h + include/DataFormatsTPC/KrCluster.h include/DataFormatsTPC/TrackTPC.h include/DataFormatsTPC/LaserTrack.h include/DataFormatsTPC/Constants.h @@ -45,8 +49,10 @@ o2_target_root_dictionary( include/DataFormatsTPC/dEdxInfo.h include/DataFormatsTPC/CompressedClusters.h include/DataFormatsTPC/CTF.h + include/DataFormatsTPC/IDC.h include/DataFormatsTPC/ZeroSuppression.h - include/DataFormatsTPC/ZeroSuppressionLinkBased.h) + include/DataFormatsTPC/ZeroSuppressionLinkBased.h + include/DataFormatsTPC/TrackCuts.h) o2_add_test( ClusterNative @@ -68,3 +74,10 @@ o2_add_test( COMPONENT_NAME DataFormats-TPC PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC LABELS tpc dataformats) + +o2_add_test( + TrackCuts + SOURCES test/test_TrackCuts.cxx + COMPONENT_NAME DataFormats-TPC + PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC + LABELS tpc dataformats) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h index c501776e34e06..1e57c9654932c 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,16 +24,18 @@ namespace o2 namespace tpc { -struct CTFHeader : public CompressedClustersCounters { +struct CTFHeader : public ctf::CTFDictHeader, public CompressedClustersCounters { enum : uint32_t { CombinedColumns = 0x1 }; uint32_t flags = 0; - ClassDefNV(CTFHeader, 1); + ClassDefNV(CTFHeader, 2); }; /// wrapper for the Entropy-encoded clusters of the TF struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 23, uint32_t> { + using container_t = o2::ctf::EncodedBlocks<CTFHeader, 23, uint32_t>; + static constexpr size_t N = getNBlocks(); static constexpr int NBitsQTot = 16; static constexpr int NBitsQMax = 10; diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterGroupAttribute.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterGroupAttribute.h index 4bd5bd2596684..dad63831c3485 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterGroupAttribute.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterGroupAttribute.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterHardware.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterHardware.h index d3e9019d5d2a5..b4c123c0ea95e 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterHardware.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterHardware.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h index 70124c72d62c9..49d61007092a8 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -81,6 +82,8 @@ struct ClusterNative { setTimePackedFlags(time, flags); } + GPUd() uint16_t getQmax() const { return qMax; } + GPUd() uint16_t getQtot() const { return qTot; } GPUd() uint8_t getFlags() const { return timeFlagsPacked >> 24; } GPUd() uint32_t getTimePacked() const { return timeFlagsPacked & 0xFFFFFF; } GPUd() void setTimePackedFlags(uint32_t timePacked, uint8_t flags) @@ -164,7 +167,7 @@ struct ClusterNativeAccess { unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]; unsigned int nClustersSector[constants::MAXSECTOR]; unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]; - unsigned int nClustersTotal; + unsigned int nClustersTotal; // Must be directly after clusterOffsets, --> =clusterOffset[nRows * nSectors]! void setOffsetPtrs(); diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNativeHelper.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNativeHelper.h index 7c316f3deba9c..b8d6a3e7a9428 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNativeHelper.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNativeHelper.h @@ -1,20 +1,22 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef CLUSTERNATIVEHELPER_H -#define CLUSTERNATIVEHELPER_H /// @file ClusterNativeHelper.h /// @brief Helper class to read the binary format of TPC ClusterNative /// @since 2019-01-23 /// @author Matthias Richter +#ifndef CLUSTERNATIVEHELPER_H +#define CLUSTERNATIVEHELPER_H + #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/ClusterGroupAttribute.h" #include "DataFormatsTPC/Constants.h" @@ -215,24 +217,24 @@ class ClusterNativeHelper // @param mcBuffer // @param inputs data arrays, fixed array, one per sector // @param mcinputs vectors mc truth container, fixed array, one per sector - // @param checkFct check whether a sector index is valid - template <typename DataArrayType, typename MCArrayType, typename CheckFct = std::function<bool(size_t&)>> + // @param sectorMask Bitmask with tpc sectors to process + template <typename DataArrayType, typename MCArrayType> static int fillIndex( ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer, ConstMCLabelContainerViewWithBuffer& mcBuffer, DataArrayType& inputs, MCArrayType const& mcinputs, - CheckFct checkFct = [](auto const&) { return true; }); + unsigned long sectorMask = 0xFFFFFFFFF); - template <typename DataArrayType, typename CheckFct = std::function<bool(size_t&)>> + template <typename DataArrayType> static int fillIndex( ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer, - DataArrayType& inputs, CheckFct checkFct = [](auto const&) { return true; }) + DataArrayType& inputs, unsigned long sectorMask = 0xFFFFFFFFF) { // just use a dummy parameter with empty vectors // TODO: maybe do in one function with conditional template parameter std::vector<std::unique_ptr<MCLabelContainer>> dummy; // another default, nothing will be added to the container ConstMCLabelContainerViewWithBuffer mcBuffer; - return fillIndex(clusterIndex, clusterBuffer, mcBuffer, inputs, dummy, checkFct); + return fillIndex(clusterIndex, clusterBuffer, mcBuffer, inputs, dummy, sectorMask); } // Process data for one sector. @@ -347,10 +349,10 @@ class ClusterNativeHelper static void copySectorData(ClusterNativeAccess const& index, int sector, BufferType& target, MCArrayType& mcTarget); }; -template <typename DataArrayType, typename MCArrayType, typename CheckFct> +template <typename DataArrayType, typename MCArrayType> int ClusterNativeHelper::Reader::fillIndex(ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer, ConstMCLabelContainerViewWithBuffer& mcBuffer, - DataArrayType& inputs, MCArrayType const& mcinputs, CheckFct checkFct) + DataArrayType& inputs, MCArrayType const& mcinputs, unsigned long sectorMask) { if (mcinputs.size() > 0 && mcinputs.size() != inputs.size()) { std::runtime_error("inconsistent size of MC label array " + std::to_string(mcinputs.size()) + ", expected " + std::to_string(inputs.size())); @@ -370,6 +372,13 @@ int ClusterNativeHelper::Reader::fillIndex(ClusterNativeAccess& clusterIndex, if (sizeof(ClusterCountIndex) + clusterIndex.nClustersTotal * sizeof(ClusterNative) > inputs[0].size()) { throw std::runtime_error("inconsistent input buffer, expecting size " + std::to_string(sizeof(ClusterCountIndex) + clusterIndex.nClustersTotal * sizeof(ClusterNative)) + " got " + std::to_string(inputs[0].size())); } + if (sectorMask != 0xFFFFFFFFF) { + for (unsigned int sector = 0; sector < NSectors; sector++) { + if (!(sectorMask & (1ul << sector)) && clusterIndex.nClustersSector[sector]) { + throw std::runtime_error("TPC sector mask provided, but received more sectors than set. (A filter could be implemented here if needed.)"); + } + } + } return clusterIndex.nClustersTotal; } @@ -377,11 +386,8 @@ int ClusterNativeHelper::Reader::fillIndex(ClusterNativeAccess& clusterIndex, const ConstMCLabelContainerView* clustersMCTruth[NSectors] = {nullptr}; int result = 0; for (size_t index = 0, end = inputs.size(); index < end; index++) { - if (!checkFct(index)) { - continue; - } o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel> const* labelsptr = nullptr; - int extent = 0; + std::size_t extent = 0; if (index < mcinputs.size()) { labelsptr = &mcinputs[index]; extent = 1; diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClusters.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClusters.h index 249d9cb4f0bae..cbdc64fde9d3a 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClusters.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClusters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClustersHelpers.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClustersHelpers.h index b7d49c56238c8..7ca33ff1bc162 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClustersHelpers.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CompressedClustersHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h index a7d4c6c410975..6f6201b7de8df 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h index 0499dcd7dc6f5..115033df5c062 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Digit.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Digit.h index 4c446024324c5..2b816569e2fbe 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Digit.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Helpers.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Helpers.h index 22333545d7d2d..56fe16e99b9b6 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Helpers.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Helpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/IDC.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/IDC.h new file mode 100644 index 0000000000000..a55a74be34c88 --- /dev/null +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/IDC.h @@ -0,0 +1,137 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDC.h +/// \brief Integrated digital currents data format definition +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de +/// The data is sent by the CRU as 256bit words. The IDC data layout is as follows: +/// Header [ 256 bits ] +/// Channel-00 [L9][L8][L7][L6][L5][L4][L3][L2][L1][L0] +/// ... +/// Channel-79 [L9][L8][L7][L6][L5][L4][L3][L2][L1][L0] +/// +/// Where [Lx] is a 25bit value for Channel yy link x + +#ifndef ALICEO2_DATAFORMATSTPC_IDC_H +#define ALICEO2_DATAFORMATSTPC_IDC_H + +#include <bitset> + +namespace o2::tpc::idc +{ +static constexpr uint32_t Links = 10; ///< maximum number of links +static constexpr uint32_t Channels = 80; ///< number of channels +static constexpr uint32_t DataWordSizeBits = 256; ///< size of header word and data words in bits +static constexpr uint32_t DataWordSizeBytes = DataWordSizeBits / 8; ///< size of header word and data words in bytes +static constexpr uint32_t IDCvalueBits = 25; ///< number of bits used for one IDC value +static constexpr uint32_t IDCvalueBitsMask = (uint32_t(1) << IDCvalueBits) - 1; ///< bitmask for 25 bit word +static constexpr uint32_t SignificantBits = 2; ///< number of bits used for floating point precision +static constexpr float FloatConversion = 1.f / float(1 << SignificantBits); ///< conversion factor from integer representation to float + +/// header definition of the IDCs +/// The header is a 256 bit word +struct Header { + static constexpr uint32_t MagicWord = 0xDC; + union { + uint64_t word0 = 0; ///< bits 0 - 63 + struct { /// + uint32_t version : 8; ///< lower bits of the 80 bit bitmask + uint32_t packetID : 8; ///< packet id + uint32_t errorCode : 8; ///< errors + uint32_t magicWord : 8; ///< magic word + uint32_t heartbeatOrbit : 32; ///< heart beat orbit of the IDC value + }; /// + }; /// + /// + union { /// + uint64_t word1 = 0; ///< bits 64 - 127 + struct { /// + uint32_t heartbeatBC : 16; ///< BC id of IDC value + uint32_t integrationTime : 16; ///< integration time used for the IDCs + uint32_t linkMask : 16; ///< mask of active links + uint32_t unused1 : 16; /// + }; /// + }; /// + /// + union { /// + uint64_t word2 = 0; ///< bits 128 - 191 + struct { /// + uint64_t unused2 : 64; ///< lower bits of the 80 bit bitmask + }; /// + }; /// + /// + union { /// + uint64_t word3 = 0; ///< bits 192 - 255 + struct { /// + uint64_t unused3 : 64; ///< lower bits of the 80 bit bitmask + }; /// + }; /// + /// +}; + +/// IDC single channel data container +/// TODO: verify that pointer arithmetics does not run into alignment issues +/// might require different logic +struct Data { + uint8_t dataWords[DataWordSizeBytes] = {0}; ///< 25bit ADC values + + uint32_t getLinkValue(const uint32_t link) const + { + const auto valPtr = dataWords; + const uint32_t offset = link * IDCvalueBits; + const uint32_t selectedWord = offset / 8; + const uint32_t requiredShift = offset % 8; + const uint32_t value = (*(uint32_t*)(dataWords + selectedWord)) >> requiredShift; + return value & IDCvalueBitsMask; + } + + void setLinkValue(const uint32_t link, const uint32_t value) + { + const uint32_t offset = link * IDCvalueBits; + const uint32_t selectedWord = offset / 8; + const uint32_t requiredShift = offset % 8; + auto dataWrite = (uint64_t*)&dataWords[selectedWord]; + *dataWrite = (value & IDCvalueBitsMask) << requiredShift; + } +}; + +/// IDC full data container +struct Container { + Header header; ///< IDC data header + Data channelData[Channels]; ///< data values for all channels in each link + + bool hasLink(const uint32_t link) + { + return (header.linkMask & (1 << link)); + } + + uint32_t getChannelValue(const uint32_t link, const uint32_t channel) const + { + return channelData[channel].getLinkValue(link); + } + + void setChannelValue(const uint32_t link, const uint32_t channel, uint32_t value) + { + channelData[channel].setLinkValue(link, value); + } + + float getChannelValueFloat(const uint32_t link, const uint32_t channel) const + { + return float(channelData[channel].getLinkValue(link)) * FloatConversion; + } + + void setChannelValueFloat(const uint32_t link, const uint32_t channel, float value) + { + channelData[channel].setLinkValue(link, uint32_t((value + 0.5f * FloatConversion) / FloatConversion)); + } +}; +} // namespace o2::tpc::idc +#endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/KrCluster.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/KrCluster.h new file mode 100644 index 0000000000000..e89ada7edbfe4 --- /dev/null +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/KrCluster.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrCluster.h +/// \brief Struct for Krypton and X-ray clusters +/// \author Philip Hauer <hauer@hiskp.uni-bonn.de> + +#ifndef ALICEO2_TPC_KrCluster_H_ +#define ALICEO2_TPC_KrCluster_H_ + +#include "Rtypes.h" + +namespace o2 +{ +namespace tpc +{ + +struct KrCluster { + public: + unsigned char size = 0; ///< Size of the cluster (TPCDigits) + unsigned char sector = 0; ///< Sector number + unsigned char maxChargePad = 0; ///< Pad with max. charge in cluster (for leader pad method) + unsigned char maxChargeRow = 0; ///< Row with max. charge in cluster (for leader pad method) + float totCharge = 0; ///< Total charge of the cluster (ADC counts) + float maxCharge = 0; ///< Maximum charge of the cluster (ADC counts) + float meanPad = 0; ///< Center of gravity (Pad number) + float meanRow = 0; ///< Center of gravity (Row number) + float sigmaPad = 0; ///< RMS of cluster in pad direction + float sigmaRow = 0; ///< RMS of cluster in row direction + float meanTime = 0; ///< Center of gravity (Time) + float sigmaTime = 0; ///< RMS of cluster in time direction + + float getQmax() const { return maxCharge; } + float getQtot() const { return totCharge; } + float getPad() const { return meanPad; } + float getSigmaPad() const { return sigmaPad; } + float getTime() const { return meanTime; } + float getSigmaTime() const { return sigmaTime; } + + /// Used to set all Cluster variables to zero. + void reset() + { + size = 0; + sector = 0; + maxChargePad = 0; + maxChargeRow = 0; + totCharge = 0; + maxCharge = 0; + meanPad = 0; + meanRow = 0; + meanTime = 0; + sigmaPad = 0; + sigmaRow = 0; + sigmaTime = 0; + } + + ClassDefNV(KrCluster, 4); +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LaserTrack.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LaserTrack.h index 6397086e10e48..00b3d749a3833 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LaserTrack.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LaserTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,11 +15,10 @@ #include <string> #include <gsl/span> +#include "CommonConstants/MathConstants.h" #include "ReconstructionDataFormats/Track.h" -namespace o2 -{ -namespace tpc +namespace o2::tpc { /// \class LaserTrack /// This is the definition of the TPC Laser Track @@ -26,10 +26,14 @@ namespace tpc class LaserTrack : public o2::track::TrackPar { public: - static constexpr int NumberOfTracks = 336; ///< Total number of laser tracks - static constexpr int RodsPerSide = 6; ///< Number of laser rods per side - static constexpr int BundlesPerRod = 4; ///< number of micro-mirror bundle per laser rod - static constexpr int TracksPerBundle = 7; ///< number of micro-mirrors per bundle + static constexpr int NumberOfTracks = 336; ///< Total number of laser tracks + static constexpr int RodsPerSide = 6; ///< Number of laser rods per side + static constexpr int BundlesPerRod = 4; ///< number of micro-mirror bundle per laser rod + static constexpr int TracksPerBundle = 7; ///< number of micro-mirrors per bundle + static constexpr float SectorSpanRad = o2::constants::math::SectorSpanRad; ///< secotor width in rad + static constexpr std::array<float, 2> FirstRodPhi{2.f * SectorSpanRad, 1.f * SectorSpanRad}; ///< phi pos of first laser rod, A-, C-Side + static constexpr float RodDistancePhi = 3.f * SectorSpanRad; ///< phi distance of laser Rods + static constexpr std::array<float, 4> CoarseBundleZPos{243.5, 165.5, 82, 11.5}; ///< coarse z-position of the laser bundles LaserTrack() = default; LaserTrack(int id, float x, float alpha, const std::array<float, o2::track::kNParams>& par) : mID(id), o2::track::TrackPar(x, alpha, par) { ; } @@ -99,6 +103,5 @@ class LaserTrackContainer ClassDefNV(LaserTrackContainer, 1); }; -} // namespace tpc -} // namespace o2 +} // namespace o2::tpc #endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TPCSectorHeader.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TPCSectorHeader.h index c9221ff5fb37a..afa6b1c53b235 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TPCSectorHeader.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TPCSectorHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/qc/include/TPCQC/TrackCuts.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h similarity index 76% rename from Detectors/TPC/qc/include/TPCQC/TrackCuts.h rename to DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h index 1cbe50b80ea23..8185d627939ea 100644 --- a/Detectors/TPC/qc/include/TPCQC/TrackCuts.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,9 +26,6 @@ namespace tpc class TrackTPC; -namespace qc -{ - /// @brief track cut class /// /// Can be used to apply cuts on tracks during qc. @@ -54,8 +52,7 @@ class TrackCuts ClassDefNV(TrackCuts, 1) }; -} // namespace qc } // namespace tpc } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h index d26d00b979ff6..adc3ff45b30eb 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #ifndef ALICEO2_TPC_TRACKTPC #define ALICEO2_TPC_TRACKTPC +#include "GPUCommonDef.h" #include "ReconstructionDataFormats/Track.h" #include "CommonDataFormat/RangeReference.h" #include "DataFormatsTPC/ClusterNative.h" @@ -40,42 +42,44 @@ class TrackTPC : public o2::track::TrackParCov using o2::track::TrackParCov::TrackParCov; // inherit /// Default constructor - TrackTPC() = default; + GPUdDefault() TrackTPC() = default; /// Destructor - ~TrackTPC() = default; - - unsigned short getFlags() const { return mFlags; } - unsigned short getClustersSideInfo() const { return mFlags & HasBothSidesClusters; } - bool hasASideClusters() const { return mFlags & HasASideClusters; } - bool hasCSideClusters() const { return mFlags & HasCSideClusters; } - bool hasBothSidesClusters() const { return (mFlags & (HasASideClusters | HasCSideClusters)) == (HasASideClusters | HasCSideClusters); } - bool hasASideClustersOnly() const { return (mFlags & HasBothSidesClusters) == HasASideClusters; } - bool hasCSideClustersOnly() const { return (mFlags & HasBothSidesClusters) == HasCSideClusters; } - - void setHasASideClusters() { mFlags |= HasASideClusters; } - void setHasCSideClusters() { mFlags |= HasCSideClusters; } - - float getTime0() const { return mTime0; } ///< Reference time of the track, i.e. t-bins of a primary track with eta=0. - float getDeltaTBwd() const { return mDeltaTBwd; } ///< max possible decrement to getTimeVertex - float getDeltaTFwd() const { return mDeltaTFwd; } ///< max possible increment to getTimeVertex - void setDeltaTBwd(float t) { mDeltaTBwd = t; } ///< set max possible decrement to getTimeVertex - void setDeltaTFwd(float t) { mDeltaTFwd = t; } ///< set max possible increment to getTimeVertex - - float getChi2() const { return mChi2; } - const o2::track::TrackParCov& getOuterParam() const { return mOuterParam; } - void setTime0(float v) { mTime0 = v; } - void setChi2(float v) { mChi2 = v; } - void setOuterParam(o2::track::TrackParCov&& v) { mOuterParam = v; } - const ClusRef& getClusterRef() const { return mClustersReference; } - void shiftFirstClusterRef(int dif) { mClustersReference.setFirstEntry(dif + mClustersReference.getFirstEntry()); } - int getNClusters() const { return mClustersReference.getEntries(); } - int getNClusterReferences() const { return getNClusters(); } - void setClusterRef(uint32_t entry, uint16_t ncl) { mClustersReference.set(entry, ncl); } + GPUdDefault() ~TrackTPC() = default; + + GPUd() unsigned short getFlags() const { return mFlags; } + GPUd() unsigned short getClustersSideInfo() const { return mFlags & HasBothSidesClusters; } + GPUd() bool hasASideClusters() const { return mFlags & HasASideClusters; } + GPUd() bool hasCSideClusters() const { return mFlags & HasCSideClusters; } + GPUd() bool hasBothSidesClusters() const { return (mFlags & (HasASideClusters | HasCSideClusters)) == (HasASideClusters | HasCSideClusters); } + GPUd() bool hasASideClustersOnly() const { return (mFlags & HasBothSidesClusters) == HasASideClusters; } + GPUd() bool hasCSideClustersOnly() const { return (mFlags & HasBothSidesClusters) == HasCSideClusters; } + + GPUd() void setHasASideClusters() { mFlags |= HasASideClusters; } + GPUd() void setHasCSideClusters() { mFlags |= HasCSideClusters; } + + GPUd() float getTime0() const { return mTime0; } ///< Reference time of the track, i.e. t-bins of a primary track with eta=0. + GPUd() float getDeltaTBwd() const { return mDeltaTBwd; } ///< max possible decrement to getTimeVertex + GPUd() float getDeltaTFwd() const { return mDeltaTFwd; } ///< max possible increment to getTimeVertex + GPUd() void setDeltaTBwd(float t) { mDeltaTBwd = t; } ///< set max possible decrement to getTimeVertex + GPUd() void setDeltaTFwd(float t) { mDeltaTFwd = t; } ///< set max possible increment to getTimeVertex + + GPUd() float getChi2() const { return mChi2; } + GPUd() const o2::track::TrackParCov& getOuterParam() const { return mOuterParam; } + GPUd() const o2::track::TrackParCov& getParamOut() const { return mOuterParam; } // to have method with same name as other tracks + GPUd() void setTime0(float v) { mTime0 = v; } + GPUd() void setChi2(float v) { mChi2 = v; } + GPUd() void setOuterParam(o2::track::TrackParCov&& v) { mOuterParam = v; } + GPUd() void setParamOut(o2::track::TrackParCov&& v) { mOuterParam = v; } // to have method with same name as other tracks + GPUd() const ClusRef& getClusterRef() const { return mClustersReference; } + GPUd() void shiftFirstClusterRef(int dif) { mClustersReference.setFirstEntry(dif + mClustersReference.getFirstEntry()); } + GPUd() int getNClusters() const { return mClustersReference.getEntries(); } + GPUd() int getNClusterReferences() const { return getNClusters(); } + GPUd() void setClusterRef(uint32_t entry, uint16_t ncl) { mClustersReference.set(entry, ncl); } template <class T> - static inline void getClusterReference(T& clinfo, int nCluster, - uint8_t& sectorIndex, uint8_t& rowIndex, uint32_t& clusterIndex, const ClusRef& ref) + GPUd() static inline void getClusterReference(T& clinfo, int nCluster, + uint8_t& sectorIndex, uint8_t& rowIndex, uint32_t& clusterIndex, const ClusRef& ref) { // data for given tracks starts at clinfo[ ref.getFirstEntry() ], // 1st ref.getEntries() cluster indices are stored as uint32_t @@ -90,15 +94,15 @@ class TrackTPC : public o2::track::TrackParCov } template <class T> - inline void getClusterReference(T& clinfo, int nCluster, - uint8_t& sectorIndex, uint8_t& rowIndex, uint32_t& clusterIndex) const + GPUd() inline void getClusterReference(T& clinfo, int nCluster, + uint8_t& sectorIndex, uint8_t& rowIndex, uint32_t& clusterIndex) const { getClusterReference<T>(clinfo, nCluster, sectorIndex, rowIndex, clusterIndex, mClustersReference); } template <class T> - static inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, - const o2::tpc::ClusterNativeAccess& clusters, uint8_t& sectorIndex, uint8_t& rowIndex, const ClusRef& ref) + GPUd() static inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, + const o2::tpc::ClusterNativeAccess& clusters, uint8_t& sectorIndex, uint8_t& rowIndex, const ClusRef& ref) { uint32_t clusterIndex; getClusterReference<T>(clinfo, nCluster, sectorIndex, rowIndex, clusterIndex, ref); @@ -106,29 +110,27 @@ class TrackTPC : public o2::track::TrackParCov } template <class T> - inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, - const o2::tpc::ClusterNativeAccess& clusters, uint8_t& sectorIndex, uint8_t& rowIndex) const + GPUd() inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, + const o2::tpc::ClusterNativeAccess& clusters, uint8_t& sectorIndex, uint8_t& rowIndex) const { return getCluster<T>(clinfo, nCluster, clusters, sectorIndex, rowIndex, mClustersReference); } template <class T> - inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, - const o2::tpc::ClusterNativeAccess& clusters) const + GPUd() inline const o2::tpc::ClusterNative& getCluster(T& clinfo, int nCluster, + const o2::tpc::ClusterNativeAccess& clusters) const { uint8_t sectorIndex, rowIndex; return (getCluster<T>(clinfo, nCluster, clusters, sectorIndex, rowIndex)); } - const dEdxInfo& getdEdx() const { return mdEdx; } - void setdEdx(const dEdxInfo& v) { mdEdx = v; } + GPUd() const dEdxInfo& getdEdx() const { return mdEdx; } + GPUd() void setdEdx(const dEdxInfo& v) { mdEdx = v; } private: - float mTime0 = 0.f; ///< Reference Z of the track assumed for the vertex, scaled with pseudo - ///< VDrift and reference timeframe length, unless it was moved to be on the - ///< side of TPC compatible with edge clusters sides. - float mDeltaTFwd = 0; ///< max possible increment to track time - float mDeltaTBwd = 0; ///< max possible decrement to track time + float mTime0 = 0.f; ///< Assumed time of the vertex that created the track in TPC time bins, 0 for triggered data + float mDeltaTFwd = 0; ///< max possible increment to mTime0 + float mDeltaTBwd = 0; ///< max possible decrement to mTime0 short mFlags = 0; ///< various flags, see Flags enum float mChi2 = 0.f; // Chi2 of the track o2::track::TrackParCov mOuterParam; // Track parameters at outer end of TPC. diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/WorkflowHelper.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/WorkflowHelper.h new file mode 100644 index 0000000000000..24d8e72557a7f --- /dev/null +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/WorkflowHelper.h @@ -0,0 +1,189 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file WorkflowHelper.h +/// @brief Helper class to obtain TPC clusters / digits / labels from DPL +/// @author David Rohr + +#ifndef WORKFLOWHELPER_H +#define WORKFLOWHELPER_H + +#include <memory> +#include "Framework/ProcessingContext.h" +#include "Framework/DataRefUtils.h" +#include <Framework/InputRecord.h> +#include "Framework/InputRecordWalker.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DataFormatsTPC/Constants.h" +#include "DataFormatsTPC/Digit.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/ClusterGroupAttribute.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/ClusterNativeHelper.h" + +// NOTE: The DataFormatsTPC package does not have all required dependencies for these includes. +// The users of these headers should add them by themselves, in order to avoid making +// DataFormatsTPC depend on the Framework. + +namespace o2 +{ +namespace tpc +{ +namespace internal +{ +struct InputRef { + o2::framework::DataRef data; + o2::framework::DataRef labels; +}; +struct getWorkflowTPCInput_ret_internal { + std::map<int, InputRef> inputrefs; + std::vector<o2::dataformats::ConstMCLabelContainerView> mcInputs; + std::vector<gsl::span<const char>> inputs; + std::vector<o2::dataformats::ConstMCLabelContainerView> inputDigitsMC; + std::unique_ptr<ClusterNative[]> clusterBuffer; + ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer clustersMCBuffer; +}; +struct getWorkflowTPCInput_ret { + getWorkflowTPCInput_ret_internal internal; + std::array<gsl::span<const o2::tpc::Digit>, constants::MAXSECTOR> inputDigits; + std::array<const o2::dataformats::ConstMCLabelContainerView*, constants::MAXSECTOR> inputDigitsMCPtrs; + ClusterNativeAccess clusterIndex; +}; +} // namespace internal + +static auto getWorkflowTPCInput(o2::framework::ProcessingContext& pc, int verbosity = 0, bool do_mcLabels = false, bool do_clusters = true, unsigned long tpcSectorMask = 0xFFFFFFFFF, bool do_digits = false) +{ + auto retVal = std::make_unique<internal::getWorkflowTPCInput_ret>(); + + if (do_clusters && do_digits) { + throw std::invalid_argument("Currently cannot process both clusters and digits"); + } + std::array<int, constants::MAXSECTOR> inputDigitsMCIndex; + + if (do_mcLabels) { + std::vector<o2::framework::InputSpec> filter = { + {"check", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "DIGITSMCTR"}, o2::framework::Lifetime::Timeframe}, + {"check", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "CLNATIVEMCLBL"}, o2::framework::Lifetime::Timeframe}, + }; + unsigned long recvMask = 0; + if (do_digits) { + std::fill(inputDigitsMCIndex.begin(), inputDigitsMCIndex.end(), -1); + } + for (auto const& ref : o2::framework::InputRecordWalker(pc.inputs(), filter)) { + auto const* sectorHeader = o2::framework::DataRefUtils::getHeader<TPCSectorHeader*>(ref); + if (sectorHeader == nullptr) { + // FIXME: think about error policy + LOG(ERROR) << "sector header missing on header stack"; + return retVal; + } + const int sector = sectorHeader->sector(); + if (sector < 0) { + continue; + } + if (recvMask & sectorHeader->sectorBits) { + throw std::runtime_error("can only have one MC data set per sector"); + } + recvMask |= (sectorHeader->sectorBits & tpcSectorMask); + retVal->internal.inputrefs[sector].labels = ref; + if (do_digits) { + inputDigitsMCIndex[sector] = retVal->internal.inputDigitsMC.size(); + retVal->internal.inputDigitsMC.emplace_back(o2::dataformats::ConstMCLabelContainerView(pc.inputs().get<gsl::span<char>>(ref))); + } + } + if (recvMask != tpcSectorMask) { + throw std::runtime_error("Incomplete set of MC labels received"); + } + if (do_digits) { + for (unsigned int i = 0; i < constants::MAXSECTOR; i++) { + if (tpcSectorMask & (1ul << i)) { + if (verbosity >= 1) { + LOG(INFO) << "GOT MC LABELS FOR SECTOR " << i << " -> " << retVal->internal.inputDigitsMC[inputDigitsMCIndex[i]].getNElements(); + } + if (inputDigitsMCIndex[i] == -1) { + throw std::runtime_error("digit mc labels missing"); + } + retVal->inputDigitsMCPtrs[i] = &retVal->internal.inputDigitsMC[inputDigitsMCIndex[i]]; + } else { + retVal->inputDigitsMCPtrs[i] = nullptr; + } + } + } + } + + if (do_clusters || do_digits) { + std::vector<o2::framework::InputSpec> filter = { + {"check", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "DIGITS"}, o2::framework::Lifetime::Timeframe}, + {"check", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "CLUSTERNATIVE"}, o2::framework::Lifetime::Timeframe}, + }; + unsigned long recvMask = 0; + for (auto const& ref : o2::framework::InputRecordWalker(pc.inputs(), filter)) { + auto const* sectorHeader = o2::framework::DataRefUtils::getHeader<TPCSectorHeader*>(ref); + if (sectorHeader == nullptr) { + throw std::runtime_error("sector header missing on header stack"); + } + const int sector = sectorHeader->sector(); + if (sector < 0) { + continue; + } + if (recvMask & sectorHeader->sectorBits) { + throw std::runtime_error("can only have one cluster data set per sector"); + } + recvMask |= (sectorHeader->sectorBits & tpcSectorMask); + retVal->internal.inputrefs[sector].data = ref; + if (do_digits) { + if (tpcSectorMask & (1ul << sector)) { + retVal->inputDigits[sector] = pc.inputs().get<gsl::span<o2::tpc::Digit>>(ref); + if (verbosity >= 1) { + LOG(INFO) << "GOT DIGITS SPAN FOR SECTOR " << sector << " -> " << retVal->inputDigits[sector].size(); + } + } + } + } + if (recvMask != tpcSectorMask) { + throw std::runtime_error("Incomplete set of clusters/digits received"); + } + + for (auto const& refentry : retVal->internal.inputrefs) { + auto& sector = refentry.first; + auto& ref = refentry.second.data; + if (do_clusters) { + if (ref.payload == nullptr) { + // skip zero-length message + continue; + } + if (!(tpcSectorMask & (1ul << sector))) { + continue; + } + if (refentry.second.labels.header != nullptr && refentry.second.labels.payload != nullptr) { + retVal->internal.mcInputs.emplace_back(o2::dataformats::ConstMCLabelContainerView(pc.inputs().get<gsl::span<char>>(refentry.second.labels))); + } + retVal->internal.inputs.emplace_back(gsl::span(ref.payload, o2::framework::DataRefUtils::getPayloadSize(ref))); + } + if (verbosity > 1) { + LOG(INFO) << "received " << *(ref.spec) << ", size " << o2::framework::DataRefUtils::getPayloadSize(ref) << " for sector " << sector; + } + } + } + + if (do_clusters) { + memset(&retVal->clusterIndex, 0, sizeof(retVal->clusterIndex)); + ClusterNativeHelper::Reader::fillIndex(retVal->clusterIndex, retVal->internal.clusterBuffer, retVal->internal.clustersMCBuffer, retVal->internal.inputs, retVal->internal.mcInputs, tpcSectorMask); + } + + return std::move(retVal); +} + +} // namespace tpc +} // namespace o2 +#endif // WORKFLOWHELPER_H diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h index 2fd6c82b920af..ad577252254ae 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h index 0f14e9a6b74af..f94d7e2fb5a10 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ /// \file ZeroSuppressionLinkBased.h /// \brief definitions to deal with the link based zero suppression format -/// \author Jens Wiechula +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de #ifndef ALICEO2_DATAFORMATSTPC_ZeroSuppressionLinkBased_H #define ALICEO2_DATAFORMATSTPC_ZeroSuppressionLinkBased_H @@ -27,37 +28,46 @@ namespace zerosupp_link_based static constexpr uint32_t DataWordSizeBits = 128; ///< size of header word and data words in bits static constexpr uint32_t DataWordSizeBytes = DataWordSizeBits / 8; ///< size of header word and data words in bytes -/// header definition of the zero suppressed link based data format -struct Header { - static constexpr uint32_t MagicWord = 0xFC000000; +/// common header definition of the zero suppressed link based data +struct CommonHeader { + static constexpr uint32_t MagicWordLinkZS = 0xFC; + static constexpr uint32_t MagicWordTrigger = 0xAA; union { - uint64_t word0 = 0; ///< lower 64 bits - struct { /// - uint64_t bitMaskLow : 64; ///< lower bits of the 80 bit bitmask - }; /// - }; /// - /// - union { /// - uint64_t word1 = 0; ///< upper bits of the 80 bit bitmask - struct { /// - uint64_t bitMaskHigh : 16; ///< higher bits of the 80 bit bitmask - uint32_t bunchCrossing : 12; ///< bunch crossing number - uint32_t numWordsPayload : 4; ///< number of 128bit words with 12bit ADC values - uint32_t magicWord : 32; ///< not used + uint64_t word0 = 0; ///< lower 64 bits + struct { /// + uint64_t bitMaskLow : 64; ///< lower bits of the 80 bit bitmask + }; /// + }; /// + /// + union { /// + uint64_t word1 = 0; ///< upper bits of the 80 bit bitmask + struct { /// + uint64_t bitMaskHigh : 16; ///< higher bits of the 80 bit bitmask + uint32_t bunchCrossing : 12; ///< bunch crossing number + uint32_t numWordsPayload : 4; ///< number of 128bit words with 12bit ADC values + uint32_t syncOffsetBC : 8; ///< sync offset in bunch crossings + uint32_t syncOffsetCRUCycles : 16; ///< sync offset in 240MHz CRU clock cycles + uint32_t magicWord : 8; ///< not used }; }; + bool hasCorrectMagicWord() const { return (magicWord == MagicWordLinkZS) || (magicWord == MagicWordTrigger); } + bool isLinkZS() const { return (magicWord == MagicWordLinkZS); } + bool isTriggerInfo() const { return (magicWord == MagicWordTrigger); } +}; + +/// header definition of the zero suppressed link based data format +struct Header final : public CommonHeader { + std::bitset<80> getChannelBits() const { return std::bitset<80>((std::bitset<80>(bitMaskHigh) << 64) | std::bitset<80>(bitMaskLow)); } - bool hasCorrectMagicWord() const { return magicWord == MagicWord; } + bool isFillWord() const { return (word0 == 0xffffffffffffffff) && (word1 == 0xffffffffffffffff); } }; -/// empty header for - /// ADC data container /// /// In case of zero suppressed data, the ADC values are stored with 12 bit @@ -207,6 +217,36 @@ struct Container { using ContainerZS = Container<>; using ContainerDecoded = Container<10, 0, false>; +/// Data definition for the trigger information +struct TriggerInfo { + union { + uint64_t word0 = 0; ///< lower 64 bits + struct { /// + uint16_t bunchCrossing : 12; ///< bunch crossing number + uint64_t orbit : 32; ///< orbit number + uint32_t triggerTypeLow : 20; ///< low bits of tigger type + }; /// + }; /// + /// + union { /// + uint64_t word1 = 0; ///< upper bits of the 80 bit bitmask + struct { /// + uint32_t triggerTypeHigh : 12; ///< number of 128bit words with 12bit ADC values + uint64_t empty : 50; ///< + }; + }; + + uint32_t getOrbit() const { return (uint32_t)orbit; } + uint32_t getTriggerType() const { return (triggerTypeHigh << 20) + triggerTypeLow; } +}; + +/// Container for Trigger information, header + data +struct TriggerContainer { + CommonHeader header; + TriggerInfo triggerInfo; + + uint32_t getTriggerType() const { return triggerInfo.getTriggerType(); } +}; } // namespace zerosupp_link_based } // namespace tpc } // namespace o2 diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h index b00725fe587aa..63b64a50b63dc 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/src/ClusterNativeHelper.cxx b/DataFormats/Detectors/TPC/src/ClusterNativeHelper.cxx index 10c38de78b7de..62be5c4fab09d 100644 --- a/DataFormats/Detectors/TPC/src/ClusterNativeHelper.cxx +++ b/DataFormats/Detectors/TPC/src/ClusterNativeHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -189,7 +190,7 @@ int ClusterNativeHelper::Reader::fillIndex(ClusterNativeAccess& clusterIndex, st } } - int result = fillIndex(clusterIndex, clusterBuffer, mcBuffer, clustersTPC, constMCLabelContainerViews, [](auto&) { return true; }); + int result = fillIndex(clusterIndex, clusterBuffer, mcBuffer, clustersTPC, constMCLabelContainerViews); return result; } diff --git a/DataFormats/Detectors/TPC/src/CompressedClusters.cxx b/DataFormats/Detectors/TPC/src/CompressedClusters.cxx index c78a0b193848f..f4e5ff3cedd6d 100644 --- a/DataFormats/Detectors/TPC/src/CompressedClusters.cxx +++ b/DataFormats/Detectors/TPC/src/CompressedClusters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,7 +61,7 @@ void CompressedClustersROOT::Streamer(TBuffer& R__b) // the custom streamer for CompressedClustersROOT if (R__b.IsReading()) { R__b.ReadClassBuffer(CompressedClustersROOT::Class(), this); - gsl::span flatdata{this->flatdata, this->flatdataSize}; + gsl::span flatdata{this->flatdata, static_cast<std::size_t>(this->flatdataSize)}; CompressedClustersHelpers::restoreFrom(flatdata, *this); } else { std::vector<char> flatdata; diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index a8eb060a3d400..3e567597563a3 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,5 +50,8 @@ #pragma link C++ class o2::tpc::CTFHeader + ; #pragma link C++ class o2::ctf::EncodedBlocks < o2::tpc::CTFHeader, 23, uint32_t> + ; #pragma link C++ enum o2::tpc::StatisticsType; +#pragma link C++ class o2::tpc::TrackCuts + ; +#pragma link C++ class o2::tpc::KrCluster + ; +#pragma link C++ class std::vector<o2::tpc::KrCluster> + ; #endif diff --git a/DataFormats/Detectors/TPC/src/Helpers.cxx b/DataFormats/Detectors/TPC/src/Helpers.cxx index cef1d03b5dd10..d9a6bb30a5ce4 100644 --- a/DataFormats/Detectors/TPC/src/Helpers.cxx +++ b/DataFormats/Detectors/TPC/src/Helpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/src/LaserTrack.cxx b/DataFormats/Detectors/TPC/src/LaserTrack.cxx index 0700cadb6d05f..975d161f76082 100644 --- a/DataFormats/Detectors/TPC/src/LaserTrack.cxx +++ b/DataFormats/Detectors/TPC/src/LaserTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/src/TPCSectorHeader.cxx b/DataFormats/Detectors/TPC/src/TPCSectorHeader.cxx index fdee9e3c141cb..96716fd966cb6 100644 --- a/DataFormats/Detectors/TPC/src/TPCSectorHeader.cxx +++ b/DataFormats/Detectors/TPC/src/TPCSectorHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/src/TrackCuts.cxx b/DataFormats/Detectors/TPC/src/TrackCuts.cxx new file mode 100644 index 0000000000000..ad7977f6f7b5b --- /dev/null +++ b/DataFormats/Detectors/TPC/src/TrackCuts.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FairLogger.h" + +#include "DataFormatsTPC/TrackCuts.h" +#include "DataFormatsTPC/TrackTPC.h" + +ClassImp(o2::tpc::TrackCuts); + +using namespace o2::tpc; + +TrackCuts::TrackCuts(float PMin, float PMax, float NClusMin) : mPMin(PMin), + mPMax(PMax), + mNClusMin(NClusMin) +{ +} + +//______________________________________________________________________________ +bool TrackCuts::goodTrack(o2::tpc::TrackTPC const& track) +{ + const auto p = track.getP(); + const auto nclusters = track.getNClusterReferences(); + + if (p > mPMax) { + return false; + } + if (p < mPMin) { + return false; + } + if (nclusters < mNClusMin) { + return false; + } + return true; +} diff --git a/DataFormats/Detectors/TPC/src/TrackTPC.cxx b/DataFormats/Detectors/TPC/src/TrackTPC.cxx index e0932ae58b681..90f1e62a7a524 100644 --- a/DataFormats/Detectors/TPC/src/TrackTPC.cxx +++ b/DataFormats/Detectors/TPC/src/TrackTPC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/src/WorkflowHelper.cxx b/DataFormats/Detectors/TPC/src/WorkflowHelper.cxx new file mode 100644 index 0000000000000..3b7e64f61f452 --- /dev/null +++ b/DataFormats/Detectors/TPC/src/WorkflowHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file WorkflowHelper.cxx +/// @author David Rohr + +// Dummy file for the workflow helper, does not include WorkflowHelper.h, +// since DataFormats/TPC does not pull in all requred framework dependenecies. diff --git a/DataFormats/Detectors/TPC/test/testClusterHardware.cxx b/DataFormats/Detectors/TPC/test/testClusterHardware.cxx index 713c2b5df68a4..1c98140db1ab8 100644 --- a/DataFormats/Detectors/TPC/test/testClusterHardware.cxx +++ b/DataFormats/Detectors/TPC/test/testClusterHardware.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/test/testClusterNative.cxx b/DataFormats/Detectors/TPC/test/testClusterNative.cxx index fe146e69ff49a..f99d11a93a6f2 100644 --- a/DataFormats/Detectors/TPC/test/testClusterNative.cxx +++ b/DataFormats/Detectors/TPC/test/testClusterNative.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/test/testCompressedClusters.cxx b/DataFormats/Detectors/TPC/test/testCompressedClusters.cxx index 15956a1f31249..ec0a99a3c07fb 100644 --- a/DataFormats/Detectors/TPC/test/testCompressedClusters.cxx +++ b/DataFormats/Detectors/TPC/test/testCompressedClusters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/TPC/test/test_TrackCuts.cxx b/DataFormats/Detectors/TPC/test/test_TrackCuts.cxx new file mode 100644 index 0000000000000..4e924ace2a775 --- /dev/null +++ b/DataFormats/Detectors/TPC/test/test_TrackCuts.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test TPC QC +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DataFormatsTPC/TrackCuts.h" + +BOOST_AUTO_TEST_CASE(ReadWriteROOTFile) +{ + o2::tpc::TrackCuts trackcuts; +} diff --git a/DataFormats/Detectors/TRD/CMakeLists.txt b/DataFormats/Detectors/TRD/CMakeLists.txt index d41cc697843a9..ef6366a90ee24 100644 --- a/DataFormats/Detectors/TRD/CMakeLists.txt +++ b/DataFormats/Detectors/TRD/CMakeLists.txt @@ -1,23 +1,51 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsTRD SOURCES src/TriggerRecord.cxx src/LinkRecord.cxx + src/AngularResidHistos.cxx src/Tracklet64.cxx src/RawData.cxx - PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::SimulationDataFormat) + src/RawDataStats.cxx + src/CompressedDigit.cxx + src/CTF.cxx + src/Digit.cxx + src/KrCluster.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::SimulationDataFormat) - o2_target_root_dictionary(DataFormatsTRD +o2_target_root_dictionary(DataFormatsTRD HEADERS include/DataFormatsTRD/TriggerRecord.h + include/DataFormatsTRD/TrackTriggerRecord.h include/DataFormatsTRD/LinkRecord.h include/DataFormatsTRD/Tracklet64.h include/DataFormatsTRD/RawData.h - include/DataFormatsTRD/Constants.h) + include/DataFormatsTRD/Constants.h + include/DataFormatsTRD/CalibratedTracklet.h + include/DataFormatsTRD/AngularResidHistos.h + include/DataFormatsTRD/HelperMethods.h + include/DataFormatsTRD/Hit.h + include/DataFormatsTRD/Digit.h + include/DataFormatsTRD/KrCluster.h + include/DataFormatsTRD/KrClusterTriggerRecord.h + include/DataFormatsTRD/CTF.h + include/DataFormatsTRD/CalVdriftExB.h + include/DataFormatsTRD/SignalArray.h + include/DataFormatsTRD/CompressedDigit.h + include/DataFormatsTRD/CompressedHeader.h) + +o2_add_test(Digit + COMPONENT_NAME trd + PUBLIC_LINK_LIBRARIES O2::DataFormatsTRD + SOURCES test/testDigit.cxx + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + LABELS trd +) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/AngularResidHistos.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/AngularResidHistos.h new file mode 100644 index 0000000000000..9b1146104fbc4 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/AngularResidHistos.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file AngularResidHistos.h +/// \brief Class to store the angular residuals of TRD tracklets wrt TPC tracks for each TRD chamber + +#ifndef ALICEO2_ANGRESIDHISTOS_H +#define ALICEO2_ANGRESIDHISTOS_H + +#include "DataFormatsTRD/Constants.h" +#include "Rtypes.h" +#include <array> +#include <gsl/span> + +namespace o2 +{ +namespace trd +{ + +class AngularResidHistos +{ + public: + AngularResidHistos() = default; + AngularResidHistos(const AngularResidHistos&) = default; + ~AngularResidHistos() = default; + bool addEntry(float deltaAlpha, float impactAngle, int chamberId); + float getHistogramEntry(int index) const { return mHistogramEntries[index]; } + int getBinCount(int index) const { return mNEntriesPerBin[index]; } + size_t getNEntries() const { return mNEntriesTotal; } + + void fill(const gsl::span<const AngularResidHistos> input); + void merge(const AngularResidHistos* prev); + void print(); + + private: + // TODO use NCHAMBER instead of MAXCHAMBER and indirection array? + static constexpr float INVBINWIDTH = constants::NBINSANGLEDIFF / (2.f * constants::MAXIMPACTANGLE); + std::array<float, constants::MAXCHAMBER * constants::NBINSANGLEDIFF> mHistogramEntries{}; ///< sum of angular deviation (tracklet to track) for given track angle + std::array<int, constants::MAXCHAMBER * constants::NBINSANGLEDIFF> mNEntriesPerBin{}; ///< number of entries per bin (needed for calculation of mean) + size_t mNEntriesTotal{0}; ///< total number of accumulated angular deviations + + ClassDefNV(AngularResidHistos, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // ALICEO2_ANGRESIDHISTOS_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CTF.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CTF.h new file mode 100644 index 0000000000000..6e8be7604bd03 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CTF.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for TRD CTF data + +#ifndef O2_TRD_CTF_H +#define O2_TRD_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" + +namespace o2 +{ +namespace trd +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t nTracklets = 0; /// number of tracklets + uint32_t nDigits = 0; /// number of digits + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + uint16_t format = 0; /// format word to be added to tracklet + + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded triggers and cells of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 15, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_entriesTrk, + BLC_entriesDig, + BLC_HCIDTrk, // tracklers sorted in HCID -> 1st entry of trigger keeps abs HCID, then increments + BLC_padrowTrk, + BLC_colTrk, + BLC_posTrk, + BLC_slopeTrk, + BLC_pidTrk, + BLC_CIDDig, // digits sorted in CID -> 1st entry of trigger keeps abs CID, then increments + BLC_ROBDig, + BLC_MCMDig, + BLC_chanDig, + BLC_ADCDig + }; + ClassDefNV(CTF, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h new file mode 100644 index 0000000000000..bad9dcfef4e37 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalVdriftExB.h +/// \brief Object with vDrift and ExB values per chamber to be written into the CCDB + +#ifndef ALICEO2_CALVDRIFTEXB_H +#define ALICEO2_CALVDRIFTEXB_H + +#include "DataFormatsTRD/Constants.h" +#include "Rtypes.h" +#include <array> + +namespace o2 +{ +namespace trd +{ + +class CalVdriftExB +{ + public: + CalVdriftExB() = default; + CalVdriftExB(const CalVdriftExB&) = default; + ~CalVdriftExB() = default; + + void setVdrift(int iDet, float vd) { mVdrift[iDet] = vd; } + void setExB(int iDet, float exb) { mExB[iDet] = exb; } + + float getVdrift(int iDet) const { return mVdrift[iDet]; } + float getExB(int iDet) const { return mExB[iDet]; } + + private: + std::array<float, constants::MAXCHAMBER> mVdrift{}; ///< calibrated drift velocity per TRD chamber + std::array<float, constants::MAXCHAMBER> mExB{}; ///< calibrated Lorentz angle per TRD chamber + + ClassDefNV(CalVdriftExB, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // ALICEO2_CALVDRIFTEXB_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalibratedTracklet.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalibratedTracklet.h new file mode 100644 index 0000000000000..c23ad040d9b9f --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalibratedTracklet.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_CALIBRATEDTRACKLET_H +#define O2_TRD_CALIBRATEDTRACKLET_H + +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" + +namespace o2 +{ +namespace trd +{ + +// The CalibratedTracklet has been calibrated in x and dy according to a calculated Lorentz Angle and Drift Velocity. +// Tracklet positions in local z direction are reported at the center of the pad-row. +// Pad-tilting correction is performed after tracking. +class CalibratedTracklet +{ + public: + GPUdDefault() CalibratedTracklet() = default; + GPUd() CalibratedTracklet(float x, float y, float z, float dy) + : mX(x), mY(y), mZ(z), mDy(dy){}; + GPUdDefault() ~CalibratedTracklet() = default; + + GPUd() float getX() const { return mX; } + GPUd() float getY() const { return mY; } + GPUd() float getZ() const { return mZ; } + GPUd() float getDy() const { return mDy; } + + GPUd() void setX(float x) { mX = x; } + GPUd() void setY(float y) { mY = y; } + GPUd() void setZ(float z) { mZ = z; } + GPUd() void setDy(float dy) { mDy = dy; } + + private: + float mX; + float mY; + float mZ; + float mDy; + + ClassDefNV(CalibratedTracklet, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedDigit.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedDigit.h new file mode 100644 index 0000000000000..0a60f9a4de7ca --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedDigit.h @@ -0,0 +1,113 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_TRDCOMPRESSEDDIGIT_H +#define ALICEO2_TRD_TRDCOMPRESSEDDIGIT_H + +#include <cstdint> +#include <array> +#include "Rtypes.h" // for ClassDef +#include "DataFormatsTRD/Constants.h" +#include "fairlogger/Logger.h" +#include "gsl/span" + +namespace o2 +{ +namespace trd +{ + +// Compressed Digit class for TRD +// Notes: +// This is to simplify the handling of raw data that comes in in the same 3 timebins per 32 bit integer format. + +class CompressedDigit +{ + public: + CompressedDigit() = default; + ~CompressedDigit() = default; + CompressedDigit(const int det, const int rob, const int mcm, const int channel, const std::array<uint16_t, constants::TIMEBINS>& adc); + CompressedDigit(const int det, const int rob, const int mcm, const int channel); // add adc data in a seperate step + + // Copy + CompressedDigit(const CompressedDigit&) = default; + // Assignment + CompressedDigit& operator=(const CompressedDigit&) = default; + // Modifiers + void setChannel(int channel) + { + mHeader &= ~(0x003f); + mHeader |= (channel)&0x003f; + } + void setMCM(int mcm) + { + mHeader &= ~(0x3c0); + mHeader |= (mcm)&0x3c0; + } + void setROB(int rob) + { + mHeader &= ~(0x1c00); + mHeader |= (rob)&0x1c00; + } + void setDetector(int det) + { + mHeader &= ~(0x7fe000); + mHeader |= (det << 12) & 0x7fe000; + } + void setADC(std::array<uint16_t, constants::TIMEBINS> const& adcs) + { + int adcindex = 0; + for (auto adc : adcs) { + int rem = adcindex % 3; + // LOG(info) << "adc index :" << adcindex << " rem:" << rem << " adcindex/3=" << adcindex/3; + mADC[adcindex / 3] &= ~((0x3ff) << (rem * 10)); + // LOG(info) << "mADC[adcindex/3] after &= :" << std::hex << mADC[adcindex/3] << rem; + mADC[adcindex / 3] |= (adcs[adcindex] << (rem * 10)); + // LOG(info) << "mADC[adcindex/3] after != :" << std::hex << mADC[adcindex/3] << rem; + adcindex++; + } + } + void setADCi(int index, uint16_t adcvalue) + { + int rem = index % 3; + mADC[index / 3] &= ~((0x3ff) << (rem * 10)); + mADC[index / 3] |= (adcvalue << (rem * 10)); + } + // Get methods + int getChannel() const { return mHeader & 0x3f; } + int getMCM() const { return (mHeader & 0x3c0) >> 6; } + int getROB() const { return (mHeader & 0x1c00) >> 10; } + int getDetector() const { return (mHeader & 0x7fe000) >> 12; } + bool isSharedCompressedDigit() const; + + uint16_t operator[](const int index) { return mADC[index / 3] >> ((index % 3) * 10); } + uint32_t getADCsum() const + { + uint32_t sum = 0; + for (int i = 0; i < constants::TIMEBINS; ++i) { + sum += (mADC[i / 3] >> ((i % 3) * 10)); + } + return sum; + } + + private: + uint32_t mHeader; + // 3322 2222 2222 1111 1111 1100 0000 0000 + // 1098 7654 3210 9876 5432 1098 7654 3210 + // uint32_t: 0000 0000 0DDD DDDD DDDR RRMM MMCC CCCC + // C= channel[5 bits 0-21], M=MCM [4bits 0-15], R=ROB[3bits 0-7], D=Detector[10 bits 0-540] + std::array<uint32_t, 10> mADC; // ADC vector (30 time-bins) packed into 10 32bit integers. + ClassDefNV(CompressedDigit, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedHeader.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedHeader.h new file mode 100644 index 0000000000000..03722b84efd43 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CompressedHeader.h @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +//#include "TRDBase/TRDGeometryBase.h" +//#include "DetectorsCommonDataFormats/DetMatrixCache.h" +//#include "DetectorsCommonDataFormats/DetID.h" + +#ifndef O2_TRD_COMPRESSEDHEADER_H +#define O2_TRD_COMPRESSEDHEADER_H + +//////////////////////////////////////////////////////////////////////////// +// // +// TRD Compressed Header // +// struct to hold the header for the raw compressed data of tracklet64 +// when compression happens on the flp +// Authors // +// Sean Murray (murrays@cern.ch) // +// +//////////////////////////////////////////////////////////////////////////// +#include "Rtypes.h" // for ClassDef +#include "fairlogger/Logger.h" + +namespace o2 +{ +namespace trd +{ +/* |63|62|61|60|59|58|57|56|55|54|53|52|51|50|49|48|47|46|45|44|43|42|41|40|39|38|37|36|35|34|33|32| + ------------------------------------------------------------------------------------------------- +Word 0 | Format | time since frame start | + ------------------------------------------------------------------------------------------------- + |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + ------------------------------------------------------------------------------------------------- +Word 0 | length of data block | + ------------------------------------------------------------------------------------------------- +This is chosen to be a 64 bit word as this is essentially a fake tracklet64 posing as a header. +This then explains the sizes. +Format is 4 bits, we only need 3 formats for now. +*/ +struct CompressedRawHeader { + union { + uint64_t word0; + struct { + uint64_t size : 32; // size of curent block, including this header in 64bit words. + uint64_t eventtime : 28; // time from beginning of the time frame + uint8_t format : 4; // format of data 1=tracklets,2=digits, 3=config. + } __attribute__((__packed__)); + uint64_t word1; // stores the information that will end up in the triggerrecord. + struct { + uint16_t bc : 16; // bunch crossing coming from rdh + uint32_t orbit : 32; // orbit of lhc + uint16_t padding : 16; // 0xeeee + } __attribute__((__packed__)); + }; +}; +//This is simply 64bits of e to mark the end and enable some form of error checking. +//this appears at the end of tracklets. +//i.e. start pointer + header.size -1 == Compressed Trailer position. +struct CompressedRawTrackletDigitSeperator { + union { + uint64_t word; //0xeeeeeexxxxeeeeeeLL where xxxx is the number of digits to follow, max digits on a link is 15*8*16*21 (links*rob*mcm*adc) + //TODO I think is off by a factor of 2 but does not matter, the first 'x' is padded in anycase, so would not save in the hex definition above. + struct { + uint32_t pad2 : 24; // padding e as a marker + uint16_t digitcount : 16; // count of digits to come + uint32_t pad1 : 24; // padding e as marker + } __attribute__((__packed__)); + }; +}; + +/* |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + ------------------------------------------------------------------------------------------------- +Word | detector | rob | mcm | ???????????? | + ------------------------------------------------------------------------------------------------- +time is supplied by the compressedrawheader of the tracklets which is always there. +detector [0-540] 9 bits , rob [0-8] 3 bits , mcm [0-16] 4 += 15 bits ... what to do with the other 17 bits ? +Word of caution, tracklets word size is 64 bit digit word size is 32. +So the raw data has 2 *different* word sizes! +TODO ignoring config data of course. +digits are padded at end with a digit end marker (32 bits of 0xe) and then padded to 64 bits. +i.e. possibly 64 bits of 0xe +TODO in real data are the digits sent in zero suppresed? +*/ + +struct CompressedRawDigitHeader { + union { + uint64_t word; + struct { + uint32_t padding : 16; // padding e as a marker + uint16_t mcm : 4; // count of digits to come + uint16_t rob : 3; // count of digits to come + uint32_t dector : 9; // detector number + } __attribute__((__packed__)); + }; +}; + +struct CompressedRawDigitEndMarker { + uint32_t word; // 0xeeeeeeee can be doubled up to pad to 64bit wide data. +}; + +//For now we ignore config data. +//TODO add config data .... +// +} //namespace trd +} //namespace o2 +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h index 39aa176c0e0a7..0e13f1f15be89 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,12 +28,19 @@ constexpr int NLAYER = 6; // the number of layers constexpr int NCHAMBERPERSEC = 30; // the number of chambers per sector constexpr int MAXCHAMBER = 540; // the maximum number of installed chambers constexpr int NCHAMBER = 521; // the number of chambers actually installed +constexpr int NHALFCRU = 72; // the number of half cru (link bundles) +constexpr int NLINKSPERHALFCRU = 15; // the number of links per half cru or cru end point. +constexpr int NRU = 36; // the number of CRU we have +constexpr int NFLP = 12; // the number of FLP we have. +constexpr int NCRUPERFLP = 3; // the number of CRU per FLP +constexpr int TRDLINKID = 15; // hard coded link id, specific to TRD constexpr int NCOLUMN = 144; // the number of pad columns for each chamber constexpr int NROWC0 = 12; // the number of pad rows for chambers of type C0 (installed stack 0,1,3 and 4) constexpr int NROWC1 = 16; // the number of pad rows for chambers of type C1 (installed in stack 2) constexpr int NMCMROB = 16; // the number of MCMs per ROB +constexpr int NMCMHCMAX = 64; // the maximum number of MCMs for one half chamber (C1 type) constexpr int NMCMROBINROW = 4; // the number of MCMs per ROB in row direction constexpr int NMCMROBINCOL = 4; // the number of MCMs per ROB in column direction constexpr int NROBC0 = 6; // the number of ROBs per C0 chamber @@ -40,9 +48,34 @@ constexpr int NROBC1 = 8; // the number of ROBs per C1 chamber constexpr int NADCMCM = 21; // the number of ADC channels per MCM constexpr int NCOLMCM = 18; // the number of pads per MCM +constexpr int NBITSTRKLPOS = 11; // number of bits for position in tracklet64 word +constexpr int NBITSTRKLSLOPE = 8; // number of bits for slope in tracklet64 word +constexpr float PADGRANULARITYTRKLPOS = 80.f; +constexpr float PADGRANULARITYTRKLSLOPE = 1000.f; +constexpr float GRANULARITYTRKLPOS = 1.f / PADGRANULARITYTRKLPOS; // granularity of position in tracklet64 word in pad-widths +constexpr float GRANULARITYTRKLSLOPE = 1.f / PADGRANULARITYTRKLSLOPE; // granularity of slope in tracklet64 word in pads/timebin + // OS: Should this not be flexible for example in case of Kr calib? constexpr int TIMEBINS = 30; // the number of time bins +constexpr float MAXIMPACTANGLE = 25.f; // the maximum impact angle for tracks relative to the TRD detector plane to be considered for vDrift and ExB calibration +constexpr int NBINSANGLEDIFF = 25; // the number of bins for the track angle used for the vDrift and ExB calibration based on the tracking + +// Trigger parameters +constexpr double READOUT_TIME = 3000; // the time the readout takes, as 30 TB = 3 micro-s. +constexpr double DEAD_TIME = 200; // trigger deadtime, 2 micro-s +constexpr double BUSY_TIME = READOUT_TIME + DEAD_TIME; // the time for which no new trigger can be received in nanoseconds +// array size to store incoming half cru payload. +constexpr int HBFBUFFERMAX = 1048576; // max buffer size for data read from a half cru, (all events) +constexpr int CRUPADDING32 = 0xeeeeeeee; // padding word used in the cru. +constexpr int TRACKLETENDMARKER = 0x10001000; // marker for the end of tracklets in raw data, 2 of these. +constexpr int DIGITENDMARKER = 0x0; // marker for the end of digits in raw data, 2 of these +constexpr int MAXDATAPERLINK32 = 13824; // max number of 32 bit words per link ((21x12+2+4)*64) 64 mcm, 21 channels, 10 words per channel 2 header words(DigitMCMHeader DigitMCMADCmask) 4 words for tracklets. +constexpr int MAXDATAPERLINK256 = 1728; // max number of linkwords per cru link. (256bit words) +constexpr int MAXEVENTCOUNTERSEPERATION = 200; // how far appart can subsequent mcmheader event counters be before we flag for concern, used as a sanity check in rawreader. +constexpr int MAXMCMCOUNT = 69120; // at most mcm count maxchamber x nrobc1 nmcmrob +constexpr int MAXLINKERRORHISTOGRAMS = 10; // size of the array holding the link error plots from the raw reader +constexpr int MAXPARSEERRORHISTOGRAMS = 60; // size of the array holding the parsing error plots from the raw reader } //namespace constants } // namespace trd } // namespace o2 diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h new file mode 100644 index 0000000000000..33f154254ca9a --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_DIGIT_H_ +#define ALICEO2_TRD_DIGIT_H_ + +#include <cstdint> +#include <vector> +#include <array> +#include <unordered_map> +#include <numeric> +#include "Rtypes.h" // for ClassDef + +#include "DataFormatsTRD/HelperMethods.h" +#include "DataFormatsTRD/Constants.h" +#include <gsl/span> + +namespace o2 +{ +namespace trd +{ + +using ADC_t = std::uint16_t; +using ArrayADC = std::array<ADC_t, constants::TIMEBINS>; + +// Digit class for TRD +// Notes: +// Shared pads: +// the lower mcm and rob is chosen for a given shared pad. +// this negates the need for need alternate indexing strategies. +// if you are trying to go from mcm/rob/adc to pad/row and back to mcm/rob/adc , +// you may not end up in the same place, you need to remember to manually check for shared pads. + +class Digit +{ + public: + Digit() = default; + ~Digit() = default; + Digit(const int det, const int row, const int pad, const ArrayADC adc); + Digit(const int det, const int row, const int pad); // add adc data in a seperate step + Digit(const int det, const int rob, const int mcm, const int channel, const ArrayADC adc); + Digit(const int det, const int rob, const int mcm, const int channel); // add adc data in a seperate step + + // Copy + Digit(const Digit&) = default; + // Assignment + Digit& operator=(const Digit&) = default; + // Modifiers + void setROB(int rob) { mROB = rob; } + void setMCM(int mcm) { mMCM = mcm; } + void setROB(int row, int col) { mROB = HelperMethods::getROBfromPad(row, col); } // set ROB from pad row, column + void setMCM(int row, int col) { mMCM = HelperMethods::getMCMfromPad(row, col); } // set MCM from pad row, column + void setChannel(int channel) { mChannel = channel; } + void setDetector(int det) { mDetector = det; } + void setADC(ArrayADC const& adc) { mADC = adc; } + void setADC(const gsl::span<ADC_t>& adc) { std::copy(adc.begin(), adc.end(), mADC.begin()); } + // Get methods + int getDetector() const { return mDetector; } + int getHCId() const { return mDetector * 2 + (mROB % 2); } + int getPadRow() const { return HelperMethods::getPadRowFromMCM(mROB, mMCM); } + int getPadCol() const { return HelperMethods::getPadColFromADC(mROB, mMCM, mChannel); } + int getROB() const { return mROB; } + int getMCM() const { return mMCM; } + int getChannel() const { return mChannel; } + bool isSharedDigit() const; + + ArrayADC const& getADC() const { return mADC; } + ADC_t getADCsum() const { return std::accumulate(mADC.begin(), mADC.end(), (ADC_t)0); } + // returns the max ADC value and sets idx to the time bin with the largest ADC value + ADC_t getADCmax(int& idx) const; + + bool operator==(const Digit& o) const + { + return mDetector == o.mDetector && mROB == o.mROB && mMCM == o.mMCM && mChannel == o.mChannel && mADC == o.mADC; + } + + private: + std::uint16_t mDetector{0}; // detector, the chamber [0-539] + std::uint8_t mROB{0}; // read out board within chamber [0-7] [0-5] depending on C0 or C1 + std::uint8_t mMCM{0}; // MCM chip this digit is attached [0-15] + std::uint8_t mChannel{0}; // channel of this chip the digit is attached to, see TDP chapter ?? TODO fill in later the figure number of ROB to MCM mapping picture + + ArrayADC mADC{}; // ADC vector (30 time-bins) + ClassDefNV(Digit, 3); +}; + +std::ostream& operator<<(std::ostream& stream, const Digit& d); + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h new file mode 100644 index 0000000000000..c1b65bb7930cf --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_HELPERMETHODS_HH +#define ALICEO2_TRD_HELPERMETHODS_HH + +#include "DataFormatsTRD/Constants.h" + +namespace o2 +{ +namespace trd +{ + +struct HelperMethods { + static int getROBfromPad(int irow, int icol) + { + return (irow / constants::NMCMROBINROW) * 2 + getColSide(icol); + } + + static int getMCMfromPad(int irow, int icol) + { + if (irow < 0 || icol < 0 || irow > constants::NROWC1 || icol > constants::NCOLUMN) { + return -1; + } + return (icol % (constants::NCOLUMN / 2)) / constants::NCOLMCM + constants::NMCMROBINCOL * (irow % constants::NMCMROBINROW); + } + + static int getColSide(int icol) + { + if (icol < 0 || icol >= constants::NCOLUMN) { + return -1; + } + + return icol / (constants::NCOLUMN / 2); + } + + static int getPadRowFromMCM(int irob, int imcm) + { + return constants::NMCMROBINROW * (irob / 2) + imcm / constants::NMCMROBINCOL; + } + + static int getPadColFromADC(int irob, int imcm, int iadc) + { + if (iadc < 0 || iadc > constants::NADCMCM) { + return -100; + } + int mcmcol = imcm % constants::NMCMROBINCOL + getROBSide(irob) * constants::NMCMROBINCOL; // MCM column number on ROC [0..7] + int padcol = mcmcol * constants::NCOLMCM + constants::NCOLMCM + 1 - iadc; + if (padcol < 0 || padcol >= constants::NCOLUMN) { + return -1; // this is commented because of reason above OK + } + return padcol; + } + + static int getROBSide(int irob) + { + if (irob < 0 || irob >= constants::NROBC1) { + return -1; + } + return irob % 2; + } + + static int getSector(int det) + { + return det / constants::NCHAMBERPERSEC; + } + + static int getStack(int det) + { + return det % (constants::NSTACK * constants::NLAYER) / constants::NLAYER; + } + static int getLayer(int det) + { + return det % constants::NLAYER; + } + + static int getORIinSuperModule(int detector, int readoutboard) + { + //given a detector and readoutboard + int ori = -1; + int trdstack = HelperMethods::getStack(detector); + int trdlayer = HelperMethods::getLayer(detector); + int side = HelperMethods::getROBSide(readoutboard); + //TODO ccdb lookup of detector/stack/layer/side for link id. + bool aside = false; + if (trdstack == 0 || trdstack == 1) { + aside = true; //aside + } else { + if (trdstack != 2) { + aside = false; //cside + } else { + if (side == 0) { + aside = true; //stack + } else { + aside = false; //stack2, halfchamber 1 + } + } + } + if (aside) { + ori = trdstack * 12 + (5 - trdlayer + side * 5) + trdlayer / 6 + side; // <- that is correct for A side at least for now, probably not for very long LUT as that will come form CCDB ni anycase. + } else { + //cside + int newside = side; + if (trdstack == 2) { + newside = 0; // the last part of C side CRU is a special case. + } + ori = (4 - trdstack) * 12 + (5 - trdlayer + newside * 5) + trdlayer / 6 + newside; + ori += 30; // 30 to offset if from the a side link , 69 links in total + } + //see TDP for explanation of mapping TODO should probably come from CCDB + return ori; + } + + static int getLinkIDfromHCID(int hcid) + { + //return a number in range [0:29] for the link related to this hcid with in its respective CRU + //lower 15 is endpoint 0 and upper 15 is endpoint 1 + //a side has 30, c side has 30 to give 60 links for a supermodule + int detector = hcid / 2; + int supermodule = hcid / 60; + int chamberside = hcid % 2; // 0 for side 0, 1 for side 1; + int ori = -1; + // now offset for supermodule (+60*supermodule); + return HelperMethods::getORIinSuperModule(detector, chamberside) + 60 * supermodule; // it takes readoutboard but only cares if its odd or even hence side here. + } + + inline static void swapByteOrder(unsigned int& word) + { + word = (word >> 24) | + ((word << 8) & 0x00FF0000) | + ((word >> 8) & 0x0000FF00) | + (word << 24); + } + inline static unsigned int swapByteOrderreturn(unsigned int word) + { + // word = (word >> 24) | + // ((word << 8) & 0x00FF0000) | + // ((word >> 8) & 0x0000FF00) | + // (word << 24); + return word; + } +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Hit.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Hit.h new file mode 100644 index 0000000000000..2b370633f8eeb --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Hit.h @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_HIT_H_ +#define ALICEO2_TRD_HIT_H_ + +#include <vector> +#include "DetectorsBase/Detector.h" +#include "SimulationDataFormat/BaseHits.h" +#include "CommonUtils/ShmAllocator.h" + +namespace o2::trd +{ + +class Hit : public o2::BasicXYZQHit<float> +{ + public: + using BasicXYZQHit<float>::BasicXYZQHit; + Hit(float x, float y, float z, float lCol, float lRow, float lTime, float tof, int charge, int trackId, int detId, bool drift) + : mInDrift(drift), locC(lCol), locR(lRow), locT(lTime), BasicXYZQHit(x, y, z, tof, charge, trackId, detId){}; + bool isFromDriftRegion() const { return mInDrift; } + void setLocalC(float lCol) { locC = lCol; } + void setLocalR(float lRow) { locR = lRow; } + void setLocalT(float lTime) { locT = lTime; } + float getLocalC() const { return locC; } + float getLocalR() const { return locR; } + float getLocalT() const { return locT; } + + private: + bool mInDrift{false}; + float locC{-99}; // col direction in amplification or drift volume + float locR{-99}; // row direction in amplification or drift volume + float locT{-99}; // time direction in amplification or drift volume + + ClassDefNV(Hit, 1); +}; +} // namespace o2::trd + +#ifdef USESHM +namespace std +{ +template <> +class allocator<o2::trd::Hit> : public o2::utils::ShmAllocator<o2::trd::Hit> +{ +}; +} // namespace std +#endif + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrCluster.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrCluster.h new file mode 100644 index 0000000000000..68b1475467b54 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrCluster.h @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrCluster.h +/// \brief A cluster formed from digits during TRD Krypton calibration + +#ifndef O2_TRD_KRCLUSTER_H +#define O2_TRD_KRCLUSTER_H + +#include "Rtypes.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/HelperMethods.h" + +namespace o2 +{ +namespace trd +{ + +class KrCluster +{ + public: + KrCluster() = default; + KrCluster(const KrCluster&) = default; + ~KrCluster() = default; + + void setGlobalPadID(int det, int row, int col); + void setAdcData(int adcSum, int adcRms, int adcMaxA, int adcMaxB, int adcEoT, int adcIntegral, int adcSumTrunc); + void setTimeData(int timeMaxA, int timeMaxB, int timeRms); + void setClusterSizeData(int rowSize, int colSize, int timeSize, int nAdcs); + + // identify global pad number (row and column with the maximum ADC value contained in the cluster) + int getDetector() const { return mDet; } + int getSector() const { return HelperMethods::getSector(mDet); } + int getStack() const { return HelperMethods::getStack(mDet); } + int getLayer() const { return HelperMethods::getLayer(mDet); } + int getRow() const { return mRow; } + int getColumn() const { return mCol; } + + // ADC related members + int getAdcSum() const { return mAdcSum; } + int getAdcRms() const { return mAdcRms; } + int getAdcMaxA() const { return mAdcMaxA; } + int getAdcMaxB() const { return mAdcMaxB; } + int getAdcSumEoverT() const { return mAdcSumEoverT; } + int getAdcIntegral() const { return mAdcIntegral; } + int getAdcSumTruncated() const { return mAdcSumTruncated; } + + // cluster size + int getClSizeRow() const { return mDeltaRow; } + int getClSizeCol() const { return mDeltaCol; } + int getClSizeTime() const { return mDeltaTime; } + int getClSize() const { return mClusterSize; } + + // time bin related members + int getTimeMaxA() const { return mTimeMaxA; } + int getTimeMaxB() const { return mTimeMaxB; } + int getTimeRms() const { return mTimeRms; } + + private: + uint16_t mDet; ///< chamber number [0..539] + uint16_t mAdcSum; ///< sum of all ADCs contributing to this cluster (baseline subtracted) + uint16_t mAdcRms; ///< RMS of the ADCs constributing to this cluster + uint16_t mAdcMaxA; ///< sum of the ADCs of the first maximum + uint16_t mAdcMaxB; ///< sum of the ADCs of the second maximum (the contribution from the first maximum is subtracted here) + uint16_t mAdcSumEoverT; ///< same as mAdcSum, but ADCs below KrClusterFinder::mMinAdcClEoverT are ignored + uint16_t mAdcIntegral; ///< integral of the Landau fit for all time bins + uint16_t mAdcSumTruncated; ///< same as mAdcSum, but only ADCs close to the RMS are counted + uint8_t mRow; ///< pad row number contributing max ADC value contained in this cluster [0..15] + uint8_t mCol; ///< pad column number contributing max ADC value contained in this cluster [0..143] + uint8_t mDeltaRow; ///< cluster size in row direction + uint8_t mDeltaCol; ///< cluster size in column direction + uint8_t mDeltaTime; ///< cluster size in time bin direction + uint8_t mClusterSize; ///< number of ADC values contributing to the cluster (ADC needs to be above KrClusterFinder::mMinAdcClContrib) + uint8_t mTimeMaxA; ///< time bin of the first maximum + uint8_t mTimeMaxB; ///< time bin of the second maximum + uint8_t mTimeRms; ///< RMS of the time bins for ADCs contributing to this cluster + + ClassDefNV(KrCluster, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_KRCLUSTER_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrClusterTriggerRecord.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrClusterTriggerRecord.h new file mode 100644 index 0000000000000..6818814fe31d2 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/KrClusterTriggerRecord.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_KRCLSTRIGGERRECORD_H +#define ALICEO2_TRD_KRCLSTRIGGERRECORD_H + +#include "Rtypes.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" + +namespace o2 +{ +namespace trd +{ + +/// \class KrClusterTriggerRecord +/// \brief Mapping of found Kr clusters to BC information which is taken from the TRD digits +/// \author Ole Schmidt + +class KrClusterTriggerRecord +{ + using BCData = o2::InteractionRecord; + + public: + KrClusterTriggerRecord() = default; + KrClusterTriggerRecord(BCData bcData, int nEntries) : mBCData(bcData), mNClusters(nEntries) {} + + // setters (currently class members are set at the time of creation, if there is need to change them afterwards setters can be added below) + + // getters + int getNumberOfClusters() const { return mNClusters; } + BCData getBCData() const { return mBCData; } + + private: + BCData mBCData; ///< bunch crossing data + int mNClusters; ///< number of Kr clusters + + ClassDefNV(KrClusterTriggerRecord, 1); +}; +} // namespace trd +} // namespace o2 + +#endif // ALICEO2_TRD_KRCLSTRIGGERRECORD_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h index dccb1a4f73532..23a35b692ff7a 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,19 +31,6 @@ class LinkRecord { using DataRange = o2::dataformats::RangeReference<int>; - struct LinkId { - union { - uint16_t word; - struct { - uint16_t spare : 4; - uint16_t side : 1; - uint16_t layer : 3; - uint16_t stack : 3; - uint16_t supermodule : 5; - }; - }; - }; - public: LinkRecord() = default; LinkRecord(const uint32_t linkid, int firstentry, int nentries) : mDataRange(firstentry, nentries) { mLinkId = linkid; } @@ -52,24 +40,40 @@ class LinkRecord ~LinkRecord() = default; void setLinkId(const uint32_t linkid) { mLinkId = linkid; } - // void setLinkId(const LinkId linkid) { mLinkId = linkid; } void setLinkId(const uint32_t sector, const uint32_t stack, const uint32_t layer, const uint32_t side); void setDataRange(int firstentry, int nentries) { mDataRange.set(firstentry, nentries); } void setIndexFirstObject(int firstentry) { mDataRange.setFirstEntry(firstentry); } void setNumberOfObjects(int nentries) { mDataRange.setEntries(nentries); } + void setSector(const int sector) { mLinkId |= ((sector << supermodulebs) & supermodulemask); } + void setStack(const int stack) { mLinkId |= ((stack << stackbs) & stackmask); } + void setLayer(const int layer) { mLinkId |= ((layer << layerbs) & layermask); } + void setSide(const int side) { mLinkId |= ((side << sidebs) & sidemask); } + void setSpare(const int spare = 0) { mLinkId |= ((spare << sparebs) & sparemask); } const uint32_t getLinkId() { return mLinkId; } //TODO come backwith a ccdb lookup. const uint32_t getLinkHCID() { return mLinkId & 0x7ff; } // the last 11 bits. - const uint32_t getSector() { return (mLinkId & 0xf800) >> 11; } - const uint32_t getStack() { return (mLinkId & 0x700) >> 8; } - const uint32_t getLayer() { return (mLinkId & 0xe0) >> 5; } - const uint32_t getSide() { return (mLinkId & 0x10) >> 4; } + const uint32_t getSector() { return (mLinkId & supermodulemask) >> supermodulebs; } + const uint32_t getStack() { return (mLinkId & stackmask) >> stackbs; } + const uint32_t getLayer() { return (mLinkId & layermask) >> layerbs; } + const uint32_t getSide() { return (mLinkId & sidemask) >> sidebs; } int getNumberOfObjects() const { return mDataRange.getEntries(); } int getFirstEntry() const { return mDataRange.getFirstEntry(); } static uint32_t getHalfChamberLinkId(uint32_t detector, uint32_t rob); static uint32_t getHalfChamberLinkId(uint32_t sector, uint32_t stack, uint32_t layer, uint32_t side); void printStream(std::ostream& stream); + // bit masks for the above raw data; + static constexpr uint64_t sparemask = 0x000f; + static constexpr uint64_t sidemask = 0x0010; + static constexpr uint64_t layermask = 0x00e0; + static constexpr uint64_t stackmask = 0x0700; + static constexpr uint64_t supermodulemask = 0xf800; + //bit shifts for the above raw data + static constexpr uint64_t sparebs = 0; + static constexpr uint64_t sidebs = 4; + static constexpr uint64_t layerbs = 5; + static constexpr uint64_t stackbs = 8; + static constexpr uint64_t supermodulebs = 11; private: uint16_t mLinkId; @@ -81,10 +85,8 @@ std::ostream& operator<<(std::ostream& stream, LinkRecord& trg); extern void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format); extern void buildTrakcletHCHeader(TrackletHCHeader& header, int detector, int rob, int chipclock, int format); -} // namespace trd +} // namespace trd } // namespace o2 #endif -//extern void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format) -//extern void buildTrakcletlHCHeader(TrackletHCHeader& header, int detector, int rob, int chipclock, int format) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h index 678138301c9d6..21bf20b2b1340 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,8 +43,8 @@ Word 1 | link 7 error flags | link 6 error flags | link 5 error flags ------------------------------------------------------------------------------------------------- Word 2 | link 11 error flags | link 10 error flags | link 9 error flags | link 8 error flags | ------------------------------------------------------------------------------------------------- -Word 2 | link 12 error flags | link 13 error flags | link 14 error flags | reserved 2 | - ------------------------------------------------------------------------------------------------- +Word 2 | reserved 2 | link 14 error flags | link 13 error flags | link 12 error flags | + ------------------------------------------------------------------------------------------------ Word 3 | reserved 3 | ------------------------------------------------------------------------------------------------- Word 3 | reserved 4 | @@ -80,7 +81,8 @@ Word 7 | reserved 5 | link 14 da // |---------------------------------------------------------------- 32..63 reserved1 struct { uint64_t HeaderVersion : 8; // TRD Header Version - uint64_t BunchCrossing : 12; // bunch crossing + uint64_t BunchCrossing : 12; // bunch crossing of the physics trigger. + //NB The BC in the RDH is the BC sent together with the heartbeat trigger, while the BC in the HalfCRUHeader is the BC of the physics trigger where the data that follows the HalfCRUHeader belongs to. However, it is not forbidden for CTP to send the heartbeat trigger together with a physics trigger, in this case the two would match (accidentally). uint64_t StopBit : 4; // 8 .. 11 stop bit 0x1 if TRD packet is last data packet of trigger, else 0x0 TODO why 4 bits if only using 1? uint64_t EndPoint : 4; // bit 0..7 event type of the data. Trigger bits from TTC-PON message, distinguish physics from calibration events. uint64_t EventType : 4; // bit 0..7 event type of the data. Trigger bits from TTC-PON message, distinguish physics from calibration events. @@ -122,7 +124,7 @@ Word 7 | reserved 5 | link 14 da struct TrackletHCHeader { union { // 10987654321098765432109876543210 - // uint32_t: 00000000000000000000000000000000 + // uint32_t: 33222222222211111111110000000000 // cccccccccccccccX LLL SSSSS // ffff| |y| sss| // | | ||| | |----- 0-4 supermodule @@ -130,7 +132,7 @@ struct TrackletHCHeader { // | | ||------------ 8-10 layer // | | |------------- 11 always 0x1 // | | |------------- 12 side of chamber - // | ----------------------------- 13-72 MCM Clock counter + // | ----------------------------- 13-27 MCM Clock counter // --------------------------------- 28-31 tracklet data format number uint32_t word; struct { @@ -139,7 +141,7 @@ struct TrackletHCHeader { uint32_t layer : 3; uint32_t one : 1; //always 1 uint32_t side : 1; // side of chamber - uint32_t MCLK : 15; // MCM clock counter 120MHz ... for simulation -- incrementing, and same number in all for each event. + uint32_t MCLK : 15; // MCM clock counter 120MHz ... for simulation -- incrementing, and uniform across an event uint32_t format : 4; // 0 baseline PID 3 time slices, 7 bit each // 1 DO NOT USE ! reserved for tracklet end marker disambiguation @@ -155,7 +157,7 @@ struct TrackletHCHeader { struct TrackletMCMHeader { //first word * // 10987654321098765432109876543210 - // uint32_t: 00000000000000000000000000000000 + // uint32_t: 33222222222211111111110000000000 // 1zzzz pppppppp pppppppp1 // || yy| pppppppp | |--- 0 1 check bits // || | | | ----------- 1-8 pid for tracklet 3 second part @@ -169,7 +171,7 @@ struct TrackletMCMHeader { uint32_t word; struct { uint32_t oneb : 1; // - uint32_t pid0 : 8; // part of pid for tracklet 0 + uint32_t pid0 : 8; // part of pid for tracklet 0 // 6 bits of Q2 and 2 bits of Q1 uint32_t pid1 : 8; // part of pid for tracklet 1 uint32_t pid2 : 8; // part of pid for tracklet 2 uint32_t col : 2; // 2 bits for position in pad direction. @@ -182,14 +184,14 @@ struct TrackletMCMHeader { // \structure TrackletMCMData. // \brief Raw Data of a tracklet, part is how ever in the MCM Header hence both are grouped together in the same file -struct TrackletMCMData { // This is a bad name as part of the tracklet data is in the MCMHeader. +struct TrackletMCMData { union { uint32_t word; struct { uint8_t checkbit : 1; // - uint16_t slope : 6; // Deflection angle of tracklet - uint16_t pid : 15; // Particle Identity - uint16_t pos : 10; // Position of tracklet, signed 10 bits, granularity 0.02 pad widths, -10.22 to +10.22, relative to centre of pad 10 + uint16_t slope : 8; // Deflection angle of tracklet + uint16_t pid : 12; // Particle Identity 7 bits of Q0 and 5 bits of Q1 + uint16_t pos : 11; // Position of tracklet, signed 11 bits, granularity 1/80 pad widths, -12.80 to +12.80, relative to centre of pad 10 } __attribute__((__packed__)); }; }; @@ -218,26 +220,240 @@ struct TRDFeeID { }; }; +/// \structure DigitHCHeader +/// \brief Digit version of the TrackletHCHeader above, although contents are rather different. +// TODO come back and comment the fields or make the name more expressive, and fill in the jjjjjjj +struct DigitHCHeader { + // + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + // + union { // section 15.6.1 in tdp + uint32_t word; + struct { + uint32_t res : 2; + uint32_t side : 1; + uint32_t stack : 3; + uint32_t layer : 3; + uint32_t supermodule : 5; + uint32_t numberHCW : 3; + uint32_t minor : 7; + uint32_t major : 7; + uint32_t version : 1; + } __attribute__((__packed__)); + }; +}; +//The next hcheaders are all optional, there can be 8, we only have 3 for now. +//They can all be distinguished by their res. +struct DigitHCHeader1 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + // + union { //section 15.6.2 in tdp + uint32_t word; + struct { + uint32_t res : 2; + uint32_t ptrigcount : 4; + uint32_t ptrigphase : 4; + uint32_t bunchcrossing : 16; + uint32_t numtimebins : 6; + } __attribute__((__packed__)); + }; +}; +struct DigitHCHeader2 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { //section 15.6.3 in tdp + uint32_t word; + struct { + uint32_t res : 6; + uint32_t dfilter : 6; + uint32_t rfilter : 1; + uint32_t nlfilter : 1; + uint32_t xtfilter : 1; + uint32_t tfilter : 1; + uint32_t gfilter : 1; + uint32_t pfilter : 6; + } __attribute__((__packed__)); + }; +}; +struct DigitHCHeader3 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { //section 15.6.4 in tdp + uint32_t word; + struct { + uint32_t res : 6; + uint32_t svnrver : 13; //readout program svn revision + uint32_t svnver : 13; //assember programm svn revision + } __attribute__((__packed__)); + }; +}; + +struct DigitMCMHeader { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { + uint32_t word; //MCM header + struct { + uint32_t res : 4; // reserve 1100 + uint32_t eventcount : 20; + uint32_t mcm : 4; + uint32_t rob : 3; + uint32_t yearflag : 1; //< oct2007 0, else 1 + } __attribute__((__packed__)); + }; +}; + +// digit mask used for the zero suppressed digit data +struct DigitMCMADCMask { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { + uint32_t word; //MCM ADC MASK header + struct { + uint32_t j : 4; // 0xc + uint32_t adcmask : 21; + uint32_t c : 5; // ~(number of bits set in adcmask) + uint32_t n : 2; // 0b01 + } __attribute__((__packed__)); + }; +}; + +//the odd numbering of 1 2 3 and 6 are taken from the TDP page 111 section 15.7.2, 15.7.3 15.7.4 15.7.5 +struct trdTestPattern1 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + // 11h41 for 2flp in data stream. before that on 14th dec was1 flp in timeframe. + union { + uint32_t word; + struct { + uint32_t eventcount : 6; // lower 6 bits of e counter. + uint32_t stack : 5; + uint32_t layer : 3; + uint32_t roc : 3; + uint32_t rob : 3; + uint32_t mcmTp2 : 4; + uint32_t cpu : 2; + uint32_t counter : 6; + } __attribute__((__packed__)); + }; +}; + +struct trdTestPattern2 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { + uint32_t word; + struct { + uint32_t eventcount : 6; // lower 6 bits of e counter. + uint32_t stack : 5; + uint32_t layer : 3; + uint32_t roc : 3; + uint32_t rob : 3; + uint32_t mcmTp2 : 4; + uint32_t cpu : 2; + uint32_t wordcounter : 6; + } __attribute__((__packed__)); + }; +}; +struct trdTestPattern3 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + union { + uint32_t word; + struct { + uint32_t eventcount : 12; //lower 12 bits of ecounter + uint32_t stack : 5; + uint32_t layer : 3; + uint32_t roc : 3; + uint32_t rob : 3; + uint32_t mcm : 4; + uint32_t cpu : 2; + } __attribute__((__packed__)); + }; +}; +struct trdTestPattern6 { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + // 1zzzz pppppppp pppppppp1 + union { + uint32_t word; //HC header0 + struct { + uint32_t eventcount; // lower 4 bits of e counter. + uint32_t stack : 5; // starting at 1 + uint32_t layer : 3; + uint32_t roc : 3; + uint32_t rob : 3; + uint32_t mcm : 4; + uint32_t cpu : 2; + uint32_t wordcounter : 6; + uint32_t oddadc : 2; + } __attribute__((__packed__)); + }; +}; + +struct DigitMCMData { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + /* union { + uint32_t word0; + struct { + uint32_t a : 2; + uint32_t b : 5; + uint32_t adc : 21; //adc bit patternpad plane + } __attribute__((__packed__)); + };*/ + union { + // 10987654321098765432109876543210 + // uint32_t: 00000000000000000000000000000000 + uint32_t word; + struct { + uint32_t c : 2; // c is wrong I cant remember name, but not a concern at the moment. + uint32_t z : 10; + uint32_t y : 10; + uint32_t x : 10; + } __attribute__((__packed__)); + }; +}; + void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format); void buildTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int chipclock, int format); uint16_t buildTRDFeeID(int supermodule, int side, int endpoint); uint32_t setHalfCRUHeader(HalfCRUHeader& cruhead, int crurdhversion, int bunchcrossing, int stopbits, int endpoint, int eventtype, int feeid, int cruid); uint32_t setHalfCRUHeaderLinkData(HalfCRUHeader& cruhead, int link, int size, int errors); +void buildTrackletMCMData(TrackletMCMData& trackletword, const uint slope, const uint pos, const uint q0, const uint q1, const uint q2); uint32_t unpacklinkinfo(const HalfCRUHeader& cruhead, const uint32_t link, const bool data); uint32_t getlinkerrorflag(const HalfCRUHeader& cruhead, const uint32_t link); uint32_t getlinkdatasize(const HalfCRUHeader& cruhead, const uint32_t link); uint32_t getlinkerrorflags(const HalfCRUHeader& cruheader, std::array<uint32_t, 15>& linkerrorflags); uint32_t getlinkdatasizes(const HalfCRUHeader& cruheader, std::array<uint32_t, 15>& linksizes); -std::ostream& operator<<(std::ostream& stream, const TrackletHCHeader halfchamberheader); +uint32_t getQFromRaw(const o2::trd::TrackletMCMHeader* header, const o2::trd::TrackletMCMData* data, int pidindex, int trackletindex); +uint32_t getHCIDFromTrackletHCHeader(const TrackletHCHeader& header); +uint32_t getHCIDFromTrackletHCHeader(const uint32_t& headerword); +std::ostream& operator<<(std::ostream& stream, const TrackletHCHeader& halfchamberheader); +std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& mcmhead); std::ostream& operator<<(std::ostream& stream, const TrackletMCMData& tracklet); void printTrackletMCMData(o2::trd::TrackletMCMData& tracklet); void printTrackletMCMHeader(o2::trd::TrackletMCMHeader& mcmhead); -std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& mcmhead); void printHalfChamber(o2::trd::TrackletHCHeader& halfchamber); void dumpHalfChamber(o2::trd::TrackletHCHeader& halfchamber); void printHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); void dumpHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); +void clearHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); std::ostream& operator<<(std::ostream& stream, const HalfCRUHeader& halfcru); +bool trackletMCMHeaderSanityCheck(o2::trd::TrackletMCMHeader& header); +bool trackletHCHeaderSanityCheck(o2::trd::TrackletHCHeader& header); +bool digitMCMHeaderSanityCheck(o2::trd::DigitMCMHeader* header); +bool digitMCMADCMaskSanityCheck(o2::trd::DigitMCMADCMask& mask, int numberofbitsset); +bool digitMCMWordSanityCheck(o2::trd::DigitMCMData* word, int adcchannel); +void printDigitMCMHeader(o2::trd::DigitMCMHeader& header); +int getDigitHCHeaderWordType(uint32_t word); +void printDigitHCHeader(o2::trd::DigitHCHeader& header, uint32_t headers[3]); +DigitMCMADCMask buildBlankADCMask(); +int getNumberofTracklets(o2::trd::TrackletMCMHeader& header); +void setNumberOfTrackletsInHeader(o2::trd::TrackletMCMHeader& header, int numberoftracklets); +int nextmcmadc(unsigned int& bp, int channel); } } #endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h new file mode 100644 index 0000000000000..81ccf440e8f88 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h @@ -0,0 +1,139 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Cru raw data reader, this is the part that parses the raw data +// it runs on the flp(pre compression) or on the epn(pre tracklet64 array generation) +// it hands off blocks of cru pay load to the parsers. + +#ifndef O2_TRD_RAWDATASTATS +#define O2_TRD_RAWDATASTATS + +#include <iostream> +#include <string> +#include <cstdint> +#include <array> +#include <vector> +#include <bitset> +#include <gsl/span> +#include "DataFormatsTRD/Constants.h" + +namespace o2::trd +{ +enum ParsingErrors { TRDParsingNoError, + TRDParsingUnrecognisedVersion, + TRDParsingBadDigt, + TRDParsingBadTracklet, + TRDParsingDigitEndMarkerWrongState, // read a end marker but we were expecting something else due to + TRDParsingDigitMCMHeaderSanityCheckFailure, //essentially we did not see an MCM header see RawData.h for requirement + TRDParsingDigitROBDecreasing, // sequential headers must have the same or increasing rob number + TRDParsingDigitMCMNotIncreasing, // sequential headers must have increasing mcm number + TRDParsingDigitADCMaskMismatch, // mask adc count does not match # of 1s in bitpattern + TRDParsingDigitADCMaskAdvanceToEnd, // in advancing to adcmask we have reached the end of the buffer + TRDParsingDigitMCMHeaderBypassButStateMCMHeader, // we are reading mcmadc data but the state is mcmheader + TRDParsingDigitEndMarkerStateButReadingMCMADCData, // read the endmarker while expecting to read the mcmadcdata + TRDParsingDigitADCChannel21, // ADCMask is zero but we are still on a digit. + TRDParsingDigitADCChannelGT22, // error allocating digit, so digit channel has error value + TRDParsingDigitGT10ADCs, // more than 10 adc data words seen + TRDParsingDigitSanityCheck, // adc failed sanity check see RawData.cxx for faiulre reasons + TRDParsingDigitExcessTimeBins, // ADC has more than 30 timebins (10 adc words) + TRDParsingDigitParsingExitInWrongState, // exiting parsing in the wrong state ... got to the end of the buffer in wrong state. + TRDParsingDigitStackMismatch, // mismatch between rdh and hcheader stack calculation/value + TRDParsingDigitLayerMismatch, // mismatch between rdh and hcheader stack calculation/value + TRDParsingDigitSectorMismatch, // mismatch between rdh and hcheader stack calculation/value + TRDParsingTrackletCRUPaddingWhileParsingTracklets, // reading a padding word while expecting tracklet data + TRDParsingTrackletBit11NotSetInTrackletHCHeader, // bit 11 not set in hc header for tracklets. + TRDParsingTrackletHCHeaderSanityCheckFailure, // HCHeader sanity check failure, see RawData.cxx for reasons. + TRDParsingTrackletMCMHeaderSanityCheckFailure, // MCMHeader sanity check failure, see RawData.cxx for reasons. + TRDParsingTrackletMCMHeaderButParsingMCMData, // state is still MCMHeader but we are parsing MCMData + TRDParsingTrackletStateMCMHeaderButParsingMCMData, + TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader, //mcmheader tracklet count does not match that in we have parsed. + TRDParsingTrackletInvalidTrackletCount, // invalid tracklet count in header vs data + TRDParsingTrackletPadRowIncreaseError, // subsequent padrow can not be less than previous one. + TRDParsingTrackletColIncreaseError, // subsequent col can not be less than previous one + TRDParsingTrackletNoTrackletEndMarker, // got to the end of the buffer with out finding a tracklet end marker. + TRDParsingTrackletExitingNoTrackletEndMarker, // got to the end of the buffer exiting tracklet parsing with no tracklet end marker + TRDParsingDigitHeaderCountGT3, // digital half chamber header had more than 3 additional words expected by header. most likely corruption above somewhere. + TRDParsingDigitHeaderWrong1, // expected header word1 but wrong ending marker + TRDParsingDigitHeaderWrong2, // expected header word2 but wrong ending marker + TRDParsingDigitHeaderWrong3, // expected header word3 but wrong ending marker + TRDParsingDigitHeaderWrong4, // expected header word but have no idea what we are looking at default of switch statement + TRDParsingDigitDataStillOnLink, // got to the end of digit parsing and there is still data on link, normally not advancing far enough when dumping data. + TRDParsingTrackletIgnoringDataTillEndMarker // for some reason we are bouncing to the end word by word, this counts those words +}; + +extern std::vector<std::string> ParsingErrorsString; + +//enumerations for the options, saves on having a long parameter list. +enum OptionBits { + TRDByteSwapBit, + TRDVerboseBit, + TRDHeaderVerboseBit, + TRDDataVerboseBit, + TRDCompressedDataBit, + TRDFixDigitCorruptionBit, + TRDEnableTimeInfoBit, + TRDEnableStatsBit, + TRDIgnoreDigitHCHeaderBit, + TRDIgnoreTrackletHCHeaderBit, + TRDEnableRootOutputBit +}; + +class TRDDataCountersPerEvent +{ //thisis on a per event basis + public: + //TODO this should go into a dpl message for catching by qc ?? I think. + uint64_t mTimeTaken; // time take to process an event (summed trackletparsing and digitparsing) parts not accounted for. + uint64_t mTimeTakenForDigits; // time take to process tracklet data blocks [us]. + uint64_t mTimeTakenForTracklets; // time take to process digit data blocks [us]. + uint64_t mDigitWordsRead; // digit words read in + uint64_t mDigitWordsSkipped; // digit words skipped for various reasons. + uint64_t mTrackletWordsRead; // tracklet words read in + uint64_t mTrackletWordsSkipped; // tracklet words skipped for various reasons. + std::array<uint8_t, 1080> mLinkErrorFlag{}; //status of the error flags for this event, 8bit values from cru halfchamber header. +}; + +class TRDDataCountersPerTimeFrame +{ //thisis on a per event basis + public: + std::array<uint32_t, 1080> mLinkNoData; // Link had no data or was not present. + std::array<uint32_t, 1080> mLinkWords{}; //units of 256bits, read from the cru half chamber header + std::array<uint32_t, 1080> mLinkWordsRead{}; // units of 32 bits the data words read before dumping or finishing + std::array<uint32_t, 1080> mLinkWordsDumped{}; // units of 32 bits the data dumped due to some or other error + std::array<int64_t, o2::trd::constants::MAXMCMCOUNT> mLinkMCMsWithData{}; // and its corresponding volume of data. + std::array<uint32_t, constants::MAXMCMCOUNT> mMCMDigitCount{}; + std::array<uint32_t, constants::MAXMCMCOUNT> mMCMTrackletCount{}; + std::array<uint32_t, 30> mParsingErrors{}; // errors in parsing, indexed by enum above of ParsingErrors + std::array<uint32_t, 1080 * 30> mParsingErrorsByLink{}; // errors in parsing, indexed by enum above of ParsingErrors + uint64_t mTimeTaken; // time taken to process the entire timeframe [ms]. + uint64_t mTimeTakenForDigits; // time take to process tracklet data blocks [us]. + uint64_t mTimeTakenForTracklets; // time take to process digit data blocks [us]. + uint64_t mDigitsFound; // digit found in the time frame. + uint64_t mTrackletsFound; // tracklets found in the time frame. + uint64_t mDigitWordsRead; // digit words read in. + uint64_t mDigitWordsSkipped; // digit words skipped for various reasons. + uint64_t mTrackletWordsRead; // tracklet words read in. + uint64_t mTrackletWordsSkipped; // tracklet words skipped for various reasons. + uint64_t mDataWordsRead; + uint64_t mDataWordsRejected; + //TRDDataCountersPerTimeFrame* operator=(TRDDataCountersPerTimeFrame *old){this=old;return *this;} +}; + +//TODO not sure this class is needed +class TRDDataCountersRunning +{ //those counters that keep counting + std::array<uint32_t, 1080> mLinkFreq{}; //units of 256bits "cru word" + std::array<bool, 1080> mLinkEmpty{}; // Link only has padding words only, probably not serious. + std::array<uint64_t, 65535> mDataFormatRead{}; // 7bits.7bits major.minor version read from HCHeader. +}; + +} // namespace o2::trd + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h new file mode 100644 index 0000000000000..21a079ec0df77 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoInputContainer.h +/// \author ole.schmidt@cern.ch +/// \brief Struct for input data required by TRD tracking workflow + +#ifndef O2_TRD_RECOINPUTCONTAINER_H +#define O2_TRD_RECOINPUTCONTAINER_H + +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "CommonConstants/LHCConstants.h" +#include "Framework/ProcessingContext.h" +#include "Framework/InputRecord.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +#include "GPUDataTypes.h" + +#include <gsl/span> +#include <memory> + +namespace o2 +{ +namespace trd +{ + +struct RecoInputContainer { + gsl::span<const o2::trd::Tracklet64> mTracklets; + gsl::span<const o2::trd::CalibratedTracklet> mSpacePoints; + gsl::span<const o2::trd::TriggerRecord> mTriggerRecords; + gsl::span<const char> mTrigRecMask; + unsigned int mNTracklets; + unsigned int mNSpacePoints; + unsigned int mNTriggerRecords; + std::vector<float> trdTriggerTimes; + std::vector<int> trdTriggerIndices; + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mTrackletLabels; + + void fillGPUIOPtr(o2::gpu::GPUTrackingInOutPointers* ptrs); +}; + +inline auto getRecoInputContainer(o2::framework::ProcessingContext& pc, o2::gpu::GPUTrackingInOutPointers* ptrs, const o2::globaltracking::RecoContainer* inputTracks, bool mc = false) +{ + auto retVal = std::make_unique<RecoInputContainer>(); + + retVal->mTracklets = pc.inputs().get<gsl::span<o2::trd::Tracklet64>>("trdtracklets"); + retVal->mSpacePoints = pc.inputs().get<gsl::span<CalibratedTracklet>>("trdctracklets"); + retVal->mTriggerRecords = pc.inputs().get<gsl::span<o2::trd::TriggerRecord>>("trdtriggerrec"); + retVal->mTrigRecMask = pc.inputs().get<gsl::span<char>>("trdtrigrecmask"); + + retVal->mNTracklets = retVal->mTracklets.size(); + retVal->mNSpacePoints = retVal->mSpacePoints.size(); + retVal->mNTriggerRecords = retVal->mTriggerRecords.size(); + + if (mc) { + retVal->mTrackletLabels = pc.inputs().get<o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("trdtrackletlabels"); + } + + for (unsigned int iEv = 0; iEv < retVal->mNTriggerRecords; ++iEv) { + const auto& trg = retVal->mTriggerRecords[iEv]; + retVal->trdTriggerIndices.push_back(trg.getFirstTracklet()); + auto evTime = trg.getBCData().differenceInBC(inputTracks->startIR) * o2::constants::lhc::LHCBunchSpacingNS; // event time in ns + retVal->trdTriggerTimes.push_back(evTime * 1e-3); // event time in us + } + + if (ptrs) { + retVal->fillGPUIOPtr(ptrs); + } + + return retVal; +} + +inline void RecoInputContainer::fillGPUIOPtr(o2::gpu::GPUTrackingInOutPointers* ptrs) +{ + ptrs->nTRDTriggerRecords = mNTriggerRecords; + ptrs->trdTriggerTimes = &(trdTriggerTimes[0]); + ptrs->trdTrackletIdxFirst = &(trdTriggerIndices[0]); + ptrs->trdTrigRecMask = reinterpret_cast<const char*>(mTrigRecMask.data()); + ptrs->nTRDTracklets = mNTracklets; + ptrs->trdTracklets = reinterpret_cast<const o2::gpu::GPUTRDTrackletWord*>(mTracklets.data()); + ptrs->trdSpacePoints = reinterpret_cast<const o2::gpu::GPUTRDSpacePoint*>(mSpacePoints.data()); +} + +} // namespace trd +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/SignalArray.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/SignalArray.h new file mode 100644 index 0000000000000..1d446c6d3f649 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/SignalArray.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_SIGNALARRAY_H_ +#define ALICEO2_TRD_SIGNALARRAY_H_ + +#include "DataFormatsTRD/Constants.h" +#include "SimulationDataFormat/MCCompLabel.h" + +#include <array> +#include <unordered_set> +#include <vector> + +namespace o2 +{ +namespace trd +{ + +struct SignalArray { + double firstTBtime; // first TB time + std::array<float, constants::TIMEBINS> signals{}; // signals + std::unordered_set<int> trackIds; // tracks Ids associated to the signal + std::vector<o2::MCCompLabel> labels; // labels associated to the signal + bool isDigit = false; // flag a signal converted to a digit + bool isShared = false; // flag if converted digit is shared (copied) + // if that is the case, also the labels have to be copied +}; + +} // namespace trd +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h new file mode 100644 index 0000000000000..9dcbde05fb743 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackTRD.h +/// \author David Rohr + +#ifndef O2_DATAFORMATS_TRACK_TRD_H +#define O2_DATAFORMATS_TRACK_TRD_H + +#include "GPUTRDTrack.h" + +namespace o2 +{ +namespace trd +{ +using TrackTRD = o2::gpu::GPUTRDTrack; +} // namespace trd +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::trd::TrackTRD> : std::true_type { +}; +} // namespace framework +namespace gpu +{ +static_assert(sizeof(o2::dataformats::GlobalTrackID) == sizeof(unsigned int)); +template <> +GPUdi() o2::dataformats::GlobalTrackID GPUTRDTrack_t<trackInterface<o2::track::TrackParCov>>::getRefGlobalTrackId() const +{ + return o2::dataformats::GlobalTrackID{mRefGlobalTrackId}; +} +template <> +GPUdi() void GPUTRDTrack_t<trackInterface<o2::track::TrackParCov>>::setRefGlobalTrackId(o2::dataformats::GlobalTrackID id) +{ + setRefGlobalTrackIdRaw(id.getRaw()); +} +} // namespace gpu +} // namespace o2 + +#endif // O2_DATAFORMATS_TRACK_TRD_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTriggerRecord.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTriggerRecord.h new file mode 100644 index 0000000000000..a6a32b90558f9 --- /dev/null +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTriggerRecord.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_TRACKTRIGGERRECORD_H +#define ALICEO2_TRD_TRACKTRIGGERRECORD_H + +#include "Rtypes.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" + +namespace o2 +{ +namespace trd +{ + +/// \class TrackTriggerRecord +/// \brief Mapping of reconstructed TRD tracks to BC information which is taken from the TRD tracklets attached to the track +/// \author Ole Schmidt + +class TrackTriggerRecord +{ + using BCData = o2::InteractionRecord; + using DataRange = o2::dataformats::RangeReference<int>; + + public: + TrackTriggerRecord() = default; + TrackTriggerRecord(BCData bcData, int firstEntry, int nEntries) : mBCData(bcData), mTrackDataRange(firstEntry, nEntries) {} + + // setters (currently class members are set at the time of creation, if there is need to change them afterwards setters can be added below) + + // getters + const auto& getTrackRefs() const { return mTrackDataRange; } + int getFirstTrack() const { return mTrackDataRange.getFirstEntry(); } + int getNumberOfTracks() const { return mTrackDataRange.getEntries(); } + BCData getBCData() const { return mBCData; } + + private: + BCData mBCData; ///< bunch crossing data + DataRange mTrackDataRange; ///< range of tracklets for each BC data + + ClassDefNV(TrackTriggerRecord, 1); +}; +} // namespace trd +} // namespace o2 + +#endif // ALICEO2_TRD_TRACKTRIGGERRECORD_H diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h index ef4a8f401ed80..a8d8a83f2c87f 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,11 +26,10 @@ // Sean Murray (murrays@cern.ch) // // //////////////////////////////////////////////////////////////////////////// -#include <vector> -#include <array> -#include <memory> // for std::unique_ptr -#include "Rtypes.h" // for ClassDef -#include "fairlogger/Logger.h" + +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" +#include "DataFormatsTRD/Constants.h" namespace o2 { @@ -48,79 +48,100 @@ class Tracklet64 { public: - Tracklet64() = default; - Tracklet64(uint64_t trackletword) { mtrackletWord = trackletword; } - Tracklet64(const Tracklet64&) = default; + GPUdDefault() Tracklet64() = default; + GPUd() Tracklet64(uint64_t trackletword) { mtrackletWord = trackletword; } + GPUdDefault() Tracklet64(const Tracklet64&) = default; + GPUd() Tracklet64(uint64_t format, uint64_t hcid, uint64_t padrow, uint64_t col, uint64_t position, + uint64_t slope, uint64_t Q0, uint64_t Q1, uint64_t Q2) + { + mtrackletWord = ((format << formatbs) & formatmask) | + ((hcid << hcidbs) & hcidmask) | + ((padrow << padrowbs) & padrowmask) | + ((col << colbs) & colmask) | + ((position << posbs) & posmask) | + ((slope << slopebs) & slopemask) | + ((Q2 << Q2bs) & Q2mask) | + ((Q1 << Q1bs) & Q1mask) | + ((Q0 << Q0bs) & Q0mask); + } + Tracklet64(uint64_t format, uint64_t hcid, uint64_t padrow, uint64_t col, uint64_t position, - uint64_t slope, uint64_t Q0, uint64_t Q1, uint64_t Q2) + uint64_t slope, uint64_t pid) { - buildTrackletWord(format, hcid, padrow, col, position, slope, Q0, Q1, Q2); + mtrackletWord = ((format << formatbs) & formatmask) | + ((hcid << hcidbs) & hcidmask) | + ((padrow << padrowbs) & padrowmask) | + ((col << colbs) & colmask) | + ((position << posbs) & posmask) | + ((slope << slopebs) & slopemask) | + (pid & PIDmask); } - ~Tracklet64() = default; + GPUdDefault() ~Tracklet64() = default; + GPUdDefault() Tracklet64& operator=(const Tracklet64& rhs) = default; - //TODO convert to the actual number regarding compliments. // ----- Getters for contents of tracklet word ----- - uint64_t getHCID() const { return ((mtrackletWord & hcidmask) >> hcidbs); }; // no units 0..1077 - uint64_t getPadRow() const { return ((mtrackletWord & padrowmask) >> padrowbs); }; // in units of - uint64_t getColumn() const { return ((mtrackletWord & colmask) >> colbs); }; // in units of - uint64_t getPosition() const { return ((mtrackletWord & posmask) >> posbs); }; // in units of 0.02 pads [10bits] .. -10.22 to 10.22 - uint64_t getSlope() const { return ((mtrackletWord & slopemask) >> slopebs); }; // in units of -127 .. 127 - uint64_t getPID() const { return ((mtrackletWord & PIDmask)); }; // in units of counts all 3 together - uint64_t getQ0() const { return ((mtrackletWord & Q0mask) >> Q0bs); }; // in units of counts all 3 together - uint64_t getQ1() const { return ((mtrackletWord & Q1mask) >> Q1bs); }; // in units of counts all 3 together - uint64_t getQ2() const { return ((mtrackletWord & Q2mask) >> Q2bs); }; // in units of counts all 3 together - - uint64_t buildTrackletWord(uint64_t format, uint64_t hcid, uint64_t padrow, uint64_t col, uint64_t position, uint64_t slope, uint64_t Q2, uint64_t Q1, uint64_t Q0) - { - mtrackletWord = ((format << formatbs) & formatmask) + ((hcid << hcidbs) & hcidmask) + ((padrow << padrowbs) & padrowmask) + ((col << colbs) & colmask) + ((position << posbs) & posmask) + ((slope << slopebs) & slopemask) + ((Q2 << Q2bs) & Q2mask) + ((Q1 << Q1bs) & Q1mask) + ((Q0 << Q0bs) & Q0mask); - return 0; - } - uint64_t setTrackletWord(uint64_t trackletword) - { - mtrackletWord = trackletword; - return 0; - } + GPUd() uint64_t getFormat() const { return ((mtrackletWord & formatmask) >> formatbs); }; // no units 0..1077 + GPUd() uint64_t getHCID() const { return ((mtrackletWord & hcidmask) >> hcidbs); }; // no units 0..1077 + GPUd() uint64_t getPadRow() const { return ((mtrackletWord & padrowmask) >> padrowbs); }; // pad row number [0..15] + GPUd() uint64_t getColumn() const { return ((mtrackletWord & colmask) >> colbs); }; // column refers to MCM position in column direction on readout board [0..3] + GPUd() uint64_t getPosition() const { return ((mtrackletWord & posmask) >> posbs); }; // in units of 1/80 pads, 11 bit granularity [-12.8..12.8] relative to MCM center + GPUd() uint64_t getSlope() const { return ((mtrackletWord & slopemask) >> slopebs); }; // in units of 1/1000 pads/timebin, 8 bit granularity [-0.128 to 0.128] + GPUd() uint64_t getPID() const { return ((mtrackletWord & PIDmask)); }; // no unit, all 3 charge windows combined + GPUd() uint64_t getQ0() const { return ((mtrackletWord & Q0mask) >> Q0bs); }; // no unit + GPUd() uint64_t getQ1() const { return ((mtrackletWord & Q1mask) >> Q1bs); }; // no unit + GPUd() uint64_t getQ2() const { return ((mtrackletWord & Q2mask) >> Q2bs); }; // no unit + + GPUd() void setTrackletWord(uint64_t trackletword) { mtrackletWord = trackletword; } // ----- Getters for tracklet information ----- - int getMCM() const - { - return (getColumn() % (72)) / 18 + 4 * (getPadRow() % 4); - } - int getROB() const - { - int side = getColumn() / 72; - return (int)((int)getPadRow() / 8 + side); - } + GPUd() int getMCM() const { return 4 * (getPadRow() % 4) + getColumn(); } // returns MCM position on ROB [0..15] + GPUd() int getROB() const { return (getHCID() % 2) ? (getPadRow() / 4) * 2 + 1 : (getPadRow() / 4) * 2; } // returns ROB number [0..5] for C0 chamber and [0..7] for C1 chamber + GPUd() float getUncalibratedY() const; // translate local position into global y (in cm) not taking into account calibrations (ExB, vDrift, t0) + GPUd() float getUncalibratedDy(float nTbDrift = 19.4f) const; // translate local slope into dy/dx with dx=3m (drift length) and default drift time in time bins (19.4 timebins / 3cm) // ----- Getters for offline corresponding values ----- - int getDetector() const { return getHCID() / 2; } + GPUd() int getDetector() const { return getHCID() / 2; } - uint64_t getTrackletWord() const { return mtrackletWord; }; - uint32_t getTrackletWord32() const; + GPUd() uint64_t getTrackletWord() const { return mtrackletWord; } - // void setDetector(int id) { uint64_t hcid= 2* id; uint64_t side=1;mtrackletWord = hcid << hcidbs + ; } - // void setHCId(int id) { mHCId = id; } - // TODO row and mcm to col and padrow mapping. - uint64_t setQ0(int charge) + GPUd() void setQ0(int charge) { + mtrackletWord &= ~Q0mask; mtrackletWord |= ((charge << Q0bs) & Q0mask); - return mtrackletWord; } - uint64_t setQ1(int charge) + GPUd() void setQ1(int charge) { + mtrackletWord &= ~Q1mask; mtrackletWord |= ((charge << Q1bs) & Q1mask); - return mtrackletWord; } - uint64_t setQ2(int charge) + GPUd() void setQ2(int charge) { + mtrackletWord &= ~Q2mask; mtrackletWord |= ((charge << Q2bs) & Q2mask); - return mtrackletWord; } - void setPID(uint64_t pid) { mtrackletWord |= ((((uint64_t)pid) << PIDbs) & PIDmask); } // set the entire pid area of the trackletword, all the 3 Q's - void setPosition(uint64_t position) { mtrackletWord |= ((((uint64_t)position) << posbs) & posmask); } - void setSlope(uint64_t slope) { mtrackletWord |= ((((uint64_t)slope) << slopebs) & slopemask); } + GPUd() void setPID(uint64_t pid) + { + // set the entire pid area of the trackletword, all the 3 Q's + mtrackletWord &= ~PIDmask; + mtrackletWord |= ((pid << PIDbs) & PIDmask); + } + GPUd() void setPosition(uint64_t position) + { + mtrackletWord &= ~posmask; + mtrackletWord |= ((position << posbs) & posmask); + } + GPUd() void setSlope(uint64_t slope) + { + mtrackletWord &= ~slopemask; + mtrackletWord |= ((slope << slopebs) & slopemask); + } + + GPUd() bool operator==(const Tracklet64& o) const { return mtrackletWord == o.mtrackletWord; } + +#ifndef GPUCA_GPUCODE_DEVICE void printStream(std::ostream& stream) const; +#endif // GPUCA_GPUCODE_DEVICE // bit masks for the above raw data; static constexpr uint64_t formatmask = 0xf000000000000000; @@ -151,8 +172,40 @@ class Tracklet64 ClassDefNV(Tracklet64, 1); }; +GPUdi() float Tracklet64::getUncalibratedY() const +{ + int padLocalBin = getPosition(); + int padLocal = 0; + if (padLocalBin & (1 << (constants::NBITSTRKLPOS - 1))) { + padLocal = -((~(padLocalBin - 1)) & ((1 << constants::NBITSTRKLPOS) - 1)); + } else { + padLocal = padLocalBin & ((1 << constants::NBITSTRKLPOS) - 1); + } + int mcmCol = (getMCM() % constants::NMCMROBINCOL) + constants::NMCMROBINCOL * (getROB() % 2); + float offset = -63.f + ((float)constants::NCOLMCM) * mcmCol; + float padWidth = 0.635f + 0.03f * (getDetector() % constants::NLAYER); + return (offset + padLocal * constants::GRANULARITYTRKLPOS) * padWidth; +} + +GPUdi() float Tracklet64::getUncalibratedDy(float nTbDrift) const +{ + float dy; + int dyLocalBin = getSlope(); + if (dyLocalBin & (1 << (constants::NBITSTRKLSLOPE - 1))) { + dy = (~(dyLocalBin - 1)) & ((1 << constants::NBITSTRKLSLOPE) - 1); + dy *= -1.f; + } else { + dy = dyLocalBin & ((1 << constants::NBITSTRKLSLOPE) - 1); + } + float padWidth = 0.635f + 0.03f * (getDetector() % constants::NLAYER); + return dy * constants::GRANULARITYTRKLSLOPE * padWidth * nTbDrift; +} + +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& stream, const Tracklet64& trg); +#endif // GPUCA_GPUCODE_DEVICE } //namespace trd } //namespace o2 + #endif diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TriggerRecord.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TriggerRecord.h index 508dd823d95a4..5a933fb218621 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TriggerRecord.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TriggerRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,26 +33,42 @@ class TriggerRecord public: TriggerRecord() = default; - TriggerRecord(const BCData& bunchcrossing, int firstentry, int nentries) : mBCData(bunchcrossing), mDataRange(firstentry, nentries) {} + TriggerRecord(const BCData& bunchcrossing, int digitentry, int ndigitentries, int trackletentry = 0, int ntrackletentries = 0) : mBCData(bunchcrossing), mTrackletDataRange(trackletentry, ntrackletentries), mDigitDataRange(digitentry, ndigitentries) {} + // The above default of 0 for tracklet info, makes the digitizer look more decent as one can simply not put in the tracklet info as you dont have it. ~TriggerRecord() = default; void setBCData(const BCData& data) { mBCData = data; } - void setDataRange(int firstentry, int nentries) { mDataRange.set(firstentry, nentries); } - void setIndexFirstObject(int firstentry) { mDataRange.setFirstEntry(firstentry); } - void setNumberOfObjects(int nentries) { mDataRange.setEntries(nentries); } const BCData& getBCData() const { return mBCData; } BCData& getBCData() { return mBCData; } - int getNumberOfObjects() const { return mDataRange.getEntries(); } - int getFirstEntry() const { return mDataRange.getFirstEntry(); } + + //Digit information + void setFirstDigit(int firstentry) { mDigitDataRange.setFirstEntry(firstentry); } + int getFirstDigit() const { return mDigitDataRange.getFirstEntry(); } + void setNumberOfDigit(int nentries) { mDigitDataRange.setEntries(nentries); } + int getNumberOfDigits() const { return mDigitDataRange.getEntries(); } + void setDigitRange(int firstentry, int nentries) { mDigitDataRange.set(firstentry, nentries); } + + //tracklet information + void setFirstTracklet(int firstentry) { mTrackletDataRange.setFirstEntry(firstentry); } + int getFirstTracklet() const { return mTrackletDataRange.getFirstEntry(); } + void setNumberOfTracklet(int nentries) { mTrackletDataRange.setEntries(nentries); } + int getNumberOfTracklets() const { return mTrackletDataRange.getEntries(); } + void setTrackletRange(int firstentry, int nentries) { mTrackletDataRange.set(firstentry, nentries); } void printStream(std::ostream& stream) const; + bool operator==(const TriggerRecord& o) const + { + return mBCData == o.mBCData && mDigitDataRange == o.mDigitDataRange && mTrackletDataRange == o.mTrackletDataRange; + } + private: BCData mBCData; /// Bunch crossing data of the trigger - DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) + DataRange mDigitDataRange; /// Index of the underlying digit data, indexes into the vector/array/span + DataRange mTrackletDataRange; /// Index of the underlying tracklet data, indexes into the vector/array/span - ClassDefNV(TriggerRecord, 1); + ClassDefNV(TriggerRecord, 2); }; std::ostream& operator<<(std::ostream& stream, const TriggerRecord& trg); diff --git a/DataFormats/Detectors/TRD/src/AngularResidHistos.cxx b/DataFormats/Detectors/TRD/src/AngularResidHistos.cxx new file mode 100644 index 0000000000000..f0c3b2637f94f --- /dev/null +++ b/DataFormats/Detectors/TRD/src/AngularResidHistos.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file AngularResidHistos.cxx +/// \brief Class to store the output of the global tracking based TRD calibration + +#include "DataFormatsTRD/AngularResidHistos.h" +#include <fairlogger/Logger.h> +#include <cmath> + +using namespace o2::trd; +using namespace o2::trd::constants; + +bool AngularResidHistos::addEntry(float deltaAlpha, float impactAngle, int chamberId) +{ + // add entry for given angular residual + // returns 0 in case of success (impact angle is in valid range) + int chamberOffset = chamberId * NBINSANGLEDIFF; + if (std::fabs(impactAngle) >= MAXIMPACTANGLE) { + LOG(DEBUG) << "Under-/overflow entry detected for impact angle " << impactAngle; + return 1; + } else { + int iBin = (impactAngle + MAXIMPACTANGLE) * INVBINWIDTH; + mHistogramEntries[chamberOffset + iBin] += deltaAlpha; + ++mNEntriesPerBin[chamberOffset + iBin]; + ++mNEntriesTotal; + } + return 0; +} + +void AngularResidHistos::fill(const gsl::span<const AngularResidHistos> input) +{ + for (const auto& data : input) { + for (int i = 0; i < MAXCHAMBER * NBINSANGLEDIFF; ++i) { + mHistogramEntries[i] += data.getHistogramEntry(i); + mNEntriesPerBin[i] += data.getBinCount(i); + mNEntriesTotal += data.getBinCount(i); + } + } +} + +void AngularResidHistos::merge(const AngularResidHistos* prev) +{ + for (int i = 0; i < MAXCHAMBER * NBINSANGLEDIFF; ++i) { + mHistogramEntries[i] += prev->getHistogramEntry(i); + mNEntriesPerBin[i] += prev->getBinCount(i); + mNEntriesTotal += prev->getBinCount(i); + } +} + +void AngularResidHistos::print() +{ + LOG(INFO) << "There are " << mNEntriesTotal << " entries in the container"; + for (int i = 0; i < MAXCHAMBER * NBINSANGLEDIFF; ++i) { + if (mNEntriesPerBin[i] != 0) { + LOGF(INFO, "Global bin %i has %i entries. Average angular residual: %f", i, mNEntriesPerBin[i], mHistogramEntries[i]); + } + } +} diff --git a/DataFormats/Detectors/TRD/src/CTF.cxx b/DataFormats/Detectors/TRD/src/CTF.cxx new file mode 100644 index 0000000000000..b39e6afda7bac --- /dev/null +++ b/DataFormats/Detectors/TRD/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsTRD/CTF.h" + +using namespace o2::trd; diff --git a/DataFormats/Detectors/TRD/src/CompressedDigit.cxx b/DataFormats/Detectors/TRD/src/CompressedDigit.cxx new file mode 100644 index 0000000000000..cc2c850b81cd1 --- /dev/null +++ b/DataFormats/Detectors/TRD/src/CompressedDigit.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsTRD/CompressedDigit.h" +#include <iostream> + +namespace o2::trd +{ + +using namespace constants; + +CompressedDigit::CompressedDigit(const int det, const int rob, const int mcm, const int channel, const std::array<uint16_t, constants::TIMEBINS>& adc) +{ + setDetector(det); + setROB(rob); + setMCM(mcm); + setChannel(channel); + setADC(adc); +} + +CompressedDigit::CompressedDigit(const int det, const int rob, const int mcm, const int channel) // add adc data in a seperate step +{ + setDetector(det); + setROB(rob); + setMCM(mcm); + setChannel(channel); +} + +bool CompressedDigit::isSharedCompressedDigit() const +{ + if (getChannel() == 0 || getChannel() == 1 || getChannel() == NADCMCM - 1) { + return 1; + } else { + return 0; + } +} + +std::ostream& operator<<(std::ostream& stream, CompressedDigit& d) +{ + stream << "CompressedDigit Det: " << d.getDetector() << " ROB: " << d.getROB() << " MCM: " << d.getMCM() << " Channel: " << d.getChannel() << " ADCs:"; + for (unsigned int i = 0; i < constants::TIMEBINS; i++) { + stream << "[" << d[i] << "]"; + } + return stream; +} + +} // namespace o2::trd diff --git a/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h b/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h index e21390345f4c7..564e4cc09fa0b 100644 --- a/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h +++ b/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,15 +16,34 @@ #pragma link off all functions; #pragma link C++ class o2::trd::TriggerRecord + ; +#pragma link C++ class o2::trd::TrackTriggerRecord + ; #pragma link C++ class o2::trd::LinkRecord + ; -#pragma link C++ struct o2::trd::LinkRecord::LinkId + ; #pragma link C++ struct o2::trd::HalfCRUHeader + ; #pragma link C++ struct o2::trd::TrackletHCHeader + ; #pragma link C++ struct o2::trd::TrackletMCMHeader + ; #pragma link C++ struct o2::trd::TrackletMCMData + ; #pragma link C++ class o2::trd::Tracklet64 + ; +#pragma link C++ class o2::trd::CalibratedTracklet + ; +#pragma link C++ class o2::trd::Hit + ; +#pragma link C++ class o2::trd::Digit + ; +#pragma link C++ class o2::trd::KrCluster + ; +#pragma link C++ class o2::trd::KrClusterTriggerRecord + ; +#pragma link C++ class o2::trd::AngularResidHistos + ; +#pragma link C++ class o2::trd::CalVdriftExB + ; +#pragma link C++ class o2::trd::CompressedDigit + ; #pragma link C++ class std::vector < o2::trd::Tracklet64> + ; +#pragma link C++ class std::vector < o2::trd::CalibratedTracklet> + ; +#pragma link C++ class std::vector < o2::trd::TrackTriggerRecord> + ; #pragma link C++ class std::vector < o2::trd::TriggerRecord > +; #pragma link C++ class std::vector < o2::trd::LinkRecord > +; +#pragma link C++ class std::vector < o2::trd::Hit > +; +#pragma link C++ class std::vector < o2::trd::Digit> + ; +#pragma link C++ class std::vector < o2::trd::AngularResidHistos> + ; +#pragma link C++ class std::vector < o2::trd::KrCluster> + ; +#pragma link C++ class std::vector < o2::trd::KrClusterTriggerRecord> + ; + +#pragma link C++ struct o2::trd::CTFHeader + ; +#pragma link C++ struct o2::trd::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::trd::CTFHeader, 15, uint32_t> + ; #endif diff --git a/DataFormats/Detectors/TRD/src/Digit.cxx b/DataFormats/Detectors/TRD/src/Digit.cxx new file mode 100644 index 0000000000000..49e1d799c8a9d --- /dev/null +++ b/DataFormats/Detectors/TRD/src/Digit.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsTRD/Digit.h" +#include <iostream> +#include <algorithm> + +namespace o2::trd +{ + +using namespace constants; + +Digit::Digit(const int det, const int row, const int pad, const ArrayADC adc) +{ + setDetector(det); + setROB(row, pad); + setMCM(row, pad); + setADC(adc); + setChannel(NADCMCM - 2 - (pad % NCOLMCM)); +} + +Digit::Digit(const int det, const int row, const int pad) // add adc data in a seperate step +{ + setDetector(det); + setROB(row, pad); + setMCM(row, pad); + setChannel(NADCMCM - 2 - (pad % NCOLMCM)); +} + +Digit::Digit(const int det, const int rob, const int mcm, const int channel, const ArrayADC adc) +{ + setDetector(det); + setROB(rob); + setMCM(mcm); + setChannel(channel); + setADC(adc); +} + +Digit::Digit(const int det, const int rob, const int mcm, const int channel) // add adc data in a seperate step +{ + setDetector(det); + setROB(rob); + setMCM(mcm); + setChannel(channel); +} + +bool Digit::isSharedDigit() const +{ + if (mChannel == 0 || mChannel == 1 || mChannel == NADCMCM - 1) { + return 1; + } else { + return 0; + } +} + +ADC_t Digit::getADCmax(int& idx) const +{ + auto itMax = std::max_element(mADC.begin(), mADC.end()); + idx = std::distance(mADC.begin(), itMax); + return *itMax; +} + +std::ostream& operator<<(std::ostream& stream, const Digit& d) +{ + stream << "Digit Det: " << d.getDetector() << " ROB: " << d.getROB() << " MCM: " << d.getMCM() << " Channel: " << d.getChannel() << " ADCs:"; + for (int i = 0; i < constants::TIMEBINS; i++) { + stream << "[" << d.getADC()[i] << "]"; + } + return stream; +} + +} // namespace o2::trd diff --git a/DataFormats/Detectors/TRD/src/KrCluster.cxx b/DataFormats/Detectors/TRD/src/KrCluster.cxx new file mode 100644 index 0000000000000..463f7010bc9da --- /dev/null +++ b/DataFormats/Detectors/TRD/src/KrCluster.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrCluster.cxx +/// \brief A cluster formed from digits during TRD Krypton calibration + +#include "DataFormatsTRD/KrCluster.h" + +using namespace o2::trd; + +void KrCluster::setGlobalPadID(int det, int row, int col) +{ + mDet = det; + mRow = row; + mCol = col; +} + +void KrCluster::setAdcData(int adcSum, int adcRms, int adcMaxA, int adcMaxB, int adcEoT, int adcIntegral, int adcSumTrunc) +{ + mAdcSum = adcSum; + mAdcRms = adcRms; + mAdcMaxA = adcMaxA; + mAdcMaxB = adcMaxB; + mAdcSumEoverT = adcEoT; + mAdcIntegral = adcIntegral; + mAdcSumTruncated = adcSumTrunc; +} + +void KrCluster::setTimeData(int timeMaxA, int timeMaxB, int timeRms) +{ + mTimeMaxA = timeMaxA; + mTimeMaxB = timeMaxB; + mTimeRms = timeRms; +} + +void KrCluster::setClusterSizeData(int rowSize, int colSize, int timeSize, int nAdcs) +{ + mDeltaRow = rowSize; + mDeltaCol = colSize; + mDeltaTime = timeSize; + mClusterSize = nAdcs; +} diff --git a/DataFormats/Detectors/TRD/src/LinkRecord.cxx b/DataFormats/Detectors/TRD/src/LinkRecord.cxx index e4d75a231fa5a..996bfc5142387 100644 --- a/DataFormats/Detectors/TRD/src/LinkRecord.cxx +++ b/DataFormats/Detectors/TRD/src/LinkRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,22 +25,24 @@ uint32_t LinkRecord::getHalfChamberLinkId(uint32_t detector, uint32_t rob) int stack = (detector % constants::NLAYER); int layer = ((detector % (constants::NLAYER * constants::NSTACK)) / constants::NLAYER); int side = rob % 2; + LOG(debug) << "sector, stack, layer, side :" << sector << " " << stack << " " << layer << " " << side; return LinkRecord::getHalfChamberLinkId(sector, stack, layer, side); } uint32_t LinkRecord::getHalfChamberLinkId(uint32_t sector, uint32_t stack, uint32_t layer, uint32_t side) { - LinkRecord tmplinkid; - tmplinkid.setLinkId(sector, stack, layer, side); - return tmplinkid.getLinkId(); + LinkRecord a; + a.setLinkId(sector, stack, layer, side); + return a.mLinkId; } void LinkRecord::setLinkId(const uint32_t sector, const uint32_t stack, const uint32_t layer, const uint32_t side) { - mLinkId |= sector << 11; - mLinkId |= stack << 8; - mLinkId |= layer << 5; - mLinkId |= side << 4; + setSector(sector); + setStack(stack); + setLayer(layer); + setSide(side); + setSpare(); } void LinkRecord::printStream(std::ostream& stream) diff --git a/DataFormats/Detectors/TRD/src/RawData.cxx b/DataFormats/Detectors/TRD/src/RawData.cxx index a67094bc98e6f..bd0146cec505b 100644 --- a/DataFormats/Detectors/TRD/src/RawData.cxx +++ b/DataFormats/Detectors/TRD/src/RawData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,6 +42,19 @@ void buildTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int buildTrackletHCHeader(header, sector, stack, layer, side, chipclock, format); } +uint32_t getHCIDFromTrackletHCHeader(const TrackletHCHeader& header) +{ + return header.layer * 2 + header.stack * constants::NLAYER * 2 + header.supermodule * constants::NLAYER * constants::NSTACK * 2 + header.side; +} + +// same method alternate input simpler to send a word pointer as const +uint32_t getHCIDFromTrackletHCHeader(const uint32_t& headerword) +{ + TrackletHCHeader header; + header.word = headerword; + return header.layer * 2 + header.stack * constants::NLAYER * 2 + header.supermodule * constants::NLAYER * constants::NSTACK * 2 + header.side; +} + uint16_t buildTRDFeeID(int supermodule, int side, int endpoint) { TRDFeeID feeid; @@ -50,6 +64,14 @@ uint16_t buildTRDFeeID(int supermodule, int side, int endpoint) return feeid.word; } +void buildTrackletMCMData(TrackletMCMData& trackletword, const uint slope, const uint pos, const uint q0, const uint q1, const uint q2) +{ + trackletword.slope = slope; + trackletword.pos = pos; + trackletword.pid = (q0 & 0x7f) & ((q1 & 0x1f) << 7); //q2 sits with upper 2 bits of q1 in the header pid word, hence the 0x1f so 5 bits are used here. + trackletword.checkbit = 1; +} + uint32_t getlinkerrorflag(const HalfCRUHeader& cruhead, const uint32_t link) { // link is the link you are requesting information on, 0-14 @@ -83,6 +105,56 @@ uint32_t getlinkdatasizes(const HalfCRUHeader& cruheader, std::array<uint32_t, 1 linksizes[link] = getlinkdatasize(cruheader, link); } return 0; +}; + +uint32_t getQFromRaw(const o2::trd::TrackletMCMHeader* header, const o2::trd::TrackletMCMData* data, int pidindex, int trackletindex) +{ + uint32_t pid = 0; + uint32_t qa, qb; + //PID VERSION 1 + //frist part of pid is in the TrackletMCMHeader + switch (trackletindex) { + case 0: + qa = header->pid0; + break; + case 1: + qa = header->pid1; + break; + case 2: + qa = header->pid2; + break; + default: + LOG(warn) << " unknown trackletindex of " << trackletindex << " to getQFromRaw : " << pidindex; + break; + } + //qa is 6bits of Q2 and 2 bits of Q1 + //second part of pid is in the TrackletMCMData + qb = data->pid; + //qb is 7 bits Q0 and 5 bits of Q1 + switch (pidindex) { + case 0: //Q0 + pid = (qb >> 5) & 0x7f; // 7 bits at the top of all of Q0 + break; + case 1: //Q1 + pid = ((qa & 0x3) << 5) | (qb >> 5); // 2 bits of qb and 5 bits of qb for Q1 .. 7 bits + break; + case 2: //Q2 + pid = (qa >> 2) & 0x2f; // 6 bits shifted down by bits 2 to 8 ... 6 bits + break; + default: + LOG(warn) << " unknown pid index of : " << pidindex; + break; + } + //PID VERSION 2 + /* + switch(pidindex) { + case 0 : pid=qa&0xffc>>2;break; + case 1 : pid=((qa&0x3)<<5)|(qb>>6);break; + case 2 : pid=qb&0x3f;break; + default : LOG(warn) << " unknown pid index of : " << pidindex; + } + */ + return pid; } uint32_t setHalfCRUHeader(HalfCRUHeader& cruhead, int crurdhversion, int bunchcrossing, int stopbits, int endpoint, int eventtype, int feeid, int cruid) @@ -91,10 +163,9 @@ uint32_t setHalfCRUHeader(HalfCRUHeader& cruhead, int crurdhversion, int bunchcr cruhead.StopBit = stopbits; cruhead.EndPoint = endpoint; cruhead.EventType = eventtype; - //later versions - // cruhead.rdhversion = crurdhversion; - // cruhead.FeeID = feeid; - // cruhead.CRUID = cruid; + cruhead.HeaderVersion = crurdhversion; + //cruhead.FeeID = feeid; + //cruhead.CRUID = cruid; return 0; } @@ -129,40 +200,49 @@ std::ostream& operator<<(std::ostream& stream, const TrackletMCMData& tracklet) << tracklet.checkbit << std::endl; return stream; } -void printTrackletMCMData(o2::trd::TrackletMCMData const& tracklet) +void printTrackletMCMData(o2::trd::TrackletMCMData& tracklet) { LOGF(INFO, "TrackletMCMData: Raw:0x%08x pos:%d slope:%d pid:0x%08x checkbit:0x%02x", tracklet.word, tracklet.pos, tracklet.slope, tracklet.pid, tracklet.checkbit); } -void printTrackletMCMHeader(o2::trd::TrackletMCMHeader const& mcmhead) +void printTrackletMCMHeader(o2::trd::TrackletMCMHeader& mcmhead) { + LOG(info) << " about to print mcm raw header"; LOGF(INFO, "MCMRawHeader: Raw:0x%08x 1:%d padrow: 0x%02x col: 0x%01x pid2 0x%02x pid1: 0x%02x pid0: 0x%02x 1:%d", mcmhead.word, mcmhead.onea, mcmhead.padrow, mcmhead.col, mcmhead.pid2, mcmhead.pid1, mcmhead.pid0, mcmhead.oneb); + LOG(info) << " printed mcm raw header"; } std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& mcmhead) { // make a pretty output of the mcm header. - stream << "MCMRawHeader: Raw:0x" << std::hex << mcmhead.word << " " << mcmhead.onea << "::" + stream << "TrackletMCMRawHeader: Raw:0x" << std::hex << mcmhead.word << " " << mcmhead.onea << "::" << mcmhead.pid2 << ":" << mcmhead.pid1 << ":" << mcmhead.pid0 << "::" << mcmhead.oneb << std::endl; return stream; } -void printHalfChamber(o2::trd::TrackletHCHeader const& halfchamber) +void printHalfChamber(o2::trd::TrackletHCHeader& halfchamber) { LOGF(INFO, "TrackletHCHeader: Raw:0x%08x SM : %d stack %d layer %d side : %d MCLK: 0x%0x Format: 0x%0x Always1:0x%0x", halfchamber.supermodule, halfchamber.stack, halfchamber.layer, halfchamber.side, halfchamber.MCLK, halfchamber.format, halfchamber.one); } +void printDigitMCMHeader(o2::trd::DigitMCMHeader& mcmhead) +{ + LOGF(INFO, "DigitMCMRawHeader: Raw:0x%08x res(0xc):0x%02x mcm: 0x%03x rob: 0x%03x eventcount 0x%05x year(>2007?): 0x%02x ", + mcmhead.word, mcmhead.res, mcmhead.mcm, mcmhead.rob, mcmhead.eventcount, + mcmhead.yearflag); +} + void dumpHalfChamber(o2::trd::TrackletHCHeader const& halfchamber) { LOGF(INFO, "HalfChamber : 0x%08x", halfchamber.word); } -void printHalfCRUHeader(o2::trd::HalfCRUHeader const& halfcru) +void printHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru) { std::array<uint32_t, 15> sizes; std::array<uint32_t, 15> errorflags; @@ -173,6 +253,10 @@ void printHalfCRUHeader(o2::trd::HalfCRUHeader const& halfcru) for (int i = 0; i < 15; i++) { LOGF(INFO, "Link %d size: %ul eflag: 0x%02x", i, sizes[i], errorflags[i]); } + LOG(INFO) << "Raw: " << std::hex << halfcru.word0 << " " << halfcru.word12[0] << " " << halfcru.word12[1] << " " << halfcru.word3 << " " << halfcru.word47[0] << " " << halfcru.word47[1] << " " << halfcru.word47[2] << " " << halfcru.word47[3]; + for (int i = 0; i < 15; i++) { + LOGF(INFO, "Raw: %d word: %ul x", i, sizes[i], errorflags[i]); + } } void dumpHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru) @@ -186,6 +270,17 @@ void dumpHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru) } } +void clearHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru) +{ + halfcru.word0 = 0; + halfcru.word12[0] = 0; + halfcru.word12[1] = 0; + halfcru.word3 = 0; + halfcru.word47[0] = 0; + halfcru.word47[1] = 0; + halfcru.word47[2] = 0; + halfcru.word47[3] = 0; +} std::ostream& operator<<(std::ostream& stream, const HalfCRUHeader& halfcru) { // make a pretty output of the header. stream << std::hex; @@ -207,5 +302,256 @@ std::ostream& operator<<(std::ostream& stream, const HalfCRUHeader& halfcru) return stream; } +bool trackletMCMHeaderSanityCheck(o2::trd::TrackletMCMHeader& header) +{ + // a bit limited to what we can check. + bool goodheader = true; + if (header.onea != 1) { + goodheader = false; + } + if (header.oneb != 1) { + goodheader = false; + } + // if we have 3rd tracklet (pid2!=0) then we must have all the others as well. + if ((header.pid2 != 0xff) && (header.pid1 == 0xff || header.pid0 == 0xff)) { + goodheader = false; + } + // sim for 2 tracklets. + if ((header.pid1 != 0xff) && (header.pid0 == 0xff)) { + goodheader = false; + } + + return goodheader; +} + +bool trackletHCHeaderSanityCheck(o2::trd::TrackletHCHeader& header) +{ + bool goodheader = true; + //TODO something wrong TDP is different from rawdata.h + //figure out but for now, just approve. + return true; + if (header.one != 1) { + LOG(warn) << "Sanity check tracklethcheader.one is not 1"; + goodheader = false; + } + if (header.supermodule > 17) { + LOG(warn) << "Sanity check tracklethcheader.supermodule>17"; + goodheader = false; + } + //if(header.format != ) only certain format versions are permitted come back an fill in if needed. + if (header.layer > 6) { + LOG(warn) << "Sanity check tracklethcheader.laywer>6"; + goodheader = false; + } + if (header.stack > 5) { + LOG(warn) << "Sanity check tracklethcheader.stack>5"; + goodheader = false; + } + return goodheader; +} + +bool digitMCMHeaderSanityCheck(o2::trd::DigitMCMHeader* header) +{ + // a bit limited to what we can check. + bool goodheader = true; + if (header->res != 0xc) { + goodheader = false; + } + if (header->yearflag == 0) { //we only have data after 2007 now in run3. + goodheader = false; + } + + return goodheader; +} + +bool digitMCMADCMaskSanityCheck(o2::trd::DigitMCMADCMask& mask, int numberofbitsset) +{ + bool goodadcmask = true; + uint32_t count = (unsigned int)mask.c; + count = ~count; + /* if(count != numberofbitsset){ + goodadcmask=false; + LOG(warn) << "***DigitMCMADCMask bad bit count maskcount:" << ~mask.c << " bitscounting:" << numberofbitsset; + }*/ + if (mask.n != 0x1) { + goodadcmask = false; + } + if (mask.j != 0xc) { + goodadcmask = false; + } + return goodadcmask; +} + +bool digitMCMWordSanityCheck(o2::trd::DigitMCMData* word, int adcchannel) +{ + bool gooddata = true; + // DigitMCMWord0x3 is odd 10 for odd adc channels and 11 for even, counted as the first of the 3. + switch (word->c) { + case 3: // even adc channnel + if (adcchannel % 2 == 0) { + gooddata = true; + } else { + gooddata = false; + } + break; + case 2: // odd adc channel + if (adcchannel % 2 == 1) { + gooddata = true; + } else { + gooddata = false; + } + break; + case 1: // error + gooddata = false; + break; + case 0: // error + gooddata = false; + break; + // no default all cases taken care of + } + return gooddata; +} + +int getDigitHCHeaderWordType(uint32_t word) +{ + if ((word & 0x3f) == 0b110001) { + return 2; + } + if ((word & 0x3f) == 0b110101) { + return 3; + } + if ((word & 0x3) == 0b01) { + return 1; + } + return -1; +} +void printDigitHCHeader(o2::trd::DigitHCHeader& header, uint32_t headers[3]) +{ + LOGF(INFO, "Digit HalfChamber Header\n Raw:0x%08x reserve:0x%01x side:0x%01x stack:0x%02x layer:0x%02x supermod:0x%02x numberHCW:0x%02x minor:0x%03x major:0x%03x version(>2007):0x%01x \n", + header.word, header.res, header.side, header.stack, header.layer, header.supermodule, + header.numberHCW, header.minor, header.major, header.version); + int countheaderwords = header.numberHCW; + //for the currently 3 implemeented other header words, they can come in any order, and are identified by their reserved portion + for (int countheaderwords = 0; countheaderwords < header.numberHCW; ++countheaderwords) { + switch (getDigitHCHeaderWordType(headers[countheaderwords])) { + case 1: + DigitHCHeader1 header1; + header1.word = headers[countheaderwords]; + if (header1.res != 0x1) { + LOGF(INFO, "*Corrupt* Digit HalfChamber Header1 Raw:0x%08x reserve:0x%02x pretriggercount=0x%02x pretriggerphase=0x%02x bunchxing:0x%05x number of timebins : 0x%03x\n", header1.word, header1.res, header1.ptrigcount, header1.ptrigphase, header1.bunchcrossing, header1.numtimebins); + } else { + LOGF(INFO, "Digit HalfChamber Header1 Raw:0x%08x reserve:0x%02x pretriggercount=0x%02x pretriggerphase=0x%02x bunchxing:0x%05x number of timebins : 0x%03x\n", header1.word, header1.res, header1.ptrigcount, header1.ptrigphase, header1.bunchcrossing, header1.numtimebins); + } + break; + case 2: + DigitHCHeader2 header2; + header2.word = headers[countheaderwords]; + if (header2.res != 0b110001) { + LOGF(INFO, "*Corrupt* Digit HalfChamber Header2 Raw:0x%08x reserve:0x%08x PedestalFilter:0x%01x GainFilter:0x%01x TailFilter:0x%01x CrosstalkFilter:0x%01x Non-linFilter:0x%01x RawDataBypassFilter:0x%01x DigitFilterCommonAdditive:0x%02x ", header2.word, header2.res, header2.dfilter, header2.rfilter, header2.nlfilter, header2.xtfilter, header2.tfilter, header2.gfilter, header2.pfilter); + } else { + LOGF(INFO, "Digit HalfChamber Header2 Raw:0x%08x reserve:0x%08x PedestalFilter:0x%01x GainFilter:0x%01x TailFilter:0x%01x CrosstalkFilter:0x%01x Non-linFilter:0x%01x RawDataBypassFilter:0x%01x DigitFilterCommonAdditive:0x%02x ", header2.word, header2.res, header2.dfilter, header2.rfilter, header2.nlfilter, header2.xtfilter, header2.tfilter, header2.gfilter, header2.pfilter); + } + break; + case 3: + DigitHCHeader3 header3; + header3.word = headers[countheaderwords]; + if (header3.res != 0b110101) { + LOGF(INFO, "*Corrupt*Digit HalfChamber Header3\n Raw:0x%08x reserve:0x%08x readout program revision:0x%08x assembler program version:0x%01x \n", header3.word, header3.res, header3.svnrver, header3.svnver); + } else { + LOGF(INFO, "Digit HalfChamber Header3\n Raw:0x%08x reserve:0x%08x readout program revision:0x%08x assembler program version:0x%01x \n", header3.word, header3.res, header3.svnrver, header3.svnver); + } + break; + } + } +} + +DigitMCMADCMask buildBlankADCMask() +{ + //set the default values for the mask. + DigitMCMADCMask mask; + mask.c = 0x1f; + mask.n = 0x1; + mask.j = 0xc; + // actual mask will beset somewhere else, the above values are *always* that. + return mask; +} + +int getNumberofTracklets(o2::trd::TrackletMCMHeader& header) +{ + int headertrackletcount = 0; + if (header.pid0 == 0xff) { + //LOG(warn) << header; + } else { + if (header.pid2 != 0xff) { + // 3 tracklets + headertrackletcount = 3; + if (header.pid1 == 0xff || header.pid0 == 0xff) { + // LOG(warn) << header; + } + } else { + if (header.pid1 != 0xff) { + // 2 tracklets + headertrackletcount = 2; + if (header.pid0 == 0xff) { + // LOG(warn) << header; + } + } else { + if (header.pid0 != 0xff) { + // 1 tracklet + headertrackletcount = 1; + } else { + // LOG(warn) << header; + } + } + } + } + return headertrackletcount; +} + +void setNumberOfTrackletsInHeader(o2::trd::TrackletMCMHeader& header, int numberoftracklets) +{ + + //header.word |= 0xff<< (1+numberoftracklets*8); + switch (numberoftracklets) { + case 0: + LOG(error) << " tracklet header but no tracklets???"; + header.pid0 = 0xff; + header.pid1 = 0xff; + header.pid2 = 0xff; + break; + case 1: + header.pid1 = 0xff; + header.pid2 = 0xff; + break; + case 2: + header.pid2 = 0xff; + break; + case 3: + break; + default: + LOG(error) << "we have more than 3 tracklets for an mcm. This should never happen: tracklet count=" << numberoftracklets; + } + // LOG(info) << " setting header tracklet number " << numberoftracklets << " header pid0 pid1 pid2 :" << std::hex << header.word << " " << header.pid0 << " " << header.pid1 << " " << header.pid2; +} + +int nextmcmadc(unsigned int& bp, int channel) +{ + //given a bitpattern (adcmask) find next channel with in the mask starting from the current channel; + if (bp == 0) { + return 22; + } + int position = channel; + int m = 1 << channel; + while (!(bp & m)) { + m = m << 1; + position++; + if (position > 31) { + break; + } + } + bp &= ~(1UL << (position)); + return position; +} + } // namespace trd } // namespace o2 diff --git a/DataFormats/Detectors/TRD/src/RawDataStats.cxx b/DataFormats/Detectors/TRD/src/RawDataStats.cxx new file mode 100644 index 0000000000000..4766481ce6997 --- /dev/null +++ b/DataFormats/Detectors/TRD/src/RawDataStats.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Cru raw data reader, this is the part that parses the raw data +// it runs on the flp(pre compression) or on the epn(pre tracklet64 array generation) +// it hands off blocks of cru pay load to the parsers. + +#include <string> +#include <vector> +#include "DataFormatsTRD/RawDataStats.h" + +// Diagnostics data to pass around. +// Primarily to QC and debug graphs built into the readers. +// This file is primarily for the strings that appear at titles in the graphs. + +std::vector<std::string> ParsingErrorsString{"TRDParsingNoError", + "TRDParsingUnrecognisedVersion", + "TRDParsingBadDigt", + "TRDParsingBadTracklet", + "TRDParsingDigitEndMarkerWrongState", + "TRDParsingDigitMCMHeaderSanityCheckFailure", + "TRDParsingDigitROBDecreasing", + "TRDParsingDigitMCMNotIncreasing", + "TRDParsingDigitADCMaskMismatch", + "TRDParsingDigitADCMaskAdvanceToEnd", + "TRDParsingDigitMCMHeaderBypassButStateMCMHeader", + "TRDParsingDigitEndMarkerStateButReadingMCMADCData", + "TRDParsingDigitADCChannel21", + "TRDParsingDigitADCChannelGT22", + "TRDParsingDigitGT10ADCs", + "TRDParsingDigitSanityCheck", + "TRDParsingDigitExcessTimeBins", + "TRDParsingDigitParsingExitInWrongState", + "TRDParsingDigitStackMisMatch", + "TRDParsingDigitLayerMisMatch", + "TRDParsingDigitSectorMisMatch", + "TRDParsingTrackletCRUPaddingWhileParsingTracklets", + "TRDParsingTrackletBit11NotSetInTrackletHCHeader", + "TRDParsingTrackletHCHeaderSanityCheckFailure", + "TRDParsingTrackletMCMHeaderSanityCheckFailure", + "TRDParsingTrackletMCMHeaderButParsingMCMData", + "TRDParsingTrackletStateMCMHeaderButParsingMCMData", + "TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader", + "TRDParsingTrackletInvalidTrackletCount", + "TRDParsingTrackletPadRowIncreaseError", + "TRDParsingTrackletColIncreaseError", + "TRDParsingTrackletNoTrackletEndMarker", + "TRDParsingTrackletExitingNoTrackletEndMarker"}; diff --git a/DataFormats/Detectors/TRD/src/Tracklet64.cxx b/DataFormats/Detectors/TRD/src/Tracklet64.cxx index 63151ddc56546..bc87152d44211 100644 --- a/DataFormats/Detectors/TRD/src/Tracklet64.cxx +++ b/DataFormats/Detectors/TRD/src/Tracklet64.cxx @@ -1,15 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include <iostream> #include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/Constants.h" + +#include "fairlogger/Logger.h" +#include <iostream> namespace o2 { @@ -17,6 +21,9 @@ namespace o2 namespace trd { +using namespace constants; + +#ifndef GPUCA_GPUCODE_DEVICE void Tracklet64::printStream(std::ostream& stream) const { stream << "Tracklet64 : 0x" << std::hex << getTrackletWord(); @@ -31,6 +38,7 @@ std::ostream& operator<<(std::ostream& stream, const Tracklet64& trg) trg.printStream(stream); return stream; } +#endif // GPUCA_GPUCODE_DEVICE } // namespace trd } // namespace o2 diff --git a/DataFormats/Detectors/TRD/src/TriggerRecord.cxx b/DataFormats/Detectors/TRD/src/TriggerRecord.cxx index 50a2e7dbd6462..ac85420d12202 100644 --- a/DataFormats/Detectors/TRD/src/TriggerRecord.cxx +++ b/DataFormats/Detectors/TRD/src/TriggerRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,10 @@ namespace trd void TriggerRecord::printStream(std::ostream& stream) const { - stream << "Data for bc " << getBCData().bc << ", orbit " << getBCData().orbit << ", starting from entry " << getFirstEntry() << " with " << getNumberOfObjects() << " objects"; + stream << "Data for bc " << getBCData().bc << ", orbit " << getBCData().orbit + << ", starting from digit entry " + << getFirstDigit() << " with " << getNumberOfDigits() << " digits and tracklet entry " + << getFirstTracklet() << " with " << getNumberOfTracklets(); } std::ostream& operator<<(std::ostream& stream, const TriggerRecord& trg) diff --git a/DataFormats/Detectors/TRD/test/testDigit.cxx b/DataFormats/Detectors/TRD/test/testDigit.cxx new file mode 100644 index 0000000000000..1406cc8671e0c --- /dev/null +++ b/DataFormats/Detectors/TRD/test/testDigit.cxx @@ -0,0 +1,182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file testTRDGeometry.cxx +/// \brief This task tests the Geometry +/// \author Sean Murray, murrays@cern.ch + +#define BOOST_TEST_MODULE Test TRD_Digit +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <iostream> +#include <numeric> + +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/Constants.h" + +namespace o2 +{ +namespace trd +{ + +using namespace o2::trd::constants; + +void testDigitDetRowPad(Digit& test, int det, int row, int pad) +{ + BOOST_CHECK(test.getPadCol() == pad); + BOOST_CHECK(test.getPadRow() == row); + BOOST_CHECK(test.getDetector() == det); +} + +void testDigitDetROBMCM(Digit& test, int det, int rob, int mcm, int channel) +{ + BOOST_CHECK(test.getMCM() == mcm); + BOOST_CHECK(test.getROB() == rob); + BOOST_CHECK(test.getChannel() == channel); + BOOST_CHECK(test.getDetector() == det); +} + +BOOST_AUTO_TEST_CASE(TRDDigit_test) +{ + //TPD + //pg 14 for rob to chamber + // + // 540 read out chambers (detector) + // each one is made up of 16 row of 144 pads. + // each one is also made up of 8 or 6 read out boards comprising 16 mcm and 21 adc each. + // we need to check the pad,row to rob,mcm and back and the inverse holds true. + // also the boundaries hold true.ends, of readout boards, ends of mcm. + // + //check digit at bottom of row is correctly assigned. + + // a pad row spans 2 read out boards. with 4 mcm in each. + // i.e. pad row 0 will have read out board 0 and 1 and mcm 0-4 and 0-4 in each making up the 8 mcm in the pad row. + // channel 0 and 1 of MCM n are shared with 18 and 19 (respectively) of MCM n+1 and channel 20 of MCM n is shared with MCM n-1 channel 2 + // channel 20 of MCM n is connected to the preceding MCM's highest number pad. i.e. MCM01 channel 20 is connected to MCM00 pad 17 (18th pad) of row. + + // so check various combinations of that, mostly just the boundaries. + Digit first(0, 0, 0); //det row pad + BOOST_CHECK(first.getMCM() == 0); + + Digit last(MAXCHAMBER - 1, NROWC1 - 1, NCOLUMN - 1); // last det row and pad + BOOST_CHECK(last.getMCM() == NMCMROB - 1); + // end of first mcm + Digit a(0, 0, NCOLMCM - 1); + BOOST_CHECK(a.getMCM() == 0); + // start of new mcm? + Digit b(0, 0, NCOLMCM); + BOOST_CHECK(b.getMCM() == 1); + // last pad connected to start of new mcm? + Digit c(0, 0, 89); + BOOST_CHECK(c.getMCM() == 0); + // last pad connected to start of new mcm? + Digit d(0, 0, 90); + BOOST_CHECK(d.getMCM() == 1); + // now to test if we set the rob and mcm do we get the correct pad and row. + // using the reciprical of the values above for simplicity. + // + //test block 1. + Digit e(0, 0, 0, 0); + //first channel of the first mcm, this is in fact the 19 pad of the first row, and connected to the 18th adc of the second trap ... + Digit f(0, e.getPadRow(), e.getPadCol()); // createa digit based on the above digits pad and row. + // we *shoulud* end up with a rob:mcm of 0:1 and channel 18 + testDigitDetROBMCM(f, 0, 0, 1, NCOLMCM); + + Digit g(0, 0, NCOLMCM - 1); // row 0 pad 17 --- should be mcm 0 and channel 2 + testDigitDetROBMCM(g, 0, 0, 0, 2); + + Digit h(0, 0, 0, 2); + testDigitDetRowPad(h, 0, 0, NCOLMCM - 1); + + //test block2 repeat block1 but at the edge of a rob boundary i.e. going from row0 the 72nd pad to 73rd. Spanning the half of 144(NCOLUMN) + Digit i(0, 0, (NCOLUMN / 2) - 1); + testDigitDetROBMCM(i, 0, 0, 3, 2); + //check the reverse creation + Digit k(0, 0, 3, 2); + testDigitDetRowPad(k, 0, 0, (NCOLUMN / 2) - 1); + + Digit j(0, 0, NCOLUMN / 2); + testDigitDetROBMCM(j, 0, 1, 0, 19); + //check the reverse creation + Digit l(0, 1, 0, 19); + testDigitDetRowPad(l, 0, 0, NCOLUMN / 2); + + // now repeat the same for another part of the first chamber, middle rows + // + Digit m(0, 12, (NCOLUMN / 2) - 1); + testDigitDetROBMCM(m, 0, 6, 3, 2); + //check the reverse creation + Digit n(0, 6, 3, 2); + testDigitDetRowPad(n, 0, 12, (NCOLUMN / 2) - 1); + + Digit o(0, 12, NCOLMCM - 1); + testDigitDetROBMCM(o, 0, 6, 0, 2); + Digit p(0, 6, 0, 2); + testDigitDetRowPad(p, 0, 12, NCOLMCM - 1); + + //and now for the last row. + Digit q(0, 15, (NCOLUMN / 2) - 1); + testDigitDetROBMCM(q, 0, 6, 15, 2); + //check the reverse creation + Digit r(0, 6, 3, 2); + testDigitDetRowPad(r, 0, 12, (NCOLUMN / 2) - 1); + + Digit s(0, 15, NCOLMCM - 1); + testDigitDetROBMCM(s, 0, 6, 12, 2); + Digit t(0, 6, 0, 2); + testDigitDetRowPad(t, 0, 12, NCOLMCM - 1); + + // as a last check that for detector changes. + // + Digit u(1, 15, (NCOLUMN / 2) - 1); + testDigitDetROBMCM(u, 1, 6, 15, 2); + //check the reverse creation + Digit v(1, 6, 3, 2); + testDigitDetRowPad(v, 1, 12, (NCOLUMN / 2) - 1); + + Digit w(10, 15, NCOLMCM - 1); + testDigitDetROBMCM(w, 10, 6, 12, 2); + Digit x(10, 6, 0, 2); + testDigitDetRowPad(x, 10, 12, NCOLMCM - 1); + + /* + * The below is left in, it helps to remove confusion when debugging + for(int rob=0;rob<8;rob++)for(int mcm=0;mcm<16;mcm++)for(int channel=0;channel<21;channel++){ + std::cout << "Digit e(0,"<<rob<<"," << mcm <<","<< channel<<");" << std::endl; + Digit e(0,rob,mcm,channel); + std::cout << " e is " << e.getPadRow() << " " << e.getPadCol(); + std::cout << " for an rob:mcm combo of " << e.getROB() << ":"<< e.getMCM() << " and adc channel:" << e.getChannel() <<std::endl; + std::cout << "Digit f(0,e.getPadRow(),e.getPadCol())" << std::endl;; + Digit f(0,e.getPadRow(),e.getPadCol()); + std::cout << " f is " << f.getPadRow() << " " << f.getPadCol(); + std::cout << " for an rob:mcm combo of " << f.getROB() << ":"<< f.getMCM() << " and adc channel:" << f.getChannel() <<std::endl; + std::cout << "*********************************************************************" << std::endl; + } + */ + + //now check that the timebins get correctly assigned on instantiation + ArrayADC data; + std::iota(data.begin(), data.end(), 42); // 42 for my personal amusement. + Digit z(10, 15, NCOLMCM - 1, data); + testDigitDetROBMCM(z, 10, 6, 12, 2); + //test adc values are true. + BOOST_CHECK(z.getADC()[4] == 46); // 4th time bin should be 46; + BOOST_CHECK(z.getADC()[6] == 48); // 6th time bin should be 48; + + Digit za(10, 6, 0, 2, data); + testDigitDetRowPad(za, 10, 12, NCOLMCM - 1); + BOOST_CHECK(za.getADC()[14] == 56); // 14th time bin should be 56; + BOOST_CHECK(za.getADC()[16] == 58); // 16th time bin should be 58; +} + +} // namespace trd +} // namespace o2 diff --git a/DataFormats/Detectors/Upgrades/CMakeLists.txt b/DataFormats/Detectors/Upgrades/CMakeLists.txt index ddf642acf6e90..a2d470b8ff6d5 100644 --- a/DataFormats/Detectors/Upgrades/CMakeLists.txt +++ b/DataFormats/Detectors/Upgrades/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. message(STATUS "Building dataformats for upgrades") diff --git a/DataFormats/Detectors/ZDC/CMakeLists.txt b/DataFormats/Detectors/ZDC/CMakeLists.txt index a5c1fec2c14c4..59bbb6be124cc 100644 --- a/DataFormats/Detectors/ZDC/CMakeLists.txt +++ b/DataFormats/Detectors/ZDC/CMakeLists.txt @@ -1,21 +1,28 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsZDC - SOURCES src/ChannelData.cxx src/BCData.cxx src/RecEvent.cxx - src/OrbitRawData.cxx src/OrbitRecData.cxx + SOURCES src/ChannelData.cxx src/BCData.cxx src/BCRecData.cxx src/RecEvent.cxx src/RecEventAux.cxx src/RawEventData.cxx + src/OrbitRawData.cxx src/OrbitRecData.cxx src/OrbitData.cxx src/ZDCTDCData.cxx src/ZDCEnergy.cxx + src/CTF.cxx src/RecEventFlat.cxx PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::CommonDataFormat - O2::ZDCBase ROOT::MathCore FairRoot::Base - O2::MathUtils ms_gsl::ms_gsl) + O2::ZDCBase ROOT::MathCore FairRoot::Base + O2::SimulationDataFormat + O2::MathUtils Microsoft.GSL::GSL) o2_target_root_dictionary(DataFormatsZDC - HEADERS include/DataFormatsZDC/BCData.h include/DataFormatsZDC/ChannelData.h - include/DataFormatsZDC/RecEvent.h include/DataFormatsZDC/OrbitRawData.h - include/DataFormatsZDC/OrbitRecData.h) + HEADERS include/DataFormatsZDC/Hit.h include/DataFormatsZDC/MCLabel.h + include/DataFormatsZDC/BCData.h include/DataFormatsZDC/ChannelData.h + include/DataFormatsZDC/OrbitData.h include/DataFormatsZDC/CTF.h + include/DataFormatsZDC/RecEvent.h include/DataFormatsZDC/RecEventAux.h include/DataFormatsZDC/RecEventFlat.h + include/DataFormatsZDC/OrbitRawData.h include/DataFormatsZDC/ZDCTDCData.h + include/DataFormatsZDC/BCRecData.h include/DataFormatsZDC/ZDCEnergy.h + include/DataFormatsZDC/OrbitRecData.h include/DataFormatsZDC/RawEventData.h) diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h index 32213f8ec4d58..cdbf813db318d 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef _ZDC_BC_DATA_H_ -#define _ZDC_BC_DATA_H_ +#ifndef O2_ZDC_BC_DATA_H_ +#define O2_ZDC_BC_DATA_H_ #include "CommonDataFormat/InteractionRecord.h" #include "CommonDataFormat/RangeReference.h" @@ -27,10 +28,30 @@ namespace zdc { class ChannelData; +struct __attribute__((__packed__)) ModuleTriggerMap { + unsigned Alice_0 : 1; + unsigned Alice_1 : 1; + unsigned Alice_2 : 1; + unsigned Alice_3 : 1; + unsigned Auto_m : 1; + unsigned Auto_0 : 1; + unsigned Auto_1 : 1; + unsigned Auto_2 : 1; + unsigned Auto_3 : 1; + unsigned empty : 7; +}; + +union ModuleTriggerMapData { + uint16_t w; + struct ModuleTriggerMap f; + void reset(); +}; + struct BCData { /// we are going to refer to at most 26 channels, so 5 bits for the NChannels and 27 for the reference o2::dataformats::RangeRefComp<5> ref; o2::InteractionRecord ir; + std::array<uint16_t, NModules> moduleTriggers{}; uint32_t channels = 0; // pattern of channels it refers to uint32_t triggers = 0; // pattern of triggered channels (not necessarily stored) in this BC uint8_t ext_triggers = 0; // pattern of ALICE triggers @@ -45,11 +66,12 @@ struct BCData { triggers = chTrig; ext_triggers = extTrig; } + BCData(const BCData&) = default; gsl::span<const ChannelData> getBunchChannelData(const gsl::span<const ChannelData> tfdata) const; - void print() const; + void print(uint32_t triggerMask = 0, int diff = 0) const; - ClassDefNV(BCData, 1); + ClassDefNV(BCData, 2); }; } // namespace zdc } // namespace o2 diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h new file mode 100644 index 0000000000000..c7c8f2f23dd4e --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_BC_REC_DATA_H +#define O2_ZDC_BC_REC_DATA_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <gsl/span> + +/// \file BCRecData.h +/// \brief Class to refer to the reconstructed information +/// \author ruben.shahoyan@cern.ch, pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ +class ChannelData; + +struct BCRecData { + o2::InteractionRecord ir; + uint32_t channels = 0; // Pattern of channels acquired + uint32_t triggers = 0; // Pattern of channels with autotrigger bit + o2::dataformats::RangeRefComp<5> refe; // Reference to reconstructed energy + o2::dataformats::RangeRefComp<5> reft; // Reference to reconstructed TDC + o2::dataformats::RangeRefComp<5> refi; // Reference to reconstruction error/information flags + + BCRecData() = default; + + // Insert interaction record for new event (will set later the number of entries) + BCRecData(int firste, int firstt, int firsti, o2::InteractionRecord iRec) + { + refe.setFirstEntry(firste); + refe.setEntries(0); + reft.setFirstEntry(firstt); + reft.setEntries(0); + refi.setFirstEntry(firsti); + refi.setEntries(0); + ir = iRec; + } + + // Update counter of energy entries + inline void addEnergy() + { + refe.setEntries(refe.getEntries() + 1); + } + + // Update counter of TDC entries + inline void addTDC() + { + reft.setEntries(reft.getEntries() + 1); + } + + // Update counter of Info entries + inline void addInfo() + { + refi.setEntries(refi.getEntries() + 1); + } + + // Get information about event + inline void getRef(int& firste, int& ne, int& firstt, int& nt, int& firsti, int& ni) + { + firste = refe.getFirstEntry(); + firstt = reft.getFirstEntry(); + firsti = refi.getFirstEntry(); + ne = refe.getEntries(); + nt = reft.getEntries(); + ni = refi.getEntries(); + } + + void print() const; + + ClassDefNV(BCRecData, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/CTF.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/CTF.h new file mode 100644 index 0000000000000..7c3e8bdc163f7 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/CTF.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTF.h +/// \author ruben.shahoyan@cern.ch +/// \brief Definitions for ZDC CTF data + +#ifndef O2_ZDC_CTF_H +#define O2_ZDC_CTF_H + +#include <vector> +#include <Rtypes.h> +#include "DetectorsCommonDataFormats/EncodedBlocks.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/OrbitData.h" + +namespace o2 +{ +namespace zdc +{ + +/// Header for a single CTF +struct CTFHeader : public o2::ctf::CTFDictHeader { + uint32_t nTriggers = 0; /// number of triggers + uint32_t nChannels = 0; /// number of referred channels + uint32_t nEOData = 0; /// number of end-of-orbit data objects (pedestal + scalers) + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint32_t firstOrbitEOData = 0; /// orbit of 1st end-of-orbit data + uint16_t firstBC = 0; /// bc of 1st trigger + std::array<uint16_t, NChannels> firstScaler{}; // inital scaler values + ClassDefNV(CTFHeader, 2); +}; + +/// wrapper for the Entropy-encoded triggers and cells of the TF +struct CTF : public o2::ctf::EncodedBlocks<CTFHeader, 12, uint32_t> { + + static constexpr size_t N = getNBlocks(); + enum Slots { BLC_bcIncTrig, + BLC_orbitIncTrig, + BLC_moduleTrig, + BLC_channelsHL, // 32-bit channels pattern word split to 2 16-bit words stored as H, then L + BLC_triggersHL, // 32-bit trigger word split to 2 16-bit words stored as H, then L + BLC_extTriggers, + BLC_nchanTrig, + // + BLC_chanID, + BLC_chanData, + // + BLC_orbitIncEOD, + BLC_pedData, + BLC_sclInc + }; + ClassDefNV(CTF, 1); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ChannelData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ChannelData.h index 5ae041e690633..e33cd7ea95ad4 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ChannelData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ChannelData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,7 @@ struct ChannelData { data[i] = int16_t(src[i]); } } + ChannelData(const ChannelData&) = default; void print() const; diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h new file mode 100644 index 0000000000000..b084507b84519 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// DataFormats/Detectors/ZDC/include/DataFormatsZDC/RawEventData.h + +#include "ZDCBase/Constants.h" + +#ifndef ALICEO2_ZDC_FEECONFIG_H +#define ALICEO2_ZDC_FEECONFIG_H + +/// \file FEEConfig.h +/// \brief ZDC FEE configuration +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct FEEFillingMap { + uint64_t filling[56]; +}; + +struct FEEConfigMap { + uint32_t address[5 * NChPerModule + 3] = {0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 76, 77, 78}; + uint64_t delay_sample[NChPerModule] = {6, 6, 6, 6}; // 4 bits + uint64_t delay_coarse[NChPerModule] = {200, 200, 200, 200}; // 8 bits + uint64_t threshold_level[NChPerModule] = {10, 10, 10, 10}; // 12 bits + uint64_t difference_delta[NChPerModule] = {4, 4, 4, 4}; // 3 bits + uint64_t masking_difference[NChPerModule] = {0x00ff00, 0x00ff00, 0x00ff00, 0x00ff00}; // 24 bits + uint64_t masking_alicet = 0x00000010; // 32 bits + uint64_t masking_autot = 0xf; // 4 bits + uint64_t masking_readout = 0xf; // 4 bits +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/Hit.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/Hit.h new file mode 100644 index 0000000000000..6e0b99dca6761 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/Hit.h @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Hit.h +/// \brief Definition of the ZDC Hit class + +#ifndef ALICEO2_ZDC_HIT_H_ +#define ALICEO2_ZDC_HIT_H_ + +#include "SimulationDataFormat/BaseHits.h" // for BasicXYZEHit +#include "CommonUtils/ShmAllocator.h" + +namespace o2 +{ +namespace zdc +{ + +class Hit : public o2::BasicXYZEHit<Float_t, Float_t> +{ + + public: + // Default constructor + Hit() = default; + + /// Class Constructor + /// \param trackID Index of MCTrack + /// \param detID Detector ID + /// \param parent mother of the track + /// \param sflag true if it is a secondary + /// \param primaryEnergy energy of the primary [GeV] + /// \param detID detector ID (1-ZNA, 2-ZPA, 3-ZEM, 4-ZNC, 5-ZPC) + /// \param sectorID sector ID + /// \param pos track position + /// \param mom track momentum + /// \param tof track TOF + /// \param xImpact x,y,z of the impact of the 1st particle + /// \param energyloss deposited energy + /// \param nphePMC light output on common PMT + /// \param nphePMQ light output on sector PMT + Hit(int trackID, int parent, Bool_t sFlag, Float_t primaryEnergy, Int_t detID, Int_t sectorID, + math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, Float_t energyloss, Int_t nphePMC, + Int_t nphePMQ); + + void setPMCLightYield(float val) { mNphePMC = val; } + void setPMQLightYield(float val) { mNphePMQ = val; } + void setNoNumContributingSteps(int val) { mNoContributingSteps = val; } + + int getParentID() const { return mParentID; } + int getSector() const { return mSectorID; } + float getPMCLightYield() const { return mNphePMC; } + float getPMQLightYield() const { return mNphePMQ; } + int getNumContributingSteps() const { return mNoContributingSteps; } + + private: + Int_t mParentID; + Bool_t mSecFlag; + Float_t mPrimaryEnergy; + Int_t mNoContributingSteps = 1; + Int_t mSectorID; + math_utils::Vector3D<float> mMomentum; + math_utils::Vector3D<float> mXImpact; + Int_t mNphePMC; + Int_t mNphePMQ; + + ClassDefNV(Hit, 1); +}; + +inline Hit::Hit(int trackID, int parent, Bool_t sFlag, Float_t primaryEnergy, Int_t detID, Int_t sectorID, + math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, Float_t energyloss, + Int_t nphePMC, Int_t nphePMQ) + : BasicXYZEHit(pos.X(), pos.Y(), pos.Z(), tof, energyloss, trackID, detID), + mParentID(parent), + mSecFlag(sFlag), + mPrimaryEnergy(primaryEnergy), + mSectorID(sectorID), + mMomentum(mom.X(), mom.Y(), mom.Z()), + mXImpact(xImpact), + mNphePMC(nphePMC), + mNphePMQ(nphePMQ) +{ +} +} // namespace zdc +} // namespace o2 + +#ifdef USESHM +namespace std +{ +template <> +class allocator<o2::zdc::Hit> : public o2::utils::ShmAllocator<o2::zdc::Hit> +{ +}; +} // namespace std + +#endif + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/MCLabel.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/MCLabel.h new file mode 100644 index 0000000000000..e67ffe673e2a7 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/MCLabel.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Declaration of a transient MC label class for ZDC + +#ifndef ALICEO2_ZDC_MCLABEL_H_ +#define ALICEO2_ZDC_MCLABEL_H_ + +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ +namespace zdc +{ +class MCLabel : public o2::MCCompLabel +{ + private: + Int_t mChannel = -1; + + public: + MCLabel() = default; + MCLabel(Int_t trackID, Int_t eventID, Int_t srcID, Int_t chID) + : o2::MCCompLabel(trackID, eventID, srcID, false), mChannel(chID) {} + + Int_t getChannel() const { return mChannel; } + + ClassDefNV(MCLabel, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h new file mode 100644 index 0000000000000..9c35d400608fa --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef _ZDC_PEDESTAL_DATA_H_ +#define _ZDC_PEDESTAL_DATA_H_ + +#include "CommonDataFormat/InteractionRecord.h" +#include "ZDCBase/Constants.h" +#include <array> +#include <Rtypes.h> + +/// \file Pedestal.h +/// \brief Class to describe pedestal data accumulated over the orbit +/// \author ruben.shahoyan@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct OrbitData { + o2::InteractionRecord ir; + std::array<int16_t, NChannels> data{}; + std::array<uint16_t, NChannels> scaler{}; + + float asFloat(int i) const { return data[i] / 8.; } + void print() const; + + ClassDefNV(OrbitData, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRawData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRawData.h index 09195353c65bc..e988e6f5d0c95 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRawData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRawData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRecData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRecData.h index c7033731d693b..ee46ca18e44d7 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRecData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitRecData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RawEventData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RawEventData.h new file mode 100644 index 0000000000000..1797e1998d24b --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RawEventData.h @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// DataFormats/Detectors/ZDC/include/DataFormatsZDC/RawEventData.h + +#ifndef ALICEO2_ZDC_RAWEVENTDATA_H_ +#define ALICEO2_ZDC_RAWEVENTDATA_H_ +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <iostream> +#include <gsl/span> + +/// \file RawEventData.h +/// \brief Container of ZDC raw data +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +constexpr unsigned short Id_w0 = 0x0; +constexpr unsigned short Id_w1 = 0x1; +constexpr unsigned short Id_w2 = 0x2; +constexpr unsigned short Id_wn = 0x3; +constexpr int NWPerGBTW = 4; + +struct __attribute__((__packed__)) ChannelDataV0 { + // First GBT word + unsigned fixed_0 : 2; + unsigned board : 4; + unsigned ch : 2; + unsigned offset : 16; + unsigned hits : 12; + unsigned bc : 12; + unsigned orbit : 32; + unsigned empty_0 : 16; + unsigned empty_1 : 32; + + // Second GBT word + unsigned fixed_1 : 2; + unsigned error : 2; + unsigned Alice_0 : 1; + unsigned Alice_1 : 1; + unsigned Alice_2 : 1; + unsigned Alice_3 : 1; + unsigned s00 : 12; + unsigned s01 : 12; + unsigned s02 : 12; + unsigned s03 : 12; + unsigned s04 : 12; + unsigned s05 : 12; + unsigned empty_2 : 16; + unsigned empty_3 : 32; + + // Third GBT word + unsigned fixed_2 : 2; + unsigned Hit : 1; + unsigned Auto_m : 1; + unsigned Auto_0 : 1; + unsigned Auto_1 : 1; + unsigned Auto_2 : 1; + unsigned Auto_3 : 1; + unsigned s06 : 12; + unsigned s07 : 12; + unsigned s08 : 12; + unsigned s09 : 12; + unsigned s10 : 12; + unsigned s11 : 12; + unsigned empty_4 : 16; + unsigned empty_5 : 32; +}; + +union EventChData { + UInt_t w[NWPerBc][NWPerGBTW]; + struct ChannelDataV0 f; + void reset(); +}; + +struct EventData { + EventChData data[NModules][NChPerModule] = {0}; + void print() const; + void reset(); + ClassDefNV(EventData, 1); +}; + +} // namespace zdc +} // namespace o2 +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h index a21812e8306e7..120d75e56c556 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,55 +12,132 @@ #ifndef _ZDC_RECEVENT_H_ #define _ZDC_RECEVENT_H_ +#include "Framework/Logger.h" #include "CommonDataFormat/InteractionRecord.h" -#include "MathUtils/Cartesian.h" +#include "DataFormatsZDC/BCRecData.h" +#include "DataFormatsZDC/ZDCEnergy.h" +#include "DataFormatsZDC/ZDCTDCData.h" #include "ZDCBase/Constants.h" +#include "MathUtils/Cartesian.h" #include <Rtypes.h> #include <array> +#include <vector> +#include <map> /// \file RecEvent.h /// \brief Class to describe reconstructed ZDC event (single BC with signal in one of detectors) -/// \author cortese@to.infn.it, ruben.shahoyan@cern.ch +/// \author pietro.cortese@cern.ch, ruben.shahoyan@cern.ch namespace o2 { namespace zdc { - struct RecEvent { - using TDCChannel = std::array<float, MaxTDCValues>; + std::vector<o2::zdc::BCRecData> mRecBC; /// Interaction record and references to data + std::vector<o2::zdc::ZDCEnergy> mEnergy; /// ZDC energy + std::vector<o2::zdc::ZDCTDCData> mTDCData; /// ZDC TDC + std::vector<uint16_t> mInfo; /// Event quality information + // Add new bunch crossing without data + inline void addBC(o2::InteractionRecord ir) + { + mRecBC.emplace_back(mEnergy.size(), mTDCData.size(), mInfo.size(), ir); + } + inline void addBC(o2::InteractionRecord ir, uint32_t channels, uint32_t triggers) + { + mRecBC.emplace_back(mEnergy.size(), mTDCData.size(), mInfo.size(), ir); + mRecBC.back().channels = channels; + mRecBC.back().triggers = triggers; + } + // Add energy + inline void addEnergy(uint8_t ch, float energy) + { + mEnergy.emplace_back(ch, energy); + mRecBC.back().addEnergy(); + } + // Add TDC + inline void addTDC(uint8_t ch, int16_t val, int16_t amp) + { + mTDCData.emplace_back(ch, val, amp); + mRecBC.back().addTDC(); + } + // Add event information + inline void addInfo(uint16_t info) + { +#ifdef O2_ZDC_DEBUG + printf("addInfo info=%u 0x%04x\n", info, info); +#endif + mInfo.emplace_back(info); + mRecBC.back().addInfo(); + } - o2::InteractionRecord ir; - uint32_t flags; /// reconstruction flags - std::array<float, NChannelsZEM> eneregyZEM; /// signal in the electromagnetic ZDCs - std::array<float, NChannelsZN> energyZNA; /// reco E in 5 ZNA sectors + sum - std::array<float, NChannelsZN> energyZNC; /// reco E in 5 ZNC sectors + sum - std::array<float, NChannelsZP> energyZPA; /// reco E in 5 ZPA sectors + sum - std::array<float, NChannelsZP> energyZPC; /// reco E in 5 ZPC sectors + sum - math_utils::Point2D<float> centroidZNA; /// centroid coordinates for ZNA - math_utils::Point2D<float> centroidZNC; /// centroid coordinates for ZNC - std::array<TDCChannel, NTDCChannels> tdcChannels; /// At most MaxTDCValues Values in ns per TDC channel + inline void addInfo(uint8_t ch, uint16_t code) + { + if (ch >= NChannels && ch != 0x1f) { + LOGF(ERROR, "Adding info (0x%x) for not existent channel %u", code, ch); + return; + } + uint16_t info = (code & 0x03ff) | ((ch & 0x1f) << 10); +#ifdef O2_ZDC_DEBUG + printf("addInfo ch=%u code=%u info=%u 0x%04x\n", ch, code, info, info); +#endif + mInfo.emplace_back(info); + mRecBC.back().addInfo(); + } - void print() const; + void addInfo(const std::array<bool, NChannels>& vec, const uint16_t code) + { + // Prepare list of channels interested by this message + int cnt = 0; + std::array<int, NChannels> active; + for (uint8_t ich = 0; ich < NChannels; ich++) { + if (vec[ich] == true) { + active[cnt] = ich; + cnt++; + } + } + if (cnt == 0) { + return; + } +#ifdef O2_ZDC_DEBUG + printf("addInfo("); + for (uint8_t ich = 0; ich < NChannels; ich++) { + if (vec[ich] == true) { + printf("1"); + } else { + printf("0"); + } + } + printf(", code=%u \"%s\") %d active.\n", code, MsgText[code].data(), cnt); +#endif + if (cnt <= 3) { + // Transmission of single channels + for (uint8_t i = 0; i < cnt; i++) { + addInfo(active[i], code); + } + } else { + // Transmission of channel pattern + uint16_t ch = 0x1f; + addInfo(ch, code); + uint16_t info = 0x8000; + uint8_t i = 0; + for (; i < cnt && active[i] < 15; i++) { + info = info | (0x1 << active[i]); + } + addInfo(info); + info = 0x8000; + for (; i < cnt; i++) { + info = info | (0x1 << (active[i] - 15)); + } + addInfo(info); + } + } + void print() const; + // TODO: remove persitency of this object (here for debugging) ClassDefNV(RecEvent, 1); }; } // namespace zdc - -/// Defining RecEvent explicitly as messageable -/// -/// It does not fulfill is_messageable because the underlying ROOT -/// classes of Point2D are note trivially copyable. -namespace framework -{ -template <typename T> -struct is_messageable; -template <> -struct is_messageable<o2::zdc::RecEvent> : std::true_type { -}; -} // namespace framework - } // namespace o2 #endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h new file mode 100644 index 0000000000000..aeb5a519dcb98 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_RECEVENT_AUX_H +#define ZDC_RECEVENT_AUX_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "MathUtils/Cartesian.h" +#include "DataFormatsZDC/RecEventFlat.h" +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <array> +#include <vector> +#include <map> + +/// \file RecEvent.h +/// \brief Class to describe reconstructed ZDC event (single BC with signal in one of detectors) during the reconstruction stage +/// \author cortese@to.infn.it, ruben.shahoyan@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct RecEventAux : public RecEventFlat { + uint32_t flags; /// reconstruction flags +#ifdef O2_ZDC_TDC_C_ARRAY + int16_t tdcVal[NTDCChannels][MaxTDCValues]; /// TdcChannels + int16_t tdcAmp[NTDCChannels][MaxTDCValues]; /// TdcAmplitudes +#endif + int ntdc[NTDCChannels] = {0}; /// Number of hits in TDC + std::array<bool, NTDCChannels> pattern; /// Pattern of TDC + uint16_t fired[NTDCChannels] = {0}; /// Position at which the trigger algorithm is fired + uint32_t ref[NChannels]; /// Cache of references + std::array<bool, NChannels> err; /// Generic error condition +#ifdef O2_ZDC_INTERP_DEBUG + float inter[NTDCChannels][NTimeBinsPerBC * TSN] = {0}; /// Interpolated samples +#endif + // Functions + RecEventAux() + { + for (int32_t i = 0; i < NChannels; i++) { + ref[i] = ZDCRefInitVal; + } + } + + void print() const; + ClassDefNV(RecEventAux, 1); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h new file mode 100644 index 0000000000000..781e6855abe7f --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h @@ -0,0 +1,180 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef _ZDC_RECEVENTFLAT_H_ +#define _ZDC_RECEVENTFLAT_H_ + +#include "CommonDataFormat/RangeReference.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsZDC/BCRecData.h" +#include "DataFormatsZDC/ZDCEnergy.h" +#include "DataFormatsZDC/ZDCTDCData.h" +#include "ZDCBase/Constants.h" +#include "MathUtils/Cartesian.h" +#include <Rtypes.h> +#include <array> +#include <vector> +#include <map> + +/// \file RecEventFlat.h +/// \brief Class to decode the reconstructed ZDC event (single BC with signal in one of detectors) +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ +using FirstEntry = int; +using NElem = int; + +struct RecEventFlat { //NOLINT: false positive in clang-tidy !! + o2::InteractionRecord ir; + uint32_t channels = 0; /// pattern of channels acquired + uint32_t triggers = 0; /// pattern of channels with autotrigger bit + std::map<uint8_t, float> ezdc; /// signal in ZDCs + std::vector<int16_t> TDCVal[NTDCChannels]; /// TdcChannels + std::vector<int16_t> TDCAmp[NTDCChannels]; /// TdcAmplitudes + std::vector<o2::zdc::BCRecData>* mRecBC; //! Interaction record and references to data + std::vector<o2::zdc::ZDCEnergy>* mEnergy; //! ZDC energy + std::vector<o2::zdc::ZDCTDCData>* mTDCData; //! ZDC TDC + std::vector<uint16_t>* mInfo; //! Event quality information + uint64_t mEntry = 0; //! Current entry + uint64_t mNEntries = 0; //! Number of entries + FirstEntry mFirstE = 0; //! First energy + FirstEntry mFirstT = 0; //! First TDC + FirstEntry mFirstI = 0; //! First info + FirstEntry mStopE = 0; //! Last + 1 energy + FirstEntry mStopT = 0; //! Last + 1 TDC + FirstEntry mStopI = 0; //! Last + 1 info + NElem mNE = 0; //! N energy + NElem mNT = 0; //! N TDC + NElem mNI = 0; //! N info + o2::zdc::BCRecData mCurB; //! Current BC + std::array<bool, NChannels> tdcPedEv = {0}; /// Event pedestal for TDC + std::array<bool, NChannels> tdcPedOr = {0}; /// Orbit pedestal for TDC + std::array<bool, NChannels> tdcPedQC = {0}; /// QC pedestal for TDC + std::array<bool, NChannels> tdcPedMissing = {0}; /// Missing pedestal for ADC + std::array<bool, NChannels> adcPedEv = {0}; /// Event pedestal for ADC + std::array<bool, NChannels> adcPedOr = {0}; /// Orbit pedestal for ADC + std::array<bool, NChannels> adcPedQC = {0}; /// QC pedestal for ADC + std::array<bool, NChannels> adcPedMissing = {0}; /// Missing pedestal for ADC + uint8_t mVerbosity = DbgZero; //! Verbosity level + uint32_t mTriggerMask = 0; //! Trigger mask for printout + + void init(std::vector<o2::zdc::BCRecData>* RecBC, std::vector<o2::zdc::ZDCEnergy>* Energy, std::vector<o2::zdc::ZDCTDCData>* TDCData, std::vector<uint16_t>* Info); + + int next(); + + inline NElem getNEnergy() const + { + return mNE; + } + + inline NElem getNTDC() const + { + return mNT; + } + + inline NElem getNInfo() const + { + return mNI; + } + + float tdcV(uint8_t ich, uint64_t ipos) const + { + if (ich < NTDCChannels) { + if (ipos < TDCVal[ich].size()) { + return FTDCVal * TDCVal[ich][ipos]; + } + } + return -std::numeric_limits<float>::infinity(); + } + + float tdcA(uint8_t ich, uint64_t ipos) const + { + if (ich < NTDCChannels) { + if (ipos < TDCAmp[ich].size()) { + return FTDCAmp * TDCAmp[ich][ipos]; + } + } + return -std::numeric_limits<float>::infinity(); + } + + int NtdcV(uint8_t ich) const + { + if (ich < NTDCChannels) { + return TDCVal[ich].size(); + } else { + return 0; + } + } + + int NtdcA(uint8_t ich) const + { + if (ich < NTDCChannels) { + return TDCAmp[ich].size(); + } else { + return 0; + } + } + + float EZDC(uint8_t ich) const + { + std::map<uint8_t, float>::const_iterator it = ezdc.find(ich); + if (it != ezdc.end()) { + return it->second; + } else { + return -std::numeric_limits<float>::infinity(); + } + } + + float EZNAC() const { return EZDC(IdZNAC); } + float EZNA1() const { return EZDC(IdZNA1); } + float EZNA2() const { return EZDC(IdZNA2); } + float EZNA3() const { return EZDC(IdZNA3); } + float EZNA4() const { return EZDC(IdZNA4); } + float EZNASum() const { return EZDC(IdZNASum); } + + float EZPAC() const { return EZDC(IdZPAC); } + float EZPA1() const { return EZDC(IdZPA1); } + float EZPA2() const { return EZDC(IdZPA2); } + float EZPA3() const { return EZDC(IdZPA3); } + float EZPA4() const { return EZDC(IdZPA4); } + float EZPASum() const { return EZDC(IdZPASum); } + + float EZEM1() const { return EZDC(IdZEM1); } + float EZEM2() const { return EZDC(IdZEM2); } + + float EZNCC() const { return EZDC(IdZNCC); } + float EZNC1() const { return EZDC(IdZNC1); } + float EZNC2() const { return EZDC(IdZNC2); } + float EZNC3() const { return EZDC(IdZNC3); } + float EZNC4() const { return EZDC(IdZNC4); } + float EZNCSum() const { return EZDC(IdZNCSum); } + + float EZPCC() const { return EZDC(IdZPCC); } + float EZPC1() const { return EZDC(IdZPC1); } + float EZPC2() const { return EZDC(IdZPC2); } + float EZPC3() const { return EZDC(IdZPC3); } + float EZPC4() const { return EZDC(IdZPC4); } + float EZPCSum() const { return EZDC(IdZPCSum); } + + void decodeInfo(uint8_t ch, uint16_t code); + void decodeMapInfo(uint32_t ch, uint16_t code); + + void print() const; + ClassDefNV(RecEventFlat, 1); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCEnergy.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCEnergy.h new file mode 100644 index 0000000000000..09179e76c1bf1 --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCEnergy.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_ENERGY_H +#define ZDC_ENERGY_H + +#include "ZDCBase/Constants.h" +#include <array> +#include <cmath> +#include <Rtypes.h> + +/// \file ZDCEnergy.h +/// \brief Container class to store energy released in the ZDC +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct ZDCEnergy { + + uint32_t value = 0; // Signal id and energy released in calorimeter + + ZDCEnergy() = default; + ZDCEnergy(uint8_t ch, float energy) + { + set(ch, energy); + } + inline void set(uint8_t ch, float energy) + { + double escaled = (energy + EnergyOffset) / EnergyUnit; + value = 0; + if (escaled > 0) { + if (escaled > EnergyMask) { + value = EnergyMask; + } else { + value = std::nearbyint(escaled); + } + } + if (ch >= NChannels) { + ch = 0x1f; + } + value = (value & EnergyMask) | (ch << 27); + } + float energy() const + { + return float(value & EnergyMask) * EnergyUnit - EnergyOffset; + } + uint8_t ch() const + { + return (value & EnergyChMask) >> 27; + } + + void print() const; + + ClassDefNV(ZDCEnergy, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCTDCData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCTDCData.h new file mode 100644 index 0000000000000..4387116d55c1f --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCTDCData.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_TDC_DATA_H +#define ZDC_TDC_DATA_H + +#include "ZDCBase/Constants.h" +#include <array> +#include <Rtypes.h> + +/// \file ZDCTDCData.h +/// \brief Container class to store a TDC hit in a ZDC channel +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct ZDCTDCData { + + int8_t id = IdDummy; // channel ID + int16_t val = 0; // tdc value + int16_t amp = 0; // tdc amplitude + + ZDCTDCData() = default; + ZDCTDCData(int8_t ida, int16_t vala, int16_t ampa) + { + id = ida; + val = vala; + amp = ampa; + } + + inline float amplitude() const + { + return FTDCAmp * amp; + } + inline float value() const + { + return FTDCVal * val; + } + inline uint8_t ch() const + { + return id; + } + + void print() const; + + ClassDefNV(ZDCTDCData, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/src/BCData.cxx b/DataFormats/Detectors/ZDC/src/BCData.cxx index a45d0f2c3da02..b086bb64ebd7c 100644 --- a/DataFormats/Detectors/ZDC/src/BCData.cxx +++ b/DataFormats/Detectors/ZDC/src/BCData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,10 +15,13 @@ using namespace o2::zdc; -void BCData::print() const +void BCData::print(uint32_t triggerMask, int diff) const { - ir.print(); - printf("%d channels starting from %d\n", ref.getEntries(), ref.getFirstEntry()); + if (diff == 0) { + printf("Orbit %9u bc %4u nch %2d pos %d\n", ir.orbit, ir.bc, ref.getEntries(), ref.getFirstEntry()); + } else { + printf("%9u.%04u ", ir.orbit, ir.bc); + } printf("Read:"); for (int ic = 0; ic < NDigiChannels; ic++) { if (ic % NChPerModule == 0) { @@ -33,7 +37,11 @@ void BCData::print() const printf(" "); } } - printf("]\nHits:"); + printf("]\n"); + if (diff) { + printf("%9u.%04u ", ir.orbit, ir.bc); + } + printf("Hits:"); for (int ic = 0; ic < NDigiChannels; ic++) { if (ic % NChPerModule == 0) { if (ic == 0) { @@ -42,13 +50,41 @@ void BCData::print() const printf("] %d[", ic / NChPerModule); } } - if (triggers & (0x1 << ic)) { - printf("H"); + bool is_hit = triggers & (0x1 << ic); + bool is_trig = triggerMask & (0x1 << ic); + if (is_trig) { + if (is_hit) { + printf("T"); + } else { + printf("."); + } } else { - printf(" "); + if (is_hit) { + printf("H"); + } else { + printf(" "); + } } } printf("]\n"); + if (diff) { + printf("%9u.%04u ", ir.orbit, ir.bc); + } + printf("AUTO:"); + for (int i = 0; i < NModules; i++) { + std::bitset<10> bb(moduleTriggers[i]); + printf(" %d %s%s%s%s%s", i, bb[8] ? "3" : "-", bb[7] ? "2" : "-", bb[6] ? "1" : "-", bb[5] ? "0" : "-", bb[4] ? "M" : "-"); + } + printf("\n"); + if (diff) { + printf("%9u.%04u ", ir.orbit, ir.bc); + } + printf("ALIT:"); + for (int i = 0; i < NModules; i++) { + std::bitset<10> bb(moduleTriggers[i]); + printf(" %d %s%s%s%s ", i, bb[3] ? "3" : "-", bb[2] ? "2" : "-", bb[1] ? "1" : "-", bb[0] ? "0" : "-"); + } + printf("\n"); } gsl::span<const ChannelData> BCData::getBunchChannelData(const gsl::span<const ChannelData> tfdata) const diff --git a/DataFormats/Detectors/ZDC/src/BCRecData.cxx b/DataFormats/Detectors/ZDC/src/BCRecData.cxx new file mode 100644 index 0000000000000..7810644f022df --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/BCRecData.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsZDC/BCRecData.h" +#include "DataFormatsZDC/ChannelData.h" +#include <bitset> + +using namespace o2::zdc; + +void BCRecData::print() const +{ + printf("Orbit %9u bc %4u nch %2d pos %d ntdc %2d pos %d nmsg %2d pos %d\n", ir.orbit, ir.bc, + refe.getEntries(), refe.getFirstEntry(), + reft.getEntries(), reft.getFirstEntry(), + refi.getEntries(), refi.getFirstEntry()); +} diff --git a/DataFormats/Detectors/ZDC/src/CTF.cxx b/DataFormats/Detectors/ZDC/src/CTF.cxx new file mode 100644 index 0000000000000..907bb1cc6b6f1 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/CTF.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <stdexcept> +#include <cstring> +#include "DataFormatsZDC/CTF.h" + +using namespace o2::zdc; diff --git a/DataFormats/Detectors/ZDC/src/ChannelData.cxx b/DataFormats/Detectors/ZDC/src/ChannelData.cxx index a29f977762e02..81ce63b0708f9 100644 --- a/DataFormats/Detectors/ZDC/src/ChannelData.cxx +++ b/DataFormats/Detectors/ZDC/src/ChannelData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h b/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h index 1f63d217effcd..699234e92bf59 100644 --- a/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h +++ b/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,14 +14,39 @@ #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; +#pragma link C++ nestedclasses; + +#pragma link C++ class o2::zdc::Hit + ; +#pragma link C++ class std::vector < o2::zdc::Hit> + ; + +#pragma link C++ class o2::zdc::MCLabel + ; +#include "SimulationDataFormat/MCTruthContainer.h" +#pragma link C++ class o2::dataformats::MCTruthContainer < o2::zdc::MCLabel> + ; #pragma link C++ class o2::zdc::ChannelData + ; #pragma link C++ class o2::zdc::BCData + ; +#pragma link C++ class o2::zdc::BCRecData + ; +#pragma link C++ class o2::zdc::OrbitData + ; +#pragma link C++ class o2::zdc::RecEvent + ; +#pragma link C++ class o2::zdc::RecEventAux + ; +#pragma link C++ class o2::zdc::RecEventFlat + ; +#pragma link C++ class o2::zdc::ZDCEnergy + ; +#pragma link C++ class o2::zdc::ZDCTDCData + ; #pragma link C++ class std::vector < o2::zdc::ChannelData> + ; #pragma link C++ class std::vector < o2::zdc::BCData> + ; - +#pragma link C++ class std::vector < o2::zdc::OrbitData> + ; +#pragma link C++ class std::vector < o2::zdc::BCRecData> + ; +#pragma link C++ class std::vector < o2::zdc::ZDCEnergy> + ; +#pragma link C++ class std::vector < o2::zdc::ZDCTDCData> + ; #pragma link C++ class std::vector < o2::zdc::RecEvent> + ; +#pragma link C++ class std::vector < o2::zdc::RecEventAux> + ; #pragma link C++ class std::vector < o2::zdc::OrbitRawData> + ; #pragma link C++ class std::vector < o2::zdc::OrbitRecData> + ; +#pragma link C++ class std::vector < uint16_t > + ; + +#pragma link C++ struct o2::zdc::CTFHeader + ; +#pragma link C++ struct o2::zdc::CTF + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::zdc::CTFHeader, 12, uint32_t> + ; + #endif diff --git a/DataFormats/Detectors/ZDC/src/OrbitData.cxx b/DataFormats/Detectors/ZDC/src/OrbitData.cxx new file mode 100644 index 0000000000000..00571de999908 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/OrbitData.cxx @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsZDC/OrbitData.h" +#include "ZDCBase/Constants.h" + +using namespace o2::zdc; + +void OrbitData::print() const +{ + printf("Orbit %9u bc %4u\n", ir.orbit, ir.bc); + for (int i = 0; i < NChannels; i++) { + printf("%2d %s: %9.3f cnt: %4u\n", i, ChannelNames[i].data(), asFloat(i), scaler[i]); + } +} diff --git a/DataFormats/Detectors/ZDC/src/OrbitRawData.cxx b/DataFormats/Detectors/ZDC/src/OrbitRawData.cxx index 3429e5d6f2ade..7c75057059a88 100644 --- a/DataFormats/Detectors/ZDC/src/OrbitRawData.cxx +++ b/DataFormats/Detectors/ZDC/src/OrbitRawData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ZDC/src/OrbitRecData.cxx b/DataFormats/Detectors/ZDC/src/OrbitRecData.cxx index e9e1f7924ec99..9f7484df36148 100644 --- a/DataFormats/Detectors/ZDC/src/OrbitRecData.cxx +++ b/DataFormats/Detectors/ZDC/src/OrbitRecData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Detectors/ZDC/src/RawEventData.cxx b/DataFormats/Detectors/ZDC/src/RawEventData.cxx new file mode 100644 index 0000000000000..4bc1d921e7e19 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/RawEventData.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// DataFormats/Detectors/ZDC/src/RawEventData.cxx +#include "DataFormatsZDC/RawEventData.h" + +using namespace o2::zdc; + +//ClassImp(EventData); + +//______________________________________________________________________________ +void EventChData::reset() +{ + static constexpr int payloadSize = NWPerGBTW * sizeof(UInt_t); + memset((void*)&w[0][0], 0, payloadSize); +} + +//______________________________________________________________________________ +void EventData::print() const +{ + for (Int_t im = 0; im < o2::zdc::NModules; im++) { + for (Int_t ic = 0; ic < o2::zdc::NChPerModule; ic++) { + if (data[im][ic].f.fixed_0 == Id_w0 && data[im][ic].f.fixed_1 == Id_w1 && data[im][ic].f.fixed_2 == Id_w2) { + // Not empty event + auto f = data[im][ic].f; + // Word 0 + printf("%04x %08x %08x ", data[im][ic].w[0][2], data[im][ic].w[0][1], data[im][ic].w[0][0]); + printf("orbit %-9u bc %-4u hits %-4u offset %+6i Board %2u Ch %1u\n", f.orbit, f.bc, f.hits, f.offset, f.ch, f.board); + // Word 1 + printf("%04x %08x %08x ", data[im][ic].w[1][2], data[im][ic].w[1][1], data[im][ic].w[1][0]); + printf(" %s %s %s %s 0-5 ", f.Alice_0 ? "A0" : " ", f.Alice_1 ? "A1" : " ", f.Alice_2 ? "A2" : " ", f.Alice_3 ? "A3" : " "); + printf(" %5d %5d %5d %5d %5d %5d EC=%u\n", f.s00, f.s01, f.s02, f.s03, f.s04, f.s05, f.error); + // Word 2 + printf("%04x %08x %08x ", data[im][ic].w[2][2], data[im][ic].w[2][1], data[im][ic].w[2][0]); + printf("%s %s %s %s %s %s 6-b ", f.Hit ? "H" : " ", f.Auto_m ? "TM" : " ", f.Auto_0 ? "T0" : " ", f.Auto_1 ? "T1" : " ", f.Auto_2 ? "T2" : " ", f.Auto_3 ? "T3" : " "); + printf(" %5d %5d %5d %5d %5d %5d\n", f.s06, f.s07, f.s08, f.s09, f.s10, f.s11); + } else if (data[im][ic].f.fixed_0 == 0 && data[im][ic].f.fixed_1 == 0 && data[im][ic].f.fixed_2 == 0) { + // Empty channel + } else { + // Wrong data format. Insert warning. + } + } + } +} + +//______________________________________________________________________________ +void EventData::reset() +{ + static constexpr int payloadSize = NModules * NChPerModule * NWPerGBTW * sizeof(UInt_t); + memset((void*)&data[0][0], 0, payloadSize); +} diff --git a/DataFormats/Detectors/ZDC/src/RecEvent.cxx b/DataFormats/Detectors/ZDC/src/RecEvent.cxx index 513b117773694..888245444d064 100644 --- a/DataFormats/Detectors/ZDC/src/RecEvent.cxx +++ b/DataFormats/Detectors/ZDC/src/RecEvent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,5 +15,16 @@ using namespace o2::zdc; void RecEvent::print() const { - ir.print(); + for (auto bcdata : mRecBC) { + bcdata.ir.print(); + int fe, ne, ft, nt, fi, ni; + bcdata.getRef(fe, ne, ft, nt, fi, ni); + for (int ie = 0; ie < ne; ie++) { + mEnergy[fe + ie].print(); + } + for (int it = 0; it < nt; it++) { + mTDCData[ft + it].print(); + } + // TODO: event info + } } diff --git a/DataFormats/Detectors/ZDC/src/RecEventAux.cxx b/DataFormats/Detectors/ZDC/src/RecEventAux.cxx new file mode 100644 index 0000000000000..85cf2751852e2 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/RecEventAux.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsZDC/RecEventAux.h" + +using namespace o2::zdc; + +void RecEventAux::print() const +{ + ir.print(); +} diff --git a/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx b/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx new file mode 100644 index 0000000000000..fb38ea2f65f55 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx @@ -0,0 +1,210 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "DataFormatsZDC/RecEventFlat.h" + +using namespace o2::zdc; + +void RecEventFlat::init(std::vector<o2::zdc::BCRecData>* RecBC, std::vector<o2::zdc::ZDCEnergy>* Energy, std::vector<o2::zdc::ZDCTDCData>* TDCData, std::vector<uint16_t>* Info) +{ + mRecBC = RecBC; + mEnergy = Energy; + mTDCData = TDCData; + mInfo = Info; + mEntry = 0; + mNEntries = mRecBC->size(); +} + +int RecEventFlat::next() +{ + if (mEntry >= mNEntries) { + return 0; + } + + tdcPedEv.fill(false); + tdcPedOr.fill(false); + tdcPedQC.fill(false); + tdcPedMissing.fill(false); + adcPedEv.fill(false); + adcPedOr.fill(false); + adcPedQC.fill(false); + adcPedMissing.fill(false); + ezdc.clear(); + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + TDCVal[itdc].clear(); + TDCAmp[itdc].clear(); + } + + // Get References + mCurB = mRecBC->at(mEntry); + mCurB.getRef(mFirstE, mNE, mFirstT, mNT, mFirstI, mNI); + mStopE = mFirstE + mNE; + mStopT = mFirstT + mNT; + mStopI = mFirstI + mNI; + + ir = mCurB.ir; + channels = mCurB.channels; + triggers = mCurB.triggers; + + // Decode event info + int infoState = 0; + uint16_t code = 0; + uint32_t map = 0; + for (int i = mFirstI; i < mStopI; i++) { + uint16_t info = mInfo->at(i); + if (infoState == 0) { + if (info & 0x8000) { + LOGF(ERROR, "Inconsistent info stream at word %d: 0x%4u", i, info); + break; + } + code = info & 0x03ff; + uint8_t ch = (info >> 10) & 0x1f; + if (ch == 0x1f) { + infoState = 1; + } else if (ch < NChannels) { + decodeInfo(ch, code); + } else { + LOGF(ERROR, "Info about non existing channel: %u", ch); + } + } else if (infoState == 1) { + if (info & 0x8000) { + map = info & 0x7fff; + } else { + LOGF(ERROR, "Inconsistent info stream at word %d: 0x%4u", i, info); + break; + } + infoState = 2; + } else if (infoState == 2) { + if (info & 0x8000) { + uint32_t maph = info & 0x7fff; + map = (maph << 15) | map; + decodeMapInfo(map, code); + } else { + LOGF(ERROR, "Inconsistent info stream at word %d: 0x%4u", i, info); + break; + } + infoState = 0; + } + } + + // Decode energy + for (int i = mFirstE; i < mStopE; i++) { + auto myenergy = mEnergy->at(i); + auto ch = myenergy.ch(); + ezdc[ch] = myenergy.energy(); + // Assign implicit event info + if (adcPedOr[ch] == false && adcPedQC[ch] == false && adcPedMissing[ch] == false) { + adcPedEv[ch] = true; + } + } + // Decode TDCs + for (int i = mFirstT; i < mStopT; i++) { + auto mytdc = mTDCData->at(i); + auto ch = mytdc.ch(); + if (ch < NTDCChannels) { + TDCVal[ch].push_back(mytdc.val); + TDCAmp[ch].push_back(mytdc.amp); + // Assign implicit event info + if (tdcPedQC[ch] == false && tdcPedMissing[ch] == false) { + tdcPedOr[ch] = true; + } + } + } + + mEntry++; + return mEntry; +} + +void RecEventFlat::decodeMapInfo(uint32_t map, uint16_t code) +{ +#ifdef O2_ZDC_DEBUG + printf("decodeMapInfo%08x code=%u\n", map, code); +#endif + for (uint8_t ch = 0; ch < NChannels; ch++) { + if (map & (0x1 << ch)) { + decodeInfo(ch, code); + } + } +} + +void RecEventFlat::decodeInfo(uint8_t ch, uint16_t code) +{ + if (mVerbosity != DbgZero) { + printf("%9u.%04u Info: ch=%2d (%s) code=%-4u (%s)\n", ir.orbit, ir.bc, ch, ch < NChannels ? ChannelNames[ch].data() : "N.D.", + code, code < MsgEnd ? MsgText[code].data() : "undefined"); + } + if (code == MsgTDCPedQC) { + tdcPedQC[ch] = true; + } + if (code == MsgTDCPedMissing) { + tdcPedMissing[ch] = true; + } + if (code == MsgADCPedOr) { + adcPedOr[ch] = true; + } + if (code == MsgADCPedQC) { + adcPedQC[ch] = true; + } + if (code == MsgADCPedMissing) { + adcPedMissing[ch] = true; + } +} + +void RecEventFlat::print() const +{ + printf("%9u.%04u ", ir.orbit, ir.bc); + printf("nE %2d pos %d nT %2d pos %d nI %2d pos %d\n", mNE, mFirstE, mNT, mFirstT, mNI, mFirstI); + printf("%9u.%04u ", ir.orbit, ir.bc); + printf("Read:"); + for (int ic = 0; ic < NDigiChannels; ic++) { + if (ic % NChPerModule == 0) { + if (ic == 0) { + printf(" %d[", ic / NChPerModule); + } else { + printf("] %d[", ic / NChPerModule); + } + } + if (channels & (0x1 << ic)) { + printf("R"); + } else { + printf(" "); + } + } + printf("]\n"); + printf("%9u.%04u ", ir.orbit, ir.bc); + printf("Hits:"); + for (int ic = 0; ic < NDigiChannels; ic++) { + if (ic % NChPerModule == 0) { + if (ic == 0) { + printf(" %d[", ic / NChPerModule); + } else { + printf("] %d[", ic / NChPerModule); + } + } + bool is_hit = triggers & (0x1 << ic); + bool is_trig = mTriggerMask & (0x1 << ic); + if (is_trig) { + if (is_hit) { + printf("T"); + } else { + printf("."); + } + } else { + if (is_hit) { + printf("H"); + } else { + printf(" "); + } + } + } + printf("]\n"); +} diff --git a/DataFormats/Detectors/ZDC/src/ZDCEnergy.cxx b/DataFormats/Detectors/ZDC/src/ZDCEnergy.cxx new file mode 100644 index 0000000000000..1f3162cd0b212 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/ZDCEnergy.cxx @@ -0,0 +1,20 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsZDC/ZDCEnergy.h" + +using namespace o2::zdc; + +void ZDCEnergy::print() const +{ + auto id = this->ch(); + printf("%2d (%s): %9u = %9.2f\n", id, channelName(id), value & EnergyChMask, energy()); +} diff --git a/DataFormats/Detectors/ZDC/src/ZDCTDCData.cxx b/DataFormats/Detectors/ZDC/src/ZDCTDCData.cxx new file mode 100644 index 0000000000000..01b9a43e1aad3 --- /dev/null +++ b/DataFormats/Detectors/ZDC/src/ZDCTDCData.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsZDC/ZDCTDCData.h" + +using namespace o2::zdc; + +void o2::zdc::ZDCTDCData::print() const +{ + printf("%2d (%s) %d = %8.3f @ %d = %6.3f\n", id, channelName(id), amp, amplitude(), val, value()); +} diff --git a/DataFormats/Headers/CMakeLists.txt b/DataFormats/Headers/CMakeLists.txt index 22addd9e4830c..3d5534fb88f5d 100644 --- a/DataFormats/Headers/CMakeLists.txt +++ b/DataFormats/Headers/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Headers SOURCES src/DataHeader.cxx src/NameHeader.cxx diff --git a/DataFormats/Headers/include/Headers/DAQID.h b/DataFormats/Headers/include/Headers/DAQID.h index 96cfb10b98997..dbde4809ebe7e 100644 --- a/DataFormats/Headers/include/Headers/DAQID.h +++ b/DataFormats/Headers/include/Headers/DAQID.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,9 @@ namespace header { /// Source IDs used by DAQ +constexpr o2::header::DataOrigin gDataOriginUnloaded{"UNL"}; +constexpr o2::header::DataOrigin gDataOriginTST{"TST"}; + class DAQID { @@ -37,7 +41,7 @@ class DAQID static constexpr ID INVALID = 9; // 1st invalid slot starting from meaningful values static constexpr ID MCH = 10; static constexpr ID ZDC = 15; - static constexpr ID TRG = 17; + static constexpr ID TRG = 17; // == CTP static constexpr ID EMC = 18; static constexpr ID TST = 19; static constexpr ID ITS = 32; @@ -48,6 +52,7 @@ class DAQID static constexpr ID MID = 37; static constexpr ID DCS = 38; static constexpr ID FOC = 39; + static constexpr ID UNLOADED = 255; static constexpr ID MINDAQ = TPC; static constexpr ID MAXDAQ = FOC; @@ -60,7 +65,7 @@ class DAQID static constexpr o2::header::DataOrigin DAQtoO2(ID daq) { - return (daq < MAXDAQ + 1) ? MAP_DAQtoO2[daq] : MAP_DAQtoO2[INVALID]; + return (daq < MAXDAQ + 1) ? MAP_DAQtoO2[daq] : (daq == UNLOADED ? gDataOriginUnloaded : MAP_DAQtoO2[INVALID]); } static constexpr ID O2toDAQ(o2::header::DataOrigin o2orig) @@ -71,7 +76,7 @@ class DAQID private: ID mID = INVALID; - static constexpr o2::header::DataOrigin MAP_DAQtoO2[] = { + static constexpr o2::header::DataOrigin MAP_DAQtoO2[0xff + 1] = { "NIL", "NIL", "NIL", "TPC", "TRD", "TOF", "HMP", "PHS", "CPV", "NIL", @@ -79,13 +84,46 @@ class DAQID "NIL", "NIL", "NIL", "NIL", "ZDC", "NIL", - "TRG", "EMC", "TST", + "CTP", "EMC", "TST", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", - "ITS", "FDD", "FT0", "FV0", "MFT", "MID", "DCS", "FOC"}; + "ITS", "FDD", "FT0", "FV0", "MFT", "MID", "DCS", "FOC", // 39 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 49 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 59 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 69 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 79 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 89 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 99 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 109 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 119 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 129 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 139 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 149 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 159 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 169 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 179 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 189 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 199 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 209 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 219 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 229 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 239 + "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", "NIL", // 249 + "NIL", "NIL", "NIL", "NIL", "NIL", "UNL" // 255 + }; + + static constexpr bool isSameOrigin(o2::header::DataOrigin origin, ID id) + { + for (auto i = sizeof(o2::header::DataOrigin); i--;) { + if (MAP_DAQtoO2[id].str[i] != origin.str[i]) { + return false; + } + } + return true; + } static constexpr ID or2daq(o2::header::DataOrigin origin, ID id) { - return id > MAXDAQ ? INVALID : (origin == MAP_DAQtoO2[id] ? id : or2daq(origin, id + 1)); + return (id > MAXDAQ) ? (isSameOrigin(origin, UNLOADED) ? UNLOADED : INVALID) : (isSameOrigin(origin, id) ? id : or2daq(origin, id + 1)); } }; diff --git a/DataFormats/Headers/include/Headers/DataHeader.h b/DataFormats/Headers/include/Headers/DataHeader.h index 1780e0ebf1607..67e48041073b9 100644 --- a/DataFormats/Headers/include/Headers/DataHeader.h +++ b/DataFormats/Headers/include/Headers/DataHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,21 +31,18 @@ #ifndef ALICEO2_BASE_DATA_HEADER_ #define ALICEO2_BASE_DATA_HEADER_ +#include <cstddef> #include <cstdint> #include <memory> #include <cassert> #include <cstring> //needed for memcmp -#include <algorithm> // std::min -#include <stdexcept> #include <string> +#include <stdexcept> #include <climits> -// FIXME: for o2::byte. Use std::byte as soon as we move to C++17.. -#include "MemoryResources/Types.h" +#include <limits> #include <cerrno> -namespace o2 -{ -namespace header +namespace o2::header { //__________________________________________________________________________________________________ @@ -148,10 +146,6 @@ struct TraitsIntType<4> { using Type = uint32_t; }; -struct defaultPrinter { - void operator()(const char* str) const {} -}; - /// compile time evaluation of a string length, which is either N - 1 or /// shorter if one character in the array has been set to 0. template <int N> @@ -202,50 +196,6 @@ constexpr T String2(const char (&str)[N]) // clang-format on } -//__________________________________________________________________________________________________ -/// helper traits to efficiently compare descriptors -/// the default implementation with memcmp is basically never used -/// specializations handle the two relevant cases -template <int S> -struct DescriptorCompareTraits { - template <typename T, typename Length> - static bool compare(const T& lh, const T& rh, Length N) - { - return std::memcmp(lh.str, rh.str, N) == 0; - } - template <typename T, typename Length> - static bool lessThen(const T& lh, const T& rh, Length N) - { - return std::memcmp(lh.str, rh.str, N) < 0; - } -}; -template <> -struct DescriptorCompareTraits<1> { - template <typename T, typename Length> - static bool compare(const T& lh, const T& rh, Length) - { - return lh.itg[0] == rh.itg[0]; - } - template <typename T, typename Length> - static bool lessThen(const T& lh, const T& rh, Length) - { - return lh.itg[0] < rh.itg[0]; - } -}; -template <> -struct DescriptorCompareTraits<2> { - template <typename T, typename Length> - static bool compare(const T& lh, const T& rh, Length) - { - return (lh.itg[0] == rh.itg[0]) && (lh.itg[1] == rh.itg[1]); - } - template <typename T, typename Length> - static bool lessThen(const T& lh, const T& rh, Length) - { - return std::tie(lh.itg[0], lh.itg[1]) < std::tie(rh.itg[0], rh.itg[1]); - } -}; - //__________________________________________________________________________________________________ /// generic descriptor class faturing the union of a char and a uint element /// of the same size @@ -253,7 +203,7 @@ struct DescriptorCompareTraits<2> { /// solution is working also for multiples of 64 bit, but then the itg member needs /// to be an array for all. This has not been enabled yet, first the implications /// have to be studied. -template <std::size_t N, typename PrinterPolicy = internal::defaultPrinter> +template <std::size_t N> struct Descriptor { static_assert(internal::NumberOfActiveBits<N>::value == 1, "Descriptor size is required to be a power of 2"); @@ -290,7 +240,7 @@ struct Descriptor { { static_assert(L <= N + 1, "initializer string must not exceed descriptor size"); unsigned i = 0; - for (; in[i] && i < std::min(N, L); ++i) { + for (; in[i] && i < (N < L ? N : L); ++i) { str[i] = in[i]; } } @@ -325,8 +275,8 @@ struct Descriptor { } } - bool operator==(const Descriptor& other) const { return DescriptorCompareTraits<arraySize>::compare(*this, other, N); } - bool operator<(const Descriptor& other) const { return DescriptorCompareTraits<arraySize>::lessThen(*this, other, N); } + bool operator==(const Descriptor& other) const { return std::memcmp(this->str, other.str, N) == 0; } + bool operator<(const Descriptor& other) const { return std::memcmp(this->str, other.str, N) < 0; } bool operator!=(const Descriptor& other) const { return not this->operator==(other); } // explicitly forbid comparison with e.g. const char* strings @@ -351,13 +301,6 @@ struct Descriptor { std::string ret(str, len); return std::move(ret); } - // print function needs to be implemented for every derivation - void print() const - { - // eventually terminate string before printing - PrinterPolicy printer; - printer(str); - }; }; //__________________________________________________________________________________________________ @@ -374,6 +317,7 @@ constexpr o2::header::SerializationMethod gSerializationMethodAny{"*******"}; constexpr o2::header::SerializationMethod gSerializationMethodInvalid{"INVALID"}; constexpr o2::header::SerializationMethod gSerializationMethodNone{"NONE"}; constexpr o2::header::SerializationMethod gSerializationMethodROOT{"ROOT"}; +constexpr o2::header::SerializationMethod gSerializationMethodCCDB{"CCDB"}; constexpr o2::header::SerializationMethod gSerializationMethodFlatBuf{"FLATBUF"}; constexpr o2::header::SerializationMethod gSerializationMethodArrow{"ARROW"}; @@ -448,7 +392,7 @@ struct BaseHeader { /// @brief access header in buffer /// /// this is to guess if the buffer starting at b looks like a header - inline static const BaseHeader* get(const o2::byte* b, size_t /*len*/ = 0) + inline static const BaseHeader* get(const std::byte* b, size_t /*len*/ = 0) { return (b != nullptr && *(reinterpret_cast<const uint32_t*>(b)) == sMagicString) ? reinterpret_cast<const BaseHeader*>(b) @@ -458,27 +402,27 @@ struct BaseHeader { /// @brief access header in buffer /// /// this is to guess if the buffer starting at b looks like a header - inline static BaseHeader* get(o2::byte* b, size_t /*len*/ = 0) + inline static BaseHeader* get(std::byte* b, size_t /*len*/ = 0) { return (b != nullptr && *(reinterpret_cast<uint32_t*>(b)) == sMagicString) ? reinterpret_cast<BaseHeader*>(b) : nullptr; } constexpr uint32_t size() const noexcept { return headerSize; } - inline const o2::byte* data() const noexcept { return reinterpret_cast<const o2::byte*>(this); } + inline const std::byte* data() const noexcept { return reinterpret_cast<const std::byte*>(this); } /// get the next header if any (const version) inline const BaseHeader* next() const noexcept { // BaseHeader::get checks that next header starts with the BaseHeader information at the // offset given by the size of the current header. - return (flagsNextHeader) ? BaseHeader::get(reinterpret_cast<const o2::byte*>(this) + headerSize) : nullptr; + return (flagsNextHeader) ? BaseHeader::get(reinterpret_cast<const std::byte*>(this) + headerSize) : nullptr; } /// get the next header if any (non-const version) inline BaseHeader* next() noexcept { - return (flagsNextHeader) ? BaseHeader::get(reinterpret_cast<o2::byte*>(this) + headerSize) : nullptr; + return (flagsNextHeader) ? BaseHeader::get(reinterpret_cast<std::byte*>(this) + headerSize) : nullptr; } /// check if the header matches expected version @@ -497,7 +441,7 @@ struct BaseHeader { /// use like this: /// HeaderType* h = get<HeaderType*>(buffer) template <typename HeaderType, typename std::enable_if_t<std::is_pointer<HeaderType>::value, int> = 0> -auto get(const o2::byte* buffer, size_t /*len*/ = 0) +auto get(const std::byte* buffer, size_t /*len*/ = 0) { using HeaderConstPtrType = const typename std::remove_pointer<HeaderType>::type*; using HeaderValueType = typename std::remove_pointer<HeaderType>::type; @@ -538,7 +482,7 @@ auto get(const o2::byte* buffer, size_t /*len*/ = 0) template <typename HeaderType, typename std::enable_if_t<std::is_pointer<HeaderType>::value, int> = 0> auto get(const void* buffer, size_t len = 0) { - return get<HeaderType>(reinterpret_cast<const byte*>(buffer), len); + return get<HeaderType>(reinterpret_cast<const std::byte*>(buffer), len); } //__________________________________________________________________________________________________ @@ -593,20 +537,8 @@ T stoui(const std::string& str, size_t* pos = nullptr, int base = 10) } }; -//__________________________________________________________________________________________________ -/// this 128 bit type for a header field describing the payload data type -struct printDataDescription { - void operator()(const char* str) const; -}; - -using DataDescription = Descriptor<gSizeDataDescriptionString, printDataDescription>; - -//__________________________________________________________________________________________________ -// 32bit (4 characters) for data origin, ex. the detector or subsystem name -struct printDataOrigin { - void operator()(const char* str) const; -}; -using DataOrigin = Descriptor<gSizeDataOriginString, printDataOrigin>; +using DataOrigin = Descriptor<gSizeDataOriginString>; +using DataDescription = Descriptor<gSizeDataDescriptionString>; //__________________________________________________________________________________________________ /// @defgroup data_description_defines Defines for data description @@ -635,10 +567,10 @@ constexpr o2::header::DataOrigin gDataOriginTOF{"TOF"}; constexpr o2::header::DataOrigin gDataOriginTPC{"TPC"}; constexpr o2::header::DataOrigin gDataOriginTRD{"TRD"}; constexpr o2::header::DataOrigin gDataOriginZDC{"ZDC"}; -#ifdef ENABLE_UPGRADES + constexpr o2::header::DataOrigin gDataOriginIT3{"IT3"}; -constexpr o2::header::DataOrigin gDataOriginIT4{"IT4"}; -#endif +constexpr o2::header::DataOrigin gDataOriginTRK{"TRK"}; +constexpr o2::header::DataOrigin gDataOriginFT3{"FT3"}; //possible data types constexpr o2::header::DataDescription gDataDescriptionAny{"***************"}; @@ -787,7 +719,6 @@ struct DataHeader : public BaseHeader { bool operator==(const DataOrigin&) const; //comparison bool operator==(const DataDescription&) const; //comparison bool operator==(const SerializationMethod&) const; //comparison - void print() const; ///pretty print the contents static const DataHeader* Get(const BaseHeader* baseHeader) { @@ -816,7 +747,6 @@ struct DataIdentifier { } bool operator==(const DataIdentifier&) const; - void print() const; }; //__________________________________________________________________________________________________ @@ -837,8 +767,14 @@ static_assert(gSizeMagicString == sizeof(BaseHeader::magicStringInt), static_assert(sizeof(BaseHeader::sMagicString) == sizeof(BaseHeader::magicStringInt), "Inconsitent size of global magic identifier"); -} //namespace header +template <typename T> +struct is_descriptor : std::false_type { +}; + +template <std::size_t S> +struct is_descriptor<o2::header::Descriptor<S>> : std::true_type { +}; -} //namespace o2 +} //namespace o2::header #endif diff --git a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h new file mode 100644 index 0000000000000..b786d26c6003e --- /dev/null +++ b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_BASE_DATA_HEADER_HELPERS_ +#define O2_BASE_DATA_HEADER_HELPERS_ + +#include "Headers/DataHeader.h" +#include <fmt/format.h> + +template <typename T> +struct fmt::formatter<T, std::enable_if_t<o2::header::is_descriptor<T>::value, char>> { + // Presentation format: 'f' - fixed, 'e' - exponential. + char presentation = 's'; + + // Parses format specifications of the form ['f' | 'e']. + constexpr auto parse(format_parse_context& ctx) + { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 's')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw format_error("invalid pick format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + template <typename FormatContext> + auto format(const T& p, FormatContext& ctx) + { + return format_to(ctx.out(), "{}", p.template as<std::string>()); + } +}; + +template <> +struct fmt::formatter<o2::header::DataHeader> { + // Presentation format: 'f' - fixed, 'e' - exponential. + char presentation = 's'; + + // Parses format specifications of the form ['f' | 'e']. + constexpr auto parse(format_parse_context& ctx) + { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 's')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw format_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + template <typename FormatContext> + auto format(const o2::header::DataHeader& h, FormatContext& ctx) + { + auto res = fmt::format("Data header version {}, flags: {}\n", h.headerVersion, h.flags) + + fmt::format(" origin : {}\n", h.dataOrigin.str) + + fmt::format(" serialization: {}\n", h.payloadSerializationMethod.str) + + fmt::format(" description : {}\n", h.dataDescription.str) + + fmt::format(" sub spec. : {}\n", (long long unsigned int)h.subSpecification) + + fmt::format(" header size : {}\n", h.headerSize) + + fmt::format(" payloadSize : {}\n", (long long unsigned int)h.payloadSize) + + fmt::format(" firstTFOrbit : {}\n", h.firstTForbit) + + fmt::format(" tfCounter : {}\n", h.tfCounter) + + fmt::format(" runNumber : {}\n", h.runNumber); + return format_to(ctx.out(), "{}", res); + } +}; + +#endif // O2_BASE_DATA_HEADER_HELPERS_ diff --git a/DataFormats/Headers/include/Headers/HeartbeatFrame.h b/DataFormats/Headers/include/Headers/HeartbeatFrame.h index 4e3afa3fa42bc..a7b810e15d471 100644 --- a/DataFormats/Headers/include/Headers/HeartbeatFrame.h +++ b/DataFormats/Headers/include/Headers/HeartbeatFrame.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/include/Headers/NameHeader.h b/DataFormats/Headers/include/Headers/NameHeader.h index f6aa282a2fc3b..1a62923a75044 100644 --- a/DataFormats/Headers/include/Headers/NameHeader.h +++ b/DataFormats/Headers/include/Headers/NameHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/include/Headers/RAWDataHeader.h b/DataFormats/Headers/include/Headers/RAWDataHeader.h index 8f68a0356c9c3..8c9f5ba43f8cd 100644 --- a/DataFormats/Headers/include/Headers/RAWDataHeader.h +++ b/DataFormats/Headers/include/Headers/RAWDataHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/include/Headers/RDHAny.h b/DataFormats/Headers/include/Headers/RDHAny.h index b4a57d362abf4..6105fb425d78c 100644 --- a/DataFormats/Headers/include/Headers/RDHAny.h +++ b/DataFormats/Headers/include/Headers/RDHAny.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/include/Headers/Stack.h b/DataFormats/Headers/include/Headers/Stack.h index 27924f3b53036..184733e35c339 100644 --- a/DataFormats/Headers/include/Headers/Stack.h +++ b/DataFormats/Headers/include/Headers/Stack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,12 +40,12 @@ struct Stack { struct freeobj { freeobj(memory_resource* mr) : resource(mr) {} memory_resource* resource{nullptr}; - void operator()(o2::byte* ptr) { resource->deallocate(ptr, 0, 0); } + void operator()(std::byte* ptr) { resource->deallocate(ptr, 0, 0); } }; public: - using allocator_type = boost::container::pmr::polymorphic_allocator<o2::byte>; - using value_type = o2::byte; + using allocator_type = boost::container::pmr::polymorphic_allocator<std::byte>; + using value_type = std::byte; using BufferType = std::unique_ptr<value_type[], freeobj>; //this gives us proper default move semantics for free Stack() = default; @@ -57,8 +58,8 @@ struct Stack { size_t size() const { return bufferSize; } allocator_type get_allocator() const { return allocator; } const BaseHeader* first() const { return reinterpret_cast<const BaseHeader*>(this->data()); } - static const BaseHeader* firstHeader(o2::byte const* buf) { return BaseHeader::get(buf); } - static const BaseHeader* lastHeader(o2::byte const* buf) + static const BaseHeader* firstHeader(std::byte const* buf) { return BaseHeader::get(buf); } + static const BaseHeader* lastHeader(std::byte const* buf) { const BaseHeader* last{firstHeader(buf)}; while (last && last->flagsNextHeader) { @@ -66,7 +67,7 @@ struct Stack { } return last; } - static size_t headerStackSize(o2::byte const* buf) + static size_t headerStackSize(std::byte const* buf) { size_t result = 0; const BaseHeader* last{firstHeader(buf)}; @@ -88,7 +89,7 @@ struct Stack { /// all headers must derive from BaseHeader, in addition also other stacks can be passed to ctor. template <typename FirstArgType, typename... Headers, typename std::enable_if_t< - !std::is_convertible<FirstArgType, boost::container::pmr::polymorphic_allocator<o2::byte>>::value, int> = 0> + !std::is_convertible<FirstArgType, boost::container::pmr::polymorphic_allocator<std::byte>>::value, int> = 0> Stack(FirstArgType&& firstHeader, Headers&&... headers) : Stack(boost::container::pmr::new_delete_resource(), std::forward<FirstArgType>(firstHeader), std::forward<Headers>(headers)...) @@ -100,7 +101,7 @@ struct Stack { Stack(const allocator_type allocatorArg, Headers&&... headers) : allocator{allocatorArg}, bufferSize{calculateSize(std::forward<Headers>(headers)...)}, - buffer{static_cast<o2::byte*>(allocator.resource()->allocate(bufferSize, alignof(std::max_align_t))), freeobj{allocator.resource()}} + buffer{static_cast<std::byte*>(allocator.resource()->allocate(bufferSize, alignof(std::max_align_t))), freeobj{allocator.resource()}} { inject(buffer.get(), std::forward<Headers>(headers)...); } @@ -117,7 +118,7 @@ struct Stack { constexpr static size_t calculateSize(T&& h) noexcept { //if it's a pointer (to a stack) traverse it - if constexpr (std::is_convertible_v<T, o2::byte*>) { + if constexpr (std::is_convertible_v<T, std::byte*>) { const BaseHeader* next = BaseHeader::get(std::forward<T>(h)); if (!next) { return 0; @@ -143,7 +144,7 @@ struct Stack { //______________________________________________________________________________________________ template <typename T> - static o2::byte* inject(o2::byte* here, T&& h, bool more = false) noexcept + static std::byte* inject(std::byte* here, T&& h, bool more = false) noexcept { using headerType = typename std::remove_cv<typename std::remove_reference<T>::type>::type; if (here == nullptr) { @@ -168,7 +169,7 @@ struct Stack { ::new (static_cast<void*>(here)) headerType(std::forward<T>(h)); reinterpret_cast<BaseHeader*>(here)->flagsNextHeader = more; return here + h.size(); - } else if constexpr (std::is_same_v<headerType, o2::byte*>) { + } else if constexpr (std::is_same_v<headerType, std::byte*>) { BaseHeader* from{BaseHeader::get(h)}; BaseHeader* last{nullptr}; while (from) { @@ -188,7 +189,7 @@ struct Stack { //______________________________________________________________________________________________ template <typename T, typename... Args> - static o2::byte* inject(o2::byte* here, T&& h, Args&&... args) noexcept + static std::byte* inject(std::byte* here, T&& h, Args&&... args) noexcept { bool more = hasNonEmptyArg(args...); auto alsohere = inject(here, h, more); @@ -210,7 +211,7 @@ struct Stack { template <typename T> static bool hasNonEmptyArg(const T& h) noexcept { - if constexpr (std::is_convertible_v<T, o2::byte*>) { + if constexpr (std::is_convertible_v<T, std::byte*>) { return get<BaseHeader*>(h); } else { if (h.size() > 0) { diff --git a/DataFormats/Headers/include/Headers/SubframeMetadata.h b/DataFormats/Headers/include/Headers/SubframeMetadata.h index a5cc9c8a12779..255fa0ceb8db6 100644 --- a/DataFormats/Headers/include/Headers/SubframeMetadata.h +++ b/DataFormats/Headers/include/Headers/SubframeMetadata.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/include/Headers/TimeStamp.h b/DataFormats/Headers/include/Headers/TimeStamp.h index 0bdae0059fd41..720fcd83412d8 100644 --- a/DataFormats/Headers/include/Headers/TimeStamp.h +++ b/DataFormats/Headers/include/Headers/TimeStamp.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/src/DAQID.cxx b/DataFormats/Headers/src/DAQID.cxx index 32fb60a1531e9..95ce0c686bce6 100644 --- a/DataFormats/Headers/src/DAQID.cxx +++ b/DataFormats/Headers/src/DAQID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/src/DataHeader.cxx b/DataFormats/Headers/src/DataHeader.cxx index 0fe5c446cc5a2..96e04bf523173 100644 --- a/DataFormats/Headers/src/DataHeader.cxx +++ b/DataFormats/Headers/src/DataHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -51,21 +52,6 @@ void o2::header::BaseHeader::throwInconsistentStackError() const throw std::runtime_error("inconsistent header stack, no O2 header at expected offset " + std::to_string(this->headerSize) + "for header of type " + this->description.as<std::string>()); } -//__________________________________________________________________________________________________ -void o2::header::DataHeader::print() const -{ - printf("Data header version %u, flags: %u\n", headerVersion, flags); - printf(" origin : %s\n", dataOrigin.str); - printf(" serialization: %s\n", payloadSerializationMethod.str); - printf(" description : %s\n", dataDescription.str); - printf(" sub spec. : %llu\n", (long long unsigned int)subSpecification); - printf(" header size : %d\n", headerSize); - printf(" payloadSize : %llu\n", (long long unsigned int)payloadSize); - printf(" firstTFOrbit : %u\n", firstTForbit); - printf(" tfCounter : %u\n", tfCounter); - printf(" runNumber : %u\n", runNumber); -} - //__________________________________________________________________________________________________ bool o2::header::DataHeader::operator==(const DataOrigin& that) const { @@ -98,18 +84,6 @@ bool o2::header::DataHeader::operator==(const DataHeader& that) const subSpecification == that.subSpecification); } -//__________________________________________________________________________________________________ -void o2::header::printDataDescription::operator()(const char* str) const -{ - printf("Data description : %s\n", str); -} - -//__________________________________________________________________________________________________ -void o2::header::printDataOrigin::operator()(const char* str) const -{ - printf("Data origin : %s\n", str); -} - //__________________________________________________________________________________________________ o2::header::DataIdentifier::DataIdentifier() : dataDescription(), dataOrigin() @@ -129,20 +103,13 @@ bool o2::header::DataIdentifier::operator==(const DataIdentifier& other) const return true; } -//__________________________________________________________________________________________________ -void o2::header::DataIdentifier::print() const -{ - dataOrigin.print(); - dataDescription.print(); -} - //__________________________________________________________________________________________________ void o2::header::hexDump(const char* desc, const void* voidaddr, size_t len, size_t max) { size_t i; unsigned char buff[17]; // stores the ASCII data memset(&buff[0], '\0', 17); - const byte* addr = reinterpret_cast<const byte*>(voidaddr); + const std::byte* addr = reinterpret_cast<const std::byte*>(voidaddr); // Output description if given. if (desc != nullptr) { @@ -177,13 +144,13 @@ void o2::header::hexDump(const char* desc, const void* voidaddr, size_t len, siz } // Now the hex code for the specific character. - printf(" %02x", addr[i]); + printf(" %02x", (char)addr[i]); // And store a printable ASCII character for later. - if ((addr[i] < 0x20) || (addr[i] > 0x7e)) { + if (((char)addr[i] < 0x20) || ((char)addr[i] > 0x7e)) { buff[i % 16] = '.'; } else { - buff[i % 16] = addr[i]; + buff[i % 16] = (char)addr[i]; } buff[(i % 16) + 1] = '\0'; fflush(stdout); diff --git a/DataFormats/Headers/src/HeartbeatFrame.cxx b/DataFormats/Headers/src/HeartbeatFrame.cxx index 053d4997fdb48..4ea042b739750 100644 --- a/DataFormats/Headers/src/HeartbeatFrame.cxx +++ b/DataFormats/Headers/src/HeartbeatFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/src/NameHeader.cxx b/DataFormats/Headers/src/NameHeader.cxx index 2d72ae4a12b27..6d2767c284d5c 100644 --- a/DataFormats/Headers/src/NameHeader.cxx +++ b/DataFormats/Headers/src/NameHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/src/RDHAny.cxx b/DataFormats/Headers/src/RDHAny.cxx index 6c62b1fa927b7..a48ae508b357f 100644 --- a/DataFormats/Headers/src/RDHAny.cxx +++ b/DataFormats/Headers/src/RDHAny.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/src/TimeStamp.cxx b/DataFormats/Headers/src/TimeStamp.cxx index dcac4c285a7ad..d540735d1f028 100644 --- a/DataFormats/Headers/src/TimeStamp.cxx +++ b/DataFormats/Headers/src/TimeStamp.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/test/testDAQID.cxx b/DataFormats/Headers/test/testDAQID.cxx index 49c741011aa50..59c87b086f658 100644 --- a/DataFormats/Headers/test/testDAQID.cxx +++ b/DataFormats/Headers/test/testDAQID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ using namespace o2::header; BOOST_AUTO_TEST_CASE(DAQIDTEST) { + for (int i = 0; i < DAQID::MAXDAQ + 5; i++) { auto vo2 = DAQID::DAQtoO2(i); auto daq = DAQID::O2toDAQ(vo2); @@ -32,4 +34,7 @@ BOOST_AUTO_TEST_CASE(DAQIDTEST) BOOST_CHECK(i == daq || vo2 == DAQID::DAQtoO2(DAQID::INVALID)); } std::cout << "DAQ INVALID " << int(DAQID::INVALID) << " <-> " << DAQID::DAQtoO2(DAQID::INVALID).str << std::endl; + std::cout << "DAQ UNLOADED " << int(DAQID::UNLOADED) << " <-> " << DAQID::DAQtoO2(DAQID::UNLOADED).str << std::endl; + BOOST_CHECK(DAQID::DAQtoO2(DAQID::UNLOADED) == o2::header::gDataOriginUnloaded); + BOOST_CHECK(DAQID::O2toDAQ(o2::header::gDataOriginUnloaded) == DAQID::UNLOADED); } diff --git a/DataFormats/Headers/test/testDataHeader.cxx b/DataFormats/Headers/test/testDataHeader.cxx index 6c41a77ea7779..0703fc6c3ae71 100644 --- a/DataFormats/Headers/test/testDataHeader.cxx +++ b/DataFormats/Headers/test/testDataHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include <iostream> #include <iomanip> #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "Headers/NameHeader.h" #include "Headers/Stack.h" @@ -247,6 +249,10 @@ BOOST_AUTO_TEST_CASE(DataHeader_test) BOOST_CHECK(!(dh4 == dh)); dh4 = dh; BOOST_CHECK(dh4 == dh); + DataHeader dh5{gDataDescriptionAny, gDataOriginAny, DataHeader::SubSpecificationType{1}, 1}; + BOOST_REQUIRE_EQUAL(fmt::format("{}", gDataOriginAny), "***"); + BOOST_REQUIRE_EQUAL(fmt::format("{}", gDataDescriptionAny), "***************"); + BOOST_REQUIRE_EQUAL(fmt::format("{}", DataHeader::SubSpecificationType{1}), "1"); } BOOST_AUTO_TEST_CASE(headerStack_test) @@ -345,5 +351,24 @@ BOOST_AUTO_TEST_CASE(Descriptor_benchmark) std::cout << nrolls << " operation(s): " << duration.count() << " ns" << std::endl; // there is not really a check at the moment } + +BOOST_AUTO_TEST_CASE(Descriptor_formatting) +{ + using TestDescriptor = Descriptor<8>; + TestDescriptor a("TESTDESC"); + TestDescriptor b(a); + + auto refTime = system_clock::now(); + const int nrolls = 1000000; + for (auto count = 0; count < nrolls; ++count) { + if (a == b) { + ++a.itg[0]; + ++b.itg[0]; + } + } + auto duration = std::chrono::duration_cast<TimeScale>(std::chrono::system_clock::now() - refTime); + std::cout << nrolls << " operation(s): " << duration.count() << " ns" << std::endl; + // there is not really a check at the moment +} } // namespace header } // namespace o2 diff --git a/DataFormats/Headers/test/testTimeStamp.cxx b/DataFormats/Headers/test/testTimeStamp.cxx index ff941f4424494..d418e05ded68f 100644 --- a/DataFormats/Headers/test/testTimeStamp.cxx +++ b/DataFormats/Headers/test/testTimeStamp.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/test/test_HeartbeatFrame.cxx b/DataFormats/Headers/test/test_HeartbeatFrame.cxx index ef690ff5a195f..aa49f9bc8c0e0 100644 --- a/DataFormats/Headers/test/test_HeartbeatFrame.cxx +++ b/DataFormats/Headers/test/test_HeartbeatFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Headers/test/test_RAWDataHeader.cxx b/DataFormats/Headers/test/test_RAWDataHeader.cxx index 7323b0c1ae5e5..12319953b1a75 100644 --- a/DataFormats/Headers/test/test_RAWDataHeader.cxx +++ b/DataFormats/Headers/test/test_RAWDataHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h b/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h index 0776b94dda46b..59be2a86c3c2b 100644 --- a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h +++ b/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/MemoryResources/CMakeLists.txt b/DataFormats/MemoryResources/CMakeLists.txt index 8979f242cd4dd..6a31d35872054 100644 --- a/DataFormats/MemoryResources/CMakeLists.txt +++ b/DataFormats/MemoryResources/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MemoryResources SOURCES src/MemoryResources.cxx diff --git a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h index 5f4e3e3584232..766be341216b5 100644 --- a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h +++ b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,6 @@ #ifndef ALICEO2_MEMORY_RESOURCES_ #define ALICEO2_MEMORY_RESOURCES_ -#include <boost/container/flat_map.hpp> #include <boost/container/pmr/memory_resource.hpp> #include <boost/container/pmr/monotonic_buffer_resource.hpp> #include <boost/container/pmr/polymorphic_allocator.hpp> @@ -41,7 +41,6 @@ #include <FairMQTransportFactory.h> #include <fairmq/MemoryResources.h> #include <fairmq/MemoryResourceTools.h> -#include "Types.h" namespace o2 { @@ -271,13 +270,42 @@ class OwningMessageSpectatorAllocator } }; +// The NoConstructAllocator behaves like the normal pmr vector but does not call constructors / destructors +template <typename T> +class NoConstructAllocator : public boost::container::pmr::polymorphic_allocator<T> +{ + public: + using boost::container::pmr::polymorphic_allocator<T>::polymorphic_allocator; + using propagate_on_container_move_assignment = std::true_type; + + template <typename... Args> + NoConstructAllocator(Args&&... args) : boost::container::pmr::polymorphic_allocator<T>(std::forward<Args>(args)...) + { + } + + // skip default construction of empty elements + // this is important for two reasons: one: it allows us to adopt an existing buffer (e.g. incoming message) and + // quickly construct large vectors while skipping the element initialization. + template <class U> + void construct(U*) + { + } + + // dont try to call destructors, makes no sense since resource is managed externally AND allowed + // types cannot have side effects + template <typename U> + void destroy(U*) + { + } +}; + //__________________________________________________________________________________________________ //__________________________________________________________________________________________________ //__________________________________________________________________________________________________ //__________________________________________________________________________________________________ -using ByteSpectatorAllocator = SpectatorAllocator<o2::byte>; -using BytePmrAllocator = boost::container::pmr::polymorphic_allocator<o2::byte>; +using ByteSpectatorAllocator = SpectatorAllocator<std::byte>; +using BytePmrAllocator = boost::container::pmr::polymorphic_allocator<std::byte>; template <class T> using vector = std::vector<T, o2::pmr::polymorphic_allocator<T>>; diff --git a/DataFormats/MemoryResources/include/MemoryResources/Types.h b/DataFormats/MemoryResources/include/MemoryResources/Types.h deleted file mode 100644 index 14639f0b8aa2b..0000000000000 --- a/DataFormats/MemoryResources/include/MemoryResources/Types.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MEMORY_RESOURCES_TYPES_ -#define O2_MEMORY_RESOURCES_TYPES_ - -namespace o2 -{ -using byte = unsigned char; -} // namespace o2 - -#endif diff --git a/DataFormats/MemoryResources/include/MemoryResources/observer_ptr.h b/DataFormats/MemoryResources/include/MemoryResources/observer_ptr.h index 8d0a281204475..603d24798bb02 100644 --- a/DataFormats/MemoryResources/include/MemoryResources/observer_ptr.h +++ b/DataFormats/MemoryResources/include/MemoryResources/observer_ptr.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/MemoryResources/src/MemoryResources.cxx b/DataFormats/MemoryResources/src/MemoryResources.cxx index 1cef7ffa1bb5b..c8c4f915e6f3f 100644 --- a/DataFormats/MemoryResources/src/MemoryResources.cxx +++ b/DataFormats/MemoryResources/src/MemoryResources.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/MemoryResources/test/testMemoryResources.cxx b/DataFormats/MemoryResources/test/testMemoryResources.cxx index 1f60cabcf0722..ece99f3cdb035 100644 --- a/DataFormats/MemoryResources/test/testMemoryResources.cxx +++ b/DataFormats/MemoryResources/test/testMemoryResources.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -82,7 +83,7 @@ BOOST_AUTO_TEST_CASE(allocator_test) v.emplace_back(1); v.emplace_back(2); v.emplace_back(3); - BOOST_CHECK((byte*)&(*v.end()) - (byte*)&(*v.begin()) == 3 * sizeof(testData)); + BOOST_CHECK((std::byte*)&(*v.end()) - (std::byte*)&(*v.begin()) == 3 * sizeof(testData)); BOOST_CHECK(testData::nconstructions == 3); } diff --git a/DataFormats/MemoryResources/test/test_observer_ptr.cxx b/DataFormats/MemoryResources/test/test_observer_ptr.cxx index 9deea71bfde36..11218ea0f830f 100644 --- a/DataFormats/MemoryResources/test/test_observer_ptr.cxx +++ b/DataFormats/MemoryResources/test/test_observer_ptr.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Parameters/CMakeLists.txt b/DataFormats/Parameters/CMakeLists.txt index c6adf65737866..a23704fe18f00 100644 --- a/DataFormats/Parameters/CMakeLists.txt +++ b/DataFormats/Parameters/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DataFormatsParameters SOURCES src/GRPObject.cxx diff --git a/DataFormats/Parameters/include/DataFormatsParameters/GRPObject.h b/DataFormats/Parameters/include/DataFormatsParameters/GRPObject.h index 20848f594e779..49654aadaf6c3 100644 --- a/DataFormats/Parameters/include/DataFormatsParameters/GRPObject.h +++ b/DataFormats/Parameters/include/DataFormatsParameters/GRPObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,6 +53,13 @@ class GRPObject timePoint getTimeEnd() const { return mTimeEnd; } void setTimeStart(timePoint t) { mTimeStart = t; } void setTimeEnd(timePoint t) { mTimeEnd = t; } + + void setNHBFPerTF(uint32_t n) { mNHBFPerTF = n; } + uint32_t getNHBFPerTF() const { return mNHBFPerTF; } + + void setFirstOrbit(uint32_t o) { mFirstOrbit = o; } + uint32_t getFirstOrbit() const { return mFirstOrbit; } + /// getters/setters for beams crossing angle (deviation from 0) o2::units::AngleRad_t getCrossingAngle() const { return mCrossingAngle; } void setCrossingAngle(o2::units::AngleRad_t v) { mCrossingAngle = v; } @@ -70,8 +78,10 @@ class GRPObject /// getters/setters for magnets currents o2::units::Current_t getL3Current() const { return mL3Current; } o2::units::Current_t getDipoleCurrent() const { return mDipoleCurrent; } + bool getFieldUniformity() const { return mUniformField; } void setL3Current(o2::units::Current_t v) { mL3Current = v; } void setDipoleCurrent(o2::units::Current_t v) { mDipoleCurrent = v; } + void setFieldUniformity(bool v) { mUniformField = v; } /// getter/setter for data taking period name const std::string& getDataPeriod() const { return mDataPeriod; } void setDataPeriod(const std::string v) { mDataPeriod = v; } @@ -129,11 +139,14 @@ class GRPObject /// print itself void print() const; - static GRPObject* loadFrom(const std::string& grpFileName, const std::string& grpName = "GRP"); + static GRPObject* loadFrom(const std::string& grpFileName = "", const std::string& grpName = "GRP"); private: - timePoint mTimeStart = 0; ///< DAQ_time_start entry from DAQ logbook - timePoint mTimeEnd = 0; ///< DAQ_time_end entry from DAQ logbook + timePoint mTimeStart = 0; ///< DAQ_time_start entry from DAQ logbook + timePoint mTimeEnd = LONG_MAX; ///< DAQ_time_end entry from DAQ logbook + + uint32_t mFirstOrbit = 0; /// 1st orbit of the 1st TF, in the MC set at digitization // RS Not sure it will stay in GRP, may go to some CTP object + uint32_t mNHBFPerTF = 256; /// Number of HBFrames per TF DetID::mask_t mDetsReadout; ///< mask of detectors which are read out DetID::mask_t mDetsContinuousRO; ///< mask of detectors read out in continuos mode @@ -142,6 +155,7 @@ class GRPObject o2::units::AngleRad_t mCrossingAngle = 0.f; ///< crossing angle in radians (as deviation from pi) o2::units::Current_t mL3Current = 0.f; ///< signed current in L3 o2::units::Current_t mDipoleCurrent = 0.f; ///< signed current in Dipole + bool mUniformField = false; ///< uniformity of magnetic field float mBeamEnergyPerZ = 0.f; ///< beam energy per charge (i.e. sqrt(s)/2 for pp) int mBeamAZ[beamDirection::NBeamDirections] = {0, 0}; ///< A<<16+Z for each beam @@ -151,7 +165,7 @@ class GRPObject std::string mDataPeriod = ""; ///< name of the period std::string mLHCState = ""; ///< machine state - ClassDefNV(GRPObject, 1); + ClassDefNV(GRPObject, 5); }; //______________________________________________ diff --git a/DataFormats/Parameters/src/GRPObject.cxx b/DataFormats/Parameters/src/GRPObject.cxx index a226af4dd0139..53be816679b59 100644 --- a/DataFormats/Parameters/src/GRPObject.cxx +++ b/DataFormats/Parameters/src/GRPObject.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "DataFormatsParameters/GRPObject.h" #include <cmath> #include "CommonConstants/PhysicsConstants.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::parameters; using namespace o2::constants::physics; @@ -50,6 +52,7 @@ void GRPObject::print() const printf("Start: %s", std::ctime(&t)); t = mTimeEnd; // system_clock::to_time_t(mTimeEnd); printf("End : %s", std::ctime(&t)); + printf("1st orbit: %u, %u orbits per TF\n", mFirstOrbit, mNHBFPerTF); printf("Beam0: Z:A = %3d:%3d, Energy = %.3f\n", getBeamZ(BeamClockWise), getBeamA(BeamClockWise), getBeamEnergyPerNucleon(BeamClockWise)); printf("Beam1: Z:A = %3d:%3d, Energy = %.3f\n", getBeamZ(BeamAntiClockWise), getBeamA(BeamAntiClockWise), @@ -111,9 +114,10 @@ GRPObject::ROMode GRPObject::getDetROMode(o2::detectors::DetID id) const GRPObject* GRPObject::loadFrom(const std::string& grpFileName, const std::string& grpName) { // load object from file - TFile flGRP(grpFileName.data()); + auto fname = o2::base::NameConf::getGRPFileName(grpFileName); + TFile flGRP(fname.c_str()); if (flGRP.IsZombie()) { - LOG(ERROR) << "Failed to open " << grpFileName; + LOG(ERROR) << "Failed to open " << fname; throw std::runtime_error("Failed to open GRP file"); } auto grp = reinterpret_cast<o2::parameters::GRPObject*>( diff --git a/DataFormats/Parameters/src/ParametersDataLinkDef.h b/DataFormats/Parameters/src/ParametersDataLinkDef.h index 3b61be067228c..0cdcca0406856 100644 --- a/DataFormats/Parameters/src/ParametersDataLinkDef.h +++ b/DataFormats/Parameters/src/ParametersDataLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/QualityControl/CMakeLists.txt b/DataFormats/QualityControl/CMakeLists.txt new file mode 100644 index 0000000000000..c1473a634ebd9 --- /dev/null +++ b/DataFormats/QualityControl/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(DataFormatsQualityControl + SOURCES src/FlagReasons.cxx + src/TimeRangeFlag.cxx + src/TimeRangeFlagCollection.cxx + PUBLIC_LINK_LIBRARIES O2::Headers + O2::FrameworkLogger + O2::DetectorsCommonDataFormats) + +o2_target_root_dictionary(DataFormatsQualityControl + HEADERS include/DataFormatsQualityControl/FlagReasons.h + include/DataFormatsQualityControl/TimeRangeFlag.h + include/DataFormatsQualityControl/TimeRangeFlagCollection.h) + +o2_add_test(FlagReasons + SOURCES test/testFlagReasons.cxx + COMPONENT_NAME DataFormatsQualityControl + PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl) + +o2_add_test(TimeRangeFlag + SOURCES test/testTimeRangeFlag.cxx + COMPONENT_NAME DataFormatsQualityControl + PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl) + +o2_add_test(TimeRangeFlagCollection + SOURCES test/testTimeRangeFlagCollection.cxx + COMPONENT_NAME DataFormatsQualityControl + PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl) \ No newline at end of file diff --git a/DataFormats/QualityControl/README.md b/DataFormats/QualityControl/README.md new file mode 100644 index 0000000000000..721b7db25ca4a --- /dev/null +++ b/DataFormats/QualityControl/README.md @@ -0,0 +1,100 @@ +\page refDataFormatsQualityControl Data Formats Quality Control + +Data formats for tagging good quality data for analysis. + +# Flagging time ranges +## General idea +* Each detector has its own CCDB (QCDB) entry - TimeRangeFlagCollection +* The CCDB Entry validity will be run or fill, depending on the final data taking granularity +* Each entry can define sub ranges (TimeRangeFlags) of certain data characteristics (FlagReasons) inside the CCDB Entry validity +* Flags are defined in a common store, they are used to derive the Data Tags - the final filters for good quality data during analysis. +* Data Tag are stored as CCDB entries. They might require different detectors and may suppress different flags dependent on the analysis type. + +## Implementation + +[Flag Reason](include/DataFormatsQualityControl/FlagReasons.h) is defined with an identifier number, a name and a 'bad quality' determinant. +The latter decides if such a flag should mark the data quality as bad by default. +FlagReasons can be created only with FlagReasonFactory, so that the list of available reasons is common and centralised. +For example: +``` +id: 10 +name: Limited Acceptance +bad: true +``` + +With [TimeRangeFlags](include/DataFormatsQualityControl/TimeRangeFlag.h) we can define the time range of a chosen FlagReason, add an additional comment and specify the source of this flag. +For example: +``` +start: 1612707603626 +end: 1613999652000 +flag: Limited Acceptance +comment: Sector B in TPC inactive +source: o2::quality_control_modules::tpc::ClustersCheck +``` + +[TimeRangeFlagCollection](include/DataFormatsQualityControl/TimeRangeFlagCollection.h) contains all TimeRangeFlags for the validity range (run or fill). +TimeRangeFlags may overlap, e.g. if they use different FlagReasons and they are sorted by their start time. +If certain period does not include any TimeRangeFlags with *bad* FlagReasons, then the data quality can be considered as good. +The [TimeRangeFlagCollection test](test/testTimeRangeFlagCollection.cxx) shows the usage example. + +TimeRangeFlagCollections are supposed to be created automatically with QC Post-processing Tasks based on Quality Objects created by QC Checks. +However, they might be created manually by QA experts as well. +The procedure to do that has to be defined. + +## TODO +* Define the complete list of available Flag Reasons +* implement CCDB storage and access + - define CCDB storage place e.g. + * `<Detector>/QC/QualityFlags` + * `Analysis/QualityFlags/<Detector>` +* Data Tags Definitions and Data Tags + +### Notes on plans for Data Tags + +Data Tag definition has: +* name +* global suppression list for bad flag reasons (applies to all detectors) +* global requirement list for not bad flag reasons +* list of needed detectors, +* list of suppression list and requirement list specific to detectors + +Example configurations +```json +{ + "name": "CentralBarrelTrackingLimitedAcceptance", + "globalRequiredDetectors" : [ "TPC", "ITS" ], + "globalIgnoredFlags" : ["Limited acceptance", "asdf"], + "globalRequiredFlags" : [], + "detectorSpecificFlags" : [ + { + "name" : "TPC", + "ignoredFlags" : [ "Reason X" ] + } + ] +}, +{ + "name": "CentralBarrelTracking", + "globalRequiredDetectors" : [ "TPC", "ITS" ], + "globalIgnoredFlags" : [], + "globalRequiredFlags" : [], + "detectorSpecificFlags" : [] +}, +{ + "name": "CentralBarrelTrackingOnlyLimitedAcceptanceinTPC", + "globalRequiredDetectors" : [ "TPC", "ITS" ], + "globalIgnoredFlags" : [], + "detectorSpecificFlags" : [ + { + "name" : "TPC", + "requiredFlags" : [ "Limited acceptance" ] + } +} +] +``` + +## Wishlist / Ideas +* executable to add flags to the flag store +* executable to extrags the flag store +* summary of all masks for one TimeRangeFlagCollection +* functionality to extract flags for a specific detector (from CCDB) +* cut class to specify detectors and flags which to exclude \ No newline at end of file diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h new file mode 100644 index 0000000000000..2c743d46ef251 --- /dev/null +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_ANALYSIS_FLAGREASONS +#define ALICEO2_ANALYSIS_FLAGREASONS + +/// \file FlagReasons.h +/// \brief classes keeping reasons for flagging time ranges +/// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de +/// \author Piotr Konopka, piotr.jan.konopka@cern.ch + +// STL +#include <iosfwd> +#include <cstdint> + +// ROOT includes +#include <Rtypes.h> + +namespace o2 +{ +namespace quality_control +{ + +struct FlagReasonFactory; + +class FlagReason +{ + private: + uint16_t mId; + std::string mName; + bool mBad; // if true, data should become bad by default + + // By making the constructor private and FlagReasons available only in the FlagReasonFactory + // we forbid to declare any flags in the user code. If you need a new FlagReason, please add it FlagReasonFactory. + private: + FlagReason(uint16_t id, const char* name, bool bad) : mId(id), mName(name), mBad(bad) {} + + public: + FlagReason(); + FlagReason& operator=(const FlagReason&) = default; + FlagReason(const FlagReason&) = default; + bool operator==(const FlagReason& rhs) const; + bool operator!=(const FlagReason& rhs) const; + bool operator<(const FlagReason& rhs) const; + bool operator>(const FlagReason& rhs) const; + + uint16_t getID() { return mId; } + const std::string& getName() { return mName; } + bool getBad() { return mBad; } + + friend std::ostream& operator<<(std::ostream& os, FlagReason const& me); + friend FlagReasonFactory; + + ClassDefNV(FlagReason, 1); +}; + +struct FlagReasonFactory { + FlagReasonFactory() = delete; + + // TODO: migrate the flag list from RCT + // TODO: find a way to have a nicely formatted list of reasons. + + // !!! NEVER MODIFY OR DELETE EXISTING FLAGS AFTER RUN 3 STARTS !!! + static FlagReason Invalid() { return {static_cast<uint16_t>(-1), "Invalid", true}; } + + static FlagReason Unknown() { return {1, "Unknown", true}; } + static FlagReason ProcessingError() { return {2, "Processing error", true}; } + // it can be used when there are no required Quality Objects in QCDB in certain time range. + static FlagReason MissingQualityObject() { return {3, "Missing Quality Object", true}; } + // Quality Object is there, but it has Quality::Null + static FlagReason MissingQuality() { return {4, "Missing Quality", true}; } + + // TODO: to be seen if we should actively do anything when a detector was off. + static FlagReason DetectorOff() { return {10, "Detector off", true}; } + static FlagReason LimitedAcceptance() { return {11, "Limited acceptance", true}; } +}; + +} // namespace quality_control +} // namespace o2 +#endif diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h new file mode 100644 index 0000000000000..bb79799d9d44e --- /dev/null +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_ANALYSIS_TIMERANGEFLAGS +#define ALICEO2_ANALYSIS_TIMERANGEFLAGS + +/// \file TimeRangeFlag.h +/// \brief Class to define a time range of a flag type +/// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de +/// \author Piotr Konopka, piotr.jan.konopka@cern.ch + +// System includes +#include <iosfwd> +#include <string> + +// ROOT includes +#include <Rtypes.h> + +#include <MathUtils/detail/Bracket.h> + +#include "DataFormatsQualityControl/FlagReasons.h" + +namespace o2 +{ +namespace quality_control +{ + +/// \class TimeRangeFlag +/// A Class for associating a bit mask with a time range +class TimeRangeFlag +{ + public: + using time_type = uint64_t; + using flag_type = FlagReason; + using RangeInterval = o2::math_utils::detail::Bracket<time_type>; + + TimeRangeFlag() = default; + TimeRangeFlag(TimeRangeFlag const&) = default; + TimeRangeFlag(time_type start, time_type end, flag_type flag, std::string comment = "", std::string source = "Unknown"); + + time_type getStart() const { return mInterval.getMin(); } + time_type getEnd() const { return mInterval.getMax(); } + RangeInterval& getInterval() { return mInterval; } + flag_type getFlag() const { return mFlag; } + const std::string& getComment() const { return mComment; } + const std::string& getSource() const { return mSource; } + + void setStart(time_type start) { mInterval.setMin(start); } + void setEnd(time_type end) { mInterval.setMax(end); } + void setInterval(RangeInterval interval) { mInterval = interval; } + void setFlag(flag_type flag) { mFlag = flag; } + void setComment(const std::string& comment) { mComment = comment; } + void setSource(const std::string& source) { mSource = source; } + + /// equal operator + bool operator==(const TimeRangeFlag& rhs) const; + + /// comparison operators + bool operator<(const TimeRangeFlag& rhs) const; + bool operator>(const TimeRangeFlag& rhs) const; + + /// write data to ostream + void streamTo(std::ostream& output) const; + + /// overloading output stream operator + friend std::ostream& operator<<(std::ostream& output, const TimeRangeFlag& data); + + private: + RangeInterval mInterval = {}; ///< time interval of the masked range + flag_type mFlag = FlagReasonFactory::Invalid(); ///< flag reason + std::string mComment = ""; ///< optional comment, which may extend the reason + std::string mSource = "Unknown"; ///< optional (but encouraged) source of the flag (e.g. Qc Check name) + + ClassDefNV(TimeRangeFlag, 1); +}; + +} // namespace quality_control +} // namespace o2 +#endif diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h new file mode 100644 index 0000000000000..70627e523422a --- /dev/null +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_ANALYSIS_TIMERANGEMASK +#define ALICEO2_ANALYSIS_TIMERANGEMASK + +/// \file TimeRangeFlagCollection.h +/// \brief classes for defining time ranges with a certain mask to be able to cut on +/// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de + +// System includes +#include <iosfwd> + +// ROOT includes +#include "Rtypes.h" + +// O2 includes +#include "DataFormatsQualityControl/TimeRangeFlag.h" + +// STL +#include <set> + +namespace o2 +{ +namespace quality_control +{ + +/// \class TimeRangeFlagCollection +/// A Class for keeping several time ranges of type TimeRangeFlag +class TimeRangeFlagCollection +{ + public: + using collection_t = std::set<TimeRangeFlag>; + + explicit TimeRangeFlagCollection(std::string name, std::string detector = "TST"); + + void insert(TimeRangeFlag&&); + void insert(const TimeRangeFlag&); + + size_t size() const; + + // moves all non-repeating TimeRangeFlags from other to this + void merge(TimeRangeFlagCollection& other); + // add all non-repeating TimeRangeFlags from other to this. + void merge(const TimeRangeFlagCollection& other); + + collection_t::const_iterator begin() const; + collection_t::const_iterator end() const; + + const std::string& getName() const; + const std::string& getDetector() const; + + /// write data to ostream + void streamTo(std::ostream& output) const; + + /// overloading output stream operator + friend std::ostream& operator<<(std::ostream& output, const TimeRangeFlagCollection& data); + + private: + std::string mDetID; // three letter detector code + std::string mName = ""; // some description of the collection, e.g. "Raw data checks", "QA Expert masks" + // with std::set we can sort the flags in time and have merge() for granted. + collection_t mTimeRangeFlags; + + ClassDefNV(TimeRangeFlagCollection, 1); +}; + +} // namespace quality_control +} // namespace o2 +#endif diff --git a/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h b/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h new file mode 100644 index 0000000000000..8d77bccef4b7c --- /dev/null +++ b/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::quality_control::FlagReason + ; +#pragma link C++ class o2::quality_control::TimeRangeFlag + ; +#pragma link C++ class o2::quality_control::TimeRangeFlagCollection + ; + +#endif diff --git a/DataFormats/QualityControl/src/FlagReasons.cxx b/DataFormats/QualityControl/src/FlagReasons.cxx new file mode 100644 index 0000000000000..25c8e7c0e4f06 --- /dev/null +++ b/DataFormats/QualityControl/src/FlagReasons.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsQualityControl/FlagReasons.h" + +#include <iostream> +#include <tuple> + +namespace o2::quality_control +{ + +FlagReason::FlagReason() +{ + *this = FlagReasonFactory::Invalid(); +} + +std::ostream& operator<<(std::ostream& os, FlagReason const& my) +{ + os << "Flag Reason: id - " << my.mId << ", name - " << my.mName << ", bad - " << (my.mBad ? "true" : "false"); + return os; +} +bool FlagReason::operator==(const FlagReason& rhs) const +{ + return std::tie(mId, mName, mBad) == std::tie(rhs.mId, rhs.mName, rhs.mBad); +} +bool FlagReason::operator!=(const FlagReason& rhs) const +{ + return std::tie(mId, mName, mBad) != std::tie(rhs.mId, rhs.mName, rhs.mBad); +} +bool FlagReason::operator<(const FlagReason& rhs) const +{ + return std::tie(mId, mName, mBad) < std::tie(rhs.mId, rhs.mName, rhs.mBad); +} +bool FlagReason::operator>(const FlagReason& rhs) const +{ + return std::tie(mId, mName, mBad) > std::tie(rhs.mId, rhs.mName, rhs.mBad); +} + +} // namespace o2::quality_control \ No newline at end of file diff --git a/DataFormats/QualityControl/src/TimeRangeFlag.cxx b/DataFormats/QualityControl/src/TimeRangeFlag.cxx new file mode 100644 index 0000000000000..f96d5bc9b7b72 --- /dev/null +++ b/DataFormats/QualityControl/src/TimeRangeFlag.cxx @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsQualityControl/TimeRangeFlag.h" + +#include <iostream> +#include <tuple> + +namespace o2::quality_control +{ + +TimeRangeFlag::TimeRangeFlag(time_type start, time_type end, flag_type flag, std::string comment, std::string source) + : mInterval(start, end), mFlag(flag), mComment(comment), mSource(source) +{ + if (mInterval.isInvalid()) { + throw std::runtime_error("TimeRangeFlag start time '" + std::to_string(mInterval.getMin()) + "' is larger than end time '" + std::to_string(mInterval.getMax()) + "'"); + } +} + +bool TimeRangeFlag::operator==(const TimeRangeFlag& rhs) const +{ + return std::tie(mInterval, mFlag, mComment, mSource) == std::tie(rhs.mInterval, rhs.mFlag, rhs.mComment, rhs.mSource); +} + +bool TimeRangeFlag::operator<(const TimeRangeFlag& rhs) const +{ + // We don't use the comparison mechanism in Bracket, + // because std::set which is used in TRFCollection assumes that a < b, a > b <=> a == b. + // Using relation operators in Bracket would break insertion and merging. + return std::tie(static_cast<const time_type&>(mInterval.getMin()), static_cast<const time_type&>(mInterval.getMax()), mFlag, mComment, mSource) < std::tie(static_cast<const time_type&>(rhs.mInterval.getMin()), static_cast<const time_type&>(rhs.mInterval.getMax()), rhs.mFlag, rhs.mComment, rhs.mSource); +} + +bool TimeRangeFlag::operator>(const TimeRangeFlag& rhs) const +{ + // we don't use the comparison mechanism in Bracket, + // because std::set which is used in TRFCollection assumes that a < b, a > b <=> a == b + return std::tie(static_cast<const time_type&>(mInterval.getMin()), static_cast<const time_type&>(mInterval.getMax()), mFlag, mComment, mSource) > std::tie(static_cast<const time_type&>(rhs.mInterval.getMin()), static_cast<const time_type&>(rhs.mInterval.getMax()), rhs.mFlag, rhs.mComment, rhs.mSource); +} + +void TimeRangeFlag::streamTo(std::ostream& output) const +{ + output << "TimeRangeFlag:\n"; + output << "- Start: " << mInterval.getMin() << "\n"; + output << "- End: " << mInterval.getMax() << "\n"; + output << "- " << mFlag << "\n"; + output << "- Comment: " << mComment << "\n"; + output << "- Source: " << mSource; +} + +std::ostream& operator<<(std::ostream& output, const TimeRangeFlag& data) +{ + data.streamTo(output); + return output; +} + +} // namespace o2::quality_control diff --git a/DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx b/DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx new file mode 100644 index 0000000000000..05924649b07be --- /dev/null +++ b/DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// O2 include +#include "DataFormatsQualityControl/TimeRangeFlagCollection.h" + +#include <iostream> + +namespace o2::quality_control +{ + +TimeRangeFlagCollection::TimeRangeFlagCollection(std::string name, std::string detector) + : mName(name), mDetID(detector) {} + +void TimeRangeFlagCollection::insert(TimeRangeFlag&& trf) +{ + mTimeRangeFlags.insert(std::move(trf)); +} +void TimeRangeFlagCollection::insert(const TimeRangeFlag& trf) +{ + mTimeRangeFlags.insert(trf); +} + +size_t TimeRangeFlagCollection::size() const +{ + return mTimeRangeFlags.size(); +} + +void TimeRangeFlagCollection::merge(TimeRangeFlagCollection& other) +{ + if (mDetID != other.mDetID) { + // We assume that one TimeRangeFlagCollection should correspond to one detector at most. + // However, if this becomes annoying, we can reconsider it. + throw std::runtime_error("The detector ID of the target collection '" + mDetID + "' is different than the other '" + mDetID); + } + mTimeRangeFlags.merge(other.mTimeRangeFlags); +} + +void TimeRangeFlagCollection::merge(const TimeRangeFlagCollection& other) +{ + TimeRangeFlagCollection otherCopy{other}; + merge(otherCopy); +} + +TimeRangeFlagCollection::collection_t::const_iterator TimeRangeFlagCollection::begin() const +{ + return mTimeRangeFlags.begin(); +} +TimeRangeFlagCollection::collection_t::const_iterator TimeRangeFlagCollection::end() const +{ + return mTimeRangeFlags.end(); +} + +void TimeRangeFlagCollection::streamTo(std::ostream& output) const +{ + output << "TimeRangeFlagCollection '" << mName << "' for detector '" << mDetID << "':" + << "\n"; + for (const auto& trf : mTimeRangeFlags) { + output << trf << "\n"; + } +} + +std::ostream& operator<<(std::ostream& output, const TimeRangeFlagCollection& data) +{ + data.streamTo(output); + return output; +} + +const std::string& TimeRangeFlagCollection::getName() const +{ + return mName; +} +const std::string& TimeRangeFlagCollection::getDetector() const +{ + return mDetID; +} + +} // namespace o2::quality_control \ No newline at end of file diff --git a/DataFormats/QualityControl/test/testFlagReasons.cxx b/DataFormats/QualityControl/test/testFlagReasons.cxx new file mode 100644 index 0000000000000..874f2b448445c --- /dev/null +++ b/DataFormats/QualityControl/test/testFlagReasons.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control FlagReasons class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include <type_traits> +#include <iostream> + +// o2 includes +#include "DataFormatsQualityControl/FlagReasons.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(FlagReasons) +{ + static_assert(std::is_constructible<FlagReason, uint16_t, const char*, bool>::value == false, + "FlagReason should not be constructible outside of its static methods."); + + FlagReason rDefault; + BOOST_CHECK_EQUAL(rDefault, FlagReasonFactory::Invalid()); + + auto r1 = FlagReasonFactory::Unknown(); + BOOST_CHECK_EQUAL(r1.getID(), 1); + BOOST_CHECK_EQUAL(r1.getName(), "Unknown"); + BOOST_CHECK_EQUAL(r1.getBad(), true); + + std::cout << r1 << std::endl; + + auto r2 = r1; + BOOST_CHECK_EQUAL(r2.getID(), 1); + BOOST_CHECK_EQUAL(r1.getName(), r2.getName()); + BOOST_CHECK_EQUAL(r2.getName(), "Unknown"); + BOOST_CHECK_EQUAL(r2.getBad(), true); + + BOOST_CHECK_EQUAL(r1, r2); + BOOST_CHECK((r1 != r2) == false); + BOOST_CHECK(!(r1 < r2)); + BOOST_CHECK(!(r1 > r2)); + + auto r3 = FlagReasonFactory::LimitedAcceptance(); + BOOST_CHECK(r3 > r1); + BOOST_CHECK(!(r3 < r1)); +} \ No newline at end of file diff --git a/DataFormats/QualityControl/test/testTimeRangeFlag.cxx b/DataFormats/QualityControl/test/testTimeRangeFlag.cxx new file mode 100644 index 0000000000000..72156c3f5e811 --- /dev/null +++ b/DataFormats/QualityControl/test/testTimeRangeFlag.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control TimeRangeFlag class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +// boost includes +#include <boost/test/unit_test.hpp> + +// o2 includes +#include "DataFormatsQualityControl/TimeRangeFlag.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(test_TimeRangeFlag) +{ + TimeRangeFlag trf1{12, 34, FlagReasonFactory::ProcessingError(), "comment", "source"}; + + BOOST_CHECK_EQUAL(trf1.getStart(), 12); + BOOST_CHECK_EQUAL(trf1.getEnd(), 34); + BOOST_CHECK_EQUAL(trf1.getFlag(), FlagReasonFactory::ProcessingError()); + BOOST_CHECK_EQUAL(trf1.getComment(), "comment"); + BOOST_CHECK_EQUAL(trf1.getSource(), "source"); + + BOOST_CHECK_THROW((TimeRangeFlag{12, 0, FlagReasonFactory::ProcessingError()}), std::runtime_error); + + TimeRangeFlag trf2{10, 34, FlagReasonFactory::ProcessingError(), "comment", "source"}; + + BOOST_CHECK(trf1 > trf2); + BOOST_CHECK(!(trf1 < trf2)); +} \ No newline at end of file diff --git a/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx b/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx new file mode 100644 index 0000000000000..b849b8cf6f2c8 --- /dev/null +++ b/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control TimeRangeFlagCollection class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +// boost includes +#include <boost/test/unit_test.hpp> + +// o2 includes +#include "DataFormatsQualityControl/TimeRangeFlagCollection.h" +#include "DataFormatsQualityControl/TimeRangeFlag.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(test_TimeRangeFlagCollection) +{ + TimeRangeFlag trf1{12, 34, FlagReasonFactory::ProcessingError(), "comment", "source"}; + TimeRangeFlag trf2{10, 34, FlagReasonFactory::ProcessingError(), "comment", "source"}; + + TimeRangeFlagCollection trfc1{"Raw data checks", "TOF"}; + trfc1.insert(trf1); // by copy + trfc1.insert(trf2); + trfc1.insert({50, 77, FlagReasonFactory::Invalid()}); // by move + BOOST_CHECK_EQUAL(trfc1.size(), 3); + + TimeRangeFlagCollection trfc2{"Reco checks", "TOF"}; + trfc2.insert({50, 77, FlagReasonFactory::Invalid()}); // this is a duplicate to an entry in trfc1 + trfc2.insert({51, 77, FlagReasonFactory::Invalid()}); + trfc2.insert({1234, 3434, FlagReasonFactory::LimitedAcceptance()}); + trfc2.insert({50, 77, FlagReasonFactory::LimitedAcceptance()}); + BOOST_CHECK_EQUAL(trfc2.size(), 4); + + // Try merging. Duplicate entries should be left in the 'other' objects. + // Notice that we merge the two partial TRFCs into the third, which covers all cases + TimeRangeFlagCollection trfc3{"ALL", "TOF"}; + trfc3.merge(trfc1); + trfc3.merge(trfc2); + BOOST_CHECK_EQUAL(trfc1.size(), 0); + BOOST_CHECK_EQUAL(trfc2.size(), 1); + BOOST_CHECK_EQUAL(trfc3.size(), 6); + + // Try const merging. It should copy the elements and keep the 'other' intact. + TimeRangeFlagCollection trfc4{"ALL", "TOF"}; + const auto& constTrfc3 = trfc3; + trfc4.merge(constTrfc3); + BOOST_CHECK_EQUAL(trfc3.size(), 6); + BOOST_CHECK_EQUAL(trfc4.size(), 6); + + // Try merging different detectors - it should throw. + TimeRangeFlagCollection trfc5{"ALL", "TPC"}; + BOOST_CHECK_THROW(trfc5.merge(trfc3), std::runtime_error); + BOOST_CHECK_THROW(trfc5.merge(constTrfc3), std::runtime_error); + + // try printing + std::cout << trfc3 << std::endl; + + // iterating + for (const auto& trf : trfc3) { + (void)trf; + } +} \ No newline at end of file diff --git a/DataFormats/README.md b/DataFormats/README.md index 86c27947518d9..6bcf0702367d6 100644 --- a/DataFormats/README.md +++ b/DataFormats/README.md @@ -9,6 +9,7 @@ There is no module description yet. <!-- doxy This module contains the following submodules: +* \subpage refDataFormatsQualityControl * \subpage refDataFormatsDetectors * \subpage refDataFormatsHeaders * \subpage refDataFormatsLegacy diff --git a/DataFormats/Reconstruction/CMakeLists.txt b/DataFormats/Reconstruction/CMakeLists.txt index c24054a29dcde..30be346891e19 100644 --- a/DataFormats/Reconstruction/CMakeLists.txt +++ b/DataFormats/Reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ReconstructionDataFormats SOURCES src/TrackParametrization.cxx @@ -17,13 +18,20 @@ o2_add_library(ReconstructionDataFormats src/Vertex.cxx src/PrimaryVertex.cxx src/MatchInfoTOF.cxx + src/MatchInfoTOFReco.cxx src/TrackLTIntegral.cxx src/PID.cxx src/DCA.cxx src/V0.cxx + src/Cascade.cxx + src/GlobalTrackID.cxx src/VtxTrackIndex.cxx src/VtxTrackRef.cxx + src/TrackTPCTOF.cxx + src/TrackCosmics.cxx + src/TrackMCHMID.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon + O2::GPUUtils O2::FrameworkLogger O2::DetectorsCommonDataFormats O2::CommonDataFormat) @@ -34,15 +42,23 @@ o2_target_root_dictionary( include/ReconstructionDataFormats/TrackFwd.h include/ReconstructionDataFormats/BaseCluster.h include/ReconstructionDataFormats/TrackTPCITS.h + include/ReconstructionDataFormats/GlobalFwdTrack.h include/ReconstructionDataFormats/Vertex.h include/ReconstructionDataFormats/PrimaryVertex.h include/ReconstructionDataFormats/MatchInfoTOF.h + include/ReconstructionDataFormats/MatchInfoTOFReco.h include/ReconstructionDataFormats/TrackLTIntegral.h include/ReconstructionDataFormats/PID.h include/ReconstructionDataFormats/DCA.h include/ReconstructionDataFormats/V0.h + include/ReconstructionDataFormats/Cascade.h + include/ReconstructionDataFormats/GlobalTrackID.h include/ReconstructionDataFormats/VtxTrackIndex.h - include/ReconstructionDataFormats/VtxTrackRef.h) + include/ReconstructionDataFormats/VtxTrackRef.h + include/ReconstructionDataFormats/TrackTPCTOF.h + include/ReconstructionDataFormats/TrackCosmics.h + include/ReconstructionDataFormats/TrackMCHMID.h + ) o2_add_test(Vertex SOURCES test/testVertex.cxx diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/BaseCluster.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/BaseCluster.h index a202249016824..de422aa0bf474 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/BaseCluster.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/BaseCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,12 +13,14 @@ #define ALICEO2_BASE_BASECLUSTER_H #include <MathUtils/Cartesian.h> -#include <TObject.h> +#include "GPUCommonRtypes.h" +#ifndef GPUCA_GPUCODE +#include "DetectorsCommonDataFormats/DetMatrixCache.h" #include <bitset> #include <iomanip> #include <ios> #include <iosfwd> -#include "DetectorsCommonDataFormats/DetMatrixCache.h" +#endif namespace o2 { @@ -64,6 +67,7 @@ class BaseCluster T getSigmaYZ() const { return mSigmaYZ; } math_utils::Point3D<T> getXYZ() const { return mPos; } math_utils::Point3D<T>& getXYZ() { return mPos; } +#ifndef GPUCA_GPUCODE // position in local frame, no check for matrices cache validity math_utils::Point3D<T> getXYZLoc(const o2::detectors::DetMatrixCache& dm) const { return dm.getMatrixT2L(mSensorID)(mPos); } // position in global frame, no check for matrices cache validity @@ -72,6 +76,7 @@ class BaseCluster // much faster for barrel detectors than using full 3D matrix. // no check for matrices cache validity math_utils::Point3D<T> getXYZGloRot(const o2::detectors::DetMatrixCache& dm) const { return dm.getMatrixT2GRot(mSensorID)(mPos); } +#endif // get sensor id std::int16_t getSensorID() const { return mSensorID; } // get count field @@ -116,6 +121,7 @@ class BaseCluster ClassDefNV(BaseCluster, 2); }; +#ifndef GPUCA_GPUCODE template <class T> std::ostream& operator<<(std::ostream& os, const BaseCluster<T>& c) { @@ -126,5 +132,6 @@ std::ostream& operator<<(std::ostream& os, const BaseCluster<T>& c) << ") cnt:" << std::setw(4) << +c.getCount() << " bits:" << std::bitset<8>(c.getBits()); return os; } +#endif } // namespace o2 #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Cascade.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Cascade.h new file mode 100644 index 0000000000000..77047357c092f --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Cascade.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_CASCADE_H +#define ALICEO2_CASCADE_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/V0.h" +#include <array> +#include <Math/SVector.h> + +namespace o2 +{ +namespace dataformats +{ + +class Cascade : public V0 +{ + public: + Cascade() = default; + Cascade(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, const std::array<float, 6>& covxyz, + const o2::track::TrackParCov& v0, const o2::track::TrackParCov& bachelor, + int v0ID, GIndex bachelorID, o2::track::PID pid = o2::track::PID::XiMinus); + + GIndex getBachelorID() const { return mProngIDs[1]; } + void setBachelorID(GIndex gid) { mProngIDs[1] = gid; } + + int getV0ID() const { return int(mProngIDs[0].getRaw()); } + void setV0ID(int vid) { mProngIDs[0].setRaw(GIndex::Base_t(vid)); } + + const Track& getV0Track() const { return mProngs[0]; } + Track& getV0Track() { return mProngs[0]; } + + const Track& getBachelorTrack() const { return mProngs[1]; } + Track& getBachelorTrack() { return mProngs[1]; } + + void setV0Track(const Track& t) { mProngs[0] = t; } + void setBachelorTrack(const Track& t) { mProngs[1] = t; } + + protected: + GIndex getProngID(int i) const = delete; + + ClassDefNV(Cascade, 1); +}; + +} // namespace dataformats +} // namespace o2 +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h index 2b827d5bb740d..922470f8992f5 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,12 +12,11 @@ #ifndef ALICEO2_DCA_H #define ALICEO2_DCA_H +#include "GPUCommonDef.h" #include "GPUCommonRtypes.h" +#include "GPUCommonArray.h" -#ifndef __OPENCL__ -#include <array> -#endif -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE #include <iosfwd> #endif @@ -32,14 +32,14 @@ class DCA { public: - DCA() = default; + GPUdDefault() DCA() = default; - DCA(float y, float z, float syy = 0.f, float syz = 0.f, float szz = 0.f) + GPUd() DCA(float y, float z, float syy = 0.f, float syz = 0.f, float szz = 0.f) { set(y, z, syy, syz, szz); } - void set(float y, float z, float syy, float syz, float szz) + GPUd() void set(float y, float z, float syy, float syz, float szz) { mY = y; mZ = z; @@ -48,30 +48,33 @@ class DCA mCov[2] = szz; } - void set(float y, float z) + GPUd() void set(float y, float z) { mY = y; mZ = z; } - auto getY() const { return mY; } - auto getZ() const { return mZ; } - auto getSigmaY2() const { return mCov[0]; } - auto getSigmaYZ() const { return mCov[1]; } - auto getSigmaZ2() const { return mCov[2]; } - const auto& getCovariance() const { return mCov; } + GPUd() auto getY() const { return mY; } + GPUd() auto getZ() const { return mZ; } + GPUd() auto getR2() const { return mY * mY + mZ * mZ; } + GPUd() auto getSigmaY2() const { return mCov[0]; } + GPUd() auto getSigmaYZ() const { return mCov[1]; } + GPUd() auto getSigmaZ2() const { return mCov[2]; } + GPUd() const auto& getCovariance() const { return mCov; } void print() const; private: float mY = 0.f; float mZ = 0.f; - std::array<float, 3> mCov; ///< s2y, syz, s2z + gpu::gpustd::array<float, 3> mCov; ///< s2y, syz, s2z ClassDefNV(DCA, 1); }; +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const DCA& d); +#endif } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalFwdTrack.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalFwdTrack.h new file mode 100644 index 0000000000000..272db5f8f61f4 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalFwdTrack.h @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GlobalFwdTrack.h +/// \brief Global Forward Muon tracks + +#ifndef ALICEO2_TRACKGLOBALFWD_H +#define ALICEO2_TRACKGLOBALFWD_H + +#include "ReconstructionDataFormats/TrackFwd.h" +#include "CommonDataFormat/TimeStamp.h" +#include "Math/SMatrix.h" + +namespace o2 +{ +namespace dataformats +{ +using SMatrix5 = ROOT::Math::SVector<Double_t, 5>; +using SMatrix55Sym = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; +using timeEst = o2::dataformats::TimeStampWithError<float, float>; + +class GlobalFwdTrack : public o2::track::TrackParCovFwd +{ + public: + GlobalFwdTrack() = default; + GlobalFwdTrack(const GlobalFwdTrack& t) = default; + ~GlobalFwdTrack() = default; + + void setMatchingChi2(double chi2) { mMatchingChi2 = chi2; } + const auto& getMatchingChi2() const { return mMatchingChi2; } + + void setMIDMatchingChi2(double chi2) { mMIDMatchingChi2 = chi2; } + const auto& getMIDMatchingChi2() const { return mMIDMatchingChi2; } + + void countCandidate() { mNMFTCandidates++; } + const auto& getNMFTCandidates() const { return mNMFTCandidates; } + + void setCloseMatch() { mCloseMatch = true; } + const auto& isCloseMatch() const { return mCloseMatch; } + + const timeEst& getTimeMUS() const { return mTimeMUS; } + timeEst& getTimeMUS() { return mTimeMUS; } + void setTimeMUS(const timeEst& t) { mTimeMUS = t; } + void setTimeMUS(float t, float te) + { + mTimeMUS.setTimeStamp(t); + mTimeMUS.setTimeStampError(te); + } + + SMatrix5 computeResiduals2Cov(const o2::track::TrackParCovFwd& t) const + { + SMatrix5 Residuals2Cov; + + Residuals2Cov(0) = (getX() - t.getX()) / TMath::Sqrt(getCovariances()(0, 0) + t.getCovariances()(0, 0)); + Residuals2Cov(1) = (getY() - t.getY()) / TMath::Sqrt(getCovariances()(1, 1) + t.getCovariances()(1, 1)); + Residuals2Cov(2) = (getPhi() - t.getPhi()) / TMath::Sqrt(getCovariances()(2, 2) + t.getCovariances()(2, 2)); + Residuals2Cov(3) = (getTanl() - t.getTanl()) / TMath::Sqrt(getCovariances()(3, 3) + t.getCovariances()(3, 3)); + Residuals2Cov(4) = (getInvQPt() - t.getInvQPt()) / TMath::Sqrt(getCovariances()(4, 4) + t.getCovariances()(4, 4)); + return Residuals2Cov; + } + + void setMCHTrackID(int ID) { mMCHTrackID = ID; } + const auto& getMCHTrackID() const { return mMCHTrackID; } + void setMFTTrackID(int ID) { mMFTTrackID = ID; } + const auto& getMFTTrackID() const { return mMFTTrackID; } + + private: + double mMatchingChi2 = 1.0E308; ///< MCH-MFT Matching Chi2 + double mMIDMatchingChi2 = -1.0; ///< MCH-MID Matching Chi2 + int mMFTTrackID = -1; ///< Track ID of best MFT-match + int mMCHTrackID = -1; ///< MCH Track ID + int mNMFTCandidates = 0; ///< Number of MFT candidates within search cut + bool mCloseMatch = false; ///< Close match = correct MFT pair tested (MC-only) + float mTrackTime = 0.f; ///< Track time + float mTrackTimeRes = 0.f; ///< Track time resolution + timeEst mTimeMUS; ///< time estimate in ns + ClassDefNV(GlobalFwdTrack, 1); +}; + +} // namespace dataformats + +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::dataformats::GlobalFwdTrack> : std::true_type { +}; +} // namespace framework + +} // namespace o2 + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackAccessor.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackAccessor.h new file mode 100644 index 0000000000000..3deeb1c364fd4 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackAccessor.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalTrackAccessor.h +/// \brief Accessor for TrackParCov derived objects from multiple containers +/// \author ruben.shahoyan@cern.ch + +#ifndef O2_GLOBAL_TRACK_ACCESSOR +#define O2_GLOBAL_TRACK_ACCESSOR + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonDataFormat/AbstractRefAccessor.h" + +namespace o2 +{ +namespace dataformats +{ +using GlobalTrackAccessor = AbstractRefAccessor<o2::track::TrackParCov, GlobalTrackID::NSources>; +} +} // namespace o2 + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h new file mode 100644 index 0000000000000..7a41f74972b4a --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h @@ -0,0 +1,183 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalTrackID.h +/// \brief Global index for barrel track: provides provenance (detectors combination), index in respective array and some number of bits +/// \author ruben.shahoyan@cern.ch + +#ifndef O2_GLOBAL_TRACK_ID +#define O2_GLOBAL_TRACK_ID + +#include "GPUCommonBitSet.h" +#include "CommonDataFormat/AbstractRef.h" +#include "DetectorsCommonDataFormats/DetID.h" +#ifndef GPUCA_GPUCODE +#include <iosfwd> +#include <string> +#include <array> +#include <string_view> +#include <bitset> +#endif // GPUCA_GPUCODE_DEVICE + +namespace o2 +{ +namespace dataformats +{ + +class GlobalTrackID : public AbstractRef<25, 5, 2> +{ + public: + using DetID = o2::detectors::DetID; + + enum Source : uint8_t { // provenance of the + ITS, // standalone detectors + TPC, + TRD, + TOF, + PHS, // FIXME Not sure PHS ... FDD should be kept here, at the moment + CPV, // they are here for completeness + EMC, + HMP, + MFT, + MCH, + MID, + ZDC, + FT0, + FV0, + FDD, + ITSTPC, // 2-detector tracks + TPCTOF, + TPCTRD, + MFTMCH, + ITSTPCTRD, // 3-detector tracks + ITSTPCTOF, + TPCTRDTOF, + MFTMCHMID, + ITSTPCTRDTOF, // full barrel track + ITSAB, // ITS AfterBurner tracklets + // + NSources + }; + + using AbstractRef<25, 5, 2>::AbstractRef; + static_assert(NSources <= 32, "bitset<32> insufficient"); + typedef o2::gpu::gpustd::bitset<32> mask_t; + +#ifndef GPUCA_GPUCODE + static constexpr std::string_view NONE{"none"}; ///< keywork for no sources + static constexpr std::string_view ALL{"all"}; ///< keywork for all sources +#endif + static constexpr mask_t MASK_ALL = (1u << NSources) - 1; + static constexpr mask_t MASK_NONE = 0; + + // methods for detector level manipulations + GPUd() static constexpr DetID::mask_t getSourceDetectorsMask(int i); + GPUd() static bool includesDet(DetID id, GlobalTrackID::mask_t srcm); + GPUdi() auto getSourceDetectorsMask() const { return getSourceDetectorsMask(getSource()); } + GPUdi() bool includesDet(DetID id) const { return (getSourceDetectorsMask() & DetID::getMask(id)).any(); } + + // methods for source level manipulations +#ifndef GPUCA_GPUCODE + static auto getSourceName(int s) { return DetID::getNames(getSourceDetectorsMask(s), '-'); } + static mask_t getSourcesMask(const std::string_view srcList); + static std::string getSourcesNames(mask_t srcm); + auto getSourceName() const { return getSourceName(getSource()); } +#endif // GPUCA_GPUCODE + GPUd() static constexpr mask_t getSourceMask(int s); + GPUdi() mask_t getSourceMask() const { return getSourceMask(getSource()); } + GPUdi() static bool includesSource(int s, mask_t srcm) { return srcm[s]; } + GPUdi() operator int() const { return int(getIndex()); } + +#ifndef GPUCA_GPUCODE + std::string asString() const; + void print() const; +#endif // GPUCA_GPUCODE + + ClassDefNV(GlobalTrackID, 3); +}; + +#ifndef GPUCA_GPUCODE +std::ostream& operator<<(std::ostream& os, const o2::dataformats::GlobalTrackID& v); +#endif // GPUCA_GPUCODE + +namespace globaltrackid_internal +{ +// static constexpr array class members not possible on the GPU, thus we use this trick. +using DetID = o2::detectors::DetID; +GPUconstexpr() DetID::mask_t SourceDetectorsMasks[GlobalTrackID::NSources] = { + DetID::mask_t(DetID::getMask(DetID::ITS)), + DetID::mask_t(DetID::getMask(DetID::TPC)), + DetID::mask_t(DetID::getMask(DetID::TRD)), + DetID::mask_t(DetID::getMask(DetID::TOF)), + DetID::mask_t(DetID::getMask(DetID::PHS)), + DetID::mask_t(DetID::getMask(DetID::CPV)), + DetID::mask_t(DetID::getMask(DetID::EMC)), + DetID::mask_t(DetID::getMask(DetID::HMP)), + DetID::mask_t(DetID::getMask(DetID::MFT)), + DetID::mask_t(DetID::getMask(DetID::MCH)), + DetID::mask_t(DetID::getMask(DetID::MID)), + DetID::mask_t(DetID::getMask(DetID::ZDC)), + DetID::mask_t(DetID::getMask(DetID::FT0)), + DetID::mask_t(DetID::getMask(DetID::FV0)), + DetID::mask_t(DetID::getMask(DetID::FDD)), + // + DetID::mask_t(DetID::getMask(DetID::ITS) | DetID::getMask(DetID::TPC)), + DetID::mask_t(DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TOF)), + DetID::mask_t(DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TRD)), + DetID::mask_t(DetID::getMask(DetID::MFT) | DetID::getMask(DetID::MCH)), + DetID::mask_t(DetID::getMask(DetID::ITS) | DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TRD)), + DetID::mask_t(DetID::getMask(DetID::ITS) | DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TOF)), + DetID::mask_t(DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TRD) | DetID::getMask(DetID::TOF)), + DetID::mask_t(DetID::getMask(DetID::MFT) | DetID::getMask(DetID::MCH) | DetID::getMask(DetID::MID)), + DetID::mask_t(DetID::getMask(DetID::ITS) | DetID::getMask(DetID::TPC) | DetID::getMask(DetID::TRD) | DetID::getMask(DetID::TOF)), + DetID::mask_t(DetID::getMask(DetID::ITS))}; + +GPUconstexpr() GlobalTrackID::mask_t sMasks[GlobalTrackID::NSources] = ///< detector masks + {GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITS)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TPC)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TRD)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TOF)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::PHS)), + GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::CPV)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::EMC)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::HMP)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::MFT)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::MCH)), + GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::MID)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ZDC)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::FT0)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::FV0)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::FDD)), + GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITSTPC)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TPCTOF)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TPCTRD)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::MFTMCH)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITSTPCTRD)), + GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITSTPCTOF)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::TPCTRDTOF)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITSTPCTRDTOF)), GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::MFTMCHMID)), + GlobalTrackID::mask_t(math_utils::bit2Mask(GlobalTrackID::ITSAB))}; +} // namespace globaltrackid_internal + +GPUdi() constexpr GlobalTrackID::DetID::mask_t GlobalTrackID::getSourceDetectorsMask(int i) { return globaltrackid_internal::SourceDetectorsMasks[i]; } +GPUdi() constexpr GlobalTrackID::mask_t GlobalTrackID::getSourceMask(int s) { return globaltrackid_internal::sMasks[s]; } + +GPUdi() bool GlobalTrackID::includesDet(DetID id, GlobalTrackID::mask_t srcm) +{ + for (int i = 0; i < NSources; i++) { + if (includesSource(i, srcm) && (getSourceDetectorsMask(i) & id.getMask()).any()) { + return true; + } + } + return false; +} + +} // namespace dataformats +} // namespace o2 + +#ifndef GPUCA_GPUCODE +namespace std +{ +// defining std::hash for GlobalTrackIndex to be used with std containers +template <> +struct hash<o2::dataformats::GlobalTrackID> { + public: + size_t operator()(const o2::dataformats::GlobalTrackID& id) const + { + return id.getRawWOFlags(); + } +}; +} // namespace std +#endif // GPUCA_GPUCODE + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h index 415fca84e7a72..ddf02168f1ce9 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #define ALICEO2_MATCHINFOTOF_H #include "ReconstructionDataFormats/TrackLTIntegral.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "CommonDataFormat/EvIndex.h" namespace o2 @@ -23,33 +25,46 @@ namespace dataformats { class MatchInfoTOF { - using evIdx = o2::dataformats::EvIndex<int, int>; + using GTrackID = o2::dataformats::GlobalTrackID; public: - MatchInfoTOF(evIdx evIdxTOFCl, float chi2, o2::track::TrackLTIntegral trkIntLT, evIdx evIdxTrack = evIdx(0, 0)) : mEvIdxTOFCl(evIdxTOFCl), mChi2(chi2), mIntLT(trkIntLT), mEvIdxTrack(evIdxTrack){}; + MatchInfoTOF(int idLocal, int idxTOFCl, double time, float chi2, o2::track::TrackLTIntegral trkIntLT, GTrackID idxTrack, float dt = 0, float z = 0) : mIdLocal(idLocal), mIdxTOFCl(idxTOFCl), mSignal(time), mChi2(chi2), mIntLT(trkIntLT), mIdxTrack(idxTrack), mDeltaT(dt), mZatTOF(z){}; MatchInfoTOF() = default; - void setEvIdxTOFCl(evIdx index) { mEvIdxTOFCl = index; } - void setEvIdxTrack(evIdx index) { mEvIdxTrack = index; } - evIdx getEvIdxTOFCl() const { return mEvIdxTOFCl; } - evIdx getEvIdxTrack() const { return mEvIdxTrack; } - int getEventTOFClIndex() const { return mEvIdxTOFCl.getEvent(); } - int getTOFClIndex() const { return mEvIdxTOFCl.getIndex(); } - int getEventTrackIndex() const { return mEvIdxTrack.getEvent(); } - int getTrackIndex() const { return mEvIdxTrack.getIndex(); } + void setIdxTOFCl(int index) { mIdxTOFCl = index; } + void setIdxTrack(GTrackID index) { mIdxTrack = index; } + int getIdxTOFCl() const { return mIdxTOFCl; } + GTrackID getTrackRef() const { return mIdxTrack; } + int getEventTOFClIndex() const { return mIdxTOFCl; } + int getTOFClIndex() const { return mIdxTOFCl; } + int getTrackIndex() const { return mIdxTrack.getIndex(); } void setChi2(int chi2) { mChi2 = chi2; } float getChi2() const { return mChi2; } o2::track::TrackLTIntegral& getLTIntegralOut() { return mIntLT; } const o2::track::TrackLTIntegral& getLTIntegralOut() const { return mIntLT; } + void print() const; + + void setDeltaT(float val) { mDeltaT = val; } + float getDeltaT() const { return mDeltaT; } + void setZatTOF(float val) { mZatTOF = val; } + float getZatTOF() const { return mZatTOF; } + void setSignal(double time) { mSignal = time; } + double getSignal() const { return mSignal; } + + int getIdLocal() const { return mIdLocal; } private: + int mIdLocal; // track id in sector of the pair track-TOFcluster float mChi2; // chi2 of the pair track-TOFcluster o2::track::TrackLTIntegral mIntLT; ///< L,TOF integral calculated during the propagation - evIdx mEvIdxTOFCl; ///< EvIdx for TOF cluster (first: ev index; second: cluster index) - evIdx mEvIdxTrack; ///< EvIdx for track (first: ev index; second: cluster index) + int mIdxTOFCl; ///< Idx for TOF cluster + GTrackID mIdxTrack; ///< Idx for track + float mZatTOF = 0.0; ///< Z position at TOF + float mDeltaT = 0.0; ///< tTOF - TPC (microsec) + double mSignal = 0.0; ///< TOF time in ps - ClassDefNV(MatchInfoTOF, 1); + ClassDefNV(MatchInfoTOF, 4); }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h new file mode 100644 index 0000000000000..13cce4c5d23e2 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MatchInfoTOFReco.h +/// \brief Class to temporary store the output of the matching to TOF in reconstruction + +#ifndef ALICEO2_MATCHINFOTOFRECO_H +#define ALICEO2_MATCHINFOTOFRECO_H + +#include "ReconstructionDataFormats/MatchInfoTOF.h" + +namespace o2 +{ +namespace dataformats +{ +class MatchInfoTOFReco : public MatchInfoTOF +{ + using GTrackID = o2::dataformats::GlobalTrackID; + + public: + enum TrackType : int8_t { UNCONS = 0, + CONSTR, + SIZE, + TPC = 0, + ITSTPC, + TPCTRD, + ITSTPCTRD, + SIZEALL }; + + MatchInfoTOFReco(int idLocal, int idxTOFCl, double time, float chi2, o2::track::TrackLTIntegral trkIntLT, GTrackID idxTrack, TrackType trkType, float dt = 0, float z = 0) : MatchInfoTOF(idLocal, idxTOFCl, time, chi2, trkIntLT, idxTrack, dt, z), mTrackType(trkType){}; + + MatchInfoTOFReco() = default; + + void setTrackType(TrackType value) { mTrackType = value; } + TrackType getTrackType() const { return mTrackType; } + + private: + TrackType mTrackType; ///< track type (TPC, ITSTPC, TPCTRD, ITSTPCTRD) + ClassDefNV(MatchInfoTOFReco, 2); +}; +} // namespace dataformats +} // namespace o2 +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchingType.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchingType.h new file mode 100644 index 0000000000000..338cd19effa5e --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchingType.h @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file MatchingType.h +/// \brief Defintions for the inter-detector matching type +/// \author ruben.shahoyan@cern.ch + +#ifndef O2_MATCHING_TYPE +#define O2_MATCHING_TYPE + +namespace o2 +{ +namespace globaltracking +{ +enum class MatchingType { + Standard, // standard matching, i.e. no extended workflow was applied + Full, // device is in the full matching mode + Strict, // device is in the strict matching mode + NModes +}; + +static constexpr uint32_t getSubSpec(MatchingType t) +{ + return t == MatchingType::Strict ? 1 : 0; // Only strict matching inputs and outputs need special SubSpec + if (t == MatchingType::Standard) { + return 0; + } +} + +} // namespace globaltracking +} // namespace o2 + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h index 25f010b20d2e4..e3002a717f051 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #ifndef ALICEO2_track_PID_H_ #define ALICEO2_track_PID_H_ +#include "GPUCommonDef.h" #include "GPUCommonRtypes.h" #include "CommonConstants/PhysicsConstants.h" @@ -24,11 +26,58 @@ namespace track { namespace o2cp = o2::constants::physics; +namespace pid_constants // GPUs currently cannot have static constexpr array members +{ +typedef uint8_t ID; +static constexpr ID NIDsTot = 16; +GPUconstexpr() const char* sNames[NIDsTot + 1] = ///< defined particle names + {"Electron", "Muon", "Pion", "Kaon", "Proton", "Deuteron", "Triton", "He3", "Alpha", + "Pion0", "Photon", "K0", "Lambda", "HyperTriton", "XiMinus", "OmegaMinus", nullptr}; + +GPUconstexpr() const float sMasses[NIDsTot] = ///< defined particle masses + {o2cp::MassElectron, o2cp::MassMuon, o2cp::MassPionCharged, o2cp::MassKaonCharged, + o2cp::MassProton, o2cp::MassDeuteron, o2cp::MassTriton, o2cp::MassHelium3, + o2cp::MassAlpha, o2cp::MassPionNeutral, o2cp::MassPhoton, + o2cp::MassKaonNeutral, o2cp::MassLambda, o2cp::MassHyperTriton, o2cp::MassXiMinus, o2cp::MassOmegaMinus}; + +GPUconstexpr() const float sMasses2[NIDsTot] = ///< defined particle masses^2 + {o2cp::MassElectron * o2cp::MassElectron, + o2cp::MassMuon* o2cp::MassMuon, + o2cp::MassPionCharged* o2cp::MassPionCharged, + o2cp::MassKaonCharged* o2cp::MassKaonCharged, + o2cp::MassProton* o2cp::MassProton, + o2cp::MassDeuteron* o2cp::MassDeuteron, + o2cp::MassTriton* o2cp::MassTriton, + o2cp::MassHelium3* o2cp::MassHelium3, + o2cp::MassAlpha* o2cp::MassAlpha, + o2cp::MassPionNeutral* o2cp::MassPionNeutral, + o2cp::MassPhoton* o2cp::MassPhoton, + o2cp::MassKaonNeutral* o2cp::MassKaonNeutral, + o2cp::MassLambda* o2cp::MassLambda, + o2cp::MassHyperTriton* o2cp::MassHyperTriton, + o2cp::MassXiMinus* o2cp::MassXiMinus, + o2cp::MassOmegaMinus* o2cp::MassOmegaMinus}; + +GPUconstexpr() const float sMasses2Z[NIDsTot] = ///< defined particle masses / Z + {o2cp::MassElectron, o2cp::MassMuon, + o2cp::MassPionCharged, o2cp::MassKaonCharged, + o2cp::MassProton, o2cp::MassDeuteron, + o2cp::MassTriton, o2cp::MassHelium3 / 2., + o2cp::MassAlpha / 2., + 0, 0, 0, 0, o2cp::MassHyperTriton, + o2cp::MassXiMinus, o2cp::MassOmegaMinus}; + +GPUconstexpr() const int sCharges[NIDsTot] = ///< defined particle charges + {1, 1, 1, 1, 1, 1, 1, 2, 2, + 0, 0, 0, 0, 1, + 1, 1}; +} // namespace pid_constants + class PID { public: // particle identifiers, continuos starting from 0 - typedef uint8_t ID; + typedef pid_constants::ID ID; static constexpr ID Electron = 0; static constexpr ID Muon = 1; @@ -50,82 +99,54 @@ class PID static constexpr ID K0 = 11; static constexpr ID Lambda = 12; static constexpr ID HyperTriton = 13; + static constexpr ID XiMinus = 14; + static constexpr ID OmegaMinus = 15; static constexpr ID FirstExt = PI0; - static constexpr ID LastExt = HyperTriton; - static constexpr ID NIDsTot = LastExt + 1; ///< total number of defined IDs - - PID() = default; - PID(ID id) : mID(id) {} - PID(const char* name); - PID(const PID& src) = default; - PID& operator=(const PID& src) = default; - - ID getID() const { return mID; } - operator ID() const { return getID(); } - - float getMass() const { return getMass(mID); } - float getMass2Z() const { return getMass2Z(mID); } - int getCharge() const { return getCharge(mID); } - const char* getName() const { return getName(mID); } - - static constexpr const char* getName(ID id) { return sNames[id]; } - static constexpr float getMass(ID id) { return sMasses[id]; } - static constexpr float getMass2(ID id) { return sMasses2[id]; } - static constexpr float getMass2Z(ID id) { return sMasses2Z[id]; } - static constexpr int getCharge(ID id) { return sCharges[id]; } + static constexpr ID LastExt = OmegaMinus; + static constexpr ID NIDsTot = pid_constants::NIDsTot; ///< total number of defined IDs + static_assert(NIDsTot == LastExt + 1, "Incorrect NIDsTot, please update!"); + + GPUdDefault() PID() = default; + GPUd() PID(ID id) : mID(id) {} + GPUd() PID(const char* name); + GPUdDefault() PID(const PID& src) = default; + GPUdDefault() PID& operator=(const PID& src) = default; + + GPUd() ID getID() const { return mID; } + GPUd() operator ID() const { return getID(); } + + GPUd() float getMass() const { return getMass(mID); } + GPUd() float getMass2() const { return getMass2(mID); } + GPUd() float getMass2Z() const { return getMass2Z(mID); } + GPUd() int getCharge() const { return getCharge(mID); } + + GPUd() static float getMass(ID id) { return pid_constants::sMasses[id]; } + GPUd() static float getMass2(ID id) { return pid_constants::sMasses2[id]; } + GPUd() static float getMass2Z(ID id) { return pid_constants::sMasses2Z[id]; } + GPUd() static int getCharge(ID id) { return pid_constants::sCharges[id]; } +#ifndef GPUCA_GPUCODE_DEVICE + GPUd() const char* getName() const + { + return getName(mID); + } + GPUd() static const char* getName(ID id) { return pid_constants::sNames[id]; } +#endif private: ID mID = Pion; // are 2 strings equal ? (trick from Giulio) - inline static constexpr bool sameStr(char const* x, char const* y) + GPUdi() static constexpr bool sameStr(char const* x, char const* y) { return !*x && !*y ? true : /* default */ (*x == *y && sameStr(x + 1, y + 1)); } - inline static constexpr ID nameToID(char const* name, ID id) +#ifndef GPUCA_GPUCODE_DEVICE + GPUdi() static constexpr ID nameToID(char const* name, ID id) { - return id > LastExt ? id : sameStr(name, sNames[id]) ? id : nameToID(name, id + 1); + return id > LastExt ? id : sameStr(name, pid_constants::sNames[id]) ? id : nameToID(name, id + 1); } - - static constexpr const char* sNames[NIDsTot + 1] = ///< defined particle names - {"Electron", "Muon", "Pion", "Kaon", "Proton", "Deuteron", "Triton", "He3", "Alpha", - "Pion0", "Photon", "K0", "Lambda", "HyperTriton", - nullptr}; - - static constexpr const float sMasses[NIDsTot] = ///< defined particle masses - {o2cp::MassElectron, o2cp::MassMuon, o2cp::MassPionCharged, o2cp::MassKaonCharged, - o2cp::MassProton, o2cp::MassDeuteron, o2cp::MassTriton, o2cp::MassHelium3, - o2cp::MassAlpha, o2cp::MassPionNeutral, o2cp::MassPhoton, - o2cp::MassKaonNeutral, o2cp::MassLambda, o2cp::MassHyperTriton}; - - static constexpr const float sMasses2[NIDsTot] = ///< defined particle masses^2 - {o2cp::MassElectron * o2cp::MassElectron, - o2cp::MassMuon* o2cp::MassMuon, - o2cp::MassPionCharged* o2cp::MassPionCharged, - o2cp::MassKaonCharged* o2cp::MassKaonCharged, - o2cp::MassProton* o2cp::MassProton, - o2cp::MassDeuteron* o2cp::MassDeuteron, - o2cp::MassTriton* o2cp::MassTriton, - o2cp::MassHelium3* o2cp::MassHelium3, - o2cp::MassAlpha* o2cp::MassAlpha, - o2cp::MassPionNeutral* o2cp::MassPionNeutral, - o2cp::MassPhoton* o2cp::MassPhoton, - o2cp::MassKaonNeutral* o2cp::MassKaonNeutral, - o2cp::MassLambda* o2cp::MassLambda, - o2cp::MassHyperTriton* o2cp::MassHyperTriton}; - - static constexpr const float sMasses2Z[NIDsTot] = ///< defined particle masses / Z - {o2cp::MassElectron, o2cp::MassMuon, - o2cp::MassPionCharged, o2cp::MassKaonCharged, - o2cp::MassProton, o2cp::MassDeuteron, - o2cp::MassTriton, o2cp::MassHelium3 / 2., - o2cp::MassAlpha / 2., - 0, 0, 0, 0, o2cp::MassHyperTriton}; - - static constexpr const int sCharges[NIDsTot] = ///< defined particle charges - {1, 1, 1, 1, 1, 1, 1, 2, 2, - 0, 0, 0, 0, 1}; +#endif ClassDefNV(PID, 2); }; diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h index 8d319333a24da..ce470361034f5 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,7 +37,7 @@ class PrimaryVertex : public Vertex<TimeStampWithError<float, float>> void setIR(const InteractionRecord& ir) { mIRMin = mIRMax = ir; } bool hasUniqueIR() const { return !mIRMin.isDummy() && (mIRMin == mIRMax); } -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE void print() const; std::string asString() const; #endif @@ -48,7 +49,7 @@ class PrimaryVertex : public Vertex<TimeStampWithError<float, float>> ClassDefNV(PrimaryVertex, 1); }; -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertex& v); #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h index 2a4a57753a580..c4b17158f7dc5 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,8 +24,13 @@ namespace o2 namespace track { -using TrackPar = TrackParametrization<float>; -using TrackParCov = TrackParametrizationWithError<float>; +using TrackParF = TrackParametrization<float>; +using TrackParD = TrackParametrization<double>; +using TrackPar = TrackParF; + +using TrackParCovF = TrackParametrizationWithError<float>; +using TrackParCovD = TrackParametrizationWithError<double>; +using TrackParCov = TrackParCovF; } // namespace track } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackCosmics.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackCosmics.h new file mode 100644 index 0000000000000..79a34dc585876 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackCosmics.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackCosmics.h +/// \brief Result of top-bottom cosmic tracks leg matching +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_TRACKCOSMICS_H +#define ALICEO2_TRACKCOSMICS_H + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonDataFormat/TimeStamp.h" + +namespace o2 +{ +namespace dataformats +{ + +class TrackCosmics : public o2::track::TrackParCov +{ + using timeEst = o2::dataformats::TimeStampWithError<float, float>; + + public: + TrackCosmics() = default; + ~TrackCosmics() = default; + TrackCosmics(const TrackCosmics& src) = default; + TrackCosmics(GlobalTrackID btm, GlobalTrackID top, const o2::track::TrackParCov& srcCent, const o2::track::TrackParCov& srcOut, float chi2Ref, float chi2Match, int ncl, float t, float tErr) + : o2::track::TrackParCov(srcCent), mParamOut(srcOut), mRefBottom(btm), mRefTop(top), mChi2Refit(chi2Ref), mChi2Match(chi2Match), mNClusters(ncl), mTimeMUS{t, tErr} {} + + GlobalTrackID getRefBottom() const { return mRefBottom; } + GlobalTrackID getRefTop() const { return mRefTop; } + void setRefBottom(GlobalTrackID id) { mRefBottom = id; } + void setRefTop(GlobalTrackID id) { mRefTop = id; } + + const timeEst& getTimeMUS() const { return mTimeMUS; } + timeEst& getTimeMUS() { return mTimeMUS; } + void setTimeMUS(const timeEst& t) { mTimeMUS = t; } + void setTimeMUS(float t, float te) + { + mTimeMUS.setTimeStamp(t); + mTimeMUS.setTimeStampError(te); + } + + void setChi2Refit(float v) { mChi2Refit = v; } + float getChi2Refit() const { return mChi2Refit; } + + void setChi2Match(float v) { mChi2Match = v; } + float getChi2Match() const { return mChi2Match; } + + int getNClusters() const { return mNClusters; } + void setNClusters(int n) { mNClusters = n; } + + o2::track::TrackParCov& getParamOut() { return mParamOut; } + const o2::track::TrackParCov& getParamOut() const { return mParamOut; } + + void print() const; + + private: + GlobalTrackID mRefBottom; ///< reference on Bottom leg + GlobalTrackID mRefTop; ///< reference on Top leg + float mChi2Refit = 0.f; ///< chi2 of the global refit + float mChi2Match = 0.f; ///< chi2 of the top/bottom match + int mNClusters = 0; ///< total number of fitted clusters + timeEst mTimeMUS; ///< time estimate in ns + o2::track::TrackParCov mParamOut; ///< refitted outer parameter + + ClassDefNV(TrackCosmics, 1); +}; +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h index bf9749a55d1ca..749a4a26f4301 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,8 @@ namespace o2 namespace track { -using SMatrix55 = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; +using SMatrix55Sym = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; +using SMatrix55Std = ROOT::Math::SMatrix<double, 5>; using SMatrix5 = ROOT::Math::SVector<Double_t, 5>; class TrackParFwd @@ -60,16 +62,9 @@ class TrackParFwd Double_t getInvQPt() const { return mParameters(4); } // return Inverse charged pt Double_t getPt() const { return TMath::Abs(1.f / mParameters(4)); } Double_t getInvPt() const { return TMath::Abs(mParameters(4)); } - Double_t getPx() const { return TMath::Cos(getPhi()) * getPt(); } // return px - Double_t getInvPx() const { return 1. / getPx(); } // return invpx - Double_t getPy() const { return TMath::Sin(getPhi()) * getPt(); } // return py - Double_t getInvPy() const { return 1. / getPx(); } // return invpy - Double_t getPz() const { return getTanl() * getPt(); } // return pz - Double_t getInvPz() const { return 1. / getPz(); } // return invpz - Double_t getP() const { return getPt() * TMath::Sqrt(1. + getTanl() * getTanl()); } // return total momentum Double_t getInverseMomentum() const { return 1.f / getP(); } @@ -125,11 +120,11 @@ class TrackParCovFwd : public TrackParFwd TrackParCovFwd() = default; ~TrackParCovFwd() = default; TrackParCovFwd& operator=(const TrackParCovFwd& tpf) = default; - TrackParCovFwd(const Double_t z, const SMatrix5 parameters, const SMatrix55 covariances, const Double_t chi2); + TrackParCovFwd(const Double_t z, const SMatrix5& parameters, const SMatrix55Sym& covariances, const Double_t chi2); - const SMatrix55& getCovariances() const { return mCovariances; } - void setCovariances(const SMatrix55& covariances) { mCovariances = covariances; } - void deleteCovariances() { mCovariances = SMatrix55(); } + const SMatrix55Sym& getCovariances() const { return mCovariances; } + void setCovariances(const SMatrix55Sym& covariances) { mCovariances = covariances; } + void deleteCovariances() { mCovariances = SMatrix55Sym(); } Double_t getSigma2X() const { return mCovariances(0, 0); } Double_t getSigma2Y() const { return mCovariances(1, 1); } @@ -141,9 +136,10 @@ class TrackParCovFwd : public TrackParFwd void propagateToZlinear(double zEnd); void propagateToZquadratic(double zEnd, double zField); void propagateToZhelix(double zEnd, double zField); + void propagateToZ(double zEnd, double zField); // Parameters: helix; errors: quadratic // Add Multiple Coulomb Scattering effects - void addMCSEffect(double dZ, double x2X0); + void addMCSEffect(double x2X0); // Kalman filter/fitting bool update(const std::array<float, 2>& p, const std::array<float, 2>& cov); @@ -155,7 +151,7 @@ class TrackParCovFwd : public TrackParFwd /// <X,PHI> <Y,PHI> <PHI,PHI> <TANL,PHI> <INVQPT,PHI> /// <X,TANL> <Y,TANL> <PHI,TANL> <TANL,TANL> <INVQPT,TANL> /// <X,INVQPT> <Y,INVQPT> <PHI,INVQPT> <TANL,INVQPT> <INVQPT,INVQPT> </pre> - SMatrix55 mCovariances{}; ///< \brief Covariance matrix of track parameters + SMatrix55Sym mCovariances{}; ///< \brief Covariance matrix of track parameters ClassDefNV(TrackParCovFwd, 1); }; diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackLTIntegral.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackLTIntegral.h index 75efa94113ed1..95d17d8b28d5b 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackLTIntegral.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackLTIntegral.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,9 +16,9 @@ #ifndef ALICEO2_TRACK_LTINTEGRAL_H_ #define ALICEO2_TRACK_LTINTEGRAL_H_ -#include <Rtypes.h> +#include "GPUCommonRtypes.h" +#include "GPUCommonDef.h" #include "ReconstructionDataFormats/PID.h" -#include "ReconstructionDataFormats/Track.h" namespace o2 { @@ -27,40 +28,50 @@ namespace track class TrackLTIntegral { public: - TrackLTIntegral() = default; - TrackLTIntegral(const TrackLTIntegral& stc) = default; - ~TrackLTIntegral() = default; + static constexpr float NeglectTime = -1.; // if 1st mT slot contains this, don't fill time - static constexpr int getNTOFs() { return o2::track::PID::NIDs; } + GPUdDefault() TrackLTIntegral() = default; + GPUdDefault() TrackLTIntegral(const TrackLTIntegral& stc) = default; + GPUdDefault() ~TrackLTIntegral() = default; - float getL() const { return mL; } - float getX2X0() const { return mX2X0; } - float getTOF(int id) const { return mT[id]; } + GPUd() static constexpr int getNTOFs() { return o2::track::PID::NIDs; } - void clear() + GPUd() float getL() const { return mL; } + GPUd() float getX2X0() const { return mX2X0; } + GPUd() float getXRho() const { return mXRho; } + GPUd() float getTOF(int id) const { return mT[id]; } + + GPUd() void clear() { mL = 0.f; mX2X0 = 0.f; + mXRho = 0.f; for (int i = getNTOFs(); i--;) { mT[i] = 0.f; } } - void addStep(float dL, const TrackPar& track); - void addX2X0(float d) { mX2X0 += d; } + GPUd() void addStep(float dL, float p2Inv); + GPUd() void addX2X0(float d) { mX2X0 += d; } + GPUd() void addXRho(float d) { mXRho += d; } + + GPUd() void setL(float l) { mL = l; } + GPUd() void setX2X0(float x) { mX2X0 = x; } + GPUd() void setXRho(float x) { mXRho = x; } + GPUd() void setTOF(float t, int id) { mT[id] = t; } - void setL(float l) { mL = l; } - void setX2X0(float x) { mX2X0 = x; } - void setTOF(float t, int id) { mT[id] = t; } + GPUd() void setTimeNotNeeded() { mT[0] = NeglectTime; } + GPUd() bool isTimeNotNeeded() const { return mT[0] == NeglectTime; } - void print() const; + GPUd() void print() const; private: float mL = 0.; // length in cm float mX2X0 = 0.; // integrated X/X0 + float mXRho = 0.; // average X*rho float mT[o2::track::PID::NIDs] = {0.}; // TOF in ps - ClassDefNV(TrackLTIntegral, 1); + ClassDefNV(TrackLTIntegral, 2); }; }; // namespace track }; // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h new file mode 100644 index 0000000000000..8542594f7da9a --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMCHMID.h +/// \brief Definition of the MUON track +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_TRACKMCHMID_H +#define ALICEO2_TRACKMCHMID_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +namespace o2 +{ +namespace dataformats +{ + +/// MUON track external format +class TrackMCHMID +{ + public: + TrackMCHMID() = default; + TrackMCHMID(const GlobalTrackID& mchID, const GlobalTrackID& midID, const InteractionRecord& midIR, double chi2) + : mMCHRef(mchID), mMIDRef(midID), mIR(midIR), mMatchNChi2(chi2) {} + TrackMCHMID(uint32_t mchIdx, uint32_t midIdx, const InteractionRecord& midIR, double chi2) + : mMCHRef(mchIdx, GlobalTrackID::MCH), mMIDRef(midIdx, GlobalTrackID::MID), mIR(midIR), mMatchNChi2(chi2) {} + ~TrackMCHMID() = default; + + TrackMCHMID(const TrackMCHMID& track) = default; + TrackMCHMID& operator=(const TrackMCHMID& track) = default; + TrackMCHMID(TrackMCHMID&&) = default; + TrackMCHMID& operator=(TrackMCHMID&&) = default; + + /// get the reference to the MCH track entry in its original container + GlobalTrackID getMCHRef() const { return mMCHRef; } + /// set the reference to the MCH track entry in its original container + void setMCHRef(const GlobalTrackID& id) { mMCHRef = id; } + /// set the reference to the MCH track entry in its original container + void setMCHRef(uint32_t idx) { mMCHRef.set(idx, GlobalTrackID::MCH); } + + /// get the reference to the MID track entry in its original container + GlobalTrackID getMIDRef() const { return mMIDRef; } + /// set the reference to the MID track entry in its original container + void setMIDRef(const GlobalTrackID& id) { mMIDRef = id; } + /// set the reference to the MID track entry in its original container + void setMIDRef(uint32_t idx) { mMIDRef.set(idx, GlobalTrackID::MID); } + + /// get the interaction record associated to this track + InteractionRecord getIR() const { return mIR; } + /// set the interaction record associated to this track + void setIR(const InteractionRecord& ir) { mIR = ir; } + + /// get the MCH-MID matching chi2/ndf + double getMatchChi2OverNDF() const { return mMatchNChi2; } + /// set the MCH-MID matching chi2/ndf + void setMatchChi2OverNDF(double chi2) { mMatchNChi2 = chi2; } + + void print() const; + + private: + GlobalTrackID mMCHRef{}; ///< reference to MCH track entry in its original container + GlobalTrackID mMIDRef{}; ///< reference to MID track entry in its original container + InteractionRecord mIR{}; ///< associated interaction record + double mMatchNChi2 = 0.; ///< MCH-MID matching chi2/ndf + + ClassDefNV(TrackMCHMID, 1); +}; + +std::ostream& operator<<(std::ostream& os, const TrackMCHMID& track); + +} // namespace dataformats +} // namespace o2 + +#endif // ALICEO2_TRACKMCHMID_H diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h index d9ffc0be528ce..c23cb7e7d1570 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,14 +29,16 @@ #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" #include "GPUCommonMath.h" +#include "GPUCommonArray.h" +#include "GPUROOTCartesianFwd.h" -#ifndef __OPENCL__ +#ifndef GPUCA_GPUCODE_DEVICE #include <algorithm> -#include <array> #include <cfloat> #include <cmath> #include <cstring> #include <iosfwd> +#include <type_traits> #endif #ifndef GPUCA_ALIGPUCODE //Used only by functions that are hidden on the GPU @@ -50,9 +53,6 @@ #include "ReconstructionDataFormats/TrackUtils.h" -//Forward declarations, since we cannot include the headers if we eventually want to use track.h on GPU -#include "GPUROOTCartesianFwd.h" - namespace o2 { template <typename T> @@ -105,14 +105,14 @@ constexpr float kCY2max = 100 * 100, // SigmaY<=100cm kCalcdEdxAuto = -999.f; // value indicating request for dedx calculation // access to covariance matrix by row and column -constexpr int CovarMap[kNParams][kNParams] = {{0, 1, 3, 6, 10}, - {1, 2, 4, 7, 11}, - {3, 4, 5, 8, 12}, - {6, 7, 8, 9, 13}, - {10, 11, 12, 13, 14}}; +GPUconstexpr() int CovarMap[kNParams][kNParams] = {{0, 1, 3, 6, 10}, + {1, 2, 4, 7, 11}, + {3, 4, 5, 8, 12}, + {6, 7, 8, 9, 13}, + {10, 11, 12, 13, 14}}; // access to covariance matrix diagonal elements -constexpr int DiagMap[kNParams] = {0, 2, 5, 9, 14}; +GPUconstexpr() int DiagMap[kNParams] = {0, 2, 5, 9, 14}; constexpr float HugeF = o2::constants::math::VeryBig; @@ -122,104 +122,108 @@ class TrackParametrization public: using value_t = value_T; - using dim2_t = std::array<value_t, 2>; - using dim3_t = std::array<value_t, 3>; - using params_t = std::array<value_t, kNParams>; + using dim2_t = gpu::gpustd::array<value_t, 2>; + using dim3_t = gpu::gpustd::array<value_t, 3>; + using params_t = gpu::gpustd::array<value_t, kNParams>; +#ifndef GPUCA_GPUCODE_DEVICE static_assert(std::is_floating_point_v<value_t>); +#endif - TrackParametrization() = default; - TrackParametrization(value_t x, value_t alpha, const params_t& par, int charge = 1); - TrackParametrization(const dim3_t& xyz, const dim3_t& pxpypz, int charge, bool sectorAlpha = true); - TrackParametrization(const TrackParametrization&) = default; - TrackParametrization(TrackParametrization&&) = default; - TrackParametrization& operator=(const TrackParametrization& src) = default; - TrackParametrization& operator=(TrackParametrization&& src) = default; - ~TrackParametrization() = default; - - const value_t* getParams() const; - value_t getParam(int i) const; - value_t getX() const; - value_t getAlpha() const; - value_t getY() const; - value_t getZ() const; - value_t getSnp() const; - value_t getTgl() const; - value_t getQ2Pt() const; - value_t getCharge2Pt() const; - int getAbsCharge() const; - PID getPID() const; - void setPID(const PID pid); + GPUdDefault() TrackParametrization() = default; + GPUd() TrackParametrization(value_t x, value_t alpha, const params_t& par, int charge = 1, const PID pid = PID::Pion); + GPUd() TrackParametrization(const dim3_t& xyz, const dim3_t& pxpypz, int charge, bool sectorAlpha = true, const PID pid = PID::Pion); + GPUdDefault() TrackParametrization(const TrackParametrization&) = default; + GPUdDefault() TrackParametrization(TrackParametrization&&) = default; + GPUdDefault() TrackParametrization& operator=(const TrackParametrization& src) = default; + GPUdDefault() TrackParametrization& operator=(TrackParametrization&& src) = default; + GPUdDefault() ~TrackParametrization() = default; + + GPUd() void set(value_t x, value_t alpha, const params_t& par, int charge = 1, const PID pid = PID::Pion); + GPUd() void set(value_t x, value_t alpha, const value_t* par, int charge = 1, const PID pid = PID::Pion); + GPUd() const value_t* getParams() const; + GPUd() value_t getParam(int i) const; + GPUd() value_t getX() const; + GPUd() value_t getAlpha() const; + GPUd() value_t getY() const; + GPUd() value_t getZ() const; + GPUd() value_t getSnp() const; + GPUd() value_t getTgl() const; + GPUd() value_t getQ2Pt() const; + GPUd() value_t getCharge2Pt() const; + GPUd() int getAbsCharge() const; + GPUd() PID getPID() const; + GPUd() void setPID(const PID pid); /// calculate cos^2 and cos of track direction in rphi-tracking - value_t getCsp2() const; - value_t getCsp() const; - - void setX(value_t v); - void setParam(value_t v, int i); - void setAlpha(value_t v); - void setY(value_t v); - void setZ(value_t v); - void setSnp(value_t v); - void setTgl(value_t v); - void setQ2Pt(value_t v); - void setAbsCharge(int q); + GPUd() value_t getCsp2() const; + GPUd() value_t getCsp() const; + + GPUd() void setX(value_t v); + GPUd() void setParam(value_t v, int i); + GPUd() void setAlpha(value_t v); + GPUd() void setY(value_t v); + GPUd() void setZ(value_t v); + GPUd() void setSnp(value_t v); + GPUd() void setTgl(value_t v); + GPUd() void setQ2Pt(value_t v); + GPUd() void setAbsCharge(int q); // derived getters - bool getXatLabR(value_t r, value_t& x, value_t bz, DirType dir = DirAuto) const; - void getCircleParamsLoc(value_t bz, o2::math_utils::CircleXY<value_t>& circle) const; - void getCircleParams(value_t bz, o2::math_utils::CircleXY<value_t>& circle, value_t& sna, value_t& csa) const; - void getLineParams(o2::math_utils::IntervalXY<value_t>& line, value_t& sna, value_t& csa) const; - value_t getCurvature(value_t b) const; - int getCharge() const; - int getSign() const; - value_t getPhi() const; - value_t getPhiPos() const; - - value_t getPtInv() const; - value_t getP2Inv() const; - value_t getP2() const; - value_t getPInv() const; - value_t getP() const; - value_t getPt() const; - - value_t getTheta() const; - value_t getEta() const; - math_utils::Point3D<value_t> getXYZGlo() const; - void getXYZGlo(dim3_t& xyz) const; - bool getPxPyPzGlo(dim3_t& pxyz) const; - bool getPosDirGlo(std::array<value_t, 9>& posdirp) const; + GPUd() bool getXatLabR(value_t r, value_t& x, value_t bz, DirType dir = DirAuto) const; + GPUd() void getCircleParamsLoc(value_t bz, o2::math_utils::CircleXY<value_t>& circle) const; + GPUd() void getCircleParams(value_t bz, o2::math_utils::CircleXY<value_t>& circle, value_t& sna, value_t& csa) const; + GPUd() void getLineParams(o2::math_utils::IntervalXY<value_t>& line, value_t& sna, value_t& csa) const; + GPUd() value_t getCurvature(value_t b) const; + GPUd() int getCharge() const; + GPUd() int getSign() const; + GPUd() value_t getPhi() const; + GPUd() value_t getPhiPos() const; + + GPUd() value_t getPtInv() const; + GPUd() value_t getP2Inv() const; + GPUd() value_t getP2() const; + GPUd() value_t getPInv() const; + GPUd() value_t getP() const; + GPUd() value_t getPt() const; + + GPUd() value_t getTheta() const; + GPUd() value_t getEta() const; + GPUd() math_utils::Point3D<value_t> getXYZGlo() const; + GPUd() void getXYZGlo(dim3_t& xyz) const; + GPUd() bool getPxPyPzGlo(dim3_t& pxyz) const; + GPUd() bool getPosDirGlo(gpu::gpustd::array<value_t, 9>& posdirp) const; // methods for track params estimate at other point - bool getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const; - value_t getZAt(value_t xk, value_t b) const; - value_t getYAt(value_t xk, value_t b) const; - math_utils::Point3D<value_t> getXYZGloAt(value_t xk, value_t b, bool& ok) const; + GPUd() bool getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const; + GPUd() value_t getZAt(value_t xk, value_t b) const; + GPUd() value_t getYAt(value_t xk, value_t b) const; + GPUd() math_utils::Point3D<value_t> getXYZGloAt(value_t xk, value_t b, bool& ok) const; // parameters manipulation - bool correctForELoss(value_t xrho, value_t mass, bool anglecorr = false, value_t dedx = kCalcdEdxAuto); - bool rotateParam(value_t alpha); - bool propagateParamTo(value_t xk, value_t b); - bool propagateParamTo(value_t xk, const dim3_t& b); + GPUd() bool correctForELoss(value_t xrho, bool anglecorr = false, value_t dedx = kCalcdEdxAuto); + GPUd() bool rotateParam(value_t alpha); + GPUd() bool propagateParamTo(value_t xk, value_t b); + GPUd() bool propagateParamTo(value_t xk, const dim3_t& b); - bool propagateParamToDCA(const math_utils::Point3D<value_t>& vtx, value_t b, dim2_t* dca = nullptr, value_t maxD = 999.f); + GPUd() bool propagateParamToDCA(const math_utils::Point3D<value_t>& vtx, value_t b, dim2_t* dca = nullptr, value_t maxD = 999.f); - void invertParam(); + GPUd() void invertParam(); - bool isValid() const; - void invalidate(); + GPUd() bool isValid() const; + GPUd() void invalidate(); - uint16_t getUserField() const; - void setUserField(uint16_t v); + GPUhd() uint16_t getUserField() const; + GPUhd() void setUserField(uint16_t v); - void printParam() const; + GPUd() void printParam() const; #ifndef GPUCA_ALIGPUCODE std::string asString() const; #endif - protected: - void updateParam(value_t delta, int i); - void updateParams(const value_t delta[kNParams]); + GPUd() void updateParam(value_t delta, int i); + GPUd() void updateParams(const params_t& delta); + GPUd() void updateParams(const value_t* delta); private: // @@ -228,7 +232,7 @@ class TrackParametrization value_t mAlpha = 0.f; /// track frame angle value_t mP[kNParams] = {0.f}; /// 5 parameters: Y,Z,sin(phi),tg(lambda),q/pT char mAbsCharge = 1; /// Extra info about the abs charge, to be taken into account only if not 1 - PID mPID{}; /// 8 bit PID + PID mPID{PID::Pion}; /// 8 bit PID uint16_t mUserField = 0; /// field provided to user ClassDefNV(TrackParametrization, 3); @@ -236,108 +240,130 @@ class TrackParametrization //____________________________________________________________ template <typename value_T> -inline TrackParametrization<value_T>::TrackParametrization(value_t x, value_t alpha, const params_t& par, int charge) - : mX{x}, mAlpha{alpha}, mAbsCharge{char(std::abs(charge))} +GPUdi() TrackParametrization<value_T>::TrackParametrization(value_t x, value_t alpha, const params_t& par, int charge, const PID pid) + : mX{x}, mAlpha{alpha}, mAbsCharge{char(gpu::CAMath::Abs(charge))}, mPID{pid} { // explicit constructor - std::copy(par.begin(), par.end(), mP); + for (int i = 0; i < kNParams; i++) { + mP[i] = par[i]; + } +} + +//____________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrization<value_T>::set(value_t x, value_t alpha, const params_t& par, int charge, const PID pid) +{ + set(x, alpha, par.data(), charge, pid); +} + +//____________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrization<value_T>::set(value_t x, value_t alpha, const value_t* par, int charge, const PID pid) +{ + mX = x; + mAlpha = alpha; + mAbsCharge = char(gpu::CAMath::Abs(charge)); + for (int i = 0; i < kNParams; i++) { + mP[i] = par[i]; + } + mPID = pid; } //____________________________________________________________ template <typename value_T> -inline const typename TrackParametrization<value_T>::value_t* TrackParametrization<value_T>::getParams() const +GPUdi() auto TrackParametrization<value_T>::getParams() const -> const value_t* { return mP; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getParam(int i) const +GPUdi() auto TrackParametrization<value_T>::getParam(int i) const -> value_t { return mP[i]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getX() const +GPUdi() auto TrackParametrization<value_T>::getX() const -> value_t { return mX; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getAlpha() const +GPUdi() auto TrackParametrization<value_T>::getAlpha() const -> value_t { return mAlpha; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getY() const +GPUdi() auto TrackParametrization<value_T>::getY() const -> value_t { return mP[kY]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getZ() const +GPUdi() auto TrackParametrization<value_T>::getZ() const -> value_t { return mP[kZ]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getSnp() const +GPUdi() auto TrackParametrization<value_T>::getSnp() const -> value_t { return mP[kSnp]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getTgl() const +GPUdi() auto TrackParametrization<value_T>::getTgl() const -> value_t { return mP[kTgl]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getQ2Pt() const +GPUdi() auto TrackParametrization<value_T>::getQ2Pt() const -> value_t { return mP[kQ2Pt]; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getCharge2Pt() const +GPUdi() auto TrackParametrization<value_T>::getCharge2Pt() const -> value_t { return mAbsCharge ? mP[kQ2Pt] : 0.f; } //____________________________________________________________ template <typename value_T> -inline int TrackParametrization<value_T>::getAbsCharge() const +GPUdi() int TrackParametrization<value_T>::getAbsCharge() const { return mAbsCharge; } //____________________________________________________________ template <typename value_T> -inline PID TrackParametrization<value_T>::getPID() const +GPUdi() PID TrackParametrization<value_T>::getPID() const { return mPID; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setPID(const PID pid) +GPUdi() void TrackParametrization<value_T>::setPID(const PID pid) { mPID = pid; - setAbsCharge(pid.getCharge()); + // setAbsCharge(pid.getCharge()); // If needed, user should change the charge via corr. setter } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getCsp2() const +GPUdi() auto TrackParametrization<value_T>::getCsp2() const -> value_t { const value_t csp2 = (1.f - mP[kSnp]) * (1.f + mP[kSnp]); return csp2 > o2::constants::math::Almost0 ? csp2 : o2::constants::math::Almost0; @@ -345,88 +371,88 @@ inline typename TrackParametrization<value_T>::value_t TrackParametrization<valu //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getCsp() const +GPUdi() auto TrackParametrization<value_T>::getCsp() const -> value_t { - return std::sqrt(getCsp2()); + return gpu::CAMath::Sqrt(getCsp2()); } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setX(value_t v) +GPUdi() void TrackParametrization<value_T>::setX(value_t v) { mX = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setParam(value_t v, int i) +GPUdi() void TrackParametrization<value_T>::setParam(value_t v, int i) { mP[i] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setAlpha(value_t v) +GPUdi() void TrackParametrization<value_T>::setAlpha(value_t v) { mAlpha = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setY(value_t v) +GPUdi() void TrackParametrization<value_T>::setY(value_t v) { mP[kY] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setZ(value_t v) +GPUdi() void TrackParametrization<value_T>::setZ(value_t v) { mP[kZ] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setSnp(value_t v) +GPUdi() void TrackParametrization<value_T>::setSnp(value_t v) { mP[kSnp] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setTgl(value_t v) +GPUdi() void TrackParametrization<value_T>::setTgl(value_t v) { mP[kTgl] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setQ2Pt(value_t v) +GPUdi() void TrackParametrization<value_T>::setQ2Pt(value_t v) { mP[kQ2Pt] = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::setAbsCharge(int q) +GPUdi() void TrackParametrization<value_T>::setAbsCharge(int q) { - mAbsCharge = std::abs(q); + mAbsCharge = gpu::CAMath::Abs(q); } //_______________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::getCircleParamsLoc(value_t bz, o2::math_utils::CircleXY<value_t>& c) const +GPUdi() void TrackParametrization<value_T>::getCircleParamsLoc(value_t bz, o2::math_utils::CircleXY<value_t>& c) const { // get circle params in track local frame, for straight line just set to local coordinates c.rC = getCurvature(bz); // treat as straight track if sagitta between the vertex and middle of TPC is below 0.01 cm constexpr value_t MinSagitta = 0.01f, TPCMidR = 160.f, MinCurv = 8 * MinSagitta / (TPCMidR * TPCMidR); - if (std::abs(c.rC) > MinCurv) { + if (gpu::CAMath::Abs(c.rC) > MinCurv) { c.rC = 1.f / getCurvature(bz); - value_t sn = getSnp(), cs = std::sqrt((1.f - sn) * (1.f + sn)); + value_t sn = getSnp(), cs = gpu::CAMath::Sqrt((1.f - sn) * (1.f + sn)); c.xC = getX() - sn * c.rC; // center in tracking c.yC = getY() + cs * c.rC; // frame. Note: r is signed!!! - c.rC = std::abs(c.rC); + c.rC = gpu::CAMath::Abs(c.rC); } else { c.rC = 0.f; // signal straight line c.xC = getX(); @@ -436,7 +462,7 @@ inline void TrackParametrization<value_T>::getCircleParamsLoc(value_t bz, o2::ma //_______________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::getCircleParams(value_t bz, o2::math_utils::CircleXY<value_t>& c, value_t& sna, value_t& csa) const +GPUdi() void TrackParametrization<value_T>::getCircleParams(value_t bz, o2::math_utils::CircleXY<value_t>& c, value_t& sna, value_t& csa) const { // get circle params in loc and lab frame, for straight line just set to global coordinates getCircleParamsLoc(bz, c); @@ -446,69 +472,69 @@ inline void TrackParametrization<value_T>::getCircleParams(value_t bz, o2::math_ //_______________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::getLineParams(o2::math_utils::IntervalXY<value_t>& ln, value_t& sna, value_t& csa) const +GPUdi() void TrackParametrization<value_T>::getLineParams(o2::math_utils::IntervalXY<value_t>& ln, value_t& sna, value_t& csa) const { // get line parameterization as { x = x0 + xSlp*t, y = y0 + ySlp*t } o2::math_utils::detail::sincos(getAlpha(), sna, csa); o2::math_utils::detail::rotateZ<value_t>(getX(), getY(), ln.getX0(), ln.getY0(), sna, csa); // reference point in global frame - value_t snp = getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); + value_t snp = getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); ln.setDX(csp * csa - snp * sna); ln.setDY(snp * csa + csp * sna); } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getCurvature(value_t b) const +GPUdi() auto TrackParametrization<value_T>::getCurvature(value_t b) const -> value_t { return mAbsCharge ? mP[kQ2Pt] * b * o2::constants::math::B2C : 0.; } //____________________________________________________________ template <typename value_T> -inline int TrackParametrization<value_T>::getCharge() const +GPUdi() int TrackParametrization<value_T>::getCharge() const { return getSign() > 0 ? mAbsCharge : -mAbsCharge; } //____________________________________________________________ template <typename value_T> -inline int TrackParametrization<value_T>::getSign() const +GPUdi() int TrackParametrization<value_T>::getSign() const { return mAbsCharge ? (mP[kQ2Pt] > 0.f ? 1 : -1) : 0; } //_______________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPhi() const +GPUdi() auto TrackParametrization<value_T>::getPhi() const -> value_t { // track pt direction phi (in 0:2pi range) - value_t phi = std::asin(getSnp()) + getAlpha(); + value_t phi = gpu::CAMath::ASin(getSnp()) + getAlpha(); math_utils::detail::bringTo02Pi<value_t>(phi); return phi; } //_______________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPhiPos() const +GPUdi() auto TrackParametrization<value_T>::getPhiPos() const -> value_t { // angle of track position (in -pi:pi range) - value_t phi = std::atan2(getY(), getX()) + getAlpha(); + value_t phi = gpu::CAMath::ATan2(getY(), getX()) + getAlpha(); math_utils::detail::bringTo02Pi<value_t>(phi); return phi; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPtInv() const +GPUdi() auto TrackParametrization<value_T>::getPtInv() const -> value_t { // return the inverted track pT - const value_t ptInv = std::fabs(mP[kQ2Pt]); + const value_t ptInv = gpu::CAMath::Abs(mP[kQ2Pt]); return (mAbsCharge > 1) ? ptInv / mAbsCharge : ptInv; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getP2Inv() const +GPUdi() auto TrackParametrization<value_T>::getP2Inv() const -> value_t { // return the inverted track momentum^2 const value_t p2 = mP[kQ2Pt] * mP[kQ2Pt] / (1.f + getTgl() * getTgl()); @@ -517,7 +543,7 @@ inline typename TrackParametrization<value_T>::value_t TrackParametrization<valu //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getP2() const +GPUdi() auto TrackParametrization<value_T>::getP2() const -> value_t { // return the track momentum^2 const value_t p2inv = getP2Inv(); @@ -526,16 +552,16 @@ inline typename TrackParametrization<value_T>::value_t TrackParametrization<valu //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPInv() const +GPUdi() auto TrackParametrization<value_T>::getPInv() const -> value_t { // return the inverted track momentum^2 - const value_t pInv = std::fabs(mP[kQ2Pt]) / std::sqrt(1.f + getTgl() * getTgl()); + const value_t pInv = gpu::CAMath::Abs(mP[kQ2Pt]) / gpu::CAMath::Sqrt(1.f + getTgl() * getTgl()); return (mAbsCharge > 1) ? pInv / mAbsCharge : pInv; } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getP() const +GPUdi() auto TrackParametrization<value_T>::getP() const -> value_t { // return the track momentum const value_t pInv = getPInv(); @@ -544,10 +570,10 @@ inline typename TrackParametrization<value_T>::value_t TrackParametrization<valu //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPt() const +GPUdi() auto TrackParametrization<value_T>::getPt() const -> value_t { // return the track transverse momentum - value_t ptI = std::fabs(mP[kQ2Pt]); + value_t ptI = gpu::CAMath::Abs(mP[kQ2Pt]); if (mAbsCharge > 1) { ptI /= mAbsCharge; } @@ -556,34 +582,34 @@ inline typename TrackParametrization<value_T>::value_t TrackParametrization<valu //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getTheta() const +GPUdi() auto TrackParametrization<value_T>::getTheta() const -> value_t { - return constants::math::PIHalf - std::atan(mP[3]); + return constants::math::PIHalf - gpu::CAMath::ATan(mP[3]); } //____________________________________________________________ template <typename value_T> -inline typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getEta() const +GPUdi() auto TrackParametrization<value_T>::getEta() const -> value_t { - return -std::log(std::tan(0.5f * getTheta())); + return -gpu::CAMath::Log(gpu::CAMath::Tan(0.5f * getTheta())); } //_______________________________________________________ template <typename value_T> -inline math_utils::Point3D<typename TrackParametrization<value_T>::value_t> TrackParametrization<value_T>::getXYZGlo() const +GPUdi() auto TrackParametrization<value_T>::getXYZGlo() const -> math_utils::Point3D<value_t> { #ifndef GPUCA_ALIGPUCODE return math_utils::Rotation2D<value_t>(getAlpha())(math_utils::Point3D<value_t>(getX(), getY(), getZ())); #else // mockup on GPU without ROOT float sina, cosa; - o2::gpu::CAMath::SinCos(getAlpha(), sina, cosa); + gpu::CAMath::SinCos(getAlpha(), sina, cosa); return math_utils::Point3D<value_t>(cosa * getX() + sina * getY(), cosa * getY() - sina * getX(), getZ()); #endif } //_______________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::getXYZGlo(dim3_t& xyz) const +GPUdi() void TrackParametrization<value_T>::getXYZGlo(dim3_t& xyz) const { // track coordinates in lab frame xyz[0] = getX(); @@ -594,7 +620,7 @@ inline void TrackParametrization<value_T>::getXYZGlo(dim3_t& xyz) const //_______________________________________________________ template <typename value_T> -inline math_utils::Point3D<typename TrackParametrization<value_T>::value_t> TrackParametrization<value_T>::getXYZGloAt(value_t xk, value_t b, bool& ok) const +GPUdi() auto TrackParametrization<value_T>::getXYZGloAt(value_t xk, value_t b, bool& ok) const -> math_utils::Point3D<value_t> { //---------------------------------------------------------------- // estimate global X,Y,Z in global frame at given X @@ -606,7 +632,7 @@ inline math_utils::Point3D<typename TrackParametrization<value_T>::value_t> Trac return math_utils::Rotation2D<value_t>(getAlpha())(math_utils::Point3D<value_t>(xk, y, z)); #else // mockup on GPU without ROOT float sina, cosa; - o2::gpu::CAMath::SinCos(getAlpha(), sina, cosa); + gpu::CAMath::SinCos(getAlpha(), sina, cosa); return math_utils::Point3D<value_t>(cosa * xk + sina * y, cosa * y - sina * xk, z); #endif } else { @@ -616,40 +642,47 @@ inline math_utils::Point3D<typename TrackParametrization<value_T>::value_t> Trac //____________________________________________________________ template <typename value_T> -inline bool TrackParametrization<value_T>::isValid() const +GPUdi() bool TrackParametrization<value_T>::isValid() const { return mX != InvalidX; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::invalidate() +GPUdi() void TrackParametrization<value_T>::invalidate() { mX = InvalidX; } template <typename value_T> -inline uint16_t TrackParametrization<value_T>::getUserField() const +GPUhdi() uint16_t TrackParametrization<value_T>::getUserField() const { return mUserField; } template <typename value_T> -inline void TrackParametrization<value_T>::setUserField(uint16_t v) +GPUhdi() void TrackParametrization<value_T>::setUserField(uint16_t v) { mUserField = v; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::updateParam(value_t delta, int i) +GPUdi() void TrackParametrization<value_T>::updateParam(value_t delta, int i) { mP[i] += delta; } //____________________________________________________________ template <typename value_T> -inline void TrackParametrization<value_T>::updateParams(const value_t delta[kNParams]) +GPUdi() void TrackParametrization<value_T>::updateParams(const params_t& delta) +{ + updateParams(delta.data()); +} + +//____________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrization<value_T>::updateParams(const value_t* delta) { for (int i = kNParams; i--;) { mP[i] += delta[i]; diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h index 9910623f25f24..78b01a007012b 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,235 +27,262 @@ namespace track template <typename value_T = float> class TrackParametrizationWithError : public TrackParametrization<value_T> { // track+error parameterization - using MatrixDSym5 = ROOT::Math::SMatrix<double, kNParams, kNParams, ROOT::Math::MatRepSym<double, kNParams>>; - using MatrixD5 = ROOT::Math::SMatrix<double, kNParams, kNParams, ROOT::Math::MatRepStd<double, kNParams, kNParams>>; - + public: using typename TrackParametrization<value_T>::value_t; using typename TrackParametrization<value_T>::dim3_t; using typename TrackParametrization<value_T>::dim2_t; using typename TrackParametrization<value_T>::params_t; +#ifndef GPUCA_GPUCODE_DEVICE static_assert(std::is_floating_point_v<value_t>); +#endif - public: - using covMat_t = std::array<value_t, kCovMatSize>; - - TrackParametrizationWithError(); - TrackParametrizationWithError(value_t x, value_t alpha, const params_t& par, const std::array<value_t, kCovMatSize>& cov, int charge = 1); - TrackParametrizationWithError(const dim3_t& xyz, const dim3_t& pxpypz, - const std::array<value_t, kLabCovMatSize>& cv, int sign, bool sectorAlpha = true); - - TrackParametrizationWithError(const TrackParametrizationWithError& src) = default; - TrackParametrizationWithError(TrackParametrizationWithError&& src) = default; - TrackParametrizationWithError& operator=(const TrackParametrizationWithError& src) = default; - TrackParametrizationWithError& operator=(TrackParametrizationWithError&& src) = default; - ~TrackParametrizationWithError() = default; + using covMat_t = gpu::gpustd::array<value_t, kCovMatSize>; + using MatrixDSym5 = ROOT::Math::SMatrix<double, kNParams, kNParams, ROOT::Math::MatRepSym<double, kNParams>>; + using MatrixD5 = ROOT::Math::SMatrix<double, kNParams, kNParams, ROOT::Math::MatRepStd<double, kNParams, kNParams>>; + + GPUd() TrackParametrizationWithError(); + GPUd() TrackParametrizationWithError(value_t x, value_t alpha, const params_t& par, const covMat_t& cov, int charge = 1, const PID pid = PID::Pion); + GPUd() TrackParametrizationWithError(const dim3_t& xyz, const dim3_t& pxpypz, + const gpu::gpustd::array<value_t, kLabCovMatSize>& cv, int sign, bool sectorAlpha = true, const PID pid = PID::Pion); + + GPUdDefault() TrackParametrizationWithError(const TrackParametrizationWithError& src) = default; + GPUdDefault() TrackParametrizationWithError(TrackParametrizationWithError&& src) = default; + GPUdDefault() TrackParametrizationWithError& operator=(const TrackParametrizationWithError& src) = default; + GPUdDefault() TrackParametrizationWithError& operator=(TrackParametrizationWithError&& src) = default; + GPUdDefault() ~TrackParametrizationWithError() = default; using TrackParametrization<value_T>::TrackParametrization; - const value_t* getCov() const; - value_t getSigmaY2() const; - value_t getSigmaZY() const; - value_t getSigmaZ2() const; - value_t getSigmaSnpY() const; - value_t getSigmaSnpZ() const; - value_t getSigmaSnp2() const; - value_t getSigmaTglY() const; - value_t getSigmaTglZ() const; - value_t getSigmaTglSnp() const; - value_t getSigmaTgl2() const; - value_t getSigma1PtY() const; - value_t getSigma1PtZ() const; - value_t getSigma1PtSnp() const; - value_t getSigma1PtTgl() const; - value_t getSigma1Pt2() const; - value_t getCovarElem(int i, int j) const; - value_t getDiagError2(int i) const; - - bool getCovXYZPxPyPzGlo(std::array<value_t, kLabCovMatSize>& c) const; - - void print() const; + using TrackParametrization<value_T>::set; + GPUd() void set(value_t x, value_t alpha, const params_t& par, const covMat_t& cov, int charge = 1, const PID pid = PID::Pion); + GPUd() void set(value_t x, value_t alpha, const value_t* par, const value_t* cov, int charge = 1, const PID pid = PID::Pion); + GPUd() void set(const dim3_t& xyz, const dim3_t& pxpypz, const gpu::gpustd::array<value_t, kLabCovMatSize>& cv, int sign, bool sectorAlpha = true, const PID pid = PID::Pion); + GPUd() const covMat_t& getCov() const; + GPUd() value_t getSigmaY2() const; + GPUd() value_t getSigmaZY() const; + GPUd() value_t getSigmaZ2() const; + GPUd() value_t getSigmaSnpY() const; + GPUd() value_t getSigmaSnpZ() const; + GPUd() value_t getSigmaSnp2() const; + GPUd() value_t getSigmaTglY() const; + GPUd() value_t getSigmaTglZ() const; + GPUd() value_t getSigmaTglSnp() const; + GPUd() value_t getSigmaTgl2() const; + GPUd() value_t getSigma1PtY() const; + GPUd() value_t getSigma1PtZ() const; + GPUd() value_t getSigma1PtSnp() const; + GPUd() value_t getSigma1PtTgl() const; + GPUd() value_t getSigma1Pt2() const; + GPUd() value_t getCovarElem(int i, int j) const; + GPUd() value_t getDiagError2(int i) const; + + GPUd() bool getCovXYZPxPyPzGlo(gpu::gpustd::array<value_t, kLabCovMatSize>& c) const; + + GPUd() void print() const; #ifndef GPUCA_ALIGPUCODE std::string asString() const; #endif // parameters + covmat manipulation - bool rotate(value_t alpha); - bool propagateTo(value_t xk, value_t b); - bool propagateTo(value_t xk, const dim3_t& b); - bool propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t b, o2::dataformats::DCA* dca = nullptr, value_t maxD = 999.f); - void invert(); + GPUd() bool rotate(value_t alpha); + GPUd() bool propagateTo(value_t xk, value_t b); + GPUd() bool propagateTo(value_t xk, const dim3_t& b); + GPUd() bool propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t b, o2::dataformats::DCA* dca = nullptr, value_t maxD = 999.f); + GPUd() void invert(); - value_t getPredictedChi2(const dim2_t& p, const dim3_t& cov) const; + GPUd() value_t getPredictedChi2(const dim2_t& p, const dim3_t& cov) const; + GPUd() value_t getPredictedChi2(const value_t* p, const value_t* cov) const; template <typename T> - value_t getPredictedChi2(const BaseCluster<T>& p) const; - - value_t getPredictedChi2(const TrackParametrizationWithError& rhs) const; + GPUd() value_t getPredictedChi2(const BaseCluster<T>& p) const; void buildCombinedCovMatrix(const TrackParametrizationWithError& rhs, MatrixDSym5& cov) const; value_t getPredictedChi2(const TrackParametrizationWithError& rhs, MatrixDSym5& covToSet) const; + value_t getPredictedChi2(const TrackParametrizationWithError& rhs) const; bool update(const TrackParametrizationWithError& rhs, const MatrixDSym5& covInv); + bool update(const TrackParametrizationWithError& rhs); - bool update(const dim2_t& p, const dim3_t& cov); + GPUd() bool update(const dim2_t& p, const dim3_t& cov); + GPUd() bool update(const value_t* p, const value_t* cov); template <typename T> - bool update(const BaseCluster<T>& p); - - bool update(const TrackParametrizationWithError& rhs); + GPUd() bool update(const BaseCluster<T>& p); - bool correctForMaterial(value_t x2x0, value_t xrho, value_t mass, bool anglecorr = false, value_t dedx = kCalcdEdxAuto); + GPUd() bool correctForMaterial(value_t x2x0, value_t xrho, bool anglecorr = false, value_t dedx = kCalcdEdxAuto); - void resetCovariance(value_t s2 = 0); - void checkCovariance(); - void setCov(value_t v, int i); + GPUd() void resetCovariance(value_t s2 = 0); + GPUd() void checkCovariance(); + GPUd() void setCov(value_t v, size_t i, size_t j); + GPUd() void setCov(value_t v, int i); + GPUd() void setCov(const covMat_t& mat); - void updateCov(const value_t delta[kCovMatSize]); - void updateCov(value_t delta, int i); + GPUd() void updateCov(const covMat_t& delta); + GPUd() void updateCov(value_t delta, size_t i, size_t j); + GPUd() void updateCov(value_t delta, size_t i); protected: - value_t mC[kCovMatSize] = {0.f}; // 15 covariance matrix elements + covMat_t mC{0.f}; // 15 covariance matrix elements ClassDefNV(TrackParametrizationWithError, 2); }; //__________________________________________________________________________ template <typename value_T> -inline TrackParametrizationWithError<value_T>::TrackParametrizationWithError() : TrackParametrization<value_T>{} +GPUdi() TrackParametrizationWithError<value_T>::TrackParametrizationWithError() : TrackParametrization<value_T>{} { } //__________________________________________________________________________ template <typename value_T> -inline TrackParametrizationWithError<value_T>::TrackParametrizationWithError(value_t x, value_t alpha, const params_t& par, - const std::array<value_t, kCovMatSize>& cov, int charge) - : TrackParametrization<value_T>{x, alpha, par, charge} +GPUdi() TrackParametrizationWithError<value_T>::TrackParametrizationWithError(value_t x, value_t alpha, const params_t& par, + const covMat_t& cov, int charge, const PID pid) + : TrackParametrization<value_T>{x, alpha, par, charge, pid} { // explicit constructor - std::copy(cov.begin(), cov.end(), mC); + for (int i = 0; i < kCovMatSize; i++) { + mC[i] = cov[i]; + } +} + +//__________________________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrizationWithError<value_T>::set(value_t x, value_t alpha, const params_t& par, const covMat_t& cov, int charge, const PID pid) +{ + set(x, alpha, par.data(), cov.data(), charge, pid); +} + +//__________________________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrizationWithError<value_T>::set(value_t x, value_t alpha, const value_t* par, const value_t* cov, int charge, const PID pid) +{ + TrackParametrization<value_T>::set(x, alpha, par, charge, pid); + for (int i = 0; i < kCovMatSize; i++) { + mC[i] = cov[i]; + } } //__________________________________________________________________________ template <typename value_T> -inline const typename TrackParametrizationWithError<value_T>::value_t* TrackParametrizationWithError<value_T>::getCov() const +GPUdi() auto TrackParametrizationWithError<value_T>::getCov() const -> const covMat_t& { return mC; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaY2() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaY2() const -> value_t { return mC[kSigY2]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaZY() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaZY() const -> value_t { return mC[kSigZY]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaZ2() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaZ2() const -> value_t { return mC[kSigZ2]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaSnpY() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaSnpY() const -> value_t { return mC[kSigSnpY]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaSnpZ() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaSnpZ() const -> value_t { return mC[kSigSnpZ]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaSnp2() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaSnp2() const -> value_t { return mC[kSigSnp2]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaTglY() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaTglY() const -> value_t { return mC[kSigTglY]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaTglZ() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaTglZ() const -> value_t { return mC[kSigTglZ]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaTglSnp() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaTglSnp() const -> value_t { return mC[kSigTglSnp]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigmaTgl2() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigmaTgl2() const -> value_t { return mC[kSigTgl2]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigma1PtY() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigma1PtY() const -> value_t { return mC[kSigQ2PtY]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigma1PtZ() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigma1PtZ() const -> value_t { return mC[kSigQ2PtZ]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigma1PtSnp() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigma1PtSnp() const -> value_t { return mC[kSigQ2PtSnp]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigma1PtTgl() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigma1PtTgl() const -> value_t { return mC[kSigQ2PtTgl]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getSigma1Pt2() const +GPUdi() auto TrackParametrizationWithError<value_T>::getSigma1Pt2() const -> value_t { return mC[kSigQ2Pt2]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getCovarElem(int i, int j) const +GPUdi() auto TrackParametrizationWithError<value_T>::getCovarElem(int i, int j) const -> value_t { return mC[CovarMap[i][j]]; } //__________________________________________________________________________ template <typename value_T> -inline typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getDiagError2(int i) const +GPUdi() auto TrackParametrizationWithError<value_T>::getDiagError2(int i) const -> value_t { return mC[DiagMap[i]]; } @@ -262,17 +290,31 @@ inline typename TrackParametrizationWithError<value_T>::value_t TrackParametriza //__________________________________________________________________________ template <typename value_T> template <typename T> -typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getPredictedChi2(const BaseCluster<T>& p) const +GPUdi() auto TrackParametrizationWithError<value_T>::getPredictedChi2(const BaseCluster<T>& p) const -> value_t { const dim2_t pyz = {p.getY(), p.getZ()}; const dim3_t cov = {p.getSigmaY2(), p.getSigmaYZ(), p.getSigmaZ2()}; return getPredictedChi2(pyz, cov); } +//______________________________________________ +template <typename value_T> +GPUdi() auto TrackParametrizationWithError<value_T>::getPredictedChi2(const dim2_t& p, const dim3_t& cov) const -> value_t +{ + return getPredictedChi2(p.data(), cov.data()); +} + +//______________________________________________ +template <typename value_T> +GPUdi() bool TrackParametrizationWithError<value_T>::update(const dim2_t& p, const dim3_t& cov) +{ + return update(p.data(), cov.data()); +} + //__________________________________________________________________________ template <typename value_T> template <typename T> -bool TrackParametrizationWithError<value_T>::update(const BaseCluster<T>& p) +GPUdi() bool TrackParametrizationWithError<value_T>::update(const BaseCluster<T>& p) { const dim2_t pyz = {p.getY(), p.getZ()}; const dim3_t cov = {p.getSigmaY2(), p.getSigmaYZ(), p.getSigmaZ2()}; @@ -281,23 +323,43 @@ bool TrackParametrizationWithError<value_T>::update(const BaseCluster<T>& p) //__________________________________________________________________________ template <typename value_T> -inline void TrackParametrizationWithError<value_T>::setCov(value_t v, int i) +GPUdi() void TrackParametrizationWithError<value_T>::setCov(value_t v, int i) { mC[i] = v; } //__________________________________________________________________________ template <typename value_T> -inline void TrackParametrizationWithError<value_T>::updateCov(value_t delta, int i) +GPUdi() void TrackParametrizationWithError<value_T>::setCov(value_t v, size_t i, size_t j) +{ + mC[CovarMap[i][j]] = v; +} + +template <typename value_T> +GPUdi() void TrackParametrizationWithError<value_T>::setCov(const covMat_t& cov) +{ + mC = cov; +} + +//__________________________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrizationWithError<value_T>::updateCov(value_t delta, size_t i, size_t j) +{ + mC[CovarMap[i][j]] += delta; +} + +//__________________________________________________________________________ +template <typename value_T> +GPUdi() void TrackParametrizationWithError<value_T>::updateCov(value_t delta, size_t i) { mC[i] += delta; } //__________________________________________________________________________ template <typename value_T> -inline void TrackParametrizationWithError<value_T>::updateCov(const value_t delta[kCovMatSize]) +GPUdi() void TrackParametrizationWithError<value_T>::updateCov(const covMat_t& delta) { - for (int i = kCovMatSize; i--;) { + for (size_t i = 0; i < kCovMatSize; ++i) { mC[i] += delta[i]; } } diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCITS.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCITS.h index 30987b522df97..5ef3fdc4ba5a7 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCITS.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackLTIntegral.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "CommonDataFormat/TimeStamp.h" namespace o2 @@ -29,49 +31,49 @@ class TrackTPCITS : public o2::track::TrackParCov using timeEst = o2::dataformats::TimeStampWithError<float, float>; public: - TrackTPCITS() = default; - ~TrackTPCITS() = default; - TrackTPCITS(const TrackTPCITS& src) = default; - TrackTPCITS(const o2::track::TrackParCov& src) : o2::track::TrackParCov(src) {} - TrackTPCITS(const o2::track::TrackParCov& srcIn, const o2::track::TrackParCov& srcOut) : o2::track::TrackParCov(srcIn), mParamOut(srcOut) {} + GPUdDefault() TrackTPCITS() = default; + GPUdDefault() ~TrackTPCITS() = default; + GPUdDefault() TrackTPCITS(const TrackTPCITS& src) = default; + GPUd() TrackTPCITS(const o2::track::TrackParCov& src) : o2::track::TrackParCov(src) {} + GPUd() TrackTPCITS(const o2::track::TrackParCov& srcIn, const o2::track::TrackParCov& srcOut) : o2::track::TrackParCov(srcIn), mParamOut(srcOut) {} - int getRefTPC() const { return mRefTPC; } - int getRefITS() const { return mRefITS; } - void setRefTPC(int id) { mRefTPC = id; } - void setRefITS(int id) { mRefITS = id; } + GPUd() GlobalTrackID getRefTPC() const { return mRefTPC; } + GPUd() GlobalTrackID getRefITS() const { return mRefITS; } + GPUd() void setRefTPC(GlobalTrackID id) { mRefTPC = id; } + GPUd() void setRefITS(GlobalTrackID id) { mRefITS = id; } - const timeEst& getTimeMUS() const { return mTimeMUS; } - timeEst& getTimeMUS() { return mTimeMUS; } - void setTimeMUS(const timeEst& t) { mTimeMUS = t; } - void setTimeMUS(float t, float te) + GPUd() const timeEst& getTimeMUS() const { return mTimeMUS; } + GPUd() timeEst& getTimeMUS() { return mTimeMUS; } + GPUd() void setTimeMUS(const timeEst& t) { mTimeMUS = t; } + GPUd() void setTimeMUS(float t, float te) { mTimeMUS.setTimeStamp(t); mTimeMUS.setTimeStampError(te); } - void setChi2Refit(float v) { mChi2Refit = v; } - float getChi2Refit() const { return mChi2Refit; } + GPUd() void setChi2Refit(float v) { mChi2Refit = v; } + GPUd() float getChi2Refit() const { return mChi2Refit; } - void setChi2Match(float v) { mChi2Match = v; } - float getChi2Match() const { return mChi2Match; } + GPUd() void setChi2Match(float v) { mChi2Match = v; } + GPUd() float getChi2Match() const { return mChi2Match; } - o2::track::TrackParCov& getParamOut() { return mParamOut; } - const o2::track::TrackParCov& getParamOut() const { return mParamOut; } + GPUd() o2::track::TrackParCov& getParamOut() { return mParamOut; } + GPUd() const o2::track::TrackParCov& getParamOut() const { return mParamOut; } - o2::track::TrackLTIntegral& getLTIntegralOut() { return mLTOut; } - const o2::track::TrackLTIntegral& getLTIntegralOut() const { return mLTOut; } + GPUd() o2::track::TrackLTIntegral& getLTIntegralOut() { return mLTOut; } + GPUd() const o2::track::TrackLTIntegral& getLTIntegralOut() const { return mLTOut; } void print() const; private: - int mRefTPC = -1; ///< reference on ITS track entry in its original container - int mRefITS = -1; ///< reference on TPC track entry in its original container + GlobalTrackID mRefTPC; ///< reference on ITS track entry in its original container + GlobalTrackID mRefITS; ///< reference on TPC track entry in its original container float mChi2Refit = 0.f; ///< chi2 of the refit float mChi2Match = 0.f; ///< chi2 of the match timeEst mTimeMUS; ///< time estimate in ns o2::track::TrackParCov mParamOut; ///< refitted outer parameter o2::track::TrackLTIntegral mLTOut; ///< L,TOF integral calculated during the outward refit - ClassDefNV(TrackTPCITS, 2); + ClassDefNV(TrackTPCITS, 3); }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCTOF.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCTOF.h new file mode 100644 index 0000000000000..aff55ce50ee14 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCTOF.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackTPCTOF.h +/// \brief Result of refitting TPC with TOF match constraint +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_TRACKTPCTOF_H +#define ALICEO2_TRACKTPCTOF_H + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackLTIntegral.h" +#include "CommonDataFormat/TimeStamp.h" + +namespace o2 +{ +namespace dataformats +{ + +class TrackTPCTOF : public o2::track::TrackParCov +{ + using timeEst = o2::dataformats::TimeStampWithError<float, float>; + + public: + TrackTPCTOF() = default; + ~TrackTPCTOF() = default; + TrackTPCTOF(const TrackTPCTOF& src) = default; + TrackTPCTOF(const o2::track::TrackParCov& src) : o2::track::TrackParCov(src) {} + + int getRefMatch() const { return mRefMatch; } + void setRefMatch(int id) { mRefMatch = id; } + + const timeEst& getTimeMUS() const { return mTimeMUS; } + timeEst& getTimeMUS() { return mTimeMUS; } + void setTimeMUS(const timeEst& t) { mTimeMUS = t; } + void setTimeMUS(float t, float te) + { + mTimeMUS.setTimeStamp(t); + mTimeMUS.setTimeStampError(te); + } + + void setChi2Refit(float v) { mChi2Refit = v; } + float getChi2Refit() const { return mChi2Refit; } + + o2::track::TrackParCov& getParamOut() { return mParamOut; } + const o2::track::TrackParCov& getParamOut() const { return mParamOut; } + void setParamOut(const o2::track::TrackParCov& v) { mParamOut = v; } + + void print() const; + + private: + o2::track::TrackParCov mParamOut; // outward fit (in TPC at the moment) + int mRefMatch = -1; ///< reference on track-TOF match in its original container + float mChi2Refit = 0.f; ///< chi2 of the refit + timeEst mTimeMUS; ///< time estimate in ns + + ClassDefNV(TrackTPCTOF, 2); +}; +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h index 1ff1f87489aac..8e8dd9033bdf8 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,9 +18,9 @@ #define INCLUDE_RECONSTRUCTIONDATAFORMATS_TRACKUTILS_H_ #include "GPUCommonRtypes.h" +#include "GPUCommonArray.h" -#ifndef __OPENCL__ -#include <array> +#ifndef GPUCA_GPUCODE_DEVICE #include <cmath> #endif @@ -32,14 +33,14 @@ namespace track { // helper function template <typename value_T = float> -value_T BetheBlochSolid(value_T bg, value_T rho = 2.33, value_T kp1 = 0.20, value_T kp2 = 3.00, value_T meanI = 173e-9, - value_T meanZA = 0.49848); +GPUd() value_T BetheBlochSolid(value_T bg, value_T rho = 2.33, value_T kp1 = 0.20, value_T kp2 = 3.00, value_T meanI = 173e-9, + value_T meanZA = 0.49848); template <typename value_T = float> -void g3helx3(value_T qfield, value_T step, std::array<value_T, 7>& vect); +GPUd() void g3helx3(value_T qfield, value_T step, gpu::gpustd::array<value_T, 7>& vect); //____________________________________________________ template <typename value_T> -void g3helx3(value_T qfield, value_T step, std::array<value_T, 7>& vect) +GPUd() void g3helx3(value_T qfield, value_T step, gpu::gpustd::array<value_T, 7>& vect) { /****************************************************************** * * @@ -58,8 +59,9 @@ void g3helx3(value_T qfield, value_T step, std::array<value_T, 7>& vect) * vect[7](cm,GeV/c) - input/output x, y, z, px/p, py/p ,pz/p, p * * * ******************************************************************/ - +#ifndef GPUCA_GPUCODE_DEVICE static_assert(std::is_floating_point_v<value_T>); +#endif const int ix = 0, iy = 1, iz = 2, ipx = 3, ipy = 4, ipz = 5, ipp = 6; constexpr value_T kOvSqSix = 0.408248f; // std::sqrt(1./6.); @@ -70,11 +72,11 @@ void g3helx3(value_T qfield, value_T step, std::array<value_T, 7>& vect) value_T tet = rho * step; value_T tsint, sintt, sint, cos1t; - if (std::fabs(tet) > 0.03f) { - sint = std::sin(tet); + if (gpu::CAMath::Abs(tet) > 0.03f) { + sint = gpu::CAMath::Sin(tet); sintt = sint / tet; tsint = (tet - sint) / tet; - value_T t = std::sin(0.5f * tet); + value_T t = gpu::CAMath::Sin(0.5f * tet); cos1t = 2 * t * t / tet; } else { tsint = tet * tet / 6.f; @@ -99,8 +101,8 @@ void g3helx3(value_T qfield, value_T step, std::array<value_T, 7>& vect) //____________________________________________________ template <typename value_T> -value_T BetheBlochSolid(value_T bg, value_T rho, value_T kp1, value_T kp2, value_T meanI, - value_T meanZA) +GPUd() value_T BetheBlochSolid(value_T bg, value_T rho, value_T kp1, value_T kp2, value_T meanI, + value_T meanZA) { // // This is the parameterization of the Bethe-Bloch formula inspired by Geant. @@ -115,7 +117,9 @@ value_T BetheBlochSolid(value_T bg, value_T rho, value_T kp1, value_T kp2, value // The default values for the kp* parameters are for silicon. // The returned value is in [GeV/(g/cm^2)]. // +#ifndef GPUCA_GPUCODE_DEVICE static_assert(std::is_floating_point_v<value_T>); +#endif constexpr value_T mK = 0.307075e-3f; // [GeV*cm^2/g] constexpr value_T me = 0.511e-3f; // [GeV/c^2] @@ -126,15 +130,15 @@ value_T BetheBlochSolid(value_T bg, value_T rho, value_T kp1, value_T kp2, value //*** Density effect value_T d2 = 0.; - const value_T x = std::log(bg); - const value_T lhwI = std::log(28.816f * 1e-9f * std::sqrt(rho * meanZA) / meanI); + const value_T x = gpu::CAMath::Log(bg); + const value_T lhwI = gpu::CAMath::Log(28.816f * 1e-9f * gpu::CAMath::Sqrt(rho * meanZA) / meanI); if (x > kp2) { d2 = lhwI + x - 0.5f; } else if (x > kp1) { double r = (kp2 - x) / (kp2 - kp1); d2 = lhwI + x - 0.5f + (0.5f - lhwI - kp1) * r * r * r; } - return mK * meanZA * (1 + bg2) / bg2 * (0.5f * std::log(2 * me * bg2 * maxT / (meanI * meanI)) - bg2 / (1 + bg2) - d2); + return mK * meanZA * (1 + bg2) / bg2 * (0.5f * gpu::CAMath::Log(2 * me * bg2 * maxT / (meanI * meanI)) - bg2 / (1 + bg2) - d2); } } // namespace track diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/V0.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/V0.h index 3c8055dc33219..53bb357a1df4e 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/V0.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/V0.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,9 +31,9 @@ class V0 : public o2::track::TrackParCov using PID = o2::track::PID; V0() = default; - V0(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, + V0(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, const std::array<float, 6>& covxyz, const o2::track::TrackParCov& trPos, const o2::track::TrackParCov& trNeg, - GIndex trPosID, GIndex trNegID); + GIndex trPosID, GIndex trNegID, o2::track::PID pid = o2::track::PID::K0); GIndex getProngID(int i) const { return mProngIDs[i]; } void setProngID(int i, GIndex gid) { mProngIDs[i] = gid; } @@ -50,18 +51,12 @@ class V0 : public o2::track::TrackParCov int getVertexID() const { return mVertexID; } void setVertexID(int id) { mVertexID = id; } - float getMass2() const - { - return calcMass2(mProngs[0].getPID(), mProngs[1].getPID()); - } - - float calcMass2(PID pidPos, PID pidNeg) const - { - return calcMass2(PID::getMass2(pidPos), PID::getMass2(pidNeg)); - } - + float calcMass2() const { return calcMass2(mProngs[0].getPID(), mProngs[1].getPID()); } + float calcMass2(PID pidPos, PID pidNeg) const { return calcMass2(PID::getMass2(pidPos), PID::getMass2(pidNeg)); } float calcMass2(float massPos2, float massNeg2) const; + float calcR2() const { return getX() * getX() + getY() * getY(); } + protected: std::array<GIndex, 2> mProngIDs; // global IDs of prongs std::array<Track, 2> mProngs; // prongs kinematics at vertex diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h index 7abcae8423447..efc09205d7f17 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,12 +12,13 @@ #ifndef ALICEO2_VERTEX_H #define ALICEO2_VERTEX_H +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "GPUCommonArray.h" #include <MathUtils/Cartesian.h> + #include "CommonDataFormat/TimeStamp.h" -#ifndef __OPENCL__ -#include <array> -#endif -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE #include <iosfwd> #endif @@ -36,51 +38,51 @@ class VertexBase kCovYZ, kCovZZ }; static constexpr int kNCov = 6; - VertexBase() = default; - ~VertexBase() = default; - VertexBase(const math_utils::Point3D<float>& pos, const std::array<float, kNCov>& cov) : mPos(pos), mCov(cov) + GPUdDefault() VertexBase() = default; + GPUdDefault() ~VertexBase() = default; + GPUd() VertexBase(const math_utils::Point3D<float>& pos, const gpu::gpustd::array<float, kNCov>& cov) : mPos(pos), mCov(cov) { } -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE void print() const; std::string asString() const; #endif // getting the cartesian coordinates and errors - float getX() const { return mPos.X(); } - float getY() const { return mPos.Y(); } - float getZ() const { return mPos.Z(); } - float getSigmaX2() const { return mCov[kCovXX]; } - float getSigmaY2() const { return mCov[kCovYY]; } - float getSigmaZ2() const { return mCov[kCovZZ]; } - float getSigmaXY() const { return mCov[kCovXY]; } - float getSigmaXZ() const { return mCov[kCovXZ]; } - float getSigmaYZ() const { return mCov[kCovYZ]; } - const std::array<float, kNCov>& getCov() const { return mCov; } - - math_utils::Point3D<float> getXYZ() const { return mPos; } - math_utils::Point3D<float>& getXYZ() { return mPos; } - - void setX(float x) { mPos.SetX(x); } - void setY(float y) { mPos.SetY(y); } - void setZ(float z) { mPos.SetZ(z); } - - void setXYZ(float x, float y, float z) + GPUd() float getX() const { return mPos.X(); } + GPUd() float getY() const { return mPos.Y(); } + GPUd() float getZ() const { return mPos.Z(); } + GPUd() float getSigmaX2() const { return mCov[kCovXX]; } + GPUd() float getSigmaY2() const { return mCov[kCovYY]; } + GPUd() float getSigmaZ2() const { return mCov[kCovZZ]; } + GPUd() float getSigmaXY() const { return mCov[kCovXY]; } + GPUd() float getSigmaXZ() const { return mCov[kCovXZ]; } + GPUd() float getSigmaYZ() const { return mCov[kCovYZ]; } + GPUd() const gpu::gpustd::array<float, kNCov>& getCov() const { return mCov; } + + GPUd() math_utils::Point3D<float> getXYZ() const { return mPos; } + GPUd() math_utils::Point3D<float>& getXYZ() { return mPos; } + + GPUd() void setX(float x) { mPos.SetX(x); } + GPUd() void setY(float y) { mPos.SetY(y); } + GPUd() void setZ(float z) { mPos.SetZ(z); } + + GPUd() void setXYZ(float x, float y, float z) { setX(x); setY(y); setZ(z); } - void setPos(const math_utils::Point3D<float>& p) { mPos = p; } - - void setSigmaX2(float v) { mCov[kCovXX] = v; } - void setSigmaY2(float v) { mCov[kCovYY] = v; } - void setSigmaZ2(float v) { mCov[kCovZZ] = v; } - void setSigmaXY(float v) { mCov[kCovXY] = v; } - void setSigmaXZ(float v) { mCov[kCovXZ] = v; } - void setSigmaYZ(float v) { mCov[kCovYZ] = v; } - void setCov(float sxx, float sxy, float syy, float sxz, float syz, float szz) + GPUd() void setPos(const math_utils::Point3D<float>& p) { mPos = p; } + + GPUd() void setSigmaX2(float v) { mCov[kCovXX] = v; } + GPUd() void setSigmaY2(float v) { mCov[kCovYY] = v; } + GPUd() void setSigmaZ2(float v) { mCov[kCovZZ] = v; } + GPUd() void setSigmaXY(float v) { mCov[kCovXY] = v; } + GPUd() void setSigmaXZ(float v) { mCov[kCovXZ] = v; } + GPUd() void setSigmaYZ(float v) { mCov[kCovYZ] = v; } + GPUd() void setCov(float sxx, float sxy, float syy, float sxz, float syz, float szz) { setSigmaX2(sxx); setSigmaY2(syy); @@ -89,11 +91,11 @@ class VertexBase setSigmaXZ(sxz); setSigmaYZ(syz); } - void setCov(const std::array<float, kNCov>& cov) { mCov = cov; } + GPUd() void setCov(const gpu::gpustd::array<float, kNCov>& cov) { mCov = cov; } protected: math_utils::Point3D<float> mPos{0., 0., 0.}; ///< cartesian position - std::array<float, kNCov> mCov{}; ///< errors, see CovElems enum + gpu::gpustd::array<float, kNCov> mCov{}; ///< errors, see CovElems enum ClassDefNV(VertexBase, 1); }; @@ -112,28 +114,28 @@ class Vertex : public VertexBase FlagsMask = 0xffff }; - Vertex() = default; - ~Vertex() = default; - Vertex(const math_utils::Point3D<float>& pos, const std::array<float, kNCov>& cov, ushort nCont, float chi2) + GPUdDefault() Vertex() = default; + GPUdDefault() ~Vertex() = default; + GPUd() Vertex(const math_utils::Point3D<float>& pos, const gpu::gpustd::array<float, kNCov>& cov, ushort nCont, float chi2) : VertexBase(pos, cov), mNContributors(nCont), mChi2(chi2) { } - ushort getNContributors() const { return mNContributors; } - void setNContributors(ushort v) { mNContributors = v; } - void addContributor() { mNContributors++; } + GPUd() ushort getNContributors() const { return mNContributors; } + GPUd() void setNContributors(ushort v) { mNContributors = v; } + GPUd() void addContributor() { mNContributors++; } - ushort getFlags() const { return mBits; } - bool isFlagSet(uint f) const { return mBits & (FlagsMask & f); } - void setFlags(ushort f) { mBits |= FlagsMask & f; } - void resetFrags(ushort f = FlagsMask) { mBits &= ~(FlagsMask & f); } + GPUd() ushort getFlags() const { return mBits; } + GPUd() bool isFlagSet(uint f) const { return mBits & (FlagsMask & f); } + GPUd() void setFlags(ushort f) { mBits |= FlagsMask & f; } + GPUd() void resetFrags(ushort f = FlagsMask) { mBits &= ~(FlagsMask & f); } - void setChi2(float v) { mChi2 = v; } - float getChi2() const { return mChi2; } + GPUd() void setChi2(float v) { mChi2 = v; } + GPUd() float getChi2() const { return mChi2; } - const Stamp& getTimeStamp() const { return mTimeStamp; } - Stamp& getTimeStamp() { return mTimeStamp; } - void setTimeStamp(const Stamp& v) { mTimeStamp = v; } + GPUd() const Stamp& getTimeStamp() const { return mTimeStamp; } + GPUd() Stamp& getTimeStamp() { return mTimeStamp; } + GPUd() void setTimeStamp(const Stamp& v) { mTimeStamp = v; } protected: float mChi2 = 0; ///< chi2 or quality of tracks to vertex attachment @@ -144,7 +146,7 @@ class Vertex : public VertexBase ClassDefNV(Vertex, 3); }; -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const o2::dataformats::VertexBase& v); #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h index 44b6ff228ba33..38b4a9ee8a408 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h @@ -1,21 +1,22 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// @file VtxTrackIndex.h -/// \brief Index of track attached to vertx: index in its proper container, container source and flags +/// \brief Extention of GlobalTrackID by flags relevant for verter-track association /// \author ruben.shahoyan@cern.ch #ifndef O2_VERTEX_TRACK_INDEX #define O2_VERTEX_TRACK_INDEX -#include "CommonDataFormat/AbstractRef.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include <iosfwd> #include <string> #include <array> @@ -26,34 +27,18 @@ namespace o2 namespace dataformats { -class VtxTrackIndex : public AbstractRef<26, 3, 3> +class VtxTrackIndex : public GlobalTrackID { public: - enum Source : uint8_t { // provenance of the track - TPCITS, - ITS, - TPC, - NSources - }; - static constexpr std::array<std::string_view, NSources> SourceNames = { - "TPCITS", - "ITS", - "TPC"}; - enum Flags : uint8_t { Contributor, // flag that it contributes to vertex fit - Reserved, // Ambiguous, // flag that attachment is ambiguous NFlags }; - using AbstractRef<26, 3, 3>::AbstractRef; - - static constexpr std::string_view getSourceName(int i) { return SourceNames[i]; } - void print() const; - std::string asString() const; - - operator auto() const { return AbstractRef<26, 3, 3>(); } + using GlobalTrackID::GlobalTrackID; + VtxTrackIndex() = default; + VtxTrackIndex(const GlobalTrackID& src) : GlobalTrackID(src) {} bool isPVContributor() const { return testBit(Contributor); } void setPVContributor() { setBit(Contributor); } @@ -61,12 +46,24 @@ class VtxTrackIndex : public AbstractRef<26, 3, 3> bool isAmbiguous() const { return testBit(Ambiguous); } void setAmbiguous() { setBit(Ambiguous); } - ClassDefNV(VtxTrackIndex, 1); + ClassDefNV(VtxTrackIndex, 2); }; -std::ostream& operator<<(std::ostream& os, const o2::dataformats::VtxTrackIndex& v); - } // namespace dataformats } // namespace o2 +namespace std +{ +// defining std::hash for VtxTrackIndex to be used with std containers +template <> +struct hash<o2::dataformats::VtxTrackIndex> { + public: + size_t operator()(const o2::dataformats::VtxTrackIndex& id) const + { + return std::hash<o2::dataformats::GlobalTrackID>{}(id); + //return id.getRawWOFlags(); + } +}; +} // namespace std + #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackRef.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackRef.h index fda790cd72108..5cdc9aafefb66 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackRef.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackRef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,19 +28,28 @@ namespace o2 namespace dataformats { +/* Class to refer in start and number of contributors in the container of with consecutively filled conributors. + The contributors are suppossed to be sorted according to their sources. + Note: the only way to fill the references is to fill them all in increasing order and set the end! + VtxTrackIndex ref; + for (int i=0;i<VtxTrackIndex::Source::NSources;i++) { + ref.setFirstEntryOfSource(i, idxI); // idxI must be >= idxI-1 (if it is =, then source i has not entries + } + ref.setEnd(idxLast + 1); // i.e. idxLast+1 = idx0 + TotalNumberOfEntries + */ + class VtxTrackRef : public RangeReference<int, int> { public: - VtxTrackRef(int ent, int n) : RangeReference(ent, n) + VtxTrackRef() : RangeReference(-1, 0) { - auto end = ent + n; for (int i = VtxTrackIndex::Source::NSources - 1; i--;) { - mFirstEntrySource[i] = end; // only 1st source (base reference) is filled at constructor level + mFirstEntrySource[i] = -1; // only 1st source (base reference) is filled at constructor level } } - using RangeReference<int, int>::RangeReference; - void print() const; - std::string asString() const; + + void print(bool skipEmpty = true) const; + std::string asString(bool skipEmpty = true) const; // get 1st of entry of indices for given source int getFirstEntryOfSource(int s) const @@ -64,10 +74,18 @@ class VtxTrackRef : public RangeReference<int, int> } } + void setVtxID(int i) { mVtxID = i; } + int getVtxID() const { return mVtxID; } + + // set the last +1 element index and finalize all references + void setEnd(int end); + private: + using RangeReference<int, int>::RangeReference; + int mVtxID = -1; // vertex ID. The reference for unassigned tracks will have it negative! std::array<int, VtxTrackIndex::Source::NSources - 1> mFirstEntrySource{0}; - ClassDefNV(VtxTrackRef, 1); + ClassDefNV(VtxTrackRef, 2); }; std::ostream& operator<<(std::ostream& os, const o2::dataformats::VtxTrackRef& v); diff --git a/DataFormats/Reconstruction/src/BaseCluster.cxx b/DataFormats/Reconstruction/src/BaseCluster.cxx index 91898ad762d57..4b19fe146e674 100644 --- a/DataFormats/Reconstruction/src/BaseCluster.cxx +++ b/DataFormats/Reconstruction/src/BaseCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/Reconstruction/src/Cascade.cxx b/DataFormats/Reconstruction/src/Cascade.cxx new file mode 100644 index 0000000000000..dbc2c4cbae011 --- /dev/null +++ b/DataFormats/Reconstruction/src/Cascade.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ReconstructionDataFormats/Cascade.h" + +using namespace o2::dataformats; + +Cascade::Cascade(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, const std::array<float, 6>& covxyz, + const o2::track::TrackParCov& v0, const o2::track::TrackParCov& bachelor, + int v0ID, GIndex bachelorID, o2::track::PID pid) +{ + std::array<float, 21> covV{}, covB{}; + v0.getCovXYZPxPyPzGlo(covV); + bachelor.getCovXYZPxPyPzGlo(covB); + for (int i = 0; i < 21; i++) { + covV[i] += covB[i]; + } + for (int i = 0; i < 6; i++) { + covV[i] = covxyz[i]; + } + this->set(xyz, pxyz, covV, v0.getCharge() + bachelor.getCharge(), true, pid); + setV0ID(v0ID); + setBachelorID(bachelorID); + setV0Track(v0); + setBachelorTrack(bachelor); +} diff --git a/DataFormats/Reconstruction/src/DCA.cxx b/DataFormats/Reconstruction/src/DCA.cxx index 925948b2bc127..9bb324c8df3a9 100644 --- a/DataFormats/Reconstruction/src/DCA.cxx +++ b/DataFormats/Reconstruction/src/DCA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ namespace o2 namespace dataformats { -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const o2::dataformats::DCA& d) { // stream itself @@ -30,7 +31,7 @@ std::ostream& operator<<(std::ostream& os, const o2::dataformats::DCA& d) void DCA::print() const { -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::cout << *this << '\n'; #endif } diff --git a/DataFormats/Reconstruction/src/GlobalTrackID.cxx b/DataFormats/Reconstruction/src/GlobalTrackID.cxx new file mode 100644 index 0000000000000..6b00c5b4534f6 --- /dev/null +++ b/DataFormats/Reconstruction/src/GlobalTrackID.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalTrackID.cxx +/// \brief Global index for barrel track: provides provenance (detectors combination), index in respective array and some number of bits +/// \author ruben.shahoyan@cern.ch + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Logger.h" +#include <fmt/printf.h> +#include <iostream> +#include <bitset> + +using namespace o2::dataformats; +using DetID = o2::detectors::DetID; + +std::string GlobalTrackID::asString() const +{ + std::bitset<NBitsFlags()> bits{getFlags()}; + return fmt::format("[{:s}/{:d}/{:s}]", getSourceName(), getIndex(), bits.to_string()); +} + +GlobalTrackID::mask_t GlobalTrackID::getSourcesMask(const std::string_view srcList) +{ + mask_t mask; + std::string ss(srcList), sname{}; + if (ss.find(NONE) != std::string::npos) { + return mask; + } + if (ss.find(ALL) != std::string::npos) { + mask = MASK_ALL; + return mask; + } + std::replace(ss.begin(), ss.end(), ' ', ','); + std::stringstream sss(ss); + while (getline(sss, sname, ',')) { + for (auto id = 0; id < NSources; id++) { + if (sname == getSourceName(id)) { + mask.set(id); + sname = ""; + break; + } + } + if (!sname.empty()) { + throw std::runtime_error(fmt::format("Wrong entry {:s} in reco-sources list {:s}", sname, srcList)); + } + } + return mask; +} + +std::ostream& o2::dataformats::operator<<(std::ostream& os, const o2::dataformats::GlobalTrackID& v) +{ + // stream itself + os << v.asString(); + return os; +} + +void GlobalTrackID::print() const +{ + LOG(INFO) << asString(); +} + +std::string GlobalTrackID::getSourcesNames(GlobalTrackID::mask_t srcm) +{ + std::string s = "["; + for (int i = 0; i < NSources; i++) { + if (srcm[i]) { + if (s.size() > 1) { + s += ','; + } + s += getSourceName(i); + } + } + s += ']'; + return std::move(s); +} diff --git a/DataFormats/Reconstruction/src/MatchInfoTOF.cxx b/DataFormats/Reconstruction/src/MatchInfoTOF.cxx index 71a25634b4689..7fe3bb14315fa 100644 --- a/DataFormats/Reconstruction/src/MatchInfoTOF.cxx +++ b/DataFormats/Reconstruction/src/MatchInfoTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,3 +17,10 @@ using namespace o2::dataformats; ClassImp(o2::dataformats::MatchInfoTOF); + +void MatchInfoTOF::print() const +{ + printf("Match of GlobalID %s and TOF cl %d with chi2 = %.3f\n", getTrackRef().asString().c_str(), + getTOFClIndex(), mChi2); + mIntLT.print(); +} diff --git a/DataFormats/Reconstruction/src/MatchInfoTOFReco.cxx b/DataFormats/Reconstruction/src/MatchInfoTOFReco.cxx new file mode 100644 index 0000000000000..b8de445df5234 --- /dev/null +++ b/DataFormats/Reconstruction/src/MatchInfoTOFReco.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MatchInfoTOFReco.cxx +/// \brief Class to temporary store the output of the matching to TOF in reconstruction + +#include "ReconstructionDataFormats/MatchInfoTOFReco.h" + +using namespace o2::dataformats; + +ClassImp(o2::dataformats::MatchInfoTOFReco); diff --git a/DataFormats/Reconstruction/src/PID.cxx b/DataFormats/Reconstruction/src/PID.cxx index 6b3986de9c7ab..2e6f7b7fc7483 100644 --- a/DataFormats/Reconstruction/src/PID.cxx +++ b/DataFormats/Reconstruction/src/PID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,11 +19,6 @@ using namespace o2::track; -constexpr const char* PID::sNames[NIDsTot + 1]; -constexpr const float PID::sMasses[NIDsTot]; -constexpr const float PID::sMasses2Z[NIDsTot]; -constexpr const int PID::sCharges[NIDsTot]; - //_______________________________ PID::PID(const char* name) : mID(nameToID(name, First)) { diff --git a/DataFormats/Reconstruction/src/PrimaryVertex.cxx b/DataFormats/Reconstruction/src/PrimaryVertex.cxx index f94606c2e203a..f1b1a8ff01181 100644 --- a/DataFormats/Reconstruction/src/PrimaryVertex.cxx +++ b/DataFormats/Reconstruction/src/PrimaryVertex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,15 +19,15 @@ namespace o2 namespace dataformats { -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE std::string PrimaryVertex::asString() const { - auto str = o2::utils::concat_string(VertexBase::asString(), - fmt::format("Chi2={:.2f} NCont={:d}: T={:.3f}+-{:.3f} IR=", mChi2, mNContributors, mTimeStamp.getTimeStamp(), mTimeStamp.getTimeStampError()), - mIRMin.asString()); + auto str = o2::utils::Str::concat_string(VertexBase::asString(), + fmt::format("Chi2={:.2f} NCont={:d}: T={:.3f}+-{:.3f} IR=", mChi2, mNContributors, mTimeStamp.getTimeStamp(), mTimeStamp.getTimeStampError()), + mIRMin.asString()); if (!hasUniqueIR()) { - str = o2::utils::concat_string(str, " : ", mIRMax.asString()); + str = o2::utils::Str::concat_string(str, " : ", mIRMax.asString()); } return str; } diff --git a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h index 6cf9150f89429..4ecbc7f702f10 100644 --- a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h +++ b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,9 +15,13 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::track::TrackParF + ; +#pragma link C++ class o2::track::TrackParD + ; #pragma link C++ class o2::track::TrackPar + ; #pragma link C++ class o2::track::TrackParametrization < float> + ; #pragma link C++ class o2::track::TrackParametrization < double> + ; +#pragma link C++ class o2::track::TrackParCovF + ; +#pragma link C++ class o2::track::TrackParCovD + ; #pragma link C++ class o2::track::TrackParCov + ; #pragma link C++ class o2::track::TrackParametrizationWithError < float> + ; #pragma link C++ class o2::track::TrackParametrizationWithError < double> + ; @@ -28,8 +33,23 @@ #pragma link C++ class o2::BaseCluster < float> + ; #pragma link C++ class o2::dataformats::TrackTPCITS + ; #pragma link C++ class std::vector < o2::dataformats::TrackTPCITS> + ; + #pragma link C++ class o2::dataformats::MatchInfoTOF + ; #pragma link C++ class std::vector < o2::dataformats::MatchInfoTOF> + ; +#pragma link C++ class o2::dataformats::MatchInfoTOFReco + ; +#pragma link C++ class std::vector < o2::dataformats::MatchInfoTOFReco> + ; + +#pragma link C++ class o2::dataformats::TrackTPCTOF + ; +#pragma link C++ class std::vector < o2::dataformats::TrackTPCTOF> + ; + +#pragma link C++ class o2::dataformats::TrackCosmics + ; +#pragma link C++ class std::vector < o2::dataformats::TrackCosmics> + ; + +#pragma link C++ class o2::dataformats::TrackMCHMID + ; +#pragma link C++ class std::vector < o2::dataformats::TrackMCHMID> + ; + +#pragma link C++ class o2::dataformats::GlobalFwdTrack + ; +#pragma link C++ class std::vector < o2::dataformats::GlobalFwdTrack> + ; #pragma link C++ class std::vector < std::pair < float, float>> + ; #pragma link C++ class std::vector < std::pair < int, float>> + ; @@ -45,6 +65,10 @@ #pragma link C++ class std::vector < o2::dataformats::Vertex < o2::dataformats::TimeStampWithError < float, float>>> + ; #pragma link C++ class std::vector < o2::dataformats::PrimaryVertex> + ; +#pragma link C++ class o2::dataformats::GlobalTrackID + ; +#pragma link C++ class std::vector < o2::dataformats::GlobalTrackID> + ; +#pragma link C++ class o2::dataformats::EvIndex < int, o2::dataformats::GlobalTrackID> + ; + #pragma link C++ class o2::dataformats::VtxTrackIndex + ; #pragma link C++ class std::vector < o2::dataformats::VtxTrackIndex> + ; @@ -56,4 +80,7 @@ #pragma link C++ class o2::dataformats::V0 + ; #pragma link C++ class std::vector < o2::dataformats::V0> + ; +#pragma link C++ class o2::dataformats::Cascade + ; +#pragma link C++ class std::vector < o2::dataformats::Cascade> + ; + #endif diff --git a/DataFormats/Reconstruction/src/TrackCosmics.cxx b/DataFormats/Reconstruction/src/TrackCosmics.cxx new file mode 100644 index 0000000000000..e360acf53adfd --- /dev/null +++ b/DataFormats/Reconstruction/src/TrackCosmics.cxx @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ReconstructionDataFormats/TrackCosmics.h" + +using namespace o2::dataformats; + +//__________________________________________________ +void TrackCosmics::print() const +{ + printf("Bottom: %s/%d Top: %s/%d Chi2Refit: %6.2f Chi2Match: %6.2f Ncl: %d Time: %10.4f+-%10.4f mus\n", + mRefBottom.getSourceName().data(), mRefBottom.getIndex(), mRefTop.getSourceName().data(), mRefTop.getIndex(), + getChi2Refit(), getChi2Match(), getNClusters(), mTimeMUS.getTimeStamp(), mTimeMUS.getTimeStampError()); + printf("Central param: "); + o2::track::TrackParCov::print(); + printf("Outer param: "); + mParamOut.print(); +} diff --git a/DataFormats/Reconstruction/src/TrackFwd.cxx b/DataFormats/Reconstruction/src/TrackFwd.cxx index c826f73126df1..9d8db3038a232 100644 --- a/DataFormats/Reconstruction/src/TrackFwd.cxx +++ b/DataFormats/Reconstruction/src/TrackFwd.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ namespace track using namespace std; //_________________________________________________________________________ -TrackParCovFwd::TrackParCovFwd(const Double_t z, const SMatrix5 parameters, const SMatrix55 covariances, const Double_t chi2) +TrackParCovFwd::TrackParCovFwd(const Double_t z, const SMatrix5& parameters, const SMatrix55Sym& covariances, const Double_t chi2) { setZ(z); setParameters(parameters); @@ -66,7 +67,7 @@ void TrackParCovFwd::propagateToZlinear(double zEnd) setZ(zEnd); // Calculate Jacobian - SMatrix55 jacob = ROOT::Math::SMatrixIdentity(); + SMatrix55Std jacob = ROOT::Math::SMatrixIdentity(); jacob(0, 2) = -n * sinphi0; jacob(0, 3) = -m * cosphi0; jacob(1, 2) = n * cosphi0; @@ -131,7 +132,7 @@ void TrackParCovFwd::propagateToZquadratic(double zEnd, double zField) mZ = zEnd; // Calculate Jacobian - SMatrix55 jacob = ROOT::Math::SMatrixIdentity(); + SMatrix55Std jacob = ROOT::Math::SMatrixIdentity(); jacob(0, 2) = -n * theta * 0.5 * Hz * cosphi0 - n * sinphi0; jacob(0, 3) = Hz * m * theta * sinphi0 - m * cosphi0; jacob(0, 4) = k * m * 0.5 * Hz * dZ * sinphi0; @@ -226,7 +227,7 @@ void TrackParCovFwd::propagateToZhelix(double zEnd, double zField) mZ = zEnd; // Calculate Jacobian - SMatrix55 jacob = ROOT::Math::SMatrixIdentity(); + SMatrix55Std jacob = ROOT::Math::SMatrixIdentity(); jacob(0, 2) = Hz * X - Hz * XC + YS; jacob(0, 3) = Hz * R * m - S * m; jacob(0, 4) = -Hz * N * R + Hz * T * Y - Hz * V * Y + N * S + U * X; @@ -240,6 +241,55 @@ void TrackParCovFwd::propagateToZhelix(double zEnd, double zField) setCovariances(ROOT::Math::Similarity(jacob, mCovariances)); } +//__________________________________________________________________________ +void TrackParCovFwd::propagateToZ(double zEnd, double zField) +{ + // Extrapolate track parameters and covariances matrix to "zEnd" + // Parameters: helix track model; Error propagation: Quadratic + + auto dZ = (zEnd - getZ()); + auto phi0 = getPhi(); + auto tanl0 = getTanl(); + auto invtanl0 = 1.0 / tanl0; + auto invqpt0 = getInvQPt(); + auto qpt0 = 1.0 / invqpt0; + auto [sinphi0, cosphi0] = o2::math_utils::sincosd(phi0); + auto k = TMath::Abs(o2::constants::math::B2C * zField); + auto invk = 1.0 / k; + auto theta = -invqpt0 * dZ * k * invtanl0; + auto [sintheta, costheta] = o2::math_utils::sincosd(theta); + auto Hz = std::copysign(1, zField); + auto Y = sinphi0 * qpt0 * invk; + auto X = cosphi0 * qpt0 * invk; + auto YC = Y * costheta; + auto YS = Y * sintheta; + auto XC = X * costheta; + auto XS = X * sintheta; + auto n = dZ * invtanl0; + auto m = n * invtanl0; + + // Extrapolate track parameters to "zEnd" + // Helix + mParameters(0) += Hz * (Y - YC) - XS; + mParameters(1) += Hz * (-X + XC) - YS; + mParameters(2) += Hz * theta; + mZ = zEnd; + + // Jacobian (quadratic) + SMatrix55Std jacob = ROOT::Math::SMatrixIdentity(); + jacob(0, 2) = -n * theta * 0.5 * Hz * cosphi0 - n * sinphi0; + jacob(0, 3) = Hz * m * theta * sinphi0 - m * cosphi0; + jacob(0, 4) = k * m * 0.5 * Hz * dZ * sinphi0; + jacob(1, 2) = -n * theta * 0.5 * Hz * sinphi0 + n * cosphi0; + jacob(1, 3) = -Hz * m * theta * cosphi0 - m * sinphi0; + jacob(1, 4) = -k * m * 0.5 * Hz * dZ * cosphi0; + jacob(2, 3) = -Hz * theta * invtanl0; + jacob(2, 4) = -Hz * k * n; + + // Extrapolate track parameter covariances to "zEnd" + setCovariances(ROOT::Math::Similarity(jacob, mCovariances)); +} + //__________________________________________________________________________ bool TrackParCovFwd::update(const std::array<float, 2>& p, const std::array<float, 2>& cov) { @@ -250,9 +300,8 @@ bool TrackParCovFwd::update(const std::array<float, 2>& p, const std::array<floa using SMatrix22 = ROOT::Math::SMatrix<double, 2>; using SMatrix25 = ROOT::Math::SMatrix<double, 2, 5>; using SMatrix52 = ROOT::Math::SMatrix<double, 5, 2>; - using SMatrix55Std = ROOT::Math::SMatrix<double, 5>; - SMatrix55 I = ROOT::Math::SMatrixIdentity(); + SMatrix55Sym I = ROOT::Math::SMatrixIdentity(); SMatrix25 H_k; SMatrix22 V_k; SVector2 m_k(p[0], p[1]), r_k_kminus1; @@ -273,7 +322,37 @@ bool TrackParCovFwd::update(const std::array<float, 2>& p, const std::array<floa mParameters = mParameters + K_k * r_k_kminus1; // Update covariances Matrix - SMatrix55Std updatedCov = (I - K_k * H_k) * mCovariances; + SMatrix55Std updatedCov; + auto& CP = mCovariances; + auto& sigmax2 = cov[0]; + auto& sigmay2 = cov[1]; + auto A = 1. / (sigmax2 * sigmay2 + sigmax2 * CP(1, 1) + sigmay2 * CP(0, 0) + CP(0, 0) * CP(1, 1) - CP(0, 1) * CP(0, 1)); + auto AX = A * sigmax2; + auto AY = A * sigmay2; + auto B = sigmax2 * sigmay2; + auto C = (sigmax2 + CP(0, 0)) * (sigmay2 + CP(1, 1)); + auto D = 1 / (-C + CP(0, 1) * CP(0, 1)); + auto E = sigmax2 + CP(0, 0); + auto F = sigmay2 + CP(1, 1); + auto G = -C + CP(0, 1) * CP(0, 1); + + // Explicit evaluation of "updatedCov = (I - K_k * H_k) * mCovariances" + updatedCov(0, 0) = AX * (sigmay2 * CP(0, 0) + CP(0, 0) * CP(1, 1) - CP(0, 1) * CP(0, 1)); + updatedCov(0, 1) = AX * sigmay2 * CP(0, 1); + updatedCov(0, 2) = AX * (sigmay2 * CP(0, 2) - CP(0, 1) * CP(1, 2) + CP(0, 2) * CP(1, 1)); + updatedCov(0, 3) = AX * (sigmay2 * CP(0, 3) - CP(0, 1) * CP(1, 3) + CP(0, 3) * CP(1, 1)); + updatedCov(0, 4) = AX * (sigmay2 * CP(0, 4) - CP(0, 1) * CP(1, 4) + CP(0, 4) * CP(1, 1)); + updatedCov(1, 1) = AY * (sigmax2 * CP(1, 1) + CP(0, 0) * CP(1, 1) - CP(0, 1) * CP(0, 1)); + updatedCov(1, 2) = AY * (sigmax2 * CP(1, 2) + CP(0, 0) * CP(1, 2) - CP(0, 1) * CP(0, 2)); + updatedCov(1, 3) = AY * (sigmax2 * CP(1, 3) + CP(0, 0) * CP(1, 3) - CP(0, 1) * CP(0, 3)); + updatedCov(1, 4) = AY * (sigmax2 * CP(1, 4) + CP(0, 0) * CP(1, 4) - CP(0, 1) * CP(0, 4)); + updatedCov(2, 2) = D * (G * CP(2, 2) - CP(0, 2) * (-F * CP(0, 2) + CP(0, 1) * CP(1, 2)) - CP(1, 2) * (-E * CP(1, 2) + CP(0, 1) * CP(0, 2))); + updatedCov(2, 3) = D * (G * CP(2, 3) - CP(0, 2) * (-F * CP(0, 3) + CP(0, 1) * CP(1, 3)) - CP(1, 2) * (-E * CP(1, 3) + CP(0, 1) * CP(0, 3))); + updatedCov(2, 4) = D * (G * CP(2, 4) - CP(0, 2) * (-F * CP(0, 4) + CP(0, 1) * CP(1, 4)) - CP(1, 2) * (-E * CP(1, 4) + CP(0, 1) * CP(0, 4))); + updatedCov(3, 3) = D * (G * CP(3, 3) - CP(0, 3) * (-F * CP(0, 3) + CP(0, 1) * CP(1, 3)) - CP(1, 3) * (-E * CP(1, 3) + CP(0, 1) * CP(0, 3))); + updatedCov(3, 4) = D * (G * CP(3, 4) - CP(0, 3) * (-F * CP(0, 4) + CP(0, 1) * CP(1, 4)) - CP(1, 3) * (-E * CP(1, 4) + CP(0, 1) * CP(0, 4))); + updatedCov(4, 4) = D * (G * CP(4, 4) - CP(0, 4) * (-F * CP(0, 4) + CP(0, 1) * CP(1, 4)) - CP(1, 4) * (-E * CP(1, 4) + CP(0, 1) * CP(0, 4))); + mCovariances(0, 0) = updatedCov(0, 0); mCovariances(0, 1) = updatedCov(0, 1); mCovariances(0, 2) = updatedCov(0, 2); @@ -297,14 +376,16 @@ bool TrackParCovFwd::update(const std::array<float, 2>& p, const std::array<floa } //__________________________________________________________________________ -void TrackParCovFwd::addMCSEffect(double dZ, double x_over_X0) +void TrackParCovFwd::addMCSEffect(double x_over_X0) { - /// Add multiple Coulomb scattering effects to the track parameter covariances. - /// * if (dZ > 0): MCS effects are evaluated with a linear propagation model. - /// * if (dZ <= 0): only angular MCS effects are evaluated as if dZ = 0. + /// Add multiple Coulomb scattering effects to the track covariances. + /// Only angular and pt MCS effects are evaluated. /// * x_over_X0 is the fraction of the radiation lenght (x/X0). /// * No energy loss correction. - /// * All scattering evaluated at the position of the first cluster. + + if (x_over_X0 == 0) { // Nothing to do + return; + } auto phi0 = getPhi(); auto tanl0 = getTanl(); @@ -321,64 +402,15 @@ void TrackParCovFwd::addMCSEffect(double dZ, double x_over_X0) sigmathetasq *= sigmathetasq * pathLengthOverX0; // Get covariance matrix - SMatrix55 newParamCov(getCovariances()); - - if (dZ > 0) { - auto A = tanl0 * tanl0 + 1; - auto B = dZ * cosphi0 * invtanl0; - auto C = dZ * sinphi0 * invtanl0; - auto D = A * B * invtanl0; - auto E = -A * C * invtanl0; - auto F = -C - D; - auto G = B + E; - auto H = -invqpt0 * tanl0; - - newParamCov(0, 0) += sigmathetasq * F * F; - - newParamCov(0, 1) += sigmathetasq * F * G; - - newParamCov(1, 1) += sigmathetasq * G * G; + SMatrix55Sym newParamCov(getCovariances()); - newParamCov(2, 0) += sigmathetasq * F; + auto A = tanl0 * tanl0 + 1; - newParamCov(2, 1) += sigmathetasq * G; + newParamCov(2, 2) += sigmathetasq * A; - newParamCov(2, 2) += sigmathetasq; + newParamCov(3, 3) += sigmathetasq * A * A; - newParamCov(3, 0) += sigmathetasq * A * F; - - newParamCov(3, 1) += sigmathetasq * A * G; - - newParamCov(3, 2) += sigmathetasq * A; - - newParamCov(3, 3) += sigmathetasq * A * A; - - newParamCov(4, 0) += sigmathetasq * F * H; - - newParamCov(4, 1) += sigmathetasq * G * H; - - newParamCov(4, 2) += sigmathetasq * H; - - newParamCov(4, 3) += sigmathetasq * A * H; - - newParamCov(4, 4) += sigmathetasq * tanl0 * tanl0 * invqpt0 * invqpt0; - } else { - - auto A = tanl0 * tanl0 + 1; - auto H = -invqpt0 * tanl0; - - newParamCov(2, 2) += sigmathetasq; - - newParamCov(3, 2) += sigmathetasq * A; - - newParamCov(3, 3) += sigmathetasq * A * A; - - newParamCov(4, 2) += sigmathetasq * H; - - newParamCov(4, 3) += sigmathetasq * A * H; - - newParamCov(4, 4) += sigmathetasq * tanl0 * tanl0 * invqpt0 * invqpt0; - } + newParamCov(4, 4) += sigmathetasq * tanl0 * tanl0 * invqpt0 * invqpt0; // Set new covariances setCovariances(newParamCov); diff --git a/DataFormats/Reconstruction/src/TrackLTIntegral.cxx b/DataFormats/Reconstruction/src/TrackLTIntegral.cxx index bbb4461c47a26..52a77ce92a4da 100644 --- a/DataFormats/Reconstruction/src/TrackLTIntegral.cxx +++ b/DataFormats/Reconstruction/src/TrackLTIntegral.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,30 +11,44 @@ #include "ReconstructionDataFormats/TrackLTIntegral.h" #include "CommonConstants/PhysicsConstants.h" -#include <cmath> +#include "MathUtils/Utils.h" -using namespace o2::track; +namespace o2 +{ +namespace track +{ //_____________________________________________________ -void TrackLTIntegral::print() const +GPUd() void TrackLTIntegral::print() const { - printf("L(cm): %6.2f, X2X0: %5.3f TOF(ps): ", getL(), getX2X0()); - for (int i = 0; i < getNTOFs(); i++) { - printf(" %7.1f |", getTOF(i)); +#ifndef GPUCA_GPUCODE_DEVICE + printf("L(cm): %6.2f, X2X0: %e XRho: %e TOF(ps): ", getL(), getX2X0(), getXRho()); + if (isTimeNotNeeded()) { + printf(" Times not filled"); + } else { + for (int i = 0; i < getNTOFs(); i++) { + printf(" %7.1f |", getTOF(i)); + } } printf("\n"); +#endif } //_____________________________________________________ -void TrackLTIntegral::addStep(float dL, const TrackPar& track) +GPUd() void TrackLTIntegral::addStep(float dL, float p2Inv) { ///< add step in cm to integrals mL += dL; - float p2 = track.getP2Inv(); - float dTns = dL * 1000.f / o2::constants::physics::LightSpeedCm2NS; // time change in ps for beta = 1 particle + if (isTimeNotNeeded()) { + return; + } + const float dTns = dL * 1000.f / o2::constants::physics::LightSpeedCm2NS; // time change in ps for beta = 1 particle for (int id = 0; id < getNTOFs(); id++) { - float m2z = o2::track::PID::getMass2Z(id); - float betaInv = std::sqrt(1.f + m2z * m2z * p2); + const float m2z = track::PID::getMass2Z(id); + const float betaInv = math_utils::sqrt(1.f + m2z * m2z * p2Inv); mT[id] += dTns * betaInv; } } + +} // namespace track +} // namespace o2 diff --git a/DataFormats/Reconstruction/src/TrackMCHMID.cxx b/DataFormats/Reconstruction/src/TrackMCHMID.cxx new file mode 100644 index 0000000000000..ab9ed3077e2cf --- /dev/null +++ b/DataFormats/Reconstruction/src/TrackMCHMID.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMCHMID.h +/// \brief Implementation of the MUON track +/// +/// \author Philippe Pillot, Subatech + +#include "ReconstructionDataFormats/TrackMCHMID.h" + +#include <iostream> + +namespace o2 +{ +namespace dataformats +{ + +//__________________________________________________________________________ +/// write the content of the track to the output stream +std::ostream& operator<<(std::ostream& os, const o2::dataformats::TrackMCHMID& track) +{ + os << track.getMCHRef() << " + " << track.getMIDRef() << " = " + << track.getIR() << " matching chi2/NDF: " << track.getMatchChi2OverNDF(); + return os; +} + +//__________________________________________________________________________ +/// write the content of the track to the standard output +void TrackMCHMID::print() const +{ + std::cout << *this << std::endl; +} + +} // namespace dataformats +} // namespace o2 diff --git a/DataFormats/Reconstruction/src/TrackParametrization.cxx b/DataFormats/Reconstruction/src/TrackParametrization.cxx index ae78900a42cb6..93785530b7d5f 100644 --- a/DataFormats/Reconstruction/src/TrackParametrization.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrization.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,11 +14,12 @@ /// @since Oct 1, 2020 /// @brief -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,8 +28,8 @@ #include "ReconstructionDataFormats/TrackParametrization.h" #include "ReconstructionDataFormats/Vertex.h" #include "ReconstructionDataFormats/DCA.h" +#include <MathUtils/Cartesian.h> #include <GPUCommonLogger.h> -#include "Math/SMatrix.h" #ifndef GPUCA_GPUCODE_DEVICE #include <iostream> @@ -37,14 +39,12 @@ #include <fmt/printf.h> #endif -namespace o2 -{ -namespace track -{ +using namespace o2::gpu; +using namespace o2::track; //______________________________________________________________ template <typename value_T> -TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim3_t& pxpypz, int charge, bool sectorAlpha) +GPUd() TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim3_t& pxpypz, int charge, bool sectorAlpha, const PID pid) : mX{0.f}, mAlpha{0.f}, mP{0.f} { // construct track param from kinematics @@ -59,9 +59,9 @@ TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim value_t radPos2 = xyz[0] * xyz[0] + xyz[1] * xyz[1]; value_t alp = 0; if (sectorAlpha || radPos2 < 1) { - alp = std::atan2(pxpypz[1], pxpypz[0]); + alp = math_utils::detail::atan2<value_T>(pxpypz[1], pxpypz[0]); } else { - alp = std::atan2(xyz[1], xyz[0]); + alp = math_utils::detail::atan2<value_T>(xyz[1], xyz[0]); } if (sectorAlpha) { alp = math_utils::detail::angle2Alpha<value_t>(alp); @@ -69,15 +69,25 @@ TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim // value_t sn, cs; math_utils::detail::sincos(alp, sn, cs); + // protection against cosp<0 + if (cs * pxpypz[0] + sn * pxpypz[1] < 0) { + LOG(debug) << "alpha from phiPos() will invalidate this track parameters, overriding to alpha from phi()"; + alp = math_utils::detail::atan2<value_T>(pxpypz[1], pxpypz[0]); + if (sectorAlpha) { + alp = math_utils::detail::angle2Alpha<value_t>(alp); + } + math_utils::detail::sincos(alp, sn, cs); + } + // protection: avoid alpha being too close to 0 or +-pi/2 - if (std::fabs(sn) < 2 * kSafe) { + if (math_utils::detail::abs<value_T>(sn) < 2 * kSafe) { if (alp > 0) { alp += alp < constants::math::PIHalf ? 2 * kSafe : -2 * kSafe; } else { alp += alp > -constants::math::PIHalf ? -2 * kSafe : 2 * kSafe; } math_utils::detail::sincos(alp, sn, cs); - } else if (std::fabs(cs) < 2 * kSafe) { + } else if (math_utils::detail::abs<value_T>(cs) < 2 * kSafe) { if (alp > 0) { alp += alp > constants::math::PIHalf ? 2 * kSafe : -2 * kSafe; } else { @@ -100,12 +110,13 @@ TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim mP[kZ] = ver[2]; mP[kSnp] = mom[1] * ptI; mP[kTgl] = mom[2] * ptI; - mAbsCharge = std::abs(charge); + mAbsCharge = math_utils::detail::abs<value_T>(charge); mP[kQ2Pt] = charge ? ptI * charge : ptI; + mPID = pid; // - if (std::fabs(1 - getSnp()) < kSafe) { + if (math_utils::detail::abs<value_T>(1 - getSnp()) < kSafe) { mP[kSnp] = 1.f - kSafe; // Protection - } else if (std::fabs(-1 - getSnp()) < kSafe) { + } else if (math_utils::detail::abs<value_T>(-1 - getSnp()) < kSafe) { mP[kSnp] = -1.f + kSafe; // Protection } // @@ -113,14 +124,14 @@ TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim //_______________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::getPxPyPzGlo(dim3_t& pxyz) const +GPUd() bool TrackParametrization<value_T>::getPxPyPzGlo(dim3_t& pxyz) const { // track momentum - if (std::fabs(getQ2Pt()) < constants::math::Almost0 || std::fabs(getSnp()) > constants::math::Almost1) { + if (math_utils::detail::abs<value_T>(getQ2Pt()) < constants::math::Almost0 || math_utils::detail::abs<value_T>(getSnp()) > constants::math::Almost1) { return false; } value_t cs, sn, pt = getPt(); - value_t r = std::sqrt((1.f - getSnp()) * (1.f + getSnp())); + value_t r = math_utils::detail::sqrt<value_T>((1.f - getSnp()) * (1.f + getSnp())); math_utils::detail::sincos(getAlpha(), sn, cs); pxyz[0] = pt * (r * cs - getSnp() * sn); pxyz[1] = pt * (getSnp() * cs + r * sn); @@ -130,17 +141,17 @@ bool TrackParametrization<value_T>::getPxPyPzGlo(dim3_t& pxyz) const //____________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::getPosDirGlo(std::array<value_t, 9>& posdirp) const +GPUd() bool TrackParametrization<value_T>::getPosDirGlo(gpu::gpustd::array<value_t, 9>& posdirp) const { // fill vector with lab x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha - value_t ptI = std::fabs(getQ2Pt()); + value_t ptI = math_utils::detail::abs<value_T>(getQ2Pt()); value_t snp = getSnp(); - if (ptI < constants::math::Almost0 || std::fabs(snp) > constants::math::Almost1) { + if (ptI < constants::math::Almost0 || math_utils::detail::abs<value_T>(snp) > constants::math::Almost1) { return false; } value_t &sn = posdirp[7], &cs = posdirp[8]; - value_t csp = std::sqrt((1.f - snp) * (1.f + snp)); - value_t cstht = std::sqrt(1.f + getTgl() * getTgl()); + value_t csp = math_utils::detail::sqrt<value_T>((1.f - snp) * (1.f + snp)); + value_t cstht = math_utils::detail::sqrt<value_T>(1.f + getTgl() * getTgl()); value_t csthti = 1.f / cstht; math_utils::detail::sincos(getAlpha(), sn, cs); posdirp[0] = getX() * cs - getY() * sn; @@ -155,11 +166,11 @@ bool TrackParametrization<value_T>::getPosDirGlo(std::array<value_t, 9>& posdirp //______________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::rotateParam(value_t alpha) +GPUd() bool TrackParametrization<value_T>::rotateParam(value_t alpha) { // rotate to alpha frame - if (std::fabs(getSnp()) > constants::math::Almost1) { - LOGP(WARNING, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", getSnp()); + if (math_utils::detail::abs<value_T>(getSnp()) > constants::math::Almost1) { + LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", getSnp()); return false; } // @@ -167,7 +178,7 @@ bool TrackParametrization<value_T>::rotateParam(value_t alpha) // value_t ca = 0, sa = 0; math_utils::detail::sincos(alpha - getAlpha(), sa, ca); - value_t snp = getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); // Improve precision + value_t snp = getSnp(), csp = math_utils::detail::sqrt<value_T>((1.f - snp) * (1.f + snp)); // Improve precision // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle // direction in local frame is along the X axis if ((csp * ca + snp * sa) < 0) { @@ -176,8 +187,8 @@ bool TrackParametrization<value_T>::rotateParam(value_t alpha) } // value_t tmp = snp * ca - csp * sa; - if (std::fabs(tmp) > constants::math::Almost1) { - LOGP(WARNING, "Rotation failed: new snp {:.2f}", tmp); + if (math_utils::detail::abs<value_T>(tmp) > constants::math::Almost1) { + LOGP(debug, "Rotation failed: new snp {:.2f}", tmp); return false; } value_t xold = getX(), yold = getY(); @@ -190,7 +201,7 @@ bool TrackParametrization<value_T>::rotateParam(value_t alpha) //____________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b) +GPUd() bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b) { //---------------------------------------------------------------- // Extrapolate this track params (w/o cov matrix) to the plane X=xk in the field b[]. @@ -200,61 +211,60 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b //---------------------------------------------------------------- value_t dx = xk - getX(); - if (std::fabs(dx) < constants::math::Almost0) { + if (math_utils::detail::abs<value_T>(dx) < constants::math::Almost0) { return true; } // Do not propagate tracks outside the ALICE detector - if (std::fabs(dx) > 1e5 || std::fabs(getY()) > 1e5 || std::fabs(getZ()) > 1e5) { - LOGP(WARNING, "Anomalous track, target X:{:f}", xk); - // print(); + if (math_utils::detail::abs<value_T>(dx) > 1e5 || math_utils::detail::abs<value_T>(getY()) > 1e5 || math_utils::detail::abs<value_T>(getZ()) > 1e5) { + LOGP(warning, "Anomalous track, target X:{:f}", xk); return false; } value_t crv = getCurvature(b[2]); value_t x2r = crv * dx; value_t f1 = getSnp(), f2 = f1 + x2r; - if (std::fabs(f1) > constants::math::Almost1 || std::fabs(f2) > constants::math::Almost1) { + if (math_utils::detail::abs<value_T>(f1) > constants::math::Almost1 || math_utils::detail::abs<value_T>(f2) > constants::math::Almost1) { return false; } - value_t r1 = std::sqrt((1.f - f1) * (1.f + f1)); - if (std::fabs(r1) < constants::math::Almost0) { + value_t r1 = math_utils::detail::sqrt<value_T>((1.f - f1) * (1.f + f1)); + if (math_utils::detail::abs<value_T>(r1) < constants::math::Almost0) { return false; } - value_t r2 = std::sqrt((1.f - f2) * (1.f + f2)); - if (std::fabs(r2) < constants::math::Almost0) { + value_t r2 = math_utils::detail::sqrt<value_T>((1.f - f2) * (1.f + f2)); + if (math_utils::detail::abs<value_T>(r2) < constants::math::Almost0) { return false; } value_t dy2dx = (f1 + f2) / (r1 + r2); - value_t step = (std::fabs(x2r) < 0.05f) ? dx * std::fabs(r2 + f2 * dy2dx) // chord - : 2.f * asinf(0.5f * dx * std::sqrt(1.f + dy2dx * dy2dx) * crv) / crv; // arc - step *= std::sqrt(1.f + getTgl() * getTgl()); + value_t step = (math_utils::detail::abs<value_T>(x2r) < 0.05f) ? dx * math_utils::detail::abs<value_T>(r2 + f2 * dy2dx) // chord + : 2.f * CAMath::ASin(0.5f * dx * math_utils::detail::sqrt<value_T>(1.f + dy2dx * dy2dx) * crv) / crv; // arc + step *= math_utils::detail::sqrt<value_T>(1.f + getTgl() * getTgl()); // // get the track x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha in the Global System - std::array<value_t, 9> vecLab{0.f}; + gpu::gpustd::array<value_t, 9> vecLab{0.f}; if (!getPosDirGlo(vecLab)) { return false; } // rotate to the system where Bx=By=0. value_t bxy2 = b[0] * b[0] + b[1] * b[1]; - value_t bt = std::sqrt(bxy2); + value_t bt = math_utils::detail::sqrt<value_T>(bxy2); value_t cosphi = 1.f, sinphi = 0.f; if (bt > constants::math::Almost0) { cosphi = b[0] / bt; sinphi = b[1] / bt; } - value_t bb = std::sqrt(bxy2 + b[2] * b[2]); + value_t bb = math_utils::detail::sqrt<value_T>(bxy2 + b[2] * b[2]); value_t costet = 1.f, sintet = 0.f; if (bb > constants::math::Almost0) { costet = b[2] / bb; sintet = bt / bb; } - std::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], - -sinphi * vecLab[0] + cosphi * vecLab[1], - sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2], - costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5], - -sinphi * vecLab[3] + cosphi * vecLab[4], - sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5], - vecLab[6]}; + gpu::gpustd::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], + -sinphi * vecLab[0] + cosphi * vecLab[1], + sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2], + costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5], + -sinphi * vecLab[3] + cosphi * vecLab[4], + sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5], + vecLab[6]}; // Do the helix step value_t q = getCharge(); @@ -280,8 +290,8 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b // Do the final correcting step to the target plane (linear approximation) value_t x = vecLab[0], y = vecLab[1], z = vecLab[2]; - if (std::fabs(dx) > constants::math::Almost0) { - if (std::fabs(vecLab[3]) < constants::math::Almost0) { + if (math_utils::detail::abs<value_T>(dx) > constants::math::Almost0) { + if (math_utils::detail::abs<value_T>(vecLab[3]) < constants::math::Almost0) { return false; } dx = xk - vecLab[0]; @@ -291,8 +301,8 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b } // Calculate the track parameters - t = 1.f / std::sqrt(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]); - mX = x; + t = 1.f / math_utils::detail::sqrt<value_T>(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]); + mX = xk; mP[kY] = y; mP[kZ] = z; mP[kSnp] = vecLab[4] * t; @@ -304,7 +314,7 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b //____________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b) +GPUd() bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b) { //---------------------------------------------------------------- // propagate this track to the plane X=xk (cm) in the field "b" (kG) @@ -312,28 +322,28 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b) // distances only (<mm, i.e. misalignment) //---------------------------------------------------------------- value_t dx = xk - getX(); - if (std::fabs(dx) < constants::math::Almost0) { + if (math_utils::detail::abs<value_T>(dx) < constants::math::Almost0) { return true; } - value_t crv = (std::fabs(b) < constants::math::Almost0) ? 0.f : getCurvature(b); + value_t crv = (math_utils::detail::abs<value_T>(b) < constants::math::Almost0) ? 0.f : getCurvature(b); value_t x2r = crv * dx; value_t f1 = getSnp(), f2 = f1 + x2r; - if ((std::fabs(f1) > constants::math::Almost1) || (std::fabs(f2) > constants::math::Almost1)) { + if ((math_utils::detail::abs<value_T>(f1) > constants::math::Almost1) || (math_utils::detail::abs<value_T>(f2) > constants::math::Almost1)) { return false; } - value_t r1 = std::sqrt((1.f - f1) * (1.f + f1)); - if (std::fabs(r1) < constants::math::Almost0) { + value_t r1 = math_utils::detail::sqrt<value_T>((1.f - f1) * (1.f + f1)); + if (math_utils::detail::abs<value_T>(r1) < constants::math::Almost0) { return false; } - value_t r2 = std::sqrt((1.f - f2) * (1.f + f2)); - if (std::fabs(r2) < constants::math::Almost0) { + value_t r2 = math_utils::detail::sqrt<value_T>((1.f - f2) * (1.f + f2)); + if (math_utils::detail::abs<value_T>(r2) < constants::math::Almost0) { return false; } mX = xk; double dy2dx = (f1 + f2) / (r1 + r2); mP[kY] += dx * dy2dx; mP[kSnp] += x2r; - if (std::fabs(x2r) < 0.05f) { + if (math_utils::detail::abs<value_T>(x2r) < 0.05f) { mP[kZ] += dx * (r2 + f2 * dy2dx) * getTgl(); } else { // for small dx/R the linear apporximation of the arc by the segment is OK, @@ -344,7 +354,7 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b) // double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center // track1 += rot/crv*track3; // - value_t rot = asinf(r1 * f2 - r2 * f1); // more economic version from Yura. + value_t rot = CAMath::ASin(r1 * f2 - r2 * f1); // more economic version from Yura. if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles if (f2 > 0.f) { rot = constants::math::PI - rot; // @@ -359,36 +369,39 @@ bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b) //_______________________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::propagateParamToDCA(const math_utils::Point3D<value_t>& vtx, value_t b, dim2_t* dca, value_t maxD) +GPUd() bool TrackParametrization<value_T>::propagateParamToDCA(const math_utils::Point3D<value_t>& vtx, value_t b, dim2_t* dca, value_t maxD) { // propagate track to DCA to the vertex value_t sn, cs, alp = getAlpha(); math_utils::detail::sincos(alp, sn, cs); - value_t x = getX(), y = getY(), snp = getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); + value_t x = getX(), y = getY(), snp = getSnp(), csp = math_utils::detail::sqrt<value_T>((1.f - snp) * (1.f + snp)); value_t xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_t d = math_utils::detail::abs<value_T>(x * snp - y * csp); if (d > maxD) { return false; } value_t crv = getCurvature(b); value_t tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1.f - sn) * (1.f + sn)); - cs = (std::abs(tgfv) > constants::math::Almost0) ? sn / tgfv : constants::math::Almost1; + sn = tgfv / math_utils::detail::sqrt<value_T>(1.f + tgfv * tgfv); + cs = math_utils::detail::sqrt<value_T>((1.f - sn) * (1.f + sn)); + cs = (math_utils::detail::abs<value_T>(tgfv) > constants::math::Almost0) ? sn / tgfv : constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(*this); // operate on the copy to recover after the failure - alp += std::asin(sn); + alp += math_utils::detail::asin<value_T>(sn); if (!tmpT.rotateParam(alp) || !tmpT.propagateParamTo(xv, b)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " - << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: "; - tmpT.printParam(); +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " + << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z(); +#endif return false; } *this = tmpT; @@ -401,33 +414,34 @@ bool TrackParametrization<value_T>::propagateParamToDCA(const math_utils::Point3 //____________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const +GPUd() bool TrackParametrization<value_T>::getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const { //---------------------------------------------------------------- // estimate Y,Z in tracking frame at given X //---------------------------------------------------------------- value_t dx = xk - getX(); - if (std::fabs(dx) < constants::math::Almost0) { + y = mP[kY]; + z = mP[kZ]; + if (math_utils::detail::abs<value_T>(dx) < constants::math::Almost0) { return true; } value_t crv = getCurvature(b); value_t x2r = crv * dx; value_t f1 = getSnp(), f2 = f1 + x2r; - if ((std::fabs(f1) > constants::math::Almost1) || (std::fabs(f2) > constants::math::Almost1)) { + if ((math_utils::detail::abs<value_T>(f1) > constants::math::Almost1) || (math_utils::detail::abs<value_T>(f2) > constants::math::Almost1)) { return false; } - value_t r1 = std::sqrt((1.f - f1) * (1.f + f1)); - if (std::fabs(r1) < constants::math::Almost0) { + value_t r1 = math_utils::detail::sqrt<value_T>((1.f - f1) * (1.f + f1)); + if (math_utils::detail::abs<value_T>(r1) < constants::math::Almost0) { return false; } - value_t r2 = std::sqrt((1.f - f2) * (1.f + f2)); - if (std::fabs(r2) < constants::math::Almost0) { + value_t r2 = math_utils::detail::sqrt<value_T>((1.f - f2) * (1.f + f2)); + if (math_utils::detail::abs<value_T>(r2) < constants::math::Almost0) { return false; } double dy2dx = (f1 + f2) / (r1 + r2); - y = mP[kY] + dx * dy2dx; - z = mP[kZ]; - if (std::fabs(x2r) < 0.05f) { + y += dx * dy2dx; + if (math_utils::detail::abs<value_T>(x2r) < 0.05f) { z += dx * (r2 + f2 * dy2dx) * getTgl(); } else { // for small dx/R the linear apporximation of the arc by the segment is OK, @@ -438,7 +452,7 @@ bool TrackParametrization<value_T>::getYZAt(value_t xk, value_t b, value_t& y, v // double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center // track1 += rot/crv*track3; // - value_t rot = asinf(r1 * f2 - r2 * f1); // more economic version from Yura. + value_t rot = CAMath::ASin(r1 * f2 - r2 * f1); // more economic version from Yura. if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles if (f2 > 0.f) { rot = constants::math::PI - rot; // @@ -453,7 +467,7 @@ bool TrackParametrization<value_T>::getYZAt(value_t xk, value_t b, value_t& y, v //______________________________________________________________ template <typename value_T> -void TrackParametrization<value_T>::invertParam() +GPUd() void TrackParametrization<value_T>::invertParam() { // Transform this track to the local coord. system rotated by 180 deg. mX = -mX; @@ -468,7 +482,7 @@ void TrackParametrization<value_T>::invertParam() //______________________________________________________________ template <typename value_T> -typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getZAt(value_t xk, value_t b) const +GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getZAt(value_t xk, value_t b) const { ///< this method is just an alias for obtaining Z @ X in the tree->Draw() value_t y, z; @@ -477,7 +491,7 @@ typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::g //______________________________________________________________ template <typename value_T> -typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getYAt(value_t xk, value_t b) const +GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getYAt(value_t xk, value_t b) const { ///< this method is just an alias for obtaining Z @ X in the tree->Draw() value_t y, z; @@ -497,7 +511,7 @@ std::string TrackParametrization<value_T>::asString() const //______________________________________________________________ template <typename value_T> -void TrackParametrization<value_T>::printParam() const +GPUd() void TrackParametrization<value_T>::printParam() const { // print parameters #ifndef GPUCA_ALIGPUCODE @@ -507,7 +521,7 @@ void TrackParametrization<value_T>::printParam() const //______________________________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz, track::DirType dir) const +GPUd() bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz, track::DirType dir) const { // Get local X of the track position estimated at the radius lab radius r. // The track curvature is accounted exactly @@ -521,16 +535,16 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz const value_t kEps = 1.e-6; // auto crv = getCurvature(bz); - if (std::fabs(crv) > constants::math::Almost0) { // helix + if (math_utils::detail::abs<value_T>(crv) > constants::math::Almost0) { // helix // get center of the track circle math_utils::CircleXY<value_t> circle; getCircleParamsLoc(bz, circle); - value_t r0 = std::sqrt(circle.getCenterD2()); + value_t r0 = math_utils::detail::sqrt<value_T>(circle.getCenterD2()); if (r0 <= constants::math::Almost0) { return false; // the track is concentric to circle } value_t tR2r0 = 1.f, g = 0.f, tmp = 0.f; - if (std::fabs(circle.rC - r0) > kEps) { + if (math_utils::detail::abs<value_T>(circle.rC - r0) > kEps) { tR2r0 = circle.rC / r0; g = 0.5f * (r * r / (r0 * circle.rC) - tR2r0 - 1.f / tR2r0); tmp = 1.f + g * tR2r0; @@ -543,7 +557,7 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz if (det < 0.f) { return false; // does not reach raduis r } - det = std::sqrt(det); + det = math_utils::detail::sqrt<value_T>(det); // // the intersection happens in 2 points: {circle.xC+tR*C,circle.yC+tR*S} // with C=f*c0+-|s0|*det and S=f*s0-+c0 sign(s0)*det @@ -551,8 +565,8 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz // x = circle.xC * tmp; value_t y = circle.yC * tmp; - if (std::fabs(circle.yC) > constants::math::Almost0) { // when circle.yC==0 the x,y is unique - value_t dfx = tR2r0 * std::fabs(circle.yC) * det; + if (math_utils::detail::abs<value_T>(circle.yC) > constants::math::Almost0) { // when circle.yC==0 the x,y is unique + value_t dfx = tR2r0 * math_utils::detail::abs<value_T>(circle.yC) * det; value_t dfy = tR2r0 * circle.xC * (circle.yC > 0.f ? det : -det); if (dir == DirAuto) { // chose the one which corresponds to smallest step value_t delta = (x - mX) * dfx - (y - fy) * dfy; // the choice of + in C will lead to smaller step if delta<0 @@ -563,7 +577,7 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz if (dfeps < -kEps) { return true; } - if (std::fabs(dfeps) < kEps && std::fabs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? + if (math_utils::detail::abs<value_T>(dfeps) < kEps && math_utils::detail::abs<value_T>(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? return mX; } x += dfx + dfx; @@ -580,7 +594,7 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz if (dfeps < -kEps) { return true; } - if (std::fabs(dfeps) < kEps && std::fabs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? + if (math_utils::detail::abs<value_T>(dfeps) < kEps && math_utils::detail::abs<value_T>(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? return mX; } x -= dfx + dfx; @@ -598,8 +612,8 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz return false; } } - } else { // this is a straight track - if (std::fabs(sn) >= constants::math::Almost1) { // || to Y axis + } else { // this is a straight track + if (math_utils::detail::abs<value_T>(sn) >= constants::math::Almost1) { // || to Y axis value_t det = (r - mX) * (r + mX); if (det < 0.f) { return false; // does not reach raduis r @@ -608,7 +622,7 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz if (dir == DirAuto) { return true; } - det = std::sqrt(det); + det = math_utils::detail::sqrt<value_T>(det); if (dir == DirOutward) { // along the track direction if (sn > 0.f) { if (fy > det) { @@ -628,12 +642,12 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz return false; // track is against Y axis } } - } else if (std::fabs(sn) <= constants::math::Almost0) { // || to X axis + } else if (math_utils::detail::abs<value_T>(sn) <= constants::math::Almost0) { // || to X axis value_t det = (r - fy) * (r + fy); if (det < 0.f) { return false; // does not reach raduis r } - det = std::sqrt(det); + det = math_utils::detail::sqrt<value_T>(det); if (dir == DirAuto) { x = mX > 0.f ? det : -det; // choose the solution requiring the smalest step return true; @@ -651,13 +665,13 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz } } } else { // general case of straight line - value_t cs = std::sqrt((1.f - sn) * (1.f + sn)); + value_t cs = math_utils::detail::sqrt<value_T>((1.f - sn) * (1.f + sn)); value_t xsyc = mX * sn - fy * cs; value_t det = (r - xsyc) * (r + xsyc); if (det < 0.f) { return false; // does not reach raduis r } - det = std::sqrt(det); + det = math_utils::detail::sqrt<value_T>(det); value_t xcys = mX * cs + fy * sn; value_t t = -xcys; if (dir == DirAuto) { @@ -684,14 +698,13 @@ bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz //______________________________________________ template <typename value_T> -bool TrackParametrization<value_T>::correctForELoss(value_t xrho, value_t mass, bool anglecorr, value_t dedx) +GPUd() bool TrackParametrization<value_T>::correctForELoss(value_t xrho, bool anglecorr, value_t dedx) { //------------------------------------------------------------------ // This function corrects the track parameters for the energy loss in crossed material. // "xrho" - is the product length*density (g/cm^2). // It should be passed as negative when propagating tracks // from the intreaction point to the outside of the central barrel. - // "mass" - the mass of this particle (GeV/c^2). // "dedx" - mean enery loss (GeV/(g/cm^2), if <=kCalcdEdxAuto : calculate on the fly // "anglecorr" - switch for the angular correction //------------------------------------------------------------------ @@ -702,45 +715,43 @@ bool TrackParametrization<value_T>::correctForELoss(value_t xrho, value_t mass, if (anglecorr) { value_t csp2 = (1.f - getSnp()) * (1.f + getSnp()); // cos(phi)^2 value_t cst2I = (1.f + getTgl() * getTgl()); // 1/cos(lambda)^2 - value_t angle = std::sqrt(cst2I / (csp2)); + value_t angle = math_utils::detail::sqrt<value_T>(cst2I / (csp2)); xrho *= angle; } - value_t p = getP(); - if (mass < 0) { - p += p; // q=2 particle - } - value_t p2 = p * p, mass2 = mass * mass; - value_t e2 = p2 + mass2; + value_t p2 = p * p; + value_t e2 = p2 + getPID().getMass2(); value_t beta2 = p2 / e2; // Calculating the energy loss corrections************************ if ((xrho != 0.f) && (beta2 < 1.f)) { if (dedx < kCalcdEdxAuto + constants::math::Almost1) { // request to calculate dedx on the fly - dedx = BetheBlochSolid(p / std::fabs(mass)); + dedx = BetheBlochSolid(p / getPID().getMass()); if (mAbsCharge != 1) { dedx *= mAbsCharge * mAbsCharge; } } value_t dE = dedx * xrho; - value_t e = std::sqrt(e2); - if (std::fabs(dE) > kMaxELossFrac * e) { + value_t e = math_utils::detail::sqrt<value_T>(e2); + if (math_utils::detail::abs<value_T>(dE) > kMaxELossFrac * e) { return false; // 30% energy loss is too much! } value_t eupd = e + dE; - value_t pupd2 = eupd * eupd - mass2; + value_t pupd2 = eupd * eupd - getPID().getMass2(); if (pupd2 < kMinP * kMinP) { return false; } - setQ2Pt(getQ2Pt() * p / std::sqrt(pupd2)); + setQ2Pt(getQ2Pt() * p / math_utils::detail::sqrt<value_T>(pupd2)); } return true; } +namespace o2::track +{ template class TrackParametrization<float>; +#ifndef GPUCA_GPUCODE_DEVICE template class TrackParametrization<double>; - -} // namespace track -} // namespace o2 +#endif +} // namespace o2::track diff --git a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx index 2d340193251c5..4b5e640ceeb0b 100644 --- a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,11 +14,12 @@ /// @since Oct 1, 2020 /// @brief -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,24 +29,24 @@ #include "ReconstructionDataFormats/Vertex.h" #include "ReconstructionDataFormats/DCA.h" #include <GPUCommonLogger.h> -#include "Math/SMatrix.h" #ifndef GPUCA_GPUCODE_DEVICE #include <iostream> +#ifndef GPUCA_STANDALONE +#include "Math/SMatrix.h" +#endif #endif #ifndef GPUCA_ALIGPUCODE #include <fmt/printf.h> #endif -namespace o2 -{ -namespace track -{ +using namespace o2::track; +using namespace o2::gpu; //______________________________________________________________ template <typename value_T> -void TrackParametrizationWithError<value_T>::invert() +GPUd() void TrackParametrizationWithError<value_T>::invert() { // Transform this track to the local coord. system rotated by 180 deg. this->invertParam(); @@ -59,35 +61,35 @@ void TrackParametrizationWithError<value_T>::invert() //______________________________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, value_t b) +GPUd() bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, value_t b) { //---------------------------------------------------------------- // propagate this track to the plane X=xk (cm) in the field "b" (kG) //---------------------------------------------------------------- value_t dx = xk - this->getX(); - if (std::fabs(dx) < constants::math::Almost0) { + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { return true; } value_t crv = this->getCurvature(b); value_t x2r = crv * dx; value_t f1 = this->getSnp(), f2 = f1 + x2r; - if ((std::fabs(f1) > constants::math::Almost1) || (std::fabs(f2) > constants::math::Almost1)) { + if ((gpu::CAMath::Abs(f1) > constants::math::Almost1) || (gpu::CAMath::Abs(f2) > constants::math::Almost1)) { return false; } - value_t r1 = std::sqrt((1.f - f1) * (1.f + f1)); - if (std::fabs(r1) < constants::math::Almost0) { + value_t r1 = gpu::CAMath::Sqrt((1.f - f1) * (1.f + f1)); + if (gpu::CAMath::Abs(r1) < constants::math::Almost0) { return false; } - value_t r2 = std::sqrt((1.f - f2) * (1.f + f2)); - if (std::fabs(r2) < constants::math::Almost0) { + value_t r2 = gpu::CAMath::Sqrt((1.f - f2) * (1.f + f2)); + if (gpu::CAMath::Abs(r2) < constants::math::Almost0) { return false; } this->setX(xk); double dy2dx = (f1 + f2) / (r1 + r2); - value_t dP[kNParams] = {0.f}; + params_t dP{0.f}; dP[kY] = dx * dy2dx; dP[kSnp] = x2r; - if (std::fabs(x2r) < 0.05f) { + if (gpu::CAMath::Abs(x2r) < 0.05f) { dP[kZ] = dx * (r2 + f2 * dy2dx) * this->getTgl(); } else { // for small dx/R the linear apporximation of the arc by the segment is OK, @@ -98,8 +100,8 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, value_t b) // double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center // mP1 += rot/crv*mP3; // - value_t rot = std::asin(r1 * f2 - r2 * f1); // more economic version from Yura. - if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles + value_t rot = gpu::CAMath::ASin(r1 * f2 - r2 * f1); // more economic version from Yura. + if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles if (f2 > 0.f) { rot = constants::math::PI - rot; // } else { @@ -164,11 +166,11 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, value_t b) //______________________________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) +GPUd() bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) { // rotate to alpha frame - if (std::fabs(this->getSnp()) > constants::math::Almost1) { - LOGP(WARNING, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", this->getSnp()); + if (gpu::CAMath::Abs(this->getSnp()) > constants::math::Almost1) { + LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", this->getSnp()); return false; } // @@ -176,7 +178,7 @@ bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) // value_t ca = 0, sa = 0; math_utils::detail::sincos(alpha - this->getAlpha(), sa, ca); - value_t snp = this->getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); // Improve precision + value_t snp = this->getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); // Improve precision // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle // direction in local frame is along the X axis if ((csp * ca + snp * sa) < 0) { @@ -186,8 +188,8 @@ bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) // value_t updSnp = snp * ca - csp * sa; - if (std::fabs(updSnp) > constants::math::Almost1) { - LOGP(WARNING, "Rotation failed: new snp {:.2f}", updSnp); + if (gpu::CAMath::Abs(updSnp) > constants::math::Almost1) { + LOGP(debug, "Rotation failed: new snp {:.2f}", updSnp); return false; } value_t xold = this->getX(), yold = this->getY(); @@ -196,8 +198,8 @@ bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) this->setY(-xold * sa + yold * ca); this->setSnp(updSnp); - if (std::fabs(csp) < constants::math::Almost0) { - LOGP(WARNING, "Too small cosine value {:f}", csp); + if (gpu::CAMath::Abs(csp) < constants::math::Almost0) { + LOGP(debug, "Too small cosine value {:f}", csp); csp = constants::math::Almost0; } @@ -219,35 +221,39 @@ bool TrackParametrizationWithError<value_T>::rotate(value_t alpha) //_______________________________________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t b, o2::dataformats::DCA* dca, value_t maxD) +GPUd() bool TrackParametrizationWithError<value_T>::propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t b, o2::dataformats::DCA* dca, value_t maxD) { // propagate track to DCA to the vertex value_t sn, cs, alp = this->getAlpha(); o2::math_utils::detail::sincos(alp, sn, cs); - value_t x = this->getX(), y = this->getY(), snp = this->getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); + value_t x = this->getX(), y = this->getY(), snp = this->getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); value_t xv = vtx.getX() * cs + vtx.getY() * sn, yv = -vtx.getX() * sn + vtx.getY() * cs, zv = vtx.getZ(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_t d = gpu::CAMath::Abs(x * snp - y * csp); if (d > maxD) { return false; } value_t crv = this->getCurvature(b); value_t tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1.f - sn) * (1.f + sn)); - cs = (std::abs(tgfv) > constants::math::Almost0) ? sn / tgfv : constants::math::Almost1; + sn = tgfv / gpu::CAMath::Sqrt(1.f + tgfv * tgfv); + cs = gpu::CAMath::Sqrt((1.f - sn) * (1.f + sn)); + cs = (gpu::CAMath::Abs(tgfv) > constants::math::Almost0) ? sn / tgfv : constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(*this); // operate on the copy to recover after the failure - alp += std::asin(sn); + alp += gpu::CAMath::ASin(sn); if (!tmpT.rotate(alp) || !tmpT.propagateTo(xv, b)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: "; - tmpT.print(); +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx; + ; +#endif return false; } *this = tmpT; @@ -261,10 +267,19 @@ bool TrackParametrizationWithError<value_T>::propagateToDCA(const o2::dataformat //______________________________________________________________ template <typename value_T> -TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3_t& xyz, const dim3_t& pxpypz, - const std::array<value_t, kLabCovMatSize>& cv, int charge, bool sectorAlpha) +GPUd() TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3_t& xyz, const dim3_t& pxpypz, + const gpu::gpustd::array<value_t, kLabCovMatSize>& cv, int charge, bool sectorAlpha, const PID pid) { // construct track param and covariance from kinematics and lab errors + set(xyz, pxpypz, cv, charge, sectorAlpha, pid); +} + +//______________________________________________________________ +template <typename value_T> +GPUd() void TrackParametrizationWithError<value_T>::set(const dim3_t& xyz, const dim3_t& pxpypz, + const gpu::gpustd::array<value_t, kLabCovMatSize>& cv, int charge, bool sectorAlpha, const PID pid) +{ + // set track param and covariance from kinematics and lab errors // Alpha of the frame is defined as: // sectorAlpha == false : -> angle of pt direction @@ -276,9 +291,9 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 value_t radPos2 = xyz[0] * xyz[0] + xyz[1] * xyz[1]; value_t alp = 0; if (sectorAlpha || radPos2 < 1) { - alp = std::atan2(pxpypz[1], pxpypz[0]); + alp = gpu::CAMath::ATan2(pxpypz[1], pxpypz[0]); } else { - alp = std::atan2(xyz[1], xyz[0]); + alp = gpu::CAMath::ATan2(xyz[1], xyz[0]); } if (sectorAlpha) { alp = math_utils::detail::angle2Alpha<value_t>(alp); @@ -286,15 +301,24 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 // value_t sn, cs; math_utils::detail::sincos(alp, sn, cs); + // protection against cosp<0 + if (cs * pxpypz[0] + sn * pxpypz[1] < 0) { + LOG(debug) << "alpha from phiPos() will invalidate this track parameters, overriding to alpha from phi()"; + alp = gpu::CAMath::ATan2(pxpypz[1], pxpypz[0]); + if (sectorAlpha) { + alp = math_utils::detail::angle2Alpha<value_t>(alp); + } + math_utils::detail::sincos(alp, sn, cs); + } // protection: avoid alpha being too close to 0 or +-pi/2 - if (std::fabs(sn) < 2.f * kSafe) { + if (gpu::CAMath::Abs(sn) < 2.f * kSafe) { if (alp > 0) { alp += alp < constants::math::PIHalf ? 2.f * kSafe : -2.f * kSafe; } else { alp += alp > -constants::math::PIHalf ? -2.f * kSafe : 2.f * kSafe; } math_utils::detail::sincos(alp, sn, cs); - } else if (std::fabs(cs) < 2.f * kSafe) { + } else if (gpu::CAMath::Abs(cs) < 2.f * kSafe) { if (alp > 0) { alp += alp > constants::math::PIHalf ? 2.f * kSafe : -2.f * kSafe; } else { @@ -310,7 +334,7 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 math_utils::detail::rotateZ<value_t>(ver, -alp); math_utils::detail::rotateZ<value_t>(mom, -alp); // - value_t pt = std::sqrt(mom[0] * mom[0] + mom[1] * mom[1]); + value_t pt = gpu::CAMath::Sqrt(mom[0] * mom[0] + mom[1] * mom[1]); value_t ptI = 1.f / pt; this->setX(ver[0]); this->setAlpha(alp); @@ -318,25 +342,26 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 this->setZ(ver[2]); this->setSnp(mom[1] * ptI); // cos(phi) this->setTgl(mom[2] * ptI); // tg(lambda) - this->setAbsCharge(std::abs(charge)); + this->setAbsCharge(gpu::CAMath::Abs(charge)); this->setQ2Pt(charge ? ptI * charge : ptI); + this->setPID(pid); // - if (std::fabs(1.f - this->getSnp()) < kSafe) { + if (gpu::CAMath::Abs(1.f - this->getSnp()) < kSafe) { this->setSnp(1.f - kSafe); // Protection - } else if (std::fabs(-1.f - this->getSnp()) < kSafe) { + } else if (gpu::CAMath::Abs(-1.f - this->getSnp()) < kSafe) { this->setSnp(-1.f + kSafe); // Protection } // // Covariance matrix (formulas to be simplified) value_t r = mom[0] * ptI; // cos(phi) - value_t cv34 = std::sqrt(cv[3] * cv[3] + cv[4] * cv[4]); + value_t cv34 = gpu::CAMath::Sqrt(cv[3] * cv[3] + cv[4] * cv[4]); // int special = 0; value_t sgcheck = r * sn + this->getSnp() * cs; - if (std::fabs(sgcheck) > 1 - kSafe) { // special case: lab phi is +-pi/2 + if (gpu::CAMath::Abs(sgcheck) > 1 - kSafe) { // special case: lab phi is +-pi/2 special = 1; sgcheck = sgcheck < 0 ? -1.f : 1.f; - } else if (std::fabs(sgcheck) < kSafe) { + } else if (gpu::CAMath::Abs(sgcheck) < kSafe) { sgcheck = cs < 0 ? -1.0f : 1.0f; special = 2; // special case: lab phi is 0 } @@ -350,38 +375,40 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 if (special == 1) { mC[kSigSnpY] = cv[6] * ptI; mC[kSigSnpZ] = -sgcheck * cv[8] * r * ptI; - mC[kSigSnp2] = std::fabs(cv[9] * r * r * ptI2); + mC[kSigSnp2] = gpu::CAMath::Abs(cv[9] * r * r * ptI2); mC[kSigTglY] = (cv[10] * this->getTgl() - sgcheck * cv[15]) * ptI / r; mC[kSigTglZ] = (cv[17] - sgcheck * cv[12] * this->getTgl()) * ptI; mC[kSigTglSnp] = (-sgcheck * cv[18] + cv[13] * this->getTgl()) * r * ptI2; - mC[kSigTgl2] = std::fabs(cv[20] - 2 * sgcheck * cv[19] * mC[4] + cv[14] * tgl2) * ptI2; + mC[kSigTgl2] = gpu::CAMath::Abs(cv[20] - 2 * sgcheck * cv[19] * mC[4] + cv[14] * tgl2) * ptI2; mC[kSigQ2PtY] = cv[10] * ptI2 / r * charge; mC[kSigQ2PtZ] = -sgcheck * cv[12] * ptI2 * charge; mC[kSigQ2PtSnp] = cv[13] * r * ptI * ptI2 * charge; mC[kSigQ2PtTgl] = (-sgcheck * cv[19] + cv[14] * this->getTgl()) * r * ptI2 * ptI; - mC[kSigQ2Pt2] = std::fabs(cv[14] * ptI2 * ptI2); + mC[kSigQ2Pt2] = gpu::CAMath::Abs(cv[14] * ptI2 * ptI2); } else if (special == 2) { mC[kSigSnpY] = -cv[10] * ptI * cs / sn; mC[kSigSnpZ] = cv[12] * cs * ptI; - mC[kSigSnp2] = std::fabs(cv[14] * cs * cs * ptI2); + mC[kSigSnp2] = gpu::CAMath::Abs(cv[14] * cs * cs * ptI2); mC[kSigTglY] = (sgcheck * cv[6] * this->getTgl() - cv[15]) * ptI / sn; mC[kSigTglZ] = (cv[17] - sgcheck * cv[8] * this->getTgl()) * ptI; mC[kSigTglSnp] = (cv[19] - sgcheck * cv[13] * this->getTgl()) * cs * ptI2; - mC[kSigTgl2] = std::fabs(cv[20] - 2 * sgcheck * cv[18] * this->getTgl() + cv[9] * tgl2) * ptI2; + mC[kSigTgl2] = gpu::CAMath::Abs(cv[20] - 2 * sgcheck * cv[18] * this->getTgl() + cv[9] * tgl2) * ptI2; mC[kSigQ2PtY] = sgcheck * cv[6] * ptI2 / sn * charge; mC[kSigQ2PtZ] = -sgcheck * cv[8] * ptI2 * charge; mC[kSigQ2PtSnp] = -sgcheck * cv[13] * cs * ptI * ptI2 * charge; mC[kSigQ2PtTgl] = (-sgcheck * cv[18] + cv[9] * this->getTgl()) * ptI2 * ptI * charge; - mC[kSigQ2Pt2] = std::fabs(cv[9] * ptI2 * ptI2); + mC[kSigQ2Pt2] = gpu::CAMath::Abs(cv[9] * ptI2 * ptI2); } else { double m00 = -sn; // m10=cs; double m23 = -pt * (sn + this->getSnp() * cs / r), m43 = -pt * pt * (r * cs - this->getSnp() * sn); double m24 = pt * (cs - this->getSnp() * sn / r), m44 = -pt * pt * (r * sn + this->getSnp() * cs); double m35 = pt, m45 = -pt * pt * this->getTgl(); // - m43 *= charge; - m44 *= charge; - m45 *= charge; + if (charge) { // RS: this is a hack, proper treatment to be implemented + m43 *= charge; + m44 *= charge; + m45 *= charge; + } // double a1 = cv[13] - cv[9] * (m23 * m44 + m43 * m24) / m23 / m43; double a2 = m23 * m24 - m23 * (m23 * m44 + m43 * m24) / m43; @@ -396,8 +423,8 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 mC[kSigSnpZ] = (cv[12] * m43 - cv[8] * m44) / (m24 * m43 - m23 * m44); mC[kSigQ2PtZ] = (cv[8] - mC[kSigSnpZ] * m23) / m43; mC[kSigTglZ] = cv[17] / m35 - mC[kSigQ2PtZ] * m45 / m35; - mC[kSigSnp2] = std::fabs((a4 * a3 - a6 * a1) / (a5 * a3 - a6 * a2)); - mC[kSigQ2Pt2] = std::fabs((a1 - a2 * mC[kSigSnp2]) / a3); + mC[kSigSnp2] = gpu::CAMath::Abs((a4 * a3 - a6 * a1) / (a5 * a3 - a6 * a2)); + mC[kSigQ2Pt2] = gpu::CAMath::Abs((a1 - a2 * mC[kSigSnp2]) / a3); mC[kSigQ2PtSnp] = (cv[9] - mC[kSigSnp2] * m23 * m23 - mC[kSigQ2Pt2] * m43 * m43) / m23 / m43; double b1 = cv[18] - mC[kSigQ2PtSnp] * m23 * m45 - mC[kSigQ2Pt2] * m43 * m45; double b2 = m23 * m35; @@ -407,14 +434,14 @@ TrackParametrizationWithError<value_T>::TrackParametrizationWithError(const dim3 double b6 = m44 * m35; mC[kSigTglSnp] = (b4 - b6 * b1 / b3) / (b5 - b6 * b2 / b3); mC[kSigQ2PtTgl] = b1 / b3 - b2 * mC[kSigTglSnp] / b3; - mC[kSigTgl2] = std::fabs((cv[20] - mC[kSigQ2Pt2] * (m45 * m45) - mC[kSigQ2PtTgl] * 2.f * m35 * m45) / (m35 * m35)); + mC[kSigTgl2] = gpu::CAMath::Abs((cv[20] - mC[kSigQ2Pt2] * (m45 * m45) - mC[kSigQ2PtTgl] * 2.f * m35 * m45) / (m35 * m35)); } checkCovariance(); } //____________________________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_t& b) +GPUd() bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_t& b) { //---------------------------------------------------------------- // Extrapolate this track to the plane X=xk in the field b[]. @@ -424,37 +451,37 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_ //---------------------------------------------------------------- value_t dx = xk - this->getX(); - if (std::fabs(dx) < constants::math::Almost0) { + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { return true; } // Do not propagate tracks outside the ALICE detector - if (std::fabs(dx) > 1e5 || std::fabs(this->getY()) > 1e5 || std::fabs(this->getZ()) > 1e5) { + if (gpu::CAMath::Abs(dx) > 1e5 || gpu::CAMath::Abs(this->getY()) > 1e5 || gpu::CAMath::Abs(this->getZ()) > 1e5) { LOGP(WARNING, "Anomalous track, target X:{:f}", xk); // print(); return false; } - value_t crv = (std::fabs(b[2]) < constants::math::Almost0) ? 0.f : this->getCurvature(b[2]); + value_t crv = (gpu::CAMath::Abs(b[2]) < constants::math::Almost0) ? 0.f : this->getCurvature(b[2]); value_t x2r = crv * dx; value_t f1 = this->getSnp(), f2 = f1 + x2r; - if ((std::fabs(f1) > constants::math::Almost1) || (std::fabs(f2) > constants::math::Almost1)) { + if ((gpu::CAMath::Abs(f1) > constants::math::Almost1) || (gpu::CAMath::Abs(f2) > constants::math::Almost1)) { return false; } - value_t r1 = std::sqrt((1.f - f1) * (1.f + f1)); - if (std::fabs(r1) < constants::math::Almost0) { + value_t r1 = gpu::CAMath::Sqrt((1.f - f1) * (1.f + f1)); + if (gpu::CAMath::Abs(r1) < constants::math::Almost0) { return false; } - value_t r2 = std::sqrt((1.f - f2) * (1.f + f2)); - if (std::fabs(r2) < constants::math::Almost0) { + value_t r2 = gpu::CAMath::Sqrt((1.f - f2) * (1.f + f2)); + if (gpu::CAMath::Abs(r2) < constants::math::Almost0) { return false; } value_t dy2dx = (f1 + f2) / (r1 + r2); - value_t step = (std::fabs(x2r) < 0.05f) ? dx * std::fabs(r2 + f2 * dy2dx) // chord - : 2.f * std::asin(0.5f * dx * std::sqrt(1.f + dy2dx * dy2dx) * crv) / crv; // arc - step *= std::sqrt(1.f + this->getTgl() * this->getTgl()); + value_t step = (gpu::CAMath::Abs(x2r) < 0.05f) ? dx * gpu::CAMath::Abs(r2 + f2 * dy2dx) // chord + : 2.f * gpu::CAMath::ASin(0.5f * dx * gpu::CAMath::Sqrt(1.f + dy2dx * dy2dx) * crv) / crv; // arc + step *= gpu::CAMath::Sqrt(1.f + this->getTgl() * this->getTgl()); // // get the track x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha in the Global System - std::array<value_t, 9> vecLab{0.f}; + gpu::gpustd::array<value_t, 9> vecLab{0.f}; if (!this->getPosDirGlo(vecLab)) { return false; } @@ -509,25 +536,25 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_ // Rotate to the system where Bx=By=0. value_t bxy2 = b[0] * b[0] + b[1] * b[1]; - value_t bt = std::sqrt(bxy2); + value_t bt = gpu::CAMath::Sqrt(bxy2); value_t cosphi = 1.f, sinphi = 0.f; if (bt > constants::math::Almost0) { cosphi = b[0] / bt; sinphi = b[1] / bt; } - value_t bb = std::sqrt(bxy2 + b[2] * b[2]); + value_t bb = gpu::CAMath::Sqrt(bxy2 + b[2] * b[2]); value_t costet = 1., sintet = 0.; if (bb > constants::math::Almost0) { costet = b[2] / bb; sintet = bt / bb; } - std::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], - -sinphi * vecLab[0] + cosphi * vecLab[1], - sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2], - costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5], - -sinphi * vecLab[3] + cosphi * vecLab[4], - sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5], - vecLab[6]}; + gpu::gpustd::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], + -sinphi * vecLab[0] + cosphi * vecLab[1], + sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2], + costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5], + -sinphi * vecLab[3] + cosphi * vecLab[4], + sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5], + vecLab[6]}; // Do the helix step value_t sgn = this->getSign(); @@ -553,8 +580,8 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_ // Do the final correcting step to the target plane (linear approximation) value_t x = vecLab[0], y = vecLab[1], z = vecLab[2]; - if (std::fabs(dx) > constants::math::Almost0) { - if (std::fabs(vecLab[3]) < constants::math::Almost0) { + if (gpu::CAMath::Abs(dx) > constants::math::Almost0) { + if (gpu::CAMath::Abs(vecLab[3]) < constants::math::Almost0) { return false; } dx = xk - vecLab[0]; @@ -564,8 +591,8 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_ } // Calculate the track parameters - t = 1.f / std::sqrt(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]); - this->setX(x); + t = 1.f / gpu::CAMath::Sqrt(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]); + this->setX(xk); this->setY(y); this->setZ(z); this->setSnp(vecLab[4] * t); @@ -577,51 +604,51 @@ bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, const dim3_ //______________________________________________ template <typename value_T> -void TrackParametrizationWithError<value_T>::checkCovariance() +GPUd() void TrackParametrizationWithError<value_T>::checkCovariance() { // This function forces the diagonal elements of the covariance matrix to be positive. // In case the diagonal element is bigger than the maximal allowed value, it is set to // the limit and the off-diagonal elements that correspond to it are set to zero. - mC[kSigY2] = std::fabs(mC[kSigY2]); + mC[kSigY2] = gpu::CAMath::Abs(mC[kSigY2]); if (mC[kSigY2] > kCY2max) { - value_t scl = std::sqrt(kCY2max / mC[kSigY2]); + value_t scl = gpu::CAMath::Sqrt(kCY2max / mC[kSigY2]); mC[kSigY2] = kCY2max; mC[kSigZY] *= scl; mC[kSigSnpY] *= scl; mC[kSigTglY] *= scl; mC[kSigQ2PtY] *= scl; } - mC[kSigZ2] = std::fabs(mC[kSigZ2]); + mC[kSigZ2] = gpu::CAMath::Abs(mC[kSigZ2]); if (mC[kSigZ2] > kCZ2max) { - value_t scl = std::sqrt(kCZ2max / mC[kSigZ2]); + value_t scl = gpu::CAMath::Sqrt(kCZ2max / mC[kSigZ2]); mC[kSigZ2] = kCZ2max; mC[kSigZY] *= scl; mC[kSigSnpZ] *= scl; mC[kSigTglZ] *= scl; mC[kSigQ2PtZ] *= scl; } - mC[kSigSnp2] = std::fabs(mC[kSigSnp2]); + mC[kSigSnp2] = gpu::CAMath::Abs(mC[kSigSnp2]); if (mC[kSigSnp2] > kCSnp2max) { - value_t scl = std::sqrt(kCSnp2max / mC[kSigSnp2]); + value_t scl = gpu::CAMath::Sqrt(kCSnp2max / mC[kSigSnp2]); mC[kSigSnp2] = kCSnp2max; mC[kSigSnpY] *= scl; mC[kSigSnpZ] *= scl; mC[kSigTglSnp] *= scl; mC[kSigQ2PtSnp] *= scl; } - mC[kSigTgl2] = std::fabs(mC[kSigTgl2]); + mC[kSigTgl2] = gpu::CAMath::Abs(mC[kSigTgl2]); if (mC[kSigTgl2] > kCTgl2max) { - value_t scl = std::sqrt(kCTgl2max / mC[kSigTgl2]); + value_t scl = gpu::CAMath::Sqrt(kCTgl2max / mC[kSigTgl2]); mC[kSigTgl2] = kCTgl2max; mC[kSigTglY] *= scl; mC[kSigTglZ] *= scl; mC[kSigTglSnp] *= scl; mC[kSigQ2PtTgl] *= scl; } - mC[kSigQ2Pt2] = std::fabs(mC[kSigQ2Pt2]); + mC[kSigQ2Pt2] = gpu::CAMath::Abs(mC[kSigQ2Pt2]); if (mC[kSigQ2Pt2] > kC1Pt2max) { - value_t scl = std::sqrt(kC1Pt2max / mC[kSigQ2Pt2]); + value_t scl = gpu::CAMath::Sqrt(kC1Pt2max / mC[kSigQ2Pt2]); mC[kSigQ2Pt2] = kC1Pt2max; mC[kSigQ2PtY] *= scl; mC[kSigQ2PtZ] *= scl; @@ -632,7 +659,7 @@ void TrackParametrizationWithError<value_T>::checkCovariance() //______________________________________________ template <typename value_T> -void TrackParametrizationWithError<value_T>::resetCovariance(value_t s2) +GPUd() void TrackParametrizationWithError<value_T>::resetCovariance(value_t s2) { // Reset the covarince matrix to "something big" double d0(kCY2max), d1(kCZ2max), d2(kCSnp2max), d3(kCTgl2max), d4(kC1Pt2max); @@ -658,7 +685,9 @@ void TrackParametrizationWithError<value_T>::resetCovariance(value_t s2) d4 = kC1Pt2max; } } - memset(mC, 0, kCovMatSize * sizeof(value_t)); + for (int i = 0; i < kCovMatSize; i++) { + mC[i] = 0; + } mC[kSigY2] = d0; mC[kSigZ2] = d1; mC[kSigSnp2] = d2; @@ -668,7 +697,7 @@ void TrackParametrizationWithError<value_T>::resetCovariance(value_t s2) //______________________________________________ template <typename value_T> -typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getPredictedChi2(const dim2_t& p, const dim3_t& cov) const +GPUd() auto TrackParametrizationWithError<value_T>::getPredictedChi2(const value_t* p, const value_t* cov) const -> value_t { // Estimate the chi2 of the space point "p" with the cov. matrix "cov" auto sdd = static_cast<double>(getSigmaY2()) + static_cast<double>(cov[0]); @@ -676,7 +705,7 @@ typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWit auto szz = static_cast<double>(getSigmaZ2()) + static_cast<double>(cov[2]); auto det = sdd * szz - sdz * sdz; - if (std::fabs(det) < constants::math::Almost0) { + if (gpu::CAMath::Abs(det) < constants::math::Almost0) { return constants::math::VeryBig; } @@ -686,6 +715,8 @@ typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWit return (d * (szz * d - sdz * z) + z * (sdd * z - d * sdz)) / det; } +#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) // Disable function relying on ROOT SMatrix on GPU + //______________________________________________ template <typename value_T> void TrackParametrizationWithError<value_T>::buildCombinedCovMatrix(const TrackParametrizationWithError<value_T>& rhs, MatrixDSym5& cov) const @@ -710,7 +741,7 @@ void TrackParametrizationWithError<value_T>::buildCombinedCovMatrix(const TrackP //______________________________________________ template <typename value_T> -typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getPredictedChi2(const TrackParametrizationWithError<value_T>& rhs) const +auto TrackParametrizationWithError<value_T>::getPredictedChi2(const TrackParametrizationWithError<value_T>& rhs) const -> value_t { MatrixDSym5 cov; // perform matrix operations in double! return getPredictedChi2(rhs, cov); @@ -718,16 +749,16 @@ typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWit //______________________________________________ template <typename value_T> -typename TrackParametrizationWithError<value_T>::value_t TrackParametrizationWithError<value_T>::getPredictedChi2(const TrackParametrizationWithError<value_T>& rhs, MatrixDSym5& covToSet) const +auto TrackParametrizationWithError<value_T>::getPredictedChi2(const TrackParametrizationWithError<value_T>& rhs, MatrixDSym5& covToSet) const -> value_t { // get chi2 wrt other track, which must be defined at the same parameters X,alpha // Supplied non-initialized covToSet matrix is filled by inverse combined matrix for further use - if (std::abs(this->getAlpha() - rhs.getAlpha()) > FLT_EPSILON) { + if (gpu::CAMath::Abs(this->getAlpha() - rhs.getAlpha()) > FLT_EPSILON) { LOG(ERROR) << "The reference Alpha of the tracks differ: " << this->getAlpha() << " : " << rhs.getAlpha(); return 2.f * HugeF; } - if (std::abs(this->getX() - rhs.getX()) > FLT_EPSILON) { + if (gpu::CAMath::Abs(this->getX() - rhs.getX()) > FLT_EPSILON) { LOG(ERROR) << "The reference X of the tracks differ: " << this->getX() << " : " << rhs.getX(); return 2.f * HugeF; } @@ -756,11 +787,11 @@ bool TrackParametrizationWithError<value_T>::update(const TrackParametrizationWi // update track with other track, the inverted combined cov matrix should be supplied // consider skipping this check, since it is usually already done upstream - if (std::abs(this->getAlpha() - rhs.getAlpha()) > FLT_EPSILON) { + if (gpu::CAMath::Abs(this->getAlpha() - rhs.getAlpha()) > FLT_EPSILON) { LOG(ERROR) << "The reference Alpha of the tracks differ: " << this->getAlpha() << " : " << rhs.getAlpha(); return false; } - if (std::abs(this->getX() - rhs.getX()) > FLT_EPSILON) { + if (gpu::CAMath::Abs(this->getX() - rhs.getX()) > FLT_EPSILON) { LOG(ERROR) << "The reference X of the tracks differ: " << this->getX() << " : " << rhs.getX(); return false; } @@ -831,9 +862,11 @@ bool TrackParametrizationWithError<value_T>::update(const TrackParametrizationWi return update(rhs, covI); } +#endif + //______________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::update(const dim2_t& p, const dim3_t& cov) +GPUd() bool TrackParametrizationWithError<value_T>::update(const value_t* p, const value_t* cov) { // Update the track parameters with the space point "p" having // the covariance matrix "cov" @@ -849,7 +882,7 @@ bool TrackParametrizationWithError<value_T>::update(const dim2_t& p, const dim3_ double r11 = static_cast<double>(cov[2]) + static_cast<double>(cm11); double det = r00 * r11 - r01 * r01; - if (std::fabs(det) < constants::math::Almost0) { + if (gpu::CAMath::Abs(det) < constants::math::Almost0) { return false; } double detI = 1. / det; @@ -866,12 +899,12 @@ bool TrackParametrizationWithError<value_T>::update(const dim2_t& p, const dim3_ value_t dy = p[kY] - this->getY(), dz = p[kZ] - this->getZ(); value_t dsnp = k20 * dy + k21 * dz; - if (std::fabs(this->getSnp() + dsnp) > constants::math::Almost1) { + if (gpu::CAMath::Abs(this->getSnp() + dsnp) > constants::math::Almost1) { return false; } - value_t dP[kNParams] = {value_t(k00 * dy + k01 * dz), value_t(k10 * dy + k11 * dz), dsnp, value_t(k30 * dy + k31 * dz), - value_t(k40 * dy + k41 * dz)}; + const params_t dP{value_t(k00 * dy + k01 * dz), value_t(k10 * dy + k11 * dz), dsnp, value_t(k30 * dy + k31 * dz), + value_t(k40 * dy + k41 * dz)}; this->updateParams(dP); double c01 = cm10, c02 = cm20, c03 = cm30, c04 = cm40; @@ -904,7 +937,7 @@ bool TrackParametrizationWithError<value_T>::update(const dim2_t& p, const dim3_ //______________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, value_t xrho, value_t mass, bool anglecorr, value_t dedx) +GPUd() bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, value_t xrho, bool anglecorr, value_t dedx) { //------------------------------------------------------------------ // This function corrects the track parameters for the crossed material. @@ -912,7 +945,6 @@ bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, va // "xrho" - is the product length*density (g/cm^2). // It should be passed as negative when propagating tracks // from the intreaction point to the outside of the central barrel. - // "mass" - the mass of this particle (GeV/c^2). // "dedx" - mean enery loss (GeV/(g/cm^2), if <=kCalcdEdxAuto : calculate on the fly // "anglecorr" - switch for the angular correction //------------------------------------------------------------------ @@ -929,20 +961,19 @@ bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, va value_t cst2I = (1.f + this->getTgl() * this->getTgl()); // 1/cos(lambda)^2 // Apply angle correction, if requested if (anglecorr) { - value_t angle = std::sqrt(cst2I / csp2); + value_t angle = gpu::CAMath::Sqrt(cst2I / csp2); x2x0 *= angle; xrho *= angle; } - value_t p = this->getP(); - value_t p2 = p * p, mass2 = mass * mass; - value_t e2 = p2 + mass2; + value_t p2 = p * p; + value_t e2 = p2 + this->getPID().getMass2(); value_t beta2 = p2 / e2; // Calculating the multiple scattering corrections****************** value_t cC22(0.f), cC33(0.f), cC43(0.f), cC44(0.f); if (x2x0 != 0.f) { - value_t theta2 = kMSConst2 / (beta2 * p2) * std::fabs(x2x0); + value_t theta2 = kMSConst2 / (beta2 * p2) * gpu::CAMath::Abs(x2x0); if (this->getAbsCharge() != 1) { theta2 *= this->getAbsCharge() * this->getAbsCharge(); } @@ -966,27 +997,27 @@ bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, va value_t cP4 = 1.f; if ((xrho != 0.f) && (beta2 < 1.f)) { if (dedx < kCalcdEdxAuto + constants::math::Almost1) { // request to calculate dedx on the fly - dedx = BetheBlochSolid(p / std::fabs(mass)); + dedx = BetheBlochSolid(p / this->getPID().getMass()); if (this->getAbsCharge() != 1) { dedx *= this->getAbsCharge() * this->getAbsCharge(); } } value_t dE = dedx * xrho; - value_t e = std::sqrt(e2); - if (std::fabs(dE) > kMaxELossFrac * e) { + value_t e = gpu::CAMath::Sqrt(e2); + if (gpu::CAMath::Abs(dE) > kMaxELossFrac * e) { return false; // 30% energy loss is too much! } value_t eupd = e + dE; - value_t pupd2 = eupd * eupd - mass2; + value_t pupd2 = eupd * eupd - this->getPID().getMass2(); if (pupd2 < kMinP * kMinP) { return false; } - cP4 = p / std::sqrt(pupd2); + cP4 = p / gpu::CAMath::Sqrt(pupd2); // // Approximate energy loss fluctuation (M.Ivanov) constexpr value_t knst = 0.07f; // To be tuned. - value_t sigmadE = knst * std::sqrt(std::fabs(dE)) * e / p2 * this->getCharge2Pt(); + value_t sigmadE = knst * gpu::CAMath::Sqrt(gpu::CAMath::Abs(dE)) * e / p2 * this->getCharge2Pt(); cC44 += sigmadE * sigmadE; } @@ -1004,7 +1035,7 @@ bool TrackParametrizationWithError<value_T>::correctForMaterial(value_t x2x0, va //______________________________________________________________ template <typename value_T> -bool TrackParametrizationWithError<value_T>::getCovXYZPxPyPzGlo(std::array<value_t, kLabCovMatSize>& cv) const +GPUd() bool TrackParametrizationWithError<value_T>::getCovXYZPxPyPzGlo(gpu::gpustd::array<value_t, kLabCovMatSize>& cv) const { //--------------------------------------------------------------------- // This function returns the global covariance matrix of the track params @@ -1018,7 +1049,7 @@ bool TrackParametrizationWithError<value_T>::getCovXYZPxPyPzGlo(std::array<value // // Results for (nearly) straight tracks are meaningless ! //--------------------------------------------------------------------- - if (std::abs(this->getQ2Pt()) <= constants::math::Almost0 || std::abs(this->getSnp()) > constants::math::Almost1) { + if (gpu::CAMath::Abs(this->getQ2Pt()) <= constants::math::Almost0 || gpu::CAMath::Abs(this->getSnp()) > constants::math::Almost1) { for (int i = 0; i < 21; i++) { cv[i] = 0.; } @@ -1028,7 +1059,7 @@ bool TrackParametrizationWithError<value_T>::getCovXYZPxPyPzGlo(std::array<value auto pt = this->getPt(); value_t sn, cs; o2::math_utils::detail::sincos(this->getAlpha(), sn, cs); - auto r = std::sqrt((1. - this->getSnp()) * (1. + this->getSnp())); + auto r = gpu::CAMath::Sqrt((1. - this->getSnp()) * (1. + this->getSnp())); auto m00 = -sn, m10 = cs; auto m23 = -pt * (sn + this->getSnp() * cs / r), m43 = -pt * pt * (r * cs - this->getSnp() * sn); auto m24 = pt * (cs - this->getSnp() * sn / r), m44 = -pt * pt * (r * sn + this->getSnp() * cs); @@ -1085,7 +1116,7 @@ std::string TrackParametrizationWithError<value_T>::asString() const //______________________________________________________________ template <typename value_T> -void TrackParametrizationWithError<value_T>::print() const +GPUd() void TrackParametrizationWithError<value_T>::print() const { // print parameters #ifndef GPUCA_ALIGPUCODE @@ -1093,8 +1124,10 @@ void TrackParametrizationWithError<value_T>::print() const #endif } +namespace o2::track +{ template class TrackParametrizationWithError<float>; +#ifndef GPUCA_GPUCODE_DEVICE template class TrackParametrizationWithError<double>; - -} // namespace track -} // namespace o2 +#endif +} // namespace o2::track diff --git a/DataFormats/Reconstruction/src/TrackTPCITS.cxx b/DataFormats/Reconstruction/src/TrackTPCITS.cxx index d93e0c4babe87..915ed32a4f26a 100644 --- a/DataFormats/Reconstruction/src/TrackTPCITS.cxx +++ b/DataFormats/Reconstruction/src/TrackTPCITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,7 @@ using namespace o2::dataformats; void TrackTPCITS::print() const { printf("TPCref: %6d ITSref: %6d\nChi2Refit: %6.2f Chi2Matc: %6.2f Time: %10.4f+-%10.4f mus\n", - mRefTPC, mRefITS, getChi2Refit(), getChi2Match(), + mRefTPC.getIndex(), mRefITS.getIndex(), getChi2Refit(), getChi2Match(), mTimeMUS.getTimeStamp(), mTimeMUS.getTimeStampError()); printf("Inner param: "); o2::track::TrackParCov::print(); diff --git a/DataFormats/Reconstruction/src/TrackTPCTOF.cxx b/DataFormats/Reconstruction/src/TrackTPCTOF.cxx new file mode 100644 index 0000000000000..a466f59ccebdf --- /dev/null +++ b/DataFormats/Reconstruction/src/TrackTPCTOF.cxx @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ReconstructionDataFormats/TrackTPCTOF.h" + +using namespace o2::dataformats; + +//__________________________________________________ +void TrackTPCTOF::print() const +{ + printf("TPC-TOC MatchRef: %6d Chi2Refit: %6.2f Time: %10.4f+-%10.4f mus\n", + mRefMatch, getChi2Refit(), mTimeMUS.getTimeStamp(), mTimeMUS.getTimeStampError()); + o2::track::TrackParCov::print(); +} diff --git a/DataFormats/Reconstruction/src/V0.cxx b/DataFormats/Reconstruction/src/V0.cxx index 0fee7300a103c..0956b3482f674 100644 --- a/DataFormats/Reconstruction/src/V0.cxx +++ b/DataFormats/Reconstruction/src/V0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,11 +13,21 @@ using namespace o2::dataformats; -V0::V0(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, +V0::V0(const std::array<float, 3>& xyz, const std::array<float, 3>& pxyz, const std::array<float, 6>& covxyz, const o2::track::TrackParCov& trPos, const o2::track::TrackParCov& trNeg, - GIndex trPosID, GIndex trNegID) - : o2::track::TrackParCov{xyz, pxyz, 0, false}, mProngIDs{trPosID, trNegID}, mProngs{trPos, trNeg} + GIndex trPosID, GIndex trNegID, o2::track::PID pid) + : mProngIDs{trPosID, trNegID}, mProngs{trPos, trNeg} { + std::array<float, 21> covV{}, covN{}; + trPos.getCovXYZPxPyPzGlo(covV); + trPos.getCovXYZPxPyPzGlo(covN); + for (int i = 0; i < 21; i++) { + covV[i] += covN[i]; + } + for (int i = 0; i < 6; i++) { + covV[i] = covxyz[i]; + } + this->set(xyz, pxyz, covV, trPos.getCharge() + trNeg.getCharge(), true, pid); } float V0::calcMass2(float massPos2, float massNeg2) const diff --git a/DataFormats/Reconstruction/src/Vertex.cxx b/DataFormats/Reconstruction/src/Vertex.cxx index b6165566e8aa1..df0448bf4e908 100644 --- a/DataFormats/Reconstruction/src/Vertex.cxx +++ b/DataFormats/Reconstruction/src/Vertex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ namespace o2 namespace dataformats { -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::string VertexBase::asString() const { diff --git a/DataFormats/Reconstruction/src/VtxTrackIndex.cxx b/DataFormats/Reconstruction/src/VtxTrackIndex.cxx index 4c75f81d4cb1f..33b96ce9033e2 100644 --- a/DataFormats/Reconstruction/src/VtxTrackIndex.cxx +++ b/DataFormats/Reconstruction/src/VtxTrackIndex.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// @file VtxTrackIndex.h -/// \brief Index of track attached to vertx: index in its proper container, container source and flags +/// \brief Extention of GlobalTrackID by flags relevant for verter-track association /// \author ruben.shahoyan@cern.ch #include "ReconstructionDataFormats/VtxTrackIndex.h" @@ -19,21 +20,3 @@ #include <bitset> using namespace o2::dataformats; - -std::string VtxTrackIndex::asString() const -{ - std::bitset<NBitsFlags()> bits{getFlags()}; - return fmt::format("[{:d}/{:d}/{:s}]", getIndex(), getSource(), bits.to_string()); -} - -std::ostream& o2::dataformats::operator<<(std::ostream& os, const o2::dataformats::VtxTrackIndex& v) -{ - // stream itself - os << v.asString(); - return os; -} - -void VtxTrackIndex::print() const -{ - LOG(INFO) << asString(); -} diff --git a/DataFormats/Reconstruction/src/VtxTrackRef.cxx b/DataFormats/Reconstruction/src/VtxTrackRef.cxx index d1b0d59dec0b9..2ded10b8afe59 100644 --- a/DataFormats/Reconstruction/src/VtxTrackRef.cxx +++ b/DataFormats/Reconstruction/src/VtxTrackRef.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,26 +18,48 @@ #include <fmt/printf.h> #include <iostream> #include <bitset> +#include <climits> using namespace o2::dataformats; -std::string VtxTrackRef::asString() const +std::string VtxTrackRef::asString(bool skipEmpty) const { - std::string str = fmt::format("1st entry: {:d} ", getFirstEntry()); + std::string str = mVtxID < 0 ? "Orphan " : fmt::format("Vtx {:3d}", mVtxID); + fmt::format(" : 1st entry: {:d} ", getFirstEntry()); for (int i = 0; i < VtxTrackIndex::NSources; i++) { - str += fmt::format(", N{:s} : {:d}", VtxTrackIndex::getSourceName(i), getEntriesOfSource(i)); + if (!skipEmpty || getEntriesOfSource(i)) { + str += fmt::format(", N{:s} : {:d}", VtxTrackIndex::getSourceName(i), getEntriesOfSource(i)); + } } return str; } +// set the last +1 element index and finalize all references +void VtxTrackRef::print(bool skipEmpty) const +{ + LOG(INFO) << asString(skipEmpty); +} + +// set the last +1 element index and check consistency +void VtxTrackRef::setEnd(int end) +{ + if (end <= 0) { + return; // empty + } + setEntries(end - getFirstEntry()); + for (int i = VtxTrackIndex::NSources - 1; i--;) { + if (getFirstEntryOfSource(i) < 0) { + throw std::runtime_error(fmt::format("1st entry for source {:d} was not set", i)); + } + if (getEntriesOfSource(i) < 0) { + throw std::runtime_error(fmt::format("Source {:d} has negative number of entrie", getEntriesOfSource(i))); + } + } +} + std::ostream& o2::dataformats::operator<<(std::ostream& os, const o2::dataformats::VtxTrackRef& v) { // stream itself os << v.asString(); return os; } - -void VtxTrackRef::print() const -{ - LOG(INFO) << asString(); -} diff --git a/DataFormats/Reconstruction/test/testLTOFIntegration.cxx b/DataFormats/Reconstruction/test/testLTOFIntegration.cxx index ae435570996a2..bb65c60d08d18 100644 --- a/DataFormats/Reconstruction/test/testLTOFIntegration.cxx +++ b/DataFormats/Reconstruction/test/testLTOFIntegration.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,8 +33,8 @@ BOOST_AUTO_TEST_CASE(TrackLTIntegral) const int nStep = 100; const float dx2x0 = 0.01f; for (int i = 0; i < nStep; i++) { - lt.addStep(1., trc); - lt1.addStep(1., trc1); + lt.addStep(1., trc.getP2Inv()); + lt1.addStep(1., trc1.getP2Inv()); lt1.addX2X0(dx2x0); } trc.printParam(); diff --git a/DataFormats/Reconstruction/test/testVertex.cxx b/DataFormats/Reconstruction/test/testVertex.cxx index 60300c6c292e6..010c21f401a5a 100644 --- a/DataFormats/Reconstruction/test/testVertex.cxx +++ b/DataFormats/Reconstruction/test/testVertex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/TimeFrame/CMakeLists.txt b/DataFormats/TimeFrame/CMakeLists.txt index 65dddd10df872..f0649731ccb2c 100644 --- a/DataFormats/TimeFrame/CMakeLists.txt +++ b/DataFormats/TimeFrame/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TimeFrame SOURCES src/TimeFrame.cxx diff --git a/DataFormats/TimeFrame/include/TimeFrame/TimeFrame.h b/DataFormats/TimeFrame/include/TimeFrame/TimeFrame.h index ee7404ebc5aac..815bfbde09c45 100644 --- a/DataFormats/TimeFrame/include/TimeFrame/TimeFrame.h +++ b/DataFormats/TimeFrame/include/TimeFrame/TimeFrame.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/TimeFrame/src/TimeFrame.cxx b/DataFormats/TimeFrame/src/TimeFrame.cxx index 1f094f0f642d9..c28a82dd5ad27 100644 --- a/DataFormats/TimeFrame/src/TimeFrame.cxx +++ b/DataFormats/TimeFrame/src/TimeFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/TimeFrame/src/TimeFrameLinkDef.h b/DataFormats/TimeFrame/src/TimeFrameLinkDef.h index de8a221d9ffad..5a1f194a693f5 100644 --- a/DataFormats/TimeFrame/src/TimeFrameLinkDef.h +++ b/DataFormats/TimeFrame/src/TimeFrameLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/TimeFrame/test/TimeFrameTest.cxx b/DataFormats/TimeFrame/test/TimeFrameTest.cxx index f48fb52e6d8df..41a78dd1217a3 100644 --- a/DataFormats/TimeFrame/test/TimeFrameTest.cxx +++ b/DataFormats/TimeFrame/test/TimeFrameTest.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/common/CMakeLists.txt b/DataFormats/common/CMakeLists.txt index f1c4e4eda918e..54084248b551e 100644 --- a/DataFormats/common/CMakeLists.txt +++ b/DataFormats/common/CMakeLists.txt @@ -1,30 +1,33 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CommonDataFormat SOURCES src/InteractionRecord.cxx src/BunchFilling.cxx src/FlatHisto1D.cxx src/FlatHisto2D.cxx + src/AbstractRefAccessor.cxx PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::GPUCommon - ROOT::Core FairRoot::Base ms_gsl::ms_gsl) + ROOT::Core FairRoot::Base O2::MathUtils Microsoft.GSL::GSL) o2_target_root_dictionary(CommonDataFormat HEADERS include/CommonDataFormat/TimeStamp.h include/CommonDataFormat/EvIndex.h include/CommonDataFormat/RangeReference.h include/CommonDataFormat/InteractionRecord.h + include/CommonDataFormat/IRFrame.h include/CommonDataFormat/BunchFilling.h include/CommonDataFormat/AbstractRef.h include/CommonDataFormat/FlatHisto1D.h - include/CommonDataFormat/FlatHisto2D.h) + include/CommonDataFormat/FlatHisto2D.h) o2_add_test(TimeStamp SOURCES test/testTimeStamp.cxx @@ -40,3 +43,8 @@ o2_add_test(FlatHisto SOURCES test/testFlatHisto.cxx COMPONENT_NAME CommonDataFormat PUBLIC_LINK_LIBRARIES O2::CommonDataFormat) + +o2_add_test(AbstractRefAccessor + SOURCES test/testAbstractRefAccessor.cxx + COMPONENT_NAME CommonDataFormat + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat) diff --git a/DataFormats/common/include/CommonDataFormat/AbstractRef.h b/DataFormats/common/include/CommonDataFormat/AbstractRef.h index 70fdc16735902..7154fd5506393 100644 --- a/DataFormats/common/include/CommonDataFormat/AbstractRef.h +++ b/DataFormats/common/include/CommonDataFormat/AbstractRef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,9 @@ #ifndef ALICEO2_ABSTRACT_REF_H #define ALICEO2_ABSTRACT_REF_H -#include <Rtypes.h> +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" +#include "GPUCommonTypeTraits.h" namespace o2 { @@ -28,6 +31,7 @@ class AbstractRef template <int NBIT> static constexpr auto MVAR() { + static_assert(NBIT <= 64, "> 64 bits not supported"); typename std::conditional<(NBIT > 32), uint64_t, typename std::conditional<(NBIT > 16), uint32_t, typename std::conditional<(NBIT > 8), uint16_t, uint8_t>::type>::type>::type tp = 0; return tp; } @@ -46,34 +50,39 @@ class AbstractRef static constexpr int NBitsSource() { return NBSrc; } static constexpr int NBitsFlags() { return NBFlg; } - AbstractRef() = default; + GPUdDefault() AbstractRef() = default; - AbstractRef(Idx_t idx) { setIndex(idx); } - - AbstractRef(Idx_t idx, Src_t src) { set(idx, src); } + GPUdi() AbstractRef(Idx_t idx, Src_t src) { set(idx, src); } + GPUdi() AbstractRef(Base_t raw) : mRef(raw) {} + GPUdDefault() AbstractRef(const AbstractRef& src) = default; // - Idx_t getIndex() const { return static_cast<Idx_t>(mRef & IdxMask); } - void setIndex(Idx_t idx) { mRef = (mRef & (BaseMask & ~IdxMask)) | (IdxMask & idx); } + GPUdi() Idx_t getIndex() const { return static_cast<Idx_t>(mRef & IdxMask); } + GPUdi() void setIndex(Idx_t idx) { mRef = (mRef & (BaseMask & ~IdxMask)) | (IdxMask & idx); } // - Src_t getSource() const { return static_cast<Idx_t>((mRef >> NBIdx) & SrcMask); } - void setSource(Src_t src) { mRef = (mRef & (BaseMask & ~(SrcMask << NBIdx))) | ((SrcMask & src) << NBIdx); } + GPUdi() Src_t getSource() const { return static_cast<Idx_t>((mRef >> NBIdx) & SrcMask); } + GPUdi() void setSource(Src_t src) { mRef = (mRef & (BaseMask & ~(SrcMask << NBIdx))) | ((SrcMask & src) << NBIdx); } // - Flg_t getFlags() const { return static_cast<Flg_t>((mRef >> (NBIdx + NBSrc)) & FlgMask); } - void setFlags(Flg_t f) { mRef = (mRef & (BaseMask & ~(FlgMask << (NBIdx + NBSrc)))) | ((FlgMask & f) << NBIdx); } - bool testBit(int i) const { return (mRef >> (NBIdx + NBSrc)) & ((0x1U << i) & FlgMask); } - void setBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))) | (((0x1U << i) & FlgMask) << (NBIdx + NBSrc)); } - void resetBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))); } - void set(Idx_t idx, Src_t src) { mRef = (mRef & (BaseMask & ~((SrcMask << NBIdx) | (BaseMask & ~IdxMask)))) | ((SrcMask & Src_t(src)) << NBIdx) | (IdxMask & Idx_t(idx)); } - - Base_t getRaw() const { return mRef; } - - operator Base_t() const { return mRef; } + GPUdi() Flg_t getFlags() const { return static_cast<Flg_t>((mRef >> (NBIdx + NBSrc)) & FlgMask); } + GPUdi() void setFlags(Flg_t f) { mRef = (mRef & (BaseMask & ~(FlgMask << (NBIdx + NBSrc)))) | ((FlgMask & f) << NBIdx); } + GPUdi() bool testBit(int i) const { return (mRef >> (NBIdx + NBSrc)) & ((0x1U << i) & FlgMask); } + GPUdi() void setBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))) | (((0x1U << i) & FlgMask) << (NBIdx + NBSrc)); } + GPUdi() void resetBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))); } + GPUdi() void set(Idx_t idx, Src_t src) { mRef = (mRef & ((Base_t)FlgMask << (NBIdx + NBSrc))) | ((SrcMask & Src_t(src)) << NBIdx) | (IdxMask & Idx_t(idx)); } + + GPUdi() Base_t getRaw() const { return mRef; } + GPUdi() void setRaw(Base_t v) { mRef = v; } + GPUdi() Base_t getRawWOFlags() const { return mRef & (IdxMask | (SrcMask << NBIdx)); } + GPUdi() bool isIndexSet() const { return getIndex() != IdxMask; } + GPUdi() bool isSourceSet() const { return getSource() != SrcMask; } + + GPUdi() bool operator==(const AbstractRef& o) const { return getRawWOFlags() == o.getRawWOFlags(); } + GPUdi() bool operator!=(const AbstractRef& o) const { return !operator==(o); } protected: - Base_t mRef = 0; // packed reference + Base_t mRef = IdxMask | (SrcMask << NBIdx); // packed reference, dummy by default ClassDefNV(AbstractRef, 1); }; diff --git a/DataFormats/common/include/CommonDataFormat/AbstractRefAccessor.h b/DataFormats/common/include/CommonDataFormat/AbstractRefAccessor.h new file mode 100644 index 0000000000000..9f6a8b1bd7d23 --- /dev/null +++ b/DataFormats/common/include/CommonDataFormat/AbstractRefAccessor.h @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file AbstractRefAccessor.h +/// \brief Accessor for objects of the same base class located in different containers +/// \author ruben.shahoyan@cern.ch + +#ifndef O2_POLYACCESSOR_H +#define O2_POLYACCESSOR_H + +#include <array> +#include <gsl/span> + +namespace o2 +{ +namespace dataformats +{ + +/* + AbstractRefAccessor allows to register multiple containers of objects convertible to type T and + to access them by providing a global index indicating the registered source ID and the + index within the original container +*/ + +template <typename T, int N> +class AbstractRefAccessor +{ + public: + /// register container in the accessor + template <typename C> + void registerContainer(const C& cont, int src) + { + mSizeOfs[src] = sizeof(typename std::remove_reference<decltype(cont)>::type::value_type); + mSizes[src] = cont.size(); + mContainerPtr[src] = reinterpret_cast<const char*>(cont.data()); + } + + bool isLoaded(int src) const + { + return mContainerPtr[src] != nullptr; + } + + /// get object as user provided type from explicitly provided source, index + template <typename U> + const U& get_as(int src, int idx) const + { + return *reinterpret_cast<const U*>(getPtr(src, idx)); + } + + /// get object as user provided type from explicitly provided source, index + template <typename U, typename I> + const U& get_as(const I globIdx) const + { + return get_as<U>(globIdx.getSource(), globIdx.getIndex()); + } + + /// get object from explicitly provided source, index + const T& get(int src, int idx) const + { + return get_as<T>(src, idx); + } + + /// get object from the global index + template <typename I> + const T& get(const I globIdx) const + { + return get_as<T>(globIdx.getSource(), globIdx.getIndex()); + } + + /// access particula source container as a span + template <typename U> + auto getSpan(int src) const + { + return getSize(src) ? gsl::span<const U>(reinterpret_cast<const U*>(getPtr(src, 0)), getSize(src)) : gsl::span<const U>(); + } + + size_t getSize(int src) const + { + return mSizes[src]; + } + + private: + auto getPtr(int src, int idx) const { return mContainerPtr[src] + mSizeOfs[src] * idx; } + + std::array<size_t, N> mSizeOfs{}; // sizeof for all containers elements + std::array<size_t, N> mSizes{}; // size of eack container + std::array<const char*, N> mContainerPtr{}; // pointers on attached containers +}; + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/common/include/CommonDataFormat/BunchFilling.h b/DataFormats/common/include/CommonDataFormat/BunchFilling.h index 30d50109a6c5c..077e3cc85b3f4 100644 --- a/DataFormats/common/include/CommonDataFormat/BunchFilling.h +++ b/DataFormats/common/include/CommonDataFormat/BunchFilling.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,37 +15,99 @@ #define ALICEO2_BUNCHFILLING_H #include "CommonConstants/LHCConstants.h" +#include <Rtypes.h> #include <bitset> #include <string> +#include <array> namespace o2 { class BunchFilling { public: - int getNBunches() const { return mPattern.count(); } - bool testBC(int bcID) const { return mPattern[bcID]; } - void setBC(int bcID, bool active = true); - void setBCTrain(int nBC, int bcSpacing, int firstBC); - void setBCTrains(int nTrains, int trainSpacingInBC, int nBC, int bcSpacing, int firstBC); - void print(int bcPerLine = 100) const; - const auto& getPattern() const { return mPattern; } - int getFirstFilledBC() const; - int getLastFilledBC() const; + using Pattern = std::bitset<o2::constants::lhc::LHCMaxBunches>; + + BunchFilling() = default; + BunchFilling(const std::string& beamA, const std::string& beanC); + BunchFilling(const std::string& interactingBC); + + // this is a pattern creator similar to Run1/2 AliTriggerBCMask + // The string has the following syntax: + // "25L 25(2H2LH 3(23HL))" + // - H/h -> 1 L/l -> 0 + // - spaces, new lines are white characters + static Pattern createPattern(const std::string& p); + + // get interacting bunches pattern (B) + const auto& getBCPattern() const { return mPattern; } + + // get pattern or clockwise (0, A) and anticlockwise (1, C) beams at P2 + const auto& getBeamPattern(int beam) const { return mBeamAC[beam]; } + + // get pattern of interacting BCs (-1) or beams filled BCs at P2 (0,1) + const auto& getPattern(int dir = -1) const { return dir < 0 ? getBCPattern() : getBeamPattern(dir); } + + // get number of interacting bunches (-1) and number of filled bunches for clockwise (0, A) and anticlockwise (1, C) beams + int getNBunches(int dir = -1) const { return dir < 0 ? mPattern.count() : mBeamAC[dir].count(); } + + // test interacting bunch + bool testInteractingBC(int bcID) const { return mPattern[bcID]; } + + // test bean bunch + bool testBeamBunch(int bcID, int dir) const { return mBeamAC[dir][bcID]; } + + // test interacting (-1) or clockwise (0, A) and anticlockwise (1, C) beams bunch + bool testBC(int bcID, int dir = -1) const { return dir < 0 ? testInteractingBC(bcID) : testBeamBunch(bcID, dir); } + + // BC setters, dir=-1 is for interacting bunches pattern, 0,1 for clockwise (A) and anticlockwise (C) beams + void setBC(int bcID, bool active = true, int dir = -1); + void setBCTrain(int nBC, int bcSpacing, int firstBC, int dir = -1); + void setBCTrains(int nTrains, int trainSpacingInBC, int nBC, int bcSpacing, int firstBC, int dir = -1); + + // new format for setting bunches pattern, see createPattern comments + void setBCFilling(const std::string& patt, int dir = -1); + + void setInteractingBCsFromBeams() { mPattern = getBeamPattern(0) & getBeamPattern(1); } + + int getFirstFilledBC(int dir = -1) const; + int getLastFilledBC(int dir = -1) const; + + // print pattern of bunches, dir=0,1: for A,C beams, dir=-1: for interacting BCs, otherwise: all + void print(int dir = -2, int bcPerLine = 100) const; + // set BC filling a la TPC TDR, 12 50ns trains of 48 BCs // but instead of uniform train spacing we add 96empty BCs after each train void setDefault() { - setBCTrains(12, 96, 48, 2, 0); + // setBCTrains(12, 96, 48, 2, 0); // obsolete way of setting the trains + setBCFilling("12(48(HL) 96L)", 0); + setBCFilling("12(48(HL) 96L)", 1); + setInteractingBCsFromBeams(); } + // merge this bunch filling with other + void mergeWith(o2::BunchFilling const& other); + static BunchFilling* loadFrom(const std::string& fileName, const std::string& objName = ""); private: - std::bitset<o2::constants::lhc::LHCMaxBunches> mPattern; + static bool parsePattern(const unsigned char*& input, Pattern& patt, int& ibit, int& level); - ClassDefNV(BunchFilling, 1); + Pattern mPattern{}; // Pattern of interacting BCs at P2 + std::array<Pattern, o2::constants::lhc::NBeamDirections> mBeamAC{}; // pattern of 2 beam bunches at P2 + + ClassDefNV(BunchFilling, 2); }; } // namespace o2 +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::BunchFilling> : std::true_type { +}; + +} // namespace framework + #endif diff --git a/DataFormats/common/include/CommonDataFormat/EvIndex.h b/DataFormats/common/include/CommonDataFormat/EvIndex.h index 882b1694d2de7..c22ebc5893a08 100644 --- a/DataFormats/common/include/CommonDataFormat/EvIndex.h +++ b/DataFormats/common/include/CommonDataFormat/EvIndex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,15 +44,9 @@ class EvIndex void shiftEvent(E inc) { mEvent += inc; } void shiftIndex(I inc) { mIndex += inc; } - void clear() - { - mEvent = 0; - mIndex = 0; - } - private: - E mEvent = 0; ///< ID of event or chunk or message containing referred object - I mIndex = 0; ///< index in the event + E mEvent{}; ///< ID of event or chunk or message containing referred object + I mIndex{}; ///< index in the event ClassDefNV(EvIndex, 1); }; diff --git a/DataFormats/common/include/CommonDataFormat/FlatHisto1D.h b/DataFormats/common/include/CommonDataFormat/FlatHisto1D.h index 18407f295cbf4..65d00b040f010 100644 --- a/DataFormats/common/include/CommonDataFormat/FlatHisto1D.h +++ b/DataFormats/common/include/CommonDataFormat/FlatHisto1D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,8 +19,11 @@ #include <Rtypes.h> #include <vector> #include <gsl/span> -#include <TH1F.h> #include <type_traits> +#include <cassert> +#include <memory> + +class TH1F; namespace o2 { @@ -50,34 +54,39 @@ class FlatHisto1D XMin, XMax, BinSize, - BinSizeInv, NServiceSlots }; FlatHisto1D() = default; + FlatHisto1D(int nb, T xmin, T xmax); + FlatHisto1D(const gsl::span<const T> ext) { adoptExternal(ext); } + void adoptExternal(const gsl::span<const T> ext); + void init() + { + // when reading from file, need to call this method to make it operational + assert(mContainer.size() > NServiceSlots); + init(gsl::span<const T>(mContainer.data(), mContainer.size())); + } - FlatHisto1D(int nb, T xmin, T xmax) + int getNBins() const { return mNBins; } + T getXMin() const { return mXMin; } + T getXMax() const { return mXMax; } + T getBinSize() const { return mBinSize; } + T getBinSizeInv() const { return mBinSizeInv; } + + T getBinContent(uint32_t ib) const { - assert(nb > 0 && xmin < xmax); - mData.resize(nb + NServiceSlots, 0.); - mData[NBins] = nb; - mData[XMin] = xmin; - mData[XMax] = xmax; - mData[BinSize] = (xmax - xmin) / nb; - mData[BinSizeInv] = nb / (xmax - xmin); - init(); + assert(ib < getNBins()); + return mDataPtr[ib]; } - FlatHisto1D(const gsl::span<const T> ext) + T getBinContentForX(T x) const { - adoptExternal(ext); + auto bin = getBin(x); + return isValidBin(bin) ? getBinContent(bin) : 0; } - int getNBins() const { return mNBins; } - T getXMin() const { return mDataView[XMin]; } - T getXMax() const { return mDataView[XMax]; } - T getBinSize() const { return mDataView[BinSize]; } - T getBinContent(uint32_t ib) const { return ib < mNBins ? mDataView[ib + NServiceSlots] : 0.; } - T getBinContentForX(T x) const { getBinContent(getBin(x)); } + bool isValidBin(uint32_t bin) const { return bin < getNBins(); } + bool isBinEmpty(uint32_t bin) const { return getBinContent(bin) == 0; } T getBinStart(int i) const { @@ -97,75 +106,48 @@ class FlatHisto1D return getXMin() + (i + 1) * getBinSize(); } - void add(const FlatHisto1D& other) - { - assert(getNBins() == other.getNBins() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && canFill()); - int last = NServiceSlots + getNBins(); - const auto& otherView = other.getView(); - for (int i = NServiceSlots; i < last; i++) { - mData[i] += otherView[i]; - } - } + void add(const FlatHisto1D& other); - void subtract(const FlatHisto1D& other) - { - assert(getNBins() == other.getNBins() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && canFill()); - int last = NServiceSlots + getNBins(); - const auto& otherView = other.getView(); - for (int i = NServiceSlots; i < last; i++) { - mData[i] -= otherView[i]; - } - } + void subtract(const FlatHisto1D& other); void setBinContent(uint32_t bin, T w) { - assert(canFill() && bin < mNBins); - mData[bin + NServiceSlots] = w; + assert(canFill() && isValidBin(bin)); + mDataPtr[bin] = w; } void clear() { assert(canFill()); - memset(mData.data() + NServiceSlots, 0, sizeof(T) * getNBins()); + memset(mDataPtr, 0, sizeof(T) * getNBins()); } - T getSum() const - { - T sum = 0; - for (int i = getNBins(); i--;) { - sum += getBinContent(i); - } - return sum; - } + T getSum() const; - void adoptExternal(const gsl::span<const T> ext) + int fill(T x) { - assert(ext.size() > NServiceSlots); - mData.clear(); - mDataView = ext; - mNBins = (int)mDataView[NBins]; - } - - void init() - { // when reading from file, need to call this method to make it operational - assert(mData.size() > NServiceSlots); - mDataView = gsl::span<const T>(mData.data(), mData.size()); - mNBins = (int)mData[NBins]; + uint32_t bin = getBin(x); + if (isValidBin(bin)) { + mDataPtr[bin]++; + return bin; + } + return -1; } - void fill(T x) + int fill(T x, T w) { uint32_t bin = getBin(x); - if (bin < mNBins) { - mData[NServiceSlots + bin]++; + if (isValidBin(bin)) { + mDataPtr[bin] += w; + return bin; } + return -1; } - void fill(T x, T w) + void fillBin(uint32_t bin, T w) { - uint32_t bin = getBin(x); - if (bin < mNBins) { - mData[NServiceSlots + bin] += w; + if (isValidBin(bin)) { + mDataPtr[bin] += w; } } @@ -178,30 +160,25 @@ class FlatHisto1D bool canFill() const { // histo can be filled only if hase its own data, otherwise only query can be done on the view - return mData.size() > NServiceSlots; + return mContainer.size() > NServiceSlots; } - TH1F createTH1F(const std::string& name = "histo1d") - { - TH1F h(name.c_str(), name.c_str(), getNBins(), getXMin(), getXMax()); - for (int i = getNBins(); i--;) { - auto w = getBinContent(i); - if (w) { - h.SetBinContent(i + 1, w); - } - } - return h; - } + std::unique_ptr<TH1F> createTH1F(const std::string& name = "histo1d"); - const std::vector<T>& getBase() const { return mData; } - gsl::span<const T> getView() const { return mDataView; } + const std::vector<T>& getBase() const { return mContainer; } + gsl::span<const T> getView() const { return mContainerView; } protected: - T getBinSizeInv() const { return mDataView[BinSizeInv]; } - - std::vector<T> mData; // data to fill - gsl::span<const T> mDataView; //! - int mNBins = 0; //! + void init(const gsl::span<const T> ext); + + std::vector<T> mContainer; // global container + gsl::span<const T> mContainerView{}; //! pointer on container + T* mDataPtr{}; //! histo data + T mXMin{}; //! + T mXMax{}; //! + T mBinSize{}; //! + T mBinSizeInv{}; //! + int mNBins{}; //! ClassDefNV(FlatHisto1D, 1); }; diff --git a/DataFormats/common/include/CommonDataFormat/FlatHisto2D.h b/DataFormats/common/include/CommonDataFormat/FlatHisto2D.h index 8da1daf658162..7db9051b105ce 100644 --- a/DataFormats/common/include/CommonDataFormat/FlatHisto2D.h +++ b/DataFormats/common/include/CommonDataFormat/FlatHisto2D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,8 +19,12 @@ #include <Rtypes.h> #include <vector> #include <gsl/span> -#include <TH2F.h> #include <type_traits> +#include <cassert> +#include <memory> + +class TH1F; +class TH2F; namespace o2 { @@ -54,172 +59,140 @@ class FlatHisto2D YMax, BinSizeX, BinSizeY, - BinSizeXInv, - BinSizeYInv, NServiceSlots }; FlatHisto2D() = default; - - FlatHisto2D(int nbx, T xmin, T xmax, int nby, T ymin, T ymax) + FlatHisto2D(int nbx, T xmin, T xmax, int nby, T ymin, T ymax); + FlatHisto2D(const gsl::span<const T> ext) { adoptExternal(ext); } + void adoptExternal(const gsl::span<const T> ext); + void init() { - assert(nbx > 0 && xmin < xmax); - assert(nby > 0 && ymin < ymax); - mData.resize(nbx * nby + NServiceSlots, 0.); - mData[NBinsX] = nbx; - mData[NBinsY] = nby; - mData[XMin] = xmin; - mData[XMax] = xmax; - mData[YMin] = ymin; - mData[YMax] = ymax; - mData[BinSizeX] = (xmax - xmin) / nbx; - mData[BinSizeXInv] = nbx / (xmax - xmin); - mData[BinSizeY] = (ymax - ymin) / nby; - mData[BinSizeYInv] = nby / (ymax - ymin); - init(); + // when reading from file, need to call this method to make it operational + assert(mContainer.size() > NServiceSlots); + init(gsl::span<const T>(mContainer.data(), mContainer.size())); } - FlatHisto2D(const gsl::span<const T> ext) + int getNBinsX() const { return mNBinsX; } + int getNBinsY() const { return mNBinsY; } + int getNBins() const { return getNBinsX() * getNBinsY(); } + + T getXMin() const { return mXMin; } + T getXMax() const { return mXMax; } + T getYMin() const { return mYMin; } + T getYMax() const { return mYMax; } + T getBinSizeX() const { return mBinSizeX; } + T getBinSizeY() const { return mBinSizeY; } + T getBinSizeXInv() const { return mBinSizeXInv; } + T getBinSizeYInv() const { return mBinSizeYInv; } + + T getBinContent(uint32_t ib) const { - adoptExternal(ext); + assert(ib < getNBins()); + return mDataPtr[ib]; } - int getNBinsX() const { return mNBinsX; } - int getNBinsY() const { return mNBinsY; } - int getNBins() const { return mNBins; } - T getXMin() const { return mDataView[XMin]; } - T getXMax() const { return mDataView[XMax]; } - T getYMin() const { return mDataView[YMin]; } - T getYMax() const { return mDataView[YMax]; } - T getBinSizeX() const { return mDataView[BinSizeX]; } - T getBinSizeY() const { return mDataView[BinSizeY]; } - T getBinContent(uint32_t ib) const { return ib < mNBins ? mDataView[ib + NServiceSlots] : 0.; } T getBinContent(uint32_t ibx, uint32_t iby) const { return getBinContent(getGlobalBin(ibx, iby)); } + T getBinContentForXY(T x, T y) const { return getBinContent(getBinX(x), getBinY(y)); } - T getBinStartX(int i) const + bool isValidBin(uint32_t bin) const { return bin < getNBins(); } + bool isBinEmpty(uint32_t bin) const { return getBinContent(bin) == 0; } + + T getBinXStart(int i) const { assert(i < getNBinsX()); return getXMin() + i * getBinSizeX(); } - T getBinCenterX(int i) const + T getBinXCenter(int i) const { assert(i < getNBinsX()); return getXMin() + (i + 0.5) * getBinSizeX(); } - T getBinEndX(int i) const + T getBinXEnd(int i) const { assert(i < getNBinsX()); return getXMin() + (i + 1) * getBinSizeX(); } - T getBinStartY(int i) const + T getBinYStart(int i) const { assert(i < getNBinsY()); return getYMin() + i * getBinSizeY(); } - T getBinCenterY(int i) const + T getBinYCenter(int i) const { assert(i < getNBinsY()); return getYMin() + (i + 0.5) * getBinSizeY(); } - T getBinEndY(int i) const + T getBinYEnd(int i) const { assert(i < getNBinsY()); return getYMin() + (i + 1) * getBinSizeY(); } - void add(const FlatHisto2D& other) - { - assert(getNBinsX() == other.getNBinsX() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && - getNBinsY() == other.getNBinsY() && getYMin() == other.getYMin() && getYMax() == other.getYMax() && - canFill()); - int last = NServiceSlots + getNBins(); - const auto& otherView = other.getView(); - for (int i = NServiceSlots; i < last; i++) { - mData[i] += otherView[i]; - } - } + int getXBin(uint32_t i) const { return i / getNBinsY(); } + int getYBin(uint32_t i) const { return i % getNBinsY(); } - void subtract(const FlatHisto2D& other) - { - assert(getNBinsX() == other.getNBinsX() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && - getNBinsY() == other.getNBinsY() && getYMin() == other.getYMin() && getYMax() == other.getYMax() && - canFill()); - int last = NServiceSlots + getNBins(); - const auto& otherView = other.getView(); - for (int i = NServiceSlots; i < last; i++) { - mData[i] -= otherView[i]; - } - } + void add(const FlatHisto2D& other); + + void subtract(const FlatHisto2D& other); void setBinContent(uint32_t bin, T w) { - assert(canFill()); - if (bin < getNBins()) { - mData[bin + NServiceSlots] = w; - } + assert(canFill() && isValidBin(bin)); + mDataPtr[bin] = w; } void setBinContent(uint32_t binX, uint32_t binY, T w) { - assert(canFill()); auto bin = getGlobalBin(binX, binY); - if (bin < getNBins()) { - mData[+NServiceSlots] = w; - } + setBinContent(bin, w); } void clear() { assert(canFill()); - memset(mData.data() + NServiceSlots, 0, sizeof(T) * getNBins()); + memset(mDataPtr, 0, sizeof(T) * getNBins()); } - T getSum() const + T getSum() const; + + int fill(T x, T y) { - T sum = 0; - for (int i = getNBins(); i--;) { - sum += getBinContent(i); + uint32_t bin = getBin(x, y); + if (isValidBin(bin)) { + mDataPtr[bin]++; + return bin; } - return sum; + return -1; } - void adoptExternal(const gsl::span<const T> ext) + int fill(T x, T y, T w) { - assert(ext.size() > NServiceSlots); - mData.clear(); - mDataView = ext; - mNBinsX = (int)mDataView[NBinsX]; - mNBinsY = (int)mDataView[NBinsY]; - mNBins = mNBinsX * mNBinsY; - } - - void init() - { // when reading from file, need to call this method to make it operational - assert(mData.size() > NServiceSlots); - mDataView = gsl::span<const T>(mData.data(), mData.size()); - mNBinsX = (int)mData[NBinsX]; - mNBinsY = (int)mData[NBinsY]; - mNBins = mNBinsX * mNBinsY; + uint32_t bin = getBin(x, y); + if (isValidBin(bin)) { + mDataPtr[bin] += w; + return bin; + } + return -1; } - void fill(T x, T y) + void fillBin(uint32_t bin, T w) { - uint32_t bin = getBin(x, y); - if (bin < mNBins) { - mData[NServiceSlots + bin]++; + if (isValidBin(bin)) { + mDataPtr[bin] += w; } } - void fill(T x, T y, T w) + void fillBin(uint32_t bx, uint32_t by, T w) { - uint32_t bin = getBin(x, y); - if (bin < mNBins) { - mData[NServiceSlots + bin] += w; + auto bin = getGlobalBin(bx, by); + if (isValidBin(bin)) { + mDataPtr[bin] += w; } } @@ -244,54 +217,42 @@ class FlatHisto2D bool canFill() const { // histo can be filled only if hase its own data, otherwise only query can be done on the view - return mData.size() > NServiceSlots; + return mContainer.size() > NServiceSlots; } gsl::span<const T> getSliceY(uint32_t binX) const { - int offs = NServiceSlots + binX * getNBinsY(); - return binX < getNBinsX() ? gsl::span<const T>(&mDataView[offs], getNBinsY()) : gsl::span<const T>(); + int offs = binX * getNBinsY(); + return binX < getNBinsX() ? gsl::span<const T>(&mDataPtr[offs], getNBinsY()) : gsl::span<const T>(); } - TH1F createSliceYTH1F(uint32_t binX, const std::string& name = "histo2dslice") const - { - TH1F h(name.c_str(), name.c_str(), getNBinsY(), getYMin(), getYMax()); - if (binX < getNBinsX()) { - for (int i = getNBinsY(); i--;) { - h.SetBinContent(i + 1, getBinContent(binX, i)); - } - } - return h; - } + std::unique_ptr<TH2F> createTH2F(const std::string& name = "histo2d"); - TH2F createTH2F(const std::string& name = "histo2d") - { - TH2F h(name.c_str(), name.c_str(), getNBinsX(), getXMin(), getXMax(), getNBinsY(), getYMin(), getYMax()); - for (int i = getNBinsX(); i--;) { - for (int j = getNBinsY(); j--;) { - auto w = getBinContent(i, j); - if (w) { - h.SetBinContent(i + 1, j + 1, w); - } - } - } - return h; - } + std::unique_ptr<TH1F> createSliceXTH1F(uint32_t binX, const std::string& name = "histo2dsliceX") const; + std::unique_ptr<TH1F> createSliceYTH1F(uint32_t binX, const std::string& name = "histo2dsliceY") const; - const std::vector<T>& getBase() const { return mData; } - gsl::span<const T> getView() const { return mDataView; } + const std::vector<T>& getBase() const { return mContainer; } + gsl::span<const T> getView() const { return mContainerView; } int getGlobalBin(uint32_t binX, uint32_t binY) const { return binX * getNBinsY() + binY; } protected: - T getBinSizeXInv() const { return mDataView[BinSizeXInv]; } - T getBinSizeYInv() const { return mDataView[BinSizeYInv]; } - - std::vector<T> mData; // data to fill - gsl::span<const T> mDataView; //! - int mNBinsX = 0; //! - int mNBinsY = 0; //! - int mNBins = 0; //! + void init(const gsl::span<const T> ext); + + std::vector<T> mContainer; // data to fill + gsl::span<const T> mContainerView; //! + T* mDataPtr{}; //! histo data + T mXMin{}; //! + T mXMax{}; //! + T mYMin{}; //! + T mYMax{}; //! + T mBinSizeX{}; //! + T mBinSizeY{}; //! + T mBinSizeXInv{}; //! + T mBinSizeYInv{}; //! + int mNBinsX{}; //! + int mNBinsY{}; //! + int mNBins{}; //! ClassDefNV(FlatHisto2D, 1); }; diff --git a/DataFormats/common/include/CommonDataFormat/IRFrame.h b/DataFormats/common/include/CommonDataFormat/IRFrame.h new file mode 100644 index 0000000000000..696ddecdf9359 --- /dev/null +++ b/DataFormats/common/include/CommonDataFormat/IRFrame.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IRFrame.h +/// \brief Class to delimit start and end IR of certain time period +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_IRFRAME_H +#define ALICEO2_IRFRAME_H + +#include "MathUtils/Primitive2D.h" +#include "CommonDataFormat/InteractionRecord.h" + +namespace o2 +{ +namespace dataformats +{ + +// Bracket of 2 IRs. +// We could just alias it to the bracket specialization, but this would create +// problems with fwd.declaration +struct IRFrame : public o2::math_utils::detail::Bracket<o2::InteractionRecord> { + using o2::math_utils::detail::Bracket<o2::InteractionRecord>::Bracket; + ClassDefNV(IRFrame, 1); +}; + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h index 841197c2af4ee..849f06b8c228e 100644 --- a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h +++ b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #define ALICEO2_INTERACTIONRECORD_H #include "GPUCommonRtypes.h" -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE #include <iosfwd> #include <cstdint> #endif @@ -107,7 +108,7 @@ struct InteractionRecord { float differenceInBCMS(const InteractionRecord& other) const { // return difference in bunch-crossings in ms - return differenceInBC(other) * o2::constants::lhc::LHCBunchSpacingMS; + return differenceInBC(other) * o2::constants::lhc::LHCBunchSpacingMUS; } int64_t toLong() const @@ -246,7 +247,7 @@ struct InteractionRecord { return InteractionRecord(l % o2::constants::lhc::LHCMaxBunches, l / o2::constants::lhc::LHCMaxBunches); } -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE void print() const; std::string asString() const; friend std::ostream& operator<<(std::ostream& stream, InteractionRecord const& ir); @@ -324,7 +325,7 @@ struct InteractionTimeRecord : public InteractionRecord { return !((*this) > other); } -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE void print() const; std::string asString() const; friend std::ostream& operator<<(std::ostream& stream, InteractionTimeRecord const& ir); @@ -334,4 +335,17 @@ struct InteractionTimeRecord : public InteractionRecord { }; } // namespace o2 +namespace std +{ +// defining std::hash for InteractionRecord to be used with std containers +template <> +struct hash<o2::InteractionRecord> { + public: + size_t operator()(const o2::InteractionRecord& ir) const + { + return ir.toLong(); + } +}; +} // namespace std + #endif diff --git a/DataFormats/common/include/CommonDataFormat/RangeReference.h b/DataFormats/common/include/CommonDataFormat/RangeReference.h index 1b2e77b229867..0308d3b8af937 100644 --- a/DataFormats/common/include/CommonDataFormat/RangeReference.h +++ b/DataFormats/common/include/CommonDataFormat/RangeReference.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #define ALICEO2_RANGEREFERENCE_H #include "GPUCommonRtypes.h" +#include "GPUCommonDef.h" namespace o2 { @@ -27,22 +29,23 @@ template <typename FirstEntry = int, typename NElem = int> class RangeReference { public: - RangeReference(FirstEntry ent, NElem n) { set(ent, n); } - RangeReference(const RangeReference<FirstEntry, NElem>& src) = default; - RangeReference() = default; - ~RangeReference() = default; - void set(FirstEntry ent, NElem n) + GPUd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } + GPUdDefault() RangeReference(const RangeReference<FirstEntry, NElem>& src) = default; + GPUdDefault() RangeReference() = default; + GPUdDefault() ~RangeReference() = default; + GPUd() void set(FirstEntry ent, NElem n) { mFirstEntry = ent; mEntries = n; } - void clear() { set(0, 0); } - FirstEntry getFirstEntry() const { return mFirstEntry; } - NElem getEntries() const { return mEntries; } - void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } - void setEntries(NElem n) { mEntries = n; } - void changeEntriesBy(NElem inc) { mEntries += inc; } - bool operator==(const RangeReference& other) const + GPUd() void clear() { set(0, 0); } + GPUd() FirstEntry getFirstEntry() const { return mFirstEntry; } + GPUd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } + GPUd() NElem getEntries() const { return mEntries; } + GPUd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } + GPUd() void setEntries(NElem n) { mEntries = n; } + GPUd() void changeEntriesBy(NElem inc) { mEntries += inc; } + GPUd() bool operator==(const RangeReference& other) const { return mFirstEntry == other.mFirstEntry && mEntries == other.mEntries; } @@ -58,34 +61,35 @@ class RangeReference template <int NBitsN> class RangeRefComp { - using Base = std::uint32_t; + using Base = unsigned int; private: static constexpr int NBitsTotal = sizeof(Base) * 8; static constexpr Base MaskN = ((0x1 << NBitsN) - 1); static constexpr Base MaskR = (~Base(0)) & (~MaskN); Base mData = 0; ///< packed 1st entry reference + N entries - void sanityCheck() + GPUd() void sanityCheck() { static_assert(NBitsN < NBitsTotal, "NBitsN too large"); } public: - RangeRefComp(int ent, int n) { set(ent, n); } - RangeRefComp() = default; - RangeRefComp(const RangeRefComp& src) = default; - void set(int ent, int n) + GPUd() RangeRefComp(int ent, int n) { set(ent, n); } + GPUdDefault() RangeRefComp() = default; + GPUdDefault() RangeRefComp(const RangeRefComp& src) = default; + GPUhd() void set(int ent, int n) { mData = (Base(ent) << NBitsN) + (Base(n) & MaskN); } - static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } - static constexpr Base getMaxEntries() { return MaskN; } - int getFirstEntry() const { return mData >> NBitsN; } - int getEntries() const { return mData & ((0x1 << NBitsN) - 1); } - void setFirstEntry(int ent) { mData = (Base(ent) << NBitsN) | (mData & MaskN); } - void setEntries(int n) { mData = (mData & MaskR) | (Base(n) & MaskN); } - void changeEntriesBy(int inc) { setEntries(getEntries() + inc); } - bool operator==(const RangeRefComp& other) const + GPUd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } + GPUd() static constexpr Base getMaxEntries() { return MaskN; } + GPUhd() int getFirstEntry() const { return mData >> NBitsN; } + GPUhd() int getEntries() const { return mData & ((0x1 << NBitsN) - 1); } + GPUhd() int getEntriesBound() const { return getFirstEntry() + getEntries(); } + GPUhd() void setFirstEntry(int ent) { mData = (Base(ent) << NBitsN) | (mData & MaskN); } + GPUhd() void setEntries(int n) { mData = (mData & MaskR) | (Base(n) & MaskN); } + GPUhd() void changeEntriesBy(int inc) { setEntries(getEntries() + inc); } + GPUhd() bool operator==(const RangeRefComp& other) const { return mData == other.mData; } diff --git a/DataFormats/common/include/CommonDataFormat/TimeStamp.h b/DataFormats/common/include/CommonDataFormat/TimeStamp.h index c3420d348c62c..486bba59656d4 100644 --- a/DataFormats/common/include/CommonDataFormat/TimeStamp.h +++ b/DataFormats/common/include/CommonDataFormat/TimeStamp.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,10 +41,10 @@ template <typename T, typename E> class TimeStampWithError : public TimeStamp<T> { public: - TimeStampWithError() = default; - TimeStampWithError(T t, E te) : TimeStamp<T>(t), mTimeStampError(te) {} - E getTimeStampError() const { return mTimeStampError; } - void setTimeStampError(E te) { mTimeStampError = te; } + GPUdDefault() TimeStampWithError() = default; + GPUd() TimeStampWithError(T t, E te) : TimeStamp<T>(t), mTimeStampError(te) {} + GPUdi() E getTimeStampError() const { return mTimeStampError; } + GPUdi() void setTimeStampError(E te) { mTimeStampError = te; } private: E mTimeStampError = 0; diff --git a/DataFormats/common/src/AbstractRefAccessor.cxx b/DataFormats/common/src/AbstractRefAccessor.cxx new file mode 100644 index 0000000000000..ddea96fe42e7d --- /dev/null +++ b/DataFormats/common/src/AbstractRefAccessor.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file AbstractRefAccessor.h +/// \brief Accessor for objects of the same base class located in different containers +/// \author ruben.shahoyan@cern.ch + +#include "CommonDataFormat/AbstractRefAccessor.h" diff --git a/DataFormats/common/src/BunchFilling.cxx b/DataFormats/common/src/BunchFilling.cxx index 818be2c9361b0..4709218f45d13 100644 --- a/DataFormats/common/src/BunchFilling.cxx +++ b/DataFormats/common/src/BunchFilling.cxx @@ -1,25 +1,42 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "FairLogger.h" +#include "Framework/Logger.h" #include "CommonDataFormat/BunchFilling.h" #include <TClass.h> #include <TFile.h> +#include <cctype> using namespace o2; //_________________________________________________ -int BunchFilling::getFirstFilledBC() const +BunchFilling::BunchFilling(const std::string& beamA, const std::string& beamC) +{ + setBCFilling(beamA, 0); + setBCFilling(beamC, 1); + setInteractingBCsFromBeams(); +} + +//_________________________________________________ +BunchFilling::BunchFilling(const std::string& interactingBC) +{ + setBCFilling(interactingBC, -1); + mBeamAC[0] = mBeamAC[1] = mPattern; +} + +//_________________________________________________ +int BunchFilling::getFirstFilledBC(int dir) const { for (int bc = 0; bc < o2::constants::lhc::LHCMaxBunches; bc++) { - if (testBC(bc)) { + if (testBC(bc, dir)) { return bc; } } @@ -27,10 +44,10 @@ int BunchFilling::getFirstFilledBC() const } //_________________________________________________ -int BunchFilling::getLastFilledBC() const +int BunchFilling::getLastFilledBC(int dir) const { for (int bc = o2::constants::lhc::LHCMaxBunches; bc--;) { - if (testBC(bc)) { + if (testBC(bc, dir)) { return bc; } } @@ -38,53 +55,83 @@ int BunchFilling::getLastFilledBC() const } //_________________________________________________ -void BunchFilling::setBC(int bcID, bool active) +void BunchFilling::setBC(int bcID, bool active, int dir) { // add interacting BC slot if (bcID >= o2::constants::lhc::LHCMaxBunches) { LOG(FATAL) << "BCid is limited to " << 0 << '-' << o2::constants::lhc::LHCMaxBunches - 1; } - mPattern.set(bcID, active); + if (dir < 0) { + mPattern.set(bcID, active); + } else { + mBeamAC[dir].set(bcID, active); + } +} + +//_________________________________________________ +void BunchFilling::mergeWith(o2::BunchFilling const& other) +{ + for (int bc = o2::constants::lhc::LHCMaxBunches; bc--;) { + for (int dir = -1; dir < 2; dir++) { + if (other.testBC(bc, dir)) { + // if the other one is filled we need to fill "this" also + setBC(bc, true, dir); + } + } + } } //_________________________________________________ -void BunchFilling::setBCTrain(int nBC, int bcSpacing, int firstBC) +void BunchFilling::setBCTrain(int nBC, int bcSpacing, int firstBC, int dir) { // add interacting BC train with given spacing starting at given place, i.e. // train with 25ns spacing should have bcSpacing = 1 for (int i = 0; i < nBC; i++) { - setBC(firstBC); + setBC(firstBC, dir); firstBC += bcSpacing; } } //_________________________________________________ -void BunchFilling::setBCTrains(int nTrains, int trainSpacingInBC, int nBC, int bcSpacing, int firstBC) +void BunchFilling::setBCTrains(int nTrains, int trainSpacingInBC, int nBC, int bcSpacing, int firstBC, int dir) { // add nTrains trains of interacting BCs with bcSpacing within the train and trainSpacingInBC empty slots // between the trains for (int it = 0; it < nTrains; it++) { - setBCTrain(nBC, bcSpacing, firstBC); + setBCTrain(nBC, bcSpacing, firstBC, dir); firstBC += nBC * bcSpacing + trainSpacingInBC; } } //_________________________________________________ -void BunchFilling::print(int bcPerLine) const +void BunchFilling::setBCFilling(const std::string& patt, int dir) { - bool endlOK = false; - for (int i = 0; i < o2::constants::lhc::LHCMaxBunches; i++) { - printf("%c", mPattern[i] ? '+' : '-'); - if (((i + 1) % bcPerLine) == 0) { - printf("\n"); - endlOK = true; - } else { - endlOK = false; + auto& dest = dir < 0 ? mPattern : mBeamAC[dir]; + dest = createPattern(patt); +} + +//_________________________________________________ +void BunchFilling::print(int dir, int bcPerLine) const +{ + const std::string names[3] = {"Interacting", "Beam-A", "Beam-C"}; + for (int id = -1; id < 2; id++) { + if (id == dir || (dir < -1 || dir > 1)) { + printf("%s bunches\n", names[id + 1].c_str()); + bool endlOK = false; + for (int i = 0; i < o2::constants::lhc::LHCMaxBunches; i++) { + printf("%c", testBC(i, id) ? '+' : '-'); + if (((i + 1) % bcPerLine) == 0) { + printf("\n"); + endlOK = true; + } else { + endlOK = false; + } + } + if (!endlOK) { + printf("\n"); + } } } - if (!endlOK) { - printf("\n"); - } } //_______________________________________________ @@ -104,3 +151,100 @@ BunchFilling* BunchFilling::loadFrom(const std::string& fileName, const std::str } return bf; } + +//_________________________________________________ +BunchFilling::Pattern BunchFilling::createPattern(const std::string& p) +{ + // create bit pattern from string according to convention of Run1/2: + // The string has the following syntax: + // "25L 25(2H2LH 3(23HL))" + // - H/h -> 1 L/l -> 0 + // - spaces, new lines are white characters + std::vector<unsigned char> input; + for (unsigned char c : p) { + if (c == '(' || c == ')' || std::isdigit(c)) { + input.push_back(c); + } else if (c == 'h' || c == 'H') { + input.push_back('H'); + } else if (c == 'l' || c == 'L') { + input.push_back('L'); + } else if (!std::isspace(c)) { + throw std::runtime_error(fmt::format("forbidden character ({}) in input string ({})", c, p)); + } + } + input.push_back(0); // flag the end + BunchFilling::Pattern patt; + int ibit = 0, level = 0; + const unsigned char* in = input.data(); + if (!parsePattern(in, patt, ibit, level)) { + throw std::runtime_error(fmt::format("failed to extract BC pattern from input string ({})", p)); + } + return patt; +} + +//_________________________________________________ +bool BunchFilling::parsePattern(const unsigned char*& input, BunchFilling::Pattern& patt, int& ibit, int& level) +{ + // this is analog of AliTriggerBCMask::Bcm2Bits + level++; + int repetion = 1; + auto setBunch = [&patt, &ibit](bool v) { + if (ibit < patt.size()) { + patt[ibit++] = v; + } else { + throw std::runtime_error(fmt::format("provided pattern overflow max bunch {}", patt.size())); + } + }; + while (1) { + if (*input == 0) { + if (level > 1) { + LOG(error) << "Missing )"; + return false; + } + break; + } + if (*input == 'H') { + for (int i = 0; i < repetion; i++) { + setBunch(true); + } + repetion = 1; + input++; + } else if (*input == 'L') { + for (int i = 0; i < repetion; i++) { + setBunch(false); + } + repetion = 1; + input++; + } else if (std::isdigit(*input)) { + repetion = int((*input++) - '0'); + while (*input && std::isdigit(*input)) { + repetion = repetion * 10 + int(*(input++) - '0'); + } + } else if (*input == '(') { + input++; + auto ibit1 = ibit; + if (!parsePattern(input, patt, ibit, level)) { + return false; + } + auto ibit2 = ibit; + for (int i = 0; i < repetion - 1; i++) { + for (int j = ibit1; j < ibit2; j++) { + setBunch(patt[j]); + } + } + repetion = 1; + } else if (*input == ')') { + input++; + if (level <= 1) { + LOG(error) << "Incorrectly placed )"; + return false; + } + break; + } else { + LOG(error) << "Unexpected symbol " << *input; + return false; + } + } + level--; + return true; +} diff --git a/DataFormats/common/src/CommonDataFormatLinkDef.h b/DataFormats/common/src/CommonDataFormatLinkDef.h index d4503c6722057..2999b4151973a 100644 --- a/DataFormats/common/src/CommonDataFormatLinkDef.h +++ b/DataFormats/common/src/CommonDataFormatLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,11 +43,15 @@ #pragma link C++ class std::vector < o2::dataformats::RangeReference < int, int>> + ; +#pragma link C++ class o2::dataformats::AbstractRef < 25, 5, 2> + ; + #pragma link C++ class o2::InteractionRecord + ; #pragma link C++ class o2::InteractionTimeRecord + ; #pragma link C++ class o2::BunchFilling + ; -#pragma link C++ class o2::dataformats::AbstractRef < 26, 3, 3> + ; +#pragma link C++ class o2::math_utils::detail::Bracket < o2::InteractionRecord> + ; +#pragma link C++ class o2::dataformats::IRFrame + ; +#pragma link C++ class std::vector < o2::dataformats::IRFrame> + ; #pragma link C++ class o2::dataformats::FlatHisto1D < float> + ; #pragma link C++ class o2::dataformats::FlatHisto1D < double> + ; diff --git a/DataFormats/common/src/FlatHisto1D.cxx b/DataFormats/common/src/FlatHisto1D.cxx index 0b59cd2b8259d..6386e2f3b940e 100644 --- a/DataFormats/common/src/FlatHisto1D.cxx +++ b/DataFormats/common/src/FlatHisto1D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,5 +14,94 @@ /// \author ruben.shahoyan@cern.ch #include "CommonDataFormat/FlatHisto1D.h" +#include <TH1F.h> -using namespace o2::dataformats; +namespace o2 +{ +namespace dataformats +{ + +template <typename T> +FlatHisto1D<T>::FlatHisto1D(int nb, T xmin, T xmax) +{ + assert(nb > 0 && xmin < xmax); + mContainer.resize(nb + NServiceSlots, 0.); + mContainer[NBins] = nb; + mContainer[XMin] = xmin; + mContainer[XMax] = xmax; + mContainer[BinSize] = (xmax - xmin) / nb; + init(gsl::span<const T>(mContainer.data(), mContainer.size())); +} + +template <typename T> +void FlatHisto1D<T>::adoptExternal(const gsl::span<const T> ext) +{ + assert(ext.size() > NServiceSlots); + mContainer.clear(); + mContainerView = ext; + init(mContainerView); +} + +template <typename T> +void FlatHisto1D<T>::add(const FlatHisto1D& other) +{ + if (!(getNBins() == other.getNBins() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && canFill())) { + throw std::runtime_error("adding incompatible histos or destination histo is const"); + } + for (int i = getNBins(); i--;) { + mDataPtr[i] += other.mDataPtr[i]; + } +} + +template <typename T> +void FlatHisto1D<T>::subtract(const FlatHisto1D& other) +{ + if (!(getNBins() == other.getNBins() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && canFill())) { + throw std::runtime_error("subtracting incompatible histos or destination histo is const"); + } + for (int i = getNBins(); i--;) { + mDataPtr[i] -= other.mDataPtr[i]; + } +} + +template <typename T> +T FlatHisto1D<T>::getSum() const +{ + T sum = 0; + for (int i = getNBins(); i--;) { + sum += getBinContent(i); + } + return sum; +} + +template <typename T> +void FlatHisto1D<T>::init(const gsl::span<const T> ext) +{ // when reading from file, need to call this method to make it operational + assert(ext.size() > NServiceSlots); + mContainerView = ext; + mDataPtr = const_cast<T*>(&ext[NServiceSlots]); + mNBins = (int)ext[NBins]; + mXMin = ext[XMin]; + mXMax = ext[XMax]; + mBinSize = ext[BinSize]; + mBinSizeInv = 1. / mBinSize; +} + +template <typename T> +std::unique_ptr<TH1F> FlatHisto1D<T>::createTH1F(const std::string& name) +{ + auto h = std::make_unique<TH1F>(name.c_str(), name.c_str(), getNBins(), getXMin(), getXMax()); + for (int i = getNBins(); i--;) { + auto w = getBinContent(i); + if (w) { + h->SetBinContent(i + 1, w); + } + } + return std::move(h); +} + +template class FlatHisto1D<float>; +template class FlatHisto1D<double>; + +} // namespace dataformats +} // namespace o2 \ No newline at end of file diff --git a/DataFormats/common/src/FlatHisto2D.cxx b/DataFormats/common/src/FlatHisto2D.cxx index 3266a23b81fd3..f2284f412a312 100644 --- a/DataFormats/common/src/FlatHisto2D.cxx +++ b/DataFormats/common/src/FlatHisto2D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,5 +14,137 @@ /// \author ruben.shahoyan@cern.ch #include "CommonDataFormat/FlatHisto2D.h" +#include <TH1F.h> +#include <TH2F.h> + +namespace o2 +{ +namespace dataformats +{ using namespace o2::dataformats; + +template <typename T> +FlatHisto2D<T>::FlatHisto2D(int nbx, T xmin, T xmax, int nby, T ymin, T ymax) +{ + assert(nbx > 0 && xmin < xmax); + assert(nby > 0 && ymin < ymax); + mContainer.resize(nbx * nby + NServiceSlots, 0.); + mContainer[NBinsX] = nbx; + mContainer[NBinsY] = nby; + mContainer[XMin] = xmin; + mContainer[XMax] = xmax; + mContainer[YMin] = ymin; + mContainer[YMax] = ymax; + mContainer[BinSizeX] = (xmax - xmin) / nbx; + mContainer[BinSizeY] = (ymax - ymin) / nby; + init(gsl::span<const T>(mContainer.data(), mContainer.size())); +} + +template <typename T> +void FlatHisto2D<T>::adoptExternal(const gsl::span<const T> ext) +{ + assert(ext.size() > NServiceSlots); + mContainer.clear(); + mContainerView = ext; + init(mContainerView); +} + +template <typename T> +void FlatHisto2D<T>::add(const FlatHisto2D& other) +{ + if (!(getNBinsX() == other.getNBinsX() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && + getNBinsY() == other.getNBinsY() && getYMin() == other.getYMin() && getYMax() == other.getYMax() && + canFill())) { + throw std::runtime_error("adding incompatible histos or destination histo is const"); + } + for (int i = getNBins(); i--;) { + mDataPtr[i] += other.mDataPtr[i]; + } +} + +template <typename T> +void FlatHisto2D<T>::subtract(const FlatHisto2D& other) +{ + if (!(getNBinsX() == other.getNBinsX() && getXMin() == other.getXMin() && getXMax() == other.getXMax() && + getNBinsY() == other.getNBinsY() && getYMin() == other.getYMin() && getYMax() == other.getYMax() && + canFill())) { + throw std::runtime_error("subtracting incompatible histos or destination histo is const"); + } + for (int i = getNBins(); i--;) { + mDataPtr[i] -= other.mDataPtr[i]; + } +} + +template <typename T> +T FlatHisto2D<T>::getSum() const +{ + T sum = 0; + for (int i = getNBins(); i--;) { + sum += getBinContent(i); + } + return sum; +} + +template <typename T> +void FlatHisto2D<T>::init(const gsl::span<const T> ext) +{ // when reading from file, need to call this method to make it operational + assert(ext.size() > NServiceSlots); + mContainerView = ext; + mDataPtr = const_cast<T*>(&ext[NServiceSlots]); + mNBinsX = (int)ext[NBinsX]; + mNBinsY = (int)ext[NBinsY]; + mXMin = ext[XMin]; + mXMax = ext[XMax]; + mYMin = ext[YMin]; + mYMax = ext[YMax]; + mBinSizeX = ext[BinSizeX]; + mBinSizeY = ext[BinSizeY]; + mBinSizeXInv = 1. / mBinSizeX; + mBinSizeYInv = 1. / mBinSizeY; +} + +template <typename T> +std::unique_ptr<TH2F> FlatHisto2D<T>::createTH2F(const std::string& name) +{ + auto h = std::make_unique<TH2F>(name.c_str(), name.c_str(), getNBinsX(), getXMin(), getXMax(), getNBinsY(), getYMin(), getYMax()); + for (int i = getNBinsX(); i--;) { + for (int j = getNBinsY(); j--;) { + auto w = getBinContent(i, j); + if (w) { + h->SetBinContent(i + 1, j + 1, w); + } + } + } + return std::move(h); +} + +template <typename T> +std::unique_ptr<TH1F> FlatHisto2D<T>::createSliceYTH1F(uint32_t binX, const std::string& name) const +{ + auto h = std::make_unique<TH1F>(name.c_str(), name.c_str(), getNBinsY(), getYMin(), getYMax()); + if (binX < getNBinsX()) { + for (int i = getNBinsY(); i--;) { + h->SetBinContent(i + 1, getBinContent(binX, i)); + } + } + return h; +} + +template <typename T> +std::unique_ptr<TH1F> FlatHisto2D<T>::createSliceXTH1F(uint32_t binY, const std::string& name) const +{ + auto h = std::make_unique<TH1F>(name.c_str(), name.c_str(), getNBinsX(), getXMin(), getXMax()); + if (binY < getNBinsY()) { + for (int i = getNBinsX(); i--;) { + h->SetBinContent(i + 1, getBinContent(i, binY)); + } + } + return h; +} + +template class FlatHisto2D<float>; +template class FlatHisto2D<double>; + +} // namespace dataformats +} // namespace o2 \ No newline at end of file diff --git a/DataFormats/common/src/InteractionRecord.cxx b/DataFormats/common/src/InteractionRecord.cxx index 4ceb8f957a45c..f15c8c8e85328 100644 --- a/DataFormats/common/src/InteractionRecord.cxx +++ b/DataFormats/common/src/InteractionRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ namespace o2 { -#ifndef ALIGPU_GPUCODE +#ifndef GPUCA_ALIGPUCODE std::string InteractionRecord::asString() const { diff --git a/DataFormats/common/test/testAbstractRefAccessor.cxx b/DataFormats/common/test/testAbstractRefAccessor.cxx new file mode 100644 index 0000000000000..fc5bedc5be715 --- /dev/null +++ b/DataFormats/common/test/testAbstractRefAccessor.cxx @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test AbstractRefAccessor class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <numeric> +#include <boost/test/unit_test.hpp> +#include "CommonDataFormat/AbstractRefAccessor.h" +#include "CommonDataFormat/AbstractRef.h" +#include "Framework/Logger.h" + +using namespace o2::dataformats; + +struct Base { + int b = 0; +}; + +struct Foo1 : public Base { + int f1 = 0; +}; + +struct Foo2 : public Foo1 { + int f2 = 0; +}; + +struct Bar1 : public Base { + double b1 = 0.; +}; + +struct GloIdx : public AbstractRef<25, 5, 2> { + enum Source : uint8_t { // provenance of the + ID0, + ID1, + ID2, + ID3, + NSources + }; + using AbstractRef<25, 5, 2>::AbstractRef; +}; + +// basic AbstractRefAccessor +BOOST_AUTO_TEST_CASE(AbstractRefAccess) +{ + + std::vector<Base> vb(10); + std::vector<Foo1> vf(10); + std::array<Foo2, 10> af; + std::vector<Bar1> bar(10); + + std::vector<GloIdx> vid; + + for (int i = 0; i < 10; i++) { + vb[i].b = GloIdx::ID0 * 100 + i; + vid.emplace_back(i, GloIdx::ID1); + + vf[i].b = GloIdx::ID1 * 100 + i; + vf[i].f1 = 0.5 + 100 + i; + vid.emplace_back(i, GloIdx::ID2); + + af[i].b = GloIdx::ID2 * 100 + i; + af[i].f2 = 0.8 + 100 + i; + vid.emplace_back(i, GloIdx::ID3); + + bar[i].b = GloIdx::ID3 * 100 + i; + bar[i].b1 = 0.2 + 300 + i; + vid.emplace_back(i, GloIdx::ID3); + } + + AbstractRefAccessor<Base, GloIdx::NSources> acc; + + acc.registerContainer(vb, GloIdx::ID0); + acc.registerContainer(vf, GloIdx::ID1); + acc.registerContainer(af, GloIdx::ID2); + acc.registerContainer(bar, GloIdx::ID3); + + size_t nid = vid.size(); + for (size_t i = 0; i < nid; i++) { + auto gid = vid[i]; + const auto& obj = acc.get(gid); + int expect = gid.getSource() * 100 + i / GloIdx::NSources; + LOG(INFO) << i << " ? " << obj.b << " == " << expect << " for " << gid.getRaw(); + BOOST_CHECK(obj.b == expect); + } + + const auto& barEl = acc.get_as<Bar1>(vid.back()); + LOG(INFO) << " ? " << barEl.b1 << " == " << bar.back().b1; + BOOST_CHECK(barEl.b1 == bar.back().b1); +} diff --git a/DataFormats/common/test/testFlatHisto.cxx b/DataFormats/common/test/testFlatHisto.cxx index d1f9a56cdfd05..f690c7ead84b5 100644 --- a/DataFormats/common/test/testFlatHisto.cxx +++ b/DataFormats/common/test/testFlatHisto.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include <TFile.h> #include <TRandom.h> #include <TFitResult.h> +#include <TH1F.h> +#include <TH2F.h> namespace o2 { @@ -33,23 +36,23 @@ BOOST_AUTO_TEST_CASE(FlatHisto) for (int i = 0; i < 10000000; i++) { auto x = gRandom->Gaus(10, 40), y = gRandom->Gaus(10, 10); h2.fill(x, y); - h2ref.Fill(x, y); + h2ref->Fill(x, y); } auto th1f = h1.createTH1F(); - auto res = th1f.Fit("gaus", "S"); + auto res = th1f->Fit("gaus", "S"); BOOST_CHECK_CLOSE(res->GetParams()[1], 10, 0.2); - printf("%e %e\n", h2.getSum(), h2ref.Integral()); - BOOST_CHECK(h2.getSum() == h2ref.Integral()); + printf("%e %e\n", h2.getSum(), h2ref->Integral()); + BOOST_CHECK(h2.getSum() == h2ref->Integral()); o2::dataformats::FlatHisto1D_f h1v(h1); BOOST_CHECK_CLOSE(h1.getBinStart(0), -100, 1e-5); BOOST_CHECK_CLOSE(h1.getBinEnd(h1.getNBins() - 1), 100, 1e-5); - BOOST_CHECK_CLOSE(h2.getBinStartX(0), -100, 1e-5); - BOOST_CHECK_CLOSE(h2.getBinEndY(h2.getNBinsY() - 1), 45, 1e-5); - BOOST_CHECK_CLOSE(h2.getBinStartY(h2.getNBinsY() - 1), 45 - h2.getBinSizeY(), 1e-5); + BOOST_CHECK_CLOSE(h2.getBinXStart(0), -100, 1e-5); + BOOST_CHECK_CLOSE(h2.getBinYEnd(h2.getNBinsY() - 1), 45, 1e-5); + BOOST_CHECK_CLOSE(h2.getBinYStart(h2.getNBinsY() - 1), 45 - h2.getBinSizeY(), 1e-5); BOOST_CHECK(h1.canFill() && h1v.canFill()); BOOST_CHECK(h1.getSum() == h1v.getSum()); diff --git a/DataFormats/common/test/testRangeRef.cxx b/DataFormats/common/test/testRangeRef.cxx index f6a339e8f3a85..7b0b66b8aabe1 100644 --- a/DataFormats/common/test/testRangeRef.cxx +++ b/DataFormats/common/test/testRangeRef.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/common/test/testTimeStamp.cxx b/DataFormats/common/test/testTimeStamp.cxx index 542ae430b029f..9912a701f0c66 100644 --- a/DataFormats/common/test/testTimeStamp.cxx +++ b/DataFormats/common/test/testTimeStamp.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/CMakeLists.txt b/DataFormats/simulation/CMakeLists.txt index 9ed5155633744..3a7cb0b61d936 100644 --- a/DataFormats/simulation/CMakeLists.txt +++ b/DataFormats/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(SimulationDataFormat SOURCES src/Stack.cxx @@ -17,7 +18,7 @@ o2_add_library(SimulationDataFormat src/StackParam.cxx src/MCEventHeader.cxx src/CustomStreamers.cxx - PUBLIC_LINK_LIBRARIES ms_gsl::ms_gsl + PUBLIC_LINK_LIBRARIES Microsoft.GSL::GSL O2::DetectorsCommonDataFormats O2::GPUCommon O2::DetectorsBase O2::SimConfig) @@ -29,6 +30,7 @@ o2_target_root_dictionary( include/SimulationDataFormat/MCTrack.h include/SimulationDataFormat/BaseHits.h include/SimulationDataFormat/MCTruthContainer.h + include/SimulationDataFormat/ConstMCTruthContainer.h include/SimulationDataFormat/MCCompLabel.h include/SimulationDataFormat/MCEventLabel.h include/SimulationDataFormat/TrackReference.h diff --git a/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h b/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h index 31e506cbe65e0..b9ed356ec8b5a 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h +++ b/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h b/DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h index f287dd56803b7..64a8b02c856ab 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h +++ b/DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -131,7 +132,11 @@ class ConstMCTruthContainerView public: ConstMCTruthContainerView(gsl::span<const char> const bufferview) : mStorage(bufferview){}; ConstMCTruthContainerView(ConstMCTruthContainer<TruthElement> const& cont) : mStorage(gsl::span<const char>(cont)){}; - ConstMCTruthContainerView() : mStorage(nullptr, (gsl::span<const char>::index_type)0) { (void)0; } // be explicit that we want nullptr / 0 for an uninitialized container + // be explicit that we want nullptr / 0 for an uninitialized container (needs (void)0 to avoid false codechecker warning) + ConstMCTruthContainerView() : mStorage{nullptr, static_cast<gsl::span<const char>::size_type>(0)} + { + (void)0; + } ConstMCTruthContainerView(const ConstMCTruthContainerView&) = default; // const data access diff --git a/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h b/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h index 8fb7aa7ed9756..683e9280c6e56 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h +++ b/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ #include "CommonDataFormat/BunchFilling.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DataFormatsParameters/GRPObject.h" -#include <FairLogger.h> +#include <GPUCommonLogger.h> namespace o2 { @@ -48,6 +49,9 @@ class DigitizationContext public: DigitizationContext() : mNofEntries{0}, mMaxPartNumber{0}, mEventRecords(), mEventParts() {} + uint32_t getFirstOrbitForSampling() const { return mFirstOrbitForSampling; } + void setFirstOrbitForSampling(uint32_t o) { mFirstOrbitForSampling = o; } + int getNCollisions() const { return mNofEntries; } void setNCollisions(int n) { mNofEntries = n; } @@ -62,7 +66,7 @@ class DigitizationContext bool isQEDProvided() const { return !mEventRecordsWithQED.empty(); } - o2::BunchFilling& getBunchFilling() { return mBCFilling; } + void setBunchFilling(o2::BunchFilling const& bf) { mBCFilling = bf; } const o2::BunchFilling& getBunchFilling() const { return (const o2::BunchFilling&)mBCFilling; } void setMuPerBC(float m) { mMuBC = m; } @@ -106,11 +110,13 @@ class DigitizationContext // helper functions to save and load a context void saveToFile(std::string_view filename) const; - static DigitizationContext const* loadFromFile(std::string_view filename); + static DigitizationContext const* loadFromFile(std::string_view filename = ""); private: int mNofEntries = 0; int mMaxPartNumber = 0; // max number of parts in any given collision + uint32_t mFirstOrbitForSampling = 0; // 1st orbit to start sampling + float mMuBC; // probability of hadronic interaction per bunch std::vector<o2::InteractionTimeRecord> mEventRecords; @@ -121,13 +127,13 @@ class DigitizationContext std::vector<o2::InteractionTimeRecord> mEventRecordsWithQED; std::vector<std::vector<o2::steer::EventPart>> mEventPartsWithQED; - o2::BunchFilling mBCFilling; // patter of active BCs + o2::BunchFilling mBCFilling; // pattern of active BCs std::vector<std::string> mSimPrefixes; // identifiers to the hit sim products; the key corresponds to the source ID of event record std::string mQEDSimPrefix; // prefix for QED production/contribution mutable o2::parameters::GRPObject* mGRP = nullptr; //! - ClassDefNV(DigitizationContext, 3); + ClassDefNV(DigitizationContext, 4); }; /// function reading the hits from a chain (previously initialized with initSimChains @@ -140,7 +146,7 @@ inline void DigitizationContext::retrieveHits(std::vector<TChain*> const& chains { auto br = chains[sourceID]->GetBranch(brname); if (!br) { - LOG(ERROR) << "No branch found"; + LOG(ERROR) << "No branch found with name " << brname; return; } br->SetAddress(&hits); diff --git a/DataFormats/simulation/include/SimulationDataFormat/IOMCTruthContainerView.h b/DataFormats/simulation/include/SimulationDataFormat/IOMCTruthContainerView.h index 590524cd61e8f..1692422c90f2c 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/IOMCTruthContainerView.h +++ b/DataFormats/simulation/include/SimulationDataFormat/IOMCTruthContainerView.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/LabelContainer.h b/DataFormats/simulation/include/SimulationDataFormat/LabelContainer.h index 656f4c2ed18d4..6264c8580db9f 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/LabelContainer.h +++ b/DataFormats/simulation/include/SimulationDataFormat/LabelContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h b/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h index ca536e767e4cc..ec81285c9e802 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,13 +21,13 @@ namespace o2 class MCCompLabel { private: - static constexpr ULong64_t ul0x1 = 0x1; - static constexpr ULong64_t NotSet = 0xffffffffffffffff; - static constexpr ULong64_t Noise = 0xfffffffffffffffe; - static constexpr ULong64_t Fake = ul0x1 << 63; + static constexpr uint64_t ul0x1 = 0x1; + static constexpr uint64_t NotSet = 0xffffffffffffffff; + static constexpr uint64_t Noise = 0xfffffffffffffffe; + static constexpr uint64_t Fake = ul0x1 << 63; static constexpr int NReservedBits = 1; - ULong64_t mLabel = NotSet; ///< MC label encoding MCtrack ID and MCevent origin + uint64_t mLabel = NotSet; ///< MC label encoding MCtrack ID and MCevent origin public: // number of bits reserved for MC track ID, DON'T modify this, since the @@ -37,17 +38,17 @@ class MCCompLabel // the rest of the bits is reserved at the moment // check if the fields are defined consistently - static_assert(nbitsTrackID + nbitsEvID + nbitsSrcID <= sizeof(ULong64_t) * 8 - NReservedBits, + static_assert(nbitsTrackID + nbitsEvID + nbitsSrcID <= sizeof(uint64_t) * 8 - NReservedBits, "Fields cannot be stored in 64 bits"); // mask to extract MC track ID - static constexpr ULong64_t maskTrackID = (ul0x1 << nbitsTrackID) - 1; + static constexpr uint64_t maskTrackID = (ul0x1 << nbitsTrackID) - 1; // mask to extract MC track ID - static constexpr ULong64_t maskEvID = (ul0x1 << nbitsEvID) - 1; + static constexpr uint64_t maskEvID = (ul0x1 << nbitsEvID) - 1; // mask to extract MC track ID - static constexpr ULong64_t maskSrcID = (ul0x1 << nbitsSrcID) - 1; + static constexpr uint64_t maskSrcID = (ul0x1 << nbitsSrcID) - 1; // mask for all used fields - static constexpr ULong64_t maskFull = (ul0x1 << (nbitsTrackID + nbitsEvID + nbitsSrcID)) - 1; + static constexpr uint64_t maskFull = (ul0x1 << (nbitsTrackID + nbitsEvID + nbitsSrcID)) - 1; MCCompLabel(int trackID, int evID, int srcID, bool fake = false) { set(trackID, evID, srcID, fake); } MCCompLabel(bool noise = false) @@ -86,13 +87,16 @@ class MCCompLabel return (tr1 == tr2) ? ((isCorrect() && other.isCorrect()) ? 1 : 0) : -1; } - // conversion operator - operator ULong64_t() const { return mLabel; } // allow to retrieve bare label - ULong64_t getRawValue() const { return mLabel; } + uint64_t getRawValue() const { return mLabel; } // comparison operator, compares only label, not eventual weight or correctness info bool operator==(const MCCompLabel& other) const { return (mLabel & maskFull) == (other.mLabel & maskFull); } + bool operator!=(const MCCompLabel& other) const { return (mLabel & maskFull) != (other.mLabel & maskFull); } + // relation operators needed for some sorting methods + bool operator<(const MCCompLabel& other) const { return (mLabel & maskFull) < (other.mLabel & maskFull); } + bool operator>(const MCCompLabel& other) const { return (mLabel & maskFull) > (other.mLabel & maskFull); } + // invalidate void unset() { mLabel = NotSet; } void setNoise() { mLabel = Noise; } @@ -108,9 +112,9 @@ class MCCompLabel void set(unsigned int trackID, int evID, int srcID, bool fake) { /// compose label: the track 1st cast to UInt32_t to preserve the sign! - mLabel = (maskTrackID & static_cast<ULong64_t>(trackID)) | - (maskEvID & static_cast<ULong64_t>(evID)) << nbitsTrackID | - (maskSrcID & static_cast<ULong64_t>(srcID)) << (nbitsTrackID + nbitsEvID); + mLabel = (maskTrackID & static_cast<uint64_t>(trackID)) | + (maskEvID & static_cast<uint64_t>(evID)) << nbitsTrackID | + (maskSrcID & static_cast<uint64_t>(srcID)) << (nbitsTrackID + nbitsEvID); if (fake) { setFakeFlag(); } @@ -120,7 +124,7 @@ class MCCompLabel int getTrackIDSigned() const { return isFake() ? -getTrackID() : getTrackID(); } int getEventID() const { return (mLabel >> nbitsTrackID) & maskEvID; } int getSourceID() const { return (mLabel >> (nbitsTrackID + nbitsEvID)) & maskSrcID; } - ULong64_t getTrackEventSourceID() const { return static_cast<ULong64_t>(mLabel & maskFull); } + uint64_t getTrackEventSourceID() const { return static_cast<uint64_t>(mLabel & maskFull); } void get(int& trackID, int& evID, int& srcID, bool& fake) { /// parse label @@ -137,9 +141,10 @@ class MCCompLabel static constexpr int maxTrackID() { return maskTrackID; } ClassDefNV(MCCompLabel, 1); }; -} // namespace o2 -std::ostream& operator<<(std::ostream& os, const o2::MCCompLabel& c); +std::ostream& operator<<(std::ostream& os, MCCompLabel const& c); + +} // namespace o2 namespace std { @@ -149,7 +154,7 @@ struct hash<o2::MCCompLabel> { public: size_t operator()(o2::MCCompLabel const& label) const { - return static_cast<uint64_t>(label); + return label.getRawValue(); } }; } // namespace std diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index 42844cb8c9894..3fc2ad1d39ef7 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,9 @@ #include "FairMCEventHeader.h" #include "SimulationDataFormat/MCEventStats.h" +#include "CommonUtils/RootSerializableKeyValueStore.h" #include <string> +#include <Framework/Logger.h> namespace o2 { @@ -42,11 +45,50 @@ class MCEventHeader : public FairMCEventHeader void setEmbeddingEventIndex(Int_t value) { mEmbeddingEventIndex = value; }; int getEmbeddedIndex() const { return mEmbeddingEventIndex; } + /** methods to handle stored information **/ + + void clearInfo() + { + mEventInfo.clear(); + }; + + template <typename T> + void putInfo(std::string const& key, T const& value) + { + mEventInfo.put<T>(key, value); + }; + + bool hasInfo(std::string const& key) const + { + return mEventInfo.has(key); + } + + template <typename T> + const T& getInfo(std::string const& key, bool& isvalid) const + { + o2::utils::RootSerializableKeyValueStore::GetState state; + auto& ref = mEventInfo.getRef<T>(key, state); + isvalid = (state == o2::utils::RootSerializableKeyValueStore::GetState::kOK); + if (!isvalid) { + LOG(WARNING) << "problem retrieving info '" << key << "': " << o2::utils::RootSerializableKeyValueStore::getStateString(state); + } + return ref; + }; + + /// prints a summary of info keys/types attached to this header + void printInfo() const + { + mEventInfo.print(); + } + /** methods **/ virtual void Reset(); MCEventStats& getMCEventStats() { return mEventStats; } + /// create a standalone ROOT file/tree with only the MCHeader branch + static void extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename); + protected: std::string mEmbeddingFileName; Int_t mEmbeddingEventIndex = 0; @@ -54,8 +96,9 @@ class MCEventHeader : public FairMCEventHeader // store a view global properties that this event // had in the current simulation (which can be used quick filtering/searching) MCEventStats mEventStats{}; + o2::utils::RootSerializableKeyValueStore mEventInfo; - ClassDefOverride(MCEventHeader, 2); + ClassDefOverride(MCEventHeader, 3); }; /** class MCEventHeader **/ diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventLabel.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventLabel.h index 4ff57f2be253e..8583d31d460ba 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventLabel.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,6 +35,8 @@ class MCEventLabel static constexpr uint32_t MaskEvID = (0x1 << nbitsEvID) - 1; // Mask to extract MC source ID static constexpr uint32_t MaskSrcID = (0x1 << nbitsSrcID) - 1; + // Mask to extract MC source and event ID only + static constexpr uint32_t MaskSrcEvID = MaskSrcID | MaskEvID; // Mask to extract MC correct contribution weight static constexpr uint32_t MaskCorrW = (0x1 << nbitsCorrW) - 1; static constexpr float WeightNorm = 1. / float(MaskCorrW); @@ -53,7 +56,7 @@ class MCEventLabel uint32_t getRawValue() const { return mLabel; } // get only combined identifier, discarding weight info - uint32_t getIDOnly() const { return mLabel & (0x1 << (nbitsEvID + nbitsSrcID)); } + uint32_t getIDOnly() const { return mLabel & MaskSrcEvID; } // compare bool compare(const MCEventLabel& other, bool strict = false) const diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventStats.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventStats.h index 087b9cf86be48..dbbfcc3932aad 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventStats.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventStats.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h index c333bd3e624d9..dd1d1198333af 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #ifndef ALICEO2_DATA_MCTRACK_H_ #define ALICEO2_DATA_MCTRACK_H_ +#include "SimulationDataFormat/ParticleStatus.h" #include "DetectorsCommonDataFormats/DetID.h" #include "Rtypes.h" #include "TDatabasePDG.h" @@ -60,7 +62,8 @@ class MCTrackT Int_t GetPdgCode() const { return mPdgCode; } Int_t getMotherTrackId() const { return mMotherTrackId; } Int_t getSecondMotherTrackId() const { return mSecondMotherTrackId; } - bool isSecondary() const { return mMotherTrackId != -1; } + bool isPrimary() const { return getProcess() == TMCProcess::kPPrimary; } + bool isSecondary() const { return !isPrimary(); } Int_t getFirstDaughterTrackId() const { return mFirstDaughterTrackId; } Int_t getLastDaughterTrackId() const { return mLastDaughterTrackId; } Double_t GetStartVertexMomentumX() const { return mStartVertexMomentumX; } @@ -184,6 +187,24 @@ class MCTrackT /// get the production process (id) of this track int getProcess() const { return ((PropEncoding)mProp).process; } + void setToBeDone(bool f) + { + auto prop = ((PropEncoding)mProp); + prop.toBeDone = f; + mProp = prop.i; + } + bool getToBeDone() const { return ((PropEncoding)mProp).toBeDone; } + + void setInhibited(bool f) + { + auto prop = ((PropEncoding)mProp); + prop.inhibited = f; + mProp = prop.i; + } + bool getInhibited() const { return ((PropEncoding)mProp).inhibited; } + + bool isTransported() const { return getToBeDone() && !getInhibited(); }; + /// get the string representation of the production process const char* getProdProcessAsString() const; @@ -198,11 +219,11 @@ class MCTrackT Int_t mPdgCode; /// Index of mother tracks - Int_t mMotherTrackId; - Int_t mSecondMotherTrackId; + Int_t mMotherTrackId = -1; + Int_t mSecondMotherTrackId = -1; - Int_t mFirstDaughterTrackId; - Int_t mLastDaughterTrackId; + Int_t mFirstDaughterTrackId = -1; + Int_t mLastDaughterTrackId = -1; // hitmask stored as an int // if bit i is set it means that this track left a trace in detector i // we should have sizeof(int) < o2::base::DetId::nDetectors @@ -216,11 +237,15 @@ class MCTrackT struct { int storage : 1; // encoding whether to store this track to the output int process : 6; // encoding process that created this track (enough to store TMCProcess from ROOT) - int hitmask : 25; // encoding hits per detector + int hitmask : 21; // encoding hits per detector + int reserved1 : 1; // bit reserved for possible future purposes + int reserved2 : 1; // bit reserved for possible future purposes + int inhibited : 1; // whether tracking of this was inhibited + int toBeDone : 1; // whether this (still) needs tracking --> we might more complete information to cover full ParticleStatus space }; }; - ClassDefNV(MCTrackT, 3); + ClassDefNV(MCTrackT, 4); }; template <typename T> @@ -305,6 +330,15 @@ inline MCTrackT<T>::MCTrackT(const TParticle& part) { // our convention is to communicate the process as (part) of the unique ID setProcess(part.GetUniqueID()); + // extract storage flag + setStore(part.TestBit(ParticleStatus::kKeep)); + // extract toBeDone flag + setToBeDone(part.TestBit(ParticleStatus::kToBeDone)); + // extract inhibited flag + if (part.TestBit(ParticleStatus::kInhibited)) { + setToBeDone(true); // if inhibited, it had to be done: restore flag + setInhibited(true); + } } template <typename T> diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCTruthContainer.h b/DataFormats/simulation/include/SimulationDataFormat/MCTruthContainer.h index cf39f7aa3a8e8..92156bd35db78 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCTruthContainer.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCTruthContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,11 +20,12 @@ #include <cstdint> // uint8_t etc #include <cassert> #include <stdexcept> -#include <gsl/gsl> // for guideline support library; array_view +#include <gsl/span> // for guideline support library span #include <type_traits> #include <cstring> // memmove, memcpy #include <memory> #include <vector> + // type traits are needed for the compile time consistency check // maybe to be moved out of Framework first //#include "Framework/TypeTraits.h" @@ -41,7 +43,7 @@ struct MCTruthHeaderElement { MCTruthHeaderElement() = default; // for ROOT IO MCTruthHeaderElement(uint32_t i) : index(i) {} - uint32_t index = -1; // the index into the actual MC track storage (-1 if invalid) + uint32_t index = (uint32_t)-1; // the index into the actual MC track storage (-1 if invalid) ClassDefNV(MCTruthHeaderElement, 1); }; @@ -140,6 +142,11 @@ class MCTruthContainer size_t getIndexedSize() const { return mHeaderArray.size(); } // return the number of elements managed in this container size_t getNElements() const { return mTruthArray.size(); } + // return unterlaying vector of elements + const std::vector<TruthElement>& getTruthArray() const + { + return mTruthArray; + } // get individual "view" container for a given data index // the caller can do modifications on this view (such as sorting) diff --git a/DataFormats/simulation/include/SimulationDataFormat/ParticleStatus.h b/DataFormats/simulation/include/SimulationDataFormat/ParticleStatus.h new file mode 100644 index 0000000000000..552436aebfdbf --- /dev/null +++ b/DataFormats/simulation/include/SimulationDataFormat/ParticleStatus.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_SIMDATA_PARTICLESTATUS_H_ +#define ALICEO2_SIMDATA_PARTICLESTATUS_H_ + +#include "TParticle.h" + +/// enumeration to define status bits for particles in simulation +enum ParticleStatus { kKeep = BIT(14), + kDaughters = BIT(15), + kToBeDone = BIT(16), + kPrimary = BIT(17), + kTransport = BIT(18), + kInhibited = BIT(19) }; + +#endif diff --git a/DataFormats/simulation/include/SimulationDataFormat/PrimaryChunk.h b/DataFormats/simulation/include/SimulationDataFormat/PrimaryChunk.h index 0376951ff574b..86f2023c3680b 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/PrimaryChunk.h +++ b/DataFormats/simulation/include/SimulationDataFormat/PrimaryChunk.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h b/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h index 568b82505029e..150a8272c7714 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h +++ b/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/include/SimulationDataFormat/Stack.h b/DataFormats/simulation/include/SimulationDataFormat/Stack.h index 6f4f6f9f1358c..d6bda808830ec 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/Stack.h +++ b/DataFormats/simulation/include/SimulationDataFormat/Stack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,9 +19,9 @@ #include "DetectorsCommonDataFormats/DetID.h" #include "FairGenericStack.h" #include "SimulationDataFormat/MCTrack.h" -#include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/TrackReference.h" #include "SimulationDataFormat/MCEventStats.h" +#include "SimulationDataFormat/ParticleStatus.h" #include "Rtypes.h" #include "TParticle.h" @@ -28,6 +29,7 @@ #include <memory> #include <stack> #include <utility> +#include <functional> class TClonesArray; class TRefArray; @@ -55,11 +57,6 @@ namespace data /// The storage of secondaries can be switched off. /// The storage of all mothers can be switched off. /// By default, the minimal number of hits is 1 and the energy cut is 0. -enum ParticleStatus { kKeep = BIT(14), - kDaughters = BIT(15), - kToBeDone = BIT(16), - kPrimary = BIT(17), - kTransport = BIT(18) }; class Stack : public FairGenericStack { public: @@ -92,6 +89,11 @@ class Stack : public FairGenericStack Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz, TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondParentId) override; + void PushTrack(Int_t toBeDone, Int_t parentID, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e, + Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz, + TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondParentId, Int_t daughter1Id, Int_t daughter2Id, + TMCProcess proc2); + // similar function taking a particle void PushTrack(Int_t toBeDone, TParticle&); @@ -225,6 +227,8 @@ class Stack : public FairGenericStack /// update values in the current event header void updateEventStats(); + typedef std::function<bool(const TParticle& p, const std::vector<TParticle>& particles)> TransportFcn; + private: /// STL stack (FILO) used to handle the TParticles for tracking /// stack entries refer to @@ -281,11 +285,11 @@ class Stack : public FairGenericStack bool mIsExternalMode = false; // is stack an external factory or directly used inside simulation? + TransportFcn mTransportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) { return false; }; //! a function to inhibit the tracking of a particle + // storage for track references std::vector<o2::TrackReference>* mTrackRefs = nullptr; //! - o2::dataformats::MCTruthContainer<o2::TrackReference>* mIndexedTrackRefs = nullptr; //! - /// a pointer to the current MCEventStats object o2::dataformats::MCEventStats* mMCEventStats = nullptr; //! @@ -309,6 +313,8 @@ class Stack : public FairGenericStack /// \param iTrack Track number void addHit(int iDet, Int_t iTrack); + void handleTransportPrimary(TParticle& p); + ClassDefOverride(Stack, 1); }; diff --git a/DataFormats/simulation/include/SimulationDataFormat/StackParam.h b/DataFormats/simulation/include/SimulationDataFormat/StackParam.h index 7c58b5327cf24..b76112b41b541 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/StackParam.h +++ b/DataFormats/simulation/include/SimulationDataFormat/StackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,10 @@ namespace sim struct StackParam : public o2::conf::ConfigurableParamHelper<StackParam> { bool storeSecondaries = true; bool pruneKine = true; + std::string transportPrimary = "all"; + std::string transportPrimaryFileName = ""; + std::string transportPrimaryFuncName = ""; + bool transportPrimaryInvert = false; // boilerplate stuff + make principal key "Stack" O2ParamDef(StackParam, "Stack"); diff --git a/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h b/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h index ba390ad11bdc5..3766f7bce07a7 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h +++ b/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/src/CustomStreamers.cxx b/DataFormats/simulation/src/CustomStreamers.cxx index ba06a6a207916..69f3607bf9d59 100644 --- a/DataFormats/simulation/src/CustomStreamers.cxx +++ b/DataFormats/simulation/src/CustomStreamers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/src/DigitizationContext.cxx b/DataFormats/simulation/src/DigitizationContext.cxx index f6263a1accd26..5cbdeca95a266 100644 --- a/DataFormats/simulation/src/DigitizationContext.cxx +++ b/DataFormats/simulation/src/DigitizationContext.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ using namespace o2::steer; void DigitizationContext::printCollisionSummary(bool withQED) const { std::cout << "Summary of DigitizationContext --\n"; - std::cout << "Parts per collision " << mMaxPartNumber << "\n"; + std::cout << "Maximal parts per collision " << mMaxPartNumber << "\n"; std::cout << "Collision parts taken from simulations specified by prefix:\n"; for (int p = 0; p < mSimPrefixes.size(); ++p) { std::cout << "Part " << p << " : " << mSimPrefixes[p] << "\n"; @@ -53,10 +54,6 @@ void DigitizationContext::printCollisionSummary(bool withQED) const void DigitizationContext::setSimPrefixes(std::vector<std::string> const& prefixes) { mSimPrefixes = prefixes; - // the number should correspond to the number of parts - if (mSimPrefixes.size() != mMaxPartNumber) { - std::cerr << "Inconsistent number of simulation prefixes and part numbers"; - } } bool DigitizationContext::initSimChains(o2::detectors::DetID detid, std::vector<TChain*>& simchains) const @@ -178,7 +175,7 @@ o2::parameters::GRPObject const& DigitizationContext::getGRP() const if (!mGRP) { // we take the GRP from the background file // maybe we should add a check that all GRPs are consistent .. - mGRP = o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName(mSimPrefixes[0].data()).c_str()); + mGRP = o2::parameters::GRPObject::loadFrom(mSimPrefixes[0]); } return *mGRP; } @@ -193,6 +190,11 @@ void DigitizationContext::saveToFile(std::string_view filename) const DigitizationContext const* DigitizationContext::loadFromFile(std::string_view filename) { + std::string tmpFile; + if (filename == "") { + tmpFile = o2::base::NameConf::getCollisionContextFileName(); + filename = tmpFile; + } DigitizationContext* incontext = nullptr; TFile file(filename.data(), "OPEN"); file.GetObject("DigitizationContext", incontext); diff --git a/DataFormats/simulation/src/MCCompLabel.cxx b/DataFormats/simulation/src/MCCompLabel.cxx index 32e6625abcbd5..8e4f2ad73f876 100644 --- a/DataFormats/simulation/src/MCCompLabel.cxx +++ b/DataFormats/simulation/src/MCCompLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,19 +15,11 @@ #include <iostream> #include <cassert> -using namespace o2; - -ClassImp(o2::MCCompLabel); - -//_____________________________________________ -void MCCompLabel::print() const +namespace o2 { - // print itself - std::cout << (MCCompLabel) * this << std::endl; -} //_____________________________________________ -std::ostream& operator<<(std::ostream& os, const o2::MCCompLabel& c) +std::ostream& operator<<(std::ostream& os, MCCompLabel const& c) { // stream itself if (c.isValid()) { @@ -37,3 +30,12 @@ std::ostream& operator<<(std::ostream& os, const o2::MCCompLabel& c) } return os; } + +//_____________________________________________ +void MCCompLabel::print() const +{ + // print itself + std::cout << (MCCompLabel) * this << std::endl; +} + +} // namespace o2 diff --git a/DataFormats/simulation/src/MCEventHeader.cxx b/DataFormats/simulation/src/MCEventHeader.cxx index 7991e3078c9ea..99004fec46ffa 100644 --- a/DataFormats/simulation/src/MCEventHeader.cxx +++ b/DataFormats/simulation/src/MCEventHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,8 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "FairRootManager.h" +#include <TFile.h> +#include <TTree.h> namespace o2 { @@ -25,9 +28,37 @@ void MCEventHeader::Reset() { /** reset **/ + FairMCEventHeader::Reset(); + + clearInfo(); mEmbeddingFileName.clear(); mEmbeddingEventIndex = 0; - FairMCEventHeader::Reset(); +} + +void MCEventHeader::extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename) +{ + auto oldfile = TFile::Open(kinefilename.data()); + auto kinetree = (TTree*)oldfile->Get("o2sim"); + // deactivate all branches + kinetree->SetBranchStatus("*", 0); + // activate the header branch + kinetree->SetBranchStatus("MCEventHeader*", 1); + // create a new file + a clone of old tree header. Do not copy events + auto newfile = TFile::Open(targetfilename.data(), "RECREATE"); + auto newtree = kinetree->CloneTree(0); + // here we copy the branches + newtree->CopyEntries(kinetree, kinetree->GetEntries()); + newtree->SetEntries(kinetree->GetEntries()); + // flush to disk + newtree->Write(); + newfile->Close(); + delete newfile; + + // clean + if (oldfile) { + oldfile->Close(); + delete oldfile; + } } /*****************************************************************/ diff --git a/DataFormats/simulation/src/MCEventLabel.cxx b/DataFormats/simulation/src/MCEventLabel.cxx index f12b6bf5d1dc1..31607eb6d3010 100644 --- a/DataFormats/simulation/src/MCEventLabel.cxx +++ b/DataFormats/simulation/src/MCEventLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/src/MCTrack.cxx b/DataFormats/simulation/src/MCTrack.cxx index 94ce726755ea0..a35779a5876f5 100644 --- a/DataFormats/simulation/src/MCTrack.cxx +++ b/DataFormats/simulation/src/MCTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/src/SimulationDataLinkDef.h b/DataFormats/simulation/src/SimulationDataLinkDef.h index 8c18aee9724ee..acaaa03198f77 100644 --- a/DataFormats/simulation/src/SimulationDataLinkDef.h +++ b/DataFormats/simulation/src/SimulationDataLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/src/Stack.cxx b/DataFormats/simulation/src/Stack.cxx index 49e3c5ebe1732..715047b8b311c 100644 --- a/DataFormats/simulation/src/Stack.cxx +++ b/DataFormats/simulation/src/Stack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,12 +17,14 @@ #include "DetectorsBase/Detector.h" #include "DetectorsCommonDataFormats/DetID.h" #include "SimulationDataFormat/MCTrack.h" -#include "SimConfig/SimCutParams.h" +#include "SimConfig/SimParams.h" #include "FairDetector.h" // for FairDetector #include "FairLogger.h" // for FairLogger #include "FairRootManager.h" #include "SimulationDataFormat/BaseHits.h" +#include "SimulationDataFormat/StackParam.h" +#include "CommonUtils/ConfigurationMacroHelper.h" #include "TLorentzVector.h" // for TLorentzVector #include "TParticle.h" // for TParticle @@ -72,12 +75,44 @@ Stack::Stack(Int_t size) mMinHits(1), mEnergyCut(0.), mTrackRefs(new std::vector<o2::TrackReference>), - mIndexedTrackRefs(new typename std::remove_pointer<decltype(mIndexedTrackRefs)>::type), mIsG4Like(false) { auto vmc = TVirtualMC::GetMC(); - if (vmc && strcmp(vmc->GetName(), "TGeant4") == 0) { - mIsG4Like = true; + if (vmc) { + mIsG4Like = !(vmc->SecondariesAreOrdered()); + } + + auto& param = o2::sim::StackParam::Instance(); + LOG(INFO) << param; + TransportFcn transportPrimary; + if (param.transportPrimary.compare("none") == 0) { + transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) { + return false; + }; + } else if (param.transportPrimary.compare("all") == 0) { + transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) { + return true; + }; + } else if (param.transportPrimary.compare("barrel") == 0) { + transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) { + return (std::fabs(p.Eta()) < 2.0); + }; + } else if (param.transportPrimary.compare("external") == 0) { + transportPrimary = o2::conf::GetFromMacro<o2::data::Stack::TransportFcn>(param.transportPrimaryFileName, + param.transportPrimaryFuncName, + "o2::data::Stack::TransportFcn", "stack_transport_primary"); + if (!mTransportPrimary) { + LOG(FATAL) << "Failed to retrieve external \'transportPrimary\' function: problem with configuration "; + } + LOG(INFO) << "Successfully retrieve external \'transportPrimary\' frunction: " << param.transportPrimaryFileName; + } else { + LOG(FATAL) << "unsupported \'trasportPrimary\' mode: " << param.transportPrimary; + } + + if (param.transportPrimaryInvert) { + mTransportPrimary = [transportPrimary](const TParticle& p, const std::vector<TParticle>& particles) { return !transportPrimary; }; + } else { + mTransportPrimary = transportPrimary; } } @@ -149,6 +184,14 @@ void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e, Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz, TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondparentId) +{ + PushTrack(toBeDone, parentId, pdgCode, px, py, pz, e, vx, vy, vz, time, polx, poly, polz, proc, ntr, weight, is, secondparentId, -1, -1, proc); +} + +void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e, + Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz, + TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondparentId, Int_t daughter1Id, Int_t daughter2Id, + TMCProcess proc2) { // printf("Pushing %s toBeDone %5d parentId %5d pdgCode %5d is %5d entries %5d \n", // proc == kPPrimary ? "Primary: " : "Secondary: ", @@ -167,50 +210,66 @@ void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px Int_t trackId = mNumberOfEntriesInParticles; // Set track variable ntr = trackId; - Int_t daughter1Id = -1; - Int_t daughter2Id = -1; + // Int_t daughter1Id = -1; + // Int_t daughter2Id = -1; Int_t iStatus = (proc == kPPrimary) ? is : trackId; TParticle p(pdgCode, iStatus, parentId, secondparentId, daughter1Id, daughter2Id, px, py, pz, e, vx, vy, vz, time); p.SetPolarisation(polx, poly, polz); p.SetWeight(weight); p.SetUniqueID(proc); // using the unique ID to transfer process ID + p.SetBit(ParticleStatus::kPrimary, proc == kPPrimary ? 1 : 0); // set primary bit + p.SetBit(ParticleStatus::kToBeDone, toBeDone == 1 ? 1 : 0); // set to be done bit mNumberOfEntriesInParticles++; insertInVector(mTrackIDtoParticlesEntry, trackId, (int)(mParticles.size())); + handleTransportPrimary(p); // handle selective transport of primary particles + // Push particle on the stack if toBeDone is set - if (proc == kPPrimary) { + if (p.TestBit(ParticleStatus::kPrimary)) { // This is a particle from the primary particle generator // // SetBit is used to pass information about the primary particle to the stack during transport. // Sime particles have already decayed or are partons from a shower. They are needed for the // event history in the stack, but not for transport. // + + // primary particles might have been pushed with a second creation process + // in case we pushed a secondary track of a previous simulation to be continued. + // We save therefore in the UniqueID the correct process + // while the particle will still be treated as a primary given its bit settings + p.SetUniqueID(proc2); + mIndexMap[trackId] = trackId; - p.SetBit(ParticleStatus::kKeep); - p.SetBit(ParticleStatus::kPrimary); - if (toBeDone == 1) { - p.SetBit(ParticleStatus::kToBeDone, 1); + p.SetBit(ParticleStatus::kKeep, 1); + if (p.TestBit(ParticleStatus::kToBeDone)) { mNumberOfPrimariesforTracking++; - } else { - p.SetBit(ParticleStatus::kToBeDone, 0); } mNumberOfPrimaryParticles++; mPrimaryParticles.push_back(p); mTracks->emplace_back(p); } else { - p.SetBit(ParticleStatus::kPrimary, 0); - if (toBeDone == 1) { - p.SetBit(ParticleStatus::kToBeDone, 1); - } else { - p.SetBit(ParticleStatus::kToBeDone, 0); - } mParticles.emplace_back(p); mCurrentParticle0 = p; } mStack.push(p); } +void Stack::handleTransportPrimary(TParticle& p) +{ + // this function tests whether we really want to transport + // this particle and sets the relevant bits accordingly + + if (!p.TestBit(ParticleStatus::kToBeDone) || !p.TestBit(ParticleStatus::kPrimary)) { + return; + } + + if (!mTransportPrimary(p, mPrimaryParticles)) { + p.SetBit(ParticleStatus::kToBeDone, 0); + p.SetBit(ParticleStatus::kInhibited, 1); + } +} + void Stack::PushTrack(int toBeDone, TParticle& p) { // printf("stack -> Pushing Primary toBeDone %5d %5d parentId %5d pdgCode %5d is %5d entries %5d \n", toBeDone, p.TestBit(ParticleStatus::kToBeDone), p.GetFirstMother(), p.GetPdgCode(), p.GetStatusCode(), mNumberOfEntriesInParticles); @@ -218,13 +277,13 @@ void Stack::PushTrack(int toBeDone, TParticle& p) // This method is called // // - during parallel simulation to push primary particles (called by the stack itself) - if (p.GetUniqueID() == 0) { + if (p.TestBit(ParticleStatus::kPrimary)) { // one to one mapping for primaries mIndexMap[mNumberOfPrimaryParticles] = mNumberOfPrimaryParticles; mNumberOfPrimaryParticles++; mPrimaryParticles.push_back(p); // Push particle on the stack - if (p.TestBit(ParticleStatus::kPrimary) && p.TestBit(ParticleStatus::kToBeDone)) { + if (p.TestBit(ParticleStatus::kToBeDone)) { mNumberOfPrimariesforTracking++; } mStack.push(p); @@ -518,14 +577,6 @@ void Stack::UpdateTrackIndex(TRefArray* detList) return a.getTrackID() < b.getTrackID(); }); - // make final indexed container for track references - // fill empty - for (auto& ref : *mTrackRefs) { - if (ref.getTrackID() >= 0) { - mIndexedTrackRefs->addElement(ref.getTrackID(), ref); - } - } - for (auto det : mActiveDetectors) { // update the track indices by delegating to specialized detector functions det->updateHitTrackIndices(mIndexMap); @@ -553,7 +604,6 @@ void Stack::Reset() mNumberOfPrimariesPopped = 0; mPrimaryParticles.clear(); mTrackRefs->clear(); - mIndexedTrackRefs->clear(); mTrackIDtoParticlesEntry.clear(); mHitCounter = 0; } @@ -562,7 +612,6 @@ void Stack::Register() { FairRootManager::Instance()->RegisterAny("MCTrack", mTracks, kTRUE); FairRootManager::Instance()->RegisterAny("TrackRefs", mTrackRefs, kTRUE); - FairRootManager::Instance()->RegisterAny("IndexedTrackRefs", mIndexedTrackRefs, kTRUE); } void Stack::Print(Int_t iVerbose) const diff --git a/DataFormats/simulation/src/StackParam.cxx b/DataFormats/simulation/src/StackParam.cxx index 59917159653b0..c5589d039f8c5 100644 --- a/DataFormats/simulation/src/StackParam.cxx +++ b/DataFormats/simulation/src/StackParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/test/MCTrack.cxx b/DataFormats/simulation/test/MCTrack.cxx index 8190a557fd957..052bb0f360ffe 100644 --- a/DataFormats/simulation/test/MCTrack.cxx +++ b/DataFormats/simulation/test/MCTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/test/testBasicHits.cxx b/DataFormats/simulation/test/testBasicHits.cxx index 8f1e97d292504..e81c173fedae8 100644 --- a/DataFormats/simulation/test/testBasicHits.cxx +++ b/DataFormats/simulation/test/testBasicHits.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/test/testMCCompLabel.cxx b/DataFormats/simulation/test/testMCCompLabel.cxx index 6c4d68498631d..43c234461498d 100644 --- a/DataFormats/simulation/test/testMCCompLabel.cxx +++ b/DataFormats/simulation/test/testMCCompLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ BOOST_AUTO_TEST_CASE(MCCompLabel_test) MCCompLabel lb(std::abs(tr), ev, src, tr < 0); std::cout << "Input: [" << src << '/' << ev << '/' << std::setw(6) << tr << ']' << std::endl; - std::cout << "Encoded: " << lb << " (packed: " << ULong_t(lb) << ")" << std::endl; + std::cout << "Encoded: " << lb << " (packed: " << lb.getRawValue() << ")" << std::endl; labelMap[lb] = tr; int trE, evE, srcE; bool fake; diff --git a/DataFormats/simulation/test/testMCEventLabel.cxx b/DataFormats/simulation/test/testMCEventLabel.cxx index 0ea2c8af288a9..e3ca5966b44ea 100644 --- a/DataFormats/simulation/test/testMCEventLabel.cxx +++ b/DataFormats/simulation/test/testMCEventLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/DataFormats/simulation/test/testMCTruthContainer.cxx b/DataFormats/simulation/test/testMCTruthContainer.cxx index 8e5b66ba826d6..071421073e0ae 100644 --- a/DataFormats/simulation/test/testMCTruthContainer.cxx +++ b/DataFormats/simulation/test/testMCTruthContainer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/AOD/CMakeLists.txt b/Detectors/AOD/CMakeLists.txt index 238591fed5a55..7174760a64e6b 100644 --- a/Detectors/AOD/CMakeLists.txt +++ b/Detectors/AOD/CMakeLists.txt @@ -1,64 +1,61 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( - AODProducerWorkflow - SOURCES src/AODProducerWorkflow.cxx - src/AODProducerWorkflowSpec.cxx - PUBLIC_LINK_LIBRARIES - O2::AnalysisDataModel - O2::DetectorsVertexing - O2::Framework - O2::FT0Workflow - O2::GlobalTracking - O2::GlobalTrackingWorkflow - O2::ITSMFTWorkflow - O2::ITStracking - O2::ITSWorkflow - O2::SimulationDataFormat - O2::Steer - O2::TOFWorkflow - O2::TPCWorkflow - O2::CCDB + AODProducerWorkflow + SOURCES src/AODProducerWorkflowSpec.cxx + PUBLIC_LINK_LIBRARIES + O2::DetectorsVertexing + O2::FT0Workflow + O2::FDDWorkflow + O2::FV0Workflow + O2::Framework + O2::GlobalTracking + O2::GlobalTrackingWorkflow + O2::ITSMFTWorkflow + O2::ITSWorkflow + O2::ITStracking + O2::MCHTracking + O2::MFTWorkflow + O2::MathUtils + O2::SimulationDataFormat + O2::Steer + O2::TPCWorkflow ) - o2_add_executable( workflow COMPONENT_NAME aod-producer SOURCES src/aod-producer-workflow.cxx PUBLIC_LINK_LIBRARIES O2::AODProducerWorkflow ) - o2_add_executable( - standalone-aod-producer - COMPONENT_NAME reco - SOURCES src/StandaloneAODProducer.cxx - PUBLIC_LINK_LIBRARIES - O2::DataFormatsTPC - O2::DataFormatsITSMFT - O2::DataFormatsITS - O2::DataFormatsFT0 - O2::DataFormatsTOF - O2::ITSReconstruction - O2::FT0Reconstruction - O2::TPCFastTransformation - O2::GPUTracking - O2::TPCBase - O2::TPCReconstruction - O2::TOFBase - O2::TOFCalibration - O2::SimConfig - O2::DataFormatsFT0 - O2::AnalysisDataModel - O2::Steer + standalone-aod-producer + COMPONENT_NAME reco + SOURCES src/StandaloneAODProducer.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsTPC + O2::DataFormatsITSMFT + O2::DataFormatsITS + O2::DataFormatsFT0 + O2::DataFormatsFDD + O2::DataFormatsFV0 + O2::DataFormatsTOF + O2::ITSReconstruction + O2::FT0Reconstruction + O2::TPCFastTransformation + O2::TPCBase + O2::TPCReconstruction + O2::TOFBase + O2::TOFCalibration + O2::SimConfig + O2::DataFormatsFT0 + O2::Steer ) - - - diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflow.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflow.h deleted file mode 100644 index c9ce6f23400b3..0000000000000 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflow.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_AODPRODUCER_WORKFLOW_H -#define O2_AODPRODUCER_WORKFLOW_H - -/// @file AODProducerWorkflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2::aodproducer -{ - -framework::WorkflowSpec getAODProducerWorkflow(); - -} // namespace o2::aodproducer -#endif diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 814ead3c15eeb..9a36c4bb3b657 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,18 +14,38 @@ #ifndef O2_AODPRODUCER_WORKFLOW_SPEC #define O2_AODPRODUCER_WORKFLOW_SPEC +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsFT0/RecPoints.h" +#include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsFV0/RecPoints.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsMFT/TrackMFT.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTRD/TrackTRD.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisHelpers.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Steer/MCKinematicsReader.h" #include "TStopwatch.h" -#include <CCDB/BasicCCDBManager.h> + +#include <boost/functional/hash.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/unordered_map.hpp> #include <string> #include <vector> using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using GIndex = o2::dataformats::VtxTrackIndex; +using DataRequest = o2::globaltracking::DataRequest; namespace o2::aodproducer { @@ -37,69 +58,301 @@ using TracksTable = o2::soa::Table<o2::aod::track::CollisionId, o2::aod::track::Z, o2::aod::track::Snp, o2::aod::track::Tgl, - o2::aod::track::Signed1Pt, - o2::aod::track::SigmaY, - o2::aod::track::SigmaZ, - o2::aod::track::SigmaSnp, - o2::aod::track::SigmaTgl, - o2::aod::track::Sigma1Pt, - o2::aod::track::RhoZY, - o2::aod::track::RhoSnpY, - o2::aod::track::RhoSnpZ, - o2::aod::track::RhoTglY, - o2::aod::track::RhoTglZ, - o2::aod::track::RhoTglSnp, - o2::aod::track::Rho1PtY, - o2::aod::track::Rho1PtZ, - o2::aod::track::Rho1PtSnp, - o2::aod::track::Rho1PtTgl, - o2::aod::track::TPCInnerParam, - o2::aod::track::Flags, - o2::aod::track::ITSClusterMap, - o2::aod::track::TPCNClsFindable, - o2::aod::track::TPCNClsFindableMinusFound, - o2::aod::track::TPCNClsFindableMinusCrossedRows, - o2::aod::track::TPCNClsShared, - o2::aod::track::TRDPattern, - o2::aod::track::ITSChi2NCl, - o2::aod::track::TPCChi2NCl, - o2::aod::track::TRDChi2, - o2::aod::track::TOFChi2, - o2::aod::track::TPCSignal, - o2::aod::track::TRDSignal, - o2::aod::track::TOFSignal, - o2::aod::track::Length, - o2::aod::track::TOFExpMom, - o2::aod::track::TrackEtaEMCAL, - o2::aod::track::TrackPhiEMCAL>; + o2::aod::track::Signed1Pt>; + +using TracksCovTable = o2::soa::Table<o2::aod::track::SigmaY, + o2::aod::track::SigmaZ, + o2::aod::track::SigmaSnp, + o2::aod::track::SigmaTgl, + o2::aod::track::Sigma1Pt, + o2::aod::track::RhoZY, + o2::aod::track::RhoSnpY, + o2::aod::track::RhoSnpZ, + o2::aod::track::RhoTglY, + o2::aod::track::RhoTglZ, + o2::aod::track::RhoTglSnp, + o2::aod::track::Rho1PtY, + o2::aod::track::Rho1PtZ, + o2::aod::track::Rho1PtSnp, + o2::aod::track::Rho1PtTgl>; + +using TracksExtraTable = o2::soa::Table<o2::aod::track::TPCInnerParam, + o2::aod::track::Flags, + o2::aod::track::ITSClusterMap, + o2::aod::track::TPCNClsFindable, + o2::aod::track::TPCNClsFindableMinusFound, + o2::aod::track::TPCNClsFindableMinusCrossedRows, + o2::aod::track::TPCNClsShared, + o2::aod::track::TRDPattern, + o2::aod::track::ITSChi2NCl, + o2::aod::track::TPCChi2NCl, + o2::aod::track::TRDChi2, + o2::aod::track::TOFChi2, + o2::aod::track::TPCSignal, + o2::aod::track::TRDSignal, + o2::aod::track::Length, + o2::aod::track::TOFExpMom, + o2::aod::track::TrackEtaEMCAL, + o2::aod::track::TrackPhiEMCAL, + o2::aod::track::TrackTime, + o2::aod::track::TrackTimeRes>; + +using MFTTracksTable = o2::soa::Table<o2::aod::fwdtrack::CollisionId, + o2::aod::fwdtrack::X, + o2::aod::fwdtrack::Y, + o2::aod::fwdtrack::Z, + o2::aod::fwdtrack::Phi, + o2::aod::fwdtrack::Tgl, + o2::aod::fwdtrack::Signed1Pt, + o2::aod::fwdtrack::NClusters, + o2::aod::fwdtrack::Chi2>; + +using FwdTracksTable = o2::soa::Table<o2::aod::fwdtrack::CollisionId, + o2::aod::fwdtrack::TrackType, + o2::aod::fwdtrack::X, + o2::aod::fwdtrack::Y, + o2::aod::fwdtrack::Z, + o2::aod::fwdtrack::Phi, + o2::aod::fwdtrack::Tgl, + o2::aod::fwdtrack::Signed1Pt, + o2::aod::fwdtrack::NClusters, + o2::aod::fwdtrack::PDca, + o2::aod::fwdtrack::RAtAbsorberEnd, + o2::aod::fwdtrack::Chi2, + o2::aod::fwdtrack::Chi2MatchMCHMID, + o2::aod::fwdtrack::Chi2MatchMCHMFT, + o2::aod::fwdtrack::MatchScoreMCHMFT, + o2::aod::fwdtrack::MFTTrackId, + o2::aod::fwdtrack::MCHTrackId, + o2::aod::fwdtrack::MCHBitMap, + o2::aod::fwdtrack::MIDBitMap, + o2::aod::fwdtrack::MIDBoards, + o2::aod::fwdtrack::TrackTime, + o2::aod::fwdtrack::TrackTimeRes>; + +using FwdTracksCovTable = o2::soa::Table<o2::aod::fwdtrack::SigmaX, + o2::aod::fwdtrack::SigmaY, + o2::aod::fwdtrack::SigmaPhi, + o2::aod::fwdtrack::SigmaTgl, + o2::aod::fwdtrack::Sigma1Pt, + o2::aod::fwdtrack::RhoXY, + o2::aod::fwdtrack::RhoPhiX, + o2::aod::fwdtrack::RhoPhiY, + o2::aod::fwdtrack::RhoTglX, + o2::aod::fwdtrack::RhoTglY, + o2::aod::fwdtrack::RhoTglPhi, + o2::aod::fwdtrack::Rho1PtX, + o2::aod::fwdtrack::Rho1PtY, + o2::aod::fwdtrack::Rho1PtPhi, + o2::aod::fwdtrack::Rho1PtTgl>; + +using MCParticlesTable = o2::soa::Table<o2::aod::mcparticle::McCollisionId, + o2::aod::mcparticle::PdgCode, + o2::aod::mcparticle::StatusCode, + o2::aod::mcparticle::Flags, + o2::aod::mcparticle::Mother0Id, + o2::aod::mcparticle::Mother1Id, + o2::aod::mcparticle::Daughter0Id, + o2::aod::mcparticle::Daughter1Id, + o2::aod::mcparticle::Weight, + o2::aod::mcparticle::Px, + o2::aod::mcparticle::Py, + o2::aod::mcparticle::Pz, + o2::aod::mcparticle::E, + o2::aod::mcparticle::Vx, + o2::aod::mcparticle::Vy, + o2::aod::mcparticle::Vz, + o2::aod::mcparticle::Vt>; + +typedef boost::tuple<int, int, int> Triplet_t; + +struct TripletHash : std::unary_function<Triplet_t, std::size_t> { + std::size_t operator()(Triplet_t const& e) const + { + std::size_t seed = 0; + boost::hash_combine(seed, e.get<0>()); + boost::hash_combine(seed, e.get<1>()); + boost::hash_combine(seed, e.get<2>()); + return seed; + } +}; + +struct TripletEqualTo : std::binary_function<Triplet_t, Triplet_t, bool> { + bool operator()(Triplet_t const& x, Triplet_t const& y) const + { + return (x.get<0>() == y.get<0>() && + x.get<1>() == y.get<1>() && + x.get<2>() == y.get<2>()); + } +}; + +typedef boost::unordered_map<Triplet_t, int, TripletHash, TripletEqualTo> TripletsMap_t; class AODProducerWorkflowDPL : public Task { public: - AODProducerWorkflowDPL() = default; + AODProducerWorkflowDPL(GID::mask_t src, std::shared_ptr<DataRequest> dataRequest) : mInputSources(src), mDataRequest(dataRequest) {} ~AODProducerWorkflowDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; void endOfStream(framework::EndOfStreamContext& ec) final; private: - int mFillTracksITS = 1; - int mFillTracksTPC = 1; - int mFillTracksITSTPC = 1; + const float cSpeed = 0.029979246f; // speed of light in TOF units + + GID::mask_t mInputSources; + int64_t mTFNumber{-1}; + int mTruncate{1}; + int mRecoOnly{0}; TStopwatch mTimer; - uint64_t maxGlBC = 0; - uint64_t minGlBC = INT64_MAX; + // unordered map connects global indices and table indices of barrel tracks + // the map is used for V0s and cascades + std::unordered_map<GIndex, int> mGIDToTableID; + int mTableTrID{0}; + + TripletsMap_t mToStore; + + std::shared_ptr<DataRequest> mDataRequest; + + // truncation is enabled by default + uint32_t mCollisionPosition = 0xFFFFFFF0; // 19 bits mantissa + uint32_t mCollisionPositionCov = 0xFFFFE000; // 10 bits mantissa + uint32_t mTrackX = 0xFFFFFFF0; // 19 bits + uint32_t mTrackAlpha = 0xFFFFFFF0; // 19 bits + uint32_t mTrackSnp = 0xFFFFFF00; // 15 bits + uint32_t mTrackTgl = 0xFFFFFF00; // 15 bits + uint32_t mTrack1Pt = 0xFFFFFC00; // 13 bits + uint32_t mTrackCovDiag = 0xFFFFFF00; // 15 bits + uint32_t mTrackCovOffDiag = 0xFFFF0000; // 7 bits + uint32_t mTrackSignal = 0xFFFFFF00; // 15 bits + uint32_t mTrackPosEMCAL = 0xFFFFFF00; // 15 bits + uint32_t mTracklets = 0xFFFFFF00; // 15 bits + uint32_t mMcParticleW = 0xFFFFFFF0; // 19 bits + uint32_t mMcParticlePos = 0xFFFFFFF0; // 19 bits + uint32_t mMcParticleMom = 0xFFFFFFF0; // 19 bits + uint32_t mCaloAmp = 0xFFFFFF00; // 15 bits + uint32_t mCaloTime = 0xFFFFFF00; // 15 bits + uint32_t mMuonTr1P = 0xFFFFFC00; // 13 bits + uint32_t mMuonTrThetaX = 0xFFFFFF00; // 15 bits + uint32_t mMuonTrThetaY = 0xFFFFFF00; // 15 bits + uint32_t mMuonTrZmu = 0xFFFFFFF0; // 19 bits + uint32_t mMuonTrBend = 0xFFFFFFF0; // 19 bits + uint32_t mMuonTrNonBend = 0xFFFFFFF0; // 19 bits + uint32_t mMuonTrCov = 0xFFFF0000; // 7 bits + uint32_t mMuonCl = 0xFFFFFF00; // 15 bits + uint32_t mMuonClErr = 0xFFFF0000; // 7 bits + uint32_t mV0Time = 0xFFFFF000; // 11 bits + uint32_t mFDDTime = 0xFFFFF000; // 11 bits + uint32_t mT0Time = 0xFFFFFF00; // 15 bits + uint32_t mV0Amplitude = 0xFFFFF000; // 11 bits + uint32_t mFDDAmplitude = 0xFFFFF000; // 11 bits + uint32_t mT0Amplitude = 0xFFFFF000; // 11 bits + + // helper struct for extra info in fillTrackTablesPerCollision() + struct TrackExtraInfo { + float tpcInnerParam = 0.f; + uint32_t flags = 0; + uint8_t itsClusterMap = 0; + uint8_t tpcNClsFindable = 0; + int8_t tpcNClsFindableMinusFound = 0; + int8_t tpcNClsFindableMinusCrossedRows = 0; + uint8_t tpcNClsShared = 0; + uint8_t trdPattern = 0; + float itsChi2NCl = -999.f; + float tpcChi2NCl = -999.f; + float trdChi2 = -999.f; + float tofChi2 = -999.f; + float tpcSignal = -999.f; + float trdSignal = -999.f; + float tofSignal = -999.f; + float length = -999.f; + float tofExpMom = -999.f; + float trackEtaEMCAL = -999.f; + float trackPhiEMCAL = -999.f; + float trackTime = -999.f; + float trackTimeRes = -999.f; + }; + + // helper struct for mc track labels + // using -1 as dummies for AOD + struct MCLabels { + uint32_t labelID = -1; + uint32_t labelITS = -1; + uint32_t labelTPC = -1; + uint16_t labelMask = 0; + uint8_t fwdLabelMask = 0; + }; + + void collectBCs(gsl::span<const o2::fdd::RecPoint>& fddRecPoints, + gsl::span<const o2::ft0::RecPoints>& ft0RecPoints, + gsl::span<const o2::fv0::RecPoints>& fv0RecPoints, + gsl::span<const o2::dataformats::PrimaryVertex>& primVertices, + const std::vector<o2::InteractionTimeRecord>& mcRecords, + std::map<uint64_t, int>& bcsMap); + + uint64_t getTFNumber(const o2::InteractionRecord& tfStartIR, int runNumber); + + template <typename TracksCursorType, typename TracksCovCursorType> + void addToTracksTable(TracksCursorType& tracksCursor, TracksCovCursorType& tracksCovCursor, + const o2::track::TrackParCov& track, int collisionID); + + template <typename TracksExtraCursorType> + void addToTracksExtraTable(TracksExtraCursorType& tracksExtraCursor, TrackExtraInfo& extraInfoHolder); + + template <typename mftTracksCursorType> + void addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, const o2::mft::TrackMFT& track, int collisionID); + + template <typename fwdTracksCursorType, typename fwdTracksCovCursorType, typename fwdTrackType> + void addToFwdTracksTable(fwdTracksCursorType& fwdTracksCursor, fwdTracksCovCursorType& fwdTracksCovCursor, const fwdTrackType& track, int collisionID, + const math_utils::Point3D<double>& vertex); + + // helper for track tables + // * fills tables collision by collision + // * interaction time is for TOF information + template <typename TracksCursorType, typename TracksCovCursorType, typename TracksExtraCursorType, typename mftTracksCursorType, typename fwdTracksCursorType, typename fwdTracksCovCursorType> + void fillTrackTablesPerCollision(int collisionID, + double interactionTime, + const o2::dataformats::VtxTrackRef& trackRef, + gsl::span<const GIndex>& GIndices, + o2::globaltracking::RecoContainer& data, + TracksCursorType& tracksCursor, + TracksCovCursorType& tracksCovCursor, + TracksExtraCursorType& tracksExtraCursor, + mftTracksCursorType& mftTracksCursor, + fwdTracksCursorType& fwdTracksCursor, + fwdTracksCovCursorType& fwdTracksCovCursor, + const dataformats::PrimaryVertex& vertex); + + template <typename MCParticlesCursorType> + void fillMCParticlesTable(o2::steer::MCKinematicsReader& mcReader, + const MCParticlesCursorType& mcParticlesCursor, + gsl::span<const o2::dataformats::VtxTrackRef>& primVer2TRefs, + gsl::span<const GIndex>& GIndices, + o2::globaltracking::RecoContainer& data, + std::vector<std::pair<int, int>> const& mcColToEvSrc); + + template <typename MCTrackLabelCursorType, typename MCMFTTrackLabelCursorType, typename MCFwdTrackLabelCursorType> + void fillMCTrackLabelsTable(const MCTrackLabelCursorType& mcTrackLabelCursor, + const MCMFTTrackLabelCursorType& mcMFTTrackLabelCursor, + const MCFwdTrackLabelCursorType& mcFwdTrackLabelCursor, + o2::dataformats::VtxTrackRef const& trackRef, + gsl::span<const GIndex>& primVerGIs, + o2::globaltracking::RecoContainer& data); - void findMinMaxBc(gsl::span<const o2::ft0::RecPoints>& ft0RecPoints, gsl::span<const o2::dataformats::TrackTPCITS>& tracksITSTPC, const std::vector<o2::InteractionTimeRecord>& mcRecords); - int64_t getTFNumber(uint64_t firstVtxGlBC, int runNumber); + // helper for tpc clusters + void countTPCClusters(const o2::tpc::TrackTPC& track, + const gsl::span<const o2::tpc::TPCClRefElem>& tpcClusRefs, + const gsl::span<const unsigned char>& tpcClusShMap, + const o2::tpc::ClusterNativeAccess& tpcClusAcc, + uint8_t& shared, uint8_t& found, uint8_t& crossed); - template <typename TracksType, typename TracksCursorType> - void fillTracksTable(const TracksType& tracks, std::vector<int>& vCollRefs, const TracksCursorType& tracksCursor, int trackType); + // helper for trd pattern + uint8_t getTRDPattern(const o2::trd::TrackTRD& track); }; /// create a processor spec -framework::DataProcessorSpec getAODProducerWorkflowSpec(); +framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool useMC); } // namespace o2::aodproducer diff --git a/Detectors/AOD/src/AODProducerWorkflow.cxx b/Detectors/AOD/src/AODProducerWorkflow.cxx deleted file mode 100644 index 51a46f46f5cd0..0000000000000 --- a/Detectors/AOD/src/AODProducerWorkflow.cxx +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file AODProducerWorkflow.cxx - -#include "Algorithm/RangeTokenizer.h" -#include "AODProducerWorkflow/AODProducerWorkflow.h" -#include "AODProducerWorkflow/AODProducerWorkflowSpec.h" -#include "DataFormatsTPC/Constants.h" -#include "FT0Workflow/DigitReaderSpec.h" -#include "FT0Workflow/ReconstructionSpec.h" -#include "GlobalTracking/MatchTPCITSParams.h" -#include "GlobalTrackingWorkflow/MatchTPCITSWorkflow.h" -#include "GlobalTrackingWorkflow/PrimaryVertexingSpec.h" -#include "GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h" -#include "GlobalTrackingWorkflow/TPCITSMatchingSpec.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h" -#include "ITSMFTWorkflow/ClusterReaderSpec.h" -#include "ITSWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/PublisherSpec.h" -#include "TPCWorkflow/TrackReaderSpec.h" - -namespace o2::aodproducer -{ - -framework::WorkflowSpec getAODProducerWorkflow() -{ - // TODO: - // switch to configurable parameters (?) - bool useMC = false; - - // FIXME: - // switch (?) from o2::ft0::getReconstructionSpec to RecPointReader - // (which does not return RECCHDATA at the moment) - framework::WorkflowSpec specs{ - o2::vertexing::getPrimaryVertexReaderSpec(useMC), - o2::globaltracking::getTrackTPCITSReaderSpec(useMC), - o2::its::getITSTrackReaderSpec(useMC), - o2::tpc::getTPCTrackReaderSpec(useMC), - o2::ft0::getDigitReaderSpec(useMC), - o2::ft0::getReconstructionSpec(useMC), - o2::aodproducer::getAODProducerWorkflowSpec()}; - - return specs; -} - -} // namespace o2::aodproducer diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 70e3f6190ad90..e75a4395e3026 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,77 +13,124 @@ #include "AODProducerWorkflow/AODProducerWorkflowSpec.h" #include "DataFormatsFT0/RecPoints.h" +#include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsITS/TrackITS.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMFT/TrackMFT.h" #include "DataFormatsTPC/TrackTPC.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include <CCDB/BasicCCDBManager.h> +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsBase/GeometryManager.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" #include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" #include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisHelpers.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/DataTypes.h" #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" #include "Framework/TableBuilder.h" #include "Framework/TableTreeHelpers.h" +#include "FDDBase/Constants.h" +#include "FT0Base/Geometry.h" +#include "FV0Base/Geometry.h" #include "GlobalTracking/MatchTOF.h" -#include "GlobalTrackingWorkflow/PrimaryVertexingSpec.h" -#include "Headers/DataHeader.h" +#include "ReconstructionDataFormats/Cascade.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" #include "SimulationDataFormat/DigitizationContext.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/MCEventLabel.h" +#include "SimulationDataFormat/MCTrack.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "Steer/MCKinematicsReader.h" #include "TMath.h" +#include "MathUtils/Utils.h" +#include "Math/SMatrix.h" +#include <TMatrixD.h> #include <map> +#include <unordered_map> #include <vector> using namespace o2::framework; +using namespace o2::math_utils::detail; +using PVertex = o2::dataformats::PrimaryVertex; +using GIndex = o2::dataformats::VtxTrackIndex; +using DataRequest = o2::globaltracking::DataRequest; +using GID = o2::dataformats::GlobalTrackID; +using SMatrix55Sym = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; namespace o2::aodproducer { -void AODProducerWorkflowDPL::findMinMaxBc(gsl::span<const o2::ft0::RecPoints>& ft0RecPoints, gsl::span<const o2::dataformats::TrackTPCITS>& tracksITSTPC, const std::vector<o2::InteractionTimeRecord>& mcRecords) +namespace { +// takes a local vertex timing in NS and converts to a global BC information +// using the orbit offset from the simulation +uint64_t relativeTime_to_GlobalBC(double relativeTimeStampInNS) +{ + return std::round((o2::raw::HBFUtils::Instance().getFirstSampledTFIR().bc2ns() + relativeTimeStampInNS) / o2::constants::lhc::LHCBunchSpacingNS); +} +// takes a local vertex timing in NS and converts to a lobal BC information +// relative to start of timeframe +uint64_t relativeTime_to_LocalBC(double relativeTimeStampInNS) +{ + return std::round(relativeTimeStampInNS / o2::constants::lhc::LHCBunchSpacingNS); +} +} // namespace + +void AODProducerWorkflowDPL::collectBCs(gsl::span<const o2::fdd::RecPoint>& fddRecPoints, + gsl::span<const o2::ft0::RecPoints>& ft0RecPoints, + gsl::span<const o2::fv0::RecPoints>& fv0RecPoints, + gsl::span<const o2::dataformats::PrimaryVertex>& primVertices, + const std::vector<o2::InteractionTimeRecord>& mcRecords, + std::map<uint64_t, int>& bcsMap) +{ + // collecting non-empty BCs and enumerating them + for (auto& rec : mcRecords) { + uint64_t globalBC = rec.toLong(); + bcsMap[globalBC] = 1; + } + + for (auto& fddRecPoint : fddRecPoints) { + uint64_t globalBC = fddRecPoint.getInteractionRecord().toLong(); + bcsMap[globalBC] = 1; + } + for (auto& ft0RecPoint : ft0RecPoints) { - uint64_t bc = ft0RecPoint.getInteractionRecord().orbit * o2::constants::lhc::LHCMaxBunches + ft0RecPoint.getInteractionRecord().bc; - if (minGlBC > bc) { - minGlBC = bc; - } - if (maxGlBC < bc) { - maxGlBC = bc; - } + uint64_t globalBC = ft0RecPoint.getInteractionRecord().toLong(); + bcsMap[globalBC] = 1; } - for (auto& trackITSTPC : tracksITSTPC) { - Double_t timeStamp = trackITSTPC.getTimeMUS().getTimeStamp() * 1.E3; // mus to ns - uint64_t bc = (uint64_t)(timeStamp / o2::constants::lhc::LHCBunchSpacingNS); - if (minGlBC > bc) { - minGlBC = bc; - } - if (maxGlBC < bc) { - maxGlBC = bc; - } + for (auto& fv0RecPoint : fv0RecPoints) { + uint64_t globalBC = fv0RecPoint.getInteractionRecord().toLong(); + bcsMap[globalBC] = 1; } - for (auto& rec : mcRecords) { - uint64_t bc = rec.bc + rec.orbit * o2::constants::lhc::LHCMaxBunches; - if (minGlBC > bc) { - minGlBC = bc; - } - if (maxGlBC < bc) { - maxGlBC = bc; - } + for (auto& vertex : primVertices) { + auto& timeStamp = vertex.getTimeStamp(); + double tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns + uint64_t globalBC = relativeTime_to_GlobalBC(tsTimeStamp); + bcsMap[globalBC] = 1; + } + + int bcID = 0; + for (auto& item : bcsMap) { + item.second = bcID; + bcID++; } } -int64_t AODProducerWorkflowDPL::getTFNumber(uint64_t firstVtxGlBC, int runNumber) +uint64_t AODProducerWorkflowDPL::getTFNumber(const o2::InteractionRecord& tfStartIR, int runNumber) { - // FIXME: - // check if this code is correct - auto& mgr = o2::ccdb::BasicCCDBManager::instance(); o2::ccdb::CcdbApi ccdb_api; const std::string rct_path = "RCT/RunInformation/"; @@ -104,127 +152,742 @@ int64_t AODProducerWorkflowDPL::getTFNumber(uint64_t firstVtxGlBC, int runNumber // mus to ms ts = ts / 1000; - // firstRec --> calculated using `minimal` global BC in the simulation (see AODProducerWorkflowDPL::findMinMaxBc) - // firstVtxGlBC --> calculated using global BC correspinding to the first prim. vertex - uint32_t initialOrbit = mapStartOrbit->at(runNumber); - uint16_t firstRecBC = minGlBC % o2::constants::lhc::LHCMaxBunches; - uint32_t firstRecOrbit = minGlBC / o2::constants::lhc::LHCMaxBunches; - uint16_t firstVtxBC = firstVtxGlBC % o2::constants::lhc::LHCMaxBunches; - uint32_t firstVtxOrbit = firstVtxGlBC / o2::constants::lhc::LHCMaxBunches; + uint16_t firstRecBC = tfStartIR.bc; + uint32_t firstRecOrbit = tfStartIR.orbit; const o2::InteractionRecord firstRec(firstRecBC, firstRecOrbit); - const o2::InteractionRecord firstVtx(firstVtxBC, firstVtxOrbit); - ts += (firstVtx - firstRec).bc2ns() / 1000000; + ts += firstRec.bc2ns() / 1000000; return ts; }; -template <typename TracksType, typename TracksCursorType> -void AODProducerWorkflowDPL::fillTracksTable(const TracksType& tracks, std::vector<int>& vCollRefs, const TracksCursorType& tracksCursor, int trackType) +template <typename TracksCursorType, typename TracksCovCursorType> +void AODProducerWorkflowDPL::addToTracksTable(TracksCursorType& tracksCursor, TracksCovCursorType& tracksCovCursor, + const o2::track::TrackParCov& track, int collisionID) +{ + // tracks + tracksCursor(0, + collisionID, + o2::aod::track::Track, + truncateFloatFraction(track.getX(), mTrackX), + truncateFloatFraction(track.getAlpha(), mTrackAlpha), + track.getY(), + track.getZ(), + truncateFloatFraction(track.getSnp(), mTrackSnp), + truncateFloatFraction(track.getTgl(), mTrackTgl), + truncateFloatFraction(track.getQ2Pt(), mTrack1Pt)); + // trackscov + float sY = TMath::Sqrt(track.getSigmaY2()), sZ = TMath::Sqrt(track.getSigmaZ2()), sSnp = TMath::Sqrt(track.getSigmaSnp2()), + sTgl = TMath::Sqrt(track.getSigmaTgl2()), sQ2Pt = TMath::Sqrt(track.getSigma1Pt2()); + tracksCovCursor(0, + truncateFloatFraction(sY, mTrackCovDiag), + truncateFloatFraction(sZ, mTrackCovDiag), + truncateFloatFraction(sSnp, mTrackCovDiag), + truncateFloatFraction(sTgl, mTrackCovDiag), + truncateFloatFraction(sQ2Pt, mTrackCovDiag), + (Char_t)(128. * track.getSigmaZY() / (sZ * sY)), + (Char_t)(128. * track.getSigmaSnpY() / (sSnp * sY)), + (Char_t)(128. * track.getSigmaSnpZ() / (sSnp * sZ)), + (Char_t)(128. * track.getSigmaTglY() / (sTgl * sY)), + (Char_t)(128. * track.getSigmaTglZ() / (sTgl * sZ)), + (Char_t)(128. * track.getSigmaTglSnp() / (sTgl * sSnp)), + (Char_t)(128. * track.getSigma1PtY() / (sQ2Pt * sY)), + (Char_t)(128. * track.getSigma1PtZ() / (sQ2Pt * sZ)), + (Char_t)(128. * track.getSigma1PtSnp() / (sQ2Pt * sSnp)), + (Char_t)(128. * track.getSigma1PtTgl() / (sQ2Pt * sTgl))); +} + +template <typename TracksExtraCursorType> +void AODProducerWorkflowDPL::addToTracksExtraTable(TracksExtraCursorType& tracksExtraCursor, TrackExtraInfo& extraInfoHolder) +{ + // extra + tracksExtraCursor(0, + truncateFloatFraction(extraInfoHolder.tpcInnerParam, mTrack1Pt), + extraInfoHolder.flags, + extraInfoHolder.itsClusterMap, + extraInfoHolder.tpcNClsFindable, + extraInfoHolder.tpcNClsFindableMinusFound, + extraInfoHolder.tpcNClsFindableMinusCrossedRows, + extraInfoHolder.tpcNClsShared, + extraInfoHolder.trdPattern, + truncateFloatFraction(extraInfoHolder.itsChi2NCl, mTrackCovOffDiag), + truncateFloatFraction(extraInfoHolder.tpcChi2NCl, mTrackCovOffDiag), + truncateFloatFraction(extraInfoHolder.trdChi2, mTrackCovOffDiag), + truncateFloatFraction(extraInfoHolder.tofChi2, mTrackCovOffDiag), + truncateFloatFraction(extraInfoHolder.tpcSignal, mTrackSignal), + truncateFloatFraction(extraInfoHolder.trdSignal, mTrackSignal), + truncateFloatFraction(extraInfoHolder.length, mTrackSignal), + truncateFloatFraction(extraInfoHolder.tofExpMom, mTrack1Pt), + truncateFloatFraction(extraInfoHolder.trackEtaEMCAL, mTrackPosEMCAL), + truncateFloatFraction(extraInfoHolder.trackPhiEMCAL, mTrackPosEMCAL), + truncateFloatFraction(extraInfoHolder.trackTime, mTrackSignal), + truncateFloatFraction(extraInfoHolder.trackTimeRes, mTrackSignal)); +} + +template <typename mftTracksCursorType> +void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, + const o2::mft::TrackMFT& track, int collisionID) +{ + // mft tracks + mftTracksCursor(0, + collisionID, + track.getX(), + track.getY(), + track.getZ(), + track.getPhi(), + track.getTanl(), + track.getInvQPt(), + track.getNumberOfPoints(), + track.getTrackChi2()); +} + +template <typename TracksCursorType, typename TracksCovCursorType, typename TracksExtraCursorType, typename MftTracksCursorType, typename FwdTracksCursorType, typename FwdTracksCovCursorType> +void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, + double interactionTime, + const o2::dataformats::VtxTrackRef& trackRef, + gsl::span<const GIndex>& GIndices, + o2::globaltracking::RecoContainer& data, + TracksCursorType& tracksCursor, + TracksCovCursorType& tracksCovCursor, + TracksExtraCursorType& tracksExtraCursor, + MftTracksCursorType& mftTracksCursor, + FwdTracksCursorType& fwdTracksCursor, + FwdTracksCovCursorType& fwdTracksCovCursor, + const dataformats::PrimaryVertex& vertex) +{ + const auto& tpcClusRefs = data.getTPCTracksClusterRefs(); + const auto& tpcClusShMap = data.clusterShMapTPC; + const auto& tpcClusAcc = data.getTPCClusters(); + const auto& tpcTracks = data.getTPCTracks(); + const auto& itsTracks = data.getITSTracks(); + const auto& itsABRefs = data.getITSABRefs(); + const auto& tofClus = data.getTOFClusters(); + + for (int src = GIndex::NSources; src--;) { + int start = trackRef.getFirstEntryOfSource(src); + int end = start + trackRef.getEntriesOfSource(src); + for (int ti = start; ti < end; ti++) { + TrackExtraInfo extraInfoHolder; + auto& trackIndex = GIndices[ti]; + if (GIndex::includesSource(src, mInputSources)) { + if (src == GIndex::Source::MFT) { // MFT tracks are treated separately since they are stored in a different table + const auto& track = data.getMFTTrack(trackIndex); + addToMFTTracksTable(mftTracksCursor, track, collisionID); + } else if (src == GIndex::Source::MCH) { + // FwdTracks tracks are treated separately since they are stored in a different table + const auto& track = data.getMCHTrack(trackIndex); + if (collisionID < 0) { + InteractionRecord meanIR; + auto rofsMCH = data.getMCHTracksROFRecords(); + for (const auto& rof : rofsMCH) { + if (trackIndex >= rof.getFirstIdx() && trackIndex <= rof.getLastIdx()) { + meanIR = rof.getBCData() + rof.getBCWidth() / 2; + } + math_utils::Point3D<double> vertex{}; + // FIXME: should we get better + // than {0,0,0} as vertex here ? + addToFwdTracksTable(fwdTracksCursor, fwdTracksCovCursor, track, -1, vertex); + } + } else { + math_utils::Point3D<double> vtx{vertex.getX(), + vertex.getY(), vertex.getZ()}; + addToFwdTracksTable(fwdTracksCursor, fwdTracksCovCursor, track, collisionID, vtx); + } + } else if (src == GIndex::Source::MFTMCH) { + const auto& track = data.getGlobalFwdTrack(trackIndex); + addToFwdTracksTable(fwdTracksCursor, fwdTracksCovCursor, track, collisionID, {0, 0, 0}); + } else { + auto contributorsGID = data.getSingleDetectorRefs(trackIndex); + const auto& trackPar = data.getTrackParam(trackIndex); + if (contributorsGID[GIndex::Source::ITS].isIndexSet()) { + extraInfoHolder.itsClusterMap = itsTracks[contributorsGID[GIndex::ITS].getIndex()].getPattern(); + } else if (contributorsGID[GIndex::Source::ITSAB].isIndexSet()) { // this is an ITS-TPC afterburner contributor + extraInfoHolder.itsClusterMap = itsABRefs[contributorsGID[GIndex::Source::ITSAB].getIndex()].pattern; + } + if (contributorsGID[GIndex::Source::TPC].isIndexSet()) { + const auto& tpcOrig = tpcTracks[contributorsGID[GIndex::TPC].getIndex()]; + extraInfoHolder.tpcInnerParam = tpcOrig.getP(); + extraInfoHolder.tpcChi2NCl = tpcOrig.getNClusters() ? tpcOrig.getChi2() / tpcOrig.getNClusters() : 0; + extraInfoHolder.tpcSignal = tpcOrig.getdEdx().dEdxTotTPC; + uint8_t shared, found, crossed; // fixme: need to switch from these placeholders to something more reasonable + countTPCClusters(tpcOrig, tpcClusRefs, tpcClusShMap, tpcClusAcc, shared, found, crossed); + extraInfoHolder.tpcNClsFindable = tpcOrig.getNClusters(); + extraInfoHolder.tpcNClsFindableMinusFound = tpcOrig.getNClusters() - found; + extraInfoHolder.tpcNClsFindableMinusCrossedRows = tpcOrig.getNClusters() - crossed; + extraInfoHolder.tpcNClsShared = shared; + } + if (contributorsGID[GIndex::Source::ITSTPCTOF].isIndexSet()) { + const auto& tofMatch = data.getTOFMatch(contributorsGID[GIndex::Source::ITSTPCTOF]); + extraInfoHolder.tofChi2 = tofMatch.getChi2(); + const auto& tofInt = tofMatch.getLTIntegralOut(); + float intLen = tofInt.getL(); + extraInfoHolder.length = intLen; + if (interactionTime > 0) { + extraInfoHolder.tofSignal = static_cast<float>(tofMatch.getSignal() - interactionTime); + } + const float mass = o2::constants::physics::MassPionCharged; // default pid = pion + if (tofInt.getTOF(o2::track::PID::Pion) > 0.f) { + const float expBeta = (intLen / (tofInt.getTOF(o2::track::PID::Pion) * cSpeed)); + extraInfoHolder.tofExpMom = mass * expBeta / std::sqrt(1.f - expBeta * expBeta); + } + const auto& tofCl = tofClus[contributorsGID[GIndex::Source::TOF]]; + // correct the time of the track + extraInfoHolder.trackTime = (tofCl.getTime() - tofInt.getTOF(trackPar.getPID())) * 1e-3; // tof time in \mus, FIXME: account for time of flight to R TOF + extraInfoHolder.trackTimeRes = 200e-3; // FIXME: calculate actual resolution (if possible?) + } + if (src == GIndex::Source::TPCTRD || src == GIndex::Source::ITSTPCTRD) { + const auto& trdOrig = data.getTrack<o2::trd::TrackTRD>(src, contributorsGID[src].getIndex()); + extraInfoHolder.trdChi2 = trdOrig.getChi2(); + extraInfoHolder.trdPattern = getTRDPattern(trdOrig); + } + addToTracksTable(tracksCursor, tracksCovCursor, trackPar, collisionID); + addToTracksExtraTable(tracksExtraCursor, extraInfoHolder); + // collecting table indices of barrel tracks for V0s table + mGIDToTableID.emplace(trackIndex, mTableTrID); + mTableTrID++; + } + } + } + } +} + +template <typename FwdTracksCursorType, typename FwdTracksCovCursorType, typename fwdTrackType> +void AODProducerWorkflowDPL::addToFwdTracksTable(FwdTracksCursorType& fwdTracksCursor, FwdTracksCovCursorType& fwdTracksCovCursor, + const fwdTrackType& track, int collisionID, + const math_utils::Point3D<double>& vertex) + +{ + + // table columns must be floats, not double + uint8_t trackTypeId; + float x; + float y; + float z; + float rabs; + float phi; + float tanl; + float invqpt; + float chi2; + float pdca; + int nClusters; + float chi2matchmchmid = -1.0; + float chi2matchmchmft = -1.0; + float matchscoremchmft = -1.0; + int matchmfttrackid = -1; + int matchmchtrackid = -1; + uint16_t mchBitMap = 0; + uint8_t midBitMap = 0; + uint32_t midBoards = 0; + float trackTime = 0; + float trackTimeRes = 0; + + float sigX = 0; + float sigY = 0; + float sigPhi = 0; + float sigTgl = 0; + float sig1Pt = 0; + + int8_t rhoXY = 0; + int8_t rhoPhiX = 0; + int8_t rhoPhiY = 0; + int8_t rhoTglX = 0; + int8_t rhoTglY = 0; + int8_t rhoTglPhi = 0; + int8_t rho1PtX = 0; + int8_t rho1PtY = 0; + int8_t rho1PtPhi = 0; + int8_t rho1PtTgl = 0; + + if constexpr (!std::is_base_of_v<o2::track::TrackParCovFwd, std::decay_t<decltype(track)>>) { + // This is a MCH track + trackTypeId = o2::aod::fwdtrack::MCHStandaloneTrack; + // mch standalone tracks extrapolated to vertex + + // compute 3 sets of tracks parameters : + // - at vertex + // - at DCA + // - at the end of the absorber + + // extrapolate to vertex + o2::mch::TrackParam trackParamAtVertex(track.getZ(), track.getParameters()); + double errVtx{0.0}; // FIXME: get errors associated with vertex if available + double errVty{0.0}; + if (!o2::mch::TrackExtrap::extrapToVertex(trackParamAtVertex, vertex.x(), vertex.y(), vertex.z(), errVtx, errVty)) { + return; + } + + // extrapolate to DCA + o2::mch::TrackParam trackParamAtDCA(track.getZ(), track.getParameters()); + if (!o2::mch::TrackExtrap::extrapToVertexWithoutBranson(trackParamAtDCA, vertex.z())) { + return; + } + + // extrapolate to the end of the absorber + o2::mch::TrackParam trackParamAtRAbs(track.getZ(), track.getParameters()); + if (!o2::mch::TrackExtrap::extrapToZ(trackParamAtRAbs, -505.)) { // FIXME: replace hardcoded 505 + return; + } + + double dcaX = trackParamAtDCA.getNonBendingCoor() - vertex.x(); + double dcaY = trackParamAtDCA.getBendingCoor() - vertex.y(); + double dca = std::sqrt(dcaX * dcaX + dcaY * dcaY); + + double xAbs = trackParamAtRAbs.getNonBendingCoor(); + double yAbs = trackParamAtRAbs.getBendingCoor(); + + double px = trackParamAtVertex.px(); + double py = trackParamAtVertex.py(); + double pz = trackParamAtVertex.pz(); + + double pt = std::sqrt(px * px + py * py); + double dphi = std::asin(py / pt); + double dtanl = pz / pt; + double dinvqpt = 1.0 / (trackParamAtVertex.getCharge() * pt); + double dpdca = trackParamAtVertex.p() * dca; + double dchi2 = track.getChi2OverNDF(); + + x = trackParamAtVertex.getNonBendingCoor(); + y = trackParamAtVertex.getBendingCoor(); + z = trackParamAtVertex.getZ(); + rabs = std::sqrt(xAbs * xAbs + yAbs * yAbs); + phi = dphi; + tanl = dtanl; + invqpt = dinvqpt; + chi2 = dchi2; + pdca = dpdca; + nClusters = track.getNClusters(); + + sigX = TMath::Sqrt(trackParamAtVertex.getCovariances()(0, 0)); + sigY = TMath::Sqrt(trackParamAtVertex.getCovariances()(1, 1)); + sigPhi = TMath::Sqrt(trackParamAtVertex.getCovariances()(2, 2)); + sigTgl = TMath::Sqrt(trackParamAtVertex.getCovariances()(3, 3)); + sig1Pt = TMath::Sqrt(trackParamAtVertex.getCovariances()(4, 4)); + rhoXY = (Char_t)(128. * trackParamAtVertex.getCovariances()(0, 1) / (sigX * sigY)); + rhoPhiX = (Char_t)(128. * trackParamAtVertex.getCovariances()(0, 2) / (sigPhi * sigX)); + rhoPhiY = (Char_t)(128. * trackParamAtVertex.getCovariances()(1, 2) / (sigPhi * sigY)); + rhoTglX = (Char_t)(128. * trackParamAtVertex.getCovariances()(0, 3) / (sigTgl * sigX)); + rhoTglY = (Char_t)(128. * trackParamAtVertex.getCovariances()(1, 3) / (sigTgl * sigY)); + rhoTglPhi = (Char_t)(128. * trackParamAtVertex.getCovariances()(2, 3) / (sigTgl * sigPhi)); + rho1PtX = (Char_t)(128. * trackParamAtVertex.getCovariances()(0, 4) / (sig1Pt * sigX)); + rho1PtY = (Char_t)(128. * trackParamAtVertex.getCovariances()(1, 4) / (sig1Pt * sigY)); + rho1PtPhi = (Char_t)(128. * trackParamAtVertex.getCovariances()(2, 4) / (sig1Pt * sigPhi)); + rho1PtTgl = (Char_t)(128. * trackParamAtVertex.getCovariances()(3, 4) / (sig1Pt * sigTgl)); + + } else { + // This is a GlobalMuonTrack or a GlobalForwardTrack + x = track.getX(); + y = track.getY(); + z = track.getZ(); + phi = track.getPhi(); + tanl = track.getTanl(); + invqpt = track.getInvQPt(); + chi2 = track.getTrackChi2(); + //nClusters = track.getNumberOfPoints(); + chi2matchmchmid = track.getMIDMatchingChi2(); + chi2matchmchmft = track.getMatchingChi2(); + matchmfttrackid = track.getMFTTrackID(); + matchmchtrackid = track.getMCHTrackID(); + + sigX = TMath::Sqrt(track.getCovariances()(0, 0)); + sigY = TMath::Sqrt(track.getCovariances()(1, 1)); + sigPhi = TMath::Sqrt(track.getCovariances()(2, 2)); + sigTgl = TMath::Sqrt(track.getCovariances()(3, 3)); + sig1Pt = TMath::Sqrt(track.getCovariances()(4, 4)); + rhoXY = (Char_t)(128. * track.getCovariances()(0, 1) / (sigX * sigY)); + rhoPhiX = (Char_t)(128. * track.getCovariances()(0, 2) / (sigPhi * sigX)); + rhoPhiY = (Char_t)(128. * track.getCovariances()(1, 2) / (sigPhi * sigY)); + rhoTglX = (Char_t)(128. * track.getCovariances()(0, 3) / (sigTgl * sigX)); + rhoTglY = (Char_t)(128. * track.getCovariances()(1, 3) / (sigTgl * sigY)); + rhoTglPhi = (Char_t)(128. * track.getCovariances()(2, 3) / (sigTgl * sigPhi)); + rho1PtX = (Char_t)(128. * track.getCovariances()(0, 4) / (sig1Pt * sigX)); + rho1PtY = (Char_t)(128. * track.getCovariances()(1, 4) / (sig1Pt * sigY)); + rho1PtPhi = (Char_t)(128. * track.getCovariances()(2, 4) / (sig1Pt * sigPhi)); + rho1PtTgl = (Char_t)(128. * track.getCovariances()(3, 4) / (sig1Pt * sigTgl)); + + trackTypeId = (chi2matchmchmid >= 0) ? o2::aod::fwdtrack::GlobalMuonTrack : o2::aod::fwdtrack::GlobalForwardTrack; + } + + auto covmat = track.getCovariances(); + + fwdTracksCursor(0, + collisionID, + trackTypeId, + x, + y, + z, + phi, + tanl, + invqpt, + nClusters, + pdca, + rabs, + chi2, + chi2matchmchmid, + chi2matchmchmft, + matchscoremchmft, + matchmfttrackid, + matchmchtrackid, + mchBitMap, + midBitMap, + midBoards, + trackTime, + trackTimeRes); + + fwdTracksCovCursor(0, + sigX, + sigY, + sigPhi, + sigTgl, + sig1Pt, + rhoXY, + rhoPhiX, + rhoPhiY, + rhoTglX, + rhoTglY, + rhoTglPhi, + rho1PtX, + rho1PtY, + rho1PtPhi, + rho1PtTgl); +} + +template <typename MCParticlesCursorType> +void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& mcReader, + const MCParticlesCursorType& mcParticlesCursor, + gsl::span<const o2::dataformats::VtxTrackRef>& primVer2TRefs, + gsl::span<const GIndex>& GIndices, + o2::globaltracking::RecoContainer& data, + std::vector<std::pair<int, int>> const& mcColToEvSrc) +{ + // mark reconstructed MC particles to store them into the table + for (auto& trackRef : primVer2TRefs) { + for (int src = GIndex::NSources; src--;) { + int start = trackRef.getFirstEntryOfSource(src); + int end = start + trackRef.getEntriesOfSource(src); + for (int ti = start; ti < end; ti++) { + auto& trackIndex = GIndices[ti]; + if (GIndex::includesSource(src, mInputSources)) { + auto mcTruth = data.getTrackMCLabel(trackIndex); + if (!mcTruth.isValid()) { + continue; + } + int source = mcTruth.getSourceID(); + int event = mcTruth.getEventID(); + int particle = mcTruth.getTrackID(); + mToStore[Triplet_t(source, event, particle)] = 1; + // treating contributors of global tracks + auto contributorsGID = data.getSingleDetectorRefs(trackIndex); + if (contributorsGID[GIndex::Source::ITS].isIndexSet() && contributorsGID[GIndex::Source::TPC].isIndexSet()) { + auto mcTruthITS = data.getTrackMCLabel(contributorsGID[GIndex::Source::ITS]); + if (mcTruthITS.isValid()) { + source = mcTruthITS.getSourceID(); + event = mcTruthITS.getEventID(); + particle = mcTruthITS.getTrackID(); + mToStore[Triplet_t(source, event, particle)] = 1; + } + auto mcTruthTPC = data.getTrackMCLabel(contributorsGID[GIndex::Source::TPC]); + if (mcTruthTPC.isValid()) { + source = mcTruthTPC.getSourceID(); + event = mcTruthTPC.getEventID(); + particle = mcTruthTPC.getTrackID(); + mToStore[Triplet_t(source, event, particle)] = 1; + } + } + } + } + } + } + int tableIndex = 1; + for (int mccolid = 0; mccolid < mcColToEvSrc.size(); ++mccolid) { + auto event = mcColToEvSrc[mccolid].first; + auto source = mcColToEvSrc[mccolid].second; + std::vector<MCTrack> const& mcParticles = mcReader.getTracks(source, event); + // mark tracks to be stored per event + // loop over stack of MC particles from end to beginning: daughters are stored after mothers + if (mRecoOnly) { + for (int particle = mcParticles.size() - 1; particle >= 0; particle--) { + int mother0 = mcParticles[particle].getMotherTrackId(); + if (mother0 == -1) { + mToStore[Triplet_t(source, event, particle)] = 1; + } + if (mToStore.find(Triplet_t(source, event, particle)) == mToStore.end()) { + continue; + } + if (mother0 != -1) { + mToStore[Triplet_t(source, event, mother0)] = 1; + } + int mother1 = mcParticles[particle].getSecondMotherTrackId(); + if (mother1 != -1) { + mToStore[Triplet_t(source, particle, mother1)] = 1; + } + int daughter0 = mcParticles[particle].getFirstDaughterTrackId(); + if (daughter0 != -1) { + mToStore[Triplet_t(source, event, daughter0)] = 1; + } + int daughterL = mcParticles[particle].getLastDaughterTrackId(); + if (daughterL != -1) { + mToStore[Triplet_t(source, event, daughterL)] = 1; + } + } + // enumerate reconstructed mc particles and their relatives to get mother/daughter relations + for (int particle = 0; particle < mcParticles.size(); particle++) { + auto mapItem = mToStore.find(Triplet_t(source, event, particle)); + if (mapItem != mToStore.end()) { + mapItem->second = tableIndex - 1; + tableIndex++; + } + } + } + // if all mc particles are stored, all mc particles will be enumerated + if (!mRecoOnly) { + for (int particle = 0; particle < mcParticles.size(); particle++) { + mToStore[Triplet_t(source, event, particle)] = tableIndex - 1; + tableIndex++; + } + } + // fill survived mc tracks into the table + for (int particle = 0; particle < mcParticles.size(); particle++) { + if (mToStore.find(Triplet_t(source, event, particle)) == mToStore.end()) { + continue; + } + int statusCode = 0; + uint8_t flags = 0; + float weight = 0.f; + int mcMother0 = mcParticles[particle].getMotherTrackId(); + auto item = mToStore.find(Triplet_t(source, event, mcMother0)); + int mother0 = -1; + if (item != mToStore.end()) { + mother0 = item->second; + } + int mcMother1 = mcParticles[particle].getSecondMotherTrackId(); + int mother1 = -1; + item = mToStore.find(Triplet_t(source, event, mcMother1)); + if (item != mToStore.end()) { + mother1 = item->second; + } + int mcDaughter0 = mcParticles[particle].getFirstDaughterTrackId(); + int daughter0 = -1; + item = mToStore.find(Triplet_t(source, event, mcDaughter0)); + if (item != mToStore.end()) { + daughter0 = item->second; + } + int mcDaughterL = mcParticles[particle].getLastDaughterTrackId(); + int daughterL = -1; + item = mToStore.find(Triplet_t(source, event, mcDaughterL)); + if (item != mToStore.end()) { + daughterL = item->second; + } + float pX = (float)mcParticles[particle].Px(); + float pY = (float)mcParticles[particle].Py(); + float pZ = (float)mcParticles[particle].Pz(); + float energy = (float)mcParticles[particle].GetEnergy(); + + mcParticlesCursor(0, + mccolid, + mcParticles[particle].GetPdgCode(), + statusCode, + flags, + mother0, + mother1, + daughter0, + daughterL, + truncateFloatFraction(weight, mMcParticleW), + truncateFloatFraction(pX, mMcParticleMom), + truncateFloatFraction(pY, mMcParticleMom), + truncateFloatFraction(pZ, mMcParticleMom), + truncateFloatFraction(energy, mMcParticleMom), + truncateFloatFraction((float)mcParticles[particle].Vx(), mMcParticlePos), + truncateFloatFraction((float)mcParticles[particle].Vy(), mMcParticlePos), + truncateFloatFraction((float)mcParticles[particle].Vz(), mMcParticlePos), + truncateFloatFraction((float)mcParticles[particle].T(), mMcParticlePos)); + } + mcReader.releaseTracksForSourceAndEvent(source, event); + } +} + +template <typename MCTrackLabelCursorType, typename MCMFTTrackLabelCursorType, typename MCFwdTrackLabelCursorType> +void AODProducerWorkflowDPL::fillMCTrackLabelsTable(const MCTrackLabelCursorType& mcTrackLabelCursor, + const MCMFTTrackLabelCursorType& mcMFTTrackLabelCursor, + const MCFwdTrackLabelCursorType& mcFwdTrackLabelCursor, + o2::dataformats::VtxTrackRef const& trackRef, + gsl::span<const GIndex>& primVerGIs, + o2::globaltracking::RecoContainer& data) +{ + // labelMask (temporary) usage: + // bit 13 -- ITS and TPC labels are not equal + // bit 14 -- isNoise() == true + // bit 15 -- isFake() == true + // labelID = -1 -- label is not set + + for (int src = GIndex::NSources; src--;) { + int start = trackRef.getFirstEntryOfSource(src); + int end = start + trackRef.getEntriesOfSource(src); + for (int ti = start; ti < end; ti++) { + auto& trackIndex = primVerGIs[ti]; + if (GIndex::includesSource(src, mInputSources)) { + auto mcTruth = data.getTrackMCLabel(trackIndex); + MCLabels labelHolder; + if ((src == GIndex::Source::MFT) || (src == GIndex::Source::MFTMCH) || (src == GIndex::Source::MCH)) { // treating mft and fwd labels separately + if (mcTruth.isValid()) { // if not set, -1 will be stored + labelHolder.labelID = mToStore.at(Triplet_t(mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID())); + } + if (mcTruth.isFake()) { + labelHolder.fwdLabelMask |= (0x1 << 7); + } + if (mcTruth.isNoise()) { + labelHolder.fwdLabelMask |= (0x1 << 6); + } + if (src == GIndex::Source::MFT) { + mcMFTTrackLabelCursor(0, + labelHolder.labelID, + labelHolder.fwdLabelMask); + + } else { + mcFwdTrackLabelCursor(0, + labelHolder.labelID, + labelHolder.fwdLabelMask); + } + } else { + if (mcTruth.isValid()) { // if not set, -1 will be stored + labelHolder.labelID = mToStore.at(Triplet_t(mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID())); + } + // treating possible mismatches for global tracks + auto contributorsGID = data.getSingleDetectorRefs(trackIndex); + if (contributorsGID[GIndex::Source::ITS].isIndexSet() && contributorsGID[GIndex::Source::TPC].isIndexSet()) { + auto mcTruthITS = data.getTrackMCLabel(contributorsGID[GIndex::Source::ITS]); + if (mcTruthITS.isValid()) { + labelHolder.labelITS = mToStore.at(Triplet_t(mcTruthITS.getSourceID(), mcTruthITS.getEventID(), mcTruthITS.getTrackID())); + } + auto mcTruthTPC = data.getTrackMCLabel(contributorsGID[GIndex::Source::TPC]); + if (mcTruthTPC.isValid()) { + labelHolder.labelTPC = mToStore.at(Triplet_t(mcTruthTPC.getSourceID(), mcTruthTPC.getEventID(), mcTruthTPC.getTrackID())); + labelHolder.labelID = labelHolder.labelTPC; + } + if (labelHolder.labelITS != labelHolder.labelTPC) { + LOG(DEBUG) << "ITS-TPC MCTruth: labelIDs do not match at " << trackIndex.getIndex() << ", src = " << src; + labelHolder.labelMask |= (0x1 << 13); + } + } + if (mcTruth.isFake()) { + labelHolder.labelMask |= (0x1 << 15); + } + if (mcTruth.isNoise()) { + labelHolder.labelMask |= (0x1 << 14); + } + mcTrackLabelCursor(0, + labelHolder.labelID, + labelHolder.labelMask); + } + } + } + } +} + +void AODProducerWorkflowDPL::countTPCClusters(const o2::tpc::TrackTPC& track, + const gsl::span<const o2::tpc::TPCClRefElem>& tpcClusRefs, + const gsl::span<const unsigned char>& tpcClusShMap, + const o2::tpc::ClusterNativeAccess& tpcClusAcc, + uint8_t& shared, uint8_t& found, uint8_t& crossed) +{ + constexpr int maxRows = 152; + constexpr int neighbour = 2; + std::array<bool, maxRows> clMap{}, shMap{}; + uint8_t sectorIndex; + uint8_t rowIndex; + uint32_t clusterIndex; + shared = 0; + for (int i = 0; i < track.getNClusterReferences(); i++) { + o2::tpc::TrackTPC::getClusterReference(tpcClusRefs, i, sectorIndex, rowIndex, clusterIndex, track.getClusterRef()); + unsigned int absoluteIndex = tpcClusAcc.clusterOffset[sectorIndex][rowIndex] + clusterIndex; + clMap[rowIndex] = true; + if (tpcClusShMap[absoluteIndex] > 1) { + if (!shMap[rowIndex]) { + shared++; + } + shMap[rowIndex] = true; + } + } + + crossed = 0; + found = 0; + int last = -1; + for (int i = 0; i < maxRows; i++) { + if (clMap[i]) { + crossed++; + found++; + last = i; + } else if ((i - last) <= neighbour) { + crossed++; + } else { + int lim = std::min(i + 1 + neighbour, maxRows); + for (int j = i + 1; j < lim; j++) { + if (clMap[j]) { + crossed++; + } + } + } + } +} + +uint8_t AODProducerWorkflowDPL::getTRDPattern(const o2::trd::TrackTRD& track) { - for (int i = 0; i < tracks.size(); i++) { - auto& track = tracks[i]; - int collisionID = vCollRefs[i]; - - float tpcInnerParam = 0.f; - uint32_t flags = 0; - uint8_t itsClusterMap = 0; - uint8_t tpcNClsFindable = 0; - int8_t tpcNClsFindableMinusFound = 0; - int8_t tpcNClsFindableMinusCrossedRows = 0; - uint8_t tpcNClsShared = 0; - uint8_t trdPattern = 0; - float itsChi2NCl = -999.f; - float tpcChi2NCl = -999.f; - float trdChi2 = -999.f; - float tofChi2 = -999.f; - float tpcSignal = -999.f; - float trdSignal = -999.f; - float tofSignal = -999.f; - float length = -999.f; - float tofExpMom = -999.f; - float trackEtaEMCAL = -999.f; - float trackPhiEMCAL = -999.f; - - // filling available columns for different track types - // FIXME: - // is there a more nice/simple way to do this? - std::variant<o2::its::TrackITS, o2::tpc::TrackTPC, o2::dataformats::TrackTPCITS> tmp = track; - std::visit( - overloaded{ - [&](o2::its::TrackITS itsTrack) { - itsClusterMap = itsTrack.getPattern(); - }, - [&](o2::tpc::TrackTPC tpcTrack) { - tpcChi2NCl = tpcTrack.getChi2(); - // FIXME: - // what values to fill here? - tpcSignal = tpcTrack.getdEdx().dEdxTotTPC; - tpcNClsFindable = tpcTrack.getNClusters(); - }, - [&](o2::dataformats::TrackTPCITS itsTpcTrack) { - LOG(DEBUG) << "TrackTPCITS: check"; - }}, - tmp); - - // TODO: - // fill trackextra table - tracksCursor(0, - collisionID, - trackType, - track.getX(), - track.getAlpha(), - track.getY(), - track.getZ(), - track.getSnp(), - track.getTgl(), - track.getQ2Pt(), - TMath::Sqrt(track.getSigmaY2()), - TMath::Sqrt(track.getSigmaZ2()), - TMath::Sqrt(track.getSigmaSnp2()), - TMath::Sqrt(track.getSigmaTgl2()), - TMath::Sqrt(track.getSigma1Pt2()), - (Char_t)(128. * track.getSigmaZY() / track.getSigmaZ2() / track.getSigmaY2()), - (Char_t)(128. * track.getSigmaSnpY() / track.getSigmaSnp2() / track.getSigmaY2()), - (Char_t)(128. * track.getSigmaSnpZ() / track.getSigmaSnp2() / track.getSigmaZ2()), - (Char_t)(128. * track.getSigmaTglY() / track.getSigmaTgl2() / track.getSigmaY2()), - (Char_t)(128. * track.getSigmaTglZ() / track.getSigmaTgl2() / track.getSigmaZ2()), - (Char_t)(128. * track.getSigmaTglSnp() / track.getSigmaTgl2() / track.getSigmaSnp2()), - (Char_t)(128. * track.getSigma1PtY() / track.getSigma1Pt2() / track.getSigmaY2()), - (Char_t)(128. * track.getSigma1PtZ() / track.getSigma1Pt2() / track.getSigmaZ2()), - (Char_t)(128. * track.getSigma1PtSnp() / track.getSigma1Pt2() / track.getSigmaSnp2()), - (Char_t)(128. * track.getSigma1PtTgl() / track.getSigma1Pt2() / track.getSigmaTgl2()), - tpcInnerParam, - flags, - itsClusterMap, - tpcNClsFindable, - tpcNClsFindableMinusFound, - tpcNClsFindableMinusCrossedRows, - tpcNClsShared, - trdPattern, - itsChi2NCl, - tpcChi2NCl, - trdChi2, - tofChi2, - tpcSignal, - trdSignal, - tofSignal, - length, - tofExpMom, - trackEtaEMCAL, - trackPhiEMCAL); + uint8_t pattern = 0; + for (int il = o2::trd::TrackTRD::EGPUTRDTrack::kNLayers; il >= 0; il--) { + if (track.getTrackletIndex(il) != -1) { + pattern |= 0x1 << il; + } } + return pattern; } void AODProducerWorkflowDPL::init(InitContext& ic) { mTimer.Stop(); + mTFNumber = ic.options().get<int64_t>("aod-timeframe-id"); + mRecoOnly = ic.options().get<int>("reco-mctracks-only"); + mTruncate = ic.options().get<int>("enable-truncation"); - mFillTracksITS = ic.options().get<int>("fill-tracks-its"); - mFillTracksTPC = ic.options().get<int>("fill-tracks-tpc"); - mFillTracksITSTPC = ic.options().get<int>("fill-tracks-its-tpc"); - LOG(INFO) << "track filling flags set to: " - << "\n ITS = " << mFillTracksITS << "\n TPC = " << mFillTracksTPC << "\n ITSTPC = " << mFillTracksITSTPC; + if (mTFNumber == -1L) { + LOG(INFO) << "TFNumber will be obtained from CCDB"; + } + + if (mTruncate != 1) { + LOG(INFO) << "Truncation is not used!"; + mCollisionPosition = 0xFFFFFFFF; + mCollisionPositionCov = 0xFFFFFFFF; + mTrackX = 0xFFFFFFFF; + mTrackAlpha = 0xFFFFFFFF; + mTrackSnp = 0xFFFFFFFF; + mTrackTgl = 0xFFFFFFFF; + mTrack1Pt = 0xFFFFFFFF; + mTrackCovDiag = 0xFFFFFFFF; + mTrackCovOffDiag = 0xFFFFFFFF; + mTrackSignal = 0xFFFFFFFF; + mTrackPosEMCAL = 0xFFFFFFFF; + mTracklets = 0xFFFFFFFF; + mMcParticleW = 0xFFFFFFFF; + mMcParticlePos = 0xFFFFFFFF; + mMcParticleMom = 0xFFFFFFFF; + mCaloAmp = 0xFFFFFFFF; + mCaloTime = 0xFFFFFFFF; + mMuonTr1P = 0xFFFFFFFF; + mMuonTrThetaX = 0xFFFFFFFF; + mMuonTrThetaY = 0xFFFFFFFF; + mMuonTrZmu = 0xFFFFFFFF; + mMuonTrBend = 0xFFFFFFFF; + mMuonTrNonBend = 0xFFFFFFFF; + mMuonTrCov = 0xFFFFFFFF; + mMuonCl = 0xFFFFFFFF; + mMuonClErr = 0xFFFFFFFF; + mV0Time = 0xFFFFFFFF; + mFDDTime = 0xFFFFFFFF; + mT0Time = 0xFFFFFFFF; + mV0Amplitude = 0xFFFFFFFF; + mFDDAmplitude = 0xFFFFFFFF; + mT0Amplitude = 0xFFFFFFFF; + } + // Needed by MCH track extrapolation + o2::base::GeometryManager::loadGeometry(); mTimer.Reset(); } @@ -233,40 +896,71 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) { mTimer.Start(false); - auto ft0ChData = pc.inputs().get<gsl::span<o2::ft0::ChannelDataFloat>>("ft0ChData"); - auto ft0RecPoints = pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("ft0RecPoints"); - auto primVer2TRefs = pc.inputs().get<gsl::span<o2::vertexing::V2TRef>>("primVer2TRefs"); - auto primVerGIs = pc.inputs().get<gsl::span<o2::vertexing::GIndex>>("primVerGIs"); - auto primVertices = pc.inputs().get<gsl::span<o2::vertexing::PVertex>>("primVertices"); - auto tracksITS = pc.inputs().get<gsl::span<o2::its::TrackITS>>("trackITS"); - auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("tracksITSTPC"); - auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("trackTPC"); + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest); + + auto primVertices = recoData.getPrimaryVertices(); + auto primVer2TRefs = recoData.getPrimaryVertexMatchedTrackRefs(); + auto primVerGIs = recoData.getPrimaryVertexMatchedTracks(); + auto primVerLabels = recoData.getPrimaryVertexMCLabels(); + + auto secVertices = recoData.getV0s(); + auto cascades = recoData.getCascades(); + + auto fddChData = recoData.getFDDChannelsData(); + auto fddRecPoints = recoData.getFDDRecPoints(); + auto ft0ChData = recoData.getFT0ChannelsData(); + auto ft0RecPoints = recoData.getFT0RecPoints(); + auto fv0ChData = recoData.getFV0ChannelsData(); + auto fv0RecPoints = recoData.getFV0RecPoints(); - LOG(INFO) << "FOUND " << tracksTPC.size() << " TPC tracks"; - LOG(INFO) << "FOUND " << tracksITS.size() << " ITS tracks"; - LOG(INFO) << "FOUND " << tracksITSTPC.size() << " ITCTPC tracks"; + LOG(DEBUG) << "FOUND " << primVertices.size() << " primary vertices"; + LOG(DEBUG) << "FOUND " << ft0RecPoints.size() << " FT0 rec. points"; + LOG(DEBUG) << "FOUND " << fv0RecPoints.size() << " FV0 rec. points"; + LOG(DEBUG) << "FOUND " << fddRecPoints.size() << " FDD rec. points"; auto& bcBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "BC"}); + auto& cascadesBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "CASCADE"}); auto& collisionsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "COLLISION"}); + auto& fddBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FDD"}); auto& ft0Builder = pc.outputs().make<TableBuilder>(Output{"AOD", "FT0"}); - auto& mcCollisionsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCCOLLISION"}); - auto& tracksBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "TRACK"}); - auto& timeFrameNumberBuilder = pc.outputs().make<uint64_t>(Output{"TFN", "TFNumber"}); - auto& fv0aBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FV0A"}); auto& fv0cBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FV0C"}); - auto& fddBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FDD"}); + auto& fwdTracksBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FWDTRACK"}); + auto& fwdTracksCovBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "FWDTRACKCOV"}); + auto& mcColLabelsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCCOLLISIONLABEL"}); + auto& mcCollisionsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCCOLLISION"}); + auto& mcMFTTrackLabelBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCMFTTRACKLABEL"}); + auto& mcFwdTrackLabelBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCFWDTRACKLABEL"}); + auto& mcParticlesBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCPARTICLE"}); + auto& mcTrackLabelBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MCTRACKLABEL"}); + auto& mftTracksBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "MFTTRACK"}); + auto& tracksBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "TRACK"}); + auto& tracksCovBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "TRACKCOV"}); + auto& tracksExtraBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "TRACKEXTRA"}); + auto& v0sBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "V0S"}); auto& zdcBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "ZDC"}); auto bcCursor = bcBuilder.cursor<o2::aod::BCs>(); + auto cascadesCursor = cascadesBuilder.cursor<o2::aod::StoredCascades>(); auto collisionsCursor = collisionsBuilder.cursor<o2::aod::Collisions>(); + auto fddCursor = fddBuilder.cursor<o2::aod::FDDs>(); auto ft0Cursor = ft0Builder.cursor<o2::aod::FT0s>(); - auto mcCollisionsCursor = mcCollisionsBuilder.cursor<o2::aod::McCollisions>(); - auto tracksCursor = tracksBuilder.cursor<o2::aodproducer::TracksTable>(); - auto fv0aCursor = fv0aBuilder.cursor<o2::aod::FV0As>(); auto fv0cCursor = fv0cBuilder.cursor<o2::aod::FV0Cs>(); - auto fddCursor = fddBuilder.cursor<o2::aod::FDDs>(); + auto fwdTracksCursor = fwdTracksBuilder.cursor<o2::aodproducer::FwdTracksTable>(); + auto fwdTracksCovCursor = fwdTracksCovBuilder.cursor<o2::aodproducer::FwdTracksCovTable>(); + auto mcColLabelsCursor = mcColLabelsBuilder.cursor<o2::aod::McCollisionLabels>(); + auto mcCollisionsCursor = mcCollisionsBuilder.cursor<o2::aod::McCollisions>(); + auto mcMFTTrackLabelCursor = mcMFTTrackLabelBuilder.cursor<o2::aod::McMFTTrackLabels>(); + auto mcFwdTrackLabelCursor = mcFwdTrackLabelBuilder.cursor<o2::aod::McFwdTrackLabels>(); + auto mcParticlesCursor = mcParticlesBuilder.cursor<o2::aodproducer::MCParticlesTable>(); + auto mcTrackLabelCursor = mcTrackLabelBuilder.cursor<o2::aod::McTrackLabels>(); + auto mftTracksCursor = mftTracksBuilder.cursor<o2::aodproducer::MFTTracksTable>(); + auto tracksCovCursor = tracksCovBuilder.cursor<o2::aodproducer::TracksCovTable>(); + auto tracksCursor = tracksBuilder.cursor<o2::aodproducer::TracksTable>(); + auto tracksExtraCursor = tracksExtraBuilder.cursor<o2::aodproducer::TracksExtraTable>(); + auto v0sCursor = v0sBuilder.cursor<o2::aod::StoredV0s>(); auto zdcCursor = zdcBuilder.cursor<o2::aod::Zdcs>(); o2::steer::MCKinematicsReader mcReader("collisioncontext.root"); @@ -274,202 +968,335 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) const auto& mcRecords = mcContext->getEventRecords(); const auto& mcParts = mcContext->getEventParts(); - LOG(INFO) << "FOUND " << mcRecords.size() << " records"; - LOG(INFO) << "FOUND " << mcParts.size() << " parts"; - - findMinMaxBc(ft0RecPoints, tracksITSTPC, mcRecords); + LOG(DEBUG) << "FOUND " << mcRecords.size() << " records"; + LOG(DEBUG) << "FOUND " << mcParts.size() << " parts"; - std::map<uint64_t, uint64_t> mGlobBC2BCID; + std::map<uint64_t, int> bcsMap; + collectBCs(fddRecPoints, ft0RecPoints, fv0RecPoints, primVertices, mcRecords, bcsMap); - // TODO: - // get real run number and triggerMask - int runNumber = 244918; - uint64_t triggerMask = 1; + const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().getFirstValid(true).header); + o2::InteractionRecord startIR = {0, dh->firstTForbit}; - // filling BC table and map<globalBC, BCId> - for (uint64_t i = 0; i <= maxGlBC - minGlBC; i++) { - bcCursor(0, - runNumber, - minGlBC + i, - triggerMask); - mGlobBC2BCID[minGlBC + i] = i; + uint64_t tfNumber; + // default dummy run number + int runNumber = 244918; // TODO: get real run number + if (mTFNumber == -1L) { + tfNumber = getTFNumber(startIR, runNumber); + } else { + tfNumber = mTFNumber; } - // TODO: - // add real FV0A, FV0C, FDD, ZDC tables instead of dummies - float dummyfv0AmplA[48] = {0.}; - fv0aCursor(0, - (uint64_t)0, - dummyfv0AmplA, - 0.f, - (uint8_t)0); + uint64_t dummyBC = 0; + float dummyTime = 0.f; + uint8_t dummyTriggerMask = 0; - float dummyfv0AmplC[32] = {0.}; + int nFV0ChannelsAside = o2::fv0::Geometry::getNumberOfReadoutChannels(); + std::vector<float> vFV0Amplitudes(nFV0ChannelsAside, 0.); + for (auto& fv0RecPoint : fv0RecPoints) { + const auto channelData = fv0RecPoint.getBunchChannelData(fv0ChData); + for (auto& channel : channelData) { + vFV0Amplitudes[channel.channel] = channel.charge; // amplitude, mV + } + float aAmplitudesA[nFV0ChannelsAside]; + for (int i = 0; i < nFV0ChannelsAside; i++) { + aAmplitudesA[i] = truncateFloatFraction(vFV0Amplitudes[i], mV0Amplitude); + } + uint64_t bc = fv0RecPoint.getInteractionRecord().toLong(); + auto item = bcsMap.find(bc); + int bcID = -1; + if (item != bcsMap.end()) { + bcID = item->second; + } else { + LOG(FATAL) << "Error: could not find a corresponding BC ID for a FV0 rec. point; BC = " << bc; + } + fv0aCursor(0, + bcID, + aAmplitudesA, + truncateFloatFraction(fv0RecPoint.getCollisionGlobalMeanTime() * 1E-3, mV0Time), // ps to ns + fv0RecPoint.getTrigger().triggerSignals); + } + + float dummyFV0AmplC[32] = {0.}; fv0cCursor(0, - (uint64_t)0, - dummyfv0AmplC, - 0.f); - - float dummyfddAmplA[4] = {0.}; - float dummyfddAmplC[4] = {0.}; - fddCursor(0, - (uint64_t)0, - dummyfddAmplA, - dummyfddAmplC, - 0.f, - 0.f, - (uint8_t)0); + dummyBC, + dummyFV0AmplC, + dummyTime); + float dummyEnergyZEM1 = 0; + float dummyEnergyZEM2 = 0; + float dummyEnergyCommonZNA = 0; + float dummyEnergyCommonZNC = 0; + float dummyEnergyCommonZPA = 0; + float dummyEnergyCommonZPC = 0; float dummyEnergySectorZNA[4] = {0.}; float dummyEnergySectorZNC[4] = {0.}; float dummyEnergySectorZPA[4] = {0.}; float dummyEnergySectorZPC[4] = {0.}; zdcCursor(0, - (uint64_t)0, - 0.f, - 0.f, - 0.f, - 0.f, - 0.f, - 0.f, + dummyBC, + dummyEnergyZEM1, + dummyEnergyZEM2, + dummyEnergyCommonZNA, + dummyEnergyCommonZNC, + dummyEnergyCommonZPA, + dummyEnergyCommonZPC, dummyEnergySectorZNA, dummyEnergySectorZNC, dummyEnergySectorZPA, dummyEnergySectorZPC, - 0.f, - 0.f, - 0.f, - 0.f, - 0.f, - 0.f); - - // TODO: - // figure out generatorID and collision weight - int index = 0; - int generatorID = 0; - float mcColWeight = 1.; + dummyTime, + dummyTime, + dummyTime, + dummyTime, + dummyTime, + dummyTime); - // filling mcCollison table + // TODO: figure out collision weight + // keep track event/source id for each mc-collision + std::vector<std::pair<int, int>> mcColToEvSrc; + + float mcColWeight = 1.; + // filling mcCollision table + int index = 0; for (auto& rec : mcRecords) { auto time = rec.getTimeNS(); + uint64_t globalBC = rec.toLong(); + auto item = bcsMap.find(globalBC); + int bcID = -1; + if (item != bcsMap.end()) { + bcID = item->second; + } else { + LOG(FATAL) << "Error: could not find a corresponding BC ID for MC collision; BC = " << globalBC << ", index = " << index; + } auto& colParts = mcParts[index]; - auto eventID = colParts[0].entryID; - auto sourceID = colParts[0].sourceID; - auto& header = mcReader.getMCEventHeader(sourceID, eventID); - uint64_t globalBC = rec.bc + rec.orbit * o2::constants::lhc::LHCMaxBunches; - mcCollisionsCursor(0, - mGlobBC2BCID.at(globalBC), - generatorID, - header.GetX(), - header.GetY(), - header.GetZ(), - time, - mcColWeight, - header.GetB()); + for (auto colPart : colParts) { + auto eventID = colPart.entryID; + auto sourceID = colPart.sourceID; + // FIXME: + // use generators' names for generatorIDs (?) + short generatorID = sourceID; + auto& header = mcReader.getMCEventHeader(sourceID, eventID); + mcCollisionsCursor(0, + bcID, + generatorID, + truncateFloatFraction(header.GetX(), mCollisionPosition), + truncateFloatFraction(header.GetY(), mCollisionPosition), + truncateFloatFraction(header.GetZ(), mCollisionPosition), + truncateFloatFraction(time, mCollisionPosition), + truncateFloatFraction(mcColWeight, mCollisionPosition), + header.GetB()); + mcColToEvSrc.emplace_back(std::pair<int, int>(eventID, sourceID)); + } index++; } + // vector of FDD amplitudes + int nFDDChannels = o2::fdd::Nchannels; + std::vector<float> vFDDAmplitudes(nFDDChannels, 0.); + // filling FDD table + for (const auto& fddRecPoint : fddRecPoints) { + const auto channelData = fddRecPoint.getBunchChannelData(fddChData); + // TODO: switch to calibrated amplitude + for (const auto& channel : channelData) { + vFDDAmplitudes[channel.mPMNumber] = channel.mChargeADC; // amplitude, mV + } + float aFDDAmplitudesA[int(nFDDChannels * 0.5)]; + float aFDDAmplitudesC[int(nFDDChannels * 0.5)]; + for (int i = 0; i < nFDDChannels; i++) { + if (i < nFDDChannels * 0.5) { + aFDDAmplitudesC[i] = truncateFloatFraction(vFDDAmplitudes[i], mFDDAmplitude); + } else { + aFDDAmplitudesA[i - int(nFDDChannels * 0.5)] = truncateFloatFraction(vFDDAmplitudes[i], mFDDAmplitude); + } + } + uint64_t globalBC = fddRecPoint.getInteractionRecord().toLong(); + uint64_t bc = globalBC; + auto item = bcsMap.find(bc); + int bcID = -1; + if (item != bcsMap.end()) { + bcID = item->second; + } else { + LOG(FATAL) << "Error: could not find a corresponding BC ID for a FDD rec. point; BC = " << bc; + } + fddCursor(0, + bcID, + aFDDAmplitudesA, + aFDDAmplitudesC, + truncateFloatFraction(fddRecPoint.getCollisionTimeA() * 1E-3, mFDDTime), // ps to ns + truncateFloatFraction(fddRecPoint.getCollisionTimeC() * 1E-3, mFDDTime), // ps to ns + fddRecPoint.getTrigger().triggersignals); + } + // vector of FT0 amplitudes - std::vector<float> vAmplitudes(208, 0.); + int nFT0Channels = o2::ft0::Geometry::Nsensors; + int nFT0ChannelsAside = o2::ft0::Geometry::NCellsA * 4; + std::vector<float> vAmplitudes(nFT0Channels, 0.); // filling FT0 table for (auto& ft0RecPoint : ft0RecPoints) { const auto channelData = ft0RecPoint.getBunchChannelData(ft0ChData); - // TODO: - // switch to calibrated amplitude + // TODO: switch to calibrated amplitude for (auto& channel : channelData) { vAmplitudes[channel.ChId] = channel.QTCAmpl; // amplitude, mV } - float aAmplitudesA[96]; - float aAmplitudesC[112]; - std::copy(vAmplitudes.begin(), vAmplitudes.begin() + 95, aAmplitudesA); - std::copy(vAmplitudes.begin() + 96, vAmplitudes.end(), aAmplitudesC); - uint64_t globalBC = ft0RecPoint.getInteractionRecord().orbit * o2::constants::lhc::LHCMaxBunches + ft0RecPoint.getInteractionRecord().bc; + float aAmplitudesA[nFT0ChannelsAside]; + float aAmplitudesC[nFT0Channels - nFT0ChannelsAside]; + for (int i = 0; i < nFT0Channels; i++) { + if (i < nFT0ChannelsAside) { + aAmplitudesA[i] = truncateFloatFraction(vAmplitudes[i], mT0Amplitude); + } else { + aAmplitudesC[i - nFT0ChannelsAside] = truncateFloatFraction(vAmplitudes[i], mT0Amplitude); + } + } + uint64_t globalBC = ft0RecPoint.getInteractionRecord().toLong(); + uint64_t bc = globalBC; + auto item = bcsMap.find(bc); + int bcID = -1; + if (item != bcsMap.end()) { + bcID = item->second; + } else { + LOG(FATAL) << "Error: could not find a corresponding BC ID for a FT0 rec. point; BC = " << bc; + } ft0Cursor(0, - mGlobBC2BCID.at(globalBC), + bcID, aAmplitudesA, aAmplitudesC, - ft0RecPoint.getCollisionTimeA() / 1E3, // ps to ns - ft0RecPoint.getCollisionTimeC() / 1E3, // ps to ns + truncateFloatFraction(ft0RecPoint.getCollisionTimeA() * 1E-3, mT0Time), // ps to ns + truncateFloatFraction(ft0RecPoint.getCollisionTimeC() * 1E-3, mT0Time), // ps to ns ft0RecPoint.getTrigger().triggersignals); } - // initializing vectors for trackID --> collisionID connection - std::vector<int> vCollRefsITS(tracksITS.size(), -1); - std::vector<int> vCollRefsTPC(tracksTPC.size(), -1); - std::vector<int> vCollRefsTPCITS(tracksITSTPC.size(), -1); + // filling MC collision labels + for (auto& label : primVerLabels) { + auto it = std::find_if(mcColToEvSrc.begin(), mcColToEvSrc.end(), + [&label](const std::pair<int, int>& item) { return (item.first == label.getEventID() && item.second == label.getSourceID()); }); + int32_t mcCollisionID = it - mcColToEvSrc.begin(); + uint16_t mcMask = 0; // todo: set mask using normalized weights? + mcColLabelsCursor(0, mcCollisionID, mcMask); + } + + // hash map for track indices of secondary vertices + std::unordered_map<int, int> v0sIndices; - // global bc of the 1st vertex for TF number - uint64_t firstVtxGlBC; + // filling unassigned tracks first + // so that all unassigned tracks are stored in the beginning of the table together + auto& trackRef = primVer2TRefs.back(); // references to unassigned tracks are at the end + // fixme: interaction time is undefined for unassigned tracks (?) + fillTrackTablesPerCollision(-1, -1, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, mftTracksCursor, fwdTracksCursor, fwdTracksCovCursor, dataformats::PrimaryVertex{}); - // filling collisions table + // filling collisions and tracks into tables int collisionID = 0; for (auto& vertex : primVertices) { auto& cov = vertex.getCov(); - auto& timeStamp = vertex.getTimeStamp(); - Double_t tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns - // FIXME: - // should use IRMin and IRMax for globalBC calculation - uint64_t globalBC = tsTimeStamp / o2::constants::lhc::LHCBunchSpacingNS; - - if (collisionID == 0) { - firstVtxGlBC = globalBC; + auto& timeStamp = vertex.getTimeStamp(); // this is a relative time + const double interactionTime = timeStamp.getTimeStamp() * 1E3; // mus to ns + uint64_t globalBC = relativeTime_to_GlobalBC(interactionTime); + uint64_t localBC = relativeTime_to_LocalBC(interactionTime); + LOG(DEBUG) << "global BC " << globalBC << " local BC " << localBC << " relative interaction time " << interactionTime; + // collision timestamp in ns wrt the beginning of collision BC + const float relInteractionTime = static_cast<float>(localBC * o2::constants::lhc::LHCBunchSpacingNS - interactionTime); + auto item = bcsMap.find(globalBC); + int bcID = -1; + if (item != bcsMap.end()) { + bcID = item->second; + } else { + LOG(FATAL) << "Error: could not find a corresponding BC ID for a collision; BC = " << globalBC << ", collisionID = " << collisionID; } - int BCid = mGlobBC2BCID.at(globalBC); - // TODO: - // get real collision time mask - int collisionTimeMask = 0; collisionsCursor(0, - BCid, - vertex.getX(), - vertex.getY(), - vertex.getZ(), - cov[0], - cov[1], - cov[2], - cov[3], - cov[4], - cov[5], - vertex.getChi2(), + bcID, + truncateFloatFraction(vertex.getX(), mCollisionPosition), + truncateFloatFraction(vertex.getY(), mCollisionPosition), + truncateFloatFraction(vertex.getZ(), mCollisionPosition), + truncateFloatFraction(cov[0], mCollisionPositionCov), + truncateFloatFraction(cov[1], mCollisionPositionCov), + truncateFloatFraction(cov[2], mCollisionPositionCov), + truncateFloatFraction(cov[3], mCollisionPositionCov), + truncateFloatFraction(cov[4], mCollisionPositionCov), + truncateFloatFraction(cov[5], mCollisionPositionCov), + vertex.getFlags(), + truncateFloatFraction(vertex.getChi2(), mCollisionPositionCov), vertex.getNContributors(), - timeStamp.getTimeStamp(), - timeStamp.getTimeStampError(), - collisionTimeMask); - auto trackRef = primVer2TRefs[collisionID]; - int start = trackRef.getFirstEntryOfSource(0); - int ntracks = trackRef.getEntriesOfSource(0); - - // FIXME: - // `track<-->vertex` ambiguity is not accounted for in this code - for (int ti = 0; ti < ntracks; ti++) { - auto trackIndex = primVerGIs[start + ti]; - const auto source = trackIndex.getSource(); - // setting collisionID for tracks attached to vertices - if (source == o2::vertexing::GIndex::Source::TPC) { - vCollRefsTPC[trackIndex.getIndex()] = collisionID; - } else if (source == o2::vertexing::GIndex::Source::ITS) { - vCollRefsITS[trackIndex.getIndex()] = collisionID; - } else if (source == o2::vertexing::GIndex::Source::TPCITS) { - vCollRefsTPCITS[trackIndex.getIndex()] = collisionID; - } else { - LOG(WARNING) << "Unsupported track type!"; - } - } + truncateFloatFraction(relInteractionTime, mCollisionPosition), + truncateFloatFraction(timeStamp.getTimeStampError() * 1E3, mCollisionPositionCov)); + auto& trackRef = primVer2TRefs[collisionID]; + // passing interaction time in [ps] + fillTrackTablesPerCollision(collisionID, interactionTime * 1E3, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, mftTracksCursor, fwdTracksCursor, fwdTracksCovCursor, vertex); collisionID++; } - // filling tracks tables - if (mFillTracksITS) { - fillTracksTable(tracksITS, vCollRefsITS, tracksCursor, o2::vertexing::GIndex::Source::ITS); // fTrackType = 1 + // filling v0s table + for (auto& svertex : secVertices) { + auto trPosID = svertex.getProngID(0); + auto trNegID = svertex.getProngID(1); + int posTableIdx = -1; + int negTableIdx = -1; + auto item = mGIDToTableID.find(trPosID); + if (item != mGIDToTableID.end()) { + posTableIdx = item->second; + } else { + LOG(WARN) << "Could not find a positive track index for prong ID " << trPosID; + } + item = mGIDToTableID.find(trNegID); + if (item != mGIDToTableID.end()) { + negTableIdx = item->second; + } else { + LOG(WARN) << "Could not find a negative track index for prong ID " << trNegID; + } + if (posTableIdx != -1 and negTableIdx != -1) { + v0sCursor(0, posTableIdx, negTableIdx); + } } - if (mFillTracksTPC) { - fillTracksTable(tracksTPC, vCollRefsTPC, tracksCursor, o2::vertexing::GIndex::Source::TPC); // fTrackType = 2 + + // filling cascades table + for (auto& cascade : cascades) { + auto bachelorID = cascade.getBachelorID(); + int bachTableIdx = -1; + auto item = mGIDToTableID.find(bachelorID); + if (item != mGIDToTableID.end()) { + bachTableIdx = item->second; + } else { + LOG(WARN) << "Could not find a bachelor track index"; + } + cascadesCursor(0, cascade.getV0ID(), bachTableIdx); } - if (mFillTracksITSTPC) { - fillTracksTable(tracksITSTPC, vCollRefsTPCITS, tracksCursor, o2::vertexing::GIndex::Source::TPCITS); // fTrackType = 0 + + mTableTrID = 0; + mGIDToTableID.clear(); + + // filling BC table + // TODO: get real triggerMask + uint64_t triggerMask = 1; + for (auto& item : bcsMap) { + uint64_t bc = item.first; + bcCursor(0, + runNumber, + bc, + triggerMask); } - timeFrameNumberBuilder = getTFNumber(firstVtxGlBC, runNumber); + bcsMap.clear(); + + // filling mc particles table + fillMCParticlesTable(mcReader, + mcParticlesCursor, + primVer2TRefs, + primVerGIs, + recoData, + mcColToEvSrc); + + // ------------------------------------------------------ + // filling track labels + + // need to go through labels in the same order as for tracks + fillMCTrackLabelsTable(mcTrackLabelCursor, mcMFTTrackLabelCursor, mcFwdTrackLabelCursor, primVer2TRefs.back(), primVerGIs, recoData); + for (int iref = 0; iref < primVer2TRefs.size() - 1; iref++) { + auto& trackRef = primVer2TRefs[iref]; + fillMCTrackLabelsTable(mcTrackLabelCursor, mcMFTTrackLabelCursor, mcFwdTrackLabelCursor, trackRef, primVerGIs, recoData); + } + + mToStore.clear(); + + pc.outputs().snapshot(Output{"TFN", "TFNumber", 0, Lifetime::Timeframe}, tfNumber); mTimer.Stop(); } @@ -480,43 +1307,51 @@ void AODProducerWorkflowDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getAODProducerWorkflowSpec() +DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool useMC) { - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); - inputs.emplace_back("ft0ChData", "FT0", "RECCHDATA", 0, Lifetime::Timeframe); - inputs.emplace_back("ft0RecPoints", "FT0", "RECPOINTS", 0, Lifetime::Timeframe); - inputs.emplace_back("primVer2TRefs", "GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); - inputs.emplace_back("primVerGIs", "GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); - inputs.emplace_back("primVertices", "GLO", "PVTX", 0, Lifetime::Timeframe); - inputs.emplace_back("trackITS", "ITS", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("tracksITSTPC", "GLO", "TPCITS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPC", "TPC", "TRACKS", 0, Lifetime::Timeframe); + dataRequest->requestTracks(src, useMC); + dataRequest->requestPrimaryVertertices(useMC); + dataRequest->requestSecondaryVertertices(useMC); + dataRequest->requestFT0RecPoints(false); + dataRequest->requestFV0RecPoints(false); + dataRequest->requestFDDRecPoints(false); + dataRequest->requestClusters(GIndex::getSourcesMask("TPC,TOF"), false); outputs.emplace_back(OutputLabel{"O2bc"}, "AOD", "BC", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2cascade"}, "AOD", "CASCADE", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"O2collision"}, "AOD", "COLLISION", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2fdd"}, "AOD", "FDD", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"O2ft0"}, "AOD", "FT0", 0, Lifetime::Timeframe); - outputs.emplace_back(OutputLabel{"O2mccollision"}, "AOD", "MCCOLLISION", 0, Lifetime::Timeframe); - outputs.emplace_back(OutputLabel{"O2track"}, "AOD", "TRACK", 0, Lifetime::Timeframe); - outputs.emplace_back(OutputSpec{"TFN", "TFNumber"}); - - // TODO: - // add FV0A, FV0C, FDD tables outputs.emplace_back(OutputLabel{"O2fv0a"}, "AOD", "FV0A", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"O2fv0c"}, "AOD", "FV0C", 0, Lifetime::Timeframe); - outputs.emplace_back(OutputLabel{"O2fdd"}, "AOD", "FDD", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2fwdtrack"}, "AOD", "FWDTRACK", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2fwdtrackcov"}, "AOD", "FWDTRACKCOV", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mccollision"}, "AOD", "MCCOLLISION", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mccollisionlabel"}, "AOD", "MCCOLLISIONLABEL", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mcmfttracklabel"}, "AOD", "MCMFTTRACKLABEL", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mcfwdtracklabel"}, "AOD", "MCFWDTRACKLABEL", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mcparticle"}, "AOD", "MCPARTICLE", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mctracklabel"}, "AOD", "MCTRACKLABEL", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2mfttrack"}, "AOD", "MFTTRACK", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2track"}, "AOD", "TRACK", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2trackcov"}, "AOD", "TRACKCOV", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2trackextra"}, "AOD", "TRACKEXTRA", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"O2v0"}, "AOD", "V0S", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"O2zdc"}, "AOD", "ZDC", 0, Lifetime::Timeframe); + outputs.emplace_back(OutputSpec{"TFN", "TFNumber"}); return DataProcessorSpec{ "aod-producer-workflow", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<AODProducerWorkflowDPL>()}, + AlgorithmSpec{adaptFromTask<AODProducerWorkflowDPL>(src, dataRequest)}, Options{ - ConfigParamSpec{"fill-tracks-its", VariantType::Int, 1, {"Fill ITS tracks into tracks table"}}, - ConfigParamSpec{"fill-tracks-tpc", VariantType::Int, 1, {"Fill TPC tracks into tracks table"}}, - ConfigParamSpec{"fill-tracks-its-tpc", VariantType::Int, 1, {"Fill ITS-TPC tracks into tracks table"}}}}; + ConfigParamSpec{"aod-timeframe-id", VariantType::Int64, -1L, {"Set timeframe number"}}, + ConfigParamSpec{"enable-truncation", VariantType::Int, 1, {"Truncation parameter: 1 -- on, != 1 -- off"}}, + ConfigParamSpec{"reco-mctracks-only", VariantType::Int, 0, {"Store only reconstructed MC tracks and their mothers/daughters. 0 -- off, != 0 -- on"}}}}; } } // namespace o2::aodproducer diff --git a/Detectors/AOD/src/StandaloneAODProducer.cxx b/Detectors/AOD/src/StandaloneAODProducer.cxx index 7c5aceb68bc36..384364c5aaaa5 100644 --- a/Detectors/AOD/src/StandaloneAODProducer.cxx +++ b/Detectors/AOD/src/StandaloneAODProducer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -107,7 +108,7 @@ void fillCollisionAndTrackTable() auto t = (TTree*)f.Get("o2sim"); // fetch the tracks (these names are not following any convention!!) - auto tpctracks = fetchTracks<o2::tpc::TrackTPC>("tpctracks.root", "events", "Tracks"); + auto tpctracks = fetchTracks<o2::tpc::TrackTPC>("tpctracks.root", "tpcrec", "TPCTracks"); auto itstracks = fetchTracks<o2::its::TrackITS>("o2trac_its.root", "o2sim", "ITSTrack"); auto itstpctracks = fetchTracks<o2::dataformats::TrackTPCITS>("o2match_itstpc.root", "matchTPCITS", "TPCITS"); LOG(INFO) << "FOUND " << tpctracks->size() << " TPC tracks"; @@ -152,7 +153,7 @@ void fillCollisionAndTrackTable() // TODO: figure out BC + CollisionTimeMask collCursor(0, BCid, v.getX(), v.getY(), v.getZ(), cov[0], cov[1], cov[2], cov[3], cov[4], cov[6], - v.getChi2(), v.getNContributors(), ts.getTimeStamp(), ts.getTimeStampError(), 1); + v.getFlags(), v.getChi2(), v.getNContributors(), ts.getTimeStamp(), ts.getTimeStampError()); // get the track for each vertex and fill the tracks table // now go over tracks via the indices @@ -169,7 +170,7 @@ void fillCollisionAndTrackTable() track = &((*tpctracks)[trackindex.getIndex()]); } else if (source == o2::dataformats::VtxTrackIndex::Source::ITS) { track = &((*itstracks)[trackindex.getIndex()]); - } else if (source == o2::dataformats::VtxTrackIndex::Source::TPCITS) { + } else if (source == o2::dataformats::VtxTrackIndex::Source::ITSTPC) { track = &((*itstpctracks)[trackindex.getIndex()]); } else { LOG(WARNING) << "Unsupported track source"; diff --git a/Detectors/AOD/src/aod-producer-workflow.cxx b/Detectors/AOD/src/aod-producer-workflow.cxx index 62226f01db3bf..debd680c78dcd 100644 --- a/Detectors/AOD/src/aod-producer-workflow.cxx +++ b/Detectors/AOD/src/aod-producer-workflow.cxx @@ -1,23 +1,60 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "AODProducerWorkflow/AODProducerWorkflow.h" -#include "CommonUtils/ConfigurableParam.h" +#include "AODProducerWorkflow/AODProducerWorkflowSpec.h" #include "Framework/CompletionPolicy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, + {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} #include "Framework/runDataProcessing.h" WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { - // Update the (declared) parameters if changed from the command line - return std::move(o2::aodproducer::getAODProducerWorkflow()); + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto useMC = !configcontext.options().get<bool>("disable-mc"); + + GID::mask_t allowedSrc = GID::getSourcesMask("ITS,MFT,MCH,TPC,ITS-TPC,ITS-TPC-TOF,TPC-TOF,MFT-MCH,FT0,FV0,FDD,TPC-TRD,ITS-TPC-TRD"); + GID::mask_t src = allowedSrc & GID::getSourcesMask(configcontext.options().get<std::string>("info-sources")); + + WorkflowSpec specs; + specs.emplace_back(o2::aodproducer::getAODProducerWorkflowSpec(src, useMC)); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, useMC, src); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); + o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); } diff --git a/Detectors/Align/CMakeLists.txt b/Detectors/Align/CMakeLists.txt new file mode 100644 index 0000000000000..d19967a90e787 --- /dev/null +++ b/Detectors/Align/CMakeLists.txt @@ -0,0 +1,82 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(Align + SOURCES src/GeometricalConstraint.cxx + src/DOFSet.cxx + src/AlignableDetector.cxx + src/AlignableDetectorITS.cxx + #src/AlignableDetectorHMPID.cxx + #src/AlignableDetectorTOF.cxx + #src/AlignableDetectorTPC.cxx + #src/AlignableDetectorTRD.cxx + src/DOFStatistics.cxx + src/Millepede2Record.cxx + src/AlignmentPoint.cxx + src/ResidualsController.cxx + src/ResidualsControllerFast.cxx + src/AlignableSensor.cxx + #src/AlignableSensorHMPID.cxx + src/AlignableSensorITS.cxx + #src/AlignableSensorTOF.cxx + #src/AlignableSensorTPC.cxx + #src/AlignableSensorTRD.cxx + src/Controller.cxx + src/AlignmentTrack.cxx + src/AlignableVolume.cxx + src/EventVertex.cxx + src/AlignConfig.cxx + src/Mille.cxx + PUBLIC_LINK_LIBRARIES O2::FrameworkLogger + O2::ReconstructionDataFormats + O2::DetectorsCommonDataFormats + O2::DetectorsBase + O2::ITSBase + ROOT::Core + ROOT::Geom + ROOT::Gpad + ROOT::Graf3d + ROOT::MathCore + ROOT::Matrix + ROOT::Hist + ROOT::RIO + ROOT::Tree) + +o2_target_root_dictionary( + Align + HEADERS include/Align/DOFSet.h + include/Align/AlignableDetector.h + include/Align/AlignableDetectorITS.h + #include/Align/AlignableDetectorTOF.h + #include/Align/AlignableDetectorTPC.h + #include/Align/AlignableDetectorTRD.h + #include/Align/AlignableDetectorHMPID.h + include/Align/Millepede2Record.h + include/Align/AlignmentPoint.h + include/Align/AlignableSensor.h + include/Align/AlignableSensorITS.h + #include/Align/AlignableSensorTOF.h + #include/Align/AlignableSensorTPC.h + #include/Align/AlignableSensorTRD.h + #include/Align/AlignableSensorHMPID.h + include/Align/Controller.h + include/Align/AlignmentTrack.h + include/Align/AlignableVolume.h + include/Align/EventVertex.h + include/Align/ResidualsController.h + include/Align/ResidualsControllerFast.h + include/Align/GeometricalConstraint.h + include/Align/DOFStatistics.h + include/Align/utils.h + include/Align/AlignConfig.h + ) + +add_subdirectory(Workflow) diff --git a/Detectors/Align/Readme.md b/Detectors/Align/Readme.md new file mode 100644 index 0000000000000..1b6be2cec166b --- /dev/null +++ b/Detectors/Align/Readme.md @@ -0,0 +1,6 @@ +<!-- doxy +\page refDetectorsAlign Detectors Alignment +/doxy --> + +#Align +This is a top page for the detector alignment documentation. \ No newline at end of file diff --git a/Detectors/Align/Workflow/CMakeLists.txt b/Detectors/Align/Workflow/CMakeLists.txt new file mode 100644 index 0000000000000..c6f2b9916de16 --- /dev/null +++ b/Detectors/Align/Workflow/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +# FIXME: do we actually need a library here, or is the executable enough ? + +o2_add_library(AlignmentWorkflow + SOURCES src/BarrelAlignmentSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Align + O2::FrameworkLogger + O2::DataFormatsGlobalTracking + O2::ReconstructionDataFormats + O2::DetectorsCommonDataFormats + O2::DetectorsBase + O2::DataFormatsITSMFT + O2::DataFormatsITS + O2::DataFormatsTPC + O2::DataFormatsTRD + O2::DataFormatsTOF + ROOT::Core + ROOT::Geom + ROOT::MathCore + ROOT::Matrix + ROOT::Hist + ROOT::RIO + ROOT::Tree) + +o2_add_executable(alignment-workflow + COMPONENT_NAME barrel + SOURCES src/barrel-alignment-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Align + O2::AlignmentWorkflow + O2::GlobalTrackingWorkflow + O2::TOFWorkflowIO + ) diff --git a/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h b/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h new file mode 100644 index 0000000000000..4172af26796ce --- /dev/null +++ b/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file BarrelAlignmentSpec.h + +#ifndef O2_BARREL_ALIGNENT_SPEC +#define O2_BARREL_ALIGNENT_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace align +{ + +/// create a processor spec +framework::DataProcessorSpec getBarrelAlignmentSpec(o2::dataformats::GlobalTrackID::mask_t src, o2::detectors::DetID::mask_t dets); + +} // namespace align +} // namespace o2 + +#endif diff --git a/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx new file mode 100644 index 0000000000000..8692ce7712e84 --- /dev/null +++ b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file BarrelAlignmentSpec.cxx + +#include <vector> +#include <string> +#include "TStopwatch.h" +#include "AlignmentWorkflow/BarrelAlignmentSpec.h" + +#include "Align/Controller.h" + +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsParameters/GRPObject.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" + +#include "Headers/DataHeader.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" + +/* +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsTPC/Constants.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITSMFTBase/DPLAlpideParam.h" +*/ + +using namespace o2::framework; +using namespace o2::globaltracking; +using namespace o2::align; + +using GTrackID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +namespace o2 +{ +namespace align +{ + +class BarrelAlignmentSpec : public Task +{ + public: + BarrelAlignmentSpec(std::shared_ptr<DataRequest> dr, DetID::mask_t m) : mDataRequest(dr), mDetMask{m} {} + ~BarrelAlignmentSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + void updateTimeDependentParams(); + + DetID::mask_t mDetMask{}; + std::unique_ptr<Controller> mController; + std::shared_ptr<DataRequest> mDataRequest; + TStopwatch mTimer; +}; + +void BarrelAlignmentSpec::init(InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); + mController = std::make_unique<Controller>(mDetMask); +} + +void BarrelAlignmentSpec::updateTimeDependentParams() +{ + // +} + +void BarrelAlignmentSpec::run(ProcessingContext& pc) +{ + mTimer.Start(false); + + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + mController->process(recoData); + + mTimer.Stop(); +} + +void BarrelAlignmentSpec::endOfStream(EndOfStreamContext& ec) +{ + //mBarrelAlign.end(); + LOGF(INFO, "Barrel alignment data pereparation total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t src, DetID::mask_t dets) +{ + std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); + + dataRequest->requestTracks(src, false); + dataRequest->requestClusters(src, false); + + return DataProcessorSpec{ + "barrel-alignment", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<BarrelAlignmentSpec>(dataRequest, dets)}, + Options{ + {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx new file mode 100644 index 0000000000000..f07d9eee9ede3 --- /dev/null +++ b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "AlignmentWorkflow/BarrelAlignmentSpec.h" + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "ITSWorkflow/TrackReaderSpec.h" +#include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" + +#include "Algorithm/RangeTokenizer.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using GID = o2::dataformats::GlobalTrackID; +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, + {"detectors", VariantType::String, std::string{"ITS,TPC,TRD,TOF"}, {"comma-separated list of detectors"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// the matcher process requires the TPC sector completion to trigger and data on all defined routes +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + // the TPC sector completion policy checks when the set of TPC/CLUSTERNATIVE data is complete + // in addition we require to have input from all other routes + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("barrel-alignment", + o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, + InputSpec{"cluster", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}})()); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + GID::mask_t alowedSources = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF,ITS-TPC-TOF"); + DetID::mask_t allowedDets = DetID::getMask("ITS,TPC,TRD,TOF,CPV,PHS,EMC,HMP"); + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the workflow + o2::conf::ConfigurableParam::writeINI("o2_barrel_alignment_configuration.ini"); + + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + + DetID::mask_t dets = allowedDets & DetID::getMask(configcontext.options().get<std::string>("detectors")); + + GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("track-sources")); + GID::mask_t dummy; + specs.emplace_back(o2::align::getBarrelAlignmentSpec(src, dets)); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, false, dummy); // clusters MC is not needed + + if (!disableRootOut) { + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/Align/include/Align/AlignConfig.h b/Detectors/Align/include/Align/AlignConfig.h new file mode 100644 index 0000000000000..794031e46ae02 --- /dev/null +++ b/Detectors/Align/include/Align/AlignConfig.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignConfig.h +/// @brief Configuration file for global alignment + +#ifndef ALICEO2_ALIGN_CONFIG_H +#define ALICEO2_ALIGN_CONFIG_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace align +{ + +struct AlignConfig : public o2::conf::ConfigurableParamHelper<AlignConfig> { + enum TrackType { Collision, + Cosmic, + NTrackTypes }; + + float q2PtMin[NTrackTypes] = {0.01, 0.01}; + float q2PtMax[NTrackTypes] = {10., 10.}; + float tglMax[NTrackTypes] = {3., 10.}; + + int minPoints[NTrackTypes] = {4, 10}; + int minDetAcc[NTrackTypes] = {1, 1}; + + int vtxMinCont = 2; // require min number of contributors in Vtx + int vtxMaxCont = 99999; // require max number of contributors in Vtx + int vtxMinContVC = 20; // min number of contributors to use as constraint + + float maxDCAforVC[2]; // DCA cut in R,Z to allow track be subjected to vertex constraint + float maxChi2forVC; // track-vertex chi2 cut to allow the track be subjected to vertex constraint + + O2ParamDef(AlignConfig, "align-conf"); +}; + +} // namespace align +} // namespace o2 + +#endif diff --git a/Detectors/Align/include/Align/AlignableDetector.h b/Detectors/Align/include/Align/AlignableDetector.h new file mode 100644 index 0000000000000..d7d97894482ad --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetector.h @@ -0,0 +1,235 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetector.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Base class for detector: wrapper for set of volumes + +#ifndef ALIGNABLEDETECTOR_H +#define ALIGNABLEDETECTOR_H + +#include "DetectorsCommonDataFormats/DetID.h" +#include <TObjArray.h> +#include <cstdio> +#include "Align/DOFSet.h" +#include "Align/utils.h" +#include "Align/AlignmentTrack.h" +#include "Align/DOFStatistics.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableSensor.h" +#include "Align/AlignableVolume.h" + +class TH1; + +namespace o2 +{ +namespace align +{ + +class Controller; + +//TODO(milettri) : fix possibly incompatible Detector IDs of O2 and AliROOT +class AlignableDetector : public DOFSet +{ + public: + using DetID = o2::detectors::DetID; + + enum { kInitGeomDone = BIT(14), + kInitDOFsDone = BIT(15) }; + enum { kNMaxKalibDOF = 64 }; + // + AlignableDetector() = default; + AlignableDetector(DetID id, Controller* ctr); + ~AlignableDetector() override; + + auto getDetID() const { return mDetID; } + // + virtual void cacheReferenceOCDB(); + virtual void acknowledgeNewRun(int run); + virtual void updateL2GRecoMatrices(); + virtual void applyAlignmentFromMPSol(); + // + int getNDOFsTot() const; + int volID2SID(int vid) const; + int sID2VolID(int sid) const { return sid < getNSensors() ? mSID2VolID[sid] : -1; } //todo + int getNSensors() const { return mSensors.GetEntriesFast(); } + int getNVolumes() const { return mVolumes.GetEntriesFast(); } + int getVolIDMin() const { return mVolIDMin; } + int getVolIDMax() const { return mVolIDMax; } + bool sensorOfDetector(int vid) const { return vid >= mVolIDMin && vid <= mVolIDMax; } + void setAddError(double y, double z); + const double* getAddError() const { return mAddError; } + // + int getNPoints() const { return mNPoints; } + // + AlignableSensor* getSensor(int id) const { return (AlignableSensor*)mSensors.UncheckedAt(id); } + AlignableSensor* getSensorByVolId(int vid) const + { + int sid = volID2SID(vid); + return sid < 0 ? nullptr : getSensor(sid); + } + AlignableSensor* getSensor(const char* symname) const { return (AlignableSensor*)mSensors.FindObject(symname); } + AlignableVolume* getVolume(int id) const { return (AlignableVolume*)mVolumes.UncheckedAt(id); } + AlignableVolume* getVolume(const char* symname) const { return (AlignableVolume*)mVolumes.FindObject(symname); } + // + bool ownsDOFID(int id) const; + AlignableVolume* getVolOfDOFID(int id) const; + // + int getDetLabel() const { return (getDetID() + 1) * 100000; } + int getSensLabel(int i) const { return getDetLabel() + i + 1; } + int getNonSensLabel(int i) const { return getDetLabel() + i + 50001; } + int getSensID(int lbl) const { return (lbl % 100000) < 50001 ? (lbl % 100000) - 1 : -1; } + int getNonSensID(int lbl) const { return (lbl % 100000) < 50001 ? -1 : (lbl % 100000) - 50001; } + + void setFreeDOF(int dof); + void fixDOF(int dof); + void setFreeDOFPattern(uint64_t pat) + { + mCalibDOF = pat; + calcFree(); + } + bool isFreeDOF(int dof) const { return (mCalibDOF & (0x1 << dof)) != 0; } + bool isCondDOF(int dof) const; + uint64_t getFreeDOFPattern() const { return mCalibDOF; } + int getNProcessedPoints() const { return mNProcPoints; } + virtual const char* getCalibDOFName(int) const { return nullptr; } + virtual double getCalibDOFVal(int) const { return 0; } + virtual double getCalibDOFValWithCal(int) const { return 0; } + // + virtual int initGeom(); + virtual int assignDOFs(); + virtual void initDOFs(); + virtual void terminate(); + void fillDOFStat(DOFStatistics& dofst) const; + virtual void addVolume(AlignableVolume* vol); + virtual void defineVolumes(); + virtual void defineMatrices(); + void Print(const Option_t* opt = "") const override; + // virtual int ProcessPoints(const AliESDtrack* esdTr, AlignmentTrack* algTrack, bool inv = false); FIXME(milettri): needs AliESDtrack + virtual void updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const; + virtual void setUseErrorParam(int v = 0); + int getUseErrorParam() const { return mUseErrorParam; } + // + // virtual bool AcceptTrack(const AliESDtrack* trc, int trtype) const = 0; FIXME(milettri): needs AliESDtrack + // bool CheckFlags(const AliESDtrack* trc, int trtype) const; FIXME(milettri): needs AliESDtrack + // + virtual AlignmentPoint* getPointFromPool(); + virtual void resetPool(); + virtual void writeSensorPositions(const char* outFName); + // + void setInitGeomDone() { SetBit(kInitGeomDone); } + bool getInitGeomDone() const { return TestBit(kInitGeomDone); } + // + void setInitDOFsDone() { SetBit(kInitDOFsDone); } + bool getInitDOFsDone() const { return TestBit(kInitDOFsDone); } + void fixNonSensors(); + void setFreeDOFPattern(uint32_t pat = 0xffffffff, int lev = -1, const char* match = nullptr); + void setDOFCondition(int dof, float condErr, int lev = -1, const char* match = nullptr); + int selectVolumes(TObjArray* arr, int lev = -1, const char* match = nullptr); + // + void setDisabled(int tp, bool v) + { + mDisabled[tp] = v; + setObligatory(tp, !v); + } + void setDisabled() + { + setDisabledColl(); + setDisabledCosm(); + } + void setDisabledColl(bool v = true) { setDisabled(utils::Coll, v); } + void setDisabledCosm(bool v = true) { setDisabled(utils::Cosm, v); } + bool isDisabled(int tp) const { return mDisabled[tp]; } + bool isDisabled() const { return IsDisabledColl() && IsDisabledCosm(); } + bool IsDisabledColl() const { return isDisabled(utils::Coll); } + bool IsDisabledCosm() const { return isDisabled(utils::Cosm); } + // + void setTrackFlagSel(int tp, uint64_t f) { mTrackFlagSel[tp] = f; } + void setTrackFlagSelColl(uint64_t f) { setTrackFlagSel(utils::Coll, f); } + void setTrackFlagSelCosm(uint64_t f) { setTrackFlagSel(utils::Cosm, f); } + uint64_t getTrackFlagSel(int tp) const { return mTrackFlagSel[tp]; } + uint64_t getTrackFlagSelColl() const { return getTrackFlagSel(utils::Coll); } + uint64_t getTrackFlagSelCosm() const { return getTrackFlagSel(utils::Cosm); } + // + void setNPointsSel(int tp, int n) { mNPointsSel[tp] = n; } + void setNPointsSelColl(int n) { setNPointsSel(utils::Coll, n); } + void setNPointsSelCosm(int n) { setNPointsSel(utils::Cosm, n); } + int getNPointsSel(int tp) const { return mNPointsSel[tp]; } + int getNPointsSelColl() const { return getNPointsSel(utils::Coll); } + int getNPointsSelCosm() const { return getNPointsSel(utils::Cosm); } + // + // + bool isObligatory(int tp) const { return mObligatory[tp]; } + bool isObligatoryColl() const { return isObligatory(utils::Coll); } + bool isObligatoryCosm() const { return isObligatory(utils::Cosm); } + void setObligatory(int tp, bool v = true); + void setObligatoryColl(bool v = true) { setObligatory(utils::Coll, v); } + void setObligatoryCosm(bool v = true) { setObligatory(utils::Cosm, v); } + // + void addAutoConstraints() const; + void constrainOrphans(const double* sigma, const char* match = nullptr); + + virtual void writePedeInfo(FILE* parOut, const Option_t* opt = "") const; + virtual void writeCalibrationResults() const; + virtual void writeAlignmentResults() const; + // + protected: + void sortSensors(); + void calcFree(bool condFree = false); + // + // ------- dummies --------- + AlignableDetector(const AlignableDetector&); + AlignableDetector& operator=(const AlignableDetector&); + // + protected: + // + DetID mDetID{}; // detector ID + + int mVolIDMin = -1; // min volID for this detector (for sensors only) + int mVolIDMax = -1; // max volID for this detector (for sensors only) + int mNSensors = 0; // number of sensors (i.e. volID's) + int* mSID2VolID = nullptr; //[mNSensors] table of conversion from VolID to sid + int mNProcPoints = 0; // total number of points processed + // + // Detector specific calibration degrees of freedom + uint64_t mCalibDOF = 0; // status of calib dof + // + // Track selection + bool mDisabled[utils::NTrackTypes] = {}; // detector disabled/enabled in the track + bool mObligatory[utils::NTrackTypes] = {}; // detector must be present in the track + uint64_t mTrackFlagSel[utils::NTrackTypes] = {}; // flag for track selection + int mNPointsSel[utils::NTrackTypes] = {}; // min number of points to require + // + int mUseErrorParam = 0; // signal that points need to be updated using track info, 0 - no + double mAddError[2] = {}; // additional error increment for measurement + TObjArray mSensors; // all sensors of the detector + TObjArray mVolumes; // all volumes of the detector + // + // this is transient info + int mNPoints = 0; //! number of points from this detector + int mPoolNPoints = 0; //! number of points in the pool + int mPoolFreePointID = 0; //! id of the last free point in the pool + TObjArray mPointsPool; //! pool of aligment points + // + ClassDefOverride(AlignableDetector, 1); // base class for detector global alignment +}; + +//FIXME(milettri): needs AliESDtrack +////_____________________________________________________ +//inline bool AlignableDetector::CheckFlags(const AliESDtrack* trc, int trtype) const +//{ +// // check if flags are ok +// return (trc->GetStatus() & mTrackFlagSel[trtype]) == mTrackFlagSel[trtype]; +//} +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableDetectorHMPID.h b/Detectors/Align/include/Align/AlignableDetectorHMPID.h new file mode 100644 index 0000000000000..b7c7bd063c576 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetectorHMPID.h @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorHMPID.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief HMPID detector wrapper + +#ifndef ALIGNABLEDETECTORHMPID_H +#define ALIGNABLEDETECTORHMPID_H + +#include "Align/AlignableDetector.h" + +namespace o2 +{ +namespace align +{ +class AlignableDetectorHMPID : public AlignableDetector +{ + public: + AlignableDetectorHMPID(const char* title = ""); + virtual ~AlignableDetectorHMPID(); + // + virtual void defineVolumes(); + // + bool AcceptTrack(const AliESDtrack* trc, int trtype) const; + // + protected: + // + // -------- dummies -------- + AlignableDetectorHMPID(const AlignableDetectorHMPID&); + AlignableDetectorHMPID& operator=(const AlignableDetectorHMPID&); + // + protected: + ClassDef(AlignableDetectorHMPID, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableDetectorITS.h b/Detectors/Align/include/Align/AlignableDetectorITS.h new file mode 100644 index 0000000000000..330552ee69eb3 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetectorITS.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorITS.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief ITS detector wrapper + +#ifndef ALIGNABLEDETECTORITS_H +#define ALIGNABLEDETECTORITS_H + +#include "Align/AlignableDetector.h" +#include "Align/utils.h" +#include "ReconstructionDataFormats/TrackParametrizationWithError.h" + +namespace o2 +{ +namespace align +{ + +class Controller; + +class AlignableDetectorITS : public AlignableDetector +{ + public: + // + enum ITSSel_t { kSPDNoSel, + kSPDBoth, + kSPDAny, + kSPD0, + kSPD1, + kNSPDSelTypes }; + // + AlignableDetectorITS() = default; + AlignableDetectorITS(Controller* ctr); + ~AlignableDetectorITS() override = default; + // + void defineVolumes() override; + // + // RSTODO + // bool AcceptTrack(const AliESDtrack* trc, int trtype) const; + + void SetAddErrorLr(int ilr, double sigY, double sigZ); + void SetSkipLr(int ilr); + // + void updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const override; + void setUseErrorParam(int v = 1) override; + void SetITSSelPattern(int trtype, ITSSel_t sel) { fITSPatt[trtype] = sel; } + void SetITSSelPatternColl(ITSSel_t sel = kSPDAny) { SetITSSelPattern(utils::Coll, sel); } + void SetITSSelPatternCosm(ITSSel_t sel = kSPDNoSel) { SetITSSelPattern(utils::Cosm, sel); } + + int GetITSSelPattern(int tp) const { return fITSPatt[tp]; } + int GetITSSelPatternColl() const { return fITSPatt[utils::Coll]; } + int GetITSSelPatternCosm() const { return fITSPatt[utils::Cosm]; } + // + void Print(const Option_t* opt = "") const override; + // + static const char* GetITSPattName(int sel) { return sel < kNSPDSelTypes ? fgkHitsSel[sel] : nullptr; } + // + protected: + // + // -------- dummies -------- + AlignableDetectorITS(const AlignableDetectorITS&); + AlignableDetectorITS& operator=(const AlignableDetectorITS&); + // + protected: + // + int fITSPatt[utils::NTrackTypes]; // ITS hits selection pattern for coll/cosm tracks + // + static const char* fgkHitsSel[kNSPDSelTypes]; // ITS selection names + // + ClassDefOverride(AlignableDetectorITS, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableDetectorTOF.h b/Detectors/Align/include/Align/AlignableDetectorTOF.h new file mode 100644 index 0000000000000..4897409260dfa --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetectorTOF.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTOF.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Wrapper for TOF detector + +#ifndef ALIGNABLEDETECTORTOF_H +#define ALIGNABLEDETECTORTOF_H + +#include "Align/AlignableDetector.h" + +namespace o2 +{ +namespace align +{ + +class AlignableDetectorTOF : public AlignableDetector +{ + public: + AlignableDetectorTOF(const char* title = ""); + virtual ~AlignableDetectorTOF(); + // + virtual void defineVolumes(); + // + bool AcceptTrack(const AliESDtrack* trc, int trtype) const; + // + protected: + // + // -------- dummies -------- + AlignableDetectorTOF(const AlignableDetectorTOF&); + AlignableDetectorTOF& operator=(const AlignableDetectorTOF&); + // + protected: + ClassDef(AlignableDetectorTOF, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableDetectorTPC.h b/Detectors/Align/include/Align/AlignableDetectorTPC.h new file mode 100644 index 0000000000000..d513f983d44e4 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetectorTPC.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTPC.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TPC detector wrapper + +#ifndef ALIGNABLEDETECTORTPC_H +#define ALIGNABLEDETECTORTPC_H + +#include "Align/AlignableDetector.h" + +namespace o2 +{ +namespace align +{ + +class AlignableDetectorTPC : public AlignableDetector +{ + public: + AlignableDetectorTPC(const char* title = ""); + virtual ~AlignableDetectorTPC(); + // + virtual void defineVolumes(); + // + bool AcceptTrack(const AliESDtrack* trc, int trtype) const; + // + protected: + // + // -------- dummies -------- + AlignableDetectorTPC(const AlignableDetectorTPC&); + AlignableDetectorTPC& operator=(const AlignableDetectorTPC&); + // + protected: + ClassDef(AlignableDetectorTPC, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableDetectorTRD.h b/Detectors/Align/include/Align/AlignableDetectorTRD.h new file mode 100644 index 0000000000000..9b193acb7d26e --- /dev/null +++ b/Detectors/Align/include/Align/AlignableDetectorTRD.h @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTRD.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TRD detector wrapper + +#ifndef ALIGNABLEDETECTORTRD_H +#define ALIGNABLEDETECTORTRD_H + +#include "Align/AlignableDetector.h" + +namespace o2 +{ +namespace align +{ + +class AlignableDetectorTRD : public AlignableDetector +{ + public: + // + enum { kCalibNRCCorrDzDtgl, // correction parameter for NonRC tracklets + kCalibDVT, // global correction to Vdrift*t + kNCalibParams }; // calibration parameters + // + AlignableDetectorTRD(const char* title = ""); + virtual ~AlignableDetectorTRD(); + // + virtual void defineVolumes(); + virtual void Print(const Option_t* opt = "") const; + // + bool AcceptTrack(const AliESDtrack* trc, int trtype) const; + // + virtual const char* getCalibDOFName(int i) const; + // + virtual void writePedeInfo(FILE* parOut, const Option_t* opt = "") const; + // + void SetNonRCCorrDzDtgl(double v = 0) { fNonRCCorrDzDtgl = v; } + double GetNonRCCorrDzDtgl() const { return fNonRCCorrDzDtgl; } + double GetNonRCCorrDzDtglWithCal() const { return GetNonRCCorrDzDtgl() + getParVal(kCalibNRCCorrDzDtgl); } + // + void SetCorrDVT(double v = 0) { fCorrDVT = 0; } + double GetCorrDVT() const { return fCorrDVT; } + double GetCorrDVTWithCal() const { return GetCorrDVT() + getParVal(kCalibDVT); } + // + virtual double getCalibDOFVal(int id) const; + virtual double getCalibDOFValWithCal(int id) const; + // + const double* GetExtraErrRC() const { return fExtraErrRC; } + void SetExtraErrRC(double y = 0.2, double z = 1.0) + { + fExtraErrRC[0] = y; + fExtraErrRC[1] = z; + } + // + protected: + // + // -------- dummies -------- + AlignableDetectorTRD(const AlignableDetectorTRD&); + AlignableDetectorTRD& operator=(const AlignableDetectorTRD&); + // + protected: + // + double fNonRCCorrDzDtgl; // correction in Z for non-crossing tracklets + double fCorrDVT; // correction to Vdrift*t + double fExtraErrRC[2]; // extra errors for RC tracklets + // + static const char* fgkCalibDOFName[kNCalibParams]; + // + ClassDef(AlignableDetectorTRD, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableSensor.h b/Detectors/Align/include/Align/AlignableSensor.h new file mode 100644 index 0000000000000..2374868417f58 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensor.h @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensor.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief End-chain alignment volume in detector branch, where the actual measurement is done. + +#ifndef ALIGNABLESENSOR_H +#define ALIGNABLESENSOR_H + +#include <TMath.h> +#include <TObjArray.h> + +#include "Align/AlignableVolume.h" +#include "Align/DOFStatistics.h" +#include "Align/utils.h" + +//class AliTrackPointArray; +//class AliESDtrack; +class TCloneArray; + +namespace o2 +{ +namespace align +{ + +class AlignableDetector; +class AlignmentPoint; + +class AlignableSensor : public AlignableVolume +{ + public: + // + AlignableSensor() = default; + AlignableSensor(const char* name, int vid, int iid, Controller* ctr); + ~AlignableSensor() override = default; + // + void addChild(AlignableVolume*) override; + // + void setDetector(AlignableDetector* det) { mDet = det; } + AlignableDetector* getDetector() const { return mDet; } + // + int getSID() const { return mSID; } + void setSID(int s) { mSID = s; } + // + void incrementStat() { mNProcPoints++; } + // + // derivatives calculation + virtual void dPosTraDParCalib(const AlignmentPoint* pnt, double* deriv, int calibID, const AlignableVolume* parent = nullptr) const; + virtual void dPosTraDParGeom(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent = nullptr) const; + // + virtual void dPosTraDParGeomLOC(const AlignmentPoint* pnt, double* deriv) const; + virtual void dPosTraDParGeomTRA(const AlignmentPoint* pnt, double* deriv) const; + virtual void dPosTraDParGeomLOC(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent) const; + virtual void dPosTraDParGeomTRA(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent) const; + // + void getModifiedMatrixT2LmodLOC(TGeoHMatrix& matMod, const double* delta) const; + void getModifiedMatrixT2LmodTRA(TGeoHMatrix& matMod, const double* delta) const; + // + virtual void applyAlignmentFromMPSol(); + // + void setAddError(double y, double z) + { + mAddError[0] = y; + mAddError[1] = z; + } + const double* getAddError() const { return mAddError; } + // + void prepareMatrixT2L() override; + // + void setTrackingFrame() override; + bool isSensor() const override { return true; } + void Print(const Option_t* opt = "") const override; + // + virtual void updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const; + void updateL2GRecoMatrices(const TClonesArray* algArr, const TGeoHMatrix* cumulDelta) override; + // + // virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t) = 0; TODO(milettri): needs AliTrackPointArray AliESDtrack + // + int finalizeStat(DOFStatistics& h) override; + // + virtual void prepareMatrixClAlg(); + virtual void prepareMatrixClAlgReco(); + const TGeoHMatrix& getMatrixClAlg() const { return mMatClAlg; } + const TGeoHMatrix& getMatrixClAlgReco() const { return mMatClAlgReco; } + void setMatrixClAlg(const TGeoHMatrix& m) { mMatClAlg = m; } + void setMatrixClAlgReco(const TGeoHMatrix& m) { mMatClAlgReco = m; } + // + protected: + // + bool IsSortable() const override { return true; } + int Compare(const TObject* a) const override; + // + // --------- dummies ----------- + AlignableSensor(const AlignableSensor&); + AlignableSensor& operator=(const AlignableSensor&); + // + protected: + // + int mSID; // sensor id in detector + double mAddError[2]; // additional error increment for measurement + AlignableDetector* mDet; // pointer on detector + TGeoHMatrix mMatClAlg; // reference cluster alignment matrix in tracking frame + TGeoHMatrix mMatClAlgReco; // reco-time cluster alignment matrix in tracking frame + + // + ClassDefOverride(AlignableSensor, 1) +}; +} // namespace align +} // namespace o2 + +#endif diff --git a/Detectors/Align/include/Align/AlignableSensorHMPID.h b/Detectors/Align/include/Align/AlignableSensorHMPID.h new file mode 100644 index 0000000000000..a31382115a8b3 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensorHMPID.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorHMPID.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief HMPID sensor (chamber) + +#ifndef ALIGNABLESENSORHMPID_H +#define ALIGNABLESENSORHMPID_H + +#include "Align/AlignableSensor.h" + +class TObjArray; +//class AliTrackPointArray; +//class AliESDtrack; +class AlignmentPoint; + +namespace o2 +{ +namespace align +{ + +class AlignableSensorHMPID : public AlignableSensor +{ + public: + AlignableSensorHMPID(const char* name = 0, int vid = 0, int iid = 0, int isec = 0); + virtual ~AlignableSensorHMPID(); + // + virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); + // virtual void setTrackingFrame(); + virtual void prepareMatrixT2L(); + // + protected: + // + ClassDef(AlignableSensorHMPID, 1) +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableSensorITS.h b/Detectors/Align/include/Align/AlignableSensorITS.h new file mode 100644 index 0000000000000..815650c3b28c8 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensorITS.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorITS.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief ITS sensor + +#ifndef ALIGNABLESENSORITS_H +#define ALIGNABLESENSORITS_H + +#include "Align/AlignableSensor.h" + +class TObjArray; +class AliTrackPointArray; +class AliESDtrack; +class AlignmentPoint; + +namespace o2 +{ +namespace align +{ + +class AlignableSensorITS : public AlignableSensor +{ + public: + AlignableSensorITS() = default; + AlignableSensorITS(const char* name, int vid, int iid, Controller* ctr); + ~AlignableSensorITS() override = default; + // + // virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); + + void setTrackingFrame() override; + // + protected: + // + ClassDefOverride(AlignableSensorITS, 1) +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableSensorTOF.h b/Detectors/Align/include/Align/AlignableSensorTOF.h new file mode 100644 index 0000000000000..2c648ebb77c96 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensorTOF.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTOF.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TOF sensor + +#ifndef ALIGNABLESENSORTOF_H +#define ALIGNABLESENSORTOF_H + +#include "Align/AlignableSensor.h" + +//class AliTrackPointArray; +//class AliESDtrack; +class AlignmentPoint; +class TObjArray; + +namespace o2 +{ +namespace align +{ + +class AlignableSensorTOF : public AlignableSensor +{ + public: + AlignableSensorTOF(const char* name = 0, int vid = 0, int iid = 0, int isec = 0); + virtual ~AlignableSensorTOF(); + // + virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); + // virtual void setTrackingFrame(); + virtual void prepareMatrixT2L(); + // + int GetSector() const { return fSector; } + void SetSector(uint32_t sc) { fSector = (uint8_t)sc; } + // + protected: + // + uint8_t fSector; // sector ID + // + ClassDef(AlignableSensorTOF, 1) +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableSensorTPC.h b/Detectors/Align/include/Align/AlignableSensorTPC.h new file mode 100644 index 0000000000000..281222394fc7b --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensorTPC.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTPC.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TPC sensor (chamber) + +#ifndef ALIGNABLESENSORTPC_H +#define ALIGNABLESENSORTPC_H + +#include "Align/AlignableSensor.h" + +class TObjArray; +//class AliTrackPointArray; +//class AliESDtrack; +class AlignmentPoint; + +namespace o2 +{ +namespace align +{ + +class AlignableSensorTPC : public AlignableSensor +{ + public: + AlignableSensorTPC(const char* name = 0, int vid = 0, int iid = 0, int isec = 0); + virtual ~AlignableSensorTPC(); + // + int GetSector() const { return fSector; } + void SetSector(uint32_t sc) { fSector = (uint8_t)sc; } + // + virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); + // virtual void setTrackingFrame(); + virtual void prepareMatrixT2L(); + // + protected: + // + uint8_t fSector; // sector ID + + ClassDef(AlignableSensorTPC, 1) +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableSensorTRD.h b/Detectors/Align/include/Align/AlignableSensorTRD.h new file mode 100644 index 0000000000000..f40062e9a1a44 --- /dev/null +++ b/Detectors/Align/include/Align/AlignableSensorTRD.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTRD.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TRD sensor + +#ifndef ALIGNABLESENSORTRD_H +#define ALIGNABLESENSORTRD_H + +#include "Align/AlignableSensor.h" +//class AliTrackPointArray; +//class AliESDtrack; +class AlignmentPoint; +class TObjArray; + +namespace o2 +{ +namespace align +{ + +class AlignableSensorTRD : public AlignableSensor +{ + public: + AlignableSensorTRD(const char* name = 0, int vid = 0, int iid = 0, int isec = 0); + virtual ~AlignableSensorTRD(); + // + int GetSector() const { return fSector; } + void SetSector(uint32_t sc) { fSector = (uint8_t)sc; } + // + virtual AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); + // + virtual void dPosTraDParCalib(const AlignmentPoint* pnt, double* deriv, int calibID, const AlignableVolume* parent = 0) const; + // + // virtual void setTrackingFrame(); + virtual void prepareMatrixT2L(); + // + protected: + // + uint8_t fSector; // sector ID + + ClassDef(AlignableSensorTRD, 1) +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignableVolume.h b/Detectors/Align/include/Align/AlignableVolume.h new file mode 100644 index 0000000000000..96c8f10ea3d8a --- /dev/null +++ b/Detectors/Align/include/Align/AlignableVolume.h @@ -0,0 +1,249 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableVolume.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Base class of alignable volume + +/** + * Base class of alignable volume. Has at least geometric + * degrees of freedom + user defined calibration DOFs. + * The name provided to constructor must be the SYMNAME which + * AliGeomManager can trace to geometry. + */ + +#ifndef ALIGNABLEVOLUME_H +#define ALIGNABLEVOLUME_H + +#include <TNamed.h> +#include <TObjArray.h> +#include <TGeoMatrix.h> +#include <cstdio> +#include "Align/DOFStatistics.h" +#include "Align/DOFSet.h" + +class TObjArray; +class TClonesArray; +class TH1; + +namespace o2 +{ +namespace align +{ + +class Controller; + +class AlignableVolume : public DOFSet +{ + public: + enum DOFGeom_t { kDOFTX, + kDOFTY, + kDOFTZ, + kDOFPS, + kDOFTH, + kDOFPH, + kNDOFGeom, + kAllGeomDOF = 0x3F }; + enum { kDOFBitTX = BIT(kDOFTX), + kDOFBitTY = BIT(kDOFTY), + kDOFBitTZ = BIT(kDOFTZ), + kDOFBitPS = BIT(kDOFPS), + kDOFBitTH = BIT(kDOFTH), + kDOFBitPH = BIT(kDOFPH) }; + enum { kNDOFMax = 32 }; + + enum Frame_t { kLOC, + kTRA, + kNVarFrames }; // variation frames defined + enum { kInitDOFsDoneBit = BIT(14), + kSkipBit = BIT(15), + kExclFromParentConstraintBit = BIT(16) }; + enum { kDefChildConstr = 0xff }; + // + AlignableVolume() = default; + AlignableVolume(const char* symname, int iid, Controller* ctr); + ~AlignableVolume() override; + // + const char* getSymName() const { return GetName(); } + // + int getVolID() const { return (int)GetUniqueID(); } + void setVolID(int v) { SetUniqueID(v); } + int getInternalID() const { return mIntID; } + void setInternalID(int v) { mIntID = v; } + // + // + void assignDOFs(); + void initDOFs(); + // + void getParValGeom(double* delta) const; + + Frame_t getVarFrame() const { return mVarFrame; } + void setVarFrame(Frame_t f) { mVarFrame = f; } + bool isFrameTRA() const { return mVarFrame == kTRA; } + bool isFrameLOC() const { return mVarFrame == kLOC; } + // + void setFreeDOF(int dof) + { + mDOF |= 0x1 << dof; + calcFree(); + } + void fixDOF(int dof) + { + mDOF &= ~(0x1 << dof); + calcFree(); + } + void setFreeDOFPattern(uint32_t pat) + { + mDOF = pat; + calcFree(); + } + bool isFreeDOF(int dof) const { return (mDOF & (0x1 << dof)) != 0; } + bool isCondDOF(int dof) const; + uint32_t getFreeDOFPattern() const { return mDOF; } + uint32_t getFreeDOFGeomPattern() const { return mDOF & kAllGeomDOF; } + // + void addAutoConstraints(TObjArray* constrArr); + bool isChildrenDOFConstrained(int dof) const { return mConstrChild & 0x1 << dof; } + uint8_t getChildrenConstraintPattern() const { return mConstrChild; } + void constrainChildrenDOF(int dof) { mConstrChild |= 0x1 << dof; } + void uConstrainChildrenDOF(int dof) { mConstrChild &= ~(0x1 << dof); } + void setChildrenConstrainPattern(uint32_t pat) { mConstrChild = pat; } + bool hasChildrenConstraint() const { return mConstrChild; } + // + AlignableVolume* getParent() const { return mParent; } + void setParent(AlignableVolume* par) + { + mParent = par; + if (par) { + par->addChild(this); + } + } + int countParents() const; + // + int getNChildren() const { return mChildren ? mChildren->GetEntriesFast() : 0; } + AlignableVolume* getChild(int i) const { return mChildren ? (AlignableVolume*)mChildren->UncheckedAt(i) : nullptr; } + virtual void addChild(AlignableVolume* ch); + // + double getXTracking() const { return mX; } + double getAlpTracking() const { return mAlp; } + // + int getNProcessedPoints() const { return mNProcPoints; } + virtual int finalizeStat(DOFStatistics& h); + void fillDOFStat(DOFStatistics& h) const; + // + int getNDOFGeomFree() const { return mNDOFGeomFree; } + // + virtual void prepareMatrixT2L(); + virtual void setTrackingFrame(); + // + const TGeoHMatrix& getMatrixL2G() const { return mMatL2G; } + const TGeoHMatrix& getMatrixL2GIdeal() const { return mMatL2GIdeal; } + const TGeoHMatrix& getMatrixL2GReco() const { return mMatL2GReco; } + const TGeoHMatrix& getGlobalDeltaRef() const { return mMatDeltaRefGlo; } + void setMatrixL2G(const TGeoHMatrix& m) { mMatL2G = m; } + void setMatrixL2GIdeal(const TGeoHMatrix& m) { mMatL2GIdeal = m; } + void setMatrixL2GReco(const TGeoHMatrix& m) { mMatL2GReco = m; } + void setGlobalDeltaRef(TGeoHMatrix& mat) { mMatDeltaRefGlo = mat; } + // + virtual void prepareMatrixL2G(bool reco = false); + virtual void prepareMatrixL2GIdeal(); + virtual void updateL2GRecoMatrices(const TClonesArray* algArr, const TGeoHMatrix* cumulDelta); + // + void getMatrixT2G(TGeoHMatrix& m) const; + // + const TGeoHMatrix& getMatrixT2L() const { return mMatT2L; } + void setMatrixT2L(const TGeoHMatrix& m); + // + void delta2Matrix(TGeoHMatrix& deltaM, const double* delta) const; + // + // preparation of variation matrices + void getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta) const; + void getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta) const; + void getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const; + void getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const; + // + // creation of global matrices for storage + void createGloDeltaMatrix(TGeoHMatrix& deltaM) const; + void createLocDeltaMatrix(TGeoHMatrix& deltaM) const; + void createPreGloDeltaMatrix(TGeoHMatrix& deltaM) const; + void createPreLocDeltaMatrix(TGeoHMatrix& deltaM) const; + void createAlignmenMatrix(TGeoHMatrix& alg) const; + void createAlignmentObjects(TClonesArray* arr) const; + // + void setSkip(bool v = true) { SetBit(kSkipBit, v); } + bool getSkip() const { return TestBit(kSkipBit); } + // + void excludeFromParentConstraint(bool v = true) { SetBit(kExclFromParentConstraintBit, v); } + bool getExcludeFromParentConstraint() const { return TestBit(kExclFromParentConstraintBit); } + // + void setInitDOFsDone() { SetBit(kInitDOFsDoneBit); } + bool getInitDOFsDone() const { return TestBit(kInitDOFsDoneBit); } + // + bool ownsDOFID(int id) const; + AlignableVolume* getVolOfDOFID(int id) const; + // + virtual bool isSensor() const { return false; } + // + virtual const char* getDOFName(int i) const; + void Print(const Option_t* opt = "") const override; + virtual void writePedeInfo(FILE* parOut, const Option_t* opt = "") const; + // + static const char* getGeomDOFName(int i) { return i < kNDOFGeom ? sDOFName[i] : nullptr; } + static void setDefGeomFree(uint8_t patt) { sDefGeomFree = patt; } + static uint8_t getDefGeomFree() { return sDefGeomFree; } + // + protected: + void calcFree(bool condFree = false); + // + // ------- dummies ------- + AlignableVolume(const AlignableVolume&); + AlignableVolume& operator=(const AlignableVolume&); + // + protected: + // + Frame_t mVarFrame = kTRA; // Variation frame for this volume + int mIntID = -1; // internal id within the detector + double mX = 0.; // tracking frame X offset + double mAlp = 0.; // tracking frame alpa + // + uint32_t mDOF = 0; // pattern of DOFs + char mNDOFGeomFree = 0; // number of free geom degrees of freedom + uint8_t mConstrChild = 0; // bitpattern for constraints on children corrections + // + AlignableVolume* mParent = nullptr; // parent volume + TObjArray* mChildren = nullptr; // array of childrens + // + int mNProcPoints = 0; // n of processed points + + TGeoHMatrix mMatL2GReco{}; // local to global matrix used for reco of data being processed + TGeoHMatrix mMatL2G{}; // local to global matrix, including current alignment + TGeoHMatrix mMatL2GIdeal{}; // local to global matrix, ideal + TGeoHMatrix mMatT2L{}; // tracking to local matrix (ideal) + TGeoHMatrix mMatDeltaRefGlo{}; // global reference delta from Align/Data + // + static const char* sDOFName[kNDOFGeom]; + static const char* sFrameName[kNVarFrames]; + static uint32_t sDefGeomFree; + // + ClassDefOverride(AlignableVolume, 2); +}; + +//___________________________________________________________ +inline void AlignableVolume::getMatrixT2G(TGeoHMatrix& m) const +{ + // compute tracking to global matrix, i.e. glo = T2G*tra = L2G*loc = L2G*T2L*tra + m = getMatrixL2GIdeal(); + m *= getMatrixT2L(); +} +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignmentPoint.h b/Detectors/Align/include/Align/AlignmentPoint.h new file mode 100644 index 0000000000000..1f86129a19226 --- /dev/null +++ b/Detectors/Align/include/Align/AlignmentPoint.h @@ -0,0 +1,283 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignmentPoint.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Meausered point in the sensor. + +/** + * Meausered point in the sensor. + * The measurement is in the tracking frame. + * Apart from measurement may contain also material information. + * Cashes residuals and track positions at its reference X +*/ + +#ifndef ALIGNMENTPOINT_H +#define ALIGNMENTPOINT_H + +#include <TObject.h> +#include <TMatrixD.h> +#include <TVectorD.h> +#include "Align/AlignableSensor.h" +#include "ReconstructionDataFormats/Track.h" +#include "Framework/Logger.h" +#include "Align/utils.h" + +namespace o2 +{ +namespace align +{ + +class AlignmentPoint : public TObject +{ + public: + enum { kMaterialBit = BIT(14), // point contains material + kMeasurementBit = BIT(15), // point contains measurement + kUpdateFromTrackBit = BIT(16), // point needs to recalculate itself using track info + kVaryELossBit = BIT(17), // ELoss variation allowed + kUseBzOnly = BIT(18), // use only Bz component (ITS) + kInvDir = BIT(19), // propagation via this point is in decreasing X direction (upper cosmic leg) + kStatOK = BIT(20) // point is accounted in global statistics + }; + enum { kParY = 0 // track parameters + , + kParZ, + kParSnp, + kParTgl, + kParQ2Pt, + kNMSPar = 4, + kNELossPar = 1, + kNMatDOFs = kNMSPar + kNELossPar }; + enum { kX, + kY, + kZ }; + // + AlignmentPoint(); + ~AlignmentPoint() override = default; + // + void init(); + void updatePointByTrackInfo(const trackParam_t* t); + // + double getAlphaSens() const { return mAlphaSens; } + double getXSens() const { return mXSens; } + double getXPoint() const { return mXSens + getXTracking(); } + double getXTracking() const { return mXYZTracking[0]; } + double getYTracking() const { return mXYZTracking[1]; } + double getZTracking() const { return mXYZTracking[2]; } + const double* getYZTracking() const { return &mXYZTracking[1]; } + const double* getXYZTracking() const { return mXYZTracking; } + const double* getYZErrTracking() const { return mErrYZTracking; } + + const AlignableSensor* getSensor() const { return mSensor; } + uint32_t getVolID() const { return mSensor->getVolID(); } + void setSensor(AlignableSensor* s) { mSensor = s; } + + int getDetID() const { return mDetID; } + int getSID() const { return mSID; } + int getMinLocVarID() const { return mMinLocVarID; } + int getMaxLocVarID() const { return mMaxLocVarID; } + int getNMatPar() const; + bool containsMaterial() const { return TestBit(kMaterialBit); } + bool containsMeasurement() const { return TestBit(kMeasurementBit); } + bool getNeedUpdateFromTrack() const { return TestBit(kUpdateFromTrackBit); } + bool getELossVaried() const { return TestBit(kVaryELossBit); } + bool getUseBzOnly() const { return TestBit(kUseBzOnly); } + bool isInvDir() const { return TestBit(kInvDir); } + bool isStatOK() const { return TestBit(kStatOK); } + // + double getXTimesRho() const { return mXTimesRho; } + double getX2X0() const { return mX2X0; } + void setXTimesRho(double v) { mXTimesRho = v; } + void setX2X0(double v) { mX2X0 = v; } + // + void setDetID(int id) { mDetID = (char)id; } + void setSID(int id) { mSID = (int16_t)id; } + // + void setMinLocVarID(int id) { mMinLocVarID = id; } + void setMaxLocVarID(int id) { mMaxLocVarID = id; } + void setELossVaried(bool v = true) { SetBit(kVaryELossBit, v); } + void setContainsMaterial(bool v = true) { SetBit(kMaterialBit, v); } + void setContainsMeasurement(bool v = true) { SetBit(kMeasurementBit, v); } + void setNeedUpdateFromTrack(bool v = true) { SetBit(kUpdateFromTrackBit, v); } + void setUseBzOnly(bool v = true) { SetBit(kUseBzOnly, v); } + void setInvDir(bool v = true) { SetBit(kInvDir, v); } + void setStatOK(bool v = true) { SetBit(kStatOK, v); } + // + void getResidualsDiag(const double* pos, double& resU, double& resV) const; + void diagonalizeResiduals(double rY, double rZ, double& resU, double& resV) const; + // + void setAlphaSens(double a) { mAlphaSens = a; } + void setXSens(double x) { mXSens = x; } + void setXYZTracking(const double r[3]) + { + for (int i = 3; i--;) { + mXYZTracking[i] = r[i]; + } + } + void setXYZTracking(double x, double y, double z); + void setYZErrTracking(double sy2, double syz, double sz2); + void setYZErrTracking(const double* err) + { + for (int i = 3; i--;) { + mErrYZTracking[i] = err[i]; + } + } + double getErrDiag(int i) const { return mErrDiag[i]; } + // + double* getTrParamWSA() const { return (double*)mTrParamWSA; } + double* getTrParamWSB() const { return (double*)mTrParamWSB; } + double getTrParamWSA(int ip) const { return mTrParamWSA[ip]; } + double getTrParamWSB(int ip) const { return mTrParamWSB[ip]; } + void getTrWSA(trackParam_t& etp) const; + void getTrWSB(trackParam_t& etp) const; + void setTrParamWSA(const double* param) + { + for (int i = 5; i--;) { + mTrParamWSA[i] = param[i]; + } + } + void setTrParamWSB(const double* param) + { + for (int i = 5; i--;) { + mTrParamWSB[i] = param[i]; + } + } + double getResidY() const { return getTrParamWSA(kParY) - getYTracking(); } + double getResidZ() const { return getTrParamWSA(kParZ) - getZTracking(); } + // + void setMatCovDiagonalizationMatrix(const TMatrixD& d); + void setMatCovDiag(const TVectorD& v); + void setMatCovDiagElem(int i, double err2) { mMatCorrCov[i] = err2; } + void unDiagMatCorr(const double* diag, double* nodiag) const; + void diagMatCorr(const double* nodiag, double* diag) const; + void unDiagMatCorr(const float* diag, float* nodiag) const; + void diagMatCorr(const float* nodiag, float* diag) const; + // + void setMatCorrExp(double* p) + { + for (int i = 5; i--;) { + mMatCorrExp[i] = p[i]; + } + } + float* getMatCorrExp() const { return (float*)mMatCorrExp; } + float* getMatCorrCov() const { return (float*)mMatCorrCov; } + // + void getXYZGlo(double r[3]) const; + double getPhiGlo() const; + int getAliceSector() const; + // + int getNGloDOFs() const { return mNGloDOFs; } + int getDGloOffs() const { return mDGloOffs; } + void setNGloDOFs(int n) { mNGloDOFs = n; } + void setDGloOffs(int n) { mDGloOffs = n; } + // + void incrementStat(); + // + virtual void dumpCoordinates() const; + void Print(Option_t* option = "") const final; + void Clear(Option_t* option = "") final; + // + protected: + bool IsSortable() const final { return true; } + int Compare(const TObject* a) const final; + // + // ---------- dummies ---------- + AlignmentPoint(const AlignmentPoint&); + AlignmentPoint& operator=(const AlignmentPoint&); + // + protected: + // + int mMinLocVarID; // The residuals/derivatives depend on fNLocExtPar params + // and point params>=mMinLocVarID. + int mMaxLocVarID; // The residuals/derivatives depend on fNLocExtPar params + // and point params<mMaxLocVarID. + // If the point contains materials, mMaxLocVarID also marks + // the parameters associated with this point + char mDetID; // DetectorID + int16_t mSID; // sensor ID in the detector + float mAlphaSens; // Alpha of tracking frame + float mXSens; // X of tracking frame + float mCosDiagErr; // Cos of Phi of rotation in YZ plane which diagonalize errors + float mSinDiagErr; // Sin of Phi of rotation in YZ plane which diagonalize errors + float mErrDiag[2]; // diagonalized errors + double mXYZTracking[3]; // X,Y,Z in tracking frame + double mErrYZTracking[3]; // errors in tracking frame + // + float mX2X0; // X2X0 seen by the track (including inclination) + float mXTimesRho; // signed Density*Length seen by the track (including inclination) + // + int mNGloDOFs; // number of global DOFs this point depends on + int mDGloOffs; // 1st entry slot of d/dGloPar in the AlgTrack fDResDGlo arrays + float mMatCorrExp[kNMatDOFs]; // material correction due to ELoss expectation (non-diagonalized) + float mMatCorrCov[kNMatDOFs]; // material correction delta covariance (diagonalized) + float mMatDiag[kNMatDOFs][kNMatDOFs]; // matrix for diagonalization of material effects errors + // + double mTrParamWSA[kNMatDOFs]; // workspace for tracks params at this point AFTER material correction + double mTrParamWSB[kNMatDOFs]; // workspace for tracks params at this point BEFORE material correction + + AlignableSensor* mSensor; // sensor of this point + + ClassDefOverride(AlignmentPoint, 1) +}; + +//____________________________________________________ +inline void AlignmentPoint::setXYZTracking(double x, double y, double z) +{ + // assign tracking coordinates + mXYZTracking[0] = x; + mXYZTracking[1] = y; + mXYZTracking[2] = z; +} + +//____________________________________________________ +inline void AlignmentPoint::setYZErrTracking(double sy2, double syz, double sz2) +{ + // assign tracking coordinates + mErrYZTracking[0] = sy2; + mErrYZTracking[1] = syz; + mErrYZTracking[2] = sz2; +} + +inline int AlignmentPoint::getNMatPar() const +{ + // get number of free params for material descriptoin + return containsMaterial() ? (getELossVaried() ? kNMSPar + kNELossPar : kNMSPar) : 0; +} + +//_____________________________________ +inline void AlignmentPoint::diagonalizeResiduals(double rY, double rZ, double& resU, double& resV) const +{ + // rotate residuals to frame where their error matrix is diagonal + resU = mCosDiagErr * rY - mSinDiagErr * rZ; + resV = mSinDiagErr * rY + mCosDiagErr * rZ; + // +} + +//_____________________________________ +inline void AlignmentPoint::getResidualsDiag(const double* pos, double& resU, double& resV) const +{ + // calculate residuals in the frame where the errors are diagonal, given the position + // of the track in the standard tracking frame + diagonalizeResiduals(pos[0] - mXYZTracking[1], pos[1] - mXYZTracking[2], resU, resV); + // +} + +//__________________________________________________________________ +inline void AlignmentPoint::incrementStat() +{ + // increment statistics for detectors this point depends on + mSensor->incrementStat(); + setStatOK(); +} +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignmentTrack.h b/Detectors/Align/include/Align/AlignmentTrack.h new file mode 100644 index 0000000000000..8bd4872f73294 --- /dev/null +++ b/Detectors/Align/include/Align/AlignmentTrack.h @@ -0,0 +1,274 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignmentTrack.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Track model for the alignment + +/** + * Track model for the alignment: trackParam_t for kinematics + * proper with number of multiple scattering kinks. + * Full support for derivatives and residuals calculation + */ + +#ifndef ALIGNMENTTRACK_H +#define ALIGNMENTTRACK_H + +#include "Align/AlignmentPoint.h" +#include "ReconstructionDataFormats/Track.h" +#include <TObjArray.h> +#include <TArrayD.h> +#include <TArrayI.h> +#include "DetectorsBase/Propagator.h" + +namespace o2 +{ +namespace align +{ + +class AlignmentTrack : public trackParam_t, public TObject +{ + public: + using trackParam_t = o2::track::TrackParametrizationWithError<double>; + using Propagator = o2::base::PropagatorImpl<double>; + using MatCorrType = Propagator::MatCorrType; + + static constexpr double MaxDefStep = 3.0; + static constexpr double MaxDefSnp = 0.95; + static constexpr MatCorrType DefMatCorrType = MatCorrType::USEMatCorrLUT; + + enum { kCosmicBit = BIT(14), + kFieldONBit = BIT(15), + kResidDoneBit = BIT(16), + kDerivDoneBit = BIT(17), + kKalmanDoneBit = BIT(18) }; + enum { kNKinParBOFF = 4 // N params for ExternalTrackParam part w/o field + , + kNKinParBON = 5 // N params for ExternalTrackParam part with field + , + kParY = 0 // track parameters + , + kParZ, + kParSnp, + kParTgl, + kParQ2Pt + }; + AlignmentTrack(); + ~AlignmentTrack() override = default; + void defineDOFs(); + double getMass() const { return mMass; } + double getMinX2X0Pt2Account() const { return mMinX2X0Pt2Account; } + int getNPoints() const { return mPoints.GetEntriesFast(); } + AlignmentPoint* getPoint(int i) const { return (AlignmentPoint*)mPoints[i]; } + void addPoint(AlignmentPoint* p) { mPoints.AddLast(p); } + void setMass(double m) { mMass = m; } + void setMinX2X0Pt2Account(double v) { mMinX2X0Pt2Account = v; } + int getNLocPar() const { return mNLocPar; } + int getNLocExtPar() const { return mNLocExtPar; } + int getInnerPointID() const { return mInnerPointID; } + AlignmentPoint* getInnerPoint() const { return getPoint(mInnerPointID); } + // + void Clear(Option_t* opt = "") final; + void Print(Option_t* opt = "") const final; + virtual void dumpCoordinates() const; + // + bool propagateToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tLT = nullptr); + bool propagateParamToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT); // param only + bool propagateParamToPoint(trackParam_t* trSet, int nTr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT); // params only + // + bool calcResiduals(const double* params = nullptr); + bool calcResidDeriv(double* params = nullptr); + bool calcResidDerivGlo(AlignmentPoint* pnt); + // + bool isCosmic() const { return TestBit(kCosmicBit); } + void setCosmic(bool v = true) { SetBit(kCosmicBit, v); } + bool getFieldON() const { return TestBit(kFieldONBit); } + void setFieldON(bool v = true) { SetBit(kFieldONBit, v); } + bool getResidDone() const { return TestBit(kResidDoneBit); } + void setResidDone(bool v = true) { SetBit(kResidDoneBit, v); } + bool getDerivDone() const { return TestBit(kDerivDoneBit); } + void setDerivDone(bool v = true) { SetBit(kDerivDoneBit, v); } + bool getKalmanDone() const { return TestBit(kKalmanDoneBit); } + void setKalmanDone(bool v = true) { SetBit(kKalmanDoneBit, v); } + // + void sortPoints(); + bool iniFit(); + bool residKalman(); + bool processMaterials(); + bool combineTracks(trackParam_t& trcL, const trackParam_t& trcU); + // + void setChi2(double c) { mChi2 = c; }; + double getChi2() const { return mChi2; } + void setChi2Ini(double c) { mChi2Ini = c; }; + double getChi2Ini() const { return mChi2Ini; } + double getChi2CosmUp() const { return mChi2CosmUp; } + double getChi2CosmDn() const { return mChi2CosmDn; } + // + void imposePtBOff(double pt) { setQ2Pt(1. / pt); } + // propagation methods + void copyFrom(const trackParam_t* etp); + bool applyMatCorr(trackParam_t& trPar, const double* corrDiag, const AlignmentPoint* pnt); + bool applyMatCorr(trackParam_t* trSet, int ntr, const double* corrDiaf, const AlignmentPoint* pnt); + bool applyMatCorr(trackParam_t& trPar, const double* corrpar); + // + double getResidual(int dim, int pntID) const { return mResidA[dim][pntID]; } + double* getDResDLoc(int dim, int pntID) const { return &mDResDLocA[dim][pntID * mNLocPar]; } + double* getDResDGlo(int dim, int id) const { return &mDResDGloA[dim][id]; } + int* getGloParID() const { return mGloParIDA; } + // + void setParams(trackParam_t& tr, double x, double alp, const double* par, bool add); + void setParams(trackParam_t* trSet, int ntr, double x, double alp, const double* par, bool add); + void setParam(trackParam_t& tr, int par, double val); + void setParam(trackParam_t* trSet, int ntr, int par, double val); + void modParam(trackParam_t& tr, int par, double delta); + void modParam(trackParam_t* trSet, int ntr, int par, double delta); + // + void richardsonDeriv(const trackParam_t* trSet, const double* delta, + const AlignmentPoint* pnt, double& derY, double& derZ); + // + const double* getLocPars() const { return mLocParA; } + void setLocPars(const double* pars); + // + protected: + // + bool calcResidDeriv(double* params, bool invert, int pFrom, int pTo); + bool calcResiduals(const double* params, bool invert, int pFrom, int pTo); + bool fitLeg(trackParam_t& trc, int pFrom, int pTo, bool& inv); + bool processMaterials(trackParam_t& trc, int pFrom, int pTo); + // + void checkExpandDerGloBuffer(int minSize); + // + static double richardsonExtrap(double* val, int ord = 1); + static double richardsonExtrap(const double* val, int ord = 1); + // + // ---------- dummies ---------- + AlignmentTrack(const AlignmentTrack&); + AlignmentTrack& operator=(const AlignmentTrack&); + // + protected: + int mNLocPar; // number of local params + int mNLocExtPar; // number of local params for the external track param + int mNGloPar; // number of free global parameters the track depends on + int mNDF; // number of degrees of freedom + int mInnerPointID; // ID of inner point in sorted track. For 2-leg cosmics - innermost point of lower leg + bool mNeedInv[2]; // set if one of cosmic legs need inversion + double mMinX2X0Pt2Account; // minimum X2X0/pT accumulated between 2 points worth to account + double mMass; // assumed mass + double mChi2; // chi2 with current residuals + double mChi2CosmUp; // chi2 for cosmic upper leg + double mChi2CosmDn; // chi2 for cosmic down leg + double mChi2Ini; // chi2 with current residuals + TObjArray mPoints; // alignment points + TArrayD mResid[2]; // residuals array + TArrayD mDResDLoc[2]; // array for derivatives over local params + TArrayD mDResDGlo[2]; // array for derivatives over global params + TArrayD mLocPar; // local parameters array + TArrayI mGloParID; // IDs of relevant global params + double* mResidA[2]; //! fast access to residuals + double* mDResDLocA[2]; //! fast access to local derivatives + double* mDResDGloA[2]; //! fast access to global derivatives + int* mGloParIDA; //! fast access to relevant global param IDs + double* mLocParA; //! fast access to local params + private: + bool propagate(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT); + // + ClassDefOverride(AlignmentTrack, 2) +}; + +//____________________________________________________________________________________________ +inline void AlignmentTrack::setParams(trackParam_t& tr, double x, double alp, const double* par, bool add) +{ + // set track params + const double kDefQ2PtCosm = 1; + const double kDefG2PtColl = 1. / 0.6; + params_t tmp; + std::copy(par, par + kNKinParBON, std::begin(tmp)); + tr.set(x, alp, tmp); + if (add) { // par is correction to reference params + for (size_t i = 0; i < kNKinParBON; ++i) { + const double val = tr.getParam(i) + this->getParam(i); + tr.setParam(val, i); + } + } + if (!getFieldON()) { + const double val = [&]() { + if (this->isCosmic()) { + return kDefQ2PtCosm; + } else { + return kDefG2PtColl; + } + }(); + tr.setQ2Pt(val); // only 4 params are valid + } +} + +//____________________________________________________________________________________________ +inline void AlignmentTrack::setParams(trackParam_t* trSet, int ntr, double x, double alp, const double* par, bool add) +{ + // set parames for multiple tracks (VECTORIZE THIS) + if (!add) { // full parameter supplied + for (int itr = ntr; itr--;) { + setParams(trSet[itr], x, alp, par, false); + } + return; + } + params_t partr{0}; // par is a correction to reference parameter + for (int i = mNLocExtPar; i--;) { + partr[i] = getParam(i) + par[i]; + } + for (int itr = ntr; itr--;) { + setParams(trSet[itr], x, alp, partr.data(), false); + } +} + +//____________________________________________________________________________________________ +inline void AlignmentTrack::setParam(trackParam_t& tr, int par, double val) +{ + // set track parameter + tr.setParam(val, par); +} + +//____________________________________________________________________________________________ +inline void AlignmentTrack::setParam(trackParam_t* trSet, int ntr, int par, double val) +{ + // set parames for multiple tracks (VECTORIZE THIS) + for (int i = 0; i < ntr; ++i) { + setParam(trSet[i], par, val); + } +} + +//____________________________________________________________________________________________ +inline void AlignmentTrack::modParam(trackParam_t& tr, int par, double delta) +{ + // modify track parameter + const auto val = tr.getParam(par) + delta; + setParam(tr, par, val); +} + +//____________________________________________________________________________________________ +inline void AlignmentTrack::modParam(trackParam_t* trSet, int ntr, int par, double delta) +{ + // modify track parameter (VECTORIZE THOS) + for (size_t i = 0; i < ntr; ++i) { + modParam(trSet[i], par, delta); + } +} + +//______________________________________________ +inline void AlignmentTrack::copyFrom(const trackParam_t* etp) +{ + // assign kinematics + set(etp->getX(), etp->getAlpha(), etp->getParams(), etp->getCov().data()); +} +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/Controller.h b/Detectors/Align/include/Align/Controller.h new file mode 100644 index 0000000000000..e1d3b1e4111db --- /dev/null +++ b/Detectors/Align/include/Align/Controller.h @@ -0,0 +1,416 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Controller.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Steering class for the global alignment + +/** + * Steering class for the global alignment. Responsible for feeding the track data + * to participating detectors and preparation of the millepede input. + */ + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/GeometryManager.h" +#include "Align/AlignmentTrack.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +// #include "AliSymMatrix.h" FIXME(milettri): needs AliSymMatrix + +#include "Align/Millepede2Record.h" +#include "Align/ResidualsController.h" + +#include <TMatrixDSym.h> +#include <TVectorD.h> +#include <TObjArray.h> +#include <string> +#include <TArrayF.h> +#include <TArrayI.h> +#include <TH1F.h> +#include "Align/utils.h" + +// can be fwd declared if we don't require root dict. +//class TTree; +//class TFile; + +#include <TTree.h> +#include <TFile.h> +#include "Align/Mille.h" + +namespace o2 +{ +namespace globaltracking +{ +class RecoContainer; +} + +namespace align +{ + +//class Mille; + +class EventVertex; +class AlignableDetector; +class AlignableVolume; +class AlignmentPoint; +class ResidualsControllerFast; +class GeometricalConstraint; +class DOFStatistics; + +class Controller : public TObject +{ + public: + struct ProcStat { + enum { kInput, + kAccepted, + kNStatCl }; + enum { kRun, + kEventColl, + kEventCosm, + kTrackColl, + kTrackCosm, + kMaxStat }; + std::array<std::array<int, kMaxStat>, kNStatCl> data{}; + void print() const; + }; + + using DetID = o2::detectors::DetID; + + enum { kNLrSkip = 4 }; + enum { kITS, + kTPC, + kTRD, + kTOF, + kHMPID, + kNDetectors, + kUndefined }; + enum { kCosmLow, + kCosmUp, + kNCosmLegs }; + enum MPOut_t { kMille = BIT(0), + kMPRec = BIT(1), + kContR = BIT(2) }; + enum { kInitGeomDone = BIT(14), + kInitDOFsDone = BIT(15), + kMPAlignDone = BIT(16) }; + // + enum { // STAT histo entries + kRunDone // input runs + , + kEvInp // input events + , + kEvVtx // after vtx selection + , + kTrackInp // input tracks + , + kTrackFitInp // input to ini fit + , + kTrackFitInpVC // those with vertex constraint + , + kTrackProcMatInp // input to process materials + , + kTrackResDerInp // input to resid/deriv calculation + , + kTrackStore // stored tracks + , + kTrackAcc // tracks accepted + , + kTrackControl // control tracks filled + // + , + kNHVars + }; + + Controller() = default; + Controller(DetID::mask_t detmask); + ~Controller() final; + + void expandGlobalsBy(int n); + void process(const o2::globaltracking::RecoContainer& recodata); + + // bool LoadRefOCDB(); FIXME(milettri): needs OCDB + // bool LoadRecoTimeOCDB(); FIXME(milettri): needs OCDB + bool getUseRecoOCDB() const { return mUseRecoOCDB; } + void setUseRecoOCDB(bool v = true) { mUseRecoOCDB = v; } + + void initDetectors(); + void initDOFs(); + void terminate(bool dostat = true); + void setStatHistoLabels(TH1* h) const; + // + void setInitGeomDone() { SetBit(kInitGeomDone); } + bool getInitGeomDone() const { return TestBit(kInitGeomDone); } + // + void setInitDOFsDone() { SetBit(kInitDOFsDone); } + bool getInitDOFsDone() const { return TestBit(kInitDOFsDone); } + // + void setMPAlignDone() { SetBit(kMPAlignDone); } + bool getMPAlignDone() const { return TestBit(kMPAlignDone); } + + void assignDOFs(); + // + void addDetector(AlignableDetector* det); + // + void addConstraint(const GeometricalConstraint* cs) { mConstraints.AddLast((TObject*)cs); } + int getNConstraints() const { return mConstraints.GetEntriesFast(); } + const TObjArray* getConstraints() const { return &mConstraints; } + const GeometricalConstraint* getConstraint(int i) const { return (GeometricalConstraint*)mConstraints[i]; } + void addAutoConstraints(); + // + void acknowledgeNewRun(int run); + void setRunNumber(int run); + int getRunNumber() const { return mRunNumber; } + bool getFieldOn() const { return mFieldOn; } + void setFieldOn(bool v = true) { mFieldOn = v; } + int getTracksType() const { return mTracksType; } + void setTracksType(int t = utils::Coll) { mTracksType = t; } + bool isCosmic() const { return mTracksType == utils::Cosm; } + bool isCollision() const { return mTracksType == utils::Coll; } + void setCosmic(bool v = true) { mTracksType = v ? utils::Cosm : utils::Coll; } + float getStat(int cls, int tp) const { return mStat.data[cls][tp]; } + // + bool checkDetectorPattern(DetID::mask_t patt) const; + bool checkDetectorPoints(const int* npsel) const; + void setObligatoryDetector(DetID id, int tp, bool v = true); + // + // void SetVertex(const AliESDVertex* v) { fVertex = v; } FIXME(milettri): needs AliESDVertex + // const AliESDVertex* GetVertex() const { return fVertex; } FIXME(milettri): needs AliESDVertex + // + //---------------------------------------- + bool readParameters(const char* parfile = "millepede.res", bool useErrors = true); + auto& getGloParVal() { return mGloParVal; } + auto& getGloParErr() { return mGloParErr; } + auto& getGloParLab() { return mGloParLab; } + int getGloParLab(int i) const { return mGloParLab[i]; } + int parID2Label(int i) const { return getGloParLab(i); } + int label2ParID(int lab) const; + AlignableVolume* getVolOfDOFID(int id) const; + AlignableDetector* getDetOfDOFID(int id) const; + // + AlignmentPoint* getRefPoint() const { return mRefPoint.get(); } + // + const ResidualsController& getContResid() const { return mCResid; } + const Millepede2Record& getMPRecord() const { return mMPRecord; } + TTree* getMPRecTree() const { return mMPRecTree.get(); } + AlignmentTrack* getAlgTrack() const { return mAlgTrack.get(); } + // bool ProcessEvent(const AliESDEvent* esdEv); FIXME(milettri): needs AliESDEvent + // bool ProcessTrack(const AliESDtrack* esdTr); FIXME(milettri): needs AliESDtrack + // bool ProcessTrack(const AliESDCosmicTrack* esdCTr); FIXME(milettri): needs AliESDCosmicTrack + // uint32_t AcceptTrack(const AliESDtrack* esdTr, bool strict = true) const; FIXME(milettri): needs AliESDtrack + // uint32_t AcceptTrackCosmic(const AliESDtrack* esdPairCosm[kNCosmLegs]) const; FIXME(milettri): needs AliESDtrack + // bool CheckSetVertex(const AliESDVertex* vtx); FIXME(milettri): needs AliESDVertex + bool addVertexConstraint(); + int getNDetectors() const { return mNDet; } + AlignableDetector* getDetector(DetID id) const { return mDetectors[id]; } + + EventVertex* getVertexSensor() const { return mVtxSens.get(); } + // + void resetDetectors(); + int getNDOFs() const { return mGloParVal.size(); } + //---------------------------------------- + // output related + void setMPDatFileName(const char* name = "mpData"); + void setMPParFileName(const char* name = "mpParams.txt"); + void setMPConFileName(const char* name = "mpConstraints.txt"); + void setMPSteerFileName(const char* name = "mpSteer.txt"); + void setResidFileName(const char* name = "mpControlRes.root"); + void setOutCDBPath(const char* name = "local://outOCDB"); + void setOutCDBComment(const char* cm = nullptr) { mOutCDBComment = cm; } + void setOutCDBResponsible(const char* v = nullptr) { mOutCDBResponsible = v; } + // void SetOutCDBRunRange(int rmin = 0, int rmax = 999999999); FIXME(milettri): needs OCDB + int* getOutCDBRunRange() const { return (int*)mOutCDBRunRange; } + int getOutCDBRunMin() const { return mOutCDBRunRange[0]; } + int getOutCDBRunMax() const { return mOutCDBRunRange[1]; } + float getControlFrac() const { return mControlFrac; } + void setControlFrac(float v = 1.) { mControlFrac = v; } + // void writeCalibrationResults() const; FIXME(milettri): needs OCDB + void applyAlignmentFromMPSol(); + const char* getOutCDBComment() const { return mOutCDBComment.c_str(); } + const char* getOutCDBResponsible() const { return mOutCDBResponsible.c_str(); } + const char* getOutCDBPath() const { return mOutCDBPath.c_str(); } + const char* getMPDatFileName() const { return mMPDatFileName.c_str(); } + const char* getResidFileName() const { return mResidFileName.c_str(); } + const char* getMPParFileName() const { return mMPParFileName.c_str(); } + const char* getMPConFileName() const { return mMPConFileName.c_str(); } + const char* getMPSteerFileName() const { return mMPSteerFileName.c_str(); } + // + bool fillMPRecData(); + bool fillMilleData(); + bool fillControlData(); + void setDoKalmanResid(bool v = true) { mDoKalmanResid = v; } + void setMPOutType(int t) { mMPOutType = t; } + void produceMPData(bool v = true) + { + if (v) { + mMPOutType |= kMille; + } else { + mMPOutType &= ~kMille; + } + } + void produceMPRecord(bool v = true) + { + if (v) { + mMPOutType |= kMPRec; + } else { + mMPOutType &= ~kMPRec; + } + } + void produceControlRes(bool v = true) + { + if (v) { + mMPOutType |= kContR; + } else { + mMPOutType &= ~kContR; + } + } + int getMPOutType() const { return mMPOutType; } + bool getDoKalmanResid() const { return mDoKalmanResid; } + bool getProduceMPData() const { return mMPOutType & kMille; } + bool getProduceMPRecord() const { return mMPOutType & kMPRec; } + bool getProduceControlRes() const { return mMPOutType & kContR; } + void closeMPRecOutput(); + void closeMilleOutput(); + void closeResidOutput(); + void initMPRecOutput(); + void initMIlleOutput(); + void initResidOutput(); + bool storeProcessedTrack(int what); + void printStatistics() const; + bool getMilleTXT() const { return !mMilleOutBin; } + void setMilleTXT(bool v = true) { mMilleOutBin = !v; } + // + void genPedeSteerFile(const Option_t* opt = "") const; + void writePedeConstraints() const; + void checkConstraints(const char* params = nullptr); + DOFStatistics& GetDOFStat() { return mDOFStat; } + void setDOFStat(const DOFStatistics& st) { mDOFStat = st; } + TH1* getHistoStat() const { return mHistoStat; } + void detachHistoStat() { setHistoStat(nullptr); } + void setHistoStat(TH1F* h) { mHistoStat = h; } + void fillStatHisto(int type, float w = 1); + void createStatHisto(); + void fixLowStatFromDOFStat(int thresh = 40); + void loadStat(const char* flname); + // + //---------------------------------------- + // + int getRefRunNumber() const { return mRefRunNumber; } + void setRefRunNumber(int r = -1) { mRefRunNumber = r; } + // + int getRefOCDBLoaded() const { return mRefOCDBLoaded; } + // + void Print(const Option_t* opt = "") const final; + void printLabels() const; + Char_t* getDOFLabelTxt(int idf) const; + // + static Char_t* getDetNameByDetID(int id) { return (Char_t*)sDetectorName[id]; } //RSREM + static void mPRec2Mille(const char* mprecfile, const char* millefile = "mpData.mille", bool bindata = true); + static void mPRec2Mille(TTree* mprTree, const char* millefile = "mpData.mille", bool bindata = true); + // + // AliSymMatrix* BuildMatrix(TVectorD& vec); FIXME(milettri): needs AliSymMatrix + bool testLocalSolution(); + // + // fast check of solution using derivatives + void checkSol(TTree* mpRecTree, bool store = true, bool verbose = false, bool loc = true, const char* outName = "resFast"); + bool checkSol(Millepede2Record* rec, ResidualsControllerFast* rLG = nullptr, ResidualsControllerFast* rL = nullptr, bool verbose = true, bool loc = true); + // + // RSTMP new code + void init(); + + void setDetectorsMask(DetID::mask_t m) { mDetMask = m; } + DetID::mask_t getDetectorsMask() const { return mDetMask; } + + protected: + // + // --------- dummies ----------- + Controller(const Controller&); + Controller& operator=(const Controller&); + // + protected: + // + DetID::mask_t mDetMask{}; + + int mNDet = 0; // number of deectors participating in the alignment + int mNDOFs = 0; // number of degrees of freedom + int mRunNumber = -1; // current run number + bool mFieldOn = false; // field on flag + int mTracksType = utils::Coll; // collision/cosmic event type + std::unique_ptr<AlignmentTrack> mAlgTrack; // current alignment track + + std::array<AlignableDetector*, DetID::nDetectors> mDetectors{}; // detectors participating in the alignment + + std::unique_ptr<EventVertex> mVtxSens; // fake sensor for the vertex + TObjArray mConstraints{}; // array of constraints + // + // Track selection + std::array<DetID::mask_t, utils::NTrackTypes> mObligatoryDetPattern{}; // pattern of obligatory detectors + // + std::vector<float> mGloParVal; // parameters for DOFs + std::vector<float> mGloParErr; // errors for DOFs + std::vector<int> mGloParLab; // labels for DOFs + std::vector<int> mOrderedLbl; //ordered labels + std::vector<int> mLbl2ID; //Label order in mOrderedLbl -> parID + // + std::unique_ptr<AlignmentPoint> mRefPoint; //! reference point for track definition + // + // statistics + ProcStat mStat{}; // processing statistics + // + // output related + float mControlFrac = 1.0; // fraction of tracks to process control residuals + int mMPOutType = kMille | kMPRec | kContR; // What to store as an output, see storeProcessedTrack + std::unique_ptr<Mille> mMille; //! Mille interface + Millepede2Record mMPRecord; //! MP record + Millepede2Record* mMPRecordPtr = &mMPRecord; //! MP record + ResidualsController mCResid; //! control residuals + ResidualsController* mCResidPtr = &mCResid; //! control residuals + + std::unique_ptr<TTree> mMPRecTree; //! tree to store MP record + std::unique_ptr<TTree> mResidTree; //! tree to store control residuals + std::unique_ptr<TFile> mMPRecFile; //! file to store MP record tree + std::unique_ptr<TFile> mResidFile; //! file to store control residuals tree + TArrayF mMilleDBuffer; //! buffer for Mille Derivatives output + TArrayI mMilleIBuffer; //! buffer for Mille Indecis output + std::string mMPDatFileName{"mpData"}; // file name for records binary data output + std::string mMPParFileName{"mpParams.txt"}; // file name for MP params + std::string mMPConFileName{"mpConstraints.txt"}; // file name for MP constraints + std::string mMPSteerFileName{"mpSteer.txt"}; // file name for MP steering + std::string mResidFileName{"mpContolRes.root"}; // file name for optional control residuals + bool mMilleOutBin = true; // optionally text output for Mille debugging + bool mDoKalmanResid = true; // calculate residuals with smoothed kalman in the ControlRes + // + std::string mOutCDBPath{}; // output OCDB path + std::string mOutCDBComment{}; // optional comment to add to output cdb objects + std::string mOutCDBResponsible{}; // optional responsible for output metadata + int mOutCDBRunRange[2] = {}; // run range for output storage + // + DOFStatistics mDOFStat; // stat of entries per dof + TH1F* mHistoStat = nullptr; // histo with general statistics + // + // input related + int mRefRunNumber = 0; // optional run number used for reference + int mRefOCDBLoaded = 0; // flag/counter for ref.OCDB loading + bool mUseRecoOCDB = true; // flag to preload reco-time calib objects + // + static const int sSkipLayers[kNLrSkip]; // detector layers for which we don't need module matrices + static const Char_t* sDetectorName[kNDetectors]; // names of detectors //RSREM + static const Char_t* sHStatName[kNHVars]; // names for stat.bins in the stat histo + static const Char_t* sMPDataExt; // extension for MP2 binary data + // + ClassDefOverride(Controller, 1) +}; + +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/DOFSet.h b/Detectors/Align/include/Align/DOFSet.h new file mode 100644 index 0000000000000..b1c9400ae9ea5 --- /dev/null +++ b/Detectors/Align/include/Align/DOFSet.h @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DOFSet.h +/// @author ruben.shahoyan@cern.ch +/// @brief Interface to contiguous set of DOFs in the controller class + +#ifndef ALG_DOFSET_H +#define ALG_DOFSET_H + +#include <TNamed.h> + +namespace o2 +{ +namespace align +{ +class Controller; + +class DOFSet : public TNamed +{ + public: + DOFSet() = default; + DOFSet(const char* symname, Controller* ctr); + ~DOFSet() override = default; + + const float* getParVals() const; + const float* getParErrs() const; + const int* getParLabs() const; + + float getParVal(int par) const { return getParVals()[par]; } + float getParErr(int par) const { return getParErrs()[par]; } + int getParLab(int par) const { return getParLabs()[par]; } + void getParValGeom(double* delta) const; + // + int getNDOFs() const { return mNDOFs; } + int getNDOFsFree() const { return mNDOFsFree; } + int getNCalibDOFs() const { return mNCalibDOFs; } + int getNCalibDOFsFree() const { return mNCalibDOFsFree; } + int getFirstParGloID() const { return mFirstParGloID; } + int getParGloID(int par) const { return mFirstParGloID + par; } + + void setNDOFs(int n) { mNDOFs = n; } + void setNDOFsFree(int n) { mNDOFsFree = n; } + void setNCalibDOFs(int n) { mNCalibDOFs = n; } + void setNCalibDOFsFree(int n) { mNCalibDOFsFree = n; } + void setFirstParGloID(int id) { mFirstParGloID = id; } + // + void setParVals(int npar, double* vl, double* er); + void setParVal(int par, double v = 0) { getParVals()[par] = v; } + void setParErr(int par, double e = 0) { getParErrs()[par] = e; } + void setParLab(int par, int lab) { getParLabs()[par] = lab; } + + protected: + auto getController() { return mController; } + float* getParVals(); + float* getParErrs(); + int* getParLabs(); + + Controller* mController = nullptr; + int mNDOFs = 0; // number of DOFs + int mNDOFsFree = 0; // numer of DOFs free + int mNCalibDOFs = 0; // number of calibDOFs + int mNCalibDOFsFree = 0; // number of calibDOFs free + int mFirstParGloID = 0; // ID of the 1st parameter in the global results array + + ClassDefOverride(DOFSet, 1); +}; + +} // namespace align +} // namespace o2 + +#endif diff --git a/Detectors/Align/include/Align/DOFStatistics.h b/Detectors/Align/include/Align/DOFStatistics.h new file mode 100644 index 0000000000000..7bb25d7c7f8ea --- /dev/null +++ b/Detectors/Align/include/Align/DOFStatistics.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DOFStatistics.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Mergable Object for statistics of points used by each DOF + +#ifndef DOFStatistics_H +#define DOFStatistics_H + +#include <vector> +#include <TNamed.h> +#include <iostream> + +class TH1F; +class TCollection; + +namespace o2 +{ +namespace align +{ + +class Controller; + +class DOFStatistics : public TNamed +{ + public: + explicit DOFStatistics(int n = 0) : TNamed("DOFStatistics", "DOF statistics"), mStat{n, 0} {}; + + inline int getNDOFs() const noexcept { return mStat.size(); } + inline int getStat(int idf) const noexcept { return idf < getNDOFs() ? mStat[idf] : 0; } + inline const int* getStat() const noexcept { return mStat.data(); }; + inline void setStat(int idf, int v) { mStat[idf] = v; } + inline void addStat(int idf, int v) { mStat[idf] += v; } + inline int getNMerges() const noexcept { return mNMerges; } + std::unique_ptr<TH1F> buildHistogram(Controller* st) const; + void Print(Option_t* opt) const final { std::cout << "NDOFs: " << mStat.size() << " NMerges: " << mNMerges << "\n"; }; + int64_t merge(TCollection* list); + + protected: + + protected: + int mNMerges{1}; // number of merges + std::vector<int> mStat; // statistics per DOF + + ClassDef(DOFStatistics, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/EventVertex.h b/Detectors/Align/include/Align/EventVertex.h new file mode 100644 index 0000000000000..a5ea897f3e445 --- /dev/null +++ b/Detectors/Align/include/Align/EventVertex.h @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EventVertex.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Special fake "sensor" for event vertex. + +/** + * Special fake "sensor" for event vertex. + * It is needed to allow adjustement of the global IP position + * if the event event is used as a measured point. + * Its degrees of freedom of LOCAL X,Y,Z, coinciding with + * GLOBAL X,Y,Z. + * Since the vertex added to the track as a mesured point must be + * defined in the frame with X axis along the tracks, the T2L + * matrix of this sensor need to be recalculated for each track! + */ + +#ifndef EVENTVERTEX_H +#define EVENTVERTEX_H + +#include "Align/AlignableSensor.h" + +class AlignmentPoint; + +namespace o2 +{ +namespace align +{ + +class Controller; + +class EventVertex : public AlignableSensor +{ + public: + EventVertex() = default; + EventVertex(Controller* ctr); + // + void applyCorrection(double* vtx) const; + bool isSensor() const final { return true; } + // + void setAlpha(double alp) + { + mAlp = alp; + prepareMatrixT2L(); + } + void prepareMatrixL2G(bool = 0) final { mMatL2G.Clear(); } // unit matrix + void prepareMatrixL2GIdeal() final { mMatL2GIdeal.Clear(); } // unit matrix + void prepareMatrixT2L() final; + // + // AlignmentPoint* TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* t); FIXME(milettri): needs AliTrackPointArray, AliESDtrack + // + protected: + EventVertex(const EventVertex&); + EventVertex& operator=(const EventVertex&); + // + protected: + // + ClassDef(EventVertex, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/GeometricalConstraint.h b/Detectors/Align/include/Align/GeometricalConstraint.h new file mode 100644 index 0000000000000..c252d4591f4e3 --- /dev/null +++ b/Detectors/Align/include/Align/GeometricalConstraint.h @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GeometricalConstraint.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Descriptor of geometrical constraint + +/** + * Descriptor of geometrical constraint: the cumulative + * corrections of children for requested DOFs in the frame of + * parent (of LAB if parent is not defined) forced to be 0. + * The parent - child relationship need not to be real + * + * Constraint wil be quazi-exact (Lagrange multiplier) if + * corresponding sigma = 0, or of gaussian type is sigma>0 + */ + +#ifndef GEOMETRICALCONSTRAINT_H +#define GEOMETRICALCONSTRAINT_H + +#include <cstdio> +#include <TNamed.h> +#include <TObjArray.h> +#include "Align/AlignableVolume.h" + +namespace o2 +{ +namespace align +{ + +class GeometricalConstraint : public TNamed +{ + public: + enum { kNDOFGeom = AlignableVolume::kNDOFGeom }; + enum { kNoJacobianBit = BIT(14) }; + // + GeometricalConstraint(const char* name = nullptr, const char* title = nullptr); + ~GeometricalConstraint() override; + // + void setParent(const AlignableVolume* par); + const AlignableVolume* getParent() const { return mParent; } + // + int getNChildren() const { return mChildren.GetEntriesFast(); } + AlignableVolume* getChild(int i) const { return (AlignableVolume*)mChildren[i]; } + void addChild(const AlignableVolume* v) + { + if (v) { + mChildren.AddLast((AlignableVolume*)v); + } + } + // + bool isDOFConstrained(int dof) const { return mConstraint & 0x1 << dof; } + uint8_t getConstraintPattern() const { return mConstraint; } + void constrainDOF(int dof) { mConstraint |= 0x1 << dof; } + void unConstrainDOF(int dof) { mConstraint &= ~(0x1 << dof); } + void setConstrainPattern(uint32_t pat) { mConstraint = pat; } + bool hasConstraint() const { return mConstraint; } + double getSigma(int i) const { return mSigma[i]; } + void setSigma(int i, double s = 0) { mSigma[i] = s; } + // + void setNoJacobian(bool v = true) { SetBit(kNoJacobianBit, v); } + bool getNoJacobian() const { return TestBit(kNoJacobianBit); } + // + void constrCoefGeom(const TGeoHMatrix& matRD, float* jac /*[kNDOFGeom][kNDOFGeom]*/) const; + // + void Print(const Option_t* opt = "") const final; + virtual void writeChildrenConstraints(FILE* conOut) const; + virtual void checkConstraint() const; + virtual const char* getDOFName(int i) const { return AlignableVolume::getGeomDOFName(i); } + // + protected: + // ------- dummies ------- + GeometricalConstraint(const GeometricalConstraint&); + GeometricalConstraint& operator=(const GeometricalConstraint&); + // + protected: + uint32_t mConstraint; // bit pattern of constraint + double mSigma[kNDOFGeom]; // optional sigma if constraint is gaussian + const AlignableVolume* mParent; // parent volume for contraint, lab if 0 + TObjArray mChildren; // volumes subjected to constraints + // + ClassDef(GeometricalConstraint, 2); +}; + +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/Mille.h b/Detectors/Align/include/Align/Mille.h new file mode 100644 index 0000000000000..82de5084033be --- /dev/null +++ b/Detectors/Align/include/Align/Mille.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Mille.h +/// @author Gero Flucke, ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since October 2006 +/// @brief Class to write C binary file. + +/** + * Class to write a C binary (cf. below) file of a given name and to fill it + * with information used as input to **pede**. + * Use its member functions \c mille(), \c special(), \c kill() and \c end() + * as you would use the fortran \ref mille.f90 "MILLE" + * and its entry points \c MILLSP, \c KILLE and \c ENDLE. + * + * For debugging purposes constructor flags enable switching to text output and/or + * to write also derivatives and labels which are ==0. + * But note that **pede** will not be able to read text output and has not been tested with + * derivatives/labels ==0. + */ + +#ifndef MILLE_H +#define MILLE_H + +#include <fstream> +#include <TArrayI.h> +#include <TArrayF.h> + +namespace o2 +{ +namespace align +{ + +class Mille +{ + public: + Mille(const char* outFileName, bool asBinary = true, bool writeZero = false); + ~Mille(); + + void mille(int NLC, const float* derLc, int NGL, const float* derGl, + const int* label, float rMeas, float sigma); + void special(int nSpecial, const float* floatings, const int* integers); + void kill(); + int end(); + + private: + void newSet(); + bool checkBufferSize(int nLocal, int nGlobal); + + std::ofstream myOutFile; ///< C-binary for output + bool myAsBinary; ///< if false output as text + bool myWriteZero; ///< if true also write out derivatives/labels ==0 + /// buffer size for ints and floats + int myBufferSize; ///< buffer size for ints and floats + TArrayI myBufferInt; ///< to collect labels etc. + TArrayF myBufferFloat; ///< to collect derivatives etc. + int myBufferPos; ///< position in buffer + bool myHasSpecial; ///< if true, special(..) already called for this record + /// largest label allowed: 2^31 - 1 + enum { myMaxLabel = (0xFFFFFFFF - (1 << 31)) }; +}; + +} // namespace align +} // namespace o2 + +#endif diff --git a/Detectors/Align/include/Align/Millepede2Record.h b/Detectors/Align/include/Align/Millepede2Record.h new file mode 100644 index 0000000000000..370f697440f9b --- /dev/null +++ b/Detectors/Align/include/Align/Millepede2Record.h @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Millepede2Record.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Millepede record in root format (can be converted to proper pede binary format. + +#ifndef MILLEPEDE2RECORD_H +#define MILLEPEDE2RECORD_H + +#include <TObject.h> + +namespace o2 +{ +namespace align +{ + +class AlignmentTrack; + +class Millepede2Record : public TObject +{ + public: + enum { kCosmicBit = BIT(14) }; + // + Millepede2Record(); + ~Millepede2Record() final; + // + int getRun() const { return GetUniqueID(); } + void setRun(int r) { SetUniqueID(r); } + uint32_t getTimeStamp() const { return mTimeStamp; } + void setTimeStamp(uint32_t t) { mTimeStamp = t; } + uint32_t getTrackID() const { return mTrackID; } + void setTrackID(uint32_t t) { mTrackID = t; } + bool isCosmic() const { return TestBit(kCosmicBit); } + void setCosmic(bool v = true) { SetBit(kCosmicBit, v); } + // + int getNVarGlo() const { return mNVarGlo; } + void setNVarGlo(int n) { mNVarGlo = n; } + // + int getNResid() const { return mNResid; } + int getNVarLoc() const { return mNVarLoc; } + // + int getNDLoc(int id) const { return mNDLoc[id]; } + int getNDGlo(int id) const { return mNDGlo[id]; } + int getVolID(int id) const { return mVolID ? mVolID[id] - 1 : -1; } + float getResid(int id) const { return mResid[id]; } + float getResErr(int id) const { return mResErr[id]; } + // + float getChi2Ini() const { return mChi2Ini; } + float getQ2Pt() const { return mQ2Pt; } + float getTgl() const { return mTgl; } + int getNDLocTot() const { return mNDLocTot; } + int getNDGloTot() const { return mNDGloTot; } + const float* getArrGlo() const { return mDGlo; } + const float* getArrLoc() const { return mDLoc; } + const int16_t* getArrLabLoc() const { return mIDLoc; } + const int* getArrLabGlo() const { return mIDGlo; } + // + bool fillTrack(const AlignmentTrack* trc, const int* id2Lab = nullptr); + void dummyRecord(float res, float err, float dGlo, int labGlo); + // + void resize(int nresid, int nloc, int nglo); + // + void Clear(const Option_t* opt = "") final; + void Print(const Option_t* opt = "") const final; + // + protected: + // + // ------- dummies -------- + Millepede2Record(const Millepede2Record&); + Millepede2Record& operator=(const Millepede2Record&); + // + protected: + // + uint32_t mTrackID; // track in the event + uint32_t mTimeStamp; // event time stamp + int mNResid; // number of residuals for the track (=2 npoints) + int mNVarLoc; // number of local variables for the track + int mNVarGlo; // number of global variables defined + int mNDLocTot; // total number of non-zero local derivatives + int mNDGloTot; // total number of non-zero global derivatives + int mNMeas; // number of measured points + float mChi2Ini; // chi2 of initial kalman fit + float mQ2Pt; // q/pt at ref point + float mTgl; // dip angle at ref point + // + int16_t* mNDLoc; //[mNResid] number of non-0 local derivatives per residual + int* mNDGlo; //[mNResid] number of non-0 global derivatives per residual + int* mVolID; //[mNResid] volume id + 1 (0 - not a volume) + float* mResid; //[mNResid] residuals + float* mResErr; //[mNResid] error associated to residual + // + int16_t* mIDLoc; //[mNDLocTot] ID of local variables for non-0 local derivatives + int* mIDGlo; //[mNDGloTot] ID of global variables for non-0 global derivatives + float* mDLoc; //[mNDLocTot] non-0 local derivatives + float* mDGlo; //[mNDGloTot] non-0 global derivatives + // + // aux info + int mNResidBook; //! number of slots booked for residuals + int mNDLocTotBook; //! number of slots booked for local derivatives + int mNDGloTotBook; //! number of slots booked for global derivatives + // + ClassDef(Millepede2Record, 4); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/ResidualsController.h b/Detectors/Align/include/Align/ResidualsController.h new file mode 100644 index 0000000000000..a42c4333f4e25 --- /dev/null +++ b/Detectors/Align/include/Align/ResidualsController.h @@ -0,0 +1,149 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ResidualsController.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Container for control residuals + +#ifndef RESIDUALSCONTROLLER_H +#define RESIDUALSCONTROLLER_H + +#include <TObject.h> +#include <TMath.h> + +namespace o2 +{ +namespace align +{ + +class AlignmentTrack; + +class ResidualsController : public TObject +{ + public: + enum { kCosmicBit = BIT(14), + kVertexBit = BIT(15), + kKalmanDoneBit = BIT(16) }; + // + ResidualsController(); + ~ResidualsController() final; + // + void setRun(int r) { mRun = r; } + void setBz(float v) { mBz = v; } + void setTimeStamp(uint32_t v) { mTimeStamp = v; } + void setTrackID(uint32_t v) { mTrackID = v; } + void setNPoints(int n) + { + mNPoints = n; + resize(n); + } + // + bool isCosmic() const { return TestBit(kCosmicBit); } + bool hasVertex() const { return TestBit(kVertexBit); } + void setCosmic(bool v = kTRUE) { SetBit(kCosmicBit, v); } + void setHasVertex(bool v = kTRUE) { SetBit(kVertexBit, v); } + // + bool getKalmanDone() const { return TestBit(kKalmanDoneBit); } + void setKalmanDone(bool v = kTRUE) { SetBit(kKalmanDoneBit, v); } + // + int getRun() const { return mRun; } + float getBz() const { return mBz; } + uint32_t getTimeStamp() const { return mTimeStamp; } + uint32_t getTrackID() const { return mTrackID; } + int getNPoints() const { return mNPoints; } + int getNBook() const { return mNBook; } + float getChi2() const { return mChi2; } + float getChi2Ini() const { return mChi2Ini; } + float getChi2K() const { return mChi2K; } + float getQ2Pt() const { return mQ2Pt; } + float getX(int i) const { return mX[i]; } + float getY(int i) const { return mY[i]; } + float getZ(int i) const { return mZ[i]; } + float getSnp(int i) const { return mSnp[i]; } + float getTgl(int i) const { return mTgl[i]; } + float getAlpha(int i) const { return mAlpha[i]; } + float getDY(int i) const { return mDY[i]; } + float getDZ(int i) const { return mDZ[i]; } + float getDYK(int i) const { return mDYK[i]; } + float getDZK(int i) const { return mDZK[i]; } + // + float getSigY2K(int i) const { return mSigY2K[i]; } + float getSigYZK(int i) const { return mSigYZK[i]; } + float getSigZ2K(int i) const { return mSigZ2K[i]; } + float getSigmaYK(int i) const { return TMath::Sqrt(mSigY2K[i]); } + float getSigmaZK(int i) const { return TMath::Sqrt(mSigZ2K[i]); } + // + float getSigY2(int i) const { return mSigY2[i]; } + float getSigYZ(int i) const { return mSigYZ[i]; } + float getSigZ2(int i) const { return mSigZ2[i]; } + float getSigmaY(int i) const { return TMath::Sqrt(mSigY2[i]); } + float getSigmaZ(int i) const { return TMath::Sqrt(mSigZ2[i]); } + // + float getSigY2Tot(int i) const { return mSigY2K[i] + mSigY2[i]; } + float getSigYZTot(int i) const { return mSigYZK[i] + mSigYZ[i]; } + float getSigZ2Tot(int i) const { return mSigZ2K[i] + mSigZ2[i]; } + float getSigmaYTot(int i) const { return TMath::Sqrt(getSigY2Tot(i)); } + float getSigmaZTot(int i) const { return TMath::Sqrt(getSigZ2Tot(i)); } + // + int getVolID(int i) const { return mVolID[i]; } + // + float getXLab(int i) const; + float getYLab(int i) const; + float getZLab(int i) const; + // + bool fillTrack(AlignmentTrack* trc, bool doKalman = kTRUE); + void resize(int n); + void Clear(const Option_t* opt = "") final; + void Print(const Option_t* opt = "re") const final; + // + protected: + // + // -------- dummies -------- + ResidualsController(const ResidualsController&); + ResidualsController& operator=(const ResidualsController&); + // + protected: + // + int mRun; // run + float mBz; // field + uint32_t mTimeStamp; // event time + uint32_t mTrackID; // track ID + int mNPoints; // n meas points + int mNBook; //! booked lenfth + float mChi2; // chi2 after solution + float mChi2Ini; // chi2 before solution + float mChi2K; // chi2 from kalman + float mQ2Pt; // Q/Pt at reference point + float* mX; //[mNPoints] tracking X of cluster + float* mY; //[mNPoints] tracking Y of cluster + float* mZ; //[mNPoints] tracking Z of cluster + float* mSnp; //[mNPoints] track Snp + float* mTgl; //[mNPoints] track Tgl + float* mAlpha; //[mNPoints] track alpha + float* mDY; //[mNPoints] Y residual (track - meas) + float* mDZ; //[mNPoints] Z residual (track - meas) + float* mDYK; //[mNPoints] Y residual (track - meas) Kalman + float* mDZK; //[mNPoints] Z residual (track - meas) Kalman + float* mSigY2; //[mNPoints] Y err^2 + float* mSigYZ; //[mNPoints] YZ err + float* mSigZ2; //[mNPoints] Z err^2 + float* mSigY2K; //[mNPoints] Y err^2 of Kalman track smoothing + float* mSigYZK; //[mNPoints] YZ err of Kalman track smoothing + float* mSigZ2K; //[mNPoints] Z err^2 of Kalman track smoothing + int* mVolID; //[mNPoints] volume id (0 for vertex constraint) + int* mLabel; //[mNPoints] label of the volume + // + ClassDef(ResidualsController, 2); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/ResidualsControllerFast.h b/Detectors/Align/include/Align/ResidualsControllerFast.h new file mode 100644 index 0000000000000..171bfb45757d2 --- /dev/null +++ b/Detectors/Align/include/Align/ResidualsControllerFast.h @@ -0,0 +1,111 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ResidualsControllerFast.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Container for control fast residuals evaluated via derivatives + +#ifndef RESIDUALSCONTROLLERFAST_H +#define RESIDUALSCONTROLLERFAST_H + +#include <TObject.h> + +namespace o2 +{ +namespace align +{ + +class ResidualsControllerFast : public TObject +{ + public: + enum { kCosmicBit = BIT(14), + kVertexBit = BIT(15) }; + // + ResidualsControllerFast(); + ~ResidualsControllerFast() final; + // + void setNPoints(int n) + { + mNPoints = n; + resize(n); + } + void setNMatSol(int n) { mNMatSol = n; } + // + void setChi2(float v) { mChi2 = v; } + float getChi2() const { return mChi2; } + // + void setChi2Ini(float v) { mChi2Ini = v; } + float getChi2Ini() const { return mChi2Ini; } + // + bool isCosmic() const { return TestBit(kCosmicBit); } + bool hasVertex() const { return TestBit(kVertexBit); } + void setCosmic(bool v = true) { SetBit(kCosmicBit, v); } + void setHasVertex(bool v = true) { SetBit(kVertexBit, v); } + // + int getNPoints() const { return mNPoints; } + int getNMatSol() const { return mNMatSol; } + int getNBook() const { return mNBook; } + float getD0(int i) const { return mD0[i]; } + float getD1(int i) const { return mD1[i]; } + float getSig0(int i) const { return mSig0[i]; } + float getSig1(int i) const { return mSig1[i]; } + int getVolID(int i) const { return mVolID[i]; } + int getLabel(int i) const { return mLabel[i]; } + // + float* getTrCor() const { return (float*)mTrCorr; } + float* getD0() const { return (float*)mD0; } + float* getD1() const { return (float*)mD1; } + float* getSig0() const { return (float*)mSig0; } + float* getSig1() const { return (float*)mSig1; } + int* getVolID() const { return (int*)mVolID; } + int* getLaber() const { return (int*)mLabel; } + float* getSolMat() const { return (float*)mSolMat; } + float* getMatErr() const { return (float*)mMatErr; } + // + void setResSigMeas(int ip, int ord, float res, float sig); + void setMatCorr(int id, float res, float sig); + void setLabel(int ip, int lab, int vol); + // + void resize(int n); + void Clear(const Option_t* opt = "") final; + void Print(const Option_t* opt = "") const final; + // + protected: + // + // -------- dummies -------- + ResidualsControllerFast(const ResidualsControllerFast&); + ResidualsControllerFast& operator=(const ResidualsControllerFast&); + // + protected: + // + int mNPoints; // n meas points + int mNMatSol; // n local params - ExtTrPar corrections + int mNBook; //! booked lenfth + float mChi2; // chi2 + float mChi2Ini; // chi2 before local fit + // + float mTrCorr[5]; // correction to ExternalTrackParam + float* mD0; //[mNPoints] 1st residual (track - meas) + float* mD1; //[mNPoints] 2ns residual (track - meas) + float* mSig0; //[mNPoints] ort. error 0 + float* mSig1; //[mNPoints] ort. errir 1 + int* mVolID; //[mNPoints] volume id (0 for vertex constraint) + int* mLabel; //[mNPoints] label of the volume + // + float* mSolMat; //[mNMatSol] // material corrections + float* mMatErr; //[mNMatSol] // material corrections errors + // + ClassDef(ResidualsControllerFast, 1); +}; +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/utils.h b/Detectors/Align/include/Align/utils.h new file mode 100644 index 0000000000000..68d5f60faf65d --- /dev/null +++ b/Detectors/Align/include/Align/utils.h @@ -0,0 +1,215 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file utils.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Collection of auxillary methods + +#ifndef UTILS_H +#define UTILS_H + +#include "CommonConstants/MathConstants.h" +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2 +{ +namespace align +{ + +using trackParam_t = typename track::TrackParametrizationWithError<double>; +using value_t = typename trackParam_t::value_t; +using dim2_t = typename trackParam_t::dim2_t; +using dim3_t = typename trackParam_t::dim3_t; +using params_t = typename trackParam_t::params_t; +using covMat_t = typename trackParam_t::covMat_t; + +namespace utils +{ +constexpr double AlmostZeroD = 1e-15; +constexpr float AlmostZeroF = 1e-11; +constexpr double AlmostOneD = 1. - AlmostZeroD; +constexpr float AlmostOneF = 1. - AlmostZeroF; +constexpr double TinyDist = 1.e-7; // ignore distances less that this + +//_________________________________________________________________________________ +enum { Coll, + Cosm, + NTrackTypes }; + +//_________________________________________________________________________________ +inline constexpr double sectorDAlpha() noexcept +{ + return constants::math::PI / 9; +}; + +//_________________________________________________________________________________ +inline constexpr double sector2Alpha(int sect) noexcept +{ + // get barrel sector alpha in -pi:pi format + if (sect > 8) { + sect -= 18; + } + return (sect + 0.5) * sectorDAlpha(); +}; + +//_________________________________________________________________________________ +inline int phi2Sector(double phi) +{ + // get barrel sector from phi in -pi:pi format + int sect = math_utils::nintd((phi * constants::math::Rad2Deg - 10) / 20.); + if (sect < 0) { + sect += 18; + } + return sect; +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr void bringTo02Pi(F& phi) noexcept +{ + // bring phi to 0-2pi range + if (phi < 0) { + phi += constants::math::TwoPI; + } else if (phi > constants::math::TwoPI) { + phi -= constants::math::TwoPI; + } +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr void bringToPiPM(F& phi) noexcept +{ + // bring phi to -pi:pi range + if (phi > constants::math::PI) { + phi -= constants::math::TwoPI; + } +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr bool okForPhiMin(F phiMin, F phi) noexcept +{ + // check if phi is above the phiMin, phi's must be in 0-2pi range + const F dphi = phi - phiMin; + if ((dphi > 0 && dphi < constants::math::PI) || dphi < -constants::math::PI) { + return true; + } else { + return false; + } +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr bool okForPhiMax(F phiMax, F phi) noexcept +{ + // check if phi is below the phiMax, phi's must be in 0-2pi range + const F dphi = phi - phiMax; + if ((dphi < 0 && dphi > -constants::math::PI) || dphi > constants::math::PI) { + return true; + } else { + return false; + } +}; + +//_________________________________________________________________________________ +template <typename F> +constexpr F meanPhiSmall(F phi0, F phi1) +{ + // return mean phi, assume phis in 0:2pi + F phi; + if (!okForPhiMin(phi0, phi1)) { + phi = phi0; + phi0 = phi1; + phi1 = phi; + } + if (phi0 > phi1) { + phi = (phi1 - (constants::math::TwoPI - phi0)) / 2; // wrap + } else { + phi = (phi0 + phi1) / 2; + } + bringTo02Pi(phi); + return phi; +}; + +//_________________________________________________________________________________ +template <typename F> +constexpr F deltaPhiSmall(F phi0, F phi1) noexcept +{ + // return delta phi, assume phi is in 0:2pi + F del; + if (!okForPhiMin(phi0, phi1)) { + del = phi0; + phi0 = phi1; + phi1 = del; + } + del = phi1 - phi0; + if (del < 0) { + del += constants::math::TwoPI; + } + return del; +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr bool smallerAbs(F d, F tolD) noexcept +{ + return std::abs(d) < tolD; +}; + +//_________________________________________________________________________________ +template <typename F> +inline constexpr bool smaller(F d, F tolD) noexcept +{ + return d < tolD; +} + +inline constexpr bool isZeroAbs(double d) noexcept { return smallerAbs(d, AlmostZeroD); }; +inline constexpr bool isZeroAbs(float f) noexcept { return smallerAbs(f, AlmostZeroF); } +inline constexpr bool isZeroPos(double d) noexcept { return smaller(d, AlmostZeroD); } +inline constexpr bool isZeroPos(float f) noexcept { return smaller(f, AlmostZeroF); } + +//__________________________________________ +inline constexpr int findKeyIndex(int key, const int* arr, int n) noexcept +{ + // finds index of key in the array + int imn = 0; + int imx = n - 1; + while (imx >= imn) { + const int mid = (imx + imn) >> 1; + if (arr[mid] == key) { + return mid; + } + + if (arr[mid] < key) { + imn = mid + 1; + } else { + imx = mid - 1; + } + } + return -1; +} + +//_______________________________________________________________ +inline void printBits(size_t patt, int maxBits) +{ + // print maxBits of the pattern + maxBits = std::min(64, maxBits); + for (int i = 0; i < maxBits; i++) { + printf("%c", ((patt >> i) & 0x1) ? '+' : '-'); + } +}; + +} // namespace utils +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/src/AlignConfig.cxx b/Detectors/Align/src/AlignConfig.cxx new file mode 100644 index 0000000000000..8edda453210f7 --- /dev/null +++ b/Detectors/Align/src/AlignConfig.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignConfig.cxx +/// @brief Configuration file for global alignment + +#include "Align/AlignConfig.h" +O2ParamImpl(o2::align::AlignConfig); diff --git a/Detectors/Align/src/AlignLinkDef.h b/Detectors/Align/src/AlignLinkDef.h new file mode 100644 index 0000000000000..d5c5747054862 --- /dev/null +++ b/Detectors/Align/src/AlignLinkDef.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::align::DOFSet + ; +#pragma link C++ class o2::align::AlignableDetector + ; +#pragma link C++ class o2::align::AlignableDetectorITS + ; +//#pragma link C++ class o2::align::AlignableDetectorTOF + ; +//#pragma link C++ class o2::align::AlignableDetectorTPC + ; +//#pragma link C++ class o2::align::AlignableDetectorTRD + ; +//#pragma link C++ class o2::align::AlignableDetectorHMPID + ; +#pragma link C++ class o2::align::Millepede2Record + ; +#pragma link C++ class o2::align::AlignmentPoint + ; +#pragma link C++ class o2::align::AlignableSensor + ; +#pragma link C++ class o2::align::AlignableSensorITS + ; +//#pragma link C++ class o2::align::AlignableSensorTOF + ; +//#pragma link C++ class o2::align::AlignableSensorTPC + ; +//#pragma link C++ class o2::align::AlignableSensorTRD + ; +//#pragma link C++ class o2::align::AlignableSensorHMPID + ; +#pragma link C++ class o2::align::Controller + ; +#pragma link C++ class o2::align::AlignmentTrack + ; +#pragma link C++ class o2::align::AlignableVolume + ; +#pragma link C++ class o2::align::EventVertex + ; +#pragma link C++ class o2::align::ResidualsController + ; +#pragma link C++ class o2::align::ResidualsControllerFast + ; +#pragma link C++ class o2::align::GeometricalConstraint + ; +#pragma link C++ class o2::align::DOFStatistics + ; +#pragma link C++ class o2::align::utils; + +#pragma link C++ class o2::align::AlignConfig + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::align::AlignConfig> + ; + +#endif diff --git a/Detectors/Align/src/AlignableDetector.cxx b/Detectors/Align/src/AlignableDetector.cxx new file mode 100644 index 0000000000000..8787a11557e72 --- /dev/null +++ b/Detectors/Align/src/AlignableDetector.cxx @@ -0,0 +1,775 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetector.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Base class for detector: wrapper for set of volumes + +#include "Align/Controller.h" +#include "Align/AlignableDetector.h" +#include "Align/AlignableSensor.h" +#include "Align/Controller.h" +#include "Align/AlignmentTrack.h" +#include "Align/DOFStatistics.h" +#include "Align/GeometricalConstraint.h" +#include "Framework/Logger.h" +//#include "AliGeomManager.h" +//#include "AliCDBManager.h" +//#include "AliCDBMetaData.h" +//#include "AliCDBEntry.h" +//#include "AliAlignObj.h" +//#include "AliCDBId.h" +//#include "AliExternalTrackParam.h" +//#include "AliAlignObjParams.h" +#include <TString.h> +#include <TH1.h> +#include <TTree.h> +#include <TFile.h> +#include <cstdio> + +ClassImp(o2::align::AlignableDetector); + +using namespace o2::align::utils; + +namespace o2 +{ +namespace align +{ +//____________________________________________ +AlignableDetector::AlignableDetector(DetID id, Controller* ctr) : DOFSet(id.getName(), ctr), mDetID(id) +{ +} + +//____________________________________________ +AlignableDetector::~AlignableDetector() +{ + // d-tor + mSensors.Clear(); // sensors are also attached as volumes, don't delete them here + mVolumes.Delete(); // here all is deleted + mPointsPool.Delete(); +} + +//____________________________________________ +int AlignableDetector::getNDOFsTot() const +{ + int n = getNDOFs(); + for (int i = 0; i < getNVolumes(); i++) { + n += getVolume(i)->getNDOFs(); + } + return n; +} + +//FIXME(milettri): needs AliESDtrack +////____________________________________________ +//int AlignableDetector::ProcessPoints(const AliESDtrack* esdTr, AlignmentTrack* algTrack, bool inv) +//{ +// // Extract the points corresponding to this detector, recalibrate/realign them to the +// // level of the "starting point" for the alignment/calibration session. +// // If inv==true, the track propagates in direction of decreasing tracking X +// // (i.e. upper leg of cosmic track) +// // +// const AliESDfriendTrack* trF(esdTr->GetFriendTrack()); +// const AliTrackPointArray* trP(trF->GetTrackPointArray()); +// // +// int np(trP->getNPoints()); +// int npSel(0); +// AlignmentPoint* apnt(0); +// for (int ip = 0; ip < np; ip++) { +// int vid = trP->GetVolumeID()[ip]; +// if (!sensorOfDetector(vid)){ +// continue;} +// apnt = getSensorByVolId(vid)->TrackPoint2AlgPoint(ip, trP, esdTr); +// if (!apnt){ +// continue;} +// algTrack->addPoint(apnt); +// if (inv){ +// apnt->setInvDir();} +// npSel++; +// mNPoints++; +// } +// // +// return npSel; +//} + +//_________________________________________________________ +void AlignableDetector::acknowledgeNewRun(int run) +{ + // update parameters needed to process this run + + // detector should be able to undo alignment/calibration used during the reco + updateL2GRecoMatrices(); +} + +//_________________________________________________________ +void AlignableDetector::updateL2GRecoMatrices() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs OCDB + // // Update L2G matrices used for data reconstruction + // // + // AliCDBManager* man = AliCDBManager::Instance(); + // AliCDBEntry* ent = man->Get(Form("%s/Align/Data", mDetID.getName())); + // const TClonesArray* algArr = (const TClonesArray*)ent->GetObject(); + // // + // int nvol = getNVolumes(); + // for (int iv = 0; iv < nvol; iv++) { + // AlignableVolume* vol = getVolume(iv); + // // call init for root level volumes, they will take care of their children + // if (!vol->getParent()){ + // vol->updateL2GRecoMatrices(algArr, 0);} + // } + // // +} + +//_________________________________________________________ +void AlignableDetector::applyAlignmentFromMPSol() +{ + // apply alignment from millepede solution array to reference alignment level + LOG(INFO) << "Applying alignment from Millepede solution"; + for (int isn = getNSensors(); isn--;) { + getSensor(isn)->applyAlignmentFromMPSol(); + } +} + +//_________________________________________________________ +void AlignableDetector::cacheReferenceOCDB() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs OCDB + // // if necessary, detector may fetch here some reference OCDB data + // // + // // cache global deltas to avoid preicision problem + // AliCDBManager* man = AliCDBManager::Instance(); + // AliCDBEntry* ent = man->Get(Form("%s/Align/Data", mDetID.getName())); + // TObjArray* arr = (TObjArray*)ent->GetObject(); + // for (int i = arr->GetEntriesFast(); i--;) { + // const AliAlignObjParams* par = (const AliAlignObjParams*)arr->At(i); + // AlignableVolume* vol = getVolume(par->GetSymName()); + // if (!vol) { + // AliErrorF("Volume %s not found", par->GetSymName()); + // continue; + // } + // TGeoHMatrix delta; + // par->GetMatrix(delta); + // vol->setGlobalDeltaRef(delta); + // } +} + +//_________________________________________________________ +AlignmentPoint* AlignableDetector::getPointFromPool() +{ + // fetch or create new free point from the pool. + // detector may override this method to create its own points derived from AlignmentPoint + // + if (mPoolFreePointID >= mPoolNPoints) { // expand pool + mPointsPool.AddAtAndExpand(new AlignmentPoint(), mPoolNPoints++); + } + // + AlignmentPoint* pnt = (AlignmentPoint*)mPointsPool.UncheckedAt(mPoolFreePointID++); + pnt->Clear(); + return pnt; + // +} + +//_________________________________________________________ +void AlignableDetector::resetPool() +{ + // declare pool free + mPoolFreePointID = 0; + mNPoints = 0; +} + +//_________________________________________________________ +void AlignableDetector::addVolume(AlignableVolume* vol) +{ + // add volume + if (getVolume(vol->getSymName())) { + LOG(FATAL) << "Volume " << vol->GetName() << " was already added to " << mDetID.getName(); + } + mVolumes.AddLast(vol); + if (vol->isSensor()) { + mSensors.AddLast(vol); + ((AlignableSensor*)vol)->setDetector(this); + int vid = ((AlignableSensor*)vol)->getVolID(); + if (mVolIDMin < 0 || vid < mVolIDMin) { + mVolIDMin = vid; + } + if (mVolIDMax < 0 || vid > mVolIDMax) { + mVolIDMax = vid; + } + } + // +} + +//_________________________________________________________ +void AlignableDetector::defineMatrices() +{ + // define transformation matrices. Detectors may override this method + // + TGeoHMatrix mtmp; + // + TIter next(&mVolumes); + AlignableVolume* vol(nullptr); + while ((vol = (AlignableVolume*)next())) { + // modified global-local matrix + vol->prepareMatrixL2G(); + // ideal global-local matrix + vol->prepareMatrixL2GIdeal(); + // + } + // Now set tracking-local matrix (MUST be done after ALL L2G matrices are done!) + // Attention: for sensor it is a real tracking matrix extracted from + // the geometry but for container alignable volumes the tracking frame + // is used for as the reference for the alignment parameters only, + // see its definition in the AlignableVolume::PrepateMatrixT2L + next.Reset(); + while ((vol = (AlignableVolume*)next())) { + vol->prepareMatrixT2L(); + if (vol->isSensor()) { + ((AlignableSensor*)vol)->prepareMatrixClAlg(); + } // alignment matrix + } + // +} + +//_________________________________________________________ +void AlignableDetector::sortSensors() +{ + // build local tables for internal numbering + mNSensors = mSensors.GetEntriesFast(); + if (!mNSensors) { + LOG(WARNING) << "No sensors defined"; + return; + } + mSensors.Sort(); + mSID2VolID = new int[mNSensors]; // cash id's for fast binary search + for (int i = 0; i < mNSensors; i++) { + mSID2VolID[i] = getSensor(i)->getVolID(); + getSensor(i)->setSID(i); + } + // +} + +//_________________________________________________________ +int AlignableDetector::initGeom() +{ + // define hiearchy, initialize matrices, return number of global parameters + if (getInitGeomDone()) { + return 0; + } + // + defineVolumes(); + sortSensors(); // VolID's must be in increasing order + defineMatrices(); + // + // calculate number of global parameters + int nvol = getNVolumes(); + mNDOFs = 0; + for (int iv = 0; iv < nvol; iv++) { + AlignableVolume* vol = getVolume(iv); + mNDOFs += vol->getNDOFs(); + } + // + mNDOFs += mNCalibDOFs; + setInitGeomDone(); + return mNDOFs; +} + +//_________________________________________________________ +int AlignableDetector::assignDOFs() +{ + // assign DOFs IDs, parameters + // + setFirstParGloID(mController->getNDOFs()); + if (mFirstParGloID == (int)mController->getGloParVal().size()) { + mController->expandGlobalsBy(mNCalibDOFs); + } + for (int icl = 0; icl < mNCalibDOFs; icl++) { + setParLab(icl, icl); // TODO RS FIXME + } + // + int nvol = getNVolumes(); + for (int iv = 0; iv < nvol; iv++) { + AlignableVolume* vol = getVolume(iv); + if (!vol->getParent()) { // call init for root level volumes, they will take care of their children + vol->assignDOFs(); + } + } + return mNDOFs; +} + +//_________________________________________________________ +void AlignableDetector::initDOFs() +{ + // initialize free parameters + if (getInitDOFsDone()) { + LOG(FATAL) << "DOFs are already initialized for " << mDetID.getName(); + } + // + auto pars = getParVals(); + auto errs = getParErrs(); + // process calibration DOFs + for (int i = 0; i < mNCalibDOFs; i++) { + if (errs[i] < -9999 && isZeroAbs(pars[i])) { + fixDOF(i); + } + } + // + int nvol = getNVolumes(); + for (int iv = 0; iv < nvol; iv++) { + getVolume(iv)->initDOFs(); + } + // + calcFree(true); + // + setInitDOFsDone(); + return; +} + +//_________________________________________________________ +int AlignableDetector::volID2SID(int vid) const +{ + // find SID corresponding to VolID + int mn(0), mx(mNSensors - 1); + while (mx >= mn) { + int md((mx + mn) >> 1), vids(getSensor(md)->getVolID()); + if (vid < vids) { + mx = md - 1; + } else if (vid > vids) { + mn = md + 1; + } else { + return md; + } + } + return -1; +} + +//____________________________________________ +void AlignableDetector::Print(const Option_t* opt) const +{ + // print info + TString opts = opt; + opts.ToLower(); + printf("\nDetector:%5s %5d volumes %5d sensors {VolID: %5d-%5d} Def.Sys.Err: %.4e %.4e | Stat:%d\n", + mDetID.getName(), getNVolumes(), getNSensors(), getVolIDMin(), + getVolIDMax(), mAddError[0], mAddError[1], mNProcPoints); + // + printf("Errors assignment: "); + if (mUseErrorParam) { + printf("param %d\n", mUseErrorParam); + } else { + printf("from TrackPoints\n"); + } + // + printf("Allowed in Collisions: %7s | Cosmic: %7s\n", + isDisabled(Coll) ? " NO " : " YES ", isDisabled(Cosm) ? " NO " : " YES "); + // + printf("Obligatory in Collisions: %7s | Cosmic: %7s\n", + isObligatory(Coll) ? " YES " : " NO ", isObligatory(Cosm) ? " YES " : " NO "); + // + fmt::printf("Sel. flags in Collisions: {:05#x}%05 | Cosmic: 0x{:05#x}%05\n", mTrackFlagSel[Coll], mTrackFlagSel[Cosm]); + // + printf("Min.points in Collisions: %7d | Cosmic: %7d\n", + mNPointsSel[Coll], mNPointsSel[Cosm]); + // + if (!(IsDisabledColl() && IsDisabledCosm()) && opts.Contains("long")) { + for (int iv = 0; iv < getNVolumes(); iv++) { + getVolume(iv)->Print(opt); + } + } + // + for (int i = 0; i < getNCalibDOFs(); i++) { + printf("CalibDOF%2d: %-20s\t%e\n", i, getCalibDOFName(i), getCalibDOFValWithCal(i)); + } +} + +//____________________________________________ +void AlignableDetector::setAddError(double sigy, double sigz) +{ + // add syst error to all sensors + LOG(INFO) << "Adding sys.error " << std::fixed << std::setprecision(4) << sigy << " " << sigz << " to all sensors"; + mAddError[0] = sigy; + mAddError[1] = sigz; + for (int isn = getNSensors(); isn--;) { + getSensor(isn)->setAddError(sigy, sigz); + } + // +} + +//____________________________________________ +void AlignableDetector::setUseErrorParam(int v) +{ + // set type of points error parameterization + LOG(FATAL) << "setUseErrorParam is not implemented for this detector"; + // +} + +//____________________________________________ +void AlignableDetector::updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const +{ + // update point using specific error parameterization + LOG(FATAL) << "If needed, this method has to be implemented for specific detector"; +} + +//____________________________________________ +void AlignableDetector::defineVolumes() +{ + // define alignment volumes + LOG(FATAL) << "defineVolumes method has to be implemented for specific detector"; +} + +//____________________________________________ +void AlignableDetector::setObligatory(int tp, bool v) +{ + // mark detector presence obligatory in the track + mObligatory[tp] = v; + mController->setObligatoryDetector(getDetID(), tp, v); +} + +//______________________________________________________ +void AlignableDetector::writePedeInfo(FILE* parOut, const Option_t* opt) const +{ + // contribute to params and constraints template files for PEDE + fprintf(parOut, "\n!!\t\tDetector:\t%s\tNDOFs: %d\n", mDetID.getName(), getNDOFs()); + // + // parameters + int nvol = getNVolumes(); + for (int iv = 0; iv < nvol; iv++) { // call for root level volumes, they will take care of their children + AlignableVolume* vol = getVolume(iv); + if (!vol->getParent()) { + vol->writePedeInfo(parOut, opt); + } + } + // +} + +//______________________________________________________ +void AlignableDetector::writeCalibrationResults() const +{ + // store calibration results + writeAlignmentResults(); + // + // eventually we may write other calibrations +} + +//______________________________________________________ +void AlignableDetector::writeAlignmentResults() const +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(lettrich): needs OCDB + // // store updated alignment + // TClonesArray* arr = new TClonesArray("AliAlignObjParams", 10); + // // + // int nvol = getNVolumes(); + // for (int iv = 0; iv < nvol; iv++) { + // AlignableVolume* vol = getVolume(iv); + // // call only for top level objects, they will take care of children + // if (!vol->getParent()){ + // vol->createAlignmentObjects(arr);} + // } + // // + // AliCDBManager* man = AliCDBManager::Instance(); + // AliCDBMetaData* md = new AliCDBMetaData(); + // md->SetResponsible(mController->getOutCDBResponsible()); + // md->SetComment(mController->getOutCDBResponsible()); + // // + // AliCDBId id(Form("%s/Align/Data", mDetID.getName()), mController->getOutCDBRunMin(), mController->getOutCDBRunMax()); + // man->Put(arr, id, md); + // // + // delete arr; +} + +//______________________________________________________ +bool AlignableDetector::ownsDOFID(int id) const +{ + // check if DOF ID belongs to this detector + for (int iv = getNVolumes(); iv--;) { + AlignableVolume* vol = getVolume(iv); // check only top level volumes + if (!vol->getParent() && vol->ownsDOFID(id)) { + return true; + } + } + // calibration DOF? + if (id >= mFirstParGloID && id < mFirstParGloID + mNCalibDOFs) { + return true; + } + // + return false; +} + +//______________________________________________________ +AlignableVolume* AlignableDetector::getVolOfDOFID(int id) const +{ + // gets volume owning this DOF ID + for (int iv = getNVolumes(); iv--;) { + AlignableVolume* vol = getVolume(iv); + if (vol->getParent()) { + continue; + } // check only top level volumes + if ((vol = vol->getVolOfDOFID(id))) { + return vol; + } + } + return nullptr; +} + +//______________________________________________________ +void AlignableDetector::terminate() +{ + // called at the end of processing + // if (isDisabled()) return; + int nvol = getNVolumes(); + mNProcPoints = 0; + auto& st = mController->GetDOFStat(); + for (int iv = 0; iv < nvol; iv++) { + AlignableVolume* vol = getVolume(iv); + // call init for root level volumes, they will take care of their children + if (!vol->getParent()) { + mNProcPoints += vol->finalizeStat(st); + } + } + fillDOFStat(st); // fill stat for calib dofs +} + +//________________________________________ +void AlignableDetector::addAutoConstraints() const +{ + // adds automatic constraints + int nvol = getNVolumes(); + for (int iv = 0; iv < nvol; iv++) { // call for root level volumes, they will take care of their children + AlignableVolume* vol = getVolume(iv); + if (!vol->getParent()) { + vol->addAutoConstraints((TObjArray*)mController->getConstraints()); + } + } +} + +//________________________________________ +void AlignableDetector::fixNonSensors() +{ + // fix all non-sensor volumes + for (int i = getNVolumes(); i--;) { + AlignableVolume* vol = getVolume(i); + if (vol->isSensor()) { + continue; + } + vol->setFreeDOFPattern(0); + vol->setChildrenConstrainPattern(0); + } +} + +//________________________________________ +int AlignableDetector::selectVolumes(TObjArray* arr, int lev, const char* match) +{ + // select volumes matching to pattern and/or hierarchy level + // + if (!arr) { + return 0; + } + int nadd = 0; + TString mts = match, syms; + for (int i = getNVolumes(); i--;) { + AlignableVolume* vol = getVolume(i); + if (lev >= 0 && vol->countParents() != lev) { + continue; + } // wrong level + if (!mts.IsNull() && !(syms = vol->getSymName()).Contains(mts)) { + continue; + } //wrong name + arr->AddLast(vol); + nadd++; + } + // + return nadd; +} + +//________________________________________ +void AlignableDetector::setFreeDOFPattern(uint32_t pat, int lev, const char* match) +{ + // set free DOFs to volumes matching either to hierarchy level or + // whose name contains match + // + TString mts = match, syms; + for (int i = getNVolumes(); i--;) { + AlignableVolume* vol = getVolume(i); + if (lev >= 0 && vol->countParents() != lev) { + continue; + } // wrong level + if (!mts.IsNull() && !(syms = vol->getSymName()).Contains(mts)) { + continue; + } //wrong name + vol->setFreeDOFPattern(pat); + } + // +} + +//________________________________________ +void AlignableDetector::setDOFCondition(int dof, float condErr, int lev, const char* match) +{ + // set condition for DOF of volumes matching either to hierarchy level or + // whose name contains match + // + TString mts = match, syms; + for (int i = getNVolumes(); i--;) { + AlignableVolume* vol = getVolume(i); + if (lev >= 0 && vol->countParents() != lev) { + continue; + } // wrong level + if (!mts.IsNull() && !(syms = vol->getSymName()).Contains(mts)) { + continue; + } //wrong name + if (dof >= vol->getNDOFs()) { + continue; + } + vol->setParErr(dof, condErr); + if (condErr >= 0 && !vol->isFreeDOF(dof)) { + vol->setFreeDOF(dof); + } + //if (condErr<0 && vol->isFreeDOF(dof)) vol->fixDOF(dof); + } + // +} + +//________________________________________ +void AlignableDetector::constrainOrphans(const double* sigma, const char* match) +{ + // additional constraint on volumes w/o parents (optionally containing "match" in symname) + // sigma<0 : dof is not contrained + // sigma=0 : dof constrained exactly (Lagrange multiplier) + // sigma>0 : dof constrained by gaussian constraint + // + TString mts = match, syms; + GeometricalConstraint* constr = new GeometricalConstraint(); + for (int i = 0; i < AlignableVolume::kNDOFGeom; i++) { + if (sigma[i] >= 0) { + constr->constrainDOF(i); + } else { + constr->unConstrainDOF(i); + } + constr->setSigma(i, sigma[i]); + } + for (int i = getNVolumes(); i--;) { + AlignableVolume* vol = getVolume(i); + if (vol->getParent()) { + continue; + } // wrong level + if (!mts.IsNull() && !(syms = vol->getSymName()).Contains(mts)) { + continue; + } //wrong name + constr->addChild(vol); + } + // + if (!constr->getNChildren()) { + LOG(INFO) << "No volume passed filter " << match; + delete constr; + } else { + ((TObjArray*)mController->getConstraints())->Add(constr); + } +} + +//________________________________________ +void AlignableDetector::setFreeDOF(int dof) +{ + // set detector free dof + if (dof >= kNMaxKalibDOF) { + LOG(FATAL) << "Detector CalibDOFs limited to " << kNMaxKalibDOF << ", requested " << dof; + } + mCalibDOF |= 0x1 << dof; + calcFree(); +} + +//________________________________________ +void AlignableDetector::fixDOF(int dof) +{ + // fix detector dof + if (dof >= kNMaxKalibDOF) { + LOG(FATAL) << "Detector CalibDOFs limited to " << kNMaxKalibDOF << ", requested " << dof; + } + mCalibDOF &= ~(0x1 << dof); + calcFree(); +} + +//__________________________________________________________________ +bool AlignableDetector::isCondDOF(int i) const +{ + // is DOF free and conditioned? + return (!isZeroAbs(getParVal(i)) || !isZeroAbs(getParErr(i))); +} + +//__________________________________________________________________ +void AlignableDetector::calcFree(bool condFix) +{ + // calculate free calib dofs. If condFix==true, condition parameter a la pede, i.e. error < 0 + mNCalibDOFsFree = 0; + for (int i = 0; i < mNCalibDOFs; i++) { + if (!isFreeDOF(i)) { + if (condFix) { + setParErr(i, -999); + } + continue; + } + mNCalibDOFsFree++; + } + // +} + +//______________________________________________________ +void AlignableDetector::fillDOFStat(DOFStatistics& st) const +{ + // fill statistics info hist + int ndf = getNCalibDOFs(); + int dof0 = getFirstParGloID(); + int stat = getNProcessedPoints(); + for (int idf = 0; idf < ndf; idf++) { + int dof = idf + dof0; + st.addStat(dof, stat); + } + // +} + +//______________________________________________________ +void AlignableDetector::writeSensorPositions(const char* outFName) +{ + // create tree with sensors ideal, ref and reco positions + int ns = getNSensors(); + double loc[3] = {0}; + // ------- local container type for dumping sensor positions ------ + typedef struct { + int volID; // volume id + double pId[3]; // ideal + double pRf[3]; // reference + double pRc[3]; // reco-time + } snpos_t; + snpos_t spos; // + TFile* fl = TFile::Open(outFName, "recreate"); + TTree* tr = new TTree("snpos", Form("sensor poisitions for %s", mDetID.getName())); + tr->Branch("volID", &spos.volID, "volID/I"); + tr->Branch("pId", &spos.pId, "pId[3]/D"); + tr->Branch("pRf", &spos.pRf, "pRf[3]/D"); + tr->Branch("pRc", &spos.pRc, "pRc[3]/D"); + // + for (int isn = 0; isn < ns; isn++) { + AlignableSensor* sens = getSensor(isn); + spos.volID = sens->getVolID(); + sens->getMatrixL2GIdeal().LocalToMaster(loc, spos.pId); + sens->getMatrixL2G().LocalToMaster(loc, spos.pRf); + sens->getMatrixL2GReco().LocalToMaster(loc, spos.pRc); + tr->Fill(); + } + tr->Write(); + delete tr; + fl->Close(); + delete fl; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableDetectorHMPID.cxx b/Detectors/Align/src/AlignableDetectorHMPID.cxx new file mode 100644 index 0000000000000..b24ae159e0c44 --- /dev/null +++ b/Detectors/Align/src/AlignableDetectorHMPID.cxx @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorHMPID.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief HMPID detector wrapper + +#include "Align/AlignableDetectorHMPID.h" +//#include "AliHMPIDParam.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableSensorHMPID.h" +#include "Align/Controller.h" +//#include "AliGeomManager.h" +//#include "AliESDtrack.h" +#include "Framework/Logger.h" +#include <TGeoManager.h> + +ClassImp(o2::align::AlignableDetectorHMPID); + +namespace o2 +{ +namespace align +{ + +//____________________________________________ +AlignableDetectorHMPID::AlignableDetectorHMPID(const char* title) +{ + // default c-tor + SetNameTitle(Controller::getDetNameByDetID(Controller::kHMPID), title); + setDetID(Controller::kHMPID); +} + +//____________________________________________ +AlignableDetectorHMPID::~AlignableDetectorHMPID() +{ + // d-tor +} + +//____________________________________________ +void AlignableDetectorHMPID::defineVolumes() +{ + // define HMPID volumes + // + int labDet = getDetLabel(); + AliGeomManager::ELayerID idHMPID = AliGeomManager::kHMPID; + for (int iCh = AliHMPIDParam::kMinCh; iCh <= AliHMPIDParam::kMaxCh; iCh++) { + const char* symname = Form("/HMPID/Chamber%i", iCh); + if (!gGeoManager->GetAlignableEntry(symname)) { + AliErrorF("Did not find alignable %s", symname); + continue; + } + uint16_t vid = AliGeomManager::LayerToVolUID(idHMPID, iCh); + int iid = labDet + (1 + iCh) * 10000; + AlignableSensorHMPID* sens = new AlignableSensorHMPID(symname, vid, iid); + addVolume(sens); + } //iCh loop + // +} + +//____________________________________________ +bool AlignableDetectorHMPID::AcceptTrack(const AliESDtrack* trc, int trtype) const +{ + // test if detector had seed this track + if (!CheckFlags(trc, trtype)) + return false; + if (trc->GetNcls(1) < mNPointsSel[trtype]) + return false; + return true; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableDetectorITS.cxx b/Detectors/Align/src/AlignableDetectorITS.cxx new file mode 100644 index 0000000000000..2ab65c9e37468 --- /dev/null +++ b/Detectors/Align/src/AlignableDetectorITS.cxx @@ -0,0 +1,180 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorITS.cxx +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief ITS detector wrapper + +#include "Align/AlignableDetectorITS.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableSensorITS.h" +#include "Align/Controller.h" +#include "ITSBase/GeometryTGeo.h" +#include <TMath.h> +#include <cstdio> + +using namespace TMath; +using namespace o2::align::utils; + +namespace o2 +{ +namespace align +{ + +const char* AlignableDetectorITS::fgkHitsSel[AlignableDetectorITS::kNSPDSelTypes] = + {"SPDNoSel", "SPDBoth", "SPDAny", "SPD0", "SPD1"}; + +//____________________________________________ +AlignableDetectorITS::AlignableDetectorITS(Controller* ctr) : AlignableDetector(DetID::ITS, ctr) +{ + // default c-tor + defineVolumes(); + setUseErrorParam(); + SetITSSelPatternColl(); + SetITSSelPatternCosm(); +} + +//____________________________________________ +void AlignableDetectorITS::defineVolumes() +{ + // define ITS volumes + // + auto geom = o2::its::GeometryTGeo::Instance(); + + AlignableVolume *volITS = nullptr, *volLr = nullptr, *volHB = nullptr, *volSt = nullptr, *volHSt = nullptr, *volMod = nullptr; + AlignableSensorITS* sens = nullptr; + // + std::unordered_map<std::string, AlignableVolume*> sym2vol; + addVolume(volITS = new AlignableVolume(geom->composeSymNameITS(), getDetLabel(), mController)); + sym2vol[volITS->getSymName()] = volITS; + // + int nonSensCnt = 0; + for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) { + addVolume(volLr = new AlignableVolume(geom->composeSymNameLayer(ilr), getNonSensLabel(nonSensCnt++), mController)); + sym2vol[volLr->getSymName()] = volLr; + volLr->setParent(volITS); + for (int ihb = 0; ihb < 2; ihb++) { + addVolume(volHB = new AlignableVolume(geom->composeSymNameHalfBarrel(ilr, ihb), getNonSensLabel(nonSensCnt++), mController)); + volHB->setParent(volLr); + int nstavesHB = geom->getNumberOfStaves(ilr) / 2; + for (int ist = 0; ist < nstavesHB; ist++) { + addVolume(volSt = new AlignableVolume(geom->composeSymNameStave(ilr, ihb, ist), getNonSensLabel(nonSensCnt++), mController)); + sym2vol[volSt->getSymName()] = volSt; + volSt->setParent(volLr); + for (int ihst = 0; ihst < geom->getNumberOfHalfStaves(ilr); ihst++) { + addVolume(volHSt = new AlignableVolume(geom->composeSymNameHalfStave(ilr, ihb, ist, ihst), getNonSensLabel(nonSensCnt++), mController)); + sym2vol[volHSt->getSymName()] = volHSt; + volHSt->setParent(volSt); + for (int imd = 0; imd < geom->getNumberOfModules(ilr); imd++) { + addVolume(volMod = new AlignableVolume(geom->composeSymNameModule(ilr, ihb, ist, ihst, imd), getNonSensLabel(nonSensCnt++), mController)); + sym2vol[volMod->getSymName()] = volMod; + volMod->setParent(volHSt); + } // module + } //halfstave + } // stave + } // halfBarrel + } // layer + + for (int ich = 0; ich < geom->getNumberOfChips(); ich++) { + int chID = o2::base::GeometryManager::getSensID(mDetID, ich); + if (ich != chID) { + throw std::runtime_error(fmt::format("mismatch between counter {} and composed {} chip IDs", ich, chID)); + } + addVolume(sens = new AlignableSensorITS(o2::base::GeometryManager::getSymbolicName(mDetID, ich), chID, getSensLabel(chID), mController)); + int lay = 0, hba, sta = 0, ssta = 0, modd = 0, chip = 0; + geom->getChipId(chID, lay, hba, sta, ssta, modd, chip); + AlignableVolume* parVol = sym2vol[modd < 0 ? geom->composeSymNameStave(lay, hba, sta) : geom->composeSymNameModule(lay, hba, sta, ssta, modd)]; + if (!parVol) { + throw std::runtime_error(fmt::format("did not find parent for chip {}", chID)); + } + sens->setParent(parVol); + } + // +} + +//____________________________________________ +void AlignableDetectorITS::Print(const Option_t* opt) const +{ + AlignableDetector::Print(opt); + printf("Sel.pattern Collisions: %7s | Cosmic: %7s\n", + GetITSPattName(fITSPatt[Coll]), GetITSPattName(fITSPatt[Cosm])); +} + +/* +// RSTODO +//____________________________________________ +bool AlignableDetectorITS::AcceptTrack(const AliESDtrack* trc, int trtype) const +{ + // test if detector had seed this track + if (!CheckFlags(trc, trtype)) + return false; + if (trc->GetNcls(0) < mNPointsSel[trtype]) + return false; + if (!CheckHitPattern(trc, GetITSSelPattern(trtype))) + return false; + // + return true; +} +*/ + +//____________________________________________ +void AlignableDetectorITS::SetAddErrorLr(int ilr, double sigY, double sigZ) +{ + // set syst. errors for specific layer + auto geom = o2::its::GeometryTGeo::Instance(); + int chMin = geom->getFirstChipIndex(ilr), chMax = geom->getLastChipIndex(ilr); + for (int isn = chMin; isn <= chMax; isn++) { + getSensor(isn)->setAddError(sigY, sigZ); + } +} + +//____________________________________________ +void AlignableDetectorITS::SetSkipLr(int ilr) +{ + // exclude sensor of the layer from alignment + auto geom = o2::its::GeometryTGeo::Instance(); + int chMin = geom->getFirstChipIndex(ilr), chMax = geom->getLastChipIndex(ilr); + for (int isn = chMin; isn <= chMax; isn++) { + getSensor(isn)->setSkip(); + } +} + +//_________________________________________________ +void AlignableDetectorITS::setUseErrorParam(int v) +{ + // set type of points error parameterization + mUseErrorParam = v; +} + +//_________________________________________________ +void AlignableDetectorITS::updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const +{ + // update point using specific error parameterization + // the track must be in the detector tracking frame + //TODO RS + /* + const AlignableSensor* sens = pnt->getSensor(); + int vid = sens->getVolID(); + double angPol = ATan(t.getTgl()); + double angAz = ASin(t.getSnp()); + double errY, errZ; + GetErrorParamAngle(lr, angPol, angAz, errY, errZ); + const double* sysE = sens->getAddError(); // additional syst error + // + pnt->setYZErrTracking(errY * errY + sysE[0] * sysE[0], 0, errZ * errZ + sysE[1] * sysE[1]); + pnt->init(); + */ + // +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableDetectorTOF.cxx b/Detectors/Align/src/AlignableDetectorTOF.cxx new file mode 100644 index 0000000000000..6dc79c7bd685f --- /dev/null +++ b/Detectors/Align/src/AlignableDetectorTOF.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTOF.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Wrapper for TOF detector + +#include "Align/AlignableDetectorTOF.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableSensorTOF.h" +#include "Align/Controller.h" +//#include "AliGeomManager.h" +//#include "AliTOFGeometry.h" +//#include "AliESDtrack.h" +#include <TGeoManager.h> + +ClassImp(o2::align::AlignableDetectorTOF); + +namespace o2 +{ +namespace align +{ + +//____________________________________________ +AlignableDetectorTOF::AlignableDetectorTOF(const char* title) +{ + // default c-tor + SetNameTitle(Controller::getDetNameByDetID(Controller::kTOF), title); + setDetID(Controller::kTOF); +} + +//____________________________________________ +AlignableDetectorTOF::~AlignableDetectorTOF() +{ + // d-tor +} + +//____________________________________________ +void AlignableDetectorTOF::defineVolumes() +{ + // define TOF volumes + // + const int kNSect = 18, kNStrips = AliTOFGeometry::NStripA() + 2 * AliTOFGeometry::NStripB() + 2 * AliTOFGeometry::NStripC(); + int labDet = getDetLabel(); + AlignableSensorTOF* strip = 0; + // + // AddVolume( volTOF = new AlignableVolume("TOF") ); // no main volume, why? + AlignableVolume* sect[kNSect] = {0}; + // + for (int isc = 0; isc < kNSect; isc++) { + int iid = labDet + (1 + isc) * 100; + addVolume(sect[isc] = new AlignableVolume(Form("TOF/sm%02d", isc), iid)); + } + // + int cnt = 0; + for (int isc = 0; isc < kNSect; isc++) { + for (int istr = 1; istr <= kNStrips; istr++) { // strip + int iid = labDet + (1 + isc) * 100 + (1 + istr); + int vid = AliGeomManager::LayerToVolUID(AliGeomManager::kTOF, cnt++); + const char* symname = Form("TOF/sm%02d/strip%02d", isc, istr); + if (!gGeoManager->GetAlignableEntry(symname)) + continue; + addVolume(strip = new AlignableSensorTOF(symname, vid, iid, isc)); + strip->setParent(sect[isc]); + } // strip + } // layer + // +} + +//____________________________________________ +bool AlignableDetectorTOF::AcceptTrack(const AliESDtrack* trc, int trtype) const +{ + // test if detector had seed this track + return CheckFlags(trc, trtype); +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableDetectorTPC.cxx b/Detectors/Align/src/AlignableDetectorTPC.cxx new file mode 100644 index 0000000000000..63fac7dd9cac6 --- /dev/null +++ b/Detectors/Align/src/AlignableDetectorTPC.cxx @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTPC.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TPC detector wrapper + +#include "Align/AlignableDetectorTPC.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableSensorTPC.h" +#include "Align/Controller.h" +//#include "AliGeomManager.h" +//#include "AliESDtrack.h" +#include "Framework/Logger.h" +#include <TGeoManager.h> + +ClassImp(o2::align::AlignableDetectorTPC); + +namespace o2 +{ +namespace align +{ + +//____________________________________________ +AlignableDetectorTPC::AlignableDetectorTPC(const char* title) +{ + // default c-tor + SetNameTitle(Controller::getDetNameByDetID(Controller::kTPC), title); + setDetID(Controller::kTPC); +} + +//____________________________________________ +AlignableDetectorTPC::~AlignableDetectorTPC() +{ + // d-tor +} + +//____________________________________________ +void AlignableDetectorTPC::defineVolumes() +{ + // define TPC volumes + // + const int kNSect = 18, kAC = 2, kIOROC = 2; + const char* kSide[kAC] = {"A", "C"}; + const char* kROC[kIOROC] = {"Inner", "Outer"}; + // AlignableSensorTPC *chamb=0; + // + int labDet = getDetLabel(); + AlignableVolume* volTPC = new AlignableVolume("ALIC_1/TPC_M_1", labDet); + addVolume(volTPC); + // + + for (int roc = 0; roc < kIOROC; roc++) { // inner/outer + for (int side = 0; side < kAC; side++) { // A/C + for (int isc = 0; isc < kNSect; isc++) { // sector ID + const char* symname = Form("TPC/Endcap%s/Sector%d/%sChamber", kSide[side], isc + 1, kROC[roc]); + if (!gGeoManager->GetAlignableEntry(symname)) { + AliErrorF("Did not find alignable %s", symname); + continue; + } + int iid = side * kNSect + isc; + uint16_t vid = AliGeomManager::LayerToVolUID(AliGeomManager::kTPC1 + roc, iid); + iid = labDet + (1 + side) * 10000 + (1 + isc) * 100 + (1 + roc); + AlignableSensorTPC* sens = new AlignableSensorTPC(symname, vid, iid, isc); + sens->setParent(volTPC); + addVolume(sens); + } // sector ID + } // A/C + } // inner/outer + // +} + +//____________________________________________ +bool AlignableDetectorTPC::AcceptTrack(const AliESDtrack* trc, int trtype) const +{ + // test if detector had seed this track + if (!CheckFlags(trc, trtype)) + return false; + if (trc->GetNcls(1) < mNPointsSel[trtype]) + return false; + return true; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableDetectorTRD.cxx b/Detectors/Align/src/AlignableDetectorTRD.cxx new file mode 100644 index 0000000000000..3b7a2177e0e60 --- /dev/null +++ b/Detectors/Align/src/AlignableDetectorTRD.cxx @@ -0,0 +1,172 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableDetectorTRD.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TRD detector wrapper + +#include "Align/AlignableDetectorTRD.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableSensorTRD.h" +#include "Align/Controller.h" +//#include "AliGeomManager.h" +//#include "AliESDtrack.h" +//#include "AliTRDgeometry.h" +#include <TGeoManager.h> +#include <TMath.h> + +using namespace TMath; + +ClassImp(o2::align::AlignableDetectorTRD); + +namespace o2 +{ +namespace align +{ + +const char* AlignableDetectorTRD::fgkCalibDOFName[AlignableDetectorTRD::kNCalibParams] = {"DZdTglNRC", "DVDriftT"}; + +//____________________________________________ +AlignableDetectorTRD::AlignableDetectorTRD(const char* title) + : AlignableDetector(), fNonRCCorrDzDtgl(0), fCorrDVT(0) +{ + // default c-tor + SetNameTitle(Controller::getDetNameByDetID(Controller::kTRD), title); + setDetID(Controller::kTRD); + fExtraErrRC[0] = fExtraErrRC[1] = 0; + // + // ad hoc correction + SetNonRCCorrDzDtgl(); + SetExtraErrRC(); + mNCalibDOFs = kNCalibParams; +} + +//____________________________________________ +AlignableDetectorTRD::~AlignableDetectorTRD() +{ + // d-tor +} + +//____________________________________________ +void AlignableDetectorTRD::defineVolumes() +{ + // define TRD volumes + // + const int kNSect = 18, kNStacks = 5, kNLayers = 6; + AlignableSensorTRD* chamb = 0; + // + int labDet = getDetLabel(); + // AddVolume( volTRD = new AlignableVolume("TRD") ); // no main volume, why? + AlignableVolume* sect[kNSect] = {0}; + // + for (int ilr = 0; ilr < kNLayers; ilr++) { // layer + for (int ich = 0; ich < kNStacks * kNSect; ich++) { // chamber + int isector = ich / AliTRDgeometry::Nstack(); + int istack = ich % AliTRDgeometry::Nstack(); + //int lid = AliTRDgeometry::GetDetector(ilr,istack,isector); + int iid = labDet + (1 + ilr) * 10000 + (1 + isector) * 100 + (1 + istack); + const char* symname = Form("TRD/sm%02d/st%d/pl%d", isector, istack, ilr); + if (!gGeoManager->GetAlignableEntry(symname)) + continue; + uint16_t vid = AliGeomManager::LayerToVolUID(AliGeomManager::kTRD1 + ilr, ich); + addVolume(chamb = new AlignableSensorTRD(symname, vid, iid /*lid*/, isector)); + iid = labDet + (1 + isector) * 100; + if (!sect[isector]) + sect[isector] = new AlignableVolume(Form("TRD/sm%02d", isector), iid); + chamb->setParent(sect[isector]); + } // chamber + } // layer + // + for (int isc = 0; isc < kNSect; isc++) { + if (sect[isc]) + addVolume(sect[isc]); + } + // +} + +//____________________________________________ +bool AlignableDetectorTRD::AcceptTrack(const AliESDtrack* trc, int trtype) const +{ + // test if detector had seed this track + if (!CheckFlags(trc, trtype)) + return false; + if (trc->GetTRDntracklets() < mNPointsSel[trtype]) + return false; + return true; +} + +//__________________________________________ +//____________________________________________ +void AlignableDetectorTRD::Print(const Option_t* opt) const +{ + // print info + AlignableDetector::Print(opt); + printf("Extra error for RC tracklets: Y:%e Z:%e\n", fExtraErrRC[0], fExtraErrRC[1]); +} + +const char* AlignableDetectorTRD::getCalibDOFName(int i) const +{ + // return calibration DOF name + return i < kNCalibParams ? fgkCalibDOFName[i] : 0; +} + +//______________________________________________________ +void AlignableDetectorTRD::writePedeInfo(FILE* parOut, const Option_t* opt) const +{ + // contribute to params and constraints template files for PEDE + AlignableDetector::writePedeInfo(parOut, opt); + // + // write calibration parameters + enum { kOff, + kOn, + kOnOn }; + const char* comment[3] = {" ", "! ", "!!"}; + const char* kKeyParam = "parameter"; + // + fprintf(parOut, "%s%s %s\t %d calibraction params for %s\n", comment[kOff], kKeyParam, comment[kOnOn], + getNCalibDOFs(), GetName()); + // + for (int ip = 0; ip < getNCalibDOFs(); ip++) { + int cmt = isCondDOF(ip) ? kOff : kOn; + fprintf(parOut, "%s %9d %+e %+e\t%s %s p%d\n", comment[cmt], getParLab(ip), + getParVal(ip), getParErr(ip), comment[kOnOn], isFreeDOF(ip) ? " " : "FX", ip); + } + // +} + +//_______________________________________________________ +double AlignableDetectorTRD::getCalibDOFVal(int id) const +{ + // return preset value of calibration dof + double val = 0; + switch (id) { + case kCalibNRCCorrDzDtgl: + val = GetNonRCCorrDzDtgl(); + break; + case kCalibDVT: + val = GetCorrDVT(); + break; + default: + break; + }; + return val; +} + +//_______________________________________________________ +double AlignableDetectorTRD::getCalibDOFValWithCal(int id) const +{ + // return preset value of calibration dof + mp correction + return getCalibDOFVal(id) + getParVal(id); +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensor.cxx b/Detectors/Align/src/AlignableSensor.cxx new file mode 100644 index 0000000000000..3bf7de91ad440 --- /dev/null +++ b/Detectors/Align/src/AlignableSensor.cxx @@ -0,0 +1,523 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensor.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief End-chain alignment volume in detector branch, where the actual measurement is done. + +#include <cstdio> +#include <TClonesArray.h> + +#include "Align/AlignableSensor.h" +#include "Framework/Logger.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" +#include "DetectorsBase/GeometryManager.h" + +ClassImp(o2::align::AlignableSensor); + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensor::AlignableSensor(const char* name, int vid, int iid, Controller* ctr) + : AlignableVolume(name, iid, ctr), mSID(0), mDet(nullptr), mMatClAlg(), mMatClAlgReco() +{ + // def c-tor + setVolID(vid); + mAddError[0] = mAddError[1] = 0; + mConstrChild = 0; // sensors don't have children +} + +//_________________________________________________________ +void AlignableSensor::dPosTraDParGeomLOC(const AlignmentPoint* pnt, double* deriv) const +{ + // Jacobian of position in sensor tracking frame (tra) vs sensor LOCAL frame + // parameters in TGeoHMatrix convention. + // Result is stored in array deriv as linearized matrix 6x3 + const double kDelta[kNDOFGeom] = {0.1, 0.1, 0.1, 0.5, 0.5, 0.5}; + double delta[kNDOFGeom], pos0[3], pos1[3], pos2[3], pos3[3]; + TGeoHMatrix matMod; + // + memset(delta, 0, kNDOFGeom * sizeof(double)); + memset(deriv, 0, kNDOFGeom * 3 * sizeof(double)); + const double* tra = pnt->getXYZTracking(); + // + for (int ip = kNDOFGeom; ip--;) { + // + if (!isFreeDOF(ip)) { + continue; + } + // + double var = kDelta[ip]; + delta[ip] -= var; + // variation matrix in tracking frame for variation in sensor LOCAL frame + getDeltaT2LmodLOC(matMod, delta); + matMod.LocalToMaster(tra, pos0); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodLOC(matMod, delta); + matMod.LocalToMaster(tra, pos1); // varied position in tracking frame + // + delta[ip] += var; + getDeltaT2LmodLOC(matMod, delta); + matMod.LocalToMaster(tra, pos2); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodLOC(matMod, delta); + matMod.LocalToMaster(tra, pos3); // varied position in tracking frame + // + delta[ip] = 0; + double* curd = deriv + ip * 3; + for (int i = 3; i--;) { + curd[i] = (8. * (pos2[i] - pos1[i]) - (pos3[i] - pos0[i])) / 6. / var; + } + } + // +} + +//_________________________________________________________ +void AlignableSensor::dPosTraDParGeomLOC(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent) const +{ + // Jacobian of position in sensor tracking frame (tra) vs parent volume LOCAL frame parameters. + // NO check of parentship is done! + // Result is stored in array deriv as linearized matrix 6x3 + const double kDelta[kNDOFGeom] = {0.1, 0.1, 0.1, 0.5, 0.5, 0.5}; + double delta[kNDOFGeom], pos0[3], pos1[3], pos2[3], pos3[3]; + TGeoHMatrix matMod; + // this is the matrix for transition from sensor to parent volume local frames: LOC=matRel*loc + TGeoHMatrix matRel = parent->getMatrixL2GIdeal().Inverse(); + matRel *= getMatrixL2GIdeal(); + // + memset(delta, 0, kNDOFGeom * sizeof(double)); + memset(deriv, 0, kNDOFGeom * 3 * sizeof(double)); + const double* tra = pnt->getXYZTracking(); + // + for (int ip = kNDOFGeom; ip--;) { + // + if (!isFreeDOF(ip)) { + continue; + } + // + double var = kDelta[ip]; + delta[ip] -= var; + getDeltaT2LmodLOC(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos0); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodLOC(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos1); // varied position in tracking frame + // + delta[ip] += var; + getDeltaT2LmodLOC(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos2); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodLOC(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos3); // varied position in tracking frame + // + delta[ip] = 0; + double* curd = deriv + ip * 3; + for (int i = 3; i--;) { + curd[i] = (8. * (pos2[i] - pos1[i]) - (pos3[i] - pos0[i])) / 6. / var; + } + } + // +} + +//_________________________________________________________ +void AlignableSensor::dPosTraDParGeomTRA(const AlignmentPoint* pnt, double* deriv) const +{ + // Jacobian of position in sensor tracking frame (tra) vs sensor TRACKING + // frame parameters in TGeoHMatrix convention, i.e. the modified parameter is + // tra' = tau*tra + // + // Result is stored in array deriv as linearized matrix 6x3 + const double kDelta[kNDOFGeom] = {0.1, 0.1, 0.1, 0.5, 0.5, 0.5}; + double delta[kNDOFGeom], pos0[3], pos1[3], pos2[3], pos3[3]; + TGeoHMatrix matMod; + // + memset(delta, 0, kNDOFGeom * sizeof(double)); + memset(deriv, 0, kNDOFGeom * 3 * sizeof(double)); + const double* tra = pnt->getXYZTracking(); + // + for (int ip = kNDOFGeom; ip--;) { + // + if (!isFreeDOF(ip)) { + continue; + } + // + double var = kDelta[ip]; + delta[ip] -= var; + getDeltaT2LmodTRA(matMod, delta); + matMod.LocalToMaster(tra, pos0); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodTRA(matMod, delta); + matMod.LocalToMaster(tra, pos1); // varied position in tracking frame + // + delta[ip] += var; + getDeltaT2LmodTRA(matMod, delta); + matMod.LocalToMaster(tra, pos2); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodTRA(matMod, delta); + matMod.LocalToMaster(tra, pos3); // varied position in tracking frame + // + delta[ip] = 0; + double* curd = deriv + ip * 3; + for (int i = 3; i--;) { + curd[i] = (8. * (pos2[i] - pos1[i]) - (pos3[i] - pos0[i])) / 6. / var; + } + } + // +} + +//_________________________________________________________ +void AlignableSensor::dPosTraDParGeomTRA(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent) const +{ + // Jacobian of position in sensor tracking frame (tra) vs sensor TRACKING + // frame parameters in TGeoHMatrix convention, i.e. the modified parameter is + // tra' = tau*tra + // + // Result is stored in array deriv as linearized matrix 6x3 + const double kDelta[kNDOFGeom] = {0.1, 0.1, 0.1, 0.5, 0.5, 0.5}; + double delta[kNDOFGeom], pos0[3], pos1[3], pos2[3], pos3[3]; + TGeoHMatrix matMod; + // + // 1st we need a matrix for transition between child and parent TRACKING frames + // Let TRA,LOC are positions in tracking and local frame of parent, linked as LOC=T2L*TRA + // and tra,loc are positions in tracking and local frame of child, linked as loc=t2l*tra + // The loc and LOC are linked as LOC=R*loc, where R = L2G^-1*l2g, with L2G and l2g + // local2global matrices for parent and child + // + // Then, TRA = T2L^-1*LOC = T2L^-1*R*loc = T2L^-1*R*t2l*tra + // -> TRA = matRel*tra, with matRel = T2L^-1*L2G^-1 * l2g*t2l + // Note that l2g*t2l are tracking to global matrices + TGeoHMatrix matRel, t2gP; + getMatrixT2G(matRel); // t2g matrix of child + parent->getMatrixT2G(t2gP); // t2g matrix of parent + const TGeoHMatrix& t2gpi = t2gP.Inverse(); + matRel.MultiplyLeft(&t2gpi); + // + memset(delta, 0, kNDOFGeom * sizeof(double)); + memset(deriv, 0, kNDOFGeom * 3 * sizeof(double)); + const double* tra = pnt->getXYZTracking(); + // + for (int ip = kNDOFGeom; ip--;) { + // + if (!isFreeDOF(ip)) { + continue; + } + // + double var = kDelta[ip]; + delta[ip] -= var; + getDeltaT2LmodTRA(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos0); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodTRA(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos1); // varied position in tracking frame + // + delta[ip] += var; + getDeltaT2LmodTRA(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos2); // varied position in tracking frame + // + delta[ip] += 0.5 * var; + getDeltaT2LmodTRA(matMod, delta, matRel); + matMod.LocalToMaster(tra, pos3); // varied position in tracking frame + // + delta[ip] = 0; + double* curd = deriv + ip * 3; + for (int i = 3; i--;) { + curd[i] = (8. * (pos2[i] - pos1[i]) - (pos3[i] - pos0[i])) / 6. / var; + } + } + // +} + +//_________________________________________________________ +void AlignableSensor::dPosTraDParGeom(const AlignmentPoint* pnt, double* deriv, const AlignableVolume* parent) const +{ + // calculate point position derivatives in tracking frame of sensor + // vs standard geometrical DOFs of its parent volume (if parent!=0) or sensor itself + Frame_t frame = parent ? parent->getVarFrame() : getVarFrame(); + switch (frame) { + case kLOC: + parent ? dPosTraDParGeomLOC(pnt, deriv, parent) : dPosTraDParGeomLOC(pnt, deriv); + break; + case kTRA: + parent ? dPosTraDParGeomTRA(pnt, deriv, parent) : dPosTraDParGeomTRA(pnt, deriv); + break; + default: + LOG(ERROR) << "Alignment frame " << parent->getVarFrame() << " is not implemented"; + break; + } +} + +//__________________________________________________________________ +void AlignableSensor::getModifiedMatrixT2LmodLOC(TGeoHMatrix& matMod, const double* delta) const +{ + // prepare the sensitive module tracking2local matrix from its current T2L matrix + // by applying local delta of modification of LOCAL frame: + // loc' = delta*loc = T2L'*tra = T2L'*T2L^-1*loc -> T2L' = delta*T2L + delta2Matrix(matMod, delta); + matMod.Multiply(&getMatrixT2L()); +} + +//__________________________________________________________________ +void AlignableSensor::getModifiedMatrixT2LmodTRA(TGeoHMatrix& matMod, const double* delta) const +{ + // prepare the sensitive module tracking2local matrix from its current T2L matrix + // by applying local delta of modification of TRACKING frame: + // loc' = T2L'*tra = T2L*delta*tra -> T2L' = T2L*delta + delta2Matrix(matMod, delta); + matMod.MultiplyLeft(&getMatrixT2L()); +} + +//__________________________________________________________________ +void AlignableSensor::addChild(AlignableVolume*) +{ + LOG(FATAL) << "Sensor volume cannot have children: id=" << getVolID() << " " << GetName(); +} + +//__________________________________________________________________ +int AlignableSensor::Compare(const TObject* b) const +{ + // compare VolIDs + return GetUniqueID() < b->GetUniqueID() ? -1 : 1; +} + +//__________________________________________________________________ +void AlignableSensor::setTrackingFrame() +{ + // define tracking frame of the sensor + // AliWarningF("Generic method called for %s",getSymName()); + double tra[3] = {0}, glo[3]; + TGeoHMatrix t2g; + getMatrixT2G(t2g); + t2g.LocalToMaster(tra, glo); + mX = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + mAlp = ATan2(glo[1], glo[0]); + utils::bringToPiPM(mAlp); + // +} + +//____________________________________________ +void AlignableSensor::Print(const Option_t* opt) const +{ + // print info + TString opts = opt; + opts.ToLower(); + printf("Lev:%2d IntID:%7d %s VId:%6d X:%8.4f Alp:%+.4f | Err: %.4e %.4e | Used Points: %d\n", + countParents(), getInternalID(), getSymName(), getVolID(), mX, mAlp, + mAddError[0], mAddError[1], mNProcPoints); + printf(" DOFs: Tot: %d (offs: %5d) Free: %d Geom: %d {", mNDOFs, mFirstParGloID, mNDOFsFree, mNDOFGeomFree); + for (int i = 0; i < kNDOFGeom; i++) { + printf("%d", isFreeDOF(i) ? 1 : 0); + } + printf("} in %s frame\n", sFrameName[mVarFrame]); + // + // + // + if (opts.Contains("par") && mFirstParGloID >= 0) { + printf(" Lb: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%10d ", getParLab(i)); + } + printf("\n"); + printf(" Vl: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%+9.3e ", getParVal(i)); + } + printf("\n"); + printf(" Er: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%+9.3e ", getParErr(i)); + } + printf("\n"); + } + // + if (opts.Contains("mat")) { // print matrices + printf("L2G ideal : "); + getMatrixL2GIdeal().Print(); + printf("L2G misalign: "); + getMatrixL2G().Print(); + printf("L2G RecoTime: "); + getMatrixL2GReco().Print(); + printf("T2L : "); + getMatrixT2L().Print(); + printf("ClAlg : "); + getMatrixClAlg().Print(); + printf("ClAlgReco: "); + getMatrixClAlgReco().Print(); + } + // +} + +//____________________________________________ +void AlignableSensor::prepareMatrixT2L() +{ + // extract geometry T2L matrix + TGeoHMatrix t2l; + t2l.Clear(); + t2l.RotateZ(mAlp * RadToDeg()); // rotate in direction of normal to the sensor plane + const TGeoHMatrix* matL2G = base::GeometryManager::getMatrix(mDet->getDetID(), getSID()); + const TGeoHMatrix& matL2Gi = matL2G->Inverse(); + t2l.MultiplyLeft(&matL2Gi); + setMatrixT2L(t2l); + + // const TGeoHMatrix* t2l = AliGeomManager::GetTracking2LocalMatrix(getVolID()); + // const if (!t2l) + // { + // Print("long"); + // LOG(FATAL) << "Failed to find T2L matrix for VID: " << getVolID() << ", " << getSymName(); + // } + // setMatrixT2L(*t2l); + // // +} + +//____________________________________________ +void AlignableSensor::prepareMatrixClAlg() +{ + // prepare alignment matrix in the LOCAL frame: delta = Gideal^-1 * G + TGeoHMatrix ma = getMatrixL2GIdeal().Inverse(); + ma *= getMatrixL2G(); + setMatrixClAlg(ma); + // +} + +//____________________________________________ +void AlignableSensor::prepareMatrixClAlgReco() +{ + // prepare alignment matrix used at reco time + TGeoHMatrix ma = getMatrixL2GIdeal().Inverse(); + ma *= getMatrixL2GReco(); + setMatrixClAlgReco(ma); + // +} + +//____________________________________________ +void AlignableSensor::updatePointByTrackInfo(AlignmentPoint* pnt, const trackParam_t* t) const +{ + // update + mDet->updatePointByTrackInfo(pnt, t); +} + +//____________________________________________ +void AlignableSensor::dPosTraDParCalib(const AlignmentPoint* pnt, double* deriv, int calibID, const AlignableVolume* parent) const +{ + // calculate point position X,Y,Z derivatives wrt calibration parameter calibID of given parent + // parent=0 means top detector object calibration + // + deriv[0] = deriv[1] = deriv[2] = 0; +} + +//______________________________________________________ +int AlignableSensor::finalizeStat(DOFStatistics& st) +{ + // finalize statistics on processed points + fillDOFStat(st); + return mNProcPoints; +} + +//_________________________________________________________________ +void AlignableSensor::updateL2GRecoMatrices(const TClonesArray* algArr, const TGeoHMatrix* cumulDelta) +{ + // recreate mMatL2GReco matrices from ideal L2G matrix and alignment objects + // used during data reconstruction. + // On top of what each volume does, also update misalignment matrix inverse + // + AlignableVolume::updateL2GRecoMatrices(algArr, cumulDelta); + prepareMatrixClAlgReco(); + // +} + +/* +//_________________________________________________________________ +AlignmentPoint* AlignableSensor::TrackPoint2AlgPoint(int, const AliTrackPointArray*, const AliESDtrack*) +{ + // dummy converter + AliError("Generic method, must be implemented in specific sensor"); + return 0; +} +*/ + +//_________________________________________________________________ +void AlignableSensor::applyAlignmentFromMPSol() +{ + // apply to the tracking coordinates in the sensor frame the full chain + // of alignments found by MP for this sensor and its parents + // + const AlignableVolume* vol = this; + TGeoHMatrix deltaG; + // create global combined delta: + // DeltaG = deltaG_0*...*deltaG_j, where delta_i is global delta of each member of hierarchy + while (vol) { + TGeoHMatrix deltaGJ; + vol->createAlignmenMatrix(deltaGJ); + deltaG.MultiplyLeft(&deltaGJ); + vol = vol->getParent(); + } + // + // update misaligned L2G matrix + deltaG *= getMatrixL2GIdeal(); + setMatrixL2G(deltaG); + // + // update local misalignment matrix + prepareMatrixClAlg(); + // +} +/* +//_________________________________________________________________ +void AlignableSensor::applyAlignmentFromMPSol() +{ + // apply to the tracking coordinates in the sensor frame the full chain + // of alignments found by MP for this sensor and its parents + double delta[kNDOFGeom]={0}; + // + TGeoHMatrix matMod; + // + // sensor proper variation + getParValGeom(delta); + isFrameTRA() ? getDeltaT2LmodTRA(matMod,delta) : getDeltaT2LmodLOC(matMod,delta); + mMatClAlg.MultiplyLeft(&matMod); + // + AlignableVolume* parent = this; + while ((parent==parent->getParent())) { + // this is the matrix for transition from sensor to parent volume frame + parent->getParValGeom(delta); + TGeoHMatrix matRel,t2gP; + if (parent->isFrameTRA()) { + getMatrixT2G(matRel); // t2g matrix of child + parent->getMatrixT2G(t2gP); // t2g matrix of parent + matRel.MultiplyLeft(&t2gP.Inverse()); + getDeltaT2LmodTRA(matMod, delta, matRel); + } + else { + matRel = parent->getMatrixL2GIdeal().Inverse(); + matRel *= getMatrixL2GIdeal(); + getDeltaT2LmodLOC(matMod, delta, matRel); + } + mMatClAlg.MultiplyLeft(&matMod); + } + // +} +*/ + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensorHMPID.cxx b/Detectors/Align/src/AlignableSensorHMPID.cxx new file mode 100644 index 0000000000000..bdeb9dbe687f4 --- /dev/null +++ b/Detectors/Align/src/AlignableSensorHMPID.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorHMPID.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief HMPID sensor (chamber) + +#include "Align/AlignableSensorHMPID.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +//#include "AliTrackPointArray.h" +//#include "AliESDtrack.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" + +ClassImp(o2::align::AlignableSensorHMPID); + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensorHMPID::AlignableSensorHMPID(const char* name, int vid, int iid, int isec) + : AlignableSensor(name, vid, iid) +{ + // def c-tor +} + +//_________________________________________________________ +AlignableSensorHMPID::~AlignableSensorHMPID() +{ + // d-tor +} +/* +//__________________________________________________________________ +void AlignableSensorHMPID::setTrackingFrame() +{ + // define tracking frame of the sensor: just rotation by sector angle + fAlp = sector2Alpha(fSector); + fX = 0; +} +*/ + +//____________________________________________ +void AlignableSensorHMPID::prepareMatrixT2L() +{ + // creat T2L matrix + double loc[3] = {0, 0, 0}, glo[3]; + getMatrixL2GIdeal().LocalToMaster(loc, glo); + double alp = ATan2(glo[1], glo[0]); + double x = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + TGeoHMatrix t2l; + t2l.SetDx(x); + t2l.RotateZ(alp * RadToDeg()); + const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse(); + t2l.MultiplyLeft(&l2gi); + /* + const TGeoHMatrix* t2l = AliGeomManager::GetTracking2LocalMatrix(getVolID()); + if (!t2l) { + Print("long"); + AliFatalF("Failed to find T2L matrix for VID:%d %s",getVolID(),getSymName()); + } + */ + setMatrixT2L(t2l); + // +} + +//____________________________________________ +AlignmentPoint* AlignableSensorHMPID::TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack*) +{ + // convert the pntId-th point to AlignmentPoint + // + AlignableDetector* det = getDetector(); + AlignmentPoint* pnt = det->getPointFromPool(); + pnt->setSensor(this); + // + double tra[3], locId[3], loc[3], + glo[3] = {trpArr->GetX()[pntId], trpArr->GetY()[pntId], trpArr->GetZ()[pntId]}; + const TGeoHMatrix& matL2Grec = getMatrixL2GReco(); // local to global matrix used for reconstruction + const TGeoHMatrix& matT2L = getMatrixT2L(); // matrix for tracking to local frame translation + // + // undo reco-time alignment + matL2Grec.MasterToLocal(glo, locId); // go to local frame using reco-time matrix, here we recover ideal measurement + // + getMatrixClAlg().LocalToMaster(locId, loc); // apply alignment + // + matT2L.MasterToLocal(loc, tra); // go to tracking frame + // + /* + double gloT[3]; + TGeoHMatrix t2g; + getMatrixT2G(t2g); t2g.LocalToMaster(tra,gloT); + printf("\n%5d %s\n",getVolID(), getSymName()); + printf("GloOR: %+.4e %+.4e %+.4e\n",glo[0],glo[1],glo[2]); + printf("LocID: %+.4e %+.4e %+.4e\n",locId[0],locId[1],locId[2]); + printf("LocML: %+.4e %+.4e %+.4e\n",loc[0],loc[1],loc[2]); + printf("Tra : %+.4e %+.4e %+.4e\n",tra[0],tra[1],tra[2]); + printf("GloTR: %+.4e %+.4e %+.4e\n",gloT[0],gloT[1],gloT[2]); + */ + // + if (!det->getUseErrorParam()) { + // convert error + TGeoHMatrix hcov; + double hcovel[9]; + const float* pntcov = trpArr->GetCov() + pntId * 6; // 6 elements per error matrix + hcovel[0] = double(pntcov[0]); + hcovel[1] = double(pntcov[1]); + hcovel[2] = double(pntcov[2]); + hcovel[3] = double(pntcov[1]); + hcovel[4] = double(pntcov[3]); + hcovel[5] = double(pntcov[4]); + hcovel[6] = double(pntcov[2]); + hcovel[7] = double(pntcov[4]); + hcovel[8] = double(pntcov[5]); + hcov.SetRotation(hcovel); + hcov.Multiply(&matL2Grec); + const TGeoHMatrix& l2gi = matL2Grec.Inverse(); + hcov.MultiplyLeft(&l2gi); // errors in local frame + hcov.Multiply(&matT2L); + const TGeoHMatrix& t2li = matT2L.Inverse(); + hcov.MultiplyLeft(&t2li); // errors in tracking frame + // + double* hcovscl = hcov.GetRotationMatrix(); + const double* sysE = getAddError(); // additional syst error + pnt->setYZErrTracking(hcovscl[4] + sysE[0] * sysE[0], hcovscl[5], hcovscl[8] + sysE[1] * sysE[1]); + } else { // errors will be calculated just before using the point in the fit, using track info + pnt->setYZErrTracking(0, 0, 0); + pnt->setNeedUpdateFromTrack(); + } + pnt->setXYZTracking(tra[0], tra[1], tra[2]); + pnt->setAlphaSens(getAlpTracking()); + pnt->setXSens(getXTracking()); + pnt->setDetID(det->getDetID()); + pnt->setSID(getSID()); + // + pnt->setContainsMeasurement(); + // + pnt->init(); + // + return pnt; + // +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensorITS.cxx b/Detectors/Align/src/AlignableSensorITS.cxx new file mode 100644 index 0000000000000..2ea5b1daa23e7 --- /dev/null +++ b/Detectors/Align/src/AlignableSensorITS.cxx @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorITS.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief ITS sensor + +#include "Align/AlignableSensorITS.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +//#include "AliTrackPointArray.h" +//#include "AliESDtrack.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" + +ClassImp(o2::align::AlignableSensorITS); + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensorITS::AlignableSensorITS(const char* name, int vid, int iid, Controller* ctr) + : AlignableSensor(name, vid, iid, ctr) +{ + // def c-tor +} + +//________________________________________________________________ +void AlignableSensorITS::setTrackingFrame() +{ + // define tracking frame of the sensor + double tra[3]={0},loc[3],glo[3]; + // ITS defines tracking frame with origin in sensor, others at 0 + getMatrixT2L().LocalToMaster(tra,loc); + getMatrixL2GIdeal().LocalToMaster(loc,glo); + mX = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + mAlp = ATan2(glo[1], glo[0]); + utils::bringToPiPM(mAlp); +} + +/* +//____________________________________________ +AlignmentPoint* AlignableSensorITS::TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack*) +{ + // convert the pntId-th point to AlignmentPoint + // + AlignableDetector* det = getDetector(); + AlignmentPoint* pnt = det->getPointFromPool(); + pnt->setSensor(this); + // + double tra[3], locId[3], loc[3], + glo[3] = {trpArr->GetX()[pntId], trpArr->GetY()[pntId], trpArr->GetZ()[pntId]}; + const TGeoHMatrix& matL2Grec = getMatrixL2GReco(); // local to global matrix used for reconstruction + const TGeoHMatrix& matT2L = getMatrixT2L(); // matrix for tracking to local frame translation + // + // undo reco-time alignment + matL2Grec.MasterToLocal(glo, locId); // go to local frame using reco-time matrix, here we recover ideal measurement + // + getMatrixClAlg().LocalToMaster(locId, loc); // apply alignment + // + matT2L.MasterToLocal(loc, tra); // go to tracking frame + // + // + if (!det->getUseErrorParam()) { + // convert error + TGeoHMatrix hcov; + double hcovel[9]; + const float* pntcov = trpArr->GetCov() + pntId * 6; // 6 elements per error matrix + hcovel[0] = double(pntcov[0]); + hcovel[1] = double(pntcov[1]); + hcovel[2] = double(pntcov[2]); + hcovel[3] = double(pntcov[1]); + hcovel[4] = double(pntcov[3]); + hcovel[5] = double(pntcov[4]); + hcovel[6] = double(pntcov[2]); + hcovel[7] = double(pntcov[4]); + hcovel[8] = double(pntcov[5]); + hcov.SetRotation(hcovel); + hcov.Multiply(&matL2Grec); + const TGeoHMatrix& l2gi = matL2Grec.Inverse(); + hcov.MultiplyLeft(&l2gi); // errors in local frame + hcov.Multiply(&matT2L); + const TGeoHMatrix& t2li = matT2L.Inverse(); + hcov.MultiplyLeft(&t2li); // errors in tracking frame + // + double* hcovscl = hcov.GetRotationMatrix(); + const double* sysE = getAddError(); // additional syst error + pnt->setYZErrTracking(hcovscl[4] + sysE[0] * sysE[0], hcovscl[5], hcovscl[8] + sysE[1] * sysE[1]); + } else { // errors will be calculated just before using the point in the fit, using track info + pnt->setYZErrTracking(0, 0, 0); + pnt->setNeedUpdateFromTrack(); + } + pnt->setXYZTracking(tra[0], tra[1], tra[2]); + pnt->setAlphaSens(getAlpTracking()); + pnt->setXSens(getXTracking()); + pnt->setDetID(det->getDetID()); + pnt->setSID(getSID()); + // + pnt->setContainsMeasurement(); + // + pnt->init(); + // + return pnt; + // +} +*/ +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensorTOF.cxx b/Detectors/Align/src/AlignableSensorTOF.cxx new file mode 100644 index 0000000000000..2e7da48ec37b6 --- /dev/null +++ b/Detectors/Align/src/AlignableSensorTOF.cxx @@ -0,0 +1,183 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTOF.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TOF sensor + +#include "Align/AlignableSensorTOF.h" +#include "Align/utils.h" +#include "Align/AlignableDetectorTOF.h" +#include "Framework/Logger.h" +#include "Align/AlignmentPoint.h" +//#include "AliTrackPointArray.h" +//#include "AliESDtrack.h" + +ClassImp(o2::align::AlignableSensorTOF); + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensorTOF::AlignableSensorTOF(const char* name, int vid, int iid, int isec) + : AlignableSensor(name, vid, iid), fSector(isec) +{ + // def c-tor +} + +//_________________________________________________________ +AlignableSensorTOF::~AlignableSensorTOF() +{ + // d-tor +} + +/* +//__________________________________________________________________ +void AlignableSensorTOF::setTrackingFrame() +{ + // define tracking frame of the sensor: just rotation by sector angle + fAlp = sector2Alpha(fSector); + fX = 0; +} +*/ + +//____________________________________________ +void AlignableSensorTOF::prepareMatrixT2L() +{ + // extract from geometry T2L matrix + double alp = sector2Alpha(fSector); + double loc[3] = {0, 0, 0}, glo[3]; + getMatrixL2GIdeal().LocalToMaster(loc, glo); + double x = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + TGeoHMatrix t2l; + t2l.SetDx(x); + t2l.RotateZ(alp * RadToDeg()); + const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse(); + t2l.MultiplyLeft(&l2gi); + /* + const TGeoHMatrix* t2l = AliGeomManager::GetTracking2LocalMatrix(getVolID()); + if (!t2l) { + Print("long"); + AliFatalF("Failed to find T2L matrix for VID:%d %s",getVolID(),getSymName()); + } + */ + setMatrixT2L(t2l); + // +} + +//____________________________________________ +AlignmentPoint* AlignableSensorTOF::TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* tr) +{ + // convert the pntId-th point to AlignmentPoint, detectors may override this method + // + // TOF stores in the trackpoints X,Y with alignment applied but Z w/o alignment!!! + // -> need special treatment unless data are already corrected + // + AlignableDetectorTOF* det = (AlignableDetectorTOF*)getDetector(); + AlignmentPoint* pnt = det->getPointFromPool(); + pnt->setSensor(this); + // + double tra[3], locId[3], loc[3], traId[3], + glo[3] = {trpArr->GetX()[pntId], trpArr->GetY()[pntId], trpArr->GetZ()[pntId]}; + const TGeoHMatrix& matL2Grec = getMatrixL2GReco(); // local to global matrix used for reconstruction + const TGeoHMatrix& matT2L = getMatrixT2L(); // matrix for tracking to local frame translation + // + // >>>------------- here we fix the z by emulating Misalign action in the tracking frame ------>>> + if (!trpArr->TestBit(AliTrackPointArray::kTOFBugFixed)) { + // + // we need reco-time alignment matrix in tracking frame, T^-1 * delta * T, where delta is local alignment matrix + TGeoHMatrix mClAlgTrec = getMatrixClAlgReco(); + mClAlgTrec.Multiply(&getMatrixT2L()); + const TGeoHMatrix& t2li = getMatrixT2L().Inverse(); + mClAlgTrec.MultiplyLeft(&t2li); + TGeoHMatrix mT2G; + getMatrixT2G(mT2G); + mT2G.MasterToLocal(glo, tra); // we are in tracking frame, with original wrong alignment + mClAlgTrec.MasterToLocal(tra, traId); // here we have almost ideal X,Y and wrong Z + const double* trans = mClAlgTrec.GetTranslation(); + const double* rotmt = mClAlgTrec.GetRotationMatrix(); + tra[2] = trans[2] + traId[0] * rotmt[6] + traId[1] * rotmt[7] + tra[2] * rotmt[8]; //we got misaligned Z + mT2G.LocalToMaster(tra, glo); + // + } + // now continue as usual + // <<<------------- here we fix the z by emulating Misalign action in the tracking frame ------<<< + // + // undo reco-time alignment + matL2Grec.MasterToLocal(glo, locId); // go to local frame using reco-time matrix, here we recover ideal measurement + // + getMatrixClAlg().LocalToMaster(locId, loc); // apply alignment + // + matT2L.MasterToLocal(loc, tra); // go to tracking frame + // + /* + double gloT[3]; + TGeoHMatrix t2g; + getMatrixT2G(t2g); t2g.LocalToMaster(tra,gloT); + printf("\n%5d %s\n",getVolID(), getSymName()); + printf("GloOR: %+.4e %+.4e %+.4e\n",glo[0],glo[1],glo[2]); + printf("LocID: %+.4e %+.4e %+.4e\n",locId[0],locId[1],locId[2]); + printf("LocML: %+.4e %+.4e %+.4e\n",loc[0],loc[1],loc[2]); + printf("Tra : %+.4e %+.4e %+.4e\n",tra[0],tra[1],tra[2]); + printf("GloTR: %+.4e %+.4e %+.4e\n",gloT[0],gloT[1],gloT[2]); + */ + // + if (!det->getUseErrorParam()) { + // convert error + TGeoHMatrix hcov; + double hcovel[9]; + const float* pntcov = trpArr->GetCov() + pntId * 6; // 6 elements per error matrix + hcovel[0] = double(pntcov[0]); + hcovel[1] = double(pntcov[1]); + hcovel[2] = double(pntcov[2]); + hcovel[3] = double(pntcov[1]); + hcovel[4] = double(pntcov[3]); + hcovel[5] = double(pntcov[4]); + hcovel[6] = double(pntcov[2]); + hcovel[7] = double(pntcov[4]); + hcovel[8] = double(pntcov[5]); + hcov.SetRotation(hcovel); + hcov.Multiply(&matL2Grec); + const TGeoHMatrix& l2gi = matL2Grec.Inverse(); + hcov.MultiplyLeft(&l2gi); // errors in local frame + hcov.Multiply(&matT2L); + const TGeoHMatrix& t2li = matT2L.Inverse(); + hcov.MultiplyLeft(&t2li); // errors in tracking frame + // + double* hcovscl = hcov.GetRotationMatrix(); + const double* sysE = getAddError(); // additional syst error + pnt->setYZErrTracking(hcovscl[4] + sysE[0] * sysE[0], hcovscl[5], hcovscl[8] + sysE[1] * sysE[1]); + } else { // errors will be calculated just before using the point in the fit, using track info + pnt->setYZErrTracking(0, 0, 0); + pnt->setNeedUpdateFromTrack(); + } + pnt->setXYZTracking(tra[0], tra[1], tra[2]); + pnt->setAlphaSens(getAlpTracking()); + pnt->setXSens(getXTracking()); + pnt->setDetID(det->getDetID()); + pnt->setSID(getSID()); + // + pnt->setContainsMeasurement(); + // + pnt->init(); + // + return pnt; + // +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensorTPC.cxx b/Detectors/Align/src/AlignableSensorTPC.cxx new file mode 100644 index 0000000000000..f99bd2e5b2eed --- /dev/null +++ b/Detectors/Align/src/AlignableSensorTPC.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTPC.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TPC sensor (chamber) + +#include "Align/AlignableSensorTPC.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +//#include "AliTrackPointArray.h" +//#include "AliESDtrack.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" + +ClassImp(o2::align::AlignableSensorTPC) + + using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensorTPC::AlignableSensorTPC(const char* name, int vid, int iid, int isec) + : AlignableSensor(name, vid, iid), fSector(isec) +{ + // def c-tor +} + +//_________________________________________________________ +AlignableSensorTPC::~AlignableSensorTPC() +{ + // d-tor +} +/* +//__________________________________________________________________ +void AlignableSensorTPC::setTrackingFrame() +{ + // define tracking frame of the sensor: just rotation by sector angle + fAlp = sector2Alpha(fSector); + fX = 0; +} +*/ + +//____________________________________________ +void AlignableSensorTPC::prepareMatrixT2L() +{ + // extract from geometry T2L matrix + double alp = sector2Alpha(fSector); + double loc[3] = {0, 0, 0}, glo[3]; + getMatrixL2GIdeal().LocalToMaster(loc, glo); + double x = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + TGeoHMatrix t2l; + t2l.SetDx(x); + t2l.RotateZ(alp * RadToDeg()); + const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse(); + t2l.MultiplyLeft(&l2gi); + /* + const TGeoHMatrix* t2l = AliGeomManager::GetTracking2LocalMatrix(getVolID()); + if (!t2l) { + Print("long"); + AliFatalF("Failed to find T2L matrix for VID:%d %s",getVolID(),getSymName()); + } + */ + setMatrixT2L(t2l); + // +} + +//____________________________________________ +AlignmentPoint* AlignableSensorTPC::TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack*) +{ + // convert the pntId-th point to AlignmentPoint + // + AlignableDetector* det = getDetector(); + AlignmentPoint* pnt = det->getPointFromPool(); + pnt->setSensor(this); + // + double tra[3], locId[3], loc[3], + glo[3] = {trpArr->GetX()[pntId], trpArr->GetY()[pntId], trpArr->GetZ()[pntId]}; + const TGeoHMatrix& matL2Grec = getMatrixL2GReco(); // local to global matrix used for reconstruction + const TGeoHMatrix& matT2L = getMatrixT2L(); // matrix for tracking to local frame translation + // + // undo reco-time alignment + matL2Grec.MasterToLocal(glo, locId); // go to local frame using reco-time matrix, here we recover ideal measurement + // + getMatrixClAlg().LocalToMaster(locId, loc); // apply alignment + // + matT2L.MasterToLocal(loc, tra); // go to tracking frame + // + /* + double gloT[3]; + TGeoHMatrix t2g; + getMatrixT2G(t2g); t2g.LocalToMaster(tra,gloT); + printf("\n%5d %s\n",getVolID(), getSymName()); + printf("GloOR: %+.4e %+.4e %+.4e\n",glo[0],glo[1],glo[2]); + printf("LocID: %+.4e %+.4e %+.4e\n",locId[0],locId[1],locId[2]); + printf("LocML: %+.4e %+.4e %+.4e\n",loc[0],loc[1],loc[2]); + printf("Tra : %+.4e %+.4e %+.4e\n",tra[0],tra[1],tra[2]); + printf("GloTR: %+.4e %+.4e %+.4e\n",gloT[0],gloT[1],gloT[2]); + */ + // + if (!det->getUseErrorParam()) { + // convert error + TGeoHMatrix hcov; + double hcovel[9]; + const float* pntcov = trpArr->GetCov() + pntId * 6; // 6 elements per error matrix + hcovel[0] = double(pntcov[0]); + hcovel[1] = double(pntcov[1]); + hcovel[2] = double(pntcov[2]); + hcovel[3] = double(pntcov[1]); + hcovel[4] = double(pntcov[3]); + hcovel[5] = double(pntcov[4]); + hcovel[6] = double(pntcov[2]); + hcovel[7] = double(pntcov[4]); + hcovel[8] = double(pntcov[5]); + hcov.SetRotation(hcovel); + hcov.Multiply(&matL2Grec); + const TGeoHMatrix& l2gi = matL2Grec.Inverse(); + hcov.MultiplyLeft(&l2gi); // errors in local frame + hcov.Multiply(&matT2L); + const TGeoHMatrix& t2li = matT2L.Inverse(); + hcov.MultiplyLeft(&t2li); // errors in tracking frame + // + double* hcovscl = hcov.GetRotationMatrix(); + const double* sysE = getAddError(); // additional syst error + pnt->setYZErrTracking(hcovscl[4] + sysE[0] * sysE[0], hcovscl[5], hcovscl[8] + sysE[1] * sysE[1]); + } else { // errors will be calculated just before using the point in the fit, using track info + pnt->setYZErrTracking(0, 0, 0); + pnt->setNeedUpdateFromTrack(); + } + pnt->setXYZTracking(tra[0], tra[1], tra[2]); + pnt->setAlphaSens(getAlpTracking()); + pnt->setXSens(getXTracking()); + pnt->setDetID(det->getDetID()); + pnt->setSID(getSID()); + // + pnt->setContainsMeasurement(); + // + pnt->init(); + // + return pnt; + // +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableSensorTRD.cxx b/Detectors/Align/src/AlignableSensorTRD.cxx new file mode 100644 index 0000000000000..8b23574e51f59 --- /dev/null +++ b/Detectors/Align/src/AlignableSensorTRD.cxx @@ -0,0 +1,232 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableSensorTRD.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief TRD sensor + +#include "Align/AlignableSensorTRD.h" +//#include "AliTRDgeometry.h" +#include "Align/AlignableDetectorTRD.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +#include "Align/AlignmentPoint.h" +//#include "AliTrackPointArray.h" +//#include "AliESDtrack.h" +//#include "AliTrackerBase.h" + +ClassImp(o2::align::AlignableSensorTRD) + + using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +AlignableSensorTRD::AlignableSensorTRD(const char* name, int vid, int iid, int isec) + : AlignableSensor(name, vid, iid), fSector(isec) +{ + // def c-tor +} + +//_________________________________________________________ +AlignableSensorTRD::~AlignableSensorTRD() +{ + // d-tor +} +/* +//__________________________________________________________________ +void AlignableSensorTRD::setTrackingFrame() +{ + // define tracking frame of the sensor: just rotation by sector angle + fAlp = sector2Alpha(fSector); + fX = 0; +} +*/ + +//____________________________________________ +void AlignableSensorTRD::prepareMatrixT2L() +{ + // extract from geometry T2L matrix + double alp = sector2Alpha(fSector); + double loc[3] = {0, 0, 0}, glo[3]; + getMatrixL2GIdeal().LocalToMaster(loc, glo); + double x = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); + TGeoHMatrix t2l; + t2l.SetDx(x); + t2l.RotateZ(alp * RadToDeg()); + const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse(); + t2l.MultiplyLeft(&l2gi); + /* + const TGeoHMatrix* t2l = AliGeomManager::GetTracking2LocalMatrix(getVolID()); + if (!t2l) { + Print("long"); + AliFatalF("Failed to find T2L matrix for VID:%d %s",getVolID(),getSymName()); + } + */ + setMatrixT2L(t2l); + // +} + +//____________________________________________ +void AlignableSensorTRD::dPosTraDParCalib(const AlignmentPoint* pnt, double* deriv, int calibID, const AlignableVolume* parent) const +{ + // calculate point position X,Y,Z derivatives wrt calibration parameter calibID of given parent + // parent=0 means top detector object calibration + // + deriv[0] = deriv[1] = deriv[2] = 0; + // + if (!parent) { // TRD detector global calibration + // + switch (calibID) { + case AlignableDetectorTRD::kCalibNRCCorrDzDtgl: { // correction for Non-Crossing tracklets Z,Y shift: Z -> Z + calib*tgl, Y -> Y + calib*tgl*tilt*sign(tilt); + double sgYZ = pnt->getYZErrTracking()[1]; // makes sense only for nonRC tracklets + if (Abs(sgYZ) > 0.01) { + const double kTilt = 2. * TMath::DegToRad(); + deriv[2] = pnt->getTrParamWSA()[AlignmentPoint::kParTgl]; + deriv[1] = deriv[2] * Sign(kTilt, sgYZ); + } + break; + } + // + case AlignableDetectorTRD::kCalibDVT: { // correction for bias in VdriftT + // error in VdriftT equivalent to shift in X at which Y measurement is evaluated + // Y -> Y + dVdriftT * tg_phi, where tg_phi is the slope of the track in YX plane + double snp = pnt->getTrParamWSA(AlignmentPoint::kParSnp), slpY = snp / Sqrt((1 - snp) * (1 + snp)); + deriv[1] = slpY; + break; + } + + default: + break; + }; + } + // +} + +//____________________________________________ +AlignmentPoint* AlignableSensorTRD::TrackPoint2AlgPoint(int pntId, const AliTrackPointArray* trpArr, const AliESDtrack* tr) +{ + // convert the pntId-th point to AlignmentPoint + // + AlignableDetectorTRD* det = (AlignableDetectorTRD*)getDetector(); + AlignmentPoint* pnt = det->getPointFromPool(); + pnt->setSensor(this); + // + double tra[3], locId[3], loc[3], + glo[3] = {trpArr->GetX()[pntId], trpArr->GetY()[pntId], trpArr->GetZ()[pntId]}; + const TGeoHMatrix& matL2Grec = getMatrixL2GReco(); // local to global matrix used for reconstruction + const TGeoHMatrix& matT2L = getMatrixT2L(); // matrix for tracking to local frame translation + // + // undo reco-time alignment + matL2Grec.MasterToLocal(glo, locId); // go to local frame using reco-time matrix, here we recover ideal measurement + // + getMatrixClAlg().LocalToMaster(locId, loc); // apply alignment + // + matT2L.MasterToLocal(loc, tra); // go to tracking frame + // + /* + double gloT[3]; + TGeoHMatrix t2g; + getMatrixT2G(t2g); t2g.LocalToMaster(tra,gloT); + printf("\n%5d %s\n",getVolID(), getSymName()); + printf("GloOR: %+.4e %+.4e %+.4e\n",glo[0],glo[1],glo[2]); + printf("LocID: %+.4e %+.4e %+.4e\n",locId[0],locId[1],locId[2]); + printf("LocML: %+.4e %+.4e %+.4e\n",loc[0],loc[1],loc[2]); + printf("Tra : %+.4e %+.4e %+.4e\n",tra[0],tra[1],tra[2]); + printf("GloTR: %+.4e %+.4e %+.4e\n",gloT[0],gloT[1],gloT[2]); + */ + // + if (!det->getUseErrorParam()) { + // convert error + TGeoHMatrix hcov; + double hcovel[9]; + const float* pntcov = trpArr->GetCov() + pntId * 6; // 6 elements per error matrix + hcovel[0] = double(pntcov[0]); + hcovel[1] = double(pntcov[1]); + hcovel[2] = double(pntcov[2]); + hcovel[3] = double(pntcov[1]); + hcovel[4] = double(pntcov[3]); + hcovel[5] = double(pntcov[4]); + hcovel[6] = double(pntcov[2]); + hcovel[7] = double(pntcov[4]); + hcovel[8] = double(pntcov[5]); + hcov.SetRotation(hcovel); + hcov.Multiply(&matL2Grec); + const TGeoHMatrix& l2gi = matL2Grec; + hcov.MultiplyLeft(&l2gi); // errors in local frame + hcov.Multiply(&matT2L); + const TGeoHMatrix& t2li = matT2L.Inverse(); + hcov.MultiplyLeft(&t2li); // errors in tracking frame + // + double* hcovscl = hcov.GetRotationMatrix(); + const double* sysE = getAddError(); // additional syst error + pnt->setYZErrTracking(hcovscl[4] + sysE[0] * sysE[0], hcovscl[5], hcovscl[8] + sysE[1] * sysE[1]); + } else { // errors will be calculated just before using the point in the fit, using track info + pnt->setYZErrTracking(0, 0, 0); + pnt->setNeedUpdateFromTrack(); + } + pnt->setXYZTracking(tra[0], tra[1], tra[2]); + pnt->setAlphaSens(getAlpTracking()); + pnt->setXSens(getXTracking()); + pnt->setDetID(det->getDetID()); + pnt->setSID(getSID()); + // + pnt->setContainsMeasurement(); + // + // Apply calibrations + // Correction for NonRC points to account for most probable Z for non-crossing + { + const double kTilt = 2. * TMath::DegToRad(); + // is it pad crrossing? + double* errYZ = (double*)pnt->getYZErrTracking(); + double sgYZ = errYZ[1]; + if (TMath::Abs(sgYZ) < 0.01) { // crossing + // increase errors since the error + const double* extraErrRC = det->GetExtraErrRC(); + errYZ[0] += extraErrRC[0] * extraErrRC[0]; + errYZ[2] += extraErrRC[1] * extraErrRC[1]; + } else { // account for probability to not cross the row + double* pYZ = (double*)pnt->getYZTracking(); + double corrZ = det->GetNonRCCorrDzDtglWithCal() * tr->GetTgl(); + pYZ[1] += corrZ; + pYZ[0] += corrZ * Sign(kTilt, sgYZ); // Y and Z are correlated + } + } + // + // Correction for DVT, equivalent to shift in X at which Y is evaluated: dY = tg_phi * dvt + { + double dvt = det->GetCorrDVTWithCal(); + if (Abs(dvt) > AlmostZeroD) { + AliExternalTrackParam trc = *tr; + if (!trc.RotateParamOnly(getAlpTracking())) + return 0; + double snp = trc.GetSnpAt(pnt->getXPoint(), AliTrackerBase::GetBz()); + if (Abs(snp) > AlmostOneD) + return 0; + double slpY = snp / Sqrt((1 - snp) * (1 + snp)); + double* pYZ = (double*)pnt->getYZTracking(); + pYZ[0] += dvt * slpY; + } + } + // + pnt->init(); + // + return pnt; + // +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignableVolume.cxx b/Detectors/Align/src/AlignableVolume.cxx new file mode 100644 index 0000000000000..acfa7db87bca8 --- /dev/null +++ b/Detectors/Align/src/AlignableVolume.cxx @@ -0,0 +1,906 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignableVolume.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Base class of alignable volume + +/* + Alignment formalism: + + Vector l in the local frame of the volume_j (assuming hierarchy of nested volumes 0...J + from most coarse to the end volume) is transformed to master frame vector + g = G_j*l_j + Matrix G_j is Local2Global matrix (L2G in the code). If the volume has a parent + volume j-1, the global vector g can be transformed to the local volume of j-1 as + l_{j-1} = G^-1_{j-1}* g + Hence, the transormation from volume j to j-1 is + l_{j-1} = G^-1_{j-1}*G_j l_j = R_j*l_j + + The alignment corrections in general can be defined either as a + + 1) local delta: l'_j = delta_j * l_j + hence g' = G_j * delta_j = G'_j*l_j + or as + 2) global Delta: g' = Delta_j * G_j * l_j = G'_j*l_j + + Hence Delta and delta are linked as + Delta_j = G_j delta_j G^-1_j + delta_j = G^-1_j Delta_j G_j + + In case the whole chain of nested volumes is aligned, the corrections pile-up as: + + G_0*delta_0 ... G^-1_{j-2}*G_{j-1}*delta_{j-1}*G^-1_{j-1}*G_j*delta_j = + Delta_0 * Delta_{1} ... Delta_{j-1}*Delta_{j}... * G_j + + -> Delta_j = G'_{j-1} * G^-1_{j-1} * G_j * G'^-1_j + where G and G' are modified and original L2G matrices + + + From this by induction one gets relation between local and global deltas: + + Delta_j = Z_j * delta_j * Z^-1_j + + where Z_j = [ Prod_{k=0}^{j-1} (G_k * delta_k * G^-1_k) ] * G_j + + By convention, aliroot aligment framework stores global Deltas ! + + In case the geometry was already prealigned by PDelta_j matrices, the result + of the new incremental alignment Delta_j must be combined with PDelta_j to + resulting matrix TDelta_j before writing new alignment object. + + Derivation: if G_j and IG_j are final and ideal L2G matrices for level j, then + + G_j = TDelta_j * TDelta_{j-1} ... TDelta_0 * IG_j + = (Delta_j * Delta_{j-1} ... Delta_0) * (PDelta_j * PDelta_{j-1} ... PDelta_0) * IG_j + + Hence: + TDelta_j = [Prod_{i=j}^0 Delta_i ] * [Prod_{k=j}^0 PDelta_k ] * [Prod_{l=0}^{j-1} TDelta_l] + + By induction we get combination rule: + + TDelta_j = Delta_j * X_{j-1} * PDelta_j * X^-1_{j-1} + + where X_i = Delta_i * Delta_{i-1} ... Delta_0 + + --------------------------------- + + This alignment framework internally allows to find geometry corrections either in the + volume LOCAL frame or in its TRACKING frame. The latter is defined for sensors as + lab frame, rotated by the angle alpha in such a way that the X axis is normal to the + sensor plane (note, that for ITS the rotated X axis origin is also moved to the sensor) + For the non-sensor volumes the TRACKING frame is defined by rotation of the lab frame + with the alpha angle = average angle of centers of its children, seen from the origin. + + The TRACKING and IDEAL LOCAL (before misalignment) frames are related by the + tracking-to-local matrix (T2L in the code), i.e. the vectors in local and tracking frames + are related as + l = T2L * t + + The alignment can be done using both frames for different volumes of the same geometry + branch. + The alignments deltas in local and tracking frames are related as: + + l' = T2L * delta_t * t + l' = delta_l * T2L * t + -> delta_l = T2L * delta_t * T2L^-1 + + */ + +#include "Align/Controller.h" +#include "Align/AlignableVolume.h" +#include "Align/DOFStatistics.h" +#include "Align/GeometricalConstraint.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsBase/GeometryManager.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +#include <TString.h> +#include <TClonesArray.h> +#include <TGeoManager.h> +#include <TGeoPhysicalNode.h> +#include <TH1.h> +#include <TAxis.h> +#include <cstdio> + +ClassImp(o2::align::AlignableVolume); + +using namespace TMath; +using namespace o2::align::utils; + +namespace o2 +{ +namespace align +{ + +const char* AlignableVolume::sFrameName[AlignableVolume::kNVarFrames] = {"LOC", "TRA"}; +// +uint32_t AlignableVolume::sDefGeomFree = + kDOFBitTX | kDOFBitTY | kDOFBitTZ | kDOFBitPS | kDOFBitTH | kDOFBitPH; +// +const char* AlignableVolume::sDOFName[AlignableVolume::kNDOFGeom] = {"TX", "TY", "TZ", "PSI", "THT", "PHI"}; + +//_________________________________________________________ +AlignableVolume::AlignableVolume(const char* symname, int iid, Controller* ctr) : DOFSet(symname, ctr), mIntID(iid) +{ + // def c-tor + if (!ctr) { + LOG(FATAL) << "Controller has to be provided :" << symname; + } + setVolID(0); // volumes have no VID, unless it is sensor + setNDOFs(kNDOFGeom); + setFreeDOFPattern(sDefGeomFree); +} + +//_________________________________________________________ +AlignableVolume::~AlignableVolume() +{ + // d-tor + delete mChildren; +} + +//_________________________________________________________ +void AlignableVolume::delta2Matrix(TGeoHMatrix& deltaM, const double* delta) const +{ + // prepare delta matrix for the volume from its + // local delta vector (AliAlignObj convension): dx,dy,dz,,theta,psi,phi + const double *tr = &delta[0], *rt = &delta[3]; // translation(cm) and rotation(degree) + + // AliAlignObjParams tempAlignObj; + // tempAlignObj.SetRotation(rt[0], rt[1], rt[2]); + // tempAlignObj.SetTranslation(tr[0], tr[1], tr[2]); + // tempAlignObj.GetMatrix(deltaM); + + detectors::AlignParam tempAlignObj; + tempAlignObj.setRotation(rt[0], rt[1], rt[2]); + tempAlignObj.setTranslation(tr[0], tr[1], tr[2]); + deltaM = tempAlignObj.createMatrix(); +} + +//__________________________________________________________________ +void AlignableVolume::getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta) const +{ + // prepare the variation matrix tau in volume TRACKING frame by applying + // local delta of modification of LOCAL frame: + // tra' = tau*tra = tau*T2L^-1*loc = T2L^-1*loc' = T2L^-1*delta*loc + // tau = T2L^-1*delta*T2L + delta2Matrix(matMod, delta); + matMod.Multiply(&getMatrixT2L()); + const TGeoHMatrix& t2li = getMatrixT2L().Inverse(); + matMod.MultiplyLeft(&t2li); +} + +//__________________________________________________________________ +void AlignableVolume::getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const +{ + // prepare the variation matrix tau in volume TRACKING frame by applying + // local delta of modification of LOCAL frame of its PARENT; + // The relMat is matrix for transformation from child to parent frame: LOC = relMat*loc + // + // tra' = tau*tra = tau*T2L^-1*loc = T2L^-1*loc' = T2L^-1*relMat^-1*Delta*relMat*loc + // tau = (relMat*T2L)^-1*Delta*(relMat*T2L) + delta2Matrix(matMod, delta); + TGeoHMatrix tmp = relMat; + tmp *= getMatrixT2L(); + matMod.Multiply(&tmp); + const TGeoHMatrix& tmpi = tmp.Inverse(); + matMod.MultiplyLeft(&tmpi); +} + +//__________________________________________________________________ +void AlignableVolume::getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta) const +{ + // prepare the variation matrix tau in volume TRACKING frame by applying + // local delta of modification of the same TRACKING frame: + // tra' = tau*tra + delta2Matrix(matMod, delta); +} + +//__________________________________________________________________ +void AlignableVolume::getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const +{ + // prepare the variation matrix tau in volume TRACKING frame by applying + // local delta of modification of TRACKING frame of its PARENT; + // The relMat is matrix for transformation from child to parent frame: TRA = relMat*tra + // (see DPosTraDParGeomTRA) + // + // tra' = tau*tra = tau*relMat^-1*TRA = relMat^-1*TAU*TRA = relMat^-1*TAU*relMat*tra + // tau = relMat^-1*TAU*relMat + delta2Matrix(matMod, delta); // TAU + matMod.Multiply(&relMat); + const TGeoHMatrix& reli = relMat.Inverse(); + matMod.MultiplyLeft(&reli); +} + +//_________________________________________________________ +int AlignableVolume::countParents() const +{ + // count parents in the chain + int cnt = 0; + const AlignableVolume* p = this; + while ((p = p->getParent())) { + cnt++; + } + return cnt; +} + +//____________________________________________ +void AlignableVolume::Print(const Option_t* opt) const +{ + // print info + TString opts = opt; + opts.ToLower(); + printf("Lev:%2d IntID:%7d %s | %2d nodes | Effective X:%8.4f Alp:%+.4f | Used Points: %d\n", + countParents(), getInternalID(), getSymName(), getNChildren(), mX, mAlp, mNProcPoints); + printf(" DOFs: Tot: %d (offs: %5d) Free: %d Geom: %d {", mNDOFs, mFirstParGloID, mNDOFsFree, mNDOFGeomFree); + for (int i = 0; i < kNDOFGeom; i++) { + printf("%d", isFreeDOF(i) ? 1 : 0); + } + printf("} in %s frame.", sFrameName[mVarFrame]); + if (getNChildren()) { + printf(" Child.Constr: {"); + for (int i = 0; i < kNDOFGeom; i++) { + printf("%d", isChildrenDOFConstrained(i) ? 1 : 0); + } + printf("}"); + } + if (getExcludeFromParentConstraint()) { + printf(" Excl.from parent constr."); + } + printf("\n"); + // + if (opts.Contains("par") && mFirstParGloID >= 0) { + printf(" Lb: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%10d ", getParLab(i)); + } + printf("\n"); + printf(" Vl: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%+9.3e ", getParVal(i)); + } + printf("\n"); + printf(" Er: "); + for (int i = 0; i < mNDOFs; i++) { + printf("%+9.3e ", getParErr(i)); + } + printf("\n"); + } + + if (opts.Contains("mat")) { // print matrices + printf("L2G ideal : "); + getMatrixL2GIdeal().Print(); + printf("L2G misalign: "); + getMatrixL2G().Print(); + printf("L2G RecoTime: "); + getMatrixL2GReco().Print(); + printf("T2L (fake) : "); + getMatrixT2L().Print(); + } + // +} + +//____________________________________________ +void AlignableVolume::prepareMatrixL2G(bool reco) +{ + // extract from geometry L2G matrix, depending on reco flag, set it as a reco-time + // or current alignment matrix + const char* path = getSymName(); + if (gGeoManager->GetAlignableEntry(path)) { + const TGeoHMatrix* l2g = base::GeometryManager::getMatrix(path); + if (!l2g) { + LOG(FATAL) << "Failed to find L2G matrix for alignable " << path; + } + reco ? setMatrixL2GReco(*l2g) : setMatrixL2G(*l2g); + } else { // extract from path + if (!gGeoManager->CheckPath(path)) { + LOG(FATAL) << "Volume path " << path << " is not valid!"; + } + TGeoPhysicalNode* node = (TGeoPhysicalNode*)gGeoManager->GetListOfPhysicalNodes()->FindObject(path); + TGeoHMatrix l2g; + if (!node) { + LOG(WARNING) << "volume " << path << " was not misaligned, extracting original matrix"; + if (!base::GeometryManager::getOriginalMatrix(path, l2g)) { + LOG(FATAL) << "Failed to find ideal L2G matrix for " << path; + } + } else { + l2g = *node->GetMatrix(); + } + reco ? setMatrixL2GReco(l2g) : setMatrixL2G(l2g); + } +} + +//____________________________________________ +void AlignableVolume::prepareMatrixL2GIdeal() +{ + // extract from geometry ideal L2G matrix + TGeoHMatrix mtmp; + if (!base::GeometryManager::getOriginalMatrix(getSymName(), mtmp)) { + LOG(FATAL) << "Failed to find ideal L2G matrix for " << getSymName(); + } + setMatrixL2GIdeal(mtmp); +} + +//____________________________________________ +void AlignableVolume::prepareMatrixT2L() +{ + // for non-sensors we define the fake tracking frame with the alpha angle being + // the average angle of centers of its children + // + double tot[3] = {0, 0, 0}, loc[3] = {0, 0, 0}, glo[3]; + int nch = getNChildren(); + for (int ich = nch; ich--;) { + AlignableVolume* vol = getChild(ich); + vol->getMatrixL2GIdeal().LocalToMaster(loc, glo); + for (int j = 3; j--;) { + tot[j] += glo[j]; + } + } + if (nch) { + for (int j = 3; j--;) { + tot[j] /= nch; + } + } + // + mAlp = TMath::ATan2(tot[1], tot[0]); + utils::bringToPiPM(mAlp); + // + mX = TMath::Sqrt(tot[0] * tot[0] + tot[1] * tot[1]); + // + // 1st create Tracking to Global matrix + mMatT2L.Clear(); + mMatT2L.SetDx(mX); + mMatT2L.RotateZ(mAlp * RadToDeg()); + // then convert it to Tracking to Local matrix + const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse(); + mMatT2L.MultiplyLeft(&l2gi); + // +} + +//____________________________________________ +void AlignableVolume::setMatrixT2L(const TGeoHMatrix& m) +{ + // set the T2L matrix and define tracking frame + // Note that this method is used for the externally set matrices + // (in case of sensors). For other volumes the tracking frame and matrix + // is defined in the prepareMatrixT2L method + mMatT2L = m; + setTrackingFrame(); +} + +//__________________________________________________________________ +void AlignableVolume::setTrackingFrame() +{ + // Define tracking frame of the sensor + // This method should be implemented for sensors, which receive the T2L + // matrix from the geometry + LOG(ERROR) << "Volume " << GetName() << " was supposed to implement its own method"; +} + +//__________________________________________________________________ +void AlignableVolume::assignDOFs() +{ + // Assigns offset of the DOFS of this volume in global array of DOFs, attaches arrays to volumes + // + setFirstParGloID(mController->getNDOFs()); + if (mFirstParGloID == (int)mController->getGloParVal().size()) { + mController->expandGlobalsBy(mNDOFs); + } + for (int i = 0; i < mNDOFs; i++) { + setParLab(i, getInternalID() * 100 + i); + } + int nch = getNChildren(); // go over childs + for (int ich = 0; ich < nch; ich++) { + getChild(ich)->assignDOFs(); + } + // + return; +} + +//__________________________________________________________________ +void AlignableVolume::initDOFs() +{ + // initialize degrees of freedom + // + // Do we need this strict condition? + if (getInitDOFsDone()) { + LOG(FATAL) << "DOFs are already initialized for " << GetName(); + } + auto pars = getParVals(); + auto errs = getParErrs(); + for (int i = 0; i < mNDOFs; i++) { + if (errs[i] < -9999 && isZeroAbs(pars[i])) { + fixDOF(i); + } + } + calcFree(true); + setInitDOFsDone(); +} + +//__________________________________________________________________ +void AlignableVolume::calcFree(bool condFix) +{ + // calculate free dofs. If condFix==true, condition parameter a la pede, i.e. error < 0 + mNDOFsFree = mNDOFGeomFree = 0; + for (int i = 0; i < mNDOFs; i++) { + if (!isFreeDOF(i)) { + if (condFix) { + setParErr(i, -999); + } + continue; + } + mNDOFsFree++; + if (i < kNDOFGeom) { + mNDOFGeomFree++; + } + } + // +} + +//_________________________________________________________ +void AlignableVolume::getParValGeom(double* delta) const +{ + auto pars = getParVals(); + for (int i = kNDOFGeom; i--;) { + delta[i] = pars[i]; + } +} + +//__________________________________________________________________ +void AlignableVolume::addChild(AlignableVolume* ch) +{ + // add child volume + if (!mChildren) { + mChildren = new TObjArray(); + mChildren->SetOwner(false); + } + mChildren->AddLast(ch); +} + +//__________________________________________________________________ +bool AlignableVolume::isCondDOF(int i) const +{ + // is DOF free and conditioned? + return (!isZeroAbs(getParVal(i)) || !isZeroAbs(getParErr(i))); +} + +//______________________________________________________ +int AlignableVolume::finalizeStat(DOFStatistics& st) +{ + // finalize statistics on processed points + mNProcPoints = 0; + for (int ich = getNChildren(); ich--;) { + AlignableVolume* child = getChild(ich); + mNProcPoints += child->finalizeStat(st); + } + fillDOFStat(st); + return mNProcPoints; +} + +//______________________________________________________ +void AlignableVolume::writePedeInfo(FILE* parOut, const Option_t* opt) const +{ + // contribute to params template file for PEDE + enum { kOff, + kOn, + kOnOn }; + const char* comment[3] = {" ", "! ", "!!"}; + const char* kKeyParam = "parameter"; + TString opts = opt; + opts.ToLower(); + bool showDef = opts.Contains("d"); // show free DOF even if not preconditioned + bool showFix = opts.Contains("f"); // show DOF even if fixed + bool showNam = opts.Contains("n"); // show volume name even if no nothing else is printable + // + // is there something to print ? + int nCond(0), nFix(0), nDef(0); + for (int i = 0; i < mNDOFs; i++) { + if (!isFreeDOF(i)) { + nFix++; + } + if (isCondDOF(i)) { + nCond++; + } + if (!isCondDOF(i) && isFreeDOF(i)) { + nDef++; + } + } + // + int cmt = nCond > 0 || nFix > 0 ? kOff : kOn; // do we comment the "parameter" keyword for this volume + if (!nFix) { + showFix = false; + } + if (!nDef) { + showDef = false; + } + // + if (nCond || showDef || showFix || showNam) { + fprintf(parOut, "%s%s %s\t\tDOF/Free: %d/%d (%s) %s\n", comment[cmt], kKeyParam, comment[kOnOn], + getNDOFs(), getNDOFsFree(), sFrameName[mVarFrame], GetName()); + } + // + if (nCond || showDef || showFix) { + for (int i = 0; i < mNDOFs; i++) { + cmt = kOn; + if (isCondDOF(i) || !isFreeDOF(i)) { + cmt = kOff; + } // free-conditioned : MUST print + else if (!isFreeDOF(i)) { + if (!showFix) { + continue; + } + } // Fixed: print commented if asked + else if (!showDef) { + continue; + } // free-unconditioned: print commented if asked + // + fprintf(parOut, "%s %9d %+e %+e\t%s %s p%d\n", comment[cmt], getParLab(i), + getParVal(i), getParErr(i), comment[kOnOn], isFreeDOF(i) ? " " : "FX", i); + } + fprintf(parOut, "\n"); + } + // children volume + int nch = getNChildren(); + // + for (int ich = 0; ich < nch; ich++) { + getChild(ich)->writePedeInfo(parOut, opt); + } + // +} + +//_________________________________________________________________ +void AlignableVolume::createGloDeltaMatrix(TGeoHMatrix& deltaM) const +{ + // Create global matrix deltaM from global array containing corrections. + // This deltaM does not account for eventual prealignment + // Volume knows if its variation was done in TRA or LOC frame + // + createLocDeltaMatrix(deltaM); + const TGeoHMatrix& l2g = getMatrixL2G(); + const TGeoHMatrix& l2gi = l2g.Inverse(); + deltaM.Multiply(&l2gi); + deltaM.MultiplyLeft(&l2g); + // +} +/* +//_________________________________________________________________ +void AlignableVolume::createGloDeltaMatrix(TGeoHMatrix &deltaM) const +{ + // Create global matrix deltaM from global array containing corrections. + // This deltaM does not account for eventual prealignment + // Volume knows if its variation was done in TRA or LOC frame + // + // deltaM = Z * deltaL * Z^-1 + // where deltaL is local correction matrix and Z is matrix defined as + // Z = [ Prod_{k=0}^{j-1} G_k * deltaL_k * G^-1_k ] * G_j + // with j=being the level of the volume in the hierarchy + // + createLocDeltaMatrix(deltaM); + TGeoHMatrix zMat = getMatrixL2G(); + const AlignableVolume* par = this; + while( (par=par->getParent()) ) { + TGeoHMatrix locP; + par->createLocDeltaMatrix(locP); + locP.MultiplyLeft( &par->getMatrixL2G() ); + locP.Multiply( &par->getMatrixL2G().Inverse() ); + zMat.MultiplyLeft( &locP ); + } + deltaM.MultiplyLeft( &zMat ); + deltaM.Multiply( &zMat.Inverse() ); + // +} +*/ + +//_________________________________________________________________ +void AlignableVolume::createPreGloDeltaMatrix(TGeoHMatrix& deltaM) const +{ + // Create prealignment global matrix deltaM from prealigned G and + // original GO local-to-global matrices + // + // From G_j = Delta_j * Delta_{j-1} ... Delta_0 * GO_j + // where Delta_j is global prealignment matrix for volume at level j + // we get by induction + // Delta_j = G_j * GO^-1_j * GO_{j-1} * G^-1_{j-1} + // + deltaM = getMatrixL2G(); + deltaM *= getMatrixL2GIdeal().Inverse(); + const AlignableVolume* par = getParent(); + if (par) { + deltaM *= par->getMatrixL2GIdeal(); + deltaM *= par->getMatrixL2G().Inverse(); + } + // +} + +/* +// this is an alternative lengthy way ! +//_________________________________________________________________ +void AlignableVolume::createPreGloDeltaMatrix(TGeoHMatrix &deltaM) const +{ + // Create prealignment global matrix deltaM from prealigned G and + // original GO local-to-global matrices + // + // From G_j = Delta_j * Delta_{j-1} ... Delta_0 * GO_j + // where Delta_j is global prealignment matrix for volume at level j + // we get by induction + // Delta_j = G_j * GO^-1_j * GO_{j-1} * G^-1_{j-1} + // + createPreLocDeltaMatrix(deltaM); + TGeoHMatrix zMat = getMatrixL2GIdeal(); + const AlignableVolume* par = this; + while( (par=par->getParent()) ) { + TGeoHMatrix locP; + par->createPreLocDeltaMatrix(locP); + locP.MultiplyLeft( &par->getMatrixL2GIdeal() ); + locP.Multiply( &par->getMatrixL2GIdeal().Inverse() ); + zMat.MultiplyLeft( &locP ); + } + deltaM.MultiplyLeft( &zMat ); + deltaM.Multiply( &zMat.Inverse() ); + // +} +*/ + +//_________________________________________________________________ +void AlignableVolume::createPreLocDeltaMatrix(TGeoHMatrix& deltaM) const +{ + // Create prealignment local matrix deltaM from prealigned G and + // original GO local-to-global matrices + // + // From G_j = GO_0 * delta_0 * GO^-1_0 * GO_1 * delta_1 ... GO^-1_{j-1}*GO_{j}*delta_j + // where delta_j is local prealignment matrix for volume at level j + // we get by induction + // delta_j = GO^-1_j * GO_{j-1} * G^-1_{j-1} * G^_{j} + // + const AlignableVolume* par = getParent(); + deltaM = getMatrixL2GIdeal().Inverse(); + if (par) { + deltaM *= par->getMatrixL2GIdeal(); + deltaM *= par->getMatrixL2G().Inverse(); + } + deltaM *= getMatrixL2G(); + // +} + +//_________________________________________________________________ +void AlignableVolume::createLocDeltaMatrix(TGeoHMatrix& deltaM) const +{ + // Create local matrix deltaM from global array containing corrections. + // This deltaM does not account for eventual prealignment + // Volume knows if its variation was done in TRA or LOC frame + auto pars = getParVals(); + double corr[kNDOFGeom]; + for (int i = kNDOFGeom; i--;) { + corr[i] = pars[i]; + } // we need doubles + delta2Matrix(deltaM, corr); + if (isFrameTRA()) { // we need corrections in local frame! + // l' = T2L * delta_t * t = T2L * delta_t * T2L^-1 * l = delta_l * l + // -> delta_l = T2L * delta_t * T2L^-1 + const TGeoHMatrix& t2l = getMatrixT2L(); + const TGeoHMatrix& t2li = t2l.Inverse(); + deltaM.Multiply(&t2li); + deltaM.MultiplyLeft(&t2l); + } + // +} + +//_________________________________________________________________ +void AlignableVolume::createAlignmenMatrix(TGeoHMatrix& alg) const +{ + // create final alignment matrix, accounting for eventual prealignment + // + // if the correction for this volume at level j is TAU (global delta) then the combined + // correction (accounting for reference prealignment) is + // (Delta_0 * .. Delta_{j-1})^-1 * TAU ( Delta_0 * .. Delta_j) + // where Delta_i is prealigment global delta of volume i (0 is top) + // In principle, it can be obtained as: + // GIdeal_{j-1} * G_{j-1}^-1 * TAU * G_{j}^-1 * GIdeal_{j}^-1 + // where G_i is pre-misaligned reference L2G and GIdeal_i is L2GIdeal, + // but this creates precision problem. + // Therefore we use explicitly cached Deltas from prealignment object. + // + createGloDeltaMatrix(alg); + // + const AlignableVolume* par = getParent(); + if (par) { + TGeoHMatrix dchain; + while (par) { + dchain.MultiplyLeft(&par->getGlobalDeltaRef()); + par = par->getParent(); + } + const TGeoHMatrix& dchaini = dchain.Inverse(); + alg.Multiply(&dchain); + alg.MultiplyLeft(&dchaini); + } + alg *= getGlobalDeltaRef(); + + /* // bad precision ? + alg.Multiply(&getMatrixL2G()); + alg.Multiply(&getMatrixL2GIdeal().Inverse()); + if (par) { + alg.MultiplyLeft(&par->getMatrixL2G().Inverse()); + alg.MultiplyLeft(&par->getMatrixL2GIdeal()); + } + */ +} + +/* +//_________________________________________________________________ +void AlignableVolume::createAlignmenMatrix(TGeoHMatrix& alg) const +{ + // create final alignment matrix, accounting for eventual prealignment + // + // deltaGlo_j * X_{j-1} * PdeltaGlo_j * X^-1_{j-1} + // + // where deltaGlo_j is global alignment matrix for this volume at level j + // of herarchy, obtained from createGloDeltaMatrix. + // PdeltaGlo_j is prealignment global matrix and + // X_i = deltaGlo_i * deltaGlo_{i-1} .. deltaGle_0 + // + TGeoHMatrix delGloPre,matX; + createGloDeltaMatrix(alg); + createPreGloDeltaMatrix(delGloPre); + const AlignableVolume* par = this; + while( (par=par->getParent()) ) { + TGeoHMatrix parDelGlo; + par->createGloDeltaMatrix(parDelGlo); + matX *= parDelGlo; + } + alg *= matX; + alg *= delGloPre; + alg *= matX.Inverse(); + // +} +*/ + +//_________________________________________________________________ +void AlignableVolume::createAlignmentObjects(TClonesArray* arr) const +{ + // add to supplied array alignment object for itself and children + TClonesArray& parr = *arr; + TGeoHMatrix algM; + createAlignmenMatrix(algM); + // new (parr[parr.GetEntriesFast()]) AliAlignObjParams(GetName(), getVolID(), algM, true); + const double* translation = algM.GetTranslation(); + const double* rotation = algM.GetRotationMatrix(); + new (parr[parr.GetEntriesFast()]) detectors::AlignParam(GetName(), getVolID(), + translation[0], translation[1], translation[2], + rotation[0], rotation[1], rotation[2], true); + int nch = getNChildren(); + for (int ich = 0; ich < nch; ich++) { + getChild(ich)->createAlignmentObjects(arr); + } +} + +//_________________________________________________________________ +void AlignableVolume::updateL2GRecoMatrices(const TClonesArray* algArr, const TGeoHMatrix* cumulDelta) +{ + // recreate mMatL2GReco matrices from ideal L2G matrix and alignment objects + // used during data reconstruction. For the volume at level J we have + // L2G' = Delta_J * Delta_{J-1} *...* Delta_0 * L2GIdeal + // cumulDelta is Delta_{J-1} * ... * Delta_0, supplied by the parent + // + mMatL2GReco = mMatL2GIdeal; + // find alignment object for this volume + int nalg = algArr->GetEntriesFast(); + const detectors::AlignParam* par = nullptr; + for (int i = 0; i < nalg; i++) { + par = (detectors::AlignParam*)algArr->At(i); + if (!strcmp(par->getSymName().c_str(), getSymName())) { + break; + } + par = nullptr; + } + TGeoHMatrix delta; + if (!par) { + LOG(INFO) << "Alignment for " << getSymName() << " is absent in Reco-Time alignment object"; + } else { + delta = par->createMatrix(); + } + // par->GetMatrix(delta); + if (cumulDelta) { + delta *= *cumulDelta; + } + // + mMatL2GReco.MultiplyLeft(&delta); + // propagate to children + for (int ich = getNChildren(); ich--;) { + getChild(ich)->updateL2GRecoMatrices(algArr, &delta); + } + // +} + +//______________________________________________________ +bool AlignableVolume::ownsDOFID(int id) const +{ + // check if DOF ID belongs to this volume or its children + if (id >= mFirstParGloID && id < mFirstParGloID + mNDOFs) { + return true; + } + // + for (int iv = getNChildren(); iv--;) { + AlignableVolume* vol = getChild(iv); + if (vol->ownsDOFID(id)) { + return true; + } + } + return false; +} + +//______________________________________________________ +AlignableVolume* AlignableVolume::getVolOfDOFID(int id) const +{ + // gets volume owning this DOF ID + if (id >= mFirstParGloID && id < mFirstParGloID + mNDOFs) { + return (AlignableVolume*)this; + } + // + for (int iv = getNChildren(); iv--;) { + AlignableVolume* vol = getChild(iv); + if ((vol = vol->getVolOfDOFID(id))) { + return vol; + } + } + return nullptr; +} + +//______________________________________________________ +const char* AlignableVolume::getDOFName(int i) const +{ + // get name of DOF + return getGeomDOFName(i); +} + +//______________________________________________________ +void AlignableVolume::fillDOFStat(DOFStatistics& h) const +{ + // fill statistics info hist + int ndf = getNDOFs(); + int dof0 = getFirstParGloID(); + int stat = getNProcessedPoints(); + for (int idf = 0; idf < ndf; idf++) { + int dof = idf + dof0; + h.addStat(dof, stat); + } +} + +//________________________________________ +void AlignableVolume::addAutoConstraints(TObjArray* constrArr) +{ + // adds automatic constraints + int nch = getNChildren(); + // + if (hasChildrenConstraint()) { + GeometricalConstraint* constr = new GeometricalConstraint(); + constr->setConstrainPattern(mConstrChild); + constr->setParent(this); + for (int ich = nch; ich--;) { + AlignableVolume* child = getChild(ich); + if (child->getExcludeFromParentConstraint()) { + continue; + } + constr->addChild(child); + } + if (constr->getNChildren()) { + constrArr->Add(constr); + } else { + delete constr; + } + } + for (int ich = 0; ich < nch; ich++) { + getChild(ich)->addAutoConstraints(constrArr); + } +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignmentPoint.cxx b/Detectors/Align/src/AlignmentPoint.cxx new file mode 100644 index 0000000000000..4034e3ca4e678 --- /dev/null +++ b/Detectors/Align/src/AlignmentPoint.cxx @@ -0,0 +1,409 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignmentPoint.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Meausered point in the sensor. + +#include <cstdio> +#include <TMath.h> +#include <TString.h> +#include "Align/AlignmentPoint.h" + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_____________________________________ +AlignmentPoint::AlignmentPoint() + : mMinLocVarID(0), mMaxLocVarID(0), mDetID(-1), mSID(-1), mAlphaSens(0), mXSens(0), mCosDiagErr(0), mSinDiagErr(0), mX2X0(0), mXTimesRho(0), mNGloDOFs(0), mDGloOffs(0), mSensor(nullptr) +{ + // def c-tor + for (int i = 3; i--;) { + mXYZTracking[i] = 0; + mErrYZTracking[i] = 0; + } + memset(mMatCorrExp, 0, 5 * sizeof(float)); + memset(mMatCorrCov, 0, 5 * sizeof(float)); + memset(mMatDiag, 0, 5 * 5 * sizeof(float)); + // + memset(mTrParamWSA, 0, 5 * sizeof(double)); + memset(mTrParamWSB, 0, 5 * sizeof(double)); + // +} + +//_____________________________________ +void AlignmentPoint::init() +{ + // compute aux info + const double kCorrToler = 1e-6; + const double kDiagToler = 1e-14; + // + // compute parameters of tranformation to diagonal error matrix + if (!isZeroPos(mErrYZTracking[0] + mErrYZTracking[2])) { + // + // is there a correlation? + if (smallerAbs(mErrYZTracking[1] * mErrYZTracking[1] / (mErrYZTracking[0] * mErrYZTracking[2]), kCorrToler)) { + mCosDiagErr = 1.; + mSinDiagErr = 0.; + mErrDiag[0] = mErrYZTracking[0]; + mErrDiag[1] = mErrYZTracking[2]; + } else { + double dfd = 0.5 * (mErrYZTracking[2] - mErrYZTracking[0]); + double phi = 0; + // special treatment if errors are equal + if (Abs(dfd) < kDiagToler) { + phi = mErrYZTracking[1] > 0 ? (Pi() * 0.25) : (Pi() * 0.75); + } else { + phi = 0.5 * ATan2(mErrYZTracking[1], dfd); + } + // + mCosDiagErr = Cos(phi); + mSinDiagErr = Sin(phi); + // + // double det = dfd*dfd + mErrYZTracking[1]*mErrYZTracking[1]; + // det = det>0 ? Sqrt(det) : 0; + // double smd = 0.5*(mErrYZTracking[0] + mErrYZTracking[2]); + // mErrDiag[0] = smd + det; + // mErrDiag[1] = smd - det; + double xterm = 2 * mCosDiagErr * mSinDiagErr * mErrYZTracking[1]; + double cc = mCosDiagErr * mCosDiagErr; + double ss = mSinDiagErr * mSinDiagErr; + mErrDiag[0] = mErrYZTracking[0] * cc + mErrYZTracking[2] * ss - xterm; + mErrDiag[1] = mErrYZTracking[0] * ss + mErrYZTracking[2] * cc + xterm; + } + } + // +} + +//_____________________________________ +void AlignmentPoint::updatePointByTrackInfo(const trackParam_t* t) +{ + // // recalculate point errors using info about the track in the sensor tracking frame + mSensor->updatePointByTrackInfo(this, t); +} + +//_____________________________________ +void AlignmentPoint::Print(Option_t* opt) const +{ + // print + TString opts = opt; + opts.ToLower(); + printf("%cDet%d SID:%4d Alp:%+.3f X:%+9.4f Meas:%s Mat: ", isInvDir() ? '*' : ' ', + getDetID(), getSID(), getAlphaSens(), getXSens(), containsMeasurement() ? "ON" : "OFF"); + if (!containsMaterial()) { + printf("OFF\n"); + } else { + printf("x2X0: %.4f x*rho: %.4f | pars:[%3d:%3d)\n", getX2X0(), getXTimesRho(), getMinLocVarID(), getMaxLocVarID()); + } + // + if (opts.Contains("meas") && containsMeasurement()) { + printf(" MeasPnt: Xtr: %+9.4f Ytr: %+8.4f Ztr: %+9.4f | ErrYZ: %+e %+e %+e | %d DOFglo\n", + getXTracking(), getYTracking(), getZTracking(), + mErrYZTracking[0], mErrYZTracking[1], mErrYZTracking[2], getNGloDOFs()); + printf(" DiagErr: %+e %+e\n", mErrDiag[0], mErrDiag[1]); + } + // + if (opts.Contains("mat") && containsMaterial()) { + printf(" MatCorr Exp(ELOSS): %+.4e %+.4e %+.4e %+.4e %+.4e\n", + mMatCorrExp[0], mMatCorrExp[1], mMatCorrExp[2], mMatCorrExp[3], mMatCorrExp[4]); + printf(" MatCorr Cov (diag): %+.4e %+.4e %+.4e %+.4e %+.4e\n", + mMatCorrCov[0], mMatCorrCov[1], mMatCorrCov[2], mMatCorrCov[3], mMatCorrCov[4]); + // + if (opts.Contains("umat")) { + float covUndiag[15]; + memset(covUndiag, 0, 15 * sizeof(float)); + int np = getNMatPar(); + for (int i = 0; i < np; i++) { + for (int j = 0; j <= i; j++) { + double val = 0; + for (int k = np; k--;) { + val += mMatDiag[i][k] * mMatDiag[j][k] * mMatCorrCov[k]; + } + int ij = (i * (i + 1) / 2) + j; + covUndiag[ij] = val; + } + } + if (np < kNMatDOFs) { + covUndiag[14] = mMatCorrCov[4]; + } // eloss was fixed + printf(" MatCorr Cov in normal form:\n"); + printf(" %+e\n", covUndiag[0]); + printf(" %+e %+e\n", covUndiag[1], covUndiag[2]); + printf(" %+e %+e %+e\n", covUndiag[3], covUndiag[4], covUndiag[5]); + printf(" %+e %+e %+e %+e\n", covUndiag[6], covUndiag[7], covUndiag[8], covUndiag[9]); + printf(" %+e %+e %+e %+e +%e\n", covUndiag[10], covUndiag[11], covUndiag[12], covUndiag[13], covUndiag[14]); + } + } + // + if (opts.Contains("diag") && containsMaterial()) { + printf(" Matrix for Mat.corr.errors diagonalization:\n"); + int npar = getNMatPar(); + for (int i = 0; i < npar; i++) { + for (int j = 0; j < npar; j++) { + printf("%+.4e ", mMatDiag[i][j]); + } + printf("\n"); + } + } + // + if (opts.Contains("wsa")) { // printf track state at this point stored during residuals calculation + printf(" Local Track (A): "); + for (int i = 0; i < 5; i++) { + printf("%+.3e ", mTrParamWSA[i]); + } + printf("\n"); + } + if (opts.Contains("wsb")) { // printf track state at this point stored during residuals calculation + printf(" Local Track (B): "); + for (int i = 0; i < 5; i++) { + printf("%+.3e ", mTrParamWSB[i]); + } + printf("\n"); + } + // +} + +//_____________________________________ +void AlignmentPoint::dumpCoordinates() const +{ + // dump various corrdinates for inspection + // global xyz + dim3_t xyz; + getXYZGlo(xyz.data()); + + auto print3d = [](dim3_t& xyz) { + for (auto i : xyz) { + printf("%+.4e ", i); + } + }; + + print3d(xyz); + trackParam_t wsb; + trackParam_t wsa; + getTrWSB(wsb); + getTrWSA(wsa); + + wsb.getXYZGlo(xyz); + print3d(xyz); // track before mat corr + + wsa.getXYZGlo(xyz); + print3d(xyz); // track after mat corr + + printf("%+.4f ", mAlphaSens); + printf("%+.4e ", getXPoint()); + printf("%+.4e ", getYTracking()); + printf("%+.4e ", getZTracking()); + // + printf("%+.4e %.4e ", wsb.getY(), wsb.getZ()); + printf("%+.4e %.4e ", wsa.getY(), wsa.getZ()); + // + printf("%4e %4e", Sqrt(mErrYZTracking[0]), Sqrt(mErrYZTracking[2])); + printf("\n"); +} + +//_____________________________________ +void AlignmentPoint::Clear(Option_t*) +{ + // reset the point + ResetBit(0xfffffff); + mMaxLocVarID = -1; + mDetID = -1; + mSID = -1; + mNGloDOFs = 0; + mDGloOffs = 0; + mSensor = nullptr; +} + +//__________________________________________________________________ +int AlignmentPoint::Compare(const TObject* b) const +{ + // sort points in direction opposite to track propagation, i.e. + // 1) for tracks from collision: range in decreasing tracking X + // 2) for cosmic tracks: upper leg (pnt->isInvDir()==true) ranged in increasing X + // lower leg - in decreasing X + AlignmentPoint* pnt = (AlignmentPoint*)b; + double x = getXPoint(); + double xp = pnt->getXPoint(); + if (!isInvDir()) { // track propagates from low to large X via this point + if (!pnt->isInvDir()) { // via this one also + return x > xp ? -1 : 1; + } else { + return -1; + } // range points of lower leg 1st + } else { // this point is from upper cosmic leg: track propagates from large to low X + if (pnt->isInvDir()) { // this one also + return x > xp ? 1 : -1; + } else { + return 1; + } // other point is from lower leg + } + // +} + +//__________________________________________________________________ +void AlignmentPoint::getXYZGlo(double r[3]) const +{ + // position in lab frame + double cs = TMath::Cos(mAlphaSens); + double sn = TMath::Sin(mAlphaSens); + double x = getXPoint(); + r[0] = x * cs - getYTracking() * sn; + r[1] = x * sn + getYTracking() * cs; + r[2] = getZTracking(); + // +} + +//__________________________________________________________________ +double AlignmentPoint::getPhiGlo() const +{ + // phi angle (-pi:pi) in global frame + double xyz[3]; + getXYZGlo(xyz); + return ATan2(xyz[1], xyz[0]); +} + +//__________________________________________________________________ +int AlignmentPoint::getAliceSector() const +{ + // get global sector ID corresponding to this point phi + return phi2Sector(getPhiGlo()); +} + +//__________________________________________________________________ +void AlignmentPoint::setMatCovDiagonalizationMatrix(const TMatrixD& d) +{ + // save non-sym matrix for material corrections cov.matrix diagonalization + // (actually, the eigenvectors are stored) + int sz = d.GetNrows(); + for (int i = sz; i--;) { + for (int j = sz; j--;) { + mMatDiag[i][j] = d(i, j); + } + } +} + +//__________________________________________________________________ +void AlignmentPoint::setMatCovDiag(const TVectorD& v) +{ + // save material correction diagonalized matrix + // (actually, the eigenvalues are stored w/o reordering them to correspond to the + // AliExternalTrackParam variables) + for (int i = v.GetNrows(); i--;) { + mMatCorrCov[i] = v(i); + } +} + +//__________________________________________________________________ +void AlignmentPoint::unDiagMatCorr(const double* diag, double* nodiag) const +{ + // transform material corrections from the frame diagonalizing the errors to point frame + // nodiag = mMatDiag * diag + int np = getNMatPar(); + for (int ip = np; ip--;) { + double v = 0; + for (int jp = np; jp--;) { + v += mMatDiag[ip][jp] * diag[jp]; + } + nodiag[ip] = v; + } + // +} + +//__________________________________________________________________ +void AlignmentPoint::unDiagMatCorr(const float* diag, float* nodiag) const +{ + // transform material corrections from the frame diagonalizing the errors to point frame + // nodiag = mMatDiag * diag + int np = getNMatPar(); + for (int ip = np; ip--;) { + double v = 0; + for (int jp = np; jp--;) { + v += double(mMatDiag[ip][jp]) * diag[jp]; + } + nodiag[ip] = v; + } + // +} + +//__________________________________________________________________ +void AlignmentPoint::diagMatCorr(const double* nodiag, double* diag) const +{ + // transform material corrections from the AliExternalTrackParam frame to + // the frame diagonalizing the errors + // diag = mMatDiag^T * nodiag + int np = getNMatPar(); + for (int ip = np; ip--;) { + double v = 0; + for (int jp = np; jp--;) { + v += mMatDiag[jp][ip] * nodiag[jp]; + } + diag[ip] = v; + } + // +} + +//__________________________________________________________________ +void AlignmentPoint::diagMatCorr(const float* nodiag, float* diag) const +{ + // transform material corrections from the AliExternalTrackParam frame to + // the frame diagonalizing the errors + // diag = mMatDiag^T * nodiag + int np = getNMatPar(); + for (int ip = np; ip--;) { + double v = 0; + for (int jp = np; jp--;) { + v += double(mMatDiag[jp][ip]) * nodiag[jp]; + } + diag[ip] = v; + } + // +} + +//__________________________________________________________________ +void AlignmentPoint::getTrWSA(trackParam_t& etp) const +{ + // assign WSA (after material corrections) parameters to supplied track + const trackParam_t::covMat_t covDum{ + 1.e-4, + 0, 1.e-4, + 0, 0, 1.e-4, + 0, 0, 0, 1.e-4, + 0, 0, 0, 0, 1e-4}; + params_t tmp; + std::copy(std::begin(mTrParamWSA), std::end(mTrParamWSA), std::begin(tmp)); + + etp.set(getXPoint(), getAlphaSens(), tmp, covDum); +} + +//__________________________________________________________________ +void AlignmentPoint::getTrWSB(trackParam_t& etp) const +{ + // assign WSB parameters (before material corrections) to supplied track + const trackParam_t::covMat_t covDum{ + 1.e-4, + 0, 1.e-4, + 0, 0, 1.e-4, + 0, 0, 0, 1.e-4, + 0, 0, 0, 0, 1e-4}; + params_t tmp; + std::copy(std::begin(mTrParamWSB), std::end(mTrParamWSB), std::begin(tmp)); + + etp.set(getXPoint(), getAlphaSens(), tmp, covDum); +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignmentTrack.cxx b/Detectors/Align/src/AlignmentTrack.cxx new file mode 100644 index 0000000000000..039b19685c654 --- /dev/null +++ b/Detectors/Align/src/AlignmentTrack.cxx @@ -0,0 +1,1516 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignmentTrack.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Track model for the alignment + +#include <cstdio> +#include "Align/AlignmentTrack.h" +#include "Framework/Logger.h" +#include "Align/AlignableSensor.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableDetector.h" +#include "Align/utils.h" +#include <TMatrixD.h> +#include <TVectorD.h> +#include <TMatrixDSymEigen.h> + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +// RS: this is not good: we define constants outside the class, but it is to +// bypass the CINT limitations on static arrays initializations +const int kRichardsonOrd = 1; // Order of Richardson extrapolation for derivative (min=1) +const int kRichardsonN = kRichardsonOrd + 1; // N of 2-point symmetric derivatives needed for requested order +const int kNRDClones = kRichardsonN * 2; // number of variations for derivative of requested order + +//____________________________________________________________________________ +AlignmentTrack::AlignmentTrack() : TrackParametrizationWithError<double>(), TObject(), mNLocPar(0), mNLocExtPar(0), mNGloPar(0), mNDF(0), mInnerPointID(0), + // ,mMinX2X0Pt2Account(5/1.0), + mMinX2X0Pt2Account(0.5e-3 / 1.0), + mMass(0.14), + mChi2(0), + mChi2CosmUp(0), + mChi2CosmDn(0), + mChi2Ini(0), + mPoints(0), + mLocPar(), + mGloParID(0), + mGloParIDA(nullptr), + mLocParA(nullptr) +{ + // def c-tor + for (int i = 0; i < 2; i++) { + // we start with 0 size buffers for derivatives, they will be expanded automatically + mResid[i].Set(0); + mDResDGlo[i].Set(0); + mDResDLoc[i].Set(0); + // + mResidA[i] = nullptr; + mDResDLocA[i] = nullptr; + mDResDGloA[i] = nullptr; + } + mNeedInv[0] = mNeedInv[1] = false; + // +} + +//____________________________________________________________________________ +void AlignmentTrack::Clear(Option_t*) +{ + // reset the track + TObject::Clear(); + ResetBit(0xffffffff); + mPoints.Clear(); + mChi2 = mChi2CosmUp = mChi2CosmDn = mChi2Ini = 0; + mNDF = 0; + mInnerPointID = -1; + mNeedInv[0] = mNeedInv[1] = false; + mNLocPar = mNLocExtPar = mNGloPar = 0; + // +} + +//____________________________________________________________________________ +void AlignmentTrack::defineDOFs() +{ + // define varied DOF's (local parameters) for the track: + // 1) kinematic params (5 or 4 depending on Bfield) + // 2) mult. scattering angles (2) + // 3) if requested by point: energy loss + // + mNLocPar = mNLocExtPar = getFieldON() ? kNKinParBON : kNKinParBOFF; + int np = getNPoints(); + // + // the points are sorted in order opposite to track direction -> outer points come 1st, + // but for the 2-leg cosmic track the innermost points are in the middle (1st lower leg, then upper one) + // + // start along track direction, i.e. last point in the ordered array + int minPar = mNLocPar; + for (int ip = getInnerPointID() + 1; ip--;) { // collision track or cosmic lower leg + AlignmentPoint* pnt = getPoint(ip); + pnt->setMinLocVarID(minPar); + if (pnt->containsMaterial()) { + mNLocPar += pnt->getNMatPar(); + } + pnt->setMaxLocVarID(mNLocPar); // flag up to which parameted ID this points depends on + } + // + if (isCosmic()) { + minPar = mNLocPar; + for (int ip = getInnerPointID() + 1; ip < np; ip++) { // collision track or cosmic lower leg + AlignmentPoint* pnt = getPoint(ip); + pnt->setMinLocVarID(minPar); + if (pnt->containsMaterial()) { + mNLocPar += pnt->getNMatPar(); + } + pnt->setMaxLocVarID(mNLocPar); // flag up to which parameted ID this points depends on + } + } + // + if (mLocPar.GetSize() < mNLocPar) { + mLocPar.Set(mNLocPar); + } + mLocPar.Reset(); + mLocParA = mLocPar.GetArray(); + // + if (mResid[0].GetSize() < np) { + mResid[0].Set(np); + mResid[1].Set(np); + } + if (mDResDLoc[0].GetSize() < mNLocPar * np) { + mDResDLoc[0].Set(mNLocPar * np); + mDResDLoc[1].Set(mNLocPar * np); + } + for (int i = 2; i--;) { + mResid[i].Reset(); + mDResDLoc[i].Reset(); + mResidA[i] = mResid[i].GetArray(); + mDResDLocA[i] = mDResDLoc[i].GetArray(); + } + // + // memcpy(mLocParA,GetParameter(),mNLocExtPar*sizeof(double)); + memset(mLocParA, 0, mNLocExtPar * sizeof(double)); +} + +//______________________________________________________ +bool AlignmentTrack::calcResidDeriv(double* params) +{ + // Propagate for given local params and calculate residuals and their derivatives. + // The 1st 4 or 5 elements of params vector should be the reference trackParam_t + // Then parameters of material corrections for each point + // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed). + // They correspond to kink parameters + // (trackParam_t_after_material - trackParam_t_before_material) + // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t + // increment will be done locally in the applyMatCorr routine. + // + // If params are not provided, use internal params array + // + if (!params) { + params = mLocParA; + } + // + if (!getResidDone()) { + calcResiduals(params); + } + // + int np = getNPoints(); + // + // collision track or cosmic lower leg + if (!calcResidDeriv(params, mNeedInv[0], getInnerPointID(), 0)) { +#if DEBUG > 3 + LOG(warn) << "Failed on derivatives calculation 0"; +#endif + return false; + } + // + if (isCosmic()) { // cosmic upper leg + if (!calcResidDeriv(params, mNeedInv[1], getInnerPointID() + 1, np - 1)) { +#if DEBUG > 3 + LOG(warn) << "Failed on derivatives calculation 0"; +#endif + } + } + // + setDerivDone(); + return true; +} + +//______________________________________________________ +bool AlignmentTrack::calcResidDeriv(double* extendedParams, bool invert, int pFrom, int pTo) +{ + // Calculate derivatives of residuals vs params for points pFrom to pT. For cosmic upper leg + // track parameter may require inversion. + // The 1st 4 or 5 elements of params vector should be the reference trackParam_t + // Then parameters of material corrections for each point + // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed). + // They correspond to kink parameters + // (trackParam_t_after_material - trackParam_t_before_material) + // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t + // increment will be done locally in the applyMatCorr routine. + // + // The derivatives are calculated using Richardson extrapolation + // (like http://root.cern.ch/root/html/ROOT__Math__RichardsonDerivator.html) + // + trackParam_t probD[kNRDClones]; // use this to vary supplied param for derivative calculation + double varDelta[kRichardsonN]; + const int kInvElem[kNKinParBON] = {-1, 1, 1, -1, -1}; + // + const double kDelta[kNKinParBON] = {0.02, 0.02, 0.001, 0.001, 0.01}; // variations for ExtTrackParam and material effects + // + double delta[kNKinParBON]; // variations of curvature term are relative + for (int i = kNKinParBOFF; i--;) { + delta[i] = kDelta[i]; + } + if (getFieldON()) { + delta[kParQ2Pt] = kDelta[kParQ2Pt] * Abs(getQ2Pt()); + } + // + int pinc; + if (pTo > pFrom) { // fit in points decreasing order: cosmics upper leg + pTo++; + pinc = 1; + } else { // fit in points increasing order: collision track or cosmics lower leg + pTo--; + pinc = -1; + } + + // 1) derivative wrt trackParam_t parameters + for (int ipar = mNLocExtPar; ipar--;) { + + setParams(probD, kNRDClones, getX(), getAlpha(), extendedParams, true); + if (invert) { + for (int ic = kNRDClones; ic--;) { + probD[ic].invert(); + } + } + double del = delta[ipar]; + // + for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4... + varDelta[icl] = del; + modParam(probD[(icl << 1) + 0], ipar, del); + modParam(probD[(icl << 1) + 1], ipar, -del); + del *= 0.5; + } + // propagate varied tracks to each point + for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction + AlignmentPoint* pnt = getPoint(ip); + if (!propagateParamToPoint(probD, kNRDClones, pnt)) { + return false; + } + // if (pnt->containsMaterial()) { // apply material corrections + if (!applyMatCorr(probD, kNRDClones, extendedParams, pnt)) { + return false; + } + // } + // + if (pnt->containsMeasurement()) { + int offsDer = ip * mNLocPar + ipar; + richardsonDeriv(probD, varDelta, pnt, mDResDLocA[0][offsDer], mDResDLocA[1][offsDer]); // calculate derivatives + if (invert && kInvElem[ipar] < 0) { + mDResDLocA[0][offsDer] = -mDResDLocA[0][offsDer]; + mDResDLocA[1][offsDer] = -mDResDLocA[1][offsDer]; + } + } + } // loop over points + } // loop over ExtTrackParam parameters + // + // 2) now vary material effect related parameters: MS and eventually ELoss + // + for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction + AlignmentPoint* pnt = getPoint(ip); + // + // global derivatives at this point + if (pnt->containsMeasurement() && !calcResidDerivGlo(pnt)) { +#if DEBUG > 3 + AliWarningF("Failed on global derivatives calculation at point %d", ip); + pnt->print("meas"); +#endif + return false; + } + // + if (!pnt->containsMaterial()) { + continue; + } + // + int nParFreeI = pnt->getNMatPar(); + // + // array delta gives desired variation of parameters in trackParam_t definition, + // while the variation should be done for parameters in the frame where the vector + // of material corrections has diagonal cov. matrix -> rotate the delta to this frame + double deltaMatD[kNKinParBON]; + pnt->diagMatCorr(delta, deltaMatD); + // + // printf("Vary %d [%+.3e %+.3e %+.3e %+.3e] ",ip,deltaMatD[0],deltaMatD[1],deltaMatD[2],deltaMatD[3]); pnt->print(); + + int offsI = pnt->getMaxLocVarID() - nParFreeI; // the parameters for this point start with this offset + // they are irrelevant for the points upstream + for (int ipar = 0; ipar < nParFreeI; ipar++) { // loop over DOFs related to MS and ELoss are point ip + double del = deltaMatD[ipar]; + // + // We will vary the tracks starting from the original parameters propagated to given point + // and stored there (before applying material corrections for this point) + // + setParams(probD, kNRDClones, pnt->getXPoint(), pnt->getAlphaSens(), pnt->getTrParamWSB(), false); + // no need for eventual track inversion here: if needed, this is already done in ParamWSB + // + int offsIP = offsI + ipar; // parameter entry in the extendedParams array + // printf(" Var:%d (%d) %e\n",ipar,offsIP, del); + + for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4... + varDelta[icl] = del; + double parOrig = extendedParams[offsIP]; + extendedParams[offsIP] += del; + // + // apply varied material effects : incremented by delta + if (!applyMatCorr(probD[(icl << 1) + 0], extendedParams, pnt)) { + return false; + } + // + // apply varied material effects : decremented by delta + extendedParams[offsIP] = parOrig - del; + if (!applyMatCorr(probD[(icl << 1) + 1], extendedParams, pnt)) { + return false; + } + // + extendedParams[offsIP] = parOrig; + del *= 0.5; + } + if (pnt->containsMeasurement()) { // calculate derivatives at the scattering point itself + int offsDerIP = ip * mNLocPar + offsIP; + richardsonDeriv(probD, varDelta, pnt, mDResDLocA[0][offsDerIP], mDResDLocA[1][offsDerIP]); // calculate derivatives for ip + // printf("DR SELF: %e %e at %d (%d)\n",mDResDLocA[0][offsDerIP], mDResDLocA[1][offsDerIP],offsI, offsDerIP); + } + // + // loop over points whose residuals can be affected by the material effects on point ip + for (int jp = ip + pinc; jp != pTo; jp += pinc) { + AlignmentPoint* pntJ = getPoint(jp); + + // printf(" DerFor:%d ",jp); pntJ->print(); + + if (!propagateParamToPoint(probD, kNRDClones, pntJ)) { + return false; + } + // + if (pntJ->containsMaterial()) { // apply material corrections + if (!applyMatCorr(probD, kNRDClones, extendedParams, pntJ)) { + return false; + } + } + // + if (pntJ->containsMeasurement()) { + int offsDerJ = jp * mNLocPar + offsIP; + // calculate derivatives + richardsonDeriv(probD, varDelta, pntJ, mDResDLocA[0][offsDerJ], mDResDLocA[1][offsDerJ]); + } + // + } // << loop over points whose residuals can be affected by the material effects on point ip + } // << loop over DOFs related to MS and ELoss are point ip + } // << loop over all points of the track + // + return true; +} + +//______________________________________________________ +bool AlignmentTrack::calcResidDerivGlo(AlignmentPoint* pnt) +{ + // calculate residuals derivatives over point's sensor and its parents global params + double deriv[AlignableVolume::kNDOFGeom * 3]; + // + const AlignableSensor* sens = pnt->getSensor(); + const AlignableVolume* vol = sens; + // precalculated track parameters + double snp = pnt->getTrParamWSA(kParSnp), tgl = pnt->getTrParamWSA(kParTgl); + // precalculate track slopes to account tracking X veriation + // these are coeffs to translate deltaX of the point to deltaY and deltaZ of track + double cspi = 1. / Sqrt((1 - snp) * (1 + snp)), slpY = snp * cspi, slpZ = tgl * cspi; + // + pnt->setDGloOffs(mNGloPar); // mark 1st entry of derivatives + do { + // measurement residuals + int nfree = vol->getNDOFsFree(); + if (!nfree) { + continue; + } // no free parameters? + sens->dPosTraDParGeom(pnt, deriv, vol == sens ? nullptr : vol); + // + checkExpandDerGloBuffer(mNGloPar + nfree); // if needed, expand derivatives buffer + // + for (int ip = 0; ip < AlignableVolume::kNDOFGeom; ip++) { // we need only free parameters + if (!vol->isFreeDOF(ip)) { + continue; + } + double* dXYZ = &deriv[ip * 3]; // tracking XYZ derivatives over this parameter + // residual is defined as diagonalized track_estimate - measured Y,Z in tracking frame + // where the track is evaluated at measured X! + // -> take into account modified X using track parameterization at the point (paramWSA) + // Attention: small simplifications(to be checked if it is ok!!!): + // effect of changing X is accounted neglecting track curvature to preserve linearity + // + // store diagonalized residuals in track buffer + pnt->diagonalizeResiduals((dXYZ[AlignmentPoint::kX] * slpY - dXYZ[AlignmentPoint::kY]), + (dXYZ[AlignmentPoint::kX] * slpZ - dXYZ[AlignmentPoint::kZ]), + mDResDGloA[0][mNGloPar], mDResDGloA[1][mNGloPar]); + // and register global ID of varied parameter + mGloParIDA[mNGloPar] = vol->getParGloID(ip); + mNGloPar++; + } + // + } while ((vol = vol->getParent())); + // + // eventual detector calibration parameters + const AlignableDetector* det = sens->getDetector(); + int ndof = 0; + if (det && (ndof = det->getNCalibDOFs())) { + // if needed, expand derivatives buffer + checkExpandDerGloBuffer(mNGloPar + det->getNCalibDOFsFree()); + for (int idf = 0; idf < ndof; idf++) { + if (!det->isFreeDOF(idf)) { + continue; + } + sens->dPosTraDParCalib(pnt, deriv, idf, nullptr); + pnt->diagonalizeResiduals((deriv[AlignmentPoint::kX] * slpY - deriv[AlignmentPoint::kY]), + (deriv[AlignmentPoint::kX] * slpZ - deriv[AlignmentPoint::kZ]), + mDResDGloA[0][mNGloPar], mDResDGloA[1][mNGloPar]); + // and register global ID of varied parameter + mGloParIDA[mNGloPar] = det->getParGloID(idf); + mNGloPar++; + } + } + // + pnt->setNGloDOFs(mNGloPar - pnt->getDGloOffs()); // mark number of global derivatives filled + // + return true; +} + +//______________________________________________________ +bool AlignmentTrack::calcResiduals(const double* extendedParams) +{ + // Propagate for given local params and calculate residuals + // The 1st 4 or 5 elements of extendedParams vector should be the reference trackParam_t + // Then parameters of material corrections for each point + // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed). + // They correspond to kink parameters + // (trackParam_t_after_material - trackParam_t_before_material) + // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t + // increment will be done locally in the applyMatCorr routine. + // + // If extendedParams are not provided, use internal extendedParams array + // + if (!extendedParams) { + extendedParams = mLocParA; + } + int np = getNPoints(); + mChi2 = 0; + mNDF = 0; + // + // collision track or cosmic lower leg + if (!calcResiduals(extendedParams, mNeedInv[0], getInnerPointID(), 0)) { +#if DEBUG > 3 + LOG(warn) << "Failed on residuals calculation 0"; +#endif + return false; + } + // + if (isCosmic()) { // cosmic upper leg + if (!calcResiduals(extendedParams, mNeedInv[1], getInnerPointID() + 1, np - 1)) { +#if DEBUG > 3 + LOG(warn) << "Failed on residuals calculation 1"; +#endif + return false; + } + } + // + mNDF -= mNLocExtPar; + setResidDone(); + return true; +} + +//______________________________________________________ +bool AlignmentTrack::calcResiduals(const double* extendedParams, bool invert, int pFrom, int pTo) +{ + // Calculate residuals for the single leg from points pFrom to pT + // The 1st 4 or 5 elements of extendedParams vector should be corrections to + // the reference trackParam_t + // Then parameters of material corrections for each point + // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed). + // They correspond to kink parameters + // (trackParam_t_after_material - trackParam_t_before_material) + // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t + // increment will be done locally in the applyMatCorr routine. + // + trackParam_t probe; + setParams(probe, getX(), getAlpha(), extendedParams, true); + if (invert) { + probe.invert(); + } + int pinc; + if (pTo > pFrom) { // fit in points decreasing order: cosmics upper leg + pTo++; + pinc = 1; + } else { // fit in points increasing order: collision track or cosmics lower leg + pTo--; + pinc = -1; + } + // + for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction + AlignmentPoint* pnt = getPoint(ip); + if (!propagateParamToPoint(probe, pnt)) { + return false; + } + // + // store the current track kinematics at the point BEFORE applying eventual material + // corrections. This kinematics will be later varied around supplied parameters (in the calcResidDeriv) + pnt->setTrParamWSB(probe.getParams()); + // + // account for materials + // if (pnt->ContainsMaterial()) { // apply material corrections + if (!applyMatCorr(probe, extendedParams, pnt)) { + return false; + } + // } + pnt->setTrParamWSA(probe.getParams()); + // + if (pnt->containsMeasurement()) { // need to calculate residuals in the frame where errors are orthogonal + pnt->getResidualsDiag(probe.getParams(), mResidA[0][ip], mResidA[1][ip]); + mChi2 += mResidA[0][ip] * mResidA[0][ip] / pnt->getErrDiag(0); + mChi2 += mResidA[1][ip] * mResidA[1][ip] / pnt->getErrDiag(1); + mNDF += 2; + } + // + if (pnt->containsMaterial()) { + // material degrees of freedom do not contribute to NDF since they are constrained by 0 expectation + int nCorrPar = pnt->getNMatPar(); + const double* corrDiag = &mLocParA[pnt->getMaxLocVarID() - nCorrPar]; // corrections in diagonalized frame + float* corCov = pnt->getMatCorrCov(); // correction diagonalized covariance + for (int i = 0; i < nCorrPar; i++) { + mChi2 += corrDiag[i] * corrDiag[i] / corCov[i]; + } + } + } + return true; +} + +//______________________________________________________ +bool AlignmentTrack::propagateParamToPoint(trackParam_t* tr, int nTr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt) +{ + // Propagate set of tracks to the point (only parameters, no error matrix) + // VECTORIZE this + // + for (int itr = nTr; itr--;) { + if (!propagateParamToPoint(tr[itr], pnt, maxStep)) { +#if DEBUG > 3 + LOG(fatal) << "Failed on clone " << itr << " propagation "; + tr[itr].print(); + pnt->print("meas mat"); +#endif + return false; + } + } + return true; +} + +//______________________________________________________ +bool AlignmentTrack::propagateParamToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt) +{ + // propagate tracks to the point (only parameters, no error matrix) + return propagate(tr, pnt, maxStep, maxSnp, mt, nullptr); +} + +//______________________________________________________ +bool AlignmentTrack::propagateToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT) +{ + // propagate tracks to the point. If matCor is true, then material corrections will be applied. + // if matPar pointer is provided, it will be filled by total x2x0 and signed xrho + return propagate(tr, pnt, maxStep, maxSnp, mt, tLT); +} + +bool AlignmentTrack::propagate(trackParam_t& track, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT) +{ + if (!track.rotate(pnt->getAlphaSens())) { +#if DEBUG > 3 + LOG(error) << "Failed to rotate to alpha=" << pnt->getAlphaSens(); + tr.print(); + pnt->Print(); +#endif + return false; + } + // calculate the sign of the energy loss correction and ensure the upper leg of cosmics is calculated correctly. + const int signCorr = [this, &pnt, &track, maxStep] { + const double dx = maxStep - track.getX(); + const int dir = dx > 0.f ? 1 : -1; + if (pnt->isInvDir()) { + // upper leg of a cosmic -> inward facing track + return dir; + } else { + // outward facing track + return -dir; + } + }(); + return Propagator::Instance()->propagateTo(track, pnt->getXPoint(), pnt->getUseBzOnly(), maxSnp, maxStep, mt, tLT, signCorr); +} + +/* +//______________________________________________________ +bool AlignmentTrack::ApplyMS(trackParam_t& trPar, double tms,double pms) +{ + //------------------------------------------------------------------------------ + // Modify track par (e.g. trackParam_t) in the tracking frame + // (dip angle lam, az. angle phi) + // by multiple scattering defined by polar and azumuthal scattering angles in + // the track collinear frame (tms and pms resp). + // The updated direction vector in the tracking frame becomes + // + // | Cos[lam]*Cos[phi] Cos[phi]*Sin[lam] -Sin[phi] | | Cos[tms] | + // | Cos[lam]*Sin[phi] Sin[lam]*Sin[phi] Cos[phi] | x | Cos[pms]*Sin[tms]| + // | Sin[lam] -Cos[lam] 0 | | Sin[pms]*Sin[tms]| + // + //------------------------------------------------------------------------------ + // + double *par = (double*) trPar.GetParameter(); + // + if (Abs(tms)<1e-7) return true; + // + double snTms = Sin(tms), csTms = Cos(tms); + double snPms = Sin(pms), csPms = Cos(pms); + double snPhi = par[2], csPhi = Sqrt((1.-snPhi)*(1.+snPhi)); + double csLam = 1./Sqrt(1.+par[3]*par[3]), snLam = csLam*par[3]; + // + double r00 = csLam*csPhi, r01 = snLam*csPhi, &r02 = snPhi; + double r10 = csLam*snPhi, r11 = snLam*snPhi, &r12 = csPhi; + double &r20 = snLam ,&r21 = csLam; + // + double &v0 = csTms, v1 = snTms*csPms, v2 = snTms*snPms; + // + double px = r00*v0 + r01*v1 - r02*v2; + double py = r10*v0 + r11*v1 + r12*v2; + double pz = r20*v0 - r21*v1; + // + double pt = Sqrt(px*px + py*py); + par[2] = py/pt; + par[3] = pz/pt; + par[4]*= csLam/pt; + // + return true; +} +*/ + +//______________________________________________________ +bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corrPar, const AlignmentPoint* pnt) +{ + // Modify track param (e.g. trackParam_t) in the tracking frame + // by delta accounting for material effects + // Note: corrPar contains delta to track parameters rotated by the matrix + // DIAGONALIZING ITS COVARIANCE MATRIX! + // transform parameters from the frame diagonalizing the errors to track frame + double corr[kNKinParBON] = {0}; + if (pnt->containsMaterial()) { // are there free params from meterials? + int nCorrPar = pnt->getNMatPar(); + const double* corrDiag = &corrPar[pnt->getMaxLocVarID() - nCorrPar]; // material corrections for this point start here + pnt->unDiagMatCorr(corrDiag, corr); // this is to account for MS and RANDOM Eloss (if varied) + } + // to this we should add expected parameters modification due to the deterministic eloss + float* detELoss = pnt->getMatCorrExp(); + for (int i = kNKinParBON; i--;) { + corr[i] += detELoss[i]; + } + //corr[kParQ2Pt] += detELoss[kParQ2Pt]; + // printf("apply corr UD %+.3e %+.3e %+.3e %+.3e %+.3e\n",corr[0],corr[1],corr[2],corr[3],corr[4]); + // printf(" corr D %+.3e %+.3e %+.3e %+.3e\n",corrDiag[0],corrDiag[1],corrDiag[2],corrDiag[3]); + // printf("at point :"); pnt->print(); + return applyMatCorr(trPar, corr); + // +} + +//______________________________________________________ +bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corr) +{ + // Modify track param (e.g. trackParam_t) in the tracking frame + // by delta accounting for material effects + // Note: corr contains delta to track frame, NOT in diagonalized one + const double kMaxSnp = 0.95; + + const double snp = trPar.getSnp() + corr[kParSnp]; + if (Abs(snp) > kMaxSnp) { +#if DEBUG > 3 + LOG(error) << "Snp is too large: " << snp; + printf("DeltaPar: "); + for (int i = 0; i < kNKinParBON; i++) { + printf("%+.3e ", corr[i]); + } + printf("\n"); + trPar.print(); +#endif + return false; + } + + trPar.updateParams(corr); + + return true; +} + +//______________________________________________________ +bool AlignmentTrack::applyMatCorr(trackParam_t* trSet, int ntr, const double* corrDiag, const AlignmentPoint* pnt) +{ + // Modify set of track params (e.g. trackParam_t) in the tracking frame + // by delta accounting for material effects + // Note: corrDiag contain delta to track parameters rotated by the matrix DIAGONALIZING ITS + // COVARIANCE MATRIX + // transform parameters from the frame diagonalizing the errors to track frame + double corr[kNKinParBON] = {0}; + if (pnt->containsMaterial()) { // are there free params from meterials? + int nCorrPar = pnt->getNMatPar(); + const double* corrDiagP = &corrDiag[pnt->getMaxLocVarID() - nCorrPar]; // material corrections for this point start here + pnt->unDiagMatCorr(corrDiagP, corr); + } + float* detELoss = pnt->getMatCorrExp(); + for (int i = kNKinParBON; i--;) { + corr[i] += detELoss[i]; + } + // if (!pnt->getELossVaried()) corr[kParQ2Pt] = pnt->getMatCorrExp()[kParQ2Pt]; // fixed eloss expected effect + // printf("apply corr UD %+.3e %+.3e %+.3e %+.3e\n",corr[0],corr[1],corr[2],corr[3]); + // printf(" corr D %+.3e %+.3e %+.3e %+.3e\n",corrDiagP[0],corrDiagP[1],corrDiagP[2],corrDiagP[3]); + // printf("at point :"); pnt->print(); + // + for (int itr = ntr; itr--;) { + if (!applyMatCorr(trSet[itr], corr)) { +#if DEBUG > 3 + LOG(error) << "Failed on clone %d materials" << itr; + trSet[itr].print(); +#endif + return false; + } + } + return true; +} + +//______________________________________________ +double AlignmentTrack::richardsonExtrap(double* val, int ord) +{ + // Calculate Richardson extrapolation of order ord (starting from 1) + // The array val should contain estimates ord+1 of derivatives with variations + // d, d/2 ... d/2^ord. + // The array val is overwritten + // + if (ord == 1) { + return (4. * val[1] - val[0]) * (1. / 3); + } + do { + for (int i = 0; i < ord; i++) { + val[i] = (4. * val[i + 1] - val[i]) * (1. / 3); + } + } while (--ord); + return val[0]; +} + +//______________________________________________ +double AlignmentTrack::richardsonExtrap(const double* val, int ord) +{ + // Calculate Richardson extrapolation of order ord (starting from 1) + // The array val should contain estimates ord+1 of derivatives with variations + // d, d/2 ... d/2^ord. + // The array val is not overwritten + // + if (ord == 1) { + return (4. * val[1] - val[0]) * (1. / 3); + } + double* buff = new double[ord + 1]; + memcpy(buff, val, (ord + 1) * sizeof(double)); + do { + for (int i = 0; i < ord; i++) { + buff[i] = (4. * buff[i + 1] - buff[i]) * (1. / 3); + } + } while (--ord); + return buff[0]; +} + +//______________________________________________ +void AlignmentTrack::richardsonDeriv(const trackParam_t* trSet, const double* delta, const AlignmentPoint* pnt, double& derY, double& derZ) +{ + // Calculate Richardson derivatives for diagonalized Y and Z from a set of kRichardsonN pairs + // of tracks with same parameter of i-th pair varied by +-delta[i] + static double derRichY[kRichardsonN], derRichZ[kRichardsonN]; + // + for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4... + double resYVP = 0, resYVN = 0, resZVP = 0, resZVN = 0; + pnt->getResidualsDiag(trSet[(icl << 1) + 0].getParams(), resYVP, resZVP); // variation with +delta + pnt->getResidualsDiag(trSet[(icl << 1) + 1].getParams(), resYVN, resZVN); // variation with -delta + derRichY[icl] = 0.5 * (resYVP - resYVN) / delta[icl]; // 2-point symmetric derivatives + derRichZ[icl] = 0.5 * (resZVP - resZVN) / delta[icl]; + } + derY = richardsonExtrap(derRichY, kRichardsonOrd); // dY/dPar + derZ = richardsonExtrap(derRichZ, kRichardsonOrd); // dZ/dPar + // +} + +//______________________________________________ +void AlignmentTrack::Print(Option_t* opt) const +{ + // print track data + printf("%s ", isCosmic() ? " Cosmic " : "Collision "); + trackParam_t::print(); + printf("N Free Par: %d (Kinem: %d) | Npoints: %d (Inner:%d) | M : %.3f | Chi2Ini:%.1f Chi2: %.1f/%d", + mNLocPar, mNLocExtPar, getNPoints(), getInnerPointID(), mMass, mChi2Ini, mChi2, mNDF); + if (isCosmic()) { + int npLow = getInnerPointID(); + int npUp = getNPoints() - npLow - 1; + printf(" [Low:%.1f/%d Up:%.1f/%d]", mChi2CosmDn, npLow, mChi2CosmUp, npUp); + } + printf("\n"); + // + TString optS = opt; + optS.ToLower(); + bool res = optS.Contains("r") && getResidDone(); + bool der = optS.Contains("d") && getDerivDone(); + bool par = optS.Contains("lc"); // local param corrections + bool paru = optS.Contains("lcu"); // local param corrections in track param frame + // + if (par) { + printf("Ref.track corr: "); + for (int i = 0; i < mNLocExtPar; i++) { + printf("%+.3e ", mLocParA[i]); + } + printf("\n"); + } + // + if (optS.Contains("p") || res || der) { + for (int ip = 0; ip < getNPoints(); ip++) { + printf("#%3d ", ip); + AlignmentPoint* pnt = getPoint(ip); + pnt->Print(opt); + // + if (res && pnt->containsMeasurement()) { + printf(" Residuals : %+.3e %+.3e -> Pulls: %+7.2f %+7.2f\n", + getResidual(0, ip), getResidual(1, ip), + getResidual(0, ip) / sqrt(pnt->getErrDiag(0)), getResidual(1, ip) / sqrt(pnt->getErrDiag(1))); + } + if (der && pnt->containsMeasurement()) { + for (int ipar = 0; ipar < mNLocPar; ipar++) { + printf(" Dres/dp%03d : %+.3e %+.3e\n", ipar, getDResDLoc(0, ip)[ipar], getDResDLoc(1, ip)[ipar]); + } + } + // + if (par && pnt->containsMaterial()) { // material corrections + int nCorrPar = pnt->getNMatPar(); + const double* corrDiag = &mLocParA[pnt->getMaxLocVarID() - nCorrPar]; + printf(" Corr.Diag: "); + for (int i = 0; i < nCorrPar; i++) { + printf("%+.3e ", corrDiag[i]); + } + printf("\n"); + printf(" Corr.Pull: "); + float* corCov = pnt->getMatCorrCov(); // correction covariance + //float *corExp = pnt->getMatCorrExp(); // correction expectation + for (int i = 0; i < nCorrPar; i++) { + printf("%+.3e ", (corrDiag[i] /* - corExp[i]*/) / Sqrt(corCov[i])); + } + printf("\n"); + if (paru) { // print also mat.corrections in track frame + double corr[5] = {0}; + pnt->unDiagMatCorr(corrDiag, corr); + // if (!pnt->getELossVaried()) corr[kParQ2Pt] = pnt->getMatCorrExp()[kParQ2Pt]; // fixed eloss expected effect + printf(" Corr.Track: "); + for (int i = 0; i < kNKinParBON; i++) { + printf("%+.3e ", corr[i]); + } + printf("\n"); + } + } + } + } // print points +} + +//______________________________________________ +void AlignmentTrack::dumpCoordinates() const +{ + // print various coordinates for inspection + printf("gpx/D:gpy/D:gpz/D:gtxb/D:gtyb/D:gtzb/D:gtxa/D:gtya/D:gtza/D:alp/D:px/D:py/D:pz/D:tyb/D:tzb/D:tya/D:tza/D:ey/D:ez/D\n"); + for (int ip = 0; ip < getNPoints(); ip++) { + AlignmentPoint* pnt = getPoint(ip); + if (!pnt->containsMeasurement()) { + continue; + } + pnt->dumpCoordinates(); + } +} + +//______________________________________________ +bool AlignmentTrack::iniFit() +{ + // perform initial fit of the track + // + // + trackParam_t trc = *this; + // + if (!getFieldON()) { // for field-off data impose nominal momentum + } + mChi2 = mChi2CosmUp = mChi2CosmDn = 0; + // + // the points are ranged from outer to inner for collision tracks, + // and from outer point of lower leg to outer point of upper leg for the cosmic track + // + // the fit will always start from the outgoing track in inward direction + if (!fitLeg(trc, 0, getInnerPointID(), mNeedInv[0])) { +#if DEBUG > 3 + LOG(warn) << "Failed fitLeg 0"; + trc.print(); +#endif + return false; // collision track or cosmic lower leg + } + // + // printf("Lower leg: %d %d\n",0,getInnerPointID()); trc.print(); + // + if (isCosmic()) { + mChi2CosmDn = mChi2; + trackParam_t trcU = trc; + if (!fitLeg(trcU, getNPoints() - 1, getInnerPointID() + 1, mNeedInv[1])) { //fit upper leg of cosmic track +#if DEBUG > 3 + LOG(warn) << "Failed fitLeg 0"; + trc.print(); +#endif + return false; // collision track or cosmic lower leg + } + // + // propagate to reference point, which is the inner point of lower leg + const AlignmentPoint* refP = getPoint(getInnerPointID()); + if (!propagateToPoint(trcU, refP, MaxDefStep, MaxDefSnp, DefMatCorrType)) { + return false; + } + // + mChi2CosmUp = mChi2 - mChi2CosmDn; + // printf("Upper leg: %d %d\n",getInnerPointID()+1,getNPoints()-1); trcU.print(); + // + if (!combineTracks(trc, trcU)) { + return false; + } + //printf("Combined\n"); trc.print(); + } + copyFrom(&trc); + // + mChi2Ini = mChi2; + + return true; +} + +//______________________________________________ +bool AlignmentTrack::combineTracks(trackParam_t& trcL, const trackParam_t& trcU) +{ + // Assign to trcL the combined tracks (Kalman update of trcL by trcU) + // The trcL and trcU MUST be defined at same X,Alpha + // + // Update equations: tracks described by vectors vL and vU and coviriances CL and CU resp. + // then the gain matrix K = CL*(CL+CU)^-1 + // Updated vector and its covariance: + // CL' = CL - K*CL + // vL' = vL + K(vU-vL) + // + if (Abs(trcL.getX() - trcU.getX()) > TinyDist || Abs(trcL.getAlpha() - trcU.getAlpha()) > TinyDist) { + LOG(error) << "Tracks must be defined at same reference X and Alpha"; + trcL.print(); + trcU.print(); + return false; + } + // + // const covMat_t& covU = trcU.getCov(); + // const covMat_t& covL = trcL.getCov(); + // + int mtSize = getFieldON() ? kNKinParBON : kNKinParBOFF; + TMatrixD matCL(mtSize, mtSize), matCLplCU(mtSize, mtSize); + TVectorD vl(mtSize), vUmnvL(mtSize); + // + // trcL.print(); + // trcU.print(); + // + for (int i = mtSize; i--;) { + vUmnvL[i] = trcU.getParam(i) - trcL.getParam(i); // y = residual of 2 tracks + vl[i] = trcL.getParam(i); + for (int j = i + 1; j--;) { + int indIJ = ((i * (i + 1)) >> 1) + j; // position of IJ cov element in the trackParam_t covariance array + matCL(i, j) = matCL(j, i) = trcL.getCovarElem(i, j); + matCLplCU(i, j) = matCLplCU(j, i) = trcL.getCovarElem(i, j) + trcU.getCovarElem(i, j); + } + } + matCLplCU.Invert(); // S^-1 = (Cl + Cu)^-1 + if (!matCLplCU.IsValid()) { +#if DEBUG > 3 + LOG(error) << "Failed to invert summed cov.matrix of cosmic track"; + matCLplCU.print(); +#endif + return false; // inversion failed + } + TMatrixD matK(matCL, TMatrixD::kMult, matCLplCU); // gain K = Cl*(Cl+Cu)^-1 + TMatrixD matKdotCL(matK, TMatrixD::kMult, matCL); // K*Cl + TVectorD vlUp = matK * vUmnvL; // K*(vl - vu) + for (int i = mtSize; i--;) { + trcL.updateParam(vlUp[i], i); // updated param: vL' = vL + K(vU-vL) + for (int j = i + 1; j--;) { + trcL.updateCov(-matKdotCL(i, j), i, j); + } // updated covariance: Cl' = Cl - K*Cl + } + // + // update chi2 + double chi2 = 0; + for (int i = mtSize; i--;) { + for (int j = mtSize; j--;) { + chi2 += matCLplCU(i, j) * vUmnvL[i] * vUmnvL[j]; + } + } + mChi2 += chi2; + // + // printf("Combined: Chi2Tot:%.2f ChiUp:%.2f ChiDn:%.2f ChiCmb:%.2f\n",mChi2,mChi2CosmUp,mChi2CosmDn, chi2); + + return true; +} + +//______________________________________________ +bool AlignmentTrack::fitLeg(trackParam_t& trc, int pFrom, int pTo, bool& inv) +{ + // perform initial fit of the track + // the fit will always start from the outgoing track in inward direction (i.e. if cosmics - bottom leg) + const int kMinNStep = 3; + const double MaxDefStep = 3.0; + const double kErrSpace = 50.; + const double kErrAng = 0.7; + const double kErrRelPtI = 1.; + const covMat_t kIniErr{// initial error + kErrSpace * kErrSpace, + 0, kErrSpace * kErrSpace, + 0, 0, kErrAng * kErrAng, + 0, 0, 0, kErrAng * kErrAng, + 0, 0, 0, 0, kErrRelPtI * kErrRelPtI}; + // + // prepare seed at outer point + AlignmentPoint* p0 = getPoint(pFrom); + double phi = trc.getPhi(), alp = p0->getAlphaSens(); + bringTo02Pi(phi); + bringTo02Pi(alp); + double dphi = deltaPhiSmall(phi, alp); // abs delta angle + if (dphi > Pi() / 2.) { // need to invert the track to new frame + inv = true; + // printf("Fit in %d %d Delta: %.3f -> Inverting for\n",pFrom,pTo,dphi); + // p0->print("meas"); + // printf("BeforeInv "); trc.print(); + trc.invert(); + // printf("After Inv "); trc.print(); + } + if (!trc.rotateParam(p0->getAlphaSens())) { +#if DEBUG > 3 + AliWarningF("Failed on rotateParam to %f", p0->getAlphaSens()); + trc.print(); +#endif + return false; + } + if (!propagateParamToPoint(trc, p0, MaxDefStep)) { + // if (!propagateToPoint(trc,p0,5,30,true)) { + //trc.PropagateParamOnlyTo(p0->getXPoint()+kOverShootX,AliTrackerBase::GetBz())) { +#if DEBUG > 3 + AliWarningF("Failed on PropagateParamOnlyTo to %f", p0->getXPoint() + kOverShootX); + trc.print(); +#endif + return false; + } + trc.setCov(kIniErr); + trc.setCov(trc.getQ2Pt() * trc.getQ2Pt(), 4, 4); // lowest diagonal element (Q2Pt2) + // + int pinc; + if (pTo > pFrom) { // fit in points increasing order: collision track or cosmics lower leg + pTo++; + pinc = 1; + } else { // fit in points decreasing order: cosmics upper leg + pTo--; + pinc = -1; + } + // + for (int ip = pFrom; ip != pTo; ip += pinc) { // inward fit from outer point + AlignmentPoint* pnt = getPoint(ip); + // + // printf("*** fitLeg %d (%d %d)\n",ip,pFrom,pTo); + // printf("Before propagate: "); trc.print(); + if (!propagateToPoint(trc, pnt, MaxDefStep, MaxDefSnp, DefMatCorrType)) { + return false; + } + if (pnt->containsMeasurement()) { + if (pnt->getNeedUpdateFromTrack()) { + pnt->updatePointByTrackInfo(&trc); + } + const double* yz = pnt->getYZTracking(); + const double* errYZ = pnt->getYZErrTracking(); + double chi = trc.getPredictedChi2(yz, errYZ); + //printf("***>> fitleg-> Y: %+e %+e / Z: %+e %+e -> Chi2: %e | %+e %+e\n",yz[0],trc.GetY(),yz[1],trc.GetZ(),chi, + // trc.Phi(),trc.GetAlpha()); + // printf("Before update at %e %e\n",yz[0],yz[1]); trc.print(); + if (!trc.update(yz, errYZ)) { +#if DEBUG > 3 + AliWarningF("Failed on Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]); + trc.print(); +#endif + return false; + } + mChi2 += chi; + // printf("After update: (%f) -> %f\n",chi,mChi2); trc.print(); + } + } + // + if (inv) { + // printf("Before inverting back "); trc.print(); + trc.invert(); + } + // + return true; +} + +//______________________________________________ +bool AlignmentTrack::residKalman() +{ + // calculate residuals from bi-directional Kalman smoother + // ATTENTION: this method modifies workspaces of the points!!! + // + bool inv = false; + const int kMinNStep = 3; + const double MaxDefStep = 3.0; + const double kErrSpace = 50.; + const double kErrAng = 0.7; + const double kErrRelPtI = 1.; + const covMat_t kIniErr = {// initial error + kErrSpace * kErrSpace, + 0, kErrSpace * kErrSpace, + 0, 0, kErrAng * kErrAng, + 0, 0, 0, kErrAng * kErrAng, + 0, 0, 0, 0, kErrRelPtI * kErrRelPtI}; + // const double kOverShootX = 5; + // + trackParam_t trc = *this; + // + int pID = 0, nPnt = getNPoints(); + ; + AlignmentPoint* pnt = nullptr; + // get 1st measured point + while (pID < nPnt && !(pnt = getPoint(pID))->containsMeasurement()) { + pID++; + } + if (!pnt) { + return false; + } + double phi = trc.getPhi(), alp = pnt->getAlphaSens(); + bringTo02Pi(phi); + bringTo02Pi(alp); + double dphi = deltaPhiSmall(phi, alp); + if (dphi > Pi() / 2.) { // need to invert the track to new frame + inv = true; + trc.invert(); + } + // prepare track seed at 1st valid point + if (!trc.rotateParam(pnt->getAlphaSens())) { +#if DEBUG > 3 + AliWarningF("Failed on rotateParam to %f", pnt->getAlphaSens()); + trc.print(); +#endif + return false; + } + if (!propagateParamToPoint(trc, pnt, MaxDefStep)) { + //if (!trc.PropagateParamOnlyTo(pnt->getXPoint()+kOverShootX,AliTrackerBase::GetBz())) { +#if DEBUG > 3 + AliWarningF("Failed on PropagateParamOnlyTo to %f", pnt->getXPoint() + kOverShootX); + trc.print(); +#endif + return false; + } + // + trc.setCov(kIniErr); + const double inwardQ2Pt2 = trc.getCovarElem(4, 4) * trc.getQ2Pt() * trc.getQ2Pt(); + trc.setCov(inwardQ2Pt2, 4, 4); // lowest diagonal element (Q2Pt2) + // + double chifwd = 0, chibwd = 0; + // inward fit + for (int ip = 0; ip < nPnt; ip++) { + pnt = getPoint(ip); + if (pnt->isInvDir() != inv) { // crossing point where the track should be inverted? + trc.invert(); + inv = !inv; + } + // printf("*** ResidKalm %d (%d %d)\n",ip,0,nPnt); + // printf("Before propagate: "); trc.print(); + if (!propagateToPoint(trc, pnt, MaxDefStep, MaxDefSnp, DefMatCorrType)) { + return false; + } + if (!pnt->containsMeasurement()) { + continue; + } + const double* yz = pnt->getYZTracking(); + const double* errYZ = pnt->getYZErrTracking(); + // store track position/errors before update in the point WorkSpace-A + double* ws = (double*)pnt->getTrParamWSA(); + ws[0] = trc.getY(); + ws[1] = trc.getZ(); + ws[2] = trc.getSigmaY2(); + ws[3] = trc.getSigmaZY(); + ws[4] = trc.getSigmaZ2(); + double chi = trc.getPredictedChi2(yz, errYZ); + // printf(">> INV%d (%9d): %+.2e %+.2e | %+.2e %+.2e %+.2e %+.2e %+.2e | %.2e %d \n",ip,pnt->getSensor()->getInternalID(),yz[0],yz[1], ws[0],ws[1],ws[2],ws[3],ws[4],chi,inv); + // printf(">>Bef ");trc.print(); + // printf("KLM Before update at %e %e\n",yz[0],yz[1]); trc.print(); + if (!trc.update(yz, errYZ)) { +#if DEBUG > 3 + AliWarningF("Failed on Inward Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]); + trc.print(); +#endif + return false; + } + // printf(">>Aft ");trc.print(); + chifwd += chi; + //printf("KLM After update: (%f) -> %f\n",chi,chifwd); trc.print(); + } + // + // outward fit + trc.setCov(kIniErr); + const double outwardQ2Pt2 = trc.getCovarElem(4, 4) * trc.getQ2Pt() * trc.getQ2Pt(); + trc.setCov(outwardQ2Pt2, 4, 4); // lowest diagonal element (Q2Pt2) + + for (int ip = nPnt; ip--;) { + pnt = getPoint(ip); + if (pnt->isInvDir() != inv) { // crossing point where the track should be inverted? + trc.invert(); + inv = !inv; + } + if (!propagateToPoint(trc, pnt, MaxDefStep, MaxDefSnp, DefMatCorrType)) { + return false; + } + if (!pnt->containsMeasurement()) { + continue; + } + const double* yz = pnt->getYZTracking(); + const double* errYZ = pnt->getYZErrTracking(); + // store track position/errors before update in the point WorkSpace-B + double* ws = (double*)pnt->getTrParamWSB(); + ws[0] = trc.getY(); + ws[1] = trc.getZ(); + ws[2] = trc.getSigmaY2(); + ws[3] = trc.getSigmaZY(); + ws[4] = trc.getSigmaZ2(); + double chi = trc.getPredictedChi2(yz, errYZ); + // printf("<< OUT%d (%9d): %+.2e %+.2e | %+.2e %+.2e %+.2e %+.2e %+.2e | %.2e %d \n",ip,pnt->getSensor()->getInternalID(),yz[0],yz[1], ws[0],ws[1],ws[2],ws[3],ws[4],chi,inv); + // printf("<<Bef "); trc.print(); + if (!trc.update(yz, errYZ)) { +#if DEBUG > 3 + AliWarningF("Failed on Outward Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]); + trc.print(); +#endif + return false; + } + chibwd += chi; + // printf("<<Aft "); trc.print(); + } + // + // now compute smoothed prediction and residual + for (int ip = 0; ip < nPnt; ip++) { + pnt = getPoint(ip); + if (!pnt->containsMeasurement()) { + continue; + } + double* wsA = (double*)pnt->getTrParamWSA(); // inward measurement + double* wsB = (double*)pnt->getTrParamWSB(); // outward measurement + double &yA = wsA[0], &zA = wsA[1], &sgAYY = wsA[2], &sgAYZ = wsA[3], &sgAZZ = wsA[4]; + double &yB = wsB[0], &zB = wsB[1], &sgBYY = wsB[2], &sgBYZ = wsB[3], &sgBZZ = wsB[4]; + // compute weighted average + double sgYY = sgAYY + sgBYY, sgYZ = sgAYZ + sgBYZ, sgZZ = sgAZZ + sgBZZ; + double detI = sgYY * sgZZ - sgYZ * sgYZ; + if (TMath::Abs(detI) < constants::math::Almost0) { + return false; + } else { + detI = 1. / detI; + } + double tmp = sgYY; + sgYY = sgZZ * detI; + sgZZ = tmp * detI; + sgYZ = -sgYZ * detI; + double dy = yB - yA, dz = zB - zA; + double k00 = sgAYY * sgYY + sgAYZ * sgYZ, k01 = sgAYY * sgYZ + sgAYZ * sgZZ; + double k10 = sgAYZ * sgYY + sgAZZ * sgYZ, k11 = sgAYZ * sgYZ + sgAZZ * sgZZ; + double sgAYZt = sgAYZ; + yA += dy * k00 + dz * k01; // these are smoothed predictions, stored in WSA + zA += dy * k10 + dz * k11; // + sgAYY -= k00 * sgAYY + k01 * sgAYZ; + sgAYZ -= k00 * sgAYZt + k01 * sgAZZ; + sgAZZ -= k10 * sgAYZt + k11 * sgAZZ; + // printf("|| WGH%d (%9d): | %+.2e %+.2e %+.2e %.2e %.2e\n",ip,pnt->getSensor()->getInternalID(), wsA[0],wsA[1],wsA[2],wsA[3],wsA[4]); + } + // + mChi2 = chifwd; + setKalmanDone(true); + return true; +} + +//______________________________________________ +bool AlignmentTrack::processMaterials() +{ + // attach material effect info to alignment points + trackParam_t trc = *this; + + // collision track of cosmic lower leg: move along track direction from last (middle for cosmic lower leg) + // point (inner) to 1st one (outer) + if (mNeedInv[0]) { + trc.invert(); + } // track needs to be inverted ? (should be for upper leg) + if (!processMaterials(trc, getInnerPointID(), 0)) { +#if DEBUG > 3 + LOG(error) << "Failed to process materials for leg along the track"; +#endif + return false; + } + if (isCosmic()) { + // cosmic upper leg: move againg the track direction from middle point (inner) to last one (outer) + trc = *this; + if (mNeedInv[1]) { + trc.invert(); + } // track needs to be inverted ? + if (!processMaterials(trc, getInnerPointID() + 1, getNPoints() - 1)) { +#if DEBUG > 3 + LOG(error) << "Failed to process materials for leg against the track"; +#endif + return false; + } + } + return true; +} + +//______________________________________________ +bool AlignmentTrack::processMaterials(trackParam_t& trc, int pFrom, int pTo) +{ + // attach material effect info to alignment points + const int kMinNStep = 3; + const double MaxDefStep = 3.0; + const double kErrSpcT = 1e-6; + const double kErrAngT = 1e-6; + const double kErrPtIT = 1e-12; + const covMat_t kErrTiny = {// initial tiny error + kErrSpcT * kErrSpcT, + 0, kErrSpcT * kErrSpcT, + 0, 0, kErrAngT * kErrAngT, + 0, 0, 0, kErrAngT * kErrAngT, + 0, 0, 0, 0, kErrPtIT * kErrPtIT}; + /* + const double kErrSpcH = 10.0; + const double kErrAngH = 0.5; + const double kErrPtIH = 0.5; + const double kErrHuge[15] = { // initial tiny error + kErrSpcH*kErrSpcH, + 0 , kErrSpcH*kErrSpcH, + 0 , 0, kErrAngH*kErrAngH, + 0 , 0, 0, kErrAngH*kErrAngH, + 0 , 0, 0, 0, kErrPtIH*kErrPtIH + }; + */ + // + // 2 copies of the track, one will be propagated accounting for materials, other - w/o + trackParam_t tr0; + track::TrackLTIntegral matTL; + double dpar[5] = {0}; + covMat_t dcov{0}; + matTL.setTimeNotNeeded(); + // + int pinc; + if (pTo > pFrom) { // fit in points decreasing order: cosmics upper leg + pTo++; + pinc = 1; + } else { // fit in points increasing order: collision track or cosmics lower leg + pTo--; + pinc = -1; + } + // + for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction + AlignmentPoint* pnt = getPoint(ip); + trc.setCov(kErrTiny); // assign tiny errors to both tracks + tr0 = trc; + // + // printf("-> ProcMat %d (%d->%d)\n",ip,pFrom,pTo); + if (!propagateToPoint(trc, pnt, MaxDefStep, MaxDefSnp, DefMatCorrType, &matTL)) { // with material corrections +#if DEBUG > 3 + LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" pTo << ") with mat.corr."; + trc.print(); + pnt->print("meas"); +#endif + return false; + } + // + // is there enough material to consider the point as a scatterer? + pnt->setContainsMaterial(matTL.getX2X0() * Abs(trc.getQ2Pt()) > getMinX2X0Pt2Account()); + // + // printf("-> ProcMat000 %d (%d->%d)\n",ip,pFrom,pTo); + if (!propagateToPoint(tr0, pnt, MaxDefStep, MaxDefSnp, MatCorrType::USEMatCorrNONE)) { // no material corrections +#if DEBUG > 3 + LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" pTo << ") with mat.corr."; + tr0.print(); + pnt->print("meas"); +#endif + return false; + } + // the difference between the params, covariance of tracks with and w/o material accounting gives + // paramets and covariance of material correction. For params ONLY ELoss effect is revealed + const covMat_t& cov0 = tr0.getCov(); + double* par0 = (double*)tr0.getParams(); + const covMat_t& cov1 = trc.getCov(); + double* par1 = (double*)trc.getParams(); + for (int l = 15; l--;) { + dcov[l] = cov1[l] - cov0[l]; + } + for (int l = kNKinParBON; l--;) { + dpar[l] = par1[l] - par0[l]; + } // eloss affects all parameters! + pnt->setMatCorrExp(dpar); + //dpar[kParQ2Pt] = par1[kParQ2Pt] - par0[kParQ2Pt]; // only e-loss expectation is non-0 + // + if (pnt->containsMaterial()) { + // + // MP2 handles only scalar residuals hence correlated matrix of material effect need to be diagonalized + bool eLossFree = pnt->getELossVaried(); + int nParFree = eLossFree ? kNKinParBON : kNKinParBOFF; + TMatrixDSym matCov(nParFree); + for (int i = nParFree; i--;) { + for (int j = i + 1; j--;) { + matCov(i, j) = matCov(j, i) = dcov[j + ((i * (i + 1)) >> 1)]; + } + } + // + TMatrixDSymEigen matDiag(matCov); // find eigenvectors + const TMatrixD& matEVec = matDiag.GetEigenVectors(); + if (!matEVec.IsValid()) { +#if DEBUG > 3 + LOG(error) << "Failed to diagonalize covariance of material correction"; + matCov.print(); + return false; +#endif + } + pnt->setMatCovDiagonalizationMatrix(matEVec); // store diagonalization matrix + pnt->setMatCovDiag(matDiag.GetEigenValues()); // store E.Values: diagonalized cov.matrix + if (!eLossFree) { + pnt->setMatCovDiagElem(kParQ2Pt, dcov[14]); + } + // + pnt->setX2X0(matTL.getX2X0()); + pnt->setXTimesRho(matTL.getXRho()); + // + } + if (pnt->containsMeasurement()) { // update track to have best possible kinematics + const double* yz = pnt->getYZTracking(); + const double* errYZ = pnt->getYZErrTracking(); + if (!trc.update(yz, errYZ)) { +#if DEBUG > 3 + AliWarningF("Failed on Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]); + trc.print(); +#endif + return false; + } + // + } + // + } + // + return true; +} + +//______________________________________________ +void AlignmentTrack::sortPoints() +{ + // sort points in order against track direction: innermost point is last + // for collision tracks. + // For 2-leg cosmic tracks: 1st points of outgoing (lower) leg are added from large to + // small radii, then the points of incomint (upper) leg are added in increasing R direction + // + // The mInnerPointID will mark the id of the innermost point, i.e. the last one for collision-like + // tracks and in case of cosmics - the point of lower leg with smallest R + // + mPoints.Sort(); + int np = getNPoints(); + mInnerPointID = np - 1; + if (isCosmic()) { + for (int ip = np; ip--;) { + AlignmentPoint* pnt = getPoint(ip); + if (pnt->isInvDir()) { + continue; + } // this is a point of upper leg + mInnerPointID = ip; + break; + } + } + // +} + +//______________________________________________ +void AlignmentTrack::setLocPars(const double* pars) +{ + // store loc par corrections + memcpy(mLocParA, pars, mNLocPar * sizeof(double)); +} + +//______________________________________________ +void AlignmentTrack::checkExpandDerGloBuffer(int minSize) +{ + // if needed, expand global derivatives buffer + if (mGloParID.GetSize() < minSize) { + mGloParID.Set(minSize + 100); + mDResDGlo[0].Set(minSize + 100); + mDResDGlo[1].Set(minSize + 100); + // + // reassign fast access arrays + mGloParIDA = mGloParID.GetArray(); + mDResDGloA[0] = mDResDGlo[0].GetArray(); + mDResDGloA[1] = mDResDGlo[1].GetArray(); + } +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/Controller.cxx b/Detectors/Align/src/Controller.cxx new file mode 100644 index 0000000000000..61bd2a2032344 --- /dev/null +++ b/Detectors/Align/src/Controller.cxx @@ -0,0 +1,2207 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Controller.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Steering class for the global alignment + +#include "Align/Controller.h" +#include "Align/AlignConfig.h" +#include "Framework/Logger.h" +#include "Align/utils.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" +#include "Align/AlignableVolume.h" +#include "Align/AlignableDetectorITS.h" +//#include "Align/AlignableDetectorTPC.h" +//#include "Align/AlignableDetectorTRD.h" +//#include "Align/AlignableDetectorTOF.h" +#include "Align/EventVertex.h" +#include "Align/ResidualsControllerFast.h" +#include "Align/GeometricalConstraint.h" +#include "Align/DOFStatistics.h" +//#include "AliTrackerBase.h" +//#include "AliESDCosmicTrack.h" +//#include "AliESDtrack.h" +//#include "AliESDEvent.h" +//#include "AliESDVertex.h" +//#include "AliRecoParam.h" +//#include "AliCDBRunRange.h" +//#include "AliCDBManager.h" +//#include "AliCDBEntry.h" +#include "MathUtils/Utils.h" + +#include <TMath.h> +#include <TString.h> + +#include <TROOT.h> +#include <TSystem.h> +#include <TRandom.h> +#include <TH1F.h> +#include <TList.h> +#include <cstdio> +#include <TGeoGlobalMagField.h> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" + +using namespace TMath; +using namespace o2::align::utils; +using namespace o2::dataformats; +using namespace o2::globaltracking; + +using std::ifstream; + +namespace o2 +{ +namespace align +{ + +void Controller::ProcStat::print() const +{ + // TODO RS + // const Char_t* Controller::sStatClName[Controller::kNStatCl] = {"Inp: ", "Acc: "}; + // const Char_t* Controller::sStatName[Controller::kMaxStat] = + // {"runs", "Ev.Coll", "Ev.Cosm", "Trc.Coll", "Trc.Cosm"}; +} + +const Char_t* Controller::sMPDataExt = ".mille"; + +const Char_t* Controller::sDetectorName[Controller::kNDetectors] = {"ITS", "TPC", "TRD", "TOF", "HMPID"}; //RSREM + +//const int Controller::mgkSkipLayers[Controller::kNLrSkip] = {AliGeomManager::kPHOS1, AliGeomManager::kPHOS2, +// AliGeomManager::kMUON, AliGeomManager::kEMCAL}; TODO(milettri, shahoian): needs detector IDs previously stored in AliGeomManager +const int Controller::sSkipLayers[Controller::kNLrSkip] = {0, 0, 0, 0}; // TODO(milettri, shahoian): needs AliGeomManager - remove this line after fix. + + +const Char_t* Controller::sHStatName[Controller::kNHVars] = { + "Runs", "Ev.Inp", "Ev.VtxOK", "Tr.Inp", "Tr.2Fit", "Tr.2FitVC", "Tr.2PrMat", "Tr.2ResDer", "Tr.Stored", "Tr.Acc", "Tr.ContRes"}; + +//________________________________________________________________ +Controller::Controller(DetID::mask_t detmask) + : mDetMask(detmask) +{ + // def c-tor + + // SetOutCDBRunRange(); FIXME(milettri): needs OCDB + init(); + + // run config macro if provided + if (!getInitDOFsDone()) { + initDOFs(); + } + if (!getNDOFs()) { + LOG(FATAL) << "No DOFs found, initialization failed"; + } +} + +//________________________________________________________________ +Controller::~Controller() +{ + // d-tor + if (mMPRecFile) { + closeMPRecOutput(); + } + if (mMille) { + closeMilleOutput(); + } + if (mResidFile) { + closeResidOutput(); + } + // + for (int i = 0; i < DetID::nDetectors; i++) { + delete mDetectors[i]; + } + delete mHistoStat; + // +} + +//________________________________________________________________ +void Controller::init() +{ + if (mDetMask[DetID::ITS]) { + addDetector(new AlignableDetectorITS(this)); + } + mVtxSens = std::make_unique<EventVertex>(this); +} + +//________________________________________________________________ +void Controller::process(const RecoContainer& recodata) +{ + /* + auto creator = [](auto& _tr, GTrackID _origID, float t0, float terr) { + if (!_origID.includesDet(DetID::ITS)) { + return true; // just in case this selection was not done on RecoContainer filling level + } + if constexpr (isITSTrack<decltype(_tr)>()) { + t0 += halfROFITS; // ITS time is supplied in \mus as beginning of ROF + terr *= hw2ErrITS; // error is supplied as a half-ROF duration, convert to \mus + } + // for all other tracks the time is in \mus with gaussian error + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) { + if (terr < maxTrackTimeError) { + tracks.emplace_back(TrackWithTimeStamp{_tr, {t0, terr}}); + gids.emplace_back(_origID); + } + } + + return true; + }; + recoData.createTracksVariadic(creator); // create track sample considered for vertexing +*/ +} + +//________________________________________________________________ +void Controller::initDetectors() +{ + // init all detectors geometry + // + if (getInitGeomDone()) { + return; + } + // + + // + mAlgTrack = std::make_unique<AlignmentTrack>(); + mRefPoint = std::make_unique<AlignmentPoint>(); + // + int dofCnt = 0; + // special fake sensor for vertex constraint point + // it has special T2L matrix adjusted for each track, no need to init it here + mVtxSens = std::make_unique<EventVertex>(this); + mVtxSens->setInternalID(1); + mVtxSens->prepareMatrixL2G(); + mVtxSens->prepareMatrixL2GIdeal(); + dofCnt += mVtxSens->getNDOFs(); + // + for (auto id = DetID::First; id <= DetID::Last; id++) { + auto* det = getDetector(id); + if (det) { + dofCnt += det->initGeom(); + } + } + if (!dofCnt) { + LOG(FATAL) << "No DOFs found"; + } + // + // + for (auto id = DetID::First; id <= DetID::Last; id++) { + auto* det = getDetector(id); + if (!det || det->isDisabled()) { + continue; + } + det->cacheReferenceOCDB(); + } + // + assignDOFs(); + LOG(INFO) << "Booked " << dofCnt << " global parameters"; + // + setInitGeomDone(); + // +} + +//________________________________________________________________ +void Controller::initDOFs() +{ + // scan all free global parameters, link detectors to array of params + // + if (getInitDOFsDone()) { + LOG(INFO) << "initDOFs was already done, just reassigning " << getNDOFs() << "DOFs arrays/labels"; + assignDOFs(); + return; + } + const auto& conf = AlignConfig::Instance(); + + mNDOFs = 0; + int ndfAct = 0; + assignDOFs(); + int nact = 0; + mVtxSens->initDOFs(); + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (det && !det->isDisabled()) { + det->initDOFs(); + nact++; + ndfAct += det->getNDOFsTot(); + } + } + for (int i = 0; i < NTrackTypes; i++) { + if (nact < conf.minDetAcc[i]) { + LOG(FATAL) << nact << " detectors are active, while " << conf.minDetAcc[i] << " in track are asked"; + } + } + LOG(INFO) << mNDOFs << " global parameters " << mNDet << " detectors, " << ndfAct << " in " << nact << " active detectors"; + addAutoConstraints(); + setInitDOFsDone(); +} + +//________________________________________________________________ +void Controller::assignDOFs() +{ + // add parameters/labels arrays to volumes. If the Controller is read from the file, this method need + // to be called (of initDOFs should be called) + // + int ndfOld = -1; + if (mNDOFs > 0) { + ndfOld = mNDOFs; + } + mNDOFs = 0; + // + // reserve + int ndofTOT = mVtxSens->getNDOFs(); + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det) { + continue; + } + ndofTOT += det->getNDOFsTot(); + } + mGloParVal.clear(); + mGloParErr.clear(); + mGloParLab.clear(); + mOrderedLbl.clear(); + mLbl2ID.clear(); + mGloParVal.reserve(ndofTOT); + mGloParErr.reserve(ndofTOT); + mGloParLab.reserve(ndofTOT); + mOrderedLbl.reserve(ndofTOT); + mLbl2ID.reserve(ndofTOT); + + mVtxSens->assignDOFs(); + + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det) { + continue; + } + mNDOFs += det->assignDOFs(); + } + LOG(INFO) << "Assigned parameters/labels arrays for " << mNDOFs << " DOFs"; + if (ndfOld > -1 && ndfOld != mNDOFs) { + LOG(ERROR) << "Recalculated NDOFs=" << mNDOFs << " not equal to saved NDOFs=" << ndfOld; + } + // + // build Lbl <-> parID table + /* FIXME RS TODO + Sort(mNDOFs, mGloParLab, mLbl2ID, false); // sort in increasing order + for (int i = mNDOFs; i--;) { + mOrderedLbl[i] = mGloParLab[mLbl2ID[i]]; + } + */ + // +} + +//_________________________________________________________ +void Controller::addDetector(AlignableDetector* det) +{ + // add detector constructed externally to alignment framework + mDetectors[det->getDetID()] = det; + mNDet++; +} + +//_________________________________________________________ +bool Controller::checkDetectorPattern(DetID::mask_t patt) const +{ + //validate detector pattern + return ((patt & mObligatoryDetPattern[mTracksType]) == mObligatoryDetPattern[mTracksType]) && + patt.count() >= AlignConfig::Instance().minDetAcc[mTracksType]; +} + +//_________________________________________________________ +bool Controller::checkDetectorPoints(const int* npsel) const +{ + //validate detectors pattern according to number of selected points + int ndOK = 0; + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det || det->isDisabled(mTracksType)) { + continue; + } + if (npsel[id] < det->getNPointsSel(mTracksType)) { + if (det->isObligatory(mTracksType)) { + return false; + } + continue; + } + ndOK++; + } + return ndOK >= AlignConfig::Instance().minDetAcc[mTracksType]; +} + +//FIXME(milettri): needs AliESDtrack +////_________________________________________________________ +//uint32_t Controller::AcceptTrack(const AliESDtrack* esdTr, bool strict) const +//{ +// // decide if the track should be processed +// AlignableDetector* det = 0; +// uint32_t detAcc = 0; +// if (mFieldOn && esdTr->Pt() < mPtMin[mTracksType]){ +// return 0;} +// if (Abs(esdTr->Eta()) > mEtaMax[mTracksType]){ +// return 0;} +// // +// for (auto id=DetID::First; id<=DetID::Last; id++) { +// +// if (!(det = getDetector(id)) || det->isDisabled(mTracksType)){ +// continue;} +// if (!det->AcceptTrack(esdTr, mTracksType)) { +// if (strict && det->isObligatory(mTracksType)){ +// return 0;} +// else +// continue; +// } +// // +// detAcc |= 0x1 << idet; +// } +// if (numberOfBitsSet(detAcc) < mMinDetAcc[mTracksType]){ +// return 0;} +// return detAcc; +// // +//} + +//FIXME(milettri): needs AliESDtrack +////_________________________________________________________ +//uint32_t Controller::AcceptTrackCosmic(const AliESDtrack* esdPairCosm[kNCosmLegs]) const +//{ +// // decide if the pair of tracks making cosmic track should be processed +// uint32_t detAcc = 0, detAccLeg; +// for (int i = kNCosmLegs; i--;) { +// detAccLeg = AcceptTrack(esdPairCosm[i], mCosmicSelStrict); // missing obligatory detectors in one leg might be allowed +// if (!detAccLeg){ +// return 0;} +// detAcc |= detAccLeg; +// } +// if (mCosmicSelStrict){ +// return detAcc;} +// // +// // for non-stric selection check convolution of detector presence +// if (!checkDetectorPattern(detAcc)){ +// return 0;} +// return detAcc; +// // +//} + +//FIXME(milettri): needs AliESDEvent +////_________________________________________________________ +//void Controller::SetESDEvent(const AliESDEvent* ev) +//{ +// // attach event to analyse +// fESDEvent = ev; +// // setup magnetic field if needed +// if (fESDEvent && +// (!TGeoGlobalMagField::Instance()->GetField() || +// !smallerAbs(fESDEvent->GetMagneticField() - AliTrackerBase::GetBz(), 5e-4))) { +// fESDEvent->InitMagneticField(); +// } +//} + +//FIXME(milettri): needs AliESDEvent +////_________________________________________________________ +//bool Controller::ProcessEvent(const AliESDEvent* esdEv) +//{ +// // process event +// const int kProcStatFreq = 100; +// static int evCount = 0; +// if (!(evCount % kProcStatFreq)) { +// ProcInfo_t procInfo; +// gSystem->GetProcInfo(&procInfo); +// LOG(INFO) << "ProcStat: CPUusr:" << int(procInfo.fCpuUser) << " CPUsys:" << int(procInfo.fCpuSys) << " RMem:" << int(procInfo.fMemResident / 1024) << " VMem:" << int(procInfo.fMemVirtual / 1024); +// } +// evCount++; +// // +// SetESDEvent(esdEv); +// // +// if (esdEv->getRunNumber() != getRunNumber()){ +// SetRunNumber(esdEv->getRunNumber()); +// } +// // +// setCosmic(esdEv->GetEventSpecie() == AliRecoParam::kCosmic || +// (esdEv->GetNumberOfCosmicTracks() > 0 && !esdEv->GetPrimaryVertexTracks()->GetStatus())); +// // +// fillStatHisto(kEvInp); +// // +//#if DEBUG > 2 +// LOG << "Processing event " << esdEv->GetEventNumberInFile() << " of ev.specie " << esdEv->GetEventSpecie() << " -> Ntr: " << esdEv->GetNumberOfTracks() << " NtrCosm: " << esdEv->GetNumberOfCosmicTracks(); +//#endif +// // +// setFieldOn(Abs(esdEv->GetMagneticField()) > kAlmost0Field); +// if (!isCosmic() && !CheckSetVertex(esdEv->GetPrimaryVertexTracks())){ +// return false;} +// fillStatHisto(kEvVtx); +// // +// int ntr = 0, accTr = 0; +// if (isCosmic()) { +// mStat[kInpStat][kEventCosm]++; +// ntr = esdEv->GetNumberOfCosmicTracks(); +// fillStatHisto(kTrackInp, ntr); +// for (int itr = 0; itr < ntr; itr++) { +// accTr += ProcessTrack(esdEv->GetCosmicTrack(itr)); +// } +// if (accTr){ +// mStat[kAccStat][kEventCosm]++;} +// } else { +// mStat[kInpStat][kEventColl]++; +// ntr = esdEv->GetNumberOfTracks(); +// fillStatHisto(kTrackInp, ntr); +// for (int itr = 0; itr < ntr; itr++) { +// // int accTrOld = accTr; +// accTr += ProcessTrack(esdEv->GetTrack(itr)); +// /* +// if (accTr>accTrOld && mCResid) { +// int ndf = mCResid.getNPoints()*2-5; +// if (mCResid.getChi2()/ndf>20 || !mCResid.getKalmanDone() +// || mCResid.getChi2K()/ndf>20) { +// printf("BAD FIT for %d\n",itr); +// } +// mCResid.Print("er"); +// } +// */ +// } +// if (accTr){ +// mStat[kAccStat][kEventColl]++;} +// } +// // +// fillStatHisto(kTrackAcc, accTr); +// // +// if (accTr) { +// LOG(INFO) << "Processed event " << esdEv->GetEventNumberInFile() << " of ev.specie " << esdEv->GetEventSpecie() << " -> Accepted: " << accTr << " of " << ntr << " tracks"; +// } +// return true; +//} + +//FIXME(milettri): needs AliESDtrack +//_________________________________________________________ +//bool Controller::ProcessTrack(const AliESDtrack* esdTr) +//{ +// // process single track +// // +// mStat[kInpStat][kTrackColl]++; +// fESDTrack[0] = esdTr; +// fESDTrack[1] = 0; +// // +// int nPnt = 0; +// const AliESDfriendTrack* trF = esdTr->GetFriendTrack(); +// if (!trF){ +// return false;} +// const AliTrackPointArray* trPoints = trF->GetTrackPointArray(); +// if (!trPoints || (nPnt = trPoints->GetNPoints()) < 1){ +// return false;} +// // +// uint32_t detAcc = AcceptTrack(esdTr); +// if (!detAcc){ +// return false;} +// // +// resetDetectors(); +// mAlgTrack->Clear(); +// // +// // process the track points for each detector, +// AlignableDetector* det = 0; +// for (auto id=DetID::First; id<=DetID::Last; id++) { +// if (!(detAcc & (0x1 << idet))){ // RS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// continue;} +// det = getDetector(id); +// if (det->ProcessPoints(esdTr, mAlgTrack) < det->getNPointsSel(kColl)) { +// detAcc &= ~(0x1 << idet); // did not survive, suppress detector in the track +// if (det->isObligatory(kColl)){ +// return false;} +// } +// if (numberOfBitsSet(detAcc) < mMinDetAcc[kColl]){ +// return false;} // abandon track +// } +// // +// if (mAlgTrack->getNPoints() < getMinPoints()){ +// return false;} +// // fill needed points (tracking frame) in the mAlgTrack +// mRefPoint->setContainsMeasurement(false); +// mRefPoint->setContainsMaterial(false); +// mAlgTrack->addPoint(mRefPoint); // reference point which the track will refer to +// // +// mAlgTrack->copyFrom(esdTr); +// if (!getFieldOn()){ +// mAlgTrack->imposePtBOff(mDefPtBOff[utils::kColl]);} +// mAlgTrack->setFieldON(getFieldOn()); +// mAlgTrack->sortPoints(); +// // +// // at this stage the points are sorted from maxX to minX, the latter corresponding to +// // reference point (e.g. vertex) with X~0. The mAlgTrack->getInnerPointID() points on it, +// // hence mAlgTrack->getInnerPointID() is the 1st really measured point. We will set the +// // alpha of the reference point to alpha of the barrel sector corresponding to this +// // 1st measured point +// int pntMeas = mAlgTrack->getInnerPointID() - 1; +// if (pntMeas < 0) { // this should not happen +// mAlgTrack->Print("p meas"); +// LOG(FATAL) << "AlignmentTrack->getInnerPointID() cannot be 0"; +// } +// // do we want to add the vertex as a measured point ? +// if (!addVertexConstraint()) { // no constrain, just reference point w/o measurement +// mRefPoint->setXYZTracking(0, 0, 0); +// mRefPoint->setAlphaSens(sector2Alpha(mAlgTrack->getPoint(pntMeas)->getAliceSector())); +// } else +// fillStatHisto(kTrackFitInpVC); +// // +// fillStatHisto(kTrackFitInp); +// if (!mAlgTrack->iniFit()){ +// return false;} +// fillStatHisto(kTrackProcMatInp); +// if (!mAlgTrack->processMaterials()){ +// return false;} +// mAlgTrack->defineDOFs(); +// // +// fillStatHisto(kTrackResDerInp); +// if (!mAlgTrack->calcResidDeriv()){ +// return false;} +// // +// if (!storeProcessedTrack(mMPOutType & ~kContR)){ +// return false;} // store derivatives for MP +// // +// if (getProduceControlRes() && // need control residuals, ignore selection fraction if this is the +// (mMPOutType == kContR || gRandom->Rndm() < mControlFrac)) { // output requested +// if (!testLocalSolution() || !storeProcessedTrack(kContR)){ +// return false;} +// } +// // +// fillStatHisto(kTrackStore); +// // +// mStat[kAccStat][kTrackColl]++; +// // +// return true; +//} + +//FIXME(milettri): needs AliESDVertex +////_________________________________________________________ +//bool Controller::CheckSetVertex(const AliESDVertex* vtx) +//{ +// // vertex selection/constraint check +// if (!vtx) { +// fVertex = 0; +// return true; +// } +// int ncont = vtx->GetNContributors(); +// if (mVtxMinCont > 0 && mVtxMinCont > ncont) { +//#if DEBUG > 2 +// LOG(INFO) << "Rejecting event with " << % d << " vertex contributors (min " << % d << " asked)", ncont, mVtxMinCont); +//#endif +// return false; +// } +// if (mVtxMaxCont > 0 && ncont > mVtxMaxCont) { +//#if DEBUG > 2 +// LOG(INFO) << "Rejecting event with " << % d << " vertex contributors (max " << % d << " asked)", ncont, mVtxMaxCont); +//#endif +// return false; +// } +// fVertex = (ncont >= mVtxMinContVC) ? vtx : 0; // use vertex as a constraint +// return true; +//} + +//FIXME(milettri): needs AliESDCosmicTrack +////_________________________________________________________ +//bool Controller::ProcessTrack(const AliESDCosmicTrack* cosmTr) +//{ +// // process single cosmic track +// // +// mStat[kInpStat][kTrackCosm]++; +// int nPnt = 0; +// fESDTrack[0] = 0; +// fESDTrack[1] = 0; +// // +// for (int leg = kNCosmLegs; leg--;) { +// const AliESDtrack* esdTr = +// fESDEvent->GetTrack(leg == kCosmLow ? cosmTr->GetESDLowerTrackIndex() : cosmTr->GetESDUpperTrackIndex()); +// const AliESDfriendTrack* trF = esdTr->GetFriendTrack(); +// if (!trF){ +// return false;} +// const AliTrackPointArray* trPoints = trF->GetTrackPointArray(); +// if (!trPoints || (nPnt += trPoints->GetNPoints()) < 1){ +// return false;} +// // +// fESDTrack[leg] = esdTr; +// } +// // +// uint32_t detAcc = AcceptTrackCosmic(fESDTrack); +// if (!detAcc){ +// return false;} +// // +// resetDetectors(); +// mAlgTrack->Clear(); +// mAlgTrack->setCosmic(true); +// // +// // process the track points for each detector, +// // fill needed points (tracking frame) in the mAlgTrack +// mRefPoint->setContainsMeasurement(false); +// mRefPoint->setContainsMaterial(false); +// mAlgTrack->addPoint(mRefPoint); // reference point which the track will refer to +// // +// AlignableDetector* det = 0; +// int npsel[kNDetectors] = {0}; +// for (int nPleg = 0, leg = kNCosmLegs; leg--;) { +// for (auto id=DetID::First; id<=DetID::Last; id++) { +// if (!(detAcc & (0x1 << idet))){ +// continue;} +// det = getDetector(id); +// // +// // upper leg points marked as the track going in inverse direction +// int np = det->ProcessPoints(fESDTrack[leg], mAlgTrack, leg == kCosmUp); +// if (np < det->getNPointsSel(Cosm) && mCosmicSelStrict && +// det->isObligatory(Cosm)) +// return false; +// npsel[id] += np; +// nPleg += np; +// } +// if (nPleg < getMinPoints()){ +// return false;} +// } +// // last check on legs-combined patter +// if (!checkDetectorPoints(npsel)){ +// return false;} +// // +// mAlgTrack->copyFrom(cosmTr); +// if (!getFieldOn()){ +// mAlgTrack->imposePtBOff(mDefPtBOff[utils::Cosm]);} +// mAlgTrack->setFieldON(getFieldOn()); +// mAlgTrack->sortPoints(); +// // +// // at this stage the points are sorted from maxX to minX, the latter corresponding to +// // reference point (e.g. vertex) with X~0. The mAlgTrack->getInnerPointID() points on it, +// // hence mAlgTrack->getInnerPointID() is the 1st really measured point. We will set the +// // alpha of the reference point to alpha of the barrel sector corresponding to this +// // 1st measured point +// int pntMeas = mAlgTrack->getInnerPointID() - 1; +// if (pntMeas < 0) { // this should not happen +// mAlgTrack->Print("p meas"); +// LOG(FATAL) << "AlignmentTrack->getInnerPointID() cannot be 0"; +// } +// mRefPoint->setAlphaSens(sector2Alpha(mAlgTrack->getPoint(pntMeas)->getAliceSector())); +// // +// fillStatHisto(kTrackFitInp); +// if (!mAlgTrack->iniFit()){ +// return false;} +// // +// fillStatHisto(kTrackProcMatInp); +// if (!mAlgTrack->processMaterials()){ +// return false;} +// mAlgTrack->defineDOFs(); +// // +// fillStatHisto(kTrackResDerInp); +// if (!mAlgTrack->calcResidDeriv()){ +// return false;} +// // +// if (!storeProcessedTrack(mMPOutType & ~kContR)){ +// return false;} // store derivatives for MP +// // +// if (getProduceControlRes() && // need control residuals, ignore selection fraction if this is the +// (mMPOutType == kContR || gRandom->Rndm() < mControlFrac)) { // output requested +// if (!testLocalSolution() || !storeProcessedTrack(kContR)){ +// return false;} +// } +// // +// fillStatHisto(kTrackStore); +// mStat[kAccStat][kTrackCosm]++; +// return true; +//} + +//_________________________________________________________ +bool Controller::storeProcessedTrack(int what) +{ + // write alignment track + bool res = true; + if ((what & kMille)) { + res &= fillMilleData(); + } + if ((what & kMPRec)) { + res &= fillMPRecData(); + } + if ((what & kContR)) { + res &= fillControlData(); + } + // + return res; +} + +//_________________________________________________________ +bool Controller::fillMilleData() +{ + // store MP2 data in Mille format + if (!mMille) { + mMille = std::make_unique<Mille>(fmt::format("{}{}", mMPDatFileName, sMPDataExt).c_str()); + } + // + if (!mAlgTrack->getDerivDone()) { + LOG(ERROR) << "Track derivatives are not yet evaluated"; + return false; + } + int np(mAlgTrack->getNPoints()), nDGloTot(0); // total number global derivatives stored + int nParETP(mAlgTrack->getNLocExtPar()); // numnber of local parameters for reference track param + int nVarLoc(mAlgTrack->getNLocPar()); // number of local degrees of freedom in the track + float *buffDL(nullptr), *buffDG(nullptr); // faster acces arrays + int* buffI(nullptr); + // + const int* gloParID(mAlgTrack->getGloParID()); // IDs of global DOFs this track depends on + for (int ip = 0; ip < np; ip++) { + AlignmentPoint* pnt = mAlgTrack->getPoint(ip); + if (pnt->containsMeasurement()) { + int gloOffs = pnt->getDGloOffs(); // 1st entry of global derivatives for this point + int nDGlo = pnt->getNGloDOFs(); // number of global derivatives (number of DOFs it depends on) + if (!pnt->isStatOK()) { + pnt->incrementStat(); + } + // check buffer sizes + { + if (mMilleDBuffer.GetSize() < nVarLoc + nDGlo) { + mMilleDBuffer.Set(100 + nVarLoc + nDGlo); + } + if (mMilleIBuffer.GetSize() < nDGlo) { + mMilleIBuffer.Set(100 + nDGlo); + } + buffDL = mMilleDBuffer.GetArray(); // faster acces + buffDG = buffDL + nVarLoc; // faster acces + buffI = mMilleIBuffer.GetArray(); // faster acces + } + // local der. array cannot be 0-suppressed by Mille construction, need to reset all to 0 + // + for (int idim = 0; idim < 2; idim++) { // 2 dimensional orthogonal measurement + memset(buffDL, 0, nVarLoc * sizeof(float)); + const double* deriv = mAlgTrack->getDResDLoc(idim, ip); // array of Dresidual/Dparams_loc + // derivatives over reference track parameters + for (int j = 0; j < nParETP; j++) { + buffDL[j] = (isZeroAbs(deriv[j])) ? 0 : deriv[j]; + } + // + // point may depend on material variables within these limits + int lp0 = pnt->getMinLocVarID(), lp1 = pnt->getMaxLocVarID(); + for (int j = lp0; j < lp1; j++) { + buffDL[j] = (isZeroAbs(deriv[j])) ? 0 : deriv[j]; + } + // + // derivatives over global params: this array can be 0-suppressed, no need to reset + int nGlo(0); + deriv = mAlgTrack->getDResDGlo(idim, gloOffs); + const int* gloIDP(gloParID + gloOffs); + for (int j = 0; j < nDGlo; j++) { + if (!isZeroAbs(deriv[j])) { + buffDG[nGlo] = deriv[j]; // value of derivative + buffI[nGlo++] = getGloParLab(gloIDP[j]); // global DOF ID + 1 (Millepede needs positive labels) + } + } + mMille->mille(nVarLoc, buffDL, nGlo, buffDG, buffI, + mAlgTrack->getResidual(idim, ip), Sqrt(pnt->getErrDiag(idim))); + nDGloTot += nGlo; + // + } + } + if (pnt->containsMaterial()) { // material point can add 4 or 5 otrhogonal pseudo-measurements + memset(buffDL, 0, nVarLoc * sizeof(float)); + int nmatpar = pnt->getNMatPar(); // residuals (correction expectation value) + // const float* expMatCorr = pnt->getMatCorrExp(); // expected corrections (diagonalized) + const float* expMatCov = pnt->getMatCorrCov(); // their diagonalized error matrix + int offs = pnt->getMaxLocVarID() - nmatpar; // start of material variables + // here all derivatives are 1 = dx/dx + for (int j = 0; j < nmatpar; j++) { // mat. "measurements" don't depend on global params + int j1 = j + offs; + buffDL[j1] = 1.0; // only 1 non-0 derivative + //mMille->mille(nVarLoc,buffDL,0,buffDG,buffI,expMatCorr[j],Sqrt(expMatCov[j])); + // expectation for MS effect is 0 + mMille->mille(nVarLoc, buffDL, 0, buffDG, buffI, 0, Sqrt(expMatCov[j])); + buffDL[j1] = 0.0; // reset buffer + } + } // material "measurement" + } // loop over points + // + if (!nDGloTot) { + LOG(INFO) << "Track does not depend on free global parameters, discard"; + mMille->kill(); + return false; + } + mMille->end(); // store the record + return true; +} + +//_________________________________________________________ +bool Controller::fillMPRecData() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs AliESDEvent + // // store MP2 in MPRecord format + // if (!mMPRecord){ + // initMPRecOutput();} + // // + // mMPRecord->Clear(); + // if (!mMPRecord->fillTrack(mAlgTrack, mGloParLab)){ + // return false;} + // mMPRecord->SetRun(mRunNumber); + // mMPRecord->setTimeStamp(fESDEvent->GetTimeStamp()); + // uint32_t tID = 0xffff & uint(fESDTrack[0]->GetID()); + // if (isCosmic()){ + // tID |= (0xffff & uint(fESDTrack[1]->GetID())) << 16;} + // mMPRecord->setTrackID(tID); + // mMPRecTree->Fill(); + return true; +} + +//_________________________________________________________ +bool Controller::fillControlData() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs AliESDEvent + // // store control residuals + // if (!mCResid){ + // initResidOutput();} + // // + // int nps, np = mAlgTrack->getNPoints(); + // nps = (!mRefPoint->containsMeasurement()) ? np - 1 : np; // ref point is dummy? + // if (nps < 0){ + // return true;} + // // + // mCResid.Clear(); + // if (!mCResid.fillTrack(mAlgTrack, mDoKalmanResid)){ + // return false;} + // mCResid.setRun(mRunNumber); + // mCResid.setTimeStamp(fESDEvent->GetTimeStamp()); + // mCResid.setBz(fESDEvent->GetMagneticField()); + // uint32_t tID = 0xffff & uint(fESDTrack[0]->GetID()); + // if (isCosmic()){ + // tID |= (0xffff & uint(fESDTrack[1]->GetID())) << 16;} + // mCResid.setTrackID(tID); + // // + // mResidTree->Fill(); + // fillStatHisto(kTrackControl); + // // + return true; +} + +//_________________________________________________________ +void Controller::setRunNumber(int run) +{ + if (run == mRunNumber) { + return; + } // nothing to do + // + acknowledgeNewRun(run); +} + +//_________________________________________________________ +void Controller::acknowledgeNewRun(int run) +{ + LOG(WARNING) << __PRETTY_FUNCTION__ << " yet incomplete"; + + o2::base::GeometryManager::loadGeometry(); + o2::base::PropagatorImpl<double>::initFieldFromGRP(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + + //FIXME(milettri): needs AliESDEvent + // // load needed info for new run + // if (run == mRunNumber){ + // return;} // nothing to do + // if (run > 0) { + // mStat[kAccStat][kRun]++; + // } + // if (mRunNumber > 0){ + // fillStatHisto(kRunDone);} + // mRunNumber = run; + // LOG(INFO) << "Processing new run " << mRunNumber; + // // + // // setup magnetic field + // if (fESDEvent && + // (!TGeoGlobalMagField::Instance()->GetField() || + // !smallerAbs(fESDEvent->GetMagneticField() - AliTrackerBase::GetBz(), 5e-4))) { + // fESDEvent->InitMagneticField(); + // } + // // + // if (!mUseRecoOCDB) { + // LOG(WARNING) << "Reco-time OCDB will NOT be preloaded"; + // return; + // } + // LoadRecoTimeOCDB(); + // // + // for (auto id=DetID::First; id<=DetID::Last; id++) { + // AlignableDetector* det = getDetector(id); + // if (!det->isDisabled()){ + // det->acknowledgeNewRun(run);} + // } + // // + // // bring to virgin state + // // CleanOCDB(); + // // + // // LoadRefOCDB(); //??? we need to get back reference OCDB ??? + // // + // mStat[kInpStat][kRun]++; + // // +} + +// FIXME(milettri): needs OCDB +////_________________________________________________________ +//bool Controller::LoadRecoTimeOCDB() +//{ +// // Load OCDB paths used for the reconstruction of data being processed +// // In order to avoid unnecessary uploads, the objects are not actually +// // loaded/cached but just added as specific paths with version +// LOG(INFO) << "Preloading Reco-Time OCDB for run " << mRunNumber << " from ESD UserInfo list"; +// // +// CleanOCDB(); +// // +// if (!mRecoOCDBConf.IsNull() && !gSystem->AccessPathName(mRecoOCDBConf.c_str(), kFileExists)) { +// LOG(INFO) << "Executing reco-time OCDB setup macro " << mRecoOCDBConf.c_str(); +// gROOT->ProcessLine(Form(".x %s(%d)", mRecoOCDBConf.c_str(), mRunNumber)); +// if (AliCDBManager::Instance()->IsDefaultStorageSet()){ +// return true;} +// LOG(FATAL) << "macro " << mRecoOCDBConf.c_str() << " failed to configure reco-time OCDB"; +// } else +// LOG(WARNING) << "No reco-time OCDB config macro" << mRecoOCDBConf.c_str() << " is found, will use ESD:UserInfo"; +// // +// if (!mESDTree){ +// LOG(FATAL) << "Cannot preload Reco-Time OCDB since the ESD tree is not set";} +// const TTree* tr = mESDTree; // go the the real ESD tree +// while (tr->GetTree() && tr->GetTree() != tr) +// tr = tr->GetTree(); +// // +// const TList* userInfo = const_cast<TTree*>(tr)->GetUserInfo(); +// TMap* cdbMap = (TMap*)userInfo->FindObject("cdbMap"); +// TList* cdbList = (TList*)userInfo->FindObject("cdbList"); +// // +// if (!cdbMap || !cdbList) { +// userInfo->Print(); +// LOG(FATAL) << "Failed to extract cdbMap and cdbList from UserInfo list"; +// } +// // +// return PreloadOCDB(mRunNumber, cdbMap, cdbList); +//} + +//____________________________________________ +void Controller::Print(const Option_t* opt) const +{ + // print info + TString opts = opt; + opts.ToLower(); + printf("%5d DOFs in %d detectors\n", mNDOFs, mNDet); + if (getMPAlignDone()) { + printf("ALIGNMENT FROM MILLEPEDE SOLUTION IS APPLIED\n"); + } + // + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det) { + continue; + } + det->Print(opt); + } + if (!opts.IsNull()) { + printf("\nSpecial sensor for Vertex Constraint\n"); + mVtxSens->Print(opt); + } + // + if (mRefRunNumber >= 0) { + printf("(%d)", mRefRunNumber); + } + // + printf("%-40s:\t%s\n", "Output OCDB path", mOutCDBPath.c_str()); + printf("%-40s:\t%s/%s\n", "Output OCDB comment/responsible", + mOutCDBComment.c_str(), mOutCDBResponsible.c_str()); + printf("%-40s:\t%6d:%6d\n", "Output OCDB run range", mOutCDBRunRange[0], mOutCDBRunRange[1]); + // + printf("%-40s:\t%s\n", "Filename for MillePede steering", mMPSteerFileName.c_str()); + printf("%-40s:\t%s\n", "Filename for MillePede parameters", mMPParFileName.c_str()); + printf("%-40s:\t%s\n", "Filename for MillePede constraints", mMPConFileName.c_str()); + printf("%-40s:\t%s\n", "Filename for control residuals:", mResidFileName.c_str()); + printf("%-40s:\t%.3f\n", "Fraction of control tracks", mControlFrac); + printf("MPData output :\t"); + if (getProduceMPData()) { + printf("%s%s ", mMPDatFileName.c_str(), sMPDataExt); + } + if (getProduceMPRecord()) { + printf("%s%s ", mMPDatFileName.c_str(), ".root"); + } + printf("\n"); + // + if (opts.Contains("stat")) { + printStatistics(); + } + + if (opts.Contains("conf")) { + AlignConfig::Instance().printKeyValues(true); + } +} + +//________________________________________________________ +void Controller::printStatistics() const +{ + // print processing stat + mStat.print(); +} + +//________________________________________________________ +void Controller::resetDetectors() +{ + // reset detectors for next track + mRefPoint->Clear(); + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (det) { + det->resetPool(); // reset used alignment points + } + } +} + +//____________________________________________ +bool Controller::testLocalSolution() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs AliSymMatrix + // // test track local solution + // TVectorD rhs; + // AliSymMatrix* mat = BuildMatrix(rhs); + // if (!mat){ + // return false;} + // // mat->Print("long data"); + // // rhs.Print(); + // TVectorD vsl(rhs); + // if (!mat->SolveChol(rhs, vsl, true)) { + // delete mat; + // return false; + // } + // // + // /* + // // print solution vector + // int nlocpar = mAlgTrack->getNLocPar(); + // int nlocparETP = mAlgTrack->getNLocExtPar(); // parameters of external track param + // printf("ETP Update: "); + // for (int i=0;i<nlocparETP;i++) printf("%+.2e(%+.2e) ",vsl[i],Sqrt((*mat)(i,i))); printf("\n"); + // // + // if (nlocpar>nlocparETP) printf("Mat.Corr. update:\n"); + // for (int ip=mAlgTrack->getNPoints();ip--;) { + // AlignmentPoint* pnt = mAlgTrack->getPoint(ip); + // int npm = pnt->getNMatPar(); + // const float* expMatCov = pnt->getMatCorrCov(); // its error + // int offs = pnt->getMaxLocVarID() - npm; + // for (int ipar=0;ipar<npm;ipar++) { + // int parI = offs + ipar; + // double err = Sqrt(expMatCov[ipar]); + // printf("Pnt:%3d MatVar:%d DOF %3d | %+.3e(%+.3e) -> sig:%+.3e -> pull: %+.2e\n", + // ip,ipar,parI,vsl[parI],Sqrt((*mat)(parI,parI)), err,vsl[parI]/err); + // } + // } + // */ + // // + // // increment current params by new solution + // rhs.SetElements(mAlgTrack->getLocPars()); + // vsl += rhs; + // mAlgTrack->setLocPars(vsl.GetMatrixArray()); + // mAlgTrack->calcResiduals(); + // delete mat; + // // + return true; +} + +//FIXME(milettri): needs AliSymMatrix +////____________________________________________ +//AliSymMatrix* Controller::BuildMatrix(TVectorD& vec) +//{ +// // build matrix/vector for local track +// int npnt = mAlgTrack->getNPoints(); +// int nlocpar = mAlgTrack->getNLocPar(); +// // +// vec.ResizeTo(nlocpar); +// memset(vec.GetMatrixArray(), 0, nlocpar * sizeof(double)); +// AliSymMatrix* matp = new AliSymMatrix(nlocpar); +// AliSymMatrix& mat = *matp; +// // +// for (int ip = npnt; ip--;) { +// AlignmentPoint* pnt = mAlgTrack->getPoint(ip); +// // +// if (pnt->containsMeasurement()) { +// // pnt->Print("meas"); +// for (int idim = 2; idim--;) { // each point has 2 position residuals +// double sigma2 = pnt->getErrDiag(idim); // residual error +// double resid = mAlgTrack->getResidual(idim, ip); // residual +// double* deriv = mAlgTrack->getDResDLoc(idim, ip); // array of Dresidual/Dparams +// // +// double sg2inv = 1. / sigma2; +// for (int parI = nlocpar; parI--;) { +// vec[parI] -= deriv[parI] * resid * sg2inv; +// // printf("%d %d %d %+e %+e %+e -> %+e\n",ip,idim,parI,sg2inv,deriv[parI],resid,vec[parI]); +// // for (int parJ=nlocpar;parJ--;) { +// for (int parJ = parI + 1; parJ--;) { +// mat(parI, parJ) += deriv[parI] * deriv[parJ] * sg2inv; +// } +// } +// } // loop over 2 orthogonal measurements at the point +// } // derivarives at measured points +// // +// // if the point contains material, consider its expected kinks, eloss +// // as measurements +// if (pnt->containsMaterial()) { +// // at least 4 parameters: 2 spatial + 2 angular kinks with 0 expectaction +// int npm = pnt->getNMatPar(); +// // const float* expMatCorr = pnt->getMatCorrExp(); // expected correction (diagonalized) +// const float* expMatCov = pnt->getMatCorrCov(); // its error +// int offs = pnt->getMaxLocVarID() - npm; +// for (int ipar = 0; ipar < npm; ipar++) { +// int parI = offs + ipar; +// // expected +// // vec[parI] -= expMatCorr[ipar]/expMatCov[ipar]; // consider expectation as measurement +// mat(parI, parI) += 1. / expMatCov[ipar]; // this measurement is orthogonal to all others +// //printf("Pnt:%3d MatVar:%d DOF %3d | ExpVal: %+e Cov: %+e\n",ip,ipar,parI, expMatCorr[ipar], expMatCov[ipar]); +// } +// } // material effect descripotion params +// // +// } // loop over track points +// // +// return matp; +//} + +//____________________________________________ +void Controller::initMPRecOutput() +{ + // prepare MP record output + mMPRecFile.reset(TFile::Open(fmt::format("{}{}", mMPDatFileName, ".root").c_str(), "recreate")); + mMPRecTree = std::make_unique<TTree>("mpTree", "MPrecord Tree"); + mMPRecTree->Branch("mprec", "Millepede2Record", &mMPRecordPtr); + // +} + +//____________________________________________ +void Controller::initResidOutput() +{ + // prepare residual output + mResidFile.reset(TFile::Open(mResidFileName.c_str(), "recreate")); + mResidTree = std::make_unique<TTree>("res", "Control Residuals"); + mResidTree->Branch("t", "ResidualsController", &mCResidPtr); + // +} + +//____________________________________________ +void Controller::closeMPRecOutput() +{ + // close output + if (!mMPRecFile) { + return; + } + LOG(INFO) << "Closing " << mMPRecFile->GetName(); + mMPRecFile->cd(); + mMPRecTree->Write(); + mMPRecTree.reset(); + mMPRecFile->Close(); + mMPRecFile.reset(); +} + +//____________________________________________ +void Controller::closeResidOutput() +{ + // close output + if (!mResidFile) { + return; + } + LOG(INFO) << "Closing " << mResidFile->GetName(); + mResidFile->cd(); + mResidTree->Write(); + mResidTree.reset(); + mResidFile->Close(); + mResidFile.reset(); + mCResid.Clear(); +} + +//____________________________________________ +void Controller::closeMilleOutput() +{ + // close output + if (mMille) { + LOG(INFO) << "Closing " << mMPDatFileName.c_str() << sMPDataExt; + } + mMille.reset(); +} + +//____________________________________________ +void Controller::setMPDatFileName(const char* name) +{ + // set output file name + mMPDatFileName = name; + if (mMPDatFileName.empty()) { + mMPDatFileName = "mpData"; + } + // +} + +//____________________________________________ +void Controller::setMPParFileName(const char* name) +{ + // set MP params output file name + mMPParFileName = name; + if (mMPParFileName.empty()) { + mMPParFileName = "mpParams.txt"; + } + // +} + +//____________________________________________ +void Controller::setMPConFileName(const char* name) +{ + // set MP constraints output file name + mMPConFileName = name; + if (mMPConFileName.empty()) { + mMPConFileName = "mpConstraints.txt"; + } + // +} + +//____________________________________________ +void Controller::setMPSteerFileName(const char* name) +{ + // set MP constraints output file name + mMPSteerFileName = name; + if (mMPSteerFileName.empty()) { + mMPSteerFileName = "mpConstraints.txt"; + } + // +} + +//____________________________________________ +void Controller::setResidFileName(const char* name) +{ + // set output file name + mResidFileName = name; + if (mResidFileName.empty()) { + mResidFileName = "mpControlRes.root"; + } + // +} + +//____________________________________________ +void Controller::setOutCDBPath(const char* name) +{ + // set output storage name + mOutCDBPath = name; + if (mOutCDBPath.empty()) { + mOutCDBPath = "local://outOCDB"; + } + // +} + +//____________________________________________ +void Controller::setObligatoryDetector(DetID detID, int trtype, bool v) +{ + // mark detector presence obligatory in the track of given type + AlignableDetector* det = getDetector(detID); + if (!det) { + LOG(ERROR) << "Detector " << detID << " is not defined"; + } + if (v) { + mObligatoryDetPattern[trtype] |= detID.getMask(); + } else { + mObligatoryDetPattern[trtype] &= ~detID.getMask(); + } + if (det->isObligatory(trtype) != v) { + det->setObligatory(trtype, v); + } + // +} + +//____________________________________________ +bool Controller::addVertexConstraint() +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs AliESDtrack + // // if vertex is set and if particle is primary, add vertex as a meared point + // // + // const AliESDtrack* esdTr = fESDTrack[0]; + // if (!fVertex || !esdTr){ + // return false;} + // // + // if (esdTr->GetNcls(0) < mMinITSClforVC){ + // return false;} // not enough ITS clusters + // if (!AlignableDetectorITS::CheckHitPattern(esdTr, mITSPattforVC)){ + // return false;} + // // + // AliExternalTrackParam trc = *esdTr; + // double dz[2], dzCov[3]; + // if (!trc.PropagateToDCA(fVertex, AliTrackerBase::GetBz(), 2 * mMaxDCAforVC[0], dz, dzCov)){ + // return false;} + // // + // // check if primary candidate + // if (Abs(dz[0]) > mMaxDCAforVC[0] || Abs(dz[1]) > mMaxDCAforVC[1]){ + // return false;} + // double covar[6]; + // fVertex->GetCovMatrix(covar); + // double p[2] = {trc.GetParameter()[0] - dz[0], trc.GetParameter()[1] - dz[1]}; + // double c[3] = {0.5 * (covar[0] + covar[2]), 0., covar[5]}; + // double chi2 = trc.GetPredictedChi2(p, c); + // if (chi2 > mMaxChi2forVC){ + // return false;} + // // + // // assing measured vertex rotated to VtxSens frame as reference point + // double xyz[3], xyzT[3]; + // fVertex->GetXYZ(xyz); + // mVtxSens->setAlpha(trc.GetAlpha()); + // // usually translation from GLO to TRA frame should go via matrix T2G + // // but for the VertexSensor Local and Global are the same frames + // mVtxSens->applyCorrection(xyz); + // mVtxSens->getMatrixT2L().MasterToLocal(xyz, xyzT); + // mRefPoint->setSensor(mVtxSens); + // mRefPoint->setAlphaSens(mVtxSens->getAlpTracking()); + // mRefPoint->setXYZTracking(xyzT); + // mRefPoint->setYZErrTracking(c); + // mRefPoint->setContainsMeasurement(true); + // mRefPoint->init(); + // // + return true; +} + +//FIXME(milettri): needs OCDB +////______________________________________________________ +//void Controller::writeCalibrationResults() const +//{ +// // writes output calibration +// CleanOCDB(); +// AliCDBManager::Instance()->SetDefaultStorage(mOutCDBPath.c_str()); +// // +// AlignableDetector* det; +// for (auto id=DetID::First; id<=DetID::Last; id++) { +// if (!(det = getDetector(id)) || det->isDisabled()){ +// continue; +// } +// det->writeCalibrationResults(); +// } +// // +//} + +//FIXME(milettri): needs OCDB +////______________________________________________________ +//void Controller::SetOutCDBRunRange(int rmin, int rmax) +//{ +// // set output run range +// mOutCDBRunRange[0] = rmin >= 0 ? rmin : 0; +// mOutCDBRunRange[1] = rmax > mOutCDBRunRange[0] ? rmax : AliCDBRunRange::Infinity(); +//} + +//FIXME(milettri): needs OCDB +////______________________________________________________ +//bool Controller::LoadRefOCDB() +//{ +// // setup OCDB whose objects will be used as a reference with respect to which the +// // alignment/calibration will prodice its corrections. +// // Detectors which need some reference calibration data must use this one +// // +// // +// LOG(INFO) << "Loading reference OCDB"); +// CleanOCDB(); +// AliCDBManager* man = AliCDBManager::Instance(); +// // +// if (!mRefOCDBConf.IsNull() && !gSystem->AccessPathName(mRefOCDBConf.c_str(), kFileExists)) { +// LOG(INFO) << "Executing reference OCDB setup macro %s", mRefOCDBConf.c_str()); +// if (mRefRunNumber > 0){ +// gROOT->ProcessLine(Form(".x %s(%d)", mRefOCDBConf.c_str(), mRefRunNumber));} +// else +// gROOT->ProcessLine(Form(".x %s", mRefOCDBConf.c_str())); +// } else { +// LOG(WARNING) << "No reference OCDB config macro "<<mRefOCDBConf.c_str()<<" is found, assume raw:// with run " << AliCDBRunRange::Infinity(); +// man->SetRaw(true); +// man->SetRun(AliCDBRunRange::Infinity()); +// } +// // +// if (AliGeomManager::GetGeometry()) { +// LOG(INFO) << "Destroying current geometry before loading reference one"); +// AliGeomManager::Destroy(); +// } +// AliGeomManager::LoadGeometry("geometry.root"); +// if (!AliGeomManager::GetGeometry()){ +// LOG(FATAL) << "Failed to load geometry, cannot run");} +// // +// TString detList = ""; +// for (int i = 0; i < kNDetectors; i++) { +// detList += getDetNameByDetID(i); +// detList += " "; +// } +// AliGeomManager::ApplyAlignObjsFromCDB(detList.c_str()); +// // +// mRefOCDBLoaded++; +// // +// return true; +//} + +//________________________________________________________ +AlignableDetector* Controller::getDetOfDOFID(int id) const +{ + // return detector owning DOF with this ID + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (det && det->ownsDOFID(id)) { + return det; + } + } + return nullptr; +} + +//________________________________________________________ +AlignableVolume* Controller::getVolOfDOFID(int id) const +{ + // return volume owning DOF with this ID + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (det && det->ownsDOFID(id)) { + return det->getVolOfDOFID(id); + } + } + if (mVtxSens && mVtxSens->ownsDOFID(id)) { + return mVtxSens.get(); + } + return nullptr; +} + +//________________________________________________________ +void Controller::terminate(bool doStat) +{ + // finalize processing + if (mRunNumber > 0) { + fillStatHisto(kRunDone); + } + if (doStat) { + if (mVtxSens) { + mVtxSens->fillDOFStat(mDOFStat); + } + } + // + for (auto id = DetID::First; id <= DetID::Last; id++) { + if (getDetector(id)) { + getDetector(id)->terminate(); + } + } + closeMPRecOutput(); + closeMilleOutput(); + closeResidOutput(); + Print("stat"); + // +} + +//________________________________________________________ +Char_t* Controller::getDOFLabelTxt(int idf) const +{ + // get DOF full label + AlignableVolume* vol = getVolOfDOFID(idf); + if (vol) { + return Form("%d_%s_%s", getGloParLab(idf), vol->getSymName(), + vol->getDOFName(idf - vol->getFirstParGloID())); + } + // + // this might be detector-specific calibration dof + AlignableDetector* det = getDetOfDOFID(idf); + if (det) { + return Form("%d_%s_%s", getGloParLab(idf), det->GetName(), + det->getCalibDOFName(idf - det->getFirstParGloID())); + } + return nullptr; +} + +//********************* interaction with PEDE ********************** + +//______________________________________________________ +void Controller::genPedeSteerFile(const Option_t* opt) const +{ + // produce steering file template for PEDE + params and constraints + // + enum { kOff, + kOn, + kOnOn }; + const char* cmt[3] = {" ", "! ", "!!"}; + const char* kSolMeth[] = {"inversion", "diagonalization", "fullGMRES", "sparseGMRES", "cholesky", "HIP"}; + const int kDefNIter = 3; // default number of iterations to ask + const float kDefDelta = 0.1; // def. delta to exit + TString opts = opt; + opts.ToLower(); + LOG(INFO) << "Generating MP2 templates:\n " + << "Steering :\t" << mMPSteerFileName << "\n" + << "Parameters :\t" << mMPParFileName << "\n" + << "Constraints:\t" << mMPConFileName << "\n"; + // + FILE* parFl = fopen(mMPParFileName.c_str(), "w+"); + FILE* strFl = fopen(mMPSteerFileName.c_str(), "w+"); + // + // --- template of steering file + fprintf(strFl, "%-20s%s %s\n", mMPParFileName.c_str(), cmt[kOnOn], "parameters template"); + fprintf(strFl, "%-20s%s %s\n", mMPConFileName.c_str(), cmt[kOnOn], "constraints template"); + // + fprintf(strFl, "\n\n%s %s\n", cmt[kOnOn], "MUST uncomment 1 solving methods and tune it"); + // + int nm = sizeof(kSolMeth) / sizeof(char*); + for (int i = 0; i < nm; i++) { + fprintf(strFl, "%s%s %-20s %2d %.2f %s\n", cmt[kOn], "method", kSolMeth[i], kDefNIter, kDefDelta, cmt[kOnOn]); + } + // + const float kDefChi2F0 = 20., kDefChi2F = 3.; // chi2 factors for 1st and following iterations + const float kDefDWFrac = 0.2; // cut outliers with downweighting above this factor + const int kDefOutlierDW = 4; // start Cauchy function downweighting from iteration + const int kDefEntries = 25; // min entries per DOF to allow its variation + // + fprintf(strFl, "\n\n%s %s\n", cmt[kOnOn], "Optional settings"); + fprintf(strFl, "\n%s%-20s %.2f %.2f %s %s\n", cmt[kOn], "chisqcut", kDefChi2F0, kDefChi2F, + cmt[kOnOn], "chi2 cut factors for 1st and next iterations"); + fprintf(strFl, "%s%-20s %2d %s %s\n", cmt[kOn], "outlierdownweighting", kDefOutlierDW, + cmt[kOnOn], "iteration for outliers downweighting with Cauchi factor"); + fprintf(strFl, "%s%-20s %.3f %s %s\n", cmt[kOn], "dwfractioncut", kDefDWFrac, + cmt[kOnOn], "cut outliers with downweighting above this factor"); + fprintf(strFl, "%s%-20s %2d %s %s\n", cmt[kOn], "entries", kDefEntries, + cmt[kOnOn], "min entries per DOF to allow its variation"); + // + fprintf(strFl, "\n\n\n%s%-20s %s %s\n\n\n", cmt[kOff], "CFiles", cmt[kOnOn], "put below *.mille files list"); + // + if (mVtxSens) { + mVtxSens->writePedeInfo(parFl, opt); + } + // + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det || det->isDisabled()) { + continue; + } + det->writePedeInfo(parFl, opt); + // + } + // + writePedeConstraints(); + // + fclose(strFl); + fclose(parFl); + // +} + +//___________________________________________________________ +bool Controller::readParameters(const char* parfile, bool useErrors) +{ + // read parameters file (millepede output) + if (mNDOFs < 1 || mGloParVal.size() || mGloParErr.size()) { + LOG(ERROR) << "Something is wrong in init: mNDOFs=" << mNDOFs << " N GloParVal=" << mGloParVal.size() << " N GloParErr=" << mGloParErr.size(); + } + ifstream inpf(parfile); + if (!inpf.good()) { + printf("Failed on input filename %s\n", parfile); + return false; + } + mGloParVal.resize(mNDOFs); + if (useErrors) { + mGloParErr.resize(mNDOFs); + } + int cnt = 0; + TString fline; + fline.ReadLine(inpf); + fline = fline.Strip(TString::kBoth, ' '); + fline.ToLower(); + if (!fline.BeginsWith("parameter")) { + LOG(ERROR) << "First line is not parameter keyword: " << fline.Data(); + return false; + } + double v0, v1, v2; + int lab, asg = 0, asg0 = 0; + while (fline.ReadLine(inpf)) { + cnt++; + fline = fline.Strip(TString::kBoth, ' '); + if (fline.BeginsWith("!") || fline.BeginsWith("*")) { + continue; + } // ignore comment + int nr = sscanf(fline.Data(), "%d%lf%lf%lf", &lab, &v0, &v1, &v2); + if (nr < 3) { + LOG(ERROR) << "Expected to read at least 3 numbers, got " << nr << ", this is NOT milleped output"; + LOG(ERROR) << "line (" << cnt << ") was:\n " << fline.Data(); + return false; + } + if (nr == 3) { + asg0++; + } + int parID = label2ParID(lab); + if (parID < 0 || parID >= mNDOFs) { + LOG(ERROR) << "Invalid label " << lab << " at line " << cnt << " -> ParID=" << parID; + return false; + } + mGloParVal[parID] = -v0; + if (useErrors) { + mGloParErr[parID] = v1; + } + asg++; + // + }; + LOG(INFO) << "Read " << cnt << " lines, assigned " << asg << " values, " << asg0 << " dummy"; + // + return true; +} + +//______________________________________________________ +void Controller::checkConstraints(const char* params) +{ + // check how the constraints are satisfied with already uploaded or provided params + // + if (params && !readParameters(params)) { + LOG(ERROR) << "Failed to load parameters from " << params; + return; + } + // + int ncon = getNConstraints(); + for (int icon = 0; icon < ncon; icon++) { + const GeometricalConstraint* con = getConstraint(icon); + con->checkConstraint(); + } + // +} + +//___________________________________________________________ +void Controller::mPRec2Mille(const char* mprecfile, const char* millefile, bool bindata) +{ + // converts MPRecord tree to millepede binary format + TFile* flmpr = TFile::Open(mprecfile); + if (!flmpr) { + LOG(ERROR) << "Failed to open MPRecord file " << mprecfile; + return; + } + TTree* mprTree = (TTree*)flmpr->Get("mpTree"); + if (!mprTree) { + LOG(ERROR) << "No mpTree in xMPRecord file " << mprecfile; + return; + } + mPRec2Mille(mprTree, millefile, bindata); + delete mprTree; + flmpr->Close(); + delete flmpr; +} + +//___________________________________________________________ +void Controller::mPRec2Mille(TTree* mprTree, const char* millefile, bool bindata) +{ + // converts MPRecord tree to millepede binary format + // + TBranch* br = mprTree->GetBranch("mprec"); + if (!br) { + LOG(ERROR) << "provided tree does not contain branch mprec"; + return; + } + Millepede2Record* rec = new Millepede2Record(); + br->SetAddress(&rec); + int nent = mprTree->GetEntries(); + TString mlname = millefile; + if (mlname.IsNull()) { + mlname = "mpRec2mpData"; + } + if (!mlname.EndsWith(sMPDataExt)) { + mlname += sMPDataExt; + } + Mille* mille = new Mille(mlname, bindata); + TArrayF buffDLoc; + for (int i = 0; i < nent; i++) { + br->GetEntry(i); + int nr = rec->getNResid(); // number of residual records + int nloc = rec->getNVarLoc(); + if (buffDLoc.GetSize() < nloc) { + buffDLoc.Set(nloc + 100); + } + float* buffLocV = buffDLoc.GetArray(); + const float* recDGlo = rec->getArrGlo(); + const float* recDLoc = rec->getArrLoc(); + const short* recLabLoc = rec->getArrLabLoc(); + const int* recLabGlo = rec->getArrLabGlo(); + // + for (int ir = 0; ir < nr; ir++) { + memset(buffLocV, 0, nloc * sizeof(float)); + int ndglo = rec->getNDGlo(ir); + int ndloc = rec->getNDLoc(ir); + // fill 0-suppressed array from MPRecord to non-0-suppressed array of Mille + for (int l = ndloc; l--;) { + buffLocV[recLabLoc[l]] = recDLoc[l]; + } + // + mille->mille(nloc, buffLocV, ndglo, recDGlo, recLabGlo, rec->getResid(ir), rec->getResErr(ir)); + // + recLabGlo += ndglo; // next record + recDGlo += ndglo; + recLabLoc += ndloc; + recDLoc += ndloc; + } + mille->end(); + } + delete mille; + br->SetAddress(nullptr); + delete rec; +} + +//____________________________________________________________ +void Controller::fillStatHisto(int type, float w) +{ + if (!mHistoStat) { + createStatHisto(); + } + mHistoStat->Fill((isCosmic() ? kNHVars : 0) + type, w); +} + +//____________________________________________________________ +void Controller::createStatHisto() +{ + mHistoStat = new TH1F("stat", "stat", 2 * kNHVars, -0.5, 2 * kNHVars - 0.5); + mHistoStat->SetDirectory(nullptr); + TAxis* xax = mHistoStat->GetXaxis(); + for (int j = 0; j < 2; j++) { + for (int i = 0; i < kNHVars; i++) { + xax->SetBinLabel(j * kNHVars + i + 1, Form("%s.%s", j ? "CSM" : "COL", sHStatName[i])); + } + } +} + +//____________________________________________________________ +void Controller::printLabels() const +{ + // print global IDs and Labels + for (int i = 0; i < mNDOFs; i++) { + printf("%5d %s\n", i, getDOFLabelTxt(i)); + } +} + +//____________________________________________________________ +int Controller::label2ParID(int lab) const +{ + // convert Mille label to ParID (slow) + int ind = 0; // FIXME RS TODO // findKeyIndex(lab, mOrderedLbl, mNDOFs); + if (ind < 0) { + return -1; + } + return mLbl2ID[ind]; +} + +//____________________________________________________________ +void Controller::addAutoConstraints() +{ + // add default constraints on children cumulative corrections within the volumes + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det || det->isDisabled()) { + continue; + } + det->addAutoConstraints(); + } + LOG(INFO) << "Added " << getNConstraints() << " automatic constraints"; +} + +//____________________________________________________________ +void Controller::writePedeConstraints() const +{ + // write constraints file + FILE* conFl = fopen(mMPConFileName.c_str(), "w+"); + // + int nconstr = getNConstraints(); + for (int icon = 0; icon < nconstr; icon++) { + getConstraint(icon)->writeChildrenConstraints(conFl); + } + // + fclose(conFl); +} + +//____________________________________________________________ +void Controller::fixLowStatFromDOFStat(int thresh) +{ + // fix DOFs having stat below threshold + // + if (mNDOFs != mDOFStat.getNDOFs()) { + LOG(ERROR) << "Discrepancy between NDOFs=" << mNDOFs << " of and statistics object: " << mDOFStat.getNDOFs(); + return; + } + for (int parID = 0; parID < mNDOFs; parID++) { + if (mDOFStat.getStat(parID) >= thresh) { + continue; + } + mGloParErr[parID] = -999.; + } + // +} + +//____________________________________________________________ +void Controller::loadStat(const char* flname) +{ + // load statistics histos from external file produced by alignment task + TFile* fl = TFile::Open(flname); + // + TObject *hdfO = nullptr, *hstO = nullptr; + TList* lst = (TList*)fl->Get("clist"); + if (lst) { + hdfO = lst->FindObject("DOFstat"); + if (hdfO) { + lst->Remove(hdfO); + } + hstO = lst->FindObject("stat"); + if (hstO) { + lst->Remove(hstO); + } + delete lst; + } else { + hdfO = fl->Get("DOFstat"); + hstO = fl->Get("stat"); + } + TH1F* hst = nullptr; + if (hstO && (hst = dynamic_cast<TH1F*>(hstO))) { + hst->SetDirectory(nullptr); + } else { + LOG(WARNING) << "did not find stat histo"; + } + // + DOFStatistics* dofSt = nullptr; + if (!hdfO || !(dofSt = dynamic_cast<DOFStatistics*>(hdfO))) { + LOG(WARNING) << "did not find DOFstat object"; + } + // + setHistoStat(hst); + setDOFStat(*dofSt); // FIXME RS TODO + // + fl->Close(); + delete fl; +} + +//______________________________________________ +void Controller::checkSol(TTree* mpRecTree, bool store, + bool verbose, bool loc, const char* outName) +{ + // do fast check of pede solution with MPRecord tree + ResidualsControllerFast* rLG = store ? new ResidualsControllerFast() : nullptr; + ResidualsControllerFast* rL = store && loc ? new ResidualsControllerFast() : nullptr; + TTree *trLG = nullptr, *trL = nullptr; + TFile* outFile = nullptr; + if (store) { + TString outNS = outName; + if (outNS.IsNull()) { + outNS = "resFast"; + } + if (!outNS.EndsWith(".root")) { + outNS += ".root"; + } + outFile = TFile::Open(outNS.Data(), "recreate"); + trLG = new TTree("resFLG", "Fast residuals with LG correction"); + trLG->Branch("rLG", "ResidualsControllerFast", &rLG); + // + if (rL) { + trL = new TTree("resFL", "Fast residuals with L correction"); + trL->Branch("rL", "ResidualsControllerFast", &rL); + } + } + // + Millepede2Record* rec = new Millepede2Record(); + mpRecTree->SetBranchAddress("mprec", &rec); + int nrec = mpRecTree->GetEntriesFast(); + for (int irec = 0; irec < nrec; irec++) { + mpRecTree->GetEntry(irec); + checkSol(rec, rLG, rL, verbose, loc); + // store even in case of failure, to have the trees aligned with controlRes + if (trLG) { + trLG->Fill(); + } + if (trL) { + trL->Fill(); + } + } + // + // save + if (trLG) { + outFile->cd(); + trLG->Write(); + delete trLG; + if (trL) { + trL->Write(); + delete trL; + } + outFile->Close(); + delete outFile; + } + // +} + +//______________________________________________ +bool Controller::checkSol(Millepede2Record* rec, + ResidualsControllerFast* rLG, ResidualsControllerFast* rL, + bool verbose, bool loc) +{ + LOG(FATAL) << __PRETTY_FUNCTION__ << " is disabled"; + //FIXME(milettri): needs AliSymMatrix + // // Check pede solution using derivates, rather than updated geometry + // // If loc==true, also produces residuals for current geometry, + // // neglecting global corrections + // // + // if (rL){ + // loc = true;} // if local sol. tree asked, always evaluate it + // // + // int nres = rec->getNResid(); + // // + // const float* recDGlo = rec->getArrGlo(); + // const float* recDLoc = rec->getArrLoc(); + // const short* recLabLoc = rec->getArrLabLoc(); + // const int* recLabGlo = rec->getArrLabGlo(); + // int nvloc = rec->getNVarLoc(); + // // + // // count number of real measurement duplets and material correction fake 4-plets + // int nPoints = 0; + // int nMatCorr = 0; + // for (int irs = 0; irs < nres; irs++) { + // if (rec->getNDGlo(irs) > 0) { + // if (irs == nres - 1 || rec->getNDGlo(irs + 1) == 0){ + // LOG(FATAL) << ("Real coordinate measurements must come in pairs");} + // nPoints++; + // irs++; // skip 2nd + // continue; + // } else if (rec->getResid(irs) == 0 && rec->getVolID(irs) == -1) { // material corrections have 0 residual + // nMatCorr++; + // } else { // might be fixed parameter, global derivs are skept + // nPoints++; + // irs++; // skip 2nd + // continue; + // } + // } + // // + // if (nMatCorr % 4){ + // LOG(WARNING) << "Error? NMatCorr=" << nMatCorr << " is not multiple of 4";} + // // + // if (rLG) { + // rLG->Clear(); + // rLG->setNPoints(nPoints); + // rLG->setNMatSol(nMatCorr); + // rLG->setCosmic(rec->isCosmic()); + // } + // if (rL) { + // rL->Clear(); + // rL->setNPoints(nPoints); + // rL->setNMatSol(nMatCorr); + // rL->setCosmic(rec->isCosmic()); + // } + // // + // AliSymMatrix* matpG = new AliSymMatrix(nvloc); + // TVectorD *vecp = 0, *vecpG = new TVectorD(nvloc); + // // + // if (loc){ + // vecp = new TVectorD(nvloc);} + // // + // float chi2Ini = 0, chi2L = 0, chi2LG = 0; + // // + // // residuals, accounting for global solution + // double* resid = new double[nres]; + // int* volID = new int[nres]; + // for (int irs = 0; irs < nres; irs++) { + // double resOr = rec->getResid(irs); + // resid[irs] = resOr; + // // + // int ndglo = rec->getNDGlo(irs); + // int ndloc = rec->getNDLoc(irs); + // volID[irs] = 0; + // for (int ig = 0; ig < ndglo; ig++) { + // int lbI = recLabGlo[ig]; + // int idP = label2ParID(lbI); + // if (idP < 0){ + // LOG(FATAL) << "Did not find parameted for label " << lbI;} + // double parVal = getGloParVal()[idP]; + // // resid[irs] -= parVal*recDGlo[ig]; + // resid[irs] += parVal * recDGlo[ig]; + // if (!ig) { + // AlignableVolume* vol = getVolOfDOFID(idP); + // if (vol){ + // volID[irs] = vol->getVolID();} + // else + // volID[irs] = -2; // calibration DOF !!! TODO + // } + // } + // // + // double sg2inv = rec->getResErr(irs); + // sg2inv = 1. / (sg2inv * sg2inv); + // // + // chi2Ini += resid[irs] * resid[irs] * sg2inv; // chi accounting for global solution only + // // + // // Build matrix to solve local parameters + // for (int il = 0; il < ndloc; il++) { + // int lbLI = recLabLoc[il]; // id of local variable + // (*vecpG)[lbLI] -= recDLoc[il] * resid[irs] * sg2inv; + // if (loc){ + // (*vecp)[lbLI] -= recDLoc[il] * resOr * sg2inv;} + // for (int jl = il + 1; jl--;) { + // int lbLJ = recLabLoc[jl]; // id of local variable + // (*matpG)(lbLI, lbLJ) += recDLoc[il] * recDLoc[jl] * sg2inv; + // } + // } + // // + // recLabGlo += ndglo; // prepare for next record + // recDGlo += ndglo; + // recLabLoc += ndloc; + // recDLoc += ndloc; + // // + // } + // // + // if (rL){ + // rL->setChi2Ini(chi2Ini);} + // if (rLG){ + // rLG->setChi2Ini(chi2Ini);} + // // + // TVectorD vecSol(nvloc); + // TVectorD vecSolG(nvloc); + // // + // if (!matpG->SolveChol(*vecpG, vecSolG, false)) { + // LOG(INFO) << "Failed to solve track corrected for globals"; + // delete matpG; + // matpG = 0; + // } else if (loc) { // solution with local correction only + // if (!matpG->SolveChol(*vecp, vecSol, false)) { + // LOG(INFO) << "Failed to solve track corrected for globals"; + // delete matpG; + // matpG = 0; + // } + // } + // delete vecpG; + // delete vecp; + // if (!matpG) { // failed + // delete[] resid; + // delete[] volID; + // if (rLG){ + // rLG->Clear();} + // if (rL){ + // rL->Clear();} + // return false; + // } + // // check + // recDGlo = rec->getArrGlo(); + // recDLoc = rec->getArrLoc(); + // recLabLoc = rec->getArrLabLoc(); + // recLabGlo = rec->getArrLabGlo(); + // // + // if (verbose) { + // printf(loc ? "Sol L/LG:\n" : "Sol LG:\n"); + // int nExtP = (nvloc % 4) ? 5 : 4; + // for (int i = 0; i < nExtP; i++){ + // loc ? printf("%+.3e/%+.3e ", vecSol[i], vecSolG[i]) : printf("%+.3e ", vecSolG[i]);} + // printf("\n"); + // bool nln = true; + // int cntL = 0; + // for (int i = nExtP; i < nvloc; i++) { + // nln = true; + // loc ? printf("%+.3e/%+.3e ", vecSol[i], vecSolG[i]) : printf("%+.3e ", vecSolG[i]); + // if (((++cntL) % 4) == 0) { + // printf("\n"); + // nln = false; + // } + // } + // if (!nln){ + // printf("\n");} + // if (loc){ + // printf("%3s (%9s) %6s | [ %7s:%7s ] [ %7s:%7s ]\n", "Pnt", "Label", + // "Sigma", "resid", "pull/L ", "resid", "pull/LG");} + // else{ + // printf("%3s (%9s) %6s | [ %7s:%7s ]\n", "Pnt", "Label", + // "Sigma", "resid", "pull/LG");} + // } + // int idMeas = -1, pntID = -1, matID = -1; + // for (int irs = 0; irs < nres; irs++) { + // double resOr = rec->getResid(irs); + // double resL = resOr; + // double resLG = resid[irs]; + // double sg = rec->getResErr(irs); + // double sg2Inv = 1 / (sg * sg); + // // + // int ndglo = rec->getNDGlo(irs); + // int ndloc = rec->getNDLoc(irs); + // // + // for (int il = 0; il < ndloc; il++) { + // int lbLI = recLabLoc[il]; // id of local variable + // resL += recDLoc[il] * vecSol[lbLI]; + // resLG += recDLoc[il] * vecSolG[lbLI]; + // } + // // + // chi2L += resL * resL * sg2Inv; // chi accounting for global solution only + // chi2LG += resLG * resLG * sg2Inv; // chi accounting for global solution only + // // + // if (ndglo || resOr != 0) { // real measurement + // idMeas++; + // if (idMeas > 1){ + // idMeas = 0;} + // if (idMeas == 0){ + // pntID++;} // measurements come in pairs + // int lbl = rec->getVolID(irs); + // lbl = ndglo ? recLabGlo[0] : 0; // TMP, until VolID is filled // RS!!!! + // if (rLG) { + // rLG->setResSigMeas(pntID, idMeas, resLG, sg); + // if (idMeas == 0){ + // rLG->setLabel(pntID, lbl, volID[irs]);} + // } + // if (rL) { + // rL->setResSigMeas(pntID, idMeas, resL, sg); + // if (idMeas == 0){ + // rL->setLabel(pntID, lbl, volID[irs]);} + // } + // } else { + // matID++; // mat.correcitons come in 4-plets, but we fill each separately + // // + // if (rLG){ + // rLG->setMatCorr(matID, resLG, sg);} + // if (rL){ + // rL->setMatCorr(matID, resL, sg);} + // } + // // + // if (verbose) { + // int lbl = rec->getVolID(irs); + // lbl = ndglo ? recLabGlo[0] : (resOr == 0 ? -1 : 0); // TMP, until VolID is filled // RS!!!! + // if (loc){ + // printf("%3d (%9d) %6.4f | [%+.2e:%+7.2f] [%+.2e:%+7.2f]\n", + // irs, lbl, sg, resL, resL / sg, resLG, resLG / sg);} + // else + // printf("%3d (%9d) %6.4f | [%+.2e:%+7.2f]\n", + // irs, lbl, sg, resLG, resLG / sg); + // } + // // + // recLabGlo += ndglo; // prepare for next record + // recDGlo += ndglo; + // recLabLoc += ndloc; + // recDLoc += ndloc; + // } + // if (rL){ + // rL->setChi2(chi2L);} + // if (rLG){ + // rLG->setChi2(chi2LG);} + // // + // if (verbose) { + // printf("Chi: G = %e | LG = %e", chi2Ini, chi2LG); + // if (loc){ + // printf(" | L = %e", chi2L);} + // printf("\n"); + // } + // // store track corrections + // int nTrCor = nvloc - matID - 1; + // for (int i = 0; i < nTrCor; i++) { + // if (rLG){ + // rLG->getTrCor()[i] = vecSolG[i];} + // if (rL){ + // rL->getTrCor()[i] = vecSol[i];} + // } + // // + // delete[] resid; + // delete[] volID; + return true; +} + +//______________________________________________ +void Controller::applyAlignmentFromMPSol() +{ + // apply alignment from millepede solution array to reference alignment level + LOG(INFO) << "Applying alignment from Millepede solution"; + for (auto id = DetID::First; id <= DetID::Last; id++) { + AlignableDetector* det = getDetector(id); + if (!det || det->isDisabled()) { + continue; + } + det->applyAlignmentFromMPSol(); + } + setMPAlignDone(); + // +} + +//______________________________________________ +void Controller::expandGlobalsBy(int n) +{ + // expand global param contaiers by n + int snew = n + mGloParVal.size(); + mGloParVal.resize(snew); + mGloParErr.resize(snew); + mGloParLab.resize(snew); + mOrderedLbl.resize(snew); + mLbl2ID.resize(snew); + mNDOFs += n; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/DOFSet.cxx b/Detectors/Align/src/DOFSet.cxx new file mode 100644 index 0000000000000..01a91de372d2a --- /dev/null +++ b/Detectors/Align/src/DOFSet.cxx @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DOFSet.cxx +/// @author ruben.shahoyan@cern.ch +/// @brief Interface to contiguous set of DOFs in the controller class + +#include "Align/DOFSet.h" +#include "Align/Controller.h" + +using namespace o2::align; + +DOFSet::DOFSet(const char* symname, Controller* ctr) : TNamed(symname, ""), mController(ctr) +{ + if (!ctr) { + LOG(FATAL) << "Controller has to be provided :" << symname; + } +} + +//_________________________________________________________ +const float* DOFSet::getParVals() const +{ + return &mController->getGloParVal()[mFirstParGloID]; +} + +//_________________________________________________________ +const float* DOFSet::getParErrs() const +{ + return &mController->getGloParErr()[mFirstParGloID]; +} + +//_________________________________________________________ +const int* DOFSet::getParLabs() const +{ + return &mController->getGloParLab()[mFirstParGloID]; +} + +//_________________________________________________________ +float* DOFSet::getParVals() +{ + return &mController->getGloParVal()[mFirstParGloID]; +} + +//_________________________________________________________ +float* DOFSet::getParErrs() +{ + return &mController->getGloParErr()[mFirstParGloID]; +} + +//_________________________________________________________ +int* DOFSet::getParLabs() +{ + return &mController->getGloParLab()[mFirstParGloID]; +} diff --git a/Detectors/Align/src/DOFStatistics.cxx b/Detectors/Align/src/DOFStatistics.cxx new file mode 100644 index 0000000000000..8df1c3f6b2a69 --- /dev/null +++ b/Detectors/Align/src/DOFStatistics.cxx @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DOFStatistics.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Mergable bbject for statistics of points used by each DOF + +#include "Align/DOFStatistics.h" +#include "Align/Controller.h" +#include "Framework/Logger.h" +#include <TCollection.h> + +ClassImp(o2::align::DOFStatistics); + +namespace o2 +{ +namespace align +{ + +//____________________________________________ +std::unique_ptr<TH1F> DOFStatistics::buildHistogram(Controller* controller) const +{ + // create histo with stat. If steer object is supplied, build labels + auto histogram = std::make_unique<TH1F>("DOFstat", "statistics per DOF", getNDOFs(), 0, getNDOFs()); + for (size_t i = 0; i < getNDOFs(); ++i) { + // Bin 0 is underflow bin + histogram->SetBinContent(i + 1, mStat[i]); + if (controller != nullptr) { + histogram->GetXaxis()->SetBinLabel(i + 1, controller->getDOFLabelTxt(i)); + } + } + return histogram; +} + +//______________________________________________________________________________ +int64_t DOFStatistics::merge(TCollection* list) +{ + // merge statistics + int nMerged = 0; + TIter next{list}; + TObject* obj = nullptr; + while ((obj = next()) != nullptr) { + DOFStatistics* otherStats = dynamic_cast<DOFStatistics*>(obj); + if (!otherStats) { + continue; + } + assert(getNDOFs() == otherStats->getNDOFs()); + std::transform(std::begin(otherStats->mStat), std::end(otherStats->mStat), std::begin(mStat), std::begin(mStat), std::plus<>{}); + mNMerges += otherStats->mNMerges; + nMerged++; + } + return nMerged; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/EventVertex.cxx b/Detectors/Align/src/EventVertex.cxx new file mode 100644 index 0000000000000..9ec705ab3378b --- /dev/null +++ b/Detectors/Align/src/EventVertex.cxx @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EventVertex.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Special fake "sensor" for event vertex. + +#include "Align/Controller.h" +#include "Align/EventVertex.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableDetector.h" +#include "Framework/Logger.h" +#include <TMath.h> + +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +EventVertex::EventVertex(Controller* ctr) : AlignableSensor("Vertex", 0, 1, ctr) +{ + // def c-tor + setVarFrame(kLOC); + setFreeDOFPattern(BIT(kDOFTX) | BIT(kDOFTY) | BIT(kDOFTZ)); + // +} + +//____________________________________________ +void EventVertex::prepareMatrixT2L() +{ + // T2L matrix for vertex needs to be adjusted for every track + // in order to have X axis along the track direction. + // This method assumes that the mAlp was already set accordingly + // fX is fixed to 0 + // + mMatT2L.Clear(); + mMatT2L.RotateZ(mAlp * RadToDeg()); + // mMatT2L.MultiplyLeft(&getMatrixL2GIdeal().Inverse()); L2G=I !!! + // +} + +//____________________________________________ +void EventVertex::applyCorrection(double* vtx) const +{ + // apply eventual correction to supplied vertex position + vtx[kDOFTX] += getParVal(kDOFTX); + vtx[kDOFTY] += getParVal(kDOFTY); + vtx[kDOFTZ] += getParVal(kDOFTZ); + // +} + +//FIXME(milettri): needs AliTrackPointArray, AliESDtrack +////____________________________________________ +//AlignmentPoint* EventVertex::TrackPoint2AlgPoint(int, const AliTrackPointArray*, const AliESDtrack*) +//{ +// // convert the pntId-th point to AlignmentPoint +// static int cnt = 0; +// LOG(ERROR) << "This method shound not have been called," << cnt++; +// return 0; +//} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/GeometricalConstraint.cxx b/Detectors/Align/src/GeometricalConstraint.cxx new file mode 100644 index 0000000000000..3cbb71f43da87 --- /dev/null +++ b/Detectors/Align/src/GeometricalConstraint.cxx @@ -0,0 +1,426 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GeometricalConstraint.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Descriptor of geometrical constraint + +#include "Align/GeometricalConstraint.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "Align/utils.h" +#include "Framework/Logger.h" +#include <TGeoMatrix.h> +#include <TMath.h> +#include <cstdio> + +ClassImp(o2::align::GeometricalConstraint); + +using namespace o2::align::utils; +using namespace TMath; + +namespace o2 +{ +namespace align +{ + +//___________________________________________________________________ +GeometricalConstraint::GeometricalConstraint(const char* name, const char* title) + : TNamed(name, title), mConstraint(0), mParent(nullptr), mChildren(2) +{ + // def. c-tor + for (int i = kNDOFGeom; i--;) { + mSigma[i] = 0; + } +} + +//___________________________________________________________________ +GeometricalConstraint::~GeometricalConstraint() +{ + // d-tor + delete mParent; +} + +//___________________________________________________________________ +void GeometricalConstraint::setParent(const AlignableVolume* par) +{ + mParent = par; + TString nm = GetName(); + if (nm.IsNull()) { + if (par) { + SetNameTitle(par->getSymName(), "Automatic"); + } else { + SetNameTitle("GLOBAL", "Automatic"); + } + } +} + +//______________________________________________________ +void GeometricalConstraint::writeChildrenConstraints(FILE* conOut) const +{ + // write for PEDE eventual constraints on children movement in parent frame + // + enum { kOff, + kOn, + kOnOn }; + enum { kConstr, + kMeas }; + const char* comment[3] = {" ", "! ", "!!"}; + const char* kKeyConstr[2] = {"constraint", "measurement"}; + // + bool doJac = !getNoJacobian(); // do we need jacobian evaluation? + int nch = getNChildren(); + float* cstrArr = new float[nch * kNDOFGeom * kNDOFGeom]; + memset(cstrArr, 0, nch * kNDOFGeom * kNDOFGeom * sizeof(float)); + // we need for each children the matrix for vector transformation from children frame + // (in which its DOFs are defined, LOC or TRA) to this parent variation frame + // matRel = mPar^-1*mChild + TGeoHMatrix mPar; + // + // in case of parent assigned use its matrix, + // otherwise Alice global frame is assumed to be the parent -> Unit matrix + if (mParent && doJac) { + if (mParent->isFrameTRA()) { + mParent->getMatrixT2G(mPar); + } // tracking to global + else { + mPar = mParent->getMatrixL2GIdeal(); + } // local to global + mPar = mPar.Inverse(); + } + // + float* jac = cstrArr; + int nContCh[kNDOFGeom] = {0}; // we need at least on contributing children DOF to constrain the parent DOF + for (int ich = 0; ich < nch; ich++) { + AlignableVolume* child = getChild(ich); + // + if (doJac) { // calculate jacobian + TGeoHMatrix matRel; + if (child->isFrameTRA()) { + child->getMatrixT2G(matRel); + } // tracking to global + else { + matRel = child->getMatrixL2GIdeal(); + } // local to global + matRel.MultiplyLeft(&mPar); + constrCoefGeom(matRel, jac); + // + for (int ics = 0; ics < kNDOFGeom; ics++) { // DOF of parent to be constrained + for (int ip = 0; ip < kNDOFGeom; ip++) { // count contributing DOFs + float jv = jac[ics * kNDOFGeom + ip]; + if (!isZeroAbs(jv) && child->isFreeDOF(ip) && child->getParErr(ip) >= 0) { + nContCh[ip]++; + } + } + } + } else { // simple constraint on the sum of requested DOF + // + for (int ip = 0; ip < kNDOFGeom; ip++) { + if (child->isFreeDOF(ip) && child->getParErr(ip) >= 0) { + nContCh[ip]++; + } + jac[ip * kNDOFGeom + ip] = 1.; + } + } + jac += kNDOFGeom * kNDOFGeom; // matrix for next slot + } + // + for (int ics = 0; ics < kNDOFGeom; ics++) { + if (!isDOFConstrained(ics)) { + continue; + } + int cmtStatus = nContCh[ics] > 0 ? kOff : kOn; // do we comment this constraint? + // + if (cmtStatus) { + LOG(INFO) << "No contributors to constraint of " << getDOFName(ics) << " of " << GetName(); + } + if (mSigma[ics] > 0) { + fprintf(conOut, "\n%s%s\t%e\t%e\t%s %s of %s %s\n", comment[cmtStatus], kKeyConstr[kMeas], 0.0, mSigma[ics], + comment[kOnOn], getDOFName(ics), GetName(), GetTitle()); + } else { + fprintf(conOut, "\n%s%s\t%e\t%s %s of %s %s\n", comment[cmtStatus], kKeyConstr[kConstr], 0.0, + comment[kOnOn], getDOFName(ics), GetName(), GetTitle()); + } + for (int ich = 0; ich < nch; ich++) { // contribution from this children DOFs to constraint + AlignableVolume* child = getChild(ich); + jac = cstrArr + kNDOFGeom * kNDOFGeom * ich; + if (cmtStatus) { + fprintf(conOut, "%s", comment[cmtStatus]); + } // comment out contribution + // first write real constraints + for (int ip = 0; ip < kNDOFGeom; ip++) { + float jv = jac[ics * kNDOFGeom + ip]; + if (child->isFreeDOF(ip) && !isZeroAbs(jv) && child->getParErr(ip) >= 0) { + fprintf(conOut, "%9d %+.3e\t", child->getParLab(ip), jv); + } + } // loop over DOF's of children contributing to this constraint + // now, after comment, write disabled constraints + fprintf(conOut, "%s ", comment[kOn]); + if (doJac) { + for (int ip = 0; ip < kNDOFGeom; ip++) { + float jv = jac[ics * kNDOFGeom + ip]; + if (child->isFreeDOF(ip) && !isZeroAbs(jv) && child->getParErr(ip) >= 0) { + continue; + } + fprintf(conOut, "%9d %+.3e\t", child->getParLab(ip), jv); + } // loop over DOF's of children contributing to this constraint + } + fprintf(conOut, "%s from %s\n", comment[kOnOn], child->GetName()); + } // loop over children + } // loop over constraints in parent volume + // + delete[] cstrArr; +} + +//______________________________________________________ +void GeometricalConstraint::checkConstraint() const +{ + // check how the constraints are satysfied + int nch = getNChildren(); + if (!nch) { + return; + } + // + bool doJac = !getNoJacobian(); // do we need jacobian evaluation? + float* cstrArr = new float[nch * kNDOFGeom * kNDOFGeom]; + memset(cstrArr, 0, nch * kNDOFGeom * kNDOFGeom * sizeof(float)); + // we need for each children the matrix for vector transformation from children frame + // (in which its DOFs are defined, LOC or TRA) to this parent variation frame + // matRel = mPar^-1*mChild + TGeoHMatrix mPar; + // in case of parent assigned use its matrix, + // otherwise Alice global frame is assumed to be the parent -> Unit matrix + if (mParent && doJac) { + if (mParent->isFrameTRA()) { + mParent->getMatrixT2G(mPar); + } // tracking to global + else { + mPar = mParent->getMatrixL2GIdeal(); + } // local to global + mPar = mPar.Inverse(); + } + // + float* jac = cstrArr; + double parsTotEx[kNDOFGeom] = {0}; // explicitly calculated total modification + double parsTotAn[kNDOFGeom] = {0}; // analyticaly calculated total modification + // + printf("\n\n ----- Constraints Validation for %s %s ------\n", GetName(), GetTitle()); + printf(" chld| "); + for (int jp = 0; jp < kNDOFGeom; jp++) { + printf(" %3s:%3s An/Ex |", getDOFName(jp), isDOFConstrained(jp) ? "ON " : "OFF"); + } + printf(" | "); + for (int jp = 0; jp < kNDOFGeom; jp++) { + printf(" D%3s ", getDOFName(jp)); + } + printf(" ! %s\n", GetName()); + for (int ich = 0; ich < nch; ich++) { + AlignableVolume* child = getChild(ich); + double parsC[kNDOFGeom] = {0}, parsPAn[kNDOFGeom] = {0}, parsPEx[kNDOFGeom] = {0}; + for (int jc = kNDOFGeom; jc--;) { + parsC[jc] = child->getParVal(jc); + } // child params in child frame + printf("#%3d | ", ich); + // + if (doJac) { + TGeoHMatrix matRel; + if (child->isFrameTRA()) { + child->getMatrixT2G(matRel); + } // tracking to global + else { + matRel = child->getMatrixL2GIdeal(); + } // local to global + // + matRel.MultiplyLeft(&mPar); + constrCoefGeom(matRel, jac); // Jacobian for analytical constraint used by MillePeded + // + TGeoHMatrix tau; + child->delta2Matrix(tau, parsC); // child correction matrix in the child frame + const TGeoHMatrix& matreli = matRel.Inverse(); + tau.Multiply(&matreli); + tau.MultiplyLeft(&matRel); // child correction matrix in the parent frame + detectors::AlignParam tmpPar; + // tmpPar.SetMatrix(tau); + // SetMatrix does setTranslation and setRotation afterwars; + tmpPar.setTranslation(tau); + tmpPar.setRotation(tau); + //tmpPar.GetTranslation(&parsPEx[0]); + // get Translation gets x,y,z; + parsPEx[0] = tmpPar.getX(); + parsPEx[1] = tmpPar.getY(); + parsPEx[2] = tmpPar.getZ(); + //tmpPar.GetAngles(&parsPEx[3]); // explicitly calculated child params in parent frame + // gets angles + parsPEx[3] = tmpPar.getPsi(); + parsPEx[4] = tmpPar.getTheta(); + parsPEx[5] = tmpPar.getPhi(); + // + // analytically calculated child params in parent frame + for (int jp = 0; jp < kNDOFGeom; jp++) { + for (int jc = 0; jc < kNDOFGeom; jc++) { + parsPAn[jp] += jac[jp * kNDOFGeom + jc] * parsC[jc]; + } + parsTotAn[jp] += parsPAn[jp]; // analyticaly calculated total modification + parsTotEx[jp] += parsPEx[jp]; // explicitly calculated total modification + // + printf("%+.1e/%+.1e ", parsPAn[jp], parsPEx[jp]); + // + } + // + jac += kNDOFGeom * kNDOFGeom; // matrix for next slot + } else { + for (int jc = 0; jc < kNDOFGeom; jc++) { + bool acc = child->isFreeDOF(jc) && child->getParErr(jc) >= 0; + if (acc) { + printf(" %+.3e ", parsC[jc]); + parsTotAn[jc] += parsC[jc]; + } else { + printf(" /* %+.3e */ ", parsC[jc]); + } // just for info, not in the constraint + } + } + printf(" | "); + for (int jc = 0; jc < kNDOFGeom; jc++) { + printf("%+.1e ", parsC[jc]); + } // child proper corrections + printf(" ! %s\n", child->getSymName()); + } + // + printf(" Tot | "); + for (int jp = 0; jp < kNDOFGeom; jp++) { + if (doJac) { + printf("%+.1e/%+.1e ", parsTotAn[jp], parsTotEx[jp]); + } else { + if (isDOFConstrained(jp)) { + printf(" %+.3e ", parsTotAn[jp]); + } else { + printf(" /* %+.3e */ ", parsTotAn[jp]); + } + } + } + printf(" | "); + if (mParent) { + for (int jp = 0; jp < kNDOFGeom; jp++) { + printf("%+.1e ", mParent->getParVal(jp)); + } + } // parent proper corrections + else { + printf(" no parent -> %s ", doJac ? "Global" : "Simple"); + } + printf(" ! <----- %s\n", GetName()); + // + printf(" Sig | "); + for (int jp = 0; jp < kNDOFGeom; jp++) { + if (isDOFConstrained(jp)) { + printf(" %+.3e ", mSigma[jp]); + } else { + printf(" /* %+.3e */ ", mSigma[jp]); + } + } + printf(" ! <----- \n"); + + // + delete[] cstrArr; + // +} + +//_________________________________________________________________ +void GeometricalConstraint::constrCoefGeom(const TGeoHMatrix& matRD, float* jac /*[kNDOFGeom][kNDOFGeom]*/) const +{ + // If the transformation R brings the vector from "local" frame to "master" frame as V=R*v + // then application of the small LOCAL correction tau to vector v is equivalent to + // aplication of correction TAU in MASTER framce V' = R*tau*v = TAU*R*v + // with TAU = R*tau*R^-1 + // Constraining the LOCAL modifications of child volumes to have 0 total movement in their parent + // frame is equivalent to request that sum of all TAU matrices is unity matrix, or TAU-I = 0. + // + // This routine calculates derivatives of the TAU-I matrix over local corrections x,y,z, psi,tht,phi + // defining matrix TAU. In small corrections approximation the constraint is equivalent to + // Sum_over_child_volumes{ [dTAU/dParam]_ij * deltaParam } = 0 + // for all elements ij of derivative matrices. Since only 6 out of 16 matrix params are independent, + // we request the constraint only for [30](X), [31](Y), [32](Z), [12](psi), [02](tht), [01](phi) + // Choice defined by convention of AliAlgObg::Angles2Matrix (need elements ~ linear in corrections) + // + TGeoHMatrix matRI = matRD.Inverse(); + const int ij[kNDOFGeom][2] = {{3, 0}, {3, 1}, {3, 2}, {1, 2}, {0, 2}, {0, 1}}; + // + const double *rd = matRD.GetRotationMatrix(), *ri = matRI.GetRotationMatrix(); + const double /**td=matRD.GetTranslation(),*/* ti = matRI.GetTranslation(); + // + // the angles are in degrees, while we use sinX->X approximation... + const double cf[kNDOFGeom] = {1, 1, 1, DegToRad(), DegToRad(), DegToRad()}; + // + // since the TAU is supposed to convert local corrections in the child frame to corrections + // in the parent frame, we scale angular degrees of freedom back to degrees and assign the + // sign of S in the S*sin(angle) in the matrix, so that the final correction has a correct + // sign, due to the choice of euler angles in the AliAlignObj::AnglesToMatrix + // costhe*cosphi; -costhe*sinphi; sinthe; + // sinpsi*sinthe*cosphi + cospsi*sinphi; -sinpsi*sinthe*sinphi + cospsi*cosphi; -costhe*sinpsi; + // -cospsi*sinthe*cosphi + sinpsi*sinphi; cospsi*sinthe*sinphi + sinpsi*cosphi; costhe*cospsi; + // + const double kJTol = 1e-4; // treat derivatives below this threshold as 0 + const double sgc[kNDOFGeom] = {1., 1., 1., -RadToDeg(), RadToDeg(), -RadToDeg()}; + // + double dDPar[kNDOFGeom][4][4] = { + // dDX[4][4] + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {rd[0], rd[3], rd[6], 0}}, + // dDY[4][4] + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {rd[1], rd[4], rd[7], 0}}, + // dDZ[4][4] + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {rd[2], rd[5], rd[8], 0}}, + // dDPSI[4][4] + {{rd[2] * ri[3] - rd[1] * ri[6], rd[2] * ri[4] - rd[1] * ri[7], rd[2] * ri[5] - rd[1] * ri[8], 0}, + {rd[5] * ri[3] - rd[4] * ri[6], rd[5] * ri[4] - rd[4] * ri[7], rd[5] * ri[5] - rd[4] * ri[8], 0}, + {rd[8] * ri[3] - rd[7] * ri[6], rd[8] * ri[4] - rd[7] * ri[7], rd[8] * ri[5] - rd[7] * ri[8], 0}, + {rd[2] * ti[1] - rd[1] * ti[2], rd[5] * ti[1] - rd[4] * ti[2], rd[8] * ti[1] - rd[7] * ti[2], 0}}, + // dDTHT[4][4] + {{rd[0] * ri[6] - rd[2] * ri[0], rd[0] * ri[7] - rd[2] * ri[1], rd[0] * ri[8] - rd[2] * ri[2], 0}, + {rd[3] * ri[6] - rd[5] * ri[0], rd[3] * ri[7] - rd[5] * ri[1], rd[3] * ri[8] - rd[5] * ri[2], 0}, + {rd[6] * ri[6] - rd[8] * ri[0], rd[6] * ri[7] - rd[8] * ri[1], rd[6] * ri[8] - rd[8] * ri[2], 0}, + {rd[0] * ti[2] - rd[2] * ti[0], rd[3] * ti[2] - rd[5] * ti[0], rd[6] * ti[2] - rd[8] * ti[0], 0}}, + // dDPHI[4][4] + {{rd[1] * ri[0] - rd[0] * ri[3], rd[1] * ri[1] - rd[0] * ri[4], rd[1] * ri[2] - rd[0] * ri[5], 0}, + {rd[4] * ri[0] - rd[3] * ri[3], rd[4] * ri[1] - rd[3] * ri[4], rd[4] * ri[2] - rd[3] * ri[5], 0}, + {rd[7] * ri[0] - rd[6] * ri[3], rd[7] * ri[1] - rd[6] * ri[4], rd[7] * ri[2] - rd[6] * ri[5], 0}, + {rd[1] * ti[0] - rd[0] * ti[1], rd[4] * ti[0] - rd[3] * ti[1], rd[7] * ti[0] - rd[6] * ti[1], 0}}, + }; + // + for (int cs = 0; cs < kNDOFGeom; cs++) { + int i = ij[cs][0], j = ij[cs][1]; + for (int ip = 0; ip < kNDOFGeom; ip++) { + double jval = sgc[cs] * dDPar[ip][i][j] * cf[ip]; + jac[cs * kNDOFGeom + ip] = (Abs(jval) > kJTol) ? jval : 0; // [cs][ip] + } + } +} + +//______________________________________________________ +void GeometricalConstraint::Print(const Option_t*) const +{ + // print info + printf("Constraint on "); + for (int i = 0; i < kNDOFGeom; i++) { + if (isDOFConstrained(i)) { + printf("%3s (Sig:%+e) ", getDOFName(i), getSigma(i)); + } + } + printf(" | %s %s\n", GetName(), GetTitle()); + if (getNoJacobian()) { + printf("!!! This is explicit constraint on sum of DOFs (no Jacobian)!!!\n"); + } + for (int i = 0; i < getNChildren(); i++) { + const AlignableVolume* child = getChild(i); + printf("%3d %s\n", i, child->GetName()); + } +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/Mille.cxx b/Detectors/Align/src/Mille.cxx new file mode 100644 index 0000000000000..03fb6bed9858c --- /dev/null +++ b/Detectors/Align/src/Mille.cxx @@ -0,0 +1,253 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Mille.h +/// @author Gero Flucke, ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since October 2006 +/// @brief Class to write C binary file. + +/* + RS: original Mille.cc from http://svnsrv.desy.de/public/MillepedeII/tags/V04-02-03 + jeudi 30 avril 2015: renamed to cxx + jeudi 30 avril 2015: added automatic buffer expansion +*/ + +#include "Align/Mille.h" + +#include <fstream> +#include <iostream> + +namespace o2 +{ +namespace align +{ +//___________________________________________________________________________ + +/// Opens outFileName (by default as binary file). +/** + * \param[in] outFileName file name + * \param[in] asBinary flag for binary + * \param[in] writeZero flag for keeping of zeros + */ +Mille::Mille(const char* outFileName, bool asBinary, bool writeZero) : myOutFile(outFileName, + (asBinary ? (std::ios::binary | std::ios::out | std::ios::trunc) : (std::ios::out | std::ios::trunc))), + myAsBinary(asBinary), + myWriteZero(writeZero), + myBufferSize(0), + myBufferInt(5000), + myBufferFloat(5000), + myBufferPos(-1), + myHasSpecial(false) +{ + // Instead myBufferPos(-1), myHasSpecial(false) and the following two lines + // we could call newSet() and kill()... + + if (!myOutFile.is_open()) { + std::cerr << "Mille::Mille: Could not open " << outFileName + << " as output file." << std::endl; + } +} + +//___________________________________________________________________________ +/// Closes file. +Mille::~Mille() +{ + myOutFile.close(); +} + +//___________________________________________________________________________ +/// Add measurement to buffer. +/** + * \param[in] NLC number of local derivatives + * \param[in] derLc local derivatives + * \param[in] NGL number of global derivatives + * \param[in] derGl global derivatives + * \param[in] label global labels + * \param[in] rMeas measurement (residuum) + * \param[in] sigma error + */ +void Mille::mille(int NLC, const float* derLc, + int NGL, const float* derGl, const int* label, + float rMeas, float sigma) +{ + if (sigma <= 0.) { + return; + } + if (myBufferPos == -1) { + this->newSet(); + } // start, e.g. new track + if (!this->checkBufferSize(NLC, NGL)) { + return; + } + + // first store measurement + ++myBufferPos; + float* bufferFloat = myBufferFloat.GetArray(); + int* bufferInt = myBufferInt.GetArray(); + bufferFloat[myBufferPos] = rMeas; + bufferInt[myBufferPos] = 0; + + // store local derivatives and local 'lables' 1,...,NLC + for (int i = 0; i < NLC; ++i) { + if (derLc[i] || myWriteZero) { // by default store only non-zero derivatives + ++myBufferPos; + bufferFloat[myBufferPos] = derLc[i]; // local derivatives + bufferInt[myBufferPos] = i + 1; // index of local parameter + } + } + + // store uncertainty of measurement in between locals and globals + ++myBufferPos; + bufferFloat[myBufferPos] = sigma; + bufferInt[myBufferPos] = 0; + + // store global derivatives and their labels + for (int i = 0; i < NGL; ++i) { + if (derGl[i] || myWriteZero) { // by default store only non-zero derivatives + if ((label[i] > 0 || myWriteZero) && label[i] <= myMaxLabel) { // and for valid labels + ++myBufferPos; + bufferFloat[myBufferPos] = derGl[i]; // global derivatives + bufferInt[myBufferPos] = label[i]; // index of global parameter + } else { + std::cerr << "Mille::mille: Invalid label " << label[i] + << " <= 0 or > " << myMaxLabel << std::endl; + } + } + } +} + +//___________________________________________________________________________ +/// Add special data to buffer. +/** + * \param[in] nSpecial number of floats/ints + * \param[in] floatings floats + * \param[in] integers ints + */ +void Mille::special(int nSpecial, const float* floatings, const int* integers) +{ + if (nSpecial == 0) { + return; + } + if (myBufferPos == -1) { + this->newSet(); + } // start, e.g. new track + if (myHasSpecial) { + std::cerr << "Mille::special: Special values already stored for this record." + << std::endl; + return; + } + if (!this->checkBufferSize(nSpecial, 0)) { + return; + } + myHasSpecial = true; // after newSet() (Note: MILLSP sets to buffer position...) + + // myBufferFloat[.] | myBufferInt[.] + // ------------------------------------ + // 0.0 | 0 + // -float(nSpecial) | 0 + // The above indicates special data, following are nSpecial floating and nSpecial integer data. + // + float* bufferFloat = myBufferFloat.GetArray(); + int* bufferInt = myBufferInt.GetArray(); + // + ++myBufferPos; // zero pair + bufferFloat[myBufferPos] = 0.; + bufferInt[myBufferPos] = 0; + + ++myBufferPos; // nSpecial and zero + bufferFloat[myBufferPos] = -nSpecial; // automatic conversion to float + bufferInt[myBufferPos] = 0; + + for (int i = 0; i < nSpecial; ++i) { + ++myBufferPos; + bufferFloat[myBufferPos] = floatings[i]; + bufferInt[myBufferPos] = integers[i]; + } +} + +//___________________________________________________________________________ +/// Reset buffers, i.e. kill derivatives accumulated for current set. +void Mille::kill() +{ + myBufferPos = -1; +} + +//___________________________________________________________________________ +/// Write buffer (set of derivatives with same local parameters) to file. +int Mille::end() +{ + int wrote = 0; + if (myBufferPos > 0) { // only if anything stored... + const int numWordsToWrite = (myBufferPos + 1) * 2; + float* bufferFloat = myBufferFloat.GetArray(); + int* bufferInt = myBufferInt.GetArray(); + + if (myAsBinary) { + myOutFile.write(reinterpret_cast<const char*>(&numWordsToWrite), + sizeof(numWordsToWrite)); + myOutFile.write(reinterpret_cast<char*>(bufferFloat), + (myBufferPos + 1) * sizeof(bufferFloat[0])); + myOutFile.write(reinterpret_cast<char*>(bufferInt), + (myBufferPos + 1) * sizeof(bufferInt[0])); + } else { + myOutFile << numWordsToWrite << "\n"; + for (int i = 0; i < myBufferPos + 1; ++i) { + myOutFile << bufferFloat[i] << " "; + } + myOutFile << "\n"; + + for (int i = 0; i < myBufferPos + 1; ++i) { + myOutFile << bufferInt[i] << " "; + } + myOutFile << "\n"; + } + wrote = (myBufferPos + 1) * (sizeof(bufferFloat[0]) + sizeof(bufferInt[0])) + sizeof(int); + } + myBufferPos = -1; // reset buffer for next set of derivatives + return wrote; +} + +//___________________________________________________________________________ +/// Initialize for new set of locals, e.g. new track. +void Mille::newSet() +{ + myBufferPos = 0; + myHasSpecial = false; + myBufferFloat[0] = 0.0; + myBufferInt[0] = 0; // position 0 used as error counter +} + +//___________________________________________________________________________ +/// Enough space for next nLocal + nGlobal derivatives incl. measurement? +/** + * \param[in] nLocal number of local derivatives + * \param[in] nGlobal number of global derivatives + * \return true if sufficient space available (else false) + */ +bool Mille::checkBufferSize(int nLocal, int nGlobal) +{ + if (myBufferPos + nLocal + nGlobal + 2 >= myBufferInt.GetSize()) { + ++(myBufferInt[0]); // increase error count + std::cerr << "Mille::checkBufferSize: Buffer too short (" + << myBufferInt.GetSize() << ")," + << "\n need space for nLocal (" << nLocal << ")" + << "/nGlobal (" << nGlobal << ") local/global derivatives, " + << myBufferPos + 1 << " already stored!" + << std::endl; + // return false; + myBufferInt.Set(myBufferPos + nLocal + nGlobal + 1000); + myBufferFloat.Set(myBufferPos + nLocal + nGlobal + 1000); + } + return true; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/Millepede2Record.cxx b/Detectors/Align/src/Millepede2Record.cxx new file mode 100644 index 0000000000000..497b5096b6702 --- /dev/null +++ b/Detectors/Align/src/Millepede2Record.cxx @@ -0,0 +1,332 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Millepede2Record.cxx +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Millepede record in root format (can be converted to proper pede binary format. + +#include "Align/Millepede2Record.h" +#include "Align/utils.h" +#include "Align/AlignmentTrack.h" +#include "Framework/Logger.h" +#include <TMath.h> +#include <cstdio> + +using namespace TMath; +using namespace o2::align::utils; + +namespace o2 +{ +namespace align +{ + +//_________________________________________________________ +Millepede2Record::Millepede2Record() + : mTrackID(0), mTimeStamp(0), mNResid(0), mNVarLoc(0), mNVarGlo(0), mNDLocTot(0), mNDGloTot(0), mNMeas(0), mChi2Ini(0), mQ2Pt(0), mTgl(0), mNDLoc(nullptr), mNDGlo(nullptr), mVolID(nullptr), mResid(nullptr), mResErr(nullptr), mIDLoc(nullptr), mIDGlo(nullptr), mDLoc(nullptr), mDGlo(nullptr) + // + , + mNResidBook(0), + mNDLocTotBook(0), + mNDGloTotBook(0) +{ + // def c-tor +} + +//_________________________________________________________ +Millepede2Record::~Millepede2Record() +{ + // d-tor + delete[] mNDLoc; + delete[] mNDGlo; + delete[] mVolID; + delete[] mResid; + delete[] mResErr; + delete[] mIDLoc; + delete[] mIDGlo; + delete[] mDLoc; + delete[] mDGlo; +} + +//_________________________________________________________ +void Millepede2Record::dummyRecord(float res, float err, float dGlo, int labGlo) +{ + // create dummy residuals record + if (!mNDGlo) { + resize(1, 1, 1); + } + mChi2Ini = 0; + mNMeas = 1; + mNResid = 1; + mNVarLoc = 0; + mNVarGlo = 1; + mIDGlo[0] = labGlo; + mDGlo[0] = dGlo; + mNDGlo[0] = 1; + mVolID[0] = -1; + mResid[0] = res; + mResErr[0] = err; + // + mIDLoc[0] = 0; + mNDLoc[0] = 0; + mDLoc[0] = 0; + mNDGloTot = 1; + mNDLocTot = 0; + // +} + +//_________________________________________________________ +bool Millepede2Record::fillTrack(const AlignmentTrack* trc, const int* id2Lab) +{ + // fill track info, optionally substitutind glopar par ID by label + // + if (!trc->getDerivDone()) { + LOG(ERROR) << "Track derivatives are not yet evaluated"; + return false; + } + mNVarLoc = trc->getNLocPar(); // number of local degrees of freedom in the track + mNResid = 0; + mNDLocTot = 0; + mNDGloTot = 0; + mChi2Ini = trc->getChi2Ini(); + mQ2Pt = trc->getQ2Pt(); + mTgl = trc->getTgl(); + mNMeas = 0; + setCosmic(trc->isCosmic()); + // 1) check sizes for buffers, expand if needed + int np = trc->getNPoints(); + int nres = 0; + int nlocd = 0; + int nglod = 0; + for (int ip = np; ip--;) { + AlignmentPoint* pnt = trc->getPoint(ip); + int ngl = pnt->getNGloDOFs(); // number of DOF's this point depends on + if (pnt->containsMeasurement()) { + nres += 2; // every point has 2 residuals + nlocd += mNVarLoc + mNVarLoc; // each residual has max mNVarLoc local derivatives + nglod += ngl + ngl; // number of global derivatives + mNMeas++; + } + if (pnt->containsMaterial()) { + int nmatpar = pnt->getNMatPar(); + nres += nmatpar; // each point with materials has nmatpar fake residuals + nlocd += nmatpar; // and nmatpar non-0 local derivatives (orthogonal) + } + } + // + resize(nres, nlocd, nglod); + int nParETP = trc->getNLocExtPar(); // numnber of local parameters for reference track param + // + const int* gloParID = trc->getGloParID(); // IDs of global DOFs this track depends on + for (int ip = 0; ip < np; ip++) { + AlignmentPoint* pnt = trc->getPoint(ip); + if (pnt->containsMeasurement()) { + int gloOffs = pnt->getDGloOffs(); // 1st entry of global derivatives for this point + int nDGlo = pnt->getNGloDOFs(); // number of global derivatives (number of DOFs it depends on) + if (!pnt->isStatOK()) { + pnt->incrementStat(); + } + // + for (int idim = 0; idim < 2; idim++) { // 2 dimensional orthogonal measurement + mNDGlo[mNResid] = 0; + mVolID[mNResid] = pnt->getSensor()->getVolID() + 1; + // + // measured residual/error + mResid[mNResid] = trc->getResidual(idim, ip); + mResErr[mNResid] = Sqrt(pnt->getErrDiag(idim)); + // + // derivatives over local params + const double* deriv = trc->getDResDLoc(idim, ip); // array of Dresidual/Dparams_loc + int nnon0 = 0; + for (int j = 0; j < nParETP; j++) { // derivatives over reference track parameters + if (isZeroAbs(deriv[j])) { + continue; + } + nnon0++; + mDLoc[mNDLocTot] = deriv[j]; // store non-0 derivative + mIDLoc[mNDLocTot] = j; // and variable id + mNDLocTot++; + } + int lp0 = pnt->getMinLocVarID(); // point may depend on material variables starting from this one + int lp1 = pnt->getMaxLocVarID(); // and up to this one (exclusive) + for (int j = lp0; j < lp1; j++) { // derivatives over material variables + if (isZeroAbs(deriv[j])) { + continue; + } + nnon0++; + mDLoc[mNDLocTot] = deriv[j]; // store non-0 derivative + mIDLoc[mNDLocTot] = j; // and variable id + mNDLocTot++; + } + // + mNDLoc[mNResid] = nnon0; // local derivatives done, store their number for this residual + // + // derivatives over global params + nnon0 = 0; + deriv = trc->getDResDGlo(idim, gloOffs); + const int* gloIDP = gloParID + gloOffs; + for (int j = 0; j < nDGlo; j++) { + if (isZeroAbs(deriv[j])) { + continue; + } + nnon0++; + mDGlo[mNDGloTot] = deriv[j]; // value of derivative + mIDGlo[mNDGloTot] = id2Lab ? id2Lab[gloIDP[j]] : gloIDP[j] + 1; // global DOF ID + mNDGloTot++; + } + mNDGlo[mNResid] = nnon0; + // + mNResid++; + } + } + if (pnt->containsMaterial()) { // material point can add 4 or 5 otrhogonal pseudo-measurements + int nmatpar = pnt->getNMatPar(); // residuals (correction expectation value) + // const float* expMatCorr = pnt->getMatCorrExp(); // expected corrections (diagonalized) + const float* expMatCov = pnt->getMatCorrCov(); // their diagonalized error matrix + int offs = pnt->getMaxLocVarID() - nmatpar; // start of material variables + // here all derivatives are 1 = dx/dx + for (int j = 0; j < nmatpar; j++) { + mNDGlo[mNResid] = 0; // mat corrections don't depend on global params + mVolID[mNResid] = 0; // not associated to global parameter + mResid[mNResid] = 0; // expectation for MS effects is 0 + mResErr[mNResid] = Sqrt(expMatCov[j]); + mNDLoc[mNResid] = 1; // only 1 non-0 derivative + mDLoc[mNDLocTot] = 1.0; + mIDLoc[mNDLocTot] = offs + j; // variable id + mNDLocTot++; + mNResid++; + } + } + } + // + if (!mNDGloTot) { + LOG(INFO) << "Track does not depend on free global parameters, discard"; + return false; + } + return true; +} + +//________________________________________________ +void Millepede2Record::resize(int nresid, int nloc, int nglo) +{ + // resize container + if (nresid > mNResidBook) { + delete[] mNDLoc; + delete[] mNDGlo; + delete[] mVolID; + delete[] mResid; + delete[] mResErr; + mNDLoc = new int16_t[nresid]; + mNDGlo = new int[nresid]; + mVolID = new int[nresid]; + mResid = new float[nresid]; + mResErr = new float[nresid]; + mNResidBook = nresid; + memset(mNDLoc, 0, nresid * sizeof(int16_t)); + memset(mNDGlo, 0, nresid * sizeof(int)); + memset(mVolID, 0, nresid * sizeof(int)); + memset(mResid, 0, nresid * sizeof(float)); + memset(mResErr, 0, nresid * sizeof(float)); + } + if (nloc > mNDLocTotBook) { + delete[] mIDLoc; + delete[] mDLoc; + mIDLoc = new int16_t[nloc]; + mDLoc = new float[nloc]; + mNDLocTotBook = nloc; + memset(mIDLoc, 0, nloc * sizeof(int16_t)); + memset(mDLoc, 0, nloc * sizeof(float)); + } + if (nglo > mNDGloTotBook) { + delete[] mIDGlo; + delete[] mDGlo; + mIDGlo = new int[nglo]; + mDGlo = new float[nglo]; + mNDGloTotBook = nglo; + memset(mIDGlo, 0, nglo * sizeof(int)); + memset(mDGlo, 0, nglo * sizeof(float)); + } + // +} + +//____________________________________________ +void Millepede2Record::Clear(const Option_t*) +{ + // reset record + TObject::Clear(); + ResetBit(0xffffffff); + mNResid = 0; + mNVarLoc = 0; + mNVarGlo = 0; + mNDLocTot = 0; + mNDGloTot = 0; +} + +//____________________________________________ +void Millepede2Record::Print(const Option_t*) const +{ + // print info + // + printf("Track %d Event TimeStamp:%d Run:%d\n", + mTrackID, mTimeStamp, getRun()); + printf("Nmeas:%3d Q/pt:%+.2e Tgl:%+.2e Chi2Ini:%.1f\n", mNMeas, mQ2Pt, mTgl, mChi2Ini); + printf("NRes: %3d NLoc: %3d NGlo:%3d | Stored: Loc:%3d Glo:%5d\n", + mNResid, mNVarLoc, mNVarGlo, mNDLocTot, mNDGloTot); + // + int curLoc = 0, curGlo = 0; + const int kNColLoc = 5; + for (int ir = 0; ir < mNResid; ir++) { + int ndloc = mNDLoc[ir], ndglo = mNDGlo[ir]; + printf("Res:%3d %+e (%+e) | NDLoc:%3d NDGlo:%4d [VID:%5d]\n", + ir, mResid[ir], mResErr[ir], ndloc, ndglo, getVolID(ir)); + // + printf("Local Derivatives:\n"); + bool eolOK = true; + for (int id = 0; id < ndloc; id++) { + int jd = id + curLoc; + printf("[%3d] %+.2e ", mIDLoc[jd], mDLoc[jd]); + if (((id + 1) % kNColLoc) == 0) { + printf("\n"); + eolOK = true; + } else { + eolOK = false; + } + } + if (!eolOK) { + printf("\n"); + } + curLoc += ndloc; + // + // + printf("Global Derivatives:\n"); + // eolOK = true; + // const int kNColGlo=6; + int prvID = -1; + for (int id = 0; id < ndglo; id++) { + int jd = id + curGlo; + // eolOK==false; + if (prvID > mIDGlo[jd] % 100) { + printf("\n"); /* eolOK = true;*/ + } + printf("[%5d] %+.2e ", mIDGlo[jd], mDGlo[jd]); + // if (((id+1)%kNColGlo)==0) + // else eolOK = false; + prvID = mIDGlo[jd] % 100; + } + // if (!eolOK) printf("\n"); + printf("\n"); + curGlo += ndglo; + // + } +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/ResidualsController.cxx b/Detectors/Align/src/ResidualsController.cxx new file mode 100644 index 0000000000000..c85267136aa8d --- /dev/null +++ b/Detectors/Align/src/ResidualsController.cxx @@ -0,0 +1,302 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ResidualsController.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Container for control residuals + +#include "Align/ResidualsController.h" +#include "Align/AlignmentTrack.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableSensor.h" +#include "Framework/Logger.h" +#include <TString.h> +#include <TMath.h> +#include <cstdio> + +using namespace TMath; + +ClassImp(o2::align::ResidualsController); + +namespace o2 +{ +namespace align +{ + +//____________________________________ +ResidualsController::ResidualsController() + : mRun(0), mBz(0), mTimeStamp(0), mTrackID(0), mNPoints(0), mNBook(0), mChi2(0), mChi2Ini(0), mChi2K(0), mQ2Pt(0), mX(nullptr), mY(nullptr), mZ(nullptr), mSnp(nullptr), mTgl(nullptr), mAlpha(nullptr), mDY(nullptr), mDZ(nullptr), mDYK(nullptr), mDZK(nullptr), mSigY2(nullptr), mSigYZ(nullptr), mSigZ2(nullptr), mSigY2K(nullptr), mSigYZK(nullptr), mSigZ2K(nullptr), mVolID(nullptr), mLabel(nullptr) +{ + // def c-tor +} + +//________________________________________________ +ResidualsController::~ResidualsController() +{ + // d-tor + delete[] mX; + delete[] mY; + delete[] mZ; + delete[] mSnp; + delete[] mTgl; + delete[] mAlpha; + delete[] mDY; + delete[] mDZ; + delete[] mSigY2; + delete[] mSigYZ; + delete[] mSigZ2; + delete[] mDYK; + delete[] mDZK; + delete[] mSigY2K; + delete[] mSigYZK; + delete[] mSigZ2K; + delete[] mVolID; + delete[] mLabel; +} + +//________________________________________________ +void ResidualsController::resize(int np) +{ + // resize container + if (np > mNBook) { + delete[] mX; + delete[] mY; + delete[] mZ; + delete[] mSnp; + delete[] mTgl; + delete[] mAlpha; + delete[] mDY; + delete[] mDZ; + delete[] mSigY2; + delete[] mSigYZ; + delete[] mSigZ2; + delete[] mDYK; + delete[] mDZK; + delete[] mSigY2K; + delete[] mSigYZK; + delete[] mSigZ2K; + delete[] mVolID; + delete[] mLabel; + // + mNBook = 100 + np; + mX = new float[mNBook]; + mY = new float[mNBook]; + mZ = new float[mNBook]; + mSnp = new float[mNBook]; + mTgl = new float[mNBook]; + mAlpha = new float[mNBook]; + mDY = new float[mNBook]; + mDZ = new float[mNBook]; + mSigY2 = new float[mNBook]; + mSigYZ = new float[mNBook]; + mSigZ2 = new float[mNBook]; + mDYK = new float[mNBook]; + mDZK = new float[mNBook]; + mSigY2K = new float[mNBook]; + mSigYZK = new float[mNBook]; + mSigZ2K = new float[mNBook]; + mVolID = new int[mNBook]; + mLabel = new int[mNBook]; + // + memset(mX, 0, mNBook * sizeof(float)); + memset(mY, 0, mNBook * sizeof(float)); + memset(mZ, 0, mNBook * sizeof(float)); + memset(mSnp, 0, mNBook * sizeof(float)); + memset(mTgl, 0, mNBook * sizeof(float)); + memset(mAlpha, 0, mNBook * sizeof(float)); + memset(mDY, 0, mNBook * sizeof(float)); + memset(mDZ, 0, mNBook * sizeof(float)); + memset(mSigY2, 0, mNBook * sizeof(float)); + memset(mSigYZ, 0, mNBook * sizeof(float)); + memset(mSigZ2, 0, mNBook * sizeof(float)); + memset(mDYK, 0, mNBook * sizeof(float)); + memset(mDZK, 0, mNBook * sizeof(float)); + memset(mSigY2K, 0, mNBook * sizeof(float)); + memset(mSigYZK, 0, mNBook * sizeof(float)); + memset(mSigZ2K, 0, mNBook * sizeof(float)); + memset(mVolID, 0, mNBook * sizeof(int)); + memset(mLabel, 0, mNBook * sizeof(int)); + } + // +} + +//____________________________________________ +void ResidualsController::Clear(const Option_t*) +{ + // reset record + TObject::Clear(); + ResetBit(0xffffffff); + mNPoints = 0; + mRun = 0; + mTimeStamp = 0; + mTrackID = 0; + mChi2 = 0; + mChi2K = 0; + mQ2Pt = 0; + // +} + +//____________________________________________ +void ResidualsController::Print(const Option_t* opt) const +{ + // print info + TString opts = opt; + opts.ToLower(); + bool lab = opts.Contains("l"); + printf("%5sTr.", isCosmic() ? "Cosm." : "Coll."); + if (isCosmic()) { + printf("%2d/%2d ", mTrackID >> 16, mTrackID & 0xffff); + } else { + printf("%5d ", mTrackID); + } + printf("Run:%6d Bz:%+4.1f Np: %3d q/Pt:%+.4f | Chi2: Ini: %6.1f LinSol:%6.1f Kalm:%6.1f |Vtx:%3s| TStamp:%d\n", + mRun, mBz, mNPoints, mQ2Pt, mChi2Ini, mChi2, mChi2K, hasVertex() ? "ON" : "OFF", mTimeStamp); + if (opts.Contains("r")) { + bool ers = opts.Contains("e"); + printf("%5s %7s %s %7s %7s %7s %5s %5s %9s %9s", + " VID ", " Label ", " Alp ", " X ", " Y ", " Z ", " Snp ", " Tgl ", " DY ", " DZ "); + if (ers) { + printf(" %8s %8s %8s", " pSgYY ", " pSgYZ ", " pSgZZ "); + } // cluster errors + if (getKalmanDone()) { + printf(" %9s %9s", " DYK ", " DZK "); + if (ers) { + printf(" %8s %8s %8s", " tSgYY ", " tSgYZ ", " tSgZZ "); + } // track errors + } + printf("\n"); + for (int i = 0; i < mNPoints; i++) { + float x = mX[i], y = mY[i], z = mZ[i]; + if (lab) { + x = getXLab(i); + y = getYLab(i); + z = getZLab(i); + } + printf("%5d %7d %+5.2f %+7.2f %+7.2f %+7.2f %+5.2f %+5.2f %+9.2e %+9.2e", + mVolID[i], mLabel[i], mAlpha[i], x, y, z, mSnp[i], mTgl[i], mDY[i], mDZ[i]); + if (ers) { + printf(" %.2e %+.1e %.2e", mSigY2[i], mSigYZ[i], mSigZ2[i]); + } + if (getKalmanDone()) { + printf(" %+9.2e %+9.2e", mDYK[i], mDZK[i]); + if (ers) { + printf(" %.2e %+.1e %.2e", mSigY2K[i], mSigYZK[i], mSigZ2K[i]); + } + } + printf("\n"); + } + } +} + +//____________________________________________________________ +bool ResidualsController::fillTrack(AlignmentTrack* trc, bool doKalman) +{ + // fill tracks residuals info + int nps, np = trc->getNPoints(); + if (trc->getInnerPoint()->containsMeasurement()) { + setHasVertex(); + nps = np; + } else { + nps = np - 1; + } // ref point is dummy? + if (nps < 0) { + return true; + } + setCosmic(trc->isCosmic()); + // + setNPoints(nps); + mQ2Pt = trc->getQ2Pt(); + mChi2 = trc->getChi2(); + mChi2Ini = trc->getChi2Ini(); + int nfill = 0; + for (int i = 0; i < np; i++) { + AlignmentPoint* pnt = trc->getPoint(i); + int inv = pnt->isInvDir() ? -1 : 1; // Flag invertion for cosmic upper leg + if (!pnt->containsMeasurement()) { + continue; + } + if (!pnt->isStatOK()) { + pnt->incrementStat(); + } + mVolID[nfill] = pnt->getVolID(); + mLabel[nfill] = pnt->getSensor()->getInternalID(); + mAlpha[nfill] = pnt->getAlphaSens(); + mX[nfill] = pnt->getXPoint() * inv; + mY[nfill] = pnt->getYTracking(); + mZ[nfill] = pnt->getZTracking(); + mDY[nfill] = pnt->getResidY(); + mDZ[nfill] = pnt->getResidZ(); + mSigY2[nfill] = pnt->getYZErrTracking()[0]; + mSigYZ[nfill] = pnt->getYZErrTracking()[1]; + mSigZ2[nfill] = pnt->getYZErrTracking()[2]; + // + mSnp[nfill] = pnt->getTrParamWSA()[AlignmentPoint::kParSnp]; + mTgl[nfill] = pnt->getTrParamWSA()[AlignmentPoint::kParTgl]; + // + nfill++; + } + if (nfill != nps) { + trc->Print("p"); + LOG(FATAL) << nfill << " residuals were stored instead of " << nps; + } + // + setKalmanDone(false); + int nfilk = 0; + if (doKalman && trc->residKalman()) { + for (int i = 0; i < np; i++) { + AlignmentPoint* pnt = trc->getPoint(i); + if (!pnt->containsMeasurement()) { + continue; + } + if (mVolID[nfilk] != int(pnt->getVolID())) { + LOG(FATAL) << "Mismatch in Kalman filling for point " << i << ": filled VID:" << mVolID[nfilk] << ", point VID:" << pnt->getVolID(); + } + const double* wsA = pnt->getTrParamWSA(); + mDYK[nfilk] = pnt->getResidY(); + mDZK[nfilk] = pnt->getResidZ(); + mSigY2K[nfilk] = wsA[2]; + mSigYZK[nfilk] = wsA[3]; + mSigZ2K[nfilk] = wsA[4]; + // + nfilk++; + } + // + mChi2K = trc->getChi2(); + setKalmanDone(true); + } + + return true; +} + +//_________________________________________________ +float ResidualsController::getXLab(int i) const +{ + // cluster lab X + return Abs(mX[i]) * Cos(mAlpha[i]) - mY[i] * Sin(mAlpha[i]); +} + +//_________________________________________________ +float ResidualsController::getYLab(int i) const +{ + // cluster lab Y + return Abs(mX[i]) * Sin(mAlpha[i]) + mY[i] * Cos(mAlpha[i]); +} + +//_________________________________________________ +float ResidualsController::getZLab(int i) const +{ + // cluster lab Z + return mZ[i]; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/ResidualsControllerFast.cxx b/Detectors/Align/src/ResidualsControllerFast.cxx new file mode 100644 index 0000000000000..66054ac75c96c --- /dev/null +++ b/Detectors/Align/src/ResidualsControllerFast.cxx @@ -0,0 +1,169 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ResidualsControllerFast.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Container for control fast residuals evaluated via derivatives + +#include "Align/ResidualsControllerFast.h" +#include "Align/AlignmentTrack.h" +#include "Align/AlignmentPoint.h" +#include "Align/AlignableSensor.h" +#include "Framework/Logger.h" +#include <TString.h> +#include <TMath.h> +#include <cstdio> + +using namespace TMath; + +ClassImp(o2::align::ResidualsControllerFast); + +namespace o2 +{ +namespace align +{ + +//____________________________________ +ResidualsControllerFast::ResidualsControllerFast() + : mNPoints(0), mNMatSol(0), mNBook(0), mChi2(0), mChi2Ini(0), mD0(nullptr), mD1(nullptr), mSig0(nullptr), mSig1(nullptr), mVolID(nullptr), mLabel(nullptr), mSolMat(nullptr), mMatErr(nullptr) +{ + // def c-tor + for (int i = 0; i < 5; ++i) { + mTrCorr[i] = 0; + } +} + +//________________________________________________ +ResidualsControllerFast::~ResidualsControllerFast() +{ + // d-tor + delete[] mD0; + delete[] mD1; + delete[] mSig0; + delete[] mSig1; + delete[] mVolID; + delete[] mLabel; + delete[] mSolMat; + delete[] mMatErr; +} + +//________________________________________________ +void ResidualsControllerFast::resize(int np) +{ + // resize container + if (np > mNBook) { + delete[] mD0; + delete[] mD1; + delete[] mSig0; + delete[] mSig1; + delete[] mVolID; + delete[] mLabel; + delete[] mSolMat; + delete[] mMatErr; + // + mNBook = 30 + np; + mD0 = new float[mNBook]; + mD1 = new float[mNBook]; + mSig0 = new float[mNBook]; + mSig1 = new float[mNBook]; + mVolID = new int[mNBook]; + mLabel = new int[mNBook]; + mSolMat = new float[mNBook * 4]; // at most 4 material params per point + mMatErr = new float[mNBook * 4]; // at most 4 material params per point + // + memset(mD0, 0, mNBook * sizeof(float)); + memset(mD1, 0, mNBook * sizeof(float)); + memset(mSig0, 0, mNBook * sizeof(float)); + memset(mSig1, 0, mNBook * sizeof(float)); + memset(mVolID, 0, mNBook * sizeof(int)); + memset(mLabel, 0, mNBook * sizeof(int)); + memset(mSolMat, 0, 4 * mNBook * sizeof(int)); + memset(mMatErr, 0, 4 * mNBook * sizeof(int)); + } + // +} + +//____________________________________________ +void ResidualsControllerFast::Clear(const Option_t*) +{ + // reset record + mNPoints = 0; + mNMatSol = 0; + mTrCorr[4] = 0; // rest will be 100% overwritten + // +} + +//____________________________________________ +void ResidualsControllerFast::Print(const Option_t* /*opt*/) const +{ + // print info + printf("%3s:%1s (%9s/%5s) %6s | [ %7s:%7s ]\n", "Pnt", "M", "Label", + "VolID", "Sigma", "resid", "pull/LG"); + for (int irs = 0; irs < mNPoints; irs++) { + printf("%3d:%1d (%9d/%5d) %6.4f | [%+.2e:%+7.2f]\n", + irs, 0, mLabel[irs], mVolID[irs], mSig0[irs], mD0[irs], + mSig0[irs] > 0 ? mD0[irs] / mSig0[irs] : -99); + printf("%3d:%1d (%9d/%5d) %6.4f | [%+.2e:%+7.2f]\n", + irs, 1, mLabel[irs], mVolID[irs], mSig1[irs], mD1[irs], + mSig1[irs] > 0 ? mD1[irs] / mSig1[irs] : -99); + } + // + printf("CorrETP: "); + for (int i = 0; i < 5; i++) { + printf("%+.3f ", mTrCorr[i]); + } + printf("\n"); + printf("MatCorr (corr/sig:pull)\n"); + int nmp = mNMatSol / 4; + int cnt = 0; + for (int imp = 0; imp < nmp; imp++) { + for (int ic = 0; ic < 4; ic++) { + printf("%+.2e/%.2e:%+8.3f|", mSolMat[cnt], mMatErr[cnt], + mMatErr[cnt] > 0 ? mSolMat[cnt] / mMatErr[cnt] : -99); + cnt++; + } + printf("\n"); + } + // +} + +//____________________________________________ +void ResidualsControllerFast::setResSigMeas(int ip, int ord, float res, float sig) +{ + // assign residual and error for measurement + if (ord == 0) { + mD0[ip] = res; + mSig0[ip] = sig; + } else { + mD1[ip] = res; + mSig1[ip] = sig; + } +} + +//____________________________________________ +void ResidualsControllerFast::setMatCorr(int id, float res, float sig) +{ + // assign residual and error for material correction + mSolMat[id] = res; + mMatErr[id] = sig; +} + +//____________________________________________ +void ResidualsControllerFast::setLabel(int ip, int lab, int vol) +{ + // set label/volid of measured volume + mVolID[ip] = vol; + mLabel[ip] = lab; +} + +} // namespace align +} // namespace o2 diff --git a/Detectors/Base/CMakeLists.txt b/Detectors/Base/CMakeLists.txt index 5d0b031415a4c..f1cd8eb58b311 100644 --- a/Detectors/Base/CMakeLists.txt +++ b/Detectors/Base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsBase SOURCES src/Detector.cxx @@ -16,9 +17,9 @@ o2_add_library(DetectorsBase src/MatLayerCyl.cxx src/MatLayerCylSet.cxx src/Ray.cxx - src/DCAFitter.cxx src/BaseDPLDigitizer.cxx src/CTFCoderBase.cxx + src/Aligner.cxx PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CommonUtils O2::DetectorsCommonDataFormats @@ -29,12 +30,14 @@ o2_add_library(DetectorsBase O2::Framework FairMQ::FairMQ O2::DataFormatsParameters - O2::SimConfig - ROOT::VMC) + O2::SimConfig + O2::CCDB + ROOT::VMC + PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Merger # Must not link to avoid cyclic dependency + ) o2_target_root_dictionary(DetectorsBase HEADERS include/DetectorsBase/Detector.h - include/DetectorsBase/DCAFitter.h include/DetectorsBase/GeometryManager.h include/DetectorsBase/MaterialManager.h include/DetectorsBase/Propagator.h @@ -42,7 +45,8 @@ o2_target_root_dictionary(DetectorsBase include/DetectorsBase/MatCell.h include/DetectorsBase/MatLayerCyl.h include/DetectorsBase/MatLayerCylSet.h - include/DetectorsBase/CTFCoderBase.h) + include/DetectorsBase/CTFCoderBase.h + include/DetectorsBase/Aligner.h) if(BUILD_SIMULATION) o2_add_test( @@ -55,15 +59,6 @@ if(BUILD_SIMULATION) VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) endif() -o2_add_test( - DCAFitter - SOURCES test/testDCAFitter.cxx - COMPONENT_NAME DetectorsBase - PUBLIC_LINK_LIBRARIES O2::DetectorsBase - LABELS detectorsbase - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) - o2_add_test_root_macro(test/buildMatBudLUT.C PUBLIC_LINK_LIBRARIES O2::DetectorsBase LABELS detectorsbase) diff --git a/Detectors/Base/README.md b/Detectors/Base/README.md new file mode 100644 index 0000000000000..7f6f48be8d170 --- /dev/null +++ b/Detectors/Base/README.md @@ -0,0 +1,53 @@ +<!-- doxy +\page refDetectorsBase Detectors base support +/doxy --> + +# Geometry + +## Loading geometry + +The `o2sim_geometry.root` file is generated by the `o2-sim` (only for the modules which are asked for the simulation). Currently it has to be loaded from the local file, in future its uploading from the CCDB will be implemented. + +The standard way to load the geometry is via static method +```cpp +o2::base::GeometryManager::loadGeometry(std::string_view geomFilePath = "", bool applyMisalignment = true); +``` + +An empty `geomFilePath` is interpreted as a request to load `o2sim_geometry.root` from the current directory. +Otherwise, the following attempts will be done: (i) if it is a valid file name, load as is, +(ii) if it is a valid directory path, load from it `o2sim_geometry.root` file, (iii) otherwise, interpret it as a prefix +to compose a file name `geomFilePath_geometry.root`. Note that if the `ConfigurableParam`-type `NameConf.mDirGeom` string is not empty or equal to `none`, then its value will be prepended +in front of the `geomFilePath` as a top directory. + +The argument `applyMisalignment` will trigger an attempt to apply the misalignment from the CCDB (see below). + +## Applying geometry (mis)alignment + +The `TGeoManager` object stored in the file (or CCDB) corresponds to closed but unlocked `ideal` geometry, whose volumes declared as `alignable` can be modified applying the relevant `TGeoHMatrix`. +This matrix is generated on the fly from the `o2::detectors::AlignParam` objects, which are stored in the vector per detector in the `<DET>/Aling` path on the CCDB. + +The volume aligned by given `AlignParam` object is identified by the its `mSymName` data member (which must be the same as assigned when declaring the volume alignable via +`gGeoManager->SetAlignableEntry(...)` in the detector geometry builder) and (for sensitive volumes only) by the `mAlignableID` data member, also provided for the sensors as an argument of +`SetAlignableEntry(...)` (for the non-sensor volumes `mAlignableID` must be -1). + +The value of the `mAlignableID` must be composed by the static method +`o2::base::GeometryManager::getSensID(DetID detId, int sensID)`, where `sensID` is the sequential number of the sensor for given detector `detId`. + +Some details about the transformations applied by the `o2::detectors::AlignParam` (similar to the Aliroot AliAlignObjParams) can be found in the [The delta-transformation](https://alice-offline.web.cern.ch/Activities/Alignment/deltatr.html) page. + +Currently the test CCDB server [http://ccdb-test.cern.ch:8080](http://ccdb-test.cern.ch:8080) is populated with empty vectors (generated by the `O2/macros/UploadDummyAlignment.C` macro) which do not modify the geometry +(except for the ITS whose misalignment is generated by the sample macro `O2/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C`. + +On the low level the (mis)alignment is applied to the geometry by the static method `o2::base::GeometryManager::applyAlignment(const std::vector<o2::detectors::AlignParam>& algPars)`. +When loading the geometry via `o2::base::GeometryManager::loadGeometry(..)` method the alignment will be applied if the argument `applyMisalignment` is `true`, using the +`o2::base::Aligner` helper. This latter inherits from the `ConfigurableParam`, so it can be configured from the command line by passing `--configKeyValues "align-geom.<key>=<value>"` string (provided the workflow invokes `o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues"))`). +It allows to set the following parameters: + +* `align-geom.mCCDB : URL of the CCDB server, default: "http://ccdb-test.cern.ch:8080"` + +* `align-geom.mDetectors : Comma separated list of detectors, "all"(default) or "none"` + +* `align-geom.mTimeStamp : the time-stamp for CCDB query. If it is 0 (default) then the time-stamp = `now()` in milliseconds will be used. + +`TODO`: once the framework will provide CCDB service, the helper will be adapted to retrieve the alignment objects via query to DPL. + diff --git a/Detectors/Base/include/DetectorsBase/Aligner.h b/Detectors/Base/include/DetectorsBase/Aligner.h new file mode 100644 index 0000000000000..76ea1bb2bde77 --- /dev/null +++ b/Detectors/Base/include/DetectorsBase/Aligner.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ALIGNER_H_ +#define O2_ALIGNER_H_ + +// Helper class to pass and deploy geometry (mis)alignment + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <string> + +namespace o2 +{ +namespace base +{ + +// Global parameters for digitization +class Aligner : public o2::conf::ConfigurableParamHelper<Aligner> +{ + public: + const std::string& getCCDB() const { return mCCDB; } + const std::string& getDetectors() const { return mDetectors; } + long getTimeStamp() const; + o2::detectors::DetID::mask_t getDetectorsMask() const; + + bool isAlignmentRequested() const { return getDetectorsMask().any(); } + void applyAlignment(long timestamp = 0, o2::detectors::DetID::mask_t addMask = o2::detectors::DetID::FullMask) const; + + private: + std::string mCCDB = "http://ccdb-test.cern.ch:8080"; // URL for CCDB acces + std::string mDetectors = "all"; // comma-separated list of modules to align, "all" or "none" + long mTimeStamp = 0; // assigned TimeStamp or now() if 0 + + O2ParamDef(Aligner, "align-geom"); +}; + +} // namespace base +} // namespace o2 + +#endif diff --git a/Detectors/Base/include/DetectorsBase/BaseDPLDigitizer.h b/Detectors/Base/include/DetectorsBase/BaseDPLDigitizer.h index a07965d84ec2c..b285a5579e1c6 100644 --- a/Detectors/Base/include/DetectorsBase/BaseDPLDigitizer.h +++ b/Detectors/Base/include/DetectorsBase/BaseDPLDigitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h index 8cf0e02639e04..afbaa036e164b 100644 --- a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h +++ b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include <TTree.h> #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/CTFDictHeader.h" #include "rANS/rans.h" namespace o2 @@ -52,6 +54,10 @@ class CTFCoderBase if (fileDict) { std::unique_ptr<TTree> tree((TTree*)fileDict->Get(std::string(o2::base::NameConf::CTFDICT).c_str())); CTF::readFromTree(bufVec, *tree.get(), mDet.getName()); + if (bufVec.size()) { + mExtHeader = static_cast<CTFDictHeader&>(CTF::get(bufVec.data())->getHeader()); + LOGP(INFO, "Found {} {} in {}", mDet.getName(), mExtHeader.asString(), dictPath); + } } return bufVec; } @@ -59,10 +65,17 @@ class CTFCoderBase template <typename S> void createCoder(OpType op, const o2::rans::FrequencyTable& freq, uint8_t probabilityBits, int slot) { - if (op == OpType::Encoder) { - mCoders[slot].reset(new o2::rans::LiteralEncoder64<S>(freq, probabilityBits)); - } else { - mCoders[slot].reset(new o2::rans::LiteralDecoder64<S>(freq, probabilityBits)); + if (!freq.size()) { + LOG(WARNING) << "Empty dictionary provided for slot " << slot << ", " << (op == OpType::Encoder ? "encoding" : "decoding") << " will assume literal symbols only"; + } + + switch (op) { + case OpType::Encoder: + mCoders[slot].reset(new o2::rans::LiteralEncoder64<S>(freq, probabilityBits)); + break; + case OpType::Decoder: + mCoders[slot].reset(new o2::rans::LiteralDecoder64<S>(freq, probabilityBits)); + break; } } @@ -74,10 +87,18 @@ class CTFCoderBase } protected: - std::string getPrefix() const { return o2::utils::concat_string(mDet.getName(), "_CTF: "); } + std::string getPrefix() const { return o2::utils::Str::concat_string(mDet.getName(), "_CTF: "); } + void assignDictVersion(CTFDictHeader& h) const + { + if (mExtHeader.isValidDictTimeStamp()) { + h = mExtHeader; + } + } + void checkDictVersion(const CTFDictHeader& h) const; std::vector<std::shared_ptr<void>> mCoders; // encoders/decoders DetID mDet; + CTFDictHeader mExtHeader; // external dictionary header ClassDefNV(CTFCoderBase, 1); }; diff --git a/Detectors/Base/include/DetectorsBase/DCAFitter.h b/Detectors/Base/include/DetectorsBase/DCAFitter.h deleted file mode 100644 index 976bcafde041c..0000000000000 --- a/Detectors/Base/include/DetectorsBase/DCAFitter.h +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file DCAFitter.h -/// \brief Defintions for DCA fitter class -/// \author ruben.shahoyan@cern.ch - -#ifndef _ALICEO2_DCA_FITTER_ -#define _ALICEO2_DCA_FITTER_ - -#include <TMath.h> -#include <Rtypes.h> - -//#define _ADAPT_FOR_ALIROOT_ // to make it compatible with AliRoot AliExternalTrackParam - -#ifdef _ADAPT_FOR_ALIROOT_ -#include "AliExternalTrackParam.h" -typedef AliExternalTrackParam Track; -typedef float ftype_t; // type precision for standard calculation (prefer float) -typedef double dtype_t; // type precision for calculation with risk of round-off errors -#define CONSTRDEF \ - { \ - } -#else -#define CONSTRDEF = default - -#include "ReconstructionDataFormats/Track.h" - -namespace o2 -{ -namespace base -{ -#endif - -class DCAFitter -{ - public: -#ifdef _ADAPT_FOR_ALIROOT_ -#define getSigmaY2 GetSigmaY2 -#define getSigmaZ2 GetSigmaZ2 -#define getSigmaZY GetSigmaZY -#define getAlpha GetAlpha -#define getX GetX -#define getY GetY -#define getZ GetZ -#define getSnp GetSnp -#define getTgl GetTgl -#define getParam GetParameter -#define getCurvature GetC -#define propagateTo PropagateTo -#define propagateParamTo PropagateParamOnlyTo - // -#else - using Track = o2::track::TrackParCov; - using ftype_t = float; // type precision for standard calculation (prefer float) - using dtype_t = double; // type precision for calculation with risk of round-off errors -#endif - - // ---> Auxiliary structs used by DCA finder - - //---------------------------------------------------- - ///< Inverse cov matrix of the point defined by the track - struct TrackCovI { - ftype_t sxx, syy, syz, szz; - - TrackCovI(const Track& trc) { set(trc); } - TrackCovI() CONSTRDEF; - void set(const Track& trc) - { - // we assign Y error to X for DCA calculation of 2 points - // (otherwise for quazi-collinear tracks the X will not be constrained) - ftype_t cyy = trc.getSigmaY2(), czz = trc.getSigmaZ2(), cyz = trc.getSigmaZY(), cxx = cyy; - ftype_t detYZ = cyy * czz - cyz * cyz; - if (detYZ > 0.) { - sxx = 1. / cxx; - syy = czz / detYZ; - syz = -cyz / detYZ; - szz = cyy / detYZ; - } else { - syy = 0.0; // failure - } - } - }; - - //---------------------------------------------------- - ///< Derivative (up to 2) of the TrackParam position over its running param X - struct TrackDeriv2 { - ftype_t dydx, dzdx, d2ydx2, d2zdx2; - - TrackDeriv2() CONSTRDEF; - TrackDeriv2(const Track& trc, ftype_t bz) { set(trc, bz); } - void set(const Track& trc, ftype_t bz) - { - ftype_t snp = trc.getSnp(), csp = TMath::Sqrt((1. - snp) * (1. + snp)), cspI = 1. / csp, crv2c = trc.getCurvature(bz) * cspI; - dydx = snp * cspI; // = snp/csp - dzdx = trc.getTgl() * cspI; // = tgl/csp - d2ydx2 = crv2c * cspI * cspI; // = crv/csp^3 - d2zdx2 = crv2c * dzdx * dydx; // = crv*tgl*snp/csp^3 - } - }; - - //---------------------------------------------------- - //< precalculated track radius, center, alpha sin,cos and their combinations - struct TrcAuxPar { - dtype_t c, s; // cos ans sin of track alpha - dtype_t cc, cs, ss; // products - dtype_t r, xCen, yCen; // helix radius and center in lab - - TrcAuxPar() CONSTRDEF; - TrcAuxPar(const Track& trc, ftype_t bz) { set(trc, bz); } - - void set(const Track& trc, ftype_t bz) - { - c = TMath::Cos(trc.getAlpha()); - s = TMath::Sin(trc.getAlpha()); - setRCen(trc, bz); - cc = c * c; - ss = s * s; - cs = c * s; - } - - void setRCen(const Track& tr, ftype_t bz); - - void glo2loc(ftype_t vX, ftype_t vY, ftype_t& vXL, ftype_t& vYL) const - { - // rotate XY in global frame to the frame of track with angle A - vXL = vX * c + vY * s; - vYL = -vX * s + vY * c; - } - - void loc2glo(ftype_t vXL, ftype_t vYL, ftype_t& vX, ftype_t& vY) const - { - // rotate XY in local alpha frame to global frame - vX = vXL * c - vYL * s; - vY = vXL * s + vYL * c; - } - void glo2loc(dtype_t vX, dtype_t vY, dtype_t& vXL, dtype_t& vYL) const - { - // rotate XY in global frame to the frame of track with angle A - vXL = vX * c + vY * s; - vYL = -vX * s + vY * c; - } - - void loc2glo(dtype_t vXL, dtype_t vYL, dtype_t& vX, dtype_t& vY) const - { - // rotate XY in local alpha frame to global frame - vX = vXL * c - vYL * s; - vY = vXL * s + vYL * c; - } - }; - - //---------------------------------------------------- - //< coefficients of the track-point contribution to the PCA (Vx,Vy,Vz) to 2 points in lab frame represented via local points coordinates as - //< Vx = mXX0*x0+mXY0*y0+mXZ0*z0 + mXX1*x1+mXY1*y1+mXZ1*z1 - //< Vy = mYX0*x0+mYY0*y0+mYZ0*z0 + mYX1*x1+mYY1*y1+mYZ1*z1 - //< Vz = mZX0*x0+mZY0*y0+mZZ0*z0 + mZX1*x1+mZY1*y1+mZZ1*z1 - //< where {x0,y0,z0} and {x1,y1,z1} are track positions in their local frames - struct TrackCoefVtx { - ftype_t mXX, mXY, mXZ, mYX, mYY, mYZ, mZX, mZY, mZZ; - TrackCoefVtx() CONSTRDEF; - }; - - //---------------------------------------------------- - ///< particular point on track trajectory (in track proper alpha-frame) - struct Triplet { - ftype_t x, y, z; - Triplet(Track& trc) { set(trc); } - Triplet(ftype_t px = 0, ftype_t py = 0, ftype_t pz = 0) : x(px), y(py), z(pz) {} - void set(const Track& trc) - { - x = trc.getX(); - y = trc.getY(); - z = trc.getZ(); - } - }; - - //---------------------------------------------------- - //< crossing coordinates of 2 circles - struct CrossInfo { - ftype_t xDCA[2]; - ftype_t yDCA[2]; - int nDCA; - - CrossInfo() CONSTRDEF; - CrossInfo(const TrcAuxPar& trc0, const TrcAuxPar& trc1) { set(trc0, trc1); } - void set(const TrcAuxPar& trc0, const TrcAuxPar& trc1); - - void notTouchingXY(ftype_t dist, ftype_t xDist, ftype_t yDist, const TrcAuxPar& trcA, ftype_t rBSign) - { - // fast method to calculate DCA between 2 circles, assuming that they don't touch each outer: - // the parametric equation of lines connecting the centers is x = xA + t/dist * xDist, y = yA + t/dist * yDist - // with xA,yY being the center of the circle A ( = trcA.xCen, trcA.yCen ), xDist = trcB.xCen = trcA.xCen ... - // There are 2 special cases: - // (a) small circle is inside the large one: provide rBSign as -trcB.r - // (b) circle are side by side: provide rBSign as trcB.r - nDCA = 1; - auto t2d = (dist + trcA.r - rBSign) / dist; - xDCA[0] = trcA.xCen + 0.5 * (xDist * t2d); - yDCA[0] = trcA.yCen + 0.5 * (yDist * t2d); - } - }; - - struct Derivatives { - dtype_t dChidx0, dChidx1; // 1st derivatives of chi2 vs tracks local parameters X - dtype_t dChidx0dx0, dChidx1dx1, dChidx0dx1; // 2nd derivatives of chi2 vs tracks local parameters X - }; - - // <--- Auxiliary structs used by DCA finder - - //=============================================================================== - - DCAFitter() CONSTRDEF; - - int getMaxIter() const - { - return mMaxIter; - } - ftype_t getMaxR() const { return TMath::Sqrt(mMaxR2); } - ftype_t getMaxChi2() const { return mMaxChi2; } - ftype_t getMinParamChange() const { return mMinParamChange; } - ftype_t getBz() const { return mBz; } - bool getUseAbsDCA() const { return mUseAbsDCA; } - - void setMaxIter(int n = 20) { mMaxIter = n > 2 ? n : 2; } - void setMaxR(ftype_t r = 200.) { mMaxR2 = r * r; } - void setMaxChi2(ftype_t chi2 = 999.) { mMaxChi2 = chi2; } - void setBz(ftype_t bz) { mBz = bz; } - void setMinParamChange(ftype_t x = 1e-3) { mMinParamChange = x > 1e-4 ? x : 1.e-4; } - void setMinRelChi2Change(ftype_t r = 0.9) { mMinRelChi2Change = r > 0.1 ? r : 999.; } - void setUseAbsDCA(bool v) { mUseAbsDCA = v; } - - void clear() - { - mNCandidates = 0; - mCrossIDCur = 0; - mCrossIDAlt = -1; - } - - DCAFitter(ftype_t bz, ftype_t minRelChiChange = 0.9, ftype_t minXChange = 1e-3, ftype_t maxChi = 999, int n = 20, ftype_t maxR = 200.) - { - setMaxIter(n); - setMaxR(maxR); - setMaxChi2(maxChi); - setMinParamChange(minXChange); - setMinRelChi2Change(minRelChiChange); - setBz(bz); - setUseAbsDCA(false); // by default use weighted DCA definition (much slower) - } - - ///< number of validated V0 candidates (at most 2 are possible) - int getNCandidates() const { return mNCandidates; } - - ///< return PCA candidate (no check for its validity) - const Triplet& getPCACandidate(int cand) const { return mPCA[cand]; } - - ///< return Chi2 at PCA candidate (no check for its validity) - ftype_t getChi2AtPCACandidate(int cand) const { return mChi2[cand]; } - - ///< 1st track params propagated to V0 candidate (no check for the candidate validity) - const Track& getTrack0(int cand) const { return mCandTr0[cand]; } - - ///< 2nd track params propagated to V0 candidate (no check for the candidate validity) - const Track& getTrack1(int cand) const { return mCandTr1[cand]; } - - ///< calculate parameters tracks at PCA - int process(const Track& trc0, const Track& trc1) - { - // find dca of 2 tracks - TrcAuxPar trc0Aux(trc0, mBz), trc1Aux(trc1, mBz); - return process(trc0, trc0Aux, trc1, trc1Aux); - } - - ///< calculate parameters tracks at PCA, using precalculated aux info // = TrcAuxPar(track) // - int process(const Track& trc0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrcAuxPar& trc1Aux); - - ///< minimizer for abs distance definition of DCA, starting with cached tracks - bool processCandidateDCA(const TrcAuxPar& trc0Aux, const TrcAuxPar& trc1Aux); - - ///< minimizer for weighted distance definition of DCA (chi2), starting with cached tracks - bool processCandidateChi2(const TrcAuxPar& trc0Aux, const TrcAuxPar& trc1Aux); - - ///< minimize w/o preliminary propagation to XY crossing points - int processAsIs(const Track& trc0, const Track& trc1); - - ///< calculate squared distance between 2 tracks - static ftype_t getDistance2(const Track& trc0, const Track& trc1); - - ///< calculate half sum of squared distances between 2 tracks and vertex - static ftype_t getDistance2(ftype_t x, ftype_t y, ftype_t z, const Track& trc0, const Track& trc1); - - protected: - void calcPCACoefs(const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, - const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1, - TrackCoefVtx& trCFVT0, TrackCoefVtx& trCFVT1) const; - - ///< PCA with weighted DCA definition - void calcPCA(const Track& trc0, const TrackCoefVtx& trCFVT0, - const Track& trc1, const TrackCoefVtx& trCFVT1, - Triplet& v) const; - - ///< PCA with abs DCA definition - void calcPCA(const Track& trc0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrcAuxPar& trc1Aux, - Triplet& v) const; - - ///< chi2 (weighted distance) - ftype_t calcChi2(const Triplet& pca, - const Track& trc0, const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, - const Track& trc1, const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1) const; - - ///< DCA (abs distance) - ftype_t calcDCA(const Track& tPnt0, const TrcAuxPar& trc0Aux, const Track& tPnt1, const TrcAuxPar& trc1Aux) const; - ftype_t calcDCA(const Triplet& pca, const Track& trc0, const TrcAuxPar& trc0Aux, const Track& trc1, const TrcAuxPar& trc1Aux) const; - - Triplet calcResid(const Track& trc, const TrcAuxPar& alpCS, const Triplet& vtx) const - { - ftype_t vlX, vlY; // Vertex XY in track local frame - alpCS.glo2loc(vtx.x, vtx.y, vlX, vlY); - return Triplet(trc.getX() - vlX, trc.getY() - vlY, trc.getZ() - vtx.z); - } - - void chi2Deriv(const Track& trc0, const TrackDeriv2& tDer0, const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, const TrackCoefVtx& trCFVT0, - const Track& trc1, const TrackDeriv2& tDer1, const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1, const TrackCoefVtx& trCFVT1, - Derivatives& deriv) const; - - void DCADeriv(const Track& trc0, const TrackDeriv2& tDer0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrackDeriv2& tDer1, const TrcAuxPar& trc1Aux, - Derivatives& deriv) const; - - bool closerToAlternative(ftype_t x, ftype_t y) const; - - private: - bool mUseAbsDCA; // ignore track errors (minimize abs DCA to vertex) - int mMaxIter; // max iterations - ftype_t mMaxR2; // max radius to consider - ftype_t mMaxChi2; // max chi2 to accept - ftype_t mMinRelChi2Change; // stop iterations if relative chi2 change is less than requested - ftype_t mMinParamChange; // stop iterations when both X params change by less than this value - - ftype_t mBz; // mag field for simple propagation - - // Working arrays - CrossInfo mCrossings; //! analystical XY crossings (max 2) of the seeds - int mCrossIDCur; //! XY crossing being tested - int mCrossIDAlt; //! XY crossing alternative to the one being tested. Abandon fit if it converges to it - - int mNCandidates; //! number of consdered candidates - Triplet mPCA[2]; //! PCA for 2 possible cases - ftype_t mChi2[2]; //! Chi2 at PCA candidate - TrackCovI mTrcEI0[2], mTrcEI1[2]; //! errors for each track candidate - TrackCoefVtx mTrCFVT0[2], mTrCFVT1[2]; //! coefficients of PCA vs track points for each track - Track mCandTr0[2], mCandTr1[2]; //! Tracks at PCA, max 2 candidates. Note: Errors are at seed XY point - - ClassDefNV(DCAFitter, 1); -}; - -#ifndef _ADAPT_FOR_ALIROOT_ -} -} -#endif - -#endif // _O2_DCA_FITTER_ diff --git a/Detectors/Base/include/DetectorsBase/Detector.h b/Detectors/Base/include/DetectorsBase/Detector.h index f37d2bc5b2ca2..70ef37af66152 100644 --- a/Detectors/Base/include/DetectorsBase/Detector.h +++ b/Detectors/Base/include/DetectorsBase/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,9 +35,11 @@ #include <type_traits> #include <unistd.h> #include <cassert> +#include <list> +#include <mutex> +#include <thread> -class FairMQParts; -class FairMQChannel; +#include <fairmq/FwdDecls.h> namespace o2 { @@ -163,6 +166,12 @@ class Detector : public FairDetector // and to decode it virtual void attachHits(FairMQChannel&, FairMQParts&) = 0; virtual void fillHitBranch(TTree& tr, FairMQParts& parts, int& index) = 0; + virtual void collectHits(int eventID, FairMQParts& parts, int& index) = 0; + virtual void mergeHitEntriesAndFlush(int eventID, + TTree& target, + std::vector<int> const& trackoffsets, + std::vector<int> const& nprimaries, + std::vector<int> const& subevtsOrdered) = 0; // interface needed to merge together hit entries in TBranches (as used by hit merger process) // trackoffsets: a map giving the corresponding trackoffset to be applied to the trackID property when @@ -388,7 +397,6 @@ class DetImpl : public o2::base::Detector } // this could be further generalized by using a policy for T std::copy(incomingdata->begin(), incomingdata->end(), std::back_inserter(*targetdata)); - // adjust offset delete incomingdata; incomingdata = nullptr; } @@ -411,6 +419,67 @@ class DetImpl : public o2::base::Detector } } + // this merges several entries from temporary hit buffer into + // into a single entry in a target TTree / same branch + // (assuming T is typically a vector; merging is simply done by appending) + template <typename T, typename L> + void mergeAndAdjustHits(std::string const& brname, L& hitbuffervector, TTree& target, + std::vector<int> const& trackoffsets, std::vector<int> const& nprimaries, + std::vector<int> const& subevtsOrdered) + { + auto entries = hitbuffervector.size(); + + auto targetdata = new T; // used to collect data inside a single container + T* filladdress = nullptr; // pointer used for final ROOT IO + if (entries == 1) { + filladdress = hitbuffervector[0].get(); + // nothing to do; we can directly do IO from the existing buffer + } else { + // here we need to do merging and index adjustment + int nprimTot = 0; + for (auto entry = 0; entry < entries; entry++) { + nprimTot += nprimaries[entry]; + } + // offset for pimary track index + int idelta0 = 0; + // offset for secondary track index + int idelta1 = nprimTot; + filladdress = targetdata; + for (int entry = entries - 1; entry >= 0; --entry) { + // proceed in the order of subevent Ids + int index = subevtsOrdered[entry]; + // number of primaries for this event + int nprim = nprimaries[index]; + idelta1 -= nprim; + + // fetch correct data item + auto incomingdata = hitbuffervector[index].get(); + if (incomingdata) { + // fix the trackIDs for this data + for (auto& hit : *incomingdata) { + const auto oldID = hit.GetTrackID(); + // offset depends on whether the trackis a primary or secondary + int offset = (oldID < nprim) ? idelta0 : idelta1; + hit.SetTrackID(oldID + offset); + } + // this could be further generalized by using a policy for T + std::copy(incomingdata->begin(), incomingdata->end(), std::back_inserter(*targetdata)); + } + // adjust offsets for next subevent + idelta0 += nprim; + idelta1 += trackoffsets[index]; + } // subevent loop + } + // fill target for this event + auto targetbr = o2::base::getOrMakeBranch(target, brname.c_str(), &filladdress); + targetbr->SetAddress(&filladdress); + targetbr->Fill(); + targetbr->ResetAddress(); + targetdata->clear(); + hitbuffervector.clear(); + delete targetdata; + } + void mergeHitEntries(TTree& origin, TTree& target, std::vector<int> const& trackoffsets, std::vector<int> const& nprimaries, std::vector<int> const& subevtsOrdered) final { // loop over hit containers / different branches @@ -425,7 +494,101 @@ class DetImpl : public o2::base::Detector } } + void mergeHitEntriesAndFlush(int eventID, TTree& target, std::vector<int> const& trackoffsets, std::vector<int> const& nprimaries, std::vector<int> const& subevtsOrdered) final + { + // loop over hit containers / different branches + // adjust trackID in hits on the go + int probe = 0; + using Hit_t = typename std::remove_pointer<decltype(static_cast<Det*>(this)->Det::getHits(0))>::type; + // remove buffered event from the hit store + using Collector_t = std::map<int, std::vector<std::vector<std::unique_ptr<Hit_t>>>>; + auto hitbufferPtr = reinterpret_cast<Collector_t*>(mHitCollectorBufferPtr); + auto iter = hitbufferPtr->find(eventID); + if (iter == hitbufferPtr->end()) { + LOG(ERROR) << "No buffered hits available for event " << eventID; + return; + } + + std::string name = static_cast<Det*>(this)->getHitBranchNames(probe); + while (name.size() > 0) { + auto& vectorofHitBuffers = (*iter).second[probe]; + // flushing and buffer removal is done inside here: + mergeAndAdjustHits<Hit_t>(name, vectorofHitBuffers, target, trackoffsets, nprimaries, subevtsOrdered); + // next name + probe++; + name = static_cast<Det*>(this)->getHitBranchNames(probe); + } + { + // std::lock_guard<std::mutex> l(mHitBufferMutex); + hitbufferPtr->erase(eventID); + } + } + public: + /// Collect Hits available as incoming message (shared mem or not) + /// inside this process for later streaming to output. A function needed + /// by the hit-merger process (not for direct use by users) + void collectHits(int eventID, FairMQParts& parts, int& index) override + { + using Hit_t = typename std::remove_pointer<decltype(static_cast<Det*>(this)->Det::getHits(0))>::type; + using Collector_t = std::map<int, std::vector<std::vector<std::unique_ptr<Hit_t>>>>; + static Collector_t hitcollector; // note: we can't put this as member because + // decltype type deduction doesn't seem to work for class members; so we use a static member + // and will use some pointer member to communicate this data to other functions + mHitCollectorBufferPtr = (char*)&hitcollector; + + int probe = 0; + bool* busy = nullptr; + using HitPtr_t = decltype(static_cast<Det*>(this)->Det::getHits(probe)); + std::string name = static_cast<Det*>(this)->getHitBranchNames(probe); + + auto copyToBuffer = [this, eventID](HitPtr_t hitdata, Collector_t& collectbuffer, int probe) { + std::vector<std::vector<std::unique_ptr<Hit_t>>>* hitvector = nullptr; + { + // we protect reading from this map by a lock + // since other threads might delete from the buffer at the same time + // std::lock_guard<std::mutex> l(mHitBufferMutex); + auto eventIter = collectbuffer.find(eventID); + if (eventIter == collectbuffer.end()) { + collectbuffer[eventID] = std::vector<std::vector<std::unique_ptr<Hit_t>>>(); + } + hitvector = &(collectbuffer[eventID]); + } + if (probe >= hitvector->size()) { + hitvector->resize(probe + 1); + } + // add empty hit bucket to list for this event and probe + (*hitvector)[probe].emplace_back(new Hit_t()); + // copy the data into this bucket + *((*hitvector)[probe].back()) = *hitdata; + }; + + while (name.size() > 0) { + if (!UseShm<Det>::value || !o2::utils::ShmManager::Instance().isOperational()) { + // for each branch name we extract/decode hits from the message parts ... + auto hitsptr = decodeTMessage<HitPtr_t>(parts, index++); + if (hitsptr) { + // ... and copy them to the buffer + copyToBuffer(hitsptr, hitcollector, probe); + delete hitsptr; + } + } else { + // for each branch name we extract/decode hits from the message parts ... + auto hitsptr = decodeShmMessage<HitPtr_t>(parts, index++, busy); + // ... and copy them to the buffer + copyToBuffer(hitsptr, hitcollector, probe); + } + // next name + probe++; + name = static_cast<Det*>(this)->getHitBranchNames(probe); + } + // there is only one busy flag per detector so we need to clear it only + // at the end (after all branches have been treated) + if (busy) { + *busy = false; + } + } + void fillHitBranch(TTree& tr, FairMQParts& parts, int& index) override { int probe = 0; @@ -576,6 +739,8 @@ class DetImpl : public o2::base::Detector std::vector<void*> mCachedPtr[NHITBUFFERS]; int mCurrentBuffer = 0; // holding the current buffer information int mInitialized = false; + + char* mHitCollectorBufferPtr = nullptr; //! pointer to hit (collector) buffer location (strictly internal) ClassDefOverride(DetImpl, 0); }; } // namespace base diff --git a/Detectors/Base/include/DetectorsBase/GeometryManager.h b/Detectors/Base/include/DetectorsBase/GeometryManager.h index dadd378f07968..c3e8f263d22d5 100644 --- a/Detectors/Base/include/DetectorsBase/GeometryManager.h +++ b/Detectors/Base/include/DetectorsBase/GeometryManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include <TObject.h> // for TObject #include <string_view> #include "DetectorsCommonDataFormats/DetID.h" -#include "FairLogger.h" // for LOG +#include "GPUCommonLogger.h" // for LOG #include "MathUtils/Cartesian.h" #include "DetectorsBase/MatCell.h" #include <mutex> @@ -48,7 +49,7 @@ class GeometryManager : public TObject { public: ///< load geometry from file - static void loadGeometry(std::string_view geomFilePath = ""); + static void loadGeometry(std::string_view geomFilePath = "", bool applyMisalignment = true); static bool isGeometryLoaded() { return gGeoManager != nullptr; } ///< Get the global transformation matrix (ideal geometry) for a given alignable volume @@ -57,6 +58,7 @@ class GeometryManager : public TObject ///< performed before alignment. static Bool_t getOriginalMatrix(o2::detectors::DetID detid, int sensid, TGeoHMatrix& m); static Bool_t getOriginalMatrix(const char* symname, TGeoHMatrix& m); + static TGeoHMatrix* getMatrix(const char* symname); static const char* getSymbolicName(o2::detectors::DetID detid, int sensid); static TGeoPNEntry* getPNEntry(o2::detectors::DetID detid, Int_t sensid); static TGeoHMatrix* getMatrix(o2::detectors::DetID detid, Int_t sensid); @@ -71,7 +73,8 @@ class GeometryManager : public TObject ~GeometryManager() override = default; /// misalign geometry with alignment objects from the array, optionaly check overlaps - static bool applyAlignment(TObjArray& alObjArray, bool ovlpcheck = false, double ovlToler = 1e-3); + static bool applyAlignment(const std::vector<o2::detectors::AlignParam>& algPars); + static bool applyAlignment(const std::vector<const std::vector<o2::detectors::AlignParam>*> algPars); struct MatBudgetExt { double meanRho = 0.; // mean density: sum(x_i*rho_i)/sum(x_i) [g/cm3] @@ -114,7 +117,7 @@ class GeometryManager : public TObject private: /// Default constructor GeometryManager() = default; - + static TGeoHMatrix* getMatrix(TGeoPNEntry* pne); static void accountMaterial(const TGeoMaterial* material, MatBudgetExt& bd); static void accountMaterial(const TGeoMaterial* material, o2::base::MatBudget& bd) { diff --git a/Detectors/Base/include/DetectorsBase/MatCell.h b/Detectors/Base/include/DetectorsBase/MatCell.h index 6f5b931155310..b5af66439955d 100644 --- a/Detectors/Base/include/DetectorsBase/MatCell.h +++ b/Detectors/Base/include/DetectorsBase/MatCell.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,6 +57,16 @@ struct MatBudget : MatCell { length *= scale; } + GPUd() float getXRho() const + { + return meanRho * length; + } + + GPUd() float getXRho(int signCorr) const + { + return meanRho * (signCorr < 0 ? -length : length); + } + ClassDefNV(MatBudget, 1); }; diff --git a/Detectors/Base/include/DetectorsBase/MatLayerCyl.h b/Detectors/Base/include/DetectorsBase/MatLayerCyl.h index cf0acc750b53b..defc60bd59a99 100644 --- a/Detectors/Base/include/DetectorsBase/MatLayerCyl.h +++ b/Detectors/Base/include/DetectorsBase/MatLayerCyl.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h b/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h index e0912de30c691..488b0eab317fb 100644 --- a/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h +++ b/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/include/DetectorsBase/MaterialManager.h b/Detectors/Base/include/DetectorsBase/MaterialManager.h index 46b48e77f7423..4faab82067bb8 100644 --- a/Detectors/Base/include/DetectorsBase/MaterialManager.h +++ b/Detectors/Base/include/DetectorsBase/MaterialManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -201,6 +202,11 @@ class MaterialManager // print out all registered media void printMedia() const; + /// set the density scaling factor + void setDensityScalingFactor(float f) { mDensityFactor = f; } + /// set the density scaling factor + float getDensityScalingFactor() const { return mDensityFactor; } + /// print all tracking media inside a logical volume (specified by name) /// and all of its daughters static void printContainingMedia(std::string const& volumename); diff --git a/Detectors/Base/include/DetectorsBase/Propagator.h b/Detectors/Base/include/DetectorsBase/Propagator.h index 861d0f2810ef4..f60ca8b370641 100644 --- a/Detectors/Base/include/DetectorsBase/Propagator.h +++ b/Detectors/Base/include/DetectorsBase/Propagator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,13 +16,18 @@ #ifndef ALICEO2_BASE_PROPAGATOR_ #define ALICEO2_BASE_PROPAGATOR_ -#include <string> +#include "GPUCommonRtypes.h" +#include "GPUCommonArray.h" #include "CommonConstants/PhysicsConstants.h" #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/TrackLTIntegral.h" #include "DetectorsBase/MatLayerCylSet.h" +#ifndef GPUCA_GPUCODE +#include <string> +#endif + namespace o2 { namespace parameters @@ -37,91 +43,133 @@ class VertexBase; namespace field { class MagFieldFast; +class MagneticField; +} + +namespace gpu +{ +class GPUTPCGMPolynomialField; } namespace base { -class Propagator + +template <typename value_T> +class PropagatorImpl { public: + using value_type = value_T; + using TrackPar_t = track::TrackParametrization<value_type>; + using TrackParCov_t = track::TrackParametrizationWithError<value_type>; + enum class MatCorrType : int { USEMatCorrNONE, // flag to not use material corrections USEMatCorrTGeo, // flag to use TGeo for material queries USEMatCorrLUT }; // flag to use LUT for material queries (user must provide a pointer - static Propagator* Instance() - { - static Propagator instance; - return &instance; - } - static constexpr float MAX_SIN_PHI = 0.85f; static constexpr float MAX_STEP = 2.0f; - bool PropagateToXBxByBz(o2::track::TrackParCov& track, float x, float mass = o2::constants::physics::MassPionCharged, - float maxSnp = MAX_SIN_PHI, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + GPUd() bool PropagateToXBxByBz(TrackParCov_t& track, value_type x, + value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + + GPUd() bool PropagateToXBxByBz(TrackPar_t& track, value_type x, + value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; - bool PropagateToXBxByBz(o2::track::TrackPar& track, float x, float mass = o2::constants::physics::MassPionCharged, - float maxSnp = MAX_SIN_PHI, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + GPUd() bool propagateToX(TrackParCov_t& track, value_type x, value_type bZ, + value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; - bool propagateToX(o2::track::TrackParCov& track, float x, float bZ, float mass = o2::constants::physics::MassPionCharged, - float maxSnp = MAX_SIN_PHI, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + GPUd() bool propagateToX(TrackPar_t& track, value_type x, value_type bZ, + value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; - bool propagateToX(o2::track::TrackPar& track, float x, float bZ, float mass = o2::constants::physics::MassPionCharged, - float maxSnp = MAX_SIN_PHI, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + template <typename track_T> + GPUd() bool propagateTo(track_T& track, value_type x, bool bzOnly = false, value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, + MatCorrType matCorr = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const + { + return bzOnly ? propagateToX(track, x, getNominalBz(), maxSnp, maxStep, matCorr, tofInfo, signCorr) : PropagateToXBxByBz(track, x, maxSnp, maxStep, matCorr, tofInfo, signCorr); + } - bool propagateToDCA(const o2::dataformats::VertexBase& vtx, o2::track::TrackParCov& track, float bZ, - float mass = o2::constants::physics::MassPionCharged, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::dataformats::DCA* dcaInfo = nullptr, o2::track::TrackLTIntegral* tofInfo = nullptr, - int signCorr = 0, float maxD = 999.f) const; + GPUd() bool propagateToDCA(const o2::dataformats::VertexBase& vtx, o2::track::TrackParametrizationWithError<value_type>& track, value_type bZ, + value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + o2::dataformats::DCA* dcaInfo = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + int signCorr = 0, value_type maxD = 999.f) const; - bool propagateToDCABxByBz(const o2::dataformats::VertexBase& vtx, o2::track::TrackParCov& track, - float mass = o2::constants::physics::MassPionCharged, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - o2::dataformats::DCA* dcaInfo = nullptr, o2::track::TrackLTIntegral* tofInfo = nullptr, - int signCorr = 0, float maxD = 999.f) const; + GPUd() bool propagateToDCABxByBz(const o2::dataformats::VertexBase& vtx, o2::track::TrackParametrizationWithError<value_type>& track, + value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + o2::dataformats::DCA* dcaInfo = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + int signCorr = 0, value_type maxD = 999.f) const; - bool propagateToDCA(const o2::math_utils::Point3D<float>& vtx, o2::track::TrackPar& track, float bZ, - float mass = o2::constants::physics::MassPionCharged, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - std::array<float, 2>* dca = nullptr, o2::track::TrackLTIntegral* tofInfo = nullptr, - int signCorr = 0, float maxD = 999.f) const; + GPUd() bool propagateToDCA(const o2::math_utils::Point3D<value_type>& vtx, o2::track::TrackParametrization<value_type>& track, value_type bZ, + value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + gpu::gpustd::array<value_type, 2>* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + int signCorr = 0, value_type maxD = 999.f) const; - bool propagateToDCABxByBz(const o2::math_utils::Point3D<float>& vtx, o2::track::TrackPar& track, - float mass = o2::constants::physics::MassPionCharged, float maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrTGeo, - std::array<float, 2>* dca = nullptr, o2::track::TrackLTIntegral* tofInfo = nullptr, - int signCorr = 0, float maxD = 999.f) const; + GPUd() bool propagateToDCABxByBz(const o2::math_utils::Point3D<value_type>& vtx, o2::track::TrackParametrization<value_type>& track, + value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, + gpu::gpustd::array<value_type, 2>* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + int signCorr = 0, value_type maxD = 999.f) const; - Propagator(Propagator const&) = delete; - Propagator(Propagator&&) = delete; - Propagator& operator=(Propagator const&) = delete; - Propagator& operator=(Propagator&&) = delete; + PropagatorImpl(PropagatorImpl const&) = delete; + PropagatorImpl(PropagatorImpl&&) = delete; + PropagatorImpl& operator=(PropagatorImpl const&) = delete; + PropagatorImpl& operator=(PropagatorImpl&&) = delete; // Bz at the origin - float getNominalBz() const { return mBz; } + GPUd() value_type getNominalBz() const { return mBz; } + + GPUd() void setMatLUT(const o2::base::MatLayerCylSet* lut) { mMatLUT = lut; } + GPUd() const o2::base::MatLayerCylSet* getMatLUT() const { return mMatLUT; } + GPUd() void setGPUField(const o2::gpu::GPUTPCGMPolynomialField* field) { mGPUField = field; } + GPUd() const o2::gpu::GPUTPCGMPolynomialField* getGPUField() const { return mGPUField; } + GPUd() void setBz(value_type bz) { mBz = bz; } + + GPUd() void estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization<value_type>& trc) const; - void setMatLUT(const o2::base::MatLayerCylSet* lut) { mMatLUT = lut; } - const o2::base::MatLayerCylSet* getMatLUT() const { return mMatLUT; } +#ifndef GPUCA_GPUCODE + static PropagatorImpl* Instance(bool uninitialized = false) + { + static PropagatorImpl instance(uninitialized); + return &instance; + } static int initFieldFromGRP(const o2::parameters::GRPObject* grp, bool verbose = false); - static int initFieldFromGRP(const std::string grpFileName, std::string grpName = "GRP", bool verbose = false); + static int initFieldFromGRP(const std::string grpFileName = "", std::string grpName = "GRP", bool verbose = false); +#endif + + GPUd() MatBudget getMatBudget(MatCorrType corrType, const o2::math_utils::Point3D<value_type>& p0, const o2::math_utils::Point3D<value_type>& p1) const; + + GPUd() void getFieldXYZ(const math_utils::Point3D<float> xyz, float* bxyz) const; + + GPUd() void getFieldXYZ(const math_utils::Point3D<double> xyz, double* bxyz) const; private: - Propagator(); - ~Propagator() = default; +#ifndef GPUCA_GPUCODE + PropagatorImpl(bool uninitialized = false); + ~PropagatorImpl() = default; +#endif - MatBudget getMatBudget(MatCorrType corrType, const o2::math_utils::Point3D<float>& p0, const o2::math_utils::Point3D<float>& p1) const; + template <typename T> + GPUd() void getFieldXYZImpl(const math_utils::Point3D<T> xyz, T* bxyz) const; - const o2::field::MagFieldFast* mField = nullptr; ///< External fast field (barrel only for the moment) - float mBz = 0; // nominal field + const o2::field::MagFieldFast* mFieldFast = nullptr; ///< External fast field map (barrel only for the moment) + o2::field::MagneticField* mField = nullptr; ///< External nominal field map + value_type mBz = 0; ///< nominal field - const o2::base::MatLayerCylSet* mMatLUT = nullptr; // externally set LUT + const o2::base::MatLayerCylSet* mMatLUT = nullptr; // externally set LUT + const o2::gpu::GPUTPCGMPolynomialField* mGPUField = nullptr; // externally set GPU Field - ClassDef(Propagator, 0); + ClassDefNV(PropagatorImpl, 0); }; + +using PropagatorF = PropagatorImpl<float>; +using PropatatorD = PropagatorImpl<double>; +using Propagator = PropagatorF; + } // namespace base } // namespace o2 diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 4b489b599fb5f..1701e65c2d638 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/src/Aligner.cxx b/Detectors/Base/src/Aligner.cxx new file mode 100644 index 0000000000000..088660dcfaec4 --- /dev/null +++ b/Detectors/Base/src/Aligner.cxx @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsBase/Aligner.h" +#include "CCDB/BasicCCDBManager.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <chrono> + +O2ParamImpl(o2::base::Aligner); + +using namespace o2::base; + +using DetID = o2::detectors::DetID; + +DetID::mask_t Aligner::getDetectorsMask() const +{ + return DetID::getMask(mDetectors) & (~DetID::getMask(DetID::CTP)); +} + +void Aligner::applyAlignment(long timestamp, DetID::mask_t addMask) const +{ + DetID::mask_t msk = getDetectorsMask() & addMask; + if (msk.none()) { + return; + } + if (!gGeoManager) { + throw std::runtime_error("Geometry is not loaded, cannot apply alignment"); + } + if (gGeoManager->IsLocked()) { + throw std::runtime_error("Geometry is locked, cannot apply alignment"); + } + + auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); + if (timestamp == 0) { + timestamp = getTimeStamp(); + } + ccdbmgr.setURL(getCCDB()); + ccdbmgr.setTimestamp(timestamp); + LOGP(INFO, "applying geometry alignment from {} for timestamp {}", getCCDB(), timestamp); + DetID::mask_t detGeoMask(gGeoManager->GetUniqueID()); + for (auto id = DetID::First; id <= DetID::Last; id++) { + if (!msk[id] || (detGeoMask.any() && !detGeoMask[id])) { + continue; + } + std::string path = o2::base::NameConf::getAlignmentPath({id}); + auto algV = ccdbmgr.get<std::vector<o2::detectors::AlignParam>>(path); + if (!algV) { + throw std::runtime_error(fmt::format("Failed to fetch alignment from {}:{}", getCCDB(), path)); + } + if (!algV->empty()) { + LOGP(INFO, "applying alignment for {}", DetID::getName(id)); + o2::base::GeometryManager::applyAlignment(*algV); + } else { + LOGP(INFO, "skipping empty alignment for {}", DetID::getName(id)); + } + } + gGeoManager->RefreshPhysicalNodes(false); +} + +long Aligner::getTimeStamp() const +{ + return mTimeStamp > 0 ? mTimeStamp : std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); +} diff --git a/Detectors/Base/src/BaseDPLDigitizer.cxx b/Detectors/Base/src/BaseDPLDigitizer.cxx index c35101d4cc650..6f6b2bc8a747d 100644 --- a/Detectors/Base/src/BaseDPLDigitizer.cxx +++ b/Detectors/Base/src/BaseDPLDigitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/src/CTFCoderBase.cxx b/Detectors/Base/src/CTFCoderBase.cxx index a5e7ff0ed92e8..90107ea7edeb5 100644 --- a/Detectors/Base/src/CTFCoderBase.cxx +++ b/Detectors/Base/src/CTFCoderBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "DetectorsCommonDataFormats/CTFHeader.h" #include "DetectorsBase/CTFCoderBase.h" +#include <filesystem> using namespace o2::ctf; @@ -34,7 +36,7 @@ bool readFromTree(TTree& tree, const std::string brname, T& dest, int ev = 0) std::unique_ptr<TFile> CTFCoderBase::loadDictionaryTreeFile(const std::string& dictPath, bool mayFail) { TDirectory* curd = gDirectory; - std::unique_ptr<TFile> fileDict(TFile::Open(dictPath.c_str())); + std::unique_ptr<TFile> fileDict(!std::filesystem::exists(dictPath) ? nullptr : TFile::Open(dictPath.c_str())); if (!fileDict || fileDict->IsZombie()) { if (mayFail) { LOG(INFO) << "CTF dictionary file " << dictPath << " for detector " << mDet.getName() << " is absent, will use dictionaries stored in CTF"; @@ -59,8 +61,15 @@ std::unique_ptr<TFile> CTFCoderBase::loadDictionaryTreeFile(const std::string& d if (!mayFail) { throw std::runtime_error("did not find CTFHeader with needed detector"); } - } else { - LOG(INFO) << "Found CTF dictionary for " << mDet.getName() << " in " << dictPath; } return fileDict; } + +void CTFCoderBase::checkDictVersion(const CTFDictHeader& h) const +{ + if (h.isValidDictTimeStamp()) { // external dictionary was used + if (h.isValidDictTimeStamp() && h != mExtHeader) { + throw std::runtime_error(fmt::format("Mismatch in {} CTF dictionary: need {}, provided {}", mDet.getName(), h.asString(), mExtHeader.asString())); + } + } +} diff --git a/Detectors/Base/src/DCAFitter.cxx b/Detectors/Base/src/DCAFitter.cxx deleted file mode 100644 index 6fd2cf12200b4..0000000000000 --- a/Detectors/Base/src/DCAFitter.cxx +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file DCAFitter.cxx -/// \brief Implementations for DCA fitter class - -#include "DetectorsBase/DCAFitter.h" - -#ifndef _ADAPT_FOR_ALIROOT_ -using namespace o2::base; -using ftype_t = DCAFitter::ftype_t; -using dtype_t = DCAFitter::dtype_t; - -#else -#include "DCAFitter.h" -#endif - -//_____________________________________________________________________________________ -void DCAFitter::CrossInfo::set(const TrcAuxPar& trc0, const TrcAuxPar& trc1) -{ - // calculate up to 2 crossings between 2 circles - nDCA = 0; - const auto& trcA = trc0.r > trc1.r ? trc0 : trc1; // designate the largest circle as A - const auto& trcB = trc0.r > trc1.r ? trc1 : trc0; - ftype_t xDist = trcB.xCen - trcA.xCen, yDist = trcB.yCen - trcA.yCen; - ftype_t dist2 = xDist * xDist + yDist * yDist, dist = TMath::Sqrt(dist2), rsum = trcA.r + trcB.r; - if (TMath::Abs(dist) < 1e-12) { - return; // circles are concentric? - } - if (dist > rsum) { // circles don't touch, chose a point in between - // the parametric equation of lines connecting the centers is - // x = x0 + t/dist * (x1-x0), y = y0 + t/dist * (y1-y0) - notTouchingXY(dist, xDist, yDist, trcA, trcB.r); - } else if (dist + trcB.r < trcA.r) { // the small circle is nestled into large one w/o touching - // select the point of closest approach of 2 circles - notTouchingXY(dist, xDist, yDist, trcA, -trcB.r); - } else { // 2 intersection points - // to simplify calculations, we move to new frame x->x+Xc0, y->y+Yc0, so that - // the 1st one is centered in origin - if (TMath::Abs(xDist) < TMath::Abs(yDist)) { - ftype_t a = (trcA.r * trcA.r - trcB.r * trcB.r + dist2) / (2. * yDist), b = -xDist / yDist, ab = a * b, bb = b * b; - ftype_t det = ab * ab - (1. + bb) * (a * a - trcA.r * trcA.r); - if (det > 0.) { - det = TMath::Sqrt(det); - xDCA[0] = (-ab + det) / (1. + b * b); - yDCA[0] = a + b * xDCA[0] + trcA.yCen; - xDCA[0] += trcA.xCen; - xDCA[1] = (-ab - det) / (1. + b * b); - yDCA[1] = a + b * xDCA[1] + trcA.yCen; - xDCA[1] += trcA.xCen; - nDCA = 2; - } else { // due to the finite precision the det<=0, i.e. the circles are barely touching, fall back to this special case - notTouchingXY(dist, xDist, yDist, trcA, trcB.r); - } - } else { - ftype_t a = (trcA.r * trcA.r - trcB.r * trcB.r + dist2) / (2. * xDist), b = -yDist / xDist, ab = a * b, bb = b * b; - ftype_t det = ab * ab - (1. + bb) * (a * a - trcA.r * trcA.r); - if (det > 0.) { - det = TMath::Sqrt(det); - yDCA[0] = (-ab + det) / (1. + bb); - xDCA[0] = a + b * yDCA[0] + trcA.xCen; - yDCA[0] += trcA.yCen; - yDCA[1] = (-ab - det) / (1. + bb); - xDCA[1] = a + b * yDCA[1] + trcA.xCen; - yDCA[1] += trcA.yCen; - nDCA = 2; - } else { // due to the finite precision the det<=0, i.e. the circles are barely touching, fall back to this special case - notTouchingXY(dist, xDist, yDist, trcA, trcB.r); - } - } - } -} - -//_____________________________________________________________________________________ -void DCAFitter::TrcAuxPar::setRCen(const Track& tr, ftype_t bz) -{ - // set track radius and circle coordinates in global frame, no check for bz==0! - r = 1. / tr.getCurvature(bz); - ftype_t sn = tr.getSnp(), cs = TMath::Sqrt((1. - sn) * (1. + sn)); - loc2glo(tr.getX() - sn * r, tr.getY() + cs * r, xCen, yCen); - r = TMath::Abs(r); -} - -//___________________________________________________________________ -int DCAFitter::process(const Track& trc0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrcAuxPar& trc1Aux) -{ - // find dca of 2 tracks with aux info preclaculated - mNCandidates = 0; - mCrossings.set(trc0Aux, trc1Aux); // find at most 2 candidates of 2 circles crossing - if (!mCrossings.nDCA) { - return 0; // no crossing - } - for (int ic = 0; ic < mCrossings.nDCA; ic++) { - // both XY crossings may eventually converge to the same point. To stop asap this redundant step - // we abandon fit if it appears to be closer to alternative crossing - mCrossIDCur = ic; - mCrossIDAlt = mCrossings.nDCA == 2 ? 1 - ic : -1; - // check if radius is acceptable - if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) { - continue; - } - // find dca starting from proximity of transverse point xv,yv - ftype_t xl, yl; - mCandTr0[mNCandidates] = trc0; - mCandTr1[mNCandidates] = trc1; - trc0Aux.glo2loc(mCrossings.xDCA[ic], mCrossings.yDCA[ic], xl, yl); - if (!mCandTr0[mNCandidates].propagateTo(xl, mBz)) { - continue; - } - trc1Aux.glo2loc(mCrossings.xDCA[ic], mCrossings.yDCA[ic], xl, yl); - if (!mCandTr1[mNCandidates].propagateTo(xl, mBz)) { - continue; - } - if (mUseAbsDCA ? processCandidateDCA(trc0Aux, trc1Aux) : processCandidateChi2(trc0Aux, trc1Aux)) { - mNCandidates++; // candidate validated - } - } - return mNCandidates; -} - -//___________________________________________________________________ -bool DCAFitter::processCandidateChi2(const TrcAuxPar& trc0Aux, const TrcAuxPar& trc1Aux) -{ - // find best chi2 (weighted DCA) of 2 tracks already propagated to their approximate vicinity - mChi2[mNCandidates] = 1e9; - Track &trc0 = mCandTr0[mNCandidates], &trc1 = mCandTr1[mNCandidates]; - TrackCovI &trcEI0 = mTrcEI0[mNCandidates], &trcEI1 = mTrcEI1[mNCandidates]; - // get error matrices at initial point - trcEI0.set(trc0); - trcEI1.set(trc1); - TrackCoefVtx &trCFVT0 = mTrCFVT0[mNCandidates], &trCFVT1 = mTrCFVT1[mNCandidates]; // get coefficients of PCA vs track points - calcPCACoefs(trc0Aux, trcEI0, trc1Aux, trcEI1, trCFVT0, trCFVT1); - TrackDeriv2 tDer0, tDer1; // their derivatives over track param X - Derivatives deriv; // chi2 1st and 2nd derivatives over tracks params - - ftype_t chi2 = 0, chi2Prev = 0; - int iter = 0; - do { - tDer0.set(trc0, mBz); // tracks derivatives - tDer1.set(trc1, mBz); // over their X params - chi2Deriv(trc0, tDer0, trc0Aux, trcEI0, trCFVT0, trc1, tDer1, trc1Aux, trcEI1, trCFVT1, deriv); - - // do Newton-Rapson iteration with corrections = - dchi2/d{x0,x1} * [ d^2chi2/d{x0,x1}^2 ]^-1 - dtype_t detDer2 = deriv.dChidx0dx0 * deriv.dChidx1dx1 - deriv.dChidx0dx1 * deriv.dChidx0dx1; - dtype_t detDer2I = 1. / detDer2; - dtype_t dX0 = -(deriv.dChidx0 * deriv.dChidx1dx1 - deriv.dChidx1 * deriv.dChidx0dx1) * detDer2I; - dtype_t dX1 = -(deriv.dChidx1 * deriv.dChidx0dx0 - deriv.dChidx0 * deriv.dChidx0dx1) * detDer2I; - if (!trc0.propagateParamTo(trc0.getX() + dX0, mBz) || !trc1.propagateParamTo(trc1.getX() + dX1, mBz)) { - return false; - } - Triplet pca; - calcPCA(trc0, trCFVT0, trc1, trCFVT1, pca); - // if there are 2 XY crossings, fit with both of them used as a starting point may converge to - // the same point. To stop asap this redundant step we abandon fit if it appears to be closer - // to alternative crossing - if (mCrossIDAlt >= 0 && closerToAlternative(pca.x, pca.y)) { - return false; - } - - chi2 = calcChi2(pca, trc0, trc0Aux, trcEI0, trc1, trc1Aux, trcEI1); - - if ((TMath::Abs(dX0) < mMinParamChange && TMath::Abs(dX1) < mMinParamChange) || - (iter && chi2 / chi2Prev > mMinRelChi2Change)) { - break; // converged - } - chi2Prev = chi2; - } while (++iter < mMaxIter); - // - if (chi2 < mMaxChi2) { - auto& pca = mPCA[mNCandidates]; - calcPCA(trc0, trCFVT0, trc1, trCFVT1, pca); - mChi2[mNCandidates] = calcChi2(pca, trc0, trc0Aux, trcEI0, trc1, trc1Aux, trcEI1); - return true; - } - return false; -} - -//___________________________________________________________________ -int DCAFitter::processAsIs(const Track& trc0, const Track& trc1) -{ - // find dca of 2 tracks w/o preliminary propagation to XY crossing points - clear(); - TrcAuxPar trc0Aux(trc0, mBz), trc1Aux(trc1, mBz); - mCandTr0[mNCandidates] = trc0; - mCandTr1[mNCandidates] = trc1; - if (mUseAbsDCA ? processCandidateDCA(trc0Aux, trc1Aux) : processCandidateChi2(trc0Aux, trc1Aux)) { - mNCandidates++; // candidate validated - } - return mNCandidates; -} - -//___________________________________________________________________ -bool DCAFitter::processCandidateDCA(const TrcAuxPar& trc0Aux, const TrcAuxPar& trc1Aux) -{ - // find DCA of 2 tracks already propagated to its approximate vicinity W/O APPLYING ANY ERRORS - // i.e. the absolute distance is minimized - Track &trc0 = mCandTr0[mNCandidates], &trc1 = mCandTr1[mNCandidates]; - - TrackDeriv2 tDer0, tDer1; // their derivatives over track param X - Derivatives deriv; // chi2 1st and 2nd derivatives over tracks params - - ftype_t chi2 = 0, chi2Prev = 0; - int iter = 0; - do { - tDer0.set(trc0, mBz); // tracks derivatives - tDer1.set(trc1, mBz); // over their X params - DCADeriv(trc0, tDer0, trc0Aux, trc1, tDer1, trc1Aux, deriv); - - // do Newton-Rapson iteration with corrections = - dchi2/d{x0,x1} * [ d^2chi2/d{x0,x1}^2 ]^-1 - dtype_t detDer2 = deriv.dChidx0dx0 * deriv.dChidx1dx1 - deriv.dChidx0dx1 * deriv.dChidx0dx1; - dtype_t detDer2I = 1. / detDer2; - dtype_t dX0 = -(deriv.dChidx0 * deriv.dChidx1dx1 - deriv.dChidx1 * deriv.dChidx0dx1) * detDer2I; - dtype_t dX1 = -(deriv.dChidx1 * deriv.dChidx0dx0 - deriv.dChidx0 * deriv.dChidx0dx1) * detDer2I; - if (!trc0.propagateParamTo(trc0.getX() + dX0, mBz) || !trc1.propagateParamTo(trc1.getX() + dX1, mBz)) { - return false; - } - - if (mCrossIDAlt >= 0) { - Triplet pca; - calcPCA(trc0, trc0Aux, trc1, trc1Aux, pca); - // if there are 2 XY crossings, fit with both of them used as a starting point may converge to - // the same point. To stop asap this redundant step we abandon fit if it appears to be closer - // to alternative crossing - if (closerToAlternative(pca.x, pca.y)) { - return false; - } - } - chi2 = calcDCA(trc0, trc0Aux, trc1, trc1Aux); - if ((TMath::Abs(dX0) < mMinParamChange && TMath::Abs(dX1) < mMinParamChange) || - (iter && chi2 / chi2Prev > mMinRelChi2Change)) { - break; // converged - } - chi2Prev = chi2; - } while (++iter < mMaxIter); - // - if (chi2 < mMaxChi2) { - auto& pca = mPCA[mNCandidates]; - calcPCA(trc0, trc0Aux, trc1, trc1Aux, pca); - mChi2[mNCandidates] = calcDCA(trc0, trc0Aux, trc1, trc1Aux); - return true; - } - return false; -} - -//___________________________________________________________________ -void DCAFitter::calcPCA(const Track& trc0, const TrackCoefVtx& trCFVT0, - const Track& trc1, const TrackCoefVtx& trCFVT1, - Triplet& pca) const -{ - // calculate the PCA (Vx,Vy,Vz) to 2 points in lab frame represented via local points coordinates - pca.x = trCFVT0.mXX * trc0.getX() + trCFVT0.mXY * trc0.getY() + trCFVT0.mXZ * trc0.getZ() + trCFVT1.mXX * trc1.getX() + trCFVT1.mXY * trc1.getY() + trCFVT1.mXZ * trc1.getZ(); - pca.y = trCFVT0.mYX * trc0.getX() + trCFVT0.mYY * trc0.getY() + trCFVT0.mYZ * trc0.getZ() + trCFVT1.mYX * trc1.getX() + trCFVT1.mYY * trc1.getY() + trCFVT1.mYZ * trc1.getZ(); - pca.z = trCFVT0.mZX * trc0.getX() + trCFVT0.mZY * trc0.getY() + trCFVT0.mZZ * trc0.getZ() + trCFVT1.mZX * trc1.getX() + trCFVT1.mZY * trc1.getY() + trCFVT1.mZZ * trc1.getZ(); -} - -//___________________________________________________________________ -void DCAFitter::calcPCA(const Track& trc0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrcAuxPar& trc1Aux, - Triplet& pca) const -{ - // calculate the PCA (Vx,Vy,Vz) to 2 points in lab frame represented via local points coordinates - // w/o accounting for the errors of the points - ftype_t xg, yg; - trc0Aux.loc2glo(trc0.getX(), trc0.getY(), xg, yg); - trc1Aux.loc2glo(trc1.getX(), trc1.getY(), pca.x, pca.y); - pca.x += xg; - pca.y += yg; - pca.z = 0.5 * (trc0.getZ() + trc1.getZ()); - pca.x *= 0.5; - pca.y *= 0.5; -} - -//___________________________________________________________________ -void DCAFitter::chi2Deriv(const Track& trc0, const TrackDeriv2& tDer0, const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, const TrackCoefVtx& trCFVT0, - const Track& trc1, const TrackDeriv2& tDer1, const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1, const TrackCoefVtx& trCFVT1, - Derivatives& deriv) const -{ - // calculate 1st and 2nd derivatives of wighted DCA (chi2) over track parameters X - Triplet vtx; - calcPCA(trc0, trCFVT0, trc1, trCFVT1, vtx); // calculate PCA for current track-points positions - // calculate residuals - auto res0 = calcResid(trc0, trc0Aux, vtx); - auto res1 = calcResid(trc1, trc1Aux, vtx); - - // res0.x,dy0,dz0 = x0 - Xl0, y0 - Yl0, ... , whith x0,y0,z0: track coords in its frame, and Xl0, Yl0, Zl0 : vertex rotated to same frame - - // aux params to minimize multiplications - ftype_t dx0s = res0.x * trcEI0.sxx; - ftype_t dy0sz0t = res0.y * trcEI0.syy + res0.z * trcEI0.syz; - ftype_t dy0tz0s = res0.y * trcEI0.syz + res0.z * trcEI0.szz; - - ftype_t dx1s = res1.x * trcEI1.sxx; - ftype_t dy1sz1t = res1.y * trcEI1.syy + res1.z * trcEI1.syz; - ftype_t dy1tz1s = res1.y * trcEI1.syz + res1.z * trcEI1.szz; - - //------------------------------- - // At the moment keep this in double. TODO: check if ftype_t is ok - dtype_t xx0DtXYXZx0 = trCFVT0.mXX + trCFVT0.mXY * tDer0.dydx + trCFVT0.mXZ * tDer0.dzdx; - dtype_t xx1DtXYXZx1 = trCFVT1.mXX + trCFVT1.mXY * tDer1.dydx + trCFVT1.mXZ * tDer1.dzdx; - dtype_t yz0DtYYYZx0 = trCFVT0.mYX + trCFVT0.mYY * tDer0.dydx + trCFVT0.mYZ * tDer0.dzdx; - dtype_t yz1DtYYYZx1 = trCFVT1.mYX + trCFVT1.mYY * tDer1.dydx + trCFVT1.mYZ * tDer1.dzdx; - - dtype_t DtXYXZx02 = trCFVT0.mXY * tDer0.d2ydx2 + trCFVT0.mXZ * tDer0.d2zdx2; - dtype_t DtYYYZx02 = trCFVT0.mYY * tDer0.d2ydx2 + trCFVT0.mYZ * tDer0.d2zdx2; - dtype_t DtXYXZx12 = trCFVT1.mXY * tDer1.d2ydx2 + trCFVT1.mXZ * tDer1.d2zdx2; - dtype_t DtYYYZx12 = trCFVT1.mYY * tDer1.d2ydx2 + trCFVT1.mYZ * tDer1.d2zdx2; - - dtype_t FDdx0Dx0 = 1. - (trc0Aux.c * xx0DtXYXZx0 + trc0Aux.s * yz0DtYYYZx0); - dtype_t FDdy0Dx0 = trc0Aux.s * xx0DtXYXZx0 - trc0Aux.c * yz0DtYYYZx0 + tDer0.dydx; - dtype_t FDdz0Dx0 = -trCFVT0.mZX - trCFVT0.mZY * tDer0.dydx + tDer0.dzdx * (1. - trCFVT0.mZZ); - - dtype_t FDdx1Dx1 = 1. - (trc1Aux.c * xx1DtXYXZx1 + trc1Aux.s * yz1DtYYYZx1); - dtype_t FDdy1Dx1 = trc1Aux.s * xx1DtXYXZx1 - trc1Aux.c * yz1DtYYYZx1 + tDer1.dydx; - dtype_t FDdz1Dx1 = -trCFVT1.mZX - trCFVT1.mZY * tDer1.dydx + tDer1.dzdx * (1. - trCFVT1.mZZ); - - dtype_t FDdx0Dx1 = -(trc0Aux.c * xx1DtXYXZx1 + trc0Aux.s * yz1DtYYYZx1); - dtype_t FDdy0Dx1 = trc0Aux.s * xx1DtXYXZx1 - trc0Aux.c * yz1DtYYYZx1; - dtype_t FDdz0Dx1 = FDdz1Dx1 - tDer1.dzdx; // -trCFVT1.mZX - trCFVT1.mZY*tDer1.dydx - trCFVT1.mZZ*tDer1.dzdx; - - dtype_t FDdx1Dx0 = -(trc1Aux.c * xx0DtXYXZx0 + trc1Aux.s * yz0DtYYYZx0); - dtype_t FDdy1Dx0 = trc1Aux.s * xx0DtXYXZx0 - trc1Aux.c * yz0DtYYYZx0; - dtype_t FDdz1Dx0 = FDdz0Dx0 - tDer0.dzdx; // -trCFVT0.mZX - trCFVT0.mZY*tDer0.dydx - trCFVT0.mZZ*tDer0.dzdx; - - dtype_t FDdx0Dx0x0 = -(trc0Aux.c * DtXYXZx02 + trc0Aux.s * DtYYYZx02); - dtype_t FDdy0Dx0x0 = tDer0.d2ydx2 + trc0Aux.s * DtXYXZx02 - trc0Aux.c * DtYYYZx02; - dtype_t FDdz0Dx0x0 = -trCFVT0.mZY * tDer0.d2ydx2 + tDer0.d2zdx2 * (1. - trCFVT0.mZZ); - - dtype_t FDdx1Dx1x1 = -(trc1Aux.c * DtXYXZx12 + trc1Aux.s * DtYYYZx12); - dtype_t FDdy1Dx1x1 = tDer1.d2ydx2 + trc1Aux.s * DtXYXZx12 - trc1Aux.c * DtYYYZx12; - dtype_t FDdz1Dx1x1 = -trCFVT1.mZY * tDer1.d2ydx2 + tDer1.d2zdx2 * (1. - trCFVT1.mZZ); - - dtype_t FDdx0Dx1x1 = -(trc0Aux.c * DtXYXZx12 + trc0Aux.s * DtYYYZx12); - dtype_t FDdx1Dx0x0 = -(trc1Aux.c * DtXYXZx02 + trc1Aux.s * DtYYYZx02); - - dtype_t FDdy1Dx0x0 = trc1Aux.s * DtXYXZx02 - trc1Aux.c * DtYYYZx02; - dtype_t FDdy0Dx1x1 = trc0Aux.s * DtXYXZx12 - trc0Aux.c * DtYYYZx12; - - dtype_t FDdz0Dx1x1 = FDdz1Dx1x1 - tDer1.d2zdx2; // -(trCFVT1.mZY*tDer1.d2ydx2 + trCFVT1.mZZ*tDer1.d2zdx2); - dtype_t FDdz1Dx0x0 = FDdz0Dx0x0 - tDer0.d2zdx2; // -(trCFVT0.mZY*tDer0.d2ydx2 + trCFVT0.mZZ*tDer0.d2zdx2); - - dtype_t FD00YYYZ = FDdy0Dx0 * trcEI0.syy + FDdz0Dx0 * trcEI0.syz; - dtype_t FD11YYYZ = FDdy1Dx1 * trcEI1.syy + FDdz1Dx1 * trcEI1.syz; - dtype_t FD10YYYZ = FDdy1Dx0 * trcEI1.syy + FDdz1Dx0 * trcEI1.syz; - dtype_t FD01YYYZ = FDdy0Dx1 * trcEI0.syy + FDdz0Dx1 * trcEI0.syz; - dtype_t FD00YZZZ = FDdy0Dx0 * trcEI0.syz + FDdz0Dx0 * trcEI0.szz; - dtype_t FD11YZZZ = FDdy1Dx1 * trcEI1.syz + FDdz1Dx1 * trcEI1.szz; - - dtype_t FD10YZZZ = FDdy1Dx0 * trcEI1.syz + FDdz1Dx0 * trcEI1.szz; - dtype_t FD01YZZZ = FDdy0Dx1 * trcEI0.syz + FDdz0Dx1 * trcEI0.szz; - - // 1st derivatives over track params x - deriv.dChidx0 = dx0s * FDdx0Dx0 + dx1s * FDdx1Dx0 + dy0sz0t * FDdy0Dx0 + dy1sz1t * FDdy1Dx0 + dy0tz0s * FDdz0Dx0 + dy1tz1s * FDdz1Dx0; - deriv.dChidx1 = dx1s * FDdx1Dx1 + dx0s * FDdx0Dx1 + dy1sz1t * FDdy1Dx1 + dy0sz0t * FDdy0Dx1 + dy1tz1s * FDdz1Dx1 + dy0tz0s * FDdz0Dx1; - - // 2nd derivative over track params x - deriv.dChidx0dx0 = dx0s * FDdx0Dx0x0 + dx1s * FDdx1Dx0x0 + FDdy0Dx0x0 * dy0sz0t + FDdy1Dx0x0 * dy1sz1t + FDdz0Dx0x0 * dy0tz0s + FDdz1Dx0x0 * dy1tz1s + - FDdx0Dx0 * FDdx0Dx0 * trcEI0.sxx + FDdx1Dx0 * FDdx1Dx0 * trcEI1.sxx + - FDdy0Dx0 * FD00YYYZ + FDdy1Dx0 * FD10YYYZ + FDdz0Dx0 * FD00YZZZ + FDdz1Dx0 * FD10YZZZ; - - deriv.dChidx1dx1 = dx1s * FDdx1Dx1x1 + dx0s * FDdx0Dx1x1 + FDdy1Dx1x1 * dy1sz1t + FDdy0Dx1x1 * dy0sz0t + FDdz1Dx1x1 * dy1tz1s + FDdz0Dx1x1 * dy0tz0s + - FDdx1Dx1 * FDdx1Dx1 * trcEI1.sxx + FDdx0Dx1 * FDdx0Dx1 * trcEI0.sxx + - FDdy1Dx1 * FD11YYYZ + FDdy0Dx1 * FD01YYYZ + FDdz1Dx1 * FD11YZZZ + FDdz0Dx1 * FD01YZZZ; - - // N.B.: cross-derivatice - // FDdx0Dx0x1 -> 0, FDdy0Dx0x1 -> 0, FDdz0Dx0x1 -> 0, FDdx1Dx1x0 -> 0; - // FDdy1Dx1x0 -> 0, FDdz1Dx1x0 -> 0, FDdx0Dx1x0 -> 0, FDdy0Dx1x0 -> 0; - // FDdz0Dx1x0 -> 0, FDdx1Dx0x1 -> 0, FDdy1Dx0x1 -> 0, FDdz1Dx0x1 -> 0; - - deriv.dChidx0dx1 = - // this part is = 0 due to the N.B. - // dx0s*FDdx0Dx0x1 + dx1s*FDdx1Dx0x1 + dy0s*FDdy0Dx0x1 + dy1s*FDdy1Dx0x1 + dz0s*FDdz0Dx0x1 + dz1s*FDdz1Dx0x1 + - // dy0t*FDdz0Dx0x1 + dy1t*FDdz1Dx0x1 +dz0t*FDdy0Dx0x1 + dz1t*FDdy1Dx0x1 + - FDdx0Dx0 * FDdx0Dx1 * trcEI0.sxx + FDdx1Dx0 * FDdx1Dx1 * trcEI1.sxx + - FDdy0Dx0 * (FDdy0Dx1 * trcEI0.syy + FDdz0Dx1 * trcEI0.syz) + - FDdy1Dx0 * (FDdy1Dx1 * trcEI1.syy + FDdz1Dx1 * trcEI1.syz) + - FDdz0Dx0 * (FDdy0Dx1 * trcEI0.syz + FDdz0Dx1 * trcEI0.szz) + - FDdz1Dx0 * (FDdy1Dx1 * trcEI1.syz + FDdz1Dx1 * trcEI1.szz); - // -} - -//___________________________________________________________________ -void DCAFitter::DCADeriv(const Track& trc0, const TrackDeriv2& tDer0, const TrcAuxPar& trc0Aux, - const Track& trc1, const TrackDeriv2& tDer1, const TrcAuxPar& trc1Aux, - Derivatives& deriv) const -{ - // DCA derivative calculation with Chi2 defined as the absolule distance (no errors applied) - ftype_t cosDA = trc0Aux.c * trc1Aux.c + trc0Aux.s * trc1Aux.s; // cos(A0-A1) - ftype_t sinDA = trc0Aux.s * trc1Aux.c - trc0Aux.c * trc1Aux.s; // sin(A0-A1) - ftype_t dx01 = trc0.getX() - (trc1.getX() * cosDA + trc1.getY() * sinDA); - ftype_t dx10 = trc1.getX() - (trc0.getX() * cosDA - trc0.getY() * sinDA); - ftype_t dy01 = trc0.getY() - (trc1.getY() * cosDA - trc1.getX() * sinDA); - ftype_t dy10 = trc1.getY() - (trc0.getY() * cosDA + trc0.getX() * sinDA); - ftype_t dz = trc0.getZ() - trc1.getZ(); - - // 1st derivatives over track params x - deriv.dChidx0 = 0.5 * (tDer0.dydx * dy01 + dx01 + dz * tDer0.dzdx); - deriv.dChidx1 = 0.5 * (tDer1.dydx * dy10 + dx10 - dz * tDer1.dzdx); - - // 2nd derivative over track params x - deriv.dChidx0dx0 = 0.5 * (1. + tDer0.dydx * tDer0.dydx + tDer0.dzdx * tDer0.dzdx + dz * tDer0.d2zdx2 + tDer0.d2ydx2 * dy01); - deriv.dChidx1dx1 = 0.5 * (1. + tDer1.dydx * tDer1.dydx + tDer1.dzdx * tDer1.dzdx - dz * tDer1.d2zdx2 + tDer1.d2ydx2 * dy10); - deriv.dChidx0dx1 = 0.5 * (sinDA * (tDer0.dydx - tDer1.dydx) - cosDA * (1. + tDer0.dydx * tDer1.dydx) - tDer0.dzdx * tDer1.dzdx); -} - -//___________________________________________________________________ -void DCAFitter::calcPCACoefs(const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, - const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1, - TrackCoefVtx& trCFVT0, TrackCoefVtx& trCFVT1) const -{ - // calculate coefficients of the PCA (Vx,Vy,Vz) to 2 points in lab frame represented via local points coordinates as - // Vx = mXX0*x0+mXY0*y0+mXZ0*z0 + mXX1*x1+mXY1*y1+mXZ1*z1 - // Vy = mYX0*x0+mYY0*y0+mYZ0*z0 + mYX1*x1+mYY1*y1+mYZ1*z1 - // Vz = mZX0*x0+mZY0*y0+mZZ0*z0 + mZX1*x1+mZY1*y1+mZZ1*z1 - // where {x0,y0,z0} and {x1,y1,z1} are track positions in their local frames - // - // we find the PCA of 2 tracks poins weighted by their errors, i.e. minimizing - // chi2 = .... - // these are the coefficients of dChi2/d{Vx,Vy,vZ} = 0 - - // At the moment keep this in dtype_t. TODO: check if ftype_t is ok - dtype_t axx = trc0Aux.cc * trcEI0.sxx + trc1Aux.cc * trcEI1.sxx + trc0Aux.ss * trcEI0.syy + trc1Aux.ss * trcEI1.syy; - dtype_t axy = trc0Aux.cs * (trcEI0.sxx - trcEI0.syy) + trc1Aux.cs * (trcEI1.sxx - trcEI1.syy); - dtype_t axz = -(trc0Aux.s * trcEI0.syz + trc1Aux.s * trcEI1.syz); - dtype_t ayy = trc0Aux.ss * trcEI0.sxx + trc1Aux.ss * trcEI1.sxx + trc0Aux.cc * trcEI0.syy + trc1Aux.cc * trcEI1.syy; // = (trcEI0.sxx + trcEI1.sxx + trcEI0.syy + trcEI1.syy) - axx - dtype_t ayz = trc0Aux.c * trcEI0.syz + trc1Aux.c * trcEI1.syz; - dtype_t azz = trcEI0.szz + trcEI1.szz; - // - // define some aux variables - dtype_t axxyy = axx * ayy, axxzz = axx * azz, axxyz = axx * ayz, - axyxy = axy * axy, axyxz = axy * axz, axyyz = axy * ayz, axyzz = axy * azz, - axzxz = axz * axz, axzyy = axz * ayy, axzyz = axz * ayz, - ayzyz = ayz * ayz, ayyzz = ayy * azz; - dtype_t dAxxyyAxyxy = axxyy - axyxy, dAxyyzAxzyy = axyyz - axzyy, dAxyxzAxxyz = axyxz - axxyz; - dtype_t dAxzyzAxyzz = axzyz - axyzz, dAyyzzAyzyz = ayyzz - ayzyz, dAxxzzAxzxz = axxzz - axzxz; - dtype_t det = -dAxyyzAxzyy * axz + dAxyxzAxxyz * ayz + dAxxyyAxyxy * azz, detI = 1. / det; - - dtype_t dfxPCS0 = dAyyzzAyzyz * trc0Aux.c + dAxzyzAxyzz * trc0Aux.s, dfxQCS0 = dAxzyzAxyzz * trc0Aux.c - dAyyzzAyzyz * trc0Aux.s; - dtype_t dfyPCS0 = dAxzyzAxyzz * trc0Aux.c + dAxxzzAxzxz * trc0Aux.s, dfyQCS0 = dAxxzzAxzxz * trc0Aux.c - dAxzyzAxyzz * trc0Aux.s; - dtype_t dfzPCS0 = dAxyyzAxzyy * trc0Aux.c + dAxyxzAxxyz * trc0Aux.s, dfzQCS0 = dAxyxzAxxyz * trc0Aux.c - dAxyyzAxzyy * trc0Aux.s; - - dtype_t dfxPCS1 = dAyyzzAyzyz * trc1Aux.c + dAxzyzAxyzz * trc1Aux.s, dfxQCS1 = dAxzyzAxyzz * trc1Aux.c - dAyyzzAyzyz * trc1Aux.s; - dtype_t dfyPCS1 = dAxzyzAxyzz * trc1Aux.c + dAxxzzAxzxz * trc1Aux.s, dfyQCS1 = dAxxzzAxzxz * trc1Aux.c - dAxzyzAxyzz * trc1Aux.s; - dtype_t dfzPCS1 = dAxyyzAxzyy * trc1Aux.c + dAxyxzAxxyz * trc1Aux.s, dfzQCS1 = dAxyxzAxxyz * trc1Aux.c - dAxyyzAxzyy * trc1Aux.s; - // - trCFVT0.mXX = detI * (dfxPCS0 * trcEI0.sxx); - trCFVT0.mXY = detI * (dfxQCS0 * trcEI0.syy + dAxyyzAxzyy * trcEI0.syz); - trCFVT0.mXZ = detI * (dfxQCS0 * trcEI0.syz + dAxyyzAxzyy * trcEI0.szz); - - trCFVT0.mYX = detI * (dfyPCS0 * trcEI0.sxx); - trCFVT0.mYY = detI * (dfyQCS0 * trcEI0.syy + dAxyxzAxxyz * trcEI0.syz); - trCFVT0.mYZ = detI * (dfyQCS0 * trcEI0.syz + dAxyxzAxxyz * trcEI0.szz); - - trCFVT0.mZX = detI * (dfzPCS0 * trcEI0.sxx); - trCFVT0.mZY = detI * (dfzQCS0 * trcEI0.syy + dAxxyyAxyxy * trcEI0.syz); - trCFVT0.mZZ = detI * (dfzQCS0 * trcEI0.syz + dAxxyyAxyxy * trcEI0.szz); - - trCFVT1.mXX = detI * (dfxPCS1 * trcEI1.sxx); - trCFVT1.mXY = detI * (dfxQCS1 * trcEI1.syy + dAxyyzAxzyy * trcEI1.syz); - trCFVT1.mXZ = detI * (dfxQCS1 * trcEI1.syz + dAxyyzAxzyy * trcEI1.szz); - - trCFVT1.mYX = detI * (dfyPCS1 * trcEI1.sxx); - trCFVT1.mYY = detI * (dfyQCS1 * trcEI1.syy + dAxyxzAxxyz * trcEI1.syz); - trCFVT1.mYZ = detI * (dfyQCS1 * trcEI1.syz + dAxyxzAxxyz * trcEI1.szz); - - trCFVT1.mZX = detI * (dfzPCS1 * trcEI1.sxx); - trCFVT1.mZY = detI * (dfzQCS1 * trcEI1.syy + dAxxyyAxyxy * trcEI1.syz); - trCFVT1.mZZ = detI * (dfzQCS1 * trcEI1.syz + dAxxyyAxyxy * trcEI1.szz); -} - -//___________________________________________________________________ -ftype_t DCAFitter::calcChi2(const Triplet& pca, - const Track& trc0, const TrcAuxPar& trc0Aux, const TrackCovI& trcEI0, - const Track& trc1, const TrcAuxPar& trc1Aux, const TrackCovI& trcEI1) const -{ - ftype_t chi2 = 0; - ftype_t xl, yl, dx, dy, dz; - trc0Aux.glo2loc(pca.x, pca.y, xl, yl); - dx = trc0.getX() - xl; - dy = trc0.getY() - yl; - dz = trc0.getZ() - pca.z; - chi2 += dx * dx * trcEI0.sxx + dy * dy * trcEI0.syy + dz * dz * trcEI0.szz + 2. * dy * dz * trcEI0.syz; - trc1Aux.glo2loc(pca.x, pca.y, xl, yl); - dx = trc1.getX() - xl; - dy = trc1.getY() - yl; - dz = trc1.getZ() - pca.z; - chi2 += dx * dx * trcEI1.sxx + dy * dy * trcEI1.syy + dz * dz * trcEI1.szz + 2. * dy * dz * trcEI1.syz; - return chi2; -} - -//___________________________________________________________________ -ftype_t DCAFitter::calcDCA(const Triplet& pca, - const Track& trc0, const TrcAuxPar& trc0Aux, const Track& trc1, const TrcAuxPar& trc1Aux) const -{ - // calculate distance (non-weighted) of closest approach of 2 points in their local frame - // (long way, see alternative getDCA w/o explicit vertex calculation) - ftype_t chi2 = 0; - ftype_t xl, yl, dx, dy, dz; - trc0Aux.glo2loc(pca.x, pca.y, xl, yl); - dx = trc0.getX() - xl; - dy = trc0.getY() - yl; - dz = trc0.getZ() - pca.z; - chi2 += dx * dx + dy * dy + dz * dz; - trc1Aux.glo2loc(pca.x, pca.y, xl, yl); - dx = trc1.getX() - xl; - dy = trc1.getY() - yl; - dz = trc1.getZ() - pca.z; - chi2 += dz * dz + dy * dy + dz * dz; - return chi2; -} - -//___________________________________________________________________ -ftype_t DCAFitter::calcDCA(const Track& trc0, const TrcAuxPar& trc0Aux, const Track& trc1, const TrcAuxPar& trc1Aux) const -{ - // calculate distance (non-weighted) of closest approach of 2 points in their local frame - ftype_t chi2 = 0; - dtype_t cosDA = trc0Aux.c * trc1Aux.c + trc0Aux.s * trc1Aux.s; // cos(A0-A1) - dtype_t sinDA = trc0Aux.s * trc1Aux.c - trc0Aux.c * trc1Aux.s; // sin(A0-A1) - dtype_t dx = trc0.getX() - trc1.getX(), dy = trc0.getY() - trc1.getY(), dz = trc0.getZ() - trc1.getZ(); - chi2 = 0.5 * (dx * dx + dy * dy + dz * dz) + (1. - cosDA) * (trc0.getX() * trc1.getX() + trc0.getY() * trc1.getY()) + - sinDA * (trc0.getY() * trc1.getX() - trc1.getY() * trc0.getX()); - - return chi2; -} - -//___________________________________________________________________ -bool DCAFitter::closerToAlternative(ftype_t x, ftype_t y) const -{ - // check if the point x,y is closer to the seeding XY point being tested or to alternative see (if any) - ftype_t dxCur = x - mCrossings.xDCA[mCrossIDCur], dyCur = y - mCrossings.yDCA[mCrossIDCur]; - ftype_t dxAlt = x - mCrossings.xDCA[mCrossIDAlt], dyAlt = y - mCrossings.yDCA[mCrossIDAlt]; - return dxCur * dxCur + dyCur * dyCur > dxAlt * dxAlt + dyAlt * dyAlt; -} - -//___________________________________________________________________ -ftype_t DCAFitter::getDistance2(const Track& trc0, const Track& trc1) -{ - // calculate un-weighted distance^2 between 2 tracks - dtype_t cosalp0 = TMath::Cos(trc0.getAlpha()), sinalp0 = TMath::Sin(trc0.getAlpha()); - dtype_t cosalp1 = TMath::Cos(trc1.getAlpha()), sinalp1 = TMath::Sin(trc1.getAlpha()); - dtype_t x0 = trc0.getX() * cosalp0 - trc0.getY() * sinalp0; - dtype_t y0 = trc0.getX() * sinalp0 + trc0.getY() * cosalp0; - dtype_t x1 = trc1.getX() * cosalp1 - trc1.getY() * sinalp1; - dtype_t y1 = trc1.getX() * sinalp1 + trc1.getY() * cosalp1; - - dtype_t dx = x0 - x1, dy = y0 - y1, dz = trc0.getZ() - trc1.getZ(); - return dx * dx + dy * dy + dz * dz; -} - -//___________________________________________________________________ -ftype_t DCAFitter::getDistance2(ftype_t x, ftype_t y, ftype_t z, const Track& trc0, const Track& trc1) -{ - // calculate un-weighted 1/2 distance^2 between 2 tracks and vertex coordinates - dtype_t cosalp0 = TMath::Cos(trc0.getAlpha()), sinalp0 = TMath::Sin(trc0.getAlpha()); - dtype_t cosalp1 = TMath::Cos(trc1.getAlpha()), sinalp1 = TMath::Sin(trc1.getAlpha()); - dtype_t x0 = trc0.getX() * cosalp0 - trc0.getY() * sinalp0; - dtype_t y0 = trc0.getX() * sinalp0 + trc0.getY() * cosalp0; - dtype_t x1 = trc1.getX() * cosalp1 - trc1.getY() * sinalp1; - dtype_t y1 = trc1.getX() * sinalp1 + trc1.getY() * cosalp1; - - dtype_t dx0 = x0 - x, dy0 = y0 - y, dz0 = trc0.getZ() - z; - dtype_t dx1 = x1 - x, dy1 = y1 - y, dz1 = trc1.getZ() - z; - return 0.5 * (dx0 * dx0 + dy0 * dy0 + dz0 * dz0 + dx1 * dx1 + dy1 * dy1 + dz1 * dz1); -} diff --git a/Detectors/Base/src/Detector.cxx b/Detectors/Base/src/Detector.cxx index cbf54e2422e0b..a41ef304273e0 100644 --- a/Detectors/Base/src/Detector.cxx +++ b/Detectors/Base/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/src/DetectorsBaseLinkDef.h b/Detectors/Base/src/DetectorsBaseLinkDef.h index 5e7edcfdc77f3..f542e0f064c3b 100644 --- a/Detectors/Base/src/DetectorsBaseLinkDef.h +++ b/Detectors/Base/src/DetectorsBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,9 @@ #pragma link C++ class o2::base::Detector + ; #pragma link C++ class o2::base::Propagator + ; +#pragma link C++ class o2::base::PropagatorF + ; +#pragma link C++ class o2::base::PropagatorImpl < double> + ; +#pragma link C++ class o2::base::PropagatorImpl < float> + ; #pragma link C++ class o2::base::GeometryManager + ; #pragma link C++ class o2::base::GeometryManager::MatBudgetExt + ; @@ -27,8 +31,9 @@ #pragma link C++ class o2::base::MatLayerCyl + ; #pragma link C++ class o2::base::MatLayerCylSet + ; -#pragma link C++ class o2::base::DCAFitter + ; - #pragma link C++ class o2::ctf::CTFCoderBase + ; +#pragma link C++ class o2::base::Aligner + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::base::Aligner> + ; + #endif diff --git a/Detectors/Base/src/GeometryManager.cxx b/Detectors/Base/src/GeometryManager.cxx index b97c6c65c2f11..0620917457125 100644 --- a/Detectors/Base/src/GeometryManager.cxx +++ b/Detectors/Base/src/GeometryManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,15 +18,15 @@ #include <TGeoMatrix.h> // for TGeoHMatrix #include <TGeoNode.h> // for TGeoNode #include <TGeoPhysicalNode.h> // for TGeoPhysicalNode, TGeoPNEntry -#include <TObjArray.h> // for TObjArray -#include <TObject.h> // for TObject #include <string> #include <cassert> #include <cstddef> // for NULL +#include <numeric> #include "DetectorsBase/GeometryManager.h" #include "DetectorsCommonDataFormats/AlignParam.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsBase/Aligner.h" using namespace o2::detectors; using namespace o2::base; @@ -118,6 +119,47 @@ Bool_t GeometryManager::getOriginalMatrixFromPath(const char* path, TGeoHMatrix& return kTRUE; } +//______________________________________________________________________ +TGeoHMatrix* GeometryManager::getMatrix(TGeoPNEntry* pne) +{ + // Get the global transformation matrix for a given PNEntry + // by quering the TGeoManager + + if (!gGeoManager || !gGeoManager->IsClosed()) { + LOG(ERROR) << "Can't get the global matrix! gGeoManager doesn't exist or it is still opened!"; + return nullptr; + } + + // if matrix already known --> return it + TGeoPhysicalNode* pnode = pne->GetPhysicalNode(); + if (pnode) { + return pnode->GetMatrix(); + } + + // otherwise calculate it from title and attach via TGeoPhysicalNode + pne->SetPhysicalNode(new TGeoPhysicalNode(pne->GetTitle())); + return pne->GetPhysicalNode()->GetMatrix(); +} + +//______________________________________________________________________ +TGeoHMatrix* GeometryManager::getMatrix(const char* symname) +{ + // Get the global transformation matrix for a given alignable volume + // identified by its symbolic name 'symname' by quering the TGeoManager + + if (!gGeoManager || !gGeoManager->IsClosed()) { + LOG(ERROR) << "No active geometry or geometry not yet closed!"; + return nullptr; + } + + TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname); + if (!pne) { + return nullptr; + } + + return getMatrix(pne); +} + //______________________________________________________________________ const char* GeometryManager::getSymbolicName(DetID detid, int sensid) { @@ -192,21 +234,31 @@ Bool_t GeometryManager::getOriginalMatrix(DetID detid, int sensid, TGeoHMatrix& } //______________________________________________________________________ -bool GeometryManager::applyAlignment(TObjArray& algParArray, bool ovlpcheck, double ovlToler) +bool GeometryManager::applyAlignment(const std::vector<const std::vector<o2::detectors::AlignParam>*> algPars) { /// misalign geometry with alignment objects from the array, optionaly check overlaps + for (auto dv : algPars) { + if (dv && !applyAlignment(*dv)) { + return false; + } + } + return true; +} - algParArray.Sort(); // sort to apply alignment in correct hierarchy +//______________________________________________________________________ +bool GeometryManager::applyAlignment(const std::vector<o2::detectors::AlignParam>& algPars) +{ + /// misalign geometry with alignment objects from the array, optionaly check overlaps + int nvols = algPars.size(); + std::vector<int> ord(nvols); + std::iota(std::begin(ord), std::end(ord), 0); // sort to apply alignment in correct hierarchy + std::sort(std::begin(ord), std::end(ord), [&algPars](int a, int b) { return algPars[a].getLevel() > algPars[b].getLevel(); }); - int nvols = algParArray.GetEntriesFast(); bool res = true; for (int i = 0; i < nvols; i++) { - AlignParam* alg = dynamic_cast<AlignParam*>(algParArray[i]); - if (alg) { - if (!alg->applyToGeometry(ovlpcheck, ovlToler)) { - res = false; - LOG(ERROR) << "Error applying alignment object for volume" << alg->getSymName(); - } + if (!algPars[ord[i]].applyToGeometry()) { + res = false; + LOG(ERROR) << "Error applying alignment object for volume" << algPars[ord[i]].getSymName(); } } return res; @@ -432,7 +484,7 @@ o2::base::MatBudget GeometryManager::meanMaterialBudget(float x0, float y0, floa } //_________________________________ -void GeometryManager::loadGeometry(std::string_view geomFileName) +void GeometryManager::loadGeometry(std::string_view geomFileName, bool applyMisalignment) { ///< load geometry from file std::string fname = o2::base::NameConf::getGeomFileName(geomFileName); @@ -444,4 +496,8 @@ void GeometryManager::loadGeometry(std::string_view geomFileName) if (!flGeom.Get(std::string(o2::base::NameConf::GEOMOBJECTNAME).c_str())) { LOG(FATAL) << "Did not find geometry named " << o2::base::NameConf::GEOMOBJECTNAME; } + if (applyMisalignment) { + auto& aligner = Aligner::Instance(); + aligner.applyAlignment(); + } } diff --git a/Detectors/Base/src/MatLayerCyl.cxx b/Detectors/Base/src/MatLayerCyl.cxx index f8705a505b334..ebd4acdea614d 100644 --- a/Detectors/Base/src/MatLayerCyl.cxx +++ b/Detectors/Base/src/MatLayerCyl.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/src/MatLayerCylSet.cxx b/Detectors/Base/src/MatLayerCylSet.cxx index 3d110766c6436..0757a5fe4fdcb 100644 --- a/Detectors/Base/src/MatLayerCylSet.cxx +++ b/Detectors/Base/src/MatLayerCylSet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/src/MaterialManager.cxx b/Detectors/Base/src/MaterialManager.cxx index 2b184635f0574..48878f2626d88 100644 --- a/Detectors/Base/src/MaterialManager.cxx +++ b/Detectors/Base/src/MaterialManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -64,7 +65,6 @@ void MaterialManager::Material(const char* modname, Int_t imat, const char* name TString uniquename = modname; uniquename.Append("_"); uniquename.Append(name); - if (TVirtualMC::GetMC()) { // Check this!!! int kmat = -1; diff --git a/Detectors/Base/src/Propagator.cxx b/Detectors/Base/src/Propagator.cxx index c9e83f16436b4..1a0eee08bbab7 100644 --- a/Detectors/Base/src/Propagator.cxx +++ b/Detectors/Base/src/Propagator.cxx @@ -1,30 +1,41 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "DetectorsBase/Propagator.h" -#include <GPUCommonLogger.h> -#include "Field/MagFieldFast.h" +#include "GPUCommonLogger.h" +#include "GPUCommonMath.h" +#include "GPUTPCGMPolynomialField.h" #include "MathUtils/Utils.h" #include "ReconstructionDataFormats/Vertex.h" using namespace o2::base; +using namespace o2::gpu; -#ifndef GPUCA_STANDALONE +#if !defined(GPUCA_GPUCODE) +#include "Field/MagFieldFast.h" // Don't use this on the GPU +#endif + +#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) #include "Field/MagneticField.h" #include "DataFormatsParameters/GRPObject.h" #include "DetectorsBase/GeometryManager.h" #include <FairRunAna.h> // eventually will get rid of it #include <TGeoGlobalMagField.h> -Propagator::Propagator() +template <typename value_T> +PropagatorImpl<value_T>::PropagatorImpl(bool uninitialized) { + if (uninitialized) { + return; + } ///< construct checking if needed components were initialized // we need the geoemtry loaded @@ -32,25 +43,27 @@ Propagator::Propagator() LOG(FATAL) << "No active geometry!"; } - o2::field::MagneticField* slowField = nullptr; - slowField = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); - if (!slowField) { + mField = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); + if (!mField) { LOG(WARNING) << "No Magnetic Field in TGeoGlobalMagField, checking legacy FairRunAna"; - slowField = dynamic_cast<o2::field::MagneticField*>(FairRunAna::Instance()->GetField()); + mField = dynamic_cast<o2::field::MagneticField*>(FairRunAna::Instance()->GetField()); } - if (!slowField) { + if (!mField) { LOG(FATAL) << "Magnetic field is not initialized!"; } - if (!slowField->getFastField()) { - slowField->AllowFastField(true); + const value_type xyz[3] = {0.}; + if (!mField->getFastField() && mField->fastFieldExists()) { + mField->AllowFastField(true); + mFieldFast = mField->getFastField(); + mFieldFast->GetBz(xyz, mBz); + } else { + mBz = mField->GetBz(xyz[0], xyz[1], xyz[2]); } - mField = slowField->getFastField(); - const float xyz[3] = {0.}; - mField->GetBz(xyz, mBz); } //____________________________________________________________ -int Propagator::initFieldFromGRP(const std::string grpFileName, std::string grpName, bool verbose) +template <typename value_T> +int PropagatorImpl<value_T>::initFieldFromGRP(const std::string grpFileName, std::string grpName, bool verbose) { /// load grp and init magnetic field if (verbose) { @@ -68,7 +81,8 @@ int Propagator::initFieldFromGRP(const std::string grpFileName, std::string grpN } //____________________________________________________________ -int Propagator::initFieldFromGRP(const o2::parameters::GRPObject* grp, bool verbose) +template <typename value_T> +int PropagatorImpl<value_T>::initFieldFromGRP(const o2::parameters::GRPObject* grp, bool verbose) { /// init mag field from GRP data and attach it to TGeoGlobalMagField @@ -82,7 +96,7 @@ int Propagator::initFieldFromGRP(const o2::parameters::GRPObject* grp, bool verb delete TGeoGlobalMagField::Instance(); } } - auto fld = o2::field::MagneticField::createFieldMap(grp->getL3Current(), grp->getDipoleCurrent()); + auto fld = o2::field::MagneticField::createFieldMap(grp->getL3Current(), grp->getDipoleCurrent(), o2::field::MagneticField::kConvLHC, grp->getFieldUniformity()); TGeoGlobalMagField::Instance()->SetField(fld); TGeoGlobalMagField::Instance()->Lock(); if (verbose) { @@ -92,12 +106,17 @@ int Propagator::initFieldFromGRP(const o2::parameters::GRPObject* grp, bool verb } return 0; } - +#elif !defined(GPUCA_GPUCODE) +template <typename value_T> +PropagatorImpl<value_T>::PropagatorImpl(bool uninitialized) +{ +} // empty dummy constructor for standalone benchmark #endif //_______________________________________________________________________ -bool Propagator::PropagateToXBxByBz(o2::track::TrackParCov& track, float xToGo, float mass, float maxSnp, float maxStep, - Propagator::MatCorrType matCorr, o2::track::TrackLTIntegral* tofInfo, int signCorr) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::PropagateToXBxByBz(TrackParCov_t& track, value_type xToGo, value_type maxSnp, value_type maxStep, + PropagatorImpl<value_T>::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const { //---------------------------------------------------------------- // @@ -105,59 +124,61 @@ bool Propagator::PropagateToXBxByBz(o2::track::TrackParCov& track, float xToGo, // taking into account all the three components of the magnetic field // and correcting for the crossed material. // - // mass - mass used in propagation - used for energy loss correction (if <0 then q=2) // maxStep - maximal step for propagation // tofInfo - optional container for track length and PID-dependent TOF integration // // matCorr - material correction type, it is up to the user to make sure the pointer is attached (if LUT is requested) //---------------------------------------------------------------- - const float Epsilon = 0.00001; + const value_type Epsilon = 0.00001; auto dx = xToGo - track.getX(); int dir = dx > 0.f ? 1 : -1; if (!signCorr) { signCorr = -dir; // sign of eloss correction is not imposed } - std::array<float, 3> b; - while (std::abs(dx) > Epsilon) { - auto step = std::min(std::abs(dx), maxStep); + gpu::gpustd::array<value_type, 3> b; + while (math_utils::detail::abs<value_type>(dx) > Epsilon) { + auto step = math_utils::detail::min<value_type>(math_utils::detail::abs<value_type>(dx), maxStep); if (dir < 0) { step = -step; } auto x = track.getX() + step; auto xyz0 = track.getXYZGlo(); - mField->Field(xyz0, b.data()); + getFieldXYZ(xyz0, &b[0]); if (!track.propagateTo(x, b)) { return false; } - if (maxSnp > 0 && std::abs(track.getSnp()) >= maxSnp) { + if (maxSnp > 0 && math_utils::detail::abs<value_type>(track.getSnp()) >= maxSnp) { return false; } if (matCorr != MatCorrType::USEMatCorrNONE) { auto xyz1 = track.getXYZGlo(); auto mb = getMatBudget(matCorr, xyz0, xyz1); - if (!track.correctForMaterial(mb.meanX2X0, ((signCorr < 0) ? -mb.length : mb.length) * mb.meanRho, mass)) { + if (!track.correctForMaterial(mb.meanX2X0, mb.getXRho(signCorr))) { return false; } if (tofInfo) { - tofInfo->addStep(mb.length, track); // fill L,ToF info using already calculated step length + tofInfo->addStep(mb.length, track.getP2Inv()); // fill L,ToF info using already calculated step length tofInfo->addX2X0(mb.meanX2X0); + tofInfo->addXRho(mb.getXRho(signCorr)); } } else if (tofInfo) { // if tofInfo filling was requested w/o material correction, we need to calculate the step lenght auto xyz1 = track.getXYZGlo(); - math_utils::Vector3D<float> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); - tofInfo->addStep(stepV.R(), track); + math_utils::Vector3D<value_type> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), track.getP2Inv()); } dx = xToGo - track.getX(); } + track.setX(xToGo); return true; } //_______________________________________________________________________ -bool Propagator::PropagateToXBxByBz(o2::track::TrackPar& track, float xToGo, float mass, float maxSnp, float maxStep, - Propagator::MatCorrType matCorr, o2::track::TrackLTIntegral* tofInfo, int signCorr) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::PropagateToXBxByBz(TrackPar_t& track, value_type xToGo, value_type maxSnp, value_type maxStep, + PropagatorImpl<value_T>::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const { //---------------------------------------------------------------- // @@ -165,58 +186,59 @@ bool Propagator::PropagateToXBxByBz(o2::track::TrackPar& track, float xToGo, flo // taking into account all the three components of the magnetic field // and optionally correcting for the e.loss crossed material. // - // mass - mass used in propagation - used for energy loss correction (if <0 then q=2) // maxStep - maximal step for propagation // tofInfo - optional container for track length and PID-dependent TOF integration // // matCorr - material correction type, it is up to the user to make sure the pointer is attached (if LUT is requested) //---------------------------------------------------------------- - const float Epsilon = 0.00001; + const value_type Epsilon = 0.00001; auto dx = xToGo - track.getX(); int dir = dx > 0.f ? 1 : -1; if (!signCorr) { signCorr = -dir; // sign of eloss correction is not imposed } - std::array<float, 3> b; - while (std::abs(dx) > Epsilon) { - auto step = std::min(std::abs(dx), maxStep); + gpu::gpustd::array<value_type, 3> b; + while (math_utils::detail::abs<value_type>(dx) > Epsilon) { + auto step = math_utils::detail::min<value_type>(math_utils::detail::abs<value_type>(dx), maxStep); if (dir < 0) { step = -step; } auto x = track.getX() + step; auto xyz0 = track.getXYZGlo(); - mField->Field(xyz0, b.data()); + getFieldXYZ(xyz0, &b[0]); if (!track.propagateParamTo(x, b)) { return false; } - if (maxSnp > 0 && std::abs(track.getSnp()) >= maxSnp) { + if (maxSnp > 0 && math_utils::detail::abs<value_type>(track.getSnp()) >= maxSnp) { return false; } if (matCorr != MatCorrType::USEMatCorrNONE) { auto xyz1 = track.getXYZGlo(); auto mb = getMatBudget(matCorr, xyz0, xyz1); - if (!track.correctForELoss(((signCorr < 0) ? -mb.length : mb.length) * mb.meanRho, mass)) { + if (!track.correctForELoss(((signCorr < 0) ? -mb.length : mb.length) * mb.meanRho)) { return false; } if (tofInfo) { - tofInfo->addStep(mb.length, track); // fill L,ToF info using already calculated step length + tofInfo->addStep(mb.length, track.getP2Inv()); // fill L,ToF info using already calculated step length tofInfo->addX2X0(mb.meanX2X0); } } else if (tofInfo) { // if tofInfo filling was requested w/o material correction, we need to calculate the step lenght auto xyz1 = track.getXYZGlo(); - math_utils::Vector3D<float> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); - tofInfo->addStep(stepV.R(), track); + math_utils::Vector3D<value_type> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), track.getP2Inv()); } dx = xToGo - track.getX(); } + track.setX(xToGo); return true; } //_______________________________________________________________________ -bool Propagator::propagateToX(o2::track::TrackParCov& track, float xToGo, float bZ, float mass, float maxSnp, float maxStep, - Propagator::MatCorrType matCorr, o2::track::TrackLTIntegral* tofInfo, int signCorr) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToX(TrackParCov_t& track, value_type xToGo, value_type bZ, value_type maxSnp, value_type maxStep, + PropagatorImpl<value_T>::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const { //---------------------------------------------------------------- // @@ -224,21 +246,20 @@ bool Propagator::propagateToX(o2::track::TrackParCov& track, float xToGo, float // taking into account all the three components of the magnetic field // and correcting for the crossed material. // - // mass - mass used in propagation - used for energy loss correction (if <0 then q=2) // maxStep - maximal step for propagation // tofInfo - optional container for track length and PID-dependent TOF integration // // matCorr - material correction type, it is up to the user to make sure the pointer is attached (if LUT is requested) //---------------------------------------------------------------- - const float Epsilon = 0.00001; + const value_type Epsilon = 0.00001; auto dx = xToGo - track.getX(); int dir = dx > 0.f ? 1 : -1; if (!signCorr) { signCorr = -dir; // sign of eloss correction is not imposed } - while (std::abs(dx) > Epsilon) { - auto step = std::min(std::abs(dx), maxStep); + while (math_utils::detail::abs<value_type>(dx) > Epsilon) { + auto step = math_utils::detail::min<value_type>(math_utils::detail::abs<value_type>(dx), maxStep); if (dir < 0) { step = -step; } @@ -248,34 +269,36 @@ bool Propagator::propagateToX(o2::track::TrackParCov& track, float xToGo, float if (!track.propagateTo(x, bZ)) { return false; } - if (maxSnp > 0 && std::abs(track.getSnp()) >= maxSnp) { + if (maxSnp > 0 && math_utils::detail::abs<value_type>(track.getSnp()) >= maxSnp) { return false; } if (matCorr != MatCorrType::USEMatCorrNONE) { auto xyz1 = track.getXYZGlo(); auto mb = getMatBudget(matCorr, xyz0, xyz1); // - if (!track.correctForMaterial(mb.meanX2X0, ((signCorr < 0) ? -mb.length : mb.length) * mb.meanRho, mass)) { + if (!track.correctForMaterial(mb.meanX2X0, mb.getXRho(signCorr))) { return false; } if (tofInfo) { - tofInfo->addStep(mb.length, track); // fill L,ToF info using already calculated step length + tofInfo->addStep(mb.length, track.getP2Inv()); // fill L,ToF info using already calculated step length tofInfo->addX2X0(mb.meanX2X0); } } else if (tofInfo) { // if tofInfo filling was requested w/o material correction, we need to calculate the step lenght auto xyz1 = track.getXYZGlo(); - math_utils::Vector3D<float> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); - tofInfo->addStep(stepV.R(), track); + math_utils::Vector3D<value_type> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), track.getP2Inv()); } dx = xToGo - track.getX(); } + track.setX(xToGo); return true; } //_______________________________________________________________________ -bool Propagator::propagateToX(o2::track::TrackPar& track, float xToGo, float bZ, float mass, float maxSnp, float maxStep, - Propagator::MatCorrType matCorr, o2::track::TrackLTIntegral* tofInfo, int signCorr) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToX(TrackPar_t& track, value_type xToGo, value_type bZ, value_type maxSnp, value_type maxStep, + PropagatorImpl<value_T>::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const { //---------------------------------------------------------------- // @@ -283,21 +306,20 @@ bool Propagator::propagateToX(o2::track::TrackPar& track, float xToGo, float bZ, // taking into account all the three components of the magnetic field // and correcting for the crossed material. // - // mass - mass used in propagation - used for energy loss correction (if <0 then q=2) // maxStep - maximal step for propagation // tofInfo - optional container for track length and PID-dependent TOF integration // // matCorr - material correction type, it is up to the user to make sure the pointer is attached (if LUT is requested) //---------------------------------------------------------------- - const float Epsilon = 0.00001; + const value_type Epsilon = 0.00001; auto dx = xToGo - track.getX(); int dir = dx > 0.f ? 1 : -1; if (!signCorr) { signCorr = -dir; // sign of eloss correction is not imposed } - while (std::abs(dx) > Epsilon) { - auto step = std::min(std::abs(dx), maxStep); + while (math_utils::detail::abs<value_type>(dx) > Epsilon) { + auto step = math_utils::detail::min<value_type>(math_utils::detail::abs<value_type>(dx), maxStep); if (dir < 0) { step = -step; } @@ -307,69 +329,74 @@ bool Propagator::propagateToX(o2::track::TrackPar& track, float xToGo, float bZ, if (!track.propagateParamTo(x, bZ)) { return false; } - if (maxSnp > 0 && std::abs(track.getSnp()) >= maxSnp) { + if (maxSnp > 0 && math_utils::detail::abs<value_type>(track.getSnp()) >= maxSnp) { return false; } if (matCorr != MatCorrType::USEMatCorrNONE) { auto xyz1 = track.getXYZGlo(); auto mb = getMatBudget(matCorr, xyz0, xyz1); // - if (!track.correctForELoss(((signCorr < 0) ? -mb.length : mb.length) * mb.meanRho, mass)) { + if (!track.correctForELoss(mb.getXRho(signCorr))) { return false; } if (tofInfo) { - tofInfo->addStep(mb.length, track); // fill L,ToF info using already calculated step length + tofInfo->addStep(mb.length, track.getP2Inv()); // fill L,ToF info using already calculated step length tofInfo->addX2X0(mb.meanX2X0); } } else if (tofInfo) { // if tofInfo filling was requested w/o material correction, we need to calculate the step lenght auto xyz1 = track.getXYZGlo(); - math_utils::Vector3D<float> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); - tofInfo->addStep(stepV.R(), track); + math_utils::Vector3D<value_type> stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), track.getP2Inv()); } dx = xToGo - track.getX(); } + track.setX(xToGo); return true; } //_______________________________________________________________________ -bool Propagator::propagateToDCA(const o2::dataformats::VertexBase& vtx, o2::track::TrackParCov& track, float bZ, - float mass, float maxStep, Propagator::MatCorrType matCorr, - o2::dataformats::DCA* dca, o2::track::TrackLTIntegral* tofInfo, - int signCorr, float maxD) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToDCA(const o2::dataformats::VertexBase& vtx, TrackParCov_t& track, value_type bZ, + value_type maxStep, PropagatorImpl<value_type>::MatCorrType matCorr, + o2::dataformats::DCA* dca, track::TrackLTIntegral* tofInfo, + int signCorr, value_type maxD) const { // propagate track to DCA to the vertex - float sn, cs, alp = track.getAlpha(); - o2::math_utils::sincos(alp, sn, cs); - float x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); - float xv = vtx.getX() * cs + vtx.getY() * sn, yv = -vtx.getX() * sn + vtx.getY() * cs, zv = vtx.getZ(); + value_type sn, cs, alp = track.getAlpha(); + math_utils::detail::sincos<value_type>(alp, sn, cs); + value_type x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = math_utils::detail::sqrt<value_type>((1.f - snp) * (1.f + snp)); + value_type xv = vtx.getX() * cs + vtx.getY() * sn, yv = -vtx.getX() * sn + vtx.getY() * cs, zv = vtx.getZ(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_type d = math_utils::detail::abs<value_type>(x * snp - y * csp); if (d > maxD) { return false; } - float crv = track.getCurvature(bZ); - float tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1. - sn) * (1. + sn)); - cs = (std::abs(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; + value_type crv = track.getCurvature(bZ); + value_type tgfv = -(crv * x - snp) / (crv * y + csp); + sn = tgfv / math_utils::detail::sqrt<value_type>(1.f + tgfv * tgfv); + cs = math_utils::detail::sqrt<value_type>((1. - sn) * (1. + sn)); + cs = (math_utils::detail::abs<value_type>(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(track); // operate on the copy to recover after the failure - alp += std::asin(sn); - if (!tmpT.rotate(alp) || !propagateToX(tmpT, xv, bZ, mass, 0.85, maxStep, matCorr, tofInfo, signCorr)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: "; - tmpT.print(); + alp += math_utils::detail::asin<value_type>(sn); + if (!tmpT.rotate(alp) || !propagateToX(tmpT, xv, bZ, 0.85, maxStep, matCorr, tofInfo, signCorr)) { +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx; +#endif return false; } track = tmpT; if (dca) { - o2::math_utils::sincos(alp, sn, cs); + math_utils::detail::sincos<value_type>(alp, sn, cs); auto s2ylocvtx = vtx.getSigmaX2() * sn * sn + vtx.getSigmaY2() * cs * cs - 2. * vtx.getSigmaXY() * cs * sn; dca->set(track.getY() - yv, track.getZ() - zv, track.getSigmaY2() + s2ylocvtx, track.getSigmaZY(), track.getSigmaZ2() + vtx.getSigmaZ2()); @@ -378,43 +405,47 @@ bool Propagator::propagateToDCA(const o2::dataformats::VertexBase& vtx, o2::trac } //_______________________________________________________________________ -bool Propagator::propagateToDCABxByBz(const o2::dataformats::VertexBase& vtx, o2::track::TrackParCov& track, - float mass, float maxStep, Propagator::MatCorrType matCorr, - o2::dataformats::DCA* dca, o2::track::TrackLTIntegral* tofInfo, - int signCorr, float maxD) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToDCABxByBz(const o2::dataformats::VertexBase& vtx, TrackParCov_t& track, + value_type maxStep, PropagatorImpl<value_type>::MatCorrType matCorr, + o2::dataformats::DCA* dca, track::TrackLTIntegral* tofInfo, + int signCorr, value_type maxD) const { // propagate track to DCA to the vertex - float sn, cs, alp = track.getAlpha(); - o2::math_utils::sincos(alp, sn, cs); - float x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); - float xv = vtx.getX() * cs + vtx.getY() * sn, yv = -vtx.getX() * sn + vtx.getY() * cs, zv = vtx.getZ(); + value_type sn, cs, alp = track.getAlpha(); + math_utils::detail::sincos<value_type>(alp, sn, cs); + value_type x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = math_utils::detail::sqrt<value_type>((1.f - snp) * (1.f + snp)); + value_type xv = vtx.getX() * cs + vtx.getY() * sn, yv = -vtx.getX() * sn + vtx.getY() * cs, zv = vtx.getZ(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_type d = math_utils::detail::abs<value_type>(x * snp - y * csp); if (d > maxD) { return false; } - float crv = track.getCurvature(mBz); - float tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1. - sn) * (1. + sn)); - cs = (std::abs(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; + value_type crv = track.getCurvature(mBz); + value_type tgfv = -(crv * x - snp) / (crv * y + csp); + sn = tgfv / math_utils::detail::sqrt<value_type>(1.f + tgfv * tgfv); + cs = math_utils::detail::sqrt<value_type>((1. - sn) * (1. + sn)); + cs = (math_utils::detail::abs<value_type>(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(track); // operate on the copy to recover after the failure - alp += std::asin(sn); - if (!tmpT.rotate(alp) || !PropagateToXBxByBz(tmpT, xv, mass, 0.85, maxStep, matCorr, tofInfo, signCorr)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: "; - tmpT.print(); + alp += math_utils::detail::asin<value_type>(sn); + if (!tmpT.rotate(alp) || !PropagateToXBxByBz(tmpT, xv, 0.85, maxStep, matCorr, tofInfo, signCorr)) { +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx; +#endif return false; } track = tmpT; if (dca) { - o2::math_utils::sincos(alp, sn, cs); + math_utils::detail::sincos<value_type>(alp, sn, cs); auto s2ylocvtx = vtx.getSigmaX2() * sn * sn + vtx.getSigmaY2() * cs * cs - 2. * vtx.getSigmaXY() * cs * sn; dca->set(track.getY() - yv, track.getZ() - zv, track.getSigmaY2() + s2ylocvtx, track.getSigmaZY(), track.getSigmaZ2() + vtx.getSigmaZ2()); @@ -423,39 +454,43 @@ bool Propagator::propagateToDCABxByBz(const o2::dataformats::VertexBase& vtx, o2 } //_______________________________________________________________________ -bool Propagator::propagateToDCA(const math_utils::Point3D<float>& vtx, o2::track::TrackPar& track, float bZ, - float mass, float maxStep, Propagator::MatCorrType matCorr, - std::array<float, 2>* dca, o2::track::TrackLTIntegral* tofInfo, - int signCorr, float maxD) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToDCA(const math_utils::Point3D<value_type>& vtx, TrackPar_t& track, value_type bZ, + value_type maxStep, PropagatorImpl<value_T>::MatCorrType matCorr, + gpu::gpustd::array<value_type, 2>* dca, track::TrackLTIntegral* tofInfo, + int signCorr, value_type maxD) const { // propagate track to DCA to the vertex - float sn, cs, alp = track.getAlpha(); - o2::math_utils::sincos(alp, sn, cs); - float x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); - float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z(); + value_type sn, cs, alp = track.getAlpha(); + math_utils::detail::sincos<value_type>(alp, sn, cs); + value_type x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = math_utils::detail::sqrt<value_type>((1.f - snp) * (1.f + snp)); + value_type xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_type d = math_utils::detail::abs<value_type>(x * snp - y * csp); if (d > maxD) { return false; } - float crv = track.getCurvature(bZ); - float tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1. - sn) * (1. + sn)); - cs = (std::abs(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; + value_type crv = track.getCurvature(bZ); + value_type tgfv = -(crv * x - snp) / (crv * y + csp); + sn = tgfv / math_utils::detail::sqrt<value_type>(1.f + tgfv * tgfv); + cs = math_utils::detail::sqrt<value_type>((1. - sn) * (1. + sn)); + cs = (math_utils::detail::abs<value_type>(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(track); // operate on the copy to recover after the failure - alp += std::asin(sn); - if (!tmpT.rotateParam(alp) || !propagateToX(tmpT, xv, bZ, mass, 0.85, maxStep, matCorr, tofInfo, signCorr)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " - << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: "; - tmpT.printParam(); + alp += math_utils::detail::asin<value_type>(sn); + if (!tmpT.rotateParam(alp) || !propagateToX(tmpT, xv, bZ, 0.85, maxStep, matCorr, tofInfo, signCorr)) { +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " + << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z(); +#endif return false; } track = tmpT; @@ -467,39 +502,43 @@ bool Propagator::propagateToDCA(const math_utils::Point3D<float>& vtx, o2::track } //_______________________________________________________________________ -bool Propagator::propagateToDCABxByBz(const math_utils::Point3D<float>& vtx, o2::track::TrackPar& track, - float mass, float maxStep, Propagator::MatCorrType matCorr, - std::array<float, 2>* dca, o2::track::TrackLTIntegral* tofInfo, - int signCorr, float maxD) const +template <typename value_T> +GPUd() bool PropagatorImpl<value_T>::propagateToDCABxByBz(const math_utils::Point3D<value_type>& vtx, TrackPar_t& track, + value_type maxStep, PropagatorImpl<value_T>::MatCorrType matCorr, + gpu::gpustd::array<value_type, 2>* dca, track::TrackLTIntegral* tofInfo, + int signCorr, value_type maxD) const { // propagate track to DCA to the vertex - float sn, cs, alp = track.getAlpha(); - o2::math_utils::sincos(alp, sn, cs); - float x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = std::sqrt((1.f - snp) * (1.f + snp)); - float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z(); + value_type sn, cs, alp = track.getAlpha(); + math_utils::detail::sincos<value_type>(alp, sn, cs); + value_type x = track.getX(), y = track.getY(), snp = track.getSnp(), csp = math_utils::detail::sqrt<value_type>((1.f - snp) * (1.f + snp)); + value_type xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z(); x -= xv; y -= yv; //Estimate the impact parameter neglecting the track curvature - Double_t d = std::abs(x * snp - y * csp); + value_type d = math_utils::detail::abs<value_type>(x * snp - y * csp); if (d > maxD) { return false; } - float crv = track.getCurvature(mBz); - float tgfv = -(crv * x - snp) / (crv * y + csp); - sn = tgfv / std::sqrt(1.f + tgfv * tgfv); - cs = std::sqrt((1. - sn) * (1. + sn)); - cs = (std::abs(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; + value_type crv = track.getCurvature(mBz); + value_type tgfv = -(crv * x - snp) / (crv * y + csp); + sn = tgfv / math_utils::detail::sqrt<value_type>(1.f + tgfv * tgfv); + cs = math_utils::detail::sqrt<value_type>((1. - sn) * (1. + sn)); + cs = (math_utils::detail::abs<value_type>(tgfv) > o2::constants::math::Almost0) ? sn / tgfv : o2::constants::math::Almost1; x = xv * cs + yv * sn; yv = -xv * sn + yv * cs; xv = x; auto tmpT(track); // operate on the copy to recover after the failure - alp += std::asin(sn); - if (!tmpT.rotateParam(alp) || !PropagateToXBxByBz(tmpT, xv, mass, 0.85, maxStep, matCorr, tofInfo, signCorr)) { - LOG(WARNING) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " - << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: "; - tmpT.printParam(); + alp += math_utils::detail::asin<value_type>(sn); + if (!tmpT.rotateParam(alp) || !PropagateToXBxByBz(tmpT, xv, 0.85, maxStep, matCorr, tofInfo, signCorr)) { +#ifndef GPUCA_ALIGPUCODE + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " + << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: " << tmpT.asString(); +#else + LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z(); +#endif return false; } track = tmpT; @@ -511,12 +550,101 @@ bool Propagator::propagateToDCABxByBz(const math_utils::Point3D<float>& vtx, o2: } //____________________________________________________________ -MatBudget Propagator::getMatBudget(Propagator::MatCorrType corrType, const math_utils::Point3D<float>& p0, const math_utils::Point3D<float>& p1) const +template <typename value_T> +GPUd() void PropagatorImpl<value_T>::estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization<value_type>& trc) const { -#ifndef GPUCA_STANDALONE - if (corrType == MatCorrType::USEMatCorrTGeo) { + value_T xdca = 0., ydca = 0., length = 0.; // , zdca = 0. // zdca might be used in future + if (math_utils::detail::abs<value_T>(mBz) > 1e-3) { // helix + o2::math_utils::CircleXY<value_T> c; + trc.getCircleParamsLoc(mBz, c); + auto distC = math_utils::detail::sqrt<value_type>(c.getCenterD2()); // distance from the circle center to origin + if (distC > 1.e-3) { + auto nrm = (distC - c.rC) / distC; + xdca = nrm * c.xC; // coordinates of the DCA to 0,0 in the local frame + ydca = nrm * c.yC; + auto v0x = trc.getX() - c.xC, v0y = trc.getY() - c.yC, v1x = xdca - c.xC, v1y = ydca - c.yC; + auto ang = math_utils::detail::acos<value_type>((v0x * v1x + v0y * v1y) / (c.rC * c.rC)); + if ((trc.getSign() > 0.f) == (mBz > 0.f)) { + ang = -ang; // we need signeg angle + c.rC = -c.rC; // we need signed curvature for zdca + } + // zdca = trc.getZ() + (trc.getSign() > 0. ? c.rC : -c.rC) * trc.getTgl() * ang; + length = math_utils::detail::abs<value_type>(c.rC * ang * math_utils::detail::sqrt<value_type>(1. + trc.getTgl() * trc.getTgl())); + } + } else { // straight line + auto csp2 = (1.f - trc.getSnp()) * (1.f + trc.getSnp()), csp = math_utils::detail::sqrt<value_type>(csp2); + auto tgp = trc.getSnp() / csp, f = trc.getX() * tgp - trc.getY(); + xdca = tgp * f * csp2; + ydca = -f * csp2; + auto dx = xdca - trc.getX(), dy = ydca - trc.getY(), dz = dx * trc.getTgl() / csp; + // zdca = trc.getZ() + dz; + length = math_utils::detail::sqrt<value_type>(dx * dx + dy * dy + dz * dz); + } + // since we assume the track or its parent comes from the beam-line or decay, add XY(?) distance to it + length += math_utils::detail::sqrt<value_type>(xdca * xdca + ydca * ydca); + lt.addStep(length, trc.getP2Inv()); +} + +//____________________________________________________________ +template <typename value_T> +GPUd() MatBudget PropagatorImpl<value_T>::getMatBudget(PropagatorImpl<value_type>::MatCorrType corrType, const math_utils::Point3D<value_type>& p0, const math_utils::Point3D<value_type>& p1) const +{ +#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) + if (corrType == MatCorrType::USEMatCorrTGeo || !mMatLUT) { return GeometryManager::meanMaterialBudget(p0, p1); } #endif return mMatLUT->getMatBudget(p0.X(), p0.Y(), p0.Z(), p1.X(), p1.Y(), p1.Z()); } + +template <typename value_T> +template <typename T> +GPUd() void PropagatorImpl<value_T>::getFieldXYZImpl(const math_utils::Point3D<T> xyz, T* bxyz) const +{ + if (mGPUField) { +#if defined(GPUCA_GPUCODE_DEVICE) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) + const auto* f = &GPUCA_CONSMEM.param.polynomialField; // Access directly from constant memory on GPU (copied here to avoid complicated header dependencies) +#else + const auto* f = mGPUField; +#endif + float bxyzF[3]; + f->GetField(xyz.X(), xyz.Y(), xyz.Z(), bxyzF); + //copy and convert + for (uint i = 0; i < 3; ++i) { + bxyz[i] = static_cast<value_type>(bxyzF[i]); + } + + } else { +#ifndef GPUCA_GPUCODE + if (mFieldFast) { + mFieldFast->Field(xyz, bxyz); // Must not call the host-only function in GPU compilation + } else { +#ifdef GPUCA_STANDALONE + LOG(FATAL) << "Normal field cannot be used in standalone benchmark"; +#else + mField->field(xyz, bxyz); +#endif + } +#endif + } +} + +template <typename value_T> +GPUd() void PropagatorImpl<value_T>::getFieldXYZ(const math_utils::Point3D<float> xyz, float* bxyz) const +{ + getFieldXYZImpl<float>(xyz, bxyz); +} + +template <typename value_T> +GPUd() void PropagatorImpl<value_T>::getFieldXYZ(const math_utils::Point3D<double> xyz, double* bxyz) const +{ + getFieldXYZImpl<double>(xyz, bxyz); +} + +namespace o2::base +{ +template class PropagatorImpl<float>; +#ifndef GPUCA_GPUCODE_DEVICE +template class PropagatorImpl<double>; +#endif +} // namespace o2::base diff --git a/Detectors/Base/src/Ray.cxx b/Detectors/Base/src/Ray.cxx index 1fede46d3be26..c4cdbcb88fb06 100644 --- a/Detectors/Base/src/Ray.cxx +++ b/Detectors/Base/src/Ray.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/test/buildMatBudLUT.C b/Detectors/Base/test/buildMatBudLUT.C index b0f0d0d2ac2b3..097176497c17f 100644 --- a/Detectors/Base/test/buildMatBudLUT.C +++ b/Detectors/Base/test/buildMatBudLUT.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/test/testDCAFitter.cxx b/Detectors/Base/test/testDCAFitter.cxx index 1ad9cdc61b881..60e0f08f4a5a1 100644 --- a/Detectors/Base/test/testDCAFitter.cxx +++ b/Detectors/Base/test/testDCAFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Base/test/testMatBudLUT.cxx b/Detectors/Base/test/testMatBudLUT.cxx index 289dc84f5bc26..d332422035cd6 100644 --- a/Detectors/Base/test/testMatBudLUT.cxx +++ b/Detectors/Base/test/testMatBudLUT.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CMakeLists.txt b/Detectors/CMakeLists.txt index e15b6fefa0c04..6ebd1ff4639d2 100644 --- a/Detectors/CMakeLists.txt +++ b/Detectors/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Base) add_subdirectory(Raw) @@ -14,6 +15,7 @@ add_subdirectory(CTF) add_subdirectory(Passive) # must be first as some detector's macros use it +add_subdirectory(CTP) add_subdirectory(PHOS) add_subdirectory(CPV) add_subdirectory(EMCAL) @@ -32,11 +34,15 @@ add_subdirectory(TPC) add_subdirectory(GlobalTracking) add_subdirectory(GlobalTrackingWorkflow) add_subdirectory(Vertexing) +if(BUILD_ANALYSIS) add_subdirectory(AOD) +endif() add_subdirectory(Calibration) add_subdirectory(DCS) +add_subdirectory(Align) + if(BUILD_SIMULATION) add_subdirectory(gconfig) o2_data_file(COPY gconfig DESTINATION Detectors) diff --git a/Detectors/CPV/CMakeLists.txt b/Detectors/CPV/CMakeLists.txt index 1a5260de68324..72cfdf2ef2b9c 100644 --- a/Detectors/CPV/CMakeLists.txt +++ b/Detectors/CPV/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(calib) diff --git a/Detectors/CPV/README.md b/Detectors/CPV/README.md new file mode 100644 index 0000000000000..b38ae97e6078b --- /dev/null +++ b/Detectors/CPV/README.md @@ -0,0 +1,108 @@ +<!-- doxy +\page refDetectorsCPV CPV +/doxy --> + +# CPV + +CPV stands for Charged Particles Veto detector which actually is pad chamber with cathode pad readout. +There are 3 CPV modules. Each module seats on top of PHOS modules M2, M3 and M4, so the numeration of CPV modules is naturally same: M2, M3, M4. +Each module has 128 x 60 = 7680 channels. +It is triggered detector and is using CRU (Common Readout Unit) for readout in LHC Run3. +More details can be found [here](https://twiki.cern.ch/twiki/bin/viewauth/ALICE/CPV). + +## Readout +CPV readout is organized in 3 GBT links, all connected to single CRU card on single FLP. +Triggered events are packed within each HeartBeatFrame. More info about data format can be found [here](https://twiki.cern.ch/twiki/pub/ALICE/CPV/cpv_data_format.pdf). + +## Reconstruction +The reconstruction is steered via [o2-cpv-reco-workflow](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx) executable. +#### 1. Raw to digits +It starts directly on FLP. Raw data is provided to [RawToDigitConverter](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/workflow/src/RawToDigitConverterSpec.cxx) + which converts raw format to cpv [digits](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h) and [trigger records](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/TriggerRecord.h). +Digits are calibrated objects: RawToDigitConverter reads + [pedestals](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/Pedestals.h), + [bad channel map](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/BadChannelMap.h) + and [gain](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/CalibParams.h) + calibration objects from CCDB, then it excludes bad channels, subtracts pedestals from raw amplitudes, +and result is multiplied by gain calibration coefficient forming the digit which keeps calibrated signal and its channel address. +Trigger records are objects which are keeping a reference to digits belonging to same event. To start conversion of raw data to digits run following command: +```shell +o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --disable-root-output +``` +If there is no need to calibrate digits, add `--pedestal` flag to `o2-cpv-reco-workflow` then digit signal will be equal to raw amplitude. Such mode is used for pedestal calibration (see below). +If you want to redirect stream of digits to root file then remove `--disable-root-output`. +If you want to process MC and you need digits to be labeled according to corresponding primary particles then remove `--disable-mc` flag. +Raw decoding itself is done by [RawDecoder](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h) class. + +#### 2. Digits to clusters +Output of previous command is stream of digits and triggers records. It's expected that the stream from FLP goes to EPNs where clusterization procedure is expected to run. +Clusterization is also steered by `o2-cpv-reco-workflow` executable. In order to run clusterization on digits, run +```shell +o2-cpv-reco-workflow --input-type digits --output-type clusters --disable-mc --disable-root-output +``` +The output of the command is stream of [clusters](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h) and corresponding trigger records. Clusterization is done by [Clusterer](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/reconstruction/include/CPVReconstruction/Clusterer.h) class. + +#### 3. Clusters to CTF +Then clusters are ready to be compressed to Compressed Time Frame and to be kept at storage. Try to convert +<!-- add here info how to run CTF creator --> + + +## Simulation +Simulation is organized as follows: +#### 1. Creation of hits +[Hits](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/Hit.h) are objects which keep information about signals such as energy depositions created by single primary particles in detector channels. Hit creation is done by [Detector](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/simulation/include/CPVSimulation/Detector.h) class. To run hits creation type +```shell + o2-sim -n10 -g boxgen --configKeyValues 'BoxGun.pdg=11 ; BoxGun.prange[0]=10.; BoxGun.prange[1]=15.; BoxGun.phirange[0]=260; BoxGun.phirange[1]=280; BoxGun.number=50; BoxGun.eta[0]=-0.125 ; BoxGun.eta[1]=0.125; ' -m CPV +``` +This command will generate 10 events (`-n 10` option) with uniform particle generator (`-g boxgen` option) which generates 50 electrons (`BoxGun.number=50; BoxGun.pdg=11`) with flat momentum distribution in range from 10 GeV/c to 15 GeV/c (`BoxGun.prange[0]=10.; BoxGun.prange[1]=15.;`), flat azimuthal angle phi distribution in range from 260 to 280 degrees (`BoxGun.phirange[0]=260; BoxGun.phirange[1]=280;`), flat pseudorapidity distribution in range from -0.125 to 0.125 units (`BoxGun.eta[0]=-0.125 ; BoxGun.eta[1]=0.125;`), and finally hist only for CPV are created (`-m CPV`). Result of this command is file o2sim_HitsCPV.root containing hits and some other important stuff. + +#### 2. Hits to digits +Hits from different primaries then needed to be merged and electronic noise to be added in order to obtain digits from hits. This can be done with [Digitizer](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h) workflow. Run +```shell +o2-sim-digitizer-workflow --onlyDet CPV +``` +in order to do so. It merges hits and adds electronic noise to merged signals. Electronic noise is simulated as 3 sigma pedestal jitter. As a result the file +You can add `--configKeyValues 'CPVSimParams.mCCDBPath=localtest'` option in order to avoid connection to CCDB and use ideal pedestals (sigma = 1.5 ADC counts for all channels). You can also choose how much sigmas to use for noise simulation providing `--configKeyValues 'CPVSimParams.mZSnSigmas=X'` option, where X is floating point number. + +#### 3. Digits to raw +Digits can be converted to raw data format using [RawWriter](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h) class. Try to run +```shell +o2-cpv-digi2raw -o raw/CPV +``` +This command will read digits from cpvdigits.root by default and produce raw/CPV/ folder with config and raw files. Digits to raw conversion is done by [RawWriter](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h) class. You can specify `--ccdb-url localtest` option in order to use dummy calibration. IMPORTANT is to use same CCDB path as you used at previous step i.e. hits to digits conversion. Input file also can be changed by providing `-i path/to/file.root` option. + + +Raw file is ready to be read as normal raw data file and be processed normally with full reconstruction chain like that: +```shell +o2-raw-file-reader-workflow --input-conf raw/CPV/CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --disable-root-output | o2-cpv-reco-workflow --input-type digits --output-type clusters --disable-mc +``` + +## Calibration +Calibration is based on [TimeSlotCalibration](https://github.com/AliceO2Group/AliceO2/tree/dev/Detectors/Calibration#readme) framework. It supposed to produce calibration objects valid for certain time intervals and put them into CCDB. Calibration processes are expected to be running on EPN using digits and clusters. + +#### Pedestals +Pedestal calibration is needed to measure pedestal values and their RMSs (sigmas). Pedestal value must be subtracted from amplitude at reconstruction stage. Also pedestals values and sigmas are used to configure FEE thresholds (so-called zero suppression) in physics runs. To measure them pedestal run without zero supression must be taken. Then its raw data converted to digits with `--pedestal` flag in order not to calibrate it. Thus digits have signal equal to raw amplitude. Then digit stream is picked up by `o2-calibration-cpv-calib-workflow`. The actual calibration is done by [PedestalCalibrator](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/calib/include/CPVCalibration/PedestalCalibrator.h) class inherited from [TimeSlotCalibration](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h). It produces PedestalSpectrum for each time slot and then finalizing it at the end of TimeSlot or at the end of run. Calibration itself can be run with followng command (it must be within some workflow, of cause): +```shell +o2-calibration-cpv-calib-workflow --pedestals --max-delay 0 --tf-per-slot 100 +``` +Option `--tf-per-slot 100` indicates length of time intervals in TimeFrames. In this particular case length of TimeSlot is 100 TFs. Please consult [this page]() for explanation of all available options. One can also use `--updateAtTheEndOfRunOnly` option in order to finalize TimeSlots and produce calibration object at the end-of-run only. Be careful with that as end-of-run can be unclear yet within the O2 project so it can never happen. At least with the `o2-raw-file-reader-workflow` the finalization of TimeSlot never started yet at the end of file reading. Output of `o2-calibration-cpv-calib-workflow --pedestals` is stream of [Pedestals](https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Detectors/CPV/include/DataFormatsCPV/Pedestals.h) objects and corresponding metadata for CCDB entry. Use `o2-ccdb-populator-workflow` in order to put created objects to CCDB. The overall calibration chain should look like that: +```shell +o2-raw-file-reader-workflow --input-conf CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --disable-root-output --pedestal | o2-calibration-cpv-calib-workflow --pedestals --max-delay 0 --tf-per-slot 100 | o2-calibration-ccdb-populator-workflow +``` +Explanation: it reads file with pedestal data; then raw data is converted to digits without calibration; then digits are picked up by calibrator; and finally produced calibration objects are putted to CCDB. After that it is possible to read them from CCDB with [this script](https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/CPV/calib/macros/readPedestalsFromCCDB.C). + +## Local testing (quick summary) +#### Simulation +```shell +o2-sim -n10 -g boxgen --configKeyValues 'BoxGun.pdg=11 ; BoxGun.prange[0]=10.; BoxGun.prange[1]=15.; BoxGun.phirange[0]=260; BoxGun.phirange[1]=280; BoxGun.number=50; BoxGun.eta[0]=-0.125 ; BoxGun.eta[1]=0.125; ' -m CPV +o2-sim-digitizer-workflow --onlyDet CPV #consider to add --configKeyValues 'CPVSimParams.mCCDBPath=localtest' to use ideal pedestals for noise simulation +o2-cpv-digi2raw -o raw/CPV +``` +#### Reconstruction +```shell +o2-raw-file-reader-workflow --input-conf raw/CPV/CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --disable-root-output | o2-cpv-reco-workflow --input-type digits --output-type clusters --disable-mc +``` +#### Pedestal calibration +```shell +o2-raw-file-reader-workflow --input-conf CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --disable-root-output --pedestal | o2-calibration-cpv-calib-workflow --pedestals --max-delay 0 --tf-per-slot 100 | o2-calibration-ccdb-populator-workflow +``` diff --git a/Detectors/CPV/base/CMakeLists.txt b/Detectors/CPV/base/CMakeLists.txt index e3ad172022a44..893b5b98f682b 100644 --- a/Detectors/CPV/base/CMakeLists.txt +++ b/Detectors/CPV/base/CMakeLists.txt @@ -1,17 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CPVBase - SOURCES src/Geometry.cxx src/Hit.cxx src/CPVSimParams.cxx + SOURCES src/Geometry.cxx + src/CPVSimParams.cxx PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat) o2_target_root_dictionary(CPVBase HEADERS include/CPVBase/Geometry.h - include/CPVBase/Hit.h include/CPVBase/CPVSimParams.h) + include/CPVBase/CPVSimParams.h) diff --git a/Detectors/CPV/base/include/CPVBase/CPVSimParams.h b/Detectors/CPV/base/include/CPVBase/CPVSimParams.h index 501902c0ff518..40c092c6f6827 100644 --- a/Detectors/CPV/base/include/CPVBase/CPVSimParams.h +++ b/Detectors/CPV/base/include/CPVBase/CPVSimParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,15 +23,15 @@ namespace cpv // (mostly used in GEANT stepping and Digitizer) struct CPVSimParams : public o2::conf::ConfigurableParamHelper<CPVSimParams> { - std::string mCCDBPath = "localtest"; ///< use "localtest" to avoid connecting ccdb server, otherwise use ccdb-test.cern.ch + std::string mCCDBPath = "http://ccdb-test.cern.ch:8080"; ///< use "localtest" to avoid connecting ccdb server, otherwise use ccdb-test.cern.ch //Parameters used in conversion of deposited energy to APD response - int mnCellZ = 128; - int mnCellX = 60; - float mPadSizeZ = 1.13; ///< overall size of CPV active size - float mPadSizeX = 2.1093; ///< in phi and z directions + int mnCellX = 128; + int mnCellZ = 60; + float mPadSizeX = 1.13; ///< overall size of CPV active size + float mPadSizeZ = 2.1093; ///< in phi and z directions float mDetR = 0.1; ///< Relative energy fluctuation in track for 100 e- - float mdEdx = 4.0; ///< Average energy loss in CPV; + float mdEdx = 400.0; ///< Average energy loss in CPV (arbitrary units); int mNgamz = 5; ///< Ionization size in Z int mNgamx = 9; ///< Ionization size in Phi float mCPVGasThickness = 1.3; ///< width of ArC02 gas gap @@ -38,22 +39,35 @@ struct CPVSimParams : public o2::conf::ConfigurableParamHelper<CPVSimParams> { float mB = 0.7; ///< Parameter to model CPV response //Parameters used in electronic noise calculation and thresholds (Digitizer) - bool mApplyDigitization = true; ///< if energy digitization should be applied - float mZSthreshold = 0.005; ///< Zero Suppression threshold - float mADCWidth = 0.005; ///< Widht of ADC channel used for energy digitization - float mNoise = 0.03; ///< charge noise in one pad - float mCoeffToNanoSecond = 1.e+9; ///< Conversion for time units - float mSortingDelta = 0.1; ///< used in sorting clusters inverse sorting band in cm + float mReadoutTime = 5.; ///< Read-out time in ns for default simulaionts + float mDeadTime = 20.; ///< PHOS dead time (includes Read-out time i.e. mDeadTime>=mReadoutTime) + float mReadoutTimePU = 2000.; ///< Read-out time in ns if pileup simulation on in DigitizerSpec + float mDeadTimePU = 30000.; ///< PHOS dead time if pileup simulation on in DigitizerSpec + bool mApplyDigitization = true; ///< if energy digitization should be applied + //float mZSthreshold = 0.01; ///< Zero Suppression threshold + float mZSnSigmas = 3.; ///< Zero Suppression threshold + //float mADCWidth = 0.005; ///< Widht of ADC channel used for energy digitization + //float mNoise = 0.01; ///< charge noise in one pad + //float mCoeffToNanoSecond = 1.e+9; ///< Conversion for time units + float mSortingDelta = 0.1; ///< used in sorting clusters inverse sorting band in cm //Parameters used in clusterization - float mDigitMinEnergy = 0.005; ///< Minimal amplitude of a digit to be used in cluster - float mClusteringThreshold = 0.050; ///< Seed digit minimal amplitude - float mUnfogingEAccuracy = 1.e-3; ///< Accuracy of energy calculation in unfoding prosedure (GeV) - float mUnfogingXZAccuracy = 1.e-1; ///< Accuracy of position calculation in unfolding procedure (cm) - float mLocalMaximumCut = 0.030; ///< Threshold to separate local maxima - float mLogWeight = 4.5; ///< weight in cluster center of gravity calculation - int mNMaxIterations = 10; ///< Maximal number of iterations in unfolding procedure - bool mUnfoldClusters = false; ///< Perform cluster unfolding? + //float mDigitMinEnergy = 0.01; ///< Minimal amplitude of a digit to be used in cluster + float mDigitMinEnergy = 5.; ///< Minimal amplitude of a digit to be used in cluster + float mClusteringThreshold = 10.; ///< Seed digit minimal amplitude + float mUnfogingEAccuracy = 1.e-3; ///< Accuracy of energy calculation in unfoding prosedure (GeV) + float mUnfogingXZAccuracy = 1.e-1; ///< Accuracy of position calculation in unfolding procedure (cm) + float mLocalMaximumCut = 0.030; ///< Threshold to separate local maxima + float mLogWeight = 4.5; ///< weight in cluster center of gravity calculation + int mNMaxIterations = 10; ///< Maximal number of iterations in unfolding procedure + bool mUnfoldClusters = false; ///< Perform cluster unfolding? + + // Parameters used in pedestal calibration + uint16_t mPedClbToleratedGapWidth = 5; ///< Tolerated gap between bins: if |bin1 - bin2| < width -> bin1 and bin2 belongs to same peak + float mPedClbToleratedChannelEfficiencyLow = 0.9; ///< Tolerated channel efficiency (lower limit) + float mPedClbToleratedChannelEfficiencyHigh = 1.01; ///< Tolerated channel efficiency (upper limit) + uint32_t mPedClbMinEvents = 100; ///< Minimal number of events to produce calibration + float mPedClbSuspiciousPedestalRMS = 10.; ///< Take additional care for channel if its RMS > mPedClbSuspiciousPedestalRMS inline float CellWr() const { return 0.5 * mPadSizeX; } ///< Distance between wires (2 wires above 1 pad) diff --git a/Detectors/CPV/base/include/CPVBase/Geometry.h b/Detectors/CPV/base/include/CPVBase/Geometry.h index 922d1d5064097..32586b8ac363a 100644 --- a/Detectors/CPV/base/include/CPVBase/Geometry.h +++ b/Detectors/CPV/base/include/CPVBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,8 +27,25 @@ class Geometry public: static constexpr short kNumberOfCPVPadsPhi = 128; static constexpr short kNumberOfCPVPadsZ = 60; + static constexpr short kNCHANNELS = kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ * 3; static constexpr float kCPVPadSizePhi = 1.13; static constexpr float kCPVPadSizeZ = 2.1093; + //for hwaddress + static constexpr short kNPAD = 48; + static constexpr short kNDilogic = 4; + static constexpr short kNGas = 5; + static constexpr short kNRow = 16; + static constexpr short kNMod = 4; + + /// Available numbering schems: + /// relative pad coordinates + /// relId[3]={Module, phi col, z row} where Module=2..4, phi col=0..127, z row=0..59 + /// Absolute pad coordunate + /// absId=0..128*60*3-1=23039 + /// Raw addresses: + /// each module consist of 16 columns of width 8 pads: row=0..15 + /// Each column consists of 10 dilogics (in z direction) dilogic=0...9 + /// Ecah dilogic contains 8*6 pads: hwaddress=0...48 /// /// Default constructor. @@ -55,7 +73,7 @@ class Geometry // = 1 are neighbour // = 2 are not neighbour but do not continue searching // =-1 are not neighbour, continue searching, but do not look before d2 next time - static int areNeighbours(short absId1, short absId2); + static short areNeighbours(unsigned short absId1, unsigned short absId2); /// /// \return AbsId index of the CPV cell @@ -64,18 +82,32 @@ class Geometry /// \param strip: strip number // \param cell: cell in strip number /// - static short relToAbsId(char moduleNumber, int iphi, int iz); - static bool absToRelNumbering(short absId, short* relid); - static char absIdToModule(short absId); - static void absIdToRelPosInModule(short absId, float& x, float& z); - static bool relToAbsNumbering(const short* relId, short& absId); + static unsigned short relToAbsId(short moduleNumber, short iphi, short iz); + static bool absToRelNumbering(unsigned short absId, short* relid); + static short absIdToModule(unsigned short absId); + static void absIdToRelPosInModule(unsigned short absId, float& x, float& z); + static bool relToAbsNumbering(const short* relId, unsigned short& absId); + + static bool hwaddressToAbsId(short ccId, short dil, short gas, short pad, unsigned short& absId); + static bool absIdToHWaddress(unsigned short absId, short& ccId, short& dil, short& gas, short& pad); - static int getTotalNPads() { return kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ * 3; } - static bool IsPadExists(short absId) + static unsigned short getTotalNPads() { return kNCHANNELS; } + static bool IsPadExists(unsigned short absId) { - return absId > 0 && absId <= getTotalNPads(); + return absId >= 0 && absId < getTotalNPads(); } // TODO: evaluate from real geometry + //Pad map per 3Gassiplex + //Fixed mapping + static constexpr short mPadMap[6][8] = {11, 9, 7, 17, 47, 43, 41, 39, + 15, 13, 5, 23, 45, 37, 35, 33, + 14, 12, 4, 25, 46, 38, 34, 32, + 10, 6, 2, 27, 21, 16, 40, 36, + 8, 1, 0, 28, 24, 20, 18, 42, + 3, 31, 30, 29, 26, 22, 19, 44}; + static constexpr short mPadToZ[48] = {4, 4, 3, 5, 2, 1, 3, 0, 4, 0, 3, 0, 2, 1, 2, 1, 3, 0, 4, 5, 4, 3, 5, 1, 4, 2, 5, 3, 4, 5, 5, 5, 2, 1, 2, 1, 3, 1, 2, 0, 3, 0, 4, 0, 5, 1, 2, 0}; + static constexpr short mPadToPhi[48] = {2, 1, 2, 0, 2, 2, 1, 2, 0, 1, 0, 0, 1, 1, 0, 0, 5, 3, 6, 6, 5, 4, 5, 3, 4, 3, 4, 3, 3, 3, 2, 1, 7, 7, 6, 6, 7, 5, 5, 7, 6, 6, 7, 5, 7, 4, 4, 4}; + ClassDefNV(Geometry, 1); }; } // namespace cpv diff --git a/Detectors/CPV/base/include/CPVBase/Hit.h b/Detectors/CPV/base/include/CPVBase/Hit.h deleted file mode 100644 index 4e7e7febba883..0000000000000 --- a/Detectors/CPV/base/include/CPVBase/Hit.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_CPV_HIT_H -#define ALICEO2_CPV_HIT_H - -#include "SimulationDataFormat/BaseHits.h" -#include "CommonUtils/ShmAllocator.h" - -namespace o2 -{ -namespace cpv -{ -/// \class Hit -/// \brief CPV simulation hit information -class Hit : public o2::BasicXYZEHit<float> -{ - public: - /// \brief Default constructor - Hit() = default; - - /// \brief Hit constructor - /// - /// Fully defining information of the CPV Hit (position, - /// momentum, energy, track, ...) - /// - /// \param trackID Index of the track entered CPV - /// \param detID ID of the detector segment - /// \param pos Position vector of the Hit - /// \param mom Momentum vector for the particle at the Hit - /// \param initialEnergy Energy of the primary particle enering the EMCAL - /// \param tof Time of the hit - /// \param length Length of the segment - Hit(int trackID, int detID, const math_utils::Point3D<float>& pos, double tof, double qLoss) - : o2::BasicXYZEHit<float>(pos.X(), pos.Y(), pos.Z(), tof, qLoss, trackID, detID) - { - } - - Hit& operator=(const Hit& hit) = default; - - /// \brief Check whether the points are from the same SuperParent and in the same detector volume - /// \return True if points are the same (origin and detector), false otherwise - Bool_t operator==(const Hit& rhs) const; - - /// \brief Check whether the points are from the same SuperParent and in the same detector volume - /// \return True if points are the same (origin and detector), false otherwise - Bool_t operator=(const Hit& rhs) const; - - /// \brief Sorting points according to parent particle and detector volume - /// \return True if this Hit is smaller, false otherwise - Bool_t operator<(const Hit& rhs) const; - - /// \brief Adds energy loss from the other Hit to this Hit - /// \param rhs cpv::Hit to add to this Hit - /// \return This Hit with the summed energy loss - Hit& operator+=(const Hit& rhs); - - /// \brief Creates a new Hit based on this Hit but adding the energy loss of the right hand side - /// \param - /// \return New Hit based on this Hit - Hit operator+(const Hit& rhs) const; - - /// \brief Destructor - ~Hit() = default; - - void AddEnergyLoss(Double_t eloss) { SetEnergyLoss(GetEnergyLoss() + eloss); } - - /// \brief Writing Hit information to an output stream; - /// \param stream target output stream - void PrintStream(std::ostream& stream) const; - - private: - ClassDefNV(Hit, 1); -}; - -std::ostream& operator<<(std::ostream& stream, const Hit& point); -} // namespace cpv -} // namespace o2 - -#ifdef USESHM -namespace std -{ -template <> -class allocator<o2::cpv::Hit> : public o2::utils::ShmAllocator<o2::cpv::Hit> -{ -}; -} // namespace std -#endif - -#endif /* Hit_h */ diff --git a/Detectors/CPV/base/src/CPVBaseLinkDef.h b/Detectors/CPV/base/src/CPVBaseLinkDef.h index 73ab6adea36da..2833c6eef89e0 100644 --- a/Detectors/CPV/base/src/CPVBaseLinkDef.h +++ b/Detectors/CPV/base/src/CPVBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,8 +16,6 @@ #pragma link off all functions; #pragma link C++ class o2::cpv::Geometry + ; -#pragma link C++ class o2::cpv::Hit + ; -#pragma link C++ class vector < o2::cpv::Hit> + ; #pragma link C++ class o2::cpv::CPVSimParams + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::cpv::CPVSimParams> + ; diff --git a/Detectors/CPV/base/src/CPVSimParams.cxx b/Detectors/CPV/base/src/CPVSimParams.cxx index 435fd309d6b52..2a25c7b0fef2b 100644 --- a/Detectors/CPV/base/src/CPVSimParams.cxx +++ b/Detectors/CPV/base/src/CPVSimParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/base/src/Geometry.cxx b/Detectors/CPV/base/src/Geometry.cxx index f80c0387183a8..eba148f4e4e43 100644 --- a/Detectors/CPV/base/src/Geometry.cxx +++ b/Detectors/CPV/base/src/Geometry.cxx @@ -1,47 +1,52 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "CPVBase/Geometry.h" +#include "FairLogger.h" using namespace o2::cpv; ClassImp(Geometry); -short Geometry::relToAbsId(char moduleNumber, int iphi, int iz) +unsigned short Geometry::relToAbsId(short moduleNumber, short iphi, short iz) { //converts module number, phi and z coordunates to absId - return kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ * (moduleNumber - 1) + kNumberOfCPVPadsZ * (iz - 1) + iphi; + return kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ * (moduleNumber - 2) + kNumberOfCPVPadsZ * iphi + iz; } -bool Geometry::absToRelNumbering(short absId, short* relid) +bool Geometry::absToRelNumbering(unsigned short absId, short* relid) { // Converts the absolute numbering into the following array // relid[0] = CPV Module number 1:fNModules // relid[1] = Column number inside a CPV module (Phi coordinate) // relid[2] = Row number inside a CPV module (Z coordinate) - - short nCPV = kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ; - relid[0] = (absId - 1) / nCPV + 1; - absId -= (relid[0] - 1) * nCPV; - relid[2] = absId / kNumberOfCPVPadsZ + 1; - relid[1] = absId - (relid[2] - 1) * kNumberOfCPVPadsZ; + if (absId >= kNCHANNELS) { + LOG(DEBUG) << "Wrong absId = " << absId << " > kNCHANNELS=" << kNCHANNELS; + return false; + } + const short nCPV = kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ; + relid[0] = absId / nCPV + 2; + absId -= (relid[0] - 2) * nCPV; + relid[1] = absId / kNumberOfCPVPadsZ; + relid[2] = absId % kNumberOfCPVPadsZ; return true; } -char Geometry::absIdToModule(short absId) +short Geometry::absIdToModule(unsigned short absId) { - return 1 + (absId - 1) / (kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ); + return 2 + absId / (kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ); } -int Geometry::areNeighbours(short absId1, short absId2) +short Geometry::areNeighbours(unsigned short absId1, unsigned short absId2) { // Gives the neighbourness of two digits = 0 are not neighbour but continue searching @@ -80,23 +85,82 @@ int Geometry::areNeighbours(short absId1, short absId2) } return 0; } -void Geometry::absIdToRelPosInModule(short absId, float& x, float& z) +void Geometry::absIdToRelPosInModule(unsigned short absId, float& x, float& z) { //Calculate from absId of a cell its position in module short relid[3]; absToRelNumbering(absId, relid); - x = (relid[1] - kNumberOfCPVPadsPhi / 2 - 0.5) * kCPVPadSizePhi; - z = (relid[2] - kNumberOfCPVPadsZ / 2 - 0.5) * kCPVPadSizeZ; + x = (relid[1] - kNumberOfCPVPadsPhi / 2 + 0.5) * kCPVPadSizePhi; + z = (relid[2] - kNumberOfCPVPadsZ / 2 + 0.5) * kCPVPadSizeZ; } -bool Geometry::relToAbsNumbering(const short* relId, short& absId) +bool Geometry::relToAbsNumbering(const short* relId, unsigned short& absId) { absId = - (relId[0] - 1) * kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ + // the offset of PHOS modules - (relId[2] - 1) * kNumberOfCPVPadsZ + // the offset along phi - relId[1]; // the offset along z + (relId[0] - 2) * kNumberOfCPVPadsPhi * kNumberOfCPVPadsZ + // the offset of PHOS modules + relId[1] * kNumberOfCPVPadsZ + // the offset along phi + relId[2]; // the offset along z return true; } +bool Geometry::hwaddressToAbsId(short ccId, short dil, short gas, short pad, unsigned short& absId) +{ + //check if hw address is valid + bool isGoodHWAddress = true; + if (pad < 0 || pad >= kNPAD) { + LOG(DEBUG) << "Geometry::hwaddressToAbsId() : Wrong pad address: pad=" << pad << " >= kNPAD=" << kNPAD; + isGoodHWAddress = false; + } + if (dil < 0 || dil >= kNDilogic) { + LOG(DEBUG) << "Geometry::hwaddressToAbsId() : Wrong dil address: dil=" << dil << " >= kNDilogic=" << kNDilogic; + isGoodHWAddress = false; + } + if (gas < 0 || gas >= kNGas) { + LOG(DEBUG) << "Geometry::hwaddressToAbsId() : Wrong gasiplex address: gas=" << gas << " >= kNGas=" << kNGas; + isGoodHWAddress = false; + } + //return false in no success case + if (!isGoodHWAddress) { + return false; + } + + short pZ = mPadToZ[pad]; + short pPhi = mPadToPhi[pad]; + short relid[3] = {short(ccId / 8 + 2), short((ccId % 8) * 16 + (dil / 2) * 8 + 7 - pPhi), short((dil % 2) * 30 + gas * 6 + pZ)}; + + return relToAbsNumbering(relid, absId); +} + +bool Geometry::absIdToHWaddress(unsigned short absId, short& ccId, short& dil, short& gas, short& pad) +{ + // Convert absId to hw address + // Arguments: ccId: 0 -- 7 - mod 2; 8...15 mod 3; 16...23 mod 4 + //dilogic: 0..3, gas=0..5, pad:0..47 + + short relid[3]; + if (!absToRelNumbering(absId, relid)) { + return false; //wrong absId passed + } + + ccId = (relid[0] - 2) * 8 + relid[1] / 16; + dil = 2 * ((relid[1] % 16) / 8) + relid[2] / 30; // Dilogic# 0..3 + gas = (relid[2] % 30) / 6; // gasiplex# 0..4 + pad = mPadMap[relid[2] % 6][7 - relid[1] % 8]; // pad 0..47 + + bool isAbsIdOk = true; + if (pad < 0 || pad >= kNPAD) { + LOG(DEBUG) << "Wrong pad address: pad=" << pad << " >= kNPAD=" << kNPAD; + isAbsIdOk = false; + } + if (dil < 0 || dil >= kNDilogic) { + LOG(DEBUG) << "Wrong dil address: dil=" << dil << " >= kNDilogic=" << kNDilogic; + isAbsIdOk = false; + } + if (gas < 0 || gas >= kNGas) { + LOG(DEBUG) << "Wrong gasiplex address: gas=" << gas << " >= kNGas=" << kNGas; + isAbsIdOk = false; + } + return isAbsIdOk; +} diff --git a/Detectors/CPV/calib/CMakeLists.txt b/Detectors/CPV/calib/CMakeLists.txt index 543513ece3f23..4b21f70bfe4b1 100644 --- a/Detectors/CPV/calib/CMakeLists.txt +++ b/Detectors/CPV/calib/CMakeLists.txt @@ -1,30 +1,46 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library(CPVCalib - SOURCES src/BadChannelMap.cxx - src/CalibParams.cxx - PUBLIC_LINK_LIBRARIES O2::CCDB O2::CPVBase) +add_subdirectory(CPVCalibWorkflow) -o2_target_root_dictionary(CPVCalib - HEADERS include/CPVCalib/BadChannelMap.h - include/CPVCalib/CalibParams.h - LINKDEF src/CPVCalibLinkDef.h) +o2_add_library(CPVCalibration + TARGETVARNAME targetName + SOURCES src/PedestalCalibrator.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsCPV + O2::CPVBase + O2::DetectorsCalibration + O2::CCDB) + +o2_target_root_dictionary(CPVCalibration + HEADERS include/CPVCalibration/PedestalCalibrator.h) + +o2_add_executable(cpv-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/cpv-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::CPVCalibration + O2::DetectorsCalibration + O2::DataFormatsCPV) if(BUILD_TESTING) - o2_add_test_root_macro(macros/PostBadMapCCDB.C - PUBLIC_LINK_LIBRARIES O2::CCDB O2::CPVBase O2::CPVCalib + o2_add_test_root_macro(macros/readPedestalsFromCCDB.C + PUBLIC_LINK_LIBRARIES O2::CCDB O2::DataFormatsCPV + LABELS CPV COMPILE_ONLY) + + o2_add_test_root_macro(macros/PostBadMapCCDB.C + PUBLIC_LINK_LIBRARIES O2::CCDB O2::DataFormatsCPV LABELS CPV COMPILE_ONLY) o2_add_test_root_macro( macros/PostCalibCCDB.C - PUBLIC_LINK_LIBRARIES O2::CCDB O2::CPVBase O2::CPVCalib + PUBLIC_LINK_LIBRARIES O2::CCDB O2::DataFormatsCPV LABELS CPV COMPILE_ONLY) endif() diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/CMakeLists.txt b/Detectors/CPV/calib/CPVCalibWorkflow/CMakeLists.txt new file mode 100644 index 0000000000000..26745a09cdd09 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(CPVCalibWorkflow + SOURCES src/CPVPedestalCalibDevice.cxx + src/CPVGainCalibDevice.cxx + src/CPVBadMapCalibDevice.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCPV + O2::DetectorsRaw + O2::CPVReconstruction + O2::DetectorsCalibration) + + +o2_add_executable(calib-workflow + COMPONENT_NAME cpv + SOURCES src/cpv-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCPV + O2::CPVCalibWorkflow + O2::DetectorsCalibration) diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVBadMapCalibDevice.h b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVBadMapCalibDevice.h new file mode 100644 index 0000000000000..9696af5654135 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVBadMapCalibDevice.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_CPVBADMAP_CALIBRATOR_H +#define O2_CALIBRATION_CPVBADMAP_CALIBRATOR_H + +/// @file BadMapCalibSpec.h +/// @brief Device to calculate CPV bad map + +#include "Framework/Task.h" +// #include "Framework/ConfigParamRegistry.h" +// #include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCPV/BadChannelMap.h" +#include "CPVBase/Geometry.h" +#include "TH2.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +class CPVBadMapCalibDevice : public o2::framework::Task +{ + + public: + explicit CPVBadMapCalibDevice(bool useCCDB, bool forceUpdate, std::string path, short m) : mUseCCDB(useCCDB), mForceUpdate(forceUpdate), mPath(path), mMethod(m) {} + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + void sendOutput(DataAllocator& output); + + bool differFromCurrent(); + + private: + bool mUseCCDB = false; /// Use CCDB for comparison and update + bool mForceUpdate = false; /// Update CCDB even if difference to current is large + bool mUpdateCCDB = true; /// set is close to current and can update it + short mMethod = 0; + std::string mPath{"./"}; ///< path and name of file with collected histograms + std::unique_ptr<BadChannelMap> mBadMap; /// Final calibration object + std::array<char, o2::cpv::Geometry::kNCHANNELS> mMapDiff; /// difference between new and old map +}; + +o2::framework::DataProcessorSpec getBadMapCalibSpec(bool useCCDB, bool forceUpdate, std::string path, short method); + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVGainCalibDevice.h b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVGainCalibDevice.h new file mode 100644 index 0000000000000..3988c62956b2f --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVGainCalibDevice.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_CPVGAINS_CALIBRATOR_H +#define O2_CALIBRATION_CPVGAINS_CALIBRATOR_H + +/// @file CPVGainCalibSpec.h +/// @brief Device to calculate CPV gains + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCPV/CalibParams.h" +#include "CPVBase/Geometry.h" +#include "TH2.h" +#include <string> + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +class CPVGainCalibDevice : public o2::framework::Task +{ + + public: + explicit CPVGainCalibDevice(bool useCCDB, bool forceUpdate, std::string path) : mUseCCDB(useCCDB), mForceUpdate(forceUpdate), mPath(path) {} + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + void sendOutput(DataAllocator& output); + void calculateGains(); + void checkGains(); + + private: + static constexpr int kMinimalStatistics = 150; /// Minimal statistics per channel + + bool mUseCCDB = false; /// Use CCDB for comparison and update + bool mForceUpdate = false; /// Update CCDB even if difference to current is large + bool mUpdateCCDB = true; /// set is close to current and can update it + + std::string mPath{"./"}; ///< path and name of file with collected histograms + std::unique_ptr<CalibParams> mCalibParams; /// Final calibration object + std::unique_ptr<TH2F> mMean; /// Mean values in High Gain channels + std::array<short, o2::cpv::Geometry::kNCHANNELS> mGainRatio; /// Gain variation wrt previous map +}; + +o2::framework::DataProcessorSpec getGainCalibSpec(bool useCCDB, bool forceUpdate, std::string path); + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVPedestalCalibDevice.h b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVPedestalCalibDevice.h new file mode 100644 index 0000000000000..72a50a3214128 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVPedestalCalibDevice.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_CPVPEDESTALS_CALIBRATOR_H +#define O2_CALIBRATION_CPVPEDESTALS_CALIBRATOR_H + +/// @file PedestalCalibSpec.h +/// @brief Device to calculate CPV pedestals + +#include "Framework/Task.h" +// #include "Framework/ConfigParamRegistry.h" +// #include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCPV/Pedestals.h" +#include "CPVBase/Geometry.h" +#include "TH2.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +class CPVPedestalCalibDevice : public o2::framework::Task +{ + + public: + explicit CPVPedestalCalibDevice(bool useCCDB, bool forceUpdate, std::string path) : mUseCCDB(useCCDB), mForceUpdate(forceUpdate), mPath(path) {} + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + void sendOutput(DataAllocator& output); + + void calculatePedestals(); + void checkPedestals(); + + private: + bool mUseCCDB = false; + bool mForceUpdate = false; /// Update CCDB even if difference to current is large + bool mUpdateCCDB = true; /// set is close to current and can update it + std::string mPath{"./"}; ///< path and name of file with collected histograms + std::unique_ptr<Pedestals> mPedestals; /// Final calibration object + std::unique_ptr<TH2F> mMean; /// Mean values in High Gain channels + std::array<short, o2::cpv::Geometry::kNCHANNELS> mPedDiff; /// Pedestal variation wrt previous map + ClassDefNV(CPVPedestalCalibDevice, 1); +}; + +o2::framework::DataProcessorSpec getPedestalCalibSpec(bool useCCDB, bool forceUpdate, std::string path); + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVBadMapCalibDevice.cxx b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVBadMapCalibDevice.cxx new file mode 100644 index 0000000000000..e8b69b07246bf --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVBadMapCalibDevice.cxx @@ -0,0 +1,219 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVCalibWorkflow/CPVBadMapCalibDevice.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/Utils.h" +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Framework/InputRecordWalker.h" +#include "CPVReconstruction/RawReaderMemory.h" +#include "CPVReconstruction/RawDecoder.h" +#include <TFile.h> + +using namespace o2::cpv; + +void CPVBadMapCalibDevice::init(o2::framework::InitContext& ic) +{ +} + +void CPVBadMapCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + + mBadMap.reset(new BadChannelMap()); + + //Probably can be configured from configKeyValues? + const float kMaxCut = 10.; + const float kMinCut = 0.1; + + if (mMethod % 2 == 0) { //Gains: dead channels (medhod= 0,2) + + std::string filename = mPath + "CPVGains.root"; + TFile f(filename.data(), "READ"); + TH2F* spectra = nullptr; + if (f.IsOpen()) { + spectra = static_cast<TH2F*>(f.Get("Gains")); + } + if (!spectra) { + LOG(ERROR) << "ERROR: can not read histo Gains from file " << filename.data(); + return; + } + float meanOccupancy = spectra->Integral() / spectra->GetNbinsX(); + short nBadChannels = 0; + float improvedOccupancy = meanOccupancy; + do { + nBadChannels = 0; + meanOccupancy = improvedOccupancy; + improvedOccupancy = 0; + short ngood = 0; + for (unsigned short i = spectra->GetNbinsX(); --i;) { + float a = spectra->Integral(i + 1, i + 1, 1, 1024); + if (a > kMaxCut * meanOccupancy + 1 || a < kMinCut * meanOccupancy - 1 || a == 0) { //noisy or dead + if (mBadMap->isChannelGood(i)) { + mBadMap->addBadChannel(i); + nBadChannels++; + } + } else { + improvedOccupancy += a; + ngood++; + } + } + if (ngood > 0) { + improvedOccupancy /= ngood; + } + } while (nBadChannels > 0); + spectra->Delete(); + f.Close(); + } + + if (mMethod > 0) { //methods 1,2: use pedestals + //Read latest pedestal file + std::string filename = mPath + "CPVPedestals.root"; + TFile f(filename.data(), "READ"); + TH2F* pedestals = nullptr; + if (f.IsOpen()) { + pedestals = static_cast<TH2F*>(f.Get("Mean")); + } + if (!pedestals) { + LOG(ERROR) << "ERROR: can not read histo Mean from file " << filename.data(); + return; + } + TH1D* proj = pedestals->ProjectionY("m"); + float meanPed = proj->GetMean(); + float rmsPed = proj->GetRMS(); + proj->Delete(); + short nBadChannels = 0; + float improvedMean = meanPed, improvedRMS = rmsPed; + do { + nBadChannels = 0; + meanPed = improvedMean; + rmsPed = improvedRMS; + improvedMean = 0.; + improvedRMS = 0.; + short ngood = 0; + for (unsigned short i = pedestals->GetNbinsX(); --i;) { + TH1D* pr = pedestals->ProjectionY(Form("proj%d", i), i + 1, i + 1); + float prMean = pr->GetMean(); + float prRMS = pr->GetRMS(); + pr->Delete(); + if (prMean > kMaxCut * meanPed || prMean < kMinCut * meanPed || prMean == 0 || + prRMS > kMaxCut * rmsPed || prRMS < kMinCut * rmsPed) { //noisy or dead + if (mBadMap->isChannelGood(i)) { + mBadMap->addBadChannel(i); + nBadChannels++; + } + } else { + improvedMean += prMean; + improvedRMS += prRMS; + ngood++; + } + } + if (ngood > 0) { + improvedMean /= ngood; + improvedRMS /= ngood; + } + } while (nBadChannels > 0); + pedestals->Delete(); + f.Close(); + } + + if (!differFromCurrent() || mForceUpdate) { + sendOutput(ctx.outputs()); + } + ctx.services().get<ControlService>().endOfStream(); + ctx.services().get<ControlService>().readyToQuit(QuitRequest::Me); +} + +void CPVBadMapCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + LOG(INFO) << "[CPVBadMapCalibDevice - endOfStream]"; + //calculate stuff here +} + +void CPVBadMapCalibDevice::sendOutput(DataAllocator& output) +{ + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + + if (mUpdateCCDB || mForceUpdate) { + // prepare all info to be sent to CCDB + o2::ccdb::CcdbObjectInfo info; + auto image = o2::ccdb::CcdbApi::createObjectImage(mBadMap.get(), &info); + + auto flName = o2::ccdb::CcdbApi::generateFileName("BadChannelMap"); + info.setPath("CPV/Calib/BadChannelMap"); + info.setObjectType("BadChannelMap"); + info.setFileName(flName); + // TODO: should be changed to time of the run + time_t now = time(nullptr); + info.setStartValidityTimestamp(now); + info.setEndValidityTimestamp(99999999999999); + std::map<std::string, std::string> md; + info.setMetaData(md); + + LOG(INFO) << "Sending object CPV/Calib/BadChannelMap"; + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_BadChanMap", subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_BadChanMap", subSpec}, info); + } + + output.snapshot(o2::framework::Output{"CPV", "BADMAPCHANGE", 0, o2::framework::Lifetime::Timeframe}, mMapDiff); +} + +bool CPVBadMapCalibDevice::differFromCurrent() +{ + // Method to compare new pedestals and latest in ccdb + // Send difference to QC + // Do not update existing object automatically if difference is too strong + + if (!mUseCCDB) { //can not compare, just update + return false; + } + // read calibration objects from ccdb + // int nSlots = pc.inputs().getNofParts(0); + // assert(pc.inputs().getNofParts(1) == nSlots); + + // int lhcphaseIndex = -1; + // for (int isl = 0; isl < nSlots; isl++) { + // const auto wrp = pc.inputs().get<CcdbObjectInfo*>("clbInfo", isl); + // if (wrp->getStartValidityTimestamp() > tfcounter) { // replace tfcounter with the timestamp of the TF + // lhxphaseIndex = isl - 1; + // break; + // } + // } + + return false; +} + +o2::framework::DataProcessorSpec o2::cpv::getBadMapCalibSpec(bool useCCDB, bool forceUpdate, std::string path, short method) +{ + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_BadChanMap"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_BadChanMap"}); + + outputs.emplace_back("CPV", "BADMAPCHANGE", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"BadMapCalibSpec", + Inputs{}, + outputs, + o2::framework::adaptFromTask<CPVBadMapCalibDevice>(useCCDB, forceUpdate, path, method), + o2::framework::Options{}}; +} diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVGainCalibDevice.cxx b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVGainCalibDevice.cxx new file mode 100644 index 0000000000000..7df8d78ae6488 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVGainCalibDevice.cxx @@ -0,0 +1,227 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVCalibWorkflow/CPVGainCalibDevice.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include <string> +#include <ctime> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/InputRecordWalker.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "CPVReconstruction/RawReaderMemory.h" +#include "CPVReconstruction/RawDecoder.h" +#include "CPVBase/Geometry.h" +#include "TF1.h" + +using namespace o2::cpv; + +void CPVGainCalibDevice::init(o2::framework::InitContext& ic) +{ + //Check if files from previous runs exist + //if yes, read histogram + mMean = std::unique_ptr<TH2F>(new TH2F("Gains", "Signals per channel", o2::cpv::Geometry::kNCHANNELS, 0.5, o2::cpv::Geometry::kNCHANNELS + 0.5, 1024, 0., 4096.)); + + std::string filename = mPath + "CPVGains.root"; + TFile filein(filename.data(), "READ"); + if (filein.IsOpen()) { + mMean->Add(static_cast<TH2F*>(filein.Get("Gains"))); + filein.Close(); + } +} + +void CPVGainCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + + // + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs())) { + + o2::cpv::RawReaderMemory rawreader(o2::framework::DataRefUtils::as<const char>(rawData)); + // loop over all the DMA pages + while (rawreader.hasNext()) { + try { + rawreader.next(); + } catch (RawErrorType_t e) { + LOG(ERROR) << "Raw decoding error " << (int)e; + //if problem in header, abandon this page + if (e == RawErrorType_t::kRDH_DECODING) { + break; + } + //if problem in payload, try to continue + continue; + } + auto& header = rawreader.getRawHeader(); + auto triggerBC = o2::raw::RDHUtils::getTriggerBC(header); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(header); + // use the altro decoder to decode the raw data, and extract the RCU trailer + o2::cpv::RawDecoder decoder(rawreader); + RawErrorType_t err = decoder.decode(); + if (err != kOK) { + //TODO handle severe errors + continue; + } + // Loop over all the channels + for (auto adch : decoder.getDigits()) { + AddressCharge ac = {adch}; + unsigned short absId = ac.Address; + mMean->Fill(absId, ac.Charge); + } + } //RawReader::hasNext + } +} + +void CPVGainCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + LOG(INFO) << "[CPVGainCalibDevice - endOfStream]"; + //calculate stuff here + calculateGains(); + checkGains(); + sendOutput(ec.outputs()); +} + +void CPVGainCalibDevice::sendOutput(DataAllocator& output) +{ + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + + if (mUpdateCCDB || mForceUpdate) { + // prepare all info to be sent to CCDB + o2::ccdb::CcdbObjectInfo info; + auto image = o2::ccdb::CcdbApi::createObjectImage(mCalibParams.get(), &info); + + auto flName = o2::ccdb::CcdbApi::generateFileName("CalibParams"); + info.setPath("CPV/Calib/CalibParams"); + info.setObjectType("CalibParams"); + info.setFileName(flName); + // TODO: should be changed to time of the run + time_t now = time(nullptr); + info.setStartValidityTimestamp(now); + info.setEndValidityTimestamp(99999999999999); + std::map<std::string, std::string> md; + info.setMetaData(md); + + LOG(INFO) << "Sending object CPV/Calib/CalibParams"; + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_CalibParams", subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_CalibParams", subSpec}, info); + } + + //Write either final spectra (to calculate bad map) or temporary file + if (mUpdateCCDB) { //good statistics, final spectra + std::string filename = mPath + "CPVGains"; + time_t now = time(nullptr); + tm* ltm = localtime(&now); + filename += TString::Format("_%d%d%d%d%d.root", 1 + ltm->tm_min, 1 + ltm->tm_hour, ltm->tm_mday, 1 + ltm->tm_mon, 1970 + ltm->tm_year); + LOG(DEBUG) << "opening file " << filename.data(); + TFile fout(filename.data(), "RECREATE"); + mMean->Write(); + fout.Close(); + } else { + std::string filename = mPath + "CPVGains.root"; + LOG(INFO) << "statistics not sufficient yet: " << mMean->Integral() / mMean->GetNbinsX() << ", writing file " << filename; + TFile fout(filename.data(), "RECREATE"); + mMean->Write(); + fout.Close(); + } + //Anyway send change to QC + output.snapshot(o2::framework::Output{"CPV", "GAINDIFF", 0, o2::framework::Lifetime::Timeframe}, mGainRatio); +} + +void CPVGainCalibDevice::calculateGains() +{ + //Check if statistics is sufficient to fit distributions + //Mean statistics should be ~2 times larger than minimal + mUpdateCCDB = false; + if (mMean->Integral() > 2 * kMinimalStatistics * (o2::cpv::Geometry::kNCHANNELS)) { //average per channel + mCalibParams.reset(new CalibParams()); + + TF1* fitFunc = new TF1("fitFunc", "landau", 0., 4000.); + fitFunc->SetParameters(1., 200., 60.); + fitFunc->SetParLimits(1, 10., 2000.); + for (int i = 1; i <= mMean->GetNbinsX(); i++) { + TH1D* tmp = mMean->ProjectionY(Form("channel%d", i), i, i); + fitFunc->SetParameters(1., 200., 60.); + if (tmp->Integral(20, 2000) < kMinimalStatistics) { + tmp->Delete(); + continue; + } + tmp->Fit(fitFunc, "QL0", "", 20., 2000.); + float a = fitFunc->GetParameter(1); + if (a > 0) { + a = 200. / a; + mCalibParams->setGain(i - 1, a); //absId starts from 0 + } + tmp->Delete(); + } + mUpdateCCDB = true; + //TODO: if file historam processed, remove temporary root file if it exists + } +} + +void CPVGainCalibDevice::checkGains() +{ + //Estimate if newly calculated gains are reasonable: close to reviously calculated + // Do not update existing object automatically if difference is too strong + // create object with validity range if far future (?) and send warning (e-mail?) to operator + + if (!mUpdateCCDB) { //gains were not calculated, do nothing + return; + } + + if (mUseCCDB) { // read calibration objects from ccdb + // //TODO: + // //Get current calibration + // int nChanged=0; + // for(short i=o2::cpv::Geometry::kNCHANNELS; --i;){ + // short dp=2. + // if(oldPed.getGain(i)>0) { + // dp = mCalibParams.getGain(i)/oldPed.getGain(i); + // } + // mGainRatio[i]=dp ; + // if(abs(dp-1.)>0.1){ //not a fluctuation + // nChanged++; + // } + // } + // if(nChanged>kMinorChange){ //serious change, do not update CCDB automatically, use "force" option to overwrite + // mUpdateCCDB=false; + // } + // else{ + // mUpdateCCDB=true; + // } + } +} + +o2::framework::DataProcessorSpec o2::cpv::getGainCalibSpec(bool useCCDB, bool forceUpdate, std::string path) +{ + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_CalibParams"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_CalibParams"}); + + outputs.emplace_back("CPV", "GAINDIFF", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"GainCalibSpec", + o2::framework::select("A:CPV/RAWDATA"), + outputs, + o2::framework::adaptFromTask<CPVGainCalibDevice>(useCCDB, forceUpdate, path), + o2::framework::Options{}}; +} diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVPedestalCalibDevice.cxx b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVPedestalCalibDevice.cxx new file mode 100644 index 0000000000000..d13e3a3db4111 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/src/CPVPedestalCalibDevice.cxx @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVCalibWorkflow/CPVPedestalCalibDevice.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/InputRecordWalker.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "CPVReconstruction/RawReaderMemory.h" +#include "CPVReconstruction/RawDecoder.h" +#include "CPVBase/Geometry.h" + +using namespace o2::cpv; + +void CPVPedestalCalibDevice::init(o2::framework::InitContext& ic) +{ + + //Create histograms for mean and RMS + short n = 3 * o2::cpv::Geometry::kNumberOfCPVPadsPhi * o2::cpv::Geometry::kNumberOfCPVPadsZ; + mMean = std::unique_ptr<TH2F>(new TH2F("Mean", "Mean", n, 0.5, n + 0.5, 500, 0., 500.)); +} + +void CPVPedestalCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + + // + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs())) { + + o2::cpv::RawReaderMemory rawreader(o2::framework::DataRefUtils::as<const char>(rawData)); + // loop over all the DMA pages + while (rawreader.hasNext()) { + try { + rawreader.next(); + } catch (RawErrorType_t e) { + LOG(ERROR) << "Raw decoding error " << (int)e; + //if problem in header, abandon this page + if (e == RawErrorType_t::kRDH_DECODING) { + break; + } + //if problem in payload, try to continue + continue; + } + auto& header = rawreader.getRawHeader(); + auto triggerBC = o2::raw::RDHUtils::getTriggerBC(header); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(header); + // use the decoder to decode the raw data, and extract signals + o2::cpv::RawDecoder decoder(rawreader); + RawErrorType_t err = decoder.decode(); + if (err != kOK) { + //TODO handle severe errors + continue; + } + // Loop over all the channels + for (auto adch : decoder.getDigits()) { + AddressCharge ac = {adch}; + unsigned short absId = ac.Address; + mMean->Fill(absId, ac.Charge); + } + } //RawReader::hasNext + } +} + +void CPVPedestalCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + LOG(INFO) << "[CPVPedestalCalibDevice - endOfStream]"; + //calculate stuff here + calculatePedestals(); + checkPedestals(); + sendOutput(ec.outputs()); +} + +void CPVPedestalCalibDevice::sendOutput(DataAllocator& output) +{ + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + // using clbUtils = o2::calibration::Utils; + if (mUpdateCCDB || mForceUpdate) { + // prepare all info to be sent to CCDB + o2::ccdb::CcdbObjectInfo info; + auto image = o2::ccdb::CcdbApi::createObjectImage(mPedestals.get(), &info); + + auto flName = o2::ccdb::CcdbApi::generateFileName("Pedestals"); + info.setPath("CPV/Calib/Pedestals"); + info.setObjectType("Pedestals"); + info.setFileName(flName); + // TODO: should be changed to time of the run + const auto now = std::chrono::system_clock::now(); + long timeStart = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count(); + info.setStartValidityTimestamp(timeStart); + info.setEndValidityTimestamp(99999999999999); + std::map<std::string, std::string> md; + info.setMetaData(md); + + LOG(INFO) << "Sending object CPV/Calib/Pedestals"; + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_PEDESTALS", subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_PEDESTALS", subSpec}, info); + } + //Anyway send change to QC + LOG(INFO) << "[CPVPedestalCalibDevice - run] Writing "; + output.snapshot(o2::framework::Output{"CPV", "PEDDIFF", 0, o2::framework::Lifetime::Timeframe}, mPedDiff); + + //Write pedestal distributions to calculate bad map + std::string filename = mPath + "CPVPedestals.root"; + TFile f(filename.data(), "RECREATE"); + mMean->Write(); + f.Close(); +} + +void CPVPedestalCalibDevice::calculatePedestals() +{ + + mPedestals.reset(new Pedestals()); + + //Calculate mean of pedestal distributions + for (unsigned short i = mMean->GetNbinsX(); i > 0; i--) { + TH1D* pr = mMean->ProjectionY(Form("proj%d", i), i, i); + short pedMean = std::min(255, int(pr->GetMean())); + pr->Delete(); + mPedestals->setPedestal(i - 1, pedMean); + } +} + +void CPVPedestalCalibDevice::checkPedestals() +{ + //Compare pedestals to current ones stored in CCDB + //and send difference to QC to check + if (!mUseCCDB) { + mUpdateCCDB = true; + return; + } + // //TODO: + // //Get current map + // int nChanged=0; + // for(short i=o2::cpv::Geometry::kNCHANNELS; --i;){ + // short dp=mPedestals.getPedestal(i)-oldPed.getPedestal(i); + // mPedDiff[i]=dp ; + // if(abs(dp)>1){ //not a fluctuation + // nChanged++; + // } + // } + // if(nChanged>kMinorChange){ //serious change, do not update CCDB automatically, use "force" option to overwrite + // mUpdateCCDB=false; + // } + // else{ + // mUpdateCCDB=true; + // } +} + +o2::framework::DataProcessorSpec o2::cpv::getPedestalCalibSpec(bool useCCDB, bool forceUpdate, std::string path) +{ + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_PEDESTALS"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_PEDESTALS"}); + + outputs.emplace_back("CPV", "PEDDIFF", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"PedestalCalibSpec", + o2::framework::select("A:CPV/RAWDATA"), + outputs, + o2::framework::adaptFromTask<CPVPedestalCalibDevice>(useCCDB, forceUpdate, path), + o2::framework::Options{}}; +} diff --git a/Detectors/CPV/calib/CPVCalibWorkflow/src/cpv-calib-workflow.cxx b/Detectors/CPV/calib/CPVCalibWorkflow/src/cpv-calib-workflow.cxx new file mode 100644 index 0000000000000..600e8aac7a3b8 --- /dev/null +++ b/Detectors/CPV/calib/CPVCalibWorkflow/src/cpv-calib-workflow.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVCalibWorkflow/CPVPedestalCalibDevice.h" +#include "CPVCalibWorkflow/CPVGainCalibDevice.h" +#include "CPVCalibWorkflow/CPVBadMapCalibDevice.h" +#include "Framework/DataProcessorSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// // we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb cpv calibration objects"}}); + workflowOptions.push_back(ConfigParamSpec{"forceupdate", o2::framework::VariantType::Bool, false, {"update ccdb even difference to previous object large"}}); + workflowOptions.push_back(ConfigParamSpec{"pedestals", o2::framework::VariantType::Bool, false, {"do pedestal calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"gains", o2::framework::VariantType::Bool, false, {"do gain calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"badmap", o2::framework::VariantType::Bool, false, {"do bad map calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"path", o2::framework::VariantType::String, "./", {"path to store temp files"}}); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); +} + +// ------------------------------------------------------------------ +// we need to add workflow options before including Framework/runDataProcessing +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto useCCDB = configcontext.options().get<bool>("use-ccdb"); + auto forceUpdate = configcontext.options().get<bool>("forceupdate"); + auto doPedestals = configcontext.options().get<bool>("pedestals"); + auto doGain = configcontext.options().get<bool>("gains"); + auto doBadMap = configcontext.options().get<bool>("badmap"); + auto path = configcontext.options().get<std::string>("path"); + if (doPedestals && doGain) { + LOG(FATAL) << "Can not run pedestal and gain calibration simulteneously"; + } + + LOG(INFO) << "CPV Calibration workflow: options"; + LOG(INFO) << "useCCDB = " << useCCDB; + if (doPedestals) { + LOG(INFO) << "pedestals "; + specs.emplace_back(o2::cpv::getPedestalCalibSpec(useCCDB, forceUpdate, path)); + } else { + if (doGain) { + LOG(INFO) << "gain calculation"; + specs.emplace_back(o2::cpv::getGainCalibSpec(useCCDB, forceUpdate, path)); + } + } + if (doBadMap) { + LOG(INFO) << "bad map calculation "; + short m = 0; + specs.emplace_back(o2::cpv::getBadMapCalibSpec(useCCDB, forceUpdate, path, m)); + } + return specs; +} diff --git a/Detectors/CPV/calib/include/CPVCalib/CalibParams.h b/Detectors/CPV/calib/include/CPVCalib/CalibParams.h deleted file mode 100644 index aa9f6ff27e898..0000000000000 --- a/Detectors/CPV/calib/include/CPVCalib/CalibParams.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \class CalibParams -/// \brief CCDB container for the full set of CPV calibration coefficients -/// \author Dmitri Peresunko, RRC Kurchatov institute -/// \since Aug. 1, 2019 -/// -/// - -#ifndef CPV_CALIBPARAMS_H -#define CPV_CALIBPARAMS_H - -#include <array> -#include "TObject.h" - -class TH2; - -namespace o2 -{ - -namespace cpv -{ - -class CalibParams -{ - public: - /// \brief Constructor - CalibParams() = default; - - /// \brief Constructor for tests - CalibParams(int test); - - /// \brief Destructor - ~CalibParams() = default; - - /// \brief Get High Gain energy calibration coefficients - /// \param cellID Absolute ID of cell - /// \return high gain energy calibration coefficient of the cell - float getGain(short cellID) const { return mGainCalib[cellID]; } - - /// \brief Set High Gain energy calibration coefficient - /// \param cellID Absolute ID of cell - /// \param c is the calibration coefficient - void setGain(short cellID, float c) { mGainCalib[cellID] = c; } - - /// \brief Set High Gain energy calibration coefficients for one module in the form of 2D histogram - /// \param 2D(64,56) histogram with calibration coefficients - /// \param module number - /// \return Is successful - bool setGain(TH2* h, char module); - - private: - static constexpr short NCHANNELS = 28673; ///< Number of channels starting from 1 - std::array<float, NCHANNELS> mGainCalib; ///< Container for the gain calibration coefficients - ClassDefNV(CalibParams, 1); -}; - -} // namespace cpv - -} // namespace o2 -#endif diff --git a/Detectors/CPV/calib/include/CPVCalibration/PedestalCalibrator.h b/Detectors/CPV/calib/include/CPVCalibration/PedestalCalibrator.h new file mode 100644 index 0000000000000..38788098b0866 --- /dev/null +++ b/Detectors/CPV/calib/include/CPVCalibration/PedestalCalibrator.h @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef CPV_PEDESTAL_CALIBRATIOR_H_ +#define CPV_PEDESTAL_CALIBRATIOR_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/Pedestals.h" +#include "CCDB/CcdbObjectInfo.h" +//#include "TString.h" + +namespace o2 +{ +namespace cpv +{ +using Digit = o2::cpv::Digit; + +//=================================================================== +class PedestalSpectrum +{ + public: + PedestalSpectrum(); + ~PedestalSpectrum() = default; + PedestalSpectrum& operator+=(const PedestalSpectrum& rhs); + void fill(uint16_t amplitude); + uint8_t getNPeaks(); + float getPeakMean(uint8_t iPeak = -1); // return mean value of i-th peak. if iPeak = -1 then return total mean + float getPeakRMS(uint8_t iPeak = -1); // return RMS value of i-th peak. if iPeak = -1 then return total RMS + float getPedestalValue(); // return final decision for pedestal value + float getPedestalRMS(); // return final decision for pedestal RMS + uint32_t getNEntries() { return mNEntries; } + + private: + void analyze(); + uint32_t mNEntries = 0; + uint8_t mNPeaks = 0; + bool mIsAnalyzed = false; + uint16_t mToleratedGapWidth = 5; + float mZSnSigmas = 3.; + float mSuspiciousPedestalRMS = 10.; + float mPedestalValue; + float mPedestalRMS; + std::vector<float> mMeanOfPeaks, mRMSOfPeaks; + std::vector<uint32_t> mPeakCounts; + std::map<uint16_t, uint32_t> mSpectrumContainer; +}; // end PedestalSpectrum + +//=================================================================== +struct PedestalCalibData { + int mNEvents = 0; + std::vector<PedestalSpectrum> mPedestalSpectra; + + PedestalCalibData(); + ~PedestalCalibData() = default; + + void fill(const gsl::span<const o2::cpv::Digit> data); + void merge(const PedestalCalibData* prev); + void print(); + +}; //end PedestalCalibData + +using TimeSlot = o2::calibration::TimeSlot<o2::cpv::PedestalCalibData>; +//=================================================================== +class PedestalCalibrator final : public o2::calibration::TimeSlotCalibration<o2::cpv::Digit, o2::cpv::PedestalCalibData> +{ + public: + PedestalCalibrator(); + ~PedestalCalibrator() final = default; + std::vector<o2::ccdb::CcdbObjectInfo> getCcdbInfoVector() { return mCcdbInfoVec; } + std::vector<o2::cpv::Pedestals> getPedestalsVector() { return mPedestalsVec; } + bool hasEnoughData(const TimeSlot& slot) const final + { + LOG(INFO) << "hasEnoughData() is being called"; + return slot.getContainer()->mNEvents >= mMinEvents; + } + void initOutput() final; + void finalizeSlot(TimeSlot& slot) final; + TimeSlot& emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) final; + + private: + int mMinEvents = 100; + std::vector<o2::ccdb::CcdbObjectInfo> mCcdbInfoVec; + std::vector<o2::cpv::Pedestals> mPedestalsVec; +}; +} //end namespace cpv +} //end namespace o2 + +#endif /* CPV_PEDESTAL_CALIBRATIOR_H_ */ \ No newline at end of file diff --git a/Detectors/CPV/calib/macros/PostBadMapCCDB.C b/Detectors/CPV/calib/macros/PostBadMapCCDB.C index 538807c2df60e..6aae7a54d4281 100644 --- a/Detectors/CPV/calib/macros/PostBadMapCCDB.C +++ b/Detectors/CPV/calib/macros/PostBadMapCCDB.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,7 @@ #if !defined(__CLING__) || defined(__ROOTCLING__) #include "TRandom.h" #include "CCDB/CcdbApi.h" -#include "CPVCalib/BadChannelMap.h" +#include "DataFormatsCPV/BadChannelMap.h" #include "CPVBase/Geometry.h" #endif void PostBadMapCCDB() diff --git a/Detectors/CPV/calib/macros/PostCalibCCDB.C b/Detectors/CPV/calib/macros/PostCalibCCDB.C index f159d2b548e7f..ec70da8885b1b 100644 --- a/Detectors/CPV/calib/macros/PostCalibCCDB.C +++ b/Detectors/CPV/calib/macros/PostCalibCCDB.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #include "TFile.h" #include "TH2F.h" #include "CCDB/CcdbApi.h" -#include "CPVCalib/CalibParams.h" +#include "DataFormatsCPV/CalibParams.h" #include "CPVBase/Geometry.h" #include <iostream> #endif diff --git a/Detectors/CPV/calib/macros/readPedestalsFromCCDB.C b/Detectors/CPV/calib/macros/readPedestalsFromCCDB.C new file mode 100644 index 0000000000000..5b5c70a6736e7 --- /dev/null +++ b/Detectors/CPV/calib/macros/readPedestalsFromCCDB.C @@ -0,0 +1,67 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/BasicCCDBManager.h" +#include "TH2F.h" +#include "TH1F.h" +#include "TCanvas.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "DataFormatsCPV/Pedestals.h" +#include "CPVBase/Geometry.h" +#include <iostream> +#endif + +o2::cpv::Pedestals* readPedestalsFromCCDB(long timeStamp = 0, const char* ccdbURI = "http://ccdb-test.cern.ch:8080") +{ + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + ccdbMgr.setURL(ccdbURI); + if (!ccdbMgr.isHostReachable()) { + std::cerr << ccdbURI << " is not reachable!" << std::endl; + return 0x0; + } + if (timeStamp == 0) { + timeStamp = o2::ccdb::getCurrentTimestamp(); + } + ccdbMgr.setTimestamp(timeStamp); + o2::cpv::Pedestals* peds = ccdbMgr.get<o2::cpv::Pedestals>("CPV/Calib/Pedestals"); + if (!peds) { + std::cerr << "Cannot get pedestals from CCDB/CPV/Calib/Pedestals!" << std::endl; + return 0x0; + } + + TH2F* hPedValues[3]; + TH2F* hPedSigmas[3]; + TH1F *hPedValues1D[3], *hPedSigmas1D[3]; + o2::cpv::Geometry geo; + short relId[3]; + for (int iMod = 0; iMod < 3; iMod++) { + hPedValues[iMod] = new TH2F(Form("hPedValuesM%d", iMod + 2), + Form("Pedestal values in M%d", iMod + 2), + 128, 0., 128., 60, 0., 60); + hPedSigmas[iMod] = new TH2F(Form("hPedSigmasM%d", iMod + 2), + Form("Pedestal sigmas in M%d", iMod + 2), + 128, 0., 128., 60, 0., 60); + hPedValues1D[iMod] = new TH1F(Form("hPedValues1DM%d", iMod + 2), + Form("Pedestal values in M%d", iMod + 2), + 1000, 0., 1000.); + hPedSigmas1D[iMod] = new TH1F(Form("hPedSigmas1DM%d", iMod + 2), + Form("Pedestal sigmas in M%d", iMod + 2), + 1000, 0., 1000.); + for (int iCh = iMod * 7680; iCh < (iMod + 1) * 7680; iCh++) { + geo.absToRelNumbering(iCh, relId); + hPedValues[iMod]->SetBinContent(relId[1] + 1, relId[2] + 1, peds->getPedestal(iCh)); + hPedSigmas[iMod]->SetBinContent(relId[1] + 1, relId[2] + 1, peds->getPedSigma(iCh)); + hPedValues1D[iMod]->Fill(peds->getPedestal(iCh)); + hPedSigmas1D[iMod]->Fill(peds->getPedSigma(iCh)); + } + TCanvas* can = new TCanvas(Form("canM%d", iMod + 2), Form("module M%d", iMod + 2), 10 * iMod, 0, 1000 + 10 * iMod, 1000); + can->Divide(2, 2); + can->cd(1); + hPedValues[iMod]->Draw("colz"); + can->cd(2); + hPedSigmas[iMod]->Draw("colz"); + can->cd(3); + hPedValues1D[iMod]->Draw(); + can->cd(4); + hPedSigmas1D[iMod]->Draw(); + } + return peds; +} diff --git a/Detectors/CPV/calib/src/BadChannelMap.cxx b/Detectors/CPV/calib/src/BadChannelMap.cxx deleted file mode 100644 index 92bf6f77f2cb1..0000000000000 --- a/Detectors/CPV/calib/src/BadChannelMap.cxx +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "CPVBase/Geometry.h" -#include "CPVCalib/BadChannelMap.h" - -#include "FairLogger.h" - -#include <TH2.h> - -#include <iostream> - -using namespace o2::cpv; - -BadChannelMap::BadChannelMap(int /*dummy*/) -{ - - //Mark few channels as bad for test peurposes - for (short i = 0; i < 60; i++) { - //module 2 - short channelID = 3584 + i * 57; - mBadCells.set(channelID); - channelID = 3640 + i * 55; - mBadCells.set(channelID); - } - - for (short i = 0; i < 16; i++) { - //module 3 - int channelID = 8972 + i * 57; - mBadCells.set(channelID); - channelID = 8092 + i * 57; - mBadCells.set(channelID); - channelID = 8147 + i * 55; - mBadCells.set(channelID); - channelID = 9059 + i * 55; - mBadCells.set(channelID); - } -} - -void BadChannelMap::getHistogramRepresentation(char module, TH2* h) const -{ - if (!h) { - LOG(ERROR) << "provide histogram to be filled"; - } - - const short MAXX = 128, - MAXZ = 60; - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return; - } - - h->Reset(); - - short relid[3] = {module, 1, 1}; - short absId; - for (short ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (short iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - if (Geometry::relToAbsNumbering(relid, absId)) { - if (!isChannelGood(absId)) { - h->SetBinContent(ix, iz, 1); - } - } - } - } -} - -void BadChannelMap::PrintStream(std::ostream& stream) const -{ - // first sort bad channel IDs - stream << "Number of bad cells: " << mBadCells.count() << "\n"; - for (int cellID = 0; cellID < mBadCells.size(); cellID++) { - if (mBadCells.test(cellID)) { - stream << cellID << "\n"; - } - } -} - -std::ostream& o2::cpv::operator<<(std::ostream& stream, const BadChannelMap& bcm) -{ - bcm.PrintStream(stream); - return stream; -} diff --git a/Detectors/CPV/calib/src/CPVCalibLinkDef.h b/Detectors/CPV/calib/src/CPVCalibLinkDef.h deleted file mode 100644 index abcf7bc777bd6..0000000000000 --- a/Detectors/CPV/calib/src/CPVCalibLinkDef.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::cpv::BadChannelMap + ; -#pragma link C++ class o2::TObjectWrapper < o2::cpv::BadChannelMap> + ; -#pragma link C++ class o2::cpv::CalibParams + ; -#pragma link C++ class o2::TObjectWrapper < o2::cpv::CalibParams> + ; - -#endif diff --git a/Detectors/CPV/calib/src/CPVCalibrationLinkDef.h b/Detectors/CPV/calib/src/CPVCalibrationLinkDef.h new file mode 100644 index 0000000000000..7e0749fcfa773 --- /dev/null +++ b/Detectors/CPV/calib/src/CPVCalibrationLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::cpv::PedestalSpectrum + ; +#pragma link C++ class o2::cpv::PedestalCalibData + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::cpv::PedestalCalibData> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::cpv::Digit, o2::cpv::PedestalCalibData> + ; +#pragma link C++ class o2::cpv::PedestalCalibrator + ; + +#endif \ No newline at end of file diff --git a/Detectors/CPV/calib/src/CalibParams.cxx b/Detectors/CPV/calib/src/CalibParams.cxx deleted file mode 100644 index f7de1a259f88a..0000000000000 --- a/Detectors/CPV/calib/src/CalibParams.cxx +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "CPVCalib/CalibParams.h" -#include "CPVBase/Geometry.h" - -#include "FairLogger.h" - -#include <TH2.h> - -#include <iostream> - -using namespace o2::cpv; - -CalibParams::CalibParams(int /*dummy*/) -{ - //produce reasonable objest for test purposes - mGainCalib.fill(0.005); -} - -bool CalibParams::setGain(TH2* h, char module) -{ - const short MAXX = 128, - MAXZ = 56; - if (!h) { - LOG(ERROR) << "no input histogam"; - return false; - } - - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return false; - } - - short relid[3] = {module, 1, 1}; - short absId; - for (short ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (short iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - - if (Geometry::relToAbsNumbering(relid, absId)) { - mGainCalib[absId] = h->GetBinContent(ix, iz); - } - } - } - return true; -} diff --git a/Detectors/CPV/calib/src/PedestalCalibrator.cxx b/Detectors/CPV/calib/src/PedestalCalibrator.cxx new file mode 100644 index 0000000000000..f4112f5bf73fe --- /dev/null +++ b/Detectors/CPV/calib/src/PedestalCalibrator.cxx @@ -0,0 +1,262 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "CPVCalibration/PedestalCalibrator.h" +#include "CommonUtils/MemFileHelper.h" +#include "DetectorsCalibration/Utils.h" +#include "CPVBase/Geometry.h" +#include "CPVBase/CPVSimParams.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CCDBTimeStampUtils.h" + +namespace o2 +{ +namespace cpv +{ +//=======================PedestalSpectrum============================ +//___________________________________________________________________ +PedestalSpectrum::PedestalSpectrum() +{ + auto& cpvParams = o2::cpv::CPVSimParams::Instance(); + mToleratedGapWidth = cpvParams.mPedClbToleratedGapWidth; + mZSnSigmas = cpvParams.mZSnSigmas; + mSuspiciousPedestalRMS = cpvParams.mPedClbSuspiciousPedestalRMS; +} +//___________________________________________________________________ +PedestalSpectrum& PedestalSpectrum::operator+=(const PedestalSpectrum& rhs) +{ + mIsAnalyzed = false; + mNEntries += rhs.mNEntries; + for (auto iAmpl = rhs.mSpectrumContainer.begin(); iAmpl != rhs.mSpectrumContainer.end(); iAmpl++) { + mSpectrumContainer[iAmpl->first] += iAmpl->second; + } + return *this; // return the result by reference +} +//___________________________________________________________________ +void PedestalSpectrum::fill(uint16_t amplitude) +{ + mSpectrumContainer[amplitude]++; + mNEntries++; + if (mIsAnalyzed) { + mIsAnalyzed = false; + } +} +//___________________________________________________________________ +void PedestalSpectrum::analyze() +{ + if (mIsAnalyzed || mNEntries == 0) { //already analyzed or no statistics + return; + } + // (A)typical amplitude spectrum from 1 channel in pedestal run + // ^ counts peak2 + // | | + // | peak1 | + // | | | + // | | || peak3 + // | || || | + // | ||| |||| |<----non-tolerated gap---->|| + // --------------------------------------------------------------------------> + // 0 10 ^ 20 30 ADC amplitude + // tolerated gap + // we want to find all the peaks, determine their mean and rms + // and mean and rms of all the distribution + std::vector<uint16_t> peakLowEdge, peakHighEdge; + peakLowEdge.push_back(mSpectrumContainer.begin()->first); + peakHighEdge.push_back((--mSpectrumContainer.end())->first); + uint32_t peakCounts(0); + float peakSumA(0.), peakSumA2(0.), totalSumA(0.), totalSumA2(0.); + + auto iNextAmpl = mSpectrumContainer.begin(); + iNextAmpl++; + for (auto iAmpl = mSpectrumContainer.begin(); iAmpl != mSpectrumContainer.end(); iAmpl++, iNextAmpl++) { + peakCounts += iAmpl->second; + peakSumA += iAmpl->first * iAmpl->second; // mean = sum [A_i * w_i], where A_i is ADC amplitude, w_i is weight = (binCount/totalCount) + peakSumA2 += (iAmpl->first * iAmpl->first) * iAmpl->second; // rms = sum [(A_i)^2 * w_i] - mean^2 + totalSumA += iAmpl->first * iAmpl->second; + totalSumA2 += (iAmpl->first * iAmpl->first) * iAmpl->second; + if ((iAmpl->first - iNextAmpl->first) > mToleratedGapWidth) { // let's consider |bin1-bin2|<=5 belong to same peak + // firts, save peak low and high edge (just for the future cases) + if (iNextAmpl != mSpectrumContainer.end()) { + peakLowEdge.push_back(iNextAmpl->first); + } + peakHighEdge.push_back(iAmpl->first); + // + mMeanOfPeaks.push_back(peakSumA / peakCounts); + mRMSOfPeaks.push_back(sqrt(peakSumA2 / peakCounts - mMeanOfPeaks.back() * mMeanOfPeaks.back())); + mPeakCounts.push_back(peakCounts); + mNPeaks++; + } + } + // last element of mPeakCounts, mMeanOfPeaks and mRMSOfPeaks is total count, mean and rms + mMeanOfPeaks.push_back(totalSumA / mNEntries); + mRMSOfPeaks.push_back(sqrt(totalSumA2 / mNEntries - mMeanOfPeaks.back() * mMeanOfPeaks.back())); + mPeakCounts.push_back(mNEntries); + + //final decision on pedestal value and RMS + if (mNPeaks == 1) { //everything seems to be good + mPedestalValue = mMeanOfPeaks.back(); + mPedestalRMS = mRMSOfPeaks.back(); + if ((mPedestalRMS > mSuspiciousPedestalRMS) && ((mPedestalValue + mPedestalRMS * mZSnSigmas) < peakHighEdge.back())) { + mPedestalRMS = (peakHighEdge.back() - mPedestalValue) / mZSnSigmas; + } + } else { //there are some problems with several pedestal peaks + mPedestalValue = mMeanOfPeaks.back(); // total mean of distribution + mPedestalRMS = mRMSOfPeaks.back(); // total RMS of distribution + if ((mPedestalValue + mPedestalRMS * mZSnSigmas) < peakHighEdge.back()) { + mPedestalRMS = (peakHighEdge.back() - mPedestalValue) / mZSnSigmas; + } + } + if (mPedestalRMS < 1. / mZSnSigmas) { + float epsilon = fabs(float(1. - (1. / mZSnSigmas) * mZSnSigmas)); + mPedestalRMS = (1. / mZSnSigmas) + epsilon; // just to be sure that mPedestalRMS * mZSnSigmas >= 1. + } + mIsAnalyzed = true; +} +//___________________________________________________________________ +uint8_t PedestalSpectrum::getNPeaks() +{ + if (!mIsAnalyzed) { + analyze(); + } + return mNPeaks; +} +//___________________________________________________________________ +float PedestalSpectrum::getPeakMean(uint8_t iPeak) +{ + if (!mIsAnalyzed) { + analyze(); + } + if (iPeak < 0) { + return mMeanOfPeaks.back(); + } else if (iPeak < mNPeaks) { + return mMeanOfPeaks.at(iPeak); + } else { + return -1000.; + } +} +//___________________________________________________________________ +float PedestalSpectrum::getPeakRMS(uint8_t iPeak) +{ + if (!mIsAnalyzed) { + analyze(); + } + if (iPeak < 0) { + return mRMSOfPeaks.back(); + } else if (iPeak < mNPeaks) { + return mRMSOfPeaks.at(iPeak); + } else { + return -1000.; + } +} +//___________________________________________________________________ +float PedestalSpectrum::getPedestalValue() +{ + if (!mIsAnalyzed) { + analyze(); + } + return mPedestalValue; +} +//___________________________________________________________________ + +float PedestalSpectrum::getPedestalRMS() +{ + if (!mIsAnalyzed) { + analyze(); + } + return mPedestalRMS; +} +//___________________________________________________________________ + +//========================PedestalCalibData========================== +//___________________________________________________________________ +PedestalCalibData::PedestalCalibData() +{ + for (int i = 0; i < Geometry::kNCHANNELS; i++) { + mPedestalSpectra.emplace_back(); + } +} +//___________________________________________________________________ +void PedestalCalibData::fill(const gsl::span<const Digit> digits) +{ + for (auto& dig : digits) { + mPedestalSpectra[dig.getAbsId()].fill(dig.getAmplitude()); + } + mNEvents++; +} +//___________________________________________________________________ +void PedestalCalibData::merge(const PedestalCalibData* prev) +{ + for (int i = 0; i < Geometry::kNCHANNELS; i++) { + mPedestalSpectra[i] += prev->mPedestalSpectra[i]; + } + mNEvents += prev->mNEvents; + LOG(INFO) << "Merged TimeSlot with previous one. Now we have " << mNEvents << " events."; +} +//___________________________________________________________________ +void PedestalCalibData::print() +{ + LOG(INFO) << "PedestalCalibData::mNEvents = " << mNEvents; +} +//___________________________________________________________________ +//=======================PedestalCalibrator========================== +//___________________________________________________________________ +PedestalCalibrator::PedestalCalibrator() +{ + auto& cpvParams = o2::cpv::CPVSimParams::Instance(); + mMinEvents = cpvParams.mPedClbMinEvents; +} +//___________________________________________________________________ +void PedestalCalibrator::initOutput() +{ + mCcdbInfoVec.clear(); + mPedestalsVec.clear(); +} +//___________________________________________________________________ +void PedestalCalibrator::finalizeSlot(TimeSlot& slot) +{ + auto& cpvParams = o2::cpv::CPVSimParams::Instance(); + auto& toleratedChannelEfficiencyLow = cpvParams.mPedClbToleratedChannelEfficiencyLow; + auto& toleratedChannelEfficiencyHigh = cpvParams.mPedClbToleratedChannelEfficiencyHigh; + + PedestalCalibData* calibData = slot.getContainer(); + LOG(INFO) << "PedestalCalibrator::finalizeSlot() : finalizing slot " + << slot.getTFStart() << " <= TF <= " << slot.getTFEnd() << " with " << calibData->mNEvents << " events."; + o2::cpv::Pedestals* peds = new o2::cpv::Pedestals(); + for (int i = 0; i < Geometry::kNCHANNELS; i++) { + short ped = std::round(calibData->mPedestalSpectra[i].getPedestalValue()); + ped = (ped > 511) ? 511 : ped; + float sigma = calibData->mPedestalSpectra[i].getPedestalRMS(); + float efficiency = calibData->mPedestalSpectra[i].getNEntries() / calibData->mNEvents; + //TODO: decide what we do with efficiency? + //somehow it should be propogated to BadChannelMap + peds->setPedestal(i, ped); + peds->setPedSigma(i, sigma); + } + mPedestalsVec.push_back(*peds); + + std::map<std::string, std::string> metaData; + auto className = o2::utils::MemFileHelper::getClassName(peds); + auto fileName = o2::ccdb::CcdbApi::generateFileName(className); + auto timeStamp = o2::ccdb::getCurrentTimestamp(); + mCcdbInfoVec.emplace_back("CPV/Calib/Pedestals", className, fileName, metaData, timeStamp, timeStamp + 31536000); // one year validity time +} +//___________________________________________________________________ +TimeSlot& PedestalCalibrator::emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<PedestalCalibData>()); + return slot; +} +//___________________________________________________________________ +} //end namespace cpv +} //end namespace o2 \ No newline at end of file diff --git a/Detectors/CPV/calib/testWorkflow/PedestalCalibratorSpec.h b/Detectors/CPV/calib/testWorkflow/PedestalCalibratorSpec.h new file mode 100644 index 0000000000000..c99fc441a0e59 --- /dev/null +++ b/Detectors/CPV/calib/testWorkflow/PedestalCalibratorSpec.h @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/Utils.h" +#include "CPVCalibration/PedestalCalibrator.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace calibration +{ +class CPVPedestalCalibDevice : public o2::framework::Task +{ + public: + //_________________________________________________________________ + void init(o2::framework::InitContext& ic) final + { + uint64_t slotL = ic.options().get<uint64_t>("tf-per-slot"); + uint64_t delay = ic.options().get<uint64_t>("max-delay"); + uint64_t updateInterval = ic.options().get<uint64_t>("updateInterval"); + bool updateAtTheEndOfRunOnly = ic.options().get<bool>("updateAtTheEndOfRunOnly"); + mCalibrator = std::make_unique<o2::cpv::PedestalCalibrator>(); + mCalibrator->setSlotLength(slotL); + mCalibrator->setMaxSlotsDelay(delay); + if (updateAtTheEndOfRunOnly) { + mCalibrator->setUpdateAtTheEndOfRunOnly(); + } + mCalibrator->setCheckIntervalInfiniteSlot(updateInterval); + LOG(INFO) << "CPVPedestalCalibDevice initialized"; + LOG(INFO) << "tf-per-slot = " << slotL; + LOG(INFO) << "max-delay = " << delay; + LOG(INFO) << "updateInterval = " << updateInterval; + LOG(INFO) << "updateAtTheEndOfRunOnly = " << updateAtTheEndOfRunOnly; + } + //_________________________________________________________________ + void run(o2::framework::ProcessingContext& pc) final + { + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("digits").header)->startTime; + auto&& digits = pc.inputs().get<gsl::span<o2::cpv::Digit>>("digits"); + auto&& trigrecs = pc.inputs().get<gsl::span<o2::cpv::TriggerRecord>>("trigrecs"); + LOG(INFO) << "Processing TF " << tfcounter << " with " << digits.size() << " digits in " << trigrecs.size() << " trigger records."; + auto& slotTF = mCalibrator->getSlotForTF(tfcounter); + + for (auto trigrec = trigrecs.begin(); trigrec != trigrecs.end(); trigrec++) { //event loop + // here we're filling TimeSlot event by event + // and when last event is reached we call mCalibrator->process() to finalize the TimeSlot + auto&& digitsInOneEvent = digits.subspan((*trigrec).getFirstEntry(), (*trigrec).getNumberOfObjects()); + if ((trigrec + 1) == trigrecs.end()) { //last event in current TF, let's process corresponding TimeSlot + //LOG(INFO) << "last event, I call mCalibrator->process()"; + mCalibrator->process(tfcounter, digitsInOneEvent); //fill TimeSlot with digits from 1 event and check slots for finalization + } else { + slotTF.getContainer()->fill(digitsInOneEvent); //fill TimeSlot with digits from 1 event + } + } + + auto infoVecSize = mCalibrator->getCcdbInfoVector().size(); + auto pedsVecSize = mCalibrator->getPedestalsVector().size(); + if (infoVecSize > 0) { + LOG(INFO) << "Created " << infoVecSize << " ccdb infos and " << pedsVecSize << " pedestal objects for TF " << tfcounter; + } + sendOutput(pc.outputs()); + } + //_________________________________________________________________ + + private: + std::unique_ptr<o2::cpv::PedestalCalibrator> mCalibrator; + + void sendOutput(DataAllocator& output) + { + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + const auto& payloadVec = mCalibrator->getPedestalsVector(); + auto&& infoVec = mCalibrator->getCcdbInfoVector(); // use non-const version as we update it + assert(payloadVec.size() == infoVec.size()); + + for (uint32_t i = 0; i < payloadVec.size(); i++) { + auto& w = infoVec[i]; + auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); + LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() + << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_Pedestals", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_Pedestals", i}, w); // root-serialized + } + if (payloadVec.size()) { + mCalibrator->initOutput(); // reset the outputs once they are already sent + } + } + +}; // class CPVPedestalCalibDevice +} // namespace calibration +namespace framework +{ +DataProcessorSpec getCPVPedestalCalibDeviceSpec() +{ + using device = o2::calibration::CPVPedestalCalibDevice; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "CPV_Pedestals"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "CPV_Pedestals"}); + return DataProcessorSpec{ + "cpv-pedestal-calibration", + Inputs{ + {"digits", "CPV", "DIGITS"}, + {"trigrecs", "CPV", "DIGITTRIGREC"}}, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"tf-per-slot", VariantType::UInt64, (uint64_t)std::numeric_limits<long>::max(), {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::UInt64, uint64_t(1000), {"number of slots in past to consider"}}, + {"updateAtTheEndOfRunOnly", VariantType::Bool, false, {"finalize the slots and prepare the CCDB entries only at the end of the run."}}, + {"updateInterval", VariantType::UInt64, (uint64_t)10, {"try to finalize the slot (and produce calibration) when the updateInterval has passed.\n To be used together with tf-per-slot = std::numeric_limits<long>::max()"}}}}; +} +} // namespace framework +} // namespace o2 \ No newline at end of file diff --git a/Detectors/CPV/calib/testWorkflow/cpv-calib-workflow.cxx b/Detectors/CPV/calib/testWorkflow/cpv-calib-workflow.cxx new file mode 100644 index 0000000000000..7c79a59874f39 --- /dev/null +++ b/Detectors/CPV/calib/testWorkflow/cpv-calib-workflow.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "PedestalCalibratorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"pedestals", o2::framework::VariantType::Bool, true, {"do pedestal calibration"}}); + //workflowOptions.push_back(ConfigParamSpec{"gains", o2::framework::VariantType::Bool, false, {"do gain calibration"}}); + //workflowOptions.push_back(ConfigParamSpec{"badmap", o2::framework::VariantType::Bool, false, {"do bad map calibration"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + auto doPedestals = configcontext.options().get<bool>("pedestals"); + //auto doGain = configcontext.options().get<bool>("gains"); + //auto doBadMap = configcontext.options().get<bool>("badmap"); + //if (doPedestals && doGain) { + // LOG(FATAL) << "Can not run pedestal and gain calibration simulteneously"; + // return specs; + //} + //if (doGain) { + // specs.emplace_back(getCPVGainCalibDeviceSpec()); + //} + //if (doBadMap) { + // specs.emplace_back(getCPVBadMapCalibDeviceSpec()); + //} + + if (doPedestals) { + specs.emplace_back(getCPVPedestalCalibDeviceSpec()); + } + return specs; +} diff --git a/Detectors/CPV/reconstruction/CMakeLists.txt b/Detectors/CPV/reconstruction/CMakeLists.txt index a7c66754ad5f4..e18166420d829 100644 --- a/Detectors/CPV/reconstruction/CMakeLists.txt +++ b/Detectors/CPV/reconstruction/CMakeLists.txt @@ -1,21 +1,30 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CPVReconstruction SOURCES src/Clusterer.cxx src/FullCluster.cxx + src/RawDecoder.cxx + src/RawReaderMemory.cxx + src/CTFCoder.cxx + src/CTFHelper.cxx PUBLIC_LINK_LIBRARIES O2::CPVBase - O2::CPVCalib O2::DataFormatsCPV - AliceO2::InfoLogger) + O2::DetectorsRaw + AliceO2::InfoLogger + O2::rANS + Microsoft.GSL::GSL) o2_target_root_dictionary(CPVReconstruction - HEADERS include/CPVReconstruction/Clusterer.h - include/CPVReconstruction/FullCluster.h) + HEADERS include/CPVReconstruction/Clusterer.h + include/CPVReconstruction/FullCluster.h + include/CPVReconstruction/RawReaderMemory.h + include/CPVReconstruction/RawDecoder.h) diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..492fd4d5cc098 --- /dev/null +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CPV data + +#ifndef O2_CPV_CTFCODER_H +#define O2_CPV_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsCPV/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "CPVReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace cpv +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::CPV) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Cluster>& cluData); + + /// entropy decode data from buffer with CTF + template <typename VTRG, typename VCLUSTER> + void decode(const CTF::base& ec, VTRG& trigVec, VCLUSTER& cluVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Cluster>& cluVec); +}; + +/// entropy-encode clusters to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Cluster>& cluData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_entriesTrig + MD::EENCODE, // BLC_posX + MD::EENCODE, // BLC_posZ + MD::EENCODE, // BLC_energy + MD::EENCODE // BLC_status + }; + + CTFHelper helper(trigData, cluData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODECPV(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODECPV(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODECPV(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + ENCODECPV(helper.begin_entriesTrig(), helper.end_entriesTrig(), CTF::BLC_entriesTrig, 0); + + ENCODECPV(helper.begin_posX(), helper.end_posX(), CTF::BLC_posX, 0); + ENCODECPV(helper.begin_posZ(), helper.end_posZ(), CTF::BLC_posZ, 0); + ENCODECPV(helper.begin_energy(), helper.end_energy(), CTF::BLC_energy, 0); + ENCODECPV(helper.begin_status(), helper.end_status(), CTF::BLC_status, 0); + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded clusters to standard compact clusters +template <typename VTRG, typename VCLUSTER> +void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VCLUSTER& cluVec) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcInc, entries, posX, posZ; + std::vector<uint32_t> orbitInc; + std::vector<uint8_t> energy, status; + +#define DECODECPV(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODECPV(bcInc, CTF::BLC_bcIncTrig); + DECODECPV(orbitInc, CTF::BLC_orbitIncTrig); + DECODECPV(entries, CTF::BLC_entriesTrig); + DECODECPV(posX, CTF::BLC_posX); + DECODECPV(posZ, CTF::BLC_posZ); + DECODECPV(energy, CTF::BLC_energy); + DECODECPV(status, CTF::BLC_status); + // clang-format on + // + trigVec.clear(); + cluVec.clear(); + trigVec.reserve(header.nTriggers); + status.reserve(header.nClusters); + + uint32_t firstEntry = 0, cluCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + + Cluster clu; + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + + firstEntry = cluVec.size(); + for (uint16_t ic = 0; ic < entries[itrig]; ic++) { + clu.setPacked(posX[cluCount], posZ[cluCount], energy[cluCount], status[cluCount]); + cluVec.emplace_back(clu); + cluCount++; + } + trigVec.emplace_back(ir, firstEntry, entries[itrig]); + } + assert(cluCount == header.nClusters); +} + +} // namespace cpv +} // namespace o2 + +#endif // O2_CPV_CTFCODER_H diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFHelper.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..506b0948d9f59 --- /dev/null +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFHelper.h @@ -0,0 +1,195 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CPV CTF creation + +#ifndef O2_CPV_CTF_HELPER_H +#define O2_CPV_CTF_HELPER_H + +#include "DataFormatsCPV/CTF.h" +#include <gsl/span> + +namespace o2 +{ +namespace cpv +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const TriggerRecord>& trgData, const gsl::span<const Cluster>& cluData) + : mTrigData(trgData), mCluData(cluData) {} + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigData.size()), uint32_t(mCluData.size()), 0, 0}; + if (mTrigData.size()) { + h.firstOrbit = mTrigData[0].getBCData().orbit; + h.firstBC = mTrigData[0].getBCData().bc; + } + return h; + } + + size_t getSize() const { return mTrigData.size() * sizeof(TriggerRecord) + mCluData.size() * sizeof(Cluster); } + + //>>> =========================== ITERATORS ======================================== + + template <typename I, typename D, typename T> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].getBCData().orbit == mData[mIndex - 1].getBCData().orbit) { + return mData[mIndex].getBCData().bc - mData[mIndex - 1].getBCData().bc; + } else { + return mData[mIndex].getBCData().bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].getBCData().orbit - mData[mIndex - 1].getBCData().orbit : 0; } + }; + + //_______________________________________________ + // Number of cells for trigger + class Iter_entriesTrig : public _Iter<Iter_entriesTrig, TriggerRecord, uint16_t> + { + public: + using _Iter<Iter_entriesTrig, TriggerRecord, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNumberOfObjects(); } + }; + + //_______________________________________________ + class Iter_posX : public _Iter<Iter_posX, Cluster, uint16_t> + { + public: + using _Iter<Iter_posX, Cluster, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedPosX(); } + }; + + //_______________________________________________ + class Iter_posZ : public _Iter<Iter_posZ, Cluster, uint16_t> + { + public: + using _Iter<Iter_posZ, Cluster, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedPosZ(); } + }; + + //_______________________________________________ + class Iter_energy : public _Iter<Iter_energy, Cluster, uint16_t> + { + public: + using _Iter<Iter_energy, Cluster, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedEnergy(); } + }; + + //_______________________________________________ + class Iter_status : public _Iter<Iter_status, Cluster, uint8_t> + { + public: + using _Iter<Iter_status, Cluster, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedClusterStatus(); } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, true); } + + Iter_entriesTrig begin_entriesTrig() const { return Iter_entriesTrig(mTrigData, false); } + Iter_entriesTrig end_entriesTrig() const { return Iter_entriesTrig(mTrigData, true); } + + Iter_posX begin_posX() const { return Iter_posX(mCluData, false); } + Iter_posX end_posX() const { return Iter_posX(mCluData, true); } + + Iter_posZ begin_posZ() const { return Iter_posZ(mCluData, false); } + Iter_posZ end_posZ() const { return Iter_posZ(mCluData, true); } + + Iter_energy begin_energy() const { return Iter_energy(mCluData, false); } + Iter_energy end_energy() const { return Iter_energy(mCluData, true); } + + Iter_status begin_status() const { return Iter_status(mCluData, false); } + Iter_status end_status() const { return Iter_status(mCluData, true); } + + private: + const gsl::span<const o2::cpv::TriggerRecord> mTrigData; + const gsl::span<const o2::cpv::Cluster> mCluData; +}; + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/Clusterer.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/Clusterer.h index cb0269312ef69..15f9dbc660cd6 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/Clusterer.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/Clusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,8 +16,8 @@ #include "DataFormatsCPV/Digit.h" #include "DataFormatsCPV/Cluster.h" #include "CPVReconstruction/FullCluster.h" -#include "CPVCalib/CalibParams.h" -#include "CPVCalib/BadChannelMap.h" +#include "DataFormatsCPV/CalibParams.h" +#include "DataFormatsCPV/BadChannelMap.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "DataFormatsCPV/TriggerRecord.h" @@ -34,7 +35,7 @@ class Clusterer void initialize(); void process(gsl::span<const Digit> digits, gsl::span<const TriggerRecord> dtr, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* dmc, - std::vector<Cluster>* clusters, std::vector<TriggerRecord>* rigRec, + std::vector<Cluster>* clusters, std::vector<TriggerRecord>* trigRec, o2::dataformats::MCTruthContainer<o2::MCCompLabel>* cluMC); void makeClusters(gsl::span<const Digit> digits); @@ -43,26 +44,19 @@ class Clusterer o2::dataformats::MCTruthContainer<o2::MCCompLabel>* cluMC); float responseShape(float dx, float dz); // Parameterization of EM shower + void propagateMC(bool toRun = true) { mRunMC = toRun; } void makeUnfoldings(gsl::span<const Digit> digits); // Find and unfold clusters with few local maxima void unfoldOneCluster(FullCluster& iniClu, char nMax, gsl::span<int> digitId, gsl::span<const Digit> digits); - protected: - //Calibrate Amplitude - inline float calibrate(float amp, short absId) { return amp * mCalibParams->getGain(absId); } - //Test Bad map - inline bool isBadChannel(short absId) { return (!mBadMap->isChannelGood(absId)); } - protected: static constexpr short NLMMax = 10; ///< maximal number of local maxima in cluster - const CalibParams* mCalibParams = nullptr; //! Calibration coefficients - const BadChannelMap* mBadMap = nullptr; //! Calibration coefficients - - std::vector<FullCluster> mClusters; ///< internal vector of clusters + bool mRunMC = false; ///< Process MC info int mFirstDigitInEvent; ///< Range of digits from one event int mLastDigitInEvent; ///< Range of digits from one event - std::vector<Digit> mDigits; ///< vector of trancient digits for cell processing + std::vector<FullCluster> mClusters; ///< internal vector of clusters + std::vector<Digit> mDigits; ///< vector of transient digits for cell processing std::vector<std::vector<float>> meInClusters = std::vector<std::vector<float>>(10, std::vector<float>(NLMMax)); std::vector<std::vector<float>> mfij = std::vector<std::vector<float>>(10, std::vector<float>(NLMMax)); diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/FullCluster.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/FullCluster.h index e24122d56fb15..5ee612b7ddacc 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/FullCluster.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/FullCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h new file mode 100644 index 0000000000000..322cce079e0d5 --- /dev/null +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h @@ -0,0 +1,123 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_CPV_RAWDECODER_H +#define ALICEO2_CPV_RAWDECODER_H + +#include <iosfwd> +#include <gsl/span> +#include <string> +#include <utility> +#include "DataFormatsCPV/Digit.h" +#include "CPVReconstruction/RawReaderMemory.h" +class Digits; + +namespace o2 +{ +namespace cpv +{ + +class RawDecoderError +{ + public: + RawDecoderError() = default; //Constructors for vector::emplace_back methods + RawDecoderError(short c, short d, short g, short p, RawErrorType_t e) : ccId(c), dil(d), gas(g), pad(p), errortype(e) {} + RawDecoderError(const RawDecoderError& e) = default; + ~RawDecoderError() = default; + + short ccId; + short dil; + short gas; + short pad; + RawErrorType_t errortype; + ClassDefNV(RawDecoderError, 1); +}; + +union AddressCharge { + uint32_t mDataWord; + struct { + uint32_t Address : 18; ///< Bits 0 - 17 : Address + uint32_t Charge : 14; ///< Bits 18 - 32 : charge + }; +}; + +/// BC reference to digits +struct BCRecord { + BCRecord() = default; + BCRecord(uint16_t bunchCrossing, unsigned int first, unsigned int last) : bc(bunchCrossing), firstDigit(first), lastDigit(last) {} + uint16_t bc; + unsigned int firstDigit; + unsigned int lastDigit; +}; + +/// \class RawDecoder +/// \brief Decoder of the ALTRO data in the raw page +/// \ingroup CPVreconstruction +/// \author Dmitri Peresunko +/// \since Dec, 2020 +/// +/// This is a base class for reading raw data digits. +/// It takes raw cpv payload from RawReaderMemory and produces +/// std::vector<uint32_t> mDigits and std::vector<BCRecord> mBCRecords + +class RawDecoder +{ + public: + /// \brief Constructor + /// \param reader Raw reader instance to be decoded + RawDecoder(RawReaderMemory& reader); + + /// \brief Destructor + ~RawDecoder() = default; + + /// \brief Decode the raw cpv payload stream + /// \throw RawDecoderError if the RCUTrailer or raw cpv payload cannot be decoded + /// + /// Decoding and checking the cpvheader, + /// cpvwords and cpvtrailer. + /// After successfull decoding the Decoder can provide + /// a reference to a vector + /// with the decoded chanenels and their bc reference + RawErrorType_t decode(); + + /// \brief Get the reference to the digits container + /// \return Reference to the digits container + const std::vector<uint32_t>& getDigits() const { return mDigits; }; + + /// \brief Get the reference to the BC records + /// \return reference to the BC records + const std::vector<o2::cpv::BCRecord>& getBCRecords() const { return mBCRecords; }; + + /// \brief Get the reference to the list of decoding errors + /// \return Reference to the list of decoding errors + const std::vector<o2::cpv::RawDecoderError>& getErrors() const { return mErrors; } + + protected: + /// \brief Read channels for the current event in the raw buffer + RawErrorType_t readChannels(); + + private: + bool addDigit(uint32_t padWord, short ddl, uint16_t bc); + void removeLastNDigits(int n); + + RawReaderMemory& mRawReader; ///< underlying raw reader + std::vector<uint32_t> mDigits; ///< vector of channels and BCs in the raw stream + std::vector<o2::cpv::BCRecord> mBCRecords; ///< vector of bc references to digits + std::vector<RawDecoderError> mErrors; ///< vector of decoding errors + bool mChannelsInitialized = false; ///< check whether the channels are initialized + + ClassDefNV(RawDecoder, 2); +}; + +} // namespace cpv + +} // namespace o2 + +#endif diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h new file mode 100644 index 0000000000000..56d48dbf26dd8 --- /dev/null +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_CPV_RAWREADERMEMORY_H +#define ALICEO2_CPV_RAWREADERMEMORY_H + +#include <gsl/span> +#include <Rtypes.h> + +#include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" + +namespace o2 +{ + +namespace cpv +{ + +enum RawErrorType_t { + kOK, ///< NoError + kOK_NO_PAYLOAD, ///< No payload per ddl (not error) + kRDH_DECODING, + kRDH_INVALID, + kNOT_CPV_RDH, + kSTOPBIT_NOTFOUND, + kPAGE_NOTFOUND, + kPAYLOAD_INCOMPLETE, + kNO_CPVHEADER, + kNO_CPVTRAILER, + kCPVHEADER_INVALID, + kCPVTRAILER_INVALID, + kSEGMENT_HEADER_ERROR, + kROW_HEADER_ERROR, + kEOE_HEADER_ERROR, + kPADERROR, + kUNKNOWN_WORD, + kPadAddress +}; + +/// \class RawReaderMemory +/// \brief Reader for raw data produced by the Readout application in in-memory format +/// \ingroup CPVreconstruction +/// \author Dmitri Peresunko after Markus Fasel +/// \since Sept. 25, 2020 +/// +///It reads one HBF, stores HBF orbit number in getCurrentHBFOrbit() and produces digits in AddressChargeBC format +class RawReaderMemory +{ + public: + /// \brief Constructor + RawReaderMemory(const gsl::span<const char> rawmemory); + + /// \brief Destructor + ~RawReaderMemory() = default; + + /// \brief set new raw memory chunk + /// \param rawmemory New raw memory chunk + void setRawMemory(const gsl::span<const char> rawmemory); + + /// \brief Read next payload from the stream + /// + /// Read the next pages until the stop bit is found. + RawErrorType_t next(); + + /// \brief Read the next page from the stream (single DMA page) + /// \param resetPayload If true the raw payload is reset + /// \throw Error if the page cannot be read or header or payload cannot be deocded + /// + /// Function reading a single DMA page from the stream. It is called + /// inside the next() function for reading payload from multiple DMA + /// pages. As the function cannot handle payload from multiple pages + /// it should not be called directly by the user. + RawErrorType_t nextPage(); + + /// \brief access to the raw header of the current page + /// \return Raw header of the current page + const o2::header::RDHAny& getRawHeader() const { return mRawHeader; } + + /// \brief access to the full raw payload (single or multiple DMA pages) + /// \return Raw Payload of the data until the stop bit is received. + const std::vector<char>& getPayload() const { return mRawPayload; } + + /// \brief Return size of the payload + /// \return size of the payload + int getPayloadSize() const { return mRawPayload.size(); } + + /// \brief get the size of the file in bytes + /// \return size of the file in byte + int getFileSize() const noexcept { return mRawMemoryBuffer.size(); } + + /// \brief check if more pages are available in the raw file + /// \return true if there is a next page + bool hasNext() const { return mCurrentPosition < mRawMemoryBuffer.size(); } + + /// \return HeartBeatFrame orbit number + uint32_t getCurrentHBFOrbit() const { return mCurrentHBFOrbit; } + + protected: + /// \brief Initialize the raw stream + /// + /// Rewind stream to the first entry + void init(); + + o2::header::RDHAny decodeRawHeader(const void* headerwords); + + private: + gsl::span<const char> mRawMemoryBuffer; ///< Memory block with multiple DMA pages + o2::header::RDHAny mRawHeader; ///< Raw header + std::vector<char> mRawPayload; ///< Raw payload (can consist of multiple pages) + int mCurrentPosition = 0; ///< Current page in file + bool mRawHeaderInitialized = false; ///< RDH for current page initialized + bool mPayloadInitialized = false; ///< Payload for current page initialized + uint32_t mCurrentHBFOrbit = 0; ///< Current orbit of HBF + bool mStopBitWasNotFound; ///< True if StopBit was not found but HBF orbit changed + bool mIsJustInited = false; ///< True if init() was just called + + ClassDefNV(RawReaderMemory, 2); +}; + +} // namespace cpv + +} // namespace o2 + +#endif diff --git a/Detectors/CPV/reconstruction/src/CPVReconstructionLinkDef.h b/Detectors/CPV/reconstruction/src/CPVReconstructionLinkDef.h index 98a55d8446614..ee792fd2dce06 100644 --- a/Detectors/CPV/reconstruction/src/CPVReconstructionLinkDef.h +++ b/Detectors/CPV/reconstruction/src/CPVReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,5 +17,7 @@ #pragma link C++ class o2::cpv::Clusterer + ; #pragma link C++ class o2::cpv::FullCluster + ; +#pragma link C++ class o2::cpv::RawReaderMemory + ; +#pragma link C++ class o2::cpv::RawDecoder + ; #endif diff --git a/Detectors/CPV/reconstruction/src/CTFCoder.cxx b/Detectors/CPV/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..eb4ceaac7d86b --- /dev/null +++ b/Detectors/CPV/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CPV data + +#include "CPVReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::cpv; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Cluster>& cluVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, trigVec, cluVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc = 0, entries = 0, cluPosX = 0, cluPosZ = 0; + uint32_t orbitInc = 0; + uint8_t energy = 0, status = 0; +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(entries, CTF::BLC_entriesTrig); + MAKECODER(cluPosX, CTF::BLC_posX); + MAKECODER(cluPosZ, CTF::BLC_posZ); + MAKECODER(energy, CTF::BLC_energy); + MAKECODER(status, CTF::BLC_status); + // clang-format on +} diff --git a/Detectors/CPV/reconstruction/src/CTFHelper.cxx b/Detectors/CPV/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..08310ffb6c48d --- /dev/null +++ b/Detectors/CPV/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CPV CTF creation + +#include "CPVReconstruction/CTFHelper.h" diff --git a/Detectors/CPV/reconstruction/src/Clusterer.cxx b/Detectors/CPV/reconstruction/src/Clusterer.cxx index 5af836e70d79e..d48583a6b3859 100644 --- a/Detectors/CPV/reconstruction/src/Clusterer.cxx +++ b/Detectors/CPV/reconstruction/src/Clusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,6 +33,7 @@ void Clusterer::initialize() mFirstDigitInEvent = 0; mLastDigitInEvent = -1; } + //____________________________________________________________________________ void Clusterer::process(gsl::span<const Digit> digits, gsl::span<const TriggerRecord> dtr, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* dmc, @@ -40,11 +42,12 @@ void Clusterer::process(gsl::span<const Digit> digits, gsl::span<const TriggerRe { clusters->clear(); //final out list of clusters trigRec->clear(); - if (cluMC) { + if (mRunMC) { cluMC->clear(); } for (const auto& tr : dtr) { + mFirstDigitInEvent = tr.getFirstEntry(); mLastDigitInEvent = mFirstDigitInEvent + tr.getNumberOfObjects(); int indexStart = clusters->size(); @@ -52,43 +55,21 @@ void Clusterer::process(gsl::span<const Digit> digits, gsl::span<const TriggerRe LOG(DEBUG) << "Starting clusteriztion digits from " << mFirstDigitInEvent << " to " << mLastDigitInEvent; - if (!mBadMap) { - if (o2::cpv::CPVSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mBadMap = new BadChannelMap(1); // test default map - mCalibParams = new CalibParams(1); //test calibration map - LOG(INFO) << "No reading BadMap/Calibration from ccdb requested, set default"; - } else { - LOG(INFO) << "Getting BadMap object from ccdb"; - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - long bcTime = 1; //TODO!!! Convert BC time to time o2::InteractionRecord bcTime = digitsTR.front().getBCData() ; - mBadMap = ccdb.retrieveFromTFileAny<o2::cpv::BadChannelMap>("CPV/BadMap", metadata, bcTime); - mCalibParams = ccdb.retrieveFromTFileAny<o2::cpv::CalibParams>("CPV/Calib", metadata, bcTime); - if (!mBadMap) { - LOG(FATAL) << "[CPVClusterer - run] can not get Bad Map"; - } - if (!mCalibParams) { - LOG(FATAL) << "[CPVClusterer - run] can not get CalibParams"; - } - } - } - // Collect digits to clusters makeClusters(digits); - // Unfold overlapped clusters - // Split clusters with several local maxima if necessary - if (o2::cpv::CPVSimParams::Instance().mUnfoldClusters) { - makeUnfoldings(digits); - } + // // Unfold overlapped clusters + // // Split clusters with several local maxima if necessary + // if (o2::cpv::CPVSimParams::Instance().mUnfoldClusters) { + // makeUnfoldings(digits); + // } // Calculate properties of collected clusters (Local position, energy, disp etc.) evalCluProperties(digits, clusters, dmc, cluMC); LOG(DEBUG) << "Found clusters from " << indexStart << " to " << clusters->size(); - trigRec->emplace_back(tr.getBCData(), indexStart, clusters->size()); + trigRec->emplace_back(tr.getBCData(), indexStart, clusters->size() - indexStart); } } //____________________________________________________________________________ @@ -97,59 +78,51 @@ void Clusterer::makeClusters(gsl::span<const Digit> digits) // A cluster is defined as a list of neighbour digits // Mark all digits as unused yet - const int maxNDigits = 12546; // There is no digits more than in CPV modules ;) - bool digitsUsed[maxNDigits]; - memset(digitsUsed, 0, sizeof(bool) * maxNDigits); + const int maxNDigits = 23040; // There is no digits more than in CPV modules ;) + std::bitset<maxNDigits> digitsUsed; ///< Container for bad cells, 1 means bad sell + digitsUsed.reset(); int iFirst = mFirstDigitInEvent; // first index of digit which potentially can be a part of cluster for (int i = iFirst; i < mLastDigitInEvent; i++) { - if (digitsUsed[i - mFirstDigitInEvent]) { + if (digitsUsed.test(i - mFirstDigitInEvent)) { continue; } const Digit& digitSeed = digits[i]; - float digitSeedEnergy = calibrate(digitSeed.getAmplitude(), digitSeed.getAbsId()); - if (isBadChannel(digitSeed.getAbsId())) { - digitSeedEnergy = 0.; - } + float digitSeedEnergy = digitSeed.getAmplitude(); //already calibrated digits if (digitSeedEnergy < o2::cpv::CPVSimParams::Instance().mDigitMinEnergy) { continue; } // is this digit so energetic that start cluster? - FullCluster* clu = nullptr; - int iDigitInCluster = 0; - if (digitSeedEnergy > o2::cpv::CPVSimParams::Instance().mClusteringThreshold) { - // start new cluster - mClusters.emplace_back(digitSeed.getAbsId(), digitSeedEnergy, digitSeed.getLabel()); - clu = &(mClusters.back()); - - digitsUsed[i - mFirstDigitInEvent] = true; - iDigitInCluster = 1; - } else { + if (digitSeedEnergy < o2::cpv::CPVSimParams::Instance().mClusteringThreshold) { continue; } + // start new cluster + mClusters.emplace_back(digitSeed.getAbsId(), digitSeedEnergy, digitSeed.getLabel()); + FullCluster& clu = mClusters.back(); + digitsUsed.set(i - mFirstDigitInEvent, true); + int iDigitInCluster = 1; + // Now scan remaining digits in list to find neigbours of our seed int index = 0; while (index < iDigitInCluster) { // scan over digits already in cluster - short digitSeedAbsId = clu->getDigitAbsId(index); + short digitSeedAbsId = clu.getDigitAbsId(index); index++; - for (Int_t j = iFirst; j < mLastDigitInEvent; j++) { - if (digitsUsed[j - mFirstDigitInEvent]) { + bool runLoop = true; + for (Int_t j = iFirst; runLoop && (j < mLastDigitInEvent); j++) { + if (digitsUsed.test(j - mFirstDigitInEvent)) { continue; // look through remaining digits } - const Digit* digitN = &(digits[j]); - float digitNEnergy = calibrate(digitN->getAmplitude(), digitN->getAbsId()); - if (isBadChannel(digitN->getAbsId())) { //remove digit - digitNEnergy = 0.; - } + const Digit& digitN = digits[j]; + float digitNEnergy = digitN.getAmplitude(); //Already calibrated digits! if (digitNEnergy < o2::cpv::CPVSimParams::Instance().mDigitMinEnergy) { continue; } // call (digit,digitN) in THAT oder !!!!! - Int_t ineb = Geometry::areNeighbours(digitSeedAbsId, digitN->getAbsId()); + Int_t ineb = Geometry::areNeighbours(digitSeedAbsId, digitN.getAbsId()); switch (ineb) { case -1: // too early (e.g. previous module), do not look before j at subsequent passes iFirst = j; @@ -157,12 +130,13 @@ void Clusterer::makeClusters(gsl::span<const Digit> digits) case 0: // not a neighbour break; case 1: // are neighbours - clu->addDigit(digitN->getAbsId(), digitNEnergy, digitN->getLabel()); + clu.addDigit(digitN.getAbsId(), digitNEnergy, digitN.getLabel()); iDigitInCluster++; - digitsUsed[j - mFirstDigitInEvent] = true; + digitsUsed.set(j - mFirstDigitInEvent, true); break; case 2: // too far from each other default: + runLoop = false; break; } // switch } @@ -349,9 +323,10 @@ void Clusterer::evalCluProperties(gsl::span<const Digit> digits, std::vector<Clu } int labelIndex = 0; - if (cluMC) { + if (mRunMC) { labelIndex = cluMC->getIndexedSize(); } + auto clu = mClusters.begin(); while (clu != mClusters.end()) { @@ -370,7 +345,7 @@ void Clusterer::evalCluProperties(gsl::span<const Digit> digits, std::vector<Clu if (clu->getEnergy() > 1.e-4) { //Non-empty cluster clusters->emplace_back(*clu); - if (cluMC) { //Handle labels + if (mRunMC) { //Handle labels //Calculate list of primaries //loop over entries in digit MCTruthContainer const std::vector<FullCluster::CluElement>* vl = clu->getElementList(); @@ -401,7 +376,6 @@ void Clusterer::evalCluProperties(gsl::span<const Digit> digits, std::vector<Clu } ++ll; } - clusters->back().setLabel(labelIndex); labelIndex++; } // Work with MC } diff --git a/Detectors/CPV/reconstruction/src/FullCluster.cxx b/Detectors/CPV/reconstruction/src/FullCluster.cxx index 8ac549b871f62..b70001aa6fef7 100644 --- a/Detectors/CPV/reconstruction/src/FullCluster.cxx +++ b/Detectors/CPV/reconstruction/src/FullCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/reconstruction/src/RawDecoder.cxx b/Detectors/CPV/reconstruction/src/RawDecoder.cxx new file mode 100644 index 0000000000000..8917799417657 --- /dev/null +++ b/Detectors/CPV/reconstruction/src/RawDecoder.cxx @@ -0,0 +1,181 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <FairLogger.h> +#include "CPVReconstruction/RawReaderMemory.h" +#include "CPVReconstruction/RawDecoder.h" +#include "DataFormatsCPV/RawFormats.h" +#include "InfoLogger/InfoLogger.hxx" +#include "DetectorsRaw/RDHUtils.h" +#include "CPVBase/Geometry.h" + +using namespace o2::cpv; + +RawDecoder::RawDecoder(RawReaderMemory& reader) : mRawReader(reader), + mChannelsInitialized(false) +{ +} + +RawErrorType_t RawDecoder::decode() +{ + + auto& rdh = mRawReader.getRawHeader(); + short linkID = o2::raw::RDHUtils::getLinkID(rdh); + mDigits.clear(); + mBCRecords.clear(); + + auto payloadWords = mRawReader.getPayload(); + if (payloadWords.size() == 0) { + return kOK_NO_PAYLOAD; + } + + return readChannels(); +} + +RawErrorType_t RawDecoder::readChannels() +{ + mChannelsInitialized = false; + + auto& payloadWords = mRawReader.getPayload(); + uint32_t wordCountFromLastHeader = 1; //header word is included + int nDigitsAddedFromLastHeader = 0; + bool isHeaderExpected = true; //true if we expect to read header, false otherwise + bool skipUntilNextHeader = true; //true if something wrong with data format, try to read next header + uint16_t currentBC; + uint32_t currentOrbit = mRawReader.getCurrentHBFOrbit(); + auto b = payloadWords.cbegin(); + auto e = payloadWords.cend(); + while (b != e) { //payload must start with cpvheader folowed by cpvwords and finished with cpvtrailer + CpvHeader header(b, e); + if (header.isOK()) { + LOG(DEBUG) << "RawDecoder::readChannels() : " + << "I read cpv header for orbit = " << header.orbit() + << " and BC = " << header.bc(); + if (!isHeaderExpected) { //actually, header was not expected + LOG(ERROR) << "RawDecoder::readChannels() : " + << "header was not expected"; + removeLastNDigits(nDigitsAddedFromLastHeader); //remove previously added digits as they are bad + mErrors.emplace_back(5, 0, 0, 0, kNO_CPVTRAILER); + } + skipUntilNextHeader = false; + currentBC = header.bc(); + wordCountFromLastHeader = 0; + nDigitsAddedFromLastHeader = 0; + if (currentOrbit != header.orbit()) { //bad cpvheader + LOG(ERROR) << "RawDecoder::readChannels() : " + << "currentOrbit(=" << currentOrbit + << ") != header.orbit()(=" << header.orbit() << ")"; + mErrors.emplace_back(5, 0, 0, 0, kCPVHEADER_INVALID); //5 is non-existing link with general errors + skipUntilNextHeader = true; + } + } else { + if (skipUntilNextHeader) { + b += 16; + continue; //continue while'ing until it's not header + } + CpvWord word(b, e); + if (word.isOK()) { + wordCountFromLastHeader++; + for (int i = 0; i < 3; i++) { + PadWord pw = {word.cpvPadWord(i)}; + if (pw.zero == 0) { //cpv pad word, not control or empty + if (addDigit(pw.mDataWord, word.ccId(), currentBC)) { + nDigitsAddedFromLastHeader++; + } else { + LOG(DEBUG) << "RawDecoder::readChannels() : " + << "read pad word with non-valid pad address"; + unsigned int dil = pw.dil, gas = pw.gas, address = pw.address; + mErrors.emplace_back(word.ccId(), dil, gas, address, kPadAddress); + } + } + } + } else { //this may be trailer + CpvTrailer trailer(b, e); + if (trailer.isOK()) { + int diffInCount = wordCountFromLastHeader - trailer.wordCounter(); + if (diffInCount > 1 || + diffInCount < -1) { + //some words lost? + LOG(ERROR) << "RawDecoder::readChannels() : " + << "Read " << wordCountFromLastHeader << " words, expected " << trailer.wordCounter(); + mErrors.emplace_back(5, 0, 0, 0, kCPVTRAILER_INVALID); + //throw all previous data and go to next header + removeLastNDigits(nDigitsAddedFromLastHeader); + skipUntilNextHeader = true; + } + if (trailer.bc() != currentBC) { + //trailer does not fit header + LOG(ERROR) << "RawDecoder::readChannels() : " + << "CPVHeader BC is " << currentBC << " but CPVTrailer BC is " << trailer.bc(); + mErrors.emplace_back(5, 0, 0, 0, kCPVTRAILER_INVALID); + removeLastNDigits(nDigitsAddedFromLastHeader); + skipUntilNextHeader = true; + } + isHeaderExpected = true; + } else { + wordCountFromLastHeader++; + //error + LOG(ERROR) << "RawDecoder::readChannels() : " + << "Read unknown word"; + mErrors.emplace_back(5, 0, 0, 0, kUNKNOWN_WORD); //add error for non-existing row + //what to do? + } + } + } + b += 16; + } + mChannelsInitialized = true; + return kOK; +} + +bool RawDecoder::addDigit(uint32_t w, short ccId, uint16_t bc) +{ + //add digit + PadWord pad = {w}; + unsigned short absId; + if (!o2::cpv::Geometry::hwaddressToAbsId(ccId, pad.dil, pad.gas, pad.address, absId)) { + return false; + } + + //new bc -> add bc reference + if (mBCRecords.empty() || (mBCRecords.back().bc != bc)) { + mBCRecords.push_back(BCRecord(bc, mDigits.size(), mDigits.size())); + } else { + mBCRecords.back().lastDigit++; + } + + AddressCharge ac = {0}; + ac.Address = absId; + ac.Charge = pad.charge; + mDigits.push_back(ac.mDataWord); + + return true; +} + +void RawDecoder::removeLastNDigits(int n) +{ + if (n < 0) { + return; + } + int nRemoved = 0; + while (nRemoved < n) { + if (mDigits.size() > 0) { // still has digits to remove + mDigits.pop_back(); + if (mBCRecords.back().lastDigit == mBCRecords.back().firstDigit) { + mBCRecords.pop_back(); + } else { + mBCRecords.back().lastDigit--; + } + nRemoved++; + } else { // has nothing to remove already + break; + } + } +} \ No newline at end of file diff --git a/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx b/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx new file mode 100644 index 0000000000000..cc48bf64717b0 --- /dev/null +++ b/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <sstream> +#include <string> +#include "FairLogger.h" +#include "CPVReconstruction/RawReaderMemory.h" +#include "DetectorsRaw/RDHUtils.h" + +using namespace o2::cpv; + +using RDHDecoder = o2::raw::RDHUtils; + +RawReaderMemory::RawReaderMemory(gsl::span<const char> rawmemory) : mRawMemoryBuffer(rawmemory) +{ + init(); +} + +void RawReaderMemory::setRawMemory(const gsl::span<const char> rawmemory) +{ + mRawMemoryBuffer = rawmemory; + init(); +} + +o2::header::RDHAny RawReaderMemory::decodeRawHeader(const void* payloadwords) +{ + auto headerversion = RDHDecoder::getVersion(payloadwords); + if (headerversion == 4) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV4*>(payloadwords)); + } else if (headerversion == 5) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV5*>(payloadwords)); + } else if (headerversion == 6) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV6*>(payloadwords)); + } + LOG(ERROR) << "RawReaderMemory::decodeRawHeader() : Unknown RDH version"; + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV6*>(payloadwords)); +} + +void RawReaderMemory::init() +{ + mCurrentPosition = 0; + mRawHeaderInitialized = false; + mPayloadInitialized = false; + mCurrentHBFOrbit = 0; + mStopBitWasNotFound = false; + mIsJustInited = true; +} + +//Read the next pages until the stop bit is found or new HBF reached +//it means we read 1 HBF per next() call +RawErrorType_t RawReaderMemory::next() +{ + mRawPayload.clear(); + bool isStopBitFound = false; + do { + RawErrorType_t e = nextPage(); + if (e == RawErrorType_t::kPAGE_NOTFOUND || // nothing left to read... + e == RawErrorType_t::kRDH_DECODING || // incorrect rdh -> fatal error + e == RawErrorType_t::kPAYLOAD_INCOMPLETE || // we reached end of mRawMemoryBuffer but payload size from rdh tells to read more + e == RawErrorType_t::kSTOPBIT_NOTFOUND) { //new HBF orbit started but no stop bit found, need to return + return e; //some principal error occured -> stop reading. + } + isStopBitFound = RDHDecoder::getStop(mRawHeader); + } while (!isStopBitFound); + + return RawErrorType_t::kOK; +} + +//Read the next ONLY ONE page from the stream (single DMA page) +//note: 1 raw header per page +RawErrorType_t RawReaderMemory::nextPage() +{ + if (!hasNext()) { + return RawErrorType_t::kPAGE_NOTFOUND; + } + mRawHeaderInitialized = false; + mPayloadInitialized = false; + + // Read RDH header + o2::header::RDHAny rawHeader; + try { + rawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); + } catch (...) { + return RawErrorType_t::kRDH_DECODING; //this is fatal error + } + if (RDHDecoder::getSourceID(rawHeader) != 0x8) { + // Not a CPV RDH + mCurrentPosition += RDHDecoder::getOffsetToNext(rawHeader); //moving on + return RawErrorType_t::kNOT_CPV_RDH; + } + if (mIsJustInited || mStopBitWasNotFound) { //reading first time after init() or stopbit was not found + mCurrentHBFOrbit = RDHDecoder::getHeartBeatOrbit(rawHeader); + mRawHeader = rawHeader; //save RDH of first page as mRawHeader + mRawHeaderInitialized = true; + mStopBitWasNotFound = false; //reset this flag as we start to read again + mIsJustInited = false; + } else if (mCurrentHBFOrbit != RDHDecoder::getHeartBeatOrbit(rawHeader)) { + //next HBF started but we didn't find stop bit. + mStopBitWasNotFound = true; + return RawErrorType_t::kSTOPBIT_NOTFOUND; //Stop reading, this will be read again by calling next() + } + mRawHeader = rawHeader; //save RDH of current page as mRawHeader + mRawHeaderInitialized = true; + + auto tmp = mRawMemoryBuffer.data(); + int start = (mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader)); + int end = (mCurrentPosition + RDHDecoder::getMemorySize(mRawHeader)); + bool isPayloadIncomplete = false; + if (mCurrentPosition + RDHDecoder::getMemorySize(mRawHeader) > mRawMemoryBuffer.size()) { + // Payload incomplete + end = mRawMemoryBuffer.size(); //OK, lets read it anyway. Maybe there still are some completed events... + } + for (auto iword = start; iword < end; iword++) { + mRawPayload.push_back(tmp[iword]); + } + mPayloadInitialized = true; + + mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); /// Assume fixed 8 kB page size + if (isPayloadIncomplete) { + return RawErrorType_t::kPAYLOAD_INCOMPLETE; //return error so we can it handle later + } + return RawErrorType_t::kOK; +} diff --git a/Detectors/CPV/simulation/CMakeLists.txt b/Detectors/CPV/simulation/CMakeLists.txt index 5d96c06ae79e0..d8a329a050b74 100644 --- a/Detectors/CPV/simulation/CMakeLists.txt +++ b/Detectors/CPV/simulation/CMakeLists.txt @@ -1,19 +1,35 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CPVSimulation - SOURCES src/Detector.cxx src/GeometryParams.cxx - src/Digitizer.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::CPVBase O2::DataFormatsCPV O2::CPVCalib O2::CCDB) + SOURCES src/Detector.cxx + src/GeometryParams.cxx + src/Digitizer.cxx + src/RawWriter.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsBase + O2::DataFormatsCPV + O2::CPVBase + O2::CCDB + O2::SimConfig + O2::SimulationDataFormat + O2::Headers + O2::DetectorsRaw) o2_target_root_dictionary(CPVSimulation HEADERS include/CPVSimulation/Detector.h include/CPVSimulation/GeometryParams.h - include/CPVSimulation/Digitizer.h) + include/CPVSimulation/Digitizer.h + include/CPVSimulation/RawWriter.h) +o2_add_executable(digi2raw + COMPONENT_NAME cpv + PUBLIC_LINK_LIBRARIES O2::CPVSimulation + SOURCES src/RawCreator.cxx) + diff --git a/Detectors/CPV/simulation/include/CPVSimulation/Detector.h b/Detectors/CPV/simulation/include/CPVSimulation/Detector.h index 9c95ec79c0017..c9ece3ba482ec 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/Detector.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include "DetectorsBase/Detector.h" #include "MathUtils/Cartesian.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" #include "RStringView.h" #include "Rtypes.h" @@ -68,13 +69,13 @@ class Detector : public o2::base::DetImpl<Detector> /// /// Initializing detector /// - void InitializeO2Detector() override; + void InitializeO2Detector() final; /// /// Processing hit creation in the CPV crystalls /// /// \param[in] v Current sensitive volume - Bool_t ProcessHits(FairVolume* v = nullptr) override; + Bool_t ProcessHits(FairVolume* v = nullptr) final; /// /// Add CPV hit @@ -109,16 +110,16 @@ class Detector : public o2::base::DetImpl<Detector> /// Reset /// Clean Hits collection /// - void Reset() override; + void Reset() final; /// Sort final hist - void FinishEvent() override; + void FinishEvent() final; /// /// Steps to be carried out at the end of the event /// For CPV cleaning the hit collection and the lookup table /// - void EndOfEvent() override; + void EndOfEvent() final; /// /// Specifies CPV modules as alignable volumes @@ -146,13 +147,13 @@ class Detector : public o2::base::DetImpl<Detector> private: /// copy constructor (used in MT) Detector(const Detector& rhs); - Detector& operator=(const Detector&); + Detector& operator=(const Detector& rhs); /// Define the sensitive volumes of the geometry void defineSensitiveVolumes(); // Geometry parameters - Bool_t mActiveModule[6]; // list of modules to create + Bool_t mActiveModule[5]; // list of modules to create // Simulation std::vector<Hit>* mHits = nullptr; //! Collection of CPV hits diff --git a/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h b/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h index 4cec0dabc1473..87b00913d54a0 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,10 +12,12 @@ #ifndef ALICEO2_CPV_DIGITIZER_H #define ALICEO2_CPV_DIGITIZER_H -#include "DataFormatsCPV/Digit.h" #include "CPVBase/Geometry.h" -#include "CPVCalib/CalibParams.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/CalibParams.h" +#include "DataFormatsCPV/Pedestals.h" +#include "DataFormatsCPV/BadChannelMap.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -34,27 +37,21 @@ class Digitizer : public TObject void finish(); /// Steer conversion of hits to digits - void process(const std::vector<Hit>* hitsBg, const std::vector<Hit>* hitsS, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels); - - void setEventTime(double t); - double getEventTime() const { return mEventTime; } - - void setCurrEvID(int v); - int getCurrEvID() const { return mCurrEvID; } + void processHits(const std::vector<Hit>* mHits, const std::vector<Digit>& digitsBg, + std::vector<Digit>& digitsOut, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mLabels, + int source, int entry, double dt); protected: - float simulateNoise(); - float uncalibrate(float e, int absId); + float simulatePedestalNoise(int absId); private: - const CalibParams* mCalibParams = nullptr; //! Calibration coefficients - double mEventTime = 0; ///< global event time - uint mROFrameMin = 0; ///< lowest RO frame of current digits - uint mROFrameMax = 0; ///< highest RO frame of current digits - int mCurrSrcID = 0; ///< current MC source from the manager - int mCurrEvID = 0; ///< current event ID from the manager - - ClassDefOverride(Digitizer, 1); + static constexpr short NCHANNELS = 23040; //128*60*3: toatl number of CPV channels + CalibParams* mCalibParams; /// Calibration coefficients + Pedestals* mPedestals; /// Pedestals + BadChannelMap* mBadMap; /// Bad channel map + std::array<Digit, NCHANNELS> mArrayD; ///array of digits (for inner use) + std::array<float, NCHANNELS> mDigitThresholds; + ClassDefOverride(Digitizer, 3); }; } // namespace cpv } // namespace o2 diff --git a/Detectors/CPV/simulation/include/CPVSimulation/GeometryParams.h b/Detectors/CPV/simulation/include/CPVSimulation/GeometryParams.h index 7c40586b518f7..2c2d55b48cc72 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/GeometryParams.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/GeometryParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h b/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h new file mode 100644 index 0000000000000..9467047aafb22 --- /dev/null +++ b/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_CPV_RAWWRITER_H +#define ALICEO2_CPV_RAWWRITER_H + +#include <gsl/span> + +#include <array> +#include <fstream> +#include <memory> +#include <string> +#include <map> +#include <vector> + +#include "Rtypes.h" + +#include "DetectorsRaw/RawFileWriter.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "DataFormatsCPV/CalibParams.h" +#include "DataFormatsCPV/Pedestals.h" +#include "DataFormatsCPV/BadChannelMap.h" + +namespace o2 +{ + +namespace cpv +{ + +static constexpr short kNcc = 24; ///< Total number of column controllers +static constexpr short kNPAD = 48; ///< Nuber of pads per dilogic +static constexpr short kNDilogic = 4; ///< Number of dilogics +static constexpr short kNGasiplex = 5; ///< Number of dilogic per row +static constexpr short kNRow = 48; ///< number of rows 16*3 mod + +struct GBTLinkAttributes { + short linkId; + short feeId; + short cruId; + short endPointId; + std::string flpId; +}; +static constexpr short kNGBTLinks = 3; ///< Number of GBT links +const GBTLinkAttributes links[kNGBTLinks] = + { + {0, 0, 0, 0, "alio2-cr1-flp162"}, + {1, 1, 0, 0, "alio2-cr1-flp162"}, + {2, 2, 0, 0, "alio2-cr1-flp162"}}; + +struct padCharge { + short charge; + short pad; + padCharge() : charge(0), pad(0) {} + padCharge(short a, short b) : charge(a), + pad(b) + { + } //for std::vector::emplace_back functionality +}; + +class RawWriter +{ + public: + enum class FileFor_t { + kFullDet, + kLink + }; + RawWriter() = default; + RawWriter(const char* outputdir) { setOutputLocation(outputdir); } + ~RawWriter() = default; + + o2::raw::RawFileWriter& getWriter() const { return *mRawWriter; } + + void setOutputLocation(const char* outputdir) { mOutputLocation = outputdir; } + void setCcdbUrl(const char* ccdbUrl) { mCcdbUrl = ccdbUrl; } + void setFileFor(FileFor_t filefor) { mFileFor = filefor; } + + void init(); + void digitsToRaw(gsl::span<o2::cpv::Digit> digits, gsl::span<o2::cpv::TriggerRecord> triggers); + bool processOrbit(const gsl::span<o2::cpv::Digit> digitsbranch, const gsl::span<o2::cpv::TriggerRecord> trgs); + + int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const; + + private: + std::vector<padCharge> mPadCharge[kNcc][kNDilogic][kNGasiplex]; ///< list of signals per event + FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files + std::string mOutputLocation = "./"; ///< Rawfile name + std::string mCcdbUrl = "http://ccdb-test.cern.ch:8080"; ///< CCDB Url + CalibParams* mCalibParams = nullptr; ///< CPV calibration + Pedestals* mPedestals = nullptr; ///< CPV pedestals + BadChannelMap* mBadMap = nullptr; ///< CPV bad channel map + + std::vector<char> mPayload[kNGBTLinks]; ///< Preformatted payload for every link to be written + gsl::span<o2::cpv::Digit> mDigits; ///< Digits input vector - must be in digitized format + std::unique_ptr<o2::raw::RawFileWriter> mRawWriter; ///< Raw writer + + ClassDefNV(RawWriter, 2); +}; + +} // namespace cpv + +} // namespace o2 + +#endif diff --git a/Detectors/CPV/simulation/src/CPVSimulationLinkDef.h b/Detectors/CPV/simulation/src/CPVSimulationLinkDef.h index 1c9ff59953133..20ca9a8264f90 100644 --- a/Detectors/CPV/simulation/src/CPVSimulationLinkDef.h +++ b/Detectors/CPV/simulation/src/CPVSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,5 +19,6 @@ #pragma link C++ class o2::cpv::GeometryParams + ; #pragma link C++ class o2::base::DetImpl < o2::cpv::Detector> + ; #pragma link C++ class o2::cpv::Digitizer + ; +#pragma link C++ class o2::cpv::RawWriter + ; #endif diff --git a/Detectors/CPV/simulation/src/Detector.cxx b/Detectors/CPV/simulation/src/Detector.cxx index a6df5ae4806f6..6f6f0c62d1392 100644 --- a/Detectors/CPV/simulation/src/Detector.cxx +++ b/Detectors/CPV/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include "FairVolume.h" #include "CPVBase/Geometry.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" #include "CPVBase/CPVSimParams.h" #include "CPVSimulation/Detector.h" #include "CPVSimulation/GeometryParams.h" @@ -96,12 +97,9 @@ void Detector::FinishEvent() mHits->erase(itr, mHits->end()); - // std::ostream stream(nullptr); - // stream.rdbuf(std::cout.rdbuf()); // uses cout's buffer - // stream.rdbuf(LOG(DEBUG2)); - // for (int i = 0; i < mHits->size(); i++) { - // mHits->at(i).PrintStream(stream); - // } + // printf("hits: %d \n",mHits->size()) ; + // int c=0; + // for(const Hit &h : *mHits){ if(h.GetDetectorID()<c){printf("Ht %d < %d\n",h.GetDetectorID(),c) ;} c=h.GetDetectorID() ;} } void Detector::Reset() { @@ -232,7 +230,7 @@ Bool_t Detector::ProcessHits(FairVolume* v) int nx3 = (cpvparam.mNgamx + 1) / 2; TVirtualMCStack* stack = fMC->GetStack(); - const Int_t partID = stack->GetCurrentTrackNumber(); + const int partID = stack->GetCurrentTrackNumber(); for (int iter = 0; iter < nIter; iter++) { @@ -249,33 +247,31 @@ Bool_t Detector::ProcessHits(FairVolume* v) int ixcell = (int)xcell; float zc = zcell - izcell - 0.5; float xc = xcell - ixcell - 0.5; - for (int iz = 1; iz <= cpvparam.mNgamz; iz++) { + for (int iz = 0; iz < cpvparam.mNgamz; iz++) { int kzg = izcell + iz - nz3; - if (kzg <= 0 || kzg > cpvparam.mnCellZ) { + if (kzg < 0 || kzg >= cpvparam.mnCellZ) { continue; } float zg = (float)(iz - nz3) - zc; - for (int ix = 1; ix <= cpvparam.mNgamx; ix++) { + for (int ix = 0; ix < cpvparam.mNgamx; ix++) { int kxg = ixcell + ix - nx3; - if (kxg <= 0 || kxg > cpvparam.mnCellX) { + if (kxg < 0 || kxg >= cpvparam.mnCellX) { continue; } float xg = (float)(ix - nx3) - xc; // Now calculate pad response - float qpad = padResponseFunction(qhit, zg, xg); - qpad += cpvparam.mNoise * rnor2; + double qpad = padResponseFunction(qhit, zg, xg); if (qpad < 0) { continue; } // Fill hit with pad response ID and amplitude // hist will be sorted and merged later if necessary - short detID = Geometry::relToAbsId(moduleNumber, kxg, kzg); + int detID = Geometry::relToAbsId(moduleNumber, kxg, kzg); addHit(partID, detID, math_utils::Point3D<float>(xyzm[0], xyzm[1], xyzm[2]), time, qpad); } } } - return true; } @@ -351,11 +347,10 @@ void Detector::ConstructGeometry() // Configure geometry So far we have only one: Run3 { mActiveModule[0] = kFALSE; - mActiveModule[1] = kTRUE; + mActiveModule[1] = kFALSE; mActiveModule[2] = kTRUE; mActiveModule[3] = kTRUE; - mActiveModule[4] = kFALSE; - mActiveModule[5] = kFALSE; + mActiveModule[4] = kTRUE; } // First create necessary materials @@ -375,7 +370,7 @@ void Detector::ConstructGeometry() int iXYZ, iAngle; char im[5]; for (int iModule = 0; iModule < 5; iModule++) { - if (!mActiveModule[iModule + 1]) { + if (!mActiveModule[iModule]) { continue; } float angle[3][2] = {0}; @@ -385,7 +380,7 @@ void Detector::ConstructGeometry() float pos[3] = {0}; geomParams->GetModuleCenter(iModule, pos); - fMC->Gspos("CPV", iModule + 1, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); + fMC->Gspos("CPV", iModule, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); } //start filling CPV moodules @@ -563,15 +558,18 @@ void Detector::addAlignableVolumes() const TString symbModuleName = "CPV/Module"; - for (Int_t iModule = 1; iModule <= geom->GetNModules(); iModule++) { + for (Int_t iModule = 0; iModule < geom->GetNModules(); iModule++) { + if (!mActiveModule[iModule]) { + continue; + } TString volPath(physModulePath); volPath += iModule; TString symName(symbModuleName); symName += iModule; - int modUID = o2::base::GeometryManager::getSensID(idCPV, iModule - 1); + int modUID = o2::base::GeometryManager::getSensID(idCPV, iModule); LOG(DEBUG) << "--------------------------------------------" << "\n"; diff --git a/Detectors/CPV/simulation/src/Digitizer.cxx b/Detectors/CPV/simulation/src/Digitizer.cxx index d2433d37123cd..fbfddad2b0328 100644 --- a/Detectors/CPV/simulation/src/Digitizer.cxx +++ b/Detectors/CPV/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,8 @@ #include "CPVSimulation/Digitizer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "CPVBase/CPVSimParams.h" -#include "CCDB/CcdbApi.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/BasicCCDBManager.h" #include <TRandom.h> #include "FairLogger.h" // for LOG @@ -26,20 +28,55 @@ using namespace o2::cpv; //_______________________________________________________________________ void Digitizer::init() { - if (!mCalibParams) { - if (o2::cpv::CPVSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mCalibParams = new CalibParams(1); // test default calibration - LOG(INFO) << "[CPVDigitizer] No reading calibration from ccdb requested, set default"; - } else { - LOG(INFO) << "[CPVDigitizer] getting calibration object from ccdb"; - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - mCalibParams = ccdb.retrieveFromTFileAny<o2::cpv::CalibParams>("CPV/Calib", metadata, mEventTime); - if (!mCalibParams) { - LOG(FATAL) << "[CPVDigitizer] can not get calibration object from ccdb"; - } + LOG(INFO) << "CPVDigitizer::init() : CCDB Url = " << o2::cpv::CPVSimParams::Instance().mCCDBPath.data(); + if (o2::cpv::CPVSimParams::Instance().mCCDBPath.compare("localtest") == 0) { + mCalibParams = new CalibParams(1); // test default calibration + mPedestals = new Pedestals(1); // test default pedestals + mBadMap = new BadChannelMap(1); // test default bad channels + LOG(INFO) << "[CPVDigitizer] No reading calibration from ccdb requested, set default"; + } else { + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + ccdbMgr.setURL(o2::cpv::CPVSimParams::Instance().mCCDBPath.data()); + bool isCcdbReachable = ccdbMgr.isHostReachable(); //if host is not reachable we can use only dummy calibration + if (!isCcdbReachable) { + LOG(FATAL) << "[CPVDigitizer] CCDB Host is not reachable!!!"; + return; + } + ccdbMgr.setCaching(true); //make local cache of remote objects + ccdbMgr.setLocalObjectValidityChecking(true); //query objects from remote site only when local one is not valid + //read calibration from ccdb (for now do it only at the beginning of dataprocessing) + //TODO: setup timestam according to anchors + ccdbMgr.setTimestamp(o2::ccdb::getCurrentTimestamp()); + + LOG(INFO) << "CCDB: Reading o2::cpv::CalibParams from CPV/Calib/Gains"; + mCalibParams = ccdbMgr.get<o2::cpv::CalibParams>("CPV/Calib/Gains"); + if (!mCalibParams) { + LOG(ERROR) << "Cannot get o2::cpv::CalibParams from CCDB. using dummy calibration!"; + mCalibParams = new CalibParams(1); + } + + LOG(INFO) << "CCDB: Reading o2::cpv::Pedestals from CPV/Calib/Pedestals"; + mPedestals = ccdbMgr.get<o2::cpv::Pedestals>("CPV/Calib/Pedestals"); + if (!mPedestals) { + LOG(ERROR) << "Cannot get o2::cpv::Pedestals from CCDB. using dummy calibration!"; + mPedestals = new Pedestals(1); + } + + LOG(INFO) << "CCDB: Reading o2::cpv::BadChannelMap from CPV/Calib/BadChannelMap"; + mBadMap = ccdbMgr.get<o2::cpv::BadChannelMap>("CPV/Calib/BadChannelMap"); + if (!mBadMap) { + LOG(ERROR) << "Cannot get o2::cpv::BadChannelMap from CCDB. using dummy calibration!"; + mBadMap = new BadChannelMap(1); } + + LOG(INFO) << "Task configuration is done."; + } + + //signal thresolds for digits + //note that digits are calibrated objects + for (int i = 0; i < NCHANNELS; i++) { + mDigitThresholds[i] = o2::cpv::CPVSimParams::Instance().mZSnSigmas * + mPedestals->getPedSigma(i) * mCalibParams->getGain(i); } } @@ -47,183 +84,81 @@ void Digitizer::init() void Digitizer::finish() {} //_______________________________________________________________________ -void Digitizer::process(const std::vector<Hit>* hitsBg, const std::vector<Hit>* hitsS, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels) +void Digitizer::processHits(const std::vector<Hit>* hits, const std::vector<Digit>& digitsBg, + std::vector<Digit>& digitsOut, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels, + int collId, int source, double dt) { // Convert list of hits to digits: // Add hits with ampl deposition in same pad and same time // Add ampl corrections // Apply time smearing - - std::vector<Hit>::const_iterator hitBg = hitsBg->cbegin(); - std::vector<Hit>::const_iterator hitS = hitsS->cbegin(); - std::vector<Hit>::const_iterator hit; - const short kBigAbsID = 32767; //Far above maximal CPV absId - short hitAbsId = kBigAbsID; - short hitBgAbsId = kBigAbsID; - short hitSAbsId = kBigAbsID; - - if (hitBg != hitsBg->end()) { - hitBgAbsId = hitBg->GetDetectorID(); - } - if (hitS != hitsS->end()) { - hitSAbsId = hitS->GetDetectorID(); + // //Despite sorting in Detector::EndEvent(), hits still can be unsorted due to splitting of processing different bunches of primary + for (int i = NCHANNELS; i--;) { + mArrayD[i].reset(); } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; + + if (digitsBg.size() == 0) { // no digits provided: try simulate pedestal noise (do it only once) + for (int i = NCHANNELS; i--;) { + float amplitude = simulatePedestalNoise(i); + mArrayD[i].setAmplitude(amplitude); + mArrayD[i].setAbsId(i); + } + } else { //if digits exist, no noise should be added + for (auto& dBg : digitsBg) { //digits are sorted and unique + mArrayD[dBg.getAbsId()] = dBg; } } - short nTotPads = Geometry::getTotalNPads(); - for (short absId = 1; absId < nTotPads; absId++) { - - // If signal exist in this pad, add noise to it, otherwise just create noise digit - if (absId == hitAbsId) { - int labelIndex = labels.getIndexedSize(); - //Add primary info: create new MCLabels entry - o2::MCCompLabel label(hit->GetTrackID(), mCurrEvID, mCurrSrcID, true); - labels.addElement(labelIndex, label); - - Digit digit((*hit), labelIndex); - - //May be add more hits to this digit? - if (hitBg == hitsBg->end()) { - hitBgAbsId = kBigAbsID; - } else { - hitBgAbsId = hitBg->GetDetectorID(); - } - if (hitS == hitsS->end()) { - hitSAbsId = kBigAbsID; - } else { - hitSAbsId = hitS->GetDetectorID(); - } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; - } else { //no hits left - hitAbsId = kBigAbsID; - continue; - } - } - - while (absId == hitAbsId) { - Digit digitNext((*hit), labelIndex); //Use same MCTruth entry so far - digit += digitNext; - - //add MCLabel to list (add energy if same primary or add another label) - o2::MCCompLabel label(hit->GetTrackID(), mCurrEvID, mCurrSrcID, true); + //add Hits + for (auto& h : *hits) { + int i = h.GetDetectorID(); + if (mArrayD[i].getAmplitude() > 0) { + mArrayD[i].setAmplitude(mArrayD[i].getAmplitude() + h.GetEnergyLoss()); + } else { + mArrayD[i].setAmplitude(h.GetEnergyLoss()); + mArrayD[i].setAbsId(i); + } + if (mArrayD[i].getAmplitude() > mDigitThresholds[i]) { + int labelIndex = mArrayD[i].getLabel(); + if (labelIndex == -1) { //no digit or noisy + labelIndex = labels.getIndexedSize(); + o2::MCCompLabel label(h.GetTrackID(), collId, source, true); labels.addElement(labelIndex, label); - - //next hit? - if (hitBg == hitsBg->end()) { - hitBgAbsId = kBigAbsID; - } else { - hitBgAbsId = hitBg->GetDetectorID(); - } - if (hitS == hitsS->end()) { - hitSAbsId = kBigAbsID; - } else { - hitSAbsId = hitS->GetDetectorID(); - } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; - } else { //no hits left - hitAbsId = kBigAbsID; - digitNext.setAbsId(kBigAbsID); - continue; + mArrayD[i].setLabel(labelIndex); + } else { //check if lable already exist + gsl::span<MCCompLabel> sp = labels.getLabels(labelIndex); + bool found = false; + for (MCCompLabel& te : sp) { + if (te.getTrackID() == h.GetTrackID() && te.getEventID() == collId && te.getSourceID() == source) { + found = true; + break; } } - - digitNext.fillFromHit(*hit); - } - // //Current digit finished, sort MCLabels according to eDeposited - // auto lbls = labels.getLabels(labelIndex); - // std::sort(lbls.begin(), lbls.end(), - // [](o2::MCCompLabel a, o2::MCCompLabel b) { return a.getEdep() > b.getEdep(); }); - - // Add Electroinc noise, apply non-linearity, digitize, de-calibrate, time resolution - float ampl = digit.getAmplitude(); - // Simulate electronic noise - ampl += simulateNoise(); - - ampl = uncalibrate(ampl, absId); - - if (ampl < o2::cpv::CPVSimParams::Instance().mZSthreshold) { - continue; - } - digit.setAmplitude(ampl); - - digits.push_back(digit); - } else { // No signal in this pad, - if (!Geometry::IsPadExists(absId)) { - continue; - } - // Simulate noise - float ampl = simulateNoise(); - ampl = uncalibrate(ampl, absId); - if (ampl > o2::cpv::CPVSimParams::Instance().mZSthreshold) { - digits.emplace_back(absId, ampl, -1); // current AbsId, energy, no primary + if (!found) { + o2::MCCompLabel label(h.GetTrackID(), collId, source, true); + //Highly inefficient management of Labels: commenting line below reeduces WHOLE digitization time by factor ~30 + labels.addElementRandomAccess(labelIndex, label); + } } } } -} - -float Digitizer::simulateNoise() { return gRandom->Gaus(0., o2::cpv::CPVSimParams::Instance().mNoise); } -//_______________________________________________________________________ -float Digitizer::uncalibrate(const float e, const int absId) -{ - // Decalibrate CPV digit, i.e. transform from amplitude to ADC counts a factor read from CDB - float calib = mCalibParams->getGain(absId); - if (calib > 0) { - return floor(e / calib); - } else { - return 0; // TODO apply de-calibration from OCDB - } -} - -void Digitizer::setEventTime(double t) -{ - // assign event time, it should be in a strictly increasing order - // convert to ns - - if (t < mEventTime) { - LOG(FATAL) << "New event time (" << t << ") is < previous event time (" << mEventTime << ")"; + //finalize output digits + for (int i = 0; i < NCHANNELS; i++) { + if (!mBadMap->isChannelGood(i)) { + continue; //bad channel -> skip this digit + } + if (mArrayD[i].getAmplitude() > mDigitThresholds[i]) { + digitsOut.push_back(mArrayD[i]); + } } - mEventTime = t; } -//_______________________________________________________________________ -void Digitizer::setCurrEvID(int v) +float Digitizer::simulatePedestalNoise(int absId) { - // set current MC event ID - if (v > MCCompLabel::maxEventID()) { - LOG(FATAL) << "MC event id " << v << " exceeds max storable in the label " << MCCompLabel::maxEventID(); + //this function is to simulate pedestal and its noise (ADC counts) + if (absId < 0 || absId >= NCHANNELS) { + return 0.; } - mCurrEvID = v; + return gRandom->Gaus(0, mPedestals->getPedSigma(absId) * mCalibParams->getGain(absId)); } diff --git a/Detectors/CPV/simulation/src/GeometryParams.cxx b/Detectors/CPV/simulation/src/GeometryParams.cxx index 064b7e2a2d425..0b7004a9cfa3d 100644 --- a/Detectors/CPV/simulation/src/GeometryParams.cxx +++ b/Detectors/CPV/simulation/src/GeometryParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ GeometryParams* GeometryParams::sGeomParam = nullptr; GeometryParams::GeometryParams(const std::string_view name) : // Set zeros to the variables: most of them should be calculated // and it is more clear to set them in the text - mNModules(3), + mNModules(5), mNumberOfCPVPadsPhi(128), mNumberOfCPVPadsZ(60), mCPVPadSizePhi(1.13), @@ -70,17 +71,17 @@ GeometryParams::GeometryParams(const std::string_view name) double const kRADDEG = 180.0 / TMath::Pi(); double r = mIPtoCPVSurface + mCPVBoxSize[1]; - for (Int_t iModule = 0; iModule < mNModules; iModule++) { - double angle = moduleAngle * (iModule - 2); //Module 3 just below IP - mCPVAngle[iModule] = -angle; - mModuleCenter[iModule][0] = r * TMath::Sin(-angle / kRADDEG); - mModuleCenter[iModule][1] = -r * TMath::Cos(-angle / kRADDEG); + for (Int_t iModule = 2; iModule < mNModules; iModule++) { + double angle = moduleAngle * (iModule - 2); //Module 2 just below IP + mCPVAngle[iModule] = angle; + mModuleCenter[iModule][0] = r * TMath::Sin(angle / kRADDEG); + mModuleCenter[iModule][1] = -r * TMath::Cos(angle / kRADDEG); mModuleCenter[iModule][2] = 0.; mModuleAngle[iModule][0][0] = 90; //thetaX polar angle for axis X - mModuleAngle[iModule][0][1] = -angle; //phiX azimuthal angle for axis X + mModuleAngle[iModule][0][1] = angle; //phiX azimuthal angle for axis X mModuleAngle[iModule][1][0] = 90; //thetaY polar angle for axis Y - mModuleAngle[iModule][1][1] = 90 - angle; //phiY azimuthal angle for axis Y + mModuleAngle[iModule][1][1] = 90 + angle; //phiY azimuthal angle for axis Y mModuleAngle[iModule][2][0] = 0; //thetaZ polar angle for axis Z mModuleAngle[iModule][2][1] = 0; //phiZ azimuthal angle for axis Z } diff --git a/Detectors/CPV/simulation/src/RawCreator.cxx b/Detectors/CPV/simulation/src/RawCreator.cxx new file mode 100644 index 0000000000000..5921cb7c3b4b6 --- /dev/null +++ b/Detectors/CPV/simulation/src/RawCreator.cxx @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <memory> +#include <string> +#include <vector> +#include "Framework/Logger.h" + +#include <boost/program_options.hpp> + +#include <TFile.h> +#include <TTree.h> +#include <TTreeReader.h> +#include <filesystem> + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/StringUtils.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "CPVBase/Geometry.h" +#include "CPVSimulation/RawWriter.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" + +namespace bpo = boost::program_options; + +int main(int argc, const char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " <cmds/options>\n" + " Tool will encode cpv raw data from input file\n" + "Commands / Options"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbose,v", bpo::value<uint32_t>()->default_value(0), "Select verbosity level [0 = no output]"); + add_option("input-file,i", bpo::value<std::string>()->default_value("cpvdigits.root"), "Specifies digit input file."); + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,cru,link"); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); + add_option("debug,d", bpo::value<uint32_t>()->default_value(0), "Select debug output level [0 = no debug output]"); + add_option("ccdb-url,c", bpo::value<std::string>()->default_value("http://ccdb-test.cern.ch:8080"), "CCDB Url ['localtest' for local testing]"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help") || argc == 1) { + std::cout << opt_general << std::endl; + exit(0); + } + + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + + auto digitfilename = vm["input-file"].as<std::string>(), + outputdir = vm["output-dir"].as<std::string>(), + filefor = vm["file-for"].as<std::string>(); + + auto ccdbUrl = vm["ccdb-url"].as<std::string>(); + + // if needed, create output directory + if (!std::filesystem::exists(outputdir)) { + if (!std::filesystem::create_directories(outputdir)) { + LOG(FATAL) << "could not create output directory " << outputdir; + } else { + LOG(INFO) << "created output directory " << outputdir; + } + } + + std::unique_ptr<TFile> digitfile(TFile::Open(digitfilename.data(), "READ")); + auto treereader = std::make_unique<TTreeReader>(static_cast<TTree*>(digitfile->Get("o2sim"))); + TTreeReaderValue<std::vector<o2::cpv::Digit>> digitbranch(*treereader, "CPVDigit"); + TTreeReaderValue<std::vector<o2::cpv::TriggerRecord>> triggerbranch(*treereader, "CPVDigitTrigRecords"); + + o2::cpv::RawWriter::FileFor_t granularity = o2::cpv::RawWriter::FileFor_t::kFullDet; + if ((filefor == "all") || (filefor == "cru")) { //CPV has only 1 cru so "all" is identical to "cru" + granularity = o2::cpv::RawWriter::FileFor_t::kFullDet; + } else if (filefor == "link") { + granularity = o2::cpv::RawWriter::FileFor_t::kLink; + } + + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + + o2::cpv::RawWriter rawwriter; + rawwriter.setOutputLocation(outputdir.data()); + rawwriter.setFileFor(granularity); + rawwriter.setCcdbUrl(ccdbUrl.data()); + rawwriter.init(); + rawwriter.getWriter().setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::CPV)); // must be set explicitly + + // Loop over all entries in the tree, where each tree entry corresponds to a time frame + for (auto en : *treereader) { + LOG(DEBUG) << "RawCreator::main() : I call rawwriter.digitsToRaw(). " + << "Sending following tree: "; + for (int i = 0; i < (*triggerbranch).size(); i++) { + LOG(DEBUG) << (*triggerbranch)[i]; + } + rawwriter.digitsToRaw(*digitbranch, *triggerbranch); + } + rawwriter.getWriter().writeConfFile("CPV", "RAWDATA", o2::utils::Str::concat_string(outputdir, "/CPVraw.cfg")); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} diff --git a/Detectors/CPV/simulation/src/RawWriter.cxx b/Detectors/CPV/simulation/src/RawWriter.cxx new file mode 100644 index 0000000000000..2fac193147c41 --- /dev/null +++ b/Detectors/CPV/simulation/src/RawWriter.cxx @@ -0,0 +1,316 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FairLogger.h" + +#include <fmt/core.h> +#include <gsl/span> +#include <TSystem.h> +#include "DetectorsRaw/RDHUtils.h" +#include "DataFormatsCPV/RawFormats.h" +#include "CPVSimulation/RawWriter.h" +#include "CPVBase/CPVSimParams.h" +#include "CPVBase/Geometry.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/BasicCCDBManager.h" + +using namespace o2::cpv; + +void RawWriter::init() +{ + mRawWriter = std::make_unique<o2::raw::RawFileWriter>(o2::header::gDataOriginCPV, true); //true = cru detector + mRawWriter->setCarryOverCallBack(this); + mRawWriter->setApplyCarryOverToLastPage(true); + + //register all cpv links + for (auto&& link : links) { + std::string rawFileName = mOutputLocation + "/CPV_" + link.flpId + "_cru" + std::to_string(link.cruId) + "_" + std::to_string(link.endPointId); + if (mFileFor == FileFor_t::kLink) { + rawFileName += Form("link%d", link.linkId); + } + rawFileName += ".raw"; + mRawWriter->registerLink(link.feeId, link.cruId, link.linkId, link.endPointId, rawFileName.data()); + } + + //CCDB setup + LOG(INFO) << "CCDB Url: " << mCcdbUrl; + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + ccdbMgr.setURL(mCcdbUrl); + bool isCcdbReachable = ccdbMgr.isHostReachable(); //if host is not reachable we can use only dummy calibration + if (!isCcdbReachable) { + if (mCcdbUrl.compare("localtest") != 0) { + LOG(ERROR) << "Host " << mCcdbUrl << " is not reachable!!!"; + } + LOG(INFO) << "Using dummy calibration"; + mCalibParams = new o2::cpv::CalibParams(1); + mBadMap = new o2::cpv::BadChannelMap(1); + mPedestals = new o2::cpv::Pedestals(1); + } else { + ccdbMgr.setCaching(true); //make local cache of remote objects + ccdbMgr.setLocalObjectValidityChecking(true); //query objects from remote site only when local one is not valid + LOG(INFO) << "Successfully initializated BasicCCDBManager with caching option"; + + //read calibration from ccdb (for now do it only at the beginning of dataprocessing) + //TODO: setup timestam according to anchors + ccdbMgr.setTimestamp(o2::ccdb::getCurrentTimestamp()); + + LOG(INFO) << "CCDB: Reading o2::cpv::CalibParams from CPV/Calib/Gains"; + mCalibParams = ccdbMgr.get<o2::cpv::CalibParams>("CPV/Calib/Gains"); + if (!mCalibParams) { + LOG(ERROR) << "Cannot get o2::cpv::CalibParams from CCDB. using dummy calibration!"; + mCalibParams = new o2::cpv::CalibParams(1); + } + + /* + LOG(INFO) << "CCDB: Reading o2::cpv::BadChannelMap from CPV/Calib/BadChannelMap"; + mBadMap = ccdbMgr.get<o2::cpv::BadChannelMap>("CPV/Calib/BadChannelMap")); + if (!mBadMap) { + LOG(ERROR) << "Cannot get o2::cpv::BadChannelMap from CCDB. using dummy calibration!"; + mBadMap = new o2::cpv::BadChannelMap(1); + } + */ + + LOG(INFO) << "CCDB: Reading o2::cpv::Pedestals from CPV/Calib/Pedestals"; + mPedestals = ccdbMgr.get<o2::cpv::Pedestals>("CPV/Calib/Pedestals"); + if (!mPedestals) { + LOG(ERROR) << "Cannot get o2::cpv::Pedestals from CCDB. using dummy calibration!"; + mPedestals = new o2::cpv::Pedestals(1); + } + LOG(INFO) << "Task configuration is done."; + } +} + +void RawWriter::digitsToRaw(gsl::span<o2::cpv::Digit> digitsbranch, gsl::span<o2::cpv::TriggerRecord> triggerbranch) +{ + if (triggerbranch.begin() == triggerbranch.end()) { //do we have any data? + return; + } + + //process digits which belong to same orbit + int iFirstTrgInCurrentOrbit = 0; + int currentOrbit = triggerbranch[0].getBCData().orbit; + int nTrgsInCurrentOrbit = 1; + for (int iTrg = 1; iTrg < triggerbranch.size(); iTrg++) { + if (triggerbranch[iTrg].getBCData().orbit != currentOrbit) { //if orbit changed, write previous orbit to file + processOrbit(digitsbranch, triggerbranch.subspan(iFirstTrgInCurrentOrbit, nTrgsInCurrentOrbit)); + iFirstTrgInCurrentOrbit = iTrg; //orbit changed + nTrgsInCurrentOrbit = 1; + currentOrbit = triggerbranch[iTrg].getBCData().orbit; + } else { + nTrgsInCurrentOrbit++; + } + } + processOrbit(digitsbranch, triggerbranch.subspan(iFirstTrgInCurrentOrbit, nTrgsInCurrentOrbit)); //process last orbit +} + +//prepare preformatted data for one orbit and send it to RawFileWriter +bool RawWriter::processOrbit(const gsl::span<o2::cpv::Digit> digitsbranch, const gsl::span<o2::cpv::TriggerRecord> trgs) +{ + static int nMaxGbtWordsPerPage = o2::raw::RDHUtils::MAXCRUPage / o2::raw::RDHUtils::GBTWord - 4; //512*16/16 - 4 = 508; + //4 gbt words are reserved for RDH + + //clear payloads of all links + for (auto& payload : mPayload) { + payload.clear(); + } + + //we're going to prepare preformatted pages + bool preformatted = true; + + int gbtWordCounter[kNGBTLinks] = {0, 0, 0}; + int gbtWordCounterBeforeCPVTrailer[kNGBTLinks] = {0, 0, 0}; + bool isHeaderClosedWithTrailer[kNGBTLinks] = {false, false, false}; + for (auto& trg : trgs) { + LOG(DEBUG) << "RawWriter::processOrbit() : " + << "I start to process trigger record (orbit = " << trg.getBCData().orbit + << ", BC = " << trg.getBCData().bc << ")"; + LOG(DEBUG) << "First entry = " << trg.getFirstEntry() << ", Number of objects = " << trg.getNumberOfObjects(); + + //Clear array which is used to store digits + for (int i = kNcc; i--;) { + for (int j = kNDilogic; j--;) { + for (int k = kNGasiplex; k--;) { + mPadCharge[i][j][k].clear(); + } + } + } + + //make payload for current trigger + int nDigsInTrg[kNGBTLinks] = {0, 0, 0}; + for (auto& dig : gsl::span(digitsbranch.data() + trg.getFirstEntry(), trg.getNumberOfObjects())) { + + short absId = dig.getAbsId(); + short ccId, dil, gas, pad; + o2::cpv::Geometry::absIdToHWaddress(absId, ccId, dil, gas, pad); + + //Convert Amp to ADC counts + short charge = std::round(dig.getAmplitude() / mCalibParams->getGain(absId) + mPedestals->getPedestal(absId)); + if (charge > 4095) { + charge = 4095; + } + mPadCharge[ccId][dil][gas].emplace_back(charge, pad); + nDigsInTrg[ccId / (kNcc / kNGBTLinks)]++; //linkId = ccId/8 or absId/7680 + } + LOG(DEBUG) << "I produced " << nDigsInTrg << " digits for this trigger record"; + + //we need to write header + at least 1 payload word + trailer + for (int iLink = 0; iLink < kNGBTLinks; iLink++) { //looping links + gbtWordCounterBeforeCPVTrailer[iLink] = 0; + if (nMaxGbtWordsPerPage - gbtWordCounter[iLink] < 3) { //otherwise flush already prepared data to file + LOG(DEBUG) << "RawWriter::processOrbit() : before header: adding preformatted dma page of size " << mPayload[iLink].size(); + mRawWriter->addData(links[iLink].feeId, links[iLink].cruId, links[iLink].linkId, links[iLink].endPointId, trg.getBCData(), + gsl::span<char>(mPayload[iLink].data(), mPayload[iLink].size()), preformatted); + mPayload[iLink].clear(); + gbtWordCounter[iLink] = 0; + gbtWordCounterBeforeCPVTrailer[iLink] = 0; + } + + //first, header goes + CpvHeader header(trg.getBCData(), false, false); + for (int i = 0; i < 16; i++) { + mPayload[iLink].push_back(header.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = false; + LOG(DEBUG) << "RawWriter::processOrbit() : " + << "I wrote cpv header for orbit = " << trg.getBCData().orbit + << " and BC = " << trg.getBCData().bc; + + gbtWordCounter[iLink]++; + gbtWordCounterBeforeCPVTrailer[iLink]++; + + int nDigsToWriteLeft = nDigsInTrg[iLink]; + + for (char ccId = iLink * (kNcc / kNGBTLinks); (ccId < (iLink + 1) * (kNcc / kNGBTLinks)) && (ccId < kNcc); ccId++) { + int ccWordCounter = 0; + for (char dil = 0; dil < kNDilogic; dil++) { + for (char gas = 0; gas < kNGasiplex; gas++) { + for (padCharge& pc : mPadCharge[ccId][dil][gas]) { + // Generate 3 CC words, add CC header and empty bits to complete 128 bits; + PadWord currentword = {0}; + currentword.charge = pc.charge; + currentword.address = pc.pad; + currentword.gas = gas; + currentword.dil = dil; + mPayload[iLink].push_back(currentword.mBytes[0]); + mPayload[iLink].push_back(currentword.mBytes[1]); + mPayload[iLink].push_back(currentword.mBytes[2]); + ccWordCounter++; + nDigsToWriteLeft--; + if (ccWordCounter % 3 == 0) { // complete 3 channels (72 bit) + CC index (8 bits) + 6 empty bits = Generate 128 bits of data + mPayload[iLink].push_back(ccId); + for (int i = 6; i--;) { + mPayload[iLink].push_back(char(0)); + } + gbtWordCounter[iLink]++; + gbtWordCounterBeforeCPVTrailer[iLink]++; + if (nMaxGbtWordsPerPage - gbtWordCounter[iLink] == 1) { //the only space for trailer left on current page + CpvTrailer tr(gbtWordCounterBeforeCPVTrailer[iLink], trg.getBCData().bc, nDigsToWriteLeft == 0); //add trailer and flush page to file + for (int i = 0; i < 16; i++) { + mPayload[iLink].push_back(tr.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = true; + LOG(DEBUG) << "RawWriter::processOrbit() : middle of payload: adding preformatted dma page of size " << mPayload[iLink].size(); + mRawWriter->addData(links[iLink].feeId, links[iLink].cruId, links[iLink].linkId, links[iLink].endPointId, trg.getBCData(), + gsl::span<char>(mPayload[iLink].data(), mPayload[iLink].size()), preformatted); + + mPayload[iLink].clear(); + gbtWordCounter[iLink] = 0; + gbtWordCounterBeforeCPVTrailer[iLink] = 0; + if (nDigsToWriteLeft) { //some digits left for writing + CpvHeader newHeader(trg.getBCData(), false, true); + for (int i = 0; i < 16; i++) { //so put a new header and continue + mPayload[iLink].push_back(newHeader.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = false; + gbtWordCounter[iLink]++; + gbtWordCounterBeforeCPVTrailer[iLink]++; + } + } + } + } + } + } //end of dil cycle + if (ccWordCounter % 3 != 0) { + while (ccWordCounter % 3 != 0) { + mPayload[iLink].push_back(char(255)); + mPayload[iLink].push_back(char(255)); + mPayload[iLink].push_back(char(255)); + ccWordCounter++; + } + mPayload[iLink].push_back(ccId); + for (int i = 6; i--;) { + mPayload[iLink].push_back(char(0)); + } + gbtWordCounter[iLink]++; + gbtWordCounterBeforeCPVTrailer[iLink]++; + if (nMaxGbtWordsPerPage - gbtWordCounter[iLink] == 1) { //the only space for trailer left on current page + CpvTrailer tr(gbtWordCounterBeforeCPVTrailer[iLink], trg.getBCData().bc, nDigsToWriteLeft == 0); //add trailer and flush page to file + for (int i = 0; i < 16; i++) { + mPayload[iLink].push_back(tr.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = true; + LOG(DEBUG) << "RawWriter::processOrbit() : middle of payload (after filling empty words): adding preformatted dma page of size " << mPayload[iLink].size(); + mRawWriter->addData(links[iLink].feeId, links[iLink].cruId, links[iLink].linkId, links[iLink].endPointId, trg.getBCData(), + gsl::span<char>(mPayload[iLink].data(), mPayload[iLink].size()), preformatted); + mPayload[iLink].clear(); + gbtWordCounter[iLink] = 0; + gbtWordCounterBeforeCPVTrailer[iLink] = 0; + if (nDigsToWriteLeft) { //some digits left for writing + for (int i = 0; i < 16; i++) { //so put a new header and continue + mPayload[iLink].push_back(header.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = false; + gbtWordCounter[iLink]++; + gbtWordCounterBeforeCPVTrailer[iLink]++; + } + } + } + } //end of ccId cycle + if (!isHeaderClosedWithTrailer[iLink]) { + CpvTrailer tr(gbtWordCounterBeforeCPVTrailer[iLink], trg.getBCData().bc, true); + for (int i = 0; i < 16; i++) { + mPayload[iLink].push_back(tr.mBytes[i]); + } + isHeaderClosedWithTrailer[iLink] = true; + gbtWordCounterBeforeCPVTrailer[iLink] = 0; + gbtWordCounter[iLink]++; + } + } //end of iLink cycle + } //end of "for (auto& trg : trgs)"" + + //flush payload to file (if any) + for (int iLink = 0; iLink < kNGBTLinks; iLink++) { + if (mPayload[iLink].size()) { + LOG(DEBUG) << "RawWriter::processOrbit() : final payload: adding preformatted dma page of size " << mPayload[iLink].size(); + mRawWriter->addData(links[iLink].feeId, links[iLink].cruId, links[iLink].linkId, links[iLink].endPointId, + trgs.back().getBCData(), gsl::span<char>(mPayload[iLink].data(), mPayload[iLink].size()), preformatted); + mPayload[iLink].clear(); + } + } + return true; +} +//carryover method is not used as we write preformatted pages +int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const +{ + + constexpr int cpvTrailerSize = 36; + int offs = ptr - &data[0]; // offset wrt the head of the payload + assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); // make sure ptr and end of the suggested block are within the payload + int leftBefore = data.size() - offs; // payload left before this splitting + int leftAfter = leftBefore - maxSize; // what would be left after the suggested splitting + int actualSize = maxSize; + if (leftAfter && leftAfter <= cpvTrailerSize) { // avoid splitting the trailer or writing only it. + actualSize -= (cpvTrailerSize - leftAfter) + 4; // (as we work with int, not char in decoding) + } + return actualSize; +} diff --git a/Detectors/CPV/testsimulation/CMakeLists.txt b/Detectors/CPV/testsimulation/CMakeLists.txt index c79c68e23f613..33a15099f64ca 100644 --- a/Detectors/CPV/testsimulation/CMakeLists.txt +++ b/Detectors/CPV/testsimulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(drawCPVgeometry.C PUBLIC_LINK_LIBRARIES O2::CPVSimulation @@ -16,8 +17,13 @@ o2_add_test_root_macro(drawCPVgeometry.C o2_add_test_root_macro(plot_hit_cpv.C PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CPVSimulation - LABELS cpv) + LABELS cpv COMPILE_ONLY) o2_add_test_root_macro(plot_dig_cpv.C PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CPVSimulation LABELS cpv) + +o2_add_test_root_macro(plot_clu_cpv.C + PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CPVSimulation + LABELS cpv) + diff --git a/Detectors/CPV/testsimulation/plot_clu_cpv.C b/Detectors/CPV/testsimulation/plot_clu_cpv.C new file mode 100644 index 0000000000000..a3d899640c1bc --- /dev/null +++ b/Detectors/CPV/testsimulation/plot_clu_cpv.C @@ -0,0 +1,118 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <sstream> +#include <iostream> + +#include "TROOT.h" +#include <TStopwatch.h> +#include "TCanvas.h" +#include "TH2.h" +//#include "DataFormatsParameters/GRPObject.h" +#include "FairFileSource.h" +#include "FairLogger.h" +#include "FairRunAna.h" +//#include "FairRuntimeDb.h" +#include "FairParRootFileIo.h" +#include "FairSystemInfo.h" +#include "SimulationDataFormat/MCCompLabel.h" + +#include "DataFormatsCPV/Cluster.h" +#include "CPVBase/Geometry.h" +#endif + +void plot_clu_cpv(std::string inputfile = "cpvclusters.root", int ifirst = 0, int ilast = -1) +{ + // macros to plot CPV clusters + + // Clusters + TFile* file0 = TFile::Open(inputfile.data()); + std::cout << " Open clusters file " << inputfile << std::endl; + TTree* cluTree = (TTree*)gFile->Get("o2sim"); + std::vector<o2::cpv::Cluster>* mClustersArray = nullptr; + cluTree->SetBranchAddress("CPVCluster", &mClustersArray); + + if (!mClustersArray) { + std::cout << "CPV clusters not found in the file. Exiting ..." << std::endl; + return; + } + + TH1F* hClusterTotEnergy[5]; + TH1F* hClusterMaxEnergy[5]; + TH1F* hClusterSize[5]; + TH1F* hClusterSizeX[5]; + TH1F* hClusterSizeZ[5]; + + TH2D* vMod[5][1000] = {0}; + int primLabels[5][1000]; + for (int mod = 2; mod < 5; mod++) { + hClusterTotEnergy[mod] = new TH1F(Form("hClusterTotEnergy%d", mod), + Form("Cluster Total Energy mod %d", mod), 10000, 0, 10000); + hClusterMaxEnergy[mod] = new TH1F(Form("hClusterMaxEnergy%d", mod), + Form("Cluster Max Energy mod %d", mod), 10000, 0, 10000); + hClusterSize[mod] = new TH1F(Form("hClusterSize%d", mod), + Form("Cluster Size mod %d", mod), 100, 0, 100); + hClusterSizeX[mod] = new TH1F(Form("hClusterSizeX%d", mod), + Form("Cluster SizeX mod %d", mod), 100, 0, 100); + hClusterSizeZ[mod] = new TH1F(Form("hClusterSizeZ%d", mod), + Form("Cluster SizeZ mod %d", mod), 100, 0, 100); + + for (int j = 0; j < 100; j++) + primLabels[mod][j] = -1; + } + + int nEntries = cluTree->GetEntriesFast(); + if (ilast < 0) + ilast = nEntries; + if (ilast > nEntries) + ilast = nEntries; + + for (int ievent = ifirst; ievent < ilast; ievent++) { + cluTree->GetEvent(ievent); + + std::vector<o2::cpv::Cluster>::const_iterator it; + std::cout << "I start cluster cycling (record #" << ievent << " in o2sim tree)" << std::endl; + + for (it = mClustersArray->begin(); it != mClustersArray->end(); it++) { + float en = (*it).getEnergy(); + float posX, posZ; + (*it).getLocalPosition(posX, posZ); + int cluSize = (*it).getMultiplicity(); + int mod = (*it).getModule(); + if (!vMod[mod][0]) { + gROOT->cd(); + vMod[mod][0] = + new TH2D(Form("hMod%d_prim%d", mod, 0), Form("hMod%d_prim%d", mod, 0), + 100, -100., 100., 100, -100., 100.); + } + vMod[mod][0]->Fill(posX, posZ, en); + hClusterTotEnergy[mod]->Fill(en); + hClusterSize[mod]->Fill(cluSize); + } + + std::cout << "I finish cycling clusters" << std::endl; + } + TCanvas* c[5]; + TH2D* box = new TH2D("box", "CPV module", 100, -100., 100., 100, -100., 100.); + TCanvas* cTotEn = new TCanvas(); + cTotEn->Divide(3, 1); + TCanvas* cSize = new TCanvas(); + cSize->Divide(3, 1); + + for (int mod = 2; mod < 5; mod++) { + c[mod] = + new TCanvas(Form("ClusterInMod%d", mod), Form("CPV clusters in module %d", mod), 10 * mod, 0, 600 + 10 * mod, 400); + box->Draw(); + int j = 0; + while (vMod[mod][j]) { + vMod[mod][j]->SetLineColor(j + 1); + if (j == 0) + vMod[mod][j]->Draw("box"); + else + vMod[mod][j]->Draw("boxsame"); + j++; + } + cTotEn->cd(mod - 1); + hClusterTotEnergy[mod]->Draw(); + cSize->cd(mod - 1); + hClusterSize[mod]->Draw(); + } +} diff --git a/Detectors/CPV/testsimulation/plot_dig_cpv.C b/Detectors/CPV/testsimulation/plot_dig_cpv.C index 23e4b98963db0..e66b4ef438221 100644 --- a/Detectors/CPV/testsimulation/plot_dig_cpv.C +++ b/Detectors/CPV/testsimulation/plot_dig_cpv.C @@ -6,6 +6,7 @@ #include <TStopwatch.h> #include "TCanvas.h" #include "TH2.h" +#include "TH1.h" //#include "DataFormatsParameters/GRPObject.h" #include "FairFileSource.h" #include "FairLogger.h" @@ -21,11 +22,11 @@ void plot_dig_cpv(int ievent = 0, std::string inputfile = "o2dig.root") { - // macros to plot CPV hits + // macros to plot CPV digits - // Hits - TFile* file0 = TFile::Open("o2dig.root"); - std::cout << " Open hits file " << inputfile << std::endl; + // Digits + TFile* file0 = TFile::Open(inputfile.data()); + std::cout << " Open digits file " << inputfile << std::endl; TTree* hitTree = (TTree*)gFile->Get("o2sim"); std::vector<o2::cpv::Digit>* mDigitsArray = nullptr; hitTree->SetBranchAddress("CPVDigit", &mDigitsArray); @@ -36,47 +37,58 @@ void plot_dig_cpv(int ievent = 0, std::string inputfile = "o2dig.root") } hitTree->GetEvent(ievent); - TH2D* vMod[5][100] = {0}; - int primLabels[5][100]; - for (int mod = 1; mod < 5; mod++) + TH1F* hDigitAmplitude[5]; + TH2D* vMod[5][1000] = {0}; + int primLabels[5][1000]; + for (int mod = 1; mod < 5; mod++) { + hDigitAmplitude[mod] = new TH1F(Form("hDigitAmplitude_mod%d", mod), + Form("Digit amplitudes in module %d", mod), + 4096, 0., 4096.); for (int j = 0; j < 100; j++) primLabels[mod][j] = -1; + } std::vector<o2::cpv::Digit>::const_iterator it; short relId[3]; + std::cout << "I start digit cycling" << std::endl; for (it = mDigitsArray->begin(); it != mDigitsArray->end(); it++) { short absId = (*it).getAbsId(); float en = (*it).getAmplitude(); int lab = (*it).getLabel(); //TODO + //std::cout << "label = " << lab << std::endl; o2::cpv::Geometry::absToRelNumbering(absId, relId); + hDigitAmplitude[relId[0]]->Fill(en); // check, if this label already exist int j = 0; bool found = false; - while (primLabels[relId[0]][j] >= -2) { - if (primLabels[relId[0]][j] == lab) { - found = true; - break; - } else { - j++; - } - } + //no labels for the time being + // while (primLabels[relId[0]][j] >= -2) { + // if (primLabels[relId[0]][j] == lab) { + // found = true; + // break; + // } else { + // j++; + // } + // } if (!found) { primLabels[relId[0]][j] = lab; } if (!vMod[relId[0]][j]) { gROOT->cd(); vMod[relId[0]][j] = - new TH2D(Form("hMod%d_prim%d", relId[0], j), Form("hMod%d_prim%d", relId[0], j), 60, 0., 60., 128, 0., 128.); + new TH2D(Form("hMod%d_prim%d", relId[0], j), Form("hMod%d_prim%d", relId[0], j), 128, 0., 128., 60, 0., 60.); } vMod[relId[0]][j]->Fill(relId[1] - 0.5, relId[2] - 0.5, en); } - TCanvas* c[5]; - TH2D* box = new TH2D("box", "CPV module", 60, 0., 60., 128, 0., 128.); - for (int mod = 1; mod < 5; mod++) { + std::cout << "I finish cycling digits" << std::endl; + + TCanvas *c[5], *c_ampl[5]; + TH2D* box = new TH2D("box", "CPV module", 128, 0., 128., 60, 0., 60.); + for (int mod = 2; mod < 5; mod++) { c[mod] = - new TCanvas(Form("DigitInMod%d", mod), Form("CPV hits in module %d", mod), 10 * mod, 0, 600 + 10 * mod, 400); + new TCanvas(Form("DigitInMod%d", mod), Form("CPV digits in module %d", mod), 10 * mod, 0, 600 + 10 * mod, 400); box->Draw(); int j = 0; while (vMod[mod][j]) { @@ -87,5 +99,8 @@ void plot_dig_cpv(int ievent = 0, std::string inputfile = "o2dig.root") vMod[mod][j]->Draw("boxsame"); j++; } + c_ampl[mod] = new TCanvas(Form("DigitAmplitudes_%d", mod), Form("DigitAmplitudes_%d", mod), + 10 * mod + 800, 0, 600 + 10 * mod + 200, 400); + hDigitAmplitude[mod]->Draw(); } } diff --git a/Detectors/CPV/testsimulation/plot_hit_cpv.C b/Detectors/CPV/testsimulation/plot_hit_cpv.C index cb883f2fa5f91..0ba358c0feb19 100644 --- a/Detectors/CPV/testsimulation/plot_hit_cpv.C +++ b/Detectors/CPV/testsimulation/plot_hit_cpv.C @@ -13,7 +13,7 @@ #include "FairSystemInfo.h" #include "SimulationDataFormat/MCCompLabel.h" #include "CPVBase/Geometry.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DetectorsCommonDataFormats/DetID.h" #endif @@ -72,7 +72,7 @@ void plot_hit_cpv(int ievent = 0, std::string inputprefix = "o2sim") if (!vMod[relId[0]][j]) { gROOT->cd(); vMod[relId[0]][j] = - new TH2D(Form("hMod%d_prim%d", relId[0], j), Form("hMod%d_prim%d", relId[0], j), 60, 0., 60., 128, 0., 128.); + new TH2D(Form("hMod%d_prim%d", relId[0], j), Form("hMod%d_prim%d", relId[0], j), 128, 0., 128., 60, 0., 60.); } vMod[relId[0]][j]->Fill(relId[1] - 0.5, relId[2] - 0.5, en); } diff --git a/Detectors/CPV/workflow/CMakeLists.txt b/Detectors/CPV/workflow/CMakeLists.txt index ec8736c8cc89b..39ac511dbd6eb 100644 --- a/Detectors/CPV/workflow/CMakeLists.txt +++ b/Detectors/CPV/workflow/CMakeLists.txt @@ -1,8 +1,9 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/ for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization @@ -10,13 +11,27 @@ o2_add_library(CPVWorkflow SOURCES src/RecoWorkflow.cxx - src/PublisherSpec.cxx + src/ReaderSpec.cxx + src/WriterSpec.cxx src/ClusterizerSpec.cxx src/DigitsPrinterSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsCPV - O2::DPLUtils O2::CPVBase O2::CPVCalib O2::CPVSimulation O2::CPVReconstruction O2::Algorithm) + src/RawToDigitConverterSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCPV + O2::DPLUtils + O2::CPVBase + O2::CPVSimulation + O2::CPVReconstruction + O2::Algorithm) o2_add_executable(reco-workflow COMPONENT_NAME cpv SOURCES src/cpv-reco-workflow.cxx PUBLIC_LINK_LIBRARIES O2::CPVWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME cpv + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::CPVWorkflow) diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/ClusterizerSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/ClusterizerSpec.h index 6c4f7acacc08e..d851fba14ef9b 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/ClusterizerSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/ClusterizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/DigitsPrinterSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/DigitsPrinterSpec.h index 18682bd7f0b4b..66d295a10aa60 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/DigitsPrinterSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/DigitsPrinterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..843692b5f6308 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to CPV digit/channels strean + +#ifndef O2_CPV_ENTROPYDECODER_SPEC +#define O2_CPV_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "CPVReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +namespace o2 +{ +namespace cpv +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::cpv::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..40ee233f72511 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert CPV data to CTF (EncodedBlocks) + +#ifndef O2_CPV_ENTROPYENCODER_SPEC +#define O2_CPV_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include <TStopwatch.h> +#include "CPVReconstruction/CTFCoder.h" + +namespace o2 +{ +namespace cpv +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::cpv::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace cpv +} // namespace o2 + +#endif diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h deleted file mode 100644 index 1c15a830ca78f..0000000000000 --- a/Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/DataProcessorSpec.h" -#include "Framework/OutputSpec.h" -#include <string> -#include <vector> - -namespace o2 -{ - -namespace cpv -{ - -using OutputSpec = framework::OutputSpec; - -struct PublisherConf { - struct BranchOptionConfig { - std::string option; - std::string defval; - std::string help; - }; - - std::string processName; - std::string defaultTreeName; - BranchOptionConfig databranch; - BranchOptionConfig datatrbranch; - BranchOptionConfig mcbranch; - OutputSpec dataoutput; - OutputSpec datatroutput; - OutputSpec mcoutput; -}; - -framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true); - -} // namespace cpv -} // end namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/RawToDigitConverterSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/RawToDigitConverterSpec.h new file mode 100644 index 0000000000000..6b86ee2231498 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/RawToDigitConverterSpec.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "DataFormatsCPV/CalibParams.h" +#include "DataFormatsCPV/BadChannelMap.h" +#include "DataFormatsCPV/Pedestals.h" +#include "CPVReconstruction/RawDecoder.h" +#include "CCDB/BasicCCDBManager.h" + +namespace o2 +{ + +namespace cpv +{ + +namespace reco_workflow +{ + +/// \class RawToDigitConverterSpec +/// \brief Coverter task for Raw data to CPV cells +/// \author Dmitri Peresunko NRC KI +/// \since Sept., 2020 +/// +class RawToDigitConverterSpec : public framework::Task +{ + public: + /// \brief Constructor + /// \param propagateMC If true the MCTruthContainer is propagated to the output + RawToDigitConverterSpec() : framework::Task(){}; + + /// \brief Destructor + ~RawToDigitConverterSpec() override = default; + + /// \brief Initializing the RawToDigitConverterSpec + /// \param ctx Init context + void init(framework::InitContext& ctx) final; + + /// \brief Run conversion of raw data to cells + /// \param ctx Processing context + /// + /// The following branches are linked: + /// Input RawData: {"ROUT", "RAWDATA", 0, Lifetime::Timeframe} + /// Output cells: {"CPV", "DIGITS", 0, Lifetime::Timeframe} + /// Output cells trigger record: {"CPV", "DIGITTRIGREC", 0, Lifetime::Timeframe} + /// Output HW errors: {"CPV", "RAWHWERRORS", 0, Lifetime::Timeframe} + void run(framework::ProcessingContext& ctx) final; + + protected: + /// \brief simple check of HW address + char CheckHWAddress(short ddl, short hwAddress, short& fee); + + private: + bool mIsPedestalData; ///< Do not subtract pedestals if true + bool mIsUsingCcdbMgr; ///< Are we using CCDB manager? + long mCurrentTimeStamp; ///< Current timestamp for CCDB querying + CalibParams* mCalibParams; ///< CPV calibration + Pedestals* mPedestals; ///< CPV pedestals + BadChannelMap* mBadMap; ///< BadMap + std::vector<Digit> mOutputDigits; ///< Container with output cells + std::vector<TriggerRecord> mOutputTriggerRecords; ///< Container with output cells + std::vector<RawDecoderError> mOutputHWErrors; ///< Errors occured in reading data +}; + +/// \brief Creating DataProcessorSpec for the CPV Digit Converter Spec +/// +/// Refer to RawToDigitConverterSpec::run for input and output specs +o2::framework::DataProcessorSpec getRawToDigitConverterSpec(bool askDISTSTF = true); + +} // namespace reco_workflow + +} // namespace cpv + +} // namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h new file mode 100644 index 0000000000000..eb78f15a84f06 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/OutputSpec.h" +#include <string> +#include <vector> + +namespace o2 +{ + +namespace cpv +{ + +using OutputSpec = framework::OutputSpec; + +framework::DataProcessorSpec getDigitsReaderSpec(bool propagateMC = true); +framework::DataProcessorSpec getClustersReaderSpec(bool propagateMC = true); + +} // namespace cpv +} // end namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h index a8fae7398f615..e9066d80d5fc7 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,11 +36,12 @@ enum struct OutputType { Digits, }; /// create the workflow for CPV reconstruction -framework::WorkflowSpec getWorkflow(bool propagateMC = true, - bool enableDigitsPrinter = false, - std::string const& cfgInput = "digits", // - std::string const& cfgOutput = "clusters" // -); +framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC = true, + bool askSTFDist = true, + std::string const& cfgInput = "digits", + std::string const& cfgOutput = "clusters"); } // namespace reco_workflow } // namespace cpv diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h new file mode 100644 index 0000000000000..e35755104f996 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.h + +#ifndef O2_CPV_WRITER +#define O2_CPV_WRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace cpv +{ + +/// create a processor spec +/// write CPV clusters to ROOT file +framework::DataProcessorSpec getClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getDigitWriterSpec(bool useMC); + +} // namespace cpv +} // namespace o2 + +#endif /* O2_CPV_WRITER */ \ No newline at end of file diff --git a/Detectors/CPV/workflow/src/ClusterizerSpec.cxx b/Detectors/CPV/workflow/src/ClusterizerSpec.cxx index 88d79e6bbeca9..49de053e9fb99 100644 --- a/Detectors/CPV/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/CPV/workflow/src/ClusterizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,41 +24,35 @@ void ClusterizerSpec::init(framework::InitContext& ctx) // Initialize clusterizer and link geometry mClusterizer.initialize(); + mClusterizer.propagateMC(mPropagateMC); } void ClusterizerSpec::run(framework::ProcessingContext& ctx) { - if (ctx.inputs().isValid("digits")) { - LOG(DEBUG) << "CPVClusterizer - run on digits called"; + LOG(INFO) << "Start run "; + LOG(DEBUG) << "CPVClusterizer - run on digits called"; + auto digits = ctx.inputs().get<std::vector<Digit>>("digits"); + // auto digitsTR = ctx.inputs().get<std::span<TriggerRecord>>("digitTriggerRecords"); //TODO:: Why span does not work??? + // auto digits = ctx.inputs().get<std::vector<o2::cpv::Digit>>("digits"); + auto digitsTR = ctx.inputs().get<std::vector<o2::cpv::TriggerRecord>>("digitTriggerRecords"); - auto dataref = ctx.inputs().get("digits"); - auto const* cpvheader = o2::framework::DataRefUtils::getHeader<o2::cpv::CPVBlockHeader*>(dataref); - if (!cpvheader->mHasPayload) { - LOG(DEBUG) << "[CPVClusterizer - run] No more digits" << std::endl; - ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); - return; - } + // printf("CluSpec: digits=%d, TR=%d \n",digits.size(),digitsTR.size()) ; - // auto digits = ctx.inputs().get<gsl::span<o2::cpv::Digit>>("digits"); - auto digits = ctx.inputs().get<std::vector<o2::cpv::Digit>>("digits"); - auto digitsTR = ctx.inputs().get<std::vector<o2::cpv::TriggerRecord>>("digitTriggerRecords"); - - LOG(DEBUG) << "[CPVClusterizer - run] Received " << digitsTR.size() << " TR, running clusterizer ..."; - auto truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("digitsmctr"); - mClusterizer.process(digits, digitsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + LOG(DEBUG) << "[CPVClusterizer - run] Received " << digitsTR.size() << " TR, running clusterizer ..."; + std::unique_ptr<const o2::dataformats::MCTruthContainer<MCCompLabel>> truthcont; + if (mPropagateMC) { + truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("digitsmctr"); } - LOG(DEBUG) << "[CPVClusterizer - run] Writing " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; + mClusterizer.process(digits, digitsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + ctx.outputs().snapshot(o2::framework::Output{"CPV", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusters); ctx.outputs().snapshot(o2::framework::Output{"CPV", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusterTrigRecs); if (mPropagateMC) { ctx.outputs().snapshot(o2::framework::Output{"CPV", "CLUSTERTRUEMC", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthCont); } - LOG(INFO) << "Finished "; - ctx.services().get<o2::framework::ControlService>().endOfStream(); - ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); + LOG(INFO) << "Finished, wrote " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; } - o2::framework::DataProcessorSpec o2::cpv::reco_workflow::getClusterizerSpec(bool propagateMC) { std::vector<o2::framework::InputSpec> inputs; diff --git a/Detectors/CPV/workflow/src/DigitsPrinterSpec.cxx b/Detectors/CPV/workflow/src/DigitsPrinterSpec.cxx index e88cf031320fe..2722ce9bba29b 100644 --- a/Detectors/CPV/workflow/src/DigitsPrinterSpec.cxx +++ b/Detectors/CPV/workflow/src/DigitsPrinterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..44a79ed94bb1f --- /dev/null +++ b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CPVWorkflow/EntropyDecoderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& triggers = pc.outputs().make<std::vector<TriggerRecord>>(OutputRef{"triggers"}); + auto& clusters = pc.outputs().make<std::vector<Cluster>>(OutputRef{"clusters"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::cpv::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, triggers, clusters); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << clusters.size() << " CPV clusters in " << triggers.size() << " triggers in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CPV Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"triggers"}, "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}, + OutputSpec{{"clusters"}, "CPV", "CLUSTERS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "cpv-entropy-decoder", + Inputs{InputSpec{"ctf", "CPV", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace cpv +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..4cf7b46e929d0 --- /dev/null +++ b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CPVWorkflow/EntropyEncoderSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto triggers = pc.inputs().get<gsl::span<TriggerRecord>>("triggers"); + auto clusters = pc.inputs().get<gsl::span<Cluster>>("clusters"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"CPV", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, triggers, clusters); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for CPV in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CPV Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("triggers", "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe); + inputs.emplace_back("clusters", "CPV", "CLUSTERS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "cpv-entropy-encoder", + inputs, + Outputs{{"CPV", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace cpv +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/PublisherSpec.cxx b/Detectors/CPV/workflow/src/PublisherSpec.cxx deleted file mode 100644 index ee17eed725064..0000000000000 --- a/Detectors/CPV/workflow/src/PublisherSpec.cxx +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFormatsCPV/CPVBlockHeader.h" -#include "CPVWorkflow/PublisherSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Headers/DataHeader.h" -#include "DPLUtils/RootTreeReader.h" -#include "Framework/DataSpecUtils.h" -#include <memory> -#include <utility> - -namespace o2 -{ - -namespace cpv -{ - -o2::framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC) -{ - struct ProcessAttributes { - std::shared_ptr<o2::framework::RootTreeReader> reader; - std::string datatype; - bool terminateOnEod; - bool finished; - }; - - auto initFunction = [config, propagateMC](o2::framework::InitContext& ic) { - // get the option from the init context - auto filename = ic.options().get<std::string>("infile"); - auto treename = ic.options().get<std::string>("treename"); - auto dtbrName = ic.options().get<std::string>(config.databranch.option.c_str()); // databranch name - auto dttrbrName = ic.options().get<std::string>(config.datatrbranch.option.c_str()); // datatrigrec name - auto mcbrName = ic.options().get<std::string>(config.mcbranch.option.c_str()); // mcbranch name - auto nofEvents = ic.options().get<int>("nevents"); - // auto publishingMode = nofEvents == -1 ? o2::framework::RootTreeReader::PublishingMode::Single : o2::framework::RootTreeReader::PublishingMode::Loop; - auto publishingMode = o2::framework::RootTreeReader::PublishingMode::Single; - - auto processAttributes = std::make_shared<ProcessAttributes>(); - { - processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); - processAttributes->finished = false; - processAttributes->datatype = config.databranch.defval; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - constexpr auto persistency = o2::framework::Lifetime::Timeframe; - o2::header::DataHeader::SubSpecificationType subSpec = 0; - if (propagateMC) { - processAttributes->reader = std::make_shared<o2::framework::RootTreeReader>(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str() // name of mc label branch - ); - } else { - processAttributes->reader = std::make_shared<o2::framework::RootTreeReader>(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str() // name of data tr branch - ); - } - } - - auto processFunction = [processAttributes, propagateMC](o2::framework::ProcessingContext& pc) { - if (processAttributes->finished) { - return; - } - - auto publish = [&processAttributes, &pc, propagateMC]() { - o2::cpv::CPVBlockHeader cpvheader(true); - if (processAttributes->reader->next()) { - (*processAttributes->reader)(pc, cpvheader); - } else { - processAttributes->reader.reset(); - return false; - } - return true; - }; - - bool active(true); - if (!publish()) { - active = false; - // Send dummy header with no payload option - o2::cpv::CPVBlockHeader dummyheader(false); - pc.outputs().snapshot(o2::framework::OutputRef{"output", 0, {dummyheader}}, 0); - pc.outputs().snapshot(o2::framework::OutputRef{"outputTR", 0, {dummyheader}}, 0); - if (propagateMC) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMC", 0, {dummyheader}}, 0); - } - } - if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { - pc.services().get<o2::framework::ControlService>().endOfStream(); - pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); - } - }; - - return processFunction; - }; - - auto createOutputSpecs = [&config, propagateMC]() { - std::vector<o2::framework::OutputSpec> outputSpecs; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"output"}, dto.origin, dto.description, 0, o2::framework::Lifetime::Timeframe}); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputTR"}, dttro.origin, dttro.description, 0, o2::framework::Lifetime::Timeframe}); - if (propagateMC) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMC"}, mco.origin, mco.description, 0, o2::framework::Lifetime::Timeframe}); - } - return std::move(outputSpecs); - }; - - auto& dtb = config.databranch; - auto& dttrb = config.datatrbranch; - auto& mcb = config.mcbranch; - return o2::framework::DataProcessorSpec{ - config.processName.c_str(), - o2::framework::Inputs{}, // no inputs - {createOutputSpecs()}, - o2::framework::AlgorithmSpec(initFunction), - o2::framework::Options{ - {"infile", o2::framework::VariantType::String, "", {"Name of the input file"}}, - {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, - {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, - {dttrb.option.c_str(), o2::framework::VariantType::String, dttrb.defval.c_str(), {dttrb.help.c_str()}}, - {mcb.option.c_str(), o2::framework::VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, - {"nevents", o2::framework::VariantType::Int, -1, {"number of events to run"}}, - {"terminate-on-eod", o2::framework::VariantType::Bool, true, {"terminate on end-of-data"}}, - }}; -} - -} // namespace cpv - -} // namespace o2 diff --git a/Detectors/CPV/workflow/src/RawToDigitConverterSpec.cxx b/Detectors/CPV/workflow/src/RawToDigitConverterSpec.cxx new file mode 100644 index 0000000000000..13c1133661d1e --- /dev/null +++ b/Detectors/CPV/workflow/src/RawToDigitConverterSpec.cxx @@ -0,0 +1,255 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCPV/CPVBlockHeader.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "DetectorsRaw/RDHUtils.h" +#include "CPVReconstruction/RawDecoder.h" +#include "CPVWorkflow/RawToDigitConverterSpec.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/BasicCCDBManager.h" +#include "CPVBase/Geometry.h" + +using namespace o2::cpv::reco_workflow; + +void RawToDigitConverterSpec::init(framework::InitContext& ctx) +{ + LOG(DEBUG) << "Initializing RawToDigitConverterSpec..."; + + //Read command-line options + //Pedestal flag true/false + mIsPedestalData = false; + if (ctx.options().isSet("pedestal")) { + mIsPedestalData = ctx.options().get<bool>("pedestal"); + } + LOG(INFO) << "Pedestal data: " << mIsPedestalData; + if (mIsPedestalData) { //no calibration for pedestal runs needed + return; //skip CCDB initialization for pedestal runs + } + + //CCDB Url + std::string ccdbUrl = "localtest"; + if (ctx.options().isSet("ccdb-url")) { + ccdbUrl = ctx.options().get<std::string>("ccdb-url"); + } + LOG(INFO) << "CCDB Url: " << ccdbUrl; + + //dummy calibration objects + if (ccdbUrl.compare("localtest") == 0) { // test default calibration + mIsUsingCcdbMgr = false; + mCalibParams = new o2::cpv::CalibParams(1); + mBadMap = new o2::cpv::BadChannelMap(1); + mPedestals = new o2::cpv::Pedestals(1); + LOG(INFO) << "No reading calibration from ccdb requested, using dummy calibration for testing"; + LOG(INFO) << "Task configuration is done."; + return; //localtest = no reading ccdb + } + + //init CCDB + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + ccdbMgr.setURL(ccdbUrl); + mIsUsingCcdbMgr = ccdbMgr.isHostReachable(); //if host is not reachable we can use only dummy calibration + if (!mIsUsingCcdbMgr) { + LOG(ERROR) << "Host " << ccdbUrl << " is not reachable!!!"; + LOG(ERROR) << "Using dummy calibration"; + mCalibParams = new o2::cpv::CalibParams(1); + mBadMap = new o2::cpv::BadChannelMap(1); + mPedestals = new o2::cpv::Pedestals(1); + + } else { + ccdbMgr.setCaching(true); //make local cache of remote objects + ccdbMgr.setLocalObjectValidityChecking(true); //query objects from remote site only when local one is not valid + LOG(INFO) << "Successfully initializated BasicCCDBManager with caching option"; + + //read calibration from ccdb (for now do it only at the beginning of dataprocessing) + //probably later we can check bad channel map more oftenly + mCurrentTimeStamp = o2::ccdb::getCurrentTimestamp(); + ccdbMgr.setTimestamp(mCurrentTimeStamp); + + mCalibParams = ccdbMgr.get<o2::cpv::CalibParams>("CPV/Calib/Gains"); + if (!mCalibParams) { + LOG(ERROR) << "Cannot get o2::cpv::CalibParams from CCDB. Using dummy calibration!"; + mCalibParams = new o2::cpv::CalibParams(1); + } + mBadMap = ccdbMgr.get<o2::cpv::BadChannelMap>("CPV/Calib/BadChannelMap"); + if (!mBadMap) { + LOG(ERROR) << "Cannot get o2::cpv::BadChannelMap from CCDB. Using dummy calibration!"; + mBadMap = new o2::cpv::BadChannelMap(1); + } + mPedestals = ccdbMgr.get<o2::cpv::Pedestals>("CPV/Calib/Pedestals"); + if (!mPedestals) { + LOG(ERROR) << "Cannot get o2::cpv::Pedestals from CCDB. Using dummy calibration!"; + mPedestals = new o2::cpv::Pedestals(1); + } + LOG(INFO) << "Task configuration is done."; + } +} + +void RawToDigitConverterSpec::run(framework::ProcessingContext& ctx) +{ + // Cache digits from bunch crossings as the component reads timeframes from many links consecutively + std::map<o2::InteractionRecord, std::shared_ptr<std::vector<o2::cpv::Digit>>> digitBuffer; // Internal digit buffer + int firstEntry = 0; + mOutputHWErrors.clear(); + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + std::vector<o2::framework::InputSpec> dummy{o2::framework::InputSpec{"dummy", o2::framework::ConcreteDataMatcher{"CPV", o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : framework::InputRecordWalker(ctx.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { // send empty output + LOG(INFO) << "Sending empty output due to data type input with 0xDEADBEEF"; + mOutputDigits.clear(); + ctx.outputs().snapshot(o2::framework::Output{"CPV", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mOutputDigits); + mOutputTriggerRecords.clear(); + ctx.outputs().snapshot(o2::framework::Output{"CPV", "DIGITTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputTriggerRecords); + mOutputHWErrors.clear(); + ctx.outputs().snapshot(o2::framework::Output{"CPV", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe}, mOutputHWErrors); + return; //empty TF, nothing to process + } + } + + std::vector<o2::framework::InputSpec> rawFilter{ + {"RAWDATA", o2::framework::ConcreteDataTypeMatcher{"CPV", "RAWDATA"}, o2::framework::Lifetime::Timeframe}, + }; + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs(), rawFilter)) { + o2::cpv::RawReaderMemory rawreader(o2::framework::DataRefUtils::as<const char>(rawData)); + // loop over all the DMA pages + while (rawreader.hasNext()) { + try { + rawreader.next(); + } catch (RawErrorType_t e) { + LOG(ERROR) << "Raw decoding error " << (int)e; + //add error list + //RawErrorType_t is defined in O2/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h + //RawDecoderError(short c, short d, short g, short p, RawErrorType_t e) + mOutputHWErrors.emplace_back(25, 0, 0, 0, e); //Put general errors to non-existing ccId 25 + //if problem in header, abandon this page + if (e == RawErrorType_t::kRDH_DECODING) { + break; + } + //if problem in payload, try to continue + continue; + } + auto& rdh = rawreader.getRawHeader(); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(rdh); + auto mod = o2::raw::RDHUtils::getLinkID(rdh) + 2; //link=0,1,2 -> mod=2,3,4 + //for now all modules are written to one LinkID + if (mod > o2::cpv::Geometry::kNMod || mod < 2) { //only 3 correct modules:2,3,4 + LOG(ERROR) << "module=" << mod << "do not exist"; + mOutputHWErrors.emplace_back(25, mod, 0, 0, kRDH_INVALID); //Add non-existing modules to non-existing ccId 25 and dilogic = mod + continue; //skip STU mod + } + o2::cpv::RawDecoder decoder(rawreader); + RawErrorType_t err = decoder.decode(); + + if (!(err == kOK || err == kOK_NO_PAYLOAD)) { + //TODO handle severe errors + //TODO: probably careful conversion of decoder errors to Fitter errors? + mOutputHWErrors.emplace_back(25, mod, 0, 0, err); //assign general RDH errors to non-existing ccId 25 and dilogic = mod + } + + std::shared_ptr<std::vector<o2::cpv::Digit>> currentDigitContainer; + auto digilets = decoder.getDigits(); + if (digilets.empty()) { //no digits -> continue to next pages + continue; + } + o2::InteractionRecord currentIR(0, triggerOrbit); //(bc, orbit) + // Loop over all the BCs + for (auto itBCRecords : decoder.getBCRecords()) { + currentIR.bc = itBCRecords.bc; + for (int iDig = itBCRecords.firstDigit; iDig <= itBCRecords.lastDigit; iDig++) { + auto adch = digilets[iDig]; + auto found = digitBuffer.find(currentIR); + if (found == digitBuffer.end()) { + currentDigitContainer = std::make_shared<std::vector<o2::cpv::Digit>>(); + digitBuffer[currentIR] = currentDigitContainer; + } else { + currentDigitContainer = found->second; + } + + AddressCharge ac = {adch}; + unsigned short absId = ac.Address; + //if we deal with non-pedestal data? + if (!mIsPedestalData) { //not a pedestal data + //test bad map + if (mBadMap->isChannelGood(absId)) { + //we need to subtract pedestal from amplidute and calibrate it + float amp = mCalibParams->getGain(absId) * (ac.Charge - mPedestals->getPedestal(absId)); + if (amp > 0) { + currentDigitContainer->emplace_back(absId, amp, -1); + } + } + } else { //pedestal data, no calibration needed. + currentDigitContainer->emplace_back(absId, (float)ac.Charge, -1); + } + } + } + //Check and send list of hwErrors + for (auto& er : decoder.getErrors()) { + mOutputHWErrors.push_back(er); + } + } //RawReader::hasNext + } + + // Loop over BCs, sort digits with increasing digit ID and write to output containers + mOutputDigits.clear(); + mOutputTriggerRecords.clear(); + for (auto [bc, digits] : digitBuffer) { + int prevDigitSize = mOutputDigits.size(); + if (digits->size()) { + // Sort digits according to digit ID + std::sort(digits->begin(), digits->end(), [](o2::cpv::Digit& lhs, o2::cpv::Digit& rhs) { return lhs.getAbsId() < rhs.getAbsId(); }); + + for (auto digit : *digits) { + mOutputDigits.push_back(digit); + } + } + + mOutputTriggerRecords.emplace_back(bc, prevDigitSize, mOutputDigits.size() - prevDigitSize); + } + digitBuffer.clear(); + + LOG(DEBUG) << "[CPVRawToDigitConverter - run] Writing " << mOutputDigits.size() << " digits ..."; + ctx.outputs().snapshot(o2::framework::Output{"CPV", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mOutputDigits); + ctx.outputs().snapshot(o2::framework::Output{"CPV", "DIGITTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputTriggerRecords); + ctx.outputs().snapshot(o2::framework::Output{"CPV", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe}, mOutputHWErrors); +} + +o2::framework::DataProcessorSpec o2::cpv::reco_workflow::getRawToDigitConverterSpec(bool askDISTSTF) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("RAWDATA", o2::framework::ConcreteDataTypeMatcher{"CPV", "RAWDATA"}, o2::framework::Lifetime::Optional); + //receive at least 1 guaranteed input (which will allow to acknowledge the TF) + if (askDISTSTF) { + inputs.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back("CPV", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("CPV", "DIGITTRIGREC", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("CPV", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe); + //note that for cpv we always have stream #0 (i.e. CPV/DIGITS/0) + + return o2::framework::DataProcessorSpec{"CPVRawToDigitConverterSpec", + inputs, // o2::framework::select("A:CPV/RAWDATA"), + outputs, + o2::framework::adaptFromTask<o2::cpv::reco_workflow::RawToDigitConverterSpec>(), + o2::framework::Options{ + {"pedestal", o2::framework::VariantType::Bool, false, {"do not subtract pedestals from digits"}}, + {"ccdb-url", o2::framework::VariantType::String, "http://ccdb-test.cern.ch:8080", {"CCDB Url"}}, + }}; +} diff --git a/Detectors/CPV/workflow/src/ReaderSpec.cxx b/Detectors/CPV/workflow/src/ReaderSpec.cxx new file mode 100644 index 0000000000000..d0fb6e19246f4 --- /dev/null +++ b/Detectors/CPV/workflow/src/ReaderSpec.cxx @@ -0,0 +1,236 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsCPV/CPVBlockHeader.h" +#include "CPVWorkflow/ReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/DataSpecUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <memory> +#include <utility> + +using namespace o2::framework; + +namespace o2 +{ + +namespace cpv +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +struct ProcessAttributes { + std::shared_ptr<RootTreeReader> reader; + std::string datatype; + bool terminateOnEod; + bool finished; +}; + +DataProcessorSpec getDigitsReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + auto treename = ic.options().get<std::string>("treename"); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "CPVDigit"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "DIGITS", subSpec, persistency}, + "CPVDigit", // name of data branch + Output{"CPV", "DIGITTRIGREC", subSpec, persistency}, + "CPVDigitTrigRecords", // name of data triggerrecords branch + Output{"CPV", "DIGITSMCTR", subSpec, persistency}, + "CPVDigitMCTruth"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "DIGITS", subSpec, persistency}, + "CPVDigit", // name of data branch + Output{"CPV", "DIGITTRIGREC", subSpec, persistency}, + "CPVDigitTrigRecords"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::cpv::CPVBlockHeader cpvheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, cpvheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::cpv::CPVBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "CPV", "DIGITS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "CPV", "DIGITTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "CPV", "DIGITSMCTR", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "cpv-digit-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "cpvdigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +DataProcessorSpec getClustersReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get<std::string>("infile"); + auto treename = ic.options().get<std::string>("treename"); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "CPVCluster"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "CLUSTERS", subSpec, persistency}, + "CPVCluster", // name of data branch + Output{"CPV", "CLUSTERTRIGRECS", subSpec, persistency}, + "CPVClusterTrigRec", // name of data triggerrecords branch + Output{"CPV", "CLUSTERTRUEMC", subSpec, persistency}, + "CPVClusterTrueMC"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "CLUSTERS", subSpec, persistency}, + "CPVCluster", // name of data branch + Output{"CPV", "CLUSTERTRIGRECS", subSpec, persistency}, + "CPVClusterTrueMC"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::cpv::CPVBlockHeader cpvheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, cpvheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::cpv::CPVBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "CPV", "CLUSTERS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "CPV", "CLUSTERTRUEMC", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "cpv-cluster-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "cpvclusters.root", {"Name of the input file"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +} // namespace cpv + +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/RecoWorkflow.cxx b/Detectors/CPV/workflow/src/RecoWorkflow.cxx index 82bc452753350..bb8f678c037df 100644 --- a/Detectors/CPV/workflow/src/RecoWorkflow.cxx +++ b/Detectors/CPV/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,8 +25,9 @@ #include "DataFormatsCPV/TriggerRecord.h" #include "CPVWorkflow/RecoWorkflow.h" #include "CPVWorkflow/ClusterizerSpec.h" -#include "CPVWorkflow/DigitsPrinterSpec.h" -#include "CPVWorkflow/PublisherSpec.h" +#include "CPVWorkflow/ReaderSpec.h" +#include "CPVWorkflow/WriterSpec.h" +#include "CPVWorkflow/RawToDigitConverterSpec.h" //#include "CPVWorkflow/RawWriterSpec.h" #include "Framework/DataSpecUtils.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -45,17 +47,18 @@ namespace reco_workflow { const std::unordered_map<std::string, InputType> InputMap{ + {"raw", InputType::Raw}, {"hits", InputType::Hits}, - {"digits", InputType::Digits}, - {"raw", InputType::Raw}}; + {"digits", InputType::Digits}}; const std::unordered_map<std::string, OutputType> OutputMap{ {"digits", OutputType::Digits}, - {"raw", OutputType::Raw}, {"clusters", OutputType::Clusters}}; -o2::framework::WorkflowSpec getWorkflow(bool propagateMC, - bool enableDigitsPrinter, +o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC, + bool askSTFDist, std::string const& cfgInput, std::string const& cfgOutput) { @@ -78,135 +81,39 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, o2::framework::WorkflowSpec specs; - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::cpv::reco_workflow::getRawWriterSpec()); - // } + // //Raw to .... + if (inputType == InputType::Raw) { + //no explicit raw reader - if (inputType == InputType::Digits) { - specs.emplace_back(o2::cpv::getPublisherSpec(PublisherConf{ - "cpv-digit-reader", - "o2sim", - {"digitbranch", "CPVDigit", "Digit branch"}, - {"digittrigger", "CPVDigitTrigRecords", "TrigRecords branch"}, - {"mcbranch", "CPVDigitMCTruth", "MC label branch"}, - o2::framework::OutputSpec{"CPV", "DIGITS"}, - o2::framework::OutputSpec{"CPV", "DIGITTRIGREC"}, - o2::framework::OutputSpec{"CPV", "DIGITSMCTR"}}, - propagateMC)); - - if (enableDigitsPrinter) { - specs.emplace_back(o2::cpv::reco_workflow::getPhosDigitsPrinterSpec()); + if (isEnabled(OutputType::Digits)) { + specs.emplace_back(o2::cpv::reco_workflow::getRawToDigitConverterSpec(askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getDigitWriterSpec(false)); + } } - if (isEnabled(OutputType::Clusters)) { // add clusterizer - specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(propagateMC)); + specs.emplace_back(o2::cpv::reco_workflow::getRawToDigitConverterSpec(askSTFDist)); + specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(false)); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getClusterWriterSpec(false)); + } } - - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::cpv::reco_workflow::getRawWriterSpec()); - // } } - // check if the process is ready to quit - // this is decided upon the meta information in the CPV block header, the operation is set - // value kNoPayload in case of no data or no operation - // see also PublisherSpec.cxx - // in this workflow, the EOD is sent after the last real data, and all inputs will receive EOD, - // so it is enough to check on the first occurence - // FIXME: this will be changed once DPL can propagate control events like EOD - auto checkReady = [](o2::framework::DataRef const& ref) { - auto const* cpvheader = o2::framework::DataRefUtils::getHeader<o2::cpv::CPVBlockHeader*>(ref); - // sector number -1 indicates end-of-data - if (cpvheader != nullptr) { - // indicate normal processing if not ready and skip if ready - if (!cpvheader->mHasPayload) { - return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::SkipProcessing, true); - } + // Digits to .... + if (inputType == InputType::Digits) { + if (!disableRootInp) { + specs.emplace_back(o2::cpv::getDigitsReaderSpec(propagateMC)); } - return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::DoProcessing, false); - }; - - // auto makeWriterSpec = [propagateMC, checkReady](const char* processName, - // const char* defaultFileName, - // const char* defaultTreeName, - // bool createMCMap, - // auto&& databranch, - // auto&& datatrbranch, - // auto&& mcbranch=nullptr, - // auto&& mcmapbranch=nullptr) { - // // depending on the MC propagation flag, the RootTreeWriter spec is created with two - // // or one branch definition - // if (propagateMC) { - // if(createMCMap){ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch), - // std::move(mcbranch), - // std::move(mcmapbranch))); - // } - // else{ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch), - // std::move(mcbranch))); - // } - // } - // else{ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch))); - // } - // }; - - // if (isEnabled(OutputType::Raw)) { - // using RawOutputType = std::vector<o2::cpv::Raw>; - // specs.push_back(makeWriterSpec("cpv-raw-writer", - // inputType == InputType::Digits ? "cpv-raw.root" : "cpvrawcells.root", - // "o2sim", - // BranchDefinition<DigitOutputType>{o2::framework::InputSpec{"data", "CPV", "RAW", 0}, - // "CPVRaw", - // "raw-branch-name"}, - // BranchDefinition<MCLabelContainer>{o2::framework::InputSpec{"mc", "CPV", "RAWMCTR", 0}, - // "CPVRawMCTruth", - // "rawmc-branch-name"})()); - // } - - if (isEnabled(OutputType::Digits)) { - using DigitOutputType = std::vector<o2::cpv::Digit>; - using DTROutputType = std::vector<o2::cpv::TriggerRecord>; - - specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("cpv-digits-writer", "cpvdigits.root", "o2sim", - -1, - o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - BranchDefinition<DigitOutputType>{o2::framework::InputSpec{"data", "CPV", "DIGITS", 0}, - "CPVDigit", - "digit-branch-name"}, - BranchDefinition<DTROutputType>{o2::framework::InputSpec{"data", "CPV", "DIGITTRIGREC", 0}, - "CPVDigTR", - "digittr-branch-name"}, - BranchDefinition<MCLabelContainer>{o2::framework::InputSpec{"mc", "CPV", "DIGITSMCTR", 0}, - "CPVDigitMCTruth", - "digitmc-branch-name"})()); - } - if (isEnabled(OutputType::Clusters)) { - specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("cpv-clusters-writer", "cpvclusters.root", "o2sim", -1, - o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - BranchDefinition<std::vector<o2::cpv::Cluster>>{o2::framework::InputSpec{"data", "CPV", "CLUSTERS", 0}, - "CPVCluster", - "cluster-branch-name"}, - BranchDefinition<std::vector<o2::cpv::TriggerRecord>>{o2::framework::InputSpec{"datatr", "CPV", "CLUSTERTRIGRECS", 0}, - "CPVClusTR", - "clustertr-branch-name"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{o2::framework::InputSpec{"mc", "CPV", "CLUSTERTRUEMC", 0}, - "CPVClusMC", - "clustermc-branch-name"})()); + if (isEnabled(OutputType::Clusters)) { + // add clusterizer + specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(propagateMC)); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getClusterWriterSpec(propagateMC)); + } + } } return std::move(specs); diff --git a/Detectors/CPV/workflow/src/WriterSpec.cxx b/Detectors/CPV/workflow/src/WriterSpec.cxx new file mode 100644 index 0000000000000..06f00624153fc --- /dev/null +++ b/Detectors/CPV/workflow/src/WriterSpec.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.cxx + +#include <vector> + +#include "CPVWorkflow/WriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsCPV/Cluster.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using ClusType = std::vector<o2::cpv::Cluster>; +using DigitType = std::vector<o2::cpv::Digit>; +using TriggerRecordType = std::vector<o2::cpv::TriggerRecord>; +using MCLabelType = o2::dataformats::MCTruthContainer<MCCompLabel>; +using namespace o2::header; + +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto ClustersSize = std::make_shared<int>(0); + auto ClustersSizeGetter = [ClustersSize](ClusType const& Clusters) { + *ClustersSize = Clusters.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("cpv-cluster-writer", + "cpvclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV clusters"}, + BranchDefinition<ClusType>{InputSpec{"clus", "CPV", "CLUSTERS", 0}, + "CPVCluster", ClustersSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"clusRecs", "CPV", "CLUSTERTRIGRECS", 0}, + "CPVClusterTrigRec"}, + BranchDefinition<MCLabelType>{InputSpec{"clusMC", "CPV", "CLUSTERTRUEMC", 0}, + "CPVClusterTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("cpv-cluster-writer", + "cpvclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV clusters"}, + BranchDefinition<ClusType>{InputSpec{"clus", "CPV", "CLUSTERS", 0}, + "CPVCluster", ClustersSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"clusRecs", "CPV", "CLUSTERTRIGRECS", 0}, + "CPVClusterTrigRec"})(); + } +} + +DataProcessorSpec getDigitWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto DigitsSize = std::make_shared<int>(0); + auto DigitsSizeGetter = [DigitsSize](DigitType const& Digits) { + *DigitsSize = Digits.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("cpv-digit-writer", + "cpvdigits.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV digits"}, + BranchDefinition<DigitType>{InputSpec{"CPVDigit", "CPV", "DIGITS", 0}, + "CPVDigit", DigitsSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"CPVDigitTrigRecords", "CPV", "DIGITTRIGREC", 0}, + "CPVDigitTrigRecords"}, + BranchDefinition<MCLabelType>{InputSpec{"clusMC", "CPV", "DIGITSMCTR", 0}, + "CPVDigitMCTruth"})(); + } else { + return MakeRootTreeWriterSpec("cpv-digit-writer", + "cpvdigits.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV digits"}, + BranchDefinition<DigitType>{InputSpec{"CPVDigit", "CPV", "DIGITS", 0}, + "CPVDigit", DigitsSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"CPVDigitTrigRecords", "CPV", "DIGITTRIGREC", 0}, + "CPVDigitTrigRecords"})(); + } +} + +} // namespace cpv +} // namespace o2 \ No newline at end of file diff --git a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx index 350a45b48981a..e0fc904791138 100644 --- a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx +++ b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include "Framework/ConfigParamSpec.h" #include "CPVWorkflow/RecoWorkflow.h" #include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include <string> #include <stdexcept> @@ -27,11 +30,16 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { std::vector<o2::framework::ConfigParamSpec> options{ - {"input-type", o2::framework::VariantType::String, "hits", {"hits, digits, raw, clusters"}}, - {"output-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters, cells"}}, - {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, + {"input-type", o2::framework::VariantType::String, "digits", {"hits, digits, raw, clusters"}}, + {"output-type", o2::framework::VariantType::String, "clusters", {"digits, clusters"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, - }; + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -52,9 +60,18 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // - return o2::cpv::reco_workflow::getWorkflow(not cfgc.options().get<bool>("disable-mc"), // - cfgc.options().get<bool>("enable-digits-printer"), // - cfgc.options().get<std::string>("input-type"), // - cfgc.options().get<std::string>("output-type") // - ); + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + auto wf = o2::cpv::reco_workflow::getWorkflow(cfgc.options().get<bool>("disable-root-input"), + cfgc.options().get<bool>("disable-root-output"), + !cfgc.options().get<bool>("disable-mc"), + !cfgc.options().get<bool>("ignore-dist-stf"), + cfgc.options().get<std::string>("input-type"), + cfgc.options().get<std::string>("output-type")); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); + + return std::move(wf); } diff --git a/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..9c79fe431e27f --- /dev/null +++ b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CPVWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::cpv::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/CTF/CMakeLists.txt b/Detectors/CTF/CMakeLists.txt index 0fd407b3f2099..2c459698ac350 100644 --- a/Detectors/CTF/CMakeLists.txt +++ b/Detectors/CTF/CMakeLists.txt @@ -1,57 +1,53 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + add_subdirectory(workflow) o2_add_test(itsmft - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::ITSMFTReconstruction - O2::DataFormatsITSMFT + PUBLIC_LINK_LIBRARIES O2::ITSMFTReconstruction + O2::DataFormatsITSMFT SOURCES test/test_ctf_io_itsmft.cxx COMPONENT_NAME ctf LABELS ctf) o2_add_test(tpc - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::TPCReconstruction - O2::DataFormatsTPC + PUBLIC_LINK_LIBRARIES O2::TPCReconstruction + O2::DataFormatsTPC SOURCES test/test_ctf_io_tpc.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(ft0 - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::FT0Reconstruction - O2::DataFormatsFT0 + PUBLIC_LINK_LIBRARIES O2::FT0Reconstruction + O2::DataFormatsFT0 SOURCES test/test_ctf_io_ft0.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(fv0 - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::FV0Reconstruction - O2::DataFormatsFV0 + PUBLIC_LINK_LIBRARIES O2::FV0Reconstruction + O2::DataFormatsFV0 SOURCES test/test_ctf_io_fv0.cxx COMPONENT_NAME ctf LABELS ctf) - + o2_add_test(fdd - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::FDDReconstruction - O2::DataFormatsFDD + PUBLIC_LINK_LIBRARIES O2::FDDReconstruction + O2::DataFormatsFDD SOURCES test/test_ctf_io_fdd.cxx COMPONENT_NAME ctf LABELS ctf) o2_add_test(tof - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::TOFBase + PUBLIC_LINK_LIBRARIES O2::TOFBase O2::TOFReconstruction O2::DataFormatsTOF SOURCES test/test_ctf_io_tof.cxx @@ -59,17 +55,66 @@ o2_add_test(tof LABELS ctf) o2_add_test(mid - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::DataFormatsMID + PUBLIC_LINK_LIBRARIES O2::DataFormatsMID O2::MIDCTF SOURCES test/test_ctf_io_mid.cxx COMPONENT_NAME ctf - LABELS ctf) - + LABELS ctf;muon;mid) + +o2_add_test(mch + PUBLIC_LINK_LIBRARIES O2::MCHCTF + SOURCES test/test_ctf_io_mch.cxx + COMPONENT_NAME ctf + LABELS ctf;muon;mch) + o2_add_test(emcal - PUBLIC_LINK_LIBRARIES O2::CTFWorkflow - O2::DataFormatsEMCAL + PUBLIC_LINK_LIBRARIES O2::DataFormatsEMCAL O2::EMCALReconstruction SOURCES test/test_ctf_io_emcal.cxx COMPONENT_NAME ctf LABELS ctf) + +o2_add_test(phos + PUBLIC_LINK_LIBRARIES O2::DataFormatsPHOS + O2::PHOSReconstruction + SOURCES test/test_ctf_io_phos.cxx + COMPONENT_NAME ctf + LABELS ctf) + +o2_add_test(cpv + PUBLIC_LINK_LIBRARIES O2::DataFormatsCPV + O2::CPVReconstruction + SOURCES test/test_ctf_io_cpv.cxx + COMPONENT_NAME ctf + LABELS ctf) + +o2_add_test(zdc + PUBLIC_LINK_LIBRARIES O2::DataFormatsZDC + O2::ZDCReconstruction + SOURCES test/test_ctf_io_zdc.cxx + COMPONENT_NAME ctf + LABELS ctf) + +o2_add_test(trd + PUBLIC_LINK_LIBRARIES O2::CTFWorkflow + O2::DataFormatsTRD + O2::TRDReconstruction + SOURCES test/test_ctf_io_trd.cxx + COMPONENT_NAME ctf + LABELS ctf) + +o2_add_test(hmpid + PUBLIC_LINK_LIBRARIES O2::CTFWorkflow + O2::DataFormatsHMP + O2::HMPIDReconstruction + SOURCES test/test_ctf_io_hmpid.cxx + COMPONENT_NAME ctf + LABELS ctf) + +o2_add_test(ctp + PUBLIC_LINK_LIBRARIES O2::CTPWorkflow + O2::DataFormatsCTP + O2::CTPReconstruction + SOURCES test/test_ctf_io_ctp.cxx + COMPONENT_NAME ctf + LABELS ctf) diff --git a/Detectors/CTF/README.md b/Detectors/CTF/README.md index f064019f33f45..af5e6e9a0e85e 100644 --- a/Detectors/CTF/README.md +++ b/Detectors/CTF/README.md @@ -16,18 +16,114 @@ Example of usage: o2-its-reco-workflow --entropy-encoding | o2-ctf-writer-workflow --onlyDet ITS ``` +For the storage optimization reason one can request multiple CTFs stored in the same output file (as entries of the `ctf` tree): +```bash +o2-ctf-writer --min-file-size <min> --max-file-size <max> ... +``` +will accumulate CTFs in entries of the same tree/file until its size fits exceeds `min` and does not exceed `max` (`max` check is disabled if `max<=min`) or EOS received. +The `--max-file-size` limit will be ignored if the very first CTF already exceeds it. +Additional option `--max-ctf-per-file <N>` will forbid writing more than `N` CTFs to single file (provided `N>0`) even if the `min-file-size` is not reached. User may request autosaving of CTFs accumulated in the file after every `N` TFs processed by passing an option `--save-ctf-after <N>`. + +The output directory (by default: `cwd`) for CTFs can be set via `--output-dir` option and must exist. Since in on the EPNs we may store the CTFs on the RAM disk of limited capacity, one can indicate the fall-back storage via `--output-dir-alt` option. The writer will switch to it if +(i) `szCheck = max(min-file-size*1.1, max-file-size)` is positive and (ii) estimated (accounting for eventual other CTFs files written concurrently) available space on the primary storage is below the `szCheck`. The available space is estimated as: +```` +current physically available space +- +number still open CTF files from concurrent writers * szCheck ++ +the current size of these files +```` + +If the option `--meta-output-dir <dir>` is not `/dev/null`, the CTF `meta-info` files will be written to this directory (which must exist!). + +By default only CTFs will written. If the upstream entropy compression is performed w/o external dictionaries, then the for every CTF its own dictionary will be generated and stored in the CTF. In this mode one can request creation of dictionary file (or dictionary file per detector if option `--dict-per-det` is provided) by passing option `--output-type dict` (in which case only the dictionares will be stored but not the CTFs) or +`--output-type both` (will store both dictionaries and CTF). This is the only valid mode for dictionaries creation (if one requests dictionary creation but the compression was done with external dictionaries, the newly created dictionaries will be empty). +In the dictionaries creation mode their data are accumulated over all CTFs procssed. User may request periodic (and incremental) saving of dictionaries after every `N` TFs processed by passing `--save-dict-after <N>` option. + +Option `--ctf-dict-dir <dir>` can be provided to indicate the (existing) directory where the dictionary will be stored. + ## CTF reader workflow `o2-ctf-reader-workflow` should be the 1st workflow in the piped chain of CTF processing. -At the moment accepts as an input a single file produced by the `o2-ctf-writer-workflow`, reads data for all detectors present in it -(the list can be narrowd by `--onlyDet arg (=none)` and `--skipDet arg (=none)` comma-separated lists), decode them using decoder provided -by detector and injects to DPL. +At the moment accepts as an input a comma-separated list of CTF files produced by the `o2-ctf-writer-workflow`, reads data for all detectors present in it +(the list can be narrowed by `--onlyDet arg (=none)` and `--skipDet arg (=none)` comma-separated lists), decode them using decoder provided +by detector and injects to DPL. In case of multiple entries in the CTF tree, they all will be read in row. Example of usage: ```bash o2-ctf-reader-workflow --onlyDet ITS --ctf-input o2_ctf_0000000000.root | o2-its-reco-workflow --trackerCA --clusters-from-upstream --disable-mc ``` +The option are: +``` +--ctf-input arg (=none) +``` +inptu data (obligatort): comma-separated list of CTF files and/or files with list of data files and/or directories containing files + +``` +--onlyDet arg (=all) +``` +comma-separated list of detectors to read, Overrides skipDet + +``` +--skipDet arg (=none) +``` +comma-separated list of detectors to skip + +``` +--max-tf arg (=-1) +``` +max CTFs to process (<= 0 : infinite) + +``` +--loop arg (=0) +``` +loop N times after the 1st pass over the data (infinite for N<0) + +``` +--delay arg (=0) +``` +delay in seconds between consecutive CTFs sending (depends also on file fetching speed) + +``` +--copy-cmd arg (=XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst) +``` +copy command for remote files or `no-copy` to avoid copying + +``` +--ctf-file-regex arg (=.+o2_ctf_run.+\.root$) +``` +regex string to identify CTF files: optional to filter data files (if the input contains directories, it will be used to avoid picking non-CTF files) + +``` +--remote-regex arg (=^/eos/aliceo2/.+) +``` +regex string to identify remote files + +``` +--max-cached-files arg (=3) +``` +max CTF files queued (copied for remote source). + +There is a possibility to read remote root files directly, w/o caching them locally. For that one should: +1) provide the full URL the remote files, e.g. if the files are supposed to be accessed by `xrootd` (the `XrdSecPROTOCOL` and `XrdSecSSSKT` env. variables should be set up in advance), use +`root://eosaliceo2.cern.ch//eos/aliceo2/ls2data/...root` (use `xrdfs root://eosaliceo2.cern.ch ls -u <path>` to list full URL). +2) provide proper regex to define remote files, e.g. for the example above: `--remote-regex "^root://.+/eos/aliceo2/.+"`. +3) pass an option `--copy-cmd no-copy`. + +For the ITS and MFT entropy decoding one can request either to decompose clusters to digits and send them instead of clusters (via `o2-ctf-reader-workflow` global options `--its-digits` and `--mft-digits` respectively) +or to apply the noise mask to decoded clusters (or decoded digits). If the masking (e.g. via option `--its-entropy-decoder " --mask-noise "`) is requested, user should provide to the entropy decoder the noise mask file (eventually will be loaded from CCDB) and cluster patterns decoding dictionary (if the clusters were encoded with patterns IDs). +For example, +``` +o2-ctf-reader-workflow --ctf-input <ctfFiles> --onlyDet ITS,MFT --its-entropy-decoder ' --mask-noise --noise-file its_noise.root --cluster-dict-file ./ ' | ... +``` +will decode ITS and MFT data, decompose on the fly ITS clusters to digits, mask the noisy pixels with the provided masks, recluster remaining ITS digits and send the new clusters out, together with unchanged MFT clusters. +``` +o2-ctf-reader-workflow --ctf-input <ctfFiles> --onlyDet ITS,MFT --mft-digits --mft-entropy-decoder ' --mask-noise --noise-file mft_noise.root --cluster-dict-file ./ ' | ... +``` +will send decompose clusters to digits and send ben out after masking the noise for the MFT, while ITS clusters will be sent as decoded. + + ## Support for externally provided encoding dictionaries By default encoding with generate for every TF and store in the CTF the dictionary information necessary to decode the CTF. diff --git a/Detectors/CTF/test/test_ctf_io_cpv.cxx b/Detectors/CTF/test/test_ctf_io_cpv.cxx new file mode 100644 index 0000000000000..f96ce1c73cee7 --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_cpv.cxx @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test CPVCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CPVReconstruction/CTFCoder.h" +#include "DataFormatsCPV/CTF.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::cpv; + +BOOST_AUTO_TEST_CASE(CTFTest) +{ + std::vector<TriggerRecord> triggers; + std::vector<Cluster> clusters; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir(0, 0); + Cluster clu; + for (int irof = 0; irof < 1000; irof++) { + ir += 1 + gRandom->Integer(200); + + auto start = clusters.size(); + int n = 1 + gRandom->Poisson(100); + for (int i = n; i--;) { + char mult = gRandom->Integer(30); + char mod = 1 + gRandom->Integer(3); + char exMax = gRandom->Integer(3); + float x = 72.3 * 2. * (gRandom->Rndm() - 0.5); + float z = 63.3 * 2. * (gRandom->Rndm() - 0.5); + float e = 254. * gRandom->Rndm(); + clusters.emplace_back(mult, mod, exMax, x, z, e); + } + triggers.emplace_back(ir, start, clusters.size() - start); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, triggers, clusters); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::cpv::CTF::get(vec.data()); + TFile flOut("test_ctf_cpv.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "CPV"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + LOG(INFO) << "Start reading from tree "; + { + sw.Start(); + TFile flIn("test_ctf_cpv.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::cpv::CTF::readFromTree(vec, *(tree.get()), "CPV"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<TriggerRecord> triggersD; + std::vector<Cluster> clustersD; + + sw.Start(); + const auto ctfImage = o2::cpv::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, triggersD, clustersD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + BOOST_CHECK(triggersD.size() == triggers.size()); + BOOST_CHECK(clustersD.size() == clusters.size()); + LOG(INFO) << " BOOST_CHECK triggersD.size() " << triggersD.size() << " triggers.size() " << triggers.size() + << " BOOST_CHECK(clustersD.size() " << clustersD.size() << " clusters.size()) " << clusters.size(); + + for (size_t i = 0; i < triggers.size(); i++) { + const auto& dor = triggers[i]; + const auto& ddc = triggersD[i]; + LOG(DEBUG) << " Orig.TriggerRecord " << i << " " << dor.getBCData() << " " << dor.getFirstEntry() << " " << dor.getNumberOfObjects(); + LOG(DEBUG) << " Deco.TriggerRecord " << i << " " << ddc.getBCData() << " " << ddc.getFirstEntry() << " " << ddc.getNumberOfObjects(); + + BOOST_CHECK(dor.getBCData() == ddc.getBCData()); + BOOST_CHECK(dor.getNumberOfObjects() == ddc.getNumberOfObjects()); + BOOST_CHECK(dor.getFirstEntry() == dor.getFirstEntry()); + } + + for (size_t i = 0; i < clusters.size(); i++) { + const auto& cor = clusters[i]; + const auto& cdc = clustersD[i]; + BOOST_CHECK(cor.getMultiplicity() == cdc.getMultiplicity()); + BOOST_CHECK(cor.getModule() == cdc.getModule()); + BOOST_CHECK(TMath::Abs(cor.getEnergy() - cdc.getEnergy()) < 1.); + float xCor, zCor, xCdc, zCdc; + cor.getLocalPosition(xCor, zCor); + cdc.getLocalPosition(xCdc, zCdc); + BOOST_CHECK(TMath::Abs(xCor - xCdc) < 0.004); + BOOST_CHECK(TMath::Abs(zCor - zCdc) < 0.004); + } +} diff --git a/Detectors/CTF/test/test_ctf_io_ctp.cxx b/Detectors/CTF/test/test_ctf_io_ctp.cxx new file mode 100644 index 0000000000000..3a8a7adc90745 --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_ctp.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test CTPCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CTPReconstruction/CTFCoder.h" +#include "DataFormatsCTP/CTF.h" +#include "DataFormatsCTP/Digits.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> +#include <random> + +using namespace o2::ctp; + +BOOST_AUTO_TEST_CASE(CTFTest, *boost::unit_test::enabled()) +{ + std::vector<CTPDigit> digits; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir0(3, 5), ir(ir0); + + std::random_device rd; + std::mt19937_64 eng(rd()); + std::uniform_int_distribution<unsigned long long> distr; + + for (int itrg = 0; itrg < 1000; itrg++) { + ir += 1 + distr(eng) % 200; + auto& dig = digits.emplace_back(); + dig.intRecord = ir; + dig.CTPInputMask |= distr(eng); + dig.CTPClassMask |= distr(eng); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, digits); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::ctp::CTF::get(vec.data()); + TFile flOut("test_ctf_ctp.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "CTP"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + { + sw.Start(); + TFile flIn("test_ctf_ctp.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::ctp::CTF::readFromTree(vec, *(tree.get()), "CTP"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<CTPDigit> digitsD; + + sw.Start(); + const auto ctfImage = o2::ctp::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, digitsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + LOG(INFO) << " BOOST_CHECK(digitsD.size() " << digitsD.size() << " digigits.size()) " << digits.size(); + + BOOST_TEST(digits == digitsD, boost::test_tools::per_element()); +} diff --git a/Detectors/CTF/test/test_ctf_io_emcal.cxx b/Detectors/CTF/test/test_ctf_io_emcal.cxx index 205efd84f7d49..e8de8e49c4bd0 100644 --- a/Detectors/CTF/test/test_ctf_io_emcal.cxx +++ b/Detectors/CTF/test/test_ctf_io_emcal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) { std::vector<TriggerRecord> triggers; std::vector<Cell> cells; - // gSystem->Load("libO2DetectorsCommonDataFormats.so"); + // gSystem->Load("libO2DetectorsCommonDataFormats"); TStopwatch sw; sw.Start(); o2::InteractionRecord ir(0, 0); diff --git a/Detectors/CTF/test/test_ctf_io_fdd.cxx b/Detectors/CTF/test/test_ctf_io_fdd.cxx index 96b8543e59e6b..c9d181c52294e 100644 --- a/Detectors/CTF/test/test_ctf_io_fdd.cxx +++ b/Detectors/CTF/test/test_ctf_io_fdd.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/CTF/test/test_ctf_io_ft0.cxx b/Detectors/CTF/test/test_ctf_io_ft0.cxx index 6570f7a02363e..54d10e1fd75ef 100644 --- a/Detectors/CTF/test/test_ctf_io_ft0.cxx +++ b/Detectors/CTF/test/test_ctf_io_ft0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include <boost/test/unit_test.hpp> #include "DetectorsCommonDataFormats/NameConf.h" #include "FT0Reconstruction/CTFCoder.h" +#include "FT0Simulation/DigitizationParameters.h" #include "Framework/Logger.h" #include <TFile.h> #include <TRandom.h> @@ -26,12 +28,11 @@ BOOST_AUTO_TEST_CASE(CTFTest) { std::vector<Digit> digits; std::vector<ChannelData> channels; - TStopwatch sw; sw.Start(); o2::InteractionRecord ir(0, 0); - int mTime_trg_gate = 192; // #channels + int trg_gate = DigitizationParameters::Instance().mTime_trg_gate; constexpr int MAXChan = 4 * (Geometry::NCellsA + Geometry::NCellsC); for (int idig = 0; idig < 1000; idig++) { ir += 1 + gRandom->Integer(200); @@ -39,6 +40,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) auto start = channels.size(); int32_t tMeanA = 0, tMeanC = 0; int32_t ampTotA = 0, ampTotC = 0; + uint8_t eventFlag = 10; Triggers trig; trig.triggersignals = gRandom->Integer(128); while (ich < MAXChan) { @@ -46,7 +48,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) uint16_t q = gRandom->Integer(4096); uint8_t chain = gRandom->Rndm() > 0.5 ? 0 : 1; channels.emplace_back(ich, t, q, chain); - if (std::abs(t) < Geometry::mTime_trg_gate) { + if (std::abs(t) < trg_gate) { if (ich < 4 * uint8_t(Geometry::NCellsA)) { trig.nChanA++; ampTotA += q; @@ -69,6 +71,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) } auto end = channels.size(); digits.emplace_back(start, end - start, ir, trig, idig); + digits[idig].setEventStatus(eventFlag); } LOG(INFO) << "Generated " << channels.size() << " channels in " << digits.size() << " digits " << sw.CpuTime() << " s"; @@ -121,13 +124,13 @@ BOOST_AUTO_TEST_CASE(CTFTest) BOOST_CHECK(digitsD.size() == digits.size()); BOOST_CHECK(channelsD.size() == channels.size()); - LOG(INFO) << " BOOST_CHECK digitsD.size() " << digitsD.size() << " digits.size() " << digits.size() << " BOOST_CHECK(channelsD.size() " << channelsD.size() << " channels.size()) " << channels.size(); + LOG(DEBUG) << " BOOST_CHECK digitsD.size() " << digitsD.size() << " digits.size() " << digits.size() << " BOOST_CHECK(channelsD.size() " << channelsD.size() << " channels.size()) " << channels.size(); for (int i = digits.size(); i--;) { const auto& dor = digits[i]; const auto& ddc = digitsD[i]; - LOG(INFO) << " dor " << dor.mTriggers.nChanA << " " << dor.mTriggers.nChanC << " " << dor.mTriggers.amplA << " " << dor.mTriggers.amplC; - LOG(INFO) << " ddc " << ddc.mTriggers.nChanA << " " << ddc.mTriggers.nChanC << " " << ddc.mTriggers.amplA << " " << ddc.mTriggers.amplC; + LOG(DEBUG) << " dor " << dor.mTriggers.nChanA << " " << dor.mTriggers.nChanC << " " << dor.mTriggers.amplA << " " << dor.mTriggers.amplC; + LOG(DEBUG) << " ddc " << ddc.mTriggers.nChanA << " " << ddc.mTriggers.nChanC << " " << ddc.mTriggers.amplA << " " << ddc.mTriggers.amplC; BOOST_CHECK(dor.mIntRecord == ddc.mIntRecord); BOOST_CHECK(dor.mTriggers.nChanA == ddc.mTriggers.nChanA); diff --git a/Detectors/CTF/test/test_ctf_io_fv0.cxx b/Detectors/CTF/test/test_ctf_io_fv0.cxx index 3e395de8ec7c7..3367b1cce3b89 100644 --- a/Detectors/CTF/test/test_ctf_io_fv0.cxx +++ b/Detectors/CTF/test/test_ctf_io_fv0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,6 +28,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) { std::vector<BCData> digits; std::vector<ChannelData> channels; + Triggers trigger; // TODO: Actual values are not set TStopwatch sw; sw.Start(); @@ -44,7 +46,8 @@ BOOST_AUTO_TEST_CASE(CTFTest) ich += 1 + gRandom->Poisson(10); } auto end = channels.size(); - digits.emplace_back(start, end - start, ir); + + digits.emplace_back(start, end - start, ir, trigger); } LOG(INFO) << "Generated " << channels.size() << " channels in " << digits.size() << " digits " << sw.CpuTime() << " s"; diff --git a/Detectors/CTF/test/test_ctf_io_hmpid.cxx b/Detectors/CTF/test/test_ctf_io_hmpid.cxx new file mode 100644 index 0000000000000..c591f3081f67b --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_hmpid.cxx @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test HMPIDCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "HMPIDReconstruction/CTFCoder.h" +#include "DataFormatsHMP/CTF.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::hmpid; + +BOOST_AUTO_TEST_CASE(CTFTest) +{ + std::vector<Trigger> triggers; + std::vector<Digit> digits; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir(0, 0); + Digit clu; + for (int irof = 0; irof < 1000; irof++) { + ir += 1 + gRandom->Integer(200); + + auto start = digits.size(); + uint8_t chID = 0; + int n = 0; + while ((chID += gRandom->Integer(10)) < 0xff) { + uint16_t q = gRandom->Integer(0xffff); + uint8_t ph = gRandom->Integer(0xff); + uint8_t x = gRandom->Integer(0xff); + uint8_t y = gRandom->Integer(0xff); + digits.emplace_back(chID, ph, x, y, q); + } + triggers.emplace_back(ir, start, digits.size() - start); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, triggers, digits); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::hmpid::CTF::get(vec.data()); + TFile flOut("test_ctf_hmpid.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "HMP"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + LOG(INFO) << "Start reading from tree "; + { + sw.Start(); + TFile flIn("test_ctf_hmpid.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::hmpid::CTF::readFromTree(vec, *(tree.get()), "HMP"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<Trigger> triggersD; + std::vector<Digit> digitsD; + + sw.Start(); + const auto ctfImage = o2::hmpid::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, triggersD, digitsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + BOOST_CHECK(triggersD.size() == triggers.size()); + BOOST_CHECK(digitsD.size() == digits.size()); + + BOOST_TEST(triggersD == triggers, boost::test_tools::per_element()); + BOOST_TEST(digitsD == digits, boost::test_tools::per_element()); +} diff --git a/Detectors/CTF/test/test_ctf_io_itsmft.cxx b/Detectors/CTF/test/test_ctf_io_itsmft.cxx index ad67d55574d0e..80779afab4c17 100644 --- a/Detectors/CTF/test/test_ctf_io_itsmft.cxx +++ b/Detectors/CTF/test/test_ctf_io_itsmft.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -104,11 +105,12 @@ BOOST_AUTO_TEST_CASE(CompressedClustersTest) std::vector<ROFRecord> rofRecVecD; std::vector<CompClusterExt> cclusVecD; std::vector<unsigned char> pattVecD; + LookUp clPattLookup; sw.Start(); const auto ctfImage = o2::itsmft::CTF::getImage(vec.data()); { CTFCoder coder(o2::detectors::DetID::ITS); - coder.decode(ctfImage, rofRecVecD, cclusVecD, pattVecD); // decompress + coder.decode(ctfImage, rofRecVecD, cclusVecD, pattVecD, nullptr, clPattLookup); // decompress } sw.Stop(); LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; diff --git a/Detectors/CTF/test/test_ctf_io_mch.cxx b/Detectors/CTF/test/test_ctf_io_mch.cxx new file mode 100644 index 0000000000000..e1f717c31aa24 --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_mch.cxx @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "MCHCTF/CTFCoder.h" +#include "DataFormatsMCH/CTF.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::mch; + +BOOST_AUTO_TEST_CASE(CTFTest, *boost::unit_test::enabled()) +{ + std::vector<ROFRecord> rofs; + std::vector<Digit> digs; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir0(3, 5), ir(ir0); + + for (int irof = 0; irof < 1000; irof++) { + ir += 1 + gRandom->Integer(200); + int nch = 0; + while (nch == 0) { + nch = gRandom->Poisson(20); + } + int start = digs.size(); + for (int ich = 0; ich < nch; ich++) { + int16_t detID = 100 + gRandom->Integer(1025 - 100); + int16_t padID = gRandom->Integer(28672); + int32_t tfTime = ir.differenceInBC(ir0); + uint32_t adc = gRandom->Integer(1024 * 1024); + uint16_t nsamp = gRandom->Integer(1024); + auto& d = digs.emplace_back(detID, padID, adc, tfTime, nsamp); + bool sat = gRandom->Rndm() > 0.9; + d.setSaturated(sat); + } + rofs.emplace_back(ir, start, nch); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, rofs, digs); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::mch::CTF::get(vec.data()); + TFile flOut("test_ctf_mch.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "MCH"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + { + sw.Start(); + TFile flIn("test_ctf_mch.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::mch::CTF::readFromTree(vec, *(tree.get()), "MCH"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<ROFRecord> rofsD; + std::vector<Digit> digsD; + + sw.Start(); + const auto ctfImage = o2::mch::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, rofsD, digsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + LOG(INFO) << " BOOST_CHECK rofsD.size() " << rofsD.size() << " rofs.size() " << rofs.size() + << " BOOST_CHECK(digsD.size() " << digsD.size() << " digs.size()) " << digs.size(); + + BOOST_TEST(rofs == rofsD, boost::test_tools::per_element()); + BOOST_TEST(digs == digsD, boost::test_tools::per_element()); +} diff --git a/Detectors/CTF/test/test_ctf_io_mid.cxx b/Detectors/CTF/test/test_ctf_io_mid.cxx index 94f6c67b087a2..586a9d57031ed 100644 --- a/Detectors/CTF/test/test_ctf_io_mid.cxx +++ b/Detectors/CTF/test/test_ctf_io_mid.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,40 +27,51 @@ using namespace o2::mid; BOOST_AUTO_TEST_CASE(CTFTest) { - std::vector<ROFRecord> rofs; - std::vector<ColumnData> cols; + std::array<std::vector<ColumnData>, NEvTypes> colData{}; + std::array<std::vector<ROFRecord>, NEvTypes> rofData{}; + CTFHelper::TFData tfData; // RS: don't understand why, but this library is not loaded automatically, although the dependencies are clearly // indicated. What it more weird is that for similar tests of other detectors the library is loaded! // Absence of the library leads to complains about the StreamerInfo and eventually segm.faul when appending the // CTH to the tree. For this reason I am loading it here manually - gSystem->Load("libO2DetectorsCommonDataFormats.so"); + gSystem->Load("libO2DetectorsCommonDataFormats"); TStopwatch sw; sw.Start(); o2::InteractionRecord ir(0, 0); std::array<uint16_t, 5> pattern; for (int irof = 0; irof < 1000; irof++) { ir += 1 + gRandom->Integer(200); - uint8_t nch = 0, evtyp = gRandom->Integer(3); - while (nch == 0) { - nch = gRandom->Poisson(10); - } - auto start = cols.size(); - for (int ich = 0; ich < nch; ich++) { - uint8_t deId = gRandom->Integer(128); - uint8_t columnId = gRandom->Integer(128); - for (int i = 0; i < 5; i++) { - pattern[i] = gRandom->Integer(0x7fff); + for (uint8_t evtyp = 0; evtyp < NEvTypes; evtyp++) { + if (gRandom->Rndm() > 0.8) { + continue; // sometimes skip some event types + } + uint8_t nch = 0; + while (nch == 0) { + nch = gRandom->Poisson(10); } - cols.emplace_back(ColumnData{deId, columnId, pattern}); + auto start = colData[evtyp].size(); + for (int ich = 0; ich < nch; ich++) { + uint8_t deId = gRandom->Integer(128); + uint8_t columnId = gRandom->Integer(128); + for (int i = 0; i < 5; i++) { + pattern[i] = gRandom->Integer(0x7fff); + } + colData[evtyp].emplace_back(ColumnData{deId, columnId, pattern}); + } + rofData[evtyp].emplace_back(ROFRecord{ir, EventType(evtyp), start, colData[evtyp].size() - start}); } - rofs.emplace_back(ROFRecord{ir, EventType(evtyp), start, cols.size() - start}); } + for (uint32_t i = 0; i < NEvTypes; i++) { + tfData.colData[i] = {colData[i].data(), colData[i].size()}; + tfData.rofData[i] = {rofData[i].data(), rofData[i].size()}; + } + tfData.buildReferences(); sw.Start(); std::vector<o2::ctf::BufferType> vec; { CTFCoder coder; - coder.encode(vec, rofs, cols); // compress + coder.encode(vec, tfData); // compress } sw.Stop(); LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; @@ -89,42 +101,49 @@ BOOST_AUTO_TEST_CASE(CTFTest) LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; } - std::vector<ROFRecord> rofsD; - std::vector<ColumnData> colsD; + std::array<std::vector<ColumnData>, NEvTypes> colDataD{}; + std::array<std::vector<ROFRecord>, NEvTypes> rofDataD{}; sw.Start(); const auto ctfImage = o2::mid::CTF::getImage(vec.data()); { CTFCoder coder; - coder.decode(ctfImage, rofsD, colsD); // decompress + coder.decode(ctfImage, rofDataD, colDataD); // decompress } sw.Stop(); LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; - BOOST_CHECK(rofsD.size() == rofs.size()); - BOOST_CHECK(colsD.size() == cols.size()); - LOG(INFO) << " BOOST_CHECK rofsD.size() " << rofsD.size() << " rofs.size() " << rofs.size() - << " BOOST_CHECK(colsD.size() " << colsD.size() << " cols.size()) " << cols.size(); + for (uint32_t it = 0; it < NEvTypes; it++) { + const auto& rofsD = rofDataD[it]; + const auto& rofs = rofData[it]; + const auto& colsD = colDataD[it]; + const auto& cols = colData[it]; + LOG(INFO) << "Test for event type " << it; + BOOST_CHECK(rofsD.size() == rofs.size()); + BOOST_CHECK(colsD.size() == cols.size()); + LOG(INFO) << " BOOST_CHECK rofsD.size() " << rofsD.size() << " rofs.size() " << rofData[0].size() + << " BOOST_CHECK(colsD.size() " << colsD.size() << " cols.size()) " << colData[0].size(); - for (size_t i = 0; i < rofs.size(); i++) { - const auto& dor = rofs[i]; - const auto& ddc = rofsD[i]; - LOG(DEBUG) << " Orig.ROFRecord " << i << " " << dor.interactionRecord << " " << dor.firstEntry << " " << dor.nEntries; - LOG(DEBUG) << " Deco.ROFRecord " << i << " " << ddc.interactionRecord << " " << ddc.firstEntry << " " << ddc.nEntries; + for (size_t i = 0; i < rofs.size(); i++) { + const auto& dor = rofs[i]; + const auto& ddc = rofsD[i]; + LOG(DEBUG) << " Orig.ROFRecord " << i << " " << dor.interactionRecord << " " << dor.firstEntry << " " << dor.nEntries; + LOG(DEBUG) << " Deco.ROFRecord " << i << " " << ddc.interactionRecord << " " << ddc.firstEntry << " " << ddc.nEntries; - BOOST_CHECK(dor.interactionRecord == ddc.interactionRecord); - BOOST_CHECK(dor.firstEntry == ddc.firstEntry); - BOOST_CHECK(dor.nEntries == dor.nEntries); - } + BOOST_CHECK(dor.interactionRecord == ddc.interactionRecord); + BOOST_CHECK(dor.firstEntry == ddc.firstEntry); + BOOST_CHECK(dor.nEntries == dor.nEntries); + } - for (size_t i = 0; i < cols.size(); i++) { - const auto& cor = cols[i]; - const auto& cdc = colsD[i]; - BOOST_CHECK(cor.deId == cdc.deId); - BOOST_CHECK(cor.columnId == cdc.columnId); - for (int j = 0; j < 5; j++) { - BOOST_CHECK(cor.patterns[j] == cdc.patterns[j]); - LOG(DEBUG) << "col " << i << " pat " << j << " : " << cor.patterns[j] << " : " << cdc.patterns[j]; + for (size_t i = 0; i < cols.size(); i++) { + const auto& cor = cols[i]; + const auto& cdc = colsD[i]; + BOOST_CHECK(cor.deId == cdc.deId); + BOOST_CHECK(cor.columnId == cdc.columnId); + for (int j = 0; j < 5; j++) { + BOOST_CHECK(cor.patterns[j] == cdc.patterns[j]); + LOG(DEBUG) << "col " << i << " pat " << j << " : " << cor.patterns[j] << " : " << cdc.patterns[j]; + } } } } diff --git a/Detectors/CTF/test/test_ctf_io_phos.cxx b/Detectors/CTF/test/test_ctf_io_phos.cxx new file mode 100644 index 0000000000000..7cff1f2ed408d --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_phos.cxx @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test PHSCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "PHOSReconstruction/CTFCoder.h" +#include "DataFormatsPHOS/CTF.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::phos; + +BOOST_AUTO_TEST_CASE(CTFTest) +{ + std::vector<TriggerRecord> triggers; + std::vector<Cell> cells; + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir(0, 0); + for (int irof = 0; irof < 1000; irof++) { + ir += 1 + gRandom->Integer(200); + + auto start = cells.size(); + int n = 1 + gRandom->Poisson(100); + for (int i = n; i--;) { + ChannelType_t tp = gRandom->Rndm() > 0.5 ? (gRandom->Rndm() > 0.5 ? TRU2x2 : TRU4x4) : (gRandom->Rndm() > 0.5 ? HIGH_GAIN : LOW_GAIN); + uint16_t id = (tp == TRU2x2 || tp == TRU4x4) ? 3000 : gRandom->Integer(kNmaxCell); + float timeCell = gRandom->Rndm() * 3.00e-07 - 0.3e-9; + float en = gRandom->Rndm() * 160.; + cells.emplace_back(id, en, timeCell, tp); + } + triggers.emplace_back(ir, start, cells.size() - start); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, triggers, cells); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::phos::CTF::get(vec.data()); + TFile flOut("test_ctf_phos.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "PHS"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + { + sw.Start(); + TFile flIn("test_ctf_phos.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::phos::CTF::readFromTree(vec, *(tree.get()), "PHS"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<TriggerRecord> triggersD; + std::vector<Cell> cellsD; + + sw.Start(); + const auto ctfImage = o2::phos::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, triggersD, cellsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + BOOST_CHECK(triggersD.size() == triggers.size()); + BOOST_CHECK(cellsD.size() == cells.size()); + LOG(INFO) << " BOOST_CHECK triggersD.size() " << triggersD.size() << " triggers.size() " << triggers.size() + << " BOOST_CHECK(cellsD.size() " << cellsD.size() << " cells.size()) " << cells.size(); + + for (size_t i = 0; i < triggers.size(); i++) { + const auto& dor = triggers[i]; + const auto& ddc = triggersD[i]; + LOG(DEBUG) << " Orig.TriggerRecord " << i << " " << dor.getBCData() << " " << dor.getFirstEntry() << " " << dor.getNumberOfObjects(); + LOG(DEBUG) << " Deco.TriggerRecord " << i << " " << ddc.getBCData() << " " << ddc.getFirstEntry() << " " << ddc.getNumberOfObjects(); + + BOOST_CHECK(dor.getBCData() == ddc.getBCData()); + BOOST_CHECK(dor.getNumberOfObjects() == ddc.getNumberOfObjects()); + BOOST_CHECK(dor.getFirstEntry() == dor.getFirstEntry()); + } + + for (size_t i = 0; i < cells.size(); i++) { + const auto& cor = cells[i]; + const auto& cdc = cellsD[i]; + BOOST_CHECK(cor.getPackedID() == cdc.getPackedID()); + BOOST_CHECK(cor.getPackedTime() == cdc.getPackedTime()); + BOOST_CHECK(cor.getPackedEnergy() == cdc.getPackedEnergy()); + BOOST_CHECK(cor.getPackedCellStatus() == cdc.getPackedCellStatus()); + } +} diff --git a/Detectors/CTF/test/test_ctf_io_tof.cxx b/Detectors/CTF/test/test_ctf_io_tof.cxx index 27810fc5b9292..c3bc0825a3211 100644 --- a/Detectors/CTF/test/test_ctf_io_tof.cxx +++ b/Detectors/CTF/test/test_ctf_io_tof.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,7 +31,7 @@ BOOST_AUTO_TEST_CASE(CompressedClustersTest) std::vector<Digit> digits; std::vector<ReadoutWindowData> rows; - std::vector<uint32_t> pattVec; + std::vector<uint8_t> pattVec; TStopwatch sw; sw.Start(); @@ -117,7 +118,7 @@ BOOST_AUTO_TEST_CASE(CompressedClustersTest) std::vector<Digit> digitsD; std::vector<ReadoutWindowData> rowsD; - std::vector<uint32_t> pattVecD; + std::vector<uint8_t> pattVecD; sw.Start(); const auto ctfImage = CTF::getImage(vec.data()); { diff --git a/Detectors/CTF/test/test_ctf_io_tpc.cxx b/Detectors/CTF/test/test_ctf_io_tpc.cxx index 99ebe3a36a5ef..3ea058dc708a8 100644 --- a/Detectors/CTF/test/test_ctf_io_tpc.cxx +++ b/Detectors/CTF/test/test_ctf_io_tpc.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,6 +43,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) { CTFCoder coder; coder.setCompClusAddresses(c, buff); + coder.setCombineColumns(true); } ccFlat->set(sz, c); @@ -85,6 +87,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) std::vector<o2::ctf::BufferType> vecIO; { CTFCoder coder; + coder.setCombineColumns(true); coder.encode(vecIO, c); // compress } sw.Stop(); @@ -120,6 +123,7 @@ BOOST_AUTO_TEST_CASE(CTFTest) const auto ctfImage = o2::tpc::CTF::getImage(vecIO.data()); { CTFCoder coder; + coder.setCombineColumns(true); coder.decode(ctfImage, vecIn); // decompress } sw.Stop(); diff --git a/Detectors/CTF/test/test_ctf_io_trd.cxx b/Detectors/CTF/test/test_ctf_io_trd.cxx new file mode 100644 index 0000000000000..dfac172ab79a8 --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_trd.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test TRDCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "TRDReconstruction/CTFCoder.h" +#include "DataFormatsTRD/CTF.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::trd; + +BOOST_AUTO_TEST_CASE(CTFTest) +{ + std::vector<TriggerRecord> triggers; + std::vector<Tracklet64> tracklets; + std::vector<Digit> digits; + + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir(0, 0); + constexpr int NCID = 540, NHCID = 2 * NCID; + constexpr uint32_t formatTrk = 5; + ArrayADC adc; + + for (int irof = 0; irof < 200; irof++) { + ir += 1 + gRandom->Integer(600); + bool doDigits = gRandom->Rndm() > 0.8; + + auto startTrk = tracklets.size(); + auto startDig = digits.size(); + int cid = 0; + while ((cid += gRandom->Poisson(5)) < NHCID) { + int hcid = cid / 2; + int nTrk = gRandom->Poisson(3); + int nDig = doDigits ? nTrk * 5 * (1. + gRandom->Rndm()) : 0; + + for (int i = nTrk; i--;) { + tracklets.emplace_back(formatTrk, hcid, gRandom->Integer(0x1 << 4), gRandom->Integer(0x1 << 2), + gRandom->Integer(0x1 << 11), gRandom->Integer(0x1 << 8), gRandom->Integer(0x1 << 24)); + } + for (int i = nDig; i--;) { + auto& dig = digits.emplace_back(cid, gRandom->Integer(0x1 << 8), gRandom->Integer(0x1 << 8), gRandom->Integer(0x1 << 8)); + for (int j = constants::TIMEBINS; j--;) { + adc[j] = gRandom->Integer(0x1 << 16); + } + dig.setADC(adc); + } + } + + triggers.emplace_back(ir, startDig, digits.size() - startDig, startTrk, tracklets.size() - startTrk); + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, triggers, tracklets, digits); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::trd::CTF::get(vec.data()); + TFile flOut("test_ctf_trd.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "TRD"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + LOG(INFO) << "Start reading from tree "; + { + sw.Start(); + TFile flIn("test_ctf_trd.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::trd::CTF::readFromTree(vec, *(tree.get()), "TRD"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<TriggerRecord> triggersD; + std::vector<Tracklet64> trackletsD; + std::vector<Digit> digitsD; + + sw.Start(); + const auto ctfImage = o2::trd::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, triggersD, trackletsD, digitsD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + BOOST_CHECK(triggersD.size() == triggers.size()); + BOOST_CHECK(trackletsD.size() == tracklets.size()); + BOOST_CHECK(digitsD.size() == digitsD.size()); + + BOOST_TEST(triggersD == triggers, boost::test_tools::per_element()); + BOOST_TEST(trackletsD == tracklets, boost::test_tools::per_element()); + BOOST_TEST(digitsD == digits, boost::test_tools::per_element()); +} diff --git a/Detectors/CTF/test/test_ctf_io_zdc.cxx b/Detectors/CTF/test/test_ctf_io_zdc.cxx new file mode 100644 index 0000000000000..5caddfce274bf --- /dev/null +++ b/Detectors/CTF/test/test_ctf_io_zdc.cxx @@ -0,0 +1,169 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test ZDCCTFIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "ZDCReconstruction/CTFCoder.h" +#include "DataFormatsZDC/CTF.h" +#include "Framework/Logger.h" +#include <TFile.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include <TSystem.h> +#include <cstring> + +using namespace o2::zdc; + +BOOST_AUTO_TEST_CASE(CTFTest) +{ + std::vector<BCData> bcdata; + std::vector<ChannelData> chandata; + std::vector<OrbitData> pedsdata; + // RS: don't understand why, but this library is not loaded automatically, although the dependencies are clearly + // indicated. What it more weird is that for similar tests of other detectors the library is loaded! + // Absence of the library leads to complains about the StreamerInfo and eventually segm.faul when appending the + // CTH to the tree. For this reason I am loading it here manually + // gSystem->Load("libO2DetectorsCommonDataFormats"); + TStopwatch sw; + sw.Start(); + o2::InteractionRecord ir(0, 0); + std::array<float, NTimeBinsPerBC> chanVals; + + // BCData and ChannelData + for (int irof = 0; irof < 1000; irof++) { + ir += 1 + gRandom->Integer(100); // randomly increaing BC + + uint32_t channPatt = 0, triggers = 0; + int8_t ich = -1; + int firstChEntry = chandata.size(); + while ((ich += 1 + gRandom->Poisson(2.)) < NDigiChannels) { + channPatt |= 0x1 << ich; + for (int i = 0; i < NTimeBinsPerBC; i++) { + chanVals[i] = gRandom->Integer(0xffff); + } + if (gRandom->Rndm() > 0.4) { + triggers |= 0x1 << ich; + } + chandata.emplace_back(ich, chanVals); + } + auto& bcd = bcdata.emplace_back(firstChEntry, chandata.size() - firstChEntry, ir, channPatt, triggers, gRandom->Integer(0xff)); + for (int im = 0; im < NModules; im++) { + bcd.moduleTriggers[im] = gRandom->Rndm() > 0.7 ? gRandom->Integer((0x1 << 10) - 1) : 0; + } + } + + // OrbitData + const auto &irFirst = bcdata.front().ir, irLast = bcdata.back().ir; + o2::InteractionRecord irPed(o2::constants::lhc::LHCMaxBunches - 1, irFirst.orbit); + int norbits = irLast.orbit - irFirst.orbit + 1; + pedsdata.resize(norbits); + for (int i = 0; i < norbits; i++) { + pedsdata[i].ir = irPed; + for (int ic = 0; ic < NChannels; ic++) { + pedsdata[i].data[ic] = gRandom->Integer(0xffff); + pedsdata[i].scaler[ic] = (i > 0 ? pedsdata[i].scaler[ic - 1] : 0) + gRandom->Integer(20); + } + irPed.orbit++; + } + + sw.Start(); + std::vector<o2::ctf::BufferType> vec; + { + CTFCoder coder; + coder.encode(vec, bcdata, chandata, pedsdata); // compress + } + sw.Stop(); + LOG(INFO) << "Compressed in " << sw.CpuTime() << " s"; + + // writing + { + sw.Start(); + auto* ctfImage = o2::zdc::CTF::get(vec.data()); + TFile flOut("test_ctf_zdc.root", "recreate"); + TTree ctfTree(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + ctfImage->print(); + ctfImage->appendToTree(ctfTree, "ZDC"); + ctfTree.Write(); + sw.Stop(); + LOG(INFO) << "Wrote to tree in " << sw.CpuTime() << " s"; + } + + // reading + vec.clear(); + { + sw.Start(); + TFile flIn("test_ctf_zdc.root"); + std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + BOOST_CHECK(tree); + o2::zdc::CTF::readFromTree(vec, *(tree.get()), "ZDC"); + sw.Stop(); + LOG(INFO) << "Read back from tree in " << sw.CpuTime() << " s"; + } + + std::vector<BCData> bcdataD; + std::vector<ChannelData> chandataD; + std::vector<OrbitData> pedsdataD; + + sw.Start(); + const auto ctfImage = o2::zdc::CTF::getImage(vec.data()); + { + CTFCoder coder; + coder.decode(ctfImage, bcdataD, chandataD, pedsdataD); // decompress + } + sw.Stop(); + LOG(INFO) << "Decompressed in " << sw.CpuTime() << " s"; + + LOG(INFO) << "Testing BCData: BOOST_CHECK bcdataD.size() " << bcdataD.size() << " bcdata.size() " << bcdata.size(); + BOOST_CHECK(bcdataD.size() == bcdata.size()); + for (size_t i = 0; i < bcdata.size(); i++) { + bool cmpBCData = (bcdata[i].ir == bcdataD[i].ir && + bcdata[i].ref == bcdataD[i].ref && + bcdata[i].moduleTriggers == bcdataD[i].moduleTriggers && + bcdata[i].channels == bcdataD[i].channels && + bcdata[i].triggers == bcdataD[i].triggers && + bcdata[i].ext_triggers == bcdataD[i].ext_triggers); + + if (!cmpBCData) { + LOG(ERROR) << "Mismatch in BC data " << i; + bcdata[i].print(); + bcdataD[i].print(); + } + BOOST_CHECK(cmpBCData); + } + + LOG(INFO) << "Testing ChannelData: BOOST_CHECK(chandataD.size() " << chandataD.size() << " chandata.size()) " << chandata.size(); + BOOST_CHECK(chandataD.size() == chandata.size()); + + for (size_t i = 0; i < chandata.size(); i++) { + bool cmpChData = chandata[i].id == chandataD[i].id && chandata[i].data == chandataD[i].data; + if (!cmpChData) { + LOG(ERROR) << "Mismatch in ChannelData " << i; + chandata[i].print(); + chandataD[i].print(); + } + BOOST_CHECK(cmpChData); + } + + LOG(INFO) << "Testing OrbitData: BOOST_CHECK(pedsdataD.size() " << pedsdataD.size() << " pedsdata.size()) " << pedsdata.size(); + BOOST_CHECK(pedsdataD.size() == pedsdata.size()); + for (size_t i = 0; i < pedsdata.size(); i++) { + bool cmpPdData = pedsdata[i].ir == pedsdataD[i].ir && pedsdata[i].data == pedsdataD[i].data && pedsdata[i].scaler == pedsdataD[i].scaler; + if (!cmpPdData) { + LOG(ERROR) << "Mismatch in OrbitData " << i; + pedsdata[i].print(); + pedsdataD[i].print(); + } + BOOST_CHECK(cmpPdData); + } +} diff --git a/Detectors/CTF/workflow/CMakeLists.txt b/Detectors/CTF/workflow/CMakeLists.txt index 166900fc24e3b..2b52c9f7dd2c5 100644 --- a/Detectors/CTF/workflow/CMakeLists.txt +++ b/Detectors/CTF/workflow/CMakeLists.txt @@ -1,34 +1,47 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(CTFWorkflow SOURCES src/CTFWriterSpec.cxx src/CTFReaderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsCommonDataFormats O2::DataFormatsITSMFT O2::DataFormatsTPC + O2::DataFormatsTRD O2::DataFormatsTOF O2::DataFormatsFT0 O2::DataFormatsFV0 - O2::DataFormatsFDD - O2::DataFormatsMID + O2::DataFormatsFDD + O2::DataFormatsMID + O2::DataFormatsPHOS + O2::DataFormatsCPV + O2::DataFormatsZDC + O2::DataFormatsHMP + O2::DataFormatsCTP O2::DataFormatsParameters O2::ITSMFTWorkflow O2::TPCWorkflow + O2::TRDWorkflow O2::FT0Workflow O2::FV0Workflow - O2::FDDWorkflow - O2::TOFWorkflow + O2::FDDWorkflow + O2::MCHWorkflow O2::MIDWorkflow O2::EMCALWorkflow + O2::PHOSWorkflow + O2::CPVWorkflow + O2::ZDCWorkflow + O2::HMPIDWorkflow + O2::CTPWorkflow O2::Algorithm O2::CommonUtils) diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h index 607d952cdc48e..4092f937e1947 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,40 +14,29 @@ #ifndef O2_CTFREADER_SPEC #define O2_CTFREADER_SPEC -#include "TFile.h" -#include "TTree.h" -#include <TStopwatch.h> - #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" - #include "DetectorsCommonDataFormats/DetID.h" +#include <string> namespace o2 { namespace ctf { - -using DetID = o2::detectors::DetID; - -class CTFReaderSpec : public o2::framework::Task -{ - public: - CTFReaderSpec(DetID::mask_t dm, const std::string& inp); - ~CTFReaderSpec() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - DetID::mask_t mDets; // detectors - std::vector<std::string> mInput; // input files - uint32_t mTFCounter = 0; - size_t mNextToProcess = 0; - TStopwatch mTimer; +struct CTFReaderInp { + std::string inpdata{}; + o2::detectors::DetID::mask_t detMask = o2::detectors::DetID::FullMask; + std::string copyCmd{}; + std::string tffileRegex{}; + std::string remoteRegex{}; + int maxFileCache = 1; + int64_t delay_us = 0; + int maxLoops = 0; + int maxTFs = -1; }; /// create a processor spec -framework::DataProcessorSpec getCTFReaderSpec(DetID::mask_t dets, const std::string& inp); +framework::DataProcessorSpec getCTFReaderSpec(const o2::ctf::CTFReaderInp& inp); } // namespace ctf } // namespace o2 diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h index c0b95b787f9ad..e0d5fe9dfa4da 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,134 +14,17 @@ #ifndef O2_CTFWRITER_SPEC #define O2_CTFWRITER_SPEC -#include "TFile.h" -#include "TTree.h" - #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsCommonDataFormats/CTFHeader.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include "DetectorsCommonDataFormats/EncodedBlocks.h" -#include "CommonUtils/StringUtils.h" -#include "rANS/rans.h" -#include <vector> -#include <array> -#include <TStopwatch.h> +#include "DetectorsCommonDataFormats/DetID.h" namespace o2 { namespace ctf { -using DetID = o2::detectors::DetID; -using FTrans = o2::rans::FrequencyTable; - -class CTFWriterSpec : public o2::framework::Task -{ - public: - CTFWriterSpec() = delete; - CTFWriterSpec(DetID::mask_t dm, uint64_t r = 0, bool doCTF = true, bool doDict = false, bool dictPerDet = false); - ~CTFWriterSpec() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - void endOfStream(o2::framework::EndOfStreamContext& ec) final; - bool isPresent(DetID id) const { return mDets[id]; } - - private: - template <typename C> - void processDet(o2::framework::ProcessingContext& pc, DetID det, CTFHeader& header, TTree* tree); - template <typename C> - void storeDictionary(DetID det, CTFHeader& header); - void storeDictionaries(); - void prepareDictionaryTreeAndFile(DetID det); - void closeDictionaryTreeAndFile(CTFHeader& header); - std::string dictionaryFileName(const std::string& detName = ""); - - DetID::mask_t mDets; // detectors - bool mWriteCTF = false; - bool mCreateDict = false; - bool mDictPerDetector = false; - size_t mNTF = 0; - int mSaveDictAfter = -1; // if positive and mWriteCTF==true, save dictionary after each mSaveDictAfter TFs processed - uint64_t mRun = 0; - - std::unique_ptr<TFile> mDictFileOut; // file to store dictionary - std::unique_ptr<TTree> mDictTreeOut; // tree to store dictionary - - // For the external dictionary creation we accumulate for each detector the frequency tables of its each block - // After accumulation over multiple TFs we store the dictionaries data in the standard CTF format of this detector, - // i.e. EncodedBlock stored in a tree, BUT with dictionary data only added to each block. - // The metadata of the block (min,max) will be used for the consistency check at the decoding - std::array<std::vector<FTrans>, DetID::nDetectors> mFreqsAccumulation; - std::array<std::vector<o2::ctf::Metadata>, DetID::nDetectors> mFreqsMetaData; - std::array<std::shared_ptr<void>, DetID::nDetectors> mHeaders; - - TStopwatch mTimer; -}; - -// process data of particular detector -template <typename C> -void CTFWriterSpec::processDet(o2::framework::ProcessingContext& pc, DetID det, CTFHeader& header, TTree* tree) -{ - if (!isPresent(det) || !pc.inputs().isValid(det.getName())) { - return; - } - auto ctfBuffer = pc.inputs().get<gsl::span<o2::ctf::BufferType>>(det.getName()); - const auto ctfImage = C::getImage(ctfBuffer.data()); - ctfImage.print(o2::utils::concat_string(det.getName(), ": ")); - if (mWriteCTF) { - ctfImage.appendToTree(*tree, det.getName()); - header.detectors.set(det); - } - if (mCreateDict) { - if (!mFreqsAccumulation[det].size()) { - mFreqsAccumulation[det].resize(C::getNBlocks()); - mFreqsMetaData[det].resize(C::getNBlocks()); - } - if (!mHeaders[det]) { // store 1st header - mHeaders[det] = ctfImage.cloneHeader(); - } - for (int ib = 0; ib < C::getNBlocks(); ib++) { - const auto& bl = ctfImage.getBlock(ib); - if (bl.getNDict()) { - auto& freq = mFreqsAccumulation[det][ib]; - auto& mdSave = mFreqsMetaData[det][ib]; - const auto& md = ctfImage.getMetadata(ib); - freq.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); - mdSave = o2::ctf::Metadata{0, 0, md.coderType, md.streamSize, md.probabilityBits, md.opt, freq.getMinSymbol(), freq.getMaxSymbol(), (int)freq.size(), 0, 0}; - } - } - } -} - -// store dictionary of a particular detector -template <typename C> -void CTFWriterSpec::storeDictionary(DetID det, CTFHeader& header) -{ - if (!isPresent(det) || !mFreqsAccumulation[det].size()) { - return; - } - prepareDictionaryTreeAndFile(det); - // create vector whose data contains dictionary in CTF format (EncodedBlock) - auto dictBlocks = C::createDictionaryBlocks(mFreqsAccumulation[det], mFreqsMetaData[det]); - auto& h = C::get(dictBlocks.data())->getHeader(); - h = *reinterpret_cast<typename std::remove_reference<decltype(h)>::type*>(mHeaders[det].get()); - C::get(dictBlocks.data())->print(o2::utils::concat_string("Storing dictionary for ", det.getName(), ": ")); - C::get(dictBlocks.data())->appendToTree(*mDictTreeOut.get(), det.getName()); // cast to EncodedBlock - // mFreqsAccumulation[det].clear(); - // mFreqsMetaData[det].clear(); - if (mDictPerDetector) { - header.detectors.reset(); - } - header.detectors.set(det); - if (mDictPerDetector) { - closeDictionaryTreeAndFile(header); - } -} - /// create a processor spec -framework::DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, uint64_t run, bool doCTF = true, bool doDict = false, bool dictPerDet = false); +framework::DataProcessorSpec getCTFWriterSpec(o2::detectors::DetID::mask_t dets, uint64_t run, const std::string& outType); } // namespace ctf } // namespace o2 diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index 75f20df01c4db..85220dd37ffee 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,19 +20,28 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/InputSpec.h" #include "CommonUtils/StringUtils.h" +#include "CommonUtils/FileFetcher.h" #include "CTFWorkflow/CTFReaderSpec.h" #include "DetectorsCommonDataFormats/EncodedBlocks.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DetectorsCommonDataFormats/CTFHeader.h" #include "DataFormatsITSMFT/CTF.h" #include "DataFormatsTPC/CTF.h" +#include "DataFormatsTRD/CTF.h" #include "DataFormatsFT0/CTF.h" #include "DataFormatsFV0/CTF.h" #include "DataFormatsFDD/CTF.h" #include "DataFormatsTOF/CTF.h" #include "DataFormatsMID/CTF.h" +#include "DataFormatsMCH/CTF.h" #include "DataFormatsEMCAL/CTF.h" +#include "DataFormatsPHOS/CTF.h" +#include "DataFormatsCPV/CTF.h" +#include "DataFormatsZDC/CTF.h" +#include "DataFormatsHMP/CTF.h" +#include "DataFormatsCTP/CTF.h" #include "Algorithm/RangeTokenizer.h" +#include <TStopwatch.h> using namespace o2::framework; @@ -54,145 +64,297 @@ bool readFromTree(TTree& tree, const std::string brname, T& dest, int ev = 0) return false; } +using DetID = o2::detectors::DetID; + +class CTFReaderSpec : public o2::framework::Task +{ + public: + CTFReaderSpec(const CTFReaderInp& inp); + ~CTFReaderSpec() override; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + private: + void openCTFFile(const std::string& flname); + void processTF(ProcessingContext& pc); + void stop(); + CTFReaderInp mInput{}; + std::unique_ptr<o2::utils::FileFetcher> mFileFetcher; + std::unique_ptr<TFile> mCTFFile; + std::unique_ptr<TTree> mCTFTree; + bool mRunning = false; + int mCTFCounter = 0; + long mLastSendTime = 0L; + long mCurrTreeEntry = 0; + TStopwatch mTimer; +}; + ///_______________________________________ -CTFReaderSpec::CTFReaderSpec(DetID::mask_t dm, const std::string& inp) : mDets(dm) +CTFReaderSpec::CTFReaderSpec(const CTFReaderInp& inp) : mInput(inp) { mTimer.Stop(); mTimer.Reset(); - mInput = RangeTokenizer::tokenize<std::string>(inp); } ///_______________________________________ -void CTFReaderSpec::init(InitContext& ic) +CTFReaderSpec::~CTFReaderSpec() { + stop(); } ///_______________________________________ -void CTFReaderSpec::run(ProcessingContext& pc) +void CTFReaderSpec::stop() { - if (mNextToProcess >= mInput.size()) { + if (!mFileFetcher) { return; } + LOG(INFO) << "CTFReader stops processing"; + LOGP(INFO, "CTF reading total timing: Cpu: {:.3f} Real: {:.3f} s for {} TFs in {} loops", + mTimer.CpuTime(), mTimer.RealTime(), mCTFCounter, mFileFetcher->getNLoops()); + mRunning = false; + mFileFetcher->stop(); + mFileFetcher.reset(); + mCTFTree.reset(); + if (mCTFFile) { + mCTFFile->Close(); + } + mCTFFile.reset(); +} - auto cput = mTimer.CpuTime(); - mTimer.Start(false); - const auto& inputFile = mInput[mNextToProcess]; - LOG(INFO) << "Reading CTF input " << mNextToProcess << ' ' << inputFile; +///_______________________________________ +void CTFReaderSpec::init(InitContext& ic) +{ + mRunning = true; + mFileFetcher = std::make_unique<o2::utils::FileFetcher>(mInput.inpdata, mInput.tffileRegex, mInput.remoteRegex, mInput.copyCmd); + mFileFetcher->setMaxFilesInQueue(mInput.maxFileCache); + mFileFetcher->setMaxLoops(mInput.maxLoops); + mFileFetcher->start(); +} - TFile flIn(inputFile.c_str()); - if (!flIn.IsOpen() || flIn.IsZombie()) { - LOG(ERROR) << "Failed to open file " << inputFile; +///_______________________________________ +void CTFReaderSpec::openCTFFile(const std::string& flname) +{ + mCTFFile.reset(TFile::Open(flname.c_str())); + if (!mCTFFile->IsOpen() || mCTFFile->IsZombie()) { + LOG(ERROR) << "Failed to open file " << flname; throw std::runtime_error("failed to open CTF file"); } - std::unique_ptr<TTree> tree((TTree*)flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); - if (!tree) { + mCTFTree.reset((TTree*)mCTFFile->Get(std::string(o2::base::NameConf::CTFTREENAME).c_str())); + if (!mCTFTree) { throw std::runtime_error("failed to load CTF tree"); } + mCurrTreeEntry = 0; +} + +///_______________________________________ +void CTFReaderSpec::run(ProcessingContext& pc) +{ + std::string tfFileName; + if (mCTFCounter >= mInput.maxTFs) { // done + mRunning = false; + } + + while (mRunning) { + if (mCTFTree) { // there is a tree open with multiple CTF + LOG(INFO) << "TF " << mCTFCounter << " of " << mInput.maxTFs << " loop " << mFileFetcher->getNLoops(); + processTF(pc); + break; + } + // + tfFileName = mFileFetcher->getNextFileInQueue(); + if (tfFileName.empty()) { + if (!mFileFetcher->isRunning()) { // nothing expected in the queue + mRunning = false; + break; + } + usleep(5000); // wait 5ms for the files cache to be filled + continue; + } + LOG(INFO) << "Reading CTF input " << ' ' << tfFileName; + openCTFFile(tfFileName); + } + + if (!mRunning) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + stop(); + } +} + +///_______________________________________ +void CTFReaderSpec::processTF(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + CTFHeader ctfHeader; - if (!readFromTree(*tree, "CTFHeader", ctfHeader)) { + if (!readFromTree(*(mCTFTree.get()), "CTFHeader", ctfHeader, mCurrTreeEntry)) { throw std::runtime_error("did not find CTFHeader"); } LOG(INFO) << ctfHeader; - auto setFirstTFOrbit = [&](const std::string& label) { + auto setFirstTFOrbit = [&pc, &ctfHeader, this](const std::string& label) { auto* hd = pc.outputs().findMessageHeader({label}); if (!hd) { - throw std::runtime_error(o2::utils::concat_string("failed to find output message header for ", label)); + throw std::runtime_error(o2::utils::Str::concat_string("failed to find output message header for ", label)); } hd->firstTForbit = ctfHeader.firstTForbit; - hd->tfCounter = mTFCounter; + hd->tfCounter = this->mCTFCounter; }; // send CTF Header pc.outputs().snapshot({"header"}, ctfHeader); setFirstTFOrbit("header"); - DetID::mask_t detsTF = mDets & ctfHeader.detectors; + DetID::mask_t detsTF = mInput.detMask & ctfHeader.detectors; DetID det; det = DetID::ITS; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::itsmft::CTF)); - o2::itsmft::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::itsmft::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::MFT; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::itsmft::CTF)); - o2::itsmft::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::itsmft::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::TPC; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::tpc::CTF)); - o2::tpc::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::tpc::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + det = DetID::TRD; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::trd::CTF)); + o2::trd::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::FT0; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::ft0::CTF)); - o2::ft0::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::ft0::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::FV0; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::fv0::CTF)); - o2::fv0::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::fv0::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::FDD; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::fdd::CTF)); - o2::fdd::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::fdd::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::TOF; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::tof::CTF)); - o2::tof::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::tof::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::MID; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::mid::CTF)); - o2::mid::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::mid::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + det = DetID::MCH; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::mch::CTF)); + o2::mch::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } det = DetID::EMC; if (detsTF[det]) { auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::emcal::CTF)); - o2::emcal::CTF::readFromTree(bufVec, *(tree.get()), det.getName()); + o2::emcal::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); setFirstTFOrbit(det.getName()); } - mTimer.Stop(); - LOG(INFO) << "Read CTF " << inputFile << " in " << mTimer.CpuTime() - cput << " s"; + det = DetID::PHS; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::phos::CTF)); + o2::phos::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } - if (++mNextToProcess >= mInput.size()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - LOGF(INFO, "CTF reading total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); + det = DetID::CPV; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::cpv::CTF)); + o2::cpv::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + det = DetID::ZDC; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::zdc::CTF)); + o2::zdc::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + det = DetID::HMP; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::hmpid::CTF)); + o2::hmpid::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + det = DetID::CTP; + if (detsTF[det]) { + auto& bufVec = pc.outputs().make<std::vector<o2::ctf::BufferType>>({det.getName()}, sizeof(o2::ctp::CTF)); + o2::ctp::CTF::readFromTree(bufVec, *(mCTFTree.get()), det.getName(), mCurrTreeEntry); + setFirstTFOrbit(det.getName()); + } + + auto entryStr = fmt::format("({} of {} in {})", mCurrTreeEntry, mCTFTree->GetEntries(), mCTFFile->GetName()); + if (++mCurrTreeEntry >= mCTFTree->GetEntries()) { // this file is done, check if there are other files + mCTFTree.reset(); + mCTFFile->Close(); + mCTFFile.reset(); + if (mFileFetcher) { + mFileFetcher->popFromQueue(mFileFetcher->getNLoops() >= mInput.maxLoops); + } + } + mTimer.Stop(); + // do we need to way to respect the delay ? + long tNow = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + auto tDiff = tNow - mLastSendTime; + if (mCTFCounter) { + if (tDiff < mInput.delay_us) { + usleep(mInput.delay_us - tDiff); // respect requested delay before sending + } + } else { + mLastSendTime = tNow; } - mTFCounter++; + tNow = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + LOGP(INFO, "Read CTF#{} {} in {:.3f} s, {:.4f} s elapsed from previous CTF", mCTFCounter, entryStr, mTimer.CpuTime() - cput, 1e-6 * (tNow - mLastSendTime)); + mLastSendTime = tNow; + mCTFCounter++; } ///_______________________________________ -DataProcessorSpec getCTFReaderSpec(DetID::mask_t dets, const std::string& inp) +DataProcessorSpec getCTFReaderSpec(const CTFReaderInp& inp) { std::vector<OutputSpec> outputs; outputs.emplace_back(OutputLabel{"header"}, "CTF", "HEADER", 0, Lifetime::Timeframe); for (auto id = DetID::First; id <= DetID::Last; id++) { - if (dets[id]) { + if (inp.detMask[id]) { DetID det(id); outputs.emplace_back(OutputLabel{det.getName()}, det.getDataOrigin(), "CTFDATA", 0, Lifetime::Timeframe); } @@ -201,7 +363,7 @@ DataProcessorSpec getCTFReaderSpec(DetID::mask_t dets, const std::string& inp) "ctf-reader", Inputs{}, outputs, - AlgorithmSpec{adaptFromTask<CTFReaderSpec>(dets, inp)}, + AlgorithmSpec{adaptFromTask<CTFReaderSpec>(inp)}, Options{}}; } diff --git a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx index 66ae942fa2601..aeae3df611d3e 100644 --- a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,24 +11,48 @@ /// @file CTFWriterSpec.cxx -#include <vector> -#include <TFile.h> -#include <TTree.h> -#include <TSystem.h> - #include "Framework/Logger.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/InputSpec.h" +#include "Framework/RawDeviceService.h" +#include "Framework/CommonServices.h" +#include <FairMQDevice.h> + #include "CTFWorkflow/CTFWriterSpec.h" +#include "DetectorsCommonDataFormats/CTFHeader.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/EncodedBlocks.h" +#include "DetectorsCommonDataFormats/FileMetaData.h" +#include "CommonUtils/StringUtils.h" #include "DataFormatsITSMFT/CTF.h" #include "DataFormatsTPC/CTF.h" +#include "DataFormatsTRD/CTF.h" +#include "DataFormatsHMP/CTF.h" #include "DataFormatsFT0/CTF.h" #include "DataFormatsFV0/CTF.h" #include "DataFormatsFDD/CTF.h" #include "DataFormatsTOF/CTF.h" #include "DataFormatsMID/CTF.h" +#include "DataFormatsMCH/CTF.h" #include "DataFormatsEMCAL/CTF.h" +#include "DataFormatsPHOS/CTF.h" +#include "DataFormatsCPV/CTF.h" +#include "DataFormatsZDC/CTF.h" +#include "DataFormatsCTP/CTF.h" +#include "rANS/rans.h" +#include <vector> +#include <array> +#include <TStopwatch.h> +#include <vector> +#include <TFile.h> +#include <TTree.h> +#include <filesystem> +#include <ctime> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <regex> using namespace o2::framework; @@ -37,8 +62,9 @@ namespace ctf { template <typename T> -void appendToTree(TTree& tree, const std::string brname, T& ptr) +size_t appendToTree(TTree& tree, const std::string brname, T& ptr) { + size_t s = 0; auto* br = tree.GetBranch(brname.c_str()); auto* pptr = &ptr; if (br) { @@ -46,23 +72,169 @@ void appendToTree(TTree& tree, const std::string brname, T& ptr) } else { br = tree.Branch(brname.c_str(), &pptr); } - br->Fill(); + int res = br->Fill(); + if (res < 0) { + throw std::runtime_error(fmt::format("Failed to fill CTF branch {}", brname)); + } + s += res; br->ResetAddress(); + return s; } -CTFWriterSpec::CTFWriterSpec(DetID::mask_t dm, uint64_t r, bool doCTF, bool doDict, bool dictPerDet) - : mDets(dm), mRun(r), mWriteCTF(doCTF), mCreateDict(doDict), mDictPerDetector(dictPerDet) +using DetID = o2::detectors::DetID; +using FTrans = o2::rans::FrequencyTable; + +class CTFWriterSpec : public o2::framework::Task +{ + public: + CTFWriterSpec() = delete; + CTFWriterSpec(DetID::mask_t dm, uint64_t r, const std::string& outType); + ~CTFWriterSpec() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + bool isPresent(DetID id) const { return mDets[id]; } + + private: + template <typename C> + size_t processDet(o2::framework::ProcessingContext& pc, DetID det, CTFHeader& header, TTree* tree); + template <typename C> + void storeDictionary(DetID det, CTFHeader& header); + void storeDictionaries(); + void prepareDictionaryTreeAndFile(DetID det); + void closeDictionaryTreeAndFile(CTFHeader& header); + std::string dictionaryFileName(const std::string& detName = ""); + void closeTFTreeAndFile(); + void prepareTFTreeAndFile(const o2::header::DataHeader* dh); + size_t estimateCTFSize(ProcessingContext& pc); + size_t getAvailableDiskSpace(const std::string& path, int level); + void createLockFile(const o2::header::DataHeader* dh, int level); + void removeLockFile(); + + DetID::mask_t mDets; // detectors + bool mWriteCTF = true; + bool mCreateDict = false; + bool mDictPerDetector = false; + bool mCreateRunEnvDir = true; + bool mStoreMetaFile = false; + int mSaveDictAfter = 0; // if positive and mWriteCTF==true, save dictionary after each mSaveDictAfter TFs processed + uint64_t mRun = 0; + size_t mMinSize = 0; // if > 0, accumulate CTFs in the same tree until the total size exceeds this minimum + size_t mMaxSize = 0; // if > MinSize, and accumulated size will exceed this value, stop accumulation (even if mMinSize is not reached) + size_t mChkSize = 0; // if > 0 and fallback storage provided, reserve this size per CTF file in production on primary storage + size_t mAccCTFSize = 0; // so far accumulated size (if any) + size_t mCurrCTFSize = 0; // size of currently processed CTF + size_t mNCTF = 0; // total number of CTFs written + size_t mNAccCTF = 0; // total number of CTFs accumulated in the current file + size_t mCTFAutoSave = 0; // if > 0, autosave after so many TFs + size_t mNCTFFiles = 0; // total number of CTF files written + int mMaxCTFPerFile = 0; // max CTFs per files to store + std::vector<uint32_t> mTFOrbits{}; // 1st orbits of TF accumulated in current file + + std::string mOutputType{}; // RS FIXME once global/local options clash is solved, --output-type will become device option + std::string mLHCPeriod{}; + std::string mEnvironmentID{}; // partition env. id + std::string mDictDir{}; + std::string mCTFDir{}; + std::string mCTFDirFallBack = "/dev/null"; + std::string mCTFMetaFileDir = "/dev/null"; + std::string mCurrentCTFFileName{}; + const std::string LOCKFileDir = "/tmp/ctf-writer-locks"; + std::string mLockFileName{}; + int mLockFD = -1; + std::unique_ptr<TFile> mCTFFileOut; + std::unique_ptr<TTree> mCTFTreeOut; + std::unique_ptr<o2::dataformats::FileMetaData> mCTFFileMetaData; + + std::unique_ptr<TFile> mDictFileOut; // file to store dictionary + std::unique_ptr<TTree> mDictTreeOut; // tree to store dictionary + + // For the external dictionary creation we accumulate for each detector the frequency tables of its each block + // After accumulation over multiple TFs we store the dictionaries data in the standard CTF format of this detector, + // i.e. EncodedBlock stored in a tree, BUT with dictionary data only added to each block. + // The metadata of the block (min,max) will be used for the consistency check at the decoding + std::array<std::vector<FTrans>, DetID::nDetectors> mFreqsAccumulation; + std::array<std::vector<o2::ctf::Metadata>, DetID::nDetectors> mFreqsMetaData; + std::array<std::shared_ptr<void>, DetID::nDetectors> mHeaders; + TStopwatch mTimer; + + static const std::string TMPFileEnding; +}; + +const std::string CTFWriterSpec::TMPFileEnding{".part"}; + +//___________________________________________________________________ +CTFWriterSpec::CTFWriterSpec(DetID::mask_t dm, uint64_t r, const std::string& outType) + : mDets(dm), mRun(r), mOutputType(outType) { mTimer.Stop(); mTimer.Reset(); +} + +//___________________________________________________________________ +void CTFWriterSpec::init(InitContext& ic) +{ + mDictPerDetector = ic.options().get<bool>("dict-per-det"); + // auto outmode = ic.options().get<std::string>("output-type"); // RS FIXME once global/local options clash is solved, --output-type will become device option + auto outmode = mOutputType; + if (outmode == "ctf") { + mWriteCTF = true; + mCreateDict = false; + } else if (outmode == "dict") { + mWriteCTF = false; + mCreateDict = true; + } else if (outmode == "both") { + mWriteCTF = true; + mCreateDict = true; + } else if (outmode == "none") { + mWriteCTF = false; + mCreateDict = false; + } else { + throw std::invalid_argument("Invalid output-type"); + } - if (doDict) { // make sure that there is no local dictonary + mSaveDictAfter = ic.options().get<int>("save-dict-after"); + mCTFAutoSave = ic.options().get<int>("save-ctf-after"); + mDictDir = o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("ctf-dict-dir")); + mCTFDir = o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("output-dir")); + mCTFDirFallBack = ic.options().get<std::string>("output-dir-alt"); + if (mCTFDirFallBack != "/dev/null") { + mCTFDirFallBack = o2::utils::Str::rectifyDirectory(mCTFDirFallBack); + } + mCTFMetaFileDir = ic.options().get<std::string>("meta-output-dir"); + if (mCTFMetaFileDir != "/dev/null") { + mCTFMetaFileDir = o2::utils::Str::rectifyDirectory(mCTFMetaFileDir); + mStoreMetaFile = true; + } + mCreateRunEnvDir = !ic.options().get<bool>("ignore-partition-run-dir"); + mMinSize = ic.options().get<int64_t>("min-file-size"); + mMaxSize = ic.options().get<int64_t>("max-file-size"); + mMaxCTFPerFile = ic.options().get<int>("max-ctf-per-file"); + if (mWriteCTF) { + if (mMinSize > 0) { + LOG(INFO) << "Multiple CTFs will be accumulated in the tree/file until its size exceeds " << mMinSize << " bytes"; + if (mMaxSize > mMinSize) { + LOG(INFO) << "but does not exceed " << mMaxSize << " bytes"; + } + } + } + mChkSize = std::max(size_t(mMinSize * 1.1), mMaxSize); + if (!std::filesystem::exists(LOCKFileDir)) { + if (!std::filesystem::create_directories(LOCKFileDir)) { + usleep(10); // protection in case the directory was created by other process at the time of query + if (std::filesystem::exists(LOCKFileDir)) { + throw std::runtime_error(fmt::format("Failed to create {} directory", LOCKFileDir)); + } + } + } + + if (mCreateDict) { // make sure that there is no local dictonary for (int id = 0; id < DetID::nDetectors; id++) { DetID det(id); if (isPresent(det)) { auto dictName = dictionaryFileName(det.getName()); - if (gSystem->AccessPathName(dictName.c_str()) == 0) { - throw std::runtime_error(o2::utils::concat_string("CTF dictionary creation is requested but ", dictName, " already exists, remove it!")); + if (std::filesystem::exists(dictName)) { + throw std::runtime_error(o2::utils::Str::concat_string("CTF dictionary creation is requested but ", dictName, " already exists, remove it!")); } if (!mDictPerDetector) { break; // no point in checking further @@ -72,68 +244,302 @@ CTFWriterSpec::CTFWriterSpec(DetID::mask_t dm, uint64_t r, bool doCTF, bool doDi } } -void CTFWriterSpec::init(InitContext& ic) +//___________________________________________________________________ +// process data of particular detector +template <typename C> +size_t CTFWriterSpec::processDet(o2::framework::ProcessingContext& pc, DetID det, CTFHeader& header, TTree* tree) { - mSaveDictAfter = ic.options().get<int>("save-dict-after"); + size_t sz = 0; + if (!isPresent(det) || !pc.inputs().isValid(det.getName())) { + return sz; + } + auto ctfBuffer = pc.inputs().get<gsl::span<o2::ctf::BufferType>>(det.getName()); + const auto ctfImage = C::getImage(ctfBuffer.data()); + ctfImage.print(o2::utils::Str::concat_string(det.getName(), ": ")); + if (mWriteCTF) { + sz += ctfImage.appendToTree(*tree, det.getName()); + header.detectors.set(det); + } + if (mCreateDict) { + if (!mFreqsAccumulation[det].size()) { + mFreqsAccumulation[det].resize(C::getNBlocks()); + mFreqsMetaData[det].resize(C::getNBlocks()); + } + if (!mHeaders[det]) { // store 1st header + mHeaders[det] = ctfImage.cloneHeader(); + auto& hb = *static_cast<o2::ctf::CTFDictHeader*>(mHeaders[det].get()); + hb.dictTimeStamp = uint32_t(std::time(nullptr)); + } + for (int ib = 0; ib < C::getNBlocks(); ib++) { + const auto& bl = ctfImage.getBlock(ib); + if (bl.getNDict()) { + auto& freq = mFreqsAccumulation[det][ib]; + auto& mdSave = mFreqsMetaData[det][ib]; + const auto& md = ctfImage.getMetadata(ib); + freq.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + mdSave = o2::ctf::Metadata{0, 0, md.coderType, md.streamSize, md.probabilityBits, md.opt, freq.getMinSymbol(), freq.getMaxSymbol(), (int)freq.size(), 0, 0}; + } + } + } + return sz; +} + +//___________________________________________________________________ +// store dictionary of a particular detector +template <typename C> +void CTFWriterSpec::storeDictionary(DetID det, CTFHeader& header) +{ + if (!isPresent(det) || !mFreqsAccumulation[det].size()) { + return; + } + prepareDictionaryTreeAndFile(det); + // create vector whose data contains dictionary in CTF format (EncodedBlock) + auto dictBlocks = C::createDictionaryBlocks(mFreqsAccumulation[det], mFreqsMetaData[det]); + auto& h = C::get(dictBlocks.data())->getHeader(); + h = *reinterpret_cast<typename std::remove_reference<decltype(h)>::type*>(mHeaders[det].get()); + auto& hb = static_cast<o2::ctf::CTFDictHeader&>(h); + hb = *static_cast<const o2::ctf::CTFDictHeader*>(mHeaders[det].get()); + + C::get(dictBlocks.data())->print(o2::utils::Str::concat_string("Storing dictionary for ", det.getName(), ": ")); + C::get(dictBlocks.data())->appendToTree(*mDictTreeOut.get(), det.getName()); // cast to EncodedBlock + // mFreqsAccumulation[det].clear(); + // mFreqsMetaData[det].clear(); + if (mDictPerDetector) { + header.detectors.reset(); + } + header.detectors.set(det); + if (mDictPerDetector) { + closeDictionaryTreeAndFile(header); + } +} + +//___________________________________________________________________ +size_t CTFWriterSpec::estimateCTFSize(ProcessingContext& pc) +{ + size_t s = 0; + for (auto id = DetID::First; id <= DetID::Last; id++) { + DetID det(id); + if (!isPresent(det) || !pc.inputs().isValid(det.getName())) { + continue; + } + s += pc.inputs().get<gsl::span<o2::ctf::BufferType>>(det.getName()).size(); + } + return s; } +//___________________________________________________________________ void CTFWriterSpec::run(ProcessingContext& pc) { + const std::string NAStr = "NA"; auto cput = mTimer.CpuTime(); mTimer.Start(false); - auto tfOrb = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getByPos(0))->firstTForbit; - std::unique_ptr<TFile> fileOut; - std::unique_ptr<TTree> treeOut; + const auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + auto oldRun = mRun; + if (dh->runNumber != 0) { + mRun = dh->runNumber; + } + // check runNumber with FMQ property, if set, override DH number + { + auto runNStr = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("runNumber", NAStr); + if (runNStr != NAStr) { + size_t nc = 0; + auto runNProp = std::stol(runNStr, &nc); + if (nc != runNStr.size()) { + LOGP(ERROR, "Property runNumber={} is provided but is not a number, ignoring", runNStr); + } else { + mRun = runNProp; + } + } + } + auto oldEnv = mEnvironmentID; + { + auto envN = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("environment_id", NAStr); + if (envN != NAStr) { + mEnvironmentID = envN; + } + } + if ((oldRun != 0 && oldRun != mRun) || (!oldEnv.empty() && oldEnv != mEnvironmentID)) { + LOGP(WARNING, "RunNumber/Environment changed from {}/{} to {}/{}", oldRun, oldEnv, mRun, mEnvironmentID); + closeTFTreeAndFile(); + } + // check for the LHCPeriod + if (mLHCPeriod.empty()) { + auto LHCPeriodStr = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("LHCPeriod", NAStr); + if (LHCPeriodStr != NAStr) { + mLHCPeriod = LHCPeriodStr; + } else { + const char* months[12] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + time_t now = time(nullptr); + auto ltm = gmtime(&now); + mLHCPeriod = months[ltm->tm_mon]; + LOG(WARNING) << "LHCPeriod is not available, using current month " << mLHCPeriod; + } + } + + mCurrCTFSize = estimateCTFSize(pc); if (mWriteCTF) { - // fileOut.reset(TFile::Open(o2::base::NameConf::getCTFFileName(tfOrb).c_str(), "recreate")); - // RS Until the DPL will propagate the firstTForbit, we will use simple counter in CTF file name to avoid overwriting in case of multiple TFs - fileOut.reset(TFile::Open(o2::base::NameConf::getCTFFileName(mNTF).c_str(), "recreate")); - treeOut = std::make_unique<TTree>(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + prepareTFTreeAndFile(dh); } // create header - CTFHeader header{mRun, tfOrb}; - - processDet<o2::itsmft::CTF>(pc, DetID::ITS, header, treeOut.get()); - processDet<o2::itsmft::CTF>(pc, DetID::MFT, header, treeOut.get()); - processDet<o2::tpc::CTF>(pc, DetID::TPC, header, treeOut.get()); - processDet<o2::tof::CTF>(pc, DetID::TOF, header, treeOut.get()); - processDet<o2::ft0::CTF>(pc, DetID::FT0, header, treeOut.get()); - processDet<o2::fv0::CTF>(pc, DetID::FV0, header, treeOut.get()); - processDet<o2::fdd::CTF>(pc, DetID::FDD, header, treeOut.get()); - processDet<o2::mid::CTF>(pc, DetID::MID, header, treeOut.get()); - processDet<o2::emcal::CTF>(pc, DetID::EMC, header, treeOut.get()); + CTFHeader header{mRun, dh->firstTForbit}; + size_t szCTF = 0; + szCTF += processDet<o2::itsmft::CTF>(pc, DetID::ITS, header, mCTFTreeOut.get()); + szCTF += processDet<o2::itsmft::CTF>(pc, DetID::MFT, header, mCTFTreeOut.get()); + szCTF += processDet<o2::tpc::CTF>(pc, DetID::TPC, header, mCTFTreeOut.get()); + szCTF += processDet<o2::trd::CTF>(pc, DetID::TRD, header, mCTFTreeOut.get()); + szCTF += processDet<o2::tof::CTF>(pc, DetID::TOF, header, mCTFTreeOut.get()); + szCTF += processDet<o2::ft0::CTF>(pc, DetID::FT0, header, mCTFTreeOut.get()); + szCTF += processDet<o2::fv0::CTF>(pc, DetID::FV0, header, mCTFTreeOut.get()); + szCTF += processDet<o2::fdd::CTF>(pc, DetID::FDD, header, mCTFTreeOut.get()); + szCTF += processDet<o2::mid::CTF>(pc, DetID::MID, header, mCTFTreeOut.get()); + szCTF += processDet<o2::mch::CTF>(pc, DetID::MCH, header, mCTFTreeOut.get()); + szCTF += processDet<o2::emcal::CTF>(pc, DetID::EMC, header, mCTFTreeOut.get()); + szCTF += processDet<o2::phos::CTF>(pc, DetID::PHS, header, mCTFTreeOut.get()); + szCTF += processDet<o2::cpv::CTF>(pc, DetID::CPV, header, mCTFTreeOut.get()); + szCTF += processDet<o2::zdc::CTF>(pc, DetID::ZDC, header, mCTFTreeOut.get()); + szCTF += processDet<o2::hmpid::CTF>(pc, DetID::HMP, header, mCTFTreeOut.get()); + szCTF += processDet<o2::ctp::CTF>(pc, DetID::CTP, header, mCTFTreeOut.get()); mTimer.Stop(); if (mWriteCTF) { - appendToTree(*treeOut.get(), "CTFHeader", header); - treeOut->SetEntries(1); - treeOut->Write(); - treeOut.reset(); - fileOut->Close(); - LOG(INFO) << "TF#" << mNTF << ": wrote " << fileOut->GetName() << " with CTF{" << header << "} in " << mTimer.CpuTime() - cput << " s"; + szCTF += appendToTree(*mCTFTreeOut.get(), "CTFHeader", header); + mAccCTFSize += szCTF; + mCTFTreeOut->SetEntries(++mNAccCTF); + mTFOrbits.push_back(dh->firstTForbit); + LOG(INFO) << "TF#" << mNCTF << ": wrote CTF{" << header << "} of size " << szCTF << " to " << mCurrentCTFFileName << " in " << mTimer.CpuTime() - cput << " s"; + if (mNAccCTF > 1) { + LOG(INFO) << "Current CTF tree has " << mNAccCTF << " entries with total size of " << mAccCTFSize << " bytes"; + } + if (mLockFD) { + lseek(mLockFD, 0, SEEK_SET); + write(mLockFD, &mAccCTFSize, sizeof(size_t)); + } + + if (mAccCTFSize >= mMinSize || (mMaxCTFPerFile > 0 && mNAccCTF >= mMaxCTFPerFile)) { + closeTFTreeAndFile(); + } else if (mCTFAutoSave > 0 && mNAccCTF % mCTFAutoSave == 0) { + mCTFTreeOut->AutoSave("override"); + } } else { - LOG(INFO) << "TF#" << mNTF << " CTF writing is disabled"; + LOG(INFO) << "TF#" << mNCTF << " CTF writing is disabled, size was " << szCTF << " bytes"; } - mNTF++; - if (mCreateDict && mSaveDictAfter > 0 && (mNTF % mSaveDictAfter) == 0) { + + mNCTF++; + if (mCreateDict && mSaveDictAfter > 0 && (mNCTF % mSaveDictAfter) == 0) { storeDictionaries(); } } +//___________________________________________________________________ void CTFWriterSpec::endOfStream(EndOfStreamContext& ec) { if (mCreateDict) { storeDictionaries(); } - + if (mWriteCTF) { + closeTFTreeAndFile(); + } LOGF(INFO, "CTF writing total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } +//___________________________________________________________________ +void CTFWriterSpec::prepareTFTreeAndFile(const o2::header::DataHeader* dh) +{ + if (!mWriteCTF) { + return; + } + bool needToOpen = false; + if (!mCTFTreeOut) { + needToOpen = true; + } else { + if ((mAccCTFSize >= mMinSize) || // min size exceeded, may close the file. + (mAccCTFSize && mMaxSize > mMinSize && ((mAccCTFSize + mCurrCTFSize) > mMaxSize))) { // this is not the 1st CTF in the file and the new size will exceed allowed max + needToOpen = true; + } else { + LOGP(INFO, "Will add new CTF of estimated size {} to existing file of size {}", mCurrCTFSize, mAccCTFSize); + } + } + if (needToOpen) { + closeTFTreeAndFile(); + auto fname = o2::base::NameConf::getCTFFileName(mRun, dh->firstTForbit, dh->tfCounter); + auto ctfDir = mCTFDir; + if (mChkSize > 0 && (mCTFDirFallBack != "/dev/null")) { + createLockFile(dh, 0); + auto sz = getAvailableDiskSpace(ctfDir, 0); // check main storage + if (sz < mChkSize) { + removeLockFile(); + LOG(WARNING) << "Primary CTF output device has available size " << sz << " while " << mChkSize << " is requested: will write on secondary one"; + ctfDir = mCTFDirFallBack; + } + } + if (mCreateRunEnvDir && !mEnvironmentID.empty()) { + ctfDir += fmt::format("{}_{}/", mEnvironmentID, mRun); + if (!std::filesystem::exists(ctfDir)) { + if (!std::filesystem::create_directories(ctfDir)) { + throw std::runtime_error(fmt::format("Failed to create {} directory", ctfDir)); + } else { + LOG(INFO) << "Created {} directory for CTFs output" << ctfDir; + } + } + } + mCurrentCTFFileName = o2::utils::Str::concat_string(ctfDir, o2::base::NameConf::getCTFFileName(mRun, dh->firstTForbit, dh->tfCounter)); + mCTFFileOut.reset(TFile::Open(o2::utils::Str::concat_string(mCurrentCTFFileName, TMPFileEnding).c_str(), "recreate")); // to prevent premature external usage, use temporary name + mCTFTreeOut = std::make_unique<TTree>(std::string(o2::base::NameConf::CTFTREENAME).c_str(), "O2 CTF tree"); + if (mStoreMetaFile) { + mCTFFileMetaData = std::make_unique<o2::dataformats::FileMetaData>(); + } + + mNCTFFiles++; + } +} + +//___________________________________________________________________ +void CTFWriterSpec::closeTFTreeAndFile() +{ + if (mCTFTreeOut) { + mCTFFileOut->cd(); + mCTFTreeOut->Write(); + mCTFTreeOut.reset(); + mCTFFileOut->Close(); + mCTFFileOut.reset(); + if (!TMPFileEnding.empty()) { + std::filesystem::rename(o2::utils::Str::concat_string(mCurrentCTFFileName, TMPFileEnding), mCurrentCTFFileName); + } + // write CTF file metaFile data + if (mStoreMetaFile) { + mCTFFileMetaData->fillFileData(mCurrentCTFFileName); + mCTFFileMetaData->run = mRun; + mCTFFileMetaData->LHCPeriod = mLHCPeriod; + mCTFFileMetaData->type = "raw"; + mCTFFileMetaData->priority = "high"; + auto metaFileName = fmt::format("{}{}.done", mCTFMetaFileDir, mCurrentCTFFileName); + try { + std::ofstream metaFileOut(metaFileName); + metaFileOut << *mCTFFileMetaData.get(); + metaFileOut << "TFOrbits: "; + for (size_t i = 0; i < mTFOrbits.size(); i++) { + metaFileOut << fmt::format("{}{}", i ? ", " : "", mTFOrbits[i]); + } + metaFileOut << '\n'; + metaFileOut.close(); + } catch (std::exception const& e) { + LOG(ERROR) << "Failed to store CTF meta data file " << metaFileName << ", reason: " << e.what(); + } + mCTFFileMetaData.reset(); + } + mTFOrbits.clear(); + mNAccCTF = 0; + mAccCTFSize = 0; + removeLockFile(); + } +} + +//___________________________________________________________________ void CTFWriterSpec::prepareDictionaryTreeAndFile(DetID det) { if (mDictPerDetector) { @@ -150,40 +556,52 @@ void CTFWriterSpec::prepareDictionaryTreeAndFile(DetID det) } } +//___________________________________________________________________ std::string CTFWriterSpec::dictionaryFileName(const std::string& detName) { if (mDictPerDetector) { if (detName.empty()) { throw std::runtime_error("Per-detector dictionary files are requested but detector name is not provided"); } - return o2::utils::concat_string(detName, "_", o2::base::NameConf::CTFDICT, ".root"); + return o2::utils::Str::concat_string(mDictDir, detName, '_', o2::base::NameConf::CTFDICT, ".root"); } else { - return o2::utils::concat_string(o2::base::NameConf::CTFDICT, ".root"); + return o2::utils::Str::concat_string(mDictDir, o2::base::NameConf::CTFDICT, ".root"); } } +//___________________________________________________________________ void CTFWriterSpec::storeDictionaries() { - CTFHeader header{mRun, uint32_t(mNTF)}; + CTFHeader header{mRun, uint32_t(mNCTF)}; storeDictionary<o2::itsmft::CTF>(DetID::ITS, header); storeDictionary<o2::itsmft::CTF>(DetID::MFT, header); storeDictionary<o2::tpc::CTF>(DetID::TPC, header); + storeDictionary<o2::trd::CTF>(DetID::TRD, header); storeDictionary<o2::tof::CTF>(DetID::TOF, header); storeDictionary<o2::ft0::CTF>(DetID::FT0, header); storeDictionary<o2::fv0::CTF>(DetID::FV0, header); storeDictionary<o2::fdd::CTF>(DetID::FDD, header); storeDictionary<o2::mid::CTF>(DetID::MID, header); + storeDictionary<o2::mch::CTF>(DetID::MCH, header); storeDictionary<o2::emcal::CTF>(DetID::EMC, header); + storeDictionary<o2::phos::CTF>(DetID::PHS, header); + storeDictionary<o2::cpv::CTF>(DetID::CPV, header); + storeDictionary<o2::zdc::CTF>(DetID::ZDC, header); + storeDictionary<o2::hmpid::CTF>(DetID::HMP, header); + storeDictionary<o2::ctp::CTF>(DetID::CTP, header); + // close remnants if (mDictTreeOut) { closeDictionaryTreeAndFile(header); } - LOG(INFO) << "Saved CTF dictionary after " << mNTF << " TFs processed"; + LOG(INFO) << "Saved CTF dictionary after " << mNCTF << " TFs processed"; } +//___________________________________________________________________ void CTFWriterSpec::closeDictionaryTreeAndFile(CTFHeader& header) { if (mDictTreeOut) { + mDictFileOut->cd(); appendToTree(*mDictTreeOut.get(), "CTFHeader", header); mDictTreeOut->SetEntries(1); mDictTreeOut->Write(mDictTreeOut->GetName(), TObject::kSingleKey); @@ -192,22 +610,115 @@ void CTFWriterSpec::closeDictionaryTreeAndFile(CTFHeader& header) } } -DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, uint64_t run, bool doCTF, bool doDict, bool dictPerDet) +//___________________________________________________________________ +void CTFWriterSpec::createLockFile(const o2::header::DataHeader* dh, int level) +{ + // create lock file for the CTF to be written to the storage of given level + while (1) { + mLockFileName = fmt::format("{}/ctfs{}-{}_{}_{}_{}.lock", LOCKFileDir, level, o2::utils::Str::getRandomString(8), mRun, dh->firstTForbit, dh->tfCounter); + if (!std::filesystem::exists(mLockFileName)) { + break; + } + } + mLockFD = open(mLockFileName.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (mLockFD == -1) { + throw std::runtime_error(fmt::format("Error opening lock file {}", mLockFileName)); + } + if (lockf(mLockFD, F_LOCK, 0)) { + throw std::runtime_error(fmt::format("Error locking file {}", mLockFileName)); + } +} + +//___________________________________________________________________ +void CTFWriterSpec::removeLockFile() +{ + // remove CTF lock file + if (mLockFD != -1) { + if (lockf(mLockFD, F_ULOCK, 0)) { + throw std::runtime_error(fmt::format("Error unlocking file {}", mLockFileName)); + } + mLockFD = -1; + std::error_code ec; + std::filesystem::remove(mLockFileName, ec); // use non-throwing version + } +} + +//___________________________________________________________________ +size_t CTFWriterSpec::getAvailableDiskSpace(const std::string& path, int level) +{ + // count number of CTF files in processing (written to storage at given level) from their lock files + std::regex pat{fmt::format("({}/ctfs{}-[[:alnum:]_]+\\.lock$)", LOCKFileDir, level)}; + int nLocked = 0; + size_t written = 0; + std::error_code ec; + for (const auto& entry : std::filesystem::directory_iterator(LOCKFileDir)) { + const auto& entryName = entry.path().native(); + if (std::regex_search(entryName, pat) && (mLockFD < 0 || entryName != mLockFileName)) { + int fdt = open(entryName.c_str(), O_RDONLY); + if (fdt != -1) { + bool locked = lockf(fdt, F_TEST, 0) != 0; + if (locked) { + nLocked++; + size_t sz = 0; + auto nrd = read(fdt, &sz, sizeof(size_t)); + if (nrd == sizeof(size_t)) { + written += sz; + } + } + close(fdt); + // unlocked file is either leftover from crached job or a file from concurent job which was being locked + // or just unlocked but not yet removed. In the former case remove it + if (!locked) { + struct stat statbuf; + if (stat(entryName.c_str(), &statbuf) != -1) { // if we fail to stat, the file was already removed +#ifdef __APPLE__ + auto ftime = statbuf.st_mtimespec.tv_sec; // last write time +#else + auto ftime = statbuf.st_mtim.tv_sec; // last write time +#endif + auto ctime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + if (ftime + 60 < ctime) { // this is an old file, remove it + std::filesystem::remove(entryName, ec); // use non-throwing version + } + } + } + } + } + } + const auto si = std::filesystem::space(path, ec); + int64_t avail = int64_t(si.available) - nLocked * mChkSize + written; // account already written part of unfinished files + LOGP(DEBUG, "{} CTF files open (curr.size: {}) -> can use {} of {} bytes", nLocked, written, avail, si.available); + return avail > 0 ? avail : 0; +} + +//___________________________________________________________________ +DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, uint64_t run, const std::string& outType) { std::vector<InputSpec> inputs; - LOG(INFO) << "Detectors list:"; + LOG(DEBUG) << "Detectors list:"; for (auto id = DetID::First; id <= DetID::Last; id++) { if (dets[id]) { inputs.emplace_back(DetID::getName(id), DetID::getDataOrigin(id), "CTFDATA", 0, Lifetime::Timeframe); - LOG(INFO) << "Det " << DetID::getName(id) << " added"; + LOG(DEBUG) << "Det " << DetID::getName(id) << " added"; } } return DataProcessorSpec{ "ctf-writer", inputs, Outputs{}, - AlgorithmSpec{adaptFromTask<CTFWriterSpec>(dets, run, doCTF, doDict, dictPerDet)}, - Options{{"save-dict-after", VariantType::Int, -1, {"In dictionary generation mode save it dictionary after certain number of TFs processed"}}}}; + AlgorithmSpec{adaptFromTask<CTFWriterSpec>(dets, run, outType)}, // RS FIXME once global/local options clash is solved, --output-type will become device option + Options{ //{"output-type", VariantType::String, "ctf", {"output types: ctf (per TF) or dict (create dictionaries) or both or none"}}, + {"save-ctf-after", VariantType::Int, 0, {"if > 0, autosave CTF tree with multiple CTFs after every N CTFs"}}, + {"save-dict-after", VariantType::Int, 0, {"if > 0, in dictionary generation mode save it dictionary after certain number of TFs processed"}}, + {"ctf-dict-dir", VariantType::String, "none", {"CTF dictionary directory, must exist"}}, + {"dict-per-det", VariantType::Bool, false, {"create dictionary file per detector"}}, + {"output-dir", VariantType::String, "none", {"CTF output directory, must exist"}}, + {"output-dir-alt", VariantType::String, "/dev/null", {"Alternative CTF output directory, must exist (if not /dev/null)"}}, + {"meta-output-dir", VariantType::String, "/dev/null", {"CTF metadata output directory, must exist (if not /dev/null)"}}, + {"min-file-size", VariantType::Int64, 0l, {"accumulate CTFs until given file size reached"}}, + {"max-file-size", VariantType::Int64, 0l, {"if > 0, try to avoid exceeding given file size, also used for space check"}}, + {"max-ctf-per-file", VariantType::Int, 0, {"if > 0, avoid storing more than requested CTFs per file"}}, + {"ignore-partition-run-dir", VariantType::Bool, false, {"Do not creare partition-run directory in output-dir"}}}}; } } // namespace ctf diff --git a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx index 38d0f730dd141..59bc7fe6de1f5 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,16 +19,24 @@ #include "CTFWorkflow/CTFReaderSpec.h" #include "DataFormatsParameters/GRPObject.h" #include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/ConfigurableParam.h" // Specific detectors specs #include "ITSMFTWorkflow/EntropyDecoderSpec.h" #include "TPCWorkflow/EntropyDecoderSpec.h" +#include "TRDWorkflow/EntropyDecoderSpec.h" +#include "HMPIDWorkflow/EntropyDecoderSpec.h" #include "FT0Workflow/EntropyDecoderSpec.h" #include "FV0Workflow/EntropyDecoderSpec.h" #include "FDDWorkflow/EntropyDecoderSpec.h" #include "TOFWorkflowUtils/EntropyDecoderSpec.h" #include "MIDWorkflow/EntropyDecoderSpec.h" +#include "MCHWorkflow/EntropyDecoderSpec.h" #include "EMCALWorkflow/EntropyDecoderSpec.h" +#include "PHOSWorkflow/EntropyDecoderSpec.h" +#include "CPVWorkflow/EntropyDecoderSpec.h" +#include "ZDCWorkflow/EntropyDecoderSpec.h" +#include "CTPWorkflow/EntropyDecoderSpec.h" using namespace o2::framework; using DetID = o2::detectors::DetID; @@ -37,9 +46,20 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters std::vector<o2::framework::ConfigParamSpec> options; - options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, std::string{DetID::NONE}, {"comma-separated list of detectors to accept. Overrides skipDet"}}); + options.push_back(ConfigParamSpec{"ctf-input", VariantType::String, "none", {"comma-separated list CTF input files"}}); + options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, std::string{DetID::ALL}, {"comma-separated list of detectors to accept. Overrides skipDet"}}); options.push_back(ConfigParamSpec{"skipDet", VariantType::String, std::string{DetID::NONE}, {"comma-separate list of detectors to skip"}}); - options.push_back(ConfigParamSpec{"ctf-input", VariantType::String, "", {"comma-separated list CTF input files"}}); + options.push_back(ConfigParamSpec{"max-tf", VariantType::Int, -1, {"max CTFs to process (<= 0 : infinite)"}}); + options.push_back(ConfigParamSpec{"loop", VariantType::Int, 0, {"loop N times (infinite for N<0)"}}); + options.push_back(ConfigParamSpec{"delay", VariantType::Float, 0.f, {"delay in seconds between consecutive TFs sending"}}); + options.push_back(ConfigParamSpec{"copy-cmd", VariantType::String, "XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst", {"copy command for remote files or no-copy to avoid copying"}}); + options.push_back(ConfigParamSpec{"ctf-file-regex", VariantType::String, ".*o2_ctf_run.+\\.root$", {"regex string to identify CTF files"}}); + options.push_back(ConfigParamSpec{"remote-regex", VariantType::String, "^/eos/aliceo2/.+", {"regex string to identify remote files"}}); + options.push_back(ConfigParamSpec{"max-cached-files", VariantType::Int, 3, {"max CTF files queued (copied for remote source)"}}); + options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); + // + options.push_back(ConfigParamSpec{"its-digits", VariantType::Bool, false, {"convert ITS clusters to digits"}}); + options.push_back(ConfigParamSpec{"mft-digits", VariantType::Bool, false, {"convert MFT clusters to digits"}}); std::swap(workflowOptions, options); } @@ -49,53 +69,94 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { - DetID::mask_t dets; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + o2::ctf::CTFReaderInp ctfInput; + WorkflowSpec specs; - std::string inpNames; - if (!configcontext.helpOnCommandLine()) { - dets.set(); // by default read all - auto mskOnly = DetID::getMask(configcontext.options().get<std::string>("onlyDet")); - auto mskSkip = DetID::getMask(configcontext.options().get<std::string>("skipDet")); - if (mskOnly.any()) { - dets &= mskOnly; - } else { - dets ^= mskSkip; - } - if ((inpNames = configcontext.options().get<std::string>("ctf-input")).empty()) { + auto mskOnly = DetID::getMask(configcontext.options().get<std::string>("onlyDet")); + auto mskSkip = DetID::getMask(configcontext.options().get<std::string>("skipDet")); + if (mskOnly.any()) { + ctfInput.detMask &= mskOnly; + } else { + ctfInput.detMask ^= mskSkip; + } + ctfInput.inpdata = configcontext.options().get<std::string>("ctf-input"); + if (ctfInput.inpdata.empty() || ctfInput.inpdata == "none") { + if (!configcontext.helpOnCommandLine()) { throw std::runtime_error("--ctf-input <file,...> is not provided"); } + ctfInput.inpdata = ""; + } + + ctfInput.maxLoops = configcontext.options().get<int>("loop"); + if (ctfInput.maxLoops < 0) { + ctfInput.maxLoops = 0x7fffffff; + } + ctfInput.delay_us = int32_t(1e6 * configcontext.options().get<float>("delay")); // delay in microseconds + if (ctfInput.delay_us < 0) { + ctfInput.delay_us = 0; } + int n = configcontext.options().get<int>("max-tf"); + ctfInput.maxTFs = n > 0 ? n : 0x7fffffff; + + ctfInput.maxFileCache = std::max(1, configcontext.options().get<int>("max-cached-files")); + + ctfInput.copyCmd = configcontext.options().get<std::string>("copy-cmd"); + ctfInput.tffileRegex = configcontext.options().get<std::string>("ctf-file-regex"); + ctfInput.remoteRegex = configcontext.options().get<std::string>("remote-regex"); + + specs.push_back(o2::ctf::getCTFReaderSpec(ctfInput)); - specs.push_back(o2::ctf::getCTFReaderSpec(dets, inpNames)); // add decodors for all allowed detectors. - if (dets[DetID::ITS]) { - specs.push_back(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS))); + if (ctfInput.detMask[DetID::ITS]) { + specs.push_back(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS), configcontext.options().get<bool>("its-digits"))); } - if (dets[DetID::MFT]) { - specs.push_back(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT))); + if (ctfInput.detMask[DetID::MFT]) { + specs.push_back(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT), configcontext.options().get<bool>("mft-digits"))); } - if (dets[DetID::TPC]) { + if (ctfInput.detMask[DetID::TPC]) { specs.push_back(o2::tpc::getEntropyDecoderSpec()); } - if (dets[DetID::TOF]) { + if (ctfInput.detMask[DetID::TRD]) { + specs.push_back(o2::trd::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::TOF]) { specs.push_back(o2::tof::getEntropyDecoderSpec()); } - if (dets[DetID::FT0]) { + if (ctfInput.detMask[DetID::FT0]) { specs.push_back(o2::ft0::getEntropyDecoderSpec()); } - if (dets[DetID::FV0]) { + if (ctfInput.detMask[DetID::FV0]) { specs.push_back(o2::fv0::getEntropyDecoderSpec()); } - if (dets[DetID::FDD]) { + if (ctfInput.detMask[DetID::FDD]) { specs.push_back(o2::fdd::getEntropyDecoderSpec()); } - if (dets[DetID::MID]) { + if (ctfInput.detMask[DetID::MID]) { specs.push_back(o2::mid::getEntropyDecoderSpec()); } - if (dets[DetID::EMC]) { + if (ctfInput.detMask[DetID::MCH]) { + specs.push_back(o2::mch::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::EMC]) { specs.push_back(o2::emcal::getEntropyDecoderSpec()); } + if (ctfInput.detMask[DetID::PHS]) { + specs.push_back(o2::phos::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::CPV]) { + specs.push_back(o2::cpv::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::ZDC]) { + specs.push_back(o2::zdc::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::HMP]) { + specs.push_back(o2::hmpid::getEntropyDecoderSpec()); + } + if (ctfInput.detMask[DetID::CTP]) { + specs.push_back(o2::ctp::getEntropyDecoderSpec()); + } return std::move(specs); } diff --git a/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx b/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx index 4bac58ca64966..a5d2a5d6ca120 100644 --- a/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "CTFWorkflow/CTFWriterSpec.h" #include "DataFormatsParameters/GRPObject.h" #include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; using DetID = o2::detectors::DetID; @@ -30,7 +32,9 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, std::string{DetID::NONE}, {"comma separated list of detectors to accept. Overrides skipDet"}}); options.push_back(ConfigParamSpec{"skipDet", VariantType::String, std::string{DetID::NONE}, {"comma separate list of detectors to skip"}}); options.push_back(ConfigParamSpec{"grpfile", VariantType::String, o2::base::NameConf::getGRPFileName(), {"name of the grp file"}}); - options.push_back(ConfigParamSpec{"output-type", VariantType::String, "ctf", {"output types: ctf (per TF) or dict (create dictionaries)"}}); + options.push_back(ConfigParamSpec{"no-grp", VariantType::Bool, false, {"do not read GRP file"}}); + options.push_back(ConfigParamSpec{"output-type", VariantType::String, "ctf", {"output types: ctf (per TF) or dict (create dictionaries) or both or none"}}); + options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); std::swap(workflowOptions, options); } @@ -39,22 +43,35 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { - DetID::mask_t dets; + DetID::mask_t dets = 0; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); long run = 0; - bool doCTF = true, doDict = false; + bool doCTF = true, doDict = false, dictPerDet = false; + size_t szMin = 0, szMax = 0; + std::string outType{}; // RS FIXME once global/local options clash is solved, --output-type will become device option if (!configcontext.helpOnCommandLine()) { - std::unique_ptr<o2::parameters::GRPObject> grp(o2::parameters::GRPObject::loadFrom(configcontext.options().get<std::string>("grpfile"))); - dets = grp->getDetsReadOut(configcontext.options().get<std::string>("onlyDet"), configcontext.options().get<std::string>("skipDet")); - auto outmode = configcontext.options().get<std::string>("output-type"); - if (outmode == "ctf") { - doCTF = true; - doDict = false; - } else if (outmode == "dict") { - doCTF = false; - doDict = true; + bool noGRP = configcontext.options().get<bool>("no-grp"); + auto onlyDet = configcontext.options().get<std::string>("onlyDet"); + if (!noGRP) { + std::unique_ptr<o2::parameters::GRPObject> grp(o2::parameters::GRPObject::loadFrom(configcontext.options().get<std::string>("grpfile"))); + dets = grp->getDetsReadOut(onlyDet, configcontext.options().get<std::string>("skipDet")); + run = grp->getRun(); + } else { + dets.set(); // by default read all + auto mskOnly = DetID::getMask(configcontext.options().get<std::string>("onlyDet")); + auto mskSkip = DetID::getMask(configcontext.options().get<std::string>("skipDet")); + if (mskOnly.any()) { + dets &= mskOnly; + } else { + dets ^= mskSkip; + } + run = 0; } - run = grp->getRun(); + if (dets.none()) { + throw std::invalid_argument("Invalid workflow: no detectors found"); + } + outType = configcontext.options().get<std::string>("output-type"); } - WorkflowSpec specs{o2::ctf::getCTFWriterSpec(dets, run, doCTF, doDict)}; + WorkflowSpec specs{o2::ctf::getCTFWriterSpec(dets, run, outType)}; return std::move(specs); } diff --git a/Detectors/CTP/CMakeLists.txt b/Detectors/CTP/CMakeLists.txt new file mode 100644 index 0000000000000..1ef8d5ecf3b92 --- /dev/null +++ b/Detectors/CTP/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(simulation) +add_subdirectory(reconstruction) +add_subdirectory(workflow) +add_subdirectory(workflowIO) +add_subdirectory(macro) diff --git a/Detectors/CTP/macro/CMakeLists.txt b/Detectors/CTP/macro/CMakeLists.txt new file mode 100644 index 0000000000000..d3a5ec3d45fea --- /dev/null +++ b/Detectors/CTP/macro/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro(CreateCTPConfig.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::CCDB + LABELS ctp) +o2_add_test_root_macro(TestCTPScalers.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::CCDB + LABELS ctp) diff --git a/Detectors/CTP/macro/CreateCTPConfig.C b/Detectors/CTP/macro/CreateCTPConfig.C new file mode 100644 index 0000000000000..5abe052ddbf0b --- /dev/null +++ b/Detectors/CTP/macro/CreateCTPConfig.C @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CreateCTPConfig.C +/// \brief create CTP config, test it and add to database +/// \author Roman Lietava + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "FairLogger.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCTP/Configuration.h" +#include <string> +#include <map> +#include <iostream> +#endif +using namespace o2::ctp; +void CreateCTPConfig(long tmin = 0, long tmax = -1, std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + /// Demo configuration + CTPConfiguration ctpcfg; + std::string cfgstr = "PARTITION: TEST \n"; + cfgstr += "VERSION:0 \n"; + cfgstr += "INPUTS: \n"; + cfgstr += "MFV0MB FV0 M 0x1 \n"; + cfgstr += "MFV0MBInner FV0 M 0x2 \n"; + cfgstr += "MFV0MBOuter FV0 M 0x4 \n"; + cfgstr += "MFV0HM FV0 M 0x8 \n"; + cfgstr += "MFT0A FT0 M 0x10 \n"; + cfgstr += "MFT0B FT0 M 0x20 \n"; + cfgstr += "MFT0Vertex FT0 M 0x40 \n"; + cfgstr += "MFT0Cent FT0 M 0x80 \n"; + cfgstr += "MFT0SemiCent FT0 M 0x100 \n"; + cfgstr += "DESCRIPTORS: \n"; + cfgstr += "DV0MB MFV0MB \n"; + cfgstr += "DV0MBInner MFV0MBInner \n"; + cfgstr += "DV0MBOuter MFV0MBOuter \n"; + cfgstr += "DT0AND MFT0A MFT0B \n"; + cfgstr += "DT0A MFT0A \n"; + cfgstr += "DT0B MFT0B \n"; + cfgstr += "DINTV0T0 MFV0MB MFT0Vertex \n"; + cfgstr += "DINT4 MFV0MB MFT0A MFT0B \n"; + cfgstr += "DV0HM MFV0HM \n"; + cfgstr += "DT0HM MFT0Cent \n"; + cfgstr += "DHM MFV0HM MFT0Cent \n"; + cfgstr += "CLUSTERS: ALL\n"; + cfgstr += "ALL FV0 FT0 TPC \n"; + cfgstr += "CLASSES:\n"; + cfgstr += "CMBV0 0 DV0MB ALL \n"; + cfgstr += "CMBT0 1 DT0AND ALL \n"; + cfgstr += "CINT4 2 DINT4 ALL \n"; + cfgstr += "CINTV0T0 3 DINTV0T0 ALL \n"; + cfgstr += "CT0A 4 DT0A ALL \n"; + cfgstr += "CT0B 62 DT0B ALL \n"; + cfgstr += "CINTHM 63 DHM ALL \n"; + + ctpcfg.loadConfiguration(cfgstr); + ctpcfg.printStream(std::cout); + /// + /// add to database + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&ctpcfg, o2::ctp::CCDBPathCTPConfig, metadata, tmin, tmax); + std::cout << "CTP config in database" << std::endl; + /// get frp, database + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(ccdbHost); + auto ctpconfigdb = mgr.get<CTPConfiguration>(CCDBPathCTPConfig); + ctpconfigdb->printStream(std::cout); +} diff --git a/Detectors/CTP/macro/TestCTPScalers.C b/Detectors/CTP/macro/TestCTPScalers.C new file mode 100644 index 0000000000000..8591dcd1b5483 --- /dev/null +++ b/Detectors/CTP/macro/TestCTPScalers.C @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TestCTPScalers.C +/// \brief create CTP scalers, test it and add to database +/// \author Roman Lietava +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "FairLogger.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCTP/Scalers.h" +#include <string> +#include <map> +#include <iostream> +#endif +using namespace o2::ctp; +void TestCTPScalers(long tmin = 0, long tmax = -1, std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + /// Demo scalers + std::string scalersstr = "0\n"; // version + scalersstr += "333 5 0 2 8 32 63\n"; // runnumber nclasses [classes list]] + scalersstr += "4 3563 4 5 \n"; // orbit bc secs usecs + scalersstr += "0 0 0 0 0 0 \n"; // class 0 + scalersstr += "0 0 0 0 0 0 \n"; // class 2 + scalersstr += "0 0 0 0 0 0 \n"; // class 8 + scalersstr += "0 0 0 0 0 0 \n"; // class 32 + scalersstr += "0 0 0 0 0 0 \n"; // class 63 + scalersstr += "1000 3563 5 5\n"; // orbit bc secs usecs + scalersstr += "1 1 1 1 1 1 \n"; // class 0 + scalersstr += "1 1 1 1 1 1 \n"; // class 2 + scalersstr += "1 1 1 1 1 1 \n"; // class 8 + scalersstr += "1 1 1 1 1 1 \n"; // class 32 + scalersstr += "1 1 1 1 1 1 \n"; // class 63 + // + /// Demo scalers: LMB >= LMA >= L0B >= L0A >= L1B >= L1A error + std::string scalersstr_e1 = "0\n"; // version + scalersstr_e1 += "333 5 0 2 8 32 63\n"; // runnumber nclasses [classes list]] + scalersstr_e1 += "4 3563 4 5 \n"; // orbit bc secs usecs + scalersstr_e1 += "20 20 20 20 20 20 \n"; // class 0 + scalersstr_e1 += "0 0 0 0 0 0 \n"; // class 2 + scalersstr_e1 += "0 0 0 0 0 0 \n"; // class 8 + scalersstr_e1 += "0 0 0 0 0 0 \n"; // class 32 + scalersstr_e1 += "0 0 0 0 0 0 \n"; // class 63 + scalersstr_e1 += "1000 3563 5 5\n"; // orbit bc secs usecs + scalersstr_e1 += "1 2 3 4 5 6 \n"; // class 0 + scalersstr_e1 += "1 1 1 1 1 1 \n"; // class 2 + scalersstr_e1 += "1 1 1 1 1 1 \n"; // class 8 + scalersstr_e1 += "1 1 1 1 1 1 \n"; // class 32 + scalersstr_e1 += "1 1 1 1 1 1 \n"; // class 63 + // + CTPRunScalers ctpscalers; + int ret = ctpscalers.readScalers(scalersstr_e1); + if (ret != 0) { + return; + } + // + ctpscalers.convertRawToO2(); + ctpscalers.printStream(std::cout); +} diff --git a/Detectors/CTP/macro/readraw.py b/Detectors/CTP/macro/readraw.py new file mode 100644 index 0000000000000..71fd7d40d872b --- /dev/null +++ b/Detectors/CTP/macro/readraw.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +import struct +import numpy as np +NGBT = 80 +def makeGBTWordInverse(dglets, GBTWord, rem, s_gbt, Npld): + diglet = rem + i = 0 + while i<(NGBT - Npld): + packed_bytes = struct.pack('IIH',0,0,0); + masksize = int.from_bytes(packed_bytes,"little") + for j in range(Npld-s_gbt): masksize |= (1 << j) + diglet |= (GBTWord & masksize) << s_gbt + dglets.append(diglet) + diglet = 0 + i += Npld-s_gbt + #print(Npld,s_gbt) + GBTWord = (GBTWord >> (Npld - s_gbt)) + s_gbt = 0 + s_gbt = NGBT - i + rem = GBTWord + return dglets,rem,s_gbt +def bytes4(n=10): + with open("ctp.raw", "rb") as f: + byte = f.read(1) + i = 0 + # number of bytes per line + nbytes = 4 + ibytes = 0 + word = 0 + iword = 0 + while byte != b"": + # Do stuff with byte. + if ibytes == nbytes: + print("W%012i w%02i %08x " % (i,iword,word)) + word = 0 + ibytes = 0 + iword += 1 + iword = (iword % 16) + ibyte = int.from_bytes(byte,"little") + word += (ibyte << 8*ibytes) + ibytes += 1 + byte = f.read(1) + i += 1 + if i == n: break +def bytes16(n=10): + with open("ctp.raw", "rb") as f: + i = 0 + # number of bytes per line + nbytes = 4 + ibytes = 0 + word = 0 + iword = 0 + words4=[] + nwords4 = 4 + iwords4 = 0 + irdh = 0 + nrdh = 6 + stopbit = 0 + feeid = 0 + packetoffset = 0 + offset = 0 + orbit0 = 0 + size_gbt = 0 + packed_bytes = struct.pack('IIH',0,0,0); + remnant = int.from_bytes(packed_bytes,"little") + byte = f.read(1) + while byte != b"": + # Do stuff with byte. + if ibytes == nbytes: + #print("W%012i w%02i %08x " % (i,iword,word)) + words4.append(word) + iwords4 += 1 + word = 0 + ibytes = 0 + iword += 1 + iword = (iword % 16) + ibyte = int.from_bytes(byte,"little") + word += (ibyte << 8*ibytes) + ibytes += 1 + byte = f.read(1) + i += 1 + #print("i",i, " packetoffset",packetoffset, "i-15+0ffset", i-15-offset) + if packetoffset == (i+1-16-offset): + #print("changing",i,packetoffset,offset) + offset = i-15 + irdh = 0 + orbit = -1 + bcid = -1 + # + if iwords4 == nwords4: + ss = ("W%012i " % (i)) + ss += (" %08x " % (words4[3])) + ss += (" %08x " % (words4[2])) + #ss += (" %04x " % (words4[2] & 0xffff)) + ss += (" %08x " % (words4[1])) + ss += (" %08x " % (words4[0])) + #print("irdh ",irdh) + #format = struct.Struct('<IIH') + w2 = int(words4[2] & 0xffff); + packed_bytes = struct.pack('IIH',words4[0],words4[1],w2); + uss = int.from_bytes(packed_bytes,"little") + prtflag=0 + if irdh == 0: + irdh+=1 + feeid = (words4[0] & 0xffff0000)>>16 + packetoffset = words4[2] & 0xffff + print("RDH==================== ccccFEEid:0x%x Packet offset:%i" % (feeid,packetoffset)) + elif irdh == 1: + irdh+=1 + bcid = words4[0] & 0xfff; + orbit = words4[1] + elif irdh == 2: + irdh+=1 + stopbit = words4[1] & 0xff0000 + #print(words4[1]) + elif irdh == 3: + irdh+=1 + print("RDH---: ORBIT:0x%x BCID:0x%x" % (orbit,bcid)) + if orbit0 != orbit: + remnant = 0 + size_gbt = 0 + orbit0 = orbit + else: + #print("Decode") + pp = (f'{uss:010x}') + if len(pp) > 20: + print("Internal error") + exit(1) + elif len(pp) < 20: + aa="" + for ii in range(20-len(pp)): aa += "0" + pp = aa+pp + diglets = [] + if feeid == 0x121: diglets,remnant,size_gbt = makeGBTWordInverse(diglets,uss,remnant,size_gbt,64+12) + else : diglets,remnant,size_gbt = makeGBTWordInverse(diglets,uss,remnant,size_gbt,48+12) + pss="i:"+f'{i:10d}' + flag = 0 + for d in diglets: + if feeid == 0x121: flag += d & 0xffffffffffffffff000 + else: flag+= d & 0xffffffffffff000 + pss += " "+f'{d:010x}' + bcid = d & 0xfff; + pss += f'{bcid:5d}' + pss += " orb:"+""f'{orbit:4d}' + #flag=1 + if flag: flag = 123456789 + print(pp,len(pp),"pld:",pss, " flag:",flag) + #print("payload:",pss) + #print(ss) + prtflag = 1 + if prtflag == 0: print(ss) + iwords4 = 0 + words4.clear() + if i == n: break +if __name__ == "__main__": + # execute only if run as a script + bytes16(0) diff --git a/Detectors/CTP/reconstruction/CMakeLists.txt b/Detectors/CTP/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..e407a102a48ee --- /dev/null +++ b/Detectors/CTP/reconstruction/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(CTPReconstruction + SOURCES src/CTFCoder.cxx src/CTFHelper.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::DetectorsBase + O2::CommonDataFormat + O2::DetectorsCommonDataFormats + O2::rANS + Microsoft.GSL::GSL) + diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..64323fef315e6 --- /dev/null +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -0,0 +1,146 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CTP data + +#ifndef O2_CTP_CTFCODER_H +#define O2_CTP_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsCTP/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "CTPReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace ctp +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::CTP) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const CTPDigit>& data); + + /// entropy decode data from buffer with CTF + template <typename VTRG> + void decode(const CTF::base& ec, VTRG& data); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<CTPDigit>& data); +}; + +/// entropy-encode clusters to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const CTPDigit>& data) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_bytesInput + MD::EENCODE, // BLC_bytesClass + }; + + CTFHelper helper(data); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODECTP(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODECTP(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODECTP(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + + ENCODECTP(helper.begin_bytesInput(), helper.end_bytesInput(), CTF::BLC_bytesInput, 0); + ENCODECTP(helper.begin_bytesClass(), helper.end_bytesClass(), CTF::BLC_bytesClass, 0); + + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded digits +template <typename VTRG> +void CTFCoder::decode(const CTF::base& ec, VTRG& data) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcInc; + std::vector<uint32_t> orbitInc; + std::vector<uint8_t> bytesInput, bytesClass; + +#define DECODECTP(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODECTP(bcInc, CTF::BLC_bcIncTrig); + DECODECTP(orbitInc, CTF::BLC_orbitIncTrig); + DECODECTP(bytesInput, CTF::BLC_bytesInput); + DECODECTP(bytesClass, CTF::BLC_bytesClass); + // clang-format on + // + data.clear(); + + uint32_t firstEntry = 0, digCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + auto itInp = bytesInput.begin(); + auto itCls = bytesClass.begin(); + + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + auto& dig = data.emplace_back(); + dig.intRecord = ir; + for (int i = 0; i < CTFHelper::CTPInpNBytes; i++) { + dig.CTPInputMask |= static_cast<uint64_t>(*itInp++) << (8 * i); + } + for (int i = 0; i < CTFHelper::CTPClsNBytes; i++) { + dig.CTPClassMask |= static_cast<uint64_t>(*itCls++) << (8 * i); + } + } + assert(itInp == bytesInput.end()); + assert(itCls == bytesClass.end()); +} + +} // namespace ctp +} // namespace o2 + +#endif // O2_CTP_CTFCODER_H diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..ce7615cbe7bb0 --- /dev/null +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h @@ -0,0 +1,170 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CTP CTF creation + +#ifndef O2_CTP_CTF_HELPER_H +#define O2_CTP_CTF_HELPER_H + +#include "DataFormatsCTP/CTF.h" +#include "DataFormatsCTP/Digits.h" +#include <gsl/span> + +namespace o2 +{ +namespace ctp +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const CTPDigit>& data) + : mData(data) {} + + static constexpr int CTPInpNBytes = CTP_NINPUTS / 8 + (CTP_NINPUTS % 8 > 0); + static constexpr int CTPClsNBytes = CTP_NCLASSES / 8 + (CTP_NCLASSES % 8 > 0); + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mData.size()), 0, 0}; + if (mData.size()) { + h.firstOrbit = mData[0].intRecord.orbit; + h.firstBC = mData[0].intRecord.bc; + } + return h; + } + + size_t getSize() const { return mData.size() * sizeof(CTPDigit); } + + //>>> =========================== ITERATORS ======================================== + + template <typename I, typename D, typename T, int M = 1> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, CTPDigit, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, CTPDigit, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].intRecord.orbit == mData[mIndex - 1].intRecord.orbit) { + return mData[mIndex].intRecord.bc - mData[mIndex - 1].intRecord.bc; + } else { + return mData[mIndex].intRecord.bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, CTPDigit, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, CTPDigit, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].intRecord.orbit - mData[mIndex - 1].intRecord.orbit : 0; } + }; + + //_______________________________________________ + class Iter_bytesInput : public _Iter<Iter_bytesInput, CTPDigit, uint8_t, CTPInpNBytes> + { + public: + using _Iter<Iter_bytesInput, CTPDigit, uint8_t, CTPInpNBytes>::_Iter; + value_type operator*() const + { + return static_cast<uint8_t>(((mData[mIndex / CTPInpNBytes].CTPInputMask.to_ullong()) >> (8 * (mIndex % CTPInpNBytes))) & 0xff); + } + }; + + //_______________________________________________ + class Iter_bytesClass : public _Iter<Iter_bytesClass, CTPDigit, uint8_t, CTPClsNBytes> + { + public: + using _Iter<Iter_bytesClass, CTPDigit, uint8_t, CTPClsNBytes>::_Iter; + value_type operator*() const + { + return static_cast<uint8_t>(((mData[mIndex / CTPClsNBytes].CTPClassMask.to_ullong()) >> (8 * (mIndex % CTPClsNBytes))) & 0xff); + } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mData, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mData, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mData, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mData, true); } + + Iter_bytesInput begin_bytesInput() const { return Iter_bytesInput(mData, false); } + Iter_bytesInput end_bytesInput() const { return Iter_bytesInput(mData, true); } + + Iter_bytesClass begin_bytesClass() const { return Iter_bytesClass(mData, false); } + Iter_bytesClass end_bytesClass() const { return Iter_bytesClass(mData, true); } + + private: + const gsl::span<const o2::ctp::CTPDigit> mData; +}; + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/reconstruction/src/CTFCoder.cxx b/Detectors/CTP/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..23a138e34b320 --- /dev/null +++ b/Detectors/CTP/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of CTP data + +#include "CTPReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::ctp; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<CTPDigit>& data) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, data); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc = 0; + uint32_t orbitInc = 0; + uint8_t bytesInput = 0, bytesClass = 0; +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(bytesInput, CTF::BLC_bytesInput); + MAKECODER(bytesClass, CTF::BLC_bytesClass); + // clang-format on +} diff --git a/Detectors/CTP/reconstruction/src/CTFHelper.cxx b/Detectors/CTP/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..548eb5251f869 --- /dev/null +++ b/Detectors/CTP/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for CTP CTF creation + +#include "CTPReconstruction/CTFHelper.h" diff --git a/Detectors/CTP/simulation/CMakeLists.txt b/Detectors/CTP/simulation/CMakeLists.txt new file mode 100644 index 0000000000000..de38c20bf731a --- /dev/null +++ b/Detectors/CTP/simulation/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(CTPSimulation + SOURCES src/Digitizer.cxx + src/Digits2Raw.cxx + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::Framework + O2::DataFormatsCTP + O2::DetectorsRaw + O2::Headers) +o2_target_root_dictionary(CTPSimulation HEADERS + include/CTPSimulation/Digitizer.h) +o2_add_executable(digi2raw + COMPONENT_NAME ctp + SOURCES src/digi2raw.cxx + PUBLIC_LINK_LIBRARIES O2::CTPSimulation + O2::DetectorsRaw + O2::DetectorsCommonDataFormats + O2::CommonUtils + Boost::program_options) diff --git a/Detectors/CTP/simulation/include/CTPSimulation/Digitizer.h b/Detectors/CTP/simulation/include/CTPSimulation/Digitizer.h new file mode 100644 index 0000000000000..0f08d9adb18c6 --- /dev/null +++ b/Detectors/CTP/simulation/include/CTPSimulation/Digitizer.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digitizer.h +/// \author Roman Lietava + +#ifndef ALICEO2_CTP_DIGITIZER_H +#define ALICEO2_CTP_DIGITIZER_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsCTP/Digits.h" +#include "DataFormatsCTP/Configuration.h" +#include "CCDB/BasicCCDBManager.h" +#include <gsl/span> + +namespace o2 +{ +namespace ctp +{ +class Digitizer +{ + public: + Digitizer() = default; + ~Digitizer() = default; + void setCCDBServer(const std::string& server) { mCCDBServer = server; } + std::vector<CTPDigit> process(const gsl::span<o2::ctp::CTPInputDigit> detinputs); + void calculateClassMask(const std::bitset<CTP_NINPUTS> ctpinpmask, std::bitset<CTP_NCLASSES>& classmask); + void init(); + private: + // CTP configuration + std::string mCCDBServer = "http://ccdb-test.cern.ch:8080"; + CTPConfiguration* mCTPConfiguration = nullptr; + ClassDefNV(Digitizer, 2); +}; +} // namespace ctp +} // namespace o2 +#endif //ALICEO2_CTP_DIGITIZER_H diff --git a/Detectors/CTP/simulation/include/CTPSimulation/Digits2Raw.h b/Detectors/CTP/simulation/include/CTPSimulation/Digits2Raw.h new file mode 100644 index 0000000000000..0bdba7736825c --- /dev/null +++ b/Detectors/CTP/simulation/include/CTPSimulation/Digits2Raw.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digits2Raw.h +/// \brief Digits tw Raw translation +/// \author Roman Lietava + +#ifndef ALICEO2_CTP_DIGITS2RAW_H_ +#define ALICEO2_CTP_DIGITS2RAW_H_ + +#include <vector> +#include "DetectorsRaw/RawFileWriter.h" +#include "DataFormatsCTP/Configuration.h" +#include "DataFormatsCTP/Digits.h" +#include "TRandom.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DetectorsRaw/HBFUtils.h" + +namespace o2 +{ +namespace ctp +{ +class Digits2Raw +{ + public: + Digits2Raw() = default; + ~Digits2Raw() = default; + void init(); + void setVerbosity(int v) { mVerbosity = v; } + void setFilePerLink(bool v) { mOutputPerLink = v; } + void setOutDir(std::string& outdir) { mOutDir = outdir; } + void setBoardId(uint32_t boardid) { mBoardId = boardid; } + void setZeroSuppressedIntRec(bool value) { mZeroSuppressedIntRec = value; } + void setZeroSuppressedClassRec(bool value) { mZeroSuppressedClassRec = value; } + bool getFilePerLink() const { return mOutputPerLink; } + uint64_t getFEEIDIR() const { return uint64_t(mBoardId + (o2::ctp::GBTLinkIDIntRec << 8)); } + uint64_t getFEEIDTC() const { return uint64_t(mBoardId + (o2::ctp::GBTLinkIDClassRec << 8)); } + o2::raw::RawFileWriter& getWriter() { return mWriter; } + void setOutDir(const std::string& outDir) { mOutDir = outDir; } + void processDigits(const std::string& fileDigitsName); + void emptyHBFMethod(const header::RDHAny* rdh, std::vector<char>& toAdd) const; + std::vector<char> digits2HBTPayload(const gsl::span<gbtword80_t> digits, uint32_t Npld) const; + bool makeGBTWord(const gbtword80_t& pld, gbtword80_t& gbtword, uint32_t& size_gbt, uint32_t Npld, gbtword80_t& gbtsend) const; + //void makeGBTWordInverse(std::vector<gbtword80_t> diglets, gbtword80_t& GBTWord, gbtword80_t& remnant, uint32_t& size_gbt, uint32_t Npld) const; + int digit2GBTdigit(gbtword80_t& gbtdigitIR, gbtword80_t& gbtdigitTR, const CTPDigit& digit); + std::vector<gbtword80_t> addEmptyBC(std::vector<gbtword80_t>& hbfIRZS); + void printDigit(std::string text, const gbtword80_t& dig) const; + void dumpRawData(std::string filename = "ctp.raw"); + + private: + // Raw Writer + o2::raw::RawFileWriter mWriter{"CTP"}; + int mVerbosity = 0; + bool mOutputPerLink = false; + uint16_t mCruID = 0; + uint32_t mEndPointID = 0; + + std::string mOutDir; + uint32_t mActiveLink = -1; + // CTP specific (commented are in Digits.h) + //const uint32_t mGBTLinkIR = 0; // Interaction record CTP GBT link + //const uint32_t mGBTLinkTC = 1; // Trigger Class Record CTP GBT link + //const uint32_t mGBTLinkMisc = 2; // HBrecord, Counters, ... + uint32_t mBoardId = 33; + bool mZeroSuppressedIntRec = false; + bool mZeroSuppressedClassRec = true; + //constexpr uint32_t CTPCRULinkIDMisc = 2; + std::string mCTPRawDataFileName = "CTP_alio2-cr1-flp163_cru1111_0"; +}; +} // namespace ctp +} // namespace o2 +#endif //_CTP_DIGITS2RAW_H_ diff --git a/Detectors/CTP/simulation/src/CTPSimulationLinkDef.h b/Detectors/CTP/simulation/src/CTPSimulationLinkDef.h new file mode 100644 index 0000000000000..28f1f37283067 --- /dev/null +++ b/Detectors/CTP/simulation/src/CTPSimulationLinkDef.h @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::ctp::Digitizer + ; +#endif diff --git a/Detectors/CTP/simulation/src/Digitizer.cxx b/Detectors/CTP/simulation/src/Digitizer.cxx new file mode 100644 index 0000000000000..7f301d27e78cb --- /dev/null +++ b/Detectors/CTP/simulation/src/Digitizer.cxx @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digitizer.cxx +/// \author Roman Lietava + +#include "CTPSimulation/Digitizer.h" +#include "TRandom.h" +#include <cassert> +#include "FairLogger.h" +#include <bitset> + +using namespace o2::ctp; + +ClassImp(Digitizer); +// Trigger detector config needed here. +std::vector<CTPDigit> Digitizer::process(const gsl::span<o2::ctp::CTPInputDigit> detinputs) +{ + std::map<o2::detectors::DetID::ID, std::vector<CTPInput>> det2ctpinp = mCTPConfiguration->getDet2InputMap(); + // To be taken from config database ? + std::map<std::string, uint64_t> detInputName2Mask = + {{"MFV0MB", 1}, {"MFV0MBInner", 2}, {"MFV0MBOuter", 4}, {"MFV0HM", 8}, {"MFT0A", 1}, {"MFT0C", 2}, {"MFT0Vertex", 4}, {"MFT0Cent", 8}, {"MFT0SemiCent", 0x10}}; + std::map<o2::InteractionRecord, std::vector<const CTPInputDigit*>> predigits; + for (auto const& inp : detinputs) { + predigits[inp.intRecord].push_back(&inp); + } + std::vector<CTPDigit> digits; + for (auto const& hits : predigits) { + CTPDigit data; + data.intRecord = hits.first; + std::bitset<CTP_NINPUTS> inpmaskcoll = 0; + for (auto const inp : hits.second) { + switch (inp->detector) { + case o2::detectors::DetID::FT0: { + // see dummy database above + for (auto const& ctpinp : det2ctpinp[o2::detectors::DetID::FT0]) { + uint64_t mask = (inp->inputsMask).to_ullong() & detInputName2Mask[ctpinp.name]; + inpmaskcoll |= std::bitset<CTP_NINPUTS>(mask); + } + break; + } + case o2::detectors::DetID::FV0: { + for (auto const& ctpinp : det2ctpinp[o2::detectors::DetID::FV0]) { + uint64_t mask = (inp->inputsMask).to_ullong() & detInputName2Mask[ctpinp.name]; + inpmaskcoll |= std::bitset<CTP_NINPUTS>(mask); + } + break; + } + default: + // Error + LOG(FATAL) << "CTP Digitizer: unknown detector:" << inp->detector; + break; + } + } + data.CTPInputMask = inpmaskcoll; + calculateClassMask(inpmaskcoll, data.CTPClassMask); + digits.emplace_back(data); + } + return std::move(digits); +} +void Digitizer::calculateClassMask(const std::bitset<CTP_NINPUTS> ctpinpmask, std::bitset<CTP_NCLASSES>& classmask) +{ + classmask = 0; + for (auto const& tcl : mCTPConfiguration->getCTPClasses()) { + if (tcl.descriptor->getInputsMask() & ctpinpmask.to_ullong()) { + classmask |= (1 << tcl.classMask); + } + } +} +void Digitizer::init() +{ + // CTP Configuration + if (mCCDBServer.empty()) { + LOG(FATAL) << "CTP digitizer: CCDB server is not set"; + } else { + LOG(INFO) << "CTP digitizer:: CCDB server:" << mCCDBServer; + } + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(mCCDBServer); + mCTPConfiguration = mgr.get<CTPConfiguration>(o2::ctp::CCDBPathCTPConfig); + LOG(INFO) << " @@@ CTP Digitizer:: CCDB connected " << std::endl; +} diff --git a/Detectors/CTP/simulation/src/Digits2Raw.cxx b/Detectors/CTP/simulation/src/Digits2Raw.cxx new file mode 100644 index 0000000000000..0bed37004a11b --- /dev/null +++ b/Detectors/CTP/simulation/src/Digits2Raw.cxx @@ -0,0 +1,317 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digits2Raw.cxx +/// \author Roman Lietava + +#include "CTPSimulation/Digits2Raw.h" +#include "FairLogger.h" +#include "CommonUtils/StringUtils.h" + +using namespace o2::ctp; + +/// CTP digits (see Digits.h) are inputs from trigger detectors. +/// GBT digit is temporary item: 80 bits long = 12 bits of BCid and payload (see digit2GBTdigit) +/// CTP digit -> GBTdigit CTPInt Record, GBTdigit TrigClass Record +/// GBT didit X -> CRU raw data +/// X= CTPInt Record to link 0 +/// X= TrigClass Record to link 1 + +void Digits2Raw::init() +{ + + // + // Register links + // + std::string outd = mOutDir; + if (outd.back() != '/') { + outd += '/'; + } + LOG(INFO) << "Raw outpud dir:" << mOutDir; + // Interaction Record + int ilink = 0; + uint64_t feeID = getFEEIDIR(); + std::string outFileLink0 = mOutputPerLink ? fmt::format("{}{}_feeid{}.raw", outd, mCTPRawDataFileName, feeID) : fmt::format("{}{}.raw", outd, mCTPRawDataFileName, feeID); + mWriter.registerLink(feeID, mCruID, ilink, mEndPointID, outFileLink0); + // Trigger Class record + ilink = 1; + feeID = getFEEIDTC(); + std::string outFileLink1 = mOutputPerLink ? fmt::format("{}{}_feeid{}.raw", outd, mCTPRawDataFileName, feeID) : fmt::format("{}{}.raw", outd, mCTPRawDataFileName, feeID); + mWriter.registerLink(feeID, mCruID, ilink, mEndPointID, outFileLink1); + // ilink = 2: HBMap, Counters - tbd + mWriter.setEmptyPageCallBack(this); +} +void Digits2Raw::processDigits(const std::string& fileDigitsName) +{ + std::unique_ptr<TFile> digiFile(TFile::Open(fileDigitsName.c_str())); + if (!digiFile || digiFile->IsZombie()) { + LOG(FATAL) << "Failed to open input digits file " << fileDigitsName; + return; + } + LOG(INFO) << "Processing digits to raw"; + TTree* digiTree = (TTree*)digiFile->Get("o2sim"); + if (!digiTree) { + LOG(FATAL) << "Failed to get digits tree"; + return; + } + std::vector<o2::ctp::CTPDigit> CTPDigits, *fCTPDigitsPtr = &CTPDigits; + if (digiTree->GetBranch("CTPDigits")) { + digiTree->SetBranchAddress("CTPDigits", &fCTPDigitsPtr); + } else { + LOG(FATAL) << "Branch CTPDigits is missing"; + return; + } + o2::InteractionRecord intRec = {0, 0}; + // Get first orbit + uint32_t orbit0 = 0; + bool firstorbit = 1; + // Add all CTPdigits for given orbit + LOG(INFO) << "Number of entries: " << digiTree->GetEntries(); + for (int ient = 0; ient < digiTree->GetEntries(); ient++) { + digiTree->GetEntry(ient); + int nbc = CTPDigits.size(); + LOG(INFO) << "Entry " << ient << " : " << nbc << " BCs stored"; + std::vector<gbtword80_t> hbfIR; + std::vector<gbtword80_t> hbfTC; + for (auto const& ctpdig : CTPDigits) { + LOG(DEBUG) << ctpdig.intRecord.bc << " bc all orbit " << ctpdig.intRecord.orbit; + if ((orbit0 == ctpdig.intRecord.orbit) || firstorbit) { + if (firstorbit == true) { + firstorbit = false; + orbit0 = ctpdig.intRecord.orbit; + LOG(INFO) << "First orbit:" << orbit0; + } + LOG(DEBUG) << ctpdig.intRecord.orbit << " orbit bc " << ctpdig.intRecord.bc; + gbtword80_t gbtdigIR; + gbtword80_t gbtdigTC; + digit2GBTdigit(gbtdigIR, gbtdigTC, ctpdig); + LOG(DEBUG) << "ir:" << gbtdigIR; + LOG(DEBUG) << "tr:" << gbtdigTC; + hbfIR.push_back(gbtdigIR); + hbfTC.push_back(gbtdigTC); + } else { + std::vector<char> buffer; + LOG(INFO) << "Packing orbit:" << orbit0; + intRec.orbit = orbit0; + LOG(INFO) << "hbfIR:" << hbfIR.size() << " hbfTC:" << hbfTC.size(); + if (mZeroSuppressedIntRec == true) { + buffer = digits2HBTPayload(hbfIR, NIntRecPayload); + } else { + std::vector<gbtword80_t> hbfIRnonZS = addEmptyBC(hbfIR); + buffer = digits2HBTPayload(hbfIRnonZS, NIntRecPayload); + } + // add data for IR + LOG(DEBUG) << "IR buffer size:" << buffer.size() << ":"; + mWriter.addData(getFEEIDIR(), mCruID, GBTLinkIDIntRec, mEndPointID, intRec, buffer); + // add data for Trigger Class Record + buffer.clear(); + buffer = digits2HBTPayload(hbfTC, NClassPayload); + LOG(DEBUG) << "TC buffer size:" << buffer.size() << ":"; + mWriter.addData(getFEEIDTC(), mCruID, GBTLinkIDClassRec, mEndPointID, intRec, buffer); + // + orbit0 = ctpdig.intRecord.orbit; + hbfIR.clear(); + hbfTC.clear(); + LOG(DEBUG) << ctpdig.intRecord.orbit << " orbit bc " << ctpdig.intRecord.bc; + gbtword80_t gbtdigIR; + gbtword80_t gbtdigTC; + digit2GBTdigit(gbtdigIR, gbtdigTC, ctpdig); + LOG(DEBUG) << "ir:" << gbtdigIR; + LOG(DEBUG) << "tr:" << gbtdigTC; + hbfIR.push_back(gbtdigIR); + hbfTC.push_back(gbtdigTC); + } + } + // Last orbit in record + std::vector<char> buffer; + LOG(INFO) << "Packing orbit:" << orbit0; + intRec.orbit = orbit0; + if (mZeroSuppressedIntRec == true) { + buffer = digits2HBTPayload(hbfIR, NIntRecPayload); + } else { + std::vector<gbtword80_t> hbfIRnonZS = addEmptyBC(hbfIR); + buffer = digits2HBTPayload(hbfIRnonZS, NIntRecPayload); + } + // add data for IR + LOG(DEBUG) << "IR buffer size:" << buffer.size() << ":"; + mWriter.addData(getFEEIDIR(), mCruID, GBTLinkIDIntRec, mEndPointID, intRec, buffer); + // add data for Trigger Class Record + buffer.clear(); + buffer = digits2HBTPayload(hbfTC, NClassPayload); + LOG(DEBUG) << "TC buffer size:" << buffer.size() << ":"; + mWriter.addData(getFEEIDTC(), mCruID, GBTLinkIDClassRec, mEndPointID, intRec, buffer); + // + //orbit0 = ctpdig.intRecord.orbit; + firstorbit = true; + hbfIR.clear(); + hbfTC.clear(); + } +} +void Digits2Raw::emptyHBFMethod(const header::RDHAny* rdh, std::vector<char>& toAdd) const +{ + // TriClassRecord data zero suppressed + // CTP INteraction Data + if (((o2::raw::RDHUtils::getFEEID(rdh) & 0xf00) >> 8) == GBTLinkIDIntRec) { + if (mZeroSuppressedIntRec == false) { + toAdd.clear(); + std::vector<gbtword80_t> digits; + for (uint32_t i = 0; i < o2::constants::lhc::LHCMaxBunches; i++) { + gbtword80_t dig = i; + digits.push_back(dig); + } + toAdd = digits2HBTPayload(digits, NIntRecPayload); + } + } +} +std::vector<char> Digits2Raw::digits2HBTPayload(const gsl::span<gbtword80_t> digits, uint32_t Npld) const +{ + std::vector<char> toAdd; + uint32_t size_gbt = 0; + gbtword80_t gbtword; + gbtword80_t gbtsend; + bool valid; + for (auto const& dig : digits) { + valid = makeGBTWord(dig, gbtword, size_gbt, Npld, gbtsend); + if (valid == true) { + for (uint32_t i = 0; i < NGBT; i += 8) { + uint32_t w = 0; + for (uint32_t j = 0; j < 8; j++) { + w += (1 << j) * gbtsend[i + j]; + } + char c = w; + toAdd.push_back(c); + } + // Pad zeros up to 128 bits + uint32_t NZeros = (o2::raw::RDHUtils::GBTWord * 8 - NGBT) / 8; + for (uint32_t i = 0; i < NZeros; i++) { + char c = 0; + toAdd.push_back(c); + } + } + } + // add what is left: maybe never left anything - tbc + //LOG(INFO) << size_gbt << " size valid " << valid; + //LOG(INFO) << "gbtword:" << gbtword; + //LOG(INFO) << "gbtsend:" << gbtsend; + if (size_gbt > 0) { + LOG(DEBUG) << "Adding left over."; + gbtword80_t gbtsend = gbtword; + for (uint32_t i = 0; i < NGBT; i += 8) { + uint32_t w = 0; + for (uint32_t j = 0; j < 8; j++) { + w += (1 << j) * gbtsend[i + j]; + } + char c = w; + toAdd.push_back(c); + } + // Pad zeros up to 128 bits + uint32_t NZeros = (o2::raw::RDHUtils::GBTWord * 8 - NGBT) / 8; + for (uint32_t i = 0; i < NZeros; i++) { + char c = 0; + toAdd.push_back(c); + } + } + return std::move(toAdd); +} +// Adding payload of size < NGBT to GBT words of size NGBT +// gbtsend valid only when return 1 +bool Digits2Raw::makeGBTWord(const gbtword80_t& pld, gbtword80_t& gbtword, uint32_t& size_gbt, uint32_t Npld, gbtword80_t& gbtsend) const +{ + bool valid = false; + //printBitset(gbtword,"GBTword"); + gbtword |= (pld << size_gbt); + if ((size_gbt + Npld) < NGBT) { + size_gbt += Npld; + } else { + // sendData + //printBitset(gbtword,"Sending"); + gbtsend = gbtword; + gbtword = pld >> (NGBT - size_gbt); + size_gbt = size_gbt + Npld - NGBT; + valid = true; + } + //printDigit("pld:", pld); + //printDigit("gbtword:", gbtword); + //std::cout << valid << " "; + //printDigit("gbtsend:", gbtsend); + //std::cout << gbtsend << std::endl; + return valid; +} +int Digits2Raw::digit2GBTdigit(gbtword80_t& gbtdigitIR, gbtword80_t& gbtdigitTR, const CTPDigit& digit) +{ + // + // CTP Interaction record (CTP inputs) + // + gbtdigitIR = 0; + gbtdigitIR = (digit.CTPInputMask).to_ullong() << 12; + gbtdigitIR |= digit.intRecord.bc; + // + // Trig Classes + // + gbtdigitTR = 0; + //gbtdigitTR = (digit.CTPClassMask).to_ullong() << 12; + gbtdigitTR |= digit.intRecord.bc; + for (int i = 0; i < CTP_NCLASSES; i++) { + gbtdigitTR[i + 12] = digit.CTPClassMask[i]; + } + return 0; +} +std::vector<gbtword80_t> Digits2Raw::addEmptyBC(std::vector<gbtword80_t>& hbfIRZS) +{ + std::vector<gbtword80_t> hbfIRnonZS; + if (hbfIRZS.size() == 0) { + LOG(ERROR) << "Int record with zero size not expected here."; + return hbfIRnonZS; + } + uint32_t bcnonzero = 0; + if (hbfIRZS[0] != 0) { + gbtword80_t bs = 0; + hbfIRnonZS.push_back(bs); + } + for (auto const& item : hbfIRZS) { + uint32_t bcnonzeroNext = (item.to_ulong()) & 0xfff; + for (int i = (bcnonzero + 1); i < bcnonzeroNext; i++) { + gbtword80_t bs = i; + hbfIRnonZS.push_back(bs); + } + bcnonzero = bcnonzeroNext; + hbfIRnonZS.push_back(item); + } + for (int i = (bcnonzero + 1); i < 3564; i++) { + gbtword80_t bs = i; + hbfIRnonZS.push_back(bs); + } + return hbfIRnonZS; +} +void Digits2Raw::printDigit(std::string text, const gbtword80_t& dig) const +{ + int bcid = 0; + uint64_t payload1 = 0; + uint64_t payload2 = 0; + std::cout << text; + for (int i = 0; i < 12; i++) { + bcid += dig[i] << i; + } + for (uint64_t i = 0; i < 64; i++) { + payload1 += uint64_t(dig[i]) << i; + } + for (uint64_t i = 64; i < NGBT; i++) { + payload2 += uint64_t(dig[i]) << (i - 64ull); + } + std::cout << "BCID:" << std::hex << bcid << " " << payload2 << payload1 << std::endl; +} +void Digits2Raw::dumpRawData(std::string filename) +{ + std::ifstream input(filename, std::ios::binary); + std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(input), {}); + for (auto const& cc : buffer) { + } +} diff --git a/Detectors/CTP/simulation/src/digi2raw.cxx b/Detectors/CTP/simulation/src/digi2raw.cxx new file mode 100644 index 0000000000000..49d6271388cb3 --- /dev/null +++ b/Detectors/CTP/simulation/src/digi2raw.cxx @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digi2raw.cxx +/// \author ruben.shahoyan@cern.ch +#include <boost/program_options.hpp> +#include <filesystem> +#include <TFile.h> +#include <TStopwatch.h> +#include "Framework/Logger.h" +#include <string> +#include <iomanip> +#include "CommonUtils/StringUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/HBFUtils.h" +#include "CTPSimulation/Digits2Raw.h" +#include "DataFormatsParameters/GRPObject.h" +namespace bpo = boost::program_options; + +void digi2raw(const std::string& inpName, const std::string& outDir, int verbosity, bool filePerLink, uint32_t rdhV = 4, bool noEmptyHBF = false, + int superPageSizeInB = 1024 * 1024); + +int main(int argc, char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + "Convert CTP digits to CRU raw data\n"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); + // add_option("input-file,i", bpo::value<std::string>()->default_value(o2::base::NameConf::getDigitsFileName(o2::detectors::DetID::CTP)),"input CTP digits file"); // why not used? + add_option("input-file,i", bpo::value<std::string>()->default_value("ctpdigits.root"), "input CTP digits file"); + add_option("file-per-link,l", bpo::value<bool>()->default_value(false)->implicit_value(true), "create output file per CRU (default: per layer)"); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); + uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); + add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); + add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help")) { + std::cout << opt_general << std::endl; + exit(0); + } + + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + digi2raw(vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["verbosity"].as<int>(), + vm["file-per-link"].as<bool>(), + vm["rdh-version"].as<uint32_t>(), + vm["no-empty-hbf"].as<bool>()); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} + +void digi2raw(const std::string& inpName, const std::string& outDir, int verbosity, bool filePerLink, uint32_t rdhV, bool noEmptyHBF, int superPageSizeInB) +{ + TStopwatch swTot; + swTot.Start(); + o2::ctp::Digits2Raw m2r; + m2r.setFilePerLink(filePerLink); + m2r.setVerbosity(verbosity); + auto& wr = m2r.getWriter(); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + wr.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::CTP)); // must be set explicitly + wr.setSuperPageSize(superPageSizeInB); + wr.useRDHVersion(rdhV); + wr.setDontFillEmptyHBF(noEmptyHBF); + + std::string outDirName(outDir); + if (outDirName.back() != '/') { + outDirName += '/'; + } + // if needed, create output directory + if (!std::filesystem::exists(outDirName)) { + if (!std::filesystem::create_directories(outDirName)) { + LOG(FATAL) << "could not create output directory " << outDirName; + } else { + LOG(INFO) << "created output directory " << outDirName; + } + } + m2r.setOutDir(outDirName); + m2r.init(); + m2r.processDigits(inpName); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); + // + swTot.Stop(); + swTot.Print(); +} diff --git a/Detectors/CTP/workflow/CMakeLists.txt b/Detectors/CTP/workflow/CMakeLists.txt new file mode 100644 index 0000000000000..69aef2902e1e4 --- /dev/null +++ b/Detectors/CTP/workflow/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(CTPWorkflow + SOURCES src/RecoWorkflow.cxx + src/RawToDigitConverterSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCTP + O2::DPLUtils + O2::DetectorsRaw + O2::Algorithm + O2::CTPReconstruction + O2::CTPWorkflowIO) +o2_add_executable(reco-workflow + COMPONENT_NAME ctp + SOURCES src/ctp-reco-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Algorithm + O2::CTPWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME ctp + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::CTPWorkflow) \ No newline at end of file diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..4a5618e1a90cc --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to CTP digit stream + +#ifndef O2_CTP_ENTROPYDECODER_SPEC +#define O2_CTP_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "CTPReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +namespace o2 +{ +namespace ctp +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::ctp::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..cbc43822f6cff --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert CTP data to CTF (EncodedBlocks) + +#ifndef O2_CTP_ENTROPYENCODER_SPEC +#define O2_CTP_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include <TStopwatch.h> +#include "CTPReconstruction/CTFCoder.h" + +namespace o2 +{ +namespace ctp +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::ctp::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace ctp +} // namespace o2 + +#endif diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/RawToDigitConverterSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/RawToDigitConverterSpec.h new file mode 100644 index 0000000000000..22fdb0a979d3b --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/RawToDigitConverterSpec.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsCTP/Digits.h" + +namespace o2 +{ + +namespace ctp +{ + +namespace reco_workflow +{ + +/// \class RawToDigitConverterSpec +/// \brief Coverter task for Raw data to CTP digits +/// \author Roman Lietava from CPV example +/// +class RawToDigitConverterSpec : public framework::Task +{ + public: + /// \brief Constructor + /// \param propagateMC If true the MCTruthContainer is propagated to the output + RawToDigitConverterSpec() = default; + + /// \brief Destructor + ~RawToDigitConverterSpec() override = default; + + /// \brief Initializing the RawToDigitConverterSpec + /// \param ctx Init context + void init(framework::InitContext& ctx) final; + + /// \brief Run conversion of raw data to cells + /// \param ctx Processing context + /// + /// The following branches are linked: + /// Input RawData: {"ROUT", "RAWDATA", 0, Lifetime::Timeframe} + /// Output HW errors: {"CTP", "RAWHWERRORS", 0, Lifetime::Timeframe} -later + void run(framework::ProcessingContext& ctx) final; + void makeGBTWordInverse(std::vector<gbtword80_t>& diglets, gbtword80_t& GBTWord, gbtword80_t& remnant, uint32_t& size_gbt, uint32_t Npld) const; + + protected: + private: + std::vector<CTPDigit> mOutputDigits; +}; + +/// \brief Creating DataProcessorSpec for the CTP +/// +o2::framework::DataProcessorSpec getRawToDigitConverterSpec(bool askSTFDist); + +} // namespace reco_workflow + +} // namespace ctp + +} // namespace o2 diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/RecoWorkflow.h b/Detectors/CTP/workflow/include/CTPWorkflow/RecoWorkflow.h new file mode 100644 index 0000000000000..9a4826e64102e --- /dev/null +++ b/Detectors/CTP/workflow/include/CTPWorkflow/RecoWorkflow.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CTP_RECOWORKFLOW_H +#define O2_CTP_RECOWORKFLOW_H + +#include "Framework/WorkflowSpec.h" +#include <string> +#include <vector> + +namespace o2 +{ + +namespace ctp +{ + +namespace reco_workflow +{ + +/// define input and output types of the workflow +enum struct InputType { Digits, // read digits from file + Raw // read data in raw page format from file +}; +enum struct OutputType { Digits, + Raw +}; + +/// create the workflow for CTP reconstruction +framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC = true, + bool noLostTF = false, + std::string const& cfgInput = "raw", // + std::string const& cfgOutput = "digits" // +); +} // namespace reco_workflow + +} // namespace ctp + +} // namespace o2 +#endif diff --git a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..ef0ffb9e24d48 --- /dev/null +++ b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CTPWorkflow/EntropyDecoderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace ctp +{ + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& digits = pc.outputs().make<std::vector<CTPDigit>>(OutputRef{"digits"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::ctp::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, digits); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << digits.size() << " CTP digits in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CTP Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{OutputSpec{{"digits"}, "CTP", "DIGITS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "ctp-entropy-decoder", + Inputs{InputSpec{"ctf", "CTP", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace ctp +} // namespace o2 diff --git a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..d631a3a64f257 --- /dev/null +++ b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CTPWorkflow/EntropyEncoderSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace ctp +{ + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto digits = pc.inputs().get<gsl::span<CTPDigit>>("digits"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"CTP", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, digits); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for CTP in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "CTP Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("digits", "CTP", "DIGITS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "ctp-entropy-encoder", + inputs, + Outputs{{"CTP", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace ctp +} // namespace o2 diff --git a/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx b/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx new file mode 100644 index 0000000000000..f8d6af766b1fb --- /dev/null +++ b/Detectors/CTP/workflow/src/RawToDigitConverterSpec.cxx @@ -0,0 +1,213 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/WorkflowSpec.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" +#include "CTPWorkflow/RawToDigitConverterSpec.h" + +using namespace o2::ctp::reco_workflow; + +void RawToDigitConverterSpec::init(framework::InitContext& ctx) +{ +} + +void RawToDigitConverterSpec::run(framework::ProcessingContext& ctx) +{ + mOutputDigits.clear(); + std::map<o2::InteractionRecord, CTPDigit> digits; + const gbtword80_t bcidmask = 0xfff; + gbtword80_t pldmask; + using InputSpec = o2::framework::InputSpec; + using ConcreteDataTypeMatcher = o2::framework::ConcreteDataTypeMatcher; + using Lifetime = o2::framework::Lifetime; + //mOutputHWErrors.clear(); + std::vector<InputSpec> filter{InputSpec{"filter", ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, Lifetime::Timeframe}}; + o2::framework::DPLRawParser parser(ctx.inputs(), filter); + //setUpDummyLink + auto& inputs = ctx.inputs(); + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", o2::framework::ConcreteDataMatcher{"CTP", "RAWDATA", 0xDEADBEEF}}}; + for (const auto& ref : o2::framework::InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mOutputDigits); + return; + } + } + } + // + uint32_t payloadCTP; + uint32_t orbit0 = 0; + bool first = true; + gbtword80_t remnant = 0; + uint32_t size_gbt = 0; + for (auto it = parser.begin(); it != parser.end(); ++it) { + auto rdh = it.get_if<o2::header::RAWDataHeader>(); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(rdh); + if (first) { + orbit0 = triggerOrbit; + first = false; + } + auto feeID = o2::raw::RDHUtils::getFEEID(rdh); // 0 = IR, 1 = TCR + auto linkCRU = (feeID & 0xf00) >> 8; + if (linkCRU == o2::ctp::GBTLinkIDIntRec) { + payloadCTP = o2::ctp::NIntRecPayload; + } else if (linkCRU == o2::ctp::GBTLinkIDClassRec) { + payloadCTP = o2::ctp::NClassPayload; + } else { + LOG(ERROR) << "Unxpected CTP CRU link:" << linkCRU; + } + LOG(DEBUG) << "RDH FEEid: " << feeID << " CTP CRU link:" << linkCRU << " Orbit:" << triggerOrbit; + pldmask = 0; + for (uint32_t i = 0; i < payloadCTP; i++) { + pldmask[12 + i] = 1; + } + //LOG(INFO) << "pldmask:" << pldmask; + // TF in 128 bits words + gsl::span<const uint8_t> payload(it.data(), it.size()); + gbtword80_t gbtWord = 0; + int wordCount = 0; + std::vector<gbtword80_t> diglets; + if (orbit0 != triggerOrbit) { + remnant = 0; + size_gbt = 0; + orbit0 = triggerOrbit; + } + for (auto payloadWord : payload) { + //LOG(INFO) << wordCount << " payload:" << int(payloadWord); + if (wordCount == 15) { + wordCount = 0; + } else if (wordCount > 9) { + wordCount++; + } else if (wordCount == 9) { + for (int i = 0; i < 8; i++) { + gbtWord[wordCount * 8 + i] = bool(int(payloadWord) & (1 << i)); + } + wordCount++; + diglets.clear(); + //LOG(INFO) << " gbtword:" << gbtWord; + makeGBTWordInverse(diglets, gbtWord, remnant, size_gbt, payloadCTP); + // save digit in buffer recs + for (auto diglet : diglets) { + //LOG(INFO) << " diglet:" << diglet; + //LOG(INFO) << " pldmas:" << pldmask; + gbtword80_t pld = (diglet & pldmask); + if (pld.count() == 0) { + continue; + } + //LOG(INFO) << " pld:" << pld; + pld >>= 12; + CTPDigit digit; + uint32_t bcid = (diglet & bcidmask).to_ulong(); + o2::InteractionRecord ir; + ir.orbit = triggerOrbit; + ir.bc = bcid; + digit.intRecord = ir; + if (linkCRU == o2::ctp::GBTLinkIDIntRec) { + LOG(DEBUG) << "InputMaskCount:" << digits[ir].CTPInputMask.count(); + if (digits.count(ir) == 0) { + digit.setInputMask(pld); + digits[ir] = digit; + LOG(DEBUG) << bcid << " inputs case 0 bcid orbit " << triggerOrbit << " pld:" << pld; + } else if (digits.count(ir) == 1) { + if (digits[ir].CTPInputMask.count() == 0) { + digits[ir].setInputMask(pld); + LOG(DEBUG) << bcid << " inputs bcid vase 1 orbit " << triggerOrbit << " pld:" << pld; + } else { + LOG(ERROR) << "Two CTP IRs with the same timestamp."; + } + } else { + LOG(ERROR) << "Two digits with the same rimestamp."; + } + } else if (linkCRU == o2::ctp::GBTLinkIDClassRec) { + if (digits.count(ir) == 0) { + digit.setClassMask(pld); + digits[ir] = digit; + LOG(DEBUG) << bcid << " class bcid case 0 orbit " << triggerOrbit << " pld:" << pld; + } else if (digits.count(ir) == 1) { + if (digits[ir].CTPClassMask.count() == 0) { + digits[ir].setClassMask(pld); + LOG(DEBUG) << bcid << " class bcid case 1 orbit " << triggerOrbit << " pld:" << pld; + } else { + LOG(ERROR) << "Two CTP Class masks for same timestamp"; + } + } else { + } + } else { + LOG(ERROR) << "Unxpected CTP CRU link:" << linkCRU; + } + } + gbtWord = 0; + } else { + //std::cout << "wordCount:" << wordCount << std::endl; + for (int i = 0; i < 8; i++) { + gbtWord[wordCount * 8 + i] = bool(int(payloadWord) & (1 << i)); + //gbtWord[(9-wordCount) * 8 + i] = bool(int(payloadWord) & (1 << i)); + } + wordCount++; + } + } + } + for (auto const digmap : digits) { + mOutputDigits.push_back(digmap.second); + } + + LOG(INFO) << "[CTPRawToDigitConverter - run] Writing " << mOutputDigits.size() << " digits ..."; + ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mOutputDigits); + //ctx.outputs().snapshot(o2::framework::Output{"CPV", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe}, mOutputHWErrors); +} +// Inverse of Digits2Raw::makeGBTWord +void RawToDigitConverterSpec::makeGBTWordInverse(std::vector<gbtword80_t>& diglets, gbtword80_t& GBTWord, gbtword80_t& remnant, uint32_t& size_gbt, uint32_t Npld) const +{ + gbtword80_t diglet = remnant; + uint32_t i = 0; + while (i < (NGBT - Npld)) { + std::bitset<NGBT> masksize = 0; + for (uint32_t j = 0; j < (Npld - size_gbt); j++) { + masksize[j] = 1; + } + diglet |= (GBTWord & masksize) << (size_gbt); + diglets.push_back(diglet); + diglet = 0; + i += Npld - size_gbt; + GBTWord = GBTWord >> (Npld - size_gbt); + size_gbt = 0; + } + size_gbt = NGBT - i; + remnant = GBTWord; +} +o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawToDigitConverterSpec(bool askDISTSTF) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("TF", o2::framework::ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, o2::framework::Lifetime::Optional); + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back("CTP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{ + "CTP-RawStreamDecoder", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<o2::ctp::reco_workflow::RawToDigitConverterSpec>()}, + o2::framework::Options{{"result-file", o2::framework::VariantType::String, "/tmp/hmpCTPDecodeResults", {"Base name of the decoding results files."}}}}; +} diff --git a/Detectors/CTP/workflow/src/RecoWorkflow.cxx b/Detectors/CTP/workflow/src/RecoWorkflow.cxx new file mode 100644 index 0000000000000..6b17c5c8b7ffb --- /dev/null +++ b/Detectors/CTP/workflow/src/RecoWorkflow.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <algorithm> +#include <unordered_map> +#include <vector> + +#include "FairLogger.h" + +#include "Framework/RootSerializationSupport.h" +#include "Algorithm/RangeTokenizer.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsCTP/Digits.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "CTPWorkflow/RecoWorkflow.h" +#include "CTPWorkflowIO/DigitReaderSpec.h" +#include "CTPWorkflowIO/DigitWriterSpec.h" +#include "CTPWorkflow/RawToDigitConverterSpec.h" +#include "Framework/DataSpecUtils.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::dataformats; + +namespace o2 +{ + +namespace ctp +{ + +namespace reco_workflow +{ + +const std::unordered_map<std::string, InputType> InputMap{ + {"raw", InputType::Raw}, + {"digits", InputType::Digits}}; + +const std::unordered_map<std::string, OutputType> OutputMap{ + {"digits", OutputType::Digits}}; + +o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC, + bool noLostTF, + std::string const& cfgInput, + std::string const& cfgOutput) +{ + InputType inputType; + + try { + inputType = InputMap.at(cfgInput); + } catch (std::out_of_range&) { + throw std::invalid_argument(std::string("invalid input type: ") + cfgInput); + } + std::vector<OutputType> outputTypes; + try { + outputTypes = RangeTokenizer::tokenize<OutputType>(cfgOutput, [](std::string const& token) { return OutputMap.at(token); }); + } catch (std::out_of_range&) { + throw std::invalid_argument(std::string("invalid output type: ") + cfgOutput); + } + auto isEnabled = [&outputTypes](OutputType type) { + return std::find(outputTypes.begin(), outputTypes.end(), type) != outputTypes.end(); + }; + + o2::framework::WorkflowSpec specs; + + // //Raw to .... + if (inputType == InputType::Raw) { + //no explicit raw reader + + if (isEnabled(OutputType::Digits)) { + specs.emplace_back(o2::ctp::reco_workflow::getRawToDigitConverterSpec(noLostTF)); + if (!disableRootOut) { + specs.emplace_back(o2::ctp::getDigitWriterSpec(true)); + } + } + } + + // Digits to .... + if (inputType == InputType::Digits) { + if (!disableRootInp) { + specs.emplace_back(o2::ctp::getDigitsReaderSpec(propagateMC)); + } + } + return std::move(specs); +} + +} // namespace reco_workflow + +} // namespace ctp + +} // namespace o2 diff --git a/Detectors/CTP/workflow/src/ctp-reco-workflow.cxx b/Detectors/CTP/workflow/src/ctp-reco-workflow.cxx new file mode 100644 index 0000000000000..684a677abda0d --- /dev/null +++ b/Detectors/CTP/workflow/src/ctp-reco-workflow.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ctp-reco-workflow.cxx +/// @author RL from CPV example +/// @brief Basic DPL workflow for CTP reconstruction starting from digits +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "CTPWorkflow/RecoWorkflow.h" +#include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +#include <string> +#include <stdexcept> +#include <unordered_map> + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"input-type", o2::framework::VariantType::String, "raw", {"digits, raw"}}, + {"output-type", o2::framework::VariantType::String, "digits", {"digits, raw"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}, + {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver + +/// The workflow executable for the stand alone CTP reconstruction workflow +/// The basic workflow for CTP reconstruction is defined in RecoWorkflow.cxx +/// and contains the following default processors +/// - digit reader +/// +/// The default workflow can be customized by specifying input and output types +/// e.g. digits, raw +/// +/// MC info is processed by default, disabled by using command line option `--disable-mc` +/// +/// This function hooks up the the workflow specifications into the DPL driver. +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + // + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + auto wf = o2::ctp::reco_workflow::getWorkflow(cfgc.options().get<bool>("disable-root-input"), + cfgc.options().get<bool>("disable-root-output"), + !cfgc.options().get<bool>("disable-mc"), + !cfgc.options().get<bool>("ignore-dist-stf"), // + cfgc.options().get<std::string>("input-type"), // + cfgc.options().get<std::string>("output-type") // + ); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); + return std::move(wf); +} diff --git a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..0d25c85462d2b --- /dev/null +++ b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CTPWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::ctp::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/CTP/workflowIO/CMakeLists.txt b/Detectors/CTP/workflowIO/CMakeLists.txt new file mode 100644 index 0000000000000..94d9a5f4abe91 --- /dev/null +++ b/Detectors/CTP/workflowIO/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_library(CTPWorkflowIO + SOURCES src/DigitReaderSpec.cxx + src/DigitWriterSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCTP + O2::DPLUtils + O2::DetectorsRaw + O2::Algorithm) diff --git a/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitReaderSpec.h b/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitReaderSpec.h new file mode 100644 index 0000000000000..c3a612e2fbfd7 --- /dev/null +++ b/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitReaderSpec.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/OutputSpec.h" +#include <string> +#include <vector> + +namespace o2 +{ + +namespace ctp +{ + +using OutputSpec = framework::OutputSpec; + +framework::DataProcessorSpec getDigitsReaderSpec(bool propagateMC = true); + +} // namespace ctp +} // end namespace o2 diff --git a/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitWriterSpec.h b/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitWriterSpec.h new file mode 100644 index 0000000000000..d03b6a95ff72a --- /dev/null +++ b/Detectors/CTP/workflowIO/include/CTPWorkflowIO/DigitWriterSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DigitWriterSpec.h +/// \author Roman Lietava + +#ifndef O2_CTPDIGITWRITERSPEC_H +#define O2_CTPDIGITWRITERSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "DataFormatsCTP/Digits.h" + +using namespace o2::framework; +namespace o2 +{ +namespace ctp +{ +framework::DataProcessorSpec getDigitWriterSpec(bool raw = true); +} +} // namespace o2 + +#endif //O2_CTPDIGITWRITERSPEC_H diff --git a/Detectors/CTP/workflowIO/src/DigitReaderSpec.cxx b/Detectors/CTP/workflowIO/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..e8ccf1006ae8b --- /dev/null +++ b/Detectors/CTP/workflowIO/src/DigitReaderSpec.cxx @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CTPWorkflowIO/DigitReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/DataSpecUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <memory> +#include <utility> + +using namespace o2::framework; + +namespace o2 +{ + +namespace ctp +{ + +struct ProcessAttributes { + std::shared_ptr<RootTreeReader> reader; + std::string datatype; + bool terminateOnEod; + bool finished; +}; + +DataProcessorSpec getDigitsReaderSpec(bool propagateMC) +{ + if (propagateMC) { + LOG(WARNING) << "MC truth not implemented for CTP, continouing wothout MC"; + propagateMC = false; + } + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + auto treename = ic.options().get<std::string>("treename"); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "CTPDigit"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + //processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + //filename.c_str(), // input file name + //nofEvents, // number of entries to publish + //publishingMode, + //Output{"CTP", "DIGITS", subSpec, persistency}, + //"CTPDigit", // name of data branch + //Output{"CTP", "DIGITSMCTR", subSpec, persistency},"CPVDigitMCTruth"); + } + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CTP", "DIGITS", subSpec, persistency}, + "CTPDigit"); // name of data branch + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { // false for propagateMC + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { // false for propgateMC + //o2::cpv::CPVBlockHeader cpvheader(true); + //if (processAttributes->reader->next()) { + //(*processAttributes->reader)(pc, cpvheader); + //} else { + //processAttributes->reader.reset(); + //return false; + //} + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + //o2::cpv::CPVBlockHeader dummyheader(false); + //pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + //pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + //if (propagateMC) { + //pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + //} + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "CTP", "DIGITS", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "CTP", "DIGITSMCTR", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "ctp-digit-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "ctpdigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} +} // namespace ctp + +} // namespace o2 diff --git a/Detectors/CTP/workflowIO/src/DigitWriterSpec.cxx b/Detectors/CTP/workflowIO/src/DigitWriterSpec.cxx new file mode 100644 index 0000000000000..51729f9ca85df --- /dev/null +++ b/Detectors/CTP/workflowIO/src/DigitWriterSpec.cxx @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DigitWriterSpec.cxx +/// \author Roman Lietava + +#include "CTPWorkflowIO/DigitWriterSpec.h" + +namespace o2 +{ +namespace ctp +{ +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +framework::DataProcessorSpec getDigitWriterSpec(bool raw) +{ + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + // Spectators for logging + auto logger = [](std::vector<o2::ctp::CTPDigit> const& vecDigits) { + LOG(INFO) << "CTPDigitWriter pulled " << vecDigits.size() << " digits"; + }; + return MakeRootTreeWriterSpec(raw ? "ctp-digit-writer-dec" : "ctp-digit-writer", + raw ? "o2_ctpdigits.root" : "ctpdigits.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CTP digits"}, + BranchDefinition<std::vector<o2::ctp::CTPDigit>>{InputSpec{"digit", "CTP", "DIGITS", 0}, "CTPDigits", logger})(); +} + +} // namespace ctp +} // namespace o2 diff --git a/Detectors/Calibration/CMakeLists.txt b/Detectors/Calibration/CMakeLists.txt index 795e51ca34a5d..40064c2756e54 100644 --- a/Detectors/Calibration/CMakeLists.txt +++ b/Detectors/Calibration/CMakeLists.txt @@ -1,45 +1,46 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsCalibration SOURCES src/TimeSlot.cxx - src/TimeSlotCalibration.cxx - src/Utils.cxx - src/MeanVertexData.cxx - src/MeanVertexCalibrator.cxx - src/MeanVertexParams.cxx - PUBLIC_LINK_LIBRARIES O2::Headers - O2::CCDB - O2::CommonUtils - ROOT::Minuit - ms_gsl::ms_gsl - O2::ReconstructionDataFormats - O2::SimConfig - O2::DataFormatsCalibration) - + src/TimeSlotCalibration.cxx + src/Utils.cxx + src/MeanVertexData.cxx + src/MeanVertexCalibrator.cxx + src/MeanVertexParams.cxx + PUBLIC_LINK_LIBRARIES O2::Headers + O2::CCDB + O2::CommonUtils + ROOT::Minuit + Microsoft.GSL::GSL + O2::ReconstructionDataFormats + O2::SimConfig + O2::DataFormatsCalibration) o2_target_root_dictionary(DetectorsCalibration HEADERS include/DetectorsCalibration/TimeSlotCalibration.h - include/DetectorsCalibration/TimeSlot.h - include/DetectorsCalibration/Utils.h - include/DetectorsCalibration/MeanVertexData.h - include/DetectorsCalibration/MeanVertexCalibrator.h - include/DetectorsCalibration/MeanVertexParams.h) + include/DetectorsCalibration/TimeSlot.h + include/DetectorsCalibration/Utils.h + include/DetectorsCalibration/MeanVertexData.h + include/DetectorsCalibration/MeanVertexCalibrator.h + include/DetectorsCalibration/MeanVertexParams.h) o2_add_executable(ccdb-populator-workflow COMPONENT_NAME calibration SOURCES workflow/ccdb-populator-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration - O2::DataFormatsTOF - O2::CCDB) + O2::TOFCalibration + O2::DetectorsCalibration + O2::DataFormatsTOF + O2::CCDB) add_subdirectory(workflow) +add_subdirectory(testMacros) diff --git a/Detectors/Calibration/README.md b/Detectors/Calibration/README.md index 28684c7b52aeb..5ddd4c95cb4c1 100644 --- a/Detectors/Calibration/README.md +++ b/Detectors/Calibration/README.md @@ -1,5 +1,5 @@ <!-- doxy -\page refDetectorsCalibration Module 'Detectors/Calibration' +\page refDetectorsCalibration Detectors Calibration /doxy --> # Time-interval based calibration flow for O2 @@ -10,8 +10,13 @@ The calibration flow of O2 foresees that every calibration device (expected to a Each calibration device (to be run in a workflow) has to derive from `o2::calibration::TimeSlotCalibration`, which is a templated class that takes as types the Input type (i.e. the object to be processed, coming from the upstream device) and the Container type (i.e. the object that will contain the calibration data per TimeSlot). Each calibration device has to be configured with the following parameters: ```cpp -tf-per-slot : default length of a TiemSlot in TFs (will be widened in case of too little statistics) -max-delay : maximum arrival delay of a TF with respect to the most recent one processed; units in number of TimeSlots; if beyond this, the TF will be considered too old, and discarded. +tf-per-slot : default length of a TiemSlot in TFs (will be widened in case of too little statistics). If this is set to `std::numeric_limits<long>::max()`, then there will be + only 1 slot at a time, valid till infinity. +updateInterval : to be used together with `tf-per-slot = std::numeric_limits<long>::max()`: it allows to try to finalize the slot (and produce calibration) when the `updateInterval` + has passed. Note that this is an approximation (as explained in the code) due to the fact that TFs will come asynchronously (not ordered in time). +max-delay : maximum arrival delay of a TF with respect to the most recent one processed; units in number of TimeSlots; if beyond this, the TF will be considered too old, and discarded. + If `tf-per-slot == std::numeric_limits<long>::max()`, or `updateAtTheEndOfRunOnly == true`, its value is irrelevant. +updateAtTheEndOfRunOnly : to tell the TimeCalibration to finalize the slots and prepare the CCDB entries only at the end of the run. ``` Example for the options above: `tf-per-slot = 20` @@ -53,13 +58,12 @@ The output to be sent by the calibrator should include: * a vector of the `o2::ccdb::CcdbObjectInfo` objects that contain the extra information (metadata, startValidity...) associated to the objects themselves. -E.g.: +The origins of the pair of outputs will always be `o2::calibration::Utils::gDataOriginCDBPayload` and `o2::calibration::Utils::gDataOriginCDBWrapper` respectively, while the DataDescription must be unique for given calibration type, e.g. ```c++ -output.snapshot(Output{clbUtils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBPayload, i}, *image.get()); // vector<char> -output.snapshot(Output{clbUtils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBInfo, i}, w); // root-serialized +output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_LHCphase", i}, *image.get()); // vector<char> +output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_LHCphase", i}, w); // root-serialized ``` -The origin of the output will always be `o2::calibration::Utils::gDataOriginCLB`, while the description will be `clbUtils::gDataDescriptionCLBPayload` for the object itself, and `o2::calibration::Utils::gDataDescriptionCLBInfo` for the description. See e.g. AliceO2/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h, AliceO2/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx @@ -68,3 +72,7 @@ See e.g. AliceO2/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h This is the workflow that, connected to all workflows producting calibrations with different granularities and frequencies, will update the CCDB. The `--ccdb-path` option of the ccdb-populator-workflow allows to define the CCDB destination (e.g. `--ccdb-path localhost:8080`). + +<!-- doxy +* \subpage refDetectorsCalibrationtestMacros +/doxy --> diff --git a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexCalibrator.h b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexCalibrator.h index d033f35f08024..e6c1a12150a76 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexCalibrator.h +++ b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexCalibrator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexData.h b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexData.h index 42f5f67920143..bf383e0f19c78 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexData.h +++ b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexParams.h b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexParams.h index 11beb9e1435d3..5de4f74de317e 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/MeanVertexParams.h +++ b/Detectors/Calibration/include/DetectorsCalibration/MeanVertexParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/include/DetectorsCalibration/TimeSlot.h b/Detectors/Calibration/include/DetectorsCalibration/TimeSlot.h index 6837e4fd5446c..28256227e86b0 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/TimeSlot.h +++ b/Detectors/Calibration/include/DetectorsCalibration/TimeSlot.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h index a1ed3375ad166..3c37e1b2c54d0 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h +++ b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "DetectorsCalibration/TimeSlot.h" #include <deque> #include <gsl/gsl> +#include <limits> namespace o2 { @@ -30,13 +32,17 @@ class TimeSlotCalibration public: TimeSlotCalibration() = default; virtual ~TimeSlotCalibration() = default; - uint32_t getMaxSlotsDelay() const { return mMaxSlotsDelay; } - void setMaxSlotsDelay(uint32_t v) { mMaxSlotsDelay = v; } - //void setMaxSlotsDelay(uint32_t v) { (mSlotLength == 1 && mMaxSlotsDelay == 0) ? mMaxSlotsDelay = 0 : mMaxSlotsDelay = v < 1 ? 1 : v; } - //void setMaxSlotsDelay(uint32_t v) { mSlotLength == 1 ? mMaxSlotsDelay = 0 : mMaxSlotsDelay = v < 1 ? 1 : v; } + uint64_t getMaxSlotsDelay() const { return mMaxSlotsDelay; } + void setMaxSlotsDelay(uint64_t v) { mMaxSlotsDelay = v; } - uint32_t getSlotLength() const { return mSlotLength; } - void setSlotLength(uint32_t v) { mSlotLength = v < 1 ? 1 : v; } + uint64_t getSlotLength() const { return mSlotLength; } + void setSlotLength(uint64_t v) { mSlotLength = v < 1 ? 1 : v; } + + uint64_t getCheckIntervalInfiniteSlot() const { return mCheckIntervalInfiniteSlot; } + void setCheckIntervalInfiniteSlot(uint64_t v) { mCheckIntervalInfiniteSlot = v; } + + uint64_t getCheckDeltaIntervalInfiniteSlot() const { return mCheckDeltaIntervalInfiniteSlot; } + void setCheckDeltaIntervalInfiniteSlot(uint64_t v) { mCheckDeltaIntervalInfiniteSlot = v < 1 ? mCheckIntervalInfiniteSlot : v; } // if the delta is 0, we ignore it TFType getFirstTF() const { return mFirstTF; } void setFirstTF(TFType v) { mFirstTF = v; } @@ -50,6 +56,8 @@ class TimeSlotCalibration const Slot& getLastSlot() const { return (Slot&)mSlots.back(); } const Slot& getFirstSlot() const { return (Slot&)mSlots.front(); } + template <typename DATA> + bool process(TFType tf, const DATA& data); virtual bool process(TFType tf, const gsl::span<const Input> data); virtual void checkSlotsToFinalize(TFType tf, int maxDelay = 0); virtual void finalizeOldestSlot(); @@ -77,32 +85,83 @@ class TimeSlotCalibration TFType mLastClosedTF = 0; TFType mFirstTF = 0; - uint32_t mSlotLength = 1; - uint32_t mMaxSlotsDelay = 3; + TFType mMaxSeenTF = 0; // largest TF processed + uint64_t mSlotLength = 1; + uint64_t mMaxSlotsDelay = 3; bool mUpdateAtTheEndOfRunOnly = false; + uint64_t mCheckIntervalInfiniteSlot = 1; // will be used if the TF length is INFINITE_TF_int64 to decide + // when to check if to call the finalize; otherwise it is called + // at every new TF; note that this is an approximation, + // since TFs come in async order + TFType mLastCheckedTFInfiniteSlot = 0; // will be used if the TF length is INFINITE_TF_int64 to book-keep + // the last TF at which we tried to calibrate + uint64_t mCheckDeltaIntervalInfiniteSlot = 1; // will be used if the TF length is INFINITE_TF_int64 when + // the check on the statistics returned false, to determine + // after how many TF to check again. + bool mWasCheckedInfiniteSlot = false; // flag to know whether the statistics of the infinite slot was already checked ClassDef(TimeSlotCalibration, 1); }; //_________________________________________________ template <typename Input, typename Container> -bool TimeSlotCalibration<Input, Container>::process(TFType tf, const gsl::span<const Input> data) +template <typename DATA> +bool TimeSlotCalibration<Input, Container>::process(TFType tf, const DATA& data) { - if (!mUpdateAtTheEndOfRunOnly) { - int maxDelay = mMaxSlotsDelay * mSlotLength; - // if (tf<mLastClosedTF || (!mSlots.empty() && getSlot(0).getTFStart() > tf + maxDelay)) { // ignore TF - if (maxDelay != 0 && (tf < mLastClosedTF || (!mSlots.empty() && getLastSlot().getTFStart() > tf + maxDelay))) { // ignore TF - LOG(INFO) << "Ignoring TF " << tf; + + // process current TF + + int maxDelay = mMaxSlotsDelay * mSlotLength; + if (!mUpdateAtTheEndOfRunOnly) { // if you update at the end of run only, then you accept everything + if (tf < mLastClosedTF || (!mSlots.empty() && getLastSlot().getTFStart() > tf + maxDelay)) { // ignore TF; note that if you have only 1 timeslot + // which is INFINITE_TF wide, then maxDelay + // does not matter: you won't accept TFs from the past, + // so the first condition will be used + LOG(INFO) << "Ignoring TF " << tf << ", mLastClosedTF = " << mLastClosedTF; return false; } + } + auto& slotTF = getSlotForTF(tf); + slotTF.getContainer()->fill(data); + if (tf > mMaxSeenTF) { + mMaxSeenTF = tf; // keep track of the most recent TF processed + } + if (!mUpdateAtTheEndOfRunOnly) { // if you update at the end of run only, you don't check at every TF which slots can be closed // check if some slots are done checkSlotsToFinalize(tf, maxDelay); } + return true; +} + +//_________________________________________________ +template <typename Input, typename Container> +bool TimeSlotCalibration<Input, Container>::process(TFType tf, const gsl::span<const Input> data) +{ + // process current TF + + int maxDelay = mMaxSlotsDelay * mSlotLength; + if (!mUpdateAtTheEndOfRunOnly) { // if you update at the end of run only, then you accept everything + if (tf < mLastClosedTF || (!mSlots.empty() && getLastSlot().getTFStart() > tf + maxDelay)) { // ignore TF; note that if you have only 1 timeslot + // which is INFINITE_TF wide, then maxDelay + // does not matter: you won't accept TFs from the past, + // so the first condition will be used + LOG(INFO) << "Ignoring TF " << tf << ", mLastClosedTF = " << mLastClosedTF; + return false; + } + } + auto& slotTF = getSlotForTF(tf); slotTF.getContainer()->fill(data); + if (tf > mMaxSeenTF) { + mMaxSeenTF = tf; // keep track of the most recent TF processed + } + if (!mUpdateAtTheEndOfRunOnly) { // if you update at the end of run only, you don't check at every TF which slots can be closed + // check if some slots are done + checkSlotsToFinalize(tf, maxDelay); + } return true; } @@ -112,27 +171,70 @@ template <typename Input, typename Container> void TimeSlotCalibration<Input, Container>::checkSlotsToFinalize(TFType tf, int maxDelay) { // Check which slots can be finalized, provided the newly arrived TF is tf - // check if some slots are done - for (auto slot = mSlots.begin(); slot != mSlots.end(); slot++) { - if (maxDelay == 0 || (slot->getTFEnd() + maxDelay) < tf) { - if (hasEnoughData(*slot)) { - finalizeSlot(*slot); // will be removed after finalization - } else if ((slot + 1) != mSlots.end()) { - LOG(INFO) << "Merging underpopulated slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd() - << " to slot " << (slot + 1)->getTFStart() << " <= TF <= " << (slot + 1)->getTFEnd(); - (slot + 1)->mergeToPrevious(*slot); + + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + constexpr int64_t INFINITE_TF_int64 = std::numeric_limits<long>::max() - 1; // this is used to define the end + // of the slot in case it is "std::numeric_limits<long>::max()" + // long (so we need to subtract 1) + + // if we have one slot only which is INFINITE_TF_int64 long, and we are not at the end of run (tf != INFINITE_TF), + // we need to check if we got enough statistics, and if so, redefine the slot + if (mSlots.size() == 1 && mSlots[0].getTFEnd() == INFINITE_TF_int64) { + uint64_t checkInterval = mCheckIntervalInfiniteSlot + mLastCheckedTFInfiniteSlot; + if (mWasCheckedInfiniteSlot) { + checkInterval = mCheckDeltaIntervalInfiniteSlot + mLastCheckedTFInfiniteSlot; + } + if (tf >= checkInterval || tf == INFINITE_TF) { + LOG(DEBUG) << "mMaxSeenTF = " << mMaxSeenTF << ", mLastCheckedTFInfiniteSlot = " << mLastCheckedTFInfiniteSlot << ", checkInterval = " << checkInterval << ", mSlots[0].getTFStart() = " << mSlots[0].getTFStart(); + if (tf == INFINITE_TF) { + LOG(INFO) << "End of run reached, trying to calibrate what we have, if we have enough statistics"; + } else { + LOG(INFO) << "Calibrating as soon as we have enough statistics:"; + LOG(INFO) << "Update interval passed (" << checkInterval << "), checking slot for " << mSlots[0].getTFStart() << " <= TF <= " << mSlots[0].getTFEnd(); + } + mLastCheckedTFInfiniteSlot = tf; + if (hasEnoughData(mSlots[0])) { + mWasCheckedInfiniteSlot = false; + mSlots[0].setTFStart(mLastClosedTF); + mSlots[0].setTFEnd(mMaxSeenTF); + LOG(INFO) << "Finalizing slot for " << mSlots[0].getTFStart() << " <= TF <= " << mSlots[0].getTFEnd(); + finalizeSlot(mSlots[0]); // will be removed after finalization + mLastClosedTF = mSlots[0].getTFEnd() + 1; // will not accept any TF below this + mSlots.erase(mSlots.begin()); + // creating a new slot if we are not at the end of run + if (tf != INFINITE_TF) { + LOG(INFO) << "Creating new slot for " << mLastClosedTF << " <= TF <= " << INFINITE_TF_int64; + emplaceNewSlot(true, mLastClosedTF, INFINITE_TF_int64); + } } else { - LOG(INFO) << "Discard underpopulated slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd(); - break; // slot has no enough stat. and there is no other slot to merge it to + LOG(INFO) << "Not enough data to calibrate"; + mWasCheckedInfiniteSlot = true; } - mLastClosedTF = slot->getTFEnd() + 1; // do not accept any TF below this - LOG(INFO) << "closing slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd(); - mSlots.erase(slot); } else { - break; + LOG(DEBUG) << "Not trying to calibrate: either not at EoS, or update interval not passed"; } - if (mSlots.empty()) { // since erasing the very last entry may invalidate mSlots.end() - break; + } else { + // check if some slots are done + for (auto slot = mSlots.begin(); slot != mSlots.end();) { + //if (maxDelay == 0 || (slot->getTFEnd() + maxDelay) < tf) { + if ((slot->getTFEnd() + maxDelay) < tf) { + if (hasEnoughData(*slot)) { + LOG(DEBUG) << "Finalizing slot for " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd(); + finalizeSlot(*slot); // will be removed after finalization + } else if ((slot + 1) != mSlots.end()) { + LOG(INFO) << "Merging underpopulated slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd() + << " to slot " << (slot + 1)->getTFStart() << " <= TF <= " << (slot + 1)->getTFEnd(); + (slot + 1)->mergeToPrevious(*slot); + } else { + LOG(INFO) << "Discard underpopulated slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd(); + break; // slot has no enough stat. and there is no other slot to merge it to + } + mLastClosedTF = slot->getTFEnd() + 1; // will not accept any TF below this + LOG(INFO) << "closing slot " << slot->getTFStart() << " <= TF <= " << slot->getTFEnd(); + slot = mSlots.erase(slot); + } else { + break; // all following slots will be even closer to the new TF + } } } } @@ -155,6 +257,9 @@ void TimeSlotCalibration<Input, Container>::finalizeOldestSlot() template <typename Input, typename Container> inline TFType TimeSlotCalibration<Input, Container>::tf2SlotMin(TFType tf) const { + + // returns the min TF of the slot to which "tf" belongs + if (tf < mFirstTF) { throw std::runtime_error("invalide TF"); } @@ -169,6 +274,8 @@ template <typename Input, typename Container> TimeSlot<Container>& TimeSlotCalibration<Input, Container>::getSlotForTF(TFType tf) { + LOG(DEBUG) << "Getting slot for TF " << tf; + if (mUpdateAtTheEndOfRunOnly) { if (!mSlots.empty() && mSlots.back().getTFEnd() < tf) { mSlots.back().setTFEnd(tf); @@ -179,8 +286,8 @@ TimeSlot<Container>& TimeSlotCalibration<Input, Container>::getSlotForTF(TFType } if (!mSlots.empty() && mSlots.front().getTFStart() > tf) { // we need to add a slot to the beginning - auto tfmn = tf2SlotMin(mSlots.front().getTFStart() - 1); - auto tftgt = tf2SlotMin(tf); + auto tfmn = tf2SlotMin(mSlots.front().getTFStart() - 1); // min TF of the slot corresponding to a TF smaller than the first seen + auto tftgt = tf2SlotMin(tf); // min TF of the slot to which the TF "tf" would belong while (tfmn >= tftgt) { LOG(INFO) << "Adding new slot for " << tfmn << " <= TF <= " << tfmn + mSlotLength - 1; emplaceNewSlot(true, tfmn, tfmn + mSlotLength - 1); diff --git a/Detectors/Calibration/include/DetectorsCalibration/Utils.h b/Detectors/Calibration/include/DetectorsCalibration/Utils.h index d85841d117edd..5093d5feda1f6 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/Utils.h +++ b/Detectors/Calibration/include/DetectorsCalibration/Utils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,10 +29,8 @@ namespace calibration { struct Utils { - - static constexpr o2::header::DataOrigin gDataOriginCLB{"CLB"}; // generic DataOrigin for calibrations - static constexpr o2::header::DataDescription gDataDescriptionCLBPayload = "CLBPAYLOAD"; // DataDescription for TMemFile sent for CCDB storage - static constexpr o2::header::DataDescription gDataDescriptionCLBInfo = "CCDBWRAPPER"; // DataDescription for wrapper helper + static constexpr o2::header::DataOrigin gDataOriginCDBPayload{"CLP"}; // generic DataOrigin for calibrations payload + static constexpr o2::header::DataOrigin gDataOriginCDBWrapper{"CLW"}; // generic DataOrigin for calibrations wrapper }; } // namespace calibration diff --git a/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h b/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h index 337be0f3bbb5c..fdb0a8e41f063 100644 --- a/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h +++ b/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/MeanVertexCalibrator.cxx b/Detectors/Calibration/src/MeanVertexCalibrator.cxx index 1141e872e4b3f..4b169a6c761a9 100644 --- a/Detectors/Calibration/src/MeanVertexCalibrator.cxx +++ b/Detectors/Calibration/src/MeanVertexCalibrator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/MeanVertexData.cxx b/Detectors/Calibration/src/MeanVertexData.cxx index dbcaf5b7616f8..19b2e6fd3ae26 100644 --- a/Detectors/Calibration/src/MeanVertexData.cxx +++ b/Detectors/Calibration/src/MeanVertexData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/MeanVertexParams.cxx b/Detectors/Calibration/src/MeanVertexParams.cxx index 99a7b8252f959..0fbf8ecd46b3d 100644 --- a/Detectors/Calibration/src/MeanVertexParams.cxx +++ b/Detectors/Calibration/src/MeanVertexParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/TimeSlot.cxx b/Detectors/Calibration/src/TimeSlot.cxx index af2e495a4bed0..36eef86c043c0 100644 --- a/Detectors/Calibration/src/TimeSlot.cxx +++ b/Detectors/Calibration/src/TimeSlot.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/TimeSlotCalibration.cxx b/Detectors/Calibration/src/TimeSlotCalibration.cxx index cb8ee39a9a405..188938d0a7c78 100644 --- a/Detectors/Calibration/src/TimeSlotCalibration.cxx +++ b/Detectors/Calibration/src/TimeSlotCalibration.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/src/Utils.cxx b/Detectors/Calibration/src/Utils.cxx index 5d97b143344a8..d24b8200168c7 100644 --- a/Detectors/Calibration/src/Utils.cxx +++ b/Detectors/Calibration/src/Utils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/testMacros/CMakeLists.txt b/Detectors/Calibration/testMacros/CMakeLists.txt new file mode 100644 index 0000000000000..2d9cec773a80d --- /dev/null +++ b/Detectors/Calibration/testMacros/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +install(FILES populateCCDB.C + retrieveFromCCDB.C + DESTINATION share/macro/) + +install(FILES cdbSizeV0.txt + DESTINATION share/Detectors/Calibration/data) + +install(FILES runEPNsimulation.sh + DESTINATION share/Detectors/Calibration/scripts) + +o2_add_test_root_macro(populateCCDB.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::Framework) + +o2_add_test_root_macro(retrieveFromCCDB.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::Framework) + +o2_add_executable(populate-ccdb + COMPONENT_NAME calibration + SOURCES populateCCDB.cxx + PUBLIC_LINK_LIBRARIES ROOT::MathCore + O2::Framework + O2::CCDB) + +o2_add_executable(retrieve-from-ccdb + COMPONENT_NAME calibration + SOURCES retrieveFromCCDB.cxx + PUBLIC_LINK_LIBRARIES ROOT::MathCore + O2::Framework + O2::CCDB) diff --git a/Detectors/Calibration/testMacros/README.md b/Detectors/Calibration/testMacros/README.md new file mode 100644 index 0000000000000..7f0d528f96e58 --- /dev/null +++ b/Detectors/Calibration/testMacros/README.md @@ -0,0 +1,37 @@ +<!-- doxy +\page refDetectorsCalibrationtestMacros Detectors/Calibration/testMacros +/doxy --> + +# Simulation of sending of calibration data from EPNs to an aggregator + +To be used when calibrations produced by several EPNs have to be sent to a single node, the aggregator. +On the aggregator, the devices producing calibration will run and send the output to the CCDB. + +* In order to populate the CCDB, the CCDB local server should be started, if the exercise is not meant to +upload the official or test CCDB. In a terminal, run: +```cpp +java -jar local.jar +``` +which will start a CCDB server on port 8080. See [instructions](https://github.com/AliceO2Group/AliceO2/tree/dev/CCDB#central-and-local-instances-of-the-ccdb). + +* To run the calibration and aggregator, open a terminal and start the aggregator, which is just the `o2-dpl-raw-proxy`: +```cpp +o2-dpl-raw-proxy --dataspec A:TOF/CALIBDATA/0 --channel-config "name=readout-proxy,type=pull,method=bind,address=tcp://localhost:30453,rateLogging=1,transport=zeromq" +``` +where, as you can see, you can overwrite the configurations of the `readout-proxy` channel, which is the channel used by the aggregator. +The aggregator should be started **before the other devices**, since it will listen for data (it is the channel that is *binding*). + +* The following example will pass the data arriving to the aggregator to the `o2-calibration-lhc-clockphase-workflow` device, and from there +to the `o2-calibration-ccdb-populator-workflow` to update the CCDB. For this, the raw-proxy should be in pipeline with these workflows like this: +```cpp +o2-dpl-raw-proxy --dataspec A:TOF/CALIBDATA/0 --channel-config "type=pull,method=bind,address=tcp://localhost:30453,rateLogging=1,transport=zeromq,name=readout-proxy" | o2-calibration-lhc-clockphase-workflow --tf-per-slot 20 -b | o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 +``` + +* To send data to the aggregator simulating an arbitrary number of EPNs, in another terminal, run: +```cpp +source runEPNsimulation.sh 3 +``` +where the argument (`3` above) is the number of EPNs to be simulated. This will send the data to the aggregator process. + +**N.B.**: the aggregator and calibration devices will need to use a different port from localHost:8080 in case the local +CCDB server is used in its default configuration, since 8080 is used by CCDB. In the example above, port 30453 is used. diff --git a/Detectors/Calibration/testMacros/cdbSizeV0.txt b/Detectors/Calibration/testMacros/cdbSizeV0.txt new file mode 100644 index 0000000000000..c35133afa2546 --- /dev/null +++ b/Detectors/Calibration/testMacros/cdbSizeV0.txt @@ -0,0 +1,233 @@ + +# CDB path FileSize (Run2) Validity (s) DCS data To Remove Comment + + ITS/Align/Data 500000 1.00E+09 + ITS/Calib/NoiseMap 30000000 28800 + ITS/Calib/DeadMap 10000000 28800 + ITS/Calib/Params 10000 1.00E+09 + + MFT/Align/Data 500000 1.00E+09 + MFT/Calib/NoiseMap 3000000 28800 + MFT/Calib/DeadMap 3000000 28800 + MFT/Calib/Params 10000 1.00E+09 + + TPC/Calib/IDC 12500000 0.25 + TPC/Align/Data 2704 1.00E+09 + TPC/Calib/Pulser 3813733 28800 + TPC/Calib/CE 4927547 28800 + TPC/Calib/PadNoise 1343329 28800 + TPC/Calib/Pedestals 1919841 28800 +# TPC/Calib/PadGainFactor 12591 28800 x + TPC/Calib/GainFactorDedx 1878278 28800 + TPC/Calib/TimeGain 61545 3600 + TPC/Calib/AltroConfig 1176942 1.00E+09 + TPC/Calib/ClusterParam 37299 1.00E+09 + TPC/Calib/CorrectionMapsRef 12768345 1.00E+09 + TPC/Calib/CorrectionMaps 17884255 60 + TPC/Calib/GasComposition 9093114 28800 x Is used for anchored simulation to account for material budget + TPC/Calib/HighVoltage 2384797 600 x + TPC/Calib/IonTail 3893405 1.00E+09 ? Much smaller ion tain with GEMs, should be corrected in CRU or cluster finder + TPC/Calib/LaserTracks 11115 1.00E+09 ? Not clear yet if this will be needed in the CCDB + TPC/Calib/Mapping 30129 1.00E+09 ? Not clear yet + TPC/Calib/PadTime0 1996850 28800 ? Not clear yet if this will be needed + TPC/Calib/Parameters 4777 28800 + TPC/Calib/PidResponse 387664 1.00E+09 ? Not clear yet if this will be needed, perhaps merged with TimeGain? + TPC/Calib/RecoParam 1070 1.00E+09 + TPC/Calib/Temperature 29282 600 x + TPC/Calib/TimeDrift 1323 600 + +# TPC/Config/GasComposition 1220 600 x The Config part was for the Run1/2 DCS export. I guess this can be removed. +# TPC/Config/HighVoltageStat 783 600 x The Config part was for the Run1/2 DCS export. I guess this can be removed. +# TPC/Config/HighVoltage 3714 600 x The Config part was for the Run1/2 DCS export. I guess this can be removed. +# TPC/Config/Temperature 5719 600 x The Config part was for the Run1/2 DCS export. I guess this can be removed. + + TRD/Align/Data 28767 1.00E+09 + TRD/Calib/ChamberExB 1925 600 + TRD/Calib/ChamberGainFactor 2036 600 + TRD/Calib/ChamberStatus 472 600 TBD: shorter validity of chamber status due to SEUs? + TRD/Calib/ChamberT0 1416 600 + TRD/Calib/ChamberVdrift 1927 600 + TRD/Calib/DCS 124655 60 ??? + TRD/Calib/DetNoise 362 600 + TRD/Calib/Krypton 3085409 1.00E+09 +# TRD/Calib/LocalGainFactor 1817327 3600 x No longer used in Run 3 + TRD/Calib/LocalT0 16487 600 Not used + TRD/Calib/LocalVdrift 17075 600 Not used + TRD/Calib/MonitoringData 8959 600 + TRD/Calib/PadNoise 1668099 28800 + TRD/Calib/PadStatus 15881 28800 + TRD/Calib/PHQ 193161 28800 What PID data will be needed? + TRD/Calib/PIDLQ1D 44294 28800 + TRD/Calib/PIDLQ 446116 28800 + TRD/Calib/PIDNN 378784 28800 + TRD/Calib/PIDThresholds 1115 28800 + TRD/Calib/PRFWidth 17725 28800 ??? + TRD/Calib/RecoParam 958 1.00E+09 ??? + TRD/Calib/TrapConfig 3017386 1.00E+09 Actual TRAPconfig data (blob) is large and stable +# TRD/Calib/TrapConfig O(1kB) 28800 Used TRAPconfig is pointer to data blob + TRD/Calib/trd_chamberStatus 5298 3600 needs merging with TRD/Calib/ChamberStatus + TRD/Calib/trd_envTemp 38434 600 + TRD/Calib/trd_gaschromatographCO2 537 600 Still used? + TRD/Calib/trd_gaschromatographN2 543 600 + TRD/Calib/trd_gaschromatographXe 544 600 + TRD/Calib/trd_gasCO2 507 600 + TRD/Calib/trd_gasH2O 655 600 + TRD/Calib/trd_gasO2 620 600 + TRD/Calib/trd_gasOverpressure 526 600 + TRD/Calib/trd_goofieCO2 516 600 No longer used + TRD/Calib/trd_goofieGain 583 600 No longer used + TRD/Calib/trd_goofieHv 514 600 No longer used + TRD/Calib/trd_goofieN2 514 600 No longer used + TRD/Calib/trd_goofiePeakArea 592 600 No longer used + TRD/Calib/trd_goofiePeakPos 587 600 No longer used + TRD/Calib/trd_goofiePressure 528 600 No longer used + TRD/Calib/trd_goofieTemp 582 600 No longer used + TRD/Calib/trd_goofieVelocity 525 600 No longer used + TRD/Calib/trd_hvAnodeImon 7748686 28800 HV currents / voltages needs further discussion + TRD/Calib/trd_hvAnodeUmon 43528 28800 where do Marian's currents go? + TRD/Calib/trd_hvDriftImon 59798 28800 + TRD/Calib/trd_hvDriftUmon 36353 28800 + TRD/Calib/TrkAttach 12516 28800 ??? + + TOF/Align/Data 79624 1.00E+09 OK + TOF/Calib/ConfigNoise 299 28800 OK (non 100% sure) + TOF/Calib/Config 371 1.00E+09 ??? To be discussed +# TOF/Calib/CTPLatency 241 28800 Yes Obsolete +# TOF/Calib/DeltaBCOffset 252 600 Yes Obsolete + TOF/Calib/FineSlewing 10027254 28800 OK - now in CalibTimeSlewingParamTOF + TOF/Calib/HW 26678 600 OK - moved to ChannelStatus (to be defined) + TOF/Calib/Noise 26680 3600 merged with ChannelStatus + TOF/Calib/ParOffline 751933 28800 merged with CalibTimeSlewingParamTOF +# TOF/Calib/ParOnlineDelay 540738 28800 Yes Obsolete +# TOF/Calib/ParOnline 32043 28800 Yes Obsolete + TOF/Calib/Problematic 2921 28800 OK (only in part covered by calibration) +# TOF/Calib/Pulser 26688 28800 Yes Obsolete + TOF/Calib/ReadoutEfficiency 17555 28800 OK (to be added in calibration chain, full dataset, online, no tracking) + TOF/Calib/RecoParam 384 1.00E+09 OK + TOF/Calib/RunParams 517 28800 Ok - now in CalibLHCphaseTOF + TOF/Calib/Status 7807 600 merged with ChannelStatus +# TOF/Calib/T0FillOnlineCalib 276 28800 Yes Obsolete +# TOF/Calib/T0Fill 231 28800 Yes Obsolete + + EMC/Align/Data 1185 1.00E+09 + EMC/Calib/BadChannels 4633 1.00E+09 + EMC/Calib/Data 4621 28800 + EMC/Calib/Mapping 9327 1.00E+09 + EMC/Calib/PeakFinder 17239 1.00E+09 + EMC/Calib/Pedestals 70701 28800 + EMC/Calib/RecoParam 1800 1.00E+09 + EMC/Calib/SimParam 309 1.00E+09 + EMC/Calib/Time 2777 28800 + EMC/Calib/Trigger 370 28800 + EMC/Config/Preprocessor 355 28800 + EMC/Config/Temperature 1603 600 + + PHS/Align/Data 618 1.00E+09 + PHS/Calib/GainPedestals 131459 28800 + PHS/Calib/BadChannels 1124 1.00E+09 + PHS/Calib/RecoParam 528 1.00E+09 + PHS/Calib/Mapping 73643 1.00E+09 + PHS/Calib/Time 10000 1.00E+09 + + CPV/Align/Data 618 1.00E+09 + CPV/Calib/GainPedestals 131459 28800 + CPV/Calib/BadChannels 1124 1.00E+09 + CPV/Calib/RecoParam 528 1.00E+09 + CPV/Calib/Mapping 73643 1.00E+09 + CPV/Calib/Time 10000 1.00E+09 + + HMP/Align/Data 538 1.00E+09 + HMP/Calib/RecoParam 403 1.00E+09 + HMP/Calib/Masked 3450 28800 + HMP/Calib/NoiseMap 159104 28800 + HMP/Calib/DaqSig 3450 28800 + HMP/Calib/Nmean 2804 28800 + HMP/Calib/QeMap 7797 28800 + HMP/Calib/Qthre 2320 28800 + + MCH/Align/Baseline 6465 1.00E+09 + MCH/Align/Data 19696 1.00E+09 + MCH/Calib/Pedestals 6743530 28800 on the long term we in principle do not need the pedestals (as the subtraction is done in sampa chips), but I would keep them here at least at the beginning for monitoring purposes + MCH/Calib/BPEVO 258083 1.00E+09 ? unclear atm if/how the Run3 equivalent of this information will be used +# MCH/Calib/Capacitances 7304542 1.00E+09 X no longer have gain calibration, so this can go + MCH/Calib/Config 72271 28800 X +# MCH/Calib/Gains 9876740 28800 X no longer have gain calibration, so this can go + MCH/Calib/HV 9011 600 X + MCH/Calib/LV 7765 600 X +# MCH/Calib/MappingData 1202122 1.00E+09 X assumption now is that detection mapping is not changing at all (or very very infrequently), so it's now embedded in the code + MCH/Calib/MappingRunData 94374 28800 while the mapping on the detector side should be fixed, the "electronic" (e.g. cru<->solar) mapping might evolve, so I would keep this one (might be renamed of course) + MCH/Calib/Neighbours 10912490 1.00E+09 ? + MCH/Calib/OccupancyMap 207825 28800 + MCH/Calib/RecoParam 589 1.00E+09 + MCH/Calib/RejectList 2159 28800 + + MID/Align/Data 19696 1.00E+09 Did not exist in Run2 (it was for MCH). Might exist in Run3, but not clear yet +# MID/Calib/RegionalTriggerBoardMasks 1511 1.00E+09 yes + MID/Calib/RegionalTriggerConfig 1533 1.00E+09 To be modified + MCH/Calib/LocalTriggerBoardMasks 1358 1.00E+09 +# MID/Calib/GlobalTriggerBoardMasks 548 1.00E+09 yes + MID/Calib/GlobalTriggerCrateConfig 499 1.00E+09 To be modified +# MID/Calib/TriggerDCS 33209 28800 yes + MID/Calib/TriggerEfficiency 12461 28800 +# MID/Calib/TriggerLut 48262 28800 yes + MID/Calib/TriggerScalers 41283 28800 + +# ZDC/Align/Data 404 1.00E+09 yes Never used in Run1-2 reconstruction nor simulation! + ZDC/Calib/ChMap 698 28800 will be modified Same info is present in ZDC/Config/Module. Should we keep both? Which should be used in reconstruction? + ZDC/Calib/EnergyCalib 303 28800 will be modified + ZDC/Calib/LaserCalib 534 28800 ? Never used in Run1-2 (issues with laser coupling) +# ZDC/Calib/MBCalib 17455 28800 x + ZDC/Calib/Pedestals 1454 28800 will be modified + ZDC/Calib/RecoParam 1250 1.00E+09 In the end it wasn not used in reconstruction (in Run 3 we foresee some reconstruction parameters that could go here) RS: we do not some recoparam +# ZDC/Calib/SaturationCalib 281 28800 x + ZDC/Calib/TDCCalib 357 28800 will be modified First version developed + ZDC/Calib/TowerCalib 277 28800 will be modified + + + FT0/Align/Data 24 1.00E+09 FileSize in bytes? + FT0/Calib/ChargeEqualization 832 3600 Done by laser + FT0/Calib/LightYields 832 1.00E+09 + FT0/Calib/PMGains 832 3600 +# FT0/Calib/PMTrends 3209 3600 Perhaps not needed? + FT0/Calib/PulseShapes 4160 1.00E+09 Crystalball-like parameters, for digitization + FT0/Calib/RecoParam 200 1.00E+09 Validity for a collision system + FT0/Calib/Saturation 832 3600 Needed for simulation only, changing at the HV change + FT0/Calib/Thresholds 832 1.00E+09 Needed for simulation only + FT0/Calib/TimeDelays 1664 600 + FT0/Calib/TimeSlewing 3328000 2.88E+04 Changed only on demand (QC), filesize very rough (overestimated) + FT0/Calib/GlobalDelays 12 3600 + + FV0/Align/Data 12 1.00E+09 + FV0/Calib/ChargeEqualization 192 3600 + FV0/Calib/LightYields 192 1.00E+09 + FV0/Calib/PMGains 192 3600 +# FV0/Calib/PMTrends 3209 3600 Perhaps not needed? + FV0/Calib/PulseShapes 2880 1.00E+09 + FV0/Calib/RecoParam 200 1.00E+09 + FV0/Calib/Saturation 192 3600 + FV0/Calib/Thresholds 192 1.00E+09 + FV0/Calib/TimeDelays 384 600 + FV0/Calib/TimeSlewing 768000 2.88E+04 Perhaps not needed? + + FDD/Align/Data 24 1.00E+09 + FDD/Calib/ChargeEqualization 64 3600 + FDD/Calib/LightYields 64 1.00E+09 + FDD/Calib/PMGains 64 3600 +# FDD/Calib/PMTrends 3209 3600 Perhaps not needed? + FDD/Calib/PulseShapes 960 1.00E+09 + FDD/Calib/RecoParam 200 1.00E+09 + FDD/Calib/Saturation 64 3600 + FDD/Calib/Thresholds 64 1.00E+09 + FDD/Calib/TimeDelays 128 600 + FDD/Calib/TimeSlewing 256000 2.88E+04 Perhaps not needed? + + GRP/GRP/Data 1760 3600 + GRP/GRP/LHCData 235537 600 + GRP/Calib/LHCClockPhase 369 60 + GRP/Calib/MeanVertex 321 600 + GRP/Calib/RecoParam 920 1.00E+09 + GRP/CTP/Aliases 558 28800 + GRP/CTP/Config 4908 28800 + GRP/CTP/CTPtiming 699 28800 + GRP/CTP/Scalers 104057 600 + GRP/CTP/LTUConfig 401 28800 \ No newline at end of file diff --git a/Detectors/Calibration/testMacros/populateCCDB.C b/Detectors/Calibration/testMacros/populateCCDB.C new file mode 100644 index 0000000000000..d38fedf3a2397 --- /dev/null +++ b/Detectors/Calibration/testMacros/populateCCDB.C @@ -0,0 +1,116 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include <string> +#include <chrono> +#include <iostream> +#include <string> +#include <fstream> +#include <regex> +#include <unistd.h> +#include <thread> +#include <TRandom.h> +#include <TVectorF.h> +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" + +#endif + +// macro to populate the CCDB emulating the rates that we expect for +// Run 3, as read (in terms of size and rate) from an external file + +using DurSec = std::chrono::duration<double, std::ratio<1, 1>>; + +struct CCDBObj { + std::string path; + float validity; + size_t sz; + size_t count = 0; + std::decay_t<decltype(std::chrono::high_resolution_clock::now())> lastUpdate{}; + CCDBObj(const std::string& _path, size_t _sz, float _val) : path(_path), validity(_val), sz(_sz) {} +}; + +std::vector<CCDBObj> readObjectsList(const std::string& fname); +void pushObject(o2::ccdb::CcdbApi& api, const CCDBObj& obj); + +void populateCCDB(const std::string& fname = "cdbSizeV0.txt", const std::string& ccdbHost = "http://localhost:8080" /*"http://ccdb-test.cern.ch:8080"*/) +{ + auto objs = readObjectsList(fname); + if (objs.empty()) { + return; + } + + o2::ccdb::CcdbApi api; + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + + while (true) { + auto timeLoopStart = std::chrono::high_resolution_clock::now(); + double minTLeft = 1e99; + for (auto& o : objs) { + DurSec elapsedSeconds = timeLoopStart - o.lastUpdate; + if (elapsedSeconds.count() > o.validity || !o.count) { + std::cout << "Storing entry: " << o.path << " copy " << o.count + << " after " << (o.count ? elapsedSeconds.count() : 0.) << "s\n"; + + auto uploadStart = std::chrono::high_resolution_clock::now(); + std::thread th(pushObject, std::ref(api), std::cref(o)); + th.detach(); + //pushObject(api, o); + auto uploadEnd = std::chrono::high_resolution_clock::now(); + DurSec uploadTime = uploadEnd - uploadStart; + LOG(INFO) << "Took " << uploadTime.count() << " to load " << o.sz << " bytes object"; + o.count++; + o.lastUpdate = timeLoopStart; + if (minTLeft < 0.9 * o.validity) { + minTLeft = o.validity; + } + } + } + usleep(minTLeft * 0.9 * 1e6); + } +} + +std::vector<CCDBObj> readObjectsList(const std::string& fname) +{ + std::vector<CCDBObj> objs; + std::ifstream inFile(fname); + if (!inFile.is_open()) { + LOG(ERROR) << "Failed to open input file " << fname; + return objs; + } + std::string str; + while (std::getline(inFile, str)) { + str = std::regex_replace(str, std::regex("^\\s+|\\s+$|\\s+\r\n$|\\s+\r$|\\s+\n$"), "$1"); + if (str[0] == '#' || str.empty()) { + continue; + } + std::stringstream ss(str); + std::string path; + float sz = 0.f, sec = 0.f; + ss >> path; + ss >> sz; + ss >> sec; + if (sz == 0 || sec == 0) { + LOG(ERROR) << "Invalid data for " << path; + objs.clear(); + break; + } + LOG(INFO) << "Account " << path << " size= " << sz << " validity= " << sec; + objs.emplace_back(path, sz, sec); + } + return objs; +} + +void pushObject(o2::ccdb::CcdbApi& api, const CCDBObj& obj) +{ + std::vector<uint8_t> buff(obj.sz); + for (auto& c : buff) { + c = gRandom->Integer(0xff); + } + std::map<std::string, std::string> metadata; // can be empty + metadata["responsible"] = "nobody"; + metadata["custom"] = "whatever"; + auto now = std::chrono::system_clock::now(); + auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now); + auto timeStamp = now_ms.time_since_epoch(); + api.storeAsTFileAny(&buff, obj.path, metadata, timeStamp.count(), 1670700184549); // one year validity time +} diff --git a/Detectors/Calibration/testMacros/populateCCDB.cxx b/Detectors/Calibration/testMacros/populateCCDB.cxx new file mode 100644 index 0000000000000..8ce0cb2b8e791 --- /dev/null +++ b/Detectors/Calibration/testMacros/populateCCDB.cxx @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// executable to populate the CCDB emulating the rates that we expect for +// Run 3, as read (in terms of size and rate) from an external file + +#include "populateCCDB.C" +#include <TRandom.h> +#include <boost/program_options.hpp> +#include <iostream> + +namespace bpo = boost::program_options; + +bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) +{ + options.add_options()( + "ccdb-server,s", bpo::value<std::string>()->default_value("http://ccdb-test.cern.ch:8080"), "CCDB server")( + "in-file-name,n", bpo::value<std::string>()->default_value("cdbSizeV0.txt"), "File name with list of CCDB entries to upload")( + "help,h", "Produce help message."); + + try { + bpo::store(parse_command_line(argc, argv, options), vm); + + // help + if (vm.count("help")) { + std::cout << options << std::endl; + return false; + } + + bpo::notify(vm); + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing command line arguments; Available options:\n"; + + std::cerr << options << std::endl; + return false; + } + return true; +} + +int main(int argc, char* argv[]) +{ + bpo::options_description options("Allowed options"); + bpo::variables_map vm; + if (!initOptionsAndParse(options, argc, argv, vm)) { + return -1; + } + + // call populate "macro" + auto& inputFile = vm["in-file-name"].as<std::string>(); + auto& ccdbHost = vm["ccdb-server"].as<std::string>(); + populateCCDB(inputFile, ccdbHost); + + return (0); +} diff --git a/Detectors/Calibration/testMacros/retrieveFromCCDB.C b/Detectors/Calibration/testMacros/retrieveFromCCDB.C new file mode 100644 index 0000000000000..fdcd26282a4d8 --- /dev/null +++ b/Detectors/Calibration/testMacros/retrieveFromCCDB.C @@ -0,0 +1,103 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include <string> +#include <chrono> +#include <iostream> +#include <string> +#include <fstream> +#include <vector> +#include <unistd.h> +#include "Framework/Logger.h" +#include "CCDB/BasicCCDBManager.h" +#include <pthread.h> +#include <thread> +#endif +#include "populateCCDB.C" + +using CcdbManager = o2::ccdb::CCDBManagerInstance; + +std::vector<std::unique_ptr<CcdbManager>> ccdbManPool; +std::vector<bool> ccdbManPoolFlag; +std::decay_t<decltype(std::chrono::high_resolution_clock::now())> startTime{}; + +// macro to populate the CCDB emulating the rates that we expect for +// Run 3, as read (in terms of size and rate) from an external file + +int getFreeCCDBManagerID(); +void retrieve(const std::vector<CCDBObj>& objs, float procTimeSec, int ccdbID, std::atomic<int>& n, size_t tfID); + +void retrieveFromCCDB(int maxTFs = 8, float procTimeSec = 10., + const std::string& fname = "cdbSizeV0.txt", + const std::string& ccdbHost = "http://localhost:8080" /*"http://ccdb-test.cern.ch:8080"*/, + bool allowCaching = true) +{ + ccdbManPool.resize(1 + maxTFs); + ccdbManPoolFlag.resize(ccdbManPool.size(), false); // nothig is used at the moment + LOG(INFO) << "Caching is " << (allowCaching ? "ON" : "OFF"); + for (auto& mgr : ccdbManPool) { + mgr = std::make_unique<CcdbManager>(ccdbHost.c_str()); + mgr->setCaching(allowCaching); + } + auto objs = readObjectsList(fname); + if (objs.empty()) { + return; + } + startTime = std::chrono::high_resolution_clock::now(); + + std::atomic<int> nTFs{0}; + size_t tfID = 0; + while (1) { + if (nTFs < maxTFs) { + int ccdbID = getFreeCCDBManagerID(); + if (ccdbID < 0) { // all slots are busy, wait + continue; + } + std::thread th(retrieve, std::cref(objs), procTimeSec, ccdbID, std::ref(nTFs), tfID++); + th.detach(); + LOG(INFO) << nTFs << " TFs currently in processing"; + } else { + usleep(long(procTimeSec * (0.01e6))); + } + } +} + +void retrieve(const std::vector<CCDBObj>& objs, float procTimeSec, int ccdbID, std::atomic<int>& n, size_t tfID) +{ + // function to retrieve the CCDB objects and wait some (TF processing) time + // to avoid all treads starting to read at the same time, we randomize the time of reading within the allocated processing time + auto mgr = ccdbManPool[ccdbID].get(); + n++; + float tfrac = gRandom->Rndm(); + usleep(long(procTimeSec * tfrac * 1e6)); + auto ret_start = std::chrono::high_resolution_clock::now(); + for (auto& o : objs) { + auto now = std::chrono::high_resolution_clock::now(); + auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now); + auto timeStamp = now_ms.time_since_epoch(); + std::vector<uint8_t>* ob = mgr->getForTimeStamp<std::vector<uint8_t>>(o.path, timeStamp.count()); + LOG(DEBUG) << "Retrieved object " << o.path << " of size " << ob->size() << " Bytes" + << " for TF " << tfID; + if (!mgr->isCachingEnabled()) { // we can delete object only when caching is disabled + delete ob; + } + } + auto ret_end = std::chrono::high_resolution_clock::now(); + usleep(long(procTimeSec * (1. - tfrac) * 1e6)); + std::chrono::duration<double, std::ratio<1, 1>> elapsedSeconds = std::chrono::high_resolution_clock::now() - startTime; + std::chrono::duration<double, std::ratio<1, 1>> retTime = ret_end - ret_start; + LOG(INFO) << "Finished TF " << tfID << " elapsed time " << elapsedSeconds.count() << " s., CCDB query time: " << retTime.count() << " s."; + n--; + ccdbManPoolFlag[ccdbID] = false; // release the manager +} + +int getFreeCCDBManagerID() +{ + /// get ID of 1st CCDBManager not used by any thread + for (unsigned i = 0; i < ccdbManPoolFlag.size(); i++) { + if (!ccdbManPoolFlag[i]) { + ccdbManPoolFlag[i] = true; + return i; + } + } + return -1; +} diff --git a/Detectors/Calibration/testMacros/retrieveFromCCDB.cxx b/Detectors/Calibration/testMacros/retrieveFromCCDB.cxx new file mode 100644 index 0000000000000..9ce46c3cfad98 --- /dev/null +++ b/Detectors/Calibration/testMacros/retrieveFromCCDB.cxx @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// executable to retrieve objects from CCDB emulating the rates that we expect for +// Run 3, as read (in terms of size and rate) from an external file + +#include "retrieveFromCCDB.C" +#include <TRandom.h> +#include <boost/program_options.hpp> +#include <iostream> + +namespace bpo = boost::program_options; + +bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) +{ + options.add_options()( + "TFs-in-parallel,m", bpo::value<int>()->default_value(8), "Number of TFs to simulate that access the CCDB in parallel")( + "TF-processing-time,t", bpo::value<float>()->default_value(10.), "Seconds supposed to be needed to process a TF")( + "ccdb-sercer,s", bpo::value<std::string>()->default_value("http://ccdb-test.cern.ch:8080"), "CCDB server")( + "in-file-name,n", bpo::value<std::string>()->default_value("cdbSizeV0.txt"), "File name with list of CCDB entries to upload")( + "disable-caching,d", bpo::value<bool>()->default_value(false)->implicit_value(true), "Disable CCDB caching")( + "help,h", "Produce help message."); + + try { + bpo::store(parse_command_line(argc, argv, options), vm); + + // help + if (vm.count("help")) { + std::cout << options << std::endl; + return false; + } + + bpo::notify(vm); + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing command line arguments; Available options:\n"; + + std::cerr << options << std::endl; + return false; + } + return true; +} + +int main(int argc, char* argv[]) +{ + bpo::options_description options("Allowed options"); + bpo::variables_map vm; + if (!initOptionsAndParse(options, argc, argv, vm)) { + return -1; + } + + // call populate "macro" + auto nTFs = vm["TFs-in-parallel"].as<int>(); + auto tTF = vm["TF-processing-time"].as<float>(); + auto& inputFile = vm["in-file-name"].as<std::string>(); + auto& ccdbHost = vm["ccdb-sercer"].as<std::string>(); + auto disableCaching = vm["disable-caching"].as<bool>(); + retrieveFromCCDB(nTFs, tTF, inputFile, ccdbHost, !disableCaching); + + return (0); +} diff --git a/Detectors/Calibration/testMacros/runEPNsimulation.sh b/Detectors/Calibration/testMacros/runEPNsimulation.sh new file mode 100755 index 0000000000000..44c0e8b011ad3 --- /dev/null +++ b/Detectors/Calibration/testMacros/runEPNsimulation.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +iEPN=0 +xpos_start=100 +while [[ $iEPN -lt $1 ]] +do + echo $iEPN + xpos=$((xpos_start+1000*$iEPN)) + xterm -hold -geometry 150x41+$xpos+300 -e bash -c "echo $iEPN; o2-calibration-data-generator-workflow --lanes 7 --gen-slot $iEPN --gen-norm 3 --mean-latency 100000 --max-timeframes 500 -b | o2-dpl-output-proxy --channel-config "name=downstream,method=connect,address=tcp://localhost:30453,type=push,transport=zeromq" --dataspec downstream:TOF/CALIBDATA -b ; exec bash" & + ((iEPN = iEPN +1 )) +done + diff --git a/Detectors/Calibration/workflow/CCDBPopulatorSpec.h b/Detectors/Calibration/workflow/CCDBPopulatorSpec.h index e6c70a4aa03fa..54e3ce6354211 100644 --- a/Detectors/Calibration/workflow/CCDBPopulatorSpec.h +++ b/Detectors/Calibration/workflow/CCDBPopulatorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include "Framework/Task.h" #include "Framework/CompletionPolicyHelpers.h" #include "Framework/DataRefUtils.h" +#include "Framework/DataDescriptorQueryBuilder.h" #include "Headers/DataHeader.h" #include "DetectorsCalibration/Utils.h" #include "CCDB/BasicCCDBManager.h" @@ -54,7 +56,7 @@ class CCDBPopulator : public o2::framework::Task assert(pc.inputs().getNofParts(1) == nSlots); for (int isl = 0; isl < nSlots; isl++) { - const auto wrp = pc.inputs().get<CcdbObjectInfo*>("clbInfo", isl); + const auto wrp = pc.inputs().get<CcdbObjectInfo*>("clbWrapper", isl); const auto pld = pc.inputs().get<gsl::span<char>>("clbPayload", isl); // this is actually an image of TMemFile LOG(INFO) << "Storing in ccdb " << wrp->getPath() << "/" << wrp->getFileName() << " of size " << pld.size() @@ -77,9 +79,7 @@ namespace framework DataProcessorSpec getCCDBPopulatorDeviceSpec() { using clbUtils = o2::calibration::Utils; - std::vector<InputSpec> inputs; - inputs.emplace_back("clbPayload", ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - inputs.emplace_back("clbInfo", ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + std::vector<InputSpec> inputs = {{"clbPayload", "CLP"}, {"clbWrapper", "CLW"}}; return DataProcessorSpec{ "ccdb-populator", diff --git a/Detectors/Calibration/workflow/CMakeLists.txt b/Detectors/Calibration/workflow/CMakeLists.txt index 7e7375d613a9e..69e17e0666dd6 100644 --- a/Detectors/Calibration/workflow/CMakeLists.txt +++ b/Detectors/Calibration/workflow/CMakeLists.txt @@ -1,31 +1,31 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsCalibrationWorkflow SOURCES src/MeanVertexCalibratorSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - O2::Headers - O2::CCDB - O2::CommonUtils - ms_gsl::ms_gsl - O2::ReconstructionDataFormats - O2::DataFormatsCalibration - O2::DetectorsCalibration) - + PUBLIC_LINK_LIBRARIES O2::Framework + O2::Headers + O2::CCDB + O2::CommonUtils + Microsoft.GSL::GSL + O2::ReconstructionDataFormats + O2::DataFormatsCalibration + O2::DetectorsCalibration) o2_add_executable(mean-vertex-calibration-workflow COMPONENT_NAME calibration SOURCES src/mean-vertex-calibration-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::DetectorsCalibration - O2::DetectorsCalibrationWorkflow - O2::ReconstructionDataFormats - O2::DataFormatsCalibration - O2::CCDB) + O2::DetectorsCalibration + O2::DetectorsCalibrationWorkflow + O2::ReconstructionDataFormats + O2::DataFormatsCalibration + O2::CCDB) diff --git a/Detectors/Calibration/workflow/ccdb-populator-workflow.cxx b/Detectors/Calibration/workflow/ccdb-populator-workflow.cxx index 6b3466895b9ca..211a01a7be370 100644 --- a/Detectors/Calibration/workflow/ccdb-populator-workflow.cxx +++ b/Detectors/Calibration/workflow/ccdb-populator-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,9 +11,20 @@ #include "Framework/DataProcessorSpec.h" #include "CCDBPopulatorSpec.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector<o2::framework::CompletionPolicy>& policies) { @@ -29,6 +41,7 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); specs.emplace_back(getCCDBPopulatorDeviceSpec()); return specs; } diff --git a/Detectors/Calibration/workflow/include/DetectorsCalibrationWorkflow/MeanVertexCalibratorSpec.h b/Detectors/Calibration/workflow/include/DetectorsCalibrationWorkflow/MeanVertexCalibratorSpec.h index 3fc11e625e4f2..226ff22d19d08 100644 --- a/Detectors/Calibration/workflow/include/DetectorsCalibrationWorkflow/MeanVertexCalibratorSpec.h +++ b/Detectors/Calibration/workflow/include/DetectorsCalibrationWorkflow/MeanVertexCalibratorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Calibration/workflow/src/MeanVertexCalibratorSpec.cxx b/Detectors/Calibration/workflow/src/MeanVertexCalibratorSpec.cxx index a43f9568496a3..cdb0ce5375514 100644 --- a/Detectors/Calibration/workflow/src/MeanVertexCalibratorSpec.cxx +++ b/Detectors/Calibration/workflow/src/MeanVertexCalibratorSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -88,8 +89,9 @@ void MeanVertexCalibDevice::sendOutput(DataAllocator& output) auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, i}, *image.get()); // vector<char> - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, i}, w); // root-serialized + + output.snapshot(Output{clbUtils::gDataOriginCDBPayload, "MEANVERTEX", i}, *image.get()); // vector<char> + output.snapshot(Output{clbUtils::gDataOriginCDBWrapper, "MEANVERTEX", i}, w); // root-serialized } if (payloadVec.size()) { mCalibrator->initOutput(); // reset the outputs once they are already sent @@ -107,8 +109,8 @@ DataProcessorSpec getMeanVertexCalibDeviceSpec() using clbUtils = o2::calibration::Utils; std::vector<OutputSpec> outputs; - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "MEANVERTEX"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "MEANVERTEX"}); return DataProcessorSpec{ "mean-vertex-calibration", diff --git a/Detectors/Calibration/workflow/src/mean-vertex-calibration-workflow.cxx b/Detectors/Calibration/workflow/src/mean-vertex-calibration-workflow.cxx index 030a201ef954d..337690ec5104d 100644 --- a/Detectors/Calibration/workflow/src/mean-vertex-calibration-workflow.cxx +++ b/Detectors/Calibration/workflow/src/mean-vertex-calibration-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,14 +11,17 @@ #include "Framework/DataProcessorSpec.h" #include "DetectorsCalibrationWorkflow/MeanVertexCalibratorSpec.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; -// we need to add workflow options before including Framework/runDataProcessing // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + std::swap(workflowOptions, options); } // ------------------------------------------------------------------ @@ -27,6 +31,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); specs.emplace_back(getMeanVertexCalibDeviceSpec()); return specs; } diff --git a/Detectors/DCS/CMakeLists.txt b/Detectors/DCS/CMakeLists.txt index 1d037f297f6da..fed7b42795576 100644 --- a/Detectors/DCS/CMakeLists.txt +++ b/Detectors/DCS/CMakeLists.txt @@ -1,42 +1,63 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library(DetectorsDCS - TARGETVARNAME targetName - SOURCES src/Clock.cxx - src/DataPointCompositeObject.cxx - src/DataPointIdentifier.cxx - src/DataPointValue.cxx - src/DeliveryType.cxx - src/GenericFunctions.cxx - src/StringUtils.cxx - src/DCSProcessor.cxx - PUBLIC_LINK_LIBRARIES O2::Headers - O2::CommonUtils - O2::CCDB - O2::DetectorsCalibration - ms_gsl::ms_gsl) +# add_compile_options(-O0 -g -fPIC) -o2_target_root_dictionary(DetectorsDCS - HEADERS include/DetectorsDCS/DataPointCompositeObject.h - include/DetectorsDCS/DataPointIdentifier.h - include/DetectorsDCS/DataPointValue.h - include/DetectorsDCS/DCSProcessor.h) +o2_add_library( + DetectorsDCS + TARGETVARNAME targetName + SOURCES src/AliasExpander.cxx + src/DataPointCompositeObject.cxx + src/DataPointCreator.cxx + src/DataPointGenerator.cxx + src/DataPointIdentifier.cxx + src/DataPointValue.cxx + src/DeliveryType.cxx + src/GenericFunctions.cxx + src/StringUtils.cxx + src/Clock.cxx + PUBLIC_LINK_LIBRARIES O2::Headers O2::CommonUtils O2::CCDB + O2::DetectorsCalibration Microsoft.GSL::GSL) -o2_add_executable(dcs-data-workflow - COMPONENT_NAME dcs - SOURCES testWorkflow/dcs-data-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::Framework - O2::DetectorsDCS) +o2_target_root_dictionary( + DetectorsDCS + HEADERS include/DetectorsDCS/DataPointCompositeObject.h + include/DetectorsDCS/DataPointIdentifier.h + include/DetectorsDCS/DataPointValue.h) -if (OpenMP_CXX_FOUND) - target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) - target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +if(OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) endif() + +if(BUILD_TESTING) + o2_add_test( + data-point-types + SOURCES test/testDataPointTypes.cxx + COMPONENT_NAME dcs + LABELS "dcs" + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsDCS) + o2_add_test( + alias-expander + SOURCES test/testAliasExpander.cxx + COMPONENT_NAME dcs + LABELS "dcs" + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsDCS) + o2_add_test( + data-point-generator + SOURCES test/testDataPointGenerator.cxx + COMPONENT_NAME dcs + LABELS "dcs" + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsDCS) + add_subdirectory(testWorkflow/macros) +endif() + +add_subdirectory(testWorkflow) diff --git a/Detectors/DCS/README.md b/Detectors/DCS/README.md new file mode 100644 index 0000000000000..fc5845ccfe76f --- /dev/null +++ b/Detectors/DCS/README.md @@ -0,0 +1,28 @@ +<!-- doxy +\page refDetectorsDCS DCS +/doxy --> + +# Export of DCS to CCDB + +To be written + +# Generating DCS aliases + +For test purposes, DCS aliases can be generated making use of the helper +function `generateRandomDataPoints`. For example : + +```c++ +#include "DetectorsDCS/DataPointGenerator.h" +std::vector<std::string> patterns = { "DET/HV/Crate[0.9]/Channel[00.42]/vMon" }; +auto dps = o2::dcs::generateRandomDataPoints(patterns,0.0,1200.0); +``` + +would generate 420 data points. + +# Example of DCS processing + +See README in https://github.com/AliceO2Group/AliceO2/tree/dev/Detectors/TOF/calibration/testWorkflow + +<!-- doxy +* \subpage refDetectorsDCStestWorkflow +/doxy --> diff --git a/Detectors/DCS/include/DetectorsDCS/AliasExpander.h b/Detectors/DCS/include/DetectorsDCS/AliasExpander.h new file mode 100644 index 0000000000000..386c99fcbda1e --- /dev/null +++ b/Detectors/DCS/include/DetectorsDCS/AliasExpander.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_ALIAS_EXPANDER_H +#define O2_DCS_ALIAS_EXPANDER_H + +#include <vector> +#include <string> + +namespace o2::dcs +{ +/** + * expandAlias converts a single pattern into a list of strings. + * + * @param pattern a pattern is made of a number of "XX[YY]" blocks (at least one) + * + * where : + * - XX is any text + * - YY describes either a integral range or a textual list + * + * An integral range is [a..b] where the formatting of the biggest of the + * two integers a and b dictates, by default, the formatting of the output + * alias. For instance [0..3] is expanded to the set 0,1,2,3 while [00..03] + * is expanded to 00,01,02,03. If you want more control on the formatting, + * you can use a python/fmt format {} e.g. [0..15{:d}] would yields 0,1, + * 2,...,14,15 simply (no 0 filling). + * + * A textual list is simply a list of values separated by commas, + * e.g. "vMon,iMon" + * + * @returns a vector of strings containing all the possible expansions of + * the pattern. That vector is not guaranteed to be sorted. + * + * For example, pattern=DET[A,B]/Channel[000,002]/[iMon,vMon] yields : + * + * - DETA/Channel000/iMon + * - DETA/Channel001/iMon + * - DETA/Channel002/iMon + * - DETA/Channel000/vMon + * - DETA/Channel001/vMon + * - DETA/Channel002/vMon + * - DETB/Channel000/iMon + * - DETB/Channel001/iMon + * - DETB/Channel002/iMon + * - DETB/Channel000/vMon + * - DETB/Channel001/vMon + * - DETB/Channel002/vMon + +*/ +std::vector<std::string> expandAlias(const std::string& pattern); + +/** expandAliases converts a list of patterns into a list of strings. + * + * each input pattern is treated by expandAlias() + * + * @returns a _sorted_ vector of strings containing all the possible + * expansions of the pattern. + */ +std::vector<std::string> expandAliases(const std::vector<std::string>& patternedAliases); +} // namespace o2::dcs + +#endif diff --git a/Detectors/DCS/include/DetectorsDCS/Clock.h b/Detectors/DCS/include/DetectorsDCS/Clock.h index 506626828c6aa..263fc698e508d 100644 --- a/Detectors/DCS/include/DetectorsDCS/Clock.h +++ b/Detectors/DCS/include/DetectorsDCS/Clock.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/include/DetectorsDCS/DCSProcessor.h b/Detectors/DCS/include/DetectorsDCS/DCSProcessor.h deleted file mode 100644 index 8f19d1eeae923..0000000000000 --- a/Detectors/DCS/include/DetectorsDCS/DCSProcessor.h +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef DETECTOR_DCS_DCSPROCESSOR_H_ -#define DETECTOR_DCS_DCSPROCESSOR_H_ - -#include <memory> -#include <Rtypes.h> -#include <unordered_map> -#include <deque> -#include <numeric> -#include "Framework/Logger.h" -#include "DetectorsDCS/DataPointCompositeObject.h" -#include "DetectorsDCS/DataPointIdentifier.h" -#include "DetectorsDCS/DataPointValue.h" -#include "DetectorsDCS/DeliveryType.h" -#include "CCDB/CcdbObjectInfo.h" -#include "CommonUtils/MemFileHelper.h" -#include "CCDB/CcdbApi.h" - -//#ifdef WITH_OPENMP -//#include <omp.h> -//#endif - -/// @brief Class to process DCS data points - -namespace o2 -{ -namespace dcs -{ - -class DCSProcessor -{ - - public: - using Ints = std::vector<int>; - using Chars = std::vector<char>; - using Doubles = std::vector<double>; - using Binaries = std::array<uint64_t, 7>; - using Strings = std::array<char, 56>; - - using DQChars = std::deque<char>; - using DQInts = std::deque<int>; - using DQDoubles = std::deque<double>; - using DQUInts = std::deque<uint32_t>; - using DQBools = std::deque<bool>; - using DQStrings = std::deque<Strings>; - using DQTimes = std::deque<uint32_t>; - using DQBinaries = std::deque<Binaries>; - - using DPID = o2::dcs::DataPointIdentifier; - using DPVAL = o2::dcs::DataPointValue; - using DPCOM = o2::dcs::DataPointCompositeObject; - - using TFType = uint64_t; - using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; - - DCSProcessor() = default; - ~DCSProcessor() = default; - - void init(const std::vector<DPID>& pidschars, const std::vector<DPID>& pidsints, - const std::vector<DPID>& pidsdoubles, const std::vector<DPID>& pidsUints, - const std::vector<DPID>& pidsbools, const std::vector<DPID>& pidsstrings, - const std::vector<DPID>& pidstimes, const std::vector<DPID>& pidsbinaries); - - void init(const std::vector<DPID>& pids); - - int processMap(const std::unordered_map<DPID, DPVAL>& map, bool isDelta = false); - - int processDP(const std::pair<DPID, DPVAL>& dpcom); - - std::unordered_map<DPID, DPVAL>::const_iterator findAndCheckPid(const DPID& pid, DeliveryType type, - const std::unordered_map<DPID, DPVAL>& map); - - template <typename T> - int processArrayType(const std::vector<DPID>& array, DeliveryType type, const std::unordered_map<DPID, DPVAL>& map, - std::vector<uint64_t>& latestTimeStamp, std::unordered_map<DPID, std::deque<T>>& destmap); - - template <typename T> - void checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, T>& destmap); - - virtual void processCharDP(const DPID& pid); - virtual void processIntDP(const DPID& pid); - virtual void processDoubleDP(const DPID& pid); - virtual void processUIntDP(const DPID& pid); - virtual void processBoolDP(const DPID& pid); - virtual void processStringDP(const DPID& pid); - virtual void processTimeDP(const DPID& pid); - virtual void processBinaryDP(const DPID& pid); - - virtual uint64_t processFlag(uint64_t flag, const char* pid); - - template <typename T> - void doSimpleMovingAverage(int nelements, std::deque<T>& vect, float& avg, bool& isSMA); - - DQChars& getVectorForPidChar(const DPID& id) { return mDpscharsmap[id]; } - DQInts& getVectorForPidInt(const DPID& id) { return mDpsintsmap[id]; } - DQDoubles& getVectorForPidDouble(const DPID& id) { return mDpsdoublesmap[id]; } - DQUInts& getVectorForPidUInt(const DPID& id) { return mDpsUintsmap[id]; } - DQBools& getVectorForPidBool(const DPID& id) { return mDpsboolsmap[id]; } - DQStrings& getVectorForPidString(const DPID& id) { return mDpsstringsmap[id]; } - DQTimes& getVectorForPidTime(const DPID& id) { return mDpstimesmap[id]; } - DQBinaries& getVectorForPidBinary(const DPID& id) { return mDpsbinariesmap[id]; } - - void setNThreads(int n); - int getNThreads() const { return mNThreads; } - const std::unordered_map<std::string, float>& getCCDBSimpleMovingAverage() const { return mccdbSimpleMovingAverage; } - const CcdbObjectInfo& getCCDBSimpleMovingAverageInfo() const { return mccdbSimpleMovingAverageInfo; } - CcdbObjectInfo& getCCDBSimpleMovingAverageInfo() { return mccdbSimpleMovingAverageInfo; } - - void setTF(TFType tf) { mTF = tf; } - - void setIsDelta(bool isDelta) { mIsDelta = isDelta; } - void isDelta() { mIsDelta = true; } - bool getIsDelta() const { return mIsDelta; } - - void setMaxCyclesNoFullMap(uint64_t maxCycles) { mMaxCyclesNoFullMap = maxCycles; } - uint64_t getMaxCyclesNoFullMap() const { return mMaxCyclesNoFullMap; } - - uint64_t getNCyclesNoFullMap() const { return mNCyclesNoFullMap; } - - template <typename T> - void prepareCCDBobject(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, - const std::map<std::string, std::string>& md); - - void setName(std::string name) { mName = name; } - const std::string getName() const { return mName; } - - private: - bool mFullMapSent = false; // set to true as soon as a full map was sent. No delta can - // be received if there was never a full map sent - int64_t mNCyclesNoFullMap = 0; // number of times the delta was sent withoug a full map - int64_t mMaxCyclesNoFullMap = 6000; // max number of times when the delta can be sent between - // two full maps (assuming DCS sends data every 50 ms, this - // means a 5 minutes threshold) - bool mIsDelta = false; // set to true in case you are processing delta map - // (containing only DPs that changed) - std::unordered_map<DPID, float> mSimpleMovingAverage; // moving average for several DPs - std::unordered_map<DPID, DQChars> mDpscharsmap; - std::unordered_map<DPID, DQInts> mDpsintsmap; - std::unordered_map<DPID, DQDoubles> mDpsdoublesmap; - std::unordered_map<DPID, DQUInts> mDpsUintsmap; - std::unordered_map<DPID, DQBools> mDpsboolsmap; - std::unordered_map<DPID, DQStrings> mDpsstringsmap; - std::unordered_map<DPID, DQTimes> mDpstimesmap; - std::unordered_map<DPID, DQBinaries> mDpsbinariesmap; - std::vector<DPID> mPidschars; - std::vector<DPID> mPidsints; - std::vector<DPID> mPidsdoubles; - std::vector<DPID> mPidsUints; - std::vector<DPID> mPidsbools; - std::vector<DPID> mPidsstrings; - std::vector<DPID> mPidstimes; - std::vector<DPID> mPidsbinaries; - std::unordered_map<DPID, int> mPids; // contains all PIDs for the current processor; the value correspond to the index - // in the mPidschars/ints/doubles.. vectors - std::vector<uint64_t> mLatestTimestampchars; - std::vector<uint64_t> mLatestTimestampints; - std::vector<uint64_t> mLatestTimestampdoubles; - std::vector<uint64_t> mLatestTimestampUints; - std::vector<uint64_t> mLatestTimestampbools; - std::vector<uint64_t> mLatestTimestampstrings; - std::vector<uint64_t> mLatestTimestamptimes; - std::vector<uint64_t> mLatestTimestampbinaries; - int mNThreads = 1; // number of threads - std::unordered_map<std::string, float> mccdbSimpleMovingAverage; // unordered map in which to store the CCDB entry - // for the DPs for which we calculated the simple - // moving average - CcdbObjectInfo mccdbSimpleMovingAverageInfo; // info to store the output of the calibration for - // the DPs for which we calculated - // the simple moving average - TFType mTF = 0; // TF index for processing, - // used to store CCDB object - std::string mName = ""; // to be used to determine CCDB path - - ClassDefNV(DCSProcessor, 0); -}; - -using Ints = std::vector<int>; -using Chars = std::vector<char>; -using Doubles = std::vector<double>; -using Binaries = std::array<uint64_t, 7>; -using Strings = std::array<char, 56>; - -using DQStrings = std::deque<Strings>; -using DQBinaries = std::deque<Binaries>; - -using DPID = o2::dcs::DataPointIdentifier; -using DPVAL = o2::dcs::DataPointValue; - -template <typename T> -int DCSProcessor::processArrayType(const std::vector<DPID>& array, - DeliveryType type, const std::unordered_map<DPID, DPVAL>& map, - std::vector<uint64_t>& latestTimeStamp, - std::unordered_map<DPID, std::deque<T>>& destmap) -{ - - // processing the array of type T - - int found = 0; - //#ifdef WITH_OPENMP - //omp_set_num_threads(mNThreads); - //#pragma omp parallel for schedule(dynamic) - //#endif - for (size_t i = 0; i != array.size(); ++i) { - auto it = findAndCheckPid(array[i], type, map); - if (it == map.end()) { - if (!mIsDelta) { - LOG(ERROR) << "Element " << array[i] << " not found " << std::endl; - } - continue; - } - found++; - std::pair<DPID, DPVAL> pairIt = *it; - checkFlagsAndFill(pairIt, latestTimeStamp[i], destmap); - if (type == RAW_CHAR) { - processCharDP(array[i]); - } else if (type == RAW_INT) { - processIntDP(array[i]); - } else if (type == RAW_DOUBLE) { - processDoubleDP(array[i]); - } else if (type == RAW_UINT) { - processUIntDP(array[i]); - } else if (type == RAW_BOOL) { - processBoolDP(array[i]); - } else if (type == RAW_STRING) { - processStringDP(array[i]); - } else if (type == RAW_TIME) { - processTimeDP(array[i]); - } else if (type == RAW_BINARY) { - processBinaryDP(array[i]); - } - // todo: better to move the "found++" after the process, in case it fails? - } - return found; -} - -//______________________________________________________________________ - -template <typename T> -void DCSProcessor::checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, T>& destmap) -{ - - // check the flags for the upcoming data, and if ok, fill the accumulator - - auto& dpid = dpcom.first; - auto& val = dpcom.second; - auto flags = val.get_flags(); - if (processFlag(flags, dpid.get_alias()) == 0) { - auto etime = val.get_epoch_time(); - // fill only if new value has a timestamp different from the timestamp of the previous one - LOG(DEBUG) << "destmap[pid].size() = " << destmap[dpid].size(); - if (destmap[dpid].size() == 0 || etime != latestTimeStamp) { - LOG(DEBUG) << "adding new value"; - destmap[dpid].push_back(val.payload_pt1); - latestTimeStamp = etime; - } - } -} - -//______________________________________________________________________ - -template <> -void DCSProcessor::checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, DCSProcessor::DQStrings>& destmap); - -//______________________________________________________________________ - -template <> -void DCSProcessor::checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, DCSProcessor::DQBinaries>& destmap); - -//______________________________________________________________________ - -template <typename T> -void DCSProcessor::doSimpleMovingAverage(int nelements, std::deque<T>& vect, float& avg, bool& isSMA) -{ - - // Do simple moving average on vector of type T - - if (vect.size() <= nelements) { - //avg = std::accumulate(vect.begin(), vect.end(), 0.0) / vect.size(); - avg = (avg * (vect.size() - 1) + vect.back()) / vect.size(); - return; - } - - avg += (vect[vect.size() - 1] - vect[0]) / nelements; - vect.pop_front(); - isSMA = true; -} - -//______________________________________________________________________ - -template <typename T> -void DCSProcessor::prepareCCDBobject(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, - const std::map<std::string, std::string>& md) -{ - - // prepare all info to be sent to CCDB for object obj - auto clName = o2::utils::MemFileHelper::getClassName(obj); - auto flName = o2::ccdb::CcdbApi::generateFileName(clName); - info.setPath(path); - info.setObjectType(clName); - info.setFileName(flName); - info.setStartValidityTimestamp(tf); - info.setEndValidityTimestamp(99999999999999); - info.setMetaData(md); -} -} // namespace dcs -} // namespace o2 - -#endif diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h b/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h index fea0bab7dfca0..3929dc52943e7 100644 --- a/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h +++ b/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -79,6 +80,19 @@ struct alignas(128) DataPointCompositeObject final { const DataPointIdentifier& id, const DataPointValue& data) noexcept : id(id), data(data) {} + /** + * Copy constructor + */ + DataPointCompositeObject(const DataPointCompositeObject& src) noexcept : DataPointCompositeObject(src.id, src.data) {} + + DataPointCompositeObject& operator=(const DataPointCompositeObject& src) noexcept + { + if (&src != this) { + memcpy(this, &src, sizeof(DataPointCompositeObject)); + } + return *this; + } + /** * Bit-by bit equality comparison of DataPointCompositeObjects. * @@ -173,6 +187,7 @@ struct alignas(128) DataPointCompositeObject final { case RAW_TIME: case RAW_STRING: case RAW_BINARY: + case RAW_FLOAT: return (void*)&data.payload_pt1; case DPVAL_INT: case DPVAL_UINT: @@ -182,6 +197,7 @@ struct alignas(128) DataPointCompositeObject final { case DPVAL_TIME: case DPVAL_STRING: case DPVAL_BINARY: + case DPVAL_FLOAT: return (void*)&data; default: case VOID: @@ -205,6 +221,7 @@ struct alignas(128) DataPointCompositeObject final { os << dpcom.id << ";" << dpcom.data << ";"; union Converter { uint64_t raw_data; + float float_value; double double_value; uint32_t uint_value; int32_t int_value; @@ -227,6 +244,9 @@ struct alignas(128) DataPointCompositeObject final { case RAW_CHAR: case DPVAL_CHAR: return os << converter.char_value; + case RAW_FLOAT: + case DPVAL_FLOAT: + return os << converter.float_value; case RAW_DOUBLE: case DPVAL_DOUBLE: return os << converter.double_value; @@ -254,9 +274,49 @@ struct alignas(128) DataPointCompositeObject final { (char*)&dpcom.data.payload_pt1, 56); } } + + /** + * The destructor for DataPointCompositeObject so it is not deleted + * and thus DataPointCompositeObject is trivially copyable + */ + ~DataPointCompositeObject() noexcept = default; ClassDefNV(DataPointCompositeObject, 1); }; + +/** + * Return the value contained in the DataPointCompositeObject, if possible. + * + * @tparam T the expected type of the value + * + * @param dpcom the DataPointCompositeObject the value is extracted from + * + * @returns the value of the data point + * + * @throws if the DeliveryType of the data point is not compatible with T + */ +template <typename T> +T getValue(const DataPointCompositeObject& dpcom); + } // namespace dcs + +/// Defining DataPointCompositeObject explicitly as messageable +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::dcs::DataPointCompositeObject> : std::true_type { +}; +} // namespace framework + } // namespace o2 +/// Defining DataPointCompositeObject explicitly as copiable +namespace std +{ +template <> +struct is_trivially_copyable<o2::dcs::DataPointCompositeObject> : std::true_type { +}; +} // namespace std + #endif /* O2_DCS_DATAPOINT_COMPOSITE_OBJECT_H */ diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointCreator.h b/Detectors/DCS/include/DetectorsDCS/DataPointCreator.h new file mode 100644 index 0000000000000..54cfb6ab29a11 --- /dev/null +++ b/Detectors/DCS/include/DetectorsDCS/DataPointCreator.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_DATAPOINT_CREATOR_H +#define O2_DCS_DATAPOINT_CREATOR_H + +#include "DataPointCompositeObject.h" + +namespace o2::dcs +{ +/** + * createDataPointCompositeObject is a convenience function to + * simplify the creation of a DataPointCompositeObject. + * + * @param alias the DataPoint alias name (max 56 characters) + * @param val the value of the datapoint + * @param flags value for ADAPOS flags. + * @param milliseconds value for milliseconds. + * @param seconds value for seconds. + * + * @returns a DataPointCompositeObject + * + * The actual DeliveryType of the returned + * DataPointCompositeObject is deduced from the type of val. + * + * Note that only a few relevant specialization are actually provided + * + * - T=int32_t : DeliveryType = RAW_INT + * - T=uint32_t : DeliveryType = RAW_UINT + * - T=float : DeliveryType = RAW_FLOAT + * - T=double : DeliveryType = RAW_DOUBLE + * - T=bool : DeliveryType = RAW_BOOL + * - T=char : DeliveryType = RAW_CHAR + * - T=std::string : DeliveryType = RAW_STRING + * + */ +template <typename T> +o2::dcs::DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, T val, uint32_t seconds, uint16_t msec, uint16_t flags = 0); +} // namespace o2::dcs + +#endif diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointGenerator.h b/Detectors/DCS/include/DetectorsDCS/DataPointGenerator.h new file mode 100644 index 0000000000000..ae9390e2302db --- /dev/null +++ b/Detectors/DCS/include/DetectorsDCS/DataPointGenerator.h @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_DATAPOINT_GENERATOR_H +#define O2_DCS_DATAPOINT_GENERATOR_H + +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include <vector> + +namespace o2::dcs +{ +/** +* Generate random data points, uniformly distributed between two values. +* +* @tparam T the type of value of the data points to be generated. Only +* a few types are supported : double, float, uint32_t, int32_t, char, bool +* +* @param aliases the list of aliases to be generated. Those can use +* patterns that will be expanded, @see AliasExpander +* @param minValue the minimum value of the values to be generated +* @param maxValue the maximum value of the values to be generated +* @param refDate the date to be associated with all data points +* in `%Y-%b-%d %H:%M:%S` format. If refDate="" the current date is used. +* +* @returns a vector of DataPointCompositeObject objects +*/ +template <typename T> +std::vector<DataPointCompositeObject> generateRandomDataPoints(const std::vector<std::string>& aliases, + T min, + T max, + std::string refDate = ""); + +} // namespace o2::dcs + +#endif diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h b/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h index a5ace31a62e17..32397b1ace0b0 100644 --- a/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h +++ b/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,8 @@ #include <iostream> #include <iomanip> #include <functional> +#include <unordered_map> + #include "Rtypes.h" #include "DetectorsDCS/StringUtils.h" #include "DetectorsDCS/GenericFunctions.h" @@ -79,6 +82,19 @@ class alignas(64) DataPointIdentifier final ((char*)&pt8)[7] = type; } + /** + * A copy constructor for DataPointIdentifier. + */ + DataPointIdentifier(const DataPointIdentifier& src) noexcept : DataPointIdentifier(src.pt1, src.pt2, src.pt3, src.pt4, src.pt5, src.pt6, src.pt7, src.pt8) {} + + DataPointIdentifier& operator=(const DataPointIdentifier& src) noexcept + { + if (&src != this) { + memcpy(this, &src, sizeof(DataPointIdentifier)); + } + return *this; + } + /** * This stati procedure fills the given DataPointIdentifier object with * the given parameters. @@ -202,6 +218,16 @@ struct DPIDHash { }; } // namespace dcs +/// Defining DataPointIdentifier explicitly as messageable +namespace framework +{ +template <typename T> +struct is_messageable; +template <> +struct is_messageable<o2::dcs::DataPointIdentifier> : std::true_type { +}; +} // namespace framework + } // namespace o2 // specailized std::hash @@ -214,6 +240,11 @@ struct hash<o2::dcs::DataPointIdentifier> { return std::hash<uint64_t>{}(dpid.hash_code()); } }; + +template <> +struct is_trivially_copyable<o2::dcs::DataPointIdentifier> : std::true_type { +}; + } // namespace std #endif /* O2_DCS_DATAPOINT_IDENTIFIER_H */ diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointValue.h b/Detectors/DCS/include/DetectorsDCS/DataPointValue.h index c32c4e04128b8..021e8bdf0beba 100644 --- a/Detectors/DCS/include/DetectorsDCS/DataPointValue.h +++ b/Detectors/DCS/include/DetectorsDCS/DataPointValue.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -390,6 +391,8 @@ struct alignas(64) DataPointValue final { case DPVAL_INT: case RAW_UINT: case DPVAL_UINT: + case RAW_FLOAT: + case DPVAL_FLOAT: this->payload_pt1 = data[0] & 0x00000000FFFFFFFF; break; case RAW_BOOL: @@ -459,9 +462,9 @@ struct alignas(64) DataPointValue final { */ inline std::unique_ptr<std::string> get_timestamp() const noexcept { -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) // time_t should be uint64_t (compatible) on 64-bit Linux platforms: - char buffer[17]; + char buffer[33]; std::time_t ts((uint64_t)sec); std::strftime(buffer, 32, "%FT%T", std::gmtime(&ts)); std::ostringstream oss; diff --git a/Detectors/DCS/include/DetectorsDCS/DeliveryType.h b/Detectors/DCS/include/DetectorsDCS/DeliveryType.h index 8da5b2452f1bc..236d9eb084759 100644 --- a/Detectors/DCS/include/DetectorsDCS/DeliveryType.h +++ b/Detectors/DCS/include/DetectorsDCS/DeliveryType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ namespace dcs * This regular expression matches with strings representing payload types. */ static const std::regex REGEX_PT( - "^(Raw|DPVAL)/(Int|Uint|Double|Bool|Char|String|Time|Binary)$"); + "^(Raw|DPVAL)/(Int|Uint|Float|Double|Bool|Char|String|Time|Binary)$"); /** * <p>DeliveryType is a piece of meta-information used for deducing types of @@ -115,6 +116,22 @@ enum DeliveryType { * numerical value of <tt>RAW_BOOL</tt> corresponds with the WinCC * constant <tt>DPEL_BOOL</tt>. */ + + RAW_FLOAT = 28, + + /** + * <tt>Float</tt> stands for IEEE 754 single precision floating point + * number (64 bit). This is the raw variant. The numerical value of + * <tt>RAW_INT</tt> corresponds with the WinCC constant + * <tt>DPEL_FLOAT</tt>. + */ + DPVAL_FLOAT = 156, + + /** + * <tt>Float</tt> stands for IEEE 754 single precision floating point + * number (64 bit). This is the DPVAL variant. + */ + RAW_BOOL = 23, /** @@ -171,6 +188,8 @@ inline DeliveryType read(const std::string& str) return RAW_INT; } else if (str == "Raw/Uint") { return RAW_UINT; + } else if (str == "Raw/Float") { + return RAW_FLOAT; } else if (str == "Raw/Double") { return RAW_DOUBLE; } else if (str == "Raw/Bool") { @@ -187,6 +206,8 @@ inline DeliveryType read(const std::string& str) return DPVAL_INT; } else if (str == "DPVAL/Uint") { return DPVAL_UINT; + } else if (str == "DPVAL/Float") { + return DPVAL_FLOAT; } else if (str == "DPVAL/Double") { return DPVAL_DOUBLE; } else if (str == "DPVAL/Bool") { @@ -219,6 +240,8 @@ inline std::string show(const DeliveryType type) return "Raw/Bool"; case RAW_CHAR: return "Raw/Char"; + case RAW_FLOAT: + return "Raw/Float"; case RAW_DOUBLE: return "Raw/Double"; case RAW_TIME: @@ -235,6 +258,8 @@ inline std::string show(const DeliveryType type) return "DPVAL/Bool"; case DPVAL_CHAR: return "DPVAL/Char"; + case DPVAL_FLOAT: + return "DPVAL/Float"; case DPVAL_DOUBLE: return "DPVAL/Double"; case DPVAL_TIME: @@ -265,6 +290,7 @@ inline bool DPVAL_variant(const DeliveryType type) case DPVAL_UINT: case DPVAL_BOOL: case DPVAL_CHAR: + case DPVAL_FLOAT: case DPVAL_DOUBLE: case DPVAL_TIME: case DPVAL_STRING: @@ -274,6 +300,7 @@ inline bool DPVAL_variant(const DeliveryType type) case RAW_UINT: case RAW_BOOL: case RAW_CHAR: + case RAW_FLOAT: case RAW_DOUBLE: case RAW_TIME: case RAW_STRING: @@ -305,6 +332,8 @@ inline std::string dim_description(const DeliveryType type) return "I:1"; case RAW_CHAR: return "C:4"; + case RAW_FLOAT: + return "F:1"; case RAW_DOUBLE: return "D:1"; case RAW_TIME: @@ -321,6 +350,8 @@ inline std::string dim_description(const DeliveryType type) return "S:2;I:1;I:1"; case DPVAL_CHAR: return "S:2;I:1;C:4"; + case DPVAL_FLOAT: + return "S:2;I:1;F:1"; case DPVAL_DOUBLE: return "S:2;I:1;D:1"; case DPVAL_TIME: @@ -350,6 +381,7 @@ inline size_t dim_buffer_size(const DeliveryType type) case RAW_UINT: case RAW_BOOL: case RAW_CHAR: + case RAW_FLOAT: return 4; case RAW_DOUBLE: case RAW_TIME: @@ -362,6 +394,7 @@ inline size_t dim_buffer_size(const DeliveryType type) case DPVAL_UINT: case DPVAL_BOOL: case DPVAL_CHAR: + case DPVAL_FLOAT: case DPVAL_DOUBLE: case DPVAL_TIME: case DPVAL_STRING: diff --git a/Detectors/DCS/include/DetectorsDCS/GenericFunctions.h b/Detectors/DCS/include/DetectorsDCS/GenericFunctions.h index 91937d33f30a3..81d825c72652b 100644 --- a/Detectors/DCS/include/DetectorsDCS/GenericFunctions.h +++ b/Detectors/DCS/include/DetectorsDCS/GenericFunctions.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/include/DetectorsDCS/StringUtils.h b/Detectors/DCS/include/DetectorsDCS/StringUtils.h index adf0dd2aad59d..0d0ff477a1186 100644 --- a/Detectors/DCS/include/DetectorsDCS/StringUtils.h +++ b/Detectors/DCS/include/DetectorsDCS/StringUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/AliasExpander.cxx b/Detectors/DCS/src/AliasExpander.cxx new file mode 100644 index 0000000000000..b197d2fb78d67 --- /dev/null +++ b/Detectors/DCS/src/AliasExpander.cxx @@ -0,0 +1,147 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/AliasExpander.h" +#include <algorithm> +#include <fmt/format.h> +#include <sstream> + +namespace +{ + +std::vector<std::string> splitString(const std::string& src, char delim) +{ + std::stringstream ss(src); + std::string token; + std::vector<std::string> tokens; + + while (std::getline(ss, token, delim)) { + if (!token.empty()) { + tokens.push_back(std::move(token)); + } + } + + return tokens; +} + +std::vector<std::string> extractList(const std::string& slist) +{ + auto dots = slist.find(","); + if (dots == std::string::npos) { + return {}; + } + return splitString(slist, ','); +} + +std::vector<std::string> extractRange(std::string range) +{ + auto dots = range.find(".."); + if (dots == std::string::npos) { + return extractList(range); + } + + auto braceStart = range.find("{"); + auto braceEnd = range.find("}"); + + if ( + (braceStart != std::string::npos && + braceEnd == std::string::npos) || + (braceStart == std::string::npos && + braceEnd != std::string::npos)) { + // incomplete custom pattern + return {}; + } + + std::string intFormat; + std::string sa, sb; + + if (braceStart != std::string::npos && + braceEnd != std::string::npos) { + intFormat = range.substr(braceStart, braceEnd - braceStart + 1); + range.erase(braceStart, braceEnd); + dots = range.find(".."); + sa = range.substr(0, dots); + sb = range.substr(dots + 2); + } else { + sa = range.substr(0, dots); + sb = range.substr(dots + 2); + auto size = std::max(sa.size(), sb.size()); + intFormat = "{:" + fmt::format("0{}d", size) + "}"; + } + + auto a = std::stoi(sa); + auto b = std::stoi(sb); + std::vector<std::string> result; + + for (auto i = a; i <= b; i++) { + auto substituted = fmt::format(intFormat, i); + result.push_back(substituted); + } + return result; +} +} // namespace + +namespace o2::dcs +{ +std::vector<std::string> expandAlias(const std::string& pattern) +{ + auto leftBracket = pattern.find("["); + auto rightBracket = pattern.find("]"); + + // no bracket at all -> return pattern simply + if (leftBracket == std::string::npos && rightBracket == std::string::npos) { + return {pattern}; + } + + // no matching bracket -> wrong pattern -> return nothing + if ((leftBracket == std::string::npos && + rightBracket != std::string::npos) || + (leftBracket != std::string::npos && + rightBracket == std::string::npos)) { + return {}; + } + auto rangeStr = pattern.substr(leftBracket + 1, rightBracket - leftBracket - 1); + + auto range = extractRange(rangeStr); + + // incorrect range -> return nothing + if (range.empty()) { + return {}; + } + + auto newPattern = pattern.substr(0, leftBracket) + + "{:s}" + + pattern.substr(rightBracket + 1); + + std::vector<std::string> result; + + for (auto r : range) { + auto substituted = fmt::format(newPattern, r); + result.emplace_back(substituted); + } + + return o2::dcs::expandAliases(result); +} + +std::vector<std::string> expandAliases(const std::vector<std::string>& patternedAliases) +{ + std::vector<std::string> result; + + for (auto a : patternedAliases) { + auto e = expandAlias(a); + result.insert(result.end(), e.begin(), e.end()); + } + // sort to get a predictable result + std::sort(result.begin(), result.end()); + + return result; +} +} // namespace o2::dcs diff --git a/Detectors/DCS/src/Clock.cxx b/Detectors/DCS/src/Clock.cxx index e8fb9eac9e0ea..ec5125dd9cf00 100644 --- a/Detectors/DCS/src/Clock.cxx +++ b/Detectors/DCS/src/Clock.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/DCSProcessor.cxx b/Detectors/DCS/src/DCSProcessor.cxx deleted file mode 100644 index 3b54607a6e5ee..0000000000000 --- a/Detectors/DCS/src/DCSProcessor.cxx +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <DetectorsDCS/DCSProcessor.h> -#include "Rtypes.h" -#include <deque> -#include <string> -#include <algorithm> -#include <iterator> - -using namespace o2::dcs; - -using DeliveryType = o2::dcs::DeliveryType; -using DPID = o2::dcs::DataPointIdentifier; -using DPVAL = o2::dcs::DataPointValue; - -//ClassImp(o2::dcs::DCSProcessor); - -void DCSProcessor::init(const std::vector<DPID>& pidschars, const std::vector<DPID>& pidsints, - const std::vector<DPID>& pidsdoubles, const std::vector<DPID>& pidsUints, - const std::vector<DPID>& pidsbools, const std::vector<DPID>& pidsstrings, - const std::vector<DPID>& pidstimes, const std::vector<DPID>& pidsbinaries) -{ - - // init from separate vectors of pids (one per data point type) - - // chars - for (auto it = std::begin(pidschars); it != std::end(pidschars); ++it) { - if ((*it).get_type() != DeliveryType::RAW_CHAR) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a char"; - } - mPidschars.emplace_back((*it).get_alias(), DeliveryType::RAW_CHAR); - mPids[*it] = mPidschars.size() - 1; - } - - // ints - for (auto it = std::begin(pidsints); it != std::end(pidsints); ++it) { - if ((*it).get_type() != DeliveryType::RAW_INT) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a int"; - } - mPidsints.emplace_back((*it).get_alias(), DeliveryType::RAW_INT); - mPids[*it] = mPidsints.size() - 1; - } - - // doubles - for (auto it = std::begin(pidsdoubles); it != std::end(pidsdoubles); ++it) { - if ((*it).get_type() != DeliveryType::RAW_DOUBLE) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a double"; - } - mPidsdoubles.emplace_back((*it).get_alias(), DeliveryType::RAW_DOUBLE); - mPids[*it] = mPidsdoubles.size() - 1; - } - - // uints - for (auto it = std::begin(pidsUints); it != std::end(pidsUints); ++it) { - if ((*it).get_type() != DeliveryType::RAW_UINT) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a uint"; - } - mPidsUints.emplace_back((*it).get_alias(), DeliveryType::RAW_UINT); - mPids[*it] = mPidsUints.size() - 1; - } - - // bools - for (auto it = std::begin(pidsbools); it != std::end(pidsbools); ++it) { - if ((*it).get_type() != DeliveryType::RAW_BOOL) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a bool"; - } - mPidsbools.emplace_back((*it).get_alias(), DeliveryType::RAW_BOOL); - mPids[*it] = mPidsbools.size() - 1; - } - - // strings - for (auto it = std::begin(pidsstrings); it != std::end(pidsstrings); ++it) { - if ((*it).get_type() != DeliveryType::RAW_STRING) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a string"; - } - mPidsstrings.emplace_back((*it).get_alias(), DeliveryType::RAW_STRING); - mPids[*it] = mPidsstrings.size() - 1; - } - - // times - for (auto it = std::begin(pidstimes); it != std::end(pidstimes); ++it) { - if ((*it).get_type() != DeliveryType::RAW_TIME) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a time"; - } - mPidstimes.emplace_back((*it).get_alias(), DeliveryType::RAW_TIME); - mPids[*it] = mPidstimes.size() - 1; - } - - // binaries - for (auto it = std::begin(pidsbinaries); it != std::end(pidsbinaries); ++it) { - if ((*it).get_type() != DeliveryType::RAW_BINARY) { - LOG(FATAL) << "Type for data point " << *it << " does not match with expectations! It should be a binary"; - } - mPidsbinaries.emplace_back((*it).get_alias(), DeliveryType::RAW_BINARY); - mPids[*it] = mPidsbinaries.size() - 1; - } - - mLatestTimestampchars.resize(pidschars.size(), 0); - mLatestTimestampints.resize(pidsints.size(), 0); - mLatestTimestampdoubles.resize(pidsdoubles.size(), 0); - mLatestTimestampUints.resize(pidsUints.size(), 0); - mLatestTimestampbools.resize(pidsbools.size(), 0); - mLatestTimestampstrings.resize(pidsstrings.size(), 0); - mLatestTimestamptimes.resize(pidstimes.size(), 0); - mLatestTimestampbinaries.resize(pidsbinaries.size(), 0); -} - -//______________________________________________________________________ - -void DCSProcessor::init(const std::vector<DPID>& pids) -{ - - int nchars = 0, nints = 0, ndoubles = 0, nUints = 0, - nbools = 0, nstrings = 0, ntimes = 0, nbinaries = 0; - for (auto it = std::begin(pids); it != std::end(pids); ++it) { - if ((*it).get_type() == DeliveryType::RAW_CHAR) { - mPidschars.emplace_back((*it).get_alias(), DeliveryType::RAW_CHAR); - mPids[*it] = nchars; - nchars++; - } - if ((*it).get_type() == DeliveryType::RAW_INT) { - mPidsints.emplace_back((*it).get_alias(), DeliveryType::RAW_INT); - mPids[*it] = nints; - nints++; - } - if ((*it).get_type() == DeliveryType::RAW_DOUBLE) { - mPidsdoubles.emplace_back((*it).get_alias(), DeliveryType::RAW_DOUBLE); - mPids[*it] = ndoubles; - ndoubles++; - } - if ((*it).get_type() == DeliveryType::RAW_UINT) { - mPidsUints.emplace_back((*it).get_alias(), DeliveryType::RAW_UINT); - mPids[*it] = nUints; - nUints++; - } - if ((*it).get_type() == DeliveryType::RAW_BOOL) { - mPidsbools.emplace_back((*it).get_alias(), DeliveryType::RAW_BOOL); - mPids[*it] = nbools; - nbools++; - } - if ((*it).get_type() == DeliveryType::RAW_STRING) { - mPidsstrings.emplace_back((*it).get_alias(), DeliveryType::RAW_STRING); - mPids[*it] = nstrings; - nstrings++; - } - if ((*it).get_type() == DeliveryType::RAW_TIME) { - mPidstimes.emplace_back((*it).get_alias(), DeliveryType::RAW_TIME); - mPids[*it] = ntimes; - ntimes++; - } - if ((*it).get_type() == DeliveryType::RAW_BINARY) { - mPidsbinaries.emplace_back((*it).get_alias(), DeliveryType::RAW_BINARY); - mPids[*it] = nbinaries; - nbinaries++; - } - } - - mLatestTimestampchars.resize(nchars, 0); - mLatestTimestampints.resize(nints, 0); - mLatestTimestampdoubles.resize(ndoubles, 0); - mLatestTimestampUints.resize(nUints, 0); - mLatestTimestampbools.resize(nbools, 0); - mLatestTimestampstrings.resize(nstrings, 0); - mLatestTimestamptimes.resize(ntimes, 0); - mLatestTimestampbinaries.resize(nbinaries, 0); -} - -//__________________________________________________________________ - -int DCSProcessor::processMap(const std::unordered_map<DPID, DPVAL>& map, bool isDelta) -{ - - // process function to do "something" with the DCS map that is passed - - // resetting the content of the CCDB object to be sent - - if (!isDelta) { - // full map sent - mFullMapSent = true; - } else { - if (!mFullMapSent) { - LOG(ERROR) << "We need first a full map!"; - } - mNCyclesNoFullMap++; - if (mNCyclesNoFullMap > mMaxCyclesNoFullMap) { - LOG(ERROR) << "We expected a full map!"; - } - } - - mIsDelta = isDelta; - - // we need to check if there are the Data Points that we need - - int foundChars = 0, foundInts = 0, foundDoubles = 0, foundUInts = 0, - foundBools = 0, foundStrings = 0, foundTimes = 0, foundBinaries = 0; - - // char type - foundChars = processArrayType(mPidschars, DeliveryType::RAW_CHAR, map, mLatestTimestampchars, mDpscharsmap); - - // int type - foundInts = processArrayType(mPidsints, DeliveryType::RAW_INT, map, mLatestTimestampints, mDpsintsmap); - - // double type - foundDoubles = processArrayType(mPidsdoubles, DeliveryType::RAW_DOUBLE, map, mLatestTimestampdoubles, - mDpsdoublesmap); - - // UInt type - foundUInts = processArrayType(mPidsUints, DeliveryType::RAW_UINT, map, mLatestTimestampUints, mDpsUintsmap); - - // Bool type - foundBools = processArrayType(mPidsbools, DeliveryType::RAW_BOOL, map, mLatestTimestampbools, mDpsboolsmap); - - // String type - foundStrings = processArrayType(mPidsstrings, DeliveryType::RAW_STRING, map, mLatestTimestampstrings, - mDpsstringsmap); - - // Time type - foundTimes = processArrayType(mPidstimes, DeliveryType::RAW_TIME, map, mLatestTimestamptimes, mDpstimesmap); - - // Binary type - foundBinaries = processArrayType(mPidsbinaries, DeliveryType::RAW_BINARY, map, mLatestTimestampbinaries, - mDpsbinariesmap); - - if (!isDelta) { - if (foundChars != mPidschars.size()) { - LOG(INFO) << "Not all expected char-typed DPs found!"; - } - if (foundInts != mPidsints.size()) { - LOG(INFO) << "Not all expected int-typed DPs found!"; - } - if (foundDoubles != mPidsdoubles.size()) { - LOG(INFO) << "Not all expected double-typed DPs found!"; - } - if (foundUInts != mPidsUints.size()) { - LOG(INFO) << "Not all expected uint-typed DPs found!"; - } - if (foundBools != mPidsbools.size()) { - LOG(INFO) << "Not all expected bool-typed DPs found!"; - } - if (foundStrings != mPidsstrings.size()) { - LOG(INFO) << "Not all expected string-typed DPs found!"; - } - if (foundTimes != mPidstimes.size()) { - LOG(INFO) << "Not all expected time-typed DPs found!"; - } - if (foundBinaries != mPidsbinaries.size()) { - LOG(INFO) << "Not all expected binary-typed DPs found!"; - } - } - - // filling CCDB info to be sent in output - std::map<std::string, std::string> md; - prepareCCDBobject(mccdbSimpleMovingAverage, mccdbSimpleMovingAverageInfo, - mName + "/TestDCS/SimpleMovingAverageDPs", mTF, md); - - LOG(DEBUG) << "Size of unordered_map for CCDB = " << mccdbSimpleMovingAverage.size(); - LOG(DEBUG) << "CCDB entry for TF " << mTF << " will be:"; - for (const auto& i : mccdbSimpleMovingAverage) { - LOG(DEBUG) << i.first << " --> " << i.second; - } - - return 0; -} - -//__________________________________________________________________ - -int DCSProcessor::processDP(const std::pair<DPID, DPVAL>& dpcom) -{ - - // processing single DP - - DPID dpid = dpcom.first; - DeliveryType type = dpid.get_type(); - - // first we check if the DP is in the list for the detector - auto el = mPids.find(dpid); - if (el == mPids.end()) { - LOG(ERROR) << "DP not found for this detector, please check"; - return 1; - } - int posInVector = (*el).second; - - if (type == DeliveryType::RAW_CHAR) { - checkFlagsAndFill(dpcom, mLatestTimestampchars[posInVector], mDpscharsmap); - processCharDP(dpid); - } - - else if (type == DeliveryType::RAW_INT) { - checkFlagsAndFill(dpcom, mLatestTimestampints[posInVector], mDpsintsmap); - processIntDP(dpid); - } - - else if (type == DeliveryType::RAW_DOUBLE) { - checkFlagsAndFill(dpcom, mLatestTimestampdoubles[posInVector], mDpsdoublesmap); - processDoubleDP(dpid); - } - - else if (type == DeliveryType::RAW_UINT) { - checkFlagsAndFill(dpcom, mLatestTimestampUints[posInVector], mDpsUintsmap); - processUIntDP(dpid); - } - - else if (type == DeliveryType::RAW_BOOL) { - checkFlagsAndFill(dpcom, mLatestTimestampbools[posInVector], mDpsboolsmap); - processBoolDP(dpid); - } - - else if (type == DeliveryType::RAW_STRING) { - checkFlagsAndFill(dpcom, mLatestTimestampstrings[posInVector], mDpsstringsmap); - processStringDP(dpid); - } - - else if (type == DeliveryType::RAW_TIME) { - checkFlagsAndFill(dpcom, mLatestTimestamptimes[posInVector], mDpstimesmap); - processTimeDP(dpid); - } - - else if (type == DeliveryType::RAW_BINARY) { - checkFlagsAndFill(dpcom, mLatestTimestampbinaries[posInVector], mDpsbinariesmap); - processBinaryDP(dpid); - } - - return 0; -} - -//______________________________________________________________________ - -template <> -void DCSProcessor::checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, DQStrings>& destmap) -{ - - // check the flags for the upcoming data, and if ok, fill the accumulator - - auto& dpid = dpcom.first; - auto& val = dpcom.second; - auto flags = val.get_flags(); - if (processFlag(flags, dpid.get_alias()) == 0) { - auto etime = val.get_epoch_time(); - // fill only if new value has a timestamp different from the timestamp of the previous one - LOG(DEBUG) << "destmap[pid].size() = " << destmap[dpid].size(); - if (destmap[dpid].size() == 0 || etime != latestTimeStamp) { - auto& tmp = destmap[dpid].emplace_back(); - std::strncpy(tmp.data(), (char*)&(val.payload_pt1), 56); - latestTimeStamp = etime; - } - } -} - -//______________________________________________________________________ - -template <> -void DCSProcessor::checkFlagsAndFill(const std::pair<DPID, DPVAL>& dpcom, uint64_t& latestTimeStamp, - std::unordered_map<DPID, DQBinaries>& destmap) -{ - - // check the flags for the upcoming data, and if ok, fill the accumulator - - auto& dpid = dpcom.first; - auto& val = dpcom.second; - auto flags = val.get_flags(); - if (processFlag(flags, dpid.get_alias()) == 0) { - auto etime = val.get_epoch_time(); - // fill only if new value has a timestamp different from the timestamp of the previous one - LOG(DEBUG) << "destmap[pid].size() = " << destmap[dpid].size(); - if (destmap[dpid].size() == 0 || etime != latestTimeStamp) { - auto& tmp = destmap[dpid].emplace_back(); - memcpy(tmp.data(), &(val.payload_pt1), 7); - latestTimeStamp = etime; - } - } -} - -//______________________________________________________________________ - -void DCSProcessor::processCharDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processIntDP(const DPID& pid) -{ - // processing the single pid of type int - bool isSMA = false; - doSimpleMovingAverage(2, mDpsintsmap[pid], mSimpleMovingAverage[pid], isSMA); - LOG(DEBUG) << "dpid = " << pid << " --> Moving average = " << mSimpleMovingAverage[pid]; - // create CCDB object - //if (isSMA) { - mccdbSimpleMovingAverage[pid.get_alias()] = mSimpleMovingAverage[pid]; - //} - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processDoubleDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processUIntDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processBoolDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processStringDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processTimeDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -void DCSProcessor::processBinaryDP(const DPID& pid) -{ - // empty for the example - return; -} - -//______________________________________________________________________ - -std::unordered_map<DPID, DPVAL>::const_iterator DCSProcessor::findAndCheckPid(const DPID& pid, - DeliveryType type, - const std::unordered_map<DPID, DPVAL>& - map) -{ - - // processing basic checks for map: all needed pids must be present - // finds dp defined by "pid" in received map "map" - - LOG(DEBUG) << "Processing " << pid; - auto it = map.find(pid); - DeliveryType tt = pid.get_type(); - if (tt != type) { - LOG(FATAL) << "Delivery Type of pid " << pid.get_alias() << " does not match definition in DCSProcessor (" - << type << ")! Please fix"; - } - return it; -} - -//______________________________________________________________________ - -uint64_t DCSProcessor::processFlag(const uint64_t flags, const char* pid) -{ - - // function to process the flag. the return code zero means that all is fine. - // anything else means that there was an issue - - if (flags & DataPointValue::KEEP_ALIVE_FLAG) { - LOG(INFO) << "KEEP_ALIVE_FLAG active for DP " << pid; - } - if (flags & DataPointValue::END_FLAG) { - LOG(INFO) << "END_FLAG active for DP " << pid; - } - if (flags & DataPointValue::FBI_FLAG) { - LOG(INFO) << "FBI_FLAG active for DP " << pid; - } - if (flags & DataPointValue::NEW_FLAG) { - LOG(INFO) << "NEW_FLAG active for DP " << pid; - } - if (flags & DataPointValue::DIRTY_FLAG) { - LOG(INFO) << "DIRTY_FLAG active for DP " << pid; - } - if (flags & DataPointValue::TURN_FLAG) { - LOG(INFO) << "TURN_FLAG active for DP " << pid; - } - if (flags & DataPointValue::WRITE_FLAG) { - LOG(INFO) << "WRITE_FLAG active for DP " << pid; - } - if (flags & DataPointValue::READ_FLAG) { - LOG(INFO) << "READ_FLAG active for DP " << pid; - } - if (flags & DataPointValue::OVERWRITE_FLAG) { - LOG(INFO) << "OVERWRITE_FLAG active for DP " << pid; - } - if (flags & DataPointValue::VICTIM_FLAG) { - LOG(INFO) << "VICTIM_FLAG active for DP " << pid; - } - if (flags & DataPointValue::DIM_ERROR_FLAG) { - LOG(INFO) << "DIM_ERROR_FLAG active for DP " << pid; - } - if (flags & DataPointValue::BAD_DPID_FLAG) { - LOG(INFO) << "BAD_DPID_FLAG active for DP " << pid; - } - if (flags & DataPointValue::BAD_FLAGS_FLAG) { - LOG(INFO) << "BAD_FLAGS_FLAG active for DP " << pid; - } - if (flags & DataPointValue::BAD_TIMESTAMP_FLAG) { - LOG(INFO) << "BAD_TIMESTAMP_FLAG active for DP " << pid; - } - if (flags & DataPointValue::BAD_PAYLOAD_FLAG) { - LOG(INFO) << "BAD_PAYLOAD_FLAG active for DP " << pid; - } - if (flags & DataPointValue::BAD_FBI_FLAG) { - LOG(INFO) << "BAD_FBI_FLAG active for DP " << pid; - } - - return 0; -} - -//______________________________________________________________________ - -void DCSProcessor::setNThreads(int n) -{ - - // to set number of threads used to process the DPs - -#ifdef WITH_OPENMP - mNThreads = n > 0 ? n : 1; -#else - LOG(WARNING) << " Multithreading is not supported, imposing single thread"; - mNThreads = 1; -#endif -} diff --git a/Detectors/DCS/src/DataPointCompositeObject.cxx b/Detectors/DCS/src/DataPointCompositeObject.cxx index 93aaa674bb2ef..cc88655c87cce 100644 --- a/Detectors/DCS/src/DataPointCompositeObject.cxx +++ b/Detectors/DCS/src/DataPointCompositeObject.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,3 +14,78 @@ using namespace o2::dcs; ClassImp(DataPointCompositeObject); + +namespace o2::dcs +{ +template <typename T, o2::dcs::DeliveryType dt> +T getValueImpl(const DataPointCompositeObject& dpcom) +{ + union Converter { + uint64_t raw_data; + T t_value; + }; + if (dpcom.id.get_type() != dt) { + throw std::runtime_error("DPCOM is of unexpected type " + o2::dcs::show(dt)); + } + Converter converter; + converter.raw_data = dpcom.data.payload_pt1; + return converter.t_value; +} + +// only specialize the getValue function for the types we support : +// +// - double +// - float +// - uint32_t +// - int32_t +// - char +// - bool +// +// - string + +template <> +double getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<double, DeliveryType::RAW_DOUBLE>(dpcom); +} + +template <> +float getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<float, DeliveryType::RAW_FLOAT>(dpcom); +} + +template <> +uint32_t getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<uint32_t, DeliveryType::RAW_UINT>(dpcom); +} + +template <> +int32_t getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<int32_t, DeliveryType::RAW_INT>(dpcom); +} + +template <> +char getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<char, DeliveryType::RAW_CHAR>(dpcom); +} + +template <> +bool getValue(const DataPointCompositeObject& dpcom) +{ + return getValueImpl<bool, DeliveryType::RAW_BOOL>(dpcom); +} + +template <> +std::string getValue(const DataPointCompositeObject& dpcom) +{ + if (dpcom.id.get_type() != o2::dcs::DeliveryType::RAW_STRING) { + throw std::runtime_error("DPCOM is of unexpected type " + o2::dcs::show(dpcom.id.get_type())); + } + return std::string((char*)&dpcom.data.payload_pt1); +} + +} // namespace o2::dcs diff --git a/Detectors/DCS/src/DataPointCreator.cxx b/Detectors/DCS/src/DataPointCreator.cxx new file mode 100644 index 0000000000000..7e107d9c9760f --- /dev/null +++ b/Detectors/DCS/src/DataPointCreator.cxx @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/DataPointCreator.h" + +namespace +{ +o2::dcs::DataPointCompositeObject createDPCOM(const std::string& alias, const uint64_t* val, uint32_t seconds, uint16_t msec, uint16_t flags, o2::dcs::DeliveryType dt) +{ + auto dpid = o2::dcs::DataPointIdentifier(alias, dt); + auto dpval = o2::dcs::DataPointValue( + flags, + msec, + seconds, + val, + dt); + return o2::dcs::DataPointCompositeObject(dpid, dpval); +} +} // namespace + +namespace o2::dcs +{ +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, double val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&val), seconds, msec, flags, DeliveryType::RAW_DOUBLE); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, float val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + float tmp[2]; + tmp[0] = val; + tmp[1] = 0; + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&tmp[0]), seconds, msec, flags, DeliveryType::RAW_FLOAT); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, int32_t val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + int64_t tmp{val}; + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&tmp), seconds, msec, flags, DeliveryType::RAW_INT); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, uint32_t val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + uint64_t tmp{val}; + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&tmp), seconds, msec, flags, DeliveryType::RAW_UINT); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, char val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&val), seconds, msec, flags, DeliveryType::RAW_CHAR); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, bool val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + uint64_t tmp{val}; + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&tmp), seconds, msec, flags, DeliveryType::RAW_BOOL); +} + +template <> +DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, std::string val, uint32_t seconds, uint16_t msec, uint16_t flags) +{ + constexpr int N{56}; + char str[N]; + strncpy(str, val.c_str(), N); + return createDPCOM(alias, reinterpret_cast<const uint64_t*>(&str[0]), seconds, msec, flags, DeliveryType::RAW_STRING); +} + +} // namespace o2::dcs diff --git a/Detectors/DCS/src/DataPointGenerator.cxx b/Detectors/DCS/src/DataPointGenerator.cxx new file mode 100644 index 0000000000000..9b8460afb3842 --- /dev/null +++ b/Detectors/DCS/src/DataPointGenerator.cxx @@ -0,0 +1,147 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DataPointGenerator.h" +#include "DetectorsDCS/DataPointCreator.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/StringUtils.h" +#include "Framework/Logger.h" +#include <fmt/format.h> +#include <random> +#include <utility> +#include <type_traits> +#include <cstdint> + +namespace +{ +std::pair<uint32_t, uint16_t> getDate(const std::string& refDate) +{ + + uint32_t seconds; + if (refDate.empty()) { + auto current = std::time(nullptr); + auto t = std::localtime(¤t); + seconds = mktime(t); + } else { + std::tm t{}; + std::istringstream ss(refDate); + ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S"); + if (ss.fail()) { // let's see if it was passed as a TDatime, as SQL string + std::tm tt{}; + std::istringstream sss(refDate); + sss >> std::get_time(&tt, "%Y-%m-%d %H:%M:%S"); + if (sss.fail()) { + std::tm ttt{}; + std::istringstream ssss(refDate); + ssss >> std::get_time(&tt, "%Y-%B-%d %H:%M:%S"); + if (ssss.fail()) { + LOG(ERROR) << "We cannot parse the date"; + } + seconds = mktime(&ttt); + } else { + seconds = mktime(&tt); + } + } else { + seconds = mktime(&t); + } + } + uint16_t msec = 5; + return std::make_pair(seconds, msec); +} + +} // namespace + +namespace o2::dcs +{ + +//std::enable_if_t<std::is_arithmetic<T>::value, bool> = true> + +template <typename T> +std::vector<o2::dcs::DataPointCompositeObject> + generateRandomDataPoints(const std::vector<std::string>& aliases, + T minValue, T maxValue, std::string refDate) +{ + std::vector<o2::dcs::DataPointCompositeObject> dpcoms; + static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type"); + typedef typename std::conditional<std::is_integral<T>::value, + std::uniform_int_distribution<T>, + std::uniform_real_distribution<T>>::type distType; + + std::random_device rd; + std::mt19937 mt(rd()); + distType dist{minValue, maxValue}; + auto [seconds, msec] = getDate(refDate); + for (auto alias : expandAliases(aliases)) { + auto value = dist(mt); + dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(alias, value, seconds, msec)); + } + return dpcoms; +} + +// only specialize the functions for the types we support : +// +// - double +// - float +// - uint32_t +// - int32_t +// - char +// - bool +// +// - std::string + +template std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<double>(const std::vector<std::string>& aliases, double minValue, double maxValue, std::string); + +template std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<float>(const std::vector<std::string>& aliases, float minValue, float maxValue, std::string); + +template std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<uint32_t>(const std::vector<std::string>& aliases, uint32_t minValue, uint32_t maxValue, std::string); + +template std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<int32_t>(const std::vector<std::string>& aliases, int32_t minValue, int32_t maxValue, std::string); + +template std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<char>(const std::vector<std::string>& aliases, char minValue, char maxValue, std::string); + +/** Need a specific specialization for bool as got into trouble compiling uniform_int_distribution<bool> + * on some platform (e.g. CC7). + */ +template <> +std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<bool>(const std::vector<std::string>& aliases, bool minValue, bool maxValue, std::string refDate) +{ + std::vector<o2::dcs::DataPointCompositeObject> dpcoms; + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_int_distribution dist{0, 1}; + auto [seconds, msec] = getDate(refDate); + for (auto alias : expandAliases(aliases)) { + bool value = dist(mt); + dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(alias, value, seconds, msec)); + } + return dpcoms; +} + +/** + * Generate data points of type string, where each string is random, with + * a length between the length of the two input strings (minLength,maxLength) + */ +template <> +std::vector<o2::dcs::DataPointCompositeObject> generateRandomDataPoints<std::string>(const std::vector<std::string>& aliases, std::string minLength, std::string maxLength, std::string refDate) +{ + std::vector<o2::dcs::DataPointCompositeObject> dpcoms; + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_int_distribution<std::string::size_type> dist{minLength.size(), maxLength.size()}; + auto [seconds, msec] = getDate(refDate); + for (auto alias : expandAliases(aliases)) { + auto value = o2::dcs::random_string2(dist(mt)); + dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(alias, value, seconds, msec)); + } + return dpcoms; +} +} // namespace o2::dcs diff --git a/Detectors/DCS/src/DataPointIdentifier.cxx b/Detectors/DCS/src/DataPointIdentifier.cxx index 85906ad6dd408..93ee2ebc3681c 100644 --- a/Detectors/DCS/src/DataPointIdentifier.cxx +++ b/Detectors/DCS/src/DataPointIdentifier.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/DataPointValue.cxx b/Detectors/DCS/src/DataPointValue.cxx index dc5874b7e3a9b..473df5733bcd4 100644 --- a/Detectors/DCS/src/DataPointValue.cxx +++ b/Detectors/DCS/src/DataPointValue.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/DeliveryType.cxx b/Detectors/DCS/src/DeliveryType.cxx index 6ff195fc8fd9d..85a81ece45b3b 100644 --- a/Detectors/DCS/src/DeliveryType.cxx +++ b/Detectors/DCS/src/DeliveryType.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/DetectorsDCSLinkDef.h b/Detectors/DCS/src/DetectorsDCSLinkDef.h index 5f53e7757a349..d20209c43438a 100644 --- a/Detectors/DCS/src/DetectorsDCSLinkDef.h +++ b/Detectors/DCS/src/DetectorsDCSLinkDef.h @@ -1,15 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#if defined(__CINT__) || defined(__CLING__) - +#if defined(__CLING__) #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; @@ -17,7 +17,13 @@ #pragma link C++ struct o2::dcs::DataPointCompositeObject + ; #pragma link C++ class o2::dcs::DataPointIdentifier + ; #pragma link C++ struct o2::dcs::DataPointValue + ; -#pragma link C++ class o2::dcs::DCSProcessor + ; #pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue> + ; +#pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, std::vector < o2::dcs::DataPointValue>> + ; +#pragma link C++ class std::vector < o2::dcs::DataPointCompositeObject> + ; +#pragma link C++ class std::vector < o2::dcs::DataPointValue> + ; +#pragma link C++ class std::vector < o2::dcs::DataPointIdentifier> + ; +#pragma link C++ function o2::dcs::expandAlias(const std::string&); +#pragma link C++ function o2::dcs::expandAliases(const std::vector <std::string>&); +#pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, std::string> + ; #endif diff --git a/Detectors/DCS/src/GenericFunctions.cxx b/Detectors/DCS/src/GenericFunctions.cxx index c8be0880092c4..f5300a8d03c5f 100644 --- a/Detectors/DCS/src/GenericFunctions.cxx +++ b/Detectors/DCS/src/GenericFunctions.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/src/StringUtils.cxx b/Detectors/DCS/src/StringUtils.cxx index a0e96d17a5752..e66e7625c6836 100644 --- a/Detectors/DCS/src/StringUtils.cxx +++ b/Detectors/DCS/src/StringUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/DCS/test/processor_dpcom_o2.C b/Detectors/DCS/test/processor_dpcom_o2.C deleted file mode 100644 index 4d1171205055c..0000000000000 --- a/Detectors/DCS/test/processor_dpcom_o2.C +++ /dev/null @@ -1,115 +0,0 @@ -using namespace o2::dcs; -using DPID = o2::dcs::DataPointIdentifier; -using DPVAL = o2::dcs::DataPointValue; -using DPCOM = o2::dcs::DataPointCompositeObject; - -int processor_dpcom_o2() -{ - - std::unordered_map<DPID, DPVAL> dpmap; - - o2::dcs::DCSProcessor dcsproc; - std::vector<DPID> aliasChars; - std::vector<DPID> aliasInts; - std::vector<DPID> aliasDoubles; - std::vector<DPID> aliasUInts; - std::vector<DPID> aliasBools; - std::vector<DPID> aliasStrings; - std::vector<DPID> aliasTimes; - std::vector<DPID> aliasBinaries; - - DeliveryType typechar = RAW_CHAR; - std::string dpAliaschar = "TestChar0"; - DPID charVar(dpAliaschar, typechar); - aliasChars.push_back(charVar); - - DeliveryType typeint = RAW_INT; - std::string dpAliasint0 = "TestInt0"; - DPID intVar0(dpAliasint0, typeint); - aliasInts.push_back(intVar0); - - std::string dpAliasint1 = "TestInt1"; - DPID intVar1(dpAliasint1, typeint); - aliasInts.push_back(intVar1); - - std::string dpAliasint2 = "TestInt2"; - DPID intVar2(dpAliasint2, typeint); - aliasInts.push_back(intVar2); - - DeliveryType typedouble = RAW_DOUBLE; - std::string dpAliasdouble0 = "TestDouble0"; - DPID doubleVar0(dpAliasdouble0, typedouble); - aliasDoubles.push_back(doubleVar0); - - std::string dpAliasdouble1 = "TestDouble1"; - DPID doubleVar1(dpAliasdouble1, typedouble); - aliasDoubles.push_back(doubleVar1); - - std::string dpAliasdouble2 = "TestDouble2"; - DPID doubleVar2(dpAliasdouble2, typedouble); - aliasDoubles.push_back(doubleVar2); - - std::string dpAliasdouble3 = "TestDouble3"; - DPID doubleVar3(dpAliasdouble3, typedouble); - aliasDoubles.push_back(doubleVar3); - - DeliveryType typestring = RAW_STRING; - std::string dpAliasstring0 = "TestString0"; - DPID stringVar0(dpAliasstring0, typestring); - aliasStrings.push_back(stringVar0); - - dcsproc.init(aliasChars, aliasInts, aliasDoubles, aliasUInts, aliasBools, aliasStrings, aliasTimes, aliasBinaries); - - uint16_t flags = 0; - uint16_t milliseconds = 0; - TDatime currentTime; - uint32_t seconds = currentTime.Get(); - uint64_t* payload = new uint64_t[7]; - - // loop that emulates the number of times the DCS DataPoints are sent - for (auto k = 0; k < 4; k++) { - payload[0] = (uint64_t)k + 33; // adding 33 to have visible chars and strings - - DPVAL valchar(flags, milliseconds + k * 10, seconds + k, payload, typechar); - DPVAL valint(flags, milliseconds + k * 10, seconds + k, payload, typeint); - DPVAL valdouble(flags, milliseconds + k * 10, seconds + k, payload, typedouble); - DPVAL valstring(flags, milliseconds + k * 10, seconds + k, payload, typestring); - - dpmap[charVar] = valchar; - dpmap[intVar0] = valint; - dpmap[intVar1] = valint; - dpmap[intVar2] = valint; - dpmap[doubleVar0] = valdouble; - dpmap[doubleVar1] = valdouble; - dpmap[doubleVar2] = valdouble; - dpmap[stringVar0] = valstring; - if (k != 3) - dpmap[doubleVar3] = valdouble; // to test the case when a DP is not updated - std::cout << "index = " << k << std::endl; - std::cout << charVar << std::endl - << valchar << " --> " << (char)valchar.payload_pt1 << std::endl; - std::cout << intVar0 << std::endl - << valint << " --> " << (int)valchar.payload_pt1 << std::endl; - std::cout << intVar1 << std::endl - << valint << " --> " << (int)valchar.payload_pt1 << std::endl; - std::cout << intVar2 << std::endl - << valint << " --> " << (int)valchar.payload_pt1 << std::endl; - std::cout << doubleVar0 << std::endl - << valdouble << " --> " << (double)valchar.payload_pt1 << std::endl; - std::cout << doubleVar1 << std::endl - << valdouble << " --> " << (double)valchar.payload_pt1 << std::endl; - std::cout << doubleVar2 << std::endl - << valdouble << " --> " << (double)valchar.payload_pt1 << std::endl; - std::cout << doubleVar3 << std::endl - << valdouble << " --> " << (double)valchar.payload_pt1 << std::endl; - char tt[56]; - memcpy(&tt[0], &valstring.payload_pt1, 56); - printf("tt = %s\n", tt); - std::cout << stringVar0 << std::endl - << valstring << " --> " << tt << std::endl; - - dcsproc.process(dpmap); - } - std::cout << "The map has " << dpmap.size() << " entries" << std::endl; - return 0; -} diff --git a/Detectors/DCS/test/testAliasExpander.cxx b/Detectors/DCS/test/testAliasExpander.cxx new file mode 100644 index 0000000000000..9f05ebb60900a --- /dev/null +++ b/Detectors/DCS/test/testAliasExpander.cxx @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test DCS AliasExpander +#define BOOST_TEST_MAIN + +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/test/data/test_case.hpp> +#include <iostream> +#include "DetectorsDCS/AliasExpander.h" + +BOOST_AUTO_TEST_CASE(ExpandAliasesIsNoopWhenNoPatternGiven) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"ab"}); + + std::vector<std::string> expected = {"ab"}; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandAliasesReturnsEmptyVectorWhenPatternIsIncorrect) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"ab[c"}); + + std::vector<std::string> expected = {}; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); + + aliases = o2::dcs::expandAliases({"ab]c"}); + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); + + aliases = o2::dcs::expandAliases({"ab[1.2]c"}); + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandAliasesWithIntegerRange) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"a[1..2]bcde[99..101]toto"}); + + std::vector<std::string> expected = { + "a1bcde099toto", + "a1bcde100toto", + "a1bcde101toto", + "a2bcde099toto", + "a2bcde100toto", + "a2bcde101toto"}; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandAliasesWithIntegerRangeWithCustomFormat) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"a[1..3{:03d}]"}); + + std::vector<std::string> expected = { + "a001", + "a002", + "a003"}; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandAliasesWithIntegerRangeWithCustomFormatBis) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"a[1..3{:d}]"}); + + std::vector<std::string> expected = { + "a1", + "a2", + "a3"}; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandAliasesWithStringList) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases({"a[1..2]bcde[99..101][toto,titi,tata]"}); + + std::vector<std::string> expected = { + "a1bcde099tata", + "a1bcde099titi", + "a1bcde099toto", + "a1bcde100tata", + "a1bcde100titi", + "a1bcde100toto", + "a1bcde101tata", + "a1bcde101titi", + "a1bcde101toto", + "a2bcde099tata", + "a2bcde099titi", + "a2bcde099toto", + "a2bcde100tata", + "a2bcde100titi", + "a2bcde100toto", + "a2bcde101tata", + "a2bcde101titi", + "a2bcde101toto", + }; + + BOOST_TEST(aliases == expected, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(ExpandMch) +{ + std::vector<std::string> aliases = o2::dcs::expandAliases( + {"MchHvLvLeft/Chamber[00..03]Left/Quad1Sect[0..2].actual.[vMon,iMon]", + "MchHvLvLeft/Chamber[00..03]Left/Quad2Sect[0..2].actual.[vMon,iMon]", + "MchHvLvLeft/Chamber[04..09]Left/Slat[00..08].actual.[vMon,iMon]", + "MchHvLvLeft/Chamber[06..09]Left/Slat[09..12].actual.[vMon,iMon]", + "MchHvLvRight/Chamber[00..03]Right/Quad0Sect[0..2].actual.[vMon,iMon]", + "MchHvLvRight/Chamber[00..03]Right/Quad3Sect[0..2].actual.[vMon,iMon]", + "MchHvLvRight/Chamber[04..09]Right/Slat[00..08].actual.[vMon,iMon]", + "MchHvLvRight/Chamber[06..09]Right/Slat[09..12].actual.[vMon,iMon]"}); + + BOOST_TEST(aliases.size(), 376); +} diff --git a/Detectors/DCS/test/testDataPointGenerator.cxx b/Detectors/DCS/test/testDataPointGenerator.cxx new file mode 100644 index 0000000000000..ee19cd7c536b5 --- /dev/null +++ b/Detectors/DCS/test/testDataPointGenerator.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test DCS DataPointGenerator +#define BOOST_TEST_MAIN + +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/test/data/test_case.hpp> +#include <iostream> +#include "DetectorsDCS/DataPointGenerator.h" +#include <algorithm> +#include <fmt/format.h> + +BOOST_AUTO_TEST_CASE(GenerateDouble) +{ + double fmin = 1620.0; + double fmax = 1710.5; + auto fbi = o2::dcs::generateRandomDataPoints({"TST/SECTOR[00..06]/CRATE[0..3]/voltage"}, fmin, fmax, "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 28); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_DOUBLE); + double value = o2::dcs::getValue<double>(dp); + BOOST_CHECK(value >= fmin && value <= fmax); + } +} + +BOOST_AUTO_TEST_CASE(GenerateFloat) +{ + float fmin = 1620.0f; + float fmax = 1710.5f; + auto fbi = o2::dcs::generateRandomDataPoints({"TST/SECTOR[00..06]/CRATE[0..3]/voltage"}, fmin, fmax, "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 28); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_FLOAT); + float value = o2::dcs::getValue<float>(dp); + BOOST_TEST_INFO(fmt::format("value={}", value)); + BOOST_CHECK(value >= fmin && value <= fmax); + } +} + +BOOST_AUTO_TEST_CASE(GenerateInt) +{ + int32_t imin = 0; + int32_t imax = 3; + auto fbi = o2::dcs::generateRandomDataPoints({"TST/SECTOR[00..06]/CRATE[0..3]/current"}, imin, imax, "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 28); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_INT); + double value = o2::dcs::getValue<int32_t>(dp); + BOOST_CHECK(value >= imin && value <= imax); + BOOST_CHECK_THROW(o2::dcs::getValue<double>(dp), std::runtime_error); + BOOST_CHECK_THROW(o2::dcs::getValue<uint32_t>(dp), std::runtime_error); + } +} + +BOOST_AUTO_TEST_CASE(GenerateUInt) +{ + uint32_t imin = 0; + uint32_t imax = 3; + auto fbi = o2::dcs::generateRandomDataPoints({"TST/SECTOR[00..06]/CRATE[0..3]/current"}, imin, imax, "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 28); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_UINT); + double value = o2::dcs::getValue<uint32_t>(dp); + BOOST_CHECK(value >= imin && value <= imax); + BOOST_CHECK_THROW(o2::dcs::getValue<double>(dp), std::runtime_error); + BOOST_CHECK_THROW(o2::dcs::getValue<int32_t>(dp), std::runtime_error); + } +} + +BOOST_AUTO_TEST_CASE(GenerateBool) +{ + auto fbi = o2::dcs::generateRandomDataPoints<bool>({"TST/SECTOR[00..06]/status"}, 0, 1, "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 7); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_BOOL); + BOOST_CHECK_NO_THROW(o2::dcs::getValue<bool>(dp)); + BOOST_CHECK_THROW(o2::dcs::getValue<int>(dp), std::runtime_error); + } +} + +BOOST_AUTO_TEST_CASE(GenerateString) +{ + auto fbi = o2::dcs::generateRandomDataPoints<std::string>({"TST/SECTOR[00..06]/name"}, "123", "1234567", "2022-November-18 12:34:56"); + + BOOST_CHECK_EQUAL(fbi.size(), 7); + + for (auto dp : fbi) { + BOOST_CHECK_EQUAL(dp.id.get_type(), o2::dcs::DeliveryType::RAW_STRING); + BOOST_CHECK_NO_THROW(o2::dcs::getValue<std::string>(dp)); + BOOST_CHECK_THROW(o2::dcs::getValue<int>(dp), std::runtime_error); + auto value = o2::dcs::getValue<std::string>(dp); + BOOST_CHECK(value.size() >= 3); + BOOST_CHECK(value.size() <= 7); + } +} diff --git a/Detectors/DCS/test/testDataPointTypes.cxx b/Detectors/DCS/test/testDataPointTypes.cxx new file mode 100644 index 0000000000000..491ebae1f5d00 --- /dev/null +++ b/Detectors/DCS/test/testDataPointTypes.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <type_traits> +#define BOOST_TEST_MODULE Test DetectorsDCS DataPoints +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "Framework/TypeTraits.h" +#include <vector> +#include <list> +#include <gsl/gsl> +#include <boost/mpl/list.hpp> + +typedef boost::mpl::list<o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue, o2::dcs::DataPointCompositeObject> testTypes; + +BOOST_AUTO_TEST_CASE_TEMPLATE(DataPointCompositeObjectTypeTraits, T, testTypes) +{ + BOOST_CHECK_EQUAL(std::is_trivially_copyable<T>::value, true); + BOOST_CHECK_EQUAL(std::is_polymorphic<T>::value, false); + BOOST_CHECK_EQUAL(std::is_pointer<T>::value, false); + BOOST_CHECK_EQUAL(o2::framework::is_forced_non_messageable<T>::value, false); +} + +BOOST_AUTO_TEST_CASE(DataPointsAreMessageable) +{ + BOOST_CHECK_EQUAL(o2::framework::is_messageable<o2::dcs::DataPointIdentifier>::value, true); + BOOST_CHECK_EQUAL(o2::framework::is_messageable<o2::dcs::DataPointValue>::value, true); + BOOST_CHECK_EQUAL(o2::framework::is_messageable<o2::dcs::DataPointCompositeObject>::value, true); +} diff --git a/Detectors/DCS/testWorkflow/CMakeLists.txt b/Detectors/DCS/testWorkflow/CMakeLists.txt new file mode 100644 index 0000000000000..a492792c9774b --- /dev/null +++ b/Detectors/DCS/testWorkflow/CMakeLists.txt @@ -0,0 +1,29 @@ + +o2_add_library( + DCStestWorkflow + SOURCES src/DCSRandomDataGeneratorSpec.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::Framework) + +o2_add_executable( + proxy + COMPONENT_NAME dcs + SOURCES src/dcs-proxy.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) + +o2_add_executable( + data-client + COMPONENT_NAME dcs + SOURCES src/dcs-data-client-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) + +o2_add_executable( + config-proxy + COMPONENT_NAME dcs + SOURCES src/dcs-config-proxy.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsCommonDataFormats O2::CommonUtils) + +o2_add_executable( + config-consumer-test-workflow + COMPONENT_NAME dcs + SOURCES src/dcs-config-test-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsCommonDataFormats) diff --git a/Detectors/DCS/testWorkflow/DCSDataGeneratorSpec.h b/Detectors/DCS/testWorkflow/DCSDataGeneratorSpec.h deleted file mode 100644 index 27c0bb2977b6d..0000000000000 --- a/Detectors/DCS/testWorkflow/DCSDataGeneratorSpec.h +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_DCS_DATAGENERATOR_H -#define O2_DCS_DATAGENERATOR_H - -/// @file DataGeneratorSpec.h -/// @brief Dummy data generator -#include <unistd.h> -#include <TRandom.h> -#include <TDatime.h> -#include <TStopwatch.h> -#include "DetectorsDCS/DataPointIdentifier.h" -#include "DetectorsDCS/DataPointValue.h" -#include "DetectorsDCS/DataPointCompositeObject.h" -#include "DetectorsDCS/DeliveryType.h" -#include "Framework/DeviceSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/Task.h" -#include "Framework/Logger.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace dcs -{ -class DCSDataGenerator : public o2::framework::Task -{ - - using DPID = o2::dcs::DataPointIdentifier; - using DPVAL = o2::dcs::DataPointValue; - using DPCOM = o2::dcs::DataPointCompositeObject; - - public: - void init(o2::framework::InitContext& ic) final - { - mMaxTF = ic.options().get<int64_t>("max-timeframes"); - - LOG(INFO) << "mMaxTF = " << mMaxTF; - - DPID dpidtmp; - - // chars - std::string dpAliaschar = "TestChar_0"; - DPID::FILL(dpidtmp, dpAliaschar, mtypechar); - mDPIDvectFull.push_back(dpidtmp); - mNumDPsFull++; - mNumDPscharFull++; - - // ints - for (int i = 0; i < 50000; i++) { - std::string dpAliasint = "TestInt_" + std::to_string(i); - DPID::FILL(dpidtmp, dpAliasint, mtypeint); - mDPIDvectFull.push_back(dpidtmp); - mNumDPsFull++; - mNumDPsintFull++; - if (i < 100) { - mDPIDvectDelta.push_back(dpidtmp); - mNumDPsDelta++; - mNumDPsintDelta++; - } - } - - // doubles - for (int i = 0; i < 4; i++) { - std::string dpAliasdouble = "TestDouble_" + std::to_string(i); - DPID::FILL(dpidtmp, dpAliasdouble, mtypedouble); - mDPIDvectFull.push_back(dpidtmp); - mNumDPsFull++; - mNumDPsdoubleFull++; - } - - // strings - std::string dpAliasstring0 = "TestString_0"; - DPID::FILL(dpidtmp, dpAliasstring0, mtypestring); - mDPIDvectFull.push_back(dpidtmp); - mNumDPsFull++; - mNumDPsstringFull++; - - LOG(INFO) << "Number of DCS data points: " << mNumDPsFull << " (full map); " << mNumDPsDelta << " (delta map)"; - } - - void run(o2::framework::ProcessingContext& pc) final - { - - uint64_t tfid; - for (auto& input : pc.inputs()) { - tfid = header::get<o2::framework::DataProcessingHeader*>(input.header)->startTime; - LOG(DEBUG) << "tfid = " << tfid; - if (tfid >= mMaxTF) { - LOG(INFO) << "Data generator reached TF " << tfid << ", stopping"; - pc.services().get<o2::framework::ControlService>().endOfStream(); - pc.services().get<o2::framework::ControlService>().readyToQuit(o2::framework::QuitRequest::Me); - } - break; // we break because one input is enough to get the TF ID - } - - LOG(DEBUG) << "TF: " << tfid << " --> building binary blob..."; - uint16_t flags = 0; - uint16_t milliseconds = 0; - TDatime currentTime; - uint32_t seconds = currentTime.Get(); - uint64_t payload[7]; - memset(payload, 0, sizeof(uint64_t) * 7); - - payload[0] = (uint64_t)tfid + 33; // adding 33 to have visible chars and strings - - DPVAL valchar(flags, milliseconds + tfid * 10, seconds + tfid, payload, mtypechar); - DPVAL valint(flags, milliseconds + tfid * 10, seconds + tfid, payload, mtypeint); - DPVAL valdouble(flags, milliseconds + tfid * 10, seconds + tfid, payload, mtypedouble); - DPVAL valstring(flags, milliseconds + tfid * 10, seconds + tfid, payload, mtypestring); - - LOG(DEBUG) << "Value used for char DPs:"; - LOG(DEBUG) << valchar << " --> " << (char)valchar.payload_pt1; - LOG(DEBUG) << "Value used for int DPs:"; - LOG(DEBUG) << valint << " --> " << (int)valint.payload_pt1; - LOG(DEBUG) << "Value used for double DPs:"; - LOG(DEBUG) << valdouble << " --> " << (double)valdouble.payload_pt1; - char tt[56]; - memcpy(&tt[0], &valstring.payload_pt1, 56); - LOG(DEBUG) << "Value used for string DPs:"; - LOG(DEBUG) << valstring << " --> " << tt; - - // full map (all DPs) - mBuildingBinaryBlock.Start(mFirstTF); - std::vector<DPCOM> dpcomVectFull; - for (int i = 0; i < mNumDPscharFull; i++) { - dpcomVectFull.emplace_back(mDPIDvectFull[i], valchar); - } - for (int i = 0; i < mNumDPsintFull; i++) { - dpcomVectFull.emplace_back(mDPIDvectFull[mNumDPscharFull + i], valint); - } - for (int i = 0; i < mNumDPsdoubleFull; i++) { - dpcomVectFull.emplace_back(mDPIDvectFull[mNumDPscharFull + mNumDPsintFull + i], valdouble); - } - for (int i = 0; i < mNumDPsstringFull; i++) { - dpcomVectFull.emplace_back(mDPIDvectFull[mNumDPscharFull + mNumDPsintFull + mNumDPsdoubleFull + i], valstring); - } - - // delta map (only DPs that changed) - mDeltaBuildingBinaryBlock.Start(mFirstTF); - std::vector<DPCOM> dpcomVectDelta; - for (int i = 0; i < mNumDPscharDelta; i++) { - dpcomVectDelta.emplace_back(mDPIDvectDelta[i], valchar); - } - for (int i = 0; i < mNumDPsintDelta; i++) { - dpcomVectDelta.emplace_back(mDPIDvectDelta[mNumDPscharDelta + i], valint); - } - for (int i = 0; i < mNumDPsdoubleDelta; i++) { - dpcomVectDelta.emplace_back(mDPIDvectDelta[mNumDPscharDelta + mNumDPsintDelta + i], valdouble); - } - for (int i = 0; i < mNumDPsstringDelta; i++) { - dpcomVectDelta.emplace_back(mDPIDvectDelta[mNumDPscharDelta + mNumDPsintDelta + mNumDPsdoubleDelta + i], - valstring); - } - - // Full map - auto svect = dpcomVectFull.size(); - LOG(DEBUG) << "dpcomVectFull has size " << svect; - for (int i = 0; i < svect; i++) { - LOG(DEBUG) << "i = " << i << ", DPCOM = " << dpcomVectFull[i]; - } - std::vector<char> buff(mNumDPsFull * sizeof(DPCOM)); - char* dptr = buff.data(); - for (int i = 0; i < svect; i++) { - memcpy(dptr + i * sizeof(DPCOM), &dpcomVectFull[i], sizeof(DPCOM)); - } - auto sbuff = buff.size(); - LOG(DEBUG) << "size of output buffer = " << sbuff; - mBuildingBinaryBlock.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...binary blob prepared: realTime = " - << mBuildingBinaryBlock.RealTime() << ", cpuTime = " - << mBuildingBinaryBlock.CpuTime(); - LOG(DEBUG) << "TF: " << tfid << " --> sending snapshot..."; - mSnapshotSending.Start(mFirstTF); - pc.outputs().snapshot(Output{"DCS", "DATAPOINTS", 0, Lifetime::Timeframe}, buff.data(), sbuff); - mSnapshotSending.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...snapshot sent: realTime = " << mSnapshotSending.RealTime() - << ", cpuTime = " << mSnapshotSending.CpuTime(); - - // Delta map - auto svectDelta = dpcomVectDelta.size(); - LOG(DEBUG) << "dpcomVectDelta has size " << svect; - for (int i = 0; i < svectDelta; i++) { - LOG(DEBUG) << "i = " << i << ", DPCOM = " << dpcomVectDelta[i]; - } - std::vector<char> buffDelta(mNumDPsDelta * sizeof(DPCOM)); - char* dptrDelta = buffDelta.data(); - for (int i = 0; i < svectDelta; i++) { - memcpy(dptrDelta + i * sizeof(DPCOM), &dpcomVectDelta[i], sizeof(DPCOM)); - } - auto sbuffDelta = buffDelta.size(); - LOG(DEBUG) << "size of output (delta) buffer = " << sbuffDelta; - mDeltaBuildingBinaryBlock.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...binary (delta) blob prepared: realTime = " - << mDeltaBuildingBinaryBlock.RealTime() << ", cpuTime = " << mDeltaBuildingBinaryBlock.CpuTime(); - LOG(DEBUG) << "TF: " << tfid << " --> sending (delta) snapshot..."; - mDeltaSnapshotSending.Start(mFirstTF); - pc.outputs().snapshot(Output{"DCS", "DATAPOINTSdelta", 0, Lifetime::Timeframe}, buffDelta.data(), sbuffDelta); - mDeltaSnapshotSending.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...snapshot (delta) sent: realTime = " - << mDeltaSnapshotSending.RealTime() << ", cpuTime = " - << mDeltaSnapshotSending.CpuTime(); - - /* - LOG(INFO) << "Reading back"; - DPCOM dptmp; - for (int i = 0; i < svect; i++) { - memcpy(&dptmp, dptr + i * sizeof(DPCOM), sizeof(DPCOM)); - LOG(DEBUG) << "Check: Reading from generator: i = " << i << ", DPCOM = " << dptmp; - } - */ - /* - auto& tmpDPmap = pc.outputs().make<std::unordered_map<DPID, DPVAL>>(o2::framework::OutputRef{"output", 0}); - tmpDPmap[mcharVar] = valchar; - tmpDPmap[mintVar0] = valint; - tmpDPmap[mintVar1] = valint; - tmpDPmap[mintVar2] = valint; - tmpDPmap[mdoubleVar0] = valdouble; - tmpDPmap[mdoubleVar1] = valdouble; - tmpDPmap[mdoubleVar2] = valdouble; - if (tfid % 3 == 0) - tmpDPmap[mdoubleVar3] = valdouble; // to test the case when a DP is not updated, we skip some updates - tmpDPmap[mstringVar0] = valstring; - */ - mFirstTF = false; - mTFs++; - } - - void endOfStream(o2::framework::EndOfStreamContext& ec) final - { - LOG(INFO) << "number of processed TF: " << mTFs; - LOG(INFO) << " --> time to prepare binary blob: realTime = " - << mBuildingBinaryBlock.RealTime() / mTFs << ", cpuTime = " - << mBuildingBinaryBlock.CpuTime() / mTFs; - LOG(INFO) << " --> time to send snapshot: realTime = " - << mSnapshotSending.RealTime() / mTFs << ", cpuTime = " - << mSnapshotSending.CpuTime() / mTFs; - LOG(INFO) << " --> time to prepare binary blob: realTime = " - << mDeltaBuildingBinaryBlock.RealTime() / mTFs << ", cpuTime = " - << mDeltaBuildingBinaryBlock.CpuTime() / mTFs; - LOG(INFO) << " --> time to send snapshot: realTime = " - << mDeltaSnapshotSending.RealTime() / mTFs << ", cpuTime = " - << mDeltaSnapshotSending.CpuTime() / mTFs; - } - - private: - uint64_t mMaxTF = 1; - - uint64_t mNumDPsFull = 0; - uint64_t mNumDPscharFull = 0; - uint64_t mNumDPsintFull = 0; - uint64_t mNumDPsdoubleFull = 0; - uint64_t mNumDPsstringFull = 0; - - uint64_t mNumDPsDelta = 0; - uint64_t mNumDPscharDelta = 0; - uint64_t mNumDPsintDelta = 0; - uint64_t mNumDPsdoubleDelta = 0; - uint64_t mNumDPsstringDelta = 0; - std::vector<DPID> mDPIDvectFull; // for full map - std::vector<DPID> mDPIDvectDelta; // for delta map (containing only DPs that changed) - DeliveryType mtypechar = RAW_CHAR; - DeliveryType mtypeint = RAW_INT; - DeliveryType mtypedouble = RAW_DOUBLE; - DeliveryType mtypestring = RAW_STRING; - - TStopwatch mBuildingBinaryBlock; - TStopwatch mDeltaBuildingBinaryBlock; - TStopwatch mSnapshotSending; - TStopwatch mDeltaSnapshotSending; - bool mFirstTF = true; - uint64_t mTFs = 0; -}; - -} // namespace dcs - -namespace framework -{ - -DataProcessorSpec getDCSDataGeneratorSpec() -{ - return DataProcessorSpec{ - "dcs-data-generator", - Inputs{}, - Outputs{{{"outputDCS"}, "DCS", "DATAPOINTS"}, {{"outputDCSdelta"}, "DCS", "DATAPOINTSdelta"}}, - AlgorithmSpec{adaptFromTask<o2::dcs::DCSDataGenerator>()}, - Options{{"max-timeframes", VariantType::Int64, 99999999999ll, {"max TimeFrames to generate"}}}}; -} - -} // namespace framework -} // namespace o2 - -#endif diff --git a/Detectors/DCS/testWorkflow/DCSDataProcessorSpec.h b/Detectors/DCS/testWorkflow/DCSDataProcessorSpec.h deleted file mode 100644 index 2f5569106e77c..0000000000000 --- a/Detectors/DCS/testWorkflow/DCSDataProcessorSpec.h +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_DCS_DATAPROCESSOR_H -#define O2_DCS_DATAPROCESSOR_H - -/// @file DataGeneratorSpec.h -/// @brief Dummy data generator - -#include <unistd.h> -#include <TRandom.h> -#include <TStopwatch.h> -#include "DetectorsDCS/DataPointIdentifier.h" -#include "DetectorsDCS/DataPointValue.h" -#include "DetectorsDCS/DataPointCompositeObject.h" -#include "DetectorsDCS/DeliveryType.h" -#include "DetectorsDCS/DCSProcessor.h" -#include "DetectorsCalibration/Utils.h" -#include "CCDB/CcdbApi.h" -#include "Framework/DeviceSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/Task.h" -#include "Framework/Logger.h" - -namespace o2 -{ -namespace dcs -{ - -using namespace o2::dcs; -using DPID = o2::dcs::DataPointIdentifier; -using DPVAL = o2::dcs::DataPointValue; -using DPCOM = o2::dcs::DataPointCompositeObject; - -class DCSDataProcessor : public o2::framework::Task -{ - public: - enum Detectors { - kTest, - // kTPC, // commented out for test, when we use only 1 "Test" detector - kNdetectors - }; - - void init(o2::framework::InitContext& ic) final - { - - // stopping all stopwatches, since they start counting from the moment they are created - for (int idet = 0; idet < kNdetectors; idet++) { - mDeltaProcessingDetLoop[idet].Stop(); - mDeltaProcessingDetLoop[idet].Reset(); - } - - std::vector<DPID> pidVect; - - DPID dpidtmp; - DeliveryType typechar = RAW_CHAR; - std::string dpAliaschar = "TestChar_0"; - DPID::FILL(dpidtmp, dpAliaschar, typechar); - pidVect.push_back(dpidtmp); - - //std::vector<int> vectDet{kTest, kTPC}; // only one detector for now - std::vector<int> vectDet{kTest}; - mDetectorPid[dpidtmp] = vectDet; - - DeliveryType typeint = RAW_INT; - for (int i = 0; i < 50000; i++) { - std::string dpAliasint = "TestInt_" + std::to_string(i); - DPID::FILL(dpidtmp, dpAliasint, typeint); - pidVect.push_back(dpidtmp); - mDetectorPid[dpidtmp] = vectDet; - } - - DeliveryType typedouble = RAW_DOUBLE; - for (int i = 0; i < 4; i++) { - std::string dpAliasdouble = "TestDouble_" + std::to_string(i); - DPID::FILL(dpidtmp, dpAliasdouble, typedouble); - pidVect.push_back(dpidtmp); - mDetectorPid[dpidtmp] = vectDet; - } - - DeliveryType typestring = RAW_STRING; - std::string dpAliasstring0 = "TestString_0"; - DPID::FILL(dpidtmp, dpAliasstring0, typestring); - pidVect.push_back(dpidtmp); - mDetectorPid[dpidtmp] = vectDet; - - mDCSproc.init(pidVect); - mDCSproc.setMaxCyclesNoFullMap(ic.options().get<int64_t>("max-cycles-no-full-map")); - mDCSproc.setName("Test0Det"); - for (int idet = 0; idet < kNdetectors; idet++) { - mDCSprocVect[idet].init(pidVect); - mDCSprocVect[idet].setMaxCyclesNoFullMap(ic.options().get<int64_t>("max-cycles-no-full-map")); - mDCSprocVect[idet].setName("Test1Det"); - } - mProcessFullDeltaMap = ic.options().get<bool>("process-full-delta-map"); - } - - void run(o2::framework::ProcessingContext& pc) final - { - auto tfid = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; - mDCSproc.setTF(tfid); - for (int idet = 0; idet < kNdetectors; idet++) { - mDCSprocVect[idet].setTF(tfid); - } - - TStopwatch s; - LOG(DEBUG) << "TF: " << tfid << " --> receiving binary data..."; - mReceiveBinaryData.Start(mFirstTF); - auto rawchar = pc.inputs().get<const char*>("input"); - mReceiveBinaryData.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...binary data received: realTime = " - << mReceiveBinaryData.RealTime() << ", cpuTime = " - << mReceiveBinaryData.CpuTime(); - LOG(DEBUG) << "TF: " << tfid << " --> receiving (delta) binary data..."; - mDeltaReceiveBinaryData.Start(mFirstTF); - auto rawcharDelta = pc.inputs().get<const char*>("inputDelta"); - mDeltaReceiveBinaryData.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...binary (delta) data received: realTime = " - << mDeltaReceiveBinaryData.RealTime() - << ", cpuTime = " << mDeltaReceiveBinaryData.CpuTime(); - - // full map - const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("input").header); - auto sz = dh->payloadSize; - int nDPs = sz / sizeof(DPCOM); - std::unordered_map<DPID, DPVAL> dcsmap; - DPCOM dptmp; - LOG(DEBUG) << "TF: " << tfid << " --> building unordered_map..."; - mBuildingUnorderedMap.Start(mFirstTF); - for (int i = 0; i < nDPs; i++) { - memcpy(&dptmp, rawchar + i * sizeof(DPCOM), sizeof(DPCOM)); - dcsmap[dptmp.id] = dptmp.data; - LOG(DEBUG) << "Reading from generator: i = " << i << ", DPCOM = " << dptmp; - LOG(DEBUG) << "Reading from generator: i = " << i << ", DPID = " << dptmp.id; - } - mBuildingUnorderedMap.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...unordered_map built = " - << mBuildingUnorderedMap.RealTime() << ", cpuTime = " << mBuildingUnorderedMap.CpuTime(); - - // delta map - const auto* dhDelta = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("inputDelta").header); - auto szDelta = dhDelta->payloadSize; - int nDPsDelta = szDelta / sizeof(DPCOM); - std::unordered_map<DPID, DPVAL> dcsmapDelta; - LOG(DEBUG) << "TF: " << tfid << " --> building (delta) unordered_map..."; - mDeltaBuildingUnorderedMap.Start(mFirstTF); - for (int i = 0; i < nDPsDelta; i++) { - memcpy(&dptmp, rawcharDelta + i * sizeof(DPCOM), sizeof(DPCOM)); - dcsmapDelta[dptmp.id] = dptmp.data; - LOG(DEBUG) << "Reading from generator: i = " << i << ", DPCOM = " << dptmp; - LOG(DEBUG) << "Reading from generator: i = " << i << ", DPID = " << dptmp.id; - } - mDeltaBuildingUnorderedMap.Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...unordered_map (delta) built = " - << mDeltaBuildingUnorderedMap.RealTime() << ", cpuTime = " - << mDeltaBuildingUnorderedMap.CpuTime(); - - if (tfid % 6000 == 0) { - LOG(INFO) << "Number of DPs received = " << nDPs; - for (int idet = 0; idet < kNdetectors; idet++) { - LOG(DEBUG) << "TF: " << tfid << " --> starting processing..."; - mProcessing[idet].Start(mResetStopwatchProcessing); - mDCSprocVect[idet].processMap(dcsmap, false); - mProcessing[idet].Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...processing done: realTime = " - << mProcessing[idet].RealTime() << ", cpuTime = " - << mProcessing[idet].CpuTime(); - } - mResetStopwatchProcessing = false; // from now on, we sum up the processing time - mTFsProcessing++; - } else { - LOG(INFO) << "Number of DPs received (delta map) = " << nDPsDelta; - if (mProcessFullDeltaMap) { - for (int idet = 0; idet < kNdetectors; idet++) { - LOG(DEBUG) << "TF: " << tfid << " --> starting (delta) processing..."; - mDeltaProcessing[idet].Start(mResetStopwatchDeltaProcessing); - mDCSprocVect[idet].processMap(dcsmapDelta, true); - mDeltaProcessing[idet].Stop(); - LOG(DEBUG) << "TF: " << tfid << " --> ...processing (delta) done: realTime = " - << mDeltaProcessing[idet].RealTime() - << ", cpuTime = " << mDeltaProcessing[idet].CpuTime(); - } - mResetStopwatchDeltaProcessing = false; // from now on, we sum up the processing time - mTFsDeltaProcessing++; - } else { - - // processing per DP found in the map, to be done in case of a delta map - - LOG(DEBUG) << "TF: " << tfid << " --> starting (delta) processing in detector loop..."; - for (const auto& dpcom : dcsmapDelta) { - std::vector<int> detVect = mDetectorPid[dpcom.first]; - for (int idet = 0; idet < detVect.size(); idet++) { - mDeltaProcessingDetLoop[idet].Start(mResetStopwatchDeltaProcessingDetLoop); - mDCSprocVect[idet].processDP(dpcom); - mDeltaProcessingDetLoop[idet].Stop(); - } - mResetStopwatchDeltaProcessingDetLoop = false; // from now on, we sum up the processing time - } - for (int idet = 0; idet < kNdetectors; idet++) { - LOG(DEBUG) << "TF: " << tfid << " --> ...processing (delta) in detector loop done: realTime = " - << mDeltaProcessingDetLoop[idet].RealTime() << ", cpuTime = " - << mDeltaProcessingDetLoop[idet].CpuTime(); - } - // now preparing CCDB object - for (int idet = 0; idet < kNdetectors; idet++) { - std::map<std::string, std::string> md; - mDCSprocVect[idet].prepareCCDBobject(mDCSprocVect[idet].getCCDBSimpleMovingAverage(), - mDCSprocVect[idet].getCCDBSimpleMovingAverageInfo(), - mDCSprocVect[idet].getName() + "/TestDCS/SimpleMovingAverageDPs", - tfid, md); - } - mTFsDeltaProcessingDetLoop++; - } - } - sendOutput(pc.outputs()); - mFirstTF = false; - mTFs++; - } - - void endOfStream(o2::framework::EndOfStreamContext& ec) final - { - LOG(INFO) << "\n\nTIMING SUMMARY:\n"; - LOG(INFO) << "Number of processed TF: " << mTFs; - LOG(INFO) << "Number of processed TF, processing full map: " << mTFsProcessing; - LOG(INFO) << "Number of processed TF, processing delta map: " << mTFsDeltaProcessing; - LOG(INFO) << "Number of processed TF, processing delta map per DP: " << mTFsDeltaProcessingDetLoop; - LOG(INFO) << "Receiving binary data --> realTime = " - << mReceiveBinaryData.RealTime() / mTFs << ", cpuTime = " - << mReceiveBinaryData.CpuTime() / mTFs; - LOG(INFO) << "Receiving binary data (delta) --> realTime = " - << mDeltaReceiveBinaryData.RealTime() / mTFs << ", cpuTime = " - << mDeltaReceiveBinaryData.CpuTime() / mTFs; - LOG(INFO) << "Building unordered_map --> realTime = " - << mBuildingUnorderedMap.RealTime() / mTFs << ", cpuTime = " - << mBuildingUnorderedMap.CpuTime() / mTFs; - LOG(INFO) << "Building unordered_map (delta) --> realTime = " - << mDeltaBuildingUnorderedMap.RealTime() / mTFs << ", cpuTime = " - << mDeltaBuildingUnorderedMap.CpuTime() / mTFs; - for (int i = 0; i < kNdetectors; i++) { - LOG(INFO) << " --> : Detector " << i; - if (mTFsProcessing != 0) { - LOG(INFO) << "Processing full map (average over " << mTFsProcessing << " TFs) --> realTime = " - << mProcessing[i].RealTime() / mTFsProcessing << ", cpuTime = " - << mProcessing[i].CpuTime() / mTFsProcessing; - } else { - LOG(INFO) << "Full DCS map was never processed"; - } - if (mTFsDeltaProcessing != 0) { - LOG(INFO) << "Processing full delta map (average over " << mTFsDeltaProcessing << " TFs) --> realTime = " - << mDeltaProcessing[i].RealTime() / mTFsDeltaProcessing << ", cpuTime = " - << mDeltaProcessing[i].CpuTime() / mTFsDeltaProcessing; - } else { - LOG(INFO) << "Full delta DCS map was never processed"; - } - if (mTFsDeltaProcessingDetLoop != 0) { - LOG(INFO) << "Processing delta map per DP (average over " << mTFsDeltaProcessingDetLoop - << " TFs) --> realTime = " - << mDeltaProcessingDetLoop[i].RealTime() / mTFsDeltaProcessingDetLoop << ", cpuTime = " - << mDeltaProcessingDetLoop[i].CpuTime() / mTFsDeltaProcessingDetLoop; - } else { - LOG(INFO) << "Delta map was never process DP by DP"; - } - } - } - - private: - std::unordered_map<DPID, std::vector<int>> mDetectorPid; - std::array<DCSProcessor, kNdetectors> mDCSprocVect; - o2::dcs::DCSProcessor mDCSproc; - TStopwatch mReceiveBinaryData; - TStopwatch mDeltaReceiveBinaryData; - TStopwatch mBuildingUnorderedMap; - TStopwatch mDeltaBuildingUnorderedMap; - TStopwatch mProcessing[kNdetectors]; - TStopwatch mDeltaProcessing[kNdetectors]; - TStopwatch mDeltaProcessingDetLoop[kNdetectors]; - bool mProcessFullDeltaMap = false; - bool mFirstTF = true; - uint64_t mTFs = 0; - uint64_t mTFsProcessing = 0; - uint64_t mTFsDeltaProcessing = 0; - uint64_t mTFsDeltaProcessingDetLoop = 0; - bool mResetStopwatchProcessing = true; - bool mResetStopwatchDeltaProcessing = true; - bool mResetStopwatchDeltaProcessingDetLoop = true; - - //________________________________________________________________ - void sendOutput(DataAllocator& output) - { - // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output - // copied from LHCClockCalibratorSpec.cxx - using clbUtils = o2::calibration::Utils; - const auto& payload = mDCSproc.getCCDBSimpleMovingAverage(); - auto& info = mDCSproc.getCCDBSimpleMovingAverageInfo(); - auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); - LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() - << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); - - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, 0}, *image.get()); - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, 0}, info); - } -}; // end class -} // namespace dcs - -namespace framework -{ - -DataProcessorSpec getDCSDataProcessorSpec() -{ - - using clbUtils = o2::calibration::Utils; - - std::vector<OutputSpec> outputs; - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); - - return DataProcessorSpec{ - "dcs-data-processor", - Inputs{{"input", "DCS", "DATAPOINTS"}, {"inputDelta", "DCS", "DATAPOINTSdelta"}}, - outputs, - AlgorithmSpec{adaptFromTask<o2::dcs::DCSDataProcessor>()}, - Options{ - {"max-cycles-no-full-map", VariantType::Int64, 6000ll, {"max num of cycles between the sending of 2 full maps"}}, - {"process-full-delta-map", VariantType::Bool, false, {"to process the delta map as a whole instead of per DP"}}}}; -} - -} // namespace framework -} // namespace o2 - -#endif diff --git a/Detectors/DCS/testWorkflow/README.md b/Detectors/DCS/testWorkflow/README.md new file mode 100644 index 0000000000000..53874959ea593 --- /dev/null +++ b/Detectors/DCS/testWorkflow/README.md @@ -0,0 +1,82 @@ +<!-- doxy +\page refDetectorsDCStestWorkflow testWorkflow +/doxy --> + +# Standalone example + +Local example workflow with local CCDB (running on port 6464) : + +```shell +o2-dcs-random-data-workflow --max-timeframes=10 | +o2-calibration-ccdb-populator-workflow --ccdb-path http://localhost:6464 +``` + +# Simulation of detector specific data points + +In order to test the processing of their datapoints, subsystems can, for instance, setup a basic workflow chain consisting of a simulator, a processor and a ccdb populator. + +```console +det-dcs-simulator | det-processor | o2-calibration-ccdb-populator-workflow +``` + +The simulator must create a message containing a vector of DataPointCompositeObject for the detector. The processor then does "something" with those data points, and creates a set of object pairs (clbInfo,clbPayload) that are transmitted to the ccdb populator to be uploaded to the CCDB. + +The ccdb populator is an existing workflow that can be reused by any susbsystem. The processor is of course detector specific and must be written accordingly. +The simulator is also detector specific in the sense that each detector has a different set of datapoints to be simulated. It can be written from scratch if so desired, but it can also be written with the help of `getDCSRandomGeneratorSpec` function (defined in the `Detectors/DCS/testWorkflow/include/DCStestWorkflow/DCSRandomDataGeneratorSpec.h` include file) for cases where random generation of data points is sufficient. + +It then boils down to : + +``` +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + + // populate the dphints vector with compact description of what + // data points should be generated using DataPointHint<T> + // + // a DataPointHint is a (pattern,min,max) triplet where the pattern + // is a string pattern that gets exanded to one or several actual + // DCS alias name(s), and the min and max are the actual range of + // the values to be generated. + + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_vp_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_ip_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"TOF_HVSTATUS_SM[00..01]MOD[0..1]", 0, 524287}); + return specs; +} +``` + +A concrete example can be found in the `Detectors/TOF/calibration/testWorkflow` dir : `tof-calibration-dcs-sim-workflow`. + +# dcs-proxy + +It is the proxy to connect to the DCS machine. +For test purposes, you can run with either hard-coded DPs (--test-mode), or reading a configuration entry from CCDB, which can be created with `testWorkflow/macros/makeCCDBEntryForDCS.C`. To validate the retrieval of data, you can attach the workflow `o2-dcs-data-client`, e.g.: + +``` +o2-dcs-proxy --dcs-proxy '--channel-config "name=dcs-proxy,type=pull,method=connect,address=tcp://10.11.28.22:60000,rateLogging=1,transport=zeromq"' --ccdb-url http://localhost:8080 --detector-list COMMON,COMMON1 -b | o2-dcs-data-client -b +``` + + + + + +# dcs-config proxy + +This is a proxy to import the detector configuration files from DCS server into the DPL. A simple test is + +``` +DET="TOF" +CHANFROM='"type=sub,method=connect,address=tcp://127.0.0.1:5556,rateLogging=1,transport=zeromq"' +CHANACK='"type=push,method=connect,address=tcp://127.0.0.1:5557,rateLogging=1,transport=zeromq"' +o2-dcs-config-proxy --subscribe-to $CHANFROM --acknowlege-to $CHANACK | o2-dcs-config-consumer-test-workflow --detector $DET +``` + +to receive from the `CHANFROM` DCS channel the configuration file name (starting with detector name) and the file itself and inject them as DPL messages with specs +`<DET>/DCS_CONFIG_NAME/0` and `<DET>/DCS_CONFIG_FILE/0` respectively. +The `o2-dcs-config-consumer-test-workflow` is a dummy processing device which just consumes such messages for the detector `<DET>`. + +If the `CHANACK` string is not empty, then the acknowledgment string `OK` will be sent to this channel on every reception of the DCS message. diff --git a/Detectors/DCS/testWorkflow/dcs-data-workflow.cxx b/Detectors/DCS/testWorkflow/dcs-data-workflow.cxx deleted file mode 100644 index e22ee95a0a76d..0000000000000 --- a/Detectors/DCS/testWorkflow/dcs-data-workflow.cxx +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DetectorsDCS/DataPointIdentifier.h" -#include "DetectorsDCS/DataPointValue.h" -#include "Framework/TypeTraits.h" -#include <unordered_map> -namespace o2::framework -{ -template <> -struct has_root_dictionary<std::unordered_map<o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue>, void> : std::true_type { -}; -} // namespace o2::framework -#include "Framework/DataProcessorSpec.h" -#include "DCSDataGeneratorSpec.h" -#include "DCSDataProcessorSpec.h" - -using namespace o2::framework; - -// we need to add workflow options before including Framework/runDataProcessing -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - // option allowing to set parameters -} - -// ------------------------------------------------------------------ - -#include "Framework/runDataProcessing.h" - -WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) -{ - WorkflowSpec specs; - specs.emplace_back(getDCSDataGeneratorSpec()); - specs.emplace_back(getDCSDataProcessorSpec()); - return specs; -} diff --git a/Detectors/DCS/testWorkflow/include/DCStestWorkflow/DCSRandomDataGeneratorSpec.h b/Detectors/DCS/testWorkflow/include/DCStestWorkflow/DCSRandomDataGeneratorSpec.h new file mode 100644 index 0000000000000..4167b5fe50cb2 --- /dev/null +++ b/Detectors/DCS/testWorkflow/include/DCStestWorkflow/DCSRandomDataGeneratorSpec.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_TEST_WORKFLOW_RANDOM_DATA_GENERATOR_SPEC_H +#define O2_DCS_TEST_WORKFLOW_RANDOM_DATA_GENERATOR_SPEC_H + +#include "Framework/DataProcessorSpec.h" +#include <variant> +#include <string> +#include <vector> +#include <cstdint> + +namespace o2::dcs::test +{ +/* + * A compact representation a group of alias to be generated + */ +template <typename T> +struct DataPointHint { + std::string aliasPattern; // alias pattern e.g. DET/HV/Crate[0..2]/Channel[000..012]/vMon + T minValue; // minimum value to generate + T maxValue; // maximum value to generate +}; + +using HintType = std::variant<DataPointHint<double>, + DataPointHint<uint32_t>, + DataPointHint<int32_t>, + DataPointHint<char>, + DataPointHint<bool>, + DataPointHint<std::string>>; + +o2::framework::DataProcessorSpec getDCSRandomDataGeneratorSpec(std::vector<HintType> hints = {}, + const char* detName = "TOF"); + +} // namespace o2::dcs::test + +#endif diff --git a/Detectors/DCS/testWorkflow/macros/CMakeLists.txt b/Detectors/DCS/testWorkflow/macros/CMakeLists.txt new file mode 100644 index 0000000000000..2c8bad56fe462 --- /dev/null +++ b/Detectors/DCS/testWorkflow/macros/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro( + makeCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +install(FILES makeCCDBEntryForDCS.C + DESTINATION share/macro/) + diff --git a/Detectors/DCS/testWorkflow/macros/makeCCDBEntryForDCS.C b/Detectors/DCS/testWorkflow/macros/makeCCDBEntryForDCS.C new file mode 100644 index 0000000000000..bea7429d72c81 --- /dev/null +++ b/Detectors/DCS/testWorkflow/macros/makeCCDBEntryForDCS.C @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include <unordered_map> +#include <chrono> + +using DPID = o2::dcs::DataPointIdentifier; + +int makeCCDBEntryForDCS(const std::string url = "http://localhost:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for TOF with the configuration for DCS + std::unordered_map<DPID, std::string> dpid2DataDesc_Common; + std::unordered_map<DPID, std::string> dpid2DataDesc_Common_1; + std::vector<std::string> aliasesCommonStr = {"ADAPOS_LG/TEST_000100", "ADAPOS_LG/TEST_000110"}; + std::vector<std::string> aliasesCommon_1_Int = {"ADAPOS_LG/TEST_000240"}; + std::vector<std::string> aliasesCommon_1_Str = {"ADAPOS_LG/TEST_000200"}; + + DPID dpidtmp; + for (size_t i = 0; i < aliasesCommonStr.size(); ++i) { + DPID::FILL(dpidtmp, aliasesCommonStr[i], o2::dcs::DeliveryType::RAW_STRING); + dpid2DataDesc_Common[dpidtmp] = "COMMON"; + } + for (size_t i = 0; i < aliasesCommon_1_Int.size(); ++i) { + DPID::FILL(dpidtmp, aliasesCommon_1_Int[i], o2::dcs::DeliveryType::RAW_INT); + dpid2DataDesc_Common_1[dpidtmp] = "COMMON1"; + } + for (size_t i = 0; i < aliasesCommon_1_Str.size(); ++i) { + DPID::FILL(dpidtmp, aliasesCommon_1_Str[i], o2::dcs::DeliveryType::RAW_STRING); + dpid2DataDesc_Common_1[dpidtmp] = "COMMON1"; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> md; + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc_Common, "COMMON/Config/DCSDPconfig", md, ts); + api.storeAsTFileAny(&dpid2DataDesc_Common_1, "COMMON1/Config/DCSDPconfig", md, ts); + + return 0; +} diff --git a/Detectors/DCS/testWorkflow/src/DCSConsumerSpec.h b/Detectors/DCS/testWorkflow/src/DCSConsumerSpec.h new file mode 100644 index 0000000000000..b2abfa5f016f0 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/DCSConsumerSpec.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_CONSUMER_H +#define O2_DCS_CONSUMER_H + +/// @file DCSConsumerSpec.h +/// @brief Consumer of DPs coming from DCS server; it is just +/// to check that we receive and pack the data correctly + +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/DataSpecUtils.h" + +using namespace o2::framework; +namespace o2h = o2::header; + +namespace o2 +{ +namespace dcs +{ +class DCSConsumer : public o2::framework::Task +{ + + using DPCOM = o2::dcs::DataPointCompositeObject; + + public: + void init(o2::framework::InitContext& ic) final + { + } + + void run(o2::framework::ProcessingContext& pc) final + { + + uint64_t tfid; + for (auto& input : pc.inputs()) { + tfid = header::get<o2::framework::DataProcessingHeader*>(input.header)->startTime; + LOG(DEBUG) << "tfid = " << tfid; + break; // we break because one input is enough to get the TF ID + } + + LOG(DEBUG) << "TF: " << tfid << " --> reading binary blob..."; + mTFs++; + auto vect = pc.inputs().get<gsl::span<DPCOM>>("COMMONDPs"); + LOG(INFO) << "vector has " << vect.size() << " Data Points inside"; + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + + LOG(INFO) << "Number of processed TFs = " << mTFs; + } + + private: + uint64_t mTFs = 0; +}; + +} // namespace dcs + +namespace framework +{ + +DataProcessorSpec getDCSConsumerSpec() +{ + return DataProcessorSpec{ + "dcs-consumer", + Inputs{{"COMMONDPs", "DCS", "COMMON", 0, Lifetime::Timeframe}}, + Outputs{}, + AlgorithmSpec{adaptFromTask<o2::dcs::DCSConsumer>()}, + Options{}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx b/Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx new file mode 100644 index 0000000000000..200e06eb9e165 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx @@ -0,0 +1,179 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointGenerator.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/Logger.h" +#include "Framework/Task.h" +#include <TDatime.h> +#include <random> +#include <variant> +#include <string> +#include <algorithm> + +using namespace o2::framework; + +namespace +{ +/** generate random integers uniformly distributed within a range. + * + * @param size the number of integers to generate + * @param min the minimum value to be generated + * @param max the maximum value to be generated + * + * @returns a vector of integers + */ +std::vector<int> generateIntegers(size_t size, int min, int max) +{ + std::uniform_int_distribution<int> distribution(min, max); + std::mt19937 generator(std::random_device{}()); + std::vector<int> data; + while (data.size() != size) { + data.emplace_back(distribution(generator)); + std::sort(begin(data), end(data)); + auto last = std::unique(begin(data), end(data)); // make sure we do not duplicate + data.erase(last, end(data)); + } + std::shuffle(begin(data), end(data), generator); + for (auto i = 0; i < data.size(); ++i) { + LOG(DEBUG) << "Generating randomly DP at index " << data[i]; + } + return data; +} + +/** generate DCS data points. + * + * @param hints vector of HintType describing what to generate + * @param fraction fraction of the generated aliases that are returned (1.0 by default) + * + * @returns a vector of DataPointCompositeObjects + */ +std::vector<o2::dcs::DataPointCompositeObject> generate(const std::vector<o2::dcs::test::HintType> hints, + float fraction = 1.0, + uint64_t tfid = 0) +{ + std::vector<o2::dcs::DataPointCompositeObject> dataPoints; + + TDatime d; + auto dsec = d.Convert(); + dsec += tfid; + d.Set(dsec); + + std::string refDate = d.AsSQLString(); + + auto GenerateVisitor = [refDate](const auto& t) { + return o2::dcs::generateRandomDataPoints({t.aliasPattern}, t.minValue, t.maxValue, refDate); + }; + + for (const auto& hint : hints) { + auto dpcoms = std::visit(GenerateVisitor, hint); + for (auto dp : dpcoms) { + dataPoints.push_back(dp); + } + } + if (fraction < 1.0) { + auto indices = generateIntegers(fraction * dataPoints.size(), 0, dataPoints.size() - 1); + std::vector<o2::dcs::DataPointCompositeObject> tmp; + tmp.swap(dataPoints); + dataPoints.clear(); + for (auto i : indices) { + dataPoints.push_back(tmp[i]); + } + } + return dataPoints; +} + +/** + * DCSRandomDataGenerator is an example device that generates random + * DCS Data Points. + * + * The actual description of what is generated is hard-coded in + * the init() method. + */ +class DCSRandomDataGenerator : public o2::framework::Task +{ + public: + DCSRandomDataGenerator(std::vector<o2::dcs::test::HintType> hints, o2::header::DataDescription description); + + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + private: + uint64_t mMaxTF; + uint64_t mTFs = 0; + uint64_t mMaxCyclesNoFullMap; + float mDeltaFraction; + std::vector<o2::dcs::test::HintType> mDataPointHints; + o2::header::DataDescription mDataDescription; +}; + +DCSRandomDataGenerator::DCSRandomDataGenerator(std::vector<o2::dcs::test::HintType> hints, + o2::header::DataDescription description) : mDataPointHints(hints), + mDataDescription(description) {} + +void DCSRandomDataGenerator::init(o2::framework::InitContext& ic) +{ + mMaxTF = ic.options().get<int64_t>("max-timeframes"); + mDeltaFraction = ic.options().get<float>("delta-fraction"); + mMaxCyclesNoFullMap = ic.options().get<int64_t>("max-cycles-no-full-map"); +} + +void DCSRandomDataGenerator::run(o2::framework::ProcessingContext& pc) +{ + auto input = pc.inputs().begin(); + uint64_t tfid = o2::header::get<o2::framework::DataProcessingHeader*>((*input).header)->startTime; + if (tfid >= mMaxTF) { + LOG(INFO) << "Data generator reached TF " << tfid << ", stopping"; + pc.services().get<o2::framework::ControlService>().endOfStream(); + pc.services().get<o2::framework::ControlService>().readyToQuit(o2::framework::QuitRequest::Me); + } + + bool generateFBI = (mTFs % mMaxCyclesNoFullMap == 0); + // fraction is one if we generate FBI (Full Buffer Image) + float fraction = (generateFBI ? 1.0 : mDeltaFraction); + + TDatime d; + auto dpcoms = generate(mDataPointHints, fraction, tfid); + + LOG(INFO) << "***************** TF " << tfid << " has generated " << dpcoms.size() << " DPs"; + pc.outputs().snapshot(Output{"DCS", mDataDescription, 0, Lifetime::Timeframe}, dpcoms); + mTFs++; +} +} // namespace + +namespace o2::dcs::test +{ +o2::framework::DataProcessorSpec getDCSRandomDataGeneratorSpec(std::vector<o2::dcs::test::HintType> hints, + const char* detName) +{ + std::string desc{detName}; + desc += "DATAPOINTS"; + + o2::header::DataDescription dd; + + dd.runtimeInit(desc.c_str(), desc.size()); + + return DataProcessorSpec{ + "dcs-random-data-generator", + Inputs{}, + Outputs{{{"outputDCS"}, "DCS", dd}}, + AlgorithmSpec{adaptFromTask<DCSRandomDataGenerator>(hints, dd)}, + Options{ + {"max-timeframes", VariantType::Int64, 99999999999ll, {"max TimeFrames to generate"}}, + {"delta-fraction", VariantType::Float, 0.05f, {"fraction of data points to put in the delta"}}, + {"max-cycles-no-full-map", VariantType::Int64, 6000ll, {"max num of cycles between the sending of 2 full maps"}}}}; +} +} // namespace o2::dcs::test diff --git a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h new file mode 100644 index 0000000000000..b09299fffbef2 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h @@ -0,0 +1,137 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_DCS_TO_DPL_CONVERTER +#define O2_DCS_TO_DPL_CONVERTER + +#include "Framework/DataSpecUtils.h" +#include "Framework/ExternalFairMQDeviceProxy.h" +#include <fairmq/FairMQParts.h> +#include <fairmq/FairMQDevice.h> +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include <unordered_map> +#include <functional> +#include <string_view> + +namespace o2h = o2::header; +namespace o2f = o2::framework; + +// we need to provide hash function for the DataDescription +namespace std +{ +template <> +struct hash<o2h::DataDescription> { + std::size_t operator()(const o2h::DataDescription& d) const noexcept + { + return std::hash<std::string_view>{}({d.str, size_t(d.size)}); + } +}; +} // namespace std + +namespace o2 +{ +namespace dcs +{ +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; + +/// A callback function to retrieve the FairMQChannel name to be used for sending +/// messages of the specified OutputSpec + +o2f::InjectorFunction dcs2dpl(std::unordered_map<DPID, o2h::DataDescription>& dpid2group, uint64_t startTime, uint64_t step, bool verbose = false) +{ + + auto timesliceId = std::make_shared<size_t>(startTime); + return [dpid2group, timesliceId, step, verbose](FairMQDevice& device, FairMQParts& parts, o2f::ChannelRetriever channelRetriever) { + static std::unordered_map<DPID, DPCOM> cache; // will keep only the latest measurement in the 1-second wide window for each DPID + static auto timer = std::chrono::high_resolution_clock::now(); + + LOG(DEBUG) << "In lambda function: ********* Size of unordered_map (--> number of defined groups) = " << dpid2group.size(); + // We first iterate over the parts of the received message + for (size_t i = 0; i < parts.Size(); ++i) { // DCS sends only 1 part, but we should be able to receive more + auto nDPCOM = parts.At(i)->GetSize() / sizeof(DPCOM); // number of DPCOM in current part + for (size_t j = 0; j < nDPCOM; j++) { + const auto& src = *(reinterpret_cast<const DPCOM*>(parts.At(i)->GetData()) + j); + // do we want to check if this DP was requested ? + auto mapEl = dpid2group.find(src.id); + if (verbose) { + LOG(INFO) << "Received DP " << src.id << " (data = " << src.data << "), matched to output-> " << (mapEl == dpid2group.end() ? "none " : mapEl->second.as<std::string>()); + } + if (mapEl != dpid2group.end()) { + auto& dst = cache[src.id] = src; // this is needed in case in the 1s window we get a new value for the same DP + } + } + } + + auto timerNow = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::ratio<1>> duration = timerNow - timer; + if (duration.count() > 1) { //did we accumulate for 1 sec? + *timesliceId += step; // we increment only if we send something + std::unordered_map<o2h::DataDescription, vector<DPCOM>, std::hash<o2h::DataDescription>> outputs; + // in the cache we have the final values of the DPs that we should put in the output + // distribute DPs over the vectors for each requested output + for (auto& it : cache) { + auto mapEl = dpid2group.find(it.first); + if (mapEl != dpid2group.end()) { + outputs[mapEl->second].push_back(it.second); + } + } + + // create and send output messages + for (auto& it : outputs) { + o2h::DataHeader hdr(it.first, "DCS", 0); + o2f::OutputSpec outsp{hdr.dataOrigin, hdr.dataDescription, hdr.subSpecification}; + if (it.second.empty()) { + LOG(WARNING) << "No data for OutputSpec " << outsp; + continue; + } + auto channel = channelRetriever(outsp, *timesliceId); + if (channel.empty()) { + LOG(WARNING) << "No output channel found for OutputSpec " << outsp << ", discarding its data"; + it.second.clear(); + continue; + } + + hdr.tfCounter = *timesliceId; // this also + hdr.payloadSerializationMethod = o2h::gSerializationMethodNone; + hdr.splitPayloadParts = 1; + hdr.splitPayloadIndex = 1; + hdr.payloadSize = it.second.size() * sizeof(DPCOM); + hdr.firstTForbit = 0; // this should be irrelevant for DCS + o2h::Stack headerStack{hdr, o2::framework::DataProcessingHeader{*timesliceId, 0}}; + auto fmqFactory = device.GetChannel(channel).Transport(); + auto hdMessage = fmqFactory->CreateMessage(headerStack.size(), fair::mq::Alignment{64}); + auto plMessage = fmqFactory->CreateMessage(hdr.payloadSize, fair::mq::Alignment{64}); + memcpy(hdMessage->GetData(), headerStack.data(), headerStack.size()); + memcpy(plMessage->GetData(), it.second.data(), hdr.payloadSize); + if (verbose) { + LOGP(INFO, "Pushing {} DPs to output for TimeSlice", it.second.size(), it.first, *timesliceId, hdr); + } + it.second.clear(); + FairMQParts outParts; + outParts.AddPart(std::move(hdMessage)); + outParts.AddPart(std::move(plMessage)); + o2f::sendOnChannel(device, outParts, channel); + } + + timer = timerNow; + cache.clear(); + } + }; +} + +} // namespace dcs +} // namespace o2 + +#endif /* O2_DCS_TO_DPL_CONVERTER_H */ diff --git a/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx new file mode 100644 index 0000000000000..44b38fa431035 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx @@ -0,0 +1,178 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// example to run: +// o2-dcs-config-proxy --dcs-config-proxy '--channel-config "name=dcs-config-proxy,type=sub,method=connect,address=tcp://127.0.0.1:5556,rateLogging=1,transport=zeromq"' \ +// --acknowlege-to "type=push,method=connect,address=tcp://127.0.0.1:5557,rateLogging=1,transport=zeromq" + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/Lifetime.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ExternalFairMQDeviceProxy.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "Headers/DataHeaderHelpers.h" +#include <fairmq/FairMQDevice.h> +#include "CommonUtils/StringUtils.h" +#include <vector> +#include <string> + +using namespace o2::framework; +using DetID = o2::detectors::DetID; + +void sendAnswer(const std::string& what, const std::string& ack_chan, FairMQDevice& device) +{ + if (!ack_chan.empty()) { + LOG(INFO) << "Sending acknowledgment " << what; + auto fmqFactory = device.GetChannel(ack_chan).Transport(); + auto msg = fmqFactory->CreateMessage(what.size(), fair::mq::Alignment{64}); + memcpy(msg->GetData(), what.c_str(), what.size()); + FairMQParts outParts; + outParts.AddPart(std::move(msg)); + sendOnChannel(device, outParts, ack_chan); + } +} + +auto getDetID(const std::string& filename) +{ + // assume the filename start with detector name + return DetID::nameToID(filename.substr(0, 3).c_str(), DetID::First); +} + +InjectorFunction dcs2dpl(const std::string& acknowledge) +{ + + auto timesliceId = std::make_shared<size_t>(0); + + return [acknowledge, timesliceId](FairMQDevice& device, FairMQParts& parts, ChannelRetriever channelRetriever) { + // make sure just 2 messages received + if (parts.Size() != 2) { + LOG(ERROR) << "received " << parts.Size() << " instead of 2 expected"; + sendAnswer("error0: wrong number of messages", acknowledge, device); + return; + } + std::string filename{static_cast<const char*>(parts.At(0)->GetData()), parts.At(0)->GetSize()}; + size_t filesize = parts.At(1)->GetSize(); + LOG(INFO) << "received file " << filename << " of size " << filesize; + int dID = getDetID(filename); + if (dID < 0) { + LOG(ERROR) << "unknown detector for " << filename; + sendAnswer("error1: unrecognized filename", acknowledge, device); + return; + } + + o2::header::DataHeader hdrF("DCS_CONFIG_FILE", DetID(dID).getDataOrigin(), 0); + o2::header::DataHeader hdrN("DCS_CONFIG_NAME", DetID(dID).getDataOrigin(), 0); + OutputSpec outsp{hdrN.dataOrigin, hdrN.dataDescription, hdrN.subSpecification}; + auto channel = channelRetriever(outsp, *timesliceId); + if (channel.empty()) { + LOG(ERROR) << "No output channel found for OutputSpec " << outsp; + sendAnswer("error2: no channel to send", acknowledge, device); + return; + } + + hdrN.tfCounter = *timesliceId; // this also + hdrN.payloadSerializationMethod = o2::header::gSerializationMethodNone; + hdrN.splitPayloadParts = 1; + hdrN.splitPayloadIndex = 1; + hdrN.payloadSize = parts.At(0)->GetSize(); + hdrN.firstTForbit = 0; // this should be irrelevant for DCS + + hdrF.tfCounter = *timesliceId; // this also + hdrF.payloadSerializationMethod = o2::header::gSerializationMethodNone; + hdrF.splitPayloadParts = 1; + hdrF.splitPayloadIndex = 1; + hdrF.payloadSize = filesize; + hdrF.firstTForbit = 0; // this should be irrelevant for DCS + + auto fmqFactory = device.GetChannel(channel).Transport(); + + o2::header::Stack headerStackF{hdrF, DataProcessingHeader{*timesliceId, 0}}; + auto hdMessageF = fmqFactory->CreateMessage(headerStackF.size(), fair::mq::Alignment{64}); + auto plMessageF = fmqFactory->CreateMessage(hdrF.payloadSize, fair::mq::Alignment{64}); + memcpy(hdMessageF->GetData(), headerStackF.data(), headerStackF.size()); + memcpy(plMessageF->GetData(), parts.At(1)->GetData(), hdrF.payloadSize); + + o2::header::Stack headerStackN{hdrN, DataProcessingHeader{*timesliceId, 0}}; + auto hdMessageN = fmqFactory->CreateMessage(headerStackN.size(), fair::mq::Alignment{64}); + auto plMessageN = fmqFactory->CreateMessage(hdrN.payloadSize, fair::mq::Alignment{64}); + memcpy(hdMessageN->GetData(), headerStackN.data(), headerStackN.size()); + memcpy(plMessageN->GetData(), parts.At(0)->GetData(), hdrN.payloadSize); + + FairMQParts outParts; + outParts.AddPart(std::move(hdMessageF)); + outParts.AddPart(std::move(plMessageF)); + outParts.AddPart(std::move(hdMessageN)); + outParts.AddPart(std::move(plMessageN)); + sendOnChannel(device, outParts, channel); + + sendAnswer("OK", acknowledge, device); + LOG(INFO) << "Sent DPL message and acknowledgment for file " << filename; + }; +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"acknowlege-to", VariantType::String, "type=push,method=connect,address=tcp://127.0.0.1:5557,rateLogging=1,transport=zeromq", {"channel to acknowledge, no acknowledgement if empty"}}); + workflowOptions.push_back(ConfigParamSpec{"subscribe-to", VariantType::String, "type=sub,method=connect,address=tcp://127.0.0.1:5556,rateLogging=1,transport=zeromq", {"channel subscribe to"}}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + auto setChanName = [](const std::string& chan, const std::string& name) { + size_t n = 0; + if (std::string(chan).find("name=") != std::string::npos) { + n = std::string(chan).find(","); + if (n == std::string::npos) { + throw std::runtime_error(fmt::format("wrongly formatted channel: {}", chan)); + } + n++; + } + return o2::utils::Str::concat_string("name=", name, ",", chan.substr(n, chan.size())); + }; + + const std::string devName = "dcs-config-proxy"; + auto chan = config.options().get<std::string>("subscribe-to"); + if (chan.empty()) { + throw std::runtime_error("input channel is not provided"); + } + chan = setChanName(chan, devName); + + auto chanTo = config.options().get<std::string>("acknowlege-to"); + std::string ackChan{}; + if (!chanTo.empty()) { + ackChan = "ackChan"; + chan = o2::utils::Str::concat_string(chan, ";", setChanName(chanTo, ackChan)); + } + LOG(INFO) << "Channels setup: " << chan; + Outputs dcsOutputs; + for (int id = DetID::First; id <= DetID::Last; id++) { + dcsOutputs.emplace_back(DetID(id).getDataOrigin(), "DCS_CONFIG_FILE", 0, Lifetime::Timeframe); + dcsOutputs.emplace_back(DetID(id).getDataOrigin(), "DCS_CONFIG_NAME", 0, Lifetime::Timeframe); + } + + DataProcessorSpec dcsConfigProxy = specifyExternalFairMQDeviceProxy( + devName.c_str(), + std::move(dcsOutputs), + // this is just default, can be overriden by --dcs-config-proxy '--channel-config..' + chan.c_str(), + dcs2dpl(ackChan)); + + WorkflowSpec workflow; + workflow.emplace_back(dcsConfigProxy); + return workflow; +} diff --git a/Detectors/DCS/testWorkflow/src/dcs-config-test-workflow.cxx b/Detectors/DCS/testWorkflow/src/dcs-config-test-workflow.cxx new file mode 100644 index 0000000000000..216850ae23409 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/dcs-config-test-workflow.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; +using DetID = o2::detectors::DetID; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"detector", VariantType::String, "ITS", {"detector name"}}}; + + std::swap(workflowOptions, options); +} +// ------------------------------------------------------------------ + +namespace o2 +{ +namespace dcs +{ +class DCSConfigConsumer : public o2::framework::Task +{ + public: + void run(o2::framework::ProcessingContext& pc) final + { + auto fileBuff = pc.inputs().get<gsl::span<char>>("confFile"); + auto fileName = pc.inputs().get<std::string>("confFileName"); + LOG(INFO) << "got input file " << fileName << " of size " << fileBuff.size(); + } +}; +} // namespace dcs +} // namespace o2 + +DataProcessorSpec getDCSConsumerSpec(DetID det) +{ + std::string procName = "dcs-config-consumer-"; + procName += det.getName(); + return DataProcessorSpec{ + procName, + Inputs{{"confFile", ConcreteDataTypeMatcher{det.getDataOrigin(), "DCS_CONFIG_FILE"}, Lifetime::Timeframe}, + {"confFileName", ConcreteDataTypeMatcher{det.getDataOrigin(), "DCS_CONFIG_NAME"}, Lifetime::Timeframe}}, + Outputs{}, + AlgorithmSpec{adaptFromTask<o2::dcs::DCSConfigConsumer>()}, + Options{}}; +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto detName = configcontext.options().get<std::string>("detector"); + auto detID = DetID::nameToID(detName.c_str(), DetID::First); + if (detID < 0) { + throw std::runtime_error(fmt::format("{} is not a valid detector name", detName)); + } + specs.emplace_back(getDCSConsumerSpec({detID})); + + return specs; +} diff --git a/Detectors/DCS/testWorkflow/src/dcs-data-client-workflow.cxx b/Detectors/DCS/testWorkflow/src/dcs-data-client-workflow.cxx new file mode 100644 index 0000000000000..489a5a4a6b7b7 --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/dcs-data-client-workflow.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/TypeTraits.h" +#include "Framework/DataSpecUtils.h" + +#include "Framework/DataProcessorSpec.h" +#include "DCSConsumerSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + specs.emplace_back(getDCSConsumerSpec()); + return specs; +} diff --git a/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx new file mode 100644 index 0000000000000..20bc9e7f96c5a --- /dev/null +++ b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// example to run: +// o2-dcs-proxy --dcs-proxy '--channel-config "name=dcs-proxy,type=pull,method=connect,address=tcp://10.11.28.22:60000,rateLogging=1,transport=zeromq"' -b + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/Lifetime.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ExternalFairMQDeviceProxy.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DCStoDPLconverter.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Headers/DataHeaderHelpers.h" +#include <vector> +#include <unordered_map> +#include <regex> +#include <string> +#include <unistd.h> + +using namespace o2::framework; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DeliveryType = o2::dcs::DeliveryType; +using CcdbManager = o2::ccdb::BasicCCDBManager; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"verbose", VariantType::Bool, false, {"verbose output"}}); + workflowOptions.push_back(ConfigParamSpec{"test-mode", VariantType::Bool, false, {"test mode"}}); + workflowOptions.push_back(ConfigParamSpec{"ccdb-url", VariantType::String, "http://ccdb-test.cern.ch:8080", {"url of CCDB to get the detectors DPs configuration"}}); + workflowOptions.push_back(ConfigParamSpec{"detector-list", VariantType::String, "TOF, MCH", {"list of detectors for which to process DCS"}}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + bool verbose = config.options().get<bool>("verbose"); + bool testMode = config.options().get<bool>("test-mode"); + std::string url = config.options().get<std::string>("ccdb-url"); + std::string detectorList = config.options().get<std::string>("detector-list"); + + std::unordered_map<DPID, o2h::DataDescription> dpid2DataDesc; + + if (testMode) { + DPID dpidtmp; + DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000100", DeliveryType::RAW_STRING); + dpid2DataDesc[dpidtmp] = "COMMON"; // i.e. this will go to {DCS/COMMON/0} OutputSpec + DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000110", DeliveryType::RAW_STRING); + dpid2DataDesc[dpidtmp] = "COMMON"; + DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000200", DeliveryType::RAW_STRING); + dpid2DataDesc[dpidtmp] = "COMMON1"; + DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000240", DeliveryType::RAW_INT); + dpid2DataDesc[dpidtmp] = "COMMON1"; + } + + else { + auto& mgr = CcdbManager::instance(); + mgr.setURL(url); // http://ccdb-test.cern.ch:8080 or http://localhost:8080 for a local installation + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + std::regex re("[\\s,-]+"); + std::sregex_token_iterator it(detectorList.begin(), detectorList.end(), re, -1); + std::sregex_token_iterator reg_end; + for (; it != reg_end; ++it) { + LOG(INFO) << "DCS DPs configured for detector " << it->str(); + std::unordered_map<DPID, std::string>* dpid2Det = mgr.getForTimeStamp<std::unordered_map<DPID, std::string>>(it->str() + "/Config/DCSDPconfig", ts); + for (auto& el : *dpid2Det) { + o2::header::DataDescription tmpd; + tmpd.runtimeInit(el.second.c_str(), el.second.size()); + dpid2DataDesc[el.first] = tmpd; + } + } + } + + // RS: here we should complete the attribution of different DPs to different outputs + // ... + + // now collect all required outputs to define OutputSpecs for specifyExternalFairMQDeviceProxy + std::unordered_map<o2h::DataDescription, int, std::hash<o2h::DataDescription>> outMap; + for (auto itdp : dpid2DataDesc) { + outMap[itdp.second]++; + } + + Outputs dcsOutputs; + for (auto itout : outMap) { + dcsOutputs.emplace_back("DCS", itout.first, 0, Lifetime::Timeframe); + } + + DataProcessorSpec dcsProxy = specifyExternalFairMQDeviceProxy( + "dcs-proxy", + std::move(dcsOutputs), + "type=pull,method=connect,address=tcp://aldcsadaposactor:60000,rateLogging=1,transport=zeromq", + dcs2dpl(dpid2DataDesc, 0, 1, verbose)); + + WorkflowSpec workflow; + workflow.emplace_back(dcsProxy); + return workflow; +} diff --git a/Detectors/EMCAL/CMakeLists.txt b/Detectors/EMCAL/CMakeLists.txt index 3bdf759039687..032ac3bbd6362 100644 --- a/Detectors/EMCAL/CMakeLists.txt +++ b/Detectors/EMCAL/CMakeLists.txt @@ -1,16 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(simulation) add_subdirectory(calib) +add_subdirectory(calibration) add_subdirectory(testsimulation) add_subdirectory(reconstruction) add_subdirectory(workflow) diff --git a/Detectors/EMCAL/base/CMakeLists.txt b/Detectors/EMCAL/base/CMakeLists.txt index b86b579230afb..1f4b5ca501806 100644 --- a/Detectors/EMCAL/base/CMakeLists.txt +++ b/Detectors/EMCAL/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EMCALBase SOURCES src/Geometry.cxx src/Hit.cxx @@ -36,6 +37,13 @@ o2_add_test(Mapper COMPONENT_NAME emcal LABELS emcal ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) + +o2_add_test(RCUTrailer + SOURCES test/testRCUTrailer.cxx + PUBLIC_LINK_LIBRARIES O2::EMCALBase + COMPONENT_NAME emcal + LABELS emcal + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) o2_add_test_root_macro(test/testGeometryRowColIndexing.C PUBLIC_LINK_LIBRARIES O2::EMCALBase diff --git a/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h b/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h index 088a8cb796292..b3e8a6308452c 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h +++ b/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h index c6e58ceb7cbea..f4a428ed58999 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -391,12 +392,14 @@ class Geometry int SuperModuleNumberFromEtaPhi(Double_t eta, Double_t phi) const; /// \brief Get cell absolute ID number from location module (2 times 2 cells) of a super module - /// \param nSupMod super module number - /// \param nModule module number - /// \param nIphi index of cell in module in phi direction 0 or 1 - /// \param nIeta index of cell in module in eta direction 0 or 1 + /// \param supermoduleID super module number + /// \param moduleID module number + /// \param phiInModule index of cell in module in phi direction 0 or 1 + /// \param etaInModule index of cell in module in eta direction 0 or 1 /// \return cell absolute ID number - Int_t GetAbsCellId(Int_t nSupMod, Int_t nModule, Int_t nIphi, Int_t nIeta) const; + /// \throw InvalidSupermoduleTypeException + /// \throw InvalidCellIDException + int GetAbsCellId(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const; /// \brief Check whether a cell number is valid /// \param absId input absolute cell ID number to check @@ -410,17 +413,18 @@ class Geometry std::tuple<int, int, int, int> GetCellIndex(Int_t absId) const; /// \brief Get eta-phi indexes of module in SM - /// \param nSupMod super module number, input - /// \param nModule module number, input + /// \param supermoduleID super module number, input + /// \param moduleID module number, input /// \return tuple (index in phi direction of module, index in eta direction of module) - std::tuple<int, int> GetModulePhiEtaIndexInSModule(Int_t nSupMod, Int_t nModule) const; + std::tuple<int, int> GetModulePhiEtaIndexInSModule(int supermoduleID, int moduleID) const; /// \brief Get eta-phi indexes of cell in SM - /// \param nSupMod super module number - /// \param nModule module number - /// \param nIphi index in phi direction in module - /// \param nIeta index in phi direction in module - std::tuple<int, int> GetCellPhiEtaIndexInSModule(Int_t nSupMod, Int_t nModule, Int_t nIphi, Int_t nIeta) const; + /// \param supermoduleID super module number + /// \param moduleID module number + /// \param phiInModule index in phi direction in module + /// \param etaInModule index in phi direction in module + /// \return Position (0 - phi, 1 - eta) of the cell inside teh supermodule + std::tuple<int, int> GetCellPhiEtaIndexInSModule(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const; /// \brief Adapt cell indices in supermodule to online indexing /// \param supermoduleID super module number of the channel/cell @@ -468,15 +472,15 @@ class Geometry } /// \brief Transition from cell indexes (iphi, ieta) to module indexes (iphim, ietam, nModule) - /// \param nSupMod super module number - /// \param iphi index of cell in phi direction inside super module - /// \param ieta index of cell in eta direction inside super module + /// \param supermoduleID super module number + /// \param phiInSupermodule index of cell in phi direction inside super module + /// \param etaInSupermodule index of cell in eta direction inside super module /// \return tuple: /// iphim: index of cell in module in phi direction: 0 or 1 /// ietam: index of cell in module in eta direction: 0 or 1 /// nModule: module number /// - std::tuple<Int_t, Int_t, Int_t> GetModuleIndexesFromCellIndexesInSModule(Int_t nSupMod, Int_t iphi, Int_t ieta) const; + std::tuple<int, int, int> GetModuleIndexesFromCellIndexesInSModule(int supermoduleID, int phiInSupermodule, int etaInSupermodule) const; /// \brief Transition from super module number (nSupMod) and cell indexes (ieta,iphi) to cell absolute ID number. /// \param nSupMod super module number @@ -501,6 +505,21 @@ class Geometry /// \throw InvalidCellIDException if cell ID does not exist math_utils::Point3D<double> RelPosCellInSModule(Int_t absId) const; + /// \brief Get link ID, row and column from cell ID, have a look here: https://alice.its.cern.ch/jira/browse/EMCAL-660 + /// \param towerID Cell ID + /// \return link ID + /// \return row + /// \return col + std::tuple<int, int, int> getOnlineID(int towerID); + + /// \brief Temporary link assignment (till final link assignment is known - + /// \brief eventually taken from CCDB) + /// \brief Current mapping can be found under https://alice.its.cern.ch/jira/browse/EMCAL-660 + /// \param ddlID DDL ID + /// \return CRORC ID + /// \return CRORC Link + std::tuple<int, int> getLinkAssignment(int ddlID) const { return std::make_tuple(mCRORCID[ddlID / 2], mCRORCLink[ddlID]); }; + std::vector<EMCALSMType> GetEMCSystem() const { return mEMCSMSystem; } // EMC System, SM type list // Local Coordinates of SM std::vector<Double_t> GetCentersOfCellsEtaDir() const @@ -670,6 +689,9 @@ class Geometry Float_t mSteelFrontThick; ///< Thickness of the front stell face of the support box - 9-sep-04; obsolete? + std::array<int, 20> mCRORCID = {110, 112, 110, 112, 110, 112, 111, 113, 111, 113, 111, 113, 114, 116, 114, 116, 115, 117, 115, 117}; // CRORC ID w.r.t SM + std::array<int, 40> mCRORCLink = {0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 4, -1, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, -1}; // CRORC limk w.r.t FEE ID + mutable const TGeoHMatrix* SMODULEMATRIX[EMCAL_MODULES]; ///< Orientations of EMCAL super modules std::vector<std::tuple<int, int, int, int>> mCellIndexLookup; ///< Lookup table for cell indices diff --git a/Detectors/EMCAL/base/include/EMCALBase/GeometryBase.h b/Detectors/EMCAL/base/include/EMCALBase/GeometryBase.h index 4b760ef78792b..96a68ed86bbc9 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/GeometryBase.h +++ b/Detectors/EMCAL/base/include/EMCALBase/GeometryBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/include/EMCALBase/Hit.h b/Detectors/EMCAL/base/include/EMCALBase/Hit.h index 15570bb09f7fb..640001a64872d 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Hit.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/include/EMCALBase/Mapper.h b/Detectors/EMCAL/base/include/EMCALBase/Mapper.h index 518803527b487..32f606840affd 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Mapper.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Mapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -67,7 +68,6 @@ class Mapper size_t h2 = std::hash<int>()(s.mColumn); size_t h3 = std::hash<int>()(o2::emcal::channelTypeToInt(s.mChannelType)); return ((h1 ^ (h2 << 1)) >> 1) ^ (h3 << 1); - return h1 ^ (h2 << 1); } }; @@ -339,6 +339,12 @@ class MappingHandler /// \throw DDLInvalid if DDL is invalid for EMCAL Mapper& getMappingForDDL(int ddl); + /// \brief Get FEC index for channel based on DDL and information in the channel header + /// \param ddl Absolute DDL index + /// \param channelFEC FEC index in channel header + /// \param branch Branch index (0 or 1) in DDL + int getFEEForChannelInDDL(int dll, int channelFEC, int branch); + private: std::array<Mapper, 4> mMappings; ///< Mapping container diff --git a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h index fb3f6e640ffb1..8723a7a68264b 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h +++ b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,7 @@ #include <string> #include <cstdint> #include <gsl/span> -#include "Rtypes.h" +#include <Rtypes.h> namespace o2 { @@ -30,11 +31,51 @@ namespace emcal /// The RCU trailer can be found at the end of /// the payload and contains general information /// sent by the SRU. +/// +/// Definition of the trailer words: +/// - mFirmwareVersion: Firmware version +/// - mTrailerSize: Size of the trailer in DDL words (32-bit) +/// - mPayloadSize: Size of the payload in DDL words (32-bit) +/// - mFECERRA +/// - mFECERRB +/// - mERRREG2 +/// - mERRREG3 +/// | Bits | Error type | +/// |-----------|-----------------------------------------------| +/// | 0 - 11 | Number of channels with address mismatch | +/// | 12 - 24 | Number of channels with length mismatch | +/// | 25 - 31 | Zeroed (used for trailer word markers) | +/// - mActiveFECsA +/// - mActiveFECsB +/// - mAltroCFG1 (32 bit) +/// | Bits | Setting | +/// |-----------|-----------------------------------------------| +/// | 0-3 | Baseline correction | +/// | 4 | Polarity | +/// | 5-6 | Number of presamples | +/// | 7-10 | Number of postsamples | +/// | 11 | Second baseline correction | +/// | 12-13 | Glitch filter | +/// | 14-16 | Number of postsamples before zero suppression | +/// | 17-18 | Number of presamples before zero suppression | +/// | 19 | Zero suppression on / off | +/// | 20 - 31 | Zeroed (used for trailer word markers) | +/// - mAltroCFG2 (32 bit) +/// | Bits | Setting | +/// |-----------|-----------------------------------------------| +/// | 0 - 4 | L1 phase | +/// | 5 - 9 | Length of the time sample | +/// | 9 | Sparse readout on / off | +/// | 10 - 19 | Number of samples per channel | +/// | 20 - 23 | Number of pretrigger samples | +/// | 24 | ALTRO buffers (0 - 4 buffers, 1 - 8 buffers) | +/// | 25 - 31 | Zeroed (used for trailer word markers) | +/// class RCUTrailer { public: /// \class Error - /// \brief Error handling of the + /// \brief Error handling of the RCU trailer class Error : public std::exception { public: @@ -71,6 +112,13 @@ class RCUTrailer std::string mErrorMessage; ///< Error Message }; + /// \enum BufferMode_t + /// \brief Handler for encoding of the number of ALTRO buffers in the configuration + enum BufferMode_t { + NBUFFERS4 = 0, ///< 4 ALTRO buffers + NBUFFERS8 = 1 ///< 8 ALTRO buffers + }; + /// \brief Constructor RCUTrailer() = default; @@ -93,85 +141,310 @@ class RCUTrailer /// specified in CDH. void constructFromRawPayload(const gsl::span<const uint32_t> payloadwords); - unsigned int getFECErrorsA() const { return mFECERRA; } - unsigned int getFECErrorsB() const { return mFECERRB; } - unsigned short getErrorsG2() const { return mERRREG2; } - unsigned int getErrorsG3() const { return mERRREG3; } - unsigned short getActiveFECsA() const { return mActiveFECsA; } - unsigned short getActiveFECsB() const { return mActiveFECsB; } - unsigned int getAltroCFGReg1() const { return mAltroCFG1; } - unsigned int getAltroCFGReg2() const { return mAltroCFG2; } + /// \brief Get index of the RCU the trailer belongs to + /// \return RCU index int getRCUID() const { return mRCUId; } - unsigned int getTrailerSize() const { return mTrailerSize; } - unsigned int getPayloadSize() const { return mPayloadSize; } - unsigned char getFirmwareVersion() const { return mFirmwareVersion; } - - unsigned short getNumberOfChannelAddressMismatch() const { return (mERRREG3 & 0xFFF); } - unsigned short getNumberOfChannelLengthMismatch() const { return ((mERRREG3 >> 12) & 0x1FFF); } - unsigned char getBaselineCorrection() const { return mAltroCFG1 & 0xF; } - bool getPolarity() const { return (mAltroCFG1 >> 4) & 0x1; } - unsigned char getNumberOfPresamples() const { return (mAltroCFG1 >> 5) & 0x3; } - unsigned char getNumberOfPostsamples() const { return (mAltroCFG1 >> 7) & 0xF; } - bool hasSecondBaselineCorr() const { return (mAltroCFG1 >> 11) & 0x1; } - unsigned char getGlitchFilter() const { return (mAltroCFG1 >> 12) & 0x3; } - unsigned char getNumberOfNonZeroSuppressedPostsamples() const { return (mAltroCFG1 >> 14) & 0x7; } - unsigned char getNumberOfNonZeroSuppressedPresamples() const { return (mAltroCFG1 >> 17) & 0x3; } - bool hasZeroSuppression() const { return (mAltroCFG1 >> 19) & 0x1; } - bool getNumberOfAltroBuffers() const { return (mAltroCFG2 >> 24) & 0x1; } - unsigned char getNumberOfPretriggerSamples() const { return (mAltroCFG2 >> 20) & 0xF; } - unsigned short getNumberOfSamplesPerChannel() const { return (mAltroCFG2 >> 10) & 0x3FF; } - bool isSparseReadout() const { return (mAltroCFG2 >> 9) & 0x1; } + + /// \brief Get the trailer size in number of DDL (32 bit) words + /// \return Size of the RCU trailer + uint32_t getTrailerSize() const { return mTrailerSize; } + + /// \brief Get size of the payload as number of DDL (32-bit) words + /// \return Size of the payload as number of 32 bit workds + uint32_t getPayloadSize() const { return mPayloadSize; } + + /// \brief Get the firmware version + /// \return Firmware version + uint8_t getFirmwareVersion() const { return mFirmwareVersion; } + + /// \brief Set the firmware version + /// \param version Firmware version + void setFirmwareVersion(uint8_t version) { mFirmwareVersion = version; } + + /// \brief Set the ID of the RCU + /// \param rcuid ID of the RCU + void setRCUID(int rcuid) { mRCUId = rcuid; } + + /// \brief set the payload size in number of DDL (32-bit) words + /// \param size Payload size + void setPayloadSize(uint32_t size) { mPayloadSize = size; } /// \brief Access to the sampling time /// \return Sampling time in seconds. /// \throw Error if the RCU trailer was not properly initializied - double getTimeSample() const; - - /// \brief set time sample - /// \param timesample Time sample (in ns) - void setTimeSample(double timesample); + double getTimeSampleNS() const; /// \brief Access to the L1 phase /// \return L1 phase w.r.t to the LHC clock - double getL1Phase() const; - - /// \brief Set the L1 phase - /// \param l1phase L1 phase (in ns) - void setL1Phase(double l1phase); - - void setFECErrorsA(unsigned int value) { mFECERRA = value; } - void setFECErrorsB(unsigned int value) { mFECERRB = value; } - void setErrorsG2(unsigned short value) { mERRREG2 = value; } - void setErrorsG3(unsigned int value) { mERRREG3 = value; } - void setActiveFECsA(unsigned short value) { mActiveFECsA = value; } - void setActiveFECsB(unsigned short value) { mActiveFECsB = value; } - void setAltroCFGReg1(unsigned int value) { mAltroCFG1 = value; } - void setAltroCFGReg2(unsigned int value) { mAltroCFG2 = value; } - void setFirmwareVersion(unsigned char version) { mFirmwareVersion = version; } - void setPayloadSize(unsigned int size) { mPayloadSize = size; } + double getL1PhaseNS() const; + + /// \brief Set the time sample length and L1 phase based on the trigger time + /// \param time Trigger time (in ns) + /// \param timesample Time sample (in ns) + /// + /// L1 phase: Collision time with respect to the sample length. Number + /// of phases: Sample length / bunch spacing (25 ns) + void setTimeSamplePhaseNS(uint64_t triggertime, uint64_t timesample); + + // + // Error counters + // + + /// \brief Get the number of channels with address mismatch + /// \return Number of channels + uint16_t getNumberOfChannelAddressMismatch() const { return mErrorCounter.mNumChannelAddressMismatch; } + + /// \brief Get the number of channels with length mismatch + /// \return Number of channels + uint16_t getNumberOfChannelLengthMismatch() const { return mErrorCounter.mNumChannelLengthMismatch; } + + /// \brief Set the number of channels with address mismatch + /// \param nchannel Number of channels + void setNumberOfChannelAddressMismatch(uint16_t nchannel) { mErrorCounter.mNumChannelAddressMismatch = nchannel; } + + /// \brief Set the number of channels with length mismatch + /// \param nchannel Number of channels + void setNumberOfChannelLengthMismatch(uint8_t nchannel) { mErrorCounter.mNumChannelLengthMismatch = nchannel; } + + uint32_t getFECErrorsA() const { return mFECERRA; } + uint32_t getFECErrorsB() const { return mFECERRB; } + uint16_t getActiveFECsA() const { return mActiveFECsA; } + uint16_t getActiveFECsB() const { return mActiveFECsB; } + void setFECErrorsA(uint32_t value) { mFECERRA = value; } + void setFECErrorsB(uint32_t value) { mFECERRB = value; } + void setActiveFECsA(uint16_t value) { mActiveFECsA = value; } + void setActiveFECsB(uint16_t value) { mActiveFECsB = value; } + + // + // ALTRO configuration + // + + /// \brief Get baseline correction method + /// \return baseline correction method + uint16_t getBaselineCorrection() const { return mAltroConfig.mBaselineCorrection; } + + /// \brief Check polarity setting + /// \return Polarity setting + bool getPolarity() const { return mAltroConfig.mPolarity; } + + /// \brief Get the number of presamples (after zero suppression) + /// \return Number of presamples + uint16_t getNumberOfPresamples() const { return mAltroConfig.mNumPresamples; } + + /// \brief Get the number of postsamples (after zero suppression) + /// \return Number of postsamples + uint16_t getNumberOfPostsamples() const { return mAltroConfig.mNumPostsamples; } + + /// \brief Check if second baseline correction is applied + /// \return True if second baseline correction has been applied, false otherwise + bool hasSecondBaselineCorr() const { return mAltroConfig.mSecondBaselineCorrection; } + + /// \brief Get the glitch filter + /// \return Glitch filter setting + uint16_t getGlitchFilter() const { return mAltroConfig.mGlitchFilter; } + + /// \brief Get the number of postsamples before zero suppression + /// \return Number of postsamples + uint16_t getNumberOfNonZeroSuppressedPostsamples() const { return mAltroConfig.mNumPostsamplesNoZS; } + + /// \brief Get the number of presamples before zero suppression + /// \return Number of presamples + uint16_t getNumberOfNonZeroSuppressedPresamples() const { return mAltroConfig.mNumPresamplesNoZS; } + + /// \brief Check whether zero suppression has been applied + /// \return True if zero suppression has been applied, false otherwise + bool hasZeroSuppression() const { return mAltroConfig.mZeroSuppression; } + + /// \brief Get the number of pretrigger samples + /// \return Number of samples + uint16_t getNumberOfPretriggerSamples() const { return mAltroConfig.mNumSamplesPretrigger; } + + /// \brief Get the number of samples per channel + /// \return Number of samples per channel + uint16_t getNumberOfSamplesPerChannel() const { return mAltroConfig.mNumSamplesChannel; } + + /// \brief Get the number of ALTRO buffers + /// \return Number of Altro Buffers + uint16_t getNumberOfAltroBuffers() const { return BufferMode_t(mAltroConfig.mAltroBuffers) == BufferMode_t::NBUFFERS4 ? 4 : 8; } + + /// \brief Check whether readout is in sparse mode + /// \return True if the readout is in sparse mode, false otherwise + bool isSparseReadout() const { return mAltroConfig.mSparseReadout; } + + /// \brief Set baseline correction method + /// \param baselineCorrection Baseline correction method + void setBaselineCorrection(uint16_t baselineCorrection) { mAltroConfig.mBaselineCorrection = baselineCorrection; } + + /// \brief Set the polarity + /// \param doSet If true polarity is set + void setPolarity(bool doSet) { mAltroConfig.mPolarity = doSet; } + + /// \brief Set the number of presamples (after zero suppression) + /// \param npresamples Number of presamples + void setNumberOfPresamples(uint16_t npresamples) { mAltroConfig.mNumPresamples = npresamples; } + + /// \brief Set the number of postsamples (after zero suppression) + /// \param + void setNumberOfPostsamples(uint16_t npostsamples) { mAltroConfig.mNumPostsamples = npostsamples; } + + /// \brief Specify whether second basedline correction has been applied + /// \param doHave If true a second baseline correction has bben applied + void setSecondBaselineCorrection(bool doHave) { mAltroConfig.mSecondBaselineCorrection = doHave; } + + /// \brief Set the glitch filter + /// \param glitchfilter Glitch filter + void setGlitchFilter(uint16_t glitchfilter) { mAltroConfig.mGlitchFilter = glitchfilter; } + + /// \brief Set the number of postsamples before zero suppression + /// \param npostsamples Number of postsamples + void setNumberOfNonZeroSuppressedPostsamples(uint16_t npostsamples) { mAltroConfig.mNumPostsamplesNoZS = npostsamples; } + + /// \brief Set the number of presamples after zero suppression + /// \param npresamples Number of presamples + void setNumberOfNonZeroSuppressedPresamples(uint16_t npresamples) { mAltroConfig.mNumPresamplesNoZS = npresamples; } + + /// \brief Set the number of pretrigger samples + /// \param nsamples Number of samples + void setNumberOfPretriggerSamples(uint16_t nsamples) { mAltroConfig.mNumSamplesPretrigger = nsamples; } + + /// \brief Set the number of samples per channel + /// \param nsamples Number of samples + void setNumberOfSamplesPerChannel(uint16_t nsamples) { mAltroConfig.mNumSamplesChannel = nsamples; } + + /// \brief Specify whether zero suppression has been applied + /// \param doHave If true zero suppression has been applied + void setZeroSuppression(bool doHave) { mAltroConfig.mZeroSuppression = doHave ? 1 : 0; } + + /// \brief Set sparse readout mode + /// \param isSparse True if readout is in sparse mode, false otherwise + void setSparseReadout(bool isSparse) { mAltroConfig.mSparseReadout = isSparse; } + + /// \brief Set the number of ALTRO buffers + /// \param bufmode Number of ALTRO buffers (4 or 8 buffers) + void setNumberOfAltroBuffers(BufferMode_t bufmode) { mAltroConfig.mAltroBuffers = uint8_t(bufmode); } + + /// + /// Direct access to RCU trailer registers (not recommended) + /// + + /// \brief Get value stored in error counter register 2 + /// \return Value of the register + uint16_t getErrorsG2() const { return mErrorCounter.mErrorRegister2; } + + /// \brief Get value stored in error counter register 3 + /// \return Value of the register + /// \deprecated Use dedicated getters for error counters + uint32_t getErrorsG3() const { return mErrorCounter.mErrorRegister3; } + + /// \brief Get value stored in ALTRO config register 1 + /// \return Value of the register + /// \deprecated Use dedicated getters for ALTRO configuration + uint32_t getAltroCFGReg1() const { return mAltroConfig.mWord1; } + + /// \brief Get value stored in ALTRO config register 1 + /// \return Value of the register + /// \deprecated Use dedicated getters for ALTRO configuration + uint32_t getAltroCFGReg2() const { return mAltroConfig.mWord2; } + + /// \brief Set error counter register 2 + /// \param value Value for register + void setErrorsG2(uint16_t value) { mErrorCounter.mErrorRegister2 = value; } + + /// \brief Set error counter register 3 + /// \param value Value for register + /// \deprecated Use dedicated setters for error counters + void setErrorsG3(uint32_t value) { mErrorCounter.mErrorRegister3 = value; } + + /// \brief Set ALTRO config register 1 + /// \param value Value for register + /// \deprecated Use dedicated setters for configuration + void setAltroCFGReg1(uint32_t value) { mAltroConfig.mWord1 = value; } + + /// \brief Set ALTRO config register 2 + /// \param value Value for register + /// \deprecated Use dedicated setters for configuration + void setAltroCFGReg2(uint32_t value) { mAltroConfig.mWord2 = value; } /// \brief checlks whether the RCU trailer is initialzied /// \return True if the trailer is initialized, false otherwise bool isInitialized() const { return mIsInitialized; } + /// \brief Encode RCU trailer as array of DDL (32-bit) words + /// \return array of trailer words after encoding + /// + /// Encoded trailer words always contain the trailer pattern + /// (bit 30 and bit 31 set) std::vector<uint32_t> encode() const; + /// \brief Decode RCU trailer from payload + /// \return RCU trailer found at the end of the given payload + /// + /// The trailer is expected at the end of the paylaod. Trailer words + /// are identified via their trailer marker (bits 30 and 31), and + /// are assigned based on the trailer word marker. static RCUTrailer constructFromPayloadWords(const gsl::span<const uint32_t> payloadwords); private: - int mRCUId = -1; ///< current RCU identifier - unsigned char mFirmwareVersion = 0; ///< RCU firmware version - unsigned int mTrailerSize = 0; ///< Size of the trailer (in number of 32 bit words) - unsigned int mPayloadSize = 0; ///< Size of the payload (in nunber of 32 bit words) - unsigned int mFECERRA = 0; ///< contains errors related to ALTROBUS transactions - unsigned int mFECERRB = 0; ///< contains errors related to ALTROBUS transactions - unsigned short mERRREG2 = 0; ///< contains errors related to ALTROBUS transactions or trailer of ALTRO channel block - unsigned int mERRREG3 = 0; ///< contains number of altro channels skipped due to an address mismatch - unsigned short mActiveFECsA = 0; ///< bit pattern of active FECs in branch A - unsigned short mActiveFECsB = 0; ///< bit pattern of active FECs in branch B - unsigned int mAltroCFG1 = 0; ///< ALTROCFG1 register - unsigned int mAltroCFG2 = 0; ///< ALTROCFG2 and ALTROIF register - bool mIsInitialized = false; ///< Flag whether RCU trailer is initialized for the given raw event + /// \struct AltroConfig + /// \brief Bit field configuration of the ALTRO config registers + struct AltroConfig { + union { + uint32_t mWord1 = 0; ///< ALTROCFG1 register + struct { + uint32_t mBaselineCorrection : 4; ///< Baseline correction setting + uint32_t mPolarity : 1; ///< Polarity + uint32_t mNumPresamples : 2; ///< Number of presamples + uint32_t mNumPostsamples : 4; ///< Number of postsamples + uint32_t mSecondBaselineCorrection : 1; ///< Second baseline correction + uint32_t mGlitchFilter : 2; ///< Glitch filter + uint32_t mNumPostsamplesNoZS : 3; ///< Number of postsamples without zero suppression + uint32_t mNumPresamplesNoZS : 2; ///< Number of presamples without zero suppression + uint32_t mZeroSuppression : 1; ///< Zero suppression + uint32_t mZero1_1 : 12; ///< Zeroed bits + }; + }; + + union { + uint32_t mWord2 = 0; ///< ALTROCFG2 and ALTROIF register (see class description for bit configuration) + struct { + uint32_t mL1Phase : 5; ///< L1 phase + uint32_t mSampleTime : 4; ///< Length of the time sample + uint32_t mSparseReadout : 1; ///< Sparse readout + uint32_t mNumSamplesChannel : 10; ///< Number of samples per channel + uint32_t mNumSamplesPretrigger : 4; ///< Number of samples per pretrigger + uint32_t mAltroBuffers : 1; ///< Number of ALTRO buffers + uint32_t mZero2_2 : 7; ///< Zeroed bits + }; + }; + }; + + /// \struct ErrorCounters + /// \brief Bit definition for error counter registers + struct ErrorCounters { + union { + uint32_t mErrorRegister2 = 0; ///< contains errors related to ALTROBUS transactions or trailer of ALTRO channel block + }; + union { + uint32_t mErrorRegister3 = 0; ///< contains number of altro channels skipped due to an address mismatch + struct { + uint32_t mNumChannelAddressMismatch : 12; ///< Number of channels with address mismatch + uint32_t mNumChannelLengthMismatch : 13; ///< Number of channels with link mismatch + uint32_t mZero3_1 : 7; ///< Zeroed bits + }; + }; + }; + + int mRCUId = -1; ///< current RCU identifier + uint8_t mFirmwareVersion = 0; ///< RCU firmware version + uint32_t mTrailerSize = 0; ///< Size of the trailer (in number of 32 bit words) + uint32_t mPayloadSize = 0; ///< Size of the payload (in nunber of 32 bit words) + uint32_t mFECERRA = 0; ///< contains errors related to ALTROBUS transactions + uint32_t mFECERRB = 0; ///< contains errors related to ALTROBUS transactions + ErrorCounters mErrorCounter = {0, 0}; ///< Error counter registers + uint16_t mActiveFECsA = 0; ///< bit pattern of active FECs in branch A + uint16_t mActiveFECsB = 0; ///< bit pattern of active FECs in branch B + AltroConfig mAltroConfig = {0, 0}; ///< ALTRO configuration registers + bool mIsInitialized = false; ///< Flag whether RCU trailer is initialized for the given raw event ClassDefNV(RCUTrailer, 1); }; diff --git a/Detectors/EMCAL/base/include/EMCALBase/ShishKebabTrd1Module.h b/Detectors/EMCAL/base/include/EMCALBase/ShishKebabTrd1Module.h index 4e92dfda6e345..7f544bfc4f0e7 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/ShishKebabTrd1Module.h +++ b/Detectors/EMCAL/base/include/EMCALBase/ShishKebabTrd1Module.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/src/ClusterFactory.cxx b/Detectors/EMCAL/base/src/ClusterFactory.cxx index 60a95e8b0ee6c..d35d629a5ecae 100644 --- a/Detectors/EMCAL/base/src/ClusterFactory.cxx +++ b/Detectors/EMCAL/base/src/ClusterFactory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/src/EMCALBaseLinkDef.h b/Detectors/EMCAL/base/src/EMCALBaseLinkDef.h index 865b3fd0d5e6d..4f7d9107a60a4 100644 --- a/Detectors/EMCAL/base/src/EMCALBaseLinkDef.h +++ b/Detectors/EMCAL/base/src/EMCALBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/src/Geometry.cxx b/Detectors/EMCAL/base/src/Geometry.cxx index 239abb334e42d..f27366e349208 100644 --- a/Detectors/EMCAL/base/src/Geometry.cxx +++ b/Detectors/EMCAL/base/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -593,18 +594,26 @@ void Geometry::DefineEMC(std::string_view mcname, std::string_view mctitle) } else { // changed SM Type, redefine the [2*i+1] Boundaries tmpSMType = GetSMType(2 * i); - if (GetSMType(2 * i) == EMCAL_STANDARD) { - mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + kfSupermodulePhiWidth; - } else if (GetSMType(2 * i) == EMCAL_HALF) { - mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 2, mIPDistance); - } else if (GetSMType(2 * i) == EMCAL_THIRD) { - mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 3, mIPDistance); - } else if (GetSMType(2 * i) == DCAL_STANDARD) { // jump the gap - mPhiBoundariesOfSM[2 * i] = (mDCALPhiMin - mArm1PhiMin) * TMath::DegToRad() + mPhiBoundariesOfSM[0]; - mPhiBoundariesOfSM[2 * i + 1] = (mDCALPhiMin - mArm1PhiMin) * TMath::DegToRad() + mPhiBoundariesOfSM[1]; - } else if (GetSMType(2 * i) == DCAL_EXT) { - mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 3, mIPDistance); - } + switch (GetSMType(2 * i)) { + case EMCAL_STANDARD: + mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + kfSupermodulePhiWidth; + break; + case EMCAL_HALF: + mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 2, mIPDistance); + break; + case EMCAL_THIRD: + mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 3, mIPDistance); + break; + case DCAL_STANDARD: + mPhiBoundariesOfSM[2 * i] = (mDCALPhiMin - mArm1PhiMin) * TMath::DegToRad() + mPhiBoundariesOfSM[0]; + mPhiBoundariesOfSM[2 * i + 1] = (mDCALPhiMin - mArm1PhiMin) * TMath::DegToRad() + mPhiBoundariesOfSM[1]; + break; + case DCAL_EXT: + mPhiBoundariesOfSM[2 * i + 1] = mPhiBoundariesOfSM[2 * i] + 2. * TMath::ATan2((mParSM[1]) / 3, mIPDistance); + break; + default: + break; + }; } mPhiCentersOfSM[i] = (mPhiBoundariesOfSM[2 * i] + mPhiBoundariesOfSM[2 * i + 1]) / 2.; mPhiCentersOfSMSec[i] = mPhiBoundariesOfSM[2 * i] + TMath::ATan2(mParSM[1], mIPDistance); @@ -613,7 +622,7 @@ void Geometry::DefineEMC(std::string_view mcname, std::string_view mctitle) // inner extend in eta (same as outer part) for DCal (0.189917), //calculated from the smallest gap (1# cell to the // 80-degree-edge), - Double_t innerExtandedPhi = + const double INNNER_EXTENDED_PHI = 1.102840997; // calculated from the smallest gap (1# cell to the 80-degree-edge), too complicatd to explain... mDCALInnerExtandedEta = -TMath::Log( TMath::Tan((TMath::Pi() / 2. - 8 * mTrd1Angle * TMath::DegToRad() + @@ -623,20 +632,27 @@ void Geometry::DefineEMC(std::string_view mcname, std::string_view mctitle) mEMCALPhiMax = mArm1PhiMin; mDCALPhiMax = mDCALPhiMin; // DCAl extention will not be included for (Int_t i = 0; i < mNumberOfSuperModules; i += 2) { - if (GetSMType(i) == EMCAL_STANDARD) { - mEMCALPhiMax += 20.; - } else if (GetSMType(i) == EMCAL_HALF) { - mEMCALPhiMax += mPhiSuperModule / 2. + innerExtandedPhi; - } else if (GetSMType(i) == EMCAL_THIRD) { - mEMCALPhiMax += mPhiSuperModule / 3. + 4.0 * innerExtandedPhi / 3.0; - } else if (GetSMType(i) == DCAL_STANDARD) { - mDCALPhiMax += 20.; - mDCALStandardPhiMax = mDCALPhiMax; - } else if (GetSMType(i) == DCAL_EXT) { - mDCALPhiMax += mPhiSuperModule / 3. + 4.0 * innerExtandedPhi / 3.0; - } else { - LOG(ERROR) << "Unkown SM Type!!\n"; - } + switch (GetSMType(i)) { + case EMCAL_STANDARD: + mEMCALPhiMax += 20.; + break; + case EMCAL_HALF: + mEMCALPhiMax += mPhiSuperModule / 2. + INNNER_EXTENDED_PHI; + break; + case EMCAL_THIRD: + mEMCALPhiMax += mPhiSuperModule / 3. + 4.0 * INNNER_EXTENDED_PHI / 3.0; + break; + case DCAL_STANDARD: + mDCALPhiMax += 20.; + mDCALStandardPhiMax = mDCALPhiMax; + break; + case DCAL_EXT: + mDCALPhiMax += mPhiSuperModule / 3. + 4.0 * INNNER_EXTENDED_PHI / 3.0; + break; + default: + LOG(ERROR) << "Unkown SM Type!!\n"; + break; + }; } // for compatible reason // if(fNumberOfSuperModules == 4) {fEMCALPhiMax = fArm1PhiMax ;} @@ -706,48 +722,57 @@ std::tuple<double, double> Geometry::EtaPhiFromIndex(Int_t absId) const return std::make_tuple(vglob.Eta(), vglob.Phi()); } -Int_t Geometry::GetAbsCellId(Int_t nSupMod, Int_t nModule, Int_t nIphi, Int_t nIeta) const +int Geometry::GetAbsCellId(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const { // 0 <= nSupMod < fNumberOfSuperModules // 0 <= nModule < fNPHI * fNZ ( fNPHI * fNZ/2 for fKey110DEG=1) // 0 <= nIphi < fNPHIdiv // 0 <= nIeta < fNETAdiv // 0 <= absid < fNCells - Int_t id = 0; // have to change from 0 to fNCells-1 - for (int i = 0; i < nSupMod; i++) { - if (GetSMType(i) == EMCAL_STANDARD) { - id += mNCellsInSupMod; - } else if (GetSMType(i) == EMCAL_HALF) { - id += mNCellsInSupMod / 2; - } else if (GetSMType(i) == EMCAL_THIRD) { - id += mNCellsInSupMod / 3; - } else if (GetSMType(i) == DCAL_STANDARD) { - id += 2 * mNCellsInSupMod / 3; - } else if (GetSMType(i) == DCAL_EXT) { - id += mNCellsInSupMod / 3; - } else { - throw InvalidSupermoduleTypeException(); - } - } - - id += mNCellsInModule * nModule; - id += mNPHIdiv * nIphi; - id += nIeta; - if (!CheckAbsCellId(id)) { - id = -TMath::Abs(id); // if negative something wrong - } - - return id; + int cellid = 0; // have to change from 0 to fNCells-1 + for (int i = 0; i < supermoduleID; i++) { + switch (GetSMType(i)) { + case EMCAL_STANDARD: + cellid += mNCellsInSupMod; + break; + case EMCAL_HALF: + cellid += mNCellsInSupMod / 2; + break; + case EMCAL_THIRD: + cellid += mNCellsInSupMod / 3; + break; + case DCAL_STANDARD: + cellid += 2 * mNCellsInSupMod / 3; + break; + case DCAL_EXT: + cellid += mNCellsInSupMod / 3; + break; + default: + throw InvalidSupermoduleTypeException(); + }; + } + + cellid += mNCellsInModule * moduleID; + cellid += mNPHIdiv * phiInModule; + cellid += etaInModule; + if (!CheckAbsCellId(cellid)) { + throw InvalidCellIDException(cellid); + } + + return cellid; } -std::tuple<Int_t, Int_t, Int_t> Geometry::GetModuleIndexesFromCellIndexesInSModule(Int_t nSupMod, Int_t iphi, Int_t ieta) const +std::tuple<int, int, int> Geometry::GetModuleIndexesFromCellIndexesInSModule(int supermoduleID, int phiInSupermodule, int etaInSupermodule) const { - Int_t nphi = GetNumberOfModuleInPhiDirection(nSupMod); - - Int_t ietam = ieta / mNETAdiv, - iphim = iphi / mNPHIdiv, - nModule = ietam * nphi + iphim; - return std::make_tuple(iphim, ietam, nModule); + int nModulesInSMPhi = GetNumberOfModuleInPhiDirection(supermoduleID); + + int moduleEta = etaInSupermodule / mNETAdiv, + modulePhi = phiInSupermodule / mNPHIdiv, + moduleID = moduleEta * nModulesInSMPhi + modulePhi; + int etaInModule = etaInSupermodule % mNETAdiv, + phiInModule = phiInSupermodule % mNPHIdiv; + //return std::make_tuple(modulePhi, moduleEta, moduleID); + return std::make_tuple(phiInModule, etaInModule, moduleID); } Int_t Geometry::GetAbsCellIdFromCellIndexes(Int_t nSupMod, Int_t iphi, Int_t ieta) const @@ -769,7 +794,7 @@ Int_t Geometry::GetAbsCellIdFromCellIndexes(Int_t nSupMod, Int_t iphi, Int_t iet std::tuple<int, int> Geometry::GlobalRowColFromIndex(int cellID) const { - if (cellID >= GetNCells()) { + if (!CheckAbsCellId(cellID)) { throw InvalidCellIDException(cellID); } auto [supermodule, module, phiInModule, etaInModule] = GetCellIndex(cellID); @@ -899,13 +924,17 @@ Int_t Geometry::GetAbsCellIdFromEtaPhi(Double_t eta, Double_t phi) const phi = TVector2::Phi_0_2pi(phi); Double_t phiLoc = phi - mPhiCentersOfSMSec[nSupMod / 2]; Int_t nphi = mPhiCentersOfCells.size(); - if (GetSMType(nSupMod) == EMCAL_HALF) { - nphi /= 2; - } else if (GetSMType(nSupMod) == EMCAL_THIRD) { - nphi /= 3; - } else if (GetSMType(nSupMod) == DCAL_EXT) { - nphi /= 3; - } + switch (GetSMType(nSupMod)) { + case EMCAL_HALF: + nphi /= 2; + case EMCAL_THIRD: + case DCAL_EXT: + nphi /= 3; + break; + default: + // All other supermodules have full number of cells in phi + break; + }; Double_t dmin = TMath::Abs(mPhiCentersOfCells[0] - phiLoc), d = 0.; @@ -969,19 +998,23 @@ std::tuple<int, int, int, int> Geometry::CalculateCellIndex(Int_t absId) const for (nSupMod = -1; test >= 0;) { nSupMod++; tmp = test; - if (GetSMType(nSupMod) == EMCAL_STANDARD) { - test -= mNCellsInSupMod; - } else if (GetSMType(nSupMod) == EMCAL_HALF) { - test -= mNCellsInSupMod / 2; - } else if (GetSMType(nSupMod) == EMCAL_THIRD) { - test -= mNCellsInSupMod / 3; - } else if (GetSMType(nSupMod) == DCAL_STANDARD) { - test -= 2 * mNCellsInSupMod / 3; - } else if (GetSMType(nSupMod) == DCAL_EXT) { - test -= mNCellsInSupMod / 3; - } else { - throw InvalidSupermoduleTypeException(); - } + switch (GetSMType(nSupMod)) { + case EMCAL_STANDARD: + test -= mNCellsInSupMod; + break; + case EMCAL_HALF: + test -= mNCellsInSupMod / 2; + break; + case DCAL_STANDARD: + test -= 2 * mNCellsInSupMod / 3; + break; + case EMCAL_THIRD: + case DCAL_EXT: + test -= mNCellsInSupMod / 3; + break; + default: + throw InvalidSupermoduleTypeException(); + }; } Int_t nModule = tmp / mNCellsInModule; @@ -1000,37 +1033,38 @@ std::tuple<int, int, int, int> Geometry::GetCellIndex(Int_t absId) const Int_t Geometry::GetSuperModuleNumber(Int_t absId) const { return std::get<0>(GetCellIndex(absId)); } -std::tuple<int, int> Geometry::GetModulePhiEtaIndexInSModule(Int_t nSupMod, Int_t nModule) const +std::tuple<int, int> Geometry::GetModulePhiEtaIndexInSModule(int supermoduleID, int moduleID) const { - Int_t nphi = -1; - if (GetSMType(nSupMod) == EMCAL_HALF) { - nphi = mNPhi / 2; // halfSM - } else if (GetSMType(nSupMod) == EMCAL_THIRD) { - nphi = mNPhi / 3; // 1/3 SM - } else if (GetSMType(nSupMod) == DCAL_EXT) { - nphi = mNPhi / 3; // 1/3 SM - } else { - nphi = mNPhi; // full SM - } - - return std::make_tuple(int(nModule % nphi), int(nModule / nphi)); + int nModulesInPhi = -1; + switch (GetSMType(supermoduleID)) { + case EMCAL_HALF: + nModulesInPhi = mNPhi / 2; // halfSM + break; + case EMCAL_THIRD: + case DCAL_EXT: + nModulesInPhi = mNPhi / 3; // 1/3 SM + break; + default: + nModulesInPhi = mNPhi; // full SM + break; + }; + return std::make_tuple(int(moduleID % nModulesInPhi), int(moduleID / nModulesInPhi)); } -std::tuple<int, int> Geometry::GetCellPhiEtaIndexInSModule(Int_t nSupMod, Int_t nModule, Int_t nIphi, - Int_t nIeta) const +std::tuple<int, int> Geometry::GetCellPhiEtaIndexInSModule(int supermoduleID, int moduleID, int phiInModule, + int etaInModule) const { - auto indices = GetModulePhiEtaIndexInSModule(nSupMod, nModule); - Int_t iphim = std::get<0>(indices), ietam = std::get<1>(indices); + auto [phiOfModule, etaOfModule] = GetModulePhiEtaIndexInSModule(supermoduleID, moduleID); - // ieta = ietam*fNETAdiv + (1-nIeta); // x(module) = -z(SM) - Int_t ieta = ietam * mNETAdiv + (mNETAdiv - 1 - nIeta); // x(module) = -z(SM) - Int_t iphi = iphim * mNPHIdiv + nIphi; // y(module) = y(SM) + // ieta = etaOfModule*fNETAdiv + (1-etaInModule); // x(module) = -z(SM) + int etaInSupermodule = etaOfModule * mNETAdiv + (mNETAdiv - 1 - etaInModule); // x(module) = -z(SM) + int phiInSupermodule = phiOfModule * mNPHIdiv + phiInModule; // y(module) = y(SM) - if (iphi < 0 || ieta < 0) { - LOG(DEBUG) << " nSupMod " << nSupMod << " nModule " << nModule << " nIphi " << nIphi << " nIeta " << nIeta - << " => ieta " << ieta << " iphi " << iphi; + if (phiInSupermodule < 0 || etaInSupermodule < 0) { + LOG(DEBUG) << " Supermodule " << supermoduleID << ", Module " << moduleID << " (phi " << phiInModule << ", eta " << etaInModule << ")" + << " => in Supermodule: eta " << etaInSupermodule << ", phi " << phiInSupermodule; } - return std::make_tuple(iphi, ieta); + return std::make_tuple(phiInSupermodule, etaInSupermodule); } std::tuple<int, int> Geometry::ShiftOnlineToOfflineCellIndexes(Int_t supermoduleID, Int_t iphi, Int_t ieta) const @@ -1762,3 +1796,28 @@ std::tuple<double, double> Geometry::GetPhiBoundariesOfSMGap(Int_t nPhiSec) cons } return std::make_tuple(mPhiBoundariesOfSM[2 * nPhiSec + 1], mPhiBoundariesOfSM[2 * nPhiSec + 2]); } + +std::tuple<int, int, int> Geometry::getOnlineID(int towerID) +{ + auto cellindex = GetCellIndex(towerID); + auto supermoduleID = std::get<0>(cellindex); + auto etaphi = GetCellPhiEtaIndexInSModule(supermoduleID, std::get<1>(cellindex), std::get<2>(cellindex), std::get<3>(cellindex)); + auto etaphishift = ShiftOfflineToOnlineCellIndexes(supermoduleID, std::get<0>(etaphi), std::get<1>(etaphi)); + int row = std::get<0>(etaphishift), col = std::get<1>(etaphishift); + + int ddlInSupermoudel = -1; + if (0 <= row && row < 8) { + ddlInSupermoudel = 0; // first cable row + } else if (8 <= row && row < 16 && 0 <= col && col < 24) { + ddlInSupermoudel = 0; // first half; + } else if (8 <= row && row < 16 && 24 <= col && col < 48) { + ddlInSupermoudel = 1; // second half; + } else if (16 <= row && row < 24) { + ddlInSupermoudel = 1; // third cable row + } + if (supermoduleID % 2 == 1) { + ddlInSupermoudel = 1 - ddlInSupermoudel; // swap for odd=C side, to allow us to cable both sides the same + } + + return std::make_tuple(supermoduleID * 2 + ddlInSupermoudel, row, col); +} diff --git a/Detectors/EMCAL/base/src/Hit.cxx b/Detectors/EMCAL/base/src/Hit.cxx index 4a7f97581942b..39edba54e6b12 100644 --- a/Detectors/EMCAL/base/src/Hit.cxx +++ b/Detectors/EMCAL/base/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/src/Mapper.cxx b/Detectors/EMCAL/base/src/Mapper.cxx index a5619a00a877e..4f6105f39c4bb 100644 --- a/Detectors/EMCAL/base/src/Mapper.cxx +++ b/Detectors/EMCAL/base/src/Mapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -119,8 +120,19 @@ Mapper& MappingHandler::getMappingForDDL(int ddl) return mMappings[sideID * NDDLSM + ddlInSM]; } +int MappingHandler::getFEEForChannelInDDL(int ddl, int channelFEC, int branch) +{ + int ddlInSupermodule = ddl % 2; + int fecID = ddlInSupermodule ? 20 : 0; + if (branch) { + fecID += 10; + } + fecID += channelFEC; + return fecID; +} + std::ostream& o2::emcal::operator<<(std::ostream& stream, const Mapper::ChannelID& channel) { stream << "Row " << static_cast<int>(channel.mRow) << ", Column " << static_cast<int>(channel.mColumn) << ", type " << o2::emcal::channelTypeToString(channel.mChannelType); return stream; -} \ No newline at end of file +} diff --git a/Detectors/EMCAL/base/src/RCUTrailer.cxx b/Detectors/EMCAL/base/src/RCUTrailer.cxx index 5e0e0c962a03f..6df0c141657e5 100644 --- a/Detectors/EMCAL/base/src/RCUTrailer.cxx +++ b/Detectors/EMCAL/base/src/RCUTrailer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,12 +25,12 @@ void RCUTrailer::reset() mPayloadSize = 0; mFECERRA = 0; mFECERRB = 0; - mERRREG2 = 0; - mERRREG3 = 0; + mErrorCounter.mErrorRegister2 = 0; + mErrorCounter.mErrorRegister3 = 0; mActiveFECsA = 0; mActiveFECsB = 0; - mAltroCFG1 = 0; - mAltroCFG2 = 0; + mAltroConfig.mWord1 = 0; + mAltroConfig.mWord2 = 0; mIsInitialized = false; } @@ -60,6 +61,7 @@ void RCUTrailer::constructFromRawPayload(const gsl::span<const uint32_t> payload } int parCode = (word >> 26) & 0xF; int parData = word & 0x3FFFFFF; + // std::cout << "Found trailer word 0x" << std::hex << word << "(Par code: " << std::dec << parCode << ", Par data: 0x" << std::hex << parData << std::dec << ")"; switch (parCode) { case 1: // ERR_REG1 @@ -68,11 +70,11 @@ void RCUTrailer::constructFromRawPayload(const gsl::span<const uint32_t> payload break; case 2: // ERR_REG2 - mERRREG2 = parData & 0x1FF; + mErrorCounter.mErrorRegister2 = parData & 0x1FF; break; case 3: // ERR_REG3 - mERRREG3 = parData & 0x1FFFFFF; + mErrorCounter.mErrorRegister3 = parData & 0x1FFFFFF; break; case 4: // FEC_RO_A @@ -84,11 +86,11 @@ void RCUTrailer::constructFromRawPayload(const gsl::span<const uint32_t> payload break; case 6: // RDO_CFG1 - mAltroCFG1 = parData & 0xFFFFF; + mAltroConfig.mWord1 = parData & 0xFFFFF; break; case 7: // RDO_CFG2 - mAltroCFG2 = parData & 0x1FFFFFF; + mAltroConfig.mWord2 = parData & 0x1FFFFFF; break; default: std::cerr << "Undefined parameter code " << parCode << ", ignore it !\n"; @@ -99,9 +101,9 @@ void RCUTrailer::constructFromRawPayload(const gsl::span<const uint32_t> payload mIsInitialized = true; } -double RCUTrailer::getTimeSample() const +double RCUTrailer::getTimeSampleNS() const { - unsigned char fq = (mAltroCFG2 >> 5) & 0xF; + uint8_t fq = mAltroConfig.mSampleTime; double tSample; switch (fq) { case 0: @@ -120,51 +122,51 @@ double RCUTrailer::getTimeSample() const throw Error(Error::ErrorType_t::SAMPLINGFREQ_INVALID, fmt::format("Invalid sampling frequency value %d !", int(fq)).data()); } - return tSample * o2::constants::lhc::LHCBunchSpacingNS * 1.e-9; + return tSample * o2::constants::lhc::LHCBunchSpacingNS; } -void RCUTrailer::setTimeSample(double timesample) +void RCUTrailer::setTimeSamplePhaseNS(uint64_t triggertime, uint64_t timesample) { - int fq = 0; - if (std::abs(timesample - 50) < DBL_EPSILON) { - fq = 0; - } else if (std::abs(timesample - 100) < DBL_EPSILON) { - fq = 1; - } else if (std::abs(timesample - 200) < DBL_EPSILON) { - fq = 2; - } else { - throw Error(Error::ErrorType_t::SAMPLINGFREQ_INVALID, fmt::format("invalid time sample: %f", timesample).data()); - } - mAltroCFG2 = (mAltroCFG2 & 0x1F) | fq << 5; + int sample = 0; + switch (timesample) { + case 50: + sample = 0; + break; + case 100: + sample = 1; + break; + case 200: + sample = 2; + break; + default: + throw Error(Error::ErrorType_t::SAMPLINGFREQ_INVALID, fmt::format("invalid time sample: %f", timesample).data()); + }; + mAltroConfig.mSampleTime = sample; + // calculate L1 phase + mAltroConfig.mL1Phase = (triggertime % timesample) / 25; } -double RCUTrailer::getL1Phase() const +double RCUTrailer::getL1PhaseNS() const { - double tSample = getTimeSample(), - phase = ((double)(mAltroCFG2 & 0x1F)) * o2::constants::lhc::LHCBunchSpacingNS * 1.e-9; + double tSample = getTimeSampleNS(), + phase = static_cast<double>(mAltroConfig.mL1Phase) * o2::constants::lhc::LHCBunchSpacingNS; if (phase >= tSample) { - throw Error(Error::ErrorType_t::L1PHASE_INVALID, fmt::format("Invalid L1 trigger phase (%e s (phase) >= %e s (sampling time)) !", phase, tSample).data()); + throw Error(Error::ErrorType_t::L1PHASE_INVALID, fmt::format("Invalid L1 trigger phase (%e ns (phase) >= %e ns (sampling time)) !", phase, tSample).data()); } return phase; } -void RCUTrailer::setL1Phase(double l1phase) -{ - int phase = l1phase / 25.; - mAltroCFG2 = (mAltroCFG2 & 0x1E0) | phase; -} - std::vector<uint32_t> RCUTrailer::encode() const { std::vector<uint32_t> encoded; encoded.emplace_back(mPayloadSize | 2 << 30); - encoded.emplace_back(mAltroCFG2 | 7 << 26 | 2 << 30); - encoded.emplace_back(mAltroCFG1 | 6 << 26 | 2 << 30); - encoded.emplace_back(mActiveFECsB | 5 << 26 | 2 << 30); - encoded.emplace_back(mActiveFECsA | 4 << 26 | 2 << 30); - encoded.emplace_back(mERRREG3 | 3 << 26 | 2 << 30); - encoded.emplace_back(mERRREG2 | 2 << 26 | 2 << 30); encoded.emplace_back(mFECERRB >> 7 | (mFECERRA >> 7) << 13 | 1 << 26 | 2 << 30); + encoded.emplace_back(mErrorCounter.mErrorRegister2 | 2 << 26 | 2 << 30); + encoded.emplace_back(mErrorCounter.mErrorRegister3 | 3 << 26 | 2 << 30); + encoded.emplace_back(mActiveFECsA | 4 << 26 | 2 << 30); + encoded.emplace_back(mActiveFECsB | 5 << 26 | 2 << 30); + encoded.emplace_back(mAltroConfig.mWord1 | 6 << 26 | 2 << 30); + encoded.emplace_back(mAltroConfig.mWord2 | 7 << 26 | 2 << 30); uint32_t lasttrailerword = 3 << 30 | mFirmwareVersion << 16 | mRCUId << 7 | (encoded.size() + 1); encoded.emplace_back(lasttrailerword); @@ -177,12 +179,12 @@ void RCUTrailer::printStream(std::ostream& stream) const std::vector<std::string> errors; double timesample = -1., l1phase = -1.; try { - timesample = getTimeSample(); + timesample = getTimeSampleNS(); } catch (Error& e) { errors.push_back(e.what()); } try { - l1phase = getL1Phase(); + l1phase = getL1PhaseNS(); } catch (Error& e) { errors.push_back(e.what()); } @@ -195,26 +197,29 @@ void RCUTrailer::printStream(std::ostream& stream) const << "Payload size: " << mPayloadSize << "\n" << "FECERRA: 0x" << std::hex << mFECERRA << "\n" << "FECERRB: 0x" << std::hex << mFECERRB << "\n" - << "ERRREG2: 0x" << std::hex << mERRREG2 << "\n" + << "ERRREG2: 0x" << std::hex << mErrorCounter.mErrorRegister2 << "\n" + << "ERRREG3: 0x" << std::hex << mErrorCounter.mErrorRegister3 << "\n" << "#channels skipped due to address mismatch: " << std::dec << getNumberOfChannelAddressMismatch() << "\n" << "#channels skipped due to bad block length: " << std::dec << getNumberOfChannelLengthMismatch() << "\n" << "Active FECs (branch A): 0x" << std::hex << mActiveFECsA << "\n" << "Active FECs (branch B): 0x" << std::hex << mActiveFECsB << "\n" - << "Baseline corr: 0x" << std::hex << int(getBaselineCorrection()) << "\n" - << "Number of presamples: " << std::dec << int(getNumberOfPresamples()) << "\n" - << "Number of postsamples: " << std::dec << int(getNumberOfPostsamples()) << "\n" + << "Baseline corr: " << std::hex << getBaselineCorrection() << "\n" + << "Polarity: " << (getPolarity() ? "yes" : "no") << "\n" + << "Number of presamples: " << std::dec << getNumberOfPresamples() << "\n" + << "Number of postsamples: " << std::dec << getNumberOfPostsamples() << "\n" << "Second baseline corr: " << (hasSecondBaselineCorr() ? "yes" : "no") << "\n" - << "GlitchFilter: " << std::dec << int(getGlitchFilter()) << "\n" - << "Number of non-ZS postsamples: " << std::dec << int(getNumberOfNonZeroSuppressedPostsamples()) << "\n" - << "Number of non-ZS presamples: " << std::dec << int(getNumberOfNonZeroSuppressedPresamples()) << "\n" + << "Glitch filter: " << std::dec << getGlitchFilter() << "\n" + << "Number of non-ZS postsamples: " << std::dec << getNumberOfNonZeroSuppressedPostsamples() << "\n" + << "Number of non-ZS presamples: " << std::dec << getNumberOfNonZeroSuppressedPresamples() << "\n" + << "Zero suppression: " << (hasZeroSuppression() ? "yes" : "no") << "\n" << "Number of ALTRO buffers: " << std::dec << getNumberOfAltroBuffers() << "\n" - << "Number of pretrigger samples: " << std::dec << int(getNumberOfPretriggerSamples()) << "\n" + << "Number of pretrigger samples: " << std::dec << getNumberOfPretriggerSamples() << "\n" << "Number of samples per channel: " << std::dec << getNumberOfSamplesPerChannel() << "\n" << "Sparse readout: " << (isSparseReadout() ? "yes" : "no") << "\n" - << "AltroCFG1: 0x" << std::hex << mAltroCFG1 << "\n" - << "AltroCFG2: 0x" << std::hex << mAltroCFG2 << "\n" - << "Sampling time: " << std::scientific << timesample << " s\n" - << "L1 Phase: " << std::scientific << l1phase << " s\n" + << "AltroCFG1: 0x" << std::hex << mAltroConfig.mWord1 << "\n" + << "AltroCFG2: 0x" << std::hex << mAltroConfig.mWord2 << "\n" + << "Sampling time: " << timesample << " ns\n" + << "L1 Phase: " << l1phase << " ns\n" << std::dec << std::fixed; if (errors.size()) { stream << "Errors: \n" diff --git a/Detectors/EMCAL/base/src/ShishKebabTrd1Module.cxx b/Detectors/EMCAL/base/src/ShishKebabTrd1Module.cxx index d33c456f0bf0c..75c9d1662db95 100644 --- a/Detectors/EMCAL/base/src/ShishKebabTrd1Module.cxx +++ b/Detectors/EMCAL/base/src/ShishKebabTrd1Module.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/base/test/testGeometryRowColIndexing.C b/Detectors/EMCAL/base/test/testGeometryRowColIndexing.C index 9006dcdf43277..a05dd89eef923 100644 --- a/Detectors/EMCAL/base/test/testGeometryRowColIndexing.C +++ b/Detectors/EMCAL/base/test/testGeometryRowColIndexing.C @@ -1,12 +1,13 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction +// or submit itself to any jurisdiction. void testGeometryRowColIndexing() { diff --git a/Detectors/EMCAL/base/test/testMapper.cxx b/Detectors/EMCAL/base/test/testMapper.cxx index 78244510b9f8f..5f410020c7881 100644 --- a/Detectors/EMCAL/base/test/testMapper.cxx +++ b/Detectors/EMCAL/base/test/testMapper.cxx @@ -1,13 +1,14 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#define BOOST_TEST_MODULE Test EMCAL Reconstruction +#define BOOST_TEST_MODULE Test EMCAL Base #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> diff --git a/Detectors/EMCAL/base/test/testRCUTrailer.cxx b/Detectors/EMCAL/base/test/testRCUTrailer.cxx new file mode 100644 index 0000000000000..4cbf5ec8d327a --- /dev/null +++ b/Detectors/EMCAL/base/test/testRCUTrailer.cxx @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#define BOOST_TEST_MODULE Test EMCAL Base +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <array> +#include <boost/test/unit_test.hpp> +#include "EMCALBase/RCUTrailer.h" + +/// \macro Test implementation of the EMCAL RCU trailer +/// +/// Test coverage: +/// - ALTRO config +/// - RCU ID +/// - ALTRO buffers +/// - error counters +BOOST_AUTO_TEST_CASE(RCUTrailer_test) +{ + // common settings + int firmware = 2, + activeFECA = 0, + activeFECB = 1, + baselineCorr = 0, + presamples = 0, + postsamples = 0, + glitchfilter = 0, + presamplesNoZS = 1, + postsamplesNoZS = 1, + samplesChannel = 15, + samplesPretrigger = 0, + timesample = 100; + bool havePolarity = false, + haveSecBaselineCorr = false, + haveZS = true, + haveSpareReadout = true; + o2::emcal::RCUTrailer::BufferMode_t bufmode = o2::emcal::RCUTrailer::BufferMode_t::NBUFFERS4; + + o2::emcal::RCUTrailer trailer; + trailer.setRCUID(0); + trailer.setFirmwareVersion(firmware); + trailer.setActiveFECsA(activeFECA); + trailer.setActiveFECsB(activeFECB); + trailer.setPayloadSize(20); + trailer.setTimeSamplePhaseNS(425, timesample); + trailer.setBaselineCorrection(baselineCorr); + trailer.setPolarity(havePolarity); + trailer.setNumberOfPresamples(presamples); + trailer.setNumberOfPostsamples(postsamples); + trailer.setSecondBaselineCorrection(false); + trailer.setGlitchFilter(glitchfilter); + trailer.setNumberOfNonZeroSuppressedPostsamples(postsamplesNoZS); + trailer.setNumberOfNonZeroSuppressedPresamples(presamplesNoZS); + trailer.setNumberOfPretriggerSamples(samplesPretrigger); + trailer.setNumberOfSamplesPerChannel(samplesChannel); + trailer.setZeroSuppression(haveZS); + trailer.setSparseReadout(haveSpareReadout); + trailer.setNumberOfAltroBuffers(bufmode); + + // + // check ALTRO config + // + auto encoded_config = trailer.encode(); + auto trailer_decoded_config = o2::emcal::RCUTrailer::constructFromPayloadWords(encoded_config); + BOOST_CHECK_EQUAL(trailer_decoded_config.getFirmwareVersion(), firmware); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfPresamples(), presamples); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfPostsamples(), postsamples); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfNonZeroSuppressedPresamples(), presamplesNoZS); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfNonZeroSuppressedPostsamples(), postsamplesNoZS); + BOOST_CHECK_EQUAL(trailer_decoded_config.getGlitchFilter(), glitchfilter); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfPretriggerSamples(), samplesPretrigger); + BOOST_CHECK_EQUAL(trailer_decoded_config.getNumberOfSamplesPerChannel(), samplesChannel); + BOOST_CHECK_EQUAL(trailer_decoded_config.getPolarity(), havePolarity); + BOOST_CHECK_EQUAL(trailer_decoded_config.hasSecondBaselineCorr(), haveSecBaselineCorr); + BOOST_CHECK_EQUAL(trailer_decoded_config.hasZeroSuppression(), haveZS); + BOOST_CHECK_EQUAL(trailer_decoded_config.isSparseReadout(), haveSpareReadout); + BOOST_CHECK_EQUAL(trailer_decoded_config.getActiveFECsA(), activeFECA); + BOOST_CHECK_EQUAL(trailer_decoded_config.getActiveFECsB(), activeFECB); + BOOST_CHECK_CLOSE(trailer_decoded_config.getTimeSampleNS(), timesample, 1); + BOOST_CHECK_CLOSE(trailer_decoded_config.getL1PhaseNS(), 25, 1); + + // + // Check RCU ID + // + for (int ircu = 0; ircu < 46; ircu++) { + trailer.setRCUID(ircu); + auto encoded_rcu = trailer.encode(); + auto trailer_decoded_rcu = o2::emcal::RCUTrailer::constructFromPayloadWords(encoded_rcu); + BOOST_CHECK_EQUAL(trailer_decoded_rcu.getRCUID(), ircu); + } + trailer.setRCUID(0); + + // + // Check buffer modes + // + std::map<o2::emcal::RCUTrailer::BufferMode_t, int> buffertests = {{o2::emcal::RCUTrailer::BufferMode_t::NBUFFERS4, 4}, {o2::emcal::RCUTrailer::BufferMode_t::NBUFFERS8, 8}}; + for (auto [bufmode, nbuffers] : buffertests) { + trailer.setNumberOfAltroBuffers(bufmode); + auto encoded_buffer = trailer.encode(); + auto trailer_decoded_buffer = o2::emcal::RCUTrailer::constructFromPayloadWords(encoded_buffer); + BOOST_CHECK_EQUAL(trailer_decoded_buffer.getNumberOfAltroBuffers(), nbuffers); + } + trailer.setNumberOfAltroBuffers(bufmode); + + // + // Check error counters + // + std::array<int, 10> nerrors = {0, 1, 6, 10, 112, 232, 255, 52, 22, 76}; + for (auto error : nerrors) { + trailer.setNumberOfChannelLengthMismatch(error); + auto encoded_error = trailer.encode(); + auto trailer_decoded_error = o2::emcal::RCUTrailer::constructFromPayloadWords(encoded_error); + BOOST_CHECK_EQUAL(trailer_decoded_error.getNumberOfChannelLengthMismatch(), error); + } + trailer.setNumberOfChannelAddressMismatch(0); + for (auto error : nerrors) { + trailer.setNumberOfChannelAddressMismatch(error); + auto encoded_error = trailer.encode(); + auto trailer_decoded_error = o2::emcal::RCUTrailer::constructFromPayloadWords(encoded_error); + BOOST_CHECK_EQUAL(trailer_decoded_error.getNumberOfChannelAddressMismatch(), error); + } + trailer.setNumberOfChannelAddressMismatch(0); +} \ No newline at end of file diff --git a/Detectors/EMCAL/calib/CMakeLists.txt b/Detectors/EMCAL/calib/CMakeLists.txt index 6edbc6633b94a..9e1b01c52deac 100644 --- a/Detectors/EMCAL/calib/CMakeLists.txt +++ b/Detectors/EMCAL/calib/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EMCALCalib SOURCES src/BadChannelMap.cxx @@ -19,8 +20,11 @@ o2_add_library(EMCALCalib src/TriggerSTUDCS.cxx src/TriggerSTUErrorCounter.cxx src/TriggerDCS.cxx + src/FeeDCS.cxx src/CalibDB.cxx - PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase) + src/ElmbMeasurement.cxx + src/EMCDCSProcessor.cxx + PUBLIC_LINK_LIBRARIES O2::CCDB O2::DetectorsDCS O2::EMCALBase) o2_target_root_dictionary(EMCALCalib HEADERS include/EMCALCalib/BadChannelMap.h @@ -33,7 +37,11 @@ o2_target_root_dictionary(EMCALCalib include/EMCALCalib/TriggerSTUDCS.h include/EMCALCalib/TriggerSTUErrorCounter.h include/EMCALCalib/TriggerDCS.h + include/EMCALCalib/FeeDCS.h include/EMCALCalib/CalibDB.h + include/EMCALCalib/ElmbData.h + include/EMCALCalib/ElmbMeasurement.h + include/EMCALCalib/EMCDCSProcessor.h LINKDEF src/EMCALCalibLinkDef.h) o2_add_test(BadChannelMap @@ -157,4 +165,14 @@ o2_add_test_root_macro(macros/TriggerDCS_CalibDBTest.C PUBLIC_LINK_LIBRARIES O2::EMCALCalib LABELS emcal COMPILE_ONLY) +o2_add_test_root_macro(macros/makeEMCALCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB + LABELS emcal COMPILE_ONLY) + +o2_add_test_root_macro(macros/readEMCALDCSentries.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB O2::EMCALCalib + LABELS emcal COMPILE_ONLY) + + o2_data_file(COPY files DESTINATION Detectors/EMC) + diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/BadChannelMap.h b/Detectors/EMCAL/calib/include/EMCALCalib/BadChannelMap.h index 507298af17a6d..998300e86af59 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/BadChannelMap.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/BadChannelMap.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h b/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h index d34a3052311a5..2d1ca5a6a94c9 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/EMCDCSProcessor.h b/Detectors/EMCAL/calib/include/EMCALCalib/EMCDCSProcessor.h new file mode 100644 index 0000000000000..5657b05ea71fa --- /dev/null +++ b/Detectors/EMCAL/calib/include/EMCALCalib/EMCDCSProcessor.h @@ -0,0 +1,134 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_EMCDCSPROCESSOR_H_ +#define ALICEO2_EMCAL_EMCDCSPROCESSOR_H_ + +#include <Rtypes.h> +#include <gsl/gsl> + +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DeliveryType.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" + +#include "EMCALCalib/ElmbMeasurement.h" +#include "EMCALCalib/TriggerTRUDCS.h" +#include "EMCALCalib/TriggerSTUDCS.h" +#include "EMCALCalib/TriggerDCS.h" +#include "EMCALCalib/FeeDCS.h" +#include "EMCALCalib/ElmbData.h" + +namespace o2 +{ + +namespace emcal +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using EMCFEE = o2::emcal::TriggerDCS; +using EMCELMB = o2::emcal::ElmbMeasurement; + +class EMCDCSProcessor +{ + + public: + using TFType = uint64_t; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + + EMCDCSProcessor() = default; + ~EMCDCSProcessor() = default; + + void init(const std::vector<DPID>& pids); + int process(const gsl::span<const DPCOM> dps); + int processDP(const DPCOM& dpcom); + void processElmb(); + + void printPDCOM(const DPCOM& dpcom); + + const FeeDCS& getFeeDCSdata() const { return *mFEECFG; } + const ElmbData& getELMBdata() const { return *mELMBdata; } + + bool isUpdateELMB() { return mUpdateELMB; } + bool isUpdateFEEcfg() { return mUpdateFEEcfg; } + + const CcdbObjectInfo& getccdbELMBinfo() const { return mccdbELMBinfo; } + const CcdbObjectInfo& getccdbFeeDCSinfo() const { return mccdbFEEcfginfo; } + + CcdbObjectInfo& getccdbELMBinfo() { return mccdbELMBinfo; } + CcdbObjectInfo& getccdbFeeDCSinfo() { return mccdbFEEcfginfo; } + + void updateFeeCCDBinfo(); + void updateElmbCCDBinfo(); + + void useVerboseMode() { mVerbose = true; } + + template <typename T> + void prepareCCDBobjectInfo(const T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, + const std::map<std::string, std::string>& md); + + void setTF(TFType tf) { mTF = tf; } + void setElmbCCDBupdateRate(TFType tf) { mElmbCCDBupdateRate = tf; } + + private: + TFType mTF{0}; // TF index for processing + TFType mTFprevELMB{0}; // TF index of previous ELMB data update in CCDB + TFType mElmbCCDBupdateRate{1000}; // duration (in TF units) for averaging and updating the ELMB data in CCDB + + std::unordered_map<DPID, bool> mPids; // contains all PIDs for the processor, the bool + // will be true if the DP was processed at least once + std::unordered_map<DPID, std::vector<DPVAL>> mapFEEcfg; // containds FEE CGF data + + bool mUpdateFEEcfg{false}; + bool mUpdateELMB{false}; + CcdbObjectInfo mccdbELMBinfo; + CcdbObjectInfo mccdbFEEcfginfo; + + std::unique_ptr<FeeDCS> mFEECFG; + std::unique_ptr<EMCELMB> mELMB; + std::unique_ptr<ElmbData> mELMBdata; + + o2::emcal::TriggerSTUDCS mSTU; + //o2::emcal::TriggerTRUDCS mTRU; + TriggerTRUDCS mTRU; + + void FillFeeDP(const DPCOM& dpcom); + void FillElmbDP(const DPCOM& dpcom); + + bool mVerbose = false; + + ClassDefNV(EMCDCSProcessor, 1); +}; + +template <typename T> +void EMCDCSProcessor::prepareCCDBobjectInfo(const T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, + const std::map<std::string, std::string>& md) +{ + + // prepare all info to be sent to CCDB for object obj + auto clName = o2::utils::MemFileHelper::getClassName(obj); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + info.setPath(path); + info.setObjectType(clName); + info.setFileName(flName); + info.setStartValidityTimestamp(tf); + info.setEndValidityTimestamp(99999999999999); + info.setMetaData(md); +} + +} // namespace emcal +} // namespace o2 +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/ElmbData.h b/Detectors/EMCAL/calib/include/EMCALCalib/ElmbData.h new file mode 100644 index 0000000000000..f3fc339866aa7 --- /dev/null +++ b/Detectors/EMCAL/calib/include/EMCALCalib/ElmbData.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_ELMBDATA_H_ +#define ALICEO2_EMCAL_ELMBDATA_H_ + +#include <vector> +#include <tuple> +#include <Rtypes.h> + +namespace o2 +{ +namespace emcal +{ + +const int NElmbSensors = 180; +typedef std::tuple<int, float, float, float, float> Sensor_t; //{Npoints, mean, rms, min, max} + +class ElmbData +{ + + public: + ElmbData() = default; + ~ElmbData() = default; + + void setData(std::vector<Sensor_t> data) { mELMB = data; } + void setSensor(int iSensor, Sensor_t data) { mELMB[iSensor] = data; } + void setSensor(int iSensor, int Npoints, float mean, float rms, float min, float max) + { + mELMB[iSensor] = std::make_tuple(Npoints, mean, rms, min, max); + } + + std::vector<Sensor_t> getData() { return mELMB; } + Sensor_t getSensor(short iSensor) { return mELMB[iSensor]; } + int getNpoints(short iSensor) { return std::get<0>(mELMB[iSensor]); } + float getMean(short iSensor) { return std::get<1>(mELMB[iSensor]); } + float getRMS(short iSensor) { return std::get<2>(mELMB[iSensor]); } + float getMin(short iSensor) { return std::get<3>(mELMB[iSensor]); } + float getMax(short iSensor) { return std::get<4>(mELMB[iSensor]); } + + private: + std::vector<Sensor_t> mELMB; ///< data container + + ClassDefNV(ElmbData, 1); +}; + +} // namespace emcal + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/ElmbMeasurement.h b/Detectors/EMCAL/calib/include/EMCALCalib/ElmbMeasurement.h new file mode 100644 index 0000000000000..471abf4cd6afa --- /dev/null +++ b/Detectors/EMCAL/calib/include/EMCALCalib/ElmbMeasurement.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_ELMBMEASUREMENT_H_ +#define ALICEO2_EMCAL_ELMBMEASUREMENT_H_ + +#include <vector> +#include <tuple> +#include <Rtypes.h> + +#include "EMCALCalib/ElmbData.h" + +namespace o2 +{ + +namespace emcal +{ + +//typedef std::tuple <int, float, float, float, float> Sensor_t; //{Npoints, mean, rms, min, max} + +class ElmbMeasurement +{ + + public: + ElmbMeasurement() = default; + ~ElmbMeasurement() = default; + + void init(); + void process(); + void reset(); + + void addMeasurement(int iPT, double val) { values[iPT].push_back(val); } + + std::vector<Sensor_t> getData() { return mELMBdata; } + std::vector<std::vector<double>> getValues() { return values; } + + private: + std::vector<std::vector<double>> values; ///<container with measured values + std::vector<float> values_prev; ///< last measurement per sensor + std::vector<Sensor_t> mELMBdata; // + + ClassDefNV(ElmbMeasurement, 1); +}; + +} // namespace emcal + +} // namespace o2 +#endif diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/FeeDCS.h b/Detectors/EMCAL/calib/include/EMCALCalib/FeeDCS.h new file mode 100644 index 0000000000000..828b844129439 --- /dev/null +++ b/Detectors/EMCAL/calib/include/EMCALCalib/FeeDCS.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_FEEDCS_H_ +#define ALICEO2_EMCAL_FEEDCS_H_ + +#include <memory> +#include <iosfwd> +#include <array> +#include <Rtypes.h> +#include <bitset> + +#include "EMCALCalib/TriggerDCS.h" + +namespace o2 +{ + +namespace emcal +{ + +const Int_t kNTRU = 46; // this + +class FeeDCS +{ + + public: + /// \brief default constructor + FeeDCS() = default; + + /// \brief Destructor + ~FeeDCS() = default; + + /// \brief copy constructor + FeeDCS(const FeeDCS& fee) = default; + + /// \brief Assignment operator + FeeDCS& operator=(const FeeDCS& source) = default; + + bool operator==(const FeeDCS& other) const; + + o2::emcal::TriggerDCS getTriggerDCS() const { return mTrigDCS; } + o2::emcal::TriggerTRUDCS getTRUDCS(Int_t iTRU) const { return mTrigDCS.getTRUDCS(iTRU); } + o2::emcal::TriggerSTUDCS getSTUDCSEMCal() const { return mTrigDCS.getSTUDCSEMCal(); } + o2::emcal::TriggerSTUDCS getSTUDCSDCal() const { return mTrigDCS.getSTUDCSDCal(); } + std::bitset<32> getDDLlist0() const { return mLinks0; } + std::bitset<14> getDDLlist1() const { return mLinks1; } + unsigned int getSRUFWversion(int ism = 0) const { return mSRUFWversion.at(ism); } + unsigned int getSRUconfig(int ism = 0) const { return mSRUcfg.at(ism); } + int getNSRUbuffers(int ism = 0) const { return (mSRUcfg.at(ism) >> 1 & 0x7); } + + void setTRUDCS(Int_t iTRU, o2::emcal::TriggerTRUDCS tru) { mTrigDCS.setTRU(iTRU, tru); } + void setSTUEMCal(o2::emcal::TriggerSTUDCS stu) { mTrigDCS.setSTUEMCal(stu); } + void setSTUDCal(o2::emcal::TriggerSTUDCS stu) { mTrigDCS.setSTUDCal(stu); } + void setDDLlist0(unsigned int a) { mLinks0 = std::bitset<32>(a); } + void setDDLlist1(unsigned int a) { mLinks1 = std::bitset<14>(a); } + void setSRUFWversion(int ism, unsigned int ver) { mSRUFWversion.at(ism) = ver; } + void setSRUconfig(int ism, unsigned int ver) { mSRUcfg.at(ism) = ver; } + + bool isDDLactive(int iDDL) { return (iDDL < 32 ? mLinks0.test(iDDL) : mLinks1.test(iDDL - 32)); } + bool isSMactive(int iSM); + bool isEMCalSTUactive() { return mLinks1.test(12); } // EMCAL STU FEEID is 44 + bool isDCalSTUactive() { return mLinks1.test(13); } // EMCAL STU FEEID is 45 + + private: + o2::emcal::TriggerDCS mTrigDCS; ///< TRU and STU config + std::bitset<32> mLinks0; ///< info on first 32 DDLs included in RO, 1 means the DDL is active + std::bitset<14> mLinks1; ///< info on remining 14 DDLs included in RO, 1 means the DDL is active + std::array<unsigned int, 20> mSRUFWversion; ///< SRU FW version + std::array<unsigned int, 20> mSRUcfg; ///< SRU configuration + + ClassDefNV(FeeDCS, 1); +}; + +std::ostream& operator<<(std::ostream& in, const FeeDCS& dcs); + +} // namespace emcal + +} // namespace o2 +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/GainCalibrationFactors.h b/Detectors/EMCAL/calib/include/EMCALCalib/GainCalibrationFactors.h index b56430979f1c7..1f048dc9738c0 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/GainCalibrationFactors.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/GainCalibrationFactors.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibParamSM.h b/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibParamSM.h index 142a76716ba76..fa8f9fffba48f 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibParamSM.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibParamSM.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibrationParams.h b/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibrationParams.h index 5626e65e6dd7b..f8eb8efd72657 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibrationParams.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TempCalibrationParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibParamL1Phase.h b/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibParamL1Phase.h index 4684b73b9f49f..dd13089a272e0 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibParamL1Phase.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibParamL1Phase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibrationParams.h b/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibrationParams.h index 610daefedb264..8733448beea2b 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibrationParams.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TimeCalibrationParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerDCS.h b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerDCS.h index 2706ac40f2a41..e7197588765a7 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerDCS.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerDCS.h @@ -1,12 +1,17 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_TRIGGERDCS_H +#define ALICEO2_EMCAL_TRIGGERDCS_H + #include <iosfwd> #include <array> #include <Rtypes.h> @@ -37,6 +42,12 @@ class TriggerDCS /// \brief Destructor ~TriggerDCS() = default; + /// \brief copy constructor + TriggerDCS(const TriggerDCS& trg) = default; + + /// \brief Assignment operator + TriggerDCS& operator=(const TriggerDCS& source) = default; + /// \brief Comparison of two DCS data /// \return true if the TRU data are identical, false otherwise /// @@ -48,18 +59,17 @@ class TriggerDCS /// \return JSON-serialized trigger DCS config object std::string toJSON() const; - void setTRUArr(std::vector<TriggerTRUDCS>& ta) { mTRUArr = ta; } - void setTRU(TriggerTRUDCS tru) { mTRUArr.emplace_back(tru); } - void setSTUEMCal(TriggerSTUDCS so) { mSTUEMCal = so; } void setSTUDCal(TriggerSTUDCS so) { mSTUDCAL = so; } - std::vector<TriggerTRUDCS> getTRUArr() const { return mTRUArr; } + std::array<TriggerTRUDCS, 46> getTRUArr() const { return mTRUArr; } TriggerSTUDCS getSTUDCSEMCal() const { return mSTUEMCal; } TriggerSTUDCS getSTUDCSDCal() const { return mSTUDCAL; } TriggerTRUDCS getTRUDCS(Int_t iTRU) const { return mTRUArr.at(iTRU); } + void setTRU(Int_t iTRU, TriggerTRUDCS a) { mTRUArr.at(iTRU) = a; } + /// \brief Check whether TRU is enabled /// \param iTRU Index of the TRU /// Enabled-status defined via presence of the TRU in the STU region: TRU @@ -67,9 +77,9 @@ class TriggerDCS bool isTRUEnabled(int iTRU) const; private: - std::vector<TriggerTRUDCS> mTRUArr; ///< TRU array - TriggerSTUDCS mSTUEMCal; ///< STU of EMCal - TriggerSTUDCS mSTUDCAL; ///< STU of DCAL + TriggerSTUDCS mSTUEMCal; ///< STU of EMCal + TriggerSTUDCS mSTUDCAL; ///< STU of DCAL + std::array<TriggerTRUDCS, 46> mTRUArr; ///< TRU array ClassDefNV(TriggerDCS, 1); }; @@ -83,3 +93,5 @@ std::ostream& operator<<(std::ostream& in, const TriggerDCS& dcs); } // namespace emcal } // namespace o2 + +#endif diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUDCS.h b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUDCS.h index c618f6add9570..eff9144aa67c1 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUDCS.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUDCS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUErrorCounter.h b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUErrorCounter.h index 8cb639ca16d7a..38079676c60e8 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUErrorCounter.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerSTUErrorCounter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerTRUDCS.h b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerTRUDCS.h index ea3e05be96f9e..b762f00e21e1b 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/TriggerTRUDCS.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/TriggerTRUDCS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/BadChannelMap_CCDBApitest.C b/Detectors/EMCAL/calib/macros/BadChannelMap_CCDBApitest.C index 9865dfb0c79b5..ff8d6c8acc8f2 100644 --- a/Detectors/EMCAL/calib/macros/BadChannelMap_CCDBApitest.C +++ b/Detectors/EMCAL/calib/macros/BadChannelMap_CCDBApitest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/BadChannelMap_CalibDBtest.C b/Detectors/EMCAL/calib/macros/BadChannelMap_CalibDBtest.C index 96218fb64ad16..05e8d8fcef94c 100644 --- a/Detectors/EMCAL/calib/macros/BadChannelMap_CalibDBtest.C +++ b/Detectors/EMCAL/calib/macros/BadChannelMap_CalibDBtest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CCDBApiTest.C index 58a5e3f1c8d8f..6f3e93449d4c1 100644 --- a/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CalibDBTest.C b/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CalibDBTest.C index f08581121b1f9..a75d3363333ed 100644 --- a/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/GainCalibrationFactors_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C b/Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C index f57e30c2e2a31..c64143f067fd9 100644 --- a/Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C +++ b/Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TempCalibParamSM_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/TempCalibParamSM_CCDBApiTest.C index 685d3c60c8d4b..a3689d951ea7d 100644 --- a/Detectors/EMCAL/calib/macros/TempCalibParamSM_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/TempCalibParamSM_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TempCalibParamSM_CalibDBTest.C b/Detectors/EMCAL/calib/macros/TempCalibParamSM_CalibDBTest.C index 6232a8ff3bc13..9b393463c36d4 100644 --- a/Detectors/EMCAL/calib/macros/TempCalibParamSM_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/TempCalibParamSM_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TempCalibrationParams_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/TempCalibrationParams_CCDBApiTest.C index 1cf1d101a5785..4d7e0bcaa3704 100644 --- a/Detectors/EMCAL/calib/macros/TempCalibrationParams_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/TempCalibrationParams_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TempCalibrationParams_CalibDBTest.C b/Detectors/EMCAL/calib/macros/TempCalibrationParams_CalibDBTest.C index 04bf0975cf862..002ad79f91aba 100644 --- a/Detectors/EMCAL/calib/macros/TempCalibrationParams_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/TempCalibrationParams_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CCDBApiTest.C index 202dbb3db017f..ae6865a06b6ec 100644 --- a/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CalibDBTest.C b/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CalibDBTest.C index f7bc03456c734..d1cf60a5148b7 100644 --- a/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/TimeCalibParamsL1Phase_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CCDBApiTest.C index dc7bbf9e11dee..24511ff3aa08a 100644 --- a/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CalibDBTest.C b/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CalibDBTest.C index 609624b1e75fc..a63bf854fd834 100644 --- a/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/TimeCalibrationParams_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/macros/TriggerDCS_CCDBApiTest.C b/Detectors/EMCAL/calib/macros/TriggerDCS_CCDBApiTest.C index fc9cf04faed4c..695b333f19063 100644 --- a/Detectors/EMCAL/calib/macros/TriggerDCS_CCDBApiTest.C +++ b/Detectors/EMCAL/calib/macros/TriggerDCS_CCDBApiTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -96,7 +97,7 @@ void TriggerDCS_CCDBApiTest(const std::string_view ccdbserver = "emcccdb-test.ce dcs->setSTUEMCal(stuEMCal); dcs->setSTUDCal(stuDCal); - dcs->setTRU(tru); + dcs->setTRU(0, tru); // Set time limits: These are from the start of the run validity range (252235) to the end of the run validity range (267166) LHC16 auto rangestart = create_timestamp(2016, 4, 23, 0, 58, 40), diff --git a/Detectors/EMCAL/calib/macros/TriggerDCS_CalibDBTest.C b/Detectors/EMCAL/calib/macros/TriggerDCS_CalibDBTest.C index 68b0c842d00d6..6ebe114c1a8c3 100644 --- a/Detectors/EMCAL/calib/macros/TriggerDCS_CalibDBTest.C +++ b/Detectors/EMCAL/calib/macros/TriggerDCS_CalibDBTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -95,7 +96,7 @@ void TriggerDCS_CalibDBTest(const std::string_view ccdbserver = "emcccdb-test.ce dcs->setSTUEMCal(stuEMCal); dcs->setSTUDCal(stuDCal); - dcs->setTRU(tru); + dcs->setTRU(0, tru); // Set time limits: These are from the start of the run validity range (252235) to the end of the run validity range (267166) LHC16 auto rangestart = create_timestamp(2016, 4, 23, 0, 58, 40), diff --git a/Detectors/EMCAL/calib/macros/makeEMCALCCDBEntryForDCS.C b/Detectors/EMCAL/calib/macros/makeEMCALCCDBEntryForDCS.C new file mode 100644 index 0000000000000..99ab45c5ccf7a --- /dev/null +++ b/Detectors/EMCAL/calib/macros/makeEMCALCCDBEntryForDCS.C @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include <unordered_map> +#include <chrono> + +using DPID = o2::dcs::DataPointIdentifier; + +int makeEMCALCCDBEntryForDCS(const std::string url = "http://ccdb-test.cern.ch:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for EMC with the configuration for DCS + std::unordered_map<DPID, std::string> dpid2DataDesc; + + std::vector<std::string> aliasesTEMP = {"EMC_PT_[00..83]/Temperature", "EMC_PT_[88..91]/Temperature", "EMC_PT_[96..159]/Temperature"}; + std::vector<std::string> aliasesUINT = {"EMC_DDL_LIST[0..1]", "EMC_SRU[00..19]_CFG", "EMC_SRU[00..19]_FMVER", + "EMC_TRU[00..45]_PEAKFINDER", "EMC_TRU[00..45]_L0ALGSEL", "EMC_TRU[00..45]_COSMTHRESH", + "EMC_TRU[00..45]_GLOBALTHRESH", "EMC_TRU[00..45]_MASK[0..5]", + "EMC_STU_ERROR_COUNT_TRU[0..67]", "DMC_STU_ERROR_COUNT_TRU[0..55]"}; + std::vector<std::string> aliasesINT = {"EMC_STU_FWVERS", "EMC_STU_GA[0..1]", "EMC_STU_GB[0..1]", "EMC_STU_GC[0..1]", + "EMC_STU_JA[0..1]", "EMC_STU_JB[0..1]", "EMC_STU_JC[0..1]", "EMC_STU_PATCHSIZE", "EMC_STU_GETRAW", + "EMC_STU_MEDIAN", "EMC_STU_REGION", "DMC_STU_FWVERS", "DMC_STU_PHOS_scale[0..3]", "DMC_STU_GA[0..1]", + "DMC_STU_GB[0..1]", "DMC_STU_GC[0..1]", "DMC_STU_JA[0..1]", "DMC_STU_JB[0..1]", "DMC_STU_JC[0..1]", + "DMC_STU_PATCHSIZE", "DMC_STU_GETRAW", "DMC_STU_MEDIAN", "DMC_STU_REGION"}; + + std::vector<std::string> expaliasesTEMP = o2::dcs::expandAliases(aliasesTEMP); + std::vector<std::string> expaliasesUINT = o2::dcs::expandAliases(aliasesUINT); + std::vector<std::string> expaliasesINT = o2::dcs::expandAliases(aliasesINT); + + DPID dpidtmp; + for (size_t i = 0; i < expaliasesTEMP.size(); ++i) { + DPID::FILL(dpidtmp, expaliasesTEMP[i], o2::dcs::DeliveryType::RAW_DOUBLE); + dpid2DataDesc[dpidtmp] = "EMCDATAPOINTS"; + } + for (size_t i = 0; i < expaliasesINT.size(); ++i) { + DPID::FILL(dpidtmp, expaliasesINT[i], o2::dcs::DeliveryType::RAW_INT); + dpid2DataDesc[dpidtmp] = "EMCDATAPOINTS"; + } + for (size_t i = 0; i < expaliasesUINT.size(); ++i) { + DPID::FILL(dpidtmp, expaliasesUINT[i], o2::dcs::DeliveryType::RAW_UINT); + dpid2DataDesc[dpidtmp] = "EMCDATAPOINTS"; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> md; + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc, "EMC/Config/DCSDPconfig", md, ts); + + return 0; +} diff --git a/Detectors/EMCAL/calib/macros/readEMCALDCSentries.C b/Detectors/EMCAL/calib/macros/readEMCALDCSentries.C new file mode 100644 index 0000000000000..ce89dfd0808d3 --- /dev/null +++ b/Detectors/EMCAL/calib/macros/readEMCALDCSentries.C @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// macro to read the EMC DCS information from CCDB +// default ts is very big: Saturday, November 20, 2286 5:46:39 PM + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "EMCALCalib/ElmbData.h" +#include "EMCALCalib/EMCDCSProcessor.h" + +//#include <string> +//#include <unordered_map> +#include <chrono> +#include <bitset> +#endif + +using namespace o2::emcal; + +void printElmbData(std::vector<Sensor_t> data); + +void readEMCALDCSentries(long ts = 9999999999000, const char* ccdb = "http://ccdb-test.cern.ch:8080") +{ + + o2::ccdb::CcdbApi api; + api.init(ccdb); // or http://localhost:8080 + std::map<std::string, std::string> metadata; + if (ts == 9999999999000) { + ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + FeeDCS* feeDCS(nullptr); + feeDCS = api.retrieveFromTFileAny<FeeDCS>("EMC/FeeDCS", metadata, ts); + if (!feeDCS) { + std::cerr << "No FeeDCS object received from CCDB" << std::endl; + } else { + std::cout << *feeDCS << std::endl; + } + + ElmbData* mELMBdata(nullptr); + mELMBdata = api.retrieveFromTFileAny<ElmbData>("EMC/Temperature", metadata, ts); + if (!mELMBdata) { + std::cerr << "No Temperature object received from CCDB" << std::endl; + } else { + printElmbData(mELMBdata->getData()); + } + + return; +} + +void printElmbData(std::vector<Sensor_t> data) +{ + + std::cout << "Temperature sensor data\n"; + std::cout << "sensor# index | Npoints | mean | rms | min | max\n"; + for (int i = 0; i < 180; i++) { + if (get<0>(data[i]) < 1) + continue; + std::cout << "sensor# " << i << " | "; + std::cout << get<0>(data[i]) << " | "; + std::cout << get<1>(data[i]) << " | "; + std::cout << get<2>(data[i]) << " | "; + std::cout << get<3>(data[i]) << " | "; + std::cout << get<4>(data[i]) << std::endl; + } +} diff --git a/Detectors/EMCAL/calib/src/BadChannelMap.cxx b/Detectors/EMCAL/calib/src/BadChannelMap.cxx index 4fed9e4ec7cd6..8594e60da4483 100644 --- a/Detectors/EMCAL/calib/src/BadChannelMap.cxx +++ b/Detectors/EMCAL/calib/src/BadChannelMap.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/CalibDB.cxx b/Detectors/EMCAL/calib/src/CalibDB.cxx index d845f9e1bcfdc..36b48d44717ef 100644 --- a/Detectors/EMCAL/calib/src/CalibDB.cxx +++ b/Detectors/EMCAL/calib/src/CalibDB.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h b/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h index 2adb3af2074bc..5123d7f10113e 100644 --- a/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h +++ b/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,5 +26,9 @@ #pragma link C++ class o2::emcal::TriggerSTUDCS + ; #pragma link C++ class o2::emcal::TriggerSTUErrorCounter + ; #pragma link C++ class o2::emcal::TriggerDCS + ; +#pragma link C++ class o2::emcal::FeeDCS + ; +#pragma link C++ class o2::emcal::ElmbData + ; +#pragma link C++ class o2::emcal::ElmbMeasurement + ; +#pragma link C++ class o2::emcal::EMCDCSProcessor + ; #endif diff --git a/Detectors/EMCAL/calib/src/EMCDCSProcessor.cxx b/Detectors/EMCAL/calib/src/EMCDCSProcessor.cxx new file mode 100644 index 0000000000000..84e5ee1b08ab1 --- /dev/null +++ b/Detectors/EMCAL/calib/src/EMCDCSProcessor.cxx @@ -0,0 +1,314 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class EMCDCSProcessor +/// \brief DCS processor for EMCAL DPs +/// \ingroup EMCALcalib +/// \author Martin Poghosyan <martin.poghosyan@cern.ch>, ORNL +/// \since Sep 5th, 2021 +/// +/// processing of all DPs incuded (except of STU_TRU_ERROR counters) +/// improvemts expected: +/// 1. archive the configuration DPs only at DCS SOR +/// 2. include the processing of STU_TRU_ERROR counters +/// +/// macro for reading the data from CCDB +/// O2/Detectors/EMCAL/calib/macros/readEMCALDCSentries.C +/// +/// macro for creating the EMC aliases for DCS/Config: +/// O2/Detectors/EMCAL/calib/macros/makeEMCALCCDBEntryForDCS.C +/// They must match with those defined in PARA and in EMCALDCSDataProcessorSpec +/// + +#include <map> +#include <iterator> +#include "EMCALCalib/EMCDCSProcessor.h" + +using namespace o2::dcs; +using namespace o2::emcal; + +using DeliveryType = o2::dcs::DeliveryType; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; + +void EMCDCSProcessor::init(const std::vector<DPID>& pids) +{ + + for (const auto& it : pids) { + mPids[it] = false; + } + + mFEECFG = std::make_unique<FeeDCS>(); + mELMB = std::make_unique<EMCELMB>(); + mELMBdata = std::make_unique<ElmbData>(); + + mELMB->init(); + + mTFprevELMB = 0; +} + +int EMCDCSProcessor::process(const gsl::span<const DPCOM> dps) +{ + mUpdateFEEcfg = false; + mUpdateELMB = false; + + if (mVerbose) { + LOG(INFO) << "\n\n\nProcessing new TF\n-----------------"; + } + + for (auto& it : dps) { + const auto& el = mPids.find(it.id); + + if (el == mPids.end()) { + LOG(DEBUG) << "DP " << it.id << " not found in the map of expected DPs- ignoring..."; + continue; + } else { + LOG(DEBUG) << "DP " << it.id << " found in map"; + } + + processDP(it); + } + + return 0; +} + +void EMCDCSProcessor::processElmb() +{ + + mUpdateELMB = true; + mELMB->process(); + mELMBdata->setData(mELMB->getData()); + mELMB->reset(); +} + +int EMCDCSProcessor::processDP(const DPCOM& dp) +{ + + auto& dpid = dp.id; + const auto& type = dpid.get_type(); + auto& val = dp.data; + + if (mVerbose) { + if (type == RAW_DOUBLE) { + LOG(INFO) << "Processing DP = " << dp << ", with value = " << o2::dcs::getValue<double>(dp); + } else if (type == RAW_INT) { + LOG(INFO) << "Processing DP = " << dp << ", with value = " << o2::dcs::getValue<int32_t>(dp); + } else if (type == RAW_UINT) { + LOG(INFO) << "Processing DP = " << dp << ", with value = " << o2::dcs::getValue<uint32_t>(dp); + } + } + + if ((type == RAW_INT) || (type == RAW_UINT)) // FEE config params and STU_TRU error counters + { + auto& dpval_prev = mapFEEcfg[dpid]; + if (dpval_prev.size() == 0 || val.get_epoch_time() != dpval_prev.back().get_epoch_time()) //compate the time stamps + { + dpval_prev.push_back(val); // do we need to archive them all????? + mUpdateFEEcfg = true; + + FillFeeDP(dp); + setTF(val.get_epoch_time()); // fix: this must not be here! + } + } else if (type == RAW_DOUBLE) { // ELMB data + FillElmbDP(dp); + } + //printPDCOM(dp); + + return 0; +} + +void EMCDCSProcessor::FillElmbDP(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto type = dpid.get_type(); + std::string type_str = show(type); + + std::string alias(dpid.get_alias()); + + auto& dpval = dpcom.data; + auto val = o2::dcs::getValue<double>(dpcom); //dpval.payload_pt1; + + std::size_t index; + int iPT = -1; + + if ((index = alias.find("EMC_PT")) != std::string::npos) { + std::sscanf(alias.data(), "EMC_PT_%d.Temperature", &iPT); + LOG(DEBUG) << "alias=" << alias.data() << ": iPT=" << iPT << ", val=" << val; + + if (iPT < 0 || iPT > 159) { + LOG(ERROR) << "Wrong Sensor Index iPT=" << iPT << " for DP " << alias.data(); + return; + } + mELMB->addMeasurement(iPT, val); + } else { + LOG(INFO) << "EMC_PT pattern not found for DPype = RAW_DOUBLE: alias = " << alias.data(); + } + return; +} + +void EMCDCSProcessor::FillFeeDP(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto type = dpid.get_type(); + std::string type_str = show(type); + + std::string alias(dpid.get_alias()); + + auto& dpval = dpcom.data; + auto ts = dpval.get_epoch_time(); + auto val = dpval.payload_pt1; + + std::size_t index; + int iTRU = -1; + int iMask = -1; + int iSM = -1; + + // if (mVerbose) { + // LOG(INFO) << "EMCDCSProcessor::FillFeeDP called"; + // } + // + + if ((index = alias.find("STU_ERROR_COUNT_TRU")) != std::string::npos) { + // processing of STU_TRU error counters not included yet + return; + } else if (alias.find("EMC_DDL_LIST0") != std::string::npos) { + mFEECFG->setDDLlist0(val); + } else if (alias.find("EMC_DDL_LIST1") != std::string::npos) { + mFEECFG->setDDLlist1(val); + } else if ((index = alias.find("SRU")) != std::string::npos) { + if ((index = alias.find("FMVER")) != std::string::npos) { + std::sscanf((std::string(alias.substr(index - 3, 2))).data(), "%02d", &iSM); + if (iSM < 0 || iSM >= 20) { + LOG(ERROR) << "ERROR : iSM = " << iSM << " for" << alias.data(); + return; + } + mFEECFG->setSRUFWversion(iSM, val); + } else if ((index = alias.find("CFG")) != std::string::npos) { + std::sscanf((std::string(alias.substr(index - 3, 2))).data(), "%02d", &iSM); + if (iSM < 0 || iSM >= 20) { + LOG(ERROR) << "ERROR : iSM = " << iSM << " for" << alias.data(); + return; + } + mFEECFG->setSRUconfig(iSM, val); + } + } else if ((index = alias.find("TRU")) != std::string::npos) { + std::sscanf((std::string(alias.substr(index + 3, 2))).data(), "%02d", &iTRU); + + if (iTRU < 0 || iTRU >= kNTRU) { + LOG(ERROR) << "ERROR : iTRU = " << iTRU << " for" << alias.data(); + return; + } + + mTRU = mFEECFG->getTRUDCS(iTRU); + if (alias.find("L0ALGSEL") != std::string::npos) { + mTRU.setL0SEL(val); + } else if (alias.find("PEAKFINDER") != std::string::npos) { + mTRU.setSELPF(val); + } else if (alias.find("GLOBALTHRESH") != std::string::npos) { + mTRU.setGTHRL0(val); + } else if (alias.find("COSMTHRESH") != std::string::npos) { + mTRU.setL0COSM(val); + } else if ((index = alias.find("MASK")) != std::string::npos) { + std::sscanf((std::string(alias.substr(index + 4, 1))).data(), "%02d", &iMask); + mTRU.setMaskReg(val, iMask); + if (iMask < 0 || iMask > 5) { + LOG(ERROR) << "ERROR : iMask = " << iMask << " for" << alias.data(); + return; + } + } + + mFEECFG->setTRUDCS(iTRU, mTRU); + } else if ((index = alias.find("_STU_")) != std::string::npos) { + bool kEMC = (std::string(alias.substr(index - 3, 3))).compare(0, 3, "DMC", 0, 3); + mSTU = kEMC ? mFEECFG->getSTUDCSEMCal() : mFEECFG->getSTUDCSDCal(); + + if (alias.find("MEDIAN") != std::string::npos) { + mSTU.setMedianMode(val); + } else if (alias.find("GETRAW") != std::string::npos) { + mSTU.setRawData(val); + } else if (alias.find("REGION") != std::string::npos) { + mSTU.setRegion(val); + } else if (alias.find("FWVERS") != std::string::npos) { + mSTU.setFw(val); + } else if (alias.find("PATCHSIZE") != std::string::npos) { + mSTU.setPatchSize(val); + } else if ((index = alias.find("STU_G")) != std::string::npos) { + char par1; + int par2; + std::sscanf((std::string(alias.substr(index + 5, 2))).data(), "%c%d", &par1, &par2); + if (par2 == 0) { + mSTU.setGammaHigh((int)par1 - 65, val); + } else { + mSTU.setGammaLow((int)par1 - 65, val); + } + } else if ((index = alias.find("STU_J")) != std::string::npos) { + char par1; + int par2; + std::sscanf((std::string(alias.substr(index + 5, 2))).data(), "%c%d", &par1, &par2); + if (par2 == 0) { + mSTU.setJetHigh((int)par1 - 65, val); + } else { + mSTU.setJetLow((int)par1 - 65, val); + } + } + + if (kEMC) { + mFEECFG->setSTUEMCal(mSTU); + } else { + mFEECFG->setSTUDCal(mSTU); + } + } +} + +void EMCDCSProcessor::updateElmbCCDBinfo() +{ + if (mVerbose) { + LOG(INFO) << "updating Temperture objects in CCDB"; + // LOG(INFO) << "Temperture objects to be written in CCDB\n"; + // << *mFEECFG.get(); + } + + std::map<std::string, std::string> metadata; + metadata["responsible"] = "Martin Poghosyan"; + prepareCCDBobjectInfo(mELMBdata.get(), mccdbELMBinfo, "EMC/Temperature", mTF, metadata); +} + +void EMCDCSProcessor::updateFeeCCDBinfo() +{ + if (mVerbose) { + LOG(INFO) << "updating FEE DCS objects in CCDB"; + // LOG(INFO) << "FEE DCS object to be written in CCDB\n" + // << *mFEECFG.get(); + } + std::map<std::string, std::string> metadata; + metadata["responsible"] = "Martin Poghosyan"; + prepareCCDBobjectInfo(mFEECFG.get(), mccdbFEEcfginfo, "EMC/FeeDCS", mTF, metadata); +} + +void EMCDCSProcessor::printPDCOM(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto type = dpid.get_type(); + std::string type_str = show(type); + + auto alias = dpid.get_alias(); + + auto& dpval = dpcom.data; + auto ts = dpval.get_epoch_time(); + auto val = dpval.payload_pt1; + + std::cout << "DPCOM Info:"; + + std::cout << " alias: " << alias; + std::cout << " | type : " << type_str; + std::cout << " | ts : " << ts; + std::cout << " | value: " << val << std::endl; +} \ No newline at end of file diff --git a/Detectors/EMCAL/calib/src/ElmbMeasurement.cxx b/Detectors/EMCAL/calib/src/ElmbMeasurement.cxx new file mode 100644 index 0000000000000..6e791b6d8ee8b --- /dev/null +++ b/Detectors/EMCAL/calib/src/ElmbMeasurement.cxx @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <iostream> + +#include "TMath.h" +#include "EMCALCalib/ElmbMeasurement.h" + +using namespace o2::emcal; + +void ElmbMeasurement::init() +{ + values.resize(NElmbSensors); + values_prev.resize(NElmbSensors, -1); + mELMBdata.resize(NElmbSensors); +} + +void ElmbMeasurement::reset() +{ + + for (int iPT = 0; iPT < NElmbSensors; iPT++) { + values[iPT].clear(); + } + mELMBdata.clear(); + + mELMBdata.resize(NElmbSensors); // check why the capacity is 0 after clear()!!! +} + +void ElmbMeasurement::process() +{ + int Npoints = 0; + float val_last = 0; + double mean = 0; + double mean2 = 0; + double rms = 0.; + double max = 0; + double min = 1000; + + for (int iPT = 0; iPT < NElmbSensors; iPT++) { + Npoints = 0; + mean = 0; + mean2 = 0; + max = 0; + min = 1000; + rms = 0; + val_last = values_prev[iPT]; + + // std::cout<< iPT << " : "; + for (auto vPT : values[iPT]) { + // std::cout << vPT << ", "; + Npoints++; + mean += vPT; + mean2 += vPT * vPT; + if (max < vPT) { + max = vPT; + } + if (min > vPT) { + min = vPT; + } + val_last = (float)vPT; + } + // std::cout << std::endl; + + if (Npoints == 0) { + mean = (double)values_prev[iPT]; + } else if (Npoints > 1) { + mean2 /= Npoints; + mean /= Npoints; + rms = mean2 - mean * mean; + rms /= (Npoints - 1); + rms = TMath::Sqrt(rms); + } + + values_prev[iPT] = val_last; + mELMBdata[iPT] = std::make_tuple(Npoints, (float)mean, (float)rms, (float)min, (float)max); + } +} diff --git a/Detectors/EMCAL/calib/src/FeeDCS.cxx b/Detectors/EMCAL/calib/src/FeeDCS.cxx new file mode 100644 index 0000000000000..8de3ab5c87be1 --- /dev/null +++ b/Detectors/EMCAL/calib/src/FeeDCS.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <sstream> + +#include "EMCALCalib/FeeDCS.h" + +using namespace o2::emcal; + +bool FeeDCS::operator==(const FeeDCS& other) const +{ + + return ((mTrigDCS == other.mTrigDCS) && (mLinks0 == other.mLinks0) && (mLinks1 == other.mLinks1) && + (mSRUFWversion == other.mSRUFWversion) && (mSRUcfg == other.mSRUcfg)); +} + +bool FeeDCS::isSMactive(int iSM) +{ + + //assert(iSM>19 && "SM index larger than 19!"); + + if (iSM == 10 || iSM == 19) { // SMs 10 and 19 have 1 DDL each + return isDDLactive(2 * iSM); + } else { + return (isDDLactive(2 * iSM) && isDDLactive(2 * iSM + 1)); + } + + return false; +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const FeeDCS& dcs) +{ + stream << "EMCAL FEE config:\n"; + stream << "================================\n"; + stream << "DDL Link list0: b'" << std::hex << dcs.getDDLlist0() << std::endl; + stream << "DDL Link list1: b'" << std::hex << dcs.getDDLlist1() << std::endl; + + for (int i = 0; i < 20; i++) { + stream << "SM" << std::dec << i << ": FW=0x" << std::hex << dcs.getSRUFWversion(i) << ", CFG=0x" << std::hex << dcs.getSRUconfig(i) << " [MEB=" << std::dec << dcs.getNSRUbuffers() << "] " << std::endl; + } + o2::emcal::TriggerDCS trg = dcs.getTriggerDCS(); + stream << trg << std::endl; + + return stream; +} diff --git a/Detectors/EMCAL/calib/src/GainCalibrationFactors.cxx b/Detectors/EMCAL/calib/src/GainCalibrationFactors.cxx index c80d8d2322909..7f5b332baef99 100644 --- a/Detectors/EMCAL/calib/src/GainCalibrationFactors.cxx +++ b/Detectors/EMCAL/calib/src/GainCalibrationFactors.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TempCalibParamSM.cxx b/Detectors/EMCAL/calib/src/TempCalibParamSM.cxx index efdb51af0f57a..79d2dc551c24d 100644 --- a/Detectors/EMCAL/calib/src/TempCalibParamSM.cxx +++ b/Detectors/EMCAL/calib/src/TempCalibParamSM.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TempCalibrationParams.cxx b/Detectors/EMCAL/calib/src/TempCalibrationParams.cxx index 6e2d97aace83d..7234395cc5ba6 100644 --- a/Detectors/EMCAL/calib/src/TempCalibrationParams.cxx +++ b/Detectors/EMCAL/calib/src/TempCalibrationParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TimeCalibParamL1Phase.cxx b/Detectors/EMCAL/calib/src/TimeCalibParamL1Phase.cxx index 27c5ef90629e9..9f1b27b1befb2 100644 --- a/Detectors/EMCAL/calib/src/TimeCalibParamL1Phase.cxx +++ b/Detectors/EMCAL/calib/src/TimeCalibParamL1Phase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TimeCalibrationParams.cxx b/Detectors/EMCAL/calib/src/TimeCalibrationParams.cxx index 03de70b3c7427..0653706426da7 100644 --- a/Detectors/EMCAL/calib/src/TimeCalibrationParams.cxx +++ b/Detectors/EMCAL/calib/src/TimeCalibrationParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TriggerDCS.cxx b/Detectors/EMCAL/calib/src/TriggerDCS.cxx index 57e7dcf302d53..3a2137f519bad 100644 --- a/Detectors/EMCAL/calib/src/TriggerDCS.cxx +++ b/Detectors/EMCAL/calib/src/TriggerDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,11 +42,12 @@ std::ostream& o2::emcal::operator<<(std::ostream& stream, const TriggerDCS& conf stream << "================================" << std::endl; for (int i = 0; i < config.getTRUArr().size(); i++) { TriggerTRUDCS tru = config.getTRUDCS(i); - stream << "TRU" << i << ": " << tru << std::endl; + stream << "TRU" << i << ": " << tru; } + TriggerSTUDCS emcalstu(config.getSTUDCSEMCal()), dcalstu(config.getSTUDCSDCal()); - std::cout << "EMCAL STU: " << emcalstu << std::endl; - std::cout << "DCAL STU: " << dcalstu << std::endl; + stream << "EMCAL STU: " << emcalstu; + stream << "DCAL STU: " << dcalstu; return stream; } diff --git a/Detectors/EMCAL/calib/src/TriggerSTUDCS.cxx b/Detectors/EMCAL/calib/src/TriggerSTUDCS.cxx index 0e4047030479a..548e71b6b7426 100644 --- a/Detectors/EMCAL/calib/src/TriggerSTUDCS.cxx +++ b/Detectors/EMCAL/calib/src/TriggerSTUDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,16 +46,15 @@ bool TriggerSTUDCS::operator==(const TriggerSTUDCS& other) const void TriggerSTUDCS::PrintStream(std::ostream& stream) const { + stream << "PatchSize: " << mPatchSize + << ", GetRawData: " << mGetRawData + << ", Region: 0x" << std::hex << mRegion << std::dec << " (b'" << std::bitset<sizeof(mRegion) * 8>(mRegion) << ")" + << ", Median: " << mMedian + << ", Firmware: 0x" << std::hex << mFw << std::dec << std::endl; stream << "Gamma High: (" << mGammaHigh[0] << ", " << mGammaHigh[1] << ", " << mGammaHigh[2] << ")" << std::endl; stream << "Gamma Low: (" << mGammaLow[0] << ", " << mGammaLow[1] << ", " << mGammaLow[2] << ")" << std::endl; stream << "Jet High: (" << mJetHigh[0] << ", " << mJetHigh[1] << ", " << mJetHigh[2] << ")" << std::endl; stream << "Jet Low: (" << mJetLow[0] << ", " << mJetLow[1] << ", " << mJetLow[2] << ")" << std::endl; - stream << "GetRawData: " << mGetRawData - << ", Region: " << std::hex << mRegion << std::dec << " (" << std::bitset<sizeof(mRegion) * 8>(mRegion) << ")" - << ", Median: " << mMedian - << ", Firmware: " << std::hex << mFw << std::dec - << ", PHOS Scale: (" << mPHOSScale[0] << ", " << mPHOSScale[1] << ", " << mPHOSScale[2] << ", " << mPHOSScale[3] - << ")" << std::endl; } std::ostream& o2::emcal::operator<<(std::ostream& stream, const TriggerSTUDCS& stu) diff --git a/Detectors/EMCAL/calib/src/TriggerSTUErrorCounter.cxx b/Detectors/EMCAL/calib/src/TriggerSTUErrorCounter.cxx index 38c92c0651eb5..dc9618573c4a6 100644 --- a/Detectors/EMCAL/calib/src/TriggerSTUErrorCounter.cxx +++ b/Detectors/EMCAL/calib/src/TriggerSTUErrorCounter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/src/TriggerTRUDCS.cxx b/Detectors/EMCAL/calib/src/TriggerTRUDCS.cxx index 9ffa1a430b6ab..169124de0e60f 100644 --- a/Detectors/EMCAL/calib/src/TriggerTRUDCS.cxx +++ b/Detectors/EMCAL/calib/src/TriggerTRUDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,11 +39,12 @@ bool TriggerTRUDCS::operator==(const TriggerTRUDCS& other) const void TriggerTRUDCS::PrintStream(std::ostream& stream) const { - stream << "SELPF: " << std::hex << mSELPF << ", L0SEL: " << mL0SEL << ", L0COSM: " << std::dec - << mL0COSM << ", GTHRL0: " << mGTHRL0 << ", RLBKSTU: " << mRLBKSTU << ", FW: " << std::hex + stream << "SELPF: 0x" << std::hex << mSELPF << ", L0SEL: 0x" << std::hex << mL0SEL << ", L0COSM: 0x" << std::hex + << mL0COSM << ", GTHRL0: 0x" << std::hex << mGTHRL0 << ", RLBKSTU: 0x" << std::hex << mRLBKSTU << ", FW: 0x" << std::hex << mFw << std::dec << std::endl; + for (int ireg = 0; ireg < 6; ireg++) { - stream << "Reg" << ireg << ": " << std::bitset<sizeof(uint32_t) * 8>(mMaskReg[ireg]) << " (" << mMaskReg[ireg] << ")" << std::endl; + stream << "Reg" << ireg << ": b'" << std::bitset<sizeof(uint32_t) * 8>(mMaskReg[ireg]) << " (" << mMaskReg[ireg] << ")" << std::endl; } } diff --git a/Detectors/EMCAL/calib/test/testBadChannelMap.cxx b/Detectors/EMCAL/calib/test/testBadChannelMap.cxx index 51c896b588c4a..57ca0f93c5bff 100644 --- a/Detectors/EMCAL/calib/test/testBadChannelMap.cxx +++ b/Detectors/EMCAL/calib/test/testBadChannelMap.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testGainCalibration.cxx b/Detectors/EMCAL/calib/test/testGainCalibration.cxx index 4fcc49fd10ede..80452ebae919c 100644 --- a/Detectors/EMCAL/calib/test/testGainCalibration.cxx +++ b/Detectors/EMCAL/calib/test/testGainCalibration.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTempCalibration.cxx b/Detectors/EMCAL/calib/test/testTempCalibration.cxx index dcd9488510987..f137272a44e3c 100644 --- a/Detectors/EMCAL/calib/test/testTempCalibration.cxx +++ b/Detectors/EMCAL/calib/test/testTempCalibration.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTempCalibrationSM.cxx b/Detectors/EMCAL/calib/test/testTempCalibrationSM.cxx index 0f087bf12123d..7a666bf460cfe 100644 --- a/Detectors/EMCAL/calib/test/testTempCalibrationSM.cxx +++ b/Detectors/EMCAL/calib/test/testTempCalibrationSM.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTimeCalibration.cxx b/Detectors/EMCAL/calib/test/testTimeCalibration.cxx index 63e5ac314b8db..8a7fe8ff1ddb6 100644 --- a/Detectors/EMCAL/calib/test/testTimeCalibration.cxx +++ b/Detectors/EMCAL/calib/test/testTimeCalibration.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTimeL1PhaseCalib.cxx b/Detectors/EMCAL/calib/test/testTimeL1PhaseCalib.cxx index cbe13ae87d6b2..83b80e6811fda 100644 --- a/Detectors/EMCAL/calib/test/testTimeL1PhaseCalib.cxx +++ b/Detectors/EMCAL/calib/test/testTimeL1PhaseCalib.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTriggerDCS.cxx b/Detectors/EMCAL/calib/test/testTriggerDCS.cxx index 8dee30ac50ef3..a494ebaf9b143 100644 --- a/Detectors/EMCAL/calib/test/testTriggerDCS.cxx +++ b/Detectors/EMCAL/calib/test/testTriggerDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -84,7 +85,7 @@ BOOST_AUTO_TEST_CASE(TriggerDCS_test) TriggerDCS testobject; testobject.setSTUEMCal(testSTUEMCal); testobject.setSTUDCal(testSTUDCal); - testobject.setTRU(testTRU); + testobject.setTRU(0, testTRU); BOOST_CHECK_EQUAL(testobject.getSTUDCSEMCal(), testSTUEMCal); BOOST_CHECK_EQUAL(testobject.getSTUDCSDCal(), testSTUDCal); @@ -107,7 +108,7 @@ BOOST_AUTO_TEST_CASE(TriggerDCS_test) testTRU1.setSELPF(7000); ref.setSTUEMCal(testSTUEMCal); ref.setSTUDCal(testSTUDCal); - ref.setTRU(testTRU1); + ref.setTRU(0, testTRU1); BOOST_CHECK_EQUAL(ref == testobject, false); } diff --git a/Detectors/EMCAL/calib/test/testTriggerSTUDCS.cxx b/Detectors/EMCAL/calib/test/testTriggerSTUDCS.cxx index b1c6884cfd1d2..2451dfe6720b0 100644 --- a/Detectors/EMCAL/calib/test/testTriggerSTUDCS.cxx +++ b/Detectors/EMCAL/calib/test/testTriggerSTUDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -126,7 +127,7 @@ BOOST_AUTO_TEST_CASE(TriggerSTUDCS_test) /// Test if operator<< for a reference configuration produces /// the expected reference string. Test is implemented using a streaming /// operator. - std::string reference = std::string("Gamma High: (0, 0, 115)\nGamma Low: (0, 0, 51)\nJet High: (0, 0, 255)\nJet Low: (0, 0, 204)\n") + std::string("GetRawData: 1, Region: ffffffff (11111111111111111111111111111111), Median: 0, Firmware: 2a012, PHOS Scale: (0, 0, 0, 0)\n"); + std::string reference = std::string("PatchSize: 2, GetRawData: 1, Region: 0xffffffff (b'11111111111111111111111111111111), Median: 0, Firmware: 0x2a012\n") + std::string("Gamma High: (0, 0, 115)\nGamma Low: (0, 0, 51)\nJet High: (0, 0, 255)\nJet Low: (0, 0, 204)\n"); TriggerSTUDCS test; ConfigureReference(test); diff --git a/Detectors/EMCAL/calib/test/testTriggerSTUErrorCounter.cxx b/Detectors/EMCAL/calib/test/testTriggerSTUErrorCounter.cxx index 859b232499c16..60ec4c5603541 100644 --- a/Detectors/EMCAL/calib/test/testTriggerSTUErrorCounter.cxx +++ b/Detectors/EMCAL/calib/test/testTriggerSTUErrorCounter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/calib/test/testTriggerTRUDCS.cxx b/Detectors/EMCAL/calib/test/testTriggerTRUDCS.cxx index 9c2c3f74027dc..036ec7b2a8fcf 100644 --- a/Detectors/EMCAL/calib/test/testTriggerTRUDCS.cxx +++ b/Detectors/EMCAL/calib/test/testTriggerTRUDCS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -116,7 +117,7 @@ BOOST_AUTO_TEST_CASE(TriggerTRUDCS_test) /// Test if operator<< for a reference configuration produces /// the expected reference string. Test is implemented using a streaming /// operator. - std::string reference = std::string("SELPF: 1e1f, L0SEL: 1, L0COSM: 100, GTHRL0: 132, RLBKSTU: 0, FW: 21\n") + std::string("Reg0: 00000000000000000000010000000000 (1024)\nReg1: 00000000000000000000000000000000 (0)\n") + std::string("Reg2: 00000000000000000000001000000000 (512)\nReg3: 00000000000000000111110011110001 (31985)\n") + std::string("Reg4: 00000000000000000000000000000000 (0)\nReg5: 00000000000000000000000000000000 (0)\n"); + std::string reference = std::string("SELPF: 0x1e1f, L0SEL: 0x1, L0COSM: 0x64, GTHRL0: 0x84, RLBKSTU: 0x0, FW: 0x21\n") + std::string("Reg0: b'00000000000000000000010000000000 (1024)\nReg1: b'00000000000000000000000000000000 (0)\n") + std::string("Reg2: b'00000000000000000000001000000000 (512)\nReg3: b'00000000000000000111110011110001 (31985)\n") + std::string("Reg4: b'00000000000000000000000000000000 (0)\nReg5: b'00000000000000000000000000000000 (0)\n"); TriggerTRUDCS test; ConfigureReference(test); diff --git a/Detectors/EMCAL/calibration/CMakeLists.txt b/Detectors/EMCAL/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..0f0b735fd8e83 --- /dev/null +++ b/Detectors/EMCAL/calibration/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(EMCALCalibration + SOURCES src/EMCALChannelData.cxx + src/EMCALTimeCalibData.cxx + PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase + O2::EMCALCalib + O2::CommonUtils + O2::DetectorsCalibration + O2::DataFormatsEMCAL + O2::Framework + O2::Algorithm + Microsoft.GSL::GSL + ) + + + +o2_target_root_dictionary(EMCALCalibration + HEADERS include/EMCALCalibration/EMCALChannelCalibrator.h + include/EMCALCalibration/EMCALChannelData.h + include/EMCALCalibration/EMCALTimeCalibData.h + LINKDEF src/EMCALCalibrationLinkDef.h) + + + + +o2_add_executable(emcal-channel-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/emc-channel-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::EMCALCalibration + O2::DetectorsCalibration) + diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelCalibrator.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelCalibrator.h new file mode 100644 index 0000000000000..cf26189c336ee --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelCalibrator.h @@ -0,0 +1,129 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class EMCALChannelCalibrator +/// \brief Perform the EMCAL bad channel calibration +/// \author Hannah Bossi, Yale University +/// \ingroup EMCALCalib +/// \since Feb 11, 2021 + +#ifndef EMCAL_CHANNEL_CALIBRATOR_H_ +#define EMCAL_CHANNEL_CALIBRATOR_H_ + +#include "EMCALCalibration/EMCALTimeCalibData.h" +#include "EMCALCalibration/EMCALChannelData.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsEMCAL/Cell.h" +#include "EMCALBase/Geometry.h" +#include "CCDB/CcdbObjectInfo.h" + +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/format.hpp> + +#include <array> +#include <boost/histogram.hpp> + +namespace o2 +{ +namespace emcal +{ +/// \brief class used for managment of bad channel and time calibration +/// template DataInput can be ChannelData or TimeData // o2::emcal::EMCALChannelData, o2::emcal::EMCALTimeCalibData +/// template HistContainer can be ChannelCalibInitParams or TimeCalibInitParams +template <typename DataInput, typename HistContainer> +class EMCALChannelCalibrator : public o2::calibration::TimeSlotCalibration<o2::emcal::Cell, DataInput> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<DataInput>; + using Cell = o2::emcal::Cell; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + using CcdbObjectInfoVector = std::vector<CcdbObjectInfo>; + + public: + EMCALChannelCalibrator(int nb = 1000, float r = 0.35) : mNBins(nb), mRange(r){}; + + ~EMCALChannelCalibrator() final = default; + + /// \brief Checking if all channels have enough data to do calibration. + bool hasEnoughData(const Slot& slot) const final; + /// \brief Initialize the vector of our output objects. + void initOutput() final; + void finalizeSlot(Slot& slot) final; + o2::calibration::TimeSlot<DataInput>& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + + void setIsTest(bool isTest) { mTest = isTest; } + bool isTest() const { return mTest; } + + private: + int mNBins = 0; ///< bins of the histogram for passing + float mRange = 0.; ///< range of the histogram for passing + bool mTest = false; ///< flag to be used when running in test mode: it simplify the processing (e.g. does not go through all channels) + + // output + CcdbObjectInfoVector mInfoVector; // vector of CCDB Infos , each element is filled with the CCDB description of the accompanying TimeSlewing object + + ClassDefOverride(EMCALChannelCalibrator, 1); +}; + +//_____________________________________________ +template <typename DataInput, typename HistContainer> +void EMCALChannelCalibrator<DataInput, HistContainer>::initOutput() +{ + mInfoVector.clear(); + return; +} + +//_____________________________________________ +template <typename DataInput, typename HistContainer> +bool EMCALChannelCalibrator<DataInput, HistContainer>::hasEnoughData(const o2::calibration::TimeSlot<DataInput>& slot) const +{ + + const DataInput* c = slot.getContainer(); + LOG(INFO) << "Checking statistics"; + return (mTest ? true : c->hasEnoughData()); +} + +//_____________________________________________ +template <typename DataInput, typename HistContainer> +void EMCALChannelCalibrator<DataInput, HistContainer>::finalizeSlot(o2::calibration::TimeSlot<DataInput>& slot) +{ + // Extract results for the single slot + DataInput* c = slot.getContainer(); + LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + + // for the CCDB entry + std::map<std::string, std::string> md; + + //auto clName = o2::utils::MemFileHelper::getClassName(tm); + //auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + mInfoVector.emplace_back("EMCAL/ChannelCalib", "clname", "flname", md, slot.getTFStart(), 99999999999999); +} + +template <typename DataInput, typename HistContainer> +o2::calibration::TimeSlot<DataInput>& EMCALChannelCalibrator<DataInput, HistContainer>::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + auto& cont = o2::calibration::TimeSlotCalibration<o2::emcal::Cell, DataInput>::getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + HistContainer histcont; // initialize struct with (default) ranges for time or channel calibration. + slot.setContainer(std::make_unique<DataInput>(histcont)); + return slot; +} + +} // end namespace emcal +} // end namespace o2 + +#endif /*EMCAL_CHANNEL_CALIBRATOR_H_ */ diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h new file mode 100644 index 0000000000000..11063655ceeca --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h @@ -0,0 +1,108 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class EMCALChannelData +/// \brief Perform the EMCAL bad channel calibration +/// \author Hannah Bossi, Yale University +/// \ingroup EMCALCalib +/// \since Feb 11, 2021 + +#ifndef CHANNEL_DATA_H_ +#define CHANNEL_DATA_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsEMCAL/Cell.h" +#include "EMCALBase/Geometry.h" +#include "CCDB/CcdbObjectInfo.h" + +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/format.hpp> + +#include <array> +#include <boost/histogram.hpp> + +namespace o2 +{ +namespace emcal +{ +struct ChannelCalibInitParams { + unsigned int nbins = 1000; + std::array<float, 2> range = {0, 0.35}; +}; + +class EMCALChannelData +{ + //using Slot = o2::calibration::TimeSlot<o2::emcal::EMCALChannelData>; + using Cells = o2::emcal::Cell; + using boostHisto = boost::histogram::histogram<std::tuple<boost::histogram::axis::regular<double, boost::use_default, boost::use_default, boost::use_default>, boost::histogram::axis::integer<>>, boost::histogram::unlimited_storage<std::allocator<char>>>; + + public: + // NCELLS includes DCal, treat as one calibration + o2::emcal::Geometry* mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + int NCELLS = mGeometry->GetNCells(); + + EMCALChannelData(const ChannelCalibInitParams& hist) : mNBins(hist.nbins), mRange(1) + { + // boost histogram with amplitude vs. cell ID, specify the range and binning of the amplitude axis + mHisto = boost::histogram::make_histogram(boost::histogram::axis::regular<>(mNBins, 0, mRange, "t-texp"), boost::histogram::axis::integer<>(0, NCELLS, "CELL ID")); + } + + ~EMCALChannelData() = default; + + /// \brief Print relevant info for EMCALChannelData on a given stream + /// \param stream Stream on which the info is printed on + /// The function is called in the operator<< providing direct access + /// to protected members. Explicit calls by the users is normally not + /// necessary. + void PrintStream(std::ostream& stream) const; + /// \brief Print a useful message about the container. + void print(); + /// \brief Fill the container with the cell ID and amplitude. + void fill(const gsl::span<const o2::emcal::Cell> data); + /// \brief Merge the data of two slots. + void merge(const EMCALChannelData* prev); + int findBin(float v) const; + bool hasEnoughData() const; + boostHisto& getHisto() { return mHisto; } + const boostHisto& getHisto() const { return mHisto; } + + float getRange() const { return mRange; } + void setRange(float r) { mRange = r; } + + int getNbins() const { return mNBins; } + void setNbins(int nb) { mNBins = nb; } + + int getNEvents() const { return mEvents; } + void setNEvents(int ne) { mEvents = ne; } + + private: + float mRange = 0.35; // looked at old QA plots where max was 0.35 GeV, might need to be changed + int mNBins = 1000; + boostHisto mHisto; + int mEvents = 1; + + ClassDefNV(EMCALChannelData, 1); +}; +/// \brief Printing EMCALChannelData on the stream +/// \param in Stream where the EMCALChannelData is printed on +/// \param emcdata EMCALChannelData to be printed +std::ostream& operator<<(std::ostream& in, const EMCALChannelData& emcdata); + +} // end namespace emcal +} // end namespace o2 + +#endif /*CHANNEL_DATA_H_ */ diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTimeCalibData.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTimeCalibData.h new file mode 100644 index 0000000000000..470d9a6cb4e41 --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTimeCalibData.h @@ -0,0 +1,108 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class EMCALTimeCalibData +/// \brief Perform the EMCAL time calibration +/// \author Joshua Koenig +/// \ingroup EMCALCalib +/// \since Jul 25, 2021 + +#ifndef EMCAL_TIME_DATA_H_ +#define EMCAL_TIME_DATA_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsEMCAL/Cell.h" +#include "EMCALBase/Geometry.h" +#include "CCDB/CcdbObjectInfo.h" +#include "EMCALCalib/TimeCalibrationParams.h" + +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/format.hpp> + +#include <array> +#include <boost/histogram.hpp> +namespace o2 +{ +namespace emcal +{ + +// class containing the initialization parameters for histograms (time bins/range etc.) +struct TimeCalibInitParams { + public: + unsigned int mTimeBins = 1500; + std::array<float, 2> mTimeRange = {-500., 1000.}; // time range in ns + unsigned int mEnergyBins = 5000; + std::array<float, 2> mEnergyRange = {0., 50.}; // energy range in GeV +}; + +class EMCALTimeCalibData +{ + public: + using Cells = o2::emcal::Cell; + using boostHisto = boost::histogram::histogram<std::tuple<boost::histogram::axis::regular<double, boost::use_default, boost::use_default, boost::use_default>, boost::histogram::axis::integer<>>, boost::histogram::unlimited_storage<std::allocator<char>>>; + + o2::emcal::Geometry* mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + int NCELLS = mGeometry->GetNCells(); + + EMCALTimeCalibData(const TimeCalibInitParams& par) + { + // boost histogram with amplitude vs. cell ID, specify the range and binning of the amplitude axis + mTimeHisto = boost::histogram::make_histogram(boost::histogram::axis::regular<>(par.mTimeBins, par.mTimeRange.at(0), par.mTimeRange.at(1), "t (ns)"), boost::histogram::axis::integer<>(0, NCELLS, "CELL ID")); + } + + ~EMCALTimeCalibData() = default; + + /// \brief Fill the container with the cell ID and amplitude and time information. + void fill(const gsl::span<const o2::emcal::Cell> data); + + /// \brief Merge the data of two slots. + void merge(const EMCALTimeCalibData* prev); + + /// \brief Check if enough data for calibration has been accumulated + bool hasEnoughData() const; + + /// \brief Print a useful message about the container. + void print(); + + /// \brief Get number of events currently available for calibration + int getNEvents() const { return mEvents; } + + /// \brief Get current histogram + boostHisto& getHisto() { return mTimeHisto; } + const boostHisto& getHisto() const { return mTimeHisto; } + + /// \brief Set number of events available for calibration + void setNEvents(int ne) { mEvents = ne; } + + void PrintStream(std::ostream& stream) const; + + /// \brief Actual function where calibration is done. Has to be called in has enough data when enough data is there + o2::emcal::TimeCalibrationParams process(); + + private: + boostHisto mTimeHisto; + TimeCalibInitParams mTimeCalibParams; + + int mEvents = 0; + + ClassDefNV(EMCALTimeCalibData, 1); +}; + +} // end namespace emcal +} // end namespace o2 + +#endif /*EMCAL_TIME_DATA_H_ */ \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h b/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h new file mode 100644 index 0000000000000..497f54a33376d --- /dev/null +++ b/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::emcal::EMCALChannelCalibrator <o2::emcal::EMCALChannelData, o2::emcal::ChannelCalibInitParams> + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::emcal::EMCALChannelData> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::emcal::Cell, o2::emcal::EMCALChannelData> + ; + +#pragma link C++ class o2::emcal::EMCALChannelCalibrator <o2::emcal::EMCALTimeCalibData, o2::emcal::TimeCalibInitParams> + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::emcal::EMCALTimeCalibData> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::emcal::Cell, o2::emcal::EMCALTimeCalibData> + ; + +#endif diff --git a/Detectors/EMCAL/calibration/src/EMCALChannelData.cxx b/Detectors/EMCAL/calibration/src/EMCALChannelData.cxx new file mode 100644 index 0000000000000..007d712ae2410 --- /dev/null +++ b/Detectors/EMCAL/calibration/src/EMCALChannelData.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "EMCALCalibration/EMCALChannelData.h" +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/format.hpp> +#include <cassert> +#include <iostream> +#include <sstream> +#include <TStopwatch.h> + +namespace o2 +{ +namespace emcal +{ + +using Slot = o2::calibration::TimeSlot<o2::emcal::EMCALChannelData>; +using clbUtils = o2::calibration::Utils; +using boost::histogram::indexed; + +//=================================================================== +//_____________________________________________ +void EMCALChannelData::PrintStream(std::ostream& stream) const +{ + stream << "EMCAL Cell ID: " << mHisto << "\n"; +} +//_____________________________________________ +std::ostream& operator<<(std::ostream& stream, const EMCALChannelData& emcdata) +{ + emcdata.PrintStream(stream); + return stream; +} +//_____________________________________________ +void EMCALChannelData::fill(const gsl::span<const o2::emcal::Cell> data) +{ + for (auto cell : data) { + Double_t cellEnergy = cell.getEnergy(); + Int_t id = cell.getTower(); + LOG(DEBUG) << "inserting in cell ID " << id << ": energy = " << cellEnergy; + mHisto(cellEnergy, id); + } +} +//_____________________________________________ +void EMCALChannelData::print() +{ + LOG(DEBUG) << *this; +} +//_____________________________________________ +void EMCALChannelData::merge(const EMCALChannelData* prev) +{ + mEvents += prev->getNEvents(); + mHisto += prev->getHisto(); +} + +//_____________________________________________ +bool EMCALChannelData::hasEnoughData() const +{ + // true if we have enough data, also want to check for the sync trigger + // this is stil to be finalized, simply a skeletron for now + + // if we have the sync trigger, finalize the slot anyway + + //finalizeOldestSlot(Slot& slot); + + // TODO: use event counter here to specify the value of enough + // guess and then adjust number of events as needed + // checking mEvents + bool enough; + + return enough; +} + +} // end namespace emcal +} // end namespace o2 \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/EMCALTimeCalibData.cxx b/Detectors/EMCAL/calibration/src/EMCALTimeCalibData.cxx new file mode 100644 index 0000000000000..a26c7243c177a --- /dev/null +++ b/Detectors/EMCAL/calibration/src/EMCALTimeCalibData.cxx @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "EMCALCalibration/EMCALTimeCalibData.h" +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/format.hpp> +#include <cassert> +#include <iostream> +#include <sstream> +#include <TStopwatch.h> + +namespace o2 +{ +namespace emcal +{ + +using Slot = o2::calibration::TimeSlot<o2::emcal::EMCALTimeCalibData>; +using clbUtils = o2::calibration::Utils; +using boost::histogram::indexed; + +//=================================================================== +//_____________________________________________ +void EMCALTimeCalibData::PrintStream(std::ostream& stream) const +{ + stream << "EMCAL Cell ID: " << mTimeHisto << "\n"; +} +//_____________________________________________ +void EMCALTimeCalibData::print() +{ + LOG(DEBUG) << *this; +} +//_____________________________________________ +std::ostream& operator<<(std::ostream& stream, const EMCALTimeCalibData& emcdata) +{ + emcdata.PrintStream(stream); + return stream; +} +//_____________________________________________ +void EMCALTimeCalibData::merge(const EMCALTimeCalibData* prev) +{ + mEvents += prev->getNEvents(); + mTimeHisto += prev->getHisto(); +} +//_____________________________________________ +bool EMCALTimeCalibData::hasEnoughData() const +{ + // true if we have enough data, also want to check for the sync trigger + // this is stil to be finalized, simply a skeletron for now + + // if we have the sync trigger, finalize the slot anyway + + //finalizeOldestSlot(Slot& slot); + + // TODO: use event counter here to specify the value of enough + // guess and then adjust number of events as needed + // checking mEvents + bool enough; + + return enough; +} +//_____________________________________________ +void EMCALTimeCalibData::fill(const gsl::span<const o2::emcal::Cell> data) +{ + for (auto cell : data) { + Double_t cellEnergy = cell.getEnergy(); + Int_t id = cell.getTower(); + LOG(DEBUG) << "inserting in cell ID " << id << ": energy = " << cellEnergy; + mTimeHisto(cellEnergy, id); + } +} + +//_____________________________________________ +o2::emcal::TimeCalibrationParams EMCALTimeCalibData::process() +{ + o2::emcal::TimeCalibrationParams TimeCalibParams; + return TimeCalibParams; +} + +} // end namespace emcal +} // end namespace o2 diff --git a/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h b/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h new file mode 100644 index 0000000000000..d29905cf551bc --- /dev/null +++ b/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h @@ -0,0 +1,134 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class EMCALChannelCalibratorSpec +/// \brief DPL Processor for EMCAL bad channel calibration data +/// \author Hannah Bossi, Yale University +/// \ingroup EMCALCalib +/// \since Feb 11, 2021 + +#ifndef O2_CALIBRATION_EMCALCHANNEL_CALIBRATOR_H +#define O2_CALIBRATION_EMCALCHANNEL_CALIBRATOR_H + +#include "EMCALCalibration/EMCALChannelCalibrator.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace calibration +{ + +class EMCALChannelCalibDevice : public o2::framework::Task +{ + + //using TimeSlewing = o2::dataformats::CalibTimeSlewingParamEMCAL; + //using LHCphase = o2::dataformats::CalibLHCphaseEMCAL; + + public: + EMCALChannelCalibDevice() = default; + void init(o2::framework::InitContext& ic) final + { + int isTest = ic.options().get<bool>("do-EMCAL-channel-calib-in-test-mode"); + mCalibrator = std::make_unique<o2::emcal::EMCALChannelCalibrator<o2::emcal::EMCALChannelData, o2::emcal::ChannelCalibInitParams>>(); + mCalibrator->setUpdateAtTheEndOfRunOnly(); + mCalibrator->setIsTest(isTest); + } + + void run(o2::framework::ProcessingContext& pc) final + { + + long startTimeChCalib; + + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; // is this the timestamp of the current TF? + + LOG(DEBUG) << " startTimeChCalib = " << startTimeChCalib; + + auto data = pc.inputs().get<gsl::span<o2::emcal::Cell>>("input"); + LOG(INFO) << "Processing TF " << tfcounter << " with " << data.size() << " cells"; + mCalibrator->process(tfcounter, data); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<o2::emcal::EMCALChannelCalibrator<o2::emcal::EMCALChannelData, o2::emcal::ChannelCalibInitParams>> mCalibrator; + std::unique_ptr<o2::emcal::EMCALChannelCalibrator<o2::emcal::EMCALTimeCalibData, o2::emcal::TimeCalibInitParams>> mTimeCalibrator; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + using clbUtils = o2::calibration::Utils; + /* + const auto& payloadVec = mCalibrator->getTimeSlewingVector(); + auto& infoVec = mCalibrator->getTimeSlewingInfoVector(); // use non-const version as we update it + assert(payloadVec.size() == infoVec.size()); + for (uint32_t i = 0; i < payloadVec.size(); i++) { + auto& w = infoVec[i]; + auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); + LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() + << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_CHANNEL", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_CHANNEL", i}, w); // root-serialized + } + */ + //if (payloadVec.size()) { + mCalibrator->initOutput(); // reset the outputs once they are already sent + //} + } +}; + +} // namespace calibration + +namespace framework +{ + +DataProcessorSpec getEMCALChannelCalibDeviceSpec() +{ + using device = o2::calibration::EMCALChannelCalibDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_CHANNEL"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_CHANNEL"}); + + std::vector<InputSpec> inputs; + inputs.emplace_back("input", o2::header::gDataOriginEMC, "CELLS"); + + return DataProcessorSpec{ + "calib-emcalchannel-calibration", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"do-EMCAL-channel-calib-in-test-mode", VariantType::Bool, false, {"to run in test mode for simplification"}}, + {"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/EMCAL/calibration/testWorkflow/emc-channel-calib-workflow.cxx b/Detectors/EMCAL/calibration/testWorkflow/emc-channel-calib-workflow.cxx new file mode 100644 index 0000000000000..036739ad7f3ad --- /dev/null +++ b/Detectors/EMCAL/calibration/testWorkflow/emc-channel-calib-workflow.cxx @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file emc-channel-calib-workflow.cxx +/// @author Hannah Bossi +/// @since 2020-12-01 +/// @brief Basic workflow for EMCAL bad channel calibration (adapted from tof-calib-workflow.cxx) + +#include "EMCALChannelCalibratorSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" + +#include <string> +#include <stdexcept> +#include <unordered_map> + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + specs.emplace_back(getEMCALChannelCalibDeviceSpec()); + return specs; +} diff --git a/Detectors/EMCAL/doxymodules.h b/Detectors/EMCAL/doxymodules.h index d570829f8a86b..a5423cadd016b 100644 --- a/Detectors/EMCAL/doxymodules.h +++ b/Detectors/EMCAL/doxymodules.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,6 +39,15 @@ * - Temperature calibration */ +/** + * @defgroup EMCALCalib EMCAL calib + * @brief EMCAL bad channel calibration + * @ingroup DetectorEMCAL + * + * Performs the EMCal bad channel calibration. + * + */ + /** * @defgroup EMCALsimulation EMCAL simulation * @brief EMCAL simulation code diff --git a/Detectors/EMCAL/reconstruction/CMakeLists.txt b/Detectors/EMCAL/reconstruction/CMakeLists.txt index ea2bbdeef9b59..d0a0bb4456472 100644 --- a/Detectors/EMCAL/reconstruction/CMakeLists.txt +++ b/Detectors/EMCAL/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EMCALReconstruction SOURCES src/RawReaderMemory.cxx @@ -20,8 +21,8 @@ o2_add_library(EMCALReconstruction src/CaloRawFitter.cxx src/CaloRawFitterStandard.cxx src/CaloRawFitterGamma2.cxx - src/ClusterizerParameters.cxx - src/Clusterizer.cxx + src/ClusterizerParameters.cxx + src/Clusterizer.cxx src/ClusterizerTask.cxx src/DigitReader.cxx src/CTFCoder.cxx @@ -33,7 +34,7 @@ o2_add_library(EMCALReconstruction O2::DetectorsRaw O2::EMCALBase O2::rANS - ms_gsl::ms_gsl) + Microsoft.GSL::GSL) o2_target_root_dictionary( EMCALReconstruction @@ -60,3 +61,8 @@ o2_add_executable(rawreader-file o2_add_test_root_macro(macros/RawFitterTESTs.C PUBLIC_LINK_LIBRARIES O2::EMCALReconstruction O2::Headers LABELS emcal COMPILE_ONLY) + +o2_add_test_root_macro(macros/RawFitterTESTMulti.C + PUBLIC_LINK_LIBRARIES O2::EMCALReconstruction O2::Headers + LABELS emcal COMPILE_ONLY) + diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h index 00720e2c5ad65..3925b76a4f483 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,6 +57,18 @@ class AltroDecoderError : public std::exception /// \return Error message const char* what() const noexcept override { return mErrorMessage.data(); } + /// \brief convert the error type from symoblic constant into int + /// \return the error number + static int errorTypeToInt(ErrorType_t errortype); + + /// \brief convert the error from number into a type (symbolic constant) + /// \return the error type + static ErrorType_t intToErrorType(int errornumber); + + /// \brief Get the number of error types handled by the AltroDecoderError + /// \return Number of error types + static constexpr int getNumberOfErrorTypes() noexcept { return 8; } + /// \brief Access to the error type connected to the erro /// \return Error type const ErrorType_t getErrorType() const noexcept { return mErrorType; } @@ -65,6 +78,74 @@ class AltroDecoderError : public std::exception std::string mErrorMessage; ///< Message connected to the error type }; +/// \class MinorAltroDecodingError +/// \brief Error handling for the ALTRO decoder for non-crashing errors +/// \ingroup EMCALreconstruction +class MinorAltroDecodingError +{ + public: + /// \enum ErrorType_t + /// \brief Error codes connected with the ALTRO decoding + enum class ErrorType_t { + BUNCH_HEADER_NULL, ///< Bunch header is 0 + CHANNEL_END_PAYLOAD_UNEXPECT, ///< Unexpected end of payload (channel or trailer word in bunch words) + CHANNEL_PAYLOAD_EXCEED ///< Exceeding channel payload block + }; + + /// \brief Dummy constructor + MinorAltroDecodingError() = default; + + /// \brief Constructor, initializing the object + /// \param errtype Type of the error + /// \param channelHeader Header of the channel raising the error + /// \param payloadword Payload word raising the error + MinorAltroDecodingError(ErrorType_t errtype, uint32_t channelHeader, uint32_t payloadword) : mErrorType(errtype), + mChannelHeader(channelHeader), + mPayloadWord(payloadword) + { + } + + /// \brief Destructor + ~MinorAltroDecodingError() noexcept = default; + + /// \brief Get the header of the channel raising the error + /// \return Hardware address + uint32_t getChannelHeader() const noexcept { return mChannelHeader; }; + + /// \brief Get the payload word raising the error + /// \return Payload word + uint32_t getPayloadWord() const noexcept { return mPayloadWord; } + + /// \brief Get the type of the error + /// \return Error type + ErrorType_t getErrorType() const noexcept { return mErrorType; } + + /// \brief Create and return error message for different error types + /// \return Error message + /// + /// Object returning a std::string which can be owned by the caller. + /// This is in contrast to exceptions inheriting from std::exception + /// which must return const char * in order to comply with the interface. + std::string what() const noexcept; + + /// \brief convert the error type from symoblic constant into int + /// \return the error number + static int errorTypeToInt(ErrorType_t errortype); + + /// \brief convert the error from number into a type (symbolic constant) + /// \return the error type + static ErrorType_t intToErrorType(int errornumber); + + /// \brief Get the number of error types handled by the AltroDecoderError + /// \return Number of error types + static constexpr int getNumberOfErrorTypes() noexcept { return 2; } + + private: + ErrorType_t mErrorType; ///< Type of the error + uint32_t mChannelHeader; ///< Hardware address raising the error + uint32_t mPayloadWord; ///< Payload word raising the error +}; + /// \class AltroDecoder /// \brief Decoder of the ALTRO data in the raw page /// \ingroup EMCALreconstruction @@ -117,6 +198,10 @@ class AltroDecoder /// \brief Read channels for the current event in the raw buffer void readChannels(); + /// \brief Get list of minor decoding errors + /// \return List of minor decoding errors + const std::vector<MinorAltroDecodingError>& getMinorDecodingErrors() const { return mMinorDecodingErrors; } + private: /// \brief run checks on the RCU trailer /// \throw Error if the RCU trailer has inconsistencies @@ -125,10 +210,11 @@ class AltroDecoder /// In case of failure an exception is thrown. void checkRCUTrailer(); - RawReaderMemory& mRawReader; ///< underlying raw reader - RCUTrailer mRCUTrailer; ///< RCU trailer - std::vector<Channel> mChannels; ///< vector of channels in the raw stream - bool mChannelsInitialized = false; ///< check whether the channels are initialized + RawReaderMemory& mRawReader; ///< underlying raw reader + RCUTrailer mRCUTrailer; ///< RCU trailer + std::vector<Channel> mChannels; ///< vector of channels in the raw stream + std::vector<MinorAltroDecodingError> mMinorDecodingErrors; ///< Container for minor (non-crashing) errors + bool mChannelsInitialized = false; ///< check whether the channels are initialized ClassDefNV(AltroDecoder, 1); }; diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Bunch.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Bunch.h index 8263a7ce5b5c7..de9b619f55f6c 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Bunch.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Bunch.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h index a51ca476032d3..a81f22b9adacd 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -72,13 +73,14 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, CTFHelper helper(trigData, cellData); // book output size with some margin - auto szIni = sizeof(CTFHeader) + helper.getSize() / 4; // will be autoexpanded if needed + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed buff.resize(szIni); auto ec = CTF::create(buff); using ECB = CTF::base; ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -87,7 +89,7 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, ENCODEEMC(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); ENCODEEMC(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); ENCODEEMC(helper.begin_entriesTrig(), helper.end_entriesTrig(), CTF::BLC_entriesTrig, 0); - + ENCODEEMC(helper.begin_towerID(), helper.end_towerID(), CTF::BLC_towerID, 0); ENCODEEMC(helper.begin_time(), helper.end_time(), CTF::BLC_time, 0); ENCODEEMC(helper.begin_energy(), helper.end_energy(), CTF::BLC_energy, 0); @@ -100,7 +102,8 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, template <typename VTRG, typename VCELL> void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VCELL& cellVec) { - auto header = ec.getHeader(); + const auto& header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); ec.print(getPrefix()); std::vector<uint16_t> bcInc, entries, energy, cellTime, tower; std::vector<uint32_t> orbitInc; diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFHelper.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFHelper.h index 4589f217226d1..924505f1cd1d6 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFHelper.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,8 @@ class CTFHelper CTFHeader createHeader() { - CTFHeader h{uint32_t(mTrigData.size()), uint32_t(mCellData.size()), 0, 0}; + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigData.size()), uint32_t(mCellData.size()), 0, 0}; if (mTrigData.size()) { h.firstOrbit = mTrigData[0].getBCData().orbit; h.firstBC = mTrigData[0].getBCData().bc; diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloFitResults.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloFitResults.h index ad2ad3d35ba0f..5a2f68b50109b 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloFitResults.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloFitResults.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitter.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitter.h index 5a91557dbe5de..2cac23479ea90 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitter.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include <iosfwd> #include <array> #include <optional> +#include <string_view> #include <Rtypes.h> #include <gsl/span> #include "EMCALReconstruction/CaloFitResults.h" @@ -39,17 +41,43 @@ class CaloRawFitter { public: + /** + * \enum RawFitterError_t + * \brief Error codes for failures in raw fitter procedure + */ + enum class RawFitterError_t { + SAMPLE_UNINITIALIZED, ///< Samples not initialized or length is 0 + FIT_ERROR, ///< Fit procedure failed + CHI2_ERROR, ///< Chi2 cannot be determined (usually due to insufficient amount of samples) + BUNCH_NOT_OK, ///< Bunch selection failed + LOW_SIGNAL ///< No ADC value above threshold found + }; + + /// \brief Create error message for a given error type + /// \param fiterror Fit error type + /// \return Error message connected to the error type + static std::string createErrorMessage(RawFitterError_t fiterror); + + /// \brief Convert error type to numeric representation + /// \param fiterror Fit error type + /// \return Numeric representation of the raw fitter error + static int getErrorNumber(RawFitterError_t fiterror); + + /// \brief Get the number of raw fit error types supported + /// \return Number of error types (4) + static constexpr int getNumberOfErrorTypes() noexcept { return 4; } + /// \brief Constructor CaloRawFitter(const char* name, const char* nameshort); /// \brief Destructor virtual ~CaloRawFitter() = default; - virtual CaloFitResults evaluate(const std::vector<Bunch>& bunchvector, - std::optional<unsigned int> altrocfg1, - std::optional<unsigned int> altrocfg2) = 0; + virtual CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector) = 0; /// \brief Method to do the selection of what should possibly be fitted. + /// \param bunchvector ALTRO bunches for the current channel + /// \param adcThreshold ADC threshold applied in peak finding /// \return Size of the sub-selected sample, /// \return index of the bunch with maximum signal, /// \return maximum signal, @@ -58,8 +86,7 @@ class CaloRawFitter /// \return pedestal, /// \return first time bin, /// \return last time bin, - std::tuple<int, int, float, short, short, float, int, int> preFitEvaluateSamples(const std::vector<Bunch>& bunchvector, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2, int acut); + std::tuple<int, int, float, short, short, float, int, int> preFitEvaluateSamples(const gsl::span<const Bunch> bunchvector, int adcThreshold); /// \brief The require time range if the maximum ADC value is between min and max (timebin) void setTimeConstraint(int min, int max); @@ -75,45 +102,60 @@ class CaloRawFitter // access to array info double getReversed(const int i) const { return mReversed[i]; } - const char* getAlgoName() const { return mName.c_str(); } - const char* getAlgoAbbr() const { return mNameShort.c_str(); } + const std::string_view getAlgoName() const { return mName.c_str(); } + const std::string_view getAlgoAbbr() const { return mNameShort.c_str(); } + + /// \brief Get Type of the fit algorithm + /// \return Fit algorithm type FitAlgorithm getAlgo() const { return mAlgo; } - /// \brief Get the maximum of a bunch array - /// \return Maximum amplitute - short maxAmp(const Bunch& bunch, int& maxindex) const; + /// \brief Get the maximum amplitude and its index of a bunch array + /// \return Maximum ADC value of the bunch + /// \return Index of the max. ADC value of the bunch + std::tuple<short, int> getMaxAmplitudeBunch(const Bunch& bunchx) const; /// \brief Get maximum of array /// \return Maximum amplitute - unsigned short maxAmp(const gsl::span<unsigned short> data) const; + unsigned short getMaxAmplitudeBunch(const gsl::span<unsigned short> data) const; - /// \brief A bunch is considered invalid if the maximum is in the first or last time-bin. - bool checkBunchEdgesForMax(const Bunch& bunch) const; + /// \brief Check if the max. ADC value is at the edge of a bunch + /// \param bunch The bunch to be checked + /// \return True if the Max. ADC value is either the first or the last value of a bunch + bool isMaxADCBunchEdge(const Bunch& bunch) const; - /// \brief Check if the index of the max ADC vaue is consistent with trigger. - bool isInTimeRange(int maxindex, int maxtime, int mintime) const; + /// \brief Check if the index of the max ADC vaue is within accepted time range + /// \param indexMaxADC Index of the max. ADC value + /// \param maxtime Max. time value of the accepted range + /// \param mintime Min. time value of the accepted range + /// \return True of the index of the max ADC is within the accepted time range, false otherwise + bool isInTimeRange(int indexMaxADC, int maxtime, int mintime) const; /// \brief Time sample comes in reversed order, revers them back Subtract the baseline based on content of altrocfg1 and altrocfg2. /// \return Pedestal /// \return Array with revered and pedestal subtracted ADC signals - std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> reverseAndSubtractPed(const Bunch& bunch, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2) const; + std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> reverseAndSubtractPed(const Bunch& bunch) const; /// \brief We select the bunch with the highest amplitude unless any time constraints is set. + /// \param bunchvector Bunches of the channel among which to select the maximium /// \return The index of the array with the maximum aplitude /// \return The bin where we have a maximum amp /// \return The maximum ADC signal - std::tuple<short, short, short> selectBunch(const std::vector<Bunch>& bunchvector); - - /// \brief Selection of subset of data from one bunch that will be used for fitting or Peak finding. - /// Go to the left and right of index of the maximum time bin - /// Until the ADC value is less than cut, or derivative changes sign (data jump) - /// \return The index of the jumb before the maximum - /// \return The index of the jumb after the maximum - std::tuple<int, int> selectSubarray(const gsl::span<double> data, short maxindex, int cut) const; - - /// \brief Pedestal evaluation if not zero suppressed - float evaluatePedestal(const std::vector<uint16_t>& data, std::optional<int> length) const; + /// \throw RawFitterError_t::BUNCH_NOT_OK ADC value is at a bunch edge + std::tuple<short, short, short> selectMaximumBunch(const gsl::span<const Bunch>& bunchvector); + + /// \brief Find region constrainded by its closest minima around the main peak + /// \param adcValues ADC values of the bunch + /// \param indexMaxADC Index of the maximum ADC value + /// \param threshold Min. ADC value accepted in peak region + /// \return Index of the closest minimum before the peak + /// \return Index of the closest minimum after the pea + std::tuple<int, int> findPeakRegion(const gsl::span<double> adcValues, short indexMaxADC, int threshold) const; + + /// \brief Calculate the pedestal from the ADC values in a bunch + /// \param data ADC values from which to calculate the pedestal + /// \param length Optional bunch length + /// \return Pedestal value + double evaluatePedestal(const gsl::span<const uint16_t> data, std::optional<int> length) const; /// \brief Calculates the chi2 of the fit /// diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterGamma2.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterGamma2.h old mode 100755 new mode 100644 index 84a797d617176..851fcf8891edd --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterGamma2.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterGamma2.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,22 +53,34 @@ class CaloRawFitterGamma2 final : public CaloRawFitter int getNiterationsMax() { return mNiterationsMax; } /// \brief Evaluation Amplitude and TOF - /// return Container with the fit results (amp, time, chi2, ...) - CaloFitResults evaluate(const std::vector<Bunch>& bunchvector, - std::optional<unsigned int> altrocfg1, - std::optional<unsigned int> altrocfg2) final; + /// \param bunchvector ALTRO bunches for the current channel + /// \param altrocfg1 ALTRO config register 1 from RCU trailer + /// \param altrocfg2 ALTRO config register 2 from RCU trailer + /// \throw RawFitterError_t::FIT_ERROR in case the peak fit failed + /// \return Container with the fit results (amp, time, chi2, ...) + CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector) final; private: int mNiter = 0; ///< number of iteraions int mNiterationsMax = 15; ///< max number of iteraions /// \brief Fits the raw signal time distribution - /// \return chi2, fit status. - std::tuple<float, bool> doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time); + /// \param firstTimeBin First timebin in the ALTRO bunch + /// \param nSamples Number of time samples of the ALTRO bunch + /// \param[in] ampl Initial guess of the amplitude for the fit + /// \param[out] ampl Amplitude result of the peak fit + /// \param[in] time Initial guess of the time for the fit + /// \param[out] time Time result of the peak fit + /// \return chi2 of the fit + /// \throw RawFitterError_t::FIT_ERROR in case of fit errors (insufficient number of time samples, matrix diagonalization error, ...) + float doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time); /// \brief Fits the raw signal time distribution + /// \param maxTimeBin Time bin of the max. amplitude /// \return the fit parameters: amplitude, time. - std::tuple<float, float> doParabolaFit(int x) const; + /// + /// Fit performed as parabola fit to the signal + std::tuple<float, float> doParabolaFit(int maxTimeBin) const; ClassDefNV(CaloRawFitterGamma2, 1); }; // End of CaloRawFitterGamma2 diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterStandard.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterStandard.h index 54fe091322810..02f968fd93c62 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterStandard.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterStandard.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,20 +51,23 @@ class CaloRawFitterStandard final : public CaloRawFitter ~CaloRawFitterStandard() final = default; /// \brief Approximate response function of the EMCal electronics. - /// \param x: bin - /// \param par: function parameters + /// \param x bin + /// \param par function parameters /// \return double with signal for a given time bin static double rawResponseFunction(double* x, double* par); /// \brief Evaluation Amplitude and TOF - /// return Container with the fit results (amp, time, chi2, ...) - CaloFitResults evaluate(const std::vector<Bunch>& bunchvector, - std::optional<unsigned int> altrocfg1, - std::optional<unsigned int> altrocfg2) final; + /// \param bunchvector Calo bunches for the tower and event + /// \return Container with the fit results (amp, time, chi2, ...) + /// \throw RawFitterError_t in case the fit failed (including all possible errors from upstream) + CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector) final; - /// \brief Fits the raw signal time distribution - /// \return the fit parameters: amplitude, time, chi2, fit status. - std::tuple<float, float, float, bool> fitRaw(int firstTimeBin, int lastTimeBin) const; + /// \brief Fits the raw signal time distribution using TMinuit + /// \param firstTimeBin First timebin of the ALTRO bunch + /// \param lastTimeBin Last timebin of the ALTRO bunch + /// \return the fit parameters: amplitude, time, chi2 + /// \throw RawFitter_t::FIT_ERROR in case the fit failed (insufficient number of samples or fit error from MINUIT) + std::tuple<float, float, float> fitRaw(int firstTimeBin, int lastTimeBin) const; private: ClassDefNV(CaloRawFitterStandard, 1); diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Channel.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Channel.h index f3a7106155168..aebe890b78fcc 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Channel.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Channel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -105,7 +106,7 @@ class Channel /// \throw HadrwareAddressError in case the hardware address is not initialized int getBranchIndex() const; - /// \brief Provide the front-end card index for the current hardware address + /// \brief Provide the front-end card index (0-9) in branch for the current hardware address /// \return Front-end card index for the current hardware address /// \throw HadrwareAddressError in case the hardware address is not initialized int getFECIndex() const; diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Clusterizer.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Clusterizer.h index bc057b0a3b4a9..0f58262f43400 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Clusterizer.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Clusterizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerParameters.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerParameters.h index 719202b605457..04f3e72369934 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerParameters.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerTask.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerTask.h index d8a6c9a8bdf3b..86ac6d274dda5 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerTask.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ClusterizerTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/DigitReader.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/DigitReader.h index 180069f147b0d..08d524b558b2c 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/DigitReader.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/DigitReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawBuffer.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawBuffer.h index 3c598b1bb71ec..9646fabebc4ac 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawBuffer.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawBuffer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h index 7c028e02cdac9..cc8100aa08670 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,17 +27,21 @@ namespace emcal /// - Page not found /// - Raw header decoding error /// - Payload decoding error +/// - Out-of-bounds errors +/// In addition to the error type the FEE ID obtained from the +/// current raw header is propagated. class RawDecodingError : public std::exception { public: /// \enum ErrorType_t /// \brief Codes for different error types enum class ErrorType_t { - PAGE_NOTFOUND, ///< Page was not found (page index outside range) - HEADER_DECODING, ///< Header cannot be decoded (format incorrect) - PAYLOAD_DECODING, ///< Payload cannot be decoded (format incorrect) - HEADER_INVALID, ///< Header in memory not belonging to requested superpage - PAYLOAD_INVALID, ///< Payload in memory not belonging to requested superpage + PAGE_NOTFOUND, ///< Page was not found (page index outside range) + HEADER_DECODING, ///< Header cannot be decoded (format incorrect) + PAYLOAD_DECODING, ///< Payload cannot be decoded (format incorrect) + HEADER_INVALID, ///< Header in memory not belonging to requested superpage + PAGE_START_INVALID, ///< Page position starting outside payload size + PAYLOAD_INVALID ///< Payload in memory not belonging to requested superpage }; /// \brief Constructor @@ -44,7 +49,7 @@ class RawDecodingError : public std::exception /// /// Constructing the error with error code. To be called when the /// exception is thrown. - RawDecodingError(ErrorType_t errtype) : mErrorType(errtype) + RawDecodingError(ErrorType_t errtype, int fecID) : mErrorType(errtype), mFecID(fecID) { } @@ -64,6 +69,8 @@ class RawDecodingError : public std::exception return "Payload of page cannot be decoded"; case ErrorType_t::HEADER_INVALID: return "Access to header not belonging to requested superpage"; + case ErrorType_t::PAGE_START_INVALID: + return "Page decoding starting outside payload size"; case ErrorType_t::PAYLOAD_INVALID: return "Access to payload not belonging to requested superpage"; }; @@ -74,8 +81,36 @@ class RawDecodingError : public std::exception /// \return Error code of the exception ErrorType_t getErrorType() const { return mErrorType; } + /// \brief Get the ID of the frontend electronics responsible for the error + /// \return ID of the frontend electronics + int getFECID() const { return mFecID; } + + /// \brief Convert error type to error code number + /// \return Numeric representation of the error type + static int ErrorTypeToInt(RawDecodingError::ErrorType_t errortype) + { + switch (errortype) { + case ErrorType_t::PAGE_NOTFOUND: + return 0; + case ErrorType_t::HEADER_DECODING: + return 1; + case ErrorType_t::PAYLOAD_DECODING: + return 2; + case ErrorType_t::HEADER_INVALID: + return 3; + case ErrorType_t::PAGE_START_INVALID: + return 4; + case ErrorType_t::PAYLOAD_INVALID: + return 5; + }; + // can never reach this, due to enum class + // just to make Werror happy + return -1; + } + private: ErrorType_t mErrorType; ///< Type of the error + int mFecID; ///< ID of the FEC responsible for the ERROR }; } // namespace emcal diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawHeaderStream.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawHeaderStream.h index 017b091203378..4f898d66934ad 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawHeaderStream.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawHeaderStream.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawPayload.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawPayload.h index 7450d3afbd478..3a4abfd8f9617 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawPayload.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawPayload.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h index c6d544e0529ff..23da7c466afc4 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,15 +61,6 @@ class RawReaderMemory /// it should not be called directly by the user. void nextPage(bool resetPayload = true); - /// \brief Read page with a given index - /// \param page Index of the page to be decoded - /// \throw RawDecodingError if the page cannot be read or header or payload cannot be deocded - /// - /// The reader will try to read the page with a certain index. In - /// case the page cannot be decoded (page index outside range, - /// decoding of header or payload failed), and excpetion is raised. - void readPage(int page); - /// \brief access to the raw header of the current page /// \return Raw header of the current page /// \throw RawDecodingError with HEADER_INVALID if the header was not decoded @@ -91,10 +83,6 @@ class RawReaderMemory /// \return size of the file in byte int getFileSize() const noexcept { return mRawMemoryBuffer.size(); } - /// \brief get the number of pages in the file - /// \return number of pages in the file - int getNumberOfPages() const noexcept { return mNumData; } - /// \brief check if more pages are available in the raw file /// \return true if there is a next page bool hasNext() const { return mCurrentPosition < mRawMemoryBuffer.size(); } @@ -115,7 +103,7 @@ class RawReaderMemory RCUTrailer mCurrentTrailer; ///< RCU trailer uint64_t mTrailerPayloadWords = 0; ///< Payload words in common trailer int mCurrentPosition = 0; ///< Current page in file - int mNumData = 0; ///< Number of pages + int mCurrentFEE = -1; ///< Current FEE in the data stream bool mRawHeaderInitialized = false; ///< RDH for current page initialized bool mPayloadInitialized = false; ///< Payload for current page initialized diff --git a/Detectors/EMCAL/reconstruction/macros/RawFitterTESTMulti.C b/Detectors/EMCAL/reconstruction/macros/RawFitterTESTMulti.C new file mode 100644 index 0000000000000..5e31105ad76a2 --- /dev/null +++ b/Detectors/EMCAL/reconstruction/macros/RawFitterTESTMulti.C @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <array> +#include <iostream> +#include <fstream> +#include <vector> +#include "RStringView.h" +#include <Rtypes.h> +#include "DetectorsRaw/RawFileReader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "EMCALReconstruction/CaloFitResults.h" +#include "EMCALReconstruction/Bunch.h" +#include "EMCALReconstruction/CaloRawFitterStandard.h" +#include "EMCALReconstruction/AltroDecoder.h" +#include "EMCALReconstruction/CaloRawFitterGamma2.h" +//#include "EMCALReconstruction/RawHeaderStream.h" +#endif + +using namespace o2::emcal; + +/// \brief Testing the standard raw fitter on run2 to run3 converted data +void RawFitterTESTMulti(const char* configfile = "") +{ + + const Int_t NoiseThreshold = 3; + + o2::raw::RawFileReader reader(configfile); + reader.init(); + + // define the standard raw fitter + //o2::emcal::CaloRawFitterStandard RawFitter; + o2::emcal::CaloRawFitterGamma2 RawFitter; + RawFitter.setAmpCut(NoiseThreshold); + RawFitter.setL1Phase(0.); + + while (1) { + int tfID = reader.getNextTFToRead(); + if (tfID >= reader.getNTimeFrames()) { + std::cerr << "nothing left to read after " << tfID << " TFs read" << std::endl; + break; + } + std::vector<char> dataBuffer; // where to put extracted data + std::cout << "Next iteration: Number of links: " << reader.getNLinks() << std::endl; + for (int il = 0; il < reader.getNLinks(); il++) { + auto& link = reader.getLink(il); + std::cout << "Decoding link " << il << std::endl; + + auto sz = link.getNextTFSize(); // size in bytes needed for the next TF of this link + dataBuffer.resize(sz); + link.readNextTF(dataBuffer.data()); + + // Parse + o2::emcal::RawReaderMemory parser(dataBuffer); + while (parser.hasNext()) { + parser.next(); + //std::cout << "next page \n"; + if (o2::raw::RDHUtils::getFEEID(parser.getRawHeader()) >= 40) + continue; + + //std::cout<<rawreader.getRawHeader()<<std::endl; + + // use the altro decoder to decode the raw data, and extract the RCU trailer + o2::emcal::AltroDecoder decoder(parser); + std::cout << "Decoding" << std::endl; + decoder.decode(); + RawFitter.setIsZeroSuppressed(decoder.getRCUTrailer().hasZeroSuppression()); + + //std::cout << decoder.getRCUTrailer() << std::endl; + std::cout << "Found number of channels: " << decoder.getChannels().size() << std::endl; + + // Loop over all the channels + for (auto& chan : decoder.getChannels()) { + std::cout << "processing next channel idx " << chan.getChannelIndex() << ", " << chan.getHardwareAddress() << std::endl; + // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter + //continue; + std::cout << "Channel has " << chan.getBunches().size() << " bunches " << std::endl; + try { + o2::emcal::CaloFitResults fitResults = RawFitter.evaluate(chan.getBunches()); + + // print the fit output + //std::cout << "The Time is : " << fitResults.getTime() << " And the Amplitude is : " << fitResults.getAmp() << std::endl; + std::cout << "Fit done" << std::endl; + } catch (o2::emcal::CaloRawFitter::RawFitterError_t& fiterror) { + std::cerr << "Error processing raw fit: " << o2::emcal::CaloRawFitter::createErrorMessage(fiterror) << std::endl; + for (auto bunch : chan.getBunches()) { + std::cout << "Next bunch: " << bunch.getADC().size() << " entries" << std::endl; + bool first = true; + for (auto en : bunch.getADC()) { + if (!first) { + std::cout << ", "; + } + std::cout << en; + first = false; + } + std::cout << std::endl; + } + std::cout << "Channel end" << std::endl; + } + } + } + } + reader.setNextTFToRead(++tfID); + } +} diff --git a/Detectors/EMCAL/reconstruction/macros/RawFitterTESTs.C b/Detectors/EMCAL/reconstruction/macros/RawFitterTESTs.C index e5106ef2971e6..0677fab99b563 100644 --- a/Detectors/EMCAL/reconstruction/macros/RawFitterTESTs.C +++ b/Detectors/EMCAL/reconstruction/macros/RawFitterTESTs.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,6 +44,7 @@ void RawFitterTESTs(const char* filename = "") inputDir += "/share/Detectors/EMC/files/"; inputfile = inputDir + "emcal.raw"; } + std::cout << "Using input file " << inputfile << std::endl; o2::raw::RawFileReader reader; reader.setDefaultDataOrigin(o2::header::gDataOriginEMC); @@ -64,6 +66,7 @@ void RawFitterTESTs(const char* filename = "") break; } std::vector<char> dataBuffer; // where to put extracted data + std::cout << "Next iteration: Number of links: " << reader.getNLinks() << std::endl; for (int il = 0; il < reader.getNLinks(); il++) { auto& link = reader.getLink(il); std::cout << "Decoding link " << il << std::endl; @@ -84,18 +87,26 @@ void RawFitterTESTs(const char* filename = "") // use the altro decoder to decode the raw data, and extract the RCU trailer o2::emcal::AltroDecoder decoder(parser); + std::cout << "Decoding" << std::endl; decoder.decode(); std::cout << decoder.getRCUTrailer() << std::endl; + std::cout << "Found number of channels: " << decoder.getChannels().size() << std::endl; + RawFitter.setIsZeroSuppressed(decoder.getRCUTrailer().hasZeroSuppression()); // Loop over all the channels for (auto& chan : decoder.getChannels()) { - + std::cout << "processing next channel idx " << chan.getChannelIndex() << ", " << chan.getHardwareAddress() << std::endl; // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter - o2::emcal::CaloFitResults fitResults = RawFitter.evaluate(chan.getBunches(), 0, 0); - - // print the fit output - std::cout << "The Time is : " << fitResults.getTime() << " And the Amplitude is : " << fitResults.getAmp() << std::endl; + continue; + try { + o2::emcal::CaloFitResults fitResults = RawFitter.evaluate(chan.getBunches()); + + // print the fit output + std::cout << "The Time is : " << fitResults.getTime() << " And the Amplitude is : " << fitResults.getAmp() << std::endl; + } catch (o2::emcal::CaloRawFitter::RawFitterError_t& fiterror) { + std::cerr << "Error processing raw fit: " << o2::emcal::CaloRawFitter::createErrorMessage(fiterror) << std::endl; + } } } } diff --git a/Detectors/EMCAL/reconstruction/run/rawReaderFile.cxx b/Detectors/EMCAL/reconstruction/run/rawReaderFile.cxx index badb7c785292d..d3daa2ab5281e 100644 --- a/Detectors/EMCAL/reconstruction/run/rawReaderFile.cxx +++ b/Detectors/EMCAL/reconstruction/run/rawReaderFile.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx index 20f8b16b3651d..7f03600ce1c75 100644 --- a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx @@ -1,15 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include <cstring> +#include <iomanip> +#include <iostream> #include <boost/format.hpp> #include "InfoLogger/InfoLogger.hxx" +#include "DetectorsRaw/RDHUtils.h" #include "EMCALReconstruction/AltroDecoder.h" #include "EMCALReconstruction/RawReaderMemory.h" @@ -24,6 +28,7 @@ AltroDecoder::AltroDecoder(RawReaderMemory& reader) : mRawReader(reader), void AltroDecoder::decode() { + mMinorDecodingErrors.clear(); readRCUTrailer(); checkRCUTrailer(); readChannels(); @@ -44,6 +49,11 @@ void AltroDecoder::readRCUTrailer() void AltroDecoder::checkRCUTrailer() { + int trailersize = mRCUTrailer.getTrailerSize(); + int buffersize = mRawReader.getPayload().getPayloadWords().size(); + if (trailersize > buffersize) { + throw AltroDecoderError(AltroDecoderError::ErrorType_t::RCU_TRAILER_SIZE_ERROR, (boost::format("Trailer size %d exceeding buffer size %d") % trailersize % buffersize).str().data()); + } } void AltroDecoder::readChannels() @@ -52,12 +62,14 @@ void AltroDecoder::readChannels() mChannels.clear(); int currentpos = 0; auto& buffer = mRawReader.getPayload().getPayloadWords(); - while (currentpos < buffer.size() - mRCUTrailer.getTrailerSize()) { + auto maxpayloadsize = buffer.size() - mRCUTrailer.getTrailerSize(); + while (currentpos < maxpayloadsize) { auto currentword = buffer[currentpos++]; if (currentword >> 30 != 1) { continue; } // starting a new channel + auto channelheader = currentword; mChannels.emplace_back(currentword & 0xFFF, (currentword >> 16) & 0x3FF); auto& currentchannel = mChannels.back(); currentchannel.setBadChannel((currentword >> 29) & 0x1); @@ -66,11 +78,13 @@ void AltroDecoder::readChannels() int numberofwords = (currentchannel.getPayloadSize() + 2) / 3; std::vector<uint16_t> bunchwords; for (int iword = 0; iword < numberofwords; iword++) { + if (currentpos >= maxpayloadsize) { + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_PAYLOAD_EXCEED, channelheader, currentword); + break; // Must break here in order not to prevent a buffer overrun + } currentword = buffer[currentpos++]; if ((currentword >> 30) != 0) { - // AliceO2::InfoLogger::InfoLogger logger; - // logger << "Unexpected end of payload in altro channel payload! DDL=" << std::setw(3) << std::setfill(0) << mRawReader.getRawHeader().getLink() - // << ", Address=0x" << std::hex << current.getHardwareAddress() << ", word=0x" << currentword << std::dec; + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, channelheader, currentword); currentpos--; continue; } @@ -81,7 +95,12 @@ void AltroDecoder::readChannels() // decode bunches int currentsample = 0; - while (currentsample < currentchannel.getPayloadSize()) { + while (currentsample < currentchannel.getPayloadSize() && bunchwords.size() > currentsample + 2) { + // Check if bunch word is 0 - if yes skip all following bunches as they can no longer be reliably decoded + if (bunchwords[currentsample] == 0) { + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_HEADER_NULL, channelheader, 0); + break; + } int bunchlength = bunchwords[currentsample] - 2, // remove words for bunchlength and starttime starttime = bunchwords[currentsample + 1]; auto& currentbunch = currentchannel.createBunch(bunchlength, starttime); @@ -106,4 +125,148 @@ const std::vector<Channel>& AltroDecoder::getChannels() const throw AltroDecoderError(AltroDecoderError::ErrorType_t::CHANNEL_ERROR, "Channels not initizalized"); } return mChannels; +} + +using AltroErrType = o2::emcal::AltroDecoderError::ErrorType_t; + +int AltroDecoderError::errorTypeToInt(AltroErrType errortype) +{ + + int errorNumber = -1; + + switch (errortype) { + case AltroErrType::RCU_TRAILER_ERROR: + errorNumber = 0; + break; + case AltroErrType::RCU_VERSION_ERROR: + errorNumber = 1; + break; + case AltroErrType::RCU_TRAILER_SIZE_ERROR: + errorNumber = 2; + break; + case AltroErrType::ALTRO_BUNCH_HEADER_ERROR: + errorNumber = 3; + break; + case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR: + errorNumber = 4; + break; + case AltroErrType::ALTRO_PAYLOAD_ERROR: + errorNumber = 5; + break; + case AltroErrType::ALTRO_MAPPING_ERROR: + errorNumber = 6; + break; + case AltroErrType::CHANNEL_ERROR: + errorNumber = 7; + break; + default: + break; + } + + return errorNumber; +} + +AltroErrType AltroDecoderError::intToErrorType(int errornumber) +{ + + AltroErrType errorType; + + switch (errornumber) { + case 0: + errorType = AltroErrType::RCU_TRAILER_ERROR; + break; + case 1: + errorType = AltroErrType::RCU_VERSION_ERROR; + break; + case 2: + errorType = AltroErrType::RCU_TRAILER_SIZE_ERROR; + break; + case 3: + errorType = AltroErrType::ALTRO_BUNCH_HEADER_ERROR; + break; + case 4: + errorType = AltroErrType::ALTRO_BUNCH_LENGTH_ERROR; + break; + case 5: + errorType = AltroErrType::ALTRO_PAYLOAD_ERROR; + break; + case 6: + errorType = AltroErrType::ALTRO_MAPPING_ERROR; + break; + case 7: + errorType = AltroErrType::CHANNEL_ERROR; + break; + default: + break; + } + + return errorType; +} + +std::string MinorAltroDecodingError::what() const noexcept +{ + std::stringstream result; + switch (mErrorType) { + case ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT: + result << "Unexpected end of payload in altro channel payload!"; + break; + case ErrorType_t::CHANNEL_PAYLOAD_EXCEED: + result << "Trying to access out-of-bound payload!"; + break; + case ErrorType_t::BUNCH_HEADER_NULL: + result << "Bunch header 0 or not configured!"; + break; + }; + auto address = mChannelHeader & 0xFFF, + payload = (mChannelHeader >> 16) & 0x3FF; + bool good = (mChannelHeader >> 29) & 0x1; + + result << " Channel header=0x" << std::hex << mChannelHeader + << " (Address=0x" << address << ", payload " << std::dec << payload << ", good " << (good ? "yes" : "no") << ")" + << ", word=0x" << std::hex << mPayloadWord << std::dec; + return result.str(); +} + +using MinorAltroErrType = o2::emcal::MinorAltroDecodingError::ErrorType_t; + +int MinorAltroDecodingError::errorTypeToInt(MinorAltroErrType errortype) +{ + + int errorNumber = -1; + + switch (errortype) { + case MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT: + errorNumber = 0; + break; + case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED: + errorNumber = 1; + break; + case MinorAltroErrType::BUNCH_HEADER_NULL: + errorNumber = 2; + break; + } + + return errorNumber; +} + +MinorAltroErrType MinorAltroDecodingError::intToErrorType(int errornumber) +{ + + MinorAltroErrType errorType; + + switch (errornumber) { + case 0: + errorType = MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT; + break; + case 1: + errorType = MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED; + break; + case 2: + errorType = MinorAltroErrType::BUNCH_HEADER_NULL; + break; + default: + break; + } + + return errorType; } \ No newline at end of file diff --git a/Detectors/EMCAL/reconstruction/src/Bunch.cxx b/Detectors/EMCAL/reconstruction/src/Bunch.cxx index fea2cd3da982c..0f532732a013f 100644 --- a/Detectors/EMCAL/reconstruction/src/Bunch.cxx +++ b/Detectors/EMCAL/reconstruction/src/Bunch.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx b/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx index 3fc31aaea0a7a..158702a36e274 100644 --- a/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/CTFHelper.cxx b/Detectors/EMCAL/reconstruction/src/CTFHelper.cxx index 1e0f385b72fce..14346f6261a6a 100644 --- a/Detectors/EMCAL/reconstruction/src/CTFHelper.cxx +++ b/Detectors/EMCAL/reconstruction/src/CTFHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/CaloFitResults.cxx b/Detectors/EMCAL/reconstruction/src/CaloFitResults.cxx index 364de7042a279..7a129f387fa44 100644 --- a/Detectors/EMCAL/reconstruction/src/CaloFitResults.cxx +++ b/Detectors/EMCAL/reconstruction/src/CaloFitResults.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/CaloRawFitter.cxx b/Detectors/EMCAL/reconstruction/src/CaloRawFitter.cxx index 7e14fe7b56eab..1c34bb9dd43d0 100644 --- a/Detectors/EMCAL/reconstruction/src/CaloRawFitter.cxx +++ b/Detectors/EMCAL/reconstruction/src/CaloRawFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,21 +11,58 @@ /// \file CaloRawFitter.cxx /// \author Hadi Hassan (hadi.hassan@cern.ch) - -#include "FairLogger.h" +#include <numeric> #include <gsl/span> // ROOT sytem #include "TMath.h" +#include "FairLogger.h" +#include "DataFormatsEMCAL/Constants.h" #include "EMCALReconstruction/Bunch.h" #include "EMCALReconstruction/CaloFitResults.h" -#include "DataFormatsEMCAL/Constants.h" - #include "EMCALReconstruction/CaloRawFitter.h" using namespace o2::emcal; +std::string CaloRawFitter::createErrorMessage(CaloRawFitter::RawFitterError_t errorcode) +{ + switch (errorcode) { + case RawFitterError_t::SAMPLE_UNINITIALIZED: + return "Sample for fit not initialzied or bunch length is 0"; + case RawFitterError_t::FIT_ERROR: + return "Fit of the raw bunch was not successful"; + case RawFitterError_t::CHI2_ERROR: + return "Chi2 of the fit could not be determined"; + case RawFitterError_t::BUNCH_NOT_OK: + return "Calo bunch could not be selected"; + case RawFitterError_t::LOW_SIGNAL: + return "No ADC value above threshold found"; + }; + // Silence compiler warnings for false positives + // can never enter here due to usage of enum class + return "Unknown error code"; +} + +int CaloRawFitter::getErrorNumber(CaloRawFitter::RawFitterError_t fiterror) +{ + switch (fiterror) { + case RawFitterError_t::SAMPLE_UNINITIALIZED: + return 0; + case RawFitterError_t::FIT_ERROR: + return 1; + case RawFitterError_t::CHI2_ERROR: + return 2; + case RawFitterError_t::BUNCH_NOT_OK: + return 3; + case RawFitterError_t::LOW_SIGNAL: + return 4; + }; + // Silence compiler warnings for false positives + // can never enter here due to usage of enum class + return -1; +} + //Default constructor CaloRawFitter::CaloRawFitter(const char* name, const char* nameshort) : mMinTimeIndex(-1), mMaxTimeIndex(-1), @@ -50,41 +88,41 @@ void CaloRawFitter::setTimeConstraint(int min, int max) } } -unsigned short CaloRawFitter::maxAmp(const gsl::span<unsigned short> data) const +unsigned short CaloRawFitter::getMaxAmplitudeBunch(const gsl::span<unsigned short> data) const { return *std::max_element(data.begin(), data.end()); } -std::tuple<int, int> CaloRawFitter::selectSubarray(const gsl::span<double> data, short maxindex, int cut) const +std::tuple<int, int> CaloRawFitter::findPeakRegion(const gsl::span<double> adcValues, short indexMaxADC, int threshold) const { int first(0), last(0); - int tmpfirst = maxindex; - int tmplast = maxindex; - double prevFirst = data[maxindex]; - double prevLast = data[maxindex]; + int tmpfirst = indexMaxADC; + int tmplast = indexMaxADC; + double prevFirst = adcValues[indexMaxADC]; + double prevLast = adcValues[indexMaxADC]; bool firstJump = false; bool lastJump = false; - while ((tmpfirst >= 0) && (data[tmpfirst] >= cut) && (!firstJump)) { + while ((tmpfirst >= 0) && (adcValues[tmpfirst] >= threshold) && (!firstJump)) { // jump check: - if (tmpfirst != maxindex) { // neighbor to maxindex can share peak with maxindex - if (data[tmpfirst] >= prevFirst) { + if (tmpfirst != indexMaxADC) { // neighbor to maxindex can share peak with maxindex + if (adcValues[tmpfirst] >= prevFirst) { firstJump = true; } } - prevFirst = data[tmpfirst]; + prevFirst = adcValues[tmpfirst]; tmpfirst--; } - while ((tmplast < data.size()) && (data[tmplast] >= cut) && (!lastJump)) { + while ((tmplast < adcValues.size()) && (adcValues[tmplast] >= threshold) && (!lastJump)) { // jump check: - if (tmplast != maxindex) { // neighbor to maxindex can share peak with maxindex - if (data[tmplast] >= prevLast) { + if (tmplast != indexMaxADC) { // neighbor to maxindex can share peak with maxindex + if (adcValues[tmplast] >= prevLast) { lastJump = true; } } - prevLast = data[tmplast]; + prevLast = adcValues[tmplast]; tmplast++; } @@ -93,7 +131,7 @@ std::tuple<int, int> CaloRawFitter::selectSubarray(const gsl::span<double> data, if (firstJump || tmpfirst < 0) { tmpfirst++; } - if (lastJump || tmplast >= data.size()) { + if (lastJump || tmplast >= adcValues.size()) { tmplast--; } @@ -103,14 +141,13 @@ std::tuple<int, int> CaloRawFitter::selectSubarray(const gsl::span<double> data, return std::make_tuple(first, last); } -std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitter::reverseAndSubtractPed(const Bunch& bunch, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2) const +std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitter::reverseAndSubtractPed(const Bunch& bunch) const { std::array<double, constants::EMCAL_MAXTIMEBINS> outarray; int length = bunch.getBunchLength(); - const std::vector<uint16_t>& sig = bunch.getADC(); + const gsl::span<const uint16_t> sig(bunch.getADC()); - double ped = evaluatePedestal(sig, length); + double ped = mIsZerosupressed ? 0. : evaluatePedestal(sig, length); for (int i = 0; i < length; i++) { outarray[i] = sig[length - i - 1] - ped; @@ -119,96 +156,84 @@ std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitte return std::make_tuple(ped, outarray); } -float CaloRawFitter::evaluatePedestal(const std::vector<uint16_t>& data, std::optional<int> length) const +double CaloRawFitter::evaluatePedestal(const gsl::span<const uint16_t> data, std::optional<int> length) const { - double tmp = 0; - - if (mIsZerosupressed == false) { - for (int i = 0; i < mNsamplePed; i++) { - tmp += data[i]; - } + if (!mNsamplePed) { + throw RawFitterError_t::SAMPLE_UNINITIALIZED; } - - return tmp / mNsamplePed; + return static_cast<double>(std::accumulate(data.begin(), data.begin() + mNsamplePed, 0)) / mNsamplePed; } -short CaloRawFitter::maxAmp(const Bunch& bunch, int& maxindex) const +std::tuple<short, int> CaloRawFitter::getMaxAmplitudeBunch(const Bunch& bunch) const { - short tmpmax = -1; - int tmpindex = -1; + short maxADC = -1; + int maxIndex = -1; const std::vector<uint16_t>& sig = bunch.getADC(); for (int i = 0; i < bunch.getBunchLength(); i++) { - if (sig[i] > tmpmax) { - tmpmax = sig[i]; - tmpindex = i; + if (sig[i] > maxADC) { + maxADC = sig[i]; + maxIndex = i; } } - if (maxindex != 0) { - maxindex = bunch.getBunchLength() - 1 - tmpindex + bunch.getStartTime(); - } - - return tmpmax; + return std::make_tuple(maxADC, bunch.getBunchLength() - 1 - maxIndex + bunch.getStartTime()); } -bool CaloRawFitter::checkBunchEdgesForMax(const Bunch& bunch) const +bool CaloRawFitter::isMaxADCBunchEdge(const Bunch& bunch) const { - short tmpmax = -1; - int tmpindex = -1; + short maxADC = -1; + int indexMax = -1; const std::vector<uint16_t>& sig = bunch.getADC(); for (int i = 0; i < bunch.getBunchLength(); i++) { - if (sig[i] > tmpmax) { - tmpmax = sig[i]; - tmpindex = i; + if (sig[i] > maxADC) { + maxADC = sig[i]; + indexMax = i; } } - bool bunchOK = true; - if (tmpindex == 0 || tmpindex == (bunch.getBunchLength() - 1)) { - bunchOK = false; + bool isBunchEdge = false; + if (indexMax == 0 || indexMax == (bunch.getBunchLength() - 1)) { + isBunchEdge = true; } - return bunchOK; + return isBunchEdge; } -std::tuple<short, short, short> CaloRawFitter::selectBunch(const std::vector<Bunch>& bunchvector) +std::tuple<short, short, short> CaloRawFitter::selectMaximumBunch(const gsl::span<const Bunch>& bunchvector) { short bunchindex = -1; - short maxall = -1; - int indx = -1; - short maxampbin(0), maxamplitude(0); + short indexMaxInBunch(0), maxADCallBunches(-1); for (unsigned int i = 0; i < bunchvector.size(); i++) { - short max = maxAmp(bunchvector.at(i), indx); // CRAP PTH, bug fix, trouble if more than one bunches - if (isInTimeRange(indx, mMaxTimeIndex, mMinTimeIndex)) { - if (max > maxall) { - maxall = max; + auto [maxADC, maxIndex] = getMaxAmplitudeBunch(bunchvector[i]); // CRAP PTH, bug fix, trouble if more than one bunches + if (isInTimeRange(maxIndex, mMaxTimeIndex, mMinTimeIndex)) { + if (maxADC > maxADCallBunches) { bunchindex = i; - maxampbin = indx; - maxamplitude = max; + indexMaxInBunch = maxIndex; + maxADCallBunches = maxADC; } } } if (bunchindex >= 0) { - bool bunchOK = checkBunchEdgesForMax(bunchvector.at(bunchindex)); - if (!bunchOK) { - bunchindex = -1; + // reject bunch if the max. ADC value is at the edges of a bunch + if (isMaxADCBunchEdge(bunchvector[bunchindex])) { + throw RawFitterError_t::BUNCH_NOT_OK; } } - return std::make_tuple(bunchindex, maxampbin, maxamplitude); + return std::make_tuple(bunchindex, indexMaxInBunch, maxADCallBunches); } -bool CaloRawFitter::isInTimeRange(int maxindex, int maxtindx, int mintindx) const +bool CaloRawFitter::isInTimeRange(int indexMaxADC, int maxtime, int mintime) const { - if ((mintindx < 0 && maxtindx < 0) || maxtindx < 0) { + if ((mintime < 0 && maxtime < 0) || maxtime < 0) { return true; } - return (maxindex < maxtindx) && (maxindex > mintindx) ? true : false; + return (indexMaxADC < maxtime) && (indexMaxADC > mintime) ? true : false; } double CaloRawFitter::calculateChi2(double amp, double time, @@ -217,7 +242,7 @@ double CaloRawFitter::calculateChi2(double amp, double time, { if (first == last || first < 0) { // signal consists of single sample, chi2 estimate (0) not too well defined.. // or, first is negative, the indices are not valid - return -1; + throw RawFitterError_t::CHI2_ERROR; } int nsamples = last - first + 1; @@ -243,50 +268,61 @@ double CaloRawFitter::calculateChi2(double amp, double time, return chi2; } -std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFitEvaluateSamples(const std::vector<Bunch>& bunchvector, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2, int acut) +std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFitEvaluateSamples(const gsl::span<const Bunch> bunchvector, int adcThreshold) { - float maxf(0), ped(0); - int nsamples(0), first(0), last(0); - short maxrev(0); + int nsamples(0), first(0), last(0), indexMaxADCRReveresed(0); + double peakADC(0.), pedestal(0.); + + // Reset buffer for reversed bunch, no matter whether the bunch could be selected or not + mReversed.fill(0); // select the bunch with the highest amplitude unless any time constraints is set - auto [index, maxampindex, maxamp] = selectBunch(bunchvector); + auto [bunchindex, indexMaxADC, adcMAX] = selectMaximumBunch(bunchvector); // something valid was found, and non-zero amplitude - if (index >= 0 && maxamp >= acut) { - // use more convenient numbering and possibly subtract pedestal + if (bunchindex >= 0) { + if (adcMAX >= adcThreshold) { + // use more convenient numbering and possibly subtract pedestal - //std::tie(ped, mReversed) = reverseAndSubtractPed((bunchvector.at(index)), altrocfg1, altrocfg2); - //maxf = (float)*std::max_element(mReversed.begin(), mReversed.end()); + //std::tie(ped, mReversed) = reverseAndSubtractPed((bunchvector.at(index)), altrocfg1, altrocfg2); + //maxf = (float)*std::max_element(mReversed.begin(), mReversed.end()); - int length = bunchvector.at(index).getBunchLength(); - const std::vector<uint16_t>& sig = bunchvector.at(index).getADC(); + int bunchlength = bunchvector[bunchindex].getBunchLength(); + const std::vector<uint16_t>& sig = bunchvector[bunchindex].getADC(); - ped = evaluatePedestal(sig, length); + if (!mIsZerosupressed) { + pedestal = evaluatePedestal(sig, bunchlength); + } - for (int i = 0; i < length; i++) { - mReversed[i] = sig[length - i - 1] - ped; - if (maxf < mReversed[i]) { - maxf = mReversed[i]; + int testindexReverse = -1; + for (int i = 0; i < bunchlength; i++) { + mReversed[i] = sig[bunchlength - i - 1] - pedestal; + if (mReversed[i] > peakADC) { + peakADC = mReversed[i]; + testindexReverse = i; + } } - } - if (maxf >= acut) // possibly significant signal - { - // select array around max to possibly be used in fit - maxrev = maxampindex - bunchvector.at(index).getStartTime(); - std::tie(first, last) = selectSubarray(gsl::span<double>(&mReversed[0], bunchvector.at(index).getBunchLength()), maxrev, acut); - - // sanity check: maximum should not be in first or last bin - // if we should do a fit - if (first != maxrev && last != maxrev) { - // calculate how many samples we have - nsamples = last - first + 1; + if (peakADC >= adcThreshold) // possibly significant signal + { + // select array around max to possibly be used in fit + indexMaxADCRReveresed = indexMaxADC - bunchvector[bunchindex].getStartTime(); + std::tie(first, last) = findPeakRegion(gsl::span<double>(&mReversed[0], bunchvector[bunchindex].getBunchLength()), indexMaxADCRReveresed, adcThreshold); + + // sanity check: maximum should not be in first or last bin + // if we should do a fit + if (first != indexMaxADCRReveresed && last != indexMaxADCRReveresed) { + // calculate how many samples we have + nsamples = last - first + 1; + } } + } else { + throw RawFitterError_t::LOW_SIGNAL; } + } else { + throw RawFitterError_t::BUNCH_NOT_OK; } - return std::make_tuple(nsamples, index, maxf, maxamp, maxrev, ped, first, last); + return std::make_tuple(nsamples, bunchindex, peakADC, adcMAX, indexMaxADCRReveresed, pedestal, first, last); } diff --git a/Detectors/EMCAL/reconstruction/src/CaloRawFitterGamma2.cxx b/Detectors/EMCAL/reconstruction/src/CaloRawFitterGamma2.cxx old mode 100755 new mode 100644 index 9fce37c26a2a6..f3d8aaafdd262 --- a/Detectors/EMCAL/reconstruction/src/CaloRawFitterGamma2.cxx +++ b/Detectors/EMCAL/reconstruction/src/CaloRawFitterGamma2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ /// \author Martin Poghosyan (Martin.Poghosyan@cern.ch) #include "FairLogger.h" +#include <cfloat> #include <random> // ROOT sytem @@ -30,8 +32,7 @@ CaloRawFitterGamma2::CaloRawFitterGamma2() : CaloRawFitter("Chi Square ( Gamma2 mAlgo = FitAlgorithm::Gamma2; } -CaloFitResults CaloRawFitterGamma2::evaluate(const std::vector<Bunch>& bunchlist, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2) +CaloFitResults CaloRawFitterGamma2::evaluate(const gsl::span<const Bunch> bunchlist) { float time = 0; float amp = 0; @@ -40,19 +41,22 @@ CaloFitResults CaloRawFitterGamma2::evaluate(const std::vector<Bunch>& bunchlist bool fitDone = false; auto [nsamples, bunchIndex, ampEstimate, - maxADC, timeEstimate, pedEstimate, first, last] = preFitEvaluateSamples(bunchlist, altrocfg1, altrocfg2, mAmpCut); + maxADC, timeEstimate, pedEstimate, first, last] = preFitEvaluateSamples(bunchlist, mAmpCut); - if (ampEstimate >= mAmpCut) { + if (bunchIndex >= 0 && ampEstimate >= mAmpCut) { time = timeEstimate; - int timebinOffset = bunchlist.at(bunchIndex).getStartTime() - (bunchlist.at(bunchIndex).getBunchLength() - 1); + int timebinOffset = bunchlist[bunchIndex].getStartTime() - (bunchlist[bunchIndex].getBunchLength() - 1); amp = ampEstimate; if (nsamples > 2 && maxADC < constants::OVERFLOWCUT) { std::tie(amp, time) = doParabolaFit(timeEstimate - 1); mNiter = 0; - std::tie(chi2, fitDone) = doFit_1peak(first, nsamples, amp, time); - - if (!fitDone) { + try { + chi2 = doFit_1peak(first, nsamples, amp, time); + fitDone = true; + } catch (RawFitterError_t& e) { + // Fit has failed, set values to estimates + // TODO: Check whether we want to include cases in which the peak fit failed amp = ampEstimate; time = timeEstimate; chi2 = 1.e9; @@ -85,20 +89,21 @@ CaloFitResults CaloRawFitterGamma2::evaluate(const std::vector<Bunch>& bunchlist return CaloFitResults(maxADC, pedEstimate, mAlgo, amp, time, (int)time, chi2, ndf); } - return CaloFitResults(-1, -1); + // Fit failed, rethrow error + throw RawFitterError_t::FIT_ERROR; } -std::tuple<float, bool> CaloRawFitterGamma2::doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time) +float CaloRawFitterGamma2::doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time) { float chi2(0.); // fit using gamma-2 function (ORDER =2 assumed) if (nSamples < 3) { - return std::make_tuple(chi2, false); + throw RawFitterError_t::FIT_ERROR; } if (mNiter > mNiterationsMax) { - return std::make_tuple(chi2, false); + throw RawFitterError_t::FIT_ERROR; } double D, dA, dt; @@ -136,7 +141,7 @@ std::tuple<float, bool> CaloRawFitterGamma2::doFit_1peak(int firstTimeBin, int n D = c11 * c22 - c12 * c21; if (TMath::Abs(D) < DBL_EPSILON) { - return std::make_tuple(chi2, false); + throw RawFitterError_t::FIT_ERROR; } dt = (d1 * c22 - d2 * c12) / D * constants::TAU; @@ -145,13 +150,11 @@ std::tuple<float, bool> CaloRawFitterGamma2::doFit_1peak(int firstTimeBin, int n time += dt; ampl += dA; - bool res = true; - if (TMath::Abs(dA) > 1 || TMath::Abs(dt) > 0.01) { - std::tie(chi2, res) = doFit_1peak(firstTimeBin, nSamples, ampl, time); + chi2 = doFit_1peak(firstTimeBin, nSamples, ampl, time); } - return std::make_tuple(chi2, res); + return chi2; } std::tuple<float, float> CaloRawFitterGamma2::doParabolaFit(int maxTimeBin) const @@ -163,7 +166,7 @@ std::tuple<float, float> CaloRawFitterGamma2::doParabolaFit(int maxTimeBin) cons double a = (getReversed(maxTimeBin + 2) + getReversed(maxTimeBin) - 2. * getReversed(maxTimeBin + 1)) / 2.; - if (TMath::Abs(a) < 1.e09) { + if (TMath::Abs(a) < DBL_EPSILON) { amp = getReversed(maxTimeBin + 1); time = maxTimeBin + 1; return std::make_tuple(amp, time); diff --git a/Detectors/EMCAL/reconstruction/src/CaloRawFitterStandard.cxx b/Detectors/EMCAL/reconstruction/src/CaloRawFitterStandard.cxx index 102185633b6de..ebfb88f897f3d 100644 --- a/Detectors/EMCAL/reconstruction/src/CaloRawFitterStandard.cxx +++ b/Detectors/EMCAL/reconstruction/src/CaloRawFitterStandard.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,10 +50,8 @@ double CaloRawFitterStandard::rawResponseFunction(double* x, double* par) return signal; } -CaloFitResults CaloRawFitterStandard::evaluate(const std::vector<Bunch>& bunchlist, - std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2) +CaloFitResults CaloRawFitterStandard::evaluate(const gsl::span<const Bunch> bunchlist) { - float time = 0; float amp = 0; float chi2 = 0; @@ -60,18 +59,22 @@ CaloFitResults CaloRawFitterStandard::evaluate(const std::vector<Bunch>& bunchli bool fitDone = kFALSE; auto [nsamples, bunchIndex, ampEstimate, - maxADC, timeEstimate, pedEstimate, first, last] = preFitEvaluateSamples(bunchlist, altrocfg1, altrocfg2, mAmpCut); + maxADC, timeEstimate, pedEstimate, first, last] = preFitEvaluateSamples(bunchlist, mAmpCut); - if (ampEstimate >= mAmpCut) { + if (bunchIndex >= 0 && ampEstimate >= mAmpCut) { time = timeEstimate; - int timebinOffset = bunchlist.at(bunchIndex).getStartTime() - (bunchlist.at(bunchIndex).getBunchLength() - 1); + int timebinOffset = bunchlist[bunchIndex].getStartTime() - (bunchlist[bunchIndex].getBunchLength() - 1); amp = ampEstimate; if (nsamples > 1 && maxADC < constants::OVERFLOWCUT) { - std::tie(amp, time, chi2, fitDone) = fitRaw(first, last); - time += timebinOffset; - timeEstimate += timebinOffset; - ndf = nsamples - 2; + try { + std::tie(amp, time, chi2) = fitRaw(first, last); + time += timebinOffset; + timeEstimate += timebinOffset; + ndf = nsamples - 2; + fitDone = true; + } catch (RawFitterError_t& error) { + } } } if (fitDone) { @@ -95,19 +98,17 @@ CaloFitResults CaloRawFitterStandard::evaluate(const std::vector<Bunch>& bunchli return CaloFitResults(maxADC, pedEstimate, mAlgo, amp, time, (int)time, chi2, ndf); } - return CaloFitResults(-1, -1); + throw RawFitterError_t::FIT_ERROR; } -std::tuple<float, float, float, bool> CaloRawFitterStandard::fitRaw(int firstTimeBin, int lastTimeBin) const +std::tuple<float, float, float> CaloRawFitterStandard::fitRaw(int firstTimeBin, int lastTimeBin) const { float amp(0), time(0), chi2(0); - bool fitDone(false); int nsamples = lastTimeBin - firstTimeBin + 1; - fitDone = kFALSE; if (nsamples < 3) { - return std::make_tuple(amp, time, chi2, fitDone); + throw RawFitterError_t::FIT_ERROR; } TGraph gSig(nsamples); @@ -134,10 +135,9 @@ std::tuple<float, float, float, bool> CaloRawFitterStandard::fitRaw(int firstTim amp = signalF.GetParameter(0); time = signalF.GetParameter(1); chi2 = signalF.GetChisquare(); - fitDone = kTRUE; } else { - fitDone = kFALSE; + throw RawFitterError_t::FIT_ERROR; } - return std::make_tuple(amp, time, chi2, fitDone); + return std::make_tuple(amp, time, chi2); } diff --git a/Detectors/EMCAL/reconstruction/src/Channel.cxx b/Detectors/EMCAL/reconstruction/src/Channel.cxx index bdd79ee9d39b5..cf9886fb7c757 100644 --- a/Detectors/EMCAL/reconstruction/src/Channel.cxx +++ b/Detectors/EMCAL/reconstruction/src/Channel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/Clusterizer.cxx b/Detectors/EMCAL/reconstruction/src/Clusterizer.cxx index 3a4d33d10555d..2816d954b7b5a 100644 --- a/Detectors/EMCAL/reconstruction/src/Clusterizer.cxx +++ b/Detectors/EMCAL/reconstruction/src/Clusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/ClusterizerParameters.cxx b/Detectors/EMCAL/reconstruction/src/ClusterizerParameters.cxx index 546b8d2170c7e..91284ebb71dc5 100644 --- a/Detectors/EMCAL/reconstruction/src/ClusterizerParameters.cxx +++ b/Detectors/EMCAL/reconstruction/src/ClusterizerParameters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/ClusterizerTask.cxx b/Detectors/EMCAL/reconstruction/src/ClusterizerTask.cxx index 6b5e8e2c56d7e..f5e4dadaebdfb 100644 --- a/Detectors/EMCAL/reconstruction/src/ClusterizerTask.cxx +++ b/Detectors/EMCAL/reconstruction/src/ClusterizerTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/DigitReader.cxx b/Detectors/EMCAL/reconstruction/src/DigitReader.cxx index 3db378c5b9d38..c03eb57cc8296 100644 --- a/Detectors/EMCAL/reconstruction/src/DigitReader.cxx +++ b/Detectors/EMCAL/reconstruction/src/DigitReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h b/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h index 3267e83f6d89f..bd41f789af02a 100644 --- a/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h +++ b/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/RawBuffer.cxx b/Detectors/EMCAL/reconstruction/src/RawBuffer.cxx index fd79bcfe088a4..c767e8cc25f4a 100644 --- a/Detectors/EMCAL/reconstruction/src/RawBuffer.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawBuffer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/RawHeaderStream.cxx b/Detectors/EMCAL/reconstruction/src/RawHeaderStream.cxx index dfecb6a4f02f5..a046656f3a67e 100644 --- a/Detectors/EMCAL/reconstruction/src/RawHeaderStream.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawHeaderStream.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/RawPayload.cxx b/Detectors/EMCAL/reconstruction/src/RawPayload.cxx index b28e49bf50bb2..80f3e0355e1f3 100644 --- a/Detectors/EMCAL/reconstruction/src/RawPayload.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawPayload.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx index dcce7d20298d0..c7c51f075e2ec 100644 --- a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ o2::header::RDHAny RawReaderMemory::decodeRawHeader(const void* payloadwords) } else if (headerversion == 6) { return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV6*>(payloadwords)); } - throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING); + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); } void RawReaderMemory::init() @@ -48,7 +49,6 @@ void RawReaderMemory::init() mRawHeaderInitialized = false; mPayloadInitialized = false; mRawBuffer.flush(); - mNumData = mRawMemoryBuffer.size() / 8192; // assume fixed 8 kB pages } void RawReaderMemory::next() @@ -85,7 +85,7 @@ void RawReaderMemory::next() void RawReaderMemory::nextPage(bool doResetPayload) { if (!hasNext()) { - throw RawDecodingError(RawDecodingError::ErrorType_t::PAGE_NOTFOUND); + throw RawDecodingError(RawDecodingError::ErrorType_t::PAGE_NOTFOUND, mCurrentFEE); } if (doResetPayload) { mRawPayload.reset(); @@ -95,36 +95,61 @@ void RawReaderMemory::nextPage(bool doResetPayload) // Read header try { mRawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); - RDHDecoder::printRDH(mRawHeader); + auto feeID = RDHDecoder::getFEEID(mRawHeader); + if (mCurrentFEE < 0 || mCurrentFEE != feeID) { + // update current FEE ID + mCurrentFEE = feeID; + } + //RDHDecoder::printRDH(mRawHeader); if (RDHDecoder::getOffsetToNext(mRawHeader) == RDHDecoder::getHeaderSize(mRawHeader)) { // No Payload - jump to next rawheader // This will eventually move, depending on whether for events without payload in the SRU we send the RCU trailer mCurrentPosition += RDHDecoder::getHeaderSize(mRawHeader); mRawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); - RDHDecoder::printRDH(mRawHeader); + feeID = RDHDecoder::getFEEID(mRawHeader); + if (mCurrentFEE < 0 || mCurrentFEE != feeID) { + // update current FEE ID + mCurrentFEE = feeID; + } + //RDHDecoder::printRDH(mRawHeader); } mRawHeaderInitialized = true; } catch (...) { - throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING); + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); } if (mCurrentPosition + RDHDecoder::getMemorySize(mRawHeader) > mRawMemoryBuffer.size()) { // Payload incomplete - throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_DECODING); + throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_DECODING, mCurrentFEE); + } else if (mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader) > mRawMemoryBuffer.size()) { + // Start position of the payload is outside the payload range + throw RawDecodingError(RawDecodingError::ErrorType_t::PAGE_START_INVALID, mCurrentFEE); } else { mRawBuffer.readFromMemoryBuffer(gsl::span<const char>(mRawMemoryBuffer.data() + mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader), RDHDecoder::getMemorySize(mRawHeader) - RDHDecoder::getHeaderSize(mRawHeader))); - // Read off and chop trailer + // Read off and chop trailer (if required) + // + // In case every page gets a trailer (intermediate format). The trailers from the single + // pages need to be removed. There will be a combined trailer which keeps the sum of the + // payloads for all trailers. This will be appended to the chopped payload. // - // Every page gets a trailer. The trailers from the single pages need to be removed. - // There will be a combined trailer which keeps the sum of the payloads for all trailers. - // This will be appended to the chopped payload. - auto trailer = RCUTrailer::constructFromPayloadWords(mRawBuffer.getDataWords()); - if (!mCurrentTrailer.isInitialized()) { - mCurrentTrailer = trailer; + // Trailer only at the last page (new format): Only last page gets trailer. The trailer is + // also chopped from the payload as it will be added later again. + auto lastword = *(mRawBuffer.getDataWords().rbegin()); + gsl::span<const uint32_t> payloadWithoutTrailer; + if (lastword >> 30 == 3) { + // lastword is a trailer word + // decode trailer and chop + auto trailer = RCUTrailer::constructFromPayloadWords(mRawBuffer.getDataWords()); + if (!mCurrentTrailer.isInitialized()) { + mCurrentTrailer = trailer; + } else { + mCurrentTrailer.setPayloadSize(mCurrentTrailer.getPayloadSize() + trailer.getPayloadSize()); + } + payloadWithoutTrailer = gsl::span<const uint32_t>(mRawBuffer.getDataWords().data(), mRawBuffer.getDataWords().size() - trailer.getTrailerSize()); } else { - mCurrentTrailer.setPayloadSize(mCurrentTrailer.getPayloadSize() + trailer.getPayloadSize()); + // Not a trailer word = copy page as it is + payloadWithoutTrailer = mRawBuffer.getDataWords(); // No trailer to be chopped } - gsl::span<const uint32_t> payloadWithoutTrailer(mRawBuffer.getDataWords().data(), mRawBuffer.getDataWords().size() - trailer.getTrailerSize()); mRawPayload.appendPayloadWords(payloadWithoutTrailer); mRawPayload.increasePageCount(); @@ -132,33 +157,10 @@ void RawReaderMemory::nextPage(bool doResetPayload) mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); /// Assume fixed 8 kB page size } -void RawReaderMemory::readPage(int page) -{ - int currentposition = 8192 * page; - if (currentposition >= mRawMemoryBuffer.size()) { - throw RawDecodingError(RawDecodingError::ErrorType_t::PAGE_NOTFOUND); - } - mRawHeaderInitialized = false; - mPayloadInitialized = false; - // Read header - try { - mRawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); - mRawHeaderInitialized = true; - } catch (...) { - throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING); - } - if (currentposition + RDHDecoder::getHeaderSize(mRawHeader) + RDHDecoder::getMemorySize(mRawHeader) >= mRawMemoryBuffer.size()) { - // Payload incomplete - throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_DECODING); - } else { - mRawBuffer.readFromMemoryBuffer(gsl::span<const char>(mRawMemoryBuffer.data() + currentposition + RDHDecoder::getHeaderSize(mRawHeader), RDHDecoder::getMemorySize(mRawHeader))); - } -} - const o2::header::RDHAny& RawReaderMemory::getRawHeader() const { if (!mRawHeaderInitialized) { - throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_INVALID); + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_INVALID, mCurrentFEE); } return mRawHeader; } @@ -166,7 +168,7 @@ const o2::header::RDHAny& RawReaderMemory::getRawHeader() const const RawBuffer& RawReaderMemory::getRawBuffer() const { if (!mPayloadInitialized) { - throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_INVALID); + throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_INVALID, mCurrentFEE); } return mRawBuffer; } diff --git a/Detectors/EMCAL/simulation/CMakeLists.txt b/Detectors/EMCAL/simulation/CMakeLists.txt index 6149eeda5bda5..9b49be71b10a9 100644 --- a/Detectors/EMCAL/simulation/CMakeLists.txt +++ b/Detectors/EMCAL/simulation/CMakeLists.txt @@ -1,23 +1,25 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EMCALSimulation - SOURCES src/Detector.cxx src/Digitizer.cxx src/DigitizerTask.cxx - src/SpaceFrame.cxx src/SimParam.cxx src/LabeledDigit.cxx - src/RawWriter.cxx + SOURCES src/Detector.cxx src/Digitizer.cxx src/SDigitizer.cxx + src/DigitsWriteoutBuffer.cxx src/SpaceFrame.cxx src/SimParam.cxx + src/LabeledDigit.cxx src/RawWriter.cxx PUBLIC_LINK_LIBRARIES O2::EMCALBase O2::DetectorsBase O2::SimConfig O2::SimulationDataFormat O2::Headers O2::DetectorsRaw) o2_target_root_dictionary(EMCALSimulation HEADERS include/EMCALSimulation/Detector.h include/EMCALSimulation/Digitizer.h - include/EMCALSimulation/DigitizerTask.h + include/EMCALSimulation/SDigitizer.h + include/EMCALSimulation/DigitsWriteoutBuffer.h include/EMCALSimulation/RawWriter.h include/EMCALSimulation/SpaceFrame.h include/EMCALSimulation/SimParam.h diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/Detector.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/Detector.h index a7fb3649ac572..1553c4b559019 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/Detector.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/Digitizer.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/Digitizer.h index 943be4819d5ef..355dae64a7769 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/Digitizer.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/Digitizer.h @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef ALICEO2_EMCAL_DIGITIZER_H -#define ALICEO2_EMCAL_DIGITIZER_H +#ifndef ALICEO2_EMCAL_FEEDIGITIZER_H +#define ALICEO2_EMCAL_FEEDIGITIZER_H #include <memory> #include <unordered_map> @@ -21,11 +22,10 @@ #include "TRandom3.h" #include "DataFormatsEMCAL/Digit.h" -#include "EMCALBase/Geometry.h" -#include "EMCALBase/GeometryBase.h" #include "EMCALBase/Hit.h" #include "EMCALSimulation/SimParam.h" #include "EMCALSimulation/LabeledDigit.h" +#include "EMCALSimulation/DigitsWriteoutBuffer.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -38,6 +38,8 @@ namespace emcal /// \brief EMCAL FEE digitizer /// \ingroup EMCALsimulation /// \author Anders Knospe, University of Houston +/// \author Hadi Hassan, ORNL +/// @TODO adapt it to digitize TRU digits class Digitizer : public TObject { public: @@ -52,17 +54,14 @@ class Digitizer : public TObject void finish(); /// Steer conversion of hits to digits - void process(const std::vector<Hit>& hits); + void process(const std::vector<LabeledDigit>& labeledDigit); void setEventTime(double t); double getTriggerTime() const { return mTriggerTime; } double getEventTime() const { return mEventTime; } - bool isLive(double t) const { return (t < mLiveTime); } + bool isLive(double t) const { return (t - mTriggerTime < mLiveTime); } bool isLive() const { return (mEventTime < mLiveTime); } - void setContinuous(bool v) { mContinuous = v; } - bool isContinuous() const { return mContinuous; } - bool isEmpty() const { return mEmpty; } void fillOutputContainer(std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::emcal::MCLabel>& labels); @@ -77,31 +76,19 @@ class Digitizer : public TObject void setCoeffToNanoSecond(double cf) { mCoeffToNanoSecond = cf; } double getCoeffToNanoSecond() const { return mCoeffToNanoSecond; } - void setCurrSrcID(int v); - int getCurrSrcID() const { return mCurrSrcID; } - - void setCurrEvID(int v); - int getCurrEvID() const { return mCurrEvID; } - - void setGeometry(const o2::emcal::Geometry* gm) { mGeometry = gm; } - - void hitToDigits(const Hit& hit); + void sampleSDigit(const Digit& sdigit); static double rawResponseFunction(double* x, double* par); /// raw pointers used here to allow interface with TF1 private: - const Geometry* mGeometry = nullptr; ///< EMCAL geometry double mTriggerTime = -1e20; ///< global trigger time double mEventTime = 0; ///< global event time short mEventTimeOffset = 0; ///< event time difference from trigger time (in number of bins) short mPhase = 0; ///< event phase double mCoeffToNanoSecond = 1.0; ///< coefficient to convert event time (Fair) to ns - bool mContinuous = false; ///< flag for continuous simulation UInt_t mROFrameMin = 0; ///< lowest RO frame of current digits UInt_t mROFrameMax = 0; ///< highest RO frame of current digits - int mCurrSrcID = 0; ///< current MC source from the manager - int mCurrEvID = 0; ///< current event ID from the manager bool mSmearEnergy = true; ///< do time and energy smearing bool mSimulateTimeResponse = true; ///< simulate time response bool mRemoveDigitsBelowThreshold = true; ///< remove digits below threshold @@ -109,12 +96,12 @@ class Digitizer : public TObject const SimParam* mSimParam = nullptr; ///< SimParam object bool mEmpty = true; ///< Digitizer contains no digits/labels - std::vector<Digit> mTempDigitVector; ///< temporary digit storage - std::unordered_map<Int_t, std::list<LabeledDigit>> mDigits; ///< used to sort digits and labels by tower + std::vector<Digit> mTempDigitVector; ///< temporary digit storage + std::unordered_map<Int_t, std::list<LabeledDigit>> mDigits; ///< used to sort digits and labels by tower - TRandom3* mRandomGenerator = nullptr; // random number generator - std::vector<int> mTimeBinOffset; // offset of first time bin - std::vector<std::vector<double>> mAmplitudeInTimeBins; // amplitude of signal for each time bin + TRandom3* mRandomGenerator = nullptr; // random number generator + std::vector<int> mTimeBinOffset; // offset of first time bin + std::vector<std::vector<double>> mAmplitudeInTimeBins; // amplitude of signal for each time bin float mLiveTime = 1500; // EMCal live time (ns) float mBusyTime = 35000; // EMCal busy time (ns) @@ -125,4 +112,4 @@ class Digitizer : public TObject } // namespace emcal } // namespace o2 -#endif /* ALICEO2_EMCAL_DIGITIZER_H */ +#endif /* ALICEO2_EMCAL_FEEDIGITIZER_H */ diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitizerTask.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitizerTask.h deleted file mode 100644 index 52f0d875a3d6e..0000000000000 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitizerTask.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_EMCAL_DIGITIZERTASK_H -#define ALICEO2_EMCAL_DIGITIZERTASK_H - -#include <cstdio> -#include "FairTask.h" // for FairTask, InitStatus -#include "Rtypes.h" // for DigitizerTask::Class, ClassDef, etc - -#include "EMCALBase/Hit.h" -#include "EMCALSimulation/Digitizer.h" - -namespace o2 -{ -namespace emcal -{ - -/// \class DigitizerTask -/// \brief FairTask running EMCAL digitization -/// \ingroup EMCALsimulation -/// \author Anders Knospe, University of Houston -class DigitizerTask : public FairTask -{ - public: - DigitizerTask(); - ~DigitizerTask() override; - - InitStatus Init() override; - - void Exec(Option_t* option) override; - void FinishTask() override; - - Digitizer& getDigitizer() { return mDigitizer; } - - void setFairTimeUnitInNS(double tinNS) { mFairTimeUnitInNS = tinNS < 1. ? 1. : tinNS; } - double getFairTimeUnitInNS() const { return mFairTimeUnitInNS; } - - private: - double mFairTimeUnitInNS = 1; ///< Fair time unit in ns - Int_t mSourceID = 0; ///< current source - Int_t mEventID = 0; ///< current event id from the source - Digitizer mDigitizer; ///< Digitizer - const std::vector<Hit>* mHitsArray = nullptr; ///< Array of MC hits - std::vector<Digit>* mDigitsArray = nullptr; ///< Array of digits - - ClassDefOverride(DigitizerTask, 1); -}; -} // namespace emcal -} // namespace o2 - -#endif /* ALICEO2_EMCAL_DIGITIZERTASK_H */ diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitsWriteoutBuffer.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitsWriteoutBuffer.h new file mode 100644 index 0000000000000..692da3f9c4550 --- /dev/null +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/DigitsWriteoutBuffer.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_DIGITSWRITEOUTBUFFER_H_ +#define ALICEO2_EMCAL_DIGITSWRITEOUTBUFFER_H_ + +#include <memory> +#include <unordered_map> +#include <vector> +#include <deque> +#include <list> +#include <gsl/span> +#include "DataFormatsEMCAL/Digit.h" +#include "EMCALSimulation/LabeledDigit.h" + +namespace o2 +{ +namespace emcal +{ + +/// \class DigitsWriteoutBuffer +/// \brief Container class for time sampled digits +/// \ingroup EMCALsimulation +/// \author Hadi Hassan, ORNL +/// \author Markus Fasel, ORNL +/// \date 08/03/2021 + +class DigitsWriteoutBuffer +{ + public: + /// Default constructor + DigitsWriteoutBuffer(unsigned int nTimeBins = 30, unsigned int binWidth = 100); + + /// Destructor + ~DigitsWriteoutBuffer() = default; + + /// clear the container + void clear(); + + /// Add digit to the container + /// \param towerID Cell ID + /// \param dig Labaled digit to add + /// \param eventTime The time of the event (w.r.t Tigger time) + void addDigit(unsigned int towerID, LabeledDigit dig, double eventTime); + + /// Getter for the last N entries (time samples) in the ring buffer + /// \param nsample number of entries to be written + /// \return Vector of map of cell IDs and labeled digits in that cell + gsl::span<std::unordered_map<int, std::list<LabeledDigit>>> getLastNSamples(int nsample = 15); + + /// Forwards the marker to the next time sample every mTimeBinWidth + void forwardMarker(double eventTime); + + void setNumberReadoutSamples(unsigned int nsamples) { mNumberReadoutSamples = nsamples; } + + /// Getter for current position in the ring buffer + /// \return current position + std::tuple<double, int> getCurrentTimeAndPosition() const { return std::make_tuple(mMarker.mReferenceTime, mMarker.mPositionInBuffer - mTimedDigits.begin()); } + + private: + struct Marker { + double mReferenceTime; + std::deque<std::unordered_map<int, std::list<LabeledDigit>>>::iterator mPositionInBuffer; + }; + + unsigned int mBufferSize = 30; ///< The size of the buffer, it has to be at least 2 times the size of the readout cycle + unsigned int mTimeBinWidth = 100; ///< The size of the time bin (ns) + unsigned int mNumberReadoutSamples = 15; ///< The number of smaples in a readout window + Marker mMarker; ///< Marker for the current time sample + std::deque<std::unordered_map<int, std::list<LabeledDigit>>> mTimedDigits; ///< Container for time sampled digits per tower ID + + ClassDefNV(DigitsWriteoutBuffer, 1); +}; + +} // namespace emcal + +} // namespace o2 + +#endif /* ALICEO2_EMCAL_DIGITSWRITEOUTBUFFER_H_ */ diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/LabeledDigit.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/LabeledDigit.h index c53cd2aeeb1d5..05939f8dc3c3c 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/LabeledDigit.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/LabeledDigit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index 1ba5f43562e16..1df607dc957dd 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include <gsl/span> #include <array> +#include <cstdint> #include <fstream> #include <memory> #include <string> @@ -35,35 +37,45 @@ namespace emcal class Geometry; +/// \struct AltroBunch +/// \brief ALTRO bunch information obtained from digits struct AltroBunch { - int mStarttime; - std::vector<int> mADCs; + int mStarttime; ///< Start time of the bunch + std::vector<int> mADCs; ///< ADCs belonging to the bunch }; +/// \struct ChannelData +/// \brief Structure for mapping digits to Channels within a SRU struct ChannelData { - int mRow; - int mCol; - std::vector<o2::emcal::Digit*> mDigits; + int mRow; ///< Row of the channel + int mCol; ///< Column of the channel + std::vector<o2::emcal::Digit*> mDigits; ///< Digits for the channel within the current event }; +/// \struct SRUDigitContainer +/// \brief Structure for organizing digits within the SRU struct SRUDigitContainer { - int mSRUid; - std::map<int, ChannelData> mChannels; + int mSRUid; ///< DDL of the SRU + std::map<int, ChannelData> mChannels; ///< Containers for channels within the SRU }; +/// \union ChannelHeader +/// \brief Bitfield encoding channel headers union ChannelHeader { - uint32_t mDataWord; + uint32_t mDataWord; ///< Full data word representation struct { uint32_t mHardwareAddress : 16; ///< Bits 0 - 15: Hardware address uint32_t mPayloadSize : 10; ///< Bits 16 - 25: Payload size uint32_t mZero1 : 3; ///< Bits 26 - 28: zeroed uint32_t mBadChannel : 1; ///< Bit 29: Bad channel status - uint32_t mZero2 : 2; ///< Bits 30 - 31: zeroed + uint32_t mHeaderBits : 2; ///< Bits 30 - 31: channel header bits (1) }; }; +/// \union CaloBunchWord +/// \brief Encoding of ALTRO words (32 bit consisting of 3 10-bit words) union CaloBunchWord { - uint32_t mDataWord; + uint32_t mDataWord; ///< Full data word representation struct { uint32_t mWord2 : 10; ///< Bits 0 - 9 : Word 2 uint32_t mWord1 : 10; ///< Bits 10 - 19 : Word 1 @@ -72,29 +84,87 @@ union CaloBunchWord { }; }; +/// \class RawWriter +/// \brief Raw data creator for EMCAL raw data based on EMCAL digits +/// \ingroup EMCALsimulation +/// \author Markus Fasel <markus.fasel@cern.ch>, Oak Ridge National Laboratory +/// \author Hadi Hassan, Oak Ridge National Laboratory +/// \since Jan 24, 2020 class RawWriter { public: + /// \enum FileFor_t + /// \brief Definition of the granularity of the raw files enum class FileFor_t { - kFullDet, - kSubDet, - kLink + kFullDet, ///< Full detector (EMCAL + DCAL) + kSubDet, ///< Subdetector (EMCAL/DCAL separate) + kLink ///< Per link }; + + /// \brief Dummy constructor RawWriter() = default; + + /// \brief Constructor, defining output location + /// \param outputdir Output directiory + /// + /// Initializing the output directory. The output files + /// can be found in the output directory with the granularity + /// defined via setFileFor RawWriter(const char* outputdir) { setOutputLocation(outputdir); } + + /// \brief Destructor ~RawWriter() = default; + /// \brief Get access to underlying RawFileWriter + /// \return RawFileWriter o2::raw::RawFileWriter& getWriter() const { return *mRawWriter; } void setOutputLocation(const char* outputdir) { mOutputLocation = outputdir; } void setDigits(gsl::span<o2::emcal::Digit> digits) { mDigits = digits; } + + /// \brief Set the granularity of the output file + /// \param filefor Output granularity + /// + /// Output files can be created for + /// - Whole EMCAL + /// - Subdetector (EMCAL or DCAL) + /// - Link void setFileFor(FileFor_t filefor) { mFileFor = filefor; } + + /// \brief Set the number of ADC samples in the readout window + /// \param nsapmles Number of time samples void setNumberOfADCSamples(int nsamples) { mNADCSamples = nsamples; } + + /// \brief Set min. ADC samples expected in a calo bunch + /// \param nsamples Minimum number of ADC samples + void setMinADCSamplesBunch(int nsamples) { mMinADCBunch = nsamples; } + + /// \brief Set pedestal threshold used to accept ADC values when creating the bunches + /// \param pedestal Pedestal value void setPedestal(int pedestal) { mPedestal = pedestal; } + + /// \brief Set the geometry parameters + /// \param geo EMCAL geometry void setGeometry(o2::emcal::Geometry* geo) { mGeometry = geo; } void init(); + + /// \brief Converting digits from a full timeframe to raw pages + /// \param digits Vector of digits belonging to the same timeframe + /// \param triggers trigger records with ranges in digits container of data for the various events in the timeframe + /// + /// Processing all events from within a timeframe. See processTrigger for more information + /// about the digit to raw converion of a single event. void digitsToRaw(gsl::span<o2::emcal::Digit> digits, gsl::span<o2::emcal::TriggerRecord> triggers); + + /// \brief Processing digits to raw conversion for the digits from the current event + /// \param trg Trigger record providing collision information and data range for the current event + /// + /// Digits are first sorted according to SRUs and within their channels and time samples. + /// For each SRU and channel within the SRU calo bunches are created. In case at least one + /// valid calo bunch is found channels are created, and they data words are organized in a + /// raw stream, which is closed by the RCU trailer of the given stream. The content of the + /// stream is then passed to the RawFileWriter for page splitting and output streaming. bool processTrigger(const o2::emcal::TriggerRecord& trg); int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, @@ -102,17 +172,47 @@ class RawWriter std::vector<char>& trailer, std::vector<char>& header) const; protected: + /// \brief Parse digits vector in channel and create ALTRO bunches + /// \param channelDigits Vector with digits in the channel for the current event + /// + /// Channels are parsed in a time-reversed order. Bunches are selected for ranges of + /// digits where the ADC value is consecutively above the pedestal. Only bunches having + /// a min. amount of ADC samples are selected. std::vector<AltroBunch> findBunches(const std::vector<o2::emcal::Digit*>& channelDigits); - std::tuple<int, int, int> getOnlineID(int towerID); - std::tuple<int, int> getLinkAssignment(int ddlID); + /// \brief Create channel header + /// \param hardwareAddress Hardware address + /// \param payloadSize Size of the payload of the channel in 10-bit ALTRO words + /// \param isBadChannel If true the channel is a bad channel at hardware level ChannelHeader createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel); - std::vector<char> createRCUTrailer(int payloadsize, int feca, int fecb, double timesample, double l1phase); + + /// \brief Creating RCU trailer + /// \param payloadsize Size of the payload as 32bit word + /// \param timesampe Length of the time sample (for L1 phase calculation) + /// \param triggertime Time of the trigger (for L1 phase calculation) + /// \param feeID Link ID + /// + /// Creating RCU trailer. Also setting the values of the ALTRO Config registers based + /// on the settings in the raw writer. The RCU trailer is then encoded and converted to + /// 8-bit words. + std::vector<char> createRCUTrailer(int payloadsize, double timesample, uint64_t triggertime, int feeID); + + /// \brief Encoding words of the ALTRO bunch into 32-bit words + /// \param data ALTRO bunch information + /// \return Encoded ALTRO words + /// + /// Converting ALTRO bunch into ALTRO words. For the ALTRO bunch the following structure is + /// expected: + /// - bunch size including bunch header size (2) + /// - start time + /// - ADC samples + /// The input data is converted to 10 but ALTRO words and put on the stream. std::vector<int> encodeBunchData(const std::vector<int>& data); private: int mNADCSamples = 15; ///< Number of time samples - int mPedestal = 0; ///< Pedestal + int mPedestal = 1; ///< Pedestal + int mMinADCBunch = 3; ///< Min. number of ADC samples in ALTRO bunch FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry std::string mOutputLocation; ///< Rawfile name diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/SDigitizer.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/SDigitizer.h new file mode 100644 index 0000000000000..09171cce5b976 --- /dev/null +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/SDigitizer.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_SDIGITIZER_H +#define ALICEO2_EMCAL_SDIGITIZER_H + +#include <memory> +#include <unordered_map> +#include <vector> +#include <list> + +#include "Rtypes.h" // for SDigitizer::Class, Double_t, ClassDef, etc +#include "TObject.h" // for TObject + +#include "DataFormatsEMCAL/Digit.h" +#include "EMCALBase/Geometry.h" +#include "EMCALBase/GeometryBase.h" +#include "EMCALBase/Hit.h" +#include "EMCALSimulation/LabeledDigit.h" + +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2 +{ +namespace emcal +{ + +/// \class SDigitizer +/// \brief EMCAL summed digitizer +/// \ingroup EMCALsimulation +/// \author Anders Knospe, University of Houston +/// \author Hadi Hassan, ORNL + +class SDigitizer +{ + public: + SDigitizer() = default; + ~SDigitizer() = default; + SDigitizer(const SDigitizer&) = delete; + SDigitizer& operator=(const SDigitizer&) = delete; + + /// Steer conversion of hits to digits + std::vector<o2::emcal::LabeledDigit> process(const std::vector<Hit>& hits); + + void setCurrSrcID(int v); + int getCurrSrcID() const { return mCurrSrcID; } + + void setCurrEvID(int v); + int getCurrEvID() const { return mCurrEvID; } + + void setGeometry(const o2::emcal::Geometry* gm) { mGeometry = gm; } + + private: + const Geometry* mGeometry = nullptr; ///< EMCAL geometry + int mCurrSrcID = 0; ///< current MC source from the manager + int mCurrEvID = 0; ///< current event ID from the manager + + ClassDefNV(SDigitizer, 1); +}; +} // namespace emcal +} // namespace o2 + +#endif /* ALICEO2_EMCAL_SDIGITIZER_H */ diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h index 2d24978328847..f3658472011f3 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/SpaceFrame.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/SpaceFrame.h index 9ddb94f4a0a91..2dd770295c992 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/SpaceFrame.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/SpaceFrame.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/src/Detector.cxx b/Detectors/EMCAL/simulation/src/Detector.cxx index 79c27568b7124..cbed97e335ee8 100644 --- a/Detectors/EMCAL/simulation/src/Detector.cxx +++ b/Detectors/EMCAL/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/src/Digitizer.cxx b/Detectors/EMCAL/simulation/src/Digitizer.cxx index a5592ca60054f..034a51994bbce 100644 --- a/Detectors/EMCAL/simulation/src/Digitizer.cxx +++ b/Detectors/EMCAL/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,13 +11,12 @@ #include "EMCALSimulation/Digitizer.h" #include "EMCALSimulation/SimParam.h" +#include "EMCALSimulation/DigitsWriteoutBuffer.h" #include "DataFormatsEMCAL/Digit.h" -#include "EMCALBase/Geometry.h" -#include "EMCALBase/GeometryBase.h" #include "EMCALBase/Hit.h" #include "MathUtils/Cartesian.h" #include "SimulationDataFormat/MCCompLabel.h" - +#include "EMCALSimulation/DigitsWriteoutBuffer.h" #include <climits> #include <forward_list> #include <chrono> @@ -106,29 +106,22 @@ void Digitizer::clear() } //_______________________________________________________________________ -void Digitizer::process(const std::vector<Hit>& hits) +void Digitizer::process(const std::vector<LabeledDigit>& labeledSDigits) { - for (auto hit : hits) { - try { - hitToDigits(hit); - - for (auto digit : mTempDigitVector) { - Int_t id = digit.getTower(); - - if (id < 0 || id > mGeometry->GetNCells()) { - LOG(WARNING) << "tower index out of range: " << id; - continue; - } - - MCLabel label(hit.GetTrackID(), mCurrEvID, mCurrSrcID, false, 1.0); - if (digit.getAmplitude() == 0) { - label.setAmplitudeFraction(0); - } - LabeledDigit d(digit, label); - mDigits[id].push_back(d); + + for (auto labeleddigit : labeledSDigits) { + + sampleSDigit(labeleddigit.getDigit()); + + for (auto digit : mTempDigitVector) { + Int_t id = digit.getTower(); + + MCLabel label(labeleddigit.getLabels()[0]); + if (digit.getAmplitude() == 0) { + label.setAmplitudeFraction(0); } - } catch (InvalidPositionException& e) { - LOG(ERROR) << "Error in creating the digit: " << e.what(); + LabeledDigit d(digit, label); + mDigits[id].push_back(d); } } @@ -136,20 +129,24 @@ void Digitizer::process(const std::vector<Hit>& hits) } //_______________________________________________________________________ -void Digitizer::hitToDigits(const Hit& hit) +void Digitizer::sampleSDigit(const Digit& sDigit) { mTempDigitVector.clear(); - Int_t tower = hit.GetDetectorID(); - Double_t energy = hit.GetEnergyLoss(); + Int_t tower = sDigit.getTower(); + Double_t energy = sDigit.getAmplitude(); if (mSmearEnergy) { energy = smearEnergy(energy); } + // Convert the amplitude from energy GeV to ADC + energy = energy / constants::EMCAL_ADCENERGY; + if (mSimulateTimeResponse && (energy != 0)) { for (int j = 0; j < mAmplitudeInTimeBins.at(mPhase).size(); j++) { double val = energy * (mAmplitudeInTimeBins.at(mPhase).at(j)); + // @TODO check if the time is set correctly Digit digit(tower, val, (mEventTimeOffset + j - mTimeBinOffset.at(mPhase) + mDelay) * constants::EMCAL_TIMESAMPLE); mTempDigitVector.push_back(digit); } @@ -174,7 +171,7 @@ void Digitizer::setEventTime(double t) // convert to ns t *= mCoeffToNanoSecond; - if (t < mEventTime && mContinuous) { + if (t < mEventTime) { LOG(FATAL) << "New event time (" << t << ") is < previous event time (" << mEventTime << ")"; } @@ -212,44 +209,28 @@ void Digitizer::fillOutputContainer(std::vector<Digit>& digits, o2::dataformats: { std::list<LabeledDigit> l; - for (auto t : mDigits) { - std::list<LabeledDigit> tower = t.second; - tower.sort(); - - while (!tower.empty()) { - LabeledDigit ld1 = tower.front(); - tower.pop_front(); - - // loop over all other entries in the container, check if we can add the digits - std::vector<decltype(tower.begin())> toDelete; - for (auto ld2 = tower.begin(); ld2 != tower.end(); ++ld2) { // must be iterator in order to know the position in the container for erasing - if (ld1.canAdd(*ld2)) { - ld1 += *ld2; - toDelete.push_back(ld2); - } - } - for (auto del : toDelete) { - tower.erase(del); - } + for (auto [tower, digitsList] : mDigits) { + digitsList.sort(); + + for (auto ld : digitsList) { if (mSimulateNoiseDigits) { - addNoiseDigits(ld1); + addNoiseDigits(ld); } - if (mRemoveDigitsBelowThreshold && (ld1.getAmplitude() < mSimParam->getDigitThreshold() * (constants::EMCAL_ADCENERGY))) { + if (mRemoveDigitsBelowThreshold && (ld.getAmplitude() < mSimParam->getDigitThreshold() * (constants::EMCAL_ADCENERGY))) { continue; } - if (ld1.getAmplitude() < 0) { + if (ld.getAmplitude() < 0) { continue; } - if (ld1.getTimeStamp() >= mSimParam->getLiveTime()) { + if (ld.getTimeStamp() >= mSimParam->getLiveTime()) { continue; } - l.push_back(ld1); + l.push_back(ld); } } - l.sort(); for (auto d : l) { @@ -265,24 +246,4 @@ void Digitizer::fillOutputContainer(std::vector<Digit>& digits, o2::dataformats: mDigits.clear(); mEmpty = true; -} - -//_______________________________________________________________________ -void Digitizer::setCurrSrcID(int v) -{ - // set current MC source ID - if (v > MCCompLabel::maxSourceID()) { - LOG(FATAL) << "MC source id " << v << " exceeds max storable in the label " << MCCompLabel::maxSourceID(); - } - mCurrSrcID = v; -} - -//_______________________________________________________________________ -void Digitizer::setCurrEvID(int v) -{ - // set current MC event ID - if (v > MCCompLabel::maxEventID()) { - LOG(FATAL) << "MC event id " << v << " exceeds max storable in the label " << MCCompLabel::maxEventID(); - } - mCurrEvID = v; -} +} \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/src/DigitizerTask.cxx b/Detectors/EMCAL/simulation/src/DigitizerTask.cxx deleted file mode 100644 index 94b3e8a58e8eb..0000000000000 --- a/Detectors/EMCAL/simulation/src/DigitizerTask.cxx +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "EMCALSimulation/DigitizerTask.h" -#include "EMCALBase/Geometry.h" -#include "EMCALBase/GeometryBase.h" -#include "EMCALBase/Hit.h" -#include "EMCALSimulation/Digitizer.h" - -#include "FairLogger.h" // for LOG -#include "FairRootManager.h" // for FairRootManager -#include "FairTask.h" // for FairTask, InitStatus -#include "Rtypes.h" // for DigitizerTask::Class, ClassDef, etc - -ClassImp(o2::emcal::DigitizerTask); - -using o2::emcal::Digit; -using o2::emcal::Digitizer; -using o2::emcal::Hit; - -using namespace o2::emcal; - -DigitizerTask::DigitizerTask() : FairTask("EMCALDigitizerTask"), mDigitizer() {} - -DigitizerTask::~DigitizerTask() -{ - if (mDigitsArray) { - mDigitsArray->clear(); - delete mDigitsArray; - } -} - -/// \brief Init function -/// -/// Inititializes the digitizer and connects input and output container -InitStatus DigitizerTask::Init() -{ - FairRootManager* mgr = FairRootManager::Instance(); - if (!mgr) { - LOG(ERROR) << "Could not instantiate FairRootManager. Exiting ..."; - return kERROR; - } - - mHitsArray = mgr->InitObjectAs<const std::vector<o2::emcal::Hit>*>("EMCALHit"); - if (!mHitsArray) { - LOG(ERROR) << "EMCAL hits not registered in the FairRootManager. Exiting ..."; - return kERROR; - } - - // Register output container - mgr->RegisterAny("EMCALDigit", mDigitsArray, kTRUE); - - mDigitizer.setCoeffToNanoSecond(mFairTimeUnitInNS); - - Geometry* geom = Geometry::GetInstance(); - mDigitizer.setGeometry(geom); - - mDigitizer.init(); - - return kSUCCESS; -} - -//________________________________________________________ -void DigitizerTask::Exec(Option_t* option) -{ - FairRootManager* mgr = FairRootManager::Instance(); - - if (mDigitsArray) { - mDigitsArray->clear(); - } - mDigitizer.setEventTime(mgr->GetEventTime()); - - LOG(DEBUG) << "Running digitization on new event " << mEventID << " from source " << mSourceID; - - mDigitizer.setCurrSrcID(mSourceID); - mDigitizer.setCurrEvID(mEventID); - - mDigitizer.process(*mHitsArray); - - mEventID++; -} - -//________________________________________________________ -void DigitizerTask::FinishTask() -{ - // finalize digitization, if needed, flash remaining digits - FairRootManager* mgr = FairRootManager::Instance(); - mgr->SetLastFill(kTRUE); /// necessary, otherwise the data is not written out - if (mDigitsArray) { - mDigitsArray->clear(); - } - // mDigitizer.fillOutputContainer(mDigitsArray); - mDigitizer.finish(); -} diff --git a/Detectors/EMCAL/simulation/src/DigitsWriteoutBuffer.cxx b/Detectors/EMCAL/simulation/src/DigitsWriteoutBuffer.cxx new file mode 100644 index 0000000000000..15d4c3ee2e66e --- /dev/null +++ b/Detectors/EMCAL/simulation/src/DigitsWriteoutBuffer.cxx @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <unordered_map> +#include <vector> +#include <list> +#include <deque> +#include <gsl/span> +#include "EMCALSimulation/LabeledDigit.h" +#include "EMCALSimulation/DigitsWriteoutBuffer.h" + +using namespace o2::emcal; + +DigitsWriteoutBuffer::DigitsWriteoutBuffer(unsigned int nTimeBins, unsigned int binWidth) : mBufferSize(nTimeBins), + mTimeBinWidth(binWidth) +{ + mTimedDigits.resize(nTimeBins); + mMarker.mReferenceTime = 0.; + mMarker.mPositionInBuffer = mTimedDigits.begin(); +} + +void DigitsWriteoutBuffer::clear() +{ + mTimedDigits.clear(); + mMarker.mReferenceTime = 0.; + mMarker.mPositionInBuffer = mTimedDigits.begin(); +} + +void DigitsWriteoutBuffer::addDigit(unsigned int towerID, LabeledDigit dig, double eventTime) +{ + + int nsamples = int((eventTime - mMarker.mReferenceTime) / mTimeBinWidth); + auto timeEntry = mMarker.mPositionInBuffer; + timeEntry[nsamples][towerID].push_back(dig); +} + +void DigitsWriteoutBuffer::forwardMarker(double eventTime) +{ + mMarker.mReferenceTime = eventTime; + mMarker.mPositionInBuffer++; + + // Allocate new memory at the end + mTimedDigits.push_back(std::unordered_map<int, std::list<LabeledDigit>>()); + + // Drop entry at the front, because it is outside the current readout window + // only done if we have at least 15 entries + if (mMarker.mPositionInBuffer - mTimedDigits.begin() > mNumberReadoutSamples) { + mTimedDigits.pop_front(); + } +} + +gsl::span<std::unordered_map<int, std::list<LabeledDigit>>> DigitsWriteoutBuffer::getLastNSamples(int nsamples) +{ + return gsl::span<std::unordered_map<int, std::list<LabeledDigit>>>(&mTimedDigits[int(mMarker.mPositionInBuffer - mTimedDigits.begin() - nsamples)], nsamples); +} diff --git a/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h b/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h index 461faa35bf6c0..f74b3ecb9922d 100644 --- a/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h +++ b/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,11 +18,12 @@ #pragma link C++ class o2::emcal::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::emcal::Detector> + ; #pragma link C++ class o2::emcal::Digitizer + ; -#pragma link C++ class o2::emcal::DigitizerTask + ; +#pragma link C++ class o2::emcal::SDigitizer + ; +#pragma link C++ class o2::emcal::DigitsWriteoutBuffer + ; #pragma link C++ class o2::emcal::SimParam + ; #pragma link C++ class o2::emcal::LabeledDigit + ; #pragma link C++ class o2::emcal::RawWriter + ; -#pragma link C++ class std::list < o2::emcal::LabeledDigit > +; +#pragma link C++ class std::list < o2::emcal::LabeledDigit> + ; #endif diff --git a/Detectors/EMCAL/simulation/src/LabeledDigit.cxx b/Detectors/EMCAL/simulation/src/LabeledDigit.cxx index 618a9f6578c92..bf2d8b7b766e6 100644 --- a/Detectors/EMCAL/simulation/src/LabeledDigit.cxx +++ b/Detectors/EMCAL/simulation/src/LabeledDigit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/src/RawCreator.cxx b/Detectors/EMCAL/simulation/src/RawCreator.cxx index 57c60140cea4e..56e77967bb25e 100644 --- a/Detectors/EMCAL/simulation/src/RawCreator.cxx +++ b/Detectors/EMCAL/simulation/src/RawCreator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,20 +13,21 @@ #include <string> #include <vector> #include "Framework/Logger.h" +#include "FairLogger.h" #include <boost/program_options.hpp> #include <TFile.h> #include <TTree.h> #include <TTreeReader.h> -#include <TSystem.h> - +#include <filesystem> #include "CommonUtils/ConfigurableParam.h" #include "CommonUtils/StringUtils.h" #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/TriggerRecord.h" #include "EMCALBase/Geometry.h" #include "EMCALSimulation/RawWriter.h" +#include "DetectorsCommonDataFormats/NameConf.h" namespace bpo = boost::program_options; @@ -48,6 +50,7 @@ int main(int argc, const char** argv) add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,subdet,link"); add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); add_option("debug,d", bpo::value<uint32_t>()->default_value(0), "Select debug output level [0 = no debug output]"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); opt_all.add(opt_general).add(opt_hidden); @@ -68,6 +71,15 @@ int main(int argc, const char** argv) exit(2); } + auto debuglevel = vm["debug"].as<uint32_t>(); + if (debuglevel > 0) { + FairLogger::GetLogger()->SetLogScreenLevel("DEBUG"); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); auto digitfilename = vm["input-file"].as<std::string>(), @@ -75,8 +87,8 @@ int main(int argc, const char** argv) filefor = vm["file-for"].as<std::string>(); // if needed, create output directory - if (gSystem->AccessPathName(outputdir.c_str())) { - if (gSystem->mkdir(outputdir.c_str(), kTRUE)) { + if (!std::filesystem::exists(outputdir)) { + if (!std::filesystem::create_directories(outputdir)) { LOG(FATAL) << "could not create output directory " << outputdir; } else { LOG(INFO) << "created output directory " << outputdir; @@ -102,12 +114,16 @@ int main(int argc, const char** argv) rawwriter.setFileFor(granularity); rawwriter.setGeometry(o2::emcal::Geometry::GetInstanceFromRunNumber(300000)); rawwriter.setNumberOfADCSamples(15); // @TODO Needs to come from CCDB - rawwriter.setPedestal(0); // @TODO Needs to come from CCDB + rawwriter.setPedestal(3); // @TODO Needs to come from CCDB rawwriter.init(); // Loop over all entries in the tree, where each tree entry corresponds to a time frame for (auto en : *treereader) { rawwriter.digitsToRaw(*digitbranch, *triggerbranch); } - rawwriter.getWriter().writeConfFile("EMC", "RAWDATA", o2::utils::concat_string(outputdir, "/EMCraw.cfg")); + rawwriter.getWriter().writeConfFile("EMC", "RAWDATA", o2::utils::Str::concat_string(outputdir, "/EMCraw.cfg")); + + o2::raw::HBFUtils::Instance().print(); + + return 0; } diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index 674ba68aa408d..ffdee8ed64867 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,14 +25,31 @@ void RawWriter::init() { mRawWriter = std::make_unique<o2::raw::RawFileWriter>(o2::header::gDataOriginEMC, false); mRawWriter->setCarryOverCallBack(this); - mRawWriter->setApplyCarryOverToLastPage(true); + + // initialize mappers + if (!mMappingHandler) { + mMappingHandler = std::make_unique<o2::emcal::MappingHandler>(); + } + for (auto iddl = 0; iddl < 40; iddl++) { // For EMCAL set // - FEE ID = DDL ID // - C-RORC and link increasing with DDL ID // @TODO replace with link assignment on production FLPs, // eventually storing in CCDB - auto [crorc, link] = getLinkAssignment(iddl); + + // initialize containers for SRU + SRUDigitContainer srucont; + srucont.mSRUid = iddl; + mSRUdata.push_back(srucont); + + // Skip empty links with these ddl IDs, + // ddl ID 21 and 39 are empty links, while 23 and 36 are connected to LEDmon only + if (iddl == 21 || iddl == 22 || iddl == 36 || iddl == 39) { + continue; + } + + auto [crorc, link] = mGeometry->getLinkAssignment(iddl); std::string rawfilename = mOutputLocation; switch (mFileFor) { case FileFor_t::kFullDet: @@ -52,17 +70,6 @@ void RawWriter::init() } mRawWriter->registerLink(iddl, crorc, link, 0, rawfilename.data()); } - // initialize mappers - if (!mMappingHandler) { - mMappingHandler = std::make_unique<o2::emcal::MappingHandler>(); - } - - // initialize containers for SRU - for (auto isru = 0; isru < 40; isru++) { - SRUDigitContainer srucont; - srucont.mSRUid = isru; - mSRUdata.push_back(srucont); - } } void RawWriter::digitsToRaw(gsl::span<o2::emcal::Digit> digitsbranch, gsl::span<o2::emcal::TriggerRecord> triggerbranch) @@ -75,7 +82,7 @@ void RawWriter::digitsToRaw(gsl::span<o2::emcal::Digit> digitsbranch, gsl::span< bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) { - for (auto srucont : mSRUdata) { + for (auto& srucont : mSRUdata) { srucont.mChannels.clear(); } std::vector<o2::emcal::Digit*>* bunchDigits; @@ -87,7 +94,7 @@ bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) if (tower > 20000) { std::cout << "Wrong cell ID " << tower << std::endl; } - auto onlineindices = getOnlineID(tower); + auto onlineindices = mGeometry->getOnlineID(tower); int sruID = std::get<0>(onlineindices); auto towerdata = mSRUdata[sruID].mChannels.find(tower); if (towerdata == mSRUdata[sruID].mChannels.end()) { @@ -111,25 +118,56 @@ bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) } // Create and fill DMA pages for each channel - std::cout << "encode data" << std::endl; - std::vector<char> payload; + LOG(DEBUG) << "encode data"; for (auto srucont : mSRUdata) { + std::vector<char> payload; // this must be initialized per SRU, becuase pages are per SRU, therefore the payload was not reset. + + if (srucont.mSRUid == 21 || srucont.mSRUid == 22 || srucont.mSRUid == 36 || srucont.mSRUid == 39) { + continue; + } + for (const auto& [tower, channel] : srucont.mChannels) { // Find out hardware address of the channel auto hwaddress = mMappingHandler->getMappingForDDL(srucont.mSRUid).getHardwareAddress(channel.mRow, channel.mCol, ChannelType_t::HIGH_GAIN); // @TODO distinguish between high- and low-gain cells std::vector<int> rawbunches; + int nbunches = 0; for (auto& bunch : findBunches(channel.mDigits)) { + if (!bunch.mADCs.size()) { + LOG(ERROR) << "Found bunch with without ADC entries - skipping ..."; + continue; + } + rawbunches.push_back(bunch.mADCs.size() + 2); // add 2 words for header information rawbunches.push_back(bunch.mStarttime); - rawbunches.push_back(bunch.mADCs.size()); for (auto adc : bunch.mADCs) { rawbunches.push_back(adc); } + nbunches++; + } + if (!rawbunches.size()) { + LOG(DEBUG) << "No bunch selected"; + continue; } + LOG(DEBUG) << "Selected " << nbunches << " bunches"; + auto encodedbunches = encodeBunchData(rawbunches); - auto chanhead = createChannelHeader(hwaddress, encodedbunches.size() * 3 - 2, false); /// bad channel status eventually to be added later + auto chanhead = createChannelHeader(hwaddress, rawbunches.size(), false); /// bad channel status eventually to be added later char* chanheadwords = reinterpret_cast<char*>(&chanhead); + uint32_t* testheader = reinterpret_cast<uint32_t*>(chanheadwords); + if ((*testheader >> 30) & 1) { + // header pattern found, check that the payload size is properly reflecting the number of words + uint32_t payloadsizeRead = ((*testheader >> 16) & 0x3FF); + uint32_t nwordsRead = (payloadsizeRead + 2) / 3; + if (encodedbunches.size() != nwordsRead) { + LOG(ERROR) << "Mismatch in number of 32-bit words, encoded " << encodedbunches.size() << ", recalculated " << nwordsRead << std::endl; + LOG(ERROR) << "Payload size: " << payloadsizeRead << ", number of words: " << rawbunches.size() << ", encodeed words " << encodedbunches.size() << ", calculated words " << nwordsRead << std::endl; + } else { + LOG(DEBUG) << "Matching number of payload 32-bit words, encoded " << encodedbunches.size() << ", decoded " << nwordsRead; + } + } else { + LOG(ERROR) << "Header without header bit detected ..." << std::endl; + } for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { payload.emplace_back(chanheadwords[iword]); } @@ -139,95 +177,94 @@ bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) } } + if (!payload.size()) { + // [EMCAL-699] No payload found in SRU + // Still the link is not completely ignored but a trailer with 0-payloadsize is added + LOG(DEBUG) << "Payload buffer has size 0 - only write empty trailer" << std::endl; + } + LOG(DEBUG) << "Payload buffer has size " << payload.size(); + // Create RCU trailer - auto trailerwords = createRCUTrailer(payload.size() / 4, 16, 16, 100., 0.); + auto trailerwords = createRCUTrailer(payload.size() / 4, 100., trg.getBCData().toLong(), srucont.mSRUid); for (auto word : trailerwords) { payload.emplace_back(word); } // register output data auto ddlid = srucont.mSRUid; - auto [crorc, link] = getLinkAssignment(ddlid); + auto [crorc, link] = mGeometry->getLinkAssignment(ddlid); LOG(DEBUG1) << "Adding payload with size " << payload.size() << " (" << payload.size() / 4 << " ALTRO words)"; - mRawWriter->addData(ddlid, crorc, link, 0, trg.getBCData(), payload); + mRawWriter->addData(ddlid, crorc, link, 0, trg.getBCData(), payload, false, trg.getTriggerBits()); } - std::cout << "Done" << std::endl; + LOG(DEBUG) << "Done"; return true; } std::vector<AltroBunch> RawWriter::findBunches(const std::vector<o2::emcal::Digit*>& channelDigits) { std::vector<AltroBunch> result; - AltroBunch* currentBunch = nullptr; + AltroBunch currentBunch; + bool bunchStarted = false; // Digits in ALTRO bunch in time-reversed order int itime; for (itime = channelDigits.size() - 1; itime >= 0; itime--) { auto dig = channelDigits[itime]; if (!dig) { + if (bunchStarted) { + // we have a bunch which is started and needs to be closed + // check if the ALTRO bunch has a minimum amount of ADCs + if (currentBunch.mADCs.size() >= mMinADCBunch) { + // Bunch selected, set start time and push to bunches + currentBunch.mStarttime = itime + 1; + result.push_back(currentBunch); + currentBunch = AltroBunch(); + bunchStarted = false; + } + } continue; } int adc = dig->getAmplitudeADC(); if (adc < mPedestal) { - // Stop bunch + // ADC value below threshold + // in case we have an open bunch it needs to be stopped bunch // Set the start time to the time sample of previous (passing) digit - currentBunch->mStarttime = itime + 1; - currentBunch = nullptr; - continue; + if (bunchStarted) { + // check if the ALTRO bunch has a minimum amount of ADCs + if (currentBunch.mADCs.size() >= mMinADCBunch) { + // Bunch selected, set start time and push to bunches + currentBunch.mStarttime = itime + 1; + result.push_back(currentBunch); + currentBunch = AltroBunch(); + bunchStarted = false; + } + } } - if (!currentBunch) { - // start new bunch - AltroBunch bunch; - result.push_back(bunch); - currentBunch = &(result.back()); + // Valid ADC value, if the bunch is closed we start a new bunch + if (!bunchStarted) { + bunchStarted = true; } - currentBunch->mADCs.emplace_back(adc); + currentBunch.mADCs.emplace_back(adc); } // if we have a last bunch set time start time to the time bin of teh previous digit - if (currentBunch) { - currentBunch->mStarttime = itime + 1; + if (bunchStarted) { + if (currentBunch.mADCs.size() >= mMinADCBunch) { + currentBunch.mStarttime = itime + 1; + result.push_back(currentBunch); + } } return result; } -std::tuple<int, int, int> RawWriter::getOnlineID(int towerID) -{ - auto cellindex = mGeometry->GetCellIndex(towerID); - auto supermoduleID = std::get<0>(cellindex); - auto etaphi = mGeometry->GetCellPhiEtaIndexInSModule(supermoduleID, std::get<1>(cellindex), std::get<2>(cellindex), std::get<3>(cellindex)); - auto etaphishift = mGeometry->ShiftOfflineToOnlineCellIndexes(supermoduleID, std::get<0>(etaphi), std::get<1>(etaphi)); - int row = std::get<0>(etaphishift), col = std::get<1>(etaphishift); - - int ddlInSupermoudel = -1; - if (0 <= row && row < 8) { - ddlInSupermoudel = 0; // first cable row - } else if (8 <= row && row < 16 && 0 <= col && col < 24) { - ddlInSupermoudel = 0; // first half; - } else if (8 <= row && row < 16 && 24 <= col && col < 48) { - ddlInSupermoudel = 1; // second half; - } else if (16 <= row && row < 24) { - ddlInSupermoudel = 1; // third cable row - } - if (supermoduleID % 2 == 1) { - ddlInSupermoudel = 1 - ddlInSupermoudel; // swap for odd=C side, to allow us to cable both sides the same - } - - return std::make_tuple(supermoduleID * 2 + ddlInSupermoudel, row, col); -} - -std::tuple<int, int> RawWriter::getLinkAssignment(int ddlID) -{ - // Temporary link assignment (till final link assignment is known - - // eventually taken from CCDB) - // - Link (0-5) and C-RORC ID linear with ddlID - return std::make_tuple(ddlID / 6, ddlID % 6); -} - std::vector<int> RawWriter::encodeBunchData(const std::vector<int>& data) { std::vector<int> encoded; CaloBunchWord currentword; + currentword.mDataWord = 0; int wordnumber = 0; for (auto adc : data) { + if (adc > 0x3FF) { + LOG(ERROR) << "Exceeding max ADC count for 10 bit ALTRO word: " << adc << " (max: 1023)" << std::endl; + } switch (wordnumber) { case 0: currentword.mWord0 = adc; @@ -239,15 +276,17 @@ std::vector<int> RawWriter::encodeBunchData(const std::vector<int>& data) currentword.mWord2 = adc; break; }; - if (wordnumber == 2) { + wordnumber++; + if (wordnumber == 3) { // start new word; encoded.push_back(currentword.mDataWord); currentword.mDataWord = 0; wordnumber = 0; - } else { - wordnumber++; } } + if (wordnumber) { + encoded.push_back(currentword.mDataWord); + } return encoded; } @@ -257,17 +296,37 @@ ChannelHeader RawWriter::createChannelHeader(int hardwareAddress, int payloadSiz header.mHardwareAddress = hardwareAddress; header.mPayloadSize = payloadSize; header.mBadChannel = isBadChannel ? 1 : 0; + header.mHeaderBits = 1; return header; } -std::vector<char> RawWriter::createRCUTrailer(int payloadsize, int feca, int fecb, double timesample, double l1phase) +std::vector<char> RawWriter::createRCUTrailer(int payloadsize, double timesample, uint64_t triggertime, int feeID) { RCUTrailer trailer; - trailer.setActiveFECsA(feca); - trailer.setActiveFECsB(fecb); trailer.setPayloadSize(payloadsize); - trailer.setL1Phase(l1phase); - trailer.setTimeSample(timesample); + trailer.setTimeSamplePhaseNS(triggertime, timesample); + + // You can find details about these settings here https://alice.its.cern.ch/jira/browse/EMCAL-650 + trailer.setRCUID(feeID); + trailer.setFirmwareVersion(2); + trailer.setActiveFECsA(0x0); + trailer.setActiveFECsB(0x1); + trailer.setBaselineCorrection(0); + trailer.setPolarity(false); + trailer.setNumberOfPresamples(0); + trailer.setNumberOfPostsamples(0); + trailer.setSecondBaselineCorrection(false); + trailer.setGlitchFilter(0); + trailer.setNumberOfNonZeroSuppressedPostsamples(1); + trailer.setNumberOfNonZeroSuppressedPresamples(1); + trailer.setNumberOfPretriggerSamples(0); + trailer.setNumberOfSamplesPerChannel(15); + // For MC we don't simulate pedestals. In order to prevent pedestal subtraction + // in the raw fitter we set the zero suppression to true in the RCU trailer + trailer.setZeroSuppression(true); + trailer.setSparseReadout(true); + trailer.setNumberOfAltroBuffers(RCUTrailer::BufferMode_t::NBUFFERS4); + auto trailerwords = trailer.encode(); std::vector<char> encoded(trailerwords.size() * sizeof(uint32_t)); memcpy(encoded.data(), trailerwords.data(), trailerwords.size() * sizeof(uint32_t)); @@ -278,32 +337,13 @@ int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> const char* ptr, int maxSize, int splitID, std::vector<char>& trailer, std::vector<char>& header) const { - int offs = ptr - &data[0]; // offset wrt the head of the payload - // make sure ptr and end of the suggested block are within the payload - assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); - - // Read trailer template from the end of payload - gsl::span<const uint32_t> payloadwords(reinterpret_cast<const uint32_t*>(data.data()), data.size() / sizeof(uint32_t)); - auto rcutrailer = RCUTrailer::constructFromPayloadWords(payloadwords); + constexpr int TrailerSize = 9 * sizeof(uint32_t); + int bytesLeft = data.data() + data.size() - ptr; + int leftAfterSplit = bytesLeft - maxSize; - int sizeNoTrailer = maxSize - rcutrailer.getTrailerSize() * sizeof(uint32_t); - // calculate payload size for RCU trailer: - // assume actualsize is in byte - // Payload size is defined as the number of 32-bit payload words - // -> actualSize to be converted to size of 32 bit words - auto payloadsize = sizeNoTrailer / sizeof(uint32_t); - rcutrailer.setPayloadSize(payloadsize); - auto trailerwords = rcutrailer.encode(); - trailer.resize(trailerwords.size() * sizeof(uint32_t)); - memcpy(trailer.data(), trailerwords.data(), trailer.size()); - // Size to return differs between intermediate pages and last page - // - intermediate page: Size of the trailer needs to be removed as the trailer gets appended - // - last page: Size of the trailer needs to be included as the trailer gets replaced - int bytesLeft = data.size() - (ptr - &data[0]); - bool lastPage = bytesLeft <= maxSize; - int actualSize = maxSize; - if (!lastPage) { - actualSize = sizeNoTrailer; + if (leftAfterSplit < TrailerSize) { + return std::max(0, bytesLeft - TrailerSize); } - return actualSize; + + return maxSize; } diff --git a/Detectors/EMCAL/simulation/src/SDigitizer.cxx b/Detectors/EMCAL/simulation/src/SDigitizer.cxx new file mode 100644 index 0000000000000..1315dc4997c72 --- /dev/null +++ b/Detectors/EMCAL/simulation/src/SDigitizer.cxx @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "EMCALSimulation/SDigitizer.h" +#include "DataFormatsEMCAL/Digit.h" +#include "EMCALBase/Geometry.h" +#include "EMCALBase/GeometryBase.h" +#include "EMCALBase/Hit.h" +#include "MathUtils/Cartesian.h" +#include "SimulationDataFormat/MCCompLabel.h" + +#include <climits> +#include <list> +#include <chrono> +#include <numeric> +#include "FairLogger.h" // for LOG + +ClassImp(o2::emcal::SDigitizer); + +using o2::emcal::Digit; +using o2::emcal::Hit; + +using namespace o2::emcal; + +//_______________________________________________________________________ +std::vector<o2::emcal::LabeledDigit> SDigitizer::process(const std::vector<Hit>& hits) +{ + + std::map<int, std::map<int, std::vector<o2::emcal::Hit>>> hitsPerTowerPerParticleID; + + // will be used to sort digits and labels by tower + std::unordered_map<Int_t, std::vector<LabeledDigit>> digitsPerTower; + + for (auto hit : hits) { + hitsPerTowerPerParticleID[hit.GetDetectorID()][hit.GetTrackID()].push_back(hit); + } + + std::vector<o2::emcal::Hit> SHits; + for (auto [towerID, hitsParticle] : hitsPerTowerPerParticleID) { + for (auto [partID, Hits] : hitsParticle) { + o2::emcal::Hit SHit = std::accumulate(std::next(Hits.begin()), Hits.end(), Hits.front()); + SHits.push_back(SHit); + } + } + + for (auto hit : SHits) { + try { + + Int_t tower = hit.GetDetectorID(); + + if (tower < 0 || tower > mGeometry->GetNCells()) { + LOG(WARNING) << "tower index out of range: " << tower; + continue; + } + + Double_t energy = hit.GetEnergyLoss(); + + //@TODO check if the summed digit time is set correctly + Digit digit(tower, energy, hit.GetTime()); + + MCLabel label(hit.GetTrackID(), mCurrEvID, mCurrSrcID, false, 1.0); + if (digit.getAmplitude() == 0) { + label.setAmplitudeFraction(0); + } + + LabeledDigit d(digit, label); + digitsPerTower[tower].push_back(d); + + } catch (InvalidPositionException& e) { + LOG(ERROR) << "Error in creating the digit: " << e.what(); + } + } + + std::vector<LabeledDigit> digitsVector; + + // Sum all digits in one tower + for (auto [towerID, labeledDigits] : digitsPerTower) { + + o2::emcal::LabeledDigit Sdigit = std::accumulate(std::next(labeledDigits.begin()), labeledDigits.end(), labeledDigits.front()); + + // Check whether the Sdigit is high gain or low gain + if (Sdigit.getAmplitude() > constants::EMCAL_HGLGTRANSITION * constants::EMCAL_ADCENERGY) { + Sdigit.setLowGain(); + } else { + Sdigit.setHighGain(); + } + + digitsVector.push_back(Sdigit); + } + + digitsPerTower.clear(); + + return digitsVector; +} + +//_______________________________________________________________________ +void SDigitizer::setCurrSrcID(int v) +{ + // set current MC source ID + if (v > MCCompLabel::maxSourceID()) { + LOG(FATAL) << "MC source id " << v << " exceeds max storable in the label " << MCCompLabel::maxSourceID(); + } + mCurrSrcID = v; +} + +//_______________________________________________________________________ +void SDigitizer::setCurrEvID(int v) +{ + // set current MC event ID + if (v > MCCompLabel::maxEventID()) { + LOG(FATAL) << "MC event id " << v << " exceeds max storable in the label " << MCCompLabel::maxEventID(); + } + mCurrEvID = v; +} diff --git a/Detectors/EMCAL/simulation/src/SimParam.cxx b/Detectors/EMCAL/simulation/src/SimParam.cxx index b179c60a5d1be..14e0e484ee033 100644 --- a/Detectors/EMCAL/simulation/src/SimParam.cxx +++ b/Detectors/EMCAL/simulation/src/SimParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/simulation/src/SpaceFrame.cxx b/Detectors/EMCAL/simulation/src/SpaceFrame.cxx index a6218e7e3a2ef..38f1707887adf 100644 --- a/Detectors/EMCAL/simulation/src/SpaceFrame.cxx +++ b/Detectors/EMCAL/simulation/src/SpaceFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/testsimulation/CMakeLists.txt b/Detectors/EMCAL/testsimulation/CMakeLists.txt index a40f842e71601..2d3ca30089f68 100644 --- a/Detectors/EMCAL/testsimulation/CMakeLists.txt +++ b/Detectors/EMCAL/testsimulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. if(NOT BUILD_TEST_ROOT_MACROS) return() diff --git a/Detectors/EMCAL/testsimulation/fixedEnergyElectronGun.C b/Detectors/EMCAL/testsimulation/fixedEnergyElectronGun.C index e695f89045b38..5bf617635b327 100644 --- a/Detectors/EMCAL/testsimulation/fixedEnergyElectronGun.C +++ b/Detectors/EMCAL/testsimulation/fixedEnergyElectronGun.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/testsimulation/fixedEnergyPhotonGun.C b/Detectors/EMCAL/testsimulation/fixedEnergyPhotonGun.C index 1f8cb1e2d0f05..ab09889af4ce0 100644 --- a/Detectors/EMCAL/testsimulation/fixedEnergyPhotonGun.C +++ b/Detectors/EMCAL/testsimulation/fixedEnergyPhotonGun.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/testsimulation/fixedEnergyPionGun.C b/Detectors/EMCAL/testsimulation/fixedEnergyPionGun.C index 773d7c1883f45..50d0b1782e041 100644 --- a/Detectors/EMCAL/testsimulation/fixedEnergyPionGun.C +++ b/Detectors/EMCAL/testsimulation/fixedEnergyPionGun.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/CMakeLists.txt b/Detectors/EMCAL/workflow/CMakeLists.txt index aac2708bddbbb..e2b49f6e1af41 100644 --- a/Detectors/EMCAL/workflow/CMakeLists.txt +++ b/Detectors/EMCAL/workflow/CMakeLists.txt @@ -1,15 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/ for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. o2_add_library(EMCALWorkflow - SOURCES src/RecoWorkflow.cxx + SOURCES src/EMCALDigitWriterSpec.cxx + src/EMCALDigitizerSpec.cxx + src/RecoWorkflow.cxx src/PublisherSpec.cxx src/CellConverterSpec.cxx src/ClusterizerSpec.cxx @@ -18,7 +21,7 @@ o2_add_library(EMCALWorkflow src/RawToCellConverterSpec.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsEMCAL + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsEMCAL O2::EMCALSimulation O2::Steer O2::DPLUtils O2::EMCALBase O2::EMCALReconstruction O2::Algorithm) o2_add_executable(reco-workflow @@ -30,3 +33,16 @@ o2_add_executable(entropy-encoder-workflow COMPONENT_NAME emcal SOURCES src/entropy-encoder-workflow.cxx PUBLIC_LINK_LIBRARIES O2::EMCALWorkflow) + +o2_add_executable(emc-dcs-workflow + COMPONENT_NAME calibration + SOURCES src/emc-dcs-data-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::EMCALCalib + O2::EMCALWorkflow + O2::DetectorsDCS) + +o2_add_executable(emc-dcs-sim-workflow + COMPONENT_NAME calibration + SOURCES src/emc-dcs-sim-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) diff --git a/Detectors/EMCAL/workflow/README.md b/Detectors/EMCAL/workflow/README.md index dfb53cee87075..1f0ca09c903bb 100644 --- a/Detectors/EMCAL/workflow/README.md +++ b/Detectors/EMCAL/workflow/README.md @@ -3,3 +3,18 @@ /doxy --> # The EMCAL reconstruction workflow + +## EMCAL DCS DP processing: + +example with test CCDB : + +```shell +o2-calibration-emc-dcs-sim-workflow --max-timeframes 10 --delta-fraction 0.5 -b | +o2-calibration-emc-dcs-workflow --use-ccdb-to-configure --use-verbose-mode -b | +o2-calibration-ccdb-populator-workflow --ccdb-path="http://ccdb-test.cern.ch:8080" -b --run +``` +For creating EMCAL DCS config in CCDB: +`O2/Detectors/EMCAL/calib/macros/makeEMCALCCDBEntryForDCS.C` + +For reading EMCAL DCS data from CCDB: +`O2/Detectors/EMCAL/calib/macros/readEMCALDCSentries.C` diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/AnalysisClusterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/AnalysisClusterSpec.h old mode 100755 new mode 100644 index a6132d114ce12..74cdd62110b73 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/AnalysisClusterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/AnalysisClusterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/CellConverterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/CellConverterSpec.h index 2d087da1ee67a..cc09f376d5b10 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/CellConverterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/CellConverterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/ClusterizerSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/ClusterizerSpec.h index 4495215c0be0c..67c60fab6655c 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/ClusterizerSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/ClusterizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/DigitsPrinterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/DigitsPrinterSpec.h index c20ec6662822e..6ee0b7143c186 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/DigitsPrinterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/DigitsPrinterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDCSDataProcessorSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDCSDataProcessorSpec.h new file mode 100644 index 0000000000000..c89e91de04e89 --- /dev/null +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDCSDataProcessorSpec.h @@ -0,0 +1,216 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_EMCAL_DATAPROCESSORSPEC_H +#define O2_EMCAL_DATAPROCESSORSPEC_H + +/// @file EMCALDCSDataProcessorSpec.h +/// @brief EMCAL Processor for DCS Data Points + +#include <unistd.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/AliasExpander.h" +#include "EMCALCalib/EMCDCSProcessor.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace emcal +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using namespace o2::ccdb; +using CcdbManager = o2::ccdb::BasicCCDBManager; +using clbUtils = o2::calibration::Utils; +using HighResClock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration<double, std::ratio<1, 1>>; + +class EMCALDCSDataProcessor : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + + std::vector<DPID> vect; + mDPsUpdateInterval = ic.options().get<int64_t>("DPs-update-interval"); + if (mDPsUpdateInterval == 0) { + LOG(ERROR) << "EMC DPs update interval set to zero seconds --> changed to 60"; + mDPsUpdateInterval = 60; + } + bool useCCDBtoConfigure = ic.options().get<bool>("use-ccdb-to-configure"); + if (useCCDBtoConfigure) { + LOG(INFO) << "Configuring via CCDB"; + std::string ccdbpath = ic.options().get<std::string>("ccdb-path"); + auto& mgr = CcdbManager::instance(); + mgr.setURL(ccdbpath); + CcdbApi api; + api.init(mgr.getURL()); + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + std::unordered_map<DPID, std::string>* dpid2DataDesc = mgr.getForTimeStamp<std::unordered_map<DPID, std::string>>("EMC/Config/DCSDPconfig", ts); + for (auto& i : *dpid2DataDesc) { + vect.push_back(i.first); + } + } else { + LOG(INFO) << "Configuring via hardcoded strings"; + + std::vector<std::string> aliasesTEMP = {"EMC_PT_[00..83]/Temperature", "EMC_PT_[88..91]/Temperature", "EMC_PT_[96..159]/Temperature"}; + std::vector<std::string> aliasesUINT = {"EMC_DDL_LIST[0..1]", "EMC_SRU[00..19]_CFG", "EMC_SRU[00..19]_FMVER", + "EMC_TRU[00..45]_PEAKFINDER", "EMC_TRU[00..45]_L0ALGSEL", "EMC_TRU[00..45]_COSMTHRESH", + "EMC_TRU[00..45]_GLOBALTHRESH", "EMC_TRU[00..45]_MASK[0..5]", + "EMC_STU_ERROR_COUNT_TRU[0..67]", "DMC_STU_ERROR_COUNT_TRU[0..55]"}; + std::vector<std::string> aliasesINT = {"EMC_STU_FWVERS", "EMC_STU_GA[0..1]", "EMC_STU_GB[0..1]", "EMC_STU_GC[0..1]", + "EMC_STU_JA[0..1]", "EMC_STU_JB[0..1]", "EMC_STU_JC[0..1]", "EMC_STU_PATCHSIZE", "EMC_STU_GETRAW", + "EMC_STU_MEDIAN", "EMC_STU_REGION", "DMC_STU_FWVERS", "DMC_STU_PHOS_scale[0..3]", "DMC_STU_GA[0..1]", + "DMC_STU_GB[0..1]", "DMC_STU_GC[0..1]", "DMC_STU_JA[0..1]", "DMC_STU_JB[0..1]", "DMC_STU_JC[0..1]", + "DMC_STU_PATCHSIZE", "DMC_STU_GETRAW", "DMC_STU_MEDIAN", "DMC_STU_REGION"}; + + std::vector<std::string> expaliasesTEMP = o2::dcs::expandAliases(aliasesTEMP); + std::vector<std::string> expaliasesUINT = o2::dcs::expandAliases(aliasesUINT); + std::vector<std::string> expaliasesINT = o2::dcs::expandAliases(aliasesINT); + + for (const auto& i : expaliasesTEMP) { + vect.emplace_back(i, o2::dcs::RAW_DOUBLE); + } + for (const auto& i : expaliasesINT) { + vect.emplace_back(i, o2::dcs::RAW_INT); + } + for (const auto& i : expaliasesUINT) { + vect.emplace_back(i, o2::dcs::RAW_UINT); + } + } + + LOG(INFO) << "Listing Data Points for EMC:"; + for (auto& i : vect) { + LOG(INFO) << i; + } + + mProcessor = std::make_unique<o2::emcal::EMCDCSProcessor>(); + bool useVerboseMode = ic.options().get<bool>("use-verbose-mode"); + LOG(INFO) << " ************************* Verbose? " << useVerboseMode; + if (useVerboseMode) { + mProcessor->useVerboseMode(); + } + mProcessor->init(vect); + mTimer = HighResClock::now(); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfid = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + auto dps = pc.inputs().get<gsl::span<DPCOM>>("input"); + mProcessor->setTF(tfid); + mProcessor->process(dps); + auto timeNow = HighResClock::now(); + Duration elapsedTime = timeNow - mTimer; // in seconds + if (elapsedTime.count() >= mDPsUpdateInterval) { + sendELMButput(pc.outputs()); + mTimer = timeNow; + } + sendCFGoutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + sendELMButput(ec.outputs()); + sendCFGoutput(ec.outputs()); + } + + private: + std::unique_ptr<EMCDCSProcessor> mProcessor; + HighResClock::time_point mTimer; + int64_t mDPsUpdateInterval; + + //________________________________________________________________ + void sendELMButput(DataAllocator& output) + { + // extract CCDB infos and Temperature Sensor data + + mProcessor->processElmb(); + mProcessor->updateElmbCCDBinfo(); + + const auto& payload = mProcessor->getELMBdata(); + auto& info = mProcessor->getccdbELMBinfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_ELMB", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_ELMB", 0}, info); + } + + //________________________________________________________________ + void sendCFGoutput(DataAllocator& output) + { + // extract CCDB and FeeDCS info + + if (mProcessor->isUpdateFEEcfg()) { + mProcessor->updateFeeCCDBinfo(); + + const auto& payload = mProcessor->getFeeDCSdata(); + auto& info = mProcessor->getccdbFeeDCSinfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_FeeDCS", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_FeeDCS", 0}, info); + } + } + +}; // end class +} // namespace emcal + +namespace framework +{ + +DataProcessorSpec getEMCALDCSDataProcessorSpec() +{ + + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_ELMB"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_ELMB"}); + + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_FeeDCS"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_FeeDCS"}); + + return DataProcessorSpec{ + "emc-dcs-data-processor", + Inputs{{"input", "DCS", "EMCDATAPOINTS"}}, + outputs, + AlgorithmSpec{adaptFromTask<o2::emcal::EMCALDCSDataProcessor>()}, + Options{{"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}, + {"use-ccdb-to-configure", VariantType::Bool, false, {"Use CCDB to configure"}}, + {"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, + {"DPs-update-interval", VariantType::Int64, 600ll, {"Interval (in s) after which to update the DPs CCDB entry"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitWriterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitWriterSpec.h new file mode 100644 index 0000000000000..e3c01e2208025 --- /dev/null +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitWriterSpec.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ +#define STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ + +#include "Framework/DataProcessorSpec.h" +namespace o2 +{ +namespace emcal +{ + +/// \brief Create new digits writer spec +/// \return digits writer spec +o2::framework::DataProcessorSpec getEMCALDigitWriterSpec(bool mctruth = true); + +} // end namespace emcal +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitizerSpec.h similarity index 79% rename from Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.h rename to Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitizerSpec.h index 6820ae102ae34..2a3d53754510b 100644 --- a/Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EMCALDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "DataFormatsEMCAL/Digit.h" #include "EMCALBase/Hit.h" #include "EMCALSimulation/Digitizer.h" +#include "EMCALSimulation/SDigitizer.h" #include "SimulationDataFormat/MCTruthContainer.h" #include <DetectorsBase/BaseDPLDigitizer.h> @@ -58,8 +60,9 @@ class DigitizerSpec final : public o2::base::BaseDPLDigitizer void run(framework::ProcessingContext& ctx); private: - Bool_t mFinished = false; ///< Flag for digitization finished - Digitizer mDigitizer; ///< Digitizer object + Bool_t mFinished = false; ///< Flag for digitization finished + Digitizer mDigitizer; ///< Digitizer object + o2::emcal::SDigitizer mSumDigitizer; ///< Summed digitizer std::vector<TChain*> mSimChains; std::vector<Hit> mHits; ///< Vector with input hits std::vector<Digit> mDigits; ///< Vector with non-accumulated digits (per collision) diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h index 2273f60d5a1f6..9f0baea56a038 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h index f0852d9367577..454d1b4e70f5a 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/PublisherSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/PublisherSpec.h index 864b360a2b747..11806c485e96a 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/PublisherSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/PublisherSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h index a37af9554fb6b..fce86658512ba 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "Framework/Task.h" #include "DataFormatsEMCAL/Cell.h" #include "DataFormatsEMCAL/TriggerRecord.h" +#include "Headers/DataHeader.h" #include "EMCALBase/Geometry.h" #include "EMCALBase/Mapper.h" #include "EMCALReconstruction/CaloRawFitter.h" @@ -36,11 +38,11 @@ class RawToCellConverterSpec : public framework::Task { public: /// \brief Constructor - /// \param propagateMC If true the MCTruthContainer is propagated to the output - RawToCellConverterSpec() : framework::Task(){}; + /// \param subspecification Output subspecification for parallel running on multiple nodes + RawToCellConverterSpec(int subspecification) : framework::Task(), mSubspecification(subspecification){}; /// \brief Destructor - ~RawToCellConverterSpec() override = default; + ~RawToCellConverterSpec() override; /// \brief Initializing the RawToCellConverterSpec /// \param ctx Init context @@ -55,22 +57,51 @@ class RawToCellConverterSpec : public framework::Task /// Output cells trigger record: {"EMC", "CELLSTR", 0, Lifetime::Timeframe} void run(framework::ProcessingContext& ctx) final; + /// \brief Set max number of error messages printed + /// \param maxMessages Max. amount of messages printed + /// + /// Error messages will be suppressed once the maximum is reached + void setMaxErrorMessages(int maxMessages) { mMaxErrorMessages = maxMessages; } + void setNoiseThreshold(int thresold) { mNoiseThreshold = thresold; } - int getNoiseThreshold() { return mNoiseThreshold; } + int getNoiseThreshold() const { return mNoiseThreshold; } + + /// \brief Set ID of the subspecification + /// \param subspecification + /// + /// Can be used to define differenciate between output in case + /// different processors run in parallel (i.e. on different FLPs) + void setSubspecification(header::DataHeader::SubSpecificationType subspecification) { mSubspecification = subspecification; } + + /// \brief Get ID of the subspecification + /// \return subspecification + /// + /// Can be used to define differenciate between output in case + /// different processors run in parallel (i.e. on different FLPs) + header::DataHeader::SubSpecificationType getSubspecification() const { return mSubspecification; } private: - int mNoiseThreshold = 0; - o2::emcal::Geometry* mGeometry = nullptr; ///!<! Geometry pointer - std::unique_ptr<o2::emcal::MappingHandler> mMapper = nullptr; ///!<! Mapper - std::unique_ptr<o2::emcal::CaloRawFitter> mRawFitter; ///!<! Raw fitter - std::vector<o2::emcal::Cell> mOutputCells; ///< Container with output cells - std::vector<o2::emcal::TriggerRecord> mOutputTriggerRecords; ///< Container with output cells + bool isLostTimeframe(framework::ProcessingContext& ctx) const; + void sendData(framework::ProcessingContext& ctx, const std::vector<o2::emcal::Cell>& cells, const std::vector<o2::emcal::TriggerRecord>& triggers, const std::vector<ErrorTypeFEE>& decodingErrors) const; + + header::DataHeader::SubSpecificationType mSubspecification = 0; ///< Subspecification for output channels + int mNoiseThreshold = 0; ///< Noise threshold in raw fit + int mNumErrorMessages = 0; ///< Current number of error messages + int mErrorMessagesSuppressed = 0; ///< Counter of suppressed error messages + int mMaxErrorMessages = 100; ///< Max. number of error messages + bool mPrintTrailer = false; + Geometry* mGeometry = nullptr; ///!<! Geometry pointer + std::unique_ptr<MappingHandler> mMapper = nullptr; ///!<! Mapper + std::unique_ptr<CaloRawFitter> mRawFitter; ///!<! Raw fitter + std::vector<Cell> mOutputCells; ///< Container with output cells + std::vector<TriggerRecord> mOutputTriggerRecords; ///< Container with output cells + std::vector<ErrorTypeFEE> mOutputDecoderErrors; ///< Container with decoder errors }; /// \brief Creating DataProcessorSpec for the EMCAL Cell Converter Spec /// /// Refer to RawToCellConverterSpec::run for input and output specs -framework::DataProcessorSpec getRawToCellConverterSpec(); +framework::DataProcessorSpec getRawToCellConverterSpec(bool askDISTSTF, int subspecification); } // namespace reco_workflow diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h index f001e24ae88d2..b92bfa0dc34af 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,15 +46,19 @@ enum struct OutputType { Digits, ///< EMCAL digits /// \brief create the workflow for EMCAL reconstruction /// \param propagateMC If true MC labels are propagated to the output files -/// \param enableDigitsPrinter If true +/// \param askDISTSTF If true the Raw->Cell converter subscribes to FLP/DISTSUBTIMEFRAME +/// \param enableDigitsPrinter If true then the simple digits printer is added as dummy task +/// \param subspecification Subspecification in case of running on different FLPs /// \param cfgInput Input objects processed in the workflow /// \param cfgOutput Output objects created in the workflow /// \return EMCAL reconstruction workflow for the configuration provided /// \ingroup EMCALwokflow framework::WorkflowSpec getWorkflow(bool propagateMC = true, + bool askDISTSTF = true, bool enableDigitsPrinter = false, - std::string const& cfgInput = "digits", // - std::string const& cfgOutput = "clusters", // + int subspecification = 0, + std::string const& cfgInput = "digits", + std::string const& cfgOutput = "clusters", bool disableRootInput = false, bool disableRootOutput = false); } // namespace reco_workflow diff --git a/Detectors/EMCAL/workflow/src/AnalysisClusterSpec.cxx b/Detectors/EMCAL/workflow/src/AnalysisClusterSpec.cxx old mode 100755 new mode 100644 index 26931ad0741df..7c1aeb2091f65 --- a/Detectors/EMCAL/workflow/src/AnalysisClusterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/AnalysisClusterSpec.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include <gsl/span> -#include "FairLogger.h" +#include <InfoLogger/InfoLogger.hxx> #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/Cluster.h" @@ -17,6 +18,7 @@ #include "DataFormatsEMCAL/TriggerRecord.h" #include "EMCALWorkflow/AnalysisClusterSpec.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "EMCALBase/Geometry.h" #include "DetectorsBase/GeometryManager.h" #include <TGeoManager.h> @@ -26,6 +28,9 @@ using namespace o2::emcal::reco_workflow; template <class InputType> void AnalysisClusterSpec<InputType>::init(framework::InitContext& ctx) { + auto& ilctx = ctx.services().get<AliceO2::InfoLogger::InfoLoggerContext>(); + ilctx.setField(AliceO2::InfoLogger::InfoLoggerContext::FieldName::Detector, "EMC"); + LOG(DEBUG) << "[EMCALClusterizer - init] Initialize clusterizer ..."; // FIXME: Placeholder configuration -> get config from CCDB object diff --git a/Detectors/EMCAL/workflow/src/CellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/CellConverterSpec.cxx index b6fbc65ea37dc..836e6dc3c1d25 100644 --- a/Detectors/EMCAL/workflow/src/CellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/CellConverterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/EMCAL/workflow/src/ClusterizerSpec.cxx b/Detectors/EMCAL/workflow/src/ClusterizerSpec.cxx index 8c4284945cb21..ec53ffb561473 100644 --- a/Detectors/EMCAL/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/EMCAL/workflow/src/ClusterizerSpec.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include <gsl/span> -#include "FairLogger.h" +#include <InfoLogger/InfoLogger.hxx> #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/Cluster.h" @@ -17,12 +18,16 @@ #include "DataFormatsEMCAL/TriggerRecord.h" #include "EMCALWorkflow/ClusterizerSpec.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" using namespace o2::emcal::reco_workflow; template <class InputType> void ClusterizerSpec<InputType>::init(framework::InitContext& ctx) { + auto& ilctx = ctx.services().get<AliceO2::InfoLogger::InfoLoggerContext>(); + ilctx.setField(AliceO2::InfoLogger::InfoLoggerContext::FieldName::Detector, "EMC"); + LOG(DEBUG) << "[EMCALClusterizer - init] Initialize clusterizer ..."; // FIXME: Placeholder configuration -> get config from CCDB object diff --git a/Detectors/EMCAL/workflow/src/DigitsPrinterSpec.cxx b/Detectors/EMCAL/workflow/src/DigitsPrinterSpec.cxx index df0131cc53e28..ec72fefd648bf 100644 --- a/Detectors/EMCAL/workflow/src/DigitsPrinterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/DigitsPrinterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.cxx b/Detectors/EMCAL/workflow/src/EMCALDigitWriterSpec.cxx similarity index 80% rename from Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.cxx rename to Detectors/EMCAL/workflow/src/EMCALDigitWriterSpec.cxx index 1bdcd1d8da4f0..63a06c8340db8 100644 --- a/Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EMCALDigitWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ /// @brief Processor spec for a ROOT file writer for EMCAL digits -#include "EMCALDigitWriterSpec.h" +#include "EMCALWorkflow/EMCALDigitWriterSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include <SimulationDataFormat/MCTruthContainer.h> #include "DataFormatsEMCAL/Digit.h" diff --git a/Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.cxx b/Detectors/EMCAL/workflow/src/EMCALDigitizerSpec.cxx similarity index 86% rename from Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.cxx rename to Detectors/EMCAL/workflow/src/EMCALDigitizerSpec.cxx index 30cf2d36ec786..722c38810ffe9 100644 --- a/Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EMCALDigitizerSpec.cxx @@ -1,14 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "EMCALDigitizerSpec.h" +#include "EMCALWorkflow/EMCALDigitizerSpec.h" +#include "CommonConstants/Triggers.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" @@ -18,6 +20,7 @@ #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" +#include <TGeoManager.h> #include "CommonDataFormat/EvIndex.h" #include "DataFormatsParameters/GRPObject.h" @@ -40,7 +43,9 @@ void DigitizerSpec::initDigitizerTask(framework::InitContext& ctx) // to be adapted with run numbers at a later stage auto geom = o2::emcal::Geometry::GetInstance("EMCAL_COMPLETE12SMV1_DCAL_8SM", "Geant4", "EMV-EMCAL"); // init digitizer - mDigitizer.setGeometry(geom); + + mSumDigitizer.setGeometry(geom); + mDigitizer.init(); mFinished = false; @@ -78,7 +83,10 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) // loop over all composite collisions given from context // (aka loop over all the interaction records) for (int collID = 0; collID < timesview.size(); ++collID) { - if (!mDigitizer.isEmpty() && (o2::emcal::SimParam::Instance().isDisablePileup() || !mDigitizer.isLive(timesview[collID].getTimeNS()))) { + + mDigitizer.setEventTime(timesview[collID].getTimeNS()); + + if (!mDigitizer.isEmpty() && (o2::emcal::SimParam::Instance().isDisablePileup() || !mDigitizer.isLive())) { // copy digits into accumulator mDigits.clear(); mLabels.clear(); @@ -92,8 +100,6 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) mLabels.clear(); } - mDigitizer.setEventTime(timesview[collID].getTimeNS()); - if (!mDigitizer.isLive()) { continue; } @@ -106,8 +112,9 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) // for each collision, loop over the constituents event and source IDs // (background signal merging is basically taking place here) for (auto& part : eventParts[collID]) { - mDigitizer.setCurrEvID(part.entryID); - mDigitizer.setCurrSrcID(part.sourceID); + + mSumDigitizer.setCurrEvID(part.entryID); + mSumDigitizer.setCurrSrcID(part.sourceID); // get the hits for this event and this source mHits.clear(); @@ -115,8 +122,10 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) LOG(INFO) << "For collision " << collID << " eventID " << part.entryID << " found " << mHits.size() << " hits "; + std::vector<o2::emcal::LabeledDigit> summedDigits = mSumDigitizer.process(mHits); + // call actual digitization procedure - mDigitizer.process(mHits); + mDigitizer.process(summedDigits); } } @@ -128,7 +137,7 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(mAccumulatedDigits)); labelAccum.mergeAtBack(mLabels); LOG(INFO) << "Have " << mAccumulatedDigits.size() << " digits "; - triggers.emplace_back(timesview[trigID], indexStart, mDigits.size()); + triggers.emplace_back(timesview[trigID], o2::trigger::PhT, indexStart, mDigits.size()); indexStart = mAccumulatedDigits.size(); mDigits.clear(); mLabels.clear(); @@ -153,7 +162,7 @@ void DigitizerSpec::run(framework::ProcessingContext& ctx) mFinished = true; } -DataProcessorSpec getEMCALDigitizerSpec(int channel, bool mctruth) +o2::framework::DataProcessorSpec getEMCALDigitizerSpec(int channel, bool mctruth) { // create the full data processor spec using // a name identifier diff --git a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx index dec7ed2f81cdd..74f71faa5f104 100644 --- a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("emcal-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -72,7 +73,7 @@ DataProcessorSpec getEntropyDecoderSpec() Inputs{InputSpec{"ctf", "EMC", "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"emcal-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace emcal diff --git a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx index b4372ed4d8186..c58cebbda2953 100644 --- a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("emcal-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -72,7 +73,7 @@ DataProcessorSpec getEntropyEncoderSpec() inputs, Outputs{{"EMC", "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"emcal-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace emcal diff --git a/Detectors/EMCAL/workflow/src/PublisherSpec.cxx b/Detectors/EMCAL/workflow/src/PublisherSpec.cxx index 13a0890405284..94c84c318d129 100644 --- a/Detectors/EMCAL/workflow/src/PublisherSpec.cxx +++ b/Detectors/EMCAL/workflow/src/PublisherSpec.cxx @@ -1,13 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "DetectorsCommonDataFormats/NameConf.h" #include "DataFormatsEMCAL/EMCALBlockHeader.h" #include "EMCALWorkflow/PublisherSpec.h" #include "Framework/ConfigParamRegistry.h" @@ -33,7 +35,8 @@ o2::framework::DataProcessorSpec createPublisherSpec(PublisherConf const& config auto initFunction = [config, propagateMC, creator](o2::framework::InitContext& ic) { // get the option from the init context - auto filename = ic.options().get<std::string>("infile"); + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); auto treename = ic.options().get<std::string>("treename"); auto dtbrName = ic.options().get<std::string>(config.databranch.option.c_str()); // databranch name auto trgbrName = ic.options().get<std::string>(config.triggerrecordbranch.option.c_str()); // triggerbranch name @@ -106,6 +109,7 @@ o2::framework::DataProcessorSpec createPublisherSpec(PublisherConf const& config o2::framework::AlgorithmSpec(initFunction), o2::framework::Options{ {"infile", o2::framework::VariantType::String, "", {"Name of the input file"}}, + {"input-dir", o2::framework::VariantType::String, "none", {"Input directory"}}, {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, {trb.option.c_str(), o2::framework::VariantType::String, trb.defval.c_str(), {trb.help.c_str()}}, diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index 9a4b6b1dea0a2..d93e309015859 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -1,22 +1,28 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include <string> +#include <iostream> +#include <bitset> -#include "FairLogger.h" +#include <InfoLogger/InfoLogger.hxx> #include "CommonDataFormat/InteractionRecord.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" #include "Framework/WorkflowSpec.h" #include "DataFormatsEMCAL/EMCALBlockHeader.h" #include "DataFormatsEMCAL/TriggerRecord.h" +#include "DataFormatsEMCAL/ErrorTypeFEE.h" #include "DetectorsRaw/RDHUtils.h" #include "EMCALBase/Geometry.h" #include "EMCALBase/Mapper.h" @@ -25,24 +31,35 @@ #include "EMCALReconstruction/CaloRawFitterStandard.h" #include "EMCALReconstruction/CaloRawFitterGamma2.h" #include "EMCALReconstruction/AltroDecoder.h" +#include "EMCALReconstruction/RawDecodingError.h" #include "EMCALWorkflow/RawToCellConverterSpec.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" using namespace o2::emcal::reco_workflow; +RawToCellConverterSpec::~RawToCellConverterSpec() +{ + if (mErrorMessagesSuppressed) { + LOG(WARNING) << "Suppressed further " << mErrorMessagesSuppressed << " error messages"; + } +} + void RawToCellConverterSpec::init(framework::InitContext& ctx) { + auto& ilctx = ctx.services().get<AliceO2::InfoLogger::InfoLoggerContext>(); + ilctx.setField(AliceO2::InfoLogger::InfoLoggerContext::FieldName::Detector, "EMC"); + LOG(DEBUG) << "[EMCALRawToCellConverter - init] Initialize converter "; if (!mGeometry) { - mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(223409); + mGeometry = Geometry::GetInstanceFromRunNumber(223409); } if (!mGeometry) { LOG(ERROR) << "Failure accessing geometry"; } if (!mMapper) { - mMapper = std::unique_ptr<o2::emcal::MappingHandler>(new o2::emcal::MappingHandler); + mMapper = std::unique_ptr<MappingHandler>(new o2::emcal::MappingHandler); } if (!mMapper) { LOG(ERROR) << "Failed to initialize mapper"; @@ -51,11 +68,19 @@ void RawToCellConverterSpec::init(framework::InitContext& ctx) auto fitmethod = ctx.options().get<std::string>("fitmethod"); if (fitmethod == "standard") { LOG(INFO) << "Using standard raw fitter"; - mRawFitter = std::unique_ptr<o2::emcal::CaloRawFitter>(new o2::emcal::CaloRawFitterStandard); + mRawFitter = std::unique_ptr<CaloRawFitter>(new o2::emcal::CaloRawFitterStandard); } else if (fitmethod == "gamma2") { - mRawFitter = std::unique_ptr<o2::emcal::CaloRawFitter>(new o2::emcal::CaloRawFitterGamma2); + LOG(INFO) << "Using gamma2 raw fitter"; + mRawFitter = std::unique_ptr<CaloRawFitter>(new o2::emcal::CaloRawFitterGamma2); + } else { + LOG(FATAL) << "Unknown fit method" << fitmethod; } + mPrintTrailer = ctx.options().get<bool>("printtrailer"); + + mMaxErrorMessages = ctx.options().get<int>("maxmessage"); + LOG(INFO) << "Suppressing error messages after " << mMaxErrorMessages << " messages"; + mRawFitter->setAmpCut(mNoiseThreshold); mRawFitter->setL1Phase(0.); } @@ -63,53 +88,161 @@ void RawToCellConverterSpec::init(framework::InitContext& ctx) void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) { LOG(DEBUG) << "[EMCALRawToCellConverter - run] called"; + const double CONVADCGEV = 0.016; // Conversion from ADC counts to energy: E = 16 MeV / ADC + constexpr auto originEMC = o2::header::gDataOriginEMC; + constexpr auto descRaw = o2::header::gDataDescriptionRawData; + + mOutputCells.clear(); + mOutputTriggerRecords.clear(); + mOutputDecoderErrors.clear(); + + if (isLostTimeframe(ctx)) { + sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); + return; + } // Cache cells from for bunch crossings as the component reads timeframes from many links consecutively - std::map<o2::InteractionRecord, std::shared_ptr<std::vector<o2::emcal::Cell>>> cellBuffer; // Internal cell buffer + std::map<o2::InteractionRecord, std::shared_ptr<std::vector<Cell>>> cellBuffer; // Internal cell buffer + std::map<o2::InteractionRecord, uint32_t> triggerBuffer; + std::vector<framework::InputSpec> filter{{"filter", framework::ConcreteDataTypeMatcher(originEMC, descRaw)}}; int firstEntry = 0; - for (const auto& rawData : ctx.inputs()) { + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs(), filter)) { + + // Skip SOX headers + auto rdhblock = reinterpret_cast<const o2::header::RDHAny*>(rawData.payload); + if (o2::raw::RDHUtils::getHeaderSize(rdhblock) == static_cast<int>(o2::framework::DataRefUtils::getPayloadSize(rawData))) { + continue; + } //o2::emcal::RawReaderMemory<o2::header::RAWDataHeaderV4> rawreader(gsl::span(rawData.payload, o2::framework::DataRefUtils::getPayloadSize(rawData))); - o2::emcal::RawReaderMemory rawreader(o2::framework::DataRefUtils::as<const char>(rawData)); + o2::emcal::RawReaderMemory rawreader(framework::DataRefUtils::as<const char>(rawData)); // loop over all the DMA pages while (rawreader.hasNext()) { - rawreader.next(); + try { + rawreader.next(); + } catch (RawDecodingError& e) { + mOutputDecoderErrors.emplace_back(e.getFECID(), ErrorTypeFEE::ErrorSource_t::PAGE_ERROR, RawDecodingError::ErrorTypeToInt(e.getErrorType())); + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(ERROR) << " EMCAL raw task: " << e.what() << " in FEC " << e.getFECID() << std::endl; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + } auto& header = rawreader.getRawHeader(); - auto triggerBC = o2::raw::RDHUtils::getTriggerBC(header); - auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(header); - auto feeID = o2::raw::RDHUtils::getFEEID(header); + auto triggerBC = raw::RDHUtils::getTriggerBC(header); + auto triggerOrbit = raw::RDHUtils::getTriggerOrbit(header); + auto feeID = raw::RDHUtils::getFEEID(header); + auto triggerbits = raw::RDHUtils::getTriggerType(header); o2::InteractionRecord currentIR(triggerBC, triggerOrbit); - std::shared_ptr<std::vector<o2::emcal::Cell>> currentCellContainer; + std::shared_ptr<std::vector<Cell>> currentCellContainer; auto found = cellBuffer.find(currentIR); if (found == cellBuffer.end()) { - currentCellContainer = std::make_shared<std::vector<o2::emcal::Cell>>(); + currentCellContainer = std::make_shared<std::vector<Cell>>(); cellBuffer[currentIR] = currentCellContainer; + // also add trigger bits + triggerBuffer[currentIR] = triggerbits; } else { currentCellContainer = found->second; } - if (feeID > 40) { + if (feeID >= 40) { continue; //skip STU ddl } //std::cout<<rawreader.getRawHeader()<<std::endl; // use the altro decoder to decode the raw data, and extract the RCU trailer - o2::emcal::AltroDecoder decoder(rawreader); - decoder.decode(); + AltroDecoder decoder(rawreader); + //check the words of the payload exception in altrodecoder + try { + decoder.decode(); + } catch (AltroDecoderError& e) { + ErrorTypeFEE errornum(feeID, ErrorTypeFEE::ErrorSource_t::ALTRO_ERROR, AltroDecoderError::errorTypeToInt(e.getErrorType())); + if (mNumErrorMessages < mMaxErrorMessages) { + std::string errormessage; + using AltroErrType = AltroDecoderError::ErrorType_t; + switch (e.getErrorType()) { + case AltroErrType::RCU_TRAILER_ERROR: + errormessage = " RCU Trailer Error "; + break; + case AltroErrType::RCU_VERSION_ERROR: + errormessage = " RCU Version Error "; + break; + case AltroErrType::RCU_TRAILER_SIZE_ERROR: + errormessage = " RCU Trailer Size Error "; + break; + case AltroErrType::ALTRO_BUNCH_HEADER_ERROR: + errormessage = " ALTRO Bunch Header Error "; + break; + case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR: + errormessage = " ALTRO Bunch Length Error "; + break; + case AltroErrType::ALTRO_PAYLOAD_ERROR: + errormessage = " ALTRO Payload Error "; + break; + case AltroErrType::ALTRO_MAPPING_ERROR: + errormessage = " ALTRO Mapping Error "; + break; + case AltroErrType::CHANNEL_ERROR: + errormessage = " Channel Error "; + break; + default: + break; + }; + LOG(ERROR) << " EMCAL raw task: " << errormessage << " in DDL " << feeID << std::endl; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + //fill histograms with error types + mOutputDecoderErrors.push_back(errornum); + continue; + } + for (auto minorerror : decoder.getMinorDecodingErrors()) { + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(ERROR) << " EMCAL raw task - Minor error in DDL " << feeID << ": " << minorerror.what() << std::endl; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + ErrorTypeFEE errornum(feeID, ErrorTypeFEE::ErrorSource_t::ALTRO_ERROR, MinorAltroDecodingError::errorTypeToInt(minorerror.getErrorType())); + mOutputDecoderErrors.push_back(errornum); + } - std::cout << decoder.getRCUTrailer() << std::endl; + if (mPrintTrailer) { + // Can become very verbose, therefore must be switched on explicitly in addition + // to high debug level + LOG(DEBUG4) << decoder.getRCUTrailer(); + } + // Apply zero suppression only in case it was enabled + if (decoder.getRCUTrailer().hasZeroSuppression()) { + LOG(DEBUG3) << "Zero suppression enabled"; + } else { + LOG(DEBUG3) << "Zero suppression disabled"; + } + mRawFitter->setIsZeroSuppressed(decoder.getRCUTrailer().hasZeroSuppression()); - o2::emcal::Mapper map = mMapper->getMappingForDDL(feeID); + const auto& map = mMapper->getMappingForDDL(feeID); int iSM = feeID / 2; // Loop over all the channels + int nBunchesNotOK = 0; for (auto& chan : decoder.getChannels()) { int iRow, iCol; @@ -119,34 +252,117 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) iCol = map.getColumn(chan.getHardwareAddress()); chantype = map.getChannelType(chan.getHardwareAddress()); } catch (Mapper::AddressNotFoundException& ex) { - std::cerr << ex.what() << std::endl; + LOG(ERROR) << "Mapping error DDL " << feeID << ": " << ex.what(); continue; - }; + } - int CellID = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iRow, iCol); + if (!(chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN)) { + continue; + } - // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter - double amp = 0., time = 0.; - o2::emcal::CaloFitResults fitResults = mRawFitter->evaluate(chan.getBunches(), 0, 0); - if (fitResults.getAmp() > 0) { - fitResults.setAmp(0.); + auto [phishift, etashift] = mGeometry->ShiftOnlineToOfflineCellIndexes(iSM, iRow, iCol); + int CellID = mGeometry->GetAbsCellIdFromCellIndexes(iSM, phishift, etashift); + if (CellID > 17664) { + if (mNumErrorMessages < mMaxErrorMessages) { + std::string celltypename; + switch (chantype) { + case o2::emcal::ChannelType_t::HIGH_GAIN: + celltypename = "high gain"; + break; + case o2::emcal::ChannelType_t::LOW_GAIN: + celltypename = "low-gain"; + break; + case o2::emcal::ChannelType_t::TRU: + celltypename = "TRU"; + break; + case o2::emcal::ChannelType_t::LEDMON: + celltypename = "LEDMON"; + break; + }; + LOG(ERROR) << "Sending invalid cell ID " << CellID << "(SM " << iSM << ", row " << iRow << " - shift " << phishift << ", col " << iCol << " - shift " << etashift << ") of type " << celltypename; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + mOutputDecoderErrors.emplace_back(feeID, ErrorTypeFEE::ErrorSource_t::GEOMETRY_ERROR, 0); // 0 -> Cell ID out of range + continue; + } + if (CellID < 0) { + if (mNumErrorMessages < mMaxErrorMessages) { + std::string celltypename; + switch (chantype) { + case o2::emcal::ChannelType_t::HIGH_GAIN: + celltypename = "high gain"; + break; + case o2::emcal::ChannelType_t::LOW_GAIN: + celltypename = "low-gain"; + break; + case o2::emcal::ChannelType_t::TRU: + celltypename = "TRU"; + break; + case o2::emcal::ChannelType_t::LEDMON: + celltypename = "LEDMON"; + break; + }; + LOG(ERROR) << "Sending negative cell ID " << CellID << "(SM " << iSM << ", row " << iRow << " - shift " << phishift << ", col " << iCol << " - shift " << etashift << ") of type " << celltypename; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + mOutputDecoderErrors.emplace_back(feeID, ErrorTypeFEE::ErrorSource_t::GEOMETRY_ERROR, -1); // Geometry error codes will start from 100 + continue; } - if (fitResults.getTime() < 0) { - fitResults.setTime(0.); + + // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter + CaloFitResults fitResults; + try { + fitResults = mRawFitter->evaluate(chan.getBunches()); + // Prevent negative entries - we should no longer get here as the raw fit usually will end in an error state + if (fitResults.getAmp() < 0) { + fitResults.setAmp(0.); + } + if (fitResults.getTime() < 0) { + fitResults.setTime(0.); + } + currentCellContainer->emplace_back(CellID, fitResults.getAmp() * CONVADCGEV, fitResults.getTime(), chantype); + } catch (CaloRawFitter::RawFitterError_t& fiterror) { + if (fiterror != CaloRawFitter::RawFitterError_t::BUNCH_NOT_OK) { + // Display + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(ERROR) << "Failure in raw fitting: " << CaloRawFitter::createErrorMessage(fiterror); + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(ERROR) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } + } else { + LOG(DEBUG2) << "Failure in raw fitting: " << CaloRawFitter::createErrorMessage(fiterror); + nBunchesNotOK++; + } + mOutputDecoderErrors.emplace_back(feeID, ErrorTypeFEE::ErrorSource_t::FIT_ERROR, CaloRawFitter::getErrorNumber(fiterror)); } - currentCellContainer->emplace_back(CellID, amp, time, chantype); + } + if (nBunchesNotOK) { + LOG(DEBUG) << "Number of failed bunches: " << nBunchesNotOK; } } } // Loop over BCs, sort cells with increasing tower ID and write to output containers - mOutputCells.clear(); - mOutputTriggerRecords.clear(); for (auto [bc, cells] : cellBuffer) { - mOutputTriggerRecords.emplace_back(bc, mOutputCells.size(), cells->size()); + mOutputTriggerRecords.emplace_back(bc, triggerBuffer[bc], mOutputCells.size(), cells->size()); if (cells->size()) { + LOG(DEBUG) << "Event has " << cells->size() << " cells"; // Sort cells according to cell ID - std::sort(cells->begin(), cells->end(), [](o2::emcal::Cell& lhs, o2::emcal::Cell& rhs) { return lhs.getTower() < rhs.getTower(); }); + std::sort(cells->begin(), cells->end(), [](Cell& lhs, Cell& rhs) { return lhs.getTower() < rhs.getTower(); }); for (auto cell : *cells) { mOutputCells.push_back(cell); } @@ -154,22 +370,53 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) } LOG(DEBUG) << "[EMCALRawToCellConverter - run] Writing " << mOutputCells.size() << " cells ..."; - ctx.outputs().snapshot(o2::framework::Output{"EMC", "CELLS", 0, o2::framework::Lifetime::Timeframe}, mOutputCells); - ctx.outputs().snapshot(o2::framework::Output{"EMC", "CELLSTRGR", 0, o2::framework::Lifetime::Timeframe}, mOutputTriggerRecords); + sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); +} + +bool RawToCellConverterSpec::isLostTimeframe(framework::ProcessingContext& ctx) const +{ + constexpr auto originEMC = header::gDataOriginEMC; + o2::framework::InputSpec dummy{"dummy", + framework::ConcreteDataMatcher{originEMC, + header::gDataDescriptionRawData, + 0xDEADBEEF}}; + for (const auto& ref : o2::framework::InputRecordWalker(ctx.inputs(), {dummy})) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + return true; + } + } + return false; } -o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec() +void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx, const std::vector<o2::emcal::Cell>& cells, const std::vector<o2::emcal::TriggerRecord>& triggers, const std::vector<ErrorTypeFEE>& decodingErrors) const { - std::vector<o2::framework::InputSpec> inputs; + constexpr auto originEMC = o2::header::gDataOriginEMC; + ctx.outputs().snapshot(framework::Output{originEMC, "CELLS", mSubspecification, framework::Lifetime::Timeframe}, cells); + ctx.outputs().snapshot(framework::Output{originEMC, "CELLSTRGR", mSubspecification, framework::Lifetime::Timeframe}, triggers); + ctx.outputs().snapshot(framework::Output{originEMC, "DECODERERR", mSubspecification, framework::Lifetime::Timeframe}, decodingErrors); +} + +o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec(bool askDISTSTF, int subspecification) +{ + constexpr auto originEMC = o2::header::gDataOriginEMC; std::vector<o2::framework::OutputSpec> outputs; - outputs.emplace_back("EMC", "CELLS", 0, o2::framework::Lifetime::Timeframe); - outputs.emplace_back("EMC", "CELLSTRGR", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "CELLS", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "CELLSTRGR", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "DECODERERR", subspecification, o2::framework::Lifetime::Timeframe); + + std::vector<o2::framework::InputSpec> inputs{{"stf", o2::framework::ConcreteDataTypeMatcher{originEMC, o2::header::gDataDescriptionRawData}, o2::framework::Lifetime::Optional}}; + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } return o2::framework::DataProcessorSpec{"EMCALRawToCellConverterSpec", - o2::framework::select("A:EMC/RAWDATA"), + inputs, outputs, - o2::framework::adaptFromTask<o2::emcal::reco_workflow::RawToCellConverterSpec>(), + o2::framework::adaptFromTask<o2::emcal::reco_workflow::RawToCellConverterSpec>(subspecification), o2::framework::Options{ - {"fitmethod", o2::framework::VariantType::String, "standard", {"Fit method (standard or gamma2)"}}}}; + {"fitmethod", o2::framework::VariantType::String, "gamma2", {"Fit method (standard or gamma2)"}}, + {"maxmessage", o2::framework::VariantType::Int, 100, {"Max. amout of error messages to be displayed"}}, + {"printtrailer", o2::framework::VariantType::Bool, false, {"Print RCU trailer (for debugging)"}}}}; } diff --git a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx index d7c7fb7f03446..528be3775953f 100644 --- a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx +++ b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include "DataFormatsEMCAL/Cell.h" #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/Cluster.h" +#include "DataFormatsEMCAL/ErrorTypeFEE.h" #include "EMCALWorkflow/RecoWorkflow.h" #include "EMCALWorkflow/CellConverterSpec.h" #include "EMCALWorkflow/ClusterizerSpec.h" @@ -44,7 +46,9 @@ namespace reco_workflow { o2::framework::WorkflowSpec getWorkflow(bool propagateMC, + bool askDISTSTF, bool enableDigitsPrinter, + int subspecification, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, @@ -67,7 +71,7 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, std::unordered_map<InputType, std::vector<OutputType>> allowedIO; allowedIO[InputType::Digits] = std::vector<OutputType>{OutputType::Cells, OutputType::Clusters, OutputType::AnalysisClusters}; - allowedIO[InputType::Cells] = std::vector<OutputType>{OutputType::Clusters, OutputType::AnalysisClusters}; + allowedIO[InputType::Cells] = std::vector<OutputType>{OutputType::Cells, OutputType::Clusters, OutputType::AnalysisClusters}; allowedIO[InputType::Raw] = std::vector<OutputType>{OutputType::Cells}; InputType inputType; @@ -164,9 +168,9 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, // add converter for cells if (inputType == InputType::Digits) { specs.emplace_back(o2::emcal::reco_workflow::getCellConverterSpec(propagateMC)); - } else { + } else if (inputType == InputType::Raw) { // raw data will come from upstream - specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec()); + specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec(askDISTSTF, subspecification)); } } @@ -237,11 +241,12 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, }; auto makeWriterSpec_CellsTR = [checkReady](const char* processName, const char* defaultFileName, const char* defaultTreeName, - auto&& CellsBranch, auto&& TriggerRecordBranch) { + auto&& CellsBranch, auto&& TriggerRecordBranch, auto&& DecoderErrorsBranch) { return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, std::move(CellsBranch), - std::move(TriggerRecordBranch))); + std::move(TriggerRecordBranch), + std::move(DecoderErrorsBranch))); }; /* // RS getting input digits and outputing them under the same outputspec will create dependency loop when piping the workflows @@ -279,6 +284,7 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, } else { using CellsDataType = std::vector<o2::emcal::Cell>; using TriggerRecordDataType = std::vector<o2::emcal::TriggerRecord>; + using DecoderErrorsDataType = std::vector<o2::emcal::ErrorTypeFEE>; specs.push_back(makeWriterSpec_CellsTR("emcal-cells-writer", "emccells.root", "o2sim", @@ -287,7 +293,10 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, "cell-branch-name"}, BranchDefinition<TriggerRecordDataType>{o2::framework::InputSpec{"trigger", "EMC", "CELLSTRGR", 0}, "EMCALCellTRGR", - "celltrigger-branch-name"})()); + "celltrigger-branch-name"}, + BranchDefinition<DecoderErrorsDataType>{o2::framework::InputSpec{"errors", "EMC", "DECODERERR", 0}, + "EMCALDECODERERR", + "decodererror-branch-name"})()); } } diff --git a/Detectors/EMCAL/workflow/src/emc-dcs-data-workflow.cxx b/Detectors/EMCAL/workflow/src/emc-dcs-data-workflow.cxx new file mode 100644 index 0000000000000..d072cf59bf409 --- /dev/null +++ b/Detectors/EMCAL/workflow/src/emc-dcs-data-workflow.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "Framework/TypeTraits.h" +#include <unordered_map> +namespace o2::framework +{ +template <> +struct has_root_dictionary<std::unordered_map<o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue>, void> : std::true_type { +}; +} // namespace o2::framework +#include "Framework/DataProcessorSpec.h" +#include "EMCALWorkflow/EMCALDCSDataProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getEMCALDCSDataProcessorSpec()); + return specs; +} diff --git a/Detectors/EMCAL/workflow/src/emc-dcs-sim-workflow.cxx b/Detectors/EMCAL/workflow/src/emc-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..6ce29c1273d0b --- /dev/null +++ b/Detectors/EMCAL/workflow/src/emc-dcs-sim-workflow.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// // we need to add workflow options before including Framework/runDataProcessing +// void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +// { +// // option allowing to set parameters +// } + +// ------------------------------------------------------------------ + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + // EMC aliases and values for sim + + //DOUBLE type + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"EMC_PT_[00..83]/Temperature", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"EMC_PT_[88..91]/Temperature", 100, 150.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"EMC_PT_[96..159]/Temperature", 200, 250.}); + + // UINT type + //FEE CFG aliases + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_DDL_LIST0", 0x55555555, 0x55555555}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_DDL_LIST1", 0x2AAA, 0x2AAA}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_SRU[00..09]_CFG", 1, 1}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_SRU[10..19]_CFG", 2, 2}); + //TRU aliases + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_SRU[00..19]_FMVER", 0xF0F0F0F0, 0xF0F0F0F0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_PEAKFINDER", 4, 4}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_L0ALGSEL", 5, 5}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_COSMTHRESH", 6, 6}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_GLOBALTHRESH", 7, 7}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK0", 8, 8}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK1", 9, 9}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK2", 10, 10}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK3", 11, 11}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK4", 12, 12}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_TRU[00..45]_MASK5", 13, 13}); + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"EMC_STU_ERROR_COUNT_TRU[0..67]", 1000, 1000}); // not implemented in EMC DCS processor yet + dphints.emplace_back(o2::dcs::test::DataPointHint<uint32_t>{"DMC_STU_ERROR_COUNT_TRU[0..55]", 2000, 2000}); // not implemented in EMC DCS processor yet + + //INT type + // EMCAL STU aliases + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_PATCHSIZE", 101, 101}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GETRAW", 102, 102}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_REGION", 0x103, 0x103}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_MEDIAN", 104, 104}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_FWVERS", 0x105, 0x105}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GA0", 106, 106}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GB0", 107, 107}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GC0", 108, 108}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GA1", 109, 109}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GB1", 110, 110}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_GC1", 111, 111}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JA0", 112, 112}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JB0", 113, 113}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JC0", 114, 114}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JA1", 115, 115}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JB1", 116, 116}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"EMC_STU_JC1", 117, 117}); + // DCAL STU aliases + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_PATCHSIZE", 201, 201}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GETRAW", 202, 202}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_REGION", 0x203, 0x203}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_MEDIAN", 204, 204}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_FWVERS", 0x205, 0x205}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GA0", 206, 206}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GB0", 207, 207}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GC0", 208, 208}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GA1", 209, 209}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GB1", 210, 210}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_GC1", 211, 211}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JA0", 212, 212}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JB0", 213, 213}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JC0", 214, 214}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JA1", 215, 215}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JB1", 216, 216}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_JC1", 217, 217}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"DMC_STU_PHOS_scale[0..3]", 218, 218}); + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "EMC")); + return specs; +} diff --git a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx index b4579e5848808..fa7b00da9d035 100644 --- a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include "Framework/ConfigParamSpec.h" #include "EMCALWorkflow/RecoWorkflow.h" #include "Algorithm/RangeTokenizer.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "CommonUtils/ConfigurableParam.h" #include <string> #include <stdexcept> @@ -32,8 +35,13 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"do not initialize root files readers"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not initialize root file writers"}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, - }; + {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"subspecification", o2::framework::VariantType::Int, 0, {"Subspecification in case the workflow runs in parallel on multiple nodes (i.e. different FLPs)"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -53,11 +61,18 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) /// This function hooks up the the workflow specifications into the DPL driver. o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { - //bla - return o2::emcal::reco_workflow::getWorkflow(not cfgc.options().get<bool>("disable-mc"), // - cfgc.options().get<bool>("enable-digits-printer"), // - cfgc.options().get<std::string>("input-type"), // - cfgc.options().get<std::string>("output-type"), // - cfgc.options().get<bool>("disable-root-input"), - cfgc.options().get<bool>("disable-root-output")); + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + auto wf = o2::emcal::reco_workflow::getWorkflow(!cfgc.options().get<bool>("disable-mc"), + !cfgc.options().get<bool>("ignore-dist-stf"), + cfgc.options().get<bool>("enable-digits-printer"), + cfgc.options().get<int>("subspecification"), + cfgc.options().get<std::string>("input-type"), + cfgc.options().get<std::string>("output-type"), + cfgc.options().get<bool>("disable-root-input"), + cfgc.options().get<bool>("disable-root-output")); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); + + return std::move(wf); } diff --git a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx index a6e34eddf3e95..2fe9aefcb5ed2 100644 --- a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/CMakeLists.txt b/Detectors/FIT/CMakeLists.txt index 62bf1cd0a9b11..43cc48f69bb16 100644 --- a/Detectors/FIT/CMakeLists.txt +++ b/Detectors/FIT/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(FT0) add_subdirectory(common) @@ -14,3 +15,4 @@ add_subdirectory(raw) add_subdirectory(FV0) add_subdirectory(FDD) add_subdirectory(macros) +add_subdirectory(workflow) diff --git a/Detectors/FIT/FDD/CMakeLists.txt b/Detectors/FIT/FDD/CMakeLists.txt index f9ecc0c9f62be..940cdd85b9441 100644 --- a/Detectors/FIT/FDD/CMakeLists.txt +++ b/Detectors/FIT/FDD/CMakeLists.txt @@ -1,14 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(raw) add_subdirectory(simulation) add_subdirectory(reconstruction) add_subdirectory(workflow) diff --git a/Detectors/FIT/FDD/base/CMakeLists.txt b/Detectors/FIT/FDD/base/CMakeLists.txt index 623d659cbbb18..18a13fb34f2a2 100644 --- a/Detectors/FIT/FDD/base/CMakeLists.txt +++ b/Detectors/FIT/FDD/base/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FDDBase SOURCES src/Geometry.cxx - PUBLIC_LINK_LIBRARIES O2::CommonConstants ROOT::Geom FairRoot::Base) + PUBLIC_LINK_LIBRARIES O2::CommonConstants ROOT::Geom FairRoot::Base O2::FrameworkLogger) o2_target_root_dictionary(FDDBase HEADERS include/FDDBase/Geometry.h diff --git a/Detectors/FIT/FDD/base/files/LookupTable_FDD.csv b/Detectors/FIT/FDD/base/files/LookupTable_FDD.csv new file mode 100644 index 0000000000000..7c8f638d07026 --- /dev/null +++ b/Detectors/FIT/FDD/base/files/LookupTable_FDD.csv @@ -0,0 +1,18 @@ +LinkID,EndPointID,CRUID,FEEID,ModuleType,LocalChannelID,channel #,EndPoint/Link,Module,PM channel,HV board,HV channel,MCP S/N,HV cable,signal cable +0,0,0,0,PM,1,0,0/0,PMA0,PMA0/Ch01,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,2,1,0/0,PMA0,PMA0/Ch02,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,3,2,0/0,PMA0,PMA0/Ch03,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,4,3,0/0,PMA0,PMA0/Ch04,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,5,4,0/0,PMA0,PMA0/Ch05,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,6,5,0/0,PMA0,PMA0/Ch06,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,7,6,0/0,PMA0,PMA0/Ch07,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,8,7,0/0,PMA0,PMA0/Ch08,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,1,8,0/1,PMC0,PMC0/Ch01,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,2,9,0/1,PMC0,PMC0/Ch02,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,3,10,0/1,PMC0,PMC0/Ch03,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,4,11,0/1,PMC0,PMC0/Ch04,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,5,12,0/1,PMC0,PMC0/Ch05,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,6,13,0/1,PMC0,PMC0/Ch06,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,7,14,0/1,PMC0,PMC0/Ch07,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,8,15,0/1,PMC0,PMC0/Ch08,0,N/A,N/A,N/A,N/A +2,0,0,2,TCM,,16,0/2,TCM,,,,,, diff --git a/Detectors/FIT/FDD/base/include/FDDBase/Constants.h b/Detectors/FIT/FDD/base/include/FDDBase/Constants.h index b5ff8e91fbea4..5b06fd7378c3e 100644 --- a/Detectors/FIT/FDD/base/include/FDDBase/Constants.h +++ b/Detectors/FIT/FDD/base/include/FDDBase/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,9 +29,10 @@ constexpr short Ntriggers = 5; constexpr float IntTimeRes = 0.4; constexpr float PhotoCathodeEfficiency = 0.18; constexpr float ChargePerADC = 0.6e-12; -constexpr float PMTransitTime = 6.0; // PM response time (corresponds to 1.9 ns rise time) -constexpr float PMTransparency = 0.25; // Transparency of the first dynode of the PM -constexpr float PMNbOfSecElec = 6.0; // Number of secondary electrons emitted from first dynode (per ph.e.) +constexpr float TimePerTDC = 1. / 0.01302; // time conversion from ns to TDC channels +constexpr float PMTransitTime = 6.0; // PM response time (corresponds to 1.9 ns rise time) +constexpr float PMTransparency = 0.25; // Transparency of the first dynode of the PM +constexpr float PMNbOfSecElec = 6.0; // Number of secondary electrons emitted from first dynode (per ph.e.) constexpr int NTimeBinsPerBC = 256; // number of samples per BC diff --git a/Detectors/FIT/FDD/base/include/FDDBase/Geometry.h b/Detectors/FIT/FDD/base/include/FDDBase/Geometry.h index 17cf1543c6621..a8080d1431052 100644 --- a/Detectors/FIT/FDD/base/include/FDDBase/Geometry.h +++ b/Detectors/FIT/FDD/base/include/FDDBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/base/src/FDDBaseLinkDef.h b/Detectors/FIT/FDD/base/src/FDDBaseLinkDef.h index 93c4d3738077a..41d6b6fde02e3 100644 --- a/Detectors/FIT/FDD/base/src/FDDBaseLinkDef.h +++ b/Detectors/FIT/FDD/base/src/FDDBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/base/src/Geometry.cxx b/Detectors/FIT/FDD/base/src/Geometry.cxx index 370dd1c226afb..cc4bc14962be5 100644 --- a/Detectors/FIT/FDD/base/src/Geometry.cxx +++ b/Detectors/FIT/FDD/base/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,8 +18,7 @@ #include <TGeoMedium.h> #include <TGeoVolume.h> #include <TGeoMatrix.h> -#include <FairLogger.h> -#include <sstream> +#include "Framework/Logger.h" ClassImp(o2::fdd::Geometry); diff --git a/Detectors/FIT/FDD/raw/CMakeLists.txt b/Detectors/FIT/FDD/raw/CMakeLists.txt new file mode 100644 index 0000000000000..09e9b2ce90f31 --- /dev/null +++ b/Detectors/FIT/FDD/raw/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FDDRaw + SOURCES src/DataBlockFDD.cxx src/DigitBlockFDD.cxx src/RawReaderFDDBase.cxx src/RawWriterFDD.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::DataFormatsFDD O2::FITRaw) diff --git a/Detectors/FIT/FDD/raw/include/FDDRaw/DataBlockFDD.h b/Detectors/FIT/FDD/raw/include/FDDRaw/DataBlockFDD.h new file mode 100644 index 0000000000000..a1499f3e2de25 --- /dev/null +++ b/Detectors/FIT/FDD/raw/include/FDDRaw/DataBlockFDD.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DataBlockFDD.h class for RAW data format data blocks at FDD +// +// Artur.Furs +// afurs@cern.ch +// + +#ifndef ALICEO2_FIT_DATABLOCKFDD_H_ +#define ALICEO2_FIT_DATABLOCKFDD_H_ +#include <DataFormatsFDD/RawEventData.h> +#include <FITRaw/DataBlockFIT.h> + +namespace o2 +{ +namespace fdd +{ +//Raw event data for FDD +using RawHeaderPM = o2::fdd::EventHeader; +using RawDataPM = o2::fdd::EventData; +using RawHeaderTCM = o2::fdd::EventHeader; +using RawDataTCM = o2::fdd::TCMdata; +using RawHeaderTCMext = o2::fdd::EventHeader; +using RawDataTCMext = o2::fdd::TCMdataExtended; +//Data block for FDD modules +using DataBlockPM = o2::fit::DataBlockPM<RawHeaderPM, RawDataPM>; +using DataBlockTCM = o2::fit::DataBlockTCM<RawHeaderTCM, RawDataTCM>; +using DataBlockTCMext = o2::fit::DataBlockTCMext<RawHeaderTCMext, RawDataTCM, RawDataTCMext>; +} // namespace fdd +} // namespace o2 +#endif diff --git a/Detectors/FIT/FDD/raw/include/FDDRaw/DigitBlockFDD.h b/Detectors/FIT/FDD/raw/include/FDDRaw/DigitBlockFDD.h new file mode 100644 index 0000000000000..ea86bfda3d406 --- /dev/null +++ b/Detectors/FIT/FDD/raw/include/FDDRaw/DigitBlockFDD.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DigitBlockFDD.h class for proccessing RAW data into Digits +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_DIGITBLOCKFDD_H_ +#define ALICEO2_FIT_DIGITBLOCKFDD_H_ +#include "FITRaw/DigitBlockFIT.h" +#include "DataFormatsFDD/Digit.h" +#include "DataFormatsFDD/ChannelData.h" +#include "DataFormatsFDD/LookUpTable.h" + +namespace o2 +{ +namespace fdd +{ +//Normal data taking mode +using DigitBlockFDD = DigitBlockFIT<o2::fdd::SingleLUT, o2::fdd::Digit, o2::fdd::ChannelData>; +//TCM extended data taking mode +using DigitBlockFDDext = DigitBlockFIText<o2::fdd::SingleLUT, o2::fdd::Digit, o2::fdd::ChannelData, o2::fdd::TriggersExt>; +} // namespace fdd +} // namespace o2 +#endif diff --git a/Detectors/FIT/FDD/raw/include/FDDRaw/RawReaderFDDBase.h b/Detectors/FIT/FDD/raw/include/FDDRaw/RawReaderFDDBase.h new file mode 100644 index 0000000000000..5b28e3e1209fa --- /dev/null +++ b/Detectors/FIT/FDD/raw/include/FDDRaw/RawReaderFDDBase.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderFDDBase.h Base class for RAW data reading +// +// Artur.Furs +// afurs@cern.ch +// +//Main purpuse is to decode FDD data blocks and push them to DigitBlockFDD for proccess +//Base class only provides static linkID-moduleType conformity + +#ifndef ALICEO2_FIT_RAWREADERFDDBASE_H_ +#define ALICEO2_FIT_RAWREADERFDDBASE_H_ +#include "FDDRaw/DataBlockFDD.h" +#include "FDDRaw/DigitBlockFDD.h" +#include "FITRaw/RawReaderBaseFIT.h" + +namespace o2 +{ +namespace fdd +{ +//Normal TCM mode +using RawReaderFDDBaseNorm = o2::fit::RawReaderBaseFIT<DigitBlockFDD, DataBlockPM, DataBlockTCM>; +//Extended TCM mode +using RawReaderFDDBaseExt = o2::fit::RawReaderBaseFIT<DigitBlockFDDext, DataBlockPM, DataBlockTCMext>; +} // namespace fdd +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FDD/raw/include/FDDRaw/RawWriterFDD.h b/Detectors/FIT/FDD/raw/include/FDDRaw/RawWriterFDD.h new file mode 100644 index 0000000000000..5cb267c40f63f --- /dev/null +++ b/Detectors/FIT/FDD/raw/include/FDDRaw/RawWriterFDD.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawWriterFDD.h Raw writer class for FDD +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_RAWWRITERFDD_H_ +#define ALICEO2_FIT_RAWWRITERFDD_H_ +#include "FDDRaw/DataBlockFDD.h" +#include "FDDRaw/DigitBlockFDD.h" +#include "FITRaw/RawWriterFIT.h" + +namespace o2 +{ +namespace fdd +{ +//Normal TCM mode +using RawWriterFDD = o2::fit::RawWriterFIT<DigitBlockFDD, DataBlockPM, DataBlockTCM>; +//Extended TCM mode +//using RawWriterFDDext = o2::fit::RawWriterFIT<DigitBlockFDDext, DataBlockPM, DataBlockTCMext>; +} // namespace fdd +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FDD/raw/src/DataBlockFDD.cxx b/Detectors/FIT/FDD/raw/src/DataBlockFDD.cxx new file mode 100644 index 0000000000000..944c3dbd598f5 --- /dev/null +++ b/Detectors/FIT/FDD/raw/src/DataBlockFDD.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FDDRaw/DataBlockFDD.h" +//using namespace o2::fdd; diff --git a/Detectors/FIT/FDD/raw/src/DigitBlockFDD.cxx b/Detectors/FIT/FDD/raw/src/DigitBlockFDD.cxx new file mode 100644 index 0000000000000..fe4948ab9480b --- /dev/null +++ b/Detectors/FIT/FDD/raw/src/DigitBlockFDD.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FDDRaw/DigitBlockFDD.h" +//using namespace o2::fdd; diff --git a/Detectors/FIT/FDD/raw/src/RawReaderFDDBase.cxx b/Detectors/FIT/FDD/raw/src/RawReaderFDDBase.cxx new file mode 100644 index 0000000000000..3708c53d3f03b --- /dev/null +++ b/Detectors/FIT/FDD/raw/src/RawReaderFDDBase.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FDDRaw/RawReaderFDDBase.h" +//using namespace o2::fdd; diff --git a/Detectors/FIT/FDD/raw/src/RawWriterFDD.cxx b/Detectors/FIT/FDD/raw/src/RawWriterFDD.cxx new file mode 100644 index 0000000000000..29b364ce400be --- /dev/null +++ b/Detectors/FIT/FDD/raw/src/RawWriterFDD.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FDDRaw/RawWriterFDD.h" diff --git a/Detectors/FIT/FDD/reconstruction/CMakeLists.txt b/Detectors/FIT/FDD/reconstruction/CMakeLists.txt index fe2598fa38f4d..d14ac3e7a3feb 100644 --- a/Detectors/FIT/FDD/reconstruction/CMakeLists.txt +++ b/Detectors/FIT/FDD/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FDDReconstruction SOURCES src/Reconstructor.cxx @@ -21,3 +22,9 @@ o2_target_root_dictionary( HEADERS include/FDDReconstruction/Reconstructor.h include/FDDReconstruction/ReadRaw.h include/FDDReconstruction/CTFCoder.h) + +o2_add_executable( + test-raw2digit + COMPONENT_NAME fdd + SOURCES src/test-raw2digit.cxx + PUBLIC_LINK_LIBRARIES O2::FDDReconstruction) diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h index 9d621f75cbbd6..31685568401be 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -92,6 +93,7 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const Digit>& digitVec, const g using ECB = CTF::base; ec->setHeader(cd.header); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -116,11 +118,12 @@ void CTFCoder::decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec) { CompressedDigits cd; cd.header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cd.header)); ec.print(getPrefix()); #define DECODEFDD(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) // clang-format off DECODEFDD(cd.trigger, CTF::BLC_trigger); - DECODEFDD(cd.bcInc, CTF::BLC_bcInc); + DECODEFDD(cd.bcInc, CTF::BLC_bcInc); DECODEFDD(cd.orbitInc, CTF::BLC_orbitInc); DECODEFDD(cd.nChan, CTF::BLC_nChan); diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h index e5547217f285e..54c8b7b203edb 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h index e43ca4835db0a..91268881f74e6 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,11 +26,14 @@ class Reconstructor public: Reconstructor() = default; ~Reconstructor() = default; - void process(const o2::fdd::Digit& digitBC, gsl::span<const o2::fdd::ChannelData> digitCh, std::vector<o2::fdd::RecPoint>& recPoints) const; + o2::fdd::RecPoint process(o2::fdd::Digit const& digitBC, + gsl::span<const o2::fdd::ChannelData> inChData, + gsl::span<o2::fdd::ChannelDataFloat> outChData); + void finish(); private: - ClassDefNV(Reconstructor, 2); + ClassDefNV(Reconstructor, 3); }; } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/reconstruction/src/CTFCoder.cxx b/Detectors/FIT/FDD/reconstruction/src/CTFCoder.cxx index 82050cd60993a..e4e84a7446cc5 100644 --- a/Detectors/FIT/FDD/reconstruction/src/CTFCoder.cxx +++ b/Detectors/FIT/FDD/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/reconstruction/src/FDDReconstructionLinkDef.h b/Detectors/FIT/FDD/reconstruction/src/FDDReconstructionLinkDef.h index 741a85871df65..ff8dce72fd44a 100644 --- a/Detectors/FIT/FDD/reconstruction/src/FDDReconstructionLinkDef.h +++ b/Detectors/FIT/FDD/reconstruction/src/FDDReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/reconstruction/src/ReadRaw.cxx b/Detectors/FIT/FDD/reconstruction/src/ReadRaw.cxx index a0935f192141e..0e499410f7041 100644 --- a/Detectors/FIT/FDD/reconstruction/src/ReadRaw.cxx +++ b/Detectors/FIT/FDD/reconstruction/src/ReadRaw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -76,29 +77,29 @@ void ReadRaw::readRawData(const LookUpTable& lut) posPayload += sizeof(mTCMdata); LOG(DEBUG) << " Read TCM: posPayload: " << posPayload << " posInFile: " << posInFile; - } else { // is PM payload - posPayload += CRUWordSize - o2::fdd::EventHeader::PayloadSize; // padding is enabled + } else { // is PM payload + posPayload += CRUWordSize - o2::fdd::RawEventData::sPayloadSize; // padding is enabled for (int i = 0; i < eventHeader.nGBTWords; ++i) { - mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i]), o2::fdd::EventData::PayloadSizeFirstWord); - posPayload += o2::fdd::EventData::PayloadSizeFirstWord; - chData = {Short_t(lut.getChannel(link, int(eventData[2 * i].channelID))), - Float_t(eventData[2 * i].time), - Short_t(eventData[2 * i].charge), 0}; + mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i]), o2::fdd::RawEventData::sPayloadSizeFirstWord); + posPayload += o2::fdd::RawEventData::sPayloadSizeFirstWord; + chData = {static_cast<uint8_t>(lut.getChannel(link, int(eventData[2 * i].channelID))), + int(eventData[2 * i].time), + int(eventData[2 * i].charge), 0}; mDigitAccum[intrec].emplace_back(chData); LOG(DEBUG) << " Read 1st half-word: (PMchannel, globalChannel, Q, T, posPayload) = " << std::setw(3) << int(eventData[2 * i].channelID) << std::setw(4) << lut.getChannel(link, int(eventData[2 * i].channelID)) << std::setw(5) << int(eventData[2 * i].charge) - << std::setw(5) << float(eventData[2 * i].time) + << std::setw(5) << int(eventData[2 * i].time) << std::setw(5) << posPayload; Short_t channelIdFirstHalfWord = chData.mPMNumber; - mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i + 1]), EventData::PayloadSizeSecondWord); - posPayload += o2::fdd::EventData::PayloadSizeSecondWord; - chData = {Short_t(lut.getChannel(link, (eventData[2 * i + 1].channelID))), - Float_t(eventData[2 * i + 1].time), - Short_t(eventData[2 * i + 1].charge), 0}; + mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i + 1]), o2::fdd::RawEventData::sPayloadSizeSecondWord); + posPayload += o2::fdd::RawEventData::sPayloadSizeSecondWord; + chData = {static_cast<uint8_t>(lut.getChannel(link, int(eventData[2 * i + 1].channelID))), + int(eventData[2 * i + 1].time), + int(eventData[2 * i + 1].charge), 0}; if (chData.mPMNumber <= channelIdFirstHalfWord) { // Don't save the second half-word if it is only filled with zeroes (empty-data) // TODO: Verify if it works correctly with real data from readout @@ -109,7 +110,7 @@ void ReadRaw::readRawData(const LookUpTable& lut) << std::setw(3) << int(eventData[2 * i + 1].channelID) << std::setw(4) << lut.getChannel(link, int(eventData[2 * i + 1].channelID)) << std::setw(5) << int(eventData[2 * i + 1].charge) - << std::setw(5) << float(eventData[2 * i + 1].time) + << std::setw(5) << int(eventData[2 * i + 1].time) << std::setw(5) << posPayload; } } @@ -152,7 +153,7 @@ void ReadRaw::writeDigits(const std::string& outputDigitsFilePath) size_t nStored = 0; size_t first = chDataVecTree.size(); for (auto& sec : digit.second) { - chDataVecTree.emplace_back(int(sec.mPMNumber), float(sec.mTime), short(sec.mChargeADC), short(0)); + chDataVecTree.emplace_back(sec.mPMNumber, sec.mTime, sec.mChargeADC, sec.mFEEBits); nStored++; } chBcVecTree.emplace_back(first, nStored, digit.first, Triggers()); diff --git a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx index 7bfcca22dedb1..49a4f44294429 100644 --- a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx +++ b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,21 +14,30 @@ #include "CommonDataFormat/InteractionRecord.h" #include "FDDReconstruction/Reconstructor.h" +#include "FDDBase/Constants.h" +#include <DataFormatsFDD/ChannelData.h> +#include <DataFormatsFDD/Digit.h> #include "FairLogger.h" using namespace o2::fdd; //_____________________________________________________________________ -void Reconstructor::process(const o2::fdd::Digit& digitBC, gsl::span<const o2::fdd::ChannelData> digitCh, std::vector<o2::fdd::RecPoint>& recPoints) const +o2::fdd::RecPoint Reconstructor::process(o2::fdd::Digit const& digitBC, + gsl::span<const o2::fdd::ChannelData> inChData, + gsl::span<o2::fdd::ChannelDataFloat> outChData) { //Compute charge weighted average time Double_t timeFDA = 0, timeFDC = 0; Double_t weightFDA = 0.0, weightFDC = 0.0; - for (const auto& channel : digitCh) { - Float_t adc = channel.mChargeADC; - Float_t time = channel.mTime; - //LOG(INFO) <<adc <<" "<<time; + int nch = inChData.size(); + for (int ich = 0; ich < nch; ich++) { + outChData[ich] = o2::fdd::ChannelDataFloat{inChData[ich].mPMNumber, + (inChData[ich].mTime) * TimePerTDC, + (double)inChData[ich].mChargeADC, + 0}; // Fill with ADC number once implemented + Float_t adc = outChData[ich].mChargeADC; + Float_t time = outChData[ich].mTime; if (time == o2::InteractionRecord::DummyTime) { continue; } @@ -35,7 +45,7 @@ void Reconstructor::process(const o2::fdd::Digit& digitBC, gsl::span<const o2::f if (adc > 1) { timeErr = 1 / adc; } - if (channel.mPMNumber < 8) { + if (outChData[ich].mPMNumber < 8) { timeFDC += time / (timeErr * timeErr); weightFDC += 1. / (timeErr * timeErr); } else { @@ -43,10 +53,13 @@ void Reconstructor::process(const o2::fdd::Digit& digitBC, gsl::span<const o2::f weightFDA += 1. / (timeErr * timeErr); } } - timeFDA = (weightFDA > 1) ? timeFDA / weightFDA : o2::InteractionRecord::DummyTime; - timeFDC = (weightFDC > 1) ? timeFDC / weightFDC : o2::InteractionRecord::DummyTime; + const int nsToPs = 1e3; + std::array<int, 2> mCollisionTime = {o2::fdd::RecPoint::sDummyCollissionTime, o2::fdd::RecPoint::sDummyCollissionTime}; - recPoints.emplace_back(timeFDA, timeFDC, digitBC.getIntRecord()); + mCollisionTime[o2::fdd::RecPoint::TimeA] = (weightFDA > 1) ? round(timeFDA / weightFDA * nsToPs) : o2::fdd::RecPoint::sDummyCollissionTime; + mCollisionTime[o2::fdd::RecPoint::TimeC] = (weightFDC > 1) ? round(timeFDC / weightFDC * nsToPs) : o2::fdd::RecPoint::sDummyCollissionTime; + + return RecPoint{mCollisionTime, digitBC.ref.getFirstEntry(), digitBC.ref.getEntries(), digitBC.getIntRecord(), digitBC.mTriggers}; } //________________________________________________________ void Reconstructor::finish() diff --git a/Detectors/FIT/FDD/reconstruction/src/test-raw2digit.cxx b/Detectors/FIT/FDD/reconstruction/src/test-raw2digit.cxx new file mode 100644 index 0000000000000..76ff1459c9e35 --- /dev/null +++ b/Detectors/FIT/FDD/reconstruction/src/test-raw2digit.cxx @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TSystem.h> +#include <TTree.h> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/Logger.h" +#include "DataFormatsFDD/Digit.h" +#include <TFile.h> +#include <cstring> + +using namespace o2::fdd; +int main() +{ + struct EventFDD_t { + o2::fdd::Digit mDigit; + std::vector<o2::fdd::ChannelData> mVecChannelData; + bool operator==(const EventFDD_t& other) const + { + return mDigit == other.mDigit && mVecChannelData == other.mVecChannelData; + } + void print() const + { + mDigit.printLog(); + for (const auto& entry : mVecChannelData) { + entry.printLog(); + } + } + }; + std::vector<EventFDD_t> vecTotalEvents, vecTotalEvents2; + gSystem->Exec("$O2_ROOT/bin/o2-sim -n 10 -m FDD -g pythia8pp"); + gSystem->Exec("$O2_ROOT/bin/o2-sim-digitizer-workflow -b"); + TFile flIn("fdddigits.root"); + std::unique_ptr<TTree> treeInput((TTree*)flIn.Get("o2sim")); + std::vector<Digit> vecDigits; + std::vector<Digit>* ptrVecDigits = &vecDigits; + std::vector<ChannelData> vecChannelData; + std::vector<ChannelData>* ptrVecChannelData = &vecChannelData; + treeInput->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries:" << treeInput->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFDD = EventFDD_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents.push_back(eventFDD); + } + } + std::cout << "\n===================================\n"; + for (auto const& entry : vecTotalEvents) { + entry.print(); + } + std::cout << "\n===================================\n"; + + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents.size() << std::endl; + std::cout << "Simulation completed!" << std::endl; + gSystem->Exec("$O2_ROOT/bin/o2-fdd-digit2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\""); + gSystem->Exec("$O2_ROOT/bin/o2-raw-file-reader-workflow -b --input-conf FDDraw.cfg --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\"|$O2_ROOT/bin/o2-fdd-flp-dpl-workflow -b"); + TFile flIn2("o2_fdddigits.root"); + std::unique_ptr<TTree> treeInput2((TTree*)flIn2.Get("o2sim")); + std::cout << "Reconstruction completed!" << std::endl; + + treeInput2->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput2->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries: " << treeInput2->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput2->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput2->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFDD = EventFDD_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents2.push_back(eventFDD); + } + } + std::cout << "\n===================================\n"; + for (auto const& entry : vecTotalEvents2) { + entry.print(); + } + std::cout << "\n===================================\n"; + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents2.size() << std::endl; + if (vecTotalEvents == vecTotalEvents2) { + std::cout << "TEST IS OK!\n"; + } else { + std::cout << "\nDIFFERENCE BETWEEN SRC AND DEST\n"; + std::cout << "\n===============================\n"; + for (int iEntry = 0; iEntry < std::max(vecTotalEvents.size(), vecTotalEvents2.size()); iEntry++) { + if (iEntry < vecTotalEvents.size() && iEntry < vecTotalEvents2.size()) { + if (vecTotalEvents[iEntry] == vecTotalEvents2[iEntry]) { + continue; + } + } + std::cout << "\nEntryID: " << iEntry; + std::cout << "\n------------------------------SOURCE------------------------------\n"; + if (iEntry < vecTotalEvents.size()) { + vecTotalEvents[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + std::cout << "\n------------------------------DESTINATION------------------------------\n"; + if (iEntry < vecTotalEvents2.size()) { + vecTotalEvents2[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + } + std::cout << "\nERROR!\n"; + } + return 0; +} diff --git a/Detectors/FIT/FDD/simulation/CMakeLists.txt b/Detectors/FIT/FDD/simulation/CMakeLists.txt index e828d6481c0b2..458da3ab5e109 100644 --- a/Detectors/FIT/FDD/simulation/CMakeLists.txt +++ b/Detectors/FIT/FDD/simulation/CMakeLists.txt @@ -1,28 +1,29 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FDDSimulation SOURCES src/Detector.cxx - src/Digitizer.cxx - src/Digits2Raw.cxx - PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat - O2::FDDBase - O2::DataFormatsFDD - O2::DetectorsRaw + src/Digitizer.cxx + src/Digits2Raw.cxx + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat + O2::FDDBase + O2::DataFormatsFDD + O2::DetectorsRaw ROOT::Physics) o2_target_root_dictionary(FDDSimulation HEADERS include/FDDSimulation/Detector.h - include/FDDSimulation/Digitizer.h - include/FDDSimulation/DigitizationParameters.h - include/FDDSimulation/Digits2Raw.h) + include/FDDSimulation/Digitizer.h + include/FDDSimulation/DigitizationParameters.h + include/FDDSimulation/Digits2Raw.h) o2_add_executable(digit2raw COMPONENT_NAME fdd @@ -31,5 +32,5 @@ o2_add_executable(digit2raw O2::DetectorsRaw O2::DetectorsCommonDataFormats O2::CommonUtils - Boost::program_options) - + Boost::program_options + O2::FDDRaw) \ No newline at end of file diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Detector.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Detector.h index 9ea50b4ee45fb..485197b30d0bb 100644 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Detector.h +++ b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/DigitizationParameters.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/DigitizationParameters.h index d66870a0de917..2a0d25839014a 100644 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/DigitizationParameters.h +++ b/Detectors/FIT/FDD/simulation/include/FDDSimulation/DigitizationParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digitizer.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digitizer.h index da6056fdf24e2..c7bd444d5ce63 100644 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digitizer.h +++ b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,8 +36,8 @@ class Digitizer { private: - typedef math_utils::RandomRing<float_v::size() * DigitizationParameters::PheRRSize> HitRandomRingType; - typedef math_utils::RandomRing<float_v::size() * DigitizationParameters::HitRRSize> PheRandomRingType; + typedef math_utils::RandomRing</*float_v::size()*/ 4 * DigitizationParameters::PheRRSize> HitRandomRingType; + typedef math_utils::RandomRing</*float_v::size()*/ 4 * DigitizationParameters::HitRRSize> PheRandomRingType; using ChannelBCDataF = std::array<float, NTimeBinsPerBC>; @@ -65,10 +66,12 @@ class Digitizer void process(const std::vector<o2::fdd::Hit>& hits, std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels); void flush(std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels); void setEventTime(long value) { mEventTime = value; } @@ -93,7 +96,7 @@ class Digitizer BCCache* getBCCache(const o2::InteractionRecord& ir); void storeBC(const BCCache& bc, - std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels); long mEventTime; // TF (run) timestamp diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h index 4df9fb96c70fd..10cec83c8afba 100644 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h +++ b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,6 +49,10 @@ class Digits2Raw void setFilePerLink(bool v) { mOutputPerLink = v; } bool getFilePerLink() const { return mOutputPerLink; } + int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const; + private: static constexpr uint32_t sTcmLink = 2; static constexpr uint16_t sCruId = 0; @@ -56,6 +61,7 @@ class Digits2Raw void makeGBTHeader(EventHeader& eventHeader, int link, o2::InteractionRecord const& mIntRecord); void fillSecondHalfWordAndAddData(int iChannelPerLink, int prevPmLink, const o2::InteractionRecord& ir); RawEventData mRawEventData; + o2::fdd::Triggers mTriggers; o2::raw::RawFileWriter mWriter{"FDD"}; bool mOutputPerLink = false; ///////////////////////////////////////////////// diff --git a/Detectors/FIT/FDD/simulation/src/Detector.cxx b/Detectors/FIT/FDD/simulation/src/Detector.cxx index e579db50e2108..6df71d3dcdb04 100644 --- a/Detectors/FIT/FDD/simulation/src/Detector.cxx +++ b/Detectors/FIT/FDD/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -147,13 +148,13 @@ Bool_t Detector::ProcessHits(FairVolume* vol) static Float_t tlength_ad = 0.; static Int_t nPhotons_ad = 0; - Float_t x, y, z; + static TVector3 vPos; eloss_ad += destep_ad; if (fMC->IsTrackEntering()) { nPhotons_ad = nPhotonsInStep_ad; - fMC->TrackPosition(x, y, z); + fMC->TrackPosition(vPos(0), vPos(1), vPos(2)); eloss_ad = 0.0; return kFALSE; @@ -164,7 +165,6 @@ Bool_t Detector::ProcessHits(FairVolume* vol) Int_t trackID = fMC->GetStack()->GetCurrentTrackNumber(); Float_t time = fMC->TrackTime() * 1.0e9; //time from seconds to ns - TVector3 vPos(x, y, z); addHit(trackID, ADsector, vPos, time, eloss_ad, nPhotons_ad); return kTRUE; diff --git a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx index fdb232dc95d66..130b024ae8f3a 100644 --- a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include <algorithm> #include <cassert> #include <iostream> +#include <Vc/Vc> using namespace o2::math_utils; using namespace o2::fdd; @@ -32,18 +34,19 @@ Digitizer::BCCache::BCCache() void Digitizer::process(const std::vector<o2::fdd::Hit>& hits, std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels) { // loop over all hits and produce digits //LOG(INFO) << "Processing IR = " << mIntRecord << " | NHits = " << hits.size(); - flush(digitsBC, digitsCh, labels); // flush cached signal which cannot be affect by new event + flush(digitsBC, digitsCh, digitsTrig, labels); // flush cached signal which cannot be affect by new event auto sorted_hits{hits}; std::sort(sorted_hits.begin(), sorted_hits.end(), [](o2::fdd::Hit const& a, o2::fdd::Hit const& b) { return a.GetTrackID() < b.GetTrackID(); }); - LOG(INFO) << "Pulse"; + //LOG(INFO) << "Pulse"; //Conversion of hits to the analogue pulse shape for (auto& hit : sorted_hits) { if (hit.GetTime() > 20e3) { @@ -137,7 +140,7 @@ void Digitizer::createPulse(int nPhE, int parID, double timeHit, std::array<o2:: q += Vc::float_v::Size; Vc::prefetchForOneRead(q); workVc.load(p); - workVc += mRndGainVar.getNextValueVc() * charge * pmtVc; + workVc += mRndGainVar.getNextValueVc<Vc::float_v>() * charge * pmtVc; workVc.store(p); p += Vc::float_v::Size; Vc::prefetchForOneRead(p); @@ -155,6 +158,7 @@ void Digitizer::createPulse(int nPhE, int parID, double timeHit, std::array<o2:: //_____________________________________________________________________________ void Digitizer::flush(std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels) { @@ -175,7 +179,7 @@ void Digitizer::flush(std::vector<o2::fdd::Digit>& digitsBC, for (int ibc = 0; ibc < nCached; ibc++) { // digitize BCs which might not be affected by future events auto& bc = mCache[ibc]; - storeBC(bc, digitsBC, digitsCh, labels); + storeBC(bc, digitsBC, digitsCh, digitsTrig, labels); } // clean cache for BCs which are not needed anymore //LOG(INFO) << "Cleaning cache"; @@ -184,21 +188,29 @@ void Digitizer::flush(std::vector<o2::fdd::Digit>& digitsBC, //_____________________________________________________________________________ void Digitizer::storeBC(const BCCache& bc, std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh, + std::vector<o2::fdd::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>& labels) { //LOG(INFO) << "Storing BC " << bc; - int first = digitsCh.size(); + int first = digitsCh.size(), nStored = 0; for (int ic = 0; ic < Nchannels; ic++) { - digitsCh.emplace_back(ic, simulateTimeCFD(bc.pulse[ic]), integrateCharge(bc.pulse[ic]), 0); + float chargeADC = integrateCharge(bc.pulse[ic]); + if (chargeADC != 0) { + digitsCh.emplace_back(ic, int(simulateTimeCFD(bc.pulse[ic])), int(chargeADC), std::rand() % (1 << 8)); + nStored++; + } } //bc.print(); - int nBC = digitsBC.size(); - digitsBC.emplace_back(first, 16, bc, mTriggers); + if (nStored != 0) { + int nBC = digitsBC.size(); + digitsBC.emplace_back(first, nStored, bc, mTriggers); + digitsTrig.emplace_back(bc, 0, 0, 0, 0, 0); - for (const auto& lbl : bc.labels) { - labels.addElement(nBC, lbl); + for (const auto& lbl : bc.labels) { + labels.addElement(nBC, lbl); + } } } @@ -210,7 +222,10 @@ float Digitizer::integrateCharge(const ChannelBCDataF& pulse) //pulse[iBin] /= ChargePerADC; chargeADC += pulse[iBin]; } - //saturation if(chargeADC > )chargeADC = ; + //saturation + if (chargeADC > 4095) { + chargeADC = 4095; + } //LOG(INFO) <<" Charge " << chargeADC; return std::lround(chargeADC); @@ -237,7 +252,8 @@ float Digitizer::simulateTimeCFD(const ChannelBCDataF& pulse) } } //LOG(INFO) <<" Time " << timeCFD; - return timeCFD; + timeCFD *= TimePerTDC; //ns -> counts + return std::lround(timeCFD); } //_____________________________________________________________________________ o2::fdd::Digitizer::BCCache& Digitizer::setBCCache(const o2::InteractionRecord& ir) diff --git a/Detectors/FIT/FDD/simulation/src/Digits2Raw.cxx b/Detectors/FIT/FDD/simulation/src/Digits2Raw.cxx index 94fa25500a227..04876f526f59c 100644 --- a/Detectors/FIT/FDD/simulation/src/Digits2Raw.cxx +++ b/Detectors/FIT/FDD/simulation/src/Digits2Raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ ClassImp(Digits2Raw); void Digits2Raw::readDigits(const std::string& outDir, const std::string& fileDigitsName) { LOG(INFO) << "==============FDD: Digits2Raw::convertDigits" << std::endl; + mWriter.setCarryOverCallBack(this); LookUpTable lut(true); std::string outd = outDir; @@ -62,9 +64,8 @@ void Digits2Raw::readDigits(const std::string& outDir, const std::string& fileDi auto channels = bcd.getBunchChannelData(digitsCh); if (!channels.empty()) { - LOG(DEBUG); - LOG(INFO) << "o2::fdd::Digits2Raw::readDigits(): Start to convertDigits() at ibc = " << ibc << " " << bcd.mIntRecord - << " iCh0:" << bcd.ref.getFirstEntry() << " nentries:" << bcd.ref.getEntries(); + LOG(DEBUG) << "o2::fdd::Digits2Raw::readDigits(): Start to convertDigits() at ibc = " << ibc << " " << bcd.mIntRecord + << " iCh0:" << bcd.ref.getFirstEntry() << " nentries:" << bcd.ref.getEntries(); convertDigits(bcd, channels, lut); } } @@ -101,15 +102,22 @@ void Digits2Raw::convertDigits(o2::fdd::Digit bcdigits, gsl::span<const ChannelD iChannelPerLink = 0; prevPmLink = nLinkPm; } - if (pmchannels[ich].mChargeADC != 0) { - LOG(DEBUG) << " Store data for channel: " << ich << " PmLink = " << nLinkPm << " "; - auto& newData = mRawEventData.mEventData[iChannelPerLink]; - newData.charge = pmchannels[ich].mChargeADC; - newData.time = pmchannels[ich].mTime; - newData.generateFlags(); - newData.channelID = lut.getModChannel(pmchannels[ich].mPMNumber); - iChannelPerLink++; - } + LOG(DEBUG) << " Store data for channel: " << ich << " PmLink = " << nLinkPm << " "; + auto& newData = mRawEventData.mEventData[iChannelPerLink]; + newData.charge = pmchannels[ich].mChargeADC; + newData.time = pmchannels[ich].mTime; + + newData.numberADC = bool(pmchannels[ich].mFEEBits & ChannelData::kNumberADC); + newData.isDoubleEvent = bool(pmchannels[ich].mFEEBits & ChannelData::kIsDoubleEvent); + newData.isTimeInfoNOTvalid = bool(pmchannels[ich].mFEEBits & ChannelData::kIsTimeInfoNOTvalid); + newData.isCFDinADCgate = bool(pmchannels[ich].mFEEBits & ChannelData::kIsCFDinADCgate); + newData.isTimeInfoLate = bool(pmchannels[ich].mFEEBits & ChannelData::kIsTimeInfoLate); + newData.isAmpHigh = bool(pmchannels[ich].mFEEBits & ChannelData::kIsAmpHigh); + newData.isEventInTVDC = bool(pmchannels[ich].mFEEBits & ChannelData::kIsEventInTVDC); + newData.isTimeInfoLost = bool(pmchannels[ich].mFEEBits & ChannelData::kIsTimeInfoLost); + + newData.channelID = lut.getModChannel(pmchannels[ich].mPMNumber); + iChannelPerLink++; if (ich == nch - 1) { fillSecondHalfWordAndAddData(iChannelPerLink, prevPmLink, intRecord); } @@ -119,17 +127,41 @@ void Digits2Raw::convertDigits(o2::fdd::Digit bcdigits, gsl::span<const ChannelD makeGBTHeader(mRawEventData.mEventHeader, sTcmLink, intRecord); mRawEventData.mEventHeader.nGBTWords = 1; auto& tcmdata = mRawEventData.mTCMdata; - tcmdata.vertex = 1; - tcmdata.orA = 1; - tcmdata.orC = 0; - tcmdata.sCen = 0; - tcmdata.cen = 0; - tcmdata.nChanA = 0; - tcmdata.nChanC = 0; - tcmdata.amplA = 0; - tcmdata.amplC = 0; - tcmdata.timeA = 0; - tcmdata.timeC = 0; + mTriggers = bcdigits.mTriggers; + + float ampA = mTriggers.amplA; + float ampC = mTriggers.amplC; + if (ampA > 131071) { + ampA = 131071; //2^17 + } + if (ampC > 131071) { + ampC = 131071; //2^17 + } + tcmdata.vertex = mTriggers.getVertex(); + tcmdata.orA = mTriggers.getOrA(); + tcmdata.orC = mTriggers.getOrC(); + tcmdata.sCen = mTriggers.getSCen(); + tcmdata.cen = mTriggers.getCen(); + tcmdata.nChanA = mTriggers.nChanA; + tcmdata.nChanC = mTriggers.nChanC; + tcmdata.amplA = ampA; + tcmdata.amplC = ampC; + tcmdata.timeA = mTriggers.timeA; + tcmdata.timeC = mTriggers.timeC; + LOG(DEBUG) << " TCM triggers read " + << " time A " << mTriggers.timeA << " time C " << mTriggers.timeC + << " amp A " << ampA << " amp C " << ampC + << " N A " << int(mTriggers.nChanA) << " N C " << int(mTriggers.nChanC) + << " trig " + << " ver " << mTriggers.getVertex() << " A " << mTriggers.getOrA() << " C " << mTriggers.getOrC(); + + LOG(DEBUG) << "TCMdata" + << " time A " << tcmdata.timeA << " time C " << tcmdata.timeC + << " amp A " << tcmdata.amplA << " amp C " << tcmdata.amplC + << " N A " << int(tcmdata.nChanA) << " N C " << int(tcmdata.nChanC) + << " trig " + << " ver " << tcmdata.vertex << " A " << tcmdata.orA << " C " << tcmdata.orC + << " size " << sizeof(tcmdata); auto data = mRawEventData.to_vector(kTRUE); //for tcm module uint32_t linkId = uint32_t(sTcmLink); @@ -171,3 +203,11 @@ void Digits2Raw::fillSecondHalfWordAndAddData(int iChannelPerLink, int prevPmLin LOG(DEBUG) << " Switch prevPmLink: " << prevPmLink << ". Save data with nGBTWords=" << nGBTWords << " in header. Last channel: " << iChannelPerLink; } + +//_____________________________________________________________________________________ +int Digits2Raw::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const +{ + return 0; // do not split, always start new CRU page +} diff --git a/Detectors/FIT/FDD/simulation/src/FDDSimulationLinkDef.h b/Detectors/FIT/FDD/simulation/src/FDDSimulationLinkDef.h index d7ba52a55bf9a..44059b3c5d75e 100644 --- a/Detectors/FIT/FDD/simulation/src/FDDSimulationLinkDef.h +++ b/Detectors/FIT/FDD/simulation/src/FDDSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/simulation/src/digit2raw.cxx b/Detectors/FIT/FDD/simulation/src/digit2raw.cxx index 250aecb36059d..e88facca1f2d1 100644 --- a/Detectors/FIT/FDD/simulation/src/digit2raw.cxx +++ b/Detectors/FIT/FDD/simulation/src/digit2raw.cxx @@ -1,42 +1,43 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file digi2raw.cxx +/// \file digit2raw.cxx /// \author ruben.shahoyan@cern.ch #include <boost/program_options.hpp> -#include <TSystem.h> +#include <filesystem> #include <TFile.h> #include <TStopwatch.h> +#include "Framework/Logger.h" #include <string> #include <iomanip> -#include "Framework/Logger.h" -#include "FairLogger.h" #include "CommonUtils/StringUtils.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DetectorsRaw/HBFUtils.h" -#include "FDDSimulation/Digits2Raw.h" +#include "FDDRaw/RawWriterFDD.h" +#include "DataFormatsParameters/GRPObject.h" -/// MC->raw conversion for FDD +/// MC->raw conversion for FT0 namespace bpo = boost::program_options; -void digi2raw(const std::string& inpName, const std::string& outDir, bool filePerLink, uint32_t rdhV = 6, bool noEmptyHBF = false, - int superPageSizeInB = 1024 * 1024); +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, + const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) { bpo::variables_map vm; bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + - " (Convert FDD digits to CRU raw data)\n"); + "Convert FDD digits to CRU raw data\n"); bpo::options_description opt_hidden(""); bpo::options_description opt_all; bpo::positional_options_description opt_pos; @@ -44,15 +45,19 @@ int main(int argc, char** argv) try { auto add_option = opt_general.add_options(); add_option("help,h", "Print this help message"); + add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); // add_option("input-file,i", bpo::value<std::string>()->default_value(o2::base::NameConf::getDigitsFileName(o2::detectors::DetID::FDD)),"input FDD digits file"); // why not used? add_option("input-file,i", bpo::value<std::string>()->default_value("fdddigits.root"), "input FDD digits file"); - add_option("file-per-link,l", bpo::value<bool>()->default_value(false)->implicit_value(true), "create output file per CRU (default: per layer)"); + add_option("flp-name", bpo::value<std::string>()->default_value("alio2-cr1-flp180-fdd"), "single file per: all,flp,cru,link"); //temporary, beacause FIT deployed only on one node + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,flp,cru,link"); add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); - + add_option("ccdb-path", bpo::value<std::string>()->default_value(""), "CCDB url which contains LookupTable"); + add_option("lut-path", bpo::value<std::string>()->default_value(""), "LookupTable path, e.g. FDD/LookupTable"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -71,43 +76,58 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); - digi2raw(vm["input-file"].as<std::string>(), - vm["output-dir"].as<std::string>(), - vm["file-per-link"].as<bool>(), - vm["rdh-version"].as<uint32_t>(), - vm["no-empty-hbf"].as<bool>()); + digit2raw(vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["verbosity"].as<int>(), + vm["file-for"].as<std::string>(), + vm["rdh-version"].as<uint32_t>(), + vm["no-empty-hbf"].as<bool>(), + vm["flp-name"].as<std::string>(), + vm["ccdb-path"].as<std::string>(), + vm["lut-path"].as<std::string>()); + + o2::raw::HBFUtils::Instance().print(); return 0; } -void digi2raw(const std::string& inpName, const std::string& outDir, bool filePerLink, uint32_t rdhV, bool noEmptyHBF, int superPageSizeInB) +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB) { TStopwatch swTot; swTot.Start(); - o2::fdd::Digits2Raw m2r; - m2r.setFilePerLink(filePerLink); + o2::fdd::RawWriterFDD m2r; + m2r.setFileFor(fileFor); + m2r.setFlpName(flpName); + m2r.setVerbosity(verbosity); + if (ccdbUrl != "") { + m2r.setCCDBurl(ccdbUrl); + } + if (lutPath != "") { + m2r.setLUTpath(lutPath); + } auto& wr = m2r.getWriter(); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + wr.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::FDD)); // must be set explicitly wr.setSuperPageSize(superPageSizeInB); wr.useRDHVersion(rdhV); wr.setDontFillEmptyHBF(noEmptyHBF); + o2::raw::assertOutputDirectory(outDir); + std::string outDirName(outDir); if (outDirName.back() != '/') { outDirName += '/'; } - // if needed, create output directory - if (gSystem->AccessPathName(outDirName.c_str())) { - if (gSystem->mkdir(outDirName.c_str(), kTRUE)) { - LOG(FATAL) << "could not create output directory " << outDirName; - } else { - LOG(INFO) << "created output directory " << outDirName; - } - } - m2r.readDigits(outDirName, inpName); - wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); - //LOG(INFO)<<o2::utils::concat_string(outDirName, wr.getOrigin().str)<<"\n"; + m2r.convertDigitsToRaw(outDirName, inpName); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); // swTot.Stop(); swTot.Print(); diff --git a/Detectors/FIT/FDD/workflow/CMakeLists.txt b/Detectors/FIT/FDD/workflow/CMakeLists.txt index 65cca7cf3aba7..f309794c39f5f 100644 --- a/Detectors/FIT/FDD/workflow/CMakeLists.txt +++ b/Detectors/FIT/FDD/workflow/CMakeLists.txt @@ -1,30 +1,36 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FDDWorkflow SOURCES src/DigitReaderSpec.cxx - src/EntropyEncoderSpec.cxx - src/EntropyDecoderSpec.cxx - src/RecoWorkflow.cxx - src/ReconstructorSpec.cxx - src/RecPointWriterSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + src/RecoWorkflow.cxx + src/ReconstructorSpec.cxx + src/RecPointWriterSpec.cxx src/RecPointReaderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::FDDReconstruction - O2::Framework - O2::DPLUtils) + src/RawReaderFDD.cxx + + PUBLIC_LINK_LIBRARIES O2::DataFormatsFDD + O2::FDDReconstruction + O2::Framework + O2::DPLUtils + O2::FDDRaw) o2_add_executable(reco-workflow COMPONENT_NAME fdd SOURCES src/fdd-reco-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::FDDWorkflow) - + PUBLIC_LINK_LIBRARIES O2::FDDWorkflow + TARGETVARNAME fddrecoexe) + o2_add_executable(entropy-encoder-workflow SOURCES src/entropy-encoder-workflow.cxx COMPONENT_NAME fdd @@ -35,3 +41,14 @@ o2_add_executable(digit-reader-workflow COMPONENT_NAME fdd PUBLIC_LINK_LIBRARIES O2::FDDWorkflow) +o2_add_executable(flp-dpl-workflow + COMPONENT_NAME fdd + SOURCES src/fdd-flp-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::FDDWorkflow O2::FDDRaw O2::FITWorkflow + TARGETVARNAME fddflpexe) + +if(NOT APPLE) + + set_property(TARGET ${fddrecoexe} PROPERTY LINK_WHAT_YOU_USE ON) + +endif() \ No newline at end of file diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitReaderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitReaderSpec.h index aad71d0e33ce3..8b2ea9a8d35e4 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitReaderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,14 +38,15 @@ class DigitReader : public Task void run(ProcessingContext& pc) final; private: - bool mFinished = false; - bool mUseMC = true; // use MC truth + bool mTrigInp = true; // read trigger inputs + bool mUseMC = true; // use MC truth o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; std::string mInputFileName = ""; std::string mDigitTreeName = "o2sim"; std::string mDigitBCBranchName = "FDDDigit"; std::string mDigitChBranchName = "FDDDigitCh"; + std::string mTriggerBranchName = "TRIGGERINPUT"; std::string mDigitMCTruthBranchName = "FDDDigitLabels"; }; diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitWriterSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitWriterSpec.h new file mode 100644 index 0000000000000..7d5fb352faa26 --- /dev/null +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitWriterSpec.h @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FDD_DIGITWRITERSPEC_H +#define O2_FDD_DIGITWRITERSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "DataFormatsFDD/Digit.h" +#include "DataFormatsFDD/MCLabel.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ +namespace fdd +{ + +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getFDDDigitWriterSpec(bool mctruth = true, bool trigInp = true) +{ + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + + // the callback to be set as hook for custom action when the writer is closed + auto finishWriting = [](TFile* outputfile, TTree* outputtree) { + const auto* brArr = outputtree->GetListOfBranches(); + int64_t nent = 0; + for (const auto* brc : *brArr) { + int64_t n = ((const TBranch*)brc)->GetEntries(); + if (nent && (nent != n)) { + LOG(ERROR) << "Branches have different number of entries"; + } + nent = n; + } + outputtree->SetEntries(nent); + outputtree->Write(); + outputfile->Close(); + }; + + // custom handler for labels: + // essentially transform the input container (as registered in the original branch definition) to the special output format for labels + auto customlabelhandler = [](TBranch& branch, std::vector<char> const& labeldata, framework::DataRef const& ref) { + o2::dataformats::ConstMCTruthContainerView<o2::fdd::MCLabel> labels(labeldata); + // make the actual output object by adopting/casting the buffer + // into a split format + o2::dataformats::IOMCTruthContainerView outputcontainer(labeldata); + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); + br->Fill(); + br->ResetAddress(); + }; + + auto labelsdef = BranchDefinition<std::vector<char>>{InputSpec{"labelinput", "FDD", "DIGITLBL"}, + "FDDDigitLabels", "labels-branch-name", + // this branch definition is disabled if MC labels are not processed + (mctruth ? 1 : 0), + customlabelhandler}; + if (trigInp) { + return MakeRootTreeWriterSpec("FDDDigitWriter", + "fdddigits.root", + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + BranchDefinition<std::vector<o2::fdd::Digit>>{InputSpec{"digitBCinput", "FDD", "DIGITSBC"}, "FDDDigit"}, + BranchDefinition<std::vector<o2::fdd::ChannelData>>{InputSpec{"digitChinput", "FDD", "DIGITSCH"}, "FDDDigitCh"}, + BranchDefinition<std::vector<o2::fdd::DetTrigInput>>{InputSpec{"digitTrinput", "FDD", "TRIGGERINPUT"}, "TRIGGERINPUT"}, + std::move(labelsdef))(); + } else { + return MakeRootTreeWriterSpec("FDDDigitWriterRaw", + "o2_fdddigits.root", + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + BranchDefinition<std::vector<o2::fdd::Digit>>{InputSpec{"digitBCinput", "FDD", "DIGITSBC"}, "FDDDigit"}, + BranchDefinition<std::vector<o2::fdd::ChannelData>>{InputSpec{"digitChinput", "FDD", "DIGITSCH"}, "FDDDigitCh"}, + std::move(labelsdef))(); + } +} + +} // end namespace fdd +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_SRC_FDDDIGITWRITERSPEC_H_ */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h index 4b8b4e5bcd309..da3d373a54f4a 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h index 1a7b131fc45fc..8d523e65d16f1 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h new file mode 100644 index 0000000000000..6ed465b6181dd --- /dev/null +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawDataProcessSpec.h + +#ifndef O2_FDD_RAWDATAPROCESSSPEC_H +#define O2_FDD_RAWDATAPROCESSSPEC_H + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/SerializationMethods.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "FDDRaw/DigitBlockFDD.h" +#include "DataFormatsFDD/Digit.h" +#include "DataFormatsFDD/ChannelData.h" + +#include <iostream> +#include <vector> +#include <gsl/span> + +using namespace o2::framework; + +namespace o2 +{ +namespace fdd +{ + +class RawDataProcessSpec : public Task +{ + public: + RawDataProcessSpec(bool dumpEventBlocks) : mDumpEventBlocks(dumpEventBlocks) {} + ~RawDataProcessSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + bool mDumpEventBlocks; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; +}; + +framework::DataProcessorSpec getFDDRawDataProcessSpec(bool dumpProcessor); + +} // namespace fdd +} // namespace o2 + +#endif /* O2_FDDDATAPROCESSDPL_H */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h new file mode 100644 index 0000000000000..74cbd48dccd0f --- /dev/null +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawDataReaderSpec.h + +#ifndef O2_FDD_RAWDATAREADERSPEC_H +#define O2_FDD_RAWDATAREADERSPEC_H + +#include "DataFormatsFDD/LookUpTable.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/SerializationMethods.h" +#include "DPLUtils/DPLRawParser.h" + +#include <iostream> +#include <vector> +#include <gsl/span> +using namespace o2::framework; + +namespace o2 +{ +namespace fdd +{ +template <typename RawReader> +class RawDataReaderSpec : public Task +{ + public: + RawDataReaderSpec(const RawReader& rawReader) : mRawReader(rawReader) {} + RawDataReaderSpec() = default; + ~RawDataReaderSpec() override = default; + void init(InitContext& ic) final { o2::fdd::SingleLUT::Instance().printFullMap(); } + void run(ProcessingContext& pc) final + { + DPLRawParser parser(pc.inputs()); + mRawReader.clear(); + LOG(INFO) << "FDD RawDataReaderSpec"; + uint64_t count = 0; + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + //Proccessing each page + count++; + auto rdhPtr = it.get_if<o2::header::RAWDataHeader>(); + gsl::span<const uint8_t> payload(it.data(), it.size()); + mRawReader.process(payload, rdhPtr->linkID, int(0)); + } + LOG(INFO) << "Pages: " << count; + mRawReader.accumulateDigits(); + mRawReader.makeSnapshot(pc); + } + RawReader mRawReader; +}; + +template <typename RawReader> +framework::DataProcessorSpec getFDDRawDataReaderSpec(const RawReader& rawReader) +{ + LOG(INFO) << "DataProcessorSpec initDataProcSpec() for RawReaderFDD"; + std::vector<OutputSpec> outputSpec; + RawReader::prepareOutputSpec(outputSpec); + return DataProcessorSpec{ + "fdd-datareader-dpl", + o2::framework::select("TF:FDD/RAWDATA"), + outputSpec, + adaptFromTask<RawDataReaderSpec<RawReader>>(rawReader), + Options{}}; +} + +} // namespace fdd +} // namespace o2 + +#endif /* O2_FDDDATAREADERDPL_H */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawReaderFDD.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawReaderFDD.h new file mode 100644 index 0000000000000..89d007fab81ab --- /dev/null +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawReaderFDD.h @@ -0,0 +1,79 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderFDD.h class for RAW data reading +// +// Artur.Furs +// afurs@cern.ch +// +//Main purpuse is to decode FDD data blocks and push them to DigitBlockFDD for proccess +//TODO: prepare wrappers for containers with digits and combine classes below into one template class? +#ifndef ALICEO2_FDD_RAWREADERFDD_H_ +#define ALICEO2_FDD_RAWREADERFDD_H_ +#include <iostream> +#include <vector> +#include <Rtypes.h> +#include "FDDRaw/RawReaderFDDBase.h" + +#include "DataFormatsFDD/Digit.h" +#include "DataFormatsFDD/ChannelData.h" + +#include "Framework/ProcessingContext.h" +#include "Framework/DataAllocator.h" +#include "Framework/OutputSpec.h" +#include <gsl/span> + +namespace o2 +{ +namespace fdd +{ +//Normal TCM mode +class RawReaderFDD : public RawReaderFDDBaseNorm +{ + public: + RawReaderFDD(bool dumpData) : mDumpData(dumpData) {} + RawReaderFDD(const RawReaderFDD&) = default; + + RawReaderFDD() = default; + ~RawReaderFDD() = default; + void clear() + { + mVecDigits.clear(); + mVecChannelData.clear(); + } + void accumulateDigits() + { + getDigits(mVecDigits, mVecChannelData); + LOG(INFO) << "Number of Digits: " << mVecDigits.size(); + LOG(INFO) << "Number of ChannelData: " << mVecChannelData.size(); + if (mDumpData) { + DigitBlockFDD::print(mVecDigits, mVecChannelData); + } + } + static void prepareOutputSpec(std::vector<o2::framework::OutputSpec>& outputSpec) + { + outputSpec.emplace_back(o2::header::gDataOriginFDD, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFDD, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); + } + void makeSnapshot(o2::framework::ProcessingContext& pc) + { + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFDD, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe}, mVecDigits); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFDD, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe}, mVecChannelData); + } + bool mDumpData; + std::vector<Digit> mVecDigits; + std::vector<ChannelData> mVecChannelData; +}; + +} // namespace fdd +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h new file mode 100644 index 0000000000000..3bbab66d16497 --- /dev/null +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FDD_RAWWORKFLOW_H +#define O2_FDD_RAWWORKFLOW_H + +/// @file RawWorkflow.h + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace fdd +{ +framework::WorkflowSpec getFDDRawWorkflow(bool useProcess, + bool dumpProcessor, bool dumpReader, + bool disableRootOut); +} // namespace fdd +} // namespace o2 +#endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointReaderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointReaderSpec.h index 6eaf38585d637..500883d5badfa 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointReaderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,10 +46,12 @@ class RecPointReader : public Task o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; std::vector<o2::fdd::RecPoint>* mRecPoints = nullptr; + std::vector<o2::fdd::ChannelDataFloat>* mChannelData = nullptr; std::string mInputFileName = "o2reco_fdd.root"; std::string mRecPointTreeName = "o2sim"; std::string mRecPointBranchName = "FDDCluster"; + std::string mChannelDataBranchName = "FDDRecChData"; }; /// create a processor spec diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointWriterSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointWriterSpec.h index 7fa95c492eb15..bc31f629ec686 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointWriterSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecPointWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,6 @@ namespace fdd { /// create a processor spec -/// write ITS clusters a root file framework::DataProcessorSpec getFDDRecPointWriterSpec(bool useMC); } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h index 0ec1a84c997e4..2dbd854e34eee 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ namespace o2 { namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC); +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); } // namespace fdd } // namespace o2 #endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h index b8d14ad22b4a4..5b950145a94a0 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,7 @@ class FDDReconstructorDPL : public Task bool mFinished = false; bool mUseMC = true; std::vector<o2::fdd::RecPoint> mRecPoints; + std::vector<o2::fdd::ChannelDataFloat> mRecChData; o2::fdd::Reconstructor mReco; o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; }; diff --git a/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx index dbbcbe1c6c164..56d5a3efb4ee2 100644 --- a/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include "FDDWorkflow/DigitReaderSpec.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "DetectorsCommonDataFormats/NameConf.h" #include <vector> using namespace o2::framework; @@ -37,17 +39,15 @@ DigitReader::DigitReader(bool useMC) void DigitReader::init(InitContext& ic) { - mInputFileName = ic.options().get<std::string>("fdd-digits-infile"); + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("fdd-digits-infile")); } void DigitReader::run(ProcessingContext& pc) { - if (mFinished) { - return; - } - std::vector<o2::fdd::Digit>* digitsBC = nullptr; std::vector<o2::fdd::ChannelData>* digitsCh = nullptr; + std::vector<o2::fdd::DetTrigInput>* digitsTrig = nullptr; o2::dataformats::IOMCTruthContainerView* mcTruthRootBuffer = nullptr; { // load data from files @@ -62,8 +62,12 @@ void DigitReader::run(ProcessingContext& pc) LOG(INFO) << "Loaded FDD digits tree " << mDigitTreeName << " from " << mInputFileName; digTree->SetBranchAddress(mDigitBCBranchName.c_str(), &digitsBC); - digTree->SetBranchAddress(mDigitChBranchName.c_str(), &digitsCh); + + digTree->SetBranchAddress(mTriggerBranchName.c_str(), &digitsTrig); if (mUseMC) { + if (digTree->GetBranch(mDigitChBranchName.c_str())) { + digTree->SetBranchAddress(mDigitChBranchName.c_str(), &digitsCh); + } if (digTree->GetBranch(mDigitMCTruthBranchName.c_str())) { digTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mcTruthRootBuffer); LOG(INFO) << "Will use MC-truth from " << mDigitMCTruthBranchName; @@ -80,8 +84,11 @@ void DigitReader::run(ProcessingContext& pc) LOG(INFO) << "FDD DigitReader pushes " << digitsBC->size() << " digits"; pc.outputs().snapshot(Output{mOrigin, "DIGITSBC", 0, Lifetime::Timeframe}, *digitsBC); pc.outputs().snapshot(Output{mOrigin, "DIGITSCH", 0, Lifetime::Timeframe}, *digitsCh); + if (mUseMC) { // TODO: To be replaced with sending ConstMCTruthContainer as soon as reco workflow supports it + pc.outputs().snapshot(Output{mOrigin, "TRIGGERINPUT", 0, Lifetime::Timeframe}, *digitsTrig); + std::vector<char> flatbuffer; mcTruthRootBuffer->copyandflatten(flatbuffer); o2::dataformats::MCTruthContainer<o2::fdd::MCLabel> mcTruth; @@ -89,7 +96,7 @@ void DigitReader::run(ProcessingContext& pc) pc.outputs().snapshot(Output{mOrigin, "DIGITLBL", 0, Lifetime::Timeframe}, mcTruth); } - mFinished = true; + pc.services().get<ControlService>().endOfStream(); pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); } @@ -99,6 +106,7 @@ DataProcessorSpec getFDDDigitReaderSpec(bool useMC) outputSpec.emplace_back(o2::header::gDataOriginFDD, "DIGITSBC", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFDD, "DIGITSCH", 0, Lifetime::Timeframe); if (useMC) { + outputSpec.emplace_back(o2::header::gDataOriginFDD, "TRIGGERINPUT", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFDD, "DIGITLBL", 0, Lifetime::Timeframe); } @@ -108,7 +116,8 @@ DataProcessorSpec getFDDDigitReaderSpec(bool useMC) outputSpec, AlgorithmSpec{adaptFromTask<DigitReader>()}, Options{ - {"fdd-digits-infile", VariantType::String, "fdddigits.root", {"Name of the input file"}}}}; + {"fdd-digits-infile", VariantType::String, "fdddigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx index b0af83a9fbbb4..a302c14a81d25 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("fdd-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -64,15 +65,15 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) DataProcessorSpec getEntropyDecoderSpec() { std::vector<OutputSpec> outputs{ - OutputSpec{{"digits"}, "FDD", "FDDDigit", 0, Lifetime::Timeframe}, - OutputSpec{{"channels"}, "FDD", "FDDDigitCh", 0, Lifetime::Timeframe}}; + OutputSpec{{"digits"}, "FDD", "DIGITSBC", 0, Lifetime::Timeframe}, + OutputSpec{{"channels"}, "FDD", "DIGITSCH", 0, Lifetime::Timeframe}}; return DataProcessorSpec{ "fdd-entropy-decoder", Inputs{InputSpec{"ctf", "FDD", "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"fdd-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx index b3d9b6b332d97..911931e410aed 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("fdd-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -63,15 +64,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) DataProcessorSpec getEntropyEncoderSpec() { std::vector<InputSpec> inputs; - inputs.emplace_back("digits", "FDD", "FDDDigit", 0, Lifetime::Timeframe); - inputs.emplace_back("channels", "FDD", "FDDDigitCh", 0, Lifetime::Timeframe); + inputs.emplace_back("digits", "FDD", "DIGITSBC", 0, Lifetime::Timeframe); + inputs.emplace_back("channels", "FDD", "DIGITSCH", 0, Lifetime::Timeframe); return DataProcessorSpec{ "fdd-entropy-encoder", inputs, Outputs{{"FDD", "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"fdd-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx b/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx new file mode 100644 index 0000000000000..e059c6fc13d2f --- /dev/null +++ b/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawDataProcessSpec.cxx + +#include "FDDWorkflow/RawDataProcessSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fdd +{ +using namespace std; +void RawDataProcessSpec::init(InitContext& ic) +{ +} + +void RawDataProcessSpec::run(ProcessingContext& pc) +{ + LOG(INFO) << "RawDataProcessSpec running..."; + auto vecDigits = pc.inputs().get<std::vector<Digit>>("digits"); + auto vecChannelData = pc.inputs().get<std::vector<ChannelData>>("digch"); + if (mDumpEventBlocks) { + DigitBlockFDD::print(vecDigits, vecChannelData); + } +} + +DataProcessorSpec getFDDRawDataProcessSpec(bool dumpProcessor) +{ + std::vector<InputSpec> inputSpec; + inputSpec.emplace_back("digits", o2::header::gDataOriginFDD, "DIGITSBC", 0, Lifetime::Timeframe); + inputSpec.emplace_back("digch", o2::header::gDataOriginFDD, "DIGITSCH", 0, Lifetime::Timeframe); + LOG(INFO) << "DataProcessorSpec getRawDataProcessSpec"; + return DataProcessorSpec{ + "fdd-dataprocess-dpl-flp", + inputSpec, + Outputs{}, + AlgorithmSpec{adaptFromTask<RawDataProcessSpec>(dumpProcessor)}, + Options{}}; +} + +} // namespace fdd +} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx new file mode 100644 index 0000000000000..631655d3038ec --- /dev/null +++ b/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawDataReaderSpec.cxx + +#include "FDDWorkflow/RawDataReaderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fdd +{ + +} // namespace fdd +} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawReaderFDD.cxx b/Detectors/FIT/FDD/workflow/src/RawReaderFDD.cxx new file mode 100644 index 0000000000000..ff470a6315898 --- /dev/null +++ b/Detectors/FIT/FDD/workflow/src/RawReaderFDD.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FDDWorkflow/RawReaderFDD.h" +using namespace o2::fdd; diff --git a/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx new file mode 100644 index 0000000000000..c9816b9b8e1da --- /dev/null +++ b/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawWorkflow.cxx + +#include "FDDWorkflow/RawWorkflow.h" +#include "FDDWorkflow/RawDataProcessSpec.h" +#include "FDDWorkflow/RawDataReaderSpec.h" +#include "FDDWorkflow/DigitWriterSpec.h" +#include "FDDWorkflow/RawReaderFDD.h" +namespace o2 +{ +namespace fdd +{ + +framework::WorkflowSpec getFDDRawWorkflow(bool useProcess, + bool dumpProcessor, bool dumpReader, + bool disableRootOut) +{ + LOG(INFO) << "framework::WorkflowSpec getFDDWorkflow"; + framework::WorkflowSpec specs; + specs.emplace_back(o2::fdd::getFDDRawDataReaderSpec(RawReaderFDD{dumpReader})); + + if (useProcess) { + specs.emplace_back(o2::fdd::getFDDRawDataProcessSpec(dumpProcessor)); + } + if (!disableRootOut) { + specs.emplace_back(o2::fdd::getFDDDigitWriterSpec(false, false)); + } + return specs; +} + +} // namespace fdd +} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx index 2fd688e96c490..e32f78a0683c2 100644 --- a/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/Logger.h" #include "FDDWorkflow/RecPointReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; using namespace o2::fdd; @@ -37,7 +39,8 @@ RecPointReader::RecPointReader(bool useMC) void RecPointReader::init(InitContext& ic) { - mInputFileName = ic.options().get<std::string>("fdd-recpoints-infile"); + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("fdd-recpoints-infile")); connectTree(mInputFileName); } @@ -47,8 +50,9 @@ void RecPointReader::run(ProcessingContext& pc) assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(INFO) << "FDD RecPointReader pushes " << mRecPoints->size() << " recpoints at entry " << ent; + LOG(INFO) << "FDD RecPointReader pushes " << mRecPoints->size() << " recpoints with " << mChannelData->size() << " channels at entry " << ent; pc.outputs().snapshot(Output{mOrigin, "RECPOINTS", 0, Lifetime::Timeframe}, *mRecPoints); + pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0, Lifetime::Timeframe}, *mChannelData); if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get<ControlService>().endOfStream(); @@ -65,6 +69,7 @@ void RecPointReader::connectTree(const std::string& filename) assert(mTree); mTree->SetBranchAddress(mRecPointBranchName.c_str(), &mRecPoints); + mTree->SetBranchAddress(mChannelDataBranchName.c_str(), &mChannelData); if (mUseMC) { LOG(WARNING) << "MC-truth is not supported for FDD recpoints currently"; mUseMC = false; @@ -77,6 +82,7 @@ DataProcessorSpec getFDDRecPointReaderSpec(bool useMC) { std::vector<OutputSpec> outputSpec; outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECPOINTS", 0, Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECCHDATA", 0, Lifetime::Timeframe); if (useMC) { LOG(WARNING) << "MC-truth is not supported for FDD recpoints currently"; } @@ -87,7 +93,8 @@ DataProcessorSpec getFDDRecPointReaderSpec(bool useMC) outputSpec, AlgorithmSpec{adaptFromTask<RecPointReader>()}, Options{ - {"fdd-recpoints-infile", VariantType::String, "o2reco_fdd.root", {"Name of the input file"}}}}; + {"fdd-recpoints-infile", VariantType::String, "o2reco_fdd.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/src/RecPointWriterSpec.cxx b/Detectors/FIT/FDD/workflow/src/RecPointWriterSpec.cxx index a359e601ef25e..dee3af0650fd6 100644 --- a/Detectors/FIT/FDD/workflow/src/RecPointWriterSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecPointWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,6 +29,7 @@ using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; DataProcessorSpec getFDDRecPointWriterSpec(bool useMC) { using RecPointsType = std::vector<o2::fdd::RecPoint>; + using ChanDataType = std::vector<o2::fdd::ChannelDataFloat>; // Spectators for logging auto logger = [](RecPointsType const& recPoints) { LOG(INFO) << "FDDRecPointWriter pulled " << recPoints.size() << " RecPoints"; @@ -39,7 +41,10 @@ DataProcessorSpec getFDDRecPointWriterSpec(bool useMC) "FDDCluster", "fdd-recpoint-branch-name", 1, - logger})(); + logger}, + BranchDefinition<ChanDataType>{InputSpec{"recChData", "FDD", "RECCHDATA", 0}, + "FDDRecChData", + "fdd-rechhdata-branch-name"})(); } } // namespace fdd diff --git a/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx index adb0d8d5b72e3..e7c5932d4b6ec 100644 --- a/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,13 +22,17 @@ namespace o2 namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC) +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) { framework::WorkflowSpec specs; - specs.emplace_back(o2::fdd::getFDDRecPointWriterSpec(useMC)); + if (!disableRootInp) { + specs.emplace_back(o2::fdd::getFDDRecPointWriterSpec(useMC)); + } specs.emplace_back(o2::fdd::getFDDReconstructorSpec(useMC)); - specs.emplace_back(o2::fdd::getFDDDigitReaderSpec(useMC)); + if (!disableRootOut) { + specs.emplace_back(o2::fdd::getFDDDigitReaderSpec(useMC)); + } return specs; } diff --git a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx index 3cacc248e5fda..5ecd3da9f7ac3 100644 --- a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -47,16 +48,20 @@ void FDDReconstructorDPL::run(ProcessingContext& pc) } int nDig = digitsBC.size(); mRecPoints.reserve(nDig); + mRecChData.resize(digitsCh.size()); for (int id = 0; id < nDig; id++) { const auto& digit = digitsBC[id]; auto channels = digit.getBunchChannelData(digitsCh); - mReco.process(digit, channels, mRecPoints); + gsl::span<o2::fdd::ChannelDataFloat> out_ch(mRecChData); + out_ch = out_ch.subspan(digit.ref.getFirstEntry(), digit.ref.getEntries()); + mRecPoints.emplace_back(mReco.process(digit, channels, out_ch)); } // do we ignore MC in this task? LOG(INFO) << "FDD reconstruction pushes " << mRecPoints.size() << " RecPoints"; pc.outputs().snapshot(Output{mOrigin, "RECPOINTS", 0, Lifetime::Timeframe}, mRecPoints); + pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0, Lifetime::Timeframe}, mRecChData); mFinished = true; pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); @@ -73,6 +78,7 @@ DataProcessorSpec getFDDReconstructorSpec(bool useMC) // inputSpec.emplace_back("labels", o2::header::gDataOriginFDD, "DIGITSMCTR", 0, Lifetime::Timeframe); } outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECPOINTS", 0, Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECCHDATA", 0, Lifetime::Timeframe); return DataProcessorSpec{ "fdd-reconstructor", diff --git a/Detectors/FIT/FDD/workflow/src/digits-reader-workflow.cxx b/Detectors/FIT/FDD/workflow/src/digits-reader-workflow.cxx index de9c7439b9aac..fa861f7e64715 100644 --- a/Detectors/FIT/FDD/workflow/src/digits-reader-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/digits-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(const ConfigContext& ctx) { WorkflowSpec specs; - + o2::conf::ConfigurableParam::updateFromString(ctx.options().get<std::string>("configKeyValues")); DataProcessorSpec producer = o2::fdd::getFDDDigitReaderSpec(ctx.options().get<bool>("disable-mc")); specs.push_back(producer); return specs; diff --git a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx index 87a8b05d20357..2adcfe0a1c422 100644 --- a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FDD/workflow/src/fdd-flp-workflow.cxx b/Detectors/FIT/FDD/workflow/src/fdd-flp-workflow.cxx new file mode 100644 index 0000000000000..1c8862ef7840b --- /dev/null +++ b/Detectors/FIT/FDD/workflow/src/fdd-flp-workflow.cxx @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "FITWorkflow/FITDataReaderDPLSpec.h" +#include "FITWorkflow/FITDigitWriterSpec.h" +#include "FITWorkflow/RawReaderFIT.h" +#include "DataFormatsFDD/MCLabel.h" +#include "FDDRaw/RawReaderFDDBase.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back( + ConfigParamSpec{"tcm-extended-mode", + o2::framework::VariantType::Bool, + false, + {"in case of extended TCM mode (1 header + 1 TCMdata + 8 " + "TCMdataExtended)"}}); + + workflowOptions.push_back( + ConfigParamSpec{"dump-blocks-reader", + o2::framework::VariantType::Bool, + false, + {"enable dumping of event blocks at reader side"}}); + workflowOptions.push_back( + ConfigParamSpec{"disable-root-output", + o2::framework::VariantType::Bool, + false, + {"disable root-files output writers"}}); + workflowOptions.push_back( + ConfigParamSpec{"configKeyValues", + o2::framework::VariantType::String, + "", + {"Semicolon separated key=value strings"}}); + workflowOptions.push_back( + ConfigParamSpec{"ignore-dist-stf", + o2::framework::VariantType::Bool, + false, + {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + LOG(INFO) << "WorkflowSpec defineDataProcessing"; + auto dumpReader = configcontext.options().get<bool>("dump-blocks-reader"); + auto isExtendedMode = configcontext.options().get<bool>("tcm-extended-mode"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto askSTFDist = !configcontext.options().get<bool>("ignore-dist-stf"); + LOG(INFO) << "WorkflowSpec FLPWorkflow"; + //Type aliases + //using RawReaderFDDtrgInput = o2::fit::RawReaderFIT<o2::fdd::RawReaderFV0BaseNorm,true>; + using RawReaderFDD = o2::fit::RawReaderFIT<o2::fdd::RawReaderFDDBaseNorm, false>; + //using RawReaderFDDtrgInputExt = o2::fit::RawReaderFIT<o2::fdd::RawReaderFDDBaseExt,true>; + using RawReaderFDDext = o2::fit::RawReaderFIT<o2::fdd::RawReaderFDDBaseExt, false>; + using MCLabelCont = o2::dataformats::MCTruthContainer<o2::fdd::MCLabel>; + o2::header::DataOrigin dataOrigin = o2::header::gDataOriginFDD; + // + WorkflowSpec specs; + if (isExtendedMode) { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFDDext{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFDDext, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } else { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFDD{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFDD, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } + return std::move(specs); +} diff --git a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx index e49a05bdf3208..b04f853ab4c40 100644 --- a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #include "FDDWorkflow/RecoWorkflow.h" #include "Framework/ConfigParamRegistry.h" #include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; @@ -21,13 +23,14 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters std::vector<o2::framework::ConfigParamSpec> options{ - {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}}; + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; - std::swap(workflowOptions, options); - - std::string keyvaluehelp("Semicolon separated key=value strings (e.g.: 'ITSDigitizerParam.roFrameLength=6000.;...')"); + o2::raw::HBFUtilsInitializer::addConfigOption(options); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::swap(workflowOptions, options); } // ------------------------------------------------------------------ @@ -39,9 +42,16 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the digitizer workflow - o2::conf::ConfigurableParam::writeINI("o2tpcits-match-recoflow_configuration.ini"); + o2::conf::ConfigurableParam::writeINI("o2-fdd-recoflow_configuration.ini"); auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + + auto wf = o2::fdd::getRecoWorkflow(useMC, disableRootInp, disableRootOut); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); - return std::move(o2::fdd::getRecoWorkflow(useMC)); + return std::move(wf); } diff --git a/Detectors/FIT/FT0/CMakeLists.txt b/Detectors/FIT/FT0/CMakeLists.txt index ba81588e3beb4..fa31a5f6b65c7 100644 --- a/Detectors/FIT/FT0/CMakeLists.txt +++ b/Detectors/FIT/FT0/CMakeLists.txt @@ -1,15 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(raw) add_subdirectory(reconstruction) add_subdirectory(simulation) add_subdirectory(workflow) +add_subdirectory(calibration) +add_subdirectory(macros) diff --git a/Detectors/FIT/FT0/base/CMakeLists.txt b/Detectors/FIT/FT0/base/CMakeLists.txt index 40350f5df2d47..f33f66252884d 100644 --- a/Detectors/FIT/FT0/base/CMakeLists.txt +++ b/Detectors/FIT/FT0/base/CMakeLists.txt @@ -1,17 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FT0Base SOURCES src/Geometry.cxx - PUBLIC_LINK_LIBRARIES ROOT::Physics FairRoot::Base) + PUBLIC_LINK_LIBRARIES ROOT::Physics FairRoot::Base O2::DetectorsBase O2::DetectorsCommonDataFormats O2::FrameworkLogger) -o2_target_root_dictionary(FT0Base HEADERS include/FT0Base/Geometry.h) +o2_target_root_dictionary(FT0Base HEADERS include/FT0Base/Geometry.h + include/FT0Base/Constants.h) o2_data_file(COPY files DESTINATION Detectors/FT0/) diff --git a/Detectors/FIT/FT0/base/files/FT0ChannelsTable.02.0.4.2021.txt b/Detectors/FIT/FT0/base/files/FT0ChannelsTable.02.0.4.2021.txt new file mode 100644 index 0000000000000..8e8f3930f944c --- /dev/null +++ b/Detectors/FIT/FT0/base/files/FT0ChannelsTable.02.0.4.2021.txt @@ -0,0 +1,230 @@ +channel # PM PM channel HV board HV channel MCP S/N HV cable signal cable EndPoint/Link +0 A0 PMA0/Ch01 0 HVA0/03 N/A FTA-D2 FTA-D2-? 0/0 +1 A0 PMA0/Ch02 0 HVA0/03 N/A FTA-D2 FTA-D2-? 0/0 +2 A0 PMA0/Ch03 0 HVA0/03 N/A FTA-D2 FTA-D2-? 0/0 +3 A0 PMA0/Ch04 0 HVA0/03 N/A FTA-D2 FTA-D2-? 0/0 +4 A0 PMA0/Ch05 0 HVA0/02 N/A FTA-D1 FTA-D1-? 0/0 +5 A0 PMA0/Ch06 0 HVA0/02 N/A FTA-D1 FTA-D1-? 0/0 +6 A0 PMA0/Ch07 0 HVA0/02 N/A FTA-D1 FTA-D1-? 0/0 +7 A0 PMA0/Ch08 0 HVA0/02 N/A FTA-D1 FTA-D1-? 0/0 +8 A0 PMA0/Ch09 0 HVA0/07 N/A FTA-E1 FTA-E1-? 0/0 +9 A0 PMA0/Ch10 0 HVA0/07 N/A FTA-E1 FTA-E1-? 0/0 +10 A0 PMA0/Ch11 0 HVA0/07 N/A FTA-E1 FTA-E1-? 0/0 +11 A0 PMA0/Ch12 0 HVA0/07 N/A FTA-E1 FTA-E1-? 0/0 +12 A1 PMA1/Ch01 0 HVA0/04 N/A FTA-D3 FTA-D3-? 0/1 +13 A1 PMA1/Ch02 0 HVA0/04 N/A FTA-D3 FTA-D3-? 0/1 +14 A1 PMA1/Ch03 0 HVA0/04 N/A FTA-D3 FTA-D3-? 0/1 +15 A1 PMA1/Ch04 0 HVA0/04 N/A FTA-D3 FTA-D3-? 0/1 +16 A1 PMA1/Ch05 0 HVA0/08 N/A FTA-E2 FTA-E2-? 0/1 +17 A1 PMA1/Ch06 0 HVA0/08 N/A FTA-E2 FTA-E2-? 0/1 +18 A1 PMA1/Ch07 0 HVA0/08 N/A FTA-E2 FTA-E2-? 0/1 +19 A1 PMA1/Ch08 0 HVA0/08 N/A FTA-E2 FTA-E2-? 0/1 +20 A1 PMA1/Ch09 0 HVA0/09 N/A FTA-E3 FTA-E3-? 0/1 +21 A1 PMA1/Ch10 0 HVA0/09 N/A FTA-E3 FTA-E3-? 0/1 +22 A1 PMA1/Ch11 0 HVA0/09 N/A FTA-E3 FTA-E3-? 0/1 +23 A1 PMA1/Ch12 0 HVA0/09 N/A FTA-E3 FTA-E3-? 0/1 +24 A2 PMA2/Ch01 0 HVA0/05 N/A FTA-D4 FTA-D4-? 0/2 +25 A2 PMA2/Ch02 0 HVA0/05 N/A FTA-D4 FTA-D4-? 0/2 +26 A2 PMA2/Ch03 0 HVA0/05 N/A FTA-D4 FTA-D4-? 0/2 +27 A2 PMA2/Ch04 0 HVA0/05 N/A FTA-D4 FTA-D4-? 0/2 +28 A2 PMA2/Ch05 0 HVA0/10 N/A FTA-E4 FTA-E4-? 0/2 +29 A2 PMA2/Ch06 0 HVA0/10 N/A FTA-E4 FTA-E4-? 0/2 +30 A2 PMA2/Ch07 0 HVA0/10 N/A FTA-E4 FTA-E4-? 0/2 +31 A2 PMA2/Ch08 0 HVA0/10 N/A FTA-E4 FTA-E4-? 0/2 +32 A2 PMA2/Ch09 0 HVA0/11 N/A FTA-E5 FTA-E5-? 0/2 +33 A2 PMA2/Ch10 0 HVA0/11 N/A FTA-E5 FTA-E5-? 0/2 +34 A2 PMA2/Ch11 0 HVA0/11 N/A FTA-E5 FTA-E5-? 0/2 +35 A2 PMA2/Ch12 0 HVA0/11 N/A FTA-E5 FTA-E5-? 0/2 +36 A3 PMA3/Ch01 0 HVA0/00 N/A FTA-C4 FTA-C4-? 0/3 +37 A3 PMA3/Ch02 0 HVA0/00 N/A FTA-C4 FTA-C4-? 0/3 +38 A3 PMA3/Ch03 0 HVA0/00 N/A FTA-C4 FTA-C4-? 0/3 +39 A3 PMA3/Ch04 0 HVA0/00 N/A FTA-C4 FTA-C4-? 0/3 +40 A3 PMA3/Ch05 0 HVA0/06 N/A FTA-D5 FTA-D5-? 0/3 +41 A3 PMA3/Ch06 0 HVA0/06 N/A FTA-D5 FTA-D5-? 0/3 +42 A3 PMA3/Ch07 0 HVA0/06 N/A FTA-D5 FTA-D5-? 0/3 +43 A3 PMA3/Ch08 0 HVA0/06 N/A FTA-D5 FTA-D5-? 0/3 +44 A3 PMA3/Ch09 0 HVA0/01 N/A FTA-C5 FTA-C5-? 0/3 +45 A3 PMA3/Ch10 0 HVA0/01 N/A FTA-C5 FTA-C5-? 0/3 +46 A3 PMA3/Ch11 0 HVA0/01 N/A FTA-C5 FTA-C5-? 0/3 +47 A3 PMA3/Ch12 0 HVA0/01 N/A FTA-C5 FTA-C5-? 0/3 +48 A4 PMA4/Ch01 1 HVA1/08 N/A FTA-B4 FTA-B4-? 0/4 +49 A4 PMA4/Ch02 1 HVA1/08 N/A FTA-B4 FTA-B4-? 0/4 +50 A4 PMA4/Ch03 1 HVA1/08 N/A FTA-B4 FTA-B4-? 0/4 +51 A4 PMA4/Ch04 1 HVA1/08 N/A FTA-B4 FTA-B4-? 0/4 +52 A4 PMA4/Ch05 1 HVA1/09 N/A FTA-B5 FTA-B5-? 0/4 +53 A4 PMA4/Ch06 1 HVA1/09 N/A FTA-B5 FTA-B5-? 0/4 +54 A4 PMA4/Ch07 1 HVA1/09 N/A FTA-B5 FTA-B5-? 0/4 +55 A4 PMA4/Ch08 1 HVA1/09 N/A FTA-B5 FTA-B5-? 0/4 +56 A4 PMA4/Ch09 1 HVA1/04 N/A FTA-A5 FTA-A5-? 0/4 +57 A4 PMA4/Ch10 1 HVA1/04 N/A FTA-A5 FTA-A5-? 0/4 +58 A4 PMA4/Ch11 1 HVA1/04 N/A FTA-A5 FTA-A5-? 0/4 +59 A4 PMA4/Ch12 1 HVA1/04 N/A FTA-A5 FTA-A5-? 0/4 +60 A5 PMA5/Ch01 1 HVA1/07 N/A FTA-B3 FTA-B3-? 0/5 +61 A5 PMA5/Ch02 1 HVA1/07 N/A FTA-B3 FTA-B3-? 0/5 +62 A5 PMA5/Ch03 1 HVA1/07 N/A FTA-B3 FTA-B3-? 0/5 +63 A5 PMA5/Ch04 1 HVA1/07 N/A FTA-B3 FTA-B3-? 0/5 +64 A5 PMA5/Ch05 1 HVA1/03 N/A FTA-A4 FTA-A4-? 0/5 +65 A5 PMA5/Ch06 1 HVA1/03 N/A FTA-A4 FTA-A4-? 0/5 +66 A5 PMA5/Ch07 1 HVA1/03 N/A FTA-A4 FTA-A4-? 0/5 +67 A5 PMA5/Ch08 1 HVA1/03 N/A FTA-A4 FTA-A4-? 0/5 +68 A5 PMA5/Ch09 1 HVA1/02 N/A FTA-A3 FTA-A3-? 0/5 +69 A5 PMA5/Ch10 1 HVA1/02 N/A FTA-A3 FTA-A3-? 0/5 +70 A5 PMA5/Ch11 1 HVA1/02 N/A FTA-A3 FTA-A3-? 0/5 +71 A5 PMA5/Ch12 1 HVA1/02 N/A FTA-A3 FTA-A3-? 0/5 +72 A6 PMA6/Ch01 1 HVA1/06 N/A FTA-B2 FTA-B2-? 0/6 +73 A6 PMA6/Ch02 1 HVA1/06 N/A FTA-B2 FTA-B2-? 0/6 +74 A6 PMA6/Ch03 1 HVA1/06 N/A FTA-B2 FTA-B2-? 0/6 +75 A6 PMA6/Ch04 1 HVA1/06 N/A FTA-B2 FTA-B2-? 0/6 +76 A6 PMA6/Ch05 1 HVA1/01 N/A FTA-A2 FTA-A2-? 0/6 +77 A6 PMA6/Ch06 1 HVA1/01 N/A FTA-A2 FTA-A2-? 0/6 +78 A6 PMA6/Ch07 1 HVA1/01 N/A FTA-A2 FTA-A2-? 0/6 +79 A6 PMA6/Ch08 1 HVA1/01 N/A FTA-A2 FTA-A2-? 0/6 +80 A6 PMA6/Ch09 1 HVA1/00 N/A FTA-A1 FTA-A1-? 0/6 +81 A6 PMA6/Ch10 1 HVA1/00 N/A FTA-A1 FTA-A1-? 0/6 +82 A6 PMA6/Ch11 1 HVA1/00 N/A FTA-A1 FTA-A1-? 0/6 +83 A6 PMA6/Ch12 1 HVA1/00 N/A FTA-A1 FTA-A1-? 0/6 +84 A7 PMA7/Ch01 1 HVA1/11 N/A FTA-C2 FTA-C2-? 0/7 +85 A7 PMA7/Ch02 1 HVA1/11 N/A FTA-C2 FTA-C2-? 0/7 +86 A7 PMA7/Ch03 1 HVA1/11 N/A FTA-C2 FTA-C2-? 0/7 +87 A7 PMA7/Ch04 1 HVA1/11 N/A FTA-C2 FTA-C2-? 0/7 +88 A7 PMA7/Ch05 1 HVA1/05 N/A FTA-B1 FTA-B1-? 0/7 +89 A7 PMA7/Ch06 1 HVA1/05 N/A FTA-B1 FTA-B1-? 0/7 +90 A7 PMA7/Ch07 1 HVA1/05 N/A FTA-B1 FTA-B1-? 0/7 +91 A7 PMA7/Ch08 1 HVA1/05 N/A FTA-B1 FTA-B1-? 0/7 +92 A7 PMA7/Ch09 1 HVA1/10 N/A FTA-C1 FTA-C1-? 0/7 +93 A7 PMA7/Ch10 1 HVA1/10 N/A FTA-C1 FTA-C1-? 0/7 +94 A7 PMA7/Ch11 1 HVA1/10 N/A FTA-C1 FTA-C1-? 0/7 +95 A7 PMA7/Ch12 1 HVA1/10 N/A FTA-C1 FTA-C1-? 0/7 +96 C0 PMC0/Ch01 2 HVC2/03 2119 FTC-B3 FTC-B3-2 1/0 +97 C0 PMC0/Ch02 2 HVC2/03 2119 FTC-B3 FTC-B3-1 1/0 +98 C0 PMC0/Ch03 2 HVC2/03 2119 FTC-B3 FTC-B3-3 1/0 +99 C0 PMC0/Ch04 2 HVC2/03 2119 FTC-B3 FTC-B3-4 1/0 +100 C0 PMC0/Ch05 2 HVC2/01 2147 FTC-A3 FTC-A3-2 1/0 +101 C0 PMC0/Ch06 2 HVC2/01 2147 FTC-A3 FTC-A3-1 1/0 +102 C0 PMC0/Ch07 2 HVC2/01 2147 FTC-A3 FTC-A3-3 1/0 +103 C0 PMC0/Ch08 2 HVC2/01 2147 FTC-A3 FTC-A3-4 1/0 +104 C0 PMC0/Ch09 2 HVC2/00 2129 FTC-A2 FTC-A2-2 1/0 +105 C0 PMC0/Ch10 2 HVC2/00 2129 FTC-A2 FTC-A2-1 1/0 +106 C0 PMC0/Ch11 2 HVC2/00 2129 FTC-A2 FTC-A2-3 1/0 +107 C0 PMC0/Ch12 2 HVC2/00 2129 FTC-A2 FTC-A2-4 1/0 +108 C1 PMC1/Ch01 2 HVC2/05 2123 FTC-C2 FTC-C2-1 1/1 +109 C1 PMC1/Ch02 2 HVC2/05 2123 FTC-C2 FTC-C2-2 1/1 +110 C1 PMC1/Ch03 2 HVC2/05 2123 FTC-C2 FTC-C2-4 1/1 +111 C1 PMC1/Ch04 2 HVC2/05 2123 FTC-C2 FTC-C2-3 1/1 +112 C1 PMC1/Ch05 2 HVC2/04 2127 FTC-C1 FTC-C1-1 1/1 +113 C1 PMC1/Ch06 2 HVC2/04 2127 FTC-C1 FTC-C1-2 1/1 +114 C1 PMC1/Ch07 2 HVC2/04 2127 FTC-C1 FTC-C1-4 1/1 +115 C1 PMC1/Ch08 2 HVC2/04 2127 FTC-C1 FTC-C1-3 1/1 +116 C1 PMC1/Ch09 2 HVC2/02 2118 FTC-B1 FTC-B1-2 1/1 +117 C1 PMC1/Ch10 2 HVC2/02 2118 FTC-B1 FTC-B1-3 1/1 +118 C1 PMC1/Ch11 2 HVC2/02 2118 FTC-B1 FTC-B1-1 1/1 +119 C1 PMC1/Ch12 2 HVC2/02 2118 FTC-B1 FTC-B1-4 1/1 +120 C2 PMC2/Ch01 2 HVC2/07 2128 FTC-D2 FTC-D2-4 1/2 +121 C2 PMC2/Ch02 2 HVC2/07 2128 FTC-D2 FTC-D2-3 1/2 +122 C2 PMC2/Ch03 2 HVC2/07 2128 FTC-D2 FTC-D2-1 1/2 +123 C2 PMC2/Ch04 2 HVC2/07 2128 FTC-D2 FTC-D2-2 1/2 +124 C2 PMC2/Ch05 2 HVC2/06 2145 FTC-D1 FTC-D1-4 1/2 +125 C2 PMC2/Ch06 2 HVC2/06 2145 FTC-D1 FTC-D1-3 1/2 +126 C2 PMC2/Ch07 2 HVC2/06 2145 FTC-D1 FTC-D1-1 1/2 +127 C2 PMC2/Ch08 2 HVC2/06 2145 FTC-D1 FTC-D1-2 1/2 +128 C2 PMC2/Ch09 2 HVC2/08 2125 FTC-E1 FTC-E1-2 1/2 +129 C2 PMC2/Ch10 2 HVC2/08 2125 FTC-E1 FTC-E1-1 1/2 +130 C2 PMC2/Ch11 2 HVC2/08 2125 FTC-E1 FTC-E1-3 1/2 +131 C2 PMC2/Ch12 2 HVC2/08 2125 FTC-E1 FTC-E1-4 1/2 +132 C3 PMC3/Ch01 2 HVC2/09 2130 FTC-E3 FTC-E3-1 1/3 +133 C3 PMC3/Ch02 2 HVC2/09 2130 FTC-E3 FTC-E3-2 1/3 +134 C3 PMC3/Ch03 2 HVC2/09 2130 FTC-E3 FTC-E3-4 1/3 +135 C3 PMC3/Ch04 2 HVC2/09 2130 FTC-E3 FTC-E3-3 1/3 +136 C3 PMC3/Ch05 2 HVC2/11 2149 FTC-F3 FTC-F3-1 1/3 +137 C3 PMC3/Ch06 2 HVC2/11 2149 FTC-F3 FTC-F3-2 1/3 +138 C3 PMC3/Ch07 2 HVC2/11 2149 FTC-F3 FTC-F3-4 1/3 +139 C3 PMC3/Ch08 2 HVC2/11 2149 FTC-F3 FTC-F3-3 1/3 +140 C3 PMC3/Ch09 2 HVC2/10 2134 FTC-F2 FTC-F2-1 1/3 +141 C3 PMC3/Ch10 2 HVC2/10 2134 FTC-F2 FTC-F2-2 1/3 +142 C3 PMC3/Ch11 2 HVC2/10 2134 FTC-F2 FTC-F2-4 1/3 +143 C3 PMC3/Ch12 2 HVC2/10 2134 FTC-F2 FTC-F2-3 1/3 +144 C4 PMC4/Ch01 3 HVC3/08 2137 FTC-E4 FTC-E4-2 1/4 +145 C4 PMC4/Ch02 3 HVC3/08 2137 FTC-E4 FTC-E4-1 1/4 +146 C4 PMC4/Ch03 3 HVC3/08 2137 FTC-E4 FTC-E4-3 1/4 +147 C4 PMC4/Ch04 3 HVC3/08 2137 FTC-E4 FTC-E4-4 1/4 +148 C4 PMC4/Ch05 3 HVC3/10 2152 FTC-F4 FTC-F4-2 1/4 +149 C4 PMC4/Ch06 3 HVC3/10 2152 FTC-F4 FTC-F4-1 1/4 +150 C4 PMC4/Ch07 3 HVC3/10 2152 FTC-F4 FTC-F4-3 1/4 +151 C4 PMC4/Ch08 3 HVC3/10 2152 FTC-F4 FTC-F4-4 1/4 +152 C4 PMC4/Ch09 3 HVC3/11 2142 FTC-F5 FTC-F5-2 1/4 +153 C4 PMC4/Ch10 3 HVC3/11 2142 FTC-F5 FTC-F5-1 1/4 +154 C4 PMC4/Ch11 3 HVC3/11 2142 FTC-F5 FTC-F5-3 1/4 +155 C4 PMC4/Ch12 3 HVC3/11 2142 FTC-F5 FTC-F5-4 1/4 +156 C5 PMC5/Ch01 3 HVC3/06 2157 FTC-D5 FTC-D5-1 1/5 +157 C5 PMC5/Ch02 3 HVC3/06 2157 FTC-D5 FTC-D5-2 1/5 +158 C5 PMC5/Ch03 3 HVC3/06 2157 FTC-D5 FTC-D5-4 1/5 +159 C5 PMC5/Ch04 3 HVC3/06 2157 FTC-D5 FTC-D5-3 1/5 +160 C5 PMC5/Ch05 3 HVC3/07 2167 FTC-D6 FTC-D6-1 1/5 +161 C5 PMC5/Ch06 3 HVC3/07 2167 FTC-D6 FTC-D6-2 1/5 +162 C5 PMC5/Ch07 3 HVC3/07 2167 FTC-D6 FTC-D6-4 1/5 +163 C5 PMC5/Ch08 3 HVC3/07 2167 FTC-D6 FTC-D6-3 1/5 +164 C5 PMC5/Ch09 3 HVC3/09 2165 FTC-E6 FTC-E6-2 1/5 +165 C5 PMC5/Ch10 3 HVC3/09 2165 FTC-E6 FTC-E6-3 1/5 +166 C5 PMC5/Ch11 3 HVC3/09 2165 FTC-E6 FTC-E6-1 1/5 +167 C5 PMC5/Ch12 3 HVC3/09 2165 FTC-E6 FTC-E6-4 1/5 +168 C6 PMC6/Ch01 3 HVC3/04 2148 FTC-C5 FTC-C5-4 1/6 +169 C6 PMC6/Ch02 3 HVC3/04 2148 FTC-C5 FTC-C5-3 1/6 +170 C6 PMC6/Ch03 3 HVC3/04 2148 FTC-C5 FTC-C5-1 1/6 +171 C6 PMC6/Ch04 3 HVC3/04 2148 FTC-C5 FTC-C5-2 1/6 +172 C6 PMC6/Ch05 3 HVC3/05 2162 FTC-C6 FTC-C6-4 1/6 +173 C6 PMC6/Ch06 3 HVC3/05 2162 FTC-C6 FTC-C6-3 1/6 +174 C6 PMC6/Ch07 3 HVC3/05 2162 FTC-C6 FTC-C6-1 1/6 +175 C6 PMC6/Ch08 3 HVC3/05 2162 FTC-C6 FTC-C6-2 1/6 +176 C6 PMC6/Ch09 3 HVC3/03 2144 FTC-B6 FTC-B6-2 1/6 +177 C6 PMC6/Ch10 3 HVC3/03 2144 FTC-B6 FTC-B6-1 1/6 +178 C6 PMC6/Ch11 3 HVC3/03 2144 FTC-B6 FTC-B6-3 1/6 +179 C6 PMC6/Ch12 3 HVC3/03 2144 FTC-B6 FTC-B6-4 1/6 +180 C7 PMC7/Ch01 3 HVC3/02 2136 FTC-B4 FTC-B4-1 1/7 +181 C7 PMC7/Ch02 3 HVC3/02 2136 FTC-B4 FTC-B4-2 1/7 +182 C7 PMC7/Ch03 3 HVC3/02 2136 FTC-B4 FTC-B4-4 1/7 +183 C7 PMC7/Ch04 3 HVC3/02 2136 FTC-B4 FTC-B4-3 1/7 +184 C7 PMC7/Ch05 3 HVC3/00 2151 FTC-A4 FTC-A4-1 1/7 +185 C7 PMC7/Ch06 3 HVC3/00 2151 FTC-A4 FTC-A4-2 1/7 +186 C7 PMC7/Ch07 3 HVC3/00 2151 FTC-A4 FTC-A4-4 1/7 +187 C7 PMC7/Ch08 3 HVC3/00 2151 FTC-A4 FTC-A4-3 1/7 +188 C7 PMC7/Ch09 3 HVC3/01 2141 FTC-A5 FTC-A5-1 1/7 +189 C7 PMC7/Ch10 3 HVC3/01 2141 FTC-A5 FTC-A5-2 1/7 +190 C7 PMC7/Ch11 3 HVC3/01 2141 FTC-A5 FTC-A5-4 1/7 +191 C7 PMC7/Ch12 3 HVC3/01 2141 FTC-A5 FTC-A5-3 1/7 +192 C8 PMC8/Ch01 4 HVC4/00 2121 FTC-B2 FTC-B2-2 1/8 +193 C8 PMC8/Ch02 4 HVC4/00 2121 FTC-B2 FTC-B2-3 1/8 +194 C8 PMC8/Ch03 4 HVC4/00 2121 FTC-B2 FTC-B2-1 1/8 +195 C8 PMC8/Ch04 4 HVC4/00 2121 FTC-B2 FTC-B2-4 1/8 +196 C8 PMC8/Ch05 4 HVC4/01 2133 FTC-E2 FTC-E2-1 1/8 +197 C8 PMC8/Ch06 4 HVC4/01 2133 FTC-E2 FTC-E2-2 1/8 +198 C8 PMC8/Ch07 4 HVC4/01 2133 FTC-E2 FTC-E2-4 1/8 +199 C8 PMC8/Ch08 4 HVC4/01 2133 FTC-E2 FTC-E2-3 1/8 +200 C8 PMC8/Ch09 N/A N/A N/A N/A N/A 1/8 +201 C8 PMC8/Ch10 N/A N/A N/A N/A N/A 1/8 +202 C8 PMC8/Ch11 N/A N/A N/A N/A N/A 1/8 +203 C8 PMC8/Ch12 N/A N/A N/A N/A N/A 1/8 +204 C9 PMC9/Ch01 4 HVC4/02 2158 FTC-E5 FTC-E5-2 1/9 +205 C9 PMC9/Ch02 4 HVC4/02 2158 FTC-E5 FTC-E5-3 1/9 +206 C9 PMC9/Ch03 4 HVC4/02 2158 FTC-E5 FTC-E5-1 1/9 +207 C9 PMC9/Ch04 4 HVC4/02 2158 FTC-E5 FTC-E5-4 1/9 +208 C9 PMC9/Ch05 4 HVC4/03 2143 FTC-B5 FTC-B5-1 1/9 +209 C9 PMC9/Ch06 4 HVC4/03 2143 FTC-B5 FTC-B5-2 1/9 +210 C9 PMC9/Ch07 4 HVC4/03 2143 FTC-B5 FTC-B5-4 1/9 +211 C9 PMC9/Ch08 4 HVC4/03 2143 FTC-B5 FTC-B5-3 1/9 +212 C9 PMC9/Ch09 N/A N/A N/A N/A N/A 1/9 +213 C9 PMC9/Ch10 N/A N/A N/A N/A N/A 1/9 +214 C9 PMC9/Ch11 N/A N/A N/A N/A N/A 1/9 +215 C9 PMC9/Ch12 N/A N/A N/A N/A N/A 1/9 +216 A9 PMA9/Ch01 4 HVCM/12 N/A FT0-LCS FTA-LCS 0/9 +217 A9 PMA9/Ch02 4 HVCM/12 N/A FT0-LCS FTA-LCS-H 0/9 +218 A9 PMA9/Ch03 4 HVCM/12 N/A FT0-LCS FTC-LCS 0/9 +219 A9 PMA9/Ch04 4 HVCM/12 N/A FT0-LCS FTC-LCS-H 0/9 +220 A9 PMA9/Ch05 4 HVCM/12 N/A FT0-LCS FTA-LCS 0/9 +221 A9 PMA9/Ch06 4 HVCM/12 N/A FT0-LCS FTA-LCS-H 0/9 +222 A9 PMA9/Ch07 4 HVCM/12 N/A FT0-LCS FTC-LCS 0/9 +223 A9 PMA9/Ch08 4 HVCM/12 N/A FT0-LCS FTC-LCS-H 0/9 +224 A9 PMA9/Ch09 4 HVCM/12 N/A FT0-LCS FTA-LCS 0/9 +225 A9 PMA9/Ch10 4 HVCM/12 N/A FT0-LCS FTA-LCS-H 0/9 +226 A9 PMA9/Ch11 4 HVCM/12 N/A FT0-LCS FTC-LCS 0/9 +227 A9 PMA9/Ch12 4 HVCM/12 N/A FT0-LCS FTC-LCS-H 0/9 +228 A11 PMA11/Ch01 N/A N/A N/A N/A N/A 0/11 diff --git a/Detectors/FIT/FT0/base/files/FT0ChannelsTable.txt b/Detectors/FIT/FT0/base/files/FT0ChannelsTable.txt new file mode 100644 index 0000000000000..924e4b1c09f87 --- /dev/null +++ b/Detectors/FIT/FT0/base/files/FT0ChannelsTable.txt @@ -0,0 +1,225 @@ +channel# PM PM_channel HV_board HV_channel MCP_S/N HV_cable signal_cable +0 A0 PMA0/Ch01 A-Out HVAO/04 ???? FTA-D2 FTA-D2-? +1 A0 PMA0/Ch02 A-Out HVAO/04 ???? FTA-D2 FTA-D2-? +2 A0 PMA0/Ch03 A-Out HVAO/04 ???? FTA-D2 FTA-D2-? +3 A0 PMA0/Ch04 A-Out HVAO/04 ???? FTA-D2 FTA-D2-? +4 A0 PMA0/Ch05 A-Out HVAO/03 ???? FTA-D1 FTA-D1-? +5 A0 PMA0/Ch06 A-Out HVAO/03 ???? FTA-D1 FTA-D1-? +6 A0 PMA0/Ch07 A-Out HVAO/03 ???? FTA-D1 FTA-D1-? +7 A0 PMA0/Ch08 A-Out HVAO/03 ???? FTA-D1 FTA-D1-? +8 A0 PMA0/Ch09 A-Out HVAO/08 ???? FTA-E1 FTA-E1-? +9 A0 PMA0/Ch10 A-Out HVAO/08 ???? FTA-E1 FTA-E1-? +10 A0 PMA0/Ch11 A-Out HVAO/08 ???? FTA-E1 FTA-E1-? +11 A0 PMA0/Ch12 A-Out HVAO/08 ???? FTA-E1 FTA-E1-? +12 A1 PMA1/Ch01 A-Out HVAO/05 ???? FTA-D3 FTA-D3-? +13 A1 PMA1/Ch02 A-Out HVAO/05 ???? FTA-D3 FTA-D3-? +14 A1 PMA1/Ch03 A-Out HVAO/05 ???? FTA-D3 FTA-D3-? +15 A1 PMA1/Ch04 A-Out HVAO/05 ???? FTA-D3 FTA-D3-? +16 A1 PMA1/Ch05 A-Out HVAO/09 ???? FTA-E2 FTA-E2-? +17 A1 PMA1/Ch06 A-Out HVAO/09 ???? FTA-E2 FTA-E2-? +18 A1 PMA1/Ch07 A-Out HVAO/09 ???? FTA-E2 FTA-E2-? +19 A1 PMA1/Ch08 A-Out HVAO/09 ???? FTA-E2 FTA-E2-? +20 A1 PMA1/Ch09 A-Out HVAO/10 ???? FTA-E3 FTA-E3-? +21 A1 PMA1/Ch10 A-Out HVAO/10 ???? FTA-E3 FTA-E3-? +22 A1 PMA1/Ch11 A-Out HVAO/10 ???? FTA-E3 FTA-E3-? +23 A1 PMA1/Ch12 A-Out HVAO/10 ???? FTA-E3 FTA-E3-? +24 A2 PMA2/Ch01 A-Out HVAO/06 ???? FTA-D4 FTA-D4-? +25 A2 PMA2/Ch02 A-Out HVAO/06 ???? FTA-D4 FTA-D4-? +26 A2 PMA2/Ch03 A-Out HVAO/06 ???? FTA-D4 FTA-D4-? +27 A2 PMA2/Ch04 A-Out HVAO/06 ???? FTA-D4 FTA-D4-? +28 A2 PMA2/Ch05 A-Out HVAO/11 ???? FTA-E4 FTA-E4-? +29 A2 PMA2/Ch06 A-Out HVAO/11 ???? FTA-E4 FTA-E4-? +30 A2 PMA2/Ch07 A-Out HVAO/11 ???? FTA-E4 FTA-E4-? +31 A2 PMA2/Ch08 A-Out HVAO/11 ???? FTA-E4 FTA-E4-? +32 A2 PMA2/Ch09 A-Out HVAO/12 ???? FTA-E5 FTA-E5-? +33 A2 PMA2/Ch10 A-Out HVAO/12 ???? FTA-E5 FTA-E5-? +34 A2 PMA2/Ch11 A-Out HVAO/12 ???? FTA-E5 FTA-E5-? +35 A2 PMA2/Ch12 A-Out HVAO/12 ???? FTA-E5 FTA-E5-? +36 A3 PMA3/Ch01 A-Out HVAO/01 ???? FTA-C4 FTA-C4-? +37 A3 PMA3/Ch02 A-Out HVAO/01 ???? FTA-C4 FTA-C4-? +38 A3 PMA3/Ch03 A-Out HVAO/01 ???? FTA-C4 FTA-C4-? +39 A3 PMA3/Ch04 A-Out HVAO/01 ???? FTA-C4 FTA-C4-? +40 A3 PMA3/Ch05 A-Out HVAO/07 ???? FTA-D5 FTA-D5-? +41 A3 PMA3/Ch06 A-Out HVAO/07 ???? FTA-D5 FTA-D5-? +42 A3 PMA3/Ch07 A-Out HVAO/07 ???? FTA-D5 FTA-D5-? +43 A3 PMA3/Ch08 A-Out HVAO/07 ???? FTA-D5 FTA-D5-? +44 A3 PMA3/Ch09 A-Out HVAO/02 ???? FTA-C5 FTA-C5-? +45 A3 PMA3/Ch10 A-Out HVAO/02 ???? FTA-C5 FTA-C5-? +46 A3 PMA3/Ch11 A-Out HVAO/02 ???? FTA-C5 FTA-C5-? +47 A3 PMA3/Ch12 A-Out HVAO/02 ???? FTA-C5 FTA-C5-? +48 A4 PMA4/Ch01 A-In HVAI/09 ???? FTA-B4 FTA-B4-? +49 A4 PMA4/Ch02 A-In HVAI/09 ???? FTA-B4 FTA-B4-? +50 A4 PMA4/Ch03 A-In HVAI/09 ???? FTA-B4 FTA-B4-? +51 A4 PMA4/Ch04 A-In HVAI/09 ???? FTA-B4 FTA-B4-? +52 A4 PMA4/Ch05 A-In HVAI/10 ???? FTA-B5 FTA-B5-? +53 A4 PMA4/Ch06 A-In HVAI/10 ???? FTA-B5 FTA-B5-? +54 A4 PMA4/Ch07 A-In HVAI/10 ???? FTA-B5 FTA-B5-? +55 A4 PMA4/Ch08 A-In HVAI/10 ???? FTA-B5 FTA-B5-? +56 A4 PMA4/Ch09 A-In HVAI/05 ???? FTA-A5 FTA-A5-? +57 A4 PMA4/Ch10 A-In HVAI/05 ???? FTA-A5 FTA-A5-? +58 A4 PMA4/Ch11 A-In HVAI/05 ???? FTA-A5 FTA-A5-? +59 A4 PMA4/Ch12 A-In HVAI/05 ???? FTA-A5 FTA-A5-? +60 A5 PMA5/Ch01 A-In HVAI/08 ???? FTA-B3 FTA-B3-? +61 A5 PMA5/Ch02 A-In HVAI/08 ???? FTA-B3 FTA-B3-? +62 A5 PMA5/Ch03 A-In HVAI/08 ???? FTA-B3 FTA-B3-? +63 A5 PMA5/Ch04 A-In HVAI/08 ???? FTA-B3 FTA-B3-? +64 A5 PMA5/Ch05 A-In HVAI/04 ???? FTA-A4 FTA-A4-? +65 A5 PMA5/Ch06 A-In HVAI/04 ???? FTA-A4 FTA-A4-? +66 A5 PMA5/Ch07 A-In HVAI/04 ???? FTA-A4 FTA-A4-? +67 A5 PMA5/Ch08 A-In HVAI/04 ???? FTA-A4 FTA-A4-? +68 A5 PMA5/Ch09 A-In HVAI/03 ???? FTA-A3 FTA-A3-? +69 A5 PMA5/Ch10 A-In HVAI/03 ???? FTA-A3 FTA-A3-? +70 A5 PMA5/Ch11 A-In HVAI/03 ???? FTA-A3 FTA-A3-? +71 A5 PMA5/Ch12 A-In HVAI/03 ???? FTA-A3 FTA-A3-? +72 A6 PMA6/Ch01 A-In HVAI/07 ???? FTA-B2 FTA-B2-? +73 A6 PMA6/Ch02 A-In HVAI/07 ???? FTA-B2 FTA-B2-? +74 A6 PMA6/Ch03 A-In HVAI/07 ???? FTA-B2 FTA-B2-? +75 A6 PMA6/Ch04 A-In HVAI/07 ???? FTA-B2 FTA-B2-? +76 A6 PMA6/Ch05 A-In HVAI/02 ???? FTA-A2 FTA-A2-? +77 A6 PMA6/Ch06 A-In HVAI/02 ???? FTA-A2 FTA-A2-? +78 A6 PMA6/Ch07 A-In HVAI/02 ???? FTA-A2 FTA-A2-? +79 A6 PMA6/Ch08 A-In HVAI/02 ???? FTA-A2 FTA-A2-? +80 A6 PMA6/Ch09 A-In HVAI/01 ???? FTA-A1 FTA-A1-? +81 A6 PMA6/Ch10 A-In HVAI/01 ???? FTA-A1 FTA-A1-? +82 A6 PMA6/Ch11 A-In HVAI/01 ???? FTA-A1 FTA-A1-? +83 A6 PMA6/Ch12 A-In HVAI/01 ???? FTA-A1 FTA-A1-? +84 A7 PMA7/Ch01 A-In HVAI/12 ???? FTA-C2 FTA-C2-? +85 A7 PMA7/Ch02 A-In HVAI/12 ???? FTA-C2 FTA-C2-? +86 A7 PMA7/Ch03 A-In HVAI/12 ???? FTA-C2 FTA-C2-? +87 A7 PMA7/Ch04 A-In HVAI/12 ???? FTA-C2 FTA-C2-? +88 A7 PMA7/Ch05 A-In HVAI/06 ???? FTA-B1 FTA-B1-? +89 A7 PMA7/Ch06 A-In HVAI/06 ???? FTA-B1 FTA-B1-? +90 A7 PMA7/Ch07 A-In HVAI/06 ???? FTA-B1 FTA-B1-? +91 A7 PMA7/Ch08 A-In HVAI/06 ???? FTA-B1 FTA-B1-? +92 A7 PMA7/Ch09 A-In HVAI/11 ???? FTA-C1 FTA-C1-? +93 A7 PMA7/Ch10 A-In HVAI/11 ???? FTA-C1 FTA-C1-? +94 A7 PMA7/Ch11 A-In HVAI/11 ???? FTA-C1 FTA-C1-? +95 A7 PMA7/Ch12 A-In HVAI/11 ???? FTA-C1 FTA-C1-? +96 C0 PMC0/Ch01 C-Up HVCU/04 2119 FTC-B3 FTC-B3-2 +97 C0 PMC0/Ch02 C-Up HVCU/04 2119 FTC-B3 FTC-B3-1 +98 C0 PMC0/Ch03 C-Up HVCU/04 2119 FTC-B3 FTC-B3-3 +99 C0 PMC0/Ch04 C-Up HVCU/04 2119 FTC-B3 FTC-B3-4 +100 C0 PMC0/Ch05 C-Up HVCU/02 2147 FTC-A3 FTC-A3-2 +101 C0 PMC0/Ch06 C-Up HVCU/02 2147 FTC-A3 FTC-A3-1 +102 C0 PMC0/Ch07 C-Up HVCU/02 2147 FTC-A3 FTC-A3-3 +103 C0 PMC0/Ch08 C-Up HVCU/02 2147 FTC-A3 FTC-A3-4 +104 C0 PMC0/Ch09 C-Up HVCU/01 2129 FTC-A2 FTC-A2-2 +105 C0 PMC0/Ch10 C-Up HVCU/01 2129 FTC-A2 FTC-A2-1 +106 C0 PMC0/Ch11 C-Up HVCU/01 2129 FTC-A2 FTC-A2-3 +107 C0 PMC0/Ch12 C-Up HVCU/01 2129 FTC-A2 FTC-A2-4 +108 C1 PMC1/Ch01 C-Up HVCU/06 2123 FTC-C2 FTC-C2-1 +109 C1 PMC1/Ch02 C-Up HVCU/06 2123 FTC-C2 FTC-C2-2 +110 C1 PMC1/Ch03 C-Up HVCU/06 2123 FTC-C2 FTC-C2-4 +111 C1 PMC1/Ch04 C-Up HVCU/06 2123 FTC-C2 FTC-C2-3 +112 C1 PMC1/Ch05 C-Up HVCU/05 2127 FTC-C1 FTC-C1-1 +113 C1 PMC1/Ch06 C-Up HVCU/05 2127 FTC-C1 FTC-C1-2 +114 C1 PMC1/Ch07 C-Up HVCU/05 2127 FTC-C1 FTC-C1-4 +115 C1 PMC1/Ch08 C-Up HVCU/05 2127 FTC-C1 FTC-C1-3 +116 C1 PMC1/Ch09 C-Up HVCU/03 2118 FTC-B1 FTC-B1-2 +117 C1 PMC1/Ch10 C-Up HVCU/03 2118 FTC-B1 FTC-B1-3 +118 C1 PMC1/Ch11 C-Up HVCU/03 2118 FTC-B1 FTC-B1-1 +119 C1 PMC1/Ch12 C-Up HVCU/03 2118 FTC-B1 FTC-B1-4 +120 C2 PMC2/Ch01 C-Up HVCU/08 2128 FTC-D2 FTC-D2-4 +121 C2 PMC2/Ch02 C-Up HVCU/08 2128 FTC-D2 FTC-D2-3 +122 C2 PMC2/Ch03 C-Up HVCU/08 2128 FTC-D2 FTC-D2-1 +123 C2 PMC2/Ch04 C-Up HVCU/08 2128 FTC-D2 FTC-D2-2 +124 C2 PMC2/Ch05 C-Up HVCU/07 2145 FTC-D1 FTC-D1-4 +125 C2 PMC2/Ch06 C-Up HVCU/07 2145 FTC-D1 FTC-D1-3 +126 C2 PMC2/Ch07 C-Up HVCU/07 2145 FTC-D1 FTC-D1-1 +127 C2 PMC2/Ch08 C-Up HVCU/07 2145 FTC-D1 FTC-D1-2 +128 C2 PMC2/Ch09 C-Up HVCU/09 2125 FTC-E1 FTC-E1-2 +129 C2 PMC2/Ch10 C-Up HVCU/09 2125 FTC-E1 FTC-E1-1 +130 C2 PMC2/Ch11 C-Up HVCU/09 2125 FTC-E1 FTC-E1-3 +131 C2 PMC2/Ch12 C-Up HVCU/09 2125 FTC-E1 FTC-E1-4 +132 C3 PMC3/Ch01 C-Up HVCU/10 2130 FTC-E3 FTC-E3-1 +133 C3 PMC3/Ch02 C-Up HVCU/10 2130 FTC-E3 FTC-E3-2 +134 C3 PMC3/Ch03 C-Up HVCU/10 2130 FTC-E3 FTC-E3-4 +135 C3 PMC3/Ch04 C-Up HVCU/10 2130 FTC-E3 FTC-E3-3 +136 C3 PMC3/Ch05 C-Up HVCU/12 2149 FTC-F3 FTC-F3-1 +137 C3 PMC3/Ch06 C-Up HVCU/12 2149 FTC-F3 FTC-F3-2 +138 C3 PMC3/Ch07 C-Up HVCU/12 2149 FTC-F3 FTC-F3-4 +139 C3 PMC3/Ch08 C-Up HVCU/12 2149 FTC-F3 FTC-F3-3 +140 C3 PMC3/Ch09 C-Up HVCU/11 2134 FTC-F2 FTC-F2-1 +141 C3 PMC3/Ch10 C-Up HVCU/11 2134 FTC-F2 FTC-F2-2 +142 C3 PMC3/Ch11 C-Up HVCU/11 2134 FTC-F2 FTC-F2-4 +143 C3 PMC3/Ch12 C-Up HVCU/11 2134 FTC-F2 FTC-F2-3 +144 C4 PMC4/Ch01 C-Down HVCD/09 2137 FTC-E4 FTC-E4-2 +145 C4 PMC4/Ch02 C-Down HVCD/09 2137 FTC-E4 FTC-E4-1 +146 C4 PMC4/Ch03 C-Down HVCD/09 2137 FTC-E4 FTC-E4-3 +147 C4 PMC4/Ch04 C-Down HVCD/09 2137 FTC-E4 FTC-E4-4 +148 C4 PMC4/Ch05 C-Down HVCD/11 2152 FTC-F4 FTC-F4-2 +149 C4 PMC4/Ch06 C-Down HVCD/11 2152 FTC-F4 FTC-F4-1 +150 C4 PMC4/Ch07 C-Down HVCD/11 2152 FTC-F4 FTC-F4-3 +151 C4 PMC4/Ch08 C-Down HVCD/11 2152 FTC-F4 FTC-F4-4 +152 C4 PMC4/Ch09 C-Down HVCD/12 2142 FTC-F5 FTC-F5-2 +153 C4 PMC4/Ch10 C-Down HVCD/12 2142 FTC-F5 FTC-F5-1 +154 C4 PMC4/Ch11 C-Down HVCD/12 2142 FTC-F5 FTC-F5-3 +155 C4 PMC4/Ch12 C-Down HVCD/12 2142 FTC-F5 FTC-F5-4 +156 C5 PMC5/Ch01 C-Down HVCD/07 2157 FTC-D5 FTC-D5-1 +157 C5 PMC5/Ch02 C-Down HVCD/07 2157 FTC-D5 FTC-D5-2 +158 C5 PMC5/Ch03 C-Down HVCD/07 2157 FTC-D5 FTC-D5-4 +159 C5 PMC5/Ch04 C-Down HVCD/07 2157 FTC-D5 FTC-D5-3 +160 C5 PMC5/Ch05 C-Down HVCD/08 2167 FTC-D6 FTC-D6-1 +161 C5 PMC5/Ch06 C-Down HVCD/08 2167 FTC-D6 FTC-D6-2 +162 C5 PMC5/Ch07 C-Down HVCD/08 2167 FTC-D6 FTC-D6-4 +163 C5 PMC5/Ch08 C-Down HVCD/08 2167 FTC-D6 FTC-D6-3 +164 C5 PMC5/Ch09 C-Down HVCD/10 2165 FTC-E6 FTC-E6-2 +165 C5 PMC5/Ch10 C-Down HVCD/10 2165 FTC-E6 FTC-E6-3 +166 C5 PMC5/Ch11 C-Down HVCD/10 2165 FTC-E6 FTC-E6-1 +167 C5 PMC5/Ch12 C-Down HVCD/10 2165 FTC-E6 FTC-E6-4 +168 C6 PMC6/Ch01 C-Down HVCD/05 2148 FTC-C5 FTC-C5-4 +169 C6 PMC6/Ch02 C-Down HVCD/05 2148 FTC-C5 FTC-C5-3 +170 C6 PMC6/Ch03 C-Down HVCD/05 2148 FTC-C5 FTC-C5-1 +171 C6 PMC6/Ch04 C-Down HVCD/05 2148 FTC-C5 FTC-C5-2 +172 C6 PMC6/Ch05 C-Down HVCD/06 2162 FTC-C6 FTC-C6-4 +173 C6 PMC6/Ch06 C-Down HVCD/06 2162 FTC-C6 FTC-C6-3 +174 C6 PMC6/Ch07 C-Down HVCD/06 2162 FTC-C6 FTC-C6-1 +175 C6 PMC6/Ch08 C-Down HVCD/06 2162 FTC-C6 FTC-C6-2 +176 C6 PMC6/Ch09 C-Down HVCD/04 2144 FTC-B6 FTC-B6-2 +177 C6 PMC6/Ch10 C-Down HVCD/04 2144 FTC-B6 FTC-B6-1 +178 C6 PMC6/Ch11 C-Down HVCD/04 2144 FTC-B6 FTC-B6-3 +179 C6 PMC6/Ch12 C-Down HVCD/04 2144 FTC-B6 FTC-B6-4 +180 C7 PMC7/Ch01 C-Down HVCD/03 2136 FTC-B4 FTC-B4-1 +181 C7 PMC7/Ch02 C-Down HVCD/03 2136 FTC-B4 FTC-B4-2 +182 C7 PMC7/Ch03 C-Down HVCD/03 2136 FTC-B4 FTC-B4-4 +183 C7 PMC7/Ch04 C-Down HVCD/03 2136 FTC-B4 FTC-B4-3 +184 C7 PMC7/Ch05 C-Down HVCD/01 2151 FTC-A4 FTC-A4-1 +185 C7 PMC7/Ch06 C-Down HVCD/01 2151 FTC-A4 FTC-A4-2 +186 C7 PMC7/Ch07 C-Down HVCD/01 2151 FTC-A4 FTC-A4-4 +187 C7 PMC7/Ch08 C-Down HVCD/01 2151 FTC-A4 FTC-A4-3 +188 C7 PMC7/Ch09 C-Down HVCD/02 2141 FTC-A5 FTC-A5-1 +189 C7 PMC7/Ch10 C-Down HVCD/02 2141 FTC-A5 FTC-A5-2 +190 C7 PMC7/Ch11 C-Down HVCD/02 2141 FTC-A5 FTC-A5-4 +191 C7 PMC7/Ch12 C-Down HVCD/02 2141 FTC-A5 FTC-A5-3 +192 C8 PMC8/Ch01 C-Mid HVCM/01 2121 FTC-B2 FTC-B2-2 +193 C8 PMC8/Ch02 C-Mid HVCM/01 2121 FTC-B2 FTC-B2-3 +194 C8 PMC8/Ch03 C-Mid HVCM/01 2121 FTC-B2 FTC-B2-1 +195 C8 PMC8/Ch04 C-Mid HVCM/01 2121 FTC-B2 FTC-B2-4 +196 C8 PMC8/Ch05 C-Mid HVCM/02 2133 FTC-E2 FTC-E2-1 +197 C8 PMC8/Ch06 C-Mid HVCM/02 2133 FTC-E2 FTC-E2-2 +198 C8 PMC8/Ch07 C-Mid HVCM/02 2133 FTC-E2 FTC-E2-4 +199 C8 PMC8/Ch08 C-Mid HVCM/02 2133 FTC-E2 FTC-E2-3 +200 C8 PMC8/Ch09 N/A N/A N/A N/A N/A +201 C8 PMC8/Ch10 N/A N/A N/A N/A N/A +202 C8 PMC8/Ch11 N/A N/A N/A N/A N/A +203 C8 PMC8/Ch12 N/A N/A N/A N/A N/A +204 C9 PMC9/Ch01 C-Mid HVCM/03 2158 FTC-E5 FTC-E5-2 +205 C9 PMC9/Ch02 C-Mid HVCM/03 2158 FTC-E5 FTC-E5-3 +206 C9 PMC9/Ch03 C-Mid HVCM/03 2158 FTC-E5 FTC-E5-1 +207 C9 PMC9/Ch04 C-Mid HVCM/03 2158 FTC-E5 FTC-E5-4 +208 C9 PMC9/Ch05 C-Mid HVCM/04 2143 FTC-B5 FTC-B5-1 +209 C9 PMC9/Ch06 C-Mid HVCM/04 2143 FTC-B5 FTC-B5-2 +210 C9 PMC9/Ch07 C-Mid HVCM/04 2143 FTC-B5 FTC-B5-4 +211 C9 PMC9/Ch08 C-Mid HVCM/04 2143 FTC-B5 FTC-B5-3 +212 C9 PMC9/Ch09 N/A N/A N/A N/A N/A +213 C9 PMC9/Ch10 N/A N/A N/A N/A N/A +214 C9 PMC9/Ch11 N/A N/A N/A N/A N/A +215 C9 PMC9/Ch12 N/A N/A N/A N/A N/A +216 A9 PMA9/Ch01 C-Mid HVCM/12 ???? FT0-LCS FTA-LCS +217 A9 PMA9/Ch02 C-Mid HVCM/12 ???? FT0-LCS FTA-LCS-H +218 A9 PMA9/Ch03 C-Mid HVCM/12 ???? FT0-LCS FTC-LCS +219 A9 PMA9/Ch04 C-Mid HVCM/12 ???? FT0-LCS FTC-LCS-H + + + + diff --git a/Detectors/FIT/FT0/base/files/LookupTable_FT0.csv b/Detectors/FIT/FT0/base/files/LookupTable_FT0.csv new file mode 100644 index 0000000000000..6a7ae56196e5a --- /dev/null +++ b/Detectors/FIT/FT0/base/files/LookupTable_FT0.csv @@ -0,0 +1,230 @@ +LinkID,EndPointID,CRUID,FEEID,ModuleType,LocalChannelID,channel #,EndPoint/Link,Module,PM channel,HV board,HV channel,MCP S/N,HV cable,signal cable +0,0,0,0,PM,1,0,0/0,PMA0,PMA0/Ch01,0,HVA0/03,2186,FTA-D2,FTA-D2-1 +0,0,0,0,PM,2,1,0/0,PMA0,PMA0/Ch02,0,HVA0/03,2186,FTA-D2,FTA-D2-4 +0,0,0,0,PM,3,2,0/0,PMA0,PMA0/Ch03,0,HVA0/03,2186,FTA-D2,FTA-D2-2 +0,0,0,0,PM,4,3,0/0,PMA0,PMA0/Ch04,0,HVA0/03,2186,FTA-D2,FTA-D2-3 +0,0,0,0,PM,5,4,0/0,PMA0,PMA0/Ch05,0,HVA0/02,2117,FTA-D1,FTA-D1-3 +0,0,0,0,PM,6,5,0/0,PMA0,PMA0/Ch06,0,HVA0/02,2117,FTA-D1,FTA-D1-2 +0,0,0,0,PM,7,6,0/0,PMA0,PMA0/Ch07,0,HVA0/02,2117,FTA-D1,FTA-D1-4 +0,0,0,0,PM,8,7,0/0,PMA0,PMA0/Ch08,0,HVA0/02,2117,FTA-D1,FTA-D1-1 +0,0,0,0,PM,9,8,0/0,PMA0,PMA0/Ch09,0,HVA0/07,2170,FTA-E1,FTA-E1-1 +0,0,0,0,PM,10,9,0/0,PMA0,PMA0/Ch10,0,HVA0/07,2170,FTA-E1,FTA-E1-4 +0,0,0,0,PM,11,10,0/0,PMA0,PMA0/Ch11,0,HVA0/07,2170,FTA-E1,FTA-E1-2 +0,0,0,0,PM,12,11,0/0,PMA0,PMA0/Ch12,0,HVA0/07,2170,FTA-E1,FTA-E1-3 +1,0,0,1,PM,1,12,0/1,PMA1,PMA1/Ch01,0,HVA0/04,2184,FTA-D3,FTA-D3-1 +1,0,0,1,PM,2,13,0/1,PMA1,PMA1/Ch02,0,HVA0/04,2184,FTA-D3,FTA-D3-2 +1,0,0,1,PM,3,14,0/1,PMA1,PMA1/Ch03,0,HVA0/04,2184,FTA-D3,FTA-D3-4 +1,0,0,1,PM,4,15,0/1,PMA1,PMA1/Ch04,0,HVA0/04,2184,FTA-D3,FTA-D3-3 +1,0,0,1,PM,5,16,0/1,PMA1,PMA1/Ch05,0,HVA0/08,2154,FTA-E2,FTA-E2-4 +1,0,0,1,PM,6,17,0/1,PMA1,PMA1/Ch06,0,HVA0/08,2154,FTA-E2,FTA-E2-1 +1,0,0,1,PM,7,18,0/1,PMA1,PMA1/Ch07,0,HVA0/08,2154,FTA-E2,FTA-E2-3 +1,0,0,1,PM,8,19,0/1,PMA1,PMA1/Ch08,0,HVA0/08,2154,FTA-E2,FTA-E2-2 +1,0,0,1,PM,9,20,0/1,PMA1,PMA1/Ch09,0,HVA0/09,2124,FTA-E3,FTA-E3-1 +1,0,0,1,PM,10,21,0/1,PMA1,PMA1/Ch10,0,HVA0/09,2124,FTA-E3,FTA-E3-2 +1,0,0,1,PM,11,22,0/1,PMA1,PMA1/Ch11,0,HVA0/09,2124,FTA-E3,FTA-E3-4 +1,0,0,1,PM,12,23,0/1,PMA1,PMA1/Ch12,0,HVA0/09,2124,FTA-E3,FTA-E3-3 +2,0,0,2,PM,1,24,0/2,PMA2,PMA2/Ch01,0,HVA0/05,2164,FTA-D4,FTA-D4-1 +2,0,0,2,PM,2,25,0/2,PMA2,PMA2/Ch02,0,HVA0/05,2164,FTA-D4,FTA-D4-4 +2,0,0,2,PM,3,26,0/2,PMA2,PMA2/Ch03,0,HVA0/05,2164,FTA-D4,FTA-D4-2 +2,0,0,2,PM,4,27,0/2,PMA2,PMA2/Ch04,0,HVA0/05,2164,FTA-D4,FTA-D4-3 +2,0,0,2,PM,5,28,0/2,PMA2,PMA2/Ch05,0,HVA0/10,2135,FTA-E4,FTA-E4-2 +2,0,0,2,PM,6,29,0/2,PMA2,PMA2/Ch06,0,HVA0/10,2135,FTA-E4,FTA-E4-1 +2,0,0,2,PM,7,30,0/2,PMA2,PMA2/Ch07,0,HVA0/10,2135,FTA-E4,FTA-E4-3 +2,0,0,2,PM,8,31,0/2,PMA2,PMA2/Ch08,0,HVA0/10,2135,FTA-E4,FTA-E4-4 +2,0,0,2,PM,9,32,0/2,PMA2,PMA2/Ch09,0,HVA0/11,2160,FTA-E5,FTA-E5-1 +2,0,0,2,PM,10,33,0/2,PMA2,PMA2/Ch10,0,HVA0/11,2160,FTA-E5,FTA-E5-4 +2,0,0,2,PM,11,34,0/2,PMA2,PMA2/Ch11,0,HVA0/11,2160,FTA-E5,FTA-E5-2 +2,0,0,2,PM,12,35,0/2,PMA2,PMA2/Ch12,0,HVA0/11,2160,FTA-E5,FTA-E5-3 +3,0,0,3,PM,1,36,0/3,PMA3,PMA3/Ch01,0,HVA0/00,2132,FTA-C4,FTA-C4-1 +3,0,0,3,PM,2,37,0/3,PMA3,PMA3/Ch02,0,HVA0/00,2132,FTA-C4,FTA-C4-2 +3,0,0,3,PM,3,38,0/3,PMA3,PMA3/Ch03,0,HVA0/00,2132,FTA-C4,FTA-C4-4 +3,0,0,3,PM,4,39,0/3,PMA3,PMA3/Ch04,0,HVA0/00,2132,FTA-C4,FTA-C4-3 +3,0,0,3,PM,5,40,0/3,PMA3,PMA3/Ch05,0,HVA0/06,2171,FTA-D5,FTA-D5-3 +3,0,0,3,PM,6,41,0/3,PMA3,PMA3/Ch06,0,HVA0/06,2171,FTA-D5,FTA-D5-4 +3,0,0,3,PM,7,42,0/3,PMA3,PMA3/Ch07,0,HVA0/06,2171,FTA-D5,FTA-D5-2 +3,0,0,3,PM,8,43,0/3,PMA3,PMA3/Ch08,0,HVA0/06,2171,FTA-D5,FTA-D5-1 +3,0,0,3,PM,9,44,0/3,PMA3,PMA3/Ch09,0,HVA0/01,2153,FTA-C5,FTA-C5-3 +3,0,0,3,PM,10,45,0/3,PMA3,PMA3/Ch10,0,HVA0/01,2153,FTA-C5,FTA-C5-4 +3,0,0,3,PM,11,46,0/3,PMA3,PMA3/Ch11,0,HVA0/01,2153,FTA-C5,FTA-C5-2 +3,0,0,3,PM,12,47,0/3,PMA3,PMA3/Ch12,0,HVA0/01,2153,FTA-C5,FTA-C5-1 +4,0,0,4,PM,1,48,0/4,PMA4,PMA4/Ch01,1,HVA1/08,2183,FTA-B4,FTA-B4-1 +4,0,0,4,PM,2,49,0/4,PMA4,PMA4/Ch02,1,HVA1/08,2183,FTA-B4,FTA-B4-4 +4,0,0,4,PM,3,50,0/4,PMA4,PMA4/Ch03,1,HVA1/08,2183,FTA-B4,FTA-B4-2 +4,0,0,4,PM,4,51,0/4,PMA4,PMA4/Ch04,1,HVA1/08,2183,FTA-B4,FTA-B4-3 +4,0,0,4,PM,5,52,0/4,PMA4,PMA4/Ch05,1,HVA1/09,2176,FTA-B5,FTA-B5-1 +4,0,0,4,PM,6,53,0/4,PMA4,PMA4/Ch06,1,HVA1/09,2176,FTA-B5,FTA-B5-4 +4,0,0,4,PM,7,54,0/4,PMA4,PMA4/Ch07,1,HVA1/09,2176,FTA-B5,FTA-B5-2 +4,0,0,4,PM,8,55,0/4,PMA4,PMA4/Ch08,1,HVA1/09,2176,FTA-B5,FTA-B5-3 +4,0,0,4,PM,9,56,0/4,PMA4,PMA4/Ch09,1,HVA1/04,2169,FTA-A5,FTA-A5-3 +4,0,0,4,PM,10,57,0/4,PMA4,PMA4/Ch10,1,HVA1/04,2169,FTA-A5,FTA-A5-2 +4,0,0,4,PM,11,58,0/4,PMA4,PMA4/Ch11,1,HVA1/04,2169,FTA-A5,FTA-A5-4 +4,0,0,4,PM,12,59,0/4,PMA4,PMA4/Ch12,1,HVA1/04,2169,FTA-A5,FTA-A5-1 +5,0,0,5,PM,1,60,0/5,PMA5,PMA5/Ch01,1,HVA1/07,2180,FTA-B3,FTA-B3-3 +5,0,0,5,PM,2,61,0/5,PMA5,PMA5/Ch02,1,HVA1/07,2180,FTA-B3,FTA-B3-4 +5,0,0,5,PM,3,62,0/5,PMA5,PMA5/Ch03,1,HVA1/07,2180,FTA-B3,FTA-B3-2 +5,0,0,5,PM,4,63,0/5,PMA5,PMA5/Ch04,1,HVA1/07,2180,FTA-B3,FTA-B3-1 +5,0,0,5,PM,5,64,0/5,PMA5,PMA5/Ch05,1,HVA1/03,2179,FTA-A4,FTA-A4-1 +5,0,0,5,PM,6,65,0/5,PMA5,PMA5/Ch06,1,HVA1/03,2179,FTA-A4,FTA-A4-2 +5,0,0,5,PM,7,66,0/5,PMA5,PMA5/Ch07,1,HVA1/03,2179,FTA-A4,FTA-A4-4 +5,0,0,5,PM,8,67,0/5,PMA5,PMA5/Ch08,1,HVA1/03,2179,FTA-A4,FTA-A4-3 +5,0,0,5,PM,9,68,0/5,PMA5,PMA5/Ch09,1,HVA1/02,2174,FTA-A3,FTA-A3-1 +5,0,0,5,PM,10,69,0/5,PMA5,PMA5/Ch10,1,HVA1/02,2174,FTA-A3,FTA-A3-2 +5,0,0,5,PM,11,70,0/5,PMA5,PMA5/Ch11,1,HVA1/02,2174,FTA-A3,FTA-A3-4 +5,0,0,5,PM,12,71,0/5,PMA5,PMA5/Ch12,1,HVA1/02,2174,FTA-A3,FTA-A3-3 +6,0,0,6,PM,1,72,0/6,PMA6,PMA6/Ch01,1,HVA1/06,2185,FTA-B2,FTA-B2-1 +6,0,0,6,PM,2,73,0/6,PMA6,PMA6/Ch02,1,HVA1/06,2185,FTA-B2,FTA-B2-4 +6,0,0,6,PM,3,74,0/6,PMA6,PMA6/Ch03,1,HVA1/06,2185,FTA-B2,FTA-B2-2 +6,0,0,6,PM,4,75,0/6,PMA6,PMA6/Ch04,1,HVA1/06,2185,FTA-B2,FTA-B2-3 +6,0,0,6,PM,5,76,0/6,PMA6,PMA6/Ch05,1,HVA1/01,2181,FTA-A2,FTA-A2-1 +6,0,0,6,PM,6,77,0/6,PMA6,PMA6/Ch06,1,HVA1/01,2181,FTA-A2,FTA-A2-4 +6,0,0,6,PM,7,78,0/6,PMA6,PMA6/Ch07,1,HVA1/01,2181,FTA-A2,FTA-A2-2 +6,0,0,6,PM,8,79,0/6,PMA6,PMA6/Ch08,1,HVA1/01,2181,FTA-A2,FTA-A2-3 +6,0,0,6,PM,9,80,0/6,PMA6,PMA6/Ch09,1,HVA1/00,2173,FTA-A1,FTA-A1-1 +6,0,0,6,PM,10,81,0/6,PMA6,PMA6/Ch10,1,HVA1/00,2173,FTA-A1,FTA-A1-4 +6,0,0,6,PM,11,82,0/6,PMA6,PMA6/Ch11,1,HVA1/00,2173,FTA-A1,FTA-A1-2 +6,0,0,6,PM,12,83,0/6,PMA6,PMA6/Ch12,1,HVA1/00,2173,FTA-A1,FTA-A1-3 +7,0,0,7,PM,1,84,0/7,PMA7,PMA7/Ch01,1,HVA1/11,2163,FTA-C2,FTA-C2-4 +7,0,0,7,PM,2,85,0/7,PMA7,PMA7/Ch02,1,HVA1/11,2163,FTA-C2,FTA-C2-1 +7,0,0,7,PM,3,86,0/7,PMA7,PMA7/Ch03,1,HVA1/11,2163,FTA-C2,FTA-C2-3 +7,0,0,7,PM,4,87,0/7,PMA7,PMA7/Ch04,1,HVA1/11,2163,FTA-C2,FTA-C2-2 +7,0,0,7,PM,5,88,0/7,PMA7,PMA7/Ch05,1,HVA1/05,2182,FTA-B1,FTA-B1-4 +7,0,0,7,PM,6,89,0/7,PMA7,PMA7/Ch06,1,HVA1/05,2182,FTA-B1,FTA-B1-1 +7,0,0,7,PM,7,90,0/7,PMA7,PMA7/Ch07,1,HVA1/05,2182,FTA-B1,FTA-B1-3 +7,0,0,7,PM,8,91,0/7,PMA7,PMA7/Ch08,1,HVA1/05,2182,FTA-B1,FTA-B1-2 +7,0,0,7,PM,9,92,0/7,PMA7,PMA7/Ch09,1,HVA1/10,2187,FTA-C1,FTA-C1-2 +7,0,0,7,PM,10,93,0/7,PMA7,PMA7/Ch10,1,HVA1/10,2187,FTA-C1,FTA-C1-3 +7,0,0,7,PM,11,94,0/7,PMA7,PMA7/Ch11,1,HVA1/10,2187,FTA-C1,FTA-C1-1 +7,0,0,7,PM,12,95,0/7,PMA7,PMA7/Ch12,1,HVA1/10,2187,FTA-C1,FTA-C1-4 +0,1,0,8,PM,1,96,1/0,PMC0,PMC0/Ch01,2,HVC2/03,2119,FTC-B3,FTC-B3-2 +0,1,0,8,PM,2,97,1/0,PMC0,PMC0/Ch02,2,HVC2/03,2119,FTC-B3,FTC-B3-1 +0,1,0,8,PM,3,98,1/0,PMC0,PMC0/Ch03,2,HVC2/03,2119,FTC-B3,FTC-B3-3 +0,1,0,8,PM,4,99,1/0,PMC0,PMC0/Ch04,2,HVC2/03,2119,FTC-B3,FTC-B3-4 +0,1,0,8,PM,5,100,1/0,PMC0,PMC0/Ch05,2,HVC2/01,2147,FTC-A3,FTC-A3-2 +0,1,0,8,PM,6,101,1/0,PMC0,PMC0/Ch06,2,HVC2/01,2147,FTC-A3,FTC-A3-1 +0,1,0,8,PM,7,102,1/0,PMC0,PMC0/Ch07,2,HVC2/01,2147,FTC-A3,FTC-A3-3 +0,1,0,8,PM,8,103,1/0,PMC0,PMC0/Ch08,2,HVC2/01,2147,FTC-A3,FTC-A3-4 +0,1,0,8,PM,9,104,1/0,PMC0,PMC0/Ch09,2,HVC2/00,2129,FTC-A2,FTC-A2-2 +0,1,0,8,PM,10,105,1/0,PMC0,PMC0/Ch10,2,HVC2/00,2129,FTC-A2,FTC-A2-1 +0,1,0,8,PM,11,106,1/0,PMC0,PMC0/Ch11,2,HVC2/00,2129,FTC-A2,FTC-A2-3 +0,1,0,8,PM,12,107,1/0,PMC0,PMC0/Ch12,2,HVC2/00,2129,FTC-A2,FTC-A2-4 +1,1,0,9,PM,1,108,1/1,PMC1,PMC1/Ch01,2,HVC2/05,2123,FTC-C2,FTC-C2-1 +1,1,0,9,PM,2,109,1/1,PMC1,PMC1/Ch02,2,HVC2/05,2123,FTC-C2,FTC-C2-2 +1,1,0,9,PM,3,110,1/1,PMC1,PMC1/Ch03,2,HVC2/05,2123,FTC-C2,FTC-C2-4 +1,1,0,9,PM,4,111,1/1,PMC1,PMC1/Ch04,2,HVC2/05,2123,FTC-C2,FTC-C2-3 +1,1,0,9,PM,5,112,1/1,PMC1,PMC1/Ch05,2,HVC2/04,2127,FTC-C1,FTC-C1-1 +1,1,0,9,PM,6,113,1/1,PMC1,PMC1/Ch06,2,HVC2/04,2127,FTC-C1,FTC-C1-2 +1,1,0,9,PM,7,114,1/1,PMC1,PMC1/Ch07,2,HVC2/04,2127,FTC-C1,FTC-C1-4 +1,1,0,9,PM,8,115,1/1,PMC1,PMC1/Ch08,2,HVC2/04,2127,FTC-C1,FTC-C1-3 +1,1,0,9,PM,9,116,1/1,PMC1,PMC1/Ch09,2,HVC2/02,2118,FTC-B1,FTC-B1-2 +1,1,0,9,PM,10,117,1/1,PMC1,PMC1/Ch10,2,HVC2/02,2118,FTC-B1,FTC-B1-3 +1,1,0,9,PM,11,118,1/1,PMC1,PMC1/Ch11,2,HVC2/02,2118,FTC-B1,FTC-B1-1 +1,1,0,9,PM,12,119,1/1,PMC1,PMC1/Ch12,2,HVC2/02,2118,FTC-B1,FTC-B1-4 +2,1,0,10,PM,1,120,1/2,PMC2,PMC2/Ch01,2,HVC2/07,2128,FTC-D2,FTC-D2-4 +2,1,0,10,PM,2,121,1/2,PMC2,PMC2/Ch02,2,HVC2/07,2128,FTC-D2,FTC-D2-3 +2,1,0,10,PM,3,122,1/2,PMC2,PMC2/Ch03,2,HVC2/07,2128,FTC-D2,FTC-D2-1 +2,1,0,10,PM,4,123,1/2,PMC2,PMC2/Ch04,2,HVC2/07,2128,FTC-D2,FTC-D2-2 +2,1,0,10,PM,5,124,1/2,PMC2,PMC2/Ch05,2,HVC2/06,2145,FTC-D1,FTC-D1-4 +2,1,0,10,PM,6,125,1/2,PMC2,PMC2/Ch06,2,HVC2/06,2145,FTC-D1,FTC-D1-3 +2,1,0,10,PM,7,126,1/2,PMC2,PMC2/Ch07,2,HVC2/06,2145,FTC-D1,FTC-D1-1 +2,1,0,10,PM,8,127,1/2,PMC2,PMC2/Ch08,2,HVC2/06,2145,FTC-D1,FTC-D1-2 +2,1,0,10,PM,9,128,1/2,PMC2,PMC2/Ch09,2,HVC2/08,2125,FTC-E1,FTC-E1-2 +2,1,0,10,PM,10,129,1/2,PMC2,PMC2/Ch10,2,HVC2/08,2125,FTC-E1,FTC-E1-1 +2,1,0,10,PM,11,130,1/2,PMC2,PMC2/Ch11,2,HVC2/08,2125,FTC-E1,FTC-E1-3 +2,1,0,10,PM,12,131,1/2,PMC2,PMC2/Ch12,2,HVC2/08,2125,FTC-E1,FTC-E1-4 +3,1,0,11,PM,1,132,1/3,PMC3,PMC3/Ch01,2,HVC2/09,2130,FTC-E3,FTC-E3-1 +3,1,0,11,PM,2,133,1/3,PMC3,PMC3/Ch02,2,HVC2/09,2130,FTC-E3,FTC-E3-2 +3,1,0,11,PM,3,134,1/3,PMC3,PMC3/Ch03,2,HVC2/09,2130,FTC-E3,FTC-E3-4 +3,1,0,11,PM,4,135,1/3,PMC3,PMC3/Ch04,2,HVC2/09,2130,FTC-E3,FTC-E3-3 +3,1,0,11,PM,5,136,1/3,PMC3,PMC3/Ch05,2,HVC2/11,2149,FTC-F3,FTC-F3-1 +3,1,0,11,PM,6,137,1/3,PMC3,PMC3/Ch06,2,HVC2/11,2149,FTC-F3,FTC-F3-2 +3,1,0,11,PM,7,138,1/3,PMC3,PMC3/Ch07,2,HVC2/11,2149,FTC-F3,FTC-F3-4 +3,1,0,11,PM,8,139,1/3,PMC3,PMC3/Ch08,2,HVC2/11,2149,FTC-F3,FTC-F3-3 +3,1,0,11,PM,9,140,1/3,PMC3,PMC3/Ch09,2,HVC2/10,2134,FTC-F2,FTC-F2-1 +3,1,0,11,PM,10,141,1/3,PMC3,PMC3/Ch10,2,HVC2/10,2134,FTC-F2,FTC-F2-2 +3,1,0,11,PM,11,142,1/3,PMC3,PMC3/Ch11,2,HVC2/10,2134,FTC-F2,FTC-F2-4 +3,1,0,11,PM,12,143,1/3,PMC3,PMC3/Ch12,2,HVC2/10,2134,FTC-F2,FTC-F2-3 +4,1,0,12,PM,1,144,1/4,PMC4,PMC4/Ch01,3,HVC3/08,2137,FTC-E4,FTC-E4-2 +4,1,0,12,PM,2,145,1/4,PMC4,PMC4/Ch02,3,HVC3/08,2137,FTC-E4,FTC-E4-1 +4,1,0,12,PM,3,146,1/4,PMC4,PMC4/Ch03,3,HVC3/08,2137,FTC-E4,FTC-E4-3 +4,1,0,12,PM,4,147,1/4,PMC4,PMC4/Ch04,3,HVC3/08,2137,FTC-E4,FTC-E4-4 +4,1,0,12,PM,5,148,1/4,PMC4,PMC4/Ch05,3,HVC3/10,2152,FTC-F4,FTC-F4-2 +4,1,0,12,PM,6,149,1/4,PMC4,PMC4/Ch06,3,HVC3/10,2152,FTC-F4,FTC-F4-1 +4,1,0,12,PM,7,150,1/4,PMC4,PMC4/Ch07,3,HVC3/10,2152,FTC-F4,FTC-F4-3 +4,1,0,12,PM,8,151,1/4,PMC4,PMC4/Ch08,3,HVC3/10,2152,FTC-F4,FTC-F4-4 +4,1,0,12,PM,9,152,1/4,PMC4,PMC4/Ch09,3,HVC3/11,2142,FTC-F5,FTC-F5-2 +4,1,0,12,PM,10,153,1/4,PMC4,PMC4/Ch10,3,HVC3/11,2142,FTC-F5,FTC-F5-1 +4,1,0,12,PM,11,154,1/4,PMC4,PMC4/Ch11,3,HVC3/11,2142,FTC-F5,FTC-F5-3 +4,1,0,12,PM,12,155,1/4,PMC4,PMC4/Ch12,3,HVC3/11,2142,FTC-F5,FTC-F5-4 +5,1,0,13,PM,1,156,1/5,PMC5,PMC5/Ch01,3,HVC3/06,2157,FTC-D5,FTC-D5-1 +5,1,0,13,PM,2,157,1/5,PMC5,PMC5/Ch02,3,HVC3/06,2157,FTC-D5,FTC-D5-2 +5,1,0,13,PM,3,158,1/5,PMC5,PMC5/Ch03,3,HVC3/06,2157,FTC-D5,FTC-D5-4 +5,1,0,13,PM,4,159,1/5,PMC5,PMC5/Ch04,3,HVC3/06,2157,FTC-D5,FTC-D5-3 +5,1,0,13,PM,5,160,1/5,PMC5,PMC5/Ch05,3,HVC3/07,2167,FTC-D6,FTC-D6-1 +5,1,0,13,PM,6,161,1/5,PMC5,PMC5/Ch06,3,HVC3/07,2167,FTC-D6,FTC-D6-2 +5,1,0,13,PM,7,162,1/5,PMC5,PMC5/Ch07,3,HVC3/07,2167,FTC-D6,FTC-D6-4 +5,1,0,13,PM,8,163,1/5,PMC5,PMC5/Ch08,3,HVC3/07,2167,FTC-D6,FTC-D6-3 +5,1,0,13,PM,9,164,1/5,PMC5,PMC5/Ch09,3,HVC3/09,2165,FTC-E6,FTC-E6-2 +5,1,0,13,PM,10,165,1/5,PMC5,PMC5/Ch10,3,HVC3/09,2165,FTC-E6,FTC-E6-3 +5,1,0,13,PM,11,166,1/5,PMC5,PMC5/Ch11,3,HVC3/09,2165,FTC-E6,FTC-E6-1 +5,1,0,13,PM,12,167,1/5,PMC5,PMC5/Ch12,3,HVC3/09,2165,FTC-E6,FTC-E6-4 +6,1,0,14,PM,1,168,1/6,PMC6,PMC6/Ch01,3,HVC3/04,2148,FTC-C5,FTC-C5-4 +6,1,0,14,PM,2,169,1/6,PMC6,PMC6/Ch02,3,HVC3/04,2148,FTC-C5,FTC-C5-3 +6,1,0,14,PM,3,170,1/6,PMC6,PMC6/Ch03,3,HVC3/04,2148,FTC-C5,FTC-C5-1 +6,1,0,14,PM,4,171,1/6,PMC6,PMC6/Ch04,3,HVC3/04,2148,FTC-C5,FTC-C5-2 +6,1,0,14,PM,5,172,1/6,PMC6,PMC6/Ch05,3,HVC3/05,2162,FTC-C6,FTC-C6-4 +6,1,0,14,PM,6,173,1/6,PMC6,PMC6/Ch06,3,HVC3/05,2162,FTC-C6,FTC-C6-3 +6,1,0,14,PM,7,174,1/6,PMC6,PMC6/Ch07,3,HVC3/05,2162,FTC-C6,FTC-C6-1 +6,1,0,14,PM,8,175,1/6,PMC6,PMC6/Ch08,3,HVC3/05,2162,FTC-C6,FTC-C6-2 +6,1,0,14,PM,9,176,1/6,PMC6,PMC6/Ch09,3,HVC3/03,2144,FTC-B6,FTC-B6-2 +6,1,0,14,PM,10,177,1/6,PMC6,PMC6/Ch10,3,HVC3/03,2144,FTC-B6,FTC-B6-1 +6,1,0,14,PM,11,178,1/6,PMC6,PMC6/Ch11,3,HVC3/03,2144,FTC-B6,FTC-B6-3 +6,1,0,14,PM,12,179,1/6,PMC6,PMC6/Ch12,3,HVC3/03,2144,FTC-B6,FTC-B6-4 +7,1,0,15,PM,1,180,1/7,PMC7,PMC7/Ch01,3,HVC3/02,2136,FTC-B4,FTC-B4-1 +7,1,0,15,PM,2,181,1/7,PMC7,PMC7/Ch02,3,HVC3/02,2136,FTC-B4,FTC-B4-2 +7,1,0,15,PM,3,182,1/7,PMC7,PMC7/Ch03,3,HVC3/02,2136,FTC-B4,FTC-B4-4 +7,1,0,15,PM,4,183,1/7,PMC7,PMC7/Ch04,3,HVC3/02,2136,FTC-B4,FTC-B4-3 +7,1,0,15,PM,5,184,1/7,PMC7,PMC7/Ch05,3,HVC3/00,2151,FTC-A4,FTC-A4-1 +7,1,0,15,PM,6,185,1/7,PMC7,PMC7/Ch06,3,HVC3/00,2151,FTC-A4,FTC-A4-2 +7,1,0,15,PM,7,186,1/7,PMC7,PMC7/Ch07,3,HVC3/00,2151,FTC-A4,FTC-A4-4 +7,1,0,15,PM,8,187,1/7,PMC7,PMC7/Ch08,3,HVC3/00,2151,FTC-A4,FTC-A4-3 +7,1,0,15,PM,9,188,1/7,PMC7,PMC7/Ch09,3,HVC3/01,2141,FTC-A5,FTC-A5-1 +7,1,0,15,PM,10,189,1/7,PMC7,PMC7/Ch10,3,HVC3/01,2141,FTC-A5,FTC-A5-2 +7,1,0,15,PM,11,190,1/7,PMC7,PMC7/Ch11,3,HVC3/01,2141,FTC-A5,FTC-A5-4 +7,1,0,15,PM,12,191,1/7,PMC7,PMC7/Ch12,3,HVC3/01,2141,FTC-A5,FTC-A5-3 +8,1,0,16,PM,1,192,1/8,PMC8,PMC8/Ch01,4,HVC4/00,2121,FTC-B2,FTC-B2-2 +8,1,0,16,PM,2,193,1/8,PMC8,PMC8/Ch02,4,HVC4/00,2121,FTC-B2,FTC-B2-3 +8,1,0,16,PM,3,194,1/8,PMC8,PMC8/Ch03,4,HVC4/00,2121,FTC-B2,FTC-B2-1 +8,1,0,16,PM,4,195,1/8,PMC8,PMC8/Ch04,4,HVC4/00,2121,FTC-B2,FTC-B2-4 +8,1,0,16,PM,5,196,1/8,PMC8,PMC8/Ch05,4,HVC4/01,2133,FTC-E2,FTC-E2-1 +8,1,0,16,PM,6,197,1/8,PMC8,PMC8/Ch06,4,HVC4/01,2133,FTC-E2,FTC-E2-2 +8,1,0,16,PM,7,198,1/8,PMC8,PMC8/Ch07,4,HVC4/01,2133,FTC-E2,FTC-E2-4 +8,1,0,16,PM,8,199,1/8,PMC8,PMC8/Ch08,4,HVC4/01,2133,FTC-E2,FTC-E2-3 +8,1,0,16,PM,9,200,1/8,PMC8,PMC8/Ch09,N/A,N/A,N/A,N/A,N/A +8,1,0,16,PM,10,201,1/8,PMC8,PMC8/Ch10,N/A,N/A,N/A,N/A,N/A +8,1,0,16,PM,11,202,1/8,PMC8,PMC8/Ch11,N/A,N/A,N/A,N/A,N/A +8,1,0,16,PM,12,203,1/8,PMC8,PMC8/Ch12,N/A,N/A,N/A,N/A,N/A +9,1,0,17,PM,1,204,1/9,PMC9,PMC9/Ch01,4,HVC4/02,2158,FTC-E5,FTC-E5-2 +9,1,0,17,PM,2,205,1/9,PMC9,PMC9/Ch02,4,HVC4/02,2158,FTC-E5,FTC-E5-3 +9,1,0,17,PM,3,206,1/9,PMC9,PMC9/Ch03,4,HVC4/02,2158,FTC-E5,FTC-E5-1 +9,1,0,17,PM,4,207,1/9,PMC9,PMC9/Ch04,4,HVC4/02,2158,FTC-E5,FTC-E5-4 +9,1,0,17,PM,5,208,1/9,PMC9,PMC9/Ch05,4,HVC4/03,2143,FTC-B5,FTC-B5-1 +9,1,0,17,PM,6,209,1/9,PMC9,PMC9/Ch06,4,HVC4/03,2143,FTC-B5,FTC-B5-2 +9,1,0,17,PM,7,210,1/9,PMC9,PMC9/Ch07,4,HVC4/03,2143,FTC-B5,FTC-B5-4 +9,1,0,17,PM,8,211,1/9,PMC9,PMC9/Ch08,4,HVC4/03,2143,FTC-B5,FTC-B5-3 +9,1,0,17,PM,9,212,1/9,PMC9,PMC9/Ch09,N/A,N/A,N/A,N/A,N/A +9,1,0,17,PM,10,213,1/9,PMC9,PMC9/Ch10,N/A,N/A,N/A,N/A,N/A +9,1,0,17,PM,11,214,1/9,PMC9,PMC9/Ch11,N/A,N/A,N/A,N/A,N/A +9,1,0,17,PM,12,215,1/9,PMC9,PMC9/Ch12,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,1,216,0/9,PMA9,PMA9/Ch01,4,HVC4/11,N/A,FT0-LCS,FTA-LCS +9,0,0,18,PM-LCS,2,217,0/9,PMA9,PMA9/Ch02,4,HVC4/11,N/A,FT0-LCS,FTA-LCS-H +9,0,0,18,PM-LCS,3,218,0/9,PMA9,PMA9/Ch03,4,HVC4/11,N/A,FT0-LCS,FTC-LCS +9,0,0,18,PM-LCS,4,219,0/9,PMA9,PMA9/Ch04,4,HVC4/11,N/A,FT0-LCS,FTC-LCS-H +9,0,0,18,PM-LCS,5,220,0/9,PMA9,PMA9/Ch05,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,6,221,0/9,PMA9,PMA9/Ch06,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,7,222,0/9,PMA9,PMA9/Ch07,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,8,223,0/9,PMA9,PMA9/Ch08,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,9,224,0/9,PMA9,PMA9/Ch09,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,10,225,0/9,PMA9,PMA9/Ch10,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,11,226,0/9,PMA9,PMA9/Ch11,N/A,N/A,N/A,N/A,N/A +9,0,0,18,PM-LCS,12,227,0/9,PMA9,PMA9/Ch12,N/A,N/A,N/A,N/A,N/A +11,0,0,19,TCM,,228,0/11,TCM,,,,,, diff --git a/Detectors/FIT/FT0/base/files/Sim2DataChannels.txt b/Detectors/FIT/FT0/base/files/Sim2DataChannels.txt new file mode 100644 index 0000000000000..f0ac8688df266 --- /dev/null +++ b/Detectors/FIT/FT0/base/files/Sim2DataChannels.txt @@ -0,0 +1,52 @@ +59 58 57 56 +55 54 53 52 +51 50 48 49 +46 47 44 45 +41 43 40 42 +61 63 62 60 +15 14 13 12 +11 10 8 9 +5 7 4 6 +37 39 36 38 +66 65 67 64 +18 17 19 16 +0 3 1 2 +32 35 33 34 +70 68 71 69 +22 20 23 21 +25 24 26 27 +28 29 30 31 +92 94 93 95 +74 72 75 73 +76 77 79 78 +81 80 82 83 +84 85 86 87 +88 89 90 91 +175 173 174 172 +204 206 205 207 +171 169 170 168 +200 202 201 203 +119 117 118 116 +140 142 141 143 +115 114 113 112 +136 137 138 139 +167 166 165 164 +196 197 198 199 +111 110 109 108 +132 133 134 135 +163 162 161 160 +192 193 194 195 +106 107 104 105 +129 128 131 130 +158 159 156 157 +189 188 191 190 +97 99 96 98 +122 120 123 121 +101 103 100 102 +126 124 127 125 +154 155 152 153 +185 184 187 186 +145 147 144 146 +178 176 179 177 +149 151 148 150 +182 180 183 181 diff --git a/Detectors/FIT/FT0/base/include/FT0Base/Constants.h b/Detectors/FIT/FT0/base/include/FT0Base/Constants.h new file mode 100644 index 0000000000000..ab3fdd9454a96 --- /dev/null +++ b/Detectors/FIT/FT0/base/include/FT0Base/Constants.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Constants.h +/// \brief General constants in FT0 +/// +/// \author Artur Furs, afurs@cern.ch + +#ifndef ALICEO2_FT0_CONSTANTS_ +#define ALICEO2_FT0_CONSTANTS_ + +namespace o2 +{ +namespace ft0 +{ + +struct Constants { + constexpr static std::size_t sNPM = 18; //Number of PMs + constexpr static std::size_t sNPM_LCS = 1; //Number of PM-LCSs + constexpr static std::size_t sNTCM = 1; //Number of TCMs + constexpr static std::size_t sNTOTAL_PM = sNPM + sNPM_LCS; //Total number of PMs(PM + PM_LCS) + constexpr static std::size_t sNTOTAL_FEE = sNPM + sNPM_LCS + sNTCM; //Total number of FEE modules + + constexpr static std::size_t sNCHANNELS_PER_PM = 12; //Number of local channels per PM + constexpr static std::size_t sNCHANNELS_PM = sNPM * sNCHANNELS_PER_PM; //Number of PM(not LCS) channels + constexpr static std::size_t sNCHANNELS_PM_LCS = sNPM_LCS * sNCHANNELS_PER_PM; //Number of PM_LCS channels + constexpr static std::size_t sNTOTAL_CHANNELS_PM = sNCHANNELS_PM + sNCHANNELS_PM_LCS; //Total number of PM(+LCS) channels +}; + +} // namespace ft0 +} // namespace o2 +#endif diff --git a/Detectors/FIT/FT0/base/include/FT0Base/Geometry.h b/Detectors/FIT/FT0/base/include/FT0Base/Geometry.h index 9d405806424e6..0365e730828cb 100644 --- a/Detectors/FIT/FT0/base/include/FT0Base/Geometry.h +++ b/Detectors/FIT/FT0/base/include/FT0Base/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,9 +14,17 @@ //////////////////////////////////////////////// // Full geomrtry hits classes for detector: FIT // //////////////////////////////////////////////// - +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "FT0Base/Constants.h" +#include "Framework/Logger.h" #include <Rtypes.h> +#include <TGeoPhysicalNode.h> #include <TVector3.h> +#include <string> + +class TGeoPNEntry; + namespace o2 { namespace ft0 @@ -35,20 +44,32 @@ class Geometry /// TVector3 centerMCP(int imcp) { return mMCP[imcp]; } + TVector3 tiltMCP(int imcp) { return mAngles[imcp]; } - static constexpr int NCellsA = 24; // number of radiatiors on A side - static constexpr int NCellsC = 28; // number of radiatiors on C side - static constexpr float ZdetA = 335; // number of radiatiors on A side - static constexpr float ZdetC = 82; // number of radiatiors on C side - static constexpr float ChannelWidth = 13.02; // channel width in ps - static constexpr float MV_2_Nchannels = 2.2857143; //amplitude channel 7 mV ->16channels - static constexpr float MV_2_NchannelsInverse = 0.437499997; //inverse amplitude channel 7 mV ->16channels - static constexpr int mTime_trg_gate = 192; // #channels + // static constexpr int Nchannels = o2::ft0::Constants::sNCHANNELS_PM; // number of PM channels + static constexpr int Nchannels = 208; // number of sensors + static constexpr int Nsensors = 208; // number of sensors + static constexpr int NCellsA = 24; // number of radiatiors on A side + static constexpr int NCellsC = 28; // number of radiatiors on C side + static constexpr float ZdetA = 335.5; // Z position of center volume on A side + static constexpr float ZdetC = 82; // Z position of center volume on C side + static constexpr float ChannelWidth = 13.02; // channel width in ps + static constexpr float ChannelWidthInverse = 0.076804916; // channel width in ps inverse + static constexpr o2::detectors::DetID::ID getDetID() { return o2::detectors::DetID::FT0; } + void setAsideModules(); + void setCsideModules(); + TGeoPNEntry* getPNEntry(int index) const + { + /// Get a pointer to the TGeoPNEntry of a chip identified by 'index' + /// Returns NULL in case of invalid index, missing TGeoManager or invalid symbolic name + return o2::base::GeometryManager::getPNEntry(getDetID(), index); + } private: TVector3 mMCP[52]; + TVector3 mAngles[28]; - ClassDefNV(Geometry, 1); + ClassDefNV(Geometry, 2); }; } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/base/src/FT0BaseLinkDef.h b/Detectors/FIT/FT0/base/src/FT0BaseLinkDef.h index ba34f1e82413b..bb9f9c55abb33 100644 --- a/Detectors/FIT/FT0/base/src/FT0BaseLinkDef.h +++ b/Detectors/FIT/FT0/base/src/FT0BaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/base/src/Geometry.cxx b/Detectors/FIT/FT0/base/src/Geometry.cxx index 6d30591501427..09eead0a77a41 100644 --- a/Detectors/FIT/FT0/base/src/Geometry.cxx +++ b/Detectors/FIT/FT0/base/src/Geometry.cxx @@ -1,42 +1,60 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include <iomanip> -//#include <TVector3.h> #include "FT0Base/Geometry.h" - -#include <FairLogger.h> +#include "TSystem.h" +#include "Framework/Logger.h" #include <sstream> +#include <iomanip> +#include <string> +#include <iostream> ClassImp(o2::ft0::Geometry); +using namespace TMath; +using namespace o2::detectors; using namespace o2::ft0; Geometry::Geometry() : mMCP{{0, 0, 0}} { - Float_t zDetA = 333; - Float_t xa[24] = {-11.8, -5.9, 0, 5.9, 11.8, -11.8, -5.9, 0, 5.9, 11.8, -12.8, -6.9, - 6.9, 12.8, -11.8, -5.9, 0, 5.9, 11.8, -11.8, -5.9, 0, 5.9, 11.8}; - - Float_t ya[24] = {11.9, 11.9, 12.9, 11.9, 11.9, 6.0, 6.0, 7.0, 6.0, 6.0, -0., -0., - 0., 0., -6.0, -6.0, -7.0, -6.0, -6.0, -11.9, -11.9, -12.9, -11.9, -11.9}; - - Float_t pmcp[3] = {2.949, 2.949, 2.8}; // MCP - - // Matrix(idrotm[901], 90., 0., 90., 90., 180., 0.); + setAsideModules(); + setCsideModules(); +} +void Geometry::setAsideModules() +{ + Float_t mPosModuleAx[Geometry::NCellsA] = {-12.2, -6.1, 0, 6.1, 12.2, -12.2, -6.1, 0, + 6.1, 12.2, -13.3743, -7.274299999999999, + 7.274299999999999, 13.3743, -12.2, -6.1, 0, + 6.1, 12.2, -12.2, -6.1, 0, 6.1, 12.2}; + + Float_t mPosModuleAy[Geometry::NCellsA] = {12.2, 12.2, 13.53, 12.2, 12.2, 6.1, 6.1, + 7.43, 6.1, 6.1, 0, 0, 0, 0, -6.1, -6.1, + -7.43, -6.1, -6.1, -12.2, -12.2, -13.53, + -12.2, -12.2}; + + // A side Translations + for (Int_t ipmt = 0; ipmt < NCellsA; ipmt++) { + mMCP[ipmt].SetXYZ(mPosModuleAx[ipmt], mPosModuleAy[ipmt], ZdetA); + } +} +void Geometry::setCsideModules() +{ // C side Concave Geometry + Float_t mInStart[3] = {2.9491, 2.9491, 2.5}; + Float_t mStartC[3] = {20., 20, 5.5}; - Double_t crad = 82.; // define concave c-side radius here + Double_t crad = ZdetC; // define concave c-side radius here - Double_t dP = pmcp[0]; // side length of mcp divided by 2 + Double_t dP = mInStart[0]; // side length of mcp divided by 2 // uniform angle between detector faces== Double_t btta = 2 * TMath::ATan(dP / crad); @@ -47,25 +65,35 @@ Geometry::Geometry() : mMCP{{0, 0, 0}} for (Int_t i = 0; i < 6; i++) { gridpoints[i] = crad * TMath::Sin((1 - 1 / (2 * TMath::Abs(grdin[i]))) * grdin[i] * btta); } - - Double_t xi[28] = {gridpoints[1], gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[0], gridpoints[1], - gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[5], gridpoints[0], gridpoints[1], - gridpoints[4], gridpoints[5], gridpoints[0], gridpoints[1], gridpoints[4], gridpoints[5], - gridpoints[0], gridpoints[1], gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[5], - gridpoints[1], gridpoints[2], gridpoints[3], gridpoints[4]}; - Double_t yi[28] = {gridpoints[5], gridpoints[5], gridpoints[5], gridpoints[5], gridpoints[4], gridpoints[4], - gridpoints[4], gridpoints[4], gridpoints[4], gridpoints[4], gridpoints[3], gridpoints[3], - gridpoints[3], gridpoints[3], gridpoints[2], gridpoints[2], gridpoints[2], gridpoints[2], - gridpoints[1], gridpoints[1], gridpoints[1], gridpoints[1], gridpoints[1], gridpoints[1], - gridpoints[0], gridpoints[0], gridpoints[0], gridpoints[0]}; - Double_t zi[28]; - for (Int_t i = 0; i < 28; i++) { + Double_t xi[NCellsC] = {-15.038271418735729, 15.038271418735729, + -15.003757581112167, 15.003757581112167, -9.02690018974363, + 9.02690018974363, -9.026897413747076, 9.026897413747076, + -9.026896531935773, 9.026896531935773, -3.0004568618531313, + 3.0004568618531313, -3.0270795197907225, 3.0270795197907225, + 3.0003978432927543, -3.0003978432927543, 3.0270569670429572, + -3.0270569670429572, 9.026750365564254, -9.026750365564254, + 9.026837450695885, -9.026837450695885, 9.026849243816981, + -9.026849243816981, 15.038129472387304, -15.038129472387304, + 15.003621961057961, -15.003621961057961}; + Double_t yi[NCellsC] = {3.1599494336464455, -3.1599494336464455, + 9.165191680982874, -9.165191680982874, 3.1383331772537426, + -3.1383331772537426, 9.165226363918643, -9.165226363918643, + 15.141616002932361, -15.141616002932361, 9.16517861649866, + -9.16517861649866, 15.188854859073416, -15.188854859073416, + 9.165053319552113, -9.165053319552113, 15.188703787345304, + -15.188703787345304, 3.138263189805292, -3.138263189805292, + 9.165104089644917, -9.165104089644917, 15.141494417823818, + -15.141494417823818, 3.1599158563428644, -3.1599158563428644, + 9.165116302773846, -9.165116302773846}; + + Double_t zi[NCellsC]; + for (Int_t i = 0; i < NCellsC; i++) { zi[i] = TMath::Sqrt(TMath::Power(crad, 2) - TMath::Power(xi[i], 2) - TMath::Power(yi[i], 2)); } // get rotation data - Double_t ac[28], bc[28], gc[28]; - for (Int_t i = 0; i < 28; i++) { + Double_t ac[NCellsC], bc[NCellsC], gc[NCellsC]; + for (Int_t i = 0; i < NCellsC; i++) { ac[i] = TMath::ATan(yi[i] / xi[i]) - TMath::Pi() / 2 + 2 * TMath::Pi(); if (xi[i] < 0) { bc[i] = TMath::ACos(zi[i] / crad); @@ -73,12 +101,12 @@ Geometry::Geometry() : mMCP{{0, 0, 0}} bc[i] = -1 * TMath::ACos(zi[i] / crad); } } - Double_t xc2[28], yc2[28], zc2[28]; + Double_t xc2[NCellsC], yc2[NCellsC], zc2[NCellsC]; // compensation based on node position within individual detector geometries // determine compensated radius - Double_t rcomp = crad /*+ pstartC[2] / 2.0*/; // - for (Int_t i = 0; i < 28; i++) { + Double_t rcomp = crad + mStartC[2] / 2.0; // + for (Int_t i = 0; i < NCellsC; i++) { // Get compensated translation data xc2[i] = rcomp * TMath::Cos(ac[i] + TMath::Pi() / 2) * TMath::Sin(-1 * bc[i]); yc2[i] = rcomp * TMath::Sin(ac[i] + TMath::Pi() / 2) * TMath::Sin(-1 * bc[i]); @@ -88,12 +116,7 @@ Geometry::Geometry() : mMCP{{0, 0, 0}} ac[i] *= 180 / TMath::Pi(); bc[i] *= 180 / TMath::Pi(); gc[i] = -1 * ac[i]; - } - // Set coordinate - for (int ipmt = 0; ipmt < 24; ipmt++) { - mMCP[ipmt].SetXYZ(xa[ipmt], xa[ipmt], zDetA); - } - for (int ipmt = 24; ipmt < 52; ipmt++) { - mMCP[ipmt].SetXYZ(xc2[ipmt - 24], yc2[ipmt - 24], zc2[ipmt - 24]); + mAngles[i].SetXYZ(ac[i], bc[i], gc[i]); + mMCP[i + NCellsA].SetXYZ(xc2[i], yc2[i], zc2[i]); } } diff --git a/Detectors/FIT/FT0/calibration/CMakeLists.txt b/Detectors/FIT/FT0/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..c9a7f11d1a0ad --- /dev/null +++ b/Detectors/FIT/FT0/calibration/CMakeLists.txt @@ -0,0 +1,88 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FT0Calibration + SOURCES + src/FT0ChannelTimeTimeSlotContainer.cxx + src/FT0ChannelTimeCalibrationObject.cxx + src/FT0CalibTimeSlewing.cxx + src/FT0CalibCollector.cxx + src/RecoCalibInfoWorkflow.cxx + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::MathUtils + O2::DataFormatsFT0 + O2::DetectorsCalibration + O2::DataFormatsGlobalTracking + ROOT::Minuit + Microsoft.GSL::GSL + ) + o2_target_root_dictionary(FT0Calibration + HEADERS + include/FT0Calibration/FT0CalibrationInfoObject.h + include/FT0Calibration/FT0ChannelTimeCalibrationObject.h + include/FT0Calibration/FT0ChannelTimeTimeSlotContainer.h + include/FT0Calibration/FT0DummyCalibrationObject.h + include/FT0Calibration/FT0CalibTimeSlewing.h + include/FT0Calibration/FT0CalibCollector.h + include/FT0Calibration/RecoCalibInfoWorkflow.h + ) + o2_add_executable(ft0-channel-offset-calibration + COMPONENT_NAME calibration + SOURCES testWorkflow/FT0ChannelTimeCalibration-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsFT0 O2::FITCalibration + ) + + o2_add_executable(ft0-tf-processor + COMPONENT_NAME calibration + SOURCES testWorkflow/FT0TFProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsFT0 O2::FITCalibration + ) + o2_add_executable(ft0-calibration + COMPONENT_NAME calibration + SOURCES testWorkflow/FT0Calibration-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsFT0 O2::FITCalibration + ) + o2_add_executable(ft0-collect-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/ft0-collect-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsFT0 O2::FITCalibration O2::DetectorsCalibration + ) + o2_add_executable(ft0-slew-upload + COMPONENT_NAME calibration + SOURCES testWorkflow/slew_upload.cxx + PUBLIC_LINK_LIBRARIES + O2::FITCalibration O2::DetectorsCalibration + ) + o2_add_executable(ft0-collect-global-offsets + COMPONENT_NAME calibration + SOURCES testWorkflow/calib-global-offsets.cxx + PUBLIC_LINK_LIBRARIES + O2::DetectorsCalibration O2::FITCalibration O2::GlobalTrackingWorkflowHelpers + ) + o2_add_executable(ft0-calib-ft0-zero-time + COMPONENT_NAME calibration + SOURCES testWorkflow/GlobalOffsetsCalibrationWorkflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DetectorsCalibration O2::FITCalibration + ) + + o2_add_executable(ft0-dummy-example + COMPONENT_NAME calibration + SOURCES testWorkflow/FT0CalibrationDummy-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsFT0 O2::FITCalibration + ) +o2_data_file(COPY files DESTINATION Detectors/FT0/) \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/files/dispatcherCalib.json b/Detectors/FIT/FT0/calibration/files/dispatcherCalib.json new file mode 100644 index 0000000000000..edaf486043790 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/files/dispatcherCalib.json @@ -0,0 +1,21 @@ +{ + "dataSamplingPolicies": [ + { + "id": "sampling1", + "active": "true", + "machines": [ + "localhost" + ], + "query": "digits:FT0/DIGITSBC/0;channels:FT0/DIGITSCH/0", + "outputs": "digits_sampled:FT0/SUB_DIGITSBC/0;channels_sampled:FT0/SUB_DIGITSCH/0", + "samplingConditions": [ + { + "condition": "random", + "fraction": "0.99", + "seed": "1234" + } + ], + "blocking": "false" + } + ] +} diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibCollector.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibCollector.h new file mode 100644 index 0000000000000..2074ea0703432 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibCollector.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef FT0_CALIB_COLLECTOR_H_ +#define FT0_CALIB_COLLECTOR_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "FT0Base/Geometry.h" + +#include <array> + +namespace o2 +{ +namespace ft0 +{ + +class FT0CalibInfoSlot +{ + + using Slot = o2::calibration::TimeSlot<o2::ft0::FT0CalibInfoSlot>; + using Geo = o2::ft0::Geometry; + + public: + static constexpr int NCHANNELS = Geo::Nchannels; + static constexpr int HISTO_RANGE = 200; + + FT0CalibInfoSlot() + { + for (int ch = 0; ch < NCHANNELS; ch++) { + mEntriesSlot[ch] = 0; + } + } + + ~FT0CalibInfoSlot() = default; + + void print() const; + void printEntries() const; + void fill(const gsl::span<const o2::ft0::FT0CalibrationInfoObject> data); + void merge(const FT0CalibInfoSlot* prev); + + auto& getEntriesPerChannel() const { return mEntriesSlot; } + auto& getEntriesPerChannel() { return mEntriesSlot; } + auto& getCollectedCalibInfoSlot() { return mFT0CollectedCalibInfoSlot; } + auto& getCollectedCalibInfoSlot() const { return mFT0CollectedCalibInfoSlot; } + + private: + std::array<int, NCHANNELS> mEntriesSlot; // vector containing number of entries per channel + std::vector<o2::ft0::FT0CalibrationInfoObject> mFT0CollectedCalibInfoSlot; ///< output FT0 calibration info + + ClassDefNV(FT0CalibInfoSlot, 1); +}; + +class FT0CalibCollector final : public o2::calibration::TimeSlotCalibration<o2::ft0::FT0CalibrationInfoObject, o2::ft0::FT0CalibInfoSlot> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<o2::ft0::FT0CalibInfoSlot>; + static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; + + public: + FT0CalibCollector(bool TFsendingPolicy, int maxNumOfHits, bool test = false) : mTFsendingPolicy(TFsendingPolicy), mMaxNumOfHits(maxNumOfHits), mTest(test){}; + + ~FT0CalibCollector() final = default; + + bool hasEnoughData(const Slot& slot) const final; + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + void setIsTest(bool istest) { mTest = istest; } + auto& getCollectedCalibInfo() const { return mFT0CollectedCalibInfo; } + auto& getEntriesPerChannel() const { return mEntries; } + void setIsMaxNumberOfHitsAbsolute(bool absNumber) { mAbsMaxNumOfHits = absNumber; } + + private: + bool mTFsendingPolicy = false; // whether we will send information at every TF or only when we have a certain statistics + int mMaxNumOfHits = 1000000; // maximum number of hits for one single channel to trigger the sending of the information (if mTFsendingPolicy = false) + bool mTest = false; // flag to say whether we are in test mode or not + bool mAbsMaxNumOfHits = true; // to decide if the mMaxNumOfHits should be multiplied by the number of FT0 channels + std::array<int, NCHANNELS> mEntries; // vector containing number of entries per channel + std::vector<o2::ft0::FT0CalibrationInfoObject> mFT0CollectedCalibInfo; ///< output FT0 calibration info + + ClassDefOverride(FT0CalibCollector, 1); +}; + +} // end namespace ft0 +} // end namespace o2 + +#endif /* FT0 CALIB COLLECTOR */ diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibTimeSlewing.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibTimeSlewing.h new file mode 100644 index 0000000000000..6ff71b100fb26 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibTimeSlewing.h @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibTimeSlewingParamFT0.h +/// \brief Class to store the output of the matching to FT0 for calibration + +#ifndef ALICEO2_FT0CALIBTIMESLEWING_H +#define ALICEO2_FT0CALIBTIMESLEWING_H + +#include <vector> +#include <array> +#include <TGraph.h> +#include <TH2F.h> +#include <TTree.h> +#include <TGraph.h> +#include "Rtypes.h" +#include "FairLogger.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "FT0Base/Geometry.h" +namespace o2::ft0 +{ +static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; +class FT0CalibTimeSlewing +{ + public: + static constexpr int HISTOGRAM_RANGE_X = 4000; + static constexpr unsigned int NUMBER_OF_HISTOGRAM_BINS_X = HISTOGRAM_RANGE_X / 4; + static constexpr int HISTOGRAM_RANGE_Y = 200; + static constexpr unsigned int NUMBER_OF_HISTOGRAM_BINS_Y = HISTOGRAM_RANGE_Y; + FT0CalibTimeSlewing(); + + FT0CalibTimeSlewing(const FT0CalibTimeSlewing& source) = default; + + FT0CalibTimeSlewing& operator=(const FT0CalibTimeSlewing& source) = default; + + float getChannelOffset(int channel, int amplitude) const; + + const TGraph getGraph(int channel) const { return mTimeSlewing[channel]; } + std::array<TGraph, NCHANNELS> getGraphs() const { return mTimeSlewing; } + void fillGraph(int channel, TH2F* histo); + + float getSigmaPeak(int channel) const { return mSigmaPeak[channel]; } + void setSigmaPeak(int channel, float value) { mSigmaPeak[channel] = value; } + + ///< perform all initializations + void init(); + void mergeFilesWithTree(); + void fillHistos(TTree* tr); + TH2F* getTimeAmpHist(int channel) { return mTimeAmpHist[channel]; }; + void setSingleFileName(std::string name) { mSingleFileName = name; } + void setMergedFileName(std::string name) { mMergedFileName = name; } + void setNfiles(int nfiles) { mNfiles = nfiles; }; + + FT0CalibTimeSlewing& operator+=(const FT0CalibTimeSlewing& other); + + private: + // FT0 channel calibrations + std::array<TGraph, NCHANNELS> mTimeSlewing; ///< array of TGraph wirh time -amplitude for each channel + std::array<float, NCHANNELS> mSigmaPeak; ///< array with the sigma of the peak + TFile* mMergedFile; // file with merged tree + TH2F* mTimeAmpHist[NCHANNELS]; //historgams time vs amplitude + int mNfiles; // number of files with stored Tree with CalibrationInfoObject + std::string mSingleFileName; + std::string mMergedFileName; + + ClassDefNV(FT0CalibTimeSlewing, 1); // class for FT0 time slewing params +}; +} // namespace o2::ft0 +#endif diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibrationInfoObject.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibrationInfoObject.h new file mode 100644 index 0000000000000..bf1c9c6f15b61 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0CalibrationInfoObject.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0CALIBRATIONINFOOBJECT_H +#define O2_FT0CALIBRATIONINFOOBJECT_H + +#include "Rtypes.h" + +namespace o2 +{ +namespace ft0 +{ +class FT0CalibrationInfoObject +{ + public: + FT0CalibrationInfoObject(uint8_t channel, int16_t time, int32_t amp) : mChannelIndex(channel), mTime(time), mAmp(amp){}; + FT0CalibrationInfoObject() = default; + ~FT0CalibrationInfoObject() = default; + + void setChannelIndex(uint8_t channel) { mChannelIndex = channel; } + [[nodiscard]] uint8_t getChannelIndex() const { return mChannelIndex; } + + void setTime(int8_t time) { mTime = time; } + [[nodiscard]] int8_t getTime() const { return mTime; } + void setAmp(int16_t amp) { mAmp = amp; } + [[nodiscard]] int16_t getAmp() const { return mAmp; } + + private: + uint8_t mChannelIndex; + int16_t mTime; + int16_t mAmp; + + ClassDefNV(FT0CalibrationInfoObject, 2); +}; +} // namespace ft0 +} // namespace o2 + +#endif //O2_FT0CALIBRATIONINFOOBJECT_H diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeCalibrationObject.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeCalibrationObject.h new file mode 100644 index 0000000000000..b614abb23b966 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeCalibrationObject.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0CHANNELTIMECALIBRATIONOBJECT_H +#define O2_FT0CHANNELTIMECALIBRATIONOBJECT_H + +#include <array> +#include "Rtypes.h" +#include "DataFormatsFT0/RawEventData.h" + +namespace o2::ft0 +{ + +struct FT0ChannelTimeCalibrationObject { + + std::array<int16_t, o2::ft0::Geometry::Nchannels> mTimeOffsets{}; + + ClassDefNV(FT0ChannelTimeCalibrationObject, 1); +}; + +class FT0ChannelTimeTimeSlotContainer; + +class FT0TimeChannelOffsetCalibrationObjectAlgorithm +{ + public: + [[nodiscard]] static FT0ChannelTimeCalibrationObject generateCalibrationObject(const FT0ChannelTimeTimeSlotContainer& container); +}; + +} // namespace o2::ft0 + +#endif //O2_FT0CHANNELTIMECALIBRATIONOBJECT_H diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeTimeSlotContainer.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeTimeSlotContainer.h new file mode 100644 index 0000000000000..77e7bfe8d2d15 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0ChannelTimeTimeSlotContainer.h @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0CHANNELTIMETIMESLOTCONTAINER_H +#define O2_FT0CHANNELTIMETIMESLOTCONTAINER_H + +#include <array> +#include <vector> +#include <gsl/span> +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "DataFormatsFT0/RawEventData.h" +#include "DataFormatsFT0/ChannelData.h" +#include "Rtypes.h" +#include <boost/histogram.hpp> + +namespace o2::ft0 +{ + +class FT0ChannelTimeTimeSlotContainer final +{ + + //ranges to be discussed + static constexpr int HISTOGRAM_RANGE = 200; + static constexpr unsigned int NUMBER_OF_HISTOGRAM_BINS = 2 * HISTOGRAM_RANGE; + + using BoostHistogramType = boost::histogram::histogram<std::tuple<boost::histogram::axis::integer<>, + boost::histogram::axis::integer<>>, + boost::histogram::unlimited_storage<std::allocator<char>>>; + + public: + explicit FT0ChannelTimeTimeSlotContainer(std::size_t minEntries); + [[nodiscard]] bool hasEnoughEntries() const; + void fill(const gsl::span<const FT0CalibrationInfoObject>& data); + [[nodiscard]] int16_t getMeanGaussianFitValue(std::size_t channelID) const; + void merge(FT0ChannelTimeTimeSlotContainer* prev); + void print() const; + + private: + std::size_t mMinEntries; + std::array<uint64_t, o2::ft0::Geometry::Nchannels> mEntriesPerChannel{}; + BoostHistogramType mHistogram; + + ClassDefNV(FT0ChannelTimeTimeSlotContainer, 1); +}; + +} // namespace o2::ft0 + +#endif //O2_FT0CHANNELTIMETIMESLOTCONTAINER_H diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0DummyCalibrationObject.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0DummyCalibrationObject.h new file mode 100644 index 0000000000000..86a527c64c045 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0DummyCalibrationObject.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +//Dummy calibration object to present usage of FIT calibration module +//Should be deleted if no more needed as an example + +#ifndef O2_FT0DUMMYCALIBRATIONOBJECT_H +#define O2_FT0DUMMYCALIBRATIONOBJECT_H + +#include <array> +#include "Rtypes.h" +#include "DataFormatsFT0/RawEventData.h" + +namespace o2::ft0 +{ + +struct FT0DummyCalibrationObjectTime { + + std::array<int16_t, o2::ft0::Nchannels_FT0> mStorage{}; + ClassDefNV(FT0DummyCalibrationObjectTime, 1); +}; + +struct FT0DummyCalibrationObjectCharge { + std::array<int16_t, o2::ft0::Nchannels_FT0> mStorage{}; + ClassDefNV(FT0DummyCalibrationObjectCharge, 1); +}; + +struct FT0DummyNeededCalibrationObject { + std::array<int16_t, o2::ft0::Nchannels_FT0> mStorage{}; + ClassDefNV(FT0DummyNeededCalibrationObject, 1); +}; + +//lets assume this object contains other calibration objects +struct FT0DummyCalibrationObject { + + FT0DummyCalibrationObjectTime mTimeCalibrationObject; + FT0DummyCalibrationObjectCharge mChargeCalibrationObject; + + ClassDefNV(FT0DummyCalibrationObject, 1); +}; + +//lets use existing container (which can be also modified if needed) +class FT0ChannelTimeTimeSlotContainer; + +class FT0DummyCalibrationObjectAlgorithm +{ + public: + [[nodiscard]] static FT0DummyCalibrationObject generateCalibrationObject(const FT0ChannelTimeTimeSlotContainer& container, const FT0DummyNeededCalibrationObject& additionalObjectNeededForCalibration) + { + //(add here your printing stuff for debug) + //do nothing + (void)additionalObjectNeededForCalibration; + return {}; + } +}; + +} // namespace o2::ft0 + +#endif //O2_FT0DUMMYCALIBRATIONOBJECT_H diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/RecoCalibInfoWorkflow.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/RecoCalibInfoWorkflow.h new file mode 100644 index 0000000000000..7d1f58397bd3e --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/RecoCalibInfoWorkflow.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoCalibInfoWorkflow.h +///\ brief Collect data for global offsets calibration +/// \author Alla.Maevskaya@cern.ch + +#ifndef O2_RECOCALIBINFO_WORKFLOW +#define O2_RECOCALIBINFO_WORKFLOW + +#include <FairLogger.h> +#include <Framework/ConfigContext.h> +#include <TMath.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsFT0/RecPoints.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "DataFormatsFT0/RecoCalibInfoObject.h" +#include "TStopwatch.h" +#include <string> +#include <vector> + +using namespace o2::framework; +using DataRequest = o2::globaltracking::DataRequest; +using GID = o2::dataformats::GlobalTrackID; + +namespace o2::ft0 +{ + +class RecoCalibInfoWorkflow final : public o2::framework::Task +{ + public: + RecoCalibInfoWorkflow(GID::mask_t src, std::shared_ptr<DataRequest> const& dataRequest) : mInputSources(src), mDataRequest(dataRequest) {} + void run(o2::framework::ProcessingContext& pc) final; + void init(InitContext& ic) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + const float cSpeed = 0.029979246f; // speed of light in TOF units + GID::mask_t mInputSources; + TStopwatch mTimer; +}; +framework::DataProcessorSpec getRecoCalibInfoWorkflow(GID::mask_t src, bool useMC); + +} // namespace o2::ft0 + +#endif /* O2_RECOCALIBINFO_WORKFLOW */ diff --git a/Detectors/FIT/FT0/calibration/macros/CMakeLists.txt b/Detectors/FIT/FT0/calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..372d7a9967a12 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/macros/CMakeLists.txt @@ -0,0 +1,8 @@ +o2_add_test_root_macro( + makeDummyFT0CalibObjectInCCDB.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsFT0 O2::Framework O2::CCDB O2::FT0Calibration O2::DetectorsCalibration) + + +install( + FILES makeDummyFT0CalibObjectInCCDB.C + DESTINATION share/macro/) diff --git a/Detectors/FIT/FT0/calibration/macros/makeDummyFT0CalibObjectInCCDB.C b/Detectors/FIT/FT0/calibration/macros/makeDummyFT0CalibObjectInCCDB.C new file mode 100644 index 0000000000000..58db1f90b3e16 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/macros/makeDummyFT0CalibObjectInCCDB.C @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include <iostream> +#include "FT0Calibration/FT0DummyCalibrationObject.h" + +int makeDummyFT0CalibObjectInCCDB(const std::string url = "http://localhost:8080") +{ + + o2::ccdb::CcdbApi api; + api.init(url); + std::map<std::string, std::string> md; + o2::ft0::FT0DummyNeededCalibrationObject obj; + api.storeAsTFileAny(&obj, "FT0/Calibration/DummyNeeded", md, 0); + + return 0; +} diff --git a/Detectors/FIT/FT0/calibration/src/FT0CalibCollector.cxx b/Detectors/FIT/FT0/calibration/src/FT0CalibCollector.cxx new file mode 100644 index 0000000000000..aee0df75f401b --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/FT0CalibCollector.cxx @@ -0,0 +1,164 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Calibration/FT0CalibCollector.h" +#include "Framework/Logger.h" +#include <cassert> +#include <iostream> +#include <sstream> +#include <TStopwatch.h> + +namespace o2 +{ +namespace ft0 +{ + +using Slot = o2::calibration::TimeSlot<o2::ft0::FT0CalibInfoSlot>; + +//_____________________________________________ +void FT0CalibInfoSlot::fill(const gsl::span<const o2::ft0::FT0CalibrationInfoObject> data) +{ + // fill container + // we first order the data that arrived, to improve speed when filling + int nd = data.size(); + LOG(INFO) << "FT0CalibInfoSlot::fill entries in incoming data = " << nd; + std::vector<int> ord(nd); + std::iota(ord.begin(), ord.end(), 0); + std::sort(ord.begin(), ord.end(), [&data](int i, int j) { return data[i].getChannelIndex() < data[j].getChannelIndex(); }); + int chPrev = 0, offsPrev = 0; + for (int i = 0; i < nd; i++) { + if (std::abs(data[ord[i]].getTime()) > HISTO_RANGE) { + continue; + } + const auto& dti = data[ord[i]]; + auto ch = dti.getChannelIndex(); + auto offset = offsPrev; + if (ch > chPrev) { + offset += std::accumulate(mEntriesSlot.begin() + chPrev, mEntriesSlot.begin() + ch, 0); + } + offsPrev = offset; + chPrev = ch; + auto it = mFT0CollectedCalibInfoSlot.emplace(mFT0CollectedCalibInfoSlot.begin() + offset, data[ord[i]].getChannelIndex(), data[ord[i]].getTime(), data[ord[i]].getAmp()); + mEntriesSlot[ch]++; + } +} +//_____________________________________________ +void FT0CalibInfoSlot::merge(const FT0CalibInfoSlot* prev) +{ + // merge data of 2 slots + + LOG(INFO) << "Merging two slots with entries: current slot -> " << mFT0CollectedCalibInfoSlot.size() << " , previous slot -> " << prev->mFT0CollectedCalibInfoSlot.size(); + + int offset = 0, offsetPrev = 0; + std::vector<o2::ft0::FT0CalibrationInfoObject> tmpVector; + for (int ch = 0; ch < NCHANNELS; ch++) { + if (mEntriesSlot[ch] != 0) { + for (int i = offset; i < offset + mEntriesSlot[ch]; i++) { + tmpVector.emplace_back(mFT0CollectedCalibInfoSlot[i]); + } + offset += mEntriesSlot[ch]; + } + if (prev->mEntriesSlot[ch] != 0) { + for (int i = offsetPrev; i < offsetPrev + prev->mEntriesSlot[ch]; i++) { + tmpVector.emplace_back(prev->mFT0CollectedCalibInfoSlot[i]); + } + offsetPrev += prev->mEntriesSlot[ch]; + mEntriesSlot[ch] += prev->mEntriesSlot[ch]; + } + } + mFT0CollectedCalibInfoSlot.swap(tmpVector); + LOG(DEBUG) << "After merging the size is " << mFT0CollectedCalibInfoSlot.size(); + return; +} +//_____________________________________________ +void FT0CalibInfoSlot::print() const +{ + // to print number of entries in the tree and the channel with the max number of entries + + LOG(INFO) << "Total number of entries " << mFT0CollectedCalibInfoSlot.size(); + auto maxElementIndex = std::max_element(mEntriesSlot.begin(), mEntriesSlot.end()); + auto channelIndex = std::distance(mEntriesSlot.begin(), maxElementIndex); + LOG(INFO) << "The maximum number of entries per channel in the current mFT0CollectedCalibInfo is " << *maxElementIndex << " for channel " << channelIndex; + return; +} + +//_____________________________________________ +void FT0CalibInfoSlot::printEntries() const +{ + // to print number of entries in the tree and per channel + + LOG(DEBUG) << "Total number of entries " << mFT0CollectedCalibInfoSlot.size(); + for (int i = 0; i < mEntriesSlot.size(); ++i) { + if (mEntriesSlot[i] != 0) { + LOG(INFO) << "channel " << i << " has " << mEntriesSlot[i] << " entries"; + } + } + return; +} + +//=================================================================== + +//_____________________________________________ +void FT0CalibCollector::initOutput() +{ + // emptying the vectors + + mFT0CollectedCalibInfo.clear(); + for (int ch = 0; ch < NCHANNELS; ch++) { + mEntries[ch] = 0; + } + + return; +} + +//_____________________________________________ +bool FT0CalibCollector::hasEnoughData(const Slot& slot) const +{ + // We define that we have enough data if the tree is big enough. + // each FT0CalibrationInfoObject is composed of two int8 and one int16 --> 32 bytes + // E.g. supposing that we have 500000 entries per channel --> 500 eneries per one amplitude bin + // we can check if we have 500000*o2::ft0::Geometry::NCHANNELS entries in the vector + + if (mTest) { + return true; + } + const o2::ft0::FT0CalibInfoSlot* c = slot.getContainer(); + LOG(INFO) << "we have " << c->getCollectedCalibInfoSlot().size() << " entries"; + int maxNumberOfHits = mAbsMaxNumOfHits ? mMaxNumOfHits : mMaxNumOfHits * NCHANNELS; + if (mTFsendingPolicy || c->getCollectedCalibInfoSlot().size() > maxNumberOfHits) { + return true; + } + return false; +} + +//_____________________________________________ +void FT0CalibCollector::finalizeSlot(Slot& slot) +{ + + o2::ft0::FT0CalibInfoSlot* c = slot.getContainer(); + mFT0CollectedCalibInfo = c->getCollectedCalibInfoSlot(); + LOG(INFO) << "vector of received with size = " << mFT0CollectedCalibInfo.size(); + mEntries = c->getEntriesPerChannel(); + return; +} + +//_____________________________________________ +Slot& FT0CalibCollector::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<FT0CalibInfoSlot>()); + return slot; +} + +} // end namespace ft0 +} // end namespace o2 diff --git a/Detectors/FIT/FT0/calibration/src/FT0CalibTimeSlewing.cxx b/Detectors/FIT/FT0/calibration/src/FT0CalibTimeSlewing.cxx new file mode 100644 index 0000000000000..4c156409701bf --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/FT0CalibTimeSlewing.cxx @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file FT0CalibTimeSlewing.cxx +/// \brief Class for slewing calibration object +/// +#include <algorithm> +#include <cstdio> +#include <TH1F.h> +#include <TF1.h> +#include <TFitResult.h> +#include <TFileMerger.h> +#include <TFile.h> +#include "FT0Calibration/FT0CalibTimeSlewing.h" + +using namespace o2::ft0; + +FT0CalibTimeSlewing::FT0CalibTimeSlewing() +{ + for (int iCh = 0; iCh < NCHANNELS; iCh++) { + mSigmaPeak[iCh] = -1.; + mTimeAmpHist[iCh] = new TH2F(Form("hTimeAmpHist%d", iCh), Form("TimeAmp%d", iCh), + NUMBER_OF_HISTOGRAM_BINS_X, 0, HISTOGRAM_RANGE_X, + NUMBER_OF_HISTOGRAM_BINS_Y, -HISTOGRAM_RANGE_Y, HISTOGRAM_RANGE_Y); + } +} + +//______________________________________________ +float FT0CalibTimeSlewing::getChannelOffset(int channel, int amplitude) const +{ + return mTimeSlewing[channel].Eval(amplitude); +} + +//______________________________________________ +void FT0CalibTimeSlewing::fillGraph(int channel, TH2F* histo) +{ + LOG(INFO) << "FT0CalibTimeSlewing::fillGraph " << channel << " entries " << int(histo->GetEntries()); + double shiftchannel = 0; + TH1D* hist_Proj = histo->ProjectionY(); + TFitResultPtr res = hist_Proj->Fit("gaus", "SQ"); + if ((Int_t)res == 0) { + shiftchannel = res->Parameter(1); + } + Double_t xgr[NUMBER_OF_HISTOGRAM_BINS_X] = {}; + Double_t ygr[NUMBER_OF_HISTOGRAM_BINS_X] = {}; + TH1D* proj = nullptr; + int nbins = 0; + for (int ibin = 1; ibin < NUMBER_OF_HISTOGRAM_BINS_X; ibin++) { + xgr[ibin] = histo->GetXaxis()->GetBinCenter(ibin); + proj = histo->ProjectionY(Form("proj_px%i", ibin), ibin, ibin + 1); + if (proj->GetEntries() < 500) { + ygr[ibin] = 0; + continue; + } + TFitResultPtr r = proj->Fit("gaus", "SQ"); + if ((Int_t)r == 0) { + ygr[ibin] = r->Parameter(1) - shiftchannel; + } + nbins++; + LOG(INFO) << "channel " << channel << " bin " << ibin << " x " << xgr[ibin] << " y " << ygr[ibin] << " ent " << proj->GetEntries() << " sigma " << r->Parameter(2) << " shiftchannel " << shiftchannel; + } + TGraph* grTimeAmp = new TGraph(nbins + 5, xgr, ygr); + mTimeSlewing[channel] = *grTimeAmp; +} +//______________________________________________ +FT0CalibTimeSlewing& FT0CalibTimeSlewing::operator+=(const FT0CalibTimeSlewing& other) +{ + for (int i = 0; i < NCHANNELS; i++) { + mTimeSlewing[i] = other.mTimeSlewing[i]; + mSigmaPeak[i] = other.mSigmaPeak[i]; + } + return *this; +} + +//______________________________________________ +void FT0CalibTimeSlewing::mergeFilesWithTree() +{ + TFileMerger merger; + merger.OutputFile(mMergedFileName.c_str()); + for (Int_t i = 0; i < mNfiles; i++) { + TFile* file = + TFile::Open(Form("%s_%d.root", mSingleFileName.c_str(), i)); + if (file) { + merger.AddAdoptFile(file); + } + } + if (!merger.Merge()) { + LOG(FATAL) << "Could not merge files"; + } + TFile mMergedFile{merger.GetOutputFileName()}; + TTree* tr = (TTree*)mMergedFile.Get("treeCollectedCalibInfo"); + if (!tr) { + LOG(FATAL) << "Could not get tree with calib info"; + } + fillHistos(tr); +} + +//______________________________________________ +void FT0CalibTimeSlewing::fillHistos(TTree* tr) +{ + std::vector<o2::ft0::FT0CalibrationInfoObject>* localCalibInfoFT0 = nullptr; + if (!tr->GetBranch("FT0CollectedCalibInfo")) { + LOG(FATAL) << "Did not find collected FT0 calib info branch in the input tree"; + } + tr->SetBranchAddress("FT0CollectedCalibInfo", &localCalibInfoFT0); + for (Int_t ievent = 0; ievent < tr->GetEntries(); ievent++) { + tr->GetEvent(ievent); + for (auto& info : *localCalibInfoFT0) { + LOG(DEBUG) << " ch " << int(info.getChannelIndex()) << " time " << info.getTime() << " amp " << info.getAmp(); + int iCh = info.getChannelIndex(); + mTimeAmpHist[iCh]->Fill(info.getAmp(), info.getTime()); + } + } + delete localCalibInfoFT0; +} diff --git a/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h new file mode 100644 index 0000000000000..fff0211aa2260 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::ft0::FT0CalibrationInfoObject + ; +#pragma link C++ class o2::ft0::FT0ChannelTimeCalibrationObject + ; +#pragma link C++ class o2::ft0::FT0ChannelTimeTimeSlotContainer + ; +#pragma link C++ class o2::ft0::FT0CalibTimeSlewing + ; +#pragma link C++ class o2::ft0::FT0CalibCollector + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::FT0CalibrationInfoObject, o2::ft0::FT0CalibInfoSlot>; +//delete lines below +#pragma link C++ class o2::ft0::FT0DummyCalibrationObject + ; +#pragma link C++ class o2::ft0::FT0DummyCalibrationObjectTime + ; +#pragma link C++ class o2::ft0::FT0DummyCalibrationObjectCharge + ; +#pragma link C++ class o2::ft0::FT0DummyNeededCalibrationObject + ; + +#endif diff --git a/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeCalibrationObject.cxx b/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeCalibrationObject.cxx new file mode 100644 index 0000000000000..fda8bc3554847 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeCalibrationObject.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" + +using namespace o2::ft0; + +FT0ChannelTimeCalibrationObject FT0TimeChannelOffsetCalibrationObjectAlgorithm::generateCalibrationObject(const FT0ChannelTimeTimeSlotContainer& container) +{ + FT0ChannelTimeCalibrationObject calibrationObject; + + for (unsigned int iCh = 0; iCh < o2::ft0::Geometry::Nchannels; ++iCh) { + calibrationObject.mTimeOffsets[iCh] = container.getMeanGaussianFitValue(iCh); + LOG(INFO) << " generateCalibrationObject " << iCh << " " << calibrationObject.mTimeOffsets[iCh]; + } + + return calibrationObject; +} diff --git a/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeTimeSlotContainer.cxx b/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeTimeSlotContainer.cxx new file mode 100644 index 0000000000000..84d75fc5b7cde --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/FT0ChannelTimeTimeSlotContainer.cxx @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" +#include "FT0Base/Geometry.h" +#include <numeric> +#include <algorithm> +#include "MathUtils/fit.h" + +using namespace o2::ft0; + +FT0ChannelTimeTimeSlotContainer::FT0ChannelTimeTimeSlotContainer(std::size_t minEntries) + : mMinEntries(minEntries) +{ + + mHistogram = boost::histogram::make_histogram(boost::histogram::axis::integer<>(-HISTOGRAM_RANGE, HISTOGRAM_RANGE, "channel_times"), + boost::histogram::axis::integer<>(0, o2::ft0::Nchannels_FT0, "channel_ID")); +} + +bool FT0ChannelTimeTimeSlotContainer::hasEnoughEntries() const +{ + return *std::min_element(mEntriesPerChannel.begin(), mEntriesPerChannel.end()) > mMinEntries; +} +void FT0ChannelTimeTimeSlotContainer::fill(const gsl::span<const FT0CalibrationInfoObject>& data) +{ + + for (auto& entry : data) { + + const auto chID = entry.getChannelIndex(); + const auto chTime = entry.getTime(); + + //i dont really know when should it be marked as invalid + if (chID < o2::ft0::Geometry::Nchannels) { + mHistogram(chTime, chID); + ++mEntriesPerChannel[chID]; + } else { + LOG(FATAL) << "Invalid channel data"; + } + } +} + +void FT0ChannelTimeTimeSlotContainer::merge(FT0ChannelTimeTimeSlotContainer* prev) +{ + + mHistogram += prev->mHistogram; + for (unsigned int iCh = 0; iCh < o2::ft0::Geometry::Nchannels; ++iCh) { + mEntriesPerChannel[iCh] += prev->mEntriesPerChannel[iCh]; + } +} + +int16_t FT0ChannelTimeTimeSlotContainer::getMeanGaussianFitValue(std::size_t channelID) const +{ + + static constexpr size_t MEAN_VALUE_INDEX_IN_OUTPUT_VECTOR = 1; + + if (0 == mEntriesPerChannel[channelID]) { + return 0; + } + LOG(DEBUG) << " for channel " << int(channelID) << " entries " << mEntriesPerChannel[channelID]; + std::vector<double> channelHistogramData(NUMBER_OF_HISTOGRAM_BINS); + std::vector<double> outputGaussianFitValues; + for (int iBin = 0; iBin < NUMBER_OF_HISTOGRAM_BINS; ++iBin) { + channelHistogramData[iBin] = mHistogram.at(iBin, channelID); + } + + double returnCode = math_utils::fitGaus<double>(NUMBER_OF_HISTOGRAM_BINS, channelHistogramData.data(), + -HISTOGRAM_RANGE, HISTOGRAM_RANGE, outputGaussianFitValues); + if (returnCode < 0) { + LOG(ERROR) << "Gaussian fit error!"; + return 0; + } + + return static_cast<int16_t>(std::round(outputGaussianFitValues[MEAN_VALUE_INDEX_IN_OUTPUT_VECTOR])); +} +void FT0ChannelTimeTimeSlotContainer::print() const +{ + //QC will do that part +} diff --git a/Detectors/FIT/FT0/calibration/src/RecoCalibInfoWorkflow.cxx b/Detectors/FIT/FT0/calibration/src/RecoCalibInfoWorkflow.cxx new file mode 100644 index 0000000000000..f32be452da5af --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/RecoCalibInfoWorkflow.cxx @@ -0,0 +1,110 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoCalibInfoWorkflow.cxx +///\ brief Collect data for global offsets calibration +/// \author Alla.Maevskaya@cern.ch + +#include <FairLogger.h> +#include <Framework/ConfigContext.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsFT0/RecPoints.h" +#include "FT0Calibration/RecoCalibInfoWorkflow.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "DataFormatsFT0/RecoCalibInfoObject.h" +#include <TMath.h> +#include <vector> +#include <map> + +using namespace o2::framework; +using namespace o2::math_utils::detail; +using PVertex = o2::dataformats::PrimaryVertex; +using GIndex = o2::dataformats::VtxTrackIndex; +using DataRequest = o2::globaltracking::DataRequest; + +namespace o2::ft0 +{ +void RecoCalibInfoWorkflow::init(InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); +} +void RecoCalibInfoWorkflow::run(o2::framework::ProcessingContext& pc) +{ + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest); + auto primVertices = recoData.getPrimaryVertices(); + auto ft0RecPoints = recoData.getFT0RecPoints(); + std::map<uint64_t, o2::dataformats::PrimaryVertex const*> bcsMap; + auto& calib_data = pc.outputs().make<std::vector<o2::ft0::RecoCalibInfoObject>>(o2::framework::OutputRef{"calib", 0}); + calib_data.reserve(ft0RecPoints.size()); + for (auto& vertex : primVertices) { + auto& timeStamp = vertex.getTimeStamp(); + double tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns + uint64_t globalBC = std::round(tsTimeStamp / o2::constants::lhc::LHCBunchSpacingNS); + LOG(DEBUG) << "PrimVertices " << globalBC; + auto [iter, inserted] = bcsMap.try_emplace(globalBC, &vertex); + if (!inserted) { + iter->second = nullptr; + } + } + for (auto& ft0RecPoint : ft0RecPoints) { + uint64_t bc = ft0RecPoint.getInteractionRecord().toLong(); + auto item = bcsMap.find(bc); + LOG(DEBUG) << " <<ft0RecPoints " << bc; + if (item == bcsMap.end() || item->second == nullptr) { + LOG(DEBUG) << "Error: could not find a corresponding BC ID for a FT0 rec. point; BC = " << bc; + continue; + } + auto& vertex = *item->second; + auto currentVertex = vertex.getZ(); + ushort ncont = vertex.getNContributors(); + LOG(DEBUG) << "CurrentVertex " << currentVertex << " ncont " << int(ncont); + if (ncont < 3) { + continue; + } + auto shift = currentVertex / cSpeed; + short t0A = ft0RecPoint.getCollisionTimeA() + shift; + short t0C = ft0RecPoint.getCollisionTimeC() - shift; + short t0AC = ft0RecPoint.getCollisionTimeMean(); + LOG(DEBUG) << " BC t0 " << bc << " shift " << shift << " A " << t0A << " C " << t0C << " AC " << t0AC; + calib_data.emplace_back(t0A, t0C, t0AC); + } + mTimer.Stop(); +} +void RecoCalibInfoWorkflow::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "Reco calib info workflow dpl total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getRecoCalibInfoWorkflow(GID::mask_t src, bool useMC) +{ + auto dataRequest = std::make_shared<DataRequest>(); + dataRequest->requestPrimaryVertertices(false); + dataRequest->requestFT0RecPoints(false); + + return DataProcessorSpec{ + "calib-global-offsets", + dataRequest->inputs, + Outputs{ + {{"calib"}, "FT0", "CALIB_INFO"}}, + AlgorithmSpec{adaptFromTask<o2::ft0::RecoCalibInfoWorkflow>(src, dataRequest)}, + Options{}}; +} + +}; // namespace o2::ft0 diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibCollectorWriterSpec.h b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibCollectorWriterSpec.h new file mode 100644 index 0000000000000..cfa4927d4a1af --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibCollectorWriterSpec.h @@ -0,0 +1,129 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_FT0CALIB_COLLECTOR_WRITER_H +#define O2_CALIBRATION_FT0CALIB_COLLECTOR_WRITER_H + +/// @file FT0CalibCollectorWriterSpec.h +/// @brief Device to write to tree the information for FT0 time slewing calibration. + +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include <TTree.h> +#include <gsl/span> +#include "FairLogger.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace calibration +{ + +class FT0CalibCollectorWriter : public o2::framework::Task +{ + + using Geo = o2::ft0::Geometry; + + public: + void createAndOpenFileAndTree() + { + TString filename = TString::Format("collFT0%d.root", mCount); + LOG(DEBUG) << "opening file " << filename.Data(); + mfileOut.reset(TFile::Open(TString::Format("%s", filename.Data()), "RECREATE")); + mOutputTree = std::make_unique<TTree>("treeCollectedCalibInfo", "Tree with FT0 calib info for Time Slewing"); + mOutputTree->Branch(mOutputBranchName.data(), &mPFT0CalibInfoOut); + } + + void init(o2::framework::InitContext& ic) final + { + mCount = 0; + createAndOpenFileAndTree(); + mFT0CalibInfoOut.reserve(1000000 * Geo::Nchannels); // tree size 216ch * 10^6 entries * 12 byte + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto collectedInfo = pc.inputs().get<gsl::span<o2::ft0::FT0CalibrationInfoObject>>("collectedInfo"); + auto entriesPerChannel = pc.inputs().get<gsl::span<int>>("entriesCh"); + int offsetStart = 0; + for (int ich = 0; ich < Geo::Nchannels; ich++) { + mFT0CalibInfoOut.clear(); + if (entriesPerChannel[ich] > 0) { + mFT0CalibInfoOut.resize(entriesPerChannel[ich]); + auto subSpanVect = collectedInfo.subspan(offsetStart, entriesPerChannel[ich]); + memcpy(&mFT0CalibInfoOut[0], subSpanVect.data(), sizeof(o2::ft0::FT0CalibrationInfoObject) * subSpanVect.size()); + const o2::ft0::FT0CalibrationInfoObject* tmp = subSpanVect.data(); + } + mOutputTree->Fill(); + offsetStart += entriesPerChannel[ich]; + } + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + mIsEndOfStream = true; + sendOutput(ec.outputs()); + } + + private: + int mCount = 0; // how many times we filled the tree + bool mIsEndOfStream = false; + std::vector<o2::ft0::FT0CalibrationInfoObject> mFT0CalibInfoOut, *mPFT0CalibInfoOut = &mFT0CalibInfoOut; ///< these are the object and pointer to the CalibInfo of a specific channel that we need to fill the output tree + std::unique_ptr<TTree> mOutputTree; ///< tree for the collected calib FT0 info + std::string mFT0CalibInfoBranchName = "FT0CalibInfo"; ///< name of branch containing input FT0 calib infos + std::string mOutputBranchName = "FT0CollectedCalibInfo"; ///< name of branch containing output + std::unique_ptr<TFile> mfileOut = nullptr; // file in which to write the output + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + // This is to fill the tree. + // One file with an empty tree will be created at the end, because we have to have a + // tree opened before processing, since we do not know a priori if something else + // will still come. The size of this extra file is ~6.5 kB + + mfileOut->cd(); + mOutputTree->Write(); + mOutputTree->Reset(); + mCount++; + if (!mIsEndOfStream) { + createAndOpenFileAndTree(); + } + } +}; +} // namespace calibration + +namespace framework +{ + +DataProcessorSpec getFT0CalibCollectorWriterSpec() +{ + LOG(DEBUG) << " @@@@ getFT0CalibCollectorWriterSpec "; + using device = o2::calibration::FT0CalibCollectorWriter; + std::vector<InputSpec> inputs; + inputs.emplace_back("collectedInfo", o2::header::gDataOriginFT0, "COLLECTEDINFO"); + inputs.emplace_back("entriesCh", o2::header::gDataOriginFT0, "ENTRIESCH"); + + std::vector<OutputSpec> outputs; // empty + + return DataProcessorSpec{ + "ft0-calib-collector-writer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibSlewingCollectorSpec.h b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibSlewingCollectorSpec.h new file mode 100644 index 0000000000000..30e25cfadbbae --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibSlewingCollectorSpec.h @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_FT0CALIB_SLEWING_COLLECTOR_H +#define O2_CALIBRATION_FT0CALIB_SLEWING_COLLECTOR_H + +/// @file FT0CalibSlewingCollectorSpec.h +/// @brief Device to collect information for FT0 time slewing calibration. + +//#include "FT0Calibration/FT0CollectCalibInfo.h" +#include "FT0Calibration/FT0CalibCollector.h" +#include "DetectorsCalibration/Utils.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "FairLogger.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace ft0 +{ + +class FT0CalibCollectorDevice : public o2::framework::Task +{ + + public: + void init(o2::framework::InitContext& ic) final + { + bool isTFsendingPolicy = ic.options().get<bool>("tf-sending-policy"); + int maxEnt = ic.options().get<int>("max-number-hits-to-fill-tree"); + bool isTest = ic.options().get<bool>("running-in-test-mode"); + bool absMaxEnt = ic.options().get<bool>("is-max-number-hits-to-fill-tree-absolute"); + mCollector = std::make_unique<o2::ft0::FT0CalibCollector>(isTFsendingPolicy, maxEnt); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; // is this the timestamp of the current TF? + auto data = pc.inputs().get<gsl::span<o2::ft0::FT0CalibrationInfoObject>>("input"); + mCollector->process(tfcounter, data); + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCollector->checkSlotsToFinalize(INFINITE_TF); + // we force finalizing slot zero (unless everything was already finalized), no matter how many entries we had + if (mCollector->getNSlots() != 0) { + mCollector->finalizeSlot(mCollector->getSlot(0)); + } + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<o2::ft0::FT0CalibCollector> mCollector; + int mMaxNumOfHits = 0; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + // in output we send the calibration tree + auto& collectedInfo = mCollector->getCollectedCalibInfo(); + LOG(DEBUG) << "In CollectorSpec sendOutput: size = " << collectedInfo.size(); + if (collectedInfo.size()) { + auto entries = collectedInfo.size(); + // this means that we are ready to send the output + auto entriesPerChannel = mCollector->getEntriesPerChannel(); + output.snapshot(Output{o2::header::gDataOriginFT0, "COLLECTEDINFO", 0, Lifetime::Timeframe}, collectedInfo); + output.snapshot(Output{o2::header::gDataOriginFT0, "ENTRIESCH", 0, Lifetime::Timeframe}, entriesPerChannel); + mCollector->initOutput(); // reset the output for the next round + } + } +}; + +} // namespace ft0 + +namespace framework +{ + +DataProcessorSpec getFT0CalibCollectorDeviceSpec() +{ + using device = o2::ft0::FT0CalibCollectorDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginFT0, "COLLECTEDINFO", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginFT0, "ENTRIESCH", 0, Lifetime::Timeframe); + + std::vector<InputSpec> inputs; + inputs.emplace_back("input", "FT0", "CALIB_INFO"); + + return DataProcessorSpec{ + "calib-ft0calib-collector", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"max-number-hits-to-fill-tree", VariantType::Int, 1000, {"maximum number of entries in one channel to trigger teh filling of the tree"}}, + {"is-max-number-hits-to-fill-tree-absolute", VariantType::Bool, false, {"to decide if we want to multiply the max-number-hits-to-fill-tree by the number of channels (when set to true), or not (when set to false) for fast checks"}}, + {"tf-sending-policy", VariantType::Bool, false, {"if we are sending output at every TF; otherwise, we use the max-number-hits-to-fill-tree"}}, + {"running-in-test-mode", VariantType::Bool, false, {"to run in test mode for simplification"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0Calibration-Workflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/FT0Calibration-Workflow.cxx new file mode 100644 index 0000000000000..a6c977d1d0de2 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0Calibration-Workflow.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0ChannelTimeCalibrationSpec.h" + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + //probably some option will be added +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + workflow.emplace_back(o2::ft0::getFT0ChannelTimeCalibrationSpec()); + //add calib spec here... + return workflow; +} \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibrationDummy-Workflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibrationDummy-Workflow.cxx new file mode 100644 index 0000000000000..ddee1295df6d4 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0CalibrationDummy-Workflow.cxx @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +//Dummy, delete this file if example not needed anymore +#include "Framework/DataProcessorSpec.h" +#include "FITCalibration/FITCalibrationDevice.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" +#include "FT0Calibration/FT0DummyCalibrationObject.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::fit; +using namespace o2::framework; + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + + using CalibrationDeviceType = o2::fit::FITCalibrationDevice<o2::ft0::FT0CalibrationInfoObject, + o2::ft0::FT0ChannelTimeTimeSlotContainer, o2::ft0::FT0DummyCalibrationObject>; + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "FIT_CALIB"}); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "FIT_CALIB"}); + + constexpr const char* DEFAULT_INPUT_LABEL = "calib"; + + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back(DEFAULT_INPUT_LABEL, "FT0", "CALIB_INFO"); + + o2::framework::DataProcessorSpec dataProcessorSpec{ + "calib-ft0-channel-time", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<CalibrationDeviceType>(DEFAULT_INPUT_LABEL)}, + o2::framework::Options{}}; + + workflow.emplace_back(dataProcessorSpec); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibration-Workflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibration-Workflow.cxx new file mode 100644 index 0000000000000..26e079733a2ae --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibration-Workflow.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0ChannelTimeCalibrationSpec.h" + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + //probably some option will be added +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + workflow.emplace_back(o2::ft0::getFT0ChannelTimeCalibrationSpec()); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibrationSpec.h b/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibrationSpec.h new file mode 100644 index 0000000000000..7b0683f9ccab3 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0ChannelTimeCalibrationSpec.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0CHANNELTIMECALIBRATIONSPEC_H +#define O2_FT0CHANNELTIMECALIBRATIONSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "FITCalibration/FITCalibrationDevice.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" + +namespace o2::ft0 +{ +o2::framework::DataProcessorSpec getFT0ChannelTimeCalibrationSpec() +{ + using CalibrationDeviceType = o2::fit::FITCalibrationDevice<o2::ft0::FT0CalibrationInfoObject, + o2::ft0::FT0ChannelTimeTimeSlotContainer, o2::ft0::FT0ChannelTimeCalibrationObject>; + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "FIT_CALIB"}); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "FIT_CALIB"}); + + constexpr const char* DEFAULT_INPUT_LABEL = "calib"; + + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back(DEFAULT_INPUT_LABEL, "FT0", "CALIB_INFO"); + + return o2::framework::DataProcessorSpec{ + "calib-ft0-channel-time", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<CalibrationDeviceType>(DEFAULT_INPUT_LABEL)}, + o2::framework::Options{}}; +} +} // namespace o2::ft0 + +#endif //O2_FT0CHANNELTIMECALIBRATIONSPEC_H diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0SlewingCalibrationWorkflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/FT0SlewingCalibrationWorkflow.cxx new file mode 100644 index 0000000000000..9a9c8e078322a --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0SlewingCalibrationWorkflow.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0SlewingCalibrationSpec.h" + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + //probably some option will be added +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + workflow.emplace_back(o2::ft0::getFT0SlewingCalibrationSpec()); + //add calib spec here... + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/FT0TFProcessor-Workflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/FT0TFProcessor-Workflow.cxx new file mode 100644 index 0000000000000..d94f30c729810 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/FT0TFProcessor-Workflow.cxx @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include <Framework/ConfigContext.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsFT0/ChannelData.h" +#include "DataFormatsFT0/Digit.h" +#include "FT0Calibration/FT0CalibrationInfoObject.h" + +using namespace o2::framework; + +namespace o2::ft0 +{ + +class FT0TFProcessor final : public o2::framework::Task +{ + + public: + void run(o2::framework::ProcessingContext& pc) final + { + auto channels = pc.inputs().get<gsl::span<o2::ft0::ChannelData>>("channels"); + auto digits = pc.inputs().get<gsl::span<o2::ft0::Digit>>("digits"); + auto& calib_data = pc.outputs().make<std::vector<o2::ft0::FT0CalibrationInfoObject>>(o2::framework::OutputRef{"calib", 0}); + calib_data.reserve(channels.size()); + + for (const auto& channel : channels) { + calib_data.emplace_back(channel.ChId, channel.CFDTime, channel.QTCAmpl); + // calib_data.emplace_back(channel.getChannelID(), channel.getTime(), channel.getAmp()); + } + } +}; + +} // namespace o2::ft0 + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options; + options.push_back(ConfigParamSpec{"dispatcher-mode", VariantType::Bool, false, {"Dispatcher mode (FT0/SUB_DIGITSCH and FT0/SUB_DIGITSBC DPL channels should be applied as dispatcher output)."}}); + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + Inputs inputs{}; + if (cfgc.options().get<bool>("dispatcher-mode")) { + inputs.push_back(InputSpec{{"channels"}, "FT0", "SUB_DIGITSCH"}); + inputs.push_back(InputSpec{{"digits"}, "FT0", "SUB_DIGITSBC"}); + } else { + inputs.push_back(InputSpec{{"channels"}, "FT0", "DIGITSCH"}); + inputs.push_back(InputSpec{{"digits"}, "FT0", "DIGITSBC"}); + } + DataProcessorSpec dataProcessorSpec{ + "FT0TFProcessor", + /* + Inputs{ + {{"channels"}, "FT0", "DIGITSCH"}, + {{"digits"}, "FT0", "DIGITSBC"}, + }, +*/ + inputs, + Outputs{ + {{"calib"}, "FT0", "CALIB_INFO"}}, + AlgorithmSpec{adaptFromTask<o2::ft0::FT0TFProcessor>()}, + Options{}}; + + WorkflowSpec workflow; + workflow.emplace_back(dataProcessorSpec); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationSpec.h b/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationSpec.h new file mode 100644 index 0000000000000..ca7091be895f2 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationSpec.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GLOBALOFFSETSCALIBRATIONSPEC_H +#define O2_GLOBALOFFSETSCALIBRATIONSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "FITCalibration/FITCalibrationDevice.h" +#include "DataFormatsFT0/GlobalOffsetsCalibrationObject.h" +#include "DataFormatsFT0/GlobalOffsetsContainer.h" +#include "DataFormatsFT0/RecoCalibInfoObject.h" + +namespace o2::ft0 +{ +o2::framework::DataProcessorSpec getGlobalOffsetsCalibrationSpec() +{ + using CalibrationDeviceType = o2::fit::FITCalibrationDevice<o2::ft0::RecoCalibInfoObject, + o2::ft0::GlobalOffsetsContainer, o2::ft0::GlobalOffsetsCalibrationObject>; + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "FIT_CALIB"}); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "FIT_CALIB"}); + + constexpr const char* DEFAULT_INPUT_LABEL = "calib"; + + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back(DEFAULT_INPUT_LABEL, "FT0", "CALIB_INFO"); + + return o2::framework::DataProcessorSpec{ + "calib-ft0-zero-time", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<CalibrationDeviceType>(DEFAULT_INPUT_LABEL)}, + o2::framework::Options{}}; +} +} // namespace o2::ft0 + +#endif //O2_GLOBALOFFSETSCALIBRATIONSPEC_H diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationWorkflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationWorkflow.cxx new file mode 100644 index 0000000000000..fbd9bd8923ca6 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/GlobalOffsetsCalibrationWorkflow.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GlobalOffsetsCalibrationSpec.h" + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + //probably some option will be added +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + workflow.emplace_back(o2::ft0::getGlobalOffsetsCalibrationSpec()); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/RecoCalibInfoWorkflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/RecoCalibInfoWorkflow.cxx new file mode 100644 index 0000000000000..fc93236ef39c4 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/RecoCalibInfoWorkflow.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <FairLogger.h> +#include <Framework/ConfigContext.h> +#include <TMath.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsFT0/ChannelData.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsFT0/RecPoints.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "DataFormatsFT0/RecoCalibInfoObject.h" + +using namespace o2::framework; + +namespace o2::ft0 +{ + +class RecoCalibInfoWorkflow final : public o2::framework::Task +{ + using DataRequest = o2::globaltracking::DataRequest; + + public: + /* void collectBCs(gsl::span<const o2::ft0::RecPoints>& ft0RecPoints, */ + /* gsl::span<const o2::dataformats::PrimaryVertex>& primVertices, */ + /* std::map<uint64_t, int>& bcsMap); */ + void run(o2::framework::ProcessingContext& pc) final + { + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest); + LOG(INFO) << " @@@read RecoContainer"; + auto primVertices = recoData.getPrimaryVertices(); + LOG(INFO) << "@@@ primVertices "; + auto ft0RecPoints = recoData.getFT0RecPoints(); + LOG(INFO) << "@@@@ read T0 recpoints "; + std::map<uint64_t, o2::dataformats::PrimaryVertex const*> bcsMap; + for (auto& vertex : primVertices) { + auto& timeStamp = vertex.getTimeStamp(); + double tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns + uint64_t globalBC = std::round(tsTimeStamp / o2::constants::lhc::LHCBunchSpacingNS); + auto [iter, inserted] = bcsMap.try_emplace(globalBC, &vertex); + if (!inserted) + iter->second = nullptr; + } + /* collectBCs(ft0RecPoints, primVertices, bcsMap); */ + + for (auto& ft0RecPoint : ft0RecPoints) { + uint64_t bc = ft0RecPoint.getInteractionRecord().toLong(); + /* uint64_t bc = globalBC; */ + auto item = bcsMap.find(bc); + if (item == bcsMap.end() || item->second == nullptr) { + LOG(FATAL) << "Error: could not find a corresponding BC ID for a FT0 rec. point; BC = " << bc; + continue; + } + auto& vertex = *item->second; + /* int bcID = -1; */ + /* if (item != bcsMap.end()) { */ + /* bcID = item->second; */ + auto currentVertex = vertex.getZ(); + ushort ncont = vertex.getNContributors(); + LOG(INFO) << "@@@ currentVertex " << currentVertex << " ncont " << int(ncont); + if (ncont == 0) + continue; + auto shift = currentVertex / TMath::C(); + LOG(INFO) << " BC t0 " << bc; + short t0A = ft0RecPoint.getCollisionTimeA() + shift; + short t0C = ft0RecPoint.getCollisionTimeC() - shift; + short t0AC = ft0RecPoint.getCollisionTimeMean(); + + /* auto recpoints = */ + /* pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("recpoints"); */ + auto& calib_data = pc.outputs().make<std::vector<o2::ft0::RecoCalibInfoObject>>(o2::framework::OutputRef{"calib", 0}); + calib_data.emplace_back(t0A, t0C, t0AC); + } + } + + private: + std::shared_ptr<DataRequest> mDataRequest; +}; + +} // namespace o2::ft0 + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + + DataProcessorSpec dataProcessorSpec{ + "RecoCalibInfoWorkflow", + Inputs{ + {{"recpoints"}, "FT0", "FT0CLUSTER"}, + }, + Outputs{ + {{"calib"}, "FT0", "CALIB_INFO"}}, + AlgorithmSpec{adaptFromTask<o2::ft0::RecoCalibInfoWorkflow>()}, + Options{}}; + + WorkflowSpec workflow; + workflow.emplace_back(dataProcessorSpec); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/calib-global-offsets.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/calib-global-offsets.cxx new file mode 100644 index 0000000000000..71b84abfe63e0 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/calib-global-offsets.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file calib-global-offsets.cxx +#include "FT0Calibration/RecoCalibInfoWorkflow.h" +#include "Framework/CompletionPolicy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <vector> + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, + {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto useMC = !configcontext.options().get<bool>("disable-mc"); + + GID::mask_t allowedSrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,FT0"); + GID::mask_t src = allowedSrc & GID::getSourcesMask(configcontext.options().get<std::string>("info-sources")); + + WorkflowSpec specs; + specs.emplace_back(o2::ft0::getRecoCalibInfoWorkflow(src, useMC)); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, false, src); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, false); + o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/ft0-collect-calib-workflow.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/ft0-collect-calib-workflow.cxx new file mode 100644 index 0000000000000..29c7d9719e0c1 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/ft0-collect-calib-workflow.cxx @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0CalibSlewingCollectorSpec.h" +#include "FT0CalibCollectorWriterSpec.h" +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getFT0CalibCollectorDeviceSpec()); + specs.emplace_back(getFT0CalibCollectorWriterSpec()); + + return specs; +} diff --git a/Detectors/FIT/FT0/calibration/testWorkflow/slew_upload.cxx b/Detectors/FIT/FT0/calibration/testWorkflow/slew_upload.cxx new file mode 100644 index 0000000000000..95432df99a130 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/testWorkflow/slew_upload.cxx @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file slew_upload.cxx +/// \author Alla.Maevskaya@cern.ch + +#include <boost/program_options.hpp> +#include <filesystem> +#include <TFile.h> +#include <TStopwatch.h> +#include "Framework/Logger.h" +#include <string> +#include <iomanip> +#include "CommonUtils/StringUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "FT0Calibration/FT0CalibTimeSlewing.h" +#include <cstdlib> +#include <vector> +#include <fstream> +#include <iostream> +#include <string_view> + +using o2::ccdb::BasicCCDBManager; +using o2::ccdb::CcdbApi; +using namespace o2::ft0; + +namespace bpo = boost::program_options; + +void slew_upload(const std::string& inFileName, const std::string& mergedFileName, int nFiles); + +int main(int argc, char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + "Upload FT0 slewing corrections\n"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("input-file", bpo::value<std::string>()->default_value("collFT0.root"), "verbosity level"); + add_option("merged-file", bpo::value<std::string>()->default_value("FT0slewGraphs.root"), "input merged file"); + add_option("number-of-files", bpo::value<int>()->default_value(1), "number of files to merge"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help")) { + std::cout << opt_general << std::endl; + exit(0); + } + + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + // o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + slew_upload(vm["input-file"].as<std::string>(), + vm["merged-file"].as<std::string>(), + vm["number-of-files"].as<int>()); + + return 0; +} + +void slew_upload(const std::string& inFileName, const std::string& mergedFileName, int nFiles) +{ + TStopwatch swTot; + swTot.Start(); + + o2::ft0::FT0CalibTimeSlewing sl; + sl.setSingleFileName(inFileName); + sl.setMergedFileName(mergedFileName); + sl.setNfiles(nFiles); + sl.mergeFilesWithTree(); + for (int iCh = 0; iCh < o2::ft0 ::Geometry::Nchannels; ++iCh) { + TH2F* hist = sl.getTimeAmpHist(iCh); + if (hist->GetEntries() < 100000) { + continue; + } + sl.fillGraph(iCh, hist); + } + std::array<TGraph, o2::ft0 ::Geometry::Nchannels> graphs = sl.getGraphs(); + TGraph& gr = graphs.at(29); + gr.Print(); + CcdbApi api; + std::map<std::string, std::string> metadata; // can be empty + api.init("http://ccdb-test.cern.ch:8080/"); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&graphs, "FT0/SlewingCorr", metadata); + + // + swTot.Stop(); + swTot.Print(); +} diff --git a/Detectors/FIT/FT0/macros/CMakeLists.txt b/Detectors/FIT/FT0/macros/CMakeLists.txt new file mode 100644 index 0000000000000..c4ed27d2513ba --- /dev/null +++ b/Detectors/FIT/FT0/macros/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_test_root_macro(FT0Misaligner.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::FT0Simulation + LABELS ft0) diff --git a/Detectors/FIT/FT0/macros/FT0Misaligner.C b/Detectors/FIT/FT0/macros/FT0Misaligner.C new file mode 100644 index 0000000000000..9a04e79cc0689 --- /dev/null +++ b/Detectors/FIT/FT0/macros/FT0Misaligner.C @@ -0,0 +1,70 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +//#define ENABLE_UPGRADES +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsBase/GeometryManager.h" +#include "CCDB/CcdbApi.h" +#include "FT0Base/Geometry.h" +#include <TRandom.h> +#include <TFile.h> +#include <vector> +#include <fmt/format.h> +#endif + +using AlgPar = std::array<double, 6>; + +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi); + +void FT0Misaligner(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080", long tmin = 0, long tmax = -1, + double xA = 0., double yA = 0., double zA = 0., double psiA = 0., double thetaA = 0., double phiA = 0., + double xC = 0., double yC = 0., double zC = 0., double psiC = 0., double thetaC = 0., double phiC = 0., + const std::string& objectPath = "", + const std::string& fileName = "FT0Alignment.root") +{ + std::vector<o2::detectors::AlignParam> params; + o2::base::GeometryManager::loadGeometry("", false); + // auto geom = o2::ft0::Geometry::Instance(); + AlgPar pars; + bool glo = true; + + o2::detectors::DetID detFT0("FT0"); + + // FT0 detector + //set A side + std::string symNameA = "FT0A"; + pars = generateMisalignment(xA, yA, zA, psiA, thetaA, phiA); + params.emplace_back(symNameA.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + //set C side + std::string symNameC = "FT0C"; + pars = generateMisalignment(xC, yC, zC, psiC, thetaC, phiC); + params.emplace_back(symNameC.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + + if (!ccdbHost.empty()) { + std::string path = objectPath.empty() ? o2::base::NameConf::getAlignmentPath(detFT0) : objectPath; + LOGP(INFO, "Storing alignment object on {}/{}", ccdbHost, path); + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(¶ms, path, metadata, tmin, tmax); + } + + if (!fileName.empty()) { + LOGP(INFO, "Storing FT0 alignment in local file {}", fileName); + TFile algFile(fileName.c_str(), "recreate"); + algFile.WriteObjectAny(¶ms, "std::vector<o2::detectors::AlignParam>", "alignment"); + algFile.Close(); + } +} +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi) +{ + AlgPar pars; + pars[0] = gRandom->Gaus(0, x); + pars[1] = gRandom->Gaus(0, y); + pars[2] = gRandom->Gaus(0, z); + pars[3] = gRandom->Gaus(0, psi); + pars[4] = gRandom->Gaus(0, theta); + pars[5] = gRandom->Gaus(0, phi); + return std::move(pars); +} diff --git a/Detectors/FIT/FT0/raw/CMakeLists.txt b/Detectors/FIT/FT0/raw/CMakeLists.txt index c2bd979816935..06b4c0f0a33b3 100644 --- a/Detectors/FIT/FT0/raw/CMakeLists.txt +++ b/Detectors/FIT/FT0/raw/CMakeLists.txt @@ -1,13 +1,14 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FT0Raw - SOURCES src/DataBlockFT0.cxx src/DigitBlockFT0.cxx src/RawReaderFT0Base.cxx + SOURCES src/DataBlockFT0.cxx src/DigitBlockFT0.cxx src/RawReaderFT0Base.cxx src/RawWriterFT0.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::DataFormatsFT0 O2::FITRaw) diff --git a/Detectors/FIT/FT0/raw/include/FT0Raw/DataBlockFT0.h b/Detectors/FIT/FT0/raw/include/FT0Raw/DataBlockFT0.h index 407fba225fc1d..ba9ff367794be 100644 --- a/Detectors/FIT/FT0/raw/include/FT0Raw/DataBlockFT0.h +++ b/Detectors/FIT/FT0/raw/include/FT0Raw/DataBlockFT0.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,93 +17,23 @@ #ifndef ALICEO2_FIT_DATABLOCKFT0_H_ #define ALICEO2_FIT_DATABLOCKFT0_H_ -#include <iostream> -#include <Rtypes.h> #include <DataFormatsFT0/RawEventData.h> -#include <FITRaw/DataBlockBase.h> - -#include <gsl/span> -#include <iostream> -#include <cassert> -using namespace o2::fit; +#include <FITRaw/DataBlockFIT.h> namespace o2 { namespace ft0 { +//Raw event data for FT0 using RawHeaderPM = o2::ft0::EventHeader; using RawDataPM = o2::ft0::EventData; using RawHeaderTCM = o2::ft0::EventHeader; using RawDataTCM = o2::ft0::TCMdata; using RawHeaderTCMext = o2::ft0::EventHeader; using RawDataTCMext = o2::ft0::TCMdataExtended; - -using namespace std; - -//FT0 DATA BLOCK DEFINITIONS - -//standard data block from PM -class DataBlockPM : public DataBlockBase<DataBlockPM, RawHeaderPM, RawDataPM> -{ - public: - DataBlockPM() = default; - DataBlockPM(const DataBlockPM&) = default; - void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) - { - DataBlockWrapper<RawHeaderPM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderPM>::MaxNwords, srcByteShift); - DataBlockWrapper<RawDataPM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderPM>::mData[0].nGBTWords, srcByteShift); - } - //Custom sanity checking for current deserialized block - // put here code for raw data checking - void sanityCheck(bool& flag) - { - if (DataBlockWrapper<RawDataPM>::mNelements % 2 == 0 && DataBlockWrapper<RawDataPM>::mData[DataBlockWrapper<RawDataPM>::mNelements - 1].channelID == 0) { - DataBlockWrapper<RawDataPM>::mNelements--; //in case of half GBT-word filling - } - //TODO, Descriptor checking, Channel range - } -}; - -//standard data block from TCM -class DataBlockTCM : public DataBlockBase<DataBlockTCM, RawHeaderTCM, RawDataTCM> -{ - public: - DataBlockTCM() = default; - DataBlockTCM(const DataBlockTCM&) = default; - void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) - { - DataBlockWrapper<RawHeaderTCM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCM>::MaxNwords, srcByteShift); - DataBlockWrapper<RawDataTCM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCM>::mData[0].nGBTWords, srcByteShift); - } - //Custom sanity checking for current deserialized block - // put here code for raw data checking - void sanityCheck(bool& flag) - { - //TODO, Descriptor checking - } -}; - -//extended TCM mode, 1 TCMdata + 8 TCMdataExtendedstructs -class DataBlockTCMext : public DataBlockBase<DataBlockTCMext, RawHeaderTCMext, RawDataTCM, RawDataTCMext> -{ - public: - DataBlockTCMext() = default; - DataBlockTCMext(const DataBlockTCMext&) = default; - void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) - { - DataBlockWrapper<RawHeaderTCMext>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCMext>::MaxNwords, srcByteShift); - DataBlockWrapper<RawDataTCM>::deserialize(srcBytes, DataBlockWrapper<RawDataTCM>::MaxNwords, srcByteShift); - DataBlockWrapper<RawDataTCMext>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCMext>::mData[0].nGBTWords - DataBlockWrapper<RawDataTCM>::MaxNwords, srcByteShift); - } - - //Custom sanity checking for current deserialized block - // put here code for raw data checking - void sanityCheck(bool& flag) - { - - //TODO, Descriptor checking - } -}; - +//Data block for FT0 modules +using DataBlockPM = o2::fit::DataBlockPM<RawHeaderPM, RawDataPM>; +using DataBlockTCM = o2::fit::DataBlockTCM<RawHeaderTCM, RawDataTCM>; +using DataBlockTCMext = o2::fit::DataBlockTCMext<RawHeaderTCMext, RawDataTCM, RawDataTCMext>; } // namespace ft0 } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/FIT/FT0/raw/include/FT0Raw/DigitBlockFT0.h b/Detectors/FIT/FT0/raw/include/FT0Raw/DigitBlockFT0.h index cc7bd3cbdb18e..716d6795e5ad2 100644 --- a/Detectors/FIT/FT0/raw/include/FT0Raw/DigitBlockFT0.h +++ b/Detectors/FIT/FT0/raw/include/FT0Raw/DigitBlockFT0.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,218 +13,22 @@ // // Artur.Furs // afurs@cern.ch -// TODO: -// traites for DataBlocks -// check if the EventID filling is correct #ifndef ALICEO2_FIT_DIGITBLOCKFT0_H_ #define ALICEO2_FIT_DIGITBLOCKFT0_H_ -#include <iostream> -#include <vector> -#include <algorithm> -#include <Rtypes.h> -#include "FT0Raw/DataBlockFT0.h" -#include "FITRaw/DigitBlockBase.h" - -#include <CommonDataFormat/InteractionRecord.h> +#include "FITRaw/DigitBlockFIT.h" #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/LookUpTable.h" -#include <boost/mpl/vector.hpp> -#include <boost/mpl/contains.hpp> - -#include <gsl/span> - -using namespace o2::fit; - namespace o2 { namespace ft0 { //Normal data taking mode -class DigitBlockFT0 : public DigitBlockBase<DigitBlockFT0> -{ - public: - typedef DigitBlockBase<DigitBlockFT0> DigitBlockBaseType; - DigitBlockFT0(o2::InteractionRecord intRec) { setIntRec(intRec); } - DigitBlockFT0() = default; - DigitBlockFT0(const DigitBlockFT0& other) = default; - ~DigitBlockFT0() = default; - void setIntRec(o2::InteractionRecord intRec) { mDigit.mIntRecord = intRec; } - Digit mDigit; - std::vector<ChannelData> mVecChannelData; - static o2::ft0::LookUpTable sLookupTable; - static int sEventID; - - template <class DataBlockType> - void processDigits(DataBlockType& dataBlock, int linkID) - { - if constexpr (std::is_same<DataBlockType, DataBlockPM>::value) { //Filling data from PM - for (int iEventData = 0; iEventData < dataBlock.DataBlockWrapper<RawDataPM>::mNelements; iEventData++) { - mVecChannelData.emplace_back(uint8_t(sLookupTable.getChannel(linkID, dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].channelID)), - int(dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].time), - int(dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].charge), - dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].getFlagWord()); - } - } else if constexpr (std::is_same<DataBlockType, DataBlockTCM>::value) { //Filling data from TCM (normal/extended mode) - dataBlock.DataBlockWrapper<RawDataTCM>::mData[0].fillTrigger(mDigit.mTriggers); - } - } - void getDigits(std::vector<Digit>& vecDigits, std::vector<ChannelData>& vecChannelData) - { - //last digit filling - mDigit.ref.set(vecChannelData.size(), mVecChannelData.size()); - mDigit.mEventID = sEventID; - // - vecDigits.push_back(std::move(mDigit)); - std::move(mVecChannelData.begin(), mVecChannelData.end(), std::back_inserter(vecChannelData)); - mVecChannelData.clear(); - - sEventID++; //Increasing static eventID. After each poping of the data, it will increase - } - void print() const - { - std::cout << "\n______________DIGIT DATA____________"; - std::cout << std::hex; - std::cout << "\nBC: " << mDigit.mIntRecord.bc << "| ORBIT: " << mDigit.mIntRecord.orbit; - std::cout << "\nRef first: " << mDigit.ref.getFirstEntry() << "| Ref entries: " << mDigit.ref.getEntries(); - std::cout << "\nmTrigger: " << static_cast<uint16_t>(mDigit.mTriggers.triggersignals); - std::cout << "\nnChanA: " << static_cast<uint16_t>(mDigit.mTriggers.nChanA) << " | nChanC: " << static_cast<uint16_t>(mDigit.mTriggers.nChanC); - std::cout << "\namplA: " << mDigit.mTriggers.amplA << " | amplC: " << mDigit.mTriggers.amplC; - std::cout << "\ntimeA: " << mDigit.mTriggers.timeA << " | timeC: " << mDigit.mTriggers.timeC; - - std::cout << "\n______________CHANNEL DATA____________\n"; - std::cout << "\nN channel: " << mVecChannelData.size(); - for (const auto& chData : mVecChannelData) { - std::cout << "\nChId: " << static_cast<uint16_t>(chData.ChId) << " | ChainQTC:" << static_cast<uint16_t>(chData.ChainQTC) << " | CFDTime: " << chData.CFDTime << " | QTCAmpl: " << chData.QTCAmpl; - } - std::cout << std::dec; - std::cout << "\n"; - LOG(INFO) << "______________________________________"; - } - - static void print(std::vector<Digit>& vecDigit, std::vector<ChannelData>& vecChannelData) - { - for (const auto& digit : vecDigit) { - std::cout << "\n______________DIGIT DATA____________"; - std::cout << std::hex; - std::cout << "\nBC: " << digit.mIntRecord.bc << "| ORBIT: " << digit.mIntRecord.orbit << " | EventID: " << digit.mEventID; - std::cout << "\nRef first: " << digit.ref.getFirstEntry() << "| Ref entries: " << digit.ref.getEntries(); - std::cout << "\nmTrigger: " << static_cast<uint16_t>(digit.mTriggers.triggersignals); - std::cout << "\nnChanA: " << static_cast<uint16_t>(digit.mTriggers.nChanA) << " | nChanC: " << static_cast<uint16_t>(digit.mTriggers.nChanC); - std::cout << "\namplA: " << digit.mTriggers.amplA << " | amplC: " << digit.mTriggers.amplC; - std::cout << "\ntimeA: " << digit.mTriggers.timeA << " | timeC: " << digit.mTriggers.timeC; - - std::cout << "\n______________CHANNEL DATA____________\n"; - for (int iChData = digit.ref.getFirstEntry(); iChData < digit.ref.getFirstEntry() + digit.ref.getEntries(); iChData++) { - - std::cout << "\nChId: " << static_cast<uint16_t>(vecChannelData[iChData].ChId) << " | ChainQTC:" << static_cast<uint16_t>(vecChannelData[iChData].ChainQTC) - << " | CFDTime: " << vecChannelData[iChData].CFDTime << " | QTCAmpl: " << vecChannelData[iChData].QTCAmpl; - } - std::cout << std::dec; - std::cout << "\n______________________________________\n"; - } - } -}; - +using DigitBlockFT0 = DigitBlockFIT<o2::ft0::SingleLUT, o2::ft0::Digit, o2::ft0::ChannelData>; //TCM extended data taking mode -class DigitBlockFT0ext : public DigitBlockBase<DigitBlockFT0ext> -{ - public: - typedef DigitBlockBase<DigitBlockFT0ext> DigitBlockBaseType; - - DigitBlockFT0ext(o2::InteractionRecord intRec) { setIntRec(intRec); } - DigitBlockFT0ext() = default; - DigitBlockFT0ext(const DigitBlockFT0ext& other) = default; - ~DigitBlockFT0ext() = default; - void setIntRec(o2::InteractionRecord intRec) { mDigit.mIntRecord = intRec; } - DigitExt mDigit; - std::vector<ChannelData> mVecChannelData; - std::vector<TriggersExt> mVecTriggersExt; - - static o2::ft0::LookUpTable sLookupTable; - static int sEventID; - - template <class DataBlockType> - void processDigits(DataBlockType& dataBlock, int linkID) - { - if constexpr (std::is_same<DataBlockType, DataBlockPM>::value) { //Filling data from PM - for (int iEventData = 0; iEventData < dataBlock.DataBlockWrapper<RawDataPM>::mNelements; iEventData++) { - mVecChannelData.emplace_back(uint8_t(sLookupTable.getChannel(linkID, dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].channelID)), - int(dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].time), - int(dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].charge), - dataBlock.DataBlockWrapper<RawDataPM>::mData[iEventData].getFlagWord()); - } - } else if constexpr (std::is_same<DataBlockType, DataBlockTCMext>::value) { //Filling data from TCM, extended mode. Same proccess as for normal mode, for now. - dataBlock.DataBlockWrapper<RawDataTCM>::mData[0].fillTrigger(mDigit.mTriggers); - for (int iTriggerWord = 0; iTriggerWord < dataBlock.DataBlockWrapper<RawDataTCMext>::mNelements; iTriggerWord++) { - mVecTriggersExt.emplace_back(dataBlock.DataBlockWrapper<RawDataTCMext>::mData[iTriggerWord].triggerWord); - } - } - } - void getDigits(std::vector<DigitExt>& vecDigits, std::vector<ChannelData>& vecChannelData, std::vector<TriggersExt>& vecTriggersExt) - { - //last digit filling - mDigit.ref.set(vecChannelData.size(), mVecChannelData.size()); - mDigit.refExt.set(vecTriggersExt.size(), mVecTriggersExt.size()); - mDigit.mEventID = sEventID; - //Digits - vecDigits.push_back(std::move(mDigit)); - //ChannelData - std::move(mVecChannelData.begin(), mVecChannelData.end(), std::back_inserter(vecChannelData)); - mVecChannelData.clear(); - //TriggersExt - std::move(mVecTriggersExt.begin(), mVecTriggersExt.end(), std::back_inserter(vecTriggersExt)); - mVecTriggersExt.clear(); - - sEventID++; //Increasing static eventID. After each poping of the data, it will increase - } - void print() const - { - std::cout << "\n______________DIGIT DATA____________"; - std::cout << std::hex; - std::cout << "\nBC: " << mDigit.mIntRecord.bc << "| ORBIT: " << mDigit.mIntRecord.orbit; - std::cout << "\nRef first: " << mDigit.ref.getFirstEntry() << "| Ref entries: " << mDigit.ref.getEntries(); - std::cout << "\nmTrigger: " << static_cast<uint16_t>(mDigit.mTriggers.triggersignals); - std::cout << "\nnChanA: " << static_cast<uint16_t>(mDigit.mTriggers.nChanA) << " | nChanC: " << static_cast<uint16_t>(mDigit.mTriggers.nChanC); - std::cout << "\namplA: " << mDigit.mTriggers.amplA << " | amplC: " << mDigit.mTriggers.amplC; - std::cout << "\ntimeA: " << mDigit.mTriggers.timeA << " | timeC: " << mDigit.mTriggers.timeC; - - std::cout << "\n______________CHANNEL DATA____________\n"; - std::cout << "\nN channel: " << mVecChannelData.size(); - for (const auto& chData : mVecChannelData) { - std::cout << "\nChId: " << static_cast<uint16_t>(chData.ChId) << " | ChainQTC:" << static_cast<uint16_t>(chData.ChainQTC) << " | CFDTime: " << chData.CFDTime << " | QTCAmpl: " << chData.QTCAmpl; - } - std::cout << std::dec; - std::cout << "\n"; - LOG(INFO) << "______________________________________"; - } - - static void print(std::vector<DigitExt>& vecDigit, std::vector<ChannelData>& vecChannelData, std::vector<TriggersExt>& vecTriggersExt) - { - for (const auto& digit : vecDigit) { - std::cout << "\n______________DIGIT DATA____________"; - std::cout << std::hex; - std::cout << "\nBC: " << digit.mIntRecord.bc << "| ORBIT: " << digit.mIntRecord.orbit << " | EventID: " << digit.mEventID; - std::cout << "\nRef first: " << digit.ref.getFirstEntry() << "| Ref entries: " << digit.ref.getEntries(); - std::cout << "\nmTrigger: " << static_cast<uint16_t>(digit.mTriggers.triggersignals); - std::cout << "\nnChanA: " << static_cast<uint16_t>(digit.mTriggers.nChanA) << " | nChanC: " << static_cast<uint16_t>(digit.mTriggers.nChanC); - std::cout << "\namplA: " << digit.mTriggers.amplA << " | amplC: " << digit.mTriggers.amplC; - std::cout << "\ntimeA: " << digit.mTriggers.timeA << " | timeC: " << digit.mTriggers.timeC; - - std::cout << "\n______________CHANNEL DATA____________\n"; - for (int iChData = digit.ref.getFirstEntry(); iChData < digit.ref.getFirstEntry() + digit.ref.getEntries(); iChData++) { - - std::cout << "\nChId: " << static_cast<uint16_t>(vecChannelData[iChData].ChId) << " | ChainQTC:" << static_cast<uint16_t>(vecChannelData[iChData].ChainQTC) - << " | CFDTime: " << vecChannelData[iChData].CFDTime << " | QTCAmpl: " << vecChannelData[iChData].QTCAmpl; - } - std::cout << std::dec; - std::cout << "\n______________________________________\n"; - } - } -}; - +using DigitBlockFT0ext = DigitBlockFIText<o2::ft0::SingleLUT, o2::ft0::Digit, o2::ft0::ChannelData, o2::ft0::TriggersExt>; } // namespace ft0 } // namespace o2 #endif diff --git a/Detectors/FIT/FT0/raw/include/FT0Raw/RawReaderFT0Base.h b/Detectors/FIT/FT0/raw/include/FT0Raw/RawReaderFT0Base.h index 213d869782df2..5f161a808edaa 100644 --- a/Detectors/FIT/FT0/raw/include/FT0Raw/RawReaderFT0Base.h +++ b/Detectors/FIT/FT0/raw/include/FT0Raw/RawReaderFT0Base.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,58 +19,18 @@ #ifndef ALICEO2_FIT_RAWREADERFT0BASE_H_ #define ALICEO2_FIT_RAWREADERFT0BASE_H_ -#include <iostream> -#include <vector> -#include <Rtypes.h> #include "FT0Raw/DataBlockFT0.h" #include "FT0Raw/DigitBlockFT0.h" -#include "FITRaw/RawReaderBase.h" +#include "FITRaw/RawReaderBaseFIT.h" -#include <boost/mpl/inherit.hpp> -#include <boost/mpl/vector.hpp> - -#include <CommonDataFormat/InteractionRecord.h> -#include "Headers/RAWDataHeader.h" - -#include <gsl/span> - -using namespace o2::fit; namespace o2 { namespace ft0 { - -// Common raw reader for FT0 -template <class DigitBlockFT0type, class DataBlockPMtype, class DataBlockTCMtype> -class RawReaderFT0Base : public RawReaderBase<DigitBlockFT0type> -{ - public: - typedef RawReaderBase<DigitBlockFT0type> RawReaderBaseType; - RawReaderFT0Base() = default; - ~RawReaderFT0Base() = default; - //deserialize payload to raw data blocks and proccesss them to digits - void process(int linkID, gsl::span<const uint8_t> payload) - { - if (0 <= linkID && linkID < 18) { - //PM data proccessing - RawReaderBaseType::template processBinaryData<DataBlockPMtype>(payload, linkID); - } else if (linkID == 18) { - //TCM data proccessing - RawReaderBaseType::template processBinaryData<DataBlockTCMtype>(payload, linkID); - } else { - //put here code in case of bad rdh.linkID value - LOG(INFO) << "WARNING! WRONG LINK ID!"; - return; - } - - // - } -}; //Normal TCM mode -using RawReaderFT0BaseNorm = RawReaderFT0Base<DigitBlockFT0, DataBlockPM, DataBlockTCM>; +using RawReaderFT0BaseNorm = o2::fit::RawReaderBaseFIT<DigitBlockFT0, DataBlockPM, DataBlockTCM>; //Extended TCM mode -using RawReaderFT0BaseExt = RawReaderFT0Base<DigitBlockFT0ext, DataBlockPM, DataBlockTCMext>; - +using RawReaderFT0BaseExt = o2::fit::RawReaderBaseFIT<DigitBlockFT0ext, DataBlockPM, DataBlockTCMext>; } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/raw/include/FT0Raw/RawWriterFT0.h b/Detectors/FIT/FT0/raw/include/FT0Raw/RawWriterFT0.h new file mode 100644 index 0000000000000..951fe42cc11fc --- /dev/null +++ b/Detectors/FIT/FT0/raw/include/FT0Raw/RawWriterFT0.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawWriterFT0.h Raw writer class for FT0 +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_RAWWRITERFT0_H_ +#define ALICEO2_FIT_RAWWRITERFT0_H_ +#include "FT0Raw/DataBlockFT0.h" +#include "FT0Raw/DigitBlockFT0.h" +#include "FITRaw/RawWriterFIT.h" + +namespace o2 +{ +namespace ft0 +{ +//Normal TCM mode +using RawWriterFT0 = o2::fit::RawWriterFIT<DigitBlockFT0, DataBlockPM, DataBlockTCM>; +//Extended TCM mode +//using RawWriterFT0ext = o2::fit::RawWriterFIT<DigitBlockFT0, DataBlockPM, DataBlockTCMext>; +} // namespace ft0 +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FT0/raw/src/DataBlockFT0.cxx b/Detectors/FIT/FT0/raw/src/DataBlockFT0.cxx index 3a8eddd8b3a5c..0506c068160b0 100644 --- a/Detectors/FIT/FT0/raw/src/DataBlockFT0.cxx +++ b/Detectors/FIT/FT0/raw/src/DataBlockFT0.cxx @@ -1,12 +1,13 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "FT0Raw/DataBlockFT0.h" -using namespace o2::ft0; +//using namespace o2::ft0; diff --git a/Detectors/FIT/FT0/raw/src/DigitBlockFT0.cxx b/Detectors/FIT/FT0/raw/src/DigitBlockFT0.cxx index 710ebee6249a2..4f320e350f83e 100644 --- a/Detectors/FIT/FT0/raw/src/DigitBlockFT0.cxx +++ b/Detectors/FIT/FT0/raw/src/DigitBlockFT0.cxx @@ -1,17 +1,13 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "FT0Raw/DigitBlockFT0.h" -using namespace o2::ft0; - -int DigitBlockFT0::sEventID = 0; -o2::ft0::LookUpTable DigitBlockFT0::sLookupTable = o2::ft0::LookUpTable::linear(); -int DigitBlockFT0ext::sEventID = 0; -o2::ft0::LookUpTable DigitBlockFT0ext::sLookupTable = o2::ft0::LookUpTable::linear(); +//using namespace o2::ft0; diff --git a/Detectors/FIT/FT0/raw/src/FT0RawLinkDef.h b/Detectors/FIT/FT0/raw/src/FT0RawLinkDef.h deleted file mode 100644 index 0928d12d07f28..0000000000000 --- a/Detectors/FIT/FT0/raw/src/FT0RawLinkDef.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::ft0::DataBlockPM + ; -#pragma link C++ class o2::ft0::DataBlockTCM + ; -#pragma link C++ class o2::ft0::DataBlockTCMext + ; -#pragma link C++ class o2::ft0::DigitBlockFT0 + ; -#pragma link C++ class o2::ft0::DigitBlockFT0ext + ; - -#endif diff --git a/Detectors/FIT/FT0/raw/src/RawReaderFT0Base.cxx b/Detectors/FIT/FT0/raw/src/RawReaderFT0Base.cxx index f4c76fb9585c0..292b3ad4fe491 100644 --- a/Detectors/FIT/FT0/raw/src/RawReaderFT0Base.cxx +++ b/Detectors/FIT/FT0/raw/src/RawReaderFT0Base.cxx @@ -1,12 +1,13 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "FT0Raw/RawReaderFT0Base.h" -using namespace o2::ft0; +//using namespace o2::ft0; diff --git a/Detectors/FIT/FT0/raw/src/RawWriterFT0.cxx b/Detectors/FIT/FT0/raw/src/RawWriterFT0.cxx new file mode 100644 index 0000000000000..cd57b0ea4fe0e --- /dev/null +++ b/Detectors/FIT/FT0/raw/src/RawWriterFT0.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Raw/RawWriterFT0.h" diff --git a/Detectors/FIT/FT0/reconstruction/CMakeLists.txt b/Detectors/FIT/FT0/reconstruction/CMakeLists.txt index 16a4eb8ffd97c..67ccbeab92933 100644 --- a/Detectors/FIT/FT0/reconstruction/CMakeLists.txt +++ b/Detectors/FIT/FT0/reconstruction/CMakeLists.txt @@ -1,31 +1,48 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FT0Reconstruction - SOURCES src/CollisionTimeRecoTask.cxx + SOURCES src/CollisionTimeRecoTask.cxx src/ReadRaw.cxx src/CTFCoder.cxx src/InteractionTag.cxx - + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::Framework O2::FT0Base + O2::FT0Simulation + O2::FT0Calibration + O2::FITCalibration + O2::DetectorsCalibration O2::DataFormatsFT0 O2::DetectorsRaw O2::CommonDataFormat O2::rANS O2::Headers) -o2_target_root_dictionary( +o2_target_root_dictionary( FT0Reconstruction HEADERS include/FT0Reconstruction/CollisionTimeRecoTask.h include/FT0Reconstruction/ReadRaw.h include/FT0Reconstruction/CTFCoder.h include/FT0Reconstruction/InteractionTag.h ) + +o2_add_executable( + test-raw-conversion + COMPONENT_NAME ft0 + SOURCES src/test-raw-conversion.cxx + PUBLIC_LINK_LIBRARIES O2::FT0Reconstruction) + +o2_add_executable( + test-raw2digit + COMPONENT_NAME ft0 + SOURCES src/test-raw2digit.cxx + PUBLIC_LINK_LIBRARIES O2::FT0Reconstruction) diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h index c6a922c529244..67e88e8b55c8a 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" #include "DetectorsCommonDataFormats/DetID.h" +#include "FT0Simulation/DigitizationParameters.h" #include "DetectorsBase/CTFCoderBase.h" #include "rANS/rans.h" @@ -60,6 +62,8 @@ class CTFCoder : public o2::ctf::CTFCoderBase void appendToTree(TTree& tree, CTF& ec); void readFromTree(TTree& tree, int entry, std::vector<Digit>& digitVec, std::vector<ChannelData>& channelVec); + // DigitizationParameters const &mParameters; + // o2::ft0::Geometry mGeometry; ClassDefNV(CTFCoder, 1); }; @@ -92,6 +96,7 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const Digit>& digitVec, const g using ECB = CTF::base; ec->setHeader(cd.header); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -116,11 +121,12 @@ void CTFCoder::decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec) { CompressedDigits cd; cd.header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cd.header)); ec.print(getPrefix()); #define DECODEFT0(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) // clang-format off DECODEFT0(cd.trigger, CTF::BLC_trigger); - DECODEFT0(cd.bcInc, CTF::BLC_bcInc); + DECODEFT0(cd.bcInc, CTF::BLC_bcInc); DECODEFT0(cd.orbitInc, CTF::BLC_orbitInc); DECODEFT0(cd.nChan, CTF::BLC_nChan); DECODEFT0(cd.eventFlags, CTF::BLC_flags); @@ -155,16 +161,16 @@ void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& cha } Triggers trig; trig.triggersignals = cd.trigger[idig]; - + const auto& params = DigitizationParameters::Instance(); + int triggerGate = params.mTime_trg_gate; firstEntry = channelVec.size(); uint8_t chID = 0; int amplA = 0, amplC = 0, timeA = 0, timeC = 0; + for (uint8_t ic = 0; ic < cd.nChan[idig]; ic++) { auto icc = channelVec.size(); const auto& chan = channelVec.emplace_back((chID += cd.idChan[icc]), cd.cfdTime[icc], cd.qtcAmpl[icc], cd.qtcChain[icc]); - // - // rebuild digit - if (std::abs(chan.CFDTime) < Geometry::mTime_trg_gate) { + if (std::abs(chan.CFDTime) < triggerGate) { if (chan.ChId < 4 * uint8_t(Geometry::NCellsA)) { // A side amplA += chan.QTCAmpl; timeA += chan.CFDTime; diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h index f99ec96326e02..97279a8693c9f 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,14 +14,18 @@ #ifndef ALICEO2_FIT_COLLISIONTIMERECOTASK_H #define ALICEO2_FIT_COLLISIONTIMERECOTASK_H -#include <vector> #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/RecPoints.h" #include "CommonDataFormat/InteractionRecord.h" #include "CommonDataFormat/TimeStamp.h" +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Base/Geometry.h" #include <gsl/span> #include <bitset> +#include <vector> +#include <array> +#include <TGraph.h> namespace o2 { @@ -28,6 +33,8 @@ namespace ft0 { class CollisionTimeRecoTask { + using offsetCalib = o2::ft0::FT0ChannelTimeCalibrationObject; + static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; public: enum : int { TimeMean, @@ -40,9 +47,19 @@ class CollisionTimeRecoTask gsl::span<const o2::ft0::ChannelData> inChData, gsl::span<o2::ft0::ChannelDataFloat> outChData); void FinishTask(); + void SetChannelOffset(o2::ft0::FT0ChannelTimeCalibrationObject* caliboffsets) { mCalibOffset = caliboffsets; }; + void SetSlew(std::array<TGraph, NCHANNELS>* calibslew) + { + LOG(INFO) << "@@@SetSlew " << calibslew->size(); + mCalibSlew = calibslew; + }; + int getOffset(int channel, int amp); private: - ClassDefNV(CollisionTimeRecoTask, 1); + o2::ft0::FT0ChannelTimeCalibrationObject* mCalibOffset; + std::array<TGraph, NCHANNELS>* mCalibSlew = nullptr; + + ClassDefNV(CollisionTimeRecoTask, 3); }; } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h index 962bb4b599ca9..2a41d980c5749 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,11 +33,6 @@ struct InteractionTag : public o2::conf::ConfigurableParamHelper<InteractionTag> return rp.isValidTime(RecPoints::TimeMean) && (rp.getTrigger().amplA + rp.getTrigger().amplC) > minAmplitudeAC; } - float getInteractionTimeNS(const RecPoints& rp, const o2::InteractionRecord& refIR) const - { - return rp.getInteractionRecord().differenceInBCNS(refIR); // RS FIXME do we want use precise MeanTime? - } - O2ParamDef(InteractionTag, "ft0tag"); }; diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/ReadRaw.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/ReadRaw.h index 84185564bb6a5..ea2ec72f8ed32 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/ReadRaw.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/ReadRaw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,7 @@ #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/LookUpTable.h" #include "DataFormatsFT0/RawEventData.h" +#include "FT0Base/Geometry.h" #include "Headers/RAWDataHeader.h" #include "TBranch.h" #include "TTree.h" @@ -40,10 +42,10 @@ namespace ft0 { class ReadRaw { - static constexpr int Nchannels_FT0 = 208; + static constexpr int Nchannels_FT0 = o2::ft0::Geometry::Nchannels; static constexpr int Nchannels_PM = 12; - static constexpr int NPMs = 19; - static constexpr int LinkTCM = 18; + static constexpr int NPMs = 20; + // static constexpr int LinkTCM = 19; static constexpr float MV_2_Nchannels = 2.2857143; //7 mV ->16channels static constexpr float CFD_NS_2_Nchannels = 76.804916; //1000.(ps)/13.02(channel); //static constexpr int GBTWORDSIZE = 80; //real size @@ -57,17 +59,6 @@ class ReadRaw void readData(const std::string fileRaw, const o2::ft0::LookUpTable& lut); void writeDigits(const std::string fileDecodeData); void close(); - static o2::ft0::LookUpTable linear() - { - std::vector<o2::ft0::Topo> lut_data(Nchannels_PM * NPMs); - for (int link = 0; link < NPMs; ++link) { - for (int mcp = 0; mcp < Nchannels_PM; ++mcp) { - lut_data[link * Nchannels_PM + mcp] = o2::ft0::Topo{link, mcp}; - } - } - - return o2::ft0::LookUpTable{lut_data}; - } private: std::ifstream mFileDest; @@ -80,6 +71,7 @@ class ReadRaw char* mBuffer = nullptr; std::vector<char> mBufferLocal; long mSize; + int mLinkTCM; std::map<o2::InteractionRecord, o2::ft0::DigitsTemp> mDigitAccum; // digit accumulator template <typename T> TBranch* getOrMakeBranch(TTree& tree, std::string brname, T* ptr) @@ -92,7 +84,7 @@ class ReadRaw return tree.Branch(brname.c_str(), ptr); } - ClassDefNV(ReadRaw, 1); + ClassDefNV(ReadRaw, 2); }; } // namespace ft0 diff --git a/Detectors/FIT/FT0/reconstruction/src/CTFCoder.cxx b/Detectors/FIT/FT0/reconstruction/src/CTFCoder.cxx index fe15747186622..3a49932c6f5bc 100644 --- a/Detectors/FIT/FT0/reconstruction/src/CTFCoder.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ /// \brief class for entropy encoding/decoding of FT0 digits data #include "FT0Reconstruction/CTFCoder.h" +#include "FT0Simulation/DigitizationParameters.h" #include "CommonUtils/StringUtils.h" #include <TTree.h> @@ -48,6 +50,7 @@ void CTFCoder::compress(CompressedDigits& cd, const gsl::span<const Digit>& digi cd.header.nTriggers = digitVec.size(); cd.header.firstOrbit = dig0.getOrbit(); cd.header.firstBC = dig0.getBC(); + cd.header.triggerGate = DigitizationParameters::Instance().mTime_trg_gate; cd.trigger.resize(cd.header.nTriggers); cd.bcInc.resize(cd.header.nTriggers); diff --git a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx index 492a588dbd90c..55edec2b8fa95 100644 --- a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "FairLogger.h" // for LOG #include "DataFormatsFT0/RecPoints.h" #include "FT0Base/Geometry.h" +#include "FT0Simulation/DigitizationParameters.h" #include <DataFormatsFT0/ChannelData.h> #include <DataFormatsFT0/Digit.h> #include <cmath> @@ -40,15 +42,14 @@ o2::ft0::RecPoints CollisionTimeRecoTask::process(o2::ft0::Digit const& bcd, Float_t sideAtime = 0, sideCtime = 0; - auto timeStamp = o2::InteractionRecord::bc2ns(bcd.mIntRecord.bc, bcd.mIntRecord.orbit); - - LOG(DEBUG) << " event time " << timeStamp << " orbit " << bcd.mIntRecord.orbit << " bc " << bcd.mIntRecord.bc; - int nch = inChData.size(); + const auto parInv = DigitizationParameters::Instance().mMV_2_NchannelsInverse; for (int ich = 0; ich < nch; ich++) { + int offsetChannel = getOffset(ich, inChData[ich].QTCAmpl); + outChData[ich] = o2::ft0::ChannelDataFloat{inChData[ich].ChId, - inChData[ich].CFDTime * Geometry::ChannelWidth, - (double)inChData[ich].QTCAmpl * Geometry::MV_2_NchannelsInverse, + (inChData[ich].CFDTime - offsetChannel) * Geometry::ChannelWidth, + (float)inChData[ich].QTCAmpl * parInv, inChData[ich].ChainQTC}; // only signals with amplitude participate in collision time @@ -62,13 +63,11 @@ o2::ft0::RecPoints CollisionTimeRecoTask::process(o2::ft0::Digit const& bcd, } } } - std::array<Float_t, 4> mCollisionTime = {2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime, - 2 * o2::InteractionRecord::DummyTime}; + auto sDummyCollissionTime = o2::ft0::RecPoints::sDummyCollissionTime; + std::array<short, 4> mCollisionTime = {sDummyCollissionTime, sDummyCollissionTime, sDummyCollissionTime, sDummyCollissionTime}; // !!!! tobe done::should be fix with ITS vertex - mCollisionTime[TimeA] = (ndigitsA > 0) ? sideAtime / Float_t(ndigitsA) : 2 * o2::InteractionRecord::DummyTime; - mCollisionTime[TimeC] = (ndigitsC > 0) ? sideCtime / Float_t(ndigitsC) : 2 * o2::InteractionRecord::DummyTime; + mCollisionTime[TimeA] = (ndigitsA > 0) ? sideAtime / ndigitsA : sDummyCollissionTime; // 2 * o2::InteractionRecord::DummyTime; + mCollisionTime[TimeC] = (ndigitsC > 0) ? sideCtime / ndigitsC : sDummyCollissionTime; //2 * o2::InteractionRecord::DummyTime; if (ndigitsA > 0 && ndigitsC > 0) { mCollisionTime[Vertex] = (mCollisionTime[TimeA] - mCollisionTime[TimeC]) / 2.; @@ -76,7 +75,7 @@ o2::ft0::RecPoints CollisionTimeRecoTask::process(o2::ft0::Digit const& bcd, } else { mCollisionTime[TimeMean] = std::min(mCollisionTime[TimeA], mCollisionTime[TimeC]); } - LOG(DEBUG) << " Collision time " << mCollisionTime[TimeA] << " " << mCollisionTime[TimeC] << " " << mCollisionTime[TimeMean] << " " << mCollisionTime[Vertex]; + LOG(DEBUG) << " Nch " << nch << " Collision time " << mCollisionTime[TimeA] << " " << mCollisionTime[TimeC] << " " << mCollisionTime[TimeMean] << " " << mCollisionTime[Vertex]; return RecPoints{ mCollisionTime, bcd.ref.getFirstEntry(), bcd.ref.getEntries(), bcd.mIntRecord, bcd.mTriggers}; } @@ -86,3 +85,18 @@ void CollisionTimeRecoTask::FinishTask() // finalize digitization, if needed, flash remaining digits // if (!mContinuous) return; } +//______________________________________________________ +int CollisionTimeRecoTask::getOffset(int channel, int amp) +{ + if (!mCalibOffset) { + return 0; + } + int offsetChannel = mCalibOffset->mTimeOffsets[channel]; + double slewoffset = 0; + if (mCalibSlew) { + TGraph& gr = mCalibSlew->at(channel); + slewoffset = gr.Eval(amp); + } + LOG(DEBUG) << "CollisionTimeRecoTask::getOffset(int channel, int amp) " << channel << " " << amp << " " << offsetChannel << " " << slewoffset; + return offsetChannel + int(slewoffset); +} diff --git a/Detectors/FIT/FT0/reconstruction/src/FT0ReconstructionLinkDef.h b/Detectors/FIT/FT0/reconstruction/src/FT0ReconstructionLinkDef.h index e8811907900b5..af9f58fc1b445 100644 --- a/Detectors/FIT/FT0/reconstruction/src/FT0ReconstructionLinkDef.h +++ b/Detectors/FIT/FT0/reconstruction/src/FT0ReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/reconstruction/src/InteractionTag.cxx b/Detectors/FIT/FT0/reconstruction/src/InteractionTag.cxx index a384e40f28895..dc7392237c10a 100644 --- a/Detectors/FIT/FT0/reconstruction/src/InteractionTag.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/InteractionTag.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/reconstruction/src/ReadRaw.cxx b/Detectors/FIT/FT0/reconstruction/src/ReadRaw.cxx index bd72a9f5a7625..b8fbe59652e19 100644 --- a/Detectors/FIT/FT0/reconstruction/src/ReadRaw.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/ReadRaw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ Event header + event data, 2 channels per 1 GBT word; if no data for this PM - only headers. Trigger mode : detector sends data to FLP at each trigger; -Continueous mode : for only bunches with data at least in 1 channel. +Continueous mode : for only bunches with data at least in 1 channel. */ #include "Headers/RAWDataHeader.h" @@ -60,6 +61,7 @@ Continueous mode : for only bunches with data at least in 1 channel. #include "TBranch.h" #include "CommonConstants/LHCConstants.h" #include "DetectorsRaw/RDHUtils.h" +#include <gsl/span_ext> using namespace o2::ft0; using RDHUtils = o2::raw::RDHUtils; @@ -73,7 +75,8 @@ ReadRaw::ReadRaw(const std::string fileRaw, std::string fileDataOut) << "file to read " << fileRaw.data() << " file to write " << fileDataOut.data(); mFileDest.exceptions(std::ios_base::failbit | std::ios_base::badbit); mFileDest.open(fileRaw, std::fstream::in | std::fstream::binary); - o2::ft0::LookUpTable lut{o2::ft0::ReadRaw::linear()}; + o2::ft0::LookUpTable lut{LookUpTable::readTable()}; + mLinkTCM = lut.getLink(lut.getTCMchannel()); ReadRaw::readData(fileRaw.c_str(), lut); ReadRaw::writeDigits(fileDataOut.data()); } @@ -96,6 +99,17 @@ void ReadRaw::readData(const std::string fileRaw, const o2::ft0::LookUpTable& lu mFileDest.seekg(0); LOG(DEBUG) << "SizeFile " << sizeFile; + for (int ilink = 0; ilink < 8; ilink++) { + for (int ich = 0; ich < 12; ich++) { + LOG(INFO) << " ep 0 " << ilink << " " << ich << " " << lut.getChannel(ilink, ich + 1, int(0)); + } + } + for (int ilink = 0; ilink < 10; ilink++) { + for (int ich = 0; ich < 12; ich++) { + LOG(INFO) << " ep 1 " << ilink << " " << ich << " " << lut.getChannel(ilink, ich + 1, int(1)); + } + } + // read content of infile long posInFile = 0; while (posInFile < sizeFile - sizeof(mRDH)) { @@ -109,6 +123,7 @@ void ReadRaw::readData(const std::string fileRaw, const o2::ft0::LookUpTable& lu int numPage = RDHUtils::getPageCounter(mRDH); int offset = RDHUtils::getOffsetToNext(mRDH); int link = RDHUtils::getLinkID(mRDH); + int ep = RDHUtils::getEndPointID(mRDH); if (nwords <= sizeof(mRDH)) { posInFile += RDHUtils::getOffsetToNext(mRDH); LOG(INFO) << " next RDH"; @@ -120,43 +135,43 @@ void ReadRaw::readData(const std::string fileRaw, const o2::ft0::LookUpTable& lu while (pos < nwords) { mFileDest.read(reinterpret_cast<char*>(&mEventHeader), sizeof(mEventHeader)); pos += sizeof(mEventHeader); - LOG(DEBUG) << "read header for " << link << "word " << (int)mEventHeader.nGBTWords << " orbit " << int(mEventHeader.orbit) << " BC " << int(mEventHeader.bc) << " pos " << pos << " posinfile " << posInFile; + LOG(DEBUG) << "read header for " << link << "word " << (int)mEventHeader.nGBTWords << " orbit " << int(mEventHeader.orbit) << " BC " << int(mEventHeader.bc) << " pos " << pos << " posinfile " << posInFile << " endPoint " << int(ep); o2::InteractionRecord intrec{uint16_t(mEventHeader.bc), uint32_t(mEventHeader.orbit)}; auto [digitIter, isNew] = mDigitAccum.try_emplace(intrec); if (isNew) { double eventTime = intrec.bc2ns(); - LOG(DEBUG) << "new intrec " << intrec.orbit << " " << intrec.bc << " link " << link; + LOG(INFO) << "new intrec " << intrec.orbit << " " << intrec.bc << " link " << link << " EP " << ep; o2::ft0::DigitsTemp& digit = digitIter->second; digit.setTime(eventTime); digit.setInteractionRecord(intrec); } chDgDataArr = &digitIter->second.getChDgData(); //&mDigitsTemp.getChDgData(); - if (link == 18) { + if (link == mLinkTCM) { mFileDest.read(reinterpret_cast<char*>(&mTCMdata), sizeof(mTCMdata)); pos += sizeof(mTCMdata); digitIter->second.setTriggers(Bool_t(mTCMdata.orA), Bool_t(mTCMdata.orC), Bool_t(mTCMdata.vertex), Bool_t(mTCMdata.sCen), Bool_t(mTCMdata.cen), uint8_t(mTCMdata.nChanA), uint8_t(mTCMdata.nChanC), int32_t(mTCMdata.amplA), int32_t(mTCMdata.amplC), int16_t(mTCMdata.timeA), int16_t(mTCMdata.timeC)); LOG(INFO) << "read TCM " << (int)mEventHeader.nGBTWords << " orbit " << int(mEventHeader.orbit) << " BC " << int(mEventHeader.bc) << " pos " << pos << " posinfile " << posInFile; } else { if (mIsPadded) { - pos += CRUWordSize - o2::ft0::EventHeader::PayloadSize; + pos += CRUWordSize - o2::ft0::RawEventData::sPayloadSize; } for (int i = 0; i < mEventHeader.nGBTWords; ++i) { - mFileDest.read(reinterpret_cast<char*>(&mEventData[2 * i]), o2::ft0::EventData::PayloadSizeFirstWord); - chDgDataArr->emplace_back(lut.getChannel(link, int(mEventData[2 * i].channelID)), + mFileDest.read(reinterpret_cast<char*>(&mEventData[2 * i]), o2::ft0::RawEventData::sPayloadSizeFirstWord); + chDgDataArr->emplace_back(lut.getChannel(link, int(mEventData[2 * i].channelID), ep), int(mEventData[2 * i].time), int(mEventData[2 * i].charge), int(mEventData[2 * i].numberADC)); - pos += o2::ft0::EventData::PayloadSizeFirstWord; - LOG(INFO) << " read 1st word channelID " << int(mEventData[2 * i].channelID) << " charge " << mEventData[2 * i].charge << " time " << mEventData[2 * i].time << " PM " << link << " lut channel " << lut.getChannel(link, int(mEventData[2 * i].channelID)) << " pos " << pos; + pos += o2::ft0::RawEventData::sPayloadSizeFirstWord; + LOG(INFO) << " read 1st word channelID " << int(mEventData[2 * i].channelID) << " charge " << mEventData[2 * i].charge << " time " << mEventData[2 * i].time << " PM " << link << " lut channel " << lut.getChannel(link, int(mEventData[2 * i].channelID), ep) << " pos " << pos; - mFileDest.read(reinterpret_cast<char*>(&mEventData[2 * i + 1]), EventData::PayloadSizeSecondWord); - pos += o2::ft0::EventData::PayloadSizeSecondWord; - LOG(INFO) << "read 2nd word channel " << int(mEventData[2 * i + 1].channelID) << " charge " << int(mEventData[2 * i + 1].charge) << " time " << mEventData[2 * i + 1].time << " PM " << link << " lut channel " << lut.getChannel(link, int(mEventData[2 * i + 1].channelID)) << " pos " << pos; + mFileDest.read(reinterpret_cast<char*>(&mEventData[2 * i + 1]), o2::ft0::RawEventData::sPayloadSizeSecondWord); + pos += o2::ft0::RawEventData::sPayloadSizeSecondWord; + LOG(INFO) << "read 2nd word channel " << int(mEventData[2 * i + 1].channelID) << " charge " << int(mEventData[2 * i + 1].charge) << " time " << mEventData[2 * i + 1].time << " PM " << link << " lut channel " << lut.getChannel(link, int(mEventData[2 * i + 1].channelID), ep) << " pos " << pos; if (mEventData[2 * i + 1].charge <= 0 && mEventData[2 * i + 1].channelID <= 0 && mEventData[2 * i + 1].time <= 0) { continue; } - chDgDataArr->emplace_back(lut.getChannel(link, int(mEventData[2 * i + 1].channelID)), + chDgDataArr->emplace_back(lut.getChannel(link, int(mEventData[2 * i + 1].channelID), ep), int(mEventData[2 * i + 1].time), int(mEventData[2 * i + 1].charge), int(mEventData[2 * i + 1].numberADC)); diff --git a/Detectors/FIT/FT0/reconstruction/src/test-raw-conversion.cxx b/Detectors/FIT/FT0/reconstruction/src/test-raw-conversion.cxx new file mode 100644 index 0000000000000..36c0bc8438f99 --- /dev/null +++ b/Detectors/FIT/FT0/reconstruction/src/test-raw-conversion.cxx @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <filesystem> +#include <TTree.h> +#include "Framework/Logger.h" +#include "DataFormatsFT0/Digit.h" +#include <TFile.h> +#include <cstring> + +using namespace o2::ft0; + +int main(int argc, char* argv[]) +{ + const std::string genDigDile{"ft0digits.root"}; + const std::string decDigDile{"o2_ft0digits.root"}; + const std::string branchBC{"FT0DIGITSBC"}; + const std::string branchCH{"FT0DIGITSCH"}; + + if (!std::filesystem::exists(genDigDile)) { + LOG(FATAL) << "Generated digits file " << genDigDile << " is absent"; + } + TFile flIn(genDigDile.c_str()); + std::unique_ptr<TTree> tree((TTree*)flIn.Get("o2sim")); + if (!flIn.IsOpen() || flIn.IsZombie() || !tree) { + LOG(FATAL) << "Failed to get tree from generated digits file " << genDigDile; + } + std::vector<o2::ft0::Digit> digitsBC, *ft0BCDataPtr = &digitsBC; + std::vector<o2::ft0::ChannelData> digitsCh, *ft0ChDataPtr = &digitsCh; + tree->SetBranchAddress("FT0DIGITSBC", &ft0BCDataPtr); + tree->SetBranchAddress("FT0DIGITSCH", &ft0ChDataPtr); + + if (!std::filesystem::exists(decDigDile)) { + LOG(FATAL) << "Decoded digits file " << genDigDile << " is absent"; + } + + TFile flIn2(decDigDile.c_str()); + std::unique_ptr<TTree> tree2((TTree*)flIn2.Get("o2sim")); + if (!flIn2.IsOpen() || flIn2.IsZombie() || !tree2) { + LOG(FATAL) << "Failed to get tree from decoded digits file " << genDigDile; + } + std::vector<o2::ft0::Digit> digitsBC2, *ft0BCDataPtr2 = &digitsBC2; + std::vector<o2::ft0::ChannelData> digitsCh2, *ft0ChDataPtr2 = &digitsCh2; + tree2->SetBranchAddress("FT0DIGITSBC", &ft0BCDataPtr2); + tree2->SetBranchAddress("FT0DIGITSCH", &ft0ChDataPtr2); + + int nbc = 0, nbc2 = 0, nch = 0, nch2 = 0; + for (int ient = 0; ient < tree->GetEntries(); ient++) { + tree->GetEntry(ient); + int nbcEntry = digitsBC.size(); + nbc += nbcEntry; + for (int ibc = 0; ibc < nbcEntry; ibc++) { + auto& bcd = digitsBC[ibc]; + int bc = bcd.getBC(); + auto channels = bcd.getBunchChannelData(digitsCh); + nch += channels.size(); + } + } + + for (int ient = 0; ient < tree2->GetEntries(); ient++) { + tree2->GetEntry(ient); + int nbc2Entry = digitsBC2.size(); + nbc2 += nbc2Entry; + for (int ibc = 0; ibc < nbc2Entry; ibc++) { + auto& bcd2 = digitsBC2[ibc]; + int bc2 = bcd2.getBC(); + auto channels2 = bcd2.getBunchChannelData(digitsCh2); + nch2 += channels2.size(); + } + } + LOG(INFO) << "FT0 simulated: " << nbc << " triggers with " << nch << " channels"; + LOG(INFO) << "FT0 decoded : " << nbc2 << " triggers with " << nch2 << " channels"; + if (nbc != nbc2 || nch != nch2) { + LOG(FATAL) << "Mismatch between the number of encoded and decoded objects"; + } + + return 0; +} diff --git a/Detectors/FIT/FT0/reconstruction/src/test-raw2digit.cxx b/Detectors/FIT/FT0/reconstruction/src/test-raw2digit.cxx new file mode 100644 index 0000000000000..114fa1edf8003 --- /dev/null +++ b/Detectors/FIT/FT0/reconstruction/src/test-raw2digit.cxx @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TSystem.h> +#include <TTree.h> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/Logger.h" +#include "DataFormatsFT0/Digit.h" +#include <TFile.h> +#include <cstring> + +using namespace o2::ft0; +int main() +{ + struct EventFT0_t { + o2::ft0::Digit mDigit; + std::vector<o2::ft0::ChannelData> mVecChannelData; + bool operator==(const EventFT0_t& other) const + { + return mDigit == other.mDigit && mVecChannelData == other.mVecChannelData; + } + void print() const + { + mDigit.printLog(); + for (const auto& entry : mVecChannelData) { + entry.printLog(); + } + } + }; + std::vector<EventFT0_t> vecTotalEvents, vecTotalEvents2; + gSystem->Exec("$O2_ROOT/bin/o2-sim -n 10 -m FT0 -g pythia8pp"); + gSystem->Exec("$O2_ROOT/bin/o2-sim-digitizer-workflow -b"); + TFile flIn("ft0digits.root"); + std::unique_ptr<TTree> treeInput((TTree*)flIn.Get("o2sim")); + std::vector<Digit> vecDigits; + std::vector<Digit>* ptrVecDigits = &vecDigits; + std::vector<ChannelData> vecChannelData; + std::vector<ChannelData>* ptrVecChannelData = &vecChannelData; + treeInput->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries:" << treeInput->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFT0 = EventFT0_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents.push_back(eventFT0); + } + } + std::cout << "\n===================================\n"; + for (auto const& entry : vecTotalEvents) { + entry.print(); + } + std::cout << "\n===================================\n"; + + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents.size() << std::endl; + std::cout << "Simulation completed!" << std::endl; + gSystem->Exec("$O2_ROOT/bin/o2-ft0-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\""); + gSystem->Exec("$O2_ROOT/bin/o2-raw-file-reader-workflow -b --input-conf FT0raw.cfg --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\"|$O2_ROOT/bin/o2-ft0-flp-dpl-workflow -b"); + TFile flIn2("o2_ft0digits.root"); + std::unique_ptr<TTree> treeInput2((TTree*)flIn2.Get("o2sim")); + std::cout << "Reconstruction completed!" << std::endl; + + treeInput2->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput2->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries: " << treeInput2->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput2->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput2->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFT0 = EventFT0_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents2.push_back(eventFT0); + } + } + std::cout << "\n===================================\n"; + for (auto const& entry : vecTotalEvents2) { + entry.print(); + } + std::cout << "\n===================================\n"; + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents2.size() << std::endl; + if (vecTotalEvents == vecTotalEvents2) { + std::cout << "\n TEST IS OK!\n"; + } else { + std::cout << "\nDIFFERENCE BETWEEN SRC AND DEST\n"; + std::cout << "\n===============================\n"; + for (int iEntry = 0; iEntry < std::max(vecTotalEvents.size(), vecTotalEvents2.size()); iEntry++) { + if (iEntry < vecTotalEvents.size() && iEntry < vecTotalEvents2.size()) { + if (vecTotalEvents[iEntry] == vecTotalEvents2[iEntry]) { + continue; + } + } + std::cout << "\nEntryID: " << iEntry; + std::cout << "\n------------------------------SOURCE------------------------------\n"; + if (iEntry < vecTotalEvents.size()) { + vecTotalEvents[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + std::cout << "\n------------------------------DESTINATION------------------------------\n"; + if (iEntry < vecTotalEvents2.size()) { + vecTotalEvents2[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + } + std::cout << "\nERROR!\n"; + } + return 0; +} diff --git a/Detectors/FIT/FT0/simulation/CMakeLists.txt b/Detectors/FIT/FT0/simulation/CMakeLists.txt index 918a248854d24..3de4e26cb08ee 100644 --- a/Detectors/FIT/FT0/simulation/CMakeLists.txt +++ b/Detectors/FIT/FT0/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FT0Simulation SOURCES src/Detector.cxx @@ -17,6 +18,8 @@ o2_add_library(FT0Simulation O2::FT0Base O2::DataFormatsFT0 O2::DetectorsRaw + O2::CCDB + O2::DetectorsCalibration O2::Headers) o2_target_root_dictionary(FT0Simulation HEADERS @@ -31,9 +34,10 @@ o2_target_root_dictionary(FT0Simulation HEADERS o2_add_executable(digi2raw COMPONENT_NAME ft0 - SOURCES src/digi2raw.cxx + SOURCES src/digit2raw.cxx PUBLIC_LINK_LIBRARIES O2::FT0Simulation O2::DetectorsRaw O2::DetectorsCommonDataFormats O2::CommonUtils - Boost::program_options) + Boost::program_options + O2::FT0Raw) diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Detector.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Detector.h index 9eea2415300ee..ac5c76526d088 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Detector.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,10 +15,12 @@ #ifndef ALICEO2_FT0_DETECTOR_H_ #define ALICEO2_FT0_DETECTOR_H_ +#include <TGeoShape.h> #include "SimulationDataFormat/BaseHits.h" #include "DetectorsBase/Detector.h" // for Detector #include "FT0Base/Geometry.h" #include "DataFormatsFT0/HitType.h" +#include <TGeoManager.h> // for gGeoManager, TGeoManager (ptr only) class FairModule; @@ -47,13 +50,15 @@ class Detector : public o2::base::DetImpl<Detector> kVac = 3, kCeramic = 4, kGlass = 6, - kOpAir = 7, + // kOpAir = 7, kAl = 15, kOpGlass = 16, kOptAl = 17, kOptBlack = 18, kOpGlassCathode = 19, - kSensAir = 22 + // kSensAir = 22, + kCable = 23, + kMCPwalls = 25 }; // materials /// Name : Detector Name @@ -93,22 +98,30 @@ class Detector : public o2::base::DetImpl<Detector> void ConstructOpGeometry() override; void SetOneMCP(TGeoVolume* stl); + void SetCablesA(TGeoVolume* stl); + TGeoVolume* SetCablesSize(int mod); + // Optical properties reader: e-Energy, abs-AbsorptionLength[cm], n-refractive index void DefineOpticalProperties(); Int_t ReadOptProperties(const std::string inputFilePath); void FillOtherOptProperties(); Bool_t RegisterPhotoE(float energy); - - // Geometry* GetGeometry(); - - /// Prints out the content of this class in ASCII format - /// \param ostream *os The output stream void Print(std::ostream* os) const; /// Reads in the content of this class in the format of Print /// \param istream *is The input stream void Read(std::istream* is); + void DefineSim2LUTindex(); + /// Add alignable volumes + void addAlignableVolumes() const override; + // Return Chip Volume UID + /// \param id volume id + Int_t chipVolUID(Int_t id) const + { + return o2::base::GeometryManager::getSensID(o2::detectors::DetID::FT0, id); + } + private: /// copy constructor (used in MT) Detector(const Detector& rhs); @@ -136,6 +149,102 @@ class Detector : public o2::base::DetImpl<Detector> std::vector<Double_t> mEffBlackPaper; std::vector<Double_t> mReflFrontWindow; + // Define the aluminium frame for the detector + TGeoVolume* constructFrameGeometry(); + std::string frame1CompositeShapeBoolean(); + std::string frame2CompositeShapeBoolean(); + std::string frameCompositeShapeBoolean(); + std::string plateGroupCompositeShapeBoolean(); + std::string opticalFiberPlateCompositeShapeBoolean1(); + std::string opticalFiberPlateCompositeShapeBoolean2(); + std::string pmtCornerCompositeShapeBoolean(); + std::string pmtCompositeShapeBoolean(); + std::string plateBoxCompositeShapeBoolean(); + void defineTransformations(); + void defineQuartzRadiatorTransformations(); + void definePmtTransformations(); + void definePlateTransformations(); + void defineFrameTransformations(); + + // BEGIN: Support structure constants + // define some error to avoid overlaps + static constexpr Float_t sEps = 0.05; + // offset found to potentially remove overlaps + static constexpr Float_t sXoffset = 0.3027999999999995; + static constexpr Float_t sYoffset = -0.6570999999999998; + + // frame 1 has a longer side horizontal + static constexpr Float_t sFrame1X = 21.500; + static constexpr Float_t sFrame1Y = 13.705; + static constexpr Float_t sFrame1PosX = 7.9278 - sXoffset; + static constexpr Float_t sFrame1PosY = 9.2454 - sYoffset; + static constexpr Float_t sRect1X = 15; + static constexpr Float_t sRect1Y = 1.33; + static constexpr Float_t sRect2X = 2.9; + static constexpr Float_t sRect2Y = 12.2; + static constexpr Float_t sRect3X = 1.57; + static constexpr Float_t sRect3Y = .175; + static constexpr Float_t sRect4X = 5.65; + static constexpr Float_t sRect4Y = 1.075; + // frame 2 has a longer side vertical + static constexpr Float_t sFrame2X = 13.930; + static constexpr Float_t sFrame2Y = 21.475; + static constexpr Float_t sFrame2PosX = 10.1428 - sXoffset; + static constexpr Float_t sFrame2PosY = -8.3446 - sYoffset; + static constexpr Float_t sRect5X = 1.33; + static constexpr Float_t sRect5Y = 12.1; + + static constexpr Float_t sRect6X = .83; + static constexpr Float_t sRect6Y = 3.0; + static constexpr Float_t sRect7X = 13.1; + static constexpr Float_t sRect7Y = 3.0; + static constexpr Float_t sRect8X = 1.425; + static constexpr Float_t sRect8Y = 5.5; + + // both frame boxes are the same height + static constexpr Float_t sFrameZ = 5.700; + static constexpr Float_t sMountZ = 1.5; + + // PMT socket dimensions + static constexpr Float_t sPmtSide = 5.950; + static constexpr Float_t sPmtZ = 3.750; + + // quartz radiator socket dimensions + // static constexpr Float_t sQuartzRadiatorSide = 5.350; + // static constexpr Float_t sQuartzRadiatorZ = 1.950; + static constexpr Float_t sQuartzRadiatorSide = 5.40; + static constexpr Float_t sQuartzRadiatorZ = 2.0; + // for the rounded socket corners + static constexpr Float_t sCornerRadius = .300; + + // bottom plates on the frame + static constexpr Float_t sPlateSide = 6.000; + static constexpr Float_t sBasicPlateZ = 0.200; + static constexpr Float_t sCablePlateZ = 0.500; + static constexpr Float_t sFiberHeadX = 0.675 * 2; + static constexpr Float_t sFiberHeadY = 0.275 * 2; + + // plate transformations + static constexpr Float_t sOpticalFiberPlateZ = 0.35; + static constexpr Float_t sPlateSpacing = 6.100; + static constexpr Float_t sPlateDisplacementDeltaY = 1.33; + static constexpr Float_t sPlateDisplacementX = sPlateSpacing + 0.3028; + static constexpr Float_t sPlateDisplacementY = 12.8789 - sPlateDisplacementDeltaY; + static constexpr Float_t sPlateGroupZ = -sFrameZ / 2 - sOpticalFiberPlateZ; + + // quartz & PMT socket transformations + static constexpr Float_t sQuartzHeight = -sFrameZ / 2 + sQuartzRadiatorZ / 2; + static constexpr Float_t sPmtHeight = sFrameZ / 2 - sPmtZ / 2; + static constexpr Float_t sPmtCornerTubePos = -.15; + static constexpr Float_t sPmtCornerPos = 2.825; + static constexpr Float_t sEdgeCornerPos[2] = {-6.515, -.515}; + static constexpr Float_t sQuartzFrameOffsetX = -1.525; + static constexpr Float_t sPos1X[3] = {sQuartzFrameOffsetX - sPlateSpacing, sQuartzFrameOffsetX, sQuartzFrameOffsetX + sPlateSpacing}; + static constexpr Float_t sPos1Y[4] = {3.6275, -2.4725, 2.2975, -3.8025}; + static constexpr Float_t sPos2X[4] = {3.69, -2.410, 2.360, -3.740}; + static constexpr Float_t sPos2Y[3] = {7.6875, 1.5875, -4.5125}; + //END: Support structure constants + /// Container for data points std::vector<o2::ft0::HitType>* mHits = nullptr; @@ -152,7 +261,18 @@ class Detector : public o2::base::DetImpl<Detector> int mTrackIdTop; int mTrackIdMCPtop; //TEMPORARY - ClassDefOverride(Detector, 2); + int mSim2LUT[Geometry::Nchannels]; + + Double_t mPosModuleAx[Geometry::NCellsA]; + Double_t mPosModuleAy[Geometry::NCellsA]; + Double_t mPosModuleCx[Geometry::NCellsC]; + Double_t mPosModuleCy[Geometry::NCellsC]; + Double_t mPosModuleCz[Geometry::NCellsC]; + Float_t mStartC[3] = {20., 20, 5.5}; + Float_t mStartA[3] = {20., 20., 5}; + Float_t mInStart[3] = {2.9491, 2.9491, 2.5}; + + ClassDefOverride(Detector, 5); }; // Input and output function for standard C++ input/output. diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationConstants.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationConstants.h index 66118f17701f3..63ba8de3f084c 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationConstants.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationParameters.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationParameters.h index 1552631a2bb80..3eba62ca05f00 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationParameters.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,44 +12,40 @@ #ifndef ALICEO2_FT0_DIGITIZATION_PARAMETERS #define ALICEO2_FT0_DIGITIZATION_PARAMETERS #include <FT0Base/Geometry.h> +#include <CommonUtils/ConfigurableParamHelper.h> namespace o2::ft0 { -struct DigitizationParameters { - int nCellsA = Geometry::NCellsA; - int nCellsC = Geometry::NCellsC; - float zDetA = Geometry::ZdetA; - float zDetC = Geometry::ZdetC; - float bunchWidth = 25; //ns - float channelWidth = Geometry::ChannelWidth; - float ChannelWidthInverse = 0.076804916; // channel width in ps inverse - float mMCPs = (Geometry::NCellsA + Geometry::NCellsC) * 4; //number of MCPs +struct DigitizationParameters + : o2::conf::ConfigurableParamHelper<DigitizationParameters> { + float mBunchWidth = 25; //ns + float mChannelWidthInverse = 0.076804916; // channel width in ps inverse + + float mMCPs = Geometry::Nchannels; //number of MCPs float mCFD_trsh = 3.; // [mV] float mAmp_trsh = 100; // [ph.e] float mAmpRecordLow = -4; // integrate charge from - float mAmpRecordUp = 15; // to [ns] - int mTime_trg_gate = 192; // #channels - // int mTime_trg_gate = 2000; //2000/13; (+-2ns) #channels no limits - float mTimeDiffAC = (Geometry::ZdetA - Geometry::ZdetC) * TMath::C(); - float C_side_cable_cmps = 2.86; //ns - float A_side_cable_cmps = 11.110; //ns - int mtrg_central_trh = 600.; // channels - int mtrg_semicentral_trh = 300.; // channels + float mC_side_cable_cmps = 2.86; //ns + float mA_side_cable_cmps = 11.110; //ns + int mtrg_central_trh = 600.; // channels + int mtrg_semicentral_trh = 300.; // channels - float mMip_in_V = 7; //MIP to mV - float mPe_in_mip = 0.004; // invserse Np.e. in MIP 1./250. - float mCfdShift = 1.66; //ns - float mCFDShiftPos = 1.47; //// shift positive part of CFD signal; distance between 0.3 of max amplitude to max - float mCFDdeadTime = 15.6; // ns - float AmpIntegrationTime = 19; //ns - float IntegWindowDelayA = 6; // ns, A side - float IntegWindowDelayC = -1.6; // ns, C side - float charge2amp = 0.22; + float mMip_in_V = 7; //MIP to mV + float mPe_in_mip = 0.004; // invserse Np.e. in MIP 1./250. + float mCfdShift = 1.66; //ns + float mCFDShiftPos = 1.47; //// shift positive part of CFD signal; distance between 0.3 of max amplitude to max + float mCFDdeadTime = 15.6; // ns + float mCharge2amp = 0.22; float mNoiseVar = 0.1; //noise level float mNoisePeriod = 1 / 0.9; // GHz low frequency noise period; - float mV_2_Nchannels = 2.2857143; //7 mV ->16channels + short mTime_trg_gate = 192; // #channels + + static constexpr float mMV_2_Nchannels = 2.2857143; //amplitude channel 7 mV ->16channels + static constexpr float mMV_2_NchannelsInverse = 0.437499997; //inverse amplitude channel 7 mV ->16channels + + O2ParamDef(DigitizationParameters, "DigitizationParameters"); }; } // namespace o2::ft0 #endif diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digitizer.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digitizer.h index faf0576122531..33479765314f0 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digitizer.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "DataFormatsFT0/MCLabel.h" #include "MathUtils/RandomRing.h" #include "FT0Simulation/Detector.h" +#include "FT0Base/Geometry.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "FT0Simulation/DigitizationConstants.h" @@ -37,20 +39,24 @@ class Digitizer { private: using DP = DigitizationConstants; - typedef math_utils::RandomRing<float_v::size() * DP::NOISE_RANDOM_RING_SIZE> NoiseRandomRingType; + typedef math_utils::RandomRing</*float_v::size()*/ 4 * DP::NOISE_RANDOM_RING_SIZE> NoiseRandomRingType; + static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; public: - Digitizer(const DigitizationParameters& params, Int_t mode = 0) : mMode(mode), mParameters(params), mRndGaus(NoiseRandomRingType::RandomType::Gaus), mNumNoiseSamples(), mNoiseSamples(), mSincTable(), mSignalTable(), mSignalCache() { initParameters(); } + Digitizer(Int_t mode = 0) : mMode(mode), mRndGaus(NoiseRandomRingType::RandomType::Gaus), mNumNoiseSamples(), mNoiseSamples(), mSincTable(), mSignalTable(), mSignalCache() { initParameters(); } ~Digitizer() = default; void process(const std::vector<o2::ft0::HitType>* hits, std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& label); void flush(std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& label); void flush_all(std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& label); void initParameters(); void printParameters() const; @@ -97,7 +103,7 @@ class Digitizer if (x <= 0.0f) { return 0.0f; } - float const y = x / mParameters.bunchWidth * DP::SIGNAL_TABLE_SIZE; + float const y = x / DigitizationParameters::Instance().mBunchWidth * DP::SIGNAL_TABLE_SIZE; int const index = std::floor(y); if (index + 1 >= DP::SIGNAL_TABLE_SIZE) { return mSignalTable.back(); @@ -106,13 +112,15 @@ class Digitizer return mSignalTable[index] + rem * (mSignalTable[index + 1] - mSignalTable[index]); } - inline Vc::float_v signalFormVc(Vc::float_v x) const + template <typename VcType> + inline VcType signalFormVc(VcType x) const { // table lookup for the signal shape (SIMD version) - auto const y = x / mParameters.bunchWidth * DP::SIGNAL_TABLE_SIZE; - Vc::float_v::IndexType const index = Vc::floor(y); + // implemented as template function, so that we don't need to include <Vc/Vc> here + auto const y = x / DigitizationParameters::Instance().mBunchWidth * DP::SIGNAL_TABLE_SIZE; + typename VcType::IndexType const index = floor(y); auto const rem = y - index; - Vc::float_v val(0); - for (size_t i = 0; i < float_v::size(); ++i) { + VcType val(0); + for (size_t i = 0; i < VcType::size(); ++i) { if (y[i] < 0.0f) { continue; } @@ -136,9 +144,9 @@ class Digitizer o2::InteractionRecord firstBCinDeque = 0; std::deque<BCCache> mCache; - std::array<GoodInteractionTimeRecord, 208> mDeadTimes; + std::array<GoodInteractionTimeRecord, NCHANNELS> mDeadTimes; - DigitizationParameters mParameters; + o2::ft0::Geometry mGeometry; NoiseRandomRingType mRndGaus; int mNumNoiseSamples; // number of noise samples in one BC @@ -150,45 +158,12 @@ class Digitizer void storeBC(BCCache& bc, std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& labels); - ClassDefNV(Digitizer, 1); + ClassDefNV(Digitizer, 2); }; -// signal shape function -template <typename Float> -Float signalForm_i(Float x) -{ - using namespace std; - Float const a = -0.45458; - Float const b = -0.83344945; - return x > Float(0) ? -(exp(b * x) - exp(a * x)) / Float(7.8446501) : Float(0); - //return -(exp(-0.83344945 * x) - exp(-0.45458 * x)) * (x >= 0) / 7.8446501; // Maximum should be 7.0/250 mV -}; - -// integrated signal shape function -inline float signalForm_integral(float x) -{ - using namespace std; - double const a = -0.45458; - double const b = -0.83344945; - if (x < 0) { - x = 0; - } - return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501; -}; - -// SIMD version of the integrated signal shape function -inline Vc::float_v signalForm_integralVc(Vc::float_v x) -{ - auto const mask = (x >= 0.0f); - Vc::float_v arg(0); - arg.assign(x, mask); // branchless if - Vc::float_v const a(-0.45458f); - Vc::float_v const b(-0.83344945f); - Vc::float_v result = -(Vc::exp(b * arg) / b - Vc::exp(a * arg) / a) / 7.8446501f; - return result; -}; } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizerTask.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizerTask.h index fc8232cc79f5f..e689fc9bfc903 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizerTask.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizerTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digits2Raw.h b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digits2Raw.h index 4a4b4cabd3f15..258a440578232 100644 --- a/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digits2Raw.h +++ b/Detectors/FIT/FT0/simulation/include/FT0Simulation/Digits2Raw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "DataFormatsFT0/ChannelData.h" #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RawFileWriter.h" +#include "FT0Base/Geometry.h" #include <TStopwatch.h> #include <cassert> #include <fstream> @@ -40,12 +42,11 @@ namespace ft0 class Digits2Raw { - static constexpr int Nchannels_FT0 = 208; static constexpr int Nchannels_PM = 12; - static constexpr int LinkTCM = 18; - static constexpr int NPMs = 19; + static constexpr int NPMs = 20; static constexpr int GBTWordSize = 128; // with padding static constexpr int Max_Page_size = 8192; + static constexpr int Nchannels_FT0 = o2::ft0::Geometry::Nchannels; public: Digits2Raw() = default; @@ -56,17 +57,6 @@ class Digits2Raw const o2::ft0::LookUpTable& lut, o2::InteractionRecord const& mIntRecord); - static o2::ft0::LookUpTable linear() - { - std::vector<o2::ft0::Topo> lut_data(Nchannels_PM * (NPMs - 1)); - for (int link = 0; link < NPMs - 1; ++link) { - for (int mcp = 0; mcp < Nchannels_PM; ++mcp) { - lut_data[link * Nchannels_PM + mcp] = o2::ft0::Topo{link, mcp}; - } - } - - return o2::ft0::LookUpTable{lut_data}; - } o2::raw::RawFileWriter& getWriter() { return mWriter; } void setFilePerLink(bool v) { mOutputPerLink = v; } @@ -74,6 +64,9 @@ class Digits2Raw void setVerbosity(int v) { mVerbosity = v; } int getVerbosity() const { return mVerbosity; } + int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const; private: EventHeader makeGBTHeader(int link, o2::InteractionRecord const& mIntRecord); @@ -88,10 +81,11 @@ class Digits2Raw uint16_t mCruID = 0; uint32_t mEndPointID = 0; uint64_t mFeeID = 0; + int mLinkTCM; ///////////////////////////////////////////////// - ClassDefNV(Digits2Raw, 1); + ClassDefNV(Digits2Raw, 2); }; } // namespace ft0 diff --git a/Detectors/FIT/FT0/simulation/src/Detector.cxx b/Detectors/FIT/FT0/simulation/src/Detector.cxx index 6becdfbf2866c..5326f25472ed7 100644 --- a/Detectors/FIT/FT0/simulation/src/Detector.cxx +++ b/Detectors/FIT/FT0/simulation/src/Detector.cxx @@ -1,13 +1,21 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include <Buttons.h> +#include <TGeoCompositeShape.h> +#include <TGeoShape.h> +#include <TGeoBBox.h> +#include <TGeoTube.h> +#include <TGeoVolume.h> +#include <TMCManagerStack.h> #include "TGeoManager.h" // for TGeoManager #include "TMath.h" #include "TGraph.h" @@ -24,6 +32,7 @@ #include "FairVolume.h" #include <sstream> +#include <string> #include "FT0Base/Geometry.h" #include "FT0Simulation/Detector.h" #include "SimulationDataFormat/Stack.h" @@ -38,7 +47,6 @@ Detector::Detector(Bool_t Active) { // Gegeo = GetGeometry() ; - // TString gn(geo->GetName()); } @@ -59,7 +67,6 @@ void Detector::InitializeO2Detector() if (v == nullptr) { LOG(WARN) << "@@@@ Sensitive volume 0REG not found!!!!!!!!"; } else { - AddSensitiveVolume(v); } @@ -82,133 +89,71 @@ void Detector::ConstructGeometry() LOG(DEBUG) << "Creating FT0 geometry\n"; CreateMaterials(); - Float_t zdetA = Geometry::ZdetA; - Float_t zdetC = Geometry::ZdetC; - - Int_t idrotm[999]; - Double_t x, y, z; - Float_t pstartC[3] = {20., 20, 5}; - Float_t pstartA[3] = {20, 20, 5}; - Float_t pinstart[3] = {2.9491, 2.9491, 2.5}; - Float_t pmcp[3] = {2.949, 2.949, 1.}; // MCP - - int nCellsA = Geometry::NCellsA; - int nCellsC = Geometry::NCellsC; + TGeoVolumeAssembly* stlinA = new TGeoVolumeAssembly("FT0A"); // A side mother + TGeoVolumeAssembly* stlinC = new TGeoVolumeAssembly("FT0C"); // C side mother Geometry geometry; - TVector3 centerMCP = geometry.centerMCP(2); - Matrix(idrotm[901], 90., 0., 90., 90., 180., 0.); - - // C side Concave Geometry - - Double_t crad = Geometry::ZdetC; // define concave c-side radius here - - Double_t dP = pmcp[0]; // side length of mcp divided by 2 - - // uniform angle between detector faces== - Double_t btta = 2 * TMath::ATan(dP / crad); - - // get noncompensated translation data - Double_t grdin[6] = {-3, -2, -1, 1, 2, 3}; - Double_t gridpoints[6]; - for (Int_t i = 0; i < 6; i++) { - gridpoints[i] = crad * TMath::Sin((1 - 1 / (2 * TMath::Abs(grdin[i]))) * grdin[i] * btta); - } - - Double_t xi[Geometry::NCellsC] = {gridpoints[1], gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[0], - gridpoints[1], gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[5], - gridpoints[0], gridpoints[1], gridpoints[4], gridpoints[5], gridpoints[0], - gridpoints[1], gridpoints[4], gridpoints[5], gridpoints[0], gridpoints[1], - gridpoints[2], gridpoints[3], gridpoints[4], gridpoints[5], gridpoints[1], - gridpoints[2], gridpoints[3], gridpoints[4]}; - Double_t yi[Geometry::NCellsC] = {gridpoints[5], gridpoints[5], gridpoints[5], gridpoints[5], gridpoints[4], - gridpoints[4], gridpoints[4], gridpoints[4], gridpoints[4], gridpoints[4], - gridpoints[3], gridpoints[3], gridpoints[3], gridpoints[3], gridpoints[2], - gridpoints[2], gridpoints[2], gridpoints[2], gridpoints[1], gridpoints[1], - gridpoints[1], gridpoints[1], gridpoints[1], gridpoints[1], gridpoints[0], - gridpoints[0], gridpoints[0], gridpoints[0]}; - Double_t zi[Geometry::NCellsC]; - for (Int_t i = 0; i < Geometry::NCellsC; i++) { - zi[i] = TMath::Sqrt(TMath::Power(crad, 2) - TMath::Power(xi[i], 2) - TMath::Power(yi[i], 2)); - } - - // get rotation data - Double_t ac[Geometry::NCellsC], bc[Geometry::NCellsC], gc[Geometry::NCellsC]; - for (Int_t i = 0; i < Geometry::NCellsC; i++) { - ac[i] = TMath::ATan(yi[i] / xi[i]) - TMath::Pi() / 2 + 2 * TMath::Pi(); - if (xi[i] < 0) { - bc[i] = TMath::ACos(zi[i] / crad); - } else { - bc[i] = -1 * TMath::ACos(zi[i] / crad); - } - } - Double_t xc2[Geometry::NCellsC], yc2[Geometry::NCellsC], zc2[Geometry::NCellsC]; - - // compensation based on node position within individual detector geometries - // determine compensated radius - Double_t rcomp = crad + pstartC[2] / 2.0; // - for (Int_t i = 0; i < Geometry::NCellsC; i++) { - // Get compensated translation data - xc2[i] = rcomp * TMath::Cos(ac[i] + TMath::Pi() / 2) * TMath::Sin(-1 * bc[i]); - yc2[i] = rcomp * TMath::Sin(ac[i] + TMath::Pi() / 2) * TMath::Sin(-1 * bc[i]); - zc2[i] = rcomp * TMath::Cos(bc[i]); - - // Convert angles to degrees - ac[i] *= 180 / TMath::Pi(); - bc[i] *= 180 / TMath::Pi(); - gc[i] = -1 * ac[i]; + Float_t zdetA = geometry.ZdetA; + Float_t zdetC = geometry.ZdetC; + int nCellsA = geometry.NCellsA; + int nCellsC = geometry.NCellsC; + + for (int ipos = 0; ipos < nCellsA; ipos++) { + mPosModuleAx[ipos] = geometry.centerMCP(ipos).X(); + mPosModuleAy[ipos] = geometry.centerMCP(ipos).Y(); } - // A Side - - Float_t xa[Geometry::NCellsA] = {-11.8, -5.9, 0, 5.9, 11.8, -11.8, -5.9, 0, 5.9, 11.8, -12.8, -6.9, - 6.9, 12.8, -11.8, -5.9, 0, 5.9, 11.8, -11.8, -5.9, 0, 5.9, 11.8}; - - Float_t ya[Geometry::NCellsA] = {11.9, 11.9, 12.9, 11.9, 11.9, 6.0, 6.0, 7.0, 6.0, 6.0, -0.1, -0.1, - 0.1, 0.1, -6.0, -6.0, -7.0, -6.0, -6.0, -11.9, -11.9, -12.9, -11.9, -11.9}; - - TGeoVolumeAssembly* stlinA = new TGeoVolumeAssembly("0STL"); // A side mother - TGeoVolumeAssembly* stlinC = new TGeoVolumeAssembly("0STR"); // C side mother // FIT interior - TVirtualMC::GetMC()->Gsvolu("0INS", "BOX", getMediumID(kAir), pinstart, 3); - TGeoVolume* ins = gGeoManager->GetVolume("0INS"); + TVirtualMC::GetMC()->Gsvolu("0MOD", "BOX", getMediumID(kAir), mInStart, 3); + TGeoVolume* ins = gGeoManager->GetVolume("0MOD"); // - TGeoTranslation* tr[Geometry::NCellsA + Geometry::NCellsC]; + TGeoTranslation* tr[nCellsA + nCellsC]; TString nameTr; - // A side Translations for (Int_t itr = 0; itr < Geometry::NCellsA; itr++) { nameTr = Form("0TR%i", itr + 1); - z = -pstartA[2] + pinstart[2]; - tr[itr] = new TGeoTranslation(nameTr.Data(), xa[itr], ya[itr], z); + float z = -mStartA[2] + mInStart[2]; + tr[itr] = new TGeoTranslation(nameTr.Data(), mPosModuleAx[itr], mPosModuleAy[itr], z); tr[itr]->RegisterYourself(); stlinA->AddNode(ins, itr, tr[itr]); + LOG(DEBUG) << " A geom " << itr << " " << mPosModuleAx[itr] << " " << mPosModuleAy[itr]; } + SetCablesA(stlinA); + //Add FT0-A support Structure to the geometry + stlinA->AddNode(constructFrameGeometry(), 1, new TGeoTranslation(0, 0, -mStartA[2] + mInStart[2])); - TGeoRotation* rot[Geometry::NCellsC]; + // C Side + TGeoRotation* rot[nCellsC]; TString nameRot; - - TGeoCombiTrans* com[Geometry::NCellsC]; + TGeoCombiTrans* com[nCellsC]; + TGeoCombiTrans* comCable[nCellsC]; TString nameCom; - // C Side Transformations - for (Int_t itr = Geometry::NCellsA; itr < Geometry::NCellsA + Geometry::NCellsC; itr++) { + for (Int_t itr = Geometry::NCellsA; itr < Geometry::NCellsA + nCellsC; itr++) { nameTr = Form("0TR%i", itr + 1); nameRot = Form("0Rot%i", itr + 1); int ic = itr - Geometry::NCellsA; - // nameCom = Form("0Com%i",itr+1); - rot[ic] = new TGeoRotation(nameRot.Data(), ac[ic], bc[ic], gc[ic]); + float ac1 = geometry.tiltMCP(ic).X(); + float bc1 = geometry.tiltMCP(ic).Y(); + float gc1 = geometry.tiltMCP(ic).Z(); + rot[ic] = new TGeoRotation(nameRot.Data(), ac1, bc1, gc1); + LOG(DEBUG) << " rot geom " << ic << " " << ac1 << " " << bc1 << " " << gc1; rot[ic]->RegisterYourself(); - - tr[itr] = new TGeoTranslation(nameTr.Data(), xc2[ic], yc2[ic], (zc2[ic] - 80.)); - tr[itr]->RegisterYourself(); - - // com[itr-Geometry::NCellsA] = new TGeoCombiTrans(tr[itr],rot[itr-Geometry::NCellsA]); - com[ic] = new TGeoCombiTrans(xc2[ic], yc2[ic], (zc2[ic] - 80), rot[ic]); - std::cout << ic << " " << xc2[ic] << " " << yc2[ic] << std::endl; + mPosModuleCx[ic] = geometry.centerMCP(ic + nCellsA).X(); + mPosModuleCy[ic] = geometry.centerMCP(ic + nCellsA).Y(); + mPosModuleCz[ic] = geometry.centerMCP(ic + nCellsA).Z() - 80; // !!! fix later + com[ic] = new TGeoCombiTrans(mPosModuleCx[ic], mPosModuleCy[ic], mPosModuleCz[ic], rot[ic]); TGeoHMatrix hm = *com[ic]; TGeoHMatrix* ph = new TGeoHMatrix(hm); stlinC->AddNode(ins, itr, ph); + //cables + TGeoVolume* cables = SetCablesSize(itr); + LOG(DEBUG) << " C " << mPosModuleCx[ic] << " " << mPosModuleCy[ic]; + // cables->Print(); + comCable[ic] = new TGeoCombiTrans(mPosModuleCx[ic], mPosModuleCy[ic], mPosModuleCz[ic] + mInStart[2] + 0.2, rot[ic]); + TGeoHMatrix hmCable = *comCable[ic]; + TGeoHMatrix* phCable = new TGeoHMatrix(hmCable); + stlinC->AddNode(cables, itr, comCable[ic]); } TGeoVolume* alice = gGeoManager->GetVolume("barrel"); @@ -218,6 +163,7 @@ void Detector::ConstructGeometry() // MCP + 4 x wrapped radiator + 4xphotocathod + MCP + Al top in front of radiators SetOneMCP(ins); + //SetCablesC(stlinC); } void Detector::ConstructOpGeometry() @@ -225,6 +171,7 @@ void Detector::ConstructOpGeometry() LOG(DEBUG) << "Creating FIT optical geometry properties"; DefineOpticalProperties(); + DefineSim2LUTindex(); } //_________________________________________ @@ -233,23 +180,22 @@ void Detector::SetOneMCP(TGeoVolume* ins) Double_t x, y, z; - Float_t pinstart[3] = {2.9491, 2.9491, 2.5}; - Float_t ptop[3] = {1.324, 1.324, 1.}; // Cherenkov radiator - // Float_t ptopblack[3] = {1.324, 1.324, 0.0002}; // black paper on the top on radiator + Float_t ptop[3] = {1.324, 1.324, 1.}; // Cherenkov radiator Float_t ptopref[3] = {1.3241, 1.3241, 1.}; // Cherenkov radiator wrapped with reflector Double_t prfv[3] = {0.0002, 1.323, 1.}; // Vertical refracting layer bettwen radiators and between radiator and not optical Air Double_t prfh[3] = {1.323, 0.0002, 1.}; // Horizontal refracting layer bettwen radiators and ... - Float_t pmcp[3] = {2.949, 2.949, 1.}; // MCP + Float_t pmcp[3] = {2.949, 2.949, 0.66}; // MCP Float_t pmcpinner[3] = {2.749, 2.749, 0.1}; - Float_t pmcpside[3] = {0.1, 2.949, 1}; - Float_t pmcpbase[3] = {2.949, 2.949, 0.1}; + Float_t pmcpbase[3] = {2.949, 2.949, 0.675}; + Float_t pmcpside[3] = {0.15, 2.949, 0.65}; Float_t pmcptopglass[3] = {2.949, 2.949, 0.1}; // MCP top glass optical + Float_t preg[3] = {1.324, 1.324, 0.005}; // Photcathode + Double_t pal[3] = {2.648, 2.648, 0.25}; // 5mm Al on top of each radiator - Float_t preg[3] = {1.324, 1.324, 0.005}; // Photcathode - Double_t pal[3] = {2.648, 2.648, 0.25}; // 5mm Al on top of each radiator // Entry window (glass) TVirtualMC::GetMC()->Gsvolu("0TOP", "BOX", getMediumID(kOpGlass), ptop, 3); // Glass radiator TGeoVolume* top = gGeoManager->GetVolume("0TOP"); + top->Print(); // TVirtualMC::GetMC()->Gsvolu("0TBL", "BOX", getMediumID(kOptBlack), ptopblack, 3); // Glass radiator // TGeoVolume* topblack = gGeoManager->GetVolume("0TBL"); TVirtualMC::GetMC()->Gsvolu("0TRE", "BOX", getMediumID(kAir), ptopref, 3); // Air: wrapped radiator @@ -259,64 +205,48 @@ void Detector::SetOneMCP(TGeoVolume* ins) TVirtualMC::GetMC()->Gsvolu("0RFH", "BOX", getMediumID(kOptAl), prfh, 3); // Optical Air horizontal TGeoVolume* rfh = gGeoManager->GetVolume("0RFH"); - TVirtualMC::GetMC()->Gsvolu("0PAL", "BOX", getMediumID(kAl), pal, 3); // 5mm Al on top of the radiator - TGeoVolume* altop = gGeoManager->GetVolume("0PAL"); - TVirtualMC::GetMC()->Gsvolu("0REG", "BOX", getMediumID(kOpGlassCathode), preg, 3); TGeoVolume* cat = gGeoManager->GetVolume("0REG"); //wrapped radiator + reflecting layers Int_t ntops = 0, nrfvs = 0, nrfhs = 0; - // Float_t yin = 0, xinv = 0, yinv = 0; x = y = z = 0; topref->AddNode(top, 1, new TGeoTranslation(0, 0, 0)); float xinv = -ptop[0] - prfv[0]; topref->AddNode(rfv, 1, new TGeoTranslation(xinv, 0, 0)); - printf(" GEOGEO refv %f , 0,0 \n", xinv); xinv = ptop[0] + prfv[0]; topref->AddNode(rfv, 2, new TGeoTranslation(xinv, 0, 0)); - printf(" GEOGEO refv %f , 0,0 \n", xinv); float yinv = -ptop[1] - prfh[1]; topref->AddNode(rfh, 1, new TGeoTranslation(0, yinv, 0)); - printf(" GEOGEO refh , 0, %f, 0 \n", yinv); yinv = ptop[1] + prfh[1]; topref->AddNode(rfh, 2, new TGeoTranslation(0, yinv, 0)); - // zin = -ptop[2] - ptopblack[2]; - // printf(" GEOGEO refh , 0, 0, %f \n", zin); - // topref->AddNode(topblack, 1, new TGeoTranslation(0, 0, zin)); //container for radiator, cathode for (Int_t ix = 0; ix < 2; ix++) { - float xin = -pinstart[0] + 0.3 + (ix + 0.5) * 2 * ptopref[0]; + float xin = -mInStart[0] + 0.3 + (ix + 0.5) * 2 * ptopref[0]; for (Int_t iy = 0; iy < 2; iy++) { - z = -pinstart[2] + 2 * pal[2] + ptopref[2]; - float yin = -pinstart[1] + 0.3 + (iy + 0.5) * 2 * ptopref[1]; + z = -mInStart[2] + ptopref[2]; + float yin = -mInStart[1] + 0.3 + (iy + 0.5) * 2 * ptopref[1]; ntops++; ins->AddNode(topref, ntops, new TGeoTranslation(xin, yin, z)); z += ptopref[2] + 2. * pmcptopglass[2] + preg[2]; ins->AddNode(cat, ntops, new TGeoTranslation(xin, yin, z)); + LOG(INFO) << " n " << ntops << " x " << xin << " y " << yin; } } - //Al top - z = -pinstart[2] + pal[2]; - ins->AddNode(altop, 1, new TGeoTranslation(0, 0, z)); - // MCP TVirtualMC::GetMC()->Gsvolu("0MTO", "BOX", getMediumID(kOpGlass), pmcptopglass, 3); //Op Glass TGeoVolume* mcptop = gGeoManager->GetVolume("0MTO"); - z = -pinstart[2] + 2 * pal[2] + 2 * ptopref[2] + pmcptopglass[2]; + z = -mInStart[2] + 2 * ptopref[2] + pmcptopglass[2]; ins->AddNode(mcptop, 1, new TGeoTranslation(0, 0, z)); TVirtualMC::GetMC()->Gsvolu("0MCP", "BOX", getMediumID(kAir), pmcp, 3); //glass TGeoVolume* mcp = gGeoManager->GetVolume("0MCP"); - z = -pinstart[2] + 2 * pal[2] + 2 * ptopref[2] + 2 * pmcptopglass[2] + 2 * preg[2] + pmcp[2]; + z = -mInStart[2] + 2 * ptopref[2] + 2 * pmcptopglass[2] + 2 * preg[2] + pmcp[2]; ins->AddNode(mcp, 1, new TGeoTranslation(0, 0, z)); - TVirtualMC::GetMC()->Gsvolu("0MIN", "BOX", getMediumID(kGlass), pmcpinner, 3); //glass - TGeoVolume* mcpinner = gGeoManager->GetVolume("0MIN"); - mcp->AddNode(mcpinner, 1, new TGeoTranslation(0, 0, 0)); - TVirtualMC::GetMC()->Gsvolu("0MSI", "BOX", getMediumID(kGlass), pmcpside, 3); //glass + TVirtualMC::GetMC()->Gsvolu("0MSI", "BOX", getMediumID(kMCPwalls), pmcpside, 3); //glass TGeoVolume* mcpside = gGeoManager->GetVolume("0MSI"); x = -pmcp[0] + pmcpside[0]; y = -pmcp[1] + pmcpside[1]; @@ -333,10 +263,614 @@ void Detector::SetOneMCP(TGeoVolume* ins) TVirtualMC::GetMC()->Gsvolu("0MBA", "BOX", getMediumID(kCeramic), pmcpbase, 3); //glass TGeoVolume* mcpbase = gGeoManager->GetVolume("0MBA"); - z = -pinstart[2] + 2 * pal[2] + 2 * ptopref[2] + pmcptopglass[2] + 2 * pmcp[2] + pmcpbase[2]; + z = -mInStart[2] + 2 * ptopref[2] + pmcptopglass[2] + 2 * pmcp[2] + pmcpbase[2]; ins->AddNode(mcpbase, 1, new TGeoTranslation(0, 0, z)); } +//---------------------------------- +void Detector::SetCablesA(TGeoVolume* stl) +{ + + float pcableplane[3] = {20, 20, 0.25}; // + + TVirtualMC::GetMC()->Gsvolu("0CAA", "BOX", getMediumID(kAir), pcableplane, 3); //container for cables + TGeoVolume* cableplane = gGeoManager->GetVolume("0CAA"); + // float zcableplane = -mStartA[2] + 2 * mInStart[2] + pcableplane[2]; + int na = 0; + double xcell[24], ycell[24]; + for (int imcp = 0; imcp < 24; imcp++) { + xcell[na] = mPosModuleAx[imcp]; + ycell[na] = mPosModuleAy[imcp]; + TGeoVolume* vol = SetCablesSize(imcp); + cableplane->AddNode(vol, na, new TGeoTranslation(xcell[na], ycell[na], 0)); + na++; + } + + //12 cables extending beyond the frame + Float_t pcablesextend[3] = {2, 15, 0.245}; + Float_t pcablesextendsmall[3] = {3, 2, 0.245}; + Float_t* ppcablesextend[] = {pcablesextend, pcablesextend, pcablesextendsmall, pcablesextendsmall}; + //left side + double xcell_side[] = {-mStartA[0] + pcablesextend[0], mStartA[0] - pcablesextend[0], 0, 0}; + double ycell_side[] = {0, 0, -mStartA[1] + pcablesextendsmall[1], mStartA[1] - pcablesextendsmall[1]}; + + for (int icab = 0; icab < 4; icab++) { + const std::string volName = Form("CAB%2.i", 52 + icab); + TVirtualMC::GetMC()->Gsvolu(volName.c_str(), " BOX", getMediumID(kCable), ppcablesextend[icab], 3); // cables + TGeoVolume* vol = gGeoManager->GetVolume(volName.c_str()); + cableplane->AddNode(vol, 1, new TGeoTranslation(xcell_side[icab], ycell_side[icab], 0)); + } + float zcableplane = mStartA[2] - pcableplane[2] - 3; + stl->AddNode(cableplane, 1, new TGeoTranslation(0, 0, zcableplane)); +} +//------------------------------------------ + +TGeoVolume* Detector::SetCablesSize(int mod) +{ + int na = 0; + int ncells = Geometry::NCellsC; + + int mcpcables[52] = {2, 1, 2, 1, 2, + 2, 1, 1, 1, 2, + 2, 1, 1, 2, + 2, 1, 1, 1, 2, + 2, 1, 2, 1, 2, + 2, 2, 3, 3, 1, + 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, + 2, 3, 3}; + + // cable D=0.257cm, Weight: 13 lbs/1000ft = 0.197g/cm; 1 piece 0.65cm + //1st 8 pieces - tube 8*0.65cm = 5.2cm; V = 0.0531cm2 -> box {0.27*0.27*1}cm; W = 0.66g + //2nd 24 pieces 24*0.65cm; V = 0.76 -> {0.44, 0.447 1}; W = 3.07g + //3d 48 pieces 48*0.65cm; V = 1.53cm^3; ->box {0.66, 0.66, 1.}; W= 6.14g + double xcell[ncells], ycell[ncells], zcell[ncells]; + float xsize[3] = {1.8, 1.8, 2.6}; // + float ysize[3] = {0.6, 1.7, 2.}; + float zsize[3] = {0.1, 0.1, 0.1}; + // for (int imcp = 0; imcp < Geometry::NCellsC; imcp++) { + int ic = mcpcables[mod]; + float calblesize[3]; + calblesize[0] = xsize[ic - 1]; + calblesize[1] = ysize[ic - 1]; + calblesize[2] = zsize[ic - 1]; + const std::string volName = Form("CAB%2.i", mod); + TVirtualMC::GetMC()->Gsvolu(volName.c_str(), "BOX", getMediumID(kCable), calblesize, 3); // cables + TGeoVolume* vol = gGeoManager->GetVolume(volName.c_str()); + LOG(DEBUG) << "C cables " << mod << " " << volName << " " << ic; + return vol; +} + +void Detector::addAlignableVolumes() const +{ + // + // Creates entries for alignable volumes associating the symbolic volume + // name with the corresponding volume path. + // + // First version (mainly ported from AliRoot) + // + + LOG(INFO) << "Add FT0 alignable volumes"; + + if (!gGeoManager) { + LOG(FATAL) << "TGeoManager doesn't exist !"; + return; + } + + TString volPath = Form("/cave_1/barrel_1"); + //set A side + TString volPathA = volPath + Form("/FT0A_1"); + TString symNameA = "FT0A"; + LOG(INFO) << symNameA << " <-> " << volPathA; + if (!gGeoManager->SetAlignableEntry(symNameA.Data(), volPathA.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << symNameA << " : " << volPathA; + } + //set C side + TString volPathC = volPath + Form("/FT0C_1"); + TString symNameC = "FT0C"; + LOG(INFO) << symNameC << " <-> " << volPathC; + if (!gGeoManager->SetAlignableEntry(symNameC.Data(), volPathC.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << symNameA << " : " << volPathA; + } + TString volPathMod, symNameMod; + for (Int_t imod = 0; imod < Geometry::NCellsA + Geometry::NCellsC; imod++) { + TString volPath = (imod < Geometry::NCellsA) ? volPathA : volPathC; + volPathMod = volPath + Form("/0MOD_%d", imod); + symNameMod = Form("0MOD_%d", imod); + if (!gGeoManager->SetAlignableEntry(symNameMod.Data(), volPathMod.Data())) { + LOG(FATAL) << (Form("Alignable entry %s not created. Volume path %s not valid", symNameMod.Data(), volPathMod.Data())); + } + } +} + +// Class wrapper for construction of FT0-A support structure +// The frame is constructed by defining two aluminum boxes that are placed in an L-shape, +// with material sequentially removed to re-create the CAD drawings, +// including sockets defined by the parameters of the sensitive elements that they are placed into +// Two L-shaped elements form the full support structure, with one reflected about the axes of symmetry +// First written by Joe Crowley and revised by Jason Pruitt from Cal Poly in 2019-2021 +TGeoVolume* Detector::constructFrameGeometry() +{ + // define the media + TGeoMedium* Vacuum = gGeoManager->GetMedium("FT0_Vacuum$"); + TGeoMedium* Al = gGeoManager->GetMedium("FT0_Aluminium$"); + + // make a volume assembly for the frame + TGeoVolumeAssembly* FT0_Frame = new TGeoVolumeAssembly("FT0_Frame"); + + // define translations for the quartz radiator and PMT sockets + defineTransformations(); + + // frame1 and frame2 are rectangles that approximate the outline of one L + // shape of the frame + TGeoBBox* frame1 = new TGeoBBox("frame1", sFrame1X / 2, sFrame1Y / 2, sFrameZ / 2); + TGeoBBox* frame2 = new TGeoBBox("frame2", sFrame2X / 2, sFrame2Y / 2, sFrameZ / 2); + + // the following elements are subtracted from frame1 and frame2 to better + // approximate the CAD shape + TGeoBBox* rect1 = new TGeoBBox("rect1", sRect1X / 2, sRect1Y / 2, sFrameZ / 2); + TGeoBBox* rect2 = new TGeoBBox("rect2", sRect2X / 2, sRect2Y / 2 + sEps, sFrameZ / 2 - sMountZ / 2); + TGeoBBox* rect3 = new TGeoBBox("rect3", sRect3X / 2, sRect3Y / 2, sFrameZ / 2); + TGeoBBox* rect4 = new TGeoBBox("rect4", sRect4X / 2, sRect4Y / 2, sFrameZ / 2); + TGeoBBox* rect5 = new TGeoBBox("rect5", sRect5X / 2 + sEps, sRect5Y / 2 + sEps, sFrameZ / 2 + sEps); + TGeoBBox* rect6 = new TGeoBBox("rect6", sRect6X / 2 + sEps, sRect6Y / 2 + sEps, sFrameZ / 2 + sEps); + TGeoBBox* rect7 = new TGeoBBox("rect7", sRect7X / 2 + sEps, sRect7Y / 2 + sEps, sFrameZ / 2 - sMountZ / 2 + sEps); + TGeoBBox* rect8 = new TGeoBBox("rect8", sRect8X / 2 + sEps, sRect8Y / 2 + sEps, sFrameZ / 2 + sEps); + + // Define a value to overcut the coincidence between the closure of the tube + // and the edge of the rectangle to eliminate artifacts + Double_t flopsErr = .00001; + // PMT and quartz radiator shapes provide the dimensions of the sockets to be subtracted + // from the frame that will make room for a sensitive element to fit + TGeoBBox* quartzRadiator = new TGeoBBox("quartzRadiator", sQuartzRadiatorSide / 2, sQuartzRadiatorSide / 2, sQuartzRadiatorZ / 2); + TGeoBBox* pmtBox = new TGeoBBox("pmtBox", sPmtSide / 2 + sEps, sPmtSide / 2 + sEps, sPmtZ / 2 + sEps); + + // these two shapes create a subtraction so that the corners of the holes that + // seat the sens elements are rounded + TGeoBBox* pmtCornerRect = new TGeoBBox("pmtCornerRect", sCornerRadius / 2 - flopsErr, sCornerRadius / 2 - flopsErr, sPmtZ / 2); + TGeoTube* pmtCornerTube = new TGeoTube("pmtCornerTube", 0, sCornerRadius, sPmtZ / 2 + sEps); + TGeoVolume* PMTCorner = new TGeoVolume("PMTCorner", new TGeoCompositeShape("PMTCorner", pmtCornerCompositeShapeBoolean().c_str()), Al); + // TGeoVolume* PMT = new TGeoVolume("PMT", new TGeoCompositeShape("PMT", pmtCompositeShapeBoolean().c_str()), Vacuum); + TGeoVolume* PMT = gGeoManager->MakeBox("PMT", Vacuum, sPmtSide / 2 + sEps, sPmtSide / 2 + sEps, sPmtZ / 2 + sEps); + + // add the plates on the bottom of the frame + TGeoBBox* basicPlate = new TGeoBBox("basicPlate", sPlateSide / 2, sPlateSide / 2, sBasicPlateZ / 2); + TGeoBBox* cablePlate = new TGeoBBox("cablePlate", sPlateSide / 2, sPlateSide / 2, sCablePlateZ / 2); + TGeoBBox* opticalFiberHead = new TGeoBBox("opticalFiberHead", sFiberHeadX / 2, sFiberHeadY / 2, sCablePlateZ / 2); + TGeoCompositeShape* opticalFiberPlate1 = new TGeoCompositeShape("opticalFiberPlate1", opticalFiberPlateCompositeShapeBoolean1().c_str()); + TGeoCompositeShape* opticalFiberPlate2 = new TGeoCompositeShape("opticalFiberPlate2", opticalFiberPlateCompositeShapeBoolean2().c_str()); + TGeoCompositeShape* plateBox = new TGeoCompositeShape("plateBox", plateBoxCompositeShapeBoolean().c_str()); + // holds 2 basic plates and 2 cable plates + TGeoVolume* plateGroup = new TGeoVolume("plateGroup", new TGeoCompositeShape("plateGroup", plateGroupCompositeShapeBoolean().c_str()), Al); // holds 3 plate boxes + // remove the material to form the sockets for the quartz radiators and PMTs + TGeoCompositeShape* frameRemovedPMTandRadiators1 = new TGeoCompositeShape("frameRemovedPMTandRadiators1", frame1CompositeShapeBoolean().c_str()); + TGeoCompositeShape* frameRemovedPMTandRadiators2 = new TGeoCompositeShape("frameRemovedPMTandRadiators2", frame2CompositeShapeBoolean().c_str()); + + // make the right side frame - L shape + TGeoVolume* frame = new TGeoVolume("frame", new TGeoCompositeShape("frame", frameCompositeShapeBoolean().c_str()), Al); + + // reflection for the left side of the frame + TGeoRotation* reflect = new TGeoRotation("reflect"); + reflect->ReflectX(true); + reflect->ReflectY(true); + reflect->RegisterYourself(); + + // add a shift to eliminate overlaps between sens elements and frame sockets + // this shift will apply to both sides of the frame + TGeoTranslation* xshift = new TGeoTranslation("xshift", .1028, 0, 0); + + // add the right and left sides to top volume + FT0_Frame->AddNode(frame, 1, xshift); // right side + FT0_Frame->AddNode(frame, 2, reflect); // left side + + return FT0_Frame; +} + +// the following are continually concatenated strings that ROOT Geometry will +// read in order to piece together the objects and translations that are +// defined above (what ROOT Geometry calls Booleans) +// frame1 is a horizontal aluminum box piece of the L-shape +std::string Detector::frame1CompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite frame shape + std::string frame1CompositeShapeBoolean = ""; + frame1CompositeShapeBoolean += "((frame1"; + + // remove the radiator shapes for the sockets + // frame1 is the horizontal piece of the right-hand L-shape (looking from back) + // with its own internal numbering for the sockets. To more easily map between + // the sensitive elements and their socket locations, we've included the correspondence + // between them. Within the horizontal piece, the sockets are numbered column by column + // from left to right + // --------- + // | | <-----Rectangle 1 removed here + // | 1 |----------------- ^ + // | | | | | + // --------- 3 | 5 | | + // | | | | | Rectangle 2 removed here + // | 2 |----------------- | + // | | | | | + // --------| 4 | 6 | | + // | | | v + // ^ ------------------ <------Rectangle 3 removed here + // | + // | + // Rectangle 4 removed here + // + // internal numbering for each is mapped to the sensitive element numbering + // for ease of comparison and identification + // Since one L is reflected about the axes of symmetry, the correspondence with + // sensitive element numbering for the left-side L-shape is also included here. + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr1"; //Sens Elmt 2,21 + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr2"; //Sens Elmt 7,16 + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr3"; //Sens Elmt 3,20 + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr4"; //Sens Elmt 8,15 + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr5"; //Sens Elmt 4,19 + frame1CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr6)"; //Sens Elmt 9,14 + + // remove the PMT shapes for the sockets + frame1CompositeShapeBoolean += " - PMT:PMTTr1"; + frame1CompositeShapeBoolean += " - PMT:PMTTr2"; + frame1CompositeShapeBoolean += " - PMT:PMTTr3"; + frame1CompositeShapeBoolean += " - PMT:PMTTr4"; + frame1CompositeShapeBoolean += " - PMT:PMTTr5"; + frame1CompositeShapeBoolean += " - PMT:PMTTr6)"; + + return frame1CompositeShapeBoolean; +} + +// frame2 is the vertical aluminum box piece of the L-shape +std::string Detector::frame2CompositeShapeBoolean() +{ + std::string frame2CompositeShapeBoolean = ""; + frame2CompositeShapeBoolean += "((frame2"; + + // remove the radiator shapes for the sockets + // frame2 is the vertical piece of the right-hand L-shape (looking from back) + // with its own internal numbering for the sockets. To more easily map between + // the sensitive elements and their socket locations, we've included the correspondence + // between them. Within the vertical piece, the sockets are numbered row by row + // from right to left + // ----------------- + // | | | + // Rectangle--> | 8 | 7 | + // 8 | | | + // removed -------------------- + // here | | | ^ + // | 10 | 9 | | + // | | | | Rectangle 5 removed here + // ----------------- | + // | | | | + // | 12 | 11 | v + // | | | <-----Rectangle 6 removed here + // ----------------- + // <----------------> + // Rectangle 7 removed here + // + // internal numbering for each is mapped to the sensitive element numbering + // for ease of comparison and identification + // Since one L is reflected about the axes of symmetry, the correspondence with + // sensitive element numbering for the left-side L-shape is also included here. + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr7"; //Sens Elmt 13,10 + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr8"; //Sens Elmt 12,11 + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr9"; //Sens Elmt 18,14 + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr10"; //Sens Elmt 17,15 + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr11"; //Sens Elmt 23,0 + frame2CompositeShapeBoolean += " - quartzRadiator:quartzRadiatorTr12)"; //Sens Elmt 22,1 + + // remove the PMT shapes for the sockets + frame2CompositeShapeBoolean += " - PMT:PMTTr7"; + frame2CompositeShapeBoolean += " - PMT:PMTTr8"; + frame2CompositeShapeBoolean += " - PMT:PMTTr9"; + frame2CompositeShapeBoolean += " - PMT:PMTTr10"; + frame2CompositeShapeBoolean += " - PMT:PMTTr11"; + frame2CompositeShapeBoolean += " - PMT:PMTTr12)"; + + return frame2CompositeShapeBoolean; +} +//Support structure L-shape element definition +std::string Detector::frameCompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite plateGroup shape + std::string frameCompositeShapeBoolean = ""; + + // add the two pieces called frame 1 and 2 into a single L-shaped element + frameCompositeShapeBoolean += "frameRemovedPMTandRadiators1:frameTr1"; + frameCompositeShapeBoolean += " + frameRemovedPMTandRadiators2:frameTr2"; + + // add the plateGroups to the L-shaped elements + frameCompositeShapeBoolean += " + plateGroup:plateGroupTr1"; + frameCompositeShapeBoolean += " + plateGroup:plateGroupTr2"; + + // subtract the extra Al from the L-shaped elements + frameCompositeShapeBoolean += " - rect1:rectTr1"; + frameCompositeShapeBoolean += " - rect2:rectTr2"; + frameCompositeShapeBoolean += " - rect3:rectTr3"; + frameCompositeShapeBoolean += " - rect4:rectTr4"; + frameCompositeShapeBoolean += " - rect5:rectTr5"; + frameCompositeShapeBoolean += " - rect6:rectTr6"; + frameCompositeShapeBoolean += " - rect7:rectTr7"; + frameCompositeShapeBoolean += " - rect8:rectTr8"; + + return frameCompositeShapeBoolean; +} + +//Plate group elements +std::string Detector::plateGroupCompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite plateGroup shape + std::string plateGroupCompositeShapeBoolean = ""; + + // add the plateBoxes to the plateGroup + plateGroupCompositeShapeBoolean += "plateBox:plateTr1"; + plateGroupCompositeShapeBoolean += " + plateBox:plateTr2"; + plateGroupCompositeShapeBoolean += " + plateBox:plateTr3"; + + return plateGroupCompositeShapeBoolean; +} + +//Optical fiber plate for the first aluminum box in the L-shaped element +std::string Detector::opticalFiberPlateCompositeShapeBoolean1() +{ + // create a string for the boolean operations for the composite opticalFiberPlate1 shape + std::string opticalFiberPlateCompositeShapeBoolean1 = ""; + opticalFiberPlateCompositeShapeBoolean1 += "cablePlate"; + opticalFiberPlateCompositeShapeBoolean1 += " - opticalFiberHead:opticalFiberHeadTr1"; + opticalFiberPlateCompositeShapeBoolean1 += " - opticalFiberHead:opticalFiberHeadTr2"; + opticalFiberPlateCompositeShapeBoolean1 += " - opticalFiberHead:opticalFiberHeadTr3"; + opticalFiberPlateCompositeShapeBoolean1 += " - opticalFiberHead:opticalFiberHeadTr4"; + + return opticalFiberPlateCompositeShapeBoolean1; +} + +//Optical fiber plate for the second aluminum box in the L-shaped element +std::string Detector::opticalFiberPlateCompositeShapeBoolean2() +{ + // create a string for the boolean operations for the composite opticalFiberPlate2 shape + std::string opticalFiberPlateCompositeShapeBoolean2 = ""; + + // remove the opticalFiberHead shapes from the cablePlate + opticalFiberPlateCompositeShapeBoolean2 += "cablePlate"; + opticalFiberPlateCompositeShapeBoolean2 += " - opticalFiberHead:opticalFiberHeadTr5"; + opticalFiberPlateCompositeShapeBoolean2 += " - opticalFiberHead:opticalFiberHeadTr6"; + opticalFiberPlateCompositeShapeBoolean2 += " - opticalFiberHead:opticalFiberHeadTr7"; + opticalFiberPlateCompositeShapeBoolean2 += " - opticalFiberHead:opticalFiberHeadTr8"; + + return opticalFiberPlateCompositeShapeBoolean2; +} +//Create rounded PMT socket corners +std::string Detector::pmtCornerCompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite pmtCorner shape + std::string pmtCornerCompositeShapeBoolean = ""; + pmtCornerCompositeShapeBoolean += "pmtCornerRect:pmtCornerRectTr"; + pmtCornerCompositeShapeBoolean += " - pmtCornerTube:pmtCornerTubeTr"; + + return pmtCornerCompositeShapeBoolean; +} + +//Create PMT socket shape +std::string Detector::pmtCompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite PMT shape + std::string pmtCompositeShapeBoolean = ""; + pmtCompositeShapeBoolean += "pmtBox"; + pmtCompositeShapeBoolean += " - PMTCorner:PMTCornerTr1"; + pmtCompositeShapeBoolean += " - PMTCorner:PMTCornerTr2"; + pmtCompositeShapeBoolean += " - PMTCorner:PMTCornerTr3"; + pmtCompositeShapeBoolean += " - PMTCorner:PMTCornerTr4"; + + return pmtCompositeShapeBoolean; +} +//Plate composite structure +std::string Detector::plateBoxCompositeShapeBoolean() +{ + // create a string for the boolean operations for the composite plateBox shape + std::string plateBoxCompositeShapeBoolean = ""; + plateBoxCompositeShapeBoolean += "basicPlate"; + plateBoxCompositeShapeBoolean += " + basicPlate:basicPlateTr"; + plateBoxCompositeShapeBoolean += " + opticalFiberPlate1:opticalFiberPlateTr1"; + plateBoxCompositeShapeBoolean += " + opticalFiberPlate2:opticalFiberPlateTr2"; + + return plateBoxCompositeShapeBoolean; +} + +//Wrapper function to define all support structure transformations at once +void Detector::defineTransformations() +{ + defineQuartzRadiatorTransformations(); + definePmtTransformations(); + definePlateTransformations(); + defineFrameTransformations(); +} + +//Transformations for quartz radiator sockets +void Detector::defineQuartzRadiatorTransformations() +{ + // translations for quartz radiator shapes to be removed from the frame2 pice of the L-shaped element + TGeoTranslation* quartzRadiatorTr1 = new TGeoTranslation("quartzRadiatorTr1", sPos1X[0], sPos1Y[0], sQuartzHeight); + quartzRadiatorTr1->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr2 = new TGeoTranslation("quartzRadiatorTr2", sPos1X[0], sPos1Y[1], sQuartzHeight); + quartzRadiatorTr2->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr3 = new TGeoTranslation("quartzRadiatorTr3", sPos1X[1], sPos1Y[2], sQuartzHeight); + quartzRadiatorTr3->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr4 = new TGeoTranslation("quartzRadiatorTr4", sPos1X[1], sPos1Y[3], sQuartzHeight); + quartzRadiatorTr4->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr5 = new TGeoTranslation("quartzRadiatorTr5", sPos1X[2], sPos1Y[2], sQuartzHeight); + quartzRadiatorTr5->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr6 = new TGeoTranslation("quartzRadiatorTr6", sPos1X[2], sPos1Y[3], sQuartzHeight); + quartzRadiatorTr6->RegisterYourself(); + + // translations for quartz radiator shapes to be removed from the frame1 piece of the L-shaped element + TGeoTranslation* quartzRadiatorTr7 = new TGeoTranslation("quartzRadiatorTr7", sPos2X[0], sPos2Y[0], sQuartzHeight); + quartzRadiatorTr7->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr8 = new TGeoTranslation("quartzRadiatorTr8", sPos2X[1], sPos2Y[0], sQuartzHeight); + quartzRadiatorTr8->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr9 = new TGeoTranslation("quartzRadiatorTr9", sPos2X[2], sPos2Y[1], sQuartzHeight); + quartzRadiatorTr9->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr10 = new TGeoTranslation("quartzRadiatorTr10", sPos2X[3], sPos2Y[1], sQuartzHeight); + quartzRadiatorTr10->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr11 = new TGeoTranslation("quartzRadiatorTr11", sPos2X[2], sPos2Y[2], sQuartzHeight); + quartzRadiatorTr11->RegisterYourself(); + TGeoTranslation* quartzRadiatorTr12 = new TGeoTranslation("quartzRadiatorTr12", sPos2X[3], sPos2Y[2], sQuartzHeight); + quartzRadiatorTr12->RegisterYourself(); +} +//Transformations for PMT sockets, including rounded corners +void Detector::definePmtTransformations() +{ + // translations for PMT shapes to be removed from the frame2 piece in the L-shaped element + TGeoTranslation* PMTTr1 = new TGeoTranslation("PMTTr1", sPos1X[0], sPos1Y[0], sPmtHeight); + PMTTr1->RegisterYourself(); + TGeoTranslation* PMTTr2 = new TGeoTranslation("PMTTr2", sPos1X[0], sPos1Y[1], sPmtHeight); + PMTTr2->RegisterYourself(); + TGeoTranslation* PMTTr3 = new TGeoTranslation("PMTTr3", sPos1X[1], sPos1Y[2], sPmtHeight); + PMTTr3->RegisterYourself(); + TGeoTranslation* PMTTr4 = new TGeoTranslation("PMTTr4", sPos1X[1], sPos1Y[3], sPmtHeight); + PMTTr4->RegisterYourself(); + TGeoTranslation* PMTTr5 = new TGeoTranslation("PMTTr5", sPos1X[2], sPos1Y[2], sPmtHeight); + PMTTr5->RegisterYourself(); + TGeoTranslation* PMTTr6 = new TGeoTranslation("PMTTr6", sPos1X[2], sPos1Y[3], sPmtHeight); + PMTTr6->RegisterYourself(); + + // translations for PMT shapes to be removed from the frame1 piece in the L-shaped element + TGeoTranslation* PMTTr7 = new TGeoTranslation("PMTTr7", sPos2X[0], sPos2Y[0], sPmtHeight); + PMTTr7->RegisterYourself(); + TGeoTranslation* PMTTr8 = new TGeoTranslation("PMTTr8", sPos2X[1], sPos2Y[0], sPmtHeight); + PMTTr8->RegisterYourself(); + TGeoTranslation* PMTTr9 = new TGeoTranslation("PMTTr9", sPos2X[2], sPos2Y[1], sPmtHeight); + PMTTr9->RegisterYourself(); + TGeoTranslation* PMTTr10 = new TGeoTranslation("PMTTr10", sPos2X[3], sPos2Y[1], sPmtHeight); + PMTTr10->RegisterYourself(); + TGeoTranslation* PMTTr11 = new TGeoTranslation("PMTTr11", sPos2X[2], sPos2Y[2], sPmtHeight); + PMTTr11->RegisterYourself(); + TGeoTranslation* PMTTr12 = new TGeoTranslation("PMTTr12", sPos2X[3], sPos2Y[2], sPmtHeight); + PMTTr12->RegisterYourself(); + + // define pmtCorner transformations + TGeoTranslation* pmtCornerTubeTr = new TGeoTranslation("pmtCornerTubeTr", sPmtCornerTubePos, sPmtCornerTubePos, 0); + pmtCornerTubeTr->RegisterYourself(); + TGeoTranslation* pmtCornerRectTr = new TGeoTranslation("pmtCornerRectTr", 0, 0, 0); + pmtCornerRectTr->RegisterYourself(); + TGeoTranslation* PMTCornerTr1 = new TGeoTranslation("PMTCornerTr1", sPmtCornerPos, sPmtCornerPos, 0); + PMTCornerTr1->RegisterYourself(); + TGeoRotation* reflect2 = new TGeoRotation(); + reflect2->ReflectX(true); + reflect2->RegisterYourself(); + TGeoCombiTrans* PMTCornerTr2 = new TGeoCombiTrans("PMTCornerTr2", -sPmtCornerPos, sPmtCornerPos, 0, reflect2); + PMTCornerTr2->RegisterYourself(); + TGeoRotation* reflect3 = new TGeoRotation(); + reflect3->ReflectX(true); + reflect3->ReflectY(true); + reflect3->RegisterYourself(); + TGeoCombiTrans* PMTCornerTr3 = new TGeoCombiTrans("PMTCornerTr3", -sPmtCornerPos, -sPmtCornerPos, 0, reflect3); + PMTCornerTr3->RegisterYourself(); + TGeoRotation* reflect4 = new TGeoRotation(); + reflect4->ReflectY(true); + reflect4->RegisterYourself(); + TGeoCombiTrans* PMTCornerTr4 = new TGeoCombiTrans("PMTCornerTr4", sPmtCornerPos, -sPmtCornerPos, 0, reflect4); + PMTCornerTr4->RegisterYourself(); + TGeoRotation* reflect5 = new TGeoRotation(); + reflect5->ReflectX(true); + reflect5->ReflectY(true); + reflect5->RegisterYourself(); + TGeoCombiTrans* edgeCornerTr = new TGeoCombiTrans("edgeCornerTr", sEdgeCornerPos[0], sEdgeCornerPos[1], 0, reflect5); + edgeCornerTr->RegisterYourself(); +} +//Transformations for plate elements +void Detector::definePlateTransformations() +{ + // TODO: redefine fiber head transformations + // TODO: move hard-coded numbers to be variables in the constants lists + // define transformations for the fiber heads in opticalFiberPlate1 + TGeoTranslation* opticalFiberHeadTr1 = new TGeoTranslation("opticalFiberHeadTr1", 1.7384, 1.36, 0); + opticalFiberHeadTr1->RegisterYourself(); + TGeoTranslation* opticalFiberHeadTr2 = new TGeoTranslation("opticalFiberHeadTr2", 1.7384, -1.36, 0); + opticalFiberHeadTr2->RegisterYourself(); + TGeoCombiTrans* opticalFiberHeadTr3 = new TGeoCombiTrans("opticalFiberHeadTr3", -0.9252, -.9375, 0, new TGeoRotation("rot3", 15, 0, 0)); + opticalFiberHeadTr3->RegisterYourself(); + TGeoCombiTrans* opticalFiberHeadTr4 = new TGeoCombiTrans("opticalFiberHeadTr4", -0.9252, .9375, 0, new TGeoRotation("rot4", -15, 0, 0)); + opticalFiberHeadTr4->RegisterYourself(); + + // make the transformations for the fiber heads in opticalFiberPlate2 + TGeoCombiTrans* opticalFiberHeadTr5 = new TGeoCombiTrans("opticalFiberHeadTr5", 1.6714, 1.525, 0, new TGeoRotation("rot5", 30, 0, 0)); + opticalFiberHeadTr5->RegisterYourself(); + TGeoCombiTrans* opticalFiberHeadTr6 = new TGeoCombiTrans("opticalFiberHeadTr6", 1.6714, -1.525, 0, new TGeoRotation("rot6", -30, 0, 0)); + opticalFiberHeadTr6->RegisterYourself(); + TGeoCombiTrans* opticalFiberHeadTr7 = new TGeoCombiTrans("opticalFiberHeadTr7", -0.9786, -1.125, 0, new TGeoRotation("rot7", 30, 0, 0)); + opticalFiberHeadTr7->RegisterYourself(); + TGeoCombiTrans* opticalFiberHeadTr8 = new TGeoCombiTrans("opticalFiberHeadTr8", -0.9786, 1.125, 0, new TGeoRotation("rot8", -30, 0, 0)); + opticalFiberHeadTr8->RegisterYourself(); + + // define transformations to form a plateBox (2 basicPlates and 2 cablePlates) + TGeoCombiTrans* basicPlateTr = new TGeoCombiTrans("basicPlateTr", 0, -sPlateSpacing, 0, new TGeoRotation("basicPlateRot", 90, 0, 0)); + basicPlateTr->RegisterYourself(); + TGeoCombiTrans* opticalFiberPlateTr1 = new TGeoCombiTrans("opticalFiberPlateTr1", 0, 0, sOpticalFiberPlateZ, new TGeoRotation("opticalFiberPlateRot1", 90, 0, 0)); + opticalFiberPlateTr1->RegisterYourself(); + TGeoCombiTrans* opticalFiberPlateTr2 = new TGeoCombiTrans("opticalFiberPlateTr2", 0, -sPlateSpacing, sOpticalFiberPlateZ, new TGeoRotation("opticalFiberPlateRot2", 90, 0, 0)); + opticalFiberPlateTr2->RegisterYourself(); + + // define transformations to form a plateGroup + TGeoTranslation* plateTr1 = new TGeoTranslation("plateTr1", -sPlateSpacing, sPlateDisplacementDeltaY, 0); + plateTr1->RegisterYourself(); + TGeoTranslation* plateTr2 = new TGeoTranslation("plateTr2", 0, 0, 0); + plateTr2->RegisterYourself(); + TGeoTranslation* plateTr3 = new TGeoTranslation("plateTr3", sPlateSpacing, 0, 0); + plateTr3->RegisterYourself(); + + // TODO: fix plateGroupTr2 + // TODO: Move hard-coded numbers to variables defined in the constants list + // define transformations for the plateGroups (6 basicPlates and 6 cablePlates) + TGeoTranslation* plateGroupTr1 = new TGeoTranslation("plateGroupTr1", sPlateDisplacementX, sPlateDisplacementY, sPlateGroupZ); + plateGroupTr1->RegisterYourself(); + TGeoCombiTrans* plateGroupTr2 = new TGeoCombiTrans("plateGroupTr2", 10.4358 + 1.5 * sPlateDisplacementDeltaY, -7.0747, sPlateGroupZ, new TGeoRotation("plateGroup2Rotation", -90, 0, 0)); + plateGroupTr2->RegisterYourself(); +} + +//Transformations for the L-shaped elements +void Detector::defineFrameTransformations() +{ + + // TODO: Confirm shifts that eliminate internal overlaps do not then cause + // overlaps with FV0 or other elements + // TODO: Move these hard-coded numbers to be variables in the list of constants + Float_t zshift = .2741; + Float_t rectShift = .274101; + Float_t frameXshift = -.1009; + + // position of the two rectangles used to approximate the L-shaped frame element + TGeoTranslation* frameTr1 = new TGeoTranslation("frameTr1", sFrame1PosX + frameXshift, sFrame1PosY, 0 + zshift); + frameTr1->RegisterYourself(); + TGeoTranslation* frameTr2 = new TGeoTranslation("frameTr2", sFrame2PosX + frameXshift, sFrame2PosY, 0 + zshift); + frameTr2->RegisterYourself(); + + // remove the two smaller rectangles from the L-shaped frame element + TGeoTranslation* rectTr1 = new TGeoTranslation("rectTr1", sFrame1PosX + sXoffset + frameXshift + 3.25, sFrame1PosY + sYoffset + 6.1875, 0 + zshift); + rectTr1->RegisterYourself(); + + TGeoTranslation* rectTr2 = new TGeoTranslation("rectTr2", sFrame1PosX + sXoffset + frameXshift + 9.3, sFrame1PosY + sYoffset - 0.5775, sMountZ / 2 + zshift); + rectTr2->RegisterYourself(); + + TGeoTranslation* rectTr3 = new TGeoTranslation("rectTr3", sFrame1PosX + sXoffset + frameXshift + 10.75 - sRect3X / 2, sFrame1PosY + sYoffset - 6.8525 + sRect3Y / 2, 0 + zshift); + rectTr3->RegisterYourself(); + + TGeoTranslation* rectTr4 = new TGeoTranslation("rectTr4", sFrame1PosX + sXoffset + frameXshift - 7.925, sFrame1PosY + sYoffset - 6.44, 0 + zshift + 10); + rectTr4->RegisterYourself(); + + TGeoTranslation* rectTr5 = new TGeoTranslation("rectTr5", sFrame2PosX + sXoffset + frameXshift + 6.965 + sRect5X / 2, sFrame2PosY + sYoffset + 4.3625 - sRect5Y / 2, 0 + zshift + rectShift); + rectTr5->RegisterYourself(); + + TGeoTranslation* rectTr6 = new TGeoTranslation("rectTr6", sFrame2PosX + sXoffset + frameXshift + 6.965 - sRect6X / 2, sFrame2PosY + sYoffset - 10.7375 + sRect6Y / 2, 0 + zshift); + rectTr6->RegisterYourself(); + + TGeoTranslation* rectTr7 = new TGeoTranslation("rectTr7", sFrame2PosX + sXoffset + frameXshift + 6.965 - sRect6X - sRect7X / 2, sFrame2PosY + sYoffset - 10.7375 + sRect7Y / 2, sMountZ / 2 + zshift); + rectTr7->RegisterYourself(); + + TGeoTranslation* rectTr8 = new TGeoTranslation("rectTr8", sFrame2PosX + sXoffset + frameXshift - 5.89 - sRect8X / 2, sFrame2PosY + sYoffset + 5.1125 + sRect8Y / 2, 0 + zshift); + rectTr8->RegisterYourself(); +} + Bool_t Detector::ProcessHits(FairVolume* v) { @@ -351,7 +885,7 @@ Bool_t Detector::ProcessHits(FairVolume* v) fMC->CurrentVolOffID(1, mcp); float time = fMC->TrackTime() * 1.0e9; //time from seconds to ns int trackID = stack->GetCurrentTrackNumber(); - int detID = 4 * mcp + quadrant - 1; + int detID = mSim2LUT[4 * mcp + quadrant - 1]; float etot = fMC->Etot(); int iPart = fMC->TrackPid(); float enDep = fMC->Edep(); @@ -371,7 +905,6 @@ Bool_t Detector::ProcessHits(FairVolume* v) if (volname.Contains("0MTO")) { if (trackID != mTrackIdTop) { if (!RegisterPhotoE(etot)) { - // std::cout<<" брысь "<<etot<<" track "<<trackID<<" parentID "<<parentID<<" "<<volname<<std::endl; fMC->StopTrack(); return kFALSE; } @@ -443,33 +976,60 @@ void Detector::CreateMaterials() Float_t aglass[2] = {28.0855, 15.9994}; Float_t zglass[2] = {14., 8.}; Float_t wglass[2] = {1., 2.}; - Float_t dglass = 2.65; + Float_t dglass = 2.2; // MCP glass SiO2 Float_t dglass_mcp = 1.3; - // Ceramic 97.2% Al2O3 , 2.8% SiO2 + /* Ceramic 97.2% Al2O3 , 2.8% SiO2 : average material for + - stack of 2 MCPs thickness 2mm with density 1.6 g/cm3 + - back wall of MCP thickness 2 mm with density 2.4 g/cm3 + - MCP electrods thickness 1 mm with density 4.2 g/cm3 + - Backplane PCBs thickness 4.5 mm with density 1.85 g/cm3 + - electromagnetic shielding 1 mm with density 2.8 g/cm3 + - Al back cover 5mm 2.7 g/cm3 + */ Float_t aCeramic[2] = {26.981539, 15.9994}; Float_t zCeramic[2] = {13., 8.}; Float_t wCeramic[2] = {2., 3.}; - Float_t denscer = 3.6; + Float_t denscer = 2.37; + + //MCP walls Ceramic+Nickel (50//50) + const Int_t nCeramicNice = 3; + Float_t aCeramicNicel[3] = {26.981539, 15.9994, 58.6934}; + Float_t zCeramicNicel[3] = {13., 8., 28}; + Float_t wCeramicNicel[3] = {0.2, 0.3, 0.5}; + Float_t denscerCeramicNickel = 5.6; + + //Mixed Cables material simulated as plastic with density taken from description of Low Loss Microwave Coax24 AWG 0 + // plastic + cooper (6%) + const Int_t nPlast = 4; + Float_t aPlast[nPlast] = {1.00784, 12.0107, 15.999, 63.54}; + Float_t zPlast[nPlast] = {1, 6, 8, 29}; + Float_t wPlast[nPlast] = {0.08, 0.53, 0.22, 0.17}; ////!!!!! + const Float_t denCable = 3.66; + //*** Definition Of avaible FIT materials *** Material(11, "Aliminium$", 26.98, 13.0, 2.7, 8.9, 999); Mixture(1, "Vacuum$", aAir, zAir, dAir1, 4, wAir); Mixture(2, "Air$", aAir, zAir, dAir, 4, wAir); Mixture(4, "MCP glass $", aglass, zglass, dglass_mcp, -2, wglass); Mixture(24, "Radiator Optical glass$", aglass, zglass, dglass, -2, wglass); - Mixture(3, "Ceramic $", aCeramic, zCeramic, denscer, -2, wCeramic); + Mixture(3, "Ceramic$", aCeramic, zCeramic, denscer, -2, wCeramic); + Mixture(23, "CablePlasticCooper$", aPlast, zPlast, denCable, 4, wPlast); + Mixture(25, "MCPwalls $", aCeramicNicel, zCeramicNicel, denscerCeramicNickel, 3, wCeramicNicel); Medium(1, "Air$", 2, 0, isxfld, sxmgmx, 10., .1, 1., .003, .003); Medium(3, "Vacuum$", 1, 0, isxfld, sxmgmx, 10., .01, .1, .003, .003); Medium(4, "Ceramic$", 3, 0, isxfld, sxmgmx, 10., .01, .1, .003, .003); Medium(6, "Glass$", 4, 0, isxfld, sxmgmx, 10., .01, .1, .003, .003); - Medium(7, "OpAir$", 2, 0, isxfld, sxmgmx, 10., .1, 1., .003, .003); - Medium(18, "OpBlack$", 2, 0, isxfld, sxmgmx, 10., .1, 1., .003, .003); + // Medium(7, "OpAir$", 2, 0, isxfld, sxmgmx, 10., .1, 1., .003, .003); + // Medium(18, "OpBlack$", 2, 0, isxfld, sxmgmx, 10., .1, 1., .003, .003); Medium(15, "Aluminium$", 11, 0, isxfld, sxmgmx, 10., .01, 1., .003, .003); Medium(17, "OptAluminium$", 11, 0, isxfld, sxmgmx, 10., .01, 1., .003, .003); Medium(16, "OpticalGlass$", 24, 1, isxfld, sxmgmx, 10., .01, .1, .003, .01); Medium(19, "OpticalGlassCathode$", 24, 1, isxfld, sxmgmx, 10., .01, .1, .003, .003); - Medium(22, "SensAir$", 2, 1, isxfld, sxmgmx, 10., .1, 1., .003, .003); + // Medium(22, "SensAir$", 2, 1, isxfld, sxmgmx, 10., .1, 1., .003, .003); + Medium(23, "Cables$", 23, 1, isxfld, sxmgmx, 10., .1, 1., .003, .003); + Medium(25, "MCPWalls", 25, 1, isxfld, sxmgmx, 10., .1, 1., .003, .003); } //------------------------------------------------------------------- @@ -640,3 +1200,30 @@ Int_t Detector::ReadOptProperties(const std::string filePath) LOG(INFO) << "Optical properties taken from the file: " << filePath.c_str() << " Number of lines read: " << iLine; return 0; } + +void Detector::DefineSim2LUTindex() +{ + // Path of the LookUp table + std::string inputDir; + const char* aliceO2env = std::getenv("O2_ROOT"); + if (aliceO2env) { + inputDir = aliceO2env; + } + inputDir += "/share/Detectors/FT0/files/"; + + std::string indPath = inputDir + "Sim2DataChannels.txt"; + indPath = gSystem->ExpandPathName(indPath.data()); // Expand $(ALICE_ROOT) into real system path + + std::ifstream infile; + infile.open(indPath.data()); + LOG(INFO) << " file open " << indPath.data(); + // Check if file is opened correctly + if (infile.fail() == true) { + LOG(ERROR) << "Error opening ascii file (it is probably a folder!): " << indPath.c_str(); + } + int fromfile; + for (int iind = 0; iind < Geometry::Nchannels; iind++) { + infile >> fromfile; + mSim2LUT[iind] = fromfile; + } +} diff --git a/Detectors/FIT/FT0/simulation/src/Digitizer.cxx b/Detectors/FIT/FT0/simulation/src/Digitizer.cxx index 3cde3b5b42ef6..359e54323d68b 100644 --- a/Detectors/FIT/FT0/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FT0/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "FT0Simulation/Digitizer.h" #include "FT0Simulation/DigitizationConstants.h" +#include "FT0Simulation/DigitizationParameters.h" #include "SimulationDataFormat/MCTruthContainer.h" #include <CommonDataFormat/InteractionRecord.h> @@ -20,12 +22,49 @@ #include <cassert> #include <iostream> #include <optional> +#include <Vc/Vc> using namespace o2::ft0; -//using o2::ft0::Geometry; ClassImp(Digitizer); +namespace o2::ft0 +{ +// signal shape function +template <typename Float> +Float signalForm_i(Float x) +{ + using namespace std; + Float const a = -0.45458; + Float const b = -0.83344945; + return x > Float(0) ? -(exp(b * x) - exp(a * x)) / Float(7.8446501) : Float(0); +}; + +// integrated signal shape function +inline float signalForm_integral(float x) +{ + using namespace std; + double const a = -0.45458; + double const b = -0.83344945; + if (x < 0) { + x = 0; + } + return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501; +}; + +// SIMD version of the integrated signal shape function +inline Vc::float_v signalForm_integralVc(Vc::float_v x) +{ + auto const mask = (x >= 0.0f); + Vc::float_v arg(0); + arg.assign(x, mask); // branchless if + Vc::float_v const a(-0.45458f); + Vc::float_v const b(-0.83344945f); + Vc::float_v result = -(Vc::exp(b * arg) / b - Vc::exp(a * arg) / a) / 7.8446501f; + return result; +}; +} // namespace o2::ft0 + Digitizer::CFDOutput Digitizer::get_time(const std::vector<float>& times, float deadTime) { assert(std::is_sorted(std::begin(times), std::end(times))); @@ -56,7 +95,7 @@ Digitizer::CFDOutput Digitizer::get_time(const std::vector<float>& times, float } // (2) add noise // find the right indices into the sinc table - int timeIndex = std::lround(time / mParameters.mNoisePeriod * mSincTable.size()); + int timeIndex = std::lround(time / DigitizationParameters::Instance().mNoisePeriod * mSincTable.size()); int timeOffset = timeIndex / mSincTable.size(); timeIndex %= mSincTable.size(); if (timeOffset >= mNumNoiseSamples) { // this happens when time >= 25 ns @@ -90,32 +129,32 @@ Digitizer::CFDOutput Digitizer::get_time(const std::vector<float>& times, float }; auto const min_time = std::max(deadTime, *std::min_element(std::begin(times), std::end(times))); - CFDOutput result{std::nullopt, -0.5f * mParameters.bunchWidth}; + CFDOutput result{std::nullopt, -0.5f * DigitizationParameters::Instance().mBunchWidth}; bool is_positive = true; // reset the chache std::fill_n(std::begin(mSignalCache), std::size(mSignalCache), -1.0f); - + const auto& params = DigitizationParameters::Instance(); // we need double precision for time in order to match previous behaviour - for (double time = min_time; time < 0.5 * mParameters.bunchWidth; time += DP::SIGNAL_CACHE_DT) { + for (double time = min_time; time < 0.5 * params.mBunchWidth; time += DP::SIGNAL_CACHE_DT) { float const val = value_at(time); - int const index = std::lround((time + 0.5 * mParameters.bunchWidth) / DP::SIGNAL_CACHE_DT); + int const index = std::lround((time + 0.5 * params.mBunchWidth) / DP::SIGNAL_CACHE_DT); if (index >= 0 && index < mSignalCache.size()) { // save the value for later use mSignalCache[index] = val; } // look up the time-shifted signal value from the past float val_prev = 0.0f; - int const index_prev = std::lround((time - mParameters.mCFDShiftPos + 0.5f * mParameters.bunchWidth) / DP::SIGNAL_CACHE_DT); + int const index_prev = std::lround((time - params.mCFDShiftPos + 0.5f * params.mBunchWidth) / DP::SIGNAL_CACHE_DT); val_prev = ((index_prev < 0 || index_prev >= mSignalCache.size() || mSignalCache[index_prev] < 0.0f) - ? value_at(time - mParameters.mCFDShiftPos) // was not computed before - : mSignalCache[index_prev]); // is available in the cache + ? value_at(time - params.mCFDShiftPos) // was not computed before + : mSignalCache[index_prev]); // is available in the cache float const cfd_val = 5.0f * val_prev - val; - if (std::abs(val) > mParameters.mCFD_trsh && !is_positive && cfd_val > 0.0f) { + if (std::abs(val) > params.mCFD_trsh && !is_positive && cfd_val > 0.0f) { if (!result.particle) { result.particle = time; } - result.deadTime = time + mParameters.mCFDdeadTime; - time += mParameters.mCFDdeadTime - DP::SIGNAL_CACHE_DT; + result.deadTime = time + params.mCFDdeadTime; + time += params.mCFDdeadTime - DP::SIGNAL_CACHE_DT; is_positive = true; } else { is_positive = cfd_val > 0.0f; @@ -126,8 +165,8 @@ Digitizer::CFDOutput Digitizer::get_time(const std::vector<float>& times, float double Digitizer::measure_amplitude(const std::vector<float>& times) const { - float const from = mParameters.mAmpRecordLow; - float const to = from + mParameters.mAmpRecordUp; + float const from = DigitizationParameters::Instance().mAmpRecordLow; + float const to = from + DigitizationParameters::Instance().mAmpRecordUp; // SIMD version has a negligible effect on the total wall time Vc::float_v acc(0); Vc::float_v tv(0); @@ -150,13 +189,14 @@ double Digitizer::measure_amplitude(const std::vector<float>& times) const void Digitizer::process(const std::vector<o2::ft0::HitType>* hits, std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& label) { ; //Calculating signal time, amplitude in mean_time +- time_gate -------------- LOG(DEBUG) << " process firstBCinDeque " << firstBCinDeque << " mIntRecord " << mIntRecord; if (firstBCinDeque != mIntRecord) { - flush(digitsBC, digitsCh, label); + flush(digitsBC, digitsCh, digitsTrig, label); } Int_t parent = -10; @@ -164,12 +204,12 @@ void Digitizer::process(const std::vector<o2::ft0::HitType>* hits, if (hit.GetEnergyLoss() > 0) { continue; } - + const auto& params = DigitizationParameters::Instance(); Int_t hit_ch = hit.GetDetectorID(); - Bool_t is_A_side = (hit_ch < 4 * mParameters.nCellsA); - Float_t time_compensate = is_A_side ? mParameters.A_side_cable_cmps : mParameters.C_side_cable_cmps; + Bool_t is_A_side = (hit_ch < 4 * mGeometry.NCellsA); + Float_t time_compensate = is_A_side ? params.mA_side_cable_cmps : params.mC_side_cable_cmps; Double_t hit_time = hit.GetTime() - time_compensate; - if (hit_time > 250) { + if (hit_time > 150) { continue; //not collect very slow particles } auto relBC = o2::InteractionRecord{hit_time}; @@ -189,6 +229,7 @@ void Digitizer::process(const std::vector<o2::ft0::HitType>* hits, void Digitizer::storeBC(BCCache& bc, std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& labels) { if (bc.hits.empty()) { @@ -197,17 +238,17 @@ void Digitizer::storeBC(BCCache& bc, int n_hit_A = 0, n_hit_C = 0, mean_time_A = 0, mean_time_C = 0; int summ_ampl_A = 0, summ_ampl_C = 0; int vertex_time; - + const auto& params = DigitizationParameters::Instance(); int first = digitsCh.size(), nStored = 0; auto& particles = bc.hits; std::sort(std::begin(particles), std::end(particles)); auto channel_end = particles.begin(); std::vector<float> channel_times; - for (Int_t ipmt = 0; ipmt < mParameters.mMCPs; ++ipmt) { + for (Int_t ipmt = 0; ipmt < params.mMCPs; ++ipmt) { auto channel_begin = channel_end; channel_end = std::find_if(channel_begin, particles.end(), [ipmt](BCCache::particle const& p) { return p.hit_ch != ipmt; }); - if (channel_end - channel_begin < mParameters.mAmp_trsh) { + if (channel_end - channel_begin < params.mAmp_trsh) { continue; } channel_times.resize(channel_end - channel_begin); @@ -222,10 +263,10 @@ void Digitizer::storeBC(BCCache& bc, if (!cfd.particle) { continue; } - int smeared_time = 1000. * (*cfd.particle - mParameters.mCfdShift) * mParameters.ChannelWidthInverse; - bool is_time_in_signal_gate = (smeared_time > -mParameters.mTime_trg_gate && smeared_time < mParameters.mTime_trg_gate); - float charge = measure_amplitude(channel_times) * mParameters.charge2amp; - float amp = is_time_in_signal_gate ? mParameters.mV_2_Nchannels * charge : 0; + int smeared_time = 1000. * (*cfd.particle - params.mCfdShift) * params.mChannelWidthInverse; + bool is_time_in_signal_gate = (smeared_time > -params.mTime_trg_gate && smeared_time < params.mTime_trg_gate); + float charge = measure_amplitude(channel_times) * params.mCharge2amp; + float amp = is_time_in_signal_gate ? params.mMV_2_Nchannels * charge : 0; if (amp > 4095) { amp = 4095; } @@ -235,7 +276,7 @@ void Digitizer::storeBC(BCCache& bc, // fill triggers - Bool_t is_A_side = (ipmt <= 4 * mParameters.nCellsA); + Bool_t is_A_side = (ipmt < 4 * mGeometry.NCellsA); if (!is_time_in_signal_gate) { continue; } @@ -253,21 +294,21 @@ void Digitizer::storeBC(BCCache& bc, Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0; is_A = n_hit_A > 0; is_C = n_hit_C > 0; - is_Central = summ_ampl_A + summ_ampl_C >= mParameters.mtrg_central_trh; - is_SemiCentral = summ_ampl_A + summ_ampl_C >= mParameters.mtrg_semicentral_trh; - vertex_time = (mean_time_A - mean_time_C) * 0.5; - isVertex = is_A && is_C && (vertex_time > -mParameters.mTime_trg_gate && vertex_time < mParameters.mTime_trg_gate); + is_Central = summ_ampl_A + summ_ampl_C >= params.mtrg_central_trh; + is_SemiCentral = summ_ampl_A + summ_ampl_C >= params.mtrg_semicentral_trh; uint32_t amplA = is_A ? summ_ampl_A * 0.125 : 0; // sum amplitude A side / 8 (hardware) uint32_t amplC = is_C ? summ_ampl_C * 0.125 : 0; // sum amplitude C side / 8 (hardware) uint16_t timeA = is_A ? mean_time_A / n_hit_A : 0; // average time A side uint16_t timeC = is_C ? mean_time_C / n_hit_C : 0; // average time C side + vertex_time = (timeC - timeA) * 0.5; + isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_gate && vertex_time < params.mTime_trg_gate); Triggers triggers; if (nStored > 0) { triggers.setTriggers(is_A, is_C, isVertex, is_Central, is_SemiCentral, int8_t(n_hit_A), int8_t(n_hit_C), amplA, amplC, timeA, timeC); - digitsBC.emplace_back(first, nStored, firstBCinDeque, triggers, mEventID - 1); + digitsTrig.emplace_back(firstBCinDeque, is_A, is_C, isVertex, is_Central, is_SemiCentral); size_t const nBC = digitsBC.size(); for (auto const& lbl : bc.labels) { labels.addElement(nBC - 1, lbl); @@ -286,13 +327,14 @@ void Digitizer::storeBC(BCCache& bc, //------------------------------------------------------------------------ void Digitizer::flush(std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& labels) { assert(firstBCinDeque <= mIntRecord); while (firstBCinDeque < mIntRecord && !mCache.empty()) { - storeBC(mCache.front(), digitsBC, digitsCh, labels); + storeBC(mCache.front(), digitsBC, digitsCh, digitsTrig, labels); mCache.pop_front(); ++firstBCinDeque; } @@ -301,13 +343,14 @@ void Digitizer::flush(std::vector<o2::ft0::Digit>& digitsBC, void Digitizer::flush_all(std::vector<o2::ft0::Digit>& digitsBC, std::vector<o2::ft0::ChannelData>& digitsCh, + std::vector<o2::ft0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>& labels) { assert(firstBCinDeque <= mIntRecord); ++mEventID; while (!mCache.empty()) { - storeBC(mCache.front(), digitsBC, digitsCh, labels); + storeBC(mCache.front(), digitsBC, digitsCh, digitsTrig, labels); mCache.pop_front(); ++firstBCinDeque; } @@ -318,33 +361,35 @@ void Digitizer::initParameters() auto const sinc = [](double x) { x *= TMath::Pi(); return (std::abs(x) < 1e-12) ? 1.0 : std::sin(x) / x; }; // number of noise samples in one BC - mNumNoiseSamples = std::ceil(mParameters.bunchWidth / mParameters.mNoisePeriod); + const auto& params = DigitizationParameters::Instance(); + mNumNoiseSamples = std::ceil(params.mBunchWidth / params.mNoisePeriod); mNoiseSamples.resize(mNumNoiseSamples); // set up tables with sinc function values (times noiseVar) for (size_t i = 0, n = mSincTable.size(); i < n; ++i) { - float const time = i / float(n) * mParameters.mNoisePeriod; // [0 .. 1/mParameters.mNoisePeriod) + float const time = i / float(n) * params.mNoisePeriod; // [0 .. 1/params.mNoisePeriod) LOG(DEBUG) << "initParameters " << i << "/" << n << " " << time; // we make a table of sinc values between -num_noise_samples and 2*num_noise_samples mSincTable[i].resize(3 * mNumNoiseSamples); for (int j = -mNumNoiseSamples; j < 2 * mNumNoiseSamples; ++j) { - mSincTable[i][mNumNoiseSamples + j] = mParameters.mNoiseVar * sinc((time + 0.5f * mParameters.bunchWidth) / mParameters.mNoisePeriod - j); + mSincTable[i][mNumNoiseSamples + j] = params.mNoiseVar * sinc((time + 0.5f * params.mBunchWidth) / params.mNoisePeriod - j); } } // set up the lookup table for the signal form for (size_t i = 0; i < DP::SIGNAL_TABLE_SIZE; ++i) { - float const x = float(i) / float(DP::SIGNAL_TABLE_SIZE) * mParameters.bunchWidth; + float const x = float(i) / float(DP::SIGNAL_TABLE_SIZE) * params.mBunchWidth; mSignalTable[i] = signalForm_i(x); } // cache for signal time series used by the CFD -BC/2 .. +3BC/2 - mSignalCache.resize(std::lround(mParameters.bunchWidth / DP::SIGNAL_CACHE_DT)); + mSignalCache.resize(std::lround(params.mBunchWidth / DP::SIGNAL_CACHE_DT)); } //_______________________________________________________________________ void Digitizer::init() { LOG(INFO) << " @@@ Digitizer::init " << std::endl; mDeadTimes.fill({InteractionRecord(0), -100.}); + printParameters(); } //_______________________________________________________________________ void Digitizer::finish() @@ -354,11 +399,14 @@ void Digitizer::finish() void Digitizer::printParameters() const { + const auto& params = DigitizationParameters::Instance(); LOG(INFO) << " Run Digitzation with parametrs: \n" - << " CFD amplitude threshold \n " << mParameters.mCFD_trsh << " CFD signal gate in ps \n" - << mParameters.mTime_trg_gate << "shift to have signal around zero after CFD trancformation \n" - << mParameters.mCfdShift << "CFD distance between 0.3 of max amplitude to max \n" - << mParameters.mCFDShiftPos << "MIP -> mV " << mParameters.mMip_in_V << " Pe in MIP \n" - << mParameters.mPe_in_mip << "noise level " << mParameters.mNoiseVar << " noise frequency \n" - << mParameters.mNoisePeriod << std::endl; + << " CFD amplitude threshold \n " << params.mCFD_trsh << " CFD signal gate in ps \n" + << params.mTime_trg_gate << "shift to have signal around zero after CFD trancformation \n" + << params.mCfdShift << "CFD distance between 0.3 of max amplitude to max \n" + << params.mCFDShiftPos << "MIP -> mV " << params.mMip_in_V << " Pe in MIP \n" + << params.mPe_in_mip << "noise level " << params.mNoiseVar << " noise frequency \n" + << params.mNoisePeriod << " mMCPs " << params.mMCPs; } + +O2ParamImpl(DigitizationParameters); diff --git a/Detectors/FIT/FT0/simulation/src/DigitizerTask.cxx b/Detectors/FIT/FT0/simulation/src/DigitizerTask.cxx index a75c3474127b0..7e325294e7032 100644 --- a/Detectors/FIT/FT0/simulation/src/DigitizerTask.cxx +++ b/Detectors/FIT/FT0/simulation/src/DigitizerTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/simulation/src/Digits2Raw.cxx b/Detectors/FIT/FT0/simulation/src/Digits2Raw.cxx index d564780137f2e..d47c784c8abda 100644 --- a/Detectors/FIT/FT0/simulation/src/Digits2Raw.cxx +++ b/Detectors/FIT/FT0/simulation/src/Digits2Raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ RDH + Event header + event data, 2 channels per 1 GBT word; if no data for this PM - only headers. Trigger mode : detector sends data to FLP at each trigger; -Continueous mode : for only bunches with data at least in 1 channel. +Continueous mode : for only bunches with data at least in 1 channel. */ #include "Headers/RAWDataHeader.h" @@ -46,8 +47,11 @@ Continueous mode : for only bunches with data at least in 1 channel. #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RawFileWriter.h" #include "CommonUtils/StringUtils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" #include <Framework/Logger.h> #include <TStopwatch.h> +#include <TSystem.h> #include <cassert> #include <fstream> #include <vector> @@ -58,6 +62,7 @@ Continueous mode : for only bunches with data at least in 1 channel. #include <gsl/span> using namespace o2::ft0; +using CcdbManager = o2::ccdb::BasicCCDBManager; ClassImp(Digits2Raw); @@ -71,23 +76,36 @@ Digits2Raw::Digits2Raw(const std::string& fileRaw, const std::string& fileDigits void Digits2Raw::readDigits(const std::string& outDir, const std::string& fileDigitsName) { LOG(INFO) << "**********Digits2Raw::convertDigits" << std::endl; + mWriter.setCarryOverCallBack(this); - o2::ft0::LookUpTable lut{o2::ft0::Digits2Raw::linear()}; - LOG(DEBUG) << " ##### LookUp set "; - + o2::ft0::LookUpTable lut{o2::ft0::LookUpTable::readTable()}; + mLinkTCM = lut.getLink(lut.getTCMchannel()); + LOG(INFO) << " ##### LookUp set, TCM " << mLinkTCM; std::string outd = outDir; if (outd.back() != '/') { outd += '/'; } using namespace o2::raw; - for (int ilink = 0; ilink < NPMs; ++ilink) { - mLinkID = uint32_t(ilink); - mFeeID = uint64_t(ilink); - mCruID = uint16_t(0); - mEndPointID = uint32_t(0); - std::string outFileLink = mOutputPerLink ? o2::utils::concat_string(outDir, "ft0_link", std::to_string(ilink), ".raw") : o2::utils::concat_string(outDir, "ft0.raw"); + for (int ilink = 0; ilink < NPMs - 1; ++ilink) { + if (ilink < 8) { + mLinkID = uint32_t(ilink); + mCruID = uint16_t(0); + mEndPointID = uint32_t(0); + mFeeID = uint64_t(ilink); + } else { + mLinkID = uint32_t(ilink) - 8; + mCruID = uint16_t(0); + mEndPointID = uint32_t(1); + mFeeID = uint64_t(ilink); + } + std::string outFileLink = mOutputPerLink ? o2::utils::Str::concat_string(outDir, "ft0_link", std::to_string(ilink), ".raw") : o2::utils::Str::concat_string(outDir, "ft0.raw"); mWriter.registerLink(mFeeID, mCruID, mLinkID, mEndPointID, outFileLink); + LOG(INFO) << " registered links " << mLinkID << " endpoint " << mEndPointID; } + //TCM + std::string outFileLink = mOutputPerLink ? o2::utils::Str::concat_string(outDir, "ft0_link", std::to_string(NPMs - 1), ".raw") : o2::utils::Str::concat_string(outDir, "ft0.raw"); + mWriter.registerLink(mLinkTCM + 8, mCruID, mLinkTCM, 0, outFileLink); + LOG(INFO) << " registered link TCM " << mLinkTCM; TFile* fdig = TFile::Open(fileDigitsName.data()); assert(fdig != nullptr); @@ -109,7 +127,7 @@ void Digits2Raw::readDigits(const std::string& outDir, const std::string& fileDi digTree->GetEntry(ient); int nbc = digitsBC.size(); - LOG(DEBUG) << "Entry " << ient << " : " << nbc << " BCs stored"; + LOG(INFO) << "Entry " << ient << " : " << nbc << " BCs stored"; for (int ibc = 0; ibc < nbc; ibc++) { auto& bcd = digitsBC[ibc]; intRecord = bcd.getIntRecord(); @@ -129,14 +147,16 @@ void Digits2Raw::convertDigits(o2::ft0::Digit bcdigits, // check empty event int oldlink = -1; + int oldendpoint = -1; int nchannels = 0; int nch = pmchannels.size(); for (int ich = 0; ich < nch; ich++) { int nlink = lut.getLink(pmchannels[ich].ChId); - if (nlink != oldlink) { + int ep = lut.getEP(pmchannels[ich].ChId); + if (nlink != oldlink || ep != oldendpoint) { if (oldlink >= 0) { uint nGBTWords = uint((nchannels + 1) / 2); - LOG(DEBUG) << " oldlink " << oldlink << " nGBTWords " << nGBTWords; + LOG(DEBUG) << " oldlink " << oldlink << " old EP " << oldendpoint << " nGBTWords " << nGBTWords << " new link " << nlink << " ep " << ep; if ((nchannels % 2) == 1) { mRawEventData.mEventData[nchannels] = {}; } @@ -144,12 +164,18 @@ void Digits2Raw::convertDigits(o2::ft0::Digit bcdigits, auto data = mRawEventData.to_vector(false); mLinkID = uint32_t(oldlink); mFeeID = uint64_t(oldlink); + mEndPointID = uint32_t(oldendpoint); + if (mEndPointID == 1) { + mFeeID += 8; + } + LOG(DEBUG) << " new link start " << mFeeID << " " << mCruID << " " << mLinkID << " " << mEndPointID; mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, intRecord, data); } oldlink = nlink; + oldendpoint = ep; mRawEventData.mEventHeader = makeGBTHeader(nlink, intRecord); nchannels = 0; - // LOG(INFO) << " switch to new link " << nlink; + LOG(DEBUG) << " switch to new link " << nlink << " EP " << ep; } auto& newData = mRawEventData.mEventData[nchannels]; bool isAside = (pmchannels[ich].ChId < 96); @@ -157,7 +183,8 @@ void Digits2Raw::convertDigits(o2::ft0::Digit bcdigits, newData.time = pmchannels[ich].CFDTime; newData.generateFlags(); newData.channelID = lut.getMCP(pmchannels[ich].ChId); - LOG(DEBUG) << "packed GBT " << nlink << " channelID " << (int)newData.channelID << " charge " << newData.charge << " time " << newData.time << " chain " << int(newData.numberADC) << " size " << sizeof(newData); + LOG(DEBUG) << " ID " << int(pmchannels[ich].ChId) << " packed GBT " << nlink << " channelID " << (int)newData.channelID << " charge " << newData.charge << " time " << newData.time << " chain " << int(newData.numberADC) + << " size " << sizeof(newData) << " mEndPointID " << ep; nchannels++; } // fill mEventData[nchannels] with 0s to flag that this is a dummy data @@ -169,10 +196,14 @@ void Digits2Raw::convertDigits(o2::ft0::Digit bcdigits, auto datalast = mRawEventData.to_vector(false); mLinkID = uint32_t(oldlink); mFeeID = uint64_t(oldlink); + mEndPointID = uint32_t(oldendpoint); + if (mEndPointID == 1) { + mFeeID += 8; + } mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, intRecord, datalast); - LOG(DEBUG) << " last " << oldlink; + LOG(DEBUG) << " last " << mFeeID << " " << mCruID << " " << mLinkID << " " << mEndPointID; //TCM - mRawEventData.mEventHeader = makeGBTHeader(LinkTCM, intRecord); //TCM + mRawEventData.mEventHeader = makeGBTHeader(mLinkTCM, intRecord); //TCM mRawEventData.mEventHeader.nGBTWords = 1; auto& tcmdata = mRawEventData.mTCMdata; mTriggers = bcdigits.getTriggers(); @@ -196,26 +227,27 @@ void Digits2Raw::convertDigits(o2::ft0::Digit bcdigits, tcmdata.amplC = ampC; tcmdata.timeA = mTriggers.timeA; tcmdata.timeC = mTriggers.timeC; - if (mVerbosity > 0) { - LOG(INFO) << " triggers read " - << " time A " << mTriggers.timeA << " time C " << mTriggers.timeC - << " amp A " << ampA << " amp C " << ampC - << " N A " << int(mTriggers.nChanA) << " N C " << int(mTriggers.nChanC) - << " trig " - << " ver " << mTriggers.getVertex() << " A " << mTriggers.getOrA() << " C " << mTriggers.getOrC(); - - LOG(INFO) << "TCMdata" - << " time A " << tcmdata.timeA << " time C " << tcmdata.timeC - << " amp A " << tcmdata.amplA << " amp C " << tcmdata.amplC - << " N A " << int(tcmdata.nChanA) << " N C " << int(tcmdata.nChanC) - << " trig " - << " ver " << tcmdata.vertex << " A " << tcmdata.orA << " C " << tcmdata.orC - << " size " << sizeof(tcmdata); - } + LOG(DEBUG) << " TCM triggers read " + << " time A " << mTriggers.timeA << " time C " << mTriggers.timeC + << " amp A " << ampA << " amp C " << ampC + << " N A " << int(mTriggers.nChanA) << " N C " << int(mTriggers.nChanC) + << " trig " + << " ver " << mTriggers.getVertex() << " A " << mTriggers.getOrA() << " C " << mTriggers.getOrC(); + + LOG(DEBUG) << "TCMdata" + << " time A " << tcmdata.timeA << " time C " << tcmdata.timeC + << " amp A " << tcmdata.amplA << " amp C " << tcmdata.amplC + << " N A " << int(tcmdata.nChanA) << " N C " << int(tcmdata.nChanC) + << " trig " + << " ver " << tcmdata.vertex << " A " << tcmdata.orA << " C " << tcmdata.orC + << " size " << sizeof(tcmdata); + auto data = mRawEventData.to_vector(1); - mLinkID = uint32_t(LinkTCM); - mFeeID = uint64_t(LinkTCM); + mLinkID = uint32_t(mLinkTCM); + mFeeID = uint64_t(mLinkTCM) + 8; + mEndPointID = 0; mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, intRecord, data); + LOG(DEBUG) << " TCM " << mFeeID << " " << mCruID << " " << mLinkID << " " << mEndPointID; } //_____________________________________________________________________________________ @@ -232,3 +264,11 @@ EventHeader Digits2Raw::makeGBTHeader(int link, o2::InteractionRecord const& mIn } return mEventHeader; } + +//_____________________________________________________________________________________ +int Digits2Raw::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const +{ + return 0; // do not split, always start new CRU page +} diff --git a/Detectors/FIT/FT0/simulation/src/FT0SimulationLinkDef.h b/Detectors/FIT/FT0/simulation/src/FT0SimulationLinkDef.h index c8e02eaabdac5..14f54600b80cf 100644 --- a/Detectors/FIT/FT0/simulation/src/FT0SimulationLinkDef.h +++ b/Detectors/FIT/FT0/simulation/src/FT0SimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/simulation/src/digi2raw.cxx b/Detectors/FIT/FT0/simulation/src/digi2raw.cxx index 71bfd0f7552b5..b87918142b628 100644 --- a/Detectors/FIT/FT0/simulation/src/digi2raw.cxx +++ b/Detectors/FIT/FT0/simulation/src/digi2raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ /// \author ruben.shahoyan@cern.ch #include <boost/program_options.hpp> -#include <TSystem.h> +#include <filesystem> #include <TFile.h> #include <TStopwatch.h> #include "Framework/Logger.h" @@ -52,6 +53,7 @@ int main(int argc, char** argv) uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); opt_all.add(opt_general).add(opt_hidden); @@ -72,6 +74,11 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); digi2raw(vm["input-file"].as<std::string>(), vm["output-dir"].as<std::string>(), @@ -80,6 +87,8 @@ int main(int argc, char** argv) vm["rdh-version"].as<uint32_t>(), vm["no-empty-hbf"].as<bool>()); + o2::raw::HBFUtils::Instance().print(); + return 0; } @@ -98,21 +107,15 @@ void digi2raw(const std::string& inpName, const std::string& outDir, int verbosi wr.useRDHVersion(rdhV); wr.setDontFillEmptyHBF(noEmptyHBF); + o2::raw::assertOutputDirectory(outDir); + std::string outDirName(outDir); if (outDirName.back() != '/') { outDirName += '/'; } - // if needed, create output directory - if (gSystem->AccessPathName(outDirName.c_str())) { - if (gSystem->mkdir(outDirName.c_str(), kTRUE)) { - LOG(FATAL) << "could not create output directory " << outDirName; - } else { - LOG(INFO) << "created output directory " << outDirName; - } - } m2r.readDigits(outDirName, inpName); - wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); // swTot.Stop(); swTot.Print(); diff --git a/Detectors/FIT/FT0/simulation/src/digit2raw.cxx b/Detectors/FIT/FT0/simulation/src/digit2raw.cxx new file mode 100644 index 0000000000000..21759c6b2643b --- /dev/null +++ b/Detectors/FIT/FT0/simulation/src/digit2raw.cxx @@ -0,0 +1,134 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digit2raw.cxx +/// \author ruben.shahoyan@cern.ch afurs@cern.ch + +#include <boost/program_options.hpp> +#include <filesystem> +#include <TFile.h> +#include <TStopwatch.h> +#include "Framework/Logger.h" +#include <string> +#include <iomanip> +#include "CommonUtils/StringUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/HBFUtils.h" +#include "FT0Raw/RawWriterFT0.h" +#include "DataFormatsParameters/GRPObject.h" + +/// MC->raw conversion for FT0 + +namespace bpo = boost::program_options; + +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, + const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB = 1024 * 1024); + +int main(int argc, char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + "Convert FT0 digits to CRU raw data\n"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); + // add_option("input-file,i", bpo::value<std::string>()->default_value(o2::base::NameConf::getDigitsFileName(o2::detectors::DetID::FT0)),"input FT0 digits file"); // why not used? + add_option("input-file,i", bpo::value<std::string>()->default_value("ft0digits.root"), "input FT0 digits file"); + add_option("flp-name", bpo::value<std::string>()->default_value("alio2-cr1-flp180"), "single file per: all,flp,cru,link"); + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,flp,cru,link"); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); + uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); + add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); + add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + add_option("ccdb-path", bpo::value<std::string>()->default_value(""), "CCDB url which contains LookupTable"); + add_option("lut-path", bpo::value<std::string>()->default_value(""), "LookupTable path, e.g. FT0/LookupTable"); + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help")) { + std::cout << opt_general << std::endl; + exit(0); + } + + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + digit2raw(vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["verbosity"].as<int>(), + vm["file-for"].as<std::string>(), + vm["rdh-version"].as<uint32_t>(), + vm["no-empty-hbf"].as<bool>(), + vm["flp-name"].as<std::string>(), + vm["ccdb-path"].as<std::string>(), + vm["lut-path"].as<std::string>()); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} + +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB) +{ + TStopwatch swTot; + swTot.Start(); + o2::ft0::RawWriterFT0 m2r; + m2r.setFileFor(fileFor); + m2r.setFlpName(flpName); + m2r.setVerbosity(verbosity); + if (ccdbUrl != "") { + m2r.setCCDBurl(ccdbUrl); + } + if (lutPath != "") { + m2r.setLUTpath(lutPath); + } + auto& wr = m2r.getWriter(); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + wr.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::FT0)); // must be set explicitly + wr.setSuperPageSize(superPageSizeInB); + wr.useRDHVersion(rdhV); + wr.setDontFillEmptyHBF(noEmptyHBF); + + o2::raw::assertOutputDirectory(outDir); + + std::string outDirName(outDir); + if (outDirName.back() != '/') { + outDirName += '/'; + } + + m2r.convertDigitsToRaw(outDirName, inpName); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); + // + swTot.Stop(); + swTot.Print(); +} diff --git a/Detectors/FIT/FT0/workflow/CMakeLists.txt b/Detectors/FIT/FT0/workflow/CMakeLists.txt index 69c116c041b14..0c66d855845c8 100644 --- a/Detectors/FIT/FT0/workflow/CMakeLists.txt +++ b/Detectors/FIT/FT0/workflow/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FT0Workflow SOURCES src/RecoWorkflow.cxx @@ -16,15 +17,14 @@ o2_add_library(FT0Workflow src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx src/DigitReaderSpec.cxx - src/FT0Workflow.cxx - src/FT0DataProcessDPLSpec.cxx - src/FT0DataReaderDPLSpec.cxx - src/FT0DigitWriterDPLSpec.cxx + src/FT0DigitWriterSpec.cxx src/RawReaderFT0.cxx + src/RecoQCworkflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsFT0 O2::FT0Reconstruction O2::DetectorsCommonDataFormats + O2::DataFormatsGlobalTracking O2::DPLUtils O2::FT0Raw) @@ -47,9 +47,16 @@ o2_add_executable(digits-reader-workflow o2_add_executable(flp-dpl-workflow COMPONENT_NAME ft0 SOURCES src/ft0-flp-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::FT0Workflow + PUBLIC_LINK_LIBRARIES O2::FT0Workflow O2::FT0Raw O2::FITWorkflow TARGETVARNAME ft0flpexe) +o2_add_executable(reco-qc + COMPONENT_NAME ft0 + SOURCES src/reco-qc.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Workflow O2::FITCalibration O2::GlobalTrackingWorkflowHelpers) + + if(NOT APPLE) set_property(TARGET ${fitrecoexe} PROPERTY LINK_WHAT_YOU_USE ON) diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/DigitReaderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/DigitReaderSpec.h index 3b0c2f2cab1c8..5fb21e9dc4b49 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/DigitReaderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/DigitReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,20 +25,21 @@ namespace ft0 class DigitReader : public framework::Task { public: - DigitReader(bool useMC) : mUseMC(useMC) {} + DigitReader(bool useMC, bool useTrgInput) : mUseMC(useMC), mUseTrgInput(useTrgInput) {} ~DigitReader() override = default; void init(framework::InitContext& ic) final; void run(framework::ProcessingContext& pc) final; private: bool mUseMC = true; + bool mUseTrgInput = true; std::unique_ptr<TTree> mTree; std::unique_ptr<TFile> mFile; }; /// create a processor spec /// read simulated FT0 digits from a root file -framework::DataProcessorSpec getDigitReaderSpec(bool useMC); +framework::DataProcessorSpec getDigitReaderSpec(bool useMC, bool useTrgInput = true); } // end namespace ft0 } // end namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h index 58b25bbcebe54..9f19696ace2c9 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h index 5b42eb0f2cd14..641e5be8551bf 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h index 0f79510037f09..7b7e98d50368e 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h index 3925995bab968..5c10762e0c927 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #ifndef O2_FT0DATAREADERDPLSPEC_H #define O2_FT0DATAREADERDPLSPEC_H - +#include "DataFormatsFT0/LookUpTable.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "Framework/CallbackService.h" @@ -23,7 +24,7 @@ #include "Framework/WorkflowSpec.h" #include "Framework/SerializationMethods.h" #include "DPLUtils/DPLRawParser.h" - +#include "Framework/InputRecordWalker.h" #include <iostream> #include <vector> #include <gsl/span> @@ -40,36 +41,55 @@ class FT0DataReaderDPLSpec : public Task FT0DataReaderDPLSpec(const RawReader& rawReader) : mRawReader(rawReader) {} FT0DataReaderDPLSpec() = default; ~FT0DataReaderDPLSpec() override = default; - void init(InitContext& ic) final {} + typedef RawReader RawReader_t; + void init(InitContext& ic) final { o2::ft0::SingleLUT::Instance().printFullMap(); } void run(ProcessingContext& pc) final { - DPLRawParser parser(pc.inputs()); - mRawReader.clear(); - LOG(INFO) << "FT0DataReaderDPLSpec"; - uint64_t count = 0; + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{o2::header::gDataOriginFT0, o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(pc.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + mRawReader.makeSnapshot(pc); // send empty output + return; + } + } + } + std::vector<InputSpec> filter{InputSpec{"filter", ConcreteDataTypeMatcher{o2::header::gDataOriginFT0, o2::header::gDataDescriptionRawData}, Lifetime::Timeframe}}; + DPLRawParser parser(pc.inputs(), filter); + std::size_t count = 0; for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { //Proccessing each page count++; auto rdhPtr = it.get_if<o2::header::RAWDataHeader>(); gsl::span<const uint8_t> payload(it.data(), it.size()); - mRawReader.process(rdhPtr->linkID, payload); + mRawReader.process(payload, rdhPtr->linkID, rdhPtr->endPointID); } LOG(INFO) << "Pages: " << count; mRawReader.accumulateDigits(); mRawReader.makeSnapshot(pc); + mRawReader.clear(); } - RawReader mRawReader; + RawReader_t mRawReader; }; template <typename RawReader> -framework::DataProcessorSpec getFT0DataReaderDPLSpec(const RawReader& rawReader) +framework::DataProcessorSpec getFT0DataReaderDPLSpec(const RawReader& rawReader, bool askSTFDist) { LOG(INFO) << "DataProcessorSpec initDataProcSpec() for RawReaderFT0"; std::vector<OutputSpec> outputSpec; RawReader::prepareOutputSpec(outputSpec); + std::vector<InputSpec> inputSpec{{"STF", ConcreteDataTypeMatcher{o2::header::gDataOriginFT0, "RAWDATA"}, Lifetime::Optional}}; + if (askSTFDist) { + inputSpec.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } return DataProcessorSpec{ "ft0-datareader-dpl", - o2::framework::select("TF:FT0/RAWDATA"), + inputSpec, outputSpec, adaptFromTask<FT0DataReaderDPLSpec<RawReader>>(rawReader), Options{}}; diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterDPLSpec.h deleted file mode 100644 index a5f985c0149b9..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterDPLSpec.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DigitWriterSpec.h - -#ifndef O2_FT0DIGITWRITERDPL_H -#define O2_FT0DIGITWRITERDPL_H - -#include "Framework/DataProcessorSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ - -/// create a processor spec -framework::DataProcessorSpec getFT0DigitWriterDPLSpec(); - -} // namespace ft0 -} // namespace o2 - -#endif /* O2_FT0DIGITWRITER_H */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterSpec.h index 13f5534745990..08400ef56d9b9 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,13 @@ #define O2_FT0DIGITWRITER_H #include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFT0/MCLabel.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" using namespace o2::framework; @@ -23,7 +31,7 @@ namespace ft0 { /// create a processor spec -framework::DataProcessorSpec getFT0DigitWriterSpec(); +framework::DataProcessorSpec getFT0DigitWriterSpec(bool mctruth = true, bool trigInp = true); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h index f2cd562af2e02..a4988b2c18fc7 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ namespace ft0 { framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, bool dumpProcessor, bool dumpReader, - bool disableRootOut); + bool disableRootOut, bool askSTFDist); } // namespace ft0 } // namespace o2 #endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h index fc65ff17b1f18..5c77e247041b1 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,6 +36,7 @@ namespace o2 namespace ft0 { //Normal TCM mode +template <bool useTrgInput = false> class RawReaderFT0 : public RawReaderFT0BaseNorm { public: @@ -43,16 +45,27 @@ class RawReaderFT0 : public RawReaderFT0BaseNorm RawReaderFT0() = default; ~RawReaderFT0() = default; + static constexpr bool sUseTrgInput = useTrgInput; void clear() { mVecDigits.clear(); + if constexpr (sUseTrgInput) { + mVecTriggerInput.clear(); + } mVecChannelData.clear(); } void accumulateDigits() { - getDigits(mVecDigits, mVecChannelData); + if constexpr (sUseTrgInput) { + getDigits(mVecDigits, mVecChannelData, mVecTriggerInput); + } else { + getDigits(mVecDigits, mVecChannelData); + } LOG(INFO) << "Number of Digits: " << mVecDigits.size(); LOG(INFO) << "Number of ChannelData: " << mVecChannelData.size(); + if constexpr (sUseTrgInput) { + LOG(INFO) << "Number of TriggerInput: " << mVecTriggerInput.size(); + } if (mDumpData) { DigitBlockFT0::print(mVecDigits, mVecChannelData); } @@ -61,40 +74,55 @@ class RawReaderFT0 : public RawReaderFT0BaseNorm { outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); + if constexpr (sUseTrgInput) { + outputSpec.emplace_back(o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe); + } } void makeSnapshot(o2::framework::ProcessingContext& pc) { pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe}, mVecDigits); pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe}, mVecChannelData); + if constexpr (sUseTrgInput) { + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe}, mVecTriggerInput); + } } bool mDumpData; std::vector<Digit> mVecDigits; + std::vector<DetTrigInput> mVecTriggerInput; std::vector<ChannelData> mVecChannelData; }; //Extended TCM mode (additional raw data struct) +template <bool useTrgInput = false> class RawReaderFT0ext : public RawReaderFT0BaseExt { public: RawReaderFT0ext(bool dumpData) : mDumpData(dumpData) {} RawReaderFT0ext(const RawReaderFT0ext&) = default; - + static constexpr bool sUseTrgInput = useTrgInput; RawReaderFT0ext() = default; ~RawReaderFT0ext() = default; void clear() { - mVecDigitsExt.clear(); + mVecDigits.clear(); mVecChannelData.clear(); mVecTrgExt.clear(); + if constexpr (sUseTrgInput) { + mVecTriggerInput.clear(); + } } void accumulateDigits() { - getDigits(mVecDigitsExt, mVecChannelData, mVecTrgExt); - LOG(INFO) << "Number of Digits: " << mVecDigitsExt.size(); + if constexpr (sUseTrgInput) { + getDigits(mVecDigits, mVecChannelData, mVecTrgExt, mVecTriggerInput); + } else { + getDigits(mVecDigits, mVecChannelData, mVecTrgExt); + } + LOG(INFO) << "Number of Digits: " << mVecDigits.size(); LOG(INFO) << "Number of ChannelData: " << mVecChannelData.size(); LOG(INFO) << "Number of TriggerExt: " << mVecTrgExt.size(); if (mDumpData) { - DigitBlockFT0ext::print(mVecDigitsExt, mVecChannelData, mVecTrgExt); + DigitBlockFT0ext::print(mVecDigits, mVecChannelData, mVecTrgExt); } } static void prepareOutputSpec(std::vector<o2::framework::OutputSpec>& outputSpec) @@ -102,17 +130,24 @@ class RawReaderFT0ext : public RawReaderFT0BaseExt outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSTRGEXT", 0, o2::framework::Lifetime::Timeframe); + if constexpr (sUseTrgInput) { + outputSpec.emplace_back(o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe); + } } void makeSnapshot(o2::framework::ProcessingContext& pc) { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe}, mVecDigitsExt); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe}, mVecDigits); pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe}, mVecChannelData); pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSTRGEXT", 0, o2::framework::Lifetime::Timeframe}, mVecTrgExt); + if constexpr (sUseTrgInput) { + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe}, mVecTriggerInput); + } } bool mDumpData; - std::vector<DigitExt> mVecDigitsExt; + std::vector<Digit> mVecDigits; std::vector<ChannelData> mVecChannelData; std::vector<TriggersExt> mVecTrgExt; + std::vector<DetTrigInput> mVecTriggerInput; }; } // namespace ft0 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointReaderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointReaderSpec.h index c16b3234a0541..f74a5339675d1 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointReaderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,10 +47,12 @@ class RecPointReader : public Task o2::header::DataOrigin mOrigin = o2::header::gDataOriginFT0; std::vector<o2::ft0::RecPoints>* mRecPoints = nullptr; + std::vector<o2::ft0::ChannelDataFloat>* mChannelData = nullptr; std::string mInputFileName = "o2reco_ft0.root"; std::string mRecPointTreeName = "o2sim"; std::string mRecPointBranchName = "FT0Cluster"; + std::string mChannelDataBranchName = "FT0RecChData"; }; /// create a processor spec diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointWriterSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointWriterSpec.h index a4a4609cb2045..d1fb0cba5e95b 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointWriterSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecPointWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoQCworkflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoQCworkflow.h new file mode 100644 index 0000000000000..e40f9f808052a --- /dev/null +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoQCworkflow.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoQCworkflow.h +///\ brief QC for reconstructed data +/// \author Alla.Maevskaya@cern.ch + +#ifndef O2_RECOQC_WORKFLOW +#define O2_RECOQC_WORKFLOW + +#include <FairLogger.h> +#include <Framework/ConfigContext.h> +#include <TMath.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsFT0/RecPoints.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +//#include "DataFormatsFT0/RecoCalibInfoObject.h" +#include "TStopwatch.h" +#include <string> +#include <vector> +#include <TH1F.h> +#include <TH2F.h> +#include <TFile.h> + +using namespace o2::framework; +using DataRequest = o2::globaltracking::DataRequest; +using GID = o2::dataformats::GlobalTrackID; + +namespace o2::ft0 +{ + +class RecoQCworkflow final : public o2::framework::Task +{ + public: + RecoQCworkflow(GID::mask_t src, std::shared_ptr<DataRequest> const& dataRequest) : mInputSources(src), mDataRequest(dataRequest) {} + void run(o2::framework::ProcessingContext& pc) final; + void init(InitContext& ic) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + const float cSpeed = 0.029979246f; // speed of light in TOF units + GID::mask_t mInputSources; + TStopwatch mTimer; + TFile* mFileOut; + TH1F* mHisto[10]; + TH2F* mVertexComp; + TH1F* mVertexT0; + TH1F* mPV; +}; + +framework::DataProcessorSpec getRecoQCworkflow(GID::mask_t src); + +} // namespace o2::ft0 + +#endif /* O2_RECOQC_WORKFLOW */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h index 157fb7bee0804..d48376afcef50 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ namespace o2 { namespace fit { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool disableRootInp, bool disableRootOut); } // namespace fit } // namespace o2 #endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h index fd4af7581eae3..030a10231fd7b 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include "Framework/Task.h" #include "FT0Reconstruction/CollisionTimeRecoTask.h" #include "DataFormatsFT0/RecPoints.h" +#include "CCDB/BasicCCDBManager.h" +#include "FT0Base/Geometry.h" #include "TStopwatch.h" using namespace o2::framework; @@ -28,15 +31,18 @@ namespace ft0 class ReconstructionDPL : public Task { + static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; + public: - ReconstructionDPL(bool useMC) : mUseMC(useMC) {} + ReconstructionDPL(bool useMC, std::string ccdbpath) : mUseMC(useMC), mCCDBpath(ccdbpath) {} ~ReconstructionDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; void endOfStream(framework::EndOfStreamContext& ec) final; private: - bool mUseMC = true; + bool mUseMC = false; + const std::string mCCDBpath = "http://o2-ccdb.internal/"; std::vector<o2::ft0::RecPoints> mRecPoints; std::vector<o2::ft0::ChannelDataFloat> mRecChData; o2::ft0::CollisionTimeRecoTask mReco; @@ -45,7 +51,7 @@ class ReconstructionDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getReconstructionSpec(bool useMC = true); +framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://o2-ccdb.internal/"); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx index ab683709b7269..285fcc62f4617 100644 --- a/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/MCLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -32,7 +34,8 @@ namespace ft0 void DigitReader::init(InitContext& ic) { - auto filename = ic.options().get<std::string>("ft0-digit-infile"); + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("ft0-digit-infile")); mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); if (!mFile->IsOpen()) { LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; @@ -49,28 +52,36 @@ void DigitReader::run(ProcessingContext& pc) { std::vector<o2::ft0::Digit> digits, *pdigits = &digits; + std::vector<o2::ft0::DetTrigInput> trgInput, *ptrTrgInput = &trgInput; std::vector<o2::ft0::ChannelData> channels, *pchannels = &channels; mTree->SetBranchAddress("FT0DIGITSBC", &pdigits); mTree->SetBranchAddress("FT0DIGITSCH", &pchannels); - + if (mUseTrgInput) { + mTree->SetBranchAddress("TRIGGERINPUT", &ptrTrgInput); + } o2::dataformats::MCTruthContainer<o2::ft0::MCLabel> labels, *plabels = &labels; if (mUseMC) { mTree->SetBranchAddress("FT0DIGITSMCTR", &plabels); } - mTree->GetEntry(0); - + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); LOG(INFO) << "FT0DigitReader pushed " << channels.size() << " channels in " << digits.size() << " digits"; - pc.outputs().snapshot(Output{"FT0", "DIGITSBC", 0, Lifetime::Timeframe}, digits); pc.outputs().snapshot(Output{"FT0", "DIGITSCH", 0, Lifetime::Timeframe}, channels); if (mUseMC) { pc.outputs().snapshot(Output{"FT0", "DIGITSMCTR", 0, Lifetime::Timeframe}, labels); } - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + if (mUseTrgInput) { + pc.outputs().snapshot(Output{"FT0", "TRIGGERINPUT", 0, Lifetime::Timeframe}, trgInput); + } + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } } -DataProcessorSpec getDigitReaderSpec(bool useMC) +DataProcessorSpec getDigitReaderSpec(bool useMC, bool useTrgInput) { std::vector<OutputSpec> outputs; outputs.emplace_back("FT0", "DIGITSBC", 0, Lifetime::Timeframe); @@ -78,14 +89,17 @@ DataProcessorSpec getDigitReaderSpec(bool useMC) if (useMC) { outputs.emplace_back("FT0", "DIGITSMCTR", 0, Lifetime::Timeframe); } - + if (useTrgInput) { + outputs.emplace_back("FT0", "TRIGGERINPUT", 0, Lifetime::Timeframe); + } return DataProcessorSpec{ "ft0-digit-reader", Inputs{}, outputs, - AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, + AlgorithmSpec{adaptFromTask<DigitReader>(useMC, useTrgInput)}, Options{ - {"ft0-digit-infile", VariantType::String, "ft0digits.root", {"Name of the input file"}}}}; + {"ft0-digit-infile", VariantType::String, "ft0digits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace ft0 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx index d69e174deb922..accc9ee99b59f 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("ft0-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -72,7 +73,7 @@ DataProcessorSpec getEntropyDecoderSpec() Inputs{InputSpec{"ctf", "FT0", "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"ft0-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace ft0 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx index 93e1d013ba95d..866a72c2e98c9 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("ft0-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -72,7 +73,7 @@ DataProcessorSpec getEntropyEncoderSpec() inputs, Outputs{{"FT0", "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"ft0-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace ft0 diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx index 9ad55e06a8c56..6ab9768805859 100644 --- a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx index d8451ba6ccb1e..caa642794b561 100644 --- a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/src/FT0DigitWriterDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DigitWriterDPLSpec.cxx deleted file mode 100644 index 052f0f62a69f7..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0DigitWriterDPLSpec.cxx +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DigitWriterSpec.cxx - -#include <vector> - -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsFT0/ChannelData.h" -#include "DataFormatsFT0/Digit.h" -#include "FT0Workflow/FT0DigitWriterDPLSpec.h" -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ - -template <typename T> -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; -DataProcessorSpec getFT0DigitWriterDPLSpec() -{ - using DigitType = std::vector<o2::ft0::Digit>; - using ChanDataType = std::vector<o2::ft0::ChannelData>; - // Spectators for logging - auto logger = [](DigitType const& digits) { - LOG(INFO) << "FT0DigitWriter pulled " << digits.size() << " digits"; - }; - return MakeRootTreeWriterSpec( - "ft0-digit-writer", "o2digit_ft0.root", "o2sim", - BranchDefinition<DigitType>{InputSpec{"digits", "FT0", "DIGITSBC", 0}, - "FT0DIGITSBC", "ft0-digits-branch-name", 1, - logger}, - BranchDefinition<ChanDataType>{InputSpec{"digch", "FT0", "DIGITSCH", 0}, - "FT0DIGITSCH", "ft0-chhdata-branch-name"})(); -} - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/FT0DigitWriterSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DigitWriterSpec.cxx index 92b613f8eebf1..2e832ec5669cc 100644 --- a/Detectors/FIT/FT0/workflow/src/FT0DigitWriterSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/FT0DigitWriterSpec.cxx @@ -1,22 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// @file FT0DigitWriterSpec.cxx - -#include <vector> - -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsFT0/ChannelData.h" -#include "DataFormatsFT0/Digit.h" #include "FT0Workflow/FT0DigitWriterSpec.h" -using namespace o2::framework; namespace o2 { @@ -24,23 +18,55 @@ namespace ft0 { template <typename T> -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; -DataProcessorSpec getFT0DigitWriterSpec() +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getFT0DigitWriterSpec(bool mctruth, bool trigInp) { - using DigitType = std::vector<o2::ft0::Digit>; - using ChanDataType = std::vector<o2::ft0::ChannelData>; + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; // Spectators for logging - auto logger = [](DigitType const& digits) { - LOG(INFO) << "FT0DigitWriter pulled " << digits.size() << " digits"; + auto logger = [](std::vector<o2::ft0::Digit> const& vecDigits) { + LOG(INFO) << "FT0DigitWriter pulled " << vecDigits.size() << " digits"; }; - return MakeRootTreeWriterSpec( - "ft0-digit-writer", "o2digit_ft0.root", "o2sim", - BranchDefinition<DigitType>{InputSpec{"digits", "FT0", "DIGITSBC", 0}, - "FT0DIGITSBC", "ft0-digits-branch-name", 1, - logger}, - BranchDefinition<ChanDataType>{InputSpec{"digch", "FT0", "DIGITSCH", 0}, - "FT0DIGITSCH", "ft0-chhdata-branch-name"})(); + // the callback to be set as hook for custom action when the writer is closed + auto finishWriting = [](TFile* outputfile, TTree* outputtree) { + const auto* brArr = outputtree->GetListOfBranches(); + int64_t nent = 0; + for (const auto* brc : *brArr) { + int64_t n = ((const TBranch*)brc)->GetEntries(); + if (nent && (nent != n)) { + LOG(ERROR) << "Branches have different number of entries"; + } + nent = n; + } + outputtree->SetEntries(nent); + outputtree->Write(); + outputfile->Close(); + }; + + auto labelsdef = BranchDefinition<o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>>{InputSpec{"labelinput", "FT0", "DIGITSMCTR"}, + "FT0DIGITSMCTR", mctruth ? 1 : 0}; + if (trigInp) { + return MakeRootTreeWriterSpec("FT0DigitWriter", + "ft0digits.root", + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + BranchDefinition<std::vector<o2::ft0::Digit>>{InputSpec{"digitBCinput", "FT0", "DIGITSBC"}, "FT0DIGITSBC", "ft0-digits-branch-name", 1, + logger}, + BranchDefinition<std::vector<o2::ft0::ChannelData>>{InputSpec{"digitChinput", "FT0", "DIGITSCH"}, "FT0DIGITSCH", "ft0-chhdata-branch-name"}, + BranchDefinition<std::vector<o2::ft0::DetTrigInput>>{InputSpec{"digitTrinput", "FT0", "TRIGGERINPUT"}, "TRIGGERINPUT", "ft0-triggerinput-branch-name"}, + std::move(labelsdef))(); + } else { + return MakeRootTreeWriterSpec("FT0DigitWriterRaw", + "o2_ft0digits.root", + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + BranchDefinition<std::vector<o2::ft0::Digit>>{InputSpec{"digitBCinput", "FT0", "DIGITSBC"}, "FT0DIGITSBC", "ft0-digits-branch-name", 1, + logger}, + BranchDefinition<std::vector<o2::ft0::ChannelData>>{InputSpec{"digitChinput", "FT0", "DIGITSCH"}, "FT0DIGITSCH", "ft0-chhdata-branch-name"}, + std::move(labelsdef))(); + } } -} // namespace ft0 -} // namespace o2 +} // end namespace ft0 +} // end namespace o2 \ No newline at end of file diff --git a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx b/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx index db4187ee49169..b3927c4b9cab2 100644 --- a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include "FT0Workflow/FT0Workflow.h" #include "FT0Workflow/FT0DataProcessDPLSpec.h" #include "FT0Workflow/FT0DataReaderDPLSpec.h" -#include "FT0Workflow/FT0DigitWriterDPLSpec.h" +#include "FT0Workflow/FT0DigitWriterSpec.h" #include "FT0Workflow/RawReaderFT0.h" namespace o2 { @@ -22,20 +23,20 @@ namespace ft0 framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, bool dumpProcessor, bool dumpReader, - bool disableRootOut) + bool disableRootOut, bool askSTFDist) { LOG(INFO) << "framework::WorkflowSpec getFT0Workflow"; framework::WorkflowSpec specs; if (isExtendedMode) { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0ext{dumpReader})); + specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0ext{dumpReader}, askSTFDist)); } else { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0{dumpReader})); + specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0<false>{dumpReader}, askSTFDist)); } if (useProcess) { specs.emplace_back(o2::ft0::getFT0DataProcessDPLSpec(dumpProcessor)); } if (!disableRootOut) { - specs.emplace_back(o2::ft0::getFT0DigitWriterDPLSpec()); + specs.emplace_back(o2::ft0::getFT0DigitWriterSpec(false, false)); } return specs; } diff --git a/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx b/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx index 3de0026f13b55..b2ef17e540112 100644 --- a/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx +++ b/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx b/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx index ef9c03c8b6618..43c3a1817183e 100644 --- a/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,12 +13,11 @@ #include <vector> -#include "TTree.h" - #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/Logger.h" #include "FT0Workflow/RecPointReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; using namespace o2::ft0; @@ -37,7 +37,8 @@ RecPointReader::RecPointReader(bool useMC) void RecPointReader::init(InitContext& ic) { - mInputFileName = ic.options().get<std::string>("ft0-recpoints-infile"); + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("ft0-recpoints-infile")); connectTree(mInputFileName); } @@ -47,8 +48,9 @@ void RecPointReader::run(ProcessingContext& pc) assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(INFO) << "FT0 RecPointReader pushes " << mRecPoints->size() << " recpoints at entry " << ent; + LOG(INFO) << "FT0 RecPointReader pushes " << mRecPoints->size() << " recpoints with " << mChannelData->size() << " channels at entry " << ent; pc.outputs().snapshot(Output{mOrigin, "RECPOINTS", 0, Lifetime::Timeframe}, *mRecPoints); + pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0, Lifetime::Timeframe}, *mChannelData); if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get<ControlService>().endOfStream(); @@ -65,6 +67,7 @@ void RecPointReader::connectTree(const std::string& filename) assert(mTree); mTree->SetBranchAddress(mRecPointBranchName.c_str(), &mRecPoints); + mTree->SetBranchAddress(mChannelDataBranchName.c_str(), &mChannelData); if (mUseMC) { LOG(WARNING) << "MC-truth is not supported for FT0 recpoints currently"; mUseMC = false; @@ -77,6 +80,7 @@ DataProcessorSpec getRecPointReaderSpec(bool useMC) { std::vector<OutputSpec> outputSpec; outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECCHDATA", 0, Lifetime::Timeframe); if (useMC) { LOG(WARNING) << "MC-truth is not supported for FT0 recpoints currently"; } @@ -87,7 +91,8 @@ DataProcessorSpec getRecPointReaderSpec(bool useMC) outputSpec, AlgorithmSpec{adaptFromTask<RecPointReader>()}, Options{ - {"ft0-recpoints-infile", VariantType::String, "o2reco_ft0.root", {"Name of the input file"}}}}; + {"ft0-recpoints-infile", VariantType::String, "o2reco_ft0.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace ft0 diff --git a/Detectors/FIT/FT0/workflow/src/RecPointWriterSpec.cxx b/Detectors/FIT/FT0/workflow/src/RecPointWriterSpec.cxx index cfae8f06c1b44..8a43394d5edfb 100644 --- a/Detectors/FIT/FT0/workflow/src/RecPointWriterSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecPointWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/src/RecoQCworkflow.cxx b/Detectors/FIT/FT0/workflow/src/RecoQCworkflow.cxx new file mode 100644 index 0000000000000..f5a45a0e82781 --- /dev/null +++ b/Detectors/FIT/FT0/workflow/src/RecoQCworkflow.cxx @@ -0,0 +1,148 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoQCworkflow.cxx +///\ brief QC for reconstructed data +/// \author Alla.Maevskaya@cern.ch + +#include <FairLogger.h> +#include <Framework/ConfigContext.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsFT0/RecPoints.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "FT0Workflow/RecoQCworkflow.h" +#include "TStopwatch.h" +#include <TString.h> +#include <vector> +#include <TH1F.h> +#include <TH2F.h> +#include <TFile.h> +#include <TMath.h> +#include <vector> +#include <map> + +using namespace o2::framework; +using namespace o2::math_utils::detail; +using PVertex = o2::dataformats::PrimaryVertex; +using GIndex = o2::dataformats::VtxTrackIndex; +using DataRequest = o2::globaltracking::DataRequest; +using GID = o2::dataformats::GlobalTrackID; + +namespace o2::ft0 +{ + +void RecoQCworkflow::init(InitContext& ic) +{ + mFileOut = TFile::Open("RecoQChistos.root", "RECREATE"); + TString histnames[9] = {"hT0AcorrPV", "hT0CcorrPV", "resolution", "hT0A", "hT0C", "hT0AC"}; + for (int ihist = 0; ihist < 6; ihist++) { + mHisto[ihist] = new TH1F(histnames[ihist].Data(), histnames[ihist].Data(), 300, -1000, 1000); + } + mVertexT0 = new TH1F("VertexT0", "T0 vertex", 100, -30, 30); + mPV = new TH1F("PV", "primary vertex", 100, -30, 30); + mVertexComp = new TH2F("hVertexComp", "FT0 and PV comparion", 100, -30, 30, 100, -30, 30); + mTimer.Stop(); + mTimer.Reset(); +} +void RecoQCworkflow::run(o2::framework::ProcessingContext& pc) +{ + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest); + auto primVertices = recoData.getPrimaryVertices(); + auto ft0RecPoints = recoData.getFT0RecPoints(); + std::map<uint64_t, o2::dataformats::PrimaryVertex const*> bcsMap; + for (auto& vertex : primVertices) { + auto& timeStamp = vertex.getTimeStamp(); + double tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns + uint64_t globalBC = std::round(tsTimeStamp / o2::constants::lhc::LHCBunchSpacingNS); + auto [iter, inserted] = bcsMap.try_emplace(globalBC, &vertex); + if (!inserted) { + iter->second = nullptr; + } + } + float vertexT0; + for (auto& ft0RecPoint : ft0RecPoints) { + uint64_t bc = ft0RecPoint.getInteractionRecord().toLong(); + auto item = bcsMap.find(bc); + + if (std::abs(ft0RecPoint.getCollisionTimeA()) < 2000) { + mHisto[3]->Fill(ft0RecPoint.getCollisionTimeA()); + } + if (std::abs(ft0RecPoint.getCollisionTimeC()) < 2000) { + mHisto[4]->Fill(ft0RecPoint.getCollisionTimeC()); + } + + if (std::abs(ft0RecPoint.getCollisionTimeC()) < 2000 && + std::abs(ft0RecPoint.getCollisionTimeA()) < 2000) { + mHisto[5]->Fill(ft0RecPoint.getCollisionTimeMean()); + vertexT0 = 0.5 * (ft0RecPoint.getCollisionTimeC() - ft0RecPoint.getCollisionTimeA()) * cSpeed; + mVertexT0->Fill(vertexT0); + } + if (item == bcsMap.end() || item->second == nullptr) { + LOG(DEBUG) << "Error: could not find a corresponding BC ID for a FT0 rec. point; BC = " << bc; + continue; + } + auto& vertex = *item->second; + auto currentVertex = vertex.getZ(); + mPV->Fill(currentVertex); + ushort ncont = vertex.getNContributors(); + LOG(DEBUG) << "CurrentVertex " << currentVertex << " ncont " << int(ncont); + if (ncont < 3) { + continue; + } + auto shift = currentVertex / cSpeed; + short t0A = ft0RecPoint.getCollisionTimeA() + shift; + short t0C = ft0RecPoint.getCollisionTimeC() - shift; + + LOG(INFO) << " BC t0 " << bc << " shift " << shift << " A " << t0A << " C " << t0C << " vertex " << vertexT0 << " PV " << currentVertex; + mHisto[0]->Fill(t0A); + mHisto[1]->Fill(t0C); + mHisto[2]->Fill((t0C - t0A) / 2); + mVertexComp->Fill(vertexT0, currentVertex); + } + mTimer.Stop(); +} +void RecoQCworkflow::endOfStream(EndOfStreamContext& ec) +{ + mFileOut->cd(); + for (int ihist = 0; ihist < 6; ihist++) { + mHisto[ihist]->Write(); + } + mPV->Write(); + mVertexT0->Write(); + mVertexComp->Write(); + mFileOut->Close(); +} + +DataProcessorSpec getRecoQCworkflow(GID::mask_t src) +{ + auto dataRequest = std::make_shared<DataRequest>(); + LOG(INFO) << "@@ request primary vertex"; + dataRequest->requestPrimaryVertertices(false); + dataRequest->requestFT0RecPoints(false); + LOG(INFO) << "@@@ requested T0"; + std::vector<OutputSpec> outputs; // empty + + return DataProcessorSpec{ + "reco-qc", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<o2::ft0::RecoQCworkflow>(src, dataRequest)}, + Options{}}; +} + +}; // namespace o2::ft0 diff --git a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx index af33a654e941e..dbe1a6bcb3555 100644 --- a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,21 +16,20 @@ #include "FT0Workflow/DigitReaderSpec.h" #include "FT0Workflow/RecPointWriterSpec.h" #include "FT0Workflow/ReconstructionSpec.h" -#include "FT0Workflow/FT0DataReaderDPLSpec.h" +//#include "FT0Workflow/FT0DataReaderDPLSpec.h" namespace o2 { namespace fit { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool disableRootInp, bool disableRootOut) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::ft0::getDigitReaderSpec(useMC)); } - - specs.emplace_back(o2::ft0::getReconstructionSpec(useMC)); + specs.emplace_back(o2::ft0::getReconstructionSpec(useMC, ccdbpath)); if (!disableRootOut) { specs.emplace_back(o2::ft0::getRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx index b659938e87585..3486b0e05b7c9 100644 --- a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/MCLabel.h" +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" using namespace o2::framework; @@ -35,10 +37,12 @@ void ReconstructionDPL::init(InitContext& ic) void ReconstructionDPL::run(ProcessingContext& pc) { + auto& mCCDBManager = o2::ccdb::BasicCCDBManager::instance(); + mCCDBManager.setURL(mCCDBpath); + LOG(INFO) << " set-up CCDB " << mCCDBpath; mTimer.Start(false); mRecPoints.clear(); auto digits = pc.inputs().get<gsl::span<o2::ft0::Digit>>("digits"); - //auto digits = pc.inputs().get<const std::vector<o2::ft0::Digit>>("digits"); auto digch = pc.inputs().get<gsl::span<o2::ft0::ChannelData>>("digch"); // RS: if we need to process MC truth, uncomment lines below //std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>> labels; @@ -48,6 +52,15 @@ void ReconstructionDPL::run(ProcessingContext& pc) // lblPtr = labels.get(); LOG(INFO) << "Ignoring MC info"; } + auto caliboffsets = mCCDBManager.get<o2::ft0::FT0ChannelTimeCalibrationObject>("FT0/Calibration/ChannelTimeOffset"); + mReco.SetChannelOffset(caliboffsets); + LOG(DEBUG) << " RecoSpec mReco.SetChannelOffset(caliboffsets)"; + auto calibslew = mCCDBManager.get<std::array<TGraph, NCHANNELS>>("FT0/SlewingCorr"); + LOG(DEBUG) << " calibslew " << calibslew; + if (calibslew) { + mReco.SetSlew(calibslew); + LOG(INFO) << " calibslew set slew " << calibslew; + } int nDig = digits.size(); LOG(DEBUG) << " nDig " << nDig; mRecPoints.reserve(nDig); @@ -75,7 +88,7 @@ void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getReconstructionSpec(bool useMC) +DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) { std::vector<InputSpec> inputSpec; std::vector<OutputSpec> outputSpec; @@ -92,7 +105,7 @@ DataProcessorSpec getReconstructionSpec(bool useMC) "ft0-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask<ReconstructionDPL>(useMC)}, + AlgorithmSpec{adaptFromTask<ReconstructionDPL>(useMC, ccdbpath)}, Options{}}; } diff --git a/Detectors/FIT/FT0/workflow/src/digits-reader-workflow.cxx b/Detectors/FIT/FT0/workflow/src/digits-reader-workflow.cxx index 09e2f407e512b..8c84b5fdd89b1 100644 --- a/Detectors/FIT/FT0/workflow/src/digits-reader-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/digits-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,8 +27,11 @@ using namespace o2::framework; void customize(std::vector<ConfigParamSpec>& workflowOptions) { // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}}; + options.push_back(ConfigParamSpec{"disable-trigger-input", o2::framework::VariantType::Bool, false, {"Disble trigger input DPL channel"}}); + std::string keyvaluehelp("Semicolon separated key=value strings"); options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); std::swap(workflowOptions, options); @@ -38,8 +42,8 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(const ConfigContext& ctx) { WorkflowSpec specs; - - DataProcessorSpec producer = o2::ft0::getDigitReaderSpec(ctx.options().get<bool>("disable-mc")); + o2::conf::ConfigurableParam::updateFromString(ctx.options().get<std::string>("configKeyValues")); + DataProcessorSpec producer = o2::ft0::getDigitReaderSpec(ctx.options().get<bool>("disable-mc"), ctx.options().get<bool>("disable-trigger-input")); specs.push_back(producer); return specs; } diff --git a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx index e4a094904a820..25271680222cc 100644 --- a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FT0/workflow/src/ft0-flp-workflow.cxx b/Detectors/FIT/FT0/workflow/src/ft0-flp-workflow.cxx index f452eee06a53f..dfc852825e23c 100644 --- a/Detectors/FIT/FT0/workflow/src/ft0-flp-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/ft0-flp-workflow.cxx @@ -1,15 +1,21 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "CommonUtils/ConfigurableParam.h" -#include "FT0Workflow/FT0Workflow.h" +#include "FITWorkflow/FITDataReaderDPLSpec.h" +#include "FITWorkflow/FITDigitWriterSpec.h" +#include "FITWorkflow/RawReaderFIT.h" +#include "DataFormatsFT0/MCLabel.h" +#include "FT0Raw/RawReaderFT0Base.h" +#include "SimulationDataFormat/MCTruthContainer.h" using namespace o2::framework; @@ -26,16 +32,6 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) {"in case of extended TCM mode (1 header + 1 TCMdata + 8 " "TCMdataExtended)"}}); - workflowOptions.push_back( - ConfigParamSpec{"use-process", - o2::framework::VariantType::Bool, - false, - {"enable processor for data taking/dumping"}}); - workflowOptions.push_back( - ConfigParamSpec{"dump-blocks-process", - o2::framework::VariantType::Bool, - false, - {"enable dumping of event blocks at processor side"}}); workflowOptions.push_back( ConfigParamSpec{"dump-blocks-reader", o2::framework::VariantType::Bool, @@ -46,6 +42,16 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); + workflowOptions.push_back( + ConfigParamSpec{"configKeyValues", + o2::framework::VariantType::String, + "", + {"Semicolon separated key=value strings"}}); + workflowOptions.push_back( + ConfigParamSpec{"ignore-dist-stf", + o2::framework::VariantType::Bool, + false, + {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}); } // ------------------------------------------------------------------ @@ -55,13 +61,30 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { LOG(INFO) << "WorkflowSpec defineDataProcessing"; - auto useProcessor = configcontext.options().get<bool>("use-process"); - auto dumpProcessor = configcontext.options().get<bool>("dump-blocks-process"); auto dumpReader = configcontext.options().get<bool>("dump-blocks-reader"); auto isExtendedMode = configcontext.options().get<bool>("tcm-extended-mode"); - auto disableRootOut = - configcontext.options().get<bool>("disable-root-output"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto askSTFDist = !configcontext.options().get<bool>("ignore-dist-stf"); LOG(INFO) << "WorkflowSpec FLPWorkflow"; - return std::move(o2::ft0::getFT0Workflow( - isExtendedMode, useProcessor, dumpProcessor, dumpReader, disableRootOut)); + //Type aliases + //using RawReaderFT0trgInput = o2::fit::RawReaderFIT<o2::ft0::RawReaderFT0BaseNorm,true>; + using RawReaderFT0 = o2::fit::RawReaderFIT<o2::ft0::RawReaderFT0BaseNorm, false>; + //using RawReaderFT0trgInputExt = o2::fit::RawReaderFIT<o2::ft0::RawReaderFT0BaseExt,true>; + using RawReaderFT0ext = o2::fit::RawReaderFIT<o2::ft0::RawReaderFT0BaseExt, false>; + using MCLabelCont = o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>; + o2::header::DataOrigin dataOrigin = o2::header::gDataOriginFT0; + // + WorkflowSpec specs; + if (isExtendedMode) { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFT0ext{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFT0ext, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } else { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFT0{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFT0, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } + return std::move(specs); } diff --git a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx index 9cfe9732aaa21..73cc816873cbc 100644 --- a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,8 @@ #include "FT0Workflow/RecoWorkflow.h" #include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include <string> using namespace o2::framework; @@ -19,14 +22,16 @@ using namespace o2::framework; void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters - workflowOptions.push_back(ConfigParamSpec{ - "disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}); - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - std::string keyvaluehelp("Semicolon separated key=value strings ..."); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"ccdb-path-ft0", o2::framework::VariantType::String, "http://o2-ccdb.internal/", {"CCDB path"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); } // ------------------------------------------------------------------ @@ -38,13 +43,22 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) LOG(INFO) << "WorkflowSpec defineDataProcessing"; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + LOG(INFO) << " ccdbpath " << configcontext.options().get<std::string>("ccdb-path-ft0"); + // write the configuration used for the digitizer workflow - o2::conf::ConfigurableParam::writeINI("o2tpcits-match-recoflow_configuration.ini"); + o2::conf::ConfigurableParam::writeINI("o2-ft0-recoflow_configuration.ini"); auto useMC = !configcontext.options().get<bool>("disable-mc"); - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); + auto ccdbpath = configcontext.options().get<std::string>("ccdb-path-ft0"); + auto disableRootInp = + configcontext.options().get<bool>("disable-root-input"); auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); - LOG(INFO) << "WorkflowSpec getRecoWorkflow useMC " << useMC; - return std::move(o2::fit::getRecoWorkflow(useMC, disableRootInp, disableRootOut)); + LOG(INFO) << "WorkflowSpec getRecoWorkflow useMC " << useMC << " CCDB " << ccdbpath; + auto wf = o2::fit::getRecoWorkflow(useMC, ccdbpath, disableRootInp, disableRootOut); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); } diff --git a/Detectors/FIT/FT0/workflow/src/reco-qc.cxx b/Detectors/FIT/FT0/workflow/src/reco-qc.cxx new file mode 100644 index 0000000000000..961881776bdfe --- /dev/null +++ b/Detectors/FIT/FT0/workflow/src/reco-qc.cxx @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file calib-global-offsets.cxx +#include "FT0Workflow/RecoQCworkflow.h" +#include "Framework/CompletionPolicy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <vector> + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + GID::mask_t allowedSrc = GID::getSourcesMask("FT0"); + GID::mask_t src = allowedSrc & GID::getSourcesMask(configcontext.options().get<std::string>("info-sources")); + + WorkflowSpec specs; + specs.emplace_back(o2::ft0::getRecoQCworkflow(src)); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, false, src); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, false); + o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/FIT/FV0/CMakeLists.txt b/Detectors/FIT/FV0/CMakeLists.txt index e4164be8f405c..d1700b2bf70ef 100644 --- a/Detectors/FIT/FV0/CMakeLists.txt +++ b/Detectors/FIT/FV0/CMakeLists.txt @@ -1,15 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(raw) add_subdirectory(simulation) add_subdirectory(reconstruction) add_subdirectory(workflow) +add_subdirectory(calibration) add_subdirectory(macro) diff --git a/Detectors/FIT/FV0/base/CMakeLists.txt b/Detectors/FIT/FV0/base/CMakeLists.txt index 804c004157da1..b8faf38fb070c 100644 --- a/Detectors/FIT/FV0/base/CMakeLists.txt +++ b/Detectors/FIT/FV0/base/CMakeLists.txt @@ -1,17 +1,21 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FV0Base SOURCES src/Geometry.cxx - PUBLIC_LINK_LIBRARIES ROOT::Geom - FairRoot::Base) + PUBLIC_LINK_LIBRARIES ROOT::Geom + FairRoot::Base + O2::FrameworkLogger + O2::DetectorsBase + O2::DetectorsCommonDataFormats) o2_target_root_dictionary(FV0Base HEADERS include/FV0Base/Geometry.h diff --git a/Detectors/FIT/FV0/base/files/LookupTable_FV0.csv b/Detectors/FIT/FV0/base/files/LookupTable_FV0.csv new file mode 100644 index 0000000000000..40c87b76a2403 --- /dev/null +++ b/Detectors/FIT/FV0/base/files/LookupTable_FV0.csv @@ -0,0 +1,50 @@ +LinkID,EndPointID,CRUID,FEEID,ModuleType,LocalChannelID,channel #,EndPoint/Link,Module,PM channel,HV board,HV channel,MCP S/N,HV cable,signal cable +0,0,0,0,PM,1,0,0/0,PMA0,PMA0/Ch01,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,2,1,0/0,PMA0,PMA0/Ch02,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,3,2,0/0,PMA0,PMA0/Ch03,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,4,3,0/0,PMA0,PMA0/Ch04,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,5,4,0/0,PMA0,PMA0/Ch05,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,6,5,0/0,PMA0,PMA0/Ch06,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,7,6,0/0,PMA0,PMA0/Ch07,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,8,7,0/0,PMA0,PMA0/Ch08,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,9,8,0/0,PMA0,PMA0/Ch09,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,10,9,0/0,PMA0,PMA0/Ch10,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,11,10,0/0,PMA0,PMA0/Ch11,0,N/A,N/A,N/A,N/A +0,0,0,0,PM,12,11,0/0,PMA0,PMA0/Ch12,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,1,12,0/1,PMA1,PMA1/Ch01,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,2,13,0/1,PMA1,PMA1/Ch02,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,3,14,0/1,PMA1,PMA1/Ch03,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,4,15,0/1,PMA1,PMA1/Ch04,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,5,16,0/1,PMA1,PMA1/Ch05,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,6,17,0/1,PMA1,PMA1/Ch06,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,7,18,0/1,PMA1,PMA1/Ch07,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,8,19,0/1,PMA1,PMA1/Ch08,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,9,20,0/1,PMA1,PMA1/Ch09,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,10,21,0/1,PMA1,PMA1/Ch10,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,11,22,0/1,PMA1,PMA1/Ch11,0,N/A,N/A,N/A,N/A +1,0,0,1,PM,12,23,0/1,PMA1,PMA1/Ch12,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,1,24,0/2,PMA2,PMA2/Ch01,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,2,25,0/2,PMA2,PMA2/Ch02,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,3,26,0/2,PMA2,PMA2/Ch03,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,4,27,0/2,PMA2,PMA2/Ch04,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,5,28,0/2,PMA2,PMA2/Ch05,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,6,29,0/2,PMA2,PMA2/Ch06,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,7,30,0/2,PMA2,PMA2/Ch07,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,8,31,0/2,PMA2,PMA2/Ch08,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,9,32,0/2,PMA2,PMA2/Ch09,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,10,33,0/2,PMA2,PMA2/Ch10,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,11,34,0/2,PMA2,PMA2/Ch11,0,N/A,N/A,N/A,N/A +2,0,0,2,PM,12,35,0/2,PMA2,PMA2/Ch12,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,1,36,0/3,PMA3,PMA3/Ch01,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,2,37,0/3,PMA3,PMA3/Ch02,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,3,38,0/3,PMA3,PMA3/Ch03,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,4,39,0/3,PMA3,PMA3/Ch04,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,5,40,0/3,PMA3,PMA3/Ch05,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,6,41,0/3,PMA3,PMA3/Ch06,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,7,42,0/3,PMA3,PMA3/Ch07,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,8,43,0/3,PMA3,PMA3/Ch08,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,9,44,0/3,PMA3,PMA3/Ch09,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,10,45,0/3,PMA3,PMA3/Ch10,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,11,46,0/3,PMA3,PMA3/Ch11,0,N/A,N/A,N/A,N/A +3,0,0,3,PM,12,47,0/3,PMA3,PMA3/Ch12,0,N/A,N/A,N/A,N/A +4,0,0,4,TCM,,48,0/4,TCM,,,,,, diff --git a/Detectors/FIT/FV0/base/include/FV0Base/Constants.h b/Detectors/FIT/FV0/base/include/FV0Base/Constants.h index 965110873e21c..ea7c0a737219b 100644 --- a/Detectors/FIT/FV0/base/include/FV0Base/Constants.h +++ b/Detectors/FIT/FV0/base/include/FV0Base/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/base/include/FV0Base/Geometry.h b/Detectors/FIT/FV0/base/include/FV0Base/Geometry.h index c659c0c47c621..59551216cc516 100644 --- a/Detectors/FIT/FV0/base/include/FV0Base/Geometry.h +++ b/Detectors/FIT/FV0/base/include/FV0Base/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,14 +17,18 @@ #ifndef ALICEO2_FV0_GEOMETRY_H_ #define ALICEO2_FV0_GEOMETRY_H_ - +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <Rtypes.h> +#include <TGeoPhysicalNode.h> #include <vector> #include <array> - #include <TGeoMatrix.h> #include <TGeoVolume.h> #include <TVirtualMC.h> +class TGeoPNEntry; + namespace o2 { namespace fv0 @@ -87,7 +92,7 @@ class Geometry /// and continues clockwise one ring at a time. /// \param fMC The virtual Monte Carlo interface. /// \return The ID of the current scintillator cell during simulation. - const int getCurrentCellId(const TVirtualMC* fMC) const; + int getCurrentCellId(const TVirtualMC* fMC) const; /// Get the names of all the sensitive volumes of the geometry. /// \return The names of all the sensitive volumes of the geometry. @@ -98,7 +103,7 @@ class Geometry /// \param component The geometry component to be enabled/disabled. /// \param enable Setting the enabled state. Default is true. /// \return The enabled state of the geometry component. - const bool enableComponent(EGeoComponent component, bool enable = true); + bool enableComponent(EGeoComponent component, bool enable = true); /// Build the geometry. void buildGeometry() const; @@ -119,6 +124,14 @@ class Geometry /// \return True if cellId belongs to ring 5. bool isRing5(UInt_t cellId); + static constexpr o2::detectors::DetID::ID getDetID() { return o2::detectors::DetID::FV0; } + TGeoPNEntry* getPNEntry(int index) const + { + /// Get a pointer to the TGeoPNEntry of a chip identified by 'index' + /// Returns NULL in case of invalid index, missing TGeoManager or invalid symbolic name + return o2::base::GeometryManager::getPNEntry(getDetID(), index); + } + private: explicit Geometry(EGeoType initType); @@ -138,8 +151,8 @@ class Geometry static constexpr float sDzHalvesSeparation = 0; ///< z-position of the right detector part relative to the left part /// Cell and scintillator constants - static constexpr int sNumberOfCellSectors = 4; ///< Number of cell sectors for one half of the detector - static constexpr int sNumberOfCellRings = 5; ///< Number of cell rings + static constexpr int sNumberOfCellSectors = 4; ///< Number of cell sectors for one half of the detector + static constexpr int sNumberOfCellRings = 5; ///< Number of cell rings static constexpr int sNumberOfCells = sNumberOfCellRings * sNumberOfCellSectors * 2; ///< Number of cells static constexpr int sNumberOfReadoutChannels = sNumberOfCells + sNumberOfCellSectors * 2; ///< Number of ch (2 ch per cell in r5) diff --git a/Detectors/FIT/FV0/base/src/FV0BaseLinkDef.h b/Detectors/FIT/FV0/base/src/FV0BaseLinkDef.h index b2ec9f0e5022c..5d5bfea6b1361 100644 --- a/Detectors/FIT/FV0/base/src/FV0BaseLinkDef.h +++ b/Detectors/FIT/FV0/base/src/FV0BaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/base/src/Geometry.cxx b/Detectors/FIT/FV0/base/src/Geometry.cxx index b40df946084af..8f6669aa98634 100644 --- a/Detectors/FIT/FV0/base/src/Geometry.cxx +++ b/Detectors/FIT/FV0/base/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -57,7 +58,7 @@ Geometry::~Geometry() } } -const int Geometry::getCurrentCellId(const TVirtualMC* fMC) const +int Geometry::getCurrentCellId(const TVirtualMC* fMC) const { int detectorHalfID = -1; int sectorID = -1; @@ -81,7 +82,7 @@ const int Geometry::getCurrentCellId(const TVirtualMC* fMC) const return sectorID + 8 * ringID; } -const bool Geometry::enableComponent(const EGeoComponent component, const bool enable) +bool Geometry::enableComponent(const EGeoComponent component, const bool enable) { if (mEnabledComponents.find(component) == mEnabledComponents.end()) { LOG(DEBUG) << "FV0 Geometry::enableComponent(): Component not initialized and cannot be enabled/disabled!"; diff --git a/Detectors/FIT/FV0/calibration/CMakeLists.txt b/Detectors/FIT/FV0/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..c738ccc54431e --- /dev/null +++ b/Detectors/FIT/FV0/calibration/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FV0Calibration + SOURCES src/FV0ChannelTimeTimeSlotContainer.cxx + src/FV0ChannelTimeCalibrationObject.cxx + src/FV0CalibCollector.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsFV0 + O2::FV0Base + O2::CCDB + O2::DetectorsCalibration + ROOT::Minuit + Microsoft.GSL::GSL +) + +o2_target_root_dictionary(FV0Calibration + HEADERS include/FV0Calibration/FV0CalibrationInfoObject.h + include/FV0Calibration/FV0ChannelTimeCalibrationObject.h + include/FV0Calibration/FV0ChannelTimeTimeSlotContainer.h + include/FV0Calibration/FV0CalibCollector.h +) + +o2_add_executable(fv0-channel-offset-calibration + COMPONENT_NAME calibration + SOURCES workflow/FV0ChannelTimeCalibration-Workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsFV0 + O2::FITCalibration +) + +o2_add_executable(fv0-tf-processor + COMPONENT_NAME calibration + SOURCES workflow/FV0TFProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsFV0 + O2::FITCalibration +) + +add_subdirectory(macros) diff --git a/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibCollector.h b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibCollector.h new file mode 100644 index 0000000000000..5cf612e43a086 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibCollector.h @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef FV0_CALIB_COLLECTOR_H_ +#define FV0_CALIB_COLLECTOR_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "FV0Calibration/FV0CalibrationInfoObject.h" +#include "FV0Base/Constants.h" + +#include <array> + +namespace o2 +{ +namespace fv0 +{ + +class FV0CalibInfoSlot +{ + using Slot = o2::calibration::TimeSlot<o2::fv0::FV0CalibInfoSlot>; + + public: + static constexpr int NCHANNELS = Constants::nFv0Channels; + static constexpr int HISTO_RANGE = 200; + + FV0CalibInfoSlot() + { + for (int ch = 0; ch < NCHANNELS; ch++) { + mEntriesSlot[ch] = 0; + } + } + + ~FV0CalibInfoSlot() = default; + + void print() const; + void printEntries() const; + void fill(const gsl::span<const o2::fv0::FV0CalibrationInfoObject> data); + void merge(const FV0CalibInfoSlot* prev); + + auto& getEntriesPerChannel() const { return mEntriesSlot; } + auto& getEntriesPerChannel() { return mEntriesSlot; } + auto& getCollectedCalibInfoSlot() { return mFV0CollectedCalibInfoSlot; } + auto& getCollectedCalibInfoSlot() const { return mFV0CollectedCalibInfoSlot; } + + private: + std::array<int, NCHANNELS> mEntriesSlot{}; // vector containing number of entries per channel + std::vector<o2::fv0::FV0CalibrationInfoObject> mFV0CollectedCalibInfoSlot; ///< output FV0 calibration info + + ClassDefNV(FV0CalibInfoSlot, 1); +}; + +class FV0CalibCollector final : public o2::calibration::TimeSlotCalibration<o2::fv0::FV0CalibrationInfoObject, o2::fv0::FV0CalibInfoSlot> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<o2::fv0::FV0CalibInfoSlot>; + static constexpr int NCHANNELS = Constants::nFv0Channels; + + public: + FV0CalibCollector(bool TFsendingPolicy, int maxNumOfHits, bool test = false) : mTFsendingPolicy(TFsendingPolicy), mMaxNumOfHits(maxNumOfHits), mTest(test){}; + + ~FV0CalibCollector() final = default; + + bool hasEnoughData(const Slot& slot) const final; + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + void setIsTest(bool istest) { mTest = istest; } + auto& getCollectedCalibInfo() const { return mFV0CollectedCalibInfo; } + auto& getEntriesPerChannel() const { return mEntries; } + void setIsMaxNumberOfHitsAbsolute(bool absNumber) { mAbsMaxNumOfHits = absNumber; } + + private: + bool mTFsendingPolicy = false; // whether we will send information at every TF or only when we have a certain statistics + int mMaxNumOfHits = 1000000; // maximum number of hits for one single channel to trigger the sending of the information (if mTFsendingPolicy = false) + bool mTest = false; // flag to say whether we are in test mode or not + bool mAbsMaxNumOfHits = true; // to decide if the mMaxNumOfHits should be multiplied by the number of FV0 channels + std::array<int, NCHANNELS> mEntries{}; // vector containing number of entries per channel + std::vector<o2::fv0::FV0CalibrationInfoObject> mFV0CollectedCalibInfo; ///< output FV0 calibration info + + ClassDefOverride(FV0CalibCollector, 1); +}; + +} // end namespace fv0 +} // end namespace o2 + +#endif /* FV0 CALIB COLLECTOR */ diff --git a/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibrationInfoObject.h b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibrationInfoObject.h new file mode 100644 index 0000000000000..9a808a898b977 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0CalibrationInfoObject.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FV0CALIBRATIONINFOOBJECT_H +#define O2_FV0CALIBRATIONINFOOBJECT_H + +#include "Rtypes.h" + +namespace o2 +{ +namespace fv0 +{ +class FV0CalibrationInfoObject +{ + public: + FV0CalibrationInfoObject(uint8_t channel, int16_t time, int32_t charge) : mChannelIndex(channel), mTime(time), mCharge(charge){}; + FV0CalibrationInfoObject() = default; + ~FV0CalibrationInfoObject() = default; + + void setChannelIndex(uint8_t channel) { mChannelIndex = channel; } + [[nodiscard]] uint8_t getChannelIndex() const { return mChannelIndex; } + + void setTime(int8_t time) { mTime = time; } + [[nodiscard]] int8_t getTime() const { return mTime; } + void setCharge(int16_t charge) { mCharge = charge; } + [[nodiscard]] int16_t getCharge() const { return mCharge; } + + private: + uint8_t mChannelIndex; + int16_t mTime; + int16_t mCharge; + + ClassDefNV(FV0CalibrationInfoObject, 1); +}; +} // namespace fv0 +} // namespace o2 + +#endif //O2_FV0CALIBRATIONINFOOBJECT_H diff --git a/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeCalibrationObject.h b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeCalibrationObject.h new file mode 100644 index 0000000000000..9a6470a3dba28 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeCalibrationObject.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FV0CHANNELTIMECALIBRATIONOBJECT_H +#define O2_FV0CHANNELTIMECALIBRATIONOBJECT_H + +#include <array> +#include "Rtypes.h" +#include "DataFormatsFV0/RawEventData.h" +#include "FV0Base/Constants.h" + +namespace o2::fv0 +{ + +struct FV0ChannelTimeCalibrationObject { + + std::array<int16_t, Constants::nFv0Channels> mTimeOffsets{}; + + ClassDefNV(FV0ChannelTimeCalibrationObject, 1); +}; + +class FV0ChannelTimeTimeSlotContainer; + +class FV0TimeChannelOffsetCalibrationObjectAlgorithm +{ + public: + [[nodiscard]] static FV0ChannelTimeCalibrationObject generateCalibrationObject(const FV0ChannelTimeTimeSlotContainer& container); +}; + +} // namespace o2::fv0 + +#endif //O2_FV0CHANNELTIMECALIBRATIONOBJECT_H diff --git a/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeTimeSlotContainer.h b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeTimeSlotContainer.h new file mode 100644 index 0000000000000..0c05f3b72a867 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/include/FV0Calibration/FV0ChannelTimeTimeSlotContainer.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FV0CHANNELTIMETIMESLOTCONTAINER_H +#define O2_FV0CHANNELTIMETIMESLOTCONTAINER_H + +#include <array> +#include <vector> +#include <gsl/span> +#include "FV0Calibration/FV0CalibrationInfoObject.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "DataFormatsFV0/RawEventData.h" +#include "DataFormatsFV0/ChannelData.h" +#include "FV0Base/Constants.h" +#include "Rtypes.h" +#include <boost/histogram.hpp> + +namespace o2::fv0 +{ + +class FV0ChannelTimeTimeSlotContainer final +{ + + //ranges to be discussed + static constexpr int HISTOGRAM_RANGE = 200; + static constexpr unsigned int NUMBER_OF_HISTOGRAM_BINS = 2 * HISTOGRAM_RANGE; + + using BoostHistogramType = boost::histogram::histogram<std::tuple<boost::histogram::axis::integer<>, + boost::histogram::axis::integer<>>, + boost::histogram::unlimited_storage<std::allocator<char>>>; + + public: + explicit FV0ChannelTimeTimeSlotContainer(std::size_t minEntries); + [[nodiscard]] bool hasEnoughEntries() const; + void fill(const gsl::span<const FV0CalibrationInfoObject>& data); + [[nodiscard]] int16_t getMeanGaussianFitValue(std::size_t channelID) const; + void merge(FV0ChannelTimeTimeSlotContainer* prev); + void print() const; + + private: + std::size_t mMinEntries; + std::array<uint64_t, Constants::nFv0Channels> mEntriesPerChannel{}; + BoostHistogramType mHistogram; + + ClassDefNV(FV0ChannelTimeTimeSlotContainer, 1); +}; + +} // namespace o2::fv0 + +#endif //O2_FV0CHANNELTIMETIMESLOTCONTAINER_H diff --git a/Detectors/FIT/FV0/calibration/macros/CMakeLists.txt b/Detectors/FIT/FV0/calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..4723d4f98d3e5 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/macros/CMakeLists.txt @@ -0,0 +1,27 @@ +o2_add_test_root_macro( + makeChannelTimeOffsetFV0CalibObjectInCCDB.C + PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats + O2::FV0Simulation + O2::DataFormatsFV0 + O2::Framework + O2::CCDB + O2::FV0Calibration + O2::DetectorsCalibration +) + +o2_add_test_root_macro( + readChannelTimeOffsetFV0CalibObjectFromCCDB.C + PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats + O2::FV0Simulation + O2::DataFormatsFV0 + O2::Framework + O2::CCDB + O2::FV0Calibration + O2::DetectorsCalibration +) + +install( + FILES makeChannelTimeOffsetFV0CalibObjectInCCDB.C + readChannelTimeOffsetFV0CalibObjectFromCCDB.C + DESTINATION share/macro/ +) diff --git a/Detectors/FIT/FV0/calibration/macros/makeChannelTimeOffsetFV0CalibObjectInCCDB.C b/Detectors/FIT/FV0/calibration/macros/makeChannelTimeOffsetFV0CalibObjectInCCDB.C new file mode 100644 index 0000000000000..81556e835d49f --- /dev/null +++ b/Detectors/FIT/FV0/calibration/macros/makeChannelTimeOffsetFV0CalibObjectInCCDB.C @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <string> +#include "TFile.h" +#include <iostream> +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "CCDB/CcdbApi.h" +#endif + +int makeChannelTimeOffsetFV0CalibObjectInCCDB(const std::string url = "http://o2-ccdb.internal/") +{ + o2::ccdb::CcdbApi api; + api.init(url); + std::map<std::string, std::string> md; + o2::fv0::FV0ChannelTimeCalibrationObject obj; + for (auto& dummyCalCoeff : obj.mTimeOffsets) { + dummyCalCoeff = 0; + } + api.storeAsTFileAny(&obj, "FV0/Calibration/ChannelTimeOffset", md, 0); + return 0; +} diff --git a/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C b/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C new file mode 100644 index 0000000000000..5f803c1ca7943 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <string> +#include "TFile.h" +#include <iostream> +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "CCDB/CcdbApi.h" +#endif + +// Macro retrieves only latest set of calibrations +int readChannelTimeOffsetFV0CalibObjectFromCCDB(const std::string url = "http://o2-ccdb.internal/") +{ + o2::ccdb::CcdbApi api; + api.init(url); + map<string, string> metadata; + map<string, string> headers; + auto retrieved = api.retrieveFromTFileAny<o2::fv0::FV0ChannelTimeCalibrationObject>("FV0/Calibration/ChannelTimeOffset", metadata, -1, &headers); + + std::cout << "--- HEADERS ---" << std::endl; + for (const auto& [key, value] : headers) { + std::cout << key << " = " << value << std::endl; + } + std::cout << std::endl + << "---------------" << std::endl; + + for (uint16_t ich = 0; ich < retrieved->mTimeOffsets.size(); ++ich) { + std::cout << "Channel: " << ich << "\t| CalibCoeff: " << retrieved->mTimeOffsets.at(ich) << std::endl; + } + std::cout << std::endl; + return 0; +} diff --git a/Detectors/FIT/FV0/calibration/src/FV0CalibCollector.cxx b/Detectors/FIT/FV0/calibration/src/FV0CalibCollector.cxx new file mode 100644 index 0000000000000..3a4b99de000c6 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/src/FV0CalibCollector.cxx @@ -0,0 +1,164 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Calibration/FV0CalibCollector.h" +#include "Framework/Logger.h" +#include <cassert> +#include <iostream> +#include <sstream> +#include <TStopwatch.h> + +namespace o2 +{ +namespace fv0 +{ + +using Slot = o2::calibration::TimeSlot<o2::fv0::FV0CalibInfoSlot>; + +//_____________________________________________ +void FV0CalibInfoSlot::fill(const gsl::span<const o2::fv0::FV0CalibrationInfoObject> data) +{ + // fill container + // we first order the data that arrived, to improve speed when filling + int nd = data.size(); + LOG(INFO) << "FV0CalibInfoSlot::fill entries in incoming data = " << nd; + std::vector<int> ord(nd); + std::iota(ord.begin(), ord.end(), 0); + std::sort(ord.begin(), ord.end(), [&data](int i, int j) { return data[i].getChannelIndex() < data[j].getChannelIndex(); }); + int chPrev = 0, offsPrev = 0; + for (int i = 0; i < nd; i++) { + if (std::abs(data[ord[i]].getTime()) > HISTO_RANGE) { + continue; + } + const auto& dti = data[ord[i]]; + auto ch = dti.getChannelIndex(); + auto offset = offsPrev; + if (ch > chPrev) { + offset += std::accumulate(mEntriesSlot.begin() + chPrev, mEntriesSlot.begin() + ch, 0); + } + offsPrev = offset; + chPrev = ch; + auto it = mFV0CollectedCalibInfoSlot.emplace(mFV0CollectedCalibInfoSlot.begin() + offset, data[ord[i]].getChannelIndex(), data[ord[i]].getTime(), data[ord[i]].getCharge()); + mEntriesSlot[ch]++; + } +} +//_____________________________________________ +void FV0CalibInfoSlot::merge(const FV0CalibInfoSlot* prev) +{ + // merge data of 2 slots + + LOG(INFO) << "Merging two slots with entries: current slot -> " << mFV0CollectedCalibInfoSlot.size() << " , previous slot -> " << prev->mFV0CollectedCalibInfoSlot.size(); + + int offset = 0, offsetPrev = 0; + std::vector<o2::fv0::FV0CalibrationInfoObject> tmpVector; + for (int ch = 0; ch < NCHANNELS; ch++) { + if (mEntriesSlot[ch] != 0) { + for (int i = offset; i < offset + mEntriesSlot[ch]; i++) { + tmpVector.emplace_back(mFV0CollectedCalibInfoSlot[i]); + } + offset += mEntriesSlot[ch]; + } + if (prev->mEntriesSlot[ch] != 0) { + for (int i = offsetPrev; i < offsetPrev + prev->mEntriesSlot[ch]; i++) { + tmpVector.emplace_back(prev->mFV0CollectedCalibInfoSlot[i]); + } + offsetPrev += prev->mEntriesSlot[ch]; + mEntriesSlot[ch] += prev->mEntriesSlot[ch]; + } + } + mFV0CollectedCalibInfoSlot.swap(tmpVector); + LOG(DEBUG) << "After merging the size is " << mFV0CollectedCalibInfoSlot.size(); + return; +} +//_____________________________________________ +void FV0CalibInfoSlot::print() const +{ + // to print number of entries in the tree and the channel with the max number of entries + + LOG(INFO) << "Total number of entries " << mFV0CollectedCalibInfoSlot.size(); + auto maxElementIndex = std::max_element(mEntriesSlot.begin(), mEntriesSlot.end()); + auto channelIndex = std::distance(mEntriesSlot.begin(), maxElementIndex); + LOG(INFO) << "The maximum number of entries per channel in the current mFV0CollectedCalibInfo is " << *maxElementIndex << " for channel " << channelIndex; + return; +} + +//_____________________________________________ +void FV0CalibInfoSlot::printEntries() const +{ + // to print number of entries in the tree and per channel + + LOG(DEBUG) << "Total number of entries " << mFV0CollectedCalibInfoSlot.size(); + for (int i = 0; i < mEntriesSlot.size(); ++i) { + if (mEntriesSlot[i] != 0) { + LOG(INFO) << "channel " << i << " has " << mEntriesSlot[i] << " entries"; + } + } + return; +} + +//=================================================================== + +//_____________________________________________ +void FV0CalibCollector::initOutput() +{ + // emptying the vectors + + mFV0CollectedCalibInfo.clear(); + for (int ch = 0; ch < NCHANNELS; ch++) { + mEntries[ch] = 0; + } + + return; +} + +//_____________________________________________ +bool FV0CalibCollector::hasEnoughData(const Slot& slot) const +{ + // We define that we have enough data if the tree is big enough. + // each FV0CalibrationInfoObject is composed of two int8 and one int16 --> 32 bytes + // E.g. supposing that we have 500000 entries per channel --> 500 eneries per one amplitude bin + // we can check if we have 500000*Constants::nFv0Channels entries in the vector + + if (mTest) { + return true; + } + const o2::fv0::FV0CalibInfoSlot* c = slot.getContainer(); + LOG(INFO) << "we have " << c->getCollectedCalibInfoSlot().size() << " entries"; + int maxNumberOfHits = mAbsMaxNumOfHits ? mMaxNumOfHits : mMaxNumOfHits * NCHANNELS; + if (mTFsendingPolicy || c->getCollectedCalibInfoSlot().size() > maxNumberOfHits) { + return true; + } + return false; +} + +//_____________________________________________ +void FV0CalibCollector::finalizeSlot(Slot& slot) +{ + + o2::fv0::FV0CalibInfoSlot* c = slot.getContainer(); + mFV0CollectedCalibInfo = c->getCollectedCalibInfoSlot(); + LOG(INFO) << "vector of received with size = " << mFV0CollectedCalibInfo.size(); + mEntries = c->getEntriesPerChannel(); + return; +} + +//_____________________________________________ +Slot& FV0CalibCollector::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<FV0CalibInfoSlot>()); + return slot; +} + +} // end namespace fv0 +} // end namespace o2 diff --git a/Detectors/FIT/FV0/calibration/src/FV0CalibrationLinkDef.h b/Detectors/FIT/FV0/calibration/src/FV0CalibrationLinkDef.h new file mode 100644 index 0000000000000..ac106bd2c5365 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/src/FV0CalibrationLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::fv0::FV0CalibrationInfoObject + ; +#pragma link C++ class o2::fv0::FV0ChannelTimeCalibrationObject + ; +#pragma link C++ class o2::fv0::FV0ChannelTimeTimeSlotContainer + ; +#pragma link C++ class o2::fv0::FV0CalibCollector + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::fv0::FV0CalibrationInfoObject, o2::fv0::FV0CalibInfoSlot>; + +#endif diff --git a/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeCalibrationObject.cxx b/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeCalibrationObject.cxx new file mode 100644 index 0000000000000..dd77bcfddaf79 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeCalibrationObject.cxx @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "FV0Calibration/FV0ChannelTimeTimeSlotContainer.h" + +using namespace o2::fv0; + +FV0ChannelTimeCalibrationObject FV0TimeChannelOffsetCalibrationObjectAlgorithm::generateCalibrationObject(const FV0ChannelTimeTimeSlotContainer& container) +{ + FV0ChannelTimeCalibrationObject calibrationObject; + + for (unsigned int iCh = 0; iCh < Constants::nFv0Channels; ++iCh) { + calibrationObject.mTimeOffsets[iCh] = container.getMeanGaussianFitValue(iCh); + } + + return calibrationObject; +} diff --git a/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeTimeSlotContainer.cxx b/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeTimeSlotContainer.cxx new file mode 100644 index 0000000000000..fd0d43184874c --- /dev/null +++ b/Detectors/FIT/FV0/calibration/src/FV0ChannelTimeTimeSlotContainer.cxx @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Calibration/FV0ChannelTimeTimeSlotContainer.h" +#include "FV0Base/Constants.h" +#include <numeric> +#include <algorithm> +#include "MathUtils/fit.h" + +using namespace o2::fv0; + +FV0ChannelTimeTimeSlotContainer::FV0ChannelTimeTimeSlotContainer(std::size_t minEntries) + : mMinEntries(minEntries) +{ + + mHistogram = boost::histogram::make_histogram(boost::histogram::axis::integer<>(-HISTOGRAM_RANGE, HISTOGRAM_RANGE, "channel_times"), + boost::histogram::axis::integer<>(0, Constants::nFv0Channels, "channel_ID")); +} + +bool FV0ChannelTimeTimeSlotContainer::hasEnoughEntries() const +{ + return *std::min_element(mEntriesPerChannel.begin(), mEntriesPerChannel.end()) > mMinEntries; +} +void FV0ChannelTimeTimeSlotContainer::fill(const gsl::span<const FV0CalibrationInfoObject>& data) +{ + + for (auto& entry : data) { + + const auto chID = entry.getChannelIndex(); + const auto chTime = entry.getTime(); + + //i dont really know when should it be marked as invalid + if (chID < Constants::nFv0Channels) { + mHistogram(chTime, chID); + ++mEntriesPerChannel[chID]; + } else { + LOG(FATAL) << "Invalid channel data"; + } + } +} + +void FV0ChannelTimeTimeSlotContainer::merge(FV0ChannelTimeTimeSlotContainer* prev) +{ + + mHistogram += prev->mHistogram; + for (unsigned int iCh = 0; iCh < Constants::nFv0Channels; ++iCh) { + mEntriesPerChannel[iCh] += prev->mEntriesPerChannel[iCh]; + } +} + +int16_t FV0ChannelTimeTimeSlotContainer::getMeanGaussianFitValue(std::size_t channelID) const +{ + + static constexpr size_t MEAN_VALUE_INDEX_IN_OUTPUT_VECTOR = 1; + + if (0 == mEntriesPerChannel[channelID]) { + return 0; + } + + std::vector<double> channelHistogramData(NUMBER_OF_HISTOGRAM_BINS); + std::vector<double> outputGaussianFitValues; + for (int iBin = 0; iBin < NUMBER_OF_HISTOGRAM_BINS; ++iBin) { + channelHistogramData[iBin] = mHistogram.at(iBin, channelID); + } + + double returnCode = math_utils::fitGaus<double>(NUMBER_OF_HISTOGRAM_BINS, channelHistogramData.data(), + -HISTOGRAM_RANGE, HISTOGRAM_RANGE, outputGaussianFitValues); + if (returnCode < 0) { + LOG(ERROR) << "Gaussian fit error!"; + return 0; + } + + return static_cast<int16_t>(std::round(outputGaussianFitValues[MEAN_VALUE_INDEX_IN_OUTPUT_VECTOR])); +} +void FV0ChannelTimeTimeSlotContainer::print() const +{ + //QC will do that part +} diff --git a/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibration-Workflow.cxx b/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibration-Workflow.cxx new file mode 100644 index 0000000000000..8aab34fb230d9 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibration-Workflow.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0ChannelTimeCalibrationSpec.h" + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + //probably some option will be added +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + workflow.emplace_back(o2::fv0::getFV0ChannelTimeCalibrationSpec()); + return workflow; +} diff --git a/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibrationSpec.h b/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibrationSpec.h new file mode 100644 index 0000000000000..050f66cb62933 --- /dev/null +++ b/Detectors/FIT/FV0/calibration/workflow/FV0ChannelTimeCalibrationSpec.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FV0CHANNELTIMECALIBRATIONSPEC_H +#define O2_FV0CHANNELTIMECALIBRATIONSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "FITCalibration/FITCalibrationDevice.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "FV0Calibration/FV0ChannelTimeTimeSlotContainer.h" +#include "FV0Calibration/FV0CalibrationInfoObject.h" + +namespace o2::fv0 +{ +o2::framework::DataProcessorSpec getFV0ChannelTimeCalibrationSpec() +{ + using CalibrationDeviceType = o2::fit::FITCalibrationDevice<o2::fv0::FV0CalibrationInfoObject, + o2::fv0::FV0ChannelTimeTimeSlotContainer, o2::fv0::FV0ChannelTimeCalibrationObject>; + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "FVO_CTO_CALIB"}); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "FV0_CTO_CALIB"}); + + constexpr const char* DEFAULT_INPUT_LABEL = "calib"; + + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back(DEFAULT_INPUT_LABEL, "FV0", "CALIB_INFO"); + + return o2::framework::DataProcessorSpec{ + "calib-fv0-channel-time", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<CalibrationDeviceType>(DEFAULT_INPUT_LABEL)}, + o2::framework::Options{}}; +} +} // namespace o2::fv0 + +#endif //O2_FV0CHANNELTIMECALIBRATIONSPEC_H diff --git a/Detectors/FIT/FV0/calibration/workflow/FV0TFProcessor-Workflow.cxx b/Detectors/FIT/FV0/calibration/workflow/FV0TFProcessor-Workflow.cxx new file mode 100644 index 0000000000000..a73de64e32c5c --- /dev/null +++ b/Detectors/FIT/FV0/calibration/workflow/FV0TFProcessor-Workflow.cxx @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <Framework/ConfigContext.h> +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFV0/BCData.h" +#include "FV0Calibration/FV0CalibrationInfoObject.h" + +using namespace o2::framework; + +namespace o2::fv0 +{ + +class FV0TFProcessor final : public o2::framework::Task +{ + + public: + void run(o2::framework::ProcessingContext& pc) final + { + auto channels = pc.inputs().get<gsl::span<o2::fv0::ChannelData>>("channels"); + auto digits = pc.inputs().get<gsl::span<o2::fv0::BCData>>("digits"); + auto& calib_data = pc.outputs().make<std::vector<o2::fv0::FV0CalibrationInfoObject>>(o2::framework::OutputRef{"calib", 0}); + calib_data.reserve(channels.size()); + + for (const auto& channel : channels) { + calib_data.emplace_back(channel.pmtNumber, channel.time, channel.chargeAdc); + } + } +}; + +} // namespace o2::fv0 + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + + DataProcessorSpec dataProcessorSpec{ + "FV0TFProcessor", + Inputs{ + {{"channels"}, "FV0", "DIGITSCH"}, + {{"digits"}, "FV0", "DIGITSBC"}, + }, + Outputs{ + {{"calib"}, "FV0", "CALIB_INFO"}}, + AlgorithmSpec{adaptFromTask<o2::fv0::FV0TFProcessor>()}, + Options{}}; + + WorkflowSpec workflow; + workflow.emplace_back(dataProcessorSpec); + return workflow; +} diff --git a/Detectors/FIT/FV0/macro/CMakeLists.txt b/Detectors/FIT/FV0/macro/CMakeLists.txt index d7fadb4a3683c..4ce668487ba32 100644 --- a/Detectors/FIT/FV0/macro/CMakeLists.txt +++ b/Detectors/FIT/FV0/macro/CMakeLists.txt @@ -1,12 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro(FV0Misaligner.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::FV0Simulation + LABELS fv0) o2_add_test_root_macro(readFV0Hits.C PUBLIC_LINK_LIBRARIES O2::FV0Simulation @@ -14,4 +20,6 @@ o2_add_test_root_macro(readFV0Hits.C o2_add_test_root_macro(readFV0Digits.C PUBLIC_LINK_LIBRARIES O2::FV0Simulation - LABELS fv0) + LABELS fv0) + + \ No newline at end of file diff --git a/Detectors/FIT/FV0/macro/FV0Misaligner.C b/Detectors/FIT/FV0/macro/FV0Misaligner.C new file mode 100644 index 0000000000000..c27ff5101a44d --- /dev/null +++ b/Detectors/FIT/FV0/macro/FV0Misaligner.C @@ -0,0 +1,63 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsBase/GeometryManager.h" +#include "CCDB/CcdbApi.h" +#include <TRandom.h> +#include <TFile.h> +#include <vector> +#include <fmt/format.h> +#endif + +using AlgPar = std::array<double, 6>; + +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi); + +void FV0Misaligner(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080", long tmin = 0, long tmax = -1, + double x = 0., double y = 0., double z = 0., double psi = 0., double theta = 0., double phi = 0., + const std::string& objectPath = "", + const std::string& fileName = "FV0Alignment.root") +{ + std::vector<o2::detectors::AlignParam> params; + o2::base::GeometryManager::loadGeometry("", false); + AlgPar pars; + bool glo = true; + + o2::detectors::DetID detFV0("FV0"); + + // FV0 detector + for (int ihalf = 1; ihalf < 3; ihalf++) { + std::string symName = Form("FV0half_%i", ihalf); + pars = generateMisalignment(x, y, z, psi, theta, phi); + params.emplace_back(symName.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + } + + if (!ccdbHost.empty()) { + std::string path = objectPath.empty() ? o2::base::NameConf::getAlignmentPath(detFV0) : objectPath; + LOGP(INFO, "Storing alignment object on {}/{}", ccdbHost, path); + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(¶ms, path, metadata, tmin, tmax); + } + + if (!fileName.empty()) { + LOGP(INFO, "Storing FV0 alignment in local file {}", fileName); + TFile algFile(fileName.c_str(), "recreate"); + algFile.WriteObjectAny(¶ms, "std::vector<o2::detectors::AlignParam>", "alignment"); + algFile.Close(); + } +} +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi) +{ + AlgPar pars; + pars[0] = gRandom->Gaus(0, x); + pars[1] = gRandom->Gaus(0, y); + pars[2] = gRandom->Gaus(0, z); + pars[3] = gRandom->Gaus(0, psi); + pars[4] = gRandom->Gaus(0, theta); + pars[5] = gRandom->Gaus(0, phi); + return std::move(pars); +} diff --git a/Detectors/FIT/FV0/raw/CMakeLists.txt b/Detectors/FIT/FV0/raw/CMakeLists.txt new file mode 100644 index 0000000000000..1848affd5749f --- /dev/null +++ b/Detectors/FIT/FV0/raw/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FV0Raw + SOURCES src/DataBlockFV0.cxx src/DigitBlockFV0.cxx src/RawReaderFV0Base.cxx src/RawWriterFV0.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::DataFormatsFV0 O2::FITRaw) diff --git a/Detectors/FIT/FV0/raw/include/FV0Raw/DataBlockFV0.h b/Detectors/FIT/FV0/raw/include/FV0Raw/DataBlockFV0.h new file mode 100644 index 0000000000000..8bbcadf45b301 --- /dev/null +++ b/Detectors/FIT/FV0/raw/include/FV0Raw/DataBlockFV0.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DataBlockFV0.h class for RAW data format data blocks at FV0 +// +// Artur.Furs +// afurs@cern.ch +// + +#ifndef ALICEO2_FIT_DATABLOCKFV0_H_ +#define ALICEO2_FIT_DATABLOCKFV0_H_ +#include <DataFormatsFV0/RawEventData.h> +#include <FITRaw/DataBlockFIT.h> +namespace o2 +{ +namespace fv0 +{ +//Raw event data for FV0 +using RawHeaderPM = o2::fv0::EventHeader; +using RawDataPM = o2::fv0::EventData; +using RawHeaderTCM = o2::fv0::EventHeader; +using RawDataTCM = o2::fv0::TCMdata; +using RawHeaderTCMext = o2::fv0::EventHeader; +using RawDataTCMext = o2::fv0::TCMdataExtended; +//Data block for FV0 modules +using DataBlockPM = o2::fit::DataBlockPM<RawHeaderPM, RawDataPM>; +using DataBlockTCM = o2::fit::DataBlockTCM<RawHeaderTCM, RawDataTCM>; +using DataBlockTCMext = o2::fit::DataBlockTCMext<RawHeaderTCMext, RawDataTCM, RawDataTCMext>; +} // namespace fv0 +} // namespace o2 +#endif diff --git a/Detectors/FIT/FV0/raw/include/FV0Raw/DigitBlockFV0.h b/Detectors/FIT/FV0/raw/include/FV0Raw/DigitBlockFV0.h new file mode 100644 index 0000000000000..37375c62e2b47 --- /dev/null +++ b/Detectors/FIT/FV0/raw/include/FV0Raw/DigitBlockFV0.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DigitBlockFV0.h class for proccessing RAW data into Digits +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_DIGITBLOCKFV0_H_ +#define ALICEO2_FIT_DIGITBLOCKFV0_H_ +#include "FITRaw/DigitBlockFIT.h" +//#include "DataFormatsFV0/Digit.h" +#include "DataFormatsFV0/BCData.h" +#include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFV0/LookUpTable.h" + +namespace o2 +{ +namespace fv0 +{ +//Normal data taking mode +//using DigitBlockFV0 = DigitBlockFIT<o2::fv0::SingleLUT, o2::fv0::Digit, o2::fv0::ChannelData>; +using DigitBlockFV0 = DigitBlockFIT<o2::fv0::SingleLUT, o2::fv0::BCData, o2::fv0::ChannelData>; +//TCM extended data taking mode +//using DigitBlockFV0ext = DigitBlockFIText<o2::fv0::SingleLUT, o2::fv0::Digit, o2::fv0::ChannelData, o2::fv0::TriggersExt>; +using DigitBlockFV0ext = DigitBlockFIText<o2::fv0::SingleLUT, o2::fv0::BCData, o2::fv0::ChannelData, o2::fv0::TriggersExt>; +} // namespace fv0 +} // namespace o2 +#endif diff --git a/Detectors/FIT/FV0/raw/include/FV0Raw/RawReaderFV0Base.h b/Detectors/FIT/FV0/raw/include/FV0Raw/RawReaderFV0Base.h new file mode 100644 index 0000000000000..f1a6c74bd8261 --- /dev/null +++ b/Detectors/FIT/FV0/raw/include/FV0Raw/RawReaderFV0Base.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderFV0Base.h Base class for RAW data reading +// +// Artur.Furs +// afurs@cern.ch +// +//Main purpuse is to decode FV0 data blocks and push them to DigitBlockFV0 for proccess +//Base class only provides static linkID-moduleType conformity + +#ifndef ALICEO2_FIT_RAWREADERFV0BASE_H_ +#define ALICEO2_FIT_RAWREADERFV0BASE_H_ +#include "FV0Raw/DataBlockFV0.h" +#include "FV0Raw/DigitBlockFV0.h" +#include "FITRaw/RawReaderBaseFIT.h" + +namespace o2 +{ +namespace fv0 +{ +//Normal TCM mode +using RawReaderFV0BaseNorm = o2::fit::RawReaderBaseFIT<DigitBlockFV0, DataBlockPM, DataBlockTCM>; +//Extended TCM mode +using RawReaderFV0BaseExt = o2::fit::RawReaderBaseFIT<DigitBlockFV0ext, DataBlockPM, DataBlockTCMext>; +} // namespace fv0 +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FV0/raw/include/FV0Raw/RawWriterFV0.h b/Detectors/FIT/FV0/raw/include/FV0Raw/RawWriterFV0.h new file mode 100644 index 0000000000000..2c25075721693 --- /dev/null +++ b/Detectors/FIT/FV0/raw/include/FV0Raw/RawWriterFV0.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawWriterFV0.h Raw writer class for FV0 +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_RAWWRITERFV0_H_ +#define ALICEO2_FIT_RAWWRITERFV0_H_ +#include "FV0Raw/DataBlockFV0.h" +#include "FV0Raw/DigitBlockFV0.h" +#include "FITRaw/RawWriterFIT.h" + +namespace o2 +{ +namespace fv0 +{ +//Normal TCM mode +using RawWriterFV0 = o2::fit::RawWriterFIT<DigitBlockFV0, DataBlockPM, DataBlockTCM>; +//Extended TCM mode +//using RawWriterFV0ext = o2::fit::RawWriterFIT<DigitBlockFV0, DataBlockPM, DataBlockTCMext>; +} // namespace fv0 +} // namespace o2 + +#endif diff --git a/Detectors/FIT/FV0/raw/src/DataBlockFV0.cxx b/Detectors/FIT/FV0/raw/src/DataBlockFV0.cxx new file mode 100644 index 0000000000000..4f53af0c80f79 --- /dev/null +++ b/Detectors/FIT/FV0/raw/src/DataBlockFV0.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Raw/DataBlockFV0.h" diff --git a/Detectors/FIT/FV0/raw/src/DigitBlockFV0.cxx b/Detectors/FIT/FV0/raw/src/DigitBlockFV0.cxx new file mode 100644 index 0000000000000..8da75f3bdbcff --- /dev/null +++ b/Detectors/FIT/FV0/raw/src/DigitBlockFV0.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Raw/DigitBlockFV0.h" diff --git a/Detectors/FIT/FV0/raw/src/RawReaderFV0Base.cxx b/Detectors/FIT/FV0/raw/src/RawReaderFV0Base.cxx new file mode 100644 index 0000000000000..7bba6ea3937c9 --- /dev/null +++ b/Detectors/FIT/FV0/raw/src/RawReaderFV0Base.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Raw/RawReaderFV0Base.h" diff --git a/Detectors/FIT/FV0/raw/src/RawWriterFV0.cxx b/Detectors/FIT/FV0/raw/src/RawWriterFV0.cxx new file mode 100644 index 0000000000000..64d75091cbe80 --- /dev/null +++ b/Detectors/FIT/FV0/raw/src/RawWriterFV0.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Raw/RawWriterFV0.h" diff --git a/Detectors/FIT/FV0/reconstruction/CMakeLists.txt b/Detectors/FIT/FV0/reconstruction/CMakeLists.txt index 7e588e3928b7b..427eb736a4123 100644 --- a/Detectors/FIT/FV0/reconstruction/CMakeLists.txt +++ b/Detectors/FIT/FV0/reconstruction/CMakeLists.txt @@ -1,19 +1,24 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FV0Reconstruction - SOURCES src/ReadRaw.cxx + SOURCES src/BaseRecoTask.cxx + src/ReadRaw.cxx src/CTFCoder.cxx + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::Framework O2::FV0Base + O2::FV0Simulation + O2::FV0Calibration O2::DataFormatsFV0 O2::DetectorsRaw O2::CommonDataFormat @@ -21,6 +26,12 @@ o2_add_library(FV0Reconstruction O2::Headers) o2_target_root_dictionary(FV0Reconstruction - HEADERS include/FV0Reconstruction/ReadRaw.h + HEADERS include/FV0Reconstruction/BaseRecoTask.h + include/FV0Reconstruction/ReadRaw.h include/FV0Reconstruction/CTFCoder.h) +o2_add_executable( + test-raw2digit + COMPONENT_NAME fv0 + SOURCES src/test-raw2digit.cxx + PUBLIC_LINK_LIBRARIES O2::FV0Reconstruction) diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h new file mode 100644 index 0000000000000..75bcac53a2126 --- /dev/null +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file BaseRecoTask.h +/// \brief Definition of the FV0 reconstruction task +#ifndef ALICEO2_FV0_BASERECOTASK_H +#define ALICEO2_FV0_BASERECOTASK_H + +#include "DataFormatsFV0/BCData.h" +#include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFV0/RecPoints.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/TimeStamp.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "FV0Base/Constants.h" +#include <gsl/span> +#include <bitset> +#include <vector> +#include <array> +#include <TGraph.h> + +namespace o2 +{ +namespace fv0 +{ +class BaseRecoTask +{ + // using offsetCalib = o2::fv0::FV0ChannelTimeCalibrationObject; + + public: + BaseRecoTask() = default; + ~BaseRecoTask() = default; + o2::fv0::RecPoints process(o2::fv0::BCData const& bcd, + gsl::span<const o2::fv0::ChannelData> inChData, + gsl::span<o2::fv0::ChannelDataFloat> outChData); + void FinishTask(); + void setChannelOffset(o2::fv0::FV0ChannelTimeCalibrationObject* caliboffsets) { mCalibOffset = caliboffsets; }; + int getChannelOffset(int channel); + + private: + o2::fv0::FV0ChannelTimeCalibrationObject* mCalibOffset; + + ClassDefNV(BaseRecoTask, 3); +}; +} // namespace fv0 +} // namespace o2 +#endif diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h index 4b60fd86d1271..e628061481c82 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -90,6 +91,7 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const BCData>& digitVec, const using ECB = CTF::base; ec->setHeader(cd.header); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -112,10 +114,11 @@ void CTFCoder::decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec) { CompressedDigits cd; cd.header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cd.header)); ec.print(getPrefix()); #define DECODEFV0(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) // clang-format off - DECODEFV0(cd.bcInc, CTF::BLC_bcInc); + DECODEFV0(cd.bcInc, CTF::BLC_bcInc); DECODEFV0(cd.orbitInc, CTF::BLC_orbitInc); DECODEFV0(cd.nChan, CTF::BLC_nChan); @@ -154,7 +157,8 @@ void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& cha auto icc = channelVec.size(); const auto& chan = channelVec.emplace_back((chID += cd.idChan[icc]), cd.time[icc], cd.charge[icc]); } - digitVec.emplace_back(firstEntry, cd.nChan[idig], ir); + Triggers triggers; // TODO: Actual values are not set + digitVec.emplace_back(firstEntry, cd.nChan[idig], ir, triggers); } } diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/ReadRaw.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/ReadRaw.h index ade792cc6ee0d..4a6d6134b5466 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/ReadRaw.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/ReadRaw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx new file mode 100644 index 0000000000000..02d0b3114927e --- /dev/null +++ b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file BaseRecoTask.cxx +/// \brief Implementation of the FV0 reconstruction task + +#include "FV0Reconstruction/BaseRecoTask.h" +#include "FairLogger.h" // for LOG +#include "DataFormatsFV0/RecPoints.h" +#include "FV0Base/Geometry.h" +#include "FV0Simulation/FV0DigParam.h" +#include "FV0Simulation/DigitizationConstant.h" +#include "FV0Simulation/FV0DigParam.h" +#include <DataFormatsFV0/ChannelData.h> +#include <DataFormatsFV0/BCData.h> +#include <cmath> +#include <bitset> +#include <cassert> +#include <iostream> +#include <algorithm> +#include <CommonDataFormat/InteractionRecord.h> +#include <Framework/Logger.h> + +using namespace o2::fv0; +using RP = o2::fv0::RecPoints; + +RP BaseRecoTask::process(o2::fv0::BCData const& bcd, + gsl::span<const o2::fv0::ChannelData> inChData, + gsl::span<o2::fv0::ChannelDataFloat> outChData) +{ + LOG(INFO) << "Running reconstruction on new event"; + + Float_t sideAtimeFirst = 1e10; + Int_t ndigitsA = 0; + Float_t sideAtimeAvg = 0; + Int_t ndigitsASelected = 0; + Float_t sideAtimeAvgSelected = 0; + + auto timeStamp = o2::InteractionRecord::bc2ns(bcd.getIntRecord().bc, bcd.getIntRecord().orbit); + + LOG(INFO) << " event time " << timeStamp << " orbit " << bcd.getIntRecord().orbit << " bc " << bcd.getIntRecord().bc; + + int nch = inChData.size(); + for (int ich = 0; ich < nch; ich++) { + LOG(INFO) << " channel " << ich << " / " << nch; + int offsetChannel = getChannelOffset(ich); + + outChData[ich] = o2::fv0::ChannelDataFloat{inChData[ich].pmtNumber, + (inChData[ich].time - offsetChannel) * DigitizationConstant::TIME_PER_TDCCHANNEL, + (double)inChData[ich].chargeAdc * o2::fv0::FV0DigParam::Instance().adcChannelsPerMilivolt, + 0}; // Fill with ADC number once implemented + + // only signals with amplitude participate in collision time + if (outChData[ich].charge > 0) { + sideAtimeFirst = std::min(static_cast<Double_t>(sideAtimeFirst), outChData[ich].time); + sideAtimeAvg += outChData[ich].time; + ndigitsA++; + } + const float chargeThreshold = 10; // TODO: move to digitization parameters or constants and adjust to reasonable value + if (outChData[ich].charge > 0) { + sideAtimeAvgSelected += outChData[ich].time; + ndigitsASelected++; + } + } + const int nsToPs = 1e3; + std::array<short, 3> mCollisionTime = {RP::sDummyCollissionTime, RP::sDummyCollissionTime, RP::sDummyCollissionTime}; + mCollisionTime[RP::TimeFirst] = (ndigitsA > 0) ? round(sideAtimeFirst * nsToPs) : RP::sDummyCollissionTime; + mCollisionTime[RP::TimeGlobalMean] = (ndigitsA > 0) ? round(sideAtimeAvg * nsToPs / Float_t(ndigitsA)) : RP::sDummyCollissionTime; + mCollisionTime[RP::TimeSelectedMean] = (ndigitsASelected > 0) ? round(sideAtimeAvgSelected * nsToPs / Float_t(ndigitsASelected)) : RP::sDummyCollissionTime; + + return RecPoints{mCollisionTime, bcd.ref.getFirstEntry(), bcd.ref.getEntries(), bcd.getIntRecord(), bcd.mTriggers}; +} +//______________________________________________________ +void BaseRecoTask::FinishTask() +{ + // finalize digitization, if needed, flash remaining digits + //if (!mContinuous) return; +} +//______________________________________________________ +int BaseRecoTask::getChannelOffset(int channel) +{ + if (!mCalibOffset) { + return 0; + } + return mCalibOffset->mTimeOffsets[channel]; +} diff --git a/Detectors/FIT/FV0/reconstruction/src/CTFCoder.cxx b/Detectors/FIT/FV0/reconstruction/src/CTFCoder.cxx index c7b7a8d994ecf..8a9a6475932aa 100644 --- a/Detectors/FIT/FV0/reconstruction/src/CTFCoder.cxx +++ b/Detectors/FIT/FV0/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/reconstruction/src/FV0ReconstructionLinkDef.h b/Detectors/FIT/FV0/reconstruction/src/FV0ReconstructionLinkDef.h index 9c78ce474d9df..4e9ca3b922628 100644 --- a/Detectors/FIT/FV0/reconstruction/src/FV0ReconstructionLinkDef.h +++ b/Detectors/FIT/FV0/reconstruction/src/FV0ReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/reconstruction/src/ReadRaw.cxx b/Detectors/FIT/FV0/reconstruction/src/ReadRaw.cxx index db2dd6e2c33ca..43790664b3c41 100644 --- a/Detectors/FIT/FV0/reconstruction/src/ReadRaw.cxx +++ b/Detectors/FIT/FV0/reconstruction/src/ReadRaw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -75,11 +76,11 @@ void ReadRaw::readRawData(const LookUpTable& lut) posPayload += sizeof(mTCMdata); LOG(DEBUG) << " Read TCM: posPayload: " << posPayload << " posInFile: " << posInFile; - } else { // is PM payload - posPayload += CRUWordSize - o2::fv0::EventHeader::PayloadSize; // padding is enabled + } else { // is PM payload + posPayload += CRUWordSize - o2::fv0::RawEventData::sPayloadSize; // padding is enabled for (int i = 0; i < eventHeader.nGBTWords; ++i) { - mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i]), o2::fv0::EventData::PayloadSizeFirstWord); - posPayload += o2::fv0::EventData::PayloadSizeFirstWord; + mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i]), o2::fv0::RawEventData::sPayloadSizeFirstWord); + posPayload += o2::fv0::RawEventData::sPayloadSizeFirstWord; chData = {Short_t(lut.getChannel(link, int(eventData[2 * i].channelID))), Float_t(eventData[2 * i].time), Short_t(eventData[2 * i].charge)}; @@ -93,8 +94,8 @@ void ReadRaw::readRawData(const LookUpTable& lut) Short_t channelIdFirstHalfWord = chData.pmtNumber; - mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i + 1]), EventData::PayloadSizeSecondWord); - posPayload += o2::fv0::EventData::PayloadSizeSecondWord; + mRawFileIn.read(reinterpret_cast<char*>(&eventData[2 * i + 1]), o2::fv0::RawEventData::sPayloadSizeSecondWord); + posPayload += o2::fv0::RawEventData::sPayloadSizeSecondWord; chData = {Short_t(lut.getChannel(link, (eventData[2 * i + 1].channelID))), Float_t(eventData[2 * i + 1].time), Short_t(eventData[2 * i + 1].charge)}; @@ -154,7 +155,8 @@ void ReadRaw::writeDigits(const std::string& outputDigitsFilePath) chDataVecTree.emplace_back(int(sec.pmtNumber), float(sec.time), Short_t(sec.chargeAdc)); nStored++; } - chBcVecTree.emplace_back(first, nStored, digit.first); + Triggers triggers; // TODO: Actual values are not set + chBcVecTree.emplace_back(first, nStored, digit.first, triggers); } outTree->Branch("FV0DigitBC", &chBcVecTree); diff --git a/Detectors/FIT/FV0/reconstruction/src/test-raw2digit.cxx b/Detectors/FIT/FV0/reconstruction/src/test-raw2digit.cxx new file mode 100644 index 0000000000000..8b57f42a8ce60 --- /dev/null +++ b/Detectors/FIT/FV0/reconstruction/src/test-raw2digit.cxx @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TSystem.h> +#include <TTree.h> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/Logger.h" +#include "DataFormatsFV0/BCData.h" +#include "DataFormatsFV0/ChannelData.h" + +#include <TFile.h> +#include <cstring> + +using namespace o2::fv0; +int main() +{ + using Digit = o2::fv0::BCData; + struct EventFV0_t { + Digit mDigit; + std::vector<o2::fv0::ChannelData> mVecChannelData; + bool operator==(const EventFV0_t& other) const + { + return mDigit == other.mDigit && mVecChannelData == other.mVecChannelData; + } + void print() const + { + mDigit.printLog(); + for (const auto& entry : mVecChannelData) { + entry.printLog(); + } + } + }; + std::vector<EventFV0_t> vecTotalEvents, vecTotalEvents2; + gSystem->Exec("$O2_ROOT/bin/o2-sim -n 10 -m FV0 -g pythia8pp"); + gSystem->Exec("$O2_ROOT/bin/o2-sim-digitizer-workflow -b"); + TFile flIn("fv0digits.root"); + std::unique_ptr<TTree> treeInput((TTree*)flIn.Get("o2sim")); + std::vector<Digit> vecDigits; + std::vector<Digit>* ptrVecDigits = &vecDigits; + std::vector<ChannelData> vecChannelData; + std::vector<ChannelData>* ptrVecChannelData = &vecChannelData; + treeInput->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries:" << treeInput->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFV0 = EventFV0_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents.push_back(eventFV0); + } + } + std::cout << "\n===================================\n"; + for (const auto& entry : vecTotalEvents) { + entry.print(); + } + std::cout << "\n===================================\n"; + + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents.size() << std::endl; + std::cout << "Simulation completed!" << std::endl; + gSystem->Exec("$O2_ROOT/bin/o2-fv0-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\""); + gSystem->Exec("$O2_ROOT/bin/o2-raw-file-reader-workflow -b --input-conf FV0raw.cfg --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\"|$O2_ROOT/bin/o2-fv0-flp-dpl-workflow -b"); + TFile flIn2("o2_fv0digits.root"); + std::unique_ptr<TTree> treeInput2((TTree*)flIn2.Get("o2sim")); + std::cout << "Reconstruction completed!" << std::endl; + + treeInput2->SetBranchAddress(Digit::sDigitBranchName, &ptrVecDigits); + treeInput2->SetBranchAddress(ChannelData::sDigitBranchName, &ptrVecChannelData); + std::cout << "Tree nEntries: " << treeInput2->GetEntries() << std::endl; + for (int iEvent = 0; iEvent < treeInput2->GetEntries(); iEvent++) { //Iterating TFs in tree + treeInput2->GetEntry(iEvent); + for (const auto& digit : (*ptrVecDigits)) { //Iterating over all digits in given TF + auto itBegin = ptrVecChannelData->begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itEnd = ptrVecChannelData->begin(); + std::advance(itEnd, digit.ref.getFirstEntry() + digit.ref.getEntries()); + //Event within given TF + auto eventFV0 = EventFV0_t{digit, std::vector<ChannelData>{itBegin, itEnd}}; + vecTotalEvents2.push_back(eventFV0); + } + } + std::cout << "\n===================================\n"; + for (const auto& entry : vecTotalEvents2) { + entry.print(); + } + std::cout << "\n===================================\n"; + std::cout << "\nTOTAL EVENTS: " << vecTotalEvents2.size() << std::endl; + if (vecTotalEvents == vecTotalEvents2) { + std::cout << "TEST IS OK!\n"; + } else { + std::cout << "\nDIFFERENCE BETWEEN SRC AND DEST\n"; + std::cout << "\n===============================\n"; + for (int iEntry = 0; iEntry < std::max(vecTotalEvents.size(), vecTotalEvents2.size()); iEntry++) { + if (iEntry < vecTotalEvents.size() && iEntry < vecTotalEvents2.size()) { + if (vecTotalEvents[iEntry] == vecTotalEvents2[iEntry]) { + continue; + } + } + std::cout << "\nEntryID: " << iEntry; + std::cout << "\n------------------------------SOURCE------------------------------\n"; + if (iEntry < vecTotalEvents.size()) { + vecTotalEvents[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + std::cout << "\n------------------------------DESTINATION------------------------------\n"; + if (iEntry < vecTotalEvents2.size()) { + vecTotalEvents2[iEntry].print(); + } else { + std::cout << "\nEMPTY!\n"; + } + } + std::cout << "\nERROR!\n"; + } + return 0; +} diff --git a/Detectors/FIT/FV0/simulation/CMakeLists.txt b/Detectors/FIT/FV0/simulation/CMakeLists.txt index 99ba6485279a9..19b65b4a88dc0 100644 --- a/Detectors/FIT/FV0/simulation/CMakeLists.txt +++ b/Detectors/FIT/FV0/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FV0Simulation SOURCES src/Detector.cxx @@ -35,7 +36,8 @@ o2_add_executable(digi2raw O2::DetectorsRaw O2::DetectorsCommonDataFormats O2::CommonUtils - Boost::program_options) - + Boost::program_options + O2::FV0Raw) + o2_data_file(COPY data DESTINATION Detectors/FV0/simulation) - + diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Detector.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Detector.h index 6e708568282f3..232f7b4c44a47 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Detector.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -92,6 +93,9 @@ class Detector : public o2::base::DetImpl<Detector> Titanium }; // media IDs used in createMaterials() + /// Add alignable volumes + void addAlignableVolumes() const override; + private: /// Container for hits std::vector<o2::fv0::Hit>* mHits = nullptr; diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/DigitizationConstant.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/DigitizationConstant.h index 6faa00ff54bec..880a295b7eb0b 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/DigitizationConstant.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/DigitizationConstant.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,10 +15,11 @@ namespace o2::fv0 { struct DigitizationConstant { - static constexpr int NCELLSA = 40; // number of scintillator cells - static constexpr float INV_CHARGE_PER_ADC = 1. / 0.6e-12; // charge conversion - static constexpr float INV_TIME_PER_TDCCHANNEL = 1. / 0.01302; // time conversion from ns to TDC channels - static constexpr float N_PHOTONS_PER_MEV = 10400; // average #photons generated per 1 MeV of deposited energy + static constexpr int NCELLSA = 40; // number of scintillator cells + static constexpr float INV_CHARGE_PER_ADC = 1. / 0.6e-12; // charge conversion + static constexpr float TIME_PER_TDCCHANNEL = 0.01302; // time conversion from TDC channels to ns + static constexpr float INV_TIME_PER_TDCCHANNEL = 1. / TIME_PER_TDCCHANNEL; // time conversion from ns to TDC channels + static constexpr float N_PHOTONS_PER_MEV = 10400; // average #photons generated per 1 MeV of deposited energy }; } // namespace o2::fv0 #endif diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h index c03614b0d5ecd..00fdeefecca1d 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ class Digitizer public: Digitizer() - : mTimeStamp(0), mIntRecord(), mEventId(-1), mSrcId(-1), mMCLabels(), mCache(), mPmtChargeVsTime(), mNBins(), mNTimeBinsPerBC(), mPmtResponseGlobal(), mPmtResponseTemp() + : mTimeStamp(0), mIntRecord(), mEventId(-1), mSrcId(-1), mMCLabels(), mCache(), mPmtChargeVsTime(), mNBins(), mNTimeBinsPerBC(), mPmtResponseGlobalRing5(), mPmtResponseGlobalRingA1ToA4(), mPmtResponseTemp(), mLastBCCache(), mCfdStartIndex() { } @@ -54,10 +55,12 @@ class Digitizer void setInteractionRecord(const InteractionTimeRecord& ir) { mIntRecord = ir; } void process(const std::vector<o2::fv0::Hit>& hits, std::vector<o2::fv0::BCData>& digitsBC, - std::vector<o2::fv0::ChannelData>& digitsCh, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels); + std::vector<o2::fv0::ChannelData>& digitsCh, std::vector<o2::fv0::DetTrigInput>& digitsTrig, + o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels); void flush(std::vector<o2::fv0::BCData>& digitsBC, std::vector<o2::fv0::ChannelData>& digitsCh, + std::vector<o2::fv0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels); const InteractionRecord& getInteractionRecord() const { return mIntRecord; } @@ -74,7 +77,7 @@ class Digitizer void clear() { for (auto& channel : mPmtChargeVsTime) { - std::fill(channel.begin(), channel.end(), 0.); + std::fill(std::begin(channel), std::end(channel), 0.); } labels.clear(); } @@ -92,33 +95,41 @@ class Digitizer void createPulse(float mipFraction, int parID, const double hitTime, std::array<o2::InteractionRecord, NBC2Cache> const& cachedIR, int nCachedIR, const int detID); - long mTimeStamp; // TF (run) timestamp + long mTimeStamp; // TF (run) timestamp InteractionTimeRecord mIntRecord; // Interaction record (orbit, bc) -> InteractionTimeRecord - Int_t mEventId; // ID of the current event - Int_t mSrcId; // signal, background or QED + Int_t mEventId; // ID of the current event + Int_t mSrcId; // signal, background or QED std::deque<fv0::MCLabel> mMCLabels; std::deque<BCCache> mCache; BCCache& setBCCache(const o2::InteractionRecord& ir); BCCache* getBCCache(const o2::InteractionRecord& ir); - void storeBC(const BCCache& bc, std::vector<o2::fv0::BCData>& digitsBC, std::vector<o2::fv0::ChannelData>& digitsCh, + void storeBC(const BCCache& bc, + std::vector<o2::fv0::BCData>& digitsBC, + std::vector<o2::fv0::ChannelData>& digitsCh, + std::vector<o2::fv0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels); + bool isRing5(int detID); std::array<std::vector<Float_t>, Constants::nFv0Channels> mPmtChargeVsTime; // Charge time series aka analogue signal pulse from PM UInt_t mNBins; // UInt_t mNTimeBinsPerBC; - Float_t mBinSize; // Time width of the pulse bin - HPTDC resolution + Float_t mBinSize; // Time width of the pulse bin - HPTDC resolution /// vectors to store the PMT signal from cosmic muons - std::vector<Double_t> mPmtResponseGlobal; + std::vector<Double_t> mPmtResponseGlobalRing5; + std::vector<Double_t> mPmtResponseGlobalRingA1ToA4; std::vector<Double_t> mPmtResponseTemp; + /// for CFD + BCCache mLastBCCache; // buffer for the last BC + std::array<int, Constants::nFv0Channels> mCfdStartIndex; // start indices for the CFD detector + /// Internal helper methods related to conversion of energy-deposition into el. signal Int_t SimulateLightYield(Int_t pmt, Int_t nPhot) const; - Float_t SimulateTimeCfd(const ChannelBCDataF& pulse) const; + Float_t SimulateTimeCfd(int& startIndex, const ChannelBCDataF& pulseLast, const ChannelBCDataF& pulse) const; Float_t IntegrateCharge(const ChannelBCDataF& pulse) const; - // Float_t SimulateTimeCfd(Int_t channel, Int_t iCache) const; /// Functions related to splitting ring-5 cell signal to two readout channels static float getDistFromCellCenter(UInt_t cellId, double hitx, double hity); diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digits2Raw.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digits2Raw.h index 8e5c881440f4c..d6c6751c6247f 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digits2Raw.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digits2Raw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h index 0901ff3c1b0ee..efe5d3b63c565 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,31 +22,45 @@ namespace fv0 { // parameters of FV0 digitization / transport simulation struct FV0DigParam : public o2::conf::ConfigurableParamHelper<FV0DigParam> { - float intrinsicTimeRes = 0.91; // time resolution + // NOTUSED float intrinsicTimeRes = 0.91; // time resolution float photoCathodeEfficiency = 0.23; // quantum efficiency = nOfPhotoE_emitted_by_photocathode / nIncidentPhotons float lightYield = 0.01; // light collection efficiency to be tuned using collision data [1%] - float pmtGain = 5e4; // value for PMT R5924-70 at default FV0 gain - float pmtTransitTime = 9.5; // PMT response time (corresponds to 1.9 ns rise time) - float pmtTransparency = 0.25; // Transparency of the first dynode of the PMT - float shapeConst = 1.18059e-14; // Crystal ball const parameter - float shapeMean = 9.5; // Crystal ball mean parameter - float shapeAlpha = -6.56586e-01; // Crystal ball alpha parameter - float shapeN = 2.36408e+00; // Crystal ball N parameter - float shapeSigma = 3.55445; // Crystal ball sigma parameter - //float timeShiftCfd = 3.3; // From the cosmic measurements of FV0 [keep it for reference] - float timeShiftCfd = 5.3; // TODO: adjust after FV0 with FEE measurements are done - float singleMipThreshold = 3.0; // in [MeV] of deposited energy - float singleHitTimeThreshold = 120.0; // in [ns] to skip very slow particles - float waveformNbins = 10000; // number of bins for the analog pulse waveform - float waveformBinWidth = 0.01302; // number of bins for the analog - float avgCfdTimeForMip = 8.63; // in ns to shift the CFD time to zero TODO do ring wise - int chargeIntBinMin = (avgCfdTimeForMip - 6.0) / waveformBinWidth; //Charge integration offset (cfd mean time - 6 ns) - int chargeIntBinMax = (avgCfdTimeForMip + 14.0) / waveformBinWidth; //Charge integration offset (cfd mean time + 14 ns) + // NOTUSED float pmtGain = 5e4; // value for PMT R5924-70 at default FV0 gain + // NOTUSED float pmtTransitTime = 9.5; // PMT response time (corresponds to 1.9 ns rise time) + // NOTUSED float pmtTransparency = 0.25; // Transparency of the first dynode of the PMT + float adcChannelsPerMip = 16; // Default: 16 for pp and 8 for PbPb + float adcChannelsPerMilivolt = adcChannelsPerMip / 7; // Non-trivial conversion depending on the pulseshape: amplitude to charge + /// Parameter for the FV0 waveform [Conv. of expo. with Landau] + // For ring 1-4 + float offsetRingA1ToA4 = 15.87e-09; + float normRingA1ToA4 = 7.9061033e-13 * adcChannelsPerMip / 16; + float constRingA1ToA4 = -25.6165; + float slopeRingA1ToA4 = 4.7942e+08; + float mpvRingA1ToA4 = -6.38203e-08; + float sigmaRingA1ToA4 = 2.12167e-09; + // For ring 5 + float offsetRing5 = 16.38e-09; + float normRing5 = 8.0303587e-13 * adcChannelsPerMip / 16; + float constRing5 = -66.76; + float slopeRing5 = 9.43117e+08; + float mpvRing5 = -6.44167e-08; + float sigmaRing5 = 2.3621e-09; + float timeShiftCfd = 5.3; // TODO: adjust after FV0 with FEE measurements are done + float singleMipThreshold = 3.0; // in [MeV] of deposited energy + float singleHitTimeThreshold = 120.0; // in [ns] to skip very slow particles + UInt_t waveformNbins = 10000; // number of bins for the analog pulse waveform + float waveformBinWidth = 0.01302; // bin width [ns] for analog pulse waveform + float avgCfdTimeForMip = 8.63; // in ns to shift the CFD time to zero TODO [do ring wise] bool isIntegrateFull = false; // Full charge integration widow in 25 ns float cfdCheckWindow = 2.5; // time window for the cfd in ns to trigger the charge integration int avgNumberPhElectronPerMip = 201; // avg number of photo-electrons per MIP - float globalTimeOfFlight = 315.0 / o2::constants::physics::LightSpeedCm2NS; //TODO check the correct value for distance of FV0 to IP - + float globalTimeOfFlight = 315.0 / o2::constants::physics::LightSpeedCm2NS; // TODO [check the correct value for distance of FV0 to IP] + float mCFDdeadTime = 15.6; // ns + float mCFD_trsh = 3.; // [mV] + ///Parameters for trigger simulation + bool useMaxChInAdc = true; // default = true + int adcChargeHighMultTh = 3 * 498; // threshold value of ADC charge for high multiplicity trigger + int maxCountInAdc = 4095; // to take care adc ADC overflow O2ParamDef(FV0DigParam, "FV0DigParam"); }; } // namespace fv0 diff --git a/Detectors/FIT/FV0/simulation/src/Detector.cxx b/Detectors/FIT/FV0/simulation/src/Detector.cxx index d444deab53ea4..06613d63bc008 100644 --- a/Detectors/FIT/FV0/simulation/src/Detector.cxx +++ b/Detectors/FIT/FV0/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -276,6 +277,32 @@ void Detector::ConstructGeometry() // mGeometry->enableComponent(Geometry::eAluminiumContainer, false); mGeometry->buildGeometry(); } +void Detector::addAlignableVolumes() const +{ + // + // Creates entries for alignable volumes associating the symbolic volume + // name with the corresponding volume path. + // + // First version (mainly ported from AliRoot) + // + + LOG(INFO) << "Add FV0 alignable volumes"; + + if (!gGeoManager) { + LOG(FATAL) << "TGeoManager doesn't exist !"; + return; + } + + TString volPath, symName; + for (int ihalf = 1; ihalf < 3; ihalf++) { + volPath = Form("/cave_1/barrel_1/FV0_1/FV0CONTAINER_%i", ihalf); + symName = Form("FV0half_%i", ihalf); + LOG(INFO) << symName << " <-> " << volPath; + if (!gGeoManager->SetAlignableEntry(symName.Data(), volPath.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << symName << " : " << volPath; + } + } +} o2::fv0::Hit* Detector::addHit(Int_t trackId, Int_t cellId, const math_utils::Point3D<float>& startPos, const math_utils::Point3D<float>& endPos, diff --git a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx index c457619ef529a..acef15dbb78c7 100644 --- a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,9 +12,11 @@ #include "FV0Simulation/Digitizer.h" #include "FV0Base/Geometry.h" #include "FV0Base/Constants.h" +#include "TF1Convolution.h" #include <TRandom.h> #include <algorithm> +#include <numeric> ClassImp(o2::fv0::Digitizer); @@ -27,53 +30,70 @@ void Digitizer::clear() for (auto& analogSignal : mPmtChargeVsTime) { std::fill_n(std::begin(analogSignal), analogSignal.size(), 0); } + mLastBCCache.clear(); + mCfdStartIndex.fill(0); } //_______________________________________________________________________ void Digitizer::init() { - LOG(INFO) << "V0Digitizer::init -> start = "; - + LOG(INFO) << "init"; mNBins = FV0DigParam::Instance().waveformNbins; //Will be computed using detector set-up from CDB mBinSize = FV0DigParam::Instance().waveformBinWidth; //Will be set-up from CDB - - mNTimeBinsPerBC = int(o2::constants::lhc::LHCBunchSpacingNS / mBinSize); + mNTimeBinsPerBC = std::lround(o2::constants::lhc::LHCBunchSpacingNS / mBinSize); // 1920 bins/BC for (Int_t detID = 0; detID < Constants::nFv0Channels; detID++) { mPmtChargeVsTime[detID].resize(mNBins); + mLastBCCache.mPmtChargeVsTime[detID].resize(mNBins); } - // set up PMT response function [avg] - TF1 signalShapeFn("signalShape", "crystalball", 0, 200); - signalShapeFn.SetParameters(FV0DigParam::Instance().shapeConst, - FV0DigParam::Instance().shapeMean, - FV0DigParam::Instance().shapeSigma, - FV0DigParam::Instance().shapeAlpha, - FV0DigParam::Instance().shapeN); - - // PMT response per hit [Global] - float x = mBinSize / 2.0; /// Calculate at BinCenter - mPmtResponseGlobal.resize(mNBins); - for (Int_t j = 0; j < mPmtResponseGlobal.size(); ++j) { - mPmtResponseGlobal[j] = signalShapeFn.Eval(x); - //LOG(INFO)<<x<<" "<<mPmtResponseGlobal[j]; - x += mBinSize; + /// set up PMT response function [avg] for ring 1 to 4 + TF1Convolution convolutionRingA1ToA4("expo", "landau", 5.e-09, 90.e-09, false); + TF1 convolutionRingA1ToA4Fn("convolutionFn", convolutionRingA1ToA4, 5.e-09, 90.e-09, convolutionRingA1ToA4.GetNpar()); + convolutionRingA1ToA4Fn.SetParameters(FV0DigParam::Instance().constRingA1ToA4, FV0DigParam::Instance().slopeRingA1ToA4, + FV0DigParam::Instance().mpvRingA1ToA4, FV0DigParam::Instance().sigmaRingA1ToA4); + + /// set up PMT response function [avg] for ring 5 + TF1Convolution convolutionRing5("expo", "landau", 5.e-09, 90.e-09, false); + TF1 convolutionRing5Fn("convolutionFn", convolutionRing5, 5.e-09, 90.e-09, convolutionRing5.GetNpar()); + convolutionRing5Fn.SetParameters(FV0DigParam::Instance().constRing5, FV0DigParam::Instance().slopeRing5, + FV0DigParam::Instance().mpvRing5, FV0DigParam::Instance().sigmaRing5); + /// PMT response per hit [Global] for ring 1 to 4 + mPmtResponseGlobalRingA1ToA4.resize(mNBins); + const float binSizeInNs = mBinSize * 1.e-09; // to convert ns into sec + double x = (binSizeInNs) / 2.0; + for (auto& y : mPmtResponseGlobalRingA1ToA4) { + y = FV0DigParam::Instance().normRingA1ToA4 // normalisation to have MIP adc at 16 + * convolutionRingA1ToA4Fn.Eval(x + FV0DigParam::Instance().offsetRingA1ToA4); //offset to adjust mean position of waveform + x += binSizeInNs; } - - LOG(INFO) << "V0Digitizer::init -> finished"; + /// PMT response per hit [Global] for ring 5 + mPmtResponseGlobalRing5.resize(mNBins); + x = (binSizeInNs) / 2.0; + for (auto& y : mPmtResponseGlobalRing5) { + y = FV0DigParam::Instance().normRing5 // normalisation to have MIP adc at 16 + * convolutionRing5Fn.Eval(x + FV0DigParam::Instance().offsetRing5); //offset to adjust mean position of waveform + x += binSizeInNs; + } + mLastBCCache.clear(); + mCfdStartIndex.fill(0); + LOG(INFO) << "init -> finished"; } -void Digitizer::process(const std::vector<o2::fv0::Hit>& hits, std::vector<o2::fv0::BCData>& digitsBC, - std::vector<o2::fv0::ChannelData>& digitsCh, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels) +void Digitizer::process(const std::vector<o2::fv0::Hit>& hits, + std::vector<o2::fv0::BCData>& digitsBC, + std::vector<o2::fv0::ChannelData>& digitsCh, + std::vector<o2::fv0::DetTrigInput>& digitsTrig, + o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels) { - LOG(INFO) << "[FV0] Digitizer::process(): begin with " << hits.size() << " hits"; - flush(digitsBC, digitsCh, labels); // flush cached signal which cannot be affect by new event + LOG(DEBUG) << "Begin with " << hits.size() << " hits"; + flush(digitsBC, digitsCh, digitsTrig, labels); // flush cached signal which cannot be affect by new event std::vector<int> hitIdx(hits.size()); std::iota(std::begin(hitIdx), std::end(hitIdx), 0); std::sort(std::begin(hitIdx), std::end(hitIdx), [&hits](int a, int b) { return hits[a].GetTrackID() < hits[b].GetTrackID(); }); - Int_t parentIdPrev = -10; + // use ordered hits for (auto ids : hitIdx) { const auto& hit = hits[ids]; @@ -104,18 +124,16 @@ void Digitizer::process(const std::vector<o2::fv0::Hit>& hits, std::vector<o2::f } else { iChannelPerCell = 2; // not a ring 5 cell -> don't repeat the loop } - Double_t const nPhotons = hitEdep * DP::N_PHOTONS_PER_MEV; float const nPhE = SimulateLightYield(detId, nPhotons); - float mipFraction = float(nPhE / FV0DigParam::Instance().avgNumberPhElectronPerMip); + float const mipFraction = float(nPhE / FV0DigParam::Instance().avgNumberPhElectronPerMip); Float_t timeHit = hitTime; timeHit += mIntRecord.getTimeNS(); - o2::InteractionTimeRecord irHit(timeHit); + o2::InteractionTimeRecord const irHit(timeHit); std::array<o2::InteractionRecord, NBC2Cache> cachedIR; int nCachedIR = 0; - for (int i = BCCacheMin; i < BCCacheMax + 1; i++) { - double tNS = timeHit + o2::constants::lhc::LHCBunchSpacingNS * i; + double const tNS = timeHit + o2::constants::lhc::LHCBunchSpacingNS * i; cachedIR[nCachedIR].setFromNS(tNS); if (tNS < 0 && cachedIR[nCachedIR] > irHit) { continue; // don't go to negative BC/orbit (it will wrap) @@ -132,10 +150,8 @@ void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, std::array<o2::InteractionRecord, NBC2Cache> const& cachedIR, int nCachedIR, const int detId) { - bool added[nCachedIR]; - for (int ir = 0; ir < nCachedIR; ir++) { - added[ir] = false; - } + std::array<bool, NBC2Cache> added; + added.fill(false); for (int ir = 0; ir < NBC2Cache; ir++) { auto bcCache = getBCCache(cachedIR[ir]); @@ -145,15 +161,26 @@ void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, } ///Time of flight subtracted from Hit time //TODO have different TOF according to thr ring number - Int_t NBinShift = std::lround((hitTime - FV0DigParam::Instance().globalTimeOfFlight) / FV0DigParam::Instance().waveformBinWidth); + Int_t const NBinShift = std::lround((hitTime - FV0DigParam::Instance().globalTimeOfFlight) / FV0DigParam::Instance().waveformBinWidth); if (NBinShift >= 0 && NBinShift < FV0DigParam::Instance().waveformNbins) { mPmtResponseTemp.resize(FV0DigParam::Instance().waveformNbins, 0.); - std::memcpy(&mPmtResponseTemp[NBinShift], &mPmtResponseGlobal[0], - sizeof(double) * (FV0DigParam::Instance().waveformNbins - NBinShift)); + if (isRing5(detId)) { + std::memcpy(&mPmtResponseTemp[NBinShift], &mPmtResponseGlobalRing5[0], + sizeof(double) * (FV0DigParam::Instance().waveformNbins - NBinShift)); + } else { + std::memcpy(&mPmtResponseTemp[NBinShift], &mPmtResponseGlobalRingA1ToA4[0], + sizeof(double) * (FV0DigParam::Instance().waveformNbins - NBinShift)); + } } else { - mPmtResponseTemp = mPmtResponseGlobal; - mPmtResponseTemp.erase(mPmtResponseTemp.begin(), mPmtResponseTemp.begin() + abs(NBinShift)); + if (isRing5(detId)) { + mPmtResponseTemp = mPmtResponseGlobalRing5; + mPmtResponseTemp.erase(mPmtResponseTemp.begin(), mPmtResponseTemp.begin() + abs(NBinShift)); + } else { + mPmtResponseTemp = mPmtResponseGlobalRingA1ToA4; + mPmtResponseTemp.erase(mPmtResponseTemp.begin(), mPmtResponseTemp.begin() + abs(NBinShift)); + } + mPmtResponseTemp.resize(FV0DigParam::Instance().waveformNbins); } @@ -174,16 +201,15 @@ void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, } } -void Digitizer::flush(std::vector<o2::fv0::BCData>& digitsBC, std::vector<o2::fv0::ChannelData>& digitsCh, +void Digitizer::flush(std::vector<o2::fv0::BCData>& digitsBC, + std::vector<o2::fv0::ChannelData>& digitsCh, + std::vector<o2::fv0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels) { - int nCached = mCache.size(); - if (nCached < 1) { - return; - } - for (auto bc : mCache) { - if (mIntRecord.differenceInBC(bc) > NBC2Cache) { // Build events those are separated by NBC2Cache BCs from current BC - storeBC(bc, digitsBC, digitsCh, labels); + while (!mCache.empty()) { + auto const& bc = mCache.front(); + if (mIntRecord.differenceInBC(bc) > NBC2Cache) { // Build events that are separated by NBC2Cache BCs from current BC + storeBC(bc, digitsBC, digitsCh, digitsTrig, labels); mCache.pop_front(); } else { return; @@ -191,35 +217,74 @@ void Digitizer::flush(std::vector<o2::fv0::BCData>& digitsBC, std::vector<o2::fv } } -void Digitizer::storeBC(const BCCache& bc, std::vector<o2::fv0::BCData>& digitsBC, std::vector<o2::fv0::ChannelData>& digitsCh, +void Digitizer::storeBC(const BCCache& bc, + std::vector<o2::fv0::BCData>& digitsBC, + std::vector<o2::fv0::ChannelData>& digitsCh, + std::vector<o2::fv0::DetTrigInput>& digitsTrig, o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>& labels) { - int first = digitsCh.size(); + size_t const nBC = digitsBC.size(); // save before digitsBC is being modified + size_t const first = digitsCh.size(); // save before digitsCh is being modified size_t nStored = 0; - double totalCharge = 0; + double totalChargeAllRing = 0; + double nSignalInner = 0; + double nSignalOuter = 0; + + if (mLastBCCache.differenceInBC(bc) != 1) { // if the last buffered BC is not the one before the current BC + mLastBCCache.clear(); // clear the bufffer (mPmtChargeVsTime set to 0s) + mCfdStartIndex.fill(0); // reset all start indices to 0, i.e., to the beginning of the BC + } + for (int iPmt = 0; iPmt < Constants::nFv0Channels; iPmt++) { - double cfdWithOffset = SimulateTimeCfd(bc.mPmtChargeVsTime[iPmt]); + // run the CFD: this updates the start index for the next BC in case the CFD dead time ends in the next BC + double cfdWithOffset = SimulateTimeCfd(mCfdStartIndex[iPmt], mLastBCCache.mPmtChargeVsTime[iPmt], bc.mPmtChargeVsTime[iPmt]); double cfdZero = cfdWithOffset - FV0DigParam::Instance().avgCfdTimeForMip; if (cfdZero < -FV0DigParam::Instance().cfdCheckWindow || cfdZero > FV0DigParam::Instance().cfdCheckWindow) { continue; } - - //LOG(INFO) << "time inside analyse and store =========> " << cfdZero <<" detid "<<iPmt; - float charge = IntegrateCharge(bc.mPmtChargeVsTime[iPmt]); - totalCharge += charge; - totalCharge *= DP::INV_CHARGE_PER_ADC; + float totalCharge = IntegrateCharge(bc.mPmtChargeVsTime[iPmt]); + if (totalCharge > (FV0DigParam::Instance().maxCountInAdc * (1. / DP::INV_CHARGE_PER_ADC)) && FV0DigParam::Instance().useMaxChInAdc) { + totalChargeAllRing += FV0DigParam::Instance().maxCountInAdc * (1. / DP::INV_CHARGE_PER_ADC); + } else { + totalChargeAllRing += totalCharge; + } + totalCharge *= DP::INV_CHARGE_PER_ADC; //convert coulomb to adc + if (totalCharge > FV0DigParam::Instance().maxCountInAdc && FV0DigParam::Instance().useMaxChInAdc) { + totalCharge = FV0DigParam::Instance().maxCountInAdc; //max adc channel for one PMT + } cfdZero *= DP::INV_TIME_PER_TDCCHANNEL; - digitsCh.emplace_back(iPmt, static_cast<short int>(std::round(cfdZero)), - static_cast<short int>(std::round(totalCharge))); - totalCharge = 0; + digitsCh.emplace_back(iPmt, std::lround(cfdZero), std::lround(totalCharge)); ++nStored; + //---trigger--- + if (iPmt < 24) { + nSignalInner++; + } else { + nSignalOuter++; + } } - int nBC = digitsBC.size(); - digitsBC.emplace_back(first, nStored, bc); - for (const auto& lbl : bc.labels) { + // save BC information for the CFD detector + mLastBCCache = bc; + if (nStored < 1) { + return; + } + totalChargeAllRing *= DP::INV_CHARGE_PER_ADC; + //LOG(INFO)<<"Total charge ADC " <<totalChargeAllRing ; + ///Triggers for FV0 + bool isMinBias, isMinBiasInner, isMinBiasOuter, isHighMult, isDummy; + isMinBias = nStored > 0; + isMinBiasInner = nSignalInner > 0; //ring 1,2 and 3 + isMinBiasOuter = nSignalOuter > 0; //ring 4 and 5 + isHighMult = totalChargeAllRing > FV0DigParam::Instance().adcChargeHighMultTh; + isDummy = false; + + Triggers triggers; + triggers.setTriggers(isMinBias, isMinBiasInner, isMinBiasOuter, isHighMult, isDummy, nStored, totalChargeAllRing); + digitsBC.emplace_back(first, nStored, bc, triggers); + digitsTrig.emplace_back(bc, isMinBias, isMinBiasInner, isMinBiasOuter, isHighMult, isDummy); + for (auto const& lbl : bc.labels) { labels.addElement(nBC, lbl); } } @@ -243,35 +308,47 @@ Int_t Digitizer::SimulateLightYield(Int_t pmt, Int_t nPhot) const //--------------------------------------------------------------------------- Float_t Digitizer::IntegrateCharge(const ChannelBCDataF& pulse) const { - int chargeIntMin = FV0DigParam::Instance().isIntegrateFull ? 0 : FV0DigParam::Instance().chargeIntBinMin; - int chargeIntMax = FV0DigParam::Instance().isIntegrateFull ? mNTimeBinsPerBC : FV0DigParam::Instance().chargeIntBinMax; - + int const chargeIntMin = FV0DigParam::Instance().isIntegrateFull ? 0 : (FV0DigParam::Instance().avgCfdTimeForMip - 6.0) / mBinSize; //Charge integration offset (cfd mean time - 6 ns) + int const chargeIntMax = FV0DigParam::Instance().isIntegrateFull ? mNTimeBinsPerBC : (FV0DigParam::Instance().avgCfdTimeForMip + 14.0) / mBinSize; //Charge integration offset (cfd mean time + 14 ns) + if (chargeIntMin < 0 || chargeIntMin > mNTimeBinsPerBC || chargeIntMax > mNTimeBinsPerBC) { + LOG(FATAL) << "invalid indicess: chargeInMin=" << chargeIntMin << " chargeIntMax=" << chargeIntMax; + } Float_t totalCharge = 0.0f; for (int iTimeBin = chargeIntMin; iTimeBin < chargeIntMax; iTimeBin++) { - Float_t const timeBinCharge = pulse[iTimeBin]; - //LOG(INFO)<<iTimeBin*0.013<<" "<<timeBinCharge; - totalCharge += timeBinCharge; + totalCharge += pulse[iTimeBin]; } return totalCharge; } //--------------------------------------------------------------------------- -Float_t Digitizer::SimulateTimeCfd(/*Int_t channel, */ const ChannelBCDataF& pulse) const +Float_t Digitizer::SimulateTimeCfd(int& startIndex, const ChannelBCDataF& pulseLast, const ChannelBCDataF& pulse) const { Float_t timeCfd = -1024.0f; - //auto& bc= mCache[iCache]; - if (pulse.empty()) { + startIndex = 0; return timeCfd; } + Float_t const cfdThrInCoulomb = FV0DigParam::Instance().mCFD_trsh * 1e-3 / 50 * mBinSize * 1e-9; // convert mV into Coulomb assuming 50 Ohm + Int_t const binShift = TMath::Nint(FV0DigParam::Instance().timeShiftCfd / mBinSize); - Float_t sigPrev = -pulse[0]; //[0]; - for (Int_t iTimeBin = 1; iTimeBin < mNTimeBinsPerBC; ++iTimeBin) { - Float_t const sigCurrent = (iTimeBin >= binShift ? 5.0f * pulse[iTimeBin - binShift] - pulse[iTimeBin] : -pulse[iTimeBin]); - if (sigPrev < 0.0f && sigCurrent >= 0.0f) { - timeCfd = Float_t(iTimeBin) * mBinSize; - break; + Float_t sigPrev = 5 * pulseLast[mNTimeBinsPerBC - binShift - 1] - pulseLast[mNTimeBinsPerBC - 1]; // CFD output from the last bin of the last BC + for (Int_t iTimeBin = 0; iTimeBin < mNTimeBinsPerBC; ++iTimeBin) { + Float_t const sigCurrent = 5.0f * (iTimeBin >= binShift ? pulse[iTimeBin - binShift] : pulseLast[mNTimeBinsPerBC - binShift + iTimeBin]) - pulse[iTimeBin]; + if (iTimeBin >= startIndex && std::abs(pulse[iTimeBin]) > cfdThrInCoulomb) { // enable + if (sigPrev < 0.0f && sigCurrent >= 0.0f) { // test for zero-crossing + timeCfd = Float_t(iTimeBin) * mBinSize; + startIndex = iTimeBin + std::lround(FV0DigParam::Instance().mCFDdeadTime / mBinSize); // update startIndex (CFD dead time) + if (startIndex < mNTimeBinsPerBC) { + startIndex = 0; // dead-time ends in same BC: no impact on the following BC + } else { + startIndex -= mNTimeBinsPerBC; + } + if (startIndex > mNTimeBinsPerBC) { + LOG(FATAL) << "CFD dead-time was set to > 25 ns"; + } + break; // only detects the 1st zero-crossing in the BC + } } sigPrev = sigCurrent; } @@ -295,7 +372,7 @@ float Digitizer::getDistFromCellCenter(UInt_t cellId, double hitx, double hity) float Digitizer::getSignalFraction(float distanceFromXc, bool isFirstChannel) { - float fraction = sigmoidPmtRing5(distanceFromXc); + float const fraction = sigmoidPmtRing5(distanceFromXc); if (distanceFromXc > 0) { return isFirstChannel ? fraction : (1. - fraction); } else { @@ -318,7 +395,6 @@ o2::fv0::Digitizer::BCCache& Digitizer::setBCCache(const o2::InteractionRecord& cb = ir; return cb; } - for (auto cb = mCache.begin(); cb != mCache.end(); cb++) { if ((*cb) == ir) { return *cb; @@ -341,4 +417,13 @@ o2::fv0::Digitizer::BCCache* Digitizer::getBCCache(const o2::InteractionRecord& } } return nullptr; -} \ No newline at end of file +} + +bool Digitizer::isRing5(int detID) +{ + if (detID > 31) { + return true; + } else { + return false; + } +} diff --git a/Detectors/FIT/FV0/simulation/src/Digits2Raw.cxx b/Detectors/FIT/FV0/simulation/src/Digits2Raw.cxx index 0e2424b6729dd..d461ac0f69f0d 100644 --- a/Detectors/FIT/FV0/simulation/src/Digits2Raw.cxx +++ b/Detectors/FIT/FV0/simulation/src/Digits2Raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,11 +60,9 @@ void Digits2Raw::readDigits(const std::string& outDir, const std::string& fileDi for (int ibc = 0; ibc < nbc; ibc++) { auto& bcd = digitsBC[ibc]; auto channels = bcd.getBunchChannelData(digitsCh); - if (!channels.empty()) { - LOG(DEBUG); - LOG(INFO) << "o2::fv0::Digits2Raw::readDigits(): Start to convertDigits() at ibc = " << ibc << " " << bcd.ir - << " iCh0:" << bcd.ref.getFirstEntry() << " nentries:" << bcd.ref.getEntries(); + LOG(DEBUG) << "o2::fv0::Digits2Raw::readDigits(): Start to convertDigits() at ibc = " << ibc << " " << bcd.ir + << " iCh0:" << bcd.ref.getFirstEntry() << " nentries:" << bcd.ref.getEntries(); convertDigits(bcd, channels, lut); } } @@ -77,7 +76,6 @@ void Digits2Raw::convertDigits(o2::fv0::BCData bcdigits, gsl::span<const Channel int prevPmLink = -1; int iChannelPerLink = 0; int nch = pmchannels.size(); - std::stringstream ss; ss << " Number of channels: " << nch << " (Ch, PMT, Q, T)\n"; for (int ich = 0; ich < nch; ich++) { @@ -118,18 +116,30 @@ void Digits2Raw::convertDigits(o2::fv0::BCData bcdigits, gsl::span<const Channel makeGBTHeader(mRawEventData.mEventHeader, sTcmLink, intRecord); mRawEventData.mEventHeader.nGBTWords = 1; auto& tcmdata = mRawEventData.mTCMdata; - tcmdata.vertex = 1; + /* tcmdata.orA = 1; tcmdata.orC = 0; tcmdata.sCen = 0; tcmdata.cen = 0; + tcmdata.vertex = 1; + */ tcmdata.nChanA = 0; tcmdata.nChanC = 0; tcmdata.amplA = 0; + tcmdata.amplC = 0; tcmdata.timeA = 0; tcmdata.timeC = 0; - + //Temporary for tests + tcmdata.orA = bool(bcdigits.mTriggers.triggerSignals & (1 << 0)); + tcmdata.orC = bool(bcdigits.mTriggers.triggerSignals & (1 << 1)); + tcmdata.sCen = bool(bcdigits.mTriggers.triggerSignals & (1 << 2)); + tcmdata.cen = bool(bcdigits.mTriggers.triggerSignals & (1 << 3)); + tcmdata.vertex = bool(bcdigits.mTriggers.triggerSignals & (1 << 4)); + tcmdata.laser = bool(bcdigits.mTriggers.triggerSignals & (1 << 5)); + tcmdata.nChanA = bcdigits.mTriggers.nChanA; + tcmdata.amplA = bcdigits.mTriggers.amplA; + // auto data = mRawEventData.to_vector(kTRUE); //for tcm module uint32_t linkId = uint32_t(sTcmLink); uint64_t feeId = uint64_t(sTcmLink); diff --git a/Detectors/FIT/FV0/simulation/src/FV0DigParam.cxx b/Detectors/FIT/FV0/simulation/src/FV0DigParam.cxx index 2b7bcd0888e66..9ad7f1cd73b86 100644 --- a/Detectors/FIT/FV0/simulation/src/FV0DigParam.cxx +++ b/Detectors/FIT/FV0/simulation/src/FV0DigParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/simulation/src/FV0SimulationLinkDef.h b/Detectors/FIT/FV0/simulation/src/FV0SimulationLinkDef.h index 96ff6069e78ba..9b98240214702 100644 --- a/Detectors/FIT/FV0/simulation/src/FV0SimulationLinkDef.h +++ b/Detectors/FIT/FV0/simulation/src/FV0SimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/simulation/src/digit2raw.cxx b/Detectors/FIT/FV0/simulation/src/digit2raw.cxx index 00d615a5ec5f0..9dd17e40857a8 100644 --- a/Detectors/FIT/FV0/simulation/src/digit2raw.cxx +++ b/Detectors/FIT/FV0/simulation/src/digit2raw.cxx @@ -1,42 +1,43 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file digi2raw.cxx +/// \file digit2raw.cxx /// \author ruben.shahoyan@cern.ch #include <boost/program_options.hpp> -#include <TSystem.h> +#include <filesystem> #include <TFile.h> #include <TStopwatch.h> +#include "Framework/Logger.h" #include <string> #include <iomanip> -#include "Framework/Logger.h" -#include "FairLogger.h" #include "CommonUtils/StringUtils.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DetectorsRaw/HBFUtils.h" -#include "FV0Simulation/Digits2Raw.h" +#include "FV0Raw/RawWriterFV0.h" +#include "DataFormatsParameters/GRPObject.h" /// MC->raw conversion for FV0 namespace bpo = boost::program_options; -void digi2raw(const std::string& inpName, const std::string& outDir, bool filePerLink, uint32_t rdhV = 6, bool noEmptyHBF = false, - int superPageSizeInB = 1024 * 1024); +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, + const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) { bpo::variables_map vm; bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + - " (Convert FV0 digits to CRU raw data)\n"); + "Convert FV0 digits to CRU raw data\n"); bpo::options_description opt_hidden(""); bpo::options_description opt_all; bpo::positional_options_description opt_pos; @@ -44,15 +45,19 @@ int main(int argc, char** argv) try { auto add_option = opt_general.add_options(); add_option("help,h", "Print this help message"); + add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); // add_option("input-file,i", bpo::value<std::string>()->default_value(o2::base::NameConf::getDigitsFileName(o2::detectors::DetID::FV0)),"input FV0 digits file"); // why not used? add_option("input-file,i", bpo::value<std::string>()->default_value("fv0digits.root"), "input FV0 digits file"); - add_option("file-per-link,l", bpo::value<bool>()->default_value(false)->implicit_value(true), "create output file per CRU (default: per layer)"); + add_option("flp-name", bpo::value<std::string>()->default_value("alio2-cr1-flp180-fv0"), "single file per: all,flp,cru,link"); //temporary, beacause FIT deployed only on one node + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,flp,cru,link"); add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); - + add_option("ccdb-path", bpo::value<std::string>()->default_value(""), "CCDB url which contains LookupTable"); + add_option("lut-path", bpo::value<std::string>()->default_value(""), "LookupTable path, e.g. FV0/LookupTable"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -71,43 +76,58 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); - digi2raw(vm["input-file"].as<std::string>(), - vm["output-dir"].as<std::string>(), - vm["file-per-link"].as<bool>(), - vm["rdh-version"].as<uint32_t>(), - vm["no-empty-hbf"].as<bool>()); + digit2raw(vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["verbosity"].as<int>(), + vm["file-for"].as<std::string>(), + vm["rdh-version"].as<uint32_t>(), + vm["no-empty-hbf"].as<bool>(), + vm["flp-name"].as<std::string>(), + vm["ccdb-path"].as<std::string>(), + vm["lut-path"].as<std::string>()); + + o2::raw::HBFUtils::Instance().print(); return 0; } -void digi2raw(const std::string& inpName, const std::string& outDir, bool filePerLink, uint32_t rdhV, bool noEmptyHBF, int superPageSizeInB) +void digit2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, bool noEmptyHBF, const std::string& flpName, const std::string& ccdbUrl, const std::string& lutPath, int superPageSizeInB) { TStopwatch swTot; swTot.Start(); - o2::fv0::Digits2Raw m2r; - m2r.setFilePerLink(filePerLink); + o2::fv0::RawWriterFV0 m2r; + m2r.setFileFor(fileFor); + m2r.setFlpName(flpName); + m2r.setVerbosity(verbosity); + if (ccdbUrl != "") { + m2r.setCCDBurl(ccdbUrl); + } + if (lutPath != "") { + m2r.setLUTpath(lutPath); + } auto& wr = m2r.getWriter(); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + wr.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::FV0)); // must be set explicitly wr.setSuperPageSize(superPageSizeInB); wr.useRDHVersion(rdhV); wr.setDontFillEmptyHBF(noEmptyHBF); + o2::raw::assertOutputDirectory(outDir); + std::string outDirName(outDir); if (outDirName.back() != '/') { outDirName += '/'; } - // if needed, create output directory - if (gSystem->AccessPathName(outDirName.c_str())) { - if (gSystem->mkdir(outDirName.c_str(), kTRUE)) { - LOG(FATAL) << "could not create output directory " << outDirName; - } else { - LOG(INFO) << "created output directory " << outDirName; - } - } - m2r.readDigits(outDirName, inpName); - wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); - //LOG(INFO)<<o2::utils::concat_string(outDirName, wr.getOrigin().str)<<"\n"; + m2r.convertDigitsToRaw(outDirName, inpName); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); // swTot.Stop(); swTot.Print(); diff --git a/Detectors/FIT/FV0/workflow/CMakeLists.txt b/Detectors/FIT/FV0/workflow/CMakeLists.txt index 6166157112792..4ebf0f0efab16 100644 --- a/Detectors/FIT/FV0/workflow/CMakeLists.txt +++ b/Detectors/FIT/FV0/workflow/CMakeLists.txt @@ -1,22 +1,34 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FV0Workflow - SOURCES src/EntropyEncoderSpec.cxx + SOURCES src/RecoWorkflow.cxx + src/ReconstructionSpec.cxx + src/RecPointWriterSpec.cxx + src/RecPointReaderSpec.cxx + src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx src/DigitReaderSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsFV0 O2::FV0Reconstruction O2::DetectorsCommonDataFormats - O2::DPLUtils) + O2::DPLUtils + O2::FV0Raw) + +o2_add_executable(reco-workflow + SOURCES src/fv0-reco-workflow.cxx + COMPONENT_NAME fv0 + PUBLIC_LINK_LIBRARIES O2::FV0Workflow + TARGETVARNAME fv0recoexe) o2_add_executable(entropy-encoder-workflow SOURCES src/entropy-encoder-workflow.cxx @@ -28,6 +40,15 @@ o2_add_executable(digit-reader-workflow COMPONENT_NAME fv0 PUBLIC_LINK_LIBRARIES O2::FV0Workflow) +o2_add_executable(flp-dpl-workflow + COMPONENT_NAME fv0 + SOURCES src/fv0-flp-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::FV0Workflow O2::FITWorkflow O2::FV0Raw + TARGETVARNAME fv0flpexe) + if(NOT APPLE) + set_property(TARGET ${fitrecoexe} PROPERTY LINK_WHAT_YOU_USE ON) -endif() + +endif() + diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/DigitReaderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/DigitReaderSpec.h index 7a71ae588a030..9d90d3b0859b3 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/DigitReaderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/DigitReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h index 744ad441effca..adc21637b2e10 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h index 0b38260cad14f..48660a01a99f4 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointReaderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointReaderSpec.h new file mode 100644 index 0000000000000..9d7c256ec9be4 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointReaderSpec.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecPointReaderSpec.h + +#ifndef O2_FV0_RECPOINTREADER +#define O2_FV0_RECPOINTREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/RootSerializationSupport.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsFV0/RecPoints.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fv0 +{ + +class RecPointReader : public Task +{ + public: + RecPointReader(bool useMC = true); + ~RecPointReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + o2::header::DataOrigin mOrigin = o2::header::gDataOriginFV0; + + std::vector<o2::fv0::RecPoints>* mRecPoints = nullptr; + std::vector<o2::fv0::ChannelDataFloat>* mChannelData = nullptr; + + std::string mInputFileName = "o2reco_fv0.root"; + std::string mRecPointTreeName = "o2sim"; + std::string mRecPointBranchName = "FV0Cluster"; + std::string mChannelDataBranchName = "FV0RecChData"; +}; + +/// create a processor spec +/// read simulated ITS digits from a root file +framework::DataProcessorSpec getRecPointReaderSpec(bool useMC); + +} // namespace fv0 +} // namespace o2 + +#endif /* O2_FV0_RECPOINTREADER */ diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointWriterSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointWriterSpec.h new file mode 100644 index 0000000000000..e5292229d03e1 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecPointWriterSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecPointWriterSpec.h + +#ifndef O2_FV0RECPOINTWRITER_H +#define O2_FV0RECPOINTWRITER_H + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fv0 +{ + +/// create a processor spec +framework::DataProcessorSpec getRecPointWriterSpec(bool useMC); + +} // namespace fv0 +} // namespace o2 + +#endif /* O2_FV0RECPOINTWRITER_H */ diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h new file mode 100644 index 0000000000000..9bb01f0a78118 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FV0_RECOWORKFLOW_H +#define O2_FV0_RECOWORKFLOW_H + +/// @file RecoWorkflow.h + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace fv0 +{ +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool disableRootInp, bool disableRootOut); +} // namespace fv0 +} // namespace o2 +#endif diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h new file mode 100644 index 0000000000000..d76b5dd84cf23 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ReconstructionSpec.h + +#ifndef O2_FV0RECONSTRUCTORDPL_H +#define O2_FV0RECONSTRUCTORDPL_H + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "FV0Reconstruction/BaseRecoTask.h" +#include "DataFormatsFV0/RecPoints.h" +#include "CCDB/BasicCCDBManager.h" +#include "FV0Base/Constants.h" +#include "TStopwatch.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fv0 +{ + +class ReconstructionDPL : public Task +{ + static constexpr int NCHANNELS = o2::fv0::Constants::nFv0Channels; + + public: + ReconstructionDPL(bool useMC, const std::string ccdbpath) : mUseMC(useMC), mCCDBpath(ccdbpath) {} + ~ReconstructionDPL() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + bool mUseMC = true; + std::string mCCDBpath = "http://o2-ccdb.internal/"; + std::vector<o2::fv0::RecPoints> mRecPoints; + std::vector<o2::fv0::ChannelDataFloat> mRecChData; + o2::fv0::BaseRecoTask mReco; + o2::header::DataOrigin mOrigin = o2::header::gDataOriginFV0; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getReconstructionSpec(bool useMC = true, const std::string ccdbpath = "http://o2-ccdb.internal/"); + +} // namespace fv0 +} // namespace o2 + +#endif /* O2_FV0RECONSTRUCTORDPL_H */ diff --git a/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx index 781950909edc1..f70138a2ca112 100644 --- a/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/MCLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -32,7 +34,8 @@ namespace fv0 void DigitReader::init(InitContext& ic) { - auto filename = ic.options().get<std::string>("fv0-digit-infile"); + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("fv0-digit-infile")); mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); if (!mFile->IsOpen()) { LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; @@ -85,7 +88,8 @@ DataProcessorSpec getDigitReaderSpec(bool useMC) outputs, AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, Options{ - {"fv0-digit-infile", VariantType::String, "fv0digits.root", {"Name of the input file"}}}}; + {"fv0-digit-infile", VariantType::String, "fv0digits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace fv0 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx index 6f5cb5b0b3a06..1b836995c0b28 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("fv0-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -72,7 +73,7 @@ DataProcessorSpec getEntropyDecoderSpec() Inputs{InputSpec{"ctf", "FV0", "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"fv0-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace fv0 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx index ff8f7bd5f6c5a..b1a648385e3e9 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("fv0-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -71,7 +72,7 @@ DataProcessorSpec getEntropyEncoderSpec() inputs, Outputs{{"FV0", "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"fv0-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace fv0 diff --git a/Detectors/FIT/FV0/workflow/src/RecPointReaderSpec.cxx b/Detectors/FIT/FV0/workflow/src/RecPointReaderSpec.cxx new file mode 100644 index 0000000000000..1ba56f3e4b170 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/RecPointReaderSpec.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecPointReaderSpec.cxx + +#include <vector> + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "FV0Workflow/RecPointReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::fv0; + +namespace o2 +{ +namespace fv0 +{ + +RecPointReader::RecPointReader(bool useMC) +{ + mUseMC = useMC; + if (useMC) { + LOG(WARNING) << "FV0 RecPoint reader at the moment does not process MC"; + } +} + +void RecPointReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("fv0-recpoints-infile")); + connectTree(mInputFileName); +} + +void RecPointReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + + LOG(INFO) << "FV0 RecPointReader pushes " << mRecPoints->size() << " recpoints with " << mChannelData->size() << " channels at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "RECPOINTS", 0, Lifetime::Timeframe}, *mRecPoints); + pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0, Lifetime::Timeframe}, *mChannelData); + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void RecPointReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mRecPointTreeName.c_str())); + assert(mTree); + + mTree->SetBranchAddress(mRecPointBranchName.c_str(), &mRecPoints); + mTree->SetBranchAddress(mChannelDataBranchName.c_str(), &mChannelData); + if (mUseMC) { + LOG(WARNING) << "MC-truth is not supported for FV0 recpoints currently"; + mUseMC = false; + } + + LOG(INFO) << "Loaded FV0 RecPoints tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getRecPointReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back(o2::header::gDataOriginFV0, "RECPOINTS", 0, Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFV0, "RECCHDATA", 0, Lifetime::Timeframe); + if (useMC) { + LOG(WARNING) << "MC-truth is not supported for FV0 recpoints currently"; + } + + return DataProcessorSpec{ + "fv0-recpoints-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<RecPointReader>()}, + Options{ + {"fv0-recpoints-infile", VariantType::String, "o2reco_fv0.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace fv0 +} // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/RecPointWriterSpec.cxx b/Detectors/FIT/FV0/workflow/src/RecPointWriterSpec.cxx new file mode 100644 index 0000000000000..ad7cda3435a9a --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/RecPointWriterSpec.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecPointWriterSpec.cxx + +#include <vector> + +#include "FV0Workflow/RecPointWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsFV0/RecPoints.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fv0 +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +DataProcessorSpec getRecPointWriterSpec(bool useMC) +{ + using RecPointsType = std::vector<o2::fv0::RecPoints>; + using ChanDataType = std::vector<o2::fv0::ChannelDataFloat>; + // Spectators for logging + auto logger = [](RecPointsType const& recPoints) { + LOG(INFO) << "FT0RecPointWriter pulled " << recPoints.size() << " RecPoints"; + }; + return MakeRootTreeWriterSpec("fv0-recpoint-writer", + "o2reco_fv0.root", + "o2sim", + BranchDefinition<RecPointsType>{InputSpec{"recPoints", "FV0", "RECPOINTS", 0}, + "FV0Cluster", + "fv0-recpoint-branch-name", + 1, + logger}, + BranchDefinition<ChanDataType>{InputSpec{"recChData", "FV0", "RECCHDATA", 0}, + "FV0RecChData", + "fv0-rechhdata-branch-name"})(); +} + +} // namespace fv0 +} // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx new file mode 100644 index 0000000000000..2c93c9ae822a6 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecoWorkflow.cxx + +#include "FV0Workflow/RecoWorkflow.h" + +#include "FV0Workflow/DigitReaderSpec.h" +#include "FV0Workflow/RecPointWriterSpec.h" +#include "FV0Workflow/ReconstructionSpec.h" + +namespace o2 +{ +namespace fv0 +{ + +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool disableRootInp, bool disableRootOut) +{ + framework::WorkflowSpec specs; + if (!disableRootInp) { + specs.emplace_back(o2::fv0::getDigitReaderSpec(useMC)); + } + + specs.emplace_back(o2::fv0::getReconstructionSpec(useMC, ccdbpath)); + if (!disableRootOut) { + specs.emplace_back(o2::fv0::getRecPointWriterSpec(useMC)); + } + return specs; +} + +} // namespace fv0 +} // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx new file mode 100644 index 0000000000000..f82c3a0017df5 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ReconstructionSpec.cxx + +#include <vector> +#include "SimulationDataFormat/MCTruthContainer.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "FV0Workflow/ReconstructionSpec.h" +#include "DataFormatsFV0/BCData.h" +#include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFV0/MCLabel.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace fv0 +{ + +void ReconstructionDPL::init(InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); + LOG(INFO) << "ReconstructionDPL::init"; +} + +void ReconstructionDPL::run(ProcessingContext& pc) +{ + auto& mCCDBManager = o2::ccdb::BasicCCDBManager::instance(); + // mCCDBManager.setURL("http://ccdb-test.cern.ch:8080"); + mCCDBManager.setURL(mCCDBpath); + LOG(INFO) << " set-up CCDB " << mCCDBpath; + mTimer.Start(false); + mRecPoints.clear(); + auto digits = pc.inputs().get<gsl::span<o2::fv0::BCData>>("digits"); + auto digch = pc.inputs().get<gsl::span<o2::fv0::ChannelData>>("digch"); + // RS: if we need to process MC truth, uncomment lines below + //std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>> labels; + //const o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>* lblPtr = nullptr; + if (mUseMC) { + // labels = pc.inputs().get<const o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>*>("labels"); + // lblPtr = labels.get(); + LOG(INFO) << "Ignoring MC info"; + } + auto caliboffsets = mCCDBManager.get<o2::fv0::FV0ChannelTimeCalibrationObject>("FV0/Calibration/ChannelTimeOffset"); + mReco.setChannelOffset(caliboffsets); + int nDig = digits.size(); + LOG(INFO) << " nDig " << nDig << " | ndigch " << digch.size(); + mRecPoints.reserve(nDig); + mRecChData.resize(digch.size()); + for (int id = 0; id < nDig; id++) { + const auto& digit = digits[id]; + LOG(INFO) << " ndig " << id << " bc " << digit.getIntRecord().bc << " orbit " << digit.getIntRecord().orbit; + auto channels = digit.getBunchChannelData(digch); + gsl::span<o2::fv0::ChannelDataFloat> out_ch(mRecChData); + out_ch = out_ch.subspan(digit.ref.getFirstEntry(), digit.ref.getEntries()); + mRecPoints.emplace_back(mReco.process(digit, channels, out_ch)); + } + + LOG(DEBUG) << "FV0 reconstruction pushes " << mRecPoints.size() << " RecPoints"; + pc.outputs().snapshot(Output{mOrigin, "RECPOINTS", 0, Lifetime::Timeframe}, mRecPoints); + pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0, Lifetime::Timeframe}, mRecChData); + + mTimer.Stop(); +} + +void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "FV0 reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) +{ + std::vector<InputSpec> inputSpec; + std::vector<OutputSpec> outputSpec; + inputSpec.emplace_back("digits", o2::header::gDataOriginFV0, "DIGITSBC", 0, Lifetime::Timeframe); + inputSpec.emplace_back("digch", o2::header::gDataOriginFV0, "DIGITSCH", 0, Lifetime::Timeframe); + if (useMC) { + LOG(INFO) << "Currently Reconstruction does not consume and provide MC truth"; + inputSpec.emplace_back("labels", o2::header::gDataOriginFV0, "DIGITSMCTR", 0, Lifetime::Timeframe); + } + outputSpec.emplace_back(o2::header::gDataOriginFV0, "RECPOINTS", 0, Lifetime::Timeframe); + outputSpec.emplace_back(o2::header::gDataOriginFV0, "RECCHDATA", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "fv0-reconstructor", + inputSpec, + outputSpec, + AlgorithmSpec{adaptFromTask<ReconstructionDPL>(useMC, ccdbpath)}, + Options{}}; +} + +} // namespace fv0 +} // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/digits-reader-workflow.cxx b/Detectors/FIT/FV0/workflow/src/digits-reader-workflow.cxx index a833355c2bb9b..064c50a076f18 100644 --- a/Detectors/FIT/FV0/workflow/src/digits-reader-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/digits-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(const ConfigContext& ctx) { WorkflowSpec specs; - + o2::conf::ConfigurableParam::updateFromString(ctx.options().get<std::string>("configKeyValues")); DataProcessorSpec producer = o2::fv0::getDigitReaderSpec(ctx.options().get<bool>("disable-mc")); specs.push_back(producer); return specs; diff --git a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx index 58455959b0854..06800f6fa0453 100644 --- a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/FV0/workflow/src/fv0-flp-workflow.cxx b/Detectors/FIT/FV0/workflow/src/fv0-flp-workflow.cxx new file mode 100644 index 0000000000000..68b88e7aa2913 --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/fv0-flp-workflow.cxx @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "FITWorkflow/FITDataReaderDPLSpec.h" +#include "FITWorkflow/FITDigitWriterSpec.h" +#include "FITWorkflow/RawReaderFIT.h" +#include "DataFormatsFV0/MCLabel.h" +#include "FV0Raw/RawReaderFV0Base.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back( + ConfigParamSpec{"tcm-extended-mode", + o2::framework::VariantType::Bool, + false, + {"in case of extended TCM mode (1 header + 1 TCMdata + 8 " + "TCMdataExtended)"}}); + + workflowOptions.push_back( + ConfigParamSpec{"dump-blocks-reader", + o2::framework::VariantType::Bool, + false, + {"enable dumping of event blocks at reader side"}}); + workflowOptions.push_back( + ConfigParamSpec{"disable-root-output", + o2::framework::VariantType::Bool, + false, + {"disable root-files output writers"}}); + workflowOptions.push_back( + ConfigParamSpec{"configKeyValues", + o2::framework::VariantType::String, + "", + {"Semicolon separated key=value strings"}}); + workflowOptions.push_back( + ConfigParamSpec{"ignore-dist-stf", + o2::framework::VariantType::Bool, + false, + {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + LOG(INFO) << "WorkflowSpec defineDataProcessing"; + auto dumpReader = configcontext.options().get<bool>("dump-blocks-reader"); + auto isExtendedMode = configcontext.options().get<bool>("tcm-extended-mode"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto askSTFDist = !configcontext.options().get<bool>("ignore-dist-stf"); + LOG(INFO) << "WorkflowSpec FLPWorkflow"; + //Type aliases + //using RawReaderFV0trgInput = o2::fit::RawReaderFIT<o2::fv0::RawReaderFV0BaseNorm,true>; + using RawReaderFV0 = o2::fit::RawReaderFIT<o2::fv0::RawReaderFV0BaseNorm, false>; + //using RawReaderFV0trgInputExt = o2::fit::RawReaderFIT<o2::fv0::RawReaderFV0BaseExt,true>; + using RawReaderFV0ext = o2::fit::RawReaderFIT<o2::fv0::RawReaderFV0BaseExt, false>; + using MCLabelCont = o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>; + o2::header::DataOrigin dataOrigin = o2::header::gDataOriginFV0; + // + WorkflowSpec specs; + if (isExtendedMode) { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFV0ext{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFV0ext, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } else { + specs.emplace_back(o2::fit::getFITDataReaderDPLSpec(RawReaderFV0{dataOrigin, dumpReader}, askSTFDist)); + if (!disableRootOut) { + specs.emplace_back(o2::fit::FITDigitWriterSpecHelper<RawReaderFV0, MCLabelCont>::getFITDigitWriterSpec(false, false, dataOrigin)); + } + } + return std::move(specs); +} diff --git a/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx new file mode 100644 index 0000000000000..17c59742bad6c --- /dev/null +++ b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FV0Workflow/RecoWorkflow.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"ccdb-path-fv0", o2::framework::VariantType::String, "http://o2-ccdb.internal/", {"CCDB path"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + LOG(INFO) << "WorkflowSpec defineDataProcessing"; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the digitizer workflow + o2::conf::ConfigurableParam::writeINI("o2-fv0-recoflow_configuration.ini"); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto ccdbpath = configcontext.options().get<std::string>("ccdb-path-fv0"); + auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + + LOG(INFO) << "WorkflowSpec getRecoWorkflow useMC " << useMC; + auto wf = o2::fv0::getRecoWorkflow(useMC, ccdbpath, disableRootInp, disableRootOut); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); +} diff --git a/Detectors/FIT/README.md b/Detectors/FIT/README.md index 87c8647513541..b079dce2cc972 100644 --- a/Detectors/FIT/README.md +++ b/Detectors/FIT/README.md @@ -8,5 +8,7 @@ This is a top page for the FIT detector documentation. <!-- doxy * \subpage refFITbenchmark +* \subpage refFITcommoncalibration * \subpage refFITFT0workflow +* \subpage refFITraw /doxy --> diff --git a/Detectors/FIT/benchmark/README.md b/Detectors/FIT/benchmark/README.md index 9ae77dfc379ac..135c207357a8b 100644 --- a/Detectors/FIT/benchmark/README.md +++ b/Detectors/FIT/benchmark/README.md @@ -22,7 +22,7 @@ To obtain plots of (FairMQ) devices operating in the simulation you will have to e.g. if you wish to monitor 50 pp (pythia) events with Geant3 as the VMC backend using the FIT detector and utilizing parallel mode with 2 simulation workers AND keep track of FairMQ devices, you can do: -`$> ./monitor.sh o2-sim -g pythia8 -e TGeant3 -m FV0 FT0 FDD -j 2 -n 50 | tee o2sim.log` +`$> ./monitor.sh o2-sim -g pythia8pp -e TGeant3 -m FV0 FT0 FDD -j 2 -n 50 | tee o2sim.log` --- @@ -40,7 +40,7 @@ The monitored data has to be processed as: This will generate an output: -```Your command was: o2-sim -g pythia8 -e TGeant3 -m FV0 FT0 FDD -j 2 -n 50 +```Your command was: o2-sim -g pythia8pp -e TGeant3 -m FV0 FT0 FDD -j 2 -n 50 You have monitored o2 simulation in parallel. ******************************** diff --git a/Detectors/FIT/common/CMakeLists.txt b/Detectors/FIT/common/CMakeLists.txt index 59c9eaeee3ac7..5a919c69af898 100644 --- a/Detectors/FIT/common/CMakeLists.txt +++ b/Detectors/FIT/common/CMakeLists.txt @@ -1,11 +1,14 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # add_subdirectory(simulation) + +add_subdirectory(calibration) \ No newline at end of file diff --git a/Detectors/FIT/common/calibration/CMakeLists.txt b/Detectors/FIT/common/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..ad4cb5ac9a218 --- /dev/null +++ b/Detectors/FIT/common/calibration/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FITCalibration + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration + O2::FV0Calibration + O2::DataFormatsFT0 + O2::Framework + O2::CCDB + O2::DetectorsCalibration + ROOT::Minuit + Microsoft.GSL::GSL + ) +# +# +o2_target_root_dictionary(FITCalibration + HEADERS + include/FITCalibration/FITCalibrator.h + include/FITCalibration/FITCalibrationDevice.h + include/FITCalibration/FITCalibrationObjectProducer.h + include/FITCalibration/FITCalibrationApi.h + ) + diff --git a/Detectors/FIT/common/calibration/README.md b/Detectors/FIT/common/calibration/README.md new file mode 100644 index 0000000000000..9cfacecca9f84 --- /dev/null +++ b/Detectors/FIT/common/calibration/README.md @@ -0,0 +1,40 @@ +<!-- doxy +\page refFITcommoncalibration Calibration workflow +/doxy --> + +## FIT Calibration workflow + +###Overview +The module was implemented in a generic way. Adding new calibration object should be easy and intuitive. Calibration device uses https://github.com/AliceO2Group/AliceO2/tree/dev/Detectors/Calibration for TimeFrame management (see link above for more detailed information). + +###How to use TimeSlotCalibration? +####It is required to define classes listed below to be able to use prepared TimeSlotCalibration module. +- TimeSlot Container class (for current state of the code, example - `FT0ChannelTimeTimeSlotContainer`). Container is responsible for data storage (CFDTime, Charge, etc.) and providing data for calibration object generation +- Calibration Info Object class (for current state of the code, example - `FT0CalibrationInfoObject`). This class is responsible for providing input data which will be saved in TimeSlot Container instance. (so we can assume it's simplified channel data type, with extracted data that will be required for calibration process) +- Calibration Object class (for current state of the code, example - `FT0ChannelTimeCalibrationObject`, `FT0DummyCalibrationObject`) - representing correction values + +To conclude, data stored in calibration info object is required to fill TimeSlot container with data and that data stored in the container is needed to generate calibration object. + +###Implementation details +FITCalibration module is based on templates, so it can be used for FT0, FDD and FV0 calibration workflows. One has to define definition of the classes described above and also provide formula for calibration object generation. + +###How to add new code, new calibration object? +- Define your calibration object class (can be combined more than one into one class) +- Define your timeslot container class (can be used for many calibration objects) +- Define algorithm / function for calibration object generation. Add template specialization with your classes in `FITCalibrationObjectProducer` `generateCalibrationObject` method +- Add template specialization for calibration object in `FitCalibrationApi`, define ccdb calib object path and also recipe how to store them in CCDB +- Create separated workflow or add your `DataProcessorSpec` to main calibration workflow + +For example check `FT0CalibrationDummy-Workflow` which uses combined calibration object. It is also uses mechanism to retrieve (from CCDB) another calibration object needed for calibration. Before running this workflow it is required to run `makeDummyFt0CalibObjectInCCDB` macro to generate dummy object in the local CCDB instance. + +###How to run these workflows? +- Dummy: +`root -l ~/alice/O2/Detectors/FIT/FT0/calibration/macros/makeDummyFT0CalibObjectInCCDB.C+` + `o2-ft0-digits-reader-workflow | o2-calibration-ft0-tf-processor | o2-calibration-ft0-dummy-example | o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 -b` +- Channel Time calibration: +`o2-ft0-digits-reader-workflow | o2-calibration-ft0-tf-processor | o2-calibration-ft0-channel-offset-calibration | o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 -` + +- General calibration workflow (for now, the same as Channel Time calibration) +`o2-ft0-digits-reader-workflow | o2-calibration-ft0-tf-processor | o2-calibration-ft0-calibration | o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 -b` + +You have to specify path to digits file in `o2-ft0-digits-reader-workflow`. If you don't need to store generated calib object you can delete last workflow part (`o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 -b`) \ No newline at end of file diff --git a/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationApi.h b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationApi.h new file mode 100644 index 0000000000000..3c681b0ae444f --- /dev/null +++ b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationApi.h @@ -0,0 +1,227 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FITCALIBRATIONAPI_H +#define O2_FITCALIBRATIONAPI_H + +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "FT0Calibration/FT0DummyCalibrationObject.h" //delete this when example not needed anymore +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Calibration/FT0CalibTimeSlewing.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CCDB/BasicCCDBManager.h" +#include <vector> +#include "DataFormatsFT0/GlobalOffsetsCalibrationObject.h" +#include "DataFormatsFT0/GlobalOffsetsContainer.h" + +namespace o2::fit +{ +class FITCalibrationApi +{ + private: + static constexpr const char* DEFAULT_CCDB_URL = "http://localhost:8080"; + using CalibObjWithInfoType = std::pair<o2::ccdb::CcdbObjectInfo, std::unique_ptr<std::vector<char>>>; + inline static unsigned long mProcessingTimestamp = 0; + + public: + FITCalibrationApi() = delete; + FITCalibrationApi(const FITCalibrationApi&) = delete; + FITCalibrationApi(FITCalibrationApi&&) = delete; + + static void init(); + static void setProcessingTimestamp(unsigned long tf) + { + LOG(INFO) << "@@@ setProcessingTimestamp " << tf; + mProcessingTimestamp = tf; + } + [[nodiscard]] static unsigned long getProcessingTimestamp() + { + LOG(INFO) << " @@@ getProcessingTimestamp " << mProcessingTimestamp; + return mProcessingTimestamp; + } + + template <typename CalibrationObjectType> + [[nodiscard]] static const char* getObjectPath(); + + template <typename CalibrationObjectType> + [[nodiscard]] static const CalibrationObjectType& getMostRecentCalibrationObject(); + + template <typename CalibrationObjectType> + [[nodiscard]] static const CalibrationObjectType& getCalibrationObjectForGivenTimestamp(long timestamp); + + template <typename CalibrationObjectType> + [[nodiscard]] static std::vector<CalibObjWithInfoType> prepareCalibrationObjectToSend(const CalibrationObjectType& calibrationObject); + + private: + template <typename CalibrationObjectType> + static void handleInvalidCalibrationObjectType(); + + template <typename CalibrationObjectType> + [[nodiscard]] static CalibObjWithInfoType doSerializationAndPrepareObjectInfo(const CalibrationObjectType& calibrationObject); +}; + +inline void FITCalibrationApi::init() +{ + //caching in basicCCDBManager enabled by default + o2::ccdb::BasicCCDBManager::instance().setURL(DEFAULT_CCDB_URL); +} + +template <typename CalibrationObjectType> +void FITCalibrationApi::handleInvalidCalibrationObjectType() +{ + static_assert(sizeof(CalibrationObjectType) == 0, "[FITCalibrationApi] Cannot find specialization provided Calibration Object Type"); +} + +template <typename CalibrationObjectType> +FITCalibrationApi::CalibObjWithInfoType FITCalibrationApi::doSerializationAndPrepareObjectInfo(const CalibrationObjectType& calibrationObject) +{ + static std::map<std::string, std::string> metaData; + static std::string dummyStringVariableThatWillBeChangedAnyway; + + CalibObjWithInfoType result; + result.first = o2::ccdb::CcdbObjectInfo(FITCalibrationApi::getObjectPath<CalibrationObjectType>(), dummyStringVariableThatWillBeChangedAnyway, dummyStringVariableThatWillBeChangedAnyway, metaData, o2::ccdb::getCurrentTimestamp(), -1); + result.second = o2::ccdb::CcdbApi::createObjectImage(&calibrationObject, &result.first); + + return result; +} + +template <typename CalibrationObjectType> +const CalibrationObjectType& FITCalibrationApi::getCalibrationObjectForGivenTimestamp(long timestamp) +{ + + o2::ccdb::BasicCCDBManager::instance().setTimestamp(timestamp); + auto calibObjectPtr = o2::ccdb::BasicCCDBManager::instance().get<CalibrationObjectType>(getObjectPath<CalibrationObjectType>()); + if (nullptr == calibObjectPtr) { + throw std::runtime_error("Cannot read requested calibration object"); + } + return *calibObjectPtr; +} + +template <typename CalibrationObjectType> +const CalibrationObjectType& FITCalibrationApi::getMostRecentCalibrationObject() +{ + return getCalibrationObjectForGivenTimestamp<CalibrationObjectType>(o2::ccdb::getCurrentTimestamp()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template <typename CalibrationObjectType> +std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend(const CalibrationObjectType& calibrationObject) +{ + handleInvalidCalibrationObjectType<CalibrationObjectType>(); + return {}; +} + +template <typename CalibrationObjectType> +const char* FITCalibrationApi::getObjectPath() +{ + handleInvalidCalibrationObjectType<CalibrationObjectType>(); + return {}; +} + +//----FT0----////////////////////////////////////////////////////////////////////////////////////////////////// + +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::FT0ChannelTimeCalibrationObject>() +{ + return "FT0/Calibration/ChannelTimeOffset"; +} + +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::FT0CalibTimeSlewing>() +{ + return "FT0/Calibration/SlewingCorrection"; +} +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::GlobalOffsetsCalibrationObject>() +{ + return "FT0/Calibration/GlobalOffsets"; +} + +template <> +inline std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend<o2::ft0::FT0ChannelTimeCalibrationObject>(const o2::ft0::FT0ChannelTimeCalibrationObject& calibrationObject) +{ + std::vector<CalibObjWithInfoType> result; + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject)); + return result; +} + +template <> +inline std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend<o2::ft0::FT0CalibTimeSlewing>(const o2::ft0::FT0CalibTimeSlewing& calibrationObject) +{ + std::vector<CalibObjWithInfoType> result; + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject)); + return result; +} + +//----FV0----////////////////////////////////////////////////////////////////////////////////////////////////// + +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::fv0::FV0ChannelTimeCalibrationObject>() +{ + return "FV0/Calibration/ChannelTimeOffset"; +} + +template <> +inline std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend<o2::fv0::FV0ChannelTimeCalibrationObject>(const o2::fv0::FV0ChannelTimeCalibrationObject& calibrationObject) +{ + std::vector<CalibObjWithInfoType> result; + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject)); + return result; +} + +template <> +inline std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend<o2::ft0::GlobalOffsetsCalibrationObject>(const o2::ft0::GlobalOffsetsCalibrationObject& calibrationObject) +{ + std::vector<CalibObjWithInfoType> result; + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject)); + return result; +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// DUMMY STUFF DELETE IT WHEN EXAMPLE NOT NEEDED ANYMORE +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::FT0DummyCalibrationObjectTime>() +{ + return "FT0/Calibration/DummyTime"; +} + +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::FT0DummyCalibrationObjectCharge>() +{ + return "FT0/Calibration/DummyCharge"; +} + +template <> +inline const char* FITCalibrationApi::getObjectPath<o2::ft0::FT0DummyNeededCalibrationObject>() +{ + return "FT0/Calibration/DummyNeeded"; +} + +template <> +inline std::vector<FITCalibrationApi::CalibObjWithInfoType> FITCalibrationApi::prepareCalibrationObjectToSend<o2::ft0::FT0DummyCalibrationObject>(const o2::ft0::FT0DummyCalibrationObject& calibrationObject) +{ + std::vector<CalibObjWithInfoType> result; + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject.mChargeCalibrationObject)); + result.emplace_back(doSerializationAndPrepareObjectInfo(calibrationObject.mTimeCalibrationObject)); + return result; +} + +// END OF DUMMY STUFF DELETE IT WHEN EXAMPLE NOT NEEDED ANYMORE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace o2::fit + +#endif //O2_FITCALIBRATIONAPI_H diff --git a/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationDevice.h b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationDevice.h new file mode 100644 index 0000000000000..f76dd2f72f606 --- /dev/null +++ b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationDevice.h @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FITCALIBRATIONDEVICE_H +#define O2_FITCALIBRATIONDEVICE_H + +#include <utility> + +#include "FITCalibration/FITCalibrator.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" + +namespace o2::fit +{ + +#define FIT_CALIBRATION_DEVICE_TEMPLATES \ + template <typename InputCalibrationInfoType, typename TimeSlotStorageType, typename CalibrationObjectType> + +#define FIT_CALIBRATION_DEVICE_TYPE \ + FITCalibrationDevice<InputCalibrationInfoType, TimeSlotStorageType, CalibrationObjectType> + +FIT_CALIBRATION_DEVICE_TEMPLATES +class FITCalibrationDevice : public o2::framework::Task +{ + + static constexpr const char* DEFAULT_INPUT_DATA_LABEL = "calib"; + using CalibratorType = FITCalibrator<InputCalibrationInfoType, TimeSlotStorageType, CalibrationObjectType>; + + public: + explicit FITCalibrationDevice(std::string inputDataLabel = DEFAULT_INPUT_DATA_LABEL) + : mInputDataLabel(std::move(inputDataLabel)) {} + + void init(o2::framework::InitContext& context) final; + void run(o2::framework::ProcessingContext& context) final; + void endOfStream(o2::framework::EndOfStreamContext& context) final; + + private: + void _sendOutputs(o2::framework::DataAllocator& outputs); + void _sendCalibrationObjectIfSlotFinalized(o2::framework::DataAllocator& outputs); + + private: + const std::string mInputDataLabel; + std::unique_ptr<CalibratorType> mCalibrator; +}; + +FIT_CALIBRATION_DEVICE_TEMPLATES +void FIT_CALIBRATION_DEVICE_TYPE::init(o2::framework::InitContext& context) +{ + mCalibrator = std::make_unique<CalibratorType>(); + FITCalibrationApi::init(); +} + +FIT_CALIBRATION_DEVICE_TEMPLATES +void FIT_CALIBRATION_DEVICE_TYPE::run(o2::framework::ProcessingContext& context) +{ + + auto TFCounter = o2::header::get<o2::framework::DataProcessingHeader*>(context.inputs().get(mInputDataLabel).header)->startTime; + auto data = context.inputs().get<gsl::span<InputCalibrationInfoType>>(mInputDataLabel); + + //something like that probably in the future + // FITCalibrationApi::setProcessingTimestamp( getTimestampForTF(TFCounter)) ); + + mCalibrator->process(TFCounter, data); + _sendCalibrationObjectIfSlotFinalized(context.outputs()); +} + +FIT_CALIBRATION_DEVICE_TEMPLATES +void FIT_CALIBRATION_DEVICE_TYPE::endOfStream(o2::framework::EndOfStreamContext& context) +{ + //nope, we have to check if we can finalize slot anyway - scenario with one batch + static constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + _sendCalibrationObjectIfSlotFinalized(context.outputs()); +} + +FIT_CALIBRATION_DEVICE_TEMPLATES +void FIT_CALIBRATION_DEVICE_TYPE::_sendCalibrationObjectIfSlotFinalized(o2::framework::DataAllocator& outputs) +{ + if (mCalibrator->isCalibrationObjectReadyToSend()) { + _sendOutputs(outputs); + } +} + +FIT_CALIBRATION_DEVICE_TEMPLATES +void FIT_CALIBRATION_DEVICE_TYPE::_sendOutputs(o2::framework::DataAllocator& outputs) +{ + + using clbUtils = o2::calibration::Utils; + const auto& objectsToSend = mCalibrator->getStoredCalibrationObjects(); + + uint32_t iSendChannel = 0; + for (const auto& [ccdbInfo, calibObject] : objectsToSend) { + outputs.snapshot(o2::framework::Output{clbUtils::gDataOriginCDBPayload, "FIT_CALIB", iSendChannel}, *calibObject); + outputs.snapshot(o2::framework::Output{clbUtils::gDataOriginCDBWrapper, "FIT_CALIB", iSendChannel}, ccdbInfo); + ++iSendChannel; + } + mCalibrator->initOutput(); +} + +#undef FIT_CALIBRATION_DEVICE_TEMPLATES +#undef FIT_CALIBRATION_DEVICE_TYPE + +} // namespace o2::fit + +#endif //O2_FITCALIBRATIONDEVICE_H diff --git a/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationObjectProducer.h b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationObjectProducer.h new file mode 100644 index 0000000000000..243a043acad1b --- /dev/null +++ b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrationObjectProducer.h @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FITCALIBRATIONOBJECTPRODUCER_H +#define O2_FITCALIBRATIONOBJECTPRODUCER_H + +#include "FITCalibration/FITCalibrationApi.h" +#include "FT0Calibration/FT0ChannelTimeCalibrationObject.h" +#include "FT0Calibration/FT0ChannelTimeTimeSlotContainer.h" +#include "FT0Calibration/FT0CalibTimeSlewing.h" +#include "FV0Calibration/FV0ChannelTimeCalibrationObject.h" +#include "FV0Calibration/FV0ChannelTimeTimeSlotContainer.h" +#include "FITCalibration/FITCalibrationObjectProducer.h" +#include "FT0Calibration/FT0DummyCalibrationObject.h" // delete this +#include "DataFormatsFT0/GlobalOffsetsCalibrationObject.h" +#include "DataFormatsFT0/GlobalOffsetsContainer.h" + +namespace o2::fit +{ +class FITCalibrationObjectProducer +{ + public: + template <typename CalibrationObjectType, typename TimeSlotContainerType> + static CalibrationObjectType generateCalibrationObject(const TimeSlotContainerType& container); +}; + +template <typename CalibrationObjectType, typename TimeSlotContainerType> +CalibrationObjectType FITCalibrationObjectProducer::generateCalibrationObject(const TimeSlotContainerType& container) +{ + static_assert(sizeof(CalibrationObjectType) == 0, "[FITCalibrationObjectProducer] Cannot find specialization provided Calibration Object Type"); + return {}; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template <> +o2::ft0::FT0ChannelTimeCalibrationObject FITCalibrationObjectProducer::generateCalibrationObject<o2::ft0::FT0ChannelTimeCalibrationObject, o2::ft0::FT0ChannelTimeTimeSlotContainer>(const o2::ft0::FT0ChannelTimeTimeSlotContainer& container) +{ + return o2::ft0::FT0TimeChannelOffsetCalibrationObjectAlgorithm::generateCalibrationObject(container); +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template <> +o2::ft0::GlobalOffsetsCalibrationObject FITCalibrationObjectProducer::generateCalibrationObject<o2::ft0::GlobalOffsetsCalibrationObject, o2::ft0::GlobalOffsetsContainer>(const o2::ft0::GlobalOffsetsContainer& container) +{ + return o2::ft0::GlobalOffsetsCalibrationObjectAlgorithm::generateCalibrationObject(container); +} + +template <> +o2::fv0::FV0ChannelTimeCalibrationObject FITCalibrationObjectProducer::generateCalibrationObject<o2::fv0::FV0ChannelTimeCalibrationObject, o2::fv0::FV0ChannelTimeTimeSlotContainer>(const o2::fv0::FV0ChannelTimeTimeSlotContainer& container) +{ + return o2::fv0::FV0TimeChannelOffsetCalibrationObjectAlgorithm::generateCalibrationObject(container); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// DUMMY STUFF DELETE IT WHEN EXAMPLE NOT NEEDED ANYMORE + +template <> +o2::ft0::FT0DummyCalibrationObject FITCalibrationObjectProducer::generateCalibrationObject<o2::ft0::FT0DummyCalibrationObject, o2::ft0::FT0ChannelTimeTimeSlotContainer>(const o2::ft0::FT0ChannelTimeTimeSlotContainer& container) +{ + //We need additional object here for calibration + const auto& neededObjectForCalibration = FITCalibrationApi::getMostRecentCalibrationObject<o2::ft0::FT0DummyNeededCalibrationObject>(); + // const auto& neededObjectForCalibration = FITCalibrationApi::getCalibrationObjectForGivenTimestamp<o2::ft0::FT0DummyNeededCalibrationObject>(FITCalibrationApi::getProcessingTimestamp()); + return o2::ft0::FT0DummyCalibrationObjectAlgorithm::generateCalibrationObject(container, neededObjectForCalibration); +} + +// END OF DUMMY STUFF DELETE IT WHEN EXAMPLE NOT NEEDED ANYMORE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace o2::fit + +#endif //O2_FITCALIBRATIONOBJECTPRODUCER_H diff --git a/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrator.h b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrator.h new file mode 100644 index 0000000000000..60565afa7e308 --- /dev/null +++ b/Detectors/FIT/common/calibration/include/FITCalibration/FITCalibrator.h @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FITCALIBRATOR_H +#define O2_FITCALIBRATOR_H + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Rtypes.h" +#include "FITCalibration/FITCalibrationObjectProducer.h" +#include "FITCalibration/FITCalibrationApi.h" + +namespace o2::fit +{ + +#define FIT_CALIBRATOR_TEMPLATES \ + template <typename InputCalibrationInfoType, typename TimeSlotStorageType, typename CalibrationObjectType> + +#define FIT_CALIBRATOR_TYPE \ + FITCalibrator<InputCalibrationInfoType, TimeSlotStorageType, CalibrationObjectType> + +FIT_CALIBRATOR_TEMPLATES +class FITCalibrator final : public o2::calibration::TimeSlotCalibration<InputCalibrationInfoType, TimeSlotStorageType> +{ + + //probably will be set via run parameter + static constexpr unsigned int DEFAULT_MIN_ENTRIES = 100; + + //temp param for testing + static constexpr bool DEFAULT_TEST_MODE = true; + + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<TimeSlotStorageType>; + + public: + explicit FITCalibrator(unsigned int minimumEntries = DEFAULT_MIN_ENTRIES, bool testMode = DEFAULT_TEST_MODE); + + ~FITCalibrator() final = default; + + [[nodiscard]] bool hasEnoughData(const Slot& slot) const final; + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + [[nodiscard]] bool isCalibrationObjectReadyToSend() const { return !mStoredCalibrationObjects.empty(); } + [[nodiscard]] const std::vector<std::pair<o2::ccdb::CcdbObjectInfo, std::unique_ptr<std::vector<char>>>>& getStoredCalibrationObjects() const { return mStoredCalibrationObjects; } + + private: + [[nodiscard]] bool _isTestModeEnabled() const { return mTestMode; } + + private: + std::vector<std::pair<o2::ccdb::CcdbObjectInfo, std::unique_ptr<std::vector<char>>>> mStoredCalibrationObjects{}; + const unsigned int mMinEntries; + const bool mTestMode; +}; + +FIT_CALIBRATOR_TEMPLATES +FIT_CALIBRATOR_TYPE::FITCalibrator(unsigned int minimumEntries, bool testMode) + : mMinEntries(minimumEntries), mTestMode(testMode) +{ +} + +FIT_CALIBRATOR_TEMPLATES +bool FIT_CALIBRATOR_TYPE::hasEnoughData(const Slot& slot) const +{ + if (_isTestModeEnabled()) { + static unsigned int testCounter = 0; + ++testCounter; + if (!(testCounter % 1000)) { + return true; + } + } + + return slot.getContainer()->hasEnoughEntries(); +} + +FIT_CALIBRATOR_TEMPLATES +void FIT_CALIBRATOR_TYPE::initOutput() +{ + mStoredCalibrationObjects.clear(); +} + +FIT_CALIBRATOR_TEMPLATES +void FIT_CALIBRATOR_TYPE::finalizeSlot(Slot& slot) +{ + static std::map<std::string, std::string> md; + const auto& container = slot.getContainer(); + + auto calibrationObject = FITCalibrationObjectProducer::generateCalibrationObject<CalibrationObjectType>(*container); + auto preparedCalibObjects = FITCalibrationApi::prepareCalibrationObjectToSend(calibrationObject); + + mStoredCalibrationObjects.insert(mStoredCalibrationObjects.end(), + std::make_move_iterator(preparedCalibObjects.begin()), + std::make_move_iterator(preparedCalibObjects.end())); +} + +FIT_CALIBRATOR_TEMPLATES +typename FIT_CALIBRATOR_TYPE::Slot& FIT_CALIBRATOR_TYPE::emplaceNewSlot( + bool front, TFType tstart, TFType tend) +{ + auto& cont = o2::calibration::TimeSlotCalibration<InputCalibrationInfoType, TimeSlotStorageType>::getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<TimeSlotStorageType>(mMinEntries)); + return slot; +} + +#undef FIT_CALIBRATOR_TEMPLATES +#undef FIT_CALIBRATOR_TYPE + +} // namespace o2::fit + +#endif //O2_FITCALIBRATOR_H diff --git a/Detectors/FIT/common/calibration/src/FITCalibrationLinkDef.h b/Detectors/FIT/common/calibration/src/FITCalibrationLinkDef.h new file mode 100644 index 0000000000000..ed3354774a81d --- /dev/null +++ b/Detectors/FIT/common/calibration/src/FITCalibrationLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::FT0CalibrationInfoObject, o2::ft0::FT0ChannelTimeTimeSlotContainer>; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::fv0::FV0CalibrationInfoObject, o2::fv0::FV0ChannelTimeTimeSlotContainer>; +//#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::FT0CalibrationInfoObject, o2::ft0::FT0SlewingCalibContainer >; + +#endif diff --git a/Detectors/FIT/common/simulation/CMakeLists.txt b/Detectors/FIT/common/simulation/CMakeLists.txt index 3b3ee8a5c24a4..7f25c1b9c0d67 100644 --- a/Detectors/FIT/common/simulation/CMakeLists.txt +++ b/Detectors/FIT/common/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FITSimulation SOURCES src/Digitizer.cxx diff --git a/Detectors/FIT/common/simulation/include/FITSimulation/DigitizationParameters.h b/Detectors/FIT/common/simulation/include/FITSimulation/DigitizationParameters.h index a1c8f5586ffe8..12bf883f4052e 100644 --- a/Detectors/FIT/common/simulation/include/FITSimulation/DigitizationParameters.h +++ b/Detectors/FIT/common/simulation/include/FITSimulation/DigitizationParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/common/simulation/src/FITSimulationLinkDef.h b/Detectors/FIT/common/simulation/src/FITSimulationLinkDef.h index 3873f7bbd8b4b..afbb4ad54a433 100644 --- a/Detectors/FIT/common/simulation/src/FITSimulationLinkDef.h +++ b/Detectors/FIT/common/simulation/src/FITSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/macros/CMakeLists.txt b/Detectors/FIT/macros/CMakeLists.txt index 8dd4aa662d117..8b5f5e9c6e606 100644 --- a/Detectors/FIT/macros/CMakeLists.txt +++ b/Detectors/FIT/macros/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(readFT0hits.C PUBLIC_LINK_LIBRARIES O2::DataFormatsFT0 @@ -14,6 +15,9 @@ o2_add_test_root_macro(readFT0hits.C o2_add_test_root_macro(readFT0digits.C PUBLIC_LINK_LIBRARIES O2::DataFormatsFT0 LABELS fit) +o2_add_test_root_macro(uploadLookUpTable.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsFT0 + LABELS fit) o2_add_test_root_macro(FT0digits2raw.C PUBLIC_LINK_LIBRARIES O2::FT0Simulation O2::DataFormatsFT0 diff --git a/Detectors/FIT/macros/readFT0digits.C b/Detectors/FIT/macros/readFT0digits.C index bc2a4e30783cc..404dec4c09fe3 100644 --- a/Detectors/FIT/macros/readFT0digits.C +++ b/Detectors/FIT/macros/readFT0digits.C @@ -17,12 +17,12 @@ void readFT0digits() TDirectory* cwd = gDirectory; gDirectory = 0x0; - TH2F* hMultDig = new TH2F("hMultDig", "amplitude ", 210, 0, 210, 200, 0, 1000); - TH2F* hTimeDig = new TH2F("hTimeDig", "Time", 210, 0, 210, 100, -100, 100); + TH2F* hMultDig = new TH2F("hMultDig", "amplitude ", 220, 0, 220, 200, 0, 1000); + TH2F* hTimeDig = new TH2F("hTimeDig", "Time", 220, 0, 220, 100, -100, 100); TH2F* hTimeDigMultA = new TH2F("hTimeDigMultA", "Time vs amplitude", 200, 0, 100, 100, -100, 100); TH2F* hTimeDigMultC = new TH2F("hTimeDigMultC", "Time vs amplitude", 200, 0, 100, 100, -100, 100); TH1F* hNchA = new TH1F("hNchA", "FT0-A", 100, 0, 100); - TH1F* hNchC = new TH1F("hNchC", "FT0-C", 100, 0, 100); + TH1F* hNchC = new TH1F("hNchC", "FT0-C", 110, 0, 110); gDirectory = cwd; @@ -35,7 +35,7 @@ void readFT0digits() digTree->SetBranchAddress("FT0DIGITSBC", &ft0BCDataPtr); digTree->SetBranchAddress("FT0DIGITSCH", &ft0ChDataPtr); - float cfd[208], amp[208]; + float cfd[216], amp[216]; for (int ient = 0; ient < digTree->GetEntries(); ient++) { digTree->GetEntry(ient); @@ -43,7 +43,7 @@ void readFT0digits() std::cout << "Entry " << ient << " : " << nbc << " BCs stored" << std::endl; for (int ibc = 0; ibc < nbc; ibc++) { auto& bcd = digitsBC[ibc]; - for (int ii = 0; ii < 208; ii++) { + for (int ii = 0; ii < 216; ii++) { cfd[ii] = amp[ii] = 0; } diff --git a/Detectors/FIT/macros/readFT0hits.C b/Detectors/FIT/macros/readFT0hits.C index 1bf04e9d77cc1..0554b715cbaf7 100644 --- a/Detectors/FIT/macros/readFT0hits.C +++ b/Detectors/FIT/macros/readFT0hits.C @@ -16,12 +16,12 @@ void readFT0hits() gDirectory = 0x0; TH2F* hMultHit = - new TH2F("hMultHits", "photons Hits ", 210, 0, 210, 500, 0, 5000); - TH2F* hTimeHitA = new TH2F("hTimeAhit", "Time Hits", 210, 0, 210, 500, -1, 1); - TH2F* hTimeHitC = new TH2F("hTimeChit", "Time Hits", 210, 0, 210, 200, -1, 1); + new TH2F("hMultHits", "photons Hits ", 220, 0, 220, 500, 0, 5000); + TH2F* hTimeHitA = new TH2F("hTimeAhit", "Time Hits", 220, 0, 220, 500, -1, 1); + TH2F* hTimeHitC = new TH2F("hTimeChit", "Time Hits", 220, 0, 220, 200, -1, 1); TH2F* hMultDig = - new TH2F("hMultDig", "amplitude ", 210, 0, 210, 500, 0, 1000); - TH2F* hPel = new TH2F("hPelDig", "N p.e. ", 210, 0, 210, 500, 0, 10000); + new TH2F("hMultDig", "amplitude ", 220, 0, 220, 500, 0, 1000); + TH2F* hPel = new TH2F("hPelDig", "N p.e. ", 220, 0, 220, 500, 0, 10000); TH2F* hXYA = new TH2F("hXYA", "X vs Y A side", 400, -20, 20, 400, -20, 20); TH2F* hXYC = new TH2F("hXYC", "X vs Y C side", 400, -20, 20, 400, -20, 20); @@ -59,15 +59,14 @@ void readFT0hits() hTimeHitA->Fill(detID, hit_time[detID] - 11.04); hTimeHitC->Fill(detID, hit_time[detID] - 2.91); countE[detID]++; - if (detID < 97) + if (detID < 96) hXYA->Fill(hit.GetX(), hit.GetY()); - if (detID > 96) + if (detID > 95) hXYC->Fill(hit.GetX(), hit.GetY()); } - for (int ii = 0; ii < 208; ii++) { + for (int ii = 0; ii < 220; ii++) { if (countE[ii] > 100) { hMultHit->Fill(ii, countE[ii]); - // std::cout<<ii<<" "<<countE[ii]<<endl; } } } diff --git a/Detectors/FIT/macros/uploadLookUpTable.C b/Detectors/FIT/macros/uploadLookUpTable.C new file mode 100644 index 0000000000000..7ae2b29de4ef3 --- /dev/null +++ b/Detectors/FIT/macros/uploadLookUpTable.C @@ -0,0 +1,43 @@ +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include <DataFormatsFT0/LookUpTable.h> +#include <cstdlib> +#include <vector> +#include <fstream> +#include <iostream> +#include <map> +#include <string_view> + +//o2::ft0::HVchannel::HVBoard readHVBoard(std::string_view str); + +void uploadLookUpTable(const std::string url = "http://o2-ccdb.internal/") +{ + using o2::ccdb::BasicCCDBManager; + using o2::ccdb::CcdbApi; + using namespace o2::ft0; + + std::ifstream f{"/home/alla/aliO2/O2/Detectors/FIT/FT0/base/files/FT0ChannelsTable.02.0.4.2021.txt"}; + int channel; + std::string pm, pm_channel, hv_board, hv_channel, mcp_sn, hv_cable, signal_cable, ep_PM; + std::vector<o2::ft0::HVchannel> table; + std::getline(f, pm); // skip one line + std::string line; + while (std::getline(f, line) && (std::istringstream(line) >> channel >> pm >> pm_channel >> hv_board >> hv_channel >> mcp_sn >> hv_cable >> signal_cable >> ep_PM)) { + o2::ft0::HVchannel chan; + chan.channel = channel; + assert(std::string_view(pm_channel).substr(2, 2) == pm); + chan.pm = read_Topo(pm_channel); + chan.HV_board = hv_board; //readHVBoard(hv_board); + chan.MCP_SN = mcp_sn; + chan.HV_cabel = hv_cable; + chan.signal_cable = signal_cable; + chan.EP = ep_PM; + LOG(INFO) << "read channel " << int(chan.channel); + table.emplace_back(chan); + } + CcdbApi api; + std::map<std::string, std::string> metadata; // can be empty + api.init(url); + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&table, "FT0/LookUpTable", metadata); +} diff --git a/Detectors/FIT/raw/CMakeLists.txt b/Detectors/FIT/raw/CMakeLists.txt index 9fa77d178fedb..9090f54029017 100644 --- a/Detectors/FIT/raw/CMakeLists.txt +++ b/Detectors/FIT/raw/CMakeLists.txt @@ -1,13 +1,14 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(FITRaw - SOURCES src/DataBlockBase.cxx src/DigitBlockBase.cxx src/RawReaderBase.cxx - PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers ms_gsl::ms_gsl) + SOURCES src/DataBlockBase.cxx src/DataBlockFIT.cxx src/DigitBlockBase.cxx src/DigitBlockFIT.cxx src/RawReaderBase.cxx src/RawReaderBaseFIT.cxx src/RawWriterFIT.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers Microsoft.GSL::GSL O2::DetectorsRaw O2::CommonUtils) diff --git a/Detectors/FIT/raw/README.md b/Detectors/FIT/raw/README.md index dbc0c741e7c41..723ce05581370 100644 --- a/Detectors/FIT/raw/README.md +++ b/Detectors/FIT/raw/README.md @@ -1,3 +1,7 @@ +<!-- doxy +\page refFITraw FIT raw +/doxy --> + # DataBlockBase DataBlockWrapper - wrapper for raw data structures\ There should be three static fields in raw data structs, which defines its "signature":\ diff --git a/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h b/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h index c200070b6c258..fd153ec9e1d5c 100644 --- a/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h +++ b/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,7 @@ #include <vector> #include <Rtypes.h> #include "CommonDataFormat/InteractionRecord.h" +#include "Headers/RAWDataHeader.h" #include <gsl/span> #include <boost/mpl/inherit.hpp> #include <boost/mpl/vector.hpp> @@ -49,7 +51,7 @@ #include <array> #include <iostream> #include <cassert> - +#include <type_traits> namespace o2 { namespace fit @@ -57,33 +59,93 @@ namespace fit using namespace std; +static constexpr size_t SIZE_WORD = 16; // should be changed to gloabal variable +static constexpr size_t SIZE_MAX_PAGE = 8192; // should be changed to gloabal variable +static constexpr size_t SIZE_MAX_PAYLOAD = SIZE_MAX_PAGE - sizeof(o2::header::RAWDataHeader); // should be changed to gloabal variable + template <typename T> +struct DataBlockHelper { + template <typename, typename = void> + struct CheckTypeMaxNelem : std::false_type { + }; + template <typename U> + struct CheckTypeMaxNelem<U, std::enable_if_t<std::is_same<decltype(U::MaxNelements), const std::size_t>::value>> : std::true_type { + }; + + template <typename, typename = void> + struct CheckTypeMinNelem : std::false_type { + }; + template <typename U> + struct CheckTypeMinNelem<U, std::enable_if_t<std::is_same<decltype(U::MinNelements), const std::size_t>::value>> : std::true_type { + }; + + template <typename, typename = void> + struct CheckTypePayloadSize : std::false_type { + }; + template <typename U> + struct CheckTypePayloadSize<U, std::enable_if_t<std::is_same<decltype(U::PayloadSize), const std::size_t>::value>> : std::true_type { + }; + + template <typename, typename = void> + struct CheckTypePayloadPerGBTword : std::false_type { + }; + template <typename U> + struct CheckTypePayloadPerGBTword<U, std::enable_if_t<std::is_same<decltype(U::PayloadPerGBTword), const std::size_t>::value>> : std::true_type { + }; + + template <typename, typename = void> + struct CheckMaxElemSize : std::false_type { + }; + template <typename U> + struct CheckMaxElemSize<U, std::enable_if_t<((T::MaxNelements * T::PayloadSize <= SIZE_MAX_PAYLOAD) && (T::MaxNelements * T::PayloadPerGBTword <= SIZE_MAX_PAYLOAD))>> : std::true_type { + }; + + template <typename, typename = void> + struct CheckNelemRange : std::false_type { + }; + template <typename U> + struct CheckNelemRange<U, std::enable_if_t<(T::MaxNelements >= T::MinNelements)>> : std::true_type { + }; + + static constexpr bool check() + { + static_assert(CheckTypeMaxNelem<T>::value, "Error! MaxNelements type should be \"static constexpr std::size_t\"!"); + static_assert(CheckTypeMinNelem<T>::value, "Error! MinNelements type should be \"static constexpr std::size_t\"!"); + static_assert(CheckTypePayloadSize<T>::value, "Error! PayloadSize type should be \"static constexpr std::size_t\"!"); + static_assert(CheckTypePayloadPerGBTword<T>::value, "Error! PayloadPerGBTword type should be \"static constexpr std::size_t\"!"); + static_assert(CheckMaxElemSize<T>::value, "Error! Check maximum number of elements, they are larger than payload size!"); + static_assert(CheckNelemRange<T>::value, "Error! Check range for number of elements, max should be bigger or equal to min!"); + return CheckTypeMaxNelem<T>::value && CheckTypeMinNelem<T>::value && CheckTypePayloadSize<T>::value && CheckTypePayloadPerGBTword<T>::value && CheckMaxElemSize<T>::value && CheckNelemRange<T>::value; + } +}; + +template <typename T, typename = typename std::enable_if_t<DataBlockHelper<T>::check()>> struct DataBlockWrapper { DataBlockWrapper() = default; DataBlockWrapper(const DataBlockWrapper&) = default; - static constexpr size_t sizeWord = 16; // should be changed to gloabal variable - std::vector<uint8_t> serialize(int nWords) + typedef T Data_t; + void serialize(std::vector<char>& vecBytes, size_t nWords, size_t& destPos) const { - std::vector<uint8_t> vecBytes(sizeWord * nWords); - uint8_t* srcAddress = (uint8_t*)mData; - if (nWords == 0 || nWords > MaxNwords) { - return std::move(vecBytes); + const uint8_t* srcAddress = (uint8_t*)mData; + if (nWords == 0 || nWords > MaxNwords || vecBytes.size() - destPos < nWords * SIZE_WORD) { + LOG(INFO) << "Warning! Incorrect serialisation procedure!"; + return; } - gsl::span<uint8_t> serializedBytes(vecBytes); + gsl::span<char> serializedBytes(vecBytes); size_t countBytes = 0; int nSteps = std::get<kNSTEPS>(sReadingLookupTable[nWords]); for (int iStep = 0; iStep < nSteps; iStep++) { - memcpy(serializedBytes.data() + std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]), srcAddress + std::get<kDESTBYTEPOS>(sByteLookupTable[iStep]), std::get<kNBYTES>(sByteLookupTable[iStep])); + memcpy(serializedBytes.data() + std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]) + destPos, srcAddress + std::get<kDESTBYTEPOS>(sByteLookupTable[iStep]), std::get<kNBYTES>(sByteLookupTable[iStep])); countBytes += std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]); } - return std::move(vecBytes); + destPos += nWords * SIZE_WORD; } void deserialize(const gsl::span<const uint8_t> inputBytes, size_t nWords, size_t& srcPos) { mNelements = 0; mNwords = 0; - if (nWords < MinNwords || nWords > MaxNwords || inputBytes.size() - srcPos < nWords * sizeWord) { + if (nWords < MinNwords || nWords > MaxNwords || inputBytes.size() - srcPos < nWords * SIZE_WORD) { //in case of bad fields responsible for deserialization logic, byte position will be pushed to the end of binary sequence srcPos = inputBytes.size(); mIsIncorrect = true; @@ -98,22 +160,22 @@ struct DataBlockWrapper { memcpy(destAddress + std::get<kDESTBYTEPOS>(sByteLookupTable[iStep]), inputBytes.data() + std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]) + srcPos, std::get<kNBYTES>(sByteLookupTable[iStep])); countBytes += std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]); } - srcPos += mNwords * sizeWord; + srcPos += mNwords * SIZE_WORD; } - static constexpr int MaxNwords = T::PayloadSize * T::MaxNelements / T::PayloadPerGBTword + (T::PayloadSize * T::MaxNelements % T::PayloadPerGBTword > 0); //calculating max GBT words per block - static constexpr int MaxNbytes = sizeWord * MaxNwords; + static constexpr int MaxNwords = Data_t::PayloadSize * Data_t::MaxNelements / Data_t::PayloadPerGBTword + (Data_t::PayloadSize * Data_t::MaxNelements % Data_t::PayloadPerGBTword > 0); //calculating max GBT words per block + static constexpr int MaxNbytes = SIZE_WORD * MaxNwords; - static constexpr int MinNwords = T::PayloadSize * T::MinNelements / T::PayloadPerGBTword + (T::PayloadSize * T::MinNelements % T::PayloadPerGBTword > 0); //calculating min GBT words per block - static constexpr int MinNbytes = sizeWord * MinNwords; + static constexpr int MinNwords = Data_t::PayloadSize * Data_t::MinNelements / Data_t::PayloadPerGBTword + (Data_t::PayloadSize * Data_t::MinNelements % Data_t::PayloadPerGBTword > 0); //calculating min GBT words per block + static constexpr int MinNbytes = SIZE_WORD * MinNwords; //get number of byte reading steps static constexpr size_t getNsteps() { int count = 0; - size_t payloadFull = T::MaxNelements * T::PayloadSize; - size_t payloadInWord = T::PayloadPerGBTword; - size_t payloadPerElem = T::PayloadSize; + size_t payloadFull = Data_t::MaxNelements * Data_t::PayloadSize; + size_t payloadInWord = Data_t::PayloadPerGBTword; + size_t payloadPerElem = Data_t::PayloadSize; while (payloadFull > 0) { if (payloadPerElem < payloadInWord) { count++; @@ -127,10 +189,10 @@ struct DataBlockWrapper { payloadInWord = 0; } if (payloadInWord == 0) { - payloadInWord = T::PayloadPerGBTword; + payloadInWord = Data_t::PayloadPerGBTword; } if (payloadPerElem == 0) { - payloadPerElem = T::PayloadSize; + payloadPerElem = Data_t::PayloadSize; } } return count; @@ -156,15 +218,15 @@ struct DataBlockWrapper { int countWord = 0; size_t destBytePosPerElem = 0; size_t srcBytePos = 0; - size_t payloadFull = T::MaxNelements * T::PayloadSize; + size_t payloadFull = Data_t::MaxNelements * Data_t::PayloadSize; - size_t bytesInWord = sizeWord; - size_t payloadInWord = T::PayloadPerGBTword; + size_t bytesInWord = SIZE_WORD; + size_t payloadInWord = Data_t::PayloadPerGBTword; - size_t payloadPerElem = T::PayloadSize; + size_t payloadPerElem = Data_t::PayloadSize; uint64_t indexElem = 0; - uint64_t indexLastElem = T::MaxNelements - 1; + uint64_t indexLastElem = Data_t::MaxNelements - 1; while (payloadFull > 0) { if (payloadPerElem < payloadInWord) { //new element @@ -197,15 +259,15 @@ struct DataBlockWrapper { } if (payloadInWord == 0) { - payloadInWord = T::PayloadPerGBTword; + payloadInWord = Data_t::PayloadPerGBTword; } if (payloadPerElem == 0) { - payloadPerElem = T::PayloadSize; + payloadPerElem = Data_t::PayloadSize; countElement++; destBytePosPerElem = countElement * sizeof(T); } if (bytesInWord == 0) { - bytesInWord = sizeWord; + bytesInWord = SIZE_WORD; countWord++; } } @@ -224,7 +286,7 @@ struct DataBlockWrapper { static constexpr std::array<std::tuple<unsigned int, unsigned int, bool>, MaxNwords + 1> GetReadingLookupTable() { std::array<std::tuple<unsigned int, unsigned int, bool>, MaxNwords + 1> readingScheme{}; - size_t payloadPerElem = T::PayloadSize; + size_t payloadPerElem = Data_t::PayloadSize; std::get<kNSTEPS>(readingScheme[0]) = 0; std::get<kNELEMENTS>(readingScheme[0]) = 0; std::get<kISPARTED>(readingScheme[0]) = false; @@ -241,7 +303,7 @@ struct DataBlockWrapper { countWord++; } if (payloadPerElem == 0) { - payloadPerElem = T::PayloadSize; + payloadPerElem = Data_t::PayloadSize; } payloadPerElem -= std::get<kNBYTES>((GetByteLookupTable())[iStep]); } @@ -261,46 +323,43 @@ struct DataBlockWrapper { //Printing LookupTables static void printLUT() { - cout << endl - << "-------------------------------------------" << endl; - std::cout << "kNELEMENTS|kNSTEPS|kISPARTED" << std::endl; + LOG(INFO) << "-------------------------------------------"; + LOG(INFO) << "kNELEMENTS|kNSTEPS|kISPARTED"; for (int i = 0; i < MaxNwords + 1; i++) { - std::cout << std::endl - << std::get<kNELEMENTS>(sReadingLookupTable[i]) << "|" + LOG(INFO) << std::get<kNELEMENTS>(sReadingLookupTable[i]) << "|" << std::get<kNSTEPS>(sReadingLookupTable[i]) << "|" - << std::get<kISPARTED>(sReadingLookupTable[i]) << endl; + << std::get<kISPARTED>(sReadingLookupTable[i]); } - cout << endl - << "-------------------------------------------" << endl; - std::cout << "kELEMENTINDEX|kWORDINDEX|kNBYTES|kSRCBYTEPOS|kDESTBYTEPOS" << std::endl; + LOG(INFO) << "-------------------------------------------"; + LOG(INFO) << "kELEMENTINDEX|kWORDINDEX|kNBYTES|kSRCBYTEPOS|kDESTBYTEPOS"; for (int i = 0; i < getNsteps(); i++) { - cout << endl - << std::get<kELEMENTINDEX>(sByteLookupTable[i]) << "|" - << std::get<kWORDINDEX>(sByteLookupTable[i]) << "|" - << std::get<kNBYTES>(sByteLookupTable[i]) << "|" - << std::get<kSRCBYTEPOS>(sByteLookupTable[i]) << "|" - << std::get<kDESTBYTEPOS>(sByteLookupTable[i]) << endl; + LOG(INFO) << std::get<kELEMENTINDEX>(sByteLookupTable[i]) << "|" + << std::get<kWORDINDEX>(sByteLookupTable[i]) << "|" + << std::get<kNBYTES>(sByteLookupTable[i]) << "|" + << std::get<kSRCBYTEPOS>(sByteLookupTable[i]) << "|" + << std::get<kDESTBYTEPOS>(sByteLookupTable[i]); } } void print() const { - assert(mNelements <= T::MaxNelements); + assert(mNelements <= Data_t::MaxNelements); for (int i = 0; i < mNelements; i++) { - std::cout << "\nPringting element number: " << i << std::endl; + LOG(INFO) << "Printing element number: " << i; mData[i].print(); } } - T mData[T::MaxNelements]; + Data_t mData[Data_t::MaxNelements]; unsigned int mNelements; //number of deserialized elements; unsigned int mNwords; //number of deserialized GBT words; //can be excluded bool mIsIncorrect; }; //CRTP(static polymorphism) + Composition over multiple inheritance(Header + multiple data structures) -template <class DataBlock, class Header, class... DataStructures> +template <template <typename...> class DataBlock, class Header, class... DataStructures> class DataBlockBase : public boost::mpl::inherit<DataBlockWrapper<Header>, DataBlockWrapper<DataStructures>...>::type { typedef boost::mpl::vector<DataStructures...> DataBlockTypes; + typedef DataBlock<Header, DataStructures...> DataBlock_t; typedef DataBlockBase<DataBlock, Header, DataStructures...> TemplateHeader; typedef typename boost::mpl::inherit<DataBlockWrapper<Header>, DataBlockWrapper<DataStructures>...>::type DataBlockDerivedBase; @@ -326,13 +385,18 @@ class DataBlockBase : public boost::mpl::inherit<DataBlockWrapper<Header>, DataB { return DataBlockWrapper<Header>::mData[0].getIntRec(); } + + void setInteractionRecord(const InteractionRecord& intRec) + { + DataBlockWrapper<Header>::mData[0].setIntRec(intRec); + } // //use this for block decoding void decodeBlock(gsl::span<const uint8_t> payload, size_t srcPos) { mSize = 0; size_t bytePos = srcPos; - static_cast<DataBlock*>(this)->deserialize(payload, bytePos); + static_cast<DataBlock_t*>(this)->deserialize(payload, bytePos); mSize = bytePos - srcPos; //checking sanity and updating update(); @@ -345,7 +409,7 @@ class DataBlockBase : public boost::mpl::inherit<DataBlockWrapper<Header>, DataB mIsCorrect = true; checkDeserialization(mIsCorrect, DataBlockWrapper<Header>::mIsIncorrect); // checking deserialization status for header (checkDeserialization(mIsCorrect, DataBlockWrapper<DataStructures>::mIsIncorrect), ...); // checking deserialization status for sub-block - static_cast<DataBlock*>(this)->sanityCheck(mIsCorrect); + static_cast<DataBlock_t*>(this)->sanityCheck(mIsCorrect); } size_t mSize; //deserialized size diff --git a/Detectors/FIT/raw/include/FITRaw/DataBlockFIT.h b/Detectors/FIT/raw/include/FITRaw/DataBlockFIT.h new file mode 100644 index 0000000000000..49796c306007b --- /dev/null +++ b/Detectors/FIT/raw/include/FITRaw/DataBlockFIT.h @@ -0,0 +1,147 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DataBlockFIT.h class for RAW data format data blocks at FIT +// +// Artur.Furs +// afurs@cern.ch +// + +#ifndef ALICEO2_FIT_DATABLOCKFIT_H_ +#define ALICEO2_FIT_DATABLOCKFIT_H_ +#include <iostream> +#include <Rtypes.h> +#include <FITRaw/DataBlockBase.h> + +#include <gsl/span> +#include <iostream> +#include <cassert> +using namespace o2::fit; +namespace o2 +{ +namespace fit +{ +//FIT DATA BLOCK DEFINITIONS + +//standard data block from PM +template <typename RawHeaderPMtype, typename RawDataPMtype> +class DataBlockPM : public DataBlockBase<DataBlockPM, RawHeaderPMtype, RawDataPMtype> +{ + public: + DataBlockPM() = default; + DataBlockPM(const DataBlockPM&) = default; + typedef RawHeaderPMtype RawHeaderPM; + typedef RawDataPMtype RawDataPM; + void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) + { + DataBlockWrapper<RawHeaderPM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderPM>::MaxNwords, srcByteShift); + DataBlockWrapper<RawDataPM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderPM>::mData[0].nGBTWords, srcByteShift); + } + const std::size_t getNgbtWords() const { return DataBlockWrapper<RawHeaderPM>::mData[0].nGBTWords; } + std::vector<char> serialize() const + { + std::size_t nBytes = DataBlockWrapper<RawHeaderPM>::MaxNwords * SIZE_WORD; + nBytes += DataBlockWrapper<RawHeaderPM>::mData[0].nGBTWords * SIZE_WORD; + std::vector<char> vecBytes(nBytes); + std::size_t destBytes = 0; + DataBlockWrapper<RawHeaderPM>::serialize(vecBytes, DataBlockWrapper<RawHeaderPM>::MaxNwords, destBytes); + DataBlockWrapper<RawDataPM>::serialize(vecBytes, DataBlockWrapper<RawHeaderPM>::mData[0].nGBTWords, destBytes); + return vecBytes; + } + //Custom sanity checking for current deserialized block + // put here code for raw data checking + void sanityCheck(bool& flag) + { + if (DataBlockWrapper<RawDataPM>::mNelements == 0) { + flag = false; + return; + } + if (DataBlockWrapper<RawDataPM>::mNelements % 2 == 0 && DataBlockWrapper<RawDataPM>::mData[DataBlockWrapper<RawDataPM>::mNelements - 1].channelID == 0) { + DataBlockWrapper<RawDataPM>::mNelements--; //in case of half GBT-word filling + } + //TODO, Descriptor checking, Channel range + } +}; + +//standard data block from TCM +template <typename RawHeaderTCMtype, typename RawDataTCMtype> +class DataBlockTCM : public DataBlockBase<DataBlockTCM, RawHeaderTCMtype, RawDataTCMtype> +{ + public: + DataBlockTCM() = default; + DataBlockTCM(const DataBlockTCM&) = default; + typedef RawHeaderTCMtype RawHeaderTCM; + typedef RawDataTCMtype RawDataTCM; + const std::size_t getNgbtWords() const { return DataBlockWrapper<RawHeaderTCM>::mData[0].nGBTWords; } + void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) + { + DataBlockWrapper<RawHeaderTCM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCM>::MaxNwords, srcByteShift); + DataBlockWrapper<RawDataTCM>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCM>::mData[0].nGBTWords, srcByteShift); + } + std::vector<char> serialize() const + { + std::size_t nBytes = DataBlockWrapper<RawHeaderTCM>::MaxNwords * SIZE_WORD; + nBytes += DataBlockWrapper<RawHeaderTCM>::mData[0].nGBTWords * SIZE_WORD; + std::vector<char> vecBytes(nBytes); + std::size_t destBytes = 0; + DataBlockWrapper<RawHeaderTCM>::serialize(vecBytes, DataBlockWrapper<RawHeaderTCM>::MaxNwords, destBytes); + DataBlockWrapper<RawDataTCM>::serialize(vecBytes, DataBlockWrapper<RawHeaderTCM>::mData[0].nGBTWords, destBytes); + return vecBytes; + } + //Custom sanity checking for current deserialized block + // put here code for raw data checking + void sanityCheck(bool& flag) + { + //TODO, Descriptor checking + } +}; + +//extended TCM mode, 1 TCMdata + 8 TCMdataExtendedstructs +template <typename RawHeaderTCMextType, typename RawDataTCMtype, typename RawDataTCMextType> +class DataBlockTCMext : public DataBlockBase<DataBlockTCMext, RawHeaderTCMextType, RawDataTCMtype, RawDataTCMextType> +{ + public: + DataBlockTCMext() = default; + DataBlockTCMext(const DataBlockTCMext&) = default; + typedef RawHeaderTCMextType RawHeaderTCMext; + typedef RawDataTCMtype RawDataTCM; + typedef RawDataTCMextType RawDataTCMext; + const std::size_t getNgbtWords() const { return DataBlockWrapper<RawHeaderTCMext>::mData[0].nGBTWords; } + void deserialize(gsl::span<const uint8_t> srcBytes, size_t& srcByteShift) + { + DataBlockWrapper<RawHeaderTCMext>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCMext>::MaxNwords, srcByteShift); + DataBlockWrapper<RawDataTCM>::deserialize(srcBytes, DataBlockWrapper<RawDataTCM>::MaxNwords, srcByteShift); + DataBlockWrapper<RawDataTCMext>::deserialize(srcBytes, DataBlockWrapper<RawHeaderTCMext>::mData[0].nGBTWords - DataBlockWrapper<RawDataTCM>::MaxNwords, srcByteShift); + } + + std::vector<char> serialize() const + { + std::size_t nBytes = DataBlockWrapper<RawHeaderTCMext>::MaxNwords * SIZE_WORD; + nBytes += DataBlockWrapper<RawHeaderTCMext>::mData[0].nGBTWords * SIZE_WORD; + std::vector<char> vecBytes(nBytes); + std::size_t destBytes = 0; + DataBlockWrapper<RawHeaderTCMext>::serialize(vecBytes, DataBlockWrapper<RawHeaderTCMext>::MaxNwords, destBytes); + DataBlockWrapper<RawDataTCM>::serialize(vecBytes, DataBlockWrapper<RawDataTCM>::MaxNwords, destBytes); + DataBlockWrapper<RawDataTCMext>::serialize(vecBytes, DataBlockWrapper<RawHeaderTCMext>::mData[0].nGBTWords - DataBlockWrapper<RawDataTCM>::MaxNwords, destBytes); + return vecBytes; + } + //Custom sanity checking for current deserialized block + // put here code for raw data checking + void sanityCheck(bool& flag) + { + + //TODO, Descriptor checking + } +}; + +} // namespace fit +} // namespace o2 +#endif diff --git a/Detectors/FIT/raw/include/FITRaw/DigitBlockBase.h b/Detectors/FIT/raw/include/FITRaw/DigitBlockBase.h index 5fd2d2738c8d8..9c95677d4fbbf 100644 --- a/Detectors/FIT/raw/include/FITRaw/DigitBlockBase.h +++ b/Detectors/FIT/raw/include/FITRaw/DigitBlockBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,33 +19,298 @@ #include <iostream> #include <vector> #include <algorithm> +#include <type_traits> +#include <utility> +#include <array> #include <Rtypes.h> #include <CommonDataFormat/InteractionRecord.h> +#include <CommonDataFormat/RangeReference.h> +#include <Framework/Logger.h> +#include <boost/mpl/vector.hpp> +#include <boost/mpl/front.hpp> +#include <boost/mpl/fold.hpp> +#include <boost/mpl/remove_if.hpp> +#include <boost/mpl/lambda.hpp> +#include <boost/mpl/not.hpp> +#include <boost/mpl/size.hpp> #include <gsl/span> namespace o2 { namespace fit { -template <class DigitBlock> + +namespace DigitBlockHelper +{ +//Check template specialisation +//Is there analog of this metafunction in Common O2 lib? +template <template <typename...> class Template, typename T> +struct IsSpecOfType : std::false_type { +}; +template <template <typename...> class Template, typename... T> +struct IsSpecOfType<Template, Template<T...>> : std::true_type { +}; +//Check if RangeReference is a single field in main digit structure +template <typename T, typename = void> +struct HasRef : std::false_type { +}; +//For FT0 +template <typename T> +struct HasRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename o2::dataformats::RangeReference<int, int>>::value>> : std::true_type { +}; +//For FV0 +template <typename T> +struct HasRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename o2::dataformats::RangeRefComp<6>>::value>> : std::true_type { +}; +//For FDD +template <typename T> +struct HasRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename o2::dataformats::RangeRefComp<5>>::value>> : std::true_type { +}; + +//Check if RangeReference is an array field in main digit structure +template <typename T, typename = void> +struct HasArrayRef : std::false_type { +}; +//For FT0 +template <typename T> +struct HasArrayRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename std::array<typename o2::dataformats::RangeReference<int, int>, std::tuple_size<decltype(std::declval<T>().ref)>::value>>::value>> : std::true_type { +}; +//For FV0 +template <typename T> +struct HasArrayRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename std::array<typename o2::dataformats::RangeRefComp<6>, std::tuple_size<decltype(std::declval<T>().ref)>::value>>::value>> : std::true_type { +}; +//For FDD +template <typename T> +struct HasArrayRef<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ref), typename std::array<typename o2::dataformats::RangeRefComp<5>, std::tuple_size<decltype(std::declval<T>().ref)>::value>>::value>> : std::true_type { +}; + +//Get RangeReference number of dimentions. +template <typename T, typename = void> +struct GetDigitRefsN { + constexpr static std::size_t value = 0; +}; +template <typename T> +struct GetDigitRefsN<T, std::enable_if_t<HasRef<T>::value>> { + constexpr static std::size_t value = 1; +}; +template <typename T> +struct GetDigitRefsN<T, std::enable_if_t<HasArrayRef<T>::value && (std::tuple_size<decltype(std::declval<T>().ref)>::value > 1)>> { + constexpr static std::size_t value = std::tuple_size<decltype(std::declval<T>().ref)>::value; +}; +//Check if InteractionRecord field exists +template <typename T, typename = void> +struct HasIntRecord : std::false_type { +}; +template <typename T> +struct HasIntRecord<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().mIntRecord), o2::InteractionRecord>::value>> : std::true_type { +}; +//Temporary for FV0 +template <typename T> +struct HasIntRecord<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ir), o2::InteractionRecord>::value>> : std::true_type { +}; +//Dividing to sub-digit structures with InteractionRecord(single one, e.g. for TCM extended mode) and without +template <typename T> +using GetVecSubDigit = typename boost::mpl::remove_if<T, boost::mpl::lambda<HasIntRecord<boost::mpl::_1>>::type>::type; +template <typename T> +using GetVecSingleSubDigit = typename boost::mpl::remove_if<T, boost::mpl::lambda<boost::mpl::not_<HasIntRecord<boost::mpl::_1>>>::type>::type; +//Converting empty Boost MPL vector to empty std::tuple +template <typename T, typename = void> +struct GetSubDigitField { + typedef std::tuple<> type; + typedef std::tuple<> vector_type; + constexpr static bool sIsEmpty = true; + constexpr static bool sIsTuple = true; + constexpr static std::size_t size = 0; +}; +//Converting Boost MPL vector with 1 element to std::vector +template <typename T> +struct GetSubDigitField<T, std::enable_if_t<boost::mpl::size<T>::value == 1>> { + typedef std::vector<typename boost::mpl::front<T>::type> vector_type; + typedef typename boost::mpl::front<T>::type type; + constexpr static bool sIsEmpty = false; + constexpr static bool sIsTuple = false; + constexpr static std::size_t size = 1; +}; +// +//Converting Boost MPL vector to std::tuple of std::vectors +template <typename T> +struct GetSubDigitField<T, std::enable_if_t<(boost::mpl::size<T>::value > 1)>> { + template <typename Arg1, typename Arg2> + struct MakeTuple; + template <typename... Args, typename LastArg> + struct MakeTuple<std::tuple<Args...>, LastArg> { + typedef std::tuple<Args..., LastArg> type; + }; + typedef typename boost::mpl::fold<T, std::tuple<>, MakeTuple<boost::mpl::_1, std::vector<boost::mpl::_2>>>::type vector_type; + typedef typename boost::mpl::fold<T, std::tuple<>, MakeTuple<boost::mpl::_1, boost::mpl::_2>>::type type; + constexpr static bool sIsEmpty = false; + constexpr static bool sIsTuple = true; + constexpr static std::size_t size = boost::mpl::size<T>::value; +}; + +} // namespace DigitBlockHelper + +// DigitBlock - digit block, for interacting with Digits structures as one +// Digit - primary digit struct which should contain InteractionRecord field and ReferenceRange to SubDigit(not all of them) +// SubDigit - sub digit structure which shouldn't contain InteractionRecord field +// SingleSubDigit - separated SubDigits which contain InteractionRecord field and not referred by ReferenceRange field in Digit structure. +// For example extended TCM mode uses such SingleSubDigits +template <typename DigitType, typename... SubDigitTypes> class DigitBlockBase //:public DigitBlock { public: - DigitBlockBase(o2::InteractionRecord intRec) - { /*static_cast<DigitBlock*>(this)->setIntRec(intRec);*/ + DigitBlockBase(const o2::InteractionRecord& intRec) + { + mDigit.setIntRecord(intRec); + // mSubDigit.reserve(256); + } + DigitBlockBase(const DigitType& digit) : mDigit(digit) + { } DigitBlockBase() = default; DigitBlockBase(const DigitBlockBase& other) = default; ~DigitBlockBase() = default; - template <class DataBlockType> - void process(DataBlockType& dataBlock, int linkID) + typedef DigitType Digit_t; + typedef std::tuple<std::vector<DigitType>, std::vector<SubDigitTypes>...> TupleVecDigitObjs_t; + typedef boost::mpl::vector<SubDigitTypes...> VecAllSubDigit_t; + typedef DigitBlockHelper::GetVecSubDigit<VecAllSubDigit_t> VecSubDigit_t; + typedef DigitBlockHelper::GetVecSingleSubDigit<VecAllSubDigit_t> VecSingleSubDigit_t; + typedef typename DigitBlockHelper::GetSubDigitField<VecSubDigit_t>::vector_type SubDigit_t; + typedef typename DigitBlockHelper::GetSubDigitField<VecSingleSubDigit_t>::type SingleSubDigit_t; + constexpr static std::size_t sNSubDigits = DigitBlockHelper::GetSubDigitField<VecSubDigit_t>::size; + constexpr static std::size_t sNSingleSubDigits = DigitBlockHelper::GetSubDigitField<VecSingleSubDigit_t>::size; + Digit_t mDigit; + SubDigit_t mSubDigit; + SingleSubDigit_t mSingleSubDigit; + template <typename VecDigit, typename... VecSubDigits> + auto getSubDigits(VecDigit& vecDigits, VecSubDigits&... vecSubDigits) + -> std::enable_if_t<sizeof...(VecSubDigits) == sNSubDigits> + { + if constexpr (sNSubDigits > 0) { + getSubDigit<sizeof...(VecSubDigits), sizeof...(VecSubDigits)>(std::tie(vecSubDigits...)); + } + vecDigits.push_back(std::move(mDigit)); + } + + template <typename... T> + auto getSingleSubDigits(T&... vecSingleSubDigits) + -> std::enable_if_t<sizeof...(T) == sNSingleSubDigits> + { + if constexpr (sNSingleSubDigits > 0) { + getSingleSubDigit<sizeof...(T), sizeof...(T)>(std::tie(vecSingleSubDigits...)); + } + } + + template <std::size_t N, std::size_t N_TOTAL, typename... T> + auto getSubDigit(std::tuple<T...> tupleVecSubDigits) -> std::enable_if_t<(N_TOTAL > 1)> + { + mDigit.ref[N - 1].set(std::get<N - 1>(tupleVecSubDigits).size(), std::get<N - 1>(mSubDigit).size()); + std::move(std::get<N - 1>(mSubDigit).begin(), std::get<N - 1>(mSubDigit).end(), std::back_inserter(std::get<N - 1>(tupleVecSubDigits))); + if constexpr (N > 1) { + getSubDigit<N - 1, N_TOTAL>(tupleVecSubDigits); + } + } + template <std::size_t N, std::size_t N_TOTAL, typename... T> + auto getSubDigit(std::tuple<T...> tupleVecSubDigits) -> std::enable_if_t<(N_TOTAL == 1)> + { + mDigit.ref.set(std::get<0>(tupleVecSubDigits).size(), mSubDigit.size()); + std::move(mSubDigit.begin(), mSubDigit.end(), std::back_inserter(std::get<0>(tupleVecSubDigits))); + } + + template <std::size_t N, std::size_t N_TOTAL, typename... T> + auto getSingleSubDigit(std::tuple<T...> tupleVecSingleSubDigits) -> std::enable_if_t<(N_TOTAL > 1)> + { + std::get<N - 1>(tupleVecSingleSubDigits).push_back(std::move(std::get<N - 1>(mSingleSubDigit))); + if constexpr (N > 1) { + getSingleSubDigit<N - 1, N_TOTAL>(tupleVecSingleSubDigits); + } + } + template <std::size_t N, std::size_t N_TOTAL, typename... T> + auto getSingleSubDigit(std::tuple<T...> tupleVecSingleSubDigits) -> std::enable_if_t<(N_TOTAL == 1)> + { + std::get<0>(tupleVecSingleSubDigits).push_back(std::move(mSingleSubDigit)); + } + // 1-Dim SubDigit + template <typename DigitBlockType, typename DigitT, typename SubDigitT> + static auto makeDigitBlock(const std::vector<DigitT>& vecDigits, const std::vector<SubDigitT>& vecSubDigits) -> std::enable_if_t<DigitBlockHelper::GetDigitRefsN<DigitT>::value == 1 && DigitBlockHelper::IsSpecOfType<DigitBlockBase, typename DigitBlockType::DigitBlockBase_t>::value, std::vector<DigitBlockType>> + { + std::vector<DigitBlockType> vecResult; + vecResult.reserve(vecDigits.size()); + for (const auto& digit : vecDigits) { + auto itBegin = vecSubDigits.begin(); + std::advance(itBegin, digit.ref.getFirstEntry()); + auto itLast = itBegin; + std::advance(itLast, digit.ref.getEntries()); + vecResult.push_back({digit}); + vecResult.back().mSubDigit.reserve(digit.ref.getEntries()); + std::copy(itBegin, itLast, std::back_inserter(vecResult.back().mSubDigit)); + } + return vecResult; + } + + // Multi-Dim SubDigits + template <typename DigitBlockType, typename DigitT, typename... SubDigitT> + static auto makeDigitBlock(const std::vector<DigitT>& vecDigits, const std::vector<SubDigitT>&... vecSubDigits) -> std::enable_if_t<(DigitBlockHelper::GetDigitRefsN<DigitT>::value > 1) && (DigitBlockHelper::IsSpecOfType<DigitBlockBase, typename DigitBlockType::DigitBlockBase_t>::value), std::vector<DigitBlockType>> + { + std::vector<DigitBlockType> vecResult; + vecResult.reserve(vecDigits.size()); + for (const auto& digit : vecDigits) { + vecResult.push_back({digit}); + auto& refTuple = vecResult.back().mSubDigit; + fillSubDigitTuple<sizeof...(SubDigitT)>(digit, std::tie(vecSubDigits...), refTuple); + } + return vecResult; + } + + template <std::size_t N, typename DigitT, typename... T> + static void fillSubDigitTuple(const DigitT& digit, const std::tuple<T...>& tupleSrc, std::tuple<T...>& tupleDest) { - static_cast<DigitBlock*>(this)->processDigits(dataBlock, linkID); + const auto& vecSrc = std::get<N>(tupleSrc); + auto& vecDest = std::get<N>(tupleSrc); + auto itBegin = vecSrc.begin(); + std::advance(itBegin, digit.ref[N - 1].getFirstEntry()); + auto itLast = itBegin; + std::advance(itLast, digit.ref[N - 1].getEntries()); + vecDest.reserve(digit.ref[N - 1].getEntries()); + std::copy(itBegin, itLast, std::back_inserter(vecDest)); + if constexpr (N > 1) { + fillSubDigitTuple<N - 1>(digit, tupleSrc, tupleDest); + } } - template <class... DigitType> - void pop(std::vector<DigitType>&... vecDigits) + void print() const { - static_cast<DigitBlock*>(this)->getDigits(vecDigits...); + mDigit.printLog(); + if constexpr (DigitBlockHelper::IsSpecOfType<std::tuple, decltype(mSubDigit)>::value) { + if constexpr ((std::tuple_size<decltype(mSubDigit)>::value) > 1) { + LOG(INFO) << "______________SUB DIGITS____________"; + std::apply([](const auto&... vecSubDigit) { + ((std::for_each(vecSubDigit.begin(), vecSubDigit.end(), [](const auto& subDigit) { + subDigit.printLog(); + })), + ...); + }, + mSubDigit); + } + } else { + LOG(INFO) << "______________SUB DIGITS____________"; + std::for_each(mSubDigit.begin(), mSubDigit.end(), [](const auto& subDigit) { + subDigit.printLog(); + }); + } + if constexpr (DigitBlockHelper::IsSpecOfType<std::tuple, decltype(mSingleSubDigit)>::value) { + if constexpr ((std::tuple_size<decltype(mSingleSubDigit)>::value) > 1) { + LOG(INFO) << "______________SINGLE SUB DIGITS____________"; + std::apply([](const auto&... singleSubDigit) { + ((singleSubDigit.printLog()), ...); + }, + mSingleSubDigit); + } + } else { + LOG(INFO) << "______________SINGLE SUB DIGITS____________"; + mSingleSubDigit.printLog(); + } + LOG(INFO) << std::dec; + LOG(INFO) << "______________________________________"; } }; diff --git a/Detectors/FIT/raw/include/FITRaw/DigitBlockFIT.h b/Detectors/FIT/raw/include/FITRaw/DigitBlockFIT.h new file mode 100644 index 0000000000000..8a62a47664461 --- /dev/null +++ b/Detectors/FIT/raw/include/FITRaw/DigitBlockFIT.h @@ -0,0 +1,494 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file DigitBlockFIT.h class for proccessing RAW data into Digits +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_DIGITBLOCKFIT_H_ +#define ALICEO2_FIT_DIGITBLOCKFIT_H_ +#include <iostream> +#include <vector> +#include <algorithm> +#include <Rtypes.h> +#include "FITRaw/DataBlockFIT.h" +#include "FITRaw/DigitBlockBase.h" + +#include <CommonDataFormat/InteractionRecord.h> + +#include "TTree.h" + +#include <gsl/span> + +namespace o2 +{ +namespace fit +{ +//Temporary helper +namespace DigitBlockFIThelper +{ +template <typename T, typename = void> +struct IsFV0; +//FV0 Digit recognition +template <typename T> +struct IsFV0<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().mIntRecord), o2::InteractionRecord>::value>> : std::false_type { +}; +template <typename T> +struct IsFV0<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().ir), o2::InteractionRecord>::value>> : std::true_type { +}; +//Temporary, PM module convertation +//FT0 +template <typename ChannelDataType, typename PMDataType> +auto ConvertChData2EventData(const ChannelDataType& chData, PMDataType& pmData, int channelID) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().QTCAmpl), int16_t>::value> +{ + pmData.word = uint64_t(chData.ChainQTC) << PMDataType::BitFlagPos; + pmData.channelID = channelID; + pmData.time = chData.CFDTime; + pmData.charge = chData.QTCAmpl; +} +//FV0 +template <typename ChannelDataType, typename PMDataType> +auto ConvertChData2EventData(const ChannelDataType& chData, PMDataType& pmData, int channelID) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().chargeAdc), Short_t>::value> +{ + pmData.channelID = channelID; + pmData.time = chData.time; + pmData.charge = chData.chargeAdc; +} +//FDD +template <typename ChannelDataType, typename PMDataType> +auto ConvertChData2EventData(const ChannelDataType& chData, PMDataType& pmData, int channelID) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().mChargeADC), int16_t>::value> +{ + pmData.word = uint64_t(chData.mFEEBits) << PMDataType::BitFlagPos; + pmData.channelID = channelID; + pmData.time = chData.mTime; + pmData.charge = chData.mChargeADC; +} +//Temporary, TCM module convertation +//FT0 and FDD +template <typename DigitType, typename TCMDataType> +auto ConvertDigit2TCMData(const DigitType& digit, TCMDataType& tcmData) -> std::enable_if_t<!IsFV0<DigitType>::value> +{ + tcmData.orA = digit.mTriggers.getOrA(); + tcmData.orC = digit.mTriggers.getOrC(); + tcmData.sCen = digit.mTriggers.getSCen(); + tcmData.cen = digit.mTriggers.getCen(); + tcmData.vertex = digit.mTriggers.getVertex(); + tcmData.laser = bool(digit.mTriggers.triggersignals & (1 << 5)); + tcmData.outputsAreBlocked = bool(digit.mTriggers.triggersignals & (1 << 6)); + tcmData.dataIsValid = bool(digit.mTriggers.triggersignals & (1 << 7)); + tcmData.nChanA = digit.mTriggers.nChanA; + tcmData.nChanC = digit.mTriggers.nChanC; + const int64_t thresholdSignedInt17bit = 65535; //pow(2,17)/2-1 + if (digit.mTriggers.amplA > thresholdSignedInt17bit) { + tcmData.amplA = thresholdSignedInt17bit; + } else { + tcmData.amplA = digit.mTriggers.amplA; + } + if (digit.mTriggers.amplC > thresholdSignedInt17bit) { + tcmData.amplC = thresholdSignedInt17bit; + } else { + tcmData.amplC = digit.mTriggers.amplC; + } + tcmData.timeA = digit.mTriggers.timeA; + tcmData.timeC = digit.mTriggers.timeC; +} +//FV0 +template <typename DigitType, typename TCMDataType> +auto ConvertDigit2TCMData(const DigitType& digit, TCMDataType& tcmData) -> std::enable_if_t<IsFV0<DigitType>::value> +{ + tcmData.orA = bool(digit.mTriggers.triggerSignals & (1 << 0)); + tcmData.orC = bool(digit.mTriggers.triggerSignals & (1 << 1)); + tcmData.sCen = bool(digit.mTriggers.triggerSignals & (1 << 2)); + tcmData.cen = bool(digit.mTriggers.triggerSignals & (1 << 3)); + tcmData.vertex = bool(digit.mTriggers.triggerSignals & (1 << 4)); + tcmData.laser = bool(digit.mTriggers.triggerSignals & (1 << 5)); + tcmData.outputsAreBlocked = bool(digit.mTriggers.triggerSignals & (1 << 6)); + tcmData.dataIsValid = bool(digit.mTriggers.triggerSignals & (1 << 7)); + tcmData.nChanA = digit.mTriggers.nChanA; + //tcmData.nChanC = digit.mTriggers.nChanC; + tcmData.nChanC = 0; + tcmData.amplA = digit.mTriggers.amplA; + //tcmdata.amplC = digit.mTriggers.amplA; + tcmData.amplC = 0; + //tcmData.timeA = digit.mTriggers.timeA + //tcmData.timeC = digit.mTriggers.timeC; + tcmData.timeA = 0; + tcmData.timeC = 0; +} +//Digit to raw helper functions, temporary +//TCM to Digit convertation +//FT0 and FDD +template <typename DigitType, typename TCMDataType> +auto ConvertTCMData2Digit(DigitType& digit, const TCMDataType& tcmData) -> std::enable_if_t<!IsFV0<DigitType>::value> +{ + using TriggerType = decltype(digit.mTriggers); + auto& trg = digit.mTriggers; + trg.triggersignals = ((bool)tcmData.orA << TriggerType::bitA) | + ((bool)tcmData.orC << TriggerType::bitC) | + ((bool)tcmData.vertex << TriggerType::bitVertex) | + ((bool)tcmData.cen << TriggerType::bitCen) | + ((bool)tcmData.sCen << TriggerType::bitSCen) | + ((bool)tcmData.laser << 5) | + ((bool)tcmData.outputsAreBlocked << 6) | + ((bool)tcmData.dataIsValid << 7); + trg.nChanA = (int8_t)tcmData.nChanA; + trg.nChanC = (int8_t)tcmData.nChanC; + trg.amplA = (int32_t)tcmData.amplA; + trg.amplC = (int32_t)tcmData.amplC; + trg.timeA = (int16_t)tcmData.timeA; + trg.timeC = (int16_t)tcmData.timeC; +} +//FV0 +template <typename DigitType, typename TCMDataType> +auto ConvertTCMData2Digit(DigitType& digit, const TCMDataType& tcmData) -> std::enable_if_t<IsFV0<DigitType>::value> +{ + using TriggerType = decltype(digit.mTriggers); + auto& trg = digit.mTriggers; + //Taken from FT0 + /* + trg.triggersignals = ((bool)tcmData.orA << TriggerType::bitA) | + ((bool)tcmData.orC << TriggerType::bitC) | + ((bool)tcmData.vertex << TriggerType::bitVertex) | + ((bool)tcmData.cen << TriggerType::bitCen) | + ((bool)tcmData.sCen << TriggerType::bitSCen) | + ((bool)tcmData.laser << TriggerType::bitLaser); + */ + //Temporary + trg.triggerSignals = ((bool)tcmData.orA << 0) | + ((bool)tcmData.orC << 1) | + ((bool)tcmData.sCen << 2) | + ((bool)tcmData.cen << 3) | + ((bool)tcmData.vertex << 4) | + ((bool)tcmData.laser << 5) | + ((bool)tcmData.outputsAreBlocked << 6) | + ((bool)tcmData.dataIsValid << 7); + trg.nChanA = (int8_t)tcmData.nChanA; + //trg.nChanC = (int8_t)tcmData.nChanC; + trg.amplA = (int32_t)tcmData.amplA; + //trg.amplC = (int32_t)tcmData.amplC; + //trg.timeA = (int16_t)tcmData.timeA; + //trg.timeC = (int16_t)tcmData.timeC; +} +//PM to ChannelData convertation +//FT0 +template <typename LookupTableType, typename ChannelDataType, typename PMDataType> +auto ConvertEventData2ChData(std::vector<ChannelDataType>& vecChData, const PMDataType& pmData, int linkID, int ep) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().QTCAmpl), int16_t>::value> +{ + bool isValid{}; + const auto globalChID = LookupTableType::Instance().getChannel(linkID, ep, pmData.channelID, isValid); + if (isValid) { + vecChData.emplace_back(static_cast<uint8_t>(globalChID), static_cast<int>(pmData.time), static_cast<int>(pmData.charge), static_cast<uint8_t>(pmData.getFlagWord())); + } else { + LOG(WARNING) << "Incorrect global channel! linkID: " << linkID << " | EndPoint: " << ep << " | LocalChID: " << pmData.channelID; + } +} +//FV0 +template <typename LookupTableType, typename ChannelDataType, typename PMDataType> +auto ConvertEventData2ChData(std::vector<ChannelDataType>& vecChData, const PMDataType& pmData, int linkID, int ep) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().chargeAdc), Short_t>::value> +{ + bool isValid{}; + const auto globalChID = LookupTableType::Instance().getChannel(linkID, ep, pmData.channelID, isValid); + if (isValid) { + vecChData.emplace_back(static_cast<Short_t>(globalChID), static_cast<Float_t>(pmData.time), static_cast<Short_t>(pmData.charge)); + } else { + LOG(WARNING) << "Incorrect global channel! linkID: " << linkID << " | EndPoint: " << ep << " | LocalChID: " << pmData.channelID; + } +} +//FDD +template <typename LookupTableType, typename ChannelDataType, typename PMDataType> +auto ConvertEventData2ChData(std::vector<ChannelDataType>& vecChData, const PMDataType& pmData, int linkID, int ep) -> std::enable_if_t<std::is_same<decltype(std::declval<ChannelDataType>().mChargeADC), int16_t>::value> +{ + bool isValid{}; + const auto globalChID = LookupTableType::Instance().getChannel(linkID, ep, pmData.channelID, isValid); + if (isValid) { + vecChData.emplace_back(static_cast<uint8_t>(globalChID), static_cast<int>(pmData.time), static_cast<int>(pmData.charge), static_cast<uint8_t>(pmData.getFlagWord())); + } else { + LOG(WARNING) << "Incorrect global channel! linkID: " << linkID << " | EndPoint: " << ep << " | LocalChID: " << pmData.channelID; + } +} +//Interface for extracting interaction record from Digit +template <typename T> +auto GetIntRecord(const T& digit) -> std::enable_if_t<!IsFV0<T>::value, o2::InteractionRecord> +{ + return digit.mIntRecord; +} +template <typename T> +auto GetIntRecord(const T& digit) -> std::enable_if_t<IsFV0<T>::value, o2::InteractionRecord> +{ + return digit.ir; +} +} // namespace DigitBlockFIThelper + +//Normal data taking mode +template <typename LookupTableType, typename DigitType, typename ChannelDataType> +class DigitBlockFIT : public DigitBlockBase<DigitType, ChannelDataType> +{ + public: + using DigitBlockFIT_t = DigitBlockFIT<LookupTableType, DigitType, ChannelDataType>; + typedef DigitBlockBase<DigitType, ChannelDataType> DigitBlockBase_t; + typedef LookupTableType LookupTable_t; + template <typename... Args> + DigitBlockFIT(Args&&... args) : DigitBlockBase_t(std::forward<Args>(args)...) + { + } + DigitBlockFIT() = default; + DigitBlockFIT(const DigitBlockFIT& other) = default; + ~DigitBlockFIT() = default; + //Filling data from PM + template <class DataBlockType> + auto processDigits(const DataBlockType& dataBlock, int linkID, int ep) -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockPM, DataBlockType>::value> + { + for (int iEventData = 0; iEventData < dataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mNelements; iEventData++) { + const auto& pmData = dataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mData[iEventData]; + DigitBlockFIThelper::ConvertEventData2ChData<LookupTable_t>(DigitBlockBase_t::mSubDigit, pmData, linkID, ep); + } + } + //Filling data from TCM (normal mode) + template <class DataBlockType> + auto processDigits(const DataBlockType& dataBlock, int linkID, int ep) -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockTCM, DataBlockType>::value> + { + auto& tcmData = dataBlock.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mData[0]; + DigitBlockFIThelper::ConvertTCMData2Digit(DigitBlockBase_t::mDigit, tcmData); + } + //Decompose digits into DataBlocks + //DataBlockPM + template <class DataBlockType> + auto decomposeDigits() const -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockPM, DataBlockType>::value, std::map<typename LookupTable_t::Topo_t, DataBlockType>> + { + using Topo_t = typename LookupTable_t::Topo_t; + std::map<Topo_t, DataBlockType> mapResult; + std::map<Topo_t, std::reference_wrapper<const ChannelDataType>> mapTopo2SortedCh; + std::map<Topo_t, std::size_t> mapTopoCounter; + //Preparing map "Topo to ChannelData refs" and map "Global Topo(FEE metadata) to number of ChannelData" + for (const auto& entry : DigitBlockBase_t::mSubDigit) { + auto topoPM = LookupTable_t::Instance().getTopoPM(static_cast<int>(entry.getChannelID())); + mapTopo2SortedCh.insert({topoPM, entry}); + auto pairInserted = mapTopoCounter.insert({LookupTable_t::makeGlobalTopo(topoPM), 0}); + pairInserted.first->second++; + } + //Preparing map of global Topo(related to PM module) to DataBlockPMs + for (const auto& entry : mapTopo2SortedCh) { + auto pairInserted = mapResult.insert({LookupTable_t::makeGlobalTopo(entry.first), {}}); + auto& refDataBlock = pairInserted.first->second; + if (pairInserted.second) { + //Header preparation + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].setIntRec(DigitBlockFIThelper::GetIntRecord(DigitBlockBase_t::mDigit)); + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].startDescriptor = 0xf; + std::size_t nElements = mapTopoCounter.find(pairInserted.first->first)->second; + std::size_t nWords = nElements / 2 + nElements % 2; + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].nGBTWords = nWords; + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mNelements = 1; + } + //Data preparation + auto& refPos = refDataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mNelements; + auto& refData = refDataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mData[refPos]; + refPos++; + DigitBlockFIThelper::ConvertChData2EventData(entry.second.get(), refData, LookupTable_t::Instance().getLocalChannelID(entry.first)); + } + return mapResult; + } + //DataBlockTCM + template <class DataBlockType> + auto decomposeDigits() const -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockTCM, DataBlockType>::value, std::pair<typename LookupTable_t::Topo_t, DataBlockType>> + { + DataBlockType dataBlockTCM{}; + //Header preparation + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCM>::mData[0].setIntRec(DigitBlockFIThelper::GetIntRecord(DigitBlockBase_t::mDigit)); + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCM>::mData[0].startDescriptor = 0xf; + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCM>::mData[0].nGBTWords = + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::MaxNwords; + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCM>::mNelements = 1; + auto& refTCMdata = dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mData[0]; + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mNelements = 1; + + //Data preparation + DigitBlockFIThelper::ConvertDigit2TCMData(DigitBlockBase_t::mDigit, refTCMdata); + return {LookupTable_t::Instance().getTopoTCM(), dataBlockTCM}; + } + //Process DigitBlocks from TTree + template <typename DigitBlockProcType> + static void processDigitBlocks(TTree* inputTree, DigitBlockProcType& digitBlockProc) + { + assert(inputTree != nullptr); + std::vector<DigitBlockFIT_t> vecResult; + std::vector<typename DigitBlockBase_t::Digit_t> vecDigit; + std::vector<typename DigitBlockBase_t::Digit_t>* ptrVecDigit = &vecDigit; + typename DigitBlockBase_t::SubDigit_t vecChannelData; + typename DigitBlockBase_t::SubDigit_t* ptrVecChannelData = &vecChannelData; + inputTree->SetBranchAddress(decltype(vecDigit)::value_type::sDigitBranchName, &ptrVecDigit); + inputTree->SetBranchAddress(decltype(vecChannelData)::value_type::sDigitBranchName, &ptrVecChannelData); + for (int iEntry = 0; iEntry < inputTree->GetEntries(); iEntry++) { + inputTree->GetEntry(iEntry); + LOG(INFO) << "Processing TF " << iEntry; + digitBlockProc.processDigitBlockPerTF(DigitBlockBase_t::template makeDigitBlock<DigitBlockFIT_t>(vecDigit, vecChannelData)); + } + } + template <typename VecDigitType, typename VecChannelDataType, typename VecDetTrigInputType> + void getDigits(VecDigitType& vecDigits, VecChannelDataType& vecChannelData, VecDetTrigInputType& vecTriggerInput) + { + DigitBlockBase_t::mDigit.fillTrgInputVec(vecTriggerInput); + DigitBlockBase_t::getSubDigits(vecDigits, vecChannelData); + } + template <typename VecDigitType, typename VecChannelDataType> + void getDigits(VecDigitType& vecDigits, VecChannelDataType& vecChannelData) + { + DigitBlockBase_t::getSubDigits(vecDigits, vecChannelData); + } + static void print(const std::vector<DigitType>& vecDigit, const std::vector<ChannelDataType>& vecChannelData) + { + for (const auto& digit : vecDigit) { + digit.printLog(); + LOG(INFO) << "______________CHANNEL DATA____________"; + for (int iChData = digit.ref.getFirstEntry(); iChData < digit.ref.getFirstEntry() + digit.ref.getEntries(); iChData++) { + vecChannelData[iChData].printLog(); + } + LOG(INFO) << "______________________________________"; + } + } + void print() const + { + DigitBlockBase_t::print(); + } +}; + +//TCM extended data taking mode +template <typename LookupTableType, typename DigitType, typename ChannelDataType, typename TriggersExtType> +class DigitBlockFIText : public DigitBlockBase<DigitType, ChannelDataType, TriggersExtType> +{ + public: + using DigitBlockFIT_t = DigitBlockFIText<LookupTableType, DigitType, ChannelDataType, TriggersExtType>; + typedef DigitBlockBase<DigitType, ChannelDataType, TriggersExtType> DigitBlockBase_t; + typedef LookupTableType LookupTable_t; + template <typename... Args> + DigitBlockFIText(Args&&... args) : DigitBlockBase_t(std::forward<Args>(args)...) + { + } + DigitBlockFIText() = default; + DigitBlockFIText(const DigitBlockFIText& other) = default; + ~DigitBlockFIText() = default; + //Filling data from PM + template <class DataBlockType> + auto processDigits(const DataBlockType& dataBlock, int linkID, int ep) -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockPM, DataBlockType>::value> + { + for (int iEventData = 0; iEventData < dataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mNelements; iEventData++) { + const auto& pmData = dataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mData[iEventData]; + DigitBlockFIThelper::ConvertEventData2ChData<LookupTable_t>(DigitBlockBase_t::mSubDigit, pmData, linkID, ep); + } + } + //Filling data from TCM (extended mode) + template <class DataBlockType> + auto processDigits(const DataBlockType& dataBlock, int linkID, int ep) -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockTCMext, DataBlockType>::value> + { + auto& tcmData = dataBlock.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mData[0]; + DigitBlockFIThelper::ConvertTCMData2Digit(DigitBlockBase_t::mDigit, tcmData); + DigitBlockBase_t::mSingleSubDigit.mIntRecord = DigitBlockFIThelper::GetIntRecord(DigitBlockBase_t::mDigit); + for (int iTriggerWord = 0; iTriggerWord < dataBlock.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mNelements; iTriggerWord++) { + DigitBlockBase_t::mSingleSubDigit.setTrgWord(dataBlock.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mData[iTriggerWord].triggerWord, iTriggerWord); + } + } + //Decompose digits into DataBlocks + //DataBlockPM + template <class DataBlockType> + auto decomposeDigits() const -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockPM, DataBlockType>::value, std::map<typename LookupTable_t::Topo_t, DataBlockType>> + { + using Topo_t = typename LookupTable_t::Topo_t; + std::map<Topo_t, DataBlockType> mapResult; + std::map<Topo_t, std::reference_wrapper<const ChannelDataType>> mapTopo2SortedCh; + std::map<Topo_t, std::size_t> mapTopoCounter; + //Preparing map "Topo to ChannelData refs" and map "Global Topo(FEE metadata) to number of ChannelData" + for (const auto& entry : DigitBlockBase_t::mSubDigit) { + auto topoPM = LookupTable_t::Instance().getTopoPM(static_cast<int>(entry.getChannelID())); + mapTopo2SortedCh.insert({topoPM, entry}); + auto pairInserted = mapTopoCounter.insert({LookupTable_t::makeGlobalTopo(topoPM), 0}); + pairInserted.first->second++; + } + //Preparing map of global Topo(related to PM module) to DataBlockPMs + for (const auto& entry : mapTopo2SortedCh) { + auto pairInserted = mapResult.insert({LookupTable_t::makeGlobalTopo(entry.first), {}}); + auto& refDataBlock = pairInserted.first->second; + if (pairInserted.second) { + //Header preparation + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].setIntRec(DigitBlockFIThelper::GetIntRecord(DigitBlockBase_t::mDigit)); + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].startDescriptor = 0xf; + std::size_t nElements = mapTopoCounter.find(pairInserted.first->first)->second; + std::size_t nWords = nElements / 2 + nElements % 2; + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mData[0].nGBTWords = nWords; + refDataBlock.DataBlockWrapper<typename DataBlockType::RawHeaderPM>::mNelements = 1; + } + //Data preparation + auto& refPos = refDataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mNelements; + auto& refData = refDataBlock.DataBlockWrapper<typename DataBlockType::RawDataPM>::mData[refPos]; + refPos++; + DigitBlockFIThelper::ConvertChData2EventData(entry.second.get(), refData, LookupTable_t::Instance().getLocalChannelID(entry.first)); + } + return mapResult; + } + //DataBlockTCM + template <class DataBlockType> + auto decomposeDigits() const -> std::enable_if_t<DigitBlockHelper::IsSpecOfType<DataBlockTCMext, DataBlockType>::value, std::pair<typename LookupTable_t::Topo_t, DataBlockType>> + { + DataBlockType dataBlockTCM{}; + //Header preparation + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCMext>::mData[0].setIntRec(DigitBlockFIThelper::GetIntRecord(DigitBlockBase_t::mDigit)); + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCMext>::mData[0].startDescriptor = 0xf; + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCMext>::mData[0].nGBTWords = dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::MaxNwords + + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::MaxNwords; + + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawHeaderTCM>::mNelements = 1; + auto& refTCMdata = dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mData[0]; + //Data preparation + DigitBlockFIThelper::ConvertDigit2TCMData(DigitBlockBase_t::mDigit, refTCMdata); + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCM>::mNelements = 1; + //Extended mode + static_assert(std::decay<decltype(dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mData[0])>::type::MaxNelements == std::tuple_size<decltype(DigitBlockBase_t::mSingleSubDigit.mTriggerWords)>::value); + for (int i = 0; i < std::decay<decltype(dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mData[0])>::type::MaxNelements; i++) { + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mData[i].triggerWord = DigitBlockBase_t::mSingleSubDigit.mTriggerWords[i]; + } + dataBlockTCM.DataBlockWrapper<typename DataBlockType::RawDataTCMext>::mNelements = 1; + return {LookupTable_t::Instance().getTopoTCM(), dataBlockTCM}; + } + template <typename VecDigitType, typename VecChannelDataType, typename VecTriggersExtType, typename VecDetTrigInputType> + void getDigits(VecDigitType& vecDigits, VecChannelDataType& vecChannelData, VecTriggersExtType& vecTriggersExt, VecDetTrigInputType& vecTriggerInput) + { + DigitBlockBase_t::mDigit.fillTrgInputVec(vecTriggerInput); + getDigits(vecDigits, vecChannelData, vecTriggersExt); + } + template <typename VecDigitType, typename VecChannelDataType, typename VecTriggersExtType> + void getDigits(VecDigitType& vecDigits, VecChannelDataType& vecChannelData, VecTriggersExtType& vecTriggersExt) + { + DigitBlockBase_t::getSubDigits(vecDigits, vecChannelData); + DigitBlockBase_t::getSingleSubDigits(vecTriggersExt); + } + static void print(const std::vector<DigitType>& vecDigit, const std::vector<ChannelDataType>& vecChannelData, const std::vector<TriggersExtType>& vecTriggersExt) + { + for (const auto& digit : vecDigit) { + digit.printLog(); + LOG(INFO) << "______________CHANNEL DATA____________"; + for (int iChData = digit.ref.getFirstEntry(); iChData < digit.ref.getFirstEntry() + digit.ref.getEntries(); iChData++) { + vecChannelData[iChData].printLog(); + } + LOG(INFO) << "______________________________________"; + } + LOG(INFO) << "______________EXTENDED TRIGGERS____________"; + for (const auto& trgExt : vecTriggersExt) { + trgExt.printLog(); + } + LOG(INFO) << "______________________________________"; + } + void print() const + { + DigitBlockBase_t::print(); + } +}; +} // namespace fit +} // namespace o2 +#endif diff --git a/Detectors/FIT/raw/include/FITRaw/RawReaderBase.h b/Detectors/FIT/raw/include/FITRaw/RawReaderBase.h index bea49dd68fc07..a582835fa4059 100644 --- a/Detectors/FIT/raw/include/FITRaw/RawReaderBase.h +++ b/Detectors/FIT/raw/include/FITRaw/RawReaderBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,8 +19,15 @@ #ifndef ALICEO2_FIT_RAWREADERBASE_H_ #define ALICEO2_FIT_RAWREADERBASE_H_ #include <iostream> +#include <type_traits> #include <vector> #include <map> +#include <tuple> + +#include <boost/mpl/vector.hpp> +#include <boost/mpl/set.hpp> +#include <boost/mpl/find.hpp> +#include <boost/mpl/count.hpp> #include <Rtypes.h> #include <CommonDataFormat/InteractionRecord.h> @@ -31,66 +39,93 @@ namespace o2 { namespace fit { -template <class DigitBlockType> +template <typename DigitBlockType, typename... DataBlockTypes> class RawReaderBase { public: RawReaderBase() = default; ~RawReaderBase() = default; - - std::map<InteractionRecord, DigitBlockType> mMapDigits; - + typedef DigitBlockType DigitBlock_t; + typedef boost::mpl::vector<DataBlockTypes...> VecDataBlocks_t; + std::tuple<std::vector<DataBlockTypes>...> mTupleVecDataBlocks; + std::map<InteractionRecord, DigitBlock_t> mMapDigits; + template <typename T> + constexpr std::vector<T>& getVecDataBlocks() + { + typedef typename boost::mpl::find<VecDataBlocks_t, T>::type it_t; + return std::get<it_t::pos::value>(mTupleVecDataBlocks); + } //decoding binary data into data blocks template <class DataBlockType> size_t decodeBlocks(const gsl::span<const uint8_t> binaryPayload, std::vector<DataBlockType>& vecDataBlocks) { size_t srcPos = 0; - while (srcPos < binaryPayload.size()) { //checking element - DataBlockType dataBlock; - dataBlock.decodeBlock(binaryPayload, srcPos); - srcPos += dataBlock.mSize; - if (dataBlock.isCorrect()) { - vecDataBlocks.push_back(dataBlock); //change to in-place construction? TODO - } else { - LOG(INFO) << "WARNING! INCORRECT DATA BLOCK!"; + while (srcPos < binaryPayload.size()) { + auto& refDataBlock = vecDataBlocks.emplace_back(); + refDataBlock.decodeBlock(binaryPayload, srcPos); + srcPos += refDataBlock.mSize; + if (!refDataBlock.isCorrect()) { + LOG(WARNING) << "INCORRECT DATA BLOCK! Byte position: " << srcPos - refDataBlock.mSize << " | Payload size: " << binaryPayload.size() << " | DataBlock size: " << refDataBlock.mSize; + refDataBlock.print(); + vecDataBlocks.pop_back(); + return srcPos; + } + if (refDataBlock.getNgbtWords() == 0) { + vecDataBlocks.pop_back(); + continue; } } return srcPos; } //processing data blocks into digits - template <class DataBlockType> - void processBinaryData(gsl::span<const uint8_t> payload, int linkID) + template <class DataBlockType, typename... T> + void processBinaryData(gsl::span<const uint8_t> payload, T&&... feeParameters) { - std::vector<DataBlockType> vecDataBlocks; + auto& vecDataBlocks = getVecDataBlocks<DataBlockType>(); auto srcPos = decodeBlocks(payload, vecDataBlocks); - - for (auto& dataBlock : vecDataBlocks) { + for (const auto& dataBlock : vecDataBlocks) { auto intRec = dataBlock.getInteractionRecord(); auto [digitIter, isNew] = mMapDigits.try_emplace(intRec, intRec); - digitIter->second.template process<DataBlockType>(dataBlock, linkID); + digitIter->second.template processDigits<DataBlockType>(dataBlock, std::forward<T>(feeParameters)...); } + vecDataBlocks.clear(); + /* //Must be checked for perfomance + std::size_t srcPos = 0; + while (srcPos < payload.size()) { + DataBlockType dataBlock{}; + dataBlock.decodeBlock(payload, srcPos); + srcPos += dataBlock.mSize; + if (!dataBlock.isCorrect()) { + LOG(WARNING) << "INCORRECT DATA BLOCK! Byte position: " << srcPos << " | Payload size: " << payload.size() << " | DataBlock size: " << dataBlock.mSize; + //dataBlock.print(); + return; + } + auto intRec = dataBlock.getInteractionRecord(); + auto [digitIter, isNew] = mMapDigits.try_emplace(intRec, intRec); + digitIter->second.template processDigits<DataBlockType>(dataBlock, std::forward<T>(feeParameters)...); + } + */ } - /* - void process(int linkID, gsl::span<const uint8_t> payload) - { - static_cast<RawReader*>(this)->processDigits(linkID,payload); - } - */ //pop digits - template <class... DigitType> - int getDigits(std::vector<DigitType>&... vecDigit) + template <typename... VecDigitType> + int getDigits(VecDigitType&... vecDigit) { int digitCounter = mMapDigits.size(); for (auto& digit : mMapDigits) { - digit.second.pop(vecDigit...); + digit.second.getDigits(vecDigit...); } mMapDigits.clear(); return digitCounter; } + + private: + //Check for unique DataBlock classes + //Line below will not be compiled in case of duplicates among DataBlockTypes + typedef std::void_t<std::enable_if_t<boost::mpl::count<boost::mpl::set<DataBlockTypes...>, DataBlockTypes>::value == 1>...> CheckUniqueTypes; }; } // namespace fit } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/FIT/raw/include/FITRaw/RawReaderBaseFIT.h b/Detectors/FIT/raw/include/FITRaw/RawReaderBaseFIT.h new file mode 100644 index 0000000000000..12ff497826c0f --- /dev/null +++ b/Detectors/FIT/raw/include/FITRaw/RawReaderBaseFIT.h @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderFITBase.h Base class for RAW data reading +// +// Artur.Furs +// afurs@cern.ch +// +//Main purpuse is to decode FIT data blocks and push them to DigitBlockFIT for proccess +//Base class only provides static linkID-moduleType conformity + +#ifndef ALICEO2_FIT_RAWREADERBASEFIT_H_ +#define ALICEO2_FIT_RAWREADERBASEFIT_H_ +#include <iostream> +#include <vector> +#include <Rtypes.h> +#include "FITRaw/RawReaderBase.h" +#include <CommonDataFormat/InteractionRecord.h> +#include "Headers/RAWDataHeader.h" + +#include <gsl/span> + +namespace o2 +{ +namespace fit +{ + +// Common raw reader for FIT +template <typename DigitBlockFITtype, typename DataBlockPMtype, typename DataBlockTCMtype> +class RawReaderBaseFIT : public RawReaderBase<DigitBlockFITtype, DataBlockPMtype, DataBlockTCMtype> +{ + public: + typedef DigitBlockFITtype DigitBlockFIT_t; + typedef typename DigitBlockFIT_t::LookupTable_t LookupTable_t; + typedef DataBlockPMtype DataBlockPM_t; + typedef DataBlockTCMtype DataBlockTCM_t; + typedef RawReaderBase<DigitBlockFIT_t, DataBlockPM_t, DataBlockTCM_t> RawReaderBase_t; + RawReaderBaseFIT() = default; + ~RawReaderBaseFIT() = default; + void reserve(std::size_t nElements, std::size_t nElemMap = 0) + { + auto& vecDataBlocksPM = RawReaderBase_t::template getVecDataBlocks<DataBlockPM_t>(); + vecDataBlocksPM.reserve(nElements); + auto& vecDataBlocksTCM = RawReaderBase_t::template getVecDataBlocks<DataBlockTCM_t>(); + vecDataBlocksTCM.reserve(nElements); + //one need to reserve memory for map + for (std::size_t iElem = 0; iElem < nElemMap; iElem++) { + RawReaderBase_t::mMapDigits.emplace(o2::InteractionRecord(0, iElem), o2::InteractionRecord(0, iElem)); + } + RawReaderBase_t::mMapDigits.clear(); + } + //deserialize payload to raw data blocks and proccesss them to digits + template <typename... T> + void process(gsl::span<const uint8_t> payload, T&&... feeParameters) + { + if (LookupTable_t::Instance().isTCM(std::forward<T>(feeParameters)...)) { + //TCM data proccessing + RawReaderBase_t::template processBinaryData<DataBlockTCM_t>(payload, std::forward<T>(feeParameters)...); + } else { + //PM data proccessing + RawReaderBase_t::template processBinaryData<DataBlockPM_t>(payload, std::forward<T>(feeParameters)...); + } + } +}; +} // namespace fit +} // namespace o2 + +#endif diff --git a/Detectors/FIT/raw/include/FITRaw/RawWriterFIT.h b/Detectors/FIT/raw/include/FITRaw/RawWriterFIT.h new file mode 100644 index 0000000000000..80cf3cbd608fe --- /dev/null +++ b/Detectors/FIT/raw/include/FITRaw/RawWriterFIT.h @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawWriterFIT.h Base class for RAW data writing +// +// Artur.Furs +// afurs@cern.ch + +#ifndef ALICEO2_FIT_RAWREADERBASEFIT_H_ +#define ALICEO2_FIT_RAWREADERBASEFIT_H_ +#include <iostream> +#include <vector> +#include <Rtypes.h> +#include "FITRaw/DataBlockFIT.h" +#include "FITRaw/DigitBlockFIT.h" +#include <Framework/Logger.h> +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "CommonUtils/StringUtils.h" +#include <gsl/span> +#include <fmt/format.h> + +namespace o2 +{ +namespace fit +{ + +// Raw writer for FIT, based on RawReader +template <typename DigitBlockFITtype, typename DataBlockPMtype, typename DataBlockTCMtype> +class RawWriterFIT +{ + public: + typedef DigitBlockFITtype DigitBlockFIT_t; + typedef typename DigitBlockFIT_t::LookupTable_t LookupTable_t; + typedef typename LookupTable_t::Topo_t Topo_t; + typedef DataBlockPMtype DataBlockPM_t; + typedef DataBlockTCMtype DataBlockTCM_t; + using RDHUtils = o2::raw::RDHUtils; + RawWriterFIT() = default; + ~RawWriterFIT() = default; + o2::raw::RawFileWriter& getWriter() { return mWriter; } + void setFileFor(const std::string& fileFor) { mFileFor = fileFor; } + void setFlpName(const std::string& flpName) { mFlpName = flpName; } + bool getFilePerLink() const { return mOutputPerLink; } + void setVerbosity(int verbosityLevel) { mVerbosity = verbosityLevel; } + void setCCDBurl(const std::string& ccdbPath) { LookupTable_t::setCCDBurl(ccdbPath); } + void setLUTpath(const std::string& lutPath) { LookupTable_t::setLUTpath(lutPath); } + int getVerbosity() const { return mVerbosity; } + int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const + { + return 0; // do not split, always start new CRU page + } + void convertDigitsToRaw(const std::string& outputDir, const std::string& filenameDigits) + { + LOG(INFO) << "Converting Digits to Raw data..."; + mWriter.setCarryOverCallBack(this); + LookupTable_t::Instance().printFullMap(); + //Preparing topo2FEEmetadata map + mMapTopo2FEEmetadata.clear(); + mMapTopo2FEEmetadata = LookupTable_t::Instance().template makeMapFEEmetadata<o2::header::RAWDataHeader, RDHUtils>(); + //Preparing filenames + std::string detName = LookupTable_t::sDetectorName; + auto makeFilename = [&](const o2::header::RAWDataHeader& rdh) -> std::string { + std::string maskName{}; + if (mFileFor != "all") { // single file for all links + maskName += fmt::format("_{}", mFlpName); + if (mFileFor != "flp") { + maskName += fmt::format("_cru{}_{}", RDHUtils::getCRUID(rdh), RDHUtils::getEndPointID(rdh)); + if (mFileFor != "cru") { + maskName += fmt::format("_lnk{}_feeid{}", RDHUtils::getLinkID(rdh), RDHUtils::getFEEID(rdh)); + if (mFileFor != "link") { + throw std::runtime_error("invalid option provided for file grouping"); + } + } + } + } + std::string outputFilename = o2::utils::Str::concat_string(outputDir, detName, maskName, ".raw"); + return outputFilename; + }; + //Registering links + for (const auto& metadataPair : mMapTopo2FEEmetadata) { + const auto& rdh = metadataPair.second; + const auto outputFilename = makeFilename(rdh); + mWriter.registerLink(RDHUtils::getFEEID(rdh), RDHUtils::getCRUID(rdh), RDHUtils::getLinkID(rdh), RDHUtils::getEndPointID(rdh), outputFilename); + } + //Processing digits into raw data + TFile* inputFile = TFile::Open(filenameDigits.c_str()); + assert(inputFile != nullptr); + LOG(INFO) << "Source file: " << filenameDigits; + TTree* inputTree = dynamic_cast<TTree*>(inputFile->Get("o2sim")); + DigitBlockFIT_t::processDigitBlocks(inputTree, *this); + delete inputTree; + inputFile->Close(); + delete inputFile; + } + void processDigitBlockPerTF(const std::vector<DigitBlockFIT_t>& vecDigitBlock) // Is used in DigitBlockFIT_t::processDigitBlocks for each TF (TTree entry) + { + for (const auto& digitBlock : vecDigitBlock) { + //Processing PM data + auto mapDataBlockPM = digitBlock.template decomposeDigits<DataBlockPM_t>(); + if (mVerbosity > 0) { + digitBlock.print(); + } + for (const auto& dataBlockPair : mapDataBlockPM) { + const auto& topo = dataBlockPair.first; + const auto& dataBlock = dataBlockPair.second; + const auto itRdh = mMapTopo2FEEmetadata.find(topo); + if (itRdh == mMapTopo2FEEmetadata.end()) { + LOG(WARNING) << "No CRU entry in map! Data block: "; + dataBlock.print(); + continue; + } + if (mVerbosity > 0) { + dataBlock.print(); + } + const auto& rdh = itRdh->second; + auto data = dataBlock.serialize(); + mWriter.addData(RDHUtils::getFEEID(rdh), RDHUtils::getCRUID(rdh), RDHUtils::getLinkID(rdh), RDHUtils::getEndPointID(rdh), dataBlock.getInteractionRecord(), data); + } + //Processing TCM data + const auto dataBlockPair = digitBlock.template decomposeDigits<DataBlockTCM_t>(); + const auto& topo = dataBlockPair.first; + const auto& dataBlock = dataBlockPair.second; + const auto itRdh = mMapTopo2FEEmetadata.find(topo); + if (itRdh == mMapTopo2FEEmetadata.end()) { + LOG(WARNING) << "No CRU entry in map! Data block: "; + dataBlock.print(); + continue; + } + if (mVerbosity > 0) { + dataBlock.print(); + } + const auto& rdh = itRdh->second; + auto data = dataBlock.serialize(); + mWriter.addData(RDHUtils::getFEEID(rdh), RDHUtils::getCRUID(rdh), RDHUtils::getLinkID(rdh), RDHUtils::getEndPointID(rdh), dataBlock.getInteractionRecord(), data); + } + } + + o2::raw::RawFileWriter mWriter{LookupTable_t::sDetectorName}; + std::string mFlpName{}; + std::string mFileFor{}; + std::map<Topo_t, o2::header::RAWDataHeader> mMapTopo2FEEmetadata; + //const o2::raw::HBFUtils& mSampler = o2::raw::HBFUtils::Instance(); + bool mOutputPerLink = false; + int mVerbosity = 0; +}; +} // namespace fit +} // namespace o2 + +#endif diff --git a/Detectors/FIT/raw/src/DataBlockBase.cxx b/Detectors/FIT/raw/src/DataBlockBase.cxx index 82ed86360af98..a2d30a36a4789 100644 --- a/Detectors/FIT/raw/src/DataBlockBase.cxx +++ b/Detectors/FIT/raw/src/DataBlockBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/raw/src/DataBlockFIT.cxx b/Detectors/FIT/raw/src/DataBlockFIT.cxx new file mode 100644 index 0000000000000..fb8c32311bf55 --- /dev/null +++ b/Detectors/FIT/raw/src/DataBlockFIT.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FITRaw/DataBlockFIT.h" +using namespace o2::fit; diff --git a/Detectors/FIT/raw/src/DigitBlockBase.cxx b/Detectors/FIT/raw/src/DigitBlockBase.cxx index 9e626d77b064a..6381a86559b33 100644 --- a/Detectors/FIT/raw/src/DigitBlockBase.cxx +++ b/Detectors/FIT/raw/src/DigitBlockBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/raw/src/DigitBlockFIT.cxx b/Detectors/FIT/raw/src/DigitBlockFIT.cxx new file mode 100644 index 0000000000000..6d9d7f4e9ee15 --- /dev/null +++ b/Detectors/FIT/raw/src/DigitBlockFIT.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FITRaw/DigitBlockFIT.h" diff --git a/Detectors/FIT/raw/src/FITRawLinkDef.h b/Detectors/FIT/raw/src/FITRawLinkDef.h deleted file mode 100644 index 71519a02a652e..0000000000000 --- a/Detectors/FIT/raw/src/FITRawLinkDef.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#endif diff --git a/Detectors/FIT/raw/src/RawReaderBase.cxx b/Detectors/FIT/raw/src/RawReaderBase.cxx index 24b38a3138533..2146ce1c3a6f5 100644 --- a/Detectors/FIT/raw/src/RawReaderBase.cxx +++ b/Detectors/FIT/raw/src/RawReaderBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/FIT/raw/src/RawReaderBaseFIT.cxx b/Detectors/FIT/raw/src/RawReaderBaseFIT.cxx new file mode 100644 index 0000000000000..003bdcb12574b --- /dev/null +++ b/Detectors/FIT/raw/src/RawReaderBaseFIT.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FITRaw/RawReaderBaseFIT.h" +using namespace o2::fit; diff --git a/Detectors/FIT/raw/src/RawWriterFIT.cxx b/Detectors/FIT/raw/src/RawWriterFIT.cxx new file mode 100644 index 0000000000000..3d8276af67486 --- /dev/null +++ b/Detectors/FIT/raw/src/RawWriterFIT.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FITRaw/RawWriterFIT.h" +using namespace o2::fit; diff --git a/Detectors/FIT/workflow/CMakeLists.txt b/Detectors/FIT/workflow/CMakeLists.txt new file mode 100644 index 0000000000000..be3c19ef8e78d --- /dev/null +++ b/Detectors/FIT/workflow/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FITWorkflow + SOURCES src/FITDataReaderDPLSpec.cxx + src/FITDigitWriterSpec.cxx + src/RawReaderFIT.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DetectorsCommonDataFormats + O2::DPLUtils + O2::FITRaw) diff --git a/Detectors/FIT/workflow/include/FITWorkflow/FITDataReaderDPLSpec.h b/Detectors/FIT/workflow/include/FITWorkflow/FITDataReaderDPLSpec.h new file mode 100644 index 0000000000000..931378f5e574b --- /dev/null +++ b/Detectors/FIT/workflow/include/FITWorkflow/FITDataReaderDPLSpec.h @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FITDataReaderDPLSpec.h + +#ifndef O2_FITDATAREADERDPLSPEC_H +#define O2_FITDATAREADERDPLSPEC_H +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/SerializationMethods.h" +#include "DPLUtils/DPLRawParser.h" +#include "Framework/InputRecordWalker.h" +#include <string> +#include <iostream> +#include <vector> +#include <gsl/span> +#include <chrono> +using namespace o2::framework; + +namespace o2 +{ +namespace fit +{ +template <typename RawReaderType> +class FITDataReaderDPLSpec : public Task +{ + public: + FITDataReaderDPLSpec(const RawReaderType& rawReader) : mRawReader(rawReader) {} + FITDataReaderDPLSpec() = delete; + ~FITDataReaderDPLSpec() override = default; + typedef RawReaderType RawReader_t; + RawReader_t mRawReader; + void init(InitContext& ic) final + { + auto ccdbUrl = ic.options().get<std::string>("ccdb-path"); + auto lutPath = ic.options().get<std::string>("lut-path"); + if (ccdbUrl != "") { + RawReader_t::LookupTable_t::setCCDBurl(ccdbUrl); + } + if (lutPath != "") { + RawReader_t::LookupTable_t::setLUTpath(lutPath); + } + RawReader_t::LookupTable_t::Instance().printFullMap(); + auto nReserveVecDig = ic.options().get<int>("reserve-vec-dig"); + auto nReserveVecChData = ic.options().get<int>("reserve-vec-chdata"); + auto nReserveVecBuffer = ic.options().get<int>("reserve-vec-buffer"); + auto nReserveMapDig = ic.options().get<int>("reserve-map-dig"); + if (nReserveVecDig || nReserveVecChData) { + mRawReader.reserveVecDPL(nReserveVecDig, nReserveVecChData); + } + if (nReserveVecBuffer || nReserveMapDig) { + mRawReader.reserve(nReserveVecBuffer, nReserveMapDig); + } + } + void run(ProcessingContext& pc) final + { + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{mRawReader.mDataOrigin, o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(pc.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + mRawReader.makeSnapshot(pc); // send empty output + return; + } + } + } + std::vector<InputSpec> filter{InputSpec{"filter", ConcreteDataTypeMatcher{mRawReader.mDataOrigin, o2::header::gDataDescriptionRawData}, Lifetime::Timeframe}}; + DPLRawParser parser(pc.inputs(), filter); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + //Proccessing each page + auto rdhPtr = it.get_if<o2::header::RAWDataHeader>(); + gsl::span<const uint8_t> payload(it.data(), it.size()); + mRawReader.process(payload, int(rdhPtr->linkID), int(rdhPtr->endPointID)); + } + mRawReader.accumulateDigits(); + mRawReader.makeSnapshot(pc); + mRawReader.clear(); + } +}; + +template <typename RawReaderType> +framework::DataProcessorSpec getFITDataReaderDPLSpec(const RawReaderType& rawReader, bool askSTFDist) +{ + std::vector<OutputSpec> outputSpec; + rawReader.configureOutputSpec(outputSpec); + std::vector<InputSpec> inputSpec{{"STF", ConcreteDataTypeMatcher{rawReader.mDataOrigin, "RAWDATA"}, Lifetime::Optional}}; + if (askSTFDist) { + inputSpec.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + std::string dataProcName = rawReader.mDataOrigin.template as<std::string>(); + std::for_each(dataProcName.begin(), dataProcName.end(), [](char& c) { c = ::tolower(c); }); + dataProcName += "-datareader-dpl"; + LOG(INFO) << dataProcName; + return DataProcessorSpec{ + dataProcName, + inputSpec, + outputSpec, + adaptFromTask<FITDataReaderDPLSpec<RawReaderType>>(rawReader), + {o2::framework::ConfigParamSpec{"ccdb-path", VariantType::String, "", {"CCDB url which contains LookupTable"}}, + o2::framework::ConfigParamSpec{"lut-path", VariantType::String, "", {"LookupTable path, e.g. FT0/LookupTable"}}, + o2::framework::ConfigParamSpec{"reserve-vec-dig", VariantType::Int, 0, {"Reserve memory for Digit vector, to DPL channel"}}, + o2::framework::ConfigParamSpec{"reserve-vec-chdata", VariantType::Int, 0, {"Reserve memory for ChannelData vector, to DPL channel"}}, + o2::framework::ConfigParamSpec{"reserve-vec-buffer", VariantType::Int, 0, {"Reserve memory for DataBlock vector, buffer for each page"}}, + o2::framework::ConfigParamSpec{"reserve-map-dig", VariantType::Int, 0, {"Reserve memory for Digit map, mapping in RawReader"}}}}; +} + +} // namespace fit +} // namespace o2 + +#endif /* O2_FITDATAREADERDPL_H */ diff --git a/Detectors/FIT/workflow/include/FITWorkflow/FITDigitWriterSpec.h b/Detectors/FIT/workflow/include/FITWorkflow/FITDigitWriterSpec.h new file mode 100644 index 0000000000000..9556a52c7efbb --- /dev/null +++ b/Detectors/FIT/workflow/include/FITWorkflow/FITDigitWriterSpec.h @@ -0,0 +1,135 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FITDigitWriterSpec.h + +#ifndef O2_FITDIGITWRITER_H +#define O2_FITDIGITWRITER_H + +#include <Framework/Logger.h> +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include <tuple> +#include <vector> +#include <string> + +using namespace o2::framework; + +namespace o2 +{ +namespace fit +{ +template <typename RawReaderType, typename MCLabelContainerType /*For example: =o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>*/> +struct FITDigitWriterSpecHelper { + typedef RawReaderType RawReader_t; + typedef MCLabelContainerType MCLabelContainer_t; //should be defined as type field within Digit structure + typedef typename RawReader_t::Digit_t Digit_t; + typedef typename Digit_t::DetTrigInput_t DetTrigInput_t; + typedef typename RawReader_t::SubDigit_t SubDigit_t; //tuple of vectors + typedef typename RawReader_t::SingleSubDigit_t SingleSubDigit_t; //tuple of vectors + typedef typename RawReader_t::IndexesSubDigit IndexesSubDigit_t; + typedef typename RawReader_t::IndexesSingleSubDigit IndexesSingleSubDigit_t; + + template <typename T> + using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + + static o2::framework::DataProcessorSpec getFITDigitWriterSpec(bool mctruth, bool trigInp, o2::header::DataOrigin dataOrigin) + { + if (trigInp) { + return callMakeSpec<true>(mctruth, dataOrigin, IndexesSubDigit_t{}, IndexesSingleSubDigit_t{}); + } else { + return callMakeSpec<false>(mctruth, dataOrigin, IndexesSubDigit_t{}, IndexesSingleSubDigit_t{}); + } + } + + template <typename T, typename... Args> + static auto getBranchDef(o2::header::DataOrigin dataOrigin, Args&&... args) + { + std::string detName = dataOrigin.template as<std::string>(); + std::string detNameLower = detName; + std::for_each(detNameLower.begin(), detNameLower.end(), [](char& c) { c = ::tolower(c); }); + auto dplName = T::sChannelNameDPL; + auto dplLabel = std::string{dplName}; + std::for_each(dplLabel.begin(), dplLabel.end(), [](char& c) { c = ::tolower(c); }); + //auto branchName = std::string{detName + dplName}; + auto branchName = std::string{T::sDigitBranchName}; + auto optionStr = std::string{detNameLower + "-" + dplName + "-branch-name"}; + //LOG(INFO)<<"Branch: "<<dplLabel.c_str()<< "|" <<detName<<" | "<<T::sChannelNameDPL<<" | "<<branchName<<" | "<<optionStr<<" | "<<(detName+dplName); + return BranchDefinition<std::vector<T>>{InputSpec{dplLabel.c_str(), dataOrigin, T::sChannelNameDPL}, branchName.c_str(), optionStr.c_str(), std::forward<Args>(args)...}; + } + + template <std::size_t N, typename TupleType, typename... Args> + static auto getBranchDefFromTuple(o2::header::DataOrigin dataOrigin, Args&&... args) + { + using ObjType = typename std::tuple_element<N, TupleType>::type::value_type; + return getBranchDef<ObjType>(dataOrigin, std::forward<Args>(args)...); + } + + template <bool trigInp, std::size_t... IsubDigits, std::size_t... IsingleSubDigits> + static auto callMakeSpec(bool mctruth, o2::header::DataOrigin dataOrigin, std::index_sequence<IsubDigits...>, std::index_sequence<IsingleSubDigits...>) + { + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + + std::string detName = dataOrigin.template as<std::string>(); + std::string detNameLower = detName; + std::for_each(detNameLower.begin(), detNameLower.end(), [](char& c) { c = ::tolower(c); }); + // Spectators for logging + auto logger = [](std::vector<Digit_t> const& vecDigits) { + LOG(INFO) << "FITDigitWriter pulled " << vecDigits.size() << " digits"; + }; + // the callback to be set as hook for custom action when the writer is closed + auto finishWriting = [](TFile* outputfile, TTree* outputtree) { + const auto* brArr = outputtree->GetListOfBranches(); + int64_t nent = 0; + for (const auto* brc : *brArr) { + int64_t n = ((const TBranch*)brc)->GetEntries(); + if (nent && (nent != n)) { + LOG(ERROR) << "Branches have different number of entries"; + } + nent = n; + } + outputtree->SetEntries(nent); + outputtree->Write(); + outputfile->Close(); + }; + auto digitsdef = getBranchDef<Digit_t>(dataOrigin, 1, logger); + auto trginputdef = getBranchDef<DetTrigInput_t>(dataOrigin); + auto labelsdef = BranchDefinition<MCLabelContainer_t>{InputSpec{"labelinput", dataOrigin, "DIGITSMCTR"}, std::string{detName + "DIGITSMCTR"}.c_str(), mctruth ? 1 : 0}; + if constexpr (trigInp == false) { + return MakeRootTreeWriterSpec( + std::string{detName + "DigitWriterRaw"}.c_str(), + std::string{"o2_" + detNameLower + "digits.root"}.c_str(), + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + getBranchDefFromTuple<IsubDigits, SubDigit_t>(dataOrigin)..., + getBranchDefFromTuple<IsingleSubDigits, SingleSubDigit_t>(dataOrigin)..., + std::move(digitsdef), + std::move(labelsdef))(); + } else { + return MakeRootTreeWriterSpec( + std::string{detName + "DigitWriter"}.c_str(), + std::string{detNameLower + "digits.root"}.c_str(), + "o2sim", + MakeRootTreeWriterSpec::CustomClose(finishWriting), + getBranchDefFromTuple<IsubDigits, SubDigit_t>(dataOrigin)..., + getBranchDefFromTuple<IsingleSubDigits, SingleSubDigit_t>(dataOrigin)..., + std::move(digitsdef), + std::move(trginputdef), + std::move(labelsdef))(); + } + } +}; +} // namespace fit +} // namespace o2 + +#endif /* O2_FITDIGITWRITER_H */ diff --git a/Detectors/FIT/workflow/include/FITWorkflow/RawReaderFIT.h b/Detectors/FIT/workflow/include/FITWorkflow/RawReaderFIT.h new file mode 100644 index 0000000000000..14f1d3f6376ee --- /dev/null +++ b/Detectors/FIT/workflow/include/FITWorkflow/RawReaderFIT.h @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderFIT.h class for RAW data reading +// +// Artur.Furs +// afurs@cern.ch +// +//Main purpuse is to decode FIT data blocks and push them to DigitBlockFIT for proccess +#ifndef ALICEO2_FIT_RAWREADERFIT_H_ +#define ALICEO2_FIT_RAWREADERFIT_H_ +#include <iostream> +#include <vector> +#include <type_traits> +#include <Rtypes.h> +#include "FITRaw/RawReaderBaseFIT.h" +#include "FITRaw/DigitBlockFIT.h" +#include <Framework/Logger.h> +#include "Framework/ProcessingContext.h" +#include "Framework/DataAllocator.h" +#include "Framework/OutputSpec.h" +#include <gsl/span> + +namespace o2 +{ +namespace fit +{ + +template <typename RawReaderType, bool useTrgInput = false> +class RawReaderFIT : public RawReaderType +{ + public: + RawReaderFIT(o2::header::DataOrigin dataOrigin, bool dumpData) : mDataOrigin(dataOrigin), mDumpData(dumpData) {} + RawReaderFIT(const RawReaderFIT&) = default; + RawReaderFIT() = delete; + ~RawReaderFIT() = default; + typedef RawReaderType RawReader_t; + typedef typename RawReader_t::DigitBlockFIT_t DigitBlockFIT_t; + typedef typename DigitBlockFIT_t::LookupTable_t LookupTable_t; + typedef typename DigitBlockFIT_t::Digit_t Digit_t; + typedef typename DigitBlockFIT_t::SubDigit_t SubDigitTmp_t; + typedef typename DigitBlockHelper::GetSubDigitField<typename DigitBlockFIT_t::VecSingleSubDigit_t>::vector_type SingleSubDigitTmp_t; + typedef typename Digit_t::DetTrigInput_t DetTrigInput_t; + typedef std::make_index_sequence<DigitBlockFIT_t::sNSubDigits> IndexesSubDigit; + typedef std::make_index_sequence<DigitBlockFIT_t::sNSingleSubDigits> IndexesSingleSubDigit; + typedef std::make_index_sequence<std::tuple_size_v<typename DigitBlockFIT_t::TupleVecDigitObjs_t>> IndexesAllDigits; + static constexpr bool sSubDigitExists = !std::is_same<SubDigitTmp_t, std::tuple<>>::value; + static constexpr bool sSingleSubDigitExists = !std::is_same<SingleSubDigitTmp_t, std::tuple<>>::value; + //Wrapping by std::tuple + typedef typename std::conditional<DigitBlockFIT_t::sNSubDigits != 1, SubDigitTmp_t, std::tuple<SubDigitTmp_t>>::type SubDigit_t; + typedef typename std::conditional<DigitBlockFIT_t::sNSingleSubDigits != 1, SingleSubDigitTmp_t, std::tuple<SingleSubDigitTmp_t>>::type SingleSubDigit_t; + static constexpr bool sUseTrgInput = useTrgInput; + o2::header::DataOrigin mDataOrigin; + std::vector<Digit_t> mVecDigit; + std::vector<DetTrigInput_t> mVecTrgInput; + SubDigit_t mVecSubDigit; //tuple of vectors + SingleSubDigit_t mVecSingleSubDigit; //tuple of vectors + bool mDumpData; + void reserveVecDPL(std::size_t nDigits, std::size_t nSubDigits) + { + mVecDigit.reserve(nDigits); + reserveSubDigits1<DigitBlockFIT_t>(nSubDigits); + } + template <typename T> + auto reserveSubDigits1(std::size_t nElements) -> std::enable_if_t<(T::sNSubDigits > 0)> + { + std::get<0>(mVecSubDigit).reserve(nElements); + } + template <typename T> + auto reserveSubDigits1(std::size_t nElements) -> std::enable_if_t<(T::sNSubDigits < 1)> + { + } //empty + void clear() + { + mVecDigit.clear(); + if constexpr (sUseTrgInput) { + mVecTrgInput.clear(); + } + if constexpr (sSubDigitExists) { + std::apply([](auto&... subDigit) { + ((subDigit.clear()), ...); + }, + mVecSubDigit); + } + if constexpr (sSingleSubDigitExists) { + std::apply([](auto&... singleSubDigit) { + ((singleSubDigit.clear()), ...); + }, + mVecSingleSubDigit); + } + } + template <std::size_t... IsubDigits, std::size_t... IsingleSubDigits> + auto callGetDigit(std::index_sequence<IsubDigits...>, std::index_sequence<IsingleSubDigits...>) + { + if constexpr (sUseTrgInput) { + RawReader_t::getDigits(mVecDigit, std::get<IsubDigits>(mVecSubDigit)..., std::get<IsingleSubDigits>(mVecSingleSubDigit)..., mVecTrgInput); + } else { + RawReader_t::getDigits(mVecDigit, std::get<IsubDigits>(mVecSubDigit)..., std::get<IsingleSubDigits>(mVecSingleSubDigit)...); + } + } + template <std::size_t... IDigits> + auto callGetDigitDirectly(o2::framework::ProcessingContext& pc, std::index_sequence<IDigits...>) + { + if constexpr (sUseTrgInput) { + RawReader_t::getDigits(getRefVec<std::tuple_element_t<IDigits, typename DigitBlockFIT_t::TupleVecDigitObjs_t>>(pc)..., getRefVec<typename std::vector<DetTrigInput_t>>(pc)); + } else { + RawReader_t::getDigits(getRefVec<std::tuple_element_t<IDigits, typename DigitBlockFIT_t::TupleVecDigitObjs_t>>(pc)...); + } + } + template <std::size_t... IsubDigits, std::size_t... IsingleSubDigits> + auto callPrint(std::index_sequence<IsubDigits...>, std::index_sequence<IsingleSubDigits...>) const + { + DigitBlockFIT_t::print(mVecDigit, std::get<IsubDigits>(mVecSubDigit)..., std::get<IsingleSubDigits>(mVecSingleSubDigit)...); + } + void accumulateDigits(o2::framework::ProcessingContext& pc) + { + callGetDigitDirectly(pc, IndexesAllDigits{}); + } + void accumulateDigits() + { + callGetDigit(IndexesSubDigit{}, IndexesSingleSubDigit{}); + LOG(DEBUG) << "Number of Digits: " << mVecDigit.size(); + if (mDumpData) { + callPrint(IndexesSubDigit{}, IndexesSingleSubDigit{}); + } + } + void configureOutputSpec(std::vector<o2::framework::OutputSpec>& outputSpec) const + { + outputSpec.emplace_back(mDataOrigin, Digit_t::sChannelNameDPL, 0, o2::framework::Lifetime::Timeframe); + if constexpr (sSubDigitExists) { + std::apply([&](const auto&... subDigit) { + ((outputSpec.emplace_back(mDataOrigin, (std::decay<decltype(subDigit)>::type::value_type::sChannelNameDPL), 0, o2::framework::Lifetime::Timeframe)), ...); + }, + mVecSubDigit); + } + if constexpr (sSingleSubDigitExists) { + std::apply([&](const auto&... singleSubDigit) { + ((outputSpec.emplace_back(mDataOrigin, (std::decay<decltype(singleSubDigit)>::type::value_type::sChannelNameDPL), 0, o2::framework::Lifetime::Timeframe)), ...); + }, + mVecSingleSubDigit); + } + if constexpr (sUseTrgInput) { + outputSpec.emplace_back(mDataOrigin, DetTrigInput_t::sChannelNameDPL, 0, o2::framework::Lifetime::Timeframe); + } + } + void makeSnapshot(o2::framework::ProcessingContext& pc) const + { + pc.outputs().snapshot(o2::framework::Output{mDataOrigin, Digit_t::sChannelNameDPL, 0, o2::framework::Lifetime::Timeframe}, mVecDigit); + if constexpr (sSubDigitExists) { + std::apply([&](const auto&... subDigit) { + ((pc.outputs().snapshot(o2::framework::Output{mDataOrigin, (std::decay<decltype(subDigit)>::type::value_type::sChannelNameDPL), 0, o2::framework::Lifetime::Timeframe}, subDigit)), ...); + }, + mVecSubDigit); + } + if constexpr (sSingleSubDigitExists) { + std::apply([&](const auto&... singleSubDigit) { + ((pc.outputs().snapshot(o2::framework::Output{mDataOrigin, (std::decay<decltype(singleSubDigit)>::type::value_type::sChannelNameDPL), 0, o2::framework::Lifetime::Timeframe}, singleSubDigit)), ...); + }, + mVecSingleSubDigit); + } + if constexpr (sUseTrgInput) { + pc.outputs().snapshot(o2::framework::Output{mDataOrigin, DetTrigInput_t::sChannelNameDPL, 0, o2::framework::Lifetime::Timeframe}, mVecTrgInput); + } + } + template <typename VecDigitType> + auto& getRefVec(o2::framework::ProcessingContext& pc) + { + auto& refVec = pc.outputs().make<VecDigitType>(o2::framework::Output{mDataOrigin, VecDigitType::value_type::sChannelNameDPL, 0, o2::framework::Lifetime::Timeframe}); + return refVec; + } +}; + +} // namespace fit +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/FIT/workflow/src/FITDataReaderDPLSpec.cxx b/Detectors/FIT/workflow/src/FITDataReaderDPLSpec.cxx new file mode 100644 index 0000000000000..4c0694f7549aa --- /dev/null +++ b/Detectors/FIT/workflow/src/FITDataReaderDPLSpec.cxx @@ -0,0 +1,14 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FITDataReaderDPLSpec.cxx + +#include "FITWorkflow/FITDataReaderDPLSpec.h" diff --git a/Detectors/FIT/workflow/src/FITDigitWriterSpec.cxx b/Detectors/FIT/workflow/src/FITDigitWriterSpec.cxx new file mode 100644 index 0000000000000..efac74cd0c4f6 --- /dev/null +++ b/Detectors/FIT/workflow/src/FITDigitWriterSpec.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FITDigitWriterSpec.cxx +#include "FITWorkflow/FITDigitWriterSpec.h" diff --git a/Detectors/FIT/workflow/src/RawReaderFIT.cxx b/Detectors/FIT/workflow/src/RawReaderFIT.cxx new file mode 100644 index 0000000000000..2ebffb8f10c96 --- /dev/null +++ b/Detectors/FIT/workflow/src/RawReaderFIT.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FITWorkflow/RawReaderFIT.h" diff --git a/Detectors/GlobalTracking/CMakeLists.txt b/Detectors/GlobalTracking/CMakeLists.txt index da30ffd8a8d79..f58744a025c53 100644 --- a/Detectors/GlobalTracking/CMakeLists.txt +++ b/Detectors/GlobalTracking/CMakeLists.txt @@ -1,35 +1,51 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library( - GlobalTracking - SOURCES src/MatchTPCITS.cxx src/MatchTOF.cxx +o2_add_library(GlobalTracking + TARGETVARNAME targetName + SOURCES src/MatchTPCITS.cxx + src/MatchTOF.cxx src/MatchTPCITSParams.cxx + src/MatchCosmics.cxx + src/MatchCosmicsParams.cxx + src/MatchGlobalFwd.cxx PUBLIC_LINK_LIBRARIES + O2::Framework O2::DataFormatsTPC O2::DataFormatsITSMFT O2::DataFormatsITS O2::DataFormatsFT0 O2::DataFormatsTOF + O2::DataFormatsTRD O2::ITSReconstruction O2::FT0Reconstruction O2::TPCFastTransformation - O2::GPUTracking + O2::GPUO2Interface O2::TPCBase O2::TPCReconstruction O2::TOFBase O2::TOFCalibration + O2::TOFWorkflowUtils O2::SimConfig - O2::DataFormatsFT0) - + O2::DataFormatsFT0 + O2::DataFormatsGlobalTracking + O2::ITStracking + O2::MFTTracking + O2::MCHTracking) o2_target_root_dictionary( GlobalTracking - HEADERS include/GlobalTracking/MatchTPCITS.h include/GlobalTracking/MatchTPCITSParams.h - include/GlobalTracking/MatchTOF.h) + HEADERS include/GlobalTracking/MatchTPCITSParams.h include/GlobalTracking/MatchGlobalFwd.h + include/GlobalTracking/MatchTOF.h include/GlobalTracking/MatchCosmics.h include/GlobalTracking/MatchCosmicsParams.h) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h new file mode 100644 index 0000000000000..8c63825b65fe0 --- /dev/null +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h @@ -0,0 +1,157 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MatchCosmics.h +/// \brief Class to perform matching/refit of cosmic tracks legs +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_MATCH_COSMICS +#define ALICEO2_MATCH_COSMICS + +#include <Rtypes.h> +#include <MathUtils/Primitive2D.h> +#include "ReconstructionDataFormats/TrackCosmics.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "ReconstructionDataFormats/BaseCluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "GlobalTracking/MatchCosmicsParams.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TPCFastTransform.h" + +#define _ALLOW_DEBUG_TREES_COSM // to allow debug and control tree output + +namespace o2 +{ +namespace globaltracking +{ + +namespace o2d = o2::dataformats; + +using GTrackID = o2d::GlobalTrackID; +using TBracket = o2::math_utils::Bracketf_t; +class RecoContainer; + +class MatchCosmics +{ + public: + static constexpr int Zero = 0; + static constexpr int MinusOne = -1; + static constexpr int MinusTen = -10; + static constexpr int Validated = -2; + static constexpr int Reject = MinusTen; + enum RejFlag { + Accept = 0, + RejY, + RejZ, + RejSnp, + RejTgl, + RejQ2Pt, + RejTime, + RejProp, + RejChi2, + RejOther + }; + + using InfoAccessor = o2d::AbstractRefAccessor<int, GTrackID::NSources>; // there is no unique <Info> structure, so the default return type is dummy (int) + + ///< record about matchig of 2 tracks + struct MatchRecord { + int id0 = MinusOne; ///< id of 1st parnter + int id1 = MinusOne; ///< id of 2nd parnter + float chi2 = -1.f; ///< matching chi2 + int next = MinusOne; ///< index of eventual next record + }; + + struct TrackSeed : public o2::track::TrackParCov { + TBracket tBracket; ///< bracketing time-bins + GTrackID origID; ///< track origin id + int matchID = MinusOne; ///< entry (none if MinusOne) of its match in the vector of matches + }; + void setITSROFrameLengthMUS(float fums) { mITSROFrameLengthMUS = fums; } + void setITSDict(std::unique_ptr<o2::itsmft::TopologyDictionary>& dict) { mITSDict = std::move(dict); } + void process(const o2::globaltracking::RecoContainer& data); + void setUseMC(bool mc) { mUseMC = mc; } + void init(); + void end(); + + auto getCosmicTracks() const { return mCosmicTracks; } + auto getCosmicTracksLbl() const { return mCosmicTracksLbl; } + +#ifdef _ALLOW_DEBUG_TREES_COSM + enum DebugFlagTypes : UInt_t { + MatchTreeAll = 0x1, ///< produce matching candidates tree for all candidates + MatchTreeAccOnly = 0x1 << 1 ///< fill the matching candidates tree only once the cut is passed + }; + ///< check if partucular flags are set + bool isDebugFlag(UInt_t flags) const { return mDBGFlags & flags; } + + ///< get debug trees flags + UInt_t getDebugFlags() const { return mDBGFlags; } + + ///< set or unset debug stream flag + void setDebugFlag(UInt_t flag, bool on = true); + + ///< set the name of output debug file + void setDebugTreeFileName(std::string name) + { + if (!name.empty()) { + mDebugTreeFileName = name; + } + } + + ///< get the name of output debug file + const std::string& getDebugTreeFileName() const { return mDebugTreeFileName; } +#endif + + private: + void updateTimeDependentParams(); + RejFlag checkPair(int i, int j); + void registerMatch(int i, int j, float chi2); + void suppressMatch(int partner0, int partner1); + void createSeeds(const o2::globaltracking::RecoContainer& data); + bool validateMatch(int partner0); + void selectWinners(); + void refitWinners(const o2::globaltracking::RecoContainer& data); + std::vector<o2::BaseCluster<float>> prepareITSClusters(const o2::globaltracking::RecoContainer& data) const; + + std::vector<TrackSeed> mSeeds; + std::vector<MatchRecord> mRecords; + std::vector<int> mWinners; + std::unique_ptr<o2::gpu::TPCFastTransform> mTPCTransform; ///< TPC cluster transformation + std::unique_ptr<o2::itsmft::TopologyDictionary> mITSDict; // cluster patterns dictionary + + int mTFCount = 0; + float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds + float mBz = 0; ///< nominal Bz + bool mFieldON = true; + bool mUseMC = true; + float mITSROFrameLengthMUS = 0.; + float mQ2PtCutoff = 1e9; + const MatchCosmicsParams* mMatchParams = nullptr; + + std::vector<o2d::TrackCosmics> mCosmicTracks; + std::vector<o2::MCCompLabel> mCosmicTracksLbl; + +#ifdef _ALLOW_DEBUG_TREES_COSM + std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut; + UInt_t mDBGFlags = 0; + std::string mDebugTreeFileName = "dbg_cosmics_match.root"; ///< name for the debug tree file +#endif + + ClassDefNV(MatchCosmics, 1); +}; + +} // namespace globaltracking +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmicsParams.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmicsParams.h new file mode 100644 index 0000000000000..402b3488193fe --- /dev/null +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmicsParams.h @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_MATCHCOSMICS_PARAMS_H +#define ALICEO2_MATCHCOSMICS_PARAMS_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DetectorsBase/Propagator.h" + +namespace o2 +{ +namespace globaltracking +{ + +struct MatchCosmicsParams : public o2::conf::ConfigurableParamHelper<MatchCosmicsParams> { + float systSigma2[o2::track::kNParams] = {0.01f, 0.01f, 1e-4f, 1e-4f, 0.f}; // extra error to be added at legs comparison + float crudeNSigma2Cut[o2::track::kNParams] = {49.f, 49.f, 49.f, 49.f, 49.f}; + float crudeChi2Cut = 999.; + float timeToleranceMUS = 0.; + float maxStep = 10.; + float maxSnp = 0.99; + float minSeedPt = 0.10; // use only tracks above this pT (scaled with field) + float nSigmaTError = 4.; // number of sigmas on track time error for matching (except for TPC which provides an interval) + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + O2ParamDef(MatchCosmicsParams, "cosmicsMatch"); +}; + +} // namespace globaltracking +} // end namespace o2 + +#endif diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h new file mode 100644 index 0000000000000..a057c7fee531b --- /dev/null +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h @@ -0,0 +1,279 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MatchGlobalFwd.h +/// \brief Class to perform MCH MFT matching +/// \author rafael.pezzi@cern.ch + +#ifndef ALICEO2_GLOBTRACKING_MATCHGLOBALFWD_ +#define ALICEO2_GLOBTRACKING_MATCHGLOBALFWD_ + +#include <Rtypes.h> +#include <array> +#include <vector> +#include <string> +#include <gsl/span> +#include <TStopwatch.h> +#include "CommonConstants/LHCConstants.h" +#include "CommonDataFormat/BunchFilling.h" +#include "ITSMFTReconstruction/ChipMappingMFT.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "MFTTracking/IOUtils.h" +#include "MFTBase/Constants.h" +#include "DataFormatsMFT/TrackMFT.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsBase/GeometryManager.h" +#include "TGeoManager.h" + +namespace o2 +{ + +namespace mft +{ +class TrackMFT; +} + +namespace mch +{ +class TrackMCH; +} + +namespace globaltracking +{ + +///< MFT track outward parameters propagated to reference Z, +///< with time bracket and index of original track in the +///< currently loaded MFT reco output +struct TrackLocMFT : public o2::track::TrackParCovFwd { + o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus + int roFrame = -1; ///< MFT readout frame assigned to this track + + ClassDefNV(TrackLocMFT, 0); +}; + +///< MCH track uncorrected parameters propagated to reference Z, +///< with time bracket and index of original track in the +///< currently loaded MCH reco output +struct TrackLocMCH : public o2::dataformats::GlobalFwdTrack { + o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus + ClassDefNV(TrackLocMCH, 0); +}; + +class MatchGlobalFwd +{ + public: + using MFTCluster = o2::BaseCluster<float>; + using BracketF = o2::math_utils::Bracket<float>; + using SMatrix55Std = ROOT::Math::SMatrix<double, 5>; + using SMatrix55Sym = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; + + using SVector2 = ROOT::Math::SVector<double, 2>; + using SVector4 = ROOT::Math::SVector<double, 4>; + using SVector5 = ROOT::Math::SVector<double, 5>; + + using SMatrix44 = ROOT::Math::SMatrix<double, 4>; + using SMatrix45 = ROOT::Math::SMatrix<double, 4, 5>; + using SMatrix54 = ROOT::Math::SMatrix<double, 5, 4>; + using SMatrix22 = ROOT::Math::SMatrix<double, 2>; + using SMatrix25 = ROOT::Math::SMatrix<double, 2, 5>; + using SMatrix52 = ROOT::Math::SMatrix<double, 5, 2>; + + MatchGlobalFwd() = default; + ~MatchGlobalFwd() = default; + + void run(const o2::globaltracking::RecoContainer& inp); + void init(std::string matchFcn, std::string cutFcn); + void finalize(); + void clear(); + + void setMFTDictionary(const o2::itsmft::TopologyDictionary* d) { mMFTDict = d; } + void setMatchingPlaneZ(float z) { mMatchingPlaneZ = z; }; + + ///< set Bunch filling and init helpers for validation by BCs + void setBunchFilling(const o2::BunchFilling& bf); + ///< MFT readout mode + void setMFTTriggered(bool v) { mMFTTriggered = v; } + bool isMFTTriggered() const { return mMFTTriggered; } + + void setMCTruthOn(bool v) { mMCTruthON = v; } + ///< set MFT ROFrame duration in microseconds + void setMFTROFrameLengthMUS(float fums); + ///< set MFT ROFrame duration in BC (continuous mode only) + void setMFTROFrameLengthInBC(int nbc); + const std::vector<o2::dataformats::GlobalFwdTrack>& getMatchedFwdTracks() const { return mMatchedTracks; } + const std::vector<o2::MCCompLabel>& getMatchLabels() const { return mMatchLabels; } + + private: + void updateTimeDependentParams(); + + bool prepareMCHData(); + bool prepareMFTData(); + + void doMatching(); + ///< Matches MFT tracks in one MFT ROFrame with all MCH tracks in the overlapping MCH ROFrames + void ROFMatch(int MFTROFId, int firstMCHROFId, int lastMCHROFId); + void fitTracks(); // Fit all matched tracks + void fitGlobalMuonTrack(o2::dataformats::GlobalFwdTrack&); // Kalman filter fit global Forward track by attaching MFT clusters + bool computeCluster(o2::dataformats::GlobalFwdTrack& track, const MFTCluster& cluster, int& startingLayerID); + + template <typename T> + bool propagateToNextClusterWithMCS(T& track, double z, int& startingLayerID, const int& newLayerID) + { + // Propagate track to the next cluster z position, adding angular MCS effects at the center of + // each disk crossed by the track. This method is valid only for track propagation between + // clusters at MFT layers positions. The startingLayerID is updated. + + if (startingLayerID == newLayerID) { // Same layer, nothing to do. + LOG(DEBUG) << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > " + << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID) + << ") ; track.getZ() = " << track.getZ() << " => " + << "destination cluster z = " << z << " ; => Same layer: no MCS effects."; + + if (z != track.getZ()) { + track.propagateToZ(z, mBz); + } + return true; + } + + using o2::mft::constants::LayerZPosition; + auto startingZ = track.getZ(); + + //https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c + auto signum = [](auto a) { + return (0 < a) - (a < 0); + }; + int direction = signum(newLayerID - startingLayerID); // takes values +1, 0, -1 + auto currentLayer = startingLayerID; + + LOG(DEBUG) << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > " + << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID) + << ") ; track.getZ() = " << track.getZ() << " => " + << "destination cluster z = " << z << " ; "; + + // Number of disks crossed by this track segment + while (currentLayer != newLayerID) { + auto nextlayer = currentLayer + direction; + auto nextZ = LayerZPosition[nextlayer]; + + int NDisksMS; + if (nextZ - track.getZ() > 0) { + NDisksMS = (currentLayer % 2 == 0) ? (currentLayer - nextlayer) / 2 : (currentLayer - nextlayer + 1) / 2; + } else { + NDisksMS = (currentLayer % 2 == 0) ? (nextlayer - currentLayer + 1) / 2 : (nextlayer - currentLayer) / 2; + } + + LOG(DEBUG) << "currentLayer = " << currentLayer << " ; " + << "nextlayer = " << nextlayer << " ; " + << "track.getZ() = " << track.getZ() << " ; " + << "nextZ = " << nextZ << " ; " + << "NDisksMS = " << NDisksMS; + + if ((NDisksMS * mMFTDiskThicknessInX0) != 0) { + track.addMCSEffect(NDisksMS * mMFTDiskThicknessInX0); + LOG(DEBUG) << "Track covariances after MCS effects:"; + LOG(DEBUG) << track.getCovariances() << std::endl; + } + + LOG(DEBUG) << " BeforeExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl; + + track.propagateToZ(nextZ, mBz); + + currentLayer = nextlayer; + } + if (z != track.getZ()) { + track.propagateToZ(z, mBz); + } + startingLayerID = newLayerID; + return true; + } + + void configMatching(const std::string& matchingFcn, const std::string& cutFcn); + double matchingEval(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + bool matchingCut(const TrackLocMCH&, const TrackLocMFT&); + double (MatchGlobalFwd::*mMatchFunc)(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + void setMatchingFunction(double (MatchGlobalFwd::*func)(const TrackLocMCH&, const TrackLocMFT&)) + { + mMatchFunc = func; + } + bool (MatchGlobalFwd::*mCutFunc)(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + void setCutFunction(bool (MatchGlobalFwd::*func)(const TrackLocMCH&, const TrackLocMFT&)) + { + mCutFunc = func; + } + /// Matching methods + /// Position + double matchMFT_MCH_TracksXY(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + /// Position & Angles + double matchMFT_MCH_TracksXYPhiTanl(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + /// Position, Angles & Charged Momentum + double matchMFT_MCH_TracksAllParam(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + /// Hiroshima's Matching + double matchHiroshima(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack); + + /// Cut functions + bool cutDisabled(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) { return true; }; + + /// Converts mchTrack parameters to Forward coordinate system + o2::dataformats::GlobalFwdTrack MCHtoFwd(const o2::mch::TrackParam& mchTrack); + + float mBz = -5.f; ///< nominal Bz in kGauss + float mMatchingPlaneZ = -77.5; ///< MCH-MFT matching plane Z position TODO: Make configurable + Float_t mMFTDiskThicknessInX0 = 0.042 / 5; + o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF + int mMFTROFrameLengthInBC = 0; ///< MFT RO frame in BC (for MFT cont. mode only) + float mMFTROFrameLengthMUS = -1.; ///< MFT RO frame in \mus + float mMFTROFrameLengthMUSInv = -1.; ///< MFT RO frame in \mus inverse + + o2::BunchFilling mBunchFilling; + std::array<int16_t, o2::constants::lhc::LHCMaxBunches> mClosestBunchAbove; // closest filled bunch from above + std::array<int16_t, o2::constants::lhc::LHCMaxBunches> mClosestBunchBelow; // closest filled bunch from below + + bool mMFTTriggered = false; ///< MFT readout is triggered + + /// mapping for tracks' continuos ROF cycle to actual continuous readout ROFs with eventual gaps + std::vector<int> mMFTTrackROFContMapping; + + const o2::globaltracking::RecoContainer* mRecoCont = nullptr; + gsl::span<const o2::mch::TrackMCH> mMCHTracks; ///< input MCH tracks + gsl::span<const o2::mch::ROFRecord> mMCHTrackROFRec; ///< MCH tracks ROFRecords + gsl::span<const o2::mft::TrackMFT> mMFTTracks; ///< input MFT tracks + gsl::span<const o2::itsmft::ROFRecord> mMFTTrackROFRec; ///< MFT tracks ROFRecords + gsl::span<const int> mMFTTrackClusIdx; ///< input MFT track cluster indices span + gsl::span<const o2::itsmft::ROFRecord> mMFTClusterROFRec; ///< input MFT clusters ROFRecord span + gsl::span<const o2::MCCompLabel> mMFTTrkLabels; ///< input MFT Track MC labels + gsl::span<const o2::MCCompLabel> mMCHTrkLabels; ///< input MCH Track MC labels + + std::vector<BracketF> mMCHROFTimes; ///< min/max times of MCH ROFs in \mus + std::vector<TrackLocMCH> mMCHWork; ///< MCH track params prepared for matching + std::vector<BracketF> mMFTROFTimes; ///< min/max times of MFT ROFs in \mus + std::vector<TrackLocMFT> mMFTWork; ///< MFT track params prepared for matching + std::vector<MFTCluster> mMFTClusters; ///< input MFT clusters + std::vector<o2::dataformats::GlobalFwdTrack> mMatchedTracks; ///< MCH-MFT(-MID) Matched tracks + std::vector<o2::MCCompLabel> mMatchLabels; ///< Output labels + + const o2::itsmft::TopologyDictionary* mMFTDict{nullptr}; // cluster patterns dictionary + o2::itsmft::ChipMappingMFT mMFTMapping; + bool mMCTruthON = false; ///< flag availability of MC truth + TGeoManager* mGeoManager; +}; + +} // namespace globaltracking +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h index ba5c2221294f1..2ba51afb76470 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,9 @@ #include <TStopwatch.h> #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackTPCITS.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "ReconstructionDataFormats/MatchInfoTOFReco.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsTOF/CalibInfoTOF.h" #include "CommonDataFormat/EvIndex.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -32,21 +35,22 @@ #include "DataFormatsTOF/Cluster.h" #include "GlobalTracking/MatchTPCITS.h" #include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTRD/TrackTRD.h" #include "ReconstructionDataFormats/PID.h" -#include <gsl/span> +#include "TPCFastTransform.h" +#include "CommonDataFormat/InteractionRecord.h" // from FIT #include "DataFormatsFT0/RecPoints.h" -#ifdef _ALLOW_DEBUG_TREES_ -//#define _ALLOW_TOF_DEBUG_ -#endif - -class TTree; - namespace o2 { +namespace globaltracking +{ +class RecoContainer; +} + namespace dataformats { template <typename TruthElement> @@ -72,63 +76,24 @@ class MatchTOF { using Geo = o2::tof::Geo; using Cluster = o2::tof::Cluster; + using evGIdx = o2::dataformats::EvIndex<int, o2::dataformats::GlobalTrackID>; using evIdx = o2::dataformats::EvIndex<int, int>; using timeEst = o2::dataformats::TimeStampWithError<float, float>; using matchTrack = std::pair<o2::track::TrackParCov, timeEst>; + using trkType = o2::dataformats::MatchInfoTOFReco::TrackType; public: ///< perform matching for provided input - void run(); - - ///< fill output tree - void fill(); - - ///< perform all initializations - void init(); - void initTPConly(); - - ///< attach DPL data and run - void run(const gsl::span<const o2::dataformats::TrackTPCITS>& trackArray, const gsl::span<const Cluster>& clusterArray, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>& toflab, const gsl::span<const o2::MCCompLabel>& itslab, const gsl::span<const o2::MCCompLabel>& tpclab); - void run(const gsl::span<const o2::tpc::TrackTPC>& trackArray, const gsl::span<const Cluster>& clusterArray, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>& toflab, const gsl::span<const o2::MCCompLabel>& tpclab); - - ///< set tree/chain containing tracks - void setInputTreeTracks(TTree* tree) { mInputTreeTracks = tree; } - - ///< set tree/chain containing TPC tracks - void setInputTreeTPCTracks(TTree* tree) { mTreeTPCTracks = tree; } - - ///< set tree/chain containing TOF clusters - void setInputTreeTOFClusters(TTree* tree) { mTreeTOFClusters = tree; } - - ///< set output tree to write matched tracks - void setOutputTree(TTree* tr) { mOutputTree = tr; } - - ///< set output tree to write calibration infos - void setOutputTreeCalib(TTree* tr) { mOutputTreeCalib = tr; } - - ///< set input branch names for the input from the tree - void setTrackBranchName(const std::string& nm) { mTracksBranchName = nm; } - void setTPCTrackBranchName(const std::string& nm) { mTPCTracksBranchName = nm; } - void setTPCMCTruthBranchName(const std::string& nm) { mTPCMCTruthBranchName = nm; } - void setITSMCTruthBranchName(const std::string& nm) { mITSMCTruthBranchName = nm; } - void setTOFMCTruthBranchName(const std::string& nm) { mTOFMCTruthBranchName = nm; } - void setTOFClusterBranchName(const std::string& nm) { mTOFClusterBranchName = nm; } - void setOutTOFMCTruthBranchName(const std::string& nm) { mOutTOFMCTruthBranchName = nm; } - void setOutTPCMCTruthBranchName(const std::string& nm) { mOutTPCMCTruthBranchName = nm; } - void setOutITSMCTruthBranchName(const std::string& nm) { mOutITSMCTruthBranchName = nm; } - void setOutTracksBranchName(const std::string& nm) { mOutTracksBranchName = nm; } - void setOutCalibBranchName(const std::string& nm) { mOutCalibBranchName = nm; } - - ///< get input branch names for the input from the tree - const std::string& getTracksBranchName() const { return mTracksBranchName; } - const std::string& getTPCTracksBranchName() const { return mTPCTracksBranchName; } - const std::string& getTPCMCTruthBranchName() const { return mTPCMCTruthBranchName; } - const std::string& getITSMCTruthBranchName() const { return mITSMCTruthBranchName; } - const std::string& getTOFMCTruthBranchName() const { return mTOFMCTruthBranchName; } - const std::string& getTOFClusterBranchName() const { return mTOFClusterBranchName; } - const std::string& getOutTOFMCTruthBranchName() const { return mOutTOFMCTruthBranchName; } - const std::string& getOutTPCMCTruthBranchName() const { return mOutTPCMCTruthBranchName; } - const std::string& getOutITSMCTruthBranchName() const { return mOutITSMCTruthBranchName; } + void run(const o2::globaltracking::RecoContainer& inp); + + void setCosmics() + { + mIsCosmics = true; + mSpaceTolerance = 150; + mTimeTolerance = 50e3; + } + + void setHighPurity(bool value = true) { mSetHighPurity = value; } ///< print settings void print() const; @@ -169,151 +134,159 @@ class MatchTOF } } - ///< get the name of output debug file - const std::string& getDebugTreeFileName() const { return mDebugTreeFileName; } - - ///< fill matching debug tree - void fillTOFmatchTree(const char* tname, int cacheTOF, int sectTOF, int plateTOF, int stripTOF, int padXTOF, int padZTOF, int cacheeTrk, int crossedStrip, int sectPropagation, int platePropagation, int stripPropagation, int padXPropagation, int padZPropagation, float resX, float resZ, float res, matchTrack& trk, float intLength, float intTimePion, float timeTOF); - void fillTOFmatchTreeWithLabels(const char* tname, int cacheTOF, int sectTOF, int plateTOF, int stripTOF, int padXTOF, int padZTOF, int cacheeTrk, int crossedStrip, int sectPropagation, int platePropagation, int stripPropagation, int padXPropagation, int padZPropagation, float resX, float resZ, float res, matchTrack& trk, int TPClabelTrackID, int TPClabelEventID, int TPClabelSourceID, int ITSlabelTrackID, int ITSlabelEventID, int ITSlabelSourceID, int TOFlabelTrackID0, int TOFlabelEventID0, int TOFlabelSourceID0, int TOFlabelTrackID1, int TOFlabelEventID1, int TOFlabelSourceID1, int TOFlabelTrackID2, int TOFlabelEventID2, int TOFlabelSourceID2, float intLength, float intTimePion, float timeTOF); - void dumpWinnerMatches(); - - std::vector<o2::dataformats::MatchInfoTOF>& getMatchedTrackVector() { return mMatchedTracks; } + std::vector<o2::dataformats::MatchInfoTOF>& getMatchedTrackVector(trkType index) { return mMatchedTracks[index]; } std::vector<o2::dataformats::CalibInfoTOF>& getCalibVector() { return mCalibInfoTOF; } - std::vector<o2::MCCompLabel>& getMatchedTOFLabelsVector() { return mOutTOFLabels; } ///< get vector of TOF label of matched tracks - std::vector<o2::MCCompLabel>& getMatchedTPCLabelsVector() { return mOutTPCLabels; } ///< get vector of TPC label of matched tracks - std::vector<o2::MCCompLabel>& getMatchedITSLabelsVector() { return mOutITSLabels; } ///< get vector of ITS label of matched tracks + std::vector<o2::MCCompLabel>& getMatchedTOFLabelsVector(trkType index) { return mOutTOFLabels[index]; } ///< get vector of TOF label of matched tracks - // this method is deprecated - void setFITRecPoints(const std::vector<o2::ft0::RecPoints>* recpoints) + ///< set input TPC tracks cluster indices + void setTPCTrackClusIdxInp(const gsl::span<const o2::tpc::TPCClRefElem> inp) { - if (recpoints) { - // need explicit cast because the gsl index_type is signed - mFITRecPoints = {recpoints->data(), static_cast<decltype(mFITRecPoints)::index_type>(recpoints->size())}; - } + mTPCTrackClusIdx = inp; } - void setFITRecPoints(gsl::span<o2::ft0::RecPoints const> recpoints) + + ///< set input TPC cluster sharing map + void setTPCClustersSharingMap(const gsl::span<const unsigned char> inp) { - mFITRecPoints = recpoints; + mTPCRefitterShMap = inp; } + ///< set input TPC clusters + void setTPCClustersInp(const o2::tpc::ClusterNativeAccess* inp) + { + mTPCClusterIdxStruct = inp; + } + + void setFIT(bool value = true) { mIsFIT = value; } int findFITIndex(int bc); + void checkRefitter(); + bool makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCTOF& trConstr); + + ///< populate externally provided container by TOF-time-constrained TPC tracks + template <typename V> + void makeConstrainedTPCTracks(V& container) + { + checkRefitter(); + int nmatched = mMatchedTracks[trkType::TPC].size(), nconstrained = 0; + container.resize(nmatched); + for (unsigned i = 0; i < nmatched; i++) { + if (makeConstrainedTPCTrack(i, container[nconstrained])) { + nconstrained++; + } + } + container.resize(nconstrained); + } + private: - void attachInputTrees(); - void attachInputTreesTPConly(); - bool prepareTracks(); - bool prepareTPCTracks(); + bool prepareFITData(); + int prepareInteractionTimes(); + bool prepareTPCData(); + void addTPCSeed(const o2::tpc::TrackTPC& _tr, o2::dataformats::GlobalTrackID srcGID); + void addITSTPCSeed(const o2::dataformats::TrackTPCITS& _tr, o2::dataformats::GlobalTrackID srcGID); + void addTRDSeed(const o2::trd::TrackTRD& _tr, o2::dataformats::GlobalTrackID srcGID, float time0, float terr); + void addConstrainedSeed(o2::track::TrackParCov& trc, o2::dataformats::GlobalTrackID srcGID, o2::track::TrackLTIntegral intLT0, timeEst timeMUS); + // void addTPCTRDSeed(const o2::track::TrackParCov& _tr, o2::dataformats::GlobalTrackID srcGID, int tpcID); + // void addITSTPCTRDSeed(const o2::track::TrackParCov& _tr, o2::dataformats::GlobalTrackID srcGID, int tpcID); bool prepareTOFClusters(); - bool loadTracksNextChunk(); - bool loadTPCTracksNextChunk(); - bool loadTOFClustersNextChunk(); void doMatching(int sec); void doMatchingForTPC(int sec); void selectBestMatches(); + void selectBestMatchesHP(); bool propagateToRefX(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, o2::track::TrackLTIntegral& intLT); bool propagateToRefXWithoutCov(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, float bz); + void updateTimeDependentParams(); + //================================================================ // Data members + const o2::globaltracking::RecoContainer* mRecoCont = nullptr; + o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF - bool mSAInitDone = false; ///< flag that standalone init already done - bool mWFInputAttached = false; ///< flag that the standalone input is attached + // for derived class + int mCurrTracksTreeEntry = 0; ///< current tracks tree entry loaded to memory float mXRef = Geo::RMIN; ///< reference radius to propage tracks for matching - int mCurrTracksTreeEntry = -1; ///< current tracks tree entry loaded to memory - int mCurrTOFClustersTreeEntry = -1; ///< current TOF clusters tree entry loaded to memory - bool mMCTruthON = false; ///< flag availability of MC truth ///========== Parameters to be set externally, e.g. from CCDB ==================== + float mBz = 0; ///< nominal Bz + float mMaxInvPt = 999.; ///< derived from nominal Bz // to be done later + float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds + float mTPCTBinMUSInv = 0.; ///< inverse TPC time bin duration in microseconds + float mTPCBin2Z = 0.; ///< conversion coeff from TPC time-bin to Z - float mTimeTolerance = 1e3; ///<tolerance in ns for track-TOF time bracket matching - float mSpaceTolerance = 10; ///<tolerance in cm for track-TOF time bracket matching + bool mIsCosmics = false; ///< switch on to reconstruct cosmics and match with TPC + float mTimeTolerance = 1e3; ///< tolerance in ns for track-TOF time bracket matching + float mSpaceTolerance = 10; ///< tolerance in cm for track-TOF time bracket matching int mSigmaTimeCut = 30.; ///< number of sigmas to cut on time when matching the track to the TOF cluster - TTree* mInputTreeTracks = nullptr; ///< input tree for tracks - TTree* mTreeTPCTracks = nullptr; ///< input tree for TPC tracks - TTree* mTreeTOFClusters = nullptr; ///< input tree for TOF clusters - - bool mIsITSused = true; + bool mIsFIT = false; + bool mIsITSTPCused = false; + bool mIsTPCused = false; + bool mIsTPCTRDused = false; + bool mIsITSTPCTRDused = false; + bool mSetHighPurity = false; - TTree* mOutputTree = nullptr; ///< output tree for matched tracks - - TTree* mOutputTreeCalib = nullptr; ///< output tree for calibration infos + // from ruben + gsl::span<const o2::tpc::TrackTPC> mTPCTracksArray; ///< input TPC tracks span ///>>>------ these are input arrays which should not be modified by the matching code // since this info is provided by external device - gsl::span<const o2::dataformats::TrackTPCITS> mTracksArrayInp; ///< input tracks - std::vector<o2::dataformats::TrackTPCITS>* mTracksArrayInpVect; ///< input tracks (vector to read from tree) - gsl::span<const o2::tpc::TrackTPC> mTPCTracksArrayInp; ///< input TPC tracks - std::vector<o2::tpc::TrackTPC>* mTPCTracksArrayInpVect; ///< input tracks (vector to read from tree) - gsl::span<const Cluster> mTOFClustersArrayInp; ///< input TOF clusters - std::vector<Cluster>* mTOFClustersArrayInpVect; ///< input TOF clusters (vector to read from tree) + // std::vector<o2::dataformats::TrackTPCITS> mITSTPCTracksArrayInp; ///< input tracks + gsl::span<const Cluster> mTOFClustersArrayInp; ///< input TOF clusters + + /// data needed for refit of time-constrained TPC tracks + gsl::span<const o2::tpc::TPCClRefElem> mTPCTrackClusIdx; ///< input TPC track cluster indices span + gsl::span<const unsigned char> mTPCRefitterShMap; ///< externally set TPC clusters sharing map + const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices + std::unique_ptr<o2::gpu::TPCFastTransform> mTPCTransform; ///< TPC cluster transformation + std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mTOFClusLabels; ///< input TOF clusters MC labels - o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mTOFClusLabelsPtr; ///< input TOF clusters MC labels (pointer to read from tree) - std::vector<o2::MCCompLabel> mTracksLblWork; ///<TPCITS track labels + const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mTOFClusLabels; ///< input TOF clusters MC labels (pointer to read from tree) - gsl::span<const o2::MCCompLabel> mTPCLabels; ///< TPC label of input tracks - gsl::span<const o2::MCCompLabel> mITSLabels; ///< ITS label of input tracks - std::vector<o2::MCCompLabel>* mTPCLabelsVect; ///< TPC label of input tracks (vector to read from tree) - std::vector<o2::MCCompLabel>* mITSLabelsVect; ///< ITS label of input tracks (vector to read from tree) + int mNotPropagatedToTOF[trkType::SIZE]; ///< number of tracks failing in propagation - gsl::span<o2::ft0::RecPoints const> mFITRecPoints; ///< FIT recpoints + gsl::span<const o2::ft0::RecPoints> mFITRecPoints; ///< FIT recpoints /// <<<----- ///<working copy of the input tracks - std::vector<matchTrack> mTracksWork; ///<track params prepared for matching + time value - std::vector<float> mExtraTPCFwdTime; ///<track extra params for TPC tracks: Fws Max time - std::vector<o2::track::TrackLTIntegral> mLTinfos; ///<expected times and others - std::vector<Cluster> mTOFClusWork; ///<track params prepared for matching - std::vector<int8_t> mSideTPC; ///<track side for TPC tracks - + std::vector<matchTrack> mTracksWork[trkType::SIZE]; ///<track params prepared for matching + time value + std::vector<o2::MCCompLabel> mTracksLblWork[trkType::SIZE]; ///<TPCITS track labels + std::vector<o2::track::TrackLTIntegral> mLTinfos[trkType::SIZE]; ///<expected times and others + std::vector<o2::dataformats::GlobalTrackID> mTrackGid[trkType::SIZE]; ///<expected times and others ///< per sector indices of track entry in mTracksWork - std::array<std::vector<int>, o2::constants::math::NSectors> mTracksSectIndexCache; - ///< per sector indices of track entry in mTPCTracksWork - std::array<std::vector<int>, o2::constants::math::NSectors> mTPCTracksSectIndexCache; + std::array<std::vector<int>, o2::constants::math::NSectors> mTracksSectIndexCache[trkType::SIZE]; + + std::vector<float> mExtraTPCFwdTime; ///<track extra params for TPC tracks: Fws Max time + std::vector<Cluster> mTOFClusWork; ///<track params prepared for matching + std::vector<int8_t> mSideTPC; ///<track side for TPC tracks + ///< per sector indices of TOF cluster entry in mTOFClusWork std::array<std::vector<int>, o2::constants::math::NSectors> mTOFClusSectIndexCache; ///<array of track-TOFCluster pairs from the matching - std::vector<o2::dataformats::MatchInfoTOF> mMatchedTracksPairs; + std::vector<o2::dataformats::MatchInfoTOFReco> mMatchedTracksPairs; ///<array of TOFChannel calibration info std::vector<o2::dataformats::CalibInfoTOF> mCalibInfoTOF; ///<array of matched TOFCluster with matching information (residuals, expected times...) with the corresponding vector of indices //std::vector<o2::dataformats::MatchInfoTOF> mMatchedTracks; - std::vector<o2::dataformats::MatchInfoTOF> mMatchedTracks; // this is the output of the matching - std::vector<o2::MCCompLabel> mOutTOFLabels; ///< TOF label of matched tracks - std::vector<o2::MCCompLabel> mOutTPCLabels; ///< TPC label of matched tracks - std::vector<o2::MCCompLabel> mOutITSLabels; ///< ITS label of matched tracks + std::vector<o2::dataformats::MatchInfoTOF> mMatchedTracks[trkType::SIZEALL]; // this is the output of the matching -> UNCONS, CONSTR + std::vector<o2::MCCompLabel> mOutTOFLabels[trkType::SIZEALL]; ///< TOF label of matched tracks + + std::vector<int> mMatchedTracksIndex[trkType::SIZE]; // vector of indexes of the tracks to be matched - int mNumOfTracks; // number of tracks to be matched - std::vector<int> mMatchedTracksIndex; // vector of indexes of the tracks to be matched int mNumOfClusters; // number of clusters to be matched int* mMatchedClustersIndex = nullptr; //[mNumOfClusters] - std::string mTracksBranchName = "TPCITS"; ///< name of branch containing input matched tracks - std::string mTPCTracksBranchName = "Tracks"; ///< name of branch containing actual TPC tracks - std::string mTPCMCTruthBranchName = "MatchTPCMCTruth"; ///< name of branch containing TPC labels - std::string mITSMCTruthBranchName = "MatchITSMCTruth"; ///< name of branch containing ITS labels - std::string mTOFMCTruthBranchName = "TOFClusterMCTruth"; ///< name of branch containing TOF clusters labels - std::string mTOFClusterBranchName = "TOFCluster"; ///< name of branch containing input ITS clusters - std::string mOutTracksBranchName = "TOFMatchInfo"; ///< name of branch containing output matched tracks - std::string mOutCalibBranchName = "TOFCalibInfo"; ///< name of branch containing output calibration infos - std::string mOutTOFMCTruthBranchName = "MatchTOFMCTruth"; ///< name of branch containing TOF labels for output matched tracks - std::string mOutTPCMCTruthBranchName = "MatchTPCMCTruth"; ///< name of branch containing TOF labels for output matched tracks - std::string mOutITSMCTruthBranchName = "MatchITSMCTruth"; ///< name of branch containing TOF labels for output matched tracks - std::string mOutTPCTrackMCTruthBranchName = "TracksMCTruth"; ///< name of branch containing TPC labels for input TPC tracks - std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut; UInt_t mDBGFlags = 0; std::string mDebugTreeFileName = "dbg_matchTOF.root"; ///< name for the debug tree file @@ -321,9 +294,9 @@ class MatchTOF ///----------- aux stuff --------------/// static constexpr float MAXSNP = 0.85; // max snp of ITS or TPC track at xRef to be matched - Bool_t mIsworkflowON = kFALSE; - TStopwatch mTimerTot; + TStopwatch mTimerMatchITSTPC; + TStopwatch mTimerMatchTPC; TStopwatch mTimerDBG; ClassDefNV(MatchTOF, 3); }; diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 0ba1d951e0371..31aa3913e5320 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,7 @@ #include "DetectorsBase/Propagator.h" #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "MathUtils/Primitive2D.h" #include "CommonDataFormat/EvIndex.h" #include "CommonDataFormat/InteractionRecord.h" @@ -45,14 +47,22 @@ #include "DataFormatsTPC/ClusterNativeHelper.h" #include "ITSReconstruction/RecoGeomHelper.h" #include "TPCFastTransform.h" +#include "GPUO2InterfaceRefit.h" #include "GlobalTracking/MatchTPCITSParams.h" #include "CommonDataFormat/FlatHisto2D.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/TrkClusRef.h" class TTree; namespace o2 { +namespace globaltracking +{ +class RecoContainer; +} + namespace dataformats { template <typename TruthElement> @@ -102,24 +112,37 @@ enum TrackRejFlag : int { ///< TPC track parameters propagated to reference X, with time bracket and index of ///< original track in the currently loaded TPC reco output struct TrackLocTPC : public o2::track::TrackParCov { - o2::math_utils::Bracketf_t timeBins; ///< bracketing time-bins - int sourceID = 0; ///< track origin id - float zMin = 0; // min possible Z of this track - float zMax = 0; // max possible Z of this track + enum Constraint_t : uint8_t { Constrained, + ASide, + CSide }; + o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus + float time0 = 0.f; ///< nominal time in \mus since start of TF (time0 for bare TPC tracks, constrained time for TRD/TOF constrained ones) + float timeErr = 0.f; ///< time sigma (makes sense for constrained tracks only) + int sourceID = 0; ///< TPC track origin in + o2::dataformats::GlobalTrackID gid{}; // global track source ID (TPC track may be part of it) int matchID = MinusOne; ///< entry (non if MinusOne) of its matchTPC struct in the mMatchesTPC - TrackLocTPC(const o2::track::TrackParCov& src, int tid) : o2::track::TrackParCov(src), sourceID(tid) {} - TrackLocTPC() = default; + Constraint_t constraint{Constrained}; + + float getCorrectedTime(float dt) const // return time0 corrected for extra drift (to match certain Z) + { + return constraint == Constrained ? time0 : (constraint == ASide ? time0 + dt : time0 - dt); + } + float getSignedDT(float dt) const // account for TPC side in time difference for dt=external_time - tpc.time0 + { + return constraint == Constrained ? 0. : (constraint == ASide ? dt : -dt); + } + ClassDefNV(TrackLocTPC, 1); }; ///< ITS track outward parameters propagated to reference X, with time bracket and index of ///< original track in the currently loaded ITS reco output struct TrackLocITS : public o2::track::TrackParCov { + o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus int sourceID = 0; ///< track origin id int roFrame = MinusOne; ///< ITS readout frame assigned to this track int matchID = MinusOne; ///< entry (non if MinusOne) of its matchCand struct in the mMatchesITS - TrackLocITS(const o2::track::TrackParCov& src, int tid) : o2::track::TrackParCov(src), sourceID(tid) {} - TrackLocITS() = default; + ClassDefNV(TrackLocITS, 1); }; @@ -152,20 +175,18 @@ struct MatchRecord { ///< original track in the currently loaded TPC reco output struct ABTrackLink : public o2::track::TrackParCov { static constexpr int Disabled = -2; - int clID = MinusOne; ///< ID of the attached cluster, MinusTen is for dummy layer above Nlr, MinusOne: no attachment on this layer + int clID = MinusOne; ///< ID of the attached cluster, MinusOne: no attachment on this layer int parentID = MinusOne; ///< ID of the parent link (on prev layer) or parent TPC seed int nextOnLr = MinusOne; ///< ID of the next (in quality) link on the same layer - int icCandID = MinusOne; ///< ID of the interaction candidate this track belongs to uint8_t nDaughters = 0; ///< number of daughter links on lower layers int8_t layerID = -1; ///< layer ID + int8_t nContLayers = 0; ///< number of contributing layers uint8_t ladderID = 0xff; ///< ladder ID in the layer (used for seeds with 2 hits in the layer) float chi2 = 0.f; ///< chi2 after update -#ifdef _ALLOW_DEBUG_AB_ - o2::track::TrackParCov seed; // seed before update -#endif - ABTrackLink() = default; - ABTrackLink(const o2::track::TrackParCov& src, int ic, int lr, int parid = MinusOne, int clid = MinusOne, float ch2 = 0.f) - : o2::track::TrackParCov(src), clID(clid), parentID(parid), icCandID(ic), layerID(lr), chi2(ch2) {} + + ABTrackLink(const o2::track::TrackParCov& tr, int cl, int parID, int nextID, int lr, int nc, int ld, float _chi2) + : o2::track::TrackParCov(tr), clID(cl), parentID(parID), nextOnLr(nextID), layerID(int8_t(lr)), nContLayers(int8_t(nc)), ladderID(uint8_t(ld)), chi2(_chi2) {} + bool isDisabled() const { return clID == Disabled; } void disable() { clID = Disabled; } bool isDummyTop() const { return clID == MinusTen; } @@ -173,81 +194,69 @@ struct ABTrackLink : public o2::track::TrackParCov { float chi2NormPredict(float chi2cl) const { return (chi2 + chi2cl) / (1 + o2::its::RecoGeomHelper::getNLayers() - layerID); } }; -struct ABTrackLinksList { - int trackID = MinusOne; ///< TPC work track id - int firstLinkID = MinusOne; ///< 1st link added (used for fast clean-up) - int bestOrdLinkID = MinusOne; ///< start of sorted list of ABOrderLink for final validation - int8_t lowestLayer = o2::its::RecoGeomHelper::getNLayers(); // lowest layer reached - int8_t status = MinusOne; ///< status (RS TODO) - std::array<int, o2::its::RecoGeomHelper::getNLayers() + 1> firstInLr; - ABTrackLinksList(int id = MinusOne) : trackID(id) +// AB primary seed: TPC track propagated to outermost ITS layer under specific InteractionCandidate hypothesis +struct TPCABSeed { + static constexpr int8_t NeedAlternative = -3; + int tpcWID = MinusOne; ///< TPC track ID + int ICCanID = MinusOne; ///< interaction candidate ID (they are sorted in increasing time) + int winLinkID = MinusOne; ///< ID of the validated link + int8_t lowestLayer = o2::its::RecoGeomHelper::getNLayers(); ///< lowest layer reached + int8_t status = MinusOne; ///< status (RS TODO) + o2::track::TrackParCov track{}; ///< Seed propagated to the outer layer under certain time constraint + std::array<int, o2::its::RecoGeomHelper::getNLayers()> firstInLr; ///< entry of 1st (best) hypothesis on each layer + std::vector<ABTrackLink> trackLinks{}; ///< links + TPCABSeed(int id, int ic, const o2::track::TrackParCov& trc) : tpcWID(id), ICCanID(ic), track(trc) { firstInLr.fill(MinusOne); } - bool isDisabled() const { return status == MinusTen; } // RS is this strict enough + bool isDisabled() const { return status == MinusTen; } void disable() { status = MinusTen; } bool isValidated() const { return status == Validated; } - void validate() { status = Validated; } -}; - -struct ABOrderLink { ///< link used for cross-layer sorting of best ABTrackLinks of the ABTrackLinksList - int trackLinkID = MinusOne; ///< ABTrackLink ID - int nextLinkID = MinusOne; ///< indext on the next ABOrderLink - ABOrderLink() = default; - ABOrderLink(int id, int nxt = MinusOne) : trackLinkID(id), nextLinkID(nxt) {} -}; - -//--------------------------------------------------- -struct ABDebugLink : o2::BaseCluster<float> { -#ifdef _ALLOW_DEBUG_AB_ - // AB link debug version, kinematics BEFORE update is stored - o2::track::TrackParCov seed; -#endif - o2::MCCompLabel clLabel; - float chi2 = 0.f; - uint8_t lr = 0; - - ClassDefNV(ABDebugLink, 1); -}; - -struct ABDebugTrack { - int trackID = 0; - int icCand = 0; - short order = 0; - short valid = 0; - o2::track::TrackParCov tpcSeed; - o2::MCCompLabel tpcLabel; - o2::math_utils::Bracket<float> icTimeBin; - std::vector<ABDebugLink> links; - float chi2 = 0; - uint8_t nClusTPC = 0; - uint8_t nClusITS = 0; - uint8_t nClusITSCorr = 0; - uint8_t sideAC = 0; - - ClassDefNV(ABDebugTrack, 1); -}; - -///< Link of the cluster used by AfterBurner: every used cluster will have 1 link for every update it did on some -///< AB seed. The link (index) points not on seed state it is updating but on the end-point of the seed (lowest layer reached) -struct ABClusterLink { - static constexpr int Disabled = -2; - int linkedABTrack = MinusOne; ///< ID of final AB track hypothesis it updates - int linkedABTrackList = MinusOne; ///< ID of the AB tracks list to which linkedABTrack belongs - int nextABClusterLink = MinusOne; ///< ID of the next link of this cluster - ABClusterLink() = default; - ABClusterLink(int idLink, int idList) : linkedABTrack(idLink), linkedABTrackList(idList) {} - bool isDisabled() const { return linkedABTrack == Disabled; } - void disable() { linkedABTrack = Disabled; } + void validate(int lID) + { + winLinkID = lID; + status = Validated; + } + bool needAlteranative() const { return status == NeedAlternative; } + void setNeedAlternative() { status = NeedAlternative; } + ABTrackLink& getLink(int i) { return trackLinks[i]; } + const ABTrackLink& getLink(int i) const { return trackLinks[i]; } + auto getBestLinkID() const + { + return lowestLayer < o2::its::RecoGeomHelper::getNLayers() ? firstInLr[lowestLayer] : -1; + } + bool checkLinkHasUsedClusters(int linkID, const std::vector<int>& clStatus) const + { + // check if some clusters used by the link or its parents are forbidden (already used by validatet track) + while (linkID > MinusOne) { + const auto& link = trackLinks[linkID]; + if (link.clID > MinusOne && clStatus[link.clID] != MinusOne) { + return true; + } + linkID = link.parentID; + } + return false; + } + void flagLinkUsedClusters(int linkID, std::vector<int>& clStatus) const + { + // check if some clusters used by the link or its parents are forbidden (already used by validated track) + while (linkID > MinusOne) { + const auto& link = trackLinks[linkID]; + if (link.clID > MinusOne) { + clStatus[link.clID] = MinusTen; + } + linkID = link.parentID; + } + } }; struct InteractionCandidate : public o2::InteractionRecord { - o2::math_utils::Bracket<float> timeBins; // interaction time (int TPC time bins) - int rofITS; // corresponding ITS ROF entry (in the ROFRecord vectors) - uint32_t flag; // origin, etc. - void* clRefPtr = nullptr; // pointer on cluster references container (if any) + o2::math_utils::Bracketf_t tBracket; // interaction time + int rofITS; // corresponding ITS ROF entry (in the ROFRecord vectors) + uint32_t flag; // origin, etc. + o2::dataformats::RangeReference<int, int> seedsRef; // references to AB seeds InteractionCandidate() = default; - InteractionCandidate(const o2::InteractionRecord& ir, float t, float dt, int rof, uint32_t f = 0) : o2::InteractionRecord(ir), timeBins(t - dt, t + dt), rofITS(rof), flag(f) {} + InteractionCandidate(const o2::InteractionRecord& ir, float t, float dt, int rof, uint32_t f = 0) : o2::InteractionRecord(ir), tBracket(t - dt, t + dt), rofITS(rof), flag(f) {} }; struct ITSChipClustersRefs { @@ -284,8 +293,6 @@ class MatchTPCITS MatchTPCITS(); // std::unique_ptr to forward declared type needs constructor / destructor in .cxx ~MatchTPCITS(); - static constexpr float XTPCInnerRef = 83.0; ///< reference radius at which TPC provides the tracks - static constexpr float XTPCOuterRef = 255.0; ///< reference radius to propagate outer TPC track static constexpr float XMatchingRef = 70.0; ///< reference radius to propage tracks for matching static constexpr float YMaxAtXMatchingRef = XMatchingRef * 0.17632698; ///< max Y in the sector at reference X @@ -294,43 +301,20 @@ class MatchTPCITS static constexpr int MaxSeedsPerLayer = 50; // TODO static constexpr int NITSLayers = o2::its::RecoGeomHelper::getNLayers(); ///< perform matching for provided input - void run(); - - // RSTODO - void runAfterBurner(); - bool runAfterBurner(int tpcWID, int iCStart, int iCEnd); - void buildABCluster2TracksLinks(); - float correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const; - int checkABSeedFromLr(int lrSeed, int seedID, ABTrackLinksList& llist); - void accountForOverlapsAB(int lrSeed); - void mergeABSeedsOnOverlaps(int lr, ABTrackLinksList& llist); - ABTrackLinksList& createABTrackLinksList(int tpcWID); - ABTrackLinksList& getABTrackLinksList(int tpcWID) { return mABTrackLinksList[mTPCWork[tpcWID].matchID]; } - void disableABTrackLinksList(int tpcWID); - int registerABTrackLink(ABTrackLinksList& llist, const o2::track::TrackParCov& src, int ic, int lr, int parentID = -1, int clID = -1, float chi2Cl = 0.f); - void printABTracksTree(const ABTrackLinksList& llist) const; - void printABClusterUsage() const; - void selectBestMatchesAB(); - bool validateABMatch(int ilink); - void buildBestLinksList(int ilink); - bool isBetter(float chi2A, float chi2B) { return chi2A < chi2B; } // RS TODO - void dumpABTracksDebugTree(const ABTrackLinksList& llist); - int prepareInteractionTimes(); - void destroyLastABTrackLinksList(); - void refitABTrack(int ibest) const; + void run(const o2::globaltracking::RecoContainer& inp); + void setSkipTPCOnly(bool v) { mSkipTPCOnly = v; } void setCosmics(bool v) { mCosmics = v; } bool isCosmics() const { return mCosmics; } + void setNThreads(int n); ///< perform all initializations void init(); + void end(); ///< clear results of previous event reco void clear(); - ///< set InteractionRecods for the beginning of the TF - void setStartIR(const o2::InteractionRecord& ir) { mStartIR = ir; } - ///< set Bunch filling and init helpers for validation by BCs void setBunchFilling(const o2::BunchFilling& bf); @@ -342,11 +326,12 @@ class MatchTPCITS bool getUseFT0() const { return mUseFT0; } ///< set ITS ROFrame duration in microseconds - void setITSROFrameLengthMUS(float fums) { mITSROFrameLengthMUS = fums; } + void setITSROFrameLengthMUS(float fums); ///< set ITS ROFrame duration in BC (continuous mode only) void setITSROFrameLengthInBC(int nbc); // ==================== >> DPL-driven input >> ======================= + void setITSDictionary(const o2::itsmft::TopologyDictionary* d) { mITSDict = d; } ///< set flag to use MC truth void setMCTruthOn(bool v) @@ -361,90 +346,18 @@ class MatchTPCITS } ///< get histo for tgl differences for VDrift calibration - auto getHistoDTgl() { return mHistoDTgl.get(); } - - ///< set input ITS tracks - void setITSTracksInp(const gsl::span<const o2::its::TrackITS> inp) - { - mITSTracksArray = inp; - } - - ///< set input ITS tracks cluster indices - void setITSTrackClusIdxInp(const gsl::span<const int> inp) - { - mITSTrackClusIdx = inp; - } - - ///< set input ITS tracks ROF records - void setITSTrackROFRecInp(const gsl::span<const o2::itsmft::ROFRecord> inp) - { - mITSTrackROFRec = inp; - } - - ///< set input ITS clusters - void setITSClustersInp(const gsl::span<const ITSCluster> inp) - { - mITSClustersArray = inp; - } - - ///< set input ITS clusters ROF records - void setITSClusterROFRecInp(const gsl::span<const o2::itsmft::ROFRecord> inp) - { - mITSClusterROFRec = inp; - } - - ///< set input TPC tracks - void setTPCTracksInp(const gsl::span<const o2::tpc::TrackTPC> inp) - { - mTPCTracksArray = inp; - } - - ///< set input TPC tracks cluster indices - void setTPCTrackClusIdxInp(const gsl::span<const o2::tpc::TPCClRefElem> inp) - { - mTPCTrackClusIdx = inp; - } - - ///< set input TPC clusters - void setTPCClustersInp(const o2::tpc::ClusterNativeAccess* inp) - { - mTPCClusterIdxStruct = inp; - } - - ///< set input ITS track MC labels - void setITSTrkLabelsInp(const MCLabSpan& lbl) - { - mITSTrkLabels = lbl; - } - - ///< set input ITS clusters MC labels - void setITSClsLabelsInp(const MCLabContCl* lbl) - { - mITSClsLabels = lbl; - } - - ///< set input TPC track MC labels - void setTPCTrkLabelsInp(const MCLabSpan& lbl) - { - mTPCTrkLabels = lbl; - } - - ///< set input FIT info - void setFITInfoInp(const gsl::span<const o2::ft0::RecPoints> inp) - { - mFITInfo = inp; - } - - // ===================== << DPL-driven input << ======================== + auto getHistoDTgl() const { return mHistoDTgl.get(); } ///< print settings void print() const; void printCandidatesTPC() const; void printCandidatesITS() const; - std::vector<o2::dataformats::TrackTPCITS>& getMatchedTracks() { return mMatchedTracks; } - MCLabContTr& getMatchedITSLabels() { return mOutITSLabels; } - MCLabContTr& getMatchedTPCLabels() { return mOutTPCLabels; } + const std::vector<o2::dataformats::TrackTPCITS>& getMatchedTracks() const { return mMatchedTracks; } + const MCLabContTr& getMatchLabels() const { return mOutLabels; } + const MCLabContTr& getABTrackletLabels() const { return mABTrackletLabels; } + const std::vector<int>& getABTrackletClusterIDs() const { return mABTrackletClusterIDs; } + const std::vector<o2::itsmft::TrkClusRef>& getABTrackletRefs() const { return mABTrackletRefs; } //>>> ====================== options =============================>>> void setUseMatCorrFlag(MatCorrType f) { mUseMatCorrFlag = f; } @@ -484,30 +397,29 @@ class MatchTPCITS #endif private: - void updateTPCTimeDependentParams(); + void updateTimeDependentParams(); int findLaddersToCheckBOn(int ilr, int lad0, const o2::math_utils::CircleXYf_t& circle, float errYFrac, std::array<int, MaxLadderCand>& lad2Check) const; int findLaddersToCheckBOff(int ilr, int lad0, const o2::math_utils::IntervalXYf_t& trcLinPar, float errYFrac, std::array<int, MatchTPCITS::MaxLadderCand>& lad2Check) const; - + bool prepareTPCData(); + bool prepareITSData(); + bool prepareFITData(); + int prepareInteractionTimes(); int prepareTPCTracksAfterBurner(); - bool prepareTPCTracks(); - bool prepareITSTracks(); - bool prepareFITInfo(); + void addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, o2::dataformats::GlobalTrackID srcGID, int tpcID); - int preselectChipClusters(std::vector<int>& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& clRefs, - float trackY, float trackZ, float tolerY, float tolerZ, const o2::MCCompLabel& lblTrc) const; - void fillClustersForAfterBurner(ITSChipClustersRefs& refCont, int rofStart, int nROFs = 1); - void cleanAfterBurnerClusRefCache(int currentIC, int& startIC); - void flagUsedITSClusters(const o2::its::TrackITS& track, int rofOffset); + int preselectChipClusters(std::vector<int>& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& itsChipClRefs, + float trackY, float trackZ, float tolerY, float tolerZ) const; + void fillClustersForAfterBurner(int rofStart, int nROFs, ITSChipClustersRefs& itsChipClRefs); + void flagUsedITSClusters(const o2::its::TrackITS& track); void doMatching(int sec); - void refitWinners(bool loopInITS = false); - bool refitTrackTPCITSloopITS(int iITS, int& iTPC); - bool refitTrackTPCITSloopTPC(int iTPC, int& iITS); - bool refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, float xTgt, int trcID, float timeTB, float m = o2::constants::physics::MassPionCharged) const; + void refitWinners(); + bool refitTrackTPCITS(int iTPC, int& iITS); + bool refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, float xTgt, int trcID, float timeTB) const; void selectBestMatches(); bool validateTPCMatch(int iTPC); @@ -534,46 +446,37 @@ class MatchTPCITS ///< get number of matching records for ITS track int getNMatchRecordsITS(const TrackLocITS& tITS) const; - ///< convert TPC timebins bracket to IR bracket - BracketIR tpcTimeBin2IRBracket(const BracketF tbrange); + ///< convert time bracket to IR bracket + BracketIR tBracket2IRBracket(const BracketF tbrange); - ///< convert TPC time bin to ITS ROFrame units - int tpcTimeBin2ITSROFrame(float tbin) const + ///< convert time to ITS ROFrame units in case of continuous ITS readout + int time2ITSROFrameCont(float t) const { - if (mITSTriggered) { - return mITSROFofTPCBin[int(tbin > 0 ? tbin : 0)]; - } - int rof = tbin > 0 ? tbin * mTPCBin2ITSROFrame : 0; + int rof = t > 0 ? t * mITSROFrameLengthMUSInv : 0; // the rof is estimated continuous counter but the actual bins might have gaps (e.g. HB rejects etc)-> use mapping - return rof < mITSTrackROFContMapping.size() ? mITSTrackROFContMapping[rof] : mITSTrackROFContMapping.back(); + return rof < int(mITSTrackROFContMapping.size()) ? mITSTrackROFContMapping[rof] : mITSTrackROFContMapping.back(); } - ///< convert ITS ROFrame to TPC time bin units // TOREMOVE - float itsROFrame2TPCTimeBin(int rof) const { return rof * mITSROFrame2TPCBin; } - - ///< convert time in microseconds to TPC time bin units - float time2TPCTimeBin(float tms) const + ///< convert time to ITS ROFrame units in case of triggered ITS readout + int time2ITSROFrameTrig(float t, int start) const { - return tms * mTPCTBinMUSInv; + while (start < mITSROFTimes.size()) { + if (mITSROFTimes[start].getMax() > t) { + return start; + } + start++; + } + return --start; } ///< convert TPC time bin to microseconds - float tpcTimeBin2MUS(float tbn) const - { - return tbn * mTPCTBinMUS; - } + float tpcTimeBin2Z(float tbn) const { return tbn * mTPCBin2Z; } - ///< convert TPC time bin to nanoseconds - float tpcTimeBin2NS(float tbn) const - { - return tbn * mTPCTBinNS; - } + ///< convert TPC time bin to microseconds + float tpcTimeBin2MUS(float tbn) const { return tbn * mTPCTBinMUS; } - ///< convert Interaction Record for TPC time bin units - float intRecord2TPCTimeBin(const o2::InteractionRecord& bc) const - { - return time2TPCTimeBin(bc.differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3); - } + ///< convert TPC time bin to nanoseconds + float tpcTimeBin2NS(float tbn) const { return tbn * mTPCTBinNS; } ///< convert Z interval to TPC time-bins float z2TPCBin(float z) const { return z * mZ2TPCBin; } @@ -587,27 +490,26 @@ class MatchTPCITS return delta > toler ? rejFlag : (delta < -toler ? -rejFlag : Accept); } - ///< correct TPC time0 (int TPC time-bins) - float getTPCTrackCorrectedTimeBin(const o2::tpc::TrackTPC& trc, float delta) const - { - float timeTB = trc.getTime0(); - if (trc.hasASideClustersOnly()) { - timeTB += delta; - } else if (trc.hasCSideClustersOnly()) { - timeTB -= delta; - } else { - // TODO : special treatment of tracks crossing the CE - } - return timeTB; - } - + // ========================= AFTERBURNER ========================= + void runAfterBurner(); + int prepareABSeeds(); + void processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs); + int followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed); + int registerABTrackLink(TPCABSeed& ABSeed, const o2::track::TrackParCov& trc, int clID, int parentID, int lr, int laddID, float chi2Cl); + bool isBetter(float chi2A, float chi2B) { return chi2A < chi2B; } // RS FIMXE TODO + void refitABWinners(); + bool refitABTrack(int iITSAB, const TPCABSeed& seed); + void accountForOverlapsAB(int lrSeed); + float correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const; // RS FIXME will be needed for refit //================================================================ bool mInitDone = false; ///< flag init already done bool mFieldON = true; ///< flag for field ON/OFF bool mCosmics = false; ///< flag cosmics mode bool mMCTruthON = false; ///< flag availability of MC truth - + float mBz = 0; ///< nominal Bz + int mTFCount = 0; ///< internal TF counter for debugger + int mNThreads = 1; ///< number of OMP threads o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF ///========== Parameters to be set externally, e.g. from CCDB ==================== @@ -616,6 +518,7 @@ class MatchTPCITS MatCorrType mUseMatCorrFlag = MatCorrType::USEMatCorrTGeo; + bool mSkipTPCOnly = false; ///< for test only: don't use TPC only tracks, use only external ones bool mITSTriggered = false; ///< ITS readout is triggered bool mUseFT0 = false; ///< FT0 information is available @@ -627,20 +530,20 @@ class MatchTPCITS ///< safety margin in TPC time bins when estimating TPC track tMin and tMax from ///< assigned time0 and its track Z position (converted from mTPCTimeEdgeZSafeMargin) float mTPCTimeEdgeTSafeMargin = 0.f; - + float mTPCExtConstrainedNSigmaInv = 0.f; // inverse for NSigmas for TPC time-interval from external constraint time sigma int mITSROFrameLengthInBC = 0; ///< ITS RO frame in BC (for ITS cont. mode only) float mITSROFrameLengthMUS = -1.; ///< ITS RO frame in \mus + float mITSROFrameLengthMUSInv = -1.; ///< ITS RO frame in \mus inverse float mTPCVDrift0 = -1.; ///< TPC nominal drift speed in cm/microseconds float mTPCVDrift0Inv = -1.; ///< inverse TPC nominal drift speed in cm/microseconds float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds float mTPCTBinNS = 0.; ///< TPC time bin duration in ns float mTPCTBinMUSInv = 0.; ///< inverse TPC time bin duration in microseconds - float mITSROFrame2TPCBin = 0.; ///< conversion coeff from ITS ROFrame units to TPC time-bin - float mTPCBin2ITSROFrame = 0.; ///< conversion coeff from TPC time-bin to ITS ROFrame units float mZ2TPCBin = 0.; ///< conversion coeff from Z to TPC time-bin float mTPCBin2Z = 0.; ///< conversion coeff from TPC time-bin to Z float mNTPCBinsFullDrift = 0.; ///< max time bin for full drift float mTPCZMax = 0.; ///< max drift length + float mTPCmeanX0Inv = 1. / 31850.; ///< TPC gas 1/X0 float mMinTPCTrackPtInv = 999.; ///< cutoff on TPC track inverse pT float mMinITSTrackPtInv = 999.; ///< cutoff on ITS track inverse pT @@ -649,12 +552,13 @@ class MatchTPCITS std::unique_ptr<o2::dataformats::FlatHisto2D_f> mHistoDTgl; ///< histo for VDrift calibration data std::unique_ptr<TPCTransform> mTPCTransform; ///< TPC cluster transformation - std::unique_ptr<o2::gpu::GPUParam> mTPCClusterParam; ///< TPC clusters error param + std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction o2::BunchFilling mBunchFilling; std::array<int16_t, o2::constants::lhc::LHCMaxBunches> mClosestBunchAbove; // closest filled bunch from above std::array<int16_t, o2::constants::lhc::LHCMaxBunches> mClosestBunchBelow; // closest filled bunch from below + const o2::globaltracking::RecoContainer* mRecoCont = nullptr; ///>>>------ these are input arrays which should not be modified by the matching code // since this info is provided by external device gsl::span<const o2::tpc::TrackTPC> mTPCTracksArray; ///< input TPC tracks span @@ -662,10 +566,14 @@ class MatchTPCITS gsl::span<const o2::itsmft::ROFRecord> mITSTrackROFRec; ///< input ITS tracks ROFRecord span gsl::span<const o2::its::TrackITS> mITSTracksArray; ///< input ITS tracks span gsl::span<const int> mITSTrackClusIdx; ///< input ITS track cluster indices span - gsl::span<const ITSCluster> mITSClustersArray; ///< input ITS clusters span + std::vector<ITSCluster> mITSClustersArray; ///< ITS clusters created in loadInput gsl::span<const o2::itsmft::ROFRecord> mITSClusterROFRec; ///< input ITS clusters ROFRecord span gsl::span<const o2::ft0::RecPoints> mFITInfo; ///< optional input FIT info span + gsl::span<const unsigned char> mTPCRefitterShMap; ///< externally set TPC clusters sharing map + + const o2::itsmft::TopologyDictionary* mITSDict{nullptr}; // cluster patterns dictionary + const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices const MCLabContCl* mITSClsLabels = nullptr; ///< input ITS Cluster MC labels @@ -681,49 +589,43 @@ class MatchTPCITS ///< container for reference to MatchRecord involving particular ITS track std::vector<MatchRecord> mMatchRecordsITS; - std::vector<int> mITSROFofTPCBin; ///< aux structure for mapping of TPC time-bins on ITS ROFs - std::vector<BracketF> mITSROFTimes; ///< min/max times of ITS ROFs in TPC time-bins + //// std::vector<int> mITSROFofTPCBin; ///< aux structure for mapping of TPC time-bins on ITS ROFs + std::vector<BracketF> mITSROFTimes; ///< min/max times of ITS ROFs in \mus std::vector<TrackLocTPC> mTPCWork; ///< TPC track params prepared for matching std::vector<TrackLocITS> mITSWork; ///< ITS track params prepared for matching MCLabContTr mTPCLblWork; ///< TPC track labels MCLabContTr mITSLblWork; ///< ITS track labels std::vector<float> mWinnerChi2Refit; ///< vector of refitChi2 for winners - std::deque<ITSChipClustersRefs> mITSChipClustersRefs; ///< range of clusters for each chip in ITS (for AfterBurner) - - std::vector<ABTrackLinksList> mABTrackLinksList; ///< pool of ABTrackLinksList objects for every TPC track matched by AB - std::vector<ABTrackLink> mABTrackLinks; ///< pool AB track links - std::vector<ABClusterLink> mABClusterLinks; ///< pool AB cluster links - std::vector<ABOrderLink> mABBestLinks; ///< pool of ABOrder links for best links of the ABTrackLinksList + // ------------------------------ + std::vector<TPCABSeed> mTPCABSeeds; ///< pool of primary TPC seeds for AB + ///< indices of selected track entries in mTPCWork (for tracks selected by AfterBurner) + std::vector<int> mTPCABIndexCache; + std::vector<int> mABWinnersIDs; + std::vector<int> mABTrackletClusterIDs; ///< IDs of ITS clusters for AfterBurner winners + std::vector<o2::itsmft::TrkClusRef> mABTrackletRefs; ///< references on AfterBurner winners clusters std::vector<int> mABClusterLinkIndex; ///< index of 1st ABClusterLink for every cluster used by AfterBurner, -1: unused, -10: used by external ITS tracks - int mMaxABLinksOnLayer = 20; ///< max number of candidate links per layer - int mMaxABFinalHyp = 10; ///< max number of final hypotheses to consider + MCLabContTr mABTrackletLabels; + // ------------------------------ ///< per sector indices of TPC track entry in mTPCWork std::array<std::vector<int>, o2::constants::math::NSectors> mTPCSectIndexCache; ///< per sector indices of ITS track entry in mITSWork std::array<std::vector<int>, o2::constants::math::NSectors> mITSSectIndexCache; - ///< indices of selected track entries in mTPCWork (for tracks selected by AfterBurner) - std::vector<int> mTPCABIndexCache; - ///< indices of 1st entries with time-bin above the value - std::vector<int> mTPCABTimeBinStart; - - ///< indices of 1st entries with time-bin above the value - std::array<std::vector<int>, o2::constants::math::NSectors> mTPCTimeBinStart; - ///< indices of 1st entries of ITS tracks with givem ROframe - std::array<std::vector<int>, o2::constants::math::NSectors> mITSTimeBinStart; + ///< indices of 1st TPC tracks with time above the ITS ROF time + std::array<std::vector<int>, o2::constants::math::NSectors> mTPCTimeStart; + ///< indices of 1st entries of ITS tracks starting at given ROframe + std::array<std::vector<int>, o2::constants::math::NSectors> mITSTimeStart; /// mapping for tracks' continuos ROF cycle to actual continuous readout ROFs with eventual gaps std::vector<int> mITSTrackROFContMapping; ///< outputs tracks container std::vector<o2::dataformats::TrackTPCITS> mMatchedTracks; - MCLabContTr mOutITSLabels; ///< ITS label of matched track - MCLabContTr mOutTPCLabels; ///< TPC label of matched track + MCLabContTr mOutLabels; ///< Labels: = TPC labels with flag isFake set in case of fake matching o2::its::RecoGeomHelper mRGHelper; ///< helper for cluster and geometry access - float mITSFiducialZCut = 9999.; ///< eliminate TPC seeds outside of this range #ifdef _ALLOW_DEBUG_TREES_ std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut; @@ -744,13 +646,17 @@ class MatchTPCITS SWDoMatching, SWSelectBest, SWRefit, + SWABSeeds, + SWABMatch, + SWABWinners, + SWABRefit, SWIO, SWDBG, NStopWatches }; - static constexpr std::string_view TimerName[] = {"Total", "PrepareITS", "PrepareTPC", "DoMatching", "SelectBest", "Refit", "IO", "Debug"}; + static constexpr std::string_view TimerName[] = {"Total", "PrepareITS", "PrepareTPC", "DoMatching", "SelectBest", "Refit", + "ABSeeds", "ABMatching", "ABWinners", "ABRefit", "IO", "Debug"}; TStopwatch mTimer[NStopWatches]; - ClassDefNV(MatchTPCITS, 1); }; //______________________________________________ @@ -771,123 +677,6 @@ inline bool MatchTPCITS::isDisabledITS(const TrackLocITS& t) const { return t.ma //______________________________________________ inline bool MatchTPCITS::isDisabledTPC(const TrackLocTPC& t) const { return t.matchID < 0; } -//______________________________________________ -inline void MatchTPCITS::removeTPCfromITS(int tpcID, int itsID) -{ - ///< remove reference to tpcID track from itsID track matches - auto& tITS = mITSWork[itsID]; - if (isValidatedITS(tITS)) { - return; - } - int topID = MinusOne, next = tITS.matchID; // ITS MatchRecord - while (next > MinusOne) { - auto& rcITS = mMatchRecordsITS[next]; - if (rcITS.partnerID == tpcID) { - if (topID < 0) { - tITS.matchID = rcITS.nextRecID; - } else { - mMatchRecordsITS[topID].nextRecID = rcITS.nextRecID; - } - return; - } - topID = next; - next = rcITS.nextRecID; - } -} - -//______________________________________________ -inline void MatchTPCITS::removeITSfromTPC(int itsID, int tpcID) -{ - ///< remove reference to itsID track from matches of tpcID track - auto& tTPC = mTPCWork[tpcID]; - if (isValidatedTPC(tTPC)) { - return; - } - int topID = MinusOne, next = tTPC.matchID; - while (next > MinusOne) { - auto& rcTPC = mMatchRecordsTPC[next]; - if (rcTPC.partnerID == itsID) { - if (topID < 0) { - tTPC.matchID = rcTPC.nextRecID; - } else { - mMatchRecordsTPC[topID].nextRecID = rcTPC.nextRecID; - } - return; - } - topID = next; - next = rcTPC.nextRecID; - } -} - -//______________________________________________ -inline void MatchTPCITS::flagUsedITSClusters(const o2::its::TrackITS& track, int rofOffset) -{ - // flag clusters used by this track - int clEntry = track.getFirstClusterEntry(); - for (int icl = track.getNumberOfClusters(); icl--;) { - mABClusterLinkIndex[rofOffset + mITSTrackClusIdx[clEntry++]] = MinusTen; - } -} -//__________________________________________________________ -inline int MatchTPCITS::preselectChipClusters(std::vector<int>& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& clRefs, - float trackY, float trackZ, float tolerY, float tolerZ, - const o2::MCCompLabel& lblTrc) const // TODO lbl is not needed -{ - clVecOut.clear(); - int icID = clRange.getFirstEntry(); - for (int icl = clRange.getEntries(); icl--;) { // note: clusters within a chip are sorted in Z - int clID = clRefs.clusterID[icID++]; // so, we go in clusterID increasing direction - const auto& cls = mITSClustersArray[clID]; - float dz = trackZ - cls.getZ(); - auto label = mITSClsLabels->getLabels(clID)[0]; // tmp - // if (!(label == lblTrc)) { - // continue; // tmp - // } - LOG(DEBUG) << "cl" << icl << '/' << clID << " " << label - << " dZ: " << dz << " [" << tolerZ << "| dY: " << trackY - cls.getY() << " [" << tolerY << "]"; - if (dz > tolerZ) { - float clsZ = cls.getZ(); - LOG(DEBUG) << "Skip the rest since " << trackZ << " > " << clsZ << "\n"; - break; - } else if (dz < -tolerZ) { - LOG(DEBUG) << "Skip cluster dz=" << dz << " Ztr=" << trackZ << " zCl=" << cls.getZ(); - continue; - } - if (fabs(trackY - cls.getY()) > tolerY) { - LOG(DEBUG) << "Skip cluster dy= " << trackY - cls.getY() << " Ytr=" << trackY << " yCl=" << cls.getY(); - continue; - } - clVecOut.push_back(clID); - } - return clVecOut.size(); -} - -//______________________________________________ -inline void MatchTPCITS::cleanAfterBurnerClusRefCache(int currentIC, int& startIC) -{ - // check if some of cached cluster reference from tables startIC to currentIC can be released, - // they will be necessarily in front slots of the mITSChipClustersRefs - while (startIC < currentIC && mInteractions[currentIC].timeBins.getMin() - mInteractions[startIC].timeBins.getMax() > MinTBToCleanCache) { - LOG(INFO) << "CAN REMOVE CACHE FOR " << startIC << " curent IC=" << currentIC; - while (mInteractions[startIC].clRefPtr == &mITSChipClustersRefs.front()) { - LOG(INFO) << "Reset cache pointer" << mInteractions[startIC].clRefPtr << " for IC=" << startIC; - mInteractions[startIC++].clRefPtr = nullptr; - } - LOG(INFO) << "Reset cache slot " << &mITSChipClustersRefs.front(); - mITSChipClustersRefs.pop_front(); - } -} - -//______________________________________________ -inline void MatchTPCITS::destroyLastABTrackLinksList() -{ - // Profit from the links of the last ABTrackLinksList having been added in the very end of mABTrackLinks - // and eliminate them also removing the last ABTrackLinksList. - // This method should not be called after buildABCluster2TracksLinks!!! - const auto& llist = mABTrackLinksList.back(); - mABTrackLinks.resize(llist.firstLinkID); - mABTrackLinksList.pop_back(); -} } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h index c10f2c13b1621..a2e2263f08127 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,38 +30,49 @@ struct MatchTPCITSParams : public o2::conf::ConfigurableParamHelper<MatchTPCITSP Prefer, Require }; // flags for usage of FT0 in match validation - bool runAfterBurner = false; ///< run afterburner for TPCtrack-ITScluster matching + bool runAfterBurner = true; ///< run afterburner for TPCtrack-ITScluster matching ValidateMatchByFIT validateMatchByFIT = Prefer; ///< when comparing ITS-TPC matches, prefer those which have time of Interaction Candidate float crudeAbsDiffCut[o2::track::kNParams] = {2.f, 2.f, 0.2f, 0.2f, 4.f}; float crudeNSigma2Cut[o2::track::kNParams] = {49.f, 49.f, 49.f, 49.f, 49.f}; - float minTPCTrackR = 26.6; ///< cut on minimal TPC tracks radius to consider for matching, 666*pt_gev*B_kgaus/5 - float minITSTrackR = 26.6; ///< cut on minimal ITS tracks radius to consider for matching, 666*pt_gev*B_kgaus/5 + float minTPCTrackR = 50.; ///< cut on minimal TPC tracks radius to consider for matching, 666*pt_gev*B_kgaus/5 + float minITSTrackR = 50.; ///< cut on minimal ITS tracks radius to consider for matching, 666*pt_gev*B_kgaus/5 int minTPCClusters = 25; ///< minimum number of clusters to consider int askMinTPCRow = 15; ///< disregard tracks starting above this row float cutMatchingChi2 = 30.f; ///< cut on matching chi2 - float cutABTrack2ClChi2 = 30.f; ///< cut on AfterBurner track-cluster chi2 - int maxMatchCandidates = 5; ///< max allowed matching candidates per TPC track - int requireToReachLayerAB = 5; ///< AB tracks should reach at least this layer from above - float safeMarginTPCITSTimeBin = 1.f; ///< safety margin (in TPC time bins) for ITS-TPC tracks time (in TPC time bins!) comparison float safeMarginTPCTimeEdge = 20.f; ///< safety margin in cm when estimating TPC track tMin and tMax from assigned time0 and its track Z position - float timeBinTolerance = 10.f; ///<tolerance in time-bin for ITS-TPC time bracket matching (not used ? TODO) - float tpcTimeICMatchingNSigma = 4.; ///< nsigma for matching TPC corrected time and InteractionCandidate from FT0 + float tpcExtConstrainedNSigma = 4.; ///< nsigma to apply to externally (TRD,TOF) time-constrained TPC tracks time error + + float tfEdgeTimeToleranceMUS = 1.; ///< corrected TPC time allowed to go out from the TF time edges by this amount + float maxVDriftUncertainty = 0.; ///< max assumed VDrift uncertainty, used only in VDrift calibration mode float maxTglForVDriftCalib = 1.; ///< maximum ITS tgl to collect data for VDrift calibration int nBinsTglVDriftCalib = 50; ///< number of bins in reference ITS tgl for VDrift calibration int nBinsDTglVDriftCalib = 100; ///< number of bins in delta tgl for VDrift calibration + //___________________ AfterBurner params + int requireToReachLayerAB = 5; ///< AB tracks should reach at least this layer from above + int lowestLayerAB = 0; ///< lowest layer to reach in AfterBurner + int minContributingLayersAB = 2; ///< AB tracks must have at least this amount on contributing layers + int maxHoleSizeAB = 1; ///< between 2 contributing layers there should be at most this amount of non-contributing ones + int maxABLinksOnLayer = 10; ///< max prolongations for single seed from one to next layer + int maxABFinalHyp = 20; ///< max final hypotheses per TPC seed + float cutABTrack2ClChi2 = 30.f; ///< cut on AfterBurner track-cluster chi2 + float nABSigmaY = 4.; ///< nSigma cut on afterburner track-cluster Y distance + float nABSigmaZ = 4.; ///< nSigma cut on afterburner track-cluster Z distance + float err2ABExtraY = 0.1 * 0.1; ///< extra "systematic" error on Y + float err2ABExtraZ = 0.1 * 0.1; ///< extra "systematic" error on Z + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; /// Material correction type O2ParamDef(MatchTPCITSParams, "tpcitsMatch"); diff --git a/Detectors/GlobalTracking/src/GlobalTrackingLinkDef.h b/Detectors/GlobalTracking/src/GlobalTrackingLinkDef.h index 74f3ce33f51aa..7eb62904366a3 100644 --- a/Detectors/GlobalTracking/src/GlobalTrackingLinkDef.h +++ b/Detectors/GlobalTracking/src/GlobalTrackingLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,15 +15,19 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::globaltracking::MatchTPCITS + ; #pragma link C++ class o2::globaltracking::MatchTOF + ; #pragma link C++ class o2::globaltracking::TrackLocTPC + ; #pragma link C++ class o2::globaltracking::TrackLocITS + ; #pragma link C++ class o2::globaltracking::MatchTPCITSParams + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::globaltracking::MatchTPCITSParams> + ; -#pragma link C++ class o2::globaltracking::ABDebugLink + ; -#pragma link C++ class o2::globaltracking::ABDebugTrack + ; +#pragma link C++ class o2::globaltracking::MatchCosmics + ; +#pragma link C++ class o2::globaltracking::MatchCosmicsParams + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::globaltracking::MatchCosmicsParams> + ; + +// RS FIXME remove ? +//#pragma link C++ class o2::globaltracking::ABDebugLink + ; +//#pragma link C++ class o2::globaltracking::ABDebugTrack + ; #pragma link C++ class std::pair < o2::dataformats::EvIndex < int, int>, o2::dataformats::MatchInfoTOF> + ; #pragma link C++ class std::vector < std::pair < o2::dataformats::EvIndex < int, int>, o2::dataformats::MatchInfoTOF>> + ; diff --git a/Detectors/GlobalTracking/src/MatchCosmics.cxx b/Detectors/GlobalTracking/src/MatchCosmics.cxx new file mode 100644 index 0000000000000..e2d21997b02e2 --- /dev/null +++ b/Detectors/GlobalTracking/src/MatchCosmics.cxx @@ -0,0 +1,578 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GlobalTracking/MatchCosmics.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "GPUO2InterfaceRefit.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTOF/Cluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsFT0/RecPoints.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ITStracking/IOUtils.h" +#include "ITSBase/GeometryTGeo.h" +#include "TPCBase/ParameterElectronics.h" +#include "DetectorsBase/Propagator.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "GlobalTracking/MatchTPCITS.h" +#include "CommonConstants/GeomConstants.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include <algorithm> +#include <numeric> + +using namespace o2::globaltracking; + +using GTrackID = o2d::GlobalTrackID; +using MatCorrType = o2::base::Propagator::MatCorrType; + +//________________________________________________________ +void MatchCosmics::process(const o2::globaltracking::RecoContainer& data) +{ + updateTimeDependentParams(); + mRecords.clear(); + mWinners.clear(); + mCosmicTracks.clear(); + mCosmicTracksLbl.clear(); + + createSeeds(data); + int ntr = mSeeds.size(); + + // propagate to DCA to origin + const o2::math_utils::Point3D<float> v{0., 0., 0}; + for (int i = 0; i < ntr; i++) { + auto& trc = mSeeds[i]; + if (!o2::base::Propagator::Instance()->propagateToDCABxByBz(v, trc, mMatchParams->maxStep, mMatchParams->matCorr)) { + trc.matchID = Reject; // reject track + } + } + + // sort in time bracket lower edge + std::vector<int> sortID(ntr); + std::iota(sortID.begin(), sortID.end(), 0); + std::sort(sortID.begin(), sortID.end(), [this](int a, int b) { return mSeeds[a].tBracket.getMin() < mSeeds[b].tBracket.getMin(); }); + + for (int i = 0; i < ntr; i++) { + for (int j = i + 1; j < ntr; j++) { + if (checkPair(sortID[i], sortID[j]) == RejTime) { + break; + } + } + } + + selectWinners(); + refitWinners(data); + + mTFCount++; +} + +//________________________________________________________ +void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data) +{ + LOG(INFO) << "Refitting " << mWinners.size() << " winner matches"; + int count = 0; + auto tpcTBinMUSInv = 1. / mTPCTBinMUS; + if (!mTPCTransform) { // eventually, should be updated at every TF? + mTPCTransform = o2::tpc::TPCFastTransformHelperO2::instance()->create(0); + } + const auto& tpcClusRefs = data.getTPCTracksClusterRefs(); + const auto& tpcClusShMap = data.clusterShMapTPC; + std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter; + if (data.inputsTPCclusters) { + tpcRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&data.inputsTPCclusters->clusterIndex, + mTPCTransform.get(), mBz, + tpcClusRefs.data(), tpcClusShMap.data(), + nullptr, o2::base::Propagator::Instance()); + } + + const auto& itsClusters = prepareITSClusters(data); + // RS FIXME: this is probably a temporary solution, since ITS tracking over boundaries will likely change the TrackITS format + std::vector<int> itsTracksROF; + + const auto& itsTracksROFRec = data.getITSTracksROFRecords(); + itsTracksROF.resize(data.getITSTracks().size()); + for (unsigned irf = 0, cnt = 0; irf < itsTracksROFRec.size(); irf++) { + int ntr = itsTracksROFRec[irf].getNEntries(); + for (int itr = 0; itr < ntr; itr++) { + itsTracksROF[cnt++] = irf; + } + } + + auto refitITSTrack = [this, &data, &itsTracksROF, &itsClusters](o2::track::TrackParCov& trFit, GTrackID gidx, float& chi2, bool inward = false) { + const auto& itsTrOrig = data.getITSTrack(gidx); + int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()]; + const auto& itsTrackClusRefs = data.getITSTracksClusterRefs(); + int clEntry = itsTrOrig.getFirstClusterEntry(); + const auto propagator = o2::base::Propagator::Instance(); + const auto geomITS = o2::its::GeometryTGeo::Instance(); + int from = ncl - 1, to = -1, step = -1; + if (inward) { + from = 0; + to = ncl; + step = 1; + } + for (int icl = from; icl != to; icl += step) { // ITS clusters are referred in layer decreasing order + const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]]; + float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()), x = clus.getX(); + if (!trFit.rotate(alpha) || !propagator->propagateToX(trFit, x, propagator->getNominalBz(), this->mMatchParams->maxSnp, this->mMatchParams->maxStep, this->mMatchParams->matCorr)) { + break; + } + chi2 += trFit.getPredictedChi2(clus); + if (!trFit.update(clus)) { + break; + } + nclRefit++; + } + return nclRefit == ncl ? ncl : -1; + }; + + for (auto winRID : mWinners) { + const auto& rec = mRecords[winRID]; + int poolEntryID[2] = {rec.id0, rec.id1}; + const o2::track::TrackParCov outerLegs[2] = {data.getTrackParamOut(mSeeds[rec.id0].origID), data.getTrackParamOut(mSeeds[rec.id1].origID)}; + auto tOverlap = mSeeds[rec.id0].tBracket.getOverlap(mSeeds[rec.id1].tBracket); + float t0 = tOverlap.mean(), dt = tOverlap.delta() * 0.5; + auto pnt0 = outerLegs[0].getXYZGlo(), pnt1 = outerLegs[1].getXYZGlo(); + int btm = 0, top = 1; + // we fit topward from bottom + if (pnt0.Y() > pnt1.Y()) { + btm = 1; + top = 0; + } + LOG(DEBUG) << "Winner " << count++ << " Record " << winRID << " Partners:" + << " B: " << mSeeds[poolEntryID[btm]].origID << "/" << mSeeds[poolEntryID[btm]].origID.getSourceName() + << " U: " << mSeeds[poolEntryID[top]].origID << "/" << mSeeds[poolEntryID[top]].origID.getSourceName() + << " | T:" << tOverlap.asString(); + + float chi2 = 0; + int nclTot = 0; + + // Start from bottom leg inward refit + o2::track::TrackParCov trCosm(mSeeds[poolEntryID[btm]]); // copy of the btm track + // The bottom leg needs refit only if it is an unconstrained TPC track, otherwise it is already refitted as inner param + if (mSeeds[poolEntryID[btm]].origID.getSource() == GTrackID::TPC) { + const auto& tpcTrOrig = data.getTPCTrack(mSeeds[poolEntryID[btm]].origID); + trCosm = outerLegs[btm]; + int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, false, true); // inward refit, reset + if (retVal < 0) { // refit failed + LOG(DEBUG) << "Inward refit of btm TPC track failed."; + continue; + } + nclTot += retVal; + LOG(DEBUG) << "chi2 after btm TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2(); + } else { // just collect NClusters and chi2 + auto gidxListBtm = data.getSingleDetectorRefs(mSeeds[poolEntryID[btm]].origID); + if (gidxListBtm[GTrackID::TPC].isIndexSet()) { + const auto& tpcTrOrig = data.getTPCTrack(gidxListBtm[GTrackID::TPC]); + nclTot += tpcTrOrig.getNClusters(); + chi2 += tpcTrOrig.getChi2(); + } + if (gidxListBtm[GTrackID::ITS].isIndexSet()) { + const auto& itsTrOrig = data.getITSTrack(gidxListBtm[GTrackID::ITS]); + nclTot += itsTrOrig.getNClusters(); + chi2 += itsTrOrig.getChi2(); + } + } + trCosm.invert(); + if (!trCosm.rotate(mSeeds[poolEntryID[top]].getAlpha()) || + !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, mSeeds[poolEntryID[top]].getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) { + LOG(DEBUG) << "Rotation/propagation of btm-track to top-track frame failed."; + continue; + } + // save bottom parameter at merging point + auto trCosmBtm = trCosm; + int nclBtm = nclTot; + + // Continue with top leg outward refit + auto gidxListTop = data.getSingleDetectorRefs(mSeeds[poolEntryID[top]].origID); + + // is there ITS sub-track? + if (gidxListTop[GTrackID::ITS].isIndexSet()) { + auto nclfit = refitITSTrack(trCosm, gidxListTop[GTrackID::ITS], chi2, false); + if (nclfit < 0) { + continue; + } + LOG(DEBUG) << "chi2 after top ITS refit with " << nclfit << " clusters : " << chi2 << " orig.chi2 was " << data.getITSTrack(gidxListTop[GTrackID::ITS]).getChi2(); + nclTot += nclfit; + } // ITS refit + // + if (gidxListTop[GTrackID::TPC].isIndexSet()) { // outward refit in TPC + // go to TPC boundary, if needed + if (trCosm.getX() * trCosm.getX() + trCosm.getY() * trCosm.getY() <= o2::constants::geom::XTPCInnerRef * o2::constants::geom::XTPCInnerRef) { + float xtogo = 0; + if (!trCosm.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) || + !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, xtogo, mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) { + LOG(DEBUG) << "Propagation to inner TPC boundary X=" << xtogo << " failed"; + continue; + } + } + const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]); + int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, true, false); // outward refit, no reset + if (retVal < 0) { // refit failed + LOG(DEBUG) << "Outward refit of top TPC track failed."; + continue; + } // outward refit in TPC + LOG(DEBUG) << "chi2 after top TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2(); + nclTot += retVal; + } + + // inward refit of top leg for evaluation in DCA + float chi2Dummy = 0; + auto trCosmTop = outerLegs[top]; + if (gidxListTop[GTrackID::TPC].isIndexSet()) { // inward refit in TPC + const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]); + int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2Dummy, false, true); // inward refit, reset + if (retVal < 0) { // refit failed + LOG(DEBUG) << "Outward refit of top TPC track failed."; + continue; + } // inward refit in TPC + } + // is there ITS sub-track ? + if (gidxListTop[GTrackID::ITS].isIndexSet()) { + auto nclfit = refitITSTrack(trCosmTop, gidxListTop[GTrackID::ITS], chi2Dummy, true); + if (nclfit < 0) { + continue; + } + nclTot += nclfit; + } // ITS refit + // propagate to bottom param + if (!trCosmTop.rotate(trCosmBtm.getAlpha()) || + !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosmTop, trCosmBtm.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) { + LOG(DEBUG) << "Rotation/propagation of top-track to bottom-track frame failed."; + continue; + } + // calculate weighted average of 2 legs and chi2 + o2::track::TrackParCov::MatrixDSym5 cov5; + float chi2Match = trCosmBtm.getPredictedChi2(trCosmTop, cov5); + if (!trCosmBtm.update(trCosmTop, cov5)) { + LOG(DEBUG) << "Top/Bottom update failed"; + continue; + } + // create final track + mCosmicTracks.emplace_back(mSeeds[poolEntryID[btm]].origID, mSeeds[poolEntryID[top]].origID, trCosmBtm, trCosmTop, chi2, chi2Match, nclTot, t0, dt); + if (mUseMC) { + o2::MCCompLabel lbl[2] = {data.getTrackMCLabel(mSeeds[poolEntryID[btm]].origID), data.getTrackMCLabel(mSeeds[poolEntryID[top]].origID)}; + auto& tlb = mCosmicTracksLbl.emplace_back((nclBtm > nclTot - nclBtm ? lbl[0] : lbl[1])); + tlb.setFakeFlag(lbl[0] != lbl[1]); + } + } + LOG(INFO) << "Validated " << mCosmicTracks.size() << " top-bottom tracks in TF# " << mTFCount; +} + +//________________________________________________________ +void MatchCosmics::selectWinners() +{ + // select mutually best matches + int ntr = mSeeds.size(), iter = 0, nValidated = 0; + mWinners.reserve(mRecords.size() / 2); // there are 2 records per match candidate + do { + nValidated = 0; + int nRemaining = 0; + for (int i = 0; i < ntr; i++) { + if (mSeeds[i].matchID < 0 || mRecords[mSeeds[i].matchID].next == Validated) { // either have no match or already validated + continue; + } + nRemaining++; + if (validateMatch(i)) { + mWinners.push_back(mSeeds[i].matchID); + nValidated++; + continue; + } + } + LOGF(INFO, "iter %d Validated %d of %d remaining matches", iter, nValidated, nRemaining); + iter++; + } while (nValidated); +} + +//________________________________________________________ +bool MatchCosmics::validateMatch(int partner0) +{ + // make sure that the best partner of seed_i has also seed_i as a best partner + auto& matchRec = mRecords[mSeeds[partner0].matchID]; + auto partner1 = matchRec.id1; + auto& patnerRec = mRecords[mSeeds[partner1].matchID]; + if (patnerRec.next == Validated) { // partner1 was already validated with other partner0 + return false; + } + if (patnerRec.id1 == partner0) { // mutually best + // unlink winner partner0 from all other mathes + auto next0 = matchRec.next; + while (next0 > MinusOne) { + auto& nextRec = mRecords[next0]; + suppressMatch(partner0, nextRec.id1); + next0 = nextRec.next; + } + matchRec.next = Validated; + + // unlink winner partner1 from all other matches + auto next1 = patnerRec.next; + while (next1 > MinusOne) { + auto& nextRec = mRecords[next1]; + suppressMatch(partner1, nextRec.id1); + next1 = nextRec.next; + } + patnerRec.next = Validated; + return true; + } + return false; +} + +//________________________________________________________ +void MatchCosmics::suppressMatch(int partner0, int partner1) +{ + // suppress reference to partner0 from partner1 match record + if (mSeeds[partner1].matchID < 0 || mRecords[mSeeds[partner1].matchID].next == Validated) { + LOG(WARNING) << "Attempt to remove null or validated partner match " << mSeeds[partner1].matchID; + return; + } + int topID = MinusOne, next = mSeeds[partner1].matchID; + while (next > MinusOne) { + auto& matchRec = mRecords[next]; + if (matchRec.id1 == partner0) { + if (topID < 0) { // best match + mSeeds[partner1].matchID = matchRec.next; // exclude best match link + } else { // not the 1st link in the chain + mRecords[topID].next = matchRec.next; + } + return; + } + topID = next; + next = matchRec.next; + } +} + +//________________________________________________________ +MatchCosmics::RejFlag MatchCosmics::checkPair(int i, int j) +{ + // if validated with given chi2, register match + RejFlag rej = RejOther; + auto& seed0 = mSeeds[i]; + auto& seed1 = mSeeds[j]; + if (seed0.matchID == Reject) { + return rej; + } + if (seed1.matchID == Reject) { + return rej; + } + + LOG(DEBUG) << "Seed " << i << " [" << seed0.tBracket.getMin() << " : " << seed0.tBracket.getMax() << "] | " + << "Seed " << j << " [" << seed1.tBracket.getMin() << " : " << seed1.tBracket.getMax() << "] | "; + LOG(DEBUG) << seed0.origID << " | " << seed0.o2::track::TrackPar::asString(); + LOG(DEBUG) << seed1.origID << " | " << seed1.o2::track::TrackPar::asString(); + + if (seed1.tBracket > seed0.tBracket) { + return (rej = RejTime); // since the brackets are sorted in tmin, all following tbj will also exceed tbi + } + float chi2 = 1.e9f; + + // check + // 1) crude check on tgl and q/pt (if B!=0). Note: back-to-back tracks will have mutually params (see TrackPar::invertParam) + while (1) { + auto dTgl = seed0.getTgl() + seed1.getTgl(); + if (dTgl * dTgl > (mMatchParams->systSigma2[o2::track::kTgl] + seed0.getSigmaTgl2() + seed1.getSigmaTgl2()) * mMatchParams->crudeNSigma2Cut[o2::track::kTgl]) { + rej = RejTgl; + break; + } + if (mFieldON) { + auto dQ2Pt = seed0.getQ2Pt() + seed1.getQ2Pt(); + if (dQ2Pt * dQ2Pt > (mMatchParams->systSigma2[o2::track::kQ2Pt] + seed0.getSigma1Pt2() + seed1.getSigma1Pt2()) * mMatchParams->crudeNSigma2Cut[o2::track::kQ2Pt]) { + rej = RejQ2Pt; + break; + } + } + o2::track::TrackParCov seed1Inv = seed1; + seed1Inv.invert(); + for (int i = 0; i < o2::track::kNParams; i++) { // add systematic error + seed1Inv.updateCov(mMatchParams->systSigma2[i], o2::track::DiagMap[i]); + } + + if (!seed1Inv.rotate(seed0.getAlpha()) || + !o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1Inv, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) { + rej = RejProp; + break; + } + auto dSnp = seed0.getSnp() - seed1Inv.getSnp(); + if (dSnp * dSnp > (seed0.getSigmaSnp2() + seed1Inv.getSigmaSnp2()) * mMatchParams->crudeNSigma2Cut[o2::track::kSnp]) { + rej = RejSnp; + break; + } + auto dY = seed0.getY() - seed1Inv.getY(); + if (dY * dY > (seed0.getSigmaY2() + seed1Inv.getSigmaY2()) * mMatchParams->crudeNSigma2Cut[o2::track::kY]) { + rej = RejY; + break; + } + bool ignoreZ = seed0.origID.getSource() == o2d::GlobalTrackID::TPC || seed1.origID.getSource() == o2d::GlobalTrackID::TPC; + if (!ignoreZ) { // cut on Z makes no sense for TPC only tracks + auto dZ = seed0.getZ() - seed1Inv.getZ(); + if (dZ * dZ > (seed0.getSigmaZ2() + seed1Inv.getSigmaZ2()) * mMatchParams->crudeNSigma2Cut[o2::track::kZ]) { + rej = RejZ; + break; + } + } else { // inflate Z error + seed1Inv.setCov(250. * 250., o2::track::DiagMap[o2::track::kZ]); + seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kY]); // set all correlation terms for Z error to 0 + seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kSnp]); + seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kTgl]); + seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kQ2Pt]); + } + // calculate chi2 (expensive) + chi2 = seed0.getPredictedChi2(seed1Inv); + if (chi2 > mMatchParams->crudeChi2Cut) { + rej = RejChi2; + break; + } + rej = Accept; + registerMatch(i, j, chi2); + registerMatch(j, i, chi2); // the reverse reference can be also done in a separate loop + LOG(DEBUG) << "Chi2 = " << chi2 << " NMatches " << mRecords.size(); + break; + } + +#ifdef _ALLOW_DEBUG_TREES_ + if (mDBGOut && ((rej == Accept && isDebugFlag(MatchTreeAccOnly)) || isDebugFlag(MatchTreeAll))) { + auto seed1I = seed1; + seed1I.invert(); + if (seed1I.rotate(seed0.getAlpha()) && o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1I, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) { + int rejI = int(rej); + (*mDBGOut) << "match" + << "tf=" << mTFCount << "seed0=" << seed0 << "seed1=" << seed1I << "chi2Match=" << chi2 << "rej=" << rejI << "\n"; + } + } +#endif + + return rej; +} + +//________________________________________________________ +void MatchCosmics::registerMatch(int i, int j, float chi2) +{ + /// register track index j as a match for track index i + int newRef = mRecords.size(); + auto& matchRec = mRecords.emplace_back(MatchRecord{i, j, chi2, MinusOne}); + auto* best = &mSeeds[i].matchID; + while (*best > MinusOne) { + auto& oldMatchRec = mRecords[*best]; + if (oldMatchRec.chi2 > chi2) { // insert new match in front of the old one + matchRec.next = *best; // new record will refer to the one it is superseding + *best = newRef; // the reference on the superseded record should now refer to new one + break; + } + best = &oldMatchRec.next; + } + if (matchRec.next == MinusOne) { // did not supersed any other record + *best = newRef; + } +} + +//________________________________________________________ +void MatchCosmics::createSeeds(const o2::globaltracking::RecoContainer& data) +{ + // Scan all inputs and create seeding tracks + + mSeeds.clear(); + + auto creator = [this](auto& _tr, GTrackID _origID, float t0, float terr) { + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) { + if (std::abs(_tr.getQ2Pt()) > this->mQ2PtCutoff) { + return true; + } + if constexpr (isTPCTrack<decltype(_tr)>()) { + // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins + t0 *= this->mTPCTBinMUS; + terr *= this->mTPCTBinMUS; + } else if (isITSTrack<decltype(_tr)>()) { + t0 += 0.5 * this->mITSROFrameLengthMUS; // time 0 is supplied as beginning of ROF in \mus + terr *= this->mITSROFrameLengthMUS; // error is supplied a half-ROF duration, convert to \mus + } else { // all other tracks are provided with time and its gaussian error in \mus + terr *= this->mMatchParams->nSigmaTError; + } + terr += this->mMatchParams->timeToleranceMUS; + mSeeds.emplace_back(TrackSeed{_tr, {t0 - terr, t0 + terr}, _origID, MinusOne}); + return true; + } else { + return false; + } + }; + + data.createTracksVariadic(creator); + + LOG(INFO) << "collected " << mSeeds.size() << " seeds"; +} + +//________________________________________________________ +void MatchCosmics::updateTimeDependentParams() +{ + ///< update parameters depending on time (once per TF) + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds + mBz = o2::base::Propagator::Instance()->getNominalBz(); + mFieldON = std::abs(mBz) > 0.01; + mQ2PtCutoff = 1.f / std::max(0.05f, mMatchParams->minSeedPt); + if (mFieldON) { + mQ2PtCutoff *= 5.00668 / std::abs(mBz); + } else { + mQ2PtCutoff = 1e9; + } +} + +//________________________________________________________ +void MatchCosmics::init() +{ + mMatchParams = &o2::globaltracking::MatchCosmicsParams::Instance(); + +#ifdef _ALLOW_DEBUG_TREES_COSM + // debug streamer + if (mDBGFlags) { + mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(), "recreate"); + } +#endif +} + +//________________________________________________________ +std::vector<o2::BaseCluster<float>> MatchCosmics::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const +{ + std::vector<o2::BaseCluster<float>> itscl; + const auto& clusITS = data.getITSClusters(); + if (clusITS.size()) { + const auto& patterns = data.getITSClustersPatterns(); + itscl.reserve(clusITS.size()); + auto pattIt = patterns.begin(); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itscl, *mITSDict); + } + return std::move(itscl); +} + +//______________________________________________ +void MatchCosmics::end() +{ +#ifdef _ALLOW_DEBUG_TREES_COSM + mDBGOut.reset(); +#endif +} + +#ifdef _ALLOW_DEBUG_TREES_ +//______________________________________________ +void MatchCosmics::setDebugFlag(UInt_t flag, bool on) +{ + ///< set debug stream flag + if (on) { + mDBGFlags |= flag; + } else { + mDBGFlags &= ~flag; + } +} + +#endif diff --git a/Detectors/GlobalTracking/src/MatchCosmicsParams.cxx b/Detectors/GlobalTracking/src/MatchCosmicsParams.cxx new file mode 100644 index 0000000000000..f14ae04897c68 --- /dev/null +++ b/Detectors/GlobalTracking/src/MatchCosmicsParams.cxx @@ -0,0 +1,17 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MatchCosmicsParams.h +/// \brief Configurable params for cosmics matching +/// \author ruben.shahoyan@cern.ch + +#include "GlobalTracking/MatchCosmicsParams.h" +O2ParamImpl(o2::globaltracking::MatchCosmicsParams); diff --git a/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx b/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx new file mode 100644 index 0000000000000..b871c9c0d510d --- /dev/null +++ b/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx @@ -0,0 +1,743 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GlobalTracking/MatchGlobalFwd.h" + +using namespace o2::globaltracking; + +//_________________________________________________________ +void MatchGlobalFwd::init(std::string matchFcn, std::string cutFcn) +{ + + configMatching(matchFcn, cutFcn); + o2::base::GeometryManager::loadGeometry(); +} + +//_________________________________________________________ +void MatchGlobalFwd::run(const o2::globaltracking::RecoContainer& inp) +{ + mRecoCont = &inp; + mStartIR = inp.startIR; + + clear(); + + if (!prepareMFTData() || !prepareMCHData()) { + return; + } + + doMatching(); + fitTracks(); + finalize(); +} + +//_________________________________________________________ +void MatchGlobalFwd::configMatching(const std::string& matchingFcn, const std::string& cutFcn) +{ + + if (matchingFcn.find("matchALL") < matchingFcn.length()) { + LOG(INFO) << " Setting MatchingFunction matchALL: " << matchingFcn; + setMatchingFunction(&MatchGlobalFwd::matchMFT_MCH_TracksAllParam); + } else if (matchingFcn.find("matchPhiTanlXY") < matchingFcn.length()) { + LOG(INFO) << " Setting MatchingFunction matchPhiTanlXY: " << matchingFcn; + setMatchingFunction(&MatchGlobalFwd::matchMFT_MCH_TracksXYPhiTanl); + } else if (matchingFcn.find("matchXY") < matchingFcn.length()) { + LOG(INFO) << " Setting MatchingFunction matchXY: " << matchingFcn; + setMatchingFunction(&MatchGlobalFwd::matchMFT_MCH_TracksXY); + } else if (matchingFcn.find("matchHiroshima") < matchingFcn.length()) { + LOG(INFO) << " Setting MatchingFunction Hiroshima: " << matchingFcn; + setMatchingFunction(&MatchGlobalFwd::matchHiroshima); + } else { + throw std::invalid_argument("Invalid matching function! Aborting..."); + } + + if (cutFcn.find("cutDisabled") < cutFcn.length()) { + LOG(INFO) << " Setting CutFunction: " << cutFcn; + setCutFunction(&MatchGlobalFwd::cutDisabled); + } else { + throw std::invalid_argument("Invalid cut function! Aborting..."); + } +} + +//_________________________________________________________ +void MatchGlobalFwd::finalize() +{ + LOG(INFO) << " Finalizing GlobalForwardMatch. Pushing " << mMatchedTracks.size() << " matched tracks"; +} + +//_________________________________________________________ +void MatchGlobalFwd::clear() +{ + mMCHROFTimes.clear(); + mMCHWork.clear(); + mMFTROFTimes.clear(); + mMFTWork.clear(); + mMFTClusters.clear(); + mMatchedTracks.clear(); + mMatchLabels.clear(); +} + +//_________________________________________________________ +bool MatchGlobalFwd::prepareMCHData() +{ + const auto& inp = *mRecoCont; + + // Load MCH tracks + mMCHTracks = inp.getMCHTracks(); + mMCHTrackROFRec = inp.getMCHTracksROFRecords(); + if (mMCTruthON) { + mMCHTrkLabels = inp.getMCHTracksMCLabels(); + } + int nROFs = mMCHTrackROFRec.size(); + LOG(INFO) << "Loaded " << mMCHTracks.size() << " MCH Tracks " + << " in " << nROFs << " ROFs"; + + mMCHWork.reserve(mMCHTracks.size()); + + for (int irof = 0; irof < nROFs; irof++) { + const auto& rofRec = mMCHTrackROFRec[irof]; + + int nBC = rofRec.getBCData().differenceInBC(mStartIR); + float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS; + float tMax = (nBC + rofRec.getBCWidth()) * o2::constants::lhc::LHCBunchSpacingMUS; + + mMCHROFTimes.emplace_back(tMin, tMax); // MCH ROF min/max time + LOG(DEBUG) << "MCH ROF # " << irof << " [tMin;tMax] = [" << tMin << ";" << tMax << "]"; + int trlim = rofRec.getFirstIdx() + rofRec.getNEntries(); + for (int it = rofRec.getFirstIdx(); it < trlim; it++) { + auto& trcOrig = mMCHTracks[it]; + int nWorkTracks = mMCHWork.size(); + // working copy MCH track propagated to matching plane and converted to the forward track format + o2::mch::TrackParam tempParam(trcOrig.getZ(), trcOrig.getParameters(), trcOrig.getCovariances()); + if (!o2::mch::TrackExtrap::extrapToVertexWithoutBranson(tempParam, mMatchingPlaneZ)) { + LOG(WARNING) << "MCH track propagation to matching plane failed!"; + continue; + } + auto convertedTrack = MCHtoFwd(tempParam); + auto& thisMCHTrack = mMCHWork.emplace_back(TrackLocMCH{convertedTrack, {tMin, tMax}}); + thisMCHTrack.setMCHTrackID(it); + } + } + + return true; +} + +//_________________________________________________________ +bool MatchGlobalFwd::prepareMFTData() +{ + const auto& inp = *mRecoCont; + + // MFT clusters + mMFTClusterROFRec = inp.getMFTClustersROFRecords(); + mMFTTrackClusIdx = inp.getMFTTracksClusterRefs(); + const auto clusMFT = inp.getMFTClusters(); + if (mMFTClusterROFRec.empty() || clusMFT.empty()) { + LOG(INFO) << "No MFT clusters"; + return false; + } + const auto patterns = inp.getMFTClustersPatterns(); + auto pattIt = patterns.begin(); + mMFTClusters.reserve(clusMFT.size()); + o2::mft::ioutils::convertCompactClusters(clusMFT, pattIt, mMFTClusters, *mMFTDict); + + // Load MFT tracks + mMFTTracks = inp.getMFTTracks(); + + mMFTTrackROFRec = inp.getMFTTracksROFRecords(); + if (mMCTruthON) { + mMFTTrkLabels = inp.getMFTTracksMCLabels(); + } + int nROFs = mMFTTrackROFRec.size(); + LOG(INFO) << "Loaded " << mMFTTracks.size() << " MFT Tracks in " << nROFs << " ROFs"; + + mMFTWork.reserve(mMFTTracks.size()); + + for (int irof = 0; irof < nROFs; irof++) { + const auto& rofRec = mMFTTrackROFRec[irof]; + + int nBC = rofRec.getBCData().differenceInBC(mStartIR); + float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS; + float tMax = (nBC + mMFTROFrameLengthInBC) * o2::constants::lhc::LHCBunchSpacingMUS; + if (!mMFTTriggered) { + auto irofCont = nBC / mMFTROFrameLengthInBC; + if (mMFTTrackROFContMapping.size() <= irofCont) { // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones + mMFTTrackROFContMapping.resize((1 + irofCont / 128) * 128, 0); + } + mMFTTrackROFContMapping[irofCont] = irof; + } + mMFTROFTimes.emplace_back(tMin, tMax); // MFT ROF min/max time + LOG(DEBUG) << "MFT ROF # " << irof << " [tMin;tMax] = [" << tMin << ";" << tMax << "]"; + + int trlim = rofRec.getFirstEntry() + rofRec.getNEntries(); + for (int it = rofRec.getFirstEntry(); it < trlim; it++) { + const auto& trcOrig = mMFTTracks[it]; + + int nWorkTracks = mMFTWork.size(); + // working copy of outer track param + auto& trc = mMFTWork.emplace_back(TrackLocMFT{trcOrig.getOutParam(), {tMin, tMax}, irof}); + trc.propagateToZ(mMatchingPlaneZ, mBz); + } + } + + return true; +} + +//_________________________________________________________ +void MatchGlobalFwd::doMatching() +{ + // Range of compatible MCH ROFS for the first MFT track + int nMCHROFs = mMCHROFTimes.size(); + + LOG(INFO) << "Running MCH-MFT Track Matching."; + // ROFrame of first MFT track + auto firstMFTTrackIdInROF = 0; + auto MFTROFId = mMFTWork.front().roFrame; + while ((firstMFTTrackIdInROF < mMFTTracks.size()) && (MFTROFId < mMFTTrackROFRec.size())) { + auto MFTROFId = mMFTWork[firstMFTTrackIdInROF].roFrame; + const auto& thisMFTBracket = mMFTROFTimes[MFTROFId]; + auto nMFTTracksInROF = mMFTTrackROFRec[MFTROFId].getNEntries(); + firstMFTTrackIdInROF = mMFTTrackROFRec[MFTROFId].getFirstEntry(); + LOG(DEBUG) << "MFT ROF = " << MFTROFId << "; interval: [" << thisMFTBracket.getMin() << "," << thisMFTBracket.getMax() << "]"; + LOG(DEBUG) << "ROF " << MFTROFId << " : firstMFTTrackIdInROF " << firstMFTTrackIdInROF << " ; nMFTTracksInROF = " << nMFTTracksInROF; + firstMFTTrackIdInROF += nMFTTracksInROF; + int mchROF = 0; + while (mchROF < nMCHROFs && (thisMFTBracket.isOutside(mMCHROFTimes[mchROF]))) { + // LOG(INFO) << "mchROF = " << mchROF << " ===> thisMFTBracket.isOutside(mMCHROFTimes[mchROF]) = " << thisMFTBracket.isOutside(mMCHROFTimes[mchROF]); + mchROF++; + } + int mchROFMatchFirst = -1; + int mchROFMatchLast = -1; + + //LOG(INFO) << "mchROF = " << mchROF << " ===> thisMFTBracket.isOutside(mMCHROFTimes[mchROF]) = " << thisMFTBracket.isOutside(mMCHROFTimes[mchROF]); + if (thisMFTBracket.isOutside(mMCHROFTimes[mchROF]) == 0) { + mchROFMatchFirst = mchROF; + + while (mchROF < nMCHROFs && !(thisMFTBracket < mMCHROFTimes[mchROF])) { + mchROF++; + } + mchROFMatchLast = mchROF - 1; + } else { + LOG(DEBUG) << "No compatible MCH ROF with MFT ROF " << MFTROFId << std::endl; + } + //std::cout << "First compatible MCH ROF = " << mchROFMatchFirst << " ; "; + //std::cout << "Last compatible MCH ROF = " << mchROFMatchLast << std::endl; + if (mchROFMatchFirst >= 0) { + ROFMatch(MFTROFId, mchROFMatchFirst, mchROFMatchLast); + } + } +} + +//_________________________________________________________ +void MatchGlobalFwd::ROFMatch(int MFTROFId, int firstMCHROFId, int lastMCHROFId) +{ + /// Matches MFT tracks on a given ROF with MCH tracks in a range of ROFs + const auto& thisMFTROF = mMFTTrackROFRec[MFTROFId]; + const auto& firstMCHROF = mMCHTrackROFRec[firstMCHROFId]; + const auto& lastMCHROF = mMCHTrackROFRec[lastMCHROFId]; + int nFakes = 0, nTrue = 0; + + auto firstMFTTrackID = thisMFTROF.getFirstEntry(); + auto lastMFTTrackID = firstMFTTrackID + thisMFTROF.getNEntries() - 1; + + auto firstMCHTrackID = firstMCHROF.getFirstIdx(); + auto lastMCHTrackID = lastMCHROF.getLastIdx(); + auto nMFTTracks = thisMFTROF.getNEntries(); + auto nMCHTracks = lastMCHTrackID - firstMCHTrackID + 1; + + LOG(DEBUG) << "Matching MFT ROF " << MFTROFId << " with MCH ROFs [" << firstMCHROFId << "->" << lastMCHROFId << "]"; + LOG(DEBUG) << " firstMFTTrackID = " << firstMFTTrackID << " ; lastMFTTrackID = " << lastMFTTrackID; + LOG(DEBUG) << " firstMCHTrackID = " << firstMCHTrackID << " ; lastMCHTrackID = " << lastMCHTrackID << std::endl; + + // loop over all MCH tracks + for (auto MCHid = firstMCHTrackID; MCHid <= lastMCHTrackID; MCHid++) { + auto& thisMCHTrack = mMCHWork[MCHid]; + o2::MCCompLabel matchLabel; + const o2::MCCompLabel* thisMCHLabel; + const o2::MCCompLabel* thisMFTLabel; + if (mMCTruthON) { + thisMCHLabel = &mMCHTrkLabels[MCHid]; + matchLabel = *thisMCHLabel; + } + for (auto MFTid = firstMFTTrackID; MFTid <= lastMFTTrackID; MFTid++) { + auto& thisMFTTrack = mMFTWork[MFTid]; + if (mMCTruthON) { + thisMFTLabel = &mMFTTrkLabels[MFTid]; + } + if (matchingCut(thisMCHTrack, thisMFTTrack)) { + thisMCHTrack.countCandidate(); + if (mMCTruthON && ((*thisMFTLabel) == (*thisMCHLabel))) { + thisMCHTrack.setCloseMatch(); + } + auto chi2 = matchingEval(thisMCHTrack, thisMFTTrack); + if (chi2 < thisMCHTrack.getMatchingChi2()) { + thisMCHTrack.setMFTTrackID(MFTid); + ; + thisMCHTrack.setMatchingChi2(chi2); + } + } + } + auto bestMatchID = thisMCHTrack.getMFTTrackID(); + LOG(DEBUG) << " Matching MCHid = " << MCHid << " ==> bestMatchID = " << thisMCHTrack.getMFTTrackID() << " ; thisMCHTrack.getMatchingChi2() = " << thisMCHTrack.getMatchingChi2(); + LOG(DEBUG) << " MCH COV<X,X> = " << thisMCHTrack.getSigma2X() << " ; COV<Y,Y> = " << thisMCHTrack.getSigma2Y() << " ; pt = " << thisMCHTrack.getPt(); + + if (bestMatchID >= 0) { // If there is a match, add to output container + + if (mMCTruthON) { + thisMFTLabel = &mMFTTrkLabels[bestMatchID]; + bool trueMatch = ((*thisMFTLabel) == (*thisMCHLabel)); + matchLabel.setFakeFlag(!trueMatch); + if (thisMFTLabel->isFake() || thisMCHLabel->isFake()) { + matchLabel.setFakeFlag(false); + } + LOG(DEBUG) << " MCHTruth = " << *thisMCHLabel << "; MFTTruth = " << *thisMFTLabel << " MatchTruth = " << matchLabel; + + matchLabel.isFake() ? nFakes++ : nTrue++; + } + + thisMCHTrack.setMFTTrackID(bestMatchID); + thisMCHTrack.setTimeMUS(thisMCHTrack.tBracket.getMin(), thisMCHTrack.tBracket.delta()); + std::cout << " thisMCHTrack.getMFTTrackID() = " << thisMCHTrack.getMFTTrackID() + << "; thisMCHTrack.getMatchingChi2() = " << thisMCHTrack.getMatchingChi2() + << "; Label: " << matchLabel << std::endl; + + mMatchedTracks.emplace_back((thisMCHTrack)); + + if (mMCTruthON) { + mMatchLabels.push_back(matchLabel); + } + } + + } // /loop over MCH tracks seeds + LOG(DEBUG) << " Done matching MFT ROF " << MFTROFId << " with " << nMFTTracks << " MFT tracks with " << nMCHTracks << " MCH Tracks. nFakes = " << nFakes << " nTrue = " << nTrue; +} + +//_________________________________________________________________________________________________ +void MatchGlobalFwd::fitTracks() +{ + std::cout << "Fitting global muon tracks..." << std::endl; + + auto GTrackID = 0; + + for (auto& track : mMatchedTracks) { + LOG(DEBUG) << " ==> Fitting Global Track # " << GTrackID << " with MFT track # " << track.getMFTTrackID() << ":"; + fitGlobalMuonTrack(track); + GTrackID++; + } + + std::cout << "Finished fitting global muon tracks." << std::endl; +} + +//_________________________________________________________________________________________________ +void MatchGlobalFwd::fitGlobalMuonTrack(o2::dataformats::GlobalFwdTrack& gTrack) +{ + const auto& MFTMatchId = gTrack.getMFTTrackID(); + const auto& mftTrack = mMFTTracks[MFTMatchId]; + const auto& mftTrackOut = mMFTWork[MFTMatchId]; + auto ncls = mftTrack.getNumberOfPoints(); + auto offset = mftTrack.getExternalClusterIndexOffset(); + auto invQPt0 = gTrack.getInvQPt(); + auto sigmainvQPtsq = gTrack.getCovariances()(4, 4); + + // initialize the starting track parameters and cluster + auto k = TMath::Abs(o2::constants::math::B2C * mBz); + auto Hz = std::copysign(1, mBz); + + LOG(DEBUG) << "\n ***************************** Start Fitting new track *****************************"; + LOG(DEBUG) << " N Clusters = " << ncls; + LOG(DEBUG) << " Best MFT Track Match ID " << gTrack.getMFTTrackID(); + LOG(DEBUG) << " MCHTrack: X = " << gTrack.getX() << " Y = " << gTrack.getY() + << " Z = " << gTrack.getZ() << " Tgl = " << gTrack.getTanl() + << " Phi = " << gTrack.getPhi() << " pz = " << gTrack.getPz() + << " qpt = " << 1.0 / gTrack.getInvQPt(); + + gTrack.setX(mftTrackOut.getX()); + gTrack.setY(mftTrackOut.getY()); + gTrack.setZ(mftTrackOut.getZ()); + gTrack.setPhi(mftTrackOut.getPhi()); + gTrack.setTanl(mftTrackOut.getTanl()); + gTrack.setInvQPt(gTrack.getInvQPt()); + + LOG(DEBUG) << " MFTTrack: X = " << mftTrackOut.getX() + << " Y = " << mftTrackOut.getY() << " Z = " << mftTrackOut.getZ() + << " Tgl = " << mftTrackOut.getTanl() + << " Phi = " << mftTrackOut.getPhi() << " pz = " << mftTrackOut.getPz() + << " qpt = " << 1.0 / mftTrackOut.getInvQPt(); + LOG(DEBUG) << " initTrack GlobalTrack: q/pt = " << gTrack.getInvQPt() << std::endl; + + SMatrix55Sym lastParamCov; + Double_t tanlsigma = TMath::Max(std::abs(mftTrackOut.getTanl()), .5); + Double_t qptsigma = TMath::Max(std::abs(mftTrackOut.getInvQPt()), .5); + + lastParamCov(0, 0) = 10000. * mftTrackOut.getCovariances()(0, 0); // <X,X> + lastParamCov(1, 1) = 10000. * mftTrackOut.getCovariances()(1, 1); // <Y,X> + lastParamCov(2, 2) = 10000. * mftTrackOut.getCovariances()(2, 2); // TMath::Pi() * TMath::Pi() / 16 // <PHI,X> + lastParamCov(3, 3) = 10000. * mftTrackOut.getCovariances()(3, 3); // 100. * tanlsigma * tanlsigma; // mftTrack.getCovariances()(3, 3); // <TANL,X> + lastParamCov(4, 4) = gTrack.getCovariances()(4, 4); //100. * qptsigma * qptsigma; // <INVQPT,X> + + gTrack.setCovariances(lastParamCov); + + auto lastLayer = mMFTMapping.ChipID2Layer[mMFTClusters[offset + ncls - 1].getSensorID()]; + LOG(DEBUG) << " Starting by MFTCluster offset " << offset + ncls - 1 << " at lastLayer " << lastLayer; + + for (int icls = ncls - 1; icls > -1; --icls) { + auto clsEntry = mMFTTrackClusIdx[offset + icls]; + auto& thiscluster = mMFTClusters[clsEntry]; + LOG(DEBUG) << " Computing MFTCluster clsEntry " << clsEntry << " at Z= " << thiscluster.getZ(); + + computeCluster(gTrack, thiscluster, lastLayer); + } +} + +//_________________________________________________________________________________________________ +bool MatchGlobalFwd::computeCluster(o2::dataformats::GlobalFwdTrack& track, const MFTCluster& cluster, int& startingLayerID) +{ + /// Propagate track to the z position of the new cluster + /// accounting for MCS dispersion in the current layer and the other(s) crossed + /// Recompute the parameters adding the cluster constraint with the Kalman filter + /// Returns false in case of failure + + const auto& clx = cluster.getX(); + const auto& cly = cluster.getY(); + const auto& clz = cluster.getZ(); + const auto& sigmaX2 = cluster.getSigmaY2(); // ALPIDE local Y coordinate => MFT global X coordinate (ALPIDE rows) + const auto& sigmaY2 = cluster.getSigmaZ2(); // ALPIDE local Z coordinate => MFT global Y coordinate (ALPIDE columns) + + const auto& newLayerID = mMFTMapping.ChipID2Layer[cluster.getSensorID()]; + LOG(DEBUG) << "computeCluster: X = " << clx << " Y = " << cly << " Z = " << clz << " nCluster = " << newLayerID; + + if (!propagateToNextClusterWithMCS(track, clz, startingLayerID, newLayerID)) { + return false; + } + + LOG(DEBUG) << " AfterExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt(); + LOG(DEBUG) << "Track covariances after extrap:" << std::endl + << track.getCovariances() << std::endl; + + // recompute parameters + const std::array<float, 2>& pos = {clx, cly}; + const std::array<float, 2>& cov = {sigmaX2, sigmaY2}; + + if (track.update(pos, cov)) { + LOG(DEBUG) << " New Cluster: X = " << clx << " Y = " << cly << " Z = " << clz; + LOG(DEBUG) << " AfterKalman: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt(); + + LOG(DEBUG) << "Track covariances after Kalman update: \n" + << track.getCovariances() << std::endl; + + return true; + } + return false; +} + +//_________________________________________________________________________________________________ +double MatchGlobalFwd::matchingEval(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + return (this->*mMatchFunc)(mchTrack, mftTrack); +} + +//_________________________________________________________________________________________________ +bool MatchGlobalFwd::matchingCut(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + return (this->*mCutFunc)(mchTrack, mftTrack); +} + +//_________________________________________________________ +void MatchGlobalFwd::setMFTROFrameLengthMUS(float fums) +{ + mMFTROFrameLengthMUS = fums; + mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS; + mMFTROFrameLengthInBC = std::max(1, int(mMFTROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3))); +} + +//_________________________________________________________ +void MatchGlobalFwd::setMFTROFrameLengthInBC(int nbc) +{ + mMFTROFrameLengthInBC = nbc; + mMFTROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS; +} + +//_________________________________________________________ +void MatchGlobalFwd::setBunchFilling(const o2::BunchFilling& bf) +{ + mBunchFilling = bf; + // find closest (from above) filled bunch + int minBC = bf.getFirstFilledBC(), maxBC = bf.getLastFilledBC(); + if (minBC < 0) { + throw std::runtime_error("Bunch filling is not set in MatchGlobalFwd"); + } + int bcAbove = minBC; + for (int i = o2::constants::lhc::LHCMaxBunches; i--;) { + if (bf.testBC(i)) { + bcAbove = i; + } + mClosestBunchAbove[i] = bcAbove; + } + int bcBelow = maxBC; + for (int i = 0; i < o2::constants::lhc::LHCMaxBunches; i++) { + if (bf.testBC(i)) { + bcBelow = i; + } + mClosestBunchBelow[i] = bcBelow; + } +} + +//_________________________________________________________________________________________________ +double MatchGlobalFwd::matchMFT_MCH_TracksAllParam(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + // Match two tracks evaluating all parameters: X,Y, phi, tanl & q/pt + + SMatrix55Sym I = ROOT::Math::SMatrixIdentity(), H_k, V_k; + SVector5 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(), + mftTrack.getTanl(), mftTrack.getInvQPt()), + r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + V_k(2, 2) = mftTrack.getCovariances()(2, 2); + V_k(3, 3) = mftTrack.getCovariances()(3, 3); + V_k(4, 4) = mftTrack.getCovariances()(4, 4); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + H_k(2, 2) = 1.0; + H_k(3, 3) = 1.0; + H_k(4, 4) = 1.0; + + // Covariance of residuals + SMatrix55Std invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Kalman Gain Matrix + SMatrix55Std K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov; + + // Update Parameters + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; // Residuals of prediction + + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; +} + +//_________________________________________________________________________________________________ +o2::dataformats::GlobalFwdTrack MatchGlobalFwd::MCHtoFwd(const o2::mch::TrackParam& mchParam) +{ + // Convert a MCH Track parameters and covariances matrix to the + // Forward track format. Must be called after propagation though the absorber + + o2::dataformats::GlobalFwdTrack convertedTrack; + + // Parameter conversion + double alpha1, alpha3, alpha4, x2, x3, x4; + + alpha1 = mchParam.getNonBendingSlope(); + alpha3 = mchParam.getBendingSlope(); + alpha4 = mchParam.getInverseBendingMomentum(); + + x2 = TMath::ATan2(-alpha3, -alpha1); + x3 = -1. / TMath::Sqrt(alpha3 * alpha3 + alpha1 * alpha1); + x4 = alpha4 * -x3 * TMath::Sqrt(1 + alpha3 * alpha3); + + auto K = alpha1 * alpha1 + alpha3 * alpha3; + auto K32 = K * TMath::Sqrt(K); + auto L = TMath::Sqrt(alpha3 * alpha3 + 1); + + // Covariances matrix conversion + SMatrix55Std jacobian; + SMatrix55Sym covariances; + + if (0) { + + std::cout << " MCHtoGlobal - MCH Covariances:\n"; + std::cout << " mchParam.getCovariances()(0, 0) = " + << mchParam.getCovariances()(0, 0) + << " ; mchParam.getCovariances()(2, 2) = " + << mchParam.getCovariances()(2, 2) << std::endl; + } + covariances(0, 0) = mchParam.getCovariances()(0, 0); + covariances(0, 1) = mchParam.getCovariances()(0, 1); + covariances(0, 2) = mchParam.getCovariances()(0, 2); + covariances(0, 3) = mchParam.getCovariances()(0, 3); + covariances(0, 4) = mchParam.getCovariances()(0, 4); + + covariances(1, 1) = mchParam.getCovariances()(1, 1); + covariances(1, 2) = mchParam.getCovariances()(1, 2); + covariances(1, 3) = mchParam.getCovariances()(1, 3); + covariances(1, 4) = mchParam.getCovariances()(1, 4); + + covariances(2, 2) = mchParam.getCovariances()(2, 2); + covariances(2, 3) = mchParam.getCovariances()(2, 3); + covariances(2, 4) = mchParam.getCovariances()(2, 4); + + covariances(3, 3) = mchParam.getCovariances()(3, 3); + covariances(3, 4) = mchParam.getCovariances()(3, 4); + + covariances(4, 4) = mchParam.getCovariances()(4, 4); + + jacobian(0, 0) = 1; + + jacobian(1, 2) = 1; + + jacobian(2, 1) = -alpha3 / K; + jacobian(2, 3) = alpha1 / K; + + jacobian(3, 1) = alpha1 / K32; + jacobian(3, 3) = alpha3 / K32; + + jacobian(4, 1) = -alpha1 * alpha4 * L / K32; + jacobian(4, 3) = alpha3 * alpha4 * (1 / (TMath::Sqrt(K) * L) - L / K32); + jacobian(4, 4) = L / TMath::Sqrt(K); + + // jacobian*covariances*jacobian^T + covariances = ROOT::Math::Similarity(jacobian, covariances); + + // Set output + convertedTrack.setX(mchParam.getNonBendingCoor()); + convertedTrack.setY(mchParam.getBendingCoor()); + convertedTrack.setZ(mchParam.getZ()); + convertedTrack.setPhi(x2); + convertedTrack.setTanl(x3); + convertedTrack.setInvQPt(x4); + convertedTrack.setCharge(mchParam.getCharge()); + convertedTrack.setCovariances(covariances); + + return convertedTrack; +} + +//_________________________________________________________________________________________________ +double MatchGlobalFwd::matchMFT_MCH_TracksXY(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + // Calculate Matching Chi2 - X and Y positions + + SMatrix55Sym I = ROOT::Math::SMatrixIdentity(); + SMatrix25 H_k; + SMatrix22 V_k; + SVector2 m_k(mftTrack.getX(), mftTrack.getY()), r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + + // Covariance of residuals + SMatrix22 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Kalman Gain Matrix + SMatrix52 K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov; + + // Residuals of prediction + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; +} + +//_________________________________________________________________________________________________ +double MatchGlobalFwd::matchMFT_MCH_TracksXYPhiTanl(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + // Match two tracks evaluating positions & angles + + SMatrix55Sym I = ROOT::Math::SMatrixIdentity(); + SMatrix45 H_k; + SMatrix44 V_k; + SVector4 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(), + mftTrack.getTanl()), + r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + V_k(2, 2) = mftTrack.getCovariances()(2, 2); + V_k(3, 3) = mftTrack.getCovariances()(3, 3); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + H_k(2, 2) = 1.0; + H_k(3, 3) = 1.0; + + // Covariance of residuals + SMatrix44 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Kalman Gain Matrix + SMatrix54 K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov; + + // Residuals of prediction + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; + + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; +} + +//_________________________________________________________________________________________________ +double MatchGlobalFwd::matchHiroshima(const TrackLocMCH& mchTrack, const TrackLocMFT& mftTrack) +{ + + //Hiroshima's Matching function + + //Matching constants + Double_t LAbs = 415.; //Absorber Length[cm] + Double_t mumass = 0.106; //mass of muon [GeV/c^2] + Double_t l; //the length that extrapolated MCHtrack passes through absorber + + if (mMatchingPlaneZ >= -90.0) { + l = LAbs; + } else { + l = 505.0 + mMatchingPlaneZ; + } + + //defference between MFTtrack and MCHtrack + + auto dx = mftTrack.getX() - mchTrack.getX(); + auto dy = mftTrack.getY() - mchTrack.getY(); + auto dthetax = TMath::ATan(mftTrack.getPx() / TMath::Abs(mftTrack.getPz())) - TMath::ATan(mchTrack.getPx() / TMath::Abs(mchTrack.getPz())); + auto dthetay = TMath::ATan(mftTrack.getPy() / TMath::Abs(mftTrack.getPz())) - TMath::ATan(mchTrack.getPy() / TMath::Abs(mchTrack.getPz())); + + //Multiple Scattering(=MS) + + auto pMCH = mchTrack.getP(); + auto lorentzbeta = pMCH / TMath::Sqrt(mumass * mumass + pMCH * pMCH); + auto zMS = copysign(1.0, mchTrack.getCharge()); + auto thetaMS = 13.6 / (1000.0 * pMCH * lorentzbeta * 1.0) * zMS * TMath::Sqrt(60.0 * l / LAbs) * (1.0 + 0.038 * TMath::Log(60.0 * l / LAbs)); + auto xMS = thetaMS * l / TMath::Sqrt(3.0); + + //normalize by theoritical Multiple Coulomb Scattering width to be momentum-independent + //make the dx and dtheta dimensionless + + auto dxnorm = dx / xMS; + auto dynorm = dy / xMS; + auto dthetaxnorm = dthetax / thetaMS; + auto dthetaynorm = dthetay / thetaMS; + + //rotate distribution + + auto dxrot = dxnorm * TMath::Cos(TMath::Pi() / 4.0) - dthetaxnorm * TMath::Sin(TMath::Pi() / 4.0); + auto dthetaxrot = dxnorm * TMath::Sin(TMath::Pi() / 4.0) + dthetaxnorm * TMath::Cos(TMath::Pi() / 4.0); + auto dyrot = dynorm * TMath::Cos(TMath::Pi() / 4.0) - dthetaynorm * TMath::Sin(TMath::Pi() / 4.0); + auto dthetayrot = dynorm * TMath::Sin(TMath::Pi() / 4.0) + dthetaynorm * TMath::Cos(TMath::Pi() / 4.0); + + //convert ellipse to circle + + auto k = 0.7; //need to optimize!! + auto dxcircle = dxrot; + auto dycircle = dyrot; + auto dthetaxcircle = dthetaxrot / k; + auto dthetaycircle = dthetayrot / k; + + //score + + auto scoreX = TMath::Sqrt(dxcircle * dxcircle + dthetaxcircle * dthetaxcircle); + auto scoreY = TMath::Sqrt(dycircle * dycircle + dthetaycircle * dthetaycircle); + auto score = TMath::Sqrt(scoreX * scoreX + scoreY * scoreY); + + return score; +}; diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index f1b84e296de23..e8de26dc48b14 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "MathUtils/Utils.h" #include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/GeomConstants.h" #include "DetectorsBase/GeometryManager.h" #include <Math/SMatrix.h> @@ -34,263 +36,111 @@ #include "ReconstructionDataFormats/TrackLTIntegral.h" #include "GlobalTracking/MatchTOF.h" -#include "GlobalTracking/MatchTPCITS.h" #include "TPCBase/ParameterGas.h" #include "TPCBase/ParameterElectronics.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" + +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" using namespace o2::globaltracking; -using evIdx = o2::dataformats::EvIndex<int, int>; +using evGIdx = o2::dataformats::EvIndex<int, o2::dataformats::GlobalTrackID>; +using trkType = o2::dataformats::MatchInfoTOFReco::TrackType; +using Cluster = o2::tof::Cluster; +using GTrackID = o2::dataformats::GlobalTrackID; +using timeEst = o2::dataformats::TimeStampWithError<float, float>; ClassImp(MatchTOF); //______________________________________________ -void MatchTOF::run() +void MatchTOF::run(const o2::globaltracking::RecoContainer& inp) { ///< running the matching + mRecoCont = &inp; + mStartIR = inp.startIR; + updateTimeDependentParams(); - if (!mWFInputAttached && !mSAInitDone) { - LOG(ERROR) << "run called with mSAInitDone=" << mSAInitDone << " and mWFInputAttached=" << mWFInputAttached; - throw std::runtime_error("standalone init was not done or workflow input was not yet attached"); - } - mTimerTot.Start(); - - // we load all TOF clusters (to be checked if we need to split per time frame) - prepareTOFClusters(); - - mTimerTot.Stop(); - LOGF(INFO, "Timing prepareTOFCluster: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - mTimerTot.Start(); - - if (mIsworkflowON) { - LOG(DEBUG) << "Number of entries in track tree = " << mCurrTracksTreeEntry; - - if (mIsITSused) { - prepareTracks(); - } else { - prepareTPCTracks(); - } - - mMatchedTracks.clear(); - mOutTOFLabels.clear(); - mOutTPCLabels.clear(); - mOutITSLabels.clear(); + mTimerMatchTPC.Reset(); + mTimerMatchITSTPC.Reset(); + mTimerTot.Reset(); - mTimerTot.Stop(); - LOGF(INFO, "Timing prepare tracks: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - mTimerTot.Start(); - - for (int sec = o2::constants::math::NSectors; sec--;) { - LOG(INFO) << "Doing matching for sector " << sec << "..."; - if (mIsITSused) { - doMatching(sec); - } else { - doMatchingForTPC(sec); - } - LOG(INFO) << "...done. Now check the best matches"; - selectBestMatches(); - } + for (int i = 0; i < trkType::SIZEALL; i++) { + mMatchedTracks[i].clear(); + mOutTOFLabels[i].clear(); } - // we do the matching per entry of the TPCITS matched tracks tree - while (!mIsworkflowON && mCurrTracksTreeEntry + 1 < mInputTreeTracks->GetEntries()) { // we add "+1" because mCurrTracksTreeEntry starts from -1, and it is incremented in loadTracksNextChunk which is called by prepareTracks - LOG(DEBUG) << "Number of entries in track tree = " << mCurrTracksTreeEntry; - - if (mIsITSused) { - prepareTracks(); - } else { - prepareTPCTracks(); + for (int i = 0; i < trkType::SIZE; i++) { + mTracksWork[i].clear(); + mTrackGid[i].clear(); + } + for (int it = 0; it < trkType::SIZE; it++) { + mMatchedTracksIndex[it].clear(); + mLTinfos[it].clear(); + if (mMCTruthON) { + mTracksLblWork[it].clear(); } - - mMatchedTracks.clear(); - mOutTOFLabels.clear(); - mOutTPCLabels.clear(); - mOutITSLabels.clear(); - - mTimerTot.Stop(); - LOGF(INFO, "Timing prepare tracks: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - mTimerTot.Start(); - for (int sec = o2::constants::math::NSectors; sec--;) { - LOG(INFO) << "Doing matching for sector " << sec << "..."; - if (mIsITSused) { - doMatching(sec); - } else { - doMatchingForTPC(sec); - } - LOG(INFO) << "...done. Now check the best matches"; - selectBestMatches(); + mTracksSectIndexCache[it][sec].clear(); } - - mTimerTot.Stop(); - LOGF(INFO, "Timing Do Matching: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - mTimerTot.Start(); - - fill(); } -#ifdef _ALLOW_TOF_DEBUG_ - if (mDBGFlags) - mDBGOut.reset(); -#endif - - mWFInputAttached = false; + mSideTPC.clear(); + mExtraTPCFwdTime.clear(); + mTimerTot.Start(); + bool isPrepareTOFClusters = prepareTOFClusters(); mTimerTot.Stop(); - LOGF(INFO, "Timing Do Matching: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); -} - -//______________________________________________ -void MatchTOF::fill() -{ - mOutputTree->Fill(); - if (mOutputTreeCalib) { - mOutputTreeCalib->Fill(); - } -} - -//______________________________________________ -void MatchTOF::run(const gsl::span<const o2::dataformats::TrackTPCITS>& trackArray, const gsl::span<const Cluster>& clusterArray, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>& toflab, const gsl::span<const o2::MCCompLabel>& itslab, const gsl::span<const o2::MCCompLabel>& tpclab) -{ - mIsITSused = true; - mTracksArrayInp = trackArray; - mTOFClustersArrayInp = clusterArray; - mIsworkflowON = kTRUE; - mTOFClusLabels = toflab; - mTPCLabels = tpclab; - mITSLabels = itslab; - - mMCTruthON = (mTOFClusLabels.getNElements() && mTPCLabels.size() && mITSLabels.size()); - mWFInputAttached = true; - mSAInitDone = true; - run(); -} -//______________________________________________ -void MatchTOF::run(const gsl::span<const o2::tpc::TrackTPC>& trackArray, const gsl::span<const Cluster>& clusterArray, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>& toflab, const gsl::span<const o2::MCCompLabel>& tpclab) -{ - mIsITSused = false; - mTPCTracksArrayInp = trackArray; - mTOFClustersArrayInp = clusterArray; - mIsworkflowON = kTRUE; - mTOFClusLabels = toflab; - mTPCLabels = tpclab; - - mMCTruthON = (mTOFClusLabels.getNElements() && mTPCLabels.size()); - mWFInputAttached = true; - mSAInitDone = true; - - run(); -} -//______________________________________________ -void MatchTOF::init() -{ - ///< initizalizations - mIsITSused = true; + LOGF(INFO, "Timing prepareTOFCluster: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - if (mSAInitDone) { - LOG(ERROR) << "Initialization was already done"; + if (!isPrepareTOFClusters) { // check cluster before of tracks to see also if MC is required return; } - attachInputTrees(); - // create output branch with track-tof matching - if (mOutputTree) { - mOutputTree->Branch(mOutTracksBranchName.data(), &mMatchedTracks); - LOG(INFO) << "Matched tracks will be stored in " << mOutTracksBranchName << " branch of tree " - << mOutputTree->GetName(); - if (mMCTruthON) { - mOutputTree->Branch(mOutITSMCTruthBranchName.data(), &mOutITSLabels); - LOG(INFO) << "ITS Tracks Labels branch: " << mOutITSMCTruthBranchName; - mOutputTree->Branch(mOutTPCMCTruthBranchName.data(), &mOutTPCLabels); - LOG(INFO) << "TPC Tracks Labels branch: " << mOutTPCMCTruthBranchName; - mOutputTree->Branch(mOutTOFMCTruthBranchName.data(), &mOutTOFLabels); - LOG(INFO) << "TOF Tracks Labels branch: " << mOutTOFMCTruthBranchName; - } - - } else { - LOG(INFO) << "Output tree is not attached, matched tracks will not be stored"; - } - - // create output branch for calibration info - if (mOutputTreeCalib) { - mOutputTreeCalib->Branch(mOutCalibBranchName.data(), &mCalibInfoTOF); - LOG(INFO) << "Calib infos will be stored in " << mOutCalibBranchName << " branch of tree " - << mOutputTreeCalib->GetName(); - } else { - LOG(INFO) << "Calib Output tree is not attached, calib infos will not be stored"; - } - -#ifdef _ALLOW_TOF_DEBUG_ - // debug streamer - if (mDBGFlags) { - mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(), "recreate"); - } -#endif - - mSAInitDone = true; - - { - mTimerTot.Stop(); - mTimerTot.Reset(); + mTimerTot.Start(); + if (!prepareTPCData()) { + return; } + mTimerTot.Stop(); + LOGF(INFO, "Timing prepare TPC tracks: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - print(); -} -//______________________________________________ -void MatchTOF::initTPConly() -{ - ///< initizalizations - - mIsITSused = false; - - if (mSAInitDone) { - LOG(ERROR) << "Initialization was already done"; + mTimerTot.Start(); + if (!prepareFITData()) { return; } - attachInputTreesTPConly(); + mTimerTot.Stop(); + LOGF(INFO, "Timing prepare FIT data: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); - // create output branch with track-tof matching - if (mOutputTree) { - mOutputTree->Branch(mOutTracksBranchName.data(), &mMatchedTracks); - LOG(INFO) << "Matched tracks will be stored in " << mOutTracksBranchName << " branch of tree " - << mOutputTree->GetName(); - if (mMCTruthON) { - mOutputTree->Branch(mOutTPCMCTruthBranchName.data(), &mOutTPCLabels); - LOG(INFO) << "TPC Tracks Labels branch: " << mOutTPCMCTruthBranchName; - mOutputTree->Branch(mOutTOFMCTruthBranchName.data(), &mOutTOFLabels); - LOG(INFO) << "TOF Tracks Labels branch: " << mOutTOFMCTruthBranchName; + mTimerTot.Start(); + for (int sec = o2::constants::math::NSectors; sec--;) { + mMatchedTracksPairs.clear(); // new sector + LOG(INFO) << "Doing matching for sector " << sec << "..."; + if (mIsITSTPCused || mIsTPCTRDused || mIsITSTPCTRDused) { + mTimerMatchITSTPC.Start(sec == o2::constants::math::NSectors - 1); + doMatching(sec); + mTimerMatchITSTPC.Stop(); } - - } else { - LOG(INFO) << "Output tree is not attached, matched tracks will not be stored"; - } - - // create output branch for calibration info - if (mOutputTreeCalib) { - mOutputTreeCalib->Branch(mOutCalibBranchName.data(), &mCalibInfoTOF); - LOG(INFO) << "Calib infos will be stored in " << mOutCalibBranchName << " branch of tree " - << mOutputTreeCalib->GetName(); - } else { - LOG(INFO) << "Calib Output tree is not attached, calib infos will not be stored"; - } - -#ifdef _ALLOW_TOF_DEBUG_ - // debug streamer - if (mDBGFlags) { - mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(), "recreate"); + if (mIsTPCused) { + mTimerMatchTPC.Start(sec == o2::constants::math::NSectors - 1); + doMatchingForTPC(sec); + mTimerMatchTPC.Stop(); + } + LOG(INFO) << "...done. Now check the best matches"; + selectBestMatches(); } -#endif - mSAInitDone = true; + // re-arrange outputs from constrained/unconstrained to the 4 cases (TPC, ITS-TPC, TPC-TRD, ITS-TPC-TRD) to be implemented as soon as TPC-TRD and ITS-TPC-TRD tracks available - { - mTimerTot.Stop(); - mTimerTot.Reset(); - } + mIsTPCused = false; + mIsITSTPCused = false; + mIsTPCTRDused = false; + mIsITSTPCTRDused = false; - print(); + mTimerTot.Stop(); + LOGF(INFO, "Timing Do Matching: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1); + LOGF(INFO, "Timing Do Matching Constrained: Cpu: %.3e s Real: %.3e s in %d slots", mTimerMatchITSTPC.CpuTime(), mTimerMatchITSTPC.RealTime(), mTimerMatchITSTPC.Counter() - 1); + LOGF(INFO, "Timing Do Matching TPC : Cpu: %.3e s Real: %.3e s in %d slots", mTimerMatchTPC.CpuTime(), mTimerMatchTPC.RealTime(), mTimerMatchTPC.Counter() - 1); } - //______________________________________________ void MatchTOF::print() const { @@ -305,388 +155,240 @@ void MatchTOF::print() const LOG(INFO) << "**********************************************************************"; } - //______________________________________________ void MatchTOF::printCandidatesTOF() const { ///< print the candidates for the matching } - -//______________________________________________ -void MatchTOF::attachInputTrees() +//_____________________________________________________ +bool MatchTOF::prepareFITData() { - ///< attaching the input tree - LOG(DEBUG) << "attachInputTrees"; - if (!mInputTreeTracks) { - LOG(FATAL) << "Input tree with tracks is not set"; - } - - if (!mTreeTOFClusters) { - LOG(FATAL) << "TOF clusters data input tree is not set"; - } - - // input tracks (this is the pairs of ITS-TPC matches) - - if (!mInputTreeTracks->GetBranch(mTracksBranchName.data())) { - LOG(FATAL) << "Did not find tracks branch " << mTracksBranchName << " in the input tree"; - } - mInputTreeTracks->SetBranchAddress(mTracksBranchName.data(), &mTracksArrayInpVect); - LOG(INFO) << "Attached tracks " << mTracksBranchName << " branch with " << mInputTreeTracks->GetEntries() - << " entries"; - - // input TOF clusters - - if (!mTreeTOFClusters->GetBranch(mTOFClusterBranchName.data())) { - LOG(FATAL) << "Did not find TOF clusters branch " << mTOFClusterBranchName << " in the input tree"; + // If available, read FIT Info + if (mIsFIT) { + mFITRecPoints = mRecoCont->getFT0RecPoints(); + // prepareInteractionTimes(); } - mTreeTOFClusters->SetBranchAddress(mTOFClusterBranchName.data(), &mTOFClustersArrayInpVect); - LOG(INFO) << "Attached TOF clusters " << mTOFClusterBranchName << " branch with " << mTreeTOFClusters->GetEntries() - << " entries"; - // is there MC info available ? - mMCTruthON = true; - if (mTreeTOFClusters->GetBranch(mTOFMCTruthBranchName.data())) { - mTOFClusLabelsPtr = &mTOFClusLabels; - mTreeTOFClusters->SetBranchAddress(mTOFMCTruthBranchName.data(), &mTOFClusLabelsPtr); - LOG(INFO) << "Found TOF Clusters MCLabels branch " << mTOFMCTruthBranchName; - } else { - mMCTruthON = false; - } - if (mInputTreeTracks->GetBranch(mTPCMCTruthBranchName.data())) { - mInputTreeTracks->SetBranchAddress(mTPCMCTruthBranchName.data(), &mTPCLabelsVect); - LOG(INFO) << "Found TPC tracks MCLabels branch " << mTPCMCTruthBranchName.data(); - } else { - mMCTruthON = false; - } - if (mInputTreeTracks->GetBranch(mITSMCTruthBranchName.data())) { - mInputTreeTracks->SetBranchAddress(mITSMCTruthBranchName.data(), &mITSLabelsVect); - LOG(INFO) << "Found ITS tracks MCLabels branch " << mITSMCTruthBranchName.data(); - } else { - mMCTruthON = false; - } - - mCurrTracksTreeEntry = -1; - mCurrTOFClustersTreeEntry = -1; + return true; +} +//______________________________________________ +int MatchTOF::prepareInteractionTimes() +{ + // do nothing. If you think it can be useful have a look at MatchTPCITS + return 0; } //______________________________________________ -void MatchTOF::attachInputTreesTPConly() +bool MatchTOF::prepareTPCData() { - ///< attaching the input tree - LOG(DEBUG) << "attachInputTrees"; + mNotPropagatedToTOF[trkType::UNCONS] = 0; + mNotPropagatedToTOF[trkType::CONSTR] = 0; + + auto creator = [this](auto& trk, GTrackID gid, float time0, float terr) { + const int nclustersMin = 0; + if constexpr (isTPCTrack<decltype(trk)>()) { + if (trk.getNClusters() < nclustersMin) { + return true; + } - if (!mTreeTPCTracks) { - LOG(FATAL) << "TPC tracks data input tree is not set"; - } + if (std::abs(trk.getQ2Pt()) > mMaxInvPt) { + return true; + } + this->addTPCSeed(trk, gid); + } + if constexpr (isTPCITSTrack<decltype(trk)>()) { + if (trk.getParamOut().getX() < o2::constants::geom::XTPCOuterRef - 1.) { + return true; + } + this->addITSTPCSeed(trk, gid); + } + if constexpr (isTRDTrack<decltype(trk)>()) { + this->addTRDSeed(trk, gid, time0, terr); + } + return true; + }; + mRecoCont->createTracksVariadic(creator); - if (!mTreeTOFClusters) { - LOG(FATAL) << "TOF clusters data input tree is not set"; + for (int it = 0; it < trkType::SIZE; it++) { + mMatchedTracksIndex[it].resize(mTracksWork[it].size()); + std::fill(mMatchedTracksIndex[it].begin(), mMatchedTracksIndex[it].end(), -1); // initializing all to -1 } - // input tracks (this is the TPC tracks) + if (mIsTPCused) { + LOG(INFO) << "Number of UNCONSTRAINED tracks that failed to be propagated to TOF = " << mNotPropagatedToTOF[trkType::UNCONS]; - if (!mTreeTPCTracks->GetBranch(mTPCTracksBranchName.data())) { - LOG(FATAL) << "Did not find tracks branch " << mTPCTracksBranchName << " in the input tree"; + // sort tracks in each sector according to their time (increasing in time) + for (int sec = o2::constants::math::NSectors; sec--;) { + auto& indexCache = mTracksSectIndexCache[trkType::UNCONS][sec]; + LOG(INFO) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks"; + if (!indexCache.size()) { + continue; + } + std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { + auto& trcA = mTracksWork[trkType::UNCONS][a].second; + auto& trcB = mTracksWork[trkType::UNCONS][b].second; + return ((trcA.getTimeStamp() - trcA.getTimeStampError()) - (trcB.getTimeStamp() - trcB.getTimeStampError()) < 0.); + }); + } // loop over tracks of single sector } - mTreeTPCTracks->SetBranchAddress(mTPCTracksBranchName.data(), &mTPCTracksArrayInpVect); - LOG(INFO) << "Attached tracks " << mTPCTracksBranchName << " branch with " << mTreeTPCTracks->GetEntries() - << " entries"; - - // input TOF clusters + if (mIsITSTPCused || mIsTPCTRDused || mIsITSTPCTRDused) { + LOG(INFO) << "Number of CONSTRAINED tracks that failed to be propagated to TOF = " << mNotPropagatedToTOF[trkType::CONSTR]; - if (!mTreeTOFClusters->GetBranch(mTOFClusterBranchName.data())) { - LOG(FATAL) << "Did not find TOF clusters branch " << mTOFClusterBranchName << " in the input tree"; - } - mTreeTOFClusters->SetBranchAddress(mTOFClusterBranchName.data(), &mTOFClustersArrayInpVect); - LOG(INFO) << "Attached TOF clusters " << mTOFClusterBranchName << " branch with " << mTreeTOFClusters->GetEntries() - << " entries"; - // is there MC info available ? - mMCTruthON = true; - if (mTreeTOFClusters->GetBranch(mTOFMCTruthBranchName.data())) { - mTOFClusLabelsPtr = &mTOFClusLabels; - mTreeTOFClusters->SetBranchAddress(mTOFMCTruthBranchName.data(), &mTOFClusLabelsPtr); - LOG(INFO) << "Found TOF Clusters MCLabels branch " << mTOFMCTruthBranchName; - } else { - mMCTruthON = false; - } - if (mTreeTPCTracks->GetBranch(mOutTPCTrackMCTruthBranchName.data())) { - mTreeTPCTracks->SetBranchAddress(mOutTPCTrackMCTruthBranchName.data(), &mTPCLabelsVect); - LOG(INFO) << "Found TPC tracks MCLabels branch " << mOutTPCTrackMCTruthBranchName; - } else { - mMCTruthON = false; + // sort tracks in each sector according to their time (increasing in time) + for (int sec = o2::constants::math::NSectors; sec--;) { + auto& indexCache = mTracksSectIndexCache[trkType::CONSTR][sec]; + LOG(INFO) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks"; + if (!indexCache.size()) { + continue; + } + std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { + auto& trcA = mTracksWork[trkType::CONSTR][a].second; + auto& trcB = mTracksWork[trkType::CONSTR][b].second; + return ((trcA.getTimeStamp() - mSigmaTimeCut * trcA.getTimeStampError()) - (trcB.getTimeStamp() - mSigmaTimeCut * trcB.getTimeStampError()) < 0.); + }); + } // loop over tracks of single sector } - mCurrTracksTreeEntry = -1; - mCurrTOFClustersTreeEntry = -1; + return true; } - //______________________________________________ -bool MatchTOF::prepareTracks() +void MatchTOF::addITSTPCSeed(const o2::dataformats::TrackTPCITS& _tr, o2::dataformats::GlobalTrackID srcGID) { - ///< prepare the tracks that we want to match to TOF + mIsITSTPCused = true; - if (!mIsworkflowON && !loadTracksNextChunk()) { - return false; - } + auto trc = _tr.getParamOut(); + o2::track::TrackLTIntegral intLT0 = _tr.getLTIntegralOut(); - mNumOfTracks = mTracksArrayInp.size(); - if (mNumOfTracks == 0) { - return false; // no tracks to be matched + addConstrainedSeed(trc, srcGID, intLT0, _tr.getTimeMUS()); +} +//______________________________________________ +void MatchTOF::addConstrainedSeed(o2::track::TrackParCov& trc, o2::dataformats::GlobalTrackID srcGID, o2::track::TrackLTIntegral intLT0, timeEst timeMUS) +{ + std::array<float, 3> globalPos; + // current track index + int it = mTracksWork[trkType::CONSTR].size(); + + // propagate to matching Xref + trc.getXYZGlo(globalPos); + LOG(DEBUG) << "Global coordinates Before propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; + LOG(DEBUG) << "Radius xy Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); + LOG(DEBUG) << "Radius xyz Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); + if (!propagateToRefXWithoutCov(trc, mXRef, 2, mBz)) { // we first propagate to 371 cm without considering the covariance matrix + mNotPropagatedToTOF[trkType::CONSTR]++; + return; } - mMatchedTracksIndex.resize(mNumOfTracks); - std::fill(mMatchedTracksIndex.begin(), mMatchedTracksIndex.end(), -1); // initializing all to -1 - // copy the track params, propagate to reference X and build sector tables - mTracksWork.clear(); - mLTinfos.clear(); - mTracksWork.reserve(mNumOfTracks); - mLTinfos.reserve(mNumOfTracks); - if (mMCTruthON) { - mTracksLblWork.clear(); - mTracksLblWork.reserve(mNumOfTracks); - } - for (int sec = o2::constants::math::NSectors; sec--;) { - mTracksSectIndexCache[sec].clear(); - mTracksSectIndexCache[sec].reserve(100 + 1.2 * mNumOfTracks / o2::constants::math::NSectors); + // the "rough" propagation worked; now we can propagate considering also the cov matrix + if (!propagateToRefX(trc, mXRef, 2, intLT0) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the prop> + mNotPropagatedToTOF[trkType::CONSTR]++; + return; } - // getting Bz (mag field) - auto o2field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); - float bzField = o2field->solenoidField(); // magnetic field in kGauss - float maxInvPt = abs(bzField) > 0.1 ? 1. / (abs(bzField) * 0.05) : 999.; + trc.getXYZGlo(globalPos); - LOG(DEBUG) << "\n\nWe have %d tracks to try to match to TOF: " << mNumOfTracks; - int nNotPropagatedToTOF = 0; - for (int it = 0; it < mNumOfTracks; it++) { - const o2::dataformats::TrackTPCITS& trcOrig = mTracksArrayInp[it]; // TODO: check if we cannot directly use the o2::track::TrackParCov class instead of o2::dataformats::TrackTPCITS, and then avoid the casting below; this is the track at the vertex - std::array<float, 3> globalPos; + LOG(DEBUG) << "Global coordinates After propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; + LOG(DEBUG) << "Radius xy After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); + LOG(DEBUG) << "Radius xyz After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); + LOG(DEBUG) << "The track will go to sector " << o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0])); - // create working copy of track param - mTracksWork.emplace_back(std::make_pair(trcOrig.getParamOut(), trcOrig.getTimeMUS())); //, mCurrTracksTreeEntry, it); - mLTinfos.emplace_back(trcOrig.getLTIntegralOut()); - // make a copy of the TPC track that we have to propagate - //o2::tpc::TrackTPC* trc = new o2::tpc::TrackTPC(trcTPCOrig); // this would take the TPCout track - //auto& trc = mTracksWork.back(); // with this we take the TPCITS track propagated to the vertex - auto& trc = mTracksWork.back().first; // with this we take the TPCITS track propagated to the vertex - auto& intLT = mLTinfos.back(); // we get the integrated length from TPC-ITC outward propagation - - if (trc.getX() < o2::globaltracking::MatchTPCITS::XTPCOuterRef - 1.) { // tpc-its track outward propagation did not reach outer ref.radius, skip this track - nNotPropagatedToTOF++; - continue; - } + int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0])); - // propagate to matching Xref - trc.getXYZGlo(globalPos); - LOG(DEBUG) << "Global coordinates Before propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; - LOG(DEBUG) << "Radius xy Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); - LOG(DEBUG) << "Radius xyz Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); - if (!propagateToRefXWithoutCov(trc, mXRef, 2, bzField)) { // we first propagate to 371 cm without considering the covariance matrix - nNotPropagatedToTOF++; - continue; - } - - // the "rough" propagation worked; now we can propagate considering also the cov matrix - if (!propagateToRefX(trc, mXRef, 2, intLT) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the propagation without the errors succeeded? - nNotPropagatedToTOF++; - continue; - } - - trc.getXYZGlo(globalPos); + // create working copy of track param + mTracksWork[trkType::CONSTR].emplace_back(std::make_pair(trc, timeMUS)); + mTrackGid[trkType::CONSTR].emplace_back(srcGID); + mLTinfos[trkType::CONSTR].emplace_back(intLT0); - LOG(DEBUG) << "Global coordinates After propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; - LOG(DEBUG) << "Radius xy After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); - LOG(DEBUG) << "Radius xyz After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); - LOG(DEBUG) << "The track will go to sector " << o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0])); + if (mMCTruthON) { + mTracksLblWork[trkType::CONSTR].emplace_back(mRecoCont->getTPCITSTrackMCLabel(srcGID)); + } - mTracksSectIndexCache[o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]))].push_back(it); - //delete trc; // Check: is this needed? + mTracksSectIndexCache[trkType::CONSTR][sector].push_back(it); + //delete trc; // Check: is this needed? +} //______________________________________________ +void MatchTOF::addTRDSeed(const o2::trd::TrackTRD& _tr, o2::dataformats::GlobalTrackID srcGID, float time0, float terr) +{ + if (srcGID.getSource() == o2::dataformats::GlobalTrackID::TPCTRD) { + mIsTPCTRDused = true; + } else if (srcGID.getSource() == o2::dataformats::GlobalTrackID::ITSTPCTRD) { + mIsITSTPCTRDused = true; + } else { // shouldn't happen + LOG(ERROR) << "MatchTOF::addTRDSee: srcGID.getSource() = " << srcGID.getSource() << " not allowed; expected ones are: " << o2::dataformats::GlobalTrackID::TPCTRD << " and " << o2::dataformats::GlobalTrackID::ITSTPCTRD; } - LOG(INFO) << "Total number of tracks = " << mNumOfTracks << ", Number of tracks that failed to be propagated to TOF = " << nNotPropagatedToTOF; + auto trc = _tr.getOuterParam(); - // sort tracks in each sector according to their time (increasing in time) - for (int sec = o2::constants::math::NSectors; sec--;) { - auto& indexCache = mTracksSectIndexCache[sec]; - LOG(INFO) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks"; - if (!indexCache.size()) { - continue; - } - std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { - auto& trcA = mTracksWork[a].second; - auto& trcB = mTracksWork[b].second; - return ((trcA.getTimeStamp() - mSigmaTimeCut * trcA.getTimeStampError()) - (trcB.getTimeStamp() - mSigmaTimeCut * trcB.getTimeStampError()) < 0.); - }); - } // loop over tracks of single sector + o2::track::TrackLTIntegral intLT0 = _tr.getLTIntegralOut(); + ; // empty for the moment - // Uncomment for local debug - /* - // printing the tracks - std::array<float, 3> globalPos; - int itmp = 0; - for (int sec = o2::constants::math::NSectors; sec--;) { - Printf("sector %d", sec); - auto& cacheTrk = mTracksSectIndexCache[sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! - for (int itrk = 0; itrk < cacheTrk.size(); itrk++){ - itmp++; - auto& trc = mTracksWork[cacheTrk[itrk]]; - trc.getXYZGlo(globalPos); - printf("Track %d: Global coordinates After propagating to 371 cm: globalPos[0] = %f, globalPos[1] = %f, globalPos[2] = %f\n", itrk, globalPos[0], globalPos[1], globalPos[2]); - // Printf("The phi angle is %f", TMath::ATan2(globalPos[1], globalPos[0])); - } - } - Printf("we have %d tracks",itmp); - */ + // o2::dataformats::TimeStampWithError<float, float> + timeEst ts(time0, terr); - return true; + addConstrainedSeed(trc, srcGID, intLT0, ts); } //______________________________________________ -bool MatchTOF::prepareTPCTracks() +void MatchTOF::addTPCSeed(const o2::tpc::TrackTPC& _tr, o2::dataformats::GlobalTrackID srcGID) { - ///< prepare the tracks that we want to match to TOF - - if (!mIsworkflowON && !loadTPCTracksNextChunk()) { - return false; - } + mIsTPCused = true; - mNumOfTracks = mTPCTracksArrayInp.size(); - if (mNumOfTracks == 0) { - return false; // no tracks to be matched - } - mMatchedTracksIndex.resize(mNumOfTracks); - std::fill(mMatchedTracksIndex.begin(), mMatchedTracksIndex.end(), -1); // initializing all to -1 + std::array<float, 3> globalPos; - // copy the track params, propagate to reference X and build sector tables - mTracksWork.clear(); - mTracksWork.reserve(mNumOfTracks); - mSideTPC.clear(); - mSideTPC.reserve(mNumOfTracks); - mExtraTPCFwdTime.clear(); - mExtraTPCFwdTime.reserve(mNumOfTracks); + // current track index + int it = mTracksWork[trkType::UNCONS].size(); - for (int sec = o2::constants::math::NSectors; sec--;) { - mTPCTracksSectIndexCache[sec].clear(); - mTPCTracksSectIndexCache[sec].reserve(100 + 1.2 * mNumOfTracks / o2::constants::math::NSectors); + // create working copy of track param + timeEst timeInfo; + // set + float extraErr = 0; + if (mIsCosmics) { + extraErr = 100; } - // getting Bz (mag field) - auto o2field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); - float bzField = o2field->solenoidField(); // magnetic field in kGauss - float maxInvPt = abs(bzField) > 0.1 ? 1. / (abs(bzField) * 0.05) : 999.; - int nclustersMin = 0; - LOG(INFO) << "Max track Inv pT allowed = " << maxInvPt; - LOG(INFO) << "Min track Nclusters allowed = " << nclustersMin; + auto trc = _tr.getOuterParam(); - LOG(DEBUG) << "\n\nWe have %d tracks to try to match to TOF: " << mNumOfTracks; - int nNotPropagatedToTOF = 0; - for (int it = 0; it < mNumOfTracks; it++) { - const o2::tpc::TrackTPC& trcOrig = mTPCTracksArrayInp[it]; // TODO: check if we cannot directly use the o2::track::TrackParCov class instead of o2::dataformats::TrackTPCITS, and then avoid the casting below; this is the track at the vertex - std::array<float, 3> globalPos; - - // create working copy of track param - timeEst timeInfo; - // set - timeInfo.setTimeStamp(trcOrig.getTime0() * o2::tpc::ParameterElectronics::Instance().ZbinWidth); - timeInfo.setTimeStampError((trcOrig.getDeltaTBwd() + 5) * o2::tpc::ParameterElectronics::Instance().ZbinWidth); - mSideTPC.push_back(trcOrig.hasASideClustersOnly() ? 1 : (trcOrig.hasCSideClustersOnly() ? -1 : 0)); - mExtraTPCFwdTime.push_back((trcOrig.getDeltaTFwd() + 5) * o2::tpc::ParameterElectronics::Instance().ZbinWidth); - - o2::track::TrackLTIntegral intLT0; //mTPCTracksWork.back().getLTIntegralOut(); // we get the integrated length from TPC-ITC outward propagation - // make a copy of the TPC track that we have to propagate - //o2::tpc::TrackTPC* trc = new o2::tpc::TrackTPC(trcTPCOrig); // this would take the TPCout track - mTracksWork.emplace_back(std::make_pair(trcOrig.getOuterParam(), timeInfo)); - auto& trc = mTracksWork.back().first; - auto& intLT = mLTinfos.emplace_back(intLT0); - - if (trcOrig.getNClusters() < nclustersMin) { - nNotPropagatedToTOF++; - continue; - } - - if (std::abs(trc.getQ2Pt()) > maxInvPt) { // tpc-its track outward propagation did not reach outer ref.radius, skip this track - nNotPropagatedToTOF++; - continue; - } - - // printf("N clusters = %d\n",trcOrig.getNClusters()); + if (!propagateToRefXWithoutCov(trc, mXRef, 10, mBz)) { // we first propagate to 371 cm without considering the covariance matri + mNotPropagatedToTOF[trkType::UNCONS]++; + return; + } -#ifdef _ALLOW_TOF_DEBUG_ - // propagate to matching Xref - trc.getXYZGlo(globalPos); - LOG(INFO) << "Global coordinates Before propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; - LOG(INFO) << "Radius xy Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); - LOG(INFO) << "Radius xyz Before propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); - // the "very rough" propagation worked; now we can propagate considering also the cov matrix -#endif + o2::track::TrackLTIntegral intLT0; //mTPCTracksWork.back().getLTIntegralOut(); // we get the integrated length from TPC-ITC outward propagation - if (!propagateToRefXWithoutCov(trc, mXRef, 10, bzField)) { // we first propagate to 371 cm without considering the covariance matrix - nNotPropagatedToTOF++; - continue; + if (trc.getX() < o2::constants::geom::XTPCOuterRef - 1.) { + if (!propagateToRefX(trc, o2::constants::geom::XTPCOuterRef, 10, intLT0) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happ + mNotPropagatedToTOF[trkType::UNCONS]++; + return; } + } - if (trc.getX() < o2::globaltracking::MatchTPCITS::XTPCOuterRef - 1.) { - if (!propagateToRefX(trc, o2::globaltracking::MatchTPCITS::XTPCOuterRef, 10, intLT) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the propagation without the errors succeeded? - nNotPropagatedToTOF++; - continue; - } - } - - // the "rough" propagation worked; now we can propagate considering also the cov matrix - if (!propagateToRefX(trc, mXRef, 2, intLT) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the propagation without the errors succeeded? - nNotPropagatedToTOF++; - continue; - } - - trc.getXYZGlo(globalPos); - -#ifdef _ALLOW_TOF_DEBUG_ - LOG(INFO) << "Global coordinates After propagating to 371 cm: globalPos[0] = " << globalPos[0] << ", globalPos[1] = " << globalPos[1] << ", globalPos[2] = " << globalPos[2]; - LOG(INFO) << "Radius xy After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1]); - LOG(INFO) << "Radius xyz After propagating to 371 cm = " << TMath::Sqrt(globalPos[0] * globalPos[0] + globalPos[1] * globalPos[1] + globalPos[2] * globalPos[2]); - LOG(INFO) << "The track will go to sector " << o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0])); -#endif - - mTracksSectIndexCache[o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]))].push_back(it); - //delete trc; // Check: is this needed? + // the "rough" propagation worked; now we can propagate considering also the cov matrix + if (!propagateToRefX(trc, mXRef, 2, intLT0)) { // || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the prop> + mNotPropagatedToTOF[trkType::UNCONS]++; + return; } - LOG(INFO) << "Total number of tracks = " << mNumOfTracks << ", Number of tracks that failed to be propagated to TOF = " << nNotPropagatedToTOF; + timeInfo.setTimeStamp(_tr.getTime0() * mTPCTBinMUS); + timeInfo.setTimeStampError((_tr.getDeltaTBwd() + 5) * mTPCTBinMUS + extraErr); + mSideTPC.push_back(_tr.hasASideClustersOnly() ? 1 : (_tr.hasCSideClustersOnly() ? -1 : 0)); + mExtraTPCFwdTime.push_back((_tr.getDeltaTFwd() + 5) * mTPCTBinMUS + extraErr); - // sort tracks in each sector according to their time (increasing in time) - for (int sec = o2::constants::math::NSectors; sec--;) { - auto& indexCache = mTracksSectIndexCache[sec]; - LOG(INFO) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks"; - if (!indexCache.size()) { - continue; - } - std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { - auto& trcA = mTracksWork[a].second; - auto& trcB = mTracksWork[b].second; - return ((trcA.getTimeStamp() - trcA.getTimeStampError()) - (trcB.getTimeStamp() - trcB.getTimeStampError()) < 0.); - }); - } // loop over tracks of single sector + trc.getXYZGlo(globalPos); + int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0])); - // Uncomment for local debug - /* - // printing the tracks - std::array<float, 3> globalPos; - int itmp = 0; - for (int sec = o2::constants::math::NSectors; sec--;) { - Printf("sector %d", sec); - auto& cacheTrk = mTracksSectIndexCache[sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! - for (int itrk = 0; itrk < cacheTrk.size(); itrk++){ - itmp++; - auto& trc = mTracksWork[cacheTrk[itrk]]; - trc.getXYZGlo(globalPos); - printf("Track %d: Global coordinates After propagating to 371 cm: globalPos[0] = %f, globalPos[1] = %f, globalPos[2] = %f\n", itrk, globalPos[0], globalPos[1], globalPos[2]); - // Printf("The phi angle is %f", TMath::ATan2(globalPos[1], globalPos[0])); - } + mTracksWork[trkType::UNCONS].emplace_back(std::make_pair(trc, timeInfo)); + mTrackGid[trkType::UNCONS].emplace_back(srcGID); + + if (mMCTruthON) { + mTracksLblWork[trkType::UNCONS].emplace_back(mRecoCont->getTPCTrackMCLabel(srcGID)); } - Printf("we have %d tracks",itmp); - */ + mLTinfos[trkType::UNCONS].emplace_back(intLT0); - return true; + mTracksSectIndexCache[trkType::UNCONS][sector].push_back(it); + //delete trc; // Check: is this needed? } //______________________________________________ bool MatchTOF::prepareTOFClusters() { + mTOFClustersArrayInp = mRecoCont->getTOFClusters(); + mTOFClusLabels = mRecoCont->getTOFClustersMCLabels(); + mMCTruthON = mTOFClusLabels && mTOFClusLabels->getNElements(); + ///< prepare the tracks that we want to match to TOF // copy the track params, propagate to reference X and build sector tables @@ -703,34 +405,18 @@ bool MatchTOF::prepareTOFClusters() } mNumOfClusters = 0; - while (!mIsworkflowON && loadTOFClustersNextChunk()) { - int nClusterInCurrentChunk = mTOFClustersArrayInp.size(); - LOG(DEBUG) << "nClusterInCurrentChunk = " << nClusterInCurrentChunk; - mNumOfClusters += nClusterInCurrentChunk; - for (int it = 0; it < nClusterInCurrentChunk; it++) { - const Cluster& clOrig = mTOFClustersArrayInp[it]; - // create working copy of track param - mTOFClusWork.emplace_back(clOrig); - auto& cl = mTOFClusWork.back(); - cl.setEntryInTree(mCurrTOFClustersTreeEntry); - // cache work track index - mTOFClusSectIndexCache[cl.getSector()].push_back(mTOFClusWork.size() - 1); - } - } - if (mIsworkflowON) { - int nClusterInCurrentChunk = mTOFClustersArrayInp.size(); - LOG(DEBUG) << "nClusterInCurrentChunk = " << nClusterInCurrentChunk; - mNumOfClusters += nClusterInCurrentChunk; - for (int it = 0; it < nClusterInCurrentChunk; it++) { - const Cluster& clOrig = mTOFClustersArrayInp[it]; - // create working copy of track param - mTOFClusWork.emplace_back(clOrig); - auto& cl = mTOFClusWork.back(); - cl.setEntryInTree(mCurrTOFClustersTreeEntry); - // cache work track index - mTOFClusSectIndexCache[cl.getSector()].push_back(mTOFClusWork.size() - 1); - } + int nClusterInCurrentChunk = mTOFClustersArrayInp.size(); + LOG(DEBUG) << "nClusterInCurrentChunk = " << nClusterInCurrentChunk; + mNumOfClusters += nClusterInCurrentChunk; + mTOFClusWork.reserve(mTOFClusWork.size() + mNumOfClusters); + for (int it = 0; it < nClusterInCurrentChunk; it++) { + const Cluster& clOrig = mTOFClustersArrayInp[it]; + // create working copy of track param + mTOFClusWork.emplace_back(clOrig); + auto& cl = mTOFClusWork.back(); + // cache work track index + mTOFClusSectIndexCache[cl.getSector()].push_back(mTOFClusWork.size() - 1); } // sort clusters in each sector according to their time (increasing in time) @@ -755,75 +441,14 @@ bool MatchTOF::prepareTOFClusters() return true; } - -//_____________________________________________________ -bool MatchTOF::loadTracksNextChunk() -{ - ///< load next chunk of tracks to be matched to TOF - while (++mCurrTracksTreeEntry < mInputTreeTracks->GetEntries()) { - mInputTreeTracks->GetEntry(mCurrTracksTreeEntry); - mTracksArrayInp = gsl::span<const o2::dataformats::TrackTPCITS>{*mTracksArrayInpVect}; - LOG(INFO) << "Loading tracks entry " << mCurrTracksTreeEntry << " -> " << mTracksArrayInp.size() - << " tracks"; - if (!mTracksArrayInp.size()) { - continue; - } - if (mMCTruthON) { - mITSLabels = gsl::span<const o2::MCCompLabel>{*mITSLabelsVect}; - mTPCLabels = gsl::span<const o2::MCCompLabel>{*mTPCLabelsVect}; - } - return true; - } - --mCurrTracksTreeEntry; - return false; -} -//_____________________________________________________ -bool MatchTOF::loadTPCTracksNextChunk() -{ - ///< load next chunk of tracks to be matched to TOF - while (++mCurrTracksTreeEntry < mTreeTPCTracks->GetEntries()) { - mTreeTPCTracks->GetEntry(mCurrTracksTreeEntry); - mTPCTracksArrayInp = gsl::span<const o2::tpc::TrackTPC>{*mTPCTracksArrayInpVect}; - LOG(INFO) << "Loading TPC tracks entry " << mCurrTracksTreeEntry << " -> " << mTPCTracksArrayInp.size() - << " tracks"; - if (!mTPCTracksArrayInp.size()) { - continue; - } - return true; - } - --mCurrTracksTreeEntry; - return false; -} -//______________________________________________ -bool MatchTOF::loadTOFClustersNextChunk() -{ - LOG(DEBUG) << "Loat clusters next chunck"; - ///< load next chunk of clusters to be matched to TOF - LOG(DEBUG) << "Loading TOF clusters: number of entries in tree = " << mTreeTOFClusters->GetEntries(); - while (++mCurrTOFClustersTreeEntry < mTreeTOFClusters->GetEntries()) { - mTreeTOFClusters->GetEntry(mCurrTOFClustersTreeEntry); - mTOFClustersArrayInp = gsl::span<const Cluster>{*mTOFClustersArrayInpVect}; - LOG(DEBUG) << "Loading TOF clusters entry " << mCurrTOFClustersTreeEntry << " -> " << mTOFClustersArrayInp.size() - << " clusters"; - LOG(INFO) << "Loading TOF clusters entry " << mCurrTOFClustersTreeEntry << " -> " << mTOFClustersArrayInp.size() - << " clusters"; - if (!mTOFClustersArrayInp.size()) { - continue; - } - return true; - } - --mCurrTOFClustersTreeEntry; - return false; -} //______________________________________________ void MatchTOF::doMatching(int sec) { + trkType type = trkType::CONSTR; ///< do the real matching per sector - mMatchedTracksPairs.clear(); // new sector - - auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time! - auto& cacheTrk = mTracksSectIndexCache[sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! + auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time! + auto& cacheTrk = mTracksSectIndexCache[type][sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! int nTracks = cacheTrk.size(), nTOFCls = cacheTOF.size(); LOG(INFO) << "Matching sector " << sec << ": number of tracks: " << nTracks << ", number of TOF clusters: " << nTOFCls; if (!nTracks || !nTOFCls) { @@ -848,30 +473,24 @@ void MatchTOF::doMatching(int sec) nStepsInsideSameStrip[ii] = 0; } int nStripsCrossedInPropagation = 0; // how many strips were hit during the propagation - auto& trackWork = mTracksWork[cacheTrk[itrk]]; + auto& trackWork = mTracksWork[type][cacheTrk[itrk]]; auto& trefTrk = trackWork.first; - auto& intLT = mLTinfos[cacheTrk[itrk]]; + auto& intLT = mLTinfos[type][cacheTrk[itrk]]; // Printf("intLT (before doing anything): length = %f, time (Pion) = %f", intLT.getL(), intLT.getTOF(o2::track::PID::Pion)); - float minTrkTime = (trackWork.second.getTimeStamp() - mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6; // minimum time in ps - float maxTrkTime = (trackWork.second.getTimeStamp() + mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6; // maximum time in ps - int istep = 1; // number of steps - float step = 1.0; // step size in cm - //uncomment for local debug - /* - //trefTrk.getXYZGlo(posBeforeProp); - //float posBeforeProp[3] = {trefTrk.getX(), trefTrk.getY(), trefTrk.getZ()}; // in local ref system - //printf("Global coordinates: posBeforeProp[0] = %f, posBeforeProp[1] = %f, posBeforeProp[2] = %f\n", posBeforeProp[0], posBeforeProp[1], posBeforeProp[2]); - //Printf("Radius xy = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1])); - //Printf("Radius xyz = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1] + posBeforeProp[2]*posBeforeProp[2])); - */ - -#ifdef _ALLOW_TOF_DEBUG_ - if (mDBGFlags) { - (*mDBGOut) << "propOK" - << "track=" << trefTrk << "\n"; - } -#endif + float minTrkTime = (trackWork.second.getTimeStamp() - mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6; // minimum time in ps + float maxTrkTime = (trackWork.second.getTimeStamp() + mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6; // maximum time in ps + int istep = 1; // number of steps + float step = 1.0; // step size in cm + + //uncomment for local debug + /* + //trefTrk.getXYZGlo(posBeforeProp); + //float posBeforeProp[3] = {trefTrk.getX(), trefTrk.getY(), trefTrk.getZ()}; // in local ref system + //printf("Global coordinates: posBeforeProp[0] = %f, posBeforeProp[1] = %f, posBeforeProp[2] = %f\n", posBeforeProp[0], posBeforeProp[1], posBeforeProp[2]); + //Printf("Radius xy = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1])); + //Printf("Radius xyz = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1] + posBeforeProp[2]*posBeforeProp[2])); + */ // initializing for (int ii = 0; ii < 2; ii++) { @@ -885,12 +504,13 @@ void MatchTOF::doMatching(int sec) double reachedPoint = mXRef + istep * step; while (propagateToRefX(trefTrk, reachedPoint, step, intLT) && nStripsCrossedInPropagation <= 2 && reachedPoint < Geo::RMAX) { - // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, o2::constants::physics::MassPionCharged, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) { + // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) { trefTrk.getXYZGlo(pos); for (int ii = 0; ii < 3; ii++) { // we need to change the type... posFloat[ii] = pos[ii]; } + // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step /* Printf("posFloat[0] = %f, posFloat[1] = %f, posFloat[2] = %f", posFloat[0], posFloat[1], posFloat[2]); @@ -902,7 +522,7 @@ void MatchTOF::doMatching(int sec) detIdTemp[idet] = -1; } - Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp); + Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp, sec); reachedPoint += step; @@ -910,20 +530,6 @@ void MatchTOF::doMatching(int sec) continue; } - // to reduce the active region of the strip -> uncomment these lines - // float yresidual = TMath::Abs(deltaPosTemp[1]); - // if(yresidual > 0.55){ - // reachedPoint += step; - // continue; - // } - - // printf("res %f %f %f -- %f %f %f (%d)\n",deltaPosTemp[0],deltaPosTemp[1],deltaPosTemp[2],pos[0],pos[1],pos[2],detIdTemp[2]); - - // if you want to exit from the strip matched uncomment this line - // reachedPoint += 3.0; // go out from the strip at the next step - - // printf("idet: %d %d %d %d %d\n",detIdTemp[0],detIdTemp[1],detIdTemp[2],detIdTemp[3],detIdTemp[4]); - // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step //Printf("detIdTemp[0] = %d, detIdTemp[1] = %d, detIdTemp[2] = %d, detIdTemp[3] = %d, detIdTemp[4] = %d", detIdTemp[0], detIdTemp[1], detIdTemp[2], detIdTemp[3], detIdTemp[4]); // if (nStripsCrossedInPropagation == 0) { // print in case you have a useful propagation @@ -941,6 +547,7 @@ void MatchTOF::doMatching(int sec) // check if after the propagation we are in a TOF strip // we ended in a TOF strip // LOG(DEBUG) << "nStripsCrossedInPropagation = " << nStripsCrossedInPropagation << ", detId[nStripsCrossedInPropagation][0] = " << detId[nStripsCrossedInPropagation][0] << ", detIdTemp[0] = " << detIdTemp[0] << ", detId[nStripsCrossedInPropagation][1] = " << detId[nStripsCrossedInPropagation][1] << ", detIdTemp[1] = " << detIdTemp[1] << ", detId[nStripsCrossedInPropagation][2] = " << detId[nStripsCrossedInPropagation][2] << ", detIdTemp[2] = " << detIdTemp[2]; + if (nStripsCrossedInPropagation == 0 || // we are crossing a strip for the first time... (nStripsCrossedInPropagation >= 1 && (detId[nStripsCrossedInPropagation - 1][0] != detIdTemp[0] || detId[nStripsCrossedInPropagation - 1][1] != detIdTemp[1] || detId[nStripsCrossedInPropagation - 1][2] != detIdTemp[2]))) { // ...or we are crossing a new strip if (nStripsCrossedInPropagation == 0) { @@ -972,27 +579,12 @@ void MatchTOF::doMatching(int sec) nStepsInsideSameStrip[nStripsCrossedInPropagation - 1]++; } } - // LOG(DEBUG) << "while done, we propagated track " << itrk << " in %d strips" << nStripsCrossedInPropagation; - // LOG(INFO) << "while done, we propagated track " << itrk << " in %d strips" << nStripsCrossedInPropagation; - - // uncomment for debug purposes, to check tracks that did not cross any strip - /* - if (nStripsCrossedInPropagation == 0) { - auto labelTPCNoStripsCrossed = mTPCLabels->at(mTracksSectIndexCache[sec][itrk]); - Printf("The current track (index = %d) never crossed a strip", cacheTrk[itrk]); - Printf("TrackID = %d, EventID = %d, SourceID = %d", labelTPCNoStripsCrossed.getTrackID(), labelTPCNoStripsCrossed.getEventID(), labelTPCNoStripsCrossed.getSourceID()); - printf("Global coordinates: pos[0] = %f, pos[1] = %f, pos[2] = %f\n", pos[0], pos[1], pos[2]); - printf("detIdTemp[0] = %d, detIdTemp[1] = %d, detIdTemp[2] = %d, detIdTemp[3] = %d, detIdTemp[4] = %d\n", detIdTemp[0], detIdTemp[1], detIdTemp[2], detIdTemp[3], detIdTemp[4]); - printf("deltaPosTemp[0] = %f, deltaPosTemp[1] = %f, deltaPosTemp[2] = %f\n", deltaPosTemp[0], deltaPosTemp[1], deltaPosTemp[2]); - } - */ for (Int_t imatch = 0; imatch < nStripsCrossedInPropagation; imatch++) { // we take as residual the average of the residuals along the propagation in the same strip deltaPos[imatch][0] /= nStepsInsideSameStrip[imatch]; deltaPos[imatch][1] /= nStepsInsideSameStrip[imatch]; deltaPos[imatch][2] /= nStepsInsideSameStrip[imatch]; - // LOG(DEBUG) << "matched strip " << imatch << ": deltaPos[0] = " << deltaPos[imatch][0] << ", deltaPos[1] = " << deltaPos[imatch][1] << ", deltaPos[2] = " << deltaPos[imatch][2] << ", residual (x, z) = " << TMath::Sqrt(deltaPos[imatch][0] * deltaPos[imatch][0] + deltaPos[imatch][2] * deltaPos[imatch][2]); } if (nStripsCrossedInPropagation == 0) { @@ -1060,29 +652,12 @@ void MatchTOF::doMatching(int sec) int sourceIdTOF; for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation; iPropagation++) { LOG(DEBUG) << "TOF Cluster [" << itof << ", " << cacheTOF[itof] << "]: indices = " << indices[0] << ", " << indices[1] << ", " << indices[2] << ", " << indices[3] << ", " << indices[4]; - LOG(DEBUG) << "Propagated Track [" << itrk << ", " << cacheTrk[itrk] << "]: detId[" << iPropagation << "] = " << detId[iPropagation][0] << ", " << detId[iPropagation][1] << ", " << detId[iPropagation][2] << ", " << detId[iPropagation][3] << ", " << detId[iPropagation][4]; + LOG(DEBUG) << "Propagated Track [" << itrk << "]: detId[" << iPropagation << "] = " << detId[iPropagation][0] << ", " << detId[iPropagation][1] << ", " << detId[iPropagation][2] << ", " << detId[iPropagation][3] << ", " << detId[iPropagation][4]; float resX = deltaPos[iPropagation][0] - (indices[4] - detId[iPropagation][4]) * Geo::XPAD + posCorr[0]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster float resZ = deltaPos[iPropagation][2] - (indices[3] - detId[iPropagation][3]) * Geo::ZPAD + posCorr[2]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster float res = TMath::Sqrt(resX * resX + resZ * resZ); LOG(DEBUG) << "resX = " << resX << ", resZ = " << resZ << ", res = " << res; -#ifdef _ALLOW_TOF_DEBUG_ - fillTOFmatchTree("match0", cacheTOF[itof], indices[0], indices[1], indices[2], indices[3], indices[4], cacheTrk[itrk], iPropagation, detId[iPropagation][0], detId[iPropagation][1], detId[iPropagation][2], detId[iPropagation][3], detId[iPropagation][4], resX, resZ, res, trackWork, trkLTInt[iPropagation].getL(), trkLTInt[iPropagation].getTOF(o2::track::PID::Pion), trefTOF.getTime()); - int tofLabelTrackID[3] = {-1, -1, -1}; - int tofLabelEventID[3] = {-1, -1, -1}; - int tofLabelSourceID[3] = {-1, -1, -1}; - if (mMCTruthON) { - const auto& labelsTOF = mTOFClusLabels.getLabels(mTOFClusSectIndexCache[indices[0]][itof]); - for (int ilabel = 0; ilabel < labelsTOF.size(); ilabel++) { - tofLabelTrackID[ilabel] = labelsTOF[ilabel].getTrackID(); - tofLabelEventID[ilabel] = labelsTOF[ilabel].getEventID(); - tofLabelSourceID[ilabel] = labelsTOF[ilabel].getSourceID(); - } - auto labelTPC = mTPCLabels[mTracksSectIndexCache[sec][itrk]]; - auto labelITS = mITSLabels[mTracksSectIndexCache[indices[0]][itrk]]; - fillTOFmatchTreeWithLabels("matchPossibleWithLabels", cacheTOF[itof], indices[0], indices[1], indices[2], indices[3], indices[4], cacheTrk[itrk], iPropagation, detId[iPropagation][0], detId[iPropagation][1], detId[iPropagation][2], detId[iPropagation][3], detId[iPropagation][4], resX, resZ, res, trackWork, labelTPC.getTrackID(), labelTPC.getEventID(), labelTPC.getSourceID(), labelITS.getTrackID(), labelITS.getEventID(), labelITS.getSourceID(), tofLabelTrackID[0], tofLabelEventID[0], tofLabelSourceID[0], tofLabelTrackID[1], tofLabelEventID[1], tofLabelSourceID[1], tofLabelTrackID[2], tofLabelEventID[2], tofLabelSourceID[2], trkLTInt[iPropagation].getL(), trkLTInt[iPropagation].getTOF(o2::track::PID::Pion), trefTOF.getTime()); - } -#endif if (indices[0] != detId[iPropagation][0]) { continue; } @@ -1093,58 +668,34 @@ void MatchTOF::doMatching(int sec) continue; } float chi2 = res; // TODO: take into account also the time! -#ifdef _ALLOW_TOF_DEBUG_ - fillTOFmatchTree("match1", cacheTOF[itof], indices[0], indices[1], indices[2], indices[3], indices[4], cacheTrk[itrk], iPropagation, detId[iPropagation][0], detId[iPropagation][1], detId[iPropagation][2], detId[iPropagation][3], detId[iPropagation][4], resX, resZ, res, trackWork, trkLTInt[iPropagation].getL(), trkLTInt[iPropagation].getTOF(o2::track::PID::Pion), trefTOF.getTime()); - if (mMCTruthON) { - auto labelTPC = mTPCLabels[mTracksSectIndexCache[sec][itrk]]; - auto labelITS = mITSLabels[mTracksSectIndexCache[indices[0]][itrk]]; - fillTOFmatchTreeWithLabels("matchOkWithLabels", cacheTOF[itof], indices[0], indices[1], indices[2], indices[3], indices[4], cacheTrk[itrk], iPropagation, detId[iPropagation][0], detId[iPropagation][1], detId[iPropagation][2], detId[iPropagation][3], detId[iPropagation][4], resX, resZ, res, trackWork, labelTPC.getTrackID(), labelTPC.getEventID(), labelTPC.getSourceID(), labelITS.getTrackID(), labelITS.getEventID(), labelITS.getSourceID(), tofLabelTrackID[0], tofLabelEventID[0], tofLabelSourceID[0], tofLabelTrackID[1], tofLabelEventID[1], tofLabelSourceID[1], tofLabelTrackID[2], tofLabelEventID[2], tofLabelSourceID[2], trkLTInt[iPropagation].getL(), trkLTInt[iPropagation].getTOF(o2::track::PID::Pion), trefTOF.getTime()); - } -#endif if (res < mSpaceTolerance) { // matching ok! - LOG(DEBUG) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[indices[0]][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof]; + LOG(DEBUG) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[type][sec][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof]; foundCluster = true; // set event indexes (to be checked) - evIdx eventIndexTOFCluster(trefTOF.getEntryInTree(), mTOFClusSectIndexCache[indices[0]][itof]); - evIdx eventIndexTracks(mCurrTracksTreeEntry, mTracksSectIndexCache[indices[0]][itrk]); - mMatchedTracksPairs.emplace_back(o2::dataformats::MatchInfoTOF(eventIndexTOFCluster, chi2, trkLTInt[iPropagation], eventIndexTracks)); // TODO: check if this is correct! - -#ifdef _ALLOW_TOF_DEBUG_ - if (mMCTruthON) { - const auto& labelsTOF = mTOFClusLabels.getLabels(mTOFClusSectIndexCache[indices[0]][itof]); - auto labelTPC = mTPCLabels[mTracksSectIndexCache[sec][itrk]]; - auto labelITS = mITSLabels[mTracksSectIndexCache[indices[0]][itrk]]; - for (int ilabel = 0; ilabel < labelsTOF.size(); ilabel++) { - LOG(DEBUG) << "TOF label " << ilabel << labelsTOF[ilabel]; - } - LOG(DEBUG) << "TPC label " << labelTPC; - LOG(DEBUG) << "ITS label " << labelITS; - fillTOFmatchTreeWithLabels("matchOkWithLabelsInSpaceTolerance", cacheTOF[itof], indices[0], indices[1], indices[2], indices[3], indices[4], cacheTrk[itrk], iPropagation, detId[iPropagation][0], detId[iPropagation][1], detId[iPropagation][2], detId[iPropagation][3], detId[iPropagation][4], resX, resZ, res, trackWork, labelTPC.getTrackID(), labelTPC.getEventID(), labelTPC.getSourceID(), labelITS.getTrackID(), labelITS.getEventID(), labelITS.getSourceID(), tofLabelTrackID[0], tofLabelEventID[0], tofLabelSourceID[0], tofLabelTrackID[1], tofLabelEventID[1], tofLabelSourceID[1], tofLabelTrackID[2], tofLabelEventID[2], tofLabelSourceID[2], trkLTInt[iPropagation].getL(), trkLTInt[iPropagation].getTOF(o2::track::PID::Pion), trefTOF.getTime()); - } -#endif + int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof]; + mMatchedTracksPairs.emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[iPropagation], mTrackGid[type][cacheTrk[itrk]], type); // TODO: check if this is correct! } } } - if (!foundCluster && mMCTruthON) { - auto labelTPC = mTPCLabels[mTracksSectIndexCache[sec][itrk]]; - LOG(DEBUG) << "We did not find any TOF cluster for track " << cacheTrk[itrk] << " (label = " << labelTPC << ", pt = " << trefTrk.getPt(); - } } return; } //______________________________________________ void MatchTOF::doMatchingForTPC(int sec) { - printf("here, DoMatch\n"); auto& gasParam = o2::tpc::ParameterGas::Instance(); float vdrift = gasParam.DriftV; + float vdriftInBC = Geo::BC_TIME_INPS * 1E-6 * vdrift; - ///< do the real matching per sector - mMatchedTracksPairs.clear(); // new sector + int bc_grouping = 40; + int bc_grouping_tolerance = bc_grouping + mTimeTolerance / 25; + int bc_grouping_half = (bc_grouping + 1) / 2; + double BCgranularity = Geo::BC_TIME_INPS * bc_grouping; - auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time! - auto& cacheTrk = mTracksSectIndexCache[sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! + ///< do the real matching per sector + auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time! + auto& cacheTrk = mTracksSectIndexCache[trkType::UNCONS][sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time! int nTracks = cacheTrk.size(), nTOFCls = cacheTOF.size(); LOG(INFO) << "Matching sector " << sec << ": number of tracks: " << nTracks << ", number of TOF clusters: " << nTOFCls; if (!nTracks || !nTOFCls) { @@ -1167,22 +718,31 @@ void MatchTOF::doMatchingForTPC(int sec) std::vector<std::array<int, 2>> nStepsInsideSameStrip; LOG(DEBUG) << "Trying to match %d tracks" << cacheTrk.size(); + for (int itrk = 0; itrk < cacheTrk.size(); itrk++) { - auto& trackWork = mTracksWork[cacheTrk[itrk]]; + auto& trackWork = mTracksWork[trkType::UNCONS][cacheTrk[itrk]]; auto& trefTrk = trackWork.first; - auto& intLT = mLTinfos[cacheTrk[itrk]]; + auto& intLT = mLTinfos[trkType::UNCONS][cacheTrk[itrk]]; - int nBCcand = 1; BCcand.clear(); nStripsCrossedInPropagation.clear(); int side = mSideTPC[cacheTrk[itrk]]; - // look at BC candidates for the track - itof0 = 0; double minTrkTime = (trackWork.second.getTimeStamp() - trackWork.second.getTimeStampError()) * 1.E6; // minimum time in ps + minTrkTime = int(minTrkTime / BCgranularity) * BCgranularity; // align min to a BC double maxTrkTime = (trackWork.second.getTimeStamp() + mExtraTPCFwdTime[cacheTrk[itrk]]) * 1.E6; // maximum time in ps + if (mIsCosmics) { + for (double tBC = minTrkTime; tBC < maxTrkTime; tBC += BCgranularity) { + unsigned long ibc = (unsigned long)(tBC * Geo::BC_TIME_INPS_INV); + BCcand.emplace_back(ibc); + nStripsCrossedInPropagation.emplace_back(0); + } + } + + int itofMax = nTOFCls; + for (auto itof = itof0; itof < nTOFCls; itof++) { auto& trefTOF = mTOFClusWork[cacheTOF[itof]]; @@ -1192,6 +752,7 @@ void MatchTOF::doMatchingForTPC(int sec) } if (trefTOF.getTime() > maxTrkTime) { // this cluster has a time that is too large for the current track, close loop + itofMax = itof; break; } @@ -1201,6 +762,8 @@ void MatchTOF::doMatchingForTPC(int sec) unsigned long bc = (unsigned long)(trefTOF.getTime() * Geo::BC_TIME_INPS_INV); + bc = (bc / bc_grouping_half) * bc_grouping_half; + bool isalreadyin = false; for (int k = 0; k < BCcand.size(); k++) { @@ -1214,6 +777,7 @@ void MatchTOF::doMatchingForTPC(int sec) nStripsCrossedInPropagation.emplace_back(0); } } + detId.clear(); detId.reserve(BCcand.size()); trkLTInt.clear(); @@ -1223,13 +787,12 @@ void MatchTOF::doMatchingForTPC(int sec) nStepsInsideSameStrip.clear(); nStepsInsideSameStrip.reserve(BCcand.size()); - // printf("%d) ts_error = %f -- z_error = %f\n", itrk, trackWork.second.getTimeStampError(), trackWork.second.getTimeStampError() * vdrift); - // Printf("intLT (before doing anything): length = %f, time (Pion) = %f", intLT.getL(), intLT.getTOF(o2::track::PID::Pion)); int istep = 1; // number of steps float step = 1.0; // step size in cm - //uncomment for local debug - /* + + //uncomment for local debug + /* //trefTrk.getXYZGlo(posBeforeProp); //float posBeforeProp[3] = {trefTrk.getX(), trefTrk.getY(), trefTrk.getZ()}; // in local ref system //printf("Global coordinates: posBeforeProp[0] = %f, posBeforeProp[1] = %f, posBeforeProp[2] = %f\n", posBeforeProp[0], posBeforeProp[1], posBeforeProp[2]); @@ -1237,13 +800,6 @@ void MatchTOF::doMatchingForTPC(int sec) //Printf("Radius xyz = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1] + posBeforeProp[2]*posBeforeProp[2])); */ -#ifdef _ALLOW_TOF_DEBUG_ - if (mDBGFlags) { - (*mDBGOut) << "propOK" - << "track=" << trefTrk << "\n"; - } -#endif - int detIdTemp[5] = {-1, -1, -1, -1, -1}; // TOF detector id at the current propagation point double reachedPoint = mXRef + istep * step; @@ -1258,17 +814,18 @@ void MatchTOF::doMatchingForTPC(int sec) } } while (propagateToRefX(trefTrk, reachedPoint, step, intLT) && reachedPoint < Geo::RMAX) { - // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, o2::constants::physics::MassPionCharged, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) { + // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) { trefTrk.getXYZGlo(pos); for (int ii = 0; ii < 3; ii++) { // we need to change the type... posFloat[ii] = pos[ii]; } + // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step /* - Printf("posFloat[0] = %f, posFloat[1] = %f, posFloat[2] = %f", posFloat[0], posFloat[1], posFloat[2]); - Printf("radius xy = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1])); - Printf("radius xyz = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1] + posFloat[2]*posFloat[2])); + Printf("posFloat[0] = %f, posFloat[1] = %f, posFloat[2] = %f", posFloat[0], posFloat[1], posFloat[2]); + Printf("radius xy = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1])); + Printf("radius xyz = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1] + posFloat[2]*posFloat[2])); */ reachedPoint += step; @@ -1287,7 +844,7 @@ void MatchTOF::doMatchingForTPC(int sec) posFloat[2] = pos[2]; } - Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp); + Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp, sec); if (detIdTemp[2] == -1) { continue; @@ -1328,14 +885,13 @@ void MatchTOF::doMatchingForTPC(int sec) } } for (int ibc = 0; ibc < BCcand.size(); ibc++) { - float minTime = (BCcand[ibc] - 1) * Geo::BC_TIME_INPS; - float maxTime = (BCcand[ibc] + 1) * Geo::BC_TIME_INPS; + float minTime = (BCcand[ibc] - bc_grouping_tolerance) * Geo::BC_TIME_INPS; + float maxTime = (BCcand[ibc] + bc_grouping_tolerance) * Geo::BC_TIME_INPS; for (Int_t imatch = 0; imatch < nStripsCrossedInPropagation[ibc]; imatch++) { // we take as residual the average of the residuals along the propagation in the same strip deltaPos[ibc][imatch][0] /= nStepsInsideSameStrip[ibc][imatch]; deltaPos[ibc][imatch][1] /= nStepsInsideSameStrip[ibc][imatch]; deltaPos[ibc][imatch][2] /= nStepsInsideSameStrip[ibc][imatch]; - // LOG(DEBUG) << "matched strip " << imatch << ": deltaPos[0] = " << deltaPos[imatch][0] << ", deltaPos[1] = " << deltaPos[imatch][1] << ", deltaPos[2] = " << deltaPos[imatch][2] << ", residual (x, z) = " << TMath::Sqrt(deltaPos[imatch][0] * deltaPos[imatch][0] + deltaPos[imatch][2] * deltaPos[imatch][2]); } if (nStripsCrossedInPropagation[ibc] == 0) { @@ -1343,16 +899,12 @@ void MatchTOF::doMatchingForTPC(int sec) } bool foundCluster = false; - itof0 = 0; - for (auto itof = itof0; itof < nTOFCls; itof++) { + for (auto itof = itof0; itof < itofMax; itof++) { // printf("itof = %d\n", itof); auto& trefTOF = mTOFClusWork[cacheTOF[itof]]; // compare the times of the track and the TOF clusters - remember that they both are ordered in time! - //Printf("trefTOF.getTime() = %f, maxTrkTime = %f, minTrkTime = %f", trefTOF.getTime(), maxTrkTime, minTrkTime); if (trefTOF.getTime() < minTime) { // this cluster has a time that is too small for the current track, we will get to the next one - //Printf("In trefTOF.getTime() < minTrkTime"); - itof0 = itof + 1; // but for the next track that we will check, we will ignore this cluster (the time is anyway too small) continue; } if (trefTOF.getTime() > maxTime) { // no more TOF clusters can be matched to this track @@ -1363,6 +915,19 @@ void MatchTOF::doMatchingForTPC(int sec) int indices[5]; Geo::getVolumeIndices(mainChannel, indices); + bool isInStrip = false; + for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation[ibc]; iPropagation++) { + if (detId[ibc][iPropagation][1] == indices[1] && detId[ibc][iPropagation][2] == indices[2]) { + isInStrip = true; + } + } + + if (!isInStrip) { + continue; + } + + unsigned long bcClus = trefTOF.getTime() * Geo::BC_TIME_INPS_INV; + // compute fine correction using cluster position instead of pad center // this because in case of multiple-hit cluster position is averaged on all pads contributing to the cluster (then error position matrix can be used for Chi2 if nedeed) int ndigits = 1; @@ -1404,11 +969,21 @@ void MatchTOF::doMatchingForTPC(int sec) int eventIdTOF; int sourceIdTOF; for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation[ibc]; iPropagation++) { + if (detId[ibc][iPropagation][1] != indices[1] || detId[ibc][iPropagation][2] != indices[2]) { + continue; + } + LOG(DEBUG) << "TOF Cluster [" << itof << ", " << cacheTOF[itof] << "]: indices = " << indices[0] << ", " << indices[1] << ", " << indices[2] << ", " << indices[3] << ", " << indices[4]; - LOG(DEBUG) << "Propagated Track [" << itrk << ", " << cacheTrk[itrk] << "]: detId[" << iPropagation << "] = " << detId[ibc][iPropagation][0] << ", " << detId[ibc][iPropagation][1] << ", " << detId[ibc][iPropagation][2] << ", " << detId[ibc][iPropagation][3] << ", " << detId[ibc][iPropagation][4]; + LOG(DEBUG) << "Propagated Track [" << itrk << "]: detId[" << iPropagation << "] = " << detId[ibc][iPropagation][0] << ", " << detId[ibc][iPropagation][1] << ", " << detId[ibc][iPropagation][2] << ", " << detId[ibc][iPropagation][3] << ", " << detId[ibc][iPropagation][4]; float resX = deltaPos[ibc][iPropagation][0] - (indices[4] - detId[ibc][iPropagation][4]) * Geo::XPAD + posCorr[0]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster float resZ = deltaPos[ibc][iPropagation][2] - (indices[3] - detId[ibc][iPropagation][3]) * Geo::ZPAD + posCorr[2]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster + if (BCcand[ibc] > bcClus) { + resZ += (BCcand[ibc] - bcClus) * vdriftInBC * side; // add bc correction + } else { + resZ -= (bcClus - BCcand[ibc]) * vdriftInBC * side; + } float res = TMath::Sqrt(resX * resX + resZ * resZ); + if (indices[0] != detId[ibc][iPropagation][0]) { continue; } @@ -1418,23 +993,19 @@ void MatchTOF::doMatchingForTPC(int sec) if (indices[2] != detId[ibc][iPropagation][2]) { continue; } + LOG(DEBUG) << "resX = " << resX << ", resZ = " << resZ << ", res = " << res; - float chi2 = res; // TODO: take into account also the time! + float chi2 = mIsCosmics ? resX : res; // TODO: take into account also the time! if (res < mSpaceTolerance) { // matching ok! - LOG(DEBUG) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[indices[0]][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof]; + LOG(DEBUG) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[trkType::UNCONS][sec][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof]; foundCluster = true; // set event indexes (to be checked) - evIdx eventIndexTOFCluster(trefTOF.getEntryInTree(), mTOFClusSectIndexCache[indices[0]][itof]); - evIdx eventIndexTracks(mCurrTracksTreeEntry, mTracksSectIndexCache[indices[0]][itrk]); - mMatchedTracksPairs.emplace_back(o2::dataformats::MatchInfoTOF(eventIndexTOFCluster, chi2, trkLTInt[ibc][iPropagation], eventIndexTracks)); // TODO: check if this is correct! + int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof]; + mMatchedTracksPairs.emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[ibc][iPropagation], mTrackGid[trkType::UNCONS][cacheTrk[itrk]], trkType::UNCONS, resZ / vdrift * side, trefTOF.getZ()); // TODO: check if this is correct! } } } - if (!foundCluster && mMCTruthON) { - const auto& labelTPC = mTPCLabels[mTracksSectIndexCache[sec][itrk]]; - LOG(DEBUG) << "We did not find any TOF cluster for track " << cacheTrk[itrk] << " (label = " << labelTPC << ", pt = " << trefTrk.getPt(); - } } } return; @@ -1467,24 +1038,41 @@ int MatchTOF::findFITIndex(int bc) //______________________________________________ void MatchTOF::selectBestMatches() { + if (mSetHighPurity) { + selectBestMatchesHP(); + return; + } ///< define the track-TOFcluster pair per sector LOG(INFO) << "Number of pair matched = " << mMatchedTracksPairs.size(); // first, we sort according to the chi2 - std::sort(mMatchedTracksPairs.begin(), mMatchedTracksPairs.end(), [this](o2::dataformats::MatchInfoTOF& a, o2::dataformats::MatchInfoTOF& b) { return (a.getChi2() < b.getChi2()); }); + std::sort(mMatchedTracksPairs.begin(), mMatchedTracksPairs.end(), [this](o2::dataformats::MatchInfoTOFReco& a, o2::dataformats::MatchInfoTOFReco& b) { return (a.getChi2() < b.getChi2()); }); int i = 0; + // then we take discard the pairs if their track or cluster was already matched (since they are ordered in chi2, we will take the best matching) - for (const o2::dataformats::MatchInfoTOF& matchingPair : mMatchedTracksPairs) { - if (mMatchedTracksIndex[matchingPair.getTrackIndex()] != -1) { // the track was already filled + for (const o2::dataformats::MatchInfoTOFReco& matchingPair : mMatchedTracksPairs) { + int trkType = (int)matchingPair.getTrackType(); + + int itrk = matchingPair.getIdLocal(); + + if (mMatchedTracksIndex[trkType][itrk] != -1) { // the track was already filled continue; } - if (mMatchedClustersIndex[matchingPair.getTOFClIndex()] != -1) { // the track was already filled + if (mMatchedClustersIndex[matchingPair.getTOFClIndex()] != -1) { // the cluster was already filled continue; } - mMatchedTracksIndex[matchingPair.getTrackIndex()] = mMatchedTracks.size(); // index of the MatchInfoTOF correspoding to this track - mMatchedClustersIndex[matchingPair.getTOFClIndex()] = mMatchedTracksIndex[matchingPair.getTrackIndex()]; // index of the track that was matched to this cluster - mMatchedTracks.push_back(matchingPair); // array of MatchInfoTOF + mMatchedTracksIndex[trkType][itrk] = mMatchedTracks[trkType].size(); // index of the MatchInfoTOF correspoding to this track + mMatchedClustersIndex[matchingPair.getTOFClIndex()] = mMatchedTracksIndex[trkType][itrk]; // index of the track that was matched to this cluster + + int trkTypeSplitted = trkType; + auto sourceID = matchingPair.getTrackRef().getSource(); + if (sourceID == o2::dataformats::GlobalTrackID::TPCTRD) { + trkTypeSplitted = (int)trkType::TPCTRD; + } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) { + trkTypeSplitted = (int)trkType::ITSTPCTRD; + } + mMatchedTracks[trkTypeSplitted].push_back(matchingPair); // array of MatchInfoTOF // get fit info double t0info = 0; @@ -1498,51 +1086,135 @@ void MatchTOF::selectBestMatches() } } + const o2::track::TrackLTIntegral& intLT = matchingPair.getLTIntegralOut(); + // add also calibration infos mCalibInfoTOF.emplace_back(mTOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel(), int(mTOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() * 1E12), // add time stamp - mTOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - mLTinfos[matchingPair.getTrackIndex()].getTOF(o2::track::PID::Pion) - t0info, + mTOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion) - t0info, mTOFClusWork[matchingPair.getTOFClIndex()].getTot()); if (mMCTruthON) { - const auto& labelsTOF = mTOFClusLabels.getLabels(matchingPair.getTOFClIndex()); - const auto& labelTPC = mTPCLabels[matchingPair.getTrackIndex()]; - // we want to store positive labels independently of how they are flagged from TPC,ITS people - // o2::MCCompLabel labelTPC(abs(labelTPCor.getTrackID()), labelTPCor.getEventID(), labelTPCor.getSourceID()); - // o2::MCCompLabel labelITS(abs(labelITSor.getTrackID()), labelITSor.getEventID(), labelITSor.getSourceID()); - LOG(DEBUG) << "TPC label" << labelTPC; - bool labelOk = false; // whether we have found or not the same TPC label of the track among the labels of the TOF cluster - - for (int ilabel = 0; ilabel < labelsTOF.size(); ilabel++) { - LOG(DEBUG) << "TOF label " << ilabel << labelsTOF[ilabel]; - if (labelsTOF[ilabel].getTrackID() == labelTPC.getTrackID() && labelsTOF[ilabel].getEventID() == labelTPC.getEventID() && labelsTOF[ilabel].getSourceID() == labelTPC.getSourceID() && !labelOk) { // if we find one TOF cluster label that is the same as the TPC one, we are happy - even if it is not the first one - mOutTOFLabels.push_back(labelsTOF[ilabel]); - labelOk = true; + const auto& labelsTOF = mTOFClusLabels->getLabels(matchingPair.getTOFClIndex()); + auto& labelTrack = mTracksLblWork[trkType][itrk]; + // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative + bool fake = true; + for (auto& lbl : labelsTOF) { + if (labelTrack == lbl) { // compares src, evID, trID, ignores fake flag. + fake = false; } } - if (!labelOk) { - // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative - //assert(labelsTOF.size()); - if (!labelsTOF.size()) { - throw std::runtime_error("TOF label not found since size of label is zero. This should not happen!!!!"); - } - mOutTOFLabels.emplace_back(labelsTOF[0].getTrackID(), labelsTOF[0].getEventID(), labelsTOF[0].getSourceID(), true); + mOutTOFLabels[trkTypeSplitted].emplace_back(labelsTOF[0].getTrackID(), labelsTOF[0].getEventID(), labelsTOF[0].getSourceID(), fake); + } + i++; + } +} +//______________________________________________ +void MatchTOF::selectBestMatchesHP() +{ + ///< define the track-TOFcluster pair per sector + float chi2SeparationCut = 2; + float chi2S = 3; + + LOG(INFO) << "Number of pair matched = " << mMatchedTracksPairs.size(); + + std::vector<o2::dataformats::MatchInfoTOFReco> tmpMatch; + + // first, we sort according to the chi2 + std::sort(mMatchedTracksPairs.begin(), mMatchedTracksPairs.end(), [this](o2::dataformats::MatchInfoTOFReco& a, o2::dataformats::MatchInfoTOFReco& b) { return (a.getChi2() < b.getChi2()); }); + int i = 0; + // then we take discard the pairs if their track or cluster was already matched (since they are ordered in chi2, we will take the best matching) + for (const o2::dataformats::MatchInfoTOFReco& matchingPair : mMatchedTracksPairs) { + int trkType = (int)matchingPair.getTrackType(); + + int itrk = matchingPair.getIdLocal(); + + bool discard = matchingPair.getChi2() > chi2S; + + if (mMatchedTracksIndex[trkType][itrk] != -1) { // the track was already filled, check if this competitor is not too close + auto winnerChi = tmpMatch[mMatchedTracksIndex[trkType][itrk]].getChi2(); + if (winnerChi < 0) { // the winner was already discarded as ambiguous + continue; } - mOutTPCLabels.push_back(labelTPC); - if (mIsITSused) { - const auto& labelITS = mITSLabels[matchingPair.getTrackIndex()]; - LOG(DEBUG) << "ITS label" << labelITS; - mOutITSLabels.push_back(labelITS); + if (matchingPair.getChi2() - winnerChi < chi2SeparationCut) { // discard previously validated winner and it has too close competitor + tmpMatch[mMatchedTracksIndex[trkType][itrk]].setChi2(-1); } + continue; + } + + if (mMatchedClustersIndex[matchingPair.getTOFClIndex()] != -1) { // the cluster was already filled, check if this competitor is not too close + auto winnerChi = tmpMatch[mMatchedClustersIndex[matchingPair.getTOFClIndex()]].getChi2(); + if (winnerChi < 0) { // the winner was already discarded as ambiguous + continue; + } + if (matchingPair.getChi2() - winnerChi < chi2SeparationCut) { // discard previously validated winner and it has too close competitor + tmpMatch[mMatchedClustersIndex[matchingPair.getTOFClIndex()]].setChi2(-1); + } + continue; + } + + if (!discard) { + mMatchedTracksIndex[trkType][itrk] = tmpMatch.size(); // index of the MatchInfoTOF correspoding to this track + mMatchedClustersIndex[matchingPair.getTOFClIndex()] = mMatchedTracksIndex[trkType][itrk]; // index of the track that was matched to this clus + tmpMatch.push_back(matchingPair); + } + } + + // now write final matches skipping disabled ones + for (auto& matchingPair : tmpMatch) { + if (matchingPair.getChi2() <= 0) { + continue; + } + int trkType = (int)matchingPair.getTrackType(); + int itrk = matchingPair.getIdLocal(); + + int trkTypeSplitted = trkType; + auto sourceID = matchingPair.getTrackRef().getSource(); + if (sourceID == o2::dataformats::GlobalTrackID::TPCTRD) { + trkTypeSplitted = (int)trkType::TPCTRD; + } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) { + trkTypeSplitted = (int)trkType::ITSTPCTRD; + } + mMatchedTracks[trkTypeSplitted].push_back(matchingPair); // array of MatchInfoTOF + + // get fit info + double t0info = 0; + + if (mFITRecPoints.size() > 0) { + int index = findFITIndex(mTOFClusWork[matchingPair.getTOFClIndex()].getBC()); + + if (index > -1) { + o2::InteractionRecord ir = mFITRecPoints[index].getInteractionRecord(); + t0info = ir.bc2ns() * 1E3; + } + } + + const o2::track::TrackLTIntegral& intLT = matchingPair.getLTIntegralOut(); + + // add also calibration infos + mCalibInfoTOF.emplace_back(mTOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel(), + int(mTOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() * 1E12), // add time stamp + mTOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion) - t0info, + mTOFClusWork[matchingPair.getTOFClIndex()].getTot()); + if (mMCTruthON) { + const auto& labelsTOF = mTOFClusLabels->getLabels(matchingPair.getTOFClIndex()); + auto& labelTrack = mTracksLblWork[trkType][itrk]; + // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative + bool fake = true; + for (auto& lbl : labelsTOF) { + if (labelTrack == lbl) { // compares src, evID, trID, ignores fake flag. + fake = false; + } + } + mOutTOFLabels[trkTypeSplitted].emplace_back(labelsTOF[0].getTrackID(), labelsTOF[0].getEventID(), labelsTOF[0].getSourceID(), fake); } - i++; } } //______________________________________________ bool MatchTOF::propagateToRefX(o2::track::TrackParCov& trc, float xRef, float stepInCm, o2::track::TrackLTIntegral& intLT) { // propagate track to matching reference X - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; // material correction method - const float tanHalfSector = tan(o2::constants::math::SectorSpanRad / 2); + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; // material correction method + static const float tanHalfSector = tan(o2::constants::math::SectorSpanRad / 2); bool refReached = false; float xStart = trc.getX(); // the first propagation will be from 2m, if the track is not at least at 2m @@ -1550,7 +1222,7 @@ bool MatchTOF::propagateToRefX(o2::track::TrackParCov& trc, float xRef, float st xStart = 50.; } int istep = 1; - bool hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, o2::constants::physics::MassPionCharged, MAXSNP, stepInCm, matCorr, &intLT); + bool hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, MAXSNP, stepInCm, matCorr, &intLT); while (hasPropagated) { if (trc.getX() > xRef) { refReached = true; // we reached the 371cm reference @@ -1561,14 +1233,14 @@ bool MatchTOF::propagateToRefX(o2::track::TrackParCov& trc, float xRef, float st //Printf("propagateToRefX: changing sector"); auto alphaNew = o2::math_utils::angle2Alpha(trc.getPhiPos()); if (!trc.rotate(alphaNew) != 0) { - // Printf("propagateToRefX: failed to rotate"); + // Printf("propagateToRefX: failed to rotate"); break; // failed (this line is taken from MatchTPCITS and the following comment too: RS: check effect on matching tracks to neighbouring sector) } } if (refReached) { break; } - hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, o2::constants::physics::MassPionCharged, MAXSNP, stepInCm, matCorr, &intLT); + hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, MAXSNP, stepInCm, matCorr, &intLT); } // if (std::abs(trc.getSnp()) > MAXSNP) Printf("propagateToRefX: condition on snp not ok, returning false"); @@ -1601,7 +1273,7 @@ bool MatchTOF::propagateToRefXWithoutCov(o2::track::TrackParCov& trc, float xRef //Printf("propagateToRefX: changing sector"); auto alphaNew = o2::math_utils::angle2Alpha(trcNoCov.getPhiPos()); if (!trcNoCov.rotateParam(alphaNew) != 0) { - // Printf("propagateToRefX: failed to rotate"); + // Printf("propagateToRefX: failed to rotate"); break; // failed (this line is taken from MatchTPCITS and the following comment too: RS: check effect on matching tracks to neighbouring sector) } } @@ -1626,44 +1298,90 @@ void MatchTOF::setDebugFlag(UInt_t flag, bool on) mDBGFlags &= ~flag; } } +//______________________________________________ +void MatchTOF::updateTimeDependentParams() +{ + ///< update parameters depending on time (once per TF) + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + auto& gasParam = o2::tpc::ParameterGas::Instance(); + mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds + mTPCTBinMUSInv = 1. / mTPCTBinMUS; + mTPCBin2Z = mTPCTBinMUS * gasParam.DriftV; + + mBz = o2::base::Propagator::Instance()->getNominalBz(); + mMaxInvPt = abs(mBz) > 0.1 ? 1. / (abs(mBz) * 0.05) : 999.; +} //_________________________________________________________ -void MatchTOF::fillTOFmatchTree(const char* trname, int cacheTOF, int sectTOF, int plateTOF, int stripTOF, int padXTOF, int padZTOF, int cacheeTrk, int crossedStrip, int sectPropagation, int platePropagation, int stripPropagation, int padXPropagation, int padZPropagation, float resX, float resZ, float res, matchTrack& trk, float intLength, float intTimePion, float timeTOF) +bool MatchTOF::makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCTOF& trConstr) { - ///< fill debug tree for TOF tracks matching check + auto& match = mMatchedTracks[trkType::TPC][matchedID]; + const auto& tpcTrOrig = mRecoCont->getTPCTrack(match.getTrackRef()); + const auto& tofCl = mTOFClustersArrayInp[match.getTOFClIndex()]; + const auto& intLT = match.getLTIntegralOut(); + + // correct the time of the track + auto timeTOFMUS = (tofCl.getTime() - intLT.getTOF(tpcTrOrig.getPID())) * 1e-6; // tof time in \mus, FIXME: account for time of flight to R TOF + auto timeTOFTB = timeTOFMUS * mTPCTBinMUSInv; // TOF time in TPC timebins + auto deltaTBins = timeTOFTB - tpcTrOrig.getTime0(); // time shift in timeBins + float timeErr = 0.010; // assume 10 ns error FIXME + auto dzCorr = deltaTBins * mTPCBin2Z; + + if (mTPCClusterIdxStruct) { // refit was requested + trConstr.o2::track::TrackParCov::operator=(tpcTrOrig.getOuterParam()); // seed for inward refit of constrained track, made from the outer param + trConstr.setParamOut(tpcTrOrig); // seed for outward refit of constrained track, made from the inner param + } else { + trConstr.o2::track::TrackParCov::operator=(tpcTrOrig); // inner param, we just correct its position, w/o refit + trConstr.setParamOut(tpcTrOrig.getOuterParam()); // outer param, we just correct its position, w/o refit + } - mTimerDBG.Start(false); + auto& trConstrOut = trConstr.getParamOut(); - // Printf("************** Filling the debug tree with %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %f, %f, %f", cacheTOF, sectTOF, plateTOF, stripTOF, padXTOF, padZTOF, cacheeTrk, crossedStrip, sectPropagation, platePropagation, stripPropagation, padXPropagation, padZPropagation, resX, resZ, res); + auto zTrack = trConstr.getZ(); + auto zTrackOut = trConstrOut.getZ(); - if (mDBGFlags) { - (*mDBGOut) << trname - << "clusterTOF=" << cacheTOF << "sectTOF=" << sectTOF << "plateTOF=" << plateTOF << "stripTOF=" << stripTOF << "padXTOF=" << padXTOF << "padZTOF=" << padZTOF - << "crossedStrip=" << crossedStrip << "sectPropagation=" << sectPropagation << "platePropagation=" << platePropagation << "stripPropagation=" << stripPropagation << "padXPropagation=" << padXPropagation - << "resX=" << resX << "resZ=" << resZ << "res=" << res << "track=" << trk.first << "intLength=" << intLength << "intTimePion=" << intTimePion << "timeTOF=" << timeTOF << "\n"; + if (tpcTrOrig.hasASideClustersOnly()) { + zTrack += dzCorr; + zTrackOut += dzCorr; + } else if (tpcTrOrig.hasCSideClustersOnly()) { + zTrack -= dzCorr; + zTrackOut -= dzCorr; + } else { + // TODO : special treatment of tracks crossing the CE + } + trConstr.setZ(zTrack); + trConstrOut.setZ(zTrackOut); + // + trConstr.setTimeMUS(timeTOFMUS, timeErr); + trConstr.setRefMatch(matchedID); + if (mTPCClusterIdxStruct) { // refit was requested + float chi2 = 0; + mTPCRefitter->setTrackReferenceX(o2::constants::geom::XTPCInnerRef); + if (mTPCRefitter->RefitTrackAsTrackParCov(trConstr, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, false, true) < 0) { // outward refit after resetting cov.mat. + LOG(DEBUG) << "Inward Refit failed"; + return false; + } + trConstr.setChi2Refit(chi2); + // + mTPCRefitter->setTrackReferenceX(o2::constants::geom::XTPCOuterRef); + if (mTPCRefitter->RefitTrackAsTrackParCov(trConstrOut, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, true, true) < 0) { // outward refit after resetting cov.mat. + LOG(DEBUG) << "Outward refit failed"; + return false; + } } - mTimerDBG.Stop(); -} + return true; +} //_________________________________________________________ -void MatchTOF::fillTOFmatchTreeWithLabels(const char* trname, int cacheTOF, int sectTOF, int plateTOF, int stripTOF, int padXTOF, int padZTOF, int cacheeTrk, int crossedStrip, int sectPropagation, int platePropagation, int stripPropagation, int padXPropagation, int padZPropagation, float resX, float resZ, float res, matchTrack& trk, int TPClabelTrackID, int TPClabelEventID, int TPClabelSourceID, int ITSlabelTrackID, int ITSlabelEventID, int ITSlabelSourceID, int TOFlabelTrackID0, int TOFlabelEventID0, int TOFlabelSourceID0, int TOFlabelTrackID1, int TOFlabelEventID1, int TOFlabelSourceID1, int TOFlabelTrackID2, int TOFlabelEventID2, int TOFlabelSourceID2, float intLength, float intTimePion, float timeTOF) +void MatchTOF::checkRefitter() { - ///< fill debug tree for TOF tracks matching check - - mTimerDBG.Start(false); - - if (mDBGFlags) { - (*mDBGOut) << trname - << "clusterTOF=" << cacheTOF << "sectTOF=" << sectTOF << "plateTOF=" << plateTOF << "stripTOF=" << stripTOF << "padXTOF=" << padXTOF << "padZTOF=" << padZTOF - << "crossedStrip=" << crossedStrip << "sectPropagation=" << sectPropagation << "platePropagation=" << platePropagation << "stripPropagation=" << stripPropagation << "padXPropagation=" << padXPropagation - << "resX=" << resX << "resZ=" << resZ << "res=" << res << "track=" << trk.first - << "TPClabelTrackID=" << TPClabelTrackID << "TPClabelEventID=" << TPClabelEventID << "TPClabelSourceID=" << TPClabelSourceID - << "ITSlabelTrackID=" << ITSlabelTrackID << "ITSlabelEventID=" << ITSlabelEventID << "ITSlabelSourceID=" << ITSlabelSourceID - << "TOFlabelTrackID0=" << TOFlabelTrackID0 << "TOFlabelEventID0=" << TOFlabelEventID0 << "TOFlabelSourceID0=" << TOFlabelSourceID0 - << "TOFlabelTrackID1=" << TOFlabelTrackID1 << "TOFlabelEventID1=" << TOFlabelEventID1 << "TOFlabelSourceID1=" << TOFlabelSourceID1 - << "TOFlabelTrackID2=" << TOFlabelTrackID2 << "TOFlabelEventID2=" << TOFlabelEventID2 << "TOFlabelSourceID2=" << TOFlabelSourceID2 - << "intLength=" << intLength << "intTimePion=" << intTimePion << "timeTOF=" << timeTOF - << "\n"; + if (mTPCClusterIdxStruct) { + if (!mTPCTransform) { // eventually, should be updated at every TF? + mTPCTransform = o2::tpc::TPCFastTransformHelperO2::instance()->create(0); + } + + mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCTransform.get(), mBz, + mTPCTrackClusIdx.data(), mTPCRefitterShMap.data(), + nullptr, o2::base::Propagator::Instance()); } - mTimerDBG.Stop(); } diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index 118fb9cd5a5f6..27cd3ba884857 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -1,23 +1,21 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include <TSystem.h> #include <TTree.h> -#include <TSystem.h> #include <cassert> #include "FairLogger.h" #include "Field/MagneticField.h" #include "Field/MagFieldFast.h" #include "ITSBase/GeometryTGeo.h" - #include "CommonUtils/TreeStream.h" #include "DataFormatsTPC/Defs.h" @@ -28,6 +26,7 @@ #include "MathUtils/Utils.h" #include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" +#include "CommonConstants/GeomConstants.h" #include "DetectorsBase/GeometryManager.h" #include <Math/SMatrix.h> @@ -36,204 +35,32 @@ #include <TGeoGlobalMagField.h> #include "DataFormatsParameters/GRPObject.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "GlobalTracking/MatchTPCITS.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "ReconstructionDataFormats/Vertex.h" +#include "GlobalTracking/MatchTPCITS.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DataFormatsTPC/WorkflowHelper.h" + +#include "ITStracking/IOUtils.h" #include "GPUO2Interface.h" // Needed for propper settings in GPUParam.h -#include "GPUParam.inc" // Consider more universal access + +#ifdef WITH_OPENMP +#include <omp.h> +#endif using namespace o2::globaltracking; using MatrixDSym4 = ROOT::Math::SMatrix<double, 4, 4, ROOT::Math::MatRepSym<double, 4>>; using MatrixD4 = ROOT::Math::SMatrix<double, 4, 4, ROOT::Math::MatRepStd<double, 4>>; using NAMES = o2::base::NameConf; - -constexpr float MatchTPCITS::XTPCInnerRef; -constexpr float MatchTPCITS::XTPCOuterRef; +using GTrackID = o2::dataformats::GlobalTrackID; constexpr float MatchTPCITS::XMatchingRef; constexpr float MatchTPCITS::YMaxAtXMatchingRef; constexpr float MatchTPCITS::Tan70, MatchTPCITS::Cos70I2, MatchTPCITS::MaxSnp, MatchTPCITS::MaxTgp; -//______________________________________________ -void MatchTPCITS::printABTracksTree(const ABTrackLinksList& llist) const -{ - // dump all hypotheses - if (llist.lowestLayer == NITSLayers) { - printf("No matches\n"); - return; - } - o2::MCCompLabel lblTrc; - if (mMCTruthON) { - lblTrc = mTPCTrkLabels[mTPCWork[llist.trackID].sourceID]; - } - LOG(INFO) << "Matches for track " << llist.trackID << " lowest lr: " << int(llist.lowestLayer) << " " << lblTrc - << " pT= " << mTPCWork[llist.trackID].getPt(); - - auto printHyp = [this, &lblTrc](int nextHyp, int cnt) { - printf("#%d Lr/IC/Lnk/ClID/Chi2/Chi2Nrm/{MC}:%c ", cnt++, mTPCTrkLabels.size() ? (lblTrc.isFake() ? 'F' : 'C') : '-'); - int nFakeClus = 0, nTotClus = 0, parID = nextHyp; // print particular hypothesis - while (1) { - const auto& lnk = mABTrackLinks[parID]; - int mcEv = -1, mcTr = -1; - if (lnk.clID > MinusOne && mITSClsLabels) { - nTotClus++; - const auto lab = mITSClsLabels->getLabels(lnk.clID)[0]; - if (lab.isValid()) { - mcEv = lab.getEventID(); - mcTr = lab.getTrackID(); - if (mcEv != lblTrc.getEventID() || mcTr != lblTrc.getTrackID()) { - nFakeClus++; - } - } else { - mcEv = mcTr = -999; // noise - nFakeClus++; - } - } else if (lnk.isDummyTop() && mMCTruthON) { // top layer, use TPC MC lbl - mcEv = lblTrc.getEventID(); - mcTr = lblTrc.getTrackID(); - } - printf("[%d/%d/%d/%d/%6.2f/%6.2f/{%d/%d}]", lnk.layerID, lnk.icCandID, parID, lnk.clID, lnk.chi2, lnk.chi2Norm(), mcEv, mcTr); - if (lnk.isDummyTop()) { // reached dummy seed on the dummy layer above the last ITS layer - break; - } - parID = lnk.parentID; - } - printf(" NTot:%d NFakes:%d\n", nTotClus, nFakeClus); - }; - - int cnt = 0; // tmp - for (int lowest = llist.lowestLayer; lowest <= mParams->requireToReachLayerAB; lowest++) { - int nextHyp = llist.firstInLr[lowest]; - while (nextHyp > MinusOne) { - if (mABTrackLinks[nextHyp].nDaughters == 0) { // select only head links, w/o daughters - printHyp(nextHyp, cnt++); - } - nextHyp = mABTrackLinks[nextHyp].nextOnLr; - } - } - - if (llist.bestOrdLinkID > MinusOne) { // print best matches list - int next = llist.bestOrdLinkID; - LOG(INFO) << "Best matches:"; - int cnt = 0; - while (next > MinusOne) { - const auto& lnkOrd = mABBestLinks[next]; - int nextHyp = lnkOrd.trackLinkID; - printHyp(nextHyp, cnt++); - next = lnkOrd.nextLinkID; - refitABTrack(nextHyp); - } - } -} - -//______________________________________________ -void MatchTPCITS::dumpABTracksDebugTree(const ABTrackLinksList& llist) -{ - // dump all hypotheses - static int entCnt = 0; - if (llist.lowestLayer == NITSLayers) { - return; - } - LOG(INFO) << "Dump AB Matches for track " << llist.trackID; - o2::MCCompLabel lblTrc; - if (mMCTruthON) { - lblTrc = mTPCTrkLabels[mTPCWork[llist.trackID].sourceID]; // tmp - } - int ord = 0; - for (int lowest = llist.lowestLayer; lowest <= mParams->requireToReachLayerAB; lowest++) { - int nextHyp = llist.firstInLr[lowest]; - while (nextHyp > MinusOne) { - if (mABTrackLinks[nextHyp].nDaughters != 0) { // select only head links, w/o daughters - nextHyp = mABTrackLinks[nextHyp].nextOnLr; - continue; - } - // fill debug AB track - ABDebugTrack dbgTrack; - int parID = nextHyp; // print particular hypothesis - while (1) { - const auto& lnk = mABTrackLinks[parID]; - if (lnk.clID > MinusOne) { - auto& dbgLnk = dbgTrack.links.emplace_back(); -#ifdef _ALLOW_DEBUG_AB_ - dbgLnk.seed = lnk.seed; // seed before update -#endif - dbgLnk.clLabel = mITSClsLabels->getLabels(lnk.clID)[0]; - dbgLnk.chi2 = lnk.chi2; - dbgLnk.lr = lnk.layerID; - (o2::BaseCluster<float>&)dbgLnk = mITSClustersArray[lnk.clID]; - dbgTrack.nClusITS++; - if (lblTrc.getEventID() == dbgLnk.clLabel.getEventID() && std::abs(lblTrc.getTrackID()) == dbgLnk.clLabel.getTrackID()) { - dbgTrack.nClusITSCorr++; - } - } - if (lnk.isDummyTop()) { // reached dummy seed on the dummy layer above the last ITS layer - dbgTrack.tpcSeed = lnk; // tpc seed - dbgTrack.trackID = llist.trackID; - dbgTrack.tpcLabel = lblTrc; - dbgTrack.icCand = lnk.icCandID; - dbgTrack.icTimeBin = mInteractions[lnk.icCandID].timeBins; - const auto& tpcTrOrig = mTPCTracksArray[mTPCWork[llist.trackID].sourceID]; - unsigned nclTPC = tpcTrOrig.getNClusterReferences(); - dbgTrack.nClusTPC = nclTPC > 0xff ? 0xff : nclTPC; - dbgTrack.sideAC = tpcTrOrig.hasASideClusters() + (tpcTrOrig.hasCSideClusters() ? 2 : 0); - break; - } - parID = lnk.parentID; - } - dbgTrack.chi2 = dbgTrack.links.front().chi2; - // at the moment links contain cumulative chi2, convert to track-to-cluster chi2 - for (int i = 0; i < dbgTrack.nClusITS - 1; i++) { - dbgTrack.links[i].chi2 -= dbgTrack.links[i + 1].chi2; - } - // at the moment the links are stored from inner to outer layers, invert this order - for (int i = dbgTrack.nClusITS / 2; i--;) { - std::swap(dbgTrack.links[i], dbgTrack.links[dbgTrack.nClusITS - i - 1]); - } - dbgTrack.valid = ord == 0 && llist.isValidated(); - dbgTrack.order = ord++; - // dump debug track - (*mDBGOut) << "abtree" - << "trc=" << dbgTrack << "\n"; - entCnt++; - nextHyp = mABTrackLinks[nextHyp].nextOnLr; - } - } // loop over layers -} - -//______________________________________________ -void MatchTPCITS::printABClusterUsage() const -{ - // print links info of clusters involved in AB tracks - int ncl = mABClusterLinkIndex.size(); - for (int icl = 0; icl < ncl; icl++) { - int lnkIdx = mABClusterLinkIndex[icl]; - if (lnkIdx <= MinusOne) { // not used or used in standard ITS tracks - continue; - } - LOG(INFO) << "Links for cluster " << icl; - int count = 0; - while (lnkIdx > MinusOne) { - const auto& linkCl = mABClusterLinks[lnkIdx]; - const auto& linkTrack = mABTrackLinks[linkCl.linkedABTrack]; - // find top track link on the dummy layer - int topIdx = linkCl.linkedABTrack, nUp = 0; - while (1) { - if (mABTrackLinks[topIdx].isDummyTop()) { - break; - } - nUp++; - topIdx = mABTrackLinks[topIdx].parentID; - } - const auto& topTrack = mABTrackLinks[topIdx]; - printf("[#%d Tr:%d IC:%d Chi2:%.2f NP:%d]", count++, topTrack.parentID, linkTrack.icCandID, linkTrack.chi2, nUp); - lnkIdx = linkCl.nextABClusterLink; - } - printf("\n"); - } -} - //______________________________________________ MatchTPCITS::MatchTPCITS() = default; @@ -241,66 +68,65 @@ MatchTPCITS::MatchTPCITS() = default; MatchTPCITS::~MatchTPCITS() = default; //______________________________________________ -void MatchTPCITS::run() +void MatchTPCITS::run(const o2::globaltracking::RecoContainer& inp) { ///< perform matching for provided input if (!mInitDone) { LOG(FATAL) << "init() was not done yet"; } - updateTPCTimeDependentParams(); - - ProcInfo_t procInfoStart, procInfoStop; - gSystem->GetProcInfo(&procInfoStart); - constexpr uint64_t kMB = 1024 * 1024; - LOGF(info, "Memory (GB) at entrance: RSS: %.3f VMem: %.3f\n", float(procInfoStart.fMemResident) / kMB, float(procInfoStart.fMemVirtual) / kMB); + mRecoCont = &inp; + mStartIR = inp.startIR; + updateTimeDependentParams(); mTimer[SWTot].Start(false); clear(); + while (1) { + if (!prepareITSData() || !prepareTPCData() || !prepareFITData()) { + break; + } - if (!prepareITSTracks() || !prepareTPCTracks() || !prepareFITInfo()) { - return; - } - if (mUseFT0) { - prepareInteractionTimes(); - } - - mTimer[SWDoMatching].Start(false); - for (int sec = o2::constants::math::NSectors; sec--;) { - doMatching(sec); - } - mTimer[SWDoMatching].Stop(); - if (0) { // enabling this creates very verbose output - mTimer[SWTot].Stop(); - printCandidatesTPC(); - printCandidatesITS(); - mTimer[SWTot].Start(false); - } + mTimer[SWDoMatching].Start(false); + for (int sec = o2::constants::math::NSectors; sec--;) { + doMatching(sec); + } + mTimer[SWDoMatching].Stop(); + if (0) { // enabling this creates very verbose output + mTimer[SWTot].Stop(); + printCandidatesTPC(); + printCandidatesITS(); + mTimer[SWTot].Start(false); + } - selectBestMatches(); + selectBestMatches(); - refitWinners(); + refitWinners(); - if (mUseFT0 && Params::Instance().runAfterBurner) { - runAfterBurner(); - } + if (mUseFT0 && Params::Instance().runAfterBurner) { + runAfterBurner(); + } #ifdef _ALLOW_DEBUG_TREES_ - if (mDBGOut && isDebugFlag(WinnerMatchesTree)) { - dumpWinnerMatches(); - } - mDBGOut.reset(); + if (mDBGOut && isDebugFlag(WinnerMatchesTree)) { + dumpWinnerMatches(); + } #endif - - gSystem->GetProcInfo(&procInfoStop); + break; + } mTimer[SWTot].Stop(); for (int i = 0; i < NStopWatches; i++) { - LOGF(INFO, "Timing for %15s: Cpu: %.3e Real: %.3e s in %d slots", TimerName[i], mTimer[i].CpuTime(), mTimer[i].RealTime(), mTimer[i].Counter() - 1); + LOGF(INFO, "Timing for %15s: Cpu: %.3e Real: %.3e s in %d slots of TF#%d", TimerName[i], mTimer[i].CpuTime(), mTimer[i].RealTime(), mTimer[i].Counter() - 1, mTFCount); } - LOGF(INFO, "Memory (GB) at exit: RSS: %.3f VMem: %.3f", float(procInfoStop.fMemResident) / kMB, float(procInfoStop.fMemVirtual) / kMB); - LOGF(INFO, "Memory increment: RSS: %.3f VMem: %.3f", float(procInfoStop.fMemResident - procInfoStart.fMemResident) / kMB, - float(procInfoStop.fMemVirtual - procInfoStart.fMemVirtual) / kMB); + mTFCount++; +} + +//______________________________________________ +void MatchTPCITS::end() +{ +#ifdef _ALLOW_DEBUG_TREES_ + mDBGOut.reset(); +#endif } //______________________________________________ @@ -311,9 +137,32 @@ void MatchTPCITS::clear() mMatchRecordsITS.clear(); mWinnerChi2Refit.clear(); mMatchedTracks.clear(); + mITSWork.clear(); + mTPCWork.clear(); + mInteractions.clear(); + mITSROFIntCandEntries.clear(); + mITSROFTimes.clear(); + mITSTrackROFContMapping.clear(); + mITSClustersArray.clear(); + mTPCABSeeds.clear(); + mTPCABIndexCache.clear(); + mABWinnersIDs.clear(); + mABClusterLinkIndex.clear(); + mABTrackletRefs.clear(); + mABTrackletClusterIDs.clear(); + mABTrackletLabels.clear(); + + for (int sec = o2::constants::math::NSectors; sec--;) { + mITSSectIndexCache[sec].clear(); + mITSTimeStart[sec].clear(); + mTPCSectIndexCache[sec].clear(); + mTPCTimeStart[sec].clear(); + } + if (mMCTruthON) { - mOutITSLabels.clear(); - mOutTPCLabels.clear(); + mOutLabels.clear(); + mITSROFTimes.clear(); + mTPCLblWork.clear(); } } @@ -339,18 +188,11 @@ void MatchTPCITS::init() } // make sure T2GRot matrices are loaded into ITS geometry helper - o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)); + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); mSectEdgeMargin2 = mParams->crudeAbsDiffCut[o2::track::kY] * mParams->crudeAbsDiffCut[o2::track::kY]; ///< precalculated ^2 std::unique_ptr<TPCTransform> fastTransform = (o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); mTPCTransform = std::move(fastTransform); - mTPCClusterParam = std::make_unique<o2::gpu::GPUParam>(); - mTPCClusterParam->SetDefaults(o2::base::Propagator::Instance()->getNominalBz()); // TODO this may change - auto bz = std::abs(o2::base::Propagator::Instance()->getNominalBz()); - mFieldON = bz > 0.01; - - mMinTPCTrackPtInv = (mFieldON && mParams->minTPCTrackR > 0) ? 1. / std::abs(mParams->minTPCTrackR * bz * o2::constants::math::B2C) : 999.; - mMinITSTrackPtInv = (mFieldON && mParams->minITSTrackR > 0) ? 1. / std::abs(mParams->minITSTrackR * bz * o2::constants::math::B2C) : 999.; if (mVDriftCalibOn) { float maxDTgl = std::min(0.02f, mParams->maxVDriftUncertainty) * mParams->maxTglForVDriftCalib; @@ -366,20 +208,20 @@ void MatchTPCITS::init() #endif mRGHelper.init(); // prepare helper for TPC track / ITS clusters matching - const auto& zr = mRGHelper.layers.back().zRange; - mITSFiducialZCut = std::max(std::abs(zr.getMin()), std::abs(zr.getMax())) + 20.; clear(); mInitDone = true; - print(); + if (fair::Logger::Logging(fair::Severity::info)) { + print(); + } } //______________________________________________ -void MatchTPCITS::updateTPCTimeDependentParams() +void MatchTPCITS::updateTimeDependentParams() { - ///< update parameters depending on TPC drift properties + ///< update parameters depending on time (once per TF) auto& gasParam = o2::tpc::ParameterGas::Instance(); auto& elParam = o2::tpc::ParameterElectronics::Instance(); auto& detParam = o2::tpc::ParameterDetector::Instance(); @@ -389,17 +231,21 @@ void MatchTPCITS::updateTPCTimeDependentParams() mTPCZMax = detParam.TPClength; mTPCTBinMUSInv = 1. / mTPCTBinMUS; assert(mITSROFrameLengthMUS > 0.0f); - if (mITSTriggered) { - mITSROFrame2TPCBin = mITSROFrameLengthMUS * mTPCTBinMUSInv; - } else { - mITSROFrame2TPCBin = mITSROFrameLengthMUS * mTPCTBinMUSInv; // RSTODO use both ITS and TPC times BCs once will be available for TPC also - } - mTPCBin2ITSROFrame = 1. / mITSROFrame2TPCBin; mTPCBin2Z = mTPCTBinMUS * mTPCVDrift0; mZ2TPCBin = 1. / mTPCBin2Z; mTPCVDrift0Inv = 1. / mTPCVDrift0; mNTPCBinsFullDrift = mTPCZMax * mZ2TPCBin; mTPCTimeEdgeTSafeMargin = z2TPCBin(mParams->safeMarginTPCTimeEdge); + mTPCExtConstrainedNSigmaInv = 1.f / mParams->tpcExtConstrainedNSigma; + mBz = o2::base::Propagator::Instance()->getNominalBz(); + mFieldON = std::abs(mBz) > 0.01; + + mMinTPCTrackPtInv = (mFieldON && mParams->minTPCTrackR > 0) ? 1. / std::abs(mParams->minTPCTrackR * mBz * o2::constants::math::B2C) : 999.; + mMinITSTrackPtInv = (mFieldON && mParams->minITSTrackR > 0) ? 1. / std::abs(mParams->minITSTrackR * mBz * o2::constants::math::B2C) : 999.; + + o2::math_utils::Point3D<float> p0(90., 1., 1), p1(90., 100., 100.); + auto matbd = o2::base::Propagator::Instance()->getMatBudget(mParams->matCorr, p0, p1); + mTPCmeanX0Inv = matbd.meanX2X0 / matbd.length; } //______________________________________________ @@ -413,7 +259,6 @@ void MatchTPCITS::selectBestMatches() do { nValidated = 0; int ntpc = mTPCWork.size(), nremaining = 0; - ; for (int it = 0; it < ntpc; it++) { auto& tTPC = mTPCWork[it]; if (isDisabledTPC(tTPC) || isValidatedTPC(tTPC)) { @@ -498,84 +343,108 @@ int MatchTPCITS::getNMatchRecordsITS(const TrackLocITS& tTPC) const } //______________________________________________ -bool MatchTPCITS::prepareTPCTracks() +void MatchTPCITS::addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, GTrackID srcGID, int tpcID) +{ + // account single TPC seed, can be from standalone TPC track or constrained track from match to TRD and/or TOF + const float SQRT12DInv = 2. / sqrt(12.); + if (_tr.getX() > o2::constants::geom::XTPCInnerRef + 0.1 || std::abs(_tr.getQ2Pt()) > mMinTPCTrackPtInv) { + return; + } + const auto& tpcOrig = mTPCTracksArray[tpcID]; + // discard tracks w/o certain number of total or innermost pads (last cluster is innermost one) + if (tpcOrig.getNClusterReferences() < mParams->minTPCClusters) { + return; + } + uint8_t clSect = 0, clRow = 0; + uint32_t clIdx = 0; + tpcOrig.getClusterReference(mTPCTrackClusIdx, tpcOrig.getNClusterReferences() - 1, clSect, clRow, clIdx); + if (clRow > mParams->askMinTPCRow) { + return; + } + // create working copy of track param + bool extConstrained = srcGID.getSource() != GTrackID::TPC; + if (extConstrained) { + terr *= mParams->tpcExtConstrainedNSigma; + } else { + terr += tpcTimeBin2MUS(tpcOrig.hasBothSidesClusters() ? mParams->safeMarginTPCITSTimeBin : mTPCTimeEdgeTSafeMargin); + } + auto& trc = mTPCWork.emplace_back( + TrackLocTPC{_tr, {t0 - terr, t0 + terr}, extConstrained ? t0 : tpcTimeBin2MUS(tpcOrig.getTime0()), + // for A/C constrained tracks the terr is half-interval, for externally constrained tracks it is sigma*Nsigma + terr * (extConstrained ? mTPCExtConstrainedNSigmaInv : SQRT12DInv), + tpcID, + srcGID, + MinusOne, + (extConstrained || tpcOrig.hasBothSidesClusters()) ? TrackLocTPC::Constrained : (tpcOrig.hasASideClustersOnly() ? TrackLocTPC::ASide : TrackLocTPC::CSide)}); + // propagate to matching Xref + if (!propagateToRefX(trc)) { + mTPCWork.pop_back(); // discard track whose propagation to XMatchingRef failed + return; + } + if (mMCTruthON) { + mTPCLblWork.emplace_back(mTPCTrkLabels[tpcID]); + } + // cache work track index + mTPCSectIndexCache[o2::math_utils::angle2Sector(trc.getAlpha())].push_back(mTPCWork.size() - 1); +} + +//______________________________________________ +bool MatchTPCITS::prepareTPCData() { - ///< load next chunk of TPC data and prepare for matching + ///< load TPC data and prepare for matching mTimer[SWPrepTPC].Start(false); - mMatchRecordsTPC.clear(); + const auto& inp = *mRecoCont; - int ntr = mTPCTracksArray.size(); - // number of records might be actually more than N tracks! - mMatchRecordsTPC.reserve(mMatchRecordsTPC.size() + mParams->maxMatchCandidates * ntr); + mTPCTracksArray = inp.getTPCTracks(); + mTPCTrackClusIdx = inp.getTPCTracksClusterRefs(); + mTPCClusterIdxStruct = &inp.inputsTPCclusters->clusterIndex; + mTPCRefitterShMap = inp.clusterShMapTPC; + if (mMCTruthON) { + mTPCTrkLabels = inp.getTPCTracksMCLabels(); + } - // copy the track params, propagate to reference X and build sector tables - mTPCWork.clear(); + int ntr = mTPCTracksArray.size(); + mMatchRecordsTPC.reserve(mParams->maxMatchCandidates * ntr); // number of records might be actually more than N tracks! mTPCWork.reserve(ntr); if (mMCTruthON) { - mTPCLblWork.clear(); mTPCLblWork.reserve(ntr); } for (int sec = o2::constants::math::NSectors; sec--;) { - mTPCSectIndexCache[sec].clear(); mTPCSectIndexCache[sec].reserve(100 + 1.2 * ntr / o2::constants::math::NSectors); - mTPCTimeBinStart[sec].clear(); } - for (int it = 0; it < ntr; it++) { - - const auto& trcOrig = mTPCTracksArray[it]; - - // make sure the track was propagated to inner TPC radius at the ref. radius - if (trcOrig.getX() > XTPCInnerRef + 0.1 || std::abs(trcOrig.getQ2Pt()) > mMinTPCTrackPtInv) { - continue; + auto creator = [this](auto& trk, GTrackID gid, float time0, float terr) { + if constexpr (isITSTrack<decltype(trk)>()) { + // do nothing, ITS tracks will be processed in a direct loop over ROFs } - // discard tracks with too few clusters - if (trcOrig.getNClusterReferences() < mParams->minTPCClusters) { - continue; + if constexpr (!std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(trk)>>) { + return true; + } else if (std::abs(trk.getQ2Pt()) > mMinTPCTrackPtInv) { + return true; } - // discard tracks w/o certain number of innermost pads (last cluster is innermost one - { - uint8_t clSect = 0, clRow = 0; - uint32_t clIdx = 0; - trcOrig.getClusterReference(mTPCTrackClusIdx, trcOrig.getNClusterReferences() - 1, clSect, clRow, clIdx); - if (clRow > mParams->askMinTPCRow) { - continue; + if constexpr (isTPCTrack<decltype(trk)>()) { + // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins + if (!this->mSkipTPCOnly) { + this->addTPCSeed(trk, this->tpcTimeBin2MUS(time0), this->tpcTimeBin2MUS(terr), gid, gid.getIndex()); } } - - // create working copy of track param - mTPCWork.emplace_back(static_cast<const o2::track::TrackParCov&>(trcOrig), it); - auto& trc = mTPCWork.back(); - // propagate to matching Xref - if (!propagateToRefX(trc)) { - mTPCWork.pop_back(); // discard track whose propagation to XMatchingRef failed - continue; + if constexpr (isTPCTOFTrack<decltype(trk)>()) { + // TPC track constrained by TOF time, time and its error in \mus + this->addTPCSeed(trk, time0, terr, gid, this->mRecoCont->getTPCContributorGID(gid)); } - if (mMCTruthON) { - mTPCLblWork.emplace_back(mTPCTrkLabels[it]); + if constexpr (isTRDTrack<decltype(trk)>()) { + // TPC track constrained by TRD trigger time, time and its error in \mus + LOG(ERROR) << "Not ready yet for TPC-TRD tracks"; } - - float time0 = trcOrig.getTime0(); - trc.timeBins.set(time0 - trcOrig.getDeltaTBwd() - mTPCTimeEdgeTSafeMargin, - time0 + trcOrig.getDeltaTFwd() + mTPCTimeEdgeTSafeMargin); - // assign min max possible Z for this track which still respects the clusters A/C side - if (trcOrig.hasASideClustersOnly()) { - trc.zMin = trc.getZ() - trcOrig.getDeltaTBwd() * mTPCBin2Z; - trc.zMax = trc.getZ() + trcOrig.getDeltaTFwd() * mTPCBin2Z; - } else if (trcOrig.hasCSideClustersOnly()) { - trc.zMin = trc.getZ() - trcOrig.getDeltaTFwd() * mTPCBin2Z; - trc.zMax = trc.getZ() + trcOrig.getDeltaTBwd() * mTPCBin2Z; + if constexpr (isTPCTRDTOFTrack<decltype(trk)>()) { + // TPC track constrained by TRD and TOF time, time and its error in \mus + LOG(ERROR) << "Not ready yet for TPC-TRD-TOF tracks"; } - // TODO : special treatment of tracks crossing the CE - - // cache work track index - mTPCSectIndexCache[o2::math_utils::angle2Sector(trc.getAlpha())].push_back(mTPCWork.size() - 1); - } - - /// full drift time + safety margin - float maxTDriftSafe = (mNTPCBinsFullDrift + mParams->safeMarginTPCITSTimeBin + mTPCTimeEdgeTSafeMargin); + return true; + }; + mRecoCont->createTracksVariadic(creator); - float maxTimeBin = 0; + float maxTime = 0; int nITSROFs = mITSROFTimes.size(); // sort tracks in each sector according to their timeMax for (int sec = o2::constants::math::NSectors; sec--;) { @@ -587,45 +456,46 @@ bool MatchTPCITS::prepareTPCTracks() std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { auto& trcA = mTPCWork[a]; auto& trcB = mTPCWork[b]; - return (trcA.timeBins.getMax() - trcB.timeBins.getMax()) < 0.; + return (trcA.tBracket.getMax() - trcB.tBracket.getMax()) < 0.; }); // build array of 1st entries with tmax corresponding to each ITS ROF (or trigger), // TPC tracks below this entry cannot match to ITS tracks of this and higher ROFs - float tmax = mTPCWork[indexCache.back()].timeBins.getMax(); - if (maxTimeBin < tmax) { - maxTimeBin = tmax; + float tmax = mTPCWork[indexCache.back()].tBracket.getMax(); + if (maxTime < tmax) { + maxTime = tmax; } - int nbins = 1 + tpcTimeBin2ITSROFrame(tmax); - auto& tbinStart = mTPCTimeBinStart[sec]; - tbinStart.resize(nbins, -1); + int nbins = 1 + (mITSTriggered ? time2ITSROFrameTrig(tmax, 0) : time2ITSROFrameCont(tmax)); + auto& timeStart = mTPCTimeStart[sec]; + timeStart.resize(nbins, -1); int itsROF = 0; - tbinStart[0] = 0; + timeStart[0] = 0; for (int itr = 0; itr < (int)indexCache.size(); itr++) { auto& trc = mTPCWork[indexCache[itr]]; - while (itsROF < nITSROFs && !(trc.timeBins < mITSROFTimes[itsROF])) { // 1st ITS frame afte max allowed time for this TPC track + while (itsROF < nITSROFs && !(trc.tBracket < mITSROFTimes[itsROF])) { // 1st ITS frame afte max allowed time for this TPC track itsROF++; } int itsROFMatch = itsROF; - if (itsROFMatch && tbinStart[--itsROFMatch] == -1) { // register ITSrof preceding the one which exceeds the TPC track tmax - tbinStart[itsROFMatch] = itr; + if (itsROFMatch && timeStart[--itsROFMatch] == -1) { // register ITSrof preceding the one which exceeds the TPC track tmax + timeStart[itsROFMatch] = itr; } } for (int i = 1; i < nbins; i++) { - if (tbinStart[i] == -1) { // fill gaps with preceding indices - tbinStart[i] = tbinStart[i - 1]; + if (timeStart[i] == -1) { // fill gaps with preceding indices + timeStart[i] = timeStart[i - 1]; } } } // loop over tracks of single sector - // create mapping from TPC time-bins to ITS ROFs - - if (mITSROFTimes.back() < maxTimeBin) { - maxTimeBin = mITSROFTimes.back().getMax(); + // FIXME We probably don't need this + /* + // create mapping from TPC time to ITS ROFs + if (mITSROFTimes.back() < maxTime) { + maxTime = mITSROFTimes.back().getMax(); } - int nb = int(maxTimeBin) + 1; + int nb = int(maxTime) + 1; mITSROFofTPCBin.resize(nb, -1); int itsROF = 0; for (int ib = 0; ib < nb; ib++) { @@ -634,71 +504,77 @@ bool MatchTPCITS::prepareTPCTracks() } mITSROFofTPCBin[ib] = itsROF; } +*/ + mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCTransform.get(), mBz, mTPCTrackClusIdx.data(), mTPCRefitterShMap.data(), nullptr, o2::base::Propagator::Instance()); + mTimer[SWPrepTPC].Stop(); - return true; + return mTPCWork.size() > 0; } //_____________________________________________________ -bool MatchTPCITS::prepareITSTracks() +bool MatchTPCITS::prepareITSData() { - // In the standalone (tree-based) mode load next chunk of ITS data, // Do preparatory work for matching - int nROFs = mITSTrackROFRec.size(); + mTimer[SWPrepITS].Start(false); + const auto& inp = *mRecoCont; - if (!nROFs) { - LOG(INFO) << "Empty TF"; + // ITS clusters + mITSClusterROFRec = inp.getITSClustersROFRecords(); + const auto clusITS = inp.getITSClusters(); + if (mITSClusterROFRec.empty() || clusITS.empty()) { + LOG(INFO) << "No ITS clusters"; return false; } - mTimer[SWPrepITS].Start(false); - mITSWork.clear(); - mITSWork.reserve(mITSTracksArray.size()); - mITSROFTimes.clear(); - // number of records might be actually more than N tracks! - mMatchRecordsITS.clear(); // RS TODO reserve(mMatchRecordsITS.size() + mParams->maxMatchCandidates*ntr); + const auto patterns = inp.getITSClustersPatterns(); + auto pattIt = patterns.begin(); + mITSClustersArray.reserve(clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, *mITSDict); + if (mMCTruthON) { + mITSClsLabels = inp.mcITSClusters.get(); + } + + // ITS tracks + mITSTracksArray = inp.getITSTracks(); + mITSTrackClusIdx = inp.getITSTracksClusterRefs(); + mITSTrackROFRec = inp.getITSTracksROFRecords(); if (mMCTruthON) { - mITSLblWork.clear(); + mITSTrkLabels = inp.getITSTracksMCLabels(); } + int nROFs = mITSTrackROFRec.size(); + mITSWork.reserve(mITSTracksArray.size()); // total N ITS clusters in TF - const auto& lastClROF = mITSClusterROFRec[nROFs - 1]; //.back(); + const auto& lastClROF = mITSClusterROFRec[nROFs - 1]; int nITSClus = lastClROF.getFirstEntry() + lastClROF.getNEntries(); - mABClusterLinkIndex.clear(); mABClusterLinkIndex.resize(nITSClus, MinusOne); - for (int sec = o2::constants::math::NSectors; sec--;) { - mITSSectIndexCache[sec].clear(); - mITSTimeBinStart[sec].clear(); - mITSTimeBinStart[sec].resize(nROFs, -1); // start of ITS work tracks in every sector + mITSTimeStart[sec].resize(nROFs, -1); // start of ITS work tracks in every sector } - mITSTrackROFContMapping.clear(); // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones - - setStartIR(mITSTrackROFRec[0].getBCData()); //// TODO: this should be set from external info - for (int irof = 0; irof < nROFs; irof++) { const auto& rofRec = mITSTrackROFRec[irof]; - + int nBC = rofRec.getBCData().differenceInBC(mStartIR); + float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS; + float tMax = (nBC + mITSROFrameLengthInBC) * o2::constants::lhc::LHCBunchSpacingMUS; if (!mITSTriggered) { - auto irofCont = (rofRec.getBCData().toLong() - mStartIR.toLong()) / mITSROFrameLengthInBC; - if (mITSTrackROFContMapping.size() <= irofCont) { + auto irofCont = nBC / mITSROFrameLengthInBC; + if (mITSTrackROFContMapping.size() <= irofCont) { // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones mITSTrackROFContMapping.resize((1 + irofCont / 128) * 128, 0); } mITSTrackROFContMapping[irofCont] = irof; } - int cluROFOffset = mITSClusterROFRec[irof].getFirstEntry(); // clusters of this ROF start at this offset - float tmn = intRecord2TPCTimeBin(rofRec.getBCData()); // ITS track min time in TPC time-bins - mITSROFTimes.emplace_back(tmn, tmn + mITSROFrame2TPCBin); // ITS track min/max time in TPC time-bins + mITSROFTimes.emplace_back(tMin, tMax); // ITS ROF min/max time for (int sec = o2::constants::math::NSectors; sec--;) { // start of sector's tracks for this ROF - mITSTimeBinStart[sec][irof] = mITSSectIndexCache[sec].size(); // The sorting does not affect this + mITSTimeStart[sec][irof] = mITSSectIndexCache[sec].size(); // The sorting does not affect this } int trlim = rofRec.getFirstEntry() + rofRec.getNEntries(); for (int it = rofRec.getFirstEntry(); it < trlim; it++) { const auto& trcOrig = mITSTracksArray[it]; if (mParams->runAfterBurner) { - flagUsedITSClusters(trcOrig, cluROFOffset); + flagUsedITSClusters(trcOrig); } if (trcOrig.getParamOut().getX() < 1.) { continue; // backward refit failed @@ -708,7 +584,7 @@ bool MatchTPCITS::prepareITSTracks() } int nWorkTracks = mITSWork.size(); // working copy of outer track param - auto& trc = mITSWork.emplace_back(static_cast<const o2::track::TrackParCov&>(trcOrig.getParamOut()), it); + auto& trc = mITSWork.emplace_back(TrackLocITS{trcOrig.getParamOut(), {tMin, tMax}, it, irof, MinusOne}); if (!trc.rotate(o2::math_utils::angle2Alpha(trc.getPhiPos()))) { mITSWork.pop_back(); // discard failed track continue; @@ -721,8 +597,6 @@ bool MatchTPCITS::prepareITSTracks() if (mMCTruthON) { mITSLblWork.emplace_back(mITSTrkLabels[it]); } - trc.roFrame = irof; - // cache work track index int sector = o2::math_utils::angle2Sector(trc.getAlpha()); mITSSectIndexCache[sector].push_back(nWorkTracks); @@ -733,16 +607,16 @@ bool MatchTPCITS::prepareITSTracks() // [(Xr*tg(10)-Yr)/(tgPhir+tg70)]^2 / cos(70)^2 // for the next sector // [(Xr*tg(10)+Yr)/(tgPhir-tg70)]^2 / cos(70)^2 // for the prev sector // Distances to the sector edges in neighbourings sectors (at Xref in theit proper frames) - float tgp = trc.getSnp(), trcY = trc.getY(); + float tgp = trc.getSnp(); tgp /= std::sqrt((1.f - tgp) * (1.f + tgp)); // tan of track direction XY // sector up - float dy2Up = (YMaxAtXMatchingRef - trcY) / (tgp + Tan70); + float dy2Up = (YMaxAtXMatchingRef - trc.getY()) / (tgp + Tan70); if ((dy2Up * dy2Up * Cos70I2) < mSectEdgeMargin2) { // need to check this track for matching in sector up addLastTrackCloneForNeighbourSector(sector < (o2::constants::math::NSectors - 1) ? sector + 1 : 0); } // sector down - float dy2Dn = (YMaxAtXMatchingRef + trcY) / (tgp - Tan70); + float dy2Dn = (YMaxAtXMatchingRef + trc.getY()) / (tgp - Tan70); if ((dy2Dn * dy2Dn * Cos70I2) < mSectEdgeMargin2) { // need to check this track for matching in sector down addLastTrackCloneForNeighbourSector(sector > 1 ? sector - 1 : o2::constants::math::NSectors - 1); } @@ -758,7 +632,8 @@ bool MatchTPCITS::prepareITSTracks() } } - // sort tracks in each sector according to their time, then tgl + // sort tracks in each sector according to their min time, then tgl + // RSTODO: sorting in tgl will be dangerous once the tracks with different time uncertaincies will be added for (int sec = o2::constants::math::NSectors; sec--;) { auto& indexCache = mITSSectIndexCache[sec]; LOG(INFO) << "Sorting sector" << sec << " | " << indexCache.size() << " ITS tracks"; @@ -768,9 +643,9 @@ bool MatchTPCITS::prepareITSTracks() std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) { auto& trackA = mITSWork[a]; auto& trackB = mITSWork[b]; - if (trackA.roFrame < trackB.roFrame) { // ITS tracks have the same time coverage + if (trackA.tBracket.getMin() < trackB.tBracket.getMin()) { return true; - } else if (trackA.roFrame > trackB.roFrame) { + } else if (trackA.tBracket.getMin() > trackB.tBracket.getMin()) { return false; } return trackA.getTgl() < trackB.getTgl(); @@ -778,14 +653,18 @@ bool MatchTPCITS::prepareITSTracks() } // loop over tracks of single sector mMatchRecordsITS.reserve(mITSWork.size() * mParams->maxMatchCandidates); mTimer[SWPrepITS].Stop(); - return true; + + return nITSClus > 0; } //_____________________________________________________ -bool MatchTPCITS::prepareFITInfo() +bool MatchTPCITS::prepareFITData() { // If available, read FIT Info - + if (mUseFT0) { + mFITInfo = mRecoCont->getFT0RecPoints(); + prepareInteractionTimes(); + } return true; } @@ -795,8 +674,8 @@ void MatchTPCITS::doMatching(int sec) ///< run matching for currently cached ITS data for given TPC sector auto& cacheITS = mITSSectIndexCache[sec]; // array of cached ITS track indices for this sector auto& cacheTPC = mTPCSectIndexCache[sec]; // array of cached ITS track indices for this sector - auto& tbinStartTPC = mTPCTimeBinStart[sec]; // array of 1st TPC track with timeMax in ITS ROFrame - auto& tbinStartITS = mITSTimeBinStart[sec]; + auto& timeStartTPC = mTPCTimeStart[sec]; // array of 1st TPC track with timeMax in ITS ROFrame + auto& timeStartITS = mITSTimeStart[sec]; int nTracksTPC = cacheTPC.size(), nTracksITS = cacheITS.size(); if (!nTracksTPC || !nTracksITS) { LOG(INFO) << "Matchng sector " << sec << " : N tracks TPC:" << nTracksTPC << " ITS:" << nTracksITS << " in sector " << sec; @@ -804,57 +683,61 @@ void MatchTPCITS::doMatching(int sec) } /// full drift time + safety margin - float maxTDriftSafe = (mNTPCBinsFullDrift + mParams->safeMarginTPCITSTimeBin + mTPCTimeEdgeTSafeMargin); - - float vdErr2TB = mZ2TPCBin * mParams->maxVDriftUncertainty; + float maxTDriftSafe = tpcTimeBin2MUS(mNTPCBinsFullDrift + mParams->safeMarginTPCITSTimeBin + mTPCTimeEdgeTSafeMargin); + float vdErrT = tpcTimeBin2MUS(mZ2TPCBin * mParams->maxVDriftUncertainty); - // get min ROFrame (in TPC time-bins) of ITS tracks currently in cache + // get min ROFrame of ITS tracks currently in cache auto minROFITS = mITSWork[cacheITS.front()].roFrame; - if (minROFITS >= int(tbinStartTPC.size())) { + if (minROFITS >= int(timeStartTPC.size())) { LOG(INFO) << "ITS min ROFrame " << minROFITS << " exceeds all cached TPC track ROF eqiuvalent " << cacheTPC.size() - 1; return; } int nCheckTPCControl = 0, nCheckITSControl = 0, nMatchesControl = 0; // temporary - int idxMinTPC = tbinStartTPC[minROFITS]; // index of 1st cached TPC track within cached ITS ROFrames - auto t2nbs = mZ2TPCBin * mParams->tpcTimeICMatchingNSigma; + int idxMinTPC = timeStartTPC[minROFITS]; // index of 1st cached TPC track within cached ITS ROFrames + auto t2nbs = tpcTimeBin2MUS(mZ2TPCBin * mParams->tpcTimeICMatchingNSigma); bool checkInteractionCandidates = mUseFT0 && mParams->validateMatchByFIT != MatchTPCITSParams::Disable; + + int itsROBin = 0; for (int itpc = idxMinTPC; itpc < nTracksTPC; itpc++) { auto& trefTPC = mTPCWork[cacheTPC[itpc]]; // estimate ITS 1st ROframe bin this track may match to: TPC track are sorted according to their // timeMax, hence the timeMax - MaxmNTPCBinsFullDrift are non-decreasing - int itsROBin = tpcTimeBin2ITSROFrame(trefTPC.timeBins.getMax() - maxTDriftSafe); + auto tmn = trefTPC.tBracket.getMax() - maxTDriftSafe; + itsROBin = mITSTriggered ? time2ITSROFrameTrig(tmn, itsROBin) : time2ITSROFrameCont(tmn); - if (itsROBin >= int(tbinStartITS.size())) { // time of TPC track exceeds the max time of ITS in the cache + if (itsROBin >= int(timeStartITS.size())) { // time of TPC track exceeds the max time of ITS in the cache break; } - int iits0 = tbinStartITS[itsROBin]; + int iits0 = timeStartITS[itsROBin]; nCheckTPCControl++; for (auto iits = iits0; iits < nTracksITS; iits++) { auto& trefITS = mITSWork[cacheITS[iits]]; - const auto& timeITS = mITSROFTimes[trefITS.roFrame]; // compare if the ITS and TPC tracks may overlap in time - if (trefTPC.timeBins < timeITS) { - // since TPC tracks are sorted in timeMax and ITS tracks are sorted in timeMin - // all following ITS tracks also will not match + if (trefTPC.tBracket < trefITS.tBracket) { // since TPC tracks are sorted in timeMax and ITS tracks are sorted in timeMin all following ITS tracks also will not match break; } - if (trefTPC.timeBins > timeITS) { // its bracket precedes TPC bracket + if (trefTPC.tBracket > trefITS.tBracket) { // its bracket precedes TPC bracket continue; } - // is corrected TPC track time compatible with ITS ROF expressed in TPC bins? - auto deltaT = (trefITS.getZ() - trefTPC.getZ()) * mZ2TPCBin; // time difference in TPC time bins corresponding to Z differences - auto timeTB = getTPCTrackCorrectedTimeBin(mTPCTracksArray[trefTPC.sourceID], deltaT); // TPC time required to match to Z of ITS track - auto timeTBErr = std::sqrt(trefITS.getSigmaZ2() + trefTPC.getSigmaZ2()) * t2nbs; // nsigma*error in number of TPC time bins + // is corrected TPC track time compatible with ITS ROF expressed + auto deltaT = (trefITS.getZ() - trefTPC.getZ()) * mTPCVDrift0Inv; // drift time difference corresponding to Z differences + auto timeCorr = trefTPC.getCorrectedTime(deltaT); // TPC time required to match to Z of ITS track + auto timeCorrErr = std::sqrt(trefITS.getSigmaZ2() + trefTPC.getSigmaZ2()) * t2nbs; // nsigma*error if (mVDriftCalibOn) { - timeTBErr += vdErr2TB * (250. - abs(trefITS.getZ())); // account for the extra error from TPC VDrift uncertainty + timeCorrErr += vdErrT * (250. - abs(trefITS.getZ())); // account for the extra error from TPC VDrift uncertainty } - o2::math_utils::Bracket<float> trange(timeTB - timeTBErr, timeTB + timeTBErr); - if (timeITS.isOutside(trange)) { + o2::math_utils::Bracketf_t trange(timeCorr - timeCorrErr, timeCorr + timeCorrErr); + if (trefITS.tBracket.isOutside(trange)) { continue; } + if (timeCorr < 0) { // RS TODO: similar check will be needed to other TF edge + if (timeCorr + mParams->tfEdgeTimeToleranceMUS < 0) { + //continue; + } + } nCheckITSControl++; float chi2 = -1; @@ -865,7 +748,8 @@ void MatchTPCITS::doMatching(int sec) fillTPCITSmatchTree(cacheITS[iits], cacheTPC[itpc], rejFlag, chi2); } #endif - + /* + // RS: this might be dangerous for ITS tracks with different time coverages. if (rejFlag == RejectOnTgl) { // ITS tracks in each ROFrame are ordered in Tgl, hence if this check failed on Tgl check // (i.e. tgl_its>tgl_tpc+tolerance), then all other ITS tracks in this ROFrame will also have tgl too large. @@ -873,24 +757,25 @@ void MatchTPCITS::doMatching(int sec) int rof = trefITS.roFrame; bool stop = false; do { - if (++rof >= int(tbinStartITS.size())) { + if (++rof >= int(timeStartITS.size())) { stop = true; break; // no more ITS ROFrames in cache } - iits = tbinStartITS[rof] - 1; // next track to be checked -1 - } while (iits <= tbinStartITS[trefITS.roFrame]); // skip empty bins + iits = timeStartITS[rof] - 1; // next track to be checked -1 + } while (iits <= timeStartITS[trefITS.roFrame]); // skip empty bins if (stop) { break; } continue; } + */ if (rejFlag != Accept) { continue; } int matchedIC = MinusOne; if (!isCosmics()) { // validate by bunch filling scheme - auto irBracket = tpcTimeBin2IRBracket(trange); + auto irBracket = tBracket2IRBracket(trange); if (irBracket.isInvalid()) { continue; } @@ -902,11 +787,11 @@ void MatchTPCITS::doMatching(int sec) if (nic) { int idIC = interactionRefs.getFirstEntry(), maxIC = idIC + nic; for (; idIC < maxIC; idIC++) { - auto cmp = mInteractions[idIC].timeBins.isOutside(trange); - if (cmp == o2::math_utils::Bracket<float>::Above) { // trange is above this interaction candidate, the following ones may match + auto cmp = mInteractions[idIC].tBracket.isOutside(trange); + if (cmp == o2::math_utils::Bracketf_t::Above) { // trange is above this interaction candidate, the following ones may match continue; } - if (cmp == o2::math_utils::Bracket<float>::Inside) { + if (cmp == o2::math_utils::Bracketf_t::Inside) { matchedIC = idIC; } break; // we loop till 1st matching IC or the one above the trange (since IC are ordered, all others will be above too) @@ -1077,7 +962,7 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC& return rejFlag; } - if (mCompareTracksDZ) { // in continuous mode we usually don't use DZ + if (tTPC.constraint == TrackLocTPC::Constrained) { // in continuous only constrained tracks can be compared in Z diff = tITS.getParam(o2::track::kZ) - tTPC.getParam(o2::track::kZ); if ((rejFlag = roughCheckDif(diff, mParams->crudeAbsDiffCut[o2::track::kZ], RejectOnZ))) { return rejFlag; @@ -1086,13 +971,6 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC& if ((rejFlag = roughCheckDif(diff, mParams->crudeNSigma2Cut[o2::track::kZ], RejectOnZ + NSigmaShift))) { return rejFlag; } - } else { // in continuous mode we use special check on allowed Z range - if (tITS.getParam(o2::track::kZ) - tTPC.zMax > mParams->crudeAbsDiffCut[o2::track::kZ]) { - return RejectOnZ; - } - if (tITS.getParam(o2::track::kZ) - tTPC.zMin < -mParams->crudeAbsDiffCut[o2::track::kZ]) { - return -RejectOnZ; - } } diff = tITS.getParam(o2::track::kSnp) - tTPC.getParam(o2::track::kSnp); @@ -1171,12 +1049,12 @@ float MatchTPCITS::getPredictedChi2NoZ(const o2::track::TrackParCov& trITS, cons // if (std::abs(trITS.getAlpha() - trTPC.getAlpha()) > FLT_EPSILON) { // LOG(ERROR) << "The reference Alpha of the tracks differ: " - // << trITS.getAlpha() << " : " << trTPC.getAlpha(); + // << trITS.getAlpha() << " : " << trTPC.getAlpha(); // return 2. * o2::track::HugeF; // } // if (std::abs(trITS.getX() - trTPC.getX()) > FLT_EPSILON) { // LOG(ERROR) << "The reference X of the tracks differ: " - // << trITS.getX() << " : " << trTPC.getX(); + // << trITS.getX() << " : " << trTPC.getX(); // return 2. * o2::track::HugeF; // } MatrixDSym4 covMat; @@ -1221,8 +1099,7 @@ void MatchTPCITS::addLastTrackCloneForNeighbourSector(int sector) mITSWork.push_back(mITSWork.back()); // clone the last track defined in given sector auto& trc = mITSWork.back(); if (trc.rotate(o2::math_utils::sector2Angle(sector)) && - o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, XMatchingRef, o2::constants::physics::MassPionCharged, MaxSnp, - 2., MatCorrType::USEMatCorrNONE)) { + o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, XMatchingRef, MaxSnp, 2., MatCorrType::USEMatCorrNONE)) { // TODO: use faster prop here, no 3d field, materials mITSSectIndexCache[sector].push_back(mITSWork.size() - 1); // register track CLONE if (mMCTruthON) { @@ -1241,8 +1118,7 @@ bool MatchTPCITS::propagateToRefX(o2::track::TrackParCov& trc) bool refReached = false; refReached = XMatchingRef < 10.; // RS: tmp, to cover XMatchingRef~0 int trialsLeft = 2; - while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, XMatchingRef, o2::constants::physics::MassPionCharged, - MaxSnp, 2., mUseMatCorrFlag)) { + while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, XMatchingRef, MaxSnp, 2., mUseMatCorrFlag)) { if (refReached) { break; } @@ -1289,7 +1165,6 @@ void MatchTPCITS::print() const } printf("\n"); - printf("TPC-ITS time(bins) bracketing safety margin: %6.2f\n", mParams->timeBinTolerance); printf("TPC Z->time(bins) bracketing safety margin: %6.2f\n", mParams->safeMarginTPCTimeEdge); #ifdef _ALLOW_DEBUG_TREES_ @@ -1310,51 +1185,37 @@ void MatchTPCITS::print() const } //______________________________________________ -void MatchTPCITS::refitWinners(bool loopInITS) +void MatchTPCITS::refitWinners() { ///< refit winning tracks mTimer[SWRefit].Start(false); LOG(INFO) << "Refitting winner matches"; mWinnerChi2Refit.resize(mITSWork.size(), -1.f); - if (loopInITS) { - int iTPC = 0; // will be ignored - for (int iITS = 0; iITS < (int)mITSWork.size(); iITS++) { - if (!refitTrackTPCITSloopITS(iITS, iTPC)) { - continue; - } - mWinnerChi2Refit[iITS] = mMatchedTracks.back().getChi2Refit(); - } - } else { - int iITS; - for (int iTPC = 0; iTPC < (int)mTPCWork.size(); iTPC++) { - if (!refitTrackTPCITSloopTPC(iTPC, iITS)) { - continue; - } - mWinnerChi2Refit[iITS] = mMatchedTracks.back().getChi2Refit(); + int iITS; + for (int iTPC = 0; iTPC < (int)mTPCWork.size(); iTPC++) { + if (!refitTrackTPCITS(iTPC, iITS)) { + continue; } + mWinnerChi2Refit[iITS] = mMatchedTracks.back().getChi2Refit(); } - /* - */ - // flush last tracks mTimer[SWRefit].Stop(); } //______________________________________________ -bool MatchTPCITS::refitTrackTPCITSloopITS(int iITS, int& iTPC) +bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) { ///< refit in inward direction the pair of TPC and ITS tracks const float maxStep = 2.f; // max propagation step (TODO: tune) - - const auto& tITS = mITSWork[iITS]; - if (isDisabledITS(tITS)) { + const auto& tTPC = mTPCWork[iTPC]; + if (isDisabledTPC(tTPC)) { return false; // no match } - const auto& itsMatchRec = mMatchRecordsITS[tITS.matchID]; - iTPC = itsMatchRec.partnerID; - const auto& tTPC = mTPCWork[iTPC]; - const auto& itsTrOrig = mITSTracksArray[tITS.sourceID]; // currently we store clusterIDs in the track + const auto& tpcMatchRec = mMatchRecordsTPC[tTPC.matchID]; + iITS = tpcMatchRec.partnerID; + const auto& tITS = mITSWork[iITS]; + const auto& itsTrOrig = mITSTracksArray[tITS.sourceID]; mMatchedTracks.emplace_back(tTPC, tITS); // create a copy of TPC track at xRef auto& trfit = mMatchedTracks.back(); @@ -1363,17 +1224,22 @@ bool MatchTPCITS::refitTrackTPCITSloopITS(int iITS, int& iTPC) if (!mCompareTracksDZ) { trfit.setZ(tITS.getZ()); // fix the seed Z } - auto dzCorr = trfit.getZ() - tTPC.getZ(); - float deltaT = dzCorr * mZ2TPCBin; // time correction in time-bins + float deltaT = (trfit.getZ() - tTPC.getZ()) * mTPCVDrift0Inv; // time correction in \mus + float timeC = tTPC.getCorrectedTime(deltaT); /// precise time estimate + float timeErr = tTPC.constraint == TrackLocTPC::Constrained ? tTPC.timeErr : std::sqrt(tITS.getSigmaZ2() + tTPC.getSigmaZ2()) * mTPCVDrift0Inv; // estimate the error on time + if (timeC < 0) { // RS TODO similar check is needed for other edge of TF + if (timeC + std::min(timeErr, mParams->tfEdgeTimeToleranceMUS * mTPCTBinMUSInv) < 0) { + mMatchedTracks.pop_back(); // destroy failed track + return false; + } + timeC = 0.; + } // refit TPC track inward into the ITS int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(); float chi2 = 0.f; auto geom = o2::its::GeometryTGeo::Instance(); auto propagator = o2::base::Propagator::Instance(); - // NOTE: the ITS cluster index is stored wrt 1st cluster of relevant ROF, while here we extract clusters from the - // buffer for the whole TF. Therefore, we should shift the index by the entry of the ROF's 1st cluster in the global cluster buffer - int clusIndOffs = mITSClusterROFRec[tITS.roFrame].getFirstEntry(); int clEntry = itsTrOrig.getFirstClusterEntry(); float addErr2 = 0; @@ -1385,14 +1251,13 @@ bool MatchTPCITS::refitTrackTPCITSloopITS(int iITS, int& iTPC) } for (int icl = 0; icl < ncl; icl++) { - const auto& clus = mITSClustersArray[clusIndOffs + mITSTrackClusIdx[clEntry++]]; + const auto& clus = mITSClustersArray[mITSTrackClusIdx[clEntry++]]; float alpha = geom->getSensorRefAlpha(clus.getSensorID()), x = clus.getX(); if (!trfit.rotate(alpha) || // note: here we also calculate the L,T integral (in the inward direction, but this is irrelevant) // note: we should eventually use TPC pid in the refit (TODO) // note: since we are at small R, we can use field BZ component at origin rather than 3D field - // !propagator->PropagateToXBxByBz(trfit, x, o2::constants::physics::MassPionCharged, - !propagator->propagateToX(trfit, x, propagator->getNominalBz(), o2::constants::physics::MassPionCharged, + !propagator->propagateToX(trfit, x, propagator->getNominalBz(), MaxSnp, maxStep, mUseMatCorrFlag, &trfit.getLTIntegralOut())) { break; } @@ -1403,412 +1268,204 @@ bool MatchTPCITS::refitTrackTPCITSloopITS(int iITS, int& iTPC) nclRefit++; } if (nclRefit != ncl) { - printf("FAILED after ncl=%d\n", nclRefit); - printf("its was: "); - tITS.print(); - printf("tpc was: "); - tTPC.print(); + LOGP(DEBUG, "Refit in ITS failed after ncl={}, match between TPC track #{} and ITS track #{}", nclRefit, tTPC.sourceID, tITS.sourceID); + LOGP(DEBUG, "{:s}", trfit.asString()); mMatchedTracks.pop_back(); // destroy failed track return false; } - // we need to update the LTOF integral by the distance to the "primary vertex" + // We need to update the LTOF integral by the distance to the "primary vertex" + // We want to leave the track at the the position of its last update, so we do a fast propagation on the TrackPar copy of trfit, + // and since for the LTOF calculation the material effects are irrelevant, we skip material corrections const o2::dataformats::VertexBase vtxDummy; // at the moment using dummy vertex: TODO use MeanVertex constraint instead - if (!propagator->propagateToDCA(vtxDummy, trfit, propagator->getNominalBz(), o2::constants::physics::MassPionCharged, - maxStep, mUseMatCorrFlag, nullptr, &trfit.getLTIntegralOut())) { + o2::track::TrackPar trpar(trfit); + if (!propagator->propagateToDCA(vtxDummy.getXYZ(), trpar, propagator->getNominalBz(), + maxStep, MatCorrType::USEMatCorrNONE, nullptr, &trfit.getLTIntegralOut())) { LOG(ERROR) << "LTOF integral might be incorrect"; } - /// precise time estimate - auto tpcTrOrig = mTPCTracksArray[tTPC.sourceID]; - float timeTB = getTPCTrackCorrectedTimeBin(tpcTrOrig, deltaT); - // convert time in timebins to time in microseconds - float time = timeTB * mTPCTBinMUS; - // estimate the error on time - float timeErr = std::sqrt(tITS.getSigmaZ2() + tTPC.getSigmaZ2()) * mTPCVDrift0Inv; - // outward refit - auto& tracOut = trfit.getParamOut(); // this track is already at the matching reference X + auto& tracOut = trfit.getParamOut(); // this is a clone of ITS outward track already at the matching reference X + auto& tofL = trfit.getLTIntegralOut(); { - if (mVDriftCalibOn) { - tracOut.updateCov(addErr2, o2::track::kSigTgl2); - } - int icl = tpcTrOrig.getNClusterReferences() - 1; - uint8_t sector, prevsector, row, prevrow; - uint32_t clusterIndexInRow; - std::array<float, 2> clsYZ; - std::array<float, 3> clsCov = {}; - float clsX; - - const auto& cl = tpcTrOrig.getCluster(mTPCTrackClusIdx, icl, *mTPCClusterIdxStruct, sector, row); - mTPCTransform->Transform(sector, row, cl.getPad(), cl.getTime(), clsX, clsYZ[0], clsYZ[1], timeTB); - // rotate to 1 cluster's sector - if (!tracOut.rotate(o2::math_utils::sector2Angle(sector % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sector % 18) << " failed"; + float xtogo = 0; + if (!tracOut.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) || + !propagator->PropagateToXBxByBz(tracOut, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { + LOG(DEBUG) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); mMatchedTracks.pop_back(); // destroy failed track return false; } - // TODO: consider propagating in empty space till TPC entrance in large step, and then in more detailed propagation with mat. corrections - - // propagate to 1st cluster X - if (!propagator->PropagateToXBxByBz(tracOut, clsX, o2::constants::physics::MassPionCharged, MaxSnp, 10., mUseMatCorrFlag, &trfit.getLTIntegralOut())) { - LOG(DEBUG) << "Propagation to 1st cluster at X=" << clsX << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); + if (mVDriftCalibOn) { + tracOut.updateCov(addErr2, o2::track::kSigTgl2); + } + float chi2Out = 0; + auto posStart = tracOut.getXYZGlo(); + auto tImposed = timeC * mTPCTBinMUSInv; + if (std::abs(tImposed - mTPCTracksArray[tTPC.sourceID].getTime0()) > 550) { // RS FIXME: should be removed once TOF fixes https://github.com/AliceO2Group/AliceO2/pull/6540#issuecomment-880060760 + LOG(ERROR) << "Impossible imposed timebin " << tImposed << " for TPC track with timebin0 " << mTPCTracksArray[tTPC.sourceID].getTime0() << " TB"; mMatchedTracks.pop_back(); // destroy failed track return false; } - // - mTPCClusterParam->GetClusterErrors2(row, clsYZ[1], tracOut.getSnp(), tracOut.getTgl(), clsCov[0], clsCov[2]); - // - float chi2Out = tracOut.getPredictedChi2(clsYZ, clsCov); - if (!tracOut.update(clsYZ, clsCov)) { - LOG(WARNING) << "Update failed at 1st cluster, chi2 =" << chi2Out; + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(tracOut, mTPCTracksArray[tTPC.sourceID].getClusterRef(), timeC * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + if (retVal < 0) { + LOG(DEBUG) << "Refit failed"; mMatchedTracks.pop_back(); // destroy failed track return false; } - prevrow = row; - prevsector = sector; - - for (; icl--;) { - const auto& cl = tpcTrOrig.getCluster(mTPCTrackClusIdx, icl, *mTPCClusterIdxStruct, sector, row); - if (row <= prevrow) { - LOG(DEBUG) << "New row/sect " << int(row) << '/' << int(sector) << " is <= the previous " << int(prevrow) - << '/' << int(prevsector) << " TrackID: " << tTPC.sourceID << " Pt:" << tracOut.getPt(); - if (row < prevrow) { - break; - } else { - continue; // just skip duplicate clusters - } - } - prevrow = row; - mTPCTransform->Transform(sector, row, cl.getPad(), cl.getTime(), clsX, clsYZ[0], clsYZ[1], timeTB); - if (prevsector != sector) { - prevsector = sector; - if (!tracOut.rotate(o2::math_utils::sector2Angle(sector % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sector % 18) << " failed"; - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - } - if (!propagator->PropagateToXBxByBz(tracOut, clsX, o2::constants::physics::MassPionCharged, MaxSnp, - 10., MatCorrType::USEMatCorrNONE, &trfit.getLTIntegralOut())) { // no material correction! - LOG(DEBUG) << "Propagation to cluster " << icl << " (of " << tpcTrOrig.getNClusterReferences() << ") at X=" - << clsX << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp() << " pT=" << tracOut.getPt(); - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - chi2Out += tracOut.getPredictedChi2(clsYZ, clsCov); - if (!tracOut.update(clsYZ, clsCov)) { - LOG(DEBUG) << "Update failed at cluster " << icl << ", chi2 =" << chi2Out; - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - } - // propagate to the outer edge of the TPC, TODO: check outer radius - // Note: it is allowed to not reach the requested radius - propagator->PropagateToXBxByBz(tracOut, XTPCOuterRef, o2::constants::physics::MassPionCharged, MaxSnp, - 10., mUseMatCorrFlag, &trfit.getLTIntegralOut()); - - // LOG(INFO) << "Refitted with chi2 = " << chi2Out; + auto posEnd = tracOut.getXYZGlo(); + // account path integrals + float dX = posEnd.x() - posStart.x(), dY = posEnd.y() - posStart.y(), dZ = posEnd.z() - posStart.z(), d2XY = dX * dX + dY * dY; + if (mFieldON) { // circular arc = 2*R*asin(dXY/2R) + float b[3]; + o2::math_utils::Point3D<float> posAv(0.5 * (posEnd.x() + posStart.x()), 0.5 * (posEnd.y() + posStart.y()), 0.5 * (posEnd.z() + posStart.z())); + propagator->getFieldXYZ(posAv, b); + float curvH = std::abs(0.5f * tracOut.getCurvature(b[2])), arcXY = 1. / curvH * std::asin(curvH * std::sqrt(d2XY)); + d2XY = arcXY * arcXY; + } + auto lInt = std::sqrt(d2XY + dZ * dZ); + tofL.addStep(lInt, tracOut.getP2Inv()); + tofL.addX2X0(lInt * mTPCmeanX0Inv); + propagator->PropagateToXBxByBz(tracOut, o2::constants::geom::XTPCOuterRef, MaxSnp, 10., mUseMatCorrFlag, &tofL); + /* + LOG(INFO) << "TPC " << iTPC << " ITS " << iITS << " Refitted with chi2 = " << chi2Out; + tracOut.print(); + tofL.print(); + */ } - trfit.setChi2Match(itsMatchRec.chi2); + trfit.setChi2Match(tpcMatchRec.chi2); trfit.setChi2Refit(chi2); - trfit.setTimeMUS(time, timeErr); - trfit.setRefTPC(tTPC.sourceID); - trfit.setRefITS(tITS.sourceID); + trfit.setTimeMUS(timeC, timeErr); + trfit.setRefTPC({unsigned(tTPC.sourceID), o2::dataformats::GlobalTrackID::TPC}); + trfit.setRefITS({unsigned(tITS.sourceID), o2::dataformats::GlobalTrackID::ITS}); - if (mMCTruthON) { // store MC info - mOutITSLabels.emplace_back(mITSLblWork[iITS]); - mOutTPCLabels.emplace_back(mTPCLblWork[iTPC]); + if (mMCTruthON) { // store MC info: we assign TPC track label and declare the match fake if the ITS and TPC labels are different (their fake flag is ignored) + auto& lbl = mOutLabels.emplace_back(mTPCLblWork[iTPC]); + lbl.setFakeFlag(mITSLblWork[iITS] != mTPCLblWork[iTPC]); } + // if requested, fill the difference of ITS and TPC tracks tgl for vdrift calibation + if (mHistoDTgl) { + auto tglITS = tITS.getTgl(); + if (std::abs(tglITS) < mHistoDTgl->getXMax()) { + auto dTgl = tglITS - tTPC.getTgl(); + mHistoDTgl->fill(tglITS, dTgl); + } + } // trfit.print(); // DBG return true; } //______________________________________________ -bool MatchTPCITS::refitTrackTPCITSloopTPC(int iTPC, int& iITS) +bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) { - ///< refit in inward direction the pair of TPC and ITS tracks + ///< refit AfterBurner track const float maxStep = 2.f; // max propagation step (TODO: tune) - const auto& tTPC = mTPCWork[iTPC]; - if (isDisabledTPC(tTPC)) { - return false; // no match - } - const auto& tpcMatchRec = mMatchRecordsTPC[tTPC.matchID]; - iITS = tpcMatchRec.partnerID; - const auto& tITS = mITSWork[iITS]; - const auto& itsTrOrig = mITSTracksArray[tITS.sourceID]; + const auto& tTPC = mTPCWork[seed.tpcWID]; + const auto& winLink = seed.getLink(seed.winLinkID); + auto& newtr = mMatchedTracks.emplace_back(winLink, winLink); // create a copy of winner param at innermost ITS cluster + auto& tracOut = newtr.getParamOut(); + auto& tofL = newtr.getLTIntegralOut(); + auto geom = o2::its::GeometryTGeo::Instance(); + auto propagator = o2::base::Propagator::Instance(); + tracOut.resetCovariance(); + propagator->estimateLTFast(tofL, winLink); // guess about initial value for the track integral from the origin - mMatchedTracks.emplace_back(tTPC, tITS); // create a copy of TPC track at xRef - auto& trfit = mMatchedTracks.back(); - // in continuos mode the Z of TPC track is meaningless, unless it is CE crossing - // track (currently absent, TODO) - if (!mCompareTracksDZ) { - trfit.setZ(tITS.getZ()); // fix the seed Z - } - auto dzCorr = trfit.getZ() - tTPC.getZ(); - float deltaT = dzCorr * mZ2TPCBin; // time correction in time-bins - - // refit TPC track inward into the ITS - int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(); + // refit track outward in the ITS + const auto& itsClRefs = mABTrackletRefs[iITSAB]; + int nclRefit = 0, ncl = itsClRefs.getNClusters(); + uint16_t patt = 0; float chi2 = 0.f; - auto geom = o2::its::GeometryTGeo::Instance(); - auto propagator = o2::base::Propagator::Instance(); - // NOTE: the ITS cluster index is stored wrt 1st cluster of relevant ROF, while here we extract clusters from the - // buffer for the whole TF. Therefore, we should shift the index by the entry of the ROF's 1st cluster in the global cluster buffer - int clusIndOffs = mITSClusterROFRec[tITS.roFrame].getFirstEntry(); - int clEntry = itsTrOrig.getFirstClusterEntry(); - - float addErr2 = 0; - // extra error on tgl due to the assumed vdrift uncertainty - if (mVDriftCalibOn) { - addErr2 = tITS.getParam(o2::track::kTgl) * mParams->maxVDriftUncertainty; - addErr2 *= addErr2; - trfit.updateCov(addErr2, o2::track::kSigTgl2); - } - - for (int icl = 0; icl < ncl; icl++) { - const auto& clus = mITSClustersArray[clusIndOffs + mITSTrackClusIdx[clEntry++]]; + // NOTE: the ITS cluster absolute indices are stored from inner to outer layers + for (int icl = itsClRefs.getFirstEntry(); icl < itsClRefs.getEntriesBound(); icl++) { + const auto& clus = mITSClustersArray[mABTrackletClusterIDs[icl]]; float alpha = geom->getSensorRefAlpha(clus.getSensorID()), x = clus.getX(); - if (!trfit.rotate(alpha) || - // note: here we also calculate the L,T integral (in the inward direction, but this is irrelevant) + if (!tracOut.rotate(alpha) || + // note: here we also calculate the L,T integral // note: we should eventually use TPC pid in the refit (TODO) // note: since we are at small R, we can use field BZ component at origin rather than 3D field - // !propagator->PropagateToXBxByBz(trfit, x, o2::constants::physics::MassPionCharged, - !propagator->propagateToX(trfit, x, propagator->getNominalBz(), o2::constants::physics::MassPionCharged, - MaxSnp, maxStep, mUseMatCorrFlag, &trfit.getLTIntegralOut())) { + !propagator->propagateToX(tracOut, x, propagator->getNominalBz(), MaxSnp, maxStep, mUseMatCorrFlag, &tofL)) { break; } - chi2 += trfit.getPredictedChi2(clus); - if (!trfit.update(clus)) { + chi2 += tracOut.getPredictedChi2(clus); + if (!tracOut.update(clus)) { break; } nclRefit++; } if (nclRefit != ncl) { - printf("FAILED after ncl=%d\n", nclRefit); - printf("its was: "); - tITS.print(); - printf("tpc was: "); - tTPC.print(); + LOGP(DEBUG, "AfterBurner refit in ITS failed after ncl={}, match between TPC track #{} and ITS tracklet #{}", nclRefit, tTPC.sourceID, iITSAB); + LOGP(DEBUG, "{:s}", tracOut.asString()); mMatchedTracks.pop_back(); // destroy failed track return false; } - - // we need to update the LTOF integral by the distance to the "primary vertex" - const o2::dataformats::VertexBase vtxDummy; // at the moment using dummy vertex: TODO use MeanVertex constraint instead - if (!propagator->propagateToDCA(vtxDummy, trfit, propagator->getNominalBz(), o2::constants::physics::MassPionCharged, - maxStep, mUseMatCorrFlag, nullptr, &trfit.getLTIntegralOut())) { - LOG(ERROR) << "LTOF integral might be incorrect"; - } - - /// precise time estimate - const auto& tpcTrOrig = mTPCTracksArray[tTPC.sourceID]; - float timeTB = tpcTrOrig.getTime0(); - if (tpcTrOrig.hasASideClustersOnly()) { - timeTB += deltaT; - } else if (tpcTrOrig.hasCSideClustersOnly()) { - timeTB -= deltaT; - } else { - // TODO : special treatment of tracks crossing the CE - } - // convert time in timebins to time in microseconds - float time = timeTB * mTPCTBinMUS; - // estimate the error on time - float timeErr = std::sqrt(tITS.getSigmaZ2() + tTPC.getSigmaZ2()) * mTPCVDrift0Inv; - - // outward refit - auto& tracOut = trfit.getParamOut(); // this track is already at the matching reference X + // perform TPC refit with interaction time constraint + float timeC = mInteractions[seed.ICCanID].tBracket.mean(); + float timeErr = mInteractions[seed.ICCanID].tBracket.delta(); // RS FIXME shall we use gaussian error? { - if (mVDriftCalibOn) { - tracOut.updateCov(addErr2, o2::track::kSigTgl2); - } - int icl = tpcTrOrig.getNClusterReferences() - 1; - uint8_t sector, prevsector, row, prevrow; - uint32_t clusterIndexInRow; - std::array<float, 2> clsYZ; - std::array<float, 3> clsCov = {}; - float clsX; - - const auto& cl = tpcTrOrig.getCluster(mTPCTrackClusIdx, icl, *mTPCClusterIdxStruct, sector, row); - mTPCTransform->Transform(sector, row, cl.getPad(), cl.getTime() - timeTB, clsX, clsYZ[0], clsYZ[1]); - // rotate to 1 cluster's sector - if (!tracOut.rotate(o2::math_utils::sector2Angle(sector % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sector % 18) << " failed"; + float xtogo = 0; + if (!tracOut.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) || + !propagator->PropagateToXBxByBz(tracOut, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { + LOG(DEBUG) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); mMatchedTracks.pop_back(); // destroy failed track return false; } - // TODO: consider propagating in empty space till TPC entrance in large step, and then in more detailed propagation with mat. corrections - - // propagate to 1st cluster X - if (!propagator->PropagateToXBxByBz(tracOut, clsX, o2::constants::physics::MassPionCharged, MaxSnp, 10., mUseMatCorrFlag, &trfit.getLTIntegralOut())) { - LOG(DEBUG) << "Propagation to 1st cluster at X=" << clsX << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); + float chi2Out = 0; + auto posStart = tracOut.getXYZGlo(); + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(tracOut, mTPCTracksArray[tTPC.sourceID].getClusterRef(), timeC * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + if (retVal < 0) { + LOG(DEBUG) << "Refit failed"; mMatchedTracks.pop_back(); // destroy failed track return false; } - // - mTPCClusterParam->GetClusterErrors2(row, clsYZ[1], tracOut.getSnp(), tracOut.getTgl(), clsCov[0], clsCov[2]); - // - float chi2Out = tracOut.getPredictedChi2(clsYZ, clsCov); - if (!tracOut.update(clsYZ, clsCov)) { - LOG(WARNING) << "Update failed at 1st cluster, chi2 =" << chi2Out; - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - prevrow = row; - prevsector = sector; - - for (; icl--;) { - const auto& cl = tpcTrOrig.getCluster(mTPCTrackClusIdx, icl, *mTPCClusterIdxStruct, sector, row); - if (row <= prevrow) { - LOG(DEBUG) << "New row/sect " << int(row) << '/' << int(sector) << " is <= the previous " << int(prevrow) - << '/' << int(prevsector) << " TrackID: " << tTPC.sourceID << " Pt:" << tracOut.getPt(); - if (row < prevrow) { - break; - } else { - continue; // just skip duplicate clusters - } - } - prevrow = row; - mTPCTransform->Transform(sector, row, cl.getPad(), cl.getTime() - timeTB, clsX, clsYZ[0], clsYZ[1]); - if (prevsector != sector) { - prevsector = sector; - if (!tracOut.rotate(o2::math_utils::sector2Angle(sector % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sector % 18) << " failed"; - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - } - if (!propagator->PropagateToXBxByBz(tracOut, clsX, o2::constants::physics::MassPionCharged, MaxSnp, - 10., MatCorrType::USEMatCorrNONE, &trfit.getLTIntegralOut())) { // no material correction! - LOG(DEBUG) << "Propagation to cluster " << icl << " (of " << tpcTrOrig.getNClusterReferences() << ") at X=" - << clsX << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp() << " pT=" << tracOut.getPt(); - mMatchedTracks.pop_back(); // destroy failed track - return false; - } - chi2Out += tracOut.getPredictedChi2(clsYZ, clsCov); - if (!tracOut.update(clsYZ, clsCov)) { - LOG(DEBUG) << "Update failed at cluster " << icl << ", chi2 =" << chi2Out; - mMatchedTracks.pop_back(); // destroy failed track - return false; - } + auto posEnd = tracOut.getXYZGlo(); + // account path integrals + float dX = posEnd.x() - posStart.x(), dY = posEnd.y() - posStart.y(), dZ = posEnd.z() - posStart.z(), d2XY = dX * dX + dY * dY; + if (mFieldON) { // circular arc = 2*R*asin(dXY/2R) + float b[3]; + o2::math_utils::Point3D<float> posAv(0.5 * (posEnd.x() + posStart.x()), 0.5 * (posEnd.y() + posStart.y()), 0.5 * (posEnd.z() + posStart.z())); + propagator->getFieldXYZ(posAv, b); + float curvH = std::abs(0.5f * tracOut.getCurvature(b[2])), arcXY = 1. / curvH * std::asin(curvH * std::sqrt(d2XY)); + d2XY = arcXY * arcXY; } - // propagate to the outer edge of the TPC, TODO: check outer radius - // Note: it is allowed to not reach the requested radius - propagator->PropagateToXBxByBz(tracOut, XTPCOuterRef, o2::constants::physics::MassPionCharged, MaxSnp, - 10., mUseMatCorrFlag, &trfit.getLTIntegralOut()); - - // LOG(INFO) << "Refitted with chi2 = " << chi2Out; - } - - trfit.setChi2Match(tpcMatchRec.chi2); - trfit.setChi2Refit(chi2); - trfit.setTimeMUS(time, timeErr); - trfit.setRefTPC(tTPC.sourceID); - trfit.setRefITS(tITS.sourceID); - - if (mMCTruthON) { // store MC info - mOutITSLabels.emplace_back(mITSLblWork[iITS]); - mOutTPCLabels.emplace_back(mTPCLblWork[iTPC]); + auto lInt = std::sqrt(d2XY + dZ * dZ); + tofL.addStep(lInt, tracOut.getP2Inv()); + tofL.addX2X0(lInt * mTPCmeanX0Inv); + propagator->PropagateToXBxByBz(tracOut, o2::constants::geom::XTPCOuterRef, MaxSnp, 10., mUseMatCorrFlag, &tofL); } - // if requested, fill the difference of ITS and TPC tracks tgl for vdrift calibation - if (mHistoDTgl) { - auto tglITS = tITS.getTgl(); - if (std::abs(tglITS) < mHistoDTgl->getXMax()) { - auto dTgl = tglITS - tTPC.getTgl(); - mHistoDTgl->fill(tglITS, dTgl); - } - } - // trfit.print(); // DBG + newtr.setChi2Match(winLink.chi2Norm()); + newtr.setChi2Refit(chi2); + newtr.setTimeMUS(timeC, timeErr); + newtr.setRefTPC({unsigned(tTPC.sourceID), o2::dataformats::GlobalTrackID::TPC}); + newtr.setRefITS({unsigned(iITSAB), o2::dataformats::GlobalTrackID::ITSAB}); return true; } //______________________________________________ -bool MatchTPCITS::refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, float xTgt, int trcID, float timeTB, float m) const +bool MatchTPCITS::refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, float xTgt, int trcID, float timeTB) const { // inward refit constexpr float TolSNP = 0.99; const auto& tpcTrOrig = mTPCTracksArray[trcID]; - constexpr int MaxClus = 2 * 152 + 1; // TODO - std::array<const o2::tpc::ClusterNative*, MaxClus> clsArr; - std::array<uint8_t, MaxClus> sectArr; - std::array<uint8_t, MaxClus> rowArr; - // select clusters to use - int iclPrev = 0, nclAcc = 0, icl = tpcTrOrig.getNClusterReferences(); - // the innermost cluster is last one - clsArr[nclAcc] = &tpcTrOrig.getCluster(mTPCTrackClusIdx, --icl, *mTPCClusterIdxStruct, sectArr[nclAcc], rowArr[nclAcc]); - nclAcc++; - for (; icl--;) { - clsArr[nclAcc] = &tpcTrOrig.getCluster(mTPCTrackClusIdx, icl, *mTPCClusterIdxStruct, sectArr[nclAcc], rowArr[nclAcc]); - if (rowArr[iclPrev] < rowArr[nclAcc] || // row grows - (rowArr[iclPrev] == rowArr[nclAcc] && sectArr[iclPrev] == sectArr[nclAcc])) { // split clusters? - iclPrev = nclAcc++; - } else { - break; // discard looping part - } - } - // now selected clusters span from inner to outer rows - - std::array<float, 2> clsYZ; - std::array<float, 3> clsCov = {}; - float clsX; trcIn = tpcTrOrig.getOuterParam(); - trcIn.resetCovariance(); - trcIn.setCov(tpcTrOrig.getQ2Pt() * tpcTrOrig.getQ2Pt(), o2::track::kSigQ2Pt2); // 100% error of the *original track inner param* chi2 = 0; - icl = nclAcc - 1; - - // printf("RowsSpan: %d %d | %d clusters of %d\n", rowArr[0], rowArr[icl], nclAcc, tpcTrOrig.getNClusterReferences()); // tmp auto propagator = o2::base::Propagator::Instance(); - mTPCTransform->Transform(sectArr[icl], rowArr[icl], clsArr[icl]->getPad(), clsArr[icl]->getTime(), clsX, clsYZ[0], clsYZ[1], timeTB); - mTPCClusterParam->GetClusterErrors2(rowArr[icl], clsYZ[1], trcIn.getSnp(), trcIn.getTgl(), clsCov[0], clsCov[2]); - uint8_t sectCurr = sectArr[icl]; - if (!trcIn.rotate(o2::math_utils::sector2Angle(sectCurr % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sectCurr % 18) << " failed"; - return false; - } - trcIn.setX(clsX); - trcIn.setY(clsYZ[0]); - trcIn.setZ(clsYZ[1]); - if (!trcIn.update(clsYZ, clsCov)) { - LOG(WARNING) << "Update failed at cluster " << icl << ", chi2 =" << chi2; + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(trcIn, tpcTrOrig.getClusterRef(), timeTB, &chi2, false, true); // inward refit with matrix reset + if (retVal < 0) { + LOG(WARNING) << "Refit failed"; LOG(WARNING) << trcIn.asString(); return false; } - for (; icl--;) { - if (sectArr[icl] != sectCurr) { - sectCurr = sectArr[icl]; - if (!trcIn.rotate(o2::math_utils::sector2Angle(sectCurr % 18))) { - LOG(DEBUG) << "Rotation to sector " << int(sectCurr % 18) << " failed"; - LOG(DEBUG) << trcIn.asString(); - return false; - } - } - mTPCTransform->Transform(sectArr[icl], rowArr[icl], clsArr[icl]->getPad(), clsArr[icl]->getTime(), clsX, clsYZ[0], clsYZ[1], timeTB); - mTPCClusterParam->GetClusterErrors2(rowArr[icl], clsYZ[1], trcIn.getSnp(), trcIn.getTgl(), clsCov[0], clsCov[2]); - if (!propagator->PropagateToXBxByBz(trcIn, clsX, m, TolSNP, 10., MatCorrType::USEMatCorrNONE)) { // no material correction! - LOG(DEBUG) << "Propagation to cluster at X=" - << clsX << " failed, Xtr=" << trcIn.getX() << " snp=" << trcIn.getSnp() << " pT=" << trcIn.getPt(); - LOG(DEBUG) << trcIn.asString(); - return false; - } - chi2 += trcIn.getPredictedChi2(clsYZ, clsCov); - if (!trcIn.update(clsYZ, clsCov)) { - LOG(WARNING) << "Update failed at cluster " << icl << ", chi2 =" << chi2; - LOG(WARNING) << trcIn.asString(); - return false; - } - } + // // propagate to the inner edge of the TPC // Note: it is allowed to not reach the requested radius - if (!propagator->PropagateToXBxByBz(trcIn, xTgt, m, MaxSnp, 2., mUseMatCorrFlag)) { + if (!propagator->PropagateToXBxByBz(trcIn, xTgt, MaxSnp, 2., mUseMatCorrFlag)) { LOG(DEBUG) << "Propagation to target X=" << xTgt << " failed, Xtr=" << trcIn.getX() << " snp=" << trcIn.getSnp() << " pT=" << trcIn.getPt(); LOG(DEBUG) << trcIn.asString(); return false; @@ -1818,15 +1475,12 @@ bool MatchTPCITS::refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, flo //>>============================= AfterBurner for TPC-track / ITS cluster matching ===================>> //______________________________________________ -int MatchTPCITS::prepareTPCTracksAfterBurner() +int MatchTPCITS::prepareABSeeds() { - ///< select TPC tracks to be considered in afterburner - mTPCABIndexCache.clear(); - mTPCABTimeBinStart.clear(); + ///< select TPC tracks to be considered in afterburner, clone them as seeds for every matching interaction candidate const auto& outerLr = mRGHelper.layers.back(); // to avoid difference between 3D field propagation and Bz-bazed getXatLabR we propagate RMax+margin const float ROuter = outerLr.rRange.getMax() + 0.5f; - auto propagator = o2::base::Propagator::Instance(); for (int iTPC = 0; iTPC < (int)mTPCWork.size(); iTPC++) { @@ -1837,20 +1491,50 @@ int MatchTPCITS::prepareTPCTracksAfterBurner() // which should be good assumption.... float xTgt; if (!tTPC.getXatLabR(ROuter, xTgt, propagator->getNominalBz(), o2::track::DirInward) || - !propagator->PropagateToXBxByBz(tTPC, xTgt, o2::constants::physics::MassPionCharged, MaxSnp, 2., mUseMatCorrFlag)) { + !propagator->PropagateToXBxByBz(tTPC, xTgt, MaxSnp, 2., mUseMatCorrFlag)) { continue; } mTPCABIndexCache.push_back(iTPC); } } // sort tracks according to their timeMin - LOG(INFO) << "Sorting " << mTPCABIndexCache.size() << " selected TPC tracks for AfterBurner in tMin"; std::sort(mTPCABIndexCache.begin(), mTPCABIndexCache.end(), [this](int a, int b) { auto& trcA = mTPCWork[a]; auto& trcB = mTPCWork[b]; - return (trcA.timeBins.getMin() - trcB.timeBins.getMin()) < 0.; + return (trcA.tBracket.getMin() - trcB.tBracket.getMin()) < 0.; }); + float maxTDriftSafe = tpcTimeBin2MUS(mNTPCBinsFullDrift + mParams->safeMarginTPCITSTimeBin + mTPCTimeEdgeTSafeMargin); + int nIntCand = mInteractions.size(), nTPCCand = mTPCABIndexCache.size(); + int tpcStart = 0; + for (int ic = 0; ic < nIntCand; ic++) { + int icFirstSeed = mTPCABSeeds.size(); + auto& intCand = mInteractions[ic]; + auto tic = intCand.tBracket.mean(); + for (int it = tpcStart; it < nTPCCand; it++) { + auto& trc = mTPCWork[mTPCABIndexCache[it]]; + auto cmp = trc.tBracket.isOutside(intCand.tBracket); + if (cmp < 0) { + break; // all other TPC tracks will be also in future wrt the interaction + } + if (cmp > 0) { + if (trc.tBracket.getMin() + maxTDriftSafe < intCand.tBracket.getMin()) { + tpcStart++; // all following int.candidates would be in future wrt this track + } + continue; + } + // we beed to create seed from this TPC track and interaction candidate + float dt = trc.getSignedDT(tic - trc.time0); + float dz = dt * mTPCVDrift0, z = trc.getZ() + dz; + if (outerLr.zRange.isOutside(z, std::sqrt(trc.getSigmaZ2()) + 2.)) { // RS FIXME introduce margin as parameter? + continue; + } + // make sure seed crosses the outer ITS layer (with some margin) + auto& seed = mTPCABSeeds.emplace_back(mTPCABIndexCache[it], ic, trc); + seed.track.setZ(z); // RS FIXME : in case of distortions and large dz the track must be refitted + } + intCand.seedsRef.set(icFirstSeed, mTPCABSeeds.size() - icFirstSeed); + } return mTPCABIndexCache.size(); } @@ -1858,9 +1542,7 @@ int MatchTPCITS::prepareTPCTracksAfterBurner() int MatchTPCITS::prepareInteractionTimes() { // guess interaction times from various sources and relate with ITS rofs - float ft0UncertaintyTB = 0.5e-3 * mTPCTBinMUSInv; // assumed T0 time uncertainty (~0.5ns) in TPC timeBins - mInteractions.clear(); - mITSROFIntCandEntries.clear(); + const float ft0Uncertainty = 0.5e-3; int nITSROFs = mITSROFTimes.size(); mITSROFIntCandEntries.resize(nITSROFs); @@ -1870,7 +1552,7 @@ int MatchTPCITS::prepareInteractionTimes() if (!mFT0Params->isSelected(ft)) { continue; } - auto fitTime = time2TPCTimeBin(mFT0Params->getInteractionTimeNS(ft, mStartIR) * 1e-3); // FIT time in TPC timebins + auto fitTime = ft.getInteractionRecord().differenceInBCMS(mStartIR); // find corresponding ITS ROF, works both in cont. and trigg. modes (ignore T0 MeanTime within the BC) for (; rof < nITSROFs; rof++) { if (mITSROFTimes[rof] < fitTime) { @@ -1882,7 +1564,7 @@ int MatchTPCITS::prepareInteractionTimes() ref.setFirstEntry(mInteractions.size()); // register entry } ref.changeEntriesBy(1); // increment counter - mInteractions.emplace_back(ft.getInteractionRecord(), fitTime, ft0UncertaintyTB, rof, o2::detectors::DetID::FT0); + mInteractions.emplace_back(ft.getInteractionRecord(), fitTime, ft0Uncertainty, rof, o2::detectors::DetID::FT0); } break; // this or next ITSrof in time is > fitTime } @@ -1895,186 +1577,232 @@ int MatchTPCITS::prepareInteractionTimes() //______________________________________________ void MatchTPCITS::runAfterBurner() { - mABTrackLinks.clear(); - - int nIntCand = mInteractions.size(); - int nTPCCand = prepareTPCTracksAfterBurner(); - LOG(INFO) << "AfterBurner will check " << nIntCand << " interaction candindates for " << nTPCCand << " TPC tracks"; - if (!nIntCand || !nTPCCand) { + mTimer[SWABSeeds].Start(false); + prepareABSeeds(); + int nIntCand = mInteractions.size(), nABSeeds = mTPCABSeeds.size(); + LOGP(INFO, "Afterburner will check {} seeds from {} TPC tracks and {} interaction candidates", nABSeeds, mTPCABIndexCache.size(), nIntCand); // TMP + mTimer[SWABSeeds].Stop(); + if (!nIntCand || !mTPCABSeeds.size()) { return; } - int iC = 0; // interaction candindate to consider and result of its time-bracket comparison to TPC track - int iCClean = iC; // id of the next candidate whose cache to be cleaned - for (int itr = 0; itr < nTPCCand; itr++) { // TPC track indices are sorted in tMin - const auto& tTPC = mTPCWork[mTPCABIndexCache[itr]]; - // find 1st interaction candidate compatible with time brackets of this track - int iCRes; - while ((iCRes = tTPC.timeBins.isOutside(mInteractions[iC].timeBins)) < 0 && ++iC < nIntCand) { // interaction precedes the track time-bracket - cleanAfterBurnerClusRefCache(iC, iCClean); // if possible, clean unneeded cached cluster references - } - if (iCRes == 0) { - int iCStart = iC, iCEnd = iC; // check all interaction candidates matching to this TPC track - do { - if (!mInteractions[iCEnd].clRefPtr) { // if not done yet, fill sorted cluster references for interaction candidate - mInteractions[iCEnd].clRefPtr = &mITSChipClustersRefs.emplace_back(); - fillClustersForAfterBurner(mITSChipClustersRefs.back(), mInteractions[iCEnd].rofITS); - // tst - int ncl = mITSChipClustersRefs.back().clusterID.size(); - printf("loaded %d clusters at cache at %p\n", ncl, mInteractions[iCEnd].clRefPtr); - } - } while (++iCEnd < nIntCand && !tTPC.timeBins.isOutside(mInteractions[iCEnd].timeBins)); - - auto lbl = mTPCLblWork[mTPCABIndexCache[itr]]; // tmp - if (runAfterBurner(mTPCABIndexCache[itr], iCStart, iCEnd)) { - lbl.print(); // tmp - //tmp - if (tTPC.matchID > MinusOne) { - printf("AB Matching tree for TPC WID %d and IC %d : %d\n", mTPCABIndexCache[itr], iCStart, iCEnd); - auto& llinks = mABTrackLinksList[tTPC.matchID]; - printABTracksTree(llinks); - } - } - } else if (iCRes > 0) { - continue; // TPC track precedes the interaction (means orphan track?), no need to check it - } else { - LOG(INFO) << "All interaction candidates precede track " << itr << " [" << tTPC.timeBins.getMin() << ":" << tTPC.timeBins.getMax() << "]"; - break; // all interaction candidates precede TPC track + mTimer[SWABMatch].Start(false); + std::vector<ITSChipClustersRefs> itsChipClRefsBuff(mNThreads); +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int ic = 0; ic < nIntCand; ic++) { + const auto& intCand = mInteractions[ic]; + if (!intCand.seedsRef.getEntries()) { + continue; } - } - buildABCluster2TracksLinks(); - selectBestMatchesAB(); // validate matches which are good in both ways: TPCtrack->ITSclusters and ITSclusters->TPCtrack +#ifdef WITH_OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + fillClustersForAfterBurner(intCand.rofITS, 1, itsChipClRefsBuff[tid]); // RS FIXME account for possibility of filling 2 ROFs + for (int is = intCand.seedsRef.getFirstEntry(); is < intCand.seedsRef.getEntriesBound(); is++) { // loop over all seeds of this interaction candidate + processABSeed(is, itsChipClRefsBuff[tid]); + } + } + mTimer[SWABMatch].Stop(); + mTimer[SWABWinners].Start(false); + int nwin = 0; + // select winners + int iter = 0; + struct SID { + int seedID = -1; + float chi2 = 1e9; + }; + std::vector<SID> candAB; + candAB.reserve(nABSeeds); + mABWinnersIDs.reserve(mTPCABIndexCache.size()); - // tmp - if (mDBGOut) { - for (const auto& llinks : mABTrackLinksList) { - dumpABTracksDebugTree(llinks); + for (int i = 0; i < nABSeeds; i++) { + auto& ABSeed = mTPCABSeeds[i]; + if (ABSeed.isDisabled()) { + continue; + } + if (ABSeed.lowestLayer > mParams->requireToReachLayerAB) { + ABSeed.disable(); + continue; + } + auto candID = ABSeed.getBestLinkID(); + if (candID < 0 || ABSeed.getLink(candID).nContLayers < mParams->minContributingLayersAB) { + ABSeed.disable(); + continue; + } + candAB.emplace_back(SID{i, ABSeed.getLink(candID).chi2Norm()}); + } + std::sort(candAB.begin(), candAB.end(), [](SID a, SID b) { return a.chi2 < b.chi2; }); + for (int i = 0; i < (int)candAB.size(); i++) { + auto& ABSeed = mTPCABSeeds[candAB[i].seedID]; + if (ABSeed.isDisabled()) { + //RSTMP LOG(INFO) << "Iter: " << iter << " seed is disabled: " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "]" << " last lr: " << int(ABSeed.lowestLayer); + continue; } + auto& tTPC = mTPCWork[ABSeed.tpcWID]; + if (tTPC.matchID > MinusOne) { // this tracks was already validated with other IC + ABSeed.disable(); + //RSTMP LOG(INFO) << "Iter: " << iter << " disabling seed " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "]" << " TPC track " << ABSeed.tpcWID << " already validated" << " last lr: " << int(ABSeed.lowestLayer); + continue; + } + auto bestID = ABSeed.getBestLinkID(); + const auto& link = ABSeed.getLink(bestID); // RS FIXME TMP + if (ABSeed.checkLinkHasUsedClusters(bestID, mABClusterLinkIndex)) { + ABSeed.setNeedAlternative(); // flag for later processing + //RSTMP LOG(INFO) << "Iter: " << iter << " seed has used clusters " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "]" << " last lr: " << int(ABSeed.lowestLayer) << " Ncont: " << int(link.nContLayers);; + continue; + } + ABSeed.validate(bestID); + ABSeed.flagLinkUsedClusters(bestID, mABClusterLinkIndex); + mABWinnersIDs.push_back(tTPC.matchID = candAB[i].seedID); + nwin++; + //RSTMP LOG(INFO) << "Iter: " << iter << " validated seed " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "] for TPC track " << ABSeed.tpcWID << " last lr: " << int(ABSeed.lowestLayer) << " Ncont: " << int(link.nContLayers); } - // tmp + mTimer[SWABWinners].Stop(); + mTimer[SWABRefit].Start(false); + refitABWinners(); + mTimer[SWABRefit].Stop(); } //______________________________________________ -bool MatchTPCITS::runAfterBurner(int tpcWID, int iCStart, int iCEnd) +void MatchTPCITS::refitABWinners() { - // Try to match TPC tracks to ITS clusters, assuming that it comes from interaction candidate in the range [iCStart:iCEnd) - // The track is already propagated to the outer R of the outermost layer - - LOG(INFO) << "AfterBurner for TPC track " << tpcWID << " with int.candidates " << iCStart << " " << iCEnd; - - auto& tTPC = mTPCWork[tpcWID]; - auto& abTrackLinksList = createABTrackLinksList(tpcWID); - - const int maxMissed = 0; - - for (int iCC = iCStart; iCC < iCEnd; iCC++) { - const auto& iCCand = mInteractions[iCC]; - int topLinkID = registerABTrackLink(abTrackLinksList, tTPC, iCC, NITSLayers, tpcWID, MinusTen); // add track copy as a link on N+1 layer - if (topLinkID == MinusOne) { - continue; // link to be discarded, RS: do we need this for the fake layer? + mABTrackletClusterIDs.reserve(mABWinnersIDs.size() * (o2::its::RecoGeomHelper::getNLayers() - mParams->lowestLayerAB)); + mABTrackletRefs.reserve(mABWinnersIDs.size()); + if (mMCTruthON) { + mABTrackletLabels.reserve(mABWinnersIDs.size()); + } + std::map<o2::MCCompLabel, int> labelOccurence; + auto accountClusterLabel = [&labelOccurence, itsClLabs = mITSClsLabels](int clID) { + auto labels = itsClLabs->getLabels(clID); + for (auto lab : labels) { // check all labels of the cluster + if (lab.isSet()) { + labelOccurence[lab]++; + } } - auto& topLink = mABTrackLinks[topLinkID]; + }; - if (correctTPCTrack(topLink, tTPC, iCCand) < 0) { // correct track for assumed Z location calibration - topLink.disable(); + for (auto wid : mABWinnersIDs) { + const auto& ABSeed = mTPCABSeeds[wid]; + int start = mABTrackletClusterIDs.size(); + int lID = ABSeed.winLinkID, ncl = 0; + auto& clref = mABTrackletRefs.emplace_back(start, ncl); + while (lID > MinusOne) { + const auto& winL = ABSeed.getLink(lID); + if (winL.clID > MinusOne) { + mABTrackletClusterIDs.push_back(winL.clID); + ncl++; + clref.pattern |= 0x1 << winL.layerID; + if (mMCTruthON) { + accountClusterLabel(winL.clID); + } + } + lID = winL.parentID; + } + if (!refitABTrack(mABTrackletRefs.size() - 1, ABSeed)) { // on failure, destroy added tracklet reference + mABTrackletRefs.pop_back(); + mABTrackletClusterIDs.resize(start); continue; } - /* - // tmp - LOG(INFO) << "Check track TPC mtc=" << tTPC.matchID << " int.cand. " << iCC - << " [" << tTPC.timeBins.getMin() << ":" << tTPC.timeBins.getMax() << "] for interaction " - << " [" << iCCand.timeBins.getMin() << ":" << iCCand.timeBins.getMax() << "]"; - */ - if (std::abs(topLink.getZ()) > mITSFiducialZCut) { // we can discard this seed - topLink.disable(); + if (mMCTruthON) { + o2::MCCompLabel lab; + int maxL = 0; // find most encountered label + for (auto [label, count] : labelOccurence) { + if (count > maxL) { + maxL = count; + lab = label; + } + } + if (maxL < ncl) { + lab.setFakeFlag(); + } + labelOccurence.clear(); + mABTrackletLabels.push_back(lab); // ITSAB tracklet label + auto& lblGlo = mOutLabels.emplace_back(mTPCLblWork[ABSeed.tpcWID]); + lblGlo.setFakeFlag(lab != lblGlo); + + LOG(DEBUG) << "ABWinner ncl=" << ncl << " mcLBAB " << lab << " mcLBGlo " << lblGlo << " chi2=" << ABSeed.getLink(ABSeed.winLinkID).chi2Norm() << " pT = " << ABSeed.track.getPt(); } + // build MC label } - for (int ilr = NITSLayers; ilr > 0; ilr--) { - int nextLinkID = abTrackLinksList.firstInLr[ilr]; + LOG(INFO) << "AfterBurner validated " << mABTrackletRefs.size() << " tracks"; +} + +//______________________________________________ +void MatchTPCITS::processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs) +{ + // prepare matching hypothesis tree for given seed + auto& ABSeed = mTPCABSeeds[sid]; + followABSeed(ABSeed.track, itsChipClRefs, MinusTen, NITSLayers - 1, ABSeed); // check matches on outermost layer + for (int ilr = NITSLayers - 1; ilr > mParams->lowestLayerAB; ilr--) { + int nextLinkID = ABSeed.firstInLr[ilr]; if (nextLinkID < 0) { break; } while (nextLinkID > MinusOne) { - if (!mABTrackLinks[nextLinkID].isDisabled()) { - checkABSeedFromLr(ilr, nextLinkID, abTrackLinksList); + const auto& seedLink = ABSeed.getLink(nextLinkID); + if (seedLink.isDisabled()) { + continue; } - nextLinkID = mABTrackLinks[nextLinkID].nextOnLr; + followABSeed(seedLink, itsChipClRefs, nextLinkID, ilr - 1, ABSeed); // check matches on the next layer + nextLinkID = seedLink.nextOnLr; + // RS FIXME account for possibility of missing a layer } - accountForOverlapsAB(ilr - 1); - // printf("After seeds of Lr %d:\n",ilr); - // printABTracksTree(abTrackLinksList); // tmp tmp } - // disable link-list if neiher of seeds reached highest requested layer - if (abTrackLinksList.lowestLayer > mParams->requireToReachLayerAB) { - destroyLastABTrackLinksList(); - tTPC.matchID = MinusTen; - return false; + /* // RS FIXME remove on final clean-up + auto bestLinkID = ABSeed.getBestLinkID(); + if (bestLinkID>MinusOne) { + const auto& bestL = ABSeed.getLink(bestLinkID); + LOG(INFO) << "seed " << sid << " last lr: " << int(ABSeed.lowestLayer) << " Ncont: " << int(bestL.nContLayers) << " chi2 " << bestL.chi2; } - - return true; -} - -//______________________________________________ -void MatchTPCITS::accountForOverlapsAB(int lrSeed) -{ - // TODO - LOG(WARNING) << "TODO"; + else { + LOG(INFO) << "seed " << sid << " : NONE"; + } + */ } //______________________________________________ -int MatchTPCITS::checkABSeedFromLr(int lrSeed, int seedID, ABTrackLinksList& llist) +int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed) { - // check seed isd on layer lrSeed for prolongation to next layer - int lrTgt = lrSeed - 1; - auto& seedLink = mABTrackLinks[seedID]; - o2::track::TrackParCov seed(seedLink); // operate with copy auto propagator = o2::base::Propagator::Instance(); float xTgt; - const auto& lr = mRGHelper.layers[lrTgt]; - if (!seed.getXatLabR(lr.rRange.getMax(), xTgt, propagator->getNominalBz(), o2::track::DirInward) || - !propagator->PropagateToXBxByBz(seed, xTgt, o2::constants::physics::MassPionCharged, MaxSnp, 2., mUseMatCorrFlag)) { - return 0; - } - auto icCandID = seedLink.icCandID; - - // fetch clusters reference object for the ITS ROF corresponding to interaction candidate - const auto& clRefs = *static_cast<const ITSChipClustersRefs*>(mInteractions[icCandID].clRefPtr); - const float nSigmaZ = 5., nSigmaY = 5.; // RS TODO: convert to settable parameter - const float YErr2Extra = 0.1 * 0.1; // // RS TODO: convert to settable parameter - float sna, csa; // circle parameters for B ON data - float zDRStep = -seed.getTgl() * lr.rRange.delta(); // approximate Z span when going from layer rMin to rMax - float errZ = std::sqrt(seed.getSigmaZ2()); - if (lr.zRange.isOutside(seed.getZ(), nSigmaZ * errZ + std::abs(zDRStep))) { - // printf("Lr %d missed by Z = %.2f + %.3f\n", lrTgt, seed.getZ(), nSigmaZ * errZ + std::abs(zDRStep)); // tmp + const auto& lr = mRGHelper.layers[lrID]; + auto seedC = seed; + if (!seedC.getXatLabR(lr.rRange.getMax(), xTgt, propagator->getNominalBz(), o2::track::DirInward) || + !propagator->propagateToX(seedC, xTgt, true, MaxSnp, 2., mUseMatCorrFlag)) { // Bz-propagation only in ITS + return -1; + } + float zDRStep = -seedC.getTgl() * lr.rRange.delta(); // approximate Z span when going from layer rMin to rMax + float errZ = std::sqrt(seedC.getSigmaZ2()); + if (lr.zRange.isOutside(seedC.getZ(), mParams->nABSigmaZ * errZ + std::abs(zDRStep))) { return 0; } - std::vector<int> chipSelClusters; // preliminary cluster candidates //RS TODO do we keep this local / consider array instead of vector - o2::math_utils::CircleXYf_t trcCircle; + std::vector<int> chipSelClusters; // preliminary cluster candidates //RS TODO do we keep this local / consider array instead of vector + o2::math_utils::CircleXYf_t trcCircle; // circle parameters for B ON data o2::math_utils::IntervalXYf_t trcLinPar; // line parameters for B OFF data + float sna, csa; // approximate errors - float errY = std::sqrt(seed.getSigmaY2() + YErr2Extra), errYFrac = errY * mRGHelper.ladderWidthInv(), errPhi = errY * lr.rInv; + float errY = std::sqrt(seedC.getSigmaY2() + mParams->err2ABExtraY), errYFrac = errY * mRGHelper.ladderWidthInv(), errPhi = errY * lr.rInv; if (mFieldON) { - seed.getCircleParams(propagator->getNominalBz(), trcCircle, sna, csa); + seedC.getCircleParams(propagator->getNominalBz(), trcCircle, sna, csa); } else { - seed.getLineParams(trcLinPar, sna, csa); + seedC.getLineParams(trcLinPar, sna, csa); } float xCurr, yCurr; - o2::math_utils::rotateZ(seed.getX(), seed.getY(), xCurr, yCurr, sna, csa); - float phi = std::atan2(yCurr, xCurr); // RS: TODO : can we use fast atan2 here? + o2::math_utils::rotateZ(seedC.getX(), seedC.getY(), xCurr, yCurr, sna, csa); // lab X,Y + float phi = std::atan2(yCurr, xCurr); // RS: TODO : can we use fast atan2 here? // find approximate ladder and chip_in_ladder corresponding to this track extrapolation - int nLad2Check = 0, ladIDguess = lr.getLadderID(phi), chipIDguess = lr.getChipID(seed.getZ() + 0.5 * zDRStep); + int nLad2Check = 0, ladIDguess = lr.getLadderID(phi), chipIDguess = lr.getChipID(seedC.getZ() + 0.5 * zDRStep); std::array<int, MaxLadderCand> lad2Check; - nLad2Check = mFieldON ? findLaddersToCheckBOn(lrTgt, ladIDguess, trcCircle, errYFrac, lad2Check) : findLaddersToCheckBOff(lrTgt, ladIDguess, trcLinPar, errYFrac, lad2Check); + nLad2Check = mFieldON ? findLaddersToCheckBOn(lrID, ladIDguess, trcCircle, errYFrac, lad2Check) : findLaddersToCheckBOff(lrID, ladIDguess, trcLinPar, errYFrac, lad2Check); - const auto& tTPC = mTPCWork[llist.trackID]; // tmp - o2::MCCompLabel lblTrc; - if (mMCTruthON) { - lblTrc = mTPCTrkLabels[tTPC.sourceID]; // tmp - } for (int ilad = nLad2Check; ilad--;) { int ladID = lad2Check[ilad]; const auto& lad = lr.ladders[ladID]; - // we assume that close chips on the same ladder with have close xyEdges, so it is enough to calculate track-chip crossing + // we assume that close chips on the same ladder will have close xyEdges, so it is enough to calculate track-chip crossing // coordinates xCross,yCross,zCross for this central chipIDguess, although we are going to check also neighbours float t = 1e9, xCross, yCross; const auto& chipC = lad.chips[chipIDguess]; @@ -2082,99 +1810,63 @@ int MatchTPCITS::checkABSeedFromLr(int lrSeed, int seedID, ABTrackLinksList& lli chipC.xyEdges.eval(t, xCross, yCross); float dx = xCross - xCurr, dy = yCross - yCurr, dst2 = dx * dx + dy * dy, dst = sqrtf(dst2); // Z-step sign depends on radius decreasing or increasing during the propagation - float zCross = seed.getZ() + seed.getTgl() * (dst2 < 2 * (dx * xCurr + dy * yCurr) ? dst : -dst); + float zCross = seedC.getZ() + seedC.getTgl() * (dst2 < 2 * (dx * xCurr + dy * yCurr) ? dst : -dst); for (int ich = -1; ich < 2; ich++) { int chipID = chipIDguess + ich; if (chipID < 0 || chipID >= lad.chips.size()) { continue; } - if (lad.chips[chipID].zRange.isOutside(zCross, nSigmaZ * errZ)) { + if (lad.chips[chipID].zRange.isOutside(zCross, mParams->nABSigmaZ * errZ)) { continue; } - const auto& clRange = clRefs.chipRefs[lad.chips[chipID].id]; + const auto& clRange = itsChipClRefs.chipRefs[lad.chips[chipID].id]; if (!clRange.getEntries()) { continue; } - /* - // tmp - printf("Lr %d #%d/%d LadID: %d (phi:%+d) ChipID: %d [%d Ncl: %d from %d] (rRhi:%d Z:%+d[%+.1f:%+.1f]) | %+.3f %+.3f -> %+.3f %+.3f %+.3f (zErr: %.3f)\n", - lrTgt, ilad, ich, ladID, lad.isPhiOutside(phi, errPhi), chipID, - chipGID, clRange.getEntries(), clRange.getFirstEntry(), - lad.chips[chipID].xyEdges.seenByCircle(trcCircle, errYFrac), lad.chips[chipID].zRange.isOutside(zCross, 3 * errZ), lad.chips[chipID].zRange.getMin(), lad.chips[chipID].zRange.getMax(), - xCurr, yCurr, xCross, yCross, zCross, errZ); - */ // track Y error in chip frame float errYcalp = errY * (csa * chipC.csAlp + sna * chipC.snAlp); // sigY_rotate(from alpha0 to alpha1) = sigY * cos(alpha1 - alpha0); - float tolerZ = errZ * nSigmaZ, tolerY = errYcalp * nSigmaY; - float yTrack = -xCross * chipC.snAlp + yCross * chipC.csAlp; // track-chip crossing Y in chip frame - if (!preselectChipClusters(chipSelClusters, clRange, clRefs, yTrack, zCross, tolerY, tolerZ, lblTrc)) { // select candidate clusters for this chip + float tolerZ = errZ * mParams->nABSigmaZ, tolerY = errYcalp * mParams->nABSigmaY; + float yTrack = -xCross * chipC.snAlp + yCross * chipC.csAlp; // track-chip crossing Y in chip frame + if (!preselectChipClusters(chipSelClusters, clRange, itsChipClRefs, yTrack, zCross, tolerY, tolerZ)) { // select candidate clusters for this chip continue; } - o2::track::TrackParCov trcLC = seed; + o2::track::TrackParCov trcLC = seedC; + if (!trcLC.rotate(chipC.alp) || !trcLC.propagateTo(chipC.xRef, propagator->getNominalBz())) { - LOG(INFO) << " failed to rotate to alpha=" << chipC.alp << " or prop to X=" << chipC.xRef; - trcLC.print(); - continue; + LOG(DEBUG) << " failed to rotate to alpha=" << chipC.alp << " or prop to X=" << chipC.xRef; + //trcLC.print(); + break; // the chips of the ladder are practically on the same X and alpha } int cntc = 0; for (auto clID : chipSelClusters) { const auto& cls = mITSClustersArray[clID]; auto chi2 = trcLC.getPredictedChi2(cls); - /* - const auto lab = mITSClsLabels->getLabels(clID)[0]; // tmp - LOG(INFO) << "cl " << cntc++ << " ClLbl:" << lab << " TrcLbl" << lblTrc << " chi2 = " << chi2 << " chipGID: " << lad.chips[chipID].id; // tmp - */ if (chi2 > mParams->cutABTrack2ClChi2) { continue; } - int lnkID = registerABTrackLink(llist, trcLC, icCandID, lrTgt, seedID, clID, chi2); // add new link with track copy + int lnkID = registerABTrackLink(ABSeed, trcLC, clID, seedID, lrID, ladID, chi2); // add new link with track copy if (lnkID > MinusOne) { - auto& link = mABTrackLinks[lnkID]; - link.ladderID = ladID; // store ladderID for double hit check -#ifdef _ALLOW_DEBUG_AB_ - link.seed = link; -#endif + auto& link = ABSeed.getLink(lnkID); link.update(cls); - link.chi2 = chi2 + mABTrackLinks[seedID].chi2; // don't use seedLink since it may be changed are reallocation - mABTrackLinks[seedID].nDaughters++; // idem, don't use seedLink.nDaughters++; - - if (lrTgt < llist.lowestLayer) { - llist.lowestLayer = lrTgt; // update lowest layer reached + if (seedID >= MinusOne) { + ABSeed.getLink(seedID).nDaughters++; // RS FIXME : do we need this? + } + if (lrID < ABSeed.lowestLayer) { + ABSeed.lowestLayer = lrID; // update lowest layer reached } - // printf("Added chi2 %.3f @ lr %d as %d\n",link.chi2, lrTgt, lnkID); // tmp tmp } } } } - return mABTrackLinks[seedID].nDaughters; + return 0; } //______________________________________________ -void MatchTPCITS::mergeABSeedsOnOverlaps(int ilrPar, ABTrackLinksList& llist) +void MatchTPCITS::accountForOverlapsAB(int lrSeed) { - // try to merge seeds which may come from double hit on the layer. Parent layer is provided, - // The merged seeds will be added unconditionally (if they pass chi2 cut) - int linksFilled = mABTrackLinks.size(); - int lrID = ilrPar - 1; - int topLinkID = llist.firstInLr[lrID]; - while (topLinkID > MinusOne) { - const auto& topLink = mABTrackLinks[topLinkID]; - int runLinkID = topLink.nextOnLr; // running link ID - while (runLinkID > MinusOne) { - const auto& runLink = mABTrackLinks[runLinkID]; - // to be considered as double hit candidate 2 links must have common parent and neighbouring ladders - while (1) { - if (topLink.parentID != runLink.parentID) { - break; - } - int dLadder = topLink.ladderID - runLink.ladderID; - if (dLadder == 0 || (dLadder > 1 && dLadder != mRGHelper.layers[lrID].ladders.size() - 1)) { // difference must be 1 or Nladders-1 - break; - } - } - } - } + // TODO + LOG(WARNING) << "TODO"; } //______________________________________________ @@ -2250,129 +1942,54 @@ int MatchTPCITS::findLaddersToCheckBOff(int ilr, int lad0, const o2::math_utils: } //______________________________________________ -void MatchTPCITS::buildABCluster2TracksLinks() -{ - // build links from clusters to tracks for afterburner - int nTrackLinkList = mABTrackLinksList.size(); - for (int ils = 0; ils < nTrackLinkList; ils++) { - auto& trList = mABTrackLinksList[ils]; - if (trList.trackID <= MinusOne) { - LOG(ERROR) << "ABTrackLinksList does not point on tracks, impossible"; // tmp - continue; - } - // register all clusters of all seeds starting from the innermost layer - for (int lr = trList.lowestLayer; lr <= mParams->requireToReachLayerAB; lr++) { - int finalTrackLinkIdx = trList.firstInLr[lr]; - while (finalTrackLinkIdx > MinusOne) { // loop over all links of this layer - auto& finalTrackLink = mABTrackLinks[finalTrackLinkIdx]; - if (finalTrackLink.nDaughters) { - finalTrackLinkIdx = finalTrackLink.nextOnLr; // pick next link on the layer - continue; // at this moment we need to find the end-point of the seed - } - // register links for clusters of this seed moving from lowest to upper layer - int followLinkIdx = finalTrackLinkIdx; - while (1) { //>> loop over links of the same seed - const auto& followLink = mABTrackLinks[followLinkIdx]; - int clID = followLink.clID; // in principle, the cluster might be missing on particular layer - if (clID > MinusOne) { //>> register cluster usage - int newClLinkIdx = mABClusterLinks.size(); - auto& newClLink = mABClusterLinks.emplace_back(finalTrackLinkIdx, ils); // create new link - - //>> insert new link in the list of other links for this cluster ordering in track final quality - int clLinkIdx = mABClusterLinkIndex[clID]; - int prevClLinkIdx = MinusOne; - while (clLinkIdx > MinusOne) { - auto& clLink = mABClusterLinks[clLinkIdx]; - const auto& competingTrackLink = mABTrackLinks[clLink.linkedABTrack]; - if (isBetter(finalTrackLink.chi2Norm(), competingTrackLink.chi2Norm())) { - newClLink.nextABClusterLink = clLinkIdx; - break; - } - prevClLinkIdx = clLinkIdx; // check next link - clLinkIdx = clLink.nextABClusterLink; - } - if (prevClLinkIdx > MinusOne) { // new link is not the best (1st) one, register it in its predecessor - mABClusterLinks[prevClLinkIdx].nextABClusterLink = newClLinkIdx; - } else { // new link is the 1st one, register it in the mABClusterLinkIndex - mABClusterLinkIndex[clID] = newClLinkIdx; - } - //<< insert new link in the list of other links for this cluster ordering in track final quality - - } //<< register cluster usage - else if (followLink.isDummyTop()) { // we reached dummy seed on the dummy layer above the last ITS layer - break; - } - - followLinkIdx = followLink.parentID; // go upward - } //>> loop over links of the same seed - - finalTrackLinkIdx = finalTrackLink.nextOnLr; // pick next link on the layer - } // loop over all final seeds of this layer - } - } - printABClusterUsage(); -} - -//______________________________________________ -int MatchTPCITS::registerABTrackLink(ABTrackLinksList& llist, const o2::track::TrackParCov& src, int ic, int lr, int parentID, int clID, float chi2Cl) +int MatchTPCITS::registerABTrackLink(TPCABSeed& ABSeed, const o2::track::TrackParCov& trc, int clID, int parentID, int lr, int laddID, float chi2Cl) { // registers new ABLink on the layer, assigning provided kinematics. The link will be registered in a // way preserving the quality ordering of the links on the layer - int lnkID = mABTrackLinks.size(); - if (llist.firstInLr[lr] == MinusOne) { // no links on this layer yet - if (lr == NITSLayers) { - llist.firstLinkID = lnkID; // register very 1st link - } - llist.firstInLr[lr] = lnkID; - mABTrackLinks.emplace_back(src, ic, lr, parentID, clID); + int lnkID = ABSeed.trackLinks.size(), nextID = ABSeed.firstInLr[lr], nc = 1 + (parentID > MinusOne ? ABSeed.getLink(parentID).nContLayers : 0); + float chi2 = chi2Cl + (parentID > MinusOne ? ABSeed.getLink(parentID).chi2 : 0.); + //LOG(INFO) << "Reg on lr " << lr << " nc = " << nc << " chi2cl=" << chi2Cl << " -> " << chi2; // RSTMP + + if (ABSeed.firstInLr[lr] == MinusOne) { // no links on this layer yet + ABSeed.firstInLr[lr] = lnkID; + ABSeed.trackLinks.emplace_back(trc, clID, parentID, MinusOne, lr, nc, laddID, chi2); return lnkID; } // add new link sorting links of this layer in quality - int count = 0, nextID = llist.firstInLr[lr], topID = MinusOne; + int count = 0, topID = MinusOne; do { - auto& nextLink = mABTrackLinks[nextID]; + auto& nextLink = ABSeed.getLink(nextID); count++; - // if clID==-10, this is a special link on the dummy layer, corresponding to particular Interaction Candidate, in this case - // it does not matter if we add new link before or after the preceding link of the same dummy layer - if (clID == MinusTen || isBetter(mABTrackLinks[parentID].chi2NormPredict(chi2Cl), nextLink.chi2Norm())) { // need to insert new link before nextLink - if (count < mMaxABLinksOnLayer) { // will insert in front of nextID - auto& newLnk = mABTrackLinks.emplace_back(src, ic, lr, parentID, clID); - newLnk.nextOnLr = nextID; // point to the next one - if (topID > MinusOne) { - mABTrackLinks[topID].nextOnLr = lnkID; // point from previous one + bool newIsBetter = parentID <= MinusOne ? isBetter(chi2, nextLink.chi2) : isBetter(ABSeed.getLink(parentID).chi2NormPredict(chi2Cl), nextLink.chi2Norm()); + if (newIsBetter) { // need to insert new link before nextLink + if (count < mParams->maxABLinksOnLayer) { // will insert in front of nextID + ABSeed.trackLinks.emplace_back(trc, clID, parentID, nextID, lr, nc, laddID, chi2); + if (topID == MinusOne) { // are we comparing new link with best link on the layer? + ABSeed.firstInLr[lr] = lnkID; // flag as best on the layer } else { - llist.firstInLr[lr] = lnkID; // flag as best on the layer + ABSeed.getLink(topID).nextOnLr = lnkID; // point from previous one } return lnkID; - } else { // max number of candidates reached, will overwrite the last one - ((o2::track::TrackParCov&)nextLink) = src; // NOTE: this makes sense only if the prolongation tree is filled from top to bottom - return nextID; // i.e. there are no links on the lower layers pointing on overwritten one!!! + } else { // max number of candidates reached, will overwrite the last one + nextLink = ABTrackLink(trc, clID, parentID, MinusOne, lr, nc, laddID, chi2); + return nextID; } } topID = nextID; nextID = nextLink.nextOnLr; } while (nextID > MinusOne); // new link is worse than all others, add it only if there is a room to expand - if (count < mMaxABLinksOnLayer) { - mABTrackLinks.emplace_back(src, ic, lr, parentID, clID); + if (count < mParams->maxABLinksOnLayer) { + ABSeed.trackLinks.emplace_back(trc, clID, parentID, MinusOne, lr, nc, laddID, chi2); if (topID > MinusOne) { - mABTrackLinks[topID].nextOnLr = lnkID; // point from previous one + ABSeed.getLink(topID).nextOnLr = lnkID; // point from previous one } return lnkID; } return MinusOne; // link to be ignored } -//______________________________________________ -ABTrackLinksList& MatchTPCITS::createABTrackLinksList(int tpcWID) -{ - // return existing or newly created AB links list for TPC track work copy ID - auto& tTPC = mTPCWork[tpcWID]; - tTPC.matchID = mABTrackLinksList.size(); // register new list in the TPC track - return mABTrackLinksList.emplace_back(tpcWID); -} - //______________________________________________ float MatchTPCITS::correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const { @@ -2380,14 +1997,14 @@ float MatchTPCITS::correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTP // return extra uncertainty in Z due to the interaction time incertainty // TODO: at the moment, apply simple shift, but with Z-dependent calibration we may // need to do corrections on TPC cluster level and refit - auto tpcTrOrig = mTPCTracksArray[tTPC.sourceID]; - if (tpcTrOrig.hasBothSidesClusters()) { - return 0.; + if (tTPC.constraint == TrackLocTPC::Constrained) { + return 0.f; } - float timeIC = cand.timeBins.mean(), timeTrc = tpcTrOrig.getTime0(); - float driftErr = cand.timeBins.delta() * mTPCBin2Z; + auto tpcTrOrig = mTPCTracksArray[tTPC.sourceID]; + float timeIC = cand.tBracket.mean(); + float driftErr = cand.tBracket.delta() * mTPCBin2Z; - // we use this for refit + // we use this for refit, at the moment do not... /* { float r = std::sqrt(trc.getX()*trc.getX() + trc.getY()*trc.getY()); @@ -2399,21 +2016,21 @@ float MatchTPCITS::correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTP float xTgt; auto propagator = o2::base::Propagator::Instance(); if (!trc.getXatLabR(r, xTgt, propagator->getNominalBz(), o2::track::DirInward) || - !propagator->PropagateToXBxByBz(trc, xTgt, o2::constants::physics::MassPionCharged, MaxSnp, 2., mUseMatCorrFlag)) { + !propagator->PropagateToXBxByBz(trc, xTgt, MaxSnp, 2., mUseMatCorrFlag)) { return -1; } } */ // if interaction time precedes the initial assumption on t0 (i.e. timeIC < timeTrc), // the track actually was drifting longer, i.e. tracks should be shifted closer to the CE - float dDrift = (timeIC - timeTrc) * mTPCBin2Z; + float dDrift = (timeIC - tTPC.time0) * mTPCBin2Z; float zz = tTPC.getZ() + (tpcTrOrig.hasASideClustersOnly() ? dDrift : -dDrift); // tmp - LOG(INFO) << "CorrTrack Z=" << trc.getZ() << " (zold= " << zz << ") at TIC= " << timeIC << " Ttr= " << timeTrc; // tmp + LOG(INFO) << "CorrTrack Z=" << trc.getZ() << " (zold= " << zz << ") at TIC= " << timeIC << " Ttr= " << tTPC.time0; // tmp // we use this w/o refit // /* { - trc.setZ(tTPC.getZ() + (tpcTrOrig.hasASideClustersOnly() ? dDrift : -dDrift)); + trc.setZ(tTPC.getZ() + (tTPC.constraint == TrackLocTPC::ASide ? dDrift : -dDrift)); } // */ trc.setCov(trc.getSigmaZ2() + driftErr * driftErr, o2::track::kSigZ2); @@ -2422,7 +2039,7 @@ float MatchTPCITS::correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTP } //______________________________________________ -void MatchTPCITS::fillClustersForAfterBurner(ITSChipClustersRefs& refCont, int rofStart, int nROFs) +void MatchTPCITS::fillClustersForAfterBurner(int rofStart, int nROFs, ITSChipClustersRefs& itsChipClRefs) { // Prepare unused clusters of given ROFs range for matching in the afterburner // Note: normally only 1 ROF needs to be filled (nROFs==1 ) unless we want @@ -2431,15 +2048,16 @@ void MatchTPCITS::fillClustersForAfterBurner(ITSChipClustersRefs& refCont, int r for (int ir = nROFs; ir--;) { last += mITSClusterROFRec[rofStart + ir].getNEntries(); } - refCont.clear(); - auto& idxSort = refCont.clusterID; + itsChipClRefs.clear(); + auto& idxSort = itsChipClRefs.clusterID; for (int icl = first; icl < last; icl++) { if (mABClusterLinkIndex[icl] != MinusTen) { // clusters with MinusOne are used in main matching idxSort.push_back(icl); } } // sort in chip, Z - sort(idxSort.begin(), idxSort.end(), [clusArr = mITSClustersArray](int i, int j) { + const auto& clusArr = mITSClustersArray; + std::sort(idxSort.begin(), idxSort.end(), [&clusArr](int i, int j) { const auto &clI = clusArr[i], &clJ = clusArr[j]; if (clI.getSensorID() < clJ.getSensorID()) { return true; @@ -2461,7 +2079,7 @@ void MatchTPCITS::fillClustersForAfterBurner(ITSChipClustersRefs& refCont, int r chipClRefs->setEntries(nClInSens); nClInSens = 0; } - chipClRefs = &refCont.chipRefs[(lastSens = sens)]; + chipClRefs = &itsChipClRefs.chipRefs[(lastSens = sens)]; chipClRefs->setFirstEntry(icl); } nClInSens++; @@ -2472,237 +2090,11 @@ void MatchTPCITS::fillClustersForAfterBurner(ITSChipClustersRefs& refCont, int r } //______________________________________________ -void MatchTPCITS::selectBestMatchesAB() -{ - ///< loop over After-Burner match records and select the ones with best quality - LOG(INFO) << "Selecting best AfterBurner matches "; - int nValidated = 0, iter = 0; - - int nTrackLinkList = mABTrackLinksList.size(), nremaining = 0; - do { - nValidated = nremaining = 0; - for (int ils = 0; ils < nTrackLinkList; ils++) { - auto& trList = mABTrackLinksList[ils]; - if (trList.isValidated() || trList.isDisabled()) { - continue; - } - nremaining++; - if (validateABMatch(ils)) { - nValidated++; - continue; - } - } - printf("iter %d Validated %d of %d remaining AB matches\n", iter, nValidated, nremaining); - iter++; - } while (nValidated); -} - -//______________________________________________ -bool MatchTPCITS::validateABMatch(int ilink) +void MatchTPCITS::setITSROFrameLengthMUS(float fums) { - // make sure the preference of the set of cluster by this link is reciprocal - - buildBestLinksList(ilink); - - auto& trList = mABTrackLinksList[ilink]; - - // pick the best TPC->ITS links branch - int bestHypID = trList.firstInLr[trList.lowestLayer]; - const auto& bestHyp = mABTrackLinks[bestHypID]; // best hypothesis - - LOG(INFO) << "validateABMatch " << ilink; - printABTracksTree(trList); - - int parID = bestHypID; - int headID = parID; - while (1) { - const auto& lnk = mABTrackLinks[parID]; - LOG(INFO) << " *link " << parID << "(head " << headID << " cl: " << lnk.clID << " on Lr:" << int(lnk.layerID) << ")"; // tmp - if (lnk.clID > MinusOne) { - int clLnkIdx = mABClusterLinkIndex[lnk.clID]; // id of ITSclus->TPCtracks quality records - if (clLnkIdx < Zero) { - LOG(ERROR) << "AB-referred cluster " << lnk.clID << " does not have ABlinks record"; - continue; - } - - // navigate to best *available* ABlTrackLinkList contributed by this cluster - while (mABTrackLinksList[mABClusterLinks[clLnkIdx].linkedABTrackList].isValidated()) { - clLnkIdx = mABClusterLinks[clLnkIdx].nextABClusterLink; - } - if (clLnkIdx < Zero) { - LOG(ERROR) << "AB-referred cluster " << lnk.clID << " does not have ABlinks record, exhausted?"; - continue; - } - - const auto& linkCl = mABClusterLinks[clLnkIdx]; - - //<< tmp : for printout only - std::stringstream mcStr; - mcStr << " **cl" << lnk.clID << " -> seed:" << linkCl.linkedABTrack << '/' << linkCl.linkedABTrackList << " | "; - // find corresponding TPC track - int linkID = linkCl.linkedABTrack; - while (1) { - const auto& linkTrack = mABTrackLinks[linkID]; - linkID = linkTrack.parentID; - if (linkTrack.isDummyTop()) { - break; - } - } - mcStr << "{TPCwrk: " << linkID << "} "; - if (mITSClsLabels) { - auto lbls = mITSClsLabels->getLabels(lnk.clID); - for (const auto lbl : lbls) { - if (lbl.isValid()) { - mcStr << '[' << lbl.getSourceID() << '/' << lbl.getEventID() << '/' << (lbl.isFake() ? '-' : '+') << std::setw(6) << lbl.getTrackID() << ']'; - } else { - mcStr << (lbl.isNoise() ? "[noise]" : "[unset]"); - } - } - } - LOG(INFO) << mcStr.str(); - //>> tmp - - if (linkCl.linkedABTrack != headID) { // best link for this cluster differs from the link we are checking - return false; - } - } else if (lnk.isDummyTop()) { // top layer reached, this is winner - break; - } - parID = lnk.parentID; // check next cluster of the same link - } - LOG(INFO) << "OK validateABMatch " << ilink; - trList.validate(); - return true; -} - -//______________________________________________ -void MatchTPCITS::buildBestLinksList(int ilink) -{ - ///< build ordered list of links for given ABTrackLinksList, including those finishing on higher layers - auto& trList = mABTrackLinksList[ilink]; - - // pick the best TPC->ITS links branch - // int bestHypID = trList.firstInLr[trList.lowestLayer]; - // - - int start = mABBestLinks.size(); // order links will be added started from here - // 1) the links on the lowestLayer are already sorted, just copy them - int lowestLayer = trList.lowestLayer; - int nextID = trList.firstInLr[lowestLayer]; - int prevOrdLink = MinusOne, newOrdLinkID = MinusOne; - int nHyp = 0; - while (nextID > MinusOne && nHyp < mMaxABFinalHyp) { - newOrdLinkID = mABBestLinks.size(); - auto& best = mABBestLinks.emplace_back(nextID); - nHyp++; - if (prevOrdLink != MinusOne) { - mABBestLinks[prevOrdLink].nextLinkID = newOrdLinkID; // register reference on the new link from previous one - } - prevOrdLink = newOrdLinkID; - nextID = mABTrackLinks[nextID].nextOnLr; - } - trList.bestOrdLinkID = start; - - // now check if shorter seed links from layers above need to be considered as final track candidates - while (++lowestLayer <= mParams->requireToReachLayerAB) { - nextID = trList.firstInLr[lowestLayer]; - - while (nextID > MinusOne) { - auto& candHyp = mABTrackLinks[nextID]; - // compare candHyp with already stored best hypotheses (keeping in mind that within a single layer they are already sorted in quality - - int nextBest = trList.bestOrdLinkID, prevBest = MinusOne; - while (nextBest > MinusOne) { - const auto& bestOrd = mABBestLinks[nextBest]; - const auto& bestHyp = mABTrackLinks[bestOrd.trackLinkID]; - if (isBetter(candHyp.chi2Norm(), bestHyp.chi2Norm())) { // need to insert new candidate before bestOrd - break; - } - prevBest = nextBest; - nextBest = bestOrd.nextLinkID; - } - - bool reuseWorst = false, newIsWorst = (nextBest <= MinusOne); - if (nHyp == mMaxABFinalHyp) { // max number of best hypotheses reached - if (newIsWorst) { // the bestHyp is worse than all already registered hypotheses, - break; // ignore candHyp and all remaining hypotheses on this layer since they are worse - } - reuseWorst = true; // we don't add new ordLink slot to the pool but reuse the worst one - } - - int newID = mABBestLinks.size(); - if (reuseWorst) { // navigate to worst hypothesis link in order to use it for registration of new ordLink - int nextWorst = nextBest, prevWorst = prevBest; - while (mABBestLinks[nextWorst].nextLinkID > MinusOne) { // navigate to worst hypothesis link - prevWorst = nextWorst; - nextWorst = mABBestLinks[nextWorst].nextLinkID; - } - newID = nextWorst; - if (prevWorst > MinusOne) { // detach the reused slot from the superior slot refferring to suppressed one - mABBestLinks[prevWorst].nextLinkID = MinusOne; - } - } else { // add new slot to the pool - mABBestLinks.emplace_back(); - nHyp++; - } - mABBestLinks[newID].trackLinkID = nextID; - if (newID != nextBest) { // if we did not reuse the worst link, register the worse one here - mABBestLinks[newID].nextLinkID = nextBest; - } - if (prevBest > MinusOne) { - mABBestLinks[prevBest].nextLinkID = newID; // register new ordLink in its superior link - } else { // register new ordLink as best link - trList.bestOrdLinkID = newID; - } - - nextID = candHyp.nextOnLr; - } - } -} - -void MatchTPCITS::refitABTrack(int ibest) const -{ - auto propagator = o2::base::Propagator::Instance(); - const float maxStep = 2.f; // max propagation step (TODO: tune) - - int ncl = 0; - const auto& lnk0 = mABTrackLinks[ibest]; - o2::track::TrackParCov trc = lnk0; - trc.resetCovariance(); - const auto& cl0 = mITSClustersArray[lnk0.clID]; - trc.setY(cl0.getY()); - trc.setZ(cl0.getZ()); - trc.setCov(cl0.getSigmaY2(), o2::track::kSigY2); - trc.setCov(cl0.getSigmaZ2(), o2::track::kSigZ2); - trc.setCov(cl0.getSigmaYZ(), o2::track::kSigZY); // for the 1st point we don't need any fit - ibest = lnk0.parentID; - float chi2 = 0; - while (ibest > MinusOne) { - const auto& lnk = mABTrackLinks[ibest]; - if (!trc.rotate(lnk.getAlpha()) || - !propagator->propagateToX(trc, lnk.getX(), propagator->getNominalBz(), o2::constants::physics::MassPionCharged, - MaxSnp, maxStep, mUseMatCorrFlag, nullptr)) { - LOG(WARNING) << "Failed to rotate to " << lnk.getAlpha() << " or propagate to " << lnk.getX(); - LOG(WARNING) << trc.asString(); - break; - } - if (lnk.clID > MinusOne) { - const auto& cl = mITSClustersArray[lnk.clID]; - chi2 += trc.getPredictedChi2(cl); - if (!trc.update(cl)) { - LOG(WARNING) << "Failed to update by " << cl; - LOG(WARNING) << trc.asString(); - break; - } - ncl++; - } else if (lnk.isDummyTop()) { // dummy layer to which TPC track was propagated - LOG(INFO) << "end of fit: chi2=" << chi2 << " ncl= " << ncl; - LOG(INFO) << "TPCtrc: " << lnk.asString(); - LOG(INFO) << "ITStrc: " << trc.asString(); - break; - } - ibest = lnk.parentID; - } + mITSROFrameLengthMUS = fums; + mITSROFrameLengthMUSInv = 1. / mITSROFrameLengthMUS; + mITSROFrameLengthInBC = std::max(1, int(mITSROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3))); } //______________________________________________ @@ -2710,6 +2102,7 @@ void MatchTPCITS::setITSROFrameLengthInBC(int nbc) { mITSROFrameLengthInBC = nbc; mITSROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + mITSROFrameLengthMUSInv = 1. / mITSROFrameLengthMUS; } //___________________________________________________________________ @@ -2738,14 +2131,14 @@ void MatchTPCITS::setBunchFilling(const o2::BunchFilling& bf) } //___________________________________________________________________ -MatchTPCITS::BracketIR MatchTPCITS::tpcTimeBin2IRBracket(const BracketF tbrange) +MatchTPCITS::BracketIR MatchTPCITS::tBracket2IRBracket(const BracketF tbrange) { - // convert TPC timebins bracket to IR bracket + // convert time bracket to IR bracket o2::InteractionRecord irMin(mStartIR), irMax(mStartIR); if (tbrange.getMin() > 0) { - irMin += o2::InteractionRecord(tpcTimeBin2NS(tbrange.getMin())); + irMin += o2::InteractionRecord(tbrange.getMin() * 1000.f); // time in ns is needed } - irMax += o2::InteractionRecord(tpcTimeBin2NS(tbrange.getMax())); + irMax += o2::InteractionRecord(tbrange.getMax() * 1000.f); irMax++; // to account for rounding int bc = mClosestBunchAbove[irMin.bc]; if (bc < irMin.bc) { @@ -2764,6 +2157,105 @@ MatchTPCITS::BracketIR MatchTPCITS::tpcTimeBin2IRBracket(const BracketF tbrange) return {irMin, irMax}; } +//______________________________________________ +void MatchTPCITS::removeTPCfromITS(int tpcID, int itsID) +{ + ///< remove reference to tpcID track from itsID track matches + auto& tITS = mITSWork[itsID]; + if (isValidatedITS(tITS)) { + return; + } + int topID = MinusOne, next = tITS.matchID; // ITS MatchRecord + while (next > MinusOne) { + auto& rcITS = mMatchRecordsITS[next]; + if (rcITS.partnerID == tpcID) { + if (topID < 0) { + tITS.matchID = rcITS.nextRecID; + } else { + mMatchRecordsITS[topID].nextRecID = rcITS.nextRecID; + } + return; + } + topID = next; + next = rcITS.nextRecID; + } +} + +//______________________________________________ +void MatchTPCITS::removeITSfromTPC(int itsID, int tpcID) +{ + ///< remove reference to itsID track from matches of tpcID track + auto& tTPC = mTPCWork[tpcID]; + if (isValidatedTPC(tTPC)) { + return; + } + int topID = MinusOne, next = tTPC.matchID; + while (next > MinusOne) { + auto& rcTPC = mMatchRecordsTPC[next]; + if (rcTPC.partnerID == itsID) { + if (topID < 0) { + tTPC.matchID = rcTPC.nextRecID; + } else { + mMatchRecordsTPC[topID].nextRecID = rcTPC.nextRecID; + } + return; + } + topID = next; + next = rcTPC.nextRecID; + } +} + +//______________________________________________ +void MatchTPCITS::flagUsedITSClusters(const o2::its::TrackITS& track) +{ + // flag clusters used by this track + int clEntry = track.getFirstClusterEntry(); + for (int icl = track.getNumberOfClusters(); icl--;) { + mABClusterLinkIndex[mITSTrackClusIdx[clEntry++]] = MinusTen; + } +} + +//__________________________________________________________ +int MatchTPCITS::preselectChipClusters(std::vector<int>& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& itsChipClRefs, + float trackY, float trackZ, float tolerY, float tolerZ) const +{ + clVecOut.clear(); + int icID = clRange.getFirstEntry(); + for (int icl = clRange.getEntries(); icl--;) { // note: clusters within a chip are sorted in Z + int clID = itsChipClRefs.clusterID[icID++]; // so, we go in clusterID increasing direction + const auto& cls = mITSClustersArray[clID]; + float dz = trackZ - cls.getZ(); + auto label = mITSClsLabels->getLabels(clID)[0]; // tmp + LOG(DEBUG) << "cl" << icl << '/' << clID << " " + << " dZ: " << dz << " [" << tolerZ << "| dY: " << trackY - cls.getY() << " [" << tolerY << "]"; + if (dz > tolerZ) { + float clsZ = cls.getZ(); + LOG(DEBUG) << "Skip the rest since " << trackZ << " > " << clsZ << "\n"; + break; + } else if (dz < -tolerZ) { + LOG(DEBUG) << "Skip cluster dz=" << dz << " Ztr=" << trackZ << " zCl=" << cls.getZ(); + continue; + } + if (fabs(trackY - cls.getY()) > tolerY) { + LOG(DEBUG) << "Skip cluster dy= " << trackY - cls.getY() << " Ytr=" << trackY << " yCl=" << cls.getY(); + continue; + } + clVecOut.push_back(clID); + } + return clVecOut.size(); +} + +//__________________________________________________________ +void MatchTPCITS::setNThreads(int n) +{ +#ifdef WITH_OPENMP + mNThreads = n > 0 ? n : 1; +#else + LOG(WARNING) << "Multithreading is not supported, imposing single thread"; + mNThreads = 1; +#endif +} + //<<============================= AfterBurner for TPC-track / ITS cluster matching ===================<< #ifdef _ALLOW_DEBUG_TREES_ @@ -2792,7 +2284,7 @@ void MatchTPCITS::fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float c } o2::MCCompLabel lblITS, lblTPC; (*mDBGOut) << "match" - << "chi2Match=" << chi2 << "its=" << trackITS << "tpc=" << trackTPC; + << "tf=" << mTFCount << "chi2Match=" << chi2 << "its=" << trackITS << "tpc=" << trackTPC; if (mMCTruthON) { lblITS = mITSLblWork[itsID]; lblTPC = mTPCLblWork[tpcID]; @@ -2823,8 +2315,7 @@ void MatchTPCITS::dumpWinnerMatches() auto& tTPC = mTPCWork[itpc]; (*mDBGOut) << "matchWin" - << "chi2Match=" << itsMatchRec.chi2 << "chi2Refit=" << mWinnerChi2Refit[iits] << "its=" << tITS - << "tpc=" << tTPC; + << "tf=" << mTFCount << "chi2Match=" << itsMatchRec.chi2 << "chi2Refit=" << mWinnerChi2Refit[iits] << "its=" << tITS << "tpc=" << tTPC; o2::MCCompLabel lblITS, lblTPC; if (mMCTruthON) { diff --git a/Detectors/GlobalTracking/src/MatchTPCITSParams.cxx b/Detectors/GlobalTracking/src/MatchTPCITSParams.cxx index 6783099b24074..9aa7556768091 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITSParams.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITSParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt index 8e75ed40d0cfe..fa1ff0155b28c 100644 --- a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt @@ -1,45 +1,59 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # FIXME: do we actually need a library here, or is the executable enough ? + o2_add_library(GlobalTrackingWorkflow SOURCES src/TrackWriterTPCITSSpec.cxx src/TPCITSMatchingSpec.cxx - src/MatchTPCITSWorkflow.cxx - src/TrackTPCITSReaderSpec.cxx src/PrimaryVertexingSpec.cxx src/PrimaryVertexWriterSpec.cxx - src/PrimaryVertexReaderSpec.cxx src/VertexTrackMatcherSpec.cxx src/SecondaryVertexingSpec.cxx + src/GlobalFwdMatchingSpec.cxx src/SecondaryVertexWriterSpec.cxx - src/SecondaryVertexReaderSpec.cxx + src/CosmicsMatchingSpec.cxx + src/TrackCosmicsWriterSpec.cxx + src/TOFMatcherSpec.cxx + src/GlobalFwdTrackWriterSpec.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTracking + O2::GlobalTrackingWorkflowReaders + O2::GlobalTrackingWorkflowHelpers + O2::DataFormatsGlobalTracking O2::ITStracking O2::ITSWorkflow + O2::MFTTracking + O2::MFTWorkflow O2::TPCWorkflow O2::FT0Workflow O2::ITSMFTWorkflow + O2::MCHWorkflow O2::SimulationDataFormat O2::DetectorsVertexing) o2_add_executable(match-workflow COMPONENT_NAME tpcits SOURCES src/tpcits-match-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow ) + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow) + +o2_add_executable(match-workflow + COMPONENT_NAME cosmics + SOURCES src/cosmics-match-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow O2::TOFWorkflowIO) o2_add_executable(vertexing-workflow COMPONENT_NAME primary SOURCES src/primary-vertexing-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow ) - + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow O2::TOFWorkflowIO) + o2_add_executable(vertex-reader-workflow COMPONENT_NAME primary SOURCES src/primary-vertex-reader-workflow.cxx @@ -53,8 +67,19 @@ o2_add_executable(vertex-reader-workflow o2_add_executable(vertexing-workflow COMPONENT_NAME secondary SOURCES src/secondary-vertexing-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow ) + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow O2::TOFWorkflowIO) + +o2_add_executable(matcher-workflow + COMPONENT_NAME tof + SOURCES src/tof-matcher-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow O2::TOFWorkflowIO) +o2_add_executable(matcher-workflow + COMPONENT_NAME globalfwd + SOURCES src/globalfwd-matcher-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow) add_subdirectory(tofworkflow) add_subdirectory(tpcinterpolationworkflow) +add_subdirectory(helpers) +add_subdirectory(readers) diff --git a/Detectors/GlobalTrackingWorkflow/README.md b/Detectors/GlobalTrackingWorkflow/README.md new file mode 100644 index 0000000000000..4add05b9a97db --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/README.md @@ -0,0 +1,31 @@ +<!-- doxy +\page refDetectorsGlobalTrackingWorkflow Workflows +/doxy --> + +# Global tracking workflows + +## Primary vertexer and vertex-track matcher + +Builds primary vertices from all allowed sources (currently by default: ITS, ITS-TPC, ITS-TPC-TOF, can be reduced with `--vertexing-sources <source0,source1...>`) and if builds a vector of indices (`VtxTrackIndex`) of tracks from every source (currently by default: ITS, TPC, ITS-TPC, TPC-TOF, ITS-TPC-TOF, can be reduced with `--vetex-track-matching-sources`) which either contributes to vertex (flagged) or matches to it time-wise (ambiguous matches are flagged). To disable vertex tracks matching used `--vetex-track-matching-sources none`. +```cpp +o2-primary-vertexing-workflow +``` +The list of track sources used for vertexing can be steer + +## Cosmics tracker + +Matches and refits top-bottom legs of cosmic tracks. A test case: +```cpp +o2-sim -n1000 -m PIPE ITS TPC TOF -g extgen --configKeyValues "GeneratorExternal.fileName=$O2_ROOT/share/Generators/external/GenCosmicsLoader.C;cosmics.maxAngle=30.;cosmics.accept=ITS0" +o2-sim-digitizer-workflow --interactionRate 70000 +o2-tpc-reco-workflow --tpc-digit-reader '--infile tpcdigits.root' --input-type digits --output-type clusters,tracks --configKeyValues "GPU_proc.ompThreads=4;" --shm-segment-size 10000000000 --run | tee recTPC.log +o2-its-reco-workflow --trackerCA --tracking-mode cosmics --shm-segment-size 10000000000 --run | tee recITS.log +o2-tpcits-match-workflow --tpc-track-reader tpctracks.root --tpc-native-cluster-reader "--infile tpc-native-clusters.root" --shm-segment-size 10000000000 --run | tee recTPCITS.log +o2-tof-reco-workflow --shm-segment-size 10000000000 --run | tee recTOF.log +o2-tof-matcher-workflow --shm-segment-size 10000000000 --run | tee recTOF_Tracks.log +o2-cosmics-match-workflow --shm-segment-size 10000000000 --run | tee cosmics.log +``` + +One can account contributions of a limited set of track sources (currently by default: ITS, TPC, ITS-TPC, TPC-TOF, ITS-TPC-TOF) by providing optiont `--track-sources`. + + diff --git a/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt new file mode 100644 index 0000000000000..43c22a5db8929 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(GlobalTrackingWorkflowHelpers + SOURCES src/InputHelper.cxx + PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats + O2::Framework + PRIVATE_LINK_LIBRARIES O2::GlobalTracking # We link all the workflow libs etc as PRIVATE, such that we do not expose tons of headers automatically + O2::ITSWorkflow + O2::ITSMFTWorkflow + O2::MCHWorkflow + O2::MFTWorkflow + O2::TPCWorkflow + O2::GlobalTrackingWorkflowReaders + O2::TOFWorkflowIO + O2::FT0Workflow + O2::FV0Workflow + O2::FDDWorkflow + O2::ZDCWorkflow + O2::ITSMFTWorkflow + O2::TRDWorkflowIO + O2::TPCReaderWorkflow + O2::SimulationDataFormat) + +o2_add_executable(track-cluster-reader + COMPONENT_NAME global + TARGETVARNAME targetName + SOURCES src/GlobalTrackClusterReader.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflowHelpers O2::DetectorsRaw) diff --git a/Detectors/GlobalTrackingWorkflow/helpers/include/GlobalTrackingWorkflowHelpers/InputHelper.h b/Detectors/GlobalTrackingWorkflow/helpers/include/GlobalTrackingWorkflowHelpers/InputHelper.h new file mode 100644 index 0000000000000..2db4b9a2b4f71 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/helpers/include/GlobalTrackingWorkflowHelpers/InputHelper.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GLOBALTRACKING_INPUTHELPER_H +#define O2_GLOBALTRACKING_INPUTHELPER_H + +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/ConfigContext.h" +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace globaltracking +{ + +class InputHelper +{ + public: + using GID = o2::dataformats::GlobalTrackID; + // If "--disable-mc" is passed as option, useMC is overwritten to false. + // If useMC is false, maskClustersMC and maskTracksMC are overwritten to NONE. + // The masks define what data to load in a quite generic way, masks with MC suffix are for the corresponding MC labels. + // For matched tracks, maskMatches refers only to the matching information, while the corresponding maskTracks can still be set to load also the refit matched tracks + // If subSpecStrict==true, then those inputs which are supposed to be produced in the "strict" mode of the extended matching workflow will by pushed with special + // subspec corresponding to this mode (see MatchingType.h) + static int addInputSpecs(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs, + GID::mask_t maskClusters, GID::mask_t maskMatches, GID::mask_t maskTracks, + bool useMC = true, GID::mask_t maskClustersMC = GID::getSourcesMask(GID::ALL), GID::mask_t maskTracksMC = GID::getSourcesMask(GID::ALL), + bool subSpecStrict = false); + static int addInputSpecsPVertex(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs, bool mc); + static int addInputSpecsSVertex(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs); + static int addInputSpecsCosmics(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs, bool mc); + static int addInputSpecsIRFramesITS(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs); +}; + +} // namespace globaltracking +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx new file mode 100644 index 0000000000000..968c7d74f4203 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +using namespace o2::framework; +using namespace o2::globaltracking; +using namespace o2::dataformats; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable visualization of MC data"}}, + {"track-types", VariantType::String, std::string{GlobalTrackID::NONE}, {"comma-separated list of track sources to read"}}, + {"cluster-types", VariantType::String, std::string{GlobalTrackID::NONE}, {"comma-separated list of cluster sources to read"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable reading root files, essentially making this workflow void, but needed for compatibility"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + bool useMC = !cfgc.options().get<bool>("disable-mc"); + GlobalTrackID::mask_t srcTrk = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("track-types")); + GlobalTrackID::mask_t srcCl = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("cluster-types")); + if (!cfgc.helpOnCommandLine() && srcTrk.none() && srcCl.none()) { + throw std::runtime_error("no tracks or clusters requested"); + } + InputHelper::addInputSpecs(cfgc, specs, srcCl, srcTrk, srcTrk, useMC); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx new file mode 100644 index 0000000000000..8b0de77e1fdfb --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file InputHelper.cxx + +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "Framework/ConfigParamRegistry.h" +#include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "ITSWorkflow/TrackReaderSpec.h" +#include "ITSWorkflow/IRFrameReaderSpec.h" +#include "MFTWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/TrackCosmicsReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "FT0Workflow/RecPointReaderSpec.h" +#include "FV0Workflow/RecPointReaderSpec.h" +#include "FDDWorkflow/RecPointReaderSpec.h" +#include "ZDCWorkflow/RecEventReaderSpec.h" +#include "TRDWorkflowIO/TRDTrackletReaderSpec.h" +#include "TRDWorkflowIO/TRDTrackReaderSpec.h" +#include "MCHWorkflow/TrackReaderSpec.h" + +using namespace o2::framework; +using namespace o2::globaltracking; +using namespace o2::dataformats; +using GID = o2::dataformats::GlobalTrackID; + +int InputHelper::addInputSpecs(const ConfigContext& configcontext, WorkflowSpec& specs, + GID::mask_t maskClusters, GID::mask_t maskMatches, GID::mask_t maskTracks, + bool useMC, GID::mask_t maskClustersMC, GID::mask_t maskTracksMC, + bool subSpecStrict) +{ + if (configcontext.options().get<bool>("disable-root-input")) { + return 0; + } + if (useMC && configcontext.options().get<bool>("disable-mc")) { + useMC = false; + } + if (!useMC) { + maskClustersMC = GID::getSourcesMask(GID::NONE); + maskTracksMC = GID::getSourcesMask(GID::NONE); + } + + if (maskTracks[GID::ITS]) { + specs.emplace_back(o2::its::getITSTrackReaderSpec(maskTracksMC[GID::ITS])); + } + if (maskClusters[GID::ITS]) { + specs.emplace_back(o2::itsmft::getITSClusterReaderSpec(maskClustersMC[GID::ITS], true)); + } + if (maskTracks[GID::MFT]) { + specs.emplace_back(o2::mft::getMFTTrackReaderSpec(maskTracksMC[GID::MFT])); + } + if (maskClusters[GID::MFT]) { + specs.emplace_back(o2::itsmft::getMFTClusterReaderSpec(maskClustersMC[GID::MFT], true)); + } + if (maskTracks[GID::MCH]) { + specs.emplace_back(o2::mch::getTrackReaderSpec(maskTracksMC[GID::MCH])); + } + if (maskTracks[GID::TPC]) { + specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(maskTracksMC[GID::TPC])); + } + if (maskClusters[GID::TPC]) { + specs.emplace_back(o2::tpc::getClusterReaderSpec(maskClustersMC[GID::TPC])); + } + if (maskTracks[GID::TPC] && maskClusters[GID::TPC]) { + specs.emplace_back(o2::tpc::getClusterSharingMapSpec()); + } + if (maskMatches[GID::ITSTPC] || maskMatches[GID::ITSTPCTOF] || maskTracks[GID::ITSTPC] || maskTracks[GID::ITSTPCTOF]) { + specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(maskTracksMC[GID::ITSTPC] || maskTracksMC[GID::ITSTPCTOF])); + } + if (maskMatches[GID::ITSTPCTOF] || maskTracks[GID::ITSTPCTOF]) { + specs.emplace_back(o2::tof::getTOFMatchedReaderSpec(maskTracksMC[GID::ITSTPCTOF], false, /*maskTracks[GID::ITSTPCTOF]*/ false)); // ITSTPCTOF does not provide tracks, only matchInfo + } + if (maskClusters[GID::TOF] || maskTracks[GID::ITSTPCTOF]) { // Note: maskTracks[GID::ITSTPCTOF] is only here to match the behavior of RecoContainer::requestTracks + specs.emplace_back(o2::tof::getClusterReaderSpec(maskClustersMC[GID::TOF])); + } + if (maskMatches[GID::TPCTOF]) { + specs.emplace_back(o2::tof::getTOFMatchedReaderSpec(maskTracksMC[GID::TPCTOF], true, maskTracks[GID::TPCTOF], subSpecStrict)); + } + if (maskTracks[GID::FT0] || maskClusters[GID::FT0]) { + specs.emplace_back(o2::ft0::getRecPointReaderSpec(maskTracksMC[GID::FT0] || maskClustersMC[GID::FT0])); + } + if (maskTracks[GID::FV0] || maskClusters[GID::FV0]) { + specs.emplace_back(o2::fv0::getRecPointReaderSpec(maskTracksMC[GID::FV0] || maskClustersMC[GID::FV0])); + } + if (maskTracks[GID::FDD] || maskClusters[GID::FDD]) { + specs.emplace_back(o2::fdd::getFDDRecPointReaderSpec(maskTracksMC[GID::FDD] || maskClustersMC[GID::FDD])); + } + if (maskTracks[GID::ZDC] || maskClusters[GID::ZDC]) { + specs.emplace_back(o2::zdc::getRecEventReaderSpec(maskTracksMC[GID::ZDC] || maskClustersMC[GID::ZDC])); + } + + if (maskClusters[GID::TRD]) { + specs.emplace_back(o2::trd::getTRDTrackletReaderSpec(maskClustersMC[GID::TRD], true)); + } + if (maskTracks[GID::ITSTPCTRD]) { + specs.emplace_back(o2::trd::getTRDGlobalTrackReaderSpec(maskTracksMC[GID::ITSTPCTRD])); + } + if (maskTracks[GID::TPCTRD]) { + specs.emplace_back(o2::trd::getTRDTPCTrackReaderSpec(maskTracksMC[GID::TPCTRD], subSpecStrict)); + } + if (maskTracks[GID::MFTMCH]) { + specs.emplace_back(o2::globaltracking::getGlobalFwdTrackReaderSpec(maskTracksMC[GID::MFTMCH])); + } + return 0; +} + +// attach primary vertex reader +int InputHelper::addInputSpecsPVertex(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs, bool mc) +{ + if (configcontext.options().get<bool>("disable-root-input")) { + return 0; + } + specs.emplace_back(o2::vertexing::getPrimaryVertexReaderSpec(mc)); + return 0; +} + +// attach secondary vertex reader +int InputHelper::addInputSpecsSVertex(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs) +{ + if (configcontext.options().get<bool>("disable-root-input")) { + return 0; + } + specs.emplace_back(o2::vertexing::getSecondaryVertexReaderSpec()); + return 0; +} + +// attach cosmic tracks reader +int InputHelper::addInputSpecsCosmics(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs, bool mc) +{ + if (configcontext.options().get<bool>("disable-root-input")) { + return 0; + } + specs.emplace_back(o2::globaltracking::getTrackCosmicsReaderSpec(mc)); + return 0; +} + +// attach vector of ITS reconstructed IRFrames +int InputHelper::addInputSpecsIRFramesITS(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& specs) +{ + if (configcontext.options().get<bool>("disable-root-input")) { + return 0; + } + specs.emplace_back(o2::its::getIRFrameReaderSpec()); + return 0; +} diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h new file mode 100644 index 0000000000000..25553c5d56d33 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CosmicsMatchingSpec.h + +#ifndef O2_COSMICS_MATCHING_SPEC +#define O2_COSMICS_MATCHING_SPEC + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +framework::DataProcessorSpec getCosmicsMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_TRACKWRITER_TPCITS */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdMatchingSpec.h new file mode 100644 index 0000000000000..87b7b5e7a0bf1 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdMatchingSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdMatchingSpec.h + +#ifndef O2_MATCHING_GLOBALFWD_SPEC +#define O2_MATCHING_GLOBALFWD_SPEC + +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ +/// create a processor spec +framework::DataProcessorSpec getGlobalFwdMatchingSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_MATCHING_MCHMFT_SPEC */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h new file mode 100644 index 0000000000000..0bd6eb8f1b0ec --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdTrackWriterSpec.h + +#ifndef O2_TRACKWRITER_GLOBALFWD +#define O2_TRACKWRITER_GLOBALFWD + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +/// write GlobalMuonTracks a root file +framework::DataProcessorSpec getGlobalFwdTrackWriterSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_TRACKWRITER_GLOBALFWD */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/MatchTPCITSWorkflow.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/MatchTPCITSWorkflow.h deleted file mode 100644 index cc9f9d3b7a403..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/MatchTPCITSWorkflow.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MATCHT_TPCITS_WORKFLOW_H -#define O2_MATCHT_TPCITS_WORKFLOW_H - -/// @file RecoWorkflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace globaltracking -{ - -framework::WorkflowSpec getMatchTPCITSWorkflow(bool useFT0, bool calib, bool useMC, bool disableRootInp, bool disableRootOut); - -} // namespace globaltracking -} // namespace o2 -#endif diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h deleted file mode 100644 index 6a32eb2c537ce..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file PrimaryVertexReaderSpec.h - -#ifndef O2_PRIMARY_VERTEXREADER -#define O2_PRIMARY_VERTEXREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -#include "CommonDataFormat/TimeStamp.h" -#include "ReconstructionDataFormats/VtxTrackIndex.h" -#include "ReconstructionDataFormats/VtxTrackRef.h" -#include "ReconstructionDataFormats/PrimaryVertex.h" -#include "SimulationDataFormat/MCEventLabel.h" - -namespace o2 -{ -namespace vertexing -{ -// read primary vertices produces by the o2-primary-vertexing-workflow - -class PrimaryVertexReader : public o2::framework::Task -{ - using Label = o2::MCEventLabel; - using V2TRef = o2::dataformats::VtxTrackRef; - using PVertex = o2::dataformats::PrimaryVertex; - using GIndex = o2::dataformats::VtxTrackIndex; - - public: - PrimaryVertexReader(bool useMC) : mUseMC(useMC) {} - ~PrimaryVertexReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - protected: - void connectTree(); - - bool mVerbose = false; - bool mUseMC = false; - - std::vector<PVertex> mVertices, *mVerticesPtr = &mVertices; - std::vector<Label> mLabels, *mLabelsPtr = &mLabels; - std::vector<V2TRef> mPV2MatchIdxRef, *mPV2MatchIdxRefPtr = &mPV2MatchIdxRef; - std::vector<GIndex> mPV2MatchIdx, *mPV2MatchIdxPtr = &mPV2MatchIdx; - - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - std::string mFileName = ""; - std::string mFileNameMatches = ""; - std::string mVertexTreeName = "o2sim"; - std::string mVertexBranchName = "PrimaryVertex"; - std::string mVertexTrackIDsBranchName = "PVTrackIndices"; - std::string mVertex2TrackIDRefsBranchName = "PV2TrackRefs"; - std::string mVertexLabelsBranchName = "PVMCTruth"; -}; - -/// create a processor spec -/// read primary vertex data from a root file -o2::framework::DataProcessorSpec getPrimaryVertexReaderSpec(bool useMC); - -} // namespace vertexing -} // namespace o2 - -#endif diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexWriterSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexWriterSpec.h index b722866e17e52..f2eb02d3f3940 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexWriterSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h index b419f788dc220..6d6fcdc9e70a2 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,36 +14,17 @@ /// @file PrimaryVertexingSpec.h -#include "DetectorsVertexing/PVertexer.h" -#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "Framework/Task.h" -#include "TStopwatch.h" +#include "Framework/DataProcessorSpec.h" namespace o2 { namespace vertexing { -using namespace o2::framework; - -class PrimaryVertexingSpec : public Task -{ - public: - PrimaryVertexingSpec(bool validateWithFT0, bool useMC) : mUseMC(useMC), mValidateWithFT0(validateWithFT0) {} - ~PrimaryVertexingSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(EndOfStreamContext& ec) final; - - private: - o2::vertexing::PVertexer mVertexer; - bool mUseMC{false}; ///< MC flag - bool mValidateWithFT0{false}; ///< require vertex validation with FT0 - TStopwatch mTimer; -}; - /// create a processor spec -DataProcessorSpec getPrimaryVertexingSpec(bool validateWithFT0, bool useMC); +o2::framework::DataProcessorSpec getPrimaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool validateWithFT0, bool useMC); } // namespace vertexing } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexReaderSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexReaderSpec.h deleted file mode 100644 index c7864843e2b47..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexReaderSpec.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file SecondaryVertexReaderSpec.h - -#ifndef O2_SECONDARY_VERTEXREADER -#define O2_SECONDARY_VERTEXREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "CommonDataFormat/RangeReference.h" -#include "ReconstructionDataFormats/V0.h" - -namespace o2 -{ -namespace vertexing -{ -// read secondary vertices produces by the o2-secondary-vertexing-workflow - -class SecondaryVertexReader : public o2::framework::Task -{ - using RRef = o2::dataformats::RangeReference<int, int>; - using V0 = o2::dataformats::V0; - - public: - SecondaryVertexReader() = default; - ~SecondaryVertexReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - protected: - void connectTree(); - - bool mVerbose = false; - - std::vector<V0> mV0s, *mV0sPtr = &mV0s; - std::vector<RRef> mPV2V0Ref, *mPV2V0RefPtr = &mPV2V0Ref; - - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - std::string mFileName = ""; - std::string mFileNameMatches = ""; - std::string mSVertexTreeName = "o2sim"; - std::string mV0BranchName = "V0s"; - std::string mPVertex2V0RefBranchName = "PV2V0Refs"; -}; - -/// create a processor spec -/// read secondary vertex data from a root file -o2::framework::DataProcessorSpec getSecondaryVertexReaderSpec(); - -} // namespace vertexing -} // namespace o2 - -#endif diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexWriterSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexWriterSpec.h index 76b3b1d815119..6d814cfe05848 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexWriterSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h index e419c3e3b570a..3376810d08923 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,34 +14,17 @@ /// @file SecondaryVertexingSpec.h -#include "DetectorsVertexing/SVertexer.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" -#include "TStopwatch.h" namespace o2 { namespace vertexing { -using namespace o2::framework; - -class SecondaryVertexingSpec : public Task -{ - public: - SecondaryVertexingSpec() = default; - ~SecondaryVertexingSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(EndOfStreamContext& ec) final; - - private: - o2::vertexing::SVertexer mVertexer; - TStopwatch mTimer; -}; - /// create a processor spec -DataProcessorSpec getSecondaryVertexingSpec(); +o2::framework::DataProcessorSpec getSecondaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool enableCasc); } // namespace vertexing } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h new file mode 100644 index 0000000000000..8fde7d6dacb0a --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatcherSpec.h + +#ifndef O2_TOF_MATCHER_SPEC +#define O2_TOF_MATCHER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/MatchInfoTOFReco.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +framework::DataProcessorSpec getTOFMatcherSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_TOF_MATCHER_SPEC */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h index 3d63a7b26257b..7d8839e89ba2b 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,14 +14,7 @@ #ifndef O2_MATCHING_TPCITS_SPEC #define O2_MATCHING_TPCITS_SPEC -#include "GlobalTracking/MatchTPCITS.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "DataFormatsTPC/Constants.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include <string> -#include <vector> -#include "TStopwatch.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" using namespace o2::framework; @@ -28,27 +22,8 @@ namespace o2 { namespace globaltracking { - -class TPCITSMatchingDPL : public Task -{ - public: - TPCITSMatchingDPL(bool useFT0, bool calib, bool useMC) : mUseFT0(useFT0), mCalibMode(calib), mUseMC(useMC) {} - ~TPCITSMatchingDPL() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(framework::EndOfStreamContext& ec) final; - - private: - o2::globaltracking::MatchTPCITS mMatching; // matching engine - o2::itsmft::TopologyDictionary mITSDict; // cluster patterns dictionary - bool mUseFT0 = false; - bool mCalibMode = false; - bool mUseMC = true; - TStopwatch mTimer; -}; - /// create a processor spec -framework::DataProcessorSpec getTPCITSMatchingSpec(bool useFT0, bool calib, bool useMC, const std::vector<int>& tpcClusLanes); +framework::DataProcessorSpec getTPCITSMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useMC); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h new file mode 100644 index 0000000000000..9cae3afa7b1d5 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackCosmicsWriterSpec.h + +#ifndef O2_TRACK_COSMICS_WRITER +#define O2_TRACK_COSMICS_WRITER + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +/// write cosmics tracks to a root file +framework::DataProcessorSpec getTrackCosmicsWriterSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_TRACK_COSMICS_WRITER */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h deleted file mode 100644 index 31cec61189a26..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.h - -#ifndef O2_GLOBAL_TRACKITSTPCREADER -#define O2_GLOBAL_TRACKITSTPCREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" -#include "SimulationDataFormat/MCCompLabel.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace globaltracking -{ - -class TrackTPCITSReader : public Task -{ - public: - TrackTPCITSReader(bool useMC) : mUseMC(useMC) {} - ~TrackTPCITSReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - void connectTree(const std::string& filename); - bool mUseMC = true; - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - std::string mFileName = ""; - std::vector<o2::dataformats::TrackTPCITS> mTracks, *mTracksPtr = &mTracks; - std::vector<o2::MCCompLabel> mTPCLabels, *mTPCLabelsPtr = &mTPCLabels; - std::vector<o2::MCCompLabel> mITSLabels, *mITSLabelsPtr = &mITSLabels; -}; - -/// create a processor spec -/// read simulated TOF digits from a root file -framework::DataProcessorSpec getTrackTPCITSReaderSpec(bool useMC); - -} // namespace globaltracking -} // namespace o2 - -#endif /* O2_GLOBAL_TRACKITSTPCREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h index 2a3763a61e9f1..f6175dd7c30be 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h index 418331b3c6445..fdb17a1d0443f 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,34 +16,17 @@ /// @brief Specs for vertex track association device /// @author ruben.shahoyan@cern.ch -#include "DetectorsVertexing/VertexTrackMatcher.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" -#include "TStopwatch.h" namespace o2 { namespace vertexing { -using namespace o2::framework; - -class VertexTrackMatcherSpec : public Task -{ - public: - VertexTrackMatcherSpec() = default; - ~VertexTrackMatcherSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(EndOfStreamContext& ec) final; - - private: - o2::vertexing::VertexTrackMatcher mMatcher; - TStopwatch mTimer; -}; - /// create a processor spec -DataProcessorSpec getVertexTrackMatcherSpec(); +o2::framework::DataProcessorSpec getVertexTrackMatcherSpec(o2::dataformats::GlobalTrackID::mask_t src); } // namespace vertexing } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/readers/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/readers/CMakeLists.txt new file mode 100644 index 0000000000000..725b546a34b56 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(GlobalTrackingWorkflowReaders + SOURCES src/TrackCosmicsReaderSpec.cxx + src/SecondaryVertexReaderSpec.cxx + src/PrimaryVertexReaderSpec.cxx + src/TrackTPCITSReaderSpec.cxx + src/GlobalFwdTrackReaderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats + O2::GlobalTracking + O2::SimulationDataFormat) diff --git a/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h new file mode 100644 index 0000000000000..939f15db0b1d3 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdTrackReaderSpec.h + +#ifndef O2_GLOBAL_TRACKGLOBALFWDREADER +#define O2_GLOBAL_TRACKGLOBALFWDREADER + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +framework::DataProcessorSpec getGlobalFwdTrackReaderSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_GLOBAL_TRACKGLOBALFWDREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h new file mode 100644 index 0000000000000..eb8d5b3c1d801 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file PrimaryVertexReaderSpec.h + +#ifndef O2_PRIMARY_VERTEXREADER +#define O2_PRIMARY_VERTEXREADER + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace vertexing +{ +/// create a processor spec +/// read primary vertex data from a root file +o2::framework::DataProcessorSpec getPrimaryVertexReaderSpec(bool useMC); + +} // namespace vertexing +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h new file mode 100644 index 0000000000000..6e80bf3ea2310 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file SecondaryVertexReaderSpec.h + +#ifndef O2_SECONDARY_VERTEXREADER +#define O2_SECONDARY_VERTEXREADER + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace vertexing +{ + +/// create a processor spec +/// read secondary vertex data from a root file +o2::framework::DataProcessorSpec getSecondaryVertexReaderSpec(); + +} // namespace vertexing +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackCosmicsReaderSpec.h b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackCosmicsReaderSpec.h new file mode 100644 index 0000000000000..214e3d4caf081 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackCosmicsReaderSpec.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackCosmicsReaderSpec.h + +#ifndef O2_GLOBAL_TRACKCOSMICS_READER +#define O2_GLOBAL_TRACKCOSMICS_READER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "ReconstructionDataFormats/TrackCosmics.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +class TrackCosmicsReader : public Task +{ + public: + TrackCosmicsReader(bool useMC) : mUseMC(useMC) {} + ~TrackCosmicsReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + bool mUseMC = true; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::vector<o2::dataformats::TrackCosmics> mTracks, *mTracksPtr = &mTracks; + std::vector<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; +}; + +/// create a processor spec to read cosmic tracks from a root file +framework::DataProcessorSpec getTrackCosmicsReaderSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_GLOBAL_TRACKCOSMICREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h new file mode 100644 index 0000000000000..b79db9136e7d7 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/include/GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackTPCITSReader.h + +#ifndef O2_GLOBAL_TRACKITSTPCREADER +#define O2_GLOBAL_TRACKITSTPCREADER + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +/// create a processor spec +framework::DataProcessorSpec getTrackTPCITSReaderSpec(bool useMC); + +} // namespace globaltracking +} // namespace o2 + +#endif /* O2_GLOBAL_TRACKITSTPCREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/readers/src/GlobalFwdTrackReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/readers/src/GlobalFwdTrackReaderSpec.cxx new file mode 100644 index 0000000000000..c806e7411c1b7 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/src/GlobalFwdTrackReaderSpec.cxx @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdTrackReaderSpec.cxx + +#include <vector> +#include "TFile.h" +#include "TTree.h" +#include "Framework/Task.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/SerializationMethods.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <fairlogger/Logger.h> + +using namespace o2::framework; +using namespace o2::globaltracking; + +namespace o2 +{ +namespace globaltracking +{ + +class GlobalFwdTrackReader : public Task +{ + public: + GlobalFwdTrackReader(bool useMC) : mUseMC(useMC) {} + ~GlobalFwdTrackReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + bool mUseMC = true; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::vector<o2::dataformats::GlobalFwdTrack> mTracks, *mTracksPtr = &mTracks; + std::vector<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; +}; + +void GlobalFwdTrackReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("globalfwd-track-infile")); + connectTree(mFileName); +} + +void GlobalFwdTrackReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mTracks.size() << " Global Forward tracks at entry " << ent; + + pc.outputs().snapshot(Output{"GLO", "GLFWD", 0, Lifetime::Timeframe}, mTracks); + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "GLFWD_MC", 0, Lifetime::Timeframe}, mLabels); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void GlobalFwdTrackReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("GlobalFwdTracks")); + assert(mTree); + mTree->SetBranchAddress("fwdtracks", &mTracksPtr); + if (mUseMC) { + mTree->SetBranchAddress("MCTruth", &mLabelsPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getGlobalFwdTrackReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("GLO", "GLFWD", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("GLO", "GLFWD_MC", 0, Lifetime::Timeframe); + } + std::cout << "Requested globalfwd at getGlobalFwdTrackReaderSpec" << std::endl; + return DataProcessorSpec{ + "globalfwd-track-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<GlobalFwdTrackReader>(useMC)}, + Options{ + {"globalfwd-track-infile", VariantType::String, "globalfwdtracks.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/readers/src/PrimaryVertexReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/readers/src/PrimaryVertexReaderSpec.cxx new file mode 100644 index 0000000000000..41b2aee351709 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/src/PrimaryVertexReaderSpec.cxx @@ -0,0 +1,175 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file VertexReaderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "TFile.h" +#include "TTree.h" +#include "CommonDataFormat/TimeStamp.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "SimulationDataFormat/MCEventLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace vertexing +{ + +// read primary vertices produces by the o2-primary-vertexing-workflow +class PrimaryVertexReader : public o2::framework::Task +{ + using Label = o2::MCEventLabel; + using V2TRef = o2::dataformats::VtxTrackRef; + using PVertex = o2::dataformats::PrimaryVertex; + using GIndex = o2::dataformats::VtxTrackIndex; + + public: + PrimaryVertexReader(bool useMC) : mUseMC(useMC) {} + ~PrimaryVertexReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(); + + bool mVerbose = false; + bool mUseMC = false; + + std::vector<PVertex> mVertices, *mVerticesPtr = &mVertices; + std::vector<Label> mLabels, *mLabelsPtr = &mLabels; + std::vector<V2TRef> mPV2MatchIdxRef, *mPV2MatchIdxRefPtr = &mPV2MatchIdxRef; + std::vector<GIndex> mPV2MatchIdx, *mPV2MatchIdxPtr = &mPV2MatchIdx; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::string mFileNameMatches = ""; + std::string mVertexTreeName = "o2sim"; + std::string mVertexBranchName = "PrimaryVertex"; + std::string mVertexTrackIDsBranchName = "PVTrackIndices"; + std::string mVertex2TrackIDRefsBranchName = "PV2TrackRefs"; + std::string mVertexLabelsBranchName = "PVMCTruth"; +}; + +void PrimaryVertexReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("primary-vertex-infile")); + connectTree(); +} + +void PrimaryVertexReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mVerticesPtr->size() << " vertices at entry " << ent; + + pc.outputs().snapshot(Output{"GLO", "PVTX", 0, Lifetime::Timeframe}, mVertices); + pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe}, mPV2MatchIdx); + pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe}, mPV2MatchIdxRef); + + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "PVTX_MCTR", 0, Lifetime::Timeframe}, mLabels); + } + + if (mVerbose) { + int cnt = 0; + for (const auto& vtx : mVertices) { + Label lb; + if (mUseMC) { + lb = mLabels[cnt]; + } + LOG(INFO) << "#" << cnt << " " << vtx << " | MC:" << lb; + LOG(INFO) << "References: " << mPV2MatchIdxRef[cnt]; + for (int is = 0; is < GIndex::NSources; is++) { + LOG(INFO) << GIndex::getSourceName(is) << " : " << mPV2MatchIdxRef[cnt].getEntriesOfSource(is) << " attached:"; + int idMin = mPV2MatchIdxRef[cnt].getFirstEntryOfSource(is), idMax = idMin + mPV2MatchIdxRef[cnt].getEntriesOfSource(is); + std::string trIDs; + int cntT = 0; + for (int i = idMin; i < idMax; i++) { + trIDs += mPV2MatchIdx[i].asString() + " "; + if (!((++cntT) % 15)) { + LOG(INFO) << trIDs; + trIDs = ""; + } + } + if (!trIDs.empty()) { + LOG(INFO) << trIDs; + } + } + cnt++; + } + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void PrimaryVertexReader::connectTree() +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(mFileName.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mVertexTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mVertexBranchName.c_str())); + assert(mTree->GetBranch(mVertexTrackIDsBranchName.c_str())); + assert(mTree->GetBranch(mVertex2TrackIDRefsBranchName.c_str())); + + mTree->SetBranchAddress(mVertexBranchName.c_str(), &mVerticesPtr); + mTree->SetBranchAddress(mVertexTrackIDsBranchName.c_str(), &mPV2MatchIdxPtr); + mTree->SetBranchAddress(mVertex2TrackIDRefsBranchName.c_str(), &mPV2MatchIdxRefPtr); + + if (mUseMC) { + assert(mTree->GetBranch(mVertexLabelsBranchName.c_str())); + mTree->SetBranchAddress(mVertexLabelsBranchName.c_str(), &mLabelsPtr); + } + + LOG(INFO) << "Loaded " << mVertexTreeName << " tree from " << mFileName << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getPrimaryVertexReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("GLO", "PVTX", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); + + if (useMC) { + outputs.emplace_back("GLO", "PVTX_MCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "primary-vertex-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<PrimaryVertexReader>(useMC)}, + Options{ + {"primary-vertex-infile", VariantType::String, "o2_primary_vertex.root", {"Name of the input primary vertex file"}}, + {"vertex-track-matches-infile", VariantType::String, "o2_pvertex_track_matches.root", {"Name of the input file with primary vertex - tracks matches"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace vertexing +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/readers/src/SecondaryVertexReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/readers/src/SecondaryVertexReaderSpec.cxx new file mode 100644 index 0000000000000..ced2c0b821751 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/src/SecondaryVertexReaderSpec.cxx @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file SecondaryVertexReaderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CommonDataFormat/RangeReference.h" +#include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/Cascade.h" +#include "TFile.h" +#include "TTree.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace vertexing +{ +// read secondary vertices produces by the o2-secondary-vertexing-workflow +class SecondaryVertexReader : public o2::framework::Task +{ + using RRef = o2::dataformats::RangeReference<int, int>; + using V0 = o2::dataformats::V0; + using Cascade = o2::dataformats::Cascade; + + public: + SecondaryVertexReader() = default; + ~SecondaryVertexReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(); + + bool mVerbose = false; + + std::vector<V0> mV0s, *mV0sPtr = &mV0s; + std::vector<RRef> mPV2V0Ref, *mPV2V0RefPtr = &mPV2V0Ref; + std::vector<Cascade> mCascs, *mCascsPtr = &mCascs; + std::vector<RRef> mPV2CascRef, *mPV2CascRefPtr = &mPV2CascRef; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::string mFileNameMatches = ""; + std::string mSVertexTreeName = "o2sim"; + std::string mV0BranchName = "V0s"; + std::string mPVertex2V0RefBranchName = "PV2V0Refs"; + std::string mCascBranchName = "Cascades"; + std::string mPVertex2CascRefBranchName = "PV2CascRefs"; +}; + +void SecondaryVertexReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("secondary-vertex-infile")); + connectTree(); +} + +void SecondaryVertexReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mV0s.size() << " V0s and " << mCascs.size() << " cascades at entry " << ent; + + pc.outputs().snapshot(Output{"GLO", "V0S", 0, Lifetime::Timeframe}, mV0s); + pc.outputs().snapshot(Output{"GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe}, mPV2V0Ref); + pc.outputs().snapshot(Output{"GLO", "CASCS", 0, Lifetime::Timeframe}, mCascs); + pc.outputs().snapshot(Output{"GLO", "PVTX_CASCREFS", 0, Lifetime::Timeframe}, mPV2CascRef); + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void SecondaryVertexReader::connectTree() +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(mFileName.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mSVertexTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mV0BranchName.c_str())); + assert(mTree->GetBranch(mPVertex2V0RefBranchName.c_str())); + assert(mTree->GetBranch(mCascBranchName.c_str())); + assert(mTree->GetBranch(mPVertex2CascRefBranchName.c_str())); + + mTree->SetBranchAddress(mV0BranchName.c_str(), &mV0sPtr); + mTree->SetBranchAddress(mPVertex2V0RefBranchName.c_str(), &mPV2V0RefPtr); + mTree->SetBranchAddress(mCascBranchName.c_str(), &mCascsPtr); + mTree->SetBranchAddress(mPVertex2CascRefBranchName.c_str(), &mPV2CascRefPtr); + + LOG(INFO) << "Loaded " << mSVertexTreeName << " tree from " << mFileName << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getSecondaryVertexReaderSpec() +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("GLO", "V0S", 0, Lifetime::Timeframe); // found V0s + outputs.emplace_back("GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe); // prim.vertex -> V0s refs + outputs.emplace_back("GLO", "CASCS", 0, Lifetime::Timeframe); // found Cascades + outputs.emplace_back("GLO", "PVTX_CASCREFS", 0, Lifetime::Timeframe); // prim.vertex -> Cascades refs + + return DataProcessorSpec{ + "secondary-vertex-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<SecondaryVertexReader>()}, + Options{ + {"secondary-vertex-infile", VariantType::String, "o2_secondary_vertex.root", {"Name of the input secondary vertex file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace vertexing +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/readers/src/TrackCosmicsReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/readers/src/TrackCosmicsReaderSpec.cxx new file mode 100644 index 0000000000000..94de4b9426698 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/src/TrackCosmicsReaderSpec.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackCosmicsReaderSpec.cxx + +#include <vector> + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "GlobalTrackingWorkflowReaders/TrackCosmicsReaderSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/SerializationMethods.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::globaltracking; + +namespace o2 +{ +namespace globaltracking +{ +void TrackCosmicsReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("cosmics-infile")); + connectTree(mFileName); +} + +void TrackCosmicsReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mTracks.size() << " Cosmic Tracks at entry " << ent; + + pc.outputs().snapshot(Output{"GLO", "COSMICTRC", 0, Lifetime::Timeframe}, mTracks); + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "COSMICTRC_MC", 0, Lifetime::Timeframe}, mLabels); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void TrackCosmicsReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("cosmics")); + assert(mTree); + mTree->SetBranchAddress("tracks", &mTracksPtr); + if (mUseMC) { + mTree->SetBranchAddress("MCTruth", &mLabelsPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getTrackCosmicsReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("GLO", "COSMICTRC", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("GLO", "COSMICTRC_MC", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "cosmic-track-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TrackCosmicsReader>(useMC)}, + Options{ + {"cosmics-infile", VariantType::String, "cosmics.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/readers/src/TrackTPCITSReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/readers/src/TrackTPCITSReaderSpec.cxx new file mode 100644 index 0000000000000..02a55acd20398 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/readers/src/TrackTPCITSReaderSpec.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackTPCITSReaderSpec.cxx + +#include <vector> +#include "TFile.h" +#include "TTree.h" +#include "Framework/Task.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/SerializationMethods.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsITSMFT/TrkClusRef.h" + +using namespace o2::framework; +using namespace o2::globaltracking; + +namespace o2 +{ +namespace globaltracking +{ + +class TrackTPCITSReader : public Task +{ + public: + TrackTPCITSReader(bool useMC) : mUseMC(useMC) {} + ~TrackTPCITSReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + bool mUseMC = true; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::vector<o2::dataformats::TrackTPCITS> mTracks, *mTracksPtr = &mTracks; + std::vector<o2::itsmft::TrkClusRef> mABTrkClusRefs, *mABTrkClusRefsPtr = &mABTrkClusRefs; + std::vector<int> mABTrkClIDs, *mABTrkClIDsPtr = &mABTrkClIDs; + std::vector<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; + std::vector<o2::MCCompLabel> mLabelsAB, *mLabelsABPtr = &mLabelsAB; +}; + +void TrackTPCITSReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("itstpc-track-infile")); + connectTree(mFileName); +} + +void TrackTPCITSReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mTracks.size() << " TPC-ITS matches at entry " << ent; + + pc.outputs().snapshot(Output{"GLO", "TPCITS", 0, Lifetime::Timeframe}, mTracks); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe}, mABTrkClusRefs); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe}, mABTrkClIDs); + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "TPCITS_MC", 0, Lifetime::Timeframe}, mLabels); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe}, mLabelsAB); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void TrackTPCITSReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("matchTPCITS")); + assert(mTree); + mTree->SetBranchAddress("TPCITS", &mTracksPtr); + mTree->SetBranchAddress("TPCITSABRefs", &mABTrkClusRefsPtr); + mTree->SetBranchAddress("TPCITSABCLID", &mABTrkClIDsPtr); + if (mUseMC) { + mTree->SetBranchAddress("MatchMCTruth", &mLabelsPtr); + mTree->SetBranchAddress("MatchABMCTruth", &mLabelsABPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getTrackTPCITSReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("GLO", "TPCITS", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe); // AftetBurner ITS tracklet references (referred by GlobalTrackID::ITSAB) on cluster indices + outputs.emplace_back("GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe); // cluster indices of ITS tracklets attached by the AfterBurner + if (useMC) { + outputs.emplace_back("GLO", "TPCITS_MC", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe); // AfterBurner ITS tracklet MC + } + + return DataProcessorSpec{ + "itstpc-track-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TrackTPCITSReader>(useMC)}, + Options{ + {"itstpc-track-infile", VariantType::String, "o2match_itstpc.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx new file mode 100644 index 0000000000000..efb7f0dd66aab --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx @@ -0,0 +1,166 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CosmicsMatchingSpec.cxx + +#include <vector> +#include <string> +#include "TStopwatch.h" +#include "GlobalTracking/MatchCosmics.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsTPC/Constants.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/ConfigParamRegistry.h" +#include "GlobalTrackingWorkflow/CosmicsMatchingSpec.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Headers/DataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "Framework/Task.h" + +using namespace o2::framework; +using MCLabelsTr = gsl::span<const o2::MCCompLabel>; +using GTrackID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +namespace o2 +{ +namespace globaltracking +{ + +class CosmicsMatchingSpec : public Task +{ + public: + CosmicsMatchingSpec(std::shared_ptr<DataRequest> dr, bool useMC) : mDataRequest(dr), mUseMC(useMC) {} + ~CosmicsMatchingSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::globaltracking::MatchCosmics mMatching; // matching engine + bool mUseMC = true; + TStopwatch mTimer; +}; + +void CosmicsMatchingSpec::init(InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); + //-------- init geometry and field --------// + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + const auto& alpParams = o2::itsmft::DPLAlpideParam<DetID::ITS>::Instance(); + if (!grp->isDetContinuousReadOut(DetID::ITS)) { + mMatching.setITSROFrameLengthMUS(alpParams.roFrameLengthTrig / 1.e3); // ITS ROFrame duration in \mus + } else { + mMatching.setITSROFrameLengthMUS(alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3); // ITS ROFrame duration in \mus + } + // + std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(DetID::ITS, dictPath, "bin"); + auto itsDict = std::make_unique<o2::itsmft::TopologyDictionary>(); + if (o2::utils::Str::pathExists(dictFile)) { + itsDict->readBinaryFile(dictFile); + LOG(INFO) << "Matching is running with a provided ITS dictionary: " << dictFile; + } else { + LOG(INFO) << "Dictionary " << dictFile << " is absent, Matching expects ITS cluster patterns"; + } + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); + mMatching.setITSDict(itsDict); + + // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB + std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); + std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); + if (o2::utils::Str::pathExists(matLUTFile)) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + + mMatching.setDebugFlag(ic.options().get<int>("debug-tree-flags")); + + mMatching.setUseMC(mUseMC); + mMatching.init(); + // +} + +void CosmicsMatchingSpec::run(ProcessingContext& pc) +{ + mTimer.Start(false); + + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + mMatching.process(recoData); + pc.outputs().snapshot(Output{"GLO", "COSMICTRC", 0, Lifetime::Timeframe}, mMatching.getCosmicTracks()); + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "COSMICTRC_MC", 0, Lifetime::Timeframe}, mMatching.getCosmicTracksLbl()); + } + mTimer.Stop(); +} + +void CosmicsMatchingSpec::endOfStream(EndOfStreamContext& ec) +{ + mMatching.end(); + LOGF(INFO, "Cosmics matching total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool useMC) +{ + std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); + + dataRequest->requestTracks(src, useMC); + dataRequest->requestClusters(src, false); // no MC labels for clusters needed for refit only + + outputs.emplace_back("GLO", "COSMICTRC", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("GLO", "COSMICTRC_MC", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "cosmics-matcher", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<CosmicsMatchingSpec>(dataRequest, useMC)}, + Options{ + {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}, + {"debug-tree-flags", VariantType::Int, 0, {"DebugFlagTypes bit-pattern for debug tree"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx new file mode 100644 index 0000000000000..c0bc8a7aeb526 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx @@ -0,0 +1,151 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdMatchingSpec.cxx + +#include <vector> +#include <string> +#include "TStopwatch.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "CommonUtils/StringUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include "DataFormatsMFT/TrackMFT.h" +#include "DataFormatsITSMFT/Cluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsParameters/GRPObject.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "GlobalTrackingWorkflow/GlobalFwdMatchingSpec.h" + +using namespace o2::framework; +using MCLabelsTr = gsl::span<const o2::MCCompLabel>; +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace globaltracking +{ + +class GlobalFwdMatchingDPL : public Task +{ + public: + GlobalFwdMatchingDPL(std::shared_ptr<DataRequest> dr, bool useMC) + : mDataRequest(dr), mUseMC(useMC) {} + ~GlobalFwdMatchingDPL() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::globaltracking::MatchGlobalFwd mMatching; // Forward matching engine + o2::itsmft::TopologyDictionary mMFTDict; // cluster patterns dictionary + + bool mUseMC = true; + TStopwatch mTimer; +}; + +void GlobalFwdMatchingDPL::init(InitContext& ic) +{ + //-------- init geometry and field --------// + o2::base::GeometryManager::loadGeometry(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + mMatching.setMFTTriggered(!grp->isDetContinuousReadOut(o2::detectors::DetID::MFT)); + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::MFT>::Instance(); + if (mMatching.isMFTTriggered()) { + mMatching.setMFTROFrameLengthMUS(alpParams.roFrameLengthTrig / 1.e3); // MFT ROFrame duration in \mus + } else { + mMatching.setMFTROFrameLengthInBC(alpParams.roFrameLengthInBC); // MFT ROFrame duration in \mus + } + mMatching.setMCTruthOn(mUseMC); + + // set bunch filling. Eventually, this should come from CCDB + const auto* digctx = o2::steer::DigitizationContext::loadFromFile(); + const auto& bcfill = digctx->getBunchFilling(); + mMatching.setBunchFilling(bcfill); + + std::string dictPath = ic.options().get<std::string>("mft-dictionary-path"); + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::MFT, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { + mMFTDict.readBinaryFile(dictFile); + LOG(INFO) << "Forward track-matching is running with a provided MFT dictionary: " << dictFile; + } else { + LOG(INFO) << "Dictionary " << dictFile << " is absent, Matching expects MFT cluster patterns"; + } + mMatching.setMFTDictionary(&mMFTDict); + float matchPlaneZ = ic.options().get<float>("matchPlaneZ"); + mMatching.setMatchingPlaneZ(matchPlaneZ); + std::string matchFcn = ic.options().get<std::string>("matchFcn"); + std::string cutFcn = ic.options().get<std::string>("cutFcn"); + + mMatching.init(matchFcn, cutFcn); +} + +void GlobalFwdMatchingDPL::run(ProcessingContext& pc) +{ + const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().getFirstValid(true).header); + LOG(INFO) << " startOrbit: " << dh->firstTForbit; + mTimer.Start(false); + + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + mMatching.run(recoData); + + pc.outputs().snapshot(Output{"GLO", "GLFWD", 0, Lifetime::Timeframe}, mMatching.getMatchedFwdTracks()); + if (mUseMC) { + pc.outputs().snapshot(Output{"GLO", "GLFWD_MC", 0, Lifetime::Timeframe}, mMatching.getMatchLabels()); + } + mTimer.Stop(); +} + +void GlobalFwdMatchingDPL::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "Forward matcher total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getGlobalFwdMatchingSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); + + o2::dataformats::GlobalTrackID::mask_t src = o2::dataformats::GlobalTrackID::getSourcesMask("MFT,MCH"); + + dataRequest->requestMFTClusters(false); // MFT clusters labels are not used + dataRequest->requestTracks(src, useMC); + + outputs.emplace_back("GLO", "GLFWD", 0, Lifetime::Timeframe); + + if (useMC) { + outputs.emplace_back("GLO", "GLFWD_MC", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "globalfwd-track-matcher", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<GlobalFwdMatchingDPL>(dataRequest, useMC)}, + Options{ + {"matchFcn", VariantType::String, "matchALL", {"Matching function (matchALL, ...)"}}, + {"cutFcn", VariantType::String, "cutDisabled", {"matching candicate cut"}}, + {"matchPlaneZ", o2::framework::VariantType::Float, -77.5f, {"Matching plane z position [-77.5]"}}, + {"mft-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackReaderSpec.cxx new file mode 100644 index 0000000000000..ab847ef8332c0 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackReaderSpec.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdTrackWriterSpec.cxx + +#include <vector> +#include "GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using TracksType = std::vector<o2::dataformats::GlobalFwdTrack>; +using LabelsType = std::vector<o2::MCCompLabel>; + +DataProcessorSpec getGlobalFwdTrackWriterSpec(bool useMC) +{ + // A spectator for logging + auto logger = [](TracksType const& tracks) { + LOG(INFO) << "Writing " << tracks.size() << " GlobalForward Tracks"; + }; + return MakeRootTreeWriterSpec("globalfwd-track-writer", + "globalfwdtracks.root", + "GlobalFwdTracks", + BranchDefinition<TracksType>{InputSpec{"fwdtracks", "GLO", "GLFWD", 0}, "fwdtracks", logger}, + BranchDefinition<LabelsType>{InputSpec{"labels", "GLO", "GLFWD_MC", 0}, "MCTruth", (useMC ? 1 : 0), ""})(); +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackWriterSpec.cxx new file mode 100644 index 0000000000000..ab847ef8332c0 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdTrackWriterSpec.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GlobalFwdTrackWriterSpec.cxx + +#include <vector> +#include "GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using TracksType = std::vector<o2::dataformats::GlobalFwdTrack>; +using LabelsType = std::vector<o2::MCCompLabel>; + +DataProcessorSpec getGlobalFwdTrackWriterSpec(bool useMC) +{ + // A spectator for logging + auto logger = [](TracksType const& tracks) { + LOG(INFO) << "Writing " << tracks.size() << " GlobalForward Tracks"; + }; + return MakeRootTreeWriterSpec("globalfwd-track-writer", + "globalfwdtracks.root", + "GlobalFwdTracks", + BranchDefinition<TracksType>{InputSpec{"fwdtracks", "GLO", "GLFWD", 0}, "fwdtracks", logger}, + BranchDefinition<LabelsType>{InputSpec{"labels", "GLO", "GLFWD_MC", 0}, "MCTruth", (useMC ? 1 : 0), ""})(); +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/MatchTPCITSWorkflow.cxx b/Detectors/GlobalTrackingWorkflow/src/MatchTPCITSWorkflow.cxx deleted file mode 100644 index dd5930b3d0d28..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/src/MatchTPCITSWorkflow.cxx +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file MatchTPCITSWorkflow.cxx - -#include "ITSMFTWorkflow/ClusterReaderSpec.h" -#include "ITSWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/PublisherSpec.h" -#include "FT0Workflow/RecPointReaderSpec.h" -#include "GlobalTrackingWorkflow/TPCITSMatchingSpec.h" -#include "GlobalTrackingWorkflow/MatchTPCITSWorkflow.h" -#include "GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h" -#include "Algorithm/RangeTokenizer.h" -#include "DataFormatsTPC/Constants.h" -#include "GlobalTracking/MatchTPCITSParams.h" - -namespace o2 -{ -namespace globaltracking -{ - -framework::WorkflowSpec getMatchTPCITSWorkflow(bool useFT0, bool useMC, bool disableRootInp, bool disableRootOut, bool calib) -{ - framework::WorkflowSpec specs; - - bool passFullITSClusters = false; // temporarily pass full clusters, - bool passCompITSClusters = true; // eventually only compact of recpoints will be passed - bool passITSClusPatterns = true; - - std::vector<int> tpcClusSectors = o2::RangeTokenizer::tokenize<int>("0-35"); - std::vector<int> tpcClusLanes = tpcClusSectors; - - if (!disableRootInp) { - specs.emplace_back(o2::its::getITSTrackReaderSpec(useMC)); - specs.emplace_back(o2::itsmft::getITSClusterReaderSpec(useMC, passITSClusPatterns)); - specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(useMC)); - specs.emplace_back(o2::tpc::getPublisherSpec(o2::tpc::PublisherConf{ - "tpc-native-cluster-reader", - "tpcrec", - {"clusterbranch", "TPCClusterNative", "Branch with TPC native clusters"}, - {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, - OutputSpec{"TPC", "CLUSTERNATIVE"}, - OutputSpec{"TPC", "CLNATIVEMCLBL"}, - tpcClusSectors, - tpcClusLanes}, - useMC)); - - if (useFT0) { - specs.emplace_back(o2::ft0::getRecPointReaderSpec(useMC)); - } - } - specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(useFT0, calib, useMC, tpcClusLanes)); - - if (!disableRootOut) { - specs.emplace_back(o2::globaltracking::getTrackWriterTPCITSSpec(useMC)); - } - return specs; -} - -} // namespace globaltracking -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx deleted file mode 100644 index a5640d7503689..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file VertexReaderSpec.cxx - -#include <vector> - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace vertexing -{ - -void PrimaryVertexReader::init(InitContext& ic) -{ - mFileName = ic.options().get<std::string>("primary-vertex-infile"); - connectTree(); -} - -void PrimaryVertexReader::run(ProcessingContext& pc) -{ - auto ent = mTree->GetReadEntry() + 1; - assert(ent < mTree->GetEntries()); // this should not happen - mTree->GetEntry(ent); - LOG(INFO) << "Pushing " << mVerticesPtr->size() << " vertices at entry " << ent; - - pc.outputs().snapshot(Output{"GLO", "PVTX", 0, Lifetime::Timeframe}, mVertices); - pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe}, mPV2MatchIdx); - pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe}, mPV2MatchIdxRef); - - if (mUseMC) { - pc.outputs().snapshot(Output{"GLO", "PVTX_MCTR", 0, Lifetime::Timeframe}, mLabels); - } - - if (mVerbose) { - int cnt = 0; - for (const auto& vtx : mVertices) { - Label lb; - if (mUseMC) { - lb = mLabels[cnt]; - } - LOG(INFO) << "#" << cnt << " " << vtx << " | MC:" << lb; - LOG(INFO) << "References: " << mPV2MatchIdxRef[cnt]; - for (int is = 0; is < GIndex::NSources; is++) { - LOG(INFO) << GIndex::getSourceName(is) << " : " << mPV2MatchIdxRef[cnt].getEntriesOfSource(is) << " attached:"; - int idMin = mPV2MatchIdxRef[cnt].getFirstEntryOfSource(is), idMax = idMin + mPV2MatchIdxRef[cnt].getEntriesOfSource(is); - std::string trIDs; - int cntT = 0; - for (int i = idMin; i < idMax; i++) { - trIDs += mPV2MatchIdx[i].asString() + " "; - if (!((++cntT) % 15)) { - LOG(INFO) << trIDs; - trIDs = ""; - } - } - if (!trIDs.empty()) { - LOG(INFO) << trIDs; - } - } - cnt++; - } - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -void PrimaryVertexReader::connectTree() -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(mFileName.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get(mVertexTreeName.c_str())); - assert(mTree); - assert(mTree->GetBranch(mVertexBranchName.c_str())); - assert(mTree->GetBranch(mVertexTrackIDsBranchName.c_str())); - assert(mTree->GetBranch(mVertex2TrackIDRefsBranchName.c_str())); - - mTree->SetBranchAddress(mVertexBranchName.c_str(), &mVerticesPtr); - mTree->SetBranchAddress(mVertexTrackIDsBranchName.c_str(), &mPV2MatchIdxPtr); - mTree->SetBranchAddress(mVertex2TrackIDRefsBranchName.c_str(), &mPV2MatchIdxRefPtr); - - if (mUseMC) { - assert(mTree->GetBranch(mVertexLabelsBranchName.c_str())); - mTree->SetBranchAddress(mVertexLabelsBranchName.c_str(), &mLabelsPtr); - } - - LOG(INFO) << "Loaded " << mVertexTreeName << " tree from " << mFileName << " with " << mTree->GetEntries() << " entries"; -} - -DataProcessorSpec getPrimaryVertexReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("GLO", "PVTX", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); - - if (useMC) { - outputs.emplace_back("GLO", "PVTX_MCTR", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "primary-vertex-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<PrimaryVertexReader>(useMC)}, - Options{ - {"primary-vertex-infile", VariantType::String, "o2_primary_vertex.root", {"Name of the input primary vertex file"}}, - {"vertex-track-matches-infile", VariantType::String, "o2_pvertex_track_matches.root", {"Name of the input file with primary vertex - tracks matches"}}}}; -} - -} // namespace vertexing -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexWriterSpec.cxx index 14770ca5e3be2..1ba4312873048 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexWriterSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx index 95e46098a117e..026be443c78f6 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,11 @@ /// @file PrimaryVertexingSpec.cxx #include <vector> +#include <TStopwatch.h> +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" #include "GlobalTrackingWorkflow/PrimaryVertexingSpec.h" @@ -19,24 +24,62 @@ #include "CommonDataFormat/BunchFilling.h" #include "SimulationDataFormat/DigitizationContext.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsFT0/RecPoints.h" #include "Framework/ConfigParamRegistry.h" +#include "FT0Reconstruction/InteractionTag.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsVertexing/PVertexer.h" using namespace o2::framework; +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; namespace o2 { namespace vertexing { +namespace o2d = o2::dataformats; + +class PrimaryVertexingSpec : public Task +{ + public: + PrimaryVertexingSpec(std::shared_ptr<DataRequest> dr, bool validateWithIR, bool useMC) + : mDataRequest(dr), mUseMC(useMC), mValidateWithIR(validateWithIR) {} + ~PrimaryVertexingSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::vertexing::PVertexer mVertexer; + bool mUseMC{false}; ///< MC flag + bool mValidateWithIR{false}; ///< require vertex validation with IR (e.g. from FT0) + float mITSROFrameLengthMUS = 0.; + TStopwatch mTimer; +}; + void PrimaryVertexingSpec::init(InitContext& ic) { //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP("o2sim_grp.root"); + o2::base::Propagator::initFieldFromGRP(); + + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + const auto& alpParams = o2::itsmft::DPLAlpideParam<DetID::ITS>::Instance(); + if (!grp->isDetContinuousReadOut(DetID::ITS)) { + mITSROFrameLengthMUS = alpParams.roFrameLengthTrig / 1.e3; // ITS ROFrame duration in \mus + } else { + mITSROFrameLengthMUS = alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; // ITS ROFrame duration in \mus + } + mVertexer.setITSROFrameLength(mITSROFrameLengthMUS); + // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); - if (o2::base::NameConf::pathExists(matLUTFile)) { + if (o2::utils::Str::pathExists(matLUTFile)) { auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); o2::base::Propagator::Instance()->setMatLUT(lut); LOG(INFO) << "Loaded material LUT from " << matLUTFile; @@ -45,10 +88,10 @@ void PrimaryVertexingSpec::init(InitContext& ic) } mTimer.Stop(); mTimer.Reset(); - mVertexer.setValidateWithFT0(mValidateWithFT0); + mVertexer.setValidateWithIR(mValidateWithIR); // set bunch filling. Eventually, this should come from CCDB - const auto* digctx = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto* digctx = o2::steer::DigitizationContext::loadFromFile(); const auto& bcfill = digctx->getBunchFilling(); mVertexer.setBunchFilling(bcfill); mVertexer.init(); @@ -58,15 +101,41 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) { double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime(); mTimer.Start(false); - const auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("match"); - gsl::span<const o2::MCCompLabel> lblITS, lblTPC; - gsl::span<const o2::ft0::RecPoints> ft0Data; - if (mValidateWithFT0) { - ft0Data = pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("fitInfo"); - } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer + + std::vector<TrackWithTimeStamp> tracks; + std::vector<o2::MCCompLabel> tracksMCInfo; + std::vector<o2d::GlobalTrackID> gids; + auto maxTrackTimeError = PVertexerParams::Instance().maxTimeErrorMUS; + auto halfROFITS = 0.5 * mITSROFrameLengthMUS; + auto hw2ErrITS = 2.f / std::sqrt(12.f) * mITSROFrameLengthMUS; // conversion from half-width to error for ITS + + auto creator = [maxTrackTimeError, hw2ErrITS, halfROFITS, &tracks, &gids](auto& _tr, GTrackID _origID, float t0, float terr) { + if (!_origID.includesDet(DetID::ITS)) { + return true; // just in case this selection was not done on RecoContainer filling level + } + if constexpr (isITSTrack<decltype(_tr)>()) { + t0 += halfROFITS; // ITS time is supplied in \mus as beginning of ROF + terr *= hw2ErrITS; // error is supplied as a half-ROF duration, convert to \mus + } + // for all other tracks the time is in \mus with gaussian error + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) { + if (terr < maxTrackTimeError) { + tracks.emplace_back(TrackWithTimeStamp{_tr, {t0, terr}}); + gids.emplace_back(_origID); + } + } + + return true; + }; + + recoData.createTracksVariadic(creator); // create track sample considered for vertexing + if (mUseMC) { - lblITS = pc.inputs().get<gsl::span<o2::MCCompLabel>>("lblITS"); - lblTPC = pc.inputs().get<gsl::span<o2::MCCompLabel>>("lblTPC"); + recoData.fillTrackMCLabels(gids, tracksMCInfo); } std::vector<PVertex> vertices; std::vector<GIndex> vertexTrackIDs; @@ -74,10 +143,20 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) std::vector<o2::MCEventLabel> lblVtx; // RS FIXME this will not have effect until the 1st orbit is propagated, until that will work only for TF starting at orbit 0 - const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("match").header); - mVertexer.setStartIR({0, dh->firstTForbit}); + mVertexer.setStartIR({0, DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->firstTForbit}); + + std::vector<o2::InteractionRecord> ft0Data; + if (mValidateWithIR) { // select BCs for validation + const o2::ft0::InteractionTag& ft0Params = o2::ft0::InteractionTag::Instance(); + auto ft0all = recoData.getFT0RecPoints(); + for (const auto& ftRP : ft0all) { + if (ft0Params.isSelected(ftRP)) { + ft0Data.push_back(ftRP.getInteractionRecord()); + } + } + } - mVertexer.process(tracksITSTPC, ft0Data, vertices, vertexTrackIDs, v2tRefs, lblITS, lblTPC, lblVtx); + mVertexer.process(tracks, gids, ft0Data, vertices, vertexTrackIDs, v2tRefs, tracksMCInfo, lblVtx); pc.outputs().snapshot(Output{"GLO", "PVTX", 0, Lifetime::Timeframe}, vertices); pc.outputs().snapshot(Output{"GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe}, v2tRefs); pc.outputs().snapshot(Output{"GLO", "PVTX_CONTID", 0, Lifetime::Timeframe}, vertexTrackIDs); @@ -93,18 +172,19 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) void PrimaryVertexingSpec::endOfStream(EndOfStreamContext& ec) { + mVertexer.end(); LOGF(INFO, "Primary vertexing total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getPrimaryVertexingSpec(bool validateWithFT0, bool useMC) +DataProcessorSpec getPrimaryVertexingSpec(GTrackID::mask_t src, bool validateWithFT0, bool useMC) { - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); - inputs.emplace_back("match", "GLO", "TPCITS", 0, Lifetime::Timeframe); - if (validateWithFT0) { - inputs.emplace_back("fitInfo", "FT0", "RECPOINTS", 0, Lifetime::Timeframe); + dataRequest->requestTracks(src, useMC); + if (validateWithFT0 && src[GTrackID::FT0]) { + dataRequest->requestFT0RecPoints(false); } outputs.emplace_back("GLO", "PVTX", 0, Lifetime::Timeframe); @@ -112,16 +192,14 @@ DataProcessorSpec getPrimaryVertexingSpec(bool validateWithFT0, bool useMC) outputs.emplace_back("GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe); if (useMC) { - inputs.emplace_back("lblITS", "GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - inputs.emplace_back("lblTPC", "GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "PVTX_MCTR", 0, Lifetime::Timeframe); } return DataProcessorSpec{ "primary-vertexing", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<PrimaryVertexingSpec>(validateWithFT0, useMC)}, + AlgorithmSpec{adaptFromTask<PrimaryVertexingSpec>(dataRequest, validateWithFT0, useMC)}, Options{{"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexReaderSpec.cxx deleted file mode 100644 index 5b4e068369bca..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexReaderSpec.cxx +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file SecondaryVertexReaderSpec.cxx - -#include <vector> - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "GlobalTrackingWorkflow/SecondaryVertexReaderSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace vertexing -{ - -void SecondaryVertexReader::init(InitContext& ic) -{ - mFileName = ic.options().get<std::string>("secondary-vertex-infile"); - connectTree(); -} - -void SecondaryVertexReader::run(ProcessingContext& pc) -{ - auto ent = mTree->GetReadEntry() + 1; - assert(ent < mTree->GetEntries()); // this should not happen - mTree->GetEntry(ent); - LOG(INFO) << "Pushing " << mV0sPtr->size() << " V0s at entry " << ent; - - pc.outputs().snapshot(Output{"GLO", "V0s", 0, Lifetime::Timeframe}, mV0s); - pc.outputs().snapshot(Output{"GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe}, mPV2V0Ref); - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -void SecondaryVertexReader::connectTree() -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(mFileName.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get(mSVertexTreeName.c_str())); - assert(mTree); - assert(mTree->GetBranch(mV0BranchName.c_str())); - assert(mTree->GetBranch(mPVertex2V0RefBranchName.c_str())); - - mTree->SetBranchAddress(mV0BranchName.c_str(), &mV0sPtr); - mTree->SetBranchAddress(mPVertex2V0RefBranchName.c_str(), &mPV2V0RefPtr); - - LOG(INFO) << "Loaded " << mSVertexTreeName << " tree from " << mFileName << " with " << mTree->GetEntries() << " entries"; -} - -DataProcessorSpec getSecondaryVertexReaderSpec() -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("GLO", "V0s", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "secondary-vertex-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<SecondaryVertexReader>()}, - Options{ - {"secondary-vertex-infile", VariantType::String, "o2_secondary_vertex.root", {"Name of the input secondary vertex file"}}}}; -} - -} // namespace vertexing -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexWriterSpec.cxx index 021951c35bc78..ec2307161c7e0 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexWriterSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "CommonDataFormat/TimeStamp.h" #include "CommonDataFormat/RangeReference.h" #include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/Cascade.h" using namespace o2::framework; @@ -26,6 +28,7 @@ namespace vertexing { using RRef = o2::dataformats::RangeReference<int, int>; using V0 = o2::dataformats::V0; +using Cascade = o2::dataformats::Cascade; template <typename T> using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; @@ -34,16 +37,26 @@ using namespace o2::header; DataProcessorSpec getSecondaryVertexWriterSpec() { - auto logger = [](std::vector<V0> const& v) { + auto loggerV = [](std::vector<V0> const& v) { LOG(INFO) << "SecondaryVertexWriter pulled " << v.size() << " v0s"; }; - auto inpID = InputSpec{"v0s", "GLO", "V0s", 0}; - auto inpIDRef = InputSpec{"pv2v0ref", "GLO", "PVTX_V0REFS", 0}; + + auto loggerC = [](std::vector<Cascade> const& v) { + LOG(INFO) << "SecondaryVertexWriter pulled " << v.size() << " cascades"; + }; + + auto inpV0ID = InputSpec{"v0s", "GLO", "V0S", 0}; + auto inpV0RefID = InputSpec{"pv2v0ref", "GLO", "PVTX_V0REFS", 0}; + auto inpCascID = InputSpec{"cascs", "GLO", "CASCS", 0}; + auto inpCascRefID = InputSpec{"pv2cascref", "GLO", "PVTX_CASCREFS", 0}; + return MakeRootTreeWriterSpec("secondary-vertex-writer", "o2_secondary_vertex.root", MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with Secondary Vertices"}, - BranchDefinition<std::vector<V0>>{inpID, "V0s", logger}, - BranchDefinition<std::vector<RRef>>{inpIDRef, "PV2V0Refs"})(); + BranchDefinition<std::vector<V0>>{inpV0ID, "V0s", loggerV}, + BranchDefinition<std::vector<RRef>>{inpV0RefID, "PV2V0Refs"}, + BranchDefinition<std::vector<Cascade>>{inpCascID, "Cascades", loggerC}, + BranchDefinition<std::vector<RRef>>{inpCascRefID, "PV2CascRefs"})(); } } // namespace vertexing diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx index 87f51f104549c..a464f5ff08200 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,11 @@ /// @file SecondaryVertexingSpec.cxx #include <vector> +#include "DataFormatsGlobalTracking/RecoContainer.h" #include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsITS/TrackITS.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" #include "GlobalTrackingWorkflow/SecondaryVertexingSpec.h" @@ -19,42 +24,64 @@ #include "CommonDataFormat/BunchFilling.h" #include "SimulationDataFormat/DigitizationContext.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsVertexing/SVertexer.h" +#include "TStopwatch.h" + #include "Framework/ConfigParamRegistry.h" using namespace o2::framework; +using GTrackID = o2::dataformats::GlobalTrackID; using GIndex = o2::dataformats::VtxTrackIndex; using VRef = o2::dataformats::VtxTrackRef; using PVertex = const o2::dataformats::PrimaryVertex; using V0 = o2::dataformats::V0; -using TrackTPCITS = o2::dataformats::TrackTPCITS; -using TrackITS = o2::its::TrackITS; -using TrackTPC = o2::tpc::TrackTPC; +using Cascade = o2::dataformats::Cascade; using RRef = o2::dataformats::RangeReference<int, int>; +using DataRequest = o2::globaltracking::DataRequest; namespace o2 { namespace vertexing { +namespace o2d = o2::dataformats; + +class SecondaryVertexingSpec : public Task +{ + public: + SecondaryVertexingSpec(std::shared_ptr<DataRequest> dr, bool enabCasc) : mDataRequest(dr), mEnableCascades(enabCasc) {} + ~SecondaryVertexingSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + bool mEnableCascades = false; + o2::vertexing::SVertexer mVertexer; + TStopwatch mTimer; +}; + void SecondaryVertexingSpec::init(InitContext& ic) { //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP("o2sim_grp.root"); + o2::base::Propagator::initFieldFromGRP(); // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); - if (o2::base::NameConf::pathExists(matLUTFile)) { + if (o2::utils::Str::pathExists(matLUTFile)) { auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); o2::base::Propagator::Instance()->setMatLUT(lut); LOG(INFO) << "Loaded material LUT from " << matLUTFile; } else { LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; } + mVertexer.setEnableCascades(mEnableCascades); + mVertexer.setNThreads(ic.options().get<int>("threads")); mTimer.Stop(); mTimer.Reset(); - mVertexer.init(); } @@ -63,57 +90,49 @@ void SecondaryVertexingSpec::run(ProcessingContext& pc) double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime(); mTimer.Start(false); - const auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("tpcits"); - const auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("tpc"); - const auto tracksITS = pc.inputs().get<gsl::span<o2::its::TrackITS>>("its"); - - const auto pvertices = pc.inputs().get<gsl::span<o2::dataformats::PrimaryVertex>>("pvtx"); - const auto pvtxTracks = pc.inputs().get<gsl::span<o2::dataformats::VtxTrackIndex>>("pvtx_cont"); - const auto pvtxTrackRefs = pc.inputs().get<gsl::span<o2::dataformats::VtxTrackRef>>("pvtx_tref"); + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); - std::vector<V0> v0s; - std::vector<RRef> pv2v0ref; + auto& v0s = pc.outputs().make<std::vector<V0>>(Output{"GLO", "V0S", 0, Lifetime::Timeframe}); + auto& v0Refs = pc.outputs().make<std::vector<RRef>>(Output{"GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe}); + auto& cascs = pc.outputs().make<std::vector<Cascade>>(Output{"GLO", "CASCS", 0, Lifetime::Timeframe}); + auto& cascRefs = pc.outputs().make<std::vector<RRef>>(Output{"GLO", "PVTX_CASCREFS", 0, Lifetime::Timeframe}); - mVertexer.process(pvertices, pvtxTracks, pvtxTrackRefs, - tracksITSTPC, tracksITS, tracksTPC, - v0s, pv2v0ref); - - pc.outputs().snapshot(Output{"GLO", "V0s", 0, Lifetime::Timeframe}, v0s); - pc.outputs().snapshot(Output{"GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe}, pv2v0ref); + mVertexer.process(recoData); + mVertexer.extractSecondaryVertices(v0s, v0Refs, cascs, cascRefs); mTimer.Stop(); - LOG(INFO) << "Found " << v0s.size() << " V0s, timing: CPU: " + LOG(INFO) << "Found " << v0s.size() << " V0s and " << cascs.size() << " cascades, timing: CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0 << " s"; } void SecondaryVertexingSpec::endOfStream(EndOfStreamContext& ec) { - LOGF(INFO, "Secondary vertexing total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); + LOGF(INFO, "Secondary vertexing total timing: Cpu: %.3e Real: %.3e s in %d slots, nThreads = %d", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1, mVertexer.getNThreads()); } -DataProcessorSpec getSecondaryVertexingSpec() +DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCasc) { - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); + + bool useMC = false; + dataRequest->requestTracks(src, useMC); + dataRequest->requestPrimaryVertertices(useMC); - inputs.emplace_back("pvtx", "GLO", "PVTX", 0, Lifetime::Timeframe); // prim.vertices - inputs.emplace_back("pvtx_cont", "GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); // global ids of associated tracks - inputs.emplace_back("pvtx_tref", "GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); // vertex - trackID refs - // - inputs.emplace_back("tpcits", "GLO", "TPCITS", 0, Lifetime::Timeframe); // matched ITS-TPC tracks - inputs.emplace_back("its", "ITS", "TRACKS", 0, Lifetime::Timeframe); // standalone ITS tracks - inputs.emplace_back("tpc", "TPC", "TRACKS", 0, Lifetime::Timeframe); // standalone TPC tracks - // - outputs.emplace_back("GLO", "V0s", 0, Lifetime::Timeframe); // found V0s - outputs.emplace_back("GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe); // prim.vertex -> V0s refs + outputs.emplace_back("GLO", "V0S", 0, Lifetime::Timeframe); // found V0s + outputs.emplace_back("GLO", "PVTX_V0REFS", 0, Lifetime::Timeframe); // prim.vertex -> V0s refs + outputs.emplace_back("GLO", "CASCS", 0, Lifetime::Timeframe); // found Cascades + outputs.emplace_back("GLO", "PVTX_CASCREFS", 0, Lifetime::Timeframe); // prim.vertex -> Cascades refs return DataProcessorSpec{ "secondary-vertexing", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<SecondaryVertexingSpec>()}, - Options{{"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; + AlgorithmSpec{adaptFromTask<SecondaryVertexingSpec>(dataRequest, enableCasc)}, + Options{{"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}, + {"threads", VariantType::Int, 1, {"Number of threads"}}}}; } } // namespace vertexing diff --git a/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx new file mode 100644 index 0000000000000..38c451a84a565 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx @@ -0,0 +1,219 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatcherSpec.cxx + +#include <vector> +#include <string> +#include "TStopwatch.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" + +// from Tracks +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/GlobalTrackAccessor.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsITS/TrackITS.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" + +// from TOF +#include "DataFormatsTOF/Cluster.h" +#include "GlobalTracking/MatchTOF.h" +#include "GlobalTrackingWorkflow/TOFMatcherSpec.h" + +using namespace o2::framework; +// using MCLabelsTr = gsl::span<const o2::MCCompLabel>; +// using GID = o2::dataformats::GlobalTrackID; +// using DetID = o2::detectors::DetID; + +using evIdx = o2::dataformats::EvIndex<int, int>; +using MatchOutputType = std::vector<o2::dataformats::MatchInfoTOF>; +using GID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace globaltracking +{ + +class TOFMatcherSpec : public Task +{ + public: + TOFMatcherSpec(std::shared_ptr<DataRequest> dr, bool useMC, bool useFIT, bool tpcRefit, bool strict) : mDataRequest(dr), mUseMC(useMC), mUseFIT(useFIT), mDoTPCRefit(tpcRefit), mStrict(strict) {} + ~TOFMatcherSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + bool mUseMC = true; + bool mUseFIT = false; + bool mDoTPCRefit = false; + bool mStrict = false; + MatchTOF mMatcher; ///< Cluster finder + TStopwatch mTimer; +}; + +void TOFMatcherSpec::init(InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); + //-------- init geometry and field --------// + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + + // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB + std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); + std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); + if (o2::utils::Str::pathExists(matLUTFile)) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + if (mStrict) { + mMatcher.setHighPurity(); + } +} + +void TOFMatcherSpec::run(ProcessingContext& pc) +{ + mTimer.Start(false); + + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + LOG(INFO) << "isTrackSourceLoaded: TPC -> " << recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::TPC); + LOG(INFO) << "isTrackSourceLoaded: ITSTPC -> " << recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::ITSTPC); + LOG(INFO) << "isTrackSourceLoaded: TPCTRD -> " << recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::TPCTRD); + LOG(INFO) << "isTrackSourceLoaded: ITSTPCTRD -> " << recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::ITSTPCTRD); + + bool isTPCused = recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::TPC); + bool isITSTPCused = recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::ITSTPC); + bool isTPCTRDused = recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::TPCTRD); + bool isITSTPCTRDused = recoData.isTrackSourceLoaded(o2::dataformats::GlobalTrackID::Source::ITSTPCTRD); + uint32_t ss = o2::globaltracking::getSubSpec(mStrict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + mMatcher.setFIT(mUseFIT); + + mMatcher.run(recoData); + + if (isTPCused) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_TPC", ss, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPC)); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMTC_TPC", ss, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPC)); + } + + auto nmatch = mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPC).size(); + if (mDoTPCRefit) { + LOG(INFO) << "Refitting " << nmatch << " matched TPC tracks with TOF time info"; + } else { + LOG(INFO) << "Shifting Z for " << nmatch << " matched TPC tracks according to TOF time info"; + } + auto& tracksTPCTOF = pc.outputs().make<std::vector<o2::dataformats::TrackTPCTOF>>(OutputRef{"tpctofTracks", ss}, nmatch); + mMatcher.makeConstrainedTPCTracks(tracksTPCTOF); + } + + if (isITSTPCused) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPC)); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMTC_ITSTPC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector(o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPC)); + } + } + + if (isTPCTRDused) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_TPCTRD", ss, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPCTRD)); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMTC_TPCTRD", ss, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPCTRD)); + } + } + + if (isITSTPCTRDused) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_ITSTPCTRD", 0, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPCTRD)); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMTC_ITSTPCTRD", 0, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector(o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPCTRD)); + } + } + + // TODO: TRD-matched tracks + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe}, mMatcher.getCalibVector()); + + mTimer.Stop(); +} + +void TOFMatcherSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "TOF matching total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict) +{ + uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + auto dataRequest = std::make_shared<DataRequest>(); + if (strict) { + dataRequest->setMatchingInputStrict(); + } + dataRequest->requestTracks(src, useMC); + dataRequest->requestClusters(GID::getSourceMask(GID::TOF), useMC); + if (useFIT) { + dataRequest->requestClusters(GID::getSourceMask(GID::FT0), false); + } + + std::vector<OutputSpec> outputs; + if (GID::includesSource(GID::TPC, src)) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_TPC", ss, Lifetime::Timeframe); + outputs.emplace_back(OutputLabel{"tpctofTracks"}, o2::header::gDataOriginTOF, "TOFTRACKS_TPC", ss, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MCMTC_TPC", ss, Lifetime::Timeframe); + } + } + if (GID::includesSource(GID::ITSTPC, src)) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MCMTC_ITSTPC", 0, Lifetime::Timeframe); + } + } + if (GID::includesSource(GID::ITSTPCTRD, src)) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_ITSTPCTRD", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MCMTC_ITSTPCTRD", 0, Lifetime::Timeframe); + } + } + if (GID::includesSource(GID::TPCTRD, src)) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_TPCTRD", ss, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "MCMTC_TPCTRD", ss, Lifetime::Timeframe); + } + } + outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tof-matcher", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<TOFMatcherSpec>(dataRequest, useMC, useFIT, tpcRefit, strict)}, + Options{ + {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx index 6cf75338fea35..9b43c2bc1da1f 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,8 +13,15 @@ #include <vector> +#include "GlobalTracking/MatchTPCITS.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsTPC/Constants.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/DataRefUtils.h" +#include <string> +#include "TStopwatch.h" #include "Framework/ConfigParamRegistry.h" -#include "Framework/InputRecordWalker.h" #include "GlobalTrackingWorkflow/TPCITSMatchingSpec.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -25,39 +33,58 @@ #include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/ClusterNativeHelper.h" -#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/WorkflowHelper.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "ITSMFTBase/DPLAlpideParam.h" #include "GlobalTracking/MatchTPCITSParams.h" -#include "ITStracking/IOUtils.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DataFormatsParameters/GRPObject.h" #include "Headers/DataHeader.h" #include "CommonDataFormat/BunchFilling.h" #include "CommonDataFormat/FlatHisto2D.h" - -// RSTODO to remove once the framework will start propagating the header.firstTForbit -#include "DetectorsRaw/HBFUtils.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" using namespace o2::framework; using MCLabelsCl = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; using MCLabelsTr = gsl::span<const o2::MCCompLabel>; +using GTrackID = o2::dataformats::GlobalTrackID; namespace o2 { namespace globaltracking { +class TPCITSMatchingDPL : public Task +{ + public: + TPCITSMatchingDPL(std::shared_ptr<DataRequest> dr, bool useFT0, bool calib, bool skipTPCOnly, bool useMC) + : mDataRequest(dr), mUseFT0(useFT0), mCalibMode(calib), mSkipTPCOnly(skipTPCOnly), mUseMC(useMC) {} + ~TPCITSMatchingDPL() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::globaltracking::MatchTPCITS mMatching; // matching engine + o2::itsmft::TopologyDictionary mITSDict; // cluster patterns dictionary + bool mUseFT0 = false; + bool mCalibMode = false; + bool mSkipTPCOnly = false; // to use only externally constrained tracks (for test only) + bool mUseMC = true; + TStopwatch mTimer; +}; + void TPCITSMatchingDPL::init(InitContext& ic) { mTimer.Stop(); mTimer.Reset(); //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP(o2::base::NameConf::getGRPFileName()); - std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName())}; + o2::base::Propagator::initFieldFromGRP(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + mMatching.setSkipTPCOnly(mSkipTPCOnly); mMatching.setITSTriggered(!grp->isDetContinuousReadOut(o2::detectors::DetID::ITS)); const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); if (mMatching.isITSTriggered()) { @@ -68,20 +95,22 @@ void TPCITSMatchingDPL::init(InitContext& ic) mMatching.setMCTruthOn(mUseMC); mMatching.setUseFT0(mUseFT0); mMatching.setVDriftCalib(mCalibMode); + mMatching.setNThreads(std::max(1, ic.options().get<int>("nthreads"))); // std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mITSDict.readBinaryFile(dictFile); LOG(INFO) << "Matching is running with a provided ITS dictionary: " << dictFile; } else { LOG(INFO) << "Dictionary " << dictFile << " is absent, Matching expects ITS cluster patterns"; } + mMatching.setITSDictionary(&mITSDict); // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); - if (o2::base::NameConf::pathExists(matLUTFile)) { + if (o2::utils::Str::pathExists(matLUTFile)) { auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); o2::base::Propagator::Instance()->setMatLUT(lut); LOG(INFO) << "Loaded material LUT from " << matLUTFile; @@ -93,7 +122,7 @@ void TPCITSMatchingDPL::init(InitContext& ic) mMatching.setDebugFlag(dbgFlags); // set bunch filling. Eventually, this should come from CCDB - const auto* digctx = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto* digctx = o2::steer::DigitizationContext::loadFromFile(); const auto& bcfill = digctx->getBunchFilling(); mMatching.setBunchFilling(bcfill); @@ -103,173 +132,20 @@ void TPCITSMatchingDPL::init(InitContext& ic) void TPCITSMatchingDPL::run(ProcessingContext& pc) { + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + LOG(INFO) << " startOrbit: " << dh->firstTForbit; mTimer.Start(false); - const auto tracksITS = pc.inputs().get<gsl::span<o2::its::TrackITS>>("trackITS"); - const auto trackClIdxITS = pc.inputs().get<gsl::span<int>>("trackClIdx"); - const auto tracksITSROF = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("trackITSROF"); - const auto clusITS = pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("clusITS"); - const auto clusITSROF = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("clusITSROF"); - const auto patterns = pc.inputs().get<gsl::span<unsigned char>>("clusITSPatt"); - const auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("trackTPC"); - const auto tracksTPCClRefs = pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs"); - - //---------------------------->> TPC Clusters loading >>------------------------------------------ - int operation = 0; - uint64_t activeSectors = 0; - std::bitset<o2::tpc::constants::MAXSECTOR> validSectors = 0; - std::map<int, DataRef> datarefs; - std::vector<InputSpec> filter = { - {"check", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe}, - }; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref); - if (sectorHeader == nullptr) { - // FIXME: think about error policy - LOG(ERROR) << "sector header missing on header stack"; - throw std::runtime_error("sector header missing on header stack"); - } - int sector = sectorHeader->sector(); - std::bitset<o2::tpc::constants::MAXSECTOR> sectorMask(sectorHeader->sectorBits); - LOG(INFO) << "Reading TPC cluster data, sector mask is " << sectorMask; - if ((validSectors & sectorMask).any()) { - // have already data for this sector, this should not happen in the current - // sequential implementation, for parallel path merged at the tracker stage - // multiple buffers need to be handled - throw std::runtime_error("can only have one data set per sector"); - } - activeSectors |= sectorHeader->activeSectors; - validSectors |= sectorMask; - datarefs[sector] = ref; - } - - auto printInputLog = [&validSectors, &activeSectors](auto& r, const char* comment, auto& s) { - LOG(INFO) << comment << " " << *(r.spec) << ", size " << DataRefUtils::getPayloadSize(r) // - << " for sector " << s // - << std::endl // - << " input status: " << validSectors // - << std::endl // - << " active sectors: " << std::bitset<o2::tpc::constants::MAXSECTOR>(activeSectors); - }; - - if (activeSectors == 0 || (activeSectors & validSectors.to_ulong()) != activeSectors) { - // not all sectors available - // Since we expect complete input, this should not happen (why does the bufferization considered for TPC CA tracker? Ask Matthias) - throw std::runtime_error("Did not receive TPC clusters data for all sectors"); - } - //------------------------------------------------------------------------------ - std::vector<gsl::span<const char>> clustersTPC; - - for (auto const& refentry : datarefs) { - auto& sector = refentry.first; - auto& ref = refentry.second; - clustersTPC.emplace_back(ref.payload, DataRefUtils::getPayloadSize(ref)); - printInputLog(ref, "received", sector); - } - - // Just print TPC clusters status - { - // make human readable information from the bitfield - std::string bitInfo; - auto nActiveBits = validSectors.count(); - if (((uint64_t)0x1 << nActiveBits) == validSectors.to_ulong() + 1) { - // sectors 0 to some upper bound are active - bitInfo = "0-" + std::to_string(nActiveBits - 1); - } else { - int rangeStart = -1; - int rangeEnd = -1; - for (size_t sector = 0; sector < validSectors.size(); sector++) { - if (validSectors.test(sector)) { - if (rangeStart < 0) { - if (rangeEnd >= 0) { - bitInfo += ","; - } - bitInfo += std::to_string(sector); - if (nActiveBits == 1) { - break; - } - rangeStart = sector; - } - rangeEnd = sector; - } else { - if (rangeStart >= 0 && rangeEnd > rangeStart) { - bitInfo += "-" + std::to_string(rangeEnd); - } - rangeStart = -1; - } - } - if (rangeStart >= 0 && rangeEnd > rangeStart) { - bitInfo += "-" + std::to_string(rangeEnd); - } - } - LOG(INFO) << "running matching for sector(s) " << bitInfo; - } + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); - o2::tpc::ClusterNativeAccess clusterIndex; - std::unique_ptr<o2::tpc::ClusterNative[]> clusterBuffer; - memset(&clusterIndex, 0, sizeof(clusterIndex)); - o2::tpc::ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer dummyMCOutput; - std::vector<o2::tpc::ClusterNativeHelper::ConstMCLabelContainerView> dummyMCInput; - o2::tpc::ClusterNativeHelper::Reader::fillIndex(clusterIndex, clusterBuffer, dummyMCOutput, clustersTPC, dummyMCInput); - //----------------------------<< TPC Clusters loading <<------------------------------------------ - - // - MCLabelsTr lblITS; - MCLabelsTr lblTPC; - - const MCLabelsCl* lblClusITSPtr = nullptr; - std::unique_ptr<const MCLabelsCl> lblClusITS; - - if (mUseMC) { - lblITS = pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackITSMCTR"); - lblTPC = pc.inputs().get<gsl::span<o2::MCCompLabel>>("trackTPCMCTR"); - - lblClusITS = pc.inputs().get<const o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("clusITSMCTR"); - lblClusITSPtr = lblClusITS.get(); - } - // - // create ITS clusters as spacepoints in tracking frame - std::vector<o2::BaseCluster<float>> itsSP; - itsSP.reserve(clusITS.size()); - auto pattIt = patterns.begin(); - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itsSP, mITSDict); - - // pass input data to MatchTPCITS object - mMatching.setITSTracksInp(tracksITS); - mMatching.setITSTrackClusIdxInp(trackClIdxITS); - mMatching.setITSTrackROFRecInp(tracksITSROF); - mMatching.setITSClustersInp(itsSP); - mMatching.setITSClusterROFRecInp(clusITSROF); - mMatching.setTPCTracksInp(tracksTPC); - mMatching.setTPCTrackClusIdxInp(tracksTPCClRefs); - mMatching.setTPCClustersInp(&clusterIndex); - - if (mUseMC) { - mMatching.setITSTrkLabelsInp(lblITS); - mMatching.setTPCTrkLabelsInp(lblTPC); - mMatching.setITSClsLabelsInp(lblClusITSPtr); - } - - if (mUseFT0) { - // Note: the particular variable will go out of scope, but the span is passed by copy to the - // worker and the underlying memory is valid throughout the whole computation - auto fitInfo = pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("fitInfo"); - mMatching.setFITInfoInp(fitInfo); - } - - const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("trackITSROF").header); - mMatching.setStartIR({0, dh->firstTForbit}); - - //RSTODO: below is a hack, to remove once the framework will start propagating the header.firstTForbit - if (tracksITSROF.size()) { - mMatching.setStartIR(o2::raw::HBFUtils::Instance().getFirstIRofTF(tracksITSROF[0].getBCData())); - } - - mMatching.run(); + mMatching.run(recoData); pc.outputs().snapshot(Output{"GLO", "TPCITS", 0, Lifetime::Timeframe}, mMatching.getMatchedTracks()); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe}, mMatching.getABTrackletRefs()); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe}, mMatching.getABTrackletClusterIDs()); if (mUseMC) { - pc.outputs().snapshot(Output{"GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe}, mMatching.getMatchedITSLabels()); - pc.outputs().snapshot(Output{"GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe}, mMatching.getMatchedTPCLabels()); + pc.outputs().snapshot(Output{"GLO", "TPCITS_MC", 0, Lifetime::Timeframe}, mMatching.getMatchLabels()); + pc.outputs().snapshot(Output{"GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe}, mMatching.getMatchLabels()); } if (mCalibMode) { @@ -277,58 +153,51 @@ void TPCITSMatchingDPL::run(ProcessingContext& pc) pc.outputs().snapshot(Output{"GLO", "TPCITS_VDHDTGL", 0, Lifetime::Timeframe}, (*hdtgl).getBase()); hdtgl->clear(); } - mTimer.Stop(); } void TPCITSMatchingDPL::endOfStream(EndOfStreamContext& ec) { + mMatching.end(); LOGF(INFO, "TPC-ITS matching total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTPCITSMatchingSpec(bool useFT0, bool calib, bool useMC, const std::vector<int>& tpcClusLanes) +DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useMC) { - - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; - inputs.emplace_back("trackITS", "ITS", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackClIdx", "ITS", "TRACKCLSID", 0, Lifetime::Timeframe); - inputs.emplace_back("trackITSROF", "ITS", "ITSTrackROF", 0, Lifetime::Timeframe); - inputs.emplace_back("clusITS", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("clusITSPatt", "ITS", "PATTERNS", 0, Lifetime::Timeframe); - inputs.emplace_back("clusITSROF", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPC", "TPC", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPCClRefs", "TPC", "CLUSREFS", 0, Lifetime::Timeframe); - - inputs.emplace_back("clusTPC", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe); + auto dataRequest = std::make_shared<DataRequest>(); + if ((src & GTrackID::getSourcesMask("TPC-TRD,TPC-TOF,TPC-TRD-TOF")).any()) { // preliminary stage of extended workflow ? + dataRequest->setMatchingInputStrict(); + } + dataRequest->requestTracks(src, useMC); + dataRequest->requestTPCClusters(false); + dataRequest->requestITSClusters(useMC); // Only ITS clusters labels are needed for the afterburner if (useFT0) { - inputs.emplace_back("fitInfo", "FT0", "RECPOINTS", 0, Lifetime::Timeframe); + dataRequest->requestFT0RecPoints(false); } - outputs.emplace_back("GLO", "TPCITS", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe); // AftetBurner ITS tracklet references (referred by GlobalTrackID::ITSAB) on cluster indices + outputs.emplace_back("GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe); // cluster indices of ITS tracklets attached by the AfterBurner if (calib) { outputs.emplace_back("GLO", "TPCITS_VDHDTGL", 0, Lifetime::Timeframe); } if (useMC) { - inputs.emplace_back("trackITSMCTR", "ITS", "TRACKSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPCMCTR", "TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe); - inputs.emplace_back("clusITSMCTR", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - // - outputs.emplace_back("GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "TPCITS_MC", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe); // AfterBurner ITS tracklet MC } return DataProcessorSpec{ "itstpc-track-matcher", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<TPCITSMatchingDPL>(useFT0, calib, useMC)}, + AlgorithmSpec{adaptFromTask<TPCITSMatchingDPL>(dataRequest, useFT0, calib, skipTPCOnly, useMC)}, Options{ {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"nthreads", VariantType::Int, 1, {"Number of afterburner threads"}}, {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}, {"debug-tree-flags", VariantType::Int, 0, {"DebugFlagTypes bit-pattern for debug tree"}}}}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/TrackCosmicsWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TrackCosmicsWriterSpec.cxx new file mode 100644 index 0000000000000..af3f4052ee8ce --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/TrackCosmicsWriterSpec.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackCosmicsWriterSpec.cxx + +#include <vector> +#include "GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "ReconstructionDataFormats/TrackCosmics.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace globaltracking +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using TracksType = std::vector<o2::dataformats::TrackCosmics>; +using LabelsType = std::vector<o2::MCCompLabel>; + +DataProcessorSpec getTrackCosmicsWriterSpec(bool useMC) +{ + // A spectator for logging + auto logger = [](TracksType const& tracks) { + LOG(INFO) << "Writing " << tracks.size() << " Cosmics Tracks"; + }; + return MakeRootTreeWriterSpec("cosmic-track-writer", + "cosmics.root", + "cosmics", + -1, // do not limit number of events to store + 100, // periodically autosave + BranchDefinition<TracksType>{InputSpec{"tracks", "GLO", "COSMICTRC", 0}, + "tracks", + "tracks-branch-name", + 1, + logger}, + BranchDefinition<LabelsType>{InputSpec{"tracksMC", "GLO", "COSMICTRC_MC", 0}, + "MCTruth", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""})(); +} + +} // namespace globaltracking +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/TrackTPCITSReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TrackTPCITSReaderSpec.cxx deleted file mode 100644 index d3d3089ff22ad..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/src/TrackTPCITSReaderSpec.cxx +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TrackTPCITSReaderSpec.cxx - -#include <vector> - -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "DataFormatsParameters/GRPObject.h" -#include "Framework/SerializationMethods.h" - -using namespace o2::framework; -using namespace o2::globaltracking; - -namespace o2 -{ -namespace globaltracking -{ -void TrackTPCITSReader::init(InitContext& ic) -{ - mFileName = ic.options().get<std::string>("itstpc-track-infile"); - connectTree(mFileName); -} - -void TrackTPCITSReader::run(ProcessingContext& pc) -{ - auto ent = mTree->GetReadEntry() + 1; - assert(ent < mTree->GetEntries()); // this should not happen - mTree->GetEntry(ent); - LOG(INFO) << "Pushing " << mTracks.size() << " TPC-ITS matches at entry " << ent; - - pc.outputs().snapshot(Output{"GLO", "TPCITS", 0, Lifetime::Timeframe}, mTracks); - if (mUseMC) { - pc.outputs().snapshot(Output{"GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe}, mITSLabels); - pc.outputs().snapshot(Output{"GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe}, mTPCLabels); - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -void TrackTPCITSReader::connectTree(const std::string& filename) -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(filename.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get("matchTPCITS")); - assert(mTree); - mTree->SetBranchAddress("TPCITS", &mTracksPtr); - if (mUseMC) { - mTree->SetBranchAddress("MatchITSMCTruth", &mITSLabelsPtr); - mTree->SetBranchAddress("MatchTPCMCTruth", &mTPCLabelsPtr); - } - LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; -} - -DataProcessorSpec getTrackTPCITSReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("GLO", "TPCITS", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back("GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "itstpc-track-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<TrackTPCITSReader>(useMC)}, - Options{ - {"itstpc-track-infile", VariantType::String, "o2match_itstpc.root", {"Name of the input file"}}}}; -} - -} // namespace globaltracking -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/TrackWriterTPCITSSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TrackWriterTPCITSSpec.cxx index 7609ccd2ce9a6..c1fd44fe96b6c 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TrackWriterTPCITSSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TrackWriterTPCITSSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "ReconstructionDataFormats/TrackTPCITS.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsITSMFT/TrkClusRef.h" using namespace o2::framework; @@ -27,6 +29,8 @@ namespace globaltracking template <typename T> using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; using TracksType = std::vector<o2::dataformats::TrackTPCITS>; +using ABRefType = std::vector<o2::itsmft::TrkClusRef>; +using ABCLIDType = std::vector<int>; using LabelsType = std::vector<o2::MCCompLabel>; DataProcessorSpec getTrackWriterTPCITSSpec(bool useMC) @@ -38,19 +42,12 @@ DataProcessorSpec getTrackWriterTPCITSSpec(bool useMC) return MakeRootTreeWriterSpec("itstpc-track-writer", "o2match_itstpc.root", "matchTPCITS", - BranchDefinition<TracksType>{InputSpec{"match", "GLO", "TPCITS", 0}, - "TPCITS", - "TPCITS-branch-name", - 1, - logger}, - BranchDefinition<LabelsType>{InputSpec{"matchITSMC", "GLO", "TPCITS_ITSMC", 0}, - "MatchITSMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition<LabelsType>{InputSpec{"matchTPCMC", "GLO", "TPCITS_TPCMC", 0}, - "MatchTPCMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); + BranchDefinition<TracksType>{InputSpec{"match", "GLO", "TPCITS", 0}, "TPCITS", logger}, + BranchDefinition<ABRefType>{InputSpec{"ABRefs", "GLO", "TPCITSAB_REFS", 0}, "TPCITSABRefs"}, + BranchDefinition<ABCLIDType>{InputSpec{"ABCLID", "GLO", "TPCITSAB_CLID", 0}, "TPCITSABCLID"}, + BranchDefinition<LabelsType>{InputSpec{"matchMC", "GLO", "TPCITS_MC", 0}, "MatchMCTruth", (useMC ? 1 : 0), ""}, // one branch if mc labels enabled + BranchDefinition<LabelsType>{InputSpec{"matchABMC", "GLO", "TPCITSAB_MC", 0}, "MatchABMCTruth", (useMC ? 1 : 0), ""} // one branch if mc labels enabled + )(); } } // namespace globaltracking diff --git a/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx index 38e5401753ddc..c7ed3ff266fb6 100644 --- a/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,14 +17,35 @@ #include "DataFormatsParameters/GRPObject.h" #include "ITSMFTBase/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsVertexing/VertexTrackMatcher.h" +#include "TStopwatch.h" using namespace o2::framework; +using DetID = o2::detectors::DetID; +using GTrackID = o2::dataformats::GlobalTrackID; +using DataRequest = o2::globaltracking::DataRequest; namespace o2 { namespace vertexing { +class VertexTrackMatcherSpec : public Task +{ + public: + VertexTrackMatcherSpec(std::shared_ptr<DataRequest> dr) : mDataRequest(dr){}; + ~VertexTrackMatcherSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::vertexing::VertexTrackMatcher mMatcher; + TStopwatch mTimer; +}; + void VertexTrackMatcherSpec::init(InitContext& ic) { //-------- init geometry and field --------// @@ -38,40 +60,20 @@ void VertexTrackMatcherSpec::run(ProcessingContext& pc) double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime(); mTimer.Start(false); - // eventually, this should be set per TF from CCDB? - if (mMatcher.getITSROFrameLengthInBC() == 0) { - std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName())}; - const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); - if (grp->isDetContinuousReadOut(o2::detectors::DetID::ITS)) { - mMatcher.setITSROFrameLengthInBC(alpParams.roFrameLengthInBC); - } else { - mMatcher.setITSROFrameLengthInBC(alpParams.roFrameLengthTrig / o2::constants::lhc::LHCOrbitNS); - } - } - - // RS FIXME this will not have effect until the 1st orbit is propagated, until that will work only for TF starting at orbit 0 - const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("vertices").header); - mMatcher.setStartIR({0, dh->firstTForbit}); - - const auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("tpcits"); - const auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("tpc"); - const auto tracksITS = pc.inputs().get<gsl::span<o2::its::TrackITS>>("its"); - const auto tracksITSROF = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("itsROF"); - const auto vertices = pc.inputs().get<gsl::span<o2::dataformats::PrimaryVertex>>("vertices"); - const auto vtxTracks = pc.inputs().get<gsl::span<o2::dataformats::VtxTrackIndex>>("vtxTracks"); - const auto vtxTrackRefs = pc.inputs().get<gsl::span<o2::dataformats::VtxTrackRef>>("vtxTrackRefs"); + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); std::vector<o2::dataformats::VtxTrackIndex> trackIndex; std::vector<o2::dataformats::VtxTrackRef> vtxRefs; - mMatcher.process(vertices, vtxTracks, vtxTrackRefs, tracksITSTPC, tracksITS, tracksITSROF, tracksTPC, trackIndex, vtxRefs); + mMatcher.process(recoData, trackIndex, vtxRefs); pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe}, trackIndex); pc.outputs().snapshot(Output{"GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe}, vtxRefs); mTimer.Stop(); - LOG(INFO) << "Made " << trackIndex.size() << " track associationgs for " << vertices.size() << " vertices, timing: CPU: " - << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0 << " s"; + LOG(INFO) << "Made " << trackIndex.size() << " track associations for " << recoData.getPrimaryVertices().size() + << " vertices, timing: CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0 << " s"; } void VertexTrackMatcherSpec::endOfStream(EndOfStreamContext& ec) @@ -80,28 +82,22 @@ void VertexTrackMatcherSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getVertexTrackMatcherSpec() +DataProcessorSpec getVertexTrackMatcherSpec(GTrackID::mask_t src) { - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); - inputs.emplace_back("tpcits", "GLO", "TPCITS", 0, Lifetime::Timeframe); - inputs.emplace_back("its", "ITS", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("itsROF", "ITS", "ITSTrackROF", 0, Lifetime::Timeframe); - inputs.emplace_back("tpc", "TPC", "TRACKS", 0, Lifetime::Timeframe); - - inputs.emplace_back("vertices", "GLO", "PVTX", 0, Lifetime::Timeframe); - inputs.emplace_back("vtxTracks", "GLO", "PVTX_CONTID", 0, Lifetime::Timeframe); - inputs.emplace_back("vtxTrackRefs", "GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe); + dataRequest->requestTracks(src, false); + dataRequest->requestPrimaryVerterticesTMP(false); outputs.emplace_back("GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); return DataProcessorSpec{ "pvertex-track-matching", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<VertexTrackMatcherSpec>()}, + AlgorithmSpec{adaptFromTask<VertexTrackMatcherSpec>(dataRequest)}, Options{}}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx new file mode 100644 index 0000000000000..dba53cc368e72 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "ITSWorkflow/TrackReaderSpec.h" +#include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "GlobalTrackingWorkflow/CosmicsMatchingSpec.h" +#include "GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h" +#include "Algorithm/RangeTokenizer.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using GID = o2::dataformats::GlobalTrackID; +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// RS FIXME Is this needed ? +// the matcher process requires the TPC sector completion to trigger and data on +// all defined routes +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + // the TPC sector completion policy checks when the set of TPC/CLUSTERNATIVE data is complete + // in addition we require to have input from all other routes + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("cosmics-matcher", + o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, + InputSpec{"cluster", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}})()); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + GID::mask_t alowedSources = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF,ITS-TPC-TOF"); + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the workflow + o2::conf::ConfigurableParam::writeINI("o2match-cosmics-workflow_configuration.ini"); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + + GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("track-sources")); + GID::mask_t dummy; + specs.emplace_back(o2::globaltracking::getCosmicsMatchingSpec(src, useMC)); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, useMC, dummy); // clusters MC is not needed + + if (!disableRootOut) { + specs.emplace_back(o2::globaltracking::getTrackCosmicsWriterSpec(useMC)); + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx new file mode 100644 index 0000000000000..2f055f330d4e6 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/DataProcessorSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "GlobalTrackingWorkflow/GlobalFwdMatchingSpec.h" +#include "GlobalTrackingWorkflow/GlobalFwdTrackWriterSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the workflow + o2::conf::ConfigurableParam::writeINI("o2matchmftmch-workflow_configuration.ini"); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::globaltracking::getGlobalFwdMatchingSpec(useMC)); + if (!configcontext.options().get<bool>("disable-root-output")) { + specs.emplace_back(o2::globaltracking::getGlobalFwdTrackWriterSpec(useMC)); + } + + auto srcTracks = GID::getSourcesMask("MFT,MCH"); + auto srcClusters = GID::getSourcesMask("MFT"); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcClusters, GID::getSourcesMask(""), srcTracks, useMC, srcClusters, srcTracks); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/src/primary-vertex-reader-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/primary-vertex-reader-workflow.cxx index 1342cdb22a4b0..628247665ec85 100644 --- a/Detectors/GlobalTrackingWorkflow/src/primary-vertex-reader-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/primary-vertex-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,8 @@ #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" #include "Framework/ConfigParamSpec.h" -#include "GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; @@ -25,6 +27,8 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -41,5 +45,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) WorkflowSpec specs; specs.emplace_back(o2::vertexing::getPrimaryVertexReaderSpec(useMC)); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/src/primary-vertexing-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/primary-vertexing-workflow.cxx index 67e6ae1e43f2c..ea206f8dd8bdb 100644 --- a/Detectors/GlobalTrackingWorkflow/src/primary-vertexing-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/primary-vertexing-workflow.cxx @@ -1,27 +1,35 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "GlobalTrackingWorkflow/PrimaryVertexingSpec.h" #include "GlobalTrackingWorkflow/PrimaryVertexWriterSpec.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/GlobalFwdTrackReaderSpec.h" #include "GlobalTrackingWorkflow/VertexTrackMatcherSpec.h" #include "ITSWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" #include "FT0Workflow/RecPointReaderSpec.h" - +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" #include "Framework/ConfigParamSpec.h" using namespace o2::framework; - +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; // ------------------------------------------------------------------ // we need to add workflow options before including Framework/runDataProcessing @@ -32,10 +40,13 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"vertexing-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use in vertexing"}}, {"validate-with-ft0", o2::framework::VariantType::Bool, false, {"use FT0 time for vertex validation"}}, - {"disable-vertex-track-matching", o2::framework::VariantType::Bool, false, {"disable matching of vertex to non-contributor tracks"}}, + {"vetex-track-matching-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use in vertex-track associations or \"none\" to disable matching"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -45,36 +56,42 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { + WorkflowSpec specs; + + GID::mask_t allowedSourcesPV = GID::getSourcesMask("ITS,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF"); + GID::mask_t allowedSourcesVT = GID::getSourcesMask("ITS,MFT,TPC,ITS-TPC,MCH,MFT-MCH,TPC-TOF,TPC-TRD,ITS-TPC-TRD,ITS-TPC-TOF"); + // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2primary-vertexing-workflow_configuration.ini"); auto useMC = !configcontext.options().get<bool>("disable-mc"); - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); auto validateWithFT0 = configcontext.options().get<bool>("validate-with-ft0"); - auto disableMatching = configcontext.options().get<bool>("disable-vertex-track-matching"); - WorkflowSpec specs; - if (!disableRootInp) { - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(useMC)); - if (validateWithFT0) { - specs.emplace_back(o2::ft0::getRecPointReaderSpec(false)); - } + GID::mask_t srcPV = allowedSourcesPV & GID::getSourcesMask(configcontext.options().get<std::string>("vertexing-sources")); + GID::mask_t srcVT = allowedSourcesVT & GID::getSourcesMask(configcontext.options().get<std::string>("vetex-track-matching-sources")); + if (validateWithFT0) { + srcPV |= GID::getSourceMask(GID::FT0); } - specs.emplace_back(o2::vertexing::getPrimaryVertexingSpec(validateWithFT0, useMC)); - - if (!disableMatching) { - if (!disableRootInp) { - specs.emplace_back(o2::its::getITSTrackReaderSpec(false)); - specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(false)); - } - specs.emplace_back(o2::vertexing::getVertexTrackMatcherSpec()); + GID::mask_t srcComb = srcPV | srcVT; + GID::mask_t dummy, srcClus = GID::includesDet(DetID::TOF, srcComb) ? GID::getSourceMask(GID::TOF) : dummy; + + specs.emplace_back(o2::vertexing::getPrimaryVertexingSpec(srcPV, validateWithFT0, useMC)); + if (!srcVT.none()) { + specs.emplace_back(o2::vertexing::getVertexTrackMatcherSpec(srcVT)); } + // only TOF clusters are needed if TOF is involved, no clusters MC needed + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcClus, srcComb, srcComb, useMC, dummy); + if (!disableRootOut) { - specs.emplace_back(o2::vertexing::getPrimaryVertexWriterSpec(disableMatching, useMC)); + specs.emplace_back(o2::vertexing::getPrimaryVertexWriterSpec(srcVT.none(), useMC)); } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/src/secondary-vertex-reader-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/secondary-vertex-reader-workflow.cxx index 433d095889277..b7af771144e89 100644 --- a/Detectors/GlobalTrackingWorkflow/src/secondary-vertex-reader-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/secondary-vertex-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,8 @@ #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" #include "Framework/ConfigParamSpec.h" -#include "GlobalTrackingWorkflow/SecondaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/SecondaryVertexReaderSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; @@ -24,6 +26,8 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) std::vector<o2::framework::ConfigParamSpec> options{ {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -38,5 +42,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) WorkflowSpec specs; specs.emplace_back(o2::vertexing::getSecondaryVertexReaderSpec()); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx index a81eaf9dd89c3..c4a6d23d8a410 100644 --- a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,17 +11,23 @@ #include "GlobalTrackingWorkflow/SecondaryVertexingSpec.h" #include "GlobalTrackingWorkflow/SecondaryVertexWriterSpec.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "ITSWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/TrackReaderSpec.h" - +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CompletionPolicy.h" #include "Framework/ConfigParamSpec.h" using namespace o2::framework; - +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; // ------------------------------------------------------------------ // we need to add workflow options before including Framework/runDataProcessing @@ -30,8 +37,12 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) std::vector<o2::framework::ConfigParamSpec> options{ {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"vertexing-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use in vertexing"}}, + {"disable-cascade-finder", o2::framework::VariantType::Bool, false, {"do not run cascade finder"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -41,24 +52,33 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { + GID::mask_t alowedSources = GID::getSourcesMask("ITS,ITS-TPC,TPC-TRD,TPC-TOF,ITS-TPC-TRD,ITS-TPC-TOF"); + // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2secondary-vertexing-workflow_configuration.ini"); - - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); + bool useMC = false; auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto enableCasc = !configcontext.options().get<bool>("disable-cascade-finder"); + + GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("vertexing-sources")); + GID::mask_t dummy, srcClus = GID::includesDet(DetID::TOF, src) ? GID::getSourceMask(GID::TOF) : dummy; WorkflowSpec specs; - if (!disableRootInp) { - specs.emplace_back(o2::vertexing::getPrimaryVertexReaderSpec(false)); - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(false)); - specs.emplace_back(o2::its::getITSTrackReaderSpec(false)); - specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(false)); - } - specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec()); + + specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec(src, enableCasc)); + + // only TOF clusters are needed if TOF is involved, no clusters MC needed + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcClus, src, src, useMC, srcClus); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed + if (!disableRootOut) { specs.emplace_back(o2::vertexing::getSecondaryVertexWriterSpec()); } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx new file mode 100644 index 0000000000000..ff7e097bfa2f8 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx @@ -0,0 +1,145 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "ITSWorkflow/TrackReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "GlobalTrackingWorkflow/TOFMatcherSpec.h" +#include "TOFWorkflowIO/TOFMatchedWriterSpec.h" +#include "TOFWorkflowIO/TOFCalibWriterSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" +#include "Algorithm/RangeTokenizer.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using GID = o2::dataformats::GlobalTrackID; +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use: allowed TPC,ITS-TPC,TPC-TRD,ITS-TPC-TRD (all)"}}, + {"use-fit", o2::framework::VariantType::Bool, false, {"enable access to fit info for calibration"}}, + {"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}, + {"strict-matching", o2::framework::VariantType::Bool, false, {"High purity preliminary matching"}}, + {"output-type", o2::framework::VariantType::String, "matching-info,calib-info", {"matching-info, calib-info"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the workflow + o2::conf::ConfigurableParam::writeINI("o2match-tof-workflow_configuration.ini"); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto disableRootIn = configcontext.options().get<bool>("disable-root-input"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto useFIT = configcontext.options().get<bool>("use-fit"); + auto useCCDB = configcontext.options().get<bool>("use-ccdb"); + auto strict = configcontext.options().get<bool>("strict-matching"); + + bool writematching = 0; + bool writecalib = 0; + auto outputType = configcontext.options().get<std::string>("output-type"); + if (outputType.rfind("matching-info") < outputType.size()) { + writematching = 1; + } + if (outputType.rfind("calib-info") < outputType.size()) { + writecalib = 1; + } + + if (!writecalib) { + useFIT = false; + } + + LOG(INFO) << "TOF MATCHER WORKFLOW configuration"; + LOG(INFO) << "TOF track inputs = " << configcontext.options().get<std::string>("track-sources"); + LOG(INFO) << "TOF output = " << outputType; + LOG(INFO) << "TOF disable-mc = " << configcontext.options().get<std::string>("disable-mc"); + LOG(INFO) << "TOF use-ccdb = " << useCCDB; + LOG(INFO) << "TOF use-fit = " << useFIT; + LOG(INFO) << "TOF disable-root-input = " << disableRootIn; + LOG(INFO) << "TOF disable-root-output = " << disableRootOut; + LOG(INFO) << "TOF matching in strict mode = " << strict; + + //GID::mask_t alowedSources = GID::getSourcesMask("TPC,ITS-TPC"); + GID::mask_t alowedSources = GID::getSourcesMask("TPC,ITS-TPC,TPC-TRD,ITS-TPC-TRD"); + + GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("track-sources")); + if (strict && (src & ~GID::getSourcesMask("TPC,TPC-TRD")).any()) { + LOGP(WARNING, "In strict matching mode only TPC and TPC-TRD sources allowed, {} asked, redefining", GID::getSourcesNames(src)); + src &= GID::getSourcesMask("TPC,TPC-TRD"); + } + GID::mask_t mcmaskcl; + GID::mask_t nonemask = GID::getSourcesMask(GID::NONE); + GID::mask_t clustermask = GID::getSourcesMask("TOF"); + if (useFIT) { + clustermask |= GID::getSourceMask(GID::FT0); + } + + if (useMC) { + mcmaskcl |= GID::getSourceMask(GID::TOF); + } + // pass strict flag to fetch eventual TPC-TRD input with correct subspec + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, clustermask, nonemask, src, useMC, mcmaskcl, GID::getSourcesMask(GID::ALL), strict); + + specs.emplace_back(o2::globaltracking::getTOFMatcherSpec(src, useMC, useFIT, false, strict)); // doTPCrefit not yet supported (need to load TPC clusters?) + + if (!disableRootOut) { + if (writematching) { + if (GID::includesSource(GID::TPC, src)) { // matching to TPC was requested + specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC, "o2match_tof_tpc.root", true, (int)o2::dataformats::MatchInfoTOFReco::TrackType::TPC, strict)); + } + if (GID::includesSource(GID::ITSTPC, src)) { // matching to ITS-TPC was requested, there is not strict mode in this case + specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC, "o2match_tof_itstpc.root", false, (int)o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPC, false)); + } + if (GID::includesSource(GID::TPCTRD, src)) { // matching to TPC-TRD was requested, there is not strict mode in this case + specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC, "o2match_tof_tpctrd.root", false, (int)o2::dataformats::MatchInfoTOFReco::TrackType::TPCTRD, strict)); + } + if (GID::includesSource(GID::ITSTPCTRD, src)) { // matching to ITS-TPC-TRD was requested, there is not strict mode in this case + specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC, "o2match_tof_itstpctrd.root", false, (int)o2::dataformats::MatchInfoTOFReco::TrackType::ITSTPCTRD, false)); + } + } + if (writecalib) { + specs.emplace_back(o2::tof::getTOFCalibWriterSpec("o2calib_tof.root", 0)); + } + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx index 0a1025134841b..7d49e941e6478 100644 --- a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx @@ -1,20 +1,28 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "GlobalTrackingWorkflow/MatchTPCITSWorkflow.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" +#include "GlobalTrackingWorkflow/TPCITSMatchingSpec.h" +#include "GlobalTrackingWorkflow/TrackWriterTPCITSSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" -#include "TPCWorkflow/TPCSectorCompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; - +using GID = o2::dataformats::GlobalTrackID; // ------------------------------------------------------------------ // we need to add workflow options before including Framework/runDataProcessing @@ -26,9 +34,12 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"track-sources", VariantType::String, "TPC", {"comma-separated list of sources to use: TPC,TPC-TOF,TPC-TRD,TPC-TRD-TOF"}}, {"produce-calibration-data", o2::framework::VariantType::Bool, false, {"produce output for TPC vdrift calibration"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -40,24 +51,43 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies) // in addition we require to have input from all other routes policies.push_back(o2::tpc::TPCSectorCompletionPolicy("itstpc-track-matcher", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, - InputSpec{"cluster", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}})()); + o2::framework::InputSpec{"cluster", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}})()); } // ------------------------------------------------------------------ #include "Framework/runDataProcessing.h" -WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) { // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2matchtpcits-workflow_configuration.ini"); + GID::mask_t alowedSources = GID::getSourcesMask("ITS,TPC,TPC-TOF"); + GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("track-sources")); + bool needStrictTRDTOF = (src & GID::getSourcesMask("TPC-TRD,TPC-TOF,TPC-TRD-TOF")).any(); auto useFT0 = configcontext.options().get<bool>("use-ft0"); + if (useFT0) { + src |= GID::getSourceMask(GID::FT0); + } auto useMC = !configcontext.options().get<bool>("disable-mc"); - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); - auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); auto calib = configcontext.options().get<bool>("produce-calibration-data"); - return std::move(o2::globaltracking::getMatchTPCITSWorkflow(useFT0, useMC, disableRootInp, disableRootOut, calib)); + auto srcL = src | GID::getSourcesMask("ITS,TPC"); // ITS is neadded always, TPC must be loaded even if bare TPC tracks are not used in matching + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(srcL, useFT0, calib, !GID::includesSource(GID::TPC, src), useMC)); + + if (!configcontext.options().get<bool>("disable-root-output")) { + specs.emplace_back(o2::globaltracking::getTrackWriterTPCITSSpec(useMC)); + } + + // the only clusters MC which is need with useMC is ITS (for afterburner), for the rest we use tracks MC labels + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcL, srcL, srcL, useMC, GID::getSourceMask(GID::ITS), GID::getSourcesMask(GID::ALL), needStrictTRDTOF); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/tofworkflow/CMakeLists.txt index 22e5e927b488d..41c505506d76f 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/CMakeLists.txt @@ -1,41 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(TOFWorkflow - SOURCES src/RecoWorkflowSpec.cxx - src/RecoWorkflowWithTPCSpec.cxx - src/TOFMatchedWriterSpec.cxx - src/TOFCalibWriterSpec.cxx - src/TOFMatchedReaderSpec.cxx - src/CalibInfoReaderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction - O2::GlobalTracking O2::GlobalTrackingWorkflow O2::TOFWorkflowUtils - O2::TOFCalibration O2::DataFormatsFT0 O2::FT0Reconstruction O2::FT0Workflow - O2::TPCWorkflow) +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_executable(reco-workflow COMPONENT_NAME tof SOURCES src/tof-reco-workflow.cxx - PUBLIC_LINK_LIBRARIES O2::TOFWorkflow) - -o2_add_executable(matcher-global - COMPONENT_NAME tof - SOURCES src/tof-matcher-global.cxx - PUBLIC_LINK_LIBRARIES O2::TOFWorkflow) - -o2_add_executable(matcher-tpc - COMPONENT_NAME tof - SOURCES src/tof-matcher-tpc.cxx - PUBLIC_LINK_LIBRARIES O2::TOFWorkflow) + PUBLIC_LINK_LIBRARIES O2::Framework O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction + O2::TOFWorkflowIO O2::TOFWorkflowUtils + O2::TOFCalibration) o2_add_executable(calib-reader COMPONENT_NAME tof SOURCES src/tof-calibinfo-reader.cxx - PUBLIC_LINK_LIBRARIES O2::TOFWorkflow) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTOF O2::TOFBase O2::TOFWorkflowIO O2::TOFWorkflowUtils O2::TOFCalibration) diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/CalibInfoReaderSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/CalibInfoReaderSpec.h deleted file mode 100644 index 09494a2191f23..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/CalibInfoReaderSpec.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CalibInfoReaderSpec.h - -#ifndef O2_TOF_CALIBINFOREADER -#define O2_TOF_CALIBINFOREADER - -#include "TFile.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "DataFormatsTOF/CalibInfoTOF.h" - -class TTree; - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -class CalibInfoReader : public Task -{ - public: - CalibInfoReader(int instance, int ninstances, const char* filename) : mInstance(instance), mNinstances(ninstances), mFileName(filename) {} - ~CalibInfoReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - int mState = 0; - int mInstance; - int mNinstances; - const char* mFileName = nullptr; - FILE* mFile = nullptr; - TTree* mTree = nullptr; - int mCurrentEntry = 0; - int mGlobalEntry = 0; - std::vector<o2::dataformats::CalibInfoTOF> mVect, *mPvect = &mVect; -}; - -/// create a processor spec -/// read simulated TOF digits from a root file -framework::DataProcessorSpec getCalibInfoReaderSpec(int instance, int ninstances, const char* filename); - -} // namespace tof -} // namespace o2 - -#endif /* O2_TOF_CALIBINFOREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowSpec.h deleted file mode 100644 index 7dbf1441b3434..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowSpec.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef TOF_RECOWORKFLOW_H_ -#define TOF_RECOWORKFLOW_H_ - -#include "Framework/DataProcessorSpec.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" - -namespace o2 -{ -namespace tof -{ - -o2::framework::DataProcessorSpec getTOFRecoWorkflowSpec(bool useMC, bool useFIT); - -} // end namespace tof -} // end namespace o2 - -#endif /* TOF_RECOWORKFLOW_H_ */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowWithTPCSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowWithTPCSpec.h deleted file mode 100644 index 9f5d5b49dc50b..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/RecoWorkflowWithTPCSpec.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef TOF_RECOWORKFLOWWITHTPC_H_ -#define TOF_RECOWORKFLOWWITHTPC_H_ - -#include "Framework/DataProcessorSpec.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" - -namespace o2 -{ -namespace tof -{ - -o2::framework::DataProcessorSpec getTOFRecoWorkflowWithTPCSpec(bool useMC, bool useFIT); - -} // end namespace tof -} // end namespace o2 - -#endif /* TOF_RECOWORKFLOWWITHTPC_H_ */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFCalibWriterSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFCalibWriterSpec.h deleted file mode 100644 index 82d696bcf0383..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFCalibWriterSpec.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFCalibWriterSpec.h - -#ifndef TOFWORKFLOW_TOFCALIBWRITER_H_ -#define TOFWORKFLOW_TOFCALIBWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -/// create a processor spec -/// write TOF calbi info in a root file -o2::framework::DataProcessorSpec getTOFCalibWriterSpec(const char* outdef = "o2calib_tof.root"); - -} // namespace tof -} // namespace o2 - -#endif /* TOFWORKFLOW_TOFCALIBWRITER_H_ */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedReaderSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedReaderSpec.h deleted file mode 100644 index d8b1488a57d9f..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedReaderSpec.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFMatchedReaderSpec.h - -#ifndef O2_TOF_MATCHINFOREADER -#define O2_TOF_MATCHINFOREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace tof -{ - -class TOFMatchedReader : public o2::framework::Task -{ - public: - TOFMatchedReader(bool useMC) : mUseMC(useMC) {} - ~TOFMatchedReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - void connectTree(const std::string& filename); - - bool mUseMC = false; - std::string mInFileName{"o2match_tof.root"}; - std::string mInTreeName{"matchTOF"}; - std::unique_ptr<TFile> mFile = nullptr; - std::unique_ptr<TTree> mTree = nullptr; - std::vector<o2::dataformats::MatchInfoTOF> mMatches, *mMatchesPtr = &mMatches; - std::vector<o2::MCCompLabel> mLabelTOF, *mLabelTOFPtr = &mLabelTOF; - std::vector<o2::MCCompLabel> mLabelTPC, *mLabelTPCPtr = &mLabelTPC; - std::vector<o2::MCCompLabel> mLabelITS, *mLabelITSPtr = &mLabelITS; -}; - -/// create a processor spec -/// read matched TOF clusters from a ROOT file -framework::DataProcessorSpec getTOFMatchedReaderSpec(bool useMC); - -} // namespace tof -} // namespace o2 - -#endif /* O2_TOF_MATCHINFOREADER */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedWriterSpec.h b/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedWriterSpec.h deleted file mode 100644 index bb9899addd94c..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/include/TOFWorkflow/TOFMatchedWriterSpec.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFMatchedWriterSpec.h - -#ifndef TOFWORKFLOW_TOFMATCHEDWRITER_H_ -#define TOFWORKFLOW_TOFMATCHEDWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -/// create a processor spec -/// write TOF matching info in a root file -o2::framework::DataProcessorSpec getTOFMatchedWriterSpec(bool useMC, const char* outdef = "o2match_tof.root"); - -} // namespace tof -} // namespace o2 - -#endif /* TOFWORKFLOW_TOFMATCHEDWRITER_H_ */ diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx deleted file mode 100644 index d78e95a392393..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.cxx - -#include <vector> -#include <unistd.h> - -#include "TChain.h" -#include "TTree.h" - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "TOFWorkflow/CalibInfoReaderSpec.h" - -using namespace o2::framework; -using namespace o2::tof; - -namespace o2 -{ -namespace tof -{ - -void CalibInfoReader::init(InitContext& ic) -{ - LOG(INFO) << "Init CalibInfo reader!"; - mFile = fopen(mFileName, "r"); - if (!mFile) { - LOG(ERROR) << "Cannot open the " << mFileName << " file !"; - mState = 0; - return; - } - mState = 1; -} - -void CalibInfoReader::run(ProcessingContext& pc) -{ - if (mState != 1) { - return; - } - - char filename[100]; - - if ((mTree && mCurrentEntry < mTree->GetEntries()) || fscanf(mFile, "%s", filename) == 1) { - if (!mTree || mCurrentEntry >= mTree->GetEntries()) { - TFile* fin = TFile::Open(filename); - mTree = (TTree*)fin->Get("calibTOF"); - mCurrentEntry = 0; - mTree->SetBranchAddress("TOFCalibInfo", &mPvect); - } - if ((mGlobalEntry % mNinstances) == mInstance) { - mTree->GetEvent(mCurrentEntry); - LOG(INFO) << "Send " << mVect.size() << " calib infos"; - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe}, mVect); - usleep(10000); - } - mGlobalEntry++; - mCurrentEntry++; - } else { - mState = 2; - pc.services().get<ControlService>().endOfStream(); - } - return; -} - -DataProcessorSpec getCalibInfoReaderSpec(int instance, int ninstances, const char* filename) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); - - const char* nameSpec; - if (ninstances == 1) { - nameSpec = "tof-calibinfo-reader"; - } else { - nameSpec = Form("tof-calibinfo-reader-%d", instance); - } - - return DataProcessorSpec{ - nameSpec, - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<CalibInfoReader>(instance, ninstances, filename)}, - Options{/* for the moment no options */}}; -} -} // namespace tof -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx index c7def5fe1cbfe..8d554c0fad988 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx @@ -1,14 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "TOFWorkflow/RecoWorkflowSpec.h" +#include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" @@ -21,6 +23,7 @@ #include "ReconstructionDataFormats/TrackTPCITS.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/NameConf.h" #include <gsl/span> #include "TStopwatch.h" @@ -54,7 +57,17 @@ class TOFDPLRecoWorkflowTask { // nothing special to be set up o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP("o2sim_grp.root"); + o2::base::Propagator::initFieldFromGRP(); + std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); + std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); + if (o2::utils::Str::pathExists(matLUTFile)) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + mTimer.Stop(); mTimer.Reset(); } @@ -74,33 +87,17 @@ class TOFDPLRecoWorkflowTask LOG(INFO) << "TOF Reco Workflow pulled " << recPoints.size() << " FIT RecPoints"; } - //-------- init geometry and field --------// - // std::string path = "./"; - // std::string inputGeom = "O2geometry.root"; - // std::string inputGRP = "o2sim_grp.root"; - - // o2::base::GeometryManager::loadGeometry(path); - // o2::base::Propagator::initFieldFromGRP(path + inputGRP); - - // call actual matching info routine - //#ifdef _ALLOW_DEBUG_TREES_ - // mMatcher.setDebugTreeFileName(path + mMatcher.getDebugTreeFileName()); - // mMatcher.setDebugFlag(o2::globaltracking::MatchTOF::MatchTreeAll); - //#endif - // we do a copy of the input but we are looking for a way to avoid it (current problem in conversion form unique_ptr to *) - gsl::span<const o2::MCCompLabel> itslab; - gsl::span<const o2::MCCompLabel> tpclab; + gsl::span<const o2::MCCompLabel> itstpclab; o2::dataformats::MCTruthContainer<o2::MCCompLabel> toflab; if (mUseMC) { const auto toflabel = pc.inputs().get<o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("tofclusterlabel"); - itslab = pc.inputs().get<gsl::span<o2::MCCompLabel>>("itstracklabel"); - tpclab = pc.inputs().get<gsl::span<o2::MCCompLabel>>("tpctracklabel"); + itstpclab = pc.inputs().get<gsl::span<o2::MCCompLabel>>("itstpclabel"); toflab = std::move(*toflabel); } - mMatcher.run(tracksRO, clustersRO, toflab, itslab, tpclab); + mMatcher.run(tracksRO, clustersRO, toflab, itstpclab); // in run_match_tof aggiugnere esplicitamente la chiamata a fill del tree (nella classe MatchTOF) e il metodo per leggere i vettori di output @@ -109,11 +106,9 @@ class TOFDPLRecoWorkflowTask // << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; // send matching-info - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector()); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector()); if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTPCLabelsVector()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedITSLabelsVector()); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMATCHTOF", 0, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector()); } pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe}, mMatcher.getCalibVector()); mTimer.Stop(); @@ -138,19 +133,16 @@ o2::framework::DataProcessorSpec getTOFRecoWorkflowSpec(bool useMC, bool useFIT) inputs.emplace_back("globaltrack", "GLO", "TPCITS", 0, Lifetime::Timeframe); if (useMC) { inputs.emplace_back("tofclusterlabel", o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("itstracklabel", "GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - inputs.emplace_back("tpctracklabel", "GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); + inputs.emplace_back("itstpclabel", "GLO", "TPCITS_MC", 0, Lifetime::Timeframe); } if (useFIT) { inputs.emplace_back("fitrecpoints", o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); } - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe); if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "MCMATCHTOF", 0, Lifetime::Timeframe); } outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); @@ -159,7 +151,8 @@ o2::framework::DataProcessorSpec getTOFRecoWorkflowSpec(bool useMC, bool useFIT) inputs, outputs, AlgorithmSpec{adaptFromTask<TOFDPLRecoWorkflowTask>(useMC, useFIT)}, - Options{/* for the moment no options */}}; + Options{ + {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; } } // end namespace tof diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowWithTPCSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowWithTPCSpec.cxx deleted file mode 100644 index aefc81024073e..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowWithTPCSpec.cxx +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TOFWorkflow/RecoWorkflowWithTPCSpec.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/DataRefUtils.h" -#include "Framework/Lifetime.h" -#include "Framework/Task.h" -#include "Framework/SerializationMethods.h" -#include "Headers/DataHeader.h" -#include "DataFormatsTOF/Cluster.h" -#include "GlobalTracking/MatchTOF.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include <gsl/span> -#include "TStopwatch.h" - -// from FIT -#include "DataFormatsFT0/RecPoints.h" - -#include <memory> // for make_shared, make_unique, unique_ptr -#include <vector> - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -// use the tasking system of DPL -// just need to implement 2 special methods init + run (there is no need to inherit from anything) -class TOFDPLRecoWorkflowWithTPCTask -{ - using evIdx = o2::dataformats::EvIndex<int, int>; - using MatchOutputType = std::vector<o2::dataformats::MatchInfoTOF>; - - bool mUseMC = true; - bool mUseFIT = false; - - public: - explicit TOFDPLRecoWorkflowWithTPCTask(bool useMC, bool useFIT) : mUseMC(useMC), mUseFIT(useFIT) {} - - void init(framework::InitContext& ic) - { - // nothing special to be set up - o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP("o2sim_grp.root"); - mTimer.Stop(); - mTimer.Reset(); - } - - void run(framework::ProcessingContext& pc) - { - mTimer.Start(false); - //>>>---------- attach input data --------------->>> - const auto clustersRO = pc.inputs().get<gsl::span<o2::tof::Cluster>>("tofcluster"); - const auto tracksRO = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("tracks"); - - if (mUseFIT) { - // Note: the particular variable will go out of scope, but the span is passed by copy to the - // worker and the underlying memory is valid throughout the whole computation - auto recPoints = std::move(pc.inputs().get<gsl::span<o2::ft0::RecPoints>>("fitrecpoints")); - mMatcher.setFITRecPoints(recPoints); - LOG(INFO) << "TOF Reco WorkflowWithTPC pulled " << recPoints.size() << " FIT RecPoints"; - } - - //-------- init geometry and field --------// - // std::string path = "./"; - // std::string inputGeom = "O2geometry.root"; - // std::string inputGRP = "o2sim_grp.root"; - - // o2::base::GeometryManager::loadGeometry(path); - // o2::base::Propagator::initFieldFromGRP(path + inputGRP); - - // call actual matching info routine - //#ifdef _ALLOW_DEBUG_TREES_ - // mMatcher.setDebugTreeFileName(path + mMatcher.getDebugTreeFileName()); - // mMatcher.setDebugFlag(o2::globaltracking::MatchTOF::MatchTreeAll); - //#endif - - // we do a copy of the input but we are looking for a way to avoid it (current problem in conversion form unique_ptr to *) - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> toflab; - gsl::span<const o2::MCCompLabel> tpclab; - printf("get MC\n"); - if (mUseMC) { - const auto toflabel = pc.inputs().get<o2::dataformats::MCTruthContainer<o2::MCCompLabel>*>("tofclusterlabel"); - tpclab = pc.inputs().get<gsl::span<o2::MCCompLabel>>("tpctracklabel"); - toflab = std::move(*toflabel); - } - printf("GOT!\n"); - - mMatcher.run(tracksRO, clustersRO, toflab, tpclab); - - printf("run done\n"); - // in run_match_tof aggiugnere esplicitamente la chiamata a fill del tree (nella classe MatchTOF) e il metodo per leggere i vettori di output - - //... - // LOG(INFO) << "TOF CLUSTERER : TRANSFORMED " << digits->size() - // << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; - - // send matching-info - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector()); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTOFLabelsVector()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedTPCLabelsVector()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe}, mMatcher.getMatchedITSLabelsVector()); - } - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe}, mMatcher.getCalibVector()); - mTimer.Stop(); - } - - void endOfStream(EndOfStreamContext& ec) - { - LOGF(INFO, "TOF Matching total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); - } - - private: - o2::globaltracking::MatchTOF mMatcher; ///< Cluster finder - TStopwatch mTimer; -}; - -o2::framework::DataProcessorSpec getTOFRecoWorkflowWithTPCSpec(bool useMC, bool useFIT) -{ - std::vector<InputSpec> inputs; - std::vector<OutputSpec> outputs; - inputs.emplace_back("tofcluster", o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("tracks", o2::header::gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); - if (useMC) { - inputs.emplace_back("tofclusterlabel", o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("tpctracklabel", o2::header::gDataOriginTPC, "TRACKSMCLBL", 0, Lifetime::Timeframe); - } - - if (useFIT) { - inputs.emplace_back("fitrecpoints", o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); - } - - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe); - } - outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "TOFRecoWorkflowWithTPC", - inputs, - outputs, - AlgorithmSpec{adaptFromTask<TOFDPLRecoWorkflowWithTPCTask>(useMC, useFIT)}, - Options{/* for the moment no options */}}; -} - -} // end namespace tof -} // end namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFCalibWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFCalibWriterSpec.cxx deleted file mode 100644 index e3d0ab0690259..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFCalibWriterSpec.cxx +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFCalibWriterSpec.cxx - -#include "TOFWorkflow/TOFCalibWriterSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "Headers/DataHeader.h" -#include <SimulationDataFormat/MCCompLabel.h> -#include <SimulationDataFormat/MCTruthContainer.h> -#include "TTree.h" -#include "TBranch.h" -#include "TFile.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" -#include "DataFormatsTOF/CalibInfoTOF.h" -#include "DataFormatsTOF/Cluster.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -template <typename T> -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; -using CalibInfosType = std::vector<o2::dataformats::CalibInfoTOF>; -DataProcessorSpec getTOFCalibWriterSpec(const char* outdef) -{ - // A spectator for logging - auto logger = [](CalibInfosType const& indata) { - LOG(INFO) << "RECEIVED MATCHED SIZE " << indata.size(); - }; - return MakeRootTreeWriterSpec("TOFCalibWriter", - outdef, - "calibTOF", - BranchDefinition<CalibInfosType>{InputSpec{"input", o2::header::gDataOriginTOF, "CALIBDATA", 0}, - "TOFCalibInfo", - "calibinfo-branch-name", - 1, - logger})(); -} - -} // namespace tof -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedReaderSpec.cxx deleted file mode 100644 index 93c432cfa21ae..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedReaderSpec.cxx +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFMatchedReaderSpec.cxx - -#include <vector> - -#include "TTree.h" -#include "TFile.h" - -#include "TOFWorkflow/TOFMatchedReaderSpec.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Headers/DataHeader.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "ReconstructionDataFormats/MatchInfoTOF.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -void TOFMatchedReader::init(InitContext& ic) -{ - // get the option from the init context - LOG(INFO) << "Init TOF matching info reader!"; - mInFileName = ic.options().get<std::string>("tof-matched-infile"); - mInTreeName = ic.options().get<std::string>("treename"); - connectTree(mInFileName); -} - -void TOFMatchedReader::connectTree(const std::string& filename) -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(filename.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get(mInTreeName.c_str())); - assert(mTree); - mTree->SetBranchAddress("TOFMatchInfo", &mMatchesPtr); - if (mUseMC) { - mTree->SetBranchAddress("MatchTOFMCTruth", &mLabelTOFPtr); - mTree->SetBranchAddress("MatchTPCMCTruth", &mLabelTPCPtr); - mTree->SetBranchAddress("MatchITSMCTruth", &mLabelITSPtr); - } - LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; -} - -void TOFMatchedReader::run(ProcessingContext& pc) -{ - auto currEntry = mTree->GetReadEntry() + 1; - assert(currEntry < mTree->GetEntries()); // this should not happen - mTree->GetEntry(currEntry); - LOG(INFO) << "Pushing " << mMatches.size() << " TOF matchings at entry " << currEntry; - - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe}, mMatches); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe}, mLabelTOF); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe}, mLabelTPC); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe}, mLabelITS); - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -DataProcessorSpec getTOFMatchedReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHINFOS", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "TOFMatchedReader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<TOFMatchedReader>(useMC)}, - Options{ - {"tof-matched-infile", VariantType::String, "o2match_tof.root", {"Name of the input file"}}, - {"treename", VariantType::String, "matchTOF", {"Name of top-level TTree"}}, - }}; -} -} // namespace tof -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedWriterSpec.cxx deleted file mode 100644 index 6e8ad5dccd840..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/TOFMatchedWriterSpec.cxx +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFMatchedWriterSpec.cxx - -#include "TOFWorkflow/TOFMatchedWriterSpec.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "Headers/DataHeader.h" -#include <SimulationDataFormat/MCCompLabel.h> -#include <SimulationDataFormat/MCTruthContainer.h> -#include "ReconstructionDataFormats/MatchInfoTOF.h" -#include "DataFormatsTOF/CalibInfoTOF.h" -#include "DataFormatsTOF/Cluster.h" -#include "CommonUtils/StringUtils.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -template <typename T> -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; -using OutputType = std::vector<o2::dataformats::MatchInfoTOF>; -using LabelsType = std::vector<o2::MCCompLabel>; -using namespace o2::header; - -DataProcessorSpec getTOFMatchedWriterSpec(bool useMC, const char* outdef) -{ - // spectators for logging - auto loggerMatched = [](OutputType const& indata) { - LOG(INFO) << "RECEIVED MATCHED SIZE " << indata.size(); - }; - auto loggerTofLabels = [](LabelsType const& labeltof) { - LOG(INFO) << "TOF LABELS GOT " << labeltof.size() << " LABELS "; - }; - auto loggerTpcLabels = [](LabelsType const& labeltpc) { - LOG(INFO) << "TPC LABELS GOT " << labeltpc.size() << " LABELS "; - }; - auto loggerItsLabels = [](LabelsType const& labelits) { - LOG(INFO) << "ITS LABELS GOT " << labelits.size() << " LABELS "; - }; - // TODO: there was a comment in the original implementation: - // RS why do we need to repead ITS/TPC labels ? - // They can be extracted from TPC-ITS matches - return MakeRootTreeWriterSpec("TOFMatchedWriter", - outdef, - "matchTOF", - BranchDefinition<OutputType>{InputSpec{"tofmatching", gDataOriginTOF, "MATCHINFOS", 0}, - "TOFMatchInfo", - "TOFMatchInfo-branch-name", - 1, - loggerMatched}, - BranchDefinition<LabelsType>{InputSpec{"matchtoflabels", gDataOriginTOF, "MATCHTOFINFOSMC", 0}, - "MatchTOFMCTruth", - "MatchTOFMCTruth-branch-name", - (useMC ? 1 : 0), // one branch if mc labels enabled - loggerTofLabels}, - BranchDefinition<LabelsType>{InputSpec{"matchtpclabels", gDataOriginTOF, "MATCHTPCINFOSMC", 0}, - "MatchTPCMCTruth", - "MatchTPCMCTruth-branch-name", - (useMC ? 1 : 0), // one branch if mc labels enabled - loggerTpcLabels}, - BranchDefinition<LabelsType>{InputSpec{"matchitslabels", gDataOriginTOF, "MATCHITSINFOSMC", 0}, - "MatchITSMCTruth", - "MatchITSMCTruth-branch-name", - (useMC ? 1 : 0), // one branch if mc labels enabled - loggerItsLabels})(); -} -} // namespace tof -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx index ca362c48ba2b0..c6c3ef42096c8 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,12 +15,9 @@ /// @brief Basic DPL workflow for TOF reconstruction starting from digits #include "DetectorsBase/Propagator.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "TOFWorkflow/CalibInfoReaderSpec.h" +#include "TOFWorkflowIO/CalibInfoReaderSpec.h" #include "Framework/WorkflowSpec.h" #include "Framework/ConfigParamSpec.h" -#include "TOFWorkflow/RecoWorkflowSpec.h" -#include "Algorithm/RangeTokenizer.h" #include "FairLogger.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsCommonDataFormats/NameConf.h" @@ -34,6 +32,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { workflowOptions.push_back(ConfigParamSpec{"collection-infile", o2::framework::VariantType::String, "list-calibfile", {"Name of the collection input file"}}); workflowOptions.push_back(ConfigParamSpec{"ninstances", o2::framework::VariantType::Int, 1, {"Number of reader instances"}}); + workflowOptions.push_back(ConfigParamSpec{"tpc-matches", o2::framework::VariantType::Bool, false, {"Made from TOF-TPC matches"}}); workflowOptions.push_back(ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}); } @@ -65,6 +64,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) int ninstances = cfgc.options().get<int>("ninstances"); auto listname = cfgc.options().get<std::string>("collection-infile"); + auto toftpc = cfgc.options().get<bool>("tpc-matches"); char* stringTBP = new char[listname.size()]; sprintf(stringTBP, "%s", listname.c_str()); @@ -74,7 +74,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // std::vector<int> laneConfiguration = tofSectors; for (int i = 0; i < ninstances; i++) { - specs.emplace_back(o2::tof::getCalibInfoReaderSpec(i, ninstances, stringTBP)); + specs.emplace_back(o2::tof::getCalibInfoReaderSpec(i, ninstances, stringTBP, toftpc)); } LOG(INFO) << "Number of active devices = " << specs.size(); diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-global.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-global.cxx deleted file mode 100644 index 3d965c015134e..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-global.cxx +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file tof-reco-workflow.cxx -/// @author Francesco Noferini -/// @since 2019-05-22 -/// @brief Basic DPL workflow for TOF reconstruction starting from digits - -#include "DetectorsBase/Propagator.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "TOFWorkflowUtils/ClusterReaderSpec.h" -#include "TOFWorkflow/TOFMatchedWriterSpec.h" -#include "TOFWorkflow/TOFCalibWriterSpec.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/ConfigParamSpec.h" -#include "TOFWorkflow/RecoWorkflowSpec.h" -#include "Algorithm/RangeTokenizer.h" -#include "FairLogger.h" -#include "CommonUtils/ConfigurableParam.h" -#include "DetectorsCommonDataFormats/NameConf.h" - -// GRP -#include "DataFormatsParameters/GRPObject.h" - -// FIT -#include "FT0Workflow/RecPointReaderSpec.h" - -#include <string> -#include <stdexcept> -#include <unordered_map> - -// add workflow options, note that customization needs to be declared before -// including Framework/runDataProcessing -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - workflowOptions.push_back(ConfigParamSpec{"input-type", o2::framework::VariantType::String, "clusters,tracks", {"clusters, tracks, fit"}}); - workflowOptions.push_back(ConfigParamSpec{"output-type", o2::framework::VariantType::String, "matching-info,calib-info", {"matching-info, calib-info"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-sectors", o2::framework::VariantType::String, "0-17", {"TOF sector range, e.g. 5-7,8,9 ,TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-lanes", o2::framework::VariantType::Int, 1, {"number of parallel lanes up to the matcher, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}); - workflowOptions.push_back(ConfigParamSpec{"use-fit", o2::framework::VariantType::Bool, false, {"enable access to fit info for calibration"}}); - workflowOptions.push_back(ConfigParamSpec{"input-desc", o2::framework::VariantType::String, "CRAWDATA", {"Input specs description string"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}); -} - -#include "Framework/runDataProcessing.h" // the main driver - -using namespace o2::framework; - -/// The workflow executable for the stand alone TOF reconstruction workflow -/// The basic workflow for TOF reconstruction is defined in RecoWorkflow.cxx -/// and contains the following default processors -/// - digit reader -/// - clusterer -/// - cluster raw decoder -/// - track-TOF matcher -/// -/// The default workflow can be customized by specifying input and output types -/// e.g. digits, raw, clusters. -/// -/// MC info is processed by default, disabled by using command line option `--disable-mc` -/// -/// This function hooks up the the workflow specifications into the DPL driver. -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec specs; - - if (!cfgc.helpOnCommandLine()) { - std::string inputGRP = o2::base::NameConf::getGRPFileName(); - o2::base::Propagator::initFieldFromGRP(inputGRP); - const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); - if (!grp) { - LOG(ERROR) << "This workflow needs a valid GRP file to start"; - return specs; - } - o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); - // o2::conf::ConfigurableParam::writeINI("o2tofrecoflow_configuration.ini"); - } - // the lane configuration defines the subspecification ids to be distributed among the lanes. - // auto tofSectors = o2::RangeTokenizer::tokenize<int>(cfgc.options().get<std::string>("tof-sectors")); - // std::vector<int> laneConfiguration = tofSectors; - auto nLanes = cfgc.options().get<int>("tof-lanes"); - auto inputType = cfgc.options().get<std::string>("input-type"); - auto outputType = cfgc.options().get<std::string>("output-type"); - - bool writematching = 0; - bool writecalib = 0; - - if (outputType.rfind("matching-info") < outputType.size()) { - writematching = 1; - } - if (outputType.rfind("calib-info") < outputType.size()) { - writecalib = 1; - } - - bool clusterinput = 0; - bool trackinput = 0; - bool fitinput = 0; - - if (inputType.rfind("clusters") < inputType.size()) { - clusterinput = 1; - } - if (inputType.rfind("tracks") < inputType.size()) { - trackinput = 1; - } - auto useMC = !cfgc.options().get<bool>("disable-mc"); - auto useCCDB = cfgc.options().get<bool>("use-ccdb"); - auto useFIT = cfgc.options().get<bool>("use-fit"); - bool disableRootInput = cfgc.options().get<bool>("disable-root-input"); - bool disableRootOutput = cfgc.options().get<bool>("disable-root-output"); - - if (inputType.rfind("fit") < inputType.size()) { - fitinput = 1; - useFIT = 1; - } - - LOG(INFO) << "TOF RECO WORKFLOW configuration"; - LOG(INFO) << "TOF input = " << cfgc.options().get<std::string>("input-type"); - LOG(INFO) << "TOF output = " << cfgc.options().get<std::string>("output-type"); - LOG(INFO) << "TOF sectors = " << cfgc.options().get<std::string>("tof-sectors"); - LOG(INFO) << "TOF disable-mc = " << cfgc.options().get<std::string>("disable-mc"); - LOG(INFO) << "TOF lanes = " << cfgc.options().get<std::string>("tof-lanes"); - LOG(INFO) << "TOF use-ccdb = " << cfgc.options().get<std::string>("use-ccdb"); - LOG(INFO) << "TOF use-fit = " << cfgc.options().get<std::string>("use-fit"); - LOG(INFO) << "TOF disable-root-input = " << disableRootInput; - LOG(INFO) << "TOF disable-root-output = " << disableRootOutput; - - if (clusterinput) { - LOG(INFO) << "Insert TOF Cluster Reader"; - specs.emplace_back(o2::tof::getClusterReaderSpec(useMC)); - } - if (trackinput) { - LOG(INFO) << "Insert ITS-TPC Track Reader"; - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(useMC)); - } - - if (fitinput) { - LOG(INFO) << "Insert FIT RecPoint Reader"; - specs.emplace_back(o2::ft0::getRecPointReaderSpec(useMC)); - } - - LOG(INFO) << "Insert TOF Matching"; - specs.emplace_back(o2::tof::getTOFRecoWorkflowSpec(useMC, useFIT)); - - if (writematching && !disableRootOutput) { - LOG(INFO) << "Insert TOF Matched Info Writer"; - specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC)); - } - if (writecalib) { - LOG(INFO) << "Insert TOF Calib Info Writer"; - specs.emplace_back(o2::tof::getTOFCalibWriterSpec()); - } - - LOG(INFO) << "Number of active devices = " << specs.size(); - - return std::move(specs); -} diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-tpc.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-tpc.cxx deleted file mode 100644 index d2882f177a79f..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-matcher-tpc.cxx +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file tof-reco-workflow.cxx -/// @author Francesco Noferini -/// @since 2019-05-22 -/// @brief Basic DPL workflow for TOF reconstruction starting from digits - -#include "DetectorsBase/Propagator.h" -#include "TOFWorkflowUtils/ClusterReaderSpec.h" -#include "TOFWorkflow/TOFMatchedWriterSpec.h" -#include "TOFWorkflow/TOFCalibWriterSpec.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/ConfigParamSpec.h" -#include "TOFWorkflow/RecoWorkflowWithTPCSpec.h" -#include "Algorithm/RangeTokenizer.h" -#include "FairLogger.h" -#include "CommonUtils/ConfigurableParam.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include "TPCWorkflow/TrackReaderSpec.h" - -// GRP -#include "DataFormatsParameters/GRPObject.h" - -// FIT -#include "FT0Workflow/RecPointReaderSpec.h" - -#include <string> -#include <stdexcept> -#include <unordered_map> - -// add workflow options, note that customization needs to be declared before -// including Framework/runDataProcessing -void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) -{ - workflowOptions.push_back(ConfigParamSpec{"input-type", o2::framework::VariantType::String, "clusters,tracks", {"clusters, tracks, fit"}}); - workflowOptions.push_back(ConfigParamSpec{"output-type", o2::framework::VariantType::String, "matching-info", {"matching-info, calib-info"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-sectors", o2::framework::VariantType::String, "0-17", {"TOF sector range, e.g. 5-7,8,9 ,TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-lanes", o2::framework::VariantType::Int, 1, {"number of parallel lanes up to the matcher, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}); - workflowOptions.push_back(ConfigParamSpec{"use-fit", o2::framework::VariantType::Bool, false, {"enable access to fit info for calibration"}}); - workflowOptions.push_back(ConfigParamSpec{"input-desc", o2::framework::VariantType::String, "CRAWDATA", {"Input specs description string"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}); -} - -#include "Framework/runDataProcessing.h" // the main driver - -using namespace o2::framework; - -/// The workflow executable for the stand alone TOF reconstruction workflow -/// The basic workflow for TOF reconstruction is defined in RecoWorkflow.cxx -/// and contains the following default processors -/// - digit reader -/// - clusterer -/// - cluster raw decoder -/// - track-TOF matcher -/// -/// The default workflow can be customized by specifying input and output types -/// e.g. digits, raw, clusters. -/// -/// MC info is processed by default, disabled by using command line option `--disable-mc` -/// -/// This function hooks up the the workflow specifications into the DPL driver. -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec specs; - - if (!cfgc.helpOnCommandLine()) { - std::string inputGRP = o2::base::NameConf::getGRPFileName(); - o2::base::Propagator::initFieldFromGRP(inputGRP); - const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); - if (!grp) { - LOG(ERROR) << "This workflow needs a valid GRP file to start"; - return specs; - } - o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); - // o2::conf::ConfigurableParam::writeINI("o2tofrecoflow_configuration.ini"); - } - // the lane configuration defines the subspecification ids to be distributed among the lanes. - // auto tofSectors = o2::RangeTokenizer::tokenize<int>(cfgc.options().get<std::string>("tof-sectors")); - // std::vector<int> laneConfiguration = tofSectors; - auto nLanes = cfgc.options().get<int>("tof-lanes"); - auto inputType = cfgc.options().get<std::string>("input-type"); - auto outputType = cfgc.options().get<std::string>("output-type"); - - bool writematching = 0; - bool writecalib = 0; - - if (outputType.rfind("matching-info") < outputType.size()) { - writematching = 1; - } - if (outputType.rfind("calib-info") < outputType.size()) { - writecalib = 1; - } - - bool clusterinput = 0; - bool trackinput = 0; - bool fitinput = 0; - - if (inputType.rfind("clusters") < inputType.size()) { - clusterinput = 1; - } - if (inputType.rfind("tracks") < inputType.size()) { - trackinput = 1; - } - auto useMC = !cfgc.options().get<bool>("disable-mc"); - auto useCCDB = cfgc.options().get<bool>("use-ccdb"); - auto useFIT = cfgc.options().get<bool>("use-fit"); - bool disableRootInput = cfgc.options().get<bool>("disable-root-input"); - bool disableRootOutput = cfgc.options().get<bool>("disable-root-output"); - - if (inputType.rfind("fit") < inputType.size()) { - fitinput = 1; - useFIT = 1; - } - - LOG(INFO) << "TOF RECO WORKFLOW configuration"; - LOG(INFO) << "TOF input = " << cfgc.options().get<std::string>("input-type"); - LOG(INFO) << "TOF output = " << cfgc.options().get<std::string>("output-type"); - LOG(INFO) << "TOF sectors = " << cfgc.options().get<std::string>("tof-sectors"); - LOG(INFO) << "TOF disable-mc = " << cfgc.options().get<std::string>("disable-mc"); - LOG(INFO) << "TOF lanes = " << cfgc.options().get<std::string>("tof-lanes"); - LOG(INFO) << "TOF use-ccdb = " << cfgc.options().get<std::string>("use-ccdb"); - LOG(INFO) << "TOF use-fit = " << cfgc.options().get<std::string>("use-fit"); - LOG(INFO) << "TOF disable-root-input = " << disableRootInput; - LOG(INFO) << "TOF disable-root-output = " << disableRootOutput; - - // useMC = false; - // LOG(INFO) << "TOF disable MC forced"; - // writecalib = false; - // LOG(INFO) << "TOF CalibInfo disabled (forced)"; - - if (clusterinput) { - LOG(INFO) << "Insert TOF Cluster Reader"; - specs.emplace_back(o2::tof::getClusterReaderSpec(useMC)); - } - if (trackinput) { - LOG(INFO) << "Insert TPC Track Reader"; - specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(useMC)); - } - - if (fitinput) { - LOG(INFO) << "Insert FIT RecPoint Reader"; - specs.emplace_back(o2::ft0::getRecPointReaderSpec(useMC)); - } - - LOG(INFO) << "Insert TOF Matching"; - specs.emplace_back(o2::tof::getTOFRecoWorkflowWithTPCSpec(useMC, useFIT)); - - if (writematching && !disableRootOutput) { - LOG(INFO) << "Insert TOF Matched Info Writer"; - specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC, "o2match_toftpc.root")); - } - if (writecalib) { - LOG(INFO) << "Insert TOF Calib Info Writer"; - specs.emplace_back(o2::tof::getTOFCalibWriterSpec("o2calib_toftpc.root")); - } - - LOG(INFO) << "Number of active devices = " << specs.size(); - - return std::move(specs); -} diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-reco-workflow.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-reco-workflow.cxx index c924950007c7c..013584ca9b669 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-reco-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,31 +15,21 @@ /// @brief Basic DPL workflow for TOF reconstruction starting from digits #include "DetectorsBase/Propagator.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "TOFWorkflowUtils/DigitReaderSpec.h" -#include "TOFWorkflowUtils/TOFDigitWriterSpec.h" -#include "TOFWorkflowUtils/ClusterReaderSpec.h" +#include "TOFWorkflowIO/DigitReaderSpec.h" +#include "TOFWorkflowIO/TOFDigitWriterSpec.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" #include "TOFWorkflowUtils/TOFClusterizerSpec.h" -#include "TOFWorkflowUtils/TOFClusterWriterSpec.h" -#include "TOFWorkflow/TOFMatchedWriterSpec.h" -#include "TOFWorkflow/TOFCalibWriterSpec.h" -#include "TOFWorkflowUtils/TOFRawWriterSpec.h" +#include "TOFWorkflowIO/TOFClusterWriterSpec.h" +#include "TOFWorkflowIO/TOFRawWriterSpec.h" #include "TOFWorkflowUtils/CompressedDecodingTask.h" #include "TOFWorkflowUtils/EntropyEncoderSpec.h" #include "TOFWorkflowUtils/EntropyDecoderSpec.h" #include "Framework/WorkflowSpec.h" #include "Framework/ConfigParamSpec.h" -#include "TOFWorkflow/RecoWorkflowSpec.h" -#include "Algorithm/RangeTokenizer.h" #include "FairLogger.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsCommonDataFormats/NameConf.h" - -// GRP -#include "DataFormatsParameters/GRPObject.h" - -// FIT -#include "FT0Workflow/RecPointReaderSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include <string> #include <stdexcept> @@ -48,20 +39,27 @@ // including Framework/runDataProcessing void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { - workflowOptions.push_back(ConfigParamSpec{"input-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters"}}); - workflowOptions.push_back(ConfigParamSpec{"output-type", o2::framework::VariantType::String, "clusters,matching-info,calib-info", {"digits, clusters, matching-info, calib-info, raw, ctf"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-sectors", o2::framework::VariantType::String, "0-17", {"TOF sector range, e.g. 5-7,8,9 ,TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"tof-lanes", o2::framework::VariantType::Int, 1, {"number of parallel lanes up to the matcher, TBI"}}); - workflowOptions.push_back(ConfigParamSpec{"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}); - workflowOptions.push_back(ConfigParamSpec{"use-fit", o2::framework::VariantType::Bool, false, {"enable access to fit info for calibration"}}); - workflowOptions.push_back(ConfigParamSpec{"input-desc", o2::framework::VariantType::String, "CRAWDATA", {"Input specs description string"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - workflowOptions.push_back(ConfigParamSpec{"conet-mode", o2::framework::VariantType::Bool, false, {"enable conet mode"}}); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}); - workflowOptions.push_back(ConfigParamSpec{"disable-row-writing", o2::framework::VariantType::Bool, false, {"disable ROW in Digit writing"}}); - workflowOptions.push_back(ConfigParamSpec{"write-decoding-errors", o2::framework::VariantType::Bool, false, {"trace errors in digits output when decoding"}}); + std::vector<o2::framework::ConfigParamSpec> options{ + {"input-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters"}}, + {"output-type", o2::framework::VariantType::String, "clusters", {"digits, clusters, raw, ctf"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information, TBI"}}, + {"tof-sectors", o2::framework::VariantType::String, "0-17", {"TOF sector range, e.g. 5-7,8,9 ,TBI"}}, + {"tof-lanes", o2::framework::VariantType::Int, 1, {"number of parallel lanes up to the matcher, TBI"}}, + {"use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}, + {"input-desc", o2::framework::VariantType::String, "CRAWDATA", {"Input specs description string"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"conet-mode", o2::framework::VariantType::Bool, false, {"enable conet mode"}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}, + {"disable-row-writing", o2::framework::VariantType::Bool, false, {"disable ROW in Digit writing"}}, + {"write-decoding-errors", o2::framework::VariantType::Bool, false, {"trace errors in digits output when decoding"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"calib-cluster", VariantType::Bool, false, {"to enable calib info production from clusters"}}, + {"cosmics", VariantType::Bool, false, {"to enable cosmics utils"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); } #include "Framework/runDataProcessing.h" // the main driver @@ -86,20 +84,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec specs; - if (!cfgc.helpOnCommandLine()) { - o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); - // o2::conf::ConfigurableParam::writeINI("o2tofrecoflow_configuration.ini"); - } // the lane configuration defines the subspecification ids to be distributed among the lanes. - // auto tofSectors = o2::RangeTokenizer::tokenize<int>(cfgc.options().get<std::string>("tof-sectors")); - // std::vector<int> laneConfiguration = tofSectors; auto nLanes = cfgc.options().get<int>("tof-lanes"); auto inputType = cfgc.options().get<std::string>("input-type"); auto outputType = cfgc.options().get<std::string>("output-type"); bool writecluster = 0; - bool writematching = 0; - bool writecalib = 0; bool writedigit = 0; bool writeraw = 0; bool writectf = 0; @@ -108,12 +98,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) if (outputType.rfind("clusters") < outputType.size()) { writecluster = 1; } - if (outputType.rfind("matching-info") < outputType.size()) { - writematching = 1; - } - if (outputType.rfind("calib-info") < outputType.size()) { - writecalib = 1; - } if (outputType.rfind("digits") < outputType.size()) { writedigit = 1; } @@ -136,26 +120,19 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) writeerr = cfgc.options().get<bool>("write-decoding-errors"); } - if (rawinput) { - } else { - if (!cfgc.helpOnCommandLine()) { - std::string inputGRP = o2::base::NameConf::getGRPFileName(); - o2::base::Propagator::initFieldFromGRP(inputGRP); - const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); - if (!grp) { - LOG(ERROR) << "This workflow needs a valid GRP file to start"; - return specs; - } - } + if (!cfgc.helpOnCommandLine()) { + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); } auto useMC = !cfgc.options().get<bool>("disable-mc"); auto useCCDB = cfgc.options().get<bool>("use-ccdb"); - auto useFIT = cfgc.options().get<bool>("use-fit"); bool disableRootInput = cfgc.options().get<bool>("disable-root-input") || rawinput; bool disableRootOutput = cfgc.options().get<bool>("disable-root-output"); bool conetmode = cfgc.options().get<bool>("conet-mode"); bool disableROWwriting = cfgc.options().get<bool>("disable-row-writing"); + auto isCalibFromCluster = cfgc.options().get<bool>("calib-cluster"); + auto isCosmics = cfgc.options().get<bool>("cosmics"); + auto ignoreDistStf = cfgc.options().get<bool>("ignore-dist-stf"); LOG(INFO) << "TOF RECO WORKFLOW configuration"; LOG(INFO) << "TOF input = " << cfgc.options().get<std::string>("input-type"); @@ -164,14 +141,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) LOG(INFO) << "TOF disable-mc = " << cfgc.options().get<std::string>("disable-mc"); LOG(INFO) << "TOF lanes = " << cfgc.options().get<std::string>("tof-lanes"); LOG(INFO) << "TOF use-ccdb = " << cfgc.options().get<std::string>("use-ccdb"); - LOG(INFO) << "TOF use-fit = " << cfgc.options().get<std::string>("use-fit"); LOG(INFO) << "TOF disable-root-input = " << disableRootInput; LOG(INFO) << "TOF disable-root-output = " << disableRootOutput; LOG(INFO) << "TOF conet-mode = " << conetmode; + LOG(INFO) << "TOF ignore Dist Stf = " << ignoreDistStf; LOG(INFO) << "TOF disable-row-writing = " << disableROWwriting; LOG(INFO) << "TOF write-decoding-errors = " << writeerr; - if (clusterinput) { + if (clusterinput && !disableRootInput) { LOG(INFO) << "Insert TOF Cluster Reader"; specs.emplace_back(o2::tof::getClusterReaderSpec(useMC)); } else if (dgtinput) { @@ -187,7 +164,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) } else if (rawinput) { LOG(INFO) << "Insert TOF Compressed Raw Decoder"; auto inputDesc = cfgc.options().get<std::string>("input-desc"); - specs.emplace_back(o2::tof::getCompressedDecodingSpec(inputDesc, conetmode)); + specs.emplace_back(o2::tof::getCompressedDecodingSpec(inputDesc, conetmode, !ignoreDistStf)); useMC = 0; if (writedigit && !disableRootOutput) { @@ -199,34 +176,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) if (!clusterinput && writecluster) { LOG(INFO) << "Insert TOF Clusterizer"; - specs.emplace_back(o2::tof::getTOFClusterizerSpec(useMC, useCCDB)); + specs.emplace_back(o2::tof::getTOFClusterizerSpec(useMC, useCCDB, isCalibFromCluster, isCosmics)); if (writecluster && !disableRootOutput) { LOG(INFO) << "Insert TOF Cluster Writer"; specs.emplace_back(o2::tof::getTOFClusterWriterSpec(useMC)); } } - if (useFIT) { - specs.emplace_back(o2::ft0::getRecPointReaderSpec(useMC)); - } - - if (writematching || writecalib) { - if (!disableRootInput) { - LOG(INFO) << "Insert ITS-TPC Track Reader"; - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(useMC)); - } - LOG(INFO) << "Insert TOF Matching"; - specs.emplace_back(o2::tof::getTOFRecoWorkflowSpec(useMC, useFIT)); - - if (writematching && !disableRootOutput) { - LOG(INFO) << "Insert TOF Matched Info Writer"; - specs.emplace_back(o2::tof::getTOFMatchedWriterSpec(useMC)); - } - if (writecalib) { - LOG(INFO) << "Insert TOF Calib Info Writer"; - specs.emplace_back(o2::tof::getTOFCalibWriterSpec()); - } - } if (writectf) { LOG(INFO) << "Insert TOF CTF encoder"; specs.emplace_back(o2::tof::getEntropyEncoderSpec()); @@ -234,5 +190,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) LOG(INFO) << "Number of active devices = " << specs.size(); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); + return std::move(specs); } diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt index d602b72f92c7b..c8eef47e61b14 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt @@ -1,25 +1,24 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -#TODO Does the O2::GlobalTracking library need to be linked? o2_add_library(TPCInterpolationWorkflow SOURCES src/TPCInterpolationSpec.cxx src/TPCResidualWriterSpec.cxx src/TrackInterpolationReaderSpec.cxx - src/TrackInterpolationWorkflow.cxx - PUBLIC_LINK_LIBRARIES O2::GlobalTracking - O2::ITSWorkflow + PUBLIC_LINK_LIBRARIES O2::ITSWorkflow O2::SpacePoints O2::GlobalTrackingWorkflow - O2::TOFWorkflow + O2::TOFWorkflowIO O2::Framework + O2::TRDWorkflowIO ) o2_add_executable(scdcalib-interpolation-workflow diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h index 08cae7bfb464c..ef42d272de7f5 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,12 +16,19 @@ #include "DataFormatsTPC/Constants.h" #include "SpacePoints/TrackInterpolation.h" +#include "SpacePoints/TrackResiduals.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "TStopwatch.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" using namespace o2::framework; +namespace o2::globaltracking +{ +struct DataRequest; +} // namespace o2::globaltracking + namespace o2 { namespace tpc @@ -28,20 +36,23 @@ namespace tpc class TPCInterpolationDPL : public Task { public: - TPCInterpolationDPL(bool useMC) : mUseMC(useMC) {} + TPCInterpolationDPL(std::shared_ptr<o2::globaltracking::DataRequest> dr, bool useMC, bool processITSTPConly) : mDataRequest(dr), mUseMC(useMC), mProcessITSTPConly(processITSTPConly) {} ~TPCInterpolationDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; void endOfStream(EndOfStreamContext& ec) final; private: - o2::tpc::TrackInterpolation mInterpolation; // track interpolation engine + o2::tpc::TrackInterpolation mInterpolation; ///< track interpolation engine + o2::tpc::TrackResiduals mResidualProcessor; ///< conversion and avg. distortion map creation engine + std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest; ///< steers the input bool mUseMC{false}; ///< MC flag + bool mProcessITSTPConly{false}; ///< should also tracks without outer point (ITS-TPC only) be processed? TStopwatch mTimer; }; /// create a processor spec -framework::DataProcessorSpec getTPCInterpolationSpec(bool useMC, const std::vector<int>& tpcClusLanes); +framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool processITSTPConly); } // namespace tpc } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualWriterSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualWriterSpec.h index 59dbbe4e7fb1b..fb68d99de8d8b 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualWriterSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationReaderSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationReaderSpec.h index 01896f687b6bf..eef17b7b6b2e1 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationReaderSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationWorkflow.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationWorkflow.h deleted file mode 100644 index 4f631c71d7854..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TrackInterpolationWorkflow.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TPC_INTERPOLATION_WORKFLOW_H -#define O2_TPC_INTERPOLATION_WORKFLOW_H - -/// @file TrackInterpolationWorkflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace tpc -{ - -framework::WorkflowSpec getTPCInterpolationWorkflow(bool disableRootInp, bool disableRootOut); - -} // namespace tpc -} // namespace o2 - -#endif diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx index cf8a9a3e48e76..7b684ee88bb46 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,18 +13,24 @@ #include <vector> -#include "Framework/InputRecordWalker.h" #include "DataFormatsITS/TrackITS.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/ClusterNativeHelper.h" -#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsTRD/TrackTRD.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "TPCInterpolationWorkflow/TPCInterpolationSpec.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "SpacePoints/SpacePointsCalibParam.h" using namespace o2::framework; +using namespace o2::globaltracking; +using GTrackID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; namespace o2 { @@ -34,139 +41,85 @@ void TPCInterpolationDPL::init(InitContext& ic) { //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP("o2sim_grp.root"); + o2::base::Propagator::initFieldFromGRP(); mTimer.Stop(); mTimer.Reset(); mInterpolation.init(); + //mResidualProcessor.init(); // FIXME: add this once the track refits are implemented in the global tracking workflows } void TPCInterpolationDPL::run(ProcessingContext& pc) { + LOG(INFO) << "TPC Interpolation Workflow initialized. Start processing..."; mTimer.Start(false); - const auto tracksITS = pc.inputs().get<gsl::span<o2::its::TrackITS>>("trackITS"); - const auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("trackTPC"); - const auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("match"); - const auto tracksTPCClRefs = pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs"); - const auto trackMatchesTOF = pc.inputs().get<gsl::span<o2::dataformats::MatchInfoTOF>>("matchTOF"); // FIXME missing reader - const auto clustersTOF = pc.inputs().get<gsl::span<o2::tof::Cluster>>("clustersTOF"); - - // TPC Cluster loading part is copied from TPCITSMatchingSpec.cxx - //---------------------------->> TPC Clusters loading >>------------------------------------------ - int operation = 0; - uint64_t activeSectors = 0; - std::bitset<o2::tpc::constants::MAXSECTOR> validSectors = 0; - std::map<int, DataRef> datarefs; - std::vector<InputSpec> filter = { - {"check", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe}, - }; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref); - if (sectorHeader == nullptr) { - // FIXME: think about error policy - LOG(ERROR) << "sector header missing on header stack"; - throw std::runtime_error("sector header missing on header stack"); - } - const int& sector = sectorHeader->sector(); - std::bitset<o2::tpc::constants::MAXSECTOR> sectorMask(sectorHeader->sectorBits); - LOG(INFO) << "Reading TPC cluster data, sector mask is " << sectorMask; - if ((validSectors & sectorMask).any()) { - // have already data for this sector, this should not happen in the current - // sequential implementation, for parallel path merged at the tracker stage - // multiple buffers need to be handled - throw std::runtime_error("can only have one data set per sector"); - } - activeSectors |= sectorHeader->activeSectors; - validSectors |= sectorMask; - datarefs[sector] = ref; - } - - auto printInputLog = [&validSectors, &activeSectors](auto& r, const char* comment, auto& s) { - LOG(INFO) << comment << " " << *(r.spec) << ", size " << DataRefUtils::getPayloadSize(r) // - << " for sector " << s // - << std::endl // - << " input status: " << validSectors // - << std::endl // - << " active sectors: " << std::bitset<o2::tpc::constants::MAXSECTOR>(activeSectors); - }; - - if (activeSectors == 0 || (activeSectors & validSectors.to_ulong()) != activeSectors) { - // not all sectors available - // Since we expect complete input, this should not happen (why does the bufferization considered for TPC CA tracker? Ask Matthias) - throw std::runtime_error("Did not receive TPC clusters data for all sectors"); - } - //------------------------------------------------------------------------------ - std::vector<gsl::span<const char>> clustersTPC; - - for (auto const& refentry : datarefs) { - auto& sector = refentry.first; - auto& ref = refentry.second; - clustersTPC.emplace_back(ref.payload, DataRefUtils::getPayloadSize(ref)); - printInputLog(ref, "received", sector); - } - - // Just print TPC clusters status - { - // make human readable information from the bitfield - std::string bitInfo; - auto nActiveBits = validSectors.count(); - if (((uint64_t)0x1 << nActiveBits) == validSectors.to_ulong() + 1) { - // sectors 0 to some upper bound are active - bitInfo = "0-" + std::to_string(nActiveBits - 1); - } else { - int rangeStart = -1; - int rangeEnd = -1; - for (size_t sector = 0; sector < validSectors.size(); sector++) { - if (validSectors.test(sector)) { - if (rangeStart < 0) { - if (rangeEnd >= 0) { - bitInfo += ","; - } - bitInfo += std::to_string(sector); - if (nActiveBits == 1) { - break; - } - rangeStart = sector; - } - rangeEnd = sector; - } else { - if (rangeStart >= 0 && rangeEnd > rangeStart) { - bitInfo += "-" + std::to_string(rangeEnd); - } - rangeStart = -1; + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + std::vector<o2::globaltracking::RecoContainer::GlobalIDSet> gidTables; + std::vector<o2::track::TrackParCov> seeds; + std::vector<float> trkTimes; + std::vector<GTrackID> gids; + bool processITSTPConly = mProcessITSTPConly; // so that the flag can be used inside the lambda + // the creator goes from most complete track (ITS-TPC-TRD-TOF) to least complete one (ITS-TPC) + auto creator = [&gidTables, &seeds, &trkTimes, &recoData, &processITSTPConly, &gids](auto& _tr, GTrackID _origID, float t0, float tErr) { + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) { + bool trackGood = true; + bool hasOuterPoint = false; + auto gidTable = recoData.getSingleDetectorRefs(_origID); + if (!gidTable[GTrackID::ITS].isIndexSet() || !gidTable[GTrackID::TPC].isIndexSet()) { + // ITS and TPC track is always needed. At this stage ITS afterburner tracks are also rejected + return true; + } + if (gidTable[GTrackID::TRD].isIndexSet() || gidTable[GTrackID::TOF].isIndexSet()) { + hasOuterPoint = true; + } + const auto itstpcTrk = &recoData.getTPCITSTrack(gidTable[GTrackID::ITSTPC]); + const auto itsTrk = &recoData.getITSTrack(gidTable[GTrackID::ITS]); + const auto tpcTrk = &recoData.getTPCTrack(gidTable[GTrackID::TPC]); + // apply track quality cuts + if (itsTrk->getChi2() / itsTrk->getNumberOfClusters() > param::MaxITSChi2 || tpcTrk->getChi2() / tpcTrk->getNClusterReferences() > param::MaxTPCChi2) { + // reduced chi2 cut is the same for all track types + trackGood = false; + } + if (!hasOuterPoint) { + // ITS-TPC track (does not have outer points in TRD or TOF) + if (!processITSTPConly) { + return true; + } + if (itsTrk->getNumberOfClusters() < param::MinITSNClsNoOuterPoint || tpcTrk->getNClusterReferences() < param::MinTPCNClsNoOuterPoint) { + trackGood = false; + } + } else { + if (itsTrk->getNumberOfClusters() < param::MinITSNCls || tpcTrk->getNClusterReferences() < param::MinTPCNCls) { + trackGood = false; } } - if (rangeStart >= 0 && rangeEnd > rangeStart) { - bitInfo += "-" + std::to_string(rangeEnd); + if (trackGood) { + trkTimes.push_back(t0); + seeds.emplace_back(itsTrk->getParamOut()); // FIXME: should this not be a refit of the ITS track? + gidTables.emplace_back(gidTable); + gids.push_back(_origID); } + return true; + } else { + return false; } - LOG(INFO) << "running matching for sector(s) " << bitInfo; - } + }; + recoData.createTracksVariadic(creator); // create track sample considered for interpolation - o2::tpc::ClusterNativeAccess clusterIndex; - std::unique_ptr<o2::tpc::ClusterNative[]> clusterBuffer; - memset(&clusterIndex, 0, sizeof(clusterIndex)); - o2::tpc::ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer dummyMCOutput; - std::vector<o2::tpc::ClusterNativeHelper::ConstMCLabelContainerView> dummyMCInput; - o2::tpc::ClusterNativeHelper::Reader::fillIndex(clusterIndex, clusterBuffer, dummyMCOutput, clustersTPC, dummyMCInput); - //----------------------------<< TPC Clusters loading <<------------------------------------------ - - // pass input data to TrackInterpolation object - mInterpolation.setITSTracksInp(tracksITS); - mInterpolation.setTPCTracksInp(tracksTPC); - mInterpolation.setTPCTrackClusIdxInp(tracksTPCClRefs); - mInterpolation.setTPCClustersInp(&clusterIndex); - mInterpolation.setTOFMatchesInp(trackMatchesTOF); - mInterpolation.setITSTPCTrackMatchesInp(tracksITSTPC); - mInterpolation.setTOFClustersInp(clustersTOF); + LOG(INFO) << "Created " << seeds.size() << " seeds."; if (mUseMC) { // possibly MC labels will be used to check filtering procedure performance before interpolation // not yet implemented } - LOG(INFO) << "TPC Interpolation Workflow initialized. Start processing..."; - - mInterpolation.process(); + mInterpolation.process(recoData, gids, gidTables, seeds, trkTimes); + mTimer.Stop(); + LOGF(INFO, "TPC insterpolation timing: Cpu: %.3e Real: %.3e s", mTimer.CpuTime(), mTimer.RealTime()); + mTimer.Start(0); + //mResidualProcessor.setInputData(mInterpolation.getReferenceTracks(), mInterpolation.getClusterResiduals()); + //mResidualProcessor.convertToLocalResiduals(); // FIXME this will create one output file per TPC sector with local residuals. TODO Add filtering of residuals pc.outputs().snapshot(Output{"GLO", "TPCINT_TRK", 0, Lifetime::Timeframe}, mInterpolation.getReferenceTracks()); pc.outputs().snapshot(Output{"GLO", "TPCINT_RES", 0, Lifetime::Timeframe}, mInterpolation.getClusterResiduals()); @@ -179,39 +132,26 @@ void TPCInterpolationDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTPCInterpolationSpec(bool useMC, const std::vector<int>& tpcClusLanes) +DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t src, bool useMC, bool processITSTPConly) { - std::vector<InputSpec> inputs; + auto dataRequest = std::make_shared<DataRequest>(); std::vector<OutputSpec> outputs; - inputs.emplace_back("trackITS", "ITS", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPC", "TPC", "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPCClRefs", "TPC", "CLUSREFS", 0, Lifetime::Timeframe); - - inputs.emplace_back("clusTPC", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe); - - inputs.emplace_back("match", "GLO", "TPCITS", 0, Lifetime::Timeframe); - inputs.emplace_back("matchTOF", "TOF", "MATCHINFOS", 0, Lifetime::Timeframe); - inputs.emplace_back("clustersTOF", "TOF", "CLUSTERS", 0, Lifetime::Timeframe); - if (useMC) { LOG(FATAL) << "MC usage must be disabled for this workflow, since it is not yet implemented"; - // are the MC inputs from ITS-TPC matching and TOF matching duplicates? if trackITSMCTR == matchTOFMCITS one of them should be removed - inputs.emplace_back("trackITSMCTR", "GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPCMCTR", "GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); - inputs.emplace_back("matchTOFMC", o2::header::gDataOriginTOF, "MATCHTOFINFOSMC", 0, Lifetime::Timeframe); - inputs.emplace_back("matchTOFMCTPC", o2::header::gDataOriginTOF, "MATCHTPCINFOSMC", 0, Lifetime::Timeframe); - inputs.emplace_back("matchTOFMCITS", o2::header::gDataOriginTOF, "MATCHITSINFOSMC", 0, Lifetime::Timeframe); } + dataRequest->requestTracks(src, useMC); + dataRequest->requestClusters(src, useMC); + outputs.emplace_back("GLO", "TPCINT_TRK", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "TPCINT_RES", 0, Lifetime::Timeframe); return DataProcessorSpec{ "tpc-track-interpolation", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask<TPCInterpolationDPL>(useMC)}, + AlgorithmSpec{adaptFromTask<TPCInterpolationDPL>(dataRequest, useMC, processITSTPConly)}, Options{}}; } diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx index 7c2e5678c8d4d..1dba6e5ec60e3 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationReaderSpec.cxx index c2e41024be2cf..db79a21c97abe 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationReaderSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationWorkflow.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationWorkflow.cxx deleted file mode 100644 index 4793d8b86ea2a..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationWorkflow.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TrackInterpolationWorkflow.cxx - -#include <vector> - -#include "ITSWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/TrackReaderSpec.h" -#include "TPCWorkflow/PublisherSpec.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "TOFWorkflowUtils/ClusterReaderSpec.h" -#include "TOFWorkflow/TOFMatchedReaderSpec.h" -#include "Algorithm/RangeTokenizer.h" -#include "TPCInterpolationWorkflow/TPCResidualWriterSpec.h" -#include "TPCInterpolationWorkflow/TPCInterpolationSpec.h" -#include "TPCInterpolationWorkflow/TrackInterpolationWorkflow.h" - -namespace o2 -{ -namespace tpc -{ - -framework::WorkflowSpec getTPCInterpolationWorkflow(bool disableRootInp, bool disableRootOut) -{ - framework::WorkflowSpec specs; - bool useMC = false; - std::vector<int> tpcClusSectors = o2::RangeTokenizer::tokenize<int>("0-35"); - std::vector<int> tpcClusLanes = tpcClusSectors; - if (!disableRootInp) { - specs.emplace_back(o2::its::getITSTrackReaderSpec(useMC)); - specs.emplace_back(o2::tpc::getTPCTrackReaderSpec(useMC)); - specs.emplace_back(o2::tpc::getPublisherSpec(o2::tpc::PublisherConf{ - "tpc-native-cluster-reader", - "tpcrec", - {"clusterbranch", "TPCClusterNative", "Branch with TPC native clusters"}, - {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, - OutputSpec{"TPC", "CLUSTERNATIVE"}, - OutputSpec{"TPC", "CLNATIVEMCLBL"}, - tpcClusSectors, - tpcClusLanes}, - useMC)); - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(useMC)); - specs.emplace_back(o2::tof::getClusterReaderSpec(useMC)); - specs.emplace_back(o2::tof::getTOFMatchedReaderSpec(useMC)); - } - - specs.emplace_back(o2::tpc::getTPCInterpolationSpec(useMC, tpcClusLanes)); - - if (!disableRootOut) { - specs.emplace_back(o2::tpc::getTPCResidualWriterSpec(useMC)); - } - return specs; -} - -} // namespace tpc -} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx index 059eae8df5d8f..21bbb9457929e 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx @@ -1,19 +1,25 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "TPCInterpolationWorkflow/TrackInterpolationWorkflow.h" #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" -#include "TPCWorkflow/TPCSectorCompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "TPCInterpolationWorkflow/TPCInterpolationSpec.h" +#include "TPCInterpolationWorkflow/TPCResidualWriterSpec.h" using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; // ------------------------------------------------------------------ @@ -21,12 +27,17 @@ using namespace o2::framework; void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - std::string keyvaluehelp("Semicolon separated key=value strings ..."); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"enable-itsonly", o2::framework::VariantType::Bool, false, {"process tracks without outer point (ITS-TPC only)"}}, + {"tracking-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use for tracking"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); } // the matcher process requires the TPC sector completion to trigger and data on @@ -46,11 +57,27 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { + WorkflowSpec specs; + GID::mask_t allowedSources = GID::getSourcesMask("ITS,TPC,TRD,TOF,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2tpcinterpolation-workflow_configuration.ini"); - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); - auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); - return std::move(o2::tpc::getTPCInterpolationWorkflow(disableRootInp, disableRootOut)); + auto useMC = !configcontext.options().get<bool>("disable-mc"); + useMC = false; // force disabling MC as long as it is not implemented + auto processITSTPConly = configcontext.options().get<bool>("enable-itsonly"); + GID::mask_t src = allowedSources & GID::getSourcesMask(configcontext.options().get<std::string>("tracking-sources")); + LOG(INFO) << "Data sources: " << GID::getSourcesNames(src); + + specs.emplace_back(o2::tpc::getTPCInterpolationSpec(src, useMC, processITSTPConly)); + if (!configcontext.options().get<bool>("disable-root-output")) { + specs.emplace_back(o2::tpc::getTPCResidualWriterSpec(useMC)); + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, useMC); + + return std::move(specs); } diff --git a/Detectors/HMPID/CMakeLists.txt b/Detectors/HMPID/CMakeLists.txt index 46b43743c005e..4be323cfcaf09 100644 --- a/Detectors/HMPID/CMakeLists.txt +++ b/Detectors/HMPID/CMakeLists.txt @@ -1,12 +1,15 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(simulation) +add_subdirectory(reconstruction) +add_subdirectory(workflow) diff --git a/Detectors/HMPID/README.md b/Detectors/HMPID/README.md new file mode 100644 index 0000000000000..775f2ad24d77c --- /dev/null +++ b/Detectors/HMPID/README.md @@ -0,0 +1,11 @@ +<!-- doxy +\page refDetectorsHMPID HMPID +/doxy --> + +# HMPID + +This is a top page for the HMPID detector documentation. + +<!-- doxy +* \subpage refHMPIDworkflow +/doxy --> diff --git a/Detectors/HMPID/base/CMakeLists.txt b/Detectors/HMPID/base/CMakeLists.txt index 5f1940e8a6597..da9b9e77b73d0 100644 --- a/Detectors/HMPID/base/CMakeLists.txt +++ b/Detectors/HMPID/base/CMakeLists.txt @@ -1,18 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(HMPIDBase - SOURCES src/Param.cxx src/Digit.cxx + SOURCES src/Param.cxx src/Geo.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat - O2::SimulationDataFormat ROOT::Physics) + O2::SimulationDataFormat + ROOT::Physics) o2_target_root_dictionary(HMPIDBase HEADERS include/HMPIDBase/Param.h - include/HMPIDBase/Digit.h) + include/HMPIDBase/Geo.h) diff --git a/Detectors/HMPID/base/include/HMPIDBase/Common.h b/Detectors/HMPID/base/include/HMPIDBase/Common.h new file mode 100644 index 0000000000000..8675d11d47755 --- /dev/null +++ b/Detectors/HMPID/base/include/HMPIDBase/Common.h @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Common.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 15/02/2021 + +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_COMMON_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_COMMON_H_ + +#include <TStopwatch.h> +#include "Framework/Logger.h" + +namespace o2 +{ +namespace hmpid +{ + +// ------- Execution time functions ------- + +/// \class ExecutionTimer +/// \brief HMPID Derived class for the Time of Workflows +class ExecutionTimer +{ + private: + TStopwatch mTimer; + Double_t mStartTime; + Double_t mLastLogTime; + Double_t mElapseLogTime; + + public: + ExecutionTimer() + { + mStartTime = 0; + mLastLogTime = 0; + mElapseLogTime = 10; // default 10 seconds + }; + + ~ExecutionTimer() = default; + + /// getElapseLogTime : returns the seconds for the elapsed log message + /// @return : the number of seconds for the elapsed logging + Double_t getElapseLogTime() { return mElapseLogTime; }; + + /// setElapseLogTime : set the interval for the elapsed logging + /// @param[in] interval : the seconds of interval for elapsed logging + void setElapseLogTime(Double_t interval) + { + mElapseLogTime = interval; + return; + }; + + /// start : starts the timer + void start() + { + mStartTime = mTimer.CpuTime(); + mLastLogTime = mStartTime; + mTimer.Start(false); + return; + }; + + /// stop : stops the timer + void stop() + { + mTimer.Stop(); + return; + }; + + /// logMes : Out a message on the LOG(INFO) with extra execution time info + /// @param[in] message : the message to print + void logMes(std::string const message) + { + LOG(INFO) << message << " Execution time = " << (mTimer.CpuTime() - mStartTime); + mTimer.Continue(); + return; + }; + + /// elapseMes : Out a message on the LOG(INFO) with extra execution time info + /// is the set interval was reached + /// @param[in] message : the message to print + void elapseMes(std::string const message) + { + if (mTimer.CpuTime() - mLastLogTime > mElapseLogTime) { + LOG(INFO) << message << " Execution time = " << (mTimer.CpuTime() - mStartTime); + mLastLogTime = mTimer.CpuTime(); + } + mTimer.Continue(); + return; + }; +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_COMMON_H_ */ diff --git a/Detectors/HMPID/base/include/HMPIDBase/Digit.h b/Detectors/HMPID/base/include/HMPIDBase/Digit.h deleted file mode 100644 index 27f43af50cedb..0000000000000 --- a/Detectors/HMPID/base/include/HMPIDBase/Digit.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_DIGIT_H_ -#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_DIGIT_H_ - -#include "CommonDataFormat/TimeStamp.h" -#include "HMPIDBase/Hit.h" // for hit -#include "HMPIDBase/Param.h" // for param -#include "TMath.h" - -namespace o2 -{ -namespace hmpid -{ - -/// \class Digit -/// \brief HMPID digit implementation -using DigitBase = o2::dataformats::TimeStamp<double>; -class Digit : public DigitBase -{ - public: - Digit() = default; - Digit(double time, int pad, float charge) : DigitBase(time), mPad(pad), mQ(charge) {} - - float getCharge() const { return mQ; } - int getPadID() const { return mPad; } - // convenience conversion to x-y pad coordinates - int getPx() const { return Param::A2X(mPad); } - int getPy() const { return Param::A2Y(mPad); } - - static void getPadAndTotalCharge(HitType const& hit, int& chamber, int& pc, int& px, int& py, float& totalcharge) - { - float localX; - float localY; - chamber = hit.GetDetectorID(); - double tmp[3] = {hit.GetX(), hit.GetY(), hit.GetZ()}; - Param::Instance()->Mars2Lors(chamber, tmp, localX, localY); - Param::Lors2Pad(localX, localY, pc, px, py); - - totalcharge = Digit::QdcTot(hit.GetEnergyLoss(), hit.GetTime(), pc, px, py, localX, localY); - } - - static float getFractionalContributionForPad(HitType const& hit, int somepad) - { - float localX; - float localY; - - // chamber number is in detID - const auto chamber = hit.GetDetectorID(); - double tmp[3] = {hit.GetX(), hit.GetY(), hit.GetZ()}; - // converting chamber id and hit coordiates to local coordinates - Param::Instance()->Mars2Lors(chamber, tmp, localX, localY); - // calculate charge fraction in given pad - return Digit::InMathieson(localX, localY, somepad); - } - - // add charge to existing digit - void addCharge(float q) { mQ += q; } - - private: - float mQ = 0.; - int mPad = 0.; // -1 indicates invalid digit - - static float LorsX(int pad) { return Param::LorsX(Param::A2P(pad), Param::A2X(pad)); } //center of the pad x, [cm] - static float LorsY(int pad) { return Param::LorsY(Param::A2P(pad), Param::A2Y(pad)); } //center of the pad y, [cm] - - // determines the total charge created by a hit - // might modify the localX, localY coordiates associated to the hit - static float QdcTot(float e, float time, int pc, int px, int py, float& localX, float& localY); - - static float IntPartMathiX(float x, int pad) - { - // Integration of Mathieson. - // This is the answer to electrostatic problem of charge distrubution in MWPC described elsewhere. (NIM A370(1988)602-603) - // Arguments: x,y- position of the center of Mathieson distribution - // Returns: a charge fraction [0-1] imposed into the pad - auto shift1 = -LorsX(pad) + 0.5 * Param::SizePadX(); - auto shift2 = -LorsX(pad) - 0.5 * Param::SizePadX(); - - auto ux1 = Param::SqrtK3x() * TMath::TanH(Param::K2x() * (x + shift1) / Param::PitchAnodeCathode()); - auto ux2 = Param::SqrtK3x() * TMath::TanH(Param::K2x() * (x + shift2) / o2::hmpid::Param::PitchAnodeCathode()); - - return o2::hmpid::Param::K4x() * (TMath::ATan(ux2) - TMath::ATan(ux1)); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - static Double_t IntPartMathiY(Double_t y, int pad) - { - // Integration of Mathieson. - // This is the answer to electrostatic problem of charge distrubution in MWPC described elsewhere. (NIM A370(1988)602-603) - // Arguments: x,y- position of the center of Mathieson distribution - // Returns: a charge fraction [0-1] imposed into the pad - Double_t shift1 = -LorsY(pad) + 0.5 * o2::hmpid::Param::SizePadY(); - Double_t shift2 = -LorsY(pad) - 0.5 * o2::hmpid::Param::SizePadY(); - - Double_t uy1 = Param::SqrtK3y() * TMath::TanH(Param::K2y() * (y + shift1) / Param::PitchAnodeCathode()); - Double_t uy2 = Param::SqrtK3y() * TMath::TanH(Param::K2y() * (y + shift2) / Param::PitchAnodeCathode()); - - return Param::K4y() * (TMath::ATan(uy2) - TMath::ATan(uy1)); - } - - static float InMathieson(float localX, float localY, int pad) - { - return 4. * Digit::IntPartMathiX(localX, pad) * Digit::IntPartMathiY(localY, pad); - } - - ClassDefNV(Digit, 2); -}; - -} // namespace hmpid -} // namespace o2 - -#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_DIGIT_H_ */ diff --git a/Detectors/HMPID/base/include/HMPIDBase/Geo.h b/Detectors/HMPID/base/include/HMPIDBase/Geo.h new file mode 100644 index 0000000000000..18fb12364ce65 --- /dev/null +++ b/Detectors/HMPID/base/include/HMPIDBase/Geo.h @@ -0,0 +1,224 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Geo.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 15/02/2021 + +#ifndef ALICEO2_HMPID_GEO_H +#define ALICEO2_HMPID_GEO_H + +#include <TMath.h> +#include <Rtypes.h> + +namespace o2 +{ +namespace hmpid +{ + +/* ------------------ HMPID Detector Coordinate definition ------------------- + + 143 .-------------. .-------------. 0 ------.------ 23 + | | |.-----.-----.| | | <-- | + | | || | || | | 9 0 | + | | || 4 | 5 || | | Dil. | + ^ | | || | || | | | | ^ + | | | ||_____|_____|| | | | | | + | | | |.-----.-----.| | | | | | + Y | | || | || | | | + | | | || 2 | 3 || Column | n | n+1 | Column + | | | || | || | | | + | | ||_____|_____|| | | | | | + | | 47 ^ |.-----.-----.| | | | | | + | | | || | || V | | | | + | | Y || 0 | 1 || | Dil. | | + | | | || | || | 9 0 | | + | | 0 ||_____|_____|| | <-- | | + 0 .-------------. ------------- 23 ------.------ 0 + 0 --X--> 159 0 -X->79 + + Pad(Module,x,y) Pad(Chamber,PhotoCat,x,y) Pad(Equipment,Column,Dilogic,Channel) + + Equipment n + + 143 + ^ + | 46 40 34 28 22 16 10 04 + | 44 38 32 26 20 14 08 02 + 40 36 30 24 18 12 06 00 + y 43 37 31 25 19 13 07 01 + 45 39 33 27 21 15 09 03 + | 47 41 35 29 23 17 11 05 + | + + 0 + + + 0 --------- x ------> 79 + + For Equipment n : x = 79 - (Dilo * 8 + Chan / 8) + y = 143 - (Column * 6 + Chan % 6) + + --------------------------------------------------------------------------- */ +/// \class Geo +/// \brief HMPID detector geometry (only statics) +class Geo +{ + public: + // From AliTOFGeometry + // static void translate(Float_t* xyz, Float_t translationVector[3]); + // enum { + // // DAQ characteristics + // kNDDL = 4, // Number of DDL (Detector Data Link) per sector + // kNTRM = 12, // Number of TRM ( Readout Module) per DDL + // kNTdc = 15, // Number of Tdc (Time to Digital Converter) per TRM + // kNChain = 2, // Number of chains per TRM + // kNCrate = 72, // Number of Crates + // kNCh = 8 // Number of channels per Tdc + // }; + + // ---- HMPID geometry ------- + static constexpr int MAXEQUIPMENTS = 14; + static constexpr int N_SEGMENTS = 3; + static constexpr int N_COLXSEGMENT = 8; + static constexpr int N_COLUMNS = 24; + static constexpr int N_DILOGICS = 10; + static constexpr int N_CHANNELS = 48; + static constexpr int N_DILOCHANNELS = 64; + + static constexpr int N_MODULES = 7; + static constexpr int N_XROWS = 160; + static constexpr int N_YCOLS = 144; + + static constexpr int MAXYCOLS = 143; + static constexpr int MAXHALFXROWS = 79; + static constexpr int HALFXROWS = 80; + + static constexpr int DILOPADSCOLS = 6; + static constexpr int DILOPADSROWS = 8; + + static constexpr int EQUIPMENTSPERMODULE = 2; + + static constexpr int N_EQUIPMENTTOTALPADS = N_SEGMENTS * N_COLXSEGMENT * N_DILOGICS * N_CHANNELS; + static constexpr int N_HMPIDTOTALPADS = MAXEQUIPMENTS * N_SEGMENTS * N_COLXSEGMENT * N_DILOGICS * N_CHANNELS; + + static constexpr int N_PHOTOCATODS = 6; + static constexpr int N_PHOTOCATODSX = 80; + static constexpr int N_PHOTOCATODSY = 48; + static constexpr int MAXXPHOTO = 79; + static constexpr int MAXYPHOTO = 47; + + // from + //static constexpr Bool_t FEAWITHMASKS[NSECTORS] = + // // TOF sectors with Nino masks: 0, 8, 9, 10, 16 + // {kTRUE, kFALSE, kFALSE, kFALSE, kFALSE, kFALSE, kFALSE, kFALSE, kTRUE, + // kTRUE, kTRUE, kFALSE, kFALSE, kFALSE, kFALSE, kFALSE, kTRUE, kFALSE}; + //; // Selecting TOF sectors containing FEA cooling masks + + // static Float_t getCableLength(Int_t icrate, Int_t islot, Int_t ichain, Int_t itdc) { return CABLELENGTH[icrate][islot - 3][ichain][itdc / 3]; } + + private: + static void Init(); + + ClassDefNV(Geo, 1); +}; + +class ReadOut +{ + public: + struct LinkAddr { + uint8_t Fee; + uint8_t Cru; + uint8_t Lnk; + uint8_t Flp; + std::string_view FlpHostName; + }; + union Lnk { + LinkAddr Id; + uint32_t LinkUId; + }; + static constexpr Lnk mEq[Geo::MAXEQUIPMENTS] = {{0, 0, 0, 160, "alio-cr1-flp160"}, + {1, 0, 1, 160, "alio-cr1-flp160"}, + {2, 0, 2, 160, "alio-cr1-flp160"}, + {3, 0, 3, 160, "alio-cr1-flp160"}, + {4, 1, 0, 160, "alio-cr1-flp160"}, + {5, 1, 1, 160, "alio-cr1-flp160"}, + {8, 1, 2, 160, "alio-cr1-flp160"}, + {9, 1, 3, 160, "alio-cr1-flp160"}, + {6, 2, 0, 161, "alio-cr1-flp161"}, + {7, 2, 1, 161, "alio-cr1-flp161"}, + {10, 2, 2, 161, "alio-cr1-flp161"}, + {11, 3, 0, 161, "alio-cr1-flp161"}, + {12, 3, 1, 161, "alio-cr1-flp161"}, + {13, 3, 2, 161, "alio-cr1-flp161"}}; + + static inline int FeeId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Fee; }; + static inline int CruId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Cru; }; + static inline int LnkId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Lnk; }; + static inline int FlpId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Flp; }; + static inline std::string_view FlpHostName(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? "" : mEq[idx].Id.FlpHostName; }; + static inline uint32_t UniqueId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].LinkUId; }; + + static unsigned int searchIdx(int FeeId) + { + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + if (FeeId == mEq[i].Id.Fee) { + return (i); + } + } + return (-1); + } + static unsigned int searchIdx(int CruId, int LnkId) + { + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + if (CruId == mEq[i].Id.Cru && LnkId == mEq[i].Id.Lnk) { + return (i); + } + } + return (-1); + } + static void getInfo(unsigned int idx, int& Fee, int& Cru, int& Lnk, int& Flp) + { + Cru = mEq[idx].Id.Cru; + Lnk = mEq[idx].Id.Lnk; + Fee = mEq[idx].Id.Fee; + Flp = mEq[idx].Id.Flp; + return; + } + + ClassDefNV(ReadOut, 1); +}; +/* +void ReadOut::Init() +{ + mEq[0].Id = { 0, 0, 0, 160}; + mEq[1].Id = { 1, 0, 1, 160}; + mEq[2].Id = { 2, 0, 2, 160}; + mEq[3].Id = { 3, 0, 3, 160}; + mEq[4].Id = { 4, 1, 0, 160}; + mEq[5].Id = { 5, 1, 1, 160}; + mEq[6].Id = { 8, 1, 2, 160}; + mEq[7].Id = { 9, 1, 3, 160}; + mEq[8].Id = { 6, 2, 0, 161}; + mEq[9].Id = { 7, 2, 1, 161}; + mEq[10].Id = {10, 2, 2, 161}; + mEq[11].Id = {11, 3, 0, 161}; + mEq[12].Id = {12, 3, 1, 161}; + mEq[13].Id = {13, 3, 2, 161}; +}; +*/ + +} // namespace hmpid +} // namespace o2 + +#endif diff --git a/Detectors/HMPID/base/include/HMPIDBase/Hit.h b/Detectors/HMPID/base/include/HMPIDBase/Hit.h deleted file mode 100644 index 16e944da8a051..0000000000000 --- a/Detectors/HMPID/base/include/HMPIDBase/Hit.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_HIT_H_ -#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_HIT_H_ - -#include "SimulationDataFormat/BaseHits.h" -#include "CommonUtils/ShmAllocator.h" - -namespace o2 -{ -namespace hmpid -{ - -// define HMPID hit type -class HitType : public o2::BasicXYZEHit<float> -{ - public: - using Base = o2::BasicXYZEHit<float>; - using Base::Base; - ClassDef(HitType, 1); -}; - -} // namespace hmpid -} // namespace o2 - -#ifdef USESHM -namespace std -{ -template <> -class allocator<o2::hmpid::HitType> : public o2::utils::ShmAllocator<o2::hmpid::HitType> -{ -}; -} // namespace std -#endif - -#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_HIT_H_ */ diff --git a/Detectors/HMPID/base/include/HMPIDBase/Param.h b/Detectors/HMPID/base/include/HMPIDBase/Param.h index d94a6c2caee95..7466ee9f26101 100644 --- a/Detectors/HMPID/base/include/HMPIDBase/Param.h +++ b/Detectors/HMPID/base/include/HMPIDBase/Param.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,10 +42,10 @@ class Param } } - void Print(Option_t* opt = "") const; //print current parametrization + void print(Option_t* opt = "") const; //print current parametrization - static Param* Instance(); //pointer to Param singleton - static inline Param* InstanceNoGeo(); //pointer to Param singleton without geometry.root for MOOD, displays, ... + static Param* instance(); //pointer to Param singleton + static inline Param* instanceNoGeo(); //pointer to Param singleton without geometry.root for MOOD, displays, ... //geo info enum EChamberData { kMinCh = 0, kMaxCh = 6, @@ -66,119 +67,111 @@ class Param kPadSigmaMasked = 20 }; //One can go up to 5 sigma cut, overflow is protected in AliHMPIDCalib static float r2d() { return 57.2957795; } - static float SizePadX() { return fgCellX; } //pad size x, [cm] - static float SizePadY() { return fgCellY; } //pad size y, [cm] - - static float SizePcX() { return fgPcX; } // PC size x - static float SizePcY() { return fgPcY; } // PC size y - static float MaxPcX(Int_t iPc) { return fgkMaxPcX[iPc]; } // PC limits - static float MaxPcY(Int_t iPc) { return fgkMaxPcY[iPc]; } // PC limits - static float MinPcX(Int_t iPc) { return fgkMinPcX[iPc]; } // PC limits - static float MinPcY(Int_t iPc) { return fgkMinPcY[iPc]; } // PC limits - static Int_t Nsig() { return fgNSigmas; } //Getter n. sigmas for noise - static float SizeAllX() { return fgAllX; } //all PCs size x, [cm] - static float SizeAllY() { return fgAllY; } //all PCs size y, [cm] + static float sizePadX() { return fgCellX; } //pad size x, [cm] + static float sizePadY() { return fgCellY; } //pad size y, [cm] + + static float sizePcX() { return fgPcX; } // PC size x + static float sizePcY() { return fgPcY; } // PC size y + static float maxPcX(Int_t iPc) { return fgkMaxPcX[iPc]; } // PC limits + static float maxPcY(Int_t iPc) { return fgkMaxPcY[iPc]; } // PC limits + static float minPcX(Int_t iPc) { return fgkMinPcX[iPc]; } // PC limits + static float minPcY(Int_t iPc) { return fgkMinPcY[iPc]; } // PC limits + static Int_t nsig() { return fgNSigmas; } //Getter n. sigmas for noise + static float sizeAllX() { return fgAllX; } //all PCs size x, [cm] + static float sizeAllY() { return fgAllY; } //all PCs size y, [cm] //center of the pad x, [cm] - static float LorsX(Int_t pc, Int_t padx) { return (padx + 0.5) * SizePadX() + fgkMinPcX[pc]; } + static float lorsX(Int_t pc, Int_t padx) { return (padx + 0.5) * sizePadX() + fgkMinPcX[pc]; } //center of the pad y, [cm] - static float LorsY(Int_t pc, Int_t pady) { return (pady + 0.5) * SizePadY() + fgkMinPcY[pc]; } + static float lorsY(Int_t pc, Int_t pady) { return (pady + 0.5) * sizePadY() + fgkMinPcY[pc]; } //PhiMin (degree) of the camber ch - float ChPhiMin(Int_t ch) { return Lors2Mars(ch, LorsX(ch, kMinPx) - mX, LorsY(ch, kMinPy) - mY).Phi() * r2d(); } + float chPhiMin(Int_t ch) { return lors2Mars(ch, lorsX(ch, kMinPx) - mX, lorsY(ch, kMinPy) - mY).Phi() * r2d(); } //ThMin (degree) of the camber ch - float ChThMin(Int_t ch) { return Lors2Mars(ch, LorsX(ch, kMinPx) - mX, LorsY(ch, kMinPy) - mY).Theta() * r2d(); } + float chThMin(Int_t ch) { return lors2Mars(ch, lorsX(ch, kMinPx) - mX, lorsY(ch, kMinPy) - mY).Theta() * r2d(); } //PhiMax (degree) of the camber ch - float ChPhiMax(Int_t ch) { return Lors2Mars(ch, LorsX(ch, kMaxPcx) - mX, LorsY(ch, kMaxPcy) - mY).Phi() * r2d(); } + float chPhiMax(Int_t ch) { return lors2Mars(ch, lorsX(ch, kMaxPcx) - mX, lorsY(ch, kMaxPcy) - mY).Phi() * r2d(); } //ThMax (degree) of the camber ch - float ChThMax(Int_t ch) { return Lors2Mars(ch, LorsX(ch, kMaxPcx) - mX, LorsY(ch, kMaxPcy) - mY).Theta() * r2d(); } + float chThMax(Int_t ch) { return lors2Mars(ch, lorsX(ch, kMaxPcx) - mX, lorsY(ch, kMaxPcy) - mY).Theta() * r2d(); } - static void Lors2Pad(float x, float y, Int_t& pc, Int_t& px, Int_t& py); //(x,y)->(pc,px,py) + static void lors2Pad(float x, float y, Int_t& pc, Int_t& px, Int_t& py); //(x,y)->(pc,px,py) - //(ch,pc,padx,pady)-> abs pad - static Int_t Abs(Int_t ch, Int_t pc, Int_t x, Int_t y) { return ch * 100000000 + pc * 1000000 + x * 1000 + y; } - static Int_t DDL2C(Int_t ddl) { return ddl / 2; } //ddl -> chamber - static Int_t A2C(Int_t pad) { return pad / 100000000; } //abs pad -> chamber - static Int_t A2P(Int_t pad) { return pad % 100000000 / 1000000; } //abs pad -> pc - static Int_t A2X(Int_t pad) { return pad % 1000000 / 1000; } //abs pad -> pad X - static Int_t A2Y(Int_t pad) { return pad % 1000; } //abs pad -> pad Y + static bool isOverTh(float q) { return q >= fgThreshold; } //is digit over threshold? - static bool IsOverTh(float q) { return q >= fgThreshold; } //is digit over threshold? + bool getInstType() const { return fgInstanceType; } //return if the instance is from geom or ideal - bool GetInstType() const { return fgInstanceType; } //return if the instance is from geom or ideal + inline static bool isInDead(float x, float y); //is the point in dead area? + inline static bool isDeadPad(Int_t padx, Int_t pady, Int_t ch); //is a dead pad? - inline static bool IsInDead(float x, float y); //is the point in dead area? - inline static bool IsDeadPad(Int_t padx, Int_t pady, Int_t ch); //is a dead pad? + inline void setChStatus(Int_t ch, bool status = kTRUE); + inline void setSectStatus(Int_t ch, Int_t sect, bool status); + inline void setPcStatus(Int_t ch, Int_t pc, bool status); + inline void printChStatus(Int_t ch); + inline void setGeomAccept(); - inline void SetChStatus(Int_t ch, bool status = kTRUE); - inline void SetSectStatus(Int_t ch, Int_t sect, bool status); - inline void SetPcStatus(Int_t ch, Int_t pc, bool status); - inline void PrintChStatus(Int_t ch); - inline void SetGeomAccept(); - - static Int_t InHVSector(float y); //find HV sector - static Int_t Radiator(float y) + static Int_t inHVSector(float y); //find HV sector + static Int_t radiator(float y) { - if (InHVSector(y) < 0) { + if (inHVSector(y) < 0) { return -1; } - return InHVSector(y) / 2; + return inHVSector(y) / 2; } // height in the radiator to estimate temperature from gradient - static double HinRad(float y) + static double hinRad(float y) { - if (Radiator(y) < 0) { + if (radiator(y) < 0) { return -1; } - return y - Radiator(y) * fgkMinPcY[Radiator(y)]; + return y - radiator(y) * fgkMinPcY[radiator(y)]; } //is point inside chamber boundaries? - static bool IsInside(float x, float y, float d = 0) + static bool isInside(float x, float y, float d = 0) { return x > -d && y > -d && x < fgkMaxPcX[kMaxPc] + d && y < fgkMaxPcY[kMaxPc] + d; } //For optical properties - static double EPhotMin() { return 5.5; } // - static double EPhotMax() { return 8.5; } //Photon energy range,[eV] - static double NIdxRad(double eV, double temp) + static double ePhotMin() { return 5.5; } // + static double ePhotMax() { return 8.5; } //Photon energy range,[eV] + static double nIdxRad(double eV, double temp) { return TMath::Sqrt(1 + 0.554 * (1239.84 / eV) * (1239.84 / eV) / ((1239.84 / eV) * (1239.84 / eV) - 5769)) - 0.0005 * (temp - 20); } - static double NIdxWin(double eV) { return TMath::Sqrt(1 + 46.411 / (10.666 * 10.666 - eV * eV) + 228.71 / (18.125 * 18.125 - eV * eV)); } - static double NMgF2Idx(double eV) { return 1.7744 - 2.866e-3 * (1239.842609 / eV) + 5.5564e-6 * (1239.842609 / eV) * (1239.842609 / eV); } // MgF2 idx of trasparency system - static double NIdxGap(double eV) { return 1 + 0.12489e-6 / (2.62e-4 - eV * eV / 1239.84 / 1239.84); } - static double LAbsRad(double eV) { return (eV < 7.8) * (GausPar(eV, 3.20491e16, -0.00917890, 0.742402) + GausPar(eV, 3035.37, 4.81171, 0.626309)) + (eV >= 7.8) * 0.0001; } - static double LAbsWin(double eV) { return (eV < 8.2) * (818.8638 - 301.0436 * eV + 36.89642 * eV * eV - 1.507555 * eV * eV * eV) + (eV >= 8.2) * 0.0001; } //fit from DiMauro data 28.10.03 - static double LAbsGap(double eV) { return (eV < 7.75) * 6512.399 + (eV >= 7.75) * 3.90743e-2 / (-1.655279e-1 + 6.307392e-2 * eV - 8.011441e-3 * eV * eV + 3.392126e-4 * eV * eV * eV); } - static double QEffCSI(double eV) { return (eV > 6.07267) * 0.344811 * (1 - exp(-1.29730 * (eV - 6.07267))); } //fit from DiMauro data 28.10.03 - static double GausPar(double x, double a1, double a2, double a3) { return a1 * TMath::Exp(-0.5 * ((x - a2) / a3) * ((x - a2) / a3)); } + static double nIdxWin(double eV) { return TMath::Sqrt(1 + 46.411 / (10.666 * 10.666 - eV * eV) + 228.71 / (18.125 * 18.125 - eV * eV)); } + static double nMgF2Idx(double eV) { return 1.7744 - 2.866e-3 * (1239.842609 / eV) + 5.5564e-6 * (1239.842609 / eV) * (1239.842609 / eV); } // MgF2 idx of trasparency system + static double nIdxGap(double eV) { return 1 + 0.12489e-6 / (2.62e-4 - eV * eV / 1239.84 / 1239.84); } + static double lAbsRad(double eV) { return (eV < 7.8) * (gausPar(eV, 3.20491e16, -0.00917890, 0.742402) + gausPar(eV, 3035.37, 4.81171, 0.626309)) + (eV >= 7.8) * 0.0001; } + static double lAbsWin(double eV) { return (eV < 8.2) * (818.8638 - 301.0436 * eV + 36.89642 * eV * eV - 1.507555 * eV * eV * eV) + (eV >= 8.2) * 0.0001; } //fit from DiMauro data 28.10.03 + static double lAbsGap(double eV) { return (eV < 7.75) * 6512.399 + (eV >= 7.75) * 3.90743e-2 / (-1.655279e-1 + 6.307392e-2 * eV - 8.011441e-3 * eV * eV + 3.392126e-4 * eV * eV * eV); } + static double qEffCSI(double eV) { return (eV > 6.07267) * 0.344811 * (1 - exp(-1.29730 * (eV - 6.07267))); } //fit from DiMauro data 28.10.03 + static double gausPar(double x, double a1, double a2, double a3) { return a1 * TMath::Exp(-0.5 * ((x - a2) / a3) * ((x - a2) / a3)); } //find the temperature of the C6F14 in a given point with coord. y (in x is uniform) - inline static double FindTemp(double tLow, double tUp, double y); + inline static double findTemp(double tLow, double tUp, double y); - double GetEPhotMean() const { return mPhotEMean; } - double GetRefIdx() const { return mRefIdx; } //running refractive index + double getEPhotMean() const { return mPhotEMean; } + double getRefIdx() const { return mRefIdx; } //running refractive index - double MeanIdxRad() const { return NIdxRad(mPhotEMean, mTemp); } - double MeanIdxWin() const { return NIdxWin(mPhotEMean); } + double meanIdxRad() const { return nIdxRad(mPhotEMean, mTemp); } + double meanIdxWin() const { return nIdxWin(mPhotEMean); } // - float DistCut() const { return 1.0; } //<--TEMPORAR--> to be removed in future. Cut for MIP-TRACK residual - float QCut() const { return 100; } //<--TEMPORAR--> to be removed in future. Separation PHOTON-MIP charge - float MultCut() const { return 30; } //<--TEMPORAR--> to be removed in future. Multiplicity cut to activate WEIGHT procedure - - double RadThick() const { return 1.5; } //<--TEMPORAR--> to be removed in future. Radiator thickness - double WinThick() const { return 0.5; } //<--TEMPORAR--> to be removed in future. Window thickness - double GapThick() const { return 8.0; } //<--TEMPORAR--> to be removed in future. Proximity gap thickness - double WinIdx() const { return 1.5787; } //<--TEMPORAR--> to be removed in future. Mean refractive index of WIN material (SiO2) - double GapIdx() const { return 1.0005; } //<--TEMPORAR--> to be removed in future. Mean refractive index of GAP material (CH4) - - static Int_t Stack(Int_t evt = -1, Int_t tid = -1); //Print stack info for event and tid - static Int_t StackCount(Int_t pid, Int_t evt); //Counts stack particles of given sort in given event - static void IdealPosition(Int_t iCh, TGeoHMatrix* m); //ideal position of given chamber + float distCut() const { return 1.0; } //<--TEMPORAR--> to be removed in future. Cut for MIP-TRACK residual + float qCut() const { return 100; } //<--TEMPORAR--> to be removed in future. Separation PHOTON-MIP charge + float multCut() const { return 30; } //<--TEMPORAR--> to be removed in future. Multiplicity cut to activate WEIGHT procedure + + double radThick() const { return 1.5; } //<--TEMPORAR--> to be removed in future. Radiator thickness + double winThick() const { return 0.5; } //<--TEMPORAR--> to be removed in future. Window thickness + double gapThick() const { return 8.0; } //<--TEMPORAR--> to be removed in future. Proximity gap thickness + double winIdx() const { return 1.5787; } //<--TEMPORAR--> to be removed in future. Mean refractive index of WIN material (SiO2) + double gapIdx() const { return 1.0005; } //<--TEMPORAR--> to be removed in future. Mean refractive index of GAP material (CH4) + + static Int_t stack(Int_t evt = -1, Int_t tid = -1); //Print stack info for event and tid + static Int_t stackCount(Int_t pid, Int_t evt); //Counts stack particles of given sort in given event + static void idealPosition(Int_t iCh, TGeoHMatrix* m); //ideal position of given chamber //trasformation methodes - void Lors2Mars(Int_t c, float x, float y, double* m, Int_t pl = kPc) const + void lors2Mars(Int_t c, double x, double y, double* m, Int_t pl = kPc) const { double z = 0; switch (pl) { @@ -195,20 +188,20 @@ class Param double l[3] = {x - mX, y - mY, z}; mM[c]->LocalToMaster(l, m); } - TVector3 Lors2Mars(Int_t c, float x, float y, Int_t pl = kPc) const + TVector3 lors2Mars(Int_t c, double x, double y, Int_t pl = kPc) const { double m[3]; - Lors2Mars(c, x, y, m, pl); + lors2Mars(c, x, y, m, pl); return TVector3(m); } //MRS->LRS - void Mars2Lors(Int_t c, double* m, float& x, float& y) const + void mars2Lors(Int_t c, double* m, double& x, double& y) const { double l[3]; mM[c]->MasterToLocal(m, l); x = l[0] + mX; y = l[1] + mY; } //MRS->LRS - void Mars2LorsVec(Int_t c, double* m, float& th, float& ph) const + void mars2LorsVec(Int_t c, double* m, double& th, double& ph) const { double l[3]; mM[c]->MasterToLocalVect(m, l); @@ -216,47 +209,47 @@ class Param th = TMath::ATan(pt / l[2]); ph = TMath::ATan2(l[1], l[0]); } - void Lors2MarsVec(Int_t c, double* m, double* l) const { mM[c]->LocalToMasterVect(m, l); } //LRS->MRS - TVector3 Norm(Int_t c) const + void lors2MarsVec(Int_t c, double* m, double* l) const { mM[c]->LocalToMasterVect(m, l); } //LRS->MRS + TVector3 norm(Int_t c) const { double n[3]; - Norm(c, n); + norm(c, n); return TVector3(n); } //norm - void Norm(Int_t c, double* n) const + void norm(Int_t c, double* n) const { double l[3] = {0, 0, 1}; mM[c]->LocalToMasterVect(l, n); } //norm - void Point(Int_t c, double* p, Int_t plane) const { Lors2Mars(c, 0, 0, p, plane); } //point of given chamber plane + void point(Int_t c, double* p, Int_t plane) const { lors2Mars(c, 0, 0, p, plane); } //point of given chamber plane - void SetTemp(double temp) { mTemp = temp; } //set actual temperature of the C6F14 - void SetEPhotMean(double ePhotMean) { mPhotEMean = ePhotMean; } //set mean photon energy + void setTemp(double temp) { mTemp = temp; } //set actual temperature of the C6F14 + void setEPhotMean(double ePhotMean) { mPhotEMean = ePhotMean; } //set mean photon energy - void SetRefIdx(double refRadIdx) { mRefIdx = refRadIdx; } //set running refractive index + void setRefIdx(double refRadIdx) { mRefIdx = refRadIdx; } //set running refractive index - void SetNSigmas(Int_t sigmas) { fgNSigmas = sigmas; } //set sigma cut - void SetThreshold(Int_t thres) { fgThreshold = thres; } //set sigma cut - void SetInstanceType(bool inst) { fgInstanceType = inst; } //kTRUE if from geomatry kFALSE if from ideal geometry + void setNSigmas(Int_t sigmas) { fgNSigmas = sigmas; } //set sigma cut + void setThreshold(Int_t thres) { fgThreshold = thres; } //set sigma cut + void setInstanceType(bool inst) { fgInstanceType = inst; } //kTRUE if from geomatry kFALSE if from ideal geometry //For PID - double SigLoc(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to cathode segmetation - double SigGeom(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to unknown photon origin - double SigCrom(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to unknonw photon energy - double Sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovPh); //photon candidate sigma^2 + double sigLoc(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to cathode segmetation + double sigGeom(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to unknown photon origin + double sigCrom(double trkTheta, double trkPhi, double ckovTh, double ckovPh, double beta); //error due to unknonw photon energy + double sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovPh); //photon candidate sigma^2 - static double SigmaCorrFact(Int_t iPart, double occupancy); //correction factor for theoretical resolution + static double sigmaCorrFact(Int_t iPart, double occupancy); //correction factor for theoretical resolution //Mathieson Getters - static double PitchAnodeCathode() { return fgkD; } - static double SqrtK3x() { return fgkSqrtK3x; } - static double K2x() { return fgkK2x; } - static double K1x() { return fgkK1x; } - static double K4x() { return fgkK4x; } - static double SqrtK3y() { return fgkSqrtK3y; } - static double K2y() { return fgkK2y; } - static double K1y() { return fgkK1y; } - static double K4y() { return fgkK4y; } + static double pitchAnodeCathode() { return fgkD; } + static double sqrtK3x() { return fgkSqrtK3x; } + static double k2x() { return fgkK2x; } + static double k1x() { return fgkK1x; } + static double k4x() { return fgkK4x; } + static double sqrtK3y() { return fgkSqrtK3y; } + static double k2y() { return fgkK2y; } + static double k1y() { return fgkK1y; } + static double k4y() { return fgkK4y; } // enum EPlaneId { kPc, kRad, diff --git a/Detectors/HMPID/base/src/Digit.cxx b/Detectors/HMPID/base/src/Digit.cxx deleted file mode 100644 index de4c9cea63ff4..0000000000000 --- a/Detectors/HMPID/base/src/Digit.cxx +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "HMPIDBase/Digit.h" -#include "HMPIDBase/Param.h" -#include "TRandom.h" -#include "TMath.h" - -using namespace o2::hmpid; - -ClassImp(o2::hmpid::Digit); - -float Digit::QdcTot(float e, float time, int pc, int px, int py, float& localX, float& localY) -{ - // Samples total charge associated to a hit - // Arguments: e- hit energy [GeV] for mip Eloss for photon Etot - // Returns: total QDC - float Q = 0; - if (time > 1.2e-6) { - Q = 0; - } - if (py < 0) { - return 0; - } else { - float y = Param::LorsY(pc, py); - localY = ((y - localY) > 0) ? y - 0.2 : y + 0.2; //shift to the nearest anod wire - - float x = (localX > 66.6) ? localX - 66.6 : localX; //sagita is for PC (0-64) and not for chamber - float qdcEle = 34.06311 + 0.2337070 * x + 5.807476e-3 * x * x - 2.956471e-04 * x * x * x + 2.310001e-06 * x * x * x * x; //reparametrised from DiMauro - - int iNele = int((e / 26e-9) * 0.8); - if (iNele < 1) { - iNele = 1; //number of electrons created by hit, if photon e=0 implies iNele=1 - } - for (Int_t i = 1; i <= iNele; i++) { - double rnd = gRandom->Rndm(); - if (rnd == 0) { - rnd = 1e-12; //1e-12 is a protection against 0 from rndm - } - Q -= qdcEle * TMath::Log(rnd); - } - } - return Q; -} diff --git a/Detectors/HMPID/base/src/Geo.cxx b/Detectors/HMPID/base/src/Geo.cxx new file mode 100644 index 0000000000000..ad8d66d425c80 --- /dev/null +++ b/Detectors/HMPID/base/src/Geo.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Geo.h +/// \author Antonio Franco - INFN Bari +/// \version 1.1 +/// \date 15/02/2021 + +#include "HMPIDBase/Geo.h" +#include "HMPIDBase/Param.h" +#include "TGeoManager.h" +#include "TMath.h" +#include "FairLogger.h" +#include "DetectorsBase/GeometryManager.h" + +ClassImp(o2::hmpid::Geo); + +using namespace o2::hmpid; + +//constexpr Bool_t Geo::FEAWITHMASKS[NSECTORS]; + +// ============= Geo Class implementation ======= + +/// Init : +void Geo::Init() +{ + LOG(INFO) << "hmpid::Geo: Initialization of HMPID parameters"; +} + diff --git a/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h b/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h index 179ba16791750..c01a2479c4725 100644 --- a/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h +++ b/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,9 +16,6 @@ #pragma link off all functions; #pragma link C++ class o2::hmpid::Param + ; -#pragma link C++ class o2::hmpid::Digit + ; -#pragma link C++ class vector < o2::hmpid::Digit> + ; -#pragma link C++ class o2::hmpid::HitType + ; -#pragma link C++ class vector < o2::hmpid::HitType> + ; +#pragma link C++ class o2::hmpid::Geo + ; #endif diff --git a/Detectors/HMPID/base/src/Param.cxx b/Detectors/HMPID/base/src/Param.cxx index 9358bc480e691..9696067801fd6 100644 --- a/Detectors/HMPID/base/src/Param.cxx +++ b/Detectors/HMPID/base/src/Param.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -89,7 +90,7 @@ Param::Param(bool noGeo) : mX(0), mY(0), mRefIdx(1.28947), mPhotEMean(6.675), mT } } */ - mRefIdx = MeanIdxRad(); //initialization of the running ref. index of freon + mRefIdx = meanIdxRad(); //initialization of the running ref. index of freon float dead = 2.6; // cm of the dead zones between PCs-> See 2CRC2099P1 @@ -141,8 +142,8 @@ Param::Param(bool noGeo) : mX(0), mY(0), mRefIdx(1.28947), mPhotEMean(6.675), mT fgkMaxPcY[4] = fgAllY; fgkMaxPcY[5] = fgkMaxPcY[4]; - mX = 0.5 * SizeAllX(); - mY = 0.5 * SizeAllY(); + mX = 0.5 * sizeAllX(); + mY = 0.5 * sizeAllY(); for (Int_t ich = kMinCh; ich <= kMaxCh; ich++) { for (Int_t padx = 0; padx < 160; padx++) { @@ -158,25 +159,25 @@ Param::Param(bool noGeo) : mX(0), mY(0), mRefIdx(1.28947), mPhotEMean(6.675), mT if (!pne) { //AliErrorClass(Form("The symbolic volume %s does not correspond to any physical entry!",Form("HMPID_%i",i))); mM[i] = new TGeoHMatrix; - IdealPosition(i, mM[i]); + idealPosition(i, mM[i]); } else { TGeoPhysicalNode* pnode = pne->GetPhysicalNode(); if (pnode) { mM[i] = new TGeoHMatrix(*(pnode->GetMatrix())); } else { mM[i] = new TGeoHMatrix; - IdealPosition(i, mM[i]); + idealPosition(i, mM[i]); } } } else { mM[i] = new TGeoHMatrix; - IdealPosition(i, mM[i]); + idealPosition(i, mM[i]); } } fgInstance = this; } //ctor //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::Print(Option_t* opt) const +void Param::print(Option_t* opt) const { // print some usefull (hopefully) info on some internal guts of HMPID parametrisation @@ -185,7 +186,7 @@ void Param::Print(Option_t* opt) const } } //Print() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::IdealPosition(Int_t iCh, TGeoHMatrix* pMatrix) +void Param::idealPosition(Int_t iCh, TGeoHMatrix* pMatrix) { // Construct ideal position matrix for a given chamber // Arguments: iCh- chamber ID; pMatrix- pointer to precreated unity matrix where to store the results @@ -275,7 +276,7 @@ void Param::IdealPosition(Int_t iCh, TGeoHMatrix* pMatrix) return iCnt; }*/ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::Sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovPh) +double Param::sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovPh) { // Analithical calculation of total error (as a sum of localization, geometrical and chromatic errors) // on Cerenkov angle for a given Cerenkov photon @@ -286,7 +287,7 @@ double Param::Sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovP // Returns: absolute error on Cerenkov angle, [radians] TVector3 v(-999, -999, -999); - double trkBeta = 1. / (TMath::Cos(ckovTh) * GetRefIdx()); + double trkBeta = 1. / (TMath::Cos(ckovTh) * getRefIdx()); if (trkBeta > 1) { trkBeta = 1; //protection against bad measured thetaCer @@ -295,14 +296,14 @@ double Param::Sigma2(double trkTheta, double trkPhi, double ckovTh, double ckovP trkBeta = 0.0001; // } - v.SetX(SigLoc(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); - v.SetY(SigGeom(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); - v.SetZ(SigCrom(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); + v.SetX(sigLoc(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); + v.SetY(sigGeom(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); + v.SetZ(sigCrom(trkTheta, trkPhi, ckovTh, ckovPh, trkBeta)); return v.Mag2(); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::SigLoc(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) +double Param::sigLoc(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) { // Analitical calculation of localization error (due to finite segmentation of PC) on Cerenkov angle for a given // Cerenkov photon @@ -323,14 +324,14 @@ double Param::SigLoc(double trkTheta, double trkPhi, double thetaC, double phiC, double tantheta = TMath::Tan(thetaC); double alpha = cost - tantheta * cosfd * sint; // formula (11) - double k = 1. - GetRefIdx() * GetRefIdx() + alpha * alpha / (betaM * betaM); // formula (after 8 in the text) + double k = 1. - getRefIdx() * getRefIdx() + alpha * alpha / (betaM * betaM); // formula (after 8 in the text) if (k < 0) { return 1e10; } double mu = sint * sinf + tantheta * (cost * cosfd * sinf + sinfd * cosf); // formula (10) double e = sint * cosf + tantheta * (cost * cosfd * cosf - sinfd * sinf); // formula (9) - double kk = betaM * TMath::Sqrt(k) / (GapThick() * alpha); // formula (6) and (7) + double kk = betaM * TMath::Sqrt(k) / (gapThick() * alpha); // formula (6) and (7) // formula (6) double dtdxc = kk * (k * (cosfd * cosf - cost * sinfd * sinf) - (alpha * mu / (betaM * betaM)) * sint * sinfd); // formula (7) pag.4 @@ -340,7 +341,7 @@ double Param::SigLoc(double trkTheta, double trkPhi, double thetaC, double phiC, return TMath::Sqrt(errX * errX * dtdxc * dtdxc + errY * errY * dtdyc * dtdyc); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::SigCrom(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) +double Param::sigCrom(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) { // Analitical calculation of chromatic error (due to lack of knowledge of Cerenkov photon energy) // on Cerenkov angle for a given Cerenkov photon @@ -358,7 +359,7 @@ double Param::SigCrom(double trkTheta, double trkPhi, double thetaC, double phiC double tantheta = TMath::Tan(thetaC); double alpha = cost - tantheta * cosfd * sint; // formula (11) - double dtdn = cost * GetRefIdx() * betaM * betaM / (alpha * tantheta); // formula (12) + double dtdn = cost * getRefIdx() * betaM * betaM / (alpha * tantheta); // formula (12) // double f = 0.00928*(7.75-5.635)/TMath::Sqrt(12.); double f = 0.0172 * (7.75 - 5.635) / TMath::Sqrt(24.); @@ -366,7 +367,7 @@ double Param::SigCrom(double trkTheta, double trkPhi, double thetaC, double phiC return f * dtdn; } //SigCrom() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::SigGeom(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) +double Param::sigGeom(double trkTheta, double trkPhi, double thetaC, double phiC, double betaM) { // Analitical calculation of geometric error (due to lack of knowledge of creation point in radiator) // on Cerenkov angle for a given Cerenkov photon @@ -387,25 +388,25 @@ double Param::SigGeom(double trkTheta, double trkPhi, double thetaC, double phiC double alpha = cost - tantheta * cosfd * sint; // formula (11) - double k = 1. - GetRefIdx() * GetRefIdx() + alpha * alpha / (betaM * betaM); // formula (after 8 in the text) + double k = 1. - getRefIdx() * getRefIdx() + alpha * alpha / (betaM * betaM); // formula (after 8 in the text) if (k < 0) { return 1e10; } - double eTr = 0.5 * RadThick() * betaM * TMath::Sqrt(k) / (GapThick() * alpha); // formula (14) + double eTr = 0.5 * radThick() * betaM * TMath::Sqrt(k) / (gapThick() * alpha); // formula (14) double lambda = (1. - sint * sinf) * (1. + sint * sinf); // formula (15) double c1 = 1. / (1. + eTr * k / (alpha * alpha * costheta * costheta)); // formula (13.a) - double c2 = betaM * TMath::Power(k, 1.5) * tantheta * lambda / (GapThick() * alpha * alpha); // formula (13.b) + double c2 = betaM * TMath::Power(k, 1.5) * tantheta * lambda / (gapThick() * alpha * alpha); // formula (13.b) double c3 = (1. + eTr * k * betaM * betaM) / ((1 + eTr) * alpha * alpha); // formula (13.c) - double c4 = TMath::Sqrt(k) * tantheta * (1 - lambda) / (GapThick() * betaM); // formula (13.d) + double c4 = TMath::Sqrt(k) * tantheta * (1 - lambda) / (gapThick() * betaM); // formula (13.d) double dtdT = c1 * (c2 + c3 * c4); - double trErr = RadThick() / (TMath::Sqrt(12.) * cost); + double trErr = radThick() / (TMath::Sqrt(12.) * cost); return trErr * dtdT; } //SigGeom() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::SigmaCorrFact(Int_t iPart, double occupancy) +double Param::sigmaCorrFact(Int_t iPart, double occupancy) { double corr = 1.0; @@ -430,7 +431,7 @@ double Param::SigmaCorrFact(Int_t iPart, double occupancy) return corr; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Param* Param::Instance() +Param* Param::instance() { // Return pointer to the AliHMPIDParam singleton. // Arguments: none @@ -442,7 +443,7 @@ Param* Param::Instance() } //Instance() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Param* Param::InstanceNoGeo() +Param* Param::instanceNoGeo() { // Return pointer to the AliHMPIDParam singleton without the geometry.root. // Arguments: none @@ -453,7 +454,7 @@ Param* Param::InstanceNoGeo() return fgInstance; } //Instance() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -bool Param::IsInDead(float x, float y) +bool Param::isInDead(float x, float y) { // Check is the current point is outside of sensitive area or in dead zones // Arguments: x,y -position @@ -467,7 +468,7 @@ bool Param::IsInDead(float x, float y) return kTRUE; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -bool Param::IsDeadPad(Int_t padx, Int_t pady, Int_t ch) +bool Param::isDeadPad(Int_t padx, Int_t pady, Int_t ch) { // Check is the current pad is active or not // Arguments: padx,pady pad integer coord @@ -480,7 +481,7 @@ bool Param::IsDeadPad(Int_t padx, Int_t pady, Int_t ch) return kTRUE; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::Lors2Pad(float x, float y, Int_t& pc, Int_t& px, Int_t& py) +void Param::lors2Pad(float x, float y, Int_t& pc, Int_t& px, Int_t& py) { // Check the pad of given position // Arguments: x,y- position [cm] in LORS; pc,px,py- pad where to store the result @@ -488,32 +489,32 @@ void Param::Lors2Pad(float x, float y, Int_t& pc, Int_t& px, Int_t& py) pc = px = py = -1; if (x > fgkMinPcX[0] && x < fgkMaxPcX[0]) { pc = 0; - px = Int_t(x / SizePadX()); + px = Int_t(x / sizePadX()); } //PC 0 or 2 or 4 else if (x > fgkMinPcX[1] && x < fgkMaxPcX[1]) { pc = 1; - px = Int_t((x - fgkMinPcX[1]) / SizePadX()); + px = Int_t((x - fgkMinPcX[1]) / sizePadX()); } //PC 1 or 3 or 5 else { return; } if (y > fgkMinPcY[0] && y < fgkMaxPcY[0]) { - py = Int_t(y / SizePadY()); + py = Int_t(y / sizePadY()); } //PC 0 or 1 else if (y > fgkMinPcY[2] && y < fgkMaxPcY[2]) { pc += 2; - py = Int_t((y - fgkMinPcY[2]) / SizePadY()); + py = Int_t((y - fgkMinPcY[2]) / sizePadY()); } //PC 2 or 3 else if (y > fgkMinPcY[4] && y < fgkMaxPcY[4]) { pc += 4; - py = Int_t((y - fgkMinPcY[4]) / SizePadY()); + py = Int_t((y - fgkMinPcY[4]) / sizePadY()); } //PC 4 or 5 else { return; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Int_t Param::InHVSector(float y) +Int_t Param::inHVSector(float y) { //Calculate the HV sector corresponding to the cluster position //Arguments: y @@ -521,7 +522,7 @@ Int_t Param::InHVSector(float y) Int_t hvsec = -1; Int_t pc, px, py; - Lors2Pad(1., y, pc, px, py); + lors2Pad(1., y, pc, px, py); if (py == -1) { return hvsec; } @@ -531,25 +532,25 @@ Int_t Param::InHVSector(float y) return hvsec; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -double Param::FindTemp(double tLow, double tHigh, double y) +double Param::findTemp(double tLow, double tHigh, double y) { // Model for gradient in temperature - double yRad = HinRad(y); //height in a given radiator + double yRad = hinRad(y); //height in a given radiator if (tHigh < tLow) { tHigh = tLow; //if Tout < Tin consider just Tin as reference... } if (yRad < 0) { yRad = 0; //protection against fake y values } - if (yRad > SizePcY()) { - yRad = SizePcY(); //protection against fake y values + if (yRad > sizePcY()) { + yRad = sizePcY(); //protection against fake y values } - double gradT = (tHigh - tLow) / SizePcY(); // linear gradient + double gradT = (tHigh - tLow) / sizePcY(); // linear gradient return gradT * yRad + tLow; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::SetChStatus(Int_t ch, bool status) +void Param::setChStatus(Int_t ch, bool status) { //Set a chamber on or off depending on the status //Arguments: ch=chamber,status=kTRUE = active, kFALSE=off @@ -561,7 +562,7 @@ void Param::SetChStatus(Int_t ch, bool status) } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::SetSectStatus(Int_t ch, Int_t sect, bool status) +void Param::setSectStatus(Int_t ch, Int_t sect, bool status) { //Set a given sector sect for a chamber ch on or off depending on the status //Sector=0,5 (6 sectors) @@ -579,7 +580,7 @@ void Param::SetSectStatus(Int_t ch, Int_t sect, bool status) } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::SetPcStatus(Int_t ch, Int_t pc, bool status) +void Param::setPcStatus(Int_t ch, Int_t pc, bool status) { //Set a given PC pc for a chamber ch on or off depending on the status //Arguments: ch=chamber,pc=PC,status: kTRUE = active, kFALSE=off @@ -599,7 +600,7 @@ void Param::SetPcStatus(Int_t ch, Int_t pc, bool status) } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::PrintChStatus(Int_t ch) +void Param::printChStatus(Int_t ch) { //Print the map status of a chamber on or off depending on the status //Arguments: ch=chamber @@ -621,14 +622,14 @@ void Param::PrintChStatus(Int_t ch) printf("\n"); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -void Param::SetGeomAccept() +void Param::setGeomAccept() { //Set the real acceptance of the modules, due to ineficciency or hardware problems (up tp 1/6/2010) //Arguments: none //Returns: none - SetSectStatus(0, 3, kFALSE); - SetSectStatus(4, 0, kFALSE); - SetSectStatus(5, 1, kFALSE); - SetSectStatus(6, 2, kFALSE); - SetSectStatus(6, 3, kFALSE); + setSectStatus(0, 3, kFALSE); + setSectStatus(4, 0, kFALSE); + setSectStatus(5, 1, kFALSE); + setSectStatus(6, 2, kFALSE); + setSectStatus(6, 3, kFALSE); } diff --git a/Detectors/HMPID/reconstruction/CMakeLists.txt b/Detectors/HMPID/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..c56e087ba555d --- /dev/null +++ b/Detectors/HMPID/reconstruction/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(HMPIDReconstruction + SOURCES src/Clusterer.cxx + src/HmpidDecoder2.cxx + src/HmpidEquipment.cxx + src/CTFHelper.cxx + src/CTFCoder.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDBase + O2::DataFormatsHMP + O2::HMPIDSimulation) + +o2_target_root_dictionary(HMPIDReconstruction + HEADERS include/HMPIDReconstruction/Clusterer.h + include/HMPIDReconstruction/HmpidDecoder2.h + include/HMPIDReconstruction/HmpidEquipment.h) diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..0de11428c6513 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of HMPID data + +#ifndef O2_HMPID_CTFCODER_H +#define O2_HMPID_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsHMP/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "HMPIDReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace hmpid +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::HMP) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const Trigger>& trigData, const gsl::span<const Digit>& digData); + + /// entropy decode data from buffer with CTF + template <typename VTRG, typename VDIG> + void decode(const CTF::base& ec, VTRG& trigVec, VDIG& digVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<Trigger>& trigVec, std::vector<Digit>& digVec); +}; + +/// entropy-encode digits and to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const Trigger>& trigData, const gsl::span<const Digit>& digData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_entriesDig + MD::EENCODE, // BLC_ChID + MD::EENCODE, // BLC_Q + MD::EENCODE, // BLC_Ph + MD::EENCODE, // BLC_X + MD::EENCODE // BLC_Y + }; + + CTFHelper helper(trigData, digData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODEHMP(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODEHMP(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODEHMP(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + ENCODEHMP(helper.begin_entriesDig(), helper.end_entriesDig(), CTF::BLC_entriesDig, 0); + + ENCODEHMP(helper.begin_ChID(), helper.end_ChID(), CTF::BLC_ChID, 0); + ENCODEHMP(helper.begin_Q(), helper.end_Q(), CTF::BLC_Q, 0); + ENCODEHMP(helper.begin_Ph(), helper.end_Ph(), CTF::BLC_Ph, 0); + ENCODEHMP(helper.begin_X(), helper.end_X(), CTF::BLC_X, 0); + ENCODEHMP(helper.begin_Y(), helper.end_Y(), CTF::BLC_Y, 0); + + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded data to digits +template <typename VTRG, typename VDIG> +void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VDIG& digVec) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcInc, q; + std::vector<uint32_t> orbitInc, entriesDig; + std::vector<uint8_t> chID, ph, x, y; + +#define DECODEHMP(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODEHMP(bcInc, CTF::BLC_bcIncTrig); + DECODEHMP(orbitInc, CTF::BLC_orbitIncTrig); + DECODEHMP(entriesDig, CTF::BLC_entriesDig); + + DECODEHMP(chID, CTF::BLC_ChID); + DECODEHMP(q, CTF::BLC_Q); + DECODEHMP(ph, CTF::BLC_Ph); + DECODEHMP(x, CTF::BLC_X); + DECODEHMP(y, CTF::BLC_Y); + // clang-format on + // + trigVec.clear(); + digVec.clear(); + trigVec.reserve(header.nTriggers); + digVec.reserve(header.nDigits); + + uint32_t digCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + + uint32_t firstEntryDig = digVec.size(); + int8_t chid = 0; + for (uint32_t id = 0; id < entriesDig[itrig]; id++) { + chid += chID[digCount]; // 1st digit of trigger was encoded with abs ChID, then increments + auto& dig = digVec.emplace_back(chid, ph[digCount], x[digCount], y[digCount], q[digCount]); + digCount++; + } + + trigVec.emplace_back(ir, firstEntryDig, entriesDig[itrig]); + } + assert(digCount == header.nDigits); +} + +} // namespace hmpid +} // namespace o2 + +#endif // O2_HMP_CTFCODER_H diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFHelper.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..21a816dd37675 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFHelper.h @@ -0,0 +1,227 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for HMPID CTF creation + +#ifndef O2_HMPID_CTF_HELPER_H +#define O2_HMPID_CTF_HELPER_H + +#include "DataFormatsHMP/CTF.h" +#include "DataFormatsHMP/Trigger.h" +#include "DataFormatsHMP/Digit.h" +#include <gsl/span> + +namespace o2 +{ +namespace hmpid +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const Trigger>& trgRec, + const gsl::span<const Digit>& digData) + : mTrigRec(trgRec), mDigData(digData), mDigStart(digData.size()) + { + // flag start of new trigger for digits + for (const auto& trg : mTrigRec) { + if (trg.getNumberOfObjects()) { + mDigStart[trg.getFirstEntry()] = true; + } + } + } + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigRec.size()), uint32_t(mDigData.size()), 0, 0}; + if (mTrigRec.size()) { + h.firstOrbit = mTrigRec[0].getOrbit(); + h.firstBC = mTrigRec[0].getBc(); + } + return h; + } + + size_t getSize() const { return mTrigRec.size() * sizeof(Trigger) + mDigData.size() * sizeof(Digit); } + + //>>> =========================== ITERATORS ======================================== + template <typename I, typename D, typename T, int M = 1> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, Trigger, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, Trigger, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].getOrbit() == mData[mIndex - 1].getOrbit()) { + return mData[mIndex].getBc() - mData[mIndex - 1].getBc(); + } else { + return mData[mIndex].getBc(); + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, Trigger, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, Trigger, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].getOrbit() - mData[mIndex - 1].getOrbit() : 0; } + }; + + //_______________________________________________ + // Number of digits for trigger + class Iter_entriesDig : public _Iter<Iter_entriesDig, Trigger, uint32_t> + { + public: + using _Iter<Iter_entriesDig, Trigger, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNumberOfObjects(); } + }; + + //_______________________________________________ + class Iter_ChID : public _Iter<Iter_ChID, Digit, uint8_t> + { + private: + const std::vector<bool>* mTrigStart{nullptr}; + + public: + using _Iter<Iter_ChID, Digit, uint8_t>::_Iter; + Iter_ChID(const std::vector<bool>* ts, const gsl::span<const Digit>& data, bool end) : mTrigStart(ts), _Iter(data, end) {} + Iter_ChID() = default; + + // assume sorting in ChID: for the 1st digit of the trigger return the abs ChID, for the following ones: difference to previous ChID + value_type operator*() const + { + return (*mTrigStart)[mIndex] ? mData[mIndex].getCh() : mData[mIndex].getCh() - mData[mIndex - 1].getCh(); + } + }; + + //_______________________________________________ + class Iter_Q : public _Iter<Iter_Q, Digit, uint16_t> + { + public: + using _Iter<Iter_Q, Digit, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getQ(); } + }; + + //_______________________________________________ + class Iter_Ph : public _Iter<Iter_Ph, Digit, uint8_t> + { + public: + using _Iter<Iter_Ph, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPh(); } + }; + + //_______________________________________________ + class Iter_X : public _Iter<Iter_X, Digit, uint8_t> + { + public: + using _Iter<Iter_X, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getX(); } + }; + + //_______________________________________________ + class Iter_Y : public _Iter<Iter_Y, Digit, uint8_t> + { + public: + using _Iter<Iter_Y, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getY(); } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mTrigRec, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mTrigRec, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigRec, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigRec, true); } + + Iter_entriesDig begin_entriesDig() const { return Iter_entriesDig(mTrigRec, false); } + Iter_entriesDig end_entriesDig() const { return Iter_entriesDig(mTrigRec, true); } + + Iter_ChID begin_ChID() const { return Iter_ChID(&mDigStart, mDigData, false); } + Iter_ChID end_ChID() const { return Iter_ChID(&mDigStart, mDigData, true); } + + Iter_Q begin_Q() const { return Iter_Q(mDigData, false); } + Iter_Q end_Q() const { return Iter_Q(mDigData, true); } + + Iter_Ph begin_Ph() const { return Iter_Ph(mDigData, false); } + Iter_Ph end_Ph() const { return Iter_Ph(mDigData, true); } + + Iter_X begin_X() const { return Iter_X(mDigData, false); } + Iter_X end_X() const { return Iter_X(mDigData, true); } + + Iter_Y begin_Y() const { return Iter_Y(mDigData, false); } + Iter_Y end_Y() const { return Iter_Y(mDigData, true); } + + private: + const gsl::span<const o2::hmpid::Trigger> mTrigRec; + const gsl::span<const o2::hmpid::Digit> mDigData; + std::vector<bool> mDigStart; +}; + +} // namespace hmpid +} // namespace o2 + +#endif diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/Clusterer.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/Clusterer.h new file mode 100644 index 0000000000000..15d738a3363bf --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/Clusterer.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Clusterer.h +/// \brief Definition of the HMPID cluster finder +#ifndef ALICEO2_HMPID_CLUSTERER_H +#define ALICEO2_HMPID_CLUSTERER_H + +#include <utility> +#include <vector> +#include "DataFormatsHMP/Cluster.h" +#include "DataFormatsHMP/Digit.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ + +namespace hmpid +{ +class Clusterer +{ + using MCLabelContainer = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; + using Cluster = o2::hmpid::Cluster; + using Digit = o2::hmpid::Digit; + + public: + Clusterer() = default; + ~Clusterer() = default; + + Clusterer(const Clusterer&) = delete; + Clusterer& operator=(const Clusterer&) = delete; + + void process(std::vector<Digit> const& digits, std::vector<o2::hmpid::Cluster>& clusters, MCLabelContainer const* digitMCTruth); + + void setMCTruthContainer(o2::dataformats::MCTruthContainer<o2::MCCompLabel>* truth) { mClsLabels = truth; } + + private: + //void processChamber(std::vector<Cluster>& clusters, MCLabelContainer const* digitMCTruth); + //void fetchMCLabels(const Digit* dig, std::array<Label, Cluster::maxLabels>& labels, int& nfilled) const; + + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mClsLabels = nullptr; // Cluster MC labels + + Digit* mContributingDigit[6]; //! array of digits contributing to the cluster; this will not be stored, it is temporary to build the final cluster + int mNumberOfContributingDigits; //! number of digits contributing to the cluster; this will not be stored, it is temporary to build the final cluster + void addContributingDigit(Digit* dig); + void buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth); +}; + +} // namespace hmpid +} // namespace o2 +#endif /* ALICEO2_TOF_CLUSTERER_H */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h new file mode 100644 index 0000000000000..e92e8375ad0d0 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecodeRawFile.h +/// \author Antonio Franco - INFN Bari +/// \brief Derived Class for decoding Raw Data File stream +/// \version 1.0 +/// \date 24 set 2020 + +#ifndef COMMON_HMPIDDECODERAWFILE_H_ +#define COMMON_HMPIDDECODERAWFILE_H_ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <unistd.h> + +#include "HMPIDReconstruction/HmpidDecoder.h" + +#define MAXFILENAMEBUFFER 512 +#define MAXRAWFILEBUFFER RAWBLOCKDIMENSION_W * 4 + 8 + +namespace o2 +{ +namespace hmpid +{ + +class HmpidDecodeRawFile : public HmpidDecoder +{ + public: + HmpidDecodeRawFile(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); + HmpidDecodeRawFile(int numOfEquipments); + ~HmpidDecodeRawFile(); + + bool setUpStream(void* InpuFileName, long Size); + + private: + bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size); + bool getHeaderFromStream(uint32_t** streamPtr); + bool getWordFromStream(uint32_t* word); + int fileExists(char* filewithpath); + void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge); + + private: + FILE* fh; + char mInputFile[MAXFILENAMEBUFFER]; + uint32_t mFileBuffer[MAXRAWFILEBUFFER]; +}; + +} // namespace hmpid +} // namespace o2 +#endif /* COMMON_HMPIDDECODERAWFILE_H_ */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h new file mode 100644 index 0000000000000..d5d82d0f238e9 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecodeRawMem.h +/// \author Antonio Franco - INFN Bari +/// \brief Derived Class for decoding Raw Data Memory stream +/// \version 1.0 +/// \date 24 set 2020 + +#ifndef COMMON_HMPIDDECODERAWMEM_H_ +#define COMMON_HMPIDDECODERAWMEM_H_ + +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <unistd.h> +#include <cstring> +#include <vector> + +#include "DataFormatsHMP/Digit.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecoder.h" + +using namespace o2; + +namespace o2 +{ +namespace hmpid +{ + +class HmpidDecodeRawMem : public HmpidDecoder +{ + public: + HmpidDecodeRawMem(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); + HmpidDecodeRawMem(int numOfEquipments); + ~HmpidDecodeRawMem(); + + bool setUpStream(void* Buffer, long BufferLen) override; + + private: + bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size) override; + bool getHeaderFromStream(uint32_t** streamPtr) override; + bool getWordFromStream(uint32_t* word) override; + void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) override; + + private: +}; + +class HmpidDecodeRawDigit : public HmpidDecodeRawMem +{ + public: + HmpidDecodeRawDigit(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); + HmpidDecodeRawDigit(int numOfEquipments); + ~HmpidDecodeRawDigit(); + + std::vector<o2::hmpid::Digit> mDigits; + + private: + void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) override; +}; + +} // namespace hmpid +} // namespace o2 +#endif /* COMMON_HMPIDDECODERAWFILE_H_ */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder.h new file mode 100644 index 0000000000000..be4b1d427b3fd --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder.h @@ -0,0 +1,175 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecoder.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to decode HMPID Raw Data stream +/// + +#ifndef COMMON_HMPIDDECODER_H_ +#define COMMON_HMPIDDECODER_H_ + +#include <cstdio> +#include <cstdint> +#include <iostream> +#include <cstring> + +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" + +#include "HMPIDReconstruction/HmpidEquipment.h" + +#define MAXDESCRIPTIONLENGHT 50 + +// ---- RDH 6 standard dimension ------- +#define RAWBLOCKDIMENSION_W 2048 +#define HEADERDIMENSION_W 16 +#define PAYLOADDIMENSION_W 2032 + +// ---- Defines for the decoding +#define WTYPE_ROW 1 +#define WTYPE_EOS 2 +#define WTYPE_PAD 3 +#define WTYPE_EOE 4 +#define WTYPE_NONE 0 + +using namespace o2; + +// Hmpid Equipment class +namespace o2 +{ + +namespace hmpid +{ + +class HmpidDecoder +{ + + // Members + public: + int mVerbose; + HmpidEquipment* mTheEquipments[Geo::MAXEQUIPMENTS]; + int mNumberOfEquipments; + + static char sErrorDescription[MAXERRORS][MAXDESCRIPTIONLENGHT]; + static char sHmpidErrorDescription[MAXHMPIDERRORS][MAXDESCRIPTIONLENGHT]; + + public: + uint64_t mHeEvent; + int mHeBusy; + int mNumberWordToRead; + int mPayloadTail; + + int mHeFEEID; + int mHeSize; + int mHeVer; + int mHePrior; + int mHeStop; + int mHePages; + int mEquipment; + + int mHeOffsetNewPack; + int mHeMemorySize; + + int mHeDetectorID; + int mHeDW; + int mHeCruID; + int mHePackNum; + int mHePAR; + + int mHePageNum; + int mHeLinkNum; + int mHeFirmwareVersion; + int mHeHmpidError; + int mHeBCDI; + int mHeORBIT; + int mHeTType; + + uint32_t* mActualStreamPtr; + uint32_t* mEndStreamPtr; + uint32_t* mStartStreamPtr; + int mRDHSize; + int mRDHAcceptedVersion; + + // Methods + public: + HmpidDecoder(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); + HmpidDecoder(int numOfEquipments); + ~HmpidDecoder(); + + void init(); + virtual bool setUpStream(void* Buffer, long BufferLen) = 0; + void setVerbosity(int Level) + { + mVerbose = Level; + }; + int getVerbosity() + { + return (mVerbose); + }; + + int getNumberOfEquipments() + { + return (mNumberOfEquipments); + }; + int getEquipmentIndex(int EquipmentId); + int getEquipmentIndex(int CruID, int LinkId); + int getEquipmentID(int CruId, int LinkId); + + void decodePage(uint32_t** streamBuffer); + void decodePageFast(uint32_t** streamBuf); + bool decodeBuffer(); + bool decodeBufferFast(); + + uint16_t getChannelSamples(int Equipment, int Column, int Dilogic, int Channel); + double getChannelSum(int Equipment, int Column, int Dilogic, int Channel); + double getChannelSquare(int Equipment, int Column, int Dilogic, int Channel); + uint16_t getPadSamples(int Module, int Row, int Column); + double getPadSum(int Module, int Row, int Column); + double getPadSquares(int Module, int Row, int Column); + + void dumpErrors(int Equipment); + void dumpPads(int Equipment, int type = 0); + void writeSummaryFile(char* summaryFileName); + + float getAverageEventSize(int Equipment); + float getAverageBusyTime(int Equipment); + + o2::InteractionRecord mIntReco; + + protected: + int checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4); + bool isRowMarker(uint32_t wp, int* Err, int* rowSize, int* mark); + bool isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg, int* mark); + bool isEoEmarker(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Eoesize); + + public: + bool decodeHmpidError(int ErrorField, char* outbuf); + void dumpHmpidError(int ErrorField); + bool isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge); + int decodeHeader(uint32_t* streamPtrAdr, int* EquipIndex); + HmpidEquipment* evaluateHeaderContents(int EquipmentIndex); + void updateStatistics(HmpidEquipment* eq); + + protected: + virtual void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) = 0; + virtual bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size) = 0; + virtual bool getHeaderFromStream(uint32_t** streamPtr) = 0; + virtual bool getWordFromStream(uint32_t* word) = 0; + uint32_t* getActualStreamPtr() + { + return (mActualStreamPtr); + }; +}; +} // namespace hmpid +} // namespace o2 +#endif /* COMMON_HMPIDDECODER_H_ */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder2.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder2.h new file mode 100644 index 0000000000000..6d49663c9e368 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecoder2.h @@ -0,0 +1,182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecoder.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to decode HMPID Raw Data stream +/// + +#ifndef COMMON_HMPIDDECODER2_H_ +#define COMMON_HMPIDDECODER2_H_ + +#include <cstdio> +#include <cstdint> +#include <iostream> +#include <cstring> + +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileReader.h" + +#include "DataFormatsHMP/Digit.h" + +#include "FairLogger.h" + +#include "HMPIDReconstruction/HmpidEquipment.h" + +#define MAXDESCRIPTIONLENGHT 50 + +// ---- RDH 6 standard dimension ------- +#define RAWBLOCKDIMENSION_W 2048 +#define HEADERDIMENSION_W 16 +#define PAYLOADDIMENSION_W 2032 + +// ---- Defines for the decoding +#define WTYPE_ROW 1 +#define WTYPE_EOS 2 +#define WTYPE_PAD 3 +#define WTYPE_EOE 4 +#define WTYPE_NONE 0 + +using namespace o2::raw; + +// Hmpid Equipment class +namespace o2 +{ + +namespace hmpid +{ + +class HmpidDecoder2 +{ + + // Members + public: + int mVerbose; + HmpidEquipment* mTheEquipments[Geo::MAXEQUIPMENTS]; + int mNumberOfEquipments; + + static char sErrorDescription[MAXERRORS][MAXDESCRIPTIONLENGHT]; + static char sHmpidErrorDescription[MAXHMPIDERRORS][MAXDESCRIPTIONLENGHT]; + + public: + uint64_t mHeEvent; + int mHeBusy; + int mNumberWordToRead; + int mPayloadTail; + + int mHeFEEID; + int mHeSize; + int mHeVer; + int mHePrior; + int mHeStop; + int mHePages; + int mEquipment; + + int mHeOffsetNewPack; + int mHeMemorySize; + + int mHeDetectorID; + int mHeDW; + int mHeCruID; + int mHePackNum; + int mHePAR; + + int mHePageNum; + int mHeLinkNum; + int mHeFirmwareVersion; + int mHeHmpidError; + int mHeBCDI; + int mHeORBIT; + int mHeTType; + + uint32_t* mActualStreamPtr; + uint32_t* mEndStreamPtr; + uint32_t* mStartStreamPtr; + int mRDHSize; + int mRDHAcceptedVersion; + + o2::InteractionRecord mIntReco; + std::vector<o2::hmpid::Digit> mDigits; + + // Methods + public: + HmpidDecoder2(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); + HmpidDecoder2(int numOfEquipments); + ~HmpidDecoder2(); + + void init(); + bool setUpStream(void* Buffer, long BufferLen); + void setVerbosity(int Level) + { + mVerbose = Level; + }; + int getVerbosity() + { + return (mVerbose); + }; + + int getNumberOfEquipments() + { + return (mNumberOfEquipments); + }; + int getEquipmentIndex(int EquipmentId); + int getEquipmentIndex(int CruID, int LinkId); + int getEquipmentID(int CruId, int LinkId); + + void decodePage(uint32_t** streamBuffer); + void decodePageFast(uint32_t** streamBuf); + bool decodeBuffer(); + bool decodeBufferFast(); + + uint16_t getChannelSamples(int Equipment, int Column, int Dilogic, int Channel); + double getChannelSum(int Equipment, int Column, int Dilogic, int Channel); + double getChannelSquare(int Equipment, int Column, int Dilogic, int Channel); + uint16_t getPadSamples(int Module, int Row, int Column); + double getPadSum(int Module, int Row, int Column); + double getPadSquares(int Module, int Row, int Column); + + void dumpErrors(int Equipment); + void dumpPads(int Equipment, int type = 0); + void writeSummaryFile(char* summaryFileName); + + float getAverageEventSize(int Equipment); + float getAverageBusyTime(int Equipment); + + protected: + int checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4); + bool isRowMarker(uint32_t wp, int* Err, int* rowSize, int* mark); + bool isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg, int* mark); + bool isEoEmarker(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Eoesize); + void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge); + + public: + bool decodeHmpidError(int ErrorField, char* outbuf); + void dumpHmpidError(int ErrorField); + bool isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge); + int decodeHeader(uint32_t* streamPtrAdr, int* EquipIndex); + HmpidEquipment* evaluateHeaderContents(int EquipmentIndex); + void updateStatistics(HmpidEquipment* eq); + + protected: + bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size); + bool getHeaderFromStream(uint32_t** streamPtr); + bool getWordFromStream(uint32_t* word); + uint32_t* getActualStreamPtr() + { + return (mActualStreamPtr); + }; +}; +} // namespace hmpid +} // namespace o2 +#endif /* COMMON_HMPIDDECODER2ß_H_ */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidEquipment.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidEquipment.h new file mode 100644 index 0000000000000..df7c62a169840 --- /dev/null +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidEquipment.h @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidEquipments.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to describe HMPID Equipment for the decoding of RawData stream +/// \version 1.0 +/// \date 24 set 2020 + +#ifndef COMMON_HMPIDEQUIPMENT_H_ +#define COMMON_HMPIDEQUIPMENT_H_ + +#include <cstdio> +#include <cstdint> +#include <iostream> + +#include "HMPIDBase/Geo.h" + +namespace o2 +{ +namespace hmpid +{ + +const int MAXERRORS = 13; +const int MAXHMPIDERRORS = 6; + +const int ERR_NOTKNOWN = 0; +const int ERR_ROWMARKEMPTY = 1; +const int ERR_DUPLICATEPAD = 2; +const int ERR_ROWMARKWRONG = 3; +const int ERR_ROWMARKLOST = 4; +const int ERR_ROWMARKERROR = 5; +const int ERR_LOSTEOEMARK = 6; +const int ERR_DOUBLEEOEMARK = 7; +const int ERR_WRONGSIZEINEOE = 8; +const int ERR_DOUBLEMARKWORD = 9; +const int ERR_WRONGSIZESEGMENTMARK = 10; +const int ERR_LOSTEOSMARK = 11; +const int ERR_HMPID = 12; + +// ---- HMPID error def ------- +const int TH_FILENOTEXISTS = 9; +const int TH_OPENFILE = 8; +const int TH_CREATEFILE = 7; +const int TH_READFILE = 6; +const int TH_WRITEFILE = 5; +const int TH_WRONGEQUIPINDEX = 19; +const int TH_WRONGHEADER = 15; +const int TH_WRONGFILELEN = 14; +const int TH_NULLBUFFERPOINTER = 13; +const int TH_BUFFEREMPTY = 12; +const int TH_WRONGBUFFERDIM = 11; + +const uint64_t OUTRANGEEVENTNUMBER = 0x1FFFFFFFFFFF; + +class HmpidEquipment +{ + + private: + uint32_t mEquipmentId; + uint32_t mCruId; + uint32_t mLinkId; + + public: + uint32_t mPadSamples[Geo::N_COLUMNS][Geo::N_DILOGICS][Geo::N_CHANNELS]; + double mPadSum[Geo::N_COLUMNS][Geo::N_DILOGICS][Geo::N_CHANNELS]; + double mPadSquares[Geo::N_COLUMNS][Geo::N_DILOGICS][Geo::N_CHANNELS]; + + int mErrors[MAXERRORS]; + + int mWillBeRowMarker; + int mWillBeSegmentMarker; + int mWillBeEoE; + int mWillBePad; + int mRowSize; + int mSegment; + int mColumnCounter; + int mWordsPerRowCounter; + int mWordsPerSegCounter; + int mWordsPerDilogicCounter; + + int mErrorsCounter; + int mErrorPadsPerEvent; + + uint64_t mEventNumber; + int mNumberOfEvents; + float mEventSizeAverage; + int mEventSize; + + int mSampleNumber; + float mPadsPerEventAverage; + + float mBusyTimeValue; + float mBusyTimeAverage; + int mBusyTimeSamples; + int mNumberOfEmptyEvents; + int mNumberOfWrongEvents; + int mTotalPads; + int mTotalErrors; + + public: + HmpidEquipment(int Equipment, int Cru, int Link); + ~HmpidEquipment(); + + int getEquipmentId() + { + return (mEquipmentId); + }; + int getEquipmentId(int cru, int link); + + void init(); + void resetPadMap(); + void resetErrors(); + void setError(int ErrType); + void setPad(int col, int dil, int cha, uint16_t charge); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* COMMON_HMPIDEQUIPMENT_H_ */ diff --git a/Detectors/HMPID/reconstruction/src/CTFCoder.cxx b/Detectors/HMPID/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..8f3a67b6d315a --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of HMP data + +#include "HMPIDReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::hmpid; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<Trigger>& trigVec, std::vector<Digit>& digVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, trigVec, digVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc, HCIDTrk, q; + uint32_t orbitInc, entriesDig; + uint8_t chID, ph, x, y; + +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(entriesDig, CTF::BLC_entriesDig); + + MAKECODER(chID, CTF::BLC_ChID); + MAKECODER(q, CTF::BLC_Q); + MAKECODER(ph, CTF::BLC_Ph); + MAKECODER(x, CTF::BLC_X); + MAKECODER(y, CTF::BLC_Y); + // clang-format on +} diff --git a/Detectors/HMPID/reconstruction/src/CTFHelper.cxx b/Detectors/HMPID/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..db1e5a454bb1a --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for HMPID CTF creation + +#include "HMPIDReconstruction/CTFHelper.h" diff --git a/Detectors/HMPID/reconstruction/src/Clusterer.cxx b/Detectors/HMPID/reconstruction/src/Clusterer.cxx new file mode 100644 index 0000000000000..1f664efebe87b --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/Clusterer.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Clusterer.cxx +/// \brief Implementation of the HMPID cluster finder +#include <algorithm> +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" +#include "DataFormatsHMP/Cluster.h" +#include "HMPIDReconstruction/Clusterer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include <TStopwatch.h> + +using namespace o2::hmpid; + +//__________________________________________________ +void Clusterer::process(std::vector<o2::hmpid::Digit> const& digits, std::vector<o2::hmpid::Cluster>& clusters, MCLabelContainer const* digitMCTruth) +{ + TStopwatch timerProcess; + timerProcess.Start(); + + // reader.init(); + // int totNumDigits = 0; + // + // while (reader.getNextStripData(mStripData)) { + // LOG(DEBUG) << "HMPIDClusterer got Strip " << mStripData.stripID << " with Ndigits " + // << mStripData.digits.size(); + // totNumDigits += mStripData.digits.size(); + // + // processStrip(clusters, digitMCTruth); + // } + + // LOG(DEBUG) << "We had " << totNumDigits << " digits in this event"; + timerProcess.Stop(); + printf("Timing:\n"); + printf("Clusterer::process: "); + timerProcess.Print(); +} diff --git a/Detectors/HMPID/reconstruction/src/HMPIDReconstructionLinkDef.h b/Detectors/HMPID/reconstruction/src/HMPIDReconstructionLinkDef.h new file mode 100644 index 0000000000000..1fa77ff6676f2 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HMPIDReconstructionLinkDef.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +//#pragma link C++ class o2::hmpid::DataReader + ; +#pragma link C++ class o2::hmpid::Clusterer + ; +//#pragma link C++ class o2::hmpid::HmpidDecodeRawMem + ; +//#pragma link C++ class o2::hmpid::HmpidDecoder + ; +#pragma link C++ class o2::hmpid::HmpidDecoder2 + ; +#pragma link C++ class o2::hmpid::HmpidEquipment + ; + +#endif diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx new file mode 100644 index 0000000000000..ff47b3e05a153 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecodeRawFile.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Derived Class for decoding Raw Data File stream +/// \version 1.0 +/// \date 24 set 2020 + +/* ------ HISTORY --------- +*/ +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" + +#include "HMPIDReconstruction/HmpidDecodeRawFile.h" + +using namespace o2::hmpid; + +/// Constructor with the default HMPID equipments map at P2 +/// @param[in] numOfEquipments : number of defined equipments [0..13] +HmpidDecodeRawFile::HmpidDecodeRawFile(int numOfEquipments) + : HmpidDecoder(numOfEquipments) +{ + fh = 0; +} + +/// Constructor with the HMPID address map +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +/// @param[in] *EqIds : the pointer to the Equipments ID array +/// @param[in] *CruIds : the pointer to the CRU ID array +/// @param[in] *LinkIds : the pointer to the Link ID array +HmpidDecodeRawFile::HmpidDecodeRawFile(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) + : HmpidDecoder(EqIds, CruIds, LinkIds, numOfEquipments) +{ + fh = 0; +} + +/// Destructor +HmpidDecodeRawFile::~HmpidDecodeRawFile() +{ +} + +/// Setup the Input Stream with a File Handle +/// verify the existence and try to open it +/// @param[in] *FileName : the string that contains the File Name +/// @param[in] Size : not used +/// @returns True if the file is opened +/// @throws TH_FILENOTEXISTS Thrown if the file doesn't exists +/// @throws TH_OPENFILE Thrown if Fails to open the file +bool HmpidDecodeRawFile::setUpStream(void* FileName, long Size) +{ + strcpy(mInputFile, (const char*)FileName); + // files section ---- + if (!fileExists(mInputFile)) { + LOG(ERROR) << "The input file " << mInputFile << " does not exist at this time."; + throw TH_FILENOTEXISTS; + } + // open the file + fh = fopen(mInputFile, "rb"); + if (fh == 0) { + LOG(ERROR) << "ERROR to open Input file ! [" << mInputFile << "]"; + throw TH_OPENFILE; + } + + mActualStreamPtr = 0; // sets the pointer to the Buffer + mEndStreamPtr = 0; //sets the End of buffer + mStartStreamPtr = 0; + + return (true); +} + +/// Gets a sized chunk from the stream. Read from the file and update the pointers +/// ATTENTION : in order to optimize the disk accesses the block read pre-load a +/// complete Header+Payload block, the Size parameter is recalculated with the +/// dimension of the pack extract from the header field 'Offeset' +/// +/// verify the existence and try to open it +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @param[in] Size : not used +/// @returns True if the file is opened +/// @throws TH_WRONGFILELEN Thrown if the file doesn't contains enough words +bool HmpidDecodeRawFile::getBlockFromStream(uint32_t** streamPtr, uint32_t Size) +{ + if (Size > MAXRAWFILEBUFFER) + return (false); + int nr = fread(mFileBuffer, sizeof(int32_t), HEADERDIMENSION_W, fh); + if (nr != HEADERDIMENSION_W) { + throw TH_WRONGFILELEN; + } + Size = ((mFileBuffer[2] & 0x0000FFFF) / sizeof(int32_t)) - HEADERDIMENSION_W; + nr = fread(mFileBuffer + HEADERDIMENSION_W, sizeof(int32_t), Size, fh); + LOG(DEBUG) << " getBlockFromStream read " << nr << " of " << Size + HEADERDIMENSION_W << " words !"; + if (nr != Size) { + throw TH_WRONGFILELEN; + } + *streamPtr = mFileBuffer; + mStartStreamPtr = mFileBuffer; + mActualStreamPtr = mFileBuffer; + mEndStreamPtr = mFileBuffer + Size; + return (true); +} + +/// Reads the Header from the file +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @returns True if the header is read +bool HmpidDecodeRawFile::getHeaderFromStream(uint32_t** streamPtr) +{ + bool flag = getBlockFromStream(streamPtr, RAWBLOCKDIMENSION_W); // reads the 8k block + mActualStreamPtr += HEADERDIMENSION_W; // Move forward for the first word + return (flag); +} + +/// Read one word from the pre-load buffer +/// @param[in] *word : the buffer for the read word +/// @returns True every time +bool HmpidDecodeRawFile::getWordFromStream(uint32_t* word) +{ + *word = *mActualStreamPtr; + mActualStreamPtr++; + return (true); +} + +/// ----- Sets the Pad ! ------ +/// this is an overloaded method. In this version the value of the charge +/// is used to update the statistical matrix of the base class +/// +/// @param[in] *eq : the pointer to the Equipment object +/// @param[in] col : the column [0..23] +/// @param[in] dil : the dilogic [0..9] +/// @param[in] ch : the channel [0..47] +/// @param[in] charge : the value of the charge +void HmpidDecodeRawFile::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) +{ + eq->setPad(col, dil, ch, charge); + return; +} + +/// Checks if the file exists ! +/// @param[in] *filewithpath : the File Name to check +/// @returns True if the file exists +int HmpidDecodeRawFile::fileExists(char* filewithpath) +{ + if (access(filewithpath, F_OK) != -1) { + return (true); + } else { + return (false); + } +} +o2::hmpid::Digit diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx new file mode 100644 index 0000000000000..3538a5eb7bc57 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecodeRawMem.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Derived Class for decoding Raw Data Memory stream +/// \version 1.0 +/// \date 24 set 2020 + +/* ------ HISTORY --------- +*/ +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" + +#include "DataFormatsHMP/Digit.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecodeRawMem.h" + +using namespace o2::hmpid; + +/// Constructor : accepts the number of equipments to define +/// The mapping is the default at P2 +/// Allocates instances for all defined equipments +/// normally it is equal to 14 +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +HmpidDecodeRawMem::HmpidDecodeRawMem(int numOfEquipments) + : HmpidDecoder(numOfEquipments) +{ +} + +/// Constructor : accepts the number of equipments to define +/// and their complete address map +/// Allocates instances for all defined equipments +/// +/// The Address map is build from three array +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +/// @param[in] *EqIds : the pointer to the Equipments ID array +/// @param[in] *CruIds : the pointer to the CRU ID array +/// @param[in] *LinkIds : the pointer to the Link ID array +HmpidDecodeRawMem::HmpidDecodeRawMem(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) + : HmpidDecoder(EqIds, CruIds, LinkIds, numOfEquipments) +{ +} + +/// Destructor +HmpidDecodeRawMem::~HmpidDecodeRawMem() = default; + +/// Setup the Input Stream with a Memory Pointer +/// the buffer length is in byte, some controls are done +/// +/// @param[in] *Buffer : the pointer to Memory buffer +/// @param[in] BufferLen : the length of the buffer (bytes) +/// @returns True if the stream is set +/// @throws TH_NULLBUFFERPOINTER Thrown if the pointer to the buffer is NULL +/// @throws TH_BUFFEREMPTY Thrown if the buffer is empty +/// @throws TH_WRONGBUFFERDIM Thrown if the buffer len is less then one header +bool HmpidDecodeRawMem::setUpStream(void* Buffer, long BufferLen) +{ + long wordsBufferLen = BufferLen / (sizeof(int32_t) / sizeof(char)); // Converts the len in words + if (Buffer == nullptr) { + LOG(ERROR) << "Raw data buffer null Pointer ! "; + throw TH_NULLBUFFERPOINTER; + } + if (wordsBufferLen == 0) { + LOG(ERROR) << "Raw data buffer Empty ! "; + throw TH_BUFFEREMPTY; + } + if (wordsBufferLen < 16) { + LOG(ERROR) << "Raw data buffer less then the Header Dimension = " << wordsBufferLen; + throw TH_WRONGBUFFERDIM; + } + + mActualStreamPtr = (uint32_t*)Buffer; // sets the pointer to the Buffer + mEndStreamPtr = ((uint32_t*)Buffer) + wordsBufferLen; //sets the End of buffer + mStartStreamPtr = ((uint32_t*)Buffer); + // std::cout << " setUpStrem : StPtr=" << mStartStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << wordsBufferLen << std::endl; + return (true); +} + +/// Gets a sized chunk from the stream. The stream pointers members are updated +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @param[in] Size : the dimension of the chunk (words) +/// @returns True every time +/// @throw TH_WRONGBUFFERDIM Buffer length shorter then the requested +bool HmpidDecodeRawMem::getBlockFromStream(uint32_t** streamPtr, uint32_t Size) +{ + *streamPtr = mActualStreamPtr; + mActualStreamPtr += Size; + if (mActualStreamPtr > mEndStreamPtr) { + // std::cout << " getBlockFromStream : StPtr=" << mActualStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << Size << std::endl; + // std::cout << "Beccato " << std::endl; + // throw TH_WRONGBUFFERDIM; + return (false); + } + return (true); +} + +/// Gets the Header Block from the stream. +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @returns True if the header is read +bool HmpidDecodeRawMem::getHeaderFromStream(uint32_t** streamPtr) +{ + return (getBlockFromStream(streamPtr, mRDHSize)); +} + +/// Gets a Word from the stream. +/// @param[in] *word : the buffer for the read word +/// @returns True if the operation end well +bool HmpidDecodeRawMem::getWordFromStream(uint32_t* word) +{ + uint32_t* appo; + *word = *mActualStreamPtr; + return (getBlockFromStream(&appo, 1)); +} + +/// ----- Sets the Pad ! ------ +/// this is an overloaded method. In this version the value of the charge +/// is used to update the statistical matrix of the base class +/// +/// @param[in] *eq : the pointer to the Equipment object +/// @param[in] col : the column [0..23] +/// @param[in] dil : the dilogic [0..9] +/// @param[in] ch : the channel [0..47] +/// @param[in] charge : the value of the charge +void HmpidDecodeRawMem::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) +{ + eq->setPad(col, dil, ch, charge); + return; +} + +// ======================================================================================== + +/// Constructor : accepts the number of equipments to define +/// The mapping is the default at P2 +/// Allocates instances for all defined equipments +/// normally it is equal to 14 +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +HmpidDecodeRawDigit::HmpidDecodeRawDigit(int numOfEquipments) + : HmpidDecodeRawMem(numOfEquipments) +{ +} + +/// Constructor : accepts the number of equipments to define +/// and their complete address map +/// Allocates instances for all defined equipments +/// +/// The Address map is build from three array +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +/// @param[in] *EqIds : the pointer to the Equipments ID array +/// @param[in] *CruIds : the pointer to the CRU ID array +/// @param[in] *LinkIds : the pointer to the Link ID array +HmpidDecodeRawDigit::HmpidDecodeRawDigit(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) + : HmpidDecodeRawMem(EqIds, CruIds, LinkIds, numOfEquipments) +{ +} + +/// Destructor +HmpidDecodeRawDigit::~HmpidDecodeRawDigit() = default; + +/// ----- Sets the Pad ! ------ +/// this is an overloaded method. In this version the value of the charge +/// is used to update the statistical matrix of the base class +/// +/// @param[in] *eq : the pointer to the Equipment object +/// @param[in] col : the column [0..23] +/// @param[in] dil : the dilogic [0..9] +/// @param[in] ch : the channel [0..47] +/// @param[in] charge : the value of the charge +void HmpidDecodeRawDigit::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) +{ + eq->setPad(col, dil, ch, charge); + mDigits.push_back(o2::hmpid::Digit(charge, eq->getEquipmentId(), col, dil, ch)); + //std::cout << "DI " << mDigits.back() << " "<<col<<","<< dil<<","<< ch<<"="<< charge<<std::endl; + return; +} diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx new file mode 100644 index 0000000000000..bece4b6486d58 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx @@ -0,0 +1,1135 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecoder.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to decode HMPID Raw Data stream +/// \version 1.1 +/// \date 17/11/2020 + +/* ------ HISTORY --------- +*/ + +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" +#include "Headers/RAWDataHeader.h" +#include "HMPIDReconstruction/HmpidDecoder.h" +#include "DataFormatsHMP/Digit.h" + +using namespace o2::hmpid; + +// ============= HmpidDecoder Class implementation ======= + +/// Decoding Error Messages Definitions +char HmpidDecoder::sErrorDescription[MAXERRORS][MAXDESCRIPTIONLENGHT] = {"Word that I don't known !", + "Row Marker Word with 0 words", "Duplicated Pad Word !", "Row Marker Wrong/Lost -> to EoE", + "Row Marker Wrong/Lost -> to EoE", "Row Marker reports an ERROR !", "Lost EoE Marker !", "Double EoE marker", + "Wrong size definition in EoE Marker", "Double Mark Word", "Wrong Size in Segment Marker", "Lost EoS Marker !", + "HMPID Header Errors"}; + +/// HMPID Firmware Error Messages Definitions +char HmpidDecoder::sHmpidErrorDescription[MAXHMPIDERRORS][MAXDESCRIPTIONLENGHT] = { + "L0 Missing," + "L1 is received without L0", + "L1A signal arrived before the L1 Latency", "L1A signal arrived after the L1 Latency", + "L1A is missing or L1 timeout", "L1A Message is missing or L1 Message"}; + +/// Constructor : accepts the number of equipments to define +/// The mapping is the default at P2 +/// Allocates instances for all defined equipments +/// normally it is equal to 14 +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +HmpidDecoder::HmpidDecoder(int numOfEquipments) +{ + // The standard definition of HMPID equipments at P2 + int EqIds[] = {0, 1, 2, 3, 4, 5, 8, 9, 6, 7, 10, 11, 12, 13}; + int CruIds[] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; + int LinkIds[] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2}; + + mNumberOfEquipments = numOfEquipments; + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i] = new HmpidEquipment(EqIds[i], CruIds[i], LinkIds[i]); + } +} + +/// Constructor : accepts the number of equipments to define +/// and their complete address map +/// Allocates instances for all defined equipments +/// +/// The Address map is build from three array +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +/// @param[in] *EqIds : the pointer to the Equipments ID array +/// @param[in] *CruIds : the pointer to the CRU ID array +/// @param[in] *LinkIds : the pointer to the Link ID array +HmpidDecoder::HmpidDecoder(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) +{ + mNumberOfEquipments = numOfEquipments; + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i] = new HmpidEquipment(EqIds[i], CruIds[i], LinkIds[i]); + } +} + +/// Destructor : remove the Equipments instances +HmpidDecoder::~HmpidDecoder() +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + delete mTheEquipments[i]; + } +} + +/// Init all the members variables. +void HmpidDecoder::init() +{ + mRDHAcceptedVersion = 6; + mRDHSize = sizeof(o2::header::RAWDataHeaderV6) / sizeof(uint32_t); + + mVerbose = 0; + mHeEvent = 0; + mHeBusy = 0; + mNumberWordToRead = 0; + mPayloadTail = 0; + + mHeFEEID = 0; + mHeSize = 0; + mHeVer = 0; + mHePrior = 0; + mHeStop = 0; + mHePages = 0; + mEquipment = 0; + + mHeOffsetNewPack = 0; + mHeMemorySize = 0; + + mHeDetectorID = 0; + mHeDW = 0; + mHeCruID = 0; + mHePackNum = 0; + mHePAR = 0; + mHePageNum = 0; + mHeLinkNum = 0; + mHeFirmwareVersion = 0; + mHeHmpidError = 0; + mHeBCDI = 0; + mHeORBIT = 0; + mHeTType = 0; + + mActualStreamPtr = nullptr; + mEndStreamPtr = nullptr; + mStartStreamPtr = nullptr; + + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + } +} + +/// Returns the Equipment Index (Pointer of the array) converting +/// the FLP hardware coords (CRU_Id and Link_Id) +/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] +/// @param[in] LinkId : the Link ID [0..3] +/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) +int HmpidDecoder::getEquipmentIndex(int CruId, int LinkId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { + return (i); + } + } + return (-1); +} + +/// Returns the Equipment Index (Pointer of the array) converting +/// the Equipment_ID (Firmaware defined Id AKA FFEID) +/// @param[in] EquipmentId : the Equipment ID [0..13] +/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) +int HmpidDecoder::getEquipmentIndex(int EquipmentId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId() == EquipmentId) { + return (i); + } + } + return (-1); +} + +/// Returns the Equipment_ID converting the FLP hardware coords +/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] +/// @param[in] LinkId : the Link ID [0..3] +/// @returns EquipmentID : the ID of the Equipment [0..13] (-1 := error) +int HmpidDecoder::getEquipmentID(int CruId, int LinkId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { + return (mTheEquipments[i]->getEquipmentId()); + } + } + return (-1); +} + +/// Scans the BitMap of Raw Data File word and detect the type +/// and the parameters +/// @param[in] wp : the word to analyze +/// @param[out] *p1 : first parameter extract (if it exists) +/// @param[out] *p2 : second parameter extract (if it exists) +/// @param[out] *p3 : third parameter extract (if it exists) +/// @param[out] *p4 : fourth parameter extract (if it exists) +/// @returns Type of Word : the type of word [0..4] (0 := undetect) +int HmpidDecoder::checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4) +{ + if ((wp & 0x0000ffff) == 0x000036A8 || (wp & 0x0000ffff) == 0x000032A8 || (wp & 0x0000ffff) == 0x000030A0 || (wp & 0x0800ffff) == 0x080010A0) { + *p2 = (wp & 0x03ff0000) >> 16; // Number of words of row + *p1 = wp & 0x0000ffff; + return (WTYPE_ROW); + } + if ((wp & 0xfff00000) >> 20 == 0xAB0) { + *p2 = (wp & 0x000fff00) >> 8; // Number of words of Segment + *p1 = (wp & 0xfff00000) >> 20; + *p3 = wp & 0x0000000F; + if (*p3 < 4 && *p3 > 0) { + return (WTYPE_EOS); + } + } + // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 + if ((wp & 0x0803FF80) == 0x08000080) { + *p1 = (wp & 0x07c00000) >> 22; + *p2 = (wp & 0x003C0000) >> 18; + *p3 = (wp & 0x0000007F); + if (*p1 < 25 && *p2 < 11) { + return (WTYPE_EOE); + } + } + if ((wp & 0x08000000) == 0) { // # this is a pad + // PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value + *p1 = (wp & 0x07c00000) >> 22; + *p2 = (wp & 0x003C0000) >> 18; + *p3 = (wp & 0x0003F000) >> 12; + *p4 = (wp & 0x00000FFF); + if (*p1 > 0 && *p1 < 25 && *p2 > 0 && *p2 < 11 && *p3 < 48) { + return (WTYPE_PAD); + } + } else { + return (WTYPE_NONE); + } + return (WTYPE_NONE); +} + +/// Checks if is a Raw Marker and extract the Row Size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *rowSize : the number of words of the row +/// @param[out] *mark : the row marker +/// @returns True if Row Marker is detected +bool HmpidDecoder::isRowMarker(uint32_t wp, int* Err, int* rowSize, int* mark) +{ + if ((wp & 0x0000ffff) == 0x36A8 || (wp & 0x0000ffff) == 0x32A8 || (wp & 0x0000ffff) == 0x30A0 || (wp & 0x0800ffff) == 0x080010A0) { + *rowSize = (wp & 0x03ff0000) >> 16; // # Number of words of row + *mark = wp & 0x0000ffff; + *Err = false; + return (true); + } else { + *Err = true; + return (false); + } +} + +/// Checks if is a Segment Marker and extracts the Segment number and the size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *segSize : the number of words of the segment +/// @param[out] *Seg : the Segment number [1..3] +/// @param[out] *mark : the Segment Marker +/// @returns True if Segment Marker is detected +bool HmpidDecoder::isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg, int* mark) +{ + *Err = false; + if ((wp & 0xfff00000) >> 20 == 0xAB0) { + *segSize = (wp & 0x000fff00) >> 8; // # Number of words of Segment + *mark = (wp & 0xfff00000) >> 20; + *Seg = wp & 0x0000000F; + if (*Seg > 3 || *Seg < 1) { + LOG(INFO) << " Wrong segment Marker Word, bad Number of segment" << *Seg << "!"; + *Err = true; + } + return (true); + } else { + return (false); + } +} + +/// Checks if is a PAD Word and extracts all the parameters +/// PAD map : 0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *Col : the column number [1..24] +/// @param[out] *Dilogic : the dilogic number [1..10] +/// @param[out] *Channel : the channel number [0..47] +/// @param[out] *Charge : the value of Charge [0..4095] +/// @returns True if PAD Word is detected +bool HmpidDecoder::isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge) +{ + *Err = false; + // if ((wp & 0x08000000) != 0) { + if ((wp & 0x08000000) != 0) { + return (false); + } + *Col = (wp & 0x07c00000) >> 22; + *Dilogic = (wp & 0x003C0000) >> 18; + *Channel = (wp & 0x0003F000) >> 12; + *Charge = (wp & 0x00000FFF); + + if ((wp & 0x0ffff) == 0x036A8 || (wp & 0x0ffff) == 0x032A8 || (wp & 0x0ffff) == 0x030A0 || (wp & 0x0ffff) == 0x010A0) { // # ! this is a pad + if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { + return (false); + } + } else { + if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { + // LOG(WARNING) << " Wrong Pad values Col=" << *Col << " Dilogic=" << *Dilogic << " Channel=" << *Channel << " Charge=" << *Charge << " wp:0x" << std::hex << wp << std::dec; + *Err = true; + return (false); + } + } + return (true); +} + +/// Checks if is a EoE Marker and extracts the Column, Dilogic and the size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *Col : the column number [1..24] +/// @param[out] *Dilogic : the dilogic number [1..10] +/// @param[out] *Eoesize : the number of words for dilogic +/// @returns True if EoE marker is detected +bool HmpidDecoder::isEoEmarker(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Eoesize) +{ + *Err = false; + // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 + if ((wp & 0x0803FF80) == 0x08000080) { + *Col = (wp & 0x07c00000) >> 22; + *Dilogic = (wp & 0x003C0000) >> 18; + *Eoesize = (wp & 0x0000007F); + if (*Col > 24 || *Dilogic > 10) { + LOG(INFO) << " EoE size wrong definition. Col=" << *Col << " Dilogic=" << *Dilogic; + *Err = true; + } + return (true); + } else { + return (false); + } +} + +/// Decode the HMPID error BitMap field (5 bits) and returns true if there are +/// errors and in addition the concat string that contains the error messages +/// ATTENTION : the char * outbuf MUST point to a 250 bytes buffer +/// @param[in] ErrorField : the HMPID Error field +/// @param[out] *outbuf : the output buffer that contains the error description +/// @returns True if EoE marker is detected +bool HmpidDecoder::decodeHmpidError(int ErrorField, char* outbuf) +{ + int res = false; + outbuf[0] = '\0'; + for (int i = 0; i < MAXHMPIDERRORS; i++) { + if ((ErrorField & (0x01 << i)) != 0) { + res = true; + strcat(outbuf, sHmpidErrorDescription[i]); + } + } + return (res); +} + +/// This Decode the Raw Data Header, returns the EquipmentIndex +/// that is obtained with the FLP hardware coords +/// +/// ATTENTION : the 'EquipIndex' parameter and the mEquipment member +/// are different data: the first is the pointer in the Equipments instances +/// array, the second is the FEE_ID number +/// +/// The EVENT_NUMBER : actually is calculated from the ORBIT number +/// +/// @param[in] *streamPtrAdr : the pointer to the Header buffer +/// @param[out] *EquipIndex : the Index to the Equipment Object Array [0..13] +/// @returns True every time +/// @throws TH_WRONGEQUIPINDEX Thrown if the Equipment Index is out of boundary (Equipment not recognized) +int HmpidDecoder::decodeHeader(uint32_t* streamPtrAdr, int* EquipIndex) +{ + uint32_t* buffer = streamPtrAdr; // Sets the pointer to buffer + o2::header::RAWDataHeaderV6* hpt = (o2::header::RAWDataHeaderV6*)buffer; + + /* + mHeFEEID = (buffer[0] & 0x000f0000) >> 16; + mHeSize = (buffer[0] & 0x0000ff00) >> 8; + mHeVer = (buffer[0] & 0x000000ff); + mHePrior = (buffer[1] & 0x000000FF); + mHeDetectorID = (buffer[1] & 0x0000FF00) >> 8; + mHeOffsetNewPack = (buffer[2] & 0x0000FFFF); + mHeMemorySize = (buffer[2] & 0xffff0000) >> 16; + mHeDW = (buffer[3] & 0xF0000000) >> 24; + mHeCruID = (buffer[3] & 0x0FF0000) >> 16; + mHePackNum = (buffer[3] & 0x0000FF00) >> 8; + mHeLinkNum = (buffer[3] & 0x000000FF); + mHeBCDI = (buffer[4] & 0x00000FFF); + mHeORBIT = buffer[5]; + mHeTType = buffer[8]; + mHePageNum = (buffer[9] & 0x0000FFFF); + mHeStop = (buffer[9] & 0x00ff0000) >> 16; + mHeBusy = (buffer[12] & 0xfffffe00) >> 9; + mHeFirmwareVersion = buffer[12] & 0x0000000f; + mHeHmpidError = (buffer[12] & 0x000001F0) >> 4; + mHePAR = buffer[13] & 0x0000FFFF; + */ + mHeFEEID = hpt->feeId; + mHeSize = hpt->headerSize; + mHeVer = hpt->version; + mHePrior = hpt->priority; + mHeDetectorID = hpt->sourceID; + mHeOffsetNewPack = hpt->offsetToNext; + mHeMemorySize = hpt->memorySize; + mHeDW = hpt->endPointID; + mHeCruID = hpt->cruID; + mHePackNum = hpt->packetCounter; + mHeLinkNum = hpt->linkID; + mHeBCDI = hpt->bunchCrossing; + mHeORBIT = hpt->orbit; + mHeTType = hpt->triggerType; + mHePageNum = hpt->pageCnt; + mHeStop = hpt->stop; + mHeBusy = (hpt->detectorField & 0xfffffe00) >> 9; + mHeFirmwareVersion = hpt->detectorField & 0x0000000f; + mHeHmpidError = (hpt->detectorField & 0x000001F0) >> 4; + mHePAR = hpt->detectorPAR; + + *EquipIndex = getEquipmentIndex(mHeCruID, mHeLinkNum); + // mEquipment = (*EquipIndex != -1) ? mTheEquipments[*EquipIndex]->getEquipmentId() : -1; + mEquipment = mHeFEEID & 0x000F; + mNumberWordToRead = ((mHeMemorySize - mHeSize) / sizeof(uint32_t)); + mPayloadTail = ((mHeOffsetNewPack - mHeMemorySize) / sizeof(uint32_t)); + + // ---- Event ID : Actualy based on ORBIT NUMBER and BC + mHeEvent = (mHeORBIT << 12) | mHeBCDI; + + LOG(DEBUG) << "FEE-ID=" << mHeFEEID << " HeSize=" << mHeSize << " HePrior=" << mHePrior << " Det.Id=" << mHeDetectorID << " HeMemorySize=" << mHeMemorySize << " HeOffsetNewPack=" << mHeOffsetNewPack; + LOG(DEBUG) << " Equipment=" << mEquipment << " PakCounter=" << mHePackNum << " Link=" << mHeLinkNum << " CruID=" << mHeCruID << " DW=" << mHeDW << " BC=" << mHeBCDI << " ORBIT=" << mHeORBIT; + LOG(DEBUG) << " TType=" << mHeTType << " HeStop=" << mHeStop << " PagesCounter=" << mHePageNum << " FirmVersion=" << mHeFirmwareVersion << " BusyTime=" << mHeBusy << " Error=" << mHeHmpidError << " PAR=" << mHePAR; + LOG(DEBUG) << " EquIdx = " << *EquipIndex << " Event = " << mHeEvent << " Payload : Words to read=" << mNumberWordToRead << " PailoadTail=" << mPayloadTail; + + if (*EquipIndex == -1) { + LOG(ERROR) << "ERROR ! Bad equipment Number: " << mEquipment; + throw TH_WRONGEQUIPINDEX; + } + // std::cout << "HMPID ! Exit decode header" << std::endl; + return (true); +} + +/// Updates some information related to the Event +/// this function is called at the end of the event +/// @param[in] *eq : the pointer to the Equipment Object +void HmpidDecoder::updateStatistics(HmpidEquipment* eq) +{ + eq->mPadsPerEventAverage = ((eq->mPadsPerEventAverage * (eq->mNumberOfEvents - 1)) + eq->mSampleNumber) / (eq->mNumberOfEvents); + eq->mEventSizeAverage = ((eq->mEventSizeAverage * (eq->mNumberOfEvents - 1)) + eq->mEventSize) / (eq->mNumberOfEvents); + eq->mBusyTimeAverage = ((eq->mBusyTimeAverage * eq->mBusyTimeSamples) + eq->mBusyTimeValue) / (++(eq->mBusyTimeSamples)); + if (eq->mSampleNumber == 0) { + eq->mNumberOfEmptyEvents += 1; + } + if (eq->mErrorsCounter > 0) { + eq->mNumberOfWrongEvents += 1; + } + eq->mTotalPads += eq->mSampleNumber; + eq->mTotalErrors += eq->mErrorsCounter; + + //std::cout << ">>>updateStatistics() >>> "<< eq->getEquipmentId() << "="<< eq->mNumberOfEvents<<" :" << eq->mEventSize <<","<< eq->mTotalPads << ", " << eq->mSampleNumber << std::endl; + + return; +} + +/// Evaluates the content of the header and detect the change of the event +/// with the relevant updates... +/// @param[in] EquipmentIndex : the pointer to the Array of Equipments Array +/// @returns the Pointer to the modified Equipment object +HmpidEquipment* HmpidDecoder::evaluateHeaderContents(int EquipmentIndex) +{ + //std::cout << "Enter evaluateHeaderContents.."; + HmpidEquipment* eq = mTheEquipments[EquipmentIndex]; + if (mHeEvent != eq->mEventNumber) { // Is a new event + if (eq->mEventNumber != OUTRANGEEVENTNUMBER) { // skip the first + updateStatistics(eq); // update previous statistics + } + eq->mNumberOfEvents++; + eq->mEventNumber = mHeEvent; + eq->mBusyTimeValue = mHeBusy * 0.00000005; + eq->mEventSize = 0; // reset the event + eq->mSampleNumber = 0; + eq->mErrorsCounter = 0; + mIntReco = {(uint16_t)mHeBCDI, (uint32_t)mHeORBIT}; + } + eq->mEventSize += mNumberWordToRead * sizeof(uint32_t); // Calculate the size in bytes + if (mHeHmpidError != 0) { + LOG(INFO) << "HMPID Header reports an error : " << mHeHmpidError; + dumpHmpidError(mHeHmpidError); + eq->setError(ERR_HMPID); + } + // std::cout << ".. end evaluateHeaderContents = " << eq->mEventNumber << std::endl; + return (eq); +} + +/// --------------- Decode One Page from Data Buffer --------------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer +void HmpidDecoder::decodePage(uint32_t** streamBuf) +{ + int equipmentIndex; + try { + getHeaderFromStream(streamBuf); + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End main decoding loop !"; + throw TH_BUFFEREMPTY; + } + try { + decodeHeader(*streamBuf, &equipmentIndex); + } catch (int e) { + LOG(ERROR) << "Failed to decode the Header !"; + throw TH_WRONGHEADER; + } + + HmpidEquipment* eq = evaluateHeaderContents(equipmentIndex); + + uint32_t wpprev = 0; + uint32_t wp = 0; + int newOne = true; + int p1, p2, p3, p4; + int error; + int type; + bool isIt; + + int payIndex = 0; + while (payIndex < mNumberWordToRead) { //start the payload loop word by word + if (newOne == true) { + wpprev = wp; + if (!getWordFromStream(&wp)) { // end the stream + break; + } + type = checkType(wp, &p1, &p2, &p3, &p4); + if (type == WTYPE_NONE) { + if (eq->mWillBePad == true) { // try to recover the first pad ! + type = checkType((wp & 0xF7FFFFFF), &p1, &p2, &p3, &p4); + if (type == WTYPE_PAD && p3 == 0 && eq->mWordsPerDilogicCounter == 0) { + newOne = false; // # reprocess as pad + continue; + } + } + eq->setError(ERR_NOTKNOWN); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_NOTKNOWN] << " [" << wp << "]"; + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + payIndex++; + continue; + } + } + if (mEquipment == 8) { + LOG(INFO) << "Event" << eq->mEventNumber << " >" << std::hex << wp << std::dec << "<" << type; + } + if (eq->mWillBeRowMarker == true) { // #shoud be a Row Marker + if (type == WTYPE_ROW) { + eq->mColumnCounter++; + eq->mWordsPerSegCounter++; + eq->mRowSize = p2; + switch (p2) { + case 0: // Empty column + eq->setError(ERR_ROWMARKEMPTY); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKEMPTY] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = true; + break; + case 0x3FF: // Error in column + eq->setError(ERR_ROWMARKERROR); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKERROR] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = true; + break; + case 0x3FE: // Masked column + LOG(INFO) << "Equip=" << mEquipment << "The column=" << (eq->mSegment) * 8 + eq->mColumnCounter << " is Masked !"; + eq->mWillBeRowMarker = true; + break; + default: + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + break; + } + newOne = true; + } else { + if (wp == wpprev) { + eq->setError(ERR_DUPLICATEPAD); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + newOne = true; + } else if (type == WTYPE_EOE) { // # Could be a EoE + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKWRONG); + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } else if (type == WTYPE_PAD) { //# Could be a PAD + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKLOST); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKLOST] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } else if (type == WTYPE_EOS) { // # Could be a EoS + eq->mWillBeRowMarker = false; + eq->mWillBeSegmentMarker = true; + newOne = false; + } else { + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKLOST); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKLOST] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } + } + } else if (eq->mWillBePad == true) { // # We expect a pad + //# PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value + // c = 1..24 d = 1..10 n = 0..47 + if (type == WTYPE_PAD) { + newOne = true; + if (wp == wpprev) { + eq->setError(ERR_DUPLICATEPAD); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + } else if (p1 != (eq->mSegment * 8 + eq->mColumnCounter)) { // # Manage + // We try to recover the RowMarker misunderstanding + isIt = isRowMarker(wp, &error, &p2, &p1); + if (isIt == true && error == false) { + type = WTYPE_ROW; + newOne = false; + eq->mWillBeEoE = true; + eq->mWillBePad = false; + } else { + LOG(DEBUG) << "Equip=" << mEquipment << " Mismatch in column" + << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mColumnCounter = p1 % 8; + } + } else { + setPad(eq, p1 - 1, p2 - 1, p3, p4); + if (mEquipment == 8) { + LOG(INFO) << "Event" << eq->mEventNumber << " >" << p1 - 1 << "," << p2 - 1 << "," << p3 << "," << p4; + } + eq->mWordsPerDilogicCounter++; + eq->mSampleNumber++; + if (p3 == 47) { + eq->mWillBeEoE = true; + eq->mWillBePad = false; + } + } + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + } else if (type == WTYPE_EOE) { //# the pads are end ok + eq->mWillBeEoE = true; + eq->mWillBePad = false; + newOne = false; + } else if (type == WTYPE_ROW) { // # We Lost the EoE ! + // We try to recover the PAD misunderstanding + isIt = isPadWord(wp, &error, &p1, &p2, &p3, &p4); + if (isIt == true && error == false) { + type = WTYPE_PAD; + newOne = false; // # reprocess as pad + } else { + eq->setError(ERR_LOSTEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = true; + eq->mWillBePad = false; + newOne = false; + } + } else if (type == WTYPE_EOS) { // # We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeSegmentMarker = true; + eq->mWillBePad = false; + newOne = false; + } + } else if (eq->mWillBeEoE == true) { // # We expect a EoE + if (type == WTYPE_EOE) { + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + if (wpprev == wp) { + eq->setError(ERR_DOUBLEEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_DOUBLEEOEMARK] << " col=" << p1; + } else if (p3 != eq->mWordsPerDilogicCounter) { + eq->setError(ERR_WRONGSIZEINEOE); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_WRONGSIZEINEOE] << " col=" << p1; + } + eq->mWordsPerDilogicCounter = 0; + if (p2 == 10) { + if (p1 % 8 != 0) { // # we expect the Row Marker + eq->mWillBeRowMarker = true; + } else { + eq->mWillBeSegmentMarker = true; + } + } else { + eq->mWillBePad = true; + } + eq->mWillBeEoE = false; + newOne = true; + } else if (type == WTYPE_EOS) { // We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeSegmentMarker = true; + eq->mWillBeEoE = false; + newOne = false; + } else if (type == WTYPE_ROW) { //# We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeRowMarker = true; + eq->mWillBeEoE = false; + newOne = false; + } else if (type == WTYPE_PAD) { // # We Lost the EoE ! + int typb, p1b, p2b, p3b, p4b; + typb = checkType((wp | 0x08000000), &p1b, &p2b, &p3b, &p4b); + if (typb == WTYPE_EOE && p3b == 48) { + type = typb; + p1 = p1b; + p2 = p2b; + p3 = p3b; + p4 = p4b; + newOne = false; // # reprocess as EoE + } else { + eq->setError(ERR_LOSTEOEMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBePad = true; + eq->mWillBeEoE = false; + newOne = false; + } + } + } else if (eq->mWillBeSegmentMarker == true) { // # We expect a EoSegment + if (wpprev == wp) { + eq->setError(ERR_DOUBLEMARKWORD); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_DOUBLEMARKWORD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + newOne = true; + } else if (type == 2) { + if (abs(eq->mWordsPerSegCounter - p2) > 5) { + eq->setError(ERR_WRONGSIZESEGMENTMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_WRONGSIZESEGMENTMARK] << " Seg=" << p2; + } + eq->mWordsPerSegCounter = 0; + eq->mWordsPerRowCounter = 0; + eq->mColumnCounter = 0; + eq->mSegment = p3 % 3; + eq->mWillBeRowMarker = true; + eq->mWillBeSegmentMarker = false; + newOne = true; + } else { + eq->setError(ERR_LOSTEOSMARK); + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOSMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; + eq->mWillBeSegmentMarker = false; + eq->mWillBeRowMarker = true; + newOne = false; + } + } + if (newOne) { + payIndex += 1; + } + } + for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail + getWordFromStream(&wp); + } +} + +/// --------------- Read Raw Data Buffer --------------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +bool HmpidDecoder::decodeBuffer() +{ + // ---------resets the PAdMap----------- + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + mTheEquipments[i]->resetPadMap(); + mTheEquipments[i]->resetErrors(); + } + + int type; + int equipmentIndex = -1; + int isIt; + HmpidEquipment* eq; + uint32_t* streamBuf; + LOG(DEBUG) << "Enter decoding !"; + + // Input Stream Main Loop + while (true) { + try { + decodePage(&streamBuf); + } catch (int e) { + LOG(DEBUG) << "End main buffer decoding loop !"; + break; + } + } // this is the end of stream + + // cycle in order to update info for the last event + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->mNumberOfEvents > 0) { + updateStatistics(mTheEquipments[i]); + } + } + return (true); +} + +/// --------- Decode One Page from Data Buffer with Fast Decoding -------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer +void HmpidDecoder::decodePageFast(uint32_t** streamBuf) +{ + int equipmentIndex; + try { + getHeaderFromStream(streamBuf); + } catch (int e) { + // The stream end ! + LOG(INFO) << "End Fast Page decoding loop !"; + throw TH_BUFFEREMPTY; + } + try { + decodeHeader(*streamBuf, &equipmentIndex); + } catch (int e) { + LOG(INFO) << "Failed to decode the Header !"; + throw TH_WRONGHEADER; + } + HmpidEquipment* eq = evaluateHeaderContents(equipmentIndex); + uint32_t wpprev = 0; + uint32_t wp = 0; + int newOne = true; + int Column, Dilogic, Channel, Charge; + int pwer; + int payIndex = 0; + while (payIndex < mNumberWordToRead) { //start the payload loop word by word + wpprev = wp; + if (!getWordFromStream(&wp)) { // end the stream + break; + } + if (wp == wpprev) { + LOG(DEBUG) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << Column << "]"; + } else { + if (isPadWord(wp, &pwer, &Column, &Dilogic, &Channel, &Charge) == true) { + if (pwer != true) { + setPad(eq, Column - 1, Dilogic - 1, Channel, Charge); + eq->mSampleNumber++; + } + } + } + payIndex += 1; + } + for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail + getWordFromStream(&wp); + } + return; +} +/// ---------- Read Raw Data Buffer with Fast Decoding ---------- +/// Read the stream, decode the contents and store resuls. +/// Fast alghoritm : no parsing of control words ! +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +bool HmpidDecoder::decodeBufferFast() +{ + // ---------resets the PAdMap----------- + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + mTheEquipments[i]->resetPadMap(); + } + + uint32_t* streamBuf; + LOG(INFO) << "Enter FAST decoding !"; + + // Input Stream Main Loop + while (true) { + try { + decodePageFast(&streamBuf); + } catch (int e) { + LOG(INFO) << " End Buffer Fast Decoding !"; + break; + } + } // this is the end of stream + + // cycle in order to update info for the last event + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->mNumberOfEvents > 0) { + updateStatistics(mTheEquipments[i]); + } + } + return (true); +} + +// ========================================================= + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Number of entries for specified pad +uint16_t HmpidDecoder::getPadSamples(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSamples[c][d][h]); +} + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Sum of Charges for specified pad +double HmpidDecoder::getPadSum(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSum[c][d][h]); +} + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Sum of Square Charges for specified pad +double HmpidDecoder::getPadSquares(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSquares[c][d][h]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Number of Entries for specified pad +uint16_t HmpidDecoder::getChannelSamples(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSamples[Column][Dilogic][Channel]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Sum of Charges for specified pad +double HmpidDecoder::getChannelSum(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSum[Column][Dilogic][Channel]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Sum of Square Charges for specified pad +double HmpidDecoder::getChannelSquare(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSquares[Column][Dilogic][Channel]); +} + +/// Gets the Average Event Size value +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @returns The Average Event Size value ( 0 for wrong Equipment Id) +float HmpidDecoder::getAverageEventSize(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0.0); + } + return (mTheEquipments[EqInd]->mEventSizeAverage); +} + +/// Gets the Average Busy Time value +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @returns The Average Busy Time value ( 0 for wrong Equipment Id) +float HmpidDecoder::getAverageBusyTime(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0.0); + } + return (mTheEquipments[EqInd]->mBusyTimeAverage); +} + +// =================================================== +// Methods to dump info + +/// Prints on the standard output the table of decoding +/// errors for one equipment +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +void HmpidDecoder::dumpErrors(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return; + } + std::cout << "Dump Errors for the Equipment = " << EquipmId << std::endl; + for (int i = 0; i < MAXERRORS; i++) { + std::cout << sErrorDescription[i] << " = " << mTheEquipments[EqInd]->mErrors[i] << std::endl; + } + std::cout << " -------- " << std::endl; + return; +} + +/// Prints on the standard output a Table of statistical +/// decoding information for one equipment +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @type[in] The type of info. 0 = Entries, 1 = Sum, 2 = Sum of squares +void HmpidDecoder::dumpPads(int EquipmId, int type) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return; + } + int Module = EquipmId / 2; + int StartRow = (EquipmId % 2 == 1) ? 80 : 0; + int EndRow = (EquipmId % 2 == 1) ? 160 : 80; + std::cout << "Dump Pads for the Equipment = " << EquipmId << std::endl; + for (int c = 0; c < 144; c++) { + for (int r = StartRow; r < EndRow; r++) { + switch (type) { + case 0: + std::cout << getPadSamples(Module, r, c) << ","; + break; + case 1: + std::cout << getPadSum(Module, r, c) << ","; + break; + case 2: + std::cout << getPadSquares(Module, r, c) << ","; + break; + } + } + std::cout << std::endl; + } + std::cout << " -------- " << std::endl; + return; +} + +/// Prints on the standard output the decoded HMPID error field +/// @param[in] ErrorField : the HMPID readout error field +void HmpidDecoder::dumpHmpidError(int ErrorField) +{ + char printbuf[MAXHMPIDERRORS * MAXDESCRIPTIONLENGHT]; + if (decodeHmpidError(ErrorField, printbuf) == true) { + LOG(ERROR) << "HMPID Error field = " << ErrorField << " : " << printbuf; + } + return; +} + +/// Writes in a ASCCI File the complete report of the decoding +/// procedure +/// @param[in] *summaryFileName : the name of the output file +/// @throws TH_CREATEFILE Thrown if was not able to create the file +void HmpidDecoder::writeSummaryFile(char* summaryFileName) +{ + FILE* fs = fopen(summaryFileName, "w"); + if (fs == nullptr) { + printf("Error opening the file %s !\n", summaryFileName); + throw TH_CREATEFILE; + } + + fprintf(fs, "HMPID Readout Raw Data Decoding Summary File\n"); + fprintf(fs, "Equipment Id\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->getEquipmentId()); + } + fprintf(fs, "\n"); + + fprintf(fs, "Number of events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEvents); + } + fprintf(fs, "\n"); + + fprintf(fs, "Average Event Size\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%f\t", mTheEquipments[i]->mEventSizeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Total pads\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mTotalPads); + } + fprintf(fs, "\n"); + + fprintf(fs, "Average pads per event\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%f\t", mTheEquipments[i]->mPadsPerEventAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Busy Time average\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%e\t", mTheEquipments[i]->mBusyTimeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Event rate\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%e\t", 1 / mTheEquipments[i]->mBusyTimeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Number of Empty Events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEmptyEvents); + } + fprintf(fs, "\n"); + + fprintf(fs, "-------------Errors--------------------\n"); + fprintf(fs, "Wrong events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfWrongEvents); + } + fprintf(fs, "\n"); + + for (int j = 0; j < MAXERRORS; j++) { + fprintf(fs, "%s\t", sErrorDescription[j]); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mErrors[j]); + } + fprintf(fs, "\n"); + } + + fprintf(fs, "Total errors\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mTotalErrors); + } + fprintf(fs, "\n"); + + fclose(fs); + return; +} diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecoder2.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecoder2.cxx new file mode 100644 index 0000000000000..d5d592842d1a5 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HmpidDecoder2.cxx @@ -0,0 +1,1295 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidDecoder.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to decode HMPID Raw Data stream +/// \version 1.1 +/// \date 17/11/2020 + +/* ------ HISTORY --------- +*/ + +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" +#include "Headers/RAWDataHeader.h" +#include "HMPIDReconstruction/HmpidEquipment.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "DataFormatsHMP/Digit.h" + +using namespace o2::hmpid; + +// ============= HmpidDecoder Class implementation ======= + +/// Decoding Error Messages Definitions +char HmpidDecoder2::sErrorDescription[MAXERRORS][MAXDESCRIPTIONLENGHT] = {"Word that I don't known !", + "Row Marker Word with 0 words", + "Duplicated Pad Word !", + "Row Marker Wrong/Lost -> to EoE", + "Row Marker Wrong/Lost -> to EoE", + "Row Marker reports an ERROR !", + "Lost EoE Marker !", + "Double EoE marker", + "Wrong size definition in EoE Marker", + "Double Mark Word", "Wrong Size in Segment Marker", + "Lost EoS Marker !", + "HMPID Header Errors"}; + +/// HMPID Firmware Error Messages Definitions +char HmpidDecoder2::sHmpidErrorDescription[MAXHMPIDERRORS][MAXDESCRIPTIONLENGHT] = { + "L0 Missing", + "L1 is received without L0", + "L1A signal arrived before the L1 Latency", + "L1A signal arrived after the L1 Latency", + "L1A is missing or L1 timeout", + "L1A Message is missing or L1 Message"}; + +/// Constructor : accepts the number of equipments to define +/// The mapping is the default at P2 +/// Allocates instances for all defined equipments +/// normally it is equal to 14 +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +HmpidDecoder2::HmpidDecoder2(int numOfEquipments) +{ + mNumberOfEquipments = numOfEquipments; + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i] = new HmpidEquipment(ReadOut::FeeId(i), ReadOut::CruId(i), ReadOut::LnkId(i)); + } +} + +/// Constructor : accepts the number of equipments to define +/// and their complete address map +/// Allocates instances for all defined equipments +/// +/// The Address map is build from three array +/// @param[in] numOfEquipments : the number of equipments to define [1..14] +/// @param[in] *EqIds : the pointer to the Equipments ID array +/// @param[in] *CruIds : the pointer to the CRU ID array +/// @param[in] *LinkIds : the pointer to the Link ID array +HmpidDecoder2::HmpidDecoder2(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) +{ + mNumberOfEquipments = numOfEquipments; + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i] = new HmpidEquipment(EqIds[i], CruIds[i], LinkIds[i]); + } +} + +/// Destructor : remove the Equipments instances +HmpidDecoder2::~HmpidDecoder2() +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + delete mTheEquipments[i]; + } +} + +/// Init all the members variables. +void HmpidDecoder2::init() +{ + mVerbose = 0; + + mRDHAcceptedVersion = 6; + mRDHSize = sizeof(o2::header::RAWDataHeaderV6) / sizeof(uint32_t); + + mHeEvent = 0; + mHeBusy = 0; + mNumberWordToRead = 0; + mPayloadTail = 0; + + mHeFEEID = 0; + mHeSize = 0; + mHeVer = 0; + mHePrior = 0; + mHeStop = 0; + mHePages = 0; + mEquipment = 0; + + mHeOffsetNewPack = 0; + mHeMemorySize = 0; + + mHeDetectorID = 0; + mHeDW = 0; + mHeCruID = 0; + mHePackNum = 0; + mHePAR = 0; + mHePageNum = 0; + mHeLinkNum = 0; + mHeFirmwareVersion = 0; + mHeHmpidError = 0; + mHeBCDI = 0; + mHeORBIT = 0; + mHeTType = 0; + + mActualStreamPtr = nullptr; + mEndStreamPtr = nullptr; + mStartStreamPtr = nullptr; + + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + mTheEquipments[i]->resetPadMap(); + } + + mDigits.clear(); +} + +/// Returns the Equipment Index (Pointer of the array) converting +/// the FLP hardware coords (CRU_Id and Link_Id) +/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] +/// @param[in] LinkId : the Link ID [0..3] +/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) +int HmpidDecoder2::getEquipmentIndex(int CruId, int LinkId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { + return (i); + } + } + return (-1); +} + +/// Returns the Equipment Index (Pointer of the array) converting +/// the Equipment_ID (Firmaware defined Id AKA FFEID) +/// @param[in] EquipmentId : the Equipment ID [0..13] +/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) +int HmpidDecoder2::getEquipmentIndex(int EquipmentId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId() == EquipmentId) { + return (i); + } + } + return (-1); +} + +/// Returns the Equipment_ID converting the FLP hardware coords +/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] +/// @param[in] LinkId : the Link ID [0..3] +/// @returns EquipmentID : the ID of the Equipment [0..13] (-1 := error) +int HmpidDecoder2::getEquipmentID(int CruId, int LinkId) +{ + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { + return (mTheEquipments[i]->getEquipmentId()); + } + } + return (-1); +} + +/// Scans the BitMap of Raw Data File word and detect the type +/// and the parameters +/// @param[in] wp : the word to analyze +/// @param[out] *p1 : first parameter extract (if it exists) +/// @param[out] *p2 : second parameter extract (if it exists) +/// @param[out] *p3 : third parameter extract (if it exists) +/// @param[out] *p4 : fourth parameter extract (if it exists) +/// @returns Type of Word : the type of word [0..4] (0 := undetect) +int HmpidDecoder2::checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4) +{ + if ((wp & 0x0000ffff) == 0x000036A8 || (wp & 0x0000ffff) == 0x000032A8 || (wp & 0x0000ffff) == 0x000030A0 || (wp & 0x0800ffff) == 0x080010A0) { + *p2 = (wp & 0x03ff0000) >> 16; // Number of words of row + *p1 = wp & 0x0000ffff; + return (WTYPE_ROW); + } + if ((wp & 0xfff00000) >> 20 == 0xAB0) { + *p2 = (wp & 0x000fff00) >> 8; // Number of words of Segment + *p1 = (wp & 0xfff00000) >> 20; + *p3 = wp & 0x0000000F; + if (*p3 < 4 && *p3 > 0) { + return (WTYPE_EOS); + } + } + // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 + if ((wp & 0x0803FF80) == 0x08000080) { + *p1 = (wp & 0x07c00000) >> 22; + *p2 = (wp & 0x003C0000) >> 18; + *p3 = (wp & 0x0000007F); + if (*p1 < 25 && *p2 < 11) { + return (WTYPE_EOE); + } + } + if ((wp & 0x08000000) == 0) { // # this is a pad + // PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value + *p1 = (wp & 0x07c00000) >> 22; + *p2 = (wp & 0x003C0000) >> 18; + *p3 = (wp & 0x0003F000) >> 12; + *p4 = (wp & 0x00000FFF); + if (*p1 > 0 && *p1 < 25 && *p2 > 0 && *p2 < 11 && *p3 < 48) { + return (WTYPE_PAD); + } + } else { + return (WTYPE_NONE); + } + return (WTYPE_NONE); +} + +/// Checks if is a Raw Marker and extract the Row Size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *rowSize : the number of words of the row +/// @param[out] *mark : the row marker +/// @returns True if Row Marker is detected +bool HmpidDecoder2::isRowMarker(uint32_t wp, int* Err, int* rowSize, int* mark) +{ + if ((wp & 0x0000ffff) == 0x36A8 || (wp & 0x0000ffff) == 0x32A8 || (wp & 0x0000ffff) == 0x30A0 || (wp & 0x0800ffff) == 0x080010A0) { + *rowSize = (wp & 0x03ff0000) >> 16; // # Number of words of row + *mark = wp & 0x0000ffff; + *Err = false; + return (true); + } else { + *Err = true; + return (false); + } +} + +/// Checks if is a Segment Marker and extracts the Segment number and the size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *segSize : the number of words of the segment +/// @param[out] *Seg : the Segment number [1..3] +/// @param[out] *mark : the Segment Marker +/// @returns True if Segment Marker is detected +bool HmpidDecoder2::isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg, int* mark) +{ + *Err = false; + if ((wp & 0xfff00000) >> 20 == 0xAB0) { + *segSize = (wp & 0x000fff00) >> 8; // # Number of words of Segment + *mark = (wp & 0xfff00000) >> 20; + *Seg = wp & 0x0000000F; + if (*Seg > 3 || *Seg < 1) { + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << " Wrong segment Marker Word, bad Number of segment" << *Seg << "!" << std::endl; + } + *Err = true; + } + return (true); + } else { + return (false); + } +} + +/// Checks if is a PAD Word and extracts all the parameters +/// PAD map : 0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *Col : the column number [1..24] +/// @param[out] *Dilogic : the dilogic number [1..10] +/// @param[out] *Channel : the channel number [0..47] +/// @param[out] *Charge : the value of Charge [0..4095] +/// @returns True if PAD Word is detected +bool HmpidDecoder2::isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge) +{ + *Err = false; + // if ((wp & 0x08000000) != 0) { + if ((wp & 0x08000000) != 0) { + return (false); + } + *Col = (wp & 0x07c00000) >> 22; + *Dilogic = (wp & 0x003C0000) >> 18; + *Channel = (wp & 0x0003F000) >> 12; + *Charge = (wp & 0x00000FFF); + uint16_t mark, row; + mark = wp & 0x0ffff; + row = (wp & 0x03ff0000) >> 16; + + if (mark == 0x036A8 || mark == 0x032A8 || mark == 0x030A0 || mark == 0x010A0) { // # ! this is a pad + if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1 || row <= 490 || row > 10) { + return (false); + } + } else { + if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { + // LOG_WARNING << " Wrong Pad values Col=" << *Col << " Dilogic=" << *Dilogic << " Channel=" << *Channel << " Charge=" << *Charge << " wp:0x" << std::hex << wp << std::dec; + *Err = true; + return (false); + } + } + return (true); +} + +/// Checks if is a EoE Marker and extracts the Column, Dilogic and the size +/// @param[in] wp : the word to check +/// @param[out] *Err : true if an error is detected +/// @param[out] *Col : the column number [1..24] +/// @param[out] *Dilogic : the dilogic number [1..10] +/// @param[out] *Eoesize : the number of words for dilogic +/// @returns True if EoE marker is detected +bool HmpidDecoder2::isEoEmarker(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Eoesize) +{ + *Err = false; + // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 + if ((wp & 0x0803FF80) == 0x08000080) { + *Col = (wp & 0x07c00000) >> 22; + *Dilogic = (wp & 0x003C0000) >> 18; + *Eoesize = (wp & 0x0000007F); + if (*Col > 24 || *Dilogic > 10) { + if (mVerbose > 8) { + std::cout << "HMPID Decoder2 : [DEBUG] " + << " EoE size wrong definition. Col=" << *Col << " Dilogic=" << *Dilogic << std::endl; + } + *Err = true; + } + return (true); + } else { + return (false); + } +} + +/// Decode the HMPID error BitMap field (5 bits) and returns true if there are +/// errors and in addition the concat string that contains the error messages +/// ATTENTION : the char * outbuf MUST point to a 250 bytes buffer +/// @param[in] ErrorField : the HMPID Error field +/// @param[out] *outbuf : the output buffer that contains the error description +/// @returns True if EoE marker is detected +bool HmpidDecoder2::decodeHmpidError(int ErrorField, char* outbuf) +{ + int res = false; + outbuf[0] = '\0'; + for (int i = 0; i < MAXHMPIDERRORS; i++) { + if ((ErrorField & (0x01 << i)) != 0) { + res = true; + strcat(outbuf, sHmpidErrorDescription[i]); + } + } + return (res); +} + +/// This Decode the Raw Data Header, returns the EquipmentIndex +/// that is obtained with the FLP hardware coords +/// +/// ATTENTION : the 'EquipIndex' parameter and the mEquipment member +/// are different data: the first is the pointer in the Equipments instances +/// array, the second is the FEE_ID number +/// +/// The EVENT_NUMBER : actually is calculated from the ORBIT number +/// +/// @param[in] *streamPtrAdr : the pointer to the Header buffer +/// @param[out] *EquipIndex : the Index to the Equipment Object Array [0..13] +/// @returns True every time +/// @throws TH_WRONGEQUIPINDEX Thrown if the Equipment Index is out of boundary (Equipment not recognized) +int HmpidDecoder2::decodeHeader(uint32_t* streamPtrAdr, int* EquipIndex) +{ + uint32_t* buffer = streamPtrAdr; // Sets the pointer to buffer + o2::header::RAWDataHeaderV6* hpt = (o2::header::RAWDataHeaderV6*)buffer; + + /* + mHeFEEID = (buffer[0] & 0x000f0000) >> 16; + mHeSize = (buffer[0] & 0x0000ff00) >> 8; + mHeVer = (buffer[0] & 0x000000ff); + mHePrior = (buffer[1] & 0x000000FF); + mHeDetectorID = (buffer[1] & 0x0000FF00) >> 8; + mHeOffsetNewPack = (buffer[2] & 0x0000FFFF); + mHeMemorySize = (buffer[2] & 0xffff0000) >> 16; + mHeDW = (buffer[3] & 0xF0000000) >> 24; + mHeCruID = (buffer[3] & 0x0FF0000) >> 16; + mHePackNum = (buffer[3] & 0x0000FF00) >> 8; + mHeLinkNum = (buffer[3] & 0x000000FF); + mHeBCDI = (buffer[4] & 0x00000FFF); + mHeORBIT = buffer[5]; + mHeTType = buffer[8]; + mHePageNum = (buffer[9] & 0x0000FFFF); + mHeStop = (buffer[9] & 0x00ff0000) >> 16; + mHeBusy = (buffer[12] & 0xfffffe00) >> 9; + mHeFirmwareVersion = buffer[12] & 0x0000000f; + mHeHmpidError = (buffer[12] & 0x000001F0) >> 4; + mHePAR = buffer[13] & 0x0000FFFF; + */ + mHeFEEID = hpt->feeId; + mHeSize = hpt->headerSize; + mHeVer = hpt->version; + mHePrior = hpt->priority; + mHeDetectorID = hpt->sourceID; + mHeOffsetNewPack = hpt->offsetToNext; + mHeMemorySize = hpt->memorySize; + mHeDW = hpt->endPointID; + mHeCruID = hpt->cruID; + mHePackNum = hpt->packetCounter; + mHeLinkNum = hpt->linkID; + mHeBCDI = hpt->bunchCrossing; + mHeORBIT = hpt->orbit; + mHeTType = hpt->triggerType; + mHePageNum = hpt->pageCnt; + mHeStop = hpt->stop; + mHeBusy = (hpt->detectorField & 0xfffffe00) >> 9; + mHeFirmwareVersion = hpt->detectorField & 0x0000000f; + mHeHmpidError = (hpt->detectorField & 0x000001F0) >> 4; + mHePAR = hpt->detectorPAR; + + *EquipIndex = getEquipmentIndex(mHeCruID, mHeLinkNum); + // mEquipment = (*EquipIndex != -1) ? mTheEquipments[*EquipIndex]->getEquipmentId() : -1; + mEquipment = mHeFEEID & 0x000F; + mNumberWordToRead = ((mHeMemorySize - mHeSize) / sizeof(uint32_t)); + mPayloadTail = ((mHeOffsetNewPack - mHeMemorySize) / sizeof(uint32_t)); + + // ---- Event ID : Actualy based on ORBIT NUMBER and BC + mHeEvent = (mHeORBIT << 12) | mHeBCDI; + + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "FEE-ID=" << mHeFEEID << " HeSize=" << mHeSize << " HePrior=" << mHePrior << " Det.Id=" << mHeDetectorID << " HeMemorySize=" << mHeMemorySize << " HeOffsetNewPack=" << mHeOffsetNewPack << std::endl; + std::cout << " Equipment=" << mEquipment << " PakCounter=" << mHePackNum << " Link=" << mHeLinkNum << " CruID=" << mHeCruID << " DW=" << mHeDW << " BC=" << mHeBCDI << " ORBIT=" << mHeORBIT << std::endl; + std::cout << " TType=" << mHeTType << " HeStop=" << mHeStop << " PagesCounter=" << mHePageNum << " FirmVersion=" << mHeFirmwareVersion << " BusyTime=" << mHeBusy << " Error=" << mHeHmpidError << " PAR=" << mHePAR << std::endl; + std::cout << " EquIdx = " << *EquipIndex << " Event = " << mHeEvent << " Payload : Words to read=" << mNumberWordToRead << " PailoadTail=" << mPayloadTail << std::endl; + } + if (*EquipIndex == -1) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "ERROR ! Bad equipment Number: " << mEquipment << std::endl; + } + throw TH_WRONGEQUIPINDEX; + } + // std::cout << "HMPID ! Exit decode header" << std::endl; + return (true); +} + +/// Updates some information related to the Event +/// this function is called at the end of the event +/// @param[in] *eq : the pointer to the Equipment Object +void HmpidDecoder2::updateStatistics(HmpidEquipment* eq) +{ + eq->mPadsPerEventAverage = ((eq->mPadsPerEventAverage * (eq->mNumberOfEvents - 1)) + eq->mSampleNumber) / (eq->mNumberOfEvents); + eq->mEventSizeAverage = ((eq->mEventSizeAverage * (eq->mNumberOfEvents - 1)) + eq->mEventSize) / (eq->mNumberOfEvents); + eq->mBusyTimeAverage = ((eq->mBusyTimeAverage * eq->mBusyTimeSamples) + eq->mBusyTimeValue) / (++(eq->mBusyTimeSamples)); + if (eq->mSampleNumber == 0) { + eq->mNumberOfEmptyEvents += 1; + } + if (eq->mErrorsCounter > 0) { + eq->mNumberOfWrongEvents += 1; + } + eq->mTotalPads += eq->mSampleNumber; + eq->mTotalErrors += eq->mErrorsCounter; + + //std::cout << ">>>updateStatistics() >>> "<< eq->getEquipmentId() << "="<< eq->mNumberOfEvents<<" :" << eq->mEventSize <<","<< eq->mTotalPads << ", " << eq->mSampleNumber << std::endl; + + return; +} + +/// Evaluates the content of the header and detect the change of the event +/// with the relevant updates... +/// @param[in] EquipmentIndex : the pointer to the Array of Equipments Array +/// @returns the Pointer to the modified Equipment object +HmpidEquipment* HmpidDecoder2::evaluateHeaderContents(int EquipmentIndex) +{ + if (EquipmentIndex < 0 || EquipmentIndex > 13) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "Bad Equipment number !" << EquipmentIndex << std::endl; + } + throw TH_WRONGEQUIPINDEX; + } + HmpidEquipment* eq = mTheEquipments[EquipmentIndex]; + if (mHeEvent != eq->mEventNumber) { // Is a new event + if (eq->mEventNumber != OUTRANGEEVENTNUMBER) { // skip the first + updateStatistics(eq); // update previous statistics + } + eq->mNumberOfEvents++; + eq->mEventNumber = mHeEvent; + eq->mBusyTimeValue = mHeBusy * 0.00000005; + eq->mEventSize = 0; // reset the event + eq->mSampleNumber = 0; + eq->mErrorsCounter = 0; + mIntReco = {(uint16_t)mHeBCDI, (uint32_t)mHeORBIT}; + } + eq->mEventSize += mNumberWordToRead * sizeof(uint32_t); // Calculate the size in bytes + if (mHeHmpidError != 0) { + std::cout << "HMPID Header reports an error : " << mHeHmpidError << std::endl; + dumpHmpidError(mHeHmpidError); + eq->setError(ERR_HMPID); + } + // std::cout << ".. end evaluateHeaderContents = " << eq->mEventNumber << std::endl; + return (eq); +} + +/// --------------- Decode One Page from Data Buffer --------------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer +void HmpidDecoder2::decodePage(uint32_t** streamBuf) +{ + mActualStreamPtr = *streamBuf; + int equipmentIndex; + try { + getHeaderFromStream(streamBuf); + } catch (int e) { + // The stream end ! + if (mVerbose > 8) { + std::cout << "HMPID Decoder2 : [DEBUG] " + << "End main decoding loop !" << std::endl; + } + throw TH_BUFFEREMPTY; + } + try { + decodeHeader(*streamBuf, &equipmentIndex); + } catch (int e) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "Failed to decode the Header !" << std::endl; + } + throw TH_WRONGHEADER; + } + HmpidEquipment* eq; + try { + eq = evaluateHeaderContents(equipmentIndex); + } catch (int e) { + throw TH_WRONGHEADER; + } + + uint32_t wpprev = 0; + uint32_t wp = 0; + int newOne = true; + int p1, p2, p3, p4; + int error; + int type; + bool isIt; + + int payIndex = 0; + while (payIndex < mNumberWordToRead) { //start the payload loop word by word + if (newOne == true) { + wpprev = wp; + if (!getWordFromStream(&wp)) { // end the stream + break; + } + type = checkType(wp, &p1, &p2, &p3, &p4); + if (type == WTYPE_NONE) { + if (eq->mWillBePad == true) { // try to recover the first pad ! + type = checkType((wp & 0xF7FFFFFF), &p1, &p2, &p3, &p4); + if (type == WTYPE_PAD && p3 == 0 && eq->mWordsPerDilogicCounter == 0) { + newOne = false; // # reprocess as pad + continue; + } + } + eq->setError(ERR_NOTKNOWN); + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + payIndex++; + continue; + } + } + if (mEquipment == 8) { + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + "Event" + << eq->mEventNumber << " >" << std::hex << wp << std::dec << "<" << type << std::endl; + } + } + if (eq->mWillBeRowMarker == true) { // #shoud be a Row Marker + if (type == WTYPE_ROW) { + eq->mColumnCounter++; + eq->mWordsPerSegCounter++; + eq->mRowSize = p2; + switch (p2) { + case 0: // Empty column + eq->setError(ERR_ROWMARKEMPTY); + eq->mWillBeRowMarker = true; + break; + case 0x3FF: // Error in column + eq->setError(ERR_ROWMARKERROR); + eq->mWillBeRowMarker = true; + break; + case 0x3FE: // Masked column + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "Equip=" << mEquipment << "The column=" << (eq->mSegment) * 8 + eq->mColumnCounter << " is Masked !" << std::endl; + } + eq->mWillBeRowMarker = true; + break; + default: + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + break; + } + newOne = true; + } else { + if (wp == wpprev) { + eq->setError(ERR_DUPLICATEPAD); + newOne = true; + } else if (type == WTYPE_EOE) { // # Could be a EoE + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKWRONG); + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } else if (type == WTYPE_PAD) { //# Could be a PAD + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKLOST); + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } else if (type == WTYPE_EOS) { // # Could be a EoS + eq->mWillBeRowMarker = false; + eq->mWillBeSegmentMarker = true; + newOne = false; + } else { + eq->mColumnCounter++; + eq->setError(ERR_ROWMARKLOST); + eq->mWillBeRowMarker = false; + eq->mWillBePad = true; + newOne = true; + } + } + } else if (eq->mWillBePad == true) { // # We expect a pad + //# PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value + // c = 1..24 d = 1..10 n = 0..47 + if (type == WTYPE_PAD) { + newOne = true; + if (wp == wpprev) { + eq->setError(ERR_DUPLICATEPAD); + } else if (p1 != (eq->mSegment * 8 + eq->mColumnCounter)) { // # Manage + // We try to recover the RowMarker misunderstanding + isIt = isRowMarker(wp, &error, &p2, &p1); + if (isIt == true && error == false) { + type = WTYPE_ROW; + newOne = false; + eq->mWillBeEoE = true; + eq->mWillBePad = false; + } else { + eq->mColumnCounter = p1 % 8; + } + } else { + setPad(eq, p1 - 1, p2 - 1, p3, p4); + if (mEquipment == 8) { + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "Event" << eq->mEventNumber << " >" << p1 - 1 << "," << p2 - 1 << "," << p3 << "," << p4 << std::endl; + } + } + eq->mWordsPerDilogicCounter++; + eq->mSampleNumber++; + if (p3 == 47) { + eq->mWillBeEoE = true; + eq->mWillBePad = false; + } + } + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + } else if (type == WTYPE_EOE) { //# the pads are end ok + eq->mWillBeEoE = true; + eq->mWillBePad = false; + newOne = false; + } else if (type == WTYPE_ROW) { // # We Lost the EoE ! + // We try to recover the PAD misunderstanding + isIt = isPadWord(wp, &error, &p1, &p2, &p3, &p4); + if (isIt == true && error == false) { + type = WTYPE_PAD; + newOne = false; // # reprocess as pad + } else { + eq->setError(ERR_LOSTEOEMARK); + eq->mWillBeRowMarker = true; + eq->mWillBePad = false; + newOne = false; + } + } else if (type == WTYPE_EOS) { // # We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + eq->mWillBeSegmentMarker = true; + eq->mWillBePad = false; + newOne = false; + } + } else if (eq->mWillBeEoE == true) { // # We expect a EoE + if (type == WTYPE_EOE) { + eq->mWordsPerRowCounter++; + eq->mWordsPerSegCounter++; + if (wpprev == wp) { + eq->setError(ERR_DOUBLEEOEMARK); + } else if (p3 != eq->mWordsPerDilogicCounter) { + eq->setError(ERR_WRONGSIZEINEOE); + } + eq->mWordsPerDilogicCounter = 0; + if (p2 == 10) { + if (p1 % 8 != 0) { // # we expect the Row Marker + eq->mWillBeRowMarker = true; + } else { + eq->mWillBeSegmentMarker = true; + } + } else { + eq->mWillBePad = true; + } + eq->mWillBeEoE = false; + newOne = true; + } else if (type == WTYPE_EOS) { // We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + eq->mWillBeSegmentMarker = true; + eq->mWillBeEoE = false; + newOne = false; + } else if (type == WTYPE_ROW) { //# We Lost the EoE ! + eq->setError(ERR_LOSTEOEMARK); + eq->mWillBeRowMarker = true; + eq->mWillBeEoE = false; + newOne = false; + } else if (type == WTYPE_PAD) { // # We Lost the EoE ! + int typb, p1b, p2b, p3b, p4b; + typb = checkType((wp | 0x08000000), &p1b, &p2b, &p3b, &p4b); + if (typb == WTYPE_EOE && p3b == 48) { + type = typb; + p1 = p1b; + p2 = p2b; + p3 = p3b; + p4 = p4b; + newOne = false; // # reprocess as EoE + } else { + eq->setError(ERR_LOSTEOEMARK); + eq->mWillBePad = true; + eq->mWillBeEoE = false; + newOne = false; + } + } + } else if (eq->mWillBeSegmentMarker == true) { // # We expect a EoSegment + if (wpprev == wp) { + eq->setError(ERR_DOUBLEMARKWORD); + newOne = true; + } else if (type == 2) { + if (abs(eq->mWordsPerSegCounter - p2) > 5) { + eq->setError(ERR_WRONGSIZESEGMENTMARK); + } + eq->mWordsPerSegCounter = 0; + eq->mWordsPerRowCounter = 0; + eq->mColumnCounter = 0; + eq->mSegment = p3 % 3; + eq->mWillBeRowMarker = true; + eq->mWillBeSegmentMarker = false; + newOne = true; + } else { + eq->setError(ERR_LOSTEOSMARK); + eq->mWillBeSegmentMarker = false; + eq->mWillBeRowMarker = true; + newOne = false; + } + } + if (newOne) { + payIndex += 1; + } + } + for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail + getWordFromStream(&wp); + } + *streamBuf = mActualStreamPtr; +} + +/// --------------- Read Raw Data Buffer --------------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +bool HmpidDecoder2::decodeBuffer() +{ + // ---------resets the PAdMap----------- + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + mTheEquipments[i]->resetPadMap(); + mTheEquipments[i]->resetErrors(); + } + + uint32_t* streamBuf = mStartStreamPtr; + if (mVerbose > 8) { + std::cout << "HMPID Decoder2 : [DEBUG] " + << "Enter decoding !" << std::endl; + } + + // Input Stream Main Loop + while (true) { + try { + decodePage(&streamBuf); + } catch (int e) { + if (mVerbose > 8) { + std::cout << "HMPID Decoder2 : [DEBUG] " + << "End main buffer decoding loop !" << std::endl; + } + break; + } + } // this is the end of stream + + // cycle in order to update info for the last event + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->mNumberOfEvents > 0) { + updateStatistics(mTheEquipments[i]); + } + } + return (true); +} + +/// ----- Sets the Pad ! ------ +/// this is an overloaded method. In this version the value of the charge +/// is used to update the statistical matrix of the base class +/// +/// @param[in] *eq : the pointer to the Equipment object +/// @param[in] col : the column [0..23] +/// @param[in] dil : the dilogic [0..9] +/// @param[in] ch : the channel [0..47] +/// @param[in] charge : the value of the charge +void HmpidDecoder2::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) +{ + eq->setPad(col, dil, ch, charge); + mDigits.push_back(o2::hmpid::Digit(charge, eq->getEquipmentId(), col, dil, ch)); + //std::cout << "DI " << mDigits.back() << " "<<col<<","<< dil<<","<< ch<<"="<< charge<<std::endl; + return; +} + +/// --------- Decode One Page from Data Buffer with Fast Decoding -------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer +void HmpidDecoder2::decodePageFast(uint32_t** streamBuf) +{ + mActualStreamPtr = *streamBuf; + int equipmentIndex; + try { + getHeaderFromStream(streamBuf); + } catch (int e) { + // The stream end ! + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "End Fast Page decoding loop !" << std::endl; + } + throw TH_BUFFEREMPTY; + } + try { + decodeHeader(*streamBuf, &equipmentIndex); + } catch (int e) { + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "Failed to decode the Header !" << std::endl; + } + throw TH_WRONGHEADER; + } + + HmpidEquipment* eq; + try { + eq = evaluateHeaderContents(equipmentIndex); + } catch (int e) { + throw TH_WRONGHEADER; + } + + uint32_t wpprev = 0; + uint32_t wp = 0; + int newOne = true; + int Column, Dilogic, Channel, Charge; + int pwer; + int payIndex = 0; + while (payIndex < mNumberWordToRead) { //start the payload loop word by word + wpprev = wp; + if (!getWordFromStream(&wp)) { // end the stream + //mPayloadTail = 0; + throw TH_BUFFEREMPTY; + } + if (wp == wpprev) { + if (mVerbose > 8) { + std::cout << "HMPID Decoder2 : [DEBUG] " + << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << Column << "]" << std::endl; + } + } else { + if (isPadWord(wp, &pwer, &Column, &Dilogic, &Channel, &Charge) == true) { + if (pwer != true) { + setPad(eq, Column - 1, Dilogic - 1, Channel, Charge); + eq->mSampleNumber++; + } + } + } + payIndex += 1; + } + for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail + if (!getWordFromStream(&wp)) { + throw TH_BUFFEREMPTY; + } + } + *streamBuf = mActualStreamPtr; + return; +} + +/// ---------- Read Raw Data Buffer with Fast Decoding ---------- +/// Read the stream, decode the contents and store resuls. +/// Fast alghoritm : no parsing of control words ! +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +bool HmpidDecoder2::decodeBufferFast() +{ + // ---------resets the PAdMap----------- + for (int i = 0; i < mNumberOfEquipments; i++) { + mTheEquipments[i]->init(); + mTheEquipments[i]->resetPadMap(); + } + uint32_t* streamBuf = mStartStreamPtr; + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << "Enter FAST decoding !" << std::endl; + } + // Input Stream Main Loop + while (true) { + try { + decodePageFast(&streamBuf); + } catch (int e) { + if (mVerbose > 6) { + std::cout << "HMPID Decoder2 : [INFO] " + << " End Buffer Fast Decoding !" << std::endl; + } + break; + } + } // this is the end of stream + + // cycle in order to update info for the last event + for (int i = 0; i < mNumberOfEquipments; i++) { + if (mTheEquipments[i]->mNumberOfEvents > 0) { + updateStatistics(mTheEquipments[i]); + } + } + return (true); +} + +// ========================================================= + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Number of entries for specified pad +uint16_t HmpidDecoder2::getPadSamples(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSamples[c][d][h]); +} + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Sum of Charges for specified pad +double HmpidDecoder2::getPadSum(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSum[c][d][h]); +} + +/// Getter method to extract Statistic Data in Digit Coords +/// @param[in] Module : the HMPID Module number [0..6] +/// @param[in] Column : the HMPID Module Column number [0..143] +/// @param[in] Row : the HMPID Module Row number [0..159] +/// @returns The Sum of Square Charges for specified pad +double HmpidDecoder2::getPadSquares(int Module, int Row, int Column) +{ + int e, c, d, h; + o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); + int EqInd = getEquipmentIndex(e); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSquares[c][d][h]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Number of Entries for specified pad +uint16_t HmpidDecoder2::getChannelSamples(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSamples[Column][Dilogic][Channel]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Sum of Charges for specified pad +double HmpidDecoder2::getChannelSum(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSum[Column][Dilogic][Channel]); +} + +/// Getter method to extract Statistic Data in Hardware Coords +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @param[in] Column : the HMPID Module Column number [0..23] +/// @param[in] Dilogic : the HMPID Module Row number [0..9] +/// @param[in] Channel : the HMPID Module Row number [0..47] +/// @returns The Sum of Square Charges for specified pad +double HmpidDecoder2::getChannelSquare(int EquipmId, int Column, int Dilogic, int Channel) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0); + } + return (mTheEquipments[EqInd]->mPadSquares[Column][Dilogic][Channel]); +} + +/// Gets the Average Event Size value +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @returns The Average Event Size value ( 0 for wrong Equipment Id) +float HmpidDecoder2::getAverageEventSize(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0.0); + } + return (mTheEquipments[EqInd]->mEventSizeAverage); +} + +/// Gets the Average Busy Time value +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @returns The Average Busy Time value ( 0 for wrong Equipment Id) +float HmpidDecoder2::getAverageBusyTime(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return (0.0); + } + return (mTheEquipments[EqInd]->mBusyTimeAverage); +} + +// =================================================== +// Methods to dump info + +/// Prints on the standard output the table of decoding +/// errors for one equipment +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +void HmpidDecoder2::dumpErrors(int EquipmId) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return; + } + std::cout << "Dump Errors for the Equipment = " << EquipmId << std::endl; + for (int i = 0; i < MAXERRORS; i++) { + std::cout << sErrorDescription[i] << " = " << mTheEquipments[EqInd]->mErrors[i] << std::endl; + } + std::cout << " -------- " << std::endl; + return; +} + +/// Prints on the standard output a Table of statistical +/// decoding information for one equipment +/// @param[in] EquipmId : the HMPID EquipmentId [0..13] +/// @type[in] The type of info. 0 = Entries, 1 = Sum, 2 = Sum of squares +void HmpidDecoder2::dumpPads(int EquipmId, int type) +{ + int EqInd = getEquipmentIndex(EquipmId); + if (EqInd < 0) { + return; + } + int Module = EquipmId / 2; + int StartRow = (EquipmId % 2 == 1) ? 80 : 0; + int EndRow = (EquipmId % 2 == 1) ? 160 : 80; + std::cout << "Dump Pads for the Equipment = " << EquipmId << std::endl; + for (int c = 0; c < 144; c++) { + for (int r = StartRow; r < EndRow; r++) { + switch (type) { + case 0: + std::cout << getPadSamples(Module, r, c) << ","; + break; + case 1: + std::cout << getPadSum(Module, r, c) << ","; + break; + case 2: + std::cout << getPadSquares(Module, r, c) << ","; + break; + } + } + std::cout << std::endl; + } + std::cout << " -------- " << std::endl; + return; +} + +/// Prints on the standard output the decoded HMPID error field +/// @param[in] ErrorField : the HMPID readout error field +void HmpidDecoder2::dumpHmpidError(int ErrorField) +{ + char printbuf[MAXHMPIDERRORS * MAXDESCRIPTIONLENGHT + 255]; + if (decodeHmpidError(ErrorField, printbuf) == true) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "HMPID Error field = " << ErrorField << " : " << printbuf << std::endl; + } + } + return; +} + +/// Writes in a ASCCI File the complete report of the decoding +/// procedure +/// @param[in] *summaryFileName : the name of the output file +/// @throws TH_CREATEFILE Thrown if was not able to create the file +void HmpidDecoder2::writeSummaryFile(char* summaryFileName) +{ + FILE* fs = fopen(summaryFileName, "w"); + if (fs == nullptr) { + printf("Error opening the file %s !\n", summaryFileName); + throw TH_CREATEFILE; + } + + fprintf(fs, "HMPID Readout Raw Data Decoding Summary File\n"); + fprintf(fs, "Equipment Id\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->getEquipmentId()); + } + fprintf(fs, "\n"); + + fprintf(fs, "Number of events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEvents); + } + fprintf(fs, "\n"); + + fprintf(fs, "Average Event Size\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%f\t", mTheEquipments[i]->mEventSizeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Total pads\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mTotalPads); + } + fprintf(fs, "\n"); + + fprintf(fs, "Average pads per event\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%f\t", mTheEquipments[i]->mPadsPerEventAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Busy Time average\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%e\t", mTheEquipments[i]->mBusyTimeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Event rate\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%e\t", 1 / mTheEquipments[i]->mBusyTimeAverage); + } + fprintf(fs, "\n"); + + fprintf(fs, "Number of Empty Events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEmptyEvents); + } + fprintf(fs, "\n"); + + fprintf(fs, "-------------Errors--------------------\n"); + fprintf(fs, "Wrong events\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfWrongEvents); + } + fprintf(fs, "\n"); + + for (int j = 0; j < MAXERRORS; j++) { + fprintf(fs, "%s\t", sErrorDescription[j]); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mErrors[j]); + } + fprintf(fs, "\n"); + } + + fprintf(fs, "Total errors\t"); + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + fprintf(fs, "%d\t", mTheEquipments[i]->mTotalErrors); + } + fprintf(fs, "\n"); + + fclose(fs); + return; +} + +/// Gets a sized chunk from the stream. The stream pointers members are updated +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @param[in] Size : the dimension of the chunk (words) +/// @returns True every time +/// @throw TH_WRONGBUFFERDIM Buffer length shorter then the requested +bool HmpidDecoder2::getBlockFromStream(uint32_t** streamPtr, uint32_t Size) +{ + *streamPtr = mActualStreamPtr; + mActualStreamPtr += Size; + if (mActualStreamPtr > mEndStreamPtr) { + // std::cout << " getBlockFromStream : StPtr=" << mActualStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << Size << std::endl; + // std::cout << "Beccato " << std::endl; + throw TH_WRONGBUFFERDIM; + return (false); + } + return (true); +} + +/// Gets the Header Block from the stream. +/// @param[in] **streamPtr : the pointer to the memory buffer +/// @returns True if the header is read +bool HmpidDecoder2::getHeaderFromStream(uint32_t** streamPtr) +{ + return (getBlockFromStream(streamPtr, mRDHSize)); +} + +/// Gets a Word from the stream. +/// @param[in] *word : the buffer for the read word +/// @returns True if the operation end well +bool HmpidDecoder2::getWordFromStream(uint32_t* word) +{ + uint32_t* appo; + if (getBlockFromStream(&appo, 1)) { + *word = *mActualStreamPtr; + return (true); + } + return (false); +} + +/// Setup the Input Stream with a Memory Pointer +/// the buffer length is in byte, some controls are done +/// +/// @param[in] *Buffer : the pointer to Memory buffer +/// @param[in] BufferLen : the length of the buffer (bytes) +/// @returns True if the stream is set +/// @throws TH_NULLBUFFERPOINTER Thrown if the pointer to the buffer is NULL +/// @throws TH_BUFFEREMPTY Thrown if the buffer is empty +/// @throws TH_WRONGBUFFERDIM Thrown if the buffer len is less then one header +bool HmpidDecoder2::setUpStream(void* Buffer, long BufferLen) +{ + long wordsBufferLen = BufferLen / (sizeof(int32_t) / sizeof(char)); // Converts the len in words + if (Buffer == nullptr) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "Raw data buffer null Pointer ! " << std::endl; + } + throw TH_NULLBUFFERPOINTER; + } + if (wordsBufferLen == 0) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "Raw data buffer Empty ! " << std::endl; + } + throw TH_BUFFEREMPTY; + } + if (wordsBufferLen < 16) { + if (mVerbose > 1) { + std::cout << "HMPID Decoder2 : [ERROR] " + << "Raw data buffer less then the Header Dimension = " << wordsBufferLen << std::endl; + } + throw TH_WRONGBUFFERDIM; + } + + mActualStreamPtr = (uint32_t*)Buffer; // sets the pointer to the Buffer + mEndStreamPtr = ((uint32_t*)Buffer) + wordsBufferLen; //sets the End of buffer + mStartStreamPtr = ((uint32_t*)Buffer); + // std::cout << " setUpStrem : StPtr=" << mStartStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << wordsBufferLen << std::endl; + return (true); +} diff --git a/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx b/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx new file mode 100644 index 0000000000000..17ece2b438b00 --- /dev/null +++ b/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx @@ -0,0 +1,170 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidEquipments.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to describe HMPID Equipment +/// \version 1.0 +/// \date 24 set 2020 + +/* ------ HISTORY --------- +*/ + +#include "HMPIDReconstruction/HmpidEquipment.h" + +using namespace o2::hmpid; + +// ============= HmpidEquipment Class implementation ======= + +/// Constructor : map the Equipment_ID with the CRU_Id and Link_Id +/// +/// @param[in] Equipment : the HMPID EquipmentId [0..13] +/// @param[in] Cru : the HMPID Cru [0..3] (FLP160 = 0,1 FLP161 = 2,3) +/// @param[in] Link : the FLP Link [0..3] +HmpidEquipment::HmpidEquipment(int Equipment, int Cru, int Link) +{ + mEquipmentId = Equipment; + mCruId = Cru; + mLinkId = Link; + mWordsPerRowCounter = 0; + mBusyTimeAverage = 0; + mBusyTimeSamples = 0; + mBusyTimeValue = 0; + mTotalErrors = 0; + mTotalPads = 0; + mNumberOfEmptyEvents = 0; + mNumberOfEvents = 0; + mNumberOfWrongEvents = 0; + mWordsPerDilogicCounter = 0; + mWordsPerRowCounter = 0; + mWordsPerSegCounter = 0; + mEventSizeAverage = 0; + mErrorsCounter = 0; + mEventNumber = 0; + mEventSize = 0; + mPadsPerEventAverage = 0; + mSegment = 0; + mWillBeEoE = false; + mWillBePad = false; + mWillBeRowMarker = false; + mWillBeSegmentMarker = false; + mSampleNumber = 0; + mEventSizeAverage = 0; + mColumnCounter = 0; + mRowSize = 0; + mErrorPadsPerEvent = 0; + return; +} + +/// Destructor : do nothing +HmpidEquipment::~HmpidEquipment() +{ + return; +} + +/// Inits the members for the decoding +void HmpidEquipment::init() +{ + mWillBeRowMarker = true; + mWillBeSegmentMarker = false; + mWillBeEoE = false; + mWillBePad = false; + mRowSize = 0; + mSegment = 0; + mColumnCounter = 0; + mWordsPerRowCounter = 0; + mWordsPerSegCounter = 0; + mWordsPerDilogicCounter = 0; + mSampleNumber = 0; + mErrorsCounter = 0; + mErrorPadsPerEvent = 0; + + mEventNumber = OUTRANGEEVENTNUMBER; // The Magic out-range event number + mNumberOfEvents = 0; + + mBusyTimeValue = 0.0; + mBusyTimeAverage = 0.0; + mBusyTimeSamples = 0; + + mEventSizeAverage = 0.0; + mEventSize = 0; + + mPadsPerEventAverage = 0.0; + + mNumberOfEmptyEvents = 0; + mNumberOfWrongEvents = 0; + mTotalPads = 0; + mTotalErrors = 0; + + return; +} + +/// Resets the matrix that contains the results of the decoding +void HmpidEquipment::resetPadMap() +{ + for (int r = 0; r < Geo::N_COLUMNS; r++) { + for (int d = 0; d < Geo::N_DILOGICS; d++) { + for (int c = 0; c < Geo::N_CHANNELS; c++) { + mPadSamples[r][d][c] = 0; + mPadSum[r][d][c] = 0.0; + mPadSquares[r][d][c] = 0.0; + } + } + } + return; +} + +/// Resets the decoding errors statistics +void HmpidEquipment::resetErrors() +{ + for (int i = 0; i < MAXERRORS; i++) { + mErrors[i] = 0; + } + return; +} + +/// Setup an error by type +/// TODO : control of array boundary +/// @param[in] ErrType : the Decoding error type [0..MAXERRORS] +void HmpidEquipment::setError(int ErrType) +{ + mErrors[ErrType]++; + mErrorsCounter++; + return; +} + +/// Set the charge value of a pad into the three statistics +/// matrix : Entries, Sum of charge, Sum of Charge squares +/// @param[in] col : column [0..23] +/// @param[in] dil : dilogic [0..9] +/// @param[in] cha : channel [0..47] +/// @param[in] charge : the value of the charge +void HmpidEquipment::setPad(int col, int dil, int cha, uint16_t charge) +{ + mPadSamples[col][dil][cha]++; + mPadSum[col][dil][cha] += (double)charge; + mPadSquares[col][dil][cha] += (double)charge * (double)charge; + return; +} + +/// Return the EquipmentId with the check of CRU_Id and Link_Id +/// @param[in] cru : FLP CRU Id [0..3] +/// @param[in] link : CRU Link Id [0..3] +/// @returns the Equipment Id +int HmpidEquipment::getEquipmentId(int cru, int link) +{ + if (cru == mCruId && link == mLinkId) { + return (mEquipmentId); + } else { + return (-1); + } +} diff --git a/Detectors/HMPID/simulation/CMakeLists.txt b/Detectors/HMPID/simulation/CMakeLists.txt index 75a4e0d973265..17be7cfa9e403 100644 --- a/Detectors/HMPID/simulation/CMakeLists.txt +++ b/Detectors/HMPID/simulation/CMakeLists.txt @@ -1,19 +1,28 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(HMPIDSimulation - SOURCES src/Detector.cxx src/HMPIDDigitizer.cxx - PUBLIC_LINK_LIBRARIES O2::HMPIDBase) + SOURCES src/HMPIDDigitizer.cxx + src/Detector.cxx + src/HmpidCoder2.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDBase + O2::SimulationDataFormat + O2::DataFormatsHMP + O2::DetectorsBase + O2::DetectorsRaw + ROOT::Physics) o2_target_root_dictionary(HMPIDSimulation - HEADERS include/HMPIDSimulation/Detector.h + HEADERS include/HMPIDSimulation/HmpidCoder2.h + include/HMPIDSimulation/Detector.h include/HMPIDSimulation/HMPIDDigitizer.h) diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h index 328478c6a5307..6b1b1f2809c90 100644 --- a/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include <vector> #include "DetectorsBase/Detector.h" -#include "HMPIDBase/Hit.h" +#include "DataFormatsHMP/Hit.h" class TGeoVolume; class TGeoHMatrix; @@ -28,7 +29,7 @@ class Detector : public o2::base::DetImpl<Detector> Detector(Bool_t active = true); ~Detector() override = default; - std::vector<HitType>* getHits(int iColl) const + std::vector<o2::hmpid::HitType>* getHits(int iColl) const { if (iColl == 0) { return mHits; @@ -38,7 +39,7 @@ class Detector : public o2::base::DetImpl<Detector> void InitializeO2Detector() override; bool ProcessHits(FairVolume* v) override; - HitType* AddHit(float x, float y, float z, float time, float energy, Int_t trackId, Int_t detId); + o2::hmpid::HitType* AddHit(float x, float y, float z, float time, float energy, Int_t trackId, Int_t detId); void GenFee(float qtot); Bool_t IsLostByFresnel(); float Fresnel(float ene, float pdoti, Bool_t pola); @@ -61,7 +62,7 @@ class Detector : public o2::base::DetImpl<Detector> // copy constructor for CloneModule Detector(const Detector&); - std::vector<HitType>* mHits = nullptr; ///!< Collection of HMPID hits + std::vector<o2::hmpid::HitType>* mHits = nullptr; ///!< Collection of HMPID hits enum EMedia { kAir = 1, kRoha = 2, diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h index d33aa0ff8bbfd..9ebac852f8e8f 100644 --- a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,8 @@ #ifndef DETECTORS_HMPID_SIMULATION_INCLUDE_HMPIDSIMULATION_HMPIDDIGITIZER_H_ #define DETECTORS_HMPID_SIMULATION_INCLUDE_HMPIDSIMULATION_HMPIDDIGITIZER_H_ -#include "HMPIDBase/Digit.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" #include "HMPIDSimulation/Detector.h" // for the hit #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -44,10 +46,12 @@ class HMPIDDigitizer // for the first trigger no busy check necessary mCurrentTriggerTime = timeNS; mReadoutCounter++; + mBc = o2::InteractionRecord::ns2bc(mCurrentTriggerTime, mOrbit); return true; } else { if ((timeNS - mCurrentTriggerTime) > BUSYTIME) { mCurrentTriggerTime = timeNS; + mBc = o2::InteractionRecord::ns2bc(mCurrentTriggerTime, mOrbit); mReadoutCounter++; return true; } else { @@ -56,6 +60,9 @@ class HMPIDDigitizer } } + uint32_t getOrbit() { return mOrbit; }; + uint16_t getBc() { return mBc; }; + void setEventID(int eventID) { mEventID = eventID; } void setSrcID(int sID) { mSrcID = sID; } @@ -83,6 +90,9 @@ class HMPIDDigitizer // (using noise and other tables for pad) double mCurrentTriggerTime = 0.; + uint32_t mOrbit = 0; + uint16_t mBc = 0; + int mEventID = 0; int mSrcID = 0; diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h new file mode 100644 index 0000000000000..2ec5a1fd13f73 --- /dev/null +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidCoder.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to code HMPID Raw Data file +/// + +#ifndef COMMON_HMPIDCODER2_H_ +#define COMMON_HMPIDCODER2_H_ + +#include <cstdio> +#include <cstdint> +#include <iostream> +#include <cstring> +#include <cmath> +#include <cstdlib> +#include <vector> +#include <memory> + +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" + +#include "FairLogger.h" +#include "HMPIDBase/Geo.h" +#include "DataFormatsHMP/Digit.h" + +// ---- RDH 6 standard dimension ------- +#define RAWBLOCKDIMENSION_W 2048 +#define HEADERDIMENSION_W 16 +#define PAYLOADDIMENSION_W 2032 +#define PAYLOADMAXSPACE_W 2028 + +// ---- CHARGE CONSTANTS ----- +#define CHARGE_CONST 150 +#define CHARGE_RAND_MAX 400 + +using namespace o2::raw; + +namespace o2 +{ + +namespace hmpid +{ + +class HmpidCoder2 +{ + public: + int mVerbose; + int mNumberOfEquipments; + + RawFileWriter mWriter{"HMP", false}; + + private: + // The standard definition of HMPID equipments at P2 + // const int mEqIds[Geo::MAXEQUIPMENTS] = {0, 1, 2, 3, 4, 5, 8, 9, 6, 7, 10, 11, 12, 13}; + // const int mCruIds[Geo::MAXEQUIPMENTS] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; + // const int mLinkIds[Geo::MAXEQUIPMENTS] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2}; + // const int mFlpIds[Geo::MAXEQUIPMENTS] = {160, 160, 160, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 161}; + + uint32_t* mPayloadBufferPtr; + uint32_t* mPadMap; + int mEventSizePerEquipment[Geo::MAXEQUIPMENTS]; + int mEventPadsPerEquipment[Geo::MAXEQUIPMENTS]; + int mPayloadBufferDimPerEquipment; + long mPadsCoded; + bool mSkipEmptyEvents; + std::unique_ptr<uint32_t[]> mUPayloadBufferPtr; + std::unique_ptr<uint32_t[]> mUPadMap; + + LinkSubSpec_t mTheRFWLinks[Geo::MAXEQUIPMENTS]; + + int mBusyTime; + int mHmpidErrorFlag; + int mHmpidFrwVersion; + + public: + HmpidCoder2(int numOfEquipments); + virtual ~HmpidCoder2() = default; + + void setVerbosity(int Level) + { + mVerbose = Level; + }; + int getVerbosity() + { + return (mVerbose); + }; + int getNumberOfEquipments() + { + return (mNumberOfEquipments); + }; + void setSkipEmptyEvents(bool Skip) + { + mSkipEmptyEvents = Skip; + } + bool getSkipEmptyEvents() + { + return (mSkipEmptyEvents); + } + o2::raw::RawFileWriter& getWriter() { return mWriter; } + + void setDetectorSpecificFields(float BusyTime = 0.001, int Error = 0, int Version = 9); + void openOutputStream(const std::string& outputFileName, const std::string& fileFor); + void closeOutputStream(); + + void codeEventChunkDigits(std::vector<o2::hmpid::Digit>& digits, InteractionRecord ir); + void dumpResults(const std::string& outputFileName); + + private: + int getEquipmentPadIndex(int eq, int col, int dil, int cha); + void fillTheOutputBuffer(uint32_t* padMap); + void writePaginatedEvent(uint32_t orbit, uint16_t bc); + void setRDHFields(int eq = -1); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* COMMON_HMPIDCODER_H_ */ diff --git a/Detectors/HMPID/simulation/src/Detector.cxx b/Detectors/HMPID/simulation/src/Detector.cxx index 89af501ba15cd..cd826eaca739f 100644 --- a/Detectors/HMPID/simulation/src/Detector.cxx +++ b/Detectors/HMPID/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,15 +33,17 @@ #include "DetectorsBase/MaterialManager.h" +#include "Framework/Logger.h" + namespace o2 { namespace hmpid { -Detector::Detector(Bool_t active) : o2::base::DetImpl<Detector>("HMP", active), mHits(new std::vector<HitType>) {} +Detector::Detector(Bool_t active) : o2::base::DetImpl<Detector>("HMP", active), mHits(new std::vector<o2::hmpid::HitType>) {} Detector::Detector(const Detector& other) : mSensitiveVolumes(other.mSensitiveVolumes), - mHits(new std::vector<HitType>) {} + mHits(new std::vector<o2::hmpid::HitType>) {} void Detector::InitializeO2Detector() { @@ -72,8 +75,8 @@ bool Detector::ProcessHits(FairVolume* v) TString tmpname = volname; tmpname.Remove(0, 4); Int_t idch = tmpname.Atoi(); //retrieve the chamber number - Float_t xl, yl; - Param::Instance()->Mars2Lors(idch, x, xl, yl); //take LORS position + Double_t xl, yl; + o2::hmpid::Param::instance()->mars2Lors(idch, x, xl, yl); //take LORS position AddHit(x[0], x[1], x[2], hitTime, etot, tid, idch); //HIT for photon, position at P, etot will be set to Q GenFee(etot); //generate feedback photons etot is modified in hit ctor to Q of hit stack->addHit(GetDetId()); @@ -110,8 +113,8 @@ bool Detector::ProcessHits(FairVolume* v) TString tmpname = volname; tmpname.Remove(0, 4); Int_t idch = tmpname.Atoi(); //retrieve the chamber number - Float_t xl, yl; - Param::Instance()->Mars2Lors(idch, out, xl, yl); //take LORS position + Double_t xl, yl; + o2::hmpid::Param::instance()->mars2Lors(idch, out, xl, yl); //take LORS position if (eloss > 0) { // HIT for MIP, position near anod plane, eloss will be set to Q AddHit(out[0], out[1], out[2], hitTime, eloss, tid, idch); @@ -130,7 +133,7 @@ bool Detector::ProcessHits(FairVolume* v) return false; } //********************************************************************************************************* -HitType* Detector::AddHit(float x, float y, float z, float time, float energy, Int_t trackId, Int_t detId) +o2::hmpid::HitType* Detector::AddHit(float x, float y, float z, float time, float energy, Int_t trackId, Int_t detId) { mHits->emplace_back(x, y, z, time, energy, trackId, detId); return &(mHits->back()); @@ -1131,16 +1134,13 @@ TGeoVolume* Detector::CradleBaseVolume(TGeoMedium* med, Double_t l[7], const cha { /* The trapezoid is build in the xy plane - 0 ________________ 1 / | \ / | \ / (0,0) \ / | \ 3 /___________|____________\ 2 - 01 is right shifted => shift is positive - //1: small base (0-1); 2: long base (3-2); //3: trapezoid height; 4: shift between the two bases; //5: height 6: height reduction; 7: z-reduction; diff --git a/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx b/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx index 155e2a8ae4455..e75405cf504b2 100644 --- a/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx +++ b/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx @@ -1,15 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "HMPIDSimulation/HMPIDDigitizer.h" -#include "HMPIDBase/Digit.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" + +#include "Framework/Logger.h" using namespace o2::hmpid; @@ -29,12 +33,13 @@ void HMPIDDigitizer::zeroSuppress(std::vector<o2::hmpid::Digit> const& digits, s int index = 0; for (auto& digit : digits) { if (digit.getCharge() >= getThreshold(digit)) { + // if(digit.getPx() < 80 && digit.getPy() < 48) { newdigits.push_back(digit); - if (newlabels) { // copy the labels to the new place with the right new index newlabels->addElements(newdigits.size() - 1, labels.getLabels(index)); } + // } } index++; } @@ -62,22 +67,26 @@ void HMPIDDigitizer::process(std::vector<o2::hmpid::HitType> const& hits, std::v int chamber, pc, px, py; float totalQ; // retrieves center pad and the total charge - Digit::getPadAndTotalCharge(hit, chamber, pc, px, py, totalQ); + o2::hmpid::Digit::getPadAndTotalCharge(hit, chamber, pc, px, py, totalQ); if (px < 0 || py < 0) { continue; } // determine which pads to loop over - std::array<int, 9> allpads; + std::array<uint32_t, 9> allpads; int counter = 0; for (int nx = -1; nx <= 1; ++nx) { for (int ny = -1; ny <= 1; ++ny) { - allpads[counter] = Param::Abs(chamber, pc, px + nx, py + ny); + if ((px + nx) < 0 || (px + nx) > 79 || (py + ny) < 0 || (py + ny) > 47) { + LOG(INFO) << ">> Pad out the PhotoCathod boundary. Excluded :" << px << " " << py << " :" << nx << "," << ny; + continue; + } + allpads[counter] = o2::hmpid::Digit::abs(chamber, pc, px + nx, py + ny); counter++; } } - + // LOG(INFO) << "." << px << " " << py ; for (auto& pad : allpads) { auto iter = mIndexForPad.find(pad); int index = -1; @@ -85,7 +94,7 @@ void HMPIDDigitizer::process(std::vector<o2::hmpid::HitType> const& hits, std::v index = iter->second; } // auto index = mIndexForPad[pad]; - float fraction = Digit::getFractionalContributionForPad(hit, pad); + float fraction = o2::hmpid::Digit::getFractionalContributionForPad(hit, (int)pad); // LOG(INFO) << "FRACTION ON PAD " << pad << " IS " << fraction; if (index != -1) { // digit exists ... reuse @@ -108,7 +117,8 @@ void HMPIDDigitizer::process(std::vector<o2::hmpid::HitType> const& hits, std::v } } else { // create digit ... and register - mDigits.emplace_back(mCurrentTriggerTime, pad, totalQ * fraction); + // mDigits.emplace_back(mCurrentTriggerTime, pad, totalQ * fraction); + mDigits.emplace_back(pad, totalQ * fraction); mIndexForPad[pad] = mDigits.size() - 1; mInvolvedPads.emplace_back(pad); diff --git a/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h b/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h index 804d708d9da3b..752c9b596db4d 100644 --- a/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h +++ b/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,5 +18,6 @@ #pragma link C++ class o2::hmpid::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::hmpid::Detector> + ; #pragma link C++ class o2::hmpid::HMPIDDigitizer + ; +#pragma link C++ class o2::hmpid::HmpidCoder2 + ; #endif diff --git a/Detectors/HMPID/simulation/src/HmpidCoder2.cxx b/Detectors/HMPID/simulation/src/HmpidCoder2.cxx new file mode 100644 index 0000000000000..6deabd2cf5a4b --- /dev/null +++ b/Detectors/HMPID/simulation/src/HmpidCoder2.cxx @@ -0,0 +1,283 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidCoder.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class for coding HMPID Raw Data File +/// \version 1.0 +/// \date 24 feb 2021 + +#include <vector> +#include <iostream> +#include <memory> + +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "DataFormatsParameters/GRPObject.h" + +#include "DataFormatsHMP/Digit.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +using namespace o2::raw; +using namespace o2::hmpid; +using namespace o2::header; + +/// HMPID Raw Coder Constructor +/// @param[in] numOfEquipments : number of Equipments +HmpidCoder2::HmpidCoder2(int numOfEquipments) +{ + mPadsCoded = 0; + mNumberOfEquipments = numOfEquipments; + mVerbose = 0; + mSkipEmptyEvents = true; + mPayloadBufferDimPerEquipment = ((Geo::N_SEGMENTS * (Geo::N_COLXSEGMENT * (Geo::N_DILOGICS * (Geo::N_CHANNELS + 1) + 1) + 1)) + 10); + mUPayloadBufferPtr = std::make_unique<uint32_t[]>(mNumberOfEquipments * mPayloadBufferDimPerEquipment); + mUPadMap = std::make_unique<uint32_t[]>(Geo::N_HMPIDTOTALPADS); + mPayloadBufferPtr = mUPayloadBufferPtr.get(); + mPadMap = mUPadMap.get(); + std::memset(mPadMap, 0, sizeof(uint32_t) * Geo::N_HMPIDTOTALPADS); // Zero the map for the first event + mBusyTime = 20000; // 1 milli sec + mHmpidErrorFlag = 0; + mHmpidFrwVersion = 9; +} + +/// setDetectorSpecificFields() : sets the HMPID parameters for the next +/// raw file writes +/// @param[in] BusyTime : busy time in milliseconds +/// @param[in] Error : the Error field +/// @param[in] Version : the Firmware Version [def. 9] +void HmpidCoder2::setDetectorSpecificFields(float BusyTime, int Error, int Version) +{ + uint32_t busy = (uint32_t)(BusyTime / 0.00000005); + mBusyTime = busy; + mHmpidErrorFlag = Error; + mHmpidFrwVersion = Version; + return; +} + +/// setRDHFields() : sets the HMPID RDH Field for the next +/// raw file writes +/// @param[in] eq : the HMPID Equipment ID [0..13] if == -1 -> all +void HmpidCoder2::setRDHFields(int eq) +{ + int st, en; + uint32_t wr = (mBusyTime << 9) | ((mHmpidErrorFlag & 0x01F) << 4) | (mHmpidFrwVersion & 0x0F); + st = (eq < 0 || eq >= Geo::MAXEQUIPMENTS) ? 0 : eq; + en = (eq < 0 || eq >= Geo::MAXEQUIPMENTS) ? Geo::MAXEQUIPMENTS : eq + 1; + for (int l = st; l < en; l++) { + o2::raw::RawFileWriter::LinkData& link = mWriter.getLinkWithSubSpec(mTheRFWLinks[l]); + RDHAny* RDHptr = link.getLastRDH(); + if (RDHptr != nullptr) { + o2::raw::RDHUtils::setDetectorField(RDHptr, wr); + } + } + return; +} + +/// constexpr to accelerate the coordinates changing +constexpr int p1() { return (Geo::N_SEGMENTS * Geo::N_COLXSEGMENT * Geo::N_DILOGICS * Geo::N_CHANNELS); } +constexpr int p2() { return (Geo::N_DILOGICS * Geo::N_CHANNELS); } + +/// getEquipmentPadIndex() : converts the (Equipment, Column, Dilogic, Channel) +/// coordinate into a unique PadIndex value used to address the PADs array +/// @param[in] eq : the HMPID Equipment ID [0..13] +/// @param[in] col : the Equipment Column [0..23] +/// @param[in] dil : the Dilogic [0..9] +/// @param[in] cha : the Channel [0..47] +/// @returns The PAD index value [0..161279] +int HmpidCoder2::getEquipmentPadIndex(int eq, int col, int dil, int cha) +{ + return (eq * p1() + col * p2() + dil * Geo::N_CHANNELS + cha); +} + +/// Scans the PADs array and fill the Output buffer with the RawFile structure +/// a two step algorithm... +/// @param[in] padMap : poiter to the PADs map array +void HmpidCoder2::fillTheOutputBuffer(uint32_t* padMap) +{ + uint32_t rowMarker, segMarker, eoeMarker, padWord; + uint32_t rowSize; + uint32_t ptr = 0; + int pads[Geo::MAXEQUIPMENTS]; + int padsCount; + int segSize; + + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + mEventSizePerEquipment[i] = 0; + } + + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + int startPtr = ptr; + padsCount = 0; + for (int s = 1; s <= Geo::N_SEGMENTS; s++) { + segSize = 0; + for (int c = 1; c <= Geo::N_COLXSEGMENT; c++) { + // ---- Pre-calculate the size of each column + for (int j = 0; j < Geo::N_DILOGICS; j++) { + pads[j] = 0; + } + rowSize = 0; + for (int j = 0; j < Geo::N_DILOGICS; j++) { + for (int k = 0; k < Geo::N_CHANNELS; k++) { + int idx = getEquipmentPadIndex(eq, ((s - 1) * Geo::N_COLXSEGMENT + (c - 1)), j, k); + if (padMap[idx] > 0) { + pads[j]++; + rowSize++; + padsCount++; + } + } + } + rowSize += Geo::N_DILOGICS; + segSize += (rowSize + 1); + rowMarker = 0x000036A8 | ((rowSize << 16) & 0x03ff0000); + + // ---- fills the Payload Buffer + mPayloadBufferPtr[ptr++] = rowMarker; + int col = (s - 1) * Geo::N_COLXSEGMENT + c; + for (int d = 1; d <= Geo::N_DILOGICS; d++) { + for (int p = 0; p < Geo::N_CHANNELS; p++) { + int idx = getEquipmentPadIndex(eq, ((s - 1) * Geo::N_COLXSEGMENT + (c - 1)), (d - 1), p); + if (padMap[idx] > 0) { + padWord = ((col << 22) & 0x07c00000) | ((d << 18) & 0x003C0000) | ((p << 12) & 0x0003F000) | (padMap[idx] & 0x00000FFF); + mPayloadBufferPtr[ptr++] = padWord; + } + } + eoeMarker = 0x08000080 | ((col << 22) & 0x07c00000) | (d << 18 & 0x003C0000) | (pads[d - 1] & 0x0000007F); + mPayloadBufferPtr[ptr++] = eoeMarker; + } + } + segSize += 1; + segMarker = 0xAB000000 | ((segSize << 8) & 0x000fff00) | (s & 0x0000000F); + mPayloadBufferPtr[ptr++] = segMarker; + } + mPadsCoded += padsCount; + mEventPadsPerEquipment[eq] = padsCount; + mEventSizePerEquipment[eq] = ptr - startPtr; + } + return; +} + +/// Add a chunk of data in the Output buffer to the RawWriter +/// setting the CRU,Link coordinates and the Trigger Info +/// One or more Pages will be created for each equipment +/// +/// @param[in] orbit : the Trigger ORBIT value +/// @param[in] bc : the Trigger BC value +void HmpidCoder2::writePaginatedEvent(uint32_t orbit, uint16_t bc) +{ + uint32_t* ptrStartEquipment = mPayloadBufferPtr; + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + int EventSize = mEventSizePerEquipment[eq]; + LOG(DEBUG) << "writePaginatedEvent() Eq=" << eq << " Size:" << EventSize << " Pads:" << mEventPadsPerEquipment[eq] << " Orbit:" << orbit << " BC:" << bc; + if (mEventPadsPerEquipment[eq] > 0 || !mSkipEmptyEvents) { // Skips the Events with 0 Pads + mWriter.addData(ReadOut::FeeId(eq), + ReadOut::CruId(eq), + ReadOut::LnkId(eq), + 0, + {bc, orbit}, + gsl::span<char>(reinterpret_cast<char*>(ptrStartEquipment), + EventSize * sizeof(uint32_t)), + false, + (uint32_t)((mBusyTime << 9) | ((mHmpidErrorFlag & 0x01F) << 4) | (mHmpidFrwVersion & 0x0F))); + // We fill the fields ! + // TODO: we can fill the detector field with Simulated Data + setDetectorSpecificFields(0.000001 * EventSize); + setRDHFields(eq); + } + ptrStartEquipment += EventSize; + } + return; +} + +/// Analyze a Digits Vector and setup the PADs array +/// with the charge value, then fills the output buffer +/// and forward it to the RawWriter object +/// +/// NOTE: the vector could be empty! +/// @param[in] digits : the vector of Digit structures +/// @param[in] ir : the Interaction Record structure +void HmpidCoder2::codeEventChunkDigits(std::vector<o2::hmpid::Digit>& digits, InteractionRecord ir) +{ + int eq, col, dil, cha, mo, x, y, idx; + uint32_t orbit = ir.orbit; + uint16_t bc = ir.bc; + + int padsCount = 0; + LOG(DEBUG) << "Manage chunk Orbit :" << orbit << " BC:" << bc << " Digits size:" << digits.size(); + for (o2::hmpid::Digit d : digits) { + Digit::pad2Equipment(d.getPadID(), &eq, &col, &dil, &cha); // From Digit to Hardware coords + eq = ReadOut::FeeId(eq); // converts the Equipment Id in Cru/Link position ref + idx = getEquipmentPadIndex(eq, col, dil, cha); // finally to the unique padmap index + if (mPadMap[idx] != 0) { // We already have the pad set + LOG(WARNING) << "Duplicated DIGIT =" << d << " (" << eq << "," << col << "," << dil << "," << cha << ")" << idx; + } else { + mPadMap[idx] = d.getCharge(); + padsCount++; + } + } + fillTheOutputBuffer(mPadMap); // Fill the Buffer for all Equipments per Event + writePaginatedEvent(orbit, bc); + std::memset(mPadMap, 0, sizeof(uint32_t) * Geo::N_HMPIDTOTALPADS); // Update for the new event + return; +} + +/// Create the Raw File/Files for the output. +/// Also registers the links in the RawWriter object +/// +/// @param[in] OutputFileName : the Path/Prefix name for the raw files +/// @param[in] perFlpFile : if true a couple of files will be created, one for each +/// HMPID FLPs +void HmpidCoder2::openOutputStream(const std::string& outputFileName, const std::string& fileFor) +{ + RAWDataHeader rdh; // by default, v6 is used currently. + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + rdh.feeId = ReadOut::FeeId(eq); + rdh.cruID = ReadOut::CruId(eq); + rdh.linkID = ReadOut::LnkId(eq); + rdh.endPointID = 0; + std::string outfname; + if (fileFor == "link") { + outfname = fmt::format("{}_{}_feeid{}.raw", outputFileName, ReadOut::FlpHostName(eq), ReadOut::FeeId(eq)); + } else if (fileFor == "flp") { + outfname = fmt::format("{}_{}.raw", outputFileName, ReadOut::FlpHostName(eq)); + } else if (fileFor == "all") { + outfname = fmt::format("{}.raw", outputFileName); + } else if (fileFor == "cru") { + outfname = fmt::format("{}_{}.raw", outputFileName, ReadOut::FlpHostName(eq)); + } else { + throw std::runtime_error(fmt::format("unknown raw file grouping option {}", fileFor)); + } + + mWriter.registerLink(rdh, outfname); // register the link + LinkSubSpec_t ap = RDHUtils::getSubSpec(ReadOut::CruId(eq), ReadOut::LnkId(eq), 0, ReadOut::FeeId(eq)); + mTheRFWLinks[eq] = ap; // Store the RawFileWriter Link ID + } + return; +} + +/// Close and flush the output streams. +void HmpidCoder2::closeOutputStream() +{ + mWriter.close(); + return; +} + +/// Dumps the results of the last coding +void HmpidCoder2::dumpResults(const std::string& outputFileName) +{ + std::cout << " **** HMPID RawFile Coder : results ****" << std::endl; + std::cout << " Created files : " << outputFileName << std::endl; + std::cout << " Number of Pads coded : " << mPadsCoded << std::endl; + std::cout << " ----------------------------------------" << std::endl; +} diff --git a/Detectors/HMPID/workflow/CMakeLists.txt b/Detectors/HMPID/workflow/CMakeLists.txt new file mode 100644 index 0000000000000..a65251c1f4539 --- /dev/null +++ b/Detectors/HMPID/workflow/CMakeLists.txt @@ -0,0 +1,80 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(HMPIDWorkflow + SOURCES src/DataDecoderSpec.cxx + src/DataDecoderSpec2.cxx + src/DigitsToRawSpec.cxx + src/DumpDigitsSpec.cxx + src/PedestalsCalculationSpec.cxx + src/RawToDigitsSpec.cxx + src/ReadRawFileSpec.cxx + src/WriteRawFileSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + + PUBLIC_LINK_LIBRARIES O2::Framework + O2::CCDB + O2::DPLUtils + O2::DetectorsRaw + O2::HMPIDBase + O2::DataFormatsHMP + O2::HMPIDSimulation + O2::HMPIDReconstruction) + +#o2_add_executable(recoworkflow +# COMPONENT_NAME hmpid +# SOURCES src/HMPIDRecoWorkflow.cxx +# PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME hhmpid + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(read-raw-file-stream-workflow + COMPONENT_NAME hmpid + SOURCES src/read-raw-file-stream-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(raw-to-pedestals-workflow + COMPONENT_NAME hmpid + SOURCES src/raw-to-pedestals-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(raw-to-digits-workflow + COMPONENT_NAME hmpid + SOURCES src/raw-to-digits-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(raw-to-digits-stream-workflow + COMPONENT_NAME hmpid + SOURCES src/raw-to-digits-stream-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(dump-digits-stream-workflow + COMPONENT_NAME hmpid + SOURCES src/dump-digits-stream-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(digits-to-raw-workflow + COMPONENT_NAME hmpid + SOURCES src/digits-to-raw-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(digits-to-raw-stream-workflow + COMPONENT_NAME hmpid + SOURCES src/digits-to-raw-stream-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME hmpid + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) diff --git a/Detectors/HMPID/workflow/README.md b/Detectors/HMPID/workflow/README.md new file mode 100644 index 0000000000000..4281a5e2d7293 --- /dev/null +++ b/Detectors/HMPID/workflow/README.md @@ -0,0 +1,229 @@ +<!-- doxy +\page refHMPIDworkflow HMP workflow +/doxy --> + +# DPL workflows for the HMPID v.0.8 + +## HMPID DPL processors + +* `hmpid-raw-to-digits` reads data from ReadOut Raw File and outputs a ROOT formatted file (Reconstruction flow) +* `hmpid-digits-to-raw` reads digits data from a ROOT formatted file and produce a ReadOut Raw File (Simulation flow) +* `hmpid-read-raw-file-stream` reads data from ReadOut Raw File and outputs a stream of RDH6 pages as HMP/RAWDATA stream +* `hmpid-raw-to-digits-stream` decodes the input raw pages stream (HMP/RAWDATA) and produces two streams avector of o2::hmpid::Digits (HMP/DIGITS) and a o2::InteractionRecord (HMP/INTRECORD) +* `hmpid-digits-to-raw-stream` codes input o2::hmpid::Digits vector (HMP/DIGITS) and (HMP/INTRECORD) stream into the binary HMPID raw file +* `hmpid-dump-digits-stream` dumps the input o2::hmpid::Digits vector (HMP/DIGITS) and (HMP/INTRECORD) stream to the stdout or in an ASCII file +* `hmpid-raw-to-pedestals` reads data from ReadOut Raw File and outputs results of Pedestals calculation in ReadOut format and CCDB (Calibration flow) + +### Workflow example +Dumping the contents of a Raw file. + +``` + o2-hmpid-read-raw-file-stream-workflow --raw-file test_full_flp1.raw -b | o2-hmpid-raw-to-digits-stream-workflow -b | o2-hmpid-dump-digits-stream-workflow --out-file /tmp/pippo.txt -b +``` + +This reads the `test_full_flp1.raw` file and after the decoding, produce an ASCII file in the /tmp/ folder that contains the Events/Digits dump. + + + +### o2-hmpid-read-raw-file-stream-workflow +Reads data from ReadOut Raw File and outputs a stream of RDH6 pages as HMP/RAWDATA stream. + +Display all options + +``` +o2-hmpid-read-raw-file-stream-workflow --help full +``` + +Data processor options: HMP-ReadRawFile: + +``` + --raw-file arg Raw input file name + --print verbose output +``` + +### o2-hmpid-raw-to-digits-stream-workflow +Decodes the input raw pages stream (HMP/RAWDATA) and produces a vector of o2::hmpid::Digits (HMP/DIGITS) and a o2::InteractionRecord (HMP/INTRECORD). + +Display all options + +``` +o2-hmpid-raw-to-digits-stream-workflow --help full +``` + +Data processor options: HMP-DataDecoder: + +``` + --root-file arg (=/tmp/hmpRawDecodeResults) + Name of the Root file with the decoding + results. + --fast-decode Use the fast algorithm. (error 0.8%) + --get-results-statistics Switch on the output of statistic result files +``` + + +### o2-hmpid-digits-to-raw-stream-workflow +Codes input o2::hmpid::Digits vector (HMP/DIGITS) and (HMP/INTRECORD) stream into the binary HMPID raw file. + +Display all options + +``` +o2-hmpid-digits-to-raw-stream-workflow --help full +``` + +Data processor options: HMP-WriteRawFromDigits: + +``` + --out-file arg (=hmpidRaw) name of the output file + --order-events order the events time + --skip-empty skip empty events + --fixed-lenght fixed lenght packets = 8K bytes +``` + + +### o2-hmpid-dump-digits-stream-workflow +Dumps the input o2::hmpid::Digits vector (HMP/DIGITS) and (HMP/INTRECORD) stream to the stdout or in an ASCII file. + +Display all options + +``` +o2-hmpid-dump-digits-stream-workflow --help full +``` + +Data processor options: HMP-DigitsDump: + +``` + --out-file arg name of the output file + --print print digits (default false ) +``` + + +### o2-hmpid-raw-to-digits-workflow +Write Raw File into a root formatted file + +``` +o2-hmpid-raw-to-digits-workflow --help full +``` + +Data processor options: HMPDigitWriter: + +``` + --in-file arg (=hmpidRaw.raw) name of the input Raw file + --out-file arg (=hmpReco.root) name of the output file + --base-file arg (=hmpDecode) base name for statistical output file + --fast-decode Use the fast algorithm. (error 0.8%) +``` + +Example + +``` +[O2Suite/latest-o2] ~/Downloads/provaRec $> o2-hmpid-raw-to-digits-workflow --in-file test_full_flp1.raw --out-file hmpidReco.root --base-file /tmp/pippo -b +``` + +### o2-hmpid-digits-to-raw-workflow +Write raw files with the digits information contained in a root file + +``` +o2-hmpid-digits-to-raw-workflow +``` + +Data processor options: HMP-WriteRawFromRootFile: + +``` + --outdir arg (=./) base dir for output file + --file-for arg (=all) single file per: all,flp,link + --outfile arg (=hmpid) base name for output file + --in-file arg (=hmpiddigits.root) name of the input sim root file + --dump-digits out the digits file in + /tmp/hmpDumpDigits.dat + --skip-empty skip empty events +``` + +Example + +``` +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-sim-serial -m HMP -n 20 -e TGeant4 -g pythia8hi +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-sim-digitizer-workflow --onlyDet HMP +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-hmpid-digits-to-raw-workflow --outdir ./ --in-file hmpiddigits.root --outfile hmpRawFromRoot --file-for all --dump-digits -b +``` + +in order to verify the write, the inverse decoding of raw file + +``` +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-hmpid-read-raw-file-stream-workflow --raw-file hmpRawFromRoot.raw -b | o2-hmpid-raw-to-digits-stream-workflow -b | o2-hmpid-dump-digits-stream-workflow --out-file /tmp/hmpDumpDigitsVerify.dat +``` + + +### o2-hmpid-raw-to-pedestals-workflow +Write the Pedestals/Threshold files for the readout and registers Mean and Sigma in the CCDB + +``` +o2-hmpid-raw-to-pedestals-workflow --help full +``` + +Data processor options: HMP-DataDecoder: + +``` + --files-basepath arg (=/tmp/hmpPedThr) + Name of the Base Path of + Pedestals/Thresholds files. + --use-ccdb Register the Pedestals/Threshold values + into the CCDB + --ccdb-uri arg (=http://ccdb-test.cern.ch:8080) + URI for the CCDB access. + --pedestals-tag arg (=Latest) The tag applied to this set of + pedestals/threshold values + --sigmacut arg (=4) Sigma values for the Thresholds + calculation. + --fast-decode Use the fast algorithm. (error 0.8%) +``` + +Example + +``` +o2-hmpid-read-raw-file-stream-workflow --raw-file ../hmpidRaw160.raw -b | o2-hmpid-raw-to-pedestals-workflow --sigmacut=2.5 --files-basepath /tmp/pippo -b --use-ccdb --pedestals-tag TEST3 +``` + +this command produce in the ccdb a set of `TMatrixF` object one for each chamber + +``` +Subfolder +HMP/Pedestals/TEST3/Mean_0 +HMP/Pedestals/TEST3/Mean_1 +HMP/Pedestals/TEST3/Mean_2 +HMP/Pedestals/TEST3/Mean_4 +HMP/Pedestals/TEST3/Sigma_0 +HMP/Pedestals/TEST3/Sigma_1 +HMP/Pedestals/TEST3/Sigma_2 +HMP/Pedestals/TEST3/Sigma_4 +``` + +and in addition a set of Ped/Thr files in the `/tmp` folder + +``` +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_0.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_1.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_2.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_3.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_4.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_5.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_8.dat +-rw-r--r-- 1 fap wheel 92166 12 Feb 10:45 pippo_9.dat +``` + +the format of Ped/Thr is ASCII, one Hexadecimal Value for row **((Threshold & 0x001FF) << 9) | (Pedestal & 0x001FF)** , for a total of 15361 rows; the last value is the `End of File` indication (A0A0A) + +``` +0F674 +1027E +1047F +1469F +13699 +. +. +. +00000 +00000 +00000 +00000 +A0A0A +``` diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h new file mode 100644 index 0000000000000..6102ec481c97c --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZER_H_ +#define STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZER_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +o2::framework::DataProcessorSpec getHMPIDClusterizerSpec(bool useMC); + +} // end namespace hmpid +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZERSPEC_H_ */ diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec.h new file mode 100644 index 0000000000000..664826919be84 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DATADECODERSPEC_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DATADECODERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "HMPIDBase/Common.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +//#include "HMPIDReconstruction/HmpidDecodeRawMem.h" + +namespace o2 +{ +namespace hmpid +{ + +class DataDecoderTask : public framework::Task +{ + public: + DataDecoderTask() = default; + ~DataDecoderTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void decodeTF(framework::ProcessingContext& pc); + void decodeReadout(framework::ProcessingContext& pc); + void decodeRawFile(framework::ProcessingContext& pc); + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + HmpidDecoder2* mDeco; + long mTotalDigits; + long mTotalFrames; + std::string mRootStatFile; + bool mFastAlgorithm; + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getDecodingSpec(bool askSTFDist); +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec2.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec2.h new file mode 100644 index 0000000000000..1dd0c37c074d3 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DataDecoderSpec2.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DATADECODERSPEC_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DATADECODERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Common.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +class DataDecoderTask2 : public framework::Task +{ + public: + DataDecoderTask2() = default; + ~DataDecoderTask2() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void decodeTF(framework::ProcessingContext& pc); + void decodeReadout(framework::ProcessingContext& pc); + void decodeRawFile(framework::ProcessingContext& pc); + void endOfStream(framework::EndOfStreamContext& ec) override; + void orderTriggers(); + + private: + HmpidDecoder2* mDeco; + long mTotalDigits; + long mTotalFrames; + std::string mRootStatFile; + bool mProduceResults; + bool mFastAlgorithm; + + ExecutionTimer mExTimer; + std::vector<o2::hmpid::Trigger> mTriggers; +}; + +o2::framework::DataProcessorSpec getDecodingSpec2(bool askSTFDist); +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h new file mode 100644 index 0000000000000..eea9b134bd911 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReader.h + +#ifndef O2_HMPID_DIGITREADER +#define O2_HMPID_DIGITREADER + +#include "TFile.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsHMP/Digit.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2 +{ +namespace hmpid +{ + +class DigitReader : public o2::framework::Task +{ + public: + DigitReader(bool useMC) : mUseMC(useMC) {} + ~DigitReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + private: + int mState = 0; + bool mUseMC = true; + std::unique_ptr<TFile> mFile = nullptr; + + std::vector<o2::hmpid::Digit> mDigits, *mPdigits = &mDigits; + + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels, *mPlabels = &mLabels; +}; + +/// read simulated HMPID digits from a root file +framework::DataProcessorSpec getDigitReaderSpec(bool useMC); + +} // namespace hmpid +} // namespace o2 + +#endif /* O2_HMPID_DIGITREADER */ diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitsToRawSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitsToRawSpec.h new file mode 100644 index 0000000000000..ee184bbe50103 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitsToRawSpec.h @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef _HMPID_DIGITS_TO_RAW_SPEC_H_ +#define _HMPID_DIGITS_TO_RAW_SPEC_H_ + +#include <vector> +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" + +#include "HMPIDBase/Common.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +class DigitsToRawSpec : public framework::Task +{ + public: + DigitsToRawSpec() = default; + ~DigitsToRawSpec() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + void readRootFile(); + std::string mBaseFileName = ""; + std::string mDirectoryName = ""; + std::string mBaseRootFileName = ""; + bool mSkipEmpty = false; + bool mDumpDigits = false; + std::string mFileFor = "all"; + bool mFastAlgorithm; + + std::vector<o2::hmpid::Digit> mDigits; + long mDigitsReceived; + int mEventsReceived; + HmpidCoder2* mCod; + ExecutionTimer mExTimer; + TTree* mDigTree; +}; + +o2::framework::DataProcessorSpec getDigitsToRawSpec(); + +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DumpDigitsSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DumpDigitsSpec.h new file mode 100644 index 0000000000000..a64ceb45ba51b --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DumpDigitsSpec.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DatDecoderSpec.h +/// \author Andrea Ferrero +/// +/// \brief Definition of a data processor to run the raw decoding +/// + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DUMPDIGITSPEC_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_DUMPDIGITSPEC_H_ + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "HMPIDBase/Common.h" +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +class DumpDigitsTask : public framework::Task +{ + public: + DumpDigitsTask() = default; + ~DumpDigitsTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + bool mPrintDigits = false; + bool mIsOutputOnFile = false; + std::string mOutputFileName = ""; + std::ofstream mOsFile; + + int mOrbit; + int mBc; + long mDigitsReceived; + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getDumpDigitsSpec(std::string inputSpec = "HMP/DIGITS"); + +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..43e3a0c0a5a78 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to HMP digit/tracklets stream + +#ifndef O2_HMP_ENTROPYDECODER_SPEC +#define O2_HMP_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace hmpid +{ + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace hmpid +} // namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..50b965aeefba7 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert HMP data to CTF (EncodedBlocks) + +#ifndef O2_HMP_ENTROPYENCODER_SPEC +#define O2_HMP_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace hmpid +{ + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace hmpid +} // namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/PedestalsCalculationSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/PedestalsCalculationSpec.h new file mode 100644 index 0000000000000..dc0c952484dd6 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/PedestalsCalculationSpec.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_PEDESTALS_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_PEDESTALS_H_ + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "CCDB/CcdbApi.h" + +#include "HMPIDBase/Common.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +class PedestalsCalculationTask : public framework::Task +{ + public: + PedestalsCalculationTask() = default; + ~PedestalsCalculationTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void decodeTF(framework::ProcessingContext& pc); + void decodeReadout(framework::ProcessingContext& pc); + void decodeRawFile(framework::ProcessingContext& pc); + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + void recordPedInCcdb(); + + private: + HmpidDecoder2* mDeco; + long mTotalDigits; + long mTotalFrames; + std::string mPedestalsBasePath; + float mSigmaCut; + std::string mPedestalTag; + + o2::ccdb::CcdbApi mDBapi; + std::map<std::string, std::string> mDbMetadata; // can be empty + bool mWriteToDB; + bool mFastAlgorithm; + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getPedestalsCalculationSpec(std::string inputSpec = "TF:HMP/RAWDATA"); +//o2::framework::DataProcessorSpec getDecodingSpec(); +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/RawToDigitsSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/RawToDigitsSpec.h new file mode 100644 index 0000000000000..e90995f7f8b83 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/RawToDigitsSpec.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_SRC_HMPDIGITWRITERSPEC_H_ +#define STEER_DIGITIZERWORKFLOW_SRC_HMPDIGITWRITERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/Task.h" +#include "Framework/InputSpec.h" + +#include "DetectorsRaw/RawFileReader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "HMPIDBase/Common.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ +namespace hmpid +{ + +class RawToDigitsTask : public framework::Task +{ + public: + RawToDigitsTask() = default; + ~RawToDigitsTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + void writeResults(); + void parseNoTF(); + + // static bool eventEquipPadsComparision(o2::hmpid::Digit d1, o2::hmpid::Digit d2); + std::string mBaseFileName = ""; + std::string mInputRawFileName = ""; + std::string mOutRootFileName = ""; + + o2::raw::RawFileReader mReader; + o2::hmpid::HmpidDecoder2* mDecod; + std::vector<o2::hmpid::Digit> mAccumulateDigits; + std::vector<o2::hmpid::Trigger> mEvents; + + long mDigitsReceived; + long mFramesReceived; + long mTotalDigits; + long mTotalFrames; + bool mFastAlgorithm; + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getRawToDigitsSpec(std::string inputSpec = "HMP/RAWDATA"); + +} // end namespace hmpid +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_SRC_HMPIDDIGITWRITERSPEC_H_ */ diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ReadRawFileSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/ReadRawFileSpec.h new file mode 100644 index 0000000000000..2476c52289b23 --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/ReadRawFileSpec.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_READRAWFILESPEC_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_READRAWFILESPEC_H_ + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "HMPIDBase/Common.h" +#include "DataFormatsHMP/Digit.h" + +namespace o2 +{ +namespace hmpid +{ + +class RawFileReaderTask : public framework::Task +{ + public: + RawFileReaderTask() = default; + ~RawFileReaderTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + + private: + std::ifstream mInputFile{}; ///< input file + bool mPrint = false; ///< print debug messages + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getReadRawFileSpec(std::string inputSpec = "HMP/RAWDATA"); + +} // end namespace hmpid +} // end namespace o2 + +#endif /* DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_READRAWFILESPEC_H_ */ diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFileSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFileSpec.h new file mode 100644 index 0000000000000..4670b089622cb --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFileSpec.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_WRITERAWFROMDIGITS_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_WRITERAWFROMDIGITS_H_ + +#include <vector> +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "HMPIDBase/Common.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +class WriteRawFileTask : public framework::Task +{ + public: + WriteRawFileTask() = default; + ~WriteRawFileTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + // static bool eventEquipPadsComparision(o2::hmpid::Digit d1, o2::hmpid::Digit d2); + std::string mBaseFileName = ""; + std::vector<o2::hmpid::Digit> mDigits; + std::vector<o2::hmpid::Trigger> mEvents; + bool mSkipEmpty = false; + bool mFixedPacketLenght = false; + bool mOrderTheEvents = true; + long mDigitsReceived; + long mFramesReceived; + bool mIsTheStremClosed = false; + HmpidCoder2* mCod; + + ExecutionTimer mExTimer; +}; + +o2::framework::DataProcessorSpec getWriteRawFileSpec(std::string inputSpec = "HMP/DIGITS"); + +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx new file mode 100644 index 0000000000000..20e8ca9ebd633 --- /dev/null +++ b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx @@ -0,0 +1,293 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataDecoderSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to run the HMPID raw decoding +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> + +#include "TTree.h" +#include "TFile.h" + +#include <gsl/span> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "HMPIDWorkflow/DataDecoderSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void DataDecoderTask::init(framework::InitContext& ic) +{ + + LOG(INFO) << "[HMPID Data Decoder - Init] ( create Raw Stream Decoder for " << Geo::MAXEQUIPMENTS << " equipments !"; + + mRootStatFile = ic.options().get<std::string>("result-file"); + mFastAlgorithm = ic.options().get<bool>("fast-decode"); + mDeco = new o2::hmpid::HmpidDecoder2(Geo::MAXEQUIPMENTS); + mDeco->init(); + mTotalDigits = 0; + mTotalFrames = 0; + + mExTimer.start(); + return; +} + +void DataDecoderTask::run(framework::ProcessingContext& pc) +{ + mDeco->mDigits.clear(); + decodeTF(pc); + // TODO: accept other types of Raw Streams ... + // decodeReadout(pc); + // decodeRawFile(pc); + + pc.outputs().snapshot(o2::framework::Output{"HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mDeco->mDigits); + pc.outputs().snapshot(o2::framework::Output{"HMP", "INTRECORDS", 0, o2::framework::Lifetime::Timeframe}, mDeco->mIntReco); + + LOG(DEBUG) << "Writing Digitis=" << mDeco->mDigits.size() << "/" << mTotalDigits << " Frame=" << mTotalFrames << " IntRec " << mDeco->mIntReco; + mExTimer.elapseMes("Decoding... Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); +} + +void DataDecoderTask::endOfStream(framework::EndOfStreamContext& ec) +{ + // Records the statistics + float avgEventSize; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float avgBusyTime; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float numOfSamples; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float sumOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float squareOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float xb; + float yb; + + TString filename = TString::Format("%s_stat.root", mRootStatFile.c_str()); + LOG(INFO) << "Create the stat file " << filename.Data(); + TFile mfileOut(TString::Format("%s", filename.Data()), "RECREATE"); + TTree* theObj[Geo::N_MODULES + 1]; + for (int i = 0; i < Geo::N_MODULES; i++) { // Create the TTree array + TString tit = TString::Format("HMPID Data Decoding Statistic results Mod=%d", i); + theObj[i] = new TTree("o2hmp", tit); + theObj[i]->Branch("x", &xb, "s"); + theObj[i]->Branch("y", &yb, "s"); + theObj[i]->Branch("Samples", &numOfSamples, "i"); + theObj[i]->Branch("Sum_of_charges", &sumOfCharges, "l"); + theObj[i]->Branch("Sum_of_square", &squareOfCharges, "l"); + } + theObj[Geo::N_MODULES] = new TTree("o2hmp", "HMPID Data Decoding Statistic results"); + theObj[Geo::N_MODULES]->Branch("Average_Event_Size", &avgEventSize, "F"); + theObj[Geo::N_MODULES]->Branch("Average_Busy_Time", &avgBusyTime, "F"); + + // Update the Stat for the Decoding + int numEqui = mDeco->getNumberOfEquipments(); + // cycle in order to update info for the last event + for (int i = 0; i < numEqui; i++) { + if (mDeco->mTheEquipments[i]->mNumberOfEvents > 0) { + mDeco->updateStatistics(mDeco->mTheEquipments[i]); + } + } + char summaryFileName[254]; + sprintf(summaryFileName, "%s_stat.txt", mRootStatFile.c_str()); + mDeco->writeSummaryFile(summaryFileName); + for (int e = 0; e < numEqui; e++) { + avgEventSize = mDeco->getAverageEventSize(e); + avgBusyTime = mDeco->getAverageBusyTime(e); + theObj[Geo::N_MODULES]->Fill(); + } + for (int m = 0; m < o2::hmpid::Geo::N_MODULES; m++) { + for (int y = 0; y < o2::hmpid::Geo::N_YCOLS; y++) { + for (int x = 0; x < o2::hmpid::Geo::N_XROWS; x++) { + xb = x; + yb = y; + numOfSamples = mDeco->getPadSamples(m, x, y); + sumOfCharges = mDeco->getPadSum(m, x, y); + squareOfCharges = mDeco->getPadSquares(m, x, y); + theObj[m]->Fill(); + } + } + } + for (int i = 0; i <= Geo::N_MODULES; i++) { + theObj[i]->Write(); + } + + mExTimer.logMes("End the Decoding ! Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + mExTimer.stop(); + return; +} +//_________________________________________________________________________________________________ +// the decodeTF() function processes the the messages generated by the (sub)TimeFrame builder +void DataDecoderTask::decodeTF(framework::ProcessingContext& pc) +{ + LOG(DEBUG) << "*********** In decodeTF **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{"HMP", "RAWDATA", 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return; + } + } + } + + DPLRawParser parser(inputs, o2::framework::select("TF:HMP/RAWDATA")); + mDeco->mDigits.clear(); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + mTotalFrames++; + } + mTotalDigits += mDeco->mDigits.size(); +} + +//_________________________________________________________________________________________________ +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +// TODO: rearrange, test +void DataDecoderTask::decodeReadout(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode readout **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + DPLRawParser parser(inputs, o2::framework::select("readout:HMP/RAWDATA")); + // DPLRawParser parser(inputs, o2::framework::select("HMP/readout")); + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + } + return; +} + +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +// TODO: rearrange, test +void DataDecoderTask::decodeRawFile(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode rawfile **************"; + + for (auto&& input : pc.inputs()) { + if (input.spec->binding == "file") { + const header::DataHeader* header = o2::header::get<header::DataHeader*>(input.header); + if (!header) { + return; + } + + auto const* raw = input.payload; + size_t payloadSize = header->payloadSize; + + LOG(INFO) << " payloadSize=" << payloadSize; + if (payloadSize == 0) { + return; + } + + uint32_t* theBuffer = (uint32_t*)input.payload; + int pagesize = header->payloadSize; + mDeco->setUpStream(theBuffer, pagesize); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + } + } + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getDecodingSpec(bool askDISTSTF) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("TF", o2::framework::ConcreteDataTypeMatcher{"HMP", "RAWDATA"}, o2::framework::Lifetime::Optional); + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back("HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("HMP", "INTRECORDS", 0, o2::framework::Lifetime::Timeframe); + + return DataProcessorSpec{ + "HMP-RawStreamDecoder", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<DataDecoderTask>()}, + Options{{"result-file", VariantType::String, "/tmp/hmpRawDecodeResults", {"Base name of the decoding results files."}}, + {"fast-decode", VariantType::Bool, false, {"Use the fast algorithm. (error 0.8%)"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx b/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx new file mode 100644 index 0000000000000..6cf8fbbb969b4 --- /dev/null +++ b/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx @@ -0,0 +1,351 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataDecoderSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to run the HMPID raw decoding +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> + +#include "TTree.h" +#include "TFile.h" + +#include <gsl/span> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/DataRefUtils.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "HMPIDWorkflow/DataDecoderSpec2.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void DataDecoderTask2::init(framework::InitContext& ic) +{ + + LOG(INFO) << "[HMPID Data Decoder - Init] ( create Raw Stream Decoder for " << Geo::MAXEQUIPMENTS << " equipments !"; + + mProduceResults = ic.options().get<bool>("get-results-statistics"); + mRootStatFile = ic.options().get<std::string>("result-file"); + mFastAlgorithm = ic.options().get<bool>("fast-decode"); + mDeco = new o2::hmpid::HmpidDecoder2(Geo::MAXEQUIPMENTS); + mDeco->init(); + mTotalDigits = 0; + mTotalFrames = 0; + + mExTimer.start(); + return; +} + +void DataDecoderTask2::run(framework::ProcessingContext& pc) +{ + mDeco->mDigits.clear(); + mTriggers.clear(); + LOG(INFO) << "[HMPID Data Decoder - Run] !"; + + decodeTF(pc); + // TODO: accept other types of Raw Streams ... + // decodeReadout(pc); + // decodeRawFile(pc); + + // Output the Digits/Triggers vector + orderTriggers(); + pc.outputs().snapshot(o2::framework::Output{"HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mDeco->mDigits); + pc.outputs().snapshot(o2::framework::Output{"HMP", "INTRECORDS", 0, o2::framework::Lifetime::Timeframe}, mTriggers); + + mExTimer.elapseMes("Decoding... Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + return; +} + +void DataDecoderTask2::endOfStream(framework::EndOfStreamContext& ec) +{ + // Records the statistics + float avgEventSize; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float avgBusyTime; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float numOfSamples; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float sumOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float squareOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float xb; + float yb; + + if (!mProduceResults) { + LOG(INFO) << "Skip the Stat file creation ! "; + } else { + TString filename = TString::Format("%s_stat.root", mRootStatFile.c_str()); + LOG(INFO) << "Create the stat file " << filename.Data(); + TFile mfileOut(TString::Format("%s", filename.Data()), "RECREATE"); + TTree* theObj[Geo::N_MODULES + 1]; + for (int i = 0; i < Geo::N_MODULES; i++) { // Create the TTree array + TString tit = TString::Format("HMPID Data Decoding Statistic results Mod=%d", i); + theObj[i] = new TTree("o2hmp", tit); + theObj[i]->Branch("x", &xb, "s"); + theObj[i]->Branch("y", &yb, "s"); + theObj[i]->Branch("Samples", &numOfSamples, "i"); + theObj[i]->Branch("Sum_of_charges", &sumOfCharges, "l"); + theObj[i]->Branch("Sum_of_square", &squareOfCharges, "l"); + } + theObj[Geo::N_MODULES] = new TTree("o2hmp", "HMPID Data Decoding Statistic results"); + theObj[Geo::N_MODULES]->Branch("Average_Event_Size", &avgEventSize, "F"); + theObj[Geo::N_MODULES]->Branch("Average_Busy_Time", &avgBusyTime, "F"); + + // Update the Stat for the Decoding + int numEqui = mDeco->getNumberOfEquipments(); + // cycle in order to update info for the last event + for (int i = 0; i < numEqui; i++) { + if (mDeco->mTheEquipments[i]->mNumberOfEvents > 0) { + mDeco->updateStatistics(mDeco->mTheEquipments[i]); + } + } + char summaryFileName[254]; + sprintf(summaryFileName, "%s_stat.txt", mRootStatFile.c_str()); + mDeco->writeSummaryFile(summaryFileName); + for (int e = 0; e < numEqui; e++) { + avgEventSize = mDeco->getAverageEventSize(e); + avgBusyTime = mDeco->getAverageBusyTime(e); + theObj[Geo::N_MODULES]->Fill(); + } + for (int m = 0; m < o2::hmpid::Geo::N_MODULES; m++) { + for (int y = 0; y < o2::hmpid::Geo::N_YCOLS; y++) { + for (int x = 0; x < o2::hmpid::Geo::N_XROWS; x++) { + xb = x; + yb = y; + numOfSamples = mDeco->getPadSamples(m, x, y); + sumOfCharges = mDeco->getPadSum(m, x, y); + squareOfCharges = mDeco->getPadSquares(m, x, y); + theObj[m]->Fill(); + } + } + } + for (int i = 0; i <= Geo::N_MODULES; i++) { + theObj[i]->Write(); + } + } + mExTimer.logMes("End the Decoding ! Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + mExTimer.stop(); + return; +} +//_________________________________________________________________________________________________ +// the decodeTF() function processes the the messages generated by the (sub)TimeFrame builder +void DataDecoderTask2::decodeTF(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decodeTF **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{"HMP", "RAWDATA", 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return; + } + } + } + + DPLRawParser parser(inputs, o2::framework::select("TF:HMP/RAWDATA")); + //mDeco->mDigits.clear(); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + int pointerToTheFirst = mDeco->mDigits.size(); + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(INFO) << "End Page decoding !"; + } + // std::cout << ">>>>" << pointerToTheFirst << "," << mDeco->mDigits.size() << std::endl; + mTriggers.push_back(o2::hmpid::Trigger(mDeco->mIntReco, pointerToTheFirst, mDeco->mDigits.size() - pointerToTheFirst)); + mTotalFrames++; + } + + mTotalDigits += mDeco->mDigits.size(); + LOG(INFO) << "Writing Digitis=" << mDeco->mDigits.size() << "/" << mTotalDigits << " Frame=" << mTotalFrames << " IntRec " << mDeco->mIntReco; + return; +} + +//_________________________________________________________________________________________________ +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +// TODO: rearrange, test +void DataDecoderTask2::decodeReadout(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode readout **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + DPLRawParser parser(inputs, o2::framework::select("readout:HMP/RAWDATA")); + // DPLRawParser parser(inputs, o2::framework::select("HMP/readout")); + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + } + return; +} + +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +// TODO: rearrange, test +void DataDecoderTask2::decodeRawFile(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode rawfile **************"; + + for (auto&& input : pc.inputs()) { + if (input.spec->binding == "file") { + + auto const* raw = input.payload; + size_t payloadSize = DataRefUtils::getPayloadSize(input); + + LOG(INFO) << " payloadSize=" << payloadSize; + if (payloadSize == 0) { + return; + } + + uint32_t* theBuffer = (uint32_t*)input.payload; + int pagesize = payloadSize; + mDeco->setUpStream(theBuffer, pagesize); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + } + } + return; +} + +void DataDecoderTask2::orderTriggers() +{ + std::vector<o2::hmpid::Digit> dig; + dig.clear(); + std::vector<o2::hmpid::Trigger> trg; + trg.clear(); + + // first arrange the triggers in chronological order + std::sort(mTriggers.begin(), mTriggers.end()); + // then build a new Digit Vector physically ordered for triggers + int i = 0; + int k = i; + o2::hmpid::Trigger tr; + int count = 0; + int firstEntry; + while (i < mTriggers.size()) { + tr = mTriggers[i]; + count = 0; + firstEntry = dig.size(); + while (k < mTriggers.size() && mTriggers[i].getTriggerID() == mTriggers[k].getTriggerID()) { + for (int j = mTriggers[k].getFirstEntry(); j <= mTriggers[k].getLastEntry(); j++) { + dig.push_back(mDeco->mDigits[j]); + count++; + } + k++; + } + tr.setDataRange(firstEntry, count); + trg.push_back(tr); + i = k; + } + + // then arrange the triggers in chamber order + for (int i = 0; i < trg.size(); i++) { + if (trg[i].getFirstEntry() > trg[i].getLastEntry()) { + continue; + } + std::sort(dig.begin() + trg[i].getFirstEntry(), dig.begin() + trg[i].getLastEntry()); + } + + mTriggers.swap(trg); + mDeco->mDigits.swap(dig); + trg.clear(); + dig.clear(); +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getDecodingSpec2(bool askDISTSTF) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("TF", o2::framework::ConcreteDataTypeMatcher{"HMP", "RAWDATA"}, o2::framework::Lifetime::Optional); + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back("HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("HMP", "INTRECORDS", 0, o2::framework::Lifetime::Timeframe); + + return DataProcessorSpec{ + "HMP-RawStreamDecoder", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<DataDecoderTask2>()}, + Options{{"get-results-statistics", VariantType::Bool, false, {"Generate intermediat output results."}}, + {"result-file", VariantType::String, "/tmp/hmpRawDecodeResults", {"Base name of the decoding results files."}}, + {"fast-decode", VariantType::Bool, false, {"Use the fast algorithm. (error 0.8%)"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/DigitsToRawSpec.cxx b/Detectors/HMPID/workflow/src/DigitsToRawSpec.cxx new file mode 100644 index 0000000000000..b72bf4ab3d381 --- /dev/null +++ b/Detectors/HMPID/workflow/src/DigitsToRawSpec.cxx @@ -0,0 +1,208 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file WriteRawFromDigitsSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to produce raw files from a Digits/Trigger root file +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> +#include <algorithm> +#include <filesystem> +#include "Framework/DataRefUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" + +#include "FairLogger.h" // for LOG +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +#include "TFile.h" +#include "TTree.h" +#include <TSystem.h> +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDSimulation/HmpidCoder2.h" +#include "HMPIDWorkflow/DigitsToRawSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void DigitsToRawSpec::init(framework::InitContext& ic) +{ + LOG(INFO) << "HMPID Write Raw File From Root sim Digits vector - init()"; + mDigitsReceived = 0; + mEventsReceived = 0; + mBaseRootFileName = ic.options().get<std::string>("in-file"); + mBaseFileName = ic.options().get<std::string>("outfile"); + mDirectoryName = ic.options().get<std::string>("outdir"); + mFileFor = ic.options().get<std::string>("file-for"); + mDumpDigits = ic.options().get<bool>("dump-digits"); // Debug flags + mSkipEmpty = ic.options().get<bool>("skip-empty"); + + // if needed, create output directory + if (!std::filesystem::exists(mDirectoryName)) { + if (!std::filesystem::create_directories(mDirectoryName)) { + LOG(FATAL) << "could not create output directory " << mDirectoryName; + } else { + LOG(INFO) << "created output directory " << mDirectoryName; + } + } + + std::string fullFName = o2::utils::Str::concat_string(mDirectoryName, "/", mBaseFileName); + + // Setup the Coder + mCod = new HmpidCoder2(Geo::MAXEQUIPMENTS); + mCod->setSkipEmptyEvents(mSkipEmpty); + mCod->openOutputStream(fullFName, mFileFor); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(inputGRP)}; + mCod->getWriter().setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::HMP)); // must be set explicitly + + // Open the ROOT file + TFile* fdig = TFile::Open(mBaseRootFileName.data()); + assert(fdig != nullptr); + LOG(INFO) << "Open Root digits file " << mBaseRootFileName.data(); + mDigTree = (TTree*)fdig->Get("o2sim"); + + // Ready to operate + mCod->getWriter().writeConfFile("HMP", "RAWDATA", o2::utils::Str::concat_string(mDirectoryName, '/', "HMPraw.cfg")); + mExTimer.start(); +} + +void DigitsToRawSpec::readRootFile() +{ + std::vector<o2::hmpid::Digit> digitsPerEvent; + std::vector<o2::hmpid::Digit> digits, *hmpBCDataPtr = &digits; + std::vector<o2::hmpid::Trigger> interactions, *interactionsPtr = &interactions; + + // Keeps the Interactions ! + mDigTree->SetBranchAddress("InteractionRecords", &interactionsPtr); + LOG(INFO) << "Number of Interaction Records vectors in the simulation file :" << mDigTree->GetEntries(); + for (int ient = 0; ient < mDigTree->GetEntries(); ient++) { + mDigTree->GetEntry(ient); + LOG(INFO) << "Interactions records in simulation :" << interactions.size(); + for (auto a : interactions) { + LOG(INFO) << a; + } + } + + mDigTree->SetBranchAddress("HMPDigit", &hmpBCDataPtr); + LOG(DEBUG) << "Number of entries in the simulation file :" << mDigTree->GetEntries(); + + // Loops in the Entry of ROOT Branch + for (int ient = 0; ient < mDigTree->GetEntries(); ient++) { + mDigTree->GetEntry(ient); + int nbc = digits.size(); + if (nbc == 0) { // exit for empty + LOG(INFO) << "The Entry :" << ient << " doesn't have digits !"; + continue; + } + if (mDumpDigits) { // we want the dump of digits ? + std::ofstream dumpfile; + dumpfile.open("/tmp/hmpDumpDigits.dat"); + for (o2::hmpid::Trigger& e : interactions) { + dumpfile << "Trigger Orbit=" << e.getOrbit() << " BC=" << e.getBc() << std::endl; + for (int i = e.getFirstEntry(); i <= e.getLastEntry(); i++) { + dumpfile << digits.at(i) << std::endl; + } + } + dumpfile.close(); + } + // ready to operate + LOG(INFO) << "For the entry = " << ient << " there are " << nbc << " DIGITS stored."; + for (o2::hmpid::Trigger& e : interactions) { + mEventsReceived++; + digitsPerEvent.clear(); + for (int i = e.getFirstEntry(); i <= e.getLastEntry(); i++) { + digitsPerEvent.push_back(digits[i]); + } + LOG(DEBUG) << "Orbit =" << e.getOrbit() << " BC =" << e.getBc() << " Digits =" << digitsPerEvent.size(); + if (digitsPerEvent.size() == 0) { + LOG(INFO) << "Empty event !" << e; + } + mCod->codeEventChunkDigits(digitsPerEvent, e.getIr()); + mDigitsReceived += digitsPerEvent.size(); + } + if (mDigitsReceived != digits.size()) { + LOG(WARNING) << "Digits outside the events defined !"; + } + } + mExTimer.logMes("End of Write raw file Job !"); + return; +} + +void DigitsToRawSpec::run(framework::ProcessingContext& pc) +{ + // Arrange Files path + readRootFile(); + mCod->closeOutputStream(); + mCod->dumpResults(mBaseRootFileName); + mExTimer.logMes("Raw File created ! Digits = " + std::to_string(mDigitsReceived) + " for Events =" + std::to_string(mEventsReceived)); + mExTimer.stop(); + pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); +} + +void DigitsToRawSpec::endOfStream(framework::EndOfStreamContext& ec) +{ + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getDigitsToRawSpec() +{ + std::vector<o2::framework::InputSpec> inputs; + std::vector<o2::framework::OutputSpec> outputs; + + return DataProcessorSpec{ + "digits-to-raw", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<DigitsToRawSpec>()}, + Options{{"outdir", VariantType::String, "./", {"base dir for output file"}}, + {"file-for", VariantType::String, "all", {"single file per: all,flp,link,cru"}}, + {"outfile", VariantType::String, "hmpid", {"base name for output file"}}, + {"in-file", VariantType::String, "hmpiddigits.root", {"name of the input sim root file"}}, + {"dump-digits", VariantType::Bool, false, {"out the digits file in /tmp/hmpDumpDigits.dat"}}, + {"skip-empty", VariantType::Bool, false, {"skip empty events"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx b/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx new file mode 100644 index 0000000000000..a9b85b1b7835a --- /dev/null +++ b/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx @@ -0,0 +1,151 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DumpDigitsSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to Dump o record a stream of Digits +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/DataRefUtils.h" +#include "Framework/InputRecordWalker.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDWorkflow/DumpDigitsSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::header; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void DumpDigitsTask::init(framework::InitContext& ic) +{ + LOG(INFO) << "[HMPID Dump Digits - init() ] "; + mPrintDigits = ic.options().get<bool>("print"); + + mIsOutputOnFile = false; + mOutputFileName = ic.options().get<std::string>("out-file"); + if (mOutputFileName != "") { + mOsFile.open(mOutputFileName, std::ios::out); + if (mOsFile.is_open()) { + mIsOutputOnFile = true; + } + } + if (mPrintDigits) { + std::cout << "--- HMP Digits : [Chamb,PhoCat,x,y]=Charge ---" << std::endl; + } + if (mIsOutputOnFile) { + mOsFile << "--- HMP Digits : [Chamb,PhoCat,x,y]=Charge ---" << std::endl; + } + mOrbit = -1; + mBc = -1; + mDigitsReceived = 0; + + mExTimer.start(); + return; +} + +void DumpDigitsTask::run(framework::ProcessingContext& pc) +{ + LOG(INFO) << "[HMPID Dump Digits - run() ] Enter Dump ..."; + std::vector<o2::hmpid::Trigger> triggers; + std::vector<o2::hmpid::Digit> digits; + + for (auto const& ref : InputRecordWalker(pc.inputs())) { + if (DataRefUtils::match(ref, {"check", ConcreteDataTypeMatcher{gDataOriginHMP, "INTRECORDS"}})) { + triggers = pc.inputs().get<std::vector<o2::hmpid::Trigger>>(ref); + LOG(INFO) << "We receive triggers =" << triggers.size(); + } + if (DataRefUtils::match(ref, {"check", ConcreteDataTypeMatcher{gDataOriginHMP, "DIGITS"}})) { + digits = pc.inputs().get<std::vector<o2::hmpid::Digit>>(ref); + LOG(INFO) << "The size of the vector =" << digits.size(); + mDigitsReceived += digits.size(); + } + for (int i = 0; i < triggers.size(); i++) { + if (mPrintDigits) { + std::cout << "Trigger Event Orbit = " << triggers[i].getOrbit() << " BC = " << triggers[i].getBc() << std::endl; + for (int j = triggers[i].getFirstEntry(); j <= triggers[i].getLastEntry(); j++) { + std::cout << digits[j] << std::endl; + } + } + if (mIsOutputOnFile) { + mOsFile << "Trigger Event Orbit = " << triggers[i].getOrbit() << " BC = " << triggers[i].getBc() << std::endl; + for (int j = triggers[i].getFirstEntry(); j <= triggers[i].getLastEntry(); j++) { + mOsFile << digits[j] << std::endl; + } + } + } + } + std::cout << ">>----->>>" << triggers.size() << " " << digits.size() << std::endl; + mExTimer.elapseMes("Dumping Digits received = " + std::to_string(mDigitsReceived)); + return; +} + +void DumpDigitsTask::endOfStream(framework::EndOfStreamContext& ec) +{ + mOsFile.close(); + + mExTimer.stop(); + mExTimer.logMes("End Digits Dump ! Dumped digits = " + std::to_string(mDigitsReceived)); + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getDumpDigitsSpec(std::string inputSpec) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("digits", o2::header::gDataOriginHMP, "DIGITS", 0, Lifetime::Timeframe); + inputs.emplace_back("intrecord", o2::header::gDataOriginHMP, "INTRECORDS", 0, Lifetime::Timeframe); + + std::vector<o2::framework::OutputSpec> outputs; + + return DataProcessorSpec{ + "HMP-DigitsDump", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<DumpDigitsTask>()}, + Options{{"out-file", VariantType::String, "", {"name of the output file"}}, + {"print", VariantType::Bool, false, {"print digits (default false )"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..a719716930bd8 --- /dev/null +++ b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "HMPIDWorkflow/EntropyDecoderSpec.h" +#include "HMPIDReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace hmpid +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::hmpid::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& triggers = pc.outputs().make<std::vector<Trigger>>(OutputRef{"triggers"}); + auto& digits = pc.outputs().make<std::vector<Digit>>(OutputRef{"digits"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::hmpid::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, triggers, digits); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << digits.size() << " HMPID digits in " << triggers.size() << " triggers in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "HMPID Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"triggers"}, "HMP", "INTRECORDS", 0, Lifetime::Timeframe}, + OutputSpec{{"digits"}, "HMP", "DIGITS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "hmpid-entropy-decoder", + Inputs{InputSpec{"ctf", "HMP", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace hmpid +} // namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..7258853eb87f7 --- /dev/null +++ b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "HMPIDWorkflow/EntropyEncoderSpec.h" +#include "HMPIDReconstruction/CTFCoder.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <TStopwatch.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace hmpid +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::hmpid::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto triggers = pc.inputs().get<gsl::span<Trigger>>("triggers"); + auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"HMP", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, triggers, digits); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for HMPID in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "HMPID Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("triggers", "HMP", "INTRECORDS", 0, Lifetime::Timeframe); + inputs.emplace_back("digits", "HMP", "DIGITS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "hmpid-entropy-encoder", + inputs, + Outputs{{"HMP", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace hmpid +} // namespace o2 diff --git a/Detectors/HMPID/workflow/src/PedestalsCalculationSpec.cxx b/Detectors/HMPID/workflow/src/PedestalsCalculationSpec.cxx new file mode 100644 index 0000000000000..5786e476a5efc --- /dev/null +++ b/Detectors/HMPID/workflow/src/PedestalsCalculationSpec.cxx @@ -0,0 +1,344 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file PedestalsCalculationSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to read a raw file and produce Pedestals/Threshold files +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> + +#include "TTree.h" +#include "TFile.h" +#include "TMath.h" +#include "TMatrixF.h" + +#include <gsl/span> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" + +#include "CCDB/CcdbApi.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "HMPIDWorkflow/PedestalsCalculationSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void PedestalsCalculationTask::init(framework::InitContext& ic) +{ + + LOG(INFO) << "[HMPID Pedestal Calculation - Init] ( create Decoder for " << Geo::MAXEQUIPMENTS << " equipments !"; + + mDeco = new o2::hmpid::HmpidDecoder2(Geo::MAXEQUIPMENTS); + mDeco->init(); + mTotalDigits = 0; + mTotalFrames = 0; + + mSigmaCut = ic.options().get<float>("sigmacut"); + mPedestalsBasePath = ic.options().get<std::string>("files-basepath"); + mPedestalTag = ic.options().get<std::string>("pedestals-tag"); + mDBapi.init(ic.options().get<std::string>("ccdb-uri")); // or http://localhost:8080 for a local installation + mWriteToDB = mDBapi.isHostReachable() ? true : false; + mFastAlgorithm = ic.options().get<bool>("fast-decode"); + + mExTimer.start(); + return; +} + +void PedestalsCalculationTask::run(framework::ProcessingContext& pc) +{ + decodeTF(pc); + // TODO: accept other types of Raw Streams ... + // decodeReadout(pc); + // decodeRawFile(pc);ccdb + + mExTimer.elapseMes("Decoding... Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + return; +} + +void PedestalsCalculationTask::endOfStream(framework::EndOfStreamContext& ec) +{ + double Average; + double Variance; + double Samples; + double SumOfCharge; + double SumOfSquares; + + uint32_t Buffer; + uint32_t Pedestal; + uint32_t Threshold; + char padsFileName[1024]; + + for (int e = 0; e < Geo::MAXEQUIPMENTS; e++) { + if (mDeco->getAverageEventSize(e) == 0) { + continue; + } + sprintf(padsFileName, "%s_%d.dat", mPedestalsBasePath.c_str(), e); + FILE* fpads = fopen(padsFileName, "w"); + // TODO: Add controls on the file open + for (int c = 0; c < Geo::N_COLUMNS; c++) { + for (int d = 0; d < Geo::N_DILOGICS; d++) { + for (int h = 0; h < Geo::N_CHANNELS; h++) { + Samples = (double)mDeco->getChannelSamples(e, c, d, h); + SumOfCharge = mDeco->getChannelSum(e, c, d, h); + SumOfSquares = mDeco->getChannelSquare(e, c, d, h); + + if (Samples > 0) { + Average = SumOfCharge / Samples; + Variance = sqrt(abs((Samples * SumOfSquares) - (SumOfCharge * SumOfCharge))) / Samples; + } else { + Average = 0; + Variance = 0; + } + Pedestal = (uint32_t)Average; + Threshold = (uint32_t)(Variance * mSigmaCut + Average); + Buffer = ((Threshold & 0x001FF) << 9) | (Pedestal & 0x001FF); + fprintf(fpads, "%05X\n", Buffer); + } + for (int h = 48; h < 64; h++) { + fprintf(fpads, "%05X\n", 0); + } + } + } + mExTimer.logMes("End write the equipment = " + std::to_string(e)); + fprintf(fpads, "%05X\n", 0xA0A0A); + fclose(fpads); + } + mExTimer.logMes("End Writing the pedestals ! Digits decoded = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + + if (mWriteToDB) { + recordPedInCcdb(); + } + mExTimer.stop(); + return; +} + +void PedestalsCalculationTask::recordPedInCcdb() +{ + // create the root structure + + LOG(INFO) << "Store Pedestals in ccdb "; + + float xb, yb, ch; + double Samples, SumOfCharge, SumOfSquares, Average, Variance; + + TObjArray aSigmas(Geo::N_MODULES); + TObjArray aPedestals(Geo::N_MODULES); + + for (int i = 0; i < Geo::N_MODULES; i++) { + aSigmas.AddAt(new TMatrixF(160, 144), i); + aPedestals.AddAt(new TMatrixF(160, 144), i); + } + + for (int m = 0; m < o2::hmpid::Geo::N_MODULES; m++) { + if (mDeco->getAverageEventSize(m * 2) == 0 && mDeco->getAverageEventSize(m * 2 + 1) == 0) { + continue; // If no events skip the chamber + } + TMatrixF* pS = (TMatrixF*)aSigmas.At(m); + TMatrixF* pP = (TMatrixF*)aPedestals.At(m); + + for (int x = 0; x < o2::hmpid::Geo::N_XROWS; x++) { + for (int y = 0; y < o2::hmpid::Geo::N_YCOLS; y++) { + + Samples = (double)mDeco->getPadSamples(m, x, y); + SumOfCharge = mDeco->getPadSum(m, x, y); + SumOfSquares = mDeco->getPadSquares(m, x, y); + if (Samples > 0) { + (*pP)(x, y) = SumOfCharge / Samples; + (*pS)(x, y) = sqrt(abs((Samples * SumOfSquares) - (SumOfCharge * SumOfCharge))) / Samples; + } else { + (*pP)(x, y) = 0; + (*pS)(x, y) = 0; + } + } + } + } + struct timeval tp; + gettimeofday(&tp, nullptr); + uint64_t ms = tp.tv_sec * 1000 + tp.tv_usec / 1000; + + uint64_t minTimeStamp = ms; + uint64_t maxTimeStamp = ms + 1; + + for (int i = 0; i < Geo::N_MODULES; i++) { + if (mDeco->getAverageEventSize(i * 2) == 0 && mDeco->getAverageEventSize(i * 2 + 1) == 0) { + continue; // If no events skip the chamber + } + TString filename = TString::Format("HMP/Pedestals/%s/Mean_%d", mPedestalTag.c_str(), i); + mDbMetadata.emplace("Tag", mPedestalTag.c_str()); + mDBapi.storeAsTFileAny(aPedestals.At(i), filename.Data(), mDbMetadata, minTimeStamp, maxTimeStamp); + } + for (int i = 0; i < Geo::N_MODULES; i++) { + if (mDeco->getAverageEventSize(i * 2) == 0 && mDeco->getAverageEventSize(i * 2 + 1) == 0) { + continue; // If no events skip the chamber + } + TString filename = TString::Format("HMP/Pedestals/%s/Sigma_%d", mPedestalTag.c_str(), i); + mDbMetadata.emplace("Tag", mPedestalTag.c_str()); + mDBapi.storeAsTFileAny(aSigmas.At(i), filename.Data(), mDbMetadata, minTimeStamp, maxTimeStamp); + } + return; +} + +//_________________________________________________________________________________________________ +// the decodeTF() function processes the the messages generated by the (sub)TimeFrame builder +void PedestalsCalculationTask::decodeTF(framework::ProcessingContext& pc) +{ + LOG(DEBUG) << "*********** In decodeTF **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + DPLRawParser parser(inputs, o2::framework::select("TF:HMP/RAWDATA")); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Fast Page decoding !"; + } + mTotalFrames++; + mTotalDigits += mDeco->mDigits.size(); + } + return; +} +//pc.outputs().make +//_________________________________________________________________________________________________ +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +void PedestalsCalculationTask::decodeReadout(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode readout **************"; + + // get the input buffer + auto& inputs = pc.inputs(); + DPLRawParser parser(inputs, o2::framework::select("readout:HMP/RAWDATA")); + // DPLRawParser parser(inputs, o2::framework::select("HMP/readout")); + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + uint32_t* theBuffer = (uint32_t*)it.raw(); + mDeco->setUpStream(theBuffer, it.size() + it.offset()); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Fast Page decoding !"; + } + } + return; +} + +// the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow +void PedestalsCalculationTask::decodeRawFile(framework::ProcessingContext& pc) +{ + LOG(INFO) << "*********** In decode rawfile **************"; + + for (auto&& input : pc.inputs()) { + if (input.spec->binding == "file") { + const header::DataHeader* header = o2::header::get<header::DataHeader*>(input.header); + if (!header) { + return; + } + + auto const* raw = input.payload; + size_t payloadSize = header->payloadSize; + + LOG(INFO) << " payloadSize=" << payloadSize; + if (payloadSize == 0) { + return; + } + + uint32_t* theBuffer = (uint32_t*)input.payload; + int pagesize = header->payloadSize; + mDeco->setUpStream(theBuffer, pagesize); + try { + if (mFastAlgorithm) { + mDeco->decodePageFast(&theBuffer); + } else { + mDeco->decodePage(&theBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Fast Page decoding !"; + } + } + } + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getPedestalsCalculationSpec(std::string inputSpec) +{ + + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("TF", o2::framework::ConcreteDataTypeMatcher{"HMP", "RAWDATA"}, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("file", o2::framework::ConcreteDataTypeMatcher{"ROUT", "RAWDATA"}, o2::framework::Lifetime::Timeframe); + // inputs.emplace_back("readout", o2::header::gDataOriginHMP, "RAWDATA", 0, Lifetime::Timeframe); + // inputs.emplace_back("readout", o2::header::gDataOriginHMP, "RAWDATA", 0, Lifetime::Timeframe); + // inputs.emplace_back("rawfile", o2::header::gDataOriginHMP, "RAWDATA", 0, Lifetime::Timeframe); + + std::vector<o2::framework::OutputSpec> outputs; + // outputs.emplace_back("HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + + return DataProcessorSpec{ + "HMP-DataDecoder", + o2::framework::select(inputSpec.c_str()), + outputs, + AlgorithmSpec{adaptFromTask<PedestalsCalculationTask>()}, + Options{{"files-basepath", VariantType::String, "/tmp/hmpPedThr", {"Name of the Base Path of Pedestals/Thresholds files."}}, + {"use-ccdb", VariantType::Bool, false, {"Register the Pedestals/Threshold values into the CCDB"}}, + {"ccdb-uri", VariantType::String, "http://ccdb-test.cern.ch:8080", {"URI for the CCDB access."}}, + {"fast-decode", VariantType::Bool, false, {"Use the fast algorithm. (error 0.8%)"}}, + {"pedestals-tag", VariantType::String, "Latest", {"The tag applied to this set of pedestals/threshold values"}}, + {"sigmacut", VariantType::Float, 4.0f, {"Sigma values for the Thresholds calculation."}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/RawToDigitsSpec.cxx b/Detectors/HMPID/workflow/src/RawToDigitsSpec.cxx new file mode 100644 index 0000000000000..a505bea538b20 --- /dev/null +++ b/Detectors/HMPID/workflow/src/RawToDigitsSpec.cxx @@ -0,0 +1,395 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RawToDigitsSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 18 mar 2021 +/// \brief Implementation of a data processor to produce Digits from Raw files +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> +#include <algorithm> + +#include "DPLUtils/DPLRawParser.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" + +#include "TTree.h" +#include "TFile.h" + +#include <gsl/span> + +#include "Framework/InputSpec.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RawFileReader.h" +#include "DetectorsRaw/RDHUtils.h" + +#include "CommonDataFormat/InteractionRecord.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDReconstruction/HmpidDecoder2.h" +#include "HMPIDWorkflow/RawToDigitsSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; +using namespace o2::hmpid::raw; + +//======================= +// Data decoder +void RawToDigitsTask::init(framework::InitContext& ic) +{ + LOG(INFO) << "[HMPID Write Root File From Raw Files - init()]"; + + // get line command options + mOutRootFileName = ic.options().get<std::string>("out-file"); + mBaseFileName = ic.options().get<std::string>("base-file"); + mInputRawFileName = ic.options().get<std::string>("in-file"); + mFastAlgorithm = ic.options().get<bool>("fast-decode"); + mDigitsReceived = 0; + mFramesReceived = 0; + + mReader.setDefaultDataOrigin(o2::header::gDataOriginHMP); + mReader.setDefaultDataDescription(o2::header::gDataDescriptionRawData); + mReader.setDefaultReadoutCardType(o2::raw::RawFileReader::RORC); + mReader.addFile(mInputRawFileName); + mReader.init(); + + mDecod = new o2::hmpid::HmpidDecoder2(Geo::MAXEQUIPMENTS); + mDecod->init(); + + mExTimer.start(); + return; +} + +void RawToDigitsTask::run(framework::ProcessingContext& pc) +{ + bool isInLoop = true; + int tfID; + std::vector<char> dataBuffer; // where to put extracted data + + if (mReader.getNTimeFrames() == 0) { + parseNoTF(); + isInLoop = false; + } + + while (isInLoop) { + tfID = mReader.getNextTFToRead(); + if (tfID >= mReader.getNTimeFrames()) { + LOG(INFO) << "nothing left to read after " << tfID << " TFs read"; + break; + } + for (int il = 0; il < mReader.getNLinks(); il++) { + auto& link = mReader.getLink(il); + LOG(INFO) << "Decoding link " << il; + auto sz = link.getNextTFSize(); // size in char needed for the next TF of this link + dataBuffer.resize(sz); + link.readNextTF(dataBuffer.data()); + link.rewindToTF(tfID); + int nhbf = link.getNHBFinTF(); + LOG(DEBUG) << " Number of HBF " << nhbf; + for (int ib = 0; ib < nhbf; ib++) { + auto zs = link.getNextHBFSize(); // size in char needed for the next TF of this link + dataBuffer.resize(zs); + link.readNextHBF(dataBuffer.data()); + // Parse + uint32_t* ptrBuffer = (uint32_t*)dataBuffer.data(); + uint32_t* ptrBufferEnd = ptrBuffer + zs / 4; + mDecod->setUpStream(ptrBuffer, zs); + while (ptrBuffer < ptrBufferEnd) { + try { + if (mFastAlgorithm) { + mDecod->decodePageFast(&ptrBuffer); + } else { + mDecod->decodePage(&ptrBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Page decoding !"; + } + int first = mAccumulateDigits.size(); + mAccumulateDigits.insert(mAccumulateDigits.end(), mDecod->mDigits.begin(), mDecod->mDigits.end()); + int last = mAccumulateDigits.size(); + if (last > first) { + mEvents.emplace_back(o2::hmpid::Trigger{mDecod->mIntReco, first, last - first}); + mDigitsReceived += mDecod->mDigits.size(); + } + mFramesReceived++; + LOG(DEBUG) << "run() Digits received =" << mDigitsReceived << " frames = " << mFramesReceived << " size=" << sz << " F-L " << first << "," << last << " " << mDecod->mIntReco; + mDecod->mDigits.clear(); + } + } + } + mReader.setNextTFToRead(++tfID); + } + mTotalDigits += mDigitsReceived; + mTotalFrames += mFramesReceived; + + mExTimer.logMes("End of Decoding ! Digits = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + + writeResults(); + + // pc.services().get<ControlService>().endOfStream(); + pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); + mExTimer.stop(); + return; +} + +void RawToDigitsTask::endOfStream(framework::EndOfStreamContext& ec) +{ + mExTimer.logMes("Received an End Of Stream !"); + return; +} + +void RawToDigitsTask::parseNoTF() +{ + std::vector<char> dataBuffer; // where to put extracted data + + for (int il = 0; il < mReader.getNLinks(); il++) { + auto& link = mReader.getLink(il); + LOG(INFO) << "Decoding link " << il; + auto sz = link.getNextTFSize(); // size in char needed for the next TF of this link + LOG(INFO) << " Size TF " << sz; + dataBuffer.resize(sz); + link.readNextTF(dataBuffer.data()); + + uint32_t* ptrBuffer = (uint32_t*)dataBuffer.data(); + uint32_t* ptrBufferEnd = ptrBuffer + sz / 4; + mDecod->setUpStream(ptrBuffer, sz); + while (ptrBuffer < ptrBufferEnd) { + try { + if (mFastAlgorithm) { + mDecod->decodePageFast(&ptrBuffer); + } else { + mDecod->decodePage(&ptrBuffer); + } + } catch (int e) { + // The stream end ! + LOG(DEBUG) << "End Fast Page decoding !"; + } + int first = mAccumulateDigits.size(); + mAccumulateDigits.insert(mAccumulateDigits.end(), mDecod->mDigits.begin(), mDecod->mDigits.end()); + int last = mAccumulateDigits.size(); + if (last > first) { + mEvents.emplace_back(mDecod->mIntReco, first, last - first); + mDigitsReceived += mDecod->mDigits.size(); + } + mFramesReceived++; + LOG(INFO) << "run() Digits received =" << mDigitsReceived << " frames = " << mFramesReceived << " size=" << sz << " F-L " << first << "," << last << " " << mDecod->mIntReco; + mDecod->mDigits.clear(); + } + } + return; +} + +void RawToDigitsTask::writeResults() +{ + int numEqui = mDecod->getNumberOfEquipments(); // Update the Stat for the Decoding + for (int i = 0; i < numEqui; i++) { + if (mDecod->mTheEquipments[i]->mNumberOfEvents > 0) { + mDecod->updateStatistics(mDecod->mTheEquipments[i]); + } + } + if (mEvents.size() == 0) { // check if no evwnts + LOG(INFO) << "There are not Event recorded ! Abort. "; + mExTimer.stop(); + return; + } + for (int i = mEvents.size() - 1; i >= 0; i--) { // remove events that are (0,0) trigger + if (mEvents[i].getTriggerID() == 0) { + mEvents.erase(mEvents.begin() + i); + } + } + sort(mEvents.begin(), mEvents.end()); // sort the events + mExTimer.logMes("Sorted Events = " + std::to_string(mEvents.size())); + + /* ------ ROOT file version 1 ---------- + o2::hmpid::Digit digit; + o2::hmpid::Trigger event; + TString filename; + TString tit; + + filename = TString::Format("%s", mOutRootFileName.c_str()); + LOG(INFO) << "Create the ROOT file " << filename.Data(); + TFile mfileOut(TString::Format("%s", filename.Data()), "RECREATE"); + TTree* theTree; + TBranch* theDigits; + TBranch* theEvents; + tit = TString::Format("HMPID Raw File Decoding"); + theTree = new TTree("o2hmp", tit); + + theDigits = theTree->Branch("HMPDigit", &digit, sizeof(o2::hmpid::Digit), 1); + theEvents = theTree->Branch("InteractionRecords", &event, sizeof(o2::hmpid::Trigger), 1); + + o2::hmpid::Trigger prevEvent = mEvents[0]; + uint32_t theFirstDigit = 0; + uint32_t theLastDigit = 0; + for (int e = 0; e < mEvents.size(); e++) { + LOG(INFO) << "Manage event " << mEvents[e]; + if (prevEvent != mEvents[e]) { // changes the event Flush It + event = prevEvent; + event.setDataRange(theFirstDigit, theLastDigit-theFirstDigit); + theEvents->Fill(); + theFirstDigit = theLastDigit; + prevEvent = mEvents[e]; + } + int first = mEvents[e].getFirstEntry(); + int last = mEvents[e].getLastEntry(); + for(int idx = first; idx <= last; idx++) { + digit = mAccumulateDigits[idx]; + theDigits->Fill(); + theLastDigit++; + } + } + event = prevEvent; + event.setDataRange(theFirstDigit, theLastDigit-theFirstDigit); + theEvents->Fill(); + theTree->Write(); + mfileOut.Close(); + -------------------------- */ + + // ---------- ROOT file version 2 --------------- + TString filename; + TString tit; + + std::vector<o2::hmpid::Digit> digitVec; + std::vector<o2::hmpid::Trigger> eventVec; + + filename = TString::Format("%s", mOutRootFileName.c_str()); + LOG(INFO) << "Create the ROOT file " << filename.Data(); + TFile mfileOut(TString::Format("%s", filename.Data()), "RECREATE"); + tit = TString::Format("HMPID Raw File Decoding"); + TTree* theTree = new TTree("o2hmp", tit); + + theTree->Branch("InteractionRecords", &eventVec); + theTree->Branch("HMPIDDigits", &digitVec); + + // builds the two arranged vectors of objects + o2::hmpid::Trigger prevEvent = mEvents[0]; + uint32_t theFirstDigit = 0; + uint32_t theLastDigit = 0; + for (int e = 0; e < mEvents.size(); e++) { + LOG(DEBUG) << "Manage event " << mEvents[e]; + if (prevEvent != mEvents[e]) { // changes the event Flush It + eventVec.emplace_back(o2::InteractionRecord(prevEvent.getBc(), prevEvent.getOrbit()), theFirstDigit, theLastDigit - theFirstDigit); + theFirstDigit = theLastDigit; + prevEvent = mEvents[e]; + } + int first = mEvents[e].getFirstEntry(); + int last = mEvents[e].getLastEntry(); + for (int idx = first; idx <= last; idx++) { + digitVec.push_back(mAccumulateDigits[idx]); + theLastDigit++; + } + } + eventVec.emplace_back(o2::InteractionRecord(prevEvent.getBc(), prevEvent.getOrbit()), theFirstDigit, theLastDigit - theFirstDigit); + theTree->Fill(); + theTree->Write(); + mfileOut.Close(); + mExTimer.logMes("Register Tree ! "); + + // ---------- Records the statistics ----------------- + float avgEventSize; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float avgBusyTime; //[o2::hmpid::Geo::MAXEQUIPMENTS]; + float numOfSamples; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float sumOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float squareOfCharges; //[o2::hmpid::Geo::N_MODULES][o2::hmpid::Geo::N_YCOLS][o2::hmpid::Geo::N_XROWS]; + float xb; + float yb; + + filename = TString::Format("%s_stat.root", mBaseFileName.c_str()); + LOG(INFO) << "Create the ROOT file " << filename.Data(); + TFile mfileOutStat(TString::Format("%s", filename.Data()), "RECREATE"); + TTree* theObj[Geo::N_MODULES + 1]; + for (int i = 0; i < Geo::N_MODULES; i++) { // Create the TTree array + tit = TString::Format("HMPID Data Decoding Statistic results Mod=%d", i); + theObj[i] = new TTree("o2hmp", tit); + theObj[i]->Branch("x", &xb, "s"); + theObj[i]->Branch("y", &yb, "s"); + theObj[i]->Branch("Samples", &numOfSamples, "i"); + theObj[i]->Branch("Sum_of_charges", &sumOfCharges, "l"); + theObj[i]->Branch("Sum_of_square", &squareOfCharges, "l"); + } + theObj[Geo::N_MODULES] = new TTree("o2hmp", "HMPID Data Decoding Statistic results"); + theObj[Geo::N_MODULES]->Branch("Average_Event_Size", &avgEventSize, "F"); + theObj[Geo::N_MODULES]->Branch("Average_Busy_Time", &avgBusyTime, "F"); + + char summaryFileName[254]; + sprintf(summaryFileName, "%s_stat.txt", mBaseFileName.c_str()); + mDecod->writeSummaryFile(summaryFileName); + for (int e = 0; e < numEqui; e++) { + avgEventSize = mDecod->getAverageEventSize(e); + avgBusyTime = mDecod->getAverageBusyTime(e); + theObj[Geo::N_MODULES]->Fill(); + } + for (int m = 0; m < o2::hmpid::Geo::N_MODULES; m++) { + for (int y = 0; y < o2::hmpid::Geo::N_YCOLS; y++) { + for (int x = 0; x < o2::hmpid::Geo::N_XROWS; x++) { + xb = x; + yb = y; + numOfSamples = mDecod->getPadSamples(m, x, y); + sumOfCharges = mDecod->getPadSum(m, x, y); + squareOfCharges = mDecod->getPadSquares(m, x, y); + theObj[m]->Fill(); + } + } + } + for (int i = 0; i <= Geo::N_MODULES; i++) { + theObj[i]->Write(); + } + + mExTimer.logMes("End storing results ! Digits = " + std::to_string(mTotalDigits) + " Frames received = " + std::to_string(mTotalFrames)); + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getRawToDigitsSpec(std::string inputSpec) +{ + std::vector<o2::framework::InputSpec> inputs; + std::vector<o2::framework::OutputSpec> outputs; + + return DataProcessorSpec{ + "HMP-RawToDigits", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<RawToDigitsTask>()}, + Options{{"in-file", VariantType::String, "hmpidRaw.raw", {"name of the input Raw file"}}, + {"fast-decode", VariantType::Bool, false, {"Use the fast algorithm. (error 0.8%)"}}, + {"out-file", VariantType::String, "hmpReco.root", {"name of the output file"}}, + {"base-file", VariantType::String, "hmpDecode", {"base name for statistical output file"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/ReadRawFileSpec.cxx b/Detectors/HMPID/workflow/src/ReadRawFileSpec.cxx new file mode 100644 index 0000000000000..98ff8677c39da --- /dev/null +++ b/Detectors/HMPID/workflow/src/ReadRawFileSpec.cxx @@ -0,0 +1,149 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ReadRawFileSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to read a raw file and produce Raw Pages stream +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "HMPIDWorkflow/ReadRawFileSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +void RawFileReaderTask::init(framework::InitContext& ic) +{ + LOG(INFO) << "Raw file reader init "; + + // read input parameters + mPrint = ic.options().get<bool>("print"); + std::string inFileName = ic.options().get<std::string>("raw-file"); + mInputFile.open(inFileName, std::ios::binary); + if (!mInputFile.is_open()) { + throw std::invalid_argument("Cannot open input file \"" + inFileName + "\""); + } + + auto stop = [this]() { + LOG(INFO) << "stop file reader"; // close the input file + this->mInputFile.close(); + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + + mExTimer.start(); + return; +} + +void RawFileReaderTask::run(framework::ProcessingContext& pc) +{ + + RDH rdh; + char* outBuffer{nullptr}; + size_t bufSize{0}; + int numberOfFrames = 0; + LOG(INFO) << "Sleep 1 sec for sync"; + sleep(1); + + while (true) { + //usleep(100); + mInputFile.read((char*)(&rdh), sizeof(RDH)); // read the next RDH, stop if no more data is available + if (mInputFile.fail()) { + free(outBuffer); + mInputFile.close(); + pc.services().get<ControlService>().endOfStream(); + pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); + break; + } + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + LOG(DEBUG) << "header_version=" << (int)rdhVersion; + if (rdhVersion < 6 || rdhHeaderSize != 64) { + LOG(INFO) << "Old or corrupted raw file, abort !"; + return; + } + auto frameSize = o2::raw::RDHUtils::getOffsetToNext(rdh); // get the frame size + LOG(DEBUG) << "frameSize=" << frameSize; + if (frameSize < rdhHeaderSize) { // stop if the frame size is too small + LOG(INFO) << "Wrong Frame size - frameSize too small: " << frameSize; + pc.services().get<ControlService>().endOfStream(); + return; + } + numberOfFrames++; + LOG(DEBUG) << "Process page " << numberOfFrames << " dim = " << frameSize; + + outBuffer = (char*)realloc(outBuffer, bufSize + frameSize); // allocate the buffer + if (outBuffer == nullptr) { + LOG(INFO) << "Buffer allocation error. Abort !"; + pc.services().get<ControlService>().endOfStream(); + return; + } + memcpy(outBuffer, &rdh, rdhHeaderSize); // fill the buffer + mInputFile.read(outBuffer + rdhHeaderSize, frameSize - rdhHeaderSize); + if (mInputFile.fail()) { // Could be EoF + free(outBuffer); + pc.services().get<ControlService>().endOfStream(); + pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); + break; // probably reached eof + } + bufSize = frameSize; // Set the buffer pointer + pc.outputs().snapshot(Output{"HMP", "RAWDATA"}, outBuffer, bufSize); + //std::cout << mExTimer.mTimer.CpuTime() << " " << mExTimer.mLastLogTime << std::endl; + mExTimer.elapseMes("... Reading... Number of Pages = " + std::to_string(numberOfFrames)); + } // while (true) + + mExTimer.logMes("End of file ! Number of frames processed = " + std::to_string(numberOfFrames)); + mExTimer.stop(); + return; +} + +//_________________________________________________________________________________________________ +// clang-format off +o2::framework::DataProcessorSpec getReadRawFileSpec(std::string inputSpec) +{ + std::vector<o2::framework::InputSpec> inputs; + return DataProcessorSpec{ + "HMP-ReadRawFile", + inputs, + Outputs{OutputSpec{"HMP", "RAWDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<RawFileReaderTask>()}, + Options{{"raw-file", VariantType::String, "", {"Raw input file name"}}, + {"print", VariantType::Bool, false, {"verbose output"}}}}; +} +// clang-format on + +} // end namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/WriteRawFileSpec.cxx b/Detectors/HMPID/workflow/src/WriteRawFileSpec.cxx new file mode 100644 index 0000000000000..09b42f7364c10 --- /dev/null +++ b/Detectors/HMPID/workflow/src/WriteRawFileSpec.cxx @@ -0,0 +1,172 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file WriteRawFileSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to produce raw files from a Digits stream +/// + +#include "HMPIDWorkflow/WriteRawFileSpec.h" + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <vector> +#include <algorithm> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/DataRefUtils.h" +#include "Framework/InputRecordWalker.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "CommonDataFormat/InteractionRecord.h" + +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::header; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void WriteRawFileTask::init(framework::InitContext& ic) +{ + LOG(INFO) << "[HMPID Write Raw File From Digits vector - init()]"; + mBaseFileName = ic.options().get<std::string>("out-file"); + mSkipEmpty = ic.options().get<bool>("skip-empty"); + mFixedPacketLenght = ic.options().get<bool>("fixed-lenght"); + mOrderTheEvents = ic.options().get<bool>("order-events"); + mDigitsReceived = 0; + mFramesReceived = 0; + + mCod = new HmpidCoder2(Geo::MAXEQUIPMENTS); + mCod->setSkipEmptyEvents(mSkipEmpty); + mCod->openOutputStream(mBaseFileName.c_str(), "all"); + + mExTimer.start(); + return; +} + +void WriteRawFileTask::run(framework::ProcessingContext& pc) +{ + std::vector<o2::hmpid::Trigger> triggers; + std::vector<o2::hmpid::Digit> digits; + + for (auto const& ref : InputRecordWalker(pc.inputs())) { + if (DataRefUtils::match(ref, {"check", ConcreteDataTypeMatcher{gDataOriginHMP, "INTRECORDS"}})) { + triggers = pc.inputs().get<std::vector<o2::hmpid::Trigger>>(ref); + } + if (DataRefUtils::match(ref, {"check", ConcreteDataTypeMatcher{gDataOriginHMP, "DIGITS"}})) { + digits = pc.inputs().get<std::vector<o2::hmpid::Digit>>(ref); + LOG(DEBUG) << "The size of the vector =" << digits.size(); + } + } + + for (int i = 0; i < triggers.size(); i++) { + if (mOrderTheEvents) { + int first = mDigits.size(); + mDigits.insert(mDigits.end(), digits.begin() + triggers[i].getFirstEntry(), digits.begin() + triggers[i].getLastEntry()); + mEvents.push_back({triggers[i].getIr(), first, int(mDigits.size() - first)}); + } else { + std::vector<o2::hmpid::Digit> dig = {digits.begin() + triggers[i].getFirstEntry(), digits.begin() + triggers[i].getLastEntry()}; + mCod->codeEventChunkDigits(dig, triggers[i].getIr()); + } + } + mDigitsReceived += digits.size(); + mFramesReceived++; + LOG(DEBUG) << "run() Digits received =" << mDigitsReceived << " frames = " << mFramesReceived; + + mExTimer.elapseMes("Write raw file ... Digits received = " + std::to_string(mDigitsReceived) + " Frames received = " + std::to_string(mFramesReceived)); + return; +} + +void WriteRawFileTask::endOfStream(framework::EndOfStreamContext& ec) +{ + std::vector<o2::hmpid::Digit> dig; + + mExTimer.logMes("Received an End Of Stream !"); + if (mOrderTheEvents && mEvents.size() > 0) { + sort(mEvents.begin(), mEvents.end()); + uint32_t orbit = mEvents[0].getOrbit(); + uint16_t bc = mEvents[0].getBc(); + for (int idx = 0; idx < mEvents.size(); idx++) { + if (mSkipEmpty && (mEvents[idx].getNumberOfObjects() == 0 || mEvents[idx].getOrbit() == 0)) { + continue; + } + if (mEvents[idx].getOrbit() != orbit || mEvents[idx].getBc() != bc) { + mCod->codeEventChunkDigits(dig, o2::InteractionRecord(bc, orbit)); + LOG(INFO) << " Event :" << idx << " orbit=" << orbit << " bc=" << bc << " Digits:" << dig.size(); + dig.clear(); + orbit = mEvents[idx].getOrbit(); + bc = mEvents[idx].getBc(); + } + for (int i = mEvents[idx].getFirstEntry(); i <= mEvents[idx].getLastEntry(); i++) { + dig.push_back(mDigits[i]); + } + } + mCod->codeEventChunkDigits(dig, o2::InteractionRecord(bc, orbit)); + LOG(INFO) << " Event :" << mEvents.size() - 1 << " orbit=" << orbit << " bc=" << bc << " Digits:" << dig.size(); + } + mCod->closeOutputStream(); + mCod->dumpResults("all"); + + mExTimer.logMes("Raw File created ! Digits received = " + std::to_string(mDigitsReceived) + " Frame received =" + std::to_string(mFramesReceived)); + mExTimer.stop(); + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getWriteRawFileSpec(std::string inputSpec) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("digits", o2::header::gDataOriginHMP, "DIGITS", 0, Lifetime::Timeframe); + inputs.emplace_back("intrecord", o2::header::gDataOriginHMP, "INTRECORDS", 0, Lifetime::Timeframe); + + std::vector<o2::framework::OutputSpec> outputs; + + return DataProcessorSpec{ + "HMP-WriteRawFile", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<WriteRawFileTask>()}, + Options{{"out-file", VariantType::String, "hmpidRaw", {"name of the output file"}}, + {"order-events", VariantType::Bool, false, {"order the events time"}}, + {"skip-empty", VariantType::Bool, false, {"skip empty events"}}, + {"fixed-lenght", VariantType::Bool, false, {"fixed lenght packets = 8K bytes"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/digits-to-raw-stream-workflow.cxx b/Detectors/HMPID/workflow/src/digits-to-raw-stream-workflow.cxx new file mode 100644 index 0000000000000..1b619ab523e61 --- /dev/null +++ b/Detectors/HMPID/workflow/src/digits-to-raw-stream-workflow.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file write-raw-from-digits-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "CommonUtils/ConfigurableParam.h" + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(CompletionPolicyHelpers::defineByName("digit-hmpid-write", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" +#include "../include/HMPIDWorkflow/WriteRawFileSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + DataProcessorSpec consumer = o2::hmpid::getWriteRawFileSpec(); + specs.push_back(consumer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx b/Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx new file mode 100644 index 0000000000000..5d707194abc06 --- /dev/null +++ b/Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digits-to-raw-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(o2::framework::CompletionPolicyHelpers::defineByName("digit-hmpid-write", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); + + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); +} + +#include "Framework/runDataProcessing.h" +#include "HMPIDWorkflow/DigitsToRawSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + DataProcessorSpec consumer = o2::hmpid::getDigitsToRawSpec(); + specs.push_back(consumer); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return specs; +} diff --git a/Detectors/HMPID/workflow/src/dump-digits-stream-workflow.cxx b/Detectors/HMPID/workflow/src/dump-digits-stream-workflow.cxx new file mode 100644 index 0000000000000..869e2fbcb0450 --- /dev/null +++ b/Detectors/HMPID/workflow/src/dump-digits-stream-workflow.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file dump-digits-workflow.cxx +/// \author Antonio Franco +/// +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "CommonUtils/ConfigurableParam.h" + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(CompletionPolicyHelpers::defineByName("digit-hmpid-dump", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" +#include "HMPIDWorkflow/DumpDigitsSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + DataProcessorSpec consumer = o2::hmpid::getDumpDigitsSpec(); + specs.push_back(consumer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..298158cb2f0df --- /dev/null +++ b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "HMPIDWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::hmpid::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/HMPID/workflow/src/raw-to-digits-stream-workflow.cxx b/Detectors/HMPID/workflow/src/raw-to-digits-stream-workflow.cxx new file mode 100644 index 0000000000000..4a142232fc925 --- /dev/null +++ b/Detectors/HMPID/workflow/src/raw-to-digits-stream-workflow.cxx @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/Variant.h" + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector<o2::framework::DispatchPolicy>& policies) +{ + using DispatchOp = o2::framework::DispatchPolicy::DispatchOp; + auto readerMatcher = [](auto const& spec) { + return true; + }; + auto triggerMatcher = [](auto const& query) { + return true; + }; + policies.push_back({"decoded-hmpid-digits", readerMatcher, DispatchOp::WhenReady, triggerMatcher}); +} + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(CompletionPolicyHelpers::defineByName("raw-hmpid-decode", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}); +} + +#include "Framework/runDataProcessing.h" +#include "HMPIDWorkflow/DataDecoderSpec2.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + auto askSTFDist = !cx.options().get<bool>("ignore-dist-stf"); + DataProcessorSpec producer = o2::hmpid::getDecodingSpec2(askSTFDist); + specs.push_back(producer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/raw-to-digits-workflow.cxx b/Detectors/HMPID/workflow/src/raw-to-digits-workflow.cxx new file mode 100644 index 0000000000000..429ac849cc63b --- /dev/null +++ b/Detectors/HMPID/workflow/src/raw-to-digits-workflow.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file raw-to-digits-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "CommonUtils/ConfigurableParam.h" + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(CompletionPolicyHelpers::defineByName("raw-hmpid-read", CompletionPolicy::CompletionOp::Process)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" +#include "../include/HMPIDWorkflow/RawToDigitsSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(ConfigContext const& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + DataProcessorSpec consumer = o2::hmpid::getRawToDigitsSpec(); + specs.push_back(consumer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/raw-to-pedestals-workflow.cxx b/Detectors/HMPID/workflow/src/raw-to-pedestals-workflow.cxx new file mode 100644 index 0000000000000..23b3bc1784e1d --- /dev/null +++ b/Detectors/HMPID/workflow/src/raw-to-pedestals-workflow.cxx @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file raw-to-pedestals-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector<o2::framework::DispatchPolicy>& policies) +{ + using DispatchOp = o2::framework::DispatchPolicy::DispatchOp; + auto readerMatcher = [](auto const& spec) { + return true; + }; + auto triggerMatcher = [](auto const& query) { + return true; + }; + policies.push_back({"raw-hmpid-pedestals", readerMatcher, DispatchOp::WhenReady, triggerMatcher}); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" +#include "HMPIDWorkflow/PedestalsCalculationSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + DataProcessorSpec producer = o2::hmpid::getPedestalsCalculationSpec(); + specs.push_back(producer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/read-raw-file-stream-workflow.cxx b/Detectors/HMPID/workflow/src/read-raw-file-stream-workflow.cxx new file mode 100644 index 0000000000000..1f96e24c5a649 --- /dev/null +++ b/Detectors/HMPID/workflow/src/read-raw-file-stream-workflow.cxx @@ -0,0 +1,79 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file read-raw-file-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "CommonUtils/ConfigurableParam.h" + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector<o2::framework::DispatchPolicy>& policies) +{ + using DispatchOp = o2::framework::DispatchPolicy::DispatchOp; + // we customize all devices to dispatch data immediately + auto readerMatcher = [](auto const& spec) { + // + // std::cout << "customize reader = " << spec.name << std::endl; + // std::cout << "PingReader" << std::endl; + return true; + // return std::regex_match(spec.name.begin(), spec.name.end(), std::regex(".*-reader")); + }; + auto triggerMatcher = [](auto const& query) { + // a bit of a hack but we want this to be configurable from the command line, + // however DispatchPolicy is inserted before all other setup. Triggering depending + // on the global variable set from the command line option. If scheduled messages + // are not triggered they are sent out at the end of the computation + // std::cout << "customize Trigger origin = " << query.origin << " description = " << query.description << std::endl; + // std::cout << "PingTrig" << std::endl; + return true; + // return gDispatchTrigger.origin == query.origin && gDispatchTrigger.description == query.description; + }; + policies.push_back({"pr-f-re", readerMatcher, DispatchOp::WhenReady, triggerMatcher}); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" +#include "HMPIDWorkflow/ReadRawFileSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext& cx) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cx.options().get<std::string>("configKeyValues")); + // The producer to generate some data in the workflow + DataProcessorSpec producer = o2::hmpid::getReadRawFileSpec(); + specs.push_back(producer); + return specs; +} diff --git a/Detectors/ITSMFT/CMakeLists.txt b/Detectors/ITSMFT/CMakeLists.txt index e08e8e47e3f87..e3ac73cf4a482 100644 --- a/Detectors/ITSMFT/CMakeLists.txt +++ b/Detectors/ITSMFT/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(common) add_subdirectory(ITS) diff --git a/Detectors/ITSMFT/ITS/CMakeLists.txt b/Detectors/ITSMFT/ITS/CMakeLists.txt index 2cd1e3c5808f9..760c4a2775d6c 100644 --- a/Detectors/ITSMFT/ITS/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/CMakeLists.txt @@ -1,14 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(calibration) add_subdirectory(simulation) add_subdirectory(reconstruction) add_subdirectory(tracking) diff --git a/Detectors/ITSMFT/ITS/QC/CMakeLists.txt b/Detectors/ITSMFT/ITS/QC/CMakeLists.txt index 3d3bc9f8029d1..e99262f0c88d9 100644 --- a/Detectors/ITSMFT/ITS/QC/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/QC/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(TestDataReaderWorkflow) diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/CMakeLists.txt index 07a32ff33cc64..152e67f8161b6 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSQCDataReaderWorkflow SOURCES src/TestDataReaderWorkflow.cxx diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/RootInclude.h b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/RootInclude.h index 22e4765543435..480ecba821435 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/RootInclude.h +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/RootInclude.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataGetter.h b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataGetter.h index 0e4e88bb1e871..90748d60e5f3b 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataGetter.h +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataGetter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReader.h b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReader.h index bef7a21ae273b..fecd7489f1784 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReader.h +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReaderWorkflow.h b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReaderWorkflow.h index 33a5cee05c57a..7da6bcf421a6b 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReaderWorkflow.h +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/include/ITSQCDataReaderWorkflow/TestDataReaderWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataGetter.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataGetter.cxx index a7270207bb18a..0be9dff8e7abc 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataGetter.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataGetter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx index 1d665b89db39e..546bbb9250f4c 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReaderWorkflow.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReaderWorkflow.cxx index 6942258133414..aa1f0933222fd 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReaderWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReaderWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/its-qc-data-reader.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/its-qc-data-reader.cxx index 15a623d421242..5f78190e31f4c 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/its-qc-data-reader.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/its-qc-data-reader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/README.md b/Detectors/ITSMFT/ITS/README.md index 26107bfa6a4f7..7706f6cb9bf53 100644 --- a/Detectors/ITSMFT/ITS/README.md +++ b/Detectors/ITSMFT/ITS/README.md @@ -46,3 +46,7 @@ o2-its-reco-workflow --configKeyValues "fastMultConfig.cutMultClusLow=50;fastMul ``` will track only ROFs with N signal clusters between 50 and 4000 and will consider seeding vertices with multiplicity below 1000 tracklets. +<!-- doxy +* \subpage refITScalibration +/doxy --> + diff --git a/Detectors/ITSMFT/ITS/base/CMakeLists.txt b/Detectors/ITSMFT/ITS/base/CMakeLists.txt index 6c311d5fc409f..170f0458feddd 100644 --- a/Detectors/ITSMFT/ITS/base/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSBase SOURCES src/GeometryTGeo.cxx src/ContainerFactory.cxx diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/ContainerFactory.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/ContainerFactory.h index 098390616b3d2..baf2f3b94d243 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/ContainerFactory.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/ContainerFactory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h index 02b46cb982050..508fc91eaeda0 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -53,10 +54,14 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static GeometryTGeo* Instance() { // get (create if needed) a unique instance of the object +#ifdef GPUCA_STANDALONE + return nullptr; // TODO: DR: Obviously wrong, but to make it compile for now +#else if (!sInstance) { sInstance = std::unique_ptr<GeometryTGeo>(new GeometryTGeo(true, 0)); } return sInstance.get(); +#endif } // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) @@ -74,7 +79,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo ); /// Default destructor - ~GeometryTGeo() override = default; + ~GeometryTGeo() override; GeometryTGeo(const GeometryTGeo& src) = delete; GeometryTGeo& operator=(const GeometryTGeo& geom) = delete; @@ -98,34 +103,39 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo int getNumberOfChipsPerModule(int lay) const { return mNumberOfChipsPerModule[lay]; } int getNumberOfChipsPerHalfStave(int lay) const { return mNumberOfChipsPerHalfStave[lay]; } int getNumberOfChipsPerStave(int lay) const { return mNumberOfChipsPerStave[lay]; } + int getNumberOfChipsPerHalfBarrel(int lay) const { return mNumberOfChipsPerHalfBarrel[lay]; } int getNumberOfChipsPerLayer(int lay) const { return mNumberOfChipsPerLayer[lay]; } int getNumberOfModules(int lay) const { return mNumberOfModules[lay]; } int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } int getNumberOfStaves(int lay) const { return mNumberOfStaves[lay]; } + int getNumberOfHalfBarrels() const { return mNumberOfHalfBarrels; } int getNumberOfLayers() const { return mNumberOfLayers; } int getChipIndex(int lay, int detInLay) const { return getFirstChipIndex(lay) + detInLay; } /// This routine computes the chip index number from the layer, stave, and chip number in stave /// \param int lay The layer number. Starting from 0. + /// \param int hba The halfbarrel number. Starting from 0 /// \param int sta The stave number. Starting from 0 /// \param int chipInStave The chip number in the stave. Starting from 0 - int getChipIndex(int lay, int sta, int detInSta) const; + int getChipIndex(int lay, int hba, int sta, int detInSta) const; /// This routine computes the chip index number from the layer, stave, substave and chip number /// in substave /// \param int lay The layer number. Starting from 0. + /// \param int hba The halfbarrel number. Starting from 0 /// \param int sta The stave number. Starting from 0 /// \param int substa The substave number. Starting from 0 /// \param int chipInSStave The chip number in the sub stave. Starting from 0 - int getChipIndex(int lay, int sta, int subSta, int detInSubSta) const; + int getChipIndex(int lay, int hba, int sta, int subSta, int detInSubSta) const; /// This routine computes the chip index number from the layer,stave, substave module and /// chip number in module. /// \param int lay The layer number. Starting from 0. + /// \param int hba The halfbarrel number. Starting from 0 /// \param int sta The stave number. Starting from 0 /// \param int substa The substave number. Starting from 0 /// \param int module The module number ... /// \param int chipInSStave The chip number in the module. Starting from 0 - int getChipIndex(int lay, int sta, int subSta, int md, int detInMod) const; + int getChipIndex(int lay, int hba, int sta, int subSta, int md, int detInMod) const; /// This routine computes the layer, stave, substave, module and chip number /// given the chip index number @@ -137,9 +147,23 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo /// \param int chip The detector number. Starting from 0 bool getChipId(int index, int& lay, int& sta, int& ssta, int& mod, int& chip) const; + /// This routine computes the layer, half barrel, stave, substave, + /// module and chip number given the chip index number + /// \param int index The chip index number, starting from zero. + /// \param int lay The layer number. Starting from 0 + /// \param int hba The half barrel number. Starting from 0 + /// \param int sta The stave number. Starting from 0 + /// \param int ssta The halfstave number. Starting from 0 + /// \param int mod The module number. Starting from 0 + /// \param int chip The detector number. Starting from 0 + bool getChipId(int index, int& lay, int& hba, int& sta, int& ssta, int& mod, int& chip) const; + /// Get chip layer, from 0 int getLayer(int index) const; + /// Get chip half barrel, from 0 + int getHalfBarrel(int index) const; + /// Get chip stave, from 0 int getStave(int index) const; @@ -169,15 +193,15 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return o2::base::GeometryManager::getSymbolicName(getDetID(), index); } - const char* getSymbolicName(int lay, int sta, int det) const + const char* getSymbolicName(int lay, int hba, int sta, int det) const { /// return symbolic name of sensor - return getSymbolicName(getChipIndex(lay, sta, det)); + return getSymbolicName(getChipIndex(lay, hba, sta, det)); } /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } - TGeoHMatrix* getMatrix(int lay, int sta, int sens) const { return getMatrix(getChipIndex(lay, sta, sens)); } + TGeoHMatrix* getMatrix(int lay, int hba, int sta, int sens) const { return getMatrix(getChipIndex(lay, hba, sta, sens)); } bool getOriginalMatrix(int index, TGeoHMatrix& m) const { /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' @@ -185,25 +209,25 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return o2::base::GeometryManager::getOriginalMatrix(getDetID(), index, m); } - bool getOriginalMatrix(int lay, int sta, int det, TGeoHMatrix& m) const + bool getOriginalMatrix(int lay, int hba, int sta, int det, TGeoHMatrix& m) const { /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' /// The method is slow, so it should be used with great care (for caching only) - return getOriginalMatrix(getChipIndex(lay, sta, det), m); + return getOriginalMatrix(getChipIndex(lay, hba, sta, det), m); } - const Mat3D& getMatrixT2L(int lay, int sta, int det) const { return getMatrixT2L(getChipIndex(lay, sta, det)); } + const Mat3D& getMatrixT2L(int lay, int hba, int sta, int det) const { return getMatrixT2L(getChipIndex(lay, hba, sta, det)); } const Mat3D& getMatrixSensor(int index) const { return getMatrixL2G(index); } - const Mat3D& getMatrixSensor(int lay, int sta, int det) + const Mat3D& getMatrixSensor(int lay, int hba, int sta, int det) { // get positioning matrix of the sensor, alias to getMatrixL2G - return getMatrixSensor(getChipIndex(lay, sta, det)); + return getMatrixSensor(getChipIndex(lay, hba, sta, det)); } - const Rot2D& getMatrixT2GRot(int lay, int sta, int sens) + const Rot2D& getMatrixT2GRot(int lay, int hba, int sta, int sens) { /// get matrix for tracking to global frame transformation - return getMatrixT2GRot(getChipIndex(lay, sta, sens)); + return getMatrixT2GRot(getChipIndex(lay, hba, sta, sens)); } bool isTrackingFrameCached() const { return !mCacheRefX.empty(); } @@ -232,6 +256,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static const char* getITSVolPattern() { return sVolumeName.c_str(); } static const char* getITSLayerPattern() { return sLayerName.c_str(); } + static const char* getITSHalfBarrelPattern() { return sHalfBarrelName.c_str(); } static const char* getITSWrapVolPattern() { return sWrapperVolumeName.c_str(); } static const char* getITSStavePattern() { return sStaveName.c_str(); } static const char* getITSHalfStavePattern() { return sHalfStaveName.c_str(); } @@ -240,6 +265,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static const char* getITSSensorPattern() { return sSensorName.c_str(); } static void setITSVolPattern(const char* nm) { sVolumeName = nm; } static void setITSLayerPattern(const char* nm) { sLayerName = nm; } + static void setITSHalfBarrelPattern(const char* nm) { sHalfBarrelName = nm; } static void setITSWrapVolPattern(const char* nm) { sWrapperVolumeName = nm; } static void setITSStavePattern(const char* nm) { sStaveName = nm; } static void setITSHalfStavePattern(const char* nm) { sHalfStaveName = nm; } @@ -251,17 +277,20 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo /// sym name of the layer static const char* composeSymNameLayer(int lr); - /// Sym name of the stave at given layer - static const char* composeSymNameStave(int lr, int sta); + /// Sym name of the half barrel at given layer + static const char* composeSymNameHalfBarrel(int lr, int hba); /// Sym name of the stave at given layer - static const char* composeSymNameHalfStave(int lr, int sta, int ssta); + static const char* composeSymNameStave(int lr, int hba, int sta); + + /// Sym name of the stave at given layer/halfbarrel + static const char* composeSymNameHalfStave(int lr, int hba, int sta, int ssta); - /// Sym name of the substave at given layer/stave - static const char* composeSymNameModule(int lr, int sta, int ssta, int mod); + /// Sym name of the substave at given layer/halfbarrel/stave + static const char* composeSymNameModule(int lr, int hba, int sta, int ssta, int mod); - /// Sym name of the chip in the given layer/stave/substave/module - static const char* composeSymNameChip(int lr, int sta, int ssta, int mod, int chip); + /// Sym name of the chip in the given layer/halfbarrel/stave/substave/module + static const char* composeSymNameChip(int lr, int hba, int sta, int ssta, int mod, int chip); protected: /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) @@ -285,6 +314,10 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo /// \param lay: layer number from 0 int extractNumberOfChipsPerModule(int lay, int& nrow) const; + /// Determines the number of halfbarrels in the layer + /// \param lay: layer number, starting from 0 + int extractNumberOfHalfBarrels() const; + /// Determines the number of layers in the Geometry /// \param lay: layer number, starting from 0 int extractNumberOfStaves(int lay) const; @@ -320,23 +353,26 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo protected: static constexpr int MAXLAYERS = 15; ///< max number of active layers - Int_t mNumberOfLayers; ///< number of layers - std::vector<int> mNumberOfStaves; ///< number of staves/layer(layer) - std::vector<int> mNumberOfHalfStaves; ///< the number of substaves/stave(layer) - std::vector<int> mNumberOfModules; ///< number of modules/substave(layer) - std::vector<int> mNumberOfChipsPerModule; ///< number of chips per module (group of chips on substaves) - std::vector<int> mNumberOfChipRowsPerModule; ///< number of chips rows per module (relevant for OB modules) - std::vector<int> mNumberOfChipsPerHalfStave; ///< number of chips per substave - std::vector<int> mNumberOfChipsPerStave; ///< number of chips per stave - std::vector<int> mNumberOfChipsPerLayer; ///< number of chips per stave - std::vector<int> mLastChipIndex; ///< max ID of the detctor in the layer - std::array<char, MAXLAYERS> mLayerToWrapper; ///< Layer to wrapper correspondence + Int_t mNumberOfLayers; ///< number of layers + Int_t mNumberOfHalfBarrels; ///< number of halfbarrels + std::vector<int> mNumberOfStaves; ///< number of staves/layer(layer) + std::vector<int> mNumberOfHalfStaves; ///< the number of substaves/stave(layer) + std::vector<int> mNumberOfModules; ///< number of modules/substave(layer) + std::vector<int> mNumberOfChipsPerModule; ///< number of chips per module (group of chips on substaves) + std::vector<int> mNumberOfChipRowsPerModule; ///< number of chips rows per module (relevant for OB modules) + std::vector<int> mNumberOfChipsPerHalfStave; ///< number of chips per substave + std::vector<int> mNumberOfChipsPerStave; ///< number of chips per stave + std::vector<int> mNumberOfChipsPerHalfBarrel; ///< number of chips per halfbarrel + std::vector<int> mNumberOfChipsPerLayer; ///< number of chips per stave + std::vector<int> mLastChipIndex; ///< max ID of the detctor in the layer + std::array<char, MAXLAYERS> mLayerToWrapper; ///< Layer to wrapper correspondence std::vector<float> mCacheRefX; ///< sensors tracking plane reference X std::vector<float> mCacheRefAlpha; ///< sensors tracking plane reference alpha static std::string sVolumeName; ///< Mother volume name static std::string sLayerName; ///< Layer name + static std::string sHalfBarrelName; ///< HalfBarrel name static std::string sStaveName; ///< Stave name static std::string sHalfStaveName; ///< HalfStave name static std::string sModuleName; ///< Module name @@ -345,7 +381,9 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static std::string sWrapperVolumeName; ///< Wrapper volume name private: +#ifndef GPUCA_STANDALONE static std::unique_ptr<o2::its::GeometryTGeo> sInstance; ///< singletone instance +#endif ClassDefOverride(GeometryTGeo, 1); // ITS geometry based on TGeo }; diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/MisalignmentParameter.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/MisalignmentParameter.h index e8b118a3c6a60..0e663f23b2514 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/MisalignmentParameter.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/MisalignmentParameter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/base/src/ContainerFactory.cxx b/Detectors/ITSMFT/ITS/base/src/ContainerFactory.cxx index 0bb3371e6716c..43e67ff9fabac 100644 --- a/Detectors/ITSMFT/ITS/base/src/ContainerFactory.cxx +++ b/Detectors/ITSMFT/ITS/base/src/ContainerFactory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx index eeb3917886377..54490df3259a1 100644 --- a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx +++ b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,9 +50,11 @@ using Segmentation = o2::itsmft::SegmentationAlpide; ClassImp(o2::its::GeometryTGeo); std::unique_ptr<o2::its::GeometryTGeo> GeometryTGeo::sInstance; +o2::its::GeometryTGeo::~GeometryTGeo() = default; std::string GeometryTGeo::sVolumeName = "ITSV"; ///< Mother volume name std::string GeometryTGeo::sLayerName = "ITSULayer"; ///< Layer name +std::string GeometryTGeo::sHalfBarrelName = "ITSUHalfBarrel"; ///< HalfBarrel name std::string GeometryTGeo::sStaveName = "ITSUStave"; ///< Stave name std::string GeometryTGeo::sHalfStaveName = "ITSUHalfStave"; ///< HalfStave name std::string GeometryTGeo::sModuleName = "ITSUModule"; ///< Module name @@ -88,15 +91,15 @@ void GeometryTGeo::adopt(GeometryTGeo* raw) } //__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int chipInStave) const +int GeometryTGeo::getChipIndex(int lay, int hba, int sta, int chipInStave) const { - return getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInStave; + return getFirstChipIndex(lay) + mNumberOfChipsPerHalfBarrel[lay] * hba + mNumberOfChipsPerStave[lay] * sta + chipInStave; } //__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int chipInSStave) const +int GeometryTGeo::getChipIndex(int lay, int hba, int sta, int substa, int chipInSStave) const { - int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInSStave; + int n = getFirstChipIndex(lay) + mNumberOfChipsPerHalfBarrel[lay] * hba + mNumberOfChipsPerStave[lay] * sta + chipInSStave; if (mNumberOfHalfStaves[lay] && substa > 0) { n += mNumberOfChipsPerHalfStave[lay] * substa; } @@ -104,16 +107,20 @@ int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int chipInSStave) c } //__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int md, int chipInMod) const +int GeometryTGeo::getChipIndex(int lay, int hba, int sta, int substa, int md, int chipInMod) const { - int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInMod; - if (mNumberOfHalfStaves[lay] && substa > 0) { - n += mNumberOfChipsPerHalfStave[lay] * substa; - } - if (mNumberOfModules[lay] && md > 0) { - n += mNumberOfChipsPerModule[lay] * md; + if (mNumberOfHalfStaves[lay] == 0) { + return getChipIndex(lay, substa, md, chipInMod); + } else { + int n = getFirstChipIndex(lay) + mNumberOfChipsPerHalfBarrel[lay] * hba + mNumberOfChipsPerStave[lay] * sta + chipInMod; + if (mNumberOfHalfStaves[lay] && substa > 0) { + n += mNumberOfChipsPerHalfStave[lay] * substa; + } + if (mNumberOfModules[lay] && md > 0) { + n += mNumberOfChipsPerModule[lay] * md; + } + return n; } - return n; } //__________________________________________________________________________ @@ -134,6 +141,17 @@ int GeometryTGeo::getLayer(int index) const return lay; } +//__________________________________________________________________________ +int GeometryTGeo::getHalfBarrel(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index / mNumberOfChipsPerHalfBarrel[lay]; +} + //__________________________________________________________________________ int GeometryTGeo::getStave(int index) const { @@ -237,6 +255,23 @@ bool GeometryTGeo::getChipId(int index, int& lay, int& sta, int& hsta, int& mod, return kTRUE; } +//__________________________________________________________________________ +bool GeometryTGeo::getChipId(int index, int& lay, int& hba, int& sta, int& hsta, int& mod, int& chip) const +{ + lay = getLayer(index); + index -= getFirstChipIndex(lay); + hba = mNumberOfHalfBarrels > 0 ? index / mNumberOfChipsPerHalfBarrel[lay] : -1; + index %= mNumberOfChipsPerHalfBarrel[lay]; + sta = index / mNumberOfChipsPerStave[lay]; + index %= mNumberOfChipsPerStave[lay]; + hsta = mNumberOfHalfStaves[lay] > 0 ? index / mNumberOfChipsPerHalfStave[lay] : -1; + index %= mNumberOfChipsPerHalfStave[lay]; + mod = mNumberOfModules[lay] > 0 ? index / mNumberOfChipsPerModule[lay] : -1; + chip = index % mNumberOfChipsPerModule[lay]; + + return kTRUE; +} + //__________________________________________________________________________ const char* GeometryTGeo::composeSymNameLayer(int lr) { @@ -244,29 +279,36 @@ const char* GeometryTGeo::composeSymNameLayer(int lr) } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameStave(int lr, int stave) +const char* GeometryTGeo::composeSymNameHalfBarrel(int lr, int hbarrel) +{ + return hbarrel >= 0 ? Form("%s/%s%d", composeSymNameLayer(lr), getITSHalfBarrelPattern(), hbarrel) + : composeSymNameLayer(lr); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameStave(int lr, int hbarrel, int stave) { - return Form("%s/%s%d", composeSymNameLayer(lr), getITSStavePattern(), stave); + return Form("%s/%s%d", composeSymNameHalfBarrel(lr, hbarrel), getITSStavePattern(), stave); } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameHalfStave(int lr, int stave, int substave) +const char* GeometryTGeo::composeSymNameHalfStave(int lr, int hba, int stave, int substave) { - return substave >= 0 ? Form("%s/%s%d", composeSymNameStave(lr, stave), getITSHalfStavePattern(), substave) - : composeSymNameStave(lr, stave); + return substave >= 0 ? Form("%s/%s%d", composeSymNameStave(lr, hba, stave), getITSHalfStavePattern(), substave) + : composeSymNameStave(lr, hba, stave); } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameModule(int lr, int stave, int substave, int mod) +const char* GeometryTGeo::composeSymNameModule(int lr, int hba, int stave, int substave, int mod) { - return mod >= 0 ? Form("%s/%s%d", composeSymNameHalfStave(lr, stave, substave), getITSModulePattern(), mod) - : composeSymNameHalfStave(lr, stave, substave); + return mod >= 0 ? Form("%s/%s%d", composeSymNameHalfStave(lr, hba, stave, substave), getITSModulePattern(), mod) + : composeSymNameHalfStave(lr, hba, stave, substave); } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameChip(int lr, int sta, int substave, int mod, int chip) +const char* GeometryTGeo::composeSymNameChip(int lr, int hba, int sta, int substave, int mod, int chip) { - return Form("%s/%s%d", composeSymNameModule(lr, sta, substave, mod), getITSChipPattern(), chip); + return Form("%s/%s%d", composeSymNameModule(lr, hba, sta, substave, mod), getITSChipPattern(), chip); } //__________________________________________________________________________ @@ -279,8 +321,8 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const // // Therefore we need to add a shift - int lay, stav, sstav, mod, chipInMod; - getChipId(index, lay, stav, sstav, mod, chipInMod); + int lay, hba, stav, sstav, mod, chipInMod; + getChipId(index, lay, hba, stav, sstav, mod, chipInMod); int wrID = mLayerToWrapper[lay]; @@ -291,7 +333,13 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const } path += - Form("%s%d_1/%s%d_%d/", GeometryTGeo::getITSLayerPattern(), lay, GeometryTGeo::getITSStavePattern(), lay, stav); + Form("%s%d_1/", GeometryTGeo::getITSLayerPattern(), lay); + + if (mNumberOfHalfBarrels > 0) { + path += Form("%s%d_%d/", GeometryTGeo::getITSHalfBarrelPattern(), lay, hba); + } + path += + Form("%s%d_%d/", GeometryTGeo::getITSStavePattern(), lay, stav); if (mNumberOfHalfStaves[lay] > 0) { path += Form("%s%d_%d/", GeometryTGeo::getITSHalfStavePattern(), lay, sstav); @@ -351,10 +399,12 @@ void GeometryTGeo::Build(int loadTrans) mNumberOfChipRowsPerModule.resize(mNumberOfLayers); mNumberOfChipsPerHalfStave.resize(mNumberOfLayers); mNumberOfChipsPerStave.resize(mNumberOfLayers); + mNumberOfChipsPerHalfBarrel.resize(mNumberOfLayers); mNumberOfChipsPerLayer.resize(mNumberOfLayers); mLastChipIndex.resize(mNumberOfLayers); int numberOfChips = 0; + mNumberOfHalfBarrels = extractNumberOfHalfBarrels(); for (int i = 0; i < mNumberOfLayers; i++) { mNumberOfStaves[i] = extractNumberOfStaves(i); mNumberOfHalfStaves[i] = extractNumberOfHalfStaves(i); @@ -363,6 +413,7 @@ void GeometryTGeo::Build(int loadTrans) mNumberOfChipsPerHalfStave[i] = mNumberOfChipsPerModule[i] * Max(1, mNumberOfModules[i]); mNumberOfChipsPerStave[i] = mNumberOfChipsPerHalfStave[i] * Max(1, mNumberOfHalfStaves[i]); mNumberOfChipsPerLayer[i] = mNumberOfChipsPerStave[i] * mNumberOfStaves[i]; + mNumberOfChipsPerHalfBarrel[i] = mNumberOfChipsPerLayer[i] / Max(1, mNumberOfHalfBarrels); numberOfChips += mNumberOfChipsPerLayer[i]; mLastChipIndex[i] = numberOfChips - 1; } @@ -500,29 +551,42 @@ int GeometryTGeo::extractNumberOfLayers() return numberOfLayers; } +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfHalfBarrels() const +{ + // We take in account that we always have 2 and only 2 half barrels + int numberOfHalfBarrels = 2; + + return numberOfHalfBarrels; +} + //__________________________________________________________________________ int GeometryTGeo::extractNumberOfStaves(int lay) const { int numberOfStaves = 0; - char laynam[30]; - snprintf(laynam, 30, "%s%d", getITSLayerPattern(), lay); - TGeoVolume* volLr = gGeoManager->GetVolume(laynam); - if (!volLr) { - LOG(FATAL) << "can't find " << laynam << " volume"; + char hbarnam[30]; + if (mNumberOfHalfBarrels == 0) { + snprintf(hbarnam, 30, "%s%d", getITSLayerPattern(), lay); + } else { + snprintf(hbarnam, 30, "%s%d", getITSHalfBarrelPattern(), lay); + } + TGeoVolume* volHb = gGeoManager->GetVolume(hbarnam); + if (!volHb) { + LOG(FATAL) << "can't find " << hbarnam << " volume"; return -1; } - // Loop on all layer nodes, count Stave volumes by checking names - int nNodes = volLr->GetNodes()->GetEntries(); + // Loop on all half barrel nodes, count Stave volumes by checking names + int nNodes = volHb->GetNodes()->GetEntries(); for (int j = 0; j < nNodes; j++) { // LOG(INFO) << "L" << lay << " " << j << " of " << nNodes << " " - // << volLr->GetNodes()->At(j)->GetName() << " " + // << volHb->GetNodes()->At(j)->GetName() << " " // << getITSStavePattern() << " -> " << numberOfStaves; - if (strstr(volLr->GetNodes()->At(j)->GetName(), getITSStavePattern())) { + if (strstr(volHb->GetNodes()->At(j)->GetName(), getITSStavePattern())) { numberOfStaves++; } } - return numberOfStaves; + return mNumberOfHalfBarrels > 0 ? (numberOfStaves * mNumberOfHalfBarrels) : numberOfStaves; } //__________________________________________________________________________ diff --git a/Detectors/ITSMFT/ITS/base/src/ITSBaseLinkDef.h b/Detectors/ITSMFT/ITS/base/src/ITSBaseLinkDef.h index c767dfe7a019b..8ed030f65bac2 100644 --- a/Detectors/ITSMFT/ITS/base/src/ITSBaseLinkDef.h +++ b/Detectors/ITSMFT/ITS/base/src/ITSBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/base/src/MisalignmentParameter.cxx b/Detectors/ITSMFT/ITS/base/src/MisalignmentParameter.cxx index c775961a56d8f..98e8518e4ee61 100644 --- a/Detectors/ITSMFT/ITS/base/src/MisalignmentParameter.cxx +++ b/Detectors/ITSMFT/ITS/base/src/MisalignmentParameter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/calibration/CMakeLists.txt b/Detectors/ITSMFT/ITS/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..9453b9e365e5a --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(macros) + +o2_add_library(ITSCalibration + SOURCES src/NoiseCalibrator.cxx + SOURCES src/NoiseSlotCalibrator.cxx + SOURCES src/NoiseCalibratorSpec.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS O2::ITSBase + O2::DetectorsCalibration + O2::CCDB) + +o2_target_root_dictionary(ITSCalibration + HEADERS include/ITSCalibration/NoiseCalibrator.h + HEADERS include/ITSCalibration/NoiseSlotCalibrator.h + LINKDEF src/ITSCalibrationLinkDef.h) + +o2_add_executable(its-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/its-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::ITSCalibration) + diff --git a/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibrator.h b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibrator.h new file mode 100644 index 0000000000000..7e27e9244461c --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibrator.h @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibrator.h + +#ifndef O2_ITS_NOISECALIBRATOR +#define O2_ITS_NOISECALIBRATOR + +#include <string> + +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "gsl/span" + +namespace o2 +{ + +namespace itsmft +{ +class CompClusterExt; +class ROFRecord; +} // namespace itsmft + +namespace its +{ + +class NoiseCalibrator +{ + public: + NoiseCalibrator() = default; + NoiseCalibrator(bool one, float prob) + { + m1pix = one; + mProbabilityThreshold = prob; + } + ~NoiseCalibrator() = default; + + void setThreshold(unsigned int t) { mThreshold = t; } + + bool processTimeFrame(gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + void finalize(); + + void loadDictionary(std::string fname) + { + mDict.readBinaryFile(fname); + } + const o2::itsmft::NoiseMap& getNoiseMap() const { return mNoiseMap; } + + private: + o2::itsmft::TopologyDictionary mDict; + o2::itsmft::NoiseMap mNoiseMap{24120}; + float mProbabilityThreshold = 3e-6f; + unsigned int mThreshold = 100; + unsigned int mNumberOfStrobes = 0; + bool m1pix = true; +}; + +} // namespace its +} // namespace o2 + +#endif /* O2_ITS_NOISECALIBRATOR */ diff --git a/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibratorSpec.h b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibratorSpec.h new file mode 100644 index 0000000000000..e793f74095c34 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibratorSpec.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibratorSpec.h + +#ifndef O2_ITS_NOISECALIBRATORSPEC +#define O2_ITS_NOISECALIBRATORSPEC + +#include <string> + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +//#define TIME_SLOT_CALIBRATION +#ifdef TIME_SLOT_CALIBRATION +#include "ITSCalibration/NoiseSlotCalibrator.h" +using CALIBRATOR = o2::its::NoiseSlotCalibrator; +#else +#include "ITSCalibration/NoiseCalibrator.h" +using CALIBRATOR = o2::its::NoiseCalibrator; +#endif + +using namespace o2::framework; + +namespace o2 +{ + +namespace its +{ + +class NoiseCalibratorSpec : public Task +{ + public: + NoiseCalibratorSpec() = default; + ~NoiseCalibratorSpec() override = default; + + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + + private: + void sendOutput(DataAllocator& output); + std::unique_ptr<CALIBRATOR> mCalibrator = nullptr; +}; + +/// create a processor spec +/// run ITS noise calibration +DataProcessorSpec getNoiseCalibratorSpec(); + +} // namespace its +} // namespace o2 + +#endif /* O2_ITS_NOISECALIBRATORSPEC */ diff --git a/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseSlotCalibrator.h b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseSlotCalibrator.h new file mode 100644 index 0000000000000..d22c9d3b6490f --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseSlotCalibrator.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseSlotCalibrator.h + +#ifndef O2_ITS_NOISESLOTCALIBRATOR +#define O2_ITS_NOISESLOTCALIBRATOR + +#include <string> + +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" + +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "gsl/span" + +namespace o2 +{ + +namespace itsmft +{ +class ROFRecord; +} // namespace itsmft + +namespace its +{ + +class NoiseSlotCalibrator : public o2::calibration::TimeSlotCalibration<o2::itsmft::CompClusterExt, o2::itsmft::NoiseMap> +{ + using Slot = calibration::TimeSlot<o2::itsmft::NoiseMap>; + + public: + NoiseSlotCalibrator() { setUpdateAtTheEndOfRunOnly(); } + NoiseSlotCalibrator(bool one, float prob) + { + m1pix = one; + mProbabilityThreshold = prob; + setUpdateAtTheEndOfRunOnly(); + } + ~NoiseSlotCalibrator() final = default; + + void setThreshold(unsigned int t) { mThreshold = t; } + + bool processTimeFrame(gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + void finalize() + { + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + auto& slot = getSlots().back(); + slot.getContainer()->applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); + } + + void loadDictionary(std::string fname) + { + mDict.readBinaryFile(fname); + } + const o2::itsmft::NoiseMap& getNoiseMap(long& start, long& end) + { + const auto& slot = getSlots().back(); + start = slot.getTFStart(); + end = slot.getTFEnd(); + return *(slot.getContainer()); + } + + // Functions overloaded from the calibration framework + bool process(calibration::TFType tf, const gsl::span<const o2::itsmft::CompClusterExt> data) final; + + // Functions required by the calibration framework + void initOutput() final {} + Slot& emplaceNewSlot(bool, calibration::TFType, calibration::TFType) final; + void finalizeSlot(Slot& slot) final; + bool hasEnoughData(const Slot& slot) const final; + + private: + o2::itsmft::TopologyDictionary mDict; + float mProbabilityThreshold = 3e-6f; + unsigned int mThreshold = 100; + unsigned int mNumberOfStrobes = 0; + bool m1pix = true; +}; + +} // namespace its +} // namespace o2 + +#endif /* O2_ITS_NOISESLOTCALIBRATOR */ diff --git a/Detectors/ITSMFT/ITS/calibration/macros/CMakeLists.txt b/Detectors/ITSMFT/ITS/calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..1b9f5d87893cb --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/macros/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro(MakeNoiseMapFromDigits.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT + O2::ITSMFTBase + O2::ITSBase) + +o2_add_test_root_macro(MakeNoiseMapFromClusters.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT + O2::ITSMFTBase + O2::ITSBase) + diff --git a/Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromClusters.C b/Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromClusters.C new file mode 100644 index 0000000000000..949e23df7775b --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromClusters.C @@ -0,0 +1,70 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <iostream> +#include <vector> +#include <string> +#include <gsl/span> + +#include <TFile.h> +#include <TTree.h> + +#include "ITSCalibration/NoiseCalibrator.h" + +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +#endif + +void MakeNoiseMapFromClusters(std::string input = "o2clus_its.root", bool only1pix = false, float probT = 3e-6, std::string output = "noise.root", std::string dict = "ITSdictionary.bin") +{ + TFile out(output.data(), "new"); + if (!out.IsOpen()) { + std::cerr << "The output file " << output << " already exists !"; + return; + } + + TFile in(input.data()); + if (!in.IsOpen()) { + std::cerr << "Can not open the input file " << input << '\n'; + return; + } + auto clusTree = (TTree*)in.Get("o2sim"); + if (!clusTree) { + std::cerr << "Can not get cluster tree\n"; + return; + } + + // Clusters + std::vector<o2::itsmft::CompClusterExt>* clusters = nullptr; + clusTree->SetBranchAddress("ITSClusterComp", &clusters); + + // Pixel patterns + std::vector<unsigned char>* patternsPtr = nullptr; + auto pattBranch = clusTree->GetBranch("ITSClusterPatt"); + if (pattBranch) { + pattBranch->SetAddress(&patternsPtr); + } + + //RO frames + std::vector<o2::itsmft::ROFRecord>* rofVec = nullptr; + clusTree->SetBranchAddress("ITSClustersROF", &rofVec); + + o2::its::NoiseCalibrator calib(only1pix, probT); + try { + calib.loadDictionary(dict.data()); + } catch (std::runtime_error) { + LOG(ERROR) << "Cannot load the dictionary file: " << dict << " !"; + LOG(INFO) << "Assuming that cluster shapes are not encoded..."; + } + + auto nevents = clusTree->GetEntries(); + for (int n = 0; n < nevents; n++) { + clusTree->GetEntry(n); + calib.processTimeFrame(*clusters, *patternsPtr, *rofVec); + } + calib.finalize(); + + const auto& map = calib.getNoiseMap(); + out.WriteObject(&map, "ccdb_object"); + out.Close(); +} diff --git a/Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromDigits.C b/Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromDigits.C similarity index 95% rename from Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromDigits.C rename to Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromDigits.C index 3ee33831ebc39..636a6dba7330f 100644 --- a/Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromDigits.C +++ b/Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromDigits.C @@ -29,7 +29,7 @@ void MakeNoiseMapFromDigits(std::string digifile = "itsdigits.root", int hitCut TFile* fout = new TFile("ITSnoise.root", "new"); fout->cd(); - fout->WriteObject(&noiseMap, "Noise"); + fout->WriteObject(&noiseMap, "ccdb_object"); fout->Close(); int nPixelCalib = noiseMap.dumpAboveThreshold(hitCut); diff --git a/Detectors/ITSMFT/ITS/calibration/src/ITSCalibrationLinkDef.h b/Detectors/ITSMFT/ITS/calibration/src/ITSCalibrationLinkDef.h new file mode 100644 index 0000000000000..0cdcb51916a33 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/src/ITSCalibrationLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::calibration::TimeSlot < o2::itsmft::CompClusterExt > +; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::itsmft::CompClusterExt, o2::itsmft::NoiseMap > +; +#pragma link C++ class o2::its::NoiseCalibrator + ; + +#endif diff --git a/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibrator.cxx b/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibrator.cxx new file mode 100644 index 0000000000000..849e79851f201 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibrator.cxx @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibrator.cxx + +#include "ITSCalibration/NoiseCalibrator.h" + +#include "FairLogger.h" +#include "TFile.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +namespace o2 +{ +namespace its +{ +bool NoiseCalibrator::processTimeFrame(gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + static int nTF = 0; + LOG(INFO) << "Processing TF# " << nTF++; + + auto pattIt = patterns.begin(); + for (const auto& rof : rofs) { + auto clustersInFrame = rof.getROFData(clusters); + for (const auto& c : clustersInFrame) { + auto pattID = c.getPatternID(); + o2::itsmft::ClusterPattern patt; + if (mDict.getSize() == 0) { + if (pattID == o2::itsmft::CompCluster::InvalidPatternID) { + o2::itsmft::ClusterPattern tmp(pattIt); + patt = tmp; + } else { + LOG(FATAL) << "Clusters contain pattern IDs, but no dictionary is provided..."; + } + } else if ((pattID == o2::itsmft::CompCluster::InvalidPatternID) || mDict.isGroup(pattID)) { + o2::itsmft::ClusterPattern tmp(pattIt); + patt = tmp; + } else { + patt = mDict.getPattern(pattID); + } + auto id = c.getSensorID(); + auto row = c.getRow(); + auto col = c.getCol(); + auto colSpan = patt.getColumnSpan(); + auto rowSpan = patt.getRowSpan(); + + // Fast 1-pixel calibration + if ((rowSpan == 1) && (colSpan == 1)) { + mNoiseMap.increaseNoiseCount(id, row, col); + continue; + } + if (m1pix) { + continue; + } + + // All-pixel calibration + auto nBits = rowSpan * colSpan; + int ic = 0, ir = 0; + for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { + unsigned char tempChar = patt.getByte(i); + int s = 128; // 0b10000000 + while (s > 0) { + if ((tempChar & s) != 0) { + mNoiseMap.increaseNoiseCount(id, row + ir, col + ic); + } + ic++; + s >>= 1; + if ((ir + 1) * ic == nBits) { + break; + } + if (ic == colSpan) { + ic = 0; + ir++; + } + } + if ((ir + 1) * ic == nBits) { + break; + } + } + } + } + mNumberOfStrobes += rofs.size(); + return (mNumberOfStrobes * mProbabilityThreshold >= mThreshold) ? true : false; +} + +void NoiseCalibrator::finalize() +{ + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + mNoiseMap.applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibratorSpec.cxx new file mode 100644 index 0000000000000..0ff7b35ac2171 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/src/NoiseCalibratorSpec.cxx @@ -0,0 +1,119 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibratorSpec.cxx + +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include "ITSCalibration/NoiseCalibratorSpec.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +#include "FairLogger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its +{ + +void NoiseCalibratorSpec::init(InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName( + o2::detectors::DetID::ITS, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { + mCalibrator->loadDictionary(dictFile); + LOG(INFO) << "ITS NoiseCalibrator is running with a provided dictionary: " << dictFile; + } else { + LOG(INFO) << "Dictionary " << dictFile + << " is absent, ITS NoiseCalibrator expects cluster patterns for all clusters"; + } + + auto onepix = ic.options().get<bool>("1pix-only"); + LOG(INFO) << "Fast 1=pixel calibration: " << onepix; + auto probT = ic.options().get<float>("prob-threshold"); + LOG(INFO) << "Setting the probability threshold to " << probT; + + mCalibrator = std::make_unique<CALIBRATOR>(onepix, probT); +} + +void NoiseCalibratorSpec::run(ProcessingContext& pc) +{ + const auto compClusters = pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("compClusters"); + gsl::span<const unsigned char> patterns = pc.inputs().get<gsl::span<unsigned char>>("patterns"); + const auto rofs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROframes"); + + if (mCalibrator->processTimeFrame(compClusters, patterns, rofs)) { + LOG(INFO) << "Minimum number of noise counts has been reached !"; + sendOutput(pc.outputs()); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + } +} + +void NoiseCalibratorSpec::sendOutput(DataAllocator& output) +{ + mCalibrator->finalize(); + + long tstart = 0, tend = 9999999; +#ifdef TIME_SLOT_CALIBRATION + const auto& payload = mCalibrator->getNoiseMap(tstart, tend); +#else + const auto& payload = mCalibrator->getNoiseMap(); +#endif + std::map<std::string, std::string> md; + o2::ccdb::CcdbObjectInfo info("ITS/Noise", "NoiseMap", "noise.root", md, tstart, tend); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + using clbUtils = o2::calibration::Utils; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, 0}, info); +} + +void NoiseCalibratorSpec::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + sendOutput(ec.outputs()); +} + +DataProcessorSpec getNoiseCalibratorSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); + inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe); + inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "ITS_NOISE"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "ITS_NOISE"}); + + return DataProcessorSpec{ + "its-noise-calibrator", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<NoiseCalibratorSpec>()}, + Options{ + {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"1pix-only", VariantType::Bool, false, {"Fast 1-pixel calibration only"}}, + {"prob-threshold", VariantType::Float, 3.e-6f, {"Probability threshold for noisy pixels"}}}}; +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/calibration/src/NoiseSlotCalibrator.cxx b/Detectors/ITSMFT/ITS/calibration/src/NoiseSlotCalibrator.cxx new file mode 100644 index 0000000000000..0f3038d255a6d --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/src/NoiseSlotCalibrator.cxx @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseSlotCalibrator.cxx + +#include "ITSCalibration/NoiseSlotCalibrator.h" + +#include "FairLogger.h" +#include "TFile.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +namespace o2 +{ +using Slot = calibration::TimeSlot<o2::itsmft::NoiseMap>; + +namespace its +{ +bool NoiseSlotCalibrator::processTimeFrame(gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + calibration::TFType nTF = rofs[0].getBCData().orbit / 256; + LOG(INFO) << "Processing TF# " << nTF; + + auto& slotTF = getSlotForTF(nTF); + auto& noiseMap = *(slotTF.getContainer()); + + auto pattIt = patterns.begin(); + for (const auto& rof : rofs) { + auto clustersInFrame = rof.getROFData(clusters); + for (const auto& c : clustersInFrame) { + auto pattID = c.getPatternID(); + o2::itsmft::ClusterPattern patt; + if (mDict.getSize() == 0) { + if (pattID == o2::itsmft::CompCluster::InvalidPatternID) { + o2::itsmft::ClusterPattern tmp(pattIt); + patt = tmp; + } else { + LOG(FATAL) << "Clusters contain pattern IDs, but no dictionary is provided..."; + } + } else if ((pattID == o2::itsmft::CompCluster::InvalidPatternID) || mDict.isGroup(pattID)) { + o2::itsmft::ClusterPattern tmp(pattIt); + patt = tmp; + } else { + patt = mDict.getPattern(pattID); + } + auto id = c.getSensorID(); + auto row = c.getRow(); + auto col = c.getCol(); + auto colSpan = patt.getColumnSpan(); + auto rowSpan = patt.getRowSpan(); + + // Fast 1-pixel calibration + if ((rowSpan == 1) && (colSpan == 1)) { + noiseMap.increaseNoiseCount(id, row, col); + continue; + } + if (m1pix) { + continue; + } + + // All-pixel calibration + auto nBits = rowSpan * colSpan; + int ic = 0, ir = 0; + for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { + unsigned char tempChar = patt.getByte(i); + int s = 128; // 0b10000000 + while (s > 0) { + if ((tempChar & s) != 0) { + noiseMap.increaseNoiseCount(id, row + ir, col + ic); + } + ic++; + s >>= 1; + if ((ir + 1) * ic == nBits) { + break; + } + if (ic == colSpan) { + ic = 0; + ir++; + } + } + if ((ir + 1) * ic == nBits) { + break; + } + } + } + } + + mNumberOfStrobes += rofs.size(); + return hasEnoughData(slotTF); +} + +// Functions overloaded from the calibration framework +bool NoiseSlotCalibrator::process(calibration::TFType tf, const gsl::span<const o2::itsmft::CompClusterExt> data) +{ + LOG(WARNING) << "Only 1-pix noise calibraton is possible !"; + return calibration::TimeSlotCalibration<o2::itsmft::CompClusterExt, o2::itsmft::NoiseMap>::process(tf, data); +} + +// Functions required by the calibration framework + +Slot& NoiseSlotCalibrator::emplaceNewSlot(bool front, calibration::TFType tstart, calibration::TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<o2::itsmft::NoiseMap>(24120)); + return slot; +} + +bool NoiseSlotCalibrator::hasEnoughData(const Slot&) const +{ + return (mNumberOfStrobes * mProbabilityThreshold >= mThreshold) ? true : false; +} + +void NoiseSlotCalibrator::finalizeSlot(Slot& slot) +{ + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + o2::itsmft::NoiseMap* map = slot.getContainer(); + map->applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/calibration/testWorkflow/README.md b/Detectors/ITSMFT/ITS/calibration/testWorkflow/README.md new file mode 100644 index 0000000000000..875e9094c6ef9 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/testWorkflow/README.md @@ -0,0 +1,23 @@ +<!-- doxy +\page refITScalibration testWorkflow +/doxy --> + +# ITS calibration workflows + +## Generation of fixed-pattern noise maps out of pass1 clusters: + +This will read clusters from a ROOT file and write a noise map to a local CCDB running on port 8080: + +```shell +o2-its-cluster-reader-workflow -b | \ +o2-calibration-its-calib-workflow -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:8080" -b +``` +The same as above, but starting from raw data, could be done like this: + +```shell +o2-raw-file-reader-workflow --detect-tf0 --input-conf run.cfg --delay 0.1 | \ +o2-itsmft-stf-decoder-workflow -b --nthreads 4 --shm-segment-size 16000000000 | \ +o2-calibration-its-calib-workflow -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:8080" -b +``` diff --git a/Detectors/ITSMFT/ITS/calibration/testWorkflow/its-calib-workflow.cxx b/Detectors/ITSMFT/ITS/calibration/testWorkflow/its-calib-workflow.cxx new file mode 100644 index 0000000000000..c222b6e196c74 --- /dev/null +++ b/Detectors/ITSMFT/ITS/calibration/testWorkflow/its-calib-workflow.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back( + ConfigParamSpec{ + "doNoise", + VariantType::Bool, + true, + {"Generate noisy-pixel maps"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "configKeyValues", + VariantType::String, + "", + {"Semicolon separated key=value strings"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" +#include "ITSCalibration/NoiseCalibratorSpec.h" +#include "ITSCalibration/NoiseCalibrator.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto doNoise = configcontext.options().get<bool>("doNoise"); + + LOG(INFO) << "ITS calibration workflow options"; + LOG(INFO) << "Generate noisy-pixel maps: " << doNoise; + + if (doNoise) { + specs.emplace_back(o2::its::getNoiseCalibratorSpec()); + } + + return specs; +} diff --git a/Detectors/ITSMFT/ITS/macros/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/CMakeLists.txt index 433d0e3e352e0..8c6767cfdad89 100644 --- a/Detectors/ITSMFT/ITS/macros/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/macros/CMakeLists.txt @@ -1,13 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(EVE) add_subdirectory(test) -add_subdirectory(Calib) diff --git a/Detectors/ITSMFT/ITS/macros/Calib/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/Calib/CMakeLists.txt deleted file mode 100644 index ef2e78517ace7..0000000000000 --- a/Detectors/ITSMFT/ITS/macros/Calib/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_test_root_macro(MakeNoiseMapFromDigits.C - PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT - O2::ITSMFTBase - O2::ITSBase) - -o2_add_test_root_macro(MakeNoiseMapFromClusters.C - PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT - O2::ITSMFTBase - O2::ITSBase) - diff --git a/Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromClusters.C b/Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromClusters.C deleted file mode 100644 index 07badfbf0888b..0000000000000 --- a/Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromClusters.C +++ /dev/null @@ -1,115 +0,0 @@ -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include <iostream> -#include <vector> -#include <string> - -#include <TFile.h> -#include <TTree.h> - -#include "DataFormatsITSMFT/ClusterPattern.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsITSMFT/NoiseMap.h" - -#endif - -void MakeNoiseMapFromClusters(std::string input = "o2clus_its.root", std::string output = "noise.root", bool only1pix = false, float probT = 3e-6) -{ - TFile in(input.data()); - if (!in.IsOpen()) { - std::cerr << "Can not open the input file " << input << '\n'; - return; - } - auto clusTree = (TTree*)in.Get("o2sim"); - if (!clusTree) { - std::cerr << "Can not get cluster tree\n"; - return; - } - - // Clusters - std::vector<o2::itsmft::CompClusterExt>* clusters = nullptr; - clusTree->SetBranchAddress("ITSClusterComp", &clusters); - - // Pixel patterns - std::vector<unsigned char>* patternsPtr = nullptr; - auto pattBranch = clusTree->GetBranch("ITSClusterPatt"); - if (pattBranch) { - pattBranch->SetAddress(&patternsPtr); - } - - //RO frames - std::vector<o2::itsmft::ROFRecord>* rofVec = nullptr; - clusTree->SetBranchAddress("ITSClustersROF", &rofVec); - - o2::itsmft::NoiseMap noiseMap(24120); - - long int nStrobes = 0; - auto nevents = clusTree->GetEntries(); - for (int n = 0; n < nevents; n++) { - clusTree->GetEntry(n); - auto pattIt = patternsPtr->cbegin(); - for (const auto& rof : *rofVec) { - nStrobes++; - auto clustersInFrame = rof.getROFData(*clusters); - for (const auto& c : clustersInFrame) { - if (c.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) - continue; - - o2::itsmft::ClusterPattern patt(pattIt); - - auto id = c.getSensorID(); - auto row = c.getRow(); - auto col = c.getCol(); - auto colSpan = patt.getColumnSpan(); - auto rowSpan = patt.getRowSpan(); - - if ((rowSpan == 1) && (colSpan == 1)) { - noiseMap.increaseNoiseCount(id, row, col); - continue; - } - - if (only1pix) - continue; - - auto nBits = rowSpan * colSpan; - int ic = 0, ir = 0; - for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { - unsigned char tempChar = patt.getByte(i); - int s = 128; // 0b10000000 - while (s > 0) { - if ((tempChar & s) != 0) { - noiseMap.increaseNoiseCount(id, row + ir, col + ic); - } - ic++; - s >>= 1; - if ((ir + 1) * ic == nBits) { - break; - } - if (ic == colSpan) { - ic = 0; - ir++; - } - } - if ((ir + 1) * ic == nBits) { - break; - } - } - } - } - } - - noiseMap.applyProbThreshold(probT, nStrobes); - - int fired = probT * nStrobes; - int ncalib = noiseMap.dumpAboveThreshold(fired); - std::cout << "Probalibity threshold: " << probT - << " number of pixels: " << ncalib << '\n'; - - TFile out(output.data(), "new"); - if (!out.IsOpen()) { - std::cerr << "Can not open the output file " << output << '\n'; - return; - } - out.WriteObject(&noiseMap, "Noise"); - out.Close(); -} diff --git a/Detectors/ITSMFT/ITS/macros/EVE/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/EVE/CMakeLists.txt index 4e03ff082bc56..c29701ec3b47c 100644 --- a/Detectors/ITSMFT/ITS/macros/EVE/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/macros/EVE/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(DisplayEventsComp.C PUBLIC_LINK_LIBRARIES O2::EventVisualisationView diff --git a/Detectors/ITSMFT/ITS/macros/EVE/DisplayEventsComp.C b/Detectors/ITSMFT/ITS/macros/EVE/DisplayEventsComp.C index 91aec1299b87c..5d3fffd7dad07 100644 --- a/Detectors/ITSMFT/ITS/macros/EVE/DisplayEventsComp.C +++ b/Detectors/ITSMFT/ITS/macros/EVE/DisplayEventsComp.C @@ -51,28 +51,37 @@ static TGNumberEntry* gChipID; class Data { public: + void loadTF(int tf) + { + if (mClusTree) + mClusTree->GetEntry(tf); + if (mTracTree) + mTracTree->GetEntry(tf); + } void loadData(int entry); void displayData(int entry, int chip); int getLastEvent() const { return mLastEvent; } - void setRawPixelReader(std::string input) + void setRawPixelReader(std::string input, int tf) { auto reader = new RawPixelReader<ChipMappingITS>(); reader->openInput(input); + // Skip to the TimeFrame = tf + // ??? mPixelReader = reader; - mPixelReader->getNextChipData(mChipData); - mIR = mChipData.getInteractionRecord(); + mPixelReader->setDecodeNextAuto(false); } - void setDigitPixelReader(std::string input) + void setDigitPixelReader(std::string input, int tf) { auto reader = new DigitPixelReader(); reader->openInput(input, o2::detectors::DetID("ITS")); reader->init(); - reader->readNextEntry(); + // Skip to the TimeFrame = tf + do { + reader->readNextEntry(); + } while (tf--); mPixelReader = reader; - mPixelReader->getNextChipData(mChipData); - mIR = mChipData.getInteractionRecord(); + mPixelReader->setDecodeNextAuto(false); } - void setDigiTree(TTree* t) { mDigiTree = t; } void setClusTree(TTree* t); void setTracTree(TTree* t); @@ -81,7 +90,6 @@ class Data int mLastEvent = 0; PixelReader* mPixelReader = nullptr; ChipPixelData mChipData; - o2::InteractionRecord mIR; std::vector<Digit> mDigits; std::vector<CompClusterExt>* mClusterBuffer = nullptr; gsl::span<CompClusterExt> mClusters; @@ -95,7 +103,6 @@ class Data void loadClusters(int entry); void loadTracks(int entry); - TTree* mDigiTree = nullptr; TTree* mClusTree = nullptr; TTree* mTracTree = nullptr; @@ -112,12 +119,11 @@ o2::itsmft::TopologyDictionary dict; void Data::loadDigits() { - auto ir = mChipData.getInteractionRecord(); + mPixelReader->decodeNextTrigger(); + auto ir = mPixelReader->getInteractionRecord(); std::cout << "orbit/crossing: " << ' ' << ir.orbit << '/' << ir.bc << '\n'; - mDigits.clear(); - - do { + while (mPixelReader->getNextChipData(mChipData)) { auto chipID = mChipData.getChipID(); auto pixels = mChipData.getData(); for (auto& pixel : pixels) { @@ -125,11 +131,7 @@ void Data::loadDigits() auto row = pixel.getRowDirect(); mDigits.emplace_back(chipID, row, col, 0); } - if (!mPixelReader->getNextChipData(mChipData)) - return; - ir = mChipData.getInteractionRecord(); - } while (mIR == ir); - mIR = ir; + } std::cout << "Number of ITSDigits: " << mDigits.size() << '\n'; } @@ -139,14 +141,12 @@ void Data::loadDigits(int entry) if (mPixelReader == nullptr) return; + mDigits.clear(); + for (; mLastEvent < entry; mLastEvent++) { - auto ir = mChipData.getInteractionRecord(); - do { - if (!mPixelReader->getNextChipData(mChipData)) - return; - ir = mChipData.getInteractionRecord(); - } while (mIR == ir); - mIR = ir; + mPixelReader->decodeNextTrigger(); + while (mPixelReader->getNextChipData(mChipData)) { + } } mLastEvent++; loadDigits(); @@ -160,7 +160,6 @@ void Data::setClusTree(TTree* tree) } tree->SetBranchAddress("ITSClusterComp", &mClusterBuffer); tree->SetBranchAddress("ITSClustersROF", &mClustersROF); - tree->GetEntry(0); mClusTree = tree; } @@ -189,7 +188,6 @@ void Data::setTracTree(TTree* tree) tree->SetBranchAddress("ITSTrack", &mTrackBuffer); tree->SetBranchAddress("ITSTrackClusIdx", &mClIdxBuffer); tree->SetBranchAddress("ITSTracksROF", &mTracksROF); - tree->GetEntry(0); mTracTree = tree; } @@ -353,7 +351,7 @@ TEveElement* Data::getEveTracks() while (nc--) { Int_t idx = (*mClIdxBuffer)[idxRef + nc]; - const CompClusterExt& c = mClusters[idx]; + const CompClusterExt& c = (*mClusterBuffer)[idx]; auto locC = dict.getClusterCoordinates(c); auto id = c.getSensorID(); const auto gloC = gman->getMatrixL2G(id) * locC; @@ -423,14 +421,14 @@ void load(int entry, int chip) evdata.displayData(entry, chip); } -void init(int entry = 0, int chip = 13, +void init(int tf, int trigger, int chip, std::string digifile = "itsdigits.root", bool rawdata = false, std::string clusfile = "o2clus_its.root", std::string tracfile = "o2trac_its.root", std::string inputGeom = "") { - dict.readBinaryFile(o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin")); + dict.readBinaryFile(o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin")); TEveManager::Create(kTRUE, "V"); TEveBrowser* browser = gEve->GetBrowser(); @@ -467,7 +465,7 @@ void init(int entry = 0, int chip = 13, auto h = new TGHorizontalFrame(frame); auto b = new TGTextButton(h, "PrevEvnt", "prev()"); h->AddFrame(b); - gEntry = new TGNumberEntry(h, 0, 5, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 0, 10000); + gEntry = new TGNumberEntry(h, 0, 7, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 0, 1000000); gEntry->Connect("ValueSet(Long_t)", 0, 0, "load()"); h->AddFrame(gEntry); b = new TGTextButton(h, "NextEvnt", "next()"); @@ -497,7 +495,7 @@ void init(int entry = 0, int chip = 13, if (rawfile->good()) { delete rawfile; std::cout << "Running with raw digits...\n"; - evdata.setRawPixelReader(digifile.data()); + evdata.setRawPixelReader(digifile.data(), tf); } else std::cerr << "\nERROR: Cannot open file: " << digifile << "\n\n"; } else { @@ -505,7 +503,7 @@ void init(int entry = 0, int chip = 13, if (file && gFile->IsOpen()) { file->Close(); std::cout << "Running with MC digits...\n"; - evdata.setDigitPixelReader(digifile.data()); + evdata.setDigitPixelReader(digifile.data(), tf); //evdata.setDigiTree((TTree*)gFile->Get("o2sim")); } else std::cerr << "\nERROR: Cannot open file: " << digifile << "\n\n"; @@ -531,7 +529,9 @@ void init(int entry = 0, int chip = 13, std::cout << " nextChip() \t\t load the next chip within the current event \n"; std::cout << " prevChip() \t\t load the previous chip within the current event \n"; - load(entry, chip); + evdata.loadTF(tf); + + load(trigger, chip); gEve->Redraw3D(kTRUE); } @@ -586,9 +586,9 @@ void prevChip() loadChip(chip); } -void DisplayEventsComp() +void DisplayEventsComp(int tf = 0, int trigger = 0, int chip = 7) { // A dummy function with the same name as this macro - init(0, 7); + init(tf, trigger, chip); gEve->GetBrowser()->GetTabRight()->SetTab(1); } diff --git a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt index 656dbe4574438..befc776289e25 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(CheckClusterShape.C PUBLIC_LINK_LIBRARIES O2::ITSBase O2::ITSMFTSimulation @@ -33,7 +34,7 @@ o2_add_test_root_macro(CheckDigits.C # O2::DataFormatsITSMFT # LABELS its) -o2_add_test_root_macro(CheckTopologies.C +o2_add_test_root_macro(CreateDictionaries.C PUBLIC_LINK_LIBRARIES O2::MathUtils O2::ITSBase O2::ITSMFTReconstruction @@ -58,6 +59,17 @@ o2_add_test_root_macro(CheckTracks.C O2::DataFormatsITSMFT LABELS its) +o2_add_test_root_macro(CheckTracksCA.C + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat + O2::ITSBase + O2::DataFormatsITS + O2::DataFormatsITSMFT + LABELS its) + +o2_add_test_root_macro(RunGPUTracking.C + PUBLIC_LINK_LIBRARIES O2::GPUTracking + LABELS its) + o2_add_test_root_macro(DisplayTrack.C PUBLIC_LINK_LIBRARIES O2::ITSBase O2::DataFormatsITSMFT @@ -78,3 +90,8 @@ o2_add_test_root_macro(run_digi2rawVarPage_its.C O2::ITSMFTBase O2::ITSMFTSimulation LABELS its) + +o2_add_test_root_macro(ITSMisaligner.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::ITSReconstruction + LABELS its) diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckClusterShape.C b/Detectors/ITSMFT/ITS/macros/test/CheckClusterShape.C index a61c2002953a2..14b5c68942849 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckClusterShape.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckClusterShape.C @@ -259,11 +259,11 @@ void CheckClusterShape(std::string digifile = "o2digi_its.root", std::string inp UInt_t layer = gman->getLayer(chipID); Pixel pixels(ix, iz); - if (clusters.find(labs[0]) == clusters.end()) { + if (clusters.find(labs[0].getRawValue()) == clusters.end()) { Cluster c; - clusters[labs[0]] = c; + clusters[labs[0].getRawValue()] = c; } - clusters[labs[0]].AddPixel(layer, pixels); + clusters[labs[0].getRawValue()].AddPixel(layer, pixels); } AnalyzeClusters(nev, clusters, freqDist, cSizeDist); } diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckClusters.C b/Detectors/ITSMFT/ITS/macros/test/CheckClusters.C index f311e4268a30c..d4adc28d94c06 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckClusters.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckClusters.C @@ -1,4 +1,4 @@ -/// \file CheckDigits.C +/// \file CheckClusters.C /// \brief Simple macro to check ITSU clusters #if !defined(__CLING__) || defined(__ROOTCLING__) @@ -43,7 +43,7 @@ void CheckClusters(std::string clusfile = "o2clus_its.root", std::string hitfile std::vector<MC2HITS_map> mc2hitVec; TFile fout("CheckClusters.root", "recreate"); - TNtuple nt("ntc", "cluster ntuple", "ev:lab:hlx:hlz:tx:tz:cgx:cgy:cgz:dx:dy:dz:rof:npx:id"); + TNtuple nt("ntc", "cluster ntuple", "ev:lab:hlx:hlz:tx:tz:cgx:cgy:cgz:dx:dy:dz:ex:ez:patid:rof:npx:id"); // Geometry o2::base::GeometryManager::loadGeometry(inputGeom); @@ -70,7 +70,7 @@ void CheckClusters(std::string clusfile = "o2clus_its.root", std::string hitfile pattBranch->SetAddress(&patternsPtr); } if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } o2::itsmft::TopologyDictionary dict; std::ifstream file(dictfile.c_str()); @@ -147,14 +147,19 @@ void CheckClusters(std::string clusfile = "o2clus_its.root", std::string hitfile const auto& cluster = (*clusArr)[clEntry]; + float errX{0.f}; + float errZ{0.f}; int npix = 0; auto pattID = cluster.getPatternID(); o2::math_utils::Point3D<float> locC; if (pattID == o2::itsmft::CompCluster::InvalidPatternID || dict.isGroup(pattID)) { o2::itsmft::ClusterPattern patt(pattIt); - locC = dict.getClusterCoordinates(cluster, patt); + npix = patt.getNPixels(); + locC = dict.getClusterCoordinates(cluster, patt, false); } else { locC = dict.getClusterCoordinates(cluster); + errX = dict.getErrX(pattID); + errZ = dict.getErrZ(pattID); npix = dict.getNpixels(pattID); } auto chipID = cluster.getSensorID(); @@ -191,11 +196,13 @@ void CheckClusters(std::string clusfile = "o2clus_its.root", std::string hitfile auto r = (0.5 * (Segmentation::SensorLayerThickness - Segmentation::SensorLayerThicknessEff) - y0) / dlty; locH.SetXYZ(x0 + r * dltx, y0 + r * dlty, z0 + r * dltz); //locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); - nt.Fill(lab.getEventID(), trID, - locH.X(), locH.Z(), dltx / dlty, dltz / dlty, - gloC.X(), gloC.Y(), gloC.Z(), - locC.X() - locH.X(), locC.Y() - locH.Y(), locC.Z() - locH.Z(), - rofRec.getROFrame(), npix, chipID); + std::array<float, 18> data = {(float)lab.getEventID(), (float)trID, + locH.X(), locH.Z(), dltx / dlty, dltz / dlty, + gloC.X(), gloC.Y(), gloC.Z(), + locC.X() - locH.X(), locC.Y() - locH.Y(), locC.Z() - locH.Z(), + errX, errZ, (float)pattID, + (float)rofRec.getROFrame(), (float)npix, (float)chipID}; + nt.Fill(data.data()); } } @@ -205,6 +212,25 @@ void CheckClusters(std::string clusfile = "o2clus_its.root", std::string hitfile nt.Draw("dz:dx", "abs(dz)<0.01 && abs(dx)<0.01"); new TCanvas; nt.Draw("dz:tz", "abs(dz)<0.005 && abs(tz)<2"); + + auto c1 = new TCanvas("p1", "pullX"); + c1->cd(); + c1->SetLogy(); + nt.Draw("dx/ex", "abs(dx/ex)<10&&patid<10"); + auto c2 = new TCanvas("p2", "pullZ"); + c2->cd(); + c2->SetLogy(); + nt.Draw("dz/ez", "abs(dz/ez)<10&&patid<10"); + + auto d1 = new TCanvas("d1", "deltaX"); + d1->cd(); + d1->SetLogy(); + nt.Draw("dx", "abs(dx)<5"); + auto d2 = new TCanvas("d2", "deltaZ"); + d2->cd(); + d2->SetLogy(); + nt.Draw("dz", "abs(dz)<5"); + fout.cd(); nt.Write(); } diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckDigits.C b/Detectors/ITSMFT/ITS/macros/test/CheckDigits.C index 9fa3d741f43ef..dec3a76a6f23a 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckDigits.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckDigits.C @@ -15,7 +15,8 @@ #include "ITSMFTBase/SegmentationAlpide.h" #include "ITSMFTSimulation/Hit.h" #include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" #include "SimulationDataFormat/MCCompLabel.h" #include "DetectorsBase/GeometryManager.h" @@ -60,8 +61,8 @@ void CheckDigits(std::string digifile = "itsdigits.root", std::string hitfile = std::vector<o2::itsmft::Digit>* digArr = nullptr; digTree->SetBranchAddress("ITSDigit", &digArr); - o2::dataformats::MCTruthContainer<o2::MCCompLabel>* labels = nullptr; - digTree->SetBranchAddress("ITSDigitMCTruth", &labels); + o2::dataformats::IOMCTruthContainerView* plabels = nullptr; + digTree->SetBranchAddress("ITSDigitMCTruth", &plabels); int nevD = digTree->GetEntries(); // digits in cont. readout may be grouped as few events per entry @@ -83,6 +84,9 @@ void CheckDigits(std::string digifile = "itsdigits.root", std::string hitfile = int nROFRec = (int)ROFRecordArrrayRef.size(); std::vector<int> mcEvMin(nROFRec, hitTree->GetEntries()); std::vector<int> mcEvMax(nROFRec, -1); + o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel> labels; + plabels->copyandflatten(labels); + delete plabels; // >> build min and max MC events used by each ROF for (int imc = MC2ROFRecordArrrayRef.size(); imc--;) { @@ -149,7 +153,7 @@ void CheckDigits(std::string digifile = "itsdigits.root", std::string hitfile = const o2::math_utils::Point3D<float> locD(x, 0., z); Int_t chipID = (*digArr)[iDigit].getChipIndex(); - auto lab = (labels->getLabels(iDigit))[0]; + auto lab = (labels.getLabels(iDigit))[0]; int trID = lab.getTrackID(); diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C b/Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C index 7c4096d7286c6..6bfbc2b1f9faa 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C @@ -37,7 +37,7 @@ void CheckLUtime(std::string clusfile = "o2clus_its.root", std::string dictfile sw.Start(); if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } std::ifstream file(dictfile.c_str()); if (file.good()) { diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckTopologies.C b/Detectors/ITSMFT/ITS/macros/test/CheckTopologies.C deleted file mode 100644 index a7e7034e3f66c..0000000000000 --- a/Detectors/ITSMFT/ITS/macros/test/CheckTopologies.C +++ /dev/null @@ -1,292 +0,0 @@ -/// \file CheckTopologies.C -/// Macros to test the generation of a dictionary of topologies. Three dictionaries are generated: one with signal-cluster only, one with noise-clusters only and one with all the clusters. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include <TAxis.h> -#include <TCanvas.h> -#include <TSystem.h> -#include <TFile.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TNtuple.h> -#include <TString.h> -#include <TStyle.h> -#include <TTree.h> -#include <TStopwatch.h> -#include <fstream> -#include <string> - -#include "MathUtils/Utils.h" -#include "ITSBase/GeometryTGeo.h" -#include "ITSMFTReconstruction/BuildTopologyDictionary.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ClusterTopology.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ITSMFTSimulation/Hit.h" -#include "MathUtils/Cartesian.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include "SimulationDataFormat/DigitizationContext.h" -#include "Framework/Logger.h" -#include <unordered_map> -#endif - -void CheckTopologies(std::string clusfile = "o2clus_its.root", - std::string hitfile = "o2sim_HitsITS.root", - std::string collContextfile = "collisioncontext.root", - std::string inputGeom = "") -{ - const int QEDSourceID = 99; // Clusters from this MC source correspond to QED electrons - - using namespace o2::base; - using namespace o2::its; - - using o2::itsmft::BuildTopologyDictionary; - using o2::itsmft::ClusterTopology; - using o2::itsmft::CompCluster; - using o2::itsmft::CompClusterExt; - using o2::itsmft::Hit; - using ROFRec = o2::itsmft::ROFRecord; - using MC2ROF = o2::itsmft::MC2ROFRecord; - using HitVec = std::vector<Hit>; - using MC2HITS_map = std::unordered_map<uint64_t, int>; // maps (track_ID<<16 + chip_ID) to entry in the hit vector - std::unordered_map<int, int> hadronicMCMap; // mapping from MC event entry to hadronic event ID - std::vector<HitVec*> hitVecPool; - std::vector<MC2HITS_map> mc2hitVec; - const o2::steer::DigitizationContext* digContext = nullptr; - TStopwatch sw; - sw.Start(); - - // Geometry - o2::base::GeometryManager::loadGeometry(inputGeom); - auto gman = o2::its::GeometryTGeo::Instance(); - gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, - o2::math_utils::TransformType::L2G)); // request cached transforms - - // Hits - TFile* fileH = nullptr; - TTree* hitTree = nullptr; - - if (!hitfile.empty() && !collContextfile.empty() && !gSystem->AccessPathName(hitfile.c_str()) && !gSystem->AccessPathName(collContextfile.c_str())) { - fileH = TFile::Open(hitfile.data()); - hitTree = (TTree*)fileH->Get("o2sim"); - mc2hitVec.resize(hitTree->GetEntries()); - hitVecPool.resize(hitTree->GetEntries(), nullptr); - digContext = o2::steer::DigitizationContext::loadFromFile(collContextfile); - - auto& intGlo = digContext->getEventParts(digContext->isQEDProvided()); - int hadrID = -1, nGlo = intGlo.size(), nHadro = 0; - for (int iglo = 0; iglo < nGlo; iglo++) { - const auto& parts = intGlo[iglo]; - bool found = false; - for (auto& part : parts) { - if (part.sourceID == 0) { // we use underlying background - hadronicMCMap[iglo] = part.entryID; - found = true; - nHadro++; - break; - } - } - if (!found) { - hadronicMCMap[iglo] = -1; - } - } - if (nHadro < hitTree->GetEntries()) { - LOG(FATAL) << "N=" << nHadro << " hadronic events < " - << " N=" << hitTree->GetEntries() << " Hit enties."; - } - } - - // Clusters - TFile* fileCl = TFile::Open(clusfile.data()); - TTree* clusTree = (TTree*)fileCl->Get("o2sim"); - std::vector<CompClusterExt>* clusArr = nullptr; - clusTree->SetBranchAddress("ITSClusterComp", &clusArr); - std::vector<unsigned char>* patternsPtr = nullptr; - auto pattBranch = clusTree->GetBranch("ITSClusterPatt"); - if (pattBranch) { - pattBranch->SetAddress(&patternsPtr); - } - - // ROFrecords - std::vector<ROFRec> rofRecVec, *rofRecVecP = &rofRecVec; - clusTree->SetBranchAddress("ITSClustersROF", &rofRecVecP); - - // Cluster MC labels - o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; - std::vector<MC2ROF> mc2rofVec, *mc2rofVecP = &mc2rofVec; - if (hitTree && clusTree->GetBranch("ITSClusterMCTruth")) { - clusTree->SetBranchAddress("ITSClusterMCTruth", &clusLabArr); - clusTree->SetBranchAddress("ITSClustersMC2ROF", &mc2rofVecP); - } - clusTree->GetEntry(0); - - // Topologies dictionaries: 1) all clusters 2) signal clusters only 3) noise clusters only - BuildTopologyDictionary completeDictionary; - BuildTopologyDictionary signalDictionary; - BuildTopologyDictionary noiseDictionary; - - int nROFRec = (int)rofRecVec.size(); - std::vector<int> mcEvMin, mcEvMax; - - if (clusLabArr) { // >> build min and max MC events used by each ROF - mcEvMin.resize(nROFRec, hitTree->GetEntries()); - mcEvMax.resize(nROFRec, -1); - for (int imc = mc2rofVec.size(); imc--;) { - int hadrID = hadronicMCMap[imc]; - if (hadrID < 0) { - continue; - } - const auto& mc2rof = mc2rofVec[imc]; - if (mc2rof.rofRecordID < 0) { - continue; // this MC event did not contribute to any ROF - } - for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { - int irof = mc2rof.rofRecordID + irfd; - if (mcEvMin[irof] > hadrID) { - mcEvMin[irof] = hadrID; - } - if (mcEvMax[irof] < hadrID) { - mcEvMax[irof] = hadrID; - } - } - } - } // << build min and max MC events used by each ROF - - auto pattIdx = patternsPtr->cbegin(); - for (int irof = 0; irof < nROFRec; irof++) { - const auto& rofRec = rofRecVec[irof]; - - rofRec.print(); - - if (clusLabArr) { // >> read and map MC events contributing to this ROF - for (int im = mcEvMin[irof]; im <= mcEvMax[irof]; im++) { - if (!hitVecPool[im]) { - hitTree->SetBranchAddress("ITSHit", &hitVecPool[im]); - hitTree->GetEntry(im); - auto& mc2hit = mc2hitVec[im]; - const auto* hitArray = hitVecPool[im]; - for (int ih = hitArray->size(); ih--;) { - const auto& hit = (*hitArray)[ih]; - uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); - mc2hit.emplace(key, ih); - } - } - } - } // << cache MC events contributing to this ROF - - for (int icl = 0; icl < rofRec.getNEntries(); icl++) { - int clEntry = rofRec.getFirstEntry() + icl; // entry of icl-th cluster of this ROF in the vector of clusters - // do we read MC data? - - const auto& cluster = (*clusArr)[clEntry]; - - if (cluster.getPatternID() != CompCluster::InvalidPatternID) { - LOG(WARNING) << "Encountered patternID = " << cluster.getPatternID() << " != " << CompCluster::InvalidPatternID; - LOG(WARNING) << "Clusters have already been generated with a dictionary! Quitting"; - return; - } - - ClusterTopology topology; - o2::itsmft::ClusterPattern pattern(pattIdx); - topology.setPattern(pattern); - - float dX = BuildTopologyDictionary::IgnoreVal, dZ = BuildTopologyDictionary::IgnoreVal; - if (clusLabArr) { - const auto& lab = (clusLabArr->getLabels(clEntry))[0]; - auto srcID = lab.getSourceID(); - if (lab.isValid() && srcID != QEDSourceID) { // use MC truth info only for non-QED and non-noise clusters - auto trID = lab.getTrackID(); - const auto& mc2hit = mc2hitVec[lab.getEventID()]; - const auto* hitArray = hitVecPool[lab.getEventID()]; - Int_t chipID = cluster.getSensorID(); - uint64_t key = (uint64_t(trID) << 32) + chipID; - auto hitEntry = mc2hit.find(key); - if (hitEntry != mc2hit.end()) { - const auto& hit = (*hitArray)[hitEntry->second]; - auto locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local - auto locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); - locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); - const auto locC = o2::itsmft::TopologyDictionary::getClusterCoordinates(cluster, pattern, false); - dX = locH.X() - locC.X(); - dZ = locH.Z() - locC.Z(); - } else { - printf("Failed to find MC hit entry for Tr:%d chipID:%d\n", trID, chipID); - lab.print(); - } - signalDictionary.accountTopology(topology, dX, dZ); - } else { - noiseDictionary.accountTopology(topology, dX, dZ); - } - } - completeDictionary.accountTopology(topology, dX, dZ); - } - // clean MC cache for events which are not needed anymore - if (clusLabArr) { - int irfNext = irof; - int limMC = irfNext == nROFRec ? hitVecPool.size() : mcEvMin[irfNext]; // can clean events up to this - for (int imc = mcEvMin[irof]; imc < limMC; imc++) { - delete hitVecPool[imc]; - hitVecPool[imc] = nullptr; - mc2hitVec[imc].clear(); - } - } - } - auto dID = o2::detectors::DetID::ITS; - - completeDictionary.setThreshold(0.0001); - completeDictionary.groupRareTopologies(); - completeDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "", ".bin")); - completeDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "", ".txt")); - completeDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "", ".root")); - - TFile histogramOutput("histograms.root", "recreate"); - TCanvas* cComplete = new TCanvas("cComplete", "Distribution of all the topologies"); - cComplete->cd(); - cComplete->SetLogy(); - TH1F* hComplete = nullptr; - o2::itsmft::TopologyDictionary::getTopologyDistribution(completeDictionary.getDictionary(), hComplete, "hComplete"); - hComplete->SetDirectory(0); - hComplete->Draw("hist"); - hComplete->Write(); - cComplete->Write(); - - TCanvas* cNoise = nullptr; - TCanvas* cSignal = nullptr; - TH1F* hNoise = nullptr; - TH1F* hSignal = nullptr; - - if (clusLabArr) { - noiseDictionary.setThreshold(0.0001); - noiseDictionary.groupRareTopologies(); - noiseDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".bin")); - noiseDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".txt")); - noiseDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".root")); - signalDictionary.setThreshold(0.0001); - signalDictionary.groupRareTopologies(); - signalDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".bin")); - signalDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".txt")); - signalDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".root")); - cNoise = new TCanvas("cNoise", "Distribution of noise topologies"); - cNoise->cd(); - cNoise->SetLogy(); - o2::itsmft::TopologyDictionary::getTopologyDistribution(noiseDictionary.getDictionary(), hNoise, "hNoise"); - hNoise->SetDirectory(0); - hNoise->Draw("hist"); - histogramOutput.cd(); - hNoise->Write(); - cNoise->Write(); - cSignal = new TCanvas("cSignal", "cSignal"); - cSignal->cd(); - cSignal->SetLogy(); - o2::itsmft::TopologyDictionary::getTopologyDistribution(signalDictionary.getDictionary(), hSignal, "hSignal"); - hSignal->SetDirectory(0); - hSignal->Draw("hist"); - histogramOutput.cd(); - hSignal->Write(); - cSignal->Write(); - sw.Stop(); - sw.Print(); - } -} diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckTracks.C b/Detectors/ITSMFT/ITS/macros/test/CheckTracks.C index 27f382b289e36..79b2f52ad29df 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckTracks.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckTracks.C @@ -13,6 +13,9 @@ #include <TMath.h> #include <TString.h> +#include "TGeoGlobalMagField.h" +#include "Field/MagneticField.h" +#include "DetectorsBase/Propagator.h" #include "ITSBase/GeometryTGeo.h" #include "SimulationDataFormat/TrackReference.h" #include "SimulationDataFormat/MCTrack.h" @@ -50,10 +53,8 @@ struct DataFrames { int lastIndex = -1; }; -void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile = "o2clus_its.root", std::string kinefile = "o2sim_Kine.root") +void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile = "o2clus_its.root", std::string kinefile = "o2sim_Kine.root", std::string grpfile = "o2sim_grp.root") { - bool filterMultiROFTracks = 1; - using namespace o2::itsmft; using namespace o2::its; @@ -68,6 +69,12 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile "mcPt:recPt:" "ipD:ipZ:label"); + // Magnetic field + o2::base::Propagator::initFieldFromGRP(grpfile.data()); + auto field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); + double orig[3] = {0., 0., 0.}; + float bz = field->getBz(orig); + // Geometry o2::base::GeometryManager::loadGeometry(); auto gman = o2::its::GeometryTGeo::Instance(); @@ -153,14 +160,16 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile if (!recTree->GetEvent(frame)) continue; int loadedEventTracks = frame; + cout << "Number of tracks in frame " << frame << ": " << recArr->size() << std::endl; for (unsigned int i = 0; i < recArr->size(); i++) { // Find the last MC event within this reconstructed entry auto lab = (*trkLabArr)[i]; if (!lab.isValid()) { const TrackITS& recTrack = (*recArr)[i]; fak->Fill(recTrack.getPt()); } - if (!lab.isValid() || lab.getSourceID() != 0 || lab.getEventID() < 0 || lab.getEventID() >= nev) + if (!lab.isValid() || lab.getSourceID() != 0 || lab.getEventID() < 0 || lab.getEventID() >= nev) { continue; + } trackFrames[lab.getEventID()].update(frame, i); } } @@ -218,11 +227,12 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile cout << "track mc label is too big!!!" << endl; continue; } - if (lab.isFake()) { - mapNFakes[mcid]++; - } else if (trackMap[mcid] >= 0) { + if (trackMap[mcid] >= 0) { mapNClones[mcid]++; } else { + if (lab.isFake()) { + mapNFakes[mcid]++; + } trackMap[mcid] = trackStore.size(); const TrackITS& recTrack = (*recArr)[i]; trackStore.emplace_back(recTrack); @@ -261,13 +271,6 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile const CompClusterExt& c = (*clusArr)[i]; - /* FIXME - if (clusRofMap[mcid] < 0) { - clusRofMap[mcid] = c.getROFrame(); - } - if (filterMultiROFTracks && (clusRofMap[mcid] != (int)c.getROFrame())) - continue; -*/ nClusters++; int& ok = clusMap[mcid]; @@ -299,26 +302,20 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile const auto& mcTrack = (*mcArr)[mc]; - if (mapNFakes[mc] > 0) { // Fake-track rate calculation - nFak += mapNFakes[mc]; - fak->Fill(mcTrack.GetPt(), mapNFakes[mc]); - } + auto x = mcTrack.Vx(); + auto y = mcTrack.Vy(); + if (x * x + y * y > 1) + continue; // Select quasi-primary particles, originating from within the beam pipe - Int_t mID = mcTrack.getMotherTrackId(); - if (mID >= 0) { - const auto& mom = (*mcArr)[mID]; - int pdg = std::abs(mom.GetPdgCode()); - if (pdg > 100 || (pdg < 20 && pdg > 10)) - continue; // Select primary particles - } Int_t pdg = mcTrack.GetPdgCode(); if (TMath::Abs(pdg) != 211) continue; // Select pions - if (clusMap[mc] != 0b1111111) - continue; + if (TMath::Abs(mcTrack.GetEta()) > 1.2) + continue; // Select within the acceptance in eta - nGen++; // Generated tracks for the efficiency calculation + if (clusMap[mc] != 0b1111111) + continue; // Select only if all 7 layers have a cluster // Float_t mcYOut=-1., recYOut=-1.; Float_t mcZOut = -1., recZOut = -1.; @@ -331,14 +328,26 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile Float_t mcPt = mcTrack.GetPt(), recPt = -1.; Float_t mcLam = TMath::ATan2(mcPz, mcPt), recLam = -1.; Float_t ip[2]{0., 0.}; - Float_t label = -123456789.; + Float_t label = mc; + nGen++; // Generated tracks for the efficiency calculation den->Fill(mcPt); - if (trackMap[mc] >= 0) { - nGoo++; // Good found tracks for the efficiency calculation - num->Fill(mcPt); + if (mapNClones[mc] > 0) { // Clone-track rate calculation + nClone += mapNClones[mc]; + clone->Fill(mcPt, mapNClones[mc]); + continue; + } + if (trackMap[mc] > 0) { + if (mapNFakes[mc] > 0) { // Fake-track rate calculation + nFak += mapNFakes[mc]; + fak->Fill(mcTrack.GetPt(), mapNFakes[mc]); + label = -mc; + } else { // Good found tracks for the efficiency calculation + nGoo++; + num->Fill(mcPt); + } const TrackITS& recTrack = trackStore[trackMap[mc]]; auto out = recTrack.getParamOut(); // recYOut = out.getY(); @@ -351,18 +360,12 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile recPhi = TMath::ATan2(p[1], p[0]); recLam = TMath::ATan2(p[2], recPt); Float_t vx = 0., vy = 0., vz = 0.; // Assumed primary vertex - Float_t bz = 5.; // Assumed magnetic field recTrack.getImpactParams(vx, vy, vz, bz, ip); - - nt->Fill( // mcYOut,recYOut, - mcZOut, recZOut, mcPhiOut, recPhiOut, mcThetaOut, recThetaOut, mcPhi, recPhi, mcLam, recLam, mcPt, recPt, ip[0], - ip[1], mc); } - if (mapNClones[mc] > 0) { // Clone-track rate calculation - nClone += mapNClones[mc]; - clone->Fill(mcPt, mapNClones[mc]); - } + nt->Fill( // mcYOut,recYOut, + mcZOut, recZOut, mcPhiOut, recPhiOut, mcThetaOut, recThetaOut, mcPhi, recPhi, + mcLam, recLam, mcPt, recPt, ip[0], ip[1], label); } statGen += nGen; @@ -390,13 +393,28 @@ void CheckTracks(std::string tracfile = "o2trac_its.root", std::string clusfile std::cout << "Good found tracks/event: " << statGoo / nDataEvents << ", efficiency: " << eff << ", fake-track rate: " << rat << " clone rate " << clonerat << std::endl; } + TH1F* hg = new TH1F("hg", "Transverse impact parameter; D (cm)", 30, -0.1, 0.1); + hg->SetLineColor(4); + TH1F* hf = new TH1F("hf", "Transverse impact parameter; D (cm)", 30, -0.1, 0.1); + hf->SetLineColor(2); + // "recPt>0" means "found tracks only" // "label>0" means "found good tracks only" + nt->Draw("ipD>>hg", "recPt>0 && label>0", "goff"); + auto norm = hg->Integral(); + if (norm > 0) + hg->Scale(1. / norm); + nt->Draw("ipD>>hf", "recPt>0 && label<0", "goff"); + norm = hf->Integral(); + if (norm > 0) + hf->Scale(1. / norm); + + new TCanvas("d", "d", 600, 600); + hg->Draw("hist"); + hf->Draw("histsame"); /* new TCanvas; - nt->Draw("ipD", "recPt>0 && label>0"); - new TCanvas; nt->Draw("mcLam-recLam", "recPt>0 && label>0"); new TCanvas; nt->Draw("mcPt-recPt", "recPt>0 && label>0"); diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C new file mode 100644 index 0000000000000..e6b4b91e00c6f --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C @@ -0,0 +1,366 @@ +/// \file CheckTracksCA.C +/// \brief Simple macro to check ITSU tracks + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <array> +#include <cmath> +#include <iostream> +#include <vector> + +#include <TFile.h> +#include <TTree.h> +#include <TClonesArray.h> +#include <TH2F.h> +#include <TCanvas.h> +#include <THStack.h> +#include <TLegend.h> +#include <TPad.h> + +#include "ITSBase/GeometryTGeo.h" +#include "SimulationDataFormat/TrackReference.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITS/TrackITS.h" + +#endif + +using namespace std; + +struct ParticleInfo { + int event; + int pdg; + float pt; + float eta; + float phi; + int mother; + int first; + unsigned short clusters = 0u; + unsigned char isReco = 0u; + unsigned char isFake = 0u; + bool isPrimary = 0u; + unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 + o2::its::TrackITS track; +}; + +#pragma link C++ class ParticleInfo + ; + +void CheckTracksCA(bool doFakeClStud = true, std::string tracfile = "o2trac_its.root", std::string clusfile = "o2clus_its.root", std::string kinefile = "o2sim_Kine.root") +{ + + using namespace o2::itsmft; + using namespace o2::its; + + // Geometry + o2::base::GeometryManager::loadGeometry(); + auto gman = o2::its::GeometryTGeo::Instance(); + + // MC tracks + TFile* file0 = TFile::Open(kinefile.data()); + TTree* mcTree = (TTree*)gFile->Get("o2sim"); + mcTree->SetBranchStatus("*", 0); //disable all branches + mcTree->SetBranchStatus("MCTrack*", 1); + + std::vector<o2::MCTrack>* mcArr = nullptr; + mcTree->SetBranchAddress("MCTrack", &mcArr); + + // Clusters + TFile::Open(clusfile.data()); + TTree* clusTree = (TTree*)gFile->Get("o2sim"); + std::vector<CompClusterExt>* clusArr = nullptr; + clusTree->SetBranchAddress("ITSClusterComp", &clusArr); + + // Cluster MC labels + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; + clusTree->SetBranchAddress("ITSClusterMCTruth", &clusLabArr); + + // Reconstructed tracks + TFile* file1 = TFile::Open(tracfile.data()); + TTree* recTree = (TTree*)gFile->Get("o2sim"); + std::vector<TrackITS>* recArr = nullptr; + recTree->SetBranchAddress("ITSTrack", &recArr); + // Track MC labels + std::vector<o2::MCCompLabel>* trkLabArr = nullptr; + recTree->SetBranchAddress("ITSTrackMCTruth", &trkLabArr); + + std::cout << "** Filling particle table ... " << std::flush; + int lastEventIDcl = -1, cf = 0; + int nev = mcTree->GetEntriesFast(); + std::vector<std::vector<ParticleInfo>> info(nev); + for (int n = 0; n < nev; n++) { // loop over MC events + mcTree->GetEvent(n); + info[n].resize(mcArr->size()); + for (unsigned int mcI{0}; mcI < mcArr->size(); ++mcI) { + auto part = mcArr->at(mcI); + info[n][mcI].event = n; + info[n][mcI].pdg = part.GetPdgCode(); + info[n][mcI].pt = part.GetPt(); + info[n][mcI].phi = part.GetPhi(); + info[n][mcI].eta = part.GetEta(); + info[n][mcI].isPrimary = part.isPrimary(); + } + } + std::cout << "done." << std::endl; + + std::cout << "** Creating particle/clusters correspondance ... " << std::flush; + for (int frame = 0; frame < clusTree->GetEntriesFast(); frame++) { // Cluster frames + if (!clusTree->GetEvent(frame)) + continue; + + for (unsigned int iClus{0}; iClus < clusArr->size(); ++iClus) { + auto lab = (clusLabArr->getLabels(iClus))[0]; + if (!lab.isValid() || lab.getSourceID() != 0 || !lab.isCorrect()) + continue; + + int trackID, evID, srcID; + bool fake; + lab.get(trackID, evID, srcID, fake); + if (evID < 0 || evID >= (int)info.size()) { + std::cout << "Cluster MC label eventID out of range" << std::endl; + continue; + } + if (trackID < 0 || trackID >= (int)info[evID].size()) { + std::cout << "Cluster MC label trackID out of range" << std::endl; + continue; + } + + const CompClusterExt& c = (*clusArr)[iClus]; + auto layer = gman->getLayer(c.getSensorID()); + info[evID][trackID].clusters |= 1 << layer; + } + } + std::cout << "done." << std::endl; + + std::cout << "** Analysing tracks ... " << std::flush; + int unaccounted{0}, good{0}, fakes{0}, total{0}; + for (int frame = 0; frame < recTree->GetEntriesFast(); frame++) { // Cluster frames + if (!recTree->GetEvent(frame)) + continue; + total += trkLabArr->size(); + for (unsigned int iTrack{0}; iTrack < trkLabArr->size(); ++iTrack) { + auto lab = trkLabArr->at(iTrack); + if (!lab.isSet()) { + unaccounted++; + continue; + } + int trackID, evID, srcID; + bool fake; + lab.get(trackID, evID, srcID, fake); + if (evID < 0 || evID >= (int)info.size()) { + unaccounted++; + continue; + } + if (trackID < 0 || trackID >= (int)info[evID].size()) { + unaccounted++; + continue; + } + info[evID][trackID].isReco += !fake; + info[evID][trackID].isFake += fake; + /// We keep the best track we would keep in the data + if (recArr->at(iTrack).isBetter(info[evID][trackID].track, 1.e9)) { + info[evID][trackID].storedStatus = fake; + info[evID][trackID].track = recArr->at(iTrack); + } + + fakes += fake; + good += !fake; + } + } + std::cout << "done." << std::endl; + + std::cout << "** Some statistics:" << std::endl; + std::cout << "\t- Total number of tracks: " << total << std::endl; + std::cout << "\t- Total number of tracks not corresponding to particles: " << unaccounted << " (" << unaccounted * 100. / total << "%)" << std::endl; + std::cout << "\t- Total number of fakes: " << fakes << " (" << fakes * 100. / total << "%)" << std::endl; + std::cout << "\t- Total number of good: " << good << " (" << good * 100. / total << "%)" << std::endl; + + int nb = 100; + double xbins[nb + 1], ptcutl = 0.01, ptcuth = 10.; + double a = std::log(ptcuth / ptcutl) / nb; + for (int i = 0; i <= nb; i++) + xbins[i] = ptcutl * std::exp(i * a); + TH1D* num = new TH1D("num", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", nb, xbins); + num->Sumw2(); + TH1D* numChi2 = new TH1D("numChi2", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", 200, 0, 100); + + TH1D* fak = new TH1D("fak", ";#it{p}_{T} (GeV/#it{c});Fak", nb, xbins); + fak->Sumw2(); + TH1D* multiFak = new TH1D("multiFak", ";#it{p}_{T} (GeV/#it{c});Fak", nb, xbins); + multiFak->Sumw2(); + TH1D* fakChi2 = new TH1D("fakChi2", ";#it{p}_{T} (GeV/#it{c});Fak", 200, 0, 100); + + TH1D* clone = new TH1D("clone", ";#it{p}_{T} (GeV/#it{c});Clone", nb, xbins); + clone->Sumw2(); + + TH1D* den = new TH1D("den", ";#it{p}_{T} (GeV/#it{c});Den", nb, xbins); + den->Sumw2(); + + for (auto& evInfo : info) { + for (auto& part : evInfo) { + if (part.clusters != 0x7f) { + // part.clusters != 0x3f && part.clusters != 0x3f << 1 && + // part.clusters != 0x1f && part.clusters != 0x1f << 1 && part.clusters != 0x1f << 2 && + // part.clusters != 0x0f && part.clusters != 0x0f << 1 && part.clusters != 0x0f << 2 && part.clusters != 0x0f << 3) { + continue; + } + if (std::abs(part.eta) > 1.1 && !part.isPrimary) { + continue; + } + den->Fill(part.pt); + if (part.isReco) { + num->Fill(part.pt); + if (part.isReco > 1) { + for (int _i{0}; _i < part.isReco - 1; ++_i) { + clone->Fill(part.pt); + } + } + } + if (part.isFake) { + fak->Fill(part.pt); + if (part.isFake > 1) { + for (int _i{0}; _i < part.isFake - 1; ++_i) { + multiFak->Fill(part.pt); + } + } + } + } + } + + TCanvas* c1 = new TCanvas; + c1->SetLogx(); + c1->SetGridx(); + c1->SetGridy(); + TH1* sum = (TH1*)num->Clone("sum"); + sum->Add(fak); + sum->Divide(sum, den, 1, 1); + sum->SetLineColor(kBlack); + sum->Draw("hist"); + num->Divide(num, den, 1, 1, "b"); + num->Draw("histesame"); + fak->Divide(fak, den, 1, 1, "b"); + fak->SetLineColor(2); + fak->Draw("histesame"); + multiFak->Divide(multiFak, den, 1, 1, "b"); + multiFak->SetLineColor(kRed + 1); + multiFak->Draw("histsame"); + clone->Divide(clone, den, 1, 1, "b"); + clone->SetLineColor(3); + clone->Draw("histesame"); + + std::cout << "** Streaming output TTree to file ... " << std::flush; + TFile file("CheckTracksCA.root", "recreate"); + TTree tree("ParticleInfo", "ParticleInfo"); + ParticleInfo pInfo; + tree.Branch("particle", &pInfo); + for (auto& event : info) { + for (auto& part : event) { + int nCl{0}; + for (unsigned int bit{0}; bit < sizeof(pInfo.clusters) * 8; ++bit) { + nCl += bool(part.clusters & (1 << bit)); + } + if (nCl < 3) { + continue; + } + pInfo = part; + tree.Fill(); + } + } + tree.Write(); + sum->Write("total"); + fak->Write("singleFake"); + num->Write("efficiency"); + multiFak->Write("multiFake"); + clone->Write("clones"); + file.Close(); + std::cout << " done." << std::endl; + + ////////////////////// + // Fake clusters study + if (doFakeClStud) { + std::vector<TH1I*> histLength, histLength1Fake, histLengthNoCl, histLength1FakeNoCl; + std::vector<THStack*> stackLength, stackLength1Fake; + std::vector<TLegend*> legends, legends1Fake; + histLength.resize(4); + histLength1Fake.resize(4); + histLengthNoCl.resize(4); + histLength1FakeNoCl.resize(4); + stackLength.resize(4); + stackLength1Fake.resize(4); + legends.resize(4); + legends1Fake.resize(4); + + for (int iH{4}; iH < 8; ++iH) { + histLength[iH - 4] = new TH1I(Form("trk_len_%d", iH), "#exists cluster", 7, -.5, 6.5); + histLength[iH - 4]->SetFillColor(kBlue); + histLength[iH - 4]->SetLineColor(kBlue); + histLength[iH - 4]->SetFillStyle(3352); + histLengthNoCl[iH - 4] = new TH1I(Form("trk_len_%d_nocl", iH), "#slash{#exists} cluster", 7, -.5, 6.5); + histLengthNoCl[iH - 4]->SetFillColor(kRed); + histLengthNoCl[iH - 4]->SetLineColor(kRed); + histLengthNoCl[iH - 4]->SetFillStyle(3352); + stackLength[iH - 4] = new THStack(Form("stack_trk_len_%d", iH), Form("trk_len=%d", iH)); + stackLength[iH - 4]->Add(histLength[iH - 4]); + stackLength[iH - 4]->Add(histLengthNoCl[iH - 4]); + } + for (int iH{4}; iH < 8; ++iH) { + histLength1Fake[iH - 4] = new TH1I(Form("trk_len_%d_1f", iH), "#exists cluster", 7, -.5, 6.5); + histLength1Fake[iH - 4]->SetFillColor(kBlue); + histLength1Fake[iH - 4]->SetLineColor(kBlue); + histLength1Fake[iH - 4]->SetFillStyle(3352); + histLength1FakeNoCl[iH - 4] = new TH1I(Form("trk_len_%d_1f_nocl", iH), "#slash{#exists} cluster", 7, -.5, 6.5); + histLength1FakeNoCl[iH - 4]->SetFillColor(kRed); + histLength1FakeNoCl[iH - 4]->SetLineColor(kRed); + histLength1FakeNoCl[iH - 4]->SetFillStyle(3352); + stackLength1Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_1f", iH), Form("trk_len=%d, 1 Fake", iH)); + stackLength1Fake[iH - 4]->Add(histLength1Fake[iH - 4]); + stackLength1Fake[iH - 4]->Add(histLength1FakeNoCl[iH - 4]); + } + + for (auto& event : info) { + for (auto& part : event) { + int nCl{0}; + for (unsigned int bit{0}; bit < sizeof(pInfo.clusters) * 8; ++bit) { + nCl += bool(part.clusters & (1 << bit)); + } + if (nCl < 3) { + continue; + } + + auto& track = part.track; + auto len = track.getNClusters(); + for (int iLayer{0}; iLayer < 7; ++iLayer) { + if (track.hasHitOnLayer(iLayer)) { + if (track.isFakeOnLayer(iLayer)) { // Reco track has fake cluster + if (part.clusters & (0x1 << iLayer)) { // Correct cluster exists + histLength[len - 4]->Fill(iLayer); + if (track.getNFakeClusters() == 1) { + histLength1Fake[len - 4]->Fill(iLayer); + } + } else { + histLengthNoCl[len - 4]->Fill(iLayer); + if (track.getNFakeClusters() == 1) { + histLength1FakeNoCl[len - 4]->Fill(iLayer); + } + } + } + } + } + } + } + + auto canvas = new TCanvas("fc_canvas", "Fake clusters", 1600, 1000); + canvas->Divide(4, 2); + for (int iH{0}; iH < 4; ++iH) { + canvas->cd(iH + 1); + stackLength[iH]->Draw(); + gPad->BuildLegend(); + } + for (int iH{0}; iH < 4; ++iH) { + canvas->cd(iH + 5); + stackLength1Fake[iH]->Draw(); + gPad->BuildLegend(); + } + canvas->SaveAs("fakeClusters.png", "recreate"); + } +} diff --git a/Detectors/ITSMFT/ITS/macros/test/CreateDictionaries.C b/Detectors/ITSMFT/ITS/macros/test/CreateDictionaries.C new file mode 100644 index 0000000000000..fd32bd9426eae --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CreateDictionaries.C @@ -0,0 +1,318 @@ +/// \file CreateDictionaries.C +/// Macros to test the generation of a dictionary of topologies. Three dictionaries are generated: one with signal-cluster only, one with noise-clusters only and one with all the clusters. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <TAxis.h> +#include <TCanvas.h> +#include <TSystem.h> +#include <TFile.h> +#include <TH1F.h> +#include <TH2F.h> +#include <TNtuple.h> +#include <TString.h> +#include <TStyle.h> +#include <TTree.h> +#include <TStopwatch.h> +#include <fstream> +#include <string> + +#include "MathUtils/Utils.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITSMFTReconstruction/BuildTopologyDictionary.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ClusterTopology.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITSMFTSimulation/Hit.h" +#include "MathUtils/Cartesian.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include "Framework/Logger.h" +#include <unordered_map> +#endif + +void CreateDictionaries(bool saveDeltas = false, + std::string clusfile = "o2clus_its.root", + std::string hitfile = "o2sim_HitsITS.root", + std::string collContextfile = "collisioncontext.root", + std::string inputGeom = "", + float checkOutliers = 2., // reject outliers (MC dX or dZ exceeds row/col span by a factor above the threshold) + float minPtMC = 0.01) // account only MC hits with pT above threshold +{ + const int QEDSourceID = 99; // Clusters from this MC source correspond to QED electrons + + using namespace o2::base; + using namespace o2::its; + + using o2::itsmft::BuildTopologyDictionary; + using o2::itsmft::ClusterTopology; + using o2::itsmft::CompCluster; + using o2::itsmft::CompClusterExt; + using o2::itsmft::Hit; + using ROFRec = o2::itsmft::ROFRecord; + using MC2ROF = o2::itsmft::MC2ROFRecord; + using HitVec = std::vector<Hit>; + using MC2HITS_map = std::unordered_map<uint64_t, int>; // maps (track_ID<<16 + chip_ID) to entry in the hit vector + std::unordered_map<int, int> hadronicMCMap; // mapping from MC event entry to hadronic event ID + std::vector<HitVec*> hitVecPool; + std::vector<MC2HITS_map> mc2hitVec; + + TFile* fout = nullptr; + TNtuple* nt = nullptr; + if (saveDeltas) { + fout = TFile::Open("CreateDictionaries.root", "recreate"); + nt = new TNtuple("nt", "hashes ntuple", "hash:dx:dz"); + } + + const o2::steer::DigitizationContext* digContext = nullptr; + TStopwatch sw; + sw.Start(); + float minPtMC2 = minPtMC > 0 ? minPtMC * minPtMC : -1; + // Geometry + o2::base::GeometryManager::loadGeometry(inputGeom); + auto gman = o2::its::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::L2G)); // request cached transforms + + // Hits + TFile* fileH = nullptr; + TTree* hitTree = nullptr; + + if (!hitfile.empty() && !collContextfile.empty() && !gSystem->AccessPathName(hitfile.c_str()) && !gSystem->AccessPathName(collContextfile.c_str())) { + fileH = TFile::Open(hitfile.data()); + hitTree = (TTree*)fileH->Get("o2sim"); + mc2hitVec.resize(hitTree->GetEntries()); + hitVecPool.resize(hitTree->GetEntries(), nullptr); + digContext = o2::steer::DigitizationContext::loadFromFile(collContextfile); + + auto& intGlo = digContext->getEventParts(digContext->isQEDProvided()); + int hadrID = -1, nGlo = intGlo.size(), nHadro = 0; + for (int iglo = 0; iglo < nGlo; iglo++) { + const auto& parts = intGlo[iglo]; + bool found = false; + for (auto& part : parts) { + if (part.sourceID == 0) { // we use underlying background + hadronicMCMap[iglo] = part.entryID; + found = true; + nHadro++; + break; + } + } + if (!found) { + hadronicMCMap[iglo] = -1; + } + } + if (nHadro < hitTree->GetEntries()) { + LOG(FATAL) << "N=" << nHadro << " hadronic events < " + << " N=" << hitTree->GetEntries() << " Hit enties."; + } + } + + // Clusters + TFile* fileCl = TFile::Open(clusfile.data()); + TTree* clusTree = (TTree*)fileCl->Get("o2sim"); + std::vector<CompClusterExt>* clusArr = nullptr; + clusTree->SetBranchAddress("ITSClusterComp", &clusArr); + std::vector<unsigned char>* patternsPtr = nullptr; + auto pattBranch = clusTree->GetBranch("ITSClusterPatt"); + if (pattBranch) { + pattBranch->SetAddress(&patternsPtr); + } + + // ROFrecords + std::vector<ROFRec> rofRecVec, *rofRecVecP = &rofRecVec; + clusTree->SetBranchAddress("ITSClustersROF", &rofRecVecP); + + // Cluster MC labels + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; + std::vector<MC2ROF> mc2rofVec, *mc2rofVecP = &mc2rofVec; + if (hitTree && clusTree->GetBranch("ITSClusterMCTruth")) { + clusTree->SetBranchAddress("ITSClusterMCTruth", &clusLabArr); + clusTree->SetBranchAddress("ITSClustersMC2ROF", &mc2rofVecP); + } + clusTree->GetEntry(0); + + // Topologies dictionaries: 1) all clusters 2) signal clusters only 3) noise clusters only + BuildTopologyDictionary completeDictionary; + BuildTopologyDictionary signalDictionary; + BuildTopologyDictionary noiseDictionary; + + int nROFRec = (int)rofRecVec.size(); + std::vector<int> mcEvMin, mcEvMax; + + if (clusLabArr) { // >> build min and max MC events used by each ROF + mcEvMin.resize(nROFRec, hitTree->GetEntries()); + mcEvMax.resize(nROFRec, -1); + for (int imc = mc2rofVec.size(); imc--;) { + int hadrID = hadronicMCMap[imc]; + if (hadrID < 0) { + continue; + } + const auto& mc2rof = mc2rofVec[imc]; + if (mc2rof.rofRecordID < 0) { + continue; // this MC event did not contribute to any ROF + } + for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { + int irof = mc2rof.rofRecordID + irfd; + if (mcEvMin[irof] > hadrID) { + mcEvMin[irof] = hadrID; + } + if (mcEvMax[irof] < hadrID) { + mcEvMax[irof] = hadrID; + } + } + } + } // << build min and max MC events used by each ROF + + auto pattIdx = patternsPtr->cbegin(); + for (int irof = 0; irof < nROFRec; irof++) { + const auto& rofRec = rofRecVec[irof]; + + rofRec.print(); + + if (clusLabArr) { // >> read and map MC events contributing to this ROF + for (int im = mcEvMin[irof]; im <= mcEvMax[irof]; im++) { + if (!hitVecPool[im]) { + hitTree->SetBranchAddress("ITSHit", &hitVecPool[im]); + hitTree->GetEntry(im); + auto& mc2hit = mc2hitVec[im]; + const auto* hitArray = hitVecPool[im]; + for (int ih = hitArray->size(); ih--;) { + const auto& hit = (*hitArray)[ih]; + uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); + mc2hit.emplace(key, ih); + } + } + } + } // << cache MC events contributing to this ROF + + for (int icl = 0; icl < rofRec.getNEntries(); icl++) { + int clEntry = rofRec.getFirstEntry() + icl; // entry of icl-th cluster of this ROF in the vector of clusters + // do we read MC data? + + const auto& cluster = (*clusArr)[clEntry]; + + if (cluster.getPatternID() != CompCluster::InvalidPatternID) { + LOG(WARNING) << "Encountered patternID = " << cluster.getPatternID() << " != " << CompCluster::InvalidPatternID; + LOG(WARNING) << "Clusters have already been generated with a dictionary! Quitting"; + return; + } + + ClusterTopology topology; + o2::itsmft::ClusterPattern pattern(pattIdx); + topology.setPattern(pattern); + + float dX = BuildTopologyDictionary::IgnoreVal, dZ = BuildTopologyDictionary::IgnoreVal; + if (clusLabArr) { + const auto& lab = (clusLabArr->getLabels(clEntry))[0]; + auto srcID = lab.getSourceID(); + if (lab.isValid() && srcID != QEDSourceID) { // use MC truth info only for non-QED and non-noise clusters + auto trID = lab.getTrackID(); + const auto& mc2hit = mc2hitVec[lab.getEventID()]; + const auto* hitArray = hitVecPool[lab.getEventID()]; + Int_t chipID = cluster.getSensorID(); + uint64_t key = (uint64_t(trID) << 32) + chipID; + auto hitEntry = mc2hit.find(key); + if (hitEntry != mc2hit.end()) { + const auto& hit = (*hitArray)[hitEntry->second]; + if (minPtMC < 0.f || hit.GetMomentum().Perp2() > minPtMC2) { + auto locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local + auto locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); + locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); + const auto locC = o2::itsmft::TopologyDictionary::getClusterCoordinates(cluster, pattern, false); + dX = locH.X() - locC.X(); + dZ = locH.Z() - locC.Z(); + if (saveDeltas) { + nt->Fill(topology.getHash(), dX, dZ); + } + if (checkOutliers > 0.) { + if (std::abs(dX) > topology.getRowSpan() * o2::itsmft::SegmentationAlpide::PitchRow * checkOutliers || + std::abs(dZ) > topology.getColumnSpan() * o2::itsmft::SegmentationAlpide::PitchCol * checkOutliers) { // ignore outlier + dX = dZ = BuildTopologyDictionary::IgnoreVal; + } + } + } + } else { + printf("Failed to find MC hit entry for Tr:%d chipID:%d\n", trID, chipID); + lab.print(); + } + signalDictionary.accountTopology(topology, dX, dZ); + } else { + noiseDictionary.accountTopology(topology, dX, dZ); + } + } + completeDictionary.accountTopology(topology, dX, dZ); + } + // clean MC cache for events which are not needed anymore + if (clusLabArr) { + int irfNext = irof; + int limMC = irfNext == nROFRec ? hitVecPool.size() : mcEvMin[irfNext]; // can clean events up to this + for (int imc = mcEvMin[irof]; imc < limMC; imc++) { + delete hitVecPool[imc]; + hitVecPool[imc] = nullptr; + mc2hitVec[imc].clear(); + } + } + } + auto dID = o2::detectors::DetID::ITS; + + completeDictionary.setThreshold(0.0001); + completeDictionary.groupRareTopologies(); + completeDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", "bin")); + completeDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", ".txt")); + completeDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", "root")); + + TFile histogramOutput("histograms.root", "recreate"); + TCanvas* cComplete = new TCanvas("cComplete", "Distribution of all the topologies"); + cComplete->cd(); + cComplete->SetLogy(); + TH1F* hComplete = nullptr; + o2::itsmft::TopologyDictionary::getTopologyDistribution(completeDictionary.getDictionary(), hComplete, "hComplete"); + hComplete->SetDirectory(0); + hComplete->Draw("hist"); + hComplete->Write(); + cComplete->Write(); + + TCanvas* cNoise = nullptr; + TCanvas* cSignal = nullptr; + TH1F* hNoise = nullptr; + TH1F* hSignal = nullptr; + + if (clusLabArr) { + noiseDictionary.setThreshold(0.0001); + noiseDictionary.groupRareTopologies(); + noiseDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTopo", "bin")); + noiseDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTopo", ".txt")); + noiseDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTopo", "root")); + signalDictionary.setThreshold(0.0001); + signalDictionary.groupRareTopologies(); + signalDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", "bin")); + signalDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", ".txt")); + signalDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", "root")); + cNoise = new TCanvas("cNoise", "Distribution of noise topologies"); + cNoise->cd(); + cNoise->SetLogy(); + o2::itsmft::TopologyDictionary::getTopologyDistribution(noiseDictionary.getDictionary(), hNoise, "hNoise"); + hNoise->SetDirectory(0); + hNoise->Draw("hist"); + histogramOutput.cd(); + hNoise->Write(); + cNoise->Write(); + cSignal = new TCanvas("cSignal", "cSignal"); + cSignal->cd(); + cSignal->SetLogy(); + o2::itsmft::TopologyDictionary::getTopologyDistribution(signalDictionary.getDictionary(), hSignal, "hSignal"); + hSignal->SetDirectory(0); + hSignal->Draw("hist"); + histogramOutput.cd(); + hSignal->Write(); + cSignal->Write(); + sw.Stop(); + sw.Print(); + } + if (saveDeltas) { + fout->cd(); + nt->Write(); + } +} diff --git a/Detectors/ITSMFT/ITS/macros/test/DisplayTrack.C b/Detectors/ITSMFT/ITS/macros/test/DisplayTrack.C index e4d47cd3666f9..1056fab29f396 100644 --- a/Detectors/ITSMFT/ITS/macros/test/DisplayTrack.C +++ b/Detectors/ITSMFT/ITS/macros/test/DisplayTrack.C @@ -130,7 +130,7 @@ void DisplayTrack(Int_t event = 0, Int_t track = 0, std::string tracfile = "o2tr std::vector<o2::itsmft::CompClusterExt>* clusArr = nullptr; tree->SetBranchAddress("ITSClusterComp", &clusArr); if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } o2::itsmft::TopologyDictionary dict; std::ifstream file(dictfile.c_str()); diff --git a/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C b/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C new file mode 100644 index 0000000000000..140918a777516 --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C @@ -0,0 +1,105 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +//#define ENABLE_UPGRADES +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsBase/GeometryManager.h" +#include "CCDB/CcdbApi.h" +#include "ITSBase/GeometryTGeo.h" +#include <TRandom.h> +#include <TFile.h> +#include <vector> +#include <fmt/format.h> +#endif + +using AlgPar = std::array<double, 6>; + +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi); + +void ITSMisaligner(const std::string& ccdbHost = "http://localhost:8080", long tmin = 0, long tmax = -1, + double xEnv = 0., double yEnv = 0., double zEnv = 0., double psiEnv = 0., double thetaEnv = 0., double phiEnv = 0., + double xHBa = 0., double yHBa = 0., double zHBa = 0., double psiHBa = 0., double thetaHBa = 0., double phiHBa = 0., + double xSta = 0., double ySta = 0., double zSta = 0., double psiSta = 0., double thetaSta = 0., double phiSta = 0., + double xHSt = 0., double yHSt = 0., double zHSt = 0., double psiHSt = 0., double thetaHSt = 0., double phiHSt = 0., + double xMod = 0., double yMod = 0., double zMod = 0., double psiMod = 0., double thetaMod = 0., double phiMod = 0., + double xChp = 0., double yChp = 0., double zChp = 0., double psiChp = 0., double thetaChp = 0., double phiChp = 0., + const std::string& objectPath = "", + const std::string& fileName = "ITSAlignment.root") +{ + std::vector<o2::detectors::AlignParam> params; + o2::base::GeometryManager::loadGeometry("", false); + auto geom = o2::its::GeometryTGeo::Instance(); + std::string symname; + AlgPar pars; + bool glo = true; + symname = geom->composeSymNameITS(); + + o2::detectors::DetID detITS("ITS"); + + // ITS envelope + pars = generateMisalignment(xEnv, yEnv, zEnv, psiEnv, thetaEnv, phiEnv); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + + for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) { + + for (int ihb = 0; ihb < geom->getNumberOfHalfBarrels(); ihb++) { + symname = geom->composeSymNameHalfBarrel(ilr, ihb); + pars = generateMisalignment(xHBa, yHBa, zHBa, psiHBa, thetaHBa, phiHBa); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + + for (int ist = 0; ist < geom->getNumberOfStaves(ilr) / 2; ist++) { + symname = geom->composeSymNameStave(ilr, ihb, ist); + pars = generateMisalignment(xSta, ySta, zSta, psiSta, thetaSta, phiSta); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + + for (int ihst = 0; ihst < geom->getNumberOfHalfStaves(ilr); ihst++) { + symname = geom->composeSymNameHalfStave(ilr, ihb, ist, ihst); + pars = generateMisalignment(xHSt, yHSt, zHSt, psiHSt, thetaHSt, phiHSt); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + + for (int imd = 0; imd < geom->getNumberOfModules(ilr); imd++) { + symname = geom->composeSymNameModule(ilr, ihb, ist, ihst, imd); + pars = generateMisalignment(xMod, yMod, zMod, psiMod, thetaMod, phiMod); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + } + } + } + } + } + + for (int ich = 0; ich < geom->getNumberOfChips(); ich++) { + symname = o2::base::GeometryManager::getSymbolicName(detITS, ich); + pars = generateMisalignment(xChp, yChp, zChp, psiChp, thetaChp, phiChp); + int chID = o2::base::GeometryManager::getSensID(detITS, ich); + params.emplace_back(symname.c_str(), chID, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], glo); + } + + if (!ccdbHost.empty()) { + std::string path = objectPath.empty() ? o2::base::NameConf::getAlignmentPath(detITS) : objectPath; + LOGP(INFO, "Storing alignment object on {}/{}", ccdbHost, path); + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(¶ms, path, metadata, tmin, tmax); + } + + if (!fileName.empty()) { + LOGP(INFO, "Storing ITS alignment in local file {}", fileName); + TFile algFile(fileName.c_str(), "recreate"); + algFile.WriteObjectAny(¶ms, "std::vector<o2::detectors::AlignParam>", "alignment"); + algFile.Close(); + } +} + +AlgPar generateMisalignment(double x, double y, double z, double psi, double theta, double phi) +{ + AlgPar pars; + pars[0] = gRandom->Gaus(0, x); + pars[1] = gRandom->Gaus(0, y); + pars[2] = gRandom->Gaus(0, z); + pars[3] = gRandom->Gaus(0, psi); + pars[4] = gRandom->Gaus(0, theta); + pars[5] = gRandom->Gaus(0, phi); + return std::move(pars); +} diff --git a/Detectors/ITSMFT/ITS/macros/test/RunGPUTracking.C b/Detectors/ITSMFT/ITS/macros/test/RunGPUTracking.C new file mode 100644 index 0000000000000..8846e5aa82b9e --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/RunGPUTracking.C @@ -0,0 +1,186 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "ITStracking/Vertexer.h" +#include "GPUO2Interface.h" +#include "GPUReconstruction.h" +#include "GPUChainITS.h" + +#include <TChain.h> +#include <TFile.h> +#include <TTree.h> +#include <TGeoGlobalMagField.h> +#include <FairEventHeader.h> +#include <FairGeoParSet.h> +#include <FairLogger.h> +#include "DetectorsCommonDataFormats/NameConf.h" +#include "SimulationDataFormat/MCEventHeader.h" + +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Field/MagneticField.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITStracking/ROframe.h" +#include "ITStracking/IOUtils.h" +#include "ITStracking/Vertexer.h" +#include "MathUtils/Utils.h" +#include "DetectorsBase/Propagator.h" + +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "ITStracking/Configuration.h" + +using MCLabCont = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; +using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; + +void RunGPUTracking(bool useLUT = true, + std::string path = "./", + std::string outputfile = "o2trac_its.root", + std::string inputClustersITS = "o2clus_its.root", + std::string dictfile = "", + std::string matLUTFile = "matbud.root", + std::string inputGRP = "o2sim_grp.root") +{ + o2::its::ROframe event(0, 7); + + if (path.back() != '/') { + path += '/'; + } + + //-------- init geometry and field --------// + const auto grp = o2::parameters::GRPObject::loadFrom(path + inputGRP); + if (!grp) { + LOG(FATAL) << "Cannot run w/o GRP object"; + } + + o2::base::GeometryManager::loadGeometry(path); + o2::base::Propagator::initFieldFromGRP(grp); + auto field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); + if (!field) { + LOG(FATAL) << "Failed to load ma"; + } + double origD[3] = {0., 0., 0.}; + // tracker.setBz(field->getBz(origD)); + + //-------- init lookuptable --------// + if (useLUT) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + } else { + // tracker.setCorrType(o2::base::PropagatorImpl<float>::MatCorrType::USEMatCorrTGeo); + } + + // if (tracker.isMatLUT()) { + // LOG(INFO) << "Loaded material LUT from " << matLUTFile; + // } else { + // LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + // } + + auto gman = o2::its::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::L2G)); // request cached transforms + + //>>>---------- attach input data --------------->>> + TChain itsClusters("o2sim"); + itsClusters.AddFile((path + inputClustersITS).data()); + + if (!itsClusters.GetBranch("ITSClusterComp")) { + LOG(FATAL) << "Did not find ITS clusters branch ITSClusterComp in the input tree"; + } + std::vector<o2::itsmft::CompClusterExt>* cclusters = nullptr; + itsClusters.SetBranchAddress("ITSClusterComp", &cclusters); + + if (!itsClusters.GetBranch("ITSClusterPatt")) { + LOG(FATAL) << "Did not find ITS cluster patterns branch ITSClusterPatt in the input tree"; + } + std::vector<unsigned char>* patterns = nullptr; + itsClusters.SetBranchAddress("ITSClusterPatt", &patterns); + + MCLabCont* labels = nullptr; + if (!itsClusters.GetBranch("ITSClusterMCTruth")) { + LOG(WARNING) << "Did not find ITS clusters branch ITSClusterMCTruth in the input tree"; + } else { + itsClusters.SetBranchAddress("ITSClusterMCTruth", &labels); + } + + if (!itsClusters.GetBranch("ITSClustersROF")) { + LOG(FATAL) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; + } + + std::vector<o2::itsmft::MC2ROFRecord>* mc2rofs = nullptr; + if (!itsClusters.GetBranch("ITSClustersMC2ROF")) { + LOG(FATAL) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; + } + itsClusters.SetBranchAddress("ITSClustersMC2ROF", &mc2rofs); + + std::vector<o2::itsmft::ROFRecord>* rofs = nullptr; + itsClusters.SetBranchAddress("ITSClustersROF", &rofs); + itsClusters.GetEntry(0); + + o2::itsmft::TopologyDictionary dict; + if (dictfile.empty()) { + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); + } + std::ifstream file(dictfile.c_str()); + if (file.good()) { + LOG(INFO) << "Running with dictionary: " << dictfile.c_str(); + dict.readBinaryFile(dictfile); + } else { + LOG(INFO) << "Running without dictionary !"; + } + //------------------------------------------------- + std::unique_ptr<o2::gpu::GPUReconstruction> recCUDA(o2::gpu::GPUReconstruction::CreateInstance(o2::gpu::GPUDataTypes::DeviceType::CUDA, true)); + auto* chainITSCUDA = recCUDA->AddChain<o2::gpu::GPUChainITS>(); + std::unique_ptr<o2::its::Vertexer> vertexerCUDA = std::make_unique<o2::its::Vertexer>(chainITSCUDA->GetITSVertexerTraits()); + + std::unique_ptr<o2::gpu::GPUReconstruction> recHIP(o2::gpu::GPUReconstruction::CreateInstance(o2::gpu::GPUDataTypes::DeviceType::HIP, true)); + auto* chainITSHIP = recHIP->AddChain<o2::gpu::GPUChainITS>(); + std::unique_ptr<o2::its::Vertexer> vertexerHIP = std::make_unique<o2::its::Vertexer>(chainITSHIP->GetITSVertexerTraits()); + + o2::its::VertexingParameters parameters; + parameters.phiCut = 0.005f; + parameters.tanLambdaCut = 0.002f; + + vertexerCUDA->setParameters(parameters); + vertexerHIP->setParameters(parameters); + + gsl::span<const unsigned char> patt(patterns->data(), patterns->size()); + auto pattIt = patt.begin(); + auto clSpan = gsl::span(cclusters->data(), cclusters->size()); + + for (auto& rof : *rofs) { + + auto it = pattIt; + o2::its::ioutils::loadROFrameData(rof, event, clSpan, pattIt, dict, labels); + + // // CUDA + vertexerCUDA->initialiseVertexer(&event); + vertexerCUDA->findTracklets(); + // vertexerCUDA.filterMCTracklets(); // to use MC check + vertexerCUDA->validateTracklets(); + vertexerCUDA->findVertices(); + std::vector<Vertex> vertITSCU = vertexerCUDA->exportVertices(); + if (!vertITSCU.empty()) { + std::cout << " - Reconstructed vertex: x = " << vertITSCU[0].getX() << " y = " << vertITSCU[0].getY() << " x = " << vertITSCU[0].getZ() << std::endl; + event.addPrimaryVertex(vertITSCU[0].getX(), vertITSCU[0].getY(), vertITSCU[0].getZ()); + } else { + std::cout << " - Vertex not reconstructed" << std::endl; + } + + // // HIP + vertexerHIP->initialiseVertexer(&event); + vertexerHIP->findTracklets(); + // // vertexerHIP.filterMCTracklets(); // to use MC check + vertexerHIP->validateTracklets(); + vertexerHIP->findVertices(); + std::vector<Vertex> vertITSHIP = vertexerHIP->exportVertices(); + if (!vertITSHIP.empty()) { + std::cout << " - Reconstructed vertex: x = " << vertITSHIP[0].getX() << " y = " << vertITSHIP[0].getY() << " x = " << vertITSHIP[0].getZ() << std::endl; + event.addPrimaryVertex(vertITSHIP[0].getX(), vertITSHIP[0].getY(), vertITSHIP[0].getZ()); + } else { + std::cout << " - Vertex not reconstructed" << std::endl; + } + } +} +#endif diff --git a/Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C b/Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C index c78e9cdd8b99d..0950bca2d5840 100644 --- a/Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C +++ b/Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C @@ -20,7 +20,7 @@ void dictionary_integrity_test(std::string dictfile = "", std::string output_nam TopologyDictionary dict; if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } dict.readBinaryFile(dictfile); LookUp finder(dictfile); diff --git a/Detectors/ITSMFT/ITS/macros/test/run_test.sh b/Detectors/ITSMFT/ITS/macros/test/run_test.sh index 894f1de96fa8a..b995013dbdd7a 100755 --- a/Detectors/ITSMFT/ITS/macros/test/run_test.sh +++ b/Detectors/ITSMFT/ITS/macros/test/run_test.sh @@ -18,7 +18,7 @@ root -b -q $O2_ROOT/share/macro/run_clus_itsSA.C+\(\"itsdigits.root\",\"o2clus_i root.exe -b -q CheckClusters.C+ >& CheckClusters.log -#root.exe -b -q CheckTopologies.C+ >& CheckTopologies.log +#root.exe -b -q CreateDictionaries.C+ >& CreateDictionaries.log root.exe -b -q $O2_ROOT/share/macro/run_trac_its.C+ >& trac_its.log diff --git a/Detectors/ITSMFT/ITS/macros/test/run_workflows.sh b/Detectors/ITSMFT/ITS/macros/test/run_workflows.sh index 8545b8e22689a..7e575e31bbb34 100755 --- a/Detectors/ITSMFT/ITS/macros/test/run_workflows.sh +++ b/Detectors/ITSMFT/ITS/macros/test/run_workflows.sh @@ -8,7 +8,7 @@ o2-its-reco-workflow >& reco.log # These macros can be run to check the quality of the results # root.exe CheckDigits.C+ # root.exe CheckClusters.C+ -# root.exe CheckTopologies.C+ +# root.exe CreateDictionaries.C+ # root.exe CheckTracks.C+ # root.exe DisplayTrack.C+ diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index 8c285186f0597..a5fcd6d475f50 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( ITSReconstruction diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h index 28ea20383ad1a..a9b6335230f1d 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h index 6a4cfd2b36fd9..5f65010130c19 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -88,7 +89,7 @@ class CookedTracker for (int i = 0; i < noc; i++) { const Cluster* c = this->getCluster(t.getClusterIndex(i)); Int_t idx = c - &mClusterCache[0]; // Index of this cluster in event - clusIdx.emplace_back(idx); + clusIdx.emplace_back(this->mFirstInFrame + idx); } trackNew.setClusterRefs(clEntry, noc); trackNew.setPattern(0x7f); // this tracker finds only complete tracks diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h index 0784b3b5b6705..abbee1b63a371 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h index b6cbb61e1244c..a22de1d8b97ea 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h index 5e927df91c1e1..f4b51fada3efb 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h index 43ed0b905ae43..3eb218dc973f6 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx index 033e5e2b92b87..27793f8391dea 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx index 0e0303dd97701..8ed4d50d776b9 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx index 605f3519b66d4..b432c404002aa 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEstConfig.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEstConfig.cxx index fc6d6613045a8..5b8fb68b41993 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEstConfig.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEstConfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h index 216a0443e1475..c93cf03d0ed3d 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h +++ b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx index 15895fa9b54f8..8af5b5efddd25 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -97,7 +98,7 @@ void RecoGeomHelper::RecoLayer::init() float dzH = o2::itsmft::SegmentationAlpide::SensorSizeCols / 2; // half width in Z int nCh = gm->getNumberOfChipsPerLayer(id), chip0 = gm->getFirstChipIndex(id); int nChMod = gm->getNumberOfChipsPerModule(id), nChModH = nChMod / 2; - nLadders = nStaves * nHStaves * (id > 2 ? 2 : 1); // 2 ladders per h-stave for OB + nLadders = nHStaves > 1 ? nStaves * nHStaves * 2 : nStaves; // 2 ladders per h-stave for OB ladders.resize(nLadders); for (auto lad : ladders) { diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx index 6eb0cfbb36f5e..0b0291e53642a 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/CMakeLists.txt b/Detectors/ITSMFT/ITS/simulation/CMakeLists.txt index 9a0e0525b2018..4525f9e40b74e 100644 --- a/Detectors/ITSMFT/ITS/simulation/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSSimulation SOURCES src/V11Geometry.cxx src/V1Layer.cxx src/V3Layer.cxx @@ -25,6 +26,7 @@ o2_data_file(COPY data DESTINATION Detectors/ITS/simulation) o2_add_executable(digi2raw COMPONENT_NAME its + TARGETVARNAME itsdigi2raw_exe SOURCES src/digi2raw.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTReconstruction O2::DataFormatsITSMFT @@ -34,3 +36,9 @@ o2_add_executable(digi2raw O2::DetectorsCommonDataFormats O2::CommonUtils Boost::program_options) + +if(NOT APPLE) + + set_property(TARGET ${itsdigi2raw_exe} PROPERTY LINK_WHAT_YOU_USE ON) + +endif() diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h index f64a443a4cdd9..5d2ea789ecb3b 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -119,12 +120,6 @@ class Detector : public o2::base::DetImpl<Detector> /// Base class to create the detector geometry void ConstructGeometry() override; - /// Creates the Service Barrel (as a simple cylinder) for IB and OB - /// \param innerBarrel if true, build IB service barrel, otherwise for OB - /// \param dest the mother volume holding the service barrel - /// \param mgr the gGeoManager pointer (used to get the material) - void createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr = gGeoManager); - /// Sets the layer parameters /// \param nlay layer number /// \param phi0 layer phi0 @@ -188,39 +183,50 @@ class Detector : public o2::base::DetImpl<Detector> /// \param lastUID on output, UID of the last volume void addAlignableVolumesLayer(Int_t lr, TString& parent, Int_t& lastUID) const; + /// Add alignable Half Barrel volumes + /// \param lr layer number + /// \param hb half barrel number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const; + /// Add alignable Stave volumes /// \param lr layer number + /// \param hb half barrel number /// \param st stave number /// \param parent path of the parent volume /// \param lastUID on output, UID of the last volume - void addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const; + void addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const; /// Add alignable HalfStave volumes /// \param lr layer number + /// \param hb half barrel number /// \param st stave number /// \param hst half stave number /// \param parent path of the parent volume /// \param lastUID on output, UID of the last volume - void addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const; + void addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const; /// Add alignable Module volumes /// \param lr layer number + /// \param hb half barrel number /// \param st stave number /// \param hst half stave number /// \param md module number /// \param parent path of the parent volume /// \param lastUID on output, UID of the last volume - void addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const; + void addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const; /// Add alignable Chip volumes /// \param lr layer number + /// \param hb half barrel number /// \param st stave number /// \param hst half stave number /// \param md module number /// \param ch chip number /// \param parent path of the parent volume /// \param lastUID on output, UID of the last volume - void addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, + void addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, Int_t& lastUID) const; /// Return Chip Volume UID diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V11Geometry.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V11Geometry.h index ff62622b4cd4e..bdbd9f0a5c66a 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V11Geometry.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V11Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V1Layer.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V1Layer.h index 97e0d120fbb7a..76e9d00e04e68 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V1Layer.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V1Layer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h index 65d221df34a00..62e09abcbdd68 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,12 +34,13 @@ namespace its { /// This class defines the Geometry for the ITS using TGeo. This is a work class used -/// to study different configurations during the development of the new ITS structure +/// to study different configurations during the development of the new ITS structure. class V3Layer : public V11Geometry { public: - enum { kStave, + enum { kHalfBarrel, + kStave, kHalfStave, kModule, kChip, @@ -86,6 +88,8 @@ class V3Layer : public V11Geometry Int_t getChipType() const { return mChipTypeID; } + Int_t getNumberOfHalfBarrelsPerParent() const { return mHierarchy[kHalfBarrel]; } + Int_t getNumberOfStavesPerParent() const { return mHierarchy[kStave]; } Int_t getNumberOfHalfStavesPerParent() const { return mHierarchy[kHalfStave]; } @@ -144,12 +148,15 @@ class V3Layer : public V11Geometry virtual void createLayer(TGeoVolume* motherVolume); private: - /// Creates the actual Layer and places inside its mother volume + /// Creates a half barrel + TGeoVolume* createHalfBarrel(); + + /// Creates a "turbo" half barrel /// A so-called "turbo" layer is a layer where staves overlap in phi /// User can set width and tilt angle, no check is performed here /// to avoid volume overlaps /// \param motherVolume The TGeoVolume owing the volume structure - void createLayerTurbo(TGeoVolume* motherVolume); + TGeoVolume* createHalfBarrelTurbo(); /// Computes the inner radius of the air container for the Turbo configuration /// as the radius of either the circle tangent to the stave or the circle @@ -161,10 +168,12 @@ class V3Layer : public V11Geometry /// \param mgr The GeoManager (used only to get the proper material) TGeoVolume* createStave(const TGeoManager* mgr = gGeoManager); - /// Creates the IB Module: (only the chips for the time being) + /// Creates the IB Module: all elements except the Chip /// Returns the module as a TGeoVolume + /// \param xchip the Chip width + /// \param zchip the Chip length /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createModuleInnerB(const TGeoManager* mgr = gGeoManager); + TGeoVolume* createModuleInnerB(const Double_t xchip, const Double_t zchip, const TGeoManager* mgr = gGeoManager); /// Creates the OB Module: HIC + FPC + Carbon plate /// Returns the module as a TGeoVolume @@ -190,10 +199,11 @@ class V3Layer : public V11Geometry /// \param mgr The GeoManager (used only to get the proper material) void createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yzero, const TGeoManager* mgr = gGeoManager); - /// Create the chip stave for the Inner Barrel(Here we fake the halfstave volume to have the - /// same formal geometry hierarchy as for the Outer Barrel) + /// Create the chip stave for the Inner Barrel + /// Returns the old "module" thickness + /// \param mother The mother volume /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveInnerB(const TGeoManager* mgr = gGeoManager); + Double_t createStaveInnerB(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); /// Create the mechanical stave structure /// \param mgr The GeoManager (used only to get the proper material) diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Services.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Services.h index 63544da519169..f289e4dbde444 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Services.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Services.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -91,6 +92,11 @@ class V3Services : public V11Geometry /// \param mgr The GeoManager (used only to get the proper material) void createOBConeSideC(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); + /// Creates the Outer Barrel CYSS Cylinder + /// \param mother the TGeoVolume owing the volume structure + /// \param mgr The GeoManager (used only to get the proper material) + void createOBCYSSCylinder(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); + private: /// Creates a single Inner Barrel End Wheel on Side A /// \param iLay the layer number @@ -161,6 +167,11 @@ class V3Services : public V11Geometry /// \param mgr The GeoManager (used only to get the proper material) void obConeTraysSideA(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); + /// Creates the Outer Barrel CYSS volume 11 + /// \param mother the volume containing the created wheel + /// \param mgr The GeoManager (used only to get the proper material) + void obCYSS11(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); + // Parameters static constexpr Int_t sNumberInnerLayers = 3; ///< Number of inner layers in ITSU static constexpr Int_t sNumberMiddlLayers = 2; ///< Number of middle layers in ITSU diff --git a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx index 4fb226daa8a6e..96b6819854ec5 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -100,10 +101,10 @@ static void configITS(Detector* its) {2.24, 2.34, 2.67, 9., 16.42, 12}, // for each inner layer: rMin,rMid,rMax,NChip/Stave, phi0, nStaves {3.01, 3.15, 3.46, 9., 12.18, 16}, {3.78, 3.93, 4.21, 9., 9.55, 20}, - {-1, 19.6, -1, 4., 0., 24}, // for others: -, rMid, -, NMod/HStave, phi0, nStaves // 24 was 49 - {-1, 24.55, -1, 4., 0., 30}, // 30 was 61 - {-1, 34.39, -1, 7., 0., 42}, // 42 was 88 - {-1, 39.34, -1, 7., 0., 48} // 48 was 100 + {-1, 19.6, -1, 4., 7.5, 24}, // for others: -, rMid, -, NMod/HStave, phi0, nStaves // 24 was 49 + {-1, 24.55, -1, 4., 6., 30}, // 30 was 61 + {-1, 34.39, -1, 7., 4.29, 42}, // 42 was 88 + {-1, 39.34, -1, 7., 3.75, 48} // 48 was 100 }; const int nChipsPerModule = 7; // For OB: how many chips in a row const double zChipGap = 0.01; // For OB: gap in Z between chips @@ -117,7 +118,7 @@ static void configITS(Detector* its) const int kNWrapVol = 3; const double wrpRMin[kNWrapVol] = {2.1, 19.3, 33.32}; - const double wrpRMax[kNWrapVol] = {15.4, 29.14, 46.0}; + const double wrpRMax[kNWrapVol] = {15.4, 29.14, 44.9}; const double wrpZSpan[kNWrapVol] = {70., 93., 163.6}; for (int iw = 0; iw < kNWrapVol; iw++) { @@ -342,12 +343,13 @@ Bool_t Detector::ProcessHits(FairVolume* vol) TLorentzVector positionStop; fMC->TrackPosition(positionStop); // Retrieve the indices with the volume path - int stave(0), halfstave(0), chipinmodule(0), module; + int halfbarrel(0), stave(0), halfstave(0), chipinmodule(0), module; fMC->CurrentVolOffID(1, chipinmodule); fMC->CurrentVolOffID(2, module); fMC->CurrentVolOffID(3, halfstave); fMC->CurrentVolOffID(4, stave); - int chipindex = mGeometryTGeo->getChipIndex(lay, stave, halfstave, module, chipinmodule); + fMC->CurrentVolOffID(5, halfbarrel); + int chipindex = mGeometryTGeo->getChipIndex(lay, halfbarrel, stave, halfstave, module, chipinmodule); Hit* p = addHit(stack->GetCurrentTrackNumber(), chipindex, mTrackData.mPositionStart.Vect(), positionStop.Vect(), mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), @@ -890,10 +892,6 @@ void Detector::constructDetectorGeometry() createOuterBarrelServices(wrapVols[2]); createOuterBarrelSupports(vITSV); - // TEMPORARY - These routines will be obsoleted once the new services are completed - TEMPORARY - // createServiceBarrel(kTRUE, wrapVols[0]); - // createServiceBarrel(kFALSE, wrapVols[2]); - delete[] wrapVols; // delete pointer only, not the volumes } @@ -988,6 +986,7 @@ void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume) // Return: // // Created: 26 Jan 2020 Mario Sitta + // Updated: 02 Mar 2020 Mario Sitta // // Create the Cone on Side A @@ -995,42 +994,9 @@ void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume) // Create the Cone on Side C mServicesGeometry->createOBConeSideC(motherVolume); -} - -// Service Barrel -void Detector::createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr) -{ - // Creates the Service Barrel (as a simple cylinder) for IB and OB - // Inputs: - // innerBarrel : if true, build IB service barrel, otherwise for OB - // dest : the mother volume holding the service barrel - // mgr : the gGeoManager pointer (used to get the material) - // - - Double_t rminIB = 4.7; - Double_t rminOB = 43.9; - Double_t zLenOB; - Double_t cInt = 0.22; // dimensioni cilindro di supporto interno - Double_t cExt = 1.00; // dimensioni cilindro di supporto esterno - // Double_t phi1 = 180; - // Double_t phi2 = 360; - - TGeoMedium* medCarbonFleece = mgr->GetMedium("ITS_CarbonFleece$"); - - if (innerBarrel) { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - // TGeoTube*ibSuppSh = new TGeoTubeSeg(rminIB,rminIB+cInt,zLenOB,phi1,phi2); - auto* ibSuppSh = new TGeoTube(rminIB, rminIB + cInt, zLenOB); - auto* ibSupp = new TGeoVolume("ibSuppCyl", ibSuppSh, medCarbonFleece); - dest->AddNode(ibSupp, 1); - } else { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - auto* obSuppSh = new TGeoTube(rminOB, rminOB + cExt, zLenOB); - auto* obSupp = new TGeoVolume("obSuppCyl", obSuppSh, medCarbonFleece); - dest->AddNode(obSupp, 1); - } - return; + // Create the CYSS Cylinder + mServicesGeometry->createOBCYSSCylinder(motherVolume); } void Detector::addAlignableVolumes() const @@ -1072,6 +1038,7 @@ void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) // Add alignable volumes for a Layer and its daughters // // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Updated: 06 Jul 2021 Mario Sitta Do not set Layer as alignable volume // TString wrpV = @@ -1079,31 +1046,56 @@ void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) TString path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr); TString sname = GeometryTGeo::composeSymNameLayer(lr); - LOG(DEBUG) << "Add " << sname << " <-> " << path; + const V3Layer* lrobj = mGeometry[lr]; + Int_t nhbarrel = lrobj->getNumberOfHalfBarrelsPerParent(); + Int_t start = nhbarrel > 0 ? 0 : -1; + for (Int_t hb = start; hb < nhbarrel; hb++) { + addAlignableVolumesHalfBarrel(lr, hb, path, lastUID); + } - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + return; +} + +void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const +{ + // + // Add alignable volumes for a Half barrel and its daughters + // + // Created: 28 Jun 2021 Mario Sitta First version (based on similar methods) + // + + TString path = parent; + if (hb >= 0) { + path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfBarrelPattern(), lr, hb); + TString sname = GeometryTGeo::composeSymNameHalfBarrel(lr, hb); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } } const V3Layer* lrobj = mGeometry[lr]; Int_t nstaves = lrobj->getNumberOfStavesPerParent(); for (int st = 0; st < nstaves; st++) { - addAlignableVolumesStave(lr, st, path, lastUID); + addAlignableVolumesStave(lr, hb, st, path, lastUID); } return; } -void Detector::addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const +void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const { // // Add alignable volumes for a Stave and its daughters // // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added // TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSStavePattern(), lr, st); - TString sname = GeometryTGeo::composeSymNameStave(lr, st); + TString sname = GeometryTGeo::composeSymNameStave(lr, hb, st); LOG(DEBUG) << "Add " << sname << " <-> " << path; @@ -1115,24 +1107,25 @@ void Detector::addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int Int_t nhstave = lrobj->getNumberOfHalfStavesPerParent(); Int_t start = nhstave > 0 ? 0 : -1; for (Int_t sst = start; sst < nhstave; sst++) { - addAlignableVolumesHalfStave(lr, st, sst, path, lastUID); + addAlignableVolumesHalfStave(lr, hb, st, sst, path, lastUID); } return; } -void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const +void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const { // // Add alignable volumes for a HalfStave (if any) and its daughters // // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added // TString path = parent; if (hst >= 0) { path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfStavePattern(), lr, hst); - TString sname = GeometryTGeo::composeSymNameHalfStave(lr, st, hst); + TString sname = GeometryTGeo::composeSymNameHalfStave(lr, hb, st, hst); LOG(DEBUG) << "Add " << sname << " <-> " << path; @@ -1145,24 +1138,25 @@ void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TStri Int_t nmodules = lrobj->getNumberOfModulesPerParent(); Int_t start = nmodules > 0 ? 0 : -1; for (Int_t md = start; md < nmodules; md++) { - addAlignableVolumesModule(lr, st, hst, md, path, lastUID); + addAlignableVolumesModule(lr, hb, st, hst, md, path, lastUID); } return; } -void Detector::addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const +void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const { // // Add alignable volumes for a Module (if any) and its daughters // // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added // TString path = parent; if (md >= 0) { path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSModulePattern(), lr, md); - TString sname = GeometryTGeo::composeSymNameModule(lr, st, hst, md); + TString sname = GeometryTGeo::composeSymNameModule(lr, hb, st, hst, md); LOG(DEBUG) << "Add " << sname << " <-> " << path; @@ -1174,23 +1168,24 @@ void Detector::addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md const V3Layer* lrobj = mGeometry[lr]; Int_t nchips = lrobj->getNumberOfChipsPerParent(); for (Int_t ic = 0; ic < nchips; ic++) { - addAlignableVolumesChip(lr, st, hst, md, ic, path, lastUID); + addAlignableVolumesChip(lr, hb, st, hst, md, ic, path, lastUID); } return; } -void Detector::addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, +void Detector::addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, Int_t& lastUID) const { // // Add alignable volumes for a Chip // // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added // TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSChipPattern(), lr, ch); - TString sname = GeometryTGeo::composeSymNameChip(lr, st, hst, md, ch); + TString sname = GeometryTGeo::composeSymNameChip(lr, hb, st, hst, md, ch); Int_t modUID = chipVolUID(lastUID++); LOG(DEBUG) << "Add " << sname << " <-> " << path; diff --git a/Detectors/ITSMFT/ITS/simulation/src/ITSSimulationLinkDef.h b/Detectors/ITSMFT/ITS/simulation/src/ITSSimulationLinkDef.h index 8b61217aaae02..005efb4c6c3e9 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/ITSSimulationLinkDef.h +++ b/Detectors/ITSMFT/ITS/simulation/src/ITSSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/src/V11Geometry.cxx b/Detectors/ITSMFT/ITS/simulation/src/V11Geometry.cxx index 9e4377fa226e9..9f39736dfebb3 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V11Geometry.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V11Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/src/V1Layer.cxx b/Detectors/ITSMFT/ITS/simulation/src/V1Layer.cxx index 416d69cdb1562..43fc298dd70c5 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V1Layer.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V1Layer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx b/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx index 86fa07c29c7a1..4c2897c42ebeb 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -309,6 +310,35 @@ V3Layer::V3Layer(Int_t lay, Bool_t turbo, Int_t debug) V3Layer::~V3Layer() = default; void V3Layer::createLayer(TGeoVolume* motherVolume) +{ + std::string volumeName; + + volumeName = fmt::format("{:s}{:d}", GeometryTGeo::getITSLayerPattern(), mLayerNumber); + TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName.c_str()); + + // Call for creation of a single Half Barrel + // and put two copies in the Layer volume + TGeoVolume* halfBarrel; + + // If a Turbo layer is requested, do it + if (mIsTurbo) { + halfBarrel = createHalfBarrelTurbo(); + } else { + halfBarrel = createHalfBarrel(); + } + + layerVolume->AddNode(halfBarrel, 0, nullptr); + layerVolume->AddNode(halfBarrel, 1, new TGeoRotation("", 180, 0, 0)); + mHierarchy[kHalfBarrel] = 2; + + // Finally put everything in the mother volume + motherVolume->AddNode(layerVolume, 1, nullptr); + + // geometry is served + return; +} + +TGeoVolume* V3Layer::createHalfBarrel() { const Int_t nameLen = 30; char volumeName[nameLen]; @@ -344,47 +374,40 @@ void V3Layer::createLayer(TGeoVolume* motherVolume) LOG(FATAL) << "Sensor thickness " << mSensorThickness << " is greater than chip thickness " << mChipThickness; } - // If a Turbo layer is requested, do it and exit - if (mIsTurbo) { - createLayerTurbo(motherVolume); - return; - } - // First create the stave container alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); // mStaveWidth = mLayerRadius*Tan(alpha); - snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); + snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSHalfBarrelPattern(), mLayerNumber); + TGeoVolume* halfBarrelVolume = new TGeoVolumeAssembly(volumeName); + halfBarrelVolume->SetUniqueID(mChipTypeID); - // layerVolume->SetVisibility(kFALSE); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); + // halfBarrelVolume->SetVisibility(kFALSE); + halfBarrelVolume->SetVisibility(kTRUE); + halfBarrelVolume->SetLineColor(1); TGeoVolume* stavVol = createStave(); // Now build up the layer alpha = 360. / mNumberOfStaves; Double_t r = mLayerRadius + (static_cast<TGeoBBox*>(stavVol->GetShape()))->GetDY(); - for (Int_t j = 0; j < mNumberOfStaves; j++) { + mHierarchy[kStave] = 0; + for (Int_t j = 0; j < mNumberOfStaves / 2; j++) { Double_t phi = j * alpha + mPhi0; xpos = r * cosD(phi); // r*sinD(-phi); ypos = r * sinD(phi); // r*cosD(-phi); zpos = 0.; phi += 90; - layerVolume->AddNode(stavVol, j, new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi, 0, 0))); + halfBarrelVolume->AddNode(stavVol, j, new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi, 0, 0))); + mHierarchy[kStave]++; } - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - // geometry is served - return; + return halfBarrelVolume; } -void V3Layer::createLayerTurbo(TGeoVolume* motherVolume) +TGeoVolume* V3Layer::createHalfBarrelTurbo() { const Int_t nameLen = 30; char volumeName[nameLen]; @@ -400,30 +423,29 @@ void V3Layer::createLayerTurbo(TGeoVolume* motherVolume) LOG(WARNING) << "Stave tilt angle (" << mStaveTilt << ") greater than 45deg"; } - snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); + snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSHalfBarrelPattern(), mLayerNumber); + TGeoVolume* halfBarrelVolume = new TGeoVolumeAssembly(volumeName); + halfBarrelVolume->SetUniqueID(mChipTypeID); + halfBarrelVolume->SetVisibility(kTRUE); + halfBarrelVolume->SetLineColor(1); TGeoVolume* stavVol = createStave(); // Now build up the layer alpha = 360. / mNumberOfStaves; Double_t r = mLayerRadius /* +chip thick ?! */; - for (Int_t j = 0; j < mNumberOfStaves; j++) { + mHierarchy[kStave] = 0; + for (Int_t j = 0; j < mNumberOfStaves / 2; j++) { Double_t phi = j * alpha + mPhi0; xpos = r * cosD(phi); // r*sinD(-phi); ypos = r * sinD(phi); // r*cosD(-phi); zpos = 0.; phi += 90; - layerVolume->AddNode(stavVol, j, - new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi - mStaveTilt, 0, 0))); + halfBarrelVolume->AddNode(stavVol, j, + new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi - mStaveTilt, 0, 0))); + mHierarchy[kStave]++; } - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - - return; + return halfBarrelVolume; } TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) @@ -447,12 +469,13 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) // Updated: 16 Mar 2017 Mario Sitta AliceO2 version // Updated: 10 Jan 2018 Mario Sitta Compute all dimensions using // AlpideChip as basis + // Updated: 10 Mar 2021 Mario Sitta Get rid of fake IB HS and Module // const Int_t nameLen = 30; char volumeName[nameLen]; - Double_t xpos, ypos; + Double_t xpos, ypos, ymod; Double_t alpha; // First create all needed shapes @@ -468,15 +491,15 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) // Now build up the stave if (mLayerNumber < sNumberOfInnerLayers) { - TGeoVolume* modVol = createStaveInnerB(); - ypos = (static_cast<TGeoBBox*>(modVol->GetShape()))->GetDY() - mChipThickness; // = 0 if not kIBModel4 - staveVol->AddNode(modVol, 0, new TGeoTranslation(0, ypos, 0)); - mHierarchy[kHalfStave] = 1; + ymod = createStaveInnerB(staveVol); + ypos = ymod - mChipThickness; // = 0 if not kIBModel4 + mHierarchy[kHalfStave] = 0; + mHierarchy[kModule] = 0; // Mechanical stave structure mechStaveVol = createStaveStructInnerB(); if (mechStaveVol) { - ypos = (static_cast<TGeoBBox*>(modVol->GetShape()))->GetDY() - ypos; + ypos = ymod - ypos; if (mStaveModel != Detector::kIBModel4) { ypos += (static_cast<TGeoBBox*>(mechStaveVol->GetShape()))->GetDY(); } @@ -511,36 +534,7 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) return staveVol; } -TGeoVolume* V3Layer::createStaveInnerB(const TGeoManager* mgr) -{ - Double_t xmod, ymod, zmod; - const Int_t nameLen = 30; - char volumeName[nameLen]; - - // First we create the module (i.e. the HIC with 9 chips) - TGeoVolume* moduleVol = createModuleInnerB(); - - // Then we create the fake halfstave and the actual stave - xmod = (static_cast<TGeoBBox*>(moduleVol->GetShape()))->GetDX(); - ymod = (static_cast<TGeoBBox*>(moduleVol->GetShape()))->GetDY(); - zmod = (static_cast<TGeoBBox*>(moduleVol->GetShape()))->GetDZ(); - - TGeoBBox* hstave = new TGeoBBox(xmod, ymod, zmod); - - TGeoMedium* medAir = mgr->GetMedium("ITS_AIR$"); - - snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - TGeoVolume* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); - - // Finally build it up - hstaveVol->AddNode(moduleVol, 0); - mHierarchy[kModule] = 1; - - // Done, return the stave structure - return hstaveVol; -} - -TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) +Double_t V3Layer::createStaveInnerB(TGeoVolume* mother, const TGeoManager* mgr) { Double_t xtot, ytot, ztot, xchip, zchip, ymod; Double_t xpos, ypos, zpos; @@ -568,7 +562,61 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) mIBModuleZLength = 2 * zchip * sIBChipsPerRow + (sIBChipsPerRow - 1) * sIBChipZGap; - // Then create the Glue, the Kapton and the two Aluminum cables + xtot = xchip + (sIBFPCWiderXPlus + sIBFPCWiderXNeg) / 2; + ztot = mIBModuleZLength / 2; + + // Then create all other elements (glue and FPC) + TGeoVolume* ibModule = createModuleInnerB(xchip, zchip); + + // Build up the stave + // Chips are rotated by 180deg around Y axis + // in order to have the correct X and Z axis orientation + xpos = -xtot + (static_cast<TGeoBBox*>(chipVol->GetShape()))->GetDX() + sIBFPCWiderXNeg; + ypos = ymod - mChipThickness; + + for (Int_t j = 0; j < sIBChipsPerRow; j++) { + zpos = ztot - j * (2 * zchip + sIBChipZGap) - zchip; + mother->AddNode(chipVol, j, new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", 0, 180, 180))); + mHierarchy[kChip]++; + } + ytot = ymod; + + // Place the FPC and glue + if (mStaveModel == Detector::kIBModel4) { + Double_t yvol = (static_cast<TGeoBBox*>(ibModule->GetShape()))->GetDY(); + ypos += (ymod + yvol); + mother->AddNode(ibModule, 1, new TGeoTranslation(0, ypos, 0)); + ytot += yvol; + } + + // Done, return the total thickness (used to properly place the services) + return ytot; +} + +TGeoVolume* V3Layer::createModuleInnerB(const Double_t xchip, const Double_t zchip, const TGeoManager* mgr) +{ + // + // Creates the FPC and glue volumes + // (zimilar to previous method, except the Chips) + // + // Input: + // xchip : the Chip width + // zchip : the Chip length + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // the module as a TGeoVolume + // + // Updated: 03 Apr 2021 + + Double_t xtot, ytot, ztot; + Double_t xpos, ypos, zpos; + const Int_t nameLen = 30; + char volumeName[nameLen]; + + // Create the Glue, the Kapton and the two Aluminum cables xtot = xchip + (sIBFPCWiderXPlus + sIBFPCWiderXNeg) / 2; ztot = mIBModuleZLength / 2; @@ -578,15 +626,11 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) TGeoVolume* aluGndCableVol = createIBFPCAlGnd(xtot, ztot); TGeoVolume* aluAnodeCableVol = createIBFPCAlAnode(xtot, ztot); - // Finally create the module and populate it with the chips - // (and the FPC Kapton and Aluminum in the most recent IB model) + // Then create the module volume Double_t ygnd = (static_cast<TGeoBBox*>(aluGndCableVol->GetShape()))->GetDY(); Double_t yano = (static_cast<TGeoBBox*>(aluAnodeCableVol->GetShape()))->GetDY(); - ytot = ymod; - if (mStaveModel == Detector::kIBModel4) { - ytot += (sIBGlueThick / 2 + ygnd + sIBFlexCableKapThick / 2 + yano + sIBFlexCapacitorYHi / 2); - } + ytot = sIBGlueThick / 2 + ygnd + sIBFlexCableKapThick / 2 + yano + sIBFlexCapacitorYHi / 2; TGeoBBox* module = new TGeoBBox(xtot, ytot, ztot); @@ -595,7 +639,7 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) TGeoMedium* medKapton = mgr->GetMedium("ITS_KAPTON(POLYCH2)$"); TGeoMedium* medGlue = mgr->GetMedium("ITS_GLUE_IBFPC$"); - snprintf(volumeName, nameLen, "%s%d", GeometryTGeo::getITSModulePattern(), mLayerNumber); + snprintf(volumeName, nameLen, "ServicesContainer%d", mLayerNumber); TGeoVolume* modVol = new TGeoVolume(volumeName, module, medAir); TGeoVolume* glueVol = new TGeoVolume("FPCGlue", glue, medGlue); @@ -607,35 +651,24 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) kapCableVol->SetFillColor(kBlue); // Build up the module - // Chips are rotated by 180deg around Y axis - // in order to have the correct X and Z axis orientation - xpos = -xtot + (static_cast<TGeoBBox*>(chipVol->GetShape()))->GetDX() + sIBFPCWiderXNeg; - ypos = -ytot + ymod; // = 0 if not kIBModel4 - for (Int_t j = 0; j < sIBChipsPerRow; j++) { - zpos = ztot - j * (2 * zchip + sIBChipZGap) - zchip; - modVol->AddNode(chipVol, j, new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", 0, 180, 180))); - mHierarchy[kChip]++; + xpos = -xtot + xchip + sIBFPCWiderXNeg; + ypos = -ytot + glue->GetDY(); + if (mBuildLevel < 2) { // Glue + modVol->AddNode(glueVol, 1, new TGeoTranslation(xpos, ypos, 0)); } + ypos += glue->GetDY(); - if (mStaveModel == Detector::kIBModel4) { - ypos += (ymod + glue->GetDY()); - if (mBuildLevel < 2) { // Glue - modVol->AddNode(glueVol, 1, new TGeoTranslation(xpos, ypos, 0)); - } - ypos += glue->GetDY(); - - if (mBuildLevel < 4) { // Kapton - ypos += ygnd; - modVol->AddNode(aluGndCableVol, 1, new TGeoTranslation(0, ypos, 0)); + if (mBuildLevel < 4) { // Kapton + ypos += ygnd; + modVol->AddNode(aluGndCableVol, 1, new TGeoTranslation(0, ypos, 0)); - ypos += (ygnd + kapCable->GetDY()); - modVol->AddNode(kapCableVol, 1, new TGeoTranslation(0, ypos, 0)); + ypos += (ygnd + kapCable->GetDY()); + modVol->AddNode(kapCableVol, 1, new TGeoTranslation(0, ypos, 0)); - ypos += (kapCable->GetDY() + yano); - modVol->AddNode(aluAnodeCableVol, 1, new TGeoTranslation(0, ypos, 0)); + ypos += (kapCable->GetDY() + yano); + modVol->AddNode(aluAnodeCableVol, 1, new TGeoTranslation(0, ypos, 0)); - ypos += yano; - } + ypos += yano; } // Add the capacitors @@ -1827,7 +1860,7 @@ TGeoVolume* V3Layer::createStaveModelOuterB2(const TGeoManager* mgr) Double_t yGraph = sOBGraphiteFoilThick; Double_t xHalfSt, yHalfSt; - Double_t xmod, ymod, zmod, ypowbus; + Double_t xmod, ymod, zmod, ypowbus, zbias; Double_t xtru[12], ytru[12]; Double_t xpos, ypos, ypos1, zpos /*, zpos5cm*/; Double_t xlen, ylen, zlen; @@ -2051,13 +2084,17 @@ TGeoVolume* V3Layer::createStaveModelOuterB2(const TGeoManager* mgr) // flex1_5cmVol->SetLineColor(kRed); // flex2_5cmVol->SetLineColor(kGreen); + // Compute starting Z pos to center modules in stave + // (no need to divide by 2, these are already half-lengths) + zbias = zlen - mNumberOfModules * zmod - (mNumberOfModules - 1) * 0.5 * sOBModuleGap; + // Now build up the half stave ypos = -ypowbus; halfStaveVol->AddNode(powerBusVol, 1, new TGeoTranslation(0, ypos, 0)); ypos -= (ypowbus + ymod); for (Int_t j = 0; j < mNumberOfModules; j++) { - zpos = zlen - j * (2 * zmod + sOBModuleGap) - zmod; + zpos = zlen - zbias - j * (2 * zmod + sOBModuleGap) - zmod; halfStaveVol->AddNode(moduleVol, j, new TGeoTranslation(0, ypos, zpos)); mHierarchy[kModule]++; } diff --git a/Detectors/ITSMFT/ITS/simulation/src/V3Services.cxx b/Detectors/ITSMFT/ITS/simulation/src/V3Services.cxx index 38294eb0ca47f..affe3eefaef9b 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V3Services.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V3Services.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -291,6 +292,28 @@ void V3Services::createOBConeSideC(TGeoVolume* mother, const TGeoManager* mgr) obConeSideC(mother, mgr); } +void V3Services::createOBCYSSCylinder(TGeoVolume* mother, const TGeoManager* mgr) +{ + // + // Creates the Outer Barrel CYSS Cylinder + // Volume and method names correspond to element names in blueprints + // + // Input: + // mother : the volume hosting the cones + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // + // Created: 02 Mar 2020 Mario Sitta + // + + TGeoVolumeAssembly* cyss = new TGeoVolumeAssembly("CYSS"); + + obCYSS11(mother, mgr); +} + void V3Services::ibEndWheelSideA(const Int_t iLay, TGeoVolume* endWheel, const TGeoManager* mgr) { // @@ -610,8 +633,8 @@ void V3Services::ibEndWheelSideC(const Int_t iLay, TGeoVolume* endWheel, const T static const Double_t sEndWCStepHoleZdist = 4.0 * sMm; static const Double_t sEndWCStepHolePhi[3] = {30.0, 22.5, 18.0}; // Deg - static const Double_t sEndWCStepHolePhi0[2] = {9.5, 10.5}; // Deg - static const Double_t sEndWCStepYlow = 7.0 * sMm; + static const Double_t sEndWCStepHolePhi0[2] = {9.5, 10.5}; // Deg - Lay 1-2 + static const Double_t sEndWCStepYlow = 7.0 * sMm; // Lay 0 only // Local variables Double_t xlen, ylen, zlen; @@ -740,7 +763,11 @@ void V3Services::ibEndWheelSideC(const Int_t iLay, TGeoVolume* endWheel, const T endWheel->AddNode(endWheelCVol, 1, new TGeoCombiTrans(0, 0, -zpos, new TGeoRotation("", 0, 180, 0))); // The position of the Steps is given wrt the holes (see eg. ALIITSUP0187) - dphi = sEndWCStepHolePhi0[iLay]; + if (iLay == 0) { + dphi = (sEndWCStepYlow / sEndWCStepYdispl[iLay]) * TMath::RadToDeg(); + } else { + dphi = sEndWCStepHolePhi0[iLay - 1]; + } Int_t numberOfStaves = GeometryTGeo::Instance()->getNumberOfStaves(iLay); zpos += (static_cast<TGeoBBox*>(stepCVol->GetShape()))->GetDZ(); @@ -1776,7 +1803,7 @@ void V3Services::mbEndWheelSideC(const Int_t iLay, TGeoVolume* mother, const TGe ringUpperVol->SetFillColor(kBlue); ringUpperVol->SetLineColor(kBlue); - TGeoVolume* shelfVol = new TGeoVolume(Form("OBEndWheelAShelf%d", nLay), shelfSh, medCarbon); + TGeoVolume* shelfVol = new TGeoVolume(Form("OBEndWheelCShelf%d", nLay), shelfSh, medCarbon); shelfVol->SetFillColor(kBlue); shelfVol->SetLineColor(kBlue); @@ -2352,3 +2379,116 @@ void V3Services::obConeSideC(TGeoVolume* mother, const TGeoManager* mgr) mother->AddNode(obConeRibVol, 3, new TGeoCombiTrans(xpos, ypos, -zpos, new TGeoRotation("", 0, -90, 0))); mother->AddNode(obConeRibVol, 4, new TGeoCombiTrans(-xpos, -ypos, -zpos, new TGeoRotation("", 0, 90, 180))); } + +void V3Services::obCYSS11(TGeoVolume* mother, const TGeoManager* mgr) +{ + // + // Creates the CYSS element 11 with all its sub-elements + // OB CYSS 11 : ALIITSUP0564 (the whole assembly) + // OB CYSS 12 : ALIITSUP0565 (the outermost cylinder) + // OB CYSS 13 : ALIITSUP0566 (the intermediate cylinder) + // OB CYSS 14 : ALIITSUP0567 (the innermost cylinder) + // + // Input: + // mother : the volume where to place the current created cylinder + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // + // Created: 02 Mar 2020 Mario Sitta + // + + static const Double_t sOBCYSS14Zlen = 1556.8 * sMm; + static const Double_t sOBCYSS14DInt = 898.0 * sMm; + static const Double_t sOBCYSS14DExt = 900.5 * sMm; + static const Double_t sOBCYSS14PhiCut = 4.0 * sMm; + + static const Double_t sOBCYSS13Zlen = 1481.0 * sMm; + static const Double_t sOBCYSS13DInt = sOBCYSS14DExt; + static const Double_t sOBCYSS13DExt = 915.5 * sMm; + static const Double_t sOBCYSS13PhiCut = 10.55 * sMm; + + static const Double_t sOBCYSS12Zlen = 1520.6 * sMm; + static const Double_t sOBCYSS12DInt = sOBCYSS13DExt; + static const Double_t sOBCYSS12DExt = 918.0 * sMm; + static const Double_t sOBCYSS12PhiCut = 4.0 * sMm; + + static const Double_t sOBCYSS20Zlen = 1500.6 * sMm; + static const Double_t sOBCYSS20Width = 7.1 * sMm; + static const Double_t sOBCYSS20Height = 6.35 * sMm; + + // Local variables + Double_t rmin, rmax, phi; + Double_t xpos, ypos, zpos; + + // The OB CYSS is made by three cylinders plus other elements + // (rings, bars, etc) fixed together + + // The three cylinders + rmin = sOBCYSS14DInt / 2; + rmax = sOBCYSS14DExt / 2; + + phi = sOBCYSS14PhiCut / rmin; + phi *= TMath::RadToDeg(); + + TGeoTubeSeg* obCyss14Sh = new TGeoTubeSeg(rmin, rmax, sOBCYSS14Zlen / 2, phi, 180. - phi); + + // + rmin = sOBCYSS13DInt / 2; + rmax = sOBCYSS13DExt / 2; + + phi = sOBCYSS13PhiCut / rmin; + phi *= TMath::RadToDeg(); + + TGeoTubeSeg* obCyss13Sh = new TGeoTubeSeg(rmin, rmax, sOBCYSS13Zlen / 2, phi, 180. - phi); + + // + rmin = sOBCYSS12DInt / 2; + rmax = sOBCYSS12DExt / 2; + + phi = sOBCYSS12PhiCut / rmin; + phi *= TMath::RadToDeg(); + + TGeoTubeSeg* obCyss12Sh = new TGeoTubeSeg(rmin, rmax, sOBCYSS12Zlen / 2, phi, 180. - phi); + + // The middle bar + TGeoBBox* obCyss20Sh = new TGeoBBox(sOBCYSS20Width / 2, sOBCYSS20Height / 2, sOBCYSS20Zlen / 2); + + // We have all shapes: now create the real volumes + TGeoMedium* medCarbon = mgr->GetMedium("ITS_M55J6K$"); // TO BE CHECKED + + TGeoVolume* obCyss14Vol = new TGeoVolume("OBCYSS14", obCyss14Sh, medCarbon); + obCyss14Vol->SetFillColor(kBlue); + obCyss14Vol->SetLineColor(kBlue); + + TGeoVolume* obCyss13Vol = new TGeoVolume("OBCYSS13", obCyss13Sh, medCarbon); + obCyss13Vol->SetFillColor(kBlue); + obCyss13Vol->SetLineColor(kBlue); + + TGeoVolume* obCyss12Vol = new TGeoVolume("OBCYSS12", obCyss12Sh, medCarbon); + obCyss12Vol->SetFillColor(kBlue); + obCyss12Vol->SetLineColor(kBlue); + + TGeoVolume* obCyss20Vol = new TGeoVolume("OBCYSS20", obCyss20Sh, medCarbon); + obCyss20Vol->SetFillColor(kYellow); + obCyss20Vol->SetLineColor(kYellow); + + // Finally put everything in the mother volume + mother->AddNode(obCyss14Vol, 1, nullptr); + mother->AddNode(obCyss14Vol, 2, new TGeoRotation("", 180, 0, 0)); + + mother->AddNode(obCyss13Vol, 1, nullptr); + mother->AddNode(obCyss13Vol, 2, new TGeoRotation("", 180, 0, 0)); + + mother->AddNode(obCyss12Vol, 1, nullptr); + mother->AddNode(obCyss12Vol, 2, new TGeoRotation("", 180, 0, 0)); + + xpos = (obCyss13Sh->GetRmin() + obCyss13Sh->GetRmax()) / 2; + ypos = sOBCYSS13PhiCut - obCyss20Sh->GetDY(); + mother->AddNode(obCyss20Vol, 1, new TGeoTranslation(xpos, ypos, 0)); + mother->AddNode(obCyss20Vol, 2, new TGeoTranslation(-xpos, ypos, 0)); + mother->AddNode(obCyss20Vol, 3, new TGeoTranslation(xpos, -ypos, 0)); + mother->AddNode(obCyss20Vol, 4, new TGeoTranslation(-xpos, -ypos, 0)); +} diff --git a/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx b/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx index 539165a1db713..6e958cc78e48e 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,11 +14,11 @@ #include <boost/program_options.hpp> #include <TTree.h> -#include <TSystem.h> #include <TChain.h> #include <TFile.h> #include <TStopwatch.h> #include "Framework/Logger.h" +#include <filesystem> #include <vector> #include <string> #include <iomanip> @@ -58,10 +59,11 @@ int main(int argc, char** argv) add_option("help,h", "Print this help message"); add_option("verbosity,v", bpo::value<uint32_t>()->default_value(0), "verbosity level [0 = no output]"); add_option("input-file,i", bpo::value<std::string>()->default_value("itsdigits.root"), "input ITS digits file"); - add_option("file-for,f", bpo::value<std::string>()->default_value("layer"), "single file per: all,layer,cru,link"); + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,flp,cru,link"); add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(DefRDHVersion), "RDH version to use"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); opt_all.add(opt_general).add(opt_hidden); @@ -82,6 +84,11 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); digi2raw(vm["input-file"].as<std::string>(), vm["output-dir"].as<std::string>(), @@ -89,6 +96,9 @@ int main(int argc, char** argv) vm["verbosity"].as<uint32_t>(), vm["rdh-version"].as<uint32_t>(), vm["no-empty-hbf"].as<bool>()); + LOG(INFO) << "HBFUtils settings used for conversion:"; + + o2::raw::HBFUtils::Instance().print(); return 0; } @@ -105,13 +115,14 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie o2::raw::HBFUtils::Instance().print(); // if needed, create output directory - if (gSystem->AccessPathName(outDir.data())) { - if (gSystem->mkdir(outDir.data(), kTRUE)) { + if (!std::filesystem::exists(outDir)) { + if (!std::filesystem::create_directories(outDir)) { LOG(FATAL) << "could not create output directory " << outDir; } else { LOG(INFO) << "created output directory " << outDir; } } + ///-------> input std::string digTreeName{o2::base::NameConf::MCTTREENAME.data()}; TChain digTree(digTreeName.c_str()); @@ -119,7 +130,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie digTree.SetBranchStatus("*MCTruth*", 0); // ignore MC info std::vector<o2::itsmft::Digit> digiVec, *digiVecP = &digiVec; - std::string digBranchName = o2::utils::concat_string(MAP::getName(), "Digit"); + std::string digBranchName = o2::utils::Str::concat_string(MAP::getName(), "Digit"); if (!digTree.GetBranch(digBranchName.c_str())) { LOG(FATAL) << "Failed to find the branch " << digBranchName << " in the tree " << digTreeName; } @@ -127,7 +138,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie // ROF record entries in the digit tree ROFRVEC rofRecVec, *rofRecVecP = &rofRecVec; - std::string rofRecName = o2::utils::concat_string(MAP::getName(), "DigitROF"); + std::string rofRecName = o2::utils::Str::concat_string(MAP::getName(), "DigitROF"); if (!digTree.GetBranch(rofRecName.c_str())) { LOG(FATAL) << "Failed to find the branch " << rofRecName << " in the tree " << digTreeName; } @@ -139,7 +150,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie o2::itsmft::MC2RawEncoder<MAP> m2r; m2r.setVerbosity(verbosity); m2r.setContinuousReadout(grp->isDetContinuousReadOut(MAP::getDetID())); // must be set explicitly - m2r.setDefaultSinkName(o2::utils::concat_string(MAP::getName(), ".raw")); + m2r.setDefaultSinkName(o2::utils::Str::concat_string(MAP::getName(), ".raw")); m2r.setMinMaxRUSW(ruSWMin, ruSWMax); m2r.getWriter().setSuperPageSize(superPageSizeInB); m2r.getWriter().useRDHVersion(rdhV); @@ -170,13 +181,218 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie } } // loop over multiple ROFvectors (in case of chaining) - m2r.getWriter().writeConfFile(MAP::getName(), "RAWDATA", o2::utils::concat_string(outDir, '/', MAP::getName(), "raw.cfg")); + m2r.getWriter().writeConfFile(MAP::getName(), "RAWDATA", o2::utils::Str::concat_string(outDir, '/', MAP::getName(), "raw.cfg")); m2r.finalize(); // finish TF and flush data // swTot.Stop(); swTot.Print(); } +struct ITSRUMapping { + std::string flp{}; + int cruHWID = 0; + int layer = 0; + int gbtChannel = 0; + int ruHWID = 0; + int ruInLayer = 0; +}; + +// FLP, CRU_HW, Lr, GBT, RU_HW, RUID_in_layer +const ITSRUMapping itsHWMap[o2::itsmft::ChipMappingITS::getNRUs()] = + { + {"alio2-cr1-flp187", 183, 0, 0, 28, 0}, + {"alio2-cr1-flp187", 183, 0, 1, 42, 1}, + {"alio2-cr1-flp187", 183, 0, 2, 122, 2}, + {"alio2-cr1-flp187", 183, 0, 3, 94, 3}, + {"alio2-cr1-flp187", 183, 0, 4, 49, 4}, + {"alio2-cr1-flp187", 183, 0, 5, 52, 5}, + {"alio2-cr1-flp187", 172, 0, 0, 187, 6}, + {"alio2-cr1-flp187", 172, 0, 1, 90, 7}, + {"alio2-cr1-flp187", 172, 0, 2, 102, 8}, + {"alio2-cr1-flp187", 172, 0, 3, 134, 9}, + {"alio2-cr1-flp187", 172, 0, 4, 127, 10}, + {"alio2-cr1-flp187", 172, 0, 5, 259, 11}, + {"alio2-cr1-flp188", 181, 1, 0, 54, 0}, + {"alio2-cr1-flp188", 181, 1, 1, 59, 1}, + {"alio2-cr1-flp188", 181, 1, 2, 61, 2}, + {"alio2-cr1-flp188", 181, 1, 3, 62, 3}, + {"alio2-cr1-flp188", 181, 1, 4, 167, 4}, + {"alio2-cr1-flp188", 181, 1, 5, 66, 5}, + {"alio2-cr1-flp188", 181, 1, 6, 64, 6}, + {"alio2-cr1-flp188", 181, 1, 7, 120, 7}, + {"alio2-cr1-flp188", 196, 1, 0, 199, 8}, + {"alio2-cr1-flp188", 196, 1, 1, 201, 9}, + {"alio2-cr1-flp188", 196, 1, 2, 212, 10}, + {"alio2-cr1-flp188", 196, 1, 3, 217, 11}, + {"alio2-cr1-flp188", 196, 1, 4, 230, 12}, + {"alio2-cr1-flp188", 196, 1, 5, 242, 13}, + {"alio2-cr1-flp188", 196, 1, 6, 244, 14}, + {"alio2-cr1-flp188", 196, 1, 7, 250, 15}, + {"alio2-cr1-flp189", 184, 2, 0, 63, 0}, + {"alio2-cr1-flp189", 184, 2, 1, 58, 1}, + {"alio2-cr1-flp189", 184, 2, 2, 44, 2}, + {"alio2-cr1-flp189", 184, 2, 3, 46, 3}, + {"alio2-cr1-flp189", 184, 2, 4, 50, 4}, + {"alio2-cr1-flp189", 191, 2, 0, 51, 5}, + {"alio2-cr1-flp189", 191, 2, 1, 219, 6}, + {"alio2-cr1-flp189", 191, 2, 2, 21, 7}, + {"alio2-cr1-flp189", 191, 2, 3, 29, 8}, + {"alio2-cr1-flp189", 191, 2, 4, 35, 9}, + {"alio2-cr1-flp190", 179, 2, 0, 99, 10}, + {"alio2-cr1-flp190", 179, 2, 1, 93, 11}, + {"alio2-cr1-flp190", 179, 2, 2, 97, 12}, + {"alio2-cr1-flp190", 179, 2, 3, 45, 13}, + {"alio2-cr1-flp190", 179, 2, 4, 92, 14}, + {"alio2-cr1-flp190", 192, 2, 0, 96, 15}, + {"alio2-cr1-flp190", 192, 2, 1, 125, 16}, + {"alio2-cr1-flp190", 192, 2, 2, 169, 17}, + {"alio2-cr1-flp190", 192, 2, 3, 168, 18}, + {"alio2-cr1-flp190", 192, 2, 4, 188, 19}, + {"alio2-cr1-flp191", 175, 3, 0, 106, 0}, + {"alio2-cr1-flp191", 175, 3, 1, 304, 1}, + {"alio2-cr1-flp191", 175, 3, 2, 147, 2}, + {"alio2-cr1-flp191", 175, 3, 3, 222, 3}, + {"alio2-cr1-flp191", 175, 3, 4, 293, 4}, + {"alio2-cr1-flp191", 175, 3, 5, 200, 5}, + {"alio2-cr1-flp191", 175, 3, 6, 233, 6}, + {"alio2-cr1-flp191", 175, 3, 7, 43, 7}, + {"alio2-cr1-flp191", 175, 3, 8, 173, 8}, + {"alio2-cr1-flp191", 175, 3, 9, 172, 9}, + {"alio2-cr1-flp191", 175, 3, 10, 177, 10}, + {"alio2-cr1-flp191", 175, 3, 11, 175, 11}, + {"alio2-cr1-flp191", 182, 3, 0, 2, 12}, + {"alio2-cr1-flp191", 182, 3, 1, 215, 13}, + {"alio2-cr1-flp191", 182, 3, 2, 108, 14}, + {"alio2-cr1-flp191", 182, 3, 3, 265, 15}, + {"alio2-cr1-flp191", 182, 3, 4, 241, 16}, + {"alio2-cr1-flp191", 182, 3, 5, 53, 17}, + {"alio2-cr1-flp191", 182, 3, 6, 183, 18}, + {"alio2-cr1-flp191", 182, 3, 7, 7, 19}, + {"alio2-cr1-flp191", 182, 3, 8, 191, 20}, + {"alio2-cr1-flp191", 182, 3, 9, 190, 21}, + {"alio2-cr1-flp191", 182, 3, 10, 284, 22}, + {"alio2-cr1-flp191", 182, 3, 11, 299, 23}, + {"alio2-cr1-flp192", 187, 4, 0, 273, 0}, + {"alio2-cr1-flp192", 187, 4, 1, 171, 1}, + {"alio2-cr1-flp192", 187, 4, 2, 252, 2}, + {"alio2-cr1-flp192", 187, 4, 3, 251, 3}, + {"alio2-cr1-flp192", 187, 4, 4, 202, 4}, + {"alio2-cr1-flp192", 187, 4, 5, 282, 5}, + {"alio2-cr1-flp192", 187, 4, 6, 181, 6}, + {"alio2-cr1-flp192", 187, 4, 7, 300, 7}, + {"alio2-cr1-flp192", 176, 4, 0, 302, 8}, + {"alio2-cr1-flp192", 176, 4, 1, 309, 9}, + {"alio2-cr1-flp192", 176, 4, 2, 270, 10}, + {"alio2-cr1-flp192", 176, 4, 3, 255, 11}, + {"alio2-cr1-flp192", 176, 4, 4, 203, 12}, + {"alio2-cr1-flp192", 176, 4, 5, 208, 13}, + {"alio2-cr1-flp192", 176, 4, 6, 277, 14}, + {"alio2-cr1-flp193", 177, 4, 0, 105, 23}, + {"alio2-cr1-flp193", 177, 4, 1, 258, 24}, + {"alio2-cr1-flp193", 177, 4, 2, 121, 25}, + {"alio2-cr1-flp193", 177, 4, 3, 119, 26}, + {"alio2-cr1-flp193", 177, 4, 4, 116, 27}, + {"alio2-cr1-flp193", 177, 4, 5, 135, 28}, + {"alio2-cr1-flp193", 177, 4, 6, 126, 29}, + {"alio2-cr1-flp193", 178, 4, 0, 137, 15}, + {"alio2-cr1-flp193", 178, 4, 1, 229, 16}, + {"alio2-cr1-flp193", 178, 4, 2, 272, 17}, + {"alio2-cr1-flp193", 178, 4, 3, 148, 18}, + {"alio2-cr1-flp193", 178, 4, 4, 297, 19}, + {"alio2-cr1-flp193", 178, 4, 5, 253, 20}, + {"alio2-cr1-flp193", 178, 4, 6, 84, 21}, + {"alio2-cr1-flp193", 178, 4, 7, 279, 22}, + {"alio2-cr1-flp194", 194, 5, 0, 132, 0}, + {"alio2-cr1-flp194", 194, 5, 1, 225, 1}, + {"alio2-cr1-flp194", 194, 5, 2, 240, 2}, + {"alio2-cr1-flp194", 194, 5, 3, 266, 3}, + {"alio2-cr1-flp194", 194, 5, 4, 128, 4}, + {"alio2-cr1-flp194", 194, 5, 5, 123, 5}, + {"alio2-cr1-flp194", 194, 5, 6, 170, 6}, + {"alio2-cr1-flp194", 194, 5, 7, 234, 7}, + {"alio2-cr1-flp194", 194, 5, 8, 320, 8}, + {"alio2-cr1-flp194", 194, 5, 9, 186, 9}, + {"alio2-cr1-flp194", 174, 5, 0, 245, 10}, + {"alio2-cr1-flp194", 174, 5, 1, 192, 11}, + {"alio2-cr1-flp194", 174, 5, 2, 206, 12}, + {"alio2-cr1-flp194", 174, 5, 3, 189, 13}, + {"alio2-cr1-flp194", 174, 5, 4, 213, 14}, + {"alio2-cr1-flp194", 174, 5, 5, 6, 15}, + {"alio2-cr1-flp194", 174, 5, 6, 228, 16}, + {"alio2-cr1-flp194", 174, 5, 7, 136, 17}, + {"alio2-cr1-flp194", 174, 5, 8, 197, 18}, + {"alio2-cr1-flp194", 174, 5, 9, 82, 19}, + {"alio2-cr1-flp194", 174, 5, 10, 100, 20}, + {"alio2-cr1-flp195", 180, 5, 0, 246, 31}, + {"alio2-cr1-flp195", 180, 5, 1, 271, 32}, + {"alio2-cr1-flp195", 180, 5, 2, 281, 33}, + {"alio2-cr1-flp195", 180, 5, 3, 285, 34}, + {"alio2-cr1-flp195", 180, 5, 4, 287, 35}, + {"alio2-cr1-flp195", 180, 5, 5, 289, 36}, + {"alio2-cr1-flp195", 180, 5, 6, 113, 37}, + {"alio2-cr1-flp195", 180, 5, 7, 193, 38}, + {"alio2-cr1-flp195", 180, 5, 8, 194, 39}, + {"alio2-cr1-flp195", 180, 5, 9, 195, 40}, + {"alio2-cr1-flp195", 180, 5, 10, 198, 41}, + {"alio2-cr1-flp195", 193, 5, 0, 214, 21}, + {"alio2-cr1-flp195", 193, 5, 1, 207, 22}, + {"alio2-cr1-flp195", 193, 5, 2, 248, 23}, + {"alio2-cr1-flp195", 193, 5, 3, 262, 24}, + {"alio2-cr1-flp195", 193, 5, 4, 263, 25}, + {"alio2-cr1-flp195", 193, 5, 5, 65, 26}, + {"alio2-cr1-flp195", 193, 5, 6, 56, 27}, + {"alio2-cr1-flp195", 193, 5, 7, 1, 28}, + {"alio2-cr1-flp195", 193, 5, 8, 210, 29}, + {"alio2-cr1-flp195", 193, 5, 9, 247, 30}, + {"alio2-cr1-flp196", 185, 6, 0, 36, 0}, + {"alio2-cr1-flp196", 185, 6, 1, 60, 1}, + {"alio2-cr1-flp196", 185, 6, 2, 41, 2}, + {"alio2-cr1-flp196", 185, 6, 3, 40, 3}, + {"alio2-cr1-flp196", 185, 6, 4, 80, 4}, + {"alio2-cr1-flp196", 185, 6, 5, 57, 5}, + {"alio2-cr1-flp196", 185, 6, 6, 185, 6}, + {"alio2-cr1-flp196", 185, 6, 7, 79, 7}, + {"alio2-cr1-flp196", 185, 6, 8, 91, 8}, + {"alio2-cr1-flp196", 185, 6, 9, 78, 9}, + {"alio2-cr1-flp196", 185, 6, 10, 5, 10}, + {"alio2-cr1-flp196", 185, 6, 11, 306, 11}, + {"alio2-cr1-flp196", 189, 6, 0, 39, 12}, + {"alio2-cr1-flp196", 189, 6, 1, 32, 13}, + {"alio2-cr1-flp196", 189, 6, 2, 23, 14}, + {"alio2-cr1-flp196", 189, 6, 3, 24, 15}, + {"alio2-cr1-flp196", 189, 6, 4, 22, 16}, + {"alio2-cr1-flp196", 189, 6, 5, 88, 17}, + {"alio2-cr1-flp196", 189, 6, 6, 25, 18}, + {"alio2-cr1-flp196", 189, 6, 7, 89, 19}, + {"alio2-cr1-flp196", 189, 6, 8, 87, 20}, + {"alio2-cr1-flp196", 189, 6, 9, 47, 21}, + {"alio2-cr1-flp196", 189, 6, 10, 17, 22}, + {"alio2-cr1-flp196", 189, 6, 11, 33, 23}, + {"alio2-cr1-flp197", 186, 6, 0, 180, 36}, + {"alio2-cr1-flp197", 186, 6, 1, 274, 37}, + {"alio2-cr1-flp197", 186, 6, 2, 275, 38}, + {"alio2-cr1-flp197", 186, 6, 3, 278, 39}, + {"alio2-cr1-flp197", 186, 6, 4, 276, 40}, + {"alio2-cr1-flp197", 186, 6, 5, 160, 41}, + {"alio2-cr1-flp197", 186, 6, 6, 280, 42}, + {"alio2-cr1-flp197", 186, 6, 7, 3, 43}, + {"alio2-cr1-flp197", 186, 6, 8, 209, 44}, + {"alio2-cr1-flp197", 186, 6, 9, 227, 45}, + {"alio2-cr1-flp197", 186, 6, 10, 256, 46}, + {"alio2-cr1-flp197", 186, 6, 11, 15, 47}, + {"alio2-cr1-flp197", 195, 6, 0, 115, 24}, + {"alio2-cr1-flp197", 195, 6, 1, 283, 25}, + {"alio2-cr1-flp197", 195, 6, 2, 104, 26}, + {"alio2-cr1-flp197", 195, 6, 3, 290, 27}, + {"alio2-cr1-flp197", 195, 6, 4, 254, 28}, + {"alio2-cr1-flp197", 195, 6, 5, 110, 29}, + {"alio2-cr1-flp197", 195, 6, 6, 103, 30}, + {"alio2-cr1-flp197", 195, 6, 7, 286, 31}, + {"alio2-cr1-flp197", 195, 6, 8, 257, 32}, + {"alio2-cr1-flp197", 195, 6, 9, 174, 33}, + {"alio2-cr1-flp197", 195, 6, 10, 13, 34}, + {"alio2-cr1-flp197", 195, 6, 11, 288, 35}}; + void setupLinks(o2::itsmft::MC2RawEncoder<MAP>& m2r, std::string_view outDir, std::string_view outPrefix, std::string_view fileFor) { //------------------------------------------------------------------------------->>>> @@ -186,107 +402,65 @@ void setupLinks(o2::itsmft::MC2RawEncoder<MAP>& m2r, std::string_view outDir, st // during encoding. // If the links of the container are not defined, a single link readout will be assigned - constexpr int MaxLinksPerRU = 3; - constexpr int MaxLinksPerCRU = 16; const auto& mp = m2r.getMapping(); + constexpr int MaxLinksPerRU = 3; + auto getNLinks = [](int lr) { return lr < 3 ? MaxLinksPerRU : MaxLinksPerRU - 1; }; int lnkAssign[3][MaxLinksPerRU] = { // requested link cabling for IB, MB and OB - /* // uncomment this to have 1 link per RU - {9, 0, 0}, // IB - {16, 0, 0}, // MB - {28, 0, 0} // OB - */ - /* // uncomment this to have 3 link per RU - {3, 3, 3}, // IB - {5, 5, 6}, // MB - {9, 9, 10} // OB - */ - // partition according to https://indico.cern.ch/event/907685/contributions/3818967/attachments/2019436/3376161/20200411_SOX_EOX_Proposal.pdf - {3, 3, 3}, // IB - {8, 8, 0}, // MB - {14, 14, 0} // OB + {3, 3, 3}, // IB + {14, 14, 0}, // MB + {14, 14, 0} // OB }; - std::vector<std::vector<int>> defRU{// number of RUs per CRU at each layer - {6, 6}, - {8, 8}, - {5, 5, 5, 5}, - {12, 12}, - {8, 7, 8, 7}, - {11, 10, 11, 10}, - {12, 12, 12, 12}}; - // this is an arbitrary mapping - int nCRU = 0, nRUtot = 0, nRU = 0, nLinks = 0; - int cruID = 0; + std::unordered_map<int, int> cruMaxRU, cruNRU; + std::array<int, o2::itsmft::ChipMappingITS::getNRUs()> ruSWEntry{}; + ruSWEntry.fill(-1); + int ntab = sizeof(itsHWMap) / sizeof(ITSRUMapping); + for (int ir = 0; ir < ntab; ir++) { + const auto& ru = itsHWMap[ir]; + cruMaxRU[ru.cruHWID]++; + ruSWEntry[mp.getRUIDSW(ru.layer, ru.ruInLayer)] = ir; + } std::string outFileLink; - - for (int ilr = 0; ilr < mp.NLayers; ilr++) { - int nruLr = mp.getNStavesOnLr(ilr); - int ruType = mp.getRUType(nRUtot); // IB, MB or OB - int* lnkAs = lnkAssign[ruType]; - // count requested number of links per RU - int nlk = 0; - for (int i = 3; i--;) { - nlk += lnkAs[i] ? 1 : 0; - } - const auto& ruList = defRU[ilr]; - // sanity check - if (std::accumulate(ruList.begin(), ruList.end(), 0) != nruLr) { - throw std::runtime_error("Declared RU partitioning does not add up to expected N staves per layer"); + for (int ruID = 0; ruID < o2::itsmft::ChipMappingITS::getNRUs(); ruID++) { + const auto& ruhw = itsHWMap[ruSWEntry[ruID]]; + int nRUsOnCRU = cruMaxRU[ruhw.cruHWID], ruOnCRU = cruNRU[ruhw.cruHWID]++; + if (ruID < m2r.getRUSWMin() || ruID > m2r.getRUSWMax()) { // ignored RUs ? + continue; } - int ruInLr = 0; // counter for RUs within the layer - int nCRUlr = ruList.size(); - for (int iCRU = 0; iCRU < nCRUlr; iCRU++) { - cruID = nCRU * 100 + o2::detectors::DetID::ITS; - int linkID = 0; - for (int irc = 0; irc < ruList[iCRU]; irc++) { - int ruID = nRUtot++; - bool acceptRU = !(ruID < m2r.getRUSWMin() || ruID > m2r.getRUSWMax()); // ignored RUs ? - if (acceptRU) { - m2r.getCreateRUDecode(ruID); // create RU container - nRU++; - } - int accL = 0; - for (int il = 0; il < MaxLinksPerRU; il++) { // create links - if (acceptRU && lnkAs[il]) { - nLinks++; - auto& ru = *m2r.getRUDecode(ruID); - uint32_t lanes = mp.getCablesOnRUType(ru.ruInfo->ruType); // lanes pattern of this RU - ru.links[il] = m2r.addGBTLink(); - auto link = m2r.getGBTLink(ru.links[il]); - link->lanes = lanes & (((0x1 << lnkAs[il]) - 1) << (accL)); // RS FIXME - link->idInCRU = linkID; - link->cruID = cruID; - link->feeID = mp.RUSW2FEEId(ruID, il); - link->endPointID = 0; // 0 or 1 - accL += lnkAs[il]; - if (m2r.getVerbosity()) { - LOG(INFO) << "RU" << ruID << '(' << ruInLr << " on lr " << ilr << ") " << link->describe() - << " -> " << outFileLink; - } - // register the link in the writer, if not done here, its data will be dumped to common default file + m2r.getCreateRUDecode(ruID); // create RU container + int* lnkAs = lnkAssign[mp.getRUType(ruID)]; + int accL = 0; + for (int il = 0; il < getNLinks(ruhw.layer); il++) { // create links + auto& ru = *m2r.getRUDecode(ruID); + ru.links[il] = m2r.addGBTLink(); + uint32_t lanes = mp.getCablesOnRUType(mp.getRUType(ruID)); // lanes pattern of this RU + auto link = m2r.getGBTLink(ru.links[il]); + link->lanes = lanes & (((0x1 << lnkAs[il]) - 1) << (accL)); - if (fileFor == "all") { // single file for all links - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, ".raw"); - } else if (fileFor == "layer") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_lr", std::to_string(ilr), ".raw"); - } else if (fileFor == "cru") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(cruID), ".raw"); - } else if (fileFor == "link") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(cruID), - "_link", std::to_string(linkID), "_ep", std::to_string(link->endPointID), - "_feeid", std::to_string(link->feeID), ".raw"); - } else { + link->idInCRU = ruOnCRU + il * nRUsOnCRU; // linkID + link->cruID = ruhw.cruHWID; + link->feeID = mp.RUSW2FEEId(ruID, il); + link->endPointID = link->idInCRU > 11 ? 1 : 0; + accL += lnkAs[il]; + outFileLink = o2::utils::Str::concat_string(outDir, "/", outPrefix); + if (fileFor != "all") { // single file for all links + outFileLink += fmt::format("_{}", ruhw.flp); + if (fileFor != "flp") { + outFileLink += fmt::format("_cru{}_{}", ruhw.cruHWID, link->endPointID); + if (fileFor != "cru") { + outFileLink += fmt::format("_lnk{}_feeid{}", link->idInCRU, link->feeID); + if (fileFor != "link") { throw std::runtime_error("invalid option provided for file grouping"); } - m2r.getWriter().registerLink(link->feeID, link->cruID, link->idInCRU, link->endPointID, outFileLink); - // - linkID++; } - } // links of RU - ruInLr++; - } // RUs of CRU - nCRU++; - } // CRUs of the layer - } // layers - LOG(INFO) << "Distributed " << nLinks << " links on " << nRU << " RUs in " << nCRU << " CRUs"; + } + } + outFileLink += ".raw"; + m2r.getWriter().registerLink(link->feeID, link->cruID, link->idInCRU, link->endPointID, outFileLink); + if (m2r.getVerbosity()) { + LOG(INFO) << "RU" << ruID << '(' << ruhw.ruInLayer << " on lr " << ruhw.layer << ") " << link->describe() + << " -> " << outFileLink; + } + } + } } diff --git a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt index 5465d25b3ab33..bf7dcd8bf1364 100644 --- a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt @@ -1,20 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITStracking TARGETVARNAME targetName SOURCES src/ClusterLines.cxx src/Cluster.cxx src/ROframe.cxx - src/Graph.cxx - src/DBScan.cxx + src/TimeFrame.cxx src/IOUtils.cxx src/Label.cxx src/PrimaryVertexContext.cxx @@ -26,8 +26,9 @@ o2_add_library(ITStracking src/ClusterLines.cxx src/Vertexer.cxx src/VertexerTraits.cxx + src/Smoother.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon - ms_gsl::ms_gsl + Microsoft.GSL::GSL O2::CommonConstants O2::DataFormatsITSMFT O2::SimulationDataFormat @@ -37,15 +38,11 @@ o2_add_library(ITStracking o2_target_root_dictionary(ITStracking HEADERS include/ITStracking/ClusterLines.h include/ITStracking/Tracklet.h - include/ITStracking/DBScan.h + include/ITStracking/Cluster.h include/ITStracking/TrackingConfigParam.h + include/ITStracking/StandaloneDebugger.h LINKDEF src/TrackingLinkDef.h) -if(CUDA_ENABLED) - add_subdirectory(cuda) - target_compile_definitions(${targetName} PRIVATE CUDA_ENABLED) -endif() -if(HIP_ENABLED) - add_subdirectory(hip) - target_compile_definitions(${targetName} PRIVATE HIP_ENABLED) +if(CUDA_ENABLED OR HIP_ENABLED) + add_subdirectory(GPU) endif() diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/CMakeLists.txt new file mode 100644 index 0000000000000..1a5f330df2006 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +# +# CUDA +if(CUDA_ENABLED) +add_subdirectory(cuda) +endif() + +# HIP +if(HIP_ENABLED) +add_subdirectory(hip) +endif() \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h new file mode 100644 index 0000000000000..c5e1ddfcbcb2c --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Array.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_ARRAY_H_ +#define ITSTRACKINGGPU_ARRAY_H_ + +#include "GPUCommonDef.h" +#ifdef __HIPCC__ +#include <hip/hip_runtime.h> +#endif + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +namespace +{ +template <typename T, size_t Size> +struct ArrayTraits final { + typedef T InternalArray[Size]; + + GPUhd() static constexpr T& getReference(const InternalArray& internalArray, size_t index) noexcept + { + return const_cast<T&>(internalArray[index]); + } + + GPUhd() static constexpr T* getPointer(const InternalArray& internalArray) noexcept + { + return const_cast<T*>(internalArray); + } +}; +} // namespace + +template <typename T, size_t Size> +struct Array final { + + void copy(const Array<T, Size>& t) + { +#ifdef __OPENCL__ + for (size_t i{0}; i < Size; ++i) { + InternalArray[i] = t[i]; + } +#else + memcpy(InternalArray, t.data(), Size * sizeof(T)); +#endif + } + + GPUhd() T* data() noexcept { return const_cast<T*>(InternalArray); } + GPUhd() const T* data() const noexcept { return const_cast<T*>(InternalArray); } + GPUhd() T& operator[](const int index) noexcept { return const_cast<T&>(InternalArray[index]); } + GPUhd() constexpr T& operator[](const int index) const noexcept { return const_cast<T&>(InternalArray[index]); } + GPUhd() size_t size() const noexcept { return Size; } + + T InternalArray[Size]; +}; +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/ClusterLinesGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h similarity index 79% rename from Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/ClusterLinesGPU.h rename to Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h index bb77765d6acd3..c85a2a7a87630 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/ClusterLinesGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,17 +13,21 @@ /// \brief GPU-compliant version of ClusterLines, for the moment separated, might create a common traits for ClusterLines + later specifications for each arch, later. /// \ autrhor: mconcas@cern.ch -#ifndef O2_ITSMFT_TRACKING_CLUSTERLINESGPU_H_ -#define O2_ITSMFT_TRACKING_CLUSTERLINESGPU_H_ +#ifndef ITSTRACKINGGPU_CLUSTERLINESGPU_H_ +#define ITSTRACKINGGPU_CLUSTERLINESGPU_H_ #include "GPUCommonDef.h" +#include <cstdint> /// Required to properly compile MathUtils #include "ITStracking/ClusterLines.h" +#ifdef __HIPCC__ +#include <hip/hip_runtime.h> +#endif namespace o2 { namespace its { -namespace GPU +namespace gpu { struct GPUVertex final { @@ -66,7 +71,7 @@ class ClusterLinesGPU final float mVertex[3]; // cluster centroid position }; -} // namespace GPU +} // namespace gpu } // namespace its } // namespace o2 #endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h new file mode 100644 index 0000000000000..294016ffdcaee --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Context.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_CONTEXT_H_ +#define ITSTRACKINGGPU_CONTEXT_H_ + +#include <string> +#include <vector> +#include "ITStracking/Definitions.h" +#ifdef __HIPCC__ +#include <hip/hip_runtime.h> +#endif + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +struct DeviceProperties final { + std::string name; + int gpuProcessors; + int gpuCores; + long globalMemorySize; + long constantMemorySize; + long sharedMemorySize; + long maxClockRate; + int busWidth; + long l2CacheSize; + long registersPerBlock; + int warpSize; + int maxThreadsPerBlock; + int maxBlocksPerSM; + dim3 maxThreadsDim; + dim3 maxGridDim; +}; + +class Context final +{ + public: + static Context& getInstance(); + + Context(const Context&); + Context& operator=(const Context&); + + const DeviceProperties& getDeviceProperties(); + const DeviceProperties& getDeviceProperties(const int); + + private: + Context(bool dumpDevices = false); + ~Context() = default; + + int mDevicesNum; + std::vector<DeviceProperties> mDeviceProperties; +}; +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif /* TRAKINGITSU_INCLUDE_GPU_CONTEXT_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreGPU.h new file mode 100644 index 0000000000000..107d94e8e3e34 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreGPU.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file DeviceStoreNV.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_DEVICESTOREGPU_H_ +#define ITSTRACKINGGPU_DEVICESTOREGPU_H_ + +#ifndef GPUCA_GPUCODE_GENRTC +#include <cub/cub.cuh> +#include <cstdint> +#endif + +#include "ITStracking/Cell.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/Constants.h" +#include "ITStracking/Tracklet.h" + +#include "Array.h" +#include "UniquePointer.h" +#include "Vector.h" + +namespace o2 +{ +namespace its +{ + +namespace gpu +{ + +class DeviceStoreNV final +{ + public: + DeviceStoreNV(); + + UniquePointer<DeviceStoreNV> initialise(const float3&, + const std::array<std::vector<Cluster>, constants::its2::LayersNumber>&, + const std::array<std::vector<Tracklet>, constants::its2::TrackletsPerRoad>&, + const std::array<std::vector<Cell>, constants::its2::CellsPerRoad>&, + const std::array<std::vector<int>, constants::its2::CellsPerRoad - 1>&, + const std::array<float, constants::its2::LayersNumber>&, + const std::array<float, constants::its2::LayersNumber>&); + GPUd() const float3& getPrimaryVertex() { return *mPrimaryVertex; }; + GPUhd() Array<Vector<Cluster>, constants::its2::LayersNumber>& getClusters(); + GPUd() Array<Array<int, constants::its2::ZBins * constants::its2::PhiBins + 1>, + constants::its2::TrackletsPerRoad>& getIndexTables() { return mIndexTables; }; + GPUhd() Array<Vector<Tracklet>, constants::its2::TrackletsPerRoad>& getTracklets(); + GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad>& getTrackletsLookupTable(); + GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad>& getTrackletsPerClusterTable(); + GPUhd() Array<Vector<Cell>, constants::its2::CellsPerRoad>& getCells(); + GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad - 1>& getCellsLookupTable(); + GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad - 1>& getCellsPerTrackletTable(); + Array<Vector<int>, constants::its2::CellsPerRoad>& getTempTableArray(); + + GPUhd() float getRmin(int layer); + GPUhd() float getRmax(int layer); + + private: + UniquePointer<float3> mPrimaryVertex; + Array<Vector<Cluster>, constants::its2::LayersNumber> mClusters; + Array<float, constants::its2::LayersNumber> mRmin; + Array<float, constants::its2::LayersNumber> mRmax; + Array<Array<int, constants::its2::ZBins * constants::its2::PhiBins + 1>, constants::its2::TrackletsPerRoad> + mIndexTables; + Array<Vector<Tracklet>, constants::its2::TrackletsPerRoad> mTracklets; + Array<Vector<int>, constants::its2::CellsPerRoad> mTrackletsLookupTable; + Array<Vector<int>, constants::its2::CellsPerRoad> mTrackletsPerClusterTable; + Array<Vector<Cell>, constants::its2::CellsPerRoad> mCells; + Array<Vector<int>, constants::its2::CellsPerRoad - 1> mCellsLookupTable; + Array<Vector<int>, constants::its2::CellsPerRoad - 1> mCellsPerTrackletTable; +}; + +GPUhd() Array<Vector<Cluster>, constants::its2::LayersNumber>& DeviceStoreNV::getClusters() +{ + return mClusters; +} + +GPUd() Array<Vector<Tracklet>, constants::its2::TrackletsPerRoad>& DeviceStoreNV::getTracklets() +{ + return mTracklets; +} + +GPUd() Array<Vector<int>, constants::its2::CellsPerRoad>& DeviceStoreNV::getTrackletsLookupTable() +{ + return mTrackletsLookupTable; +} + +GPUd() Array<Vector<int>, constants::its2::CellsPerRoad>& DeviceStoreNV::getTrackletsPerClusterTable() +{ + return mTrackletsPerClusterTable; +} + +GPUhd() Array<Vector<Cell>, constants::its2::CellsPerRoad>& DeviceStoreNV::getCells() +{ + return mCells; +} + +GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad - 1>& DeviceStoreNV::getCellsLookupTable() +{ + return mCellsLookupTable; +} + +GPUhd() Array<Vector<int>, constants::its2::CellsPerRoad - 1>& DeviceStoreNV::getCellsPerTrackletTable() +{ + return mCellsPerTrackletTable; +} + +GPUhd() float DeviceStoreNV::getRmin(int layer) +{ + return mRmin[layer]; +} + +GPUhd() float DeviceStoreNV::getRmax(int layer) +{ + return mRmax[layer]; +} + +} // namespace gpu +} // namespace its +} // namespace o2 +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreVertexerGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreVertexerGPU.h similarity index 86% rename from Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreVertexerGPU.h rename to Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreVertexerGPU.h index 6bf180fcb93ad..6f63566a4463e 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreVertexerGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/DeviceStoreVertexerGPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,11 +14,17 @@ /// routines as static as possible. /// \author matteo.concas@cern.ch -#ifndef O2_ITS_TRACKING_DEVICE_STORE_VERTEXER_GPU_H_ -#define O2_ITS_TRACKING_DEVICE_STORE_VERTEXER_GPU_H_ +#ifndef ITSTRACKINGGPU_DEVICESTOREVERTEXERGPU_H_ +#define ITSTRACKINGGPU_DEVICESTOREVERTEXERGPU_H_ #ifndef GPUCA_GPUCODE_GENRTC +#ifdef __CUDACC__ #include <cub/cub.cuh> +#include <cstdint> +#endif +#ifdef __HIPCC__ +#include <hipcub/hipcub.hpp> +#endif #endif #include "ITStracking/Cluster.h" @@ -25,17 +32,18 @@ #include "ITStracking/Configuration.h" #include "ITStracking/Tracklet.h" #include "ITStracking/ClusterLines.h" -#include "ITStrackingCUDA/Array.h" -#include "ITStrackingCUDA/ClusterLinesGPU.h" -#include "ITStrackingCUDA/UniquePointer.h" -#include "ITStrackingCUDA/Vector.h" + +#include "Array.h" +#include "ClusterLinesGPU.h" +#include "UniquePointer.h" +#include "Vector.h" #include "GPUCommonDef.h" namespace o2 { namespace its { -namespace GPU +namespace gpu { enum class TrackletingLayerOrder { @@ -57,8 +65,7 @@ class DeviceStoreVertexerGPU final ~DeviceStoreVertexerGPU() = default; UniquePointer<DeviceStoreVertexerGPU> initialise(const std::array<std::vector<Cluster>, constants::its::LayersNumberVertexer>&, - const std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::LayersNumberVertexer>&); + const std::array<std::vector<int>, constants::its::LayersNumberVertexer>&); // RO APIs GPUd() const Array<Vector<Cluster>, constants::its::LayersNumberVertexer>& getClusters() @@ -80,7 +87,18 @@ class DeviceStoreVertexerGPU final GPUhd() Vector<float>& getXYCentroids() { return mXYCentroids; } GPUhd() Vector<float>& getZCentroids() { return mZCentroids; } GPUhd() Array<Vector<int>, 3>& getHistogramXYZ() { return mHistogramXYZ; } - GPUhd() Vector<cub::KeyValuePair<int, int>>& getTmpVertexPositionBins() { return mTmpVertexPositionBins; } +#ifdef __CUDACC__ + GPUhd() Vector<cub::KeyValuePair<int, int>>& getTmpVertexPositionBins() + { + return mTmpVertexPositionBins; + } +#endif +#ifdef __HIPCC__ + GPUhd() Vector<hipcub::KeyValuePair<int, int>>& getTmpVertexPositionBins() + { + return mTmpVertexPositionBins; + } +#endif #ifdef _ALLOW_DEBUG_TREES_ITS_ GPUd() Array<Vector<int>, 2>& getDupletIndices() @@ -127,7 +145,12 @@ class DeviceStoreVertexerGPU final Vector<float> mZCentroids; Vector<float> mBeamPosition; Array<Vector<int>, 3> mHistogramXYZ; +#ifdef __CUDACC__ Vector<cub::KeyValuePair<int, int>> mTmpVertexPositionBins; +#endif +#ifdef __HIPCC__ + Vector<hipcub::KeyValuePair<int, int>> mTmpVertexPositionBins; +#endif #ifdef _ALLOW_DEBUG_TREES_ITS_ Array<Vector<int>, 2> mDupletIndices; @@ -145,7 +168,7 @@ inline std::vector<int> DeviceStoreVertexerGPU::getNFoundTrackletsFromGPU(const std::vector<int> nFoundDuplets; nFoundDuplets.resize(sizes[1]); - if (order == GPU::Order::fromInnermostToMiddleLayer) { + if (order == gpu::Order::fromInnermostToMiddleLayer) { mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); } else { mNFoundDuplets[1].copyIntoSizedVector(nFoundDuplets); @@ -165,7 +188,7 @@ inline std::vector<Tracklet> DeviceStoreVertexerGPU::getRawDupletsFromGPU(const std::vector<int> nFoundDuplets; nFoundDuplets.resize(sizes[1]); - if (order == GPU::Order::fromInnermostToMiddleLayer) { + if (order == gpu::Order::fromInnermostToMiddleLayer) { mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); mDuplets01.copyIntoSizedVector(tmpDuplets); } else { @@ -188,7 +211,7 @@ inline std::vector<Tracklet> DeviceStoreVertexerGPU::getDupletsFromGPU(const Ord nFoundDuplets.resize(sizes[1]); std::vector<Tracklet> shrinkedDuplets; - if (order == GPU::Order::fromInnermostToMiddleLayer) { + if (order == gpu::Order::fromInnermostToMiddleLayer) { mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); mDuplets01.copyIntoSizedVector(tmpDuplets); } else { @@ -226,7 +249,7 @@ inline std::array<std::vector<int>, 2> DeviceStoreVertexerGPU::getHistogramXYFro { std::array<std::vector<int>, 2> histoXY; for (int iHisto{0}; iHisto < 2; ++iHisto) { - histoXY[iHisto].resize(mGPUConf.nBinsXYZ[iHisto] - 1); + histoXY[iHisto].resize(mGPUConf.histConf.nBinsXYZ[iHisto] - 1); mHistogramXYZ[iHisto].copyIntoSizedVector(histoXY[iHisto]); } @@ -236,7 +259,7 @@ inline std::array<std::vector<int>, 2> DeviceStoreVertexerGPU::getHistogramXYFro inline std::vector<int> DeviceStoreVertexerGPU::getHistogramZFromGPU() { std::vector<int> histoZ; - histoZ.resize(mGPUConf.nBinsXYZ[2] - 1); + histoZ.resize(mGPUConf.histConf.nBinsXYZ[2] - 1); mHistogramXYZ[2].copyIntoSizedVector(histoZ); return histoZ; @@ -244,7 +267,7 @@ inline std::vector<int> DeviceStoreVertexerGPU::getHistogramZFromGPU() inline void DeviceStoreVertexerGPU::updateDuplets(const Order order, std::vector<Tracklet>& duplets) { - if (order == GPU::Order::fromInnermostToMiddleLayer) { + if (order == gpu::Order::fromInnermostToMiddleLayer) { mDuplets01.reset(duplets.data(), static_cast<int>(duplets.size())); } else { mDuplets12.reset(duplets.data(), static_cast<int>(duplets.size())); @@ -253,7 +276,7 @@ inline void DeviceStoreVertexerGPU::updateDuplets(const Order order, std::vector inline void DeviceStoreVertexerGPU::updateFoundDuplets(const Order order, std::vector<int>& nDuplets) { - if (order == GPU::Order::fromInnermostToMiddleLayer) { + if (order == gpu::Order::fromInnermostToMiddleLayer) { mNFoundDuplets[0].reset(nDuplets.data(), static_cast<int>(nDuplets.size())); } else { mNFoundDuplets[1].reset(nDuplets.data(), static_cast<int>(nDuplets.size())); @@ -296,7 +319,7 @@ inline std::vector<Line> DeviceStoreVertexerGPU::getLinesFromGPU() return lines; } -} // namespace GPU +} // namespace gpu } // namespace its } // namespace o2 -#endif //O2_ITS_TRACKING_DEVICE_STORE_VERTEXER_GPU_H_ +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/PrimaryVertexContextGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/PrimaryVertexContextGPU.h new file mode 100644 index 0000000000000..67e5109b04623 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/PrimaryVertexContextGPU.h @@ -0,0 +1,146 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file PrimaryVertexContextNVNV.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_PRIMARYVERTEXCONTEXTGPU_H_ +#define ITSTRACKINGGPU_PRIMARYVERTEXCONTEXTGPU_H_ + +#include <array> + +#ifndef GPUCA_GPUCODE_GENRTC +#include <cub/cub.cuh> +#include <cstdint> +#endif + +#include "ITStracking/Configuration.h" +#include "ITStracking/Constants.h" +#include "ITStracking/Definitions.h" +#include "ITStracking/PrimaryVertexContext.h" +#include "ITStracking/Road.h" +#include "ITStracking/Tracklet.h" + +#include "DeviceStoreGPU.h" +#include "UniquePointer.h" + +namespace o2 +{ +namespace its +{ + +class PrimaryVertexContextNV final : public PrimaryVertexContext +{ + public: + PrimaryVertexContextNV() = default; + ~PrimaryVertexContextNV() override; + + void initialise(const MemoryParameters& memParam, const TrackingParameters& trkParam, + const std::vector<std::vector<Cluster>>& cl, const std::array<float, 3>& pv, const int iteration) override; + + gpu::DeviceStoreNV& getDeviceContext(); + gpu::Array<gpu::Vector<Cluster>, constants::its2::LayersNumber>& getDeviceClusters(); + gpu::Array<gpu::Vector<Tracklet>, constants::its2::TrackletsPerRoad>& getDeviceTracklets(); + gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad>& getDeviceTrackletsLookupTable(); + gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad>& getDeviceTrackletsPerClustersTable(); + gpu::Array<gpu::Vector<Cell>, constants::its2::CellsPerRoad>& getDeviceCells(); + gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad - 1>& getDeviceCellsLookupTable(); + gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad - 1>& getDeviceCellsPerTrackletTable(); + std::array<gpu::Vector<int>, constants::its2::CellsPerRoad>& getTempTableArray(); + std::array<gpu::Vector<Tracklet>, constants::its2::CellsPerRoad>& getTempTrackletArray(); + std::array<gpu::Vector<Cell>, constants::its2::CellsPerRoad - 1>& getTempCellArray(); + void updateDeviceContext(); + + private: + gpu::DeviceStoreNV mGPUContext; + gpu::UniquePointer<gpu::DeviceStoreNV> mGPUContextDevicePointer; + std::array<gpu::Vector<int>, constants::its2::CellsPerRoad> mTempTableArray; + std::array<gpu::Vector<Tracklet>, constants::its2::CellsPerRoad> mTempTrackletArray; + std::array<gpu::Vector<Cell>, constants::its2::CellsPerRoad - 1> mTempCellArray; +}; + +inline PrimaryVertexContextNV::~PrimaryVertexContextNV() = default; + +inline gpu::DeviceStoreNV& PrimaryVertexContextNV::getDeviceContext() +{ + return *mGPUContextDevicePointer; +} + +inline gpu::Array<gpu::Vector<Cluster>, constants::its2::LayersNumber>& PrimaryVertexContextNV::getDeviceClusters() +{ + return mGPUContext.getClusters(); +} + +inline gpu::Array<gpu::Vector<Tracklet>, constants::its2::TrackletsPerRoad>& PrimaryVertexContextNV::getDeviceTracklets() +{ + return mGPUContext.getTracklets(); +} + +inline gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad>& PrimaryVertexContextNV::getDeviceTrackletsLookupTable() +{ + return mGPUContext.getTrackletsLookupTable(); +} + +inline gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad>& + PrimaryVertexContextNV::getDeviceTrackletsPerClustersTable() +{ + return mGPUContext.getTrackletsPerClusterTable(); +} + +inline gpu::Array<gpu::Vector<Cell>, constants::its2::CellsPerRoad>& PrimaryVertexContextNV::getDeviceCells() +{ + return mGPUContext.getCells(); +} + +inline gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad - 1>& PrimaryVertexContextNV::getDeviceCellsLookupTable() +{ + return mGPUContext.getCellsLookupTable(); +} + +inline gpu::Array<gpu::Vector<int>, constants::its2::CellsPerRoad - 1>& + PrimaryVertexContextNV::getDeviceCellsPerTrackletTable() +{ + return mGPUContext.getCellsPerTrackletTable(); +} + +inline std::array<gpu::Vector<int>, constants::its2::CellsPerRoad>& PrimaryVertexContextNV::getTempTableArray() +{ + return mTempTableArray; +} + +inline std::array<gpu::Vector<Tracklet>, constants::its2::CellsPerRoad>& PrimaryVertexContextNV::getTempTrackletArray() +{ + return mTempTrackletArray; +} + +inline std::array<gpu::Vector<Cell>, constants::its2::CellsPerRoad - 1>& PrimaryVertexContextNV::getTempCellArray() +{ + return mTempCellArray; +} + +inline void PrimaryVertexContextNV::updateDeviceContext() +{ + mGPUContextDevicePointer = gpu::UniquePointer<gpu::DeviceStoreNV>{mGPUContext}; +} + +inline void PrimaryVertexContextNV::initialise(const MemoryParameters& memParam, const TrackingParameters& trkParam, + const std::vector<std::vector<Cluster>>& cl, const std::array<float, 3>& pv, const int iteration) +{ + ///TODO: to be re-enabled in the future + // this->PrimaryVertexContext::initialise(memParam, cl, pv, iteration); + // mGPUContextDevicePointer = mGPUContext.initialise(mPrimaryVertex, mClusters, mTracklets, mCells, mCellsLookupTable, mMinR, mMaxR); +} + +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h new file mode 100644 index 0000000000000..ffcd845bd168b --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Stream.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_STREAM_H_ +#define ITSTRACKINGGPU_STREAM_H_ + +#include "ITStracking/Definitions.h" +#ifdef __HIPCC__ +#include <hip/hip_runtime.h> +#endif + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +class Stream final +{ + + public: + Stream(); + ~Stream(); + + Stream(const Stream&) = delete; + Stream& operator=(const Stream&) = delete; + + const GPUStream& get() const; + + private: + GPUStream mStream; +}; +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif /* TRAKINGITSU_INCLUDE_GPU_STREAM_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h new file mode 100644 index 0000000000000..33dba90156a25 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TrackerTraitsNV.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_TRACKERTRAITSGPU_H_ +#define ITSTRACKINGGPU_TRACKERTRAITSGPU_H_ + +#ifndef GPUCA_GPUCODE_GENRTC +#include <cub/cub.cuh> +#include <cstdint> +#endif +#include "ITStracking/Configuration.h" +#include "ITStracking/Definitions.h" +#include "ITStracking/TrackerTraits.h" + +namespace o2 +{ +namespace its +{ + +class PrimaryVertexContext; + +class TrackerTraitsNV : public TrackerTraits +{ + public: + TrackerTraitsNV() = default; + ~TrackerTraitsNV() override = default; + + void computeLayerCells() final; + void computeLayerTracklets() final; + void refitTracks(const std::vector<std::vector<TrackingFrameInfo>>& tf, std::vector<TrackITSExt>& tracks) override; +}; + +extern "C" TrackerTraits* createTrackerTraitsNV(); +} // namespace its +} // namespace o2 + +#endif /* TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/UniquePointer.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/UniquePointer.h new file mode 100644 index 0000000000000..ce04da3dde622 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/UniquePointer.h @@ -0,0 +1,153 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file UniquePointer.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_UNIQUEPOINTER_H_ +#define ITSTRACKINGGPU_UNIQUEPOINTER_H_ + +#include "Utils.h" + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +namespace +{ +template <typename T> +struct UniquePointerTraits final { + typedef T* InternalPointer; + + GPUhd() static constexpr T& getReference(const InternalPointer& internalPointer) noexcept + { + return const_cast<T&>(*internalPointer); + } + + GPUhd() static constexpr T* getPointer(const InternalPointer& internalPointer) noexcept + { + return const_cast<T*>(internalPointer); + } +}; +} // namespace + +template <typename T> +class UniquePointer final +{ + typedef UniquePointerTraits<T> PointerTraits; + + public: + UniquePointer(); + explicit UniquePointer(const T&); + ~UniquePointer(); + + UniquePointer(const UniquePointer&) = delete; + UniquePointer& operator=(const UniquePointer&) = delete; + + UniquePointer(UniquePointer&&); + UniquePointer& operator=(UniquePointer&&); + + GPUhd() T* get() noexcept; + GPUhd() const T* get() const noexcept; + GPUhd() T& operator*() noexcept; + GPUhd() const T& operator*() const noexcept; + + protected: + void destroy(); + + private: + typename PointerTraits::InternalPointer mDevicePointer; +}; + +template <typename T> +UniquePointer<T>::UniquePointer() : mDevicePointer{nullptr} +{ + // Nothing to do +} + +template <typename T> +UniquePointer<T>::UniquePointer(const T& ref) +{ + try { + + utils::host::gpuMalloc(reinterpret_cast<void**>(&mDevicePointer), sizeof(T)); + utils::host::gpuMemcpyHostToDevice(mDevicePointer, &ref, sizeof(T)); + + } catch (...) { + + destroy(); + + throw; + } +} + +template <typename T> +UniquePointer<T>::~UniquePointer() +{ + destroy(); +} + +template <typename T> +UniquePointer<T>::UniquePointer(UniquePointer<T>&& other) : mDevicePointer{other.mDevicePointer} +{ + // Nothing to do +} + +template <typename T> +UniquePointer<T>& UniquePointer<T>::operator=(UniquePointer<T>&& other) +{ + mDevicePointer = other.mDevicePointer; + other.mDevicePointer = nullptr; + + return *this; +} + +template <typename T> +void UniquePointer<T>::destroy() +{ + if (mDevicePointer != nullptr) { + + utils::host::gpuFree(mDevicePointer); + } +} + +template <typename T> +GPUhd() T* UniquePointer<T>::get() noexcept +{ + return PointerTraits::getPointer(mDevicePointer); +} + +template <typename T> +GPUhd() const T* UniquePointer<T>::get() const noexcept +{ + return PointerTraits::getPointer(mDevicePointer); +} + +template <typename T> +GPUhd() T& UniquePointer<T>::operator*() noexcept +{ + return PointerTraits::getReference(mDevicePointer); +} + +template <typename T> +GPUhd() const T& UniquePointer<T>::operator*() const noexcept +{ + return PointerTraits::getReference(mDevicePointer); +} +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h new file mode 100644 index 0000000000000..d435e8928cf97 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Utils.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_UTILS_H_ +#define ITSTRACKINGGPU_UTILS_H_ + +#include "GPUCommonDef.h" +#include "Stream.h" + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +namespace utils +{ + +namespace host +{ + +#ifdef __CUDACC__ +void checkGPUError(const cudaError_t error, const char* file, const int line); +#endif +#ifdef __HIPCC__ +void checkGPUError(const hipError_t error, const char* file, const int line); +#endif + +dim3 getBlockSize(const int); +dim3 getBlockSize(const int, const int); +dim3 getBlockSize(const int, const int, const int); +dim3 getBlocksGrid(const dim3&, const int); +dim3 getBlocksGrid(const dim3&, const int, const int); + +void gpuMalloc(void**, const int); +void gpuFree(void*); +void gpuMemset(void*, int, int); +void gpuMemcpyHostToDevice(void*, const void*, int); +// void gpuMemcpyHostToDeviceAsync(void*, const void*, int, Stream&); +void gpuMemcpyDeviceToHost(void*, const void*, int); +// void gpuStartProfiler(); +// void gpuStopProfiler(); +} // namespace host + +namespace device +{ +GPUd() int getLaneIndex(); +GPUd() int shareToWarp(const int, const int); +GPUd() int gpuAtomicAdd(int*, const int); +} // namespace device +} // namespace utils +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Vector.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Vector.h new file mode 100644 index 0000000000000..22099d53cd843 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Vector.h @@ -0,0 +1,331 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Vector.h +/// \brief +/// + +#ifndef ITSTRACKINGGPU_VECTOR_H_ +#define ITSTRACKINGGPU_VECTOR_H_ + +#include <cassert> +#include <new> +#include <type_traits> +#include <vector> + +#include "Stream.h" +#include "Utils.h" + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +template <typename T> +class Vector final +{ + static_assert(std::is_trivially_destructible<T>::value, "Vector only supports trivially destructible objects."); + + public: + Vector(); + explicit Vector(const int, const int = 0); + Vector(const T* const, const int, const int = 0); + GPUhd() ~Vector(); + + Vector(const Vector&) = delete; + Vector& operator=(const Vector&) = delete; + + GPUhd() Vector(Vector&&); + Vector& operator=(Vector&&); + + int getSizeFromDevice() const; + + T getElementFromDevice(const int) const; + + void resize(const int); + void reset(const int, const int = 0); + void reset(const T* const, const int, const int = 0); + void copyIntoVector(std::vector<T>&, const int); + void copyIntoSizedVector(std::vector<T>&); + + GPUhd() T* get() const; + GPUhd() int capacity() const; + GPUhd() Vector<T> getWeakCopy() const; + GPUd() T& operator[](const int) const; + + GPUd() int size() const; + GPUd() int extend(const int) const; + GPUhd() void dump(); + + template <typename... Args> + GPUd() void emplace(const int, Args&&...); + + protected: + void destroy(); + + private: + GPUhd() Vector(const Vector&, const bool); + + T* mArrayPointer = nullptr; + int* mDeviceSize = nullptr; + int mCapacity; + bool mIsWeak; +}; + +template <typename T> +Vector<T>::Vector() : Vector{nullptr, 0} +{ + // Nothing to do +} + +template <typename T> +Vector<T>::Vector(const int capacity, const int initialSize) : Vector{nullptr, capacity, initialSize} +{ + // Nothing to do +} + +template <typename T> +Vector<T>::Vector(const T* const source, const int size, const int initialSize) : mCapacity{size}, mIsWeak{false} +{ + if (size > 0) { + try { + + utils::host::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); + utils::host::gpuMalloc(reinterpret_cast<void**>(&mDeviceSize), sizeof(int)); + + if (source != nullptr) { + + utils::host::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); + utils::host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); + + } else { + + utils::host::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); + } + + } catch (...) { + + destroy(); + + throw; + } + } +} + +template <typename T> +GPUhd() Vector<T>::Vector(const Vector& other, const bool isWeak) + : mArrayPointer{other.mArrayPointer}, + mDeviceSize{other.mDeviceSize}, + mCapacity{other.mCapacity}, + mIsWeak{isWeak} +{ + // Nothing to do +} + +template <typename T> +GPUhd() Vector<T>::~Vector() +{ + if (mIsWeak) { + + return; + + } else { +#if defined(TRACKINGITSU_GPU_DEVICE) + assert(0); +#else + destroy(); +#endif + } +} + +template <typename T> +GPUhd() Vector<T>::Vector(Vector<T>&& other) + : mArrayPointer{other.mArrayPointer}, + mDeviceSize{other.mDeviceSize}, + mCapacity{other.mCapacity}, + mIsWeak{other.mIsWeak} +{ + other.mArrayPointer = nullptr; + other.mDeviceSize = nullptr; +} + +template <typename T> +Vector<T>& Vector<T>::operator=(Vector<T>&& other) +{ + destroy(); + + mArrayPointer = other.mArrayPointer; + mDeviceSize = other.mDeviceSize; + mCapacity = other.mCapacity; + mIsWeak = other.mIsWeak; + + other.mArrayPointer = nullptr; + other.mDeviceSize = nullptr; + + return *this; +} + +template <typename T> +int Vector<T>::getSizeFromDevice() const +{ + int size; + utils::host::gpuMemcpyDeviceToHost(&size, mDeviceSize, sizeof(int)); + + return size; +} + +template <typename T> +void Vector<T>::resize(const int size) +{ + utils::host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); +} + +template <typename T> +void Vector<T>::reset(const int capacity, const int initialSize) +{ + reset(nullptr, capacity, initialSize); +} + +template <typename T> +void Vector<T>::reset(const T* const source, const int size, const int initialSize) +{ + if (size > mCapacity) { + if (mArrayPointer != nullptr) { + utils::host::gpuFree(mArrayPointer); + } + utils::host::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); + mCapacity = size; + } + + if (source != nullptr) { + utils::host::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); + utils::host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); + + } else { + if (mDeviceSize == nullptr) { + utils::host::gpuMalloc(reinterpret_cast<void**>(&mDeviceSize), sizeof(int)); + } + utils::host::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); + } +} + +template <typename T> +void Vector<T>::copyIntoVector(std::vector<T>& destinationVector, const int size) +{ + + T* hostPrimitivePointer = nullptr; + + try { + + hostPrimitivePointer = static_cast<T*>(malloc(size * sizeof(T))); + utils::host::gpuMemcpyDeviceToHost(hostPrimitivePointer, mArrayPointer, size * sizeof(T)); + + destinationVector = std::move(std::vector<T>(hostPrimitivePointer, hostPrimitivePointer + size)); + + } catch (...) { + + if (hostPrimitivePointer != nullptr) { + + free(hostPrimitivePointer); + } + + throw; + } +} + +template <typename T> +void Vector<T>::copyIntoSizedVector(std::vector<T>& destinationVector) +{ + utils::host::gpuMemcpyDeviceToHost(destinationVector.data(), mArrayPointer, destinationVector.size() * sizeof(T)); +} + +template <typename T> +inline void Vector<T>::destroy() +{ + if (mArrayPointer != nullptr) { + + utils::host::gpuFree(mArrayPointer); + } + + if (mDeviceSize != nullptr) { + + utils::host::gpuFree(mDeviceSize); + } +} + +template <typename T> +GPUhd() T* Vector<T>::get() const +{ + return mArrayPointer; +} + +template <typename T> +GPUhd() int Vector<T>::capacity() const +{ + return mCapacity; +} + +template <typename T> +GPUhd() Vector<T> Vector<T>::getWeakCopy() const +{ + return Vector{*this, true}; +} + +template <typename T> +GPUd() T& Vector<T>::operator[](const int index) const +{ + return mArrayPointer[index]; +} + +template <typename T> +GPUh() T Vector<T>::getElementFromDevice(const int index) const +{ + T element; + utils::host::gpuMemcpyDeviceToHost(&element, mArrayPointer + index, sizeof(T)); + + return element; +} + +template <typename T> +GPUd() int Vector<T>::size() const +{ + return *mDeviceSize; +} + +template <typename T> +GPUd() int Vector<T>::extend(const int sizeIncrement) const +{ + const int startIndex = utils::device::gpuAtomicAdd(mDeviceSize, sizeIncrement); + assert(size() <= mCapacity); + + return startIndex; +} + +template <typename T> +template <typename... Args> +GPUd() void Vector<T>::emplace(const int index, Args&&... arguments) +{ + new (mArrayPointer + index) T(std::forward<Args>(arguments)...); +} + +template <typename T> +GPUhd() void Vector<T>::dump() +{ + printf("mArrayPointer = %p\nmDeviceSize = %p\nmCapacity = %d\nmIsWeak = %s\n", + mArrayPointer, mDeviceSize, mCapacity, mIsWeak ? "true" : "false"); +} +} // namespace gpu +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h new file mode 100644 index 0000000000000..3c9ba66629290 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file VertexerTraitsGPU.h +/// \brief +/// \author matteo.concas@cern.ch + +#ifndef ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ +#define ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ + +#include <vector> +#include <array> + +#include "ITStracking/VertexerTraits.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/Constants.h" +#include "ITStracking/Definitions.h" +#include "ITStracking/Tracklet.h" + +#include "DeviceStoreVertexerGPU.h" +#include "UniquePointer.h" + +#ifdef _ALLOW_DEBUG_TREES_ITS_ +#include "ITStracking/StandaloneDebugger.h" +#endif + +namespace o2 +{ +namespace its +{ +class ROframe; + +using constants::its2::InversePhiBinSize; + +class VertexerTraitsGPU : public VertexerTraits +{ + public: +#ifdef _ALLOW_DEBUG_TREES_ITS_ + VertexerTraitsGPU(); + ~VertexerTraitsGPU() override; +#else + VertexerTraitsGPU(); +#endif + void initialise(ROframe*) override; + void computeTracklets() override; + void computeTrackletMatching() override; + void computeVertices() override; +#ifdef _ALLOW_DEBUG_TREES_ITS_ + void computeMCFiltering() override; +#endif + + // GPU-specific getters + GPUd() static const int2 getBinsPhiRectWindow(const Cluster&, float maxdeltaphi); + GPUhd() gpu::DeviceStoreVertexerGPU& getDeviceContext(); + + protected: + gpu::DeviceStoreVertexerGPU mStoreVertexerGPU; + gpu::UniquePointer<gpu::DeviceStoreVertexerGPU> mStoreVertexerGPUPtr; +}; + +inline GPUd() const int2 VertexerTraitsGPU::getBinsPhiRectWindow(const Cluster& currentCluster, float phiCut) +{ + // This function returns the lowest PhiBin and the number of phi bins to be spanned, In the form int2{phiBinLow, PhiBinSpan} + const int phiBinMin{constants::its2::getPhiBinIndex( + math_utils::getNormalizedPhi(currentCluster.phi - phiCut))}; + const int phiBinSpan{static_cast<int>(MATH_CEIL(phiCut * InversePhiBinSize))}; + return int2{phiBinMin, phiBinSpan}; +} + +GPUhd() gpu::DeviceStoreVertexerGPU& VertexerTraitsGPU::getDeviceContext() +{ + return *mStoreVertexerGPUPtr; +} + +extern "C" VertexerTraits* createVertexerTraitsGPU(); + +} // namespace its +} // namespace o2 +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt new file mode 100644 index 0000000000000..beb4352f94c36 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +# CUDA +if(CUDA_ENABLED) + +message(STATUS "Building ITS CUDA tracker") +o2_add_library(ITStrackingCUDA + SOURCES ClusterLinesGPU.cu + Context.cu + DeviceStoreGPU.cu + DeviceStoreVertexerGPU.cu + Stream.cu + TrackerTraitsGPU.cu + VertexerTraitsGPU.cu + Utils.cu + PUBLIC_INCLUDE_DIRECTORIES ../ + PUBLIC_LINK_LIBRARIES O2::ITStracking + O2::SimConfig + O2::SimulationDataFormat + TARGETVARNAME targetName) + +set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) +target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB $<TARGET_PROPERTY:O2::ITStracking,COMPILE_DEFINITIONS>) + +endif() \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/ClusterLinesGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu similarity index 93% rename from Detectors/ITSMFT/ITS/tracking/cuda/src/ClusterLinesGPU.cu rename to Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu index 9c1f048292b52..f50031cd3f203 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/ClusterLinesGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu @@ -1,20 +1,23 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// +/// \author matteo.concas@cern.ch -#include "ITStrackingCUDA/ClusterLinesGPU.h" +#include "ITStrackingGPU/ClusterLinesGPU.h" namespace o2 { namespace its { -namespace GPU +namespace gpu { GPUd() ClusterLinesGPU::ClusterLinesGPU(const Line& firstLine, const Line& secondLine) @@ -129,6 +132,6 @@ GPUd() void ClusterLinesGPU::computeClusterCentroid() mBMatrix[0] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])) / determinant; } -} // namespace GPU +} // namespace gpu } // namespace its } // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu new file mode 100644 index 0000000000000..68766e4bd4336 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITStrackingGPU/Context.h" +#include "ITStrackingGPU/Utils.h" + +#include <sstream> +#include <stdexcept> +#include <iostream> + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +using utils::host::checkGPUError; + +Context::Context(bool dumpDevices) +{ + checkGPUError(cudaGetDeviceCount(&mDevicesNum), __FILE__, __LINE__); + + if (mDevicesNum == 0) { + throw std::runtime_error{"There are no available GPU device(s)\n"}; + } + + mDeviceProperties.resize(mDevicesNum, DeviceProperties{}); + + int currentDeviceIndex; + checkGPUError(cudaGetDevice(¤tDeviceIndex), __FILE__, __LINE__); + + for (int iDevice{0}; iDevice < mDevicesNum; ++iDevice) { + + cudaDeviceProp deviceProperties; + + checkGPUError(cudaSetDevice(iDevice), __FILE__, __LINE__); + checkGPUError(cudaGetDeviceProperties(&deviceProperties, iDevice), __FILE__, __LINE__); + + int major = deviceProperties.major; + int minor = deviceProperties.minor; + + mDeviceProperties[iDevice].name = deviceProperties.name; + mDeviceProperties[iDevice].gpuProcessors = deviceProperties.multiProcessorCount; + mDeviceProperties[iDevice].gpuCores = getGPUCores(major, minor) * deviceProperties.multiProcessorCount; + mDeviceProperties[iDevice].globalMemorySize = deviceProperties.totalGlobalMem; + mDeviceProperties[iDevice].constantMemorySize = deviceProperties.totalConstMem; + mDeviceProperties[iDevice].sharedMemorySize = deviceProperties.sharedMemPerBlock; + mDeviceProperties[iDevice].maxClockRate = deviceProperties.memoryClockRate; + mDeviceProperties[iDevice].busWidth = deviceProperties.memoryBusWidth; + mDeviceProperties[iDevice].l2CacheSize = deviceProperties.l2CacheSize; + mDeviceProperties[iDevice].registersPerBlock = deviceProperties.regsPerBlock; + mDeviceProperties[iDevice].warpSize = deviceProperties.warpSize; + mDeviceProperties[iDevice].maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock; + mDeviceProperties[iDevice].maxBlocksPerSM = getGPUMaxThreadsPerComputingUnit(); + mDeviceProperties[iDevice].maxThreadsDim = dim3{static_cast<unsigned int>(deviceProperties.maxThreadsDim[0]), + static_cast<unsigned int>(deviceProperties.maxThreadsDim[1]), + static_cast<unsigned int>(deviceProperties.maxThreadsDim[2])}; + mDeviceProperties[iDevice].maxGridDim = dim3{static_cast<unsigned int>(deviceProperties.maxGridSize[0]), + static_cast<unsigned int>(deviceProperties.maxGridSize[1]), + static_cast<unsigned int>(deviceProperties.maxGridSize[2])}; + if (dumpDevices) { + std::cout << "################ " << GPU_ARCH << " DEVICE " << iDevice << " ################" << std::endl; + std::cout << "Name " << mDeviceProperties[iDevice].name << std::endl; + std::cout << "minor " << minor << " major " << major << std::endl; + std::cout << "gpuProcessors " << mDeviceProperties[iDevice].gpuProcessors << std::endl; + std::cout << "gpuCores " << mDeviceProperties[iDevice].gpuCores << std::endl; + std::cout << "globalMemorySize " << mDeviceProperties[iDevice].globalMemorySize << std::endl; + std::cout << "constantMemorySize " << mDeviceProperties[iDevice].constantMemorySize << std::endl; + std::cout << "sharedMemorySize " << mDeviceProperties[iDevice].sharedMemorySize << std::endl; + std::cout << "maxClockRate " << mDeviceProperties[iDevice].maxClockRate << std::endl; + std::cout << "busWidth " << mDeviceProperties[iDevice].busWidth << std::endl; + std::cout << "l2CacheSize " << mDeviceProperties[iDevice].l2CacheSize << std::endl; + std::cout << "registersPerBlock " << mDeviceProperties[iDevice].registersPerBlock << std::endl; + std::cout << "warpSize " << mDeviceProperties[iDevice].warpSize << std::endl; + std::cout << "maxThreadsPerBlock " << mDeviceProperties[iDevice].maxThreadsPerBlock << std::endl; + std::cout << "maxBlocksPerSM " << mDeviceProperties[iDevice].maxBlocksPerSM << std::endl; + std::cout << "maxThreadsDim " << mDeviceProperties[iDevice].maxThreadsDim.x << ", " + << mDeviceProperties[iDevice].maxThreadsDim.y << ", " + << mDeviceProperties[iDevice].maxThreadsDim.z << std::endl; + std::cout << "maxGridDim " << mDeviceProperties[iDevice].maxGridDim.x << ", " + << mDeviceProperties[iDevice].maxGridDim.y << ", " + << mDeviceProperties[iDevice].maxGridDim.z << std::endl; + std::cout << std::endl; + } + } + + checkGPUError(cudaSetDevice(currentDeviceIndex), __FILE__, __LINE__); +} + +Context& Context::getInstance() +{ + static Context gpuContext; + return gpuContext; +} + +const DeviceProperties& Context::getDeviceProperties() +{ + int currentDeviceIndex; + checkGPUError(cudaGetDevice(¤tDeviceIndex), __FILE__, __LINE__); + + return getDeviceProperties(currentDeviceIndex); +} + +const DeviceProperties& Context::getDeviceProperties(const int deviceIndex) +{ + return mDeviceProperties[deviceIndex]; +} + +} // namespace gpu +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreGPU.cu new file mode 100644 index 0000000000000..3a3fd910226ea --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreGPU.cu @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file DeviceStoreNV.cxx +/// \brief +/// + +#include "ITStrackingGPU/DeviceStoreGPU.h" +#include "ITStrackingGPU/Stream.h" +#include <sstream> + +namespace +{ + +using namespace o2::its; + +__device__ void fillIndexTables(o2::its::gpu::DeviceStoreNV& primaryVertexContext, const int layerIndex) +{ + + const int currentClusterIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; + const int nextLayerClustersNum{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; + + if (currentClusterIndex < nextLayerClustersNum) { + + const int currentBinIndex{ + primaryVertexContext.getClusters()[layerIndex + 1][currentClusterIndex].indexTableBinIndex}; + int previousBinIndex; + + if (currentClusterIndex == 0) { + + primaryVertexContext.getIndexTables()[layerIndex][0] = 0; + previousBinIndex = 0; + + } else { + + previousBinIndex = primaryVertexContext.getClusters()[layerIndex + 1][currentClusterIndex - 1].indexTableBinIndex; + } + + if (currentBinIndex > previousBinIndex) { + + for (int iBin{previousBinIndex + 1}; iBin <= currentBinIndex; ++iBin) { + + primaryVertexContext.getIndexTables()[layerIndex][iBin] = currentClusterIndex; + } + + previousBinIndex = currentBinIndex; + } + + if (currentClusterIndex == nextLayerClustersNum - 1) { + + for (int iBin{currentBinIndex + 1}; iBin <= o2::its::constants::its2::ZBins * o2::its::constants::its2::PhiBins; + iBin++) { + + primaryVertexContext.getIndexTables()[layerIndex][iBin] = nextLayerClustersNum; + } + } + } +} + +__device__ void fillTrackletsPerClusterTables(o2::its::gpu::DeviceStoreNV& primaryVertexContext, const int layerIndex) +{ + const int currentClusterIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; + const int clustersSize{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; + + if (currentClusterIndex < clustersSize) { + + primaryVertexContext.getTrackletsPerClusterTable()[layerIndex][currentClusterIndex] = 0; + } +} + +__device__ void fillCellsPerClusterTables(o2::its::gpu::DeviceStoreNV& primaryVertexContext, const int layerIndex) +{ + const int totalThreadNum{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; + const int trackletsSize{static_cast<int>(primaryVertexContext.getTracklets()[layerIndex + 1].capacity())}; + const int trackletsPerThread{1 + (trackletsSize - 1) / totalThreadNum}; + const int firstTrackletIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x) * trackletsPerThread}; + + if (firstTrackletIndex < trackletsSize) { + + const int trackletsToSet{min(trackletsSize, firstTrackletIndex + trackletsPerThread) - firstTrackletIndex}; + memset(&primaryVertexContext.getCellsPerTrackletTable()[layerIndex][firstTrackletIndex], 0, + trackletsToSet * sizeof(int)); + } +} + +__global__ void fillDeviceStructures(o2::its::gpu::DeviceStoreNV& primaryVertexContext, const int layerIndex) +{ + fillIndexTables(primaryVertexContext, layerIndex); + + if (layerIndex < o2::its::constants::its2::CellsPerRoad) { + + fillTrackletsPerClusterTables(primaryVertexContext, layerIndex); + } + + if (layerIndex < o2::its::constants::its2::CellsPerRoad - 1) { + + fillCellsPerClusterTables(primaryVertexContext, layerIndex); + } +} +} // namespace + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +DeviceStoreNV::DeviceStoreNV() = default; + +UniquePointer<DeviceStoreNV> DeviceStoreNV::initialise(const float3& primaryVertex, + const std::array<std::vector<Cluster>, constants::its2::LayersNumber>& clusters, + const std::array<std::vector<Tracklet>, constants::its2::TrackletsPerRoad>& tracklets, + const std::array<std::vector<Cell>, constants::its2::CellsPerRoad>& cells, + const std::array<std::vector<int>, constants::its2::CellsPerRoad - 1>& cellsLookupTable, + const std::array<float, constants::its2::LayersNumber>& rmin, + const std::array<float, constants::its2::LayersNumber>& rmax) +{ + mPrimaryVertex = UniquePointer<float3>{primaryVertex}; + + for (int iLayer{0}; iLayer < constants::its2::LayersNumber; ++iLayer) { + this->mRmin[iLayer] = rmin[iLayer]; + this->mRmax[iLayer] = rmax[iLayer]; + + this->mClusters[iLayer] = + Vector<Cluster>{&clusters[iLayer][0], static_cast<int>(clusters[iLayer].size())}; + + if (iLayer < constants::its2::TrackletsPerRoad) { + this->mTracklets[iLayer].reset(tracklets[iLayer].capacity()); + } + + if (iLayer < constants::its2::CellsPerRoad) { + + this->mTrackletsLookupTable[iLayer].reset(static_cast<int>(clusters[iLayer + 1].size())); + this->mTrackletsPerClusterTable[iLayer].reset(static_cast<int>(clusters[iLayer + 1].size())); + this->mCells[iLayer].reset(static_cast<int>(cells[iLayer].capacity())); + } + + if (iLayer < constants::its2::CellsPerRoad - 1) { + + this->mCellsLookupTable[iLayer].reset(static_cast<int>(cellsLookupTable[iLayer].size())); + this->mCellsPerTrackletTable[iLayer].reset(static_cast<int>(cellsLookupTable[iLayer].size())); + } + } + + UniquePointer<DeviceStoreNV> gpuContextDevicePointer{*this}; + + std::array<Stream, constants::its2::LayersNumber> streamArray; + + for (int iLayer{0}; iLayer < constants::its2::TrackletsPerRoad; ++iLayer) { + + const int nextLayerClustersNum = static_cast<int>(clusters[iLayer + 1].size()); + + dim3 threadsPerBlock{utils::host::getBlockSize(nextLayerClustersNum)}; + dim3 blocksGrid{utils::host::getBlocksGrid(threadsPerBlock, nextLayerClustersNum)}; + + fillDeviceStructures<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(*gpuContextDevicePointer, iLayer); + + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + + std::ostringstream errorString{}; + errorString << __FILE__ << ":" << __LINE__ << " CUDA API returned error [" << cudaGetErrorString(error) + << "] (code " << error << ")" << std::endl; + + throw std::runtime_error{errorString.str()}; + } + } + + return gpuContextDevicePointer; +} + +} // namespace gpu +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreVertexerGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreVertexerGPU.cu similarity index 83% rename from Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreVertexerGPU.cu rename to Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreVertexerGPU.cu index cdcec77a16029..d5abcb87bf52f 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreVertexerGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/DeviceStoreVertexerGPU.cu @@ -1,27 +1,26 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// -/// \file DeviceStoreVertexerGPU.cu -/// \brief /// \author matteo.concas@cern.ch #include <iostream> -#include "ITStrackingCUDA/DeviceStoreVertexerGPU.h" +#include "ITStrackingGPU/DeviceStoreVertexerGPU.h" #include "ITStracking/Configuration.h" namespace o2 { namespace its { -namespace GPU +namespace gpu { GPUg() void defaultInitArrayKernel(int* array, const size_t arraySize, const int initValue = 0) { @@ -47,7 +46,7 @@ DeviceStoreVertexerGPU::DeviceStoreVertexerGPU() mBeamPosition = Vector<float>{2, 2}; for (int iTable{0}; iTable < 2; ++iTable) { - mIndexTables[iTable] = Vector<int>{constants::index_table::ZBins * constants::index_table::PhiBins + 1}; // 2*20*20+1 * sizeof(int) = 802B + mIndexTables[iTable] = Vector<int>{constants::its2::ZBins * constants::its2::PhiBins + 1}; // 2*20*20+1 * sizeof(int) = 802B } for (int iLayer{0}; iLayer < constants::its::LayersNumberVertexer; ++iLayer) { // 4e4 * 3 * sizof(Cluster) = 3.36MB mClusters[iLayer] = Vector<Cluster>{mGPUConf.clustersPerLayerCapacity, mGPUConf.clustersPerLayerCapacity}; @@ -65,11 +64,10 @@ DeviceStoreVertexerGPU::DeviceStoreVertexerGPU() } mSizes = Vector<int>{constants::its::LayersNumberVertexer}; #endif -} // namespace GPU +} // namespace gpu UniquePointer<DeviceStoreVertexerGPU> DeviceStoreVertexerGPU::initialise(const std::array<std::vector<Cluster>, constants::its::LayersNumberVertexer>& clusters, - const std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::LayersNumberVertexer>& indexTables) + const std::array<std::vector<int>, constants::its::LayersNumberVertexer>& indexTables) { #ifdef _ALLOW_DEBUG_TREES_ITS_ std::array<int, constants::its::LayersNumberVertexer> tmpSizes = {static_cast<int>(clusters[0].size()), @@ -83,8 +81,8 @@ UniquePointer<DeviceStoreVertexerGPU> DeviceStoreVertexerGPU::initialise(const s mIndexTables[0].reset(indexTables[0].data(), static_cast<int>(indexTables[0].size())); mIndexTables[1].reset(indexTables[2].data(), static_cast<int>(indexTables[2].size())); - const dim3 threadsPerBlock{Utils::Host::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{Utils::Host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; + const dim3 threadsPerBlock{utils::host::getBlockSize(mClusters[1].capacity())}; + const dim3 blocksGrid{utils::host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; UniquePointer<DeviceStoreVertexerGPU> deviceStoreVertexerPtr{*this}; @@ -104,6 +102,6 @@ GPUd() const Vector<int>& DeviceStoreVertexerGPU::getIndexTable(const VertexerLa return mIndexTables[1]; } -} // namespace GPU +} // namespace gpu } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu new file mode 100644 index 0000000000000..ae2a7b2a0263a --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// + +#include "ITStrackingGPU/Stream.h" + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +Stream::Stream() +{ + discardResult(cudaStreamCreateWithFlags(&mStream, cudaStreamNonBlocking)); +} +// usles +Stream::~Stream() +{ + discardResult(cudaStreamDestroy(mStream)); +} + +const GPUStream& Stream::get() const +{ + return mStream; +} + +} // namespace gpu +} // namespace its +} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cu new file mode 100644 index 0000000000000..0cfc318d42364 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cu @@ -0,0 +1,535 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TrackerTraitsNV.cu +/// \brief +/// + +#include <array> +#include <sstream> +#include <iostream> + +#ifndef GPUCA_GPUCODE_GENRTC +#include <cooperative_groups.h> +#include "cub/cub.cuh" +#endif + +#include "ITStracking/Constants.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/IndexTableUtils.h" +#include "ITStracking/MathUtils.h" + +#include "ITStrackingGPU/Context.h" +#include "ITStrackingGPU/DeviceStoreGPU.h" +#include "ITStrackingGPU/PrimaryVertexContextGPU.h" +#include "ITStrackingGPU/Stream.h" +#include "ITStrackingGPU/Vector.h" +#include "ITStrackingGPU/TrackerTraitsGPU.h" + +namespace o2 +{ +namespace its +{ + +using namespace constants::its2; +GPUd() const int4 getBinsRect(const Cluster& currentCluster, const int layerIndex, + const float z1, const float z2, float maxdeltaz, float maxdeltaphi) +{ + const float zRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; + const float phiRangeMin = currentCluster.phi - maxdeltaphi; + const float zRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; + const float phiRangeMax = currentCluster.phi + maxdeltaphi; + + if (zRangeMax < -LayersZCoordinate()[layerIndex + 1] || + zRangeMin > LayersZCoordinate()[layerIndex + 1] || zRangeMin > zRangeMax) { + + return getEmptyBinsRect(); + } + + return int4{o2::gpu::GPUCommonMath::Max(0, getZBinIndex(layerIndex + 1, zRangeMin)), + getPhiBinIndex(phiRangeMin), + o2::gpu::GPUCommonMath::Min(ZBins - 1, getZBinIndex(layerIndex + 1, zRangeMax)), + getPhiBinIndex(phiRangeMax)}; +} + +namespace gpu +{ + +struct StaticTrackingParameters { + StaticTrackingParameters& operator=(const StaticTrackingParameters& t); + + int CellMinimumLevel(); + + /// General parameters + int ClusterSharing = 0; + int MinTrackLength = 7; + /// Trackleting cuts + float TrackletMaxDeltaPhi = 0.3f; + float TrackletMaxDeltaZ[constants::its2::TrackletsPerRoad] = {0.1f, 0.1f, 0.3f, 0.3f, 0.3f, 0.3f}; + /// Cell finding cuts + float CellMaxDeltaTanLambda = 0.025f; + float CellMaxDCA[constants::its2::CellsPerRoad] = {0.05f, 0.04f, 0.05f, 0.2f, 0.4f}; + float CellMaxDeltaPhi = 0.14f; + float CellMaxDeltaZ[constants::its2::CellsPerRoad] = {0.2f, 0.4f, 0.5f, 0.6f, 3.0f}; + /// Neighbour finding cuts + float NeighbourMaxDeltaCurvature[constants::its2::CellsPerRoad - 1] = {0.008f, 0.0025f, 0.003f, 0.0035f}; + float NeighbourMaxDeltaN[constants::its2::CellsPerRoad - 1] = {0.002f, 0.0090f, 0.002f, 0.005f}; +}; +__constant__ StaticTrackingParameters kTrkPar; + +GPUd() void computeLayerTracklets(DeviceStoreNV& devStore, const int layerIndex, + Vector<Tracklet>& trackletsVector) +{ + const int currentClusterIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); + int clusterTrackletsNum = 0; + + if (currentClusterIndex < devStore.getClusters()[layerIndex].size()) { + + Vector<Cluster> nextLayerClusters{devStore.getClusters()[layerIndex + 1].getWeakCopy()}; + const Cluster currentCluster{devStore.getClusters()[layerIndex][currentClusterIndex]}; + + /*if (mUsedClustersTable[currentCluster.clusterId] != constants::its::UnusedIndex) { + + continue; + }*/ + + const float tanLambda{(currentCluster.zCoordinate - devStore.getPrimaryVertex().z) / currentCluster.radius}; + const float zAtRmin{tanLambda * (devStore.getRmin(layerIndex + 1) - currentCluster.radius) + currentCluster.zCoordinate}; + const float zAtRmax{tanLambda * (devStore.getRmax(layerIndex + 1) - currentCluster.radius) + currentCluster.zCoordinate}; + + const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex, zAtRmin, zAtRmax, + kTrkPar.TrackletMaxDeltaZ[layerIndex], kTrkPar.TrackletMaxDeltaPhi)}; + + if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { + + const int nextLayerClustersNum{static_cast<int>(nextLayerClusters.size())}; + int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; + + if (phiBinsNum < 0) { + + phiBinsNum += constants::its2::PhiBins; + } + + for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; + iPhiBin = ++iPhiBin == constants::its2::PhiBins ? 0 : iPhiBin, iPhiCount++) { + + const int firstBinIndex{constants::its2::getBinIndex(selectedBinsRect.x, iPhiBin)}; + const int firstRowClusterIndex = devStore.getIndexTables()[layerIndex][firstBinIndex]; + const int maxRowClusterIndex = devStore.getIndexTables()[layerIndex][{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}]; + + for (int iNextLayerCluster{firstRowClusterIndex}; + iNextLayerCluster <= maxRowClusterIndex && iNextLayerCluster < nextLayerClustersNum; ++iNextLayerCluster) { + + const Cluster& nextCluster{nextLayerClusters[iNextLayerCluster]}; + + const float deltaZ{o2::gpu::GPUCommonMath::Abs( + tanLambda * (nextCluster.radius - currentCluster.radius) + currentCluster.zCoordinate - nextCluster.zCoordinate)}; + const float deltaPhi{o2::gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi)}; + + if (deltaZ < kTrkPar.TrackletMaxDeltaZ[layerIndex] && (deltaPhi < kTrkPar.TrackletMaxDeltaPhi || o2::gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < kTrkPar.TrackletMaxDeltaPhi)) { + + cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); + int currentIndex{}; + + if (threadGroup.thread_rank() == 0) { + + currentIndex = trackletsVector.extend(threadGroup.size()); + } + + currentIndex = threadGroup.shfl(currentIndex, 0) + threadGroup.thread_rank(); + + trackletsVector.emplace(currentIndex, currentClusterIndex, iNextLayerCluster, currentCluster, nextCluster); + ++clusterTrackletsNum; + } + } + } + + if (layerIndex > 0) { + + devStore.getTrackletsPerClusterTable()[layerIndex - 1][currentClusterIndex] = clusterTrackletsNum; + } + } + } +} + +GPUd() void computeLayerCells(DeviceStoreNV& devStore, const int layerIndex, + Vector<Cell>& cellsVector) +{ + const int currentTrackletIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); + const float3& primaryVertex = devStore.getPrimaryVertex(); + int trackletCellsNum = 0; + + if (currentTrackletIndex < devStore.getTracklets()[layerIndex].size()) { + + const Tracklet& currentTracklet{devStore.getTracklets()[layerIndex][currentTrackletIndex]}; + const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; + const int nextLayerFirstTrackletIndex{ + devStore.getTrackletsLookupTable()[layerIndex][nextLayerClusterIndex]}; + const int nextLayerTrackletsNum{static_cast<int>(devStore.getTracklets()[layerIndex + 1].size())}; + + if (devStore.getTracklets()[layerIndex + 1][nextLayerFirstTrackletIndex].firstClusterIndex == nextLayerClusterIndex) { + + const Cluster& firstCellCluster{ + devStore.getClusters()[layerIndex][currentTracklet.firstClusterIndex]}; + const Cluster& secondCellCluster{ + devStore.getClusters()[layerIndex + 1][currentTracklet.secondClusterIndex]}; + const float firstCellClusterQuadraticRCoordinate{firstCellCluster.radius * firstCellCluster.radius}; + const float secondCellClusterQuadraticRCoordinate{secondCellCluster.radius * secondCellCluster.radius}; + const float3 firstDeltaVector{secondCellCluster.xCoordinate - firstCellCluster.xCoordinate, + secondCellCluster.yCoordinate - firstCellCluster.yCoordinate, secondCellClusterQuadraticRCoordinate - firstCellClusterQuadraticRCoordinate}; + + for (int iNextLayerTracklet{nextLayerFirstTrackletIndex}; + iNextLayerTracklet < nextLayerTrackletsNum && devStore.getTracklets()[layerIndex + 1][iNextLayerTracklet].firstClusterIndex == nextLayerClusterIndex; ++iNextLayerTracklet) { + + const Tracklet& nextTracklet{devStore.getTracklets()[layerIndex + 1][iNextLayerTracklet]}; + const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; + const float deltaPhi{o2::gpu::GPUCommonMath::Abs(currentTracklet.phi - nextTracklet.phi)}; + + if (deltaTanLambda < kTrkPar.CellMaxDeltaTanLambda && (deltaPhi < kTrkPar.CellMaxDeltaPhi || o2::gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < kTrkPar.CellMaxDeltaPhi)) { + + const float averageTanLambda{0.5f * (currentTracklet.tanLambda + nextTracklet.tanLambda)}; + const float directionZIntersection{-averageTanLambda * firstCellCluster.radius + firstCellCluster.zCoordinate}; + const float deltaZ{o2::gpu::GPUCommonMath::Abs(directionZIntersection - primaryVertex.z)}; + + if (deltaZ < kTrkPar.CellMaxDeltaZ[layerIndex]) { + + const Cluster& thirdCellCluster{ + devStore.getClusters()[layerIndex + 2][nextTracklet.secondClusterIndex]}; + + const float thirdCellClusterQuadraticRCoordinate{thirdCellCluster.radius * thirdCellCluster.radius}; + + const float3 secondDeltaVector{thirdCellCluster.xCoordinate - firstCellCluster.xCoordinate, + thirdCellCluster.yCoordinate - firstCellCluster.yCoordinate, thirdCellClusterQuadraticRCoordinate - firstCellClusterQuadraticRCoordinate}; + + float3 cellPlaneNormalVector{math_utils::crossProduct(firstDeltaVector, secondDeltaVector)}; + + const float vectorNorm{o2::gpu::GPUCommonMath::Sqrt( + cellPlaneNormalVector.x * cellPlaneNormalVector.x + cellPlaneNormalVector.y * cellPlaneNormalVector.y + cellPlaneNormalVector.z * cellPlaneNormalVector.z)}; + + if (!(vectorNorm < constants::math::FloatMinThreshold || o2::gpu::GPUCommonMath::Abs(cellPlaneNormalVector.z) < constants::math::FloatMinThreshold)) { + + const float inverseVectorNorm{1.0f / vectorNorm}; + const float3 normalizedPlaneVector{cellPlaneNormalVector.x * inverseVectorNorm, cellPlaneNormalVector.y * inverseVectorNorm, cellPlaneNormalVector.z * inverseVectorNorm}; + const float planeDistance{-normalizedPlaneVector.x * (secondCellCluster.xCoordinate - primaryVertex.x) - (normalizedPlaneVector.y * secondCellCluster.yCoordinate - primaryVertex.y) - normalizedPlaneVector.z * secondCellClusterQuadraticRCoordinate}; + const float normalizedPlaneVectorQuadraticZCoordinate{normalizedPlaneVector.z * normalizedPlaneVector.z}; + const float cellTrajectoryRadius{o2::gpu::GPUCommonMath::Sqrt( + (1.0f - normalizedPlaneVectorQuadraticZCoordinate - 4.0f * planeDistance * normalizedPlaneVector.z) / (4.0f * normalizedPlaneVectorQuadraticZCoordinate))}; + const float2 circleCenter{-0.5f * normalizedPlaneVector.x / normalizedPlaneVector.z, -0.5f * normalizedPlaneVector.y / normalizedPlaneVector.z}; + const float distanceOfClosestApproach{o2::gpu::GPUCommonMath::Abs( + cellTrajectoryRadius - o2::gpu::GPUCommonMath::Sqrt(circleCenter.x * circleCenter.x + circleCenter.y * circleCenter.y))}; + + if (distanceOfClosestApproach <= kTrkPar.CellMaxDCA[layerIndex]) { + + cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); + int currentIndex{}; + + if (threadGroup.thread_rank() == 0) { + + currentIndex = cellsVector.extend(threadGroup.size()); + } + + currentIndex = threadGroup.shfl(currentIndex, 0) + threadGroup.thread_rank(); + + cellsVector.emplace(currentIndex, currentTracklet.firstClusterIndex, + nextTracklet.firstClusterIndex, nextTracklet.secondClusterIndex, currentTrackletIndex, + iNextLayerTracklet, normalizedPlaneVector, 1.0f / cellTrajectoryRadius); + ++trackletCellsNum; + } + } + } + } + } + + if (layerIndex > 0) { + + devStore.getCellsPerTrackletTable()[layerIndex - 1][currentTrackletIndex] = trackletCellsNum; + } + } + } +} + +GPUg() void layerTrackletsKernel(DeviceStoreNV& devStore, const int layerIndex, + Vector<Tracklet> trackletsVector) +{ + computeLayerTracklets(devStore, layerIndex, trackletsVector); +} + +GPUg() void sortTrackletsKernel(DeviceStoreNV& devStore, const int layerIndex, + Vector<Tracklet> tempTrackletArray) +{ + const int currentTrackletIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; + + if (currentTrackletIndex < tempTrackletArray.size()) { + + const int firstClusterIndex = tempTrackletArray[currentTrackletIndex].firstClusterIndex; + const int offset = atomicAdd(&devStore.getTrackletsPerClusterTable()[layerIndex - 1][firstClusterIndex], + -1) - + 1; + const int startIndex = devStore.getTrackletsLookupTable()[layerIndex - 1][firstClusterIndex]; + + memcpy(&devStore.getTracklets()[layerIndex][startIndex + offset], + &tempTrackletArray[currentTrackletIndex], sizeof(Tracklet)); + } +} + +GPUg() void layerCellsKernel(DeviceStoreNV& devStore, const int layerIndex, + Vector<Cell> cellsVector) +{ + computeLayerCells(devStore, layerIndex, cellsVector); +} + +GPUg() void sortCellsKernel(DeviceStoreNV& devStore, const int layerIndex, + Vector<Cell> tempCellsArray) +{ + const int currentCellIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); + + if (currentCellIndex < tempCellsArray.size()) { + + const int firstTrackletIndex = tempCellsArray[currentCellIndex].getFirstTrackletIndex(); + const int offset = atomicAdd(&devStore.getCellsPerTrackletTable()[layerIndex - 1][firstTrackletIndex], + -1) - + 1; + const int startIndex = devStore.getCellsLookupTable()[layerIndex - 1][firstTrackletIndex]; + + memcpy(&devStore.getCells()[layerIndex][startIndex + offset], &tempCellsArray[currentCellIndex], + sizeof(Cell)); + } +} + +} // namespace gpu + +TrackerTraits* createTrackerTraitsNV() +{ + return new TrackerTraitsNV; +} + +void TrackerTraitsNV::computeLayerTracklets() +{ + PrimaryVertexContextNV* primaryVertexContext = static_cast<PrimaryVertexContextNV*>(nullptr); //TODO: FIX THIS with Time Frames + + // cudaMemcpyToSymbol(gpu::kTrkPar, &mTrkParams, sizeof(TrackingParameters)); + std::array<size_t, constants::its2::CellsPerRoad> tempSize; + std::array<int, constants::its2::CellsPerRoad> trackletsNum; + std::array<gpu::Stream, constants::its2::TrackletsPerRoad> streamArray; + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad; ++iLayer) { + + tempSize[iLayer] = 0; + primaryVertexContext->getTempTrackletArray()[iLayer].reset( + static_cast<int>(primaryVertexContext->getDeviceTracklets()[iLayer + 1].capacity())); + + cub::DeviceScan::ExclusiveSum(static_cast<void*>(NULL), tempSize[iLayer], + primaryVertexContext->getDeviceTrackletsPerClustersTable()[iLayer].get(), + primaryVertexContext->getDeviceTrackletsLookupTable()[iLayer].get(), + primaryVertexContext->getClusters()[iLayer + 1].size()); + + primaryVertexContext->getTempTableArray()[iLayer].reset(static_cast<int>(tempSize[iLayer])); + } + + cudaDeviceSynchronize(); + + for (int iLayer{0}; iLayer < constants::its2::TrackletsPerRoad; ++iLayer) { + + const gpu::DeviceProperties& deviceProperties = gpu::Context::getInstance().getDeviceProperties(); + const int clustersNum{static_cast<int>(primaryVertexContext->getClusters()[iLayer].size())}; + dim3 threadsPerBlock{gpu::utils::host::getBlockSize(clustersNum, 1, 192)}; + dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, clustersNum)}; + + if (iLayer == 0) { + + gpu::layerTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer, primaryVertexContext->getDeviceTracklets()[iLayer].getWeakCopy()); + + } else { + + gpu::layerTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer, primaryVertexContext->getTempTrackletArray()[iLayer - 1].getWeakCopy()); + } + + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + + std::ostringstream errorString{}; + errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" + << std::endl; + + throw std::runtime_error{errorString.str()}; + } + } + + cudaDeviceSynchronize(); + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad; ++iLayer) { + + trackletsNum[iLayer] = primaryVertexContext->getTempTrackletArray()[iLayer].getSizeFromDevice(); + if (trackletsNum[iLayer] == 0) { + continue; + } + primaryVertexContext->getDeviceTracklets()[iLayer + 1].resize(trackletsNum[iLayer]); + + cub::DeviceScan::ExclusiveSum(static_cast<void*>(primaryVertexContext->getTempTableArray()[iLayer].get()), tempSize[iLayer], + primaryVertexContext->getDeviceTrackletsPerClustersTable()[iLayer].get(), + primaryVertexContext->getDeviceTrackletsLookupTable()[iLayer].get(), + primaryVertexContext->getClusters()[iLayer + 1].size(), streamArray[iLayer + 1].get()); + + dim3 threadsPerBlock{gpu::utils::host::getBlockSize(trackletsNum[iLayer])}; + dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, trackletsNum[iLayer])}; + + gpu::sortTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer + 1].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer + 1, primaryVertexContext->getTempTrackletArray()[iLayer].getWeakCopy()); + + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + + std::ostringstream errorString{}; + errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" + << std::endl; + + throw std::runtime_error{errorString.str()}; + } + } +} + +void TrackerTraitsNV::computeLayerCells() +{ + + PrimaryVertexContextNV* primaryVertexContext = static_cast<PrimaryVertexContextNV*>(nullptr); //TODO: FIX THIS with Time Frames + std::array<size_t, constants::its2::CellsPerRoad - 1> tempSize; + std::array<int, constants::its2::CellsPerRoad - 1> trackletsNum; + std::array<int, constants::its2::CellsPerRoad - 1> cellsNum; + std::array<gpu::Stream, constants::its2::CellsPerRoad> streamArray; + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad - 1; ++iLayer) { + + tempSize[iLayer] = 0; + trackletsNum[iLayer] = primaryVertexContext->getDeviceTracklets()[iLayer + 1].getSizeFromDevice(); + primaryVertexContext->getTempCellArray()[iLayer].reset( + static_cast<int>(primaryVertexContext->getDeviceCells()[iLayer + 1].capacity())); + if (trackletsNum[iLayer] == 0) { + continue; + } + cub::DeviceScan::ExclusiveSum(static_cast<void*>(NULL), tempSize[iLayer], + primaryVertexContext->getDeviceCellsPerTrackletTable()[iLayer].get(), + primaryVertexContext->getDeviceCellsLookupTable()[iLayer].get(), trackletsNum[iLayer]); + + primaryVertexContext->getTempTableArray()[iLayer].reset(static_cast<int>(tempSize[iLayer])); + } + + cudaDeviceSynchronize(); + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad; ++iLayer) { + const gpu::DeviceProperties& deviceProperties = gpu::Context::getInstance().getDeviceProperties(); + const int trackletsSize = primaryVertexContext->getDeviceTracklets()[iLayer].getSizeFromDevice(); + if (trackletsSize == 0) { + continue; + } + dim3 threadsPerBlock{gpu::utils::host::getBlockSize(trackletsSize)}; + dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, trackletsSize)}; + + if (iLayer == 0) { + + gpu::layerCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer, primaryVertexContext->getDeviceCells()[iLayer].getWeakCopy()); + + } else { + + gpu::layerCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer, primaryVertexContext->getTempCellArray()[iLayer - 1].getWeakCopy()); + } + + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + + std::ostringstream errorString{}; + errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" + << std::endl; + + throw std::runtime_error{errorString.str()}; + } + } + + cudaDeviceSynchronize(); + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad - 1; ++iLayer) { + cellsNum[iLayer] = primaryVertexContext->getTempCellArray()[iLayer].getSizeFromDevice(); + if (cellsNum[iLayer] == 0) { + continue; + } + primaryVertexContext->getDeviceCells()[iLayer + 1].resize(cellsNum[iLayer]); + + cub::DeviceScan::ExclusiveSum(static_cast<void*>(primaryVertexContext->getTempTableArray()[iLayer].get()), tempSize[iLayer], + primaryVertexContext->getDeviceCellsPerTrackletTable()[iLayer].get(), + primaryVertexContext->getDeviceCellsLookupTable()[iLayer].get(), trackletsNum[iLayer], + streamArray[iLayer + 1].get()); + + dim3 threadsPerBlock{gpu::utils::host::getBlockSize(trackletsNum[iLayer])}; + dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, trackletsNum[iLayer])}; + + gpu::sortCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer + 1].get()>>>(primaryVertexContext->getDeviceContext(), + iLayer + 1, primaryVertexContext->getTempCellArray()[iLayer].getWeakCopy()); + + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + + std::ostringstream errorString{}; + errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" + << std::endl; + + throw std::runtime_error{errorString.str()}; + } + } + + cudaDeviceSynchronize(); + + for (int iLayer{0}; iLayer < constants::its2::CellsPerRoad; ++iLayer) { + + int cellsSize = 0; + if (iLayer == 0) { + + cellsSize = primaryVertexContext->getDeviceCells()[iLayer].getSizeFromDevice(); + if (cellsSize == 0) { + continue; + } + } else { + + cellsSize = cellsNum[iLayer - 1]; + if (cellsSize == 0) { + continue; + } + primaryVertexContext->getDeviceCellsLookupTable()[iLayer - 1].copyIntoVector( + primaryVertexContext->getCellsLookupTable()[iLayer - 1], trackletsNum[iLayer - 1]); + } + + primaryVertexContext->getDeviceCells()[iLayer].copyIntoVector(primaryVertexContext->getCells()[iLayer], cellsSize); + } +} + +void TrackerTraitsNV::refitTracks(const std::vector<std::vector<TrackingFrameInfo>>& tf, std::vector<TrackITSExt>& tracks) +{ + PrimaryVertexContextNV* pvctx = static_cast<PrimaryVertexContextNV*>(nullptr); //TODO: FIX THIS with Time Frames + + std::array<const Cell*, 5> cells; + for (int iLayer = 0; iLayer < 5; iLayer++) { + cells[iLayer] = pvctx->getDeviceCells()[iLayer].get(); + } + std::array<const Cluster*, 7> clusters; + for (int iLayer = 0; iLayer < 7; iLayer++) { + clusters[iLayer] = pvctx->getDeviceClusters()[iLayer].get(); + } + //TODO: restore this + // mChainRunITSTrackFit(*mChain, mPrimaryVertexContext->getRoads(), clusters, cells, tf, tracks); +} +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu new file mode 100644 index 0000000000000..404702ab010ca --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu @@ -0,0 +1,182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITStrackingGPU/Utils.h" +#include "ITStrackingGPU/Context.h" + +#include <sstream> +#include <stdexcept> + +#if !defined(GPUCA_GPUCODE_GENRTC) && !defined(__HIPCC__) +#include <cuda_profiler_api.h> +#include <cooperative_groups.h> +#endif + +#include <iostream> + +namespace +{ + +int roundUp(const int numToRound, const int multiple) +{ + if (multiple == 0) { + return numToRound; + } + + int remainder{numToRound % multiple}; + if (remainder == 0) { + return numToRound; + } + return numToRound + multiple - remainder; +} + +int findNearestDivisor(const int numToRound, const int divisor) +{ + + if (numToRound > divisor) { + return divisor; + } + + int result = numToRound; + while (divisor % result != 0) { + ++result; + } + return result; +} + +} // namespace + +namespace o2 +{ +namespace its +{ +namespace gpu +{ + +void utils::host::checkGPUError(const cudaError_t error, const char* file, const int line) +{ + if (error != cudaSuccess) { + std::ostringstream errorString{}; + errorString << file << ":" << line << GPU_ARCH << " API returned error [" << cudaGetErrorString(error) << "] (code " + << error << ")" << std::endl; + throw std::runtime_error{errorString.str()}; + } +} + +dim3 utils::host::getBlockSize(const int colsNum) +{ + return getBlockSize(colsNum, 1); +} + +dim3 utils::host::getBlockSize(const int colsNum, const int rowsNum) +{ + const DeviceProperties& deviceProperties = Context::getInstance().getDeviceProperties(); + return getBlockSize(colsNum, rowsNum, deviceProperties.gpuCores / deviceProperties.maxBlocksPerSM); +} + +dim3 utils::host::getBlockSize(const int colsNum, const int rowsNum, const int maxThreadsPerBlock) +{ + const DeviceProperties& deviceProperties = Context::getInstance().getDeviceProperties(); + int xThreads = max(min(colsNum, deviceProperties.maxThreadsDim.x), 1); + int yThreads = max(min(rowsNum, deviceProperties.maxThreadsDim.y), 1); + const int totalThreads = roundUp(min(xThreads * yThreads, maxThreadsPerBlock), + deviceProperties.warpSize); + + if (xThreads > yThreads) { + + xThreads = findNearestDivisor(xThreads, totalThreads); + yThreads = totalThreads / xThreads; + + } else { + + yThreads = findNearestDivisor(yThreads, totalThreads); + xThreads = totalThreads / yThreads; + } + + return dim3{static_cast<unsigned int>(xThreads), static_cast<unsigned int>(yThreads)}; +} + +dim3 utils::host::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum) +{ + + return getBlocksGrid(threadsPerBlock, rowsNum, 1); +} + +dim3 utils::host::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum, const int colsNum) +{ + + return dim3{1 + (rowsNum - 1) / threadsPerBlock.x, 1 + (colsNum - 1) / threadsPerBlock.y}; +} + +void utils::host::gpuMalloc(void** p, const int size) +{ + checkGPUError(cudaMalloc(p, size), __FILE__, __LINE__); +} + +void utils::host::gpuFree(void* p) +{ + checkGPUError(cudaFree(p), __FILE__, __LINE__); +} + +void utils::host::gpuMemset(void* p, int value, int size) +{ + checkGPUError(cudaMemset(p, value, size), __FILE__, __LINE__); +} + +void utils::host::gpuMemcpyHostToDevice(void* dst, const void* src, int size) +{ + checkGPUError(cudaMemcpy(dst, src, size, cudaMemcpyHostToDevice), __FILE__, __LINE__); +} + +// void utils::host::gpuMemcpyHostToDeviceAsync(void* dst, const void* src, int size, Stream& stream) +// { +// checkGPUError(cudaMemcpyAsync(dst, src, size, cudaMemcpyHostToDevice, stream.get()), __FILE__, __LINE__); +// } + +void utils::host::gpuMemcpyDeviceToHost(void* dst, const void* src, int size) +{ + checkGPUError(cudaMemcpy(dst, src, size, cudaMemcpyDeviceToHost), __FILE__, __LINE__); +} + +// void utils::host::gpuStartProfiler() +// { +// checkGPUError(cudaProfilerStart(), __FILE__, __LINE__); +// } + +// void utils::host::gpuStopProfiler() +// { +// checkGPUError(cudaProfilerStop(), __FILE__, __LINE__); +// } + +GPUd() int utils::device::getLaneIndex() +{ + uint32_t laneIndex; + asm volatile("mov.u32 %0, %%laneid;" + : "=r"(laneIndex)); + return static_cast<int>(laneIndex); +} + +#ifndef __HIPCC__ +GPUd() int utils::device::shareToWarp(const int value, const int laneIndex) +{ + cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); + return threadGroup.shfl(value, laneIndex); +} + +GPUd() int utils::device::gpuAtomicAdd(int* p, const int incrementSize) +{ + return atomicAdd(p, incrementSize); +} +#endif + +} // namespace gpu +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu new file mode 100644 index 0000000000000..9d6afd853783a --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu @@ -0,0 +1,517 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \author matteo.concas@cern.ch + +#include <iostream> +#include <sstream> +#include <array> +#include <cassert> + +#ifndef GPUCA_GPUCODE_GENRTC +#include <cub/cub.cuh> +#endif + +#include "ITStracking/MathUtils.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/ClusterLines.h" +#include "ITStracking/Tracklet.h" + +#include "ITStrackingGPU/Utils.h" +#include "ITStrackingGPU/ClusterLinesGPU.h" +#include "ITStrackingGPU/Context.h" +#include "ITStrackingGPU/Stream.h" +#include "ITStrackingGPU/VertexerTraitsGPU.h" + +namespace o2 +{ +namespace its +{ + +using constants::its::VertexerHistogramVolume; +using constants::math::TwoPi; +using math_utils::getNormalizedPhi; + +using namespace constants::its2; +GPUd() const int4 getBinsRect(const Cluster& currentCluster, const int layerIndex, + const float z1, float maxdeltaz, float maxdeltaphi) +{ + const float zRangeMin = z1 - maxdeltaz; + const float phiRangeMin = currentCluster.phi - maxdeltaphi; + const float zRangeMax = z1 + maxdeltaz; + const float phiRangeMax = currentCluster.phi + maxdeltaphi; + + if (zRangeMax < -LayersZCoordinate()[layerIndex + 1] || + zRangeMin > LayersZCoordinate()[layerIndex + 1] || zRangeMin > zRangeMax) { + + return getEmptyBinsRect(); + } + + return int4{o2::gpu::GPUCommonMath::Max(0, getZBinIndex(layerIndex + 1, zRangeMin)), + getPhiBinIndex(phiRangeMin), + o2::gpu::GPUCommonMath::Min(ZBins - 1, getZBinIndex(layerIndex + 1, zRangeMax)), + getPhiBinIndex(phiRangeMax)}; +} + +GPUh() void gpuThrowOnError() +{ + cudaError_t error = cudaGetLastError(); + + if (error != cudaSuccess) { + std::ostringstream errorString{}; + errorString << GPU_ARCH << " API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" << std::endl; + throw std::runtime_error{errorString.str()}; + } +} + +#ifdef _ALLOW_DEBUG_TREES_ITS_ +VertexerTraitsGPU::VertexerTraitsGPU() +{ + setIsGPU(true); + std::cout << "[DEBUG] Creating file: dbg_ITSVertexerGPU.root" << std::endl; + mDebugger = new StandaloneDebugger::StandaloneDebugger("dbg_ITSVertexerGPU.root"); +} + +VertexerTraitsGPU::~VertexerTraitsGPU() +{ + delete mDebugger; +} +#else +VertexerTraitsGPU::VertexerTraitsGPU() +{ + setIsGPU(true); +} +#endif + +void VertexerTraitsGPU::initialise(ROframe* event) +{ + reset(); + arrangeClusters(event); + mStoreVertexerGPUPtr = mStoreVertexerGPU.initialise(mClusters, mIndexTables); +} + +namespace gpu +{ + +template <typename... Args> +GPUd() void printOnThread(const int tId, const char* str, Args... args) +{ + if (blockIdx.x * blockDim.x + threadIdx.x == tId) { + printf(str, args...); + } +} + +GPUd() void printVectorOnThread(const char* name, Vector<int>& vector, size_t size, const int tId = 0) +{ + if (blockIdx.x * blockDim.x + threadIdx.x == tId) { + printf("vector %s :", name); + for (int i{0}; i < size; ++i) { + printf("%d ", vector[i]); + } + printf("\n"); + } +} + +GPUg() void printVectorKernel(DeviceStoreVertexerGPU& store, const int threadId) +{ + if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { + for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[0] - 1; ++i) { + printf("%d: %d\n", i, store.getHistogramXYZ()[0].get()[i]); + } + printf("\n"); + for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[1] - 1; ++i) { + printf("%d: %d\n", i, store.getHistogramXYZ()[1].get()[i]); + } + printf("\n"); + for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[2] - 1; ++i) { + printf("%d: %d\n", i, store.getHistogramXYZ()[2].get()[i]); + } + printf("\n"); + } +} + +GPUg() void dumpMaximaKernel(DeviceStoreVertexerGPU& store, const int threadId) +{ + if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { + printf("XmaxBin: %d at index: %d | YmaxBin: %d at index: %d | ZmaxBin: %d at index: %d\n", + store.getTmpVertexPositionBins()[0].value, store.getTmpVertexPositionBins()[0].key, + store.getTmpVertexPositionBins()[1].value, store.getTmpVertexPositionBins()[1].key, + store.getTmpVertexPositionBins()[2].value, store.getTmpVertexPositionBins()[2].key); + } +} + +GPUg() void trackleterKernel( + DeviceStoreVertexerGPU& store, + const TrackletingLayerOrder layerOrder, + const float phiCut) +{ + const size_t nClustersMiddleLayer = store.getClusters()[1].size(); + for (size_t currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { + if (currentClusterIndex < nClustersMiddleLayer) { + int storedTracklets{0}; + const size_t stride{currentClusterIndex * store.getConfig().maxTrackletsPerCluster}; + const Cluster& currentCluster = store.getClusters()[1][currentClusterIndex]; // assign-constructor may be a problem, check + const VertexerLayerName adjacentLayerIndex{layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer ? VertexerLayerName::innermostLayer : VertexerLayerName::outerLayer}; + const int4 selectedBinsRect{getBinsRect(currentCluster, static_cast<int>(adjacentLayerIndex), 0.f, 50.f, phiCut / 2)}; + if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { + int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; + if (phiBinsNum < 0) { + phiBinsNum += PhiBins; + } + const size_t nClustersAdjacentLayer = store.getClusters()[static_cast<int>(adjacentLayerIndex)].size(); + for (size_t iPhiBin{(size_t)selectedBinsRect.y}, iPhiCount{0}; iPhiCount < (size_t)phiBinsNum; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { + const int firstBinIndex{constants::its2::getBinIndex(selectedBinsRect.x, iPhiBin)}; + const int firstRowClusterIndex{store.getIndexTable(adjacentLayerIndex)[firstBinIndex]}; + const int maxRowClusterIndex{store.getIndexTable(adjacentLayerIndex)[firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1]}; + for (size_t iAdjacentCluster{(size_t)firstRowClusterIndex}; iAdjacentCluster < (size_t)maxRowClusterIndex && iAdjacentCluster < nClustersAdjacentLayer; ++iAdjacentCluster) { + const Cluster& adjacentCluster = store.getClusters()[static_cast<int>(adjacentLayerIndex)][iAdjacentCluster]; // assign-constructor may be a problem, check + if (o2::gpu::GPUCommonMath::Abs(currentCluster.phi - adjacentCluster.phi) < phiCut) { + if (storedTracklets < store.getConfig().maxTrackletsPerCluster) { + if (layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer) { + store.getDuplets01().emplace(stride + storedTracklets, iAdjacentCluster, currentClusterIndex, adjacentCluster, currentCluster); + } else { + store.getDuplets12().emplace(stride + storedTracklets, currentClusterIndex, iAdjacentCluster, currentCluster, adjacentCluster); + } + ++storedTracklets; + } else { + printf("debug: leaving tracklet behind\n"); + } + } + } + } + } + store.getNFoundTracklets(layerOrder).emplace(currentClusterIndex, storedTracklets); + } + } +} + +GPUg() void trackletSelectionKernel( + DeviceStoreVertexerGPU& store, + const unsigned char isInitRun = false, + const float tanLambdaCut = 0.025f, + const float phiCut = 0.002f) +{ + const size_t nClustersMiddleLayer = store.getClusters()[1].size(); + for (size_t currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { + const int stride{static_cast<int>(currentClusterIndex * store.getConfig().maxTrackletsPerCluster)}; + int validTracklets{0}; + for (int iTracklet12{0}; iTracklet12 < store.getNFoundTracklets(TrackletingLayerOrder::fromMiddleToOuterLayer)[currentClusterIndex]; ++iTracklet12) { + for (int iTracklet01{0}; iTracklet01 < store.getNFoundTracklets(TrackletingLayerOrder::fromInnermostToMiddleLayer)[currentClusterIndex] && validTracklets < store.getConfig().maxTrackletsPerCluster; ++iTracklet01) { + const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(store.getDuplets01()[stride + iTracklet01].tanLambda - store.getDuplets12()[stride + iTracklet12].tanLambda)}; + const float deltaPhi{o2::gpu::GPUCommonMath::Abs(store.getDuplets01()[stride + iTracklet01].phi - store.getDuplets12()[stride + iTracklet12].phi)}; + if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != store.getConfig().maxTrackletsPerCluster) { + assert(store.getDuplets01()[stride + iTracklet01].secondClusterIndex == store.getDuplets12()[stride + iTracklet12].firstClusterIndex); + if (!isInitRun) { + store.getLines().emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, store.getDuplets01()[stride + iTracklet01], store.getClusters()[0].get(), store.getClusters()[1].get()); +#ifdef _ALLOW_DEBUG_TREES_ITS_ + store.getDupletIndices()[0].emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet01); + store.getDupletIndices()[1].emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet12); +#endif + } + ++validTracklets; + } + } + } + if (isInitRun) { + store.getNFoundLines().emplace(currentClusterIndex, validTracklets); + if (validTracklets >= store.getConfig().maxTrackletsPerCluster) { + printf("Warning: not enough space for tracklet selection, some lines will be left behind\n"); + } + } + } +} + +GPUg() void computeCentroidsKernel(DeviceStoreVertexerGPU& store, + const float pairCut) +{ + const int nLines = store.getNExclusiveFoundLines()[store.getClusters()[1].size() - 1] + store.getNFoundLines()[store.getClusters()[1].size() - 1]; + const int maxIterations{nLines * (nLines - 1) / 2}; + for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < maxIterations; currentThreadIndex += blockDim.x * gridDim.x) { + int iFirstLine = currentThreadIndex / nLines; + int iSecondLine = currentThreadIndex % nLines; + if (iSecondLine <= iFirstLine) { + iFirstLine = nLines - iFirstLine - 2; + iSecondLine = nLines - iSecondLine - 1; + } + if (Line::getDCA(store.getLines()[iFirstLine], store.getLines()[iSecondLine]) < pairCut) { + ClusterLinesGPU cluster{store.getLines()[iFirstLine], store.getLines()[iSecondLine]}; + if (cluster.getVertex()[0] * cluster.getVertex()[0] + cluster.getVertex()[1] * cluster.getVertex()[1] < 1.98f * 1.98f) { + // printOnThread(0, "xCentr: %f, yCentr: %f \n", cluster.getVertex()[0], cluster.getVertex()[1]); + store.getXYCentroids().emplace(2 * currentThreadIndex, cluster.getVertex()[0]); + store.getXYCentroids().emplace(2 * currentThreadIndex + 1, cluster.getVertex()[1]); + } else { + // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. + store.getXYCentroids().emplace(2 * currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[0]); + store.getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[1]); + } + } else { + // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. + store.getXYCentroids().emplace(2 * currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[0]); + store.getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[1]); + } + } +} + +GPUg() void computeZCentroidsKernel(DeviceStoreVertexerGPU& store, + const float pairCut, const int binOpeningX, const int binOpeningY) +{ + const int nLines = store.getNExclusiveFoundLines()[store.getClusters()[1].size() - 1] + store.getNFoundLines()[store.getClusters()[1].size() - 1]; + for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < nLines; currentThreadIndex += blockDim.x * gridDim.x) { + if (store.getTmpVertexPositionBins()[0].value || store.getTmpVertexPositionBins()[1].value) { + float tmpX{store.getConfig().histConf.lowHistBoundariesXYZ[0] + store.getTmpVertexPositionBins()[0].key * store.getConfig().histConf.binSizeHistX + store.getConfig().histConf.binSizeHistX / 2}; + int sumWX{store.getTmpVertexPositionBins()[0].value}; + float wX{tmpX * store.getTmpVertexPositionBins()[0].value}; + for (int iBin{o2::gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[0].key - binOpeningX)}; iBin < o2::gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[0].key + binOpeningX + 1, store.getConfig().histConf.nBinsXYZ[0] - 1); ++iBin) { + if (iBin != store.getTmpVertexPositionBins()[0].key) { + wX += (store.getConfig().histConf.lowHistBoundariesXYZ[0] + iBin * store.getConfig().histConf.binSizeHistX + store.getConfig().histConf.binSizeHistX / 2) * store.getHistogramXYZ()[0].get()[iBin]; + sumWX += store.getHistogramXYZ()[0].get()[iBin]; + } + } + float tmpY{store.getConfig().histConf.lowHistBoundariesXYZ[1] + store.getTmpVertexPositionBins()[1].key * store.getConfig().histConf.binSizeHistY + store.getConfig().histConf.binSizeHistY / 2}; + int sumWY{store.getTmpVertexPositionBins()[1].value}; + float wY{tmpY * store.getTmpVertexPositionBins()[1].value}; + for (int iBin{o2::gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[1].key - binOpeningY)}; iBin < o2::gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[1].key + binOpeningY + 1, store.getConfig().histConf.nBinsXYZ[1] - 1); ++iBin) { + if (iBin != store.getTmpVertexPositionBins()[1].key) { + wY += (store.getConfig().histConf.lowHistBoundariesXYZ[1] + iBin * store.getConfig().histConf.binSizeHistY + store.getConfig().histConf.binSizeHistY / 2) * store.getHistogramXYZ()[1].get()[iBin]; + sumWY += store.getHistogramXYZ()[1].get()[iBin]; + } + } + store.getBeamPosition().emplace(0, wX / sumWX); + store.getBeamPosition().emplace(1, wY / sumWY); + float fakeBeamPoint1[3] = {store.getBeamPosition()[0], store.getBeamPosition()[1], -1}; // get two points laying at different z, to create line object + float fakeBeamPoint2[3] = {store.getBeamPosition()[0], store.getBeamPosition()[1], 1}; + Line pseudoBeam = {fakeBeamPoint1, fakeBeamPoint2}; + if (Line::getDCA(store.getLines()[currentThreadIndex], pseudoBeam) < pairCut) { + ClusterLinesGPU cluster{store.getLines()[currentThreadIndex], pseudoBeam}; + store.getZCentroids().emplace(currentThreadIndex, cluster.getVertex()[2]); + } else { + store.getZCentroids().emplace(currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[2]); + } + } + } +} + +GPUg() void computeVertexKernel(DeviceStoreVertexerGPU& store, const int vertIndex, const int minContributors, const int binOpeningZ) +{ + for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < binOpeningZ; currentThreadIndex += blockDim.x * gridDim.x) { + if (currentThreadIndex == 0) { + if (store.getTmpVertexPositionBins()[2].value > 1 && (store.getTmpVertexPositionBins()[0].value || store.getTmpVertexPositionBins()[1].value)) { + float z{store.getConfig().histConf.lowHistBoundariesXYZ[2] + store.getTmpVertexPositionBins()[2].key * store.getConfig().histConf.binSizeHistZ + store.getConfig().histConf.binSizeHistZ / 2}; + float ex{0.f}; + float ey{0.f}; + float ez{0.f}; + int sumWZ{store.getTmpVertexPositionBins()[2].value}; + float wZ{z * store.getTmpVertexPositionBins()[2].value}; + for (int iBin{o2::gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[2].key - binOpeningZ)}; iBin < o2::gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[2].key + binOpeningZ + 1, store.getConfig().histConf.nBinsXYZ[2] - 1); ++iBin) { + if (iBin != store.getTmpVertexPositionBins()[2].key) { + wZ += (store.getConfig().histConf.lowHistBoundariesXYZ[2] + iBin * store.getConfig().histConf.binSizeHistZ + store.getConfig().histConf.binSizeHistZ / 2) * store.getHistogramXYZ()[2].get()[iBin]; + sumWZ += store.getHistogramXYZ()[2].get()[iBin]; + } + store.getHistogramXYZ()[2].get()[iBin] = 0; + } + if (sumWZ > minContributors || vertIndex == 0) { + store.getVertices().emplace(vertIndex, store.getBeamPosition()[0], store.getBeamPosition()[1], wZ / sumWZ, ex, ey, ez, sumWZ); + } else { + store.getVertices().emplace(vertIndex); + } + } else { + store.getVertices().emplace(vertIndex); + } + } + } +} +} // namespace gpu + +void VertexerTraitsGPU::computeTracklets() +{ + if (!mClusters[1].size()) { + std::cout << "\t\tno clusters on layer 1. Returning.\n"; + return; + } + const dim3 threadsPerBlock{gpu::utils::host::getBlockSize(mClusters[1].capacity())}; + const dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; + + gpu::trackleterKernel<<<blocksGrid, threadsPerBlock>>>( + getDeviceContext(), + gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer, + mVrtParams.phiCut); + + gpu::trackleterKernel<<<blocksGrid, threadsPerBlock>>>( + getDeviceContext(), + gpu::TrackletingLayerOrder::fromMiddleToOuterLayer, + mVrtParams.phiCut); + + gpuThrowOnError(); + +#ifdef _ALLOW_DEBUG_TREES_ITS_ + if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { + mDebugger->fillCombinatoricsTree(mClusters, + mStoreVertexerGPU.getDupletsFromGPU(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer), + mStoreVertexerGPU.getDupletsFromGPU(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer), + mEvent); + } +#endif +} + +void VertexerTraitsGPU::computeTrackletMatching() +{ + if (!mClusters[1].size()) { + std::cout << "\t\tno clusters on layer 1. Returning.\n"; + return; + } + const dim3 threadsPerBlock{gpu::utils::host::getBlockSize(mClusters[1].capacity())}; + const dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; + size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); + + gpu::trackletSelectionKernel<<<blocksGrid, threadsPerBlock>>>( + getDeviceContext(), + true, // isInitRun + mVrtParams.tanLambdaCut, + mVrtParams.phiCut); + + discardResult(cub::DeviceScan::ExclusiveSum(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), + bufferSize, + mStoreVertexerGPU.getNFoundLines().get(), + mStoreVertexerGPU.getNExclusiveFoundLines().get(), + mClusters[1].size())); + + gpu::trackletSelectionKernel<<<blocksGrid, threadsPerBlock>>>( + getDeviceContext(), + false, // isInitRun + mVrtParams.tanLambdaCut, + mVrtParams.phiCut); + + gpuThrowOnError(); + +#ifdef _ALLOW_DEBUG_TREES_ITS_ + if (isDebugFlag(VertexerDebug::TrackletTreeAll)) { + mDebugger->fillTrackletSelectionTree(mClusters, + mStoreVertexerGPU.getRawDupletsFromGPU(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer), + mStoreVertexerGPU.getRawDupletsFromGPU(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer), + mStoreVertexerGPU.getDupletIndicesFromGPU(), + mEvent); + } + mTracklets = mStoreVertexerGPU.getLinesFromGPU(); + if (isDebugFlag(VertexerDebug::LineTreeAll)) { + mDebugger->fillPairsInfoTree(mTracklets, mEvent); + } + if (isDebugFlag(VertexerDebug::LineSummaryAll)) { + mDebugger->fillLinesSummaryTree(mTracklets, mEvent); + } +#endif +} + +void VertexerTraitsGPU::computeVertices() +{ + if (!mClusters[1].size()) { + std::cout << "\t\tno clusters on layer 1. Returning.\n"; + return; + } + const dim3 threadsPerBlock{gpu::utils::host::getBlockSize(mClusters[1].capacity())}; + const dim3 blocksGrid{gpu::utils::host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; + size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); + int nLines = mStoreVertexerGPU.getNExclusiveFoundLines().getElementFromDevice(mClusters[1].size() - 1) + mStoreVertexerGPU.getNFoundLines().getElementFromDevice(mClusters[1].size() - 1); + int nCentroids{static_cast<int>(nLines * (nLines - 1) / 2)}; + int* histogramXY[2] = {mStoreVertexerGPU.getHistogramXYZ()[0].get(), mStoreVertexerGPU.getHistogramXYZ()[1].get()}; + float tmpArrayLow[2] = {mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[1]}; + float tmpArrayHigh[2] = {mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[1]}; + gpu::computeCentroidsKernel<<<blocksGrid, threadsPerBlock>>>(getDeviceContext(), + mVrtParams.histPairCut); + + discardResult(cub::DeviceHistogram::MultiHistogramEven<2, 2>(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage + bufferSize, // temp_storage_bytes + mStoreVertexerGPU.getXYCentroids().get(), // d_samples + histogramXY, // d_histogram + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ, // num_levels + tmpArrayLow, // lower_level + tmpArrayHigh, // fupper_level + nCentroids)); // num_row_pixels + discardResult(cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), + bufferSize, + histogramXY[0], + mStoreVertexerGPU.getTmpVertexPositionBins().get(), + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0])); + discardResult(cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), + bufferSize, + histogramXY[1], + mStoreVertexerGPU.getTmpVertexPositionBins().get() + 1, + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0])); + gpu::computeZCentroidsKernel<<<blocksGrid, threadsPerBlock>>>(getDeviceContext(), mVrtParams.histPairCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[0], mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[1]); + discardResult(cub::DeviceHistogram::HistogramEven(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage + bufferSize, // temp_storage_bytes + mStoreVertexerGPU.getZCentroids().get(), // d_samples + mStoreVertexerGPU.getHistogramXYZ()[2].get(), // d_histogram + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2], // num_levels + mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[2], // lower_level + mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[2], // fupper_level + nLines)); // num_row_pixels + for (int iVertex{0}; iVertex < mStoreVertexerGPU.getConfig().nMaxVertices; ++iVertex) { + discardResult(cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), + bufferSize, + mStoreVertexerGPU.getHistogramXYZ()[2].get(), + mStoreVertexerGPU.getTmpVertexPositionBins().get() + 2, + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2])); +#ifdef _ALLOW_DEBUG_TREES_ITS_ + if (isDebugFlag(VertexerDebug::HistCentroids) && !iVertex) { + mDebugger->fillXYZHistogramTree(std::array<std::vector<int>, 3>{mStoreVertexerGPU.getHistogramXYFromGPU()[0], + mStoreVertexerGPU.getHistogramXYFromGPU()[1], mStoreVertexerGPU.getHistogramZFromGPU()}, + std::array<int, 3>{mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0] - 1, + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[1] - 1, + mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2] - 1}); + } +#endif + gpu::computeVertexKernel<<<blocksGrid, 5>>>(getDeviceContext(), iVertex, mVrtParams.clusterContributorsCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[2]); + } + std::vector<gpu::GPUVertex> vertices; + vertices.resize(mStoreVertexerGPU.getConfig().nMaxVertices); + mStoreVertexerGPU.getVertices().copyIntoSizedVector(vertices); + + for (auto& vertex : vertices) { + if (vertex.realVertex) { + mVertices.emplace_back(vertex.xCoord, vertex.yCoord, vertex.zCoord, std::array<float, 6>{0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, vertex.contributors, 0.f, -9); + } + } + + gpuThrowOnError(); +} + +#ifdef _ALLOW_DEBUG_TREES_ITS_ +void VertexerTraitsGPU::computeMCFiltering() +{ + std::vector<Tracklet> tracklets01 = mStoreVertexerGPU.getRawDupletsFromGPU(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer); + std::vector<Tracklet> tracklets12 = mStoreVertexerGPU.getRawDupletsFromGPU(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer); + std::vector<int> labels01 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer); + std::vector<int> labels12 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer); + VertexerStoreConfigurationGPU tmpGPUConf; + const int stride = tmpGPUConf.maxTrackletsPerCluster; + + filterTrackletsWithMC(tracklets01, tracklets12, labels01, labels12, stride); + mStoreVertexerGPU.updateFoundDuplets(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer, labels01); + mStoreVertexerGPU.updateDuplets(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer, tracklets01); + mStoreVertexerGPU.updateFoundDuplets(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer, labels12); + mStoreVertexerGPU.updateDuplets(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer, tracklets12); + + if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { + mDebugger->fillCombinatoricsTree(mClusters, + mStoreVertexerGPU.getDupletsFromGPU(gpu::TrackletingLayerOrder::fromInnermostToMiddleLayer), + mStoreVertexerGPU.getDupletsFromGPU(gpu::TrackletingLayerOrder::fromMiddleToOuterLayer), + mEvent); + } +} +#endif + +VertexerTraits* createVertexerTraitsGPU() +{ + return new VertexerTraitsGPU; +} + +} // namespace its +} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore b/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore new file mode 100644 index 0000000000000..5854f8830a79b --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore @@ -0,0 +1,2 @@ +# Don't track generated hip sources +*.hip.cxx \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt new file mode 100644 index 0000000000000..0cd383260c27c --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +if(HIP_ENABLED) + # Hipify-perl to generate HIP sources + set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") + file(GLOB CUDA_SOURCES_FULL_PATH "../cuda/*.cu") + foreach(file ${CUDA_SOURCES_FULL_PATH}) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file}) + get_filename_component(CUDA_SOURCE ${file} NAME) + string(REPLACE ".cu" "" CUDA_SOURCE_NAME ${CUDA_SOURCE}) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx + COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} + ) + endforeach() + + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${baseTargetName} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + set(CMAKE_CXX_COMPILER ${hip_HIPCC_EXECUTABLE}) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") + + message(STATUS "Building ITS HIP vertexer") + o2_add_library(ITStrackingHIP + SOURCES ClusterLinesGPU.hip.cxx + Context.hip.cxx + # DeviceStore.hip.cxx + DeviceStoreVertexerGPU.hip.cxx + Stream.hip.cxx + # TrackerTraits.hip.cxx + VertexerTraitsGPU.hip.cxx + Utils.hip.cxx + PUBLIC_INCLUDE_DIRECTORIES ../ + PUBLIC_LINK_LIBRARIES O2::ITStracking + hip::host + hip::device + hip::hipcub + TARGETVARNAME targetName) + + target_compile_definitions( + ${targetName} PRIVATE $<TARGET_PROPERTY:O2::ITStracking,COMPILE_DEFINITIONS>) + + if(HIP_AMDGPUTARGET) + # Need to add gpu target also to link flags due to gpu-rdc option + target_link_options(${targetName} PUBLIC --amdgpu-target=${HIP_AMDGPUTARGET}) + endif() +endif() \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/cuda/CMakeLists.txt deleted file mode 100644 index 4b38a02a1da3f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -message(STATUS "Building ITS CUDA tracker") - -o2_add_library(ITStrackingCUDA - SOURCES src/ClusterLinesGPU.cu - src/Context.cu - src/DeviceStoreNV.cu - src/DeviceStoreVertexerGPU.cu - src/Stream.cu - src/TrackerTraitsNV.cu - src/VertexerTraitsGPU.cu - src/Utils.cu - PUBLIC_LINK_LIBRARIES O2::ITStracking - O2::SimConfig - O2::SimulationDataFormat - TARGETVARNAME targetName) - -set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) - -target_compile_definitions( - ${targetName} PRIVATE $<TARGET_PROPERTY:O2::ITStracking,COMPILE_DEFINITIONS>) diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Array.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Array.h deleted file mode 100644 index f59c9885e97c2..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Array.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Array.h -/// \brief -/// - -#ifndef TRAKINGITSU_INCLUDE_GPU_ARRAY_H_ -#define TRAKINGITSU_INCLUDE_GPU_ARRAY_H_ - -#include "ITStracking/Definitions.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace -{ -template <typename T, size_t Size> -struct ArrayTraits final { - typedef T InternalArray[Size]; - - GPU_HOST_DEVICE static constexpr T& getReference(const InternalArray& internalArray, size_t index) noexcept - { - return const_cast<T&>(internalArray[index]); - } - - GPU_HOST_DEVICE static constexpr T* getPointer(const InternalArray& internalArray) noexcept - { - return const_cast<T*>(internalArray); - } -}; -} // namespace - -template <typename T, size_t Size> -struct Array final { - - void copy(const Array<T, Size>& t) - { -#ifdef __OPENCL__ - for (size_t i{0}; i < Size; ++i) { - InternalArray[i] = t[i]; - } -#else - memcpy(InternalArray, t.data(), Size * sizeof(T)); -#endif - } - - GPU_HOST_DEVICE T* data() noexcept { return const_cast<T*>(InternalArray); } - GPU_HOST_DEVICE const T* data() const noexcept { return const_cast<T*>(InternalArray); } - GPU_HOST_DEVICE T& operator[](const int index) noexcept { return const_cast<T&>(InternalArray[index]); } - GPU_HOST_DEVICE constexpr T& operator[](const int index) const noexcept { return const_cast<T&>(InternalArray[index]); } - GPU_HOST_DEVICE size_t size() const noexcept { return Size; } - - T InternalArray[Size]; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRAKINGITSU_INCLUDE_GPU_CAGPUVECTOR_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Context.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Context.h deleted file mode 100644 index 246dfa76a1979..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Context.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Context.h -/// \brief -/// - -#ifndef TRAKINGITSU_INCLUDE_GPU_CONTEXT_H_ -#define TRAKINGITSU_INCLUDE_GPU_CONTEXT_H_ - -#include <string> -#include <vector> -#include "ITStracking/Definitions.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -struct DeviceProperties final { - std::string name; - int gpuProcessors; - int cudaCores; - long globalMemorySize; - long constantMemorySize; - long sharedMemorySize; - long maxClockRate; - int busWidth; - long l2CacheSize; - long registersPerBlock; - int warpSize; - int maxThreadsPerBlock; - int maxBlocksPerSM; - dim3 maxThreadsDim; - dim3 maxGridDim; -}; - -class Context final -{ - public: - static Context& getInstance(); - - Context(const Context&); - Context& operator=(const Context&); - - const DeviceProperties& getDeviceProperties(); - const DeviceProperties& getDeviceProperties(const int); - - private: - Context(bool dumpDevices = true); - ~Context() = default; - - int mDevicesNum; - std::vector<DeviceProperties> mDeviceProperties; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRAKINGITSU_INCLUDE_GPU_CONTEXT_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h deleted file mode 100644 index d5e38ff3b6319..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DeviceStoreNV.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_DEVICESTORENV_H_ -#define TRACKINGITSU_INCLUDE_DEVICESTORENV_H_ - -#include "ITStracking/Cell.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Tracklet.h" -#include "ITStrackingCUDA/Array.h" -#include "ITStrackingCUDA/UniquePointer.h" -#include "ITStrackingCUDA/Vector.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -class DeviceStoreNV final -{ - public: - DeviceStoreNV(); - - UniquePointer<DeviceStoreNV> initialise(const float3&, - const std::array<std::vector<Cluster>, constants::its::LayersNumber>&, - const std::array<std::vector<Tracklet>, constants::its::TrackletsPerRoad>&, - const std::array<std::vector<Cell>, constants::its::CellsPerRoad>&, - const std::array<std::vector<int>, constants::its::CellsPerRoad - 1>&, - const std::array<float, constants::its::LayersNumber>&, - const std::array<float, constants::its::LayersNumber>&); - GPU_DEVICE const float3& getPrimaryVertex(); - GPU_HOST_DEVICE Array<Vector<Cluster>, constants::its::LayersNumber>& getClusters(); - GPU_DEVICE Array<Array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::TrackletsPerRoad>& - getIndexTables(); - GPU_HOST_DEVICE Array<Vector<Tracklet>, constants::its::TrackletsPerRoad>& getTracklets(); - GPU_HOST_DEVICE Array<Vector<int>, constants::its::CellsPerRoad>& getTrackletsLookupTable(); - GPU_HOST_DEVICE Array<Vector<int>, constants::its::CellsPerRoad>& getTrackletsPerClusterTable(); - GPU_HOST_DEVICE Array<Vector<Cell>, constants::its::CellsPerRoad>& getCells(); - GPU_HOST_DEVICE Array<Vector<int>, constants::its::CellsPerRoad - 1>& getCellsLookupTable(); - GPU_HOST_DEVICE Array<Vector<int>, constants::its::CellsPerRoad - 1>& getCellsPerTrackletTable(); - Array<Vector<int>, constants::its::CellsPerRoad>& getTempTableArray(); - - GPU_HOST_DEVICE float getRmin(int layer); - GPU_HOST_DEVICE float getRmax(int layer); - - private: - UniquePointer<float3> mPrimaryVertex; - Array<Vector<Cluster>, constants::its::LayersNumber> mClusters; - Array<float, constants::its::LayersNumber> mRmin; - Array<float, constants::its::LayersNumber> mRmax; - Array<Array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, constants::its::TrackletsPerRoad> - mIndexTables; - Array<Vector<Tracklet>, constants::its::TrackletsPerRoad> mTracklets; - Array<Vector<int>, constants::its::CellsPerRoad> mTrackletsLookupTable; - Array<Vector<int>, constants::its::CellsPerRoad> mTrackletsPerClusterTable; - Array<Vector<Cell>, constants::its::CellsPerRoad> mCells; - Array<Vector<int>, constants::its::CellsPerRoad - 1> mCellsLookupTable; - Array<Vector<int>, constants::its::CellsPerRoad - 1> mCellsPerTrackletTable; -}; - -GPU_DEVICE inline const float3& DeviceStoreNV::getPrimaryVertex() { return *mPrimaryVertex; } - -GPU_HOST_DEVICE inline Array<Vector<Cluster>, constants::its::LayersNumber>& DeviceStoreNV::getClusters() -{ - return mClusters; -} - -GPU_DEVICE inline Array<Array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::TrackletsPerRoad>& - DeviceStoreNV::getIndexTables() -{ - return mIndexTables; -} - -GPU_DEVICE inline Array<Vector<Tracklet>, constants::its::TrackletsPerRoad>& DeviceStoreNV::getTracklets() -{ - return mTracklets; -} - -GPU_DEVICE inline Array<Vector<int>, constants::its::CellsPerRoad>& DeviceStoreNV::getTrackletsLookupTable() -{ - return mTrackletsLookupTable; -} - -GPU_DEVICE inline Array<Vector<int>, constants::its::CellsPerRoad>& DeviceStoreNV::getTrackletsPerClusterTable() -{ - return mTrackletsPerClusterTable; -} - -GPU_HOST_DEVICE inline Array<Vector<Cell>, constants::its::CellsPerRoad>& DeviceStoreNV::getCells() -{ - return mCells; -} - -GPU_HOST_DEVICE inline Array<Vector<int>, constants::its::CellsPerRoad - 1>& DeviceStoreNV::getCellsLookupTable() -{ - return mCellsLookupTable; -} - -GPU_HOST_DEVICE inline Array<Vector<int>, constants::its::CellsPerRoad - 1>& - DeviceStoreNV::getCellsPerTrackletTable() -{ - return mCellsPerTrackletTable; -} - -GPU_HOST_DEVICE inline float DeviceStoreNV::getRmin(int layer) -{ - return mRmin[layer]; -} - -GPU_HOST_DEVICE inline float DeviceStoreNV::getRmax(int layer) -{ - return mRmax[layer]; -} - -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h deleted file mode 100644 index d5d3493a52292..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file PrimaryVertexContextNVNV.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_PRIMARYVERTEXCONTEXTNVNV_H_ -#define TRACKINGITSU_INCLUDE_PRIMARYVERTEXCONTEXTNVNV_H_ - -#include <array> - -#include "ITStracking/Configuration.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/PrimaryVertexContext.h" -#include "ITStracking/Road.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingCUDA/DeviceStoreNV.h" -#include "ITStrackingCUDA/UniquePointer.h" - -namespace o2 -{ -namespace its -{ - -class PrimaryVertexContextNV final : public PrimaryVertexContext -{ - public: - PrimaryVertexContextNV() = default; - virtual ~PrimaryVertexContextNV() = default; - - virtual void initialise(const MemoryParameters& memParam, const std::array<std::vector<Cluster>, constants::its::LayersNumber>& cl, - const std::array<float, 3>& pv, const int iteration); - - GPU::DeviceStoreNV& getDeviceContext(); - GPU::Array<GPU::Vector<Cluster>, constants::its::LayersNumber>& getDeviceClusters(); - GPU::Array<GPU::Vector<Tracklet>, constants::its::TrackletsPerRoad>& getDeviceTracklets(); - GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad>& getDeviceTrackletsLookupTable(); - GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad>& getDeviceTrackletsPerClustersTable(); - GPU::Array<GPU::Vector<Cell>, constants::its::CellsPerRoad>& getDeviceCells(); - GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad - 1>& getDeviceCellsLookupTable(); - GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad - 1>& getDeviceCellsPerTrackletTable(); - std::array<GPU::Vector<int>, constants::its::CellsPerRoad>& getTempTableArray(); - std::array<GPU::Vector<Tracklet>, constants::its::CellsPerRoad>& getTempTrackletArray(); - std::array<GPU::Vector<Cell>, constants::its::CellsPerRoad - 1>& getTempCellArray(); - void updateDeviceContext(); - - private: - GPU::DeviceStoreNV mGPUContext; - GPU::UniquePointer<GPU::DeviceStoreNV> mGPUContextDevicePointer; - std::array<GPU::Vector<int>, constants::its::CellsPerRoad> mTempTableArray; - std::array<GPU::Vector<Tracklet>, constants::its::CellsPerRoad> mTempTrackletArray; - std::array<GPU::Vector<Cell>, constants::its::CellsPerRoad - 1> mTempCellArray; -}; - -inline GPU::DeviceStoreNV& PrimaryVertexContextNV::getDeviceContext() -{ - return *mGPUContextDevicePointer; -} - -inline GPU::Array<GPU::Vector<Cluster>, constants::its::LayersNumber>& PrimaryVertexContextNV::getDeviceClusters() -{ - return mGPUContext.getClusters(); -} - -inline GPU::Array<GPU::Vector<Tracklet>, constants::its::TrackletsPerRoad>& PrimaryVertexContextNV::getDeviceTracklets() -{ - return mGPUContext.getTracklets(); -} - -inline GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad>& PrimaryVertexContextNV::getDeviceTrackletsLookupTable() -{ - return mGPUContext.getTrackletsLookupTable(); -} - -inline GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad>& - PrimaryVertexContextNV::getDeviceTrackletsPerClustersTable() -{ - return mGPUContext.getTrackletsPerClusterTable(); -} - -inline GPU::Array<GPU::Vector<Cell>, constants::its::CellsPerRoad>& PrimaryVertexContextNV::getDeviceCells() -{ - return mGPUContext.getCells(); -} - -inline GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad - 1>& PrimaryVertexContextNV::getDeviceCellsLookupTable() -{ - return mGPUContext.getCellsLookupTable(); -} - -inline GPU::Array<GPU::Vector<int>, constants::its::CellsPerRoad - 1>& - PrimaryVertexContextNV::getDeviceCellsPerTrackletTable() -{ - return mGPUContext.getCellsPerTrackletTable(); -} - -inline std::array<GPU::Vector<int>, constants::its::CellsPerRoad>& PrimaryVertexContextNV::getTempTableArray() -{ - return mTempTableArray; -} - -inline std::array<GPU::Vector<Tracklet>, constants::its::CellsPerRoad>& PrimaryVertexContextNV::getTempTrackletArray() -{ - return mTempTrackletArray; -} - -inline std::array<GPU::Vector<Cell>, constants::its::CellsPerRoad - 1>& PrimaryVertexContextNV::getTempCellArray() -{ - return mTempCellArray; -} - -inline void PrimaryVertexContextNV::updateDeviceContext() -{ - mGPUContextDevicePointer = GPU::UniquePointer<GPU::DeviceStoreNV>{mGPUContext}; -} - -inline void PrimaryVertexContextNV::initialise(const MemoryParameters& memParam, const std::array<std::vector<Cluster>, constants::its::LayersNumber>& cl, - const std::array<float, 3>& pv, const int iteration) -{ - this->PrimaryVertexContext::initialise(memParam, cl, pv, iteration); - mGPUContextDevicePointer = mGPUContext.initialise(mPrimaryVertex, mClusters, mTracklets, mCells, mCellsLookupTable, mMinR, mMaxR); -} - -} // namespace its -} // namespace o2 - -#endif /* TRACKINGITSU_INCLUDE_PRIMARYVERTEXCONTEXTNV_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Stream.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Stream.h deleted file mode 100644 index 52460ad6ff955..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Stream.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Stream.h -/// \brief -/// - -#ifndef TRAKINGITSU_INCLUDE_GPU_STREAM_H_ -#define TRAKINGITSU_INCLUDE_GPU_STREAM_H_ - -#include "ITStracking/Definitions.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -class Stream final -{ - - public: - Stream(); - ~Stream(); - - Stream(const Stream&) = delete; - Stream& operator=(const Stream&) = delete; - - const GPUStream& get() const; - - private: - GPUStream mStream; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRAKINGITSU_INCLUDE_GPU_STREAM_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/TrackerTraitsNV.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/TrackerTraitsNV.h deleted file mode 100644 index ea90e52114428..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/TrackerTraitsNV.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file TrackerTraitsNV.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_TRACKERTRAITSNV_H_ -#define TRACKINGITSU_INCLUDE_TRACKERTRAITSNV_H_ - -#include "ITStracking/Configuration.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/TrackerTraits.h" - -namespace o2 -{ -namespace its -{ - -class PrimaryVertexContext; - -class TrackerTraitsNV : public TrackerTraits -{ - public: - TrackerTraitsNV(); - virtual ~TrackerTraitsNV(); - - void computeLayerCells() final; - void computeLayerTracklets() final; - void refitTracks(const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) final; -}; - -extern "C" TrackerTraits* createTrackerTraitsNV(); -} // namespace its -} // namespace o2 - -#endif /* TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/UniquePointer.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/UniquePointer.h deleted file mode 100644 index e82d58f32add2..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/UniquePointer.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file UniquePointer.h -/// \brief -/// - -#ifndef TRAKINGITSU_INCLUDE_GPU_CAGPUUNIQUE_POINTER_H_ -#define TRAKINGITSU_INCLUDE_GPU_CAGPUUNIQUE_POINTER_H_ - -#include "ITStrackingCUDA/Utils.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace -{ -template <typename T> -struct UniquePointerTraits final { - typedef T* InternalPointer; - - GPU_HOST_DEVICE static constexpr T& getReference(const InternalPointer& internalPointer) noexcept - { - return const_cast<T&>(*internalPointer); - } - - GPU_HOST_DEVICE static constexpr T* getPointer(const InternalPointer& internalPointer) noexcept - { - return const_cast<T*>(internalPointer); - } -}; -} // namespace - -template <typename T> -class UniquePointer final -{ - typedef UniquePointerTraits<T> PointerTraits; - - public: - UniquePointer(); - explicit UniquePointer(const T&); - ~UniquePointer(); - - UniquePointer(const UniquePointer&) = delete; - UniquePointer& operator=(const UniquePointer&) = delete; - - UniquePointer(UniquePointer&&); - UniquePointer& operator=(UniquePointer&&); - - GPU_HOST_DEVICE T* get() noexcept; - GPU_HOST_DEVICE const T* get() const noexcept; - GPU_HOST_DEVICE T& operator*() noexcept; - GPU_HOST_DEVICE const T& operator*() const noexcept; - - protected: - void destroy(); - - private: - typename PointerTraits::InternalPointer mDevicePointer; -}; - -template <typename T> -UniquePointer<T>::UniquePointer() : mDevicePointer{nullptr} -{ - // Nothing to do -} - -template <typename T> -UniquePointer<T>::UniquePointer(const T& ref) -{ - try { - - Utils::Host::gpuMalloc(reinterpret_cast<void**>(&mDevicePointer), sizeof(T)); - Utils::Host::gpuMemcpyHostToDevice(mDevicePointer, &ref, sizeof(T)); - - } catch (...) { - - destroy(); - - throw; - } -} - -template <typename T> -UniquePointer<T>::~UniquePointer() -{ - destroy(); -} - -template <typename T> -UniquePointer<T>::UniquePointer(UniquePointer<T>&& other) : mDevicePointer{other.mDevicePointer} -{ - // Nothing to do -} - -template <typename T> -UniquePointer<T>& UniquePointer<T>::operator=(UniquePointer<T>&& other) -{ - mDevicePointer = other.mDevicePointer; - other.mDevicePointer = nullptr; - - return *this; -} - -template <typename T> -void UniquePointer<T>::destroy() -{ - if (mDevicePointer != nullptr) { - - Utils::Host::gpuFree(mDevicePointer); - } -} - -template <typename T> -GPU_HOST_DEVICE T* UniquePointer<T>::get() noexcept -{ - return PointerTraits::getPointer(mDevicePointer); -} - -template <typename T> -GPU_HOST_DEVICE const T* UniquePointer<T>::get() const noexcept -{ - return PointerTraits::getPointer(mDevicePointer); -} - -template <typename T> -GPU_HOST_DEVICE T& UniquePointer<T>::operator*() noexcept -{ - return PointerTraits::getReference(mDevicePointer); -} - -template <typename T> -GPU_HOST_DEVICE const T& UniquePointer<T>::operator*() const noexcept -{ - return PointerTraits::getReference(mDevicePointer); -} -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRAKINGITSU_INCLUDE_GPU_CAGPUUNIQUE_POINTER_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Utils.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Utils.h deleted file mode 100644 index 5babb15320f6b..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Utils.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Utils.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_GPU_UTILS_H_ -#define TRACKINGITSU_INCLUDE_GPU_UTILS_H_ - -#include "GPUCommonDef.h" -#include "ITStrackingCUDA/Stream.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace Utils -{ - -namespace Host -{ - -#ifdef __CUDACC__ -void checkCUDAError(const cudaError_t error, const char* file, const int line); -#endif - -dim3 getBlockSize(const int); -dim3 getBlockSize(const int, const int); -dim3 getBlockSize(const int, const int, const int); -dim3 getBlocksGrid(const dim3&, const int); -dim3 getBlocksGrid(const dim3&, const int, const int); - -void gpuMalloc(void**, const int); -void gpuFree(void*); -void gpuMemset(void*, int, int); -void gpuMemcpyHostToDevice(void*, const void*, int); -void gpuMemcpyHostToDeviceAsync(void*, const void*, int, Stream&); -void gpuMemcpyDeviceToHost(void*, const void*, int); -// void gpuStartProfiler(); -// void gpuStopProfiler(); -} // namespace Host - -namespace Device -{ -GPUd() int getLaneIndex(); -GPUd() int shareToWarp(const int, const int); -GPUd() int gpuAtomicAdd(int*, const int); -} // namespace Device -} // namespace Utils -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRACKINGITSU_INCLUDE_GPU_UTILS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Vector.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Vector.h deleted file mode 100644 index bf09f269e0449..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Vector.h +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Vector.h -/// \brief -/// - -#ifndef TRAKINGITSU_INCLUDE_GPU_VECTOR_H_ -#define TRAKINGITSU_INCLUDE_GPU_VECTOR_H_ - -#include <assert.h> -#include <new> -#include <type_traits> -#include <vector> - -#include "ITStracking/Definitions.h" -#include "ITStrackingCUDA/Stream.h" -#include "ITStrackingCUDA/Utils.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -template <typename T> -class Vector final -{ - static_assert(std::is_trivially_destructible<T>::value, "Vector only supports trivially destructible objects."); - - public: - Vector(); - explicit Vector(const int, const int = 0); - Vector(const T* const, const int, const int = 0); - GPU_HOST_DEVICE ~Vector(); - - Vector(const Vector&) = delete; - Vector& operator=(const Vector&) = delete; - - GPU_HOST_DEVICE Vector(Vector&&); - Vector& operator=(Vector&&); - - int getSizeFromDevice() const; - - T getElementFromDevice(const int) const; - - void resize(const int); - void reset(const int, const int = 0); - void reset(const T* const, const int, const int = 0); - void copyIntoVector(std::vector<T>&, const int); - void copyIntoSizedVector(std::vector<T>&); - - GPU_HOST_DEVICE T* get() const; - GPU_HOST_DEVICE int capacity() const; - GPU_HOST_DEVICE Vector<T> getWeakCopy() const; - GPU_DEVICE T& operator[](const int) const; - - GPU_DEVICE int size() const; - GPU_DEVICE int extend(const int) const; - GPU_HOST_DEVICE void dump(); - - template <typename... Args> - GPU_DEVICE void emplace(const int, Args&&...); - - protected: - void destroy(); - - private: - GPU_HOST_DEVICE Vector(const Vector&, const bool); - - T* mArrayPointer = nullptr; - int* mDeviceSize = nullptr; - int mCapacity; - bool mIsWeak; -}; - -template <typename T> -Vector<T>::Vector() : Vector{nullptr, 0} -{ - // Nothing to do -} - -template <typename T> -Vector<T>::Vector(const int capacity, const int initialSize) : Vector{nullptr, capacity, initialSize} -{ - // Nothing to do -} - -template <typename T> -Vector<T>::Vector(const T* const source, const int size, const int initialSize) : mCapacity{size}, mIsWeak{false} -{ - if (size > 0) { - try { - - Utils::Host::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); - Utils::Host::gpuMalloc(reinterpret_cast<void**>(&mDeviceSize), sizeof(int)); - - if (source != nullptr) { - - Utils::Host::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); - Utils::Host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); - - } else { - - Utils::Host::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); - } - - } catch (...) { - - destroy(); - - throw; - } - } -} - -template <typename T> -Vector<T>::Vector(const Vector& other, const bool isWeak) - : mArrayPointer{other.mArrayPointer}, - mDeviceSize{other.mDeviceSize}, - mCapacity{other.mCapacity}, - mIsWeak{isWeak} -{ - // Nothing to do -} - -template <typename T> -GPU_HOST_DEVICE Vector<T>::~Vector() -{ - if (mIsWeak) { - - return; - - } else { -#if defined(TRACKINGITSU_GPU_DEVICE) - assert(0); -#else - destroy(); -#endif - } -} - -template <typename T> -GPU_HOST_DEVICE Vector<T>::Vector(Vector<T>&& other) - : mArrayPointer{other.mArrayPointer}, - mDeviceSize{other.mDeviceSize}, - mCapacity{other.mCapacity}, - mIsWeak{other.mIsWeak} -{ - other.mArrayPointer = nullptr; - other.mDeviceSize = nullptr; -} - -template <typename T> -Vector<T>& Vector<T>::operator=(Vector<T>&& other) -{ - destroy(); - - mArrayPointer = other.mArrayPointer; - mDeviceSize = other.mDeviceSize; - mCapacity = other.mCapacity; - mIsWeak = other.mIsWeak; - - other.mArrayPointer = nullptr; - other.mDeviceSize = nullptr; - - return *this; -} - -template <typename T> -int Vector<T>::getSizeFromDevice() const -{ - int size; - Utils::Host::gpuMemcpyDeviceToHost(&size, mDeviceSize, sizeof(int)); - - return size; -} - -template <typename T> -void Vector<T>::resize(const int size) -{ - Utils::Host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); -} - -template <typename T> -void Vector<T>::reset(const int capacity, const int initialSize) -{ - reset(nullptr, capacity, initialSize); -} - -template <typename T> -void Vector<T>::reset(const T* const source, const int size, const int initialSize) -{ - if (size > mCapacity) { - if (mArrayPointer != nullptr) { - Utils::Host::gpuFree(mArrayPointer); - } - Utils::Host::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); - mCapacity = size; - } - - if (source != nullptr) { - Utils::Host::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); - Utils::Host::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); - - } else { - if (mDeviceSize == nullptr) { - Utils::Host::gpuMalloc(reinterpret_cast<void**>(&mDeviceSize), sizeof(int)); - } - Utils::Host::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); - } -} - -template <typename T> -void Vector<T>::copyIntoVector(std::vector<T>& destinationVector, const int size) -{ - - T* hostPrimitivePointer = nullptr; - - try { - - hostPrimitivePointer = static_cast<T*>(malloc(size * sizeof(T))); - Utils::Host::gpuMemcpyDeviceToHost(hostPrimitivePointer, mArrayPointer, size * sizeof(T)); - - destinationVector = std::move(std::vector<T>(hostPrimitivePointer, hostPrimitivePointer + size)); - - } catch (...) { - - if (hostPrimitivePointer != nullptr) { - - free(hostPrimitivePointer); - } - - throw; - } -} - -template <typename T> -void Vector<T>::copyIntoSizedVector(std::vector<T>& destinationVector) -{ - Utils::Host::gpuMemcpyDeviceToHost(destinationVector.data(), mArrayPointer, destinationVector.size() * sizeof(T)); -} - -template <typename T> -inline void Vector<T>::destroy() -{ - if (mArrayPointer != nullptr) { - - Utils::Host::gpuFree(mArrayPointer); - } - - if (mDeviceSize != nullptr) { - - Utils::Host::gpuFree(mDeviceSize); - } -} - -template <typename T> -GPU_HOST_DEVICE inline T* Vector<T>::get() const -{ - return mArrayPointer; -} - -template <typename T> -GPU_HOST_DEVICE inline int Vector<T>::capacity() const -{ - return mCapacity; -} - -template <typename T> -GPU_HOST_DEVICE inline Vector<T> Vector<T>::getWeakCopy() const -{ - return Vector{*this, true}; -} - -template <typename T> -GPU_DEVICE inline T& Vector<T>::operator[](const int index) const -{ - return mArrayPointer[index]; -} - -template <typename T> -GPU_HOST inline T Vector<T>::getElementFromDevice(const int index) const -{ - T element; - Utils::Host::gpuMemcpyDeviceToHost(&element, mArrayPointer + index, sizeof(T)); - - return element; -} - -template <typename T> -GPU_DEVICE inline int Vector<T>::size() const -{ - return *mDeviceSize; -} - -template <typename T> -GPU_DEVICE int Vector<T>::extend(const int sizeIncrement) const -{ - const int startIndex = Utils::Device::gpuAtomicAdd(mDeviceSize, sizeIncrement); - assert(size() <= mCapacity); - - return startIndex; -} - -template <typename T> -template <typename... Args> -GPU_DEVICE void Vector<T>::emplace(const int index, Args&&... arguments) -{ - new (mArrayPointer + index) T(std::forward<Args>(arguments)...); -} - -template <typename T> -GPU_HOST_DEVICE void Vector<T>::dump() -{ - printf("mArrayPointer = %p\nmDeviceSize = %p\nmCapacity = %d\nmIsWeak = %s\n", - mArrayPointer, mDeviceSize, mCapacity, mIsWeak ? "true" : "false"); -} -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* TRAKINGITSU_INCLUDE_GPU_VECTOR_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/VertexerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/VertexerTraitsGPU.h deleted file mode 100644 index a3447e55c586f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/VertexerTraitsGPU.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsGPU.h -/// \brief -/// \author matteo.concas@cern.ch - -#ifndef O2_ITS_TRACKING_VERTEXER_TRAITS_GPU_H_ -#define O2_ITS_TRACKING_VERTEXER_TRAITS_GPU_H_ - -#include <vector> -#include <array> - -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingCUDA/DeviceStoreVertexerGPU.h" -#include "ITStrackingCUDA/UniquePointer.h" - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -#include "ITStracking/StandaloneDebugger.h" -#endif - -namespace o2 -{ -namespace its -{ -class ROframe; - -using constants::index_table::InversePhiBinSize; - -class VertexerTraitsGPU : public VertexerTraits -{ - public: -#ifdef _ALLOW_DEBUG_TREES_ITS_ - VertexerTraitsGPU(); - virtual ~VertexerTraitsGPU(); -#else - VertexerTraitsGPU(); - virtual ~VertexerTraitsGPU() = default; -#endif - void initialise(ROframe*) override; - void computeTracklets() override; - void computeTrackletMatching() override; - void computeVertices() override; -#ifdef _ALLOW_DEBUG_TREES_ITS_ - void computeMCFiltering() override; -#endif - - // GPU-specific getters - GPUd() static const int2 getBinsPhiRectWindow(const Cluster&, float maxdeltaphi); - GPUhd() GPU::DeviceStoreVertexerGPU& getDeviceContext(); - - protected: - GPU::DeviceStoreVertexerGPU mStoreVertexerGPU; - GPU::UniquePointer<GPU::DeviceStoreVertexerGPU> mStoreVertexerGPUPtr; -}; - -inline GPUd() const int2 VertexerTraitsGPU::getBinsPhiRectWindow(const Cluster& currentCluster, float phiCut) -{ - // This function returns the lowest PhiBin and the number of phi bins to be spanned, In the form int2{phiBinLow, PhiBinSpan} - const int phiBinMin{index_table_utils::getPhiBinIndex( - math_utils::getNormalizedPhiCoordinate(currentCluster.phiCoordinate - phiCut))}; - const int phiBinSpan{static_cast<int>(MATH_CEIL(phiCut * InversePhiBinSize))}; - return int2{phiBinMin, phiBinSpan}; -} - -inline GPU::DeviceStoreVertexerGPU& VertexerTraitsGPU::getDeviceContext() -{ - return *mStoreVertexerGPUPtr; -} - -extern "C" VertexerTraits* createVertexerTraitsGPU(); - -} // namespace its -} // namespace o2 -#endif /* O2_ITS_TRACKING_VERTEXER_TRAITS_GPU_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/Context.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/Context.cu deleted file mode 100644 index 633b4c4abf9f1..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/Context.cu +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Context.cu -/// \brief -/// - -#include "ITStrackingCUDA/Context.h" -#include "ITStrackingCUDA/Utils.h" - -#include <sstream> -#include <stdexcept> - -#include <iostream> - -namespace -{ - -inline int getCudaCores(const int major, const int minor) -{ - // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM - typedef struct - { - int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = - { - {0x20, 32}, // Fermi Generation (SM 2.0) GF100 class - {0x21, 48}, // Fermi Generation (SM 2.1) GF10x class - {0x30, 192}, // Kepler Generation (SM 3.0) GK10x class - {0x32, 192}, // Kepler Generation (SM 3.2) GK10x class - {0x35, 192}, // Kepler Generation (SM 3.5) GK11x class - {0x37, 192}, // Kepler Generation (SM 3.7) GK21x class - {0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class - {0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class - {0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class - {0x60, 64}, // Pascal Generation (SM 6.0) GP100 class - {0x61, 128}, // Pascal Generation (SM 6.1) GP10x class - {0x62, 128}, // Pascal Generation (SM 6.2) GP10x class - {0x70, 64}, // Volta Generation (SM 7.0) GV100 class - {0x72, 64}, // Volta Generation (SM 7.2) GV10B class - {0x75, 64}, // Turing Generation (SM 7.5) TU1xx class - {-1, -1}}; - - int index = 0; - - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { - return nGpuArchCoresPerSM[index].Cores; - } - - index++; - } - - // If we don't find the values, we default use the previous one to run properly - printf("MapSMtoCores for SM %d.%d is undefined. Default to use %d Cores/SM\n", major, minor, nGpuArchCoresPerSM[index - 1].Cores); - return nGpuArchCoresPerSM[index - 1].Cores; -} - -inline int getMaxThreadsPerSM(const int major, const int minor) -{ - return 8; -} - -} // namespace - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -using Utils::Host::checkCUDAError; - -Context::Context(bool dumpDevices) -{ - checkCUDAError(cudaGetDeviceCount(&mDevicesNum), __FILE__, __LINE__); - - if (mDevicesNum == 0) { - - throw std::runtime_error{"There are no available device(s) that support CUDA\n"}; - } - - mDeviceProperties.resize(mDevicesNum, DeviceProperties{}); - - int currentDeviceIndex; - checkCUDAError(cudaGetDevice(¤tDeviceIndex), __FILE__, __LINE__); - - for (int iDevice{0}; iDevice < mDevicesNum; ++iDevice) { - - cudaDeviceProp deviceProperties; - - checkCUDAError(cudaSetDevice(iDevice), __FILE__, __LINE__); - checkCUDAError(cudaGetDeviceProperties(&deviceProperties, iDevice), __FILE__, __LINE__); - - int major = deviceProperties.major; - int minor = deviceProperties.minor; - - mDeviceProperties[iDevice].name = deviceProperties.name; - mDeviceProperties[iDevice].gpuProcessors = deviceProperties.multiProcessorCount; - mDeviceProperties[iDevice].cudaCores = getCudaCores(major, minor) * deviceProperties.multiProcessorCount; - mDeviceProperties[iDevice].globalMemorySize = deviceProperties.totalGlobalMem; - mDeviceProperties[iDevice].constantMemorySize = deviceProperties.totalConstMem; - mDeviceProperties[iDevice].sharedMemorySize = deviceProperties.sharedMemPerBlock; - mDeviceProperties[iDevice].maxClockRate = deviceProperties.memoryClockRate; - mDeviceProperties[iDevice].busWidth = deviceProperties.memoryBusWidth; - mDeviceProperties[iDevice].l2CacheSize = deviceProperties.l2CacheSize; - mDeviceProperties[iDevice].registersPerBlock = deviceProperties.regsPerBlock; - mDeviceProperties[iDevice].warpSize = deviceProperties.warpSize; - mDeviceProperties[iDevice].maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock; - mDeviceProperties[iDevice].maxBlocksPerSM = getMaxThreadsPerSM(major, minor); - mDeviceProperties[iDevice].maxThreadsDim = dim3{static_cast<unsigned int>(deviceProperties.maxThreadsDim[0]), - static_cast<unsigned int>(deviceProperties.maxThreadsDim[1]), - static_cast<unsigned int>(deviceProperties.maxThreadsDim[2])}; - mDeviceProperties[iDevice].maxGridDim = dim3{static_cast<unsigned int>(deviceProperties.maxGridSize[0]), - static_cast<unsigned int>(deviceProperties.maxGridSize[1]), - static_cast<unsigned int>(deviceProperties.maxGridSize[2])}; - if (dumpDevices) { - std::cout << "################ CUDA DEVICE " << iDevice << " ################" << std::endl; - std::cout << "Name " << mDeviceProperties[iDevice].name << std::endl; - std::cout << "minor " << minor << " major " << major << std::endl; - std::cout << "gpuProcessors " << mDeviceProperties[iDevice].gpuProcessors << std::endl; - std::cout << "cudaCores " << mDeviceProperties[iDevice].cudaCores << std::endl; - std::cout << "globalMemorySize " << mDeviceProperties[iDevice].globalMemorySize << std::endl; - std::cout << "constantMemorySize " << mDeviceProperties[iDevice].constantMemorySize << std::endl; - std::cout << "sharedMemorySize " << mDeviceProperties[iDevice].sharedMemorySize << std::endl; - std::cout << "maxClockRate " << mDeviceProperties[iDevice].maxClockRate << std::endl; - std::cout << "busWidth " << mDeviceProperties[iDevice].busWidth << std::endl; - std::cout << "l2CacheSize " << mDeviceProperties[iDevice].l2CacheSize << std::endl; - std::cout << "registersPerBlock " << mDeviceProperties[iDevice].registersPerBlock << std::endl; - std::cout << "warpSize " << mDeviceProperties[iDevice].warpSize << std::endl; - std::cout << "maxThreadsPerBlock " << mDeviceProperties[iDevice].maxThreadsPerBlock << std::endl; - std::cout << "maxBlocksPerSM " << mDeviceProperties[iDevice].maxBlocksPerSM << std::endl; - std::cout << "maxThreadsDim " << mDeviceProperties[iDevice].maxThreadsDim.x << ", " << mDeviceProperties[iDevice].maxThreadsDim.y << ", " << mDeviceProperties[iDevice].maxThreadsDim.z << std::endl; - std::cout << "maxGridDim " << mDeviceProperties[iDevice].maxGridDim.x << ", " << mDeviceProperties[iDevice].maxGridDim.y << ", " << mDeviceProperties[iDevice].maxGridDim.z << std::endl; - std::cout << std::endl; - } - } - - checkCUDAError(cudaSetDevice(currentDeviceIndex), __FILE__, __LINE__); -} - -Context& Context::getInstance() -{ - static Context gpuContext; - return gpuContext; -} - -const DeviceProperties& Context::getDeviceProperties() -{ - int currentDeviceIndex; - checkCUDAError(cudaGetDevice(¤tDeviceIndex), __FILE__, __LINE__); - - return getDeviceProperties(currentDeviceIndex); -} - -const DeviceProperties& Context::getDeviceProperties(const int deviceIndex) -{ - return mDeviceProperties[deviceIndex]; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu deleted file mode 100644 index 14eb74ff41bde..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DeviceStoreNV.cxx -/// \brief -/// - -#include "ITStrackingCUDA/DeviceStoreNV.h" - -#include <sstream> - -#include "ITStrackingCUDA/Stream.h" - -namespace -{ - -using namespace o2::its; - -__device__ void fillIndexTables(GPU::DeviceStoreNV& primaryVertexContext, const int layerIndex) -{ - - const int currentClusterIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; - const int nextLayerClustersNum{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; - - if (currentClusterIndex < nextLayerClustersNum) { - - const int currentBinIndex{ - primaryVertexContext.getClusters()[layerIndex + 1][currentClusterIndex].indexTableBinIndex}; - int previousBinIndex; - - if (currentClusterIndex == 0) { - - primaryVertexContext.getIndexTables()[layerIndex][0] = 0; - previousBinIndex = 0; - - } else { - - previousBinIndex = primaryVertexContext.getClusters()[layerIndex + 1][currentClusterIndex - 1].indexTableBinIndex; - } - - if (currentBinIndex > previousBinIndex) { - - for (int iBin{previousBinIndex + 1}; iBin <= currentBinIndex; ++iBin) { - - primaryVertexContext.getIndexTables()[layerIndex][iBin] = currentClusterIndex; - } - - previousBinIndex = currentBinIndex; - } - - if (currentClusterIndex == nextLayerClustersNum - 1) { - - for (int iBin{currentBinIndex + 1}; iBin <= o2::its::constants::index_table::ZBins * o2::its::constants::index_table::PhiBins; - iBin++) { - - primaryVertexContext.getIndexTables()[layerIndex][iBin] = nextLayerClustersNum; - } - } - } -} - -__device__ void fillTrackletsPerClusterTables(GPU::DeviceStoreNV& primaryVertexContext, const int layerIndex) -{ - const int currentClusterIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; - const int clustersSize{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; - - if (currentClusterIndex < clustersSize) { - - primaryVertexContext.getTrackletsPerClusterTable()[layerIndex][currentClusterIndex] = 0; - } -} - -__device__ void fillCellsPerClusterTables(GPU::DeviceStoreNV& primaryVertexContext, const int layerIndex) -{ - const int totalThreadNum{static_cast<int>(primaryVertexContext.getClusters()[layerIndex + 1].size())}; - const int trackletsSize{static_cast<int>(primaryVertexContext.getTracklets()[layerIndex + 1].capacity())}; - const int trackletsPerThread{1 + (trackletsSize - 1) / totalThreadNum}; - const int firstTrackletIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x) * trackletsPerThread}; - - if (firstTrackletIndex < trackletsSize) { - - const int trackletsToSet{min(trackletsSize, firstTrackletIndex + trackletsPerThread) - firstTrackletIndex}; - memset(&primaryVertexContext.getCellsPerTrackletTable()[layerIndex][firstTrackletIndex], 0, - trackletsToSet * sizeof(int)); - } -} - -__global__ void fillDeviceStructures(GPU::DeviceStoreNV& primaryVertexContext, const int layerIndex) -{ - fillIndexTables(primaryVertexContext, layerIndex); - - if (layerIndex < o2::its::constants::its::CellsPerRoad) { - - fillTrackletsPerClusterTables(primaryVertexContext, layerIndex); - } - - if (layerIndex < o2::its::constants::its::CellsPerRoad - 1) { - - fillCellsPerClusterTables(primaryVertexContext, layerIndex); - } -} -} // namespace - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -DeviceStoreNV::DeviceStoreNV() -{ - // Nothing to do -} - -UniquePointer<DeviceStoreNV> DeviceStoreNV::initialise(const float3& primaryVertex, - const std::array<std::vector<Cluster>, constants::its::LayersNumber>& clusters, - const std::array<std::vector<Tracklet>, constants::its::TrackletsPerRoad>& tracklets, - const std::array<std::vector<Cell>, constants::its::CellsPerRoad>& cells, - const std::array<std::vector<int>, constants::its::CellsPerRoad - 1>& cellsLookupTable, - const std::array<float, constants::its::LayersNumber>& rmin, - const std::array<float, constants::its::LayersNumber>& rmax) -{ - mPrimaryVertex = UniquePointer<float3>{primaryVertex}; - - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { - this->mRmin[iLayer] = rmin[iLayer]; - this->mRmax[iLayer] = rmax[iLayer]; - - this->mClusters[iLayer] = - Vector<Cluster>{&clusters[iLayer][0], static_cast<int>(clusters[iLayer].size())}; - - if (iLayer < constants::its::TrackletsPerRoad) { - this->mTracklets[iLayer].reset(tracklets[iLayer].capacity()); - } - - if (iLayer < constants::its::CellsPerRoad) { - - this->mTrackletsLookupTable[iLayer].reset(static_cast<int>(clusters[iLayer + 1].size())); - this->mTrackletsPerClusterTable[iLayer].reset(static_cast<int>(clusters[iLayer + 1].size())); - this->mCells[iLayer].reset(static_cast<int>(cells[iLayer].capacity())); - } - - if (iLayer < constants::its::CellsPerRoad - 1) { - - this->mCellsLookupTable[iLayer].reset(static_cast<int>(cellsLookupTable[iLayer].size())); - this->mCellsPerTrackletTable[iLayer].reset(static_cast<int>(cellsLookupTable[iLayer].size())); - } - } - - UniquePointer<DeviceStoreNV> gpuContextDevicePointer{*this}; - - std::array<Stream, constants::its::LayersNumber> streamArray; - - for (int iLayer{0}; iLayer < constants::its::TrackletsPerRoad; ++iLayer) { - - const int nextLayerClustersNum = static_cast<int>(clusters[iLayer + 1].size()); - - dim3 threadsPerBlock{Utils::Host::getBlockSize(nextLayerClustersNum)}; - dim3 blocksGrid{Utils::Host::getBlocksGrid(threadsPerBlock, nextLayerClustersNum)}; - - fillDeviceStructures<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(*gpuContextDevicePointer, iLayer); - - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - errorString << __FILE__ << ":" << __LINE__ << " CUDA API returned error [" << cudaGetErrorString(error) - << "] (code " << error << ")" << std::endl; - - throw std::runtime_error{errorString.str()}; - } - } - - return gpuContextDevicePointer; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/Stream.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/Stream.cu deleted file mode 100644 index 6313bac5157e5..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/Stream.cu +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Stream.cu -/// \brief -/// - -#include "ITStrackingCUDA/Stream.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -Stream::Stream() -{ - cudaStreamCreateWithFlags(&mStream, cudaStreamNonBlocking); -} - -Stream::~Stream() -{ - cudaStreamDestroy(mStream); -} - -const GPUStream& Stream::get() const -{ - return mStream; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu deleted file mode 100644 index 186f0b25ead9a..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file TrackerTraitsNV.cu -/// \brief -/// - -#include "ITStrackingCUDA/TrackerTraitsNV.h" - -#include <array> -#include <sstream> -#include <iostream> - -#ifndef GPUCA_GPUCODE_GENRTC -#include <cooperative_groups.h> -#include "cub/cub.cuh" -#endif - -#include "ITStracking/Constants.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/IndexTableUtils.h" -#include "ITStracking/MathUtils.h" -#include "ITStrackingCUDA/Context.h" -#include "ITStrackingCUDA/DeviceStoreNV.h" -#include "ITStrackingCUDA/PrimaryVertexContextNV.h" -#include "ITStrackingCUDA/Stream.h" -#include "ITStrackingCUDA/Vector.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -__constant__ TrackingParameters kTrkPar; - -__device__ void computeLayerTracklets(DeviceStoreNV& devStore, const int layerIndex, - Vector<Tracklet>& trackletsVector) -{ - const int currentClusterIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); - int clusterTrackletsNum = 0; - - if (currentClusterIndex < devStore.getClusters()[layerIndex].size()) { - - Vector<Cluster> nextLayerClusters{devStore.getClusters()[layerIndex + 1].getWeakCopy()}; - const Cluster currentCluster{devStore.getClusters()[layerIndex][currentClusterIndex]}; - - /*if (mUsedClustersTable[currentCluster.clusterId] != constants::its::UnusedIndex) { - - continue; - }*/ - - const float tanLambda{(currentCluster.zCoordinate - devStore.getPrimaryVertex().z) / currentCluster.rCoordinate}; - const float zAtRmin{tanLambda * (devStore.getRmin(layerIndex + 1) - currentCluster.rCoordinate) + currentCluster.zCoordinate}; - const float zAtRmax{tanLambda * (devStore.getRmax(layerIndex + 1) - currentCluster.rCoordinate) + currentCluster.zCoordinate}; - - const int4 selectedBinsRect{TrackerTraits::getBinsRect(currentCluster, layerIndex, zAtRmin, zAtRmax, - kTrkPar.TrackletMaxDeltaZ[layerIndex], kTrkPar.TrackletMaxDeltaPhi)}; - - if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { - - const int nextLayerClustersNum{static_cast<int>(nextLayerClusters.size())}; - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - - if (phiBinsNum < 0) { - - phiBinsNum += constants::index_table::PhiBins; - } - - for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; - iPhiBin = ++iPhiBin == constants::index_table::PhiBins ? 0 : iPhiBin, iPhiCount++) { - - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int firstRowClusterIndex = devStore.getIndexTables()[layerIndex][firstBinIndex]; - const int maxRowClusterIndex = devStore.getIndexTables()[layerIndex][{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}]; - - for (int iNextLayerCluster{firstRowClusterIndex}; - iNextLayerCluster <= maxRowClusterIndex && iNextLayerCluster < nextLayerClustersNum; ++iNextLayerCluster) { - - const Cluster& nextCluster{nextLayerClusters[iNextLayerCluster]}; - - const float deltaZ{gpu::GPUCommonMath::Abs( - tanLambda * (nextCluster.rCoordinate - currentCluster.rCoordinate) + currentCluster.zCoordinate - nextCluster.zCoordinate)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(currentCluster.phiCoordinate - nextCluster.phiCoordinate)}; - - if (deltaZ < kTrkPar.TrackletMaxDeltaZ[layerIndex] && (deltaPhi < kTrkPar.TrackletMaxDeltaPhi || gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < kTrkPar.TrackletMaxDeltaPhi)) { - - cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); - int currentIndex{}; - - if (threadGroup.thread_rank() == 0) { - - currentIndex = trackletsVector.extend(threadGroup.size()); - } - - currentIndex = threadGroup.shfl(currentIndex, 0) + threadGroup.thread_rank(); - - trackletsVector.emplace(currentIndex, currentClusterIndex, iNextLayerCluster, currentCluster, nextCluster); - ++clusterTrackletsNum; - } - } - } - - if (layerIndex > 0) { - - devStore.getTrackletsPerClusterTable()[layerIndex - 1][currentClusterIndex] = clusterTrackletsNum; - } - } - } -} - -__device__ void computeLayerCells(DeviceStoreNV& devStore, const int layerIndex, - Vector<Cell>& cellsVector) -{ - const int currentTrackletIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); - const float3& primaryVertex = devStore.getPrimaryVertex(); - int trackletCellsNum = 0; - - if (currentTrackletIndex < devStore.getTracklets()[layerIndex].size()) { - - const Tracklet& currentTracklet{devStore.getTracklets()[layerIndex][currentTrackletIndex]}; - const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; - const int nextLayerFirstTrackletIndex{ - devStore.getTrackletsLookupTable()[layerIndex][nextLayerClusterIndex]}; - const int nextLayerTrackletsNum{static_cast<int>(devStore.getTracklets()[layerIndex + 1].size())}; - - if (devStore.getTracklets()[layerIndex + 1][nextLayerFirstTrackletIndex].firstClusterIndex == nextLayerClusterIndex) { - - const Cluster& firstCellCluster{ - devStore.getClusters()[layerIndex][currentTracklet.firstClusterIndex]}; - const Cluster& secondCellCluster{ - devStore.getClusters()[layerIndex + 1][currentTracklet.secondClusterIndex]}; - const float firstCellClusterQuadraticRCoordinate{firstCellCluster.rCoordinate * firstCellCluster.rCoordinate}; - const float secondCellClusterQuadraticRCoordinate{secondCellCluster.rCoordinate * secondCellCluster.rCoordinate}; - const float3 firstDeltaVector{secondCellCluster.xCoordinate - firstCellCluster.xCoordinate, - secondCellCluster.yCoordinate - firstCellCluster.yCoordinate, secondCellClusterQuadraticRCoordinate - firstCellClusterQuadraticRCoordinate}; - - for (int iNextLayerTracklet{nextLayerFirstTrackletIndex}; - iNextLayerTracklet < nextLayerTrackletsNum && devStore.getTracklets()[layerIndex + 1][iNextLayerTracklet].firstClusterIndex == nextLayerClusterIndex; ++iNextLayerTracklet) { - - const Tracklet& nextTracklet{devStore.getTracklets()[layerIndex + 1][iNextLayerTracklet]}; - const float deltaTanLambda{gpu::GPUCommonMath::Abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(currentTracklet.phiCoordinate - nextTracklet.phiCoordinate)}; - - if (deltaTanLambda < kTrkPar.CellMaxDeltaTanLambda && (deltaPhi < kTrkPar.CellMaxDeltaPhi || gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < kTrkPar.CellMaxDeltaPhi)) { - - const float averageTanLambda{0.5f * (currentTracklet.tanLambda + nextTracklet.tanLambda)}; - const float directionZIntersection{-averageTanLambda * firstCellCluster.rCoordinate + firstCellCluster.zCoordinate}; - const float deltaZ{gpu::GPUCommonMath::Abs(directionZIntersection - primaryVertex.z)}; - - if (deltaZ < kTrkPar.CellMaxDeltaZ[layerIndex]) { - - const Cluster& thirdCellCluster{ - devStore.getClusters()[layerIndex + 2][nextTracklet.secondClusterIndex]}; - - const float thirdCellClusterQuadraticRCoordinate{thirdCellCluster.rCoordinate * thirdCellCluster.rCoordinate}; - - const float3 secondDeltaVector{thirdCellCluster.xCoordinate - firstCellCluster.xCoordinate, - thirdCellCluster.yCoordinate - firstCellCluster.yCoordinate, thirdCellClusterQuadraticRCoordinate - firstCellClusterQuadraticRCoordinate}; - - float3 cellPlaneNormalVector{math_utils::crossProduct(firstDeltaVector, secondDeltaVector)}; - - const float vectorNorm{gpu::GPUCommonMath::Sqrt( - cellPlaneNormalVector.x * cellPlaneNormalVector.x + cellPlaneNormalVector.y * cellPlaneNormalVector.y + cellPlaneNormalVector.z * cellPlaneNormalVector.z)}; - - if (!(vectorNorm < constants::math::FloatMinThreshold || gpu::GPUCommonMath::Abs(cellPlaneNormalVector.z) < constants::math::FloatMinThreshold)) { - - const float inverseVectorNorm{1.0f / vectorNorm}; - const float3 normalizedPlaneVector{cellPlaneNormalVector.x * inverseVectorNorm, cellPlaneNormalVector.y * inverseVectorNorm, cellPlaneNormalVector.z * inverseVectorNorm}; - const float planeDistance{-normalizedPlaneVector.x * (secondCellCluster.xCoordinate - primaryVertex.x) - (normalizedPlaneVector.y * secondCellCluster.yCoordinate - primaryVertex.y) - normalizedPlaneVector.z * secondCellClusterQuadraticRCoordinate}; - const float normalizedPlaneVectorQuadraticZCoordinate{normalizedPlaneVector.z * normalizedPlaneVector.z}; - const float cellTrajectoryRadius{gpu::GPUCommonMath::Sqrt( - (1.0f - normalizedPlaneVectorQuadraticZCoordinate - 4.0f * planeDistance * normalizedPlaneVector.z) / (4.0f * normalizedPlaneVectorQuadraticZCoordinate))}; - const float2 circleCenter{-0.5f * normalizedPlaneVector.x / normalizedPlaneVector.z, -0.5f * normalizedPlaneVector.y / normalizedPlaneVector.z}; - const float distanceOfClosestApproach{gpu::GPUCommonMath::Abs( - cellTrajectoryRadius - gpu::GPUCommonMath::Sqrt(circleCenter.x * circleCenter.x + circleCenter.y * circleCenter.y))}; - - if (distanceOfClosestApproach <= kTrkPar.CellMaxDCA[layerIndex]) { - - cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); - int currentIndex{}; - - if (threadGroup.thread_rank() == 0) { - - currentIndex = cellsVector.extend(threadGroup.size()); - } - - currentIndex = threadGroup.shfl(currentIndex, 0) + threadGroup.thread_rank(); - - cellsVector.emplace(currentIndex, currentTracklet.firstClusterIndex, - nextTracklet.firstClusterIndex, nextTracklet.secondClusterIndex, currentTrackletIndex, - iNextLayerTracklet, normalizedPlaneVector, 1.0f / cellTrajectoryRadius); - ++trackletCellsNum; - } - } - } - } - } - - if (layerIndex > 0) { - - devStore.getCellsPerTrackletTable()[layerIndex - 1][currentTrackletIndex] = trackletCellsNum; - } - } - } -} - -__global__ void layerTrackletsKernel(DeviceStoreNV& devStore, const int layerIndex, - Vector<Tracklet> trackletsVector) -{ - computeLayerTracklets(devStore, layerIndex, trackletsVector); -} - -__global__ void sortTrackletsKernel(DeviceStoreNV& devStore, const int layerIndex, - Vector<Tracklet> tempTrackletArray) -{ - const int currentTrackletIndex{static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x)}; - - if (currentTrackletIndex < tempTrackletArray.size()) { - - const int firstClusterIndex = tempTrackletArray[currentTrackletIndex].firstClusterIndex; - const int offset = atomicAdd(&devStore.getTrackletsPerClusterTable()[layerIndex - 1][firstClusterIndex], - -1) - - 1; - const int startIndex = devStore.getTrackletsLookupTable()[layerIndex - 1][firstClusterIndex]; - - memcpy(&devStore.getTracklets()[layerIndex][startIndex + offset], - &tempTrackletArray[currentTrackletIndex], sizeof(Tracklet)); - } -} - -__global__ void layerCellsKernel(DeviceStoreNV& devStore, const int layerIndex, - Vector<Cell> cellsVector) -{ - computeLayerCells(devStore, layerIndex, cellsVector); -} - -__global__ void sortCellsKernel(DeviceStoreNV& devStore, const int layerIndex, - Vector<Cell> tempCellsArray) -{ - const int currentCellIndex = static_cast<int>(blockDim.x * blockIdx.x + threadIdx.x); - - if (currentCellIndex < tempCellsArray.size()) { - - const int firstTrackletIndex = tempCellsArray[currentCellIndex].getFirstTrackletIndex(); - const int offset = atomicAdd(&devStore.getCellsPerTrackletTable()[layerIndex - 1][firstTrackletIndex], - -1) - - 1; - const int startIndex = devStore.getCellsLookupTable()[layerIndex - 1][firstTrackletIndex]; - - memcpy(&devStore.getCells()[layerIndex][startIndex + offset], &tempCellsArray[currentCellIndex], - sizeof(Cell)); - } -} - -} // namespace GPU - -TrackerTraits* createTrackerTraitsNV() -{ - return new TrackerTraitsNV; -} - -TrackerTraitsNV::TrackerTraitsNV() -{ - mPrimaryVertexContext = new PrimaryVertexContextNV; -} - -TrackerTraitsNV::~TrackerTraitsNV() -{ - delete mPrimaryVertexContext; -} - -void TrackerTraitsNV::computeLayerTracklets() -{ - PrimaryVertexContextNV* primaryVertexContext = static_cast<PrimaryVertexContextNV*>(mPrimaryVertexContext); - - cudaMemcpyToSymbol(GPU::kTrkPar, &mTrkParams, sizeof(TrackingParameters)); - std::array<size_t, constants::its::CellsPerRoad> tempSize; - std::array<int, constants::its::CellsPerRoad> trackletsNum; - std::array<GPU::Stream, constants::its::TrackletsPerRoad> streamArray; - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad; ++iLayer) { - - tempSize[iLayer] = 0; - primaryVertexContext->getTempTrackletArray()[iLayer].reset( - static_cast<int>(primaryVertexContext->getDeviceTracklets()[iLayer + 1].capacity())); - - cub::DeviceScan::ExclusiveSum(static_cast<void*>(NULL), tempSize[iLayer], - primaryVertexContext->getDeviceTrackletsPerClustersTable()[iLayer].get(), - primaryVertexContext->getDeviceTrackletsLookupTable()[iLayer].get(), - primaryVertexContext->getClusters()[iLayer + 1].size()); - - primaryVertexContext->getTempTableArray()[iLayer].reset(static_cast<int>(tempSize[iLayer])); - } - - cudaDeviceSynchronize(); - - for (int iLayer{0}; iLayer < constants::its::TrackletsPerRoad; ++iLayer) { - - const GPU::DeviceProperties& deviceProperties = GPU::Context::getInstance().getDeviceProperties(); - const int clustersNum{static_cast<int>(primaryVertexContext->getClusters()[iLayer].size())}; - dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(clustersNum, 1, 192)}; - dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, clustersNum)}; - - if (iLayer == 0) { - - GPU::layerTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer, primaryVertexContext->getDeviceTracklets()[iLayer].getWeakCopy()); - - } else { - - GPU::layerTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer, primaryVertexContext->getTempTrackletArray()[iLayer - 1].getWeakCopy()); - } - - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" - << std::endl; - - throw std::runtime_error{errorString.str()}; - } - } - - cudaDeviceSynchronize(); - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad; ++iLayer) { - - trackletsNum[iLayer] = primaryVertexContext->getTempTrackletArray()[iLayer].getSizeFromDevice(); - if (trackletsNum[iLayer] == 0) { - continue; - } - primaryVertexContext->getDeviceTracklets()[iLayer + 1].resize(trackletsNum[iLayer]); - - cub::DeviceScan::ExclusiveSum(static_cast<void*>(primaryVertexContext->getTempTableArray()[iLayer].get()), tempSize[iLayer], - primaryVertexContext->getDeviceTrackletsPerClustersTable()[iLayer].get(), - primaryVertexContext->getDeviceTrackletsLookupTable()[iLayer].get(), - primaryVertexContext->getClusters()[iLayer + 1].size(), streamArray[iLayer + 1].get()); - - dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(trackletsNum[iLayer])}; - dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, trackletsNum[iLayer])}; - - GPU::sortTrackletsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer + 1].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer + 1, primaryVertexContext->getTempTrackletArray()[iLayer].getWeakCopy()); - - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" - << std::endl; - - throw std::runtime_error{errorString.str()}; - } - } -} - -void TrackerTraitsNV::computeLayerCells() -{ - - PrimaryVertexContextNV* primaryVertexContext = static_cast<PrimaryVertexContextNV*>(mPrimaryVertexContext); - std::array<size_t, constants::its::CellsPerRoad - 1> tempSize; - std::array<int, constants::its::CellsPerRoad - 1> trackletsNum; - std::array<int, constants::its::CellsPerRoad - 1> cellsNum; - std::array<GPU::Stream, constants::its::CellsPerRoad> streamArray; - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad - 1; ++iLayer) { - - tempSize[iLayer] = 0; - trackletsNum[iLayer] = primaryVertexContext->getDeviceTracklets()[iLayer + 1].getSizeFromDevice(); - primaryVertexContext->getTempCellArray()[iLayer].reset( - static_cast<int>(primaryVertexContext->getDeviceCells()[iLayer + 1].capacity())); - if (trackletsNum[iLayer] == 0) { - continue; - } - cub::DeviceScan::ExclusiveSum(static_cast<void*>(NULL), tempSize[iLayer], - primaryVertexContext->getDeviceCellsPerTrackletTable()[iLayer].get(), - primaryVertexContext->getDeviceCellsLookupTable()[iLayer].get(), trackletsNum[iLayer]); - - primaryVertexContext->getTempTableArray()[iLayer].reset(static_cast<int>(tempSize[iLayer])); - } - - cudaDeviceSynchronize(); - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad; ++iLayer) { - const GPU::DeviceProperties& deviceProperties = GPU::Context::getInstance().getDeviceProperties(); - const int trackletsSize = primaryVertexContext->getDeviceTracklets()[iLayer].getSizeFromDevice(); - if (trackletsSize == 0) { - continue; - } - dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(trackletsSize)}; - dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, trackletsSize)}; - - if (iLayer == 0) { - - GPU::layerCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer, primaryVertexContext->getDeviceCells()[iLayer].getWeakCopy()); - - } else { - - GPU::layerCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer, primaryVertexContext->getTempCellArray()[iLayer - 1].getWeakCopy()); - } - - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" - << std::endl; - - throw std::runtime_error{errorString.str()}; - } - } - - cudaDeviceSynchronize(); - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad - 1; ++iLayer) { - cellsNum[iLayer] = primaryVertexContext->getTempCellArray()[iLayer].getSizeFromDevice(); - if (cellsNum[iLayer] == 0) { - continue; - } - primaryVertexContext->getDeviceCells()[iLayer + 1].resize(cellsNum[iLayer]); - - cub::DeviceScan::ExclusiveSum(static_cast<void*>(primaryVertexContext->getTempTableArray()[iLayer].get()), tempSize[iLayer], - primaryVertexContext->getDeviceCellsPerTrackletTable()[iLayer].get(), - primaryVertexContext->getDeviceCellsLookupTable()[iLayer].get(), trackletsNum[iLayer], - streamArray[iLayer + 1].get()); - - dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(trackletsNum[iLayer])}; - dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, trackletsNum[iLayer])}; - - GPU::sortCellsKernel<<<blocksGrid, threadsPerBlock, 0, streamArray[iLayer + 1].get()>>>(primaryVertexContext->getDeviceContext(), - iLayer + 1, primaryVertexContext->getTempCellArray()[iLayer].getWeakCopy()); - - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" - << std::endl; - - throw std::runtime_error{errorString.str()}; - } - } - - cudaDeviceSynchronize(); - - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad; ++iLayer) { - - int cellsSize = 0; - if (iLayer == 0) { - - cellsSize = primaryVertexContext->getDeviceCells()[iLayer].getSizeFromDevice(); - if (cellsSize == 0) - continue; - } else { - - cellsSize = cellsNum[iLayer - 1]; - if (cellsSize == 0) - continue; - primaryVertexContext->getDeviceCellsLookupTable()[iLayer - 1].copyIntoVector( - primaryVertexContext->getCellsLookupTable()[iLayer - 1], trackletsNum[iLayer - 1]); - } - - primaryVertexContext->getDeviceCells()[iLayer].copyIntoVector(primaryVertexContext->getCells()[iLayer], cellsSize); - } -} - -void TrackerTraitsNV::refitTracks(const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) -{ - PrimaryVertexContextNV* pvctx = static_cast<PrimaryVertexContextNV*>(mPrimaryVertexContext); - - std::array<const Cell*, 5> cells; - for (int iLayer = 0; iLayer < 5; iLayer++) { - cells[iLayer] = pvctx->getDeviceCells()[iLayer].get(); - } - std::array<const Cluster*, 7> clusters; - for (int iLayer = 0; iLayer < 7; iLayer++) { - clusters[iLayer] = pvctx->getDeviceClusters()[iLayer].get(); - } - mChainRunITSTrackFit(*mChain, mPrimaryVertexContext->getRoads(), clusters, cells, tf, tracks); -} -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/Utils.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/Utils.cu deleted file mode 100644 index 5dbe67abe9e51..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/Utils.cu +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Utils.cu -/// \brief -/// - -#include "ITStrackingCUDA/Utils.h" - -#include <sstream> -#include <stdexcept> - -#ifndef GPUCA_GPUCODE_GENRTC -#include <cuda_profiler_api.h> -#include <cooperative_groups.h> -#endif - -#include "ITStrackingCUDA/Context.h" - -#include <iostream> - -namespace -{ - -int roundUp(const int numToRound, const int multiple) -{ - if (multiple == 0) { - - return numToRound; - } - - int remainder{numToRound % multiple}; - - if (remainder == 0) { - - return numToRound; - } - - return numToRound + multiple - remainder; -} - -int findNearestDivisor(const int numToRound, const int divisor) -{ - - if (numToRound > divisor) { - - return divisor; - } - - int result = numToRound; - - while (divisor % result != 0) { - - ++result; - } - - return result; -} - -} // namespace - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -void Utils::Host::checkCUDAError(const cudaError_t error, const char* file, const int line) -{ - if (error != cudaSuccess) { - - std::ostringstream errorString{}; - - errorString << file << ":" << line << " CUDA API returned error [" << cudaGetErrorString(error) << "] (code " - << error << ")" << std::endl; - - throw std::runtime_error{errorString.str()}; - } -} - -dim3 Utils::Host::getBlockSize(const int colsNum) -{ - return getBlockSize(colsNum, 1); -} - -dim3 Utils::Host::getBlockSize(const int colsNum, const int rowsNum) -{ - const DeviceProperties& deviceProperties = Context::getInstance().getDeviceProperties(); - return getBlockSize(colsNum, rowsNum, deviceProperties.cudaCores / deviceProperties.maxBlocksPerSM); -} - -dim3 Utils::Host::getBlockSize(const int colsNum, const int rowsNum, const int maxThreadsPerBlock) -{ - const DeviceProperties& deviceProperties = Context::getInstance().getDeviceProperties(); - int xThreads = max(min(colsNum, deviceProperties.maxThreadsDim.x), 1); - int yThreads = max(min(rowsNum, deviceProperties.maxThreadsDim.y), 1); - const int totalThreads = roundUp(min(xThreads * yThreads, maxThreadsPerBlock), - deviceProperties.warpSize); - - if (xThreads > yThreads) { - - xThreads = findNearestDivisor(xThreads, totalThreads); - yThreads = totalThreads / xThreads; - - } else { - - yThreads = findNearestDivisor(yThreads, totalThreads); - xThreads = totalThreads / yThreads; - } - - return dim3{static_cast<unsigned int>(xThreads), static_cast<unsigned int>(yThreads)}; -} - -dim3 Utils::Host::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum) -{ - - return getBlocksGrid(threadsPerBlock, rowsNum, 1); -} - -dim3 Utils::Host::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum, const int colsNum) -{ - - return dim3{1 + (rowsNum - 1) / threadsPerBlock.x, 1 + (colsNum - 1) / threadsPerBlock.y}; -} - -void Utils::Host::gpuMalloc(void** p, const int size) -{ - checkCUDAError(cudaMalloc(p, size), __FILE__, __LINE__); -} - -void Utils::Host::gpuFree(void* p) -{ - checkCUDAError(cudaFree(p), __FILE__, __LINE__); -} - -void Utils::Host::gpuMemset(void* p, int value, int size) -{ - checkCUDAError(cudaMemset(p, value, size), __FILE__, __LINE__); -} - -void Utils::Host::gpuMemcpyHostToDevice(void* dst, const void* src, int size) -{ - checkCUDAError(cudaMemcpy(dst, src, size, cudaMemcpyHostToDevice), __FILE__, __LINE__); -} - -void Utils::Host::gpuMemcpyHostToDeviceAsync(void* dst, const void* src, int size, Stream& stream) -{ - checkCUDAError(cudaMemcpyAsync(dst, src, size, cudaMemcpyHostToDevice, stream.get()), __FILE__, __LINE__); -} - -void Utils::Host::gpuMemcpyDeviceToHost(void* dst, const void* src, int size) -{ - checkCUDAError(cudaMemcpy(dst, src, size, cudaMemcpyDeviceToHost), __FILE__, __LINE__); -} - -// void Utils::Host::gpuStartProfiler() -// { -// checkCUDAError(cudaProfilerStart(), __FILE__, __LINE__); -// } - -// void Utils::Host::gpuStopProfiler() -// { -// checkCUDAError(cudaProfilerStop(), __FILE__, __LINE__); -// } - -GPUd() int Utils::Device::getLaneIndex() -{ - uint32_t laneIndex; - asm volatile("mov.u32 %0, %%laneid;" - : "=r"(laneIndex)); - return static_cast<int>(laneIndex); -} - -GPUd() int Utils::Device::shareToWarp(const int value, const int laneIndex) -{ - cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); - return threadGroup.shfl(value, laneIndex); -} - -GPUd() int Utils::Device::gpuAtomicAdd(int* p, const int incrementSize) -{ - return atomicAdd(p, incrementSize); -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu deleted file mode 100644 index 790a7b9f5b3bb..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsGPU.cu.cu -/// \brief -/// \author matteo.concas@cern.ch - -#include <iostream> -#include <sstream> -#include <array> -#include <assert.h> - -#ifndef GPUCA_GPUCODE_GENRTC -#include <cub/cub.cuh> -#endif - -#include "ITStracking/MathUtils.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingCUDA/Utils.h" -#include "ITStrackingCUDA/ClusterLinesGPU.h" -#include "ITStrackingCUDA/Context.h" -#include "ITStrackingCUDA/Stream.h" -#include "ITStrackingCUDA/VertexerTraitsGPU.h" - -namespace o2 -{ -namespace its -{ - -using constants::index_table::PhiBins; -using constants::index_table::ZBins; -using constants::its::LayersRCoordinate; -using constants::its::LayersZCoordinate; -using constants::its::VertexerHistogramVolume; -using constants::math::TwoPi; -using index_table_utils::getPhiBinIndex; -using index_table_utils::getZBinIndex; -using math_utils::getNormalizedPhiCoordinate; - -GPUh() void gpuThrowOnError() -{ - cudaError_t error = cudaGetLastError(); - - if (error != cudaSuccess) { - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << cudaGetErrorString(error) << "] (code " << error << ")" << std::endl; - throw std::runtime_error{errorString.str()}; - } -} - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -VertexerTraitsGPU::VertexerTraitsGPU() -{ - setIsGPU(true); - std::cout << "[DEBUG] Creating file: dbg_ITSVertexerGPU.root" << std::endl; - mDebugger = new StandaloneDebugger::StandaloneDebugger("dbg_ITSVertexerGPU.root"); -} - -VertexerTraitsGPU::~VertexerTraitsGPU() -{ - delete mDebugger; -} -#else -VertexerTraitsGPU::VertexerTraitsGPU() -{ - setIsGPU(true); -} - -#endif - -void VertexerTraitsGPU::initialise(ROframe* event) -{ - reset(); - arrangeClusters(event); - mStoreVertexerGPUPtr = mStoreVertexerGPU.initialise(mClusters, mIndexTables); -} - -namespace GPU -{ - -template <typename... Args> -GPUd() void printOnThread(const int tId, const char* str, Args... args) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf(str, args...); - } -} - -GPUd() void printVectorOnThread(const char* name, Vector<int>& vector, size_t size, const int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf("vector %s :", name); - for (int i{0}; i < size; ++i) { - printf("%d ", vector[i]); - } - printf("\n"); - } -} - -GPUg() void printVectorKernel(DeviceStoreVertexerGPU& store, const int threadId) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { - for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[0] - 1; ++i) { - printf("%d: %d\n", i, store.getHistogramXYZ()[0].get()[i]); - } - printf("\n"); - for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[1] - 1; ++i) { - printf("%d: %d\n", i, store.getHistogramXYZ()[1].get()[i]); - } - printf("\n"); - for (int i{0}; i < store.getConfig().histConf.nBinsXYZ[2] - 1; ++i) { - printf("%d: %d\n", i, store.getHistogramXYZ()[2].get()[i]); - } - printf("\n"); - } -} - -GPUg() void dumpMaximaKernel(DeviceStoreVertexerGPU& store, const int threadId) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { - printf("XmaxBin: %d at index: %d | YmaxBin: %d at index: %d | ZmaxBin: %d at index: %d\n", - store.getTmpVertexPositionBins()[0].value, store.getTmpVertexPositionBins()[0].key, - store.getTmpVertexPositionBins()[1].value, store.getTmpVertexPositionBins()[1].key, - store.getTmpVertexPositionBins()[2].value, store.getTmpVertexPositionBins()[2].key); - } -} - -GPUg() void trackleterKernel( - DeviceStoreVertexerGPU& store, - const TrackletingLayerOrder layerOrder, - const float phiCut) -{ - const size_t nClustersMiddleLayer = store.getClusters()[1].size(); - for (size_t currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { - if (currentClusterIndex < nClustersMiddleLayer) { - int storedTracklets{0}; - const size_t stride{currentClusterIndex * store.getConfig().maxTrackletsPerCluster}; - const Cluster& currentCluster = store.getClusters()[1][currentClusterIndex]; // assign-constructor may be a problem, check - const VertexerLayerName adjacentLayerIndex{layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer ? VertexerLayerName::innermostLayer : VertexerLayerName::outerLayer}; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, static_cast<int>(adjacentLayerIndex), 0.f, 50.f, phiCut / 2)}; - if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - if (phiBinsNum < 0) { - phiBinsNum += PhiBins; - } - const size_t nClustersAdjacentLayer = store.getClusters()[static_cast<int>(adjacentLayerIndex)].size(); - for (size_t iPhiBin{(size_t)selectedBinsRect.y}, iPhiCount{0}; iPhiCount < (size_t)phiBinsNum; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int firstRowClusterIndex{store.getIndexTable(adjacentLayerIndex)[firstBinIndex]}; - const int maxRowClusterIndex{store.getIndexTable(adjacentLayerIndex)[firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1]}; - for (size_t iAdjacentCluster{(size_t)firstRowClusterIndex}; iAdjacentCluster < (size_t)maxRowClusterIndex && iAdjacentCluster < nClustersAdjacentLayer; ++iAdjacentCluster) { - const Cluster& adjacentCluster = store.getClusters()[static_cast<int>(adjacentLayerIndex)][iAdjacentCluster]; // assign-constructor may be a problem, check - if (gpu::GPUCommonMath::Abs(currentCluster.phiCoordinate - adjacentCluster.phiCoordinate) < phiCut) { - if (storedTracklets < store.getConfig().maxTrackletsPerCluster) { - if (layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer) { - store.getDuplets01().emplace(stride + storedTracklets, iAdjacentCluster, currentClusterIndex, adjacentCluster, currentCluster); - } else { - store.getDuplets12().emplace(stride + storedTracklets, currentClusterIndex, iAdjacentCluster, currentCluster, adjacentCluster); - } - ++storedTracklets; - } else { - printf("debug: leaving tracklet behind\n"); - } - } - } - } - } - store.getNFoundTracklets(layerOrder).emplace(currentClusterIndex, storedTracklets); - } - } -} - -GPUg() void trackletSelectionKernel( - DeviceStoreVertexerGPU& store, - const unsigned char isInitRun = false, - const float tanLambdaCut = 0.025f, - const float phiCut = 0.002f) -{ - const size_t nClustersMiddleLayer = store.getClusters()[1].size(); - for (size_t currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { - const int stride{static_cast<int>(currentClusterIndex * store.getConfig().maxTrackletsPerCluster)}; - int validTracklets{0}; - for (int iTracklet12{0}; iTracklet12 < store.getNFoundTracklets(TrackletingLayerOrder::fromMiddleToOuterLayer)[currentClusterIndex]; ++iTracklet12) { - for (int iTracklet01{0}; iTracklet01 < store.getNFoundTracklets(TrackletingLayerOrder::fromInnermostToMiddleLayer)[currentClusterIndex] && validTracklets < store.getConfig().maxTrackletsPerCluster; ++iTracklet01) { - const float deltaTanLambda{gpu::GPUCommonMath::Abs(store.getDuplets01()[stride + iTracklet01].tanLambda - store.getDuplets12()[stride + iTracklet12].tanLambda)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(store.getDuplets01()[stride + iTracklet01].phiCoordinate - store.getDuplets12()[stride + iTracklet12].phiCoordinate)}; - if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != store.getConfig().maxTrackletsPerCluster) { - assert(store.getDuplets01()[stride + iTracklet01].secondClusterIndex == store.getDuplets12()[stride + iTracklet12].firstClusterIndex); - if (!isInitRun) { - store.getLines().emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, store.getDuplets01()[stride + iTracklet01], store.getClusters()[0].get(), store.getClusters()[1].get()); -#ifdef _ALLOW_DEBUG_TREES_ITS_ - store.getDupletIndices()[0].emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet01); - store.getDupletIndices()[1].emplace(store.getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet12); -#endif - } - ++validTracklets; - } - } - } - if (isInitRun) { - store.getNFoundLines().emplace(currentClusterIndex, validTracklets); - if (validTracklets >= store.getConfig().maxTrackletsPerCluster) { - printf("Warning: not enough space for tracklet selection, some lines will be left behind\n"); - } - } - } - if (blockIdx.x * blockDim.x + threadIdx.x == 0) { - // first thread I want to write an empty line after last found, as debug flag. Might delete later - store.getLines().emplace(store.getNExclusiveFoundLines()[store.getClusters()[1].size() - 1] + store.getNFoundLines()[store.getClusters()[1].size() - 1]); - } -} - -GPUg() void computeCentroidsKernel(DeviceStoreVertexerGPU& store, - const float pairCut) -{ - const int nLines = store.getNExclusiveFoundLines()[store.getClusters()[1].size() - 1] + store.getNFoundLines()[store.getClusters()[1].size() - 1]; - const int maxIterations{nLines * (nLines - 1) / 2}; - for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < maxIterations; currentThreadIndex += blockDim.x * gridDim.x) { - int iFirstLine = currentThreadIndex / nLines; - int iSecondLine = currentThreadIndex % nLines; - if (iSecondLine <= iFirstLine) { - iFirstLine = nLines - iFirstLine - 2; - iSecondLine = nLines - iSecondLine - 1; - } - if (Line::getDCA(store.getLines()[iFirstLine], store.getLines()[iSecondLine]) < pairCut) { - ClusterLinesGPU cluster{store.getLines()[iFirstLine], store.getLines()[iSecondLine]}; - if (cluster.getVertex()[0] * cluster.getVertex()[0] + cluster.getVertex()[1] * cluster.getVertex()[1] < 1.98f * 1.98f) { - // printOnThread(0, "xCentr: %f, yCentr: %f \n", cluster.getVertex()[0], cluster.getVertex()[1]); - store.getXYCentroids().emplace(2 * currentThreadIndex, cluster.getVertex()[0]); - store.getXYCentroids().emplace(2 * currentThreadIndex + 1, cluster.getVertex()[1]); - } else { - // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. - store.getXYCentroids().emplace(2 * currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[0]); - store.getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[1]); - } - } else { - // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. - store.getXYCentroids().emplace(2 * currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[0]); - store.getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[1]); - } - } -} - -GPUg() void computeZCentroidsKernel(DeviceStoreVertexerGPU& store, - const float pairCut, const int binOpeningX, const int binOpeningY) -{ - const int nLines = store.getNExclusiveFoundLines()[store.getClusters()[1].size() - 1] + store.getNFoundLines()[store.getClusters()[1].size() - 1]; - for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < nLines; currentThreadIndex += blockDim.x * gridDim.x) { - if (store.getTmpVertexPositionBins()[0].value || store.getTmpVertexPositionBins()[1].value) { - float tmpX{store.getConfig().histConf.lowHistBoundariesXYZ[0] + store.getTmpVertexPositionBins()[0].key * store.getConfig().histConf.binSizeHistX + store.getConfig().histConf.binSizeHistX / 2}; - int sumWX{store.getTmpVertexPositionBins()[0].value}; - float wX{tmpX * store.getTmpVertexPositionBins()[0].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[0].key - binOpeningX)}; iBin < gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[0].key + binOpeningX + 1, store.getConfig().histConf.nBinsXYZ[0] - 1); ++iBin) { - if (iBin != store.getTmpVertexPositionBins()[0].key) { - wX += (store.getConfig().histConf.lowHistBoundariesXYZ[0] + iBin * store.getConfig().histConf.binSizeHistX + store.getConfig().histConf.binSizeHistX / 2) * store.getHistogramXYZ()[0].get()[iBin]; - sumWX += store.getHistogramXYZ()[0].get()[iBin]; - } - } - float tmpY{store.getConfig().histConf.lowHistBoundariesXYZ[1] + store.getTmpVertexPositionBins()[1].key * store.getConfig().histConf.binSizeHistY + store.getConfig().histConf.binSizeHistY / 2}; - int sumWY{store.getTmpVertexPositionBins()[1].value}; - float wY{tmpY * store.getTmpVertexPositionBins()[1].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[1].key - binOpeningY)}; iBin < gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[1].key + binOpeningY + 1, store.getConfig().histConf.nBinsXYZ[1] - 1); ++iBin) { - if (iBin != store.getTmpVertexPositionBins()[1].key) { - wY += (store.getConfig().histConf.lowHistBoundariesXYZ[1] + iBin * store.getConfig().histConf.binSizeHistY + store.getConfig().histConf.binSizeHistY / 2) * store.getHistogramXYZ()[1].get()[iBin]; - sumWY += store.getHistogramXYZ()[1].get()[iBin]; - } - } - store.getBeamPosition().emplace(0, wX / sumWX); - store.getBeamPosition().emplace(1, wY / sumWY); - float fakeBeamPoint1[3] = {store.getBeamPosition()[0], store.getBeamPosition()[1], -1}; // get two points laying at different z, to create line object - float fakeBeamPoint2[3] = {store.getBeamPosition()[0], store.getBeamPosition()[1], 1}; - Line pseudoBeam = {fakeBeamPoint1, fakeBeamPoint2}; - if (Line::getDCA(store.getLines()[currentThreadIndex], pseudoBeam) < pairCut) { - ClusterLinesGPU cluster{store.getLines()[currentThreadIndex], pseudoBeam}; - store.getZCentroids().emplace(currentThreadIndex, cluster.getVertex()[2]); - } else { - store.getZCentroids().emplace(currentThreadIndex, 2 * store.getConfig().histConf.lowHistBoundariesXYZ[2]); - } - } - } -} - -GPUg() void computeVertexKernel(DeviceStoreVertexerGPU& store, const int vertIndex, const int minContributors, const int binOpeningZ) -{ - for (size_t currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < binOpeningZ; currentThreadIndex += blockDim.x * gridDim.x) { - if (currentThreadIndex == 0) { - if (store.getTmpVertexPositionBins()[2].value > 1 && (store.getTmpVertexPositionBins()[0].value || store.getTmpVertexPositionBins()[1].value)) { - float z{store.getConfig().histConf.lowHistBoundariesXYZ[2] + store.getTmpVertexPositionBins()[2].key * store.getConfig().histConf.binSizeHistZ + store.getConfig().histConf.binSizeHistZ / 2}; - float ex{0.f}; - float ey{0.f}; - float ez{0.f}; - int sumWZ{store.getTmpVertexPositionBins()[2].value}; - float wZ{z * store.getTmpVertexPositionBins()[2].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store.getTmpVertexPositionBins()[2].key - binOpeningZ)}; iBin < gpu::GPUCommonMath::Min(store.getTmpVertexPositionBins()[2].key + binOpeningZ + 1, store.getConfig().histConf.nBinsXYZ[2] - 1); ++iBin) { - if (iBin != store.getTmpVertexPositionBins()[2].key) { - wZ += (store.getConfig().histConf.lowHistBoundariesXYZ[2] + iBin * store.getConfig().histConf.binSizeHistZ + store.getConfig().histConf.binSizeHistZ / 2) * store.getHistogramXYZ()[2].get()[iBin]; - sumWZ += store.getHistogramXYZ()[2].get()[iBin]; - } - store.getHistogramXYZ()[2].get()[iBin] = 0; - } - if (sumWZ > minContributors || vertIndex == 0) { - store.getVertices().emplace(vertIndex, store.getBeamPosition()[0], store.getBeamPosition()[1], wZ / sumWZ, ex, ey, ez, sumWZ); - } else { - store.getVertices().emplace(vertIndex); - } - } else { - store.getVertices().emplace(vertIndex); - } - } - } -} -} // namespace GPU - -void VertexerTraitsGPU::computeTracklets() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - - GPU::trackleterKernel<<<blocksGrid, threadsPerBlock>>>( - getDeviceContext(), - GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, - mVrtParams.phiCut); - - GPU::trackleterKernel<<<blocksGrid, threadsPerBlock>>>( - getDeviceContext(), - GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, - mVrtParams.phiCut); - - gpuThrowOnError(); - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { - mDebugger->fillCombinatoricsTree(mClusters, - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mEvent); - } -#endif -} - -void VertexerTraitsGPU::computeTrackletMatching() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); - - GPU::trackletSelectionKernel<<<blocksGrid, threadsPerBlock>>>( - getDeviceContext(), - true, // isInitRun - mVrtParams.tanLambdaCut, - mVrtParams.phiCut); - - cub::DeviceScan::ExclusiveSum(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - mStoreVertexerGPU.getNFoundLines().get(), - mStoreVertexerGPU.getNExclusiveFoundLines().get(), - mClusters[1].size()); - - GPU::trackletSelectionKernel<<<blocksGrid, threadsPerBlock>>>( - getDeviceContext(), - false, // isInitRun - mVrtParams.tanLambdaCut, - mVrtParams.phiCut); - - gpuThrowOnError(); - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::TrackletTreeAll)) { - mDebugger->fillTrackletSelectionTree(mClusters, - mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mStoreVertexerGPU.getDupletIndicesFromGPU(), - mEvent); - } - mTracklets = mStoreVertexerGPU.getLinesFromGPU(); - if (isDebugFlag(VertexerDebug::LineTreeAll)) { - mDebugger->fillPairsInfoTree(mTracklets, mEvent); - } - if (isDebugFlag(VertexerDebug::LineSummaryAll)) { - mDebugger->fillLinesSummaryTree(mTracklets, mEvent); - } -#endif -} - -void VertexerTraitsGPU::computeVertices() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::Host::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::Host::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); - int nLines = mStoreVertexerGPU.getNExclusiveFoundLines().getElementFromDevice(mClusters[1].size() - 1) + mStoreVertexerGPU.getNFoundLines().getElementFromDevice(mClusters[1].size() - 1); - int nCentroids{static_cast<int>(nLines * (nLines - 1) / 2)}; - int* histogramXY[2] = {mStoreVertexerGPU.getHistogramXYZ()[0].get(), mStoreVertexerGPU.getHistogramXYZ()[1].get()}; - float tmpArrayLow[2] = {mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[1]}; - float tmpArrayHigh[2] = {mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[1]}; - GPU::computeCentroidsKernel<<<blocksGrid, threadsPerBlock>>>(getDeviceContext(), - mVrtParams.histPairCut); - - cub::DeviceHistogram::MultiHistogramEven<2, 2>(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage - bufferSize, // temp_storage_bytes - mStoreVertexerGPU.getXYCentroids().get(), // d_samples - histogramXY, // d_histogram - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ, // num_levels - tmpArrayLow, // lower_level - tmpArrayHigh, // fupper_level - nCentroids); // num_row_pixels - cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - histogramXY[0], - mStoreVertexerGPU.getTmpVertexPositionBins().get(), - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0]); - cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - histogramXY[1], - mStoreVertexerGPU.getTmpVertexPositionBins().get() + 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0]); - GPU::computeZCentroidsKernel<<<blocksGrid, threadsPerBlock>>>(getDeviceContext(), mVrtParams.histPairCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[0], mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[1]); - cub::DeviceHistogram::HistogramEven(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage - bufferSize, // temp_storage_bytes - mStoreVertexerGPU.getZCentroids().get(), // d_samples - mStoreVertexerGPU.getHistogramXYZ()[2].get(), // d_histogram - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2], // num_levels - mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[2], // lower_level - mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[2], // fupper_level - nLines); // num_row_pixels - for (int iVertex{0}; iVertex < mStoreVertexerGPU.getConfig().nMaxVertices; ++iVertex) { - cub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - mStoreVertexerGPU.getHistogramXYZ()[2].get(), - mStoreVertexerGPU.getTmpVertexPositionBins().get() + 2, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2]); -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::HistCentroids) && !iVertex) { - mDebugger->fillXYZHistogramTree(std::array<std::vector<int>, 3>{mStoreVertexerGPU.getHistogramXYFromGPU()[0], - mStoreVertexerGPU.getHistogramXYFromGPU()[1], mStoreVertexerGPU.getHistogramZFromGPU()}, - std::array<int, 3>{mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0] - 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[1] - 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2] - 1}); - } -#endif - GPU::computeVertexKernel<<<blocksGrid, 5>>>(getDeviceContext(), iVertex, mVrtParams.clusterContributorsCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[2]); - } - std::vector<GPU::GPUVertex> vertices; - vertices.resize(mStoreVertexerGPU.getConfig().nMaxVertices); - mStoreVertexerGPU.getVertices().copyIntoSizedVector(vertices); - - for (auto& vertex : vertices) { - if (vertex.realVertex) { - mVertices.emplace_back(vertex.xCoord, vertex.yCoord, vertex.zCoord, std::array<float, 6>{0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, vertex.contributors, 0.f, -9); - } - } - - gpuThrowOnError(); -} - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -void VertexerTraitsGPU::computeMCFiltering() -{ - std::vector<Tracklet> tracklets01 = mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer); - std::vector<Tracklet> tracklets12 = mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer); - std::vector<int> labels01 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer); - std::vector<int> labels12 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer); - VertexerStoreConfigurationGPU tmpGPUConf; - const int stride = tmpGPUConf.maxTrackletsPerCluster; - - filterTrackletsWithMC(tracklets01, tracklets12, labels01, labels12, stride); - mStoreVertexerGPU.updateFoundDuplets(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, labels01); - mStoreVertexerGPU.updateDuplets(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, tracklets01); - mStoreVertexerGPU.updateFoundDuplets(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, labels12); - mStoreVertexerGPU.updateDuplets(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, tracklets12); - - if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { - mDebugger->fillCombinatoricsTree(mClusters, - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mEvent); - } -} -#endif - -VertexerTraits* createVertexerTraitsGPU() -{ - return new VertexerTraitsGPU; -} - -} // namespace its -} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/hip/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/hip/CMakeLists.txt deleted file mode 100644 index b857741663c64..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -set(CMAKE_CXX_COMPILER ${hip_HIPCC_EXECUTABLE}) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") - -message(STATUS "Building ITS HIP vertexer") -o2_add_library(ITStrackingHIP - SOURCES src/ClusterLinesHIP.hip.cxx - src/ContextHIP.hip.cxx - # src/DeviceStoreHIP.hip.cxx - src/DeviceStoreVertexerHIP.hip.cxx - src/StreamHIP.hip.cxx - # src/TrackerTraitsHIP.hip.cxx - src/VertexerTraitsHIP.hip.cxx - src/UtilsHIP.hip.cxx - PUBLIC_LINK_LIBRARIES O2::ITStracking - hip::host - hip::device - hip::hipcub - TARGETVARNAME targetName) - -target_compile_definitions( - ${targetName} PRIVATE $<TARGET_PROPERTY:O2::ITStracking,COMPILE_DEFINITIONS>) - -if(HIP_AMDGPUTARGET) - # Need to add gpu target also to link flags due to gpu-rdc option - target_link_options(${targetName} PUBLIC --amdgpu-target=${HIP_AMDGPUTARGET}) -endif() diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ArrayHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ArrayHIP.h deleted file mode 100644 index e728a0ae7b530..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ArrayHIP.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ArrayHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_ARRAY_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_ARRAY_HIP_H_ - -#include <hip/hip_runtime.h> - -#include "GPUCommonDef.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace -{ -template <typename T, size_t Size> -struct ArrayTraitsHIP final { - typedef T InternalArray[Size]; - - GPUhd() static constexpr T& getReference(const InternalArray& internalArray, size_t index) noexcept - { - return const_cast<T&>(internalArray[index]); - } - - GPUhd() static constexpr T* getPointer(const InternalArray& internalArray) noexcept - { - return const_cast<T*>(internalArray); - } -}; -} // namespace - -template <typename T, size_t Size> -struct ArrayHIP final { - - void copy(const ArrayHIP<T, Size>& t) - { -#ifdef __OPENCL__ - for (size_t i{0}; i < Size; ++i) { - InternalArray[i] = t[i]; - } -#else - memcpy(InternalArray, t.data(), Size * sizeof(T)); -#endif - } - - GPUhd() T* data() noexcept { return const_cast<T*>(InternalArray); } - GPUhd() const T* data() const noexcept { return const_cast<T*>(InternalArray); } - GPUhd() T& operator[](const int index) noexcept { return const_cast<T&>(InternalArray[index]); } - GPUhd() constexpr T& operator[](const int index) const noexcept { return const_cast<T&>(InternalArray[index]); } - GPUhd() size_t size() const noexcept { return Size; } - - T InternalArray[Size]; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_ARRAY_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ClusterLinesHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ClusterLinesHIP.h deleted file mode 100644 index 3a8f92998dc8e..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ClusterLinesHIP.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ClusterLinesHIP.h -/// \brief GPU-compliant version of ClusterLines, for the moment separated, might create a common traits for ClusterLines + later specifications for each arch, later. -/// \ author: mconcas@cern.ch - -#ifndef O2_ITS_TRACKING_INCLUDE_CLUSTERLINES_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_CLUSTERLINES_HIP_H_ - -#include <hip/hip_runtime.h> -#include "GPUCommonDef.h" -#include "ITStracking/ClusterLines.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -struct GPUVertex final { - GPUhd() GPUVertex() : realVertex{false} - { - } - - GPUhd() GPUVertex(float x, float y, float z, float eX, float eY, float eZ, int contrib) : xCoord{x}, - yCoord{y}, - zCoord{z}, - errorX{eZ}, - errorY{eY}, - errorZ{eZ}, - contributors{contrib}, - realVertex{true} - { - } - float xCoord; - float yCoord; - float zCoord; - float errorX; - float errorY; - float errorZ; - int contributors; - unsigned char realVertex; -}; - -class ClusterLinesHIP final -{ - public: - GPUd() ClusterLinesHIP(const Line& firstLine, const Line& secondLine); // poor man solution to calculate duplets' centroid - GPUd() void computeClusterCentroid(); - GPUd() inline float* getVertex() { return mVertex; } - - private: - float mAMatrix[6]; // AX=B - float mBMatrix[3]; // AX=B - int mLabels[2]; // labels - float mVertexCandidate[3]; // vertex candidate - float mWeightMatrix[9]; // weight matrix - float mVertex[3]; // cluster centroid position -}; - -} // namespace GPU -} // namespace its -} // namespace o2 -#endif /* O2_ITS_TRACKING_INCLUDE_CLUSTERLINES_HIP_H_ */ \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ContextHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ContextHIP.h deleted file mode 100644 index 4b11d7d876a28..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/ContextHIP.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ContextHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_CONTEXT_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_CONTEXT_HIP_H_ - -#include <string> -#include <vector> -// #include "ITStracking/Definitions.h" -#include <hip/hip_runtime_api.h> -#include "GPUCommonDef.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -struct DeviceProperties final { - std::string name; - int gpuProcessors; - int streamProcessors; - long globalMemorySize; - long constantMemorySize; - long sharedMemorySize; - long maxClockRate; - int busWidth; - long l2CacheSize; - long registersPerBlock; - int warpSize; - int maxThreadsPerBlock; - int maxBlocksPerSM; - dim3 maxThreadsDim; - dim3 maxGridDim; -}; - -class ContextHIP final -{ - public: - static ContextHIP& getInstance(); - - ContextHIP(const ContextHIP&); - ContextHIP& operator=(const ContextHIP&); - - const DeviceProperties& getDeviceProperties(); - const DeviceProperties& getDeviceProperties(const int); - - private: - ContextHIP(bool dumpDevices = true); - ~ContextHIP() = default; - - int mDevicesNum; - std::vector<DeviceProperties> mDeviceProperties; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_CONTEXT_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/DeviceStoreVertexerHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/DeviceStoreVertexerHIP.h deleted file mode 100644 index 8b41060de7728..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/DeviceStoreVertexerHIP.h +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DeviceStoreVertexerHIP.h -/// \brief This class serves as memory interface for GPU vertexer. It will access needed data structures from devicestore apis. -/// routines as static as possible. -/// \author matteo.concas@cern.ch - -#ifndef O2_ITS_TRACKING_INCLUDE_DEVICESTOREVERTEXER_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_DEVICESTOREVERTEXER_HIP_H_ - -#include <hipcub/hipcub.hpp> - -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Tracklet.h" -#include "ITStracking/ClusterLines.h" -#include "ITStrackingHIP/ArrayHIP.h" -#include "ITStrackingHIP/ClusterLinesHIP.h" -#include "ITStrackingHIP/UniquePointerHIP.h" -#include "ITStrackingHIP/VectorHIP.h" -#include "GPUCommonDef.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -enum class TrackletingLayerOrder { - fromInnermostToMiddleLayer, - fromMiddleToOuterLayer -}; - -enum class VertexerLayerName { - innermostLayer, - middleLayer, - outerLayer -}; - -typedef TrackletingLayerOrder Order; -class DeviceStoreVertexerHIP final -{ - public: - DeviceStoreVertexerHIP(); - ~DeviceStoreVertexerHIP() = default; - - UniquePointer<DeviceStoreVertexerHIP> initialise(const std::array<std::vector<Cluster>, constants::its::LayersNumberVertexer>&, - const std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::LayersNumberVertexer>&); - - // RO APIs - GPUd() const ArrayHIP<VectorHIP<Cluster>, constants::its::LayersNumberVertexer>& getClusters() - { - return mClusters; - } - GPUd() const VectorHIP<int>& getIndexTable(const VertexerLayerName); - GPUhd() VertexerStoreConfigurationGPU& getConfig() { return mGPUConf; } - - // Writable APIs - GPUd() VectorHIP<Tracklet>& getDuplets01() { return mDuplets01; } - GPUd() VectorHIP<Tracklet>& getDuplets12() { return mDuplets12; } - GPUd() VectorHIP<Line>& getLines() { return mTracklets; } - GPUd() VectorHIP<float>& getBeamPosition() { return mBeamPosition; } - GPUhd() VectorHIP<GPUVertex>& getVertices() { return mGPUVertices; } - GPUhd() VectorHIP<int>& getNFoundLines() { return mNFoundLines; } - GPUhd() VectorHIP<int>& getNExclusiveFoundLines() { return mNExclusiveFoundLines; } - GPUhd() VectorHIP<int>& getCUBTmpBuffer() { return mCUBTmpBuffer; } - GPUhd() VectorHIP<float>& getXYCentroids() { return mXYCentroids; } - GPUhd() VectorHIP<float>& getZCentroids() { return mZCentroids; } - GPUhd() ArrayHIP<VectorHIP<int>, 3>& getHistogramXYZ() { return mHistogramXYZ; } - GPUhd() VectorHIP<hipcub::KeyValuePair<int, int>>& getTmpVertexPositionBins() { return mTmpVertexPositionBins; } - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - GPUd() ArrayHIP<VectorHIP<int>, 2>& getDupletIndices() - { - return mDupletIndices; - } -#endif - GPUhd() VectorHIP<int>& getNFoundTracklets(Order order) - { - return mNFoundDuplets[static_cast<int>(order)]; - } - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - /*GPUh()*/ void updateDuplets(const Order, std::vector<Tracklet>&); - /*GPUh()*/ void updateFoundDuplets(const Order, std::vector<int>&); - /*GPUh()*/ std::vector<int> getNFoundTrackletsFromGPU(const Order); - /*GPUh()*/ std::vector<Tracklet> getRawDupletsFromGPU(const Order); - /*GPUh()*/ std::vector<Tracklet> getDupletsFromGPU(const Order); - /*GPUh()*/ std::vector<Line> getRawLinesFromGPU(); - /*GPUh()*/ std::vector<std::array<int, 2>> getDupletIndicesFromGPU(); - /*GPUh()*/ std::vector<int> getNFoundLinesFromGPU(); - /*GPUh()*/ std::array<std::vector<int>, 2> getHistogramXYFromGPU(); - /*GPUh()*/ std::vector<int> getHistogramZFromGPU(); - /*GPUh()*/ std::vector<Line> getLinesFromGPU(); -#endif - - private: - VertexerStoreConfigurationGPU mGPUConf; - ArrayHIP<VectorHIP<Cluster>, constants::its::LayersNumberVertexer> mClusters; - VectorHIP<Line> mTracklets; - ArrayHIP<VectorHIP<int>, 2> mIndexTables; - VectorHIP<GPUVertex> mGPUVertices; - - // service buffers - VectorHIP<int> mNFoundLines; - VectorHIP<int> mNExclusiveFoundLines; - VectorHIP<Tracklet> mDuplets01; - VectorHIP<Tracklet> mDuplets12; - ArrayHIP<VectorHIP<int>, constants::its::LayersNumberVertexer - 1> mNFoundDuplets; - VectorHIP<int> mCUBTmpBuffer; - VectorHIP<float> mXYCentroids; - VectorHIP<float> mZCentroids; - VectorHIP<float> mBeamPosition; - ArrayHIP<VectorHIP<int>, 3> mHistogramXYZ; - VectorHIP<hipcub::KeyValuePair<int, int>> mTmpVertexPositionBins; - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - ArrayHIP<VectorHIP<int>, 2> mDupletIndices; - VectorHIP<int> mSizes; -#endif -}; - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -inline std::vector<int> DeviceStoreVertexerHIP::getNFoundTrackletsFromGPU(const Order order) -{ - // Careful: this might lead to large allocations, use debug-purpose only - std::vector<int> sizes; - sizes.resize(constants::its::LayersNumberVertexer); - mSizes.copyIntoSizedVector(sizes); - std::vector<int> nFoundDuplets; - nFoundDuplets.resize(sizes[1]); - - if (order == GPU::Order::fromInnermostToMiddleLayer) { - mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); - } else { - mNFoundDuplets[1].copyIntoSizedVector(nFoundDuplets); - } - - return nFoundDuplets; -} - -inline std::vector<Tracklet> DeviceStoreVertexerHIP::getRawDupletsFromGPU(const Order order) -{ - // Careful: this might lead to large allocations, use debug-purpose only - std::vector<int> sizes; - sizes.resize(constants::its::LayersNumberVertexer); - mSizes.copyIntoSizedVector(sizes); - std::vector<Tracklet> tmpDuplets; - tmpDuplets.resize(static_cast<size_t>(mGPUConf.dupletsCapacity)); - std::vector<int> nFoundDuplets; - nFoundDuplets.resize(sizes[1]); - - if (order == GPU::Order::fromInnermostToMiddleLayer) { - mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); - mDuplets01.copyIntoSizedVector(tmpDuplets); - } else { - mDuplets12.copyIntoSizedVector(tmpDuplets); - mNFoundDuplets[1].copyIntoSizedVector(nFoundDuplets); - } - - return tmpDuplets; -} - -inline std::vector<Tracklet> DeviceStoreVertexerHIP::getDupletsFromGPU(const Order order) -{ - // Careful: this might lead to large allocations, use debug-purpose only - std::vector<int> sizes; - sizes.resize(constants::its::LayersNumberVertexer); - mSizes.copyIntoSizedVector(sizes); - std::vector<Tracklet> tmpDuplets; - tmpDuplets.resize(static_cast<size_t>(mGPUConf.dupletsCapacity)); - std::vector<int> nFoundDuplets; - nFoundDuplets.resize(sizes[1]); - std::vector<Tracklet> shrinkedDuplets; - - if (order == GPU::Order::fromInnermostToMiddleLayer) { - mNFoundDuplets[0].copyIntoSizedVector(nFoundDuplets); - mDuplets01.copyIntoSizedVector(tmpDuplets); - } else { - mDuplets12.copyIntoSizedVector(tmpDuplets); - mNFoundDuplets[1].copyIntoSizedVector(nFoundDuplets); - } - - for (int iCluster{0}; iCluster < sizes[1]; ++iCluster) { - const int stride{iCluster * mGPUConf.maxTrackletsPerCluster}; - for (int iDuplet{0}; iDuplet < nFoundDuplets[iCluster]; ++iDuplet) { - shrinkedDuplets.push_back(tmpDuplets[stride + iDuplet]); - } - } - return shrinkedDuplets; -} - -inline std::vector<std::array<int, 2>> DeviceStoreVertexerHIP::getDupletIndicesFromGPU() -{ - // Careful: this might lead to large allocations, use debug-purpose only. - std::array<std::vector<int>, 2> allowedLines; - std::vector<std::array<int, 2>> allowedPairIndices; - int nLines = getNExclusiveFoundLines().getElementFromDevice(mClusters[1].getSizeFromDevice() - 1) + getNFoundLines().getElementFromDevice(mClusters[1].getSizeFromDevice() - 1); - allowedPairIndices.reserve(nLines); - for (int iAllowed{0}; iAllowed < 2; ++iAllowed) { - allowedLines[iAllowed].resize(nLines); - mDupletIndices[iAllowed].resize(nLines); - mDupletIndices[iAllowed].copyIntoSizedVector(allowedLines[iAllowed]); - } - for (size_t iPair{0}; iPair < allowedLines[0].size(); ++iPair) { - allowedPairIndices.emplace_back(std::array<int, 2>{allowedLines[0][iPair], allowedLines[1][iPair]}); - } - return allowedPairIndices; -} - -inline std::array<std::vector<int>, 2> DeviceStoreVertexerHIP::getHistogramXYFromGPU() -{ - std::array<std::vector<int>, 2> histoXY; - for (int iHisto{0}; iHisto < 2; ++iHisto) { - histoXY[iHisto].resize(mGPUConf.nBinsXYZ[iHisto] - 1); - mHistogramXYZ[iHisto].copyIntoSizedVector(histoXY[iHisto]); - } - - return histoXY; -} - -inline std::vector<int> DeviceStoreVertexerHIP::getHistogramZFromGPU() -{ - std::vector<int> histoZ; - histoZ.resize(mGPUConf.nBinsXYZ[2] - 1); - std::cout << "Size of dest vector to be refined" << std::endl; - mHistogramXYZ[2].copyIntoSizedVector(histoZ); - - return histoZ; -} - -inline void DeviceStoreVertexerHIP::updateDuplets(const Order order, std::vector<Tracklet>& duplets) -{ - if (order == GPU::Order::fromInnermostToMiddleLayer) { - mDuplets01.reset(duplets.data(), static_cast<int>(duplets.size())); - } else { - mDuplets12.reset(duplets.data(), static_cast<int>(duplets.size())); - } -} - -inline void DeviceStoreVertexerHIP::updateFoundDuplets(const Order order, std::vector<int>& nDuplets) -{ - if (order == GPU::Order::fromInnermostToMiddleLayer) { - mNFoundDuplets[0].reset(nDuplets.data(), static_cast<int>(nDuplets.size())); - } else { - mNFoundDuplets[1].reset(nDuplets.data(), static_cast<int>(nDuplets.size())); - } -} - -inline std::vector<Line> DeviceStoreVertexerHIP::getRawLinesFromGPU() -{ - std::vector<Line> lines; - lines.resize(mGPUConf.processedTrackletsCapacity); - mTracklets.copyIntoSizedVector(lines); - - return lines; -} - -inline std::vector<int> DeviceStoreVertexerHIP::getNFoundLinesFromGPU() -{ - std::vector<int> nFoundLines; - nFoundLines.resize(mGPUConf.clustersPerLayerCapacity); - mNFoundLines.copyIntoSizedVector(nFoundLines); - - return nFoundLines; -} - -inline std::vector<Line> DeviceStoreVertexerHIP::getLinesFromGPU() -{ - std::vector<Line> lines; - std::vector<Line> tmpLines; - tmpLines.resize(mGPUConf.processedTrackletsCapacity); - mTracklets.copyIntoSizedVector(tmpLines); - for (auto& line : tmpLines) { - if (line.isEmpty) { - break; - } - lines.push_back(line); - } - return lines; -} -#endif -} // namespace GPU -} // namespace its -} // namespace o2 -#endif //O2_ITS_TRACKING_INCLUDE_DEVICESTOREVERTEXER_HIP_H_ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/StreamHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/StreamHIP.h deleted file mode 100644 index d0006fd40ace9..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/StreamHIP.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file StreamHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_STREAM_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_STREAM_HIP_H_ - -#include <hip/hip_runtime_api.h> - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -class StreamHIP final -{ - - public: - StreamHIP(); - ~StreamHIP(); - - StreamHIP(const StreamHIP&) = delete; - StreamHIP& operator=(const StreamHIP&) = delete; - - const hipStream_t& get() const; - - private: - hipStream_t mStream; -}; -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_STREAM_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UniquePointerHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UniquePointerHIP.h deleted file mode 100644 index 444fb9e199390..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UniquePointerHIP.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file UniquePointerHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_UNIQUEPOINTER_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_UNIQUEPOINTER_HIP_H_ - -#include "GPUCommonDef.h" -#include "ITStrackingHIP/UtilsHIP.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace -{ -template <typename T> -struct UniquePointerTraits final { - typedef T* InternalPointer; - - GPUhd() static constexpr T& getReference(const InternalPointer& internalPointer) noexcept - { - return const_cast<T&>(*internalPointer); - } - - GPUhd() static constexpr T* getPointer(const InternalPointer& internalPointer) noexcept - { - return const_cast<T*>(internalPointer); - } -}; -} // namespace - -template <typename T> -class UniquePointer final -{ - typedef UniquePointerTraits<T> PointerTraits; - - public: - UniquePointer(); - explicit UniquePointer(const T&); - ~UniquePointer(); - - UniquePointer(const UniquePointer&) = delete; - UniquePointer& operator=(const UniquePointer&) = delete; - - UniquePointer(UniquePointer&&); - UniquePointer& operator=(UniquePointer&&); - - GPUhd() T* get() noexcept; - GPUhd() const T* get() const noexcept; - GPUhd() T& operator*() noexcept; - GPUhd() const T& operator*() const noexcept; - - protected: - void destroy(); - - private: - typename PointerTraits::InternalPointer mDevicePointer; -}; - -template <typename T> -UniquePointer<T>::UniquePointer() : mDevicePointer{nullptr} -{ - // Nothing to do -} - -template <typename T> -UniquePointer<T>::UniquePointer(const T& ref) -{ - try { - - Utils::HostHIP::gpuMalloc(reinterpret_cast<void**>(&mDevicePointer), sizeof(T)); - Utils::HostHIP::gpuMemcpyHostToDevice(mDevicePointer, &ref, sizeof(T)); - - } catch (...) { - - destroy(); - - throw; - } -} - -template <typename T> -UniquePointer<T>::~UniquePointer() -{ - destroy(); -} - -template <typename T> -UniquePointer<T>::UniquePointer(UniquePointer<T>&& other) : mDevicePointer{other.mDevicePointer} -{ - // Nothing to do -} - -template <typename T> -UniquePointer<T>& UniquePointer<T>::operator=(UniquePointer<T>&& other) -{ - mDevicePointer = other.mDevicePointer; - other.mDevicePointer = nullptr; - - return *this; -} - -template <typename T> -void UniquePointer<T>::destroy() -{ - if (mDevicePointer != nullptr) { - - Utils::HostHIP::gpuFree(mDevicePointer); - } -} - -template <typename T> -GPUhd() T* UniquePointer<T>::get() noexcept -{ - return PointerTraits::getPointer(mDevicePointer); -} - -template <typename T> -GPUhd() const T* UniquePointer<T>::get() const noexcept -{ - return PointerTraits::getPointer(mDevicePointer); -} - -template <typename T> -GPUhd() T& UniquePointer<T>::operator*() noexcept -{ - return PointerTraits::getReference(mDevicePointer); -} - -template <typename T> -GPUhd() const T& UniquePointer<T>::operator*() const noexcept -{ - return PointerTraits::getReference(mDevicePointer); -} -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_UNIQUEPOINTER_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UtilsHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UtilsHIP.h deleted file mode 100644 index f536f12529f2f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UtilsHIP.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file UtilsHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_UTILS_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_UTILS_HIP_H_ - -#include "GPUCommonDef.h" -#include "ITStrackingHIP/StreamHIP.h" -#include <hip/hip_runtime_api.h> - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -namespace Utils -{ - -namespace HostHIP -{ - -#ifdef __HIPCC__ -void checkHIPError(const hipError_t error, const char* file, const int line); -#endif - -dim3 getBlockSize(const int); -dim3 getBlockSize(const int, const int); -dim3 getBlockSize(const int, const int, const int); -dim3 getBlocksGrid(const dim3&, const int); -dim3 getBlocksGrid(const dim3&, const int, const int); -// -void gpuMalloc(void**, const int); -void gpuFree(void*); -void gpuMemset(void*, int, int); -void gpuMemcpyHostToDevice(void*, const void*, int); -void gpuMemcpyHostToDeviceAsync(void*, const void*, int, hipStream_t&); -void gpuMemcpyDeviceToHost(void*, const void*, int); -// void gpuStartProfiler(); -// void gpuStopProfiler(); -} // namespace Host -// -namespace DeviceHIP -{ -GPUd() int getLaneIndex(); -GPUd() int shareToWarp(const int, const int); -GPUd() int gpuAtomicAdd(int*, const int); -} // namespace Device -} // namespace Utils -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_UTILS_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VectorHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VectorHIP.h deleted file mode 100644 index 42c69111a9f5f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VectorHIP.h +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VectorHIP.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_INCLUDE_VECTOR_HIP_H_ -#define O2_ITS_TRACKING_INCLUDE_VECTOR_HIP_H_ - -#include <cassert> -#include <new> -#include <type_traits> -#include <vector> - -#include "ITStrackingHIP/StreamHIP.h" -#include "ITStrackingHIP/UtilsHIP.h" -#include "GPUCommonDef.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -template <typename T> -class VectorHIP final -{ - static_assert(std::is_trivially_destructible<T>::value, "VectorHIP only supports trivially destructible objects."); - - public: - VectorHIP(); - explicit VectorHIP(const int, const int = 0); - VectorHIP(const T* const, const int, const int = 0); - GPUhd() ~VectorHIP(); - - VectorHIP(const VectorHIP&) = delete; - VectorHIP& operator=(const VectorHIP&) = delete; - - GPUhd() VectorHIP(VectorHIP&&); - VectorHIP& operator=(VectorHIP&&); - - int getSizeFromDevice() const; - - T getElementFromDevice(const int) const; - - void resize(const int); - void reset(const int, const int = 0); - void reset(const T* const, const int, const int = 0); - void copyIntoVector(std::vector<T>&, const int); - void copyIntoSizedVector(std::vector<T>&); - - GPUhd() T* get() const; - GPUhd() int capacity() const; - GPUhd() VectorHIP<T> getWeakCopy() const; - GPUhd() T& operator[](const int) const; - - GPUhd() int size() const; - GPUd() int extend(const int) const; - GPUhd() void dump(); - - template <typename... Args> - GPUd() void emplace(const int, Args&&...); - - protected: - void destroy(); - - private: - GPUhd() VectorHIP(const VectorHIP&, const bool); - - T* mArrayPointer = nullptr; - int* mDeviceSize = nullptr; - int mCapacity; - bool mIsWeak; -}; - -template <typename T> -VectorHIP<T>::VectorHIP() : VectorHIP{nullptr, 0} -{ - // Nothing to do -} - -template <typename T> -VectorHIP<T>::VectorHIP(const int capacity, const int initialSize) : VectorHIP{nullptr, capacity, initialSize} -{ - // Nothing to do -} - -template <typename T> -VectorHIP<T>::VectorHIP(const T* const source, const int size, const int initialSize) : mCapacity{size}, mIsWeak{false} -{ - if (size > 0) { - try { - - Utils::HostHIP::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); - Utils::HostHIP::gpuMalloc(reinterpret_cast<void**>(&mDeviceSize), sizeof(int)); - - if (source != nullptr) { - - Utils::HostHIP::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); - Utils::HostHIP::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); - - } else { - - Utils::HostHIP::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); - } - - } catch (...) { - - destroy(); - - throw; - } - } -} - -template <typename T> -GPUhdi() VectorHIP<T>::VectorHIP(const VectorHIP& other, const bool isWeak) - : mArrayPointer{other.mArrayPointer}, - mDeviceSize{other.mDeviceSize}, - mCapacity{other.mCapacity}, - mIsWeak{isWeak} -{ - // Nothing to do -} - -template <typename T> -GPUhd() VectorHIP<T>::~VectorHIP() -{ - if (mIsWeak) { - - return; - - } else { -#if defined(TRACKINGITSU_GPU_DEVICE) - assert(0); -#else - destroy(); -#endif - } -} - -template <typename T> -GPUhd() VectorHIP<T>::VectorHIP(VectorHIP<T>&& other) - : mArrayPointer{other.mArrayPointer}, - mDeviceSize{other.mDeviceSize}, - mCapacity{other.mCapacity}, - mIsWeak{other.mIsWeak} -{ - other.mArrayPointer = nullptr; - other.mDeviceSize = nullptr; -} - -template <typename T> -VectorHIP<T>& VectorHIP<T>::operator=(VectorHIP<T>&& other) -{ - destroy(); - - mArrayPointer = other.mArrayPointer; - mDeviceSize = other.mDeviceSize; - mCapacity = other.mCapacity; - mIsWeak = other.mIsWeak; - - other.mArrayPointer = nullptr; - other.mDeviceSize = nullptr; - - return *this; -} - -template <typename T> -int VectorHIP<T>::getSizeFromDevice() const -{ - int size; - Utils::HostHIP::gpuMemcpyDeviceToHost(&size, mDeviceSize, sizeof(int)); - - return size; -} - -template <typename T> -void VectorHIP<T>::resize(const int size) -{ - Utils::HostHIP::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); -} - -template <typename T> -void VectorHIP<T>::reset(const int capacity, const int initialSize) -{ - reset(nullptr, capacity, initialSize); -} - -template <typename T> -void VectorHIP<T>::reset(const T* const source, const int size, const int initialSize) -{ - if (size > mCapacity) { - if (mArrayPointer != nullptr) { - Utils::HostHIP::gpuFree(mArrayPointer); - } - - Utils::HostHIP::gpuMalloc(reinterpret_cast<void**>(&mArrayPointer), size * sizeof(T)); - mCapacity = size; - } - - if (source != nullptr) { - - Utils::HostHIP::gpuMemcpyHostToDevice(mArrayPointer, source, size * sizeof(T)); - Utils::HostHIP::gpuMemcpyHostToDevice(mDeviceSize, &size, sizeof(int)); - - } else { - Utils::HostHIP::gpuMemcpyHostToDevice(mDeviceSize, &initialSize, sizeof(int)); - } -} - -template <typename T> -void VectorHIP<T>::copyIntoVector(std::vector<T>& destinationVector, const int size) -{ - - T* hostPrimitivePointer = nullptr; - - try { - - hostPrimitivePointer = static_cast<T*>(malloc(size * sizeof(T))); - Utils::HostHIP::gpuMemcpyDeviceToHost(hostPrimitivePointer, mArrayPointer, size * sizeof(T)); - - destinationVector = std::move(std::vector<T>(hostPrimitivePointer, hostPrimitivePointer + size)); - - } catch (...) { - - if (hostPrimitivePointer != nullptr) { - - free(hostPrimitivePointer); - } - - throw; - } -} - -template <typename T> -void VectorHIP<T>::copyIntoSizedVector(std::vector<T>& destinationVector) -{ - Utils::HostHIP::gpuMemcpyDeviceToHost(destinationVector.data(), mArrayPointer, destinationVector.size() * sizeof(T)); -} - -template <typename T> -inline void VectorHIP<T>::destroy() -{ - if (mArrayPointer != nullptr) { - - Utils::HostHIP::gpuFree(mArrayPointer); - } - - if (mDeviceSize != nullptr) { - - Utils::HostHIP::gpuFree(mDeviceSize); - } -} - -template <typename T> -GPUhd() T* VectorHIP<T>::get() const -{ - return mArrayPointer; -} - -template <typename T> -GPUhd() int VectorHIP<T>::capacity() const -{ - return mCapacity; -} - -template <typename T> -GPUhd() VectorHIP<T> VectorHIP<T>::getWeakCopy() const -{ - return VectorHIP{*this, true}; -} - -template <typename T> -GPUhd() T& VectorHIP<T>::operator[](const int index) const -{ - return mArrayPointer[index]; -} - -template <typename T> -T VectorHIP<T>::getElementFromDevice(const int index) const -{ - T element; - Utils::HostHIP::gpuMemcpyDeviceToHost(&element, mArrayPointer + index, sizeof(T)); - - return element; -} - -template <typename T> -GPUhd() int VectorHIP<T>::size() const -{ - return *mDeviceSize; -} - -template <typename T> -GPUd() int VectorHIP<T>::extend(const int sizeIncrement) const -{ - const int startIndex = Utils::DeviceHIP::gpuAtomicAdd(mDeviceSize, sizeIncrement); - assert(size() <= mCapacity); - - return startIndex; -} - -template <typename T> -template <typename... Args> -GPUd() void VectorHIP<T>::emplace(const int index, Args&&... arguments) -{ - new (mArrayPointer + index) T(std::forward<Args>(arguments)...); -} - -template <typename T> -GPUhd() void VectorHIP<T>::dump() -{ - printf("mArrayPointer = %p\nmDeviceSize = %p\nmCapacity = %d\nmIsWeak = %s\n", - mArrayPointer, mDeviceSize, mCapacity, mIsWeak ? "true" : "false"); -} -} // namespace GPU -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_TRACKING_INCLUDE_VECTOR_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VertexerTraitsHIP.h b/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VertexerTraitsHIP.h deleted file mode 100644 index 355b1243c127f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VertexerTraitsHIP.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsHIP.h -/// \brief -/// \author matteo.concas@cern.ch - -#ifndef O2_ITS_TRACKING_VERTEXERTRAITS_HIP_H_ -#define O2_ITS_TRACKING_VERTEXERTRAITS_HIP_H_ - -#include <vector> -#include <array> - -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -// #include "ITStracking/Definitions.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingHIP/DeviceStoreVertexerHIP.h" -#include "ITStrackingHIP/UniquePointerHIP.h" - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -#include "ITStracking/StandaloneDebugger.h" -#endif - -namespace o2 -{ -namespace its -{ -class ROframe; - -using constants::index_table::InversePhiBinSize; - -class VertexerTraitsHIP : public VertexerTraits -{ - public: -#ifdef _ALLOW_DEBUG_TREES_ITS_ - VertexerTraitsHIP(); - ~VertexerTraitsHIP(); -#else - VertexerTraitsHIP(); - ~VertexerTraitsHIP() = default; -#endif - void initialise(ROframe*) override; - void computeTracklets() override; - void computeTrackletMatching() override; - void computeVertices() override; -#ifdef _ALLOW_DEBUG_TREES_ITS_ - void computeMCFiltering() override; -#endif - - // GPU-specific getters - GPUd() static const int2 getBinsPhiRectWindow(const Cluster&, float maxdeltaphi); - GPUhd() GPU::DeviceStoreVertexerHIP& getDeviceContext(); - GPUhd() GPU::DeviceStoreVertexerHIP* getDeviceContextPtr(); - - protected: - // #ifdef _ALLOW_DEBUG_TREES_ITS_ - // StandaloneDebugger* mDebugger; - // #endif - GPU::DeviceStoreVertexerHIP mStoreVertexerGPU; - GPU::UniquePointer<GPU::DeviceStoreVertexerHIP> mStoreVertexerGPUPtr; -}; - -GPUdi() const int2 VertexerTraitsHIP::getBinsPhiRectWindow(const Cluster& currentCluster, float phiCut) -{ - // This function returns the lowest PhiBin and the number of phi bins to be spanned, In the form int2{phiBinLow, PhiBinSpan} - const int phiBinMin{index_table_utils::getPhiBinIndex( - math_utils::getNormalizedPhiCoordinate(currentCluster.phiCoordinate - phiCut))}; - const int phiBinSpan{static_cast<int>(MATH_CEIL(phiCut * InversePhiBinSize))}; - return int2{phiBinMin, phiBinSpan}; -} - -GPUhdi() GPU::DeviceStoreVertexerHIP& VertexerTraitsHIP::getDeviceContext() -{ - return *mStoreVertexerGPUPtr; -} - -GPUhdi() GPU::DeviceStoreVertexerHIP* VertexerTraitsHIP::getDeviceContextPtr() -{ - return mStoreVertexerGPUPtr.get(); -} - -extern "C" VertexerTraits* createVertexerTraitsHIP(); - -} // namespace its -} // namespace o2 -#endif /* O2_ITS_TRACKING_VERTEXERTRAITS_HIP_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/ClusterLinesHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/ClusterLinesHIP.hip.cxx deleted file mode 100644 index 79c13119e5e21..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/ClusterLinesHIP.hip.cxx +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ClusterLinesHIP.hip.cxx -/// \brief -/// \author matteo.concas@cern.ch - -#include "ITStrackingHIP/ClusterLinesHIP.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -GPUd() ClusterLinesHIP::ClusterLinesHIP(const Line& firstLine, const Line& secondLine) -{ - float covarianceFirst[3]; - float covarianceSecond[3]; - - for (int i{0}; i < 3; ++i) { - covarianceFirst[i] = 1.f; - covarianceSecond[i] = 1.f; - } - - float determinantFirst = - firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] * covarianceFirst[2] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1] * covarianceFirst[2]; - float determinantSecond = - secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] * covarianceSecond[2] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1] * covarianceSecond[2]; - - mAMatrix[0] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[1] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[1] * covarianceFirst[2] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[1] * covarianceSecond[2] / determinantSecond; - - mAMatrix[2] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[2] * covarianceFirst[1] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[2] * covarianceSecond[1] / determinantSecond; - - mAMatrix[3] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[4] = -firstLine.cosinesDirector[1] * firstLine.cosinesDirector[2] * covarianceFirst[0] / determinantFirst - - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[2] * covarianceSecond[0] / determinantSecond; - - mAMatrix[5] = (firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1]) / - determinantFirst + - (secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1]) / - determinantSecond; - - mBMatrix[0] = - (firstLine.cosinesDirector[1] * covarianceFirst[2] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[1]) + - firstLine.cosinesDirector[2] * covarianceFirst[1] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[0] += - (secondLine.cosinesDirector[1] * covarianceSecond[2] * (-secondLine.cosinesDirector[1] * secondLine.originPoint[0] + secondLine.cosinesDirector[0] * secondLine.originPoint[1]) + - secondLine.cosinesDirector[2] * covarianceSecond[1] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[0] + - secondLine.cosinesDirector[0] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[1] = - (firstLine.cosinesDirector[0] * covarianceFirst[2] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[2] * covarianceFirst[0] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[1] += - (secondLine.cosinesDirector[0] * covarianceSecond[2] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[1] + secondLine.cosinesDirector[1] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[2] * covarianceSecond[0] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[1] + - secondLine.cosinesDirector[1] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[2] = - (firstLine.cosinesDirector[0] * covarianceFirst[1] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[1] * covarianceFirst[0] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[1])) / - determinantFirst; - - mBMatrix[2] += - (secondLine.cosinesDirector[0] * covarianceSecond[1] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[2] + secondLine.cosinesDirector[2] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[1] * covarianceSecond[0] * - (-secondLine.cosinesDirector[1] * secondLine.originPoint[2] + - secondLine.cosinesDirector[2] * secondLine.originPoint[1])) / - determinantSecond; - - computeClusterCentroid(); -} - -GPUd() void ClusterLinesHIP::computeClusterCentroid() -{ - - float determinant{mAMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])}; - - if (determinant == 0) { - return; - } - - mVertex[0] = -(mBMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mBMatrix[1] * mAMatrix[5] - mAMatrix[4] * mBMatrix[2]) + - mAMatrix[2] * (mBMatrix[1] * mAMatrix[4] - mBMatrix[2] * mAMatrix[3])) / - determinant; - mVertex[1] = -(mAMatrix[0] * (mBMatrix[1] * mAMatrix[5] - mBMatrix[2] * mAMatrix[4]) - - mBMatrix[0] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mBMatrix[2] - mAMatrix[2] * mBMatrix[1])) / - determinant; - mVertex[2] = -(mAMatrix[0] * (mAMatrix[3] * mBMatrix[2] - mBMatrix[1] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mBMatrix[2] - mBMatrix[1] * mAMatrix[2]) + - mBMatrix[0] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])) / - determinant; -} -} // namespace GPU -} // namespace its -} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/ContextHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/ContextHIP.hip.cxx deleted file mode 100644 index 0c6744b58b5d5..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/ContextHIP.hip.cxx +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ContextHIP.hip.cxx -/// \brief -/// - -#include "ITStrackingHIP/ContextHIP.h" -#include "ITStrackingHIP/UtilsHIP.h" - -#include <sstream> -#include <stdexcept> - -#include <iostream> - -namespace -{ - -inline int getStreamProcessors(const int major, const int minor) -{ - // Hardcoded result for AMD RADEON WX 9100, to be decided if and how determine this paramter - return 4096; -} - -inline int getMaxThreadsPerComputingUnit(const int major, const int minor) -{ - return 8; -} - -} // namespace - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -using Utils::HostHIP::checkHIPError; - -ContextHIP::ContextHIP(bool dumpDevices) -{ - checkHIPError(hipGetDeviceCount(&mDevicesNum), __FILE__, __LINE__); - if (mDevicesNum == 0) { - throw std::runtime_error{"There are no available device(s) that support HIP\n"}; - } - - mDeviceProperties.resize(mDevicesNum, DeviceProperties{}); - - int currentDeviceIndex; - checkHIPError(hipGetDevice(¤tDeviceIndex), __FILE__, __LINE__); - - for (int iDevice{0}; iDevice < mDevicesNum; ++iDevice) { - - hipDeviceProp_t deviceProperties; - - checkHIPError(hipSetDevice(iDevice), __FILE__, __LINE__); - checkHIPError(hipGetDeviceProperties(&deviceProperties, iDevice), __FILE__, __LINE__); - - int major = deviceProperties.major; // Codacy warning - int minor = deviceProperties.minor; // Codacy warning - - mDeviceProperties[iDevice].name = deviceProperties.name; - mDeviceProperties[iDevice].gpuProcessors = deviceProperties.multiProcessorCount; - mDeviceProperties[iDevice].streamProcessors = getStreamProcessors(major, minor) * deviceProperties.multiProcessorCount; // >>>> alarm - mDeviceProperties[iDevice].globalMemorySize = deviceProperties.totalGlobalMem; - mDeviceProperties[iDevice].constantMemorySize = deviceProperties.totalConstMem; - mDeviceProperties[iDevice].sharedMemorySize = deviceProperties.sharedMemPerBlock; - mDeviceProperties[iDevice].maxClockRate = deviceProperties.memoryClockRate; - mDeviceProperties[iDevice].busWidth = deviceProperties.memoryBusWidth; - mDeviceProperties[iDevice].l2CacheSize = deviceProperties.l2CacheSize; - mDeviceProperties[iDevice].registersPerBlock = deviceProperties.regsPerBlock; - mDeviceProperties[iDevice].warpSize = deviceProperties.warpSize; - mDeviceProperties[iDevice].maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock; - mDeviceProperties[iDevice].maxBlocksPerSM = getMaxThreadsPerComputingUnit(major, minor); - mDeviceProperties[iDevice].maxThreadsDim = dim3{static_cast<unsigned int>(deviceProperties.maxThreadsDim[0]), - static_cast<unsigned int>(deviceProperties.maxThreadsDim[1]), - static_cast<unsigned int>(deviceProperties.maxThreadsDim[2])}; - mDeviceProperties[iDevice].maxGridDim = dim3{static_cast<unsigned int>(deviceProperties.maxGridSize[0]), - static_cast<unsigned int>(deviceProperties.maxGridSize[1]), - static_cast<unsigned int>(deviceProperties.maxGridSize[2])}; - if (dumpDevices) { - std::cout << "################ HIP DEVICE " << iDevice << " ################" << std::endl; - std::cout << "Name " << mDeviceProperties[iDevice].name << std::endl; - std::cout << "gpuProcessors " << mDeviceProperties[iDevice].gpuProcessors << std::endl; - std::cout << "minor " << minor << " major " << major << std::endl; - std::cout << "globalMemorySize " << mDeviceProperties[iDevice].globalMemorySize << std::endl; - std::cout << "constantMemorySize " << mDeviceProperties[iDevice].constantMemorySize << std::endl; - std::cout << "sharedMemorySize " << mDeviceProperties[iDevice].sharedMemorySize << std::endl; - std::cout << "maxClockRate " << mDeviceProperties[iDevice].maxClockRate << std::endl; - std::cout << "busWidth " << mDeviceProperties[iDevice].busWidth << std::endl; - std::cout << "l2CacheSize " << mDeviceProperties[iDevice].l2CacheSize << std::endl; - std::cout << "registersPerBlock " << mDeviceProperties[iDevice].registersPerBlock << std::endl; - std::cout << "warpSize " << mDeviceProperties[iDevice].warpSize << std::endl; - std::cout << "maxThreadsPerBlock " << mDeviceProperties[iDevice].maxThreadsPerBlock << std::endl; - std::cout << "maxBlocksPerSM " << mDeviceProperties[iDevice].maxBlocksPerSM << std::endl; - std::cout << "maxThreadsDim " << mDeviceProperties[iDevice].maxThreadsDim.x << ", " << mDeviceProperties[iDevice].maxThreadsDim.y << ", " << mDeviceProperties[iDevice].maxThreadsDim.z << std::endl; - std::cout << "maxGridDim " << mDeviceProperties[iDevice].maxGridDim.x << ", " << mDeviceProperties[iDevice].maxGridDim.y << ", " << mDeviceProperties[iDevice].maxGridDim.z << std::endl; - std::cout << std::endl; - } - } - - checkHIPError(hipSetDevice(currentDeviceIndex), __FILE__, __LINE__); -} - -ContextHIP& ContextHIP::getInstance() -{ - static ContextHIP gpuContextHIP; - return gpuContextHIP; -} - -const DeviceProperties& ContextHIP::getDeviceProperties() -{ - int currentDeviceIndex; - checkHIPError(hipGetDevice(¤tDeviceIndex), __FILE__, __LINE__); - - return getDeviceProperties(currentDeviceIndex); -} - -const DeviceProperties& ContextHIP::getDeviceProperties(const int deviceIndex) -{ - return mDeviceProperties[deviceIndex]; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/DeviceStoreVertexerHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/DeviceStoreVertexerHIP.hip.cxx deleted file mode 100644 index 39a05cfecb033..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/DeviceStoreVertexerHIP.hip.cxx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DeviceStoreVertexerHIP.hip.cxx -/// \brief -/// \author matteo.concas@cern.ch - -#include <iostream> - -#include "ITStrackingHIP/DeviceStoreVertexerHIP.h" -#include "ITStracking/Configuration.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ -GPUg() void defaultInitArrayKernel(int* array, const size_t arraySize, const int initValue = 0) -{ - for (size_t i{blockIdx.x * blockDim.x + threadIdx.x}; i < arraySize; i += blockDim.x * gridDim.x) { - if (i < arraySize) { - array[i] = initValue; - } - } -} - -DeviceStoreVertexerHIP::DeviceStoreVertexerHIP() -{ - mDuplets01 = VectorHIP<Tracklet>{mGPUConf.dupletsCapacity, mGPUConf.dupletsCapacity}; // 200 * 4e4 * sizeof(Tracklet) = 128MB - mDuplets12 = VectorHIP<Tracklet>{mGPUConf.dupletsCapacity, mGPUConf.dupletsCapacity}; // 200 * 4e4 * sizeof(Tracklet) = 128MB - mTracklets = VectorHIP<Line>{mGPUConf.processedTrackletsCapacity, mGPUConf.processedTrackletsCapacity}; // 200 * 4e4 * sizeof(Line) = 296MB - mCUBTmpBuffer = VectorHIP<int>{mGPUConf.tmpCUBBufferSize, mGPUConf.tmpCUBBufferSize}; // 5e3 * sizeof(int) = 20KB - mXYCentroids = VectorHIP<float>{2 * mGPUConf.maxCentroidsXYCapacity, 2 * mGPUConf.maxCentroidsXYCapacity}; // - mZCentroids = VectorHIP<float>{mGPUConf.processedTrackletsCapacity, mGPUConf.processedTrackletsCapacity}; // - mNFoundLines = VectorHIP<int>{mGPUConf.clustersPerLayerCapacity, mGPUConf.clustersPerLayerCapacity}; // 4e4 * sizeof(int) = 160KB - mNExclusiveFoundLines = VectorHIP<int>{mGPUConf.clustersPerLayerCapacity, mGPUConf.clustersPerLayerCapacity}; // 4e4 * sizeof(int) = 160KB, tot = <10MB - mTmpVertexPositionBins = VectorHIP<hipcub::KeyValuePair<int, int>>{3, 3}; - mGPUVertices = VectorHIP<GPUVertex>{mGPUConf.nMaxVertices, mGPUConf.nMaxVertices}; - mBeamPosition = VectorHIP<float>{2, 2}; - - for (int iTable{0}; iTable < 2; ++iTable) { - mIndexTables[iTable] = VectorHIP<int>{constants::index_table::ZBins * constants::index_table::PhiBins + 1}; // 2*20*20+1 * sizeof(int) = 802B - } - for (int iLayer{0}; iLayer < constants::its::LayersNumberVertexer; ++iLayer) { // 4e4 * 3 * sizof(Cluster) = 3.36MB - mClusters[iLayer] = VectorHIP<Cluster>{mGPUConf.clustersPerLayerCapacity, mGPUConf.clustersPerLayerCapacity}; - } - for (int iPair{0}; iPair < constants::its::LayersNumberVertexer - 1; ++iPair) { - mNFoundDuplets[iPair] = VectorHIP<int>{mGPUConf.clustersPerLayerCapacity, mGPUConf.clustersPerLayerCapacity}; // 4e4 * 2 * sizeof(int) = 320KB - } - for (int iHisto{0}; iHisto < 3; ++iHisto) { - mHistogramXYZ[iHisto] = VectorHIP<int>{mGPUConf.histConf.nBinsXYZ[iHisto], mGPUConf.histConf.nBinsXYZ[iHisto]}; - } - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - for (int iLayersCouple{0}; iLayersCouple < 2; ++iLayersCouple) { - mDupletIndices[iLayersCouple] = VectorHIP<int>{mGPUConf.processedTrackletsCapacity, mGPUConf.processedTrackletsCapacity}; - } - mSizes = VectorHIP<int>{constants::its::LayersNumberVertexer}; -#endif -} // namespace GPU - -UniquePointer<DeviceStoreVertexerHIP> DeviceStoreVertexerHIP::initialise(const std::array<std::vector<Cluster>, constants::its::LayersNumberVertexer>& clusters, - const std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::LayersNumberVertexer>& indexTables) -{ -#ifdef _ALLOW_DEBUG_TREES_ITS_ - std::array<int, constants::its::LayersNumberVertexer> tmpSizes = {static_cast<int>(clusters[0].size()), - static_cast<int>(clusters[1].size()), - static_cast<int>(clusters[2].size())}; - - mSizes.reset(tmpSizes.data(), static_cast<int>(3)); -#endif - for (int iLayer{0}; iLayer < constants::its::LayersNumberVertexer; ++iLayer) { - mClusters[iLayer].reset(clusters[iLayer].data(), static_cast<int>(clusters[iLayer].size())); - } - mIndexTables[0].reset(indexTables[0].data(), static_cast<int>(indexTables[0].size())); - mIndexTables[1].reset(indexTables[2].data(), static_cast<int>(indexTables[2].size())); - - const dim3 threadsPerBlock{Utils::HostHIP::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{Utils::HostHIP::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - - UniquePointer<DeviceStoreVertexerHIP> deviceStoreVertexerPtr{*this}; - - hipLaunchKernelGGL((defaultInitArrayKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, getNFoundTracklets(TrackletingLayerOrder::fromInnermostToMiddleLayer).get(), - getNFoundTracklets(TrackletingLayerOrder::fromInnermostToMiddleLayer).capacity(), 0); - hipLaunchKernelGGL((defaultInitArrayKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, getNFoundTracklets(TrackletingLayerOrder::fromMiddleToOuterLayer).get(), - getNFoundTracklets(TrackletingLayerOrder::fromMiddleToOuterLayer).capacity(), 0); - - return deviceStoreVertexerPtr; -} - -GPUd() const VectorHIP<int>& DeviceStoreVertexerHIP::getIndexTable(const VertexerLayerName layer) -{ - if (layer == VertexerLayerName::innermostLayer) { - return mIndexTables[0]; - } - return mIndexTables[1]; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/StreamHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/StreamHIP.hip.cxx deleted file mode 100644 index 50e24c6eb041f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/StreamHIP.hip.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file StreamHIP.hip.cxx -/// \brief -/// - -#include "ITStrackingHIP/StreamHIP.h" - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -StreamHIP::StreamHIP() -{ - (void)hipStreamCreateWithFlags(&mStream, hipStreamNonBlocking); -} - -StreamHIP::~StreamHIP() // NOLINT: clang-tidy doesn't understand hip macro magic, and thinks this is trivial -{ - (void)hipStreamDestroy(mStream); -} - -const hipStream_t& StreamHIP::get() const -{ - return mStream; -} - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/UtilsHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/UtilsHIP.hip.cxx deleted file mode 100644 index bd58b7c9c3e0f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/UtilsHIP.hip.cxx +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file UtilsHIP.hip.cxx -/// \brief -/// - -#include <iostream> -#include <algorithm> -#include <sstream> -#include <stdexcept> - -#include <hip/hip_runtime_api.h> -#include "ITStrackingHIP/ContextHIP.h" -#include "ITStrackingHIP/UtilsHIP.h" - -namespace -{ - -int roundUp(const int numToRound, const int multiple) -{ - if (multiple == 0) { - return numToRound; - } - int remainder{numToRound % multiple}; - if (remainder == 0) { - return numToRound; - } - return numToRound + multiple - remainder; -} - -int findNearestDivisor(const int numToRound, const int divisor) -{ - if (numToRound > divisor) { - return divisor; - } - int result = numToRound; - while (divisor % result != 0) { - ++result; - } - - return result; -} - -} // namespace - -namespace o2 -{ -namespace its -{ -namespace GPU -{ - -void Utils::HostHIP::checkHIPError(const hipError_t error, const char* file, const int line) -{ - if (error != hipSuccess) { - std::ostringstream errorString{}; - errorString << file << ":" << line << " HIP API returned error [" << hipGetErrorString(error) << "] (code " - << error << ")" << std::endl; - throw std::runtime_error{errorString.str()}; - } -} - -dim3 Utils::HostHIP::getBlockSize(const int colsNum) -{ - return getBlockSize(colsNum, 1); -} - -dim3 Utils::HostHIP::getBlockSize(const int colsNum, const int rowsNum) -{ - const DeviceProperties& deviceProperties = ContextHIP::getInstance().getDeviceProperties(); - return getBlockSize(colsNum, rowsNum, deviceProperties.streamProcessors / deviceProperties.maxBlocksPerSM); -} - -dim3 Utils::HostHIP::getBlockSize(const int colsNum, const int rowsNum, const int maxThreadsPerBlock) -{ - const DeviceProperties& deviceProperties = ContextHIP::getInstance().getDeviceProperties(); - int xThreads = std::max(std::min(colsNum, static_cast<int>(deviceProperties.maxThreadsDim.x)), 1); - int yThreads = std::max(std::min(rowsNum, static_cast<int>(deviceProperties.maxThreadsDim.y)), 1); - const int totalThreads = roundUp(std::min(xThreads * yThreads, maxThreadsPerBlock), - static_cast<int>(deviceProperties.warpSize)); - if (xThreads > yThreads) { - xThreads = findNearestDivisor(xThreads, totalThreads); - yThreads = totalThreads / xThreads; - - } else { - yThreads = findNearestDivisor(yThreads, totalThreads); - xThreads = totalThreads / yThreads; - } - - return dim3{static_cast<unsigned int>(xThreads), static_cast<unsigned int>(yThreads)}; -} - -dim3 Utils::HostHIP::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum) -{ - return getBlocksGrid(threadsPerBlock, rowsNum, 1); -} - -dim3 Utils::HostHIP::getBlocksGrid(const dim3& threadsPerBlock, const int rowsNum, const int colsNum) -{ - return dim3{1 + (rowsNum - 1) / threadsPerBlock.x, 1 + (colsNum - 1) / threadsPerBlock.y}; -} - -void Utils::HostHIP::gpuMalloc(void** p, const int size) -{ - checkHIPError(hipMalloc(p, size), __FILE__, __LINE__); -} - -void Utils::HostHIP::gpuFree(void* p) -{ - checkHIPError(hipFree(p), __FILE__, __LINE__); -} - -void Utils::HostHIP::gpuMemset(void* p, int value, int size) -{ - checkHIPError(hipMemset(p, value, size), __FILE__, __LINE__); -} - -void Utils::HostHIP::gpuMemcpyHostToDevice(void* dst, const void* src, int size) -{ - checkHIPError(hipMemcpy(dst, src, size, hipMemcpyHostToDevice), __FILE__, __LINE__); -} - -void Utils::HostHIP::gpuMemcpyHostToDeviceAsync(void* dst, const void* src, int size, hipStream_t& stream) -{ - checkHIPError(hipMemcpyAsync(dst, src, size, hipMemcpyHostToDevice, stream), __FILE__, __LINE__); -} - -void Utils::HostHIP::gpuMemcpyDeviceToHost(void* dst, const void* src, int size) -{ - checkHIPError(hipMemcpy(dst, src, size, hipMemcpyDeviceToHost), __FILE__, __LINE__); -} - -// void Utils::HostHIP::gpuStartProfiler() -// { -// checkHIPError(hipProfilerStart(), __FILE__, __LINE__); -// } - -// void Utils::HostHIP::gpuStopProfiler() -// { -// checkHIPError(hipProfilerStop(), __FILE__, __LINE__); -// } - -GPUd() int Utils::DeviceHIP::getLaneIndex() -{ - uint32_t laneIndex; - asm volatile("mov.u32 %0, %%laneid;" - : "=r"(laneIndex)); - return static_cast<int>(laneIndex); -} - -// GPUd() int Utils::Device::shareToWarp(const int value, const int laneIndex) -// { -// cooperative_groups::coalesced_group threadGroup = cooperative_groups::coalesced_threads(); -// return threadGroup.shfl(value, laneIndex); -// } - -// GPUd() int Utils::Device::gpuAtomicAdd(int* p, const int incrementSize) -// { -// return atomicAdd(p, incrementSize); -// } - -} // namespace GPU -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/hip/src/VertexerTraitsHIP.hip.cxx b/Detectors/ITSMFT/ITS/tracking/hip/src/VertexerTraitsHIP.hip.cxx deleted file mode 100644 index 425d7c04d98d5..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/hip/src/VertexerTraitsHIP.hip.cxx +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsHIP.hip.cxx -/// \brief -/// \author matteo.concas@cern.ch - -#include <iostream> -#include <sstream> -#include <array> -#include <cassert> -#include <hipcub/hipcub.hpp> - -#include "ITStracking/MathUtils.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingHIP/UtilsHIP.h" -#include "ITStrackingHIP/ClusterLinesHIP.h" -#include "ITStrackingHIP/ContextHIP.h" -#include "ITStrackingHIP/StreamHIP.h" -#include "ITStrackingHIP/VertexerTraitsHIP.h" - -namespace o2 -{ -namespace its -{ - -using constants::index_table::PhiBins; -using constants::index_table::ZBins; -using constants::its::LayersRCoordinate; -using constants::its::LayersZCoordinate; -using constants::its::VertexerHistogramVolume; -using constants::math::TwoPi; -using index_table_utils::getPhiBinIndex; -using index_table_utils::getZBinIndex; -using math_utils::getNormalizedPhiCoordinate; - -GPUh() void gpuThrowOnError() -{ - hipError_t error = hipGetLastError(); - - if (error != hipSuccess) { - std::ostringstream errorString{}; - errorString << "CUDA API returned error [" << hipGetErrorString(error) << "] (code " << error << ")" << std::endl; - throw std::runtime_error{errorString.str()}; - } -} - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -VertexerTraitsHIP::VertexerTraitsHIP() -{ - setIsGPU(true); - std::cout << "[DEBUG] Creating file: dbg_ITSVertexerHIP.root" << std::endl; - mDebugger = new StandaloneDebugger("dbg_ITSVertexerHIP.root"); -} - -VertexerTraitsHIP::~VertexerTraitsHIP() -{ - delete mDebugger; -} -#else -VertexerTraitsHIP::VertexerTraitsHIP() -{ - setIsGPU(true); -} - -#endif - -void VertexerTraitsHIP::initialise(ROframe* event) -{ - reset(); - arrangeClusters(event); - mStoreVertexerGPUPtr = mStoreVertexerGPU.initialise(mClusters, mIndexTables); -} - -namespace GPU -{ - -template <typename... Args> -GPUd() void printOnThread(const unsigned int tId, const char* str, Args... args) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf(str, args...); - } -} - -GPUd() void printVectorOnThread(const char* name, VectorHIP<int>& vector, size_t size, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf("vector %s :", name); - for (size_t i{0}; i < size; ++i) { - printf("%d ", vector[i]); - } - printf("\n"); - } -} - -GPUg() void printVectorKernel(DeviceStoreVertexerHIP* store, const unsigned int threadId) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { - for (int i{0}; i < store->getConfig().histConf.nBinsXYZ[0] - 1; ++i) { - printf("%d: %d\n", i, store->getHistogramXYZ()[0].get()[i]); - } - printf("\n"); - for (int i{0}; i < store->getConfig().histConf.nBinsXYZ[1] - 1; ++i) { - printf("%d: %d\n", i, store->getHistogramXYZ()[1].get()[i]); - } - printf("\n"); - for (int i{0}; i < store->getConfig().histConf.nBinsXYZ[2] - 1; ++i) { - printf("%d: %d\n", i, store->getHistogramXYZ()[2].get()[i]); - } - printf("\n"); - } -} - -GPUg() void dumpMaximaKernel(DeviceStoreVertexerHIP* store, const unsigned int threadId) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == threadId) { - printf("XmaxBin: %d at index: %d | YmaxBin: %d at index: %d | ZmaxBin: %d at index: %d\n", - store->getTmpVertexPositionBins()[0].value, store->getTmpVertexPositionBins()[0].key, - store->getTmpVertexPositionBins()[1].value, store->getTmpVertexPositionBins()[1].key, - store->getTmpVertexPositionBins()[2].value, store->getTmpVertexPositionBins()[2].key); - } -} - -GPUg() void trackleterKernel( - DeviceStoreVertexerHIP* store, - const TrackletingLayerOrder layerOrder, - const float phiCut) -{ - const size_t nClustersMiddleLayer = store->getClusters()[1].size(); - for (unsigned int currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { - if (currentClusterIndex < nClustersMiddleLayer) { - int storedTracklets{0}; - const unsigned int stride{currentClusterIndex * store->getConfig().maxTrackletsPerCluster}; - const Cluster& currentCluster = store->getClusters()[1][currentClusterIndex]; // assign-constructor may be a problem, check - const VertexerLayerName adjacentLayerIndex{layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer ? VertexerLayerName::innermostLayer : VertexerLayerName::outerLayer}; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, static_cast<int>(adjacentLayerIndex), 0.f, 50.f, phiCut / 2)}; - if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - if (phiBinsNum < 0) { - phiBinsNum += PhiBins; - } - const int nClustersAdjacentLayer = store->getClusters()[static_cast<int>(adjacentLayerIndex)].size(); - for (size_t iPhiBin{static_cast<size_t>(selectedBinsRect.y)}, iPhiCount{0}; (int)iPhiCount < phiBinsNum; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int firstRowClusterIndex{store->getIndexTable(adjacentLayerIndex)[firstBinIndex]}; - const int maxRowClusterIndex{store->getIndexTable(adjacentLayerIndex)[firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1]}; - for (int iAdjacentCluster{firstRowClusterIndex}; iAdjacentCluster < maxRowClusterIndex && iAdjacentCluster < nClustersAdjacentLayer; ++iAdjacentCluster) { - const Cluster& adjacentCluster = store->getClusters()[static_cast<int>(adjacentLayerIndex)][iAdjacentCluster]; // assign-constructor may be a problem, check - if (gpu::GPUCommonMath::Abs(currentCluster.phiCoordinate - adjacentCluster.phiCoordinate) < phiCut) { - if (storedTracklets < store->getConfig().maxTrackletsPerCluster) { - if (layerOrder == TrackletingLayerOrder::fromInnermostToMiddleLayer) { - store->getDuplets01().emplace(stride + storedTracklets, iAdjacentCluster, currentClusterIndex, adjacentCluster, currentCluster); - } else { - store->getDuplets12().emplace(stride + storedTracklets, currentClusterIndex, iAdjacentCluster, currentCluster, adjacentCluster); - } - ++storedTracklets; - } else { - printf("debug: leaving tracklet behind\n"); - } - } - } - } - } - store->getNFoundTracklets(layerOrder).emplace(currentClusterIndex, storedTracklets); - } - } -} - -GPUg() void trackletSelectionKernel( - DeviceStoreVertexerHIP* store, - const unsigned char isInitRun = false, - const float tanLambdaCut = 0.025f, - const float phiCut = 0.002f) -{ - const size_t nClustersMiddleLayer = store->getClusters()[1].size(); - for (size_t currentClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; currentClusterIndex < nClustersMiddleLayer; currentClusterIndex += blockDim.x * gridDim.x) { - const int stride{static_cast<int>(currentClusterIndex * store->getConfig().maxTrackletsPerCluster)}; - int validTracklets{0}; - for (int iTracklet12{0}; iTracklet12 < store->getNFoundTracklets(TrackletingLayerOrder::fromMiddleToOuterLayer)[currentClusterIndex]; ++iTracklet12) { - for (int iTracklet01{0}; iTracklet01 < store->getNFoundTracklets(TrackletingLayerOrder::fromInnermostToMiddleLayer)[currentClusterIndex] && validTracklets < store->getConfig().maxTrackletsPerCluster; ++iTracklet01) { - const float deltaTanLambda{gpu::GPUCommonMath::Abs(store->getDuplets01()[stride + iTracklet01].tanLambda - store->getDuplets12()[stride + iTracklet12].tanLambda)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(store->getDuplets01()[stride + iTracklet01].phiCoordinate - store->getDuplets12()[stride + iTracklet12].phiCoordinate)}; - if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != store->getConfig().maxTrackletsPerCluster) { - assert(store->getDuplets01()[stride + iTracklet01].secondClusterIndex == store->getDuplets12()[stride + iTracklet12].firstClusterIndex); - if (!isInitRun) { - store->getLines().emplace(store->getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, store->getDuplets01()[stride + iTracklet01], store->getClusters()[0].get(), store->getClusters()[1].get()); -#ifdef _ALLOW_DEBUG_TREES_ITS_ - store->getDupletIndices()[0].emplace(store->getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet01); - store->getDupletIndices()[1].emplace(store->getNExclusiveFoundLines()[currentClusterIndex] + validTracklets, stride + iTracklet12); -#endif - } - ++validTracklets; - } - } - } - if (isInitRun) { - store->getNFoundLines().emplace(currentClusterIndex, validTracklets); - if (validTracklets >= store->getConfig().maxTrackletsPerCluster) { - printf("Warning: not enough space for tracklet selection, some lines will be left behind\n"); - } - } - } - if (blockIdx.x * blockDim.x + threadIdx.x == 0) { - // first thread I want to write an empty line after last found, as adebug flag. Might delete later - store->getLines().emplace(store->getNExclusiveFoundLines()[store->getClusters()[1].size() - 1] + store->getNFoundLines()[store->getClusters()[1].size() - 1]); - } -} - -GPUg() void computeCentroidsKernel(DeviceStoreVertexerHIP* store, - const float pairCut) -{ - const unsigned int nLines = store->getNExclusiveFoundLines()[store->getClusters()[1].size() - 1] + store->getNFoundLines()[store->getClusters()[1].size() - 1]; - const unsigned int maxIterations{nLines * (nLines - 1) / 2}; - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < maxIterations; currentThreadIndex += blockDim.x * gridDim.x) { - int iFirstLine = currentThreadIndex / nLines; - int iSecondLine = currentThreadIndex % nLines; - if (iSecondLine <= iFirstLine) { - iFirstLine = nLines - iFirstLine - 2; - iSecondLine = nLines - iSecondLine - 1; - } - if (Line::getDCA(store->getLines()[iFirstLine], store->getLines()[iSecondLine]) < pairCut) { - ClusterLinesHIP cluster{store->getLines()[iFirstLine], store->getLines()[iSecondLine]}; - if (cluster.getVertex()[0] * cluster.getVertex()[0] + cluster.getVertex()[1] * cluster.getVertex()[1] < 1.98f * 1.98f) { - // printOnThread(0, "xCentr: %f, yCentr: %f \n", cluster.getVertex()[0], cluster.getVertex()[1]); - store->getXYCentroids().emplace(2 * currentThreadIndex, cluster.getVertex()[0]); - store->getXYCentroids().emplace(2 * currentThreadIndex + 1, cluster.getVertex()[1]); - } else { - // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. - store->getXYCentroids().emplace(2 * currentThreadIndex, 2 * store->getConfig().histConf.lowHistBoundariesXYZ[0]); - store->getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store->getConfig().histConf.lowHistBoundariesXYZ[1]); - } - } else { - // writing some data anyway outside the histogram, they will not be put in the histogram, by construction. - store->getXYCentroids().emplace(2 * currentThreadIndex, 2 * store->getConfig().histConf.lowHistBoundariesXYZ[0]); - store->getXYCentroids().emplace(2 * currentThreadIndex + 1, 2 * store->getConfig().histConf.lowHistBoundariesXYZ[1]); - } - } -} - -GPUg() void computeZCentroidsKernel(DeviceStoreVertexerHIP* store, - const float pairCut, const int binOpeningX, const int binOpeningY) -{ - const unsigned int nLines = store->getNExclusiveFoundLines()[store->getClusters()[1].size() - 1] + store->getNFoundLines()[store->getClusters()[1].size() - 1]; - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < nLines; currentThreadIndex += blockDim.x * gridDim.x) { - // printOnThread(0, "Max X: %d Max Y %d \n", store->getTmpVertexPositionBins()[0].value, store->getTmpVertexPositionBins()[1].value); - if (store->getTmpVertexPositionBins()[0].value || store->getTmpVertexPositionBins()[1].value) { - float tmpX{store->getConfig().histConf.lowHistBoundariesXYZ[0] + store->getTmpVertexPositionBins()[0].key * store->getConfig().histConf.binSizeHistX + store->getConfig().histConf.binSizeHistX / 2}; - int sumWX{store->getTmpVertexPositionBins()[0].value}; - float wX{tmpX * store->getTmpVertexPositionBins()[0].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store->getTmpVertexPositionBins()[0].key - binOpeningX)}; iBin < gpu::GPUCommonMath::Min(store->getTmpVertexPositionBins()[0].key + binOpeningX + 1, store->getConfig().histConf.nBinsXYZ[0] - 1); ++iBin) { - if (iBin != store->getTmpVertexPositionBins()[0].key) { - wX += (store->getConfig().histConf.lowHistBoundariesXYZ[0] + iBin * store->getConfig().histConf.binSizeHistX + store->getConfig().histConf.binSizeHistX / 2) * store->getHistogramXYZ()[0].get()[iBin]; - sumWX += store->getHistogramXYZ()[0].get()[iBin]; - } - } - float tmpY{store->getConfig().histConf.lowHistBoundariesXYZ[1] + store->getTmpVertexPositionBins()[1].key * store->getConfig().histConf.binSizeHistY + store->getConfig().histConf.binSizeHistY / 2}; - int sumWY{store->getTmpVertexPositionBins()[1].value}; - float wY{tmpY * store->getTmpVertexPositionBins()[1].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store->getTmpVertexPositionBins()[1].key - binOpeningY)}; iBin < gpu::GPUCommonMath::Min(store->getTmpVertexPositionBins()[1].key + binOpeningY + 1, store->getConfig().histConf.nBinsXYZ[1] - 1); ++iBin) { - if (iBin != store->getTmpVertexPositionBins()[1].key) { - wY += (store->getConfig().histConf.lowHistBoundariesXYZ[1] + iBin * store->getConfig().histConf.binSizeHistY + store->getConfig().histConf.binSizeHistY / 2) * store->getHistogramXYZ()[1].get()[iBin]; - sumWY += store->getHistogramXYZ()[1].get()[iBin]; - } - } - store->getBeamPosition().emplace(0, wX / sumWX); - store->getBeamPosition().emplace(1, wY / sumWY); - float fakeBeamPoint1[3] = {store->getBeamPosition()[0], store->getBeamPosition()[1], -1}; // get two points laying at different z, to create line object - float fakeBeamPoint2[3] = {store->getBeamPosition()[0], store->getBeamPosition()[1], 1}; - Line pseudoBeam{fakeBeamPoint1, fakeBeamPoint2}; - if (Line::getDCA(store->getLines()[currentThreadIndex], pseudoBeam) < pairCut) { - ClusterLinesHIP cluster{store->getLines()[currentThreadIndex], pseudoBeam}; - store->getZCentroids().emplace(currentThreadIndex, cluster.getVertex()[2]); - } else { - store->getZCentroids().emplace(currentThreadIndex, 2 * store->getConfig().histConf.lowHistBoundariesXYZ[2]); - } - } - } -} - -GPUg() void computeVertexKernel(DeviceStoreVertexerHIP* store, const int vertIndex, const int minContributors, const int binOpeningZ) -{ - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; (int)currentThreadIndex < binOpeningZ; currentThreadIndex += blockDim.x * gridDim.x) { - if (currentThreadIndex == 0) { - if (store->getTmpVertexPositionBins()[2].value > 1 && (store->getTmpVertexPositionBins()[0].value || store->getTmpVertexPositionBins()[1].value)) { - float z{store->getConfig().histConf.lowHistBoundariesXYZ[2] + store->getTmpVertexPositionBins()[2].key * store->getConfig().histConf.binSizeHistZ + store->getConfig().histConf.binSizeHistZ / 2}; - float ex{0.f}; - float ey{0.f}; - float ez{0.f}; - int sumWZ{store->getTmpVertexPositionBins()[2].value}; - float wZ{z * store->getTmpVertexPositionBins()[2].value}; - for (int iBin{gpu::GPUCommonMath::Max(0, store->getTmpVertexPositionBins()[2].key - binOpeningZ)}; iBin < gpu::GPUCommonMath::Min(store->getTmpVertexPositionBins()[2].key + binOpeningZ + 1, store->getConfig().histConf.nBinsXYZ[2] - 1); ++iBin) { - if (iBin != store->getTmpVertexPositionBins()[2].key) { - wZ += (store->getConfig().histConf.lowHistBoundariesXYZ[2] + iBin * store->getConfig().histConf.binSizeHistZ + store->getConfig().histConf.binSizeHistZ / 2) * store->getHistogramXYZ()[2].get()[iBin]; - sumWZ += store->getHistogramXYZ()[2].get()[iBin]; - } - store->getHistogramXYZ()[2].get()[iBin] = 0; - } - if (sumWZ > minContributors || vertIndex == 0) { - store->getVertices().emplace(vertIndex, store->getBeamPosition()[0], store->getBeamPosition()[1], wZ / sumWZ, ex, ey, ez, sumWZ); - } else { - store->getVertices().emplace(vertIndex); - } - } else { - store->getVertices().emplace(vertIndex); - } - } - } -} -} // namespace GPU - -void VertexerTraitsHIP::computeTracklets() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::HostHIP::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::HostHIP::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - - hipLaunchKernelGGL((GPU::trackleterKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, - getDeviceContextPtr(), - GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, - mVrtParams.phiCut); - - hipLaunchKernelGGL((GPU::trackleterKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, - getDeviceContextPtr(), - GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, - mVrtParams.phiCut); - - gpuThrowOnError(); - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { - mDebugger->fillCombinatoricsTree(mClusters, - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mEvent); - } -#endif -} - -void VertexerTraitsHIP::computeTrackletMatching() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::HostHIP::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::HostHIP::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); - - hipLaunchKernelGGL((GPU::trackletSelectionKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, - getDeviceContextPtr(), - true, // isInitRun - mVrtParams.tanLambdaCut, - mVrtParams.phiCut); - - (void)hipcub::DeviceScan::ExclusiveSum(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - mStoreVertexerGPU.getNFoundLines().get(), - mStoreVertexerGPU.getNExclusiveFoundLines().get(), - mClusters[1].size()); - - hipLaunchKernelGGL((GPU::trackletSelectionKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, - getDeviceContextPtr(), - false, // isInitRun - mVrtParams.tanLambdaCut, - mVrtParams.phiCut); - - gpuThrowOnError(); - -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::TrackletTreeAll)) { - mDebugger->fillTrackletSelectionTree(mClusters, - mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mStoreVertexerGPU.getDupletIndicesFromGPU(), - mEvent); - } - mTracklets = mStoreVertexerGPU.getLinesFromGPU(); - if (isDebugFlag(VertexerDebug::LineTreeAll)) { - mDebugger->fillPairsInfoTree(mTracklets, mEvent); - } - if (isDebugFlag(VertexerDebug::LineSummaryAll)) { - mDebugger->fillLinesSummaryTree(mTracklets, mEvent); - } -#endif -} - -void VertexerTraitsHIP::computeVertices() -{ - if (!mClusters[1].size()) { - std::cout << "\t\tno clusters on layer 1. Returning.\n"; - return; - } - const dim3 threadsPerBlock{GPU::Utils::HostHIP::getBlockSize(mClusters[1].capacity())}; - const dim3 blocksGrid{GPU::Utils::HostHIP::getBlocksGrid(threadsPerBlock, mClusters[1].capacity())}; - size_t bufferSize = mStoreVertexerGPU.getConfig().tmpCUBBufferSize * sizeof(int); - int nLines = mStoreVertexerGPU.getNExclusiveFoundLines().getElementFromDevice(mClusters[1].size() - 1) + mStoreVertexerGPU.getNFoundLines().getElementFromDevice(mClusters[1].size() - 1); - int nCentroids{static_cast<int>(nLines * (nLines - 1) / 2)}; - int* histogramXY[2] = {mStoreVertexerGPU.getHistogramXYZ()[0].get(), mStoreVertexerGPU.getHistogramXYZ()[1].get()}; - float tmpArrayLow[2] = {mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[1]}; - float tmpArrayHigh[2] = {mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[0], mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[1]}; - hipLaunchKernelGGL((GPU::computeCentroidsKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, getDeviceContextPtr(), - mVrtParams.histPairCut); - - (void)hipcub::DeviceHistogram::MultiHistogramEven<2, 2>(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage - bufferSize, // temp_storage_bytes - mStoreVertexerGPU.getXYCentroids().get(), // d_samples - histogramXY, // d_histogram - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ, // num_levels - tmpArrayLow, // lower_level - tmpArrayHigh, // fupper_level - nCentroids); // num_row_pixels - - (void)hipcub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - histogramXY[0], - mStoreVertexerGPU.getTmpVertexPositionBins().get(), - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0]); - (void)hipcub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - histogramXY[1], - mStoreVertexerGPU.getTmpVertexPositionBins().get() + 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0]); - - hipLaunchKernelGGL((GPU::computeZCentroidsKernel), dim3(blocksGrid), dim3(threadsPerBlock), 0, 0, getDeviceContextPtr(), mVrtParams.histPairCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[0], mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[1]); - - (void)hipcub::DeviceHistogram::HistogramEven(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), // d_temp_storage - bufferSize, // temp_storage_bytes - mStoreVertexerGPU.getZCentroids().get(), // d_samples - mStoreVertexerGPU.getHistogramXYZ()[2].get(), // d_histogram - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2], // num_levels - mStoreVertexerGPU.getConfig().histConf.lowHistBoundariesXYZ[2], // lower_level - mStoreVertexerGPU.getConfig().histConf.highHistBoundariesXYZ[2], // fupper_level - nLines); // num_row_pixels - - for (int iVertex{0}; iVertex < mStoreVertexerGPU.getConfig().nMaxVertices; ++iVertex) { - (void)hipcub::DeviceReduce::ArgMax(reinterpret_cast<void*>(mStoreVertexerGPU.getCUBTmpBuffer().get()), - bufferSize, - mStoreVertexerGPU.getHistogramXYZ()[2].get(), - mStoreVertexerGPU.getTmpVertexPositionBins().get() + 2, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2]); -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (isDebugFlag(VertexerDebug::HistCentroids) && !iVertex) { - mDebugger->fillXYZHistogramTree(std::array<std::vector<int>, 3>{mStoreVertexerGPU.getHistogramXYFromGPU()[0], - mStoreVertexerGPU.getHistogramXYFromGPU()[1], mStoreVertexerGPU.getHistogramZFromGPU()}, - std::array<int, 3>{mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[0] - 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[1] - 1, - mStoreVertexerGPU.getConfig().histConf.nBinsXYZ[2] - 1}); - } -#endif - hipLaunchKernelGGL((GPU::computeVertexKernel), dim3(blocksGrid), dim3(5), 0, 0, getDeviceContextPtr(), iVertex, mVrtParams.clusterContributorsCut, mStoreVertexerGPU.getConfig().histConf.binSpanXYZ[2]); - } - std::vector<GPU::GPUVertex> vertices; - vertices.resize(mStoreVertexerGPU.getConfig().nMaxVertices); - mStoreVertexerGPU.getVertices().copyIntoSizedVector(vertices); - - for (auto& vertex : vertices) { - if (vertex.realVertex) { - mVertices.emplace_back(vertex.xCoord, vertex.yCoord, vertex.zCoord, std::array<float, 6>{0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, vertex.contributors, 0.f, -9); - } - } - - gpuThrowOnError(); -} - -#ifdef _ALLOW_DEBUG_TREES_ITS_ -void VertexerTraitsHIP::computeMCFiltering() -{ - std::vector<Tracklet> tracklets01 = mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer); - std::vector<Tracklet> tracklets12 = mStoreVertexerGPU.getRawDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer); - std::vector<int> labels01 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer); - std::vector<int> labels12 = mStoreVertexerGPU.getNFoundTrackletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer); - VertexerStoreConfigurationGPU tmpGPUConf; - const int stride = tmpGPUConf.maxTrackletsPerCluster; - - filterTrackletsWithMC(tracklets01, tracklets12, labels01, labels12, stride); - mStoreVertexerGPU.updateFoundDuplets(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, labels01); - mStoreVertexerGPU.updateDuplets(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer, tracklets01); - mStoreVertexerGPU.updateFoundDuplets(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, labels12); - mStoreVertexerGPU.updateDuplets(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer, tracklets12); - - if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { - mDebugger->fillCombinatoricsTree(mClusters, - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromInnermostToMiddleLayer), - mStoreVertexerGPU.getDupletsFromGPU(GPU::TrackletingLayerOrder::fromMiddleToOuterLayer), - mEvent); - } -} -#endif - -VertexerTraits* createVertexerTraitsHIP() -{ - return new VertexerTraitsHIP; -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h index 059cde495b013..971ae6a7fe83a 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h index 8e71bade83e5f..397ef4274e5c2 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,6 @@ #include <vector> #endif -#include "ITStracking/Definitions.h" #include "GPUCommonDef.h" namespace o2 @@ -31,17 +31,17 @@ namespace its class Cell final { public: - GPU_DEVICE Cell(const int, const int, const int, const int, const int, const float3&, const float); - - GPUhdni() int getFirstClusterIndex() const; - GPUhdni() int getSecondClusterIndex() const; - GPUhdni() int getThirdClusterIndex() const; - GPU_HOST_DEVICE int getFirstTrackletIndex() const; - int getSecondTrackletIndex() const; - int getLevel() const; - float getCurvature() const; - const float3& getNormalVectorCoordinates() const; - void setLevel(const int level); + GPUd() Cell(const int, const int, const int, const int, const int, const float3&, const float); + + GPUhdni() int getFirstClusterIndex() const { return mFirstClusterIndex; }; + GPUhdni() int getSecondClusterIndex() const { return mSecondClusterIndex; }; + GPUhdni() int getThirdClusterIndex() const { return mThirdClusterIndex; }; + GPUhd() int getFirstTrackletIndex() const { return mFirstTrackletIndex; }; + int getSecondTrackletIndex() const { return mSecondTrackletIndex; }; + int getLevel() const { return mLevel; }; + float getCurvature() const { return mCurvature; }; + const float3& getNormalVectorCoordinates() const { return mNormalVectorCoordinates; }; + void setLevel(const int level) { mLevel = level; }; private: const int mFirstClusterIndex; @@ -54,9 +54,9 @@ class Cell final int mLevel; }; -inline GPU_DEVICE Cell::Cell(const int firstClusterIndex, const int secondClusterIndex, const int thirdClusterIndex, - const int firstTrackletIndex, const int secondTrackletIndex, - const float3& normalVectorCoordinates, const float curvature) +GPUdi() Cell::Cell(const int firstClusterIndex, const int secondClusterIndex, const int thirdClusterIndex, + const int firstTrackletIndex, const int secondTrackletIndex, + const float3& normalVectorCoordinates, const float curvature) : mFirstClusterIndex{firstClusterIndex}, mSecondClusterIndex{secondClusterIndex}, mThirdClusterIndex{thirdClusterIndex}, @@ -69,23 +69,6 @@ inline GPU_DEVICE Cell::Cell(const int firstClusterIndex, const int secondCluste // Nothing to do } -GPUhdi() int Cell::getFirstClusterIndex() const { return mFirstClusterIndex; } - -GPUhdi() int Cell::getSecondClusterIndex() const { return mSecondClusterIndex; } - -GPUhdi() int Cell::getThirdClusterIndex() const { return mThirdClusterIndex; } - -GPU_HOST_DEVICE inline int Cell::getFirstTrackletIndex() const { return mFirstTrackletIndex; } - -inline int Cell::getSecondTrackletIndex() const { return mSecondTrackletIndex; } - -inline int Cell::getLevel() const { return mLevel; } - -inline float Cell::getCurvature() const { return mCurvature; } - -inline const float3& Cell::getNormalVectorCoordinates() const { return mNormalVectorCoordinates; } - -inline void Cell::setLevel(const int level) { mLevel = level; } } // namespace its } // namespace o2 #endif /* TRACKINGITSU_INCLUDE_CACELL_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h index 68c09dc52f5a5..81b8ccb37dcfe 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,29 +20,33 @@ #include <array> #endif +#include "GPUCommonRtypes.h" #include "ITStracking/Definitions.h" #include "ITStracking/MathUtils.h" -#include "ITStracking/IndexTableUtils.h" namespace o2 { namespace its { +class IndexTableUtils; + struct Cluster final { Cluster() = default; Cluster(const float x, const float y, const float z, const int idx); - Cluster(const int, const Cluster&); - Cluster(const int, const float3&, const Cluster&); - void Init(const int, const float3&, const Cluster&); + Cluster(const int, const IndexTableUtils& utils, const Cluster&); + Cluster(const int, const float3&, const IndexTableUtils& utils, const Cluster&); + void Init(const int, const float3&, const IndexTableUtils& utils, const Cluster&); float xCoordinate; // = -999.f; float yCoordinate; // = -999.f; float zCoordinate; // = -999.f; - float phiCoordinate; // = -999.f; - float rCoordinate; // = -999.f; + float phi; // = -999.f; + float radius; // = -999.f; int clusterId; // = -1; int indexTableBinIndex; // = -1; + + ClassDefNV(Cluster, 1); }; struct TrackingFrameInfo { @@ -55,6 +60,8 @@ struct TrackingFrameInfo { float alphaTrackingFrame; GPUArray<float, 2> positionTrackingFrame = {-1., -1.}; GPUArray<float, 3> covarianceTrackingFrame = {999., 999., 999.}; + + ClassDefNV(TrackingFrameInfo, 1); }; } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h index 16a3446eaf72f..ca05ec41ab143 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ struct Line final { GPUhd() Line(const Tracklet&, const Cluster*, const Cluster*); #ifdef _ALLOW_DEBUG_TREES_ITS_ - Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters, const int evId); + GPUhd() Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters, const int evId); #endif inline static float getDistanceFromPoint(const Line& line, const std::array<float, 3>& point); @@ -88,8 +89,8 @@ GPUhdi() Line::Line(const float firstPoint[3], const float secondPoint[3]) cosinesDirector[i] = secondPoint[i] - firstPoint[i]; } - float inverseNorm{1.f / gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + - cosinesDirector[2] * cosinesDirector[2])}; + float inverseNorm{1.f / o2::gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + + cosinesDirector[2] * cosinesDirector[2])}; for (int index{0}; index < 3; ++index) { cosinesDirector[index] *= inverseNorm; @@ -106,8 +107,8 @@ GPUhdi() Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, cons cosinesDirector[1] = outerClusters[tracklet.secondClusterIndex].yCoordinate - innerClusters[tracklet.firstClusterIndex].yCoordinate; cosinesDirector[2] = outerClusters[tracklet.secondClusterIndex].zCoordinate - innerClusters[tracklet.firstClusterIndex].zCoordinate; - float inverseNorm{1.f / gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + - cosinesDirector[2] * cosinesDirector[2])}; + float inverseNorm{1.f / o2::gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + + cosinesDirector[2] * cosinesDirector[2])}; for (int index{0}; index < 3; ++index) { cosinesDirector[index] *= inverseNorm; @@ -125,8 +126,8 @@ GPUhdi() Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, cons cosinesDirector[1] = outerClusters[tracklet.secondClusterIndex].yCoordinate - innerClusters[tracklet.firstClusterIndex].yCoordinate; cosinesDirector[2] = outerClusters[tracklet.secondClusterIndex].zCoordinate - innerClusters[tracklet.firstClusterIndex].zCoordinate; - float inverseNorm{1.f / gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + - cosinesDirector[2] * cosinesDirector[2])}; + float inverseNorm{1.f / o2::gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + + cosinesDirector[2] * cosinesDirector[2])}; for (int index{0}; index < 3; ++index) cosinesDirector[index] *= inverseNorm; @@ -145,7 +146,7 @@ inline float Line::getDistanceFromPoint(const Line& line, const std::array<float DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) * (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta); } - return gpu::CAMath::Sqrt(DCASquared); + return o2::gpu::CAMath::Sqrt(DCASquared); } GPUhdi() float Line::getDistanceFromPoint(const Line& line, const float point[3]) @@ -159,7 +160,7 @@ GPUhdi() float Line::getDistanceFromPoint(const Line& line, const float point[3] DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) * (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta); } - return gpu::CAMath::Sqrt(DCASquared); + return o2::gpu::CAMath::Sqrt(DCASquared); } GPUhdi() float Line::getDCA(const Line& firstLine, const Line& secondLine, const float precision) @@ -178,7 +179,7 @@ GPUhdi() float Line::getDCA(const Line& firstLine, const Line& secondLine, const distance += (secondLine.originPoint[i] - firstLine.originPoint[i]) * normalVector[i]; } if (norm > precision) { - return gpu::CAMath::Abs(distance / gpu::CAMath::Sqrt(norm)); + return o2::gpu::CAMath::Abs(distance / o2::gpu::CAMath::Sqrt(norm)); } else { #if defined(__CUDACC__) || defined(__HIPCC__) float stdOriginPoint[3]; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index 2951da3b81ae3..5ff3cb0225785 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,10 +16,12 @@ #ifndef TRACKINGITSU_INCLUDE_CONFIGURATION_H_ #define TRACKINGITSU_INCLUDE_CONFIGURATION_H_ +#ifndef GPUCA_GPUCODE_DEVICE #include <array> #include <climits> #include <vector> #include <cmath> +#endif #include "ITStracking/Constants.h" @@ -44,32 +47,59 @@ class Configuration : public Param }; struct TrackingParameters { - TrackingParameters& operator=(const TrackingParameters& t); + TrackingParameters& operator=(const TrackingParameters& t) = default; + void CopyCuts(TrackingParameters& other, float scale = 1.) + { + TrackletMaxDeltaPhi = other.TrackletMaxDeltaPhi * scale; + for (unsigned int ii{0}; ii < TrackletMaxDeltaZ.size(); ++ii) { + TrackletMaxDeltaZ[ii] = other.TrackletMaxDeltaZ[ii] * scale; + } + CellMaxDeltaTanLambda = other.CellMaxDeltaTanLambda * scale; + for (unsigned int ii{0}; ii < CellMaxDCA.size(); ++ii) { + CellMaxDCA[ii] = other.CellMaxDCA[ii] * scale; + } + for (unsigned int ii{0}; ii < NeighbourMaxDeltaCurvature.size(); ++ii) { + NeighbourMaxDeltaCurvature[ii] = other.NeighbourMaxDeltaCurvature[ii] * scale; + NeighbourMaxDeltaN[ii] = other.NeighbourMaxDeltaN[ii] * scale; + } + } int CellMinimumLevel(); + int CellsPerRoad() const { return NLayers - 2; } + int TrackletsPerRoad() const { return NLayers - 1; } + + int NLayers = 7; + int DeltaROF = 1; + std::vector<float> LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; + std::vector<float> LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; + int ZBins{256}; + int PhiBins{128}; /// General parameters int ClusterSharing = 0; int MinTrackLength = 7; /// Trackleting cuts float TrackletMaxDeltaPhi = 0.3f; - float TrackletMaxDeltaZ[constants::its::TrackletsPerRoad] = {0.1f, 0.1f, 0.3f, 0.3f, 0.3f, 0.3f}; + std::vector<float> TrackletMaxDeltaZ = {0.1f, 0.1f, 0.3f, 0.3f, 0.3f, 0.3f}; /// Cell finding cuts float CellMaxDeltaTanLambda = 0.025f; - float CellMaxDCA[constants::its::CellsPerRoad] = {0.05f, 0.04f, 0.05f, 0.2f, 0.4f}; + std::vector<float> CellMaxDCA = {0.05f, 0.04f, 0.05f, 0.2f, 0.4f}; float CellMaxDeltaPhi = 0.14f; - float CellMaxDeltaZ[constants::its::CellsPerRoad] = {0.2f, 0.4f, 0.5f, 0.6f, 3.0f}; + std::vector<float> CellMaxDeltaZ = {0.2f, 0.4f, 0.5f, 0.6f, 3.0f}; /// Neighbour finding cuts - float NeighbourMaxDeltaCurvature[constants::its::CellsPerRoad - 1] = {0.008f, 0.0025f, 0.003f, 0.0035f}; - float NeighbourMaxDeltaN[constants::its::CellsPerRoad - 1] = {0.002f, 0.0090f, 0.002f, 0.005f}; + std::vector<float> NeighbourMaxDeltaCurvature = {0.008f, 0.0025f, 0.003f, 0.0035f}; + std::vector<float> NeighbourMaxDeltaN = {0.002f, 0.0090f, 0.002f, 0.005f}; + /// Fitter parameters + bool UseMatBudLUT = false; + std::array<float, 2> FitIterationMaxChi2 = {100, 50}; }; struct MemoryParameters { /// Memory coefficients - MemoryParameters& operator=(const MemoryParameters& t); + MemoryParameters& operator=(const MemoryParameters& t) = default; int MemoryOffset = 256; - float CellsMemoryCoefficients[constants::its::CellsPerRoad] = {2.3208e-08f, 2.104e-08f, 1.6432e-08f, 1.2412e-08f, 1.3543e-08f}; - float TrackletsMemoryCoefficients[constants::its::TrackletsPerRoad] = {0.0016353f, 0.0013627f, 0.000984f, 0.00078135f, 0.00057934f, 0.00052217f}; + std::vector<float> CellsMemoryCoefficients = {2.3208e-08f, 2.104e-08f, 1.6432e-08f, 1.2412e-08f, 1.3543e-08f}; + std::vector<float> TrackletsMemoryCoefficients = {0.0016353f, 0.0013627f, 0.000984f, 0.00078135f, 0.00057934f, 0.00052217f}; }; inline int TrackingParameters::CellMinimumLevel() @@ -77,43 +107,12 @@ inline int TrackingParameters::CellMinimumLevel() return MinTrackLength - constants::its::ClustersPerCell + 1; } -inline TrackingParameters& TrackingParameters::operator=(const TrackingParameters& t) -{ - this->ClusterSharing = t.ClusterSharing; - this->MinTrackLength = t.MinTrackLength; - /// Trackleting cuts - this->TrackletMaxDeltaPhi = t.TrackletMaxDeltaPhi; - for (int iT = 0; iT < constants::its::TrackletsPerRoad; ++iT) { - this->TrackletMaxDeltaZ[iT] = t.TrackletMaxDeltaZ[iT]; - } - /// Cell finding cuts - this->CellMaxDeltaTanLambda = t.CellMaxDeltaTanLambda; - this->CellMaxDeltaPhi = t.CellMaxDeltaPhi; - for (int iC = 0; iC < constants::its::CellsPerRoad; ++iC) { - this->CellMaxDCA[iC] = t.CellMaxDCA[iC]; - this->CellMaxDeltaZ[iC] = t.CellMaxDeltaZ[iC]; - } - /// Neighbour finding cuts - for (int iC = 0; iC < constants::its::CellsPerRoad - 1; ++iC) { - this->NeighbourMaxDeltaCurvature[iC] = t.NeighbourMaxDeltaCurvature[iC]; - this->NeighbourMaxDeltaN[iC] = t.NeighbourMaxDeltaN[iC]; - } - return *this; -} - -inline MemoryParameters& MemoryParameters::operator=(const MemoryParameters& t) -{ - this->MemoryOffset = t.MemoryOffset; - for (int iC = 0; iC < constants::its::CellsPerRoad; ++iC) { - this->CellsMemoryCoefficients[iC] = t.CellsMemoryCoefficients[iC]; - } - for (int iT = 0; iT < constants::its::TrackletsPerRoad; ++iT) { - this->TrackletsMemoryCoefficients[iT] = t.TrackletsMemoryCoefficients[iT]; - } - return *this; -} - struct VertexingParameters { + std::vector<float> LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; + std::vector<float> LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; + int ZBins{256}; + int PhiBins{128}; + float zCut = 0.002f; //0.002f float phiCut = 0.005f; //0.005f float pairCut = 0.04f; @@ -165,7 +164,7 @@ struct VertexerStoreConfigurationGPU { int maxTrkCap, int maxVert); - // o2::its::GPU::Vector constructor requires signed size for initialisation + // o2::its::gpu::Vector constructor requires signed size for initialisation int tmpCUBBufferSize = 25e5; int maxTrackletsPerCluster = 2e2; int clustersPerLayerCapacity = 4e4; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h index e6353c9cae8af..25825dace2404 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,9 @@ #endif #include "ITStracking/Definitions.h" +#include "CommonConstants/MathConstants.h" +#include "GPUCommonMath.h" +#include "GPUCommonDef.h" namespace o2 { @@ -41,48 +45,79 @@ constexpr float FloatMinThreshold{1e-20f}; namespace its { -constexpr int LayersNumber{7}; constexpr int LayersNumberVertexer{3}; -constexpr int TrackletsPerRoad{LayersNumber - 1}; -constexpr int CellsPerRoad{LayersNumber - 2}; constexpr int ClustersPerCell{3}; constexpr int UnusedIndex{-1}; constexpr float Resolution{0.0005f}; -GPU_HOST_DEVICE constexpr GPUArray<float, LayersNumber> LayersZCoordinate() +GPUhdi() constexpr GPUArray<float, 3> VertexerHistogramVolume() +{ + return GPUArray<float, 3>{{1.98, 1.98, 40.f}}; +} +} // namespace its + +namespace its2 +{ +constexpr int LayersNumber{7}; +constexpr int TrackletsPerRoad{LayersNumber - 1}; +constexpr int CellsPerRoad{LayersNumber - 2}; + +GPUhdi() constexpr GPUArray<float, LayersNumber> LayersZCoordinate() { constexpr double s = 1.; // safety margin return GPUArray<float, LayersNumber>{{16.333f + s, 16.333f + s, 16.333f + s, 42.140f + s, 42.140f + s, 73.745f + s, 73.745f + s}}; } -GPU_HOST_DEVICE constexpr GPUArray<float, LayersNumber> LayersRCoordinate() +GPUhdi() constexpr GPUArray<float, LayersNumber> LayersRCoordinate() { return GPUArray<float, LayersNumber>{{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}}; } -GPU_HOST_DEVICE constexpr GPUArray<float, 3> VertexerHistogramVolume() + +constexpr int ZBins{256}; +constexpr int PhiBins{128}; +constexpr float InversePhiBinSize{PhiBins / constants::math::TwoPi}; +GPUhdi() constexpr GPUArray<float, LayersNumber> InverseZBinSize() +{ + constexpr auto zSize = LayersZCoordinate(); + return GPUArray<float, LayersNumber>{{0.5f * ZBins / (zSize[0]), 0.5f * ZBins / (zSize[1]), 0.5f * ZBins / (zSize[2]), + 0.5f * ZBins / (zSize[3]), 0.5f * ZBins / (zSize[4]), 0.5f * ZBins / (zSize[5]), + 0.5f * ZBins / (zSize[6])}}; +} +inline float getInverseZCoordinate(const int layerIndex) { - return GPUArray<float, 3>{{1.98, 1.98, 40.f}}; + return 0.5f * ZBins / LayersZCoordinate()[layerIndex]; } -} // namespace its -namespace index_table +GPUhdi() int getZBinIndex(const int layerIndex, const float zCoordinate) { -constexpr int ZBins{256}; -constexpr int PhiBins{128}; -constexpr float InversePhiBinSize{constants::index_table::PhiBins / constants::math::TwoPi}; -GPU_HOST_DEVICE constexpr GPUArray<float, its::LayersNumber> InverseZBinSize() + return (zCoordinate + LayersZCoordinate()[layerIndex]) * + InverseZBinSize()[layerIndex]; +} + +GPUhdi() int getPhiBinIndex(const float currentPhi) +{ + return (currentPhi * InversePhiBinSize); +} + +GPUhdi() int getBinIndex(const int zIndex, const int phiIndex) { - constexpr auto zSize = its::LayersZCoordinate(); - return GPUArray<float, its::LayersNumber>{{0.5f * ZBins / (zSize[0]), 0.5f * ZBins / (zSize[1]), 0.5f * ZBins / (zSize[2]), - 0.5f * ZBins / (zSize[3]), 0.5f * ZBins / (zSize[4]), 0.5f * ZBins / (zSize[5]), - 0.5f * ZBins / (zSize[6])}}; + return o2::gpu::GPUCommonMath::Min(phiIndex * ZBins + zIndex, + ZBins * PhiBins - 1); } -} // namespace index_table + +GPUhdi() constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } + +} // namespace its2 namespace pdgcodes { constexpr int PionCode{211}; } } // namespace constants +// typedef std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, +// constants::its::TrackletsPerRoad> index_table_t; +#ifndef __OPENCL__ /// FIXME: this is for compatibility with OCL +typedef std::vector<std::vector<int>> index_table_t; +#endif } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/DBScan.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/DBScan.h deleted file mode 100644 index 1e8d16b42bdea..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/DBScan.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DBScan.h -/// \brief -/// - -#ifndef O2_ITS_TRACKING_DBSCAN_H_ -#define O2_ITS_TRACKING_DBSCAN_H_ - -#include <algorithm> -#include "ITStracking/Graph.h" - -namespace o2 -{ -namespace its -{ - -typedef std::pair<int, unsigned char> State; - -template <typename T> -class DBScan : Graph<T> -{ - public: - DBScan() = delete; - explicit DBScan(const size_t nThreads); - void init(std::vector<T>&, std::function<bool(const T& v1, const T& v2)>); - void classifyVertices(const int); - void classifyVertices(std::function<unsigned char(std::vector<Edge>&)> classFunction); - void classifyVertices(std::function<unsigned char(std::vector<Edge>&)> classFunction, std::function<bool(State&, State&)> sortFunction); - std::vector<State> getStates() const { return mStates; } - std::vector<int> getCores(); - std::vector<std::vector<int>> computeClusters(); - - private: - std::vector<State> mStates; - std::function<unsigned char(std::vector<Edge>&)> mClassFunction; -}; - -template <typename T> -DBScan<T>::DBScan(const size_t nThreads) : Graph<T>(nThreads) -{ -} - -template <typename T> -void DBScan<T>::init(std::vector<T>& vertices, std::function<bool(const T& v1, const T& v2)> discFunction) -{ - this->Graph<T>::init(vertices); - this->Graph<T>::computeEdges(discFunction); -} - -template <typename T> -void DBScan<T>::classifyVertices(const int nContributors) -{ - classifyVertices([nContributors](std::vector<o2::its::Edge>& edges) { return edges.size() == 0 ? 0 : edges.size() >= static_cast<size_t>(nContributors - 1) ? 2 : 1; }, - [](State& s1, State& s2) { return static_cast<int>(s1.second) > static_cast<int>(s2.second); }); -} - -template <typename T> -void DBScan<T>::classifyVertices(std::function<unsigned char(std::vector<Edge>& edges)> classFunction) -{ - mClassFunction = classFunction; - const size_t size = {this->mVertices->size()}; - mStates.resize(size); - - if (!this->isMultiThreading()) { - for (size_t iVertex{0}; iVertex < size; ++iVertex) { - mStates[iVertex] = std::make_pair<int, unsigned char>(iVertex, classFunction(this->getEdges()[iVertex])); - } - } else { - const size_t stride{static_cast<size_t>(std::ceil(this->mVertices->size() / static_cast<size_t>(this->mExecutors.size())))}; - for (size_t iExecutor{0}; iExecutor < this->mExecutors.size(); ++iExecutor) { - // We cannot pass a template function to std::thread(), using lambda instead - this->mExecutors[iExecutor] = std::thread( - [iExecutor, stride, this](const auto& classFunction) { - for (size_t iVertex{iExecutor * stride}; iVertex < stride * (iExecutor + 1) && iVertex < this->mVertices->size(); ++iVertex) { - mStates[iVertex] = std::make_pair<int, unsigned char>(iVertex, classFunction(this->getEdges()[iVertex])); - } - }, - mClassFunction); - } - } - for (auto&& thread : this->mExecutors) { - thread.join(); - } -} - -template <typename T> -void DBScan<T>::classifyVertices(std::function<unsigned char(std::vector<Edge>&)> classFunction, std::function<bool(State&, State&)> sortFunction) -{ - classifyVertices(classFunction); - std::sort(mStates.begin(), mStates.end(), sortFunction); -} - -template <typename T> -std::vector<int> DBScan<T>::getCores() -{ - std::vector<State> cores; - std::vector<int> coreIndices; - std::copy_if(mStates.begin(), mStates.end(), std::back_inserter(cores), [](const State& state) { return state.second == 2; }); - std::transform(cores.begin(), cores.end(), std::back_inserter(coreIndices), [](const State& state) -> int { return state.first; }); - return coreIndices; -} - -template <typename T> -std::vector<std::vector<int>> DBScan<T>::computeClusters() -{ - std::vector<std::vector<int>> clusters; - std::vector<int> cores = getCores(); - std::vector<unsigned char> usedVertices(this->mVertices->size(), false); - - for (size_t core{0}; core < cores.size(); ++core) { - if (!usedVertices[cores[core]]) { - std::vector<unsigned char> clusterFlags = this->getCluster(cores[core]); - std::transform(usedVertices.begin(), usedVertices.end(), clusterFlags.begin(), usedVertices.begin(), std::logical_or<>()); - clusters.emplace_back(std::move(this->getClusterIndices(clusterFlags))); - } - } - return clusters; -} - -struct Centroid final { - Centroid() = default; - Centroid(int* indices, float* position); - void init(); - static float ComputeDistance(const Centroid& c1, const Centroid& c2); - - int mIndices[2]; - float mPosition[3]; -}; - -} // namespace its -} // namespace o2 -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h index c3f9ca43f2ac0..73a62c05c0aab 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,96 +11,127 @@ /// /// \file Definitions.h /// \brief -/// -#ifndef TRACKINGITSU_INCLUDE_CADEFINITIONS_H_ -#define TRACKINGITSU_INCLUDE_CADEFINITIONS_H_ +#ifndef TRACKINGITS_DEFINITIONS_H_ +#define TRACKINGITS_DEFINITIONS_H_ // #define _ALLOW_DEBUG_TREES_ITS_ // to allow debug (vertexer only) +// #define CA_DEBUG + +template <typename T> +void discardResult(const T&) +{ +} #ifndef GPUCA_GPUCODE_DEVICE #include <array> #endif -//#define CA_DEBUG - #ifdef CA_DEBUG #define CA_DEBUGGER(x) x #else #define CA_DEBUGGER(x) \ do { \ } while (0) -// #ifndef NDEBUG -// #define NDEBUG 1 -// #endif -#endif - -#if defined(CUDA_ENABLED) -#define TRACKINGITSU_GPU_MODE true -#else -#define TRACKINGITSU_GPU_MODE false #endif -#if defined(__CUDACC__) -#define TRACKINGITSU_GPU_COMPILING -#endif - -#if defined(__CUDA_ARCH__) +#if defined(__CUDA_ARCH__) // ???? #define TRACKINGITSU_GPU_DEVICE #endif -#if defined(__CUDACC__) - -#define GPU_HOST __host__ -#define GPU_DEVICE __device__ -#define GPU_HOST_DEVICE __host__ __device__ -#define GPU_GLOBAL __global__ -#define GPU_SHARED __shared__ -#define GPU_SYNC __syncthreads() - +#if defined(__CUDACC__) || defined(__HIPCC__) #define MATH_CEIL ceil #ifndef GPUCA_GPUCODE_DEVICE #include <cstddef> #endif -#include "ITStrackingCUDA/Array.h" +#include "../GPU/ITStrackingGPU/Array.h" template <typename T, size_t Size> -using GPUArray = o2::its::GPU::Array<T, Size>; +using GPUArray = o2::its::gpu::Array<T, Size>; + +#ifdef __CUDACC__ +#define GPU_ARCH "CUDA" typedef cudaStream_t GPUStream; +inline int getGPUCores(const int major, const int minor) +{ + // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM + typedef struct + { + int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version + int Cores; + } sSMtoCores; + + sSMtoCores nGpuArchCoresPerSM[] = + { + {0x20, 32}, // Fermi Generation (SM 2.0) GF100 class + {0x21, 48}, // Fermi Generation (SM 2.1) GF10x class + {0x30, 192}, // Kepler Generation (SM 3.0) GK10x class + {0x32, 192}, // Kepler Generation (SM 3.2) GK10x class + {0x35, 192}, // Kepler Generation (SM 3.5) GK11x class + {0x37, 192}, // Kepler Generation (SM 3.7) GK21x class + {0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class + {0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class + {0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class + {0x60, 64}, // Pascal Generation (SM 6.0) GP100 class + {0x61, 128}, // Pascal Generation (SM 6.1) GP10x class + {0x62, 128}, // Pascal Generation (SM 6.2) GP10x class + {0x70, 64}, // Volta Generation (SM 7.0) GV100 class + {0x72, 64}, // Volta Generation (SM 7.2) GV10B class + {0x75, 64}, // Turing Generation (SM 7.5) TU1xx class + {-1, -1}}; + + int index = 0; + + while (nGpuArchCoresPerSM[index].SM != -1) { + if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { + return nGpuArchCoresPerSM[index].Cores; + } + + index++; + } + + // If we don't find the values, we default use the previous one to run properly + return nGpuArchCoresPerSM[index - 1].Cores; +} +inline int getGPUMaxThreadsPerComputingUnit() +{ + return 8; +} + +#else // __HIPCC__ +#define GPU_ARCH "HIP" +typedef hipStream_t GPUStream; +inline int getGPUCores(const int major, const int minor) +{ + // Hardcoded result for AMD RADEON WX 9100, to be decided if and how determine this paramter + return 4096; +} + +inline int getGPUMaxThreadsPerComputingUnit() +{ + return 8; +} +#endif #else - -#define GPU_HOST -#define GPU_DEVICE -#define GPU_HOST_DEVICE -#define GPU_GLOBAL -#define GPU_SHARED -#define GPU_SYNC - #define MATH_CEIL std::ceil - #ifndef __VECTOR_TYPES_H__ - #include "GPUCommonDef.h" - #endif - #ifndef __OPENCL__ #include <cstddef> template <typename T, size_t Size> using GPUArray = std::array<T, Size>; #else -#include "ITStrackingCUDA/Array.h" - +#include "../GPU/ITStrackingGPU/Array.h" template <typename T, size_t Size> -using GPUArray = o2::its::GPU::Array<T, Size>; +using GPUArray = o2::its::gpu::Array<T, Size>; #endif typedef struct _dummyStream { } GPUStream; - #endif -#endif /* TRACKINGITSU_INCLUDE_CADEFINITIONS_H_ */ +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Graph.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Graph.h deleted file mode 100644 index d1fca077e29c6..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Graph.h +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Graph.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_ALGORITHMS_H_ -#define TRACKINGITSU_INCLUDE_ALGORITHMS_H_ - -#include <array> -#include <cmath> -#include <condition_variable> -#include <functional> -#include <iostream> -#include <mutex> -#include <queue> -#include <thread> -#include <utility> -#include <vector> - -namespace o2 -{ -namespace its -{ - -typedef int Edge; - -class Barrier -{ - public: - explicit Barrier(std::size_t count) : count(count) {} - void Wait(); - - private: - std::mutex mutex; - std::condition_variable condition; - std::size_t count; -}; - -template <typename T> -class Graph -{ - public: - Graph() = delete; - explicit Graph(const size_t nThreads = 1); - void init(std::vector<T>&); - std::vector<unsigned char> getCluster(const int); - std::vector<int> getClusterIndices(const int); - std::vector<int> getClusterIndices(const std::vector<unsigned char> /* , const int*/); - void computeEdges(std::function<bool(const T& v1, const T& v2)>); - std::vector<std::vector<Edge>> getEdges() const { return mEdges; } - char isMultiThreading() const { return mIsMultiThread; } - - std::vector<T>* mVertices = nullptr; // Observer pointer - std::vector<std::thread> mExecutors; // Difficult to pass - - private: - void findVertexEdges(std::vector<Edge>& localEdges, const T& vertex, const size_t vId, const size_t size); - - // Multithread block - size_t mNThreads; - char mIsMultiThread; - - // Common data members - std::function<bool(const T&, const T&)> mLinkFunction; - std::vector<std::vector<Edge>> mEdges; - std::vector<unsigned char> mVisited; -}; - -template <typename T> -Graph<T>::Graph(const size_t nThreads) : mNThreads{nThreads} -{ - mIsMultiThread = nThreads > 1 ? true : false; -} - -template <typename T> -void Graph<T>::init(std::vector<T>& vertices) -{ - - // Graph initialization - mVertices = &vertices; - if (mIsMultiThread) { - mNThreads = std::min(static_cast<const size_t>(std::thread::hardware_concurrency()), mNThreads); - mExecutors.resize(mNThreads); - } - - mEdges.resize(vertices.size()); - mVisited.resize(vertices.size(), false); -} - -template <typename T> -void Graph<T>::computeEdges(std::function<bool(const T& v1, const T& v2)> linkFunction) -{ - mLinkFunction = linkFunction; - int tot_nedges = 0; - const size_t size = {mVertices->size()}; - if (!mIsMultiThread) { - for (size_t iVertex{0}; iVertex < size; ++iVertex) { - findVertexEdges(mEdges[iVertex], (*mVertices)[iVertex], iVertex, size); - tot_nedges += static_cast<int>(mEdges[iVertex].size()); - } - } else { - mNThreads = std::min(static_cast<const size_t>(std::thread::hardware_concurrency()), mNThreads); - mExecutors.resize(mNThreads); - const size_t stride{static_cast<size_t>(std::ceil(mVertices->size() / static_cast<size_t>(mExecutors.size())))}; - for (size_t iExecutor{0}; iExecutor < mExecutors.size(); ++iExecutor) { - // We cannot pass a template function to std::thread(), using lambda instead - mExecutors[iExecutor] = std::thread( - [iExecutor, stride, this](const auto& linkFunction) { - for (size_t iVertex1{iExecutor * stride}; iVertex1 < stride * (iExecutor + 1) && iVertex1 < mVertices->size(); ++iVertex1) { - for (size_t iVertex2{0}; iVertex2 < mVertices->size(); ++iVertex2) { - if (iVertex1 != iVertex2 && linkFunction((*mVertices)[iVertex1], (*mVertices)[iVertex2])) { - mEdges[iVertex1].emplace_back(iVertex2); - } - } - } - }, - mLinkFunction); - } - } - for (auto&& thread : mExecutors) { - thread.join(); - } -} -template <typename T> -void Graph<T>::findVertexEdges(std::vector<Edge>& localEdges, const T& vertex, const size_t vId, const size_t size) -{ - for (size_t iVertex2{0}; iVertex2 < size; ++iVertex2) { - if (vId != iVertex2 && mLinkFunction(vertex, (*mVertices)[iVertex2])) { - localEdges.emplace_back(iVertex2); - } - } -} - -template <typename T> -std::vector<unsigned char> Graph<T>::getCluster(const int vertexId) -{ - // This method uses a BFS algorithm to return all the graph - // vertex ids belonging to a graph - std::vector<int> indices; - std::vector<unsigned char> visited(mVertices->size(), false); - - if (!mIsMultiThread) { - std::queue<int> idQueue; - idQueue.emplace(vertexId); - visited[vertexId] = true; - - // Consume the queue - while (!idQueue.empty()) { - const int id = idQueue.front(); - idQueue.pop(); - for (Edge edge : mEdges[id]) { - if (!visited[edge]) { - idQueue.emplace(edge); - indices.emplace_back(edge); - visited[edge] = true; - } - } - } - } else { - const size_t stride{static_cast<size_t>(std::ceil(static_cast<float>(this->mVertices->size()) / static_cast<size_t>(this->mExecutors.size())))}; - std::vector<unsigned char> frontier(mVertices->size(), false); - std::vector<unsigned char> flags(mVertices->size(), false); - - frontier[vertexId] = true; - int counter{0}; - while (std::any_of(frontier.begin(), frontier.end(), [](const char t) { return t; })) { - flags.resize(mVertices->size(), false); - Barrier barrier(mExecutors.size()); - for (size_t iExecutor{0}; iExecutor < this->mExecutors.size(); ++iExecutor) { - mExecutors[iExecutor] = std::thread( - [&stride, &frontier, &visited, &barrier, &flags, this](const int executorId) { - for (size_t iVertex{executorId * stride}; iVertex < stride * (executorId + 1) && iVertex < this->mVertices->size(); ++iVertex) { - if (frontier[iVertex]) { - flags[iVertex] = true; - frontier[iVertex] = false; - visited[iVertex] = true; - } - } - barrier.Wait(); - for (size_t iVertex{executorId * stride}; iVertex < stride * (executorId + 1) && iVertex < this->mVertices->size(); ++iVertex) { - if (flags[iVertex]) { - for (auto& edge : mEdges[iVertex]) { - if (!visited[edge]) { - frontier[edge] = true; - } - } - } - } - }, - iExecutor); - } - for (auto&& thread : mExecutors) { - thread.join(); - } - } - } - return visited; -} - -template <typename T> -std::vector<int> Graph<T>::getClusterIndices(const std::vector<unsigned char> visited) -{ - // Return a smaller vector only with the int IDs of the vertices belonging to cluster - std::vector<int> indices; - for (size_t iVisited{0}; iVisited < visited.size(); ++iVisited) { - if (visited[iVisited]) { - indices.emplace_back(iVisited); - } - } - return indices; -} - -template <typename T> -std::vector<int> Graph<T>::getClusterIndices(const int vertexId) -{ - std::vector<unsigned char> visited = std::move(getCluster(vertexId)); - return getClusterIndices(visited); -} - -} // namespace its -} // namespace o2 - -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IOUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IOUtils.h index 8afe8dbbe4b78..7ff05ebacc054 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IOUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IOUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -55,15 +56,12 @@ constexpr float DefClusErrorCol = o2::itsmft::SegmentationAlpide::PitchCol * 0.5 constexpr float DefClusError2Row = DefClusErrorRow * DefClusErrorRow; constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; -void loadConfigurations(const std::string&); -std::vector<ROframe> loadEventData(const std::string&); void loadEventData(ROframe& events, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* clsLabels = nullptr); int loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& events, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* mClsLabels = nullptr); -void generateSimpleData(ROframe& event, const int phiDivs, const int zDivs); void convertCompactClusters(gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h index 228defce3b650..4ace28b31e490 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #endif #include "ITStracking/Constants.h" +#include "ITStracking/Configuration.h" #include "ITStracking/Definitions.h" #include "GPUCommonMath.h" #include "GPUCommonDef.h" @@ -31,42 +33,64 @@ namespace o2 namespace its { -namespace index_table_utils +class IndexTableUtils { -float getInverseZBinSize(const int); -GPUhdi() int getZBinIndex(const int, const float); -GPUhdi() int getPhiBinIndex(const float); -GPUhdi() int getBinIndex(const int, const int); -GPUhdi() int countRowSelectedBins( - const GPUArray<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>&, const int, const int, - const int); -} // namespace index_table_utils + public: + template <class T> + void setTrackingParameters(const T& params); + float getInverseZCoordinate(const int layerIndex) const; + GPUhdi() int getZBinIndex(const int, const float) const; + GPUhdi() int getPhiBinIndex(const float) const; + GPUhdi() int getBinIndex(const int, const int) const; + GPUhdi() int countRowSelectedBins(const int*, const int, const int, const int) const; -inline float getInverseZCoordinate(const int layerIndex) + GPUhdi() int getNzBins() const { return mNzBins; } + GPUhdi() int getNphiBins() const { return mNphiBins; } + GPUhdi() float getLayerZ(int i) const { return mLayerZ[i]; } + + private: + int mNzBins = 0; + int mNphiBins = 0; + float mInversePhiBinSize = 0.f; + std::vector<float> mLayerZ; + std::vector<float> mInverseZBinSize; +}; + +template <class T> +inline void IndexTableUtils::setTrackingParameters(const T& params) +{ + mInversePhiBinSize = params.PhiBins / constants::math::TwoPi; + mInverseZBinSize.resize(params.LayerZ.size()); + mNzBins = params.ZBins; + mNphiBins = params.PhiBins; + mLayerZ = params.LayerZ; + for (unsigned int iL{0}; iL < mInverseZBinSize.size(); ++iL) { + mInverseZBinSize[iL] = 0.5f * params.ZBins / params.LayerZ[iL]; + } +} + +inline float IndexTableUtils::getInverseZCoordinate(const int layerIndex) const { - return 0.5f * constants::index_table::ZBins / constants::its::LayersZCoordinate()[layerIndex]; + return 0.5f * mNzBins / mLayerZ[layerIndex]; } -GPUhdi() int index_table_utils::getZBinIndex(const int layerIndex, const float zCoordinate) +GPUhdi() int IndexTableUtils::getZBinIndex(const int layerIndex, const float zCoordinate) const { - return (zCoordinate + constants::its::LayersZCoordinate()[layerIndex]) * - constants::index_table::InverseZBinSize()[layerIndex]; + return (zCoordinate + mLayerZ[layerIndex]) * mInverseZBinSize[layerIndex]; } -GPUhdi() int index_table_utils::getPhiBinIndex(const float currentPhi) +GPUhdi() int IndexTableUtils::getPhiBinIndex(const float currentPhi) const { - return (currentPhi * constants::index_table::InversePhiBinSize); + return (currentPhi * mInversePhiBinSize); } -GPUhdi() int index_table_utils::getBinIndex(const int zIndex, const int phiIndex) +GPUhdi() int IndexTableUtils::getBinIndex(const int zIndex, const int phiIndex) const { - return gpu::GPUCommonMath::Min(phiIndex * constants::index_table::ZBins + zIndex, - constants::index_table::ZBins * constants::index_table::PhiBins - 1); + return o2::gpu::GPUCommonMath::Min(phiIndex * mNzBins + zIndex, mNzBins * mNphiBins - 1); } -GPUhdi() int index_table_utils::countRowSelectedBins( - const GPUArray<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>& indexTable, - const int phiBinIndex, const int minZBinIndex, const int maxZBinIndex) +GPUhdi() int IndexTableUtils::countRowSelectedBins(const int* indexTable, const int phiBinIndex, + const int minZBinIndex, const int maxZBinIndex) const { const int firstBinIndex{getBinIndex(minZBinIndex, phiBinIndex)}; const int maxBinIndex{firstBinIndex + maxZBinIndex - minZBinIndex + 1}; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Label.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Label.h index 90c9031d17261..ec45e6587a974 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Label.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Label.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,7 @@ struct Label final { int monteCarloId; float transverseMomentum; - float phiCoordinate; + float phi; float pseudorapidity; int pdgCode; int numberOfClusters; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h index 8e8df9e9c7a74..b9a2b599f0ba8 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,9 +35,9 @@ namespace its namespace math_utils { -GPUhdni() float calculatePhiCoordinate(const float, const float); -GPUhdni() float calculateRCoordinate(const float, const float); -GPUhdni() constexpr float getNormalizedPhiCoordinate(const float); +GPUhdni() float computePhi(const float, const float); +GPUhdni() float hypot(const float, const float); +GPUhdni() constexpr float getNormalizedPhi(const float); GPUhdni() constexpr float3 crossProduct(const float3&, const float3&); GPUhdni() float computeCurvature(float x1, float y1, float x2, float y2, float x3, float y3); GPUhdni() float computeCurvatureCentreX(float x1, float y1, float x2, float y2, float x3, float y3); @@ -44,22 +45,21 @@ GPUhdni() float computeTanDipAngle(float x1, float y1, float x2, float y2, float } // namespace math_utils -GPUhdi() float math_utils::calculatePhiCoordinate(const float xCoordinate, const float yCoordinate) +GPUhdi() float math_utils::computePhi(const float x, const float y) { //return o2::gpu::CAMath::ATan2(-yCoordinate, -xCoordinate) + constants::math::Pi; - return o2::math_utils::fastATan2(-yCoordinate, -xCoordinate) + constants::math::Pi; + return o2::math_utils::fastATan2(-y, -x) + constants::math::Pi; } -GPUhdi() float math_utils::calculateRCoordinate(const float xCoordinate, const float yCoordinate) +GPUhdi() float math_utils::hypot(const float x, const float y) { - return o2::gpu::CAMath::Sqrt(xCoordinate * xCoordinate + yCoordinate * yCoordinate); + return o2::gpu::CAMath::Sqrt(x * x + y * y); } -GPUhdi() constexpr float math_utils::getNormalizedPhiCoordinate(const float phiCoordinate) +GPUhdi() constexpr float math_utils::getNormalizedPhi(const float phi) { - return (phiCoordinate < 0) - ? phiCoordinate + constants::math::TwoPi - : (phiCoordinate > constants::math::TwoPi) ? phiCoordinate - constants::math::TwoPi : phiCoordinate; + return (phi < 0) ? phi + constants::math::TwoPi : (phi > constants::math::TwoPi) ? phi - constants::math::TwoPi + : phi; } GPUhdi() constexpr float3 math_utils::crossProduct(const float3& firstVector, const float3& secondVector) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h index 3c363c4d7219f..4338e08609cfa 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,7 @@ #include "ITStracking/Configuration.h" #include "ITStracking/Constants.h" #include "ITStracking/Definitions.h" +#include "ITStracking/IndexTableUtils.h" #include "ITStracking/Road.h" #include "ITStracking/Tracklet.h" @@ -42,99 +44,55 @@ class PrimaryVertexContext PrimaryVertexContext(const PrimaryVertexContext&) = delete; PrimaryVertexContext& operator=(const PrimaryVertexContext&) = delete; - virtual void initialise(const MemoryParameters& memParam, const std::array<std::vector<Cluster>, constants::its::LayersNumber>& cl, - const std::array<float, 3>& pv, const int iteration); - const float3& getPrimaryVertex() const; - std::array<std::vector<Cluster>, constants::its::LayersNumber>& getClusters(); - std::array<std::vector<Cell>, constants::its::CellsPerRoad>& getCells(); - std::array<std::vector<int>, constants::its::CellsPerRoad - 1>& getCellsLookupTable(); - std::array<std::vector<std::vector<int>>, constants::its::CellsPerRoad - 1>& getCellsNeighbours(); - std::vector<Road>& getRoads(); + virtual void initialise(const MemoryParameters& memParam, const TrackingParameters& trkParam, + const std::vector<std::vector<Cluster>>& cl, const std::array<float, 3>& pv, const int iteration); + const float3& getPrimaryVertex() const { return mPrimaryVertex; } + auto& getClusters() { return mClusters; } + auto& getCells() { return mCells; } + auto& getCellsLookupTable() { return mCellsLookupTable; } + auto& getCellsNeighbours() { return mCellsNeighbours; } + auto& getRoads() { return mRoads; } float getMinR(int layer) { return mMinR[layer]; } float getMaxR(int layer) { return mMaxR[layer]; } - bool isClusterUsed(int layer, int clusterId) const; + bool isClusterUsed(int layer, int clusterId) const { return mUsedClusters[layer][clusterId]; } void markUsedCluster(int layer, int clusterId); - std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::TrackletsPerRoad>& - getIndexTables(); - std::array<std::vector<Tracklet>, constants::its::TrackletsPerRoad>& getTracklets(); - std::array<std::vector<int>, constants::its::CellsPerRoad>& getTrackletsLookupTable(); + auto& getIndexTables() { return mIndexTables; } + auto& getTracklets() { return mTracklets; } + auto& getTrackletsLookupTable() { return mTrackletsLookupTable; } void initialiseRoadLabels(); void setRoadLabel(int i, const unsigned long long& lab, bool fake); const unsigned long long& getRoadLabel(int i) const; bool isRoadFake(int i) const; + IndexTableUtils mIndexTableUtils; + protected: float3 mPrimaryVertex; - std::array<float, constants::its::LayersNumber> mMinR; - std::array<float, constants::its::LayersNumber> mMaxR; - std::array<std::vector<Cluster>, constants::its::LayersNumber> mUnsortedClusters; - std::array<std::vector<Cluster>, constants::its::LayersNumber> mClusters; - std::array<std::vector<bool>, constants::its::LayersNumber> mUsedClusters; - std::array<std::vector<Cell>, constants::its::CellsPerRoad> mCells; - std::array<std::vector<int>, constants::its::CellsPerRoad - 1> mCellsLookupTable; - std::array<std::vector<std::vector<int>>, constants::its::CellsPerRoad - 1> mCellsNeighbours; + std::vector<float> mMinR; + std::vector<float> mMaxR; + std::vector<std::vector<Cluster>> mClusters; + std::vector<std::vector<bool>> mUsedClusters; + std::vector<std::vector<Cell>> mCells; + std::vector<std::vector<int>> mCellsLookupTable; + std::vector<std::vector<std::vector<int>>> mCellsNeighbours; std::vector<Road> mRoads; - std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::TrackletsPerRoad> - mIndexTables; - std::array<std::vector<Tracklet>, constants::its::TrackletsPerRoad> mTracklets; - std::array<std::vector<int>, constants::its::CellsPerRoad> mTrackletsLookupTable; + // std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, + // constants::its::TrackletsPerRoad> + std::vector<std::vector<int>> mIndexTables; + std::vector<std::vector<Tracklet>> mTracklets; + std::vector<std::vector<int>> mTrackletsLookupTable; std::vector<std::pair<unsigned long long, bool>> mRoadLabels; }; -inline const float3& PrimaryVertexContext::getPrimaryVertex() const { return mPrimaryVertex; } - -inline std::array<std::vector<Cluster>, constants::its::LayersNumber>& PrimaryVertexContext::getClusters() -{ - return mClusters; -} - -inline std::array<std::vector<Cell>, constants::its::CellsPerRoad>& PrimaryVertexContext::getCells() { return mCells; } - -inline std::array<std::vector<int>, constants::its::CellsPerRoad - 1>& PrimaryVertexContext::getCellsLookupTable() -{ - return mCellsLookupTable; -} - -inline std::array<std::vector<std::vector<int>>, constants::its::CellsPerRoad - 1>& - PrimaryVertexContext::getCellsNeighbours() -{ - return mCellsNeighbours; -} - -inline std::vector<Road>& PrimaryVertexContext::getRoads() { return mRoads; } - -inline bool PrimaryVertexContext::isClusterUsed(int layer, int clusterId) const -{ - return mUsedClusters[layer][clusterId]; -} inline void PrimaryVertexContext::markUsedCluster(int layer, int clusterId) { mUsedClusters[layer][clusterId] = true; } -inline std::array<std::array<int, constants::index_table::ZBins * constants::index_table::PhiBins + 1>, - constants::its::TrackletsPerRoad>& - PrimaryVertexContext::getIndexTables() -{ - return mIndexTables; -} - -inline std::array<std::vector<Tracklet>, constants::its::TrackletsPerRoad>& PrimaryVertexContext::getTracklets() -{ - return mTracklets; -} - -inline std::array<std::vector<int>, constants::its::CellsPerRoad>& PrimaryVertexContext::getTrackletsLookupTable() -{ - return mTrackletsLookupTable; -} - inline void PrimaryVertexContext::initialiseRoadLabels() { mRoadLabels.clear(); diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h index 99c1578540e4d..a39ee1b96c72a 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; class ROframe final { public: - ROframe(int ROframeId); + ROframe(int ROframeId, int nLayers); int getROFrameId() const; const float3& getPrimaryVertex(const int) const; int getPrimaryVerticesNum() const; @@ -49,14 +50,16 @@ class ROframe final int getTotalClusters() const; bool empty() const; - const std::array<std::vector<Cluster>, constants::its::LayersNumber>& getClusters() const; + const auto& getClusters() const { return mClusters; } const std::vector<Cluster>& getClustersOnLayer(int layerId) const; const std::vector<TrackingFrameInfo>& getTrackingFrameInfoOnLayer(int layerId) const; - const std::array<std::vector<TrackingFrameInfo>, constants::its::LayersNumber>& getTrackingFrameInfo() const; + const auto& getTrackingFrameInfo() const { return mTrackingFrameInfo; } const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; - const MCCompLabel& getClusterLabels(int layerId, const Cluster& cl) const; - const MCCompLabel& getClusterLabels(int layerId, const int clId) const; + const MCCompLabel& getClusterFirstLabel(int layerId, const Cluster& cl) const; + const MCCompLabel& getClusterFirstLabel(int layerId, const int clId) const; + gsl::span<o2::MCCompLabel> getClusterLabels(int layerId, const int clId) const; + gsl::span<o2::MCCompLabel> getClusterLabels(int layerId, const Cluster& cl) const; int getClusterExternalIndex(int layerId, const int clId) const; std::vector<int> getTracksId(const int layerId, const std::vector<Cluster>& cl); @@ -64,7 +67,7 @@ class ROframe final void addClusterToLayer(int layer, T&&... args); template <typename... T> void addTrackingFrameInfoToLayer(int layer, T&&... args); - void addClusterLabelToLayer(int layer, const MCCompLabel label); + void setMClabelsContainer(const dataformats::MCTruthContainer<MCCompLabel>* ptr); void addClusterExternalIndexToLayer(int layer, const int idx); bool hasMCinformation() const; @@ -72,11 +75,11 @@ class ROframe final private: const int mROframeId; + o2::dataformats::MCTruthContainer<MCCompLabel>* mMClabels = nullptr; std::vector<float3> mPrimaryVertices; - std::array<std::vector<Cluster>, constants::its::LayersNumber> mClusters; - std::array<std::vector<TrackingFrameInfo>, constants::its::LayersNumber> mTrackingFrameInfo; - std::array<std::vector<MCCompLabel>, constants::its::LayersNumber> mClusterLabels; - std::array<std::vector<int>, constants::its::LayersNumber> mClusterExternalIndices; + std::vector<std::vector<Cluster>> mClusters; + std::vector<std::vector<TrackingFrameInfo>> mTrackingFrameInfo; + std::vector<std::vector<int>> mClusterExternalIndices; }; inline int ROframe::getROFrameId() const { return mROframeId; } @@ -87,11 +90,6 @@ inline int ROframe::getPrimaryVerticesNum() const { return mPrimaryVertices.size inline bool ROframe::empty() const { return getTotalClusters() == 0; } -inline const std::array<std::vector<Cluster>, constants::its::LayersNumber>& ROframe::getClusters() const -{ - return mClusters; -} - inline const std::vector<Cluster>& ROframe::getClustersOnLayer(int layerId) const { return mClusters[layerId]; @@ -102,24 +100,29 @@ inline const std::vector<TrackingFrameInfo>& ROframe::getTrackingFrameInfoOnLaye return mTrackingFrameInfo[layerId]; } -inline const std::array<std::vector<TrackingFrameInfo>, constants::its::LayersNumber>& ROframe::getTrackingFrameInfo() const +inline const TrackingFrameInfo& ROframe::getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const { - return mTrackingFrameInfo; + return mTrackingFrameInfo[layerId][cl.clusterId]; } -inline const TrackingFrameInfo& ROframe::getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const +inline const MCCompLabel& ROframe::getClusterFirstLabel(int layerId, const Cluster& cl) const { - return mTrackingFrameInfo[layerId][cl.clusterId]; + return getClusterFirstLabel(layerId, cl.clusterId); } -inline const MCCompLabel& ROframe::getClusterLabels(int layerId, const Cluster& cl) const +inline const MCCompLabel& ROframe::getClusterFirstLabel(int layerId, const int clId) const { - return mClusterLabels[layerId][cl.clusterId]; + return *(mMClabels->getLabels(getClusterExternalIndex(layerId, clId)).begin()); } -inline const MCCompLabel& ROframe::getClusterLabels(int layerId, const int clId) const +inline gsl::span<o2::MCCompLabel> ROframe::getClusterLabels(int layerId, const int clId) const { - return mClusterLabels[layerId][clId]; + return mMClabels->getLabels(getClusterExternalIndex(layerId, clId)); +} + +inline gsl::span<o2::MCCompLabel> ROframe::getClusterLabels(int layerId, const Cluster& cl) const +{ + return getClusterLabels(layerId, cl.clusterId); } inline int ROframe::getClusterExternalIndex(int layerId, const int clId) const @@ -131,7 +134,7 @@ inline std::vector<int> ROframe::getTracksId(const int layerId, const std::vecto { std::vector<int> tracksId; for (auto& cluster : cl) { - tracksId.push_back(getClusterLabels(layerId, cluster).isNoise() ? -1 : getClusterLabels(layerId, cluster).getTrackID()); + tracksId.push_back(getClusterFirstLabel(layerId, cluster).isNoise() ? -1 : getClusterFirstLabel(layerId, cluster).getTrackID()); } return tracksId; } @@ -148,7 +151,10 @@ void ROframe::addTrackingFrameInfoToLayer(int layer, T&&... values) mTrackingFrameInfo[layer].emplace_back(std::forward<T>(values)...); } -inline void ROframe::addClusterLabelToLayer(int layer, const MCCompLabel label) { mClusterLabels[layer].emplace_back(label); } +inline void ROframe::setMClabelsContainer(const dataformats::MCTruthContainer<MCCompLabel>* ptr) +{ + mMClabels = const_cast<dataformats::MCTruthContainer<MCCompLabel>*>(ptr); +} inline void ROframe::addClusterExternalIndexToLayer(int layer, const int idx) { @@ -157,23 +163,25 @@ inline void ROframe::addClusterExternalIndexToLayer(int layer, const int idx) inline void ROframe::clear() { - for (int iL = 0; iL < constants::its::LayersNumber; ++iL) { + for (unsigned int iL = 0; iL < mClusters.size(); ++iL) { mClusters[iL].clear(); mTrackingFrameInfo[iL].clear(); - mClusterLabels[iL].clear(); + // mClusterLabels[iL].clear(); mClusterExternalIndices[iL].clear(); } mPrimaryVertices.clear(); + mMClabels = nullptr; } inline bool ROframe::hasMCinformation() const { - for (const auto& vect : mClusterLabels) { - if (!vect.empty()) { - return true; - } - } - return false; + // for (const auto& vect : mClusterLabels) { + // if (!vect.empty()) { + // return true; + // } + // } + // return false; + return mMClabels; } } // namespace its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h index 9650eb9fa9ab7..ceb799cc82899 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,8 +44,10 @@ class Road final void resetRoad(); void addCell(int, int); + static constexpr int mMaxRoadSize = 13; + private: - int mCellIds[constants::its::CellsPerRoad]; + int mCellIds[mMaxRoadSize]; int mRoadSize; int mLabel; bool mIsFakeRoad; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h new file mode 100644 index 0000000000000..e83251e368bd2 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file Smoother.h +/// \brief Class to handle Kalman smoothing for ITS tracking. +/// Its instance stores the state of the track to the level we want to smooth to avoid multiple re-propagations when testing different clusters. +/// + +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsITS/TrackITS.h" +#include "DetectorsBase/Propagator.h" +#include "ITStracking/ROframe.h" + +#if defined(CA_DEBUG) || defined(CA_STANDALONE_DEBUGGER) +#include "ITStracking/StandaloneDebugger.h" +#endif + +namespace o2 +{ +namespace its +{ + +template <unsigned int D> +class Smoother +{ + public: + Smoother(TrackITSExt& track, int layer, const ROframe& event, float bZ, o2::base::PropagatorF::MatCorrType corr); + ~Smoother(); + + bool isValidInit() const + { + return mInitStatus; + } + bool testCluster(const int clusterId, const ROframe& event); + bool getSmoothedTrack(); + float getChi2() const { return mBestChi2; } + float getLastChi2() const { return mLastChi2; } + + private: + float computeSmoothedPredictedChi2(const o2::track::TrackParCov& outwTrack, + const o2::track::TrackParCov& inwTrack, + const std::array<float, 2>& cls, + const std::array<float, 3>& clCov); + bool smoothTrack(); + + private: + int mLayerToSmooth; // Layer to compute smoothing optimization + float mBz; // Magnetic field along Z + bool mInitStatus; // State after the initialization + o2::base::PropagatorF::MatCorrType mCorr; // Type of correction to use + TrackITSExt mInwardsTrack; // outwards track: from innermost cluster to outermost + TrackITSExt mOutwardsTrack; // inwards track: from outermost cluster to innermost + float mBestChi2; // Best value of local smoothed chi2 + float mLastChi2 = 1e8; // Latest computed chi2 + +#if defined(CA_DEBUG) || defined(CA_STANDALONE_DEBUGGER) + StandaloneDebugger* mDebugger; +#endif +}; +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/StandaloneDebugger.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/StandaloneDebugger.h index 6693d13f93d90..c89fe704dfbe2 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/StandaloneDebugger.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/StandaloneDebugger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,11 +16,20 @@ #ifndef O2_ITS_STANDALONE_DEBUGGER_H_ #define O2_ITS_STANDALONE_DEBUGGER_H_ +#include <string> +#include <iterator> + +// Tracker +#if !defined(__CUDACC__) && !defined(__HIPCC__) +#include "ITStracking/ROframe.h" +#endif + +#include "DataFormatsITS/TrackITS.h" +#include "ITStracking/PrimaryVertexContext.h" + namespace o2 { -class MCCompLabel; - namespace utils { class TreeStreamRedirector; @@ -30,6 +40,95 @@ namespace its class Tracklet; class Line; class ROframe; +class ClusterLines; + +using constants::its::UnusedIndex; + +#if !defined(__CUDACC__) && !defined(__HIPCC__) +template <int numClusters = TrackITSExt::MaxClusters> +struct FakeTrackInfo { + public: + FakeTrackInfo(); + FakeTrackInfo(PrimaryVertexContext* pvc, const ROframe& event, TrackITSExt& track, bool storeClusters) : isFake{false}, isAmbiguousId{false}, mainLabel{UnusedIndex, UnusedIndex, UnusedIndex, false} + { + occurrences.clear(); + for (auto& c : clusStatuses) { + c = -1; + } + for (size_t iCluster{0}; iCluster < numClusters; ++iCluster) { + int extIndex = track.getClusterIndex(iCluster); + if (extIndex == -1) { + continue; + } + o2::MCCompLabel mcLabel = *(event.getClusterLabels(iCluster, extIndex).begin()); + bool found = false; + + for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { + std::pair<o2::MCCompLabel, int>& occurrence = occurrences[iOcc]; + if (mcLabel == occurrence.first) { + ++occurrence.second; + found = true; + break; + } + } + if (!found) { + occurrences.emplace_back(mcLabel, 1); + } + } + + if (occurrences.size() > 1) { + isFake = true; + } + std::sort(std::begin(occurrences), std::end(occurrences), [](auto e1, auto e2) { + return e1.second > e2.second; + }); + mainLabel = occurrences[0].first; + + for (size_t iOcc{1}; iOcc < occurrences.size(); ++iOcc) { + if (occurrences[iOcc].second == occurrences[0].second) { + isAmbiguousId = true; + break; + } + } + + for (size_t iCluster{0}; iCluster < numClusters; ++iCluster) { + int extIndex = track.getClusterIndex(iCluster); + if (extIndex == -1) { + continue; + } + o2::MCCompLabel lbl = *(event.getClusterLabels(iCluster, extIndex).begin()); + if (lbl == mainLabel && occurrences[0].second > 1 && !lbl.isNoise()) { // if we have MaxClusters fake clusters -> occurrences[0].second = 1 + clusStatuses[iCluster] = 1; + } else { + clusStatuses[iCluster] = 0; + ++nFakeClusters; + } + } + if (storeClusters) { + for (auto iCluster{0}; iCluster < numClusters; ++iCluster) { + const int index = track.getClusterIndex(iCluster); + if (index != constants::its::UnusedIndex) { + clusters[iCluster] = pvc->getClusters()[iCluster][index]; + trackingFrameInfos[iCluster] = event.getTrackingFrameInfoOnLayer(iCluster).at(index); + } + } + } + } + + // Data + std::vector<std::pair<MCCompLabel, int>> + occurrences; + MCCompLabel mainLabel; + std::array<int, numClusters> clusStatuses; + std::array<o2::its::Cluster, numClusters> clusters; + std::array<o2::its::TrackingFrameInfo, numClusters> trackingFrameInfos; + + bool isFake; + bool isAmbiguousId; + int nFakeClusters = 0; + ClassDefNV(FakeTrackInfo, 1); +}; // namespace its +#endif class StandaloneDebugger { @@ -59,6 +158,9 @@ class StandaloneDebugger void fillXYZHistogramTree(std::array<std::vector<int>, 3>, const std::array<int, 3>); void fillVerticesInfoTree(float x, float y, float z, int size, int rId, int eId, float pur); + // Tracker debug utilities + void dumpTrackToBranchWithInfo(std::string branchName, o2::its::TrackITSExt track, const ROframe event, PrimaryVertexContext* pvc, const bool dumpClusters = false); + static int getBinIndex(const float, const int, const float, const float); private: diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h new file mode 100644 index 0000000000000..3c65dafa45ce6 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -0,0 +1,360 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TimeFrame.h +/// \brief +/// + +#ifndef TRACKINGITSU_INCLUDE_TIMEFRAME_H_ +#define TRACKINGITSU_INCLUDE_TIMEFRAME_H_ + +#include <array> +#include <vector> +#include <utility> +#include <cassert> +#include <gsl/gsl> + +#include "DataFormatsITS/TrackITS.h" + +#include "ITStracking/Cell.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/Constants.h" +#include "ITStracking/Definitions.h" +#include "ITStracking/Road.h" +#include "ITStracking/Tracklet.h" +#include "ITStracking/IndexTableUtils.h" + +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +#include "ReconstructionDataFormats/Vertex.h" + +namespace o2 +{ + +namespace itsmft +{ +class Cluster; +class CompClusterExt; +class TopologyDictionary; +class ROFRecord; +} // namespace itsmft + +namespace its +{ + +using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; + +class TimeFrame final +{ + public: + TimeFrame(int nLayers = 7); + const Vertex& getPrimaryVertex(const int) const; + gsl::span<const Vertex> getPrimaryVertices(int tf) const; + gsl::span<const Vertex> getPrimaryVertices(int romin, int romax) const; + int getPrimaryVerticesNum(int rofID = -1) const; + void addPrimaryVertices(const std::vector<Vertex>& vertices); + int loadROFrameData(const o2::itsmft::ROFRecord& rof, gsl::span<const itsmft::Cluster> clusters, + const dataformats::MCTruthContainer<MCCompLabel>* mcLabels = nullptr); + + int loadROFrameData(gsl::span<o2::itsmft::ROFRecord> rofs, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, + const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* mcLabels = nullptr); + int getTotalClusters() const; + bool empty() const; + + int getSortedIndex(int rof, int layer, int i) const; + int getNrof() const; + float getBeamX() const; + float getBeamY() const; + + float getMinR(int layer) const { return mMinR[layer]; } + float getMaxR(int layer) const { return mMaxR[layer]; } + + gsl::span<Cluster> getClustersOnLayer(int rofId, int layerId); + gsl::span<const Cluster> getClustersOnLayer(int rofId, int layerId) const; + gsl::span<const Cluster> getUnsortedClustersOnLayer(int rofId, int layerId) const; + index_table_t& getIndexTables(int tf); + const std::vector<TrackingFrameInfo>& getTrackingFrameInfoOnLayer(int layerId) const; + + const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; + const gsl::span<const MCCompLabel> getClusterLabels(int layerId, const Cluster& cl) const; + const gsl::span<const MCCompLabel> getClusterLabels(int layerId, const int clId) const; + int getClusterExternalIndex(int layerId, const int clId) const; + + std::vector<MCCompLabel>& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } + std::vector<MCCompLabel>& getCellsLabel(int layer) { return mCellLabels[layer]; } + + bool hasMCinformation() const; + void initialise(const int iteration, const MemoryParameters& memParam, const TrackingParameters& trkParam); + + bool isClusterUsed(int layer, int clusterId) const; + void markUsedCluster(int layer, int clusterId); + + std::vector<std::vector<Tracklet>>& getTracklets(); + std::vector<std::vector<int>>& getTrackletsLookupTable(); + + std::vector<std::vector<Cluster>>& getClusters(); + std::vector<std::vector<Cluster>>& getUnsortedClusters(); + int getClusterROF(int iLayer, int iCluster); + std::vector<std::vector<Cell>>& getCells(); + std::vector<std::vector<int>>& getCellsLookupTable(); + std::vector<std::vector<std::vector<int>>>& getCellsNeighbours(); + std::vector<Road>& getRoads(); + std::vector<TrackITSExt>& getTracks(int rof) { return mTracks[rof]; } + std::vector<MCCompLabel>& getTracksLabel(int rof) { return mTracksLabel[rof]; } + + void initialiseRoadLabels(); + void setRoadLabel(int i, const unsigned long long& lab, bool fake); + const unsigned long long& getRoadLabel(int i) const; + bool isRoadFake(int i) const; + + void clear(); + + /// Debug and printing + void checkTrackletLUTs(); + void printROFoffsets(); + void printVertices(); + void printTrackletLUTonLayer(int i); + void printCellLUTonLayer(int i); + void printTrackletLUTs(); + void printCellLUTs(); + + IndexTableUtils mIndexTableUtils; + + private: + template <typename... T> + void addClusterToLayer(int layer, T&&... args); + template <typename... T> + void addTrackingFrameInfoToLayer(int layer, T&&... args); + void addClusterExternalIndexToLayer(int layer, const int idx); + + int mNrof = 0; + int mBeamPosWeight = 0; + float mBeamPos[2] = {0.f, 0.f}; + std::vector<float> mMinR; + std::vector<float> mMaxR; + std::vector<int> mROframesPV = {0}; + std::vector<std::vector<int>> mROframesClusters; + std::vector<Vertex> mPrimaryVertices; + std::vector<std::vector<Cluster>> mClusters; + std::vector<std::vector<Cluster>> mUnsortedClusters; + std::vector<std::vector<bool>> mUsedClusters; + std::vector<std::vector<TrackingFrameInfo>> mTrackingFrameInfo; + const dataformats::MCTruthContainer<MCCompLabel>* mClusterLabels = nullptr; + std::vector<std::vector<MCCompLabel>> mTrackletLabels; + std::vector<std::vector<MCCompLabel>> mCellLabels; + std::vector<std::vector<int>> mClusterExternalIndices; + std::vector<std::vector<Cell>> mCells; + std::vector<std::vector<int>> mCellsLookupTable; + std::vector<std::vector<std::vector<int>>> mCellsNeighbours; + std::vector<Road> mRoads; + std::vector<std::vector<MCCompLabel>> mTracksLabel; + std::vector<std::vector<TrackITSExt>> mTracks; + + std::vector<index_table_t> mIndexTables; + std::vector<std::vector<Tracklet>> mTracklets; + std::vector<std::vector<int>> mTrackletsLookupTable; + + std::vector<std::pair<unsigned long long, bool>> mRoadLabels; +}; + +inline const Vertex& TimeFrame::getPrimaryVertex(const int vertexIndex) const { return mPrimaryVertices[vertexIndex]; } + +inline gsl::span<const Vertex> TimeFrame::getPrimaryVertices(int tf) const +{ + const int start = mROframesPV[tf]; + const int stop = tf >= mNrof - 1 ? mNrof : tf + 1; + return {&mPrimaryVertices[start], static_cast<gsl::span<const Vertex>::size_type>(mROframesPV[stop] - mROframesPV[tf])}; +} + +inline gsl::span<const Vertex> TimeFrame::getPrimaryVertices(int romin, int romax) const +{ + return {&mPrimaryVertices[mROframesPV[romin]], static_cast<gsl::span<const Vertex>::size_type>(mROframesPV[romax + 1] - mROframesPV[romin])}; +} + +inline int TimeFrame::getPrimaryVerticesNum(int rofID) const +{ + return rofID < 0 ? mPrimaryVertices.size() : mROframesPV[rofID + 1] - mROframesPV[rofID]; +} + +inline bool TimeFrame::empty() const { return getTotalClusters() == 0; } + +inline int TimeFrame::getSortedIndex(int rof, int layer, int index) const { return mROframesClusters[layer][rof] + index; } + +inline int TimeFrame::getNrof() const { return mNrof; }; + +inline float TimeFrame::getBeamX() const { return mBeamPos[0]; } + +inline float TimeFrame::getBeamY() const { return mBeamPos[1]; } + +inline gsl::span<Cluster> TimeFrame::getClustersOnLayer(int rofId, int layerId) +{ + if (rofId < 0 || rofId >= mNrof) { + return gsl::span<Cluster>(); + } + int startIdx{mROframesClusters[layerId][rofId]}; + return {&mClusters[layerId][startIdx], static_cast<gsl::span<Cluster>::size_type>(mROframesClusters[layerId][rofId + 1] - startIdx)}; +} + +inline gsl::span<const Cluster> TimeFrame::getClustersOnLayer(int rofId, int layerId) const +{ + if (rofId < 0 || rofId >= mNrof) { + return gsl::span<const Cluster>(); + } + int startIdx{mROframesClusters[layerId][rofId]}; + return {&mClusters[layerId][startIdx], static_cast<gsl::span<Cluster>::size_type>(mROframesClusters[layerId][rofId + 1] - startIdx)}; +} + +inline int TimeFrame::getClusterROF(int iLayer, int iCluster) +{ + return std::lower_bound(mROframesClusters[iLayer].begin(), mROframesClusters[iLayer].end(), iCluster + 1) - mROframesClusters[iLayer].begin() - 1; +} + +inline gsl::span<const Cluster> TimeFrame::getUnsortedClustersOnLayer(int rofId, int layerId) const +{ + if (rofId < 0 || rofId >= mNrof) { + return gsl::span<const Cluster>(); + } + int startIdx{mROframesClusters[layerId][rofId]}; + return {&mUnsortedClusters[layerId][startIdx], static_cast<gsl::span<Cluster>::size_type>(mROframesClusters[layerId][rofId + 1] - startIdx)}; +} + +inline const std::vector<TrackingFrameInfo>& TimeFrame::getTrackingFrameInfoOnLayer(int layerId) const +{ + return mTrackingFrameInfo[layerId]; +} + +inline const TrackingFrameInfo& TimeFrame::getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const +{ + return mTrackingFrameInfo[layerId][cl.clusterId]; +} + +inline const gsl::span<const MCCompLabel> TimeFrame::getClusterLabels(int layerId, const Cluster& cl) const +{ + return getClusterLabels(layerId, cl.clusterId); +} + +inline const gsl::span<const MCCompLabel> TimeFrame::getClusterLabels(int layerId, int clId) const +{ + return mClusterLabels->getLabels(mClusterExternalIndices[layerId][clId]); +} + +inline int TimeFrame::getClusterExternalIndex(int layerId, const int clId) const +{ + return mClusterExternalIndices[layerId][clId]; +} + +inline index_table_t& TimeFrame::getIndexTables(int tf) +{ + return mIndexTables[tf]; +} + +template <typename... T> +void TimeFrame::addClusterToLayer(int layer, T&&... values) +{ + mUnsortedClusters[layer].emplace_back(std::forward<T>(values)...); +} + +template <typename... T> +void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) +{ + mTrackingFrameInfo[layer].emplace_back(std::forward<T>(values)...); +} + +inline void TimeFrame::addClusterExternalIndexToLayer(int layer, const int idx) +{ + mClusterExternalIndices[layer].push_back(idx); +} + +inline void TimeFrame::clear() +{ + for (unsigned int iL = 0; iL < mClusters.size(); ++iL) { + mClusters[iL].clear(); + mTrackingFrameInfo[iL].clear(); + mClusterExternalIndices[iL].clear(); + } + mClusterLabels = nullptr; + mPrimaryVertices.clear(); +} + +inline bool TimeFrame::hasMCinformation() const +{ + return mClusterLabels; +} + +inline bool TimeFrame::isClusterUsed(int layer, int clusterId) const +{ + return mUsedClusters[layer][clusterId]; +} + +inline void TimeFrame::markUsedCluster(int layer, int clusterId) { mUsedClusters[layer][clusterId] = true; } + +inline std::vector<std::vector<Tracklet>>& TimeFrame::getTracklets() +{ + return mTracklets; +} + +inline std::vector<std::vector<int>>& TimeFrame::getTrackletsLookupTable() +{ + return mTrackletsLookupTable; +} + +inline void TimeFrame::initialiseRoadLabels() +{ + mRoadLabels.clear(); + mRoadLabels.resize(mRoads.size()); +} + +inline void TimeFrame::setRoadLabel(int i, const unsigned long long& lab, bool fake) +{ + mRoadLabels[i].first = lab; + mRoadLabels[i].second = fake; +} + +inline const unsigned long long& TimeFrame::getRoadLabel(int i) const +{ + return mRoadLabels[i].first; +} + +inline bool TimeFrame::isRoadFake(int i) const +{ + return mRoadLabels[i].second; +} + +inline std::vector<std::vector<Cluster>>& TimeFrame::getClusters() +{ + return mClusters; +} + +inline std::vector<std::vector<Cluster>>& TimeFrame::getUnsortedClusters() +{ + return mUnsortedClusters; +} + +inline std::vector<std::vector<Cell>>& TimeFrame::getCells() { return mCells; } + +inline std::vector<std::vector<int>>& TimeFrame::getCellsLookupTable() +{ + return mCellsLookupTable; +} + +inline std::vector<std::vector<std::vector<int>>>& TimeFrame::getCellsNeighbours() +{ + return mCellsNeighbours; +} + +inline std::vector<Road>& TimeFrame::getRoads() { return mRoads; } + +} // namespace its +} // namespace o2 + +#endif /* TRACKINGITSU_INCLUDE_TimeFrame_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h index 920ac2f2ae949..1c4bb4f542c87 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,21 +24,28 @@ #include <iosfwd> #include <memory> #include <utility> +#include <sstream> #include "ITStracking/Configuration.h" +#include "DetectorsBase/MatLayerCylSet.h" +#include "CommonConstants/MathConstants.h" #include "ITStracking/Definitions.h" #include "ITStracking/ROframe.h" #include "ITStracking/MathUtils.h" -#include "ITStracking/PrimaryVertexContext.h" +#include "DetectorsBase/Propagator.h" +#include "ITStracking/TimeFrame.h" #include "ITStracking/Road.h" #include "DataFormatsITS/TrackITS.h" #include "SimulationDataFormat/MCCompLabel.h" -#include "Framework/Logger.h" +#ifdef CA_DEBUG +#include "ITStracking/StandaloneDebugger.h" +#endif namespace o2 { + namespace gpu { class GPUChainITS; @@ -45,7 +53,7 @@ class GPUChainITS; namespace its { -class PrimaryVertexContext; +class TimeFrame; class TrackerTraits; class Tracker @@ -61,46 +69,54 @@ class Tracker void setBz(float bz); float getBz() const; - std::vector<TrackITSExt>& getTracks(); - auto& getTrackLabels() { return mTrackLabels; } + void clustersToTracks(std::function<void(std::string s)> = [](std::string s) { std::cout << s << std::endl; }); + void setSmoothing(bool v) { mApplySmoothing = v; } + bool getSmoothing() const { return mApplySmoothing; } - void clustersToTracks(const ROframe&, std::ostream& = std::cout); + std::vector<TrackITSExt>& getTracks(); void setROFrame(std::uint32_t f) { mROFrame = f; } std::uint32_t getROFrame() const { return mROFrame; } + void setCorrType(const o2::base::PropagatorImpl<float>::MatCorrType& type) { mCorrType = type; } void setParameters(const std::vector<MemoryParameters>&, const std::vector<TrackingParameters>&); + void getGlobalConfiguration(); + bool isMatLUT() const { return o2::base::Propagator::Instance()->getMatLUT() && (mCorrType == o2::base::PropagatorImpl<float>::MatCorrType::USEMatCorrLUT); } private: track::TrackParCov buildTrackSeed(const Cluster& cluster1, const Cluster& cluster2, const Cluster& cluster3, const TrackingFrameInfo& tf3); template <typename... T> - void initialisePrimaryVertexContext(T&&... args); + void initialiseTimeFrame(T&&... args); void computeTracklets(); void computeCells(); void findCellsNeighbours(int& iteration); void findRoads(int& iteration); - void findTracks(const ROframe& ev); - bool fitTrack(const ROframe& event, TrackITSExt& track, int start, int end, int step); + void findTracks(); + bool fitTrack(TrackITSExt& track, int start, int end, int step, const float chi2cut = o2::constants::math::VeryBig, const float maxQoverPt = o2::constants::math::VeryBig); void traverseCellsTree(const int, const int); - void computeRoadsMClabels(const ROframe&); - void computeTracksMClabels(const ROframe&); - void rectifyClusterIndices(const ROframe& event); + void computeRoadsMClabels(); + void computeTracksMClabels(); + void rectifyClusterIndices(); template <typename... T> - float evaluateTask(void (Tracker::*)(T...), const char*, std::ostream& ostream, T&&... args); + float evaluateTask(void (Tracker::*)(T...), const char*, std::function<void(std::string s)> logger, T&&... args); TrackerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class - PrimaryVertexContext* mPrimaryVertexContext = nullptr; /// Observer pointer, not owned by this class + TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class std::vector<MemoryParameters> mMemParams; std::vector<TrackingParameters> mTrkParams; bool mCUDA = false; + bool mApplySmoothing = false; + o2::base::PropagatorImpl<float>::MatCorrType mCorrType = o2::base::PropagatorImpl<float>::MatCorrType::USEMatCorrLUT; float mBz = 5.f; std::uint32_t mROFrame = 0; - std::vector<TrackITSExt> mTracks; - std::vector<MCCompLabel> mTrackLabels; o2::gpu::GPUChainITS* mRecoChain = nullptr; + +#ifdef CA_DEBUG + StandaloneDebugger* mDebugger; +#endif }; inline void Tracker::setParameters(const std::vector<MemoryParameters>& memPars, const std::vector<TrackingParameters>& trkPars) @@ -120,18 +136,13 @@ inline void Tracker::setBz(float bz) } template <typename... T> -void Tracker::initialisePrimaryVertexContext(T&&... args) -{ - mPrimaryVertexContext->initialise(std::forward<T>(args)...); -} - -inline std::vector<TrackITSExt>& Tracker::getTracks() +void Tracker::initialiseTimeFrame(T&&... args) { - return mTracks; + mTimeFrame->initialise(std::forward<T>(args)...); } template <typename... T> -float Tracker::evaluateTask(void (Tracker::*task)(T...), const char* taskName, std::ostream& ostream, +float Tracker::evaluateTask(void (Tracker::*task)(T...), const char* taskName, std::function<void(std::string s)> logger, T&&... args) { float diff{0.f}; @@ -144,13 +155,13 @@ float Tracker::evaluateTask(void (Tracker::*task)(T...), const char* taskName, s std::chrono::duration<double, std::milli> diff_t{end - start}; diff = diff_t.count(); - if (fair::Logger::Logging(fair::Severity::info)) { - if (taskName == nullptr) { - ostream << diff << "\t"; - } else { - ostream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms" << std::endl; - } + std::stringstream sstream; + if (taskName == nullptr) { + sstream << diff << "\t"; + } else { + sstream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms"; } + logger(sstream.str()); } else { (this->*task)(std::forward<T>(args)...); } diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index 65500276c3374..504fad090f1c1 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ #include "ITStracking/Configuration.h" #include "ITStracking/Definitions.h" #include "ITStracking/MathUtils.h" -#include "ITStracking/PrimaryVertexContext.h" +#include "ITStracking/TimeFrame.h" #include "ITStracking/Road.h" namespace o2 @@ -41,15 +42,15 @@ namespace its { class TrackITSExt; -typedef std::function<int(o2::gpu::GPUChainITS&, std::vector<Road>& roads, std::array<const Cluster*, 7>, std::array<const Cell*, 5>, const std::array<std::vector<TrackingFrameInfo>, 7>&, std::vector<TrackITSExt>&)> FuncRunITSTrackFit_t; +typedef std::function<int(o2::gpu::GPUChainITS&, std::vector<Road>& roads, std::vector<const Cluster*>&, std::vector<const Cell*>&, const std::vector<std::vector<TrackingFrameInfo>>&, std::vector<TrackITSExt>&)> FuncRunITSTrackFit_t; class TrackerTraits { public: virtual ~TrackerTraits() = default; - GPU_HOST_DEVICE static constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - GPU_DEVICE static const int4 getBinsRect(const Cluster&, const int, const float, const float, float maxdeltaz, float maxdeltaphi); + GPUhd() static constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } + const int4 getBinsRect(const Cluster&, const int, const float, const float, float maxdeltaz, float maxdeltaphi); void SetRecoChain(o2::gpu::GPUChainITS* chain, FuncRunITSTrackFit_t&& funcRunITSTrackFit) { @@ -59,13 +60,13 @@ class TrackerTraits virtual void computeLayerTracklets(){}; virtual void computeLayerCells(){}; - virtual void refitTracks(const std::array<std::vector<TrackingFrameInfo>, 7>&, std::vector<TrackITSExt>&){}; + virtual void refitTracks(const std::vector<std::vector<TrackingFrameInfo>>&, std::vector<TrackITSExt>&){}; void UpdateTrackingParameters(const TrackingParameters& trkPar); - PrimaryVertexContext* getPrimaryVertexContext() { return mPrimaryVertexContext; } + TimeFrame* getTimeFrame() { return mTimeFrame; } protected: - PrimaryVertexContext* mPrimaryVertexContext; + TimeFrame* mTimeFrame; TrackingParameters mTrkParams; o2::gpu::GPUChainITS* mChain = nullptr; @@ -77,24 +78,25 @@ inline void TrackerTraits::UpdateTrackingParameters(const TrackingParameters& tr mTrkParams = trkPar; } -inline GPU_DEVICE const int4 TrackerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, - const float z1, const float z2, float maxdeltaz, float maxdeltaphi) +inline const int4 TrackerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, + const float z1, const float z2, float maxdeltaz, float maxdeltaphi) { - const float zRangeMin = gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; - const float phiRangeMin = currentCluster.phiCoordinate - maxdeltaphi; - const float zRangeMax = gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; - const float phiRangeMax = currentCluster.phiCoordinate + maxdeltaphi; + const float zRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; + const float phiRangeMin = currentCluster.phi - maxdeltaphi; + const float zRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; + const float phiRangeMax = currentCluster.phi + maxdeltaphi; - if (zRangeMax < -constants::its::LayersZCoordinate()[layerIndex + 1] || - zRangeMin > constants::its::LayersZCoordinate()[layerIndex + 1] || zRangeMin > zRangeMax) { + if (zRangeMax < -mTrkParams.LayerZ[layerIndex + 1] || + zRangeMin > mTrkParams.LayerZ[layerIndex + 1] || zRangeMin > zRangeMax) { return getEmptyBinsRect(); } - return int4{gpu::GPUCommonMath::Max(0, index_table_utils::getZBinIndex(layerIndex + 1, zRangeMin)), - index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phiRangeMin)), - gpu::GPUCommonMath::Min(constants::index_table::ZBins - 1, index_table_utils::getZBinIndex(layerIndex + 1, zRangeMax)), - index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phiRangeMax))}; + const IndexTableUtils& utils{mTimeFrame->mIndexTableUtils}; + return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex + 1, zRangeMin)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), + o2::gpu::GPUCommonMath::Min(mTrkParams.ZBins - 1, utils.getZBinIndex(layerIndex + 1, zRangeMax)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; } } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraitsCPU.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraitsCPU.h index 865ae121abe04..c6ef2e511e250 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraitsCPU.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraitsCPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ #include "ITStracking/Configuration.h" #include "ITStracking/Definitions.h" #include "ITStracking/MathUtils.h" -#include "ITStracking/PrimaryVertexContext.h" +#include "ITStracking/TimeFrame.h" #include "ITStracking/Road.h" namespace o2 @@ -39,12 +40,12 @@ namespace its class TrackerTraitsCPU : public TrackerTraits { public: - TrackerTraitsCPU() { mPrimaryVertexContext = new PrimaryVertexContext; } - ~TrackerTraitsCPU() override { delete mPrimaryVertexContext; } + TrackerTraitsCPU(TimeFrame* tf = nullptr) { mTimeFrame = tf; } //TODO: the TimeFrame pointer should be given by the tracker that is the external interface + ~TrackerTraitsCPU() override { delete mTimeFrame; } void computeLayerCells() final; void computeLayerTracklets() final; - void refitTracks(const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) final; + void refitTracks(const std::vector<std::vector<TrackingFrameInfo>>& tf, std::vector<TrackITSExt>& tracks) final; protected: std::vector<std::vector<Tracklet>> mTracklets; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h index eec5b41210e2b..e39e22b364197 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,6 @@ namespace o2 namespace its { -class VertexingParameters; struct VertexerParamConfig : public o2::conf::ConfigurableParamHelper<VertexerParamConfig> { // geometrical cuts @@ -36,7 +36,14 @@ struct VertexerParamConfig : public o2::conf::ConfigurableParamHelper<VertexerPa O2ParamDef(VertexerParamConfig, "ITSVertexerParam"); }; -// VertexerParamConfig VertexerParamConfig::sInstance; +struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper<TrackerParamConfig> { + + // Use TGeo for mat. budget + bool useMatCorrTGeo = false; + + O2ParamDef(TrackerParamConfig, "ITSCATrackerParam"); +}; + } // namespace its } // namespace o2 #endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h index e2b39b99efbe3..377ca7a6906f2 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,32 +28,34 @@ namespace its struct Tracklet final { Tracklet(); - GPUdi() Tracklet(const int, const int, const Cluster&, const Cluster&); + GPUdi() Tracklet(const int, const int, const Cluster&, const Cluster&, int rof0, int rof1); #ifdef _ALLOW_DEBUG_TREES_ITS_ unsigned char isEmpty() const; void dump(); - unsigned char operator<(const Tracklet&); + unsigned char operator<(const Tracklet&) const; #endif int firstClusterIndex; int secondClusterIndex; float tanLambda; - float phiCoordinate; + float phi; + unsigned short rof[2]; }; -inline Tracklet::Tracklet() : firstClusterIndex{0}, secondClusterIndex{0}, tanLambda{0.0f}, phiCoordinate{0.0f} +inline Tracklet::Tracklet() : firstClusterIndex{0}, secondClusterIndex{0}, tanLambda{0.0f}, phi{0.0f} { // Nothing to do } GPUdi() Tracklet::Tracklet(const int firstClusterOrderingIndex, const int secondClusterOrderingIndex, - const Cluster& firstCluster, const Cluster& secondCluster) + const Cluster& firstCluster, const Cluster& secondCluster, int rof0 = -1, int rof1 = -1) : firstClusterIndex{firstClusterOrderingIndex}, secondClusterIndex{secondClusterOrderingIndex}, tanLambda{(firstCluster.zCoordinate - secondCluster.zCoordinate) / - (firstCluster.rCoordinate - secondCluster.rCoordinate)}, - phiCoordinate{gpu::GPUCommonMath::ATan2(firstCluster.yCoordinate - secondCluster.yCoordinate, - firstCluster.xCoordinate - secondCluster.xCoordinate)} + (firstCluster.radius - secondCluster.radius)}, + phi{o2::gpu::GPUCommonMath::ATan2(firstCluster.yCoordinate - secondCluster.yCoordinate, + firstCluster.xCoordinate - secondCluster.xCoordinate)}, + rof{static_cast<unsigned short>(rof0), static_cast<unsigned short>(rof1)} { // Nothing to do } @@ -60,10 +63,10 @@ GPUdi() Tracklet::Tracklet(const int firstClusterOrderingIndex, const int second #ifdef _ALLOW_DEBUG_TREES_ITS_ inline unsigned char Tracklet::isEmpty() const { - return !firstClusterIndex && !secondClusterIndex && !tanLambda && !phiCoordinate; + return !firstClusterIndex && !secondClusterIndex && !tanLambda && !phi; } -inline unsigned char Tracklet::operator<(const Tracklet& t) +inline unsigned char Tracklet::operator<(const Tracklet& t) const { if (isEmpty() && t.isEmpty()) { return false; @@ -79,7 +82,7 @@ inline void Tracklet::dump() std::cout << "firstClusterIndex: " << firstClusterIndex << std::endl; std::cout << "secondClusterIndex: " << secondClusterIndex << std::endl; std::cout << "tanLambda: " << tanLambda << std::endl; - std::cout << "phiCoordinate: " << phiCoordinate << std::endl; + std::cout << "phi: " << phi << std::endl; } #endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h index 88984c94daf32..b51fa14e38fc5 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,7 +60,8 @@ class Vertexer std::vector<Vertex> exportVertices(); VertexerTraits* getTraits() const { return mTraits; }; - float clustersToVertices(ROframe&, const bool useMc = false, std::ostream& = std::cout); + float clustersToVertices( + ROframe&, const bool useMc = false, std::function<void(std::string s)> = [](std::string s) { std::cout << s << std::endl; }); void filterMCTracklets(); void validateTracklets(); @@ -76,7 +78,7 @@ class Vertexer // Utils void dumpTraits(); template <typename... T> - float evaluateTask(void (Vertexer::*)(T...), const char*, std::ostream& ostream, T&&... args); + float evaluateTask(void (Vertexer::*)(T...), bool, const char*, std::function<void(std::string s)> logger, T&&... args); // debug void setDebugCombinatorics(); @@ -139,9 +141,6 @@ inline std::vector<Vertex> Vertexer::exportVertices() { std::vector<Vertex> vertices; for (auto& vertex : mTraits->getVertices()) { - if (fair::Logger::Logging(fair::Severity::info)) { - std::cout << "\t\tFound vertex with: " << std::setw(6) << vertex.mContributors << " contributors" << std::endl; - } vertices.emplace_back(o2::math_utils::Point3D<float>(vertex.mX, vertex.mY, vertex.mZ), vertex.mRMS2, vertex.mContributors, vertex.mAvgDistance2); vertices.back().setTimeStamp(vertex.mTimeStamp); } @@ -149,7 +148,7 @@ inline std::vector<Vertex> Vertexer::exportVertices() } template <typename... T> -float Vertexer::evaluateTask(void (Vertexer::*task)(T...), const char* taskName, std::ostream& ostream, +float Vertexer::evaluateTask(void (Vertexer::*task)(T...), bool verbose, const char* taskName, std::function<void(std::string s)> logger, T&&... args) { float diff{0.f}; @@ -162,12 +161,14 @@ float Vertexer::evaluateTask(void (Vertexer::*task)(T...), const char* taskName, std::chrono::duration<double, std::milli> diff_t{end - start}; diff = diff_t.count(); - if (fair::Logger::Logging(fair::Severity::info)) { - if (taskName == nullptr) { - ostream << diff << "\t"; - } else { - ostream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms" << std::endl; - } + std::stringstream sstream; + if (taskName == nullptr) { + sstream << diff << "\t"; + } else { + sstream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms"; + } + if (verbose) { + logger(sstream.str()); } } else { (this->*task)(std::forward<T>(args)...); diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h index be341b69a39a3..b85d6984affe8 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,9 +24,7 @@ #include "ITStracking/Configuration.h" #include "ITStracking/ClusterLines.h" #include "ITStracking/Definitions.h" -#ifdef _ALLOW_DEBUG_TREES_ITS_ -#include "ITStracking/StandaloneDebugger.h" -#endif +#include "ITStracking/IndexTableUtils.h" #include "ITStracking/Tracklet.h" #include "GPUCommonMath.h" @@ -42,11 +41,9 @@ class TreeStreamRedirector; namespace its { - +class StandaloneDebugger; class ROframe; -using constants::index_table::PhiBins; -using constants::index_table::ZBins; using constants::its::LayersNumberVertexer; struct lightVertex { @@ -99,15 +96,18 @@ class VertexerTraits virtual ~VertexerTraits(); #else VertexerTraits(); - virtual ~VertexerTraits() = default; + ~VertexerTraits() = default; #endif GPUhd() static constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - GPUhd() static const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi); - GPUhd() static const int2 getPhiBins(float phi, float deltaPhi); + GPUhd() const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi); + GPUhd() const int2 getPhiBins(float phi, float deltaPhi); + + GPUhd() static const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi, const IndexTableUtils&); + GPUhd() static const int2 getPhiBins(float phi, float deltaPhi, const IndexTableUtils&); // virtual vertexer interface virtual void reset(); @@ -128,12 +128,14 @@ class VertexerTraits void updateVertexingParameters(const VertexingParameters& vrtPar); VertexingParameters getVertexingParameters() const { return mVrtParams; } - static const std::vector<std::pair<int, int>> selectClusters(const std::array<int, ZBins * PhiBins + 1>& indexTable, - const std::array<int, 4>& selectedBinsRect); + static const std::vector<std::pair<int, int>> selectClusters(const int* indexTable, + const std::array<int, 4>& selectedBinsRect, + const IndexTableUtils& utils); std::vector<lightVertex> getVertices() const { return mVertices; } // utils void setIsGPU(const unsigned char); + unsigned char getIsGPU() const; void dumpVertexerTraits(); void arrangeClusters(ROframe*); std::vector<int> getMClabelsLayer(const int layer) const; @@ -160,7 +162,8 @@ class VertexerTraits #endif VertexingParameters mVrtParams; - std::array<std::array<int, ZBins * PhiBins + 1>, LayersNumberVertexer> mIndexTables; + IndexTableUtils mIndexTableUtils; + std::array<std::vector<int>, LayersNumberVertexer> mIndexTables; std::vector<lightVertex> mVertices; // Frame related quantities @@ -177,6 +180,9 @@ class VertexerTraits inline void VertexerTraits::initialise(ROframe* event) { reset(); + if (!mIndexTableUtils.getNzBins()) { + updateVertexingParameters(mVrtParams); + } arrangeClusters(event); setIsGPU(false); } @@ -186,35 +192,56 @@ inline void VertexerTraits::setIsGPU(const unsigned char isgpu) mIsGPU = isgpu; } +inline unsigned char VertexerTraits::getIsGPU() const { return mIsGPU; } + inline void VertexerTraits::updateVertexingParameters(const VertexingParameters& vrtPar) { mVrtParams = vrtPar; + mIndexTableUtils.setTrackingParameters(vrtPar); + mVrtParams.phiSpan = static_cast<int>(std::ceil(mIndexTableUtils.getNphiBins() * mVrtParams.phiCut / + constants::math::TwoPi)); + mVrtParams.zSpan = static_cast<int>(std::ceil(mVrtParams.zCut * mIndexTableUtils.getInverseZCoordinate(0))); + for (auto& table : mIndexTables) { + table.resize(mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1, 0); + } } GPUhdi() const int2 VertexerTraits::getPhiBins(float phi, float dPhi) { - return int2{index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phi - dPhi)), - index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phi + dPhi))}; + return VertexerTraits::getPhiBins(phi, dPhi, mIndexTableUtils); +} + +GPUhdi() const int2 VertexerTraits::getPhiBins(float phi, float dPhi, const IndexTableUtils& utils) +{ + return int2{utils.getPhiBinIndex(math_utils::getNormalizedPhi(phi - dPhi)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phi + dPhi))}; } GPUhdi() const int4 VertexerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, - const float directionZIntersection, float maxdeltaz, float maxdeltaphi) + const float directionZIntersection, float maxdeltaz, float maxdeltaphi, + const IndexTableUtils& utils) { const float zRangeMin = directionZIntersection - 2 * maxdeltaz; - const float phiRangeMin = currentCluster.phiCoordinate - maxdeltaphi; + const float phiRangeMin = currentCluster.phi - maxdeltaphi; const float zRangeMax = directionZIntersection + 2 * maxdeltaz; - const float phiRangeMax = currentCluster.phiCoordinate + maxdeltaphi; + const float phiRangeMax = currentCluster.phi + maxdeltaphi; - if (zRangeMax < -constants::its::LayersZCoordinate()[layerIndex + 1] || - zRangeMin > constants::its::LayersZCoordinate()[layerIndex + 1] || zRangeMin > zRangeMax) { + if (zRangeMax < -utils.getLayerZ(layerIndex + 1) || + zRangeMin > utils.getLayerZ(layerIndex + 1) || zRangeMin > zRangeMax) { return getEmptyBinsRect(); } - return int4{gpu::GPUCommonMath::Max(0, index_table_utils::getZBinIndex(layerIndex + 1, zRangeMin)), - index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phiRangeMin)), - gpu::GPUCommonMath::Min(constants::index_table::ZBins - 1, index_table_utils::getZBinIndex(layerIndex + 1, zRangeMax)), - index_table_utils::getPhiBinIndex(math_utils::getNormalizedPhiCoordinate(phiRangeMax))}; + return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex + 1, zRangeMin)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), + o2::gpu::GPUCommonMath::Min(utils.getNzBins() - 1, utils.getZBinIndex(layerIndex + 1, zRangeMax)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; +} + +GPUhdi() const int4 VertexerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, + const float directionZIntersection, float maxdeltaz, float maxdeltaphi) +{ + return VertexerTraits::getBinsRect(currentCluster, layerIndex, directionZIntersection, maxdeltaz, maxdeltaphi, mIndexTableUtils); } // debug diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h index f6bf18f6e04e5..d1d246b329907 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx b/Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx index ed96496fcfb6e..f4bac7dc62c7e 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,70 +14,69 @@ /// #include "ITStracking/Cluster.h" - -#include "ITStracking/IndexTableUtils.h" #include "ITStracking/MathUtils.h" +#include "ITStracking/IndexTableUtils.h" namespace o2 { namespace its { -using math_utils::calculatePhiCoordinate; -using math_utils::calculateRCoordinate; -using math_utils::getNormalizedPhiCoordinate; +using math_utils::computePhi; +using math_utils::getNormalizedPhi; +using math_utils::hypot; Cluster::Cluster(const float x, const float y, const float z, const int index) : xCoordinate{x}, yCoordinate{y}, zCoordinate{z}, - phiCoordinate{getNormalizedPhiCoordinate(calculatePhiCoordinate(x, y))}, - rCoordinate{calculateRCoordinate(x, y)}, + phi{getNormalizedPhi(computePhi(x, y))}, + radius{hypot(x, y)}, clusterId{index}, indexTableBinIndex{0} { // Nothing to do } -Cluster::Cluster(const int layerIndex, const Cluster& other) +Cluster::Cluster(const int layerIndex, const IndexTableUtils& utils, const Cluster& other) : xCoordinate{other.xCoordinate}, yCoordinate{other.yCoordinate}, zCoordinate{other.zCoordinate}, - phiCoordinate{getNormalizedPhiCoordinate(calculatePhiCoordinate(other.xCoordinate, other.yCoordinate))}, - rCoordinate{calculateRCoordinate(other.xCoordinate, other.yCoordinate)}, + phi{getNormalizedPhi(computePhi(other.xCoordinate, other.yCoordinate))}, + radius{hypot(other.xCoordinate, other.yCoordinate)}, clusterId{other.clusterId}, - indexTableBinIndex{index_table_utils::getBinIndex(index_table_utils::getZBinIndex(layerIndex, zCoordinate), - index_table_utils::getPhiBinIndex(phiCoordinate))} + indexTableBinIndex{utils.getBinIndex(utils.getZBinIndex(layerIndex, zCoordinate), + utils.getPhiBinIndex(phi))} //, montecarloId{ other.montecarloId } { // Nothing to do } -Cluster::Cluster(const int layerIndex, const float3& primaryVertex, const Cluster& other) +Cluster::Cluster(const int layerIndex, const float3& primaryVertex, const IndexTableUtils& utils, const Cluster& other) : xCoordinate{other.xCoordinate}, yCoordinate{other.yCoordinate}, zCoordinate{other.zCoordinate}, - phiCoordinate{getNormalizedPhiCoordinate( - calculatePhiCoordinate(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y))}, - rCoordinate{calculateRCoordinate(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y)}, + phi{getNormalizedPhi( + computePhi(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y))}, + radius{hypot(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y)}, clusterId{other.clusterId}, - indexTableBinIndex{index_table_utils::getBinIndex(index_table_utils::getZBinIndex(layerIndex, zCoordinate), - index_table_utils::getPhiBinIndex(phiCoordinate))} + indexTableBinIndex{utils.getBinIndex(utils.getZBinIndex(layerIndex, zCoordinate), + utils.getPhiBinIndex(phi))} { // Nothing to do } -void Cluster::Init(const int layerIndex, const float3& primaryVertex, const Cluster& other) +void Cluster::Init(const int layerIndex, const float3& primaryVertex, const IndexTableUtils& utils, const Cluster& other) { xCoordinate = other.xCoordinate; yCoordinate = other.yCoordinate; zCoordinate = other.zCoordinate; - phiCoordinate = getNormalizedPhiCoordinate( - calculatePhiCoordinate(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y)); - rCoordinate = calculateRCoordinate(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y); + phi = getNormalizedPhi( + computePhi(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y)); + radius = hypot(xCoordinate - primaryVertex.x, yCoordinate - primaryVertex.y); clusterId = other.clusterId; - indexTableBinIndex = index_table_utils::getBinIndex(index_table_utils::getZBinIndex(layerIndex, zCoordinate), - index_table_utils::getPhiBinIndex(phiCoordinate)); + indexTableBinIndex = utils.getBinIndex(utils.getZBinIndex(layerIndex, zCoordinate), + utils.getPhiBinIndex(phi)); } TrackingFrameInfo::TrackingFrameInfo(float x, float y, float z, float xTF, float alpha, GPUArray<float, 2>&& posTF, diff --git a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx b/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx index a51e30edd2117..4b271bea0e5c1 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -171,8 +172,8 @@ ClusterLines::ClusterLines(const int firstLabel, const Line& firstLine, const in computeClusterCentroid(); // RMS2 - mRMS2 = std::move(Line::getDCAComponents(firstLine, mVertex)); - const std::array<float, 6> tmpRMS2Line2 = std::move(Line::getDCAComponents(secondLine, mVertex)); + mRMS2 = Line::getDCAComponents(firstLine, mVertex); + const std::array<float, 6> tmpRMS2Line2 = Line::getDCAComponents(secondLine, mVertex); std::transform(mRMS2.begin(), mRMS2.end(), tmpRMS2Line2.begin(), mRMS2.begin(), [&](const float a, const float b) { return a + (b - a) / mLabels.size(); }); // AvgDistance2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/DBScan.cxx b/Detectors/ITSMFT/ITS/tracking/src/DBScan.cxx deleted file mode 100644 index 52795b0287246..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/DBScan.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file DBScan.cxx -/// \brief -/// - -#include "ITStracking/DBScan.h" -#include "ITStracking/Definitions.h" -#include "GPUCommonMath.h" - -namespace o2 -{ -namespace its -{ - -Centroid::Centroid(int* indices, float* position) -{ - for (int i{0}; i < 2; ++i) { - mIndices[i] = indices[i]; - } - for (int i{0}; i < 3; ++i) { - mPosition[i] = position[i]; - } -} - -float Centroid::ComputeDistance(const Centroid& c1, const Centroid& c2) -{ - return gpu::GPUCommonMath::Sqrt((c1.mPosition[0] - c2.mPosition[0]) * (c1.mPosition[0] - c2.mPosition[0]) + - (c1.mPosition[1] - c2.mPosition[1]) * (c1.mPosition[1] - c2.mPosition[1]) + - (c1.mPosition[2] - c2.mPosition[2]) * (c1.mPosition[2] - c2.mPosition[2])); -} -} // namespace its -} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/src/Graph.cxx b/Detectors/ITSMFT/ITS/tracking/src/Graph.cxx deleted file mode 100644 index a43b8c036056e..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/Graph.cxx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Graph.cxx -/// \brief -/// - -#include "ITStracking/Graph.h" - -namespace o2 -{ -namespace its -{ - -void Barrier::Wait() -{ - std::unique_lock<std::mutex> lock(mutex); - if (--count == 0) { - condition.notify_all(); - } else { - condition.wait(lock, [this] { return count == 0; }); - } -} - -} // namespace its -} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/src/IOUtils.cxx b/Detectors/ITSMFT/ITS/tracking/src/IOUtils.cxx index f3cecb7c53944..ddd2ca8934115 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/IOUtils.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/IOUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,9 +39,6 @@ constexpr int PrimaryVertexLayerId{-1}; constexpr int EventLabelsSeparator{-1}; } // namespace -using o2::its::constants::its::LayersRCoordinate; -using o2::its::constants::its::LayersZCoordinate; - namespace o2 { namespace its @@ -80,68 +78,6 @@ void ioutils::convertCompactClusters(gsl::span<const itsmft::CompClusterExt> clu } } -void ioutils::loadConfigurations(const std::string& fileName) -{ - if (!fileName.empty()) { - std::ifstream inputStream; - inputStream.open(fileName); - nlohmann::json j; - inputStream >> j; - static_cast<TrackingParameters&>(Configuration<TrackingParameters>::getInstance()) = j.at("TrackingParameters").get<TrackingParameters>(); - //static_cast<IndexTableParameters&>(Configuration<IndexTableParameters>::getInstance()) = j.at("IndexTableParameters").get<IndexTableParameters>(); - } -} - -std::vector<ROframe> ioutils::loadEventData(const std::string& fileName) -{ - std::vector<ROframe> events{}; - std::ifstream inputStream{}; - std::string line{}, unusedVariable{}; - int layerId{}, monteCarlo{}; - int clusterId{EventLabelsSeparator}; - float xCoordinate{}, yCoordinate{}, zCoordinate{}, alphaAngle{}; - float varZ{-1.f}, varY{-1.f}; - - inputStream.open(fileName); - - /// THIS IS LEAKING IN THE BACKWARD COMPATIBLE MODE. KEEP IT IN MIND. - dataformats::MCTruthContainer<MCCompLabel>* mcLabels = nullptr; - while (std::getline(inputStream, line)) { - - std::istringstream inputStringStream(line); - if (inputStringStream >> layerId >> xCoordinate >> yCoordinate >> zCoordinate) { - - if (layerId == PrimaryVertexLayerId) { - - if (clusterId != 0) { - events.emplace_back(events.size()); - } - - events.back().addPrimaryVertex(xCoordinate, yCoordinate, zCoordinate); - clusterId = 0; - - } else { - - if (inputStringStream >> varY >> varZ >> unusedVariable >> alphaAngle >> monteCarlo) { - events.back().addClusterToLayer(layerId, xCoordinate, yCoordinate, zCoordinate, - events.back().getClustersOnLayer(layerId).size()); - const float sinAlpha = std::sin(alphaAngle); - const float cosAlpha = std::cos(alphaAngle); - const float xTF = xCoordinate * cosAlpha - yCoordinate * sinAlpha; - const float yTF = xCoordinate * sinAlpha + yCoordinate * cosAlpha; - events.back().addTrackingFrameInfoToLayer(layerId, xCoordinate, yCoordinate, zCoordinate, xTF, alphaAngle, - std::array<float, 2>{yTF, zCoordinate}, std::array<float, 3>{varY, 0.f, varZ}); - events.back().addClusterLabelToLayer(layerId, MCCompLabel(monteCarlo)); - - ++clusterId; - } - } - } - } - - return events; -} - void ioutils::loadEventData(ROframe& event, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* clsLabels) @@ -187,7 +123,8 @@ void ioutils::loadEventData(ROframe& event, gsl::span<const itsmft::CompClusterE /// Rotate to the global frame event.addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), event.getClustersOnLayer(layer).size()); if (clsLabels) { - event.addClusterLabelToLayer(layer, *(clsLabels->getLabels(clusterId).begin())); + // event.addClusterLabelToLayer(layer, *(clsLabels->getLabels(clusterId).begin())); + event.setMClabelsContainer(clsLabels); } event.addClusterExternalIndexToLayer(layer, clusterId); clusterId++; @@ -236,7 +173,8 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g /// Rotate to the global frame event.addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), event.getClustersOnLayer(layer).size()); if (mcLabels) { - event.addClusterLabelToLayer(layer, *(mcLabels->getLabels(first + clusterId).begin())); + // event.addClusterLabelToLayer(layer, *(mcLabels->getLabels(first + clusterId).begin())); + event.setMClabelsContainer(mcLabels); } event.addClusterExternalIndexToLayer(layer, first + clusterId); clusterId++; @@ -244,34 +182,6 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g return clusters_in_frame.size(); } -void ioutils::generateSimpleData(ROframe& event, const int phiDivs, const int zDivs = 1) -{ - const float angleOffset = constants::math::TwoPi / static_cast<float>(phiDivs); - // Maximum z allowed on innermost layer should be: ~9,75 - const float zOffsetFirstLayer = (zDivs == 1) ? 0 : 1.5 * (LayersZCoordinate()[6] * LayersRCoordinate()[0]) / (LayersRCoordinate()[6] * (static_cast<float>(zDivs) - 1)); - std::vector<float> x, y; - std::array<std::vector<float>, 7> z; - for (size_t j{0}; j < zDivs; ++j) { - for (size_t i{0}; i < phiDivs; ++i) { - x.emplace_back(cos(i * angleOffset + 0.001)); // put an epsilon to move from periods (e.g. 20 clusters vs 20 cells) - y.emplace_back(sin(i * angleOffset + 0.001)); - const float zFirstLayer{-static_cast<float>((zDivs - 1.) / 2.) * zOffsetFirstLayer + zOffsetFirstLayer * static_cast<float>(j)}; - z[0].emplace_back(zFirstLayer); - for (size_t iLayer{1}; iLayer < constants::its::LayersNumber; ++iLayer) { - z[iLayer].emplace_back(zFirstLayer * LayersRCoordinate()[iLayer] / LayersRCoordinate()[0]); - } - } - } - - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { - for (int i = 0; i < phiDivs * zDivs; i++) { - o2::MCCompLabel label{i, 0, 0, false}; - event.addClusterLabelToLayer(iLayer, label); //last argument : label, goes into mClustersLabel - event.addClusterToLayer(iLayer, LayersRCoordinate()[iLayer] * x[i], LayersRCoordinate()[iLayer] * y[i], z[iLayer][i], i); //uses 1st constructor for clusters - } - } -} - std::vector<std::unordered_map<int, Label>> ioutils::loadLabels(const int eventsNum, const std::string& fileName) { std::vector<std::unordered_map<int, Label>> labelsMap{}; @@ -279,7 +189,7 @@ std::vector<std::unordered_map<int, Label>> ioutils::loadLabels(const int events std::ifstream inputStream{}; std::string line{}; int monteCarloId{}, pdgCode{}, numberOfClusters{}; - float transverseMomentum{}, phiCoordinate{}, pseudorapidity{}; + float transverseMomentum{}, phi{}, pseudorapidity{}; labelsMap.reserve(eventsNum); @@ -299,12 +209,12 @@ std::vector<std::unordered_map<int, Label>> ioutils::loadLabels(const int events } else { - if (inputStringStream >> transverseMomentum >> phiCoordinate >> pseudorapidity >> pdgCode >> numberOfClusters) { + if (inputStringStream >> transverseMomentum >> phi >> pseudorapidity >> pdgCode >> numberOfClusters) { if (std::abs(pdgCode) == constants::pdgcodes::PionCode && numberOfClusters == 7) { currentEventLabelsMap.emplace(std::piecewise_construct, std::forward_as_tuple(monteCarloId), - std::forward_as_tuple(monteCarloId, transverseMomentum, phiCoordinate, + std::forward_as_tuple(monteCarloId, transverseMomentum, phi, pseudorapidity, pdgCode, numberOfClusters)); } } @@ -364,70 +274,5 @@ void ioutils::writeRoadsReport(std::ofstream& correctRoadsOutputStream, std::ofs } } -void to_json(nlohmann::json& j, const TrackingParameters& par) -{ - std::array<float, constants::its::TrackletsPerRoad> tmpTrackletMaxDeltaZ; - std::copy(par.TrackletMaxDeltaZ, par.TrackletMaxDeltaZ + tmpTrackletMaxDeltaZ.size(), tmpTrackletMaxDeltaZ.begin()); - std::array<float, constants::its::CellsPerRoad> tmpCellMaxDCA; - std::copy(par.CellMaxDCA, par.CellMaxDCA + tmpCellMaxDCA.size(), tmpCellMaxDCA.begin()); - std::array<float, constants::its::CellsPerRoad> tmpCellMaxDeltaZ; - std::copy(par.CellMaxDeltaZ, par.CellMaxDeltaZ + tmpCellMaxDeltaZ.size(), tmpCellMaxDeltaZ.begin()); - std::array<float, constants::its::CellsPerRoad - 1> tmpNeighbourMaxDeltaCurvature; - std::copy(par.NeighbourMaxDeltaCurvature, par.NeighbourMaxDeltaCurvature + tmpNeighbourMaxDeltaCurvature.size(), tmpNeighbourMaxDeltaCurvature.begin()); - std::array<float, constants::its::CellsPerRoad - 1> tmpNeighbourMaxDeltaN; - std::copy(par.NeighbourMaxDeltaN, par.NeighbourMaxDeltaN + tmpNeighbourMaxDeltaN.size(), tmpNeighbourMaxDeltaN.begin()); - j = nlohmann::json{ - {"ClusterSharing", par.ClusterSharing}, - {"MinTrackLength", par.MinTrackLength}, - {"TrackletMaxDeltaPhi", par.TrackletMaxDeltaPhi}, - {"TrackletMaxDeltaZ", tmpTrackletMaxDeltaZ}, - {"CellMaxDeltaTanLambda", par.CellMaxDeltaTanLambda}, - {"CellMaxDCA", tmpCellMaxDCA}, - {"CellMaxDeltaPhi", par.CellMaxDeltaPhi}, - {"CellMaxDeltaZ", tmpCellMaxDeltaZ}, - {"NeighbourMaxDeltaCurvature", tmpNeighbourMaxDeltaCurvature}, - {"NeighbourMaxDeltaN", tmpNeighbourMaxDeltaN}}; -} - -void from_json(const nlohmann::json& j, TrackingParameters& par) -{ - par.ClusterSharing = j.at("ClusterSharing").get<int>(); - par.MinTrackLength = j.at("MinTrackLength").get<int>(); - par.TrackletMaxDeltaPhi = j.at("TrackletMaxDeltaPhi").get<float>(); - par.CellMaxDeltaTanLambda = j.at("CellMaxDeltaTanLambda").get<float>(); - par.CellMaxDeltaPhi = j.at("CellMaxDeltaPhi").get<float>(); - auto tmpTrackletMaxDeltaZ = j.at("TrackletMaxDeltaZ").get<std::array<float, constants::its::TrackletsPerRoad>>(); - std::copy(tmpTrackletMaxDeltaZ.begin(), tmpTrackletMaxDeltaZ.end(), par.TrackletMaxDeltaZ); - auto tmpCellMaxDCA = j.at("CellMaxDCA").get<std::array<float, constants::its::CellsPerRoad>>(); - std::copy(tmpCellMaxDCA.begin(), tmpCellMaxDCA.end(), par.CellMaxDCA); - auto tmpCellMaxDeltaZ = j.at("CellMaxDeltaZ").get<std::array<float, constants::its::CellsPerRoad>>(); - std::copy(tmpCellMaxDCA.begin(), tmpCellMaxDeltaZ.end(), par.CellMaxDeltaZ); - auto tmpNeighbourMaxDeltaCurvature = j.at("NeighbourMaxDeltaCurvature").get<std::array<float, constants::its::CellsPerRoad - 1>>(); - std::copy(tmpNeighbourMaxDeltaCurvature.begin(), tmpNeighbourMaxDeltaCurvature.end(), par.NeighbourMaxDeltaCurvature); - auto tmpNeighbourMaxDeltaN = j.at("NeighbourMaxDeltaN").get<std::array<float, constants::its::CellsPerRoad - 1>>(); - std::copy(tmpNeighbourMaxDeltaN.begin(), tmpNeighbourMaxDeltaN.end(), par.NeighbourMaxDeltaN); -} - -void to_json(nlohmann::json& j, const MemoryParameters& par) -{ - std::array<float, constants::its::CellsPerRoad> tmpCellsMemoryCoefficients; - std::copy(par.CellsMemoryCoefficients, par.CellsMemoryCoefficients + tmpCellsMemoryCoefficients.size(), tmpCellsMemoryCoefficients.begin()); - std::array<float, constants::its::TrackletsPerRoad> tmpTrackletsMemoryCoefficients; - std::copy(par.TrackletsMemoryCoefficients, par.TrackletsMemoryCoefficients + tmpTrackletsMemoryCoefficients.size(), tmpTrackletsMemoryCoefficients.begin()); - j = nlohmann::json{ - {"MemoryOffset", par.MemoryOffset}, - {"CellsMemoryCoefficients", tmpCellsMemoryCoefficients}, - {"TrackletsMemoryCoefficients", tmpTrackletsMemoryCoefficients}}; -} - -void from_json(const nlohmann::json& j, MemoryParameters& par) -{ - par.MemoryOffset = j.at("MemoryOffset").get<int>(); - auto tmpCellsMemoryCoefficients = j.at("CellsMemoryCoefficients").get<std::array<float, constants::its::CellsPerRoad>>(); - std::copy(tmpCellsMemoryCoefficients.begin(), tmpCellsMemoryCoefficients.end(), par.CellsMemoryCoefficients); - auto tmpTrackletsMemoryCoefficients = j.at("TrackletsMemoryCoefficients").get<std::array<float, constants::its::TrackletsPerRoad>>(); - std::copy(tmpTrackletsMemoryCoefficients.begin(), tmpTrackletsMemoryCoefficients.end(), par.TrackletsMemoryCoefficients); -} - } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx b/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx index 47adb50c21520..7152640e9a70f 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/tracking/src/Label.cxx b/Detectors/ITSMFT/ITS/tracking/src/Label.cxx index f5b560d9b00f5..e195318828f51 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Label.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Label.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ namespace its Label::Label(const int mcId, const float pT, const float phi, const float eta, const int pdg, const int ncl) : monteCarloId{mcId}, transverseMomentum{pT}, - phiCoordinate{phi}, + phi{phi}, pseudorapidity{eta}, pdgCode{pdg}, numberOfClusters{ncl} @@ -32,7 +33,7 @@ Label::Label(const int mcId, const float pT, const float phi, const float eta, c std::ostream& operator<<(std::ostream& outputStream, const Label& label) { - outputStream << label.monteCarloId << "\t" << label.transverseMomentum << "\t" << label.phiCoordinate << "\t" + outputStream << label.monteCarloId << "\t" << label.transverseMomentum << "\t" << label.phi << "\t" << label.pseudorapidity << "\t" << label.pdgCode << "\t" << label.numberOfClusters; return outputStream; diff --git a/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx b/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx index d4dcbe5f36fc9..22c259d7390fd 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,8 +22,8 @@ namespace o2 namespace its { -void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const std::array<std::vector<Cluster>, constants::its::LayersNumber>& cl, - const std::array<float, 3>& pVtx, const int iteration) +void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const TrackingParameters& trkParam, + const std::vector<std::vector<Cluster>>& cl, const std::array<float, 3>& pVtx, const int iteration) { struct ClusterHelper { @@ -38,7 +39,20 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st std::vector<ClusterHelper> cHelper; - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { + mMinR.resize(trkParam.NLayers, 10000.); + mMaxR.resize(trkParam.NLayers, -1.); + mClusters.resize(trkParam.NLayers); + mUsedClusters.resize(trkParam.NLayers); + mCells.resize(trkParam.CellsPerRoad()); + mCellsLookupTable.resize(trkParam.CellsPerRoad() - 1); + mCellsNeighbours.resize(trkParam.CellsPerRoad() - 1); + mIndexTables.resize(trkParam.TrackletsPerRoad(), std::vector<int>(trkParam.ZBins * trkParam.PhiBins + 1, 0)); + mTracklets.resize(trkParam.TrackletsPerRoad()); + mTrackletsLookupTable.resize(trkParam.CellsPerRoad()); + mIndexTableUtils.setTrackingParameters(trkParam); + + std::vector<int> clsPerBin(trkParam.PhiBins * trkParam.ZBins, 0); + for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { const auto& currentLayer{cl[iLayer]}; const int clustersNum{static_cast<int>(currentLayer.size())}; @@ -48,11 +62,7 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st mUsedClusters[iLayer].clear(); mUsedClusters[iLayer].resize(clustersNum, false); - constexpr int _size = constants::index_table::PhiBins * constants::index_table::ZBins; - std::array<int, _size> clsPerBin; - for (int iB{0}; iB < _size; ++iB) { - clsPerBin[iB] = 0; - } + std::fill(clsPerBin.begin(), clsPerBin.end(), 0); cHelper.clear(); cHelper.resize(clustersNum); @@ -65,20 +75,21 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st ClusterHelper& h = cHelper[iCluster]; float x = c.xCoordinate - mPrimaryVertex.x; float y = c.yCoordinate - mPrimaryVertex.y; - float phi = math_utils::calculatePhiCoordinate(x, y); - int bin = index_table_utils::getBinIndex(index_table_utils::getZBinIndex(iLayer, c.zCoordinate), - index_table_utils::getPhiBinIndex(phi)); + float phi = math_utils::computePhi(x, y); + const int zBin{mIndexTableUtils.getZBinIndex(iLayer, c.zCoordinate)}; + int bin = mIndexTableUtils.getBinIndex(zBin, mIndexTableUtils.getPhiBinIndex(phi)); + CA_DEBUGGER(assert(zBin > 0)); h.phi = phi; - h.r = math_utils::calculateRCoordinate(x, y); - mMinR[iLayer] = gpu::GPUCommonMath::Min(h.r, mMinR[iLayer]); - mMaxR[iLayer] = gpu::GPUCommonMath::Max(h.r, mMaxR[iLayer]); + h.r = std::hypot(x, y); + mMinR[iLayer] = o2::gpu::GPUCommonMath::Min(h.r, mMinR[iLayer]); + mMaxR[iLayer] = o2::gpu::GPUCommonMath::Max(h.r, mMaxR[iLayer]); h.bin = bin; h.ind = clsPerBin[bin]++; } - std::array<int, _size> lutPerBin; + std::vector<int> lutPerBin(clsPerBin.size()); lutPerBin[0] = 0; - for (int iB{1}; iB < _size; ++iB) { + for (unsigned int iB{1}; iB < lutPerBin.size(); ++iB) { lutPerBin[iB] = lutPerBin[iB - 1] + clsPerBin[iB - 1]; } @@ -86,16 +97,16 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st ClusterHelper& h = cHelper[iCluster]; Cluster& c = mClusters[iLayer][lutPerBin[h.bin] + h.ind]; c = currentLayer[iCluster]; - c.phiCoordinate = h.phi; - c.rCoordinate = h.r; + c.phi = h.phi; + c.radius = h.r; c.indexTableBinIndex = h.bin; } if (iLayer > 0) { - for (int iB{0}; iB < _size; ++iB) { + for (unsigned int iB{0}; iB < clsPerBin.size(); ++iB) { mIndexTables[iLayer - 1][iB] = lutPerBin[iB]; } - for (int iB{_size}; iB < (int)mIndexTables[iLayer - 1].size(); iB++) { + for (auto iB{clsPerBin.size()}; iB < mIndexTables[iLayer - 1].size(); iB++) { mIndexTables[iLayer - 1][iB] = clustersNum; } } @@ -104,8 +115,8 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st mRoads.clear(); - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { - if (iLayer < constants::its::CellsPerRoad) { + for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { + if (iLayer < mCells.size()) { mCells[iLayer].clear(); float cellsMemorySize = memParam.MemoryOffset + @@ -118,32 +129,32 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st } } - if (iLayer < constants::its::CellsPerRoad - 1) { + if (iLayer < mCells.size() - 1) { mCellsLookupTable[iLayer].clear(); - mCellsLookupTable[iLayer].resize( - std::max(cl[iLayer + 1].size(), cl[iLayer + 2].size()) + - std::ceil((memParam.TrackletsMemoryCoefficients[iLayer + 1] * - cl[iLayer + 1].size()) * - cl[iLayer + 2].size()), - constants::its::UnusedIndex); + mCellsLookupTable[iLayer].resize(memParam.MemoryOffset + + std::max(cl[iLayer + 1].size(), cl[iLayer + 2].size()) + + std::ceil((memParam.TrackletsMemoryCoefficients[iLayer + 1] * + cl[iLayer + 1].size()) * + cl[iLayer + 2].size()), + constants::its::UnusedIndex); mCellsNeighbours[iLayer].clear(); } } - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { - if (iLayer < constants::its::TrackletsPerRoad) { + for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { + if (iLayer < mTracklets.size()) { mTracklets[iLayer].clear(); - float trackletsMemorySize = - std::max(cl[iLayer].size(), cl[iLayer + 1].size()) + - std::ceil((memParam.TrackletsMemoryCoefficients[iLayer] * cl[iLayer].size()) * - cl[iLayer + 1].size()); + float trackletsMemorySize = memParam.MemoryOffset + + std::max(cl[iLayer].size(), cl[iLayer + 1].size()) + + std::ceil((memParam.TrackletsMemoryCoefficients[iLayer] * cl[iLayer].size()) * + cl[iLayer + 1].size()); if (trackletsMemorySize > mTracklets[iLayer].capacity()) { mTracklets[iLayer].reserve(trackletsMemorySize); } } - if (iLayer < constants::its::CellsPerRoad) { + if (iLayer < mCells.size()) { mTrackletsLookupTable[iLayer].clear(); mTrackletsLookupTable[iLayer].resize(cl[iLayer + 1].size(), constants::its::UnusedIndex); } diff --git a/Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx b/Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx index e4375d1caafb9..ee885db3c49ea 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,8 +22,12 @@ namespace o2 namespace its { -ROframe::ROframe(const int ROframeId) : mROframeId{ROframeId} +ROframe::ROframe(int ROframeId, int nLayers) : mROframeId{ROframeId} { + mClusters.resize(nLayers); + mTrackingFrameInfo.resize(nLayers); + // mClusterLabels.resize(nLayers); + mClusterExternalIndices.resize(nLayers); } void ROframe::addPrimaryVertex(const float xCoordinate, const float yCoordinate, const float zCoordinate) diff --git a/Detectors/ITSMFT/ITS/tracking/src/Road.cxx b/Detectors/ITSMFT/ITS/tracking/src/Road.cxx index da5748bbcd75a..5d1187673bba1 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Road.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Road.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,8 @@ /// #include "ITStracking/Road.h" +#include <cassert> +#include <iostream> namespace o2 { @@ -25,7 +28,7 @@ Road::Road(int cellLayer, int cellId) : Road() { addCell(cellLayer, cellId); } void Road::resetRoad() { - for (int i = 0; i < constants::its::CellsPerRoad; i++) { + for (int i = 0; i < mMaxRoadSize; i++) { mCellIds[i] = constants::its::UnusedIndex; } mRoadSize = 0; diff --git a/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx b/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx new file mode 100644 index 0000000000000..04fe093af8d0f --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx @@ -0,0 +1,234 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// \author matteo.concas@cern.ch + +#include "ITStracking/Smoother.h" + +namespace o2 +{ +namespace its +{ + +constexpr std::array<double, 3> getInverseSymm2D(const std::array<double, 3>& mat) +{ + const double det = mat[0] * mat[2] - mat[1] * mat[1]; + return std::array<double, 3>{mat[2] / det, -mat[1] / det, mat[0] / det}; +} + +// Smoother +template <unsigned int D> +Smoother<D>::Smoother(TrackITSExt& track, int smoothingLayer, const ROframe& event, float bZ, o2::base::PropagatorF::MatCorrType corr) : mLayerToSmooth{smoothingLayer}, + mBz(bZ), + mCorr(corr) +{ +#if defined(CA_DEBUG) || defined(CA_STANDALONE_DEBUGGER) + mDebugger = new StandaloneDebugger("dbg_ITSSmootherCPU.root"); +#endif + + auto propInstance = o2::base::Propagator::Instance(); + const TrackingFrameInfo& originalTf = event.getTrackingFrameInfoOnLayer(mLayerToSmooth).at(track.getClusterIndex(mLayerToSmooth)); + + mOutwardsTrack = track; // This track will be propagated outwards inside the smoother! (as last step of fitting did inward propagation) + mInwardsTrack = {track.getParamOut(), // This track will be propagated inwards inside the smoother! + static_cast<short>(mOutwardsTrack.getNumberOfClusters()), -999, static_cast<std::uint32_t>(event.getROFrameId()), + mOutwardsTrack.getParamOut(), mOutwardsTrack.getClusterIndexes()}; + + mOutwardsTrack.resetCovariance(); + mOutwardsTrack.setChi2(0); + mInwardsTrack.resetCovariance(); + mInwardsTrack.setChi2(0); + + bool statusOutw{false}; + bool statusInw{false}; + + ////////////////////// + // Outward propagation + for (size_t iLayer{0}; iLayer < mLayerToSmooth; ++iLayer) { + if (mOutwardsTrack.getClusterIndex(iLayer) == constants::its::UnusedIndex) { // Shorter tracks + continue; + } + const TrackingFrameInfo& tF = event.getTrackingFrameInfoOnLayer(iLayer).at(mOutwardsTrack.getClusterIndex(iLayer)); + statusOutw = mOutwardsTrack.rotate(tF.alphaTrackingFrame); + statusOutw &= propInstance->propagateToX(mOutwardsTrack, + tF.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + mOutwardsTrack.setChi2(mOutwardsTrack.getChi2() + mOutwardsTrack.getPredictedChi2(tF.positionTrackingFrame, tF.covarianceTrackingFrame)); + statusOutw &= mOutwardsTrack.o2::track::TrackParCov::update(tF.positionTrackingFrame, tF.covarianceTrackingFrame); + // LOG(INFO) << "Outwards loop on inwards track, layer: " << iLayer << " x: " << mOutwardsTrack.getX(); + } + + // Prediction on the previously outwards-propagated track is done on a copy, as the process seems to be not reversible + auto outwardsClone = mOutwardsTrack; + statusOutw = outwardsClone.rotate(originalTf.alphaTrackingFrame); + statusOutw &= propInstance->propagateToX(outwardsClone, + originalTf.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + ///////////////////// + // Inward propagation + for (size_t iLayer{D - 1}; iLayer > mLayerToSmooth; --iLayer) { + if (mInwardsTrack.getClusterIndex(iLayer) == constants::its::UnusedIndex) { // Shorter tracks + continue; + } + const TrackingFrameInfo& tF = event.getTrackingFrameInfoOnLayer(iLayer).at(mInwardsTrack.getClusterIndex(iLayer)); + statusInw = mInwardsTrack.rotate(tF.alphaTrackingFrame); + statusInw &= propInstance->propagateToX(mInwardsTrack, + tF.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + mInwardsTrack.setChi2(mInwardsTrack.getChi2() + mInwardsTrack.getPredictedChi2(tF.positionTrackingFrame, tF.covarianceTrackingFrame)); + statusInw &= mInwardsTrack.o2::track::TrackParCov::update(tF.positionTrackingFrame, tF.covarianceTrackingFrame); + // LOG(INFO) << "Inwards loop on outwards track, layer: " << iLayer << " x: " << mInwardsTrack.getX(); + } + + // Prediction on the previously inwards-propagated track is done on a copy, as the process seems to be not revesible + auto inwardsClone = mInwardsTrack; + statusInw = inwardsClone.rotate(originalTf.alphaTrackingFrame); + statusInw &= propInstance->propagateToX(inwardsClone, + originalTf.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + // Compute weighted local chi2 + mInitStatus = statusInw && statusOutw; + if (mInitStatus) { + mBestChi2 = computeSmoothedPredictedChi2(inwardsClone, outwardsClone, originalTf.positionTrackingFrame, originalTf.covarianceTrackingFrame); + mLastChi2 = mBestChi2; + LOG(INFO) << "Smoothed chi2 on original cluster: " << mBestChi2; + } +} + +#if defined(CA_DEBUG) || defined(CA_STANDALONE_DEBUGGER) +template <unsigned int D> +Smoother<D>::~Smoother() +{ + delete mDebugger; +} +#else +template <unsigned int D> +Smoother<D>::~Smoother() = default; +#endif + +template <unsigned int D> +float Smoother<D>::computeSmoothedPredictedChi2(const o2::track::TrackParCov& firstTrack, // outwards track: from innermost cluster to outermost + const o2::track::TrackParCov& secondTrack, // inwards track: from outermost cluster to innermost + const std::array<float, 2>& cls, + const std::array<float, 3>& clCov) +{ + // Tracks need to be already propagated, compute only chi2 + // Symmetric covariances assumed + + if (firstTrack.getX() != secondTrack.getX()) { + LOG(FATAL) << "Tracks need to be propagated to the same point! secondTrack.X=" << secondTrack.getX() << " firstTrack.X=" << firstTrack.getX(); + } + + std::array<double, 2> pp1 = {static_cast<double>(firstTrack.getY()), static_cast<double>(firstTrack.getZ())}; // P1: predicted Y,Z points + std::array<double, 2> pp2 = {static_cast<double>(secondTrack.getY()), static_cast<double>(secondTrack.getZ())}; // P2: predicted Y,Z points + + std::array<double, 3> c1 = {static_cast<double>(firstTrack.getSigmaY2()), + static_cast<double>(firstTrack.getSigmaZY()), + static_cast<double>(firstTrack.getSigmaZ2())}; // Cov. track 1 + + std::array<double, 3> c2 = {static_cast<double>(secondTrack.getSigmaY2()), + static_cast<double>(secondTrack.getSigmaZY()), + static_cast<double>(secondTrack.getSigmaZ2())}; // Cov. track 2 + + std::array<double, 3> w1 = getInverseSymm2D(c1); // weight matrices + std::array<double, 3> w2 = getInverseSymm2D(c2); + + std::array<double, 3> w1w2 = {w1[0] + w2[0], w1[1] + w2[1], w1[2] + w2[2]}; // (W1 + W2) + std::array<double, 3> C = getInverseSymm2D(w1w2); // C = (W1+W2)^-1 + + std::array<double, 2> w1pp1 = {w1[0] * pp1[0] + w1[1] * pp1[1], w1[1] * pp1[0] + w1[2] * pp1[1]}; // W1 * P1 + std::array<double, 2> w2pp2 = {w2[0] * pp2[0] + w2[1] * pp2[1], w2[1] * pp2[0] + w2[2] * pp2[1]}; // W2 * P2 + + double Y = C[0] * (w1pp1[0] + w2pp2[0]) + C[1] * (w1pp1[1] + w2pp2[1]); // Pp: weighted normalized combination of the predictions: + double Z = C[1] * (w1pp1[0] + w2pp2[0]) + C[2] * (w1pp1[1] + w2pp2[1]); // Pp = [(W1 * P1) + (W2 * P2)] / (W1 + W2) + + std::array<double, 2> delta = {Y - cls[0], Z - cls[1]}; // Δ = Pp - X, X: space point of cluster (Y,Z) + std::array<double, 3> CCp = {C[0] + static_cast<double>(clCov[0]), C[1] + static_cast<double>(clCov[1]), C[2] + static_cast<double>(clCov[2])}; // Transformation of cluster covmat: CCp = C + Cov + std::array<double, 3> Wp = getInverseSymm2D(CCp); // Get weight matrix: Wp = CCp^-1 + + float chi2 = static_cast<float>(delta[0] * (Wp[0] * delta[0] + Wp[1] * delta[1]) + delta[1] * (Wp[1] * delta[0] + Wp[2] * delta[1])); // chi2 = tΔ * (Wp * Δ) + + // #ifdef CA_DEBUG + LOG(INFO) << "Cluster_y: " << cls[0] << " Cluster_z: " << cls[1]; + LOG(INFO) << "\t\t- Covariance cluster: Y2: " << clCov[0] << " YZ: " << clCov[1] << " Z2: " << clCov[2]; + LOG(INFO) << "\t\t- Propagated t1_y: " << pp1[0] << " t1_z: " << pp1[1]; + LOG(INFO) << "\t\t- Propagated t2_y: " << pp2[0] << " t2_z: " << pp2[1]; + LOG(INFO) << "\t\t- Covariance t1: sY2: " << c1[0] << " sYZ: " << c1[1] << " sZ2: " << c1[2]; + LOG(INFO) << "\t\t- Covariance t2: sY2: " << c2[0] << " sYZ: " << c2[1] << " sZ2: " << c2[2]; + LOG(INFO) << "Smoother prediction Y: " << Y << " Z: " << Z; + LOG(INFO) << "\t\t- Delta_y: " << delta[0] << " Delta_z: " << delta[1]; + LOG(INFO) << "\t\t- Covariance Pr: Y2: " << C[0] << " YZ: " << C[1] << " Z2: " << C[2]; + LOG(INFO) << "\t\t- predicted chi2 t1: " << firstTrack.getPredictedChi2(cls, clCov); + LOG(INFO) << "\t\t- predicted chi2 t2: " << secondTrack.getPredictedChi2(cls, clCov); + // #endif + return chi2; +} + +template <unsigned int D> +bool Smoother<D>::testCluster(const int clusterId, const ROframe& event) +{ + if (!mInitStatus) { + return false; + } + auto propInstance = o2::base::Propagator::Instance(); + const TrackingFrameInfo& testTf = event.getTrackingFrameInfoOnLayer(mLayerToSmooth).at(clusterId); + + bool statusOutw{false}; + bool statusInw{false}; + + // Prediction on the previously outwards-propagated track is done on a copy, as the process seems to be not reversible + auto outwardsClone = mOutwardsTrack; + statusOutw = outwardsClone.rotate(testTf.alphaTrackingFrame); + statusOutw &= propInstance->propagateToX(outwardsClone, + testTf.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + + // Prediction on the previously inwards-propagated track is done on a copy, as the process seems to be not reversible + auto inwardsClone = mInwardsTrack; + statusInw = inwardsClone.rotate(testTf.alphaTrackingFrame); + statusInw &= propInstance->propagateToX(inwardsClone, + testTf.xTrackingFrame, + mBz, + o2::base::PropagatorImpl<float>::MAX_SIN_PHI, + o2::base::PropagatorImpl<float>::MAX_STEP, + mCorr); + bool testStatus = statusOutw && statusInw; + if (!(statusOutw && statusInw)) { + LOG(WARNING) << "Failed propagation in smoother!"; + return false; + } + + // Compute weighted local chi2 + mLastChi2 = computeSmoothedPredictedChi2(inwardsClone, outwardsClone, testTf.positionTrackingFrame, testTf.covarianceTrackingFrame); + LOG(INFO) << "Smoothed chi2 on tested cluster: " << mLastChi2; + + return true; +} + +template class Smoother<7>; + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/StandaloneDebugger.cxx b/Detectors/ITSMFT/ITS/tracking/src/StandaloneDebugger.cxx index 7a7b495946db0..84e80b02e07ce 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/StandaloneDebugger.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/StandaloneDebugger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,14 +13,12 @@ /// \brief /// \author matteo.concas@cern.ch -#include <string> -#include <iterator> #include "ITStracking/Cluster.h" #include "ITStracking/Tracklet.h" #include "ITStracking/ClusterLines.h" #include "CommonUtils/TreeStreamRedirector.h" -#include "ITStracking/ROframe.h" #include "ITStracking/StandaloneDebugger.h" + #include "TH1I.h" #include "TMath.h" @@ -42,8 +41,8 @@ StandaloneDebugger::~StandaloneDebugger() // Monte carlo oracle part int StandaloneDebugger::getEventId(int firstClusterId, int secondClusterId, ROframe* event) { - o2::MCCompLabel lblClus0 = event->getClusterLabels(0, firstClusterId); - o2::MCCompLabel lblClus1 = event->getClusterLabels(1, secondClusterId); + o2::MCCompLabel lblClus0 = *(event->getClusterLabels(0, firstClusterId).begin()); + o2::MCCompLabel lblClus1 = *(event->getClusterLabels(1, secondClusterId).begin()); return lblClus0.compare(lblClus1) == 1 ? lblClus0.getEventID() : -1; } @@ -56,15 +55,15 @@ void StandaloneDebugger::fillCombinatoricsTree(std::array<std::vector<Cluster>, assert(mTreeStream != nullptr); for (auto& combination : comb01) { - o2::MCCompLabel lblClus0 = event->getClusterLabels(0, clusters[0][combination.firstClusterIndex].clusterId); - o2::MCCompLabel lblClus1 = event->getClusterLabels(1, clusters[1][combination.secondClusterIndex].clusterId); + o2::MCCompLabel lblClus0 = *(event->getClusterLabels(0, clusters[0][combination.firstClusterIndex].clusterId).begin()); + o2::MCCompLabel lblClus1 = *(event->getClusterLabels(1, clusters[1][combination.secondClusterIndex].clusterId).begin()); float c0z{clusters[0][combination.firstClusterIndex].zCoordinate}; float c1z{clusters[1][combination.secondClusterIndex].zCoordinate}; unsigned char isValidated{lblClus0.compare(lblClus1) == 1}; (*mTreeStream) << "combinatorics01" << "tanLambda=" << combination.tanLambda - << "phi=" << combination.phiCoordinate + << "phi=" << combination.phi << "c0z=" << c0z << "c1z=" << c1z << "isValidated=" << isValidated @@ -74,15 +73,15 @@ void StandaloneDebugger::fillCombinatoricsTree(std::array<std::vector<Cluster>, } for (auto& combination : comb12) { - o2::MCCompLabel lblClus1 = event->getClusterLabels(1, clusters[1][combination.secondClusterIndex].clusterId); - o2::MCCompLabel lblClus2 = event->getClusterLabels(2, clusters[2][combination.secondClusterIndex].clusterId); + o2::MCCompLabel lblClus1 = *(event->getClusterLabels(1, clusters[1][combination.secondClusterIndex].clusterId).begin()); + o2::MCCompLabel lblClus2 = *(event->getClusterLabels(2, clusters[2][combination.secondClusterIndex].clusterId).begin()); float c1z{clusters[1][combination.firstClusterIndex].zCoordinate}; float c2z{clusters[2][combination.secondClusterIndex].zCoordinate}; unsigned char isValidated{lblClus1.compare(lblClus2) == 1}; (*mTreeStream) << "combinatorics12" << "tanLambda=" << combination.tanLambda - << "phi=" << combination.phiCoordinate + << "phi=" << combination.phi << "c1z=" << c1z << "c2z=" << c2z << "isValidated=" << isValidated @@ -102,11 +101,11 @@ void StandaloneDebugger::fillTrackletSelectionTree(std::array<std::vector<Cluste assert(mTreeStream != nullptr); int id = event->getROFrameId(); for (auto& trackletPair : allowedTracklets) { - o2::MCCompLabel lblClus0 = event->getClusterLabels(0, clusters[0][comb01[trackletPair[0]].firstClusterIndex].clusterId); - o2::MCCompLabel lblClus1 = event->getClusterLabels(1, clusters[1][comb01[trackletPair[0]].secondClusterIndex].clusterId); - o2::MCCompLabel lblClus2 = event->getClusterLabels(2, clusters[2][comb12[trackletPair[1]].secondClusterIndex].clusterId); + o2::MCCompLabel lblClus0 = *(event->getClusterLabels(0, clusters[0][comb01[trackletPair[0]].firstClusterIndex].clusterId).begin()); + o2::MCCompLabel lblClus1 = *(event->getClusterLabels(1, clusters[1][comb01[trackletPair[0]].secondClusterIndex].clusterId).begin()); + o2::MCCompLabel lblClus2 = *(event->getClusterLabels(2, clusters[2][comb12[trackletPair[1]].secondClusterIndex].clusterId).begin()); unsigned char isValidated{lblClus0.compare(lblClus1) == 1 && lblClus0.compare(lblClus2) == 1}; - float deltaPhi{comb01[trackletPair[0]].phiCoordinate - comb12[trackletPair[1]].phiCoordinate}; + float deltaPhi{comb01[trackletPair[0]].phi - comb12[trackletPair[1]].phi}; float deltaTanLambda{comb01[trackletPair[0]].tanLambda - comb12[trackletPair[1]].tanLambda}; mTreeStream->GetDirectory()->cd(); // in case of existing other open files (*mTreeStream) @@ -116,13 +115,13 @@ void StandaloneDebugger::fillTrackletSelectionTree(std::array<std::vector<Cluste << "deltaPhi=" << deltaPhi << "isValidated=" << isValidated << "cluster0z=" << clusters[0][comb01[trackletPair[0]].firstClusterIndex].zCoordinate - << "cluster0r=" << clusters[0][comb01[trackletPair[0]].firstClusterIndex].rCoordinate - << "cluster0phi=" << clusters[0][comb01[trackletPair[0]].firstClusterIndex].phiCoordinate + << "cluster0r=" << clusters[0][comb01[trackletPair[0]].firstClusterIndex].radius + << "cluster0phi=" << clusters[0][comb01[trackletPair[0]].firstClusterIndex].phi << "cluster1z=" << clusters[1][comb01[trackletPair[0]].secondClusterIndex].zCoordinate - << "cluster1r=" << clusters[1][comb01[trackletPair[0]].secondClusterIndex].rCoordinate - << "cluster1phi=" << clusters[1][comb01[trackletPair[0]].secondClusterIndex].phiCoordinate + << "cluster1r=" << clusters[1][comb01[trackletPair[0]].secondClusterIndex].radius + << "cluster1phi=" << clusters[1][comb01[trackletPair[0]].secondClusterIndex].phi << "cluster2z=" << clusters[2][comb12[trackletPair[1]].secondClusterIndex].zCoordinate - << "cluster2r=" << clusters[2][comb12[trackletPair[1]].secondClusterIndex].rCoordinate + << "cluster2r=" << clusters[2][comb12[trackletPair[1]].secondClusterIndex].radius << "lblClus0=" << lblClus0 << "lblClus1=" << lblClus1 << "lblClus2=" << lblClus2 @@ -257,5 +256,20 @@ int StandaloneDebugger::getBinIndex(const float value, const int size, const flo return std::distance(divisions.begin(), TMath::BinarySearch(divisions.begin(), divisions.end(), value)); } +// Tracker +void StandaloneDebugger::dumpTrackToBranchWithInfo(std::string branchName, o2::its::TrackITSExt track, const ROframe event, PrimaryVertexContext* pvc, const bool dumpClusters) +{ + FakeTrackInfo<7> t{pvc, event, track, dumpClusters}; + + (*mTreeStream) + << branchName.data() + << track + << "\n"; + + (*mTreeStream) + << "TracksInfo" + << t + << "\n"; +} } // namespace its } // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx new file mode 100644 index 0000000000000..30ba0f8a1001a --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -0,0 +1,363 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TimeFrame.cxx +/// \brief +/// + +#include "ITStracking/TimeFrame.h" +#include "DataFormatsITSMFT/Cluster.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITSMFTBase/SegmentationAlpide.h" + +#include <iostream> + +namespace +{ +struct ClusterHelper { + float phi; + float r; + int bin; + int ind; +}; +} // namespace + +namespace o2 +{ +namespace its +{ + +constexpr float DefClusErrorRow = o2::itsmft::SegmentationAlpide::PitchRow * 0.5; +constexpr float DefClusErrorCol = o2::itsmft::SegmentationAlpide::PitchCol * 0.5; +constexpr float DefClusError2Row = DefClusErrorRow * DefClusErrorRow; +constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; + +TimeFrame::TimeFrame(int nLayers) +{ + mMinR.resize(nLayers, 10000.); + mMaxR.resize(nLayers, -1.); + mClusters.resize(nLayers); + mUnsortedClusters.resize(nLayers); + mTrackingFrameInfo.resize(nLayers); + mClusterExternalIndices.resize(nLayers); + mUsedClusters.resize(nLayers); + mROframesClusters.resize(nLayers, {0}); ///TBC: if resetting the timeframe is required, then this has to be done +} + +void TimeFrame::addPrimaryVertices(const std::vector<Vertex>& vertices) +{ + for (const auto& vertex : vertices) { + mPrimaryVertices.emplace_back(vertex); + const int w{vertex.getNContributors()}; + mBeamPos[0] = (mBeamPos[0] * mBeamPosWeight + vertex.getX() * w) / (mBeamPosWeight + w); + mBeamPos[1] = (mBeamPos[1] * mBeamPosWeight + vertex.getY() * w) / (mBeamPosWeight + w); + mBeamPosWeight += w; + } + mROframesPV.push_back(mPrimaryVertices.size()); +} + +int TimeFrame::loadROFrameData(const o2::itsmft::ROFRecord& rof, gsl::span<const itsmft::Cluster> clusters, + const dataformats::MCTruthContainer<MCCompLabel>* mcLabels) +{ + GeometryTGeo* geom = GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + int clusterId{0}; + + auto first = rof.getFirstEntry(); + auto clusters_in_frame = rof.getROFData(clusters); + for (auto& c : clusters_in_frame) { + int layer = geom->getLayer(c.getSensorID()); + + /// Clusters are stored in the tracking frame + auto xyz = c.getXYZGloRot(*geom); + addTrackingFrameInfoToLayer(layer, xyz.x(), xyz.y(), xyz.z(), c.getX(), geom->getSensorRefAlpha(c.getSensorID()), + std::array<float, 2>{c.getY(), c.getZ()}, + std::array<float, 3>{c.getSigmaY2(), c.getSigmaYZ(), c.getSigmaZ2()}); + + /// Rotate to the global frame + addClusterToLayer(layer, xyz.x(), xyz.y(), xyz.z(), mUnsortedClusters[layer].size()); + addClusterExternalIndexToLayer(layer, first + clusterId); + clusterId++; + } + + for (unsigned int iL{0}; iL < mUnsortedClusters.size(); ++iL) { + mROframesClusters[iL].push_back(mUnsortedClusters[iL].size()); + } + if (mcLabels) { + mClusterLabels = mcLabels; + } + mNrof++; + return clusters_in_frame.size(); +} + +int TimeFrame::loadROFrameData(gsl::span<o2::itsmft::ROFRecord> rofs, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* mcLabels) +{ + GeometryTGeo* geom = GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + + mNrof = 0; + for (int clusterId{0}; clusterId < clusters.size() && mNrof < rofs.size(); ++clusterId) { + auto& c = clusters[clusterId]; + + int layer = geom->getLayer(c.getSensorID()); + + auto pattID = c.getPatternID(); + o2::math_utils::Point3D<float> locXYZ; + float sigmaY2 = DefClusError2Row, sigmaZ2 = DefClusError2Col, sigmaYZ = 0; //Dummy COG errors (about half pixel size) + if (pattID != itsmft::CompCluster::InvalidPatternID) { + sigmaY2 = dict.getErr2X(pattID); + sigmaZ2 = dict.getErr2Z(pattID); + if (!dict.isGroup(pattID)) { + locXYZ = dict.getClusterCoordinates(c); + } else { + o2::itsmft::ClusterPattern patt(pattIt); + locXYZ = dict.getClusterCoordinates(c, patt); + } + } else { + o2::itsmft::ClusterPattern patt(pattIt); + locXYZ = dict.getClusterCoordinates(c, patt, false); + } + auto sensorID = c.getSensorID(); + // Inverse transformation to the local --> tracking + auto trkXYZ = geom->getMatrixT2L(sensorID) ^ locXYZ; + // Transformation to the local --> global + auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; + + addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), geom->getSensorRefAlpha(sensorID), + std::array<float, 2>{trkXYZ.y(), trkXYZ.z()}, + std::array<float, 3>{sigmaY2, sigmaYZ, sigmaZ2}); + + /// Rotate to the global frame + addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), mUnsortedClusters[layer].size()); + addClusterExternalIndexToLayer(layer, clusterId); + + while (mNrof < rofs.size() && clusterId >= rofs[mNrof].getFirstEntry() + rofs[mNrof].getNEntries() - 1) { + for (unsigned int iL{0}; iL < mUnsortedClusters.size(); ++iL) { + mROframesClusters[iL].push_back(mUnsortedClusters[iL].size()); + } + mNrof++; + } + } + if (mcLabels) { + mClusterLabels = mcLabels; + } + return mNrof; +} + +int TimeFrame::getTotalClusters() const +{ + size_t totalClusters{0}; + for (auto& clusters : mUnsortedClusters) { + totalClusters += clusters.size(); + } + return int(totalClusters); +} + +void TimeFrame::initialise(const int iteration, const MemoryParameters& memParam, const TrackingParameters& trkParam) +{ + if (iteration == 0) { + mTracks.clear(); + mTracksLabel.clear(); + mTracks.resize(mNrof); + mTracksLabel.resize(mNrof); + mCells.resize(trkParam.CellsPerRoad()); + mCellsLookupTable.resize(trkParam.CellsPerRoad() - 1); + mCellsNeighbours.resize(trkParam.CellsPerRoad() - 1); + mCellLabels.resize(trkParam.CellsPerRoad()); + mTracklets.resize(trkParam.TrackletsPerRoad()); + mTrackletLabels.resize(trkParam.TrackletsPerRoad()); + mTrackletsLookupTable.resize(trkParam.CellsPerRoad()); + mIndexTableUtils.setTrackingParameters(trkParam); + + for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { + if (mClusters[iLayer].size()) { + continue; + } + mClusters[iLayer].clear(); + mClusters[iLayer].resize(mUnsortedClusters[iLayer].size()); + mUsedClusters[iLayer].clear(); + mUsedClusters[iLayer].resize(mUnsortedClusters[iLayer].size(), false); + } + + mIndexTables.resize(mNrof); + std::vector<ClusterHelper> cHelper; + for (int rof{0}; rof < mNrof; ++rof) { + mIndexTables[rof].resize(trkParam.TrackletsPerRoad(), std::vector<int>(trkParam.ZBins * trkParam.PhiBins + 1, 0)); + for (int iLayer{0}; iLayer < trkParam.NLayers; ++iLayer) { + std::vector<int> clsPerBin(trkParam.PhiBins * trkParam.ZBins, 0); + + const auto unsortedClusters{getUnsortedClustersOnLayer(rof, iLayer)}; + const int clustersNum{static_cast<int>(unsortedClusters.size())}; + + cHelper.clear(); + cHelper.resize(clustersNum); + + for (int iCluster{0}; iCluster < clustersNum; ++iCluster) { + const Cluster& c = unsortedClusters[iCluster]; + ClusterHelper& h = cHelper[iCluster]; + float x = c.xCoordinate - mBeamPos[0]; + float y = c.yCoordinate - mBeamPos[1]; + float phi = math_utils::computePhi(x, y); + const int zBin{mIndexTableUtils.getZBinIndex(iLayer, c.zCoordinate)}; + int bin = mIndexTableUtils.getBinIndex(zBin, mIndexTableUtils.getPhiBinIndex(phi)); + h.phi = phi; + h.r = math_utils::hypot(x, y); + mMinR[iLayer] = o2::gpu::GPUCommonMath::Min(h.r, mMinR[iLayer]); + mMaxR[iLayer] = o2::gpu::GPUCommonMath::Max(h.r, mMaxR[iLayer]); + h.bin = bin; + h.ind = clsPerBin[bin]++; + } + std::vector<int> lutPerBin(clsPerBin.size()); + lutPerBin[0] = 0; + for (unsigned int iB{1}; iB < lutPerBin.size(); ++iB) { + lutPerBin[iB] = lutPerBin[iB - 1] + clsPerBin[iB - 1]; + } + + auto clusters2beSorted{getClustersOnLayer(rof, iLayer)}; + for (int iCluster{0}; iCluster < clustersNum; ++iCluster) { + const ClusterHelper& h = cHelper[iCluster]; + + Cluster& c = clusters2beSorted[lutPerBin[h.bin] + h.ind]; + c = unsortedClusters[iCluster]; + c.phi = h.phi; + c.radius = h.r; + c.indexTableBinIndex = h.bin; + } + + if (iLayer > 0) { + for (unsigned int iB{0}; iB < clsPerBin.size(); ++iB) { + mIndexTables[rof][iLayer - 1][iB] = lutPerBin[iB]; + } + for (auto iB{clsPerBin.size()}; iB < (int)mIndexTables[rof][iLayer - 1].size(); iB++) { + mIndexTables[rof][iLayer - 1][iB] = clustersNum; + } + } + } + } + } + + mRoads.clear(); + + for (unsigned int iLayer{0}; iLayer < mTracklets.size(); ++iLayer) { + mTracklets[iLayer].clear(); + mTrackletLabels[iLayer].clear(); + if (iLayer < mCells.size()) { + mCells[iLayer].clear(); + mTrackletsLookupTable[iLayer].clear(); + mTrackletsLookupTable[iLayer].resize(mClusters[iLayer + 1].size(), 0); + mCellLabels[iLayer].clear(); + } + + if (iLayer < mCells.size() - 1) { + mCellsLookupTable[iLayer].clear(); + mCellsNeighbours[iLayer].clear(); + } + } +} + +void TimeFrame::checkTrackletLUTs() +{ + for (uint32_t iLayer{0}; iLayer < getTracklets().size(); ++iLayer) { + int prev{-1}; + int count{0}; + for (uint32_t iTracklet{0}; iTracklet < getTracklets()[iLayer].size(); ++iTracklet) { + auto& trk = getTracklets()[iLayer][iTracklet]; + int currentId{trk.firstClusterIndex}; + if (currentId < prev) { + std::cout << "First Cluster Index not increasing monotonically on L:T:ID:Prev " << iLayer << "\t" << iTracklet << "\t" << currentId << "\t" << prev << std::endl; + } else if (currentId == prev) { + count++; + } else { + if (iLayer > 0) { + auto& lut{getTrackletsLookupTable()[iLayer - 1]}; + if (count != lut[prev + 1] - lut[prev]) { + std::cout << "LUT count broken " << iLayer - 1 << "\t" << prev << "\t" << count << "\t" << lut[prev + 1] << "\t" << lut[prev] << std::endl; + } + } + count = 1; + } + prev = currentId; + if (iLayer > 0) { + auto& lut{getTrackletsLookupTable()[iLayer - 1]}; + if (iTracklet >= lut[currentId + 1] || iTracklet < lut[currentId]) { + std::cout << "LUT broken: " << iLayer - 1 << "\t" << currentId << "\t" << iTracklet << std::endl; + } + } + } + } +} + +void TimeFrame::printTrackletLUTonLayer(int i) +{ + std::cout << "--------" << std::endl + << "Tracklet LUT " << i << std::endl; + for (int j : mTrackletsLookupTable[i]) { + std::cout << j << "\t"; + } + std::cout << "\n--------" << std::endl + << std::endl; +} + +void TimeFrame::printCellLUTonLayer(int i) +{ + std::cout << "--------" << std::endl + << "Cell LUT " << i << std::endl; + for (int j : mCellsLookupTable[i]) { + std::cout << j << "\t"; + } + std::cout << "\n--------" << std::endl + << std::endl; +} + +void TimeFrame::printTrackletLUTs() +{ + for (unsigned int i{0}; i < mTrackletsLookupTable.size(); ++i) { + printTrackletLUTonLayer(i); + } +} + +void TimeFrame::printCellLUTs() +{ + for (unsigned int i{0}; i < mCellsLookupTable.size(); ++i) { + printCellLUTonLayer(i); + } +} + +void TimeFrame::printVertices() +{ + std::cout << "Vertices in ROF (nROF = " << mNrof << ", lut size = " << mROframesPV.size() << ")" << std::endl; + for (unsigned int iR{0}; iR < mROframesPV.size(); ++iR) { + std::cout << mROframesPV[iR] << "\t"; + } + std::cout << "\n\n Vertices:" << std::endl; + for (unsigned int iV{0}; iV < mPrimaryVertices.size(); ++iV) { + std::cout << mPrimaryVertices[iV].getX() << "\t" << mPrimaryVertices[iV].getY() << "\t" << mPrimaryVertices[iV].getZ() << std::endl; + } + std::cout << "--------" << std::endl; +} + +void TimeFrame::printROFoffsets() +{ + std::cout << "--------" << std::endl; + for (unsigned int iLayer{0}; iLayer < mROframesClusters.size(); ++iLayer) { + std::cout << "Layer " << iLayer << std::endl; + for (auto value : mROframesClusters[iLayer]) { + std::cout << value << "\t"; + } + std::cout << std::endl; + } +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx index 1aa9483d6f84b..9f86c6f487af8 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,13 +15,14 @@ #include "ITStracking/Tracker.h" -#include "CommonConstants/MathConstants.h" #include "ITStracking/Cell.h" #include "ITStracking/Constants.h" #include "ITStracking/IndexTableUtils.h" +#include "ITStracking/Smoother.h" #include "ITStracking/Tracklet.h" #include "ITStracking/TrackerTraits.h" #include "ITStracking/TrackerTraitsCPU.h" +#include "ITStracking/TrackingConfigParam.h" #include "ReconstructionDataFormats/Track.h" #include <cassert> @@ -28,6 +30,7 @@ #include <dlfcn.h> #include <cstdlib> #include <string> +#include <climits> namespace o2 { @@ -39,46 +42,47 @@ Tracker::Tracker(o2::its::TrackerTraits* traits) /// Initialise standard configuration with 1 iteration mTrkParams.resize(1); mMemParams.resize(1); - assert(traits != nullptr); mTraits = traits; - mPrimaryVertexContext = mTraits->getPrimaryVertexContext(); + mTimeFrame = mTraits->getTimeFrame(); +#ifdef CA_DEBUG + mDebugger = new StandaloneDebugger("dbg_ITSTrackerCPU.root"); +#endif } - +#ifdef CA_DEBUG +Tracker::~Tracker() +{ + delete mDebugger; +} +#else Tracker::~Tracker() = default; +#endif -void Tracker::clustersToTracks(const ROframe& event, std::ostream& timeBenchmarkOutputStream) +void Tracker::clustersToTracks(std::function<void(std::string s)> logger) { - const int verticesNum = event.getPrimaryVerticesNum(); - mTracks.clear(); - mTrackLabels.clear(); - - for (int iVertex = 0; iVertex < verticesNum; ++iVertex) { - - float total{0.f}; - - for (int iteration = 0; iteration < mTrkParams.size(); ++iteration) { - mTraits->UpdateTrackingParameters(mTrkParams[iteration]); - /// Ugly hack -> Unifiy float3 definition in CPU and CUDA/HIP code - int pass = iteration + iVertex; /// Do not reinitialise the context if we analyse pile-up events - std::array<float, 3> pV = {event.getPrimaryVertex(iVertex).x, event.getPrimaryVertex(iVertex).y, event.getPrimaryVertex(iVertex).z}; - total += evaluateTask(&Tracker::initialisePrimaryVertexContext, "Context initialisation", - timeBenchmarkOutputStream, mMemParams[iteration], event.getClusters(), pV, pass); - total += evaluateTask(&Tracker::computeTracklets, "Tracklet finding", timeBenchmarkOutputStream); - total += evaluateTask(&Tracker::computeCells, "Cell finding", timeBenchmarkOutputStream); - total += evaluateTask(&Tracker::findCellsNeighbours, "Neighbour finding", timeBenchmarkOutputStream, iteration); - total += evaluateTask(&Tracker::findRoads, "Road finding", timeBenchmarkOutputStream, iteration); - total += evaluateTask(&Tracker::findTracks, "Track finding", timeBenchmarkOutputStream, event); - } - if (constants::DoTimeBenchmarks && fair::Logger::Logging(fair::Severity::info)) { - timeBenchmarkOutputStream << std::setw(2) << " - " - << "Vertex processing completed in: " << total << "ms" << std::endl; - } + double total{0}; + for (int iteration = 0; iteration < mTrkParams.size(); ++iteration) { + mTraits->UpdateTrackingParameters(mTrkParams[iteration]); + + total += evaluateTask(&Tracker::initialiseTimeFrame, "Context initialisation", + logger, iteration, mMemParams[iteration], mTrkParams[iteration]); + total += evaluateTask(&Tracker::computeTracklets, "Tracklet finding", logger); + total += evaluateTask(&Tracker::computeCells, "Cell finding", logger); + total += evaluateTask(&Tracker::findCellsNeighbours, "Neighbour finding", logger, iteration); + total += evaluateTask(&Tracker::findRoads, "Road finding", logger, iteration); + total += evaluateTask(&Tracker::findTracks, "Track finding", logger); + } + + std::stringstream sstream; + if (constants::DoTimeBenchmarks) { + sstream << std::setw(2) << " - " + << "Vertex processing completed in: " << total << "ms" << std::endl; } - if (event.hasMCinformation()) { - computeTracksMClabels(event); - } else { - rectifyClusterIndices(event); + logger(sstream.str()); + + if (mTimeFrame->hasMCinformation()) { + computeTracksMClabels(); } + rectifyClusterIndices(); } void Tracker::computeTracklets() @@ -93,56 +97,50 @@ void Tracker::computeCells() void Tracker::findCellsNeighbours(int& iteration) { - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad - 1; ++iLayer) { + for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad() - 1; ++iLayer) { - if (mPrimaryVertexContext->getCells()[iLayer + 1].empty() || - mPrimaryVertexContext->getCellsLookupTable()[iLayer].empty()) { + if (mTimeFrame->getCells()[iLayer + 1].empty() || + mTimeFrame->getCellsLookupTable()[iLayer].empty()) { continue; } - int layerCellsNum{static_cast<int>(mPrimaryVertexContext->getCells()[iLayer].size())}; + int layerCellsNum{static_cast<int>(mTimeFrame->getCells()[iLayer].size())}; + const int nextLayerCellsNum{static_cast<int>(mTimeFrame->getCells()[iLayer + 1].size())}; + mTimeFrame->getCellsNeighbours()[iLayer].resize(nextLayerCellsNum); for (int iCell{0}; iCell < layerCellsNum; ++iCell) { - const Cell& currentCell{mPrimaryVertexContext->getCells()[iLayer][iCell]}; + const Cell& currentCell{mTimeFrame->getCells()[iLayer][iCell]}; const int nextLayerTrackletIndex{currentCell.getSecondTrackletIndex()}; - const int nextLayerFirstCellIndex{mPrimaryVertexContext->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]}; - if (nextLayerFirstCellIndex != constants::its::UnusedIndex && - mPrimaryVertexContext->getCells()[iLayer + 1][nextLayerFirstCellIndex].getFirstTrackletIndex() == - nextLayerTrackletIndex) { - - const int nextLayerCellsNum{static_cast<int>(mPrimaryVertexContext->getCells()[iLayer + 1].size())}; - mPrimaryVertexContext->getCellsNeighbours()[iLayer].resize(nextLayerCellsNum); + const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]}; + const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]}; + for (int iNextLayerCell{nextLayerFirstCellIndex}; iNextLayerCell < nextLayerLastCellIndex; ++iNextLayerCell) { - for (int iNextLayerCell{nextLayerFirstCellIndex}; - iNextLayerCell < nextLayerCellsNum && - mPrimaryVertexContext->getCells()[iLayer + 1][iNextLayerCell].getFirstTrackletIndex() == - nextLayerTrackletIndex; - ++iNextLayerCell) { - - Cell& nextCell{mPrimaryVertexContext->getCells()[iLayer + 1][iNextLayerCell]}; - const float3 currentCellNormalVector{currentCell.getNormalVectorCoordinates()}; - const float3 nextCellNormalVector{nextCell.getNormalVectorCoordinates()}; - const float3 normalVectorsDeltaVector{currentCellNormalVector.x - nextCellNormalVector.x, - currentCellNormalVector.y - nextCellNormalVector.y, - currentCellNormalVector.z - nextCellNormalVector.z}; + Cell& nextCell{mTimeFrame->getCells()[iLayer + 1][iNextLayerCell]}; + if (nextCell.getFirstTrackletIndex() != nextLayerTrackletIndex) { + break; + } - const float deltaNormalVectorsModulus{(normalVectorsDeltaVector.x * normalVectorsDeltaVector.x) + - (normalVectorsDeltaVector.y * normalVectorsDeltaVector.y) + - (normalVectorsDeltaVector.z * normalVectorsDeltaVector.z)}; - const float deltaCurvature{std::abs(currentCell.getCurvature() - nextCell.getCurvature())}; + const float3 currentCellNormalVector{currentCell.getNormalVectorCoordinates()}; + const float3 nextCellNormalVector{nextCell.getNormalVectorCoordinates()}; + const float3 normalVectorsDeltaVector{currentCellNormalVector.x - nextCellNormalVector.x, + currentCellNormalVector.y - nextCellNormalVector.y, + currentCellNormalVector.z - nextCellNormalVector.z}; - if (deltaNormalVectorsModulus < mTrkParams[iteration].NeighbourMaxDeltaN[iLayer] && - deltaCurvature < mTrkParams[iteration].NeighbourMaxDeltaCurvature[iLayer]) { + const float deltaNormalVectorsModulus{(normalVectorsDeltaVector.x * normalVectorsDeltaVector.x) + + (normalVectorsDeltaVector.y * normalVectorsDeltaVector.y) + + (normalVectorsDeltaVector.z * normalVectorsDeltaVector.z)}; + const float deltaCurvature{std::abs(currentCell.getCurvature() - nextCell.getCurvature())}; - mPrimaryVertexContext->getCellsNeighbours()[iLayer][iNextLayerCell].push_back(iCell); + if (deltaNormalVectorsModulus < mTrkParams[iteration].NeighbourMaxDeltaN[iLayer] && + deltaCurvature < mTrkParams[iteration].NeighbourMaxDeltaCurvature[iLayer]) { - const int currentCellLevel{currentCell.getLevel()}; + mTimeFrame->getCellsNeighbours()[iLayer][iNextLayerCell].push_back(iCell); - if (currentCellLevel >= nextCell.getLevel()) { + const int currentCellLevel{currentCell.getLevel()}; - nextCell.setLevel(currentCellLevel + 1); - } + if (currentCellLevel >= nextCell.getLevel()) { + nextCell.setLevel(currentCellLevel + 1); } } } @@ -152,23 +150,23 @@ void Tracker::findCellsNeighbours(int& iteration) void Tracker::findRoads(int& iteration) { - for (int iLevel{constants::its::CellsPerRoad}; iLevel >= mTrkParams[iteration].CellMinimumLevel(); --iLevel) { - CA_DEBUGGER(int nRoads = -mPrimaryVertexContext->getRoads().size()); + for (int iLevel{mTrkParams[iteration].CellsPerRoad()}; iLevel >= mTrkParams[iteration].CellMinimumLevel(); --iLevel) { + CA_DEBUGGER(int nRoads = -mTimeFrame->getRoads().size()); const int minimumLevel{iLevel - 1}; - for (int iLayer{constants::its::CellsPerRoad - 1}; iLayer >= minimumLevel; --iLayer) { + for (int iLayer{mTrkParams[iteration].CellsPerRoad() - 1}; iLayer >= minimumLevel; --iLayer) { - const int levelCellsNum{static_cast<int>(mPrimaryVertexContext->getCells()[iLayer].size())}; + const int levelCellsNum{static_cast<int>(mTimeFrame->getCells()[iLayer].size())}; for (int iCell{0}; iCell < levelCellsNum; ++iCell) { - Cell& currentCell{mPrimaryVertexContext->getCells()[iLayer][iCell]}; + Cell& currentCell{mTimeFrame->getCells()[iLayer][iCell]}; if (currentCell.getLevel() != iLevel) { continue; } - mPrimaryVertexContext->getRoads().emplace_back(iLayer, iCell); + mTimeFrame->getRoads().emplace_back(iLayer, iCell); /// For 3 clusters roads (useful for cascades and hypertriton) we just store the single cell /// and we do not do the candidate tree traversal @@ -177,13 +175,13 @@ void Tracker::findRoads(int& iteration) } const int cellNeighboursNum{static_cast<int>( - mPrimaryVertexContext->getCellsNeighbours()[iLayer - 1][iCell].size())}; + mTimeFrame->getCellsNeighbours()[iLayer - 1][iCell].size())}; bool isFirstValidNeighbour = true; for (int iNeighbourCell{0}; iNeighbourCell < cellNeighboursNum; ++iNeighbourCell) { - const int neighbourCellId = mPrimaryVertexContext->getCellsNeighbours()[iLayer - 1][iCell][iNeighbourCell]; - const Cell& neighbourCell = mPrimaryVertexContext->getCells()[iLayer - 1][neighbourCellId]; + const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iCell][iNeighbourCell]; + const Cell& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId]; if (iLevel - 1 != neighbourCell.getLevel()) { continue; @@ -195,7 +193,7 @@ void Tracker::findRoads(int& iteration) } else { - mPrimaryVertexContext->getRoads().emplace_back(iLayer, iCell); + mTimeFrame->getRoads().emplace_back(iLayer, iCell); } traverseCellsTree(neighbourCellId, iLayer - 1); @@ -206,38 +204,37 @@ void Tracker::findRoads(int& iteration) } } #ifdef CA_DEBUG - nRoads += mPrimaryVertexContext->getRoads().size(); - std::cout << "+++ Roads with " << iLevel + 2 << " clusters: " << nRoads << " / " << mPrimaryVertexContext->getRoads().size() << std::endl; + nRoads += mTimeFrame->getRoads().size(); + std::cout << "+++ Roads with " << iLevel + 2 << " clusters: " << nRoads << " / " << mTimeFrame->getRoads().size() << std::endl; #endif } } -void Tracker::findTracks(const ROframe& event) +void Tracker::findTracks() { - mTracks.reserve(mTracks.capacity() + mPrimaryVertexContext->getRoads().size()); std::vector<TrackITSExt> tracks; - tracks.reserve(mPrimaryVertexContext->getRoads().size()); -#ifdef CA_DEBUG - std::array<int, 4> roadCounters{0, 0, 0, 0}; - std::array<int, 4> fitCounters{0, 0, 0, 0}; - std::array<int, 4> backpropagatedCounters{0, 0, 0, 0}; - std::array<int, 4> refitCounters{0, 0, 0, 0}; - std::array<int, 4> nonsharingCounters{0, 0, 0, 0}; -#endif + tracks.reserve(mTimeFrame->getRoads().size()); - for (auto& road : mPrimaryVertexContext->getRoads()) { - std::array<int, 7> clusters{constants::its::UnusedIndex, constants::its::UnusedIndex, constants::its::UnusedIndex, constants::its::UnusedIndex, constants::its::UnusedIndex, constants::its::UnusedIndex, constants::its::UnusedIndex}; + for (auto& road : mTimeFrame->getRoads()) { + std::vector<int> clusters(mTrkParams[0].NLayers, constants::its::UnusedIndex); int lastCellLevel = constants::its::UnusedIndex; CA_DEBUGGER(int nClusters = 2); + int firstTracklet{constants::its::UnusedIndex}; + std::vector<int> tracklets(mTrkParams[0].TrackletsPerRoad(), constants::its::UnusedIndex); - for (int iCell{0}; iCell < constants::its::CellsPerRoad; ++iCell) { + for (int iCell{0}; iCell < mTrkParams[0].CellsPerRoad(); ++iCell) { const int cellIndex = road[iCell]; if (cellIndex == constants::its::UnusedIndex) { continue; } else { - clusters[iCell] = mPrimaryVertexContext->getCells()[iCell][cellIndex].getFirstClusterIndex(); - clusters[iCell + 1] = mPrimaryVertexContext->getCells()[iCell][cellIndex].getSecondClusterIndex(); - clusters[iCell + 2] = mPrimaryVertexContext->getCells()[iCell][cellIndex].getThirdClusterIndex(); + if (firstTracklet == constants::its::UnusedIndex) { + firstTracklet = iCell; + } + tracklets[iCell] = mTimeFrame->getCells()[iCell][cellIndex].getFirstTrackletIndex(); + tracklets[iCell + 1] = mTimeFrame->getCells()[iCell][cellIndex].getSecondTrackletIndex(); + clusters[iCell] = mTimeFrame->getCells()[iCell][cellIndex].getFirstClusterIndex(); + clusters[iCell + 1] = mTimeFrame->getCells()[iCell][cellIndex].getSecondClusterIndex(); + clusters[iCell + 2] = mTimeFrame->getCells()[iCell][cellIndex].getThirdClusterIndex(); assert(clusters[iCell] != constants::its::UnusedIndex && clusters[iCell + 1] != constants::its::UnusedIndex && clusters[iCell + 2] != constants::its::UnusedIndex); @@ -246,6 +243,24 @@ void Tracker::findTracks(const ROframe& event) } } + CA_DEBUGGER(assert(nClusters >= mTrkParams[0].MinTrackLength)); + int count{1}; + unsigned short rof{mTimeFrame->getTracklets()[firstTracklet][tracklets[firstTracklet]].rof[0]}; + for (int iT = firstTracklet; iT < 6; ++iT) { + if (tracklets[iT] == constants::its::UnusedIndex) { + continue; + } + if (rof == mTimeFrame->getTracklets()[iT][tracklets[iT]].rof[1]) { + count++; + } else { + if (count == 1) { + rof = mTimeFrame->getTracklets()[iT][tracklets[iT]].rof[1]; + } else { + count--; + } + } + } + CA_DEBUGGER(assert(nClusters >= mTrkParams[0].MinTrackLength)); CA_DEBUGGER(roadCounters[nClusters - 4]++); @@ -256,188 +271,137 @@ void Tracker::findTracks(const ROframe& event) /// From primary vertex context index to event index (== the one used as input of the tracking code) for (int iC{0}; iC < clusters.size(); iC++) { if (clusters[iC] != constants::its::UnusedIndex) { - clusters[iC] = mPrimaryVertexContext->getClusters()[iC][clusters[iC]].clusterId; + clusters[iC] = mTimeFrame->getClusters()[iC][clusters[iC]].clusterId; } } + /// Track seed preparation. Clusters are numbered progressively from the outermost to the innermost. - const auto& cluster1_glo = event.getClustersOnLayer(lastCellLevel + 2).at(clusters[lastCellLevel + 2]); - const auto& cluster2_glo = event.getClustersOnLayer(lastCellLevel + 1).at(clusters[lastCellLevel + 1]); - const auto& cluster3_glo = event.getClustersOnLayer(lastCellLevel).at(clusters[lastCellLevel]); + const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel + 2].at(clusters[lastCellLevel + 2]); + const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel + 1].at(clusters[lastCellLevel + 1]); + const auto& cluster3_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel].at(clusters[lastCellLevel]); - const auto& cluster3_tf = event.getTrackingFrameInfoOnLayer(lastCellLevel).at(clusters[lastCellLevel]); + const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(lastCellLevel).at(clusters[lastCellLevel]); /// FIXME! TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_glo, cluster3_tf)}; for (size_t iC = 0; iC < clusters.size(); ++iC) { temporaryTrack.setExternalClusterIndex(iC, clusters[iC], clusters[iC] != constants::its::UnusedIndex); } - bool fitSuccess = fitTrack(event, temporaryTrack, constants::its::LayersNumber - 4, -1, -1); + bool fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 4, -1, -1); if (!fitSuccess) { continue; } CA_DEBUGGER(fitCounters[nClusters - 4]++); temporaryTrack.resetCovariance(); - fitSuccess = fitTrack(event, temporaryTrack, 0, constants::its::LayersNumber, 1); + fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].FitIterationMaxChi2[0]); if (!fitSuccess) { continue; } CA_DEBUGGER(backpropagatedCounters[nClusters - 4]++); temporaryTrack.getParamOut() = temporaryTrack; temporaryTrack.resetCovariance(); - fitSuccess = fitTrack(event, temporaryTrack, constants::its::LayersNumber - 1, -1, -1); + fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].FitIterationMaxChi2[1], 50.); if (!fitSuccess) { continue; } - CA_DEBUGGER(refitCounters[nClusters - 4]++); + // temporaryTrack.setROFrame(rof); tracks.emplace_back(temporaryTrack); - CA_DEBUGGER(assert(nClusters == temporaryTrack.getNumberOfClusters())); } - //mTraits->refitTracks(event.getTrackingFrameInfo(), tracks); + if (mApplySmoothing) { + // Smoothing tracks + } std::sort(tracks.begin(), tracks.end(), [](TrackITSExt& track1, TrackITSExt& track2) { return track1.isBetter(track2, 1.e6f); }); -#ifdef CA_DEBUG - std::array<int, 26> sharingMatrix{0}; - int prevNclusters = 7; - auto cumulativeIndex = [](int ncl) -> int { - constexpr int idx[5] = {0, 5, 11, 18, 26}; - return idx[ncl - 4]; - }; - std::array<int, 4> xcheckCounters{0}; -#endif - for (auto& track : tracks) { - CA_DEBUGGER(int nClusters = 0); int nShared = 0; - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { + for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) { continue; } - nShared += int(mPrimaryVertexContext->isClusterUsed(iLayer, track.getClusterIndex(iLayer))); - CA_DEBUGGER(nClusters++); + nShared += int(mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer))); } -#ifdef CA_DEBUG - assert(nClusters == track.getNumberOfClusters()); - xcheckCounters[nClusters - 4]++; - assert(nShared <= nClusters); - sharingMatrix[cumulativeIndex(nClusters) + nShared]++; -#endif - if (nShared > mTrkParams[0].ClusterSharing) { continue; } -#ifdef CA_DEBUG - nonsharingCounters[nClusters - 4]++; - assert(nClusters <= prevNclusters); - prevNclusters = nClusters; -#endif - - for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { + std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX}; + for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) { continue; } - mPrimaryVertexContext->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); + mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); + int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer)); + for (int iR{0}; iR < 3; ++iR) { + if (rofs[iR] == INT_MAX) { + rofs[iR] = currentROF; + } + if (rofs[iR] == currentROF) { + break; + } + } } - mTracks.emplace_back(track); - } - -#ifdef CA_DEBUG - std::cout << "+++ Found candidates with 4, 5, 6 and 7 clusters:\t"; - for (int count : roadCounters) - std::cout << count << "\t"; - std::cout << std::endl; - - std::cout << "+++ Fitted candidates with 4, 5, 6 and 7 clusters:\t"; - for (int count : fitCounters) - std::cout << count << "\t"; - std::cout << std::endl; - - std::cout << "+++ Backprop candidates with 4, 5, 6 and 7 clusters:\t"; - for (int count : backpropagatedCounters) - std::cout << count << "\t"; - std::cout << std::endl; - - std::cout << "+++ Refitted candidates with 4, 5, 6 and 7 clusters:\t"; - for (int count : refitCounters) - std::cout << count << "\t"; - std::cout << std::endl; - - std::cout << "+++ Cross check counters for 4, 5, 6 and 7 clusters:\t"; - for (size_t iCount = 0; iCount < refitCounters.size(); ++iCount) { - std::cout << xcheckCounters[iCount] << "\t"; - //assert(refitCounters[iCount] == xcheckCounters[iCount]); - } - std::cout << std::endl; - - std::cout << "+++ Nonsharing candidates with 4, 5, 6 and 7 clusters:\t"; - for (int count : nonsharingCounters) - std::cout << count << "\t"; - std::cout << std::endl; - - std::cout << "+++ Sharing matrix:\n"; - for (int iCl = 4; iCl <= 7; ++iCl) { - std::cout << "+++ "; - for (int iSh = cumulativeIndex(iCl); iSh < cumulativeIndex(iCl + 1); ++iSh) { - std::cout << sharingMatrix[iSh] << "\t"; + if (rofs[2] != INT_MAX) { + continue; } - std::cout << std::endl; + if (rofs[1] != INT_MAX) { + track.setNextROFbit(); + } + mTimeFrame->getTracks(std::min(rofs[0], rofs[1])).emplace_back(track); } -#endif } -bool Tracker::fitTrack(const ROframe& event, TrackITSExt& track, int start, int end, int step) +bool Tracker::fitTrack(TrackITSExt& track, int start, int end, int step, const float chi2cut, const float maxQoverPt) { + auto propInstance = o2::base::Propagator::Instance(); track.setChi2(0); + int nCl{0}; for (int iLayer{start}; iLayer != end; iLayer += step) { if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) { continue; } - const TrackingFrameInfo& trackingHit = event.getTrackingFrameInfoOnLayer(iLayer).at(track.getClusterIndex(iLayer)); + const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).at(track.getClusterIndex(iLayer)); if (!track.rotate(trackingHit.alphaTrackingFrame)) { return false; } - if (!track.propagateTo(trackingHit.xTrackingFrame, getBz())) { + if (!propInstance->propagateToX(track, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl<float>::MAX_SIN_PHI, o2::base::PropagatorImpl<float>::MAX_STEP, mCorrType)) { return false; } - track.setChi2(track.getChi2() + - track.getPredictedChi2(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)); - if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { + auto predChi2{track.getPredictedChi2(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; + if (nCl >= 3 && predChi2 > chi2cut * (nCl * 2 - 5)) { return false; } - - const float xx0 = (iLayer > 2) ? 0.008f : 0.003f; // Rough layer thickness - constexpr float radiationLength = 9.36f; // Radiation length of Si [cm] - constexpr float density = 2.33f; // Density of Si [g/cm^3] - if (!track.correctForMaterial(xx0, xx0 * radiationLength * density, true)) { + track.setChi2(track.getChi2() + predChi2); + if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { return false; } + nCl++; } - return true; + return std::abs(track.getQ2Pt()) < maxQoverPt; } void Tracker::traverseCellsTree(const int currentCellId, const int currentLayerId) { - Cell& currentCell{mPrimaryVertexContext->getCells()[currentLayerId][currentCellId]}; + Cell& currentCell{mTimeFrame->getCells()[currentLayerId][currentCellId]}; const int currentCellLevel = currentCell.getLevel(); - mPrimaryVertexContext->getRoads().back().addCell(currentLayerId, currentCellId); + mTimeFrame->getRoads().back().addCell(currentLayerId, currentCellId); if (currentLayerId > 0 && currentCellLevel > 1) { const int cellNeighboursNum{static_cast<int>( - mPrimaryVertexContext->getCellsNeighbours()[currentLayerId - 1][currentCellId].size())}; + mTimeFrame->getCellsNeighbours()[currentLayerId - 1][currentCellId].size())}; bool isFirstValidNeighbour = true; for (int iNeighbourCell{0}; iNeighbourCell < cellNeighboursNum; ++iNeighbourCell) { const int neighbourCellId = - mPrimaryVertexContext->getCellsNeighbours()[currentLayerId - 1][currentCellId][iNeighbourCell]; - const Cell& neighbourCell = mPrimaryVertexContext->getCells()[currentLayerId - 1][neighbourCellId]; + mTimeFrame->getCellsNeighbours()[currentLayerId - 1][currentCellId][iNeighbourCell]; + const Cell& neighbourCell = mTimeFrame->getCells()[currentLayerId - 1][neighbourCellId]; if (currentCellLevel - 1 != neighbourCell.getLevel()) { continue; @@ -446,7 +410,7 @@ void Tracker::traverseCellsTree(const int currentCellId, const int currentLayerI if (isFirstValidNeighbour) { isFirstValidNeighbour = false; } else { - mPrimaryVertexContext->getRoads().push_back(mPrimaryVertexContext->getRoads().back()); + mTimeFrame->getRoads().push_back(mTimeFrame->getRoads().back()); } traverseCellsTree(neighbourCellId, currentLayerId - 1); @@ -457,27 +421,25 @@ void Tracker::traverseCellsTree(const int currentCellId, const int currentLayerI // currentCell.setLevel(0); } -void Tracker::computeRoadsMClabels(const ROframe& event) +void Tracker::computeRoadsMClabels() { /// Moore's Voting Algorithm - if (!event.hasMCinformation()) { + if (!mTimeFrame->hasMCinformation()) { return; } - mPrimaryVertexContext->initialiseRoadLabels(); + mTimeFrame->initialiseRoadLabels(); - int roadsNum{static_cast<int>(mPrimaryVertexContext->getRoads().size())}; + int roadsNum{static_cast<int>(mTimeFrame->getRoads().size())}; for (int iRoad{0}; iRoad < roadsNum; ++iRoad) { - Road& currentRoad{mPrimaryVertexContext->getRoads()[iRoad]}; - MCCompLabel maxOccurrencesValue{constants::its::UnusedIndex, constants::its::UnusedIndex, - constants::its::UnusedIndex, false}; - int count{0}; + Road& currentRoad{mTimeFrame->getRoads()[iRoad]}; + std::vector<std::pair<MCCompLabel, size_t>> occurrences; bool isFakeRoad{false}; bool isFirstRoadCell{true}; - for (int iCell{0}; iCell < constants::its::CellsPerRoad; ++iCell) { + for (int iCell{0}; iCell < mTrkParams[0].CellsPerRoad(); ++iCell) { const int currentCellIndex{currentRoad[iCell]}; if (currentCellIndex == constants::its::UnusedIndex) { @@ -488,104 +450,150 @@ void Tracker::computeRoadsMClabels(const ROframe& event) } } - const Cell& currentCell{mPrimaryVertexContext->getCells()[iCell][currentCellIndex]}; + const Cell& currentCell{mTimeFrame->getCells()[iCell][currentCellIndex]}; if (isFirstRoadCell) { - const int cl0index{mPrimaryVertexContext->getClusters()[iCell][currentCell.getFirstClusterIndex()].clusterId}; - auto& cl0labs{event.getClusterLabels(iCell, cl0index)}; - maxOccurrencesValue = cl0labs; - count = 1; - - const int cl1index{mPrimaryVertexContext->getClusters()[iCell + 1][currentCell.getSecondClusterIndex()].clusterId}; - auto& cl1labs{event.getClusterLabels(iCell + 1, cl1index)}; - const int secondMonteCarlo{cl1labs.getTrackID()}; + const int cl0index{mTimeFrame->getClusters()[iCell][currentCell.getFirstClusterIndex()].clusterId}; + auto cl0labs{mTimeFrame->getClusterLabels(iCell, cl0index)}; + bool found{false}; + for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { + std::pair<o2::MCCompLabel, size_t>& occurrence = occurrences[iOcc]; + for (auto& label : cl0labs) { + if (label == occurrence.first) { + ++occurrence.second; + found = true; + // break; // uncomment to stop to the first hit + } + } + } + if (!found) { + for (auto& label : cl0labs) { + occurrences.emplace_back(label, 1); + } + } - if (secondMonteCarlo == maxOccurrencesValue) { - ++count; - } else { - maxOccurrencesValue = secondMonteCarlo; - count = 1; - isFakeRoad = true; + const int cl1index{mTimeFrame->getClusters()[iCell + 1][currentCell.getSecondClusterIndex()].clusterId}; + + const auto& cl1labs{mTimeFrame->getClusterLabels(iCell + 1, cl1index)}; + found = false; + for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { + std::pair<o2::MCCompLabel, size_t>& occurrence = occurrences[iOcc]; + for (auto& label : cl1labs) { + if (label == occurrence.first) { + ++occurrence.second; + found = true; + // break; // uncomment to stop to the first hit + } + } + } + if (!found) { + for (auto& label : cl1labs) { + occurrences.emplace_back(label, 1); + } } isFirstRoadCell = false; } - const int cl2index{mPrimaryVertexContext->getClusters()[iCell + 2][currentCell.getThirdClusterIndex()].clusterId}; - auto& cl2labs{event.getClusterLabels(iCell + 2, cl2index)}; - const int currentMonteCarlo = {cl2labs.getTrackID()}; - - if (currentMonteCarlo == maxOccurrencesValue) { - ++count; - } else { - --count; - isFakeRoad = true; + const int cl2index{mTimeFrame->getClusters()[iCell + 2][currentCell.getThirdClusterIndex()].clusterId}; + const auto& cl2labs{mTimeFrame->getClusterLabels(iCell + 2, cl2index)}; + bool found{false}; + for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { + std::pair<o2::MCCompLabel, size_t>& occurrence = occurrences[iOcc]; + for (auto& label : cl2labs) { + if (label == occurrence.first) { + ++occurrence.second; + found = true; + // break; // uncomment to stop to the first hit + } + } } - - if (count == 0) { - maxOccurrencesValue = currentMonteCarlo; - count = 1; + if (!found) { + for (auto& label : cl2labs) { + occurrences.emplace_back(label, 1); + } } } - mPrimaryVertexContext->setRoadLabel(iRoad, maxOccurrencesValue, isFakeRoad); + std::sort(occurrences.begin(), occurrences.end(), [](auto e1, auto e2) { + return e1.second > e2.second; + }); + + auto maxOccurrencesValue = occurrences[0].first; + mTimeFrame->setRoadLabel(iRoad, maxOccurrencesValue.getRawValue(), isFakeRoad); } } -void Tracker::computeTracksMClabels(const ROframe& event) +void Tracker::computeTracksMClabels() { - /// Moore's Voting Algorithm - if (!event.hasMCinformation()) { - return; - } - - int tracksNum{static_cast<int>(mTracks.size())}; - - for (auto& track : mTracks) { - MCCompLabel maxOccurrencesValue{constants::its::UnusedIndex, constants::its::UnusedIndex, - constants::its::UnusedIndex, false}; - int count{0}; - bool isFakeTrack{false}; - - for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { - const int index = track.getClusterIndex(iCluster); - if (index == constants::its::UnusedIndex) { - continue; - } + for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { + for (auto& track : mTimeFrame->getTracks(iROF)) { + std::vector<std::pair<MCCompLabel, size_t>> occurrences; + occurrences.clear(); + bool isFakeTrack{false}; - const MCCompLabel& currentLabel = event.getClusterLabels(iCluster, index); - if (currentLabel == maxOccurrencesValue) { - ++count; - } else { - if (count != 0) { // only in the first iteration count can be 0 at this point - isFakeTrack = true; - --count; + for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { + const int index = track.getClusterIndex(iCluster); + if (index == constants::its::UnusedIndex) { + continue; + } + auto labels = mTimeFrame->getClusterLabels(iCluster, index); + bool found{false}; + for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { + std::pair<o2::MCCompLabel, size_t>& occurrence = occurrences[iOcc]; + for (auto& label : labels) { + if (label == occurrence.first) { + ++occurrence.second; + found = true; + // break; // uncomment to stop to the first hit + } + } + } + if (!found) { + for (auto& label : labels) { + occurrences.emplace_back(label, 1); + } } - if (count == 0) { - maxOccurrencesValue = currentLabel; - count = 1; + } + std::sort(std::begin(occurrences), std::end(occurrences), [](auto e1, auto e2) { + return e1.second > e2.second; + }); + + auto maxOccurrencesValue = occurrences[0].first; + uint32_t pattern = track.getPattern(); + // set fake clusters pattern + for (int ic{TrackITSExt::MaxClusters}; ic--;) { + auto clid = track.getClusterIndex(ic); + if (clid != constants::its::UnusedIndex) { + auto labelsSpan = mTimeFrame->getClusterLabels(ic, clid); + for (auto& currentLabel : labelsSpan) { + if (currentLabel == maxOccurrencesValue) { + pattern |= 0x1 << (16 + ic); // set bit if correct + break; + } + } } } - track.setExternalClusterIndex(iCluster, event.getClusterExternalIndex(iCluster, index)); - } - - if (isFakeTrack) { - maxOccurrencesValue.setFakeFlag(); + track.setPattern(pattern); + if (occurrences[0].second < track.getNumberOfClusters()) { + maxOccurrencesValue.setFakeFlag(); + } + mTimeFrame->getTracksLabel(iROF).emplace_back(maxOccurrencesValue); } - mTrackLabels.emplace_back(maxOccurrencesValue); } } -void Tracker::rectifyClusterIndices(const ROframe& event) +void Tracker::rectifyClusterIndices() { - int tracksNum{static_cast<int>(mTracks.size())}; - for (auto& track : mTracks) { - for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { - const int index = track.getClusterIndex(iCluster); - if (index != constants::its::UnusedIndex) { - track.setExternalClusterIndex(iCluster, event.getClusterExternalIndex(iCluster, index)); + for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { + for (auto& track : mTimeFrame->getTracks(iROF)) { + for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { + const int index = track.getClusterIndex(iCluster); + if (index != constants::its::UnusedIndex) { + track.setExternalClusterIndex(iCluster, mTimeFrame->getClusterExternalIndex(iCluster, index)); + } } } } @@ -614,7 +622,7 @@ track::TrackParCov Tracker::buildTrackSeed(const Cluster& cluster1, const Cluste const float tgl12 = math_utils::computeTanDipAngle(x1, y1, x2, y2, z1, z2); const float tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3); - const float fy = 1. / (cluster2.rCoordinate - cluster3.rCoordinate); + const float fy = 1. / (cluster2.radius - cluster3.radius); const float& tz = fy; const float cy = (math_utils::computeCurvature(x1, y1, x2, y2 + constants::its::Resolution, x3, y3) - crv) / (constants::its::Resolution * getBz() * o2::constants::math::B2C) * @@ -629,5 +637,13 @@ track::TrackParCov Tracker::buildTrackSeed(const Cluster& cluster1, const Cluste s2 * fy * cy, 0.f, s2 * cy * cy}); } +void Tracker::getGlobalConfiguration() +{ + auto& tc = o2::its::TrackerParamConfig::Instance(); + if (tc.useMatCorrTGeo) { + setCorrType(o2::base::PropagatorImpl<float>::MatCorrType::USEMatCorrTGeo); + } +} + } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx index 5925a66c7a204..399a4c6184dde 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include "ITStracking/Constants.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/Tracklet.h" - +#include <fmt/format.h> #include "ReconstructionDataFormats/Track.h" #include <cassert> #include <iostream> @@ -31,80 +32,166 @@ namespace o2 namespace its { +constexpr int debugLevel{0}; + void TrackerTraitsCPU::computeLayerTracklets() { - PrimaryVertexContext* primaryVertexContext = mPrimaryVertexContext; - for (int iLayer{0}; iLayer < constants::its::TrackletsPerRoad; ++iLayer) { - if (primaryVertexContext->getClusters()[iLayer].empty() || primaryVertexContext->getClusters()[iLayer + 1].empty()) { - return; - } - - const float3& primaryVertex = primaryVertexContext->getPrimaryVertex(); - const int currentLayerClustersNum{static_cast<int>(primaryVertexContext->getClusters()[iLayer].size())}; - - for (int iCluster{0}; iCluster < currentLayerClustersNum; ++iCluster) { - const Cluster& currentCluster{primaryVertexContext->getClusters()[iLayer][iCluster]}; - - if (primaryVertexContext->isClusterUsed(iLayer, currentCluster.clusterId)) { - continue; - } - - const float tanLambda{(currentCluster.zCoordinate - primaryVertex.z) / currentCluster.rCoordinate}; - const float zAtRmin{tanLambda * (mPrimaryVertexContext->getMinR(iLayer + 1) - - currentCluster.rCoordinate) + - currentCluster.zCoordinate}; - const float zAtRmax{tanLambda * (mPrimaryVertexContext->getMaxR(iLayer + 1) - - currentCluster.rCoordinate) + - currentCluster.zCoordinate}; - - const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer, zAtRmin, zAtRmax, - mTrkParams.TrackletMaxDeltaZ[iLayer], mTrkParams.TrackletMaxDeltaPhi)}; - - if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { + TimeFrame* tf = mTimeFrame; + + for (int rof0{0}; rof0 < tf->getNrof(); ++rof0) { + gsl::span<const Vertex> primaryVertices = tf->getPrimaryVertices(rof0); + int minRof = (rof0 >= mTrkParams.DeltaROF) ? rof0 - mTrkParams.DeltaROF : 0; + int maxRof = (rof0 == tf->getNrof() - mTrkParams.DeltaROF) ? rof0 : rof0 + mTrkParams.DeltaROF; + for (int iLayer{0}; iLayer < mTrkParams.TrackletsPerRoad(); ++iLayer) { + gsl::span<const Cluster> layer0 = tf->getClustersOnLayer(rof0, iLayer); + if (layer0.empty()) { continue; } - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; + const int currentLayerClustersNum{static_cast<int>(layer0.size())}; + for (int iCluster{0}; iCluster < currentLayerClustersNum; ++iCluster) { + const Cluster& currentCluster{layer0[iCluster]}; + const int currentSortedIndex{tf->getSortedIndex(rof0, iLayer, iCluster)}; - if (phiBinsNum < 0) { - phiBinsNum += constants::index_table::PhiBins; - } + if (tf->isClusterUsed(iLayer, currentCluster.clusterId)) { + continue; + } - for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; - iPhiBin = ++iPhiBin == constants::index_table::PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}; - const int firstRowClusterIndex = primaryVertexContext->getIndexTables()[iLayer][firstBinIndex]; - const int maxRowClusterIndex = primaryVertexContext->getIndexTables()[iLayer][maxBinIndex]; + for (auto& primaryVertex : primaryVertices) { + const float tanLambda{(currentCluster.zCoordinate - primaryVertex.getZ()) / currentCluster.radius}; - for (int iNextLayerCluster{firstRowClusterIndex}; iNextLayerCluster < maxRowClusterIndex; - ++iNextLayerCluster) { + const float zAtRmin{tanLambda * (tf->getMinR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate}; + const float zAtRmax{tanLambda * (tf->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate}; - const Cluster& nextCluster{primaryVertexContext->getClusters()[iLayer + 1][iNextLayerCluster]}; + const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer, zAtRmin, zAtRmax, + mTrkParams.TrackletMaxDeltaZ[iLayer], mTrkParams.TrackletMaxDeltaPhi)}; - if (primaryVertexContext->isClusterUsed(iLayer + 1, nextCluster.clusterId)) { + if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { continue; } - const float deltaZ{gpu::GPUCommonMath::Abs(tanLambda * (nextCluster.rCoordinate - currentCluster.rCoordinate) + - currentCluster.zCoordinate - nextCluster.zCoordinate)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(currentCluster.phiCoordinate - nextCluster.phiCoordinate)}; + int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - if (deltaZ < mTrkParams.TrackletMaxDeltaZ[iLayer] && - (deltaPhi < mTrkParams.TrackletMaxDeltaPhi || - gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < mTrkParams.TrackletMaxDeltaPhi)) { + if (phiBinsNum < 0) { + phiBinsNum += mTrkParams.PhiBins; + } - if (iLayer > 0 && - primaryVertexContext->getTrackletsLookupTable()[iLayer - 1][iCluster] == constants::its::UnusedIndex) { + for (int rof1{minRof}; rof1 <= maxRof; ++rof1) { + gsl::span<const Cluster> layer1 = tf->getClustersOnLayer(rof1, iLayer + 1); + if (layer1.empty()) { + continue; + } - primaryVertexContext->getTrackletsLookupTable()[iLayer - 1][iCluster] = - primaryVertexContext->getTracklets()[iLayer].size(); + for (int iPhiCount{0}; iPhiCount < phiBinsNum; iPhiCount++) { + int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams.PhiBins; + const int firstBinIndex{tf->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)}; + const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}; + if constexpr (debugLevel) { + if (firstBinIndex < 0 || firstBinIndex > tf->getIndexTables(rof1)[iLayer].size() || + maxBinIndex < 0 || maxBinIndex > tf->getIndexTables(rof1)[iLayer].size()) { + std::cout << iLayer << "\t" << iCluster << "\t" << zAtRmin << "\t" << zAtRmax << "\t" << mTrkParams.TrackletMaxDeltaZ[iLayer] << "\t" << mTrkParams.TrackletMaxDeltaPhi << std::endl; + std::cout << currentCluster.zCoordinate << "\t" << primaryVertex.getZ() << "\t" << currentCluster.radius << std::endl; + std::cout << tf->getMinR(iLayer + 1) << "\t" << currentCluster.radius << "\t" << currentCluster.zCoordinate << std::endl; + std::cout << "Illegal access to IndexTable " << firstBinIndex << "\t" << maxBinIndex << "\t" << selectedBinsRect.z << "\t" << selectedBinsRect.x << std::endl; + exit(1); + } + } + const int firstRowClusterIndex = tf->getIndexTables(rof1)[iLayer][firstBinIndex]; + const int maxRowClusterIndex = tf->getIndexTables(rof1)[iLayer][maxBinIndex]; + + for (int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) { + if (iNextCluster >= (int)layer1.size()) { + break; + } + const Cluster& nextCluster{layer1[iNextCluster]}; + + if (tf->isClusterUsed(iLayer + 1, nextCluster.clusterId)) { + continue; + } + + const float deltaZ{gpu::GPUCommonMath::Abs(tanLambda * (nextCluster.radius - currentCluster.radius) + + currentCluster.zCoordinate - nextCluster.zCoordinate)}; + const float deltaPhi{gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi)}; + + if (deltaZ < mTrkParams.TrackletMaxDeltaZ[iLayer] && + (deltaPhi < mTrkParams.TrackletMaxDeltaPhi || + gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < mTrkParams.TrackletMaxDeltaPhi)) { + if (iLayer > 0) { + tf->getTrackletsLookupTable()[iLayer - 1][currentSortedIndex]++; + } + tf->getTracklets()[iLayer].emplace_back(currentSortedIndex, tf->getSortedIndex(rof1, iLayer + 1, iNextCluster), currentCluster, + nextCluster, rof0, rof1); + } + } } + } + } + } + } + } + /// Cold code, fixups + + for (int iLayer{0}; iLayer < mTrkParams.CellsPerRoad(); ++iLayer) { + /// Sort tracklets + auto& trkl{tf->getTracklets()[iLayer + 1]}; + std::sort(trkl.begin(), trkl.end(), [](const Tracklet& a, const Tracklet& b) { + return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex); + }); + /// Remove duplicates + auto& lut{tf->getTrackletsLookupTable()[iLayer]}; + int id0{-1}, id1{-1}; + std::vector<Tracklet> newTrk; + newTrk.reserve(trkl.size()); + for (auto& trk : trkl) { + if (trk.firstClusterIndex == id0 && trk.secondClusterIndex == id1) { + lut[id0]--; + } else { + id0 = trk.firstClusterIndex; + id1 = trk.secondClusterIndex; + newTrk.push_back(trk); + } + } + trkl.swap(newTrk); - primaryVertexContext->getTracklets()[iLayer].emplace_back(iCluster, iNextLayerCluster, currentCluster, - nextCluster); + /// Compute LUT + std::exclusive_scan(lut.begin(), lut.end(), lut.begin(), 0); + lut.push_back(trkl.size()); + } + /// Layer 0 is done outside the loop + std::sort(tf->getTracklets()[0].begin(), tf->getTracklets()[0].end(), [](const Tracklet& a, const Tracklet& b) { + return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex); + }); + int id0{-1}, id1{-1}; + std::vector<Tracklet> newTrk; + newTrk.reserve(tf->getTracklets()[0].size()); + for (auto& trk : tf->getTracklets()[0]) { + if (trk.firstClusterIndex != id0 || trk.secondClusterIndex != id1) { + id0 = trk.firstClusterIndex; + id1 = trk.secondClusterIndex; + newTrk.push_back(trk); + } + } + tf->getTracklets()[0].swap(newTrk); + + /// Create tracklets labels + if (tf->hasMCinformation()) { + for (int iLayer{0}; iLayer < mTrkParams.TrackletsPerRoad(); ++iLayer) { + for (auto& trk : tf->getTracklets()[iLayer]) { + MCCompLabel label; + int currentId{tf->getClusters()[iLayer][trk.firstClusterIndex].clusterId}; + int nextId{tf->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId}; + for (auto& lab1 : tf->getClusterLabels(iLayer, currentId)) { + for (auto& lab2 : tf->getClusterLabels(iLayer, nextId)) { + if (lab1 == lab2 && lab1.isValid()) { + label = lab1; + break; + } + } + if (label.isValid()) { + break; } } + tf->getTrackletsLabel(iLayer).emplace_back(label); } } } @@ -112,136 +199,146 @@ void TrackerTraitsCPU::computeLayerTracklets() void TrackerTraitsCPU::computeLayerCells() { - PrimaryVertexContext* primaryVertexContext = mPrimaryVertexContext; - for (int iLayer{0}; iLayer < constants::its::CellsPerRoad; ++iLayer) { + TimeFrame* tf = mTimeFrame; + for (int iLayer{0}; iLayer < mTrkParams.CellsPerRoad(); ++iLayer) { - if (primaryVertexContext->getTracklets()[iLayer + 1].empty() || - primaryVertexContext->getTracklets()[iLayer].empty()) { - - return; + if (tf->getTracklets()[iLayer + 1].empty() || + tf->getTracklets()[iLayer].empty()) { + continue; } - const float3& primaryVertex = primaryVertexContext->getPrimaryVertex(); - const int currentLayerTrackletsNum{static_cast<int>(primaryVertexContext->getTracklets()[iLayer].size())}; + const int currentLayerTrackletsNum{static_cast<int>(tf->getTracklets()[iLayer].size())}; for (int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) { - const Tracklet& currentTracklet{primaryVertexContext->getTracklets()[iLayer][iTracklet]}; + const Tracklet& currentTracklet{tf->getTracklets()[iLayer][iTracklet]}; const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; const int nextLayerFirstTrackletIndex{ - primaryVertexContext->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]}; - - if (nextLayerFirstTrackletIndex == constants::its::UnusedIndex) { + tf->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]}; + const int nextLayerLastTrackletIndex{ + tf->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]}; + if (nextLayerFirstTrackletIndex == nextLayerLastTrackletIndex) { continue; } - const Cluster& firstCellCluster{primaryVertexContext->getClusters()[iLayer][currentTracklet.firstClusterIndex]}; - const Cluster& secondCellCluster{ - primaryVertexContext->getClusters()[iLayer + 1][currentTracklet.secondClusterIndex]}; - const float firstCellClusterQuadraticRCoordinate{firstCellCluster.rCoordinate * firstCellCluster.rCoordinate}; - const float secondCellClusterQuadraticRCoordinate{secondCellCluster.rCoordinate * - secondCellCluster.rCoordinate}; - const float3 firstDeltaVector{secondCellCluster.xCoordinate - firstCellCluster.xCoordinate, - secondCellCluster.yCoordinate - firstCellCluster.yCoordinate, - secondCellClusterQuadraticRCoordinate - firstCellClusterQuadraticRCoordinate}; - const int nextLayerTrackletsNum{static_cast<int>(primaryVertexContext->getTracklets()[iLayer + 1].size())}; - - for (int iNextLayerTracklet{nextLayerFirstTrackletIndex}; - iNextLayerTracklet < nextLayerTrackletsNum && - primaryVertexContext->getTracklets()[iLayer + 1][iNextLayerTracklet].firstClusterIndex == - nextLayerClusterIndex; - ++iNextLayerTracklet) { - - const Tracklet& nextTracklet{primaryVertexContext->getTracklets()[iLayer + 1][iNextLayerTracklet]}; + const Cluster& cellClus0{tf->getClusters()[iLayer][currentTracklet.firstClusterIndex]}; + const Cluster& cellClus1{ + tf->getClusters()[iLayer + 1][currentTracklet.secondClusterIndex]}; + const float cellClus0R2{cellClus0.radius * cellClus0.radius}; + const float cellClus1R2{cellClus1.radius * cellClus1.radius}; + const float3 firstDeltaVector{cellClus1.xCoordinate - cellClus0.xCoordinate, + cellClus1.yCoordinate - cellClus0.yCoordinate, + cellClus1R2 - cellClus0R2}; + + for (int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) { + if (tf->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) { + break; + } + const Tracklet& nextTracklet{tf->getTracklets()[iLayer + 1][iNextTracklet]}; const float deltaTanLambda{std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; - const float deltaPhi{std::abs(currentTracklet.phiCoordinate - nextTracklet.phiCoordinate)}; + const float deltaPhi{std::abs(currentTracklet.phi - nextTracklet.phi)}; if (deltaTanLambda < mTrkParams.CellMaxDeltaTanLambda && (deltaPhi < mTrkParams.CellMaxDeltaPhi || std::abs(deltaPhi - constants::math::TwoPi) < mTrkParams.CellMaxDeltaPhi)) { const float averageTanLambda{0.5f * (currentTracklet.tanLambda + nextTracklet.tanLambda)}; - const float directionZIntersection{-averageTanLambda * firstCellCluster.rCoordinate + - firstCellCluster.zCoordinate}; - const float deltaZ{std::abs(directionZIntersection - primaryVertex.z)}; + const float directionZIntersection{-averageTanLambda * cellClus0.radius + + cellClus0.zCoordinate}; + + unsigned short romin = std::min(std::min(currentTracklet.rof[0], currentTracklet.rof[1]), nextTracklet.rof[1]); + unsigned short romax = std::max(std::max(currentTracklet.rof[0], currentTracklet.rof[1]), nextTracklet.rof[1]); + bool deltaZflag{false}; + gsl::span<const Vertex> primaryVertices{tf->getPrimaryVertices(romin, romax)}; + for (const auto& primaryVertex : primaryVertices) { + deltaZflag |= std::abs(directionZIntersection - primaryVertex.getZ()) < mTrkParams.CellMaxDeltaZ[iLayer]; + } - if (deltaZ < mTrkParams.CellMaxDeltaZ[iLayer]) { + if (deltaZflag) { const Cluster& thirdCellCluster{ - primaryVertexContext->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex]}; + tf->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex]}; - const float thirdCellClusterQuadraticRCoordinate{thirdCellCluster.rCoordinate * - thirdCellCluster.rCoordinate}; + const float thirdCellClusterR2{thirdCellCluster.radius * + thirdCellCluster.radius}; - const float3 secondDeltaVector{thirdCellCluster.xCoordinate - firstCellCluster.xCoordinate, - thirdCellCluster.yCoordinate - firstCellCluster.yCoordinate, - thirdCellClusterQuadraticRCoordinate - - firstCellClusterQuadraticRCoordinate}; + const float3 secondDeltaVector{thirdCellCluster.xCoordinate - cellClus0.xCoordinate, + thirdCellCluster.yCoordinate - cellClus0.yCoordinate, + thirdCellClusterR2 - cellClus0R2}; float3 cellPlaneNormalVector{math_utils::crossProduct(firstDeltaVector, secondDeltaVector)}; - const float vectorNorm{std::sqrt(cellPlaneNormalVector.x * cellPlaneNormalVector.x + - cellPlaneNormalVector.y * cellPlaneNormalVector.y + - cellPlaneNormalVector.z * cellPlaneNormalVector.z)}; + const float vectorNorm{std::hypot(cellPlaneNormalVector.x, cellPlaneNormalVector.y, cellPlaneNormalVector.z)}; if (vectorNorm < constants::math::FloatMinThreshold || std::abs(cellPlaneNormalVector.z) < constants::math::FloatMinThreshold) { - continue; } const float inverseVectorNorm{1.0f / vectorNorm}; - const float3 normalizedPlaneVector{cellPlaneNormalVector.x * inverseVectorNorm, - cellPlaneNormalVector.y * inverseVectorNorm, - cellPlaneNormalVector.z * inverseVectorNorm}; - const float planeDistance{-normalizedPlaneVector.x * (secondCellCluster.xCoordinate - primaryVertex.x) - - (normalizedPlaneVector.y * secondCellCluster.yCoordinate - primaryVertex.y) - - normalizedPlaneVector.z * secondCellClusterQuadraticRCoordinate}; - const float normalizedPlaneVectorQuadraticZCoordinate{normalizedPlaneVector.z * normalizedPlaneVector.z}; - const float cellTrajectoryRadius{std::sqrt( - (1.0f - normalizedPlaneVectorQuadraticZCoordinate - 4.0f * planeDistance * normalizedPlaneVector.z) / - (4.0f * normalizedPlaneVectorQuadraticZCoordinate))}; - const float2 circleCenter{-0.5f * normalizedPlaneVector.x / normalizedPlaneVector.z, - -0.5f * normalizedPlaneVector.y / normalizedPlaneVector.z}; - const float distanceOfClosestApproach{std::abs( - cellTrajectoryRadius - std::sqrt(circleCenter.x * circleCenter.x + circleCenter.y * circleCenter.y))}; - - if (distanceOfClosestApproach > - mTrkParams.CellMaxDCA[iLayer]) { - + const float3 normVect{cellPlaneNormalVector.x * inverseVectorNorm, + cellPlaneNormalVector.y * inverseVectorNorm, + cellPlaneNormalVector.z * inverseVectorNorm}; + const float planeDistance{-normVect.x * (cellClus1.xCoordinate - tf->getBeamX()) - normVect.y * (cellClus1.yCoordinate - tf->getBeamY()) - normVect.z * cellClus1R2}; + const float normVectZsquare{normVect.z * normVect.z}; + const float cellRadius{std::sqrt( + (1.0f - normVectZsquare - 4.0f * planeDistance * normVect.z) / + (4.0f * normVectZsquare))}; + const float2 circleCenter{-0.5f * normVect.x / normVect.z, + -0.5f * normVect.y / normVect.z}; + const float dca{std::abs(cellRadius - std::hypot(circleCenter.x, circleCenter.y))}; + + if (dca > mTrkParams.CellMaxDCA[iLayer]) { continue; } - const float cellTrajectoryCurvature{1.0f / cellTrajectoryRadius}; - if (iLayer > 0 && - primaryVertexContext->getCellsLookupTable()[iLayer - 1][iTracklet] == constants::its::UnusedIndex) { - - primaryVertexContext->getCellsLookupTable()[iLayer - 1][iTracklet] = - primaryVertexContext->getCells()[iLayer].size(); + const float cellTrajectoryCurvature{1.0f / cellRadius}; + if (iLayer > 0 && tf->getCellsLookupTable()[iLayer - 1].size() <= iTracklet) { + tf->getCellsLookupTable()[iLayer - 1].resize(iTracklet + 1, tf->getCells()[iLayer].size()); } - primaryVertexContext->getCells()[iLayer].emplace_back( + tf->getCells()[iLayer].emplace_back( currentTracklet.firstClusterIndex, nextTracklet.firstClusterIndex, nextTracklet.secondClusterIndex, - iTracklet, iNextLayerTracklet, normalizedPlaneVector, cellTrajectoryCurvature); + iTracklet, iNextTracklet, normVect, cellTrajectoryCurvature); } } } } + if (iLayer > 0) { + tf->getCellsLookupTable()[iLayer - 1].resize(currentLayerTrackletsNum + 1, currentLayerTrackletsNum); + } + } + + /// Create cells labels + if (tf->hasMCinformation()) { + for (int iLayer{0}; iLayer < mTrkParams.CellsPerRoad(); ++iLayer) { + for (auto& cell : tf->getCells()[iLayer]) { + MCCompLabel currentLab{tf->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]}; + MCCompLabel nextLab{tf->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]}; + tf->getCellsLabel(iLayer).emplace_back(currentLab == nextLab ? currentLab : MCCompLabel()); + } + } + } + + if constexpr (debugLevel) { + for (int iLayer{0}; iLayer < mTrkParams.CellsPerRoad(); ++iLayer) { + std::cout << "Cells on layer " << iLayer << " " << tf->getCells()[iLayer].size() << std::endl; + } } } -void TrackerTraitsCPU::refitTracks(const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) +void TrackerTraitsCPU::refitTracks(const std::vector<std::vector<TrackingFrameInfo>>& tf, std::vector<TrackITSExt>& tracks) { - std::array<const Cell*, 5> cells; - for (int iLayer = 0; iLayer < 5; iLayer++) { - cells[iLayer] = mPrimaryVertexContext->getCells()[iLayer].data(); + std::vector<const Cell*> cells; + for (int iLayer = 0; iLayer < mTrkParams.CellsPerRoad(); iLayer++) { + cells.push_back(mTimeFrame->getCells()[iLayer].data()); } - std::array<const Cluster*, 7> clusters; - for (int iLayer = 0; iLayer < 7; iLayer++) { - clusters[iLayer] = mPrimaryVertexContext->getClusters()[iLayer].data(); + std::vector<const Cluster*> clusters; + for (int iLayer = 0; iLayer < mTrkParams.NLayers; iLayer++) { + clusters.push_back(mTimeFrame->getClusters()[iLayer].data()); } - mChainRunITSTrackFit(*mChain, mPrimaryVertexContext->getRoads(), clusters, cells, tf, tracks); + mChainRunITSTrackFit(*mChain, mTimeFrame->getRoads(), clusters, cells, tf, tracks); } } // namespace its diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx index bcea094aab68b..89b4f79efe554 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,9 @@ namespace o2 namespace its { static auto& sVertexerParamITS = o2::its::VertexerParamConfig::Instance(); +static auto& sCATrackerParamITS = o2::its::TrackerParamConfig::Instance(); -O2ParamImpl(o2::its::VertexerParamConfig) +O2ParamImpl(o2::its::VertexerParamConfig); +O2ParamImpl(o2::its::TrackerParamConfig); } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h b/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h index afc832a3a6b24..2a22d8306fdb8 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,11 @@ #pragma link C++ class o2::its::ClusterLines + ; #pragma link C++ class o2::its::Tracklet + ; -#pragma link C++ class o2::its::Centroid + ; #pragma link C++ class o2::its::VertexerParamConfig + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper <o2::its::VertexerParamConfig> + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::VertexerParamConfig> + ; + +#pragma link C++ class o2::its::TrackerParamConfig + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper <o2::its::TrackerParamConfig> + ; #endif diff --git a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx b/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx index a9d456eee2c9f..b549e49dd63de 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// /// \file Vertexer.cxx -/// \brief +/// \author Matteo Concas mconcas@cern.ch /// #include "ITStracking/Vertexer.h" @@ -29,22 +30,25 @@ namespace its Vertexer::Vertexer(VertexerTraits* traits) { + if (!traits) { + LOG(FATAL) << "nullptr passed to ITS vertexer construction."; + } mTraits = traits; } -float Vertexer::clustersToVertices(ROframe& event, const bool useMc, std::ostream& timeBenchmarkOutputStream) +float Vertexer::clustersToVertices(ROframe& event, const bool useMc, std::function<void(std::string s)> logger) { ROframe* eventptr = &event; float total{0.f}; - total += evaluateTask(&Vertexer::initialiseVertexer, "Vertexer initialisation", timeBenchmarkOutputStream, eventptr); - total += evaluateTask(&Vertexer::findTracklets, "Tracklet finding", timeBenchmarkOutputStream); + total += evaluateTask(&Vertexer::initialiseVertexer, false, "Vertexer initialisation", logger, eventptr); + total += evaluateTask(&Vertexer::findTracklets, false, "Tracklet finding", logger); #ifdef _ALLOW_DEBUG_TREES_ITS_ if (useMc) { - total += evaluateTask(&Vertexer::filterMCTracklets, "MC tracklets filtering", timeBenchmarkOutputStream); + total += evaluateTask(&Vertexer::filterMCTracklets, "MC tracklets filtering", logger); } #endif - total += evaluateTask(&Vertexer::validateTracklets, "Adjacent tracklets validation", timeBenchmarkOutputStream); - total += evaluateTask(&Vertexer::findVertices, "Vertex finding", timeBenchmarkOutputStream); + total += evaluateTask(&Vertexer::validateTracklets, false, "Adjacent tracklets validation", logger); + total += evaluateTask(&Vertexer::findVertices, false, "Vertex finding", logger); return total; } diff --git a/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx index b5b843f33e24e..d21ea31585872 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,12 +23,10 @@ #include "ITStracking/ClusterLines.h" #include "ITStracking/Tracklet.h" -// debug #ifdef _ALLOW_DEBUG_TREES_ITS_ -#include "CommonUtils/TreeStreamRedirector.h" +#include "ITStracking/StandaloneDebugger.h" #include <unordered_map> #endif -// \debug #define LAYER0_TO_LAYER1 0 #define LAYER1_TO_LAYER2 1 @@ -37,31 +36,30 @@ namespace o2 namespace its { using boost::histogram::indexed; -using constants::index_table::PhiBins; -using constants::index_table::ZBins; -using constants::its::LayersRCoordinate; -using constants::its::LayersZCoordinate; using constants::math::TwoPi; -using index_table_utils::getZBinIndex; void trackleterKernelSerial( const std::vector<Cluster>& clustersNextLayer, // 0 2 const std::vector<Cluster>& clustersCurrentLayer, // 1 1 - const std::array<int, ZBins * PhiBins + 1>& indexTableNext, + const int* indexTableNext, const unsigned char pairOfLayers, const float phiCut, std::vector<Tracklet>& Tracklets, std::vector<int>& foundTracklets, + const IndexTableUtils& utils, // const ROframe* evt = nullptr, const int maxTrackletsPerCluster = static_cast<int>(2e3)) { + const int PhiBins{utils.getNphiBins()}; + const int ZBins{utils.getNzBins()}; + foundTracklets.resize(clustersCurrentLayer.size(), 0); // loop on layer1 clusters for (unsigned int iCurrentLayerClusterIndex{0}; iCurrentLayerClusterIndex < clustersCurrentLayer.size(); ++iCurrentLayerClusterIndex) { int storedTracklets{0}; const Cluster currentCluster{clustersCurrentLayer[iCurrentLayerClusterIndex]}; const int layerIndex{pairOfLayers == LAYER0_TO_LAYER1 ? 0 : 2}; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, layerIndex, 0.f, 50.f, phiCut / 2)}; + const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, layerIndex, 0.f, 50.f, phiCut / 2, utils)}; if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; if (phiBinsNum < 0) { @@ -69,13 +67,13 @@ void trackleterKernelSerial( } // loop on phi bins next layer for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect.x, iPhiBin)}; + const int firstBinIndex{utils.getBinIndex(selectedBinsRect.x, iPhiBin)}; const int firstRowClusterIndex{indexTableNext[firstBinIndex]}; const int maxRowClusterIndex{indexTableNext[firstBinIndex + ZBins]}; // loop on clusters next layer for (int iNextLayerClusterIndex{firstRowClusterIndex}; iNextLayerClusterIndex < maxRowClusterIndex && iNextLayerClusterIndex < static_cast<int>(clustersNextLayer.size()); ++iNextLayerClusterIndex) { const Cluster& nextCluster{clustersNextLayer[iNextLayerClusterIndex]}; - if (gpu::GPUCommonMath::Abs(currentCluster.phiCoordinate - nextCluster.phiCoordinate) < phiCut) { + if (o2::gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi) < phiCut) { if (storedTracklets < maxTrackletsPerCluster) { if (pairOfLayers == LAYER0_TO_LAYER1) { Tracklets.emplace_back(iNextLayerClusterIndex, iCurrentLayerClusterIndex, nextCluster, currentCluster); @@ -115,8 +113,8 @@ void trackletSelectionKernelSerial( int validTracklets{0}; for (int iTracklet12{offset12}; iTracklet12 < offset12 + foundTracklets12[iCurrentLayerClusterIndex]; ++iTracklet12) { for (int iTracklet01{offset01}; iTracklet01 < offset01 + foundTracklets01[iCurrentLayerClusterIndex]; ++iTracklet01) { - const float deltaTanLambda{gpu::GPUCommonMath::Abs(tracklets01[iTracklet01].tanLambda - tracklets12[iTracklet12].tanLambda)}; - const float deltaPhi{gpu::GPUCommonMath::Abs(tracklets01[iTracklet01].phiCoordinate - tracklets12[iTracklet12].phiCoordinate)}; + const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklets01[iTracklet01].tanLambda - tracklets12[iTracklet12].tanLambda)}; + const float deltaPhi{o2::gpu::GPUCommonMath::Abs(tracklets01[iTracklet01].phi - tracklets12[iTracklet12].phi)}; if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != maxTracklets) { assert(tracklets01[iTracklet01].secondClusterIndex == tracklets12[iTracklet12].firstClusterIndex); #ifdef _ALLOW_DEBUG_TREES_ITS_ @@ -138,9 +136,9 @@ void trackletSelectionKernelSerial( VertexerTraits::VertexerTraits() : mAverageClustersRadii{std::array<float, 3>{0.f, 0.f, 0.f}}, mMaxDirectorCosine3{0.f} { - mVrtParams.phiSpan = static_cast<int>(std::ceil(constants::index_table::PhiBins * mVrtParams.phiCut / + mVrtParams.phiSpan = static_cast<int>(std::ceil(constants::its2::PhiBins * mVrtParams.phiCut / constants::math::TwoPi)); - mVrtParams.zSpan = static_cast<int>(std::ceil(mVrtParams.zCut * constants::index_table::InverseZBinSize()[0])); + mVrtParams.zSpan = static_cast<int>(std::ceil(mVrtParams.zCut * constants::its2::InverseZBinSize()[0])); setIsGPU(false); std::cout << "[DEBUG] Creating file: dbg_ITSVertexerCPU.root" << std::endl; @@ -150,9 +148,6 @@ VertexerTraits::VertexerTraits() : mAverageClustersRadii{std::array<float, 3>{0. VertexerTraits::VertexerTraits() : mAverageClustersRadii{std::array<float, 3>{0.f, 0.f, 0.f}}, mMaxDirectorCosine3{0.f} { - mVrtParams.phiSpan = static_cast<int>(std::ceil(constants::index_table::PhiBins * mVrtParams.phiCut / - constants::math::TwoPi)); - mVrtParams.zSpan = static_cast<int>(std::ceil(mVrtParams.zCut * constants::index_table::InverseZBinSize()[0])); } #endif @@ -169,7 +164,7 @@ void VertexerTraits::reset() { for (int iLayer{0}; iLayer < constants::its::LayersNumberVertexer; ++iLayer) { mClusters[iLayer].clear(); - mIndexTables[iLayer].fill(0); + std::fill(mIndexTables[iLayer].begin(), mIndexTables[iLayer].end(), 0); } mTracklets.clear(); @@ -193,6 +188,7 @@ std::vector<int> VertexerTraits::getMClabelsLayer(const int layer) const void VertexerTraits::arrangeClusters(ROframe* event) { + const auto& LayersZCoordinate = mVrtParams.LayerZ; mEvent = event; for (int iLayer{0}; iLayer < constants::its::LayersNumberVertexer; ++iLayer) { const auto& currentLayer{event->getClustersOnLayer(iLayer)}; @@ -202,8 +198,8 @@ void VertexerTraits::arrangeClusters(ROframe* event) mClusters[iLayer].reserve(clustersNum); } for (unsigned int iCluster{0}; iCluster < clustersNum; ++iCluster) { - mClusters[iLayer].emplace_back(iLayer, currentLayer.at(iCluster)); - mAverageClustersRadii[iLayer] += mClusters[iLayer].back().rCoordinate; + mClusters[iLayer].emplace_back(iLayer, mIndexTableUtils, currentLayer.at(iCluster)); + mAverageClustersRadii[iLayer] += mClusters[iLayer].back().radius; } mAverageClustersRadii[iLayer] *= 1.f / clustersNum; @@ -221,7 +217,7 @@ void VertexerTraits::arrangeClusters(ROframe* event) previousBinIndex = currentBinIndex; } } - for (int iBin{previousBinIndex + 1}; iBin <= ZBins * PhiBins; iBin++) { + for (int iBin{previousBinIndex + 1}; iBin <= mIndexTableUtils.getNzBins() * mIndexTableUtils.getNphiBins(); iBin++) { mIndexTables[iLayer][iBin] = static_cast<int>(clustersNum); } } @@ -229,25 +225,25 @@ void VertexerTraits::arrangeClusters(ROframe* event) mDeltaRadii10 = mAverageClustersRadii[1] - mAverageClustersRadii[0]; mDeltaRadii21 = mAverageClustersRadii[2] - mAverageClustersRadii[1]; mMaxDirectorCosine3 = - LayersZCoordinate()[2] / std::sqrt(LayersZCoordinate()[2] * LayersZCoordinate()[2] + - (mDeltaRadii10 + mDeltaRadii21) * (mDeltaRadii10 + mDeltaRadii21)); + LayersZCoordinate[2] / std::hypot(LayersZCoordinate[2], mDeltaRadii10 + mDeltaRadii21); } -const std::vector<std::pair<int, int>> VertexerTraits::selectClusters(const std::array<int, ZBins * PhiBins + 1>& indexTable, - const std::array<int, 4>& selectedBinsRect) +const std::vector<std::pair<int, int>> VertexerTraits::selectClusters(const int* indexTable, + const std::array<int, 4>& selectedBinsRect, + const IndexTableUtils& utils) { std::vector<std::pair<int, int>> filteredBins{}; int phiBinsNum{selectedBinsRect[3] - selectedBinsRect[1] + 1}; if (phiBinsNum < 0) { - phiBinsNum += PhiBins; + phiBinsNum += utils.getNphiBins(); } filteredBins.reserve(phiBinsNum); for (int iPhiBin{selectedBinsRect[1]}, iPhiCount{0}; iPhiCount < phiBinsNum; - iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect[0], iPhiBin)}; + iPhiBin = ++iPhiBin == utils.getNphiBins() ? 0 : iPhiBin, iPhiCount++) { + const int firstBinIndex{utils.getBinIndex(selectedBinsRect[0], iPhiBin)}; filteredBins.emplace_back( indexTable[firstBinIndex], - index_table_utils::countRowSelectedBins(indexTable, iPhiBin, selectedBinsRect[0], selectedBinsRect[2])); + utils.countRowSelectedBins(indexTable, iPhiBin, selectedBinsRect[0], selectedBinsRect[2])); } return filteredBins; } @@ -263,8 +259,8 @@ void VertexerTraits::computeTrackletsPureMontecarlo() auto& currentCluster{mClusters[0][iCurrentLayerClusterIndex]}; for (unsigned int iNextLayerClusterIndex = 0; iNextLayerClusterIndex < mClusters[1].size(); iNextLayerClusterIndex++) { const Cluster& nextCluster{mClusters[1][iNextLayerClusterIndex]}; - const auto& lblNext = mEvent->getClusterLabels(1, nextCluster.clusterId); - const auto& lblCurr = mEvent->getClusterLabels(0, currentCluster.clusterId); + const auto& lblNext = *(mEvent->getClusterLabels(1, nextCluster.clusterId).begin()); + const auto& lblCurr = *(mEvent->getClusterLabels(0, currentCluster.clusterId).begin()); if (lblNext.compare(lblCurr) == 1 && lblCurr.getSourceID() == 0) { mComb01.emplace_back(iCurrentLayerClusterIndex, iNextLayerClusterIndex, currentCluster, nextCluster); } @@ -275,8 +271,8 @@ void VertexerTraits::computeTrackletsPureMontecarlo() auto& currentCluster{mClusters[2][iCurrentLayerClusterIndex]}; for (unsigned int iNextLayerClusterIndex = 0; iNextLayerClusterIndex < mClusters[1].size(); iNextLayerClusterIndex++) { const Cluster& nextCluster{mClusters[1][iNextLayerClusterIndex]}; - const auto& lblNext = mEvent->getClusterLabels(1, nextCluster.clusterId); - const auto& lblCurr = mEvent->getClusterLabels(2, currentCluster.clusterId); + const auto& lblNext = *(mEvent->getClusterLabels(1, nextCluster.clusterId).begin()); + const auto& lblCurr = *(mEvent->getClusterLabels(2, currentCluster.clusterId).begin()); if (lblNext.compare(lblCurr) == 1 && lblCurr.getSourceID() == 0) { mComb12.emplace_back(iNextLayerClusterIndex, iCurrentLayerClusterIndex, nextCluster, currentCluster); } @@ -312,20 +308,22 @@ void VertexerTraits::computeTracklets() trackleterKernelSerial( mClusters[0], mClusters[1], - mIndexTables[0], + mIndexTables[0].data(), LAYER0_TO_LAYER1, mVrtParams.phiCut, mComb01, - mFoundTracklets01); + mFoundTracklets01, + mIndexTableUtils); trackleterKernelSerial( mClusters[2], mClusters[1], - mIndexTables[2], + mIndexTables[2].data(), LAYER1_TO_LAYER2, mVrtParams.phiCut, mComb12, - mFoundTracklets12); + mFoundTracklets12, + mIndexTableUtils); #ifdef _ALLOW_DEBUG_TREES_ITS_ if (isDebugFlag(VertexerDebug::CombinatoricsTreeAll)) { @@ -369,8 +367,8 @@ void VertexerTraits::computeMCFiltering() { assert(mEvent != nullptr); for (size_t iTracklet{0}; iTracklet < mComb01.size(); ++iTracklet) { - const auto& lbl0 = mEvent->getClusterLabels(0, mClusters[0][mComb01[iTracklet].firstClusterIndex].clusterId); - const auto& lbl1 = mEvent->getClusterLabels(1, mClusters[1][mComb01[iTracklet].secondClusterIndex].clusterId); + const auto& lbl0 = *(mEvent->getClusterLabels(0, mClusters[0][mComb01[iTracklet].firstClusterIndex].clusterId).begin()); + const auto& lbl1 = *(mEvent->getClusterLabels(1, mClusters[1][mComb01[iTracklet].secondClusterIndex].clusterId).begin()); if (!(lbl0.compare(lbl1) == 1 && lbl0.getSourceID() == 0)) { // evtId && trackId && isValid mComb01.erase(mComb01.begin() + iTracklet); --iTracklet; // vector size has been decreased @@ -378,8 +376,8 @@ void VertexerTraits::computeMCFiltering() } for (size_t iTracklet{0}; iTracklet < mComb12.size(); ++iTracklet) { - const auto& lbl1 = mEvent->getClusterLabels(1, mClusters[1][mComb12[iTracklet].firstClusterIndex].clusterId); - const auto& lbl2 = mEvent->getClusterLabels(2, mClusters[2][mComb12[iTracklet].secondClusterIndex].clusterId); + const auto& lbl1 = *(mEvent->getClusterLabels(1, mClusters[1][mComb12[iTracklet].firstClusterIndex].clusterId).begin()); + const auto& lbl2 = *(mEvent->getClusterLabels(2, mClusters[2][mComb12[iTracklet].secondClusterIndex].clusterId).begin()); if (!(lbl1.compare(lbl2) == 1 && lbl1.getSourceID() == 0)) { // evtId && trackId && isValid mComb12.erase(mComb12.begin() + iTracklet); --iTracklet; // vector size has been decreased @@ -696,8 +694,8 @@ void VertexerTraits::filterTrackletsWithMC(std::vector<Tracklet>& tracklets01, int removed{0}; for (size_t iTrackletIndex{0}; iTrackletIndex < indices01[iFoundTrackletIndex]; ++iTrackletIndex) { const size_t iTracklet{offset + iTrackletIndex}; - const auto& lbl0 = mEvent->getClusterLabels(0, mClusters[0][tracklets01[iTracklet].firstClusterIndex].clusterId); - const auto& lbl1 = mEvent->getClusterLabels(1, mClusters[1][tracklets01[iTracklet].secondClusterIndex].clusterId); + const auto& lbl0 = *(mEvent->getClusterLabels(0, mClusters[0][tracklets01[iTracklet].firstClusterIndex].clusterId).begin()); + const auto& lbl1 = *(mEvent->getClusterLabels(1, mClusters[1][tracklets01[iTracklet].secondClusterIndex].clusterId).begin()); if (!(lbl0.compare(lbl1) == 1 && lbl0.getSourceID() == 0)) { tracklets01[iTracklet] = Tracklet(); ++removed; @@ -714,8 +712,8 @@ void VertexerTraits::filterTrackletsWithMC(std::vector<Tracklet>& tracklets01, int removed{0}; for (size_t iTrackletIndex{0}; iTrackletIndex < indices12[iFoundTrackletIndex]; ++iTrackletIndex) { const size_t iTracklet{offset + iTrackletIndex}; - const auto& lbl1 = mEvent->getClusterLabels(1, mClusters[1][tracklets12[iTracklet].firstClusterIndex].clusterId); - const auto& lbl2 = mEvent->getClusterLabels(2, mClusters[2][tracklets12[iTracklet].secondClusterIndex].clusterId); + const auto& lbl1 = *(mEvent->getClusterLabels(1, mClusters[1][tracklets12[iTracklet].firstClusterIndex].clusterId).begin()); + const auto& lbl2 = *(mEvent->getClusterLabels(2, mClusters[2][tracklets12[iTracklet].secondClusterIndex].clusterId).begin()); if (!(lbl1.compare(lbl2) == 1 && lbl1.getSourceID() == 0)) { tracklets12[iTracklet] = Tracklet(); ++removed; diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index 60788887fd94f..9bc96e9afaa59 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -1,25 +1,27 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSWorkflow SOURCES src/RecoWorkflow.cxx src/ClusterWriterWorkflow.cxx - src/DigitReaderSpec.cxx src/ClustererSpec.cxx src/ClusterWriterSpec.cxx src/TrackerSpec.cxx src/CookedTrackerSpec.cxx src/TrackWriterSpec.cxx + src/IRFrameWriterSpec.cxx + src/IRFrameReaderSpec.cxx src/TrackReaderSpec.cxx - src/VertexReaderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework + src/VertexReaderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::SimConfig O2::DataFormatsITS O2::SimulationDataFormat @@ -39,3 +41,8 @@ o2_add_executable(cluster-writer-workflow COMPONENT_NAME its PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) +o2_add_executable(cluster-reader-workflow + SOURCES src/its-cluster-reader-workflow.cxx + COMPONENT_NAME its + PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) + diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h index db85ef5b54bee..42b96786af27a 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterWorkflow.h index 3ac0c47d5e9c9..15c22f9bcf23d 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h index 475d325f7132d..e9d70c78c5c82 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h index 77e17fdd6b513..07ab9c1075359 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DigitReaderSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DigitReaderSpec.h deleted file mode 100644 index 0cbf8abb17a41..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DigitReaderSpec.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.h - -#ifndef O2_ITS_DIGITREADER -#define O2_ITS_DIGITREADER - -#include "TFile.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -class DigitReader : public Task -{ - public: - DigitReader(bool useMC) : mUseMC(useMC) {} - ~DigitReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - int mState = 0; - bool mUseMC = true; - std::unique_ptr<TFile> mFile = nullptr; -}; - -/// create a processor spec -/// read simulated ITS digits from a root file -framework::DataProcessorSpec getDigitReaderSpec(bool useMC); - -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_DIGITREADER */ diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameReaderSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameReaderSpec.h new file mode 100644 index 0000000000000..7d5caf5be6075 --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameReaderSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file IRFramesReaderSpec.h + +#ifndef O2_ITS_IRFRAMES_READER +#define O2_ITS_IRFRAMES_READER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace its +{ + +/// create a processor spec +/// read ITS IRFrames data from a root file +framework::DataProcessorSpec getIRFrameReaderSpec(); + +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameWriterSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameWriterSpec.h new file mode 100644 index 0000000000000..e6c35b9de70e2 --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/IRFrameWriterSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file IRFrameWriterSpec.h + +#ifndef O2_ITS_IRFRAMEWRITER +#define O2_ITS_IRFRAMEWRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace its +{ + +/// create a processor spec +/// write IRFrames for which ITS was reconstructed and tracks found +o2::framework::DataProcessorSpec getIRFrameWriterSpec(); + +} // namespace its +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h index 7ef7ae7ae7ca3..ba3c33d0fe0a1 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,7 @@ namespace its namespace reco_workflow { -framework::WorkflowSpec getWorkflow(bool useMC, bool useCAtracker, bool async, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU, +framework::WorkflowSpec getWorkflow(bool useMC, bool useCAtracker, const std::string& trmode, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU, bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, bool eencode = false); } diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackReaderSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackReaderSpec.h index 066b679c1c026..42f74943d08d6 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackReaderSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h index 85afb4c6a2e11..686a9f29371f4 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h index 374371f344005..a57e56df4dd47 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" +#include "ITStracking/TimeFrame.h" #include "ITStracking/Tracker.h" #include "ITStracking/TrackerTraitsCPU.h" #include "ITStracking/Vertexer.h" @@ -38,7 +40,7 @@ namespace its class TrackerDPL : public framework::Task { public: - TrackerDPL(bool isMC, bool async, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); // : mIsMC{isMC} {} + TrackerDPL(bool isMC, const std::string& trModeS, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); // : mIsMC{isMC} {} ~TrackerDPL() override = default; void init(framework::InitContext& ic) final; void run(framework::ProcessingContext& pc) final; @@ -46,8 +48,10 @@ class TrackerDPL : public framework::Task private: bool mIsMC = false; - bool mAsyncMode = false; + bool mRunVertexer = true; + std::string mMode = "sync"; o2::itsmft::TopologyDictionary mDict; + TimeFrame mTimeFrame; std::unique_ptr<o2::gpu::GPUReconstruction> mRecChain = nullptr; std::unique_ptr<parameters::GRPObject> mGRP = nullptr; std::unique_ptr<Tracker> mTracker = nullptr; @@ -57,7 +61,7 @@ class TrackerDPL : public framework::Task /// create a processor spec /// run ITS CA tracker -framework::DataProcessorSpec getTrackerSpec(bool useMC, bool async, o2::gpu::GPUDataTypes::DeviceType dType); +framework::DataProcessorSpec getTrackerSpec(bool useMC, const std::string& trModeS, o2::gpu::GPUDataTypes::DeviceType dType); } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/VertexReaderSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/VertexReaderSpec.h index 64ecd2d4453e0..f412640a702ef 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/VertexReaderSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/VertexReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx index bfd88f2189f01..9aaae6dfca236 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx index 1330f30f7e42c..ca5db7acd63e1 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx index 094b60ec5370d..010da424a582a 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -63,8 +64,8 @@ void ClustererDPL::init(InitContext& ic) mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mClusterer->loadDictionary(dictFile); LOG(INFO) << "ITSClusterer running with a provided dictionary: " << dictFile; } else { diff --git a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx index c27ac26b4a6cf..6183d397347d4 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,12 +24,13 @@ #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "DataFormatsITSMFT/ROFRecord.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "Field/MagneticField.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "ITSBase/GeometryTGeo.h" - +#include "CommonDataFormat/IRFrame.h" #include "ITStracking/ROframe.h" #include "ITStracking/IOUtils.h" #include "ITStracking/Vertexer.h" @@ -55,7 +57,7 @@ void CookedTrackerDPL::init(InitContext& ic) auto nthreads = ic.options().get<int>("nthreads"); mTracker.setNumberOfThreads(nthreads); auto filename = ic.options().get<std::string>("grp-file"); - const auto grp = o2::parameters::GRPObject::loadFrom(filename.c_str()); + const auto grp = o2::parameters::GRPObject::loadFrom(filename); if (grp) { mGRP.reset(grp); o2::base::Propagator::initFieldFromGRP(grp); @@ -74,12 +76,12 @@ void CookedTrackerDPL::init(InitContext& ic) LOG(INFO) << "ITSCookedTracker RO: continuous=" << continuous; mTracker.setContinuousMode(continuous); } else { - throw std::runtime_error(o2::utils::concat_string("Cannot retrieve GRP from the ", filename)); + throw std::runtime_error(o2::utils::Str::concat_string("Cannot retrieve GRP from the ", filename)); } std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mDict.readBinaryFile(dictFile); LOG(INFO) << "Tracker running with a provided dictionary: " << dictFile; } else { @@ -119,12 +121,16 @@ void CookedTrackerDPL::run(ProcessingContext& pc) o2::its::VertexerTraits vertexerTraits; o2::its::Vertexer vertexer(&vertexerTraits); - o2::its::ROframe event(0); + o2::its::ROframe event(0, 7); auto& vertROFvec = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(Output{"ITS", "VERTICESROF", 0, Lifetime::Timeframe}); auto& vertices = pc.outputs().make<std::vector<Vertex>>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); auto& tracks = pc.outputs().make<std::vector<o2::its::TrackITS>>(Output{"ITS", "TRACKS", 0, Lifetime::Timeframe}); auto& clusIdx = pc.outputs().make<std::vector<int>>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); + auto& irFrames = pc.outputs().make<std::vector<o2::dataformats::IRFrame>>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); + + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); // RS: this should come from CCDB + int nBCPerTF = mTracker.getContinuousMode() ? alpParams.roFrameLengthInBC : alpParams.roFrameLengthTrig; gsl::span<const unsigned char>::iterator pattIt = patterns.begin(); for (auto& rof : rofs) { @@ -147,7 +153,7 @@ void CookedTrackerDPL::run(ProcessingContext& pc) } } - vertexer.clustersToVertices(event); + vertexer.clustersToVertices(event, false, [&](std::string s) { LOG(INFO) << s; }); auto vtxVecLoc = vertexer.exportVertices(); if (multEstConf.cutMultVtxLow > 0 || multEstConf.cutMultVtxHigh > 0) { // cut was requested @@ -178,6 +184,9 @@ void CookedTrackerDPL::run(ProcessingContext& pc) } mTracker.setVertices(vtxVecLoc); mTracker.process(compClusters, it, mDict, tracks, clusIdx, rof); + if (tracks.size()) { + irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1); + } } LOG(INFO) << "ITSCookedTracker pushed " << tracks.size() << " tracks"; @@ -208,6 +217,7 @@ DataProcessorSpec getCookedTrackerSpec(bool useMC) outputs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); + outputs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); if (useMC) { inputs.emplace_back("labels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); diff --git a/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx deleted file mode 100644 index c5c4d7f77170f..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.cxx - -#include <vector> - -#include "TTree.h" - -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Logger.h" -#include "ITSWorkflow/DigitReaderSpec.h" -#include "DataFormatsITSMFT/Digit.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/IOMCTruthContainerView.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include <cmath> - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace its -{ - -void DigitReader::init(InitContext& ic) -{ - auto filename = ic.options().get<std::string>("its-digit-infile"); - mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); - if (!mFile->IsOpen()) { - LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; - mState = 0; - return; - } - mState = 1; -} - -void DigitReader::run(ProcessingContext& pc) -{ - if (mState != 1) { - return; - } - - std::unique_ptr<TTree> treeDig((TTree*)mFile->Get("o2sim")); - - if (treeDig) { - - std::vector<o2::itsmft::Digit> digits, *pdigits = &digits; - treeDig->SetBranchAddress("ITSDigit", &pdigits); - - std::vector<ROFRecord> rofs, *profs = &rofs; - treeDig->SetBranchAddress("ITSDigitROF", &profs); - - o2::dataformats::IOMCTruthContainerView* plabels = nullptr; - - std::vector<MC2ROFRecord> mc2rofs, *pmc2rofs = &mc2rofs; - if (mUseMC) { - treeDig->SetBranchAddress("ITSDigitMCTruth", &plabels); - treeDig->SetBranchAddress("ITSDigitMC2ROF", &pmc2rofs); - } - treeDig->GetEntry(0); - - LOG(INFO) << "ITSDigitReader pushed " << digits.size() << " digits, in " - << profs->size() << " RO frames"; - - pc.outputs().snapshot(Output{"ITS", "DIGITS", 0, Lifetime::Timeframe}, digits); - pc.outputs().snapshot(Output{"ITS", "DIGITSROF", 0, Lifetime::Timeframe}, *profs); - if (mUseMC) { - auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"ITS", "DIGITSMCTR", 0, Lifetime::Timeframe}); - plabels->copyandflatten(sharedlabels); - delete plabels; - pc.outputs().snapshot(Output{"ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe}, *pmc2rofs); - } - } else { - LOG(ERROR) << "Cannot read the ITS digits !"; - return; - } - mState = 2; - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); -} - -DataProcessorSpec getDigitReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("ITS", "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "DIGITSROF", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back("ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "its-digit-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, - Options{ - {"its-digit-infile", VariantType::String, "itsdigits.root", {"Name of the input file"}}}}; -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/IRFrameReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/IRFrameReaderSpec.cxx new file mode 100644 index 0000000000000..dd3b64951f604 --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/src/IRFrameReaderSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file IRFrameReaderSpec.cxx + +#include <vector> +#include <cassert> +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "ITSWorkflow/IRFrameReaderSpec.h" +#include "CommonDataFormat/IRFrame.h" +#include "CommonUtils/StringUtils.h" +#include "TFile.h" +#include "TTree.h" + +using namespace o2::framework; +using namespace o2::its; + +namespace o2 +{ +namespace its +{ + +class IRFrameReaderSpec : public o2::framework::Task +{ + public: + IRFrameReaderSpec() = default; + ~IRFrameReaderSpec() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector<o2::dataformats::IRFrame> mIRF, *mIRFInp = &mIRF; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mInputFileName = ""; + std::string mTreeName = "o2sim"; + std::string mBranchName = "IRFrames"; +}; + +void IRFrameReaderSpec::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("its-irframe-infile")); + connectTree(mInputFileName); +} + +void IRFrameReaderSpec::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mIRF.size() << " IR-frames in at entry " << ent; + pc.outputs().snapshot(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}, mIRF); + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void IRFrameReaderSpec::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mBranchName.c_str())); + + mTree->SetBranchAddress(mBranchName.c_str(), &mIRFInp); + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getIRFrameReaderSpec() +{ + std::vector<OutputSpec> outputSpec; + + return DataProcessorSpec{ + "its-irframe-reader", + Inputs{}, + Outputs{{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<IRFrameReaderSpec>()}, + Options{ + {"its-irframe-infile", VariantType::String, "o2_its_irframe.root", {"Name of the input IRFrames file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/IRFrameWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/IRFrameWriterSpec.cxx new file mode 100644 index 0000000000000..2ca82c1b0a28a --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/src/IRFrameWriterSpec.cxx @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file IRFrameWriterSpec.cxx + +#include <vector> + +#include "ITSWorkflow/IRFrameWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "CommonDataFormat/IRFrame.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +DataProcessorSpec getIRFrameWriterSpec() +{ + return MakeRootTreeWriterSpec("its-irframe-writer", + "o2_its_irframe.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with reconstructed ITS IR Frames"}, + BranchDefinition<std::vector<o2::dataformats::IRFrame>>{InputSpec{"irfr", "ITS", "IRFRAMES", 0}, "IRFrames"})(); +} + +} // namespace its +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index 1b8cbaa7525e0..ca829579c4955 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,14 +12,14 @@ /// @file RecoWorkflow.cxx #include "ITSWorkflow/RecoWorkflow.h" - -#include "ITSWorkflow/DigitReaderSpec.h" #include "ITSWorkflow/ClustererSpec.h" #include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSWorkflow/IRFrameWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/CookedTrackerSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITSMFTWorkflow/EntropyEncoderSpec.h" +#include "ITSMFTWorkflow/DigitReaderSpec.h" namespace o2 { @@ -28,14 +29,14 @@ namespace its namespace reco_workflow { -framework::WorkflowSpec getWorkflow(bool useMC, bool useCAtracker, bool async, o2::gpu::GPUDataTypes::DeviceType dtype, +framework::WorkflowSpec getWorkflow(bool useMC, bool useCAtracker, const std::string& trmode, o2::gpu::GPUDataTypes::DeviceType dtype, bool upstreamDigits, bool upstreamClusters, bool disableRootOutput, bool eencode) { framework::WorkflowSpec specs; if (!(upstreamDigits || upstreamClusters)) { - specs.emplace_back(o2::its::getDigitReaderSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSDigitReaderSpec(useMC, false, "itsdigits.root")); } if (!upstreamClusters) { @@ -43,15 +44,14 @@ framework::WorkflowSpec getWorkflow(bool useMC, bool useCAtracker, bool async, o } if (!disableRootOutput) { specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); + specs.emplace_back(o2::its::getIRFrameWriterSpec()); } if (useCAtracker) { - specs.emplace_back(o2::its::getTrackerSpec(useMC, async, dtype)); + specs.emplace_back(o2::its::getTrackerSpec(useMC, trmode, dtype)); } else { specs.emplace_back(o2::its::getCookedTrackerSpec(useMC)); } - if (!disableRootOutput) { - specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); - } if (eencode) { specs.emplace_back(o2::itsmft::getEntropyEncoderSpec("ITS")); diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackReaderSpec.cxx index bd19dd45a0060..acf93477469c8 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackReaderSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "ITSWorkflow/TrackReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; using namespace o2::its; @@ -31,7 +33,8 @@ TrackReader::TrackReader(bool useMC) void TrackReader::init(InitContext& ic) { - mInputFileName = ic.options().get<std::string>("its-tracks-infile"); + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("its-tracks-infile")); connectTree(mInputFileName); } @@ -107,7 +110,8 @@ DataProcessorSpec getITSTrackReaderSpec(bool useMC) outputSpec, AlgorithmSpec{adaptFromTask<TrackReader>(useMC)}, Options{ - {"its-tracks-infile", VariantType::String, "o2trac_its.root", {"Name of the input track file"}}}}; + {"its-tracks-infile", VariantType::String, "o2trac_its.root", {"Name of the input track file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace its diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx index f67dce3a96f79..5e3d24c63d004 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index 47bfbdc8c93de..484f505be212d 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,11 +27,13 @@ #include "ITStracking/ROframe.h" #include "ITStracking/IOUtils.h" #include "ITStracking/TrackingConfigParam.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "Field/MagneticField.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "ITSBase/GeometryTGeo.h" +#include "CommonDataFormat/IRFrame.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "ITSReconstruction/FastMultEstConfig.h" @@ -44,8 +47,9 @@ namespace its { using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; -TrackerDPL::TrackerDPL(bool isMC, bool async, o2::gpu::GPUDataTypes::DeviceType dType) : mIsMC{isMC}, mAsyncMode{async}, mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)} +TrackerDPL::TrackerDPL(bool isMC, const std::string& trModeS, o2::gpu::GPUDataTypes::DeviceType dType) : mIsMC{isMC}, mMode{trModeS}, mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)} { + std::transform(mMode.begin(), mMode.end(), mMode.begin(), [](unsigned char c) { return std::tolower(c); }); } void TrackerDPL::init(InitContext& ic) @@ -53,7 +57,7 @@ void TrackerDPL::init(InitContext& ic) mTimer.Stop(); mTimer.Reset(); auto filename = ic.options().get<std::string>("grp-file"); - const auto grp = parameters::GRPObject::loadFrom(filename.c_str()); + const auto grp = parameters::GRPObject::loadFrom(filename); if (grp) { mGRP.reset(grp); base::Propagator::initFieldFromGRP(grp); @@ -64,31 +68,80 @@ void TrackerDPL::init(InitContext& ic) geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); + std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); + std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); + if (o2::utils::Str::pathExists(matLUTFile)) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + auto* chainITS = mRecChain->AddChain<o2::gpu::GPUChainITS>(); - mRecChain->Init(); mVertexer = std::make_unique<Vertexer>(chainITS->GetITSVertexerTraits()); - mTracker = std::make_unique<Tracker>(chainITS->GetITSTrackerTraits()); - if (mAsyncMode) { - std::vector<TrackingParameters> trackParams(3); + mTracker = std::make_unique<Tracker>(new TrackerTraitsCPU(&mTimeFrame)); + + std::vector<TrackingParameters> trackParams; + std::vector<MemoryParameters> memParams; + + mRunVertexer = true; + if (mMode == "async") { + + trackParams.resize(3); trackParams[0].TrackletMaxDeltaPhi = 0.05f; - trackParams[1].TrackletMaxDeltaPhi = 0.1f; + trackParams[0].DeltaROF = 0; + trackParams[1].CopyCuts(trackParams[0], 2.); + trackParams[1].DeltaROF = 0; + trackParams[2].CopyCuts(trackParams[1], 2.); + trackParams[2].DeltaROF = 1; trackParams[2].MinTrackLength = 4; - trackParams[2].TrackletMaxDeltaPhi = 0.3; - std::vector<MemoryParameters> memParams(3); - mTracker->setParameters(memParams, trackParams); + memParams.resize(3); LOG(INFO) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; + + } else if (mMode == "sync") { + + trackParams.resize(1); + memParams.resize(1); + LOG(INFO) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; + + } else if (mMode == "cosmics") { + + mRunVertexer = false; + trackParams.resize(1); + memParams.resize(1); + trackParams[0].MinTrackLength = 4; + trackParams[0].TrackletMaxDeltaPhi = o2::its::constants::math::Pi * 0.5f; + for (int iLayer = 0; iLayer < o2::its::constants::its2::TrackletsPerRoad; iLayer++) { + trackParams[0].TrackletMaxDeltaZ[iLayer] = o2::its::constants::its2::LayersZCoordinate()[iLayer + 1]; + memParams[0].TrackletsMemoryCoefficients[iLayer] = 0.5f; + // trackParams[0].TrackletMaxDeltaZ[iLayer] = 10.f; + } + for (int iLayer = 0; iLayer < o2::its::constants::its2::CellsPerRoad; iLayer++) { + trackParams[0].CellMaxDCA[iLayer] = 10000.f; //cm + trackParams[0].CellMaxDeltaZ[iLayer] = 10000.f; //cm + memParams[0].CellsMemoryCoefficients[iLayer] = 0.001f; + } + LOG(INFO) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; + + } else { + throw std::runtime_error(fmt::format("Unsupported ITS tracking mode {:s} ", mMode)); } + mTracker->setParameters(memParams, trackParams); + mVertexer->getGlobalConfiguration(); - // mVertexer->dumpTraits(); + mTracker->getGlobalConfiguration(); + LOG(INFO) << Form("Using %s for material budget approximation", (mTracker->isMatLUT() ? "lookup table" : "TGeometry")); + double origD[3] = {0., 0., 0.}; mTracker->setBz(field->getBz(origD)); } else { - throw std::runtime_error(o2::utils::concat_string("Cannot retrieve GRP from the ", filename)); + throw std::runtime_error(o2::utils::Str::concat_string("Cannot retrieve GRP from the ", filename)); } std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mDict.readBinaryFile(dictFile); LOG(INFO) << "Tracker running with a provided dictionary: " << dictFile; } else { @@ -109,6 +162,11 @@ void TrackerDPL::run(ProcessingContext& pc) auto rofsinput = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROframes"); auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); + auto& irFrames = pc.outputs().make<std::vector<o2::dataformats::IRFrame>>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); + + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); // RS: this should come from CCDB + int nBCPerTF = alpParams.roFrameLengthInBC; + LOG(INFO) << "ITSTracker pulled " << compClusters.size() << " clusters, " << rofs.size() << " RO frames"; const dataformats::MCTruthContainer<MCCompLabel>* labels = nullptr; @@ -130,7 +188,7 @@ void TrackerDPL::run(ProcessingContext& pc) auto& vertices = pc.outputs().make<std::vector<Vertex>>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); std::uint32_t roFrame = 0; - ROframe event(0); + ROframe event(0, 7); bool continuous = mGRP->isDetContinuousReadOut("ITS"); LOG(INFO) << "ITSTracker RO: continuous=" << continuous; @@ -138,105 +196,81 @@ void TrackerDPL::run(ProcessingContext& pc) const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts FastMultEst multEst; // mult estimator - // snippet to convert found tracks to final output tracks with separate cluster indices - auto copyTracks = [](auto& tracks, auto& allTracks, auto& allClusIdx, int offset = 0) { - for (auto& trc : tracks) { - trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices - int ncl = trc.getNumberOfClusters(), nclf = 0; - uint8_t patt = 0; - for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! - auto clid = trc.getClusterIndex(ic); - if (clid >= 0) { - allClusIdx.push_back(clid + offset); - nclf++; - patt |= 0x1 << ic; - } - } - assert(ncl == nclf); - trc.setPattern(patt); - allTracks.emplace_back(trc); - } - }; - gsl::span<const unsigned char>::iterator pattIt = patterns.begin(); if (continuous) { - for (auto& rof : rofs) { - int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels); + gsl::span<itsmft::ROFRecord> rofspan(rofs); + mTimeFrame.loadROFrameData(rofspan, compClusters, pattIt, mDict, labels); + pattIt = patterns.begin(); + std::vector<int> savedROF; + auto logger = [&](std::string s) { LOG(INFO) << s; }; + float vertexerElapsedTime{0.f}; + int nclUsed = 0; + for (auto& rof : rofspan) { + + nclUsed += ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels); // prepare in advance output ROFRecords, even if this ROF to be rejected int first = allTracks.size(); - if (nclUsed) { - LOG(INFO) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed; - - // for vertices output - auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the - vtxROF.setFirstEntry(vertices.size()); // dedicated ROFRecord - vtxROF.setNEntries(0); - - if (multEstConf.cutMultClusLow > 0 || multEstConf.cutMultClusHigh > 0) { // cut was requested - auto mult = multEst.process(rof.getROFData(compClusters)); - if (mult < multEstConf.cutMultClusLow || mult > multEstConf.cutMultClusHigh) { - LOG(INFO) << "Estimated cluster mult. " << mult << " is outside of requested range " - << multEstConf.cutMultClusLow << " : " << multEstConf.cutMultClusHigh << " | ROF " << rof.getBCData(); - rof.setFirstEntry(first); - rof.setNEntries(0); - continue; - } - } + // for vertices output + auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the + vtxROF.setFirstEntry(vertices.size()); // dedicated ROFRecord + vtxROF.setNEntries(0); - mVertexer->clustersToVertices(event); - auto vtxVecLoc = mVertexer->exportVertices(); - - if (multEstConf.cutMultVtxLow > 0 || multEstConf.cutMultVtxHigh > 0) { // cut was requested - std::vector<o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>> vtxVecSel; - vtxVecSel.swap(vtxVecLoc); - for (const auto& vtx : vtxVecSel) { - if (vtx.getNContributors() < multEstConf.cutMultVtxLow || (multEstConf.cutMultVtxHigh > 0 && vtx.getNContributors() > multEstConf.cutMultVtxHigh)) { - LOG(INFO) << "Found vertex mult. " << vtx.getNContributors() << " is outside of requested range " - << multEstConf.cutMultVtxLow << " : " << multEstConf.cutMultVtxHigh << " | ROF " << rof.getBCData(); - continue; // skip vertex of unwanted multiplicity - } - vtxVecLoc.push_back(vtx); - } - if (vtxVecLoc.empty()) { // reject ROF - rof.setFirstEntry(first); - rof.setNEntries(0); - continue; - } - } + std::vector<Vertex> vtxVecLoc; + if (mRunVertexer) { + vertexerElapsedTime += mVertexer->clustersToVertices(event, false, logger); + vtxVecLoc = mVertexer->exportVertices(); + } + mTimeFrame.addPrimaryVertices(vtxVecLoc); - event.addPrimaryVertices(vtxVecLoc); - mTracker->setROFrame(roFrame); - mTracker->clustersToTracks(event); - tracks.swap(mTracker->getTracks()); - LOG(INFO) << "Found tracks: " << tracks.size(); - int number = tracks.size(); - trackLabels.swap(mTracker->getTrackLabels()); /// FIXME: assignment ctor is not optimal. - int shiftIdx = -rof.getFirstEntry(); // cluster entry!!! - rof.setFirstEntry(first); - rof.setNEntries(number); - copyTracks(tracks, allTracks, allClusIdx, shiftIdx); - std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); - trackLabels.clear(); - vtxROF.setNEntries(vtxVecLoc.size()); - for (const auto& vtx : vtxVecLoc) { - vertices.push_back(vtx); - } + vtxROF.setNEntries(vtxVecLoc.size()); + for (const auto& vtx : vtxVecLoc) { + vertices.push_back(vtx); } + savedROF.push_back(roFrame); roFrame++; } - } else { - ioutils::loadEventData(event, compClusters, pattIt, mDict, labels); - // RS: FIXME: this part seems to be not functional !!! - event.addPrimaryVertex(0.f, 0.f, 0.f); //FIXME : run an actual vertex finder ! - mTracker->clustersToTracks(event); - tracks.swap(mTracker->getTracks()); - copyTracks(tracks, allTracks, allClusIdx); - allTrackLabels.swap(mTracker->getTrackLabels()); /// FIXME: assignment ctor is not optimal. - } + LOG(INFO) << " - Vertex seeding total elapsed time: " << vertexerElapsedTime << " ms for " << nclUsed << " clusters in " << rofspan.size() << " ROFs"; + + mTracker->clustersToTracks(logger); + + for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { + + auto& rof{rofs[iROF]}; + tracks = mTimeFrame.getTracks(iROF); + trackLabels = mTimeFrame.getTracksLabel(iROF); + auto number{tracks.size()}; + auto first{allTracks.size()}; + int offset = -rof.getFirstEntry(); // cluster entry!!! + rof.setFirstEntry(first); + rof.setNEntries(number); + + if (tracks.size()) { + irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1); + } + std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); + // Some conversions that needs to be moved in the tracker internals + for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { + auto& trc{tracks[iTrk]}; + trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices + int ncl = trc.getNumberOfClusters(), nclf = 0; + for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! + auto clid = trc.getClusterIndex(ic); + if (clid >= 0) { + allClusIdx.push_back(clid); + nclf++; + } + } + assert(ncl == nclf); + allTracks.emplace_back(trc); + } + } + } //MP: no triggered mode for the time being LOG(INFO) << "ITSTracker pushed " << allTracks.size() << " tracks"; if (mIsMC) { + LOG(INFO) << "ITSTracker pushed " << allTrackLabels.size() << " track labels"; + pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}, allTrackLabels); pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); } @@ -249,7 +283,7 @@ void TrackerDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTrackerSpec(bool useMC, bool async, o2::gpu::GPUDataTypes::DeviceType dType) +DataProcessorSpec getTrackerSpec(bool useMC, const std::string& trModeS, o2::gpu::GPUDataTypes::DeviceType dType) { std::vector<InputSpec> inputs; inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); @@ -262,6 +296,7 @@ DataProcessorSpec getTrackerSpec(bool useMC, bool async, o2::gpu::GPUDataTypes:: outputs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); + outputs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); if (useMC) { inputs.emplace_back("labels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); @@ -275,10 +310,11 @@ DataProcessorSpec getTrackerSpec(bool useMC, bool async, o2::gpu::GPUDataTypes:: "its-tracker", inputs, outputs, - AlgorithmSpec{adaptFromTask<TrackerDPL>(useMC, async, dType)}, + AlgorithmSpec{adaptFromTask<TrackerDPL>(useMC, trModeS, dType)}, Options{ {"grp-file", VariantType::String, "o2sim_grp.root", {"Name of the grp file"}}, - {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}}}; + {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; } } // namespace its diff --git a/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx index 31a3d29dacfed..a0359fe6bd2d7 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/Logger.h" #include "ITSWorkflow/VertexReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; using namespace o2::its; @@ -27,7 +29,8 @@ namespace its void VertexReader::init(InitContext& ic) { - mFileName = ic.options().get<std::string>("its-vertex-infile"); + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("its-vertex-infile")); connectTree(mFileName); } @@ -73,7 +76,8 @@ DataProcessorSpec getITSVertexReaderSpec() outputSpec, AlgorithmSpec{adaptFromTask<VertexReader>()}, Options{ - {"its-vertex-infile", VariantType::String, "o2trac_its.root", {"Name of the input ITS vertex file"}}}}; + {"its-vertex-infile", VariantType::String, "o2trac_its.root", {"Name of the input ITS vertex file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace its diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-cluster-reader-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-cluster-reader-workflow.cxx new file mode 100644 index 0000000000000..8c2398bead27e --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/src/its-cluster-reader-workflow.cxx @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "with-mc", + o2::framework::VariantType::Bool, + false, + {"propagate MC labels"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "without-patterns", + o2::framework::VariantType::Bool, + false, + {"do not propagate pixel patterns"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "configKeyValues", + VariantType::String, + "", + {"Semicolon separated key=value strings"}}); +} + +#include "Framework/runDataProcessing.h" +#include "ITSMFTWorkflow/ClusterReaderSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cc) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cc.options().get<std::string>("configKeyValues")); + auto withMC = cc.options().get<bool>("with-mc"); + auto withPatterns = !cc.options().get<bool>("without-patterns"); + + specs.emplace_back(o2::itsmft::getITSClusterReaderSpec(withMC, withPatterns)); + + return specs; +} diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-cluster-writer-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-cluster-writer-workflow.cxx index 92c538b24283a..0b0dfc6ddaa14 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/its-cluster-writer-workflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/its-cluster-writer-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx index 6ca83b2160247..4bbec09bfda38 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #include "CommonUtils/ConfigurableParam.h" #include "ITStracking/TrackingConfigParam.h" #include "ITStracking/Configuration.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include "GPUO2Interface.h" #include "GPUReconstruction.h" @@ -31,14 +33,14 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, {"trackerCA", o2::framework::VariantType::Bool, false, {"use trackerCA (default: trackerCM)"}}, - {"async-phase", o2::framework::VariantType::Bool, false, {"perform multiple passes for async. phase reconstruction"}}, + {"tracking-mode", o2::framework::VariantType::String, "sync", {"sync,async,cosmics"}}, {"entropy-encoding", o2::framework::VariantType::Bool, false, {"produce entropy encoded data"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, {"gpuDevice", o2::framework::VariantType::Int, 1, {"use gpu device: CPU=1,CUDA=2,HIP=3 (default: CPU)"}}}; - std::swap(workflowOptions, options); + o2::raw::HBFUtilsInitializer::addConfigOption(options); - std::string keyvaluehelp("Semicolon separated key=value strings (e.g.: 'ITSDigitizerParam.roFrameLength=6000.;...')"); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::swap(workflowOptions, options); } // ------------------------------------------------------------------ @@ -49,22 +51,30 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { // Update the (declared) parameters if changed from the command line - o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); - // write the configuration used for the digitizer workflow - o2::conf::ConfigurableParam::writeINI("o2itsrecoflow_configuration.ini"); - auto useMC = !configcontext.options().get<bool>("disable-mc"); auto useCAtracker = configcontext.options().get<bool>("trackerCA"); - auto async = configcontext.options().get<bool>("async-phase"); + auto trmode = configcontext.options().get<std::string>("tracking-mode"); auto gpuDevice = static_cast<o2::gpu::GPUDataTypes::DeviceType>(configcontext.options().get<int>("gpuDevice")); auto extDigits = configcontext.options().get<bool>("digits-from-upstream"); auto extClusters = configcontext.options().get<bool>("clusters-from-upstream"); auto disableRootOutput = configcontext.options().get<bool>("disable-root-output"); auto eencode = configcontext.options().get<bool>("entropy-encoding"); - if (async && !useCAtracker) { - LOG(ERROR) << "Async.mode is not supported by CookedTracker, use --trackerCA"; + std::transform(trmode.begin(), trmode.end(), trmode.begin(), [](unsigned char c) { return std::tolower(c); }); + if (trmode != "sync" && !useCAtracker) { + LOG(ERROR) << "requested CookedTracker supports only sync tracking-mode, use --trackerCA"; throw std::runtime_error("incompatible options provided"); } - return std::move(o2::its::reco_workflow::getWorkflow(useMC, useCAtracker, async, gpuDevice, extDigits, extClusters, disableRootOutput, eencode)); + + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + auto wf = o2::its::reco_workflow::getWorkflow(useMC, useCAtracker, trmode, gpuDevice, extDigits, extClusters, disableRootOutput, eencode); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + // write the configuration used for the reco workflow + o2::conf::ConfigurableParam::writeINI("o2itsrecoflow_configuration.ini"); + + return std::move(wf); } diff --git a/Detectors/ITSMFT/MFT/CMakeLists.txt b/Detectors/ITSMFT/MFT/CMakeLists.txt index 5615d7d3d0381..49afa6a41d15e 100644 --- a/Detectors/ITSMFT/MFT/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/CMakeLists.txt @@ -1,17 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(simulation) add_subdirectory(macros) add_subdirectory(tracking) add_subdirectory(workflow) +add_subdirectory(calibration) +add_subdirectory(condition) o2_data_file(COPY data DESTINATION Detectors/Geometry/MFT/) diff --git a/Detectors/ITSMFT/MFT/base/CMakeLists.txt b/Detectors/ITSMFT/MFT/base/CMakeLists.txt index 63e6cb4ac4617..3a56c77547ca6 100644 --- a/Detectors/ITSMFT/MFT/base/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MFTBase SOURCES src/GeometryTGeo.cxx @@ -33,7 +34,8 @@ o2_add_library(MFTBase PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase O2::SimConfig - O2::ITSMFTSimulation ROOT::XMLIO) + O2::ITSMFTSimulation + ROOT::XMLIO) o2_target_root_dictionary(MFTBase HEADERS include/MFTBase/Constants.h diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Barrel.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Barrel.h index 087aaa23cf1d6..e5fdf9a73ec44 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Barrel.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Barrel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/ChipSegmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/ChipSegmentation.h index e66d43d310d1b..5ab22849b4074 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/ChipSegmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/ChipSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Constants.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Constants.h index 45d1aaee8c71a..34dcc70062298 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Constants.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Flex.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Flex.h index dfb91549ae972..be9b258b44a41 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Flex.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Flex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ class Flex Double_t* mFlexOrigin; LadderSegmentation* mLadderSeg; - ClassDef(Flex, 1); + ClassDefNV(Flex, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Geometry.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Geometry.h old mode 100755 new mode 100644 index ab129549446b4..73b931269ed26 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Geometry.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryBuilder.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryBuilder.h index 4fe54cdab99a1..33092f0d5a466 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryBuilder.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryBuilder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ class GeometryBuilder void buildGeometry(); private: - ClassDef(GeometryBuilder, 1); + ClassDefNV(GeometryBuilder, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h index 59d724b2f886c..a4e40dc3d12f8 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -103,8 +104,34 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo /// ladder is the matrix ID and is converted to geometry ID Int_t getNumberOfSensorsPerLadder(Int_t half, Int_t disk, Int_t ladder) const { - Int_t ladderID = mLadderIndex2Id[disk][ladder]; - return extractNumberOfSensorsPerLadder(half, disk, ladderID); + return extractNumberOfSensorsPerLadder(half, disk, ladder); + } + /// Returns the number of ladders in each disk of each half + Int_t getNumberOfLaddersPerDisk(Int_t half, Int_t disk, Int_t sensors) const + { + return extractNumberOfLadders(half, disk, sensors); + } + /// Returns the number of disks in each half + Int_t getNumberOfDisksPerHalf(Int_t half) const + { + return extractNumberOfDisks(half); + } + /// Returns the number of halfs MFT + Int_t getNumberOfHalfs() + { + return extractNumberOfHalves(); + } + + /// Returns the min number of sensors per ladder + Int_t getMinSensorsPerLadder() + { + return MinSensorsPerLadder; + } + + /// Returns the max number of sensors per ladder + Int_t getMaxSensorsPerLadder() + { + return MaxSensorsPerLadder; } /// Returns the ladder geometry ID from the matrix ID @@ -113,6 +140,21 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return mLadderIndex2Id[disk][ladder]; } + /// sym name of the MFT + static const char* composeSymNameMFT() { return o2::detectors::DetID(o2::detectors::DetID::MFT).getName(); } + + /// sym name of the half + static const char* composeSymNameHalf(int hf); + + /// Sym name of the disk at given half + static const char* composeSymNameDisk(int hf, int dk); + + /// Sym name of the ladder at given half/disk + static const char* composeSymNameLadder(int hf, int dk, int lr); + + /// Sym name of the chip in the given half/disk/ladder + static const char* composeSymNameChip(int hf, int dk, int lr, int chip); + protected: /// Determines the number of detector halves in the Geometry Int_t extractNumberOfHalves(); diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfCone.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfCone.h index 8514c28deebac..7541895f6109f 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfCone.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfCone.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,6 +29,11 @@ class HalfCone public: HalfCone(); + void makeAirVentilation(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe); + void makeMotherBoards(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe, Double_t tyMB0, Double_t tyMB0_3, Double_t tzMB0); + void makeFlexCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe); + void makeReadoutCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe); + void makePowerCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe); ~HalfCone(); @@ -37,7 +43,7 @@ class HalfCone TGeoVolumeAssembly* mHalfCone; private: - ClassDef(HalfCone, 1); + ClassDefNV(HalfCone, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDetector.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDetector.h index 8797d4b2e797b..681b41284a370 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDetector.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDetector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDisk.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDisk.h index 3ec44f196a8e8..17dce4cd6f3c0 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDisk.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDisk.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDiskSegmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDiskSegmentation.h index ad0b0b2e9d419..2f8082874fb86 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDiskSegmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfDiskSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfSegmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfSegmentation.h index 45a3efd7d6768..4a106361d7d63 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfSegmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HalfSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/HeatExchanger.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/HeatExchanger.h index 6cff3879dc02b..0e6ea9b019021 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/HeatExchanger.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/HeatExchanger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,6 +43,7 @@ class HeatExchanger void createHalfDisk3(Int_t half); void createHalfDisk4(Int_t half); void createManifold(Int_t disk); + void createCoolingPipes(Int_t half, Int_t disk); Double_t getWaterRadius() { return mRWater; } void setWaterRadius(Double_t& Rwater) { mRWater = Rwater; } @@ -138,7 +140,7 @@ class HeatExchanger Double_t mAngle4fifth[4]; // angle of torus for fifth pipe of disk 4 Double_t mRadius4fifth[4]; // radius of torus for fifth pipe of disk 4 - ClassDef(HeatExchanger, 2); + ClassDefNV(HeatExchanger, 2); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Ladder.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Ladder.h index 5c43f6589f625..7885d9dd666db 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Ladder.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Ladder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/LadderSegmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/LadderSegmentation.h index 6662a192b6481..24dcaabd7707c 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/LadderSegmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/LadderSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/MFTBaseParam.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/MFTBaseParam.h index bd981afebdfcd..ac22668b86bba 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/MFTBaseParam.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/MFTBaseParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,8 @@ struct MFTBaseParam : public o2::conf::ConfigurableParamHelper<MFTBaseParam> { bool buildPCBSupports = true; bool buildPCBs = true; bool buildPSU = true; + bool buildReadoutCables = true; + bool buildServices = true; // General configurations bool minimal = false; // Disables all elements out of MFT acceptance diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/PCBSupport.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/PCBSupport.h index ce17dd13c2a6b..c7f4d934b3302 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/PCBSupport.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/PCBSupport.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -73,7 +74,7 @@ class PCBSupport Int_t mNumberOfHoles[5]; // Number of Holes in each PCB Double_t (*mHoles[5])[3]; // Holes on each PCB - ClassDef(PCBSupport, 1); + ClassDefNV(PCBSupport, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/PatchPanel.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/PatchPanel.h index 62e36b44af61a..aa1a340711b83 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/PatchPanel.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/PatchPanel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,7 +35,7 @@ class PatchPanel TGeoVolumeAssembly* createPatchPanel(); private: - ClassDef(PatchPanel, 1); + ClassDefNV(PatchPanel, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/PowerSupplyUnit.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/PowerSupplyUnit.h index cf894f6ed66ad..fe1ec8a39f308 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/PowerSupplyUnit.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/PowerSupplyUnit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,7 +37,7 @@ class PowerSupplyUnit TGeoVolumeAssembly* create(); private: - ClassDef(PowerSupplyUnit, 2); + ClassDefNV(PowerSupplyUnit, 2); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Segmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Segmentation.h index a32a2680a9b28..9a0a08abe5dc0 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Segmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Segmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,7 +61,7 @@ class Segmentation private: TClonesArray* mHalves; ///< \brief Array of pointer to HalfSegmentation - ClassDef(Segmentation, 1); + ClassDefNV(Segmentation, 1); }; } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/Support.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/Support.h index a61575c759358..b78da4cb4c7ba 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/Support.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/Support.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -110,7 +111,7 @@ class Support Double_t mHeight_D2; Double_t (*mD2Holes[5])[2]; // Positions of D2 mm holes on disk - ClassDef(Support, 1); + ClassDefNV(Support, 1); }; //Template to reduce boilerplate for TGeo boolean operations diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/VSegmentation.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/VSegmentation.h index 6025b58703526..86be974397a48 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/VSegmentation.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/VSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/Barrel.cxx b/Detectors/ITSMFT/MFT/base/src/Barrel.cxx index c1b4ba90865c5..f666bc16a8151 100644 --- a/Detectors/ITSMFT/MFT/base/src/Barrel.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Barrel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/ChipSegmentation.cxx b/Detectors/ITSMFT/MFT/base/src/ChipSegmentation.cxx index 974d9c685078c..5eb319aad0636 100644 --- a/Detectors/ITSMFT/MFT/base/src/ChipSegmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/ChipSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/Flex.cxx b/Detectors/ITSMFT/MFT/base/src/Flex.cxx index ba1849ed1b212..62a3f23757ef5 100644 --- a/Detectors/ITSMFT/MFT/base/src/Flex.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Flex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -350,11 +351,11 @@ TGeoVolume* Flex::makeLines(Int_t nbsensors, Double_t length, Double_t widthflex length_line = length - Geometry::sConnectorOffset - TMath::Nint((iline - 6) / 3) * SegmentationAlpide::SensorSizeCols - SegmentationAlpide::SensorSizeCols / 2; - ts[iline] = new TGeoTranslation(Form("t%d", iline), length / 2 - length_line / 2 - Geometry::sConnectorOffset, - -2 * (iline - 6) * Geometry::sLineWidth + 0.5 - widthflex / 2, 0.); + ts[iline - 6] = new TGeoTranslation(Form("t%d", iline), length / 2 - length_line / 2 - Geometry::sConnectorOffset, + -2 * (iline - 6) * Geometry::sLineWidth + 0.5 - widthflex / 2, 0.); line[iline] = new TGeoBBox(Form("line%d", iline), length_line / 2, Geometry::sLineWidth / 2, thickness / 2 + Geometry::sEpsilon); - layerl[iline] = new TGeoSubtraction(layern[iline - 1], line[iline], nullptr, ts[iline]); + layerl[iline] = new TGeoSubtraction(layern[iline - 1], line[iline], nullptr, ts[iline - 6]); layern[iline] = new TGeoCompositeShape(Form("layer%d", iline), layerl[iline]); kTotalLinesNb++; } diff --git a/Detectors/ITSMFT/MFT/base/src/Geometry.cxx b/Detectors/ITSMFT/MFT/base/src/Geometry.cxx index 37e81f9ac3955..177095613caa9 100644 --- a/Detectors/ITSMFT/MFT/base/src/Geometry.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/GeometryBuilder.cxx b/Detectors/ITSMFT/MFT/base/src/GeometryBuilder.cxx index 7608c734e6a69..d2242546a7068 100644 --- a/Detectors/ITSMFT/MFT/base/src/GeometryBuilder.cxx +++ b/Detectors/ITSMFT/MFT/base/src/GeometryBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/GeometryTGeo.cxx b/Detectors/ITSMFT/MFT/base/src/GeometryTGeo.cxx index 1757e32facfff..7aaa53dcb5459 100644 --- a/Detectors/ITSMFT/MFT/base/src/GeometryTGeo.cxx +++ b/Detectors/ITSMFT/MFT/base/src/GeometryTGeo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -568,3 +569,27 @@ Int_t GeometryTGeo::getSensorIndex(Int_t halfID, Int_t diskID, Int_t ladderID, I //__________________________________________________________________________ Int_t GeometryTGeo::getLayer(Int_t index) const { return mSensorIndexToLayer[index]; } + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameHalf(int hf) +{ + return Form("%s_0/%s_%d_%d", composeSymNameMFT(), getMFTHalfPattern(), hf, hf); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameDisk(int hf, int dk) +{ + return Form("%s/%s_%d_%d_%d", composeSymNameHalf(hf), getMFTDiskPattern(), hf, dk, dk); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameLadder(int hf, int dk, int lr) +{ + return Form("%s/%s_%d_%d_%d_%d", composeSymNameDisk(hf, dk), getMFTLadderPattern(), hf, dk, lr, lr); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameChip(int hf, int dk, int lr, int chip) +{ + return Form("%s/%s_%d_%d_%d_%d", composeSymNameLadder(hf, dk, lr), getMFTChipPattern(), hf, dk, lr, chip); +} diff --git a/Detectors/ITSMFT/MFT/base/src/HalfCone.cxx b/Detectors/ITSMFT/MFT/base/src/HalfCone.cxx index 458c8f4465065..0c4c88bad17bb 100644 --- a/Detectors/ITSMFT/MFT/base/src/HalfCone.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HalfCone.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,22 +15,26 @@ /// \Carlos csoncco@pucp.edu.pe /// \date 01/07/2020 -#include "TGeoManager.h" -#include "TGeoMatrix.h" -#include "TGeoManager.h" +#include "TGeoBBox.h" +#include "TGeoBoolNode.h" #include "TGeoCompositeShape.h" -#include "TGeoShape.h" #include "TGeoCone.h" -#include "TGeoVolume.h" +#include "TGeoManager.h" #include "TGeoMaterial.h" +#include "TGeoMatrix.h" #include "TGeoMedium.h" -#include "TGeoTube.h" +#include "TGeoShape.h" #include "TGeoTrd1.h" -#include "TMath.h" +#include "TGeoTube.h" +#include "TGeoVolume.h" #include "TGeoXtru.h" +#include "TMath.h" +#include <TGeoArb8.h> // for TGeoTrap +#include "MFTBase/MFTBaseParam.h" +#include "MFTBase/GeometryBuilder.h" -#include "MFTBase/HalfCone.h" #include "MFTBase/Constants.h" +#include "MFTBase/HalfCone.h" using namespace o2::mft; @@ -49,37 +54,9 @@ HalfCone::~HalfCone() = default; TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) { - auto* HalfConeVolume = new TGeoVolumeAssembly("HalfConeVolume"); - - TGeoElement* Silicon = new TGeoElement("Silicon", "Silicon", 14, 28.0855); - TGeoElement* Iron = new TGeoElement("Iron", "Iron", 26, 55.845); - TGeoElement* Copper = new TGeoElement("Copper", "Copper", 29, 63.546); - TGeoElement* Manganese = - new TGeoElement("Manganese", "Manganese", 25, 54.938049); - TGeoElement* Magnesium = - new TGeoElement("Magnesium", "Magnesium", 12, 24.3050); - TGeoElement* Zinc = new TGeoElement("Zinc", "Zinc", 30, 65.39); - TGeoElement* Titanium = new TGeoElement("Titanium", "Titanium", 22, 47.867); - TGeoElement* Chromium = new TGeoElement("Chromium", "Chromium", 24, 51.9961); - TGeoElement* Aluminum = new TGeoElement("Aluminum", "Aluminum", 13, 26981538); - - TGeoMixture* alu5083 = new TGeoMixture("alu5083", 9, 2.650); // g/cm3 - alu5083->AddElement(Iron, 0.004); - alu5083->AddElement(Silicon, 0.004); - alu5083->AddElement(Copper, 0.001); - alu5083->AddElement(Manganese, 0.002); - alu5083->AddElement(Magnesium, 0.0025); - alu5083->AddElement(Zinc, 0.0025); - alu5083->AddElement(Titanium, 0.0015); - alu5083->AddElement(Chromium, 0.0010); - alu5083->AddElement(Aluminum, 0.9815); - // alu5083->SetTemperature(); // 25. - alu5083->SetDensity(2.65); // g/cm3 - alu5083->SetState(TGeoMaterial::kMatStateSolid); - - TGeoMedium* kMedAlu = gGeoManager->GetMedium("MFT_Alu$"); - TGeoMedium* malu5083 = - new TGeoMedium("malu5083", 2, alu5083); // name, numer medio, material + auto* HalfConeVolume = new TGeoVolumeAssembly(Form("HalfConeVolume%d", half)); + + TGeoMedium* malu5083 = gGeoManager->GetMedium("MFT_Alu5083$"); // Rotation TGeoRotation* rot1 = new TGeoRotation("rot1", 180, -180, 0); @@ -91,14 +68,13 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoRotation* rot3 = new TGeoRotation("rot3", 0, 90, 0); rot3->RegisterYourself(); - TGeoRotation* rot_90x = new TGeoRotation("rot_90x", 0, -90, 0); // half0 + TGeoRotation* rot_90x = new TGeoRotation("rot_90x", 0, -90, 0); rot_90x->RegisterYourself(); - TGeoRotation* rot_base = new TGeoRotation("rot_base", 180, 180, 0); // rail_r + TGeoRotation* rot_base = new TGeoRotation("rot_base", 180, 180, 0); rot_base->RegisterYourself(); - TGeoCombiTrans* combi1 = - new TGeoCombiTrans(0, -10.3, 1.29, rot1); // y=-10.80 belt + TGeoCombiTrans* combi1 = new TGeoCombiTrans(0, -10.3, 1.29, rot1); combi1->RegisterYourself(); TGeoCombiTrans* combi2 = new TGeoCombiTrans(-16.8, 0., 0., rot2); combi2->RegisterYourself(); @@ -117,7 +93,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) ///// holes tub 1hole tranversal Double_t radin_1hmb0 = 0.; - Double_t radout_1hmb0 = 0.175; // diameter 3.5 H9 (0.35cm) + Double_t radout_1hmb0 = 0.175; Double_t high_1hmb0 = 0.7; TGeoRotation* rot_1hole_mb0 = new TGeoRotation("rot_1hole_mb0", 0, 90, 0); @@ -126,16 +102,14 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoCombiTrans* acombi_1h_mb0 = new TGeoCombiTrans(5.2, 0, 0, rot_1hole_mb0); acombi_1h_mb0->SetName("acombi_1h_mb0"); acombi_1h_mb0->RegisterYourself(); - TGeoCombiTrans* bcombi_1h_mb0 = - new TGeoCombiTrans(-5.2, 0, 0, rot_1hole_mb0); // y= + TGeoCombiTrans* bcombi_1h_mb0 = new TGeoCombiTrans(-5.2, 0, 0, rot_1hole_mb0); bcombi_1h_mb0->SetName("bcombi_1h_mb0"); bcombi_1h_mb0->RegisterYourself(); // 2hole coaxial Double_t radin_2hmb0 = 0.; - Double_t radout_2hmb0 = 0.15; // diameter M3 - Double_t high_2hmb0 = 1.2; // 12 - + Double_t radout_2hmb0 = 0.15; + Double_t high_2hmb0 = 1.2; TGeoRotation* rot_2hole_mb0 = new TGeoRotation("rot_2hole_mb0", 90, 90, 0); rot_2hole_mb0->SetName("rot_2hole_mb0"); rot_2hole_mb0->RegisterYourself(); @@ -146,13 +120,11 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) combi_2hole_mb0->RegisterYourself(); TGeoCombiTrans* combi_2hole_mb0_b = - new TGeoCombiTrans(-6.7, 0, 0, rot_2hole_mb0); // y= + new TGeoCombiTrans(-6.7, 0, 0, rot_2hole_mb0); combi_2hole_mb0_b->SetName("combi_2hole_mb0_b"); combi_2hole_mb0_b->RegisterYourself(); // shape for cross_mb0.. - // TGeoShape* box_mb0 = new TGeoBBox("s_box_mb0", x_boxmb0 / 2, y_boxmb0 / 2, - // z_boxmb0 / 2); new TGeoBBox("box_mb0", x_boxmb0 / 2, y_boxmb0 / 2, z_boxmb0 / 2); new TGeoTube("hole1_mb0", radin_1hmb0, radout_1hmb0, high_1hmb0 / 2); new TGeoTube("hole2_mb0", radin_2hmb0, radout_2hmb0, high_2hmb0 / 2); @@ -161,18 +133,14 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) auto* c_mb0_Shape_0 = new TGeoCompositeShape( "c_mb0_Shape_0", "box_mb0 - hole2_mb0:combi_2hole_mb0 - " - "hole2_mb0:combi_2hole_mb0_b"); //- hole1_mb0:acombi_1h_mb0 - - // hole1_mb0:bcombi_1h_mb0 + "hole2_mb0:combi_2hole_mb0_b"); - /// auto* cross_mb0_Volume = new TGeoVolume("cross_mb0_Volume", c_mb0_Shape_0, - /// kMedAlu); auto* cross_mb0_Volume = new TGeoVolume("cross_mb0_Volume", c_mb0_Shape_0, malu5083); Cross_mb0->AddNode(cross_mb0_Volume, 1); // 2nd piece cross beam MFT (cbeam) - auto* Cross_mft = new TGeoVolumeAssembly("Cross_mft"); auto* Cross_mft_2 = new TGeoVolumeAssembly("Cross_mft_2"); auto* Cross_mft_3 = new TGeoVolumeAssembly("Cross_mft_3"); @@ -191,11 +159,10 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) // using the same "box" of the 1 piece // 2hole coaxial Double_t radin_hole_cbeam = 0.; - Double_t radout_hole_cbeam = 0.15; // diameter M3 - Double_t high_hole_cbeam = 0.91; // + Double_t radout_hole_cbeam = 0.15; + Double_t high_hole_cbeam = 0.91; // same rotation in tub aximatAl "rot_2hole_mb0" - TGeoCombiTrans* combi_hole_1cbeam = new TGeoCombiTrans(6.8, 0, 0, rot_2hole_mb0); combi_hole_1cbeam->SetName("combi_hole_1cbeam"); @@ -207,21 +174,17 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) combi_hole_2cbeam->RegisterYourself(); // shape for shape cross beam - new TGeoTube("hole_cbeam", radin_hole_cbeam, radout_hole_cbeam, high_hole_cbeam / 2); new TGeoTube("s_cb", radin_cb, radout_cb, high_cb / 2); // new // composite shape for cross beam (using the same box of mb0) - /// auto* c_cbeam_Shape = new TGeoCompositeShape("c_cbeam_Shape", "box_mb0 - - /// hole_cbeam:combi_hole_1cbeam - hole_cbeam:combi_hole_2cbeam"); + auto* c_cbeam_Shape = new TGeoCompositeShape( "c_cbeam_Shape", " s_cb:rot_cb - hole_cbeam:combi_hole_1cbeam - " "hole_cbeam:combi_hole_2cbeam"); - /// auto* Cross_mft_Volume = new TGeoVolume("Cross_mft_Volume", c_cbeam_Shape, - /// kMedAlu); auto* Cross_mft_Volume = new TGeoVolume("Cross_mft_Volume", c_cbeam_Shape, malu5083); auto* Cross_mft_Volume_2 = @@ -237,7 +200,6 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Cross_mft_4->AddNode(Cross_mft_Volume_4, 1); // 3th piece Framework front - auto* Fra_front = new TGeoVolumeAssembly("Fra_front"); auto* Fra_front_L = new TGeoVolumeAssembly("Fra_front_L"); auto* Fra_front_R = new TGeoVolumeAssembly("Fra_front_R"); @@ -280,8 +242,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) top_adfwf->SetName("top_adfwf"); Double_t x_top_adfwf[4] = {-14.8, -14.2, -14.2, -14.8}; - Double_t y_top_adfwf[4] = {-3.6 - 0.12, -3.6 - 0.12, -5.56, - -5.83}; // 5.52 , 5.9 --5.83 + Double_t y_top_adfwf[4] = {-3.6 - 0.12, -3.6 - 0.12, -5.56, -5.83}; top_adfwf->DefinePolygon(4, x_top_adfwf, y_top_adfwf); top_adfwf->DefineSection(0, -0.3, 0., 0., 1); //(plane,-zplane/ +zplane, x0, y0,(x/y)) @@ -296,15 +257,13 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) new TGeoTranslation("tr_q_upbox", -14.8 - 0.2, -3.6 - 0.6, 0.); tr_q_upbox->RegisterYourself(); - TGeoRotation* rot_180yR = - new TGeoRotation("rot_180yR", 180, -180, 0); // half0 + TGeoRotation* rot_180yR = new TGeoRotation("rot_180yR", 180, -180, 0); rot_180yR->RegisterYourself(); TGeoCombiTrans* combi_fwb_R = new TGeoCombiTrans(0, 0, 0, rot_180yR); combi_fwb_R->SetName("combi_fwb_R"); combi_fwb_R->RegisterYourself(); /////////////////////////////////////////// - Double_t x_box_up = 0.6; // cm Double_t y_box_up = 0.605; Double_t z_box_up = 2.84; @@ -321,20 +280,20 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t x_boxB_down = 0.6; Double_t y_boxB_down = 0.605; - Double_t z_boxB_down = 1.26; // 12.6 + Double_t z_boxB_down = 1.26; // seg tub Double_t radin_segtub = 16.9; Double_t radout_segtub = 17.5; Double_t high_segtub = 0.6; Double_t ang_in_segtub = 212.1; - Double_t ang_fin_segtub = 241.92; // + Double_t ang_fin_segtub = 241.92; // trans. rot. TGeoCombiTrans* combi_3a = new TGeoCombiTrans(-7.4, 0, 8.975, rot2); combi_3a->SetName("combi_3a"); combi_3a->RegisterYourself(); - TGeoTranslation* tr1_up = new TGeoTranslation("tr1_up", -7.4, 0, 8.28); // + TGeoTranslation* tr1_up = new TGeoTranslation("tr1_up", -7.4, 0, 8.28); tr1_up->RegisterYourself(); @@ -377,7 +336,6 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) new TGeoTube("tubdown", 0., dia_tubdown / 2, high_tubdown / 2); // Composite shapes for Fra_front - new TGeoCompositeShape("fra_front_Shape_0", "box_up:tr1_up + seg_tub:combi_3b + boxB_down:tr3_box " "+ boxA_down:tr_2_box"); @@ -393,8 +351,6 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoRotation* rot_halfR = new TGeoRotation("rot_halfR", 180, 180, 0); // half0_R rot_halfR->RegisterYourself(); - /// TGeoCombiTrans* combi_front_L = new TGeoCombiTrans(-7.1, -16.2, 32.5 + - /// 0.675, rot_90x); // x=7.35, y=0, z=15.79 TGeoCombiTrans* combi_front_L = new TGeoCombiTrans(-7.1, -16.2, 32.5 + 0.675, rot_90x); @@ -404,11 +360,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoTranslation* tr_ff = new TGeoTranslation( "tr_ff", 0, -2.5 - 0.31, 32.5 + 0.675); // 7.1 , -16.2 z32.5 tr_ff->RegisterYourself(); - // TGeoRotation *rot_180yR = new TGeoRotation("rot_180yR", 180,-180,0); // - // half0 rot_180yR->RegisterYourself(); - // TGeoCombiTrans* combi_front_R = new TGeoCombiTrans(7.1, -16.2, 32.5 + - // 0.675, rot_z180x90); //x=7.35, y=0, z=15.79 TGeoCombiTrans* combi_front_R = new TGeoCombiTrans(0, -2.5 - 0.31, 32.5 + 0.675, rot_180yR); combi_front_R->SetName("combi_front_R"); @@ -419,18 +371,9 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) "fwf_tub - box_qdown:tr_qdown + box_addown:tr_addown + tria_fwf + " "top_adfwf - q_upbox:tr_q_upbox"); - // auto * fra_front_Shape_3 = new - // TGeoCompositeShape("Fra_front_Shape_3","Fra_front_Shape_2 + - // Fra_front_Shape_2:combi_front_R "); - auto* fra_front_Shape_3 = new TGeoCompositeShape( "Fra_front_Shape_3", "Fra_front_Shape_2 + Fra_front_Shape_2:rot_180yR"); - // auto * fra_front_Shape_3 = new - // TGeoCompositeShape("fra_front_Shape_3","fra_front_Shape_2:rot_halfR "); - - /// auto* Fra_front_Volume = new TGeoVolume("Fra_front_Volume", - /// fra_front_Shape_1, kMedAlu); auto* Fra_front_Volume_R = new TGeoVolume("Fra_front_Volume_R", fra_front_Shape_2, malu5083); auto* Fra_front_Volume_L = @@ -439,15 +382,9 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) auto* Fra_front_Volume_RL = new TGeoVolume("Fra_front_Volume_RL", fra_front_Shape_3, malu5083); - // Fra_front_L->AddNode(Fra_front_Volume, 1, tr_ff); - // Fra_front_R->AddNode(Fra_front_Volume, 1, combi_front_R); - - // Fra_front->AddNode(Fra_front_L, 1); - // Fra_front->AddNode(Fra_front_R, 2); Fra_front->AddNode(Fra_front_Volume_RL, 1, tr_ff); // 4th piece "BASE" framework half support - auto* base = new TGeoVolumeAssembly("base"); // seg tub disc @@ -518,7 +455,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_2labox = 2.8; // C-B Double_t z_2labox = 0.303; TGeoTranslation* tr_2la = - new TGeoTranslation("tr_2la", 0, -8.1, high_disc / 2); // + new TGeoTranslation("tr_2la", 0, -8.1, high_disc / 2); tr_2la->RegisterYourself(); // circular border C SEG_BORD @@ -528,8 +465,6 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t high_bord = 1.355; // 13.5 Double_t ang_in_bord = 0; Double_t ang_fin_bord = 90; - // TGeoRotation *rot_bord1 = new TGeoRotation("rot_bord1", ang_in_1hole - // +0.0167,0,0); TGeoRotation* rot1_bord1 = new TGeoRotation("rot1_bord1", 14.8, 0, 0); rot1_bord1->RegisterYourself(); TGeoCombiTrans* combi_bord1 = @@ -540,21 +475,21 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoRotation* rot2_bord1 = new TGeoRotation("rot2_bord1", -50, 0, 0); rot2_bord1->RegisterYourself(); TGeoCombiTrans* combi2_bord1 = - new TGeoCombiTrans(-21.3795, -20.7636, 0, rot2_bord1); // y= + new TGeoCombiTrans(-21.3795, -20.7636, 0, rot2_bord1); combi2_bord1->SetName("combi2_bord1"); combi2_bord1->RegisterYourself(); // TGeoRotation* rot1_bord2 = new TGeoRotation("rot1_bord2", 250, 0, 0); rot1_bord2->RegisterYourself(); TGeoCombiTrans* combi1_bord2 = - new TGeoCombiTrans(-9.0527, -23.3006, 0, rot1_bord2); // y= + new TGeoCombiTrans(-9.0527, -23.3006, 0, rot1_bord2); combi1_bord2->SetName("combi1_bord2"); combi1_bord2->RegisterYourself(); // e|°____°| TGeoRotation* rot_cent_bord = new TGeoRotation("rot_cent_bord", 90, 0, 0); rot_cent_bord->RegisterYourself(); TGeoCombiTrans* combi_cent_bord = - new TGeoCombiTrans(-6.5, -27.094, 0, rot_cent_bord); // y= + new TGeoCombiTrans(-6.5, -27.094, 0, rot_cent_bord); combi_cent_bord->SetName("combi_cent_bord"); combi_cent_bord->RegisterYourself(); // box tonge @@ -567,8 +502,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t radin_hole1 = 0; Double_t radout_hole1 = 0.4; Double_t high_hole1 = 1.36; - TGeoTranslation* tr_hole1 = - new TGeoTranslation("tr_hole1", 0, -28.0, 0); // tonge + TGeoTranslation* tr_hole1 = new TGeoTranslation("tr_hole1", 0, -28.0, 0); tr_hole1->RegisterYourself(); TGeoTranslation* tr2_hole1 = @@ -581,8 +515,8 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) // circular hole2 ; hole2 r=6.7 Double_t radin_hole2 = 0; - Double_t radout_hole2 = 0.335; // diameter 6.7 - Double_t high_hole2 = 1.36; // 13.5 + Double_t radout_hole2 = 0.335; + Double_t high_hole2 = 1.36; TGeoTranslation* tr1_hole2 = new TGeoTranslation("tr1_hole2", -28.0, -8.5, 0); // tr1_hole2->RegisterYourself(); @@ -599,15 +533,14 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t radin_T2 = 0; Double_t radout_T2 = 1.1; Double_t high_T2 = 1.2; // dz 6 - // seg tong xy + Double_t radin_ccut = 27.5; - Double_t radout_ccut = 29.; // 304 - Double_t high_ccut = 1.4; /// 13.5 + Double_t radout_ccut = 29.; + Double_t high_ccut = 1.4; Double_t ang_in_ccut = 260; Double_t ang_fin_ccut = 280; // shape for base - new TGeoTubeSeg("disc", radin_disc, radout_disc, high_disc / 2, ang_in_disc, ang_fin_disc); new TGeoTubeSeg("c_cut", radin_ccut, radout_ccut, high_ccut / 2, ang_in_ccut, @@ -622,7 +555,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) new TGeoBBox("tongbox", x_tong / 2, y_tong / 2, z_tong / 2); new TGeoTubeSeg("seg_1hole", radin_1hole, radout_1hole, high_1hole / 2, - ang_in_1hole, ang_fin_1hole); // r_in,r_out,dZ,ang,ang + ang_in_1hole, ang_fin_1hole); new TGeoTubeSeg("seg_2hole", radin_2hole, radout_2hole, high_2hole / 2, ang_in_2hole, ang_fin_2hole); new TGeoTubeSeg("seg_3hole", radin_3hole, radout_3hole, high_3hole / 2, @@ -638,52 +571,35 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) // composite shape for base - // new TGeoCompositeShape("base_Shape_0", " disc - box1 - box2 - box3 - - // circ_holeB:tr1_holeB - circ_holeB:tr2_holeB"); new TGeoCompositeShape("base_Shape_0", " disc - box1 - box2 - box3"); new TGeoCompositeShape( "base_Shape_1", "(seg_1hole - seg_bord:combi_bord1 - seg_bord:combi2_bord1) + seg_2hole " "-seg_bord:combi1_bord2 + cbox:tr_cbox"); - new TGeoCompositeShape( - "base_Shape_2", - " seg_3hole + seg_bord:combi_cent_bord"); // seg_bord:combi_cent_bord + new TGeoCompositeShape("base_Shape_2", + " seg_3hole + seg_bord:combi_cent_bord"); new TGeoCompositeShape("base_Shape_3", " labox1:tr_la + labox2:tr_2la "); - /// auto* base_Shape_4 = new TGeoCompositeShape("base_Shape_4", "base_Shape_0 - /// - base_Shape_1 - base_Shape_1:rot1 + base_Shape_2 + tongbox:tr_tong - - /// circ_hole1:tr_hole1 - circ_hole1:tr2_hole1 - circ_hole1:tr3_hole1 - - /// circ_hole2:tr1_hole2 - circ_hole2:tr2_hole2 - base_Shape_3 "); auto* base_Shape_4 = new TGeoCompositeShape( "base_Shape_4", "base_Shape_0 - base_Shape_1 - base_Shape_1:rot1 + base_Shape_2 - " - "base_Shape_3 + tongbox:tr_tong - c_cut"); //- circ_hole1:tr_hole1 - - // circ_hole1:tr2_hole1 - - // circ_hole1:tr3_hole1 - - // circ_hole2:tr1_hole2 - - // circ_hole2:tr2_hole2 - - // auto * base_Shape_5 = new TGeoCompositeShape("base_Shape_5","disc-box1 - // -box2 -box3 -seg_1hole -seg_2hole +seg_3hole -seg_1hole:rot1-seg_2hole:rot1 - // - cbox:tr_cbox - labox:tr_la - labox2:tr_2la + seg_bord "); + "base_Shape_3 + tongbox:tr_tong - c_cut"); auto* base4_Volume = new TGeoVolume("base4_Volume", base_Shape_4, malu5083); base->AddNode(base4_Volume, 2, rot_base); - // base->AddNode(base4_Volume,2); // 5th piece middle Framework middle - auto* middle = new TGeoVolumeAssembly("middle"); auto* middle_L = new TGeoVolumeAssembly("middle_L"); auto* middle_R = new TGeoVolumeAssembly("middle_R"); ////new2020 framework middle Double_t radin_fwm = 14.406; - Double_t radout_fwm = 15.185; // - Double_t high_fwm = 0.6; /// + Double_t radout_fwm = 15.185; + Double_t high_fwm = 0.6; Double_t ang_in_fwm = 180. + 12.93; Double_t ang_fin_fwm = 180. + 58.65; @@ -692,7 +608,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_fwm_1box = 1.45; Double_t z_fwm_1box = 0.6; // 6.5 -> 6.6 to quit TGeoTranslation* tr_fwm_1box = - new TGeoTranslation("tr_fwm_1box", -14.4, -3.398 + 1.45 / 2, 0); // 81 + new TGeoTranslation("tr_fwm_1box", -14.4, -3.398 + 1.45 / 2, 0); tr_fwm_1box->RegisterYourself(); ////box quit down @@ -700,10 +616,9 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_fwm_2box = 1.2; Double_t z_fwm_2box = 0.7; // 6.5 -> 6.6 to quit TGeoTranslation* tr_fwm_2box = - new TGeoTranslation("tr_fwm_2box", -14.4 + 6.9, -3.398 - 9.1, 0); // 81 + new TGeoTranslation("tr_fwm_2box", -14.4 + 6.9, -3.398 - 9.1, 0); tr_fwm_2box->RegisterYourself(); - //// TGeoXtru* tria_fwm = new TGeoXtru(2); tria_fwm->SetName("tria_fwm"); @@ -715,16 +630,16 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) ////////// // box up to quit and to join - Double_t x_middle = 0.8; // dx=4 - Double_t y_middle = 3.495; // y=34.9 - Double_t z_middle = 0.62; // z=6 + Double_t x_middle = 0.8; + Double_t y_middle = 3.495; + Double_t z_middle = 0.62; // tr1 to join with arc TGeoTranslation* tr1_middle_box = - new TGeoTranslation("tr1_middle_box", -14.4, -0.745, 0); // -152,-17.45,0 + new TGeoTranslation("tr1_middle_box", -14.4, -0.745, 0); tr1_middle_box->RegisterYourself(); // tr2 to quiet TGeoTranslation* tr2_middle_box = - new TGeoTranslation("tr2_middle_box", -15.2, -0.745, 0); // -152,-17.45,0 + new TGeoTranslation("tr2_middle_box", -15.2, -0.745, 0); tr2_middle_box->RegisterYourself(); // box down_1 @@ -732,7 +647,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_middle_d1box = 0.28; Double_t z_middle_d1box = 0.66; TGeoTranslation* tr_middle_d1box = - new TGeoTranslation("tr_middle_d1box", -7.3, -11.96, 0.); // 81 + new TGeoTranslation("tr_middle_d1box", -7.3, -11.96, 0.); tr_middle_d1box->RegisterYourself(); // box down_2 @@ -740,35 +655,35 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_middle_d2box = 1.0; Double_t z_middle_d2box = 0.66; // TGeoTranslation* tr_middle_d2box = - new TGeoTranslation("tr_middle_d2box", -7.5, -12.6249, 0); // 81 + new TGeoTranslation("tr_middle_d2box", -7.5, -12.6249, 0); tr_middle_d2box->RegisterYourself(); // arc circ part Double_t radin_middle = 14.0; - Double_t radout_middle = 15.0; // - Double_t high_middle = 0.6; // + Double_t radout_middle = 15.0; + Double_t high_middle = 0.6; Double_t ang_in_middle = 180; Double_t ang_fin_middle = 238.21; // alfa=57.60 // circular hole1 ; hole_middle d=3.5 Double_t radin_mid_1hole = 0.; - Double_t radout_mid_1hole = 0.175; // diameter 3.5 - Double_t high_mid_1hole = 1.5; // 2.4 + Double_t radout_mid_1hole = 0.175; + Double_t high_mid_1hole = 1.5; TGeoRotation* rot_mid_1hole = new TGeoRotation("rot_mid_1hole", 90, 90, 0); rot_mid_1hole->RegisterYourself(); TGeoCombiTrans* combi_mid_1tubhole = - new TGeoCombiTrans(-14.2, 0.325, 0, rot_mid_1hole); // + new TGeoCombiTrans(-14.2, 0.325, 0, rot_mid_1hole); combi_mid_1tubhole->SetName("combi_mid_1tubhole"); combi_mid_1tubhole->RegisterYourself(); // circular hole2 ; hole_middle d=3 Double_t radin_mid_2hole = 0.; - Double_t radout_mid_2hole = 0.15; // diameter 3 - Double_t high_mid_2hole = 1.8; // + Double_t radout_mid_2hole = 0.15; + Double_t high_mid_2hole = 1.8; TGeoCombiTrans* combi_mid_2tubhole = - new TGeoCombiTrans(-7.7, -12.355, 0, rot_mid_1hole); // x=81 + new TGeoCombiTrans(-7.7, -12.355, 0, rot_mid_1hole); combi_mid_2tubhole->SetName("combi_mid_2tubhole"); combi_mid_2tubhole->RegisterYourself(); @@ -798,7 +713,6 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) new TGeoBBox("fwm_2box", x_fwm_2box / 2, y_fwm_2box / 2, z_fwm_2box / 2); // composite shape for middle - new TGeoCompositeShape( "middle_Shape_0", " arc_middle + middle_box:tr1_middle_box - middle_box:tr2_middle_box - " @@ -811,19 +725,17 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoRotation* rot_middlez = new TGeoRotation("rot_middley", 180, 180, 0); rot_middlez->RegisterYourself(); - TGeoCombiTrans* combi_middle_L = new TGeoCombiTrans( - 0, -7.625, 24.15 + 0.675, - rot_90x); // x=7.35, y=0, z=15.79- 0,-7.625,24.15+0.675-80) + TGeoCombiTrans* combi_middle_L = + new TGeoCombiTrans(0, -7.625, 24.15 + 0.675, rot_90x); combi_middle_L->SetName("combi_middle_L"); combi_middle_L->RegisterYourself(); - TGeoTranslation* tr_middle_L = new TGeoTranslation( - "tr_middle_L", 0, -4.45 - 0.1, 24.85 + 0.675); //+2.5,, -152,-17.45,0 + TGeoTranslation* tr_middle_L = + new TGeoTranslation("tr_middle_L", 0, -4.45 - 0.1, 24.85 + 0.675); tr_middle_L->RegisterYourself(); TGeoCombiTrans* combi_middle_R = - new TGeoCombiTrans(0, -4.45 - 0.1, 24.85 + 0.675, - rot_middlez); // x=7.35, y=0, z=15.79 y7.625 ++2.5 + new TGeoCombiTrans(0, -4.45 - 0.1, 24.85 + 0.675, rot_middlez); combi_middle_R->SetName("combi_middle_R"); combi_middle_R->RegisterYourself(); @@ -835,15 +747,13 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) "middle_Shape_4", " tube_fwm + fwm_1box:tr_fwm_1box - fwm_2box:tr_fwm_2box +tria_fwm"); - // auto* middle_Volume = new TGeoVolume("middle_Volume", middle_Shape_1, - // kMedAlu); auto* middle_Volume_L = new TGeoVolume("middle_Volume_L", middle_Shape_3, malu5083); auto* middle_Volume_R = new TGeoVolume("middle_Volume_R", middle_Shape_4, malu5083); - TGeoTranslation* tr_middle = new TGeoTranslation( - "tr_middle", 0, -4.45 - 0.1, 24.85 + 0.675); //+2.5,, -152,-17.45,0 + TGeoTranslation* tr_middle = + new TGeoTranslation("tr_middle", 0, -4.45 - 0.1, 24.85 + 0.675); tr_middle->RegisterYourself(); middle_L->AddNode(middle_Volume_L, 1, tr_middle); @@ -864,40 +774,24 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t x_RL_1box = 3.0; // dx=15 Double_t y_RL_1box = 1.21; // dy=6, -dy=6 Double_t z_RL_1box = 0.8; // dz=4 to quit - TGeoTranslation* tr_RL_1box = - new TGeoTranslation(0, y_RL_1box / 2, 1.825); // 81 + TGeoTranslation* tr_RL_1box = new TGeoTranslation(0, y_RL_1box / 2, 1.825); tr_RL_1box->SetName("tr_RL_1box"); tr_RL_1box->RegisterYourself(); TGeoXtru* xtru_RL1 = new TGeoXtru(2); xtru_RL1->SetName("S_XTRU_RL1"); - Double_t x_RL1[5] = {-1.5, 1.5, 0.5, 0.5, - -1.5}; // 93,93,73,73,-15}; //vertices - Double_t y_RL1[5] = {1.2, 1.2, 2.2, 8.2, 8.2}; // 357.5,357.5,250.78,145.91}; + Double_t x_RL1[5] = {-1.5, 1.5, 0.5, 0.5, -1.5}; + Double_t y_RL1[5] = {1.2, 1.2, 2.2, 8.2, 8.2}; xtru_RL1->DefinePolygon(5, x_RL1, y_RL1); - xtru_RL1->DefineSection(0, -2.225, 0., 0., - 1); // (plane,-zplane/ +zplane, x0, y0,(x/y)) + xtru_RL1->DefineSection(0, -2.225, 0., 0., 1); xtru_RL1->DefineSection(1, 2.225, 0., 0., 1); - /// TGeoXtru* xtru_RL2 = new TGeoXtru(2); - /// xtru_RL2->SetName("S_XTRU_RL2"); - - /// Double_t x_RL2[8] = {-1.5, 0.5, 0.5, 9.3, 9.3, 7.3, 7.3, -1.5}; // - /// vertices Double_t y_RL2[8] = - /// {8.2, 8.2, 13.863, 24.35, 35.75, 35.75, 25.078, 14.591}; - - /// xtru_RL2->DefinePolygon(8, x_RL2, y_RL2); - - /// xtru_RL2->DefineSection(0, 0.776, 0, 0, 1); // (plane,-zplane/+zplane, x0, - /// y0,(x/y)) xtru_RL2->DefineSection(1, 2.225, 0, 0, 1); - // box knee - Double_t x_RL_kneebox = 1.5; // dx=7.5 - Double_t y_RL_kneebox = 3.5; // dy=17.5 - Double_t z_RL_kneebox = 1.5; // dz=7.5 to quit - TGeoTranslation* tr_RL_kneebox = - new TGeoTranslation(0, 0, 0); // 81 x =-2.5, y=145.91 + Double_t x_RL_kneebox = 1.5; + Double_t y_RL_kneebox = 3.5; + Double_t z_RL_kneebox = 1.5; + TGeoTranslation* tr_RL_kneebox = new TGeoTranslation(0, 0, 0); tr_RL_kneebox->SetName("tr_RL_kneebox"); tr_RL_kneebox->RegisterYourself(); @@ -905,7 +799,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) rot_knee->SetName("rot_knee"); rot_knee->RegisterYourself(); TGeoCombiTrans* combi_knee = - new TGeoCombiTrans(0.96, 1.75 + 0.81864, 0, rot_knee); // y= + new TGeoCombiTrans(0.96, 1.75 + 0.81864, 0, rot_knee); combi_knee->SetName("combi_knee"); combi_knee->RegisterYourself(); // quit diagona-> qdi @@ -915,8 +809,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoRotation* rot_qdi = new TGeoRotation("rot_qdi", 0, 24.775, 0); rot_qdi->RegisterYourself(); - TGeoCombiTrans* combi_qdi = - new TGeoCombiTrans(0, 5.579, -2.087, rot_qdi); // y= + TGeoCombiTrans* combi_qdi = new TGeoCombiTrans(0, 5.579, -2.087, rot_qdi); combi_qdi->SetName("combi_qdi"); combi_qdi->RegisterYourself(); // knee small @@ -924,38 +817,37 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoXtru* xtru3_RL = new TGeoXtru(2); xtru3_RL->SetName("xtru3_RL"); - Double_t x_3RL[6] = {-0.75, 0.75, 0.75, 2.6487, 1.4997, -0.75}; // vertices + Double_t x_3RL[6] = {-0.75, 0.75, 0.75, 2.6487, 1.4997, -0.75}; Double_t y_3RL[6] = {-1.75, -1.75, 1.203, 3.465, 4.4311, 1.75}; xtru3_RL->DefinePolygon(6, x_3RL, y_3RL); - xtru3_RL->DefineSection(0, -0.75, 0, 0, - 1); // (plane,-zplane/+zplane, x0, y0,(x/y)) + xtru3_RL->DefineSection(0, -0.75, 0, 0, 1); xtru3_RL->DefineSection(1, 0.76, 0, 0, 1); - TGeoTranslation* tr_vol3_RL = new TGeoTranslation(-0.25, 12.66, 0); // + TGeoTranslation* tr_vol3_RL = new TGeoTranslation(-0.25, 12.66, 0); tr_vol3_RL->SetName("tr_vol3_RL"); tr_vol3_RL->RegisterYourself(); - // circular holes could be for rail R and L .. + // circular holes for rail R and L // circular hole1_RL (a(6,22)); hole_midle d=6.5 H11 Double_t radin_RL1hole = 0.; - Double_t radout_RL1hole = 0.325; // diameter 3.5 - Double_t high_RL1hole = 1.0; // + Double_t radout_RL1hole = 0.325; + Double_t high_RL1hole = 1.0; TGeoRotation* rot_RL1hole = new TGeoRotation("rot_RL1hole", 0, 0, 0); rot_RL1hole->RegisterYourself(); TGeoCombiTrans* combi_RL1hole = - new TGeoCombiTrans(0.7, 0.6, 1.85, rot_RL1hole); // y= + new TGeoCombiTrans(0.7, 0.6, 1.85, rot_RL1hole); combi_RL1hole->SetName("combi_RL1hole"); combi_RL1hole->RegisterYourself(); // similar hole for R Join. // circular hole_ir. diameter=M3 (3 mm)) prof trou:8, tar:6mm Double_t radin_ir_railL = 0.; - Double_t radout_ir_railL = 0.15; // diameter 0.3cm - Double_t high_ir_railL = 3.9; // + Double_t radout_ir_railL = 0.15; + Double_t high_ir_railL = 3.9; TGeoRotation* rot_ir_RL = new TGeoRotation("rot_ir_RL", 90, 90, 0); rot_ir_RL->RegisterYourself(); - // in y = l_253.5 - 6. enter in (0,6,0) + TGeoCombiTrans* combi_ir1_RL = new TGeoCombiTrans(8.62, 24.75, 1.5, rot_ir_RL); combi_ir1_RL->SetName("combi_ir1_RL"); @@ -965,17 +857,14 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) combi_ir2_RL->SetName("combi_ir2_RL"); combi_ir2_RL->RegisterYourself(); // - // 1) modification TGeoXtru* xtru_RL2 = new TGeoXtru(2); xtru_RL2->SetName("S_XTRU_RL2"); - // modi the arm L---> new L Double_t x_RL2[8] = {-1.5, 0.5, 0.5, 9.3, 9.3, 7.3, 7.3, -1.5}; Double_t y_RL2[8] = {8.2, 8.2, 13.863, 24.35, 25.65, 25.65, 25.078, 14.591}; xtru_RL2->DefinePolygon(8, x_RL2, y_RL2); - xtru_RL2->DefineSection(0, 0.7752, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) 0.775 + xtru_RL2->DefineSection(0, 0.7752, 0, 0, 1); xtru_RL2->DefineSection(1, 2.225, 0, 0, 1); // 2) modi adding box new element 1 box @@ -985,13 +874,9 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t x_adi1RL[4] = {-1.5, -1.5, 0.5, 0.5}; Double_t y_adi1RL[4] = {2.2, 13.863, 13.863, 2.2}; - /// Double_t x_adi1RL[4]={-0.5,-0.5,1.5,1.5}; //vertices - ////Double_t y_adi1RL[4]={2.2,13.86,13.86,2.2}; - adi1_RL->DefinePolygon(4, x_adi1RL, y_adi1RL); - adi1_RL->DefineSection(0, -0.75, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) - adi1_RL->DefineSection(1, 0.775, 0, 0, 1); // 0.76 + adi1_RL->DefineSection(0, -0.75, 0, 0, 1); + adi1_RL->DefineSection(1, 0.775, 0, 0, 1); //// 3) modi adding new knee new element 2 new knee TGeoXtru* adi2_RL = new TGeoXtru(2); // @@ -1000,64 +885,57 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t y_adi2RL[6] = {13.863, 13.863, 24.35, 25.65, 25.65, 25.078}; adi2_RL->DefinePolygon(6, x_adi2RL, y_adi2RL); - adi2_RL->DefineSection(0, -0.75, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) - adi2_RL->DefineSection(1, 0.7755, 0, 0, 1); // 0.76, 0.775 + adi2_RL->DefineSection(0, -0.75, 0, 0, 1); + adi2_RL->DefineSection(1, 0.7755, 0, 0, 1); // 4)modi to quit ---> trap - Double_t RL_dx1 = 2.66; // at -z - Double_t RL_dx2 = 1; // dat +z - Double_t RL_dy = 2.2; // dz=7.5 to quit - Double_t RL_dz = 1.5; // dz=1.5 to quit - // auto *trap1 = new TGeoTrd1("TRAP1",RL_dx1,RL_dx2 ,RL_dy ,RL_dz); + Double_t RL_dx1 = 2.66; + Double_t RL_dx2 = 1; + Double_t RL_dy = 2.2; + Double_t RL_dz = 1.5; TGeoRotation* rot_RL_Z50 = new TGeoRotation("rot_RL_Z50", 50, 0, 0); rot_RL_Z50->RegisterYourself(); TGeoCombiTrans* combi_RL_trap = - new TGeoCombiTrans(5, 18.633, -1.5 - 0.025, rot_RL_Z50); // y= + new TGeoCombiTrans(5, 18.633, -1.5 - 0.025, rot_RL_Z50); combi_RL_trap->SetName("combi_RL_trap"); combi_RL_trap->RegisterYourself(); - ///// 5) modi to quit inferior part box - Double_t x_qinf_box = 10.66; // - Double_t y_qinf_box = 10.2; // - Double_t z_qinf_box = 3.; // dz =1.5 + ///// 5) modi to quit inferior part box + Double_t x_qinf_box = 10.66; + Double_t y_qinf_box = 10.2; + Double_t z_qinf_box = 3.; auto* s_RL_qinf_box = new TGeoBBox("S_RL_QINF_BOX", x_qinf_box / 2, y_qinf_box / 2, z_qinf_box / 2); TGeoCombiTrans* combi_RL_qbox = - new TGeoCombiTrans(7, 23., -1.5 - 0.025, rot_RL_Z50); // y= , z=-0.75-0.75 + new TGeoCombiTrans(7, 23., -1.5 - 0.025, rot_RL_Z50); combi_RL_qbox->SetName("combi_RL_qbox"); combi_RL_qbox->RegisterYourself(); // 6) modi. add penta face z - TGeoXtru* pentfa_RL = new TGeoXtru(2); // not work + TGeoXtru* pentfa_RL = new TGeoXtru(2); pentfa_RL->SetName("S_PENTFA_RL"); Double_t x_pentfaRL[5] = {-1., -1., 0.13, 1., 1.}; - Double_t y_pentfaRL[5] = {1.125, 0.045, -1.125, -1.125, 1.125}; // 1.125 + Double_t y_pentfaRL[5] = {1.125, 0.045, -1.125, -1.125, 1.125}; pentfa_RL->DefinePolygon(5, x_pentfaRL, y_pentfaRL); - pentfa_RL->DefineSection(0, -5.05, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) // 0.75 - pentfa_RL->DefineSection(1, 5.055, 0, 0, 1); // 0.76.. 0.9036 + pentfa_RL->DefineSection(0, -5.05, 0, 0, 1); + pentfa_RL->DefineSection(1, 5.055, 0, 0, 1); TGeoRotation* rot_X90 = new TGeoRotation("rot_X90", 0, 90, 0); rot_X90->RegisterYourself(); - TGeoCombiTrans* combi_RL_pent = new TGeoCombiTrans( - 8.3, 30.705, 1.125 - 0.025, rot_X90); // x =8.3 , z= 1.125 + TGeoCombiTrans* combi_RL_pent = + new TGeoCombiTrans(8.3, 30.705, 1.125 - 0.025, rot_X90); combi_RL_pent->SetName("combi_RL_pent"); combi_RL_pent->RegisterYourself(); - // // shape for Rail L geom new TGeoBBox("RL_1box", x_RL_1box / 2, y_RL_1box / 2, z_RL_1box / 2); new TGeoBBox("RL_kneebox", x_RL_kneebox / 2, y_RL_kneebox / 2, - z_RL_kneebox / 2); // no_ used + z_RL_kneebox / 2); new TGeoBBox("qdi_box", x_qdi_box / 2, y_qdi_box / 2, z_qdi_box / 2); new TGeoTrd1("TRAP1", RL_dx1, RL_dx2, RL_dy, RL_dz); - // auto *s_RL1hole=new - // TGeoTube("S_RL1HOLE",radin_RL1hole,radout_RL1hole,high_RL1hole/2); auto - // *s_irL_hole=new - // TGeoTube("S_irL_HOLE",radin_ir_railL,radout_ir_railL,high_ir_railL/2); + // composite shape for rail L auto* RL_Shape_0 = new TGeoCompositeShape( @@ -1066,96 +944,70 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) "qdi_box:combi_qdi + " "S_ADI1_RL + S_ADI2_RL - TRAP1:combi_RL_trap - " "S_RL_QINF_BOX:combi_RL_qbox + " - "S_PENTFA_RL:combi_RL_pent"); // xtru3_RL:tr_vol3_RL - // + + "S_PENTFA_RL:combi_RL_pent"); TGeoVolume* rail_L_vol0 = new TGeoVolume("RAIL_L_VOL0", RL_Shape_0, malu5083); - // TGeoVolume* rail_L_vol0 = new TGeoVolume("RAIL_L_VOL0", RL_Shape_0, - // kMedAlu); rail_L->AddNode(rail_L_vol0, 1, new TGeoTranslation(0., 0., 1.5)); // piece 7th RAIL RIGHT - // auto *rail_R = new TGeoVolumeAssembly("rail_R"); - Double_t x_RR_1box = 3.0; // dx=15 Double_t y_RR_1box = 1.2; // dy=6, -dy=6 Double_t z_RR_1box = 0.8; // dz=4 to quit TGeoTranslation* tr_RR_1box = - new TGeoTranslation("tr_RR_1box", 0, 0.6, 1.825); // 81 + new TGeoTranslation("tr_RR_1box", 0, 0.6, 1.825); tr_RR_1box->RegisterYourself(); TGeoXtru* part_RR1 = new TGeoXtru(2); part_RR1->SetName("part_RR1"); - // TGeoVolume *vol_RR1 = gGeoManager->MakeXtru("S_part_RR1",kMedAlu,2); - // TGeoXtru *part_RR1 = (TGeoXtru*)vol_RR1->GetShape(); - Double_t x_RR1[5] = {-1.5, -0.5, -0.5, 1.5, 1.5}; // C,D,K,L,C' //vertices - Double_t y_RR1[5] = {1.2, 2.2, 8.2, 8.2, 1.2}; // 357.5,357.5,250.78,145.91}; + Double_t x_RR1[5] = {-1.5, -0.5, -0.5, 1.5, 1.5}; + Double_t y_RR1[5] = {1.2, 2.2, 8.2, 8.2, 1.2}; part_RR1->DefinePolygon(5, x_RR1, y_RR1); - part_RR1->DefineSection(0, -2.225, 0, 0, - 1); // (plane,-zplane/ +zplane, x0, y0,(x/y)) + part_RR1->DefineSection(0, -2.225, 0, 0, 1); part_RR1->DefineSection(1, 2.225, 0, 0, 1); - // TGeoXtru* part_RR2 = new TGeoXtru(2); - // part_RR2->SetName("part_RR2"); - // TGeoVolume *vol_RR2 = gGeoManager->MakeXtru("part_RR2",Al,2); - // TGeoXtru *xtru_RR2 = (TGeoXtru*)vol_RR2->GetShape(); - - // Double_t x_RR2[8] = {-0.5, -0.5, -9.3, -9.3, -7.3, -7.3, 1.5, 1.5}; // - // K,E,F,G,H,I,J,L // vertices Double_t y_RR2[8] = - // {8.2, 13.863, 24.35, 35.75, 35.75, 25.078, 14.591, 8.2}; - - // part_RR2->DefinePolygon(8, x_RR2, y_RR2); - // part_RR2->DefineSection(0, 0.776, 0, 0, 1); // (plane,-zplane/+zplane, x0, - // y0,(x/y)) part_RR2->DefineSection(1, 2.225, 0, 0, 1); - // knee (small) - TGeoXtru* part_RR3 = new TGeoXtru(2); part_RR3->SetName("part_RR3"); - Double_t x_3RR[6] = {1.0, 1.0, -1.2497, - -2.2138, -0.5, -0.5}; // R,Q,P,O,N.M // vertices + Double_t x_3RR[6] = {1.0, 1.0, -1.2497, -2.2138, -0.5, -0.5}; Double_t y_3RR[6] = {10.91, 14.41, 17.0911, 15.9421, 13.86, 10.91}; part_RR3->DefinePolygon(6, x_3RR, y_3RR); - part_RR3->DefineSection(0, -0.75, 0, 0, - 1); // (plane,-zplane/+zplane, x0, y0,(x/y)) + part_RR3->DefineSection(0, -0.75, 0, 0, 1); part_RR3->DefineSection(1, 0.78, 0, 0, 1); TGeoTranslation* tr_vol3_RR = - new TGeoTranslation("tr_vol3_RR", -0.25, 12.66, 0); // + new TGeoTranslation("tr_vol3_RR", -0.25, 12.66, 0); tr_vol3_RR->RegisterYourself(); // quit diagona-> qdi - Double_t x_qdi_Rbox = 3.1; // dx=1.5 - Double_t y_qdi_Rbox = 7.159; // - Double_t z_qdi_Rbox = 3.005; // + Double_t x_qdi_Rbox = 3.1; + Double_t y_qdi_Rbox = 7.159; + Double_t z_qdi_Rbox = 3.005; TGeoRotation* rot_Rqdi = new TGeoRotation("rot_Rqdi", 0, 24.775, 0); rot_Rqdi->RegisterYourself(); - TGeoCombiTrans* combi_Rqdi = - new TGeoCombiTrans(0, 5.579, -2.087, rot_Rqdi); // y= + TGeoCombiTrans* combi_Rqdi = new TGeoCombiTrans(0, 5.579, -2.087, rot_Rqdi); combi_Rqdi->SetName("combi_Rqdi"); combi_Rqdi->RegisterYourself(); // holes circular hole_a. diameter=6.5 (a(6,22)); hole_midle d=6.5 H11 Double_t radin_a_rail = 0.; - Double_t radout_a_rail = 0.325; // diameter 3.5 - Double_t high_a_rail = 0.82; // + Double_t radout_a_rail = 0.325; + Double_t high_a_rail = 0.82; - TGeoTranslation* tr_a_RR = - new TGeoTranslation("tr_a_RR", -0.7, 0.6, 1.825); // right + TGeoTranslation* tr_a_RR = new TGeoTranslation("tr_a_RR", -0.7, 0.6, 1.825); tr_a_RR->RegisterYourself(); - // circular hole_ir. diameter=M3 (3 mm)) prof trou:8, tar:6mm + Double_t radin_ir_rail = 0.; - Double_t radout_ir_rail = 0.15; // diameter 3 - Double_t high_ir_rail = 3.2; // 19 + Double_t radout_ir_rail = 0.15; + Double_t high_ir_rail = 3.2; TGeoRotation* rot_ir_RR = new TGeoRotation("rot_ir_RR", 90, 90, 0); rot_ir_RR->RegisterYourself(); - // in y = l_253.5 - 6. center in (0,6,0) + TGeoCombiTrans* combi_ir_RR = new TGeoCombiTrans(-8.62, 24.75, 1.5, rot_ir_RR); combi_ir_RR->SetName("combi_ir_RR"); @@ -1166,82 +1018,62 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) combi_ir2_RR->SetName("combi_ir2_RR"); combi_ir2_RR->RegisterYourself(); - TGeoCombiTrans* combi_rail_R = - new TGeoCombiTrans(24.1, -1.825, 0, rot_90x); // y= + TGeoCombiTrans* combi_rail_R = new TGeoCombiTrans(24.1, -1.825, 0, rot_90x); combi_rail_R->SetName("combi_rail_R"); combi_rail_R->RegisterYourself(); - TGeoCombiTrans* combi_rail_L = - new TGeoCombiTrans(-24.1, -1.825, 0, rot_90x); // y= + TGeoCombiTrans* combi_rail_L = new TGeoCombiTrans(-24.1, -1.825, 0, rot_90x); combi_rail_L->SetName("combi_rail_L"); combi_rail_L->RegisterYourself(); // trasl L and R - TGeoTranslation* tr_sr_l = new TGeoTranslation("tr_sr_l", -15.01, 0, 0); // + TGeoTranslation* tr_sr_l = new TGeoTranslation("tr_sr_l", -15.01, 0, 0); tr_sr_l->RegisterYourself(); - TGeoTranslation* tr_sr_r = new TGeoTranslation("tr_sr_r", 15.01, 0, 0); // + TGeoTranslation* tr_sr_r = new TGeoTranslation("tr_sr_r", 15.01, 0, 0); tr_sr_r->RegisterYourself(); - // + //////// new modfi b /////// cut arm TGeoXtru* part_RR2 = new TGeoXtru(2); part_RR2->SetName("part_RR2"); - //-TGeoVolume *vol_RR2 = gGeoManager->MakeXtru("S_XTRU_RR2",Al,2); - //-TGeoXtru *xtru_RR2 = (TGeoXtru*)vol_RR2->GetShape(); - // 1b) modi, reducing arm - // 1b) modi, reducing arm - Double_t x_RR2[8] = {-0.5, -0.5, -9.3, -9.3, - -7.3, -7.3, 1.5, 1.5}; // K,E,F,G,H,I,J,L//vertices - Double_t y_RR2[8] = {8.2, 13.863, 24.35, 25.65, - 25.65, 25.078, 14.591, 8.2}; // 35.75, 35.75 -->25.65 + + Double_t x_RR2[8] = {-0.5, -0.5, -9.3, -9.3, -7.3, -7.3, 1.5, 1.5}; + Double_t y_RR2[8] = {8.2, 13.863, 24.35, 25.65, 25.65, 25.078, 14.591, 8.2}; part_RR2->DefinePolygon(8, x_RR2, y_RR2); - part_RR2->DefineSection(0, 0.776, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) + part_RR2->DefineSection(0, 0.776, 0, 0, 1); part_RR2->DefineSection(1, 2.225, 0, 0, 1); // 2b) modi adding box new element 1 box TGeoXtru* adi1_RR = new TGeoXtru(2); adi1_RR->SetName("S_ADI1_RR"); - Double_t x_adi1RR[4] = {-0.5, -.5, 1.5, 1.5}; // vertices + Double_t x_adi1RR[4] = {-0.5, -.5, 1.5, 1.5}; Double_t y_adi1RR[4] = {2.2, 13.863, 13.863, 2.2}; adi1_RR->DefinePolygon(4, x_adi1RR, y_adi1RR); - adi1_RR->DefineSection(0, -0.75, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) - adi1_RR->DefineSection(1, 0.775, 0, 0, 1); // 0.76 + adi1_RR->DefineSection(0, -0.75, 0, 0, 1); + adi1_RR->DefineSection(1, 0.775, 0, 0, 1); - // 3b) modi adding new knee new element 2 new knee + // 3b) modi adding new knee new element TGeoXtru* adi2_RR = new TGeoXtru(2); // adi2_RR->SetName("S_ADI2_RR"); Double_t x_adi2RR[6] = {1.5, -0.5, -9.3, -9.3, -7.8, -7.8}; Double_t y_adi2RR[6] = {13.863, 13.863, 24.35, 25.65, 25.65, 25.078}; adi2_RR->DefinePolygon(6, x_adi2RR, y_adi2RR); - adi2_RR->DefineSection(0, -0.75, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) - adi2_RR->DefineSection(1, 0.7755, 0, 0, 1); // 0.775 + adi2_RR->DefineSection(0, -0.75, 0, 0, 1); + adi2_RR->DefineSection(1, 0.7755, 0, 0, 1); // 4)modi to quit ---> trap - // Double_t RL_dx1=2.66; //at -z (defined in rail L) - // Double_t RL_dx2=1; // dat +z - // Double_t RL_dy=2.2; // dz=7.5 to quit - // Double_t RL_dz=1.5; // dz=1.5 to quit - // auto *trap1 = new TGeoTrd1("TRAP1",RL_dx1,RL_dx2 ,RL_dy ,RL_dz); TGeoRotation* rot_RR_Z310 = new TGeoRotation("rot_RR_Z310", -50, 0, 0); rot_RR_Z310->RegisterYourself(); TGeoCombiTrans* combi_RR_trap = - new TGeoCombiTrans(-5, 18.633, -1.5 - 0.025, rot_RR_Z310); // y= + new TGeoCombiTrans(-5, 18.633, -1.5 - 0.025, rot_RR_Z310); combi_RR_trap->SetName("combi_RR_trap"); combi_RR_trap->RegisterYourself(); // 5) modi to quit inferior part box - // Double_t x_qinf_box=10.66; // defined in RL - // Double_t y_qinf_box=10.2; // - /// Double_t z_qinf_box=3.; // dz =1.5 - /// auto *s_RL_qinf_box =new TGeoBBox("S_RL_QINF_BOX", - /// x_qinf_box/2,y_qinf_box/2,z_qinf_box/2); TGeoCombiTrans* combi_RR_qbox = - new TGeoCombiTrans(-7, 23., -1.5 - 0.025, rot_RR_Z310); // rot to RR + new TGeoCombiTrans(-7, 23., -1.5 - 0.025, rot_RR_Z310); combi_RR_qbox->SetName("combi_RR_qbox"); combi_RR_qbox->RegisterYourself(); @@ -1249,46 +1081,26 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoXtru* pentfa_RR = new TGeoXtru(2); pentfa_RR->SetName("S_PENTFA_RR"); Double_t x_pentfaRR[5] = {1., 1., -0.13, -1., -1.}; - Double_t y_pentfaRR[5] = {1.125, 0.045, -1.125, -1.125, 1.125}; // 1.125 + Double_t y_pentfaRR[5] = {1.125, 0.045, -1.125, -1.125, 1.125}; pentfa_RR->DefinePolygon(5, x_pentfaRR, y_pentfaRR); - pentfa_RR->DefineSection(0, -5.05, 0, 0, - 1); //(plane,-zplane/+zplane, x0, y0,(x/y)) // 0.75 - pentfa_RR->DefineSection(1, 5.055, 0, 0, 1); // 0.76.. 0.9036 - - // TGeoRotation *rot_X90 = new TGeoRotation("rot_X90", 0,90,0); - // rot_X90->RegisterYourself(); - TGeoCombiTrans* combi_RR_pent = new TGeoCombiTrans( - -8.3, 30.705, 1.125 - 0.025, rot_X90); // x =8.3 , z= 1.125 + pentfa_RR->DefineSection(0, -5.05, 0, 0, 1); + pentfa_RR->DefineSection(1, 5.055, 0, 0, 1); + + TGeoCombiTrans* combi_RR_pent = + new TGeoCombiTrans(-8.3, 30.705, 1.125 - 0.025, rot_X90); combi_RR_pent->SetName("combi_RR_pent"); combi_RR_pent->RegisterYourself(); // shape for rail R new TGeoBBox("RR_1box", x_RR_1box / 2, y_RR_1box / 2, z_RR_1box / 2); - // auto *s_qdi_Rbox =new TGeoBBox("S_QDI_RBOX", - // x_qdi_Rbox/2,y_qdi_Rbox/2,z_qdi_Rbox/2); - - // auto *s_ir_hole=new - // TGeoTube("S_ir_HOLE",radin_ir_rail,radout_ir_rail,high_ir_rail/2); - - // auto *s_cc_hole=new - // TGeoTube("S_CC_HOLE",radin_cc_rail,radout_cc_rail,high_cc_rail/2); - // composite shape for rail R new TGeoCompositeShape( "RR_Shape_0", "RR_1box:tr_RR_1box + part_RR1 + part_RR2 - qdi_box:combi_qdi + " "S_ADI1_RR + S_ADI2_RR - TRAP1:combi_RR_trap - " - "S_RL_QINF_BOX:combi_RR_qbox +S_PENTFA_RR:combi_RR_pent "); // quit + - // part_RR3 - // old knee - - // auto * RR_Shape_0 = new - // TGeoCompositeShape("RR_Shape_0","RR_1box:tr_RR_1box+ S_part_RR1 + part_RR2 - // +part_RR3- qdi_box:combi_qdi + S_ir_HOLE:combi_ir_RR - // +S_ir_HOLE:combi_ir2_RR "); //-RR_1box:tr_RL_1box- S_b_HOLE:tr_b_RR - // -S_CC_HOLE:combi_cc2_RR + "S_RL_QINF_BOX:combi_RR_qbox +S_PENTFA_RR:combi_RR_pent "); // JOIN only for show L and R parts auto* rail_L_R_Shape = new TGeoCompositeShape( @@ -1296,13 +1108,10 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) TGeoVolume* rail_L_R_vol0 = new TGeoVolume("RAIL_L_R_VOL0", rail_L_R_Shape, malu5083); - // TGeoVolume* rail_L_R_vol0 = new TGeoVolume("RAIL_L_R_VOL0", rail_L_R_Shape, - // kMedAlu); TGeoRotation* rot_rLR = new TGeoRotation("rot_rLR", 180, 180, 0); rot_rLR->RegisterYourself(); - TGeoCombiTrans* combi_rLR = - new TGeoCombiTrans(0, -6.9, -0.5, rot_rLR); // 0,-6.9,-0.5-80 + TGeoCombiTrans* combi_rLR = new TGeoCombiTrans(0, -6.9, -0.5, rot_rLR); combi_rLR->SetName("combi_rLR"); combi_rLR->RegisterYourself(); @@ -1324,144 +1133,117 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) 13.4, 13.4, 12.6, 12.6, 0.}; sup_MB_L->DefinePolygon(11, x_sMB_L, y_sMB_L); - sup_MB_L->DefineSection(0, -0.4, 0, 0, - 1); //(plane, -zplane/ +zplane,x0,y0,(x/y)) + sup_MB_L->DefineSection(0, -0.4, 0, 0, 1); sup_MB_L->DefineSection(1, 0.4, 0, 0, 1); TGeoXtru* part_MBL_0 = new TGeoXtru(2); - part_MBL_0->SetName("part_MBL_0"); // V-MBL_0 + part_MBL_0->SetName("part_MBL_0"); - // vertices a,b,c,d,e,f,g,h Double_t x[8] = {0., 0, 6.1, 31.55, 34.55, 34.55, 31.946, 6.496}; Double_t y[8] = {-0.4, 0.4, 0.4, 13.0, 13.0, 12.2, 12.2, -0.4}; part_MBL_0->DefinePolygon(8, x, y); - part_MBL_0->DefineSection(0, -0.4, 0, 0, - 1); // (plane, -zplane/ +zplane,x0,y0,(x/y)) + part_MBL_0->DefineSection(0, -0.4, 0, 0, 1); part_MBL_0->DefineSection(1, 0.4, 0, 0, 1); TGeoRotation* rot1_MBL_0 = new TGeoRotation("rot1_MBL_0", -90, -90, 90); rot1_MBL_0->RegisterYourself(); // quit box in diag - Double_t x_mb_box = 0.8; // dx=4 - Double_t y_mb_box = 0.8; // dy=4 - Double_t z_mb_box = 0.81; // dz=4 to quit - TGeoTranslation* tr_mb_box = - new TGeoTranslation("tr_mb_box", 24.05, 9.55, 0); // 240.5 + Double_t x_mb_box = 0.8; + Double_t y_mb_box = 0.8; + Double_t z_mb_box = 0.81; + TGeoTranslation* tr_mb_box = new TGeoTranslation("tr_mb_box", 24.05, 9.55, 0); tr_mb_box->RegisterYourself(); // lateral hole-box - Double_t x_lat_box = 0.7; // dx=0.35 - Double_t y_lat_box = 1.8; // dy=0.9 - Double_t z_lat_box = 0.2; // dz=0.1 + Double_t x_lat_box = 0.7; + Double_t y_lat_box = 1.8; + Double_t z_lat_box = 0.2; TGeoTranslation* tr_lat1L_box = - new TGeoTranslation("tr_lat1L_box", 4.6, 0, 0.4); // + new TGeoTranslation("tr_lat1L_box", 4.6, 0, 0.4); tr_lat1L_box->RegisterYourself(); TGeoTranslation* tr_lat2L_box = - new TGeoTranslation("tr_lat2L_box", 9.6, 1.65, 0.4); // + new TGeoTranslation("tr_lat2L_box", 9.6, 1.65, 0.4); tr_lat2L_box->RegisterYourself(); - /// TGeoTranslation* tr_lat3L_box = new - /// TGeoTranslation("tr_lat3L_box", 18.53, 6.1, 0.4); // + TGeoTranslation* tr_lat3L_box = - new TGeoTranslation("tr_lat3L_box", 17.35, 5.923, 0.4); // 18.53 + new TGeoTranslation("tr_lat3L_box", 17.35, 5.923, 0.4); tr_lat3L_box->RegisterYourself(); TGeoTranslation* tr_lat4L_box = - new TGeoTranslation("tr_lat4L_box", 26.45, 10, 0.4); // + new TGeoTranslation("tr_lat4L_box", 26.45, 10, 0.4); tr_lat4L_box->RegisterYourself(); TGeoTranslation* tr_lat5L_box = - new TGeoTranslation("tr_lat5L_box", 29.9, 11.6, 0.4); // + new TGeoTranslation("tr_lat5L_box", 29.9, 11.6, 0.4); tr_lat5L_box->RegisterYourself(); TGeoTranslation* tr_lat1R_box = - new TGeoTranslation("tr_lat1R_box", 4.6, 0, -0.4); // + new TGeoTranslation("tr_lat1R_box", 4.6, 0, -0.4); tr_lat1R_box->RegisterYourself(); TGeoTranslation* tr_lat2R_box = - new TGeoTranslation("tr_lat2R_box", 9.6, 1.65, -0.4); // + new TGeoTranslation("tr_lat2R_box", 9.6, 1.65, -0.4); tr_lat2R_box->RegisterYourself(); - /// TGeoTranslation* tr_lat3R_box = new - /// TGeoTranslation("tr_lat3R_box", 18.53, 6.1, -0.4); // + TGeoTranslation* tr_lat3R_box = - new TGeoTranslation("tr_lat3R_box", 17.35, 5.923, -0.4); // + new TGeoTranslation("tr_lat3R_box", 17.35, 5.923, -0.4); tr_lat3R_box->RegisterYourself(); TGeoTranslation* tr_lat4R_box = - new TGeoTranslation("tr_lat4R_box", 26.45, 10, -0.4); // + new TGeoTranslation("tr_lat4R_box", 26.45, 10, -0.4); tr_lat4R_box->RegisterYourself(); TGeoTranslation* tr_lat5R_box = - new TGeoTranslation("tr_lat5R_box", 29.9, 11.6, -0.4); // + new TGeoTranslation("tr_lat5R_box", 29.9, 11.6, -0.4); tr_lat5R_box->RegisterYourself(); // circular hole_1mbl. diameter=3.5 H9 Double_t radin_1mb = 0.; - Double_t radout_1mb = 0.175; // diameter 3.5mm _0.35 cm - Double_t high_1mb = 2.825; // dh=+/- 4 - TGeoTranslation* tr1_mb = - new TGeoTranslation("tr1_mb", 18.48, 6.1, 0.); // right + Double_t radout_1mb = 0.175; + Double_t high_1mb = 2.825; + TGeoTranslation* tr1_mb = new TGeoTranslation("tr1_mb", 18.48, 6.1, 0.); tr1_mb->RegisterYourself(); - TGeoTranslation* tr2_mb = - new TGeoTranslation("tr2_mb", 24.15, 8.9, 0.); // right + TGeoTranslation* tr2_mb = new TGeoTranslation("tr2_mb", 24.15, 8.9, 0.); tr2_mb->RegisterYourself(); // circular hole_2mbl inclined and hole-up.diameter=M3 (3 mm)) prof , tar:8mm Double_t radin_2mb = 0.; - Double_t radout_2mb = 0.15; // diameter 0.3 - Double_t high_2mb = 0.82; /// dh=+/- 4 + Double_t radout_2mb = 0.15; + Double_t high_2mb = 0.82; TGeoRotation* rot_hole2_MBL = new TGeoRotation("rot_hole2_MBL", 0, 90, 0); rot_hole2_MBL->RegisterYourself(); - TGeoTranslation* tr_mbl = new TGeoTranslation("tr_mbl", -7.5, 0., 0.); // + TGeoTranslation* tr_mbl = new TGeoTranslation("tr_mbl", -7.5, 0., 0.); tr_mbl->RegisterYourself(); - TGeoTranslation* tr_mbr = new TGeoTranslation("tr_mbr", 7.5, 0, 0); // + TGeoTranslation* tr_mbr = new TGeoTranslation("tr_mbr", 7.5, 0, 0); tr_mbr->RegisterYourself(); // hole up || hup - TGeoCombiTrans* combi_hup_mb = - new TGeoCombiTrans(32.5, 12.6, 0, rot_90x); // y= + TGeoCombiTrans* combi_hup_mb = new TGeoCombiTrans(32.5, 12.6, 0, rot_90x); combi_hup_mb->SetName("combi_hup_mb"); combi_hup_mb->RegisterYourself(); // shape for rail MB new TGeoBBox("mb_box", x_mb_box / 2, y_mb_box / 2, z_mb_box / 2); - new TGeoTube("hole_1mbl", radin_1mb, radout_1mb, high_1mb / 2); // d3.5 - new TGeoTube("hole_2mbl", radin_2mb, radout_2mb, high_2mb / 2); // d3 + new TGeoTube("hole_1mbl", radin_1mb, radout_1mb, high_1mb / 2); + new TGeoTube("hole_2mbl", radin_2mb, radout_2mb, high_2mb / 2); new TGeoBBox("lat_box", x_lat_box / 2, y_lat_box / 2, z_lat_box / 2); // composite shape for rail_MB R + L auto* MB_Shape_0 = new TGeoCompositeShape( - "MB_Shape_0", " sup_MB_L - hole_2mbl:combi_hup_mb "); // new2020 + "MB_Shape_0", " sup_MB_L - hole_2mbl:combi_hup_mb "); auto* MB_Shape_0L = new TGeoCompositeShape( "MB_Shape_0L", "MB_Shape_0 - lat_box:tr_lat3L_box "); auto* MB_Shape_0R = new TGeoCompositeShape( "MB_Shape_0R", "MB_Shape_0 - lat_box:tr_lat3R_box "); - // auto * MB_Shape_0 = new TGeoCompositeShape("MB_Shape_0"," V_MBL_0 - - // mb_box:tr_mb_box - hole_1mbl:tr1_mb + hole_1mbl:tr2_mb - // -hole_2mbl:combi_hup_mb "); - ////new TGeoCompositeShape("MB_Shape_0", "part_MBL_0 - mb_box:tr_mb_box - - /// hole_1mbl:tr1_mb - hole_2mbl:combi_hup_mb"); - - /// new TGeoCompositeShape("MB_Shape_0L", "MB_Shape_0 - lat_box:tr_lat1L_box - - /// lat_box:tr_lat2L_box - lat_box:tr_lat3L_box - lat_box:tr_lat4L_box - - /// lat_box:tr_lat5L_box"); - - /// new TGeoCompositeShape("MB_Shape_0R", "MB_Shape_0 - lat_box:tr_lat1R_box - - /// lat_box:tr_lat2R_box - lat_box:tr_lat3R_box - lat_box:tr_lat4R_box - - /// lat_box:tr_lat5R_box"); - - new TGeoCompositeShape( - "MB_Shape_1L", - "MB_Shape_0L:rot1_MBL_0 - hole_2mbl"); // one piece "completed" + new TGeoCompositeShape("MB_Shape_1L", "MB_Shape_0L:rot1_MBL_0 - hole_2mbl"); // left and right new TGeoCompositeShape("MB_Shape_1R", "MB_Shape_0R:rot1_MBL_0 - hole_2mbl"); auto* MB_Shape_2 = new TGeoCompositeShape( "MB_Shape_2", " MB_Shape_1L:tr_mbl + MB_Shape_1R:tr_mbr "); - // TGeoVolume *sup_rail_MBL_vol0 = new - // TGeoVolume("SUPPORT_MBL_VOL0",MB_Shape_0,Al); TGeoVolume* sup_rail_MBL_vol = new TGeoVolume("SUPPORT_MBL_VOL", MB_Shape_2, malu5083); @@ -1475,7 +1257,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) stair->AddNode(Cross_mft_2, 2, new TGeoTranslation(0, 1.65 - 28.8, 9.55 + 0.675)); stair->AddNode(Cross_mb0, 4, - new TGeoTranslation(0, 5.423 - 28.8, 17.35 + 0.675)); // 6.1 + new TGeoTranslation(0, 5.423 - 28.8, 17.35 + 0.675)); stair->AddNode(Cross_mft_3, 5, new TGeoTranslation(0, 11.7 - 28.8, 25.55 + 0.675)); stair->AddNode(Cross_mft_4, 6, @@ -1490,6 +1272,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) Double_t r_final_z; Double_t tyMB0; + Double_t tyMB0_3; Double_t tzMB0; if (half == 0) { @@ -1502,6 +1285,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) r_final_z = 0; tyMB0 = -16.72; + tyMB0_3 = -18.0; tzMB0 = -(45.3 + 46.7) / 2; } @@ -1515,6 +1299,7 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) r_final_z = 180; tyMB0 = 16.72; + tyMB0_3 = 18.0; tzMB0 = -(45.3 + 46.7) / 2; } @@ -1525,63 +1310,59 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) // 9th new 2020 ELEMENT middle framework back ----------------------------- auto* frame_back = new TGeoVolumeAssembly("frame_back"); - /// variables + // rectangular box1 to quit - Double_t x_box_fwb = 15.8; // dx= 7.2 cm + Double_t x_box_fwb = 15.8; Double_t y_box_fwb = 5; Double_t z_box_fwb = 1; // rectangular box2 to add - Double_t x_box2_fwb = 1.9; // dx= 7.2 cm + Double_t x_box2_fwb = 1.9; Double_t y_box2_fwb = 0.5; Double_t z_box2_fwb = 0.6; ///// holes tub 1hole tranversal Double_t radin_fwb = 25.75; - Double_t radout_fwb = 26.75; // diameter 3.5 H9 (0.35cm) - Double_t high_fwb = 0.6; /// + Double_t radout_fwb = 26.75; + Double_t high_fwb = 0.6; // seg tub_back - Double_t radin_stub = 23.6; // 25.75 - Double_t radout_stub = 24.4; // 26.05 + Double_t radin_stub = 23.6; + Double_t radout_stub = 24.4; Double_t high_stub = 0.6; - Double_t ang_in_stub = 288.9; // 270 + 19.56 - Double_t ang_fin_stub = 342.; // 360-17.56 + Double_t ang_in_stub = 288.9; + Double_t ang_fin_stub = 342.; TGeoRotation* rot_1hole_fwb = new TGeoRotation("rot_1hole_fwb", 0, 90, 0); rot_1hole_fwb->RegisterYourself(); - /// h= hole + TGeoCombiTrans* acombi_fwb = new TGeoCombiTrans(5.2, 0, 0, rot_1hole_fwb); acombi_fwb->SetName("acombi_1h_fwb"); acombi_fwb->RegisterYourself(); - TGeoTranslation* tr_box_y24 = - new TGeoTranslation("tr_box_y24", 0, -24., 0.); // + TGeoTranslation* tr_box_y24 = new TGeoTranslation("tr_box_y24", 0, -24., 0.); tr_box_y24->RegisterYourself(); - TGeoTranslation* tr_box2_fwb = new TGeoTranslation( - "tr_box2_fwb", 24.4 - 1.9 / 2, -7.121 - 0.5 / 2, 0.); // + TGeoTranslation* tr_box2_fwb = + new TGeoTranslation("tr_box2_fwb", 24.4 - 1.9 / 2, -7.121 - 0.5 / 2, 0.); tr_box2_fwb->RegisterYourself(); TGeoRotation* rot_Z180_X180 = new TGeoRotation("rot_Z180_X180", 180, 180, 0); rot_Z180_X180->RegisterYourself(); TGeoTranslation* tr_fb = - new TGeoTranslation("tr_fb", 0, -2.3 - 0.06, 13.85 + 0.675); // + new TGeoTranslation("tr_fb", 0, -2.3 - 0.06, 13.85 + 0.675); tr_fb->RegisterYourself(); - // auto* q_box_fwb = new TGeoBBox("q_box_fwb", x_box_fwb / 2, y_box_fwb / 2, z_box_fwb / 2); auto* box2_fwb = new TGeoBBox("box2_fwb", x_box2_fwb / 2, y_box2_fwb / 2, z_box2_fwb / 2); auto* s_tub_fwb = new TGeoTube("s_tub_fwb", radin_fwb, radout_fwb, high_fwb / 2); - // auto *s_ctub_fwb=new - // TGeoTube("S_ctub_fwb",radin_fwb,radout_fwb,high_2hole_mb0/2); - auto* s_stub_fwb = - new TGeoTubeSeg("s_stub_fwb", radin_stub, radout_stub, high_stub / 2, - ang_in_stub, ang_fin_stub); // r_in,r_out,dZ,ang,ang + + auto* s_stub_fwb = new TGeoTubeSeg("s_stub_fwb", radin_stub, radout_stub, + high_stub / 2, ang_in_stub, ang_fin_stub); /// composite shape for mb0 @@ -1591,49 +1372,45 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) auto* fwb_Shape_1 = new TGeoCompositeShape( "fwb_Shape_1", "fwb_Shape_0 + fwb_Shape_0:rot_Z180_X180"); - auto* fwb_Volume = - new TGeoVolume("fwb_Volume", fwb_Shape_1, malu5083); // malu5083 + auto* fwb_Volume = new TGeoVolume("fwb_Volume", fwb_Shape_1, malu5083); frame_back->AddNode(fwb_Volume, 1, tr_fb); - //////////////////////////////////////////////// /// 10 th colonne_support_MB012 new 2020 auto* colonne_mb = new TGeoVolumeAssembly("colonne_mb"); - /// variables + // rectangular box - Double_t x_box_cmb = 1.9; // dx= 7.2 cm + Double_t x_box_cmb = 1.9; Double_t y_box_cmb = 0.6; Double_t z_box_cmb = 2.2033; ///// holes tub 1hole tranversal Double_t radin_c_mb = 0.; - Double_t radout_c_mb = 0.3; // diameter 3.5 H9 (0.35cm) - Double_t high_c_mb = 2.2033; /// + Double_t radout_c_mb = 0.3; + Double_t high_c_mb = 2.2033; TGeoRotation* rot_1c_mb0 = new TGeoRotation("rot_1c_mb0", 0, 90, 0); rot_1c_mb0->RegisterYourself(); - /// h= hole + TGeoCombiTrans* acombi_1c_mb0 = new TGeoCombiTrans(0.95, 0, 0, rot_1c_mb0); acombi_1c_mb0->SetName("acombi_1c_mb0"); acombi_1c_mb0->RegisterYourself(); - TGeoCombiTrans* bcombi_1c_mb0 = - new TGeoCombiTrans(-0.95, 0, 0, rot_1c_mb0); // y= + TGeoCombiTrans* bcombi_1c_mb0 = new TGeoCombiTrans(-0.95, 0, 0, rot_1c_mb0); bcombi_1c_mb0->SetName("bcombi_1c_mb0"); bcombi_1c_mb0->RegisterYourself(); // box to cut - Double_t x_boxq_cmb = 3.; // dx= 7.2 cm + Double_t x_boxq_cmb = 3.; Double_t y_boxq_cmb = 1.05; Double_t z_boxq_cmb = 4.; TGeoRotation* rot_X19 = new TGeoRotation("rot_X19", 0, -19, 0); rot_X19->RegisterYourself(); TGeoCombiTrans* combi_qbox = - new TGeoCombiTrans(0, +2.1 / 2 + 0.5, 0, rot_X19); // x =8.3 , z= 1.125 + new TGeoCombiTrans(0, +2.1 / 2 + 0.5, 0, rot_X19); combi_qbox->SetName("combi_qbox"); combi_qbox->RegisterYourself(); // shapes - auto* box_cmb = new TGeoBBox("box_cmb", x_box_cmb / 2, y_box_cmb / 2, z_box_cmb / 2); auto* tub_cmb = @@ -1641,27 +1418,21 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) auto* boxq_cmb = new TGeoBBox("boxq_cmb", x_boxq_cmb / 2, y_boxq_cmb / 2, z_boxq_cmb / 2); - // auto *s_2hole_mb0=new - // TGeoTube("S_2HOLE_MB0",radin_2hole_mb0,radout_2hole_mb0,high_2hole_mb0/2); - /// composite shape for mb0 - auto* c_mb_Shape_0 = new TGeoCompositeShape( "box_cmb:rot_1c_mb0 + tub_cmb:acombi_1c_mb0 + " "tub_cmb:bcombi_1c_mb0 - boxq_cmb:combi_qbox"); TGeoTranslation* tr_cmb = new TGeoTranslation( - "tr_cmb", 0, 5.923 - 28.8 + 2.2033 / 2 - 0.2, 17.35 + 0.675); // + "tr_cmb", 0, 5.923 - 28.8 + 2.2033 / 2 - 0.2, 17.35 + 0.675); tr_cmb->RegisterYourself(); /////////////////// - // auto * cross_mb0_Volume = new - // TGeoVolume("cross_mb0_Volume",c_mb0_Shape_0,Al); // + auto* colonne_mb_Volume = - new TGeoVolume("colonne_mb_Volume", c_mb_Shape_0, malu5083); // malu5083 + new TGeoVolume("colonne_mb_Volume", c_mb_Shape_0, malu5083); colonne_mb->AddNode(colonne_mb_Volume, 1, tr_cmb); - // auto* Half_3 = new TGeoVolumeAssembly("Half_3"); // Shell radii @@ -1748,143 +1519,376 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) "Half_3_Shape_2:Rz + Half_3_Shape_2:Rz_inv)+Half_3_Shape_3"); auto* Half_3_Volume = - new TGeoVolume("Half_3_Volume", Half_3_Shape_4, kMedAlu); - // Position of the piece relative to the origin which for this code is the - // center of the the Framework piece (See Half_2) - // Half_3->AddNode(Half_3_Volume, 1, new TGeoTranslation(0., 0., -19.)); + new TGeoVolume("Half_3_Volume", Half_3_Shape_4, malu5083); - TGeoRotation* rot_z180 = - new TGeoRotation("rot_z180", 0, 180, 0); // orig: (180,0,0) + TGeoRotation* rot_z180 = new TGeoRotation("rot_z180", 0, 180, 0); rot_z180->RegisterYourself(); - // in y = l_253.5 - 6. center in (0,6,0) + TGeoCombiTrans* combi_coat = new TGeoCombiTrans(0, 0, 19.5 - 0.45, rot_z180); combi_coat->SetName("combi_coat"); combi_coat->RegisterYourself(); Half_3->AddNode(Half_3_Volume, 1, combi_coat); - HalfConeVolume->AddNode(stair, 1, c_final); // + HalfConeVolume->AddNode(stair, 1, c_final); HalfConeVolume->AddNode(base, 2, c_final); HalfConeVolume->AddNode(rail_L_R, 3, c_final); // R&L HalfConeVolume->AddNode(Fra_front, 4, c_final); - HalfConeVolume->AddNode(middle, 5, c_final); // - HalfConeVolume->AddNode(frame_back, 6, c_final); // - HalfConeVolume->AddNode(colonne_mb, 7, c_final); // + HalfConeVolume->AddNode(middle, 5, c_final); + HalfConeVolume->AddNode(frame_back, 6, c_final); + HalfConeVolume->AddNode(colonne_mb, 7, c_final); - //========================== Mother Boards ========================================= + // ======================== Mother Boards and Services ======================= + Int_t signe; + if (half == 0) { + signe = -1; + } + if (half == 1) { + signe = +1; + } + auto& mftBaseParam = MFTBaseParam::Instance(); + if (mftBaseParam.buildServices) { + makeMotherBoards(HalfConeVolume, half, signe, tyMB0, tyMB0_3, tzMB0); + makeAirVentilation(HalfConeVolume, half, signe); + makeFlexCables(HalfConeVolume, half, signe); + makePowerCables(HalfConeVolume, half, signe); + if (!mftBaseParam.minimal && mftBaseParam.buildCone && mftBaseParam.buildReadoutCables) { + makeReadoutCables(HalfConeVolume, half, signe); + } + } + // =========================================================================== + + return HalfConeVolume; +} + +void HalfCone::makeAirVentilation(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe) +{ + TGeoMedium* mVentilation = gGeoManager->GetMedium("MFT_Polypropylene$"); + // Bottom + TGeoSubtraction* vent_subB1; + Float_t lB1 = 5.5; // half length + Float_t xB1 = 0.3; + Float_t yB1 = 0.4; + auto* ventB1 = new TGeoBBox(Form("ventB1_H%d", half), xB1, yB1, lB1); + auto* ventB1_int = + new TGeoBBox(Form("ventB1_int_H%d", half), 0.2, 0.3, lB1 + 0.0001); + vent_subB1 = new TGeoSubtraction(ventB1, ventB1_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalB1 = + new TGeoCompositeShape(Form("vent_finalB1_H%d", half), vent_subB1); + auto* vent_B1 = + new TGeoVolume(Form("ventB1_H%d", half), vent_finalB1, mVentilation); + vent_B1->SetLineColor(kGray); + auto* t_airB1 = new TGeoTranslation("t_airB1", signe * (15.3 - xB1), + -8.75 - yB1 - 0.1, -45.570 - lB1); + t_airB1->RegisterYourself(); + auto* r_airB1 = new TGeoRotation("r_airB1", 0.0, 0.0, 0.0); + r_airB1->RegisterYourself(); + auto* p_airB1 = new TGeoCombiTrans(*t_airB1, *r_airB1); + p_airB1->RegisterYourself(); + HalfConeVolume->AddNode(vent_B1, 1, p_airB1); + + TGeoSubtraction* vent_subB2; + Float_t lB2 = 10.6; // half length + auto* ventB2 = new TGeoBBox(Form("ventB2_H%d", half), yB1, xB1, lB2); + auto* ventB2_int = + new TGeoBBox(Form("ventB2_int_H%d", half), 0.3, 0.2, lB2 + 0.0001); + vent_subB2 = new TGeoSubtraction(ventB2, ventB2_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalB2 = + new TGeoCompositeShape(Form("vent_finalB2_H%d", half), vent_subB2); + auto* vent_B2 = + new TGeoVolume(Form("ventB2_H%d", half), vent_finalB2, mVentilation); + vent_B2->SetLineColor(kGray); + Float_t theta = -signe * 32.; + Float_t phi = signe * 23.; + Float_t thetaRad = theta * TMath::Pi() / 180.; + Float_t phiRad = phi * TMath::Pi() / 180.; + auto* r_airB2 = new TGeoRotation("r_airB2", 90.0 - phi, theta, 0.); + r_airB2->RegisterYourself(); + Float_t XairB2 = + signe * + (15.3 + lB2 * TMath::Sin(TMath::Abs(thetaRad) * TMath::Cos(phiRad))); + Float_t YairB2 = + -8.75 - 2 * yB1 + TMath::Sin(phiRad) * TMath::Sin(thetaRad) * lB2 + 0.2; + Float_t ZairB2 = -45.570 - 2 * lB1 - TMath::Cos(thetaRad) * lB2 - 0.2; + auto* t_airB2 = new TGeoTranslation("t_airB2", XairB2, YairB2, ZairB2); + t_airB2->RegisterYourself(); + auto* p_airB2 = new TGeoCombiTrans(*t_airB2, *r_airB2); + p_airB2->RegisterYourself(); + HalfConeVolume->AddNode(vent_B2, 1, p_airB2); + + TGeoSubtraction* vent_subB3; + Float_t lB3 = 4.8; // half length + auto* ventB3 = new TGeoBBox(Form("ventB3_H%d", half), yB1, xB1, lB3); + auto* ventB3_int = + new TGeoBBox(Form("ventB3_int_H%d", half), 0.3, 0.2, lB3 + 0.0001); + vent_subB3 = new TGeoSubtraction(ventB3, ventB3_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalB3 = + new TGeoCompositeShape(Form("vent_finalB3_H%d", half), vent_subB3); + auto* vent_B3 = + new TGeoVolume(Form("ventB3_H%d", half), vent_finalB3, mVentilation); + vent_B3->SetLineColor(kGray); + auto* r_airB3 = new TGeoRotation("r_airB3", 90.0 - phi, theta, 0.); + r_airB3->RegisterYourself(); + Float_t XairB3 = + signe * + (15.3 + + (2 * lB2 - lB3) * TMath::Sin(TMath::Abs(thetaRad) * TMath::Cos(phiRad)) - + xB1); + Float_t YairB3 = -8.75 - 2 * yB1 + + TMath::Sin(phiRad) * TMath::Sin(thetaRad) * (2 * lB2 - lB3) + + 0.2 - 1.9 * yB1; + Float_t ZairB3 = + -45.570 - 2 * lB1 - TMath::Cos(thetaRad) * (2 * lB2 - lB3) - 0.2; + + auto* t_airB3 = new TGeoTranslation("t_airB3", XairB3, YairB3, ZairB3); + + t_airB3->RegisterYourself(); + auto* p_airB3 = new TGeoCombiTrans(*t_airB3, *r_airB3); + p_airB3->RegisterYourself(); + HalfConeVolume->AddNode(vent_B3, 1, p_airB3); + + TGeoSubtraction* vent_subB4; + Float_t lB4 = 4.5; // half length + Float_t xB4 = 0.3; + Float_t yB4 = 0.8; + auto* ventB4 = new TGeoBBox(Form("ventB4_H%d", half), yB4, xB4, lB4); + auto* ventB4_int = + new TGeoBBox(Form("ventB4_int_H%d", half), 0.7, 0.2, lB4 + 0.0001); + vent_subB4 = new TGeoSubtraction(ventB4, ventB4_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalB4 = + new TGeoCompositeShape(Form("vent_finalB4_H%d", half), vent_subB4); + auto* vent_B4 = + new TGeoVolume(Form("ventB3_H%d", half), vent_finalB4, mVentilation); + vent_B4->SetLineColor(kGray); + auto* r_airB4 = + new TGeoRotation("r_airB4", 90.0 - signe * 25., -signe * 5, 0.); + r_airB4->RegisterYourself(); + auto* t_airB4 = new TGeoTranslation( + "t_airB4", + XairB2 + + signe * (lB2 * TMath::Sin(TMath::Abs(thetaRad) * TMath::Cos(phiRad)) + + 0.4), + YairB2 + TMath::Sin(phiRad) * TMath::Sin(thetaRad) * lB2 - 0.6, + ZairB3 - TMath::Cos(thetaRad) * lB2 * 0.965); + t_airB4->RegisterYourself(); + auto* p_airB4 = new TGeoCombiTrans(*t_airB4, *r_airB4); + p_airB4->RegisterYourself(); + HalfConeVolume->AddNode(vent_B4, 1, p_airB4); + + // Top + TGeoSubtraction* vent_subT1; + auto* ventT1 = new TGeoBBox(Form("ventT1_H%d", half), xB1, yB1, lB1); + auto* ventT1_int = + new TGeoBBox(Form("ventT1_int_H%d", half), 0.2, 0.3, lB1 + 0.0001); + vent_subT1 = new TGeoSubtraction(ventB1, ventB1_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalT1 = + new TGeoCompositeShape(Form("vent_finalT1_H%d", half), vent_subT1); + auto* vent_T1 = + new TGeoVolume(Form("ventT1_H%d", half), vent_finalT1, mVentilation); + vent_T1->SetLineColor(kGray); + auto* t_airT1 = new TGeoTranslation("t_airT1", signe * (15.3 - xB1), + -(-8.75 - yB1 - 0.1), -45.570 - lB1); + t_airB1->RegisterYourself(); + auto* r_airT1 = new TGeoRotation("r_airT1", 0.0, 0.0, 0.0); + r_airT1->RegisterYourself(); + auto* p_airT1 = new TGeoCombiTrans(*t_airT1, *r_airT1); + p_airT1->RegisterYourself(); + HalfConeVolume->AddNode(vent_T1, 1, p_airT1); + + TGeoSubtraction* vent_subT2; + auto* ventT2 = new TGeoBBox(Form("ventT2_H%d", half), yB1, xB1, lB2); + auto* ventT2_int = + new TGeoBBox(Form("ventT2_int_H%d", half), 0.3, 0.2, lB2 + 0.0001); + vent_subT2 = new TGeoSubtraction(ventT2, ventT2_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalT2 = + new TGeoCompositeShape(Form("vent_finalT2_H%d", half), vent_subT2); + auto* vent_T2 = + new TGeoVolume(Form("ventT2_H%d", half), vent_finalT2, mVentilation); + vent_T2->SetLineColor(kGray); + theta = -signe * 32.; + phi = signe * 23.; + thetaRad = theta * TMath::Pi() / 180.; + phiRad = phi * TMath::Pi() / 180.; + auto* r_airT2 = new TGeoRotation("r_airT2", 90.0 - phi, -theta, 0.); + r_airT2->RegisterYourself(); + auto* t_airT2 = new TGeoTranslation("t_airT2", -XairB2, -YairB2, ZairB2); + t_airT2->RegisterYourself(); + auto* p_airT2 = new TGeoCombiTrans(*t_airT2, *r_airT2); + p_airT2->RegisterYourself(); + HalfConeVolume->AddNode(vent_T2, 1, p_airT2); + + TGeoSubtraction* vent_subT3; + auto* ventT3 = new TGeoBBox(Form("ventT3_H%d", half), yB1, xB1, lB3); + auto* ventT3_int = + new TGeoBBox(Form("ventT3_int_H%d", half), 0.3, 0.2, lB3 + 0.0001); + vent_subT3 = new TGeoSubtraction(ventT3, ventT3_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalT3 = + new TGeoCompositeShape(Form("vent_finalT3_H%d", half), vent_subT3); + auto* vent_T3 = + new TGeoVolume(Form("ventT3_H%d", half), vent_finalT3, mVentilation); + vent_T3->SetLineColor(kGray); + auto* r_airT3 = new TGeoRotation("r_airT3", 90.0 - phi, -theta, 0.); + r_airT3->RegisterYourself(); + auto* t_airT3 = new TGeoTranslation("t_airT3", -XairB3, -YairB3, ZairB3); + t_airT3->RegisterYourself(); + auto* p_airT3 = new TGeoCombiTrans(*t_airT3, *r_airT3); + p_airT3->RegisterYourself(); + HalfConeVolume->AddNode(vent_T3, 1, p_airT3); + + TGeoSubtraction* vent_subT4; + auto* ventT4 = new TGeoBBox(Form("ventT4_H%d", half), yB4, xB4, lB4); + auto* ventT4_int = + new TGeoBBox(Form("ventT4_int_H%d", half), 0.7, 0.2, lB4 + 0.0001); + vent_subT4 = new TGeoSubtraction(ventT4, ventT4_int, nullptr, nullptr); + TGeoCompositeShape* vent_finalT4 = + new TGeoCompositeShape(Form("vent_finalT4_H%d", half), vent_subT4); + auto* vent_T4 = + new TGeoVolume(Form("ventT4_H%d", half), vent_finalT4, mVentilation); + vent_T4->SetLineColor(kGray); + auto* r_airT4 = + new TGeoRotation("r_airT4", 90.0 - signe * 25., signe * 5, 0.); + r_airT4->RegisterYourself(); + auto* t_airT4 = new TGeoTranslation( + "t_airT4", + -(XairB2 + + signe * (lB2 * TMath::Sin(TMath::Abs(thetaRad) * TMath::Cos(phiRad)) + + 0.4)), + -(YairB2 + TMath::Sin(phiRad) * TMath::Sin(thetaRad) * lB2 - 0.6), + ZairB3 - TMath::Cos(thetaRad) * lB2 * 0.965); + t_airT4->RegisterYourself(); + auto* p_airT4 = new TGeoCombiTrans(*t_airT4, *r_airT4); + p_airT4->RegisterYourself(); + HalfConeVolume->AddNode(vent_T4, 1, p_airT4); +} +void HalfCone::makeMotherBoards(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe, Double_t tyMB0, Double_t tyMB0_3, Double_t tzMB0) +{ // ============= MotherBoard 0 and 1 Double_t mMB0cu[3]; Double_t mMB0fr4; Double_t mMB0pol; Double_t mMB0epo; // Sizes - mMB0cu[0] = {13.65}; + mMB0cu[0] = {14.00}; // 13.65 old mMB0cu[1] = {0.00615}; // 122.5 microns * taux d'occupation 50% = 61.5 microns - mMB0cu[2] = {2.39}; - mMB0fr4 = 0.1; // 1 mm - mMB0pol = 0.0150; // 150 microns - mMB0epo = 0.0225; // 225 microns + mMB0cu[2] = {2.45}; // 2.39 old + mMB0fr4 = 0.1; // 1 m + mMB0pol = 0.0150; // 150 microns + mMB0epo = 0.0225; // 225 microns + // Materials auto* mCu = gGeoManager->GetMedium("MFT_Cu$"); auto* mFR4 = gGeoManager->GetMedium("MFT_FR4$"); auto* mPol = gGeoManager->GetMedium("MFT_Polyimide$"); auto* mEpo = gGeoManager->GetMedium("MFT_Epoxy$"); auto* mInox = gGeoManager->GetMedium("MFT_Inox$"); + auto* mPolyu = gGeoManager->GetMedium("MFT_Polyurethane$"); + // Mother boards connected to the first three disk auto* MotherBoard0 = new TGeoVolumeAssembly(Form("MotherBoard0_H%d", half)); // 4 layers TGeoVolume* vMB0cu = gGeoManager->MakeBox("vMB0cu", mCu, mMB0cu[0] / 2, mMB0cu[1] / 2, mMB0cu[2] / 2); TGeoVolume* vMB0fr4 = gGeoManager->MakeBox("vMB0fr4", mFR4, mMB0cu[0] / 2, mMB0fr4 / 2, mMB0cu[2] / 2); TGeoVolume* vMB0pol = gGeoManager->MakeBox("vMB0pol", mPol, mMB0cu[0] / 2, mMB0pol / 2, mMB0cu[2] / 2); TGeoVolume* vMB0epo = gGeoManager->MakeBox("vMB0epo", mEpo, mMB0cu[0] / 2, mMB0epo / 2, mMB0cu[2] / 2); + // Screws = Head + Thread TGeoVolume* vMB0screwH = gGeoManager->MakeTube("vMB0screwH", mInox, 0.0, 0.7 / 2, 0.35 / 2); // tete - TGeoVolume* vMB0screwT = gGeoManager->MakeTube("vMB0screwT", mInox, 0.0, 0.4 / 2, 1.2 / 2); // filetage + TGeoVolume* vMB0screwT = gGeoManager->MakeTube("vMB0screwT", mInox, 0.0, 0.4 / 2, 0.95 / 2); // filetage // Insert Sertitec TGeoVolume* vMB0serti = gGeoManager->MakeTube("vMB0serti", mInox, 0.16 / 2, 0.556 / 2, 0.15 / 2); // tete - vMB0cu->SetLineColor(kRed); + Float_t heigthConnector = 0.4; // male + female + TGeoVolume* vConnector = gGeoManager->MakeBox("vConnector", mPolyu, 6.2 / 2, heigthConnector / 2, 1.4 / 2); // in liquid-crystal polymer --> polyurethane? + vMB0cu->SetLineColor(kGreen); vMB0fr4->SetLineColor(kBlack); - vMB0pol->SetLineColor(kGreen); - vMB0epo->SetLineColor(kBlue); + vMB0pol->SetLineColor(kBlue); + vMB0epo->SetLineColor(kGreen); vMB0screwH->SetLineColor(kOrange); vMB0screwT->SetLineColor(kOrange); vMB0serti->SetLineColor(kOrange); + vConnector->SetLineColor(kGray + 3); + // Positioning the layers MotherBoard0->AddNode(vMB0cu, 1); - Int_t signe; - if (half == 0) { - signe = -1; - } - if (half == 1) { - signe = +1; - } + auto* t_MB0fr4 = new TGeoTranslation("translation_fr4", 0.0, signe * (mMB0fr4 + mMB0cu[1]) / 2, 0.0); t_MB0fr4->RegisterYourself(); MotherBoard0->AddNode(vMB0fr4, 1, t_MB0fr4); - auto* t_MB0pol = new TGeoTranslation("translation_pol", 0.0, signe * (mMB0fr4 + (mMB0cu[1] + mMB0pol) / 2), 0.0); + auto* t_MB0pol = + new TGeoTranslation("translation_pol", 0.0, signe * (mMB0fr4 + (mMB0cu[1] + mMB0pol) / 2), 0.0); t_MB0pol->RegisterYourself(); MotherBoard0->AddNode(vMB0pol, 1, t_MB0pol); auto* t_MB0epo = new TGeoTranslation("translation_epo", 0.0, signe * (mMB0fr4 + mMB0pol + (mMB0cu[1] + mMB0epo) / 2), 0.0); t_MB0epo->RegisterYourself(); MotherBoard0->AddNode(vMB0epo, 1, t_MB0epo); auto* r_MB0screw = new TGeoRotation("rotation_vMB0screw", 0, 90, 0); - auto* t_MB0screwH1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 1.65, - signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.35) / 2), 0.0, r_MB0screw); + auto* t_MB0screwH1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 1.65, signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.35) / 2), 0.0, r_MB0screw); t_MB0screwH1->RegisterYourself(); - auto* t_MB0screwT1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 1.65, -signe * (mMB0cu[1] + 1.2) / 2, 0.0, r_MB0screw); + auto* t_MB0screwT1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 1.65, -signe * (mMB0cu[1] + 0.95) / 2, 0.0, r_MB0screw); t_MB0screwT1->RegisterYourself(); - auto* t_MB0screwH2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 1.65), - signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.35) / 2), 0.0, r_MB0screw); + auto* t_MB0screwH2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 1.65), signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.35) / 2), 0.0, r_MB0screw); t_MB0screwH2->RegisterYourself(); - auto* t_MB0screwT2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 1.65), -signe * (mMB0cu[1] + 1.2) / 2, 0.0, r_MB0screw); + auto* t_MB0screwT2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 1.65), -signe * (mMB0cu[1] + 0.95) / 2, 0.0, r_MB0screw); t_MB0screwT2->RegisterYourself(); - auto* t_MB0serti1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 2.65, - signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.153) / 2), 0.0, r_MB0screw); + auto* t_MB0serti1 = new TGeoCombiTrans(mMB0cu[0] / 2 - 2.65, signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.153) / 2), 0.0, r_MB0screw); t_MB0serti1->RegisterYourself(); - auto* t_MB0serti2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 2.65), - signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.153) / 2), 0.0, r_MB0screw); + auto* t_MB0serti2 = new TGeoCombiTrans(-(mMB0cu[0] / 2 - 2.65), signe * (mMB0fr4 + mMB0pol + mMB0epo + (mMB0cu[1] + 0.153) / 2), 0.0, r_MB0screw); t_MB0serti2->RegisterYourself(); + auto* t_MB0Connector = new TGeoTranslation("translation_connector", 0.0, signe * (-mMB0cu[1] - 0.2), 0.0); + t_MB0Connector->RegisterYourself(); + MotherBoard0->AddNode(vMB0screwH, 1, t_MB0screwH1); MotherBoard0->AddNode(vMB0screwT, 1, t_MB0screwT1); MotherBoard0->AddNode(vMB0screwH, 1, t_MB0screwH2); MotherBoard0->AddNode(vMB0screwT, 1, t_MB0screwT2); MotherBoard0->AddNode(vMB0serti, 1, t_MB0serti1); MotherBoard0->AddNode(vMB0serti, 1, t_MB0serti2); - - // Positioning the board - auto* t_MB0 = new TGeoTranslation("translation_MB0", 0.0, tyMB0, tzMB0); - t_MB0->RegisterYourself(); - auto* t_MB1 = new TGeoTranslation("translation_MB1", 0.0, tyMB0, tzMB0 - 3.3); // 3.3 cm is the interdistance between disk 0 and 1 - t_MB1->RegisterYourself(); + MotherBoard0->AddNode(vConnector, 1, t_MB0Connector); + + // Positioning the boards on the disks + Float_t shift = 0.23; + Float_t shift3 = 0.09; + auto* t_disk0 = new TGeoTranslation("translation_disk0", 0.0, tyMB0 - signe * shift, tzMB0); + t_disk0->RegisterYourself(); + auto* t_disk1 = new TGeoTranslation("translation_disk1", 0.0, tyMB0 - signe * shift, tzMB0 - 3.3); + t_disk1->RegisterYourself(); + auto* t_disk2 = new TGeoTranslation("translation_disk2", 0.0, tyMB0_3 - signe * shift3, tzMB0 - 7.1); + t_disk2->RegisterYourself(); auto* r_MB0 = new TGeoRotation("rotation_MB0", 0.0, 0.0, 0.0); r_MB0->RegisterYourself(); - auto* p_MB0 = new TGeoCombiTrans(*t_MB0, *r_MB0); - p_MB0->RegisterYourself(); - auto* p_MB1 = new TGeoCombiTrans(*t_MB1, *r_MB0); - p_MB1->RegisterYourself(); - // Final addition of the board - HalfConeVolume->AddNode(MotherBoard0, 1, p_MB0); - HalfConeVolume->AddNode(MotherBoard0, 1, p_MB1); - + auto* p_disk0 = new TGeoCombiTrans(*t_disk0, *r_MB0); + p_disk0->RegisterYourself(); + auto* p_disk1 = new TGeoCombiTrans(*t_disk1, *r_MB0); + p_disk1->RegisterYourself(); + auto* p_disk2 = new TGeoCombiTrans(*t_disk2, *r_MB0); + p_disk2->RegisterYourself(); + // Final addition of the boards + HalfConeVolume->AddNode(MotherBoard0, 1, p_disk0); + HalfConeVolume->AddNode(MotherBoard0, 1, p_disk1); + HalfConeVolume->AddNode(MotherBoard0, 1, p_disk2); + + // Small boards on to the main mother board auto* MotherBoard0_1 = new TGeoVolumeAssembly(Form("MotherBoard0_1_H%d", half)); // 4 layers - TGeoVolume* vMB0cu_1 = gGeoManager->MakeBox("vMB0cu_1", mCu, 18.0 / 2, mMB0cu[1] / 2, 1.2 / 2); - TGeoVolume* vMB0fr4_1 = gGeoManager->MakeBox("vMB0fr4_1", mFR4, 18.0 / 2, mMB0fr4 / 2, 1.2 / 2); - TGeoVolume* vMB0pol_1 = gGeoManager->MakeBox("vMB0pol_1", mPol, 18.0 / 2, mMB0pol / 2, 1.2 / 2); - TGeoVolume* vMB0epo_1 = gGeoManager->MakeBox("vMB0epo_1", mEpo, 18.0 / 2, mMB0epo / 2, 1.2 / 2); - vMB0cu_1->SetLineColor(kRed); + TGeoVolume* vMB0cu_1 = + gGeoManager->MakeBox("vMB0cu_1", mCu, 18.0 / 2, mMB0cu[1] / 2, 1.2 / 2); + TGeoVolume* vMB0fr4_1 = + gGeoManager->MakeBox("vMB0fr4_1", mFR4, 18.0 / 2, mMB0fr4 / 2, 1.2 / 2); + TGeoVolume* vMB0pol_1 = + gGeoManager->MakeBox("vMB0pol_1", mPol, 18.0 / 2, mMB0pol / 2, 1.2 / 2); + TGeoVolume* vMB0epo_1 = + gGeoManager->MakeBox("vMB0epo_1", mEpo, 18.0 / 2, mMB0epo / 2, 1.2 / 2); + vMB0cu_1->SetLineColor(kGreen); vMB0fr4_1->SetLineColor(kBlack); - vMB0pol_1->SetLineColor(kGreen); - vMB0epo_1->SetLineColor(kBlue); - + vMB0pol_1->SetLineColor(kBlue); + vMB0epo_1->SetLineColor(kGreen); MotherBoard0_1->AddNode(vMB0cu_1, 1); MotherBoard0_1->AddNode(vMB0fr4_1, 1, t_MB0fr4); MotherBoard0_1->AddNode(vMB0pol_1, 1, t_MB0pol); MotherBoard0_1->AddNode(vMB0epo_1, 1, t_MB0epo); - // ================ MotherBoard 2 + // ================ Main Mother Board Double_t mMB2cu[4]; Double_t mMB2fr4; Double_t mMB2pol; @@ -1899,31 +1903,45 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) mMB2epo = 0.0075; // 75 microns auto* MotherBoard2 = new TGeoVolumeAssembly(Form("MotherBoard2_H%d", half)); // 4 layers - TGeoVolume* vMB2cu = gGeoManager->MakeTrd1("vMB2cu", mCu, mMB2cu[0] / 2, mMB2cu[1] / 2, mMB2cu[2] / 2, mMB2cu[3] / 2); - TGeoVolume* vMB2fr4 = gGeoManager->MakeTrd1("vMB2fr4", mFR4, mMB2cu[0] / 2, mMB2cu[1] / 2, mMB2fr4 / 2, mMB2cu[3] / 2); - TGeoVolume* vMB2pol = gGeoManager->MakeTrd1("vMB2pol", mPol, mMB2cu[0] / 2, mMB2cu[1] / 2, mMB2pol / 2, mMB2cu[3] / 2); - TGeoVolume* vMB2epo = gGeoManager->MakeTrd1("vMB2epo", mEpo, mMB2cu[0] / 2, mMB2cu[1] / 2, mMB2epo / 2, mMB2cu[3] / 2); - - vMB2cu->SetLineColor(kRed); + TGeoVolume* vMB2cu = + gGeoManager->MakeTrd1("vMB2cu", mCu, mMB2cu[0] / 2, mMB2cu[1] / 2, + mMB2cu[2] / 2, mMB2cu[3] / 2); + TGeoVolume* vMB2fr4 = + gGeoManager->MakeTrd1("vMB2fr4", mFR4, mMB2cu[0] / 2, mMB2cu[1] / 2, + mMB2fr4 / 2, mMB2cu[3] / 2); + TGeoVolume* vMB2pol = + gGeoManager->MakeTrd1("vMB2pol", mPol, mMB2cu[0] / 2, mMB2cu[1] / 2, + mMB2pol / 2, mMB2cu[3] / 2); + TGeoVolume* vMB2epo = + gGeoManager->MakeTrd1("vMB2epo", mEpo, mMB2cu[0] / 2, mMB2cu[1] / 2, + mMB2epo / 2, mMB2cu[3] / 2); + vMB2cu->SetLineColor(kGreen); vMB2fr4->SetLineColor(kBlack); - vMB2pol->SetLineColor(kGreen); - vMB2epo->SetLineColor(kBlue); - - auto* t_MB2fr4 = new TGeoTranslation("translation_fr4", 0.0, signe * (mMB2fr4 + mMB2cu[2]) / 2, 0.0); + vMB2pol->SetLineColor(kBlue); + vMB2epo->SetLineColor(kGreen + 2); + auto* t_MB2fr4 = new TGeoTranslation("translation_fr4", 0.0, + signe * (mMB2fr4 + mMB2cu[2]) / 2, 0.0); t_MB2fr4->RegisterYourself(); - auto* t_MB2pol = new TGeoTranslation("translation_pol", 0.0, signe * (mMB2fr4 + (mMB2cu[2] + mMB2pol) / 2), 0.0); + auto* t_MB2pol = + new TGeoTranslation("translation_pol", 0.0, + signe * (mMB2fr4 + (mMB2cu[2] + mMB2pol) / 2), 0.0); t_MB2pol->RegisterYourself(); - auto* t_MB2epo = new TGeoTranslation("translation_epo", 0.0, signe * (mMB2fr4 + mMB2pol + (mMB2cu[2] + mMB2epo) / 2), 0.0); + auto* t_MB2epo = new TGeoTranslation( + "translation_epo", 0.0, + signe * (mMB2fr4 + mMB2pol + (mMB2cu[2] + mMB2epo) / 2), 0.0); t_MB2epo->RegisterYourself(); - MotherBoard2->AddNode(vMB2cu, 1); MotherBoard2->AddNode(vMB2fr4, 1, t_MB2fr4); MotherBoard2->AddNode(vMB2pol, 1, t_MB2pol); MotherBoard2->AddNode(vMB2epo, 1, t_MB2epo); + for (Float_t i = -1; i < 3; i++) { - auto* t_MB2serti1 = new TGeoTranslation("translationMB2serti1", 8.5, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); + auto* t_MB2serti1 = new TGeoTranslation( + "translationMB2serti1", 8.5, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); t_MB2serti1->RegisterYourself(); - auto* t_MB2serti2 = new TGeoTranslation("translationMB2serti2", -8.5, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); + auto* t_MB2serti2 = + new TGeoTranslation("translationMB2serti2", -8.5, + -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); t_MB2serti2->RegisterYourself(); auto* p_MB2serti1 = new TGeoCombiTrans(*t_MB2serti1, *r_MB0screw); p_MB2serti1->RegisterYourself(); @@ -1934,9 +1952,12 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) } for (Float_t i = -2; i < 1; i++) { - auto* t_MB2serti3 = new TGeoTranslation("translationMB2serti3", 0.7, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); + auto* t_MB2serti3 = new TGeoTranslation( + "translationMB2serti3", 0.7, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); t_MB2serti3->RegisterYourself(); - auto* t_MB2serti4 = new TGeoTranslation("translationMB2serti4", -0.7, -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); + auto* t_MB2serti4 = + new TGeoTranslation("translationMB2serti4", -0.7, + -signe * (mMB2cu[2] + 0.153) / 2, 1.3 * i); t_MB2serti4->RegisterYourself(); auto* p_MB2serti3 = new TGeoCombiTrans(*t_MB2serti3, *r_MB0screw); p_MB2serti3->RegisterYourself(); @@ -1947,34 +1968,1190 @@ TGeoVolumeAssembly* HalfCone::createHalfCone(Int_t half) } for (Float_t i = -2; i < 2; i++) { - auto* t_MB2serti5 = new TGeoTranslation("translationMB2serti5", 7.0 * i + 3.5, -signe * (mMB2cu[2] + 0.153) / 2, -2.5); + auto* t_MB2serti5 = + new TGeoTranslation("translationMB2serti5", 7.0 * i + 3.5, + -signe * (mMB2cu[2] + 0.153) / 2, -2.5); t_MB2serti5->RegisterYourself(); auto* p_MB2serti5 = new TGeoCombiTrans(*t_MB2serti5, *r_MB0screw); p_MB2serti5->RegisterYourself(); - auto* t_MB2serti6 = new TGeoTranslation("translationMB2serti6", 7.0 * i + 3.5, -signe * (mMB2cu[2] + 0.153) / 2, -3.5); + auto* t_MB2serti6 = + new TGeoTranslation("translationMB2serti6", 7.0 * i + 3.5, + -signe * (mMB2cu[2] + 0.153) / 2, -3.5); t_MB2serti6->RegisterYourself(); auto* p_MB2serti6 = new TGeoCombiTrans(*t_MB2serti6, *r_MB0screw); p_MB2serti6->RegisterYourself(); MotherBoard2->AddNode(vMB0serti, 1, p_MB2serti5); MotherBoard2->AddNode(vMB0serti, 1, p_MB2serti6); } - // Connector board of MB0 on MB2 - auto* t_MotherBoard0_1 = new TGeoTranslation("translation_MB0_1", 0.0, -signe * (-0.5), 3.5); + // Two boards (from the two first disks) located on the main mother board + auto* t_MotherBoard0_1 = + new TGeoTranslation("translation_MB0_1", 0.0, -signe * (-heigthConnector - mMB2cu[2] - mMB2fr4 - mMB2pol - mMB2epo), 3.5); t_MotherBoard0_1->RegisterYourself(); - auto* t_MotherBoard0_2 = new TGeoTranslation("translation_MB0_2", 0.0, -signe * (-0.5), 1.5); + auto* t_MotherBoard0_2 = + new TGeoTranslation("translation_MB0_2", 0.0, -signe * (-heigthConnector - mMB2cu[2] - mMB2fr4 - mMB2pol - mMB2epo), 1.5); + t_MotherBoard0_2->RegisterYourself(); MotherBoard2->AddNode(MotherBoard0_1, 1, t_MotherBoard0_1); - MotherBoard2->AddNode(MotherBoard0_1, 1, t_MotherBoard0_2); - // Positioning the board - auto* t_MotherBoard2 = new TGeoTranslation("translation_MB2", 0.0, - -signe * (-20.52 + mMB2fr4 + mMB2pol + mMB2epo + 2.2 * TMath::Sin(19.0)), - -62.8 + 2.2 * TMath::Cos(19.0)); + MotherBoard2->AddNode(MotherBoard0_1, 2, t_MotherBoard0_2); + + TGeoVolume* vConnector2 = gGeoManager->MakeBox("vConnector2", mPolyu, 12.00 / 2, heigthConnector / 2, 0.7 / 2); + TGeoVolume* vConnector2p = gGeoManager->MakeBox("vConnector2p", mPolyu, 6.00 / 2, heigthConnector / 2, 0.7 / 2); + // === Readout cables connectors === + + TGeoVolume* vConnectorRC = gGeoManager->MakeBox("vConnectorRC-MB2", mPolyu, 6.00 / 2, heigthConnector / 2, 1.4 / 2); + // ================================== + Double_t yMB2Connector = signe * (mMB2cu[2] / 2 + mMB2fr4 + mMB2pol + mMB2epo + heigthConnector / 2); + auto* t_MB2Connector1 = new TGeoTranslation("translation_connector1", 0.0, yMB2Connector, 1.5); + t_MB2Connector1->RegisterYourself(); + auto* t_MB2Connector2 = new TGeoTranslation("translation_connector2", 0.0, yMB2Connector, 3.5); + t_MB2Connector2->RegisterYourself(); + auto* t_MB2ConnectorRC_1 = new TGeoTranslation("translation_connectorRC_1", 3.5, yMB2Connector, -0.5); + t_MB2ConnectorRC_1->RegisterYourself(); + auto* t_MB2ConnectorRC_2 = new TGeoTranslation("translation_connectorRC_2", -3.5, yMB2Connector, -0.5); + t_MB2ConnectorRC_1->RegisterYourself(); + auto* t_MB2ConnectorRC_3 = new TGeoTranslation("translation_connectorRC_3", 7.0, yMB2Connector, -3.5); + t_MB2ConnectorRC_2->RegisterYourself(); + auto* t_MB2ConnectorRC_4 = new TGeoTranslation("translation_connectorRC_4", -7.0, yMB2Connector, -3.5); + t_MB2ConnectorRC_2->RegisterYourself(); + + yMB2Connector = signe * (-mMB2cu[2] / 2 - heigthConnector / 2); + auto* t_MB2ConnectorRCp_1 = new TGeoTranslation("translation_connectorRCp_1", 4.0, yMB2Connector, 0.5); + t_MB2ConnectorRCp_1->RegisterYourself(); + auto* t_MB2ConnectorRCp_2 = new TGeoTranslation("translation_connectorRCp_2", -4.0, yMB2Connector, 0.5); + t_MB2ConnectorRCp_2->RegisterYourself(); + auto* t_MB2ConnectorRCp_3 = new TGeoTranslation("translation_connectorRCp_3", 7.0, yMB2Connector, -3.5); + t_MB2ConnectorRCp_3->RegisterYourself(); + auto* t_MB2ConnectorRCp_4 = new TGeoTranslation("translation_connectorRCp_4", -7.0, yMB2Connector, -3.5); + t_MB2ConnectorRCp_4->RegisterYourself(); + + vConnector2->SetLineColor(kGray + 3); + vConnectorRC->SetLineColor(kGray + 3); + MotherBoard2->AddNode(vConnector2, 1, t_MB2Connector1); + MotherBoard2->AddNode(vConnector2, 1, t_MB2Connector2); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRC_1); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRC_2); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRC_3); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRC_4); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRCp_1); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRCp_2); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRCp_3); + MotherBoard2->AddNode(vConnectorRC, 1, t_MB2ConnectorRCp_4); + + // Positioning the main mother board + auto* t_MotherBoard2 = new TGeoTranslation( + "translation_MB2", 0.0, + -signe * (-20.52 + mMB2fr4 + mMB2pol + mMB2epo + 2.2 * TMath::Sin(19.0)), + -62.8 + 2.2 * TMath::Cos(19.0)); t_MotherBoard2->RegisterYourself(); - auto* r_MotherBoard2 = new TGeoRotation("rotation_MB2", 0.0, -signe * (-19.0), 0.0); + auto* r_MotherBoard2 = + new TGeoRotation("rotation_MB2", 0.0, -signe * (-19.0), 0.0); r_MotherBoard2->RegisterYourself(); auto* p_MB2 = new TGeoCombiTrans(*t_MotherBoard2, *r_MotherBoard2); p_MB2->RegisterYourself(); HalfConeVolume->AddNode(MotherBoard2, 1, p_MB2); - //=================================================================== - return HalfConeVolume; +} + +void HalfCone::makeFlexCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe) +{ + auto* mCu = gGeoManager->GetMedium("MFT_Cu$"); + // Flat cables between disk 0 and main board + Float_t width_flat = 1.0; // 4 flexs, fully arbitrary! + Float_t thickness_flat = 0.0041; // 10 microns lines (228 lines, 0.0175x0.1 mm2) + 31 microns ground plane (~width 70 mm, thickness 0.0175mm) + Double_t theta1 = -22.70 + signe * 16.5; + Double_t theta2 = 22.60 + signe * 16.5; + TGeoVolume* vFlat0_1 = gGeoManager->MakeTubs("vFlat0_1", mCu, 15.0, 15.0 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat0_2 = gGeoManager->MakeTubs("vFlat0_2", mCu, 15.0, 15.0 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat0_3 = gGeoManager->MakeTubs("vFlat0_3", mCu, 15.0, 15.0 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat0_4 = gGeoManager->MakeTubs("vFlat0_4", mCu, 15.0, 15.0 + thickness_flat, width_flat / 2., theta1, theta2); + auto* t_flat0_1 = new TGeoTranslation("translation_flat0_1", 4.5, signe * 5.0, -56.73); + t_flat0_1->RegisterYourself(); + auto* t_flat0_2 = new TGeoTranslation("translation_flat0_2", 1.5, signe * 5.0, -56.73); + t_flat0_2->RegisterYourself(); + auto* t_flat0_3 = new TGeoTranslation("translation_flat0_3", -1.5, signe * 5.0, -56.73); + t_flat0_3->RegisterYourself(); + auto* t_flat0_4 = new TGeoTranslation("translation_flat0_4", -4.5, signe * 5.0, -56.73); + t_flat0_4->RegisterYourself(); + auto* r_flat0 = new TGeoRotation("rotation_flat0", signe * 90.0, signe * 90.0, 0.0); + r_flat0->RegisterYourself(); + auto* p_flat0_1 = new TGeoCombiTrans(*t_flat0_1, *r_flat0); + p_flat0_1->RegisterYourself(); + auto* p_flat0_2 = new TGeoCombiTrans(*t_flat0_2, *r_flat0); + p_flat0_2->RegisterYourself(); + auto* p_flat0_3 = new TGeoCombiTrans(*t_flat0_3, *r_flat0); + p_flat0_3->RegisterYourself(); + auto* p_flat0_4 = new TGeoCombiTrans(*t_flat0_4, *r_flat0); + p_flat0_4->RegisterYourself(); + HalfConeVolume->AddNode(vFlat0_1, 1, p_flat0_1); + HalfConeVolume->AddNode(vFlat0_2, 1, p_flat0_2); + HalfConeVolume->AddNode(vFlat0_3, 1, p_flat0_3); + HalfConeVolume->AddNode(vFlat0_4, 1, p_flat0_4); + + // Flat lines between disk 1 and main board + theta1 = -32.0 + signe * 24.69; + theta2 = 32.7 + signe * 24.69; + TGeoVolume* vFlat1_1 = gGeoManager->MakeTubs("vFlat1_1", mCu, 6.0, 6.00 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat1_2 = gGeoManager->MakeTubs("vFlat1_2", mCu, 6.0, 6.00 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat1_3 = gGeoManager->MakeTubs("vFlat1_3", mCu, 6.0, 6.00 + thickness_flat, width_flat / 2., theta1, theta2); + TGeoVolume* vFlat1_4 = gGeoManager->MakeTubs("vFlat1_4", mCu, 6.0, 6.00 + thickness_flat, width_flat / 2., theta1, theta2); + auto* t_flat1_1 = new TGeoTranslation("translation_flat1_1", 3., signe * 13.4, -55.6); + t_flat1_1->RegisterYourself(); + auto* t_flat1_2 = new TGeoTranslation("translation_flat1_2", 1., signe * 13.4, -55.6); + t_flat1_2->RegisterYourself(); + auto* t_flat1_3 = new TGeoTranslation("translation_flat1_3", -1., signe * 13.4, -55.6); + t_flat1_3->RegisterYourself(); + auto* t_flat1_4 = new TGeoTranslation("translation_flat1_4", -3., signe * 13.4, -55.6); + t_flat1_4->RegisterYourself(); + auto* r_flat1 = new TGeoRotation("rotation_flat1", signe * 90.0, signe * 90.0, 0.0); + r_flat1->RegisterYourself(); + auto* p_flat1_1 = new TGeoCombiTrans(*t_flat1_1, *r_flat1); + p_flat1_1->RegisterYourself(); + auto* p_flat1_2 = new TGeoCombiTrans(*t_flat1_2, *r_flat1); + p_flat1_2->RegisterYourself(); + auto* p_flat1_3 = new TGeoCombiTrans(*t_flat1_3, *r_flat1); + p_flat1_3->RegisterYourself(); + auto* p_flat1_4 = new TGeoCombiTrans(*t_flat1_4, *r_flat1); + p_flat1_4->RegisterYourself(); + HalfConeVolume->AddNode(vFlat1_1, 1, p_flat1_1); + HalfConeVolume->AddNode(vFlat1_2, 1, p_flat1_2); + HalfConeVolume->AddNode(vFlat1_3, 1, p_flat1_3); + HalfConeVolume->AddNode(vFlat1_4, 1, p_flat1_4); + + // Flat lines between disk 2 and main board + width_flat = 14.0; + thickness_flat = 0.017; // 3 microns lines (268 lines, 0.0175x0.09 mm2), 14 microns ground plane (140 mm x 0.0175mm) including flex ~20% longer in o2! + TGeoVolume* vFlat2 = gGeoManager->MakeBox("vFlat2", mCu, width_flat / 2, thickness_flat / 2, 2.3 / 2); + auto* t_flat2 = new TGeoTranslation("translation_flat2", 0.0, -signe * 18.35, -55.45); + t_flat2->RegisterYourself(); + auto* r_flat2 = new TGeoRotation("rotation_flat2", 0.0, -signe * (18.), 0.0); + r_flat2->RegisterYourself(); + auto* p_flat2 = new TGeoCombiTrans(*t_flat2, *r_flat2); + p_flat2->RegisterYourself(); + HalfConeVolume->AddNode(vFlat2, 1, p_flat2); +} + +void HalfCone::makeReadoutCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe) +{ + auto* mCu = gGeoManager->GetMedium("MFT_Cu$"); + + // Connector + Float_t heigthConnector = 0.4; // male + female + auto* mPolyu = gGeoManager->GetMedium("MFT_Polyurethane$"); + TGeoVolume* vConnectorRC = gGeoManager->MakeBox("vConnectorRC", mPolyu, 6.00 / 2, heigthConnector / 2, 1.4 / 2); + vConnectorRC->SetLineColor(kGray + 3); + + // Fondamental numbers for the sections of Copper in the 2 types of readout cables + Double_t section_ROcable_48pairs = 0.26544; // in cm2 + Double_t section_ROcable_16pairs = 0.08848; // in cm2 + + // Starting from the MFT backside: from the patch panel to MB2 + Double_t mRO1[3]; + mRO1[0] = {14.0}; //width + mRO1[1] = (16 * section_ROcable_48pairs + 6 * section_ROcable_16pairs) / mRO1[0]; // thickness + mRO1[2] = {6.5}; // length + TGeoVolume* vRO1 = gGeoManager->MakeBox("vRO1", mCu, mRO1[0] / 2, mRO1[1] / 2, mRO1[2] / 2); + Double_t zRO1 = -80.20; + auto* t_RO1 = new TGeoTranslation("translation_RO1", 0.0, -signe * 28.0, zRO1); + t_RO1->RegisterYourself(); + + Double_t mRO2[3]; + mRO2[0] = mRO1[0]; + mRO2[1] = (14 * section_ROcable_48pairs + 5 * section_ROcable_16pairs) / mRO2[0]; + mRO2[2] = {3.0}; + TGeoVolume* vRO2 = gGeoManager->MakeBox("vRO2", mCu, mRO2[0] / 2, mRO2[1] / 2, mRO2[2] / 2); + auto* t_RO2 = new TGeoTranslation("translation_RO2", 0.0, -signe * 28.0, zRO1 + mRO1[2] / 2 + mRO2[2] / 2); + t_RO2->RegisterYourself(); + + Double_t mRO3[3]; + mRO3[0] = mRO1[0]; + mRO3[1] = (12 * section_ROcable_48pairs + 4 * section_ROcable_16pairs) / mRO3[0]; + mRO3[2] = {3.6}; + TGeoVolume* vRO3 = gGeoManager->MakeBox("vRO3", mCu, mRO3[0] / 2, mRO3[1] / 2, mRO3[2] / 2); + auto* t_RO3 = new TGeoTranslation("translation_RO3", 0.0, -signe * 28.0, zRO1 + mRO1[2] / 2 + mRO2[2] + mRO3[2] / 2); + t_RO3->RegisterYourself(); + + Double_t eRO4 = 12 * section_ROcable_48pairs / mRO1[0]; + TGeoVolume* vRO4 = gGeoManager->MakeTubs("vRO4", mCu, 6.5, 6.5 + eRO4, mRO1[0] / 2, -21.0 + signe * 26.11, 21.0 + signe * 26.11); + auto* t_RO4 = new TGeoTranslation("translation_RO4", 0.0, signe * 21.4, -70.9); + t_RO4->RegisterYourself(); + auto* r_RO4 = new TGeoRotation("rotation_RO4", signe * 90.0, signe * 90.0, 0.0); + r_RO4->RegisterYourself(); + auto* p_RO4 = new TGeoCombiTrans(*t_RO4, *r_RO4); + p_RO4->RegisterYourself(); + HalfConeVolume->AddNode(vRO4, 1, p_RO4); + + // RO5 = cable connected to the upper part of MB2 + Double_t mRO5[3]; + mRO5[0] = {4.5}; + mRO5[1] = section_ROcable_48pairs / mRO5[0]; + mRO5[2] = {7.071}; + TGeoVolume* vRO5 = gGeoManager->MakeBox("vRO5", mCu, mRO5[0] / 2, mRO5[1] / 2, mRO5[2] / 2); + auto* t_RO5_1 = new TGeoTranslation("translation_RO5_1", 3.5, -signe * (20.83 + mRO5[2] / 2 * TMath::Sin(45.0 * TMath::Pi() / 180)), -61 - mRO5[2] / 2 * TMath::Cos(45 * TMath::Pi() / 180)); + t_RO5_1->RegisterYourself(); + auto* t_RO5_2 = new TGeoTranslation("translation_RO5_1", -3.5, -signe * (20.83 + mRO5[2] / 2 * TMath::Sin(45.0 * TMath::Pi() / 180)), -61 - mRO5[2] / 2 * TMath::Cos(45 * TMath::Pi() / 180)); + t_RO5_2->RegisterYourself(); + auto* r_RO5 = new TGeoRotation("rotation_RO5", 0.0, -signe * (45.0), 0.0); + r_RO5->RegisterYourself(); + auto* p_RO5_1 = new TGeoCombiTrans(*t_RO5_1, *r_RO5); + p_RO5_1->RegisterYourself(); + auto* p_RO5_2 = new TGeoCombiTrans(*t_RO5_2, *r_RO5); + p_RO5_2->RegisterYourself(); + + // =========== TGeoTrap ---> trapezoid shapes =============== + Float_t length = 2.20 / 2; + Float_t angleZ = 69.; + Float_t angleXY = -signe * 50.; + Float_t width = 3.5; + Float_t thickness = (section_ROcable_48pairs / width) / TMath::Cos(angleXY * TMath::Pi() / 180); // special thickness!! + TGeoVolume* vRO6 = new TGeoVolume("vRO6", new TGeoTrap(length, angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + Double_t yRO6 = -signe * (22.45 + length * 1.26 * TMath::Sin(angleZ * TMath::Pi() / 180)); + Double_t zRO6 = -64.1 - length * 2. * TMath::Cos(angleZ * TMath::Pi() / 180); + auto* t_RO6 = new TGeoTranslation("translation_RO6", 5.3, yRO6, zRO6); + t_RO6->RegisterYourself(); + auto* r_RO6 = new TGeoRotation("rotation_RO6", signe * 90.0, -signe * (0), 0.0); + r_RO6->RegisterYourself(); + auto* p_RO6 = new TGeoCombiTrans(*t_RO6, *r_RO6); + p_RO6->RegisterYourself(); + + TGeoVolume* vRO7 = new TGeoVolume("vRO7", new TGeoTrap(length, angleZ, -angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_RO7 = new TGeoTranslation("translation_RO6", -5.3, yRO6, zRO6); + t_RO7->RegisterYourself(); + auto* r_RO7 = new TGeoRotation("rotation_RO7", signe * 90.0, -signe * (0), 0.0); + r_RO7->RegisterYourself(); + auto* p_RO7 = new TGeoCombiTrans(*t_RO7, *r_RO7); + p_RO7->RegisterYourself(); + + // ============= under the main mother board ============= + Double_t mRO8[3]; + mRO8[0] = mRO5[0]; // width + mRO8[1] = 2 * section_ROcable_48pairs / mRO8[0]; // thickness, 2 cables coded in one cable + mRO8[2] = {6.40}; // length + TGeoVolume* vRO8 = gGeoManager->MakeBox("vRO8", mCu, mRO8[0] / 2, mRO8[1] / 2, mRO8[2] / 2); + Double_t yRO8 = -signe * (19.1 + mRO8[2] / 2 * TMath::Sin(19.0 * TMath::Pi() / 180)); + Double_t zRO8 = -59.95 - mRO8[2] / 2 * TMath::Cos(19.0 * TMath::Pi() / 180); + auto* t_RO8_1 = new TGeoTranslation("translation_RO8_1", 3.5, yRO8, zRO8); + t_RO8_1->RegisterYourself(); + auto* t_RO8_2 = new TGeoTranslation("translation_RO8_1", -3.5, yRO8, zRO8); + t_RO8_2->RegisterYourself(); + auto* r_RO8 = new TGeoRotation("rotation_RO8", 0.0, -signe * (19.0), 0.0); + r_RO8->RegisterYourself(); + auto* p_RO8_1 = new TGeoCombiTrans(*t_RO8_1, *r_RO8); + p_RO8_1->RegisterYourself(); + auto* p_RO8_2 = new TGeoCombiTrans(*t_RO8_2, *r_RO8); + p_RO8_2->RegisterYourself(); + + Double_t mRO9[3]; + mRO9[0] = mRO5[0]; // width + mRO9[1] = 2 * section_ROcable_48pairs / mRO9[0]; // thickness, 2 cables coded in one cable + mRO9[2] = {4.5}; // length + TGeoVolume* vRO9 = gGeoManager->MakeBox("vRO9", mCu, mRO9[0] / 2, mRO9[1] / 2, mRO9[2] / 2); + auto* t_RO9_1 = new TGeoTranslation("translation_RO9_1", 3.5, -signe * (23.5), -66.15); + t_RO9_1->RegisterYourself(); + auto* t_RO9_2 = new TGeoTranslation("translation_RO9_2", -3.5, -signe * (23.5), -66.15); + t_RO9_2->RegisterYourself(); + auto* r_RO9 = new TGeoRotation("rotation_RO9", 0.0, -signe * (90.0), 0.0); + r_RO9->RegisterYourself(); + auto* p_RO9_1 = new TGeoCombiTrans(*t_RO9_1, *r_RO9); + p_RO9_1->RegisterYourself(); + auto* p_RO9_2 = new TGeoCombiTrans(*t_RO9_2, *r_RO9); + p_RO9_2->RegisterYourself(); + + // =========== For the 2 latest disks ================ + // ============= Disk 3 ============ + length = 6.9 / 2; + angleZ = -45.; + angleXY = 0.; + thickness = 3.5; // inversion width/thickness! this is the width + width = section_ROcable_48pairs / thickness; // inversion width/thickness! this is the thickness + // ==== front + TGeoVolume* vRO_D3_1 = new TGeoVolume("vRO_D3_1", new TGeoTrap(length, angleZ + 10., angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD3_1 = new TGeoTranslation("translation_ROD3_1", 4.5, -signe * (20.9 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -67.4); + t_ROD3_1->RegisterYourself(); + auto* r_ROD3_1 = new TGeoRotation("rotation_ROD3_1", signe * 180.0, signe * (90), 0.0); + r_ROD3_1->RegisterYourself(); + auto* p_ROD3_1 = new TGeoCombiTrans(*t_ROD3_1, *r_ROD3_1); + p_ROD3_1->RegisterYourself(); + + TGeoVolume* vRO_D3_2 = new TGeoVolume("vRO_D3_2", new TGeoTrap(length, -angleZ - 10., angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD3_2 = new TGeoTranslation("translation_ROD3_2", -4.5, -signe * (20.9 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -67.4); + t_ROD3_2->RegisterYourself(); + auto* r_ROD3_2 = new TGeoRotation("rotation_ROD3_2", signe * 180.0, signe * (90), 0.0); + r_ROD3_2->RegisterYourself(); + auto* p_ROD3_2 = new TGeoCombiTrans(*t_ROD3_2, *r_ROD3_2); + p_ROD3_2->RegisterYourself(); + + // ===== rear + TGeoVolume* vRO_D3_3 = new TGeoVolume("vRO_D3_3", new TGeoTrap(length + 0.4, angleZ + 10., angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD3_3 = new TGeoTranslation("translation_ROD3_3", 4.5, -signe * (21.3 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -69.4); + t_ROD3_3->RegisterYourself(); + auto* r_ROD3_3 = new TGeoRotation("rotation_ROD3_3", signe * 180.0, signe * (90), 0.0); + r_ROD3_3->RegisterYourself(); + auto* p_ROD3_3 = new TGeoCombiTrans(*t_ROD3_3, *r_ROD3_3); + p_ROD3_3->RegisterYourself(); + + TGeoVolume* vRO_D3_4 = new TGeoVolume("vRO_D3_4", new TGeoTrap(length + 0.4, -angleZ - 10., angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD3_4 = new TGeoTranslation("translation_ROD3_4", -4.5, -signe * (21.3 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -69.4); + t_ROD3_4->RegisterYourself(); + auto* r_ROD3_4 = new TGeoRotation("rotation_ROD3_4", signe * 180.0, signe * (90), 0.0); + r_ROD3_4->RegisterYourself(); + auto* p_ROD3_4 = new TGeoCombiTrans(*t_ROD3_4, *r_ROD3_4); + p_ROD3_4->RegisterYourself(); + + auto* t_ConnectorRC3_1 = new TGeoTranslation("translation_RC3_1", 5.9, -signe * (20.2), -67.87 + heigthConnector / 2); + t_ConnectorRC3_1->RegisterYourself(); + auto* r_ConnectorRC3_1 = new TGeoRotation("rotation_RC3_1", 0.0, 90, 0.0); + r_ConnectorRC3_1->RegisterYourself(); + auto* p_ConnectorRC3_1 = new TGeoCombiTrans(*t_ConnectorRC3_1, *r_ConnectorRC3_1); + p_ConnectorRC3_1->RegisterYourself(); + auto* t_ConnectorRC3_2 = new TGeoTranslation("translation_RC3_2", -5.9, -signe * (20.2), -67.87 + heigthConnector / 2); + t_ConnectorRC3_2->RegisterYourself(); + auto* p_ConnectorRC3_2 = new TGeoCombiTrans(*t_ConnectorRC3_2, *r_ConnectorRC3_1); + p_ConnectorRC3_2->RegisterYourself(); + auto* t_ConnectorRC3_3 = new TGeoTranslation("translation_RC3_3", 5.9, -signe * (20.2), -68.93 - heigthConnector / 2); + t_ConnectorRC3_3->RegisterYourself(); + auto* p_ConnectorRC3_3 = new TGeoCombiTrans(*t_ConnectorRC3_3, *r_ConnectorRC3_1); + p_ConnectorRC3_3->RegisterYourself(); + auto* t_ConnectorRC3_4 = new TGeoTranslation("translation_RC3_4", -5.9, -signe * (20.2), -68.93 - heigthConnector / 2); + t_ConnectorRC3_4->RegisterYourself(); + auto* p_ConnectorRC3_4 = new TGeoCombiTrans(*t_ConnectorRC3_4, *r_ConnectorRC3_1); + p_ConnectorRC3_4->RegisterYourself(); + + // ============== Disk 4 ================ + length = 6.3 / 2; + angleZ = -20.; + angleXY = 0.; + thickness = 3.5; // inversion width and thickness! this is the width + width = section_ROcable_48pairs / thickness; // inversion width and thickness! this is the thickness + Float_t xD4 = 6.1; + Float_t yD4 = 21.6; + // ===== front + TGeoVolume* vRO_D4_1 = new TGeoVolume("vRO_D4_1", new TGeoTrap(length, angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_1 = new TGeoTranslation("translation_ROD4_1", xD4, -signe * (yD4 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -75.8); + t_ROD4_1->RegisterYourself(); + auto* r_ROD4_1 = new TGeoRotation("rotation_ROD4_1", signe * 180.0, signe * (90), 0.0); + r_ROD4_1->RegisterYourself(); + auto* p_ROD4_1 = new TGeoCombiTrans(*t_ROD4_1, *r_ROD3_1); + p_ROD4_1->RegisterYourself(); + + TGeoVolume* vRO_D4_2 = new TGeoVolume("vRO_D4_2", new TGeoTrap(length, -angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_2 = new TGeoTranslation("translation_ROD4_2", -xD4, -signe * (yD4 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -75.8); + t_ROD4_2->RegisterYourself(); + auto* r_ROD4_2 = new TGeoRotation("rotation_ROD4_2", signe * 180.0, signe * (90), 0.0); + r_ROD4_2->RegisterYourself(); + auto* p_ROD4_2 = new TGeoCombiTrans(*t_ROD4_2, *r_ROD4_2); + p_ROD4_2->RegisterYourself(); + + // ===== rear + TGeoVolume* vRO_D4_3 = new TGeoVolume("vRO_D4_3", new TGeoTrap(length, angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_3 = new TGeoTranslation("translation_ROD4_3", xD4, -signe * (yD4 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -77.8); + t_ROD4_3->RegisterYourself(); + auto* r_ROD4_3 = new TGeoRotation("rotation_ROD4_3", signe * 180.0, signe * (90), 0.0); + r_ROD4_3->RegisterYourself(); + auto* p_ROD4_3 = new TGeoCombiTrans(*t_ROD4_3, *r_ROD3_3); + p_ROD4_3->RegisterYourself(); + + TGeoVolume* vRO_D4_4 = new TGeoVolume("vRO_D4_4", new TGeoTrap(length, -angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_4 = new TGeoTranslation("translation_ROD4_4", -xD4, -signe * (yD4 + length * TMath::Cos(angleZ * TMath::Pi() / 180)), -77.8); + t_ROD4_4->RegisterYourself(); + auto* r_ROD4_4 = new TGeoRotation("rotation_ROD4_4", signe * 180.0, signe * (90), 0.0); + r_ROD4_4->RegisterYourself(); + auto* p_ROD4_4 = new TGeoCombiTrans(*t_ROD4_4, *r_ROD4_4); + p_ROD4_4->RegisterYourself(); + + // Middle + // 16 pairs cable + width = section_ROcable_16pairs / thickness; // inversion width and thickness! this is thickness... + TGeoVolume* vRO_D4_5 = new TGeoVolume("vRO_D4_5", new TGeoTrap(length, 0., 0., width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_5 = new TGeoTranslation("translation_ROD4_5", 0, -signe * (yD4 + length - 0.2), -75.8); + t_ROD4_5->RegisterYourself(); + auto* r_ROD4_5 = new TGeoRotation("rotation_ROD4_5", signe * 180.0, signe * (90), 0.0); + r_ROD4_5->RegisterYourself(); + auto* p_ROD4_5 = new TGeoCombiTrans(*t_ROD4_5, *r_ROD4_5); + p_ROD4_5->RegisterYourself(); + TGeoVolume* vRO_D4_6 = new TGeoVolume("vRO_D4_6", new TGeoTrap(length, 0., 0., width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_ROD4_6 = new TGeoTranslation("translation_ROD4_6", 0, -signe * (yD4 + length - 0.2), -77.8); + t_ROD4_6->RegisterYourself(); + auto* r_ROD4_6 = new TGeoRotation("rotation_ROD4_6", signe * 180.0, signe * (90), 0.0); + r_ROD4_6->RegisterYourself(); + auto* p_ROD4_6 = new TGeoCombiTrans(*t_ROD4_6, *r_ROD4_6); + p_ROD4_6->RegisterYourself(); + + auto* t_ConnectorRC4_1 = new TGeoTranslation("translation_RC4_1", 7.5, -signe * (21.5), -76.26 + heigthConnector / 2); + t_ConnectorRC4_1->RegisterYourself(); + auto* p_ConnectorRC4_1 = new TGeoCombiTrans(*t_ConnectorRC4_1, *r_ConnectorRC3_1); + p_ConnectorRC4_1->RegisterYourself(); + auto* t_ConnectorRC4_2 = new TGeoTranslation("translation_RC4_2", -7.5, -signe * (21.5), -76.26 + heigthConnector / 2); + t_ConnectorRC4_2->RegisterYourself(); + auto* p_ConnectorRC4_2 = new TGeoCombiTrans(*t_ConnectorRC4_2, *r_ConnectorRC3_1); + p_ConnectorRC4_2->RegisterYourself(); + auto* t_ConnectorRC4_3 = new TGeoTranslation("translation_RC4_3", 7.5, -signe * (21.5), -77.34 - heigthConnector / 2); + t_ConnectorRC4_3->RegisterYourself(); + auto* p_ConnectorRC4_3 = new TGeoCombiTrans(*t_ConnectorRC4_3, *r_ConnectorRC3_1); + p_ConnectorRC4_3->RegisterYourself(); + auto* t_ConnectorRC4_4 = new TGeoTranslation("translation_RC4_4", -7.5, -signe * (21.5), -77.34 - heigthConnector / 2); + t_ConnectorRC4_4->RegisterYourself(); + auto* p_ConnectorRC4_4 = new TGeoCombiTrans(*t_ConnectorRC4_4, *r_ConnectorRC3_1); + p_ConnectorRC4_4->RegisterYourself(); + auto* t_ConnectorRC4_5 = new TGeoTranslation("translation_RC4_5", 0, -signe * (21.5), -76.26 + heigthConnector / 2); + t_ConnectorRC4_5->RegisterYourself(); + auto* p_ConnectorRC4_5 = new TGeoCombiTrans(*t_ConnectorRC4_5, *r_ConnectorRC3_1); + p_ConnectorRC4_5->RegisterYourself(); + auto* t_ConnectorRC4_6 = new TGeoTranslation("translation_RC4_6", 0, -signe * (21.5), -77.34 - heigthConnector / 2); + t_ConnectorRC4_6->RegisterYourself(); + auto* p_ConnectorRC4_6 = new TGeoCombiTrans(*t_ConnectorRC4_6, *r_ConnectorRC3_1); + p_ConnectorRC4_6->RegisterYourself(); + + // ========== For the RO Supply Unit (PSU) ========== + length = 1.6 / 2; + angleZ = 70.; + angleXY = -signe * 25.; + width = 3.5; + thickness = section_ROcable_16pairs / width / TMath::Cos(angleZ * TMath::Pi() / 180); + TGeoVolume* vRO_PSU_1 = new TGeoVolume("vRO_PSU_1", new TGeoTrap(length, angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + Double_t yPSU = -signe * (24.8 + length * 1.26 * TMath::Sin(angleZ * TMath::Pi() / 180)); + Double_t zPSU = -71.1 - length * 2. * TMath::Cos(angleZ * TMath::Pi() / 180); + auto* t_RO_PSU_1 = new TGeoTranslation("translation_RO_PSU_1", 5.0, yPSU, zPSU); + t_RO_PSU_1->RegisterYourself(); + auto* r_RO_PSU_1 = new TGeoRotation("rotation_RO_PSU_1", signe * 90.0, -signe * (0), 0.0); + r_RO_PSU_1->RegisterYourself(); + auto* p_RO_PSU_1 = new TGeoCombiTrans(*t_RO_PSU_1, *r_RO_PSU_1); + p_RO_PSU_1->RegisterYourself(); + + TGeoVolume* vRO_PSU_2 = new TGeoVolume("vRO_PSU_2", new TGeoTrap(length, angleZ, -angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_RO_PSU_2 = new TGeoTranslation("translation_RO_PSU_2", -5.0, yPSU, zPSU); + t_RO_PSU_2->RegisterYourself(); + auto* r_RO_PSU_2 = new TGeoRotation("rotation_RO_PSU_2", signe * 90.0, -signe * (0), 0.0); + r_RO_PSU_2->RegisterYourself(); + auto* p_RO_PSU_2 = new TGeoCombiTrans(*t_RO_PSU_2, *r_RO_PSU_2); + p_RO_PSU_2->RegisterYourself(); + + zPSU = -72.98 - length * 2. * TMath::Cos(angleZ * TMath::Pi() / 180); + TGeoVolume* vRO_PSU_3 = new TGeoVolume("vRO_PSU_3", new TGeoTrap(length, -angleZ, angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_RO_PSU_3 = new TGeoTranslation("translation_RO_PSU_3", 5.0, yPSU, zPSU); + t_RO_PSU_3->RegisterYourself(); + auto* r_RO_PSU_3 = new TGeoRotation("rotation_RO_PSU_3", signe * 90.0, -signe * (0), 0.0); + r_RO_PSU_3->RegisterYourself(); + auto* p_RO_PSU_3 = new TGeoCombiTrans(*t_RO_PSU_3, *r_RO_PSU_3); + p_RO_PSU_3->RegisterYourself(); + + TGeoVolume* vRO_PSU_4 = new TGeoVolume("vRO_PSU_4", new TGeoTrap(length, -angleZ, -angleXY, width / 2, thickness / 2, thickness / 2, 0., width / 2, thickness / 2, thickness / 2, 0.), mCu); + auto* t_RO_PSU_4 = new TGeoTranslation("translation_RO_PSU_4", -5.0, yPSU, zPSU); + t_RO_PSU_4->RegisterYourself(); + auto* r_RO_PSU_4 = new TGeoRotation("rotation_RO_PSU_4", signe * 90.0, -signe * (0), 0.0); + r_RO_PSU_4->RegisterYourself(); + auto* p_RO_PSU_4 = new TGeoCombiTrans(*t_RO_PSU_4, *r_RO_PSU_4); + p_RO_PSU_4->RegisterYourself(); + + auto* t_ConnectorPSU_1 = new TGeoTranslation("translation_PSU_1", 6.9, -signe * (23.5), -70.44 - heigthConnector / 2); + t_ConnectorPSU_1->RegisterYourself(); + auto* p_ConnectorPSU_1 = new TGeoCombiTrans(*t_ConnectorPSU_1, *r_ConnectorRC3_1); + p_ConnectorPSU_1->RegisterYourself(); + auto* t_ConnectorPSU_2 = new TGeoTranslation("translation_PSU_2", -6.9, -signe * (23.5), -70.44 - heigthConnector / 2); + t_ConnectorPSU_2->RegisterYourself(); + auto* p_ConnectorPSU_2 = new TGeoCombiTrans(*t_ConnectorPSU_2, *r_ConnectorRC3_1); + p_ConnectorPSU_2->RegisterYourself(); + auto* t_ConnectorPSU_3 = new TGeoTranslation("translation_PSU_3", 6.9, -signe * (23.5), -74.77 + heigthConnector / 2); + t_ConnectorPSU_3->RegisterYourself(); + auto* p_ConnectorPSU_3 = new TGeoCombiTrans(*t_ConnectorPSU_3, *r_ConnectorRC3_1); + p_ConnectorPSU_3->RegisterYourself(); + auto* t_ConnectorPSU_4 = new TGeoTranslation("translation_PSU_4", -6.9, -signe * (23.5), -74.77 + heigthConnector / 2); + t_ConnectorPSU_4->RegisterYourself(); + auto* p_ConnectorPSU_4 = new TGeoCombiTrans(*t_ConnectorPSU_4, *r_ConnectorRC3_1); + p_ConnectorPSU_4->RegisterYourself(); + + vRO1->SetLineColor(kGray + 2); + vRO2->SetLineColor(kGray + 2); + vRO3->SetLineColor(kGray + 2); + vRO4->SetLineColor(kGray + 2); + vRO5->SetLineColor(kGray + 2); + vRO6->SetLineColor(kGray + 2); + vRO7->SetLineColor(kGray + 2); + vRO8->SetLineColor(kGray + 2); + vRO9->SetLineColor(kGray + 2); + vRO_D3_1->SetLineColor(kGray + 2); + vRO_D3_2->SetLineColor(kGray + 2); + vRO_D3_3->SetLineColor(kGray + 2); + vRO_D3_4->SetLineColor(kGray + 2); + vRO_D4_1->SetLineColor(kGray + 2); + vRO_D4_2->SetLineColor(kGray + 2); + vRO_D4_3->SetLineColor(kGray + 2); + vRO_D4_4->SetLineColor(kGray + 2); + vRO_D4_5->SetLineColor(kGray + 2); + vRO_D4_6->SetLineColor(kGray + 2); + vRO_PSU_1->SetLineColor(kGray + 2); + vRO_PSU_2->SetLineColor(kGray + 2); + vRO_PSU_3->SetLineColor(kGray + 2); + vRO_PSU_4->SetLineColor(kGray + 2); + + HalfConeVolume->AddNode(vRO1, 1, t_RO1); + HalfConeVolume->AddNode(vRO2, 1, t_RO2); + HalfConeVolume->AddNode(vRO3, 1, t_RO3); + HalfConeVolume->AddNode(vRO4, 1, p_RO4); + HalfConeVolume->AddNode(vRO5, 1, p_RO5_1); + HalfConeVolume->AddNode(vRO5, 1, p_RO5_2); + HalfConeVolume->AddNode(vRO6, 1, p_RO6); + HalfConeVolume->AddNode(vRO7, 1, p_RO7); + HalfConeVolume->AddNode(vRO8, 1, p_RO8_1); + HalfConeVolume->AddNode(vRO8, 1, p_RO8_2); + HalfConeVolume->AddNode(vRO9, 1, p_RO9_1); + HalfConeVolume->AddNode(vRO9, 1, p_RO9_2); + HalfConeVolume->AddNode(vRO_D3_1, 1, p_ROD3_1); + HalfConeVolume->AddNode(vRO_D3_2, 1, p_ROD3_2); + HalfConeVolume->AddNode(vRO_D3_3, 1, p_ROD3_3); + HalfConeVolume->AddNode(vRO_D3_4, 1, p_ROD3_4); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC3_1); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC3_2); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC3_3); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC3_4); + + HalfConeVolume->AddNode(vRO_D4_1, 1, p_ROD4_1); + HalfConeVolume->AddNode(vRO_D4_2, 1, p_ROD4_2); + HalfConeVolume->AddNode(vRO_D4_3, 1, p_ROD4_3); + HalfConeVolume->AddNode(vRO_D4_4, 1, p_ROD4_4); + HalfConeVolume->AddNode(vRO_D4_5, 1, p_ROD4_5); + HalfConeVolume->AddNode(vRO_D4_6, 1, p_ROD4_6); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_1); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_2); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_3); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_4); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_5); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorRC4_6); + + HalfConeVolume->AddNode(vRO_PSU_1, 1, p_RO_PSU_1); + HalfConeVolume->AddNode(vRO_PSU_2, 1, p_RO_PSU_2); + HalfConeVolume->AddNode(vRO_PSU_3, 1, p_RO_PSU_3); + HalfConeVolume->AddNode(vRO_PSU_4, 1, p_RO_PSU_4); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorPSU_1); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorPSU_2); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorPSU_3); + HalfConeVolume->AddNode(vConnectorRC, 1, p_ConnectorPSU_4); +} + +void HalfCone::makePowerCables(TGeoVolumeAssembly* HalfConeVolume, Int_t half, Int_t signe) +{ + auto* mCu = gGeoManager->GetMedium("MFT_Cu$"); + + // ========= Cables for the first 3 disks =========== + // ==================== Bottom side =================== + Double_t xPC0 = 8.0; + Double_t yPC0 = 0.0313; + Double_t zPC0 = 2.0; // length + Int_t side; + if (signe == -1) { + side = 1; // left + } + if (signe == 1) { + side = 2; // right + } + + TGeoVolume* vPCb0 = gGeoManager->MakeBox(Form("vPCb0_S%d", side), mCu, xPC0 / 2, yPC0 / 2, zPC0 / 2); + auto* r_PC0 = new TGeoRotation("rotation_PC0", 0., 0., 0.); + r_PC0->RegisterYourself(); + Double_t XPC0 = signe * 18.5; + Double_t YPC0 = -4. + yPC0 / 2; + Double_t ZPC0 = -72.5; + auto* p_PC0 = new TGeoCombiTrans(XPC0, YPC0, ZPC0, r_PC0); + + //===================== first cable =============================== + Double_t rmaxPC1 = 0.163; + Double_t zPC1 = 5.5; + TGeoVolume* vPCb1_1 = gGeoManager->MakeTube(Form("vPCb1_1_S%d", side), mCu, 0., rmaxPC1, zPC1 / 2); + Double_t XPC1 = XPC0 + signe * (2 * rmaxPC1 - 0.3); + Double_t YPC1 = YPC0; + Double_t ZPC1 = ZPC0 + (zPC0 + zPC1) / 2; + auto* p_PC1_1 = new TGeoCombiTrans(XPC1, YPC1, ZPC1, r_PC0); + p_PC1_1->RegisterYourself(); + //=========== + Double_t rPC2 = 0.95; + TGeoVolume* vPCb2_1 = gGeoManager->MakeTorus(Form("vPCb2_1_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + auto* r_PC2 = new TGeoRotation("rotation_PC2", 90., -90., -90.); + r_PC2->RegisterYourself(); + Double_t XPC2 = XPC1; + Double_t YPC2 = YPC1 - rPC2; + Double_t ZPC2 = ZPC1 + zPC1 / 2; + auto* p_PC2_1 = new TGeoCombiTrans(XPC2, YPC2, ZPC2, r_PC2); + p_PC2_1->RegisterYourself(); + //=========== + Double_t zPC3 = 2.6; + TGeoVolume* vPCb3_1 = gGeoManager->MakeTube(Form("vPCb3_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + auto* r_PC3 = new TGeoRotation("rotation_PC3", 0., 90., 0.); + r_PC3->RegisterYourself(); + Double_t XPC3 = XPC2; + Double_t YPC3 = YPC2 - zPC3 / 2; + Double_t ZPC3 = ZPC2 + rPC2; + auto* p_PC3_1 = new TGeoCombiTrans(XPC3, YPC3, ZPC3, r_PC3); + p_PC3_1->RegisterYourself(); + //=========== + Double_t rPC4 = 0.95; + TGeoVolume* vPCb4_1 = gGeoManager->MakeTorus(Form("vPCb4_1_H%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + auto* r_PC4 = new TGeoRotation("rotation_PC4", 90., -90. - signe * 45., 90.); + r_PC4->RegisterYourself(); + Double_t XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + Double_t YPC4 = YPC3 - zPC3 / 2; + Double_t ZPC4 = ZPC3 + rPC4 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC4_1 = new TGeoCombiTrans(XPC4, YPC4, ZPC4, r_PC4); + p_PC4_1->RegisterYourself(); + //=========== + Double_t zPC5 = 8.1; + TGeoVolume* vPCb5_1 = gGeoManager->MakeTube(Form("vPCb5_S%d", side), mCu, 0., rmaxPC1, zPC5 / 2); + auto* r_PC5 = new TGeoRotation("rotation_PC5", 90., -signe * 45., 0); + r_PC5->RegisterYourself(); + Double_t XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + Double_t YPC5 = YPC4 - rPC4; + Double_t ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC5_1 = new TGeoCombiTrans(XPC5, YPC5, ZPC5, r_PC5); + p_PC5_1->RegisterYourself(); + //=========== + Double_t rPC6 = 0.95; + TGeoVolume* vPCb6_1 = gGeoManager->MakeTorus(Form("vPCb6_1_H%d", side), mCu, rPC2, 0.0, rmaxPC1, 45., 45.); + auto* r_PC6 = new TGeoRotation("rotation_PC6", 0., -signe * 90., signe * 90.); + r_PC6->RegisterYourself(); + Double_t XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45 * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45. * TMath::Pi() / 180.)); + Double_t YPC6 = YPC5; + Double_t ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45. * TMath::Pi() / 180.); + auto* p_PC6_1 = new TGeoCombiTrans(XPC6, YPC6, ZPC6, r_PC6); + p_PC6_1->RegisterYourself(); + //=========== + Double_t zPC7 = 13.0; + TGeoVolume* vPCb7_1 = gGeoManager->MakeTube(Form("vPCb7_1_H%d", side), mCu, 0., rmaxPC1, zPC7 / 2); + auto* r_PC7 = new TGeoRotation("rotation_PC7", 0., 0., 0.); + r_PC7->RegisterYourself(); + Double_t XPC7 = XPC6 - signe * rPC6; + Double_t YPC7 = YPC6; + Double_t ZPC7 = ZPC6 + zPC7 / 2; + auto* p_PC7_1 = new TGeoCombiTrans(XPC7, YPC7, ZPC7, r_PC7); + p_PC7_1->RegisterYourself(); + + //===================== second cable ============================== + zPC1 = 5.5; + TGeoVolume* vPCb1_2 = gGeoManager->MakeTube(Form("vPCb1_2_S%d", side), mCu, 0., rmaxPC1, zPC1 / 2); + XPC1 = XPC0 + signe * (8 * rmaxPC1 - 0.3); + auto* p_PC1_2 = new TGeoCombiTrans(XPC1, YPC1, ZPC1, r_PC0); + p_PC1_2->RegisterYourself(); + //=========== + TGeoVolume* vPCb2_2 = gGeoManager->MakeTorus(Form("vPCb2_2_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 0., 90.); + XPC2 = XPC1; + auto* p_PC2_2 = new TGeoCombiTrans(XPC2, YPC2, ZPC2, r_PC2); + p_PC2_2->RegisterYourself(); + //=========== + TGeoVolume* vPCb3_2 = gGeoManager->MakeTube(Form("vPCb3_2_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + XPC3 = XPC2; + YPC3 = YPC2 - zPC3 / 2; + ZPC3 = ZPC2 + rPC2; + auto* p_PC3_2 = new TGeoCombiTrans(XPC3, YPC3, ZPC3, r_PC3); + p_PC3_2->RegisterYourself(); + //=========== + TGeoVolume* vPCb4_2 = gGeoManager->MakeTorus(Form("vPCb4_2_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC4 = YPC3 - zPC3 / 2; + ZPC4 = ZPC3 + rPC4 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC4_2 = new TGeoCombiTrans(XPC4, YPC4, ZPC4, r_PC4); + p_PC4_2->RegisterYourself(); + //=========== + zPC5 = 8.1; + TGeoVolume* vPCb5_2 = gGeoManager->MakeTube(Form("vPCb5_2_S%d", side), mCu, 0., rmaxPC1, zPC5 / 2); + XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC5 = YPC4 - rPC4; + ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC5_2 = new TGeoCombiTrans(XPC5, YPC5, ZPC5, r_PC5); + p_PC5_2->RegisterYourself(); + //=========== + TGeoVolume* vPCb6_2 = gGeoManager->MakeTorus(Form("vPCb6_2_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 45., 45.); + XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45. * TMath::Pi() / 180.)); + YPC6 = YPC5; + ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45. * TMath::Pi() / 180.); + auto* p_PC6_2 = new TGeoCombiTrans(XPC6, YPC6, ZPC6, r_PC6); + p_PC6_2->RegisterYourself(); + //=========== + zPC7 = 9.8; + TGeoVolume* vPCb7_2 = gGeoManager->MakeTube(Form("vPCb7_2_S%d", side), mCu, 0., rmaxPC1, zPC7 / 2); + XPC7 = XPC6 - signe * rPC6; + YPC7 = YPC6; + ZPC7 = ZPC6 + zPC7 / 2; + auto* p_PC7_2 = new TGeoCombiTrans(XPC7, YPC7, ZPC7, r_PC7); + p_PC7_2->RegisterYourself(); + + //===================== third cable ============================== + zPC1 = 5.5; + TGeoVolume* vPCb1_3 = gGeoManager->MakeTube(Form("vPCb1_3_S%d", side), mCu, 0., rmaxPC1, zPC1 / 2); + XPC1 = XPC0 + signe * (14 * rmaxPC1 - 0.3); + auto* p_PC1_3 = new TGeoCombiTrans(XPC1, YPC1, ZPC1, r_PC0); + p_PC1_3->RegisterYourself(); + //=========== + TGeoVolume* vPCb2_3 = gGeoManager->MakeTorus(Form("vPCb2_3_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + XPC2 = XPC1; + auto* p_PC2_3 = new TGeoCombiTrans(XPC2, YPC2, ZPC2, r_PC2); + p_PC2_3->RegisterYourself(); + //=========== + zPC3 = 2.6; + TGeoVolume* vPCb3_3 = gGeoManager->MakeTube(Form("vPCb3_3_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + XPC3 = XPC2; + YPC3 = YPC2 - zPC3 / 2; + ZPC3 = ZPC2 + rPC2; + auto* p_PC3_3 = new TGeoCombiTrans(XPC3, YPC3, ZPC3, r_PC3); + p_PC3_3->RegisterYourself(); + //=========== + TGeoVolume* vPCb4_3 = gGeoManager->MakeTorus(Form("vPCb4_3_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC4 = YPC3 - zPC3 / 2; + ZPC4 = ZPC3 + rPC4 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC4_3 = new TGeoCombiTrans(XPC4, YPC4, ZPC4, r_PC4); + p_PC4_3->RegisterYourself(); + //=========== + zPC5 = 8.1 + 0.3; + TGeoVolume* vPCb5_3 = gGeoManager->MakeTube(Form("vPCb5_3_S%d", side), mCu, 0., rmaxPC1, zPC5 / 2); + XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC5 = YPC4 - rPC4; + ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.); + auto* p_PC5_3 = new TGeoCombiTrans(XPC5, YPC5, ZPC5, r_PC5); + p_PC5_3->RegisterYourself(); + //=========== + TGeoVolume* vPCb6_3 = gGeoManager->MakeTorus(Form("vPCb6_3_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 45., 45.); + XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45. * TMath::Pi() / 180.)); + YPC6 = YPC5; + ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45. * TMath::Pi() / 180.); + auto* p_PC6_3 = new TGeoCombiTrans(XPC6, YPC6, ZPC6, r_PC6); + p_PC6_3->RegisterYourself(); + //=========== + zPC7 = 5.8; + TGeoVolume* vPCb7_3 = gGeoManager->MakeTube(Form("vPCb7_3_S%d", side), mCu, 0., rmaxPC1, zPC7 / 2); + XPC7 = XPC6 - signe * rPC6; + YPC7 = YPC6; + ZPC7 = ZPC6 + zPC7 / 2; + auto* p_PC7_3 = new TGeoCombiTrans(XPC7, YPC7, ZPC7, r_PC7); + p_PC7_3->RegisterYourself(); + //========================================================== + + vPCb0->SetLineColor(kBlue); + vPCb1_1->SetLineColor(kBlue); + vPCb1_2->SetLineColor(kBlue); + vPCb1_3->SetLineColor(kBlue); + vPCb2_1->SetLineColor(kBlue); + vPCb2_2->SetLineColor(kBlue); + vPCb2_3->SetLineColor(kBlue); + vPCb3_1->SetLineColor(kBlue); + vPCb3_2->SetLineColor(kBlue); + vPCb3_3->SetLineColor(kBlue); + vPCb4_1->SetLineColor(kBlue); + vPCb4_2->SetLineColor(kBlue); + vPCb4_3->SetLineColor(kBlue); + vPCb5_1->SetLineColor(kBlue); + vPCb5_2->SetLineColor(kBlue); + vPCb5_3->SetLineColor(kBlue); + vPCb6_1->SetLineColor(kBlue); + vPCb6_2->SetLineColor(kBlue); + vPCb6_3->SetLineColor(kBlue); + vPCb7_1->SetLineColor(kBlue); + vPCb7_2->SetLineColor(kBlue); + vPCb7_3->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPCb0, 1, p_PC0); + HalfConeVolume->AddNode(vPCb1_1, 1, p_PC1_1); + HalfConeVolume->AddNode(vPCb1_2, 1, p_PC1_2); + HalfConeVolume->AddNode(vPCb1_3, 1, p_PC1_3); + HalfConeVolume->AddNode(vPCb2_1, 1, p_PC2_1); + HalfConeVolume->AddNode(vPCb2_2, 1, p_PC2_2); + HalfConeVolume->AddNode(vPCb2_3, 1, p_PC2_3); + HalfConeVolume->AddNode(vPCb3_1, 1, p_PC3_1); + HalfConeVolume->AddNode(vPCb3_2, 1, p_PC3_2); + HalfConeVolume->AddNode(vPCb3_3, 1, p_PC3_3); + HalfConeVolume->AddNode(vPCb4_1, 1, p_PC4_1); + HalfConeVolume->AddNode(vPCb4_2, 1, p_PC4_2); + HalfConeVolume->AddNode(vPCb4_3, 1, p_PC4_3); + HalfConeVolume->AddNode(vPCb5_1, 1, p_PC5_1); + HalfConeVolume->AddNode(vPCb5_2, 1, p_PC5_2); + HalfConeVolume->AddNode(vPCb5_3, 1, p_PC5_3); + HalfConeVolume->AddNode(vPCb6_1, 1, p_PC6_1); + HalfConeVolume->AddNode(vPCb6_2, 1, p_PC6_2); + HalfConeVolume->AddNode(vPCb6_3, 1, p_PC6_3); + HalfConeVolume->AddNode(vPCb7_1, 1, p_PC7_1); + HalfConeVolume->AddNode(vPCb7_2, 1, p_PC7_2); + HalfConeVolume->AddNode(vPCb7_3, 1, p_PC7_3); + + // ==================== Top side =================== + TGeoVolume* vPCt0 = gGeoManager->MakeBox(Form("vPCt0_S%d", side), mCu, xPC0 / 2, yPC0 / 2, zPC0 / 2); + p_PC0 = new TGeoCombiTrans(XPC0, -YPC0, ZPC0, r_PC0); + + //===================== first cable =============================== + zPC1 = 5.5; + TGeoVolume* vPCt1_1 = gGeoManager->MakeTube(Form("vPCt1_1_S%d", side), mCu, 0.0, rmaxPC1, zPC1 / 2); + XPC1 = XPC0 + signe * (2 * rmaxPC1 - 0.3); + p_PC1_1 = new TGeoCombiTrans(XPC1, -YPC1, ZPC1, r_PC0); + p_PC1_1->RegisterYourself(); + //========== + TGeoVolume* vPCt2_1 = gGeoManager->MakeTorus(Form("vPCt2_1_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + r_PC2 = new TGeoRotation("rotation_PC2", 90., 90., 90.); + r_PC2->RegisterYourself(); + XPC2 = XPC1; + YPC2 = YPC1 - rPC2; + ZPC2 = ZPC1 + zPC1 / 2; + p_PC2_1 = new TGeoCombiTrans(XPC2, -YPC2, ZPC2, r_PC2); + p_PC2_1->RegisterYourself(); + //=========== + zPC3 = 2.6; + TGeoVolume* vPCt3_1 = gGeoManager->MakeTube(Form("vPCt3_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + r_PC3->RegisterYourself(); + XPC3 = XPC2; + YPC3 = YPC2 - zPC3 / 2; + ZPC3 = ZPC2 + rPC2; + p_PC3_1 = new TGeoCombiTrans(XPC3, -YPC3, ZPC3, r_PC3); + p_PC3_1->RegisterYourself(); + //=========== + rPC4 = 0.95; + TGeoVolume* vPCt4_1 = gGeoManager->MakeTorus(Form("vPCt4_1_H%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + r_PC4 = new TGeoRotation("rotation_PC4", 90., 90. - signe * 45., 180. + 90.); + r_PC4->RegisterYourself(); + XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC4 = YPC3 - zPC3 / 2; + ZPC4 = ZPC3 + rPC4 * TMath::Cos(45. * TMath::Pi() / 180.); + p_PC4_1 = new TGeoCombiTrans(XPC4, -YPC4, ZPC4, r_PC4); + p_PC4_1->RegisterYourself(); + //=========== + zPC5 = 8.1; + TGeoVolume* vPCt5_1 = gGeoManager->MakeTube(Form("vPCt5_S%d", side), mCu, 0.0, rmaxPC1, zPC5 / 2); + r_PC5 = new TGeoRotation("rotation_PC5", 90., 180.0 - signe * 45., 180); + r_PC5->RegisterYourself(); + XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC5 = YPC4 - rPC4; + ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.); + p_PC5_1 = new TGeoCombiTrans(XPC5, -YPC5, ZPC5, r_PC5); + p_PC5_1->RegisterYourself(); + //=========== + rPC6 = 0.95; + TGeoVolume* vPCt6_1 = gGeoManager->MakeTorus(Form("vPCt6_1_H%d", side), mCu, rPC2, 0.0, rmaxPC1, 45., 45.); + XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45.0 * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45 * TMath::Pi() / 180.)); + YPC6 = YPC5; + ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45 * TMath::Pi() / 180.); + p_PC6_1 = new TGeoCombiTrans(XPC6, -YPC6, ZPC6, r_PC6); + p_PC6_1->RegisterYourself(); + //=========== + zPC7 = 13.0; + TGeoVolume* vPCt7_1 = gGeoManager->MakeTube(Form("vPCt7_1_H%d", side), mCu, 0., rmaxPC1, zPC7 / 2); + XPC7 = XPC6 - signe * rPC6; + YPC7 = YPC6; + ZPC7 = ZPC6 + zPC7 / 2; + p_PC7_1 = new TGeoCombiTrans(XPC7, -YPC7, ZPC7, r_PC7); + p_PC7_1->RegisterYourself(); + + //===================== second cable ============================== + zPC1 = 5.5; + TGeoVolume* vPCt1_2 = gGeoManager->MakeTube(Form("vPCt1_2_S%d", side), mCu, 0., rmaxPC1, zPC1 / 2); + XPC1 = XPC0 + signe * (8 * rmaxPC1 - 0.3); + p_PC1_2 = new TGeoCombiTrans(XPC1, -YPC1, ZPC1, r_PC0); + p_PC1_2->RegisterYourself(); + //=========== + TGeoVolume* vPCt2_2 = gGeoManager->MakeTorus(Form("TorusPCt2_2_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 0., 90.); + XPC2 = XPC1; + p_PC2_2 = new TGeoCombiTrans(XPC2, -YPC2, ZPC2, r_PC2); + p_PC2_2->RegisterYourself(); + //=========== + TGeoVolume* vPCt3_2 = gGeoManager->MakeTube(Form("vPCt3_2_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + XPC3 = XPC2; + p_PC3_2 = new TGeoCombiTrans(XPC3, -YPC3, ZPC3, r_PC3); + p_PC3_2->RegisterYourself(); + //=========== + TGeoVolume* vPCt4_2 = gGeoManager->MakeTorus(Form("TorusPCt4_2_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 0., 90.); + XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC4 = YPC3 - zPC3 / 2; + ZPC4 = ZPC3 + rPC4 * TMath::Cos(45 * TMath::Pi() / 180.); + p_PC4_2 = new TGeoCombiTrans(XPC4, -YPC4, ZPC4, r_PC4); + p_PC4_2->RegisterYourself(); + //=========== + zPC5 = 8.1; + TGeoVolume* vPCt5_2 = gGeoManager->MakeTube(Form("vPCt5_2_S%d", side), mCu, 0., rmaxPC1, zPC5 / 2); + XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45.0 * TMath::Pi() / 180.); + YPC5 = YPC4 - rPC4; + ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45.0 * TMath::Pi() / 180.); + p_PC5_2 = new TGeoCombiTrans(XPC5, -YPC5, ZPC5, r_PC5); + p_PC5_2->RegisterYourself(); + //=========== + TGeoVolume* vPCt6_2 = gGeoManager->MakeTorus(Form("TorusPCt6_2_S%d", side), mCu, rPC2, 0.0, rmaxPC1, 45., 45.); + XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45.0 * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45. * TMath::Pi() / 180.)); + YPC6 = YPC5; + ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45. * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45. * TMath::Pi() / 180.); + p_PC6_2 = new TGeoCombiTrans(XPC6, -YPC6, ZPC6, r_PC6); + p_PC6_2->RegisterYourself(); + //=========== + zPC7 = 9.8; + TGeoVolume* vPCt7_2 = gGeoManager->MakeTube(Form("vPCt7_2_S%d", side), mCu, 0.0, rmaxPC1, zPC7 / 2); + XPC7 = XPC6 - signe * rPC6; + YPC7 = YPC6; + ZPC7 = ZPC6 + zPC7 / 2; + p_PC7_2 = new TGeoCombiTrans(XPC7, -YPC7, ZPC7, r_PC7); + p_PC7_2->RegisterYourself(); + + //===================== third cable ============================== + zPC1 = 5.5; + TGeoVolume* vPCt1_3 = gGeoManager->MakeTube(Form("vPCt1_3_S%d", side), mCu, 0., rmaxPC1, zPC1 / 2); + XPC1 = XPC0 + signe * (14 * rmaxPC1 - 0.3); + p_PC1_3 = new TGeoCombiTrans(XPC1, -YPC1, ZPC1, r_PC0); + p_PC1_3->RegisterYourself(); + //=========== + zPC3 = 2.6; + TGeoVolume* vPCt2_3 = gGeoManager->MakeTorus(Form("TorusPCt2_3_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + XPC2 = XPC1; + p_PC2_3 = new TGeoCombiTrans(XPC2, -YPC2, ZPC2, r_PC2); + p_PC2_3->RegisterYourself(); + //=========== + TGeoVolume* vPCt3_3 = gGeoManager->MakeTube(Form("vPCt3_3_S%d", side), mCu, 0., rmaxPC1, zPC3 / 2); + XPC3 = XPC2; + YPC3 = YPC2 - zPC3 / 2; + ZPC3 = ZPC2 + rPC2; + p_PC3_3 = new TGeoCombiTrans(XPC3, -YPC3, ZPC3, r_PC3); + p_PC3_3->RegisterYourself(); + //=========== + TGeoVolume* vPCt4_3 = gGeoManager->MakeTorus(Form("TorusPCt4_3_S%d", side), mCu, rPC2, 0., rmaxPC1, 0., 90.); + XPC4 = XPC3 - signe * rPC4 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC4 = YPC3 - zPC3 / 2; + ZPC4 = ZPC3 + rPC4 * TMath::Cos(45.0 * TMath::Pi() / 180.); + p_PC4_3 = new TGeoCombiTrans(XPC4, -YPC4, ZPC4, r_PC4); + p_PC4_3->RegisterYourself(); + //=========== + zPC5 = 8.1 + 0.3; + TGeoVolume* vPCt5_3 = gGeoManager->MakeTube(Form("vPCt5_3_S%d", side), mCu, 0., rmaxPC1, zPC5 / 2); + XPC5 = XPC4 - signe * zPC5 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + YPC5 = YPC4 - rPC4; + ZPC5 = ZPC4 + zPC5 / 2 * TMath::Cos(45 * TMath::Pi() / 180.); + p_PC5_3 = new TGeoCombiTrans(XPC5, -YPC5, ZPC5, r_PC5); + p_PC5_3->RegisterYourself(); + //=========== + TGeoVolume* vPCt6_3 = gGeoManager->MakeTorus(Form("TorusPCt6_3_S%d", side), mCu, rPC2, 0., rmaxPC1, 45., 45.); + XPC6 = XPC5 - signe * (zPC5 / 2 * TMath::Sin(45.0 * TMath::Pi() / 180.) - rPC6 * TMath::Cos(45. * TMath::Pi() / 180.)); + YPC6 = YPC5; + ZPC6 = ZPC5 + zPC5 / 2 * TMath::Cos(45.0 * TMath::Pi() / 180.) + rPC6 * TMath::Sin(45. * TMath::Pi() / 180.); + p_PC6_3 = new TGeoCombiTrans(XPC6, -YPC6, ZPC6, r_PC6); + p_PC6_3->RegisterYourself(); + //=========== + zPC7 = 5.8; + TGeoVolume* vPCt7_3 = gGeoManager->MakeTube(Form("vPCt7_3_S%d", side), mCu, 0., rmaxPC1, zPC7 / 2); + XPC7 = XPC6 - signe * rPC6; + YPC7 = YPC6; + ZPC7 = ZPC6 + zPC7 / 2; + p_PC7_3 = new TGeoCombiTrans(XPC7, -YPC7, ZPC7, r_PC7); + p_PC7_3->RegisterYourself(); + //========================================================== + + vPCt0->SetLineColor(kBlue); + vPCt1_1->SetLineColor(kBlue); + vPCt2_1->SetLineColor(kBlue); + vPCt3_1->SetLineColor(kBlue); + vPCt4_1->SetLineColor(kBlue); + vPCt5_1->SetLineColor(kBlue); + vPCt6_1->SetLineColor(kBlue); + vPCt7_1->SetLineColor(kBlue); + vPCt1_2->SetLineColor(kBlue); + vPCt2_2->SetLineColor(kBlue); + vPCt3_2->SetLineColor(kBlue); + vPCt4_2->SetLineColor(kBlue); + vPCt5_2->SetLineColor(kBlue); + vPCt6_2->SetLineColor(kBlue); + vPCt7_2->SetLineColor(kBlue); + vPCt1_3->SetLineColor(kBlue); + vPCt2_3->SetLineColor(kBlue); + vPCt3_3->SetLineColor(kBlue); + vPCt4_3->SetLineColor(kBlue); + vPCt5_3->SetLineColor(kBlue); + vPCt6_3->SetLineColor(kBlue); + vPCt7_3->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPCt0, 1, p_PC0); + HalfConeVolume->AddNode(vPCt1_1, 1, p_PC1_1); + HalfConeVolume->AddNode(vPCt2_1, 1, p_PC2_1); + HalfConeVolume->AddNode(vPCt3_1, 1, p_PC3_1); + HalfConeVolume->AddNode(vPCt4_1, 1, p_PC4_1); + HalfConeVolume->AddNode(vPCt5_1, 1, p_PC5_1); + HalfConeVolume->AddNode(vPCt6_1, 1, p_PC6_1); + HalfConeVolume->AddNode(vPCt7_1, 1, p_PC7_1); + HalfConeVolume->AddNode(vPCt1_2, 1, p_PC1_2); + HalfConeVolume->AddNode(vPCt2_2, 1, p_PC2_2); + HalfConeVolume->AddNode(vPCt3_2, 1, p_PC3_2); + HalfConeVolume->AddNode(vPCt4_2, 1, p_PC4_2); + HalfConeVolume->AddNode(vPCt5_2, 1, p_PC5_2); + HalfConeVolume->AddNode(vPCt6_2, 1, p_PC6_2); + HalfConeVolume->AddNode(vPCt7_2, 1, p_PC7_2); + HalfConeVolume->AddNode(vPCt1_3, 1, p_PC1_3); + HalfConeVolume->AddNode(vPCt2_3, 1, p_PC2_3); + HalfConeVolume->AddNode(vPCt3_3, 1, p_PC3_3); + HalfConeVolume->AddNode(vPCt4_3, 1, p_PC4_3); + HalfConeVolume->AddNode(vPCt5_3, 1, p_PC5_3); + HalfConeVolume->AddNode(vPCt6_3, 1, p_PC6_3); + HalfConeVolume->AddNode(vPCt7_3, 1, p_PC7_3); + + // ================================================== + // ========= Cables for the 2 latest disks ========== + // ================================================== + // PSU --> DISK3 + // one diagonal + Double_t xPC_0 = 1.0; // width + Double_t yPC_0 = 0.0836; // thickness + Double_t zPC_0 = 5.0; // length + TGeoVolume* vPC_0 = gGeoManager->MakeBox(Form("vPC_0_S%d", side), mCu, xPC_0 / 2, yPC_0 / 2, zPC_0 / 2); + auto* r_PC_0 = new TGeoRotation("rotation_PC_0", -45., 0., 0.); + r_PC_0->RegisterYourself(); + Double_t XPC_0 = signe * 19.7; + Double_t YPC_0 = signe * 20.0; + Double_t ZPC_0 = -71.0; + auto* p_PC_0 = new TGeoCombiTrans(XPC_0, YPC_0, ZPC_0, r_PC_0); + //=========== + Double_t xPC_1 = 4.8; // length + Double_t yPC_1 = yPC_0; + Double_t zPC_1 = xPC_0; + TGeoVolume* vPC_1 = gGeoManager->MakeBox(Form("vPC_1_S%d", side), mCu, xPC_1 / 2, yPC_1 / 2, zPC_1 / 2); + auto* r_PC_1 = new TGeoRotation("rotation_PC_1", 45., 90., 0.); + r_PC_1->RegisterYourself(); + Double_t XPC_1 = XPC_0 - signe * xPC_1 / 2 * TMath::Cos(45. * TMath::Pi() / 180.); + Double_t YPC_1 = YPC_0 - signe * xPC_1 / 2 * TMath::Sin(45. * TMath::Pi() / 180.); + Double_t ZPC_1 = ZPC_0 + (zPC_0 + yPC_1) / 2; + auto* p_PC_1 = new TGeoCombiTrans(XPC_1, YPC_1, ZPC_1, r_PC_1); + //=========== + vPC_0->SetLineColor(kBlue); + vPC_1->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_0, 1, p_PC_0); + HalfConeVolume->AddNode(vPC_1, 1, p_PC_1); + + // other diagonal + TGeoVolume* vPC_P0 = gGeoManager->MakeBox(Form("vPC_P0_S%d", side), mCu, xPC_0 / 2, yPC_0 / 2, zPC_0 / 2); + auto* r_PC_P0 = new TGeoRotation("rotation_PC_P0", 45., 0., 0.); + r_PC_P0->RegisterYourself(); + Double_t XPC_P0 = -signe * 19.7; + Double_t YPC_P0 = signe * 20.0; + Double_t ZPC_P0 = -71.0; + auto* p_PC_P0 = new TGeoCombiTrans(XPC_P0, YPC_P0, ZPC_P0, r_PC_P0); + //=========== + Double_t xPC_P1 = xPC_0; + Double_t yPC_P1 = yPC_0; + Double_t zPC_P1 = 4.8; + TGeoVolume* vPC_P1 = gGeoManager->MakeBox(Form("vPC_P1_S%d", side), mCu, xPC_P1 / 2, yPC_P1 / 2, zPC_P1 / 2); + auto* r_PC_P1 = new TGeoRotation("rotation_PC_P1", 45., 90., 0.); + r_PC_P1->RegisterYourself(); + Double_t XPC_P1 = XPC_P0 + signe * zPC_P1 / 2 * TMath::Cos(45 * TMath::Pi() / 180); + Double_t YPC_P1 = YPC_P0 - signe * zPC_P1 / 2 * TMath::Sin(45 * TMath::Pi() / 180); + Double_t ZPC_P1 = ZPC_P0 + (zPC_0 + yPC_P1) / 2; + auto* p_PC_P1 = new TGeoCombiTrans(XPC_P1, YPC_P1, ZPC_P1, r_PC_P1); + //=========== + vPC_P0->SetLineColor(kBlue); + vPC_P1->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_P0, 1, p_PC_P0); + HalfConeVolume->AddNode(vPC_P1, 1, p_PC_P1); + + // PSU --> DISK4 + // one diagonal + TGeoVolume* vPC_2 = gGeoManager->MakeBox(Form("vPC_2_S%d", side), mCu, xPC_0 / 2, yPC_0 / 2, zPC_0 / 2); + auto* r_PC_2 = new TGeoRotation("rotation_PC_2", -39., 0., 0.); + r_PC_2->RegisterYourself(); + Double_t XPC_2 = signe * 17.2; + Double_t YPC_2 = signe * 22.0; + Double_t ZPC_2 = -74.0; + auto* p_PC_2 = new TGeoCombiTrans(XPC_2, YPC_2, ZPC_2, r_PC_2); + //=========== + Double_t xPC_3 = 4.8; // length + Double_t yPC_3 = yPC_0; + Double_t zPC_3 = xPC_0; + TGeoVolume* vPC_3 = gGeoManager->MakeBox(Form("vPC_3_S%d", side), mCu, xPC_3 / 2, yPC_3 / 2, zPC_3 / 2); + auto* r_PC_3 = new TGeoRotation("rotation_PC_3", 90. - 39., 90., 0.); + r_PC_3->RegisterYourself(); + Double_t XPC_3 = XPC_2 - signe * xPC_3 / 2 * TMath::Cos((90. - 39.) * TMath::Pi() / 180.); + Double_t YPC_3 = YPC_2 - signe * xPC_3 / 2 * TMath::Sin((90. - 39.) * TMath::Pi() / 180.); + Double_t ZPC_3 = ZPC_2 - (zPC_0 + yPC_3) / 2; + auto* p_PC_3 = new TGeoCombiTrans(XPC_3, YPC_3, ZPC_3, r_PC_3); + //=========== + vPC_2->SetLineColor(kBlue); + vPC_3->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_2, 1, p_PC_2); + HalfConeVolume->AddNode(vPC_3, 1, p_PC_3); + + // other diagonal + TGeoVolume* vPC_P2 = gGeoManager->MakeBox(Form("vPC_P2_S%d", side), mCu, xPC_0 / 2, yPC_0 / 2, zPC_0 / 2); + auto* r_PC_P2 = new TGeoRotation("rotation_PC_P2", 39., 0., 0.); + r_PC_P2->RegisterYourself(); + Double_t XPC_P2 = -signe * 17.2; + Double_t YPC_P2 = signe * 22.0; + Double_t ZPC_P2 = -74.0; + auto* p_PC_P2 = new TGeoCombiTrans(XPC_P2, YPC_P2, ZPC_P2, r_PC_P2); + //=========== + Double_t xPC_P3 = xPC_0; + Double_t yPC_P3 = yPC_0; + Double_t zPC_P3 = 4.8; + TGeoVolume* vPC_P3 = gGeoManager->MakeBox(Form("vPC_P3_S%d", side), mCu, xPC_P1 / 2, yPC_P1 / 2, zPC_P1 / 2); + auto* r_PC_P3 = new TGeoRotation("rotation_PC_P3", 39., 90., 0.); + r_PC_P3->RegisterYourself(); + Double_t XPC_P3 = XPC_P2 + signe * zPC_P3 / 2 * TMath::Cos((90. - 39.) * TMath::Pi() / 180.); + Double_t YPC_P3 = YPC_P2 - signe * zPC_P3 / 2 * TMath::Sin((90. - 39.) * TMath::Pi() / 180.); + Double_t ZPC_P3 = ZPC_P2 - (zPC_0 + yPC_P3) / 2; + auto* p_PC_P3 = new TGeoCombiTrans(XPC_P3, YPC_P3, ZPC_P3, r_PC_P3); + //=========== + vPC_P2->SetLineColor(kBlue); + vPC_P3->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_P2, 1, p_PC_P2); + HalfConeVolume->AddNode(vPC_P3, 1, p_PC_P3); + + // Cables for PSU from the patch panel + // b :bottom + Double_t xPC_PSUb0 = 2.5; // width + Double_t yPC_PSUb0 = 0.0418; // thickness + Double_t zPC_PSUb0 = 0.8; // length + // on the PSU connectors + TGeoVolume* vPC_PSUb0 = gGeoManager->MakeBox(Form("vPC_PSUb0_S%d", side), mCu, xPC_PSUb0 / 2, yPC_PSUb0 / 2, zPC_PSUb0 / 2); + auto* r_PC_PSU = new TGeoRotation("rotation_PC_PSU", -signe * 52., 0., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUb0 = -signe * 22.4; + Double_t YPC_PSUb0 = -16.4; + Double_t ZPC_PSUb0 = -72.5 + signe * 1.; + auto* p_PC_PSU = new TGeoCombiTrans(XPC_PSUb0, YPC_PSUb0, ZPC_PSUb0, r_PC_PSU); + vPC_PSUb0->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUb0, 1, p_PC_PSU); + //=========== + Double_t xPC_PSUb1 = 2.1; // length + Double_t yPC_PSUb1 = 0.274; // square side + Double_t zPC_PSUb1 = yPC_PSUb1; + TGeoVolume* vPC_PSUb1 = gGeoManager->MakeBox(Form("vPC_PSUb1_S%d", side), mCu, xPC_PSUb1 / 2, yPC_PSUb1 / 2, zPC_PSUb1 / 2); + r_PC_PSU = new TGeoRotation("rotation_PC_PSU", 90. - signe * 52., 90., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUb1 = XPC_PSUb0 - signe * xPC_PSUb1 / 2 * TMath::Cos((90. - 52.) * TMath::Pi() / 180.); + Double_t YPC_PSUb1 = YPC_PSUb0 - xPC_PSUb1 / 2 * TMath::Sin((90. - 52.) * TMath::Pi() / 180.); + Double_t ZPC_PSUb1 = ZPC_PSUb0 - zPC_PSUb0 / 2 - yPC_PSUb1 / 2; + p_PC_PSU = new TGeoCombiTrans(XPC_PSUb1, YPC_PSUb1, ZPC_PSUb1, r_PC_PSU); + vPC_PSUb1->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUb1, 1, p_PC_PSU); + //=========== + Double_t xPC_PSUb2 = yPC_PSUb1; + Double_t yPC_PSUb2 = yPC_PSUb1; + Double_t zPC_PSUb2 = 11.; // length + TGeoVolume* vPC_PSUb2 = gGeoManager->MakeBox(Form("vPC_PSUb0_S%d", side), mCu, xPC_PSUb2 / 2, yPC_PSUb2 / 2, zPC_PSUb2 / 2); + r_PC_PSU = new TGeoRotation("rotation_PC_PSU", -signe * 52., 0., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUb2 = -signe * 24.2; + Double_t YPC_PSUb2 = -17.8; + Double_t ZPC_PSUb2 = ZPC_PSUb0 - zPC_PSUb0 / 2 - zPC_PSUb2 / 2; + p_PC_PSU = new TGeoCombiTrans(XPC_PSUb2, YPC_PSUb2, ZPC_PSUb2, r_PC_PSU); + vPC_PSUb2->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUb2, 1, p_PC_PSU); + + // t : top + TGeoVolume* vPC_PSUt0 = gGeoManager->MakeBox(Form("vPC_PSUt0_S%d", side), mCu, xPC_PSUb0 / 2, yPC_PSUb0 / 2, zPC_PSUb0 / 2); + r_PC_PSU = new TGeoRotation("rotation_PC_PSU", signe * 52., 0., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUt0 = -signe * 22.4; + Double_t YPC_PSUt0 = 16.4; + Double_t ZPC_PSUt0 = -72.5 - signe * 1.; + p_PC_PSU = new TGeoCombiTrans(XPC_PSUt0, YPC_PSUt0, ZPC_PSUt0, r_PC_PSU); + vPC_PSUt0->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUt0, 1, p_PC_PSU); + //=========== + TGeoVolume* vPC_PSUt1 = gGeoManager->MakeBox(Form("vPC_PSUt1_S%d", side), mCu, xPC_PSUb1 / 2, yPC_PSUb1 / 2, zPC_PSUb1 / 2); + r_PC_PSU = new TGeoRotation("rotation_PC_PSU", -(90.0 - signe * 52.0), 90., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUt1 = XPC_PSUt0 - signe * xPC_PSUb1 / 2 * TMath::Cos((90. - 52.) * TMath::Pi() / 180); + Double_t YPC_PSUt1 = YPC_PSUt0 + xPC_PSUb1 / 2 * TMath::Sin((90. - 52.) * TMath::Pi() / 180.); + Double_t ZPC_PSUt1 = ZPC_PSUt0 - zPC_PSUb0 / 2 - yPC_PSUb1 / 2; + p_PC_PSU = new TGeoCombiTrans(XPC_PSUt1, YPC_PSUt1, ZPC_PSUt1, r_PC_PSU); + vPC_PSUt1->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUt1, 1, p_PC_PSU); + //=========== + TGeoVolume* vPC_PSUt2 = gGeoManager->MakeBox(Form("vPC_PSUt0_S%d", side), mCu, xPC_PSUb2 / 2, yPC_PSUb2 / 2, zPC_PSUb2 / 2); + r_PC_PSU = new TGeoRotation("rotation_PC_PSU", signe * 52., 0., 0.); + r_PC_PSU->RegisterYourself(); + Double_t XPC_PSUt2 = XPC_PSUb2; + Double_t YPC_PSUt2 = -YPC_PSUb2; + Double_t ZPC_PSUt2 = ZPC_PSUt0 - zPC_PSUb0 / 2 - zPC_PSUb2 / 2; + p_PC_PSU = new TGeoCombiTrans(XPC_PSUt2, YPC_PSUt2, ZPC_PSUt2, r_PC_PSU); + vPC_PSUt2->SetLineColor(kBlue); + HalfConeVolume->AddNode(vPC_PSUt2, 1, p_PC_PSU); } diff --git a/Detectors/ITSMFT/MFT/base/src/HalfDetector.cxx b/Detectors/ITSMFT/MFT/base/src/HalfDetector.cxx index b3a133dbae734..7bf1025e0f801 100644 --- a/Detectors/ITSMFT/MFT/base/src/HalfDetector.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HalfDetector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/HalfDisk.cxx b/Detectors/ITSMFT/MFT/base/src/HalfDisk.cxx index 6783e8440d0a0..4114476562b4b 100644 --- a/Detectors/ITSMFT/MFT/base/src/HalfDisk.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HalfDisk.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/HalfDiskSegmentation.cxx b/Detectors/ITSMFT/MFT/base/src/HalfDiskSegmentation.cxx index 5b5651c566712..80d902c3f8d60 100644 --- a/Detectors/ITSMFT/MFT/base/src/HalfDiskSegmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HalfDiskSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/HalfSegmentation.cxx b/Detectors/ITSMFT/MFT/base/src/HalfSegmentation.cxx index 0d6521e6cf3d1..167681724b93d 100644 --- a/Detectors/ITSMFT/MFT/base/src/HalfSegmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HalfSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx index b674159cdb603..82e8ef6aaece5 100644 --- a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -1408,6 +1409,7 @@ void HeatExchanger::createHalfDisk0(Int_t half) mHalfDisk->AddNode(rohacellPlate, 1, transformation); createManifold(disk); + createCoolingPipes(half, disk); } //_____________________________________________________________________________ @@ -1957,6 +1959,7 @@ void HeatExchanger::createHalfDisk1(Int_t half) mHalfDisk->AddNode(rohacellPlate, 2, transformation); createManifold(disk); + createCoolingPipes(half, disk); } //_____________________________________________________________________________ @@ -2612,6 +2615,7 @@ void HeatExchanger::createHalfDisk2(Int_t half) mHalfDisk->AddNode(rohacellPlate, 2, transformation); createManifold(disk); + createCoolingPipes(half, disk); } //_____________________________________________________________________________ @@ -3160,6 +3164,7 @@ void HeatExchanger::createHalfDisk3(Int_t half) mHalfDisk->AddNode(rohacellPlate, 2, transformation); createManifold(disk); + createCoolingPipes(half, disk); } //_____________________________________________________________________________ @@ -3712,6 +3717,493 @@ void HeatExchanger::createHalfDisk4(Int_t half) mHalfDisk->AddNode(rohacellPlate, 2, transformation); createManifold(disk); + createCoolingPipes(half, disk); +} + +//_____________________________________________________________________________ +void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) +{ + mPipe = gGeoManager->GetMedium("MFT_Polyurethane$"); + mWater = gGeoManager->GetMedium("MFT_Water$"); + Float_t length1; + Float_t length2; + Float_t rin = 0.25 / 2; + Float_t rout = 0.4 / 2; + TGeoVolume* Tube1 = nullptr; + TGeoVolume* Torus1 = nullptr; + TGeoVolume* TubeW1 = nullptr; + TGeoVolume* TorusW1 = nullptr; + TGeoRotation* rTorus1 = nullptr; + TGeoCombiTrans* transfoTorus1 = nullptr; + Float_t radius1; + //----------------------------------------------------------------- + if (disk == 0 || disk == 1 || disk == 2) { + auto* mCoolingPipe1 = new TGeoVolumeAssembly(Form("cooling_pipe1_H%d", half)); + auto* mCoolingPipeRear1 = new TGeoVolumeAssembly(Form("cooling_pipeRear1_H%d", half)); + auto* mCoolingPipeRear2 = new TGeoVolumeAssembly(Form("cooling_pipeRear2_H%d", half)); + if (disk == 0) { + length1 = 1.5; + } + if (disk == 1) { + length1 = 1.0; + } + if (disk == 2) { + length1 = 0.5; + } + Tube1 = gGeoManager->MakeTube(Form("Tube1_H%d_D%d", half, disk), mPipe, rin, rout, length1 / 2); + TubeW1 = gGeoManager->MakeTube(Form("TubeW1_H%d_D%d", half, disk), mWater, 0., rin, length1 / 2); + TGeoTranslation* tTube1 = new TGeoTranslation(0.0, 0.0, 0.0); + tTube1->RegisterYourself(); + + radius1 = 0.4; + Torus1 = gGeoManager->MakeTorus(Form("Torus1_H%d_D%d", half, disk), mPipe, radius1, rin, rout, 0., 90.); + TorusW1 = gGeoManager->MakeTorus(Form("TorusW1_H%d_D%d", half, disk), mWater, radius1, 0., rin, 0., 90.); + rTorus1 = new TGeoRotation("rotationTorus1", 0.0, 90.0, 0.0); + rTorus1->RegisterYourself(); + transfoTorus1 = new TGeoCombiTrans(-radius1, 0., length1 / 2, rTorus1); + transfoTorus1->RegisterYourself(); + + if (disk == 0) { + length2 = 8.0; + } + if (disk == 1) { + length2 = 4.3; + } + if (disk == 2) { + length2 = 0.55; + } + TGeoVolume* Tube2 = gGeoManager->MakeTube(Form("Tube2_H%d_D%d", half, disk), mPipe, rin, rout, length2 / 2); + TGeoVolume* TubeW2 = gGeoManager->MakeTube(Form("TubeW2_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); + TGeoRotation* rTube2 = new TGeoRotation("rotationTube2", 90.0, 90.0, 0.0); + rTube2->RegisterYourself(); + TGeoCombiTrans* transfoTube2 = new TGeoCombiTrans(-length2 / 2 - radius1, 0., length1 / 2 + radius1, rTube2); + transfoTube2->RegisterYourself(); + + Float_t radius2 = 4.; + if (disk == 2) { + radius2 = 3.5; + } + TGeoVolume* Torus2 = gGeoManager->MakeTorus(Form("Torus2_H%d_D%d", half, disk), mPipe, radius2, rin, rout, 0., -90.); + TGeoVolume* TorusW2 = gGeoManager->MakeTorus(Form("TorusW2_H%d_D%d", half, disk), mWater, radius2, 0., rin, 0., -90.); + TGeoRotation* rTorus2 = new TGeoRotation("rotationTorus2", 180.0, 0.0, 0.0); + rTorus2->RegisterYourself(); + TGeoCombiTrans* transfoTorus2 = new TGeoCombiTrans(-length2 - radius1, -radius2, length1 / 2 + radius1, rTorus2); + transfoTorus2->RegisterYourself(); + + Float_t length3; + if (disk == 0) { + length3 = 3.9; + } + if (disk == 1) { + length3 = 3.8; + } + if (disk == 2) { + length3 = 4.2; + } + TGeoVolume* Tube3 = gGeoManager->MakeTube(Form("Tube3_H%d_D%d", half, disk), mPipe, rin, rout, length3 / 2); + TGeoVolume* TubeW3 = gGeoManager->MakeTube(Form("TubeW3_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); + TGeoRotation* rTube3 = new TGeoRotation("rotationTube3", 0.0, -90.0, 0.0); + rTube3->RegisterYourself(); + TGeoCombiTrans* transfoTube3 = new TGeoCombiTrans(-length2 - radius2 - radius1, -radius2 - length3 / 2, length1 / 2 + radius1, rTube3); + transfoTube3->RegisterYourself(); + + Float_t length4 = 16.0; // one single pipe instead of 3 pipes coming from the 3 first disks + Float_t rin4 = 0.216; + Float_t rout4 = 0.346; + TGeoVolume* Tube4 = gGeoManager->MakeTube(Form("Tube4_H%d_D%d", half, disk), mPipe, rin4, rout4, length4 / 2); + TGeoVolume* TubeW4 = gGeoManager->MakeTube(Form("TubeW4_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); + Float_t theta4 = 10.5; // horizontal plane angle + Float_t phi4 = 35; // vertical plane angle + TGeoRotation* rTube4 = new TGeoRotation("rotationTube4", 90.0 + theta4, 90.0 + phi4, 0.0); + rTube4->RegisterYourself(); + // next line, the x and z axis are reversed in the location... + Float_t dx = 2.0; + Float_t xTube4 = length1 / 2. + radius1 + TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 * 0.8; + Float_t yTube4 = -radius2 - length3 - TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 * 0.8; + Float_t zTube4 = -radius1 - length2 - radius2 - TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 * 0.8 - 0.2; + TGeoCombiTrans* transfoTube4 = new TGeoCombiTrans(zTube4, yTube4 - 0.2, xTube4 - 0.1, rTube4); + transfoTube4->RegisterYourself(); + + Float_t length5 = 13.0; // one single pipe instead of 5 pipes + Double_t theta = 180. * TMath::Pi() / 180.; + Double_t phi = 0. * TMath::Pi() / 180.; + Double_t nlow[3]; + nlow[0] = TMath::Sin(theta) * TMath::Cos(phi); + nlow[1] = TMath::Sin(theta) * TMath::Sin(phi); + nlow[2] = TMath::Cos(theta); + theta = 15. * TMath::Pi() / 180.; + phi = -90. * TMath::Pi() / 180.; + Double_t nhi[3]; + nhi[0] = TMath::Sin(theta) * TMath::Cos(phi); + nhi[1] = TMath::Sin(theta) * TMath::Sin(phi); + nhi[2] = TMath::Cos(theta); + Float_t rin5 = 0.278; + Float_t rout5 = 0.447; + TGeoVolume* Tube5 = gGeoManager->MakeCtub(Form("Tube5_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoVolume* TubeW5 = gGeoManager->MakeCtub(Form("TubeW5_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + Float_t theta5 = 11.5; // angle from the "horizontal" plane x,z + Float_t phi5 = 16.7; // "azimutal" angle + TGeoRotation* rTube5 = new TGeoRotation("rotationTube5", 90.0 + theta5, 90.0 + phi5, 0.0); + rTube5->RegisterYourself(); + Float_t xTube5 = xTube4 + TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 + TMath::Cos(theta5 * TMath::DegToRad()) * TMath::Sin(phi5 * TMath::DegToRad()) * length5 / 2 * 1.03; + Float_t yTube5 = yTube4 - TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 - TMath::Sin(theta5 * TMath::DegToRad()) * length5 / 2 * 1.03 + 0.2; + Float_t zTube5 = zTube4 - TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 - TMath::Cos(theta5 * TMath::DegToRad()) * TMath::Cos(phi5 * TMath::DegToRad()) * length5 / 2 * 1.03; + TGeoCombiTrans* transfoTube5 = new TGeoCombiTrans(zTube5, yTube5, xTube5, rTube5); + transfoTube5->RegisterYourself(); + + Tube1->SetLineColor(kGray); + Torus1->SetLineColor(kGray); + Tube2->SetLineColor(kGray); + Torus2->SetLineColor(kGray); + Tube3->SetLineColor(kGray); + Tube4->SetLineColor(kGray); + Tube5->SetLineColor(kGray); + TubeW3->SetLineColor(kBlue); + TubeW4->SetLineColor(kBlue); + TubeW5->SetLineColor(kBlue); + + mCoolingPipe1->AddNode(Tube1, 1, tTube1); + mCoolingPipe1->AddNode(Torus1, 1, transfoTorus1); + mCoolingPipe1->AddNode(Tube2, 1, transfoTube2); + mCoolingPipe1->AddNode(Torus2, 1, transfoTorus2); + mCoolingPipe1->AddNode(Tube3, 1, transfoTube3); + mCoolingPipe1->AddNode(TubeW1, 1, tTube1); + mCoolingPipe1->AddNode(TorusW1, 1, transfoTorus1); + mCoolingPipe1->AddNode(TubeW2, 1, transfoTube2); + mCoolingPipe1->AddNode(TorusW2, 1, transfoTorus2); + mCoolingPipe1->AddNode(TubeW3, 1, transfoTube3); + + if (disk == 0) { // to create only one time Tube4 and Tube5 + mCoolingPipeRear1->AddNode(Tube4, 1, transfoTube4); + mCoolingPipeRear1->AddNode(Tube5, 1, transfoTube5); + mCoolingPipeRear1->AddNode(TubeW4, 1, transfoTube4); + mCoolingPipeRear1->AddNode(TubeW5, 1, transfoTube5); + } + + //----------------------------------------------------------------- + auto* mCoolingPipe2 = new TGeoVolumeAssembly(Form("cooling_pipe2_H%d_D%d", half, disk)); + TGeoVolume* Tube1p = gGeoManager->MakeTube(Form("Tube1p_H%d_D%d", half, disk), mPipe, rin, rout, length1 / 2); + TGeoVolume* TubeW1p = gGeoManager->MakeTube(Form("TubeW1p_H%d_D%d", half, disk), mWater, 0., rin, length1 / 2); + + TGeoVolume* Torus1p = gGeoManager->MakeTorus(Form("Torus1p_H%d_D%d", half, disk), mPipe, radius1, rin, rout, 0., 90.); + TGeoVolume* TorusW1p = gGeoManager->MakeTorus(Form("TorusW1p_H%d_D%d", half, disk), mWater, radius1, 0., rin, 0., 90.); + + TGeoVolume* Tube2p = gGeoManager->MakeTube(Form("Tube2p_H%d_D%d", half, disk), mPipe, rin, rout, length2 / 2); + TGeoVolume* TubeW2p = gGeoManager->MakeTube(Form("TubeW2p_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); + + TGeoVolume* Torus2p = gGeoManager->MakeTorus(Form("Torus2p_H%d_D%d", half, disk), mPipe, radius2, rin, rout, 0., 90.); + TGeoVolume* TorusW2p = gGeoManager->MakeTorus(Form("TorusW2p_H%d_D%d", half, disk), mWater, radius2, 0., rin, 0., 90.); + + TGeoVolume* Tube3p = gGeoManager->MakeTube(Form("Tube3p_H%d_D%d", half, disk), mPipe, rin, rout, length3 / 2); + TGeoVolume* TubeW3p = gGeoManager->MakeTube(Form("TubeW3p_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); + + TGeoRotation* rTorus2p = new TGeoRotation("rotationTorus2p", 180.0, 0.0, 0.0); + rTorus2p->RegisterYourself(); + TGeoCombiTrans* transfoTorus2p = new TGeoCombiTrans(-length2 - radius1, radius2, length1 / 2 + radius1, rTorus2p); + transfoTorus2p->RegisterYourself(); + TGeoCombiTrans* transfoTube3p = new TGeoCombiTrans(-length2 - radius2 - radius1, radius2 + length3 / 2, length1 / 2 + radius1, rTube3); + transfoTube3p->RegisterYourself(); + TGeoRotation* rTube4p = new TGeoRotation(Form("rotationTube4p_H%d_D%d", half, disk), 90.0 - theta4, phi4 - 90.0, 0.0); + rTube4p->RegisterYourself(); + + TGeoCombiTrans* transfoTube4p = new TGeoCombiTrans(zTube4, -yTube4 + 0.2, xTube4 - 0.1, rTube4p); + transfoTube4p->RegisterYourself(); + + Tube1p->SetLineColor(kGray); + Torus1p->SetLineColor(kGray); + Tube2p->SetLineColor(kGray); + Torus2p->SetLineColor(kGray); + Tube3p->SetLineColor(kGray); + TubeW3p->SetLineColor(kBlue); + + mCoolingPipe2->AddNode(Tube1p, 1, tTube1); + mCoolingPipe2->AddNode(Torus1p, 1, transfoTorus1); + mCoolingPipe2->AddNode(Tube2p, 1, transfoTube2); + mCoolingPipe2->AddNode(Torus2p, 1, transfoTorus2p); + mCoolingPipe2->AddNode(Tube3p, 1, transfoTube3p); + mCoolingPipe2->AddNode(TubeW1p, 1, tTube1); + mCoolingPipe2->AddNode(TorusW1p, 1, transfoTorus1); + mCoolingPipe2->AddNode(TubeW2p, 1, transfoTube2); + mCoolingPipe2->AddNode(TorusW2p, 1, transfoTorus2p); + mCoolingPipe2->AddNode(TubeW3p, 1, transfoTube3p); + + if (disk == 0) { + + TGeoVolume* Tube4p = gGeoManager->MakeTube(Form("Tube4p_H%d_D%d", half, disk), mPipe, rin4, rout4, length4 / 2); + TGeoVolume* TubeW4p = gGeoManager->MakeTube(Form("TubeW4p_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); + Tube4p->SetLineColor(kGray); + TubeW4p->SetLineColor(kBlue); + + mCoolingPipeRear2->AddNode(Tube4p, 1, transfoTube4p); + mCoolingPipeRear2->AddNode(TubeW4p, 1, transfoTube4p); + theta = 180. * TMath::Pi() / 180.; + phi = 0. * TMath::Pi() / 180.; + nlow[0] = TMath::Sin(theta) * TMath::Cos(phi); + nlow[1] = TMath::Sin(theta) * TMath::Sin(phi); + nlow[2] = TMath::Cos(theta); + theta = -15. * TMath::Pi() / 180.; + phi = 270. * TMath::Pi() / 180.; + nhi[0] = TMath::Sin(theta) * TMath::Cos(phi); + nhi[1] = TMath::Sin(theta) * TMath::Sin(phi); + nhi[2] = TMath::Cos(theta); + TGeoVolume* Tube5p = gGeoManager->MakeCtub(Form("Tube5p_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoVolume* TubeW5p = gGeoManager->MakeCtub(Form("TubeW5p_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoRotation* rTube5p = new TGeoRotation("rotationTube5p", -90.0 - theta5, -(90.0 + phi5), 0.0); + rTube5p->RegisterYourself(); + TGeoCombiTrans* transfoTube5p; + transfoTube5p = new TGeoCombiTrans(zTube5, -yTube5, xTube5, rTube5p); + transfoTube5p->RegisterYourself(); + Tube5p->SetLineColor(kGray); + TubeW5p->SetLineColor(kBlue); + mCoolingPipeRear2->AddNode(Tube5p, 1, transfoTube5p); + mCoolingPipeRear2->AddNode(TubeW5p, 1, transfoTube5p); + } + TGeoCombiTrans* transfoCoolingPipe1 = nullptr; + TGeoCombiTrans* transfoCoolingPipe2 = nullptr; + TGeoCombiTrans* transfoCoolingPipeRear1 = nullptr; + TGeoCombiTrans* transfoCoolingPipeRear2 = nullptr; + + TGeoRotation* rotation1 = new TGeoRotation("rotation1", 90., 90., 90.); + rotation1->RegisterYourself(); + // 0.75 = Y location from manifold line 836 + transfoCoolingPipe1 = new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); + transfoCoolingPipe1->RegisterYourself(); + transfoCoolingPipeRear1 = new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); + transfoCoolingPipeRear1->RegisterYourself(); + TGeoRotation* rotation2 = new TGeoRotation("rotation2", 90., 90., 90.); + rotation2->RegisterYourself(); + transfoCoolingPipe2 = new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); + transfoCoolingPipe2->RegisterYourself(); + transfoCoolingPipeRear2 = new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); + transfoCoolingPipeRear2->RegisterYourself(); + mHalfDisk->AddNode(mCoolingPipe1, 1, transfoCoolingPipe1); + mHalfDisk->AddNode(mCoolingPipeRear1, 1, transfoCoolingPipeRear1); + mHalfDisk->AddNode(mCoolingPipe2, 1, transfoCoolingPipe2); + mHalfDisk->AddNode(mCoolingPipeRear2, 1, transfoCoolingPipeRear2); + } + + //================================================================= + //================================================================= + if (disk == 3) { + // One diagonal side + auto* mCoolingPipe3 = new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); + Float_t length1_3 = 4.0; + TGeoVolume* Tube1_3 = gGeoManager->MakeTube(Form("Tube1_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); + TGeoVolume* TubeW1_3 = gGeoManager->MakeTube(Form("TubeW1_3_H%d_D%d", half, disk), mWater, 0., rin, length1_3 / 2); + TGeoTranslation* tTube1_3 = new TGeoTranslation(0.0, 0.0, 0.0); + tTube1_3->RegisterYourself(); + Float_t radius1_3 = 0.4; + TGeoVolume* Torus1_3 = gGeoManager->MakeTorus(Form("Torus1_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); + TGeoVolume* TorusW1_3 = gGeoManager->MakeTorus(Form("TorusW1_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); + TGeoRotation* rTorus1_3 = new TGeoRotation("rotationTorus1_3", 90.0, 90.0, 0.0); + rTorus1_3->RegisterYourself(); + TGeoCombiTrans* transfoTorus1_3 = new TGeoCombiTrans(0.0, -radius1_3, length1_3 / 2, rTorus1_3); + transfoTorus1_3->RegisterYourself(); + + Float_t length2_3; + if (disk == 3) { + length2_3 = 10.4; + } + TGeoVolume* Tube2_3 = gGeoManager->MakeTube(Form("Tube2_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); + TGeoVolume* TubeW2_3 = gGeoManager->MakeTube(Form("TubeW2_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); + TGeoRotation* rTube2_3 = new TGeoRotation("rotationTube2_3", 180.0, 90.0, 90.0); + rTube2_3->RegisterYourself(); + TGeoCombiTrans* transfoTube2_3 = new TGeoCombiTrans(0., -length2_3 / 2 - radius1_3, length1_3 / 2 + radius1_3, rTube2_3); + transfoTube2_3->RegisterYourself(); + TGeoVolume* Torus2_3 = gGeoManager->MakeTorus(Form("Torus2_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); + TGeoVolume* TorusW2_3 = gGeoManager->MakeTorus(Form("TorusW2_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); + TGeoRotation* rTorus2_3 = new TGeoRotation("rotationTorus2_3", 90.0, 90.0, 180.0); + rTorus2_3->RegisterYourself(); + TGeoCombiTrans* transfoTorus2_3 = new TGeoCombiTrans(0.0, -length2_3 - radius1_3, length1_3 / 2 + radius1_3 + radius1_3, rTorus2_3); + transfoTorus2_3->RegisterYourself(); + + Float_t length3_3; + if (disk == 3) { + length3_3 = 1.5; + } + TGeoVolume* Tube3_3 = gGeoManager->MakeTube(Form("Tube3_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); + TGeoVolume* TubeW3_3 = gGeoManager->MakeTube(Form("TubeW3_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); + TGeoRotation* rTube3_3 = new TGeoRotation("rotationTube3_3", 0.0, 0.0, 0.0); + rTube3_3->RegisterYourself(); + TGeoCombiTrans* transfoTube3_3 = new TGeoCombiTrans(0., -length2_3 - radius1_3 - radius1_3, length1_3 / 2 + radius1_3 + radius1_3 + length3_3 / 2, rTube3_3); + transfoTube3_3->RegisterYourself(); + + Tube1_3->SetLineColor(kGray); + Torus1_3->SetLineColor(kGray); + Tube2_3->SetLineColor(kGray); + Torus2_3->SetLineColor(kGray); + Tube3_3->SetLineColor(kGray); + TubeW3_3->SetLineColor(kBlue); + + mCoolingPipe3->AddNode(Tube1_3, 1, tTube1_3); + mCoolingPipe3->AddNode(Torus1_3, 1, transfoTorus1_3); + mCoolingPipe3->AddNode(Tube2_3, 1, transfoTube2_3); + mCoolingPipe3->AddNode(Torus2_3, 1, transfoTorus2_3); + mCoolingPipe3->AddNode(Tube3_3, 1, transfoTube3_3); + mCoolingPipe3->AddNode(TubeW1_3, 1, tTube1_3); + mCoolingPipe3->AddNode(TorusW1_3, 1, transfoTorus1_3); + mCoolingPipe3->AddNode(TubeW2_3, 1, transfoTube2_3); + mCoolingPipe3->AddNode(TorusW2_3, 1, transfoTorus2_3); + mCoolingPipe3->AddNode(TubeW3_3, 1, transfoTube3_3); + + TGeoCombiTrans* transfoCoolingPipe3_3 = nullptr; + TGeoRotation* rotation3_3 = new TGeoRotation("rotation3_3", 90., 90., 76.); + rotation3_3->RegisterYourself(); + transfoCoolingPipe3_3 = new TGeoCombiTrans(17. + length1_3 / 2, 0.75, 0.0, rotation3_3); + + // ------------------Other diagonal side + auto* mCoolingPipe4 = new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); + + TGeoVolume* Tube1p_3 = gGeoManager->MakeTube(Form("Tube1p_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); + TGeoVolume* Torus1p_3 = gGeoManager->MakeTorus(Form("Torus1p_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); + TGeoVolume* Tube2p_3 = gGeoManager->MakeTube(Form("Tube2p_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); + TGeoVolume* Torus2p_3 = gGeoManager->MakeTorus(Form("Torus2p_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); + TGeoVolume* Tube3p_3 = gGeoManager->MakeTube(Form("Tube3p_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); + TGeoVolume* TubeW1p_3 = gGeoManager->MakeTube(Form("TubeW1p_3_H%d_D%d", half, disk), mWater, 0, rin, length1_3 / 2); + TGeoVolume* TorusW1p_3 = gGeoManager->MakeTorus(Form("TorusW1p_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); + TGeoVolume* TubeW2p_3 = gGeoManager->MakeTube(Form("TubeW2p_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); + TGeoVolume* TorusW2p_3 = gGeoManager->MakeTorus(Form("TorusW2p_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); + TGeoVolume* TubeW3p_3 = gGeoManager->MakeTube(Form("TubeW3p_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); + + Tube1p_3->SetLineColor(kGray); + Torus1p_3->SetLineColor(kGray); + Tube2p_3->SetLineColor(kGray); + Torus2p_3->SetLineColor(kGray); + Tube3p_3->SetLineColor(kGray); + TubeW3p_3->SetLineColor(kBlue); + + mCoolingPipe4->AddNode(Tube1p_3, 1, tTube1_3); + mCoolingPipe4->AddNode(Torus1p_3, 1, transfoTorus1_3); + mCoolingPipe4->AddNode(Tube2p_3, 1, transfoTube2_3); + mCoolingPipe4->AddNode(Torus2p_3, 1, transfoTorus2_3); + mCoolingPipe4->AddNode(Tube3p_3, 1, transfoTube3_3); + mCoolingPipe4->AddNode(TubeW1p_3, 1, tTube1_3); + mCoolingPipe4->AddNode(TorusW1p_3, 1, transfoTorus1_3); + mCoolingPipe4->AddNode(TubeW2p_3, 1, transfoTube2_3); + mCoolingPipe4->AddNode(TorusW2p_3, 1, transfoTorus2_3); + mCoolingPipe4->AddNode(TubeW3p_3, 1, transfoTube3_3); + + TGeoCombiTrans* transfoCoolingPipe4_3 = nullptr; + TGeoRotation* rotation4_3 = new TGeoRotation("rotation4_3", 90., 90., -76.); + rotation4_3->RegisterYourself(); + transfoCoolingPipe4_3 = new TGeoCombiTrans(17. + length1_3 / 2, -0.75, 0.0, rotation4_3); + transfoCoolingPipe4_3->RegisterYourself(); + + mHalfDisk->AddNode(mCoolingPipe3, 1, transfoCoolingPipe3_3); + mHalfDisk->AddNode(mCoolingPipe4, 1, transfoCoolingPipe4_3); + } + + //================================================================= + if (disk == 4) { + // One diagonal side + auto* mCoolingPipe3 = new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); + Float_t length1_4 = 3.0; + TGeoVolume* Tube1_4 = gGeoManager->MakeTube(Form("Tube1_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); + TGeoVolume* TubeW1_4 = gGeoManager->MakeTube(Form("TubeW1_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); + TGeoTranslation* tTube1_4 = new TGeoTranslation(0.0, 0.0, 0.0); + tTube1_4->RegisterYourself(); + + Float_t radius1_4 = 0.4; + TGeoVolume* Torus1_4 = gGeoManager->MakeTorus(Form("Torus1_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); + TGeoVolume* TorusW1_4 = gGeoManager->MakeTorus(Form("TorusW1_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); + TGeoRotation* rTorus1_4 = new TGeoRotation("rotationTorus1_4", 90.0, 90.0, 0.0); + rTorus1_4->RegisterYourself(); + TGeoCombiTrans* transfoTorus1_4 = new TGeoCombiTrans(0.0, -radius1_4, length1_4 / 2, rTorus1_4); + transfoTorus1_4->RegisterYourself(); + + Float_t length2_4; + if (disk == 4) { + length2_4 = 10.8; + } + TGeoVolume* Tube2_4 = gGeoManager->MakeTube("Tube2_4", mPipe, rin, rout, length2_4 / 2); + TGeoVolume* TubeW2_4 = gGeoManager->MakeTube("TubeW2_4", mWater, 0., rin, length2_4 / 2); + TGeoRotation* rTube2_4 = new TGeoRotation("rotationTube2_4", 180.0, 90.0, 90.0); + rTube2_4->RegisterYourself(); + TGeoCombiTrans* transfoTube2_4 = new TGeoCombiTrans(0., -length2_4 / 2 - radius1_4, length1_4 / 2 + radius1_4, rTube2_4); + transfoTube2_4->RegisterYourself(); + + TGeoVolume* Torus2_4 = gGeoManager->MakeTorus(Form("Torus2_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); + TGeoVolume* TorusW2_4 = gGeoManager->MakeTorus(Form("TorusW2_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); + TGeoRotation* rTorus2_4 = new TGeoRotation("rotationTorus2_4", 90.0, 90.0, 180.0); + rTorus2_4->RegisterYourself(); + TGeoCombiTrans* transfoTorus2_4 = new TGeoCombiTrans(0.0, -length2_4 - radius1_4, length1_4 / 2 + radius1_4 + radius1_4, rTorus2_4); + transfoTorus2_4->RegisterYourself(); + + Float_t length3_4; + if (disk == 4) { + length3_4 = 3.8; + } + TGeoVolume* Tube3_4 = gGeoManager->MakeTube(Form("Tube3_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); + TGeoVolume* TubeW3_4 = gGeoManager->MakeTube(Form("TubeW3_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); + TGeoRotation* rTube3_4 = new TGeoRotation("rotationTube3_4", 0.0, 0.0, 0.0); + rTube3_4->RegisterYourself(); + TGeoCombiTrans* transfoTube3_4 = new TGeoCombiTrans(0., -length2_4 - radius1_4 - radius1_4, length1_4 / 2 + radius1_4 + radius1_4 + length3_4 / 2, rTube3_4); + transfoTube3_4->RegisterYourself(); + + Tube1_4->SetLineColor(kGray); + Torus1_4->SetLineColor(kGray); + Tube2_4->SetLineColor(kGray); + Torus2_4->SetLineColor(kGray); + Tube3_4->SetLineColor(kGray); + TubeW3_4->SetLineColor(kBlue); + + mCoolingPipe3->AddNode(Tube1_4, 1, tTube1_4); + mCoolingPipe3->AddNode(Torus1_4, 1, transfoTorus1_4); + mCoolingPipe3->AddNode(Tube2_4, 1, transfoTube2_4); + mCoolingPipe3->AddNode(Torus2_4, 1, transfoTorus2_4); + mCoolingPipe3->AddNode(Tube3_4, 1, transfoTube3_4); + mCoolingPipe3->AddNode(TubeW1_4, 1, tTube1_4); + mCoolingPipe3->AddNode(TorusW1_4, 1, transfoTorus1_4); + mCoolingPipe3->AddNode(TubeW2_4, 1, transfoTube2_4); + mCoolingPipe3->AddNode(TorusW2_4, 1, transfoTorus2_4); + mCoolingPipe3->AddNode(TubeW3_4, 1, transfoTube3_4); + + TGeoCombiTrans* transfoCoolingPipe3_4 = nullptr; + TGeoRotation* rotation3_4 = new TGeoRotation("rotation3_4", 90., 90., 100.); + rotation3_4->RegisterYourself(); + transfoCoolingPipe3_4 = new TGeoCombiTrans(17. + length1_4 / 2, 0.75, 0.0, rotation3_4); + transfoCoolingPipe3_4->RegisterYourself(); + // ------------------Other diagonal side + auto* mCoolingPipe4 = new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); + TGeoVolume* Tube1p_4 = gGeoManager->MakeTube(Form("Tube1p_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); + TGeoVolume* Torus1p_4 = gGeoManager->MakeTorus(Form("Torus1p_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); + TGeoVolume* Tube2p_4 = gGeoManager->MakeTube(Form("Tube2p_4_H%d_D%d", half, disk), mPipe, rin, rout, length2_4 / 2); + TGeoVolume* Torus2p_4 = gGeoManager->MakeTorus(Form("Torus2p_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); + TGeoVolume* Tube3p_4 = gGeoManager->MakeTube(Form("Tube3p_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); + TGeoVolume* TubeW1p_4 = gGeoManager->MakeTube(Form("TubeW1p_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); + TGeoVolume* TorusW1p_4 = gGeoManager->MakeTorus(Form("TorusW1p_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); + TGeoVolume* TubeW2p_4 = gGeoManager->MakeTube(Form("TubeW2p_4_H%d_D%d", half, disk), mWater, 0., rin, length2_4 / 2); + TGeoVolume* TorusW2p_4 = gGeoManager->MakeTorus(Form("TorusW2p_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); + TGeoVolume* TubeW3p_4 = gGeoManager->MakeTube(Form("TubeW3p_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); + + Tube1p_4->SetLineColor(kGray); + Torus1p_4->SetLineColor(kGray); + Tube2p_4->SetLineColor(kGray); + Torus2p_4->SetLineColor(kGray); + Tube3p_4->SetLineColor(kGray); + TubeW3p_4->SetLineColor(kBlue); + + mCoolingPipe4->AddNode(Tube1p_4, 1, tTube1_4); + mCoolingPipe4->AddNode(Torus1p_4, 1, transfoTorus1_4); + mCoolingPipe4->AddNode(Tube2p_4, 1, transfoTube2_4); + mCoolingPipe4->AddNode(Torus2p_4, 1, transfoTorus2_4); + mCoolingPipe4->AddNode(Tube3p_4, 1, transfoTube3_4); + mCoolingPipe4->AddNode(TubeW1p_4, 1, tTube1_4); + mCoolingPipe4->AddNode(TorusW1p_4, 1, transfoTorus1_4); + mCoolingPipe4->AddNode(TubeW2p_4, 1, transfoTube2_4); + mCoolingPipe4->AddNode(TorusW2p_4, 1, transfoTorus2_4); + mCoolingPipe4->AddNode(TubeW3p_4, 1, transfoTube3_4); + + TGeoCombiTrans* transfoCoolingPipe4_4 = nullptr; + TGeoRotation* rotation4_4 = new TGeoRotation("rotation4_4", 90., 90., -100.); + rotation4_4->RegisterYourself(); + transfoCoolingPipe4_4 = new TGeoCombiTrans(17. + length1_4 / 2, -0.75, 0.0, rotation4_4); + transfoCoolingPipe4_4->RegisterYourself(); + + mHalfDisk->AddNode(mCoolingPipe3, 1, transfoCoolingPipe3_4); + mHalfDisk->AddNode(mCoolingPipe4, 1, transfoCoolingPipe4_4); + } + //================================================================= } //_____________________________________________________________________________ diff --git a/Detectors/ITSMFT/MFT/base/src/Ladder.cxx b/Detectors/ITSMFT/MFT/base/src/Ladder.cxx index 48dd77c2e2a4f..d57fa411cf556 100644 --- a/Detectors/ITSMFT/MFT/base/src/Ladder.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Ladder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/LadderSegmentation.cxx b/Detectors/ITSMFT/MFT/base/src/LadderSegmentation.cxx index 6791d13307e4d..903db118b5d9a 100644 --- a/Detectors/ITSMFT/MFT/base/src/LadderSegmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/LadderSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/MFTBaseLinkDef.h b/Detectors/ITSMFT/MFT/base/src/MFTBaseLinkDef.h index 22dc1917c1583..501cddda6cbbc 100644 --- a/Detectors/ITSMFT/MFT/base/src/MFTBaseLinkDef.h +++ b/Detectors/ITSMFT/MFT/base/src/MFTBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/MFTBaseParam.cxx b/Detectors/ITSMFT/MFT/base/src/MFTBaseParam.cxx index 79a25f95dffaa..80cd8b2b03135 100644 --- a/Detectors/ITSMFT/MFT/base/src/MFTBaseParam.cxx +++ b/Detectors/ITSMFT/MFT/base/src/MFTBaseParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/PCBSupport.cxx b/Detectors/ITSMFT/MFT/base/src/PCBSupport.cxx index e6d1ca89ca65a..b3823a173c930 100644 --- a/Detectors/ITSMFT/MFT/base/src/PCBSupport.cxx +++ b/Detectors/ITSMFT/MFT/base/src/PCBSupport.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/PatchPanel.cxx b/Detectors/ITSMFT/MFT/base/src/PatchPanel.cxx index 6b756aac967cb..5a3dfa887b1e4 100644 --- a/Detectors/ITSMFT/MFT/base/src/PatchPanel.cxx +++ b/Detectors/ITSMFT/MFT/base/src/PatchPanel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -47,6 +48,7 @@ TGeoVolumeAssembly* PatchPanel::createPatchPanel() auto* PatchPanelVolume = new TGeoVolumeAssembly("PatchPanelVolume"); TGeoMedium* kMedAlu = gGeoManager->GetMedium("MFT_Alu$"); + TGeoMedium* kMedCu = gGeoManager->GetMedium("MFT_Cu$"); ///////////////////////////////////// A //////////////////////////// @@ -442,8 +444,8 @@ TGeoVolumeAssembly* PatchPanel::createPatchPanel() ang_in_scut2, ang_fin_scut2); // new TGeoTubeSeg("S_ARM", radin_arm, radout_arm, high_arm / 2, angin_arm, - // angfin_arm); new TGeoTubeSeg("S_ARM_R", radin_armR, radout_armR, high_armR / - // 2, angin_armR, angfin_armR); + // angfin_arm); new TGeoTubeSeg("S_ARM_R", radin_armR, radout_armR, high_armR + // / 2, angin_armR, angfin_armR); new TGeoBBox("Abox", x_Abox / 2, y_Abox / 2, z_Abox / 2); @@ -816,11 +818,163 @@ TGeoVolumeAssembly* PatchPanel::createPatchPanel() auto* patchpanel_Volume = new TGeoVolume("patchpanel_Volume", patchpanel_Shape, kMedAlu); + //====== Contents of the patch panel (cables, pipes, cards) coded as plates + //====== + Double_t radin_pl0 = 33; // inner radius + Double_t radout_pl0 = 45; // outer radius + Double_t high_pl0 = 0.15; // thickness + Double_t angin_pl0 = 20.; // theta min + Double_t angfin_pl0 = 30.; // theta max + + Double_t radin_pl1 = 33; + Double_t radout_pl1 = 49; + Double_t high_pl1 = 0.15; + Double_t angin_pl1 = 31.; + Double_t angfin_pl1 = 49.; + + //=== Central part with high density of materials == + Double_t radin_pl2 = 32; + Double_t radout_pl2 = 49; + Double_t high_pl2 = 0.3; + Double_t angin_pl2 = 57.; + Double_t angfin_pl2 = 75.; + + Double_t radin_pl3 = 29; + Double_t radout_pl3 = 47; + Double_t high_pl3 = 0.3; + Double_t angin_pl3 = 75.5; + Double_t angfin_pl3 = 104.5; + + Double_t radin_pl4 = 32; + Double_t radout_pl4 = 49; + Double_t high_pl4 = 0.3; + Double_t angin_pl4 = 105.; + Double_t angfin_pl4 = 122.; + //=================================================== + + Double_t radin_pl5 = 33; + Double_t radout_pl5 = 49; + Double_t high_pl5 = 0.15; + Double_t angin_pl5 = 131; + Double_t angfin_pl5 = 149; + + Double_t radin_pl6 = 33; + Double_t radout_pl6 = 45; + Double_t high_pl6 = 0.15; + Double_t angin_pl6 = 150; + Double_t angfin_pl6 = 160; + + auto* plate_0 = + new TGeoTubeSeg("plate_0", radin_pl0, radout_pl0, high_pl0 / 2, + 180. + angin_pl0, 180. + angfin_pl0); + auto* plate_1 = + new TGeoTubeSeg("plate_1", radin_pl1, radout_pl1, high_pl1 / 2, + 180. + angin_pl1, 180. + angfin_pl1); + auto* plate_2 = + new TGeoTubeSeg("plate_2", radin_pl2, radout_pl2, high_pl2 / 2, + 180. + angin_pl2, 180. + angfin_pl2); + auto* plate_3 = + new TGeoTubeSeg("plate_3", radin_pl3, radout_pl3, high_pl3 / 2, + 180. + angin_pl3, 180. + angfin_pl3); + auto* plate_4 = + new TGeoTubeSeg("plate_4", radin_pl4, radout_pl4, high_pl4 / 2, + 180. + angin_pl4, 180. + angfin_pl4); + auto* plate_5 = + new TGeoTubeSeg("plate_5", radin_pl5, radout_pl5, high_pl5 / 2, + 180. + angin_pl5, 180. + angfin_pl5); + auto* plate_6 = + new TGeoTubeSeg("plate_6", radin_pl6, radout_pl6, high_pl6 / 2, + 180. + angin_pl6, 180. + angfin_pl6); + auto* plate_Shape = new TGeoCompositeShape( + "plate_Shape", + "plate_0 + plate_1 + plate_2 + plate_3 + plate_4 + plate_5 + plate_6"); + auto* plate_Volume = new TGeoVolume("plate_Volume", plate_Shape, kMedCu); + auto* tr_pl = new TGeoTranslation("tr_pl", 0, 0, -2.4); + tr_pl->RegisterYourself(); + plate_Volume->SetLineColor(kGray + 2); + auto* tr_fin = new TGeoTranslation("tr_fin", 0, 0, -0.2); tr_fin->RegisterYourself(); + //====== Connection to the C-Side, along the hadronic absorber + + Double_t xcable = 12.0; // width + Double_t ycable = 0.28; // thickness + Double_t zcable = 20.0; + TGeoVolume* v_cable0 = gGeoManager->MakeBox("v_cable0", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable0 = new TGeoRotation("rotation_cable0", 24., 8., 0.); + r_cable0->RegisterYourself(); + Double_t Xcable = 18.5; + Double_t Ycable = -42.5; + Double_t Zcable = -(zcable / 2. + 4.); + auto* p_cable0 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable0); + p_cable0->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable0, 1, p_cable0); + + TGeoVolume* v_cable1 = gGeoManager->MakeBox("v_cable1", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable1 = new TGeoRotation("rotation_cable1", -24., 8., 0.); + r_cable1->RegisterYourself(); + Xcable = -18.5; + auto* p_cable1 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable1); + p_cable1->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable1, 1, p_cable1); + + zcable = 170.; + TGeoVolume* v_cable2 = gGeoManager->MakeBox("v_cable2", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable2 = new TGeoRotation("rotation_cable2", 24., -5., 0.); + r_cable2->RegisterYourself(); + Xcable = 21.; + Ycable = -48.; + Zcable = -108.8; + auto* p_cable2 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable2); + p_cable2->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable2, 1, p_cable2); + + TGeoVolume* v_cable3 = gGeoManager->MakeBox("v_cable3", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable3 = new TGeoRotation("rotation_cable3", -24., -5., 0.); + r_cable3->RegisterYourself(); + Xcable = -21.; + auto* p_cable3 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable3); + p_cable3->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable3, 1, p_cable3); + + zcable = 170.; + TGeoVolume* v_cable4 = gGeoManager->MakeBox("v_cable4", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable4 = new TGeoRotation("rotation_cable4", 24., -10., 0.); + r_cable4->RegisterYourself(); + Xcable = 30.5; + Ycable = -68.5; + Zcable = -278.; + auto* p_cable4 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable4); + p_cable4->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable4, 1, p_cable4); + + TGeoVolume* v_cable5 = gGeoManager->MakeBox("v_cable5", kMedCu, xcable / 2, + ycable / 2, zcable / 2); + auto* r_cable5 = new TGeoRotation("rotation_cable5", -24., -10., 0.); + r_cable5->RegisterYourself(); + Xcable = -30.5; + auto* p_cable5 = new TGeoCombiTrans(Xcable, Ycable, Zcable, r_cable5); + p_cable5->RegisterYourself(); + PatchPanelVolume->AddNode(v_cable5, 1, p_cable5); + + v_cable0->SetLineColor(kGray + 2); + v_cable1->SetLineColor(kGray + 2); + v_cable2->SetLineColor(kGray + 2); + v_cable3->SetLineColor(kGray + 2); + v_cable4->SetLineColor(kGray + 2); + v_cable5->SetLineColor(kGray + 2); + + //=========================================================== + patchpanel_Volume->SetLineColor(kGreen - 9); PatchPanelVolume->AddNode(patchpanel_Volume, 1, tr_fin); + PatchPanelVolume->AddNode(plate_Volume, 2, tr_pl); return PatchPanelVolume; } diff --git a/Detectors/ITSMFT/MFT/base/src/PowerSupplyUnit.cxx b/Detectors/ITSMFT/MFT/base/src/PowerSupplyUnit.cxx index e780b4bacd467..fea44b5552948 100644 --- a/Detectors/ITSMFT/MFT/base/src/PowerSupplyUnit.cxx +++ b/Detectors/ITSMFT/MFT/base/src/PowerSupplyUnit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,6 +47,7 @@ TGeoVolumeAssembly* PowerSupplyUnit::create() TGeoMedium* kMedPeek = gGeoManager->GetMedium("MFT_PEEK$"); TGeoMedium* kMed_Water = gGeoManager->GetMedium("MFT_Water$"); TGeoMedium* kMedAlu = gGeoManager->GetMedium("MFT_Alu$"); + TGeoMedium* kMedPolyPipe = gGeoManager->GetMedium("MFT_Polyimide$"); TGeoVolumeAssembly* mHalfPSU = new TGeoVolumeAssembly("PSU"); @@ -396,11 +398,51 @@ TGeoVolumeAssembly* PowerSupplyUnit::create() combtrans_water_pipe_straight_tube_side_left2->RegisterYourself(); combtrans_water_pipe_straight_tube_side_right2->RegisterYourself(); + //==================== PIPE - connection to the patch panel ====================== + TGeoTorus* pipe_side_torus_left3 = new TGeoTorus("pipe_side_torus_left3", water_pipe_side_position_radius, water_pipe_inner_radius, water_pipe_outer_radius, 0, 90); + TGeoRotation* rotate_water_torus_left3 = new TGeoRotation("rotate_water_torus_left3", -90, 90, 0); + TGeoCombiTrans* combtrans_water_torus_left3 = new TGeoCombiTrans("combtrans_water_torus_left3", +(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Cos((90 - water_pipe_side_angle) * TMath::Pi() / 180.) + water_pipe_straight_tube_side1_length * 2 + water_pipe_side_position_radius, + -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Sin((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - 2 * water_pipe_straight_tube_side2_length, -water_pipe_side_position_radius, rotate_water_torus_left3); + combtrans_water_torus_left3->RegisterYourself(); + Float_t water_pipe_straight_tube_side3_length = 5; + TGeoTubeSeg* pipe_straight_tube_left3 = new TGeoTubeSeg("pipe_straight_tube_left3", water_pipe_inner_radius, water_pipe_outer_radius, water_pipe_straight_tube_side3_length, 0, 360); + TGeoRotation* rotate_water_straight_tube_left3 = new TGeoRotation("rotate_water_straight_tube_left3", 0, 0, 0); + TGeoCombiTrans* combtrans_water_straight_tube_side_left3 = new TGeoCombiTrans("combtrans_water_straight_tube_side_left3", +(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Cos((90 - water_pipe_side_angle) * TMath::Pi() / 180.) + water_pipe_straight_tube_side1_length * 2 + water_pipe_side_position_radius, + -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Sin((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - 2 * water_pipe_straight_tube_side2_length - water_pipe_side_position_radius, -water_pipe_straight_tube_side3_length - water_pipe_side_position_radius, rotate_water_straight_tube_left3); + combtrans_water_straight_tube_side_left3->RegisterYourself(); + + TGeoTorus* pipe_side_torus_rigth3 = new TGeoTorus("pipe_side_torus_rigth3", water_pipe_side_position_radius, water_pipe_inner_radius, water_pipe_outer_radius, 0, 90); + TGeoRotation* rotate_water_torus_rigth3 = new TGeoRotation("rotate_water_torus_rigth3", -90, 90, 0); + TGeoCombiTrans* combtrans_water_torus_rigth3 = new TGeoCombiTrans("combtrans_water_torus_rigth3", -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Cos((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - water_pipe_straight_tube_side1_length * 2 - water_pipe_side_position_radius, + -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Sin((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - 2 * water_pipe_straight_tube_side2_length, -water_pipe_side_position_radius, rotate_water_torus_rigth3); + combtrans_water_torus_rigth3->RegisterYourself(); + + TGeoTubeSeg* pipe_straight_tube_rigth3 = new TGeoTubeSeg("pipe_straight_tube_rigth3", water_pipe_inner_radius, water_pipe_outer_radius, water_pipe_straight_tube_side3_length, 0, 360); + TGeoRotation* rotate_water_straight_tube_rigth3 = new TGeoRotation("rotate_water_straight_tube_rigth3", 0, 0, 0); + TGeoCombiTrans* combtrans_water_straight_tube_side_rigth3 = new TGeoCombiTrans("combtrans_water_straight_tube_side_rigth3", -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Cos((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - water_pipe_straight_tube_side1_length * 2 - water_pipe_side_position_radius, + -(water_pipe_main_position_radius + water_pipe_side_position_radius) * TMath::Sin((90 - water_pipe_side_angle) * TMath::Pi() / 180.) - 2 * water_pipe_straight_tube_side2_length - water_pipe_side_position_radius, -water_pipe_straight_tube_side3_length - water_pipe_side_position_radius, rotate_water_straight_tube_rigth3); + combtrans_water_straight_tube_side_rigth3->RegisterYourself(); + + TGeoCompositeShape* water_pipe_toPatchPanel = new TGeoCompositeShape("water_pipe_toPatchPanel", + "pipe_straight_tube_left3:combtrans_water_straight_tube_side_left3" + " + pipe_side_torus_left3:combtrans_water_torus_left3" + " + pipe_straight_tube_rigth3:combtrans_water_straight_tube_side_rigth3" + " + pipe_side_torus_rigth3:combtrans_water_torus_rigth3"); + TGeoVolume* poly_pipe = new TGeoVolume("poly_pipe_toPatchPanel", water_pipe_toPatchPanel, kMedPolyPipe); + poly_pipe->SetLineColor(kGray); + mHalfPSU->AddNode(poly_pipe, 1, nullptr); + + //================================================== + TGeoCompositeShape* water_pipe_shape = new TGeoCompositeShape("water_pipe_shape", "water_pipe_main_torus + water_pipe_side_torus_left1:trans_water_pipe_side_torus_left1 + water_pipe_side_torus_right1:trans_water_pipe_side_torus_right1" " + water_pipe_straight_tube_side1:combtrans_rotated_water_pipe_straight_tube_side1_left + water_pipe_straight_tube_side1:combtrans_rotated_water_pipe_straight_tube_side1_right" " + water_pipe_side_torus_left2:trans_water_pipe_side_torus_left2 + water_pipe_side_torus_right2:trans_water_pipe_side_torus_right2" - " + water_pipe_straight_tube_side2:combtrans_water_pipe_straight_tube_side_left2 + water_pipe_straight_tube_side2:combtrans_water_pipe_straight_tube_side_right2"); + " + water_pipe_straight_tube_side2:combtrans_water_pipe_straight_tube_side_left2 + water_pipe_straight_tube_side2:combtrans_water_pipe_straight_tube_side_right2" + " + pipe_straight_tube_left3:combtrans_water_straight_tube_side_left3" + " + pipe_side_torus_left3:combtrans_water_torus_left3" + " + pipe_straight_tube_rigth3:combtrans_water_straight_tube_side_rigth3" + " + pipe_side_torus_rigth3:combtrans_water_torus_rigth3"); TGeoVolume* water_pipe = new TGeoVolume("water_pipe", water_pipe_shape, kMedAlu); water_pipe->SetLineColor(kGray); @@ -449,11 +491,22 @@ TGeoVolumeAssembly* PowerSupplyUnit::create() combtrans_water_straight_tube_side_left2->RegisterYourself(); combtrans_water_straight_tube_side_right2->RegisterYourself(); + //============ WATER, Connecting to the Patch Panel =============== + TGeoTorus* water_side_torus_left3 = new TGeoTorus("water_side_torus_left3", water_pipe_side_position_radius, 0, water_pipe_inner_radius, 0, 90); + TGeoTubeSeg* water_straight_tube_left3 = new TGeoTubeSeg("water_straight_tube_left3", 0, water_pipe_inner_radius, water_pipe_straight_tube_side3_length, 0, 360); + TGeoTorus* water_side_torus_rigth3 = new TGeoTorus("water_side_torus_rigth3", water_pipe_side_position_radius, 0, water_pipe_inner_radius, 0, 90); + TGeoTubeSeg* water_straight_tube_rigth3 = new TGeoTubeSeg("water_straight_tube_rigth3", 0, water_pipe_inner_radius, water_pipe_straight_tube_side3_length, 0, 360); + //================================================================== + TGeoCompositeShape* water_shape = new TGeoCompositeShape("water_shape", "water_main_torus + water_side_torus_left1:trans_water_side_torus_left1 + water_side_torus_right1:trans_water_side_torus_right1" " + water_straight_tube_side1:combtrans_rotated_water_straight_tube_side1_left + water_straight_tube_side1:combtrans_rotated_water_straight_tube_side1_right" " + water_side_torus_left2:trans_water_side_torus_left2 + water_side_torus_right2:trans_water_side_torus_right2" - " + water_straight_tube_side2:combtrans_water_straight_tube_side_left2 + water_straight_tube_side2:combtrans_water_straight_tube_side_right2"); + " + water_straight_tube_side2:combtrans_water_straight_tube_side_left2 + water_straight_tube_side2:combtrans_water_straight_tube_side_right2" + " + water_straight_tube_left3:combtrans_water_straight_tube_side_left3" + " + water_side_torus_left3:combtrans_water_torus_left3" + " + water_straight_tube_rigth3:combtrans_water_straight_tube_side_rigth3" + " + water_side_torus_rigth3:combtrans_water_torus_rigth3"); TGeoVolume* water = new TGeoVolume("water", water_shape, kMed_Water); water->SetLineColor(kBlue); diff --git a/Detectors/ITSMFT/MFT/base/src/Segmentation.cxx b/Detectors/ITSMFT/MFT/base/src/Segmentation.cxx index 9da51d9a88b28..2af2722633a4e 100644 --- a/Detectors/ITSMFT/MFT/base/src/Segmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Segmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/base/src/Support.cxx b/Detectors/ITSMFT/MFT/base/src/Support.cxx index 7b7f02ddf6568..21f1ec2e0000e 100644 --- a/Detectors/ITSMFT/MFT/base/src/Support.cxx +++ b/Detectors/ITSMFT/MFT/base/src/Support.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -231,8 +232,8 @@ void Support::initParameters() {2.9, 11.885, th, 0., 0., 0}, {2.9 / 2, .7, th, -12.15, 9.9, 0}, {2.9 / 2, .7, th, 12.15, 9.9, 0}, - {1.3875, 1.45, th, 16.1875, 7.9, 0}, - {1.3875, 1.45, th, -16.1875, 7.9, 0}}; + {1.3875, 1.4, th, 16.1875, 7.9, 0}, + {1.3875, 1.4, th, -16.1875, 7.9, 0}}; // ### halfDisks 01 mDiskBoxCuts[1] = mDiskBoxCuts[0]; diff --git a/Detectors/ITSMFT/MFT/base/src/VSegmentation.cxx b/Detectors/ITSMFT/MFT/base/src/VSegmentation.cxx index 646cdf923b3ac..23d18286eaebb 100644 --- a/Detectors/ITSMFT/MFT/base/src/VSegmentation.cxx +++ b/Detectors/ITSMFT/MFT/base/src/VSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/calibration/CMakeLists.txt b/Detectors/ITSMFT/MFT/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..5bc4321988b94 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MFTCalibration + SOURCES src/NoiseCalibrator.cxx + SOURCES src/NoiseCalibratorSpec.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsMFT O2::MFTBase + O2::DetectorsCalibration + O2::CCDB) + +o2_target_root_dictionary(MFTCalibration + HEADERS include/MFTCalibration/NoiseCalibrator.h + LINKDEF src/MFTCalibrationLinkDef.h) + +o2_add_executable(mft-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/mft-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::MFTCalibration) + diff --git a/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibrator.h b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibrator.h new file mode 100644 index 0000000000000..7bd77d6ea14d3 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibrator.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibrator.h + +#ifndef O2_MFT_NOISECALIBRATOR +#define O2_MFT_NOISECALIBRATOR + +#include <string> + +#include "DataFormatsITSMFT/NoiseMap.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "gsl/span" + +namespace o2 +{ + +namespace itsmft +{ +class Digit; +class ROFRecord; +} // namespace itsmft + +namespace mft +{ + +class NoiseCalibrator +{ + public: + NoiseCalibrator() = default; + NoiseCalibrator(float prob) + { + mProbabilityThreshold = prob; + } + ~NoiseCalibrator() = default; + + void setThreshold(unsigned int t) { mThreshold = t; } + + bool processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::Digit> const& digits, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + bool processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + void finalize(); + + const o2::itsmft::NoiseMap& getNoiseMap() const { return mNoiseMap; } + + private: + o2::itsmft::NoiseMap mNoiseMap{936}; + float mProbabilityThreshold = 1e-6f; + unsigned int mThreshold = 100; + unsigned int mNumberOfStrobes = 0; +}; + +} // namespace mft +} // namespace o2 + +#endif /* O2_MFT_NOISECALIBRATOR */ diff --git a/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibratorSpec.h b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibratorSpec.h new file mode 100644 index 0000000000000..4780a5dadc155 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseCalibratorSpec.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibratorSpec.h + +#ifndef O2_MFT_NOISECALIBRATORSPEC +#define O2_MFT_NOISECALIBRATORSPEC + +#include <string> + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "MFTCalibration/NoiseCalibrator.h" +using CALIBRATOR = o2::mft::NoiseCalibrator; + +//#include "MFTCalibration/NoiseSlotCalibrator.h" //For TimeSlot calibration +//using CALIBRATOR = o2::mft::NoiseSlotCalibrator; + +#include "DataFormatsITSMFT/NoiseMap.h" + +using namespace o2::framework; + +namespace o2 +{ + +namespace mft +{ + +class NoiseCalibratorSpec : public Task +{ + public: + NoiseCalibratorSpec(bool digits = false); + ~NoiseCalibratorSpec() override = default; + + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + + private: + void sendOutput(DataAllocator& output); + o2::itsmft::NoiseMap mNoiseMap{936}; + std::unique_ptr<CALIBRATOR> mCalibrator = nullptr; + std::string mPath; + std::string mMeta; + double mThresh; + int64_t mStart; + int64_t mEnd; + bool mDigits = false; +}; + +/// create a processor spec +/// run MFT noise calibration +DataProcessorSpec getNoiseCalibratorSpec(bool useDigits); + +} // namespace mft +} // namespace o2 + +#endif /* O2_MFT_NOISECALIBRATORSPEC */ diff --git a/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h new file mode 100644 index 0000000000000..30393a8d8d0c5 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseSlotCalibrator.h + +#ifndef O2_MFT_NOISESLOTCALIBRATOR +#define O2_MFT_NOISESLOTCALIBRATOR + +#include <string> + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" + +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "gsl/span" + +namespace o2 +{ + +namespace itsmft +{ +class ROFRecord; +} // namespace itsmft + +namespace mft +{ + +class NoiseSlotCalibrator : public o2::calibration::TimeSlotCalibration<o2::itsmft::CompClusterExt, o2::itsmft::NoiseMap> +{ + using Slot = calibration::TimeSlot<o2::itsmft::NoiseMap>; + + public: + NoiseSlotCalibrator() { setUpdateAtTheEndOfRunOnly(); } + NoiseSlotCalibrator(float prob) + { + mProbabilityThreshold = prob; + setUpdateAtTheEndOfRunOnly(); + setSlotLength(std::numeric_limits<TFType>::max); + } + ~NoiseSlotCalibrator() final = default; + + void setThreshold(unsigned int t) { mThreshold = t; } + + bool processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::Digit> const& digits, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + bool processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs); + + void finalize() + { + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + auto& slot = getSlots().back(); + slot.getContainer()->applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); + } + + const o2::itsmft::NoiseMap& getNoiseMap(long& start, long& end) + { + const auto& slot = getSlots().back(); + start = slot.getTFStart(); + end = slot.getTFEnd(); + return *(slot.getContainer()); + } + + // Functions overloaded from the calibration framework + bool process(calibration::TFType tf, const gsl::span<const o2::itsmft::CompClusterExt> data) final; + + // Functions required by the calibration framework + void initOutput() final {} + Slot& emplaceNewSlot(bool, calibration::TFType, calibration::TFType) final; + void finalizeSlot(Slot& slot) final; + bool hasEnoughData(const Slot& slot) const final; + + private: + float mProbabilityThreshold = 1e-6f; + unsigned int mThreshold = 100; + unsigned int mNumberOfStrobes = 0; +}; + +} // namespace mft +} // namespace o2 + +#endif /* O2_MFT_NOISESLOTCALIBRATOR */ diff --git a/Detectors/ITSMFT/MFT/calibration/src/MFTCalibrationLinkDef.h b/Detectors/ITSMFT/MFT/calibration/src/MFTCalibrationLinkDef.h new file mode 100644 index 0000000000000..4d012b61dd642 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/src/MFTCalibrationLinkDef.h @@ -0,0 +1,20 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::mft::NoiseCalibrator + ; + +#endif diff --git a/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibrator.cxx b/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibrator.cxx new file mode 100644 index 0000000000000..0c0aaf59101e8 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibrator.cxx @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibrator.cxx + +#include "MFTCalibration/NoiseCalibrator.h" + +#include "FairLogger.h" +#include "TFile.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +namespace o2 +{ +namespace mft +{ +bool NoiseCalibrator::processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::Digit> const& digits, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + static int nTF = 0; + LOG(INFO) << "Processing TF# " << nTF++; + + for (const auto& rof : rofs) { + auto digitsInFrame = rof.getROFData(digits); + for (const auto& d : digitsInFrame) { + auto id = d.getChipIndex(); + auto row = d.getRow(); + auto col = d.getColumn(); + + mNoiseMap.increaseNoiseCount(id, row, col); + } + } + mNumberOfStrobes += rofs.size(); + return (mNumberOfStrobes * mProbabilityThreshold >= mThreshold) ? true : false; +} + +bool NoiseCalibrator::processTimeFrame(calibration::TFType tf, + gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + static int nTF = 0; + LOG(INFO) << "Processing TF# " << nTF++; + + auto pattIt = patterns.begin(); + for (const auto& rof : rofs) { + auto clustersInFrame = rof.getROFData(clusters); + for (const auto& c : clustersInFrame) { + if (c.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) { + // For the noise calibration, we use "pass1" clusters... + continue; + } + o2::itsmft::ClusterPattern patt(pattIt); + + auto id = c.getSensorID(); + auto row = c.getRow(); + auto col = c.getCol(); + auto colSpan = patt.getColumnSpan(); + auto rowSpan = patt.getRowSpan(); + + // Fast 1-pixel calibration + if ((rowSpan == 1) && (colSpan == 1)) { + mNoiseMap.increaseNoiseCount(id, row, col); + continue; + } + + // All-pixel calibration + auto nBits = rowSpan * colSpan; + int ic = 0, ir = 0; + for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { + unsigned char tempChar = patt.getByte(i); + int s = 128; // 0b10000000 + while (s > 0) { + if ((tempChar & s) != 0) { + mNoiseMap.increaseNoiseCount(id, row + ir, col + ic); + } + ic++; + s >>= 1; + if ((ir + 1) * ic == nBits) { + break; + } + if (ic == colSpan) { + ic = 0; + ir++; + } + } + if ((ir + 1) * ic == nBits) { + break; + } + } + } + } + mNumberOfStrobes += rofs.size(); + return (mNumberOfStrobes * mProbabilityThreshold >= mThreshold) ? true : false; +} + +void NoiseCalibrator::finalize() +{ + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + mNoiseMap.applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); +} + +} // namespace mft +} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibratorSpec.cxx b/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibratorSpec.cxx new file mode 100644 index 0000000000000..98cf7853c8818 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/src/NoiseCalibratorSpec.cxx @@ -0,0 +1,163 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseCalibratorSpec.cxx + +#include "CCDB/CcdbApi.h" +#include "CommonUtils/StringUtils.h" +#include "DetectorsCalibration/Utils.h" +#include "MFTCalibration/NoiseCalibratorSpec.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +#include "FairLogger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" + +using namespace o2::framework; +using namespace o2::utils; + +namespace o2 +{ +namespace mft +{ + +NoiseCalibratorSpec::NoiseCalibratorSpec(bool useDigits) + : mDigits(useDigits) +{ +} + +void NoiseCalibratorSpec::init(InitContext& ic) +{ + auto probT = ic.options().get<float>("prob-threshold"); + LOG(INFO) << "Setting the probability threshold to " << probT; + + mPath = ic.options().get<std::string>("path"); + mMeta = ic.options().get<std::string>("meta"); + mStart = ic.options().get<int64_t>("tstart"); + mEnd = ic.options().get<int64_t>("tend"); + + mCalibrator = std::make_unique<CALIBRATOR>(probT); +} + +void NoiseCalibratorSpec::run(ProcessingContext& pc) +{ + if (mDigits) { + const auto digits = pc.inputs().get<gsl::span<o2::itsmft::Digit>>("digits"); + const auto rofs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("digitsROF"); + const auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("digitsROF").header)->startTime; + + if (mCalibrator->processTimeFrame(tfcounter, digits, rofs)) { + LOG(INFO) << "Minimum number of noise counts has been reached !"; + sendOutput(pc.outputs()); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + } + } else { + const auto compClusters = pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("compClusters"); + gsl::span<const unsigned char> patterns = pc.inputs().get<gsl::span<unsigned char>>("patterns"); + const auto rofs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROframes"); + const auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("ROframes").header)->startTime; + + if (mCalibrator->processTimeFrame(tfcounter, compClusters, patterns, rofs)) { + LOG(INFO) << "Minimum number of noise counts has been reached !"; + sendOutput(pc.outputs()); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + } + } +} + +void NoiseCalibratorSpec::sendOutput(DataAllocator& output) +{ + mCalibrator->finalize(); + + long tstart = mStart; + if (tstart == -1) { + tstart = o2::ccdb::getCurrentTimestamp(); + } + long tend = mEnd; + if (tend == -1) { + constexpr long SECONDSPERYEAR = 365 * 24 * 60 * 60; + tend = o2::ccdb::getFutureTimestamp(SECONDSPERYEAR); + } + + std::map<std::string, std::string> meta; + auto toKeyValPairs = [&meta](std::vector<std::string> const& tokens) { + for (auto& token : tokens) { + auto keyval = Str::tokenize(token, '=', false); + if (keyval.size() != 2) { + LOG(ERROR) << "Illegal command-line key/value string: " << token; + continue; + } + Str::trim(keyval[1]); + meta[keyval[0]] = keyval[1]; + } + }; + toKeyValPairs(Str::tokenize(mMeta, ';', true)); + + long startTF, endTF; + + const auto& payload = mCalibrator->getNoiseMap(); + // const auto& payload = mCalibrator->getNoiseMap(starTF, endTF); //For TimeSlot calibration + + o2::ccdb::CcdbObjectInfo info(mPath, "NoiseMap", "noise.root", meta, tstart, tend); + auto flName = o2::ccdb::CcdbApi::generateFileName("noise"); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + info.setFileName(flName); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + using clbUtils = o2::calibration::Utils; + output.snapshot(Output{clbUtils::gDataOriginCDBPayload, "MFT_NoiseMap", 0}, *image.get()); + output.snapshot(Output{clbUtils::gDataOriginCDBWrapper, "MFT_NoiseMap", 0}, info); +} + +void NoiseCalibratorSpec::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + sendOutput(ec.outputs()); +} + +DataProcessorSpec getNoiseCalibratorSpec(bool useDigits) +{ + o2::header::DataOrigin detOrig = o2::header::gDataOriginMFT; + std::vector<InputSpec> inputs; + if (useDigits) { + inputs.emplace_back("digits", detOrig, "DIGITS", 0, Lifetime::Timeframe); + inputs.emplace_back("digitsROF", detOrig, "DIGITSROF", 0, Lifetime::Timeframe); + } else { + inputs.emplace_back("compClusters", detOrig, "COMPCLUSTERS", 0, Lifetime::Timeframe); + inputs.emplace_back("patterns", detOrig, "PATTERNS", 0, Lifetime::Timeframe); + inputs.emplace_back("ROframes", detOrig, "CLUSTERSROF", 0, Lifetime::Timeframe); + } + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "MFT_NoiseMap"}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "MFT_NoiseMap"}); + + return DataProcessorSpec{ + "mft-noise-calibrator", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<NoiseCalibratorSpec>(useDigits)}, + Options{ + {"prob-threshold", VariantType::Float, 1.e-6f, {"Probability threshold for noisy pixels"}}, + {"tstart", VariantType::Int64, -1ll, {"Start of validity timestamp"}}, + {"tend", VariantType::Int64, -1ll, {"End of validity timestamp"}}, + {"path", VariantType::String, "/MFT/Calib/NoiseMap", {"Path to write to in CCDB"}}, + {"meta", VariantType::String, "", {"meta data to write in CCDB"}}, + {"hb-per-tf", VariantType::Int, 256, {"Number of HBF per TF"}}}}; +} + +} // namespace mft +} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx b/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx new file mode 100644 index 0000000000000..0294878838e8e --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx @@ -0,0 +1,145 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file NoiseSlotCalibrator.cxx + +#include "MFTCalibration/NoiseSlotCalibrator.h" + +#include "FairLogger.h" +#include "TFile.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +namespace o2 +{ +using Slot = calibration::TimeSlot<o2::itsmft::NoiseMap>; + +namespace mft +{ +bool NoiseSlotCalibrator::processTimeFrame(calibration::TFType nTF, + gsl::span<const o2::itsmft::Digit> const& digits, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + LOG(INFO) << "Processing TF# " << nTF; + + auto& slotTF = getSlotForTF(nTF); + auto& noiseMap = *(slotTF.getContainer()); + + for (const auto& rof : rofs) { + auto digitsInFrame = rof.getROFData(digits); + for (const auto& d : digitsInFrame) { + auto id = d.getChipIndex(); + auto row = d.getRow(); + auto col = d.getColumn(); + + noiseMap.increaseNoiseCount(id, row, col); + } + } + + mNumberOfStrobes += rofs.size(); + return hasEnoughData(slotTF); +} + +bool NoiseSlotCalibrator::processTimeFrame(calibration::TFType nTF, + gsl::span<const o2::itsmft::CompClusterExt> const& clusters, + gsl::span<const unsigned char> const& patterns, + gsl::span<const o2::itsmft::ROFRecord> const& rofs) +{ + LOG(INFO) << "Processing TF# " << nTF; + + auto& slotTF = getSlotForTF(nTF); + auto& noiseMap = *(slotTF.getContainer()); + + auto pattIt = patterns.begin(); + for (const auto& rof : rofs) { + auto clustersInFrame = rof.getROFData(clusters); + for (const auto& c : clustersInFrame) { + if (c.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) { + // For the noise calibration, we use "pass1" clusters... + continue; + } + o2::itsmft::ClusterPattern patt(pattIt); + + auto id = c.getSensorID(); + auto row = c.getRow(); + auto col = c.getCol(); + auto colSpan = patt.getColumnSpan(); + auto rowSpan = patt.getRowSpan(); + + // Fast 1-pixel calibration + if ((rowSpan == 1) && (colSpan == 1)) { + noiseMap.increaseNoiseCount(id, row, col); + continue; + } + + // All-pixel calibration + auto nBits = rowSpan * colSpan; + int ic = 0, ir = 0; + for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { + unsigned char tempChar = patt.getByte(i); + int s = 128; // 0b10000000 + while (s > 0) { + if ((tempChar & s) != 0) { + noiseMap.increaseNoiseCount(id, row + ir, col + ic); + } + ic++; + s >>= 1; + if ((ir + 1) * ic == nBits) { + break; + } + if (ic == colSpan) { + ic = 0; + ir++; + } + } + if ((ir + 1) * ic == nBits) { + break; + } + } + } + } + + mNumberOfStrobes += rofs.size(); + return hasEnoughData(slotTF); +} + +// Functions overloaded from the calibration framework +bool NoiseSlotCalibrator::process(calibration::TFType tf, const gsl::span<const o2::itsmft::CompClusterExt> data) +{ + LOG(WARNING) << "Only 1-pix noise calibraton is possible !"; + return calibration::TimeSlotCalibration<o2::itsmft::CompClusterExt, o2::itsmft::NoiseMap>::process(tf, data); +} + +// Functions required by the calibration framework + +Slot& NoiseSlotCalibrator::emplaceNewSlot(bool front, calibration::TFType tstart, calibration::TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<o2::itsmft::NoiseMap>(936)); + return slot; +} + +bool NoiseSlotCalibrator::hasEnoughData(const Slot&) const +{ + return (mNumberOfStrobes * mProbabilityThreshold >= mThreshold) ? true : false; +} + +void NoiseSlotCalibrator::finalizeSlot(Slot& slot) +{ + LOG(INFO) << "Number of processed strobes is " << mNumberOfStrobes; + o2::itsmft::NoiseMap* map = slot.getContainer(); + map->applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); +} + +} // namespace mft +} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/calibration/testWorkflow/README.md b/Detectors/ITSMFT/MFT/calibration/testWorkflow/README.md new file mode 100644 index 0000000000000..39319c968878c --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/testWorkflow/README.md @@ -0,0 +1,27 @@ + +# MFT calibration workflows + +This will read data from raw data file, produces clusters and write a noise map to a local CCDB running on port 8080: + +```shell +o2-raw-file-reader-workflow -b --delay ${DELAY_S} --nocheck-missing-stop --nocheck-starts-with-tf --nocheck-packet-increment --nocheck-hbf-jump --nocheck-hbf-per-tf --detect-tf0 --configKeyValues "HBFUtils.nHBFPerTF=${HBF_PER_TF}" --input-conf ${CFGFILE} | \ +o2-itsmft-stf-decoder-workflow -b --nthreads ${N_THREAD} --runmft --decoder-verbosity ${DECODER_VERBOSITY} | \ +o2-calibration-mft-calib-workflow --path "/MFT/test_CCDB/" --meta "Description=MFT;Author=Maurice Coquet;Uploader=Maurice Coquet" -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:8080" -b +``` +The same as before but uses digits instead of clusters: +```shell +o2-raw-file-reader-workflow -b --delay ${DELAY_S} --nocheck-missing-stop --nocheck-starts-with-tf --nocheck-packet-increment --nocheck-hbf-jump --nocheck-hbf-per-tf --detect-tf0 --configKeyValues "HBFUtils.nHBFPerTF=${HBF_PER_TF}" --input-conf ${CFGFILE} | \ +o2-itsmft-stf-decoder-workflow -b --nthreads ${N_THREAD} --runmft --digits --no-clusters --no-cluster-patterns --decoder-verbosity ${DECODER_VERBOSITY} | \ +o2-calibration-mft-calib-workflow --useDigits --path "/MFT/test_CCDB/" --meta "Description=MFT;Author=Maurice Coquet;Uploader=Maurice Coquet" -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:8080" -b +``` + +Additional options to the mft-calib DPL : +``` + --path "/path/in/CCDB/" : defines path to write to in CCDB (default : "/MFT/Calib/NoiseMap") + --meta "Description=...;Author=...;Uploader=..." : add meta data to the input in the CCDB + --tstart <start timestamp> : defines the start of validity timestamp of the file written in the CCDB (default is -1 : current timestamp) + --tend <end timestamp> : defines the start of validity timestamp of the file written in the CCDB (defult is -1 : one year from the current timestamp) + --prob-threshold <proba> : defined probability threshold for noisy pixels (default : 3e-6) +``` diff --git a/Detectors/ITSMFT/MFT/calibration/testWorkflow/mft-calib-workflow.cxx b/Detectors/ITSMFT/MFT/calibration/testWorkflow/mft-calib-workflow.cxx new file mode 100644 index 0000000000000..cc78fa200d794 --- /dev/null +++ b/Detectors/ITSMFT/MFT/calibration/testWorkflow/mft-calib-workflow.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"useDigits", VariantType::Bool, false, {"Use decoded digits"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" +#include "MFTCalibration/NoiseCalibratorSpec.h" +#include "MFTCalibration/NoiseCalibrator.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + auto useDigits = cfgc.options().get<bool>("useDigits"); + + LOG(INFO) << "MFT calibration workflow options"; + LOG(INFO) << "Use Digits: " << useDigits; + + specs.emplace_back(o2::mft::getNoiseCalibratorSpec(useDigits)); + + return specs; +} diff --git a/Detectors/ITSMFT/MFT/condition/CMakeLists.txt b/Detectors/ITSMFT/MFT/condition/CMakeLists.txt new file mode 100644 index 0000000000000..0b133d14e8743 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_library(MFTCondition + SOURCES src/MFTDCSProcessor.cxx + src/DCSNameResolver.cxx + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::DetectorsCalibration + O2::DetectorsDCS + Microsoft.GSL::GSL) + +o2_target_root_dictionary(MFTCondition + HEADERS include/MFTCondition/MFTDCSProcessor.h + include/MFTCondition/DCSNameResolver.h + LINKDEF src/MFTConditionLinkDef.h) + +o2_add_executable(mft-dcs-sim-workflow + COMPONENT_NAME condition + SOURCES testWorkflow/mft-dcs-sim-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) + +o2_add_executable(mft-dcs-workflow + COMPONENT_NAME condition + SOURCES testWorkflow/mft-dcs-data-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::MFTCondition + O2::DetectorsDCS) + +add_subdirectory(macros) diff --git a/Detectors/ITSMFT/MFT/condition/README.md b/Detectors/ITSMFT/MFT/condition/README.md new file mode 100644 index 0000000000000..0325b7ae48e7c --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/README.md @@ -0,0 +1,4 @@ +<!-- doxy +\page refDetectorsMUONMFTConditions Conditions +/doxy --> +# MFT Conditions diff --git a/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSNameResolver.h b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSNameResolver.h new file mode 100644 index 0000000000000..aabd84b37045c --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSNameResolver.h @@ -0,0 +1,239 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MFT_DATAPROCESSOR_H +#define O2_MFT_DATAPROCESSOR_H + +/// @file DCSMFTDataProcessorSpec.h +/// @brief MFT Processor for DCS Data Points + +#include <TString.h> +#include <unordered_map> +#include <iostream> + +namespace o2 +{ +namespace mft +{ + +class DCSNameResolver +{ + + public: + void init() + { + + mDictAlias2Full.clear(); + mDictFull2Alias.clear(); + + for (int iH = 0; iH < 2; ++iH) { + for (int iD = 0; iD < 5; ++iD) { + for (int iF = 0; iF < 2; ++iF) { + for (int iZ = 0; iZ < 4; ++iZ) { + + mDictFull2Alias.emplace(Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.Analog", iH, iD, iF, iZ), Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/Analog", iH, iD, iF, iZ)); + mDictFull2Alias.emplace(Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.BackBias", iH, iD, iF, iZ), Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/BackBias", iH, iD, iF, iZ)); + mDictFull2Alias.emplace(Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.Digital", iH, iD, iF, iZ), Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/Digital", iH, iD, iF, iZ)); + mDictFull2Alias.emplace(Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Voltage.BackBias", iH, iD, iF, iZ), Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Voltage/BackBias", iH, iD, iF, iZ)); + + mDictAlias2Full.emplace(Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/Analog", iH, iD, iF, iZ), Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.Analog", iH, iD, iF, iZ)); + mDictAlias2Full.emplace(Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/BackBias", iH, iD, iF, iZ), Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.BackBias", iH, iD, iF, iZ)); + mDictAlias2Full.emplace(Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Current/Digital", iH, iD, iF, iZ), Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Current.Digital", iH, iD, iF, iZ)); + mDictAlias2Full.emplace(Form("MFT_PSU_ZONE/H%d/D%d/F%d/Z%d/Voltage/BackBias", iH, iD, iF, iZ), Form("mft_main:MFT_PSU_Zone/H%dD%dF%dZ%d.Monitoring.Voltage.BackBias", iH, iD, iF, iZ)); + } + } + } + } + + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel008.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel009.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel010.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel011.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D0/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D1/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel008.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel009.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel010.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D2/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel011.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D3/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H0/D4/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel008.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel009.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel010.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel011.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F0/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F0/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F0/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F0/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D0/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D1/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel007.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel008.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel009.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel010.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D2/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel011.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel000.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel001.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel002.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D3/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel003.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F1/Z0/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel004.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F1/Z1/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel005.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F1/Z2/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel006.actual.iMon"); + mDictAlias2Full.emplace("MFT_RU_LV/H1/D4/F1/Z3/iMon", "mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel007.actual.iMon"); + + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel000.actual.iMon", "MFT_RU_LV/H0/D0/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel001.actual.iMon", "MFT_RU_LV/H0/D0/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel002.actual.iMon", "MFT_RU_LV/H0/D0/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel003.actual.iMon", "MFT_RU_LV/H0/D0/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel004.actual.iMon", "MFT_RU_LV/H0/D1/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel005.actual.iMon", "MFT_RU_LV/H0/D1/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel006.actual.iMon", "MFT_RU_LV/H0/D1/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel007.actual.iMon", "MFT_RU_LV/H0/D1/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel008.actual.iMon", "MFT_RU_LV/H0/D2/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel009.actual.iMon", "MFT_RU_LV/H0/D2/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel010.actual.iMon", "MFT_RU_LV/H0/D2/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard00/channel011.actual.iMon", "MFT_RU_LV/H0/D2/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel000.actual.iMon", "MFT_RU_LV/H0/D3/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel001.actual.iMon", "MFT_RU_LV/H0/D3/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel002.actual.iMon", "MFT_RU_LV/H0/D3/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel003.actual.iMon", "MFT_RU_LV/H0/D3/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel004.actual.iMon", "MFT_RU_LV/H0/D4/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel005.actual.iMon", "MFT_RU_LV/H0/D4/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel006.actual.iMon", "MFT_RU_LV/H0/D4/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard05/channel007.actual.iMon", "MFT_RU_LV/H0/D4/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel000.actual.iMon", "MFT_RU_LV/H0/D0/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel001.actual.iMon", "MFT_RU_LV/H0/D0/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel002.actual.iMon", "MFT_RU_LV/H0/D0/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel003.actual.iMon", "MFT_RU_LV/H0/D0/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel004.actual.iMon", "MFT_RU_LV/H0/D1/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel005.actual.iMon", "MFT_RU_LV/H0/D1/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel006.actual.iMon", "MFT_RU_LV/H0/D1/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel007.actual.iMon", "MFT_RU_LV/H0/D1/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel008.actual.iMon", "MFT_RU_LV/H0/D2/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel009.actual.iMon", "MFT_RU_LV/H0/D2/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel010.actual.iMon", "MFT_RU_LV/H0/D2/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard10/channel011.actual.iMon", "MFT_RU_LV/H0/D2/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel000.actual.iMon", "MFT_RU_LV/H0/D3/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel001.actual.iMon", "MFT_RU_LV/H0/D3/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel002.actual.iMon", "MFT_RU_LV/H0/D3/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel003.actual.iMon", "MFT_RU_LV/H0/D3/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel004.actual.iMon", "MFT_RU_LV/H0/D4/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel005.actual.iMon", "MFT_RU_LV/H0/D4/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel006.actual.iMon", "MFT_RU_LV/H0/D4/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate0/easyBoard15/channel007.actual.iMon", "MFT_RU_LV/H0/D4/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel000.actual.iMon", "MFT_RU_LV/H1/D0/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel001.actual.iMon", "MFT_RU_LV/H1/D0/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel002.actual.iMon", "MFT_RU_LV/H1/D0/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel003.actual.iMon", "MFT_RU_LV/H1/D0/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel004.actual.iMon", "MFT_RU_LV/H1/D1/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel005.actual.iMon", "MFT_RU_LV/H1/D1/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel006.actual.iMon", "MFT_RU_LV/H1/D1/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel007.actual.iMon", "MFT_RU_LV/H1/D1/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel008.actual.iMon", "MFT_RU_LV/H1/D2/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel009.actual.iMon", "MFT_RU_LV/H1/D2/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel010.actual.iMon", "MFT_RU_LV/H1/D2/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard00/channel011.actual.iMon", "MFT_RU_LV/H1/D2/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel000.actual.iMon", "MFT_RU_LV/H1/D3/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel001.actual.iMon", "MFT_RU_LV/H1/D3/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel002.actual.iMon", "MFT_RU_LV/H1/D3/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel003.actual.iMon", "MFT_RU_LV/H1/D3/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel004.actual.iMon", "MFT_RU_LV/H1/D4/F0/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel005.actual.iMon", "MFT_RU_LV/H1/D4/F0/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel006.actual.iMon", "MFT_RU_LV/H1/D4/F0/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard05/channel007.actual.iMon", "MFT_RU_LV/H1/D4/F0/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel000.actual.iMon", "MFT_RU_LV/H1/D0/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel001.actual.iMon", "MFT_RU_LV/H1/D0/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel002.actual.iMon", "MFT_RU_LV/H1/D0/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel003.actual.iMon", "MFT_RU_LV/H1/D0/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel004.actual.iMon", "MFT_RU_LV/H1/D1/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel005.actual.iMon", "MFT_RU_LV/H1/D1/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel006.actual.iMon", "MFT_RU_LV/H1/D1/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel007.actual.iMon", "MFT_RU_LV/H1/D1/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel008.actual.iMon", "MFT_RU_LV/H1/D2/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel009.actual.iMon", "MFT_RU_LV/H1/D2/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel010.actual.iMon", "MFT_RU_LV/H1/D2/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard10/channel011.actual.iMon", "MFT_RU_LV/H1/D2/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel000.actual.iMon", "MFT_RU_LV/H1/D3/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel001.actual.iMon", "MFT_RU_LV/H1/D3/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel002.actual.iMon", "MFT_RU_LV/H1/D3/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel003.actual.iMon", "MFT_RU_LV/H1/D3/F1/Z3/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel004.actual.iMon", "MFT_RU_LV/H1/D4/F1/Z0/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel005.actual.iMon", "MFT_RU_LV/H1/D4/F1/Z1/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel006.actual.iMon", "MFT_RU_LV/H1/D4/F1/Z2/iMon"); + mDictFull2Alias.emplace("mft_infra:CAEN/alimftcae001/branchController11/easyCrate1/easyBoard15/channel007.actual.iMon", "MFT_RU_LV/H1/D4/F1/Z3/iMon"); + } + + std::string& getFullName(const std::string& alias) + { + return mDictAlias2Full[alias]; + } + + std::string& getAlias(const std::string& full) + { + return mDictFull2Alias[full]; + } + + private: + std::unordered_map<std::string, std::string> mDictAlias2Full; + std::unordered_map<std::string, std::string> mDictFull2Alias; + + ClassDefNV(DCSNameResolver, 1); + +}; // end class +} // namespace mft +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/MFT/condition/include/MFTCondition/MFTDCSProcessor.h b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/MFTDCSProcessor.h new file mode 100644 index 0000000000000..6541165574016 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/MFTDCSProcessor.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTOR_MFTDCSPROCESSOR_H_ +#define DETECTOR_MFTDCSPROCESSOR_H_ + +#include <memory> +#include <Rtypes.h> +#include <unordered_map> +#include <deque> +#include <numeric> +#include "Framework/Logger.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DeliveryType.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include <gsl/gsl> + +/// @brief Class to process DCS data points + +namespace o2 +{ +namespace mft +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; + +struct MFTDCSinfo { + std::pair<uint64_t, double> firstValue; // first value seen by the MFT DCS processor + std::pair<uint64_t, double> lastValue; // last value seen by the MFT DCS processor + std::pair<uint64_t, double> midValue; // mid value seen by the MFT DCS processor + std::pair<uint64_t, double> maxChange; // maximum variation seen by the MFT DCS processor + MFTDCSinfo() + { + firstValue = std::make_pair(0, -999999999); + lastValue = std::make_pair(0, -999999999); + midValue = std::make_pair(0, -999999999); + maxChange = std::make_pair(0, -999999999); + } + void makeEmpty() + { + firstValue.first = lastValue.first = midValue.first = maxChange.first = 0; + firstValue.second = lastValue.second = midValue.second = maxChange.second = -999999999; + } + void print() const; + + ClassDefNV(MFTDCSinfo, 1); +}; + +class MFTDCSProcessor +{ + + public: + using TFType = uint64_t; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + using DQDoubles = std::deque<double>; + + MFTDCSProcessor() = default; + ~MFTDCSProcessor() = default; + + void init(const std::vector<DPID>& pids); + + int process(const gsl::span<const DPCOM> dps); + int processDP(const DPCOM& dpcom); + + void updateDPsCCDB(); + + const CcdbObjectInfo& getccdbDPsInfo() const { return mccdbDPsInfo; } + CcdbObjectInfo& getccdbDPsInfo() { return mccdbDPsInfo; } + const std::unordered_map<DPID, MFTDCSinfo>& getMFTDPsInfo() const { return mMFTDCS; } + + template <typename T> + void prepareCCDBobjectInfo(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, const std::map<std::string, std::string>& md); + + void setTF(TFType tf) { mTF = tf; } + void useVerboseMode() { mVerbose = true; } + + void clearDPsinfo() + { + mDpsdoublesmap.clear(); + mMFTDCS.clear(); + } + + private: + std::unordered_map<DPID, MFTDCSinfo> mMFTDCS; // this is the object that will go to the CCDB + std::unordered_map<DPID, bool> mPids; // contains all PIDs for the processor, the bool + // will be true if the DP was processed at least once + std::unordered_map<DPID, std::vector<DPVAL>> mDpsdoublesmap; // this is the map that will hold the DPs for the + // double type (voltages and currents) + CcdbObjectInfo mccdbDPsInfo; + + TFType mStartTF; // TF index for processing of first processed TF, used to store CCDB object + TFType mTF = 0; // TF index for processing, used to store CCDB object + bool mStartTFset = false; + + bool mVerbose = false; + + ClassDefNV(MFTDCSProcessor, 0); +}; + +template <typename T> +void MFTDCSProcessor::prepareCCDBobjectInfo(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, const std::map<std::string, std::string>& md) +{ + + // prepare all info to be sent to CCDB for object obj + auto clName = o2::utils::MemFileHelper::getClassName(obj); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + info.setPath(path); + info.setObjectType(clName); + info.setFileName(flName); + info.setStartValidityTimestamp(tf); + info.setEndValidityTimestamp(99999999999999); + info.setMetaData(md); +} + +} // namespace mft +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/MFT/condition/macros/CMakeLists.txt b/Detectors/ITSMFT/MFT/condition/macros/CMakeLists.txt new file mode 100644 index 0000000000000..77800b1f5b64c --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/macros/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro( + readMFTDCSentries.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB O2::MFTCondition) + +o2_add_test_root_macro( + makeMFTCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +install( + FILES makeMFTCCDBEntryForDCS.C + readMFTDCSentries.C + DESTINATION share/macro/) diff --git a/Detectors/ITSMFT/MFT/condition/macros/makeMFTCCDBEntryForDCS.C b/Detectors/ITSMFT/MFT/condition/macros/makeMFTCCDBEntryForDCS.C new file mode 100644 index 0000000000000..a4c6f147a6d08 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/macros/makeMFTCCDBEntryForDCS.C @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include <unordered_map> +#include <chrono> + +using DPID = o2::dcs::DataPointIdentifier; + +int makeMFTCCDBEntryForDCS(const std::string url = "http://ccdb-test.cern.ch:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for TOF with the configuration for DCS + std::unordered_map<DPID, std::string> dpid2DataDesc; + + std::vector<std::string> aliases = {"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Analog", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/BackBias", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Digital", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Voltage/BackBias", + "MFT_RU_LV/H0/D0/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D1/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D2/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D3/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D4/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D0/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D1/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D2/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D3/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D4/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D0/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D1/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D2/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D3/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D4/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D0/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D1/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D2/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D3/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D4/F1/Z[0..3]/iMon"}; + + std::vector<std::string> expaliases = o2::dcs::expandAliases(aliases); + + DPID dpidtmp; + for (size_t i = 0; i < expaliases.size(); ++i) { + DPID::FILL(dpidtmp, expaliases[i], o2::dcs::DeliveryType::RAW_DOUBLE); + dpid2DataDesc[dpidtmp] = "MFTDATAPOINTS"; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> md; + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc, "MFT/Config/DCSDPconfig", md, ts); + + return 0; +} diff --git a/Detectors/ITSMFT/MFT/condition/macros/readMFTDCSentries.C b/Detectors/ITSMFT/MFT/condition/macros/readMFTDCSentries.C new file mode 100644 index 0000000000000..0d72820376048 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/macros/readMFTDCSentries.C @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// macro to read the TOF DCS information from CCDB +// default ts is very big: Saturday, November 20, 2286 5:46:39 PM + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "MFTCondition/DCSNameResolver.h" +#include "MFTCondition/MFTDCSProcessor.h" +#include <string> +#include <unordered_map> +#include <chrono> +#include <bitset> +#endif + +void readMFTDCSentries(long ts = 9999999999000, const char* ccdb = "http://ccdb-test.cern.ch:8080") +{ + + o2::mft::DCSNameResolver namer; + namer.init(); + + o2::ccdb::CcdbApi api; + api.init(ccdb); // or http://ccdb-test.cern.ch:8080 + std::map<std::string, std::string> metadata; + if (ts == 9999999999000) { + ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + std::unordered_map<o2::dcs::DataPointIdentifier, o2::mft::MFTDCSinfo>* m = api.retrieveFromTFileAny<std::unordered_map<o2::dcs::DataPointIdentifier, o2::mft::MFTDCSinfo>>("MFT/Condition/DCSDPs", metadata, ts); + std::cout << "size of map = " << m->size() << std::endl; + for (auto& i : *m) { + std::cout << " PID = " << i.first.get_alias() << " (alias) ======> " << namer.getFullName(string(i.first.get_alias())) << " (full name)" << std::endl; + i.second.print(); + } + + return; +} diff --git a/Detectors/ITSMFT/MFT/condition/src/DCSNameResolver.cxx b/Detectors/ITSMFT/MFT/condition/src/DCSNameResolver.cxx new file mode 100644 index 0000000000000..1ffaf78d6da30 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/src/DCSNameResolver.cxx @@ -0,0 +1,12 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MFTCondition/DCSNameResolver.h" diff --git a/Detectors/ITSMFT/MFT/condition/src/MFTConditionLinkDef.h b/Detectors/ITSMFT/MFT/condition/src/MFTConditionLinkDef.h new file mode 100644 index 0000000000000..a5819a37c9891 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/src/MFTConditionLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ struct o2::mft::MFTDCSinfo + ; +#pragma link C++ class o2::mft::DCSNameResolver + ; +#pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, o2::mft::MFTDCSinfo> + ; + +#endif diff --git a/Detectors/ITSMFT/MFT/condition/src/MFTDCSProcessor.cxx b/Detectors/ITSMFT/MFT/condition/src/MFTDCSProcessor.cxx new file mode 100644 index 0000000000000..890c073f9ab1a --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/src/MFTDCSProcessor.cxx @@ -0,0 +1,220 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <MFTCondition/MFTDCSProcessor.h> +#include "Rtypes.h" +#include <deque> +#include <string> +#include <algorithm> +#include <iterator> +#include <cstring> +#include <bitset> + +using namespace o2::mft; +using namespace o2::dcs; + +using DeliveryType = o2::dcs::DeliveryType; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; + +ClassImp(o2::mft::MFTDCSinfo); + +void MFTDCSinfo::print() const +{ + LOG(INFO) << "First Value: timestamp = " << firstValue.first << ", value = " << firstValue.second; + LOG(INFO) << "Last Value: timestamp = " << lastValue.first << ", value = " << lastValue.second; + LOG(INFO) << "Mid Value: timestamp = " << midValue.first << ", value = " << midValue.second; + LOG(INFO) << "Max Change: timestamp = " << maxChange.first << ", value = " << maxChange.second; +} + +//__________________________________________________________________ + +void MFTDCSProcessor::init(const std::vector<DPID>& pids) +{ + // fill the array of the DPIDs that will be used by MFT + // pids should be provided by CCDB + + for (const auto& it : pids) { + mPids[it] = false; + mMFTDCS[it].makeEmpty(); + } +} + +//__________________________________________________________________ + +int MFTDCSProcessor::process(const gsl::span<const DPCOM> dps) +{ + + // first we check which DPs are missing - if some are, it means that + // the delta map was sent + if (mVerbose) { + LOG(INFO) << "\n\n\nProcessing new TF\n-----------------"; + } + if (!mStartTFset) { + mStartTF = mTF; + mStartTFset = true; + } + + std::unordered_map<DPID, DPVAL> mapin; + for (auto& it : dps) { + mapin[it.id] = it.data; + } + for (auto& it : mPids) { + const auto& el = mapin.find(it.first); + if (el == mapin.end()) { + LOG(DEBUG) << "DP " << it.first << " not found in map"; + } else { + LOG(DEBUG) << "DP " << it.first << " found in map"; + } + } + + // now we process all DPs, one by one + for (const auto& it : dps) { + // we process only the DPs defined in the configuration + const auto& el = mPids.find(it.id); + if (el == mPids.end()) { + LOG(INFO) << "DP " << it.id << " not found in MFTDCSProcessor, we will not process it"; + continue; + } + /* + //it.id = DataPointIdentifier + //id.data = DataPointValue + const DPCOM new_it(new_id,it.data); + processDP(new_it); + */ + processDP(it); + + mPids[it.id] = true; + } + + //updateCurrentAnalogCCDB(); + updateDPsCCDB(); + + return 0; +} + +//__________________________________________________________________ + +int MFTDCSProcessor::processDP(const DPCOM& dpcom) +{ + + // processing single DP + + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + auto& val = dpcom.data; + if (mVerbose) { + if (type == RAW_DOUBLE) { + LOG(INFO); + LOG(INFO) << "Processing DP = " << dpcom << ", with value = " << o2::dcs::getValue<double>(dpcom); + } else if (type == RAW_INT) { + LOG(INFO); + LOG(INFO) << "Processing DP = " << dpcom << ", with value = " << o2::dcs::getValue<int32_t>(dpcom); + } + } + + auto flags = val.get_flags(); + + // now I need to access the correct element + if (type == RAW_DOUBLE) { + // for these DPs, we will store the first, last, mid value, plus the value where the maximum variation occurred + auto& dvect = mDpsdoublesmap[dpid]; + LOG(INFO) << "mDpsdoublesmap[dpid].size() = " << dvect.size(); + auto etime = val.get_epoch_time(); + if (dvect.size() == 0 || etime != dvect.back().get_epoch_time()) { // we check + // that we did not get the + // same timestamp as the + // latest one + dvect.push_back(val); + } + } + + return 0; +} + +//______________________________________________________________________ + +void MFTDCSProcessor::updateDPsCCDB() +{ + + // here we create the object to then be sent to CCDB + LOG(INFO) << "Finalizing"; + union Converter { + uint64_t raw_data; + double double_value; + } converter0, converter1; + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::RAW_DOUBLE) { + auto& mftdcs = mMFTDCS[it.first]; + if (it.second == true) { // we processed the DP at least 1x + auto& dpvect = mDpsdoublesmap[it.first]; + mftdcs.firstValue.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + mftdcs.firstValue.second = converter0.double_value; + mftdcs.lastValue.first = dpvect.back().get_epoch_time(); + converter0.raw_data = dpvect.back().payload_pt1; + mftdcs.lastValue.second = converter0.double_value; + // now I will look for the max change + if (dpvect.size() > 1) { + auto deltatime = dpvect.back().get_epoch_time() - dpvect[0].get_epoch_time(); + if (deltatime < 60000) { + // if we did not cover at least 1 minute, + // max variation is defined as the difference between first and last value + converter0.raw_data = dpvect[0].payload_pt1; + converter1.raw_data = dpvect.back().payload_pt1; + double delta = std::abs(converter0.double_value - converter1.double_value); + mftdcs.maxChange.first = deltatime; // is it ok to do like this, as in Run 2? + mftdcs.maxChange.second = delta; + } else { + for (auto i = 0; i < dpvect.size() - 1; ++i) { + for (auto j = i + 1; j < dpvect.size(); ++j) { + auto deltatime = dpvect[j].get_epoch_time() - dpvect[i].get_epoch_time(); + if (deltatime >= 60000) { // we check every min; epoch_time in ms + converter0.raw_data = dpvect[i].payload_pt1; + converter1.raw_data = dpvect[j].payload_pt1; + double delta = std::abs(converter0.double_value - converter1.double_value); + if (delta > mftdcs.maxChange.second) { + mftdcs.maxChange.first = deltatime; // is it ok to do like this, as in Run 2? + mftdcs.maxChange.second = delta; + } + } + } + } + } + // mid point + auto midIdx = dpvect.size() / 2 - 1; + mftdcs.midValue.first = dpvect[midIdx].get_epoch_time(); + converter0.raw_data = dpvect[midIdx].payload_pt1; + mftdcs.midValue.second = converter0.double_value; + } else { + mftdcs.maxChange.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + mftdcs.maxChange.second = converter0.double_value; + mftdcs.midValue.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + mftdcs.midValue.second = converter0.double_value; + } + } + if (mVerbose) { + LOG(INFO) << "PID = " << it.first.get_alias(); + mftdcs.print(); + } + } + } + + std::map<std::string, std::string> md; + md["responsible"] = "Satoshi Yano"; + prepareCCDBobjectInfo(mMFTDCS, mccdbDPsInfo, "MFT/Condition/DCSDPs", mTF, md); + + return; +} diff --git a/Detectors/ITSMFT/MFT/condition/src/dcs-check-ccdb.cxx b/Detectors/ITSMFT/MFT/condition/src/dcs-check-ccdb.cxx new file mode 100644 index 0000000000000..4e10beda11e4f --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/src/dcs-check-ccdb.cxx @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include <boost/program_options.hpp> +#include <ctime> +#include <iostream> +#include <numeric> +#include <string> +#include <unordered_map> +#include <vector> + +namespace po = boost::program_options; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPMAP = std::unordered_map<DPID, std::vector<DPVAL>>; + +int main(int argc, char** argv) +{ + po::variables_map vm; + po::options_description usage("Usage"); + + std::string ccdbUrl; + uint64_t timestamp; + bool lv; + bool hv; + bool vcasn; + bool ithr; + bool ibb; + bool verbose; + + std::time_t now = std::time(nullptr); + + // clang-format off + usage.add_options() + ("help,h", "produce help message") + ("ccdb",po::value<std::string>(&ccdbUrl)->default_value("http://localhost:6464"),"ccdb url") + ("timestamp,t",po::value<uint64_t>(×tamp)->default_value(now),"timestamp to query") + ("hv",po::bool_switch(&hv),"query HV") + ("lv",po::bool_switch(&lv),"query LV") + ("vcasn",po::bool_switch(&vcasn),"query VCASN") + ("ithr",po::bool_switch(&ithr),"query ITHR") + ("ibb",po::bool_switch(&ibb),"query IBB") + ("verbose,v",po::bool_switch(&verbose),"verbose output") + ; + // clang-format on + + po::options_description cmdline; + cmdline.add(usage); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << "This program printout summary information from MFT DCS entries.\n"; + std::cout << usage << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + if (!vcasn && !ithr && !ibb) { + std::cout << "Must specify at least one of --vcasn or --ithr or --ibb\n"; + std::cout << usage << "\n"; + return 3; + } + + std::vector<std::string> what; + if (vcasn) { + what.emplace_back("MFT/Condition/VCASN"); + } + if (ithr) { + what.emplace_back("MFT/Condition/ITHR"); + } + if (ibb) { + what.emplace_back("MFT/Condition/IBB"); + } + + auto sum = + [](float s, o2::dcs::DataPointValue v) { + union Converter { + uint64_t raw_data; + double value; + } converter; + converter.raw_data = v.payload_pt1; + return s + converter.value; + }; + + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + for (auto w : what) { + std::map<std::string, std::string> metadata; + auto* m = api.retrieveFromTFileAny<DPMAP>(w, metadata, timestamp); + std::cout << "size of " << w << " map = " << m->size() << std::endl; + if (verbose) { + for (auto& i : *m) { + auto v = i.second; + auto mean = std::accumulate(v.begin(), v.end(), 0.0, sum); + if (v.size()) { + mean /= v.size(); + } + std::cout << fmt::format("{:64s} {:4d} values of mean {:7.2f}\n", i.first.get_alias(), v.size(), mean); + } + } + } + return 0; +} diff --git a/Detectors/ITSMFT/MFT/condition/testWorkflow/MFTDCSDataProcessorSpec.h b/Detectors/ITSMFT/MFT/condition/testWorkflow/MFTDCSDataProcessorSpec.h new file mode 100644 index 0000000000000..99aad1648b3f9 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/testWorkflow/MFTDCSDataProcessorSpec.h @@ -0,0 +1,233 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MFT_DATAPROCESSOR_H +#define O2_MFT_DATAPROCESSOR_H + +/// @file DCSMFTDataProcessorSpec.h +/// @brief MFT Processor for DCS Data Points + +#include <unistd.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/AliasExpander.h" +#include "MFTCondition/MFTDCSProcessor.h" +#include "MFTCondition/DCSNameResolver.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace mft +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using namespace o2::ccdb; +using CcdbManager = o2::ccdb::BasicCCDBManager; +using clbUtils = o2::calibration::Utils; +using HighResClock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration<double, std::ratio<1, 1>>; + +class MFTDCSDataProcessor : public o2::framework::Task +{ + public: + //________________________________________________________________ + void init(o2::framework::InitContext& ic) final + { + std::vector<DPID> vect; + mDPsUpdateInterval = ic.options().get<int64_t>("DPs-update-interval"); + if (mDPsUpdateInterval == 0) { + LOG(ERROR) << "MFT DPs update interval set to zero seconds --> changed to 60"; + mDPsUpdateInterval = 60; + } + bool useCCDBtoConfigure = ic.options().get<bool>("use-ccdb-to-configure"); + + mStart = ic.options().get<int64_t>("tstart"); + mEnd = ic.options().get<int64_t>("tend"); + + if (useCCDBtoConfigure) { + LOG(INFO) << "Configuring via CCDB"; + std::string ccdbpath = ic.options().get<std::string>("ccdb-path"); + auto& mgr = CcdbManager::instance(); + mgr.setURL(ccdbpath); + CcdbApi api; + api.init(mgr.getURL()); + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + std::unordered_map<DPID, std::string>* dpid2DataDesc = mgr.getForTimeStamp<std::unordered_map<DPID, std::string>>("MFT/Config/DCSDPconfig", ts); + for (auto& i : *dpid2DataDesc) { + vect.push_back(i.first); + } + } + + else { + LOG(INFO) << "Configuring via hardcoded strings"; + std::vector<std::string> aliases = {"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Analog", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/BackBias", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Digital", + "MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Voltage/BackBias", + "MFT_RU_LV/H0/D0/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D1/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D2/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D3/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D4/F0/Z[0..3]/iMon", + "MFT_RU_LV/H0/D0/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D1/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D2/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D3/F1/Z[0..3]/iMon", + "MFT_RU_LV/H0/D4/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D0/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D1/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D2/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D3/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D4/F0/Z[0..3]/iMon", + "MFT_RU_LV/H1/D0/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D1/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D2/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D3/F1/Z[0..3]/iMon", + "MFT_RU_LV/H1/D4/F1/Z[0..3]/iMon"}; + + std::vector<std::string> expaliases = o2::dcs::expandAliases(aliases); + for (const auto& i : expaliases) { + vect.emplace_back(i, o2::dcs::RAW_DOUBLE); + } + } + + LOG(INFO) << "Listing Data Points for MFT:"; + for (auto& i : vect) { + LOG(INFO) << i; + } + + mProcessor = std::make_unique<o2::mft::MFTDCSProcessor>(); + bool useVerboseMode = ic.options().get<bool>("use-verbose-mode"); + LOG(INFO) << " ************************* Verbose?" << useVerboseMode; + + if (useVerboseMode) { + mProcessor->useVerboseMode(); + } + mProcessor->init(vect); + + mTimer = HighResClock::now(); + } + + //________________________________________________________________ + void run(o2::framework::ProcessingContext& pc) final + { + auto tfid = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + auto dps = pc.inputs().get<gsl::span<DPCOM>>("input"); + + mProcessor->setTF(tfid); + mProcessor->process(dps); + + auto timeNow = HighResClock::now(); + Duration elapsedTime = timeNow - mTimer; // in seconds + + LOG(INFO) << "mDPsUpdateInterval " << mDPsUpdateInterval << "[sec.]"; + + if (elapsedTime.count() >= mDPsUpdateInterval) { + sendDPsoutput(pc.outputs()); + mTimer = timeNow; + } + } + + //________________________________________________________________ + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + sendDPsoutput(ec.outputs()); + } + + private: + std::unique_ptr<MFTDCSProcessor> mProcessor; + HighResClock::time_point mTimer; + int64_t mDPsUpdateInterval; + + long mStart; + long mEnd; + + //________________________________________________________________ + void sendDPsoutput(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + mProcessor->updateDPsCCDB(); + const auto& payload = mProcessor->getMFTDPsInfo(); + auto& info = mProcessor->getccdbDPsInfo(); + + long tstart = mStart; + long tend = mEnd; + + if (tstart == -1) { + tstart = o2::ccdb::getCurrentTimestamp(); + } + + if (tend == -1) { + constexpr long SECONDSPERYEAR = 365 * 24 * 60 * 60; + tend = o2::ccdb::getFutureTimestamp(SECONDSPERYEAR); + } + + info.setStartValidityTimestamp(tstart); + info.setEndValidityTimestamp(tend); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "MFT_DCSDPs", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "MFT_DCSDPs", 0}, info); + mProcessor->clearDPsinfo(); + } + //________________________________________________________________ +}; // end class +} // namespace mft + +namespace framework +{ + +DataProcessorSpec getMFTDCSDataProcessorSpec() +{ + + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "MFT_DCSDPs"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "MFT_DCSDPs"}); + + return DataProcessorSpec{ + "mft-dcs-data-processor", + Inputs{{"input", "DCS", "MFTDATAPOINTS"}}, + outputs, + AlgorithmSpec{adaptFromTask<o2::mft::MFTDCSDataProcessor>()}, + Options{ + {"ccdb-path", VariantType::String, "http://localhost:8080", {"Path to CCDB"}}, + {"tstart", VariantType::Int64, -1ll, {"Start of validity timestamp"}}, + {"tend", VariantType::Int64, -1ll, {"End of validity timestamp"}}, + {"use-ccdb-to-configure", VariantType::Bool, false, {"Use CCDB to configure"}}, + {"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, + {"DPs-update-interval", VariantType::Int64, 600ll, {"Interval (in s) after which to update the DPs CCDB entry"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-data-workflow.cxx b/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-data-workflow.cxx new file mode 100644 index 0000000000000..d302040402e03 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-data-workflow.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "Framework/TypeTraits.h" +#include <unordered_map> +namespace o2::framework +{ +template <> +struct has_root_dictionary<std::unordered_map<o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue>, void> : std::true_type { +}; +} // namespace o2::framework +#include "Framework/DataProcessorSpec.h" +#include "MFTDCSDataProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getMFTDCSDataProcessorSpec()); + return specs; +} diff --git a/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-sim-workflow.cxx b/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..298d0a69eabe5 --- /dev/null +++ b/Detectors/ITSMFT/MFT/condition/testWorkflow/mft-dcs-sim-workflow.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// // we need to add workflow options before including Framework/runDataProcessing +// void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +// { +// // option allowing to set parameters +// } + +// ------------------------------------------------------------------ + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + // for MFT + // for test, we use less DPs that official ones + + /* + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"mft_main/MFT_PSU_Zone/H[0..1]D[0..4]F[0..1]Z[0..3]/Monitoring/Current/Analog", 0.05, 0.3}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"mft_main/MFT_PSU_Zone/H[0..1]D[0..4]F[0..1]Z[0..3]/Monitoring/Current/Digital", 0.1, 2.0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"mft_main/MFT_PSU_Zone/H[0..1]D[0..4]F[0..1]Z[0..3]/Monitoring/Current/BackBias", 0.0, 1.0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"mft_main/MFT_PSU_Zone/H[0..1]D[0..4]F[0..1]Z[0..3]/Monitoring/Voltage/BackBias", 0, 3.}); + */ + + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Analog", 0.05, 0.3}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/BackBias", 0.0, 1.0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Current/Digital", 0.1, 2.0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_PSU_ZONE/H[0..1]/D[0..4]/F[0..1]/Z[0..3]/Voltage/BackBias", 0., 3.0}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D0/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D1/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D2/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D3/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H0/D4/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F0/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F0/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F0/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F0/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D0/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D1/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D2/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D3/F1/Z3/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F1/Z0/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F1/Z1/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F1/Z2/iMon", 1.8, 2.2}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"MFT_RU_LV/H1/D4/F1/Z3/iMon", 1.8, 2.2}); + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "MFT")); + return specs; +} diff --git a/Detectors/ITSMFT/MFT/macros/CMakeLists.txt b/Detectors/ITSMFT/MFT/macros/CMakeLists.txt index 016c6ec06431e..3888cf528d7eb 100644 --- a/Detectors/ITSMFT/MFT/macros/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/macros/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(mapping) add_subdirectory(test) diff --git a/Detectors/ITSMFT/MFT/macros/mapping/CMakeLists.txt b/Detectors/ITSMFT/MFT/macros/mapping/CMakeLists.txt index 9a82d0b44a6c3..f4b1a0da5453a 100644 --- a/Detectors/ITSMFT/MFT/macros/mapping/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/macros/mapping/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(extractMFTMapping.C PUBLIC_LINK_LIBRARIES O2::MFTBase diff --git a/Detectors/ITSMFT/MFT/macros/mapping/extractMFTMapping.C b/Detectors/ITSMFT/MFT/macros/mapping/extractMFTMapping.C index 3167f936f3e7f..c121ba1b0aa85 100644 --- a/Detectors/ITSMFT/MFT/macros/mapping/extractMFTMapping.C +++ b/Detectors/ITSMFT/MFT/macros/mapping/extractMFTMapping.C @@ -1,6 +1,7 @@ #if !defined(__CLING__) || defined(__ROOTCLING__) #include "MFTBase/GeometryTGeo.h" +#include "ITSMFTReconstruction/ChipMappingMFT.h" constexpr int NChips = 936; constexpr int NModules = 280; @@ -10,10 +11,27 @@ constexpr int NConnectors = 5; constexpr int NMaxChipsPerLadder = 5; constexpr int NRUTypes = 13; +struct MFTChipFullMappingData { + UShort_t globalChipSWID = 0; // global software chip ID + UShort_t localChipSWID = 0; // local software chip ID + UShort_t localChipHWID = 0; // local hardware chip ID + UChar_t chipOnRU = 0; // chip within the read-out-unit + UChar_t cableHW = 0; // cable in the connector (transceiver) + UChar_t connector = 0; // cable connector in a zone + UChar_t zone = 0; // read-out zone id + UChar_t ruOnLayer = 0; // read-out-unit index on layer + UChar_t ruType = 0; // read-out-unit type + UChar_t ruSWID = 0; // read-out-unit hardware ID + UChar_t ruHWID = 0; // read-out-unit software ID + UChar_t layer = 0; // MFT layer + UChar_t disk = 0; // MFT disk + UChar_t half = 0; // MFT half +}; + struct MFTChipMappingData { UShort_t module = 0; // global module ID UChar_t chipOnModule = 0; // chip within the module - UChar_t cable = 0; // cable in the connector + UChar_t cable = 0; // cable in the connector (transceiver) UChar_t chipOnRU = 0; // chip within the RU (SW) }; @@ -27,6 +45,7 @@ struct MFTModuleMappingData { UChar_t half = 0; // half id }; +std::array<MFTChipFullMappingData, NChips> ChipFullMappingData; std::array<MFTChipMappingData, NChips> ChipMappingData; std::array<MFTModuleMappingData, NModules> ModuleMappingData; @@ -61,6 +80,7 @@ constexpr Int_t ZoneRUType[NZonesPerLayer / 2][NLayers / 2]{ constexpr std::array<int, NRUTypes> NChipsOnRUType{7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 14}; void createCXXfile(o2::mft::GeometryTGeo*); +void createCXXfileFullMap(o2::mft::GeometryTGeo*); Int_t getZone(Int_t layer, Int_t ladderID, Int_t& connector); Int_t getZoneRUID(Int_t half, Int_t layer, Int_t zone, Int_t& zoneID); @@ -71,7 +91,7 @@ Int_t ruHW, zoneID; Int_t nModules; std::vector<Int_t> modFirstChip, modNChips, RUNChips; -void extractMFTMapping(const std::string inputGeom = "") +void extractMFTMapping(const std::string inputGeom = "o2sim_geometry.root") { o2::base::GeometryManager::loadGeometry(inputGeom); auto gm = o2::mft::GeometryTGeo::Instance(); // geometry manager for mapping @@ -109,6 +129,109 @@ void extractMFTMapping(const std::string inputGeom = "") // create again the CXX file with the chipOnRUSW member createCXXfile(gm); + + // write version with full mapping in MFTChipMappingData + createCXXfileFullMap(gm); +} + +//__________________________________________________________________________ +void createCXXfileFullMap(o2::mft::GeometryTGeo* gm) +{ + const o2::itsmft::ChipMappingMFT map; + + int half, disk, layer, zone, module, ladder, ladderID; + int chipIDglo, chipIDlocSW, chipIDlocHW, chipOnModule; + int ruSWID, ruHWID, ruType; + uint16_t ruOnLayer, chipOnRU, link = 0; + uint8_t connector, cableHW, cableSW; + Int_t cnct; + + const o2::itsmft::ChipOnRUInfo* chipOnRUInfo; + const o2::itsmft::RUInfo* ruInfo; + o2::itsmft::ChipInfo chipInfo; + + // fill chip full mapping information + for (int iChip = 0; iChip < NChips; ++iChip) { + chipIDglo = iChip; + + ChipFullMappingData[iChip].globalChipSWID = chipIDglo; + + gm->getSensorID(iChip, half, disk, ladder, chipIDlocSW); + + ChipFullMappingData[iChip].localChipSWID = chipIDlocSW; + ChipFullMappingData[iChip].disk = disk; + ChipFullMappingData[iChip].half = half; + + module = map.chipID2Module(chipIDglo, chipOnModule); + + layer = gm->getLayer(chipIDglo); + ChipFullMappingData[iChip].layer = layer; + + ladderID = gm->getLadderID(disk, ladder); + map.getChipInfoSW(chipIDglo, chipInfo); + + ruType = chipInfo.ruType; + ChipFullMappingData[iChip].ruType = ruType; + + zone = getZone(layer, ladderID, cnct); + ChipFullMappingData[iChip].zone = zone; + + ruOnLayer = 4 * half + zone; + ChipFullMappingData[iChip].ruOnLayer = ruOnLayer; + + ruSWID = map.getRUIDSW(layer, ruOnLayer); + ChipFullMappingData[iChip].ruSWID = ruSWID; + + ruHWID = map.RUSW2FEEId(ruSWID); + ChipFullMappingData[iChip].ruHWID = ruHWID; + + chipIDlocHW = map.chipModuleIDSW2HW(ruType, chipIDlocSW); + ChipFullMappingData[iChip].localChipHWID = chipIDlocHW; + + chipOnRUInfo = chipInfo.chOnRU; + + chipOnRU = chipOnRUInfo->id; + ChipFullMappingData[iChip].chipOnRU = chipOnRU; + + connector = chipOnRUInfo->moduleHW; + ChipFullMappingData[iChip].connector = connector; + + cableHW = chipOnRUInfo->cableHW; + ChipFullMappingData[iChip].cableHW = cableHW; + } + FILE* srcFile = fopen("ChipMappingMFT_full.cxx", "w"); + fprintf(srcFile, "\n// { module, chipOnModule, cable, chipOnRU, globalChipSWID, localChipSWID, localChipHWID, connector, zone, ruOnLayer, ruType, ruSWID, ruHWID, layer, disk, half }\n\n"); + Int_t ladderP = -1, layerP = -1, halfP = -1; + for (Int_t iChip = 0; iChip < NChips; iChip++) { + gm->getSensorID(iChip, half, disk, ladder, sensor); + layer = gm->getLayer(iChip); + if (layer != layerP || ladder != ladderP || half != halfP) { // new module + layerP = layer; + ladderP = ladder; + halfP = half; + fprintf(srcFile, "// chip: %3d (%1d), ladder: %2d (%2d), layer: %1d, disk: %1d, half: %1d, zone: %1d \n", iChip, nChipsPerLadder, ladder, ladderID, layer, disk, half, zone); + } + fprintf(srcFile, "{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d}%s\n", + ChipMappingData[iChip].module, + ChipMappingData[iChip].chipOnModule, + ChipMappingData[iChip].cable, + ChipMappingData[iChip].chipOnRU, + ChipFullMappingData[iChip].globalChipSWID, + ChipFullMappingData[iChip].localChipSWID, + ChipFullMappingData[iChip].localChipHWID, + ChipFullMappingData[iChip].connector, + ChipFullMappingData[iChip].zone, + ChipFullMappingData[iChip].ruOnLayer, + ChipFullMappingData[iChip].ruType, + ChipFullMappingData[iChip].ruSWID, + ChipFullMappingData[iChip].ruHWID, + ChipFullMappingData[iChip].layer, + ChipFullMappingData[iChip].disk, + ChipFullMappingData[iChip].half, + (iChip < NChips - 1 ? "," : "")); + } + fprintf(srcFile, "\n}};\n"); + fclose(srcFile); } //__________________________________________________________________________ @@ -130,11 +253,12 @@ void createCXXfile(o2::mft::GeometryTGeo* gm) FILE* srcFile = fopen("ChipMappingMFT.cxx", "w"); fprintf(srcFile, - "// Copyright CERN and copyright holders of ALICE O2. This software is\n" - "// distributed under the terms of the GNU General Public License v3 (GPL\n" - "// Version 3), copied verbatim in the file \"COPYING\".\n" + "// Copyright 2019-2020 CERN and copyright holders of ALICE O2.\n" + "// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.\n" + "// All rights not expressly granted are reserved.\n" "//\n" - "// See http://alice-o2.web.cern.ch/license for full licensing information.\n" + "// This software is distributed under the terms of the GNU General Public\n" + "// License v3 (GPL Version 3), copied verbatim in the file \"COPYING\".\n" "//\n" "// In applying this license CERN does not waive the privileges and immunities\n" "// granted to it by virtue of its status as an Intergovernmental Organization\n" @@ -168,9 +292,12 @@ void createCXXfile(o2::mft::GeometryTGeo* gm) } Int_t iconnector = connector; fprintf(srcFile, "{%d, %d, %d, %d}%s\n", (nModules - 1), sensor, ChipConnectorCable[connector][sensor], ChipOnRUSW[ZoneRUType[zone][layer / 2]][iconnector][sensor], (iChip < nChips - 1 ? "," : "")); + + // fill MFTChipMappingData ChipMappingData[iChip].module = nModules - 1; ChipMappingData[iChip].chipOnModule = sensor; ChipMappingData[iChip].cable = ChipConnectorCable[connector][sensor]; + ChipMappingData[iChip].chipOnRU = ChipOnRUSW[ZoneRUType[zone][layer / 2]][iconnector][sensor]; } fprintf(srcFile, "\n}};\n\n"); diff --git a/Detectors/ITSMFT/MFT/macros/test/CMakeLists.txt b/Detectors/ITSMFT/MFT/macros/test/CMakeLists.txt index dc80010644a91..ce575aa159efc 100644 --- a/Detectors/ITSMFT/MFT/macros/test/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/macros/test/CMakeLists.txt @@ -1,14 +1,15 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_test_root_macro(CheckTopologies.C +o2_add_test_root_macro(CreateDictionaries.C PUBLIC_LINK_LIBRARIES O2::MathUtils O2::MFTBase O2::ITSMFTReconstruction @@ -17,3 +18,8 @@ o2_add_test_root_macro(CheckTopologies.C O2::SimulationDataFormat LABELS mft) +o2_add_test_root_macro(MFTMisaligner.C + PUBLIC_LINK_LIBRARIES O2::MFTBase + O2::CCDB + LABELS mft) + diff --git a/Detectors/ITSMFT/MFT/macros/test/CheckTopologies.C b/Detectors/ITSMFT/MFT/macros/test/CheckTopologies.C deleted file mode 100644 index 87690f85485d7..0000000000000 --- a/Detectors/ITSMFT/MFT/macros/test/CheckTopologies.C +++ /dev/null @@ -1,292 +0,0 @@ -/// \file CheckTopologies.C -/// Macros to test the generation of a dictionary of topologies. Three dictionaries are generated: one with signal-cluster only, one with noise-clusters only and one with all the clusters. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include <TAxis.h> -#include <TCanvas.h> -#include <TSystem.h> -#include <TFile.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TNtuple.h> -#include <TString.h> -#include <TStyle.h> -#include <TTree.h> -#include <TStopwatch.h> -#include <fstream> -#include <string> - -#include "MathUtils/Utils.h" -#include "MFTBase/GeometryTGeo.h" -#include "ITSMFTReconstruction/BuildTopologyDictionary.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ClusterTopology.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ITSMFTSimulation/Hit.h" -#include "MathUtils/Cartesian.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include "SimulationDataFormat/DigitizationContext.h" -#include "Framework/Logger.h" -#include <unordered_map> -#endif - -void CheckTopologies(std::string clusfile = "mftclusters.root", - std::string hitfile = "o2sim_HitsMFT.root", - std::string collContextfile = "collisioncontext.root", - std::string inputGeom = "") -{ - const int QEDSourceID = 99; // Clusters from this MC source correspond to QED electrons - - using namespace o2::base; - using namespace o2::mft; - - using o2::itsmft::BuildTopologyDictionary; - using o2::itsmft::ClusterTopology; - using o2::itsmft::CompCluster; - using o2::itsmft::CompClusterExt; - using o2::itsmft::Hit; - using ROFRec = o2::itsmft::ROFRecord; - using MC2ROF = o2::itsmft::MC2ROFRecord; - using HitVec = std::vector<Hit>; - using MC2HITS_map = std::unordered_map<uint64_t, int>; // maps (track_ID<<16 + chip_ID) to entry in the hit vector - std::unordered_map<int, int> hadronicMCMap; // mapping from MC event entry to hadronic event ID - std::vector<HitVec*> hitVecPool; - std::vector<MC2HITS_map> mc2hitVec; - const o2::steer::DigitizationContext* digContext = nullptr; - TStopwatch sw; - sw.Start(); - - // Geometry - o2::base::GeometryManager::loadGeometry(inputGeom); - auto gman = o2::mft::GeometryTGeo::Instance(); - gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, - o2::math_utils::TransformType::L2G)); // request cached transforms - - // Hits - TFile* fileH = nullptr; - TTree* hitTree = nullptr; - - if (!hitfile.empty() && !collContextfile.empty() && !gSystem->AccessPathName(hitfile.c_str()) && !gSystem->AccessPathName(collContextfile.c_str())) { - fileH = TFile::Open(hitfile.data()); - hitTree = (TTree*)fileH->Get("o2sim"); - mc2hitVec.resize(hitTree->GetEntries()); - hitVecPool.resize(hitTree->GetEntries(), nullptr); - digContext = o2::steer::DigitizationContext::loadFromFile(collContextfile); - - auto& intGlo = digContext->getEventParts(digContext->isQEDProvided()); - int hadrID = -1, nGlo = intGlo.size(), nHadro = 0; - for (int iglo = 0; iglo < nGlo; iglo++) { - const auto& parts = intGlo[iglo]; - bool found = false; - for (auto& part : parts) { - if (part.sourceID == 0) { // we use underlying background - hadronicMCMap[iglo] = part.entryID; - found = true; - nHadro++; - break; - } - } - if (!found) { - hadronicMCMap[iglo] = -1; - } - } - if (nHadro < hitTree->GetEntries()) { - LOG(FATAL) << "N=" << nHadro << " hadronic events < " - << " N=" << hitTree->GetEntries() << " Hit enties."; - } - } - - // Clusters - TFile* fileCl = TFile::Open(clusfile.data()); - TTree* clusTree = (TTree*)fileCl->Get("o2sim"); - std::vector<CompClusterExt>* clusArr = nullptr; - clusTree->SetBranchAddress("MFTClusterComp", &clusArr); - std::vector<unsigned char>* patternsPtr = nullptr; - auto pattBranch = clusTree->GetBranch("MFTClusterPatt"); - if (pattBranch) { - pattBranch->SetAddress(&patternsPtr); - } - - // ROFrecords - std::vector<ROFRec> rofRecVec, *rofRecVecP = &rofRecVec; - clusTree->SetBranchAddress("MFTClustersROF", &rofRecVecP); - - // Cluster MC labels - o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; - std::vector<MC2ROF> mc2rofVec, *mc2rofVecP = &mc2rofVec; - if (hitTree && clusTree->GetBranch("MFTClusterMCTruth")) { - clusTree->SetBranchAddress("MFTClusterMCTruth", &clusLabArr); - clusTree->SetBranchAddress("MFTClustersMC2ROF", &mc2rofVecP); - } - clusTree->GetEntry(0); - - // Topologies dictionaries: 1) all clusters 2) signal clusters only 3) noise clusters only - BuildTopologyDictionary completeDictionary; - BuildTopologyDictionary signalDictionary; - BuildTopologyDictionary noiseDictionary; - - int nROFRec = (int)rofRecVec.size(); - std::vector<int> mcEvMin, mcEvMax; - - if (clusLabArr) { // >> build min and max MC events used by each ROF - mcEvMin.resize(nROFRec, hitTree->GetEntries()); - mcEvMax.resize(nROFRec, -1); - for (int imc = mc2rofVec.size(); imc--;) { - int hadrID = hadronicMCMap[imc]; - if (hadrID < 0) { - continue; - } - const auto& mc2rof = mc2rofVec[imc]; - if (mc2rof.rofRecordID < 0) { - continue; // this MC event did not contribute to any ROF - } - for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { - int irof = mc2rof.rofRecordID + irfd; - if (mcEvMin[irof] > hadrID) { - mcEvMin[irof] = hadrID; - } - if (mcEvMax[irof] < hadrID) { - mcEvMax[irof] = hadrID; - } - } - } - } // << build min and max MC events used by each ROF - - auto pattIdx = patternsPtr->cbegin(); - for (int irof = 0; irof < nROFRec; irof++) { - const auto& rofRec = rofRecVec[irof]; - - rofRec.print(); - - if (clusLabArr) { // >> read and map MC events contributing to this ROF - for (int im = mcEvMin[irof]; im <= mcEvMax[irof]; im++) { - if (!hitVecPool[im]) { - hitTree->SetBranchAddress("MFTHit", &hitVecPool[im]); - hitTree->GetEntry(im); - auto& mc2hit = mc2hitVec[im]; - const auto* hitArray = hitVecPool[im]; - for (int ih = hitArray->size(); ih--;) { - const auto& hit = (*hitArray)[ih]; - uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); - mc2hit.emplace(key, ih); - } - } - } - } // << cache MC events contributing to this ROF - - for (int icl = 0; icl < rofRec.getNEntries(); icl++) { - int clEntry = rofRec.getFirstEntry() + icl; // entry of icl-th cluster of this ROF in the vector of clusters - // do we read MC data? - - const auto& cluster = (*clusArr)[clEntry]; - - if (cluster.getPatternID() != CompCluster::InvalidPatternID) { - LOG(WARNING) << "Encountered patternID = " << cluster.getPatternID() << " != " << CompCluster::InvalidPatternID; - LOG(WARNING) << "Clusters have already been generated with a dictionary! Quitting"; - return; - } - - ClusterTopology topology; - o2::itsmft::ClusterPattern pattern(pattIdx); - topology.setPattern(pattern); - - float dX = BuildTopologyDictionary::IgnoreVal, dZ = BuildTopologyDictionary::IgnoreVal; - if (clusLabArr) { - const auto& lab = (clusLabArr->getLabels(clEntry))[0]; - auto srcID = lab.getSourceID(); - if (lab.isValid() && srcID != QEDSourceID) { // use MC truth info only for non-QED and non-noise clusters - auto trID = lab.getTrackID(); - const auto& mc2hit = mc2hitVec[lab.getEventID()]; - const auto* hitArray = hitVecPool[lab.getEventID()]; - Int_t chipID = cluster.getSensorID(); - uint64_t key = (uint64_t(trID) << 32) + chipID; - auto hitEntry = mc2hit.find(key); - if (hitEntry != mc2hit.end()) { - const auto& hit = (*hitArray)[hitEntry->second]; - auto locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local - auto locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); - locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); - const auto locC = o2::itsmft::TopologyDictionary::getClusterCoordinates(cluster, pattern); - dX = locH.X() - locC.X(); - dZ = locH.Z() - locC.Z(); - } else { - printf("Failed to find MC hit entry for Tr:%d chipID:%d\n", trID, chipID); - lab.print(); - } - signalDictionary.accountTopology(topology, dX, dZ); - } else { - noiseDictionary.accountTopology(topology, dX, dZ); - } - } - completeDictionary.accountTopology(topology, dX, dZ); - } - // clean MC cache for events which are not needed anymore - if (clusLabArr) { - int irfNext = irof; - int limMC = irfNext == nROFRec ? hitVecPool.size() : mcEvMin[irfNext]; // can clean events up to this - for (int imc = mcEvMin[irof]; imc < limMC; imc++) { - delete hitVecPool[imc]; - hitVecPool[imc] = nullptr; - mc2hitVec[imc].clear(); - } - } - } - auto dID = o2::detectors::DetID::MFT; - - completeDictionary.setThreshold(0.0001); - completeDictionary.groupRareTopologies(); - completeDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "", ".bin")); - completeDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "", ".txt")); - completeDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "", ".root")); - - TFile histogramOutput("histograms.root", "recreate"); - TCanvas* cComplete = new TCanvas("cComplete", "Distribution of all the topologies"); - cComplete->cd(); - cComplete->SetLogy(); - TH1F* hComplete = nullptr; - o2::itsmft::TopologyDictionary::getTopologyDistribution(completeDictionary.getDictionary(), hComplete, "hComplete"); - hComplete->SetDirectory(0); - hComplete->Draw("hist"); - hComplete->Write(); - cComplete->Write(); - - TCanvas* cNoise = nullptr; - TCanvas* cSignal = nullptr; - TH1F* hNoise = nullptr; - TH1F* hSignal = nullptr; - - if (clusLabArr) { - noiseDictionary.setThreshold(0.0001); - noiseDictionary.groupRareTopologies(); - noiseDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".bin")); - noiseDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".txt")); - noiseDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "noise", ".root")); - signalDictionary.setThreshold(0.0001); - signalDictionary.groupRareTopologies(); - signalDictionary.printDictionaryBinary(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".bin")); - signalDictionary.printDictionary(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".txt")); - signalDictionary.saveDictionaryRoot(o2::base::NameConf::getDictionaryFileName(dID, "signal", ".root")); - cNoise = new TCanvas("cNoise", "Distribution of noise topologies"); - cNoise->cd(); - cNoise->SetLogy(); - o2::itsmft::TopologyDictionary::getTopologyDistribution(noiseDictionary.getDictionary(), hNoise, "hNoise"); - hNoise->SetDirectory(0); - hNoise->Draw("hist"); - histogramOutput.cd(); - hNoise->Write(); - cNoise->Write(); - cSignal = new TCanvas("cSignal", "cSignal"); - cSignal->cd(); - cSignal->SetLogy(); - o2::itsmft::TopologyDictionary::getTopologyDistribution(signalDictionary.getDictionary(), hSignal, "hSignal"); - hSignal->SetDirectory(0); - hSignal->Draw("hist"); - histogramOutput.cd(); - hSignal->Write(); - cSignal->Write(); - sw.Stop(); - sw.Print(); - } -} diff --git a/Detectors/ITSMFT/MFT/macros/test/CreateDictionaries.C b/Detectors/ITSMFT/MFT/macros/test/CreateDictionaries.C new file mode 100644 index 0000000000000..e9c589e2a0528 --- /dev/null +++ b/Detectors/ITSMFT/MFT/macros/test/CreateDictionaries.C @@ -0,0 +1,318 @@ +/// \file CreateDictionaries.C +/// Macros to test the generation of a dictionary of topologies. Three dictionaries are generated: one with signal-cluster only, one with noise-clusters only and one with all the clusters. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <TAxis.h> +#include <TCanvas.h> +#include <TSystem.h> +#include <TFile.h> +#include <TH1F.h> +#include <TH2F.h> +#include <TNtuple.h> +#include <TString.h> +#include <TStyle.h> +#include <TTree.h> +#include <TStopwatch.h> +#include <fstream> +#include <string> + +#include "MathUtils/Utils.h" +#include "MFTBase/GeometryTGeo.h" +#include "ITSMFTReconstruction/BuildTopologyDictionary.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ClusterTopology.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITSMFTSimulation/Hit.h" +#include "MathUtils/Cartesian.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include "Framework/Logger.h" +#include <unordered_map> +#endif + +void CreateDictionaries(bool saveDeltas = false, + std::string clusfile = "mftclusters.root", + std::string hitfile = "o2sim_HitsMFT.root", + std::string collContextfile = "collisioncontext.root", + std::string inputGeom = "", + float checkOutliers = 2., // reject outliers (MC dX or dZ exceeds row/col span by a factor above the threshold) + float minPtMC = 0.01) // account only MC hits with pT above threshold +{ + const int QEDSourceID = 99; // Clusters from this MC source correspond to QED electrons + + using namespace o2::base; + using namespace o2::mft; + + using o2::itsmft::BuildTopologyDictionary; + using o2::itsmft::ClusterTopology; + using o2::itsmft::CompCluster; + using o2::itsmft::CompClusterExt; + using o2::itsmft::Hit; + using ROFRec = o2::itsmft::ROFRecord; + using MC2ROF = o2::itsmft::MC2ROFRecord; + using HitVec = std::vector<Hit>; + using MC2HITS_map = std::unordered_map<uint64_t, int>; // maps (track_ID<<16 + chip_ID) to entry in the hit vector + std::unordered_map<int, int> hadronicMCMap; // mapping from MC event entry to hadronic event ID + std::vector<HitVec*> hitVecPool; + std::vector<MC2HITS_map> mc2hitVec; + + TFile* fout = nullptr; + TNtuple* nt = nullptr; + if (saveDeltas) { + fout = TFile::Open("CreateDictionaries.root", "recreate"); + nt = new TNtuple("nt", "hashes ntuple", "hash:dx:dz"); + } + + const o2::steer::DigitizationContext* digContext = nullptr; + TStopwatch sw; + sw.Start(); + float minPtMC2 = minPtMC > 0 ? minPtMC * minPtMC : -1; + // Geometry + o2::base::GeometryManager::loadGeometry(inputGeom); + auto gman = o2::mft::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::L2G)); // request cached transforms + + // Hits + TFile* fileH = nullptr; + TTree* hitTree = nullptr; + + if (!hitfile.empty() && !collContextfile.empty() && !gSystem->AccessPathName(hitfile.c_str()) && !gSystem->AccessPathName(collContextfile.c_str())) { + fileH = TFile::Open(hitfile.data()); + hitTree = (TTree*)fileH->Get("o2sim"); + mc2hitVec.resize(hitTree->GetEntries()); + hitVecPool.resize(hitTree->GetEntries(), nullptr); + digContext = o2::steer::DigitizationContext::loadFromFile(collContextfile); + + auto& intGlo = digContext->getEventParts(digContext->isQEDProvided()); + int hadrID = -1, nGlo = intGlo.size(), nHadro = 0; + for (int iglo = 0; iglo < nGlo; iglo++) { + const auto& parts = intGlo[iglo]; + bool found = false; + for (auto& part : parts) { + if (part.sourceID == 0) { // we use underlying background + hadronicMCMap[iglo] = part.entryID; + found = true; + nHadro++; + break; + } + } + if (!found) { + hadronicMCMap[iglo] = -1; + } + } + if (nHadro < hitTree->GetEntries()) { + LOG(FATAL) << "N=" << nHadro << " hadronic events < " + << " N=" << hitTree->GetEntries() << " Hit enties."; + } + } + + // Clusters + TFile* fileCl = TFile::Open(clusfile.data()); + TTree* clusTree = (TTree*)fileCl->Get("o2sim"); + std::vector<CompClusterExt>* clusArr = nullptr; + clusTree->SetBranchAddress("MFTClusterComp", &clusArr); + std::vector<unsigned char>* patternsPtr = nullptr; + auto pattBranch = clusTree->GetBranch("MFTClusterPatt"); + if (pattBranch) { + pattBranch->SetAddress(&patternsPtr); + } + + // ROFrecords + std::vector<ROFRec> rofRecVec, *rofRecVecP = &rofRecVec; + clusTree->SetBranchAddress("MFTClustersROF", &rofRecVecP); + + // Cluster MC labels + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; + std::vector<MC2ROF> mc2rofVec, *mc2rofVecP = &mc2rofVec; + if (hitTree && clusTree->GetBranch("MFTClusterMCTruth")) { + clusTree->SetBranchAddress("MFTClusterMCTruth", &clusLabArr); + clusTree->SetBranchAddress("MFTClustersMC2ROF", &mc2rofVecP); + } + clusTree->GetEntry(0); + + // Topologies dictionaries: 1) all clusters 2) signal clusters only 3) noise clusters only + BuildTopologyDictionary completeDictionary; + BuildTopologyDictionary signalDictionary; + BuildTopologyDictionary noiseDictionary; + + int nROFRec = (int)rofRecVec.size(); + std::vector<int> mcEvMin, mcEvMax; + + if (clusLabArr) { // >> build min and max MC events used by each ROF + mcEvMin.resize(nROFRec, hitTree->GetEntries()); + mcEvMax.resize(nROFRec, -1); + for (int imc = mc2rofVec.size(); imc--;) { + int hadrID = hadronicMCMap[imc]; + if (hadrID < 0) { + continue; + } + const auto& mc2rof = mc2rofVec[imc]; + if (mc2rof.rofRecordID < 0) { + continue; // this MC event did not contribute to any ROF + } + for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { + int irof = mc2rof.rofRecordID + irfd; + if (mcEvMin[irof] > hadrID) { + mcEvMin[irof] = hadrID; + } + if (mcEvMax[irof] < hadrID) { + mcEvMax[irof] = hadrID; + } + } + } + } // << build min and max MC events used by each ROF + + auto pattIdx = patternsPtr->cbegin(); + for (int irof = 0; irof < nROFRec; irof++) { + const auto& rofRec = rofRecVec[irof]; + + rofRec.print(); + + if (clusLabArr) { // >> read and map MC events contributing to this ROF + for (int im = mcEvMin[irof]; im <= mcEvMax[irof]; im++) { + if (!hitVecPool[im]) { + hitTree->SetBranchAddress("MFTHit", &hitVecPool[im]); + hitTree->GetEntry(im); + auto& mc2hit = mc2hitVec[im]; + const auto* hitArray = hitVecPool[im]; + for (int ih = hitArray->size(); ih--;) { + const auto& hit = (*hitArray)[ih]; + uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); + mc2hit.emplace(key, ih); + } + } + } + } // << cache MC events contributing to this ROF + + for (int icl = 0; icl < rofRec.getNEntries(); icl++) { + int clEntry = rofRec.getFirstEntry() + icl; // entry of icl-th cluster of this ROF in the vector of clusters + // do we read MC data? + + const auto& cluster = (*clusArr)[clEntry]; + + if (cluster.getPatternID() != CompCluster::InvalidPatternID) { + LOG(WARNING) << "Encountered patternID = " << cluster.getPatternID() << " != " << CompCluster::InvalidPatternID; + LOG(WARNING) << "Clusters have already been generated with a dictionary! Quitting"; + return; + } + + ClusterTopology topology; + o2::itsmft::ClusterPattern pattern(pattIdx); + topology.setPattern(pattern); + + float dX = BuildTopologyDictionary::IgnoreVal, dZ = BuildTopologyDictionary::IgnoreVal; + if (clusLabArr) { + const auto& lab = (clusLabArr->getLabels(clEntry))[0]; + auto srcID = lab.getSourceID(); + if (lab.isValid() && srcID != QEDSourceID) { // use MC truth info only for non-QED and non-noise clusters + auto trID = lab.getTrackID(); + const auto& mc2hit = mc2hitVec[lab.getEventID()]; + const auto* hitArray = hitVecPool[lab.getEventID()]; + Int_t chipID = cluster.getSensorID(); + uint64_t key = (uint64_t(trID) << 32) + chipID; + auto hitEntry = mc2hit.find(key); + if (hitEntry != mc2hit.end()) { + const auto& hit = (*hitArray)[hitEntry->second]; + if (minPtMC < 0.f || hit.GetMomentum().Perp2() > minPtMC2) { + auto locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local + auto locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); + locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); + const auto locC = o2::itsmft::TopologyDictionary::getClusterCoordinates(cluster, pattern, false); + dX = locH.X() - locC.X(); + dZ = locH.Z() - locC.Z(); + if (saveDeltas) { + nt->Fill(topology.getHash(), dX, dZ); + } + if (checkOutliers > 0.) { + if (std::abs(dX) > topology.getRowSpan() * o2::itsmft::SegmentationAlpide::PitchRow * checkOutliers || + std::abs(dZ) > topology.getColumnSpan() * o2::itsmft::SegmentationAlpide::PitchCol * checkOutliers) { // ignore outlier + dX = dZ = BuildTopologyDictionary::IgnoreVal; + } + } + } + } else { + printf("Failed to find MC hit entry for Tr:%d chipID:%d\n", trID, chipID); + lab.print(); + } + signalDictionary.accountTopology(topology, dX, dZ); + } else { + noiseDictionary.accountTopology(topology, dX, dZ); + } + } + completeDictionary.accountTopology(topology, dX, dZ); + } + // clean MC cache for events which are not needed anymore + if (clusLabArr) { + int irfNext = irof; + int limMC = irfNext == nROFRec ? hitVecPool.size() : mcEvMin[irfNext]; // can clean events up to this + for (int imc = mcEvMin[irof]; imc < limMC; imc++) { + delete hitVecPool[imc]; + hitVecPool[imc] = nullptr; + mc2hitVec[imc].clear(); + } + } + } + auto dID = o2::detectors::DetID::MFT; + + completeDictionary.setThreshold(0.0001); + completeDictionary.groupRareTopologies(); + completeDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", "bin")); + completeDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", ".txt")); + completeDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "", "root")); + + TFile histogramOutput("histograms.root", "recreate"); + TCanvas* cComplete = new TCanvas("cComplete", "Distribution of all the topologies"); + cComplete->cd(); + cComplete->SetLogy(); + TH1F* hComplete = nullptr; + o2::itsmft::TopologyDictionary::getTopologyDistribution(completeDictionary.getDictionary(), hComplete, "hComplete"); + hComplete->SetDirectory(0); + hComplete->Draw("hist"); + hComplete->Write(); + cComplete->Write(); + + TCanvas* cNoise = nullptr; + TCanvas* cSignal = nullptr; + TH1F* hNoise = nullptr; + TH1F* hSignal = nullptr; + + if (clusLabArr) { + noiseDictionary.setThreshold(0.0001); + noiseDictionary.groupRareTopologies(); + noiseDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTopo", "bin")); + noiseDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTopo", ".txt")); + noiseDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "noiseClusTop", "root")); + signalDictionary.setThreshold(0.0001); + signalDictionary.groupRareTopologies(); + signalDictionary.printDictionaryBinary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", "bin")); + signalDictionary.printDictionary(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", ".txt")); + signalDictionary.saveDictionaryRoot(o2::base::NameConf::getAlpideClusterDictionaryFileName(dID, "signal", "root")); + cNoise = new TCanvas("cNoise", "Distribution of noise topologies"); + cNoise->cd(); + cNoise->SetLogy(); + o2::itsmft::TopologyDictionary::getTopologyDistribution(noiseDictionary.getDictionary(), hNoise, "hNoise"); + hNoise->SetDirectory(0); + hNoise->Draw("hist"); + histogramOutput.cd(); + hNoise->Write(); + cNoise->Write(); + cSignal = new TCanvas("cSignal", "cSignal"); + cSignal->cd(); + cSignal->SetLogy(); + o2::itsmft::TopologyDictionary::getTopologyDistribution(signalDictionary.getDictionary(), hSignal, "hSignal"); + hSignal->SetDirectory(0); + hSignal->Draw("hist"); + histogramOutput.cd(); + hSignal->Write(); + cSignal->Write(); + sw.Stop(); + sw.Print(); + } + if (saveDeltas) { + fout->cd(); + nt->Write(); + } +} diff --git a/Detectors/ITSMFT/MFT/macros/test/MFTMisaligner.C b/Detectors/ITSMFT/MFT/macros/test/MFTMisaligner.C new file mode 100644 index 0000000000000..5be2c8bd38995 --- /dev/null +++ b/Detectors/ITSMFT/MFT/macros/test/MFTMisaligner.C @@ -0,0 +1,35 @@ +/// \file MFTMisaligner.C +/// Macros to test the (mis)alignment of the MFT geometry + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "MFTBase/GeometryTGeo.h" +#include "MFTSimulation/GeometryMisAligner.h" +#include "DetectorsBase/GeometryManager.h" +#endif + +//_____________________________________________________________________________ +void MFTMisaligner(const std::string& ccdbHost = "http://localhost:8080/", long tmin = 0, long tmax = -1, + double xHalf = 0., double yHalf = 0., double zHalf = 0., double psiHalf = 0., double thetaHalf = 0., double phiHalf = 0., + double xDisk = 0., double yDisk = 0., double zDisk = 0., double psiDisk = 0., double thetaDisk = 0., double phiDisk = 0., + double xLadder = 0., double yLadder = 0., double zLadder = 0., double psiLadder = 0., double thetaLadder = 0., double phiLadder = 0., + double xChip = 0., double yChip = 0., double zChip = 0., double psiChip = 0., double thetaChip = 0., double phiChip = 0., + const std::string& objectPath = "", + const std::string& fileName = "MFTAlignment.root", + bool verbose = false) +{ + o2::base::GeometryManager::loadGeometry("", false); + + // Initialize the misaligner + o2::mft::GeometryMisAligner misaligner; + + misaligner.SetHalfCartMisAlig(0., xHalf, 0., yHalf, 0., zHalf); + misaligner.SetHalfAngMisAlig(0., psiHalf, 0., thetaHalf, 0., phiHalf); + misaligner.SetDiskCartMisAlig(0., xDisk, 0., yDisk, 0., zDisk); + misaligner.SetDiskAngMisAlig(0., psiDisk, 0., thetaDisk, 0., phiDisk); + misaligner.SetLadderCartMisAlig(0., xLadder, 0., yLadder, 0., zLadder); + misaligner.SetLadderAngMisAlig(0., psiLadder, 0., thetaLadder, 0., phiLadder); + misaligner.SetSensorCartMisAlig(0., xChip, 0., yChip, 0., zChip); + misaligner.SetSensorAngMisAlig(0., psiChip, 0., thetaChip, 0., phiChip); + + misaligner.MisAlign(verbose, ccdbHost, tmin, tmax, objectPath, fileName); +} diff --git a/Detectors/ITSMFT/MFT/reconstruction/include/MFTReconstruction/ClustererTask.h b/Detectors/ITSMFT/MFT/reconstruction/include/MFTReconstruction/ClustererTask.h deleted file mode 100644 index 029c7f8c653bf..0000000000000 --- a/Detectors/ITSMFT/MFT/reconstruction/include/MFTReconstruction/ClustererTask.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.h -/// \brief Task driving the cluster finding from digits -/// \author bogdan.vulpescu@cern.ch -/// \date 03/05/2017 - -#ifndef ALICEO2_MFT_CLUSTERERTASK_H_ -#define ALICEO2_MFT_CLUSTERERTASK_H_ - -#include "ITSMFTReconstruction/ChipMappingMFT.h" -#include "ITSMFTReconstruction/PixelReader.h" -#include "ITSMFTReconstruction/RawPixelReader.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include <memory> - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template <typename T> -class MCTruthContainer; -} - -namespace mft -{ - -class ClustererTask -{ - using Clusterer = o2::itsmft::Clusterer; - using Cluster = o2::itsmft::Cluster; - using CompCluster = o2::itsmft::CompCluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using MCTruth = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; - - public: - ClustererTask(bool useMC = true, bool raw = false); - ~ClustererTask(); - - void Init(); - Clusterer& getClusterer() { return mClusterer; } - void run(const std::string inpName, const std::string outName); - o2::itsmft::PixelReader* getReader() const { return (o2::itsmft::PixelReader*)mReader; } - void loadDictionary(std::string fileName) { mClusterer.loadDictionary(fileName); } - - void writeTree(std::string basename, int i); - void setMaxROframe(int max) { maxROframe = max; } - int getMaxROframe() const { return maxROframe; } - - private: - int maxROframe = std::numeric_limits<int>::max(); ///< maximal number of RO frames per a file - bool mRawDataMode = false; ///< input from raw data or MC digits - bool mUseMCTruth = true; ///< flag to use MCtruth if available - o2::itsmft::PixelReader* mReader = nullptr; ///< Pointer on the relevant Pixel reader - std::unique_ptr<o2::itsmft::DigitPixelReader> mReaderMC; ///< reader for MC data - std::unique_ptr<o2::itsmft::RawPixelReader<o2::itsmft::ChipMappingMFT>> mReaderRaw; ///< reader for raw data - - Clusterer mClusterer; ///< Cluster finder - - std::vector<CompClusterExt> mCompClus; //!< vector of compact clusters - - std::vector<o2::itsmft::ROFRecord> mROFRecVec; //!< vector of ROFRecord references - - MCTruth mClsLabels; //! MC labels - - std::vector<unsigned char> mPatterns; - - ClassDefNV(ClustererTask, 2); -}; -} // namespace mft -} // namespace o2 - -#endif diff --git a/Detectors/ITSMFT/MFT/reconstruction/src/ClustererTask.cxx b/Detectors/ITSMFT/MFT/reconstruction/src/ClustererTask.cxx deleted file mode 100644 index 4bff2797b2856..0000000000000 --- a/Detectors/ITSMFT/MFT/reconstruction/src/ClustererTask.cxx +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTrack.h -/// \brief Cluster finding from digits (MFT) -/// \author bogdan.vulpescu@cern.ch -/// \date 03/05/2017 - -#include "DetectorsCommonDataFormats/DetID.h" -#include "MFTReconstruction/ClustererTask.h" -#include "MFTBase/Constants.h" -#include "MFTBase/Geometry.h" -#include "FairLogger.h" -#include <TFile.h> -#include <TTree.h> - -using namespace o2::mft; - -//_____________________________________________________________________ -ClustererTask::ClustererTask(bool useMC, bool raw) : mRawDataMode(raw), - mUseMCTruth(useMC && (!raw)) -{ - LOG(INFO) << Class()->GetName() << ": MC digits mode: " << (mRawDataMode ? "OFF" : "ON") - << " | Use MCtruth: " << (mUseMCTruth ? "ON" : "OFF"); - - mClusterer.setNChips(o2::itsmft::ChipMappingMFT::getNChips()); -} - -//_____________________________________________________________________ -ClustererTask::~ClustererTask() -{ - mCompClus.clear(); - mClsLabels.clear(); -} - -//_____________________________________________________________________ -void ClustererTask::Init() -{ - /// Inititializes the clusterer and connects input and output container - - if (mReader) { - return; // already initialized - } - - // create reader according to requested raw of MC mode - if (mRawDataMode) { - mReaderRaw = std::make_unique<o2::itsmft::RawPixelReader<o2::itsmft::ChipMappingMFT>>(); - mReader = mReaderRaw.get(); - } else { // clusterizer of digits - mReaderMC = std::make_unique<o2::itsmft::DigitPixelReader>(); - mReader = mReaderMC.get(); - } - - mClusterer.print(); - - return; -} - -//_____________________________________________________________________ -void ClustererTask::run(const std::string inpName, const std::string outName) -{ - // standalone execution - Init(); // create reader, clusterer - - if (mRawDataMode) { - - mReaderRaw->openInput(inpName); - mClusterer.process(1, *mReaderRaw.get(), &mCompClus, &mPatterns, &mROFRecVec, nullptr); - - auto basename = outName.substr(0, outName.size() - sizeof("root")); - auto nFiles = int(mROFRecVec.size() / maxROframe); - int i = 0; - for (; i < nFiles; i++) { - writeTree(basename, i); - } - writeTree(basename, i); // The remainder - - } else { - - mReaderMC->openInput(inpName, o2::detectors::DetID("ITS")); - - TFile outFile(outName.data(), "new"); - if (!outFile.IsOpen()) { - LOG(FATAL) << "Failed to open output file " << outName; - } - - TTree outTree("o2sim", "ITS Clusters"); - - auto compClusPtr = &mCompClus; - outTree.Branch("MFTClusterComp", &compClusPtr); - - auto rofRecVecPtr = &mROFRecVec; - outTree.Branch("MFTClustersROF", &rofRecVecPtr); - - auto clsLabelsPtr = &mClsLabels; - if (mUseMCTruth && mReaderMC->getDigitsMCTruth()) { - // digit labels are provided directly to clusterer - outTree.Branch("MFTClusterMCTruth", &clsLabelsPtr); - } else { - mUseMCTruth = false; - } - LOG(INFO) << Class()->GetName() << " | MCTruth: " << (mUseMCTruth ? "ON" : "OFF"); - - // loop over entries of the input tree - while (mReaderMC->readNextEntry()) { - mClusterer.process(1, *mReaderMC.get(), &mCompClus, &mPatterns, &mROFRecVec, &mClsLabels); - } - - outTree.Branch("MFTClusterPatt", &mPatterns); - - std::vector<o2::itsmft::MC2ROFRecord> mc2rof, *mc2rofPtr = &mc2rof; - if (mUseMCTruth) { - auto mc2rofOrig = mReaderMC->getMC2ROFRecords(); - mc2rof.reserve(mc2rofOrig.size()); - for (const auto& m2r : mc2rofOrig) { // clone from the span - mc2rof.push_back(m2r); - } - outTree.Branch("MFTClustersMC2ROF", mc2rofPtr); - } - - outTree.Fill(); - outTree.Write(); - } - - mClusterer.clear(); -} - -void ClustererTask::writeTree(std::string basename, int i) -{ - auto name = basename + std::to_string(i) + ".root"; - TFile outFile(name.data(), "new"); - if (!outFile.IsOpen()) { - LOG(FATAL) << "Failed to open output file " << name; - } - TTree outTree("o2sim", "MFT Clusters"); - - auto max = (i + 1) * maxROframe; - auto lastf = (max < mROFRecVec.size()) ? mROFRecVec.begin() + max : mROFRecVec.end(); - std::vector<o2::itsmft::ROFRecord> rofRecBuffer(mROFRecVec.begin() + i * maxROframe, lastf); - std::vector<o2::itsmft::ROFRecord>* rofRecPtr = &rofRecBuffer; - outTree.Branch("MFTClustersROF", rofRecPtr); - - auto first = rofRecBuffer[0].getFirstEntry(); - auto last = rofRecBuffer.back().getFirstEntry() + rofRecBuffer.back().getNEntries(); - - std::vector<CompClusterExt> compClusBuffer, *compClusPtr = &compClusBuffer; - compClusBuffer.assign(&mCompClus[first], &mCompClus[last]); - outTree.Branch("MFTClusterComp", &compClusPtr); - outTree.Branch("MFTClusterPatt", &mPatterns); - - for (auto& rof : rofRecBuffer) { - rof.setFirstEntry(rof.getFirstEntry() - first); - } - - outTree.Fill(); - outTree.Write(); -} diff --git a/Detectors/ITSMFT/MFT/simulation/CMakeLists.txt b/Detectors/ITSMFT/MFT/simulation/CMakeLists.txt index 2c8386ae463e1..9c92707347afd 100644 --- a/Detectors/ITSMFT/MFT/simulation/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/simulation/CMakeLists.txt @@ -1,20 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MFTSimulation - SOURCES src/Detector.cxx src/DigitizerTask.cxx - PUBLIC_LINK_LIBRARIES O2::MFTBase ROOT::Physics) + SOURCES src/Detector.cxx src/DigitizerTask.cxx src/GeometryMisAligner.cxx + PUBLIC_LINK_LIBRARIES O2::MFTBase O2::CCDB ROOT::Physics) o2_target_root_dictionary(MFTSimulation HEADERS include/MFTSimulation/Detector.h - include/MFTSimulation/DigitizerTask.h) + include/MFTSimulation/DigitizerTask.h + include/MFTSimulation/GeometryMisAligner.h) o2_data_file(COPY data DESTINATION Detectors/MFT/simulation) diff --git a/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/Detector.h b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/Detector.h index 70d01ef726ef5..f57073eea3c89 100644 --- a/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/Detector.h +++ b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -84,7 +85,38 @@ class Detector : public o2::base::DetImpl<Detector> void PreTrack() override { ; } void ConstructGeometry() override; // inherited from FairModule - // + /// Add alignable top volumes + void addAlignableVolumes() const override; + + /// Add alignable Half volumes + /// \param hf Half number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesHalf(Int_t hf, TString& parent, Int_t& lastUID) const; + + /// Add alignable Disk volumes + /// \param hf half number + /// \param dk disk number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesDisk(Int_t hf, Int_t dk, TString& parent, Int_t& lastUID) const; + + /// Add alignable Ladder volumes + /// \param hf half number + /// \param dk disk number + /// \param lr ladder stave number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesLadder(Int_t hf, Int_t dk, Int_t lr, TString& parent, Int_t& lastUID) const; + + /// Add alignable Sensor volumes + /// \param hf half number + /// \param dk disk number + /// \param lr ladder number + /// \param ms sensor number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesChip(Int_t hf, Int_t dk, Int_t lr, Int_t ms, TString& parent, Int_t& lastUID) const; Int_t isVersion() const { return mVersion; } /// Creating materials for the detector diff --git a/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/DigitizerTask.h b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/DigitizerTask.h index 0d27ab53764a1..6ada0e21d0858 100644 --- a/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/DigitizerTask.h +++ b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/DigitizerTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/GeometryMisAligner.h b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/GeometryMisAligner.h new file mode 100644 index 0000000000000..4cb0958abc513 --- /dev/null +++ b/Detectors/ITSMFT/MFT/simulation/include/MFTSimulation/GeometryMisAligner.h @@ -0,0 +1,249 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryMisAligner.h +/// \brief This macro is used to misalign the existing MFT geometry +/// \author robin.caron@cern.ch (based on MUON/MCH AliRoot macros) +/// \date 01/07/2020 +/// + +#ifndef ALICEO2_MFT_GEOMETRYMISALIGNER_H +#define ALICEO2_MFT_GEOMETRYMISALIGNER_H + +#include <TObject.h> + +class TGeoCombiTrans; +class TClonesArray; + +namespace o2 +{ +namespace mft +{ +class GeometryTGeo; +} +} // namespace o2 + +namespace o2 +{ +namespace mft +{ +class GeometryMisAligner +{ + public: + GeometryMisAligner(Double_t cartXMisAligM, Double_t cartXMisAligW, Double_t cartYMisAligM, Double_t cartYMisAligW, Double_t angMisAligM, Double_t angMisAligW); + GeometryMisAligner(Double_t cartMisAligM, Double_t cartMisAligW, Double_t angMisAligM, Double_t angMisAligW); + GeometryMisAligner(Double_t cartMisAligW, Double_t angMisAligW); + GeometryMisAligner(); + ~GeometryMisAligner() = default; + + /// Not implemented + GeometryMisAligner(const GeometryMisAligner& right); + /// Not implemented + GeometryMisAligner& operator=(const GeometryMisAligner& right); + + //_________________________________________________________________ + // methods + + GeometryTGeo* mGeometryTGeo; //! access to geometry details + + bool matrixToAngles(const double* rot, double& psi, double& theta, double& phi); + + // return a misaligned geometry obtained from the existing one. + void MisAlign(bool verbose = false, const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080", long tmin = 0, long tmax = -1, const std::string& objectPath = "", const std::string& fileName = "MFTAlignment.root"); + + /// Set sensor cartesian displacement parameters different along x, y + void SetSensorCartMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fSensorMisAlig[0][0] = xmean; + fSensorMisAlig[0][1] = xwidth; + fSensorMisAlig[1][0] = ymean; + fSensorMisAlig[1][1] = ywidth; + fSensorMisAlig[2][0] = zmean; + fSensorMisAlig[2][1] = zwidth; + } + + /// Set sensor cartesian displacement parameters, the same along x, y + void SetSensorCartMisAlig(Double_t mean, Double_t width) + { + fSensorMisAlig[0][0] = mean; + fSensorMisAlig[0][1] = width; + fSensorMisAlig[1][0] = mean; + fSensorMisAlig[1][1] = width; + } + + /// Set sensor angular displacement + void SetSensorAngMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fSensorMisAlig[3][0] = xmean; + fSensorMisAlig[3][1] = xwidth; + fSensorMisAlig[4][0] = ymean; + fSensorMisAlig[4][1] = ywidth; + fSensorMisAlig[5][0] = zmean; + fSensorMisAlig[5][1] = zwidth; + } + + /// Set sensor cartesian displacement (Kept for backward compatibility) + void SetMaxSensorCartMisAlig(Double_t width) + { + fSensorMisAlig[0][0] = 0.0; + fSensorMisAlig[0][1] = width; + fSensorMisAlig[1][0] = 0.0; + fSensorMisAlig[1][1] = width; + } + + /// Set sensor angular displacement (Kept for backward compatibility) + void SetMaxSensorAngMisAlig(Double_t width) + { + fSensorMisAlig[5][0] = 0.0; + fSensorMisAlig[5][1] = width; + } + + /// Set sensor cartesian displacement parameters different along x, y + void SetLadderCartMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fLadderMisAlig[0][0] = xmean; + fLadderMisAlig[0][1] = xwidth; + fLadderMisAlig[1][0] = ymean; + fLadderMisAlig[1][1] = ywidth; + fLadderMisAlig[2][0] = zmean; + fLadderMisAlig[2][1] = zwidth; + } + + /// Set ladder cartesian displacement parameters, the same along x, y + void SetLadderCartMisAlig(Double_t mean, Double_t width) + { + fLadderMisAlig[0][0] = mean; + fLadderMisAlig[0][1] = width; + fLadderMisAlig[1][0] = mean; + fLadderMisAlig[1][1] = width; + } + + /// Set ladder angular displacement + void SetLadderAngMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fLadderMisAlig[3][0] = xmean; + fLadderMisAlig[3][1] = xwidth; + fLadderMisAlig[4][0] = ymean; + fLadderMisAlig[4][1] = ywidth; + fLadderMisAlig[5][0] = zmean; + fLadderMisAlig[5][1] = zwidth; + } + + /// Set cartesian displacement for ladder (Kept for backward compatibility) + void SetMaxLadderCartMisAlig(Double_t width) + { + fLadderMisAlig[0][0] = 0.0; + fLadderMisAlig[0][1] = width; + fLadderMisAlig[1][0] = 0.0; + fLadderMisAlig[1][1] = width; + } + + /// Set angular displacement for ladder (Kept for backward compatibility) + void SetMaxLadderAngMisAlig(Double_t width) + { + fLadderMisAlig[5][0] = 0.0; + fLadderMisAlig[5][1] = width; + } + + void SetXYAngMisAligFactor(Double_t factor); + + void SetZCartMisAligFactor(Double_t factor); + + /// Set option for gaussian distribution + void SetUseGaus(Bool_t usegaus) + { + fUseGaus = usegaus; + fUseUni = !usegaus; + } + + /// Set option for uniform distribution + void SetUseUni(Bool_t useuni) + { + fUseGaus = !useuni; + fUseUni = useuni; + } + + /// Set half cartesian displacement parameters + void SetHalfCartMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fHalfMisAlig[0][0] = xmean; + fHalfMisAlig[0][1] = xwidth; + fHalfMisAlig[1][0] = ymean; + fHalfMisAlig[1][1] = ywidth; + fHalfMisAlig[2][0] = zmean; + fHalfMisAlig[2][1] = zwidth; + } + + /// Set half cartesian displacement parameters + void SetHalfAngMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fHalfMisAlig[3][0] = xmean; + fHalfMisAlig[3][1] = xwidth; + fHalfMisAlig[4][0] = ymean; + fHalfMisAlig[4][1] = ywidth; + fHalfMisAlig[5][0] = zmean; + fHalfMisAlig[5][1] = zwidth; + } + + /// Set disk cartesian displacement parameters + void SetDiskCartMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fDiskMisAlig[0][0] = xmean; + fDiskMisAlig[0][1] = xwidth; + fDiskMisAlig[1][0] = ymean; + fDiskMisAlig[1][1] = ywidth; + fDiskMisAlig[2][0] = zmean; + fDiskMisAlig[2][1] = zwidth; + } + + /// Set disk cartesian displacement parameters + void SetDiskAngMisAlig(Double_t xmean, Double_t xwidth, Double_t ymean, Double_t ywidth, Double_t zmean, Double_t zwidth) + { + fDiskMisAlig[3][0] = xmean; + fDiskMisAlig[3][1] = xwidth; + fDiskMisAlig[4][0] = ymean; + fDiskMisAlig[4][1] = ywidth; + fDiskMisAlig[5][0] = zmean; + fDiskMisAlig[5][1] = zwidth; + } + + /// Set alignment resolution to misalign objects to be stored in CCDB + void SetAlignmentResolution(const TClonesArray* misAlignArray, Int_t chId = -1, Double_t chResX = -1., Double_t chResY = -1., Double_t deResX = -1., Double_t deResY = -1.); + + protected: + private: + // return a misaligned transformation + TGeoCombiTrans MisAlignLadder() const; + TGeoCombiTrans MisAlignDisk() const; + TGeoCombiTrans MisAlignSensor() const; + TGeoCombiTrans MisAlignHalf() const; + + void GetUniMisAlign(Double_t cartMisAlig[3], Double_t angMisAlig[3], const Double_t lParMisAlig[6][2]) const; + void GetGausMisAlign(Double_t cartMisAlig[3], Double_t angMisAlig[3], const Double_t lParMisAlig[6][2]) const; + + Bool_t fUseUni; ///< use uniform distribution for misaligmnets + Bool_t fUseGaus; ///< use gaussian distribution for misaligmnets + + Double_t fSensorMisAlig[6][2]; ///< Mean and width of the displacements of the sensors along x,y,z (translations) and about x,y,z (rotations) + Double_t fLadderMisAlig[6][2]; ///< Mean and width of the displacements of the ladder along x,y,z (translations) and about x,y,z (rotations) + Double_t fDiskMisAlig[6][2]; ///< Mean and width of the displacements of the half-disk along x,y,z (translations) and about x,y,z (rotations) + Double_t fHalfMisAlig[6][2]; ///< Mean and width of the displacements of the half-MF along x,y,z (translations) and about x,y,z (rotations) + + Double_t fXYAngMisAligFactor; ///< factor (<1) to apply to angular misalignment range since range of motion is restricted out of the xy plane + Double_t fZCartMisAligFactor; ///< factor (<1) to apply to cartetian misalignment range since range of motion is restricted in z direction + + ClassDefNV(GeometryMisAligner, 0) // Geometry parametrisation +}; + +} // namespace mft +} // namespace o2 + +#endif //ALICEO2_MFT_GEOMETRYMISALIGNER_H diff --git a/Detectors/ITSMFT/MFT/simulation/src/Detector.cxx b/Detectors/ITSMFT/MFT/simulation/src/Detector.cxx index a1c934cc90aa3..63b6e0b2b6d03 100644 --- a/Detectors/ITSMFT/MFT/simulation/src/Detector.cxx +++ b/Detectors/ITSMFT/MFT/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,17 +21,16 @@ #include "MFTSimulation/Detector.h" -#include "SimulationDataFormat/Stack.h" #include "Field/MagneticField.h" +#include "SimulationDataFormat/Stack.h" -#include "TVirtualMC.h" -#include "TLorentzVector.h" -#include "TVector3.h" -#include "TGeoManager.h" #include "FairLogger.h" #include "FairRootManager.h" #include "FairVolume.h" -#include "FairRootManager.h" +#include "TGeoManager.h" +#include "TLorentzVector.h" +#include "TVector3.h" +#include "TVirtualMC.h" using o2::itsmft::Hit; using namespace o2::mft; @@ -39,23 +39,11 @@ ClassImp(o2::mft::Detector); //_____________________________________________________________________________ Detector::Detector() - : o2::base::DetImpl<Detector>("MFT", kTRUE), - mVersion(1), - mDensitySupportOverSi(0.036), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mTrackData() -{ -} + : o2::base::DetImpl<Detector>("MFT", kTRUE), mVersion(1), mDensitySupportOverSi(0.036), mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), mTrackData() {} //_____________________________________________________________________________ Detector::Detector(const Detector& src) - : o2::base::DetImpl<Detector>(src), - mVersion(src.mVersion), - mDensitySupportOverSi(src.mDensitySupportOverSi), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mTrackData() -{ -} + : o2::base::DetImpl<Detector>(src), mVersion(src.mVersion), mDensitySupportOverSi(src.mDensitySupportOverSi), mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), mTrackData() {} //_____________________________________________________________________________ Detector& Detector::operator=(const Detector& src) @@ -122,10 +110,11 @@ Bool_t Detector::ProcessHits(FairVolume* vol) fMC->CurrentVolOffID(++level, diskID); fMC->CurrentVolOffID(++level, halfID); - Int_t sensorIndex = mGeometryTGeo->getSensorIndex(halfID, diskID, ladderID, sensorID); + Int_t sensorIndex = + mGeometryTGeo->getSensorIndex(halfID, diskID, ladderID, sensorID); - // LOG(INFO) << "Found hit into half = " << halfID << "; disk = " << diskID << "; ladder = " << ladderID << "; sensor - // = " << sensorID ; + // LOG(INFO) << "Found hit into half = " << halfID << "; disk = " << diskID << + // "; ladder = " << ladderID << "; sensor = " << sensorID ; bool startHit = false, stopHit = false; unsigned char status = 0; @@ -149,9 +138,11 @@ Bool_t Detector::ProcessHits(FairVolume* vol) } // track is entering or created in the volume - if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { + if ((status & Hit::kTrackEntering) || + (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { startHit = true; - } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { + } else if ((status & + (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { stopHit = true; } @@ -180,8 +171,9 @@ Bool_t Detector::ProcessHits(FairVolume* vol) Int_t trackID = fMC->GetStack()->GetCurrentTrackNumber(); // Int_t detID = vol->getMCid(); - Hit* p = addHit(trackID, sensorIndex, mTrackData.mPositionStart.Vect(), positionStop.Vect(), - mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), + Hit* p = addHit(trackID, sensorIndex, mTrackData.mPositionStart.Vect(), + positionStop.Vect(), mTrackData.mMomentumStart.Vect(), + mTrackData.mMomentumStart.E(), positionStop.T(), mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); o2::data::Stack* stack = (o2::data::Stack*)fMC->GetStack(); @@ -192,12 +184,14 @@ Bool_t Detector::ProcessHits(FairVolume* vol) } //_____________________________________________________________________________ -Hit* Detector::addHit(Int_t trackID, Int_t detID, TVector3 startPos, TVector3 endPos, TVector3 startMom, - Double_t startE, Double_t endTime, Double_t eLoss, unsigned char startStatus, - unsigned char endStatus) +Hit* Detector::addHit(Int_t trackID, Int_t detID, TVector3 startPos, + TVector3 endPos, TVector3 startMom, Double_t startE, + Double_t endTime, Double_t eLoss, + unsigned char startStatus, unsigned char endStatus) { - mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); + mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, + endTime, eLoss, startStatus, endStatus); return &(mHits->back()); } @@ -206,36 +200,46 @@ Hit* Detector::addHit(Int_t trackID, Int_t detID, TVector3 startPos, TVector3 en void Detector::createMaterials() { - // data from PDG booklet 2002 density [gr/cm^3] rad len [cm] abs len [cm] - Float_t aSi = 28.085, zSi = 14., dSi = 2.329, radSi = 21.82 / dSi, absSi = 108.4 / dSi; // Silicon - Float_t aCarb = 12.01, zCarb = 6., dCarb = 2.265, radCarb = 18.8, absCarb = 49.9; // Carbon - Float_t aAlu = 26.98, zAlu = 13., dAlu = 2.70, radAlu = 8.897, absAlu = 39.70; // Aluminum - Float_t aBe = 9.012182, zBe = 4., dBe = 1.85, radBe = 65.19 / dBe, absBe = 77.8 / dBe; // Beryllium - Float_t aCu = 63.546, zCu = 29., dCu = 8.96, radCu = 1.436, absCu = 15.32; // Copper + // data from PDG booklet 2002 density [gr/cm^3] rad len + // [cm] abs len [cm] + Float_t aSi = 28.085, zSi = 14., dSi = 2.329, radSi = 21.82 / dSi, + absSi = 108.4 / dSi; // Silicon + Float_t aCarb = 12.01, zCarb = 6., dCarb = 2.265, radCarb = 18.8, + absCarb = 49.9; // Carbon + Float_t aAlu = 26.98, zAlu = 13., dAlu = 2.70, radAlu = 8.897, + absAlu = 39.70; // Aluminum + Float_t aBe = 9.012182, zBe = 4., dBe = 1.85, radBe = 65.19 / dBe, + absBe = 77.8 / dBe; // Beryllium + Float_t aCu = 63.546, zCu = 29., dCu = 8.96, radCu = 1.436, + absCu = 15.32; // Copper // Air mixture const Int_t nAir = 4; Float_t aAir[nAir] = {12, 14, 16, 36}, zAir[nAir] = {6, 7, 8, 18}, - wAir[nAir] = {0.000124, 0.755267, 0.231781, 0.012827}, dAir = 0.00120479, dAirVacuum = 0.00120479e-4; + wAir[nAir] = {0.000124, 0.755267, 0.231781, 0.012827}, + dAir = 0.00120479, dAirVacuum = 0.00120479e-4; // Water mixture const Int_t nWater = 2; - Float_t aWater[nWater] = {1.00794, 15.9994}, zWater[nWater] = {1, 8}, wWater[nWater] = {0.111894, 0.888106}, - dWater = 1.; + Float_t aWater[nWater] = {1.00794, 15.9994}, zWater[nWater] = {1, 8}, + wWater[nWater] = {0.111894, 0.888106}, dWater = 1.; // SiO2 mixture const Int_t nSiO2 = 2; - Float_t aSiO2[nSiO2] = {15.9994, 28.0855}, zSiO2[nSiO2] = {8., 14.}, wSiO2[nSiO2] = {0.532565, 0.467435}, - dSiO2 = 2.20; + Float_t aSiO2[nSiO2] = {15.9994, 28.0855}, zSiO2[nSiO2] = {8., 14.}, + wSiO2[nSiO2] = {0.532565, 0.467435}, dSiO2 = 2.20; // Inox mixture const Int_t nInox = 9; - Float_t aInox[nInox] = {12.0107, 54.9380, 28.0855, 30.9738, 32.0660, 58.6928, 51.9961, 95.9400, 55.8450}; + Float_t aInox[nInox] = {12.0107, 54.9380, 28.0855, 30.9738, 32.0660, + 58.6928, 51.9961, 95.9400, 55.8450}; Float_t zInox[nInox] = {6, 25, 14, 15, 16, 28, 24, 42, 26}; - Float_t wInox[nInox] = {0.0003, 0.02, 0.01, 0.00045, 0.0003, 0.12, 0.17, 0.025, 0.65395}; + Float_t wInox[nInox] = {0.0003, 0.02, 0.01, 0.00045, 0.0003, + 0.12, 0.17, 0.025, 0.65395}; Float_t dInox = 8.03; - // Kapton polyimide film (from SPD AliITSv11.cxx) and http://physics.nist.gov/cgi-bin/Star/compos.pl?matno=179 + // Kapton polyimide film (from SPD AliITSv11.cxx) and + // http://physics.nist.gov/cgi-bin/Star/compos.pl?matno=179 Float_t aKapton[4] = {1.00794, 12.0107, 14.010, 15.9994}; Float_t zKapton[4] = {1., 6., 7., 8.}; Float_t wKapton[4] = {0.026362, 0.69113, 0.07327, 0.209235}; @@ -245,7 +249,8 @@ void Detector::createMaterials() Float_t aEpoxy[3] = {15.9994, 1.00794, 12.0107}; Float_t zEpoxy[3] = {8., 1., 6.}; Float_t wEpoxy[3] = {3., 19., 18.}; - Float_t dEpoxy = 1.23; // 1.8 very high value from ITS! ou 1.23 from eccobond 45 lv datasheet + Float_t dEpoxy = 1.23; // 1.8 very high value from ITS! ou 1.23 from eccobond + // 45 lv datasheet //--- Silicone SE4445 Dow Corning // Si, Al, O, C, H @@ -267,10 +272,14 @@ void Detector::createMaterials() Float_t wRohacell[nRohacell] = {0.0858, 0.5964, 0.3178}; Float_t dRohacell; if (Geometry::sGrooves == 0) { - dRohacell = 0.032 / (1 - 0.15); // No grooves, water pipes outside rohacell ==> smaller thcikness, greater rohacell density by 15% + dRohacell = + 0.032 / + (1 - 0.15); // No grooves, water pipes outside rohacell ==> smaller + // thcikness, greater rohacell density by 15% } if (Geometry::sGrooves == 1) { - dRohacell = 0.032; // With grooves, usual rohacell density: 0.032 g/cm3 rohacell 31, 0.075 g/cm3 rohacell 71; + dRohacell = 0.032; // With grooves, usual rohacell density: 0.032 g/cm3 + // rohacell 31, 0.075 g/cm3 rohacell 71; } // Polyimide pipe mixture @@ -302,7 +311,8 @@ void Detector::createMaterials() // 137.327 Ba, 47.867 Ti, 15.9994 O (mainly BaTiO3) Float_t aX7R[6] = {137.327, 47.867, 15.9994, 58.6928, 63.5460, 118.710}; Float_t zX7R[6] = {56., 22., 8., 28., 29., 50.}; - Float_t wX7R[6] = {0.524732, 0.176736, 0.179282, 0.079750, 0.019750, 0.019750}; + Float_t wX7R[6] = {0.524732, 0.176736, 0.179282, + 0.079750, 0.019750, 0.019750}; Float_t dX7R = 6.07914; // X7R weld, i.e. Sn 60% Pb 40% (from F.Tosello's web page - M.S. 15 Oct 10) @@ -313,21 +323,21 @@ void Detector::createMaterials() Float_t dX7Rweld = 8.52358; //========================================================================== - //Barrel CarbonFiber M46J + // Barrel CarbonFiber M46J const Int_t nCM46J = 4; Float_t aCM46J[4] = {12.0107, 14.0067, 15.9994, 1.00794}; Float_t zCM46J[4] = {6., 7., 8., 1.}; Float_t wCM46J[4] = {0.908508078, 0.010387573, 0.055957585, 0.025146765}; Float_t dCM46J = 1.84; // only changes density - //Polypropylene[C3H6]n + // Polypropylene[C3H6]n const Int_t nPolyppln = 2; Float_t aPolyppln[2] = {12.0107, 1.00794}; Float_t zPolyppln[2] = {6.0, 1.0}; Float_t wPolyppln[2] = {0.856307, 0.143693}; Float_t dPolyppln = 1.19; - //Polyurethane [HN-CO-O] + // Polyurethane [HN-CO-O] const Int_t nPolyurthn = 4; Float_t aPolyurthn[4] = {1.00794, 14.010, 12.0107, 15.9994}; Float_t zPolyurthn[4] = {1.0, 7.0, 6.0, 8.0}; @@ -336,52 +346,65 @@ void Detector::createMaterials() Int_t matId = 0; // tmp material id number Int_t unsens = 0, sens = 1; // sensitive or unsensitive medium - Int_t itgfld = - 3; // type of field intergration 0 no field -1 user in guswim 1 Runge Kutta 2 helix 3 const field along z - Float_t maxfld = 5.; // max field value - - Float_t tmaxfd = 0.1; // -10.0; // max deflection angle due to magnetic field in one step - Float_t stemax = 1.0; // 0.001; // max step allowed [cm] - Float_t deemax = 0.1; // -0.2; // maximum fractional energy loss in one step 0<deemax<=1 + Int_t itgfld = 3; // type of field intergration 0 no field -1 user in guswim 1 + // Runge Kutta 2 helix 3 const field along z + Float_t maxfld = 5.; // max field value + + Float_t tmaxfd = + 0.1; // -10.0; // max deflection angle due to magnetic field in one step + Float_t stemax = 1.0; // 0.001; // max step allowed [cm] + Float_t deemax = + 0.1; // -0.2; // maximum fractional energy loss in one step 0<deemax<=1 Float_t epsil = 1.0e-4; // 0.001; // tracking precision [cm] - Float_t stmin = 0.0; // -0.001; // minimum step due to continuous processes [cm] (negative value: choose it automatically) + Float_t stmin = 0.0; // -0.001; // minimum step due to continuous processes + // [cm] (negative value: choose it automatically) - Float_t tmaxfdSi = 0.1; // max deflection angle due to magnetic field in one step + Float_t tmaxfdSi = + 0.1; // max deflection angle due to magnetic field in one step Float_t stemaxSi = 0.075; // 5.0e-4; // maximum step allowed [cm] - Float_t deemaxSi = 0.1; // maximum fractional energy loss in one step 0<deemax<=1 + Float_t deemaxSi = + 0.1; // maximum fractional energy loss in one step 0<deemax<=1 Float_t epsilSi = 1.0e-4; // 0.5e-4; // tracking precision [cm] - Float_t stminSi = 0.0; // -0.001; // minimum step due to continuous processes [cm] (negative value: choose it automatically) + Float_t stminSi = 0.0; // -0.001; // minimum step due to continuous processes + // [cm] (negative value: choose it automatically) Int_t fieldType; Float_t maxField; o2::base::Detector::initFieldTrackingParams(fieldType, maxField); - LOG(DEBUG) << "Detector::createMaterials >>>>> fieldType " << fieldType << " maxField " << maxField; + LOG(DEBUG) << "Detector::createMaterials >>>>> fieldType " << fieldType + << " maxField " << maxField; matId = 0; // starting value o2::base::Detector::Mixture(matId, "Air$", aAir, zAir, dAir, nAir, wAir); - o2::base::Detector::Medium(matId, "Air$", matId, unsens, fieldType, maxField, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Medium(matId, "Air$", matId, unsens, fieldType, maxField, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Vacuum$", aAir, zAir, dAirVacuum, nAir, wAir); - o2::base::Detector::Medium(matId, "Vacuum$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Vacuum$", aAir, zAir, dAirVacuum, nAir, + wAir); + o2::base::Detector::Medium(matId, "Vacuum$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; o2::base::Detector::Material(matId, "Si$", aSi, zSi, dSi, radSi, absSi); - o2::base::Detector::Medium(matId, "Si$", matId, sens, fieldType, maxField, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, - stminSi); + o2::base::Detector::Medium(matId, "Si$", matId, sens, fieldType, maxField, + tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); matId++; o2::base::Detector::Material(matId, "Readout$", aSi, zSi, dSi, radSi, absSi); - o2::base::Detector::Medium(matId, "Readout$", matId, unsens, fieldType, maxField, tmaxfdSi, stemaxSi, deemaxSi, - epsilSi, stminSi); + o2::base::Detector::Medium(matId, "Readout$", matId, unsens, fieldType, + maxField, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, + stminSi); matId++; - o2::base::Detector::Material(matId, "Support$", aSi, zSi, dSi * mDensitySupportOverSi, - radSi / mDensitySupportOverSi, absSi / mDensitySupportOverSi); - o2::base::Detector::Medium(matId, "Support$", matId, unsens, fieldType, maxField, tmaxfdSi, stemaxSi, deemaxSi, - epsilSi, stminSi); + o2::base::Detector::Material( + matId, "Support$", aSi, zSi, dSi * mDensitySupportOverSi, + radSi / mDensitySupportOverSi, absSi / mDensitySupportOverSi); + o2::base::Detector::Medium(matId, "Support$", matId, unsens, fieldType, + maxField, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, + stminSi); matId++; Double_t maxBending = 0; // Max Angle @@ -400,96 +423,147 @@ void Detector::createMaterials() maxStepSize = .01; precision = .003; minStepSize = .003; - o2::base::Detector::Material(matId, "Carbon$", aCarb, zCarb, dCarb, radCarb, absCarb); - o2::base::Detector::Medium(matId, "Carbon$", matId, 0, fieldType, maxField, maxBending, maxStepSize, maxEnergyLoss, - precision, minStepSize); + o2::base::Detector::Material(matId, "Carbon$", aCarb, zCarb, dCarb, radCarb, + absCarb); + o2::base::Detector::Medium(matId, "Carbon$", matId, 0, fieldType, maxField, + maxBending, maxStepSize, maxEnergyLoss, precision, + minStepSize); matId++; o2::base::Detector::Material(matId, "Be$", aBe, zBe, dBe, radBe, absBe); - o2::base::Detector::Medium(matId, "Be$", matId, unsens, fieldType, maxField, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Medium(matId, "Be$", matId, unsens, fieldType, maxField, + tmaxfd, stemax, deemax, epsil, stmin); matId++; o2::base::Detector::Material(matId, "Alu$", aAlu, zAlu, dAlu, radAlu, absAlu); - o2::base::Detector::Medium(matId, "Alu$", matId, unsens, fieldType, maxField, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Medium(matId, "Alu$", matId, unsens, fieldType, maxField, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Water$", aWater, zWater, dWater, nWater, wWater); - o2::base::Detector::Medium(matId, "Water$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Water$", aWater, zWater, dWater, nWater, + wWater); + o2::base::Detector::Medium(matId, "Water$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "SiO2$", aSiO2, zSiO2, dSiO2, nSiO2, wSiO2); - o2::base::Detector::Medium(matId, "SiO2$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "SiO2$", aSiO2, zSiO2, dSiO2, nSiO2, + wSiO2); + o2::base::Detector::Medium(matId, "SiO2$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Inox$", aInox, zInox, dInox, nInox, wInox); - o2::base::Detector::Medium(matId, "Inox$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Inox$", aInox, zInox, dInox, nInox, + wInox); + o2::base::Detector::Medium(matId, "Inox$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Kapton$", aKapton, zKapton, dKapton, 4, wKapton); - o2::base::Detector::Medium(matId, "Kapton$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Kapton$", aKapton, zKapton, dKapton, 4, + wKapton); + o2::base::Detector::Medium(matId, "Kapton$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Epoxy$", aEpoxy, zEpoxy, dEpoxy, -3, wEpoxy); - o2::base::Detector::Medium(matId, "Epoxy$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Epoxy$", aEpoxy, zEpoxy, dEpoxy, -3, + wEpoxy); + o2::base::Detector::Medium(matId, "Epoxy$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "SE4445$", aSE4445, zSE4445, dSE4445, -5, wSE4445); - o2::base::Detector::Medium(matId, "SE4445$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "SE4445$", aSE4445, zSE4445, dSE4445, -5, + wSE4445); + o2::base::Detector::Medium(matId, "SE4445$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "CarbonFiber$", aCM55J, zCM55J, dCM55J, 4, wCM55J); - o2::base::Detector::Medium(matId, "CarbonFiber$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, - stmin); + o2::base::Detector::Mixture(matId, "CarbonFiber$", aCM55J, zCM55J, dCM55J, 4, + wCM55J); + o2::base::Detector::Medium(matId, "CarbonFiber$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Rohacell$", aRohacell, zRohacell, dRohacell, nRohacell, wRohacell); - o2::base::Detector::Medium(matId, "Rohacell$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Rohacell$", aRohacell, zRohacell, + dRohacell, nRohacell, wRohacell); + o2::base::Detector::Medium(matId, "Rohacell$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Polyimide$", aPolyimide, zPolyimide, dPolyimide, nPolyimide, wPolyimide); - o2::base::Detector::Medium(matId, "Polyimide$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, - stmin); + o2::base::Detector::Mixture(matId, "Polyimide$", aPolyimide, zPolyimide, + dPolyimide, nPolyimide, wPolyimide); + o2::base::Detector::Medium(matId, "Polyimide$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "PEEK$", aPEEK, zPEEK, dPEEK, nPEEK, wPEEK); - o2::base::Detector::Medium(matId, "PEEK$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "PEEK$", aPEEK, zPEEK, dPEEK, nPEEK, + wPEEK); + o2::base::Detector::Medium(matId, "PEEK$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; o2::base::Detector::Mixture(matId, "FR4$", aFR4, zFR4, dFR4, nFR4, wFR4); - o2::base::Detector::Medium(matId, "FR4$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Medium(matId, "FR4$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; o2::base::Detector::Material(matId, "Cu$", aCu, zCu, dCu, radCu, absCu); - o2::base::Detector::Medium(matId, "Cu$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Medium(matId, "Cu$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "X7Rcapacitors$", aX7R, zX7R, dX7R, 6, wX7R); - o2::base::Detector::Medium(matId, "X7Rcapacitors$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, - stmin); + o2::base::Detector::Mixture(matId, "X7Rcapacitors$", aX7R, zX7R, dX7R, 6, + wX7R); + o2::base::Detector::Medium(matId, "X7Rcapacitors$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "X7Rweld$", aX7Rweld, zX7Rweld, dX7Rweld, 2, wX7Rweld); - o2::base::Detector::Medium(matId, "X7Rweld$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "X7Rweld$", aX7Rweld, zX7Rweld, dX7Rweld, + 2, wX7Rweld); + o2::base::Detector::Medium(matId, "X7Rweld$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; // Carbon fleece from AliITSSUv2.cxx - o2::base::Detector::Material(matId, "CarbonFleece$", 12.0107, 6, 0.4, radCarb, absCarb); // 999,999); why 999??? - o2::base::Detector::Medium(matId, "CarbonFleece$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, - epsil, stmin); + o2::base::Detector::Material(matId, "CarbonFleece$", 12.0107, 6, 0.4, radCarb, + absCarb); // 999,999); why 999??? + o2::base::Detector::Medium(matId, "CarbonFleece$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); matId++; - //Barrel Materials + // Barrel Materials + + o2::base::Detector::Mixture(matId, "CarbonFiberM46J$", aCM46J, zCM46J, dCM46J, + nCM46J, wCM46J); + o2::base::Detector::Medium(matId, "CarbonFiberM46J$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); + matId++; - o2::base::Detector::Mixture(matId, "CarbonFiberM46J$", aCM46J, zCM46J, dCM46J, nCM46J, wCM46J); - o2::base::Detector::Medium(matId, "CarbonFiberM46J$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Polypropylene$", aPolyppln, zPolyppln, + dPolyppln, nPolyppln, wPolyppln); + o2::base::Detector::Medium(matId, "Polypropylene$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Polypropylene$", aPolyppln, zPolyppln, dPolyppln, nPolyppln, wPolyppln); - o2::base::Detector::Medium(matId, "Polypropylene$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + o2::base::Detector::Mixture(matId, "Polyurethane$", aPolyurthn, zPolyurthn, + dPolyurthn, nPolyurthn, wPolyurthn); + o2::base::Detector::Medium(matId, "Polyurethane$", matId, unsens, itgfld, + maxfld, tmaxfd, stemax, deemax, epsil, stmin); matId++; - o2::base::Detector::Mixture(matId, "Polyurethane$", aPolyurthn, zPolyurthn, dPolyurthn, nPolyurthn, wPolyurthn); - o2::base::Detector::Medium(matId, "Polyurethane$", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); + // Halfcone Materials + // Alu5083 mixture + const Int_t nAlu5083 = 9; // iron, silicon, copper, Manganese, Magnesium, + // Zinc, Titanium, Chromium, Aluminium + Float_t aAlu5083[nAlu5083] = {55.845, 28.0855, 63.546, 54.938049, 24.3050, + 65.39, 47.867, 51.9961, 26.981538}; + Float_t zAlu5083[nAlu5083] = {26., 14., 29., 25., 12., 30., 22., 24., 13.}; + Float_t wAlu5083[nAlu5083] = {0.004, 0.004, 0.001, 0.002, 0.0025, + 0.0025, 0.0015, 0.0010, 0.9815}; + Float_t dAlu5083 = 2.65; + + o2::base::Detector::Mixture(matId, "Alu5083$", aAlu5083, zAlu5083, dAlu5083, + nAlu5083, wAlu5083); + o2::base::Detector::Medium(matId, "Alu5083$", matId, unsens, itgfld, maxfld, + tmaxfd, stemax, deemax, epsil, stmin); matId++; LOG(DEBUG) << "Detector::createMaterials -----> matId = " << matId; @@ -525,6 +599,114 @@ void Detector::defineSensitiveVolumes() } } +//_____________________________________________________________________________ +void Detector::addAlignableVolumes() const +{ + // Creates entries for MFT alignable volumes associating the symbolic volume + // name with the corresponding volume path. + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // Modified: 21 Apr 2021 Robin Caron + + if (!gGeoManager) { + LOG(FATAL) << "TGeoManager doesn't exist !"; + return; + } + + TString path = Form("/cave_1/barrel_1/%s_0", GeometryTGeo::getMFTVolPattern()); + TString sname = GeometryTGeo::composeSymNameMFT(); + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t lastUID = 0; + Int_t nHalf = mGeometryTGeo->getNumberOfHalfs(); + + for (Int_t hf = 0; hf < nHalf; hf++) { + addAlignableVolumesHalf(hf, path, lastUID); + } +} + +//_____________________________________________________________________________ +void Detector::addAlignableVolumesHalf(int hf, TString& parent, Int_t& lastUID) const +{ + // Add alignable volumes for half-MFT and its daughters + + TString path = Form("%s/%s_%d_%d", parent.Data(), GeometryTGeo::getMFTHalfPattern(), hf, hf); + TString sname = mGeometryTGeo->composeSymNameHalf(hf); + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t nDisks = mGeometryTGeo->getNumberOfDisksPerHalf(hf); + + for (int dk = 0; dk < nDisks; dk++) { + addAlignableVolumesDisk(hf, dk, path, lastUID); + } +} + +//_____________________________________________________________________________ +void Detector::addAlignableVolumesDisk(Int_t hf, Int_t dk, + TString& parent, Int_t& lastUID) const +{ + // Add alignable volumes for disk and its daughters + + TString path = Form("%s/%s_%d_%d_%d", parent.Data(), GeometryTGeo::getMFTDiskPattern(), hf, dk, dk); + TString sname = mGeometryTGeo->composeSymNameDisk(hf, dk); + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t nLadders = 0; + + for (Int_t sensor = mGeometryTGeo->getMinSensorsPerLadder(); sensor < mGeometryTGeo->getMaxSensorsPerLadder() + 1; sensor++) { + nLadders += mGeometryTGeo->getNumberOfLaddersPerDisk(hf, dk, sensor); + } + + for (Int_t lr = 0; lr < nLadders; lr++) { + addAlignableVolumesLadder(hf, dk, lr, path, lastUID); + } +} + +//_____________________________________________________________________________ +void Detector::addAlignableVolumesLadder(Int_t hf, Int_t dk, Int_t lr, + TString& parent, Int_t& lastUID) const +{ + // Add alignable volumes for ladder and its daughters + + TString path = parent; + path = Form("%s/%s_%d_%d_%d_%d", parent.Data(), GeometryTGeo::getMFTLadderPattern(), hf, dk, lr, lr); + TString sname = mGeometryTGeo->composeSymNameLadder(hf, dk, lr); + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t nSensors = mGeometryTGeo->getNumberOfSensorsPerLadder(hf, dk, lr); + + for (Int_t ms = 0; ms < nSensors; ms++) { + addAlignableVolumesChip(hf, dk, lr, ms, path, lastUID); + } +} + +//_____________________________________________________________________________ +void Detector::addAlignableVolumesChip(Int_t hf, Int_t dk, Int_t lr, Int_t ms, + TString& parent, Int_t& lastUID) const +{ + // Add alignable volumes for a Chip + + TString path = Form("%s/%s_%d_%d_%d_%d", parent.Data(), GeometryTGeo::getMFTChipPattern(), hf, dk, lr, ms); + TString sname = mGeometryTGeo->composeSymNameChip(hf, dk, lr, ms); + + Int_t uid = o2::base::GeometryManager::getSensID(o2::detectors::DetID::MFT, lastUID++); + + if (!gGeoManager->SetAlignableEntry(sname, path.Data(), uid)) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } +} + //_____________________________________________________________________________ void Detector::EndOfEvent() { Reset(); } @@ -532,11 +714,12 @@ void Detector::EndOfEvent() { Reset(); } void Detector::Register() { // This will create a branch in the output tree called Hit, setting the last - // parameter to kFALSE means that this collection will not be written to the file, - // it will exist only during the simulation + // parameter to kFALSE means that this collection will not be written to the + // file, it will exist only during the simulation if (FairRootManager::Instance()) { - FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); + FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, + kTRUE); } } diff --git a/Detectors/ITSMFT/MFT/simulation/src/DigitizerTask.cxx b/Detectors/ITSMFT/MFT/simulation/src/DigitizerTask.cxx index b1070a2a1da18..75e689867188b 100644 --- a/Detectors/ITSMFT/MFT/simulation/src/DigitizerTask.cxx +++ b/Detectors/ITSMFT/MFT/simulation/src/DigitizerTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/simulation/src/GeometryMisAligner.cxx b/Detectors/ITSMFT/MFT/simulation/src/GeometryMisAligner.cxx new file mode 100644 index 0000000000000..19c0c822b27ce --- /dev/null +++ b/Detectors/ITSMFT/MFT/simulation/src/GeometryMisAligner.cxx @@ -0,0 +1,531 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryMisAligner.cxx +/// \brief This macro is used to misalign the existing MFT geometry +/// \author robin.caron@cern.ch (based on MUON/MCH AliRoot macros) +/// \date 01/07/2020 + +/// This macro performs the misalignment of an existing MFT geometry +/// based on the standard definition of the detector elements in +/// the MFTGeometryTransformer class. +/// +/// It uses GeometryMisAligner : +/// - Creates a new MFTGeometryTransformer and GeometryMisAligner +/// - Loads the geometry from the specified geometry file (default is geometry.root) +/// - Creates a second MFTGeometryTransformer by misaligning the existing +/// one using GeometryMisAligner::MisAlign +/// - User has to specify the magnitude of the alignments, in the Cartesian +/// co-ordiantes (which are used to apply translation misalignments) and in the +/// spherical co-ordinates (which are used to apply angular displacements) +/// - User can also set misalignment ranges by hand using the methods : +/// SetMaxCartMisAlig, SetMaxAngMisAlig, SetXYAngMisAligFactor +/// (last method takes account of the fact that the misalingment is greatest in +/// the XY plane, since the detection elements are fixed to a support structure +/// in this plane. Misalignments in the XZ and YZ plane will be very small +/// compared to those in the XY plane, which are small already - of the order +/// of microns) +/// - Default behavior generates a "residual" misalignment using gaussian +/// distributions. Uniform distributions can still be used, see +/// GeometryMisAligner. +/// - User can also generate half, disk, ladder misalignments using: +/// SetHalfCartMisAlig and SetHalfAngMisAlig, +/// SetDiskCartMisAlig and SetDiskAngMisAlig, +/// SetLadderCartMisAlig and SetLadderAngMisAlig, +/// +/// Note: If the detection elements are allowed to be misaligned in all +/// directions, this has consequences for the alignment algorithm, which +/// needs to know the number of free parameters. Eric only allowed 3 : +/// x,y,theta_xy, but in principle z and the other two angles are alignable +/// as well. +/// +//----------------------------------------------------------------------------- + +#include "MFTSimulation/GeometryMisAligner.h" + +#include "MFTBase/Geometry.h" +#include "MFTBase/GeometryTGeo.h" +#include "MFTBase/GeometryBuilder.h" + +#include "MFTSimulation/Detector.h" + +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsBase/GeometryManager.h" + +#include "CCDB/CcdbApi.h" +#include <TClonesArray.h> +#include <TGeoMatrix.h> +#include <TMatrixDSym.h> +#include <TMath.h> +#include <TRandom.h> +#include <Riostream.h> +#include <vector> +#include <TFile.h> +#include <TGeoManager.h> +#include <TGeoMatrix.h> +#include <TGeoOverlap.h> +#include <TGeoPhysicalNode.h> +#include <fmt/format.h> +#include "Framework/Logger.h" + +using namespace o2::mft; +using namespace o2::detectors; + +ClassImp(o2::mft::GeometryMisAligner); + +//______________________________________________________________________________ +GeometryMisAligner::GeometryMisAligner(Double_t cartXMisAligM, Double_t cartXMisAligW, Double_t cartYMisAligM, Double_t cartYMisAligW, Double_t angMisAligM, Double_t angMisAligW) : fUseUni(kFALSE), + fUseGaus(kTRUE), + fXYAngMisAligFactor(0.0), + fZCartMisAligFactor(0.0) +{ + /// Standard constructor + for (Int_t i = 0; i < 6; i++) { + for (Int_t j = 0; j < 2; j++) { + fLadderMisAlig[i][j] = 0.0; + fDiskMisAlig[i][j] = 0.0; + fSensorMisAlig[i][j] = 0.0; + fHalfMisAlig[i][j] = 0.0; + } + } + fLadderMisAlig[0][0] = cartXMisAligM; + fLadderMisAlig[0][1] = cartXMisAligW; + fLadderMisAlig[1][0] = cartYMisAligM; + fLadderMisAlig[1][1] = cartYMisAligW; + fLadderMisAlig[5][0] = angMisAligM; + fLadderMisAlig[5][1] = angMisAligW; +} + +//______________________________________________________________________________ +GeometryMisAligner::GeometryMisAligner(Double_t cartMisAligM, Double_t cartMisAligW, Double_t angMisAligM, Double_t angMisAligW) : fUseUni(kFALSE), + fUseGaus(kTRUE), + fXYAngMisAligFactor(0.0), + fZCartMisAligFactor(0.0) +{ + /// Standard constructor + for (Int_t i = 0; i < 6; i++) { + for (Int_t j = 0; j < 2; j++) { + fLadderMisAlig[i][j] = 0.0; + fDiskMisAlig[i][j] = 0.0; + fSensorMisAlig[i][j] = 0.0; + fHalfMisAlig[i][j] = 0.0; + } + } + fLadderMisAlig[0][0] = cartMisAligM; + fLadderMisAlig[0][1] = cartMisAligW; + fLadderMisAlig[1][0] = cartMisAligM; + fLadderMisAlig[1][1] = cartMisAligW; + fLadderMisAlig[5][0] = angMisAligM; + fLadderMisAlig[5][1] = angMisAligW; +} + +//______________________________________________________________________________ +GeometryMisAligner::GeometryMisAligner(Double_t cartMisAlig, Double_t angMisAlig) : fUseUni(kTRUE), + fUseGaus(kFALSE), + fXYAngMisAligFactor(0.0), + fZCartMisAligFactor(0.0) +{ + /// Standard constructor + for (Int_t i = 0; i < 6; i++) { + for (Int_t j = 0; j < 2; j++) { + fLadderMisAlig[i][j] = 0.0; + fDiskMisAlig[i][j] = 0.0; + fSensorMisAlig[i][j] = 0.0; + fHalfMisAlig[i][j] = 0.0; + } + } + fLadderMisAlig[0][1] = cartMisAlig; + fLadderMisAlig[1][1] = cartMisAlig; + fLadderMisAlig[5][1] = angMisAlig; +} + +//_____________________________________________________________________________ +GeometryMisAligner::GeometryMisAligner() : fUseUni(kTRUE), + fUseGaus(kFALSE), + fXYAngMisAligFactor(0.0), + fZCartMisAligFactor(0.0) +{ + /// Default constructor + for (Int_t i = 0; i < 6; i++) { + for (Int_t j = 0; j < 2; j++) { + fLadderMisAlig[i][j] = 0.0; + fDiskMisAlig[i][j] = 0.0; + fSensorMisAlig[i][j] = 0.0; + fHalfMisAlig[i][j] = 0.0; + } + } +} + +//_________________________________________________________________________ +void GeometryMisAligner::SetXYAngMisAligFactor(Double_t factor) +{ + /// Set XY angular misalign factor + + if (TMath::Abs(factor) > 1.0 && factor > 0.) { + fXYAngMisAligFactor = factor; + fLadderMisAlig[3][0] = fLadderMisAlig[5][0] * factor; // These lines were + fLadderMisAlig[3][1] = fLadderMisAlig[5][1] * factor; // added to keep + fLadderMisAlig[4][0] = fLadderMisAlig[5][0] * factor; // backward + fLadderMisAlig[4][1] = fLadderMisAlig[5][1] * factor; // compatibility + } else { + LOG(ERROR) << "Invalid XY angular misalign factor, " << factor; + } +} + +//_________________________________________________________________________ +void GeometryMisAligner::SetZCartMisAligFactor(Double_t factor) +{ + /// Set XY angular misalign factor + if (TMath::Abs(factor) < 1.0 && factor > 0.) { + fZCartMisAligFactor = factor; + fLadderMisAlig[2][0] = fLadderMisAlig[0][0]; + fLadderMisAlig[2][1] = fLadderMisAlig[0][1] * factor; + } else { + LOG(ERROR) << "Invalid Z cartesian misalign factor, " << factor; + } +} + +//_________________________________________________________________________ +void GeometryMisAligner::GetUniMisAlign(double cartMisAlig[3], double angMisAlig[3], const double lParMisAlig[6][2]) const +{ + /// Misalign using uniform distribution + + /// misalign the centre of the local transformation + /// rotation axes : + /// fAngMisAlig[1,2,3] = [x,y,z] + /// Assume that misalignment about the x and y axes (misalignment of z plane) + /// is much smaller, since the entire detection plane has to be moved (the + /// detection elements are on a support structure), while rotation of the x-y + /// plane is more free. + + cartMisAlig[0] = gRandom->Uniform(-lParMisAlig[0][1] + lParMisAlig[0][0], lParMisAlig[0][0] + lParMisAlig[0][1]); + cartMisAlig[1] = gRandom->Uniform(-lParMisAlig[1][1] + lParMisAlig[1][0], lParMisAlig[1][0] + lParMisAlig[1][1]); + cartMisAlig[2] = gRandom->Uniform(-lParMisAlig[2][1] + lParMisAlig[2][0], lParMisAlig[2][0] + lParMisAlig[2][1]); + + angMisAlig[0] = gRandom->Uniform(-lParMisAlig[3][1] + lParMisAlig[3][0], lParMisAlig[3][0] + lParMisAlig[3][1]); + angMisAlig[1] = gRandom->Uniform(-lParMisAlig[4][1] + lParMisAlig[4][0], lParMisAlig[4][0] + lParMisAlig[4][1]); + angMisAlig[2] = gRandom->Uniform(-lParMisAlig[5][1] + lParMisAlig[5][0], lParMisAlig[5][0] + lParMisAlig[5][1]); // degrees +} + +//_________________________________________________________________________ +void GeometryMisAligner::GetGausMisAlign(double cartMisAlig[3], double angMisAlig[3], const double lParMisAlig[6][2]) const +{ + /// Misalign using gaussian distribution + + /// misalign the centre of the local transformation + /// rotation axes : + /// fAngMisAlig[1,2,3] = [x,y,z] + /// Assume that misalignment about the x and y axes (misalignment of z plane) + /// is much smaller, since the entire detection plane has to be moved (the + /// detection elements are on a support structure), while rotation of the x-y + /// plane is more free. + + cartMisAlig[0] = gRandom->Gaus(lParMisAlig[0][0], lParMisAlig[0][1]); + cartMisAlig[1] = gRandom->Gaus(lParMisAlig[1][0], lParMisAlig[1][1]); + cartMisAlig[2] = gRandom->Gaus(lParMisAlig[2][0], lParMisAlig[2][1]); + + angMisAlig[0] = gRandom->Gaus(lParMisAlig[3][0], lParMisAlig[3][1]); + angMisAlig[1] = gRandom->Gaus(lParMisAlig[4][0], lParMisAlig[4][1]); + angMisAlig[2] = gRandom->Gaus(lParMisAlig[5][0], lParMisAlig[5][1]); +} + +//_________________________________________________________________________ +TGeoCombiTrans GeometryMisAligner::MisAlignSensor() const +{ + /// Misalign given transformation and return the misaligned transformation. + /// Use misalignment parameters for sensor on the ladder. + /// Note that applied misalignments are small deltas with respect to the detection + /// element own ideal local reference frame. Thus deltaTransf represents + /// the transformation to go from the misaligned sensor local coordinates to the + /// ideal sensor local coordinates. + /// Also note that this -is not- what is in the ALICE alignment framework known + /// as local nor global (see GeometryMisAligner::MisAlign) + + Double_t cartMisAlig[3] = {0, 0, 0}; + Double_t angMisAlig[3] = {0, 0, 0}; + + if (fUseUni) { + GetUniMisAlign(cartMisAlig, angMisAlig, fSensorMisAlig); + } else { + if (!fUseGaus) { + LOG(INFO) << "Neither uniform nor gausian distribution is set! Will use gausian..."; + } + GetGausMisAlign(cartMisAlig, angMisAlig, fSensorMisAlig); + } + + TGeoTranslation deltaTrans(cartMisAlig[0], cartMisAlig[1], cartMisAlig[2]); + TGeoRotation deltaRot; + deltaRot.RotateX(angMisAlig[0]); + deltaRot.RotateY(angMisAlig[1]); + deltaRot.RotateZ(angMisAlig[2]); + + TGeoCombiTrans deltaTransf(deltaTrans, deltaRot); + + return TGeoCombiTrans(deltaTransf); +} + +//_________________________________________________________________________ +TGeoCombiTrans GeometryMisAligner::MisAlignLadder() const +{ + /// Misalign given transformation and return the misaligned transformation. + /// Use misalignment parameters for ladder. + /// Note that applied misalignments are small deltas with respect to the detection + /// element own ideal local reference frame. Thus deltaTransf represents + /// the transformation to go from the misaligned ladder local coordinates to the + /// ideal ladder local coordinates. + /// Also note that this -is not- what is in the ALICE alignment framework known + /// as local nor global (see GeometryMisAligner::MisAlign) + + Double_t cartMisAlig[3] = {0, 0, 0}; + Double_t angMisAlig[3] = {0, 0, 0}; + + if (fUseUni) { + GetUniMisAlign(cartMisAlig, angMisAlig, fLadderMisAlig); + } else { + if (!fUseGaus) { + LOG(INFO) << "Neither uniform nor gausian distribution is set! Will use gausian..."; + } + GetGausMisAlign(cartMisAlig, angMisAlig, fLadderMisAlig); + } + + TGeoTranslation deltaTrans(cartMisAlig[0], cartMisAlig[1], cartMisAlig[2]); + TGeoRotation deltaRot; + deltaRot.RotateX(angMisAlig[0]); + deltaRot.RotateY(angMisAlig[1]); + deltaRot.RotateZ(angMisAlig[2]); + + TGeoCombiTrans deltaTransf(deltaTrans, deltaRot); + + return TGeoCombiTrans(deltaTransf); +} + +//_________________________________________________________________________ +TGeoCombiTrans + GeometryMisAligner::MisAlignHalf() const +{ + /// Misalign given transformation and return the misaligned transformation. + /// Use misalignment parameters for half-MFT. + /// Note that applied misalignments are small deltas with respect to the module + /// own ideal local reference frame. Thus deltaTransf represents + /// the transformation to go from the misaligned half local coordinates to the + /// ideal half local coordinates. + /// Also note that this -is not- what is in the ALICE alignment framework known + /// as local nor global (see GeometryMisAligner::MisAlign) + + Double_t cartMisAlig[3] = {0, 0, 0}; + Double_t angMisAlig[3] = {0, 0, 0}; + + if (fUseUni) { + GetUniMisAlign(cartMisAlig, angMisAlig, fHalfMisAlig); + } else { + if (!fUseGaus) { + LOG(INFO) << "Neither uniform nor gausian distribution is set! Will use gausian..."; + } + GetGausMisAlign(cartMisAlig, angMisAlig, fHalfMisAlig); + } + + TGeoTranslation deltaTrans(cartMisAlig[0], cartMisAlig[1], cartMisAlig[2]); + TGeoRotation deltaRot; + deltaRot.RotateX(angMisAlig[0]); + deltaRot.RotateY(angMisAlig[1]); + deltaRot.RotateZ(angMisAlig[2]); + + TGeoCombiTrans deltaTransf(deltaTrans, deltaRot); + + return TGeoCombiTrans(deltaTransf); +} + +//_________________________________________________________________________ +TGeoCombiTrans + GeometryMisAligner::MisAlignDisk() const +{ + /// Misalign given transformation and return the misaligned transformation. + /// Use misalignment parameters for disk. + /// Note that applied misalignments are small deltas with respect to the module + /// own ideal local reference frame. Thus deltaTransf represents + /// the transformation to go from the misaligned disk local coordinates to the + /// ideal disk local coordinates. + /// Also note that this -is not- what is in the ALICE alignment framework known + /// as local nor global (see GeometryMisAligner::MisAlign) + + Double_t cartMisAlig[3] = {0, 0, 0}; + Double_t angMisAlig[3] = {0, 0, 0}; + + if (fUseUni) { + GetUniMisAlign(cartMisAlig, angMisAlig, fDiskMisAlig); + } else { + if (!fUseGaus) { + LOG(INFO) << "Neither uniform nor gausian distribution is set! Will use gausian..."; + } + GetGausMisAlign(cartMisAlig, angMisAlig, fDiskMisAlig); + } + + TGeoTranslation deltaTrans(cartMisAlig[0], cartMisAlig[1], cartMisAlig[2]); + TGeoRotation deltaRot; + deltaRot.RotateX(angMisAlig[0]); + deltaRot.RotateY(angMisAlig[1]); + deltaRot.RotateZ(angMisAlig[2]); + + TGeoCombiTrans deltaTransf(deltaTrans, deltaRot); + + return TGeoCombiTrans(deltaTransf); +} + +//______________________________________________________________________ +bool GeometryMisAligner::matrixToAngles(const double* rot, double& psi, double& theta, double& phi) +{ + /// Calculates the Euler angles in "x y z" notation + /// using the rotation matrix + /// Returns false in case the rotation angles can not be + /// extracted from the matrix + + if (std::abs(rot[0]) < 1e-7 || std::abs(rot[8]) < 1e-7) { + LOG(ERROR) << "Failed to extract roll-pitch-yall angles!"; + return false; + } + psi = std::atan2(-rot[5], rot[8]); + theta = std::asin(rot[2]); + phi = std::atan2(-rot[1], rot[0]); + return true; +} + +//______________________________________________________________________ +void GeometryMisAligner::MisAlign(Bool_t verbose, const std::string& ccdbHost, long tmin, long tmax, const std::string& objectPath, const std::string& fileName) +{ + /// Takes the internal geometry module transformers, copies them to + /// new geometry module transformers. + /// Calculates module misalignment parameters and applies these + /// to the new module transformer. + /// Calculates the module misalignment delta transformation in the + /// Alice Alignment Framework newTransf = delta * oldTransf. + /// Add a module misalignment to the new geometry transformer. + /// Gets the Detection Elements from the module transformer. + /// Calculates misalignment parameters and applies these + /// to the local transformation of the Detection Element. + /// Obtains the new global transformation by multiplying the new + /// module transformer transformation with the new local transformation. + /// Applies the new global transform to a new detection element. + /// Adds the new detection element to a new module transformer. + /// Calculates the d.e. misalignment delta transformation in the + /// Alice Alignment Framework (newGlobalTransf = delta * oldGlobalTransf). + /// Add a d.e. misalignment to the new geometry transformer. + /// Adds the new module transformer to a new geometry transformer. + /// Returns the new geometry transformer. + + mGeometryTGeo = GeometryTGeo::Instance(); + o2::detectors::AlignParam lAP; + std::vector<o2::detectors::AlignParam> lAPvec; + LOG(INFO) << "GeometryMisAligner::MisAlign "; + + double lPsi, lTheta, lPhi = 0.; + Int_t nAlignID = 0; + Int_t nChip = 0; + Int_t nHalf = mGeometryTGeo->getNumberOfHalfs(); + + for (Int_t hf = 0; hf < nHalf; hf++) { + Int_t nDisks = mGeometryTGeo->getNumberOfDisksPerHalf(hf); + // New module transformation + TGeoCombiTrans localDeltaTransform = MisAlignHalf(); + TString sname = mGeometryTGeo->composeSymNameHalf(hf); + lAP.setSymName(sname); + lAP.setAlignableID(-1); + lAP.setLocalParams(localDeltaTransform); + lAP.applyToGeometry(); + lAPvec.emplace_back(lAP); + + for (Int_t dk = 0; dk < nDisks; dk++) { + localDeltaTransform = MisAlignDisk(); + sname = mGeometryTGeo->composeSymNameDisk(hf, dk); + lAP.setSymName(sname); + lAP.setAlignableID(-1); + LOG(DEBUG) << "**** LocalDeltaTransform Disk: " << fmt::format("{} : {} | X: {:+f} Y: {:+f} Z: {:+f} | pitch: {:+f} roll: {:+f} yaw: {:+f}\n", lAP.getSymName(), lAP.getAlignableID(), localDeltaTransform.GetTranslation()[0], localDeltaTransform.GetTranslation()[1], localDeltaTransform.GetTranslation()[2], localDeltaTransform.GetRotationMatrix()[0], localDeltaTransform.GetRotationMatrix()[1], localDeltaTransform.GetRotationMatrix()[2]); + + lAP.setLocalParams(localDeltaTransform); + lAP.applyToGeometry(); + lAPvec.emplace_back(lAP); + + Int_t nLadders = 0; + for (Int_t sensor = mGeometryTGeo->getMinSensorsPerLadder(); sensor < mGeometryTGeo->getMaxSensorsPerLadder() + 1; sensor++) { + nLadders += mGeometryTGeo->getNumberOfLaddersPerDisk(hf, dk, sensor); + } + + for (Int_t lr = 0; lr < nLadders; lr++) { //nLadders + localDeltaTransform = MisAlignLadder(); + sname = mGeometryTGeo->composeSymNameLadder(hf, dk, lr); + Int_t nSensorsPerLadder = mGeometryTGeo->getNumberOfSensorsPerLadder(hf, dk, lr); + TString path = "/cave_1/barrel_1/" + sname; + lAP.setSymName(sname); + lAP.setAlignableID(-1); + lAP.setLocalParams(localDeltaTransform); + lAP.applyToGeometry(); + lAPvec.emplace_back(lAP); + + for (Int_t sr = 0; sr < nSensorsPerLadder; sr++) { + localDeltaTransform = MisAlignSensor(); + sname = mGeometryTGeo->composeSymNameChip(hf, dk, lr, sr); + if (!matrixToAngles(localDeltaTransform.GetRotationMatrix(), lPsi, lTheta, lPhi)) { + LOG(ERROR) << "Problem extracting angles from sensor"; + } + lAP.setSymName(sname); + Int_t uid = o2::base::GeometryManager::getSensID(o2::detectors::DetID::MFT, nChip++); + lAP.setAlignableID(uid); + lAP.setLocalParams(localDeltaTransform); + lAP.applyToGeometry(); + lAPvec.emplace_back(lAP); + if (verbose) { + LOG(INFO) << "misaligner: " << sname << ", sensor: " << nChip; + } + nChip++; + } + } + } + } + + if (!ccdbHost.empty()) { + std::string path = objectPath.empty() ? o2::base::NameConf::getAlignmentPath(o2::detectors::DetID::MFT) : objectPath; + LOGP(INFO, "Storing alignment object on {}/{}", ccdbHost, path); + o2::ccdb::CcdbApi api; + std::map<std::string, std::string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&lAPvec, path, metadata, tmin, tmax); + } + + if (!fileName.empty()) { + LOGP(INFO, "Storing MFT alignment in local file {}", fileName); + TFile algFile(fileName.c_str(), "recreate"); + algFile.WriteObjectAny(&lAPvec, "std::vector<o2::detectors::AlignParam>", "alignment"); + algFile.Close(); + } +} + +void GeometryMisAligner::SetAlignmentResolution(const TClonesArray* misAlignArray, Int_t rChId, Double_t rChResX, Double_t rChResY, Double_t rDeResX, Double_t rDeResY) +{ + + Int_t chIdMin = (rChId < 0) ? 0 : rChId; + Int_t chIdMax = (rChId < 0) ? 9 : rChId; + Double_t chResX = (rChResX < 0) ? fDiskMisAlig[0][1] : rChResX; + Double_t chResY = (rChResY < 0) ? fDiskMisAlig[1][1] : rChResY; + Double_t deResX = (rDeResX < 0) ? fLadderMisAlig[0][1] : rDeResX; + Double_t deResY = (rDeResY < 0) ? fLadderMisAlig[1][1] : rDeResY; + + TMatrixDSym mChCorrMatrix(6); + mChCorrMatrix[0][0] = chResX * chResX; + mChCorrMatrix[1][1] = chResY * chResY; + + TMatrixDSym mDECorrMatrix(6); + mDECorrMatrix[0][0] = deResX * deResX; + mDECorrMatrix[1][1] = deResY * deResY; + + // not yet implemented +} diff --git a/Detectors/ITSMFT/MFT/simulation/src/MFTSimulationLinkDef.h b/Detectors/ITSMFT/MFT/simulation/src/MFTSimulationLinkDef.h index 8d9c88c94ef29..f768448b3ef6c 100644 --- a/Detectors/ITSMFT/MFT/simulation/src/MFTSimulationLinkDef.h +++ b/Detectors/ITSMFT/MFT/simulation/src/MFTSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,5 +18,6 @@ #pragma link C++ class o2::mft::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::mft::Detector> + ; #pragma link C++ class o2::mft::DigitizerTask + ; +#pragma link C++ class o2::mft::GeometryMisAligner + ; #endif diff --git a/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx b/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx index 4158628616e16..57dab3e28e1e5 100644 --- a/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx +++ b/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,6 @@ #include <boost/program_options.hpp> #include <TTree.h> -#include <TSystem.h> #include <TChain.h> #include <TFile.h> #include <TStopwatch.h> @@ -21,6 +21,7 @@ #include <vector> #include <string> #include <iomanip> +#include <filesystem> #include "ITSMFTReconstruction/ChipMappingMFT.h" #include "ITSMFTReconstruction/GBTWord.h" #include "DataFormatsITSMFT/ROFRecord.h" @@ -60,6 +61,7 @@ int main(int argc, char** argv) uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); opt_all.add(opt_general).add(opt_hidden); @@ -80,6 +82,11 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); digi2raw(vm["input-file"].as<std::string>(), vm["output-dir"].as<std::string>(), @@ -87,6 +94,9 @@ int main(int argc, char** argv) vm["verbosity"].as<uint32_t>(), vm["rdh-version"].as<uint32_t>(), vm["no-empty-hbf"].as<bool>()); + LOG(INFO) << "HBFUtils settings used for conversion:"; + + o2::raw::HBFUtils::Instance().print(); return 0; } @@ -103,13 +113,14 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie o2::raw::HBFUtils::Instance().print(); // if needed, create output directory - if (gSystem->AccessPathName(outDir.data())) { - if (gSystem->mkdir(outDir.data(), kTRUE)) { + if (!std::filesystem::exists(outDir)) { + if (!std::filesystem::create_directories(outDir)) { LOG(FATAL) << "could not create output directory " << outDir; } else { LOG(INFO) << "created output directory " << outDir; } } + ///-------> input std::string digTreeName{o2::base::NameConf::MCTTREENAME.data()}; TChain digTree(digTreeName.c_str()); @@ -117,7 +128,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie digTree.SetBranchStatus("*MCTruth*", 0); // ignore MC info std::vector<o2::itsmft::Digit> digiVec, *digiVecP = &digiVec; - std::string digBranchName = o2::utils::concat_string(MAP::getName(), "Digit"); + std::string digBranchName = o2::utils::Str::concat_string(MAP::getName(), "Digit"); if (!digTree.GetBranch(digBranchName.c_str())) { LOG(FATAL) << "Failed to find the branch " << digBranchName << " in the tree " << digTreeName; } @@ -125,7 +136,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie // ROF record entries in the digit tree ROFRVEC rofRecVec, *rofRecVecP = &rofRecVec; - std::string rofRecName = o2::utils::concat_string(MAP::getName(), "DigitROF"); + std::string rofRecName = o2::utils::Str::concat_string(MAP::getName(), "DigitROF"); if (!digTree.GetBranch(rofRecName.c_str())) { LOG(FATAL) << "Failed to find the branch " << rofRecName << " in the tree " << digTreeName; } @@ -137,7 +148,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie o2::itsmft::MC2RawEncoder<MAP> m2r; m2r.setVerbosity(verbosity); m2r.setContinuousReadout(grp->isDetContinuousReadOut(MAP::getDetID())); // must be set explicitly - m2r.setDefaultSinkName(o2::utils::concat_string(MAP::getName(), ".raw")); + m2r.setDefaultSinkName(o2::utils::Str::concat_string(MAP::getName(), ".raw")); m2r.setMinMaxRUSW(ruSWMin, ruSWMax); m2r.getWriter().setSuperPageSize(superPageSizeInB); m2r.getWriter().useRDHVersion(rdhV); @@ -168,7 +179,7 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie } } // loop over multiple ROFvectors (in case of chaining) - m2r.getWriter().writeConfFile(MAP::getName(), "RAWDATA", o2::utils::concat_string(outDir, '/', MAP::getName(), "raw.cfg")); + m2r.getWriter().writeConfFile(MAP::getName(), "RAWDATA", o2::utils::Str::concat_string(outDir, '/', MAP::getName(), "raw.cfg")); m2r.finalize(); // finish TF and flush data // swTot.Stop(); @@ -228,7 +239,6 @@ void setupLinks(o2::itsmft::MC2RawEncoder<MAP>& m2r, std::string_view outDir, st int ruID = nRUtot++; bool accept = !(ruSW < m2r.getRUSWMin() || ruSW > m2r.getRUSWMax()); // ignored RUs ? - int accL = 0; if (accept) { m2r.getCreateRUDecode(ruSW); // create RU container nRU++; @@ -237,12 +247,11 @@ void setupLinks(o2::itsmft::MC2RawEncoder<MAP>& m2r, std::string_view outDir, st uint32_t lanes = mp.getCablesOnRUType(ru.ruInfo->ruType); // lanes patter of this RU ru.links[0] = m2r.addGBTLink(); auto link = m2r.getGBTLink(ru.links[0]); - link->lanes = lanes & ((0x1 << lnkAs) - 1) << (accL); + link->lanes = lanes; link->idInCRU = linkID; link->cruID = cruIDtmp * 100 + o2::detectors::DetID::MFT; link->feeID = mp.RUSW2FEEId(ruSW); link->endPointID = 0; // 0 or 1 - accL += lnkAs; // register the link in the writer, if not done here, its data will be dumped to common default file //printf("Register link: FeeID 0x%02x , CRU ID 0x%x , link ID %2d \n", link->feeID, link->cruID, link->idInCRU); //printf("RU SW: %2d HW: 0x%02x Type: %2d %s \n", ruSW, ruHW, ruType, outFileLink.data()); @@ -250,14 +259,14 @@ void setupLinks(o2::itsmft::MC2RawEncoder<MAP>& m2r, std::string_view outDir, st //LOG(INFO) << "with lanes " << bv_lanes; if (fileFor == "all") { // single file for all links - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, ".raw"); + outFileLink = o2::utils::Str::concat_string(outDir, "/", outPrefix, ".raw"); } else if (fileFor == "layer") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_lr", std::to_string(ilr), ".raw"); + outFileLink = o2::utils::Str::concat_string(outDir, "/", outPrefix, "_lr", std::to_string(ilr), ".raw"); } else if (fileFor == "cru") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(link->cruID), ".raw"); + outFileLink = o2::utils::Str::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(link->cruID), ".raw"); } else if (fileFor == "link") { - outFileLink = o2::utils::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(cruID), - "_link", std::to_string(linkID), "_ep", std::to_string(link->endPointID), ".raw"); + outFileLink = o2::utils::Str::concat_string(outDir, "/", outPrefix, "_cru", std::to_string(link->cruID), + "_link", std::to_string(linkID), "_ep", std::to_string(link->endPointID), "_feeid", std::to_string(link->feeID), ".raw"); } else { throw std::runtime_error("invalid option provided for file grouping"); } diff --git a/Detectors/ITSMFT/MFT/tracking/CMakeLists.txt b/Detectors/ITSMFT/MFT/tracking/CMakeLists.txt index 1ec7e28dc5ce2..7f8fcf79d08ae 100644 --- a/Detectors/ITSMFT/MFT/tracking/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/tracking/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MFTTracking TARGETVARNAME targetName @@ -14,8 +15,9 @@ o2_add_library(MFTTracking src/ROframe.cxx src/Cluster.cxx src/IOUtils.cxx - src/TrackFitter.cxx - src/MFTTrackingParam.cxx + src/TrackFitter.cxx + src/MFTTrackingParam.cxx + src/TrackerConfig.cxx PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::DataFormatsITSMFT O2::SimulationDataFormat @@ -27,4 +29,5 @@ o2_target_root_dictionary(MFTTracking HEADERS include/MFTTracking/TrackCA.h HEADERS include/MFTTracking/TrackFitter.h HEADERS include/MFTTracking/MFTTrackingParam.h + HEADERS include/MFTTracking/TrackerConfig.h LINKDEF src/MFTTrackingLinkDef.h) diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cell.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cell.h index 68b6a47150fe4..d80bdd8e7ed7d 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cell.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cell.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,10 +27,11 @@ namespace o2 namespace mft { -class Cell final +class Cell { public: Cell(); + /// layer1, layer2, clsInLayer1, clsInLayer2, cellId; set level = 1 Cell(const Int_t, const Int_t, const Int_t, const Int_t, const Int_t); const Int_t getFirstLayerId() const; @@ -51,6 +53,23 @@ class Cell final const UChar_t getNLeftNeighbours() const { return mNLeftNeighbours; } const UChar_t getNRightNeighbours() const { return mNRightNeighbours; } + void setCoordinates(Float_t* coord) + { + mCoord[0] = coord[0]; // X1 + mCoord[1] = coord[1]; // Y1 + mCoord[2] = coord[2]; // Z1 + mCoord[3] = coord[3]; // X2 + mCoord[4] = coord[4]; // Y2 + mCoord[5] = coord[5]; // Z2 + } + + const Float_t getX1() const { return mCoord[0]; } + const Float_t getY1() const { return mCoord[1]; } + const Float_t getZ1() const { return mCoord[2]; } + const Float_t getX2() const { return mCoord[3]; } + const Float_t getY2() const { return mCoord[4]; } + const Float_t getZ2() const { return mCoord[5]; } + private: const Int_t mFirstLayerId; const Int_t mSecondLayerId; @@ -64,6 +83,7 @@ class Cell final UChar_t mNRightNeighbours; std::array<std::pair<Int_t, Int_t>, constants::mft::MaxCellNeighbours> mLeftNeighbours; std::array<std::pair<Int_t, Int_t>, constants::mft::MaxCellNeighbours> mRightNeighbours; + Float_t mCoord[6]; }; inline Cell::Cell() @@ -93,7 +113,6 @@ inline Cell::Cell(const Int_t firstLayerId, const Int_t secondLayerId, const Int mNLeftNeighbours{0}, mNRightNeighbours{0} { - // Nothing to do } inline const Int_t Cell::getFirstLayerId() const { return mFirstLayerId; } @@ -113,24 +132,16 @@ inline void Cell::setLevel(const Int_t level) { mLevel = level; } inline void Cell::addRightNeighbour(const Int_t layer, const Int_t clusterId) { - //std::cout << "Cell::addRightNeighbour " << layer << " " << clusterId << std::endl; - try { - mRightNeighbours.at(mNRightNeighbours++) = std::pair<Int_t, Int_t>(layer, clusterId); - } catch (const std::out_of_range& err) { - std::cout << "Maximum number of right neighbours for this cell!" << std::endl; - } - //std::cout << "Cell::addRightNeighbour done..." << std::endl; + mRightNeighbours.at(mNRightNeighbours++) = std::pair<Int_t, Int_t>(layer, clusterId); } inline void Cell::addLeftNeighbour(const Int_t layer, const Int_t clusterId) { - //std::cout << "Cell::addLeftNeighbour " << layer << " " << clusterId << std::endl; try { mLeftNeighbours.at(mNLeftNeighbours++) = std::pair<Int_t, Int_t>(layer, clusterId); } catch (const std::out_of_range& err) { std::cout << "Maximum number of left neighbours for this cell!" << std::endl; } - //std::cout << "Cell::addLeftNeighbour done..." << std::endl; } inline const std::array<std::pair<Int_t, Int_t>, constants::mft::MaxCellNeighbours>& Cell::getLeftNeighbours() const diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cluster.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cluster.h index 851151caa71a2..711e0a06ba742 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cluster.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,6 @@ #include <array> #include "ReconstructionDataFormats/BaseCluster.h" -#include "MFTTracking/IndexTableUtils.h" #include "GPUCommonDef.h" namespace o2 @@ -34,9 +34,12 @@ struct Cluster : public o2::BaseCluster<float> { clusterId{id}, indexTableBin{bin}, sigmaX2{sigX2}, - sigmaY2{sigY2} {}; + sigmaY2{sigY2}, + isUsed{false} {}; Cluster(const Float_t x, const Float_t y, const Float_t z, const Int_t index); - Cluster(const Int_t layerIndex, const Cluster& other); + + void setUsed(Bool_t bval) { isUsed = bval; } + const Bool_t getUsed() { return isUsed; } Float_t phiCoordinate; Float_t rCoordinate; @@ -44,6 +47,7 @@ struct Cluster : public o2::BaseCluster<float> { Int_t indexTableBin; Float_t sigmaX2; Float_t sigmaY2; + Bool_t isUsed; }; } // namespace mft diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Constants.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Constants.h index 26a1f51555f1a..7651c131b93fa 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Constants.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include <climits> #include <vector> +#include <array> #include <Rtypes.h> @@ -47,11 +49,9 @@ constexpr std::array<Float_t, LayersNumber> InverseLayerZCoordinate() { return std::array<Float_t, LayersNumber>{-1. / 45.3, -1. / 46.7, -1. / 48.6, -1. / 50.0, -1. / 52.4, -1. / 53.8, -1. / 67.7, -1. / 69.1, -1. / 76.1, -1. / 77.5}; } -constexpr Int_t MinTrackPoints{4}; -constexpr Int_t MaxTrackPoints{20}; -constexpr Float_t LTFclsRCut{0.0100}; -constexpr Float_t ROADclsRCut{0.0400}; -constexpr Int_t MaxCellNeighbours{10}; +constexpr Int_t MaxCellNeighbours{50}; +constexpr Int_t MaxPointsInRoad{100}; +constexpr Int_t MaxCellsInRoad{100}; } // namespace mft namespace index_table @@ -62,33 +62,7 @@ constexpr Float_t RMax{16.0}; constexpr Float_t PhiMin{0.}; constexpr Float_t PhiMax{o2::constants::math::TwoPI}; // [rad] -constexpr Int_t RBins{50}; -constexpr Int_t PhiBins{50}; - -constexpr Float_t InversePhiBinSize{PhiBins / (PhiMax - PhiMin)}; -constexpr Float_t InverseRBinSize{RBins / (RMax - RMin)}; - -constexpr UChar_t LTFseed2BinWin{3}; -constexpr UChar_t LTFinterBinWin{3}; - -constexpr Int_t getRBinIndex(const Float_t r) -{ - return (Int_t)((r - RMin) * InverseRBinSize); -} - -constexpr Int_t getPhiBinIndex(const Float_t phi) -{ - return (Int_t)((phi - PhiMin) * InversePhiBinSize); -} - -constexpr Int_t getBinIndex(const Int_t rIndex, const Int_t phiIndex) -{ - if (0 <= rIndex && rIndex < RBins && - 0 <= phiIndex && phiIndex < PhiBins) { - return (phiIndex * RBins + rIndex); - } - return -1; -} +constexpr Int_t MaxRPhiBins{100 * 100}; } // namespace index_table } // namespace constants diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h index 99d2b3a15aaf7..ea8986348820e 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include <vector> #include <gsl/gsl> +#include "MFTTracking/Tracker.h" #include "MFTTracking/ROframe.h" #include "ITSMFTBase/SegmentationAlpide.h" #include "DataFormatsITSMFT/ROFRecord.h" @@ -56,8 +58,12 @@ constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; int loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& events, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, - const dataformats::MCTruthContainer<MCCompLabel>* mClsLabels = nullptr); + const dataformats::MCTruthContainer<MCCompLabel>* mClsLabels = nullptr, const o2::mft::Tracker* tracker = nullptr); +void convertCompactClusters(gsl::span<const itsmft::CompClusterExt> clusters, + gsl::span<const unsigned char>::iterator& pattIt, + std::vector<o2::BaseCluster<float>>& output, + const itsmft::TopologyDictionary& dict); } // namespace ioutils } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IndexTableUtils.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IndexTableUtils.h deleted file mode 100644 index 85729dabe08b5..0000000000000 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IndexTableUtils.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file IndexTableUtils.h -/// \brief May collect the functions to place clusters into R-Phi bins (to be fixed) -/// - -#ifndef O2_MFT_INDEXTABLEUTILS_H_ -#define O2_MFT_INDEXTABLEUTILS_H_ - -#include <array> -#include <utility> -#include <vector> - -#include "MFTTracking/Constants.h" - -namespace o2 -{ -namespace mft -{ - -namespace index_table_utils -{ -Int_t getRBinIndex(const Int_t, const Float_t); -Int_t getPhiBinIndex(const Float_t); -Int_t getBinIndex(const Int_t, const Int_t); -} // namespace IndexTableUtils - -inline Int_t index_table_utils::getRBinIndex(const Int_t layerIndex, const Float_t rCoordinate) -{ - return -1; -} - -inline Int_t index_table_utils::getPhiBinIndex(const Float_t currentPhi) -{ - return -1; -} - -inline Int_t index_table_utils::getBinIndex(const Int_t rIndex, const Int_t phiIndex) -{ - return -1; -} -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_INDEXTABLEUTILS_H_ */ diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h index c28807bdc959b..f51addc167c26 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,17 +25,46 @@ namespace mft enum MFTTrackModel { Helix, Quadratic, - Linear + Linear, + Optimized // Parameter propagation with helix model; covariance propagation with quadratic model }; // ** // ** Parameters for MFT tracking configuration // ** struct MFTTrackingParam : public o2::conf::ConfigurableParamHelper<MFTTrackingParam> { - Int_t trackmodel = MFTTrackModel::Helix; - double MFTRadLength = 1.0; // MFT average material budget within acceptance. Should be 0.041 + Int_t trackmodel = MFTTrackModel::Optimized; + double MFTRadLength = 0.042; // MFT average material budget within acceptance bool verbose = false; + /// tracking algorithm (LTF and CA) parameters + /// minimum number of points for a LTF track + Int_t MinTrackPointsLTF = 5; + /// minimum number of points for a CA track + Int_t MinTrackPointsCA = 4; + /// minimum number of detector stations for a LTF track + Int_t MinTrackStationsLTF = 4; + /// minimum number of detector stations for a CA track + Int_t MinTrackStationsCA = 4; + /// maximum distance for a cluster to be attached to a seed line (LTF) + Float_t LTFclsRCut = 0.0100; + /// maximum distance for a cluster to be attached to a seed line (CA road) + Float_t ROADclsRCut = 0.0400; + /// number of bins in r-direction + Int_t RBins = 50; + /// number of bins in phi-direction + Int_t PhiBins = 50; + /// RPhi search window bin width for the second point of a seed (LTF and CA) + Int_t LTFseed2BinWin = 3; + /// RPhi search window bin width for the intermediate points + Int_t LTFinterBinWin = 3; + /// Special version for TED shots and cosmics, with full scan of the clusters + bool FullClusterScan = false; + /// road for LTF algo : cylinder or cone (default) + Bool_t LTFConeRadius = kFALSE; + /// road for CA algo : cylinder or cone (default) + Bool_t CAConeRadius = kFALSE; + O2ParamDef(MFTTrackingParam, "MFTTracking"); }; diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h index f6f0b039a8ad8..b267cd6cbe9ac 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ namespace mft class TrackCA; class TrackLTF; -class ROframe final +class ROframe { public: ROframe(Int_t ROframeId); @@ -48,57 +49,48 @@ class ROframe final void setROFrameId(const Int_t rofid) { mROframeId = rofid; } - const std::array<std::vector<Cluster>, constants::mft::LayersNumber>& getClusters() const { return mClusters; } - const std::vector<Cluster>& getClustersInLayer(Int_t layerId) const { return mClusters[layerId]; } + std::vector<Cluster>& getClustersInLayer(Int_t layerId) { return mClusters[layerId]; } - const MCCompLabel& getClusterLabels(Int_t layerId, const Cluster& cl) const { return mClusterLabels[layerId][cl.clusterId]; } const MCCompLabel& getClusterLabels(Int_t layerId, const Int_t clusterId) const { return mClusterLabels[layerId][clusterId]; } - const std::map<Int_t, std::pair<Int_t, Int_t>>& getClusterBinIndexRange(Int_t layerId) const { return mClusterBinIndexRange[layerId]; } + const std::array<std::pair<Int_t, Int_t>, constants::index_table::MaxRPhiBins>& getClusterBinIndexRange(Int_t layerId) const { return mClusterBinIndexRange[layerId]; } + const Int_t getClusterExternalIndex(Int_t layerId, const Int_t clusterId) const { return mClusterExternalIndices[layerId][clusterId]; } - const std::array<std::vector<Cell>, constants::mft::LayersNumber>& getCells() const; - const std::vector<Cell>& getCellsInLayer(Int_t layerId) const { return mCells[layerId]; } std::vector<TrackLTF>& getTracksLTF(); TrackLTF& getCurrentTrackLTF(); - void removeCurrentTrackLTF(); - Road& getCurrentRoad(); - void removeCurrentRoad(); - std::vector<Road>& getRoads(); + std::vector<TrackCA>& getTracksCA(); TrackCA& getCurrentTrackCA(); - void removeCurrentTrackCA(); - template <typename... T> - void addClusterToLayer(Int_t layer, T&&... args); + Road& getCurrentRoad(); template <typename... T> - void addCellToLayer(Int_t layer, T&&... args); + void addClusterToLayer(Int_t layer, T&&... args); void addClusterLabelToLayer(Int_t layer, const MCCompLabel label); void addClusterExternalIndexToLayer(Int_t layer, const Int_t idx); - void addClusterBinIndexRangeToLayer(Int_t layer, const std::pair<Int_t, std::pair<Int_t, Int_t>> range); + void addTrackLTF() { mTracksLTF.emplace_back(); } - void addTrackCA(); + void addTrackCA(const Int_t); + void addRoad(); - void initialise(); - void sortClusters(); + void initialize(bool fullClusterScan = false); - Bool_t isClusterUsed(Int_t layer, Int_t clusterId) const; - void markUsedCluster(Int_t layer, Int_t clusterId); + void sortClusters(); void clear(); + const Int_t getNClustersInLayer(Int_t layerId) const { return mClusters[layerId].size(); } + private: Int_t mROframeId; std::array<std::vector<Cluster>, constants::mft::LayersNumber> mClusters; std::array<std::vector<MCCompLabel>, constants::mft::LayersNumber> mClusterLabels; std::array<std::vector<Int_t>, constants::mft::LayersNumber> mClusterExternalIndices; - std::array<std::map<Int_t, std::pair<Int_t, Int_t>>, constants::mft::LayersNumber> mClusterBinIndexRange; - std::array<std::vector<Bool_t>, constants::mft::LayersNumber> mUsedClusters; - std::array<std::vector<Cell>, constants::mft::LayersNumber> mCells; + std::array<std::array<std::pair<Int_t, Int_t>, constants::index_table::MaxRPhiBins>, constants::mft::LayersNumber> mClusterBinIndexRange; std::vector<TrackLTF> mTracksLTF; std::vector<TrackCA> mTracksCA; std::vector<Road> mRoads; @@ -117,34 +109,11 @@ inline void ROframe::addClusterExternalIndexToLayer(Int_t layer, const Int_t idx mClusterExternalIndices[layer].push_back(idx); } -inline void ROframe::addClusterBinIndexRangeToLayer(Int_t layer, const std::pair<Int_t, std::pair<Int_t, Int_t>> range) -{ - mClusterBinIndexRange[layer].insert(range); -} - -template <typename... T> -void ROframe::addCellToLayer(Int_t layer, T&&... values) -{ - mCells[layer].emplace_back(layer, std::forward<T>(values)...); -} - -inline Bool_t ROframe::isClusterUsed(Int_t layer, Int_t clusterId) const -{ - return mUsedClusters[layer][clusterId]; -} - -inline void ROframe::markUsedCluster(Int_t layer, Int_t clusterId) { mUsedClusters[layer][clusterId] = kTRUE; } - inline TrackLTF& ROframe::getCurrentTrackLTF() { return mTracksLTF.back(); } -inline void ROframe::removeCurrentTrackLTF() -{ - mTracksLTF.pop_back(); -} - inline std::vector<TrackLTF>& ROframe::getTracksLTF() { return mTracksLTF; @@ -153,7 +122,6 @@ inline std::vector<TrackLTF>& ROframe::getTracksLTF() inline void ROframe::addRoad() { mRoads.emplace_back(); - mRoads.back().setRoadId(mRoads.size() - 1); } inline Road& ROframe::getCurrentRoad() @@ -161,28 +129,16 @@ inline Road& ROframe::getCurrentRoad() return mRoads.back(); } -inline void ROframe::removeCurrentRoad() -{ - mRoads.pop_back(); -} - -inline std::vector<Road>& ROframe::getRoads() +inline void ROframe::addTrackCA(const Int_t roadId) { - return mRoads; + mTracksCA.emplace_back(); } -inline void ROframe::addTrackCA() { mTracksCA.emplace_back(); } - inline TrackCA& ROframe::getCurrentTrackCA() { return mTracksCA.back(); } -inline void ROframe::removeCurrentTrackCA() -{ - mTracksCA.pop_back(); -} - inline std::vector<TrackCA>& ROframe::getTracksCA() { return mTracksCA; @@ -194,8 +150,9 @@ inline void ROframe::clear() mClusters[iLayer].clear(); mClusterLabels[iLayer].clear(); mClusterExternalIndices[iLayer].clear(); - mClusterBinIndexRange[iLayer].clear(); - mCells[iLayer].clear(); + for (Int_t iBin = 0; iBin < constants::index_table::MaxRPhiBins; ++iBin) { + mClusterBinIndexRange[iLayer][iBin] = std::pair<Int_t, Int_t>(0, -1); + } } mTracksLTF.clear(); mTracksCA.clear(); diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Road.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Road.h index c458549c4bdad..f03bb498586ec 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Road.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Road.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,99 +18,85 @@ #include "MFTTracking/Cell.h" #include "MFTTracking/Constants.h" -#include "SimulationDataFormat/MCCompLabel.h" namespace o2 { namespace mft { -class Road final +class Road { public: - Road(); - void setPoint(const Float_t x, const Float_t y, const Float_t z, const Int_t layer, const Int_t clusterId, const MCCompLabel label, Bool_t& newPoint); + Road() { mRoadId = 0; }; + void reset(); + void initialize(); + + void setPoint(const Int_t layer, const Int_t clusterId) + { + mClusterId[layer].push_back(clusterId); + } + void setRoadId(const Int_t id) { mRoadId = id; } const Int_t getRoadId() const { return mRoadId; } - void setNDisks(const Int_t nd) { mNDisks = nd; } - const Int_t getNDisks() const { return mNDisks; } - const Int_t getNPoints() const { return mNPoints; } + const Int_t getNPointsInLayer(Int_t layer) const; + void getLength(Int_t& layer1, Int_t& layer2) const; - void setHasTracksCA() { mHasTracksCA = kTRUE; } - const Bool_t hasTracksCA() const; - const std::vector<Float_t>& getXCoordinatesInLayer(Int_t layer) const { return mX[layer]; } - const std::vector<Float_t>& getYCoordinatesInLayer(Int_t layer) const { return mY[layer]; } - const std::vector<Float_t>& getZCoordinatesInLayer(Int_t layer) const { return mZ[layer]; } const std::vector<Int_t>& getClustersIdInLayer(Int_t layer) const { return mClusterId[layer]; } - const std::vector<MCCompLabel>& getMCCompLabelsInLayer(Int_t layer) const { return mMCCompLabel[layer]; } template <typename... T> - void addCellToLayer(Int_t layer, T&&... args); + Cell& addCellInLayer(Int_t layer, T&&... args); + + std::vector<Cell>& getCellsInLayer(Int_t); - const std::vector<Cell>& getCellsInLayer(Int_t) const; void addLeftNeighbourToCell(const Int_t, const Int_t, const Int_t, const Int_t); void addRightNeighbourToCell(const Int_t, const Int_t, const Int_t, const Int_t); + void incrementCellLevel(const Int_t, const Int_t); void updateCellLevel(const Int_t, const Int_t); + + void setCellLevel(const Int_t, const Int_t, const Int_t); const Int_t getCellLevel(const Int_t, const Int_t) const; - const Bool_t isCellUsed(const Int_t, const Int_t) const; void setCellUsed(const Int_t, const Int_t, const Bool_t); - void setCellLevel(const Int_t, const Int_t, const Int_t); + const Bool_t isCellUsed(const Int_t, const Int_t) const; private: Int_t mRoadId; - Int_t mNDisks; - Int_t mNPoints; - Bool_t mHasTracksCA; - std::array<std::vector<Float_t>, constants::mft::LayersNumber> mX; - std::array<std::vector<Float_t>, constants::mft::LayersNumber> mY; - std::array<std::vector<Float_t>, constants::mft::LayersNumber> mZ; std::array<std::vector<Int_t>, constants::mft::LayersNumber> mClusterId; - std::array<std::vector<MCCompLabel>, constants::mft::LayersNumber> mMCCompLabel; std::array<std::vector<Cell>, (constants::mft::LayersNumber - 1)> mCell; }; -inline Road::Road() - : mRoadId{0}, - mNDisks{0}, - mNPoints{0} +inline void Road::reset() { - // Nothing to do + Int_t layer; + for (layer = 0; layer < (constants::mft::LayersNumber - 1); ++layer) { + mCell[layer].clear(); + mClusterId[layer].clear(); + } + mClusterId[layer].clear(); } -inline void Road::setPoint(const Float_t x, const Float_t y, const Float_t z, const Int_t layer, const Int_t clusterId, const MCCompLabel label, Bool_t& newPoint) +inline void Road::initialize() { - if (!newPoint) { - if (!mZ.empty()) { - mX[layer].pop_back(); - mY[layer].pop_back(); - mZ[layer].pop_back(); - mClusterId[layer].pop_back(); - mMCCompLabel[layer].pop_back(); - } - } else { // end replace point - newPoint = kFALSE; + Int_t layer; + for (layer = 0; layer < (constants::mft::LayersNumber - 1); ++layer) { + mCell[layer].reserve(constants::mft::MaxCellsInRoad); + mClusterId[layer].reserve(constants::mft::MaxPointsInRoad); } - mX[layer].push_back(x); - mY[layer].push_back(y); - mZ[layer].push_back(z); - mClusterId[layer].push_back(clusterId); - mMCCompLabel[layer].emplace_back(label); - ++mNPoints; + mClusterId[layer].reserve(constants::mft::MaxPointsInRoad); } inline const Int_t Road::getNPointsInLayer(Int_t layer) const { - return mX[layer].size(); + return mClusterId[layer].size(); } inline void Road::getLength(Int_t& layer1, Int_t& layer2) const { layer1 = -1, layer2 = 10; for (Int_t layer = 0; layer < constants::mft::LayersNumber; ++layer) { - if (mX[layer].size() > 0) { + if (mClusterId[layer].size() > 0) { if (layer1 < 0) { layer1 = layer; } @@ -118,18 +105,14 @@ inline void Road::getLength(Int_t& layer1, Int_t& layer2) const } } -inline const Bool_t Road::hasTracksCA() const -{ - return mHasTracksCA; -} - template <typename... T> -void Road::addCellToLayer(Int_t layer, T&&... values) +Cell& Road::addCellInLayer(Int_t layer, T&&... values) { mCell[layer].emplace_back(layer, std::forward<T>(values)...); + return mCell[layer].back(); } -inline const std::vector<Cell>& Road::getCellsInLayer(Int_t layer) const +inline std::vector<Cell>& Road::getCellsInLayer(Int_t layer) { return mCell[layer]; } diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h index 779c75efe27f5..33911f1c47abd 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,7 +42,7 @@ class TrackLTF : public TrackMFTExt const std::array<Int_t, constants::mft::LayersNumber>& getLayers() const { return mLayer; } const std::array<Int_t, constants::mft::LayersNumber>& getClustersId() const { return mClusterId; } const std::array<MCCompLabel, constants::mft::LayersNumber>& getMCCompLabels() const { return mMCCompLabels; } - void setPoint(const Cluster, const Int_t layer, const Int_t clusterId, const MCCompLabel label, const Int_t extClsIndex, Bool_t& newPoint); + void setPoint(const Cluster& cl, const Int_t layer, const Int_t clusterId, const MCCompLabel label, const Int_t extClsIndex); void sort(); @@ -54,97 +55,50 @@ class TrackLTF : public TrackMFTExt std::array<Int_t, constants::mft::LayersNumber> mLayer; std::array<Int_t, constants::mft::LayersNumber> mClusterId; std::array<MCCompLabel, constants::mft::LayersNumber> mMCCompLabels; + + ClassDefNV(TrackLTF, 10); }; //_________________________________________________________________________________________________ class TrackCA : public TrackLTF { public: - TrackCA() = default; + TrackCA() + { + TrackLTF(); + this->setCA(true); + } TrackCA(const TrackCA& t) = default; ~TrackCA() = default; - void addCell(const Int_t, const Int_t); - void removeLastCell(Int_t&, Int_t&); - const Int_t getNCells() const { return mNCells; } - void setRoadId(const Int_t rid) { mRoadId = rid; } - const Int_t getRoadId() const { return mRoadId; } - void setChiSquareZX(const Float_t chisq) { mChiSquareZX = chisq; } - void setChiSquareZY(const Float_t chisq) { mChiSquareZY = chisq; } - const Float_t getChiSquareZX() const { return mChiSquareZX; } - const Float_t getChiSquareZY() const { return mChiSquareZY; } - - const std::array<Int_t, constants::mft::LayersNumber>& getCellsLayer() const { return mCellLayer; } - const std::array<Int_t, constants::mft::LayersNumber>& getCellsId() const { return mCellId; } private: - Int_t mNCells{0}; - Int_t mRoadId{-1}; - Float_t mChiSquareZX{0.}; - Float_t mChiSquareZY{0.}; - - std::array<Int_t, constants::mft::LayersNumber> mCellLayer; - std::array<Int_t, constants::mft::LayersNumber> mCellId; - ClassDefNV(TrackCA, 2); + ClassDefNV(TrackCA, 10); }; //_________________________________________________________________________________________________ -inline void TrackCA::addCell(const Int_t layer, const Int_t cellId) -{ - mCellLayer[mNCells] = layer; - mCellId[mNCells] = cellId; - mNCells++; -} - -//_________________________________________________________________________________________________ -inline void TrackCA::removeLastCell(Int_t& layer, Int_t& cellId) +inline void TrackLTF::setPoint(const Cluster& cl, const Int_t layer, const Int_t clusterId, const MCCompLabel label, const Int_t extClsIndex) { - layer = mCellLayer[mNCells - 1]; - cellId = mCellId[mNCells - 1]; - auto nPoints = getNumberOfPoints(); - if (nPoints == 2) { // we have only a single cell in the track - setNumberOfPoints(--nPoints); - } - setNumberOfPoints(--nPoints); - mNCells--; -} - -//_________________________________________________________________________________________________ -inline void TrackLTF::setPoint(const Cluster cl, const Int_t layer, const Int_t clusterId, const MCCompLabel label, const Int_t extClsIndex, Bool_t& newPoint) -{ - auto nPoints = getNumberOfPoints(); - if (newPoint) { - if (nPoints > 0) { - if (mZ[nPoints - 1] == cl.getZ()) { - LOG(WARN) << "MFT TrackLTF: skipping setPoint (1 cluster per layer!)"; - return; - } - } - if (nPoints > constants::mft::LayersNumber) { - LOG(WARN) << "MFT TrackLTF Overflow"; + if (nPoints > 0) { + if (mZ[nPoints - 1] == cl.getZ()) { + LOG(WARN) << "MFT TrackLTF: skipping setPoint (1 cluster per layer!)"; return; } - mX[nPoints] = cl.getX(); - mY[nPoints] = cl.getY(); - mZ[nPoints] = cl.getZ(); - mSigmaX2[nPoints] = cl.sigmaX2; - mSigmaY2[nPoints] = cl.sigmaY2; - mLayer[nPoints] = layer; - mClusterId[nPoints] = clusterId; - mMCCompLabels[nPoints] = label; - setExternalClusterIndex(nPoints, extClsIndex); - setNumberOfPoints(nPoints + 1); - } else { - mX[nPoints] = cl.getX(); - mY[nPoints] = cl.getY(); - mZ[nPoints] = cl.getZ(); - mSigmaX2[nPoints] = cl.sigmaX2; - mSigmaY2[nPoints] = cl.sigmaY2; - mLayer[nPoints] = layer; - mClusterId[nPoints] = clusterId; - mMCCompLabels[nPoints] = label; - setExternalClusterIndex(nPoints, extClsIndex); } + if (nPoints > constants::mft::LayersNumber) { + LOG(WARN) << "MFT TrackLTF Overflow"; + return; + } + mX[nPoints] = cl.getX(); + mY[nPoints] = cl.getY(); + mZ[nPoints] = cl.getZ(); + mSigmaX2[nPoints] = cl.sigmaX2; + mSigmaY2[nPoints] = cl.sigmaY2; + mLayer[nPoints] = layer; + mClusterId[nPoints] = clusterId; + mMCCompLabels[nPoints] = label; + setExternalClusterIndex(nPoints, extClsIndex); + setNumberOfPoints(nPoints + 1); } //_________________________________________________________________________________________________ diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h index 91601db595087..0aa56f1005b26 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ namespace mft class TrackFitter { - using SMatrix55 = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; + using SMatrix55Sym = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; using SMatrix5 = ROOT::Math::SVector<Double_t, 5>; public: @@ -44,7 +45,10 @@ class TrackFitter TrackFitter(TrackFitter&&) = delete; TrackFitter& operator=(TrackFitter&&) = delete; - void setBz(float bZ); + void setBz(float bZ) { mBZField = bZ; } + void setMFTRadLength(float MFT_x2X0) { mMFTDiskThicknessInX0 = MFT_x2X0 / 5.0; } + void setVerbosity(float v) { mVerbose = v; } + void setTrackModel(float m) { mTrackModel = m; } bool initTrack(TrackLTF& track, bool outward = false); bool fit(TrackLTF& track, bool outward = false); @@ -53,20 +57,22 @@ class TrackFitter static constexpr double getMaxChi2() { return SMaxChi2; } private: - bool computeCluster(TrackLTF& track, int cluster); - - Float_t mBZField; // kiloGauss. - static constexpr double SMaxChi2 = 2.e10; ///< maximum chi2 above which the track can be considered as abnormal - /// default layer thickness in X0 for reconstruction //FIXME: set values for the MFT - static constexpr double SLayerThicknessInX0[10] = {0.065, 0.065, 0.075, 0.075, 0.035, - 0.035, 0.035, 0.035, 0.035, 0.035}; + bool propagateToZ(TrackLTF& track, double z); + bool propagateToNextClusterWithMCS(TrackLTF& track, double z, int& startingLayerID, const int& newLayerID); + bool computeCluster(TrackLTF& track, int cluster, int& startingLayerID); bool mFieldON = true; + Float_t mBZField; // kiloGauss. + Float_t mMFTDiskThicknessInX0 = 0.042 / 5; + Int_t mTrackModel = MFTTrackModel::Optimized; + + static constexpr double SMaxChi2 = 2.e10; ///< maximum chi2 above which the track can be considered as abnormal + bool mVerbose = false; }; // Functions to estimate momentum and charge from track curvature Double_t invQPtFromFCF(const TrackLTF& track, Double_t bFieldZ, Double_t& chi2); -Bool_t LinearRegression(Int_t nVal, Double_t* xVal, Double_t* yVal, Double_t* yErr, Double_t& a, Double_t& ae, Double_t& b, Double_t& be); +Bool_t LinearRegression(Int_t nVal, std::vector<double>& xVal, std::vector<double>& yVal, std::vector<double>& yErr, Double_t& a, Double_t& ae, Double_t& b, Double_t& be); } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h index 45b0fc2792eba..a301af50f40db 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "MFTTracking/ROframe.h" #include "MFTTracking/TrackFitter.h" #include "MFTTracking/Cluster.h" +#include "MFTTracking/TrackerConfig.h" #include "MathUtils/Utils.h" #include "MathUtils/Cartesian.h" @@ -33,7 +35,7 @@ namespace mft class TrackLTF; -class Tracker +class Tracker : public TrackerConfig { public: @@ -46,9 +48,9 @@ class Tracker void setBz(Float_t bz); const Float_t getBz() const { return mBz; } - std::vector<TrackMFTExt>& getTracks() { return mTracks; } - std::vector<TrackLTF>& getTracksLTF() { return mTracksLTF; } - o2::dataformats::MCTruthContainer<MCCompLabel>& getTrackLabels() { return mTrackLabels; } + auto& getTracks() { return mTracks; } + auto& getTracksLTF() { return mTracksLTF; } + auto& getTrackLabels() { return mTrackLabels; } void clustersToTracks(ROframe&, std::ostream& = std::cout); @@ -58,40 +60,62 @@ class Tracker void setROFrame(std::uint32_t f) { mROFrame = f; } std::uint32_t getROFrame() const { return mROFrame; } + void initialize(bool fullClusterScan = false); + void initConfig(const MFTTrackingParam& trkParam, bool printConfig = false); + private: void findTracks(ROframe&); void findTracksLTF(ROframe&); void findTracksCA(ROframe&); - void computeCells(ROframe&); - void computeCellsInRoad(Road&); - void runForwardInRoad(ROframe&); + void findTracksLTFfcs(ROframe&); + void findTracksCAfcs(ROframe&); + void computeCellsInRoad(ROframe&); + void runForwardInRoad(); void runBackwardInRoad(ROframe&); - void updateCellStatusInRoad(Road&); + void updateCellStatusInRoad(); bool fitTracks(ROframe&); const Int_t isDiskFace(Int_t layer) const { return (layer % 2); } const Float_t getDistanceToSeed(const Cluster&, const Cluster&, const Cluster&) const; - void getRPhiProjectionBin(const Cluster&, const Int_t, const Int_t, Int_t&, Int_t&) const; - Bool_t getBinClusterRange(const ROframe&, const Int_t, const Int_t, Int_t&, Int_t&) const; - const Float_t getCellDeviation(const ROframe&, const Cell&, const Cell&) const; - const Bool_t getCellsConnect(const ROframe&, const Cell&, const Cell&) const; - const Float_t getCellChisquare(ROframe&, const Cell&) const; - const Bool_t addCellToCurrentTrackCA(const Int_t, const Int_t, ROframe&); - - const Bool_t LinearRegression(Int_t, Float_t*, Float_t*, Float_t*, Float_t&, Float_t&, Float_t&, Float_t&, Float_t&, Int_t skip = -1) const; + void getBinClusterRange(const ROframe&, const Int_t, const Int_t, Int_t&, Int_t&) const; + const Float_t getCellDeviation(const Cell&, const Cell&) const; + const Bool_t getCellsConnect(const Cell&, const Cell&) const; + void addCellToCurrentTrackCA(const Int_t, const Int_t, ROframe&); + void addCellToCurrentRoad(ROframe&, const Int_t, const Int_t, const Int_t, const Int_t, Int_t&); Float_t mBz = 5.f; std::uint32_t mROFrame = 0; std::vector<TrackMFTExt> mTracks; std::vector<TrackLTF> mTracksLTF; std::vector<Cluster> mClusters; - o2::dataformats::MCTruthContainer<MCCompLabel> mTrackLabels; + std::vector<MCCompLabel> mTrackLabels; std::unique_ptr<o2::mft::TrackFitter> mTrackFitter = nullptr; Int_t mMaxCellLevel = 0; bool mUseMC = false; + + std::array<std::array<std::array<std::vector<Int_t>, constants::index_table::MaxRPhiBins>, (constants::mft::LayersNumber - 1)>, (constants::mft::LayersNumber - 1)> mBinsS; + std::array<std::array<std::array<std::vector<Int_t>, constants::index_table::MaxRPhiBins>, (constants::mft::LayersNumber - 1)>, (constants::mft::LayersNumber - 1)> mBins; + + /// helper to store points of a track candidate + struct TrackElement { + TrackElement() = default; + TrackElement(Int_t la, Int_t id) + { + layer = la; + idInLayer = id; + }; + Int_t layer; + Int_t idInLayer; + }; + + /// current road for CA algorithm + Road mRoad; + + /// Special version for TED shots and cosmics, with full scan of the clusters + bool mFullClusterScan = false; }; //_________________________________________________________________________________________________ @@ -99,91 +123,36 @@ inline const Float_t Tracker::getDistanceToSeed(const Cluster& cluster1, const C { // the seed is between "cluster1" and "cluster2" and cuts the plane // of the "cluster" at a distance dR from it - Float_t dxSeed, dySeed, dzSeed, dz, dR, xSeed, ySeed; + Float_t dxSeed, dySeed, dzSeed, invdzSeed, dz, dR2, xSeed, ySeed; dxSeed = cluster2.getX() - cluster1.getX(); dySeed = cluster2.getY() - cluster1.getY(); dzSeed = cluster2.getZ() - cluster1.getZ(); dz = cluster.getZ() - cluster1.getZ(); - xSeed = cluster1.getX() + dxSeed * dz / dzSeed; - ySeed = cluster1.getY() + dySeed * dz / dzSeed; - dR = std::sqrt((cluster.getX() - xSeed) * (cluster.getX() - xSeed) + (cluster.getY() - ySeed) * (cluster.getY() - ySeed)); - return dR; + invdzSeed = dz / dzSeed; + xSeed = cluster1.getX() + dxSeed * invdzSeed; + ySeed = cluster1.getY() + dySeed * invdzSeed; + dR2 = (cluster.getX() - xSeed) * (cluster.getX() - xSeed) + (cluster.getY() - ySeed) * (cluster.getY() - ySeed); + return dR2; } //_________________________________________________________________________________________________ -inline void Tracker::getRPhiProjectionBin(const Cluster& cluster1, const Int_t layer1, const Int_t layer, Int_t& binR_proj, Int_t& binPhi_proj) const +inline void Tracker::getBinClusterRange(const ROframe& event, const Int_t layer, const Int_t bin, Int_t& clsMinIndex, Int_t& clsMaxIndex) const { - Float_t dz, x_proj, y_proj, r_proj, phi_proj; - dz = constants::mft::LayerZCoordinate()[layer] - constants::mft::LayerZCoordinate()[layer1]; - x_proj = cluster1.getX() + dz * cluster1.getX() * constants::mft::InverseLayerZCoordinate()[layer1]; - y_proj = cluster1.getY() + dz * cluster1.getY() * constants::mft::InverseLayerZCoordinate()[layer1]; - auto clsPoint2D = math_utils::Point2D<Float_t>(x_proj, y_proj); - r_proj = clsPoint2D.R(); - phi_proj = clsPoint2D.Phi(); - o2::math_utils::bringTo02PiGen(phi_proj); - binR_proj = constants::index_table::getRBinIndex(r_proj); - binPhi_proj = constants::index_table::getPhiBinIndex(phi_proj); - return; + const auto& pair = event.getClusterBinIndexRange(layer)[bin]; + clsMinIndex = pair.first; + clsMaxIndex = pair.second; } //_________________________________________________________________________________________________ -inline Bool_t Tracker::getBinClusterRange(const ROframe& event, const Int_t layer, const Int_t bin, Int_t& clsMinIndex, Int_t& clsMaxIndex) const +inline const Float_t Tracker::getCellDeviation(const Cell& cell1, const Cell& cell2) const { - const auto pair2 = event.getClusterBinIndexRange(layer).find(bin); - if (pair2 == event.getClusterBinIndexRange(layer).end()) { - return kFALSE; - } - Int_t binIndex = pair2->first; - // get the range in ordered cluster index within this bin - std::pair<Int_t, Int_t> pair1 = pair2->second; - clsMinIndex = pair1.first; - clsMaxIndex = pair1.second; - return kTRUE; -} - -//_________________________________________________________________________________________________ -inline const Float_t Tracker::getCellDeviation(const ROframe& event, const Cell& cell1, const Cell& cell2) const -{ - Int_t cell1layer1 = cell1.getFirstLayerId(); - Int_t cell1layer2 = cell1.getSecondLayerId(); - - Int_t cell2layer1 = cell2.getFirstLayerId(); - Int_t cell2layer2 = cell2.getSecondLayerId(); - - Int_t cell1cls1 = cell1.getFirstClusterIndex(); - Int_t cell1cls2 = cell1.getSecondClusterIndex(); - - Int_t cell2cls1 = cell2.getFirstClusterIndex(); - Int_t cell2cls2 = cell2.getSecondClusterIndex(); - - auto cluster11 = event.getClustersInLayer(cell1layer1)[cell1cls1]; - auto cluster12 = event.getClustersInLayer(cell1layer2)[cell1cls2]; - auto cluster21 = event.getClustersInLayer(cell2layer1)[cell2cls1]; - auto cluster22 = event.getClustersInLayer(cell2layer2)[cell2cls2]; - - Float_t cell1x1 = cluster11.getX(); - Float_t cell1y1 = cluster11.getY(); - Float_t cell1z1 = cluster11.getZ(); + Float_t cell1dx = cell1.getX2() - cell1.getX1(); + Float_t cell1dy = cell1.getY2() - cell1.getY1(); + Float_t cell1dz = cell1.getZ2() - cell1.getZ1(); - Float_t cell1x2 = cluster12.getX(); - Float_t cell1y2 = cluster12.getY(); - Float_t cell1z2 = cluster12.getZ(); - - Float_t cell2x1 = cluster21.getX(); - Float_t cell2y1 = cluster21.getY(); - Float_t cell2z1 = cluster21.getZ(); - - Float_t cell2x2 = cluster22.getX(); - Float_t cell2y2 = cluster22.getY(); - Float_t cell2z2 = cluster22.getZ(); - - Float_t cell1dx = cell1x2 - cell1x1; - Float_t cell1dy = cell1y2 - cell1y1; - Float_t cell1dz = cell1z2 - cell1z1; - - Float_t cell2dx = cell2x2 - cell2x1; - Float_t cell2dy = cell2y2 - cell2y1; - Float_t cell2dz = cell2z2 - cell2z1; + Float_t cell2dx = cell2.getX2() - cell2.getX1(); + Float_t cell2dy = cell2.getY2() - cell2.getY1(); + Float_t cell2dz = cell2.getZ2() - cell2.getZ1(); Float_t cell1mod = std::sqrt(cell1dx * cell1dx + cell1dy * cell1dy + cell1dz * cell1dz); Float_t cell2mod = std::sqrt(cell2dx * cell2dx + cell2dy * cell2dy + cell2dz * cell2dz); @@ -194,54 +163,17 @@ inline const Float_t Tracker::getCellDeviation(const ROframe& event, const Cell& } //_________________________________________________________________________________________________ -inline const Bool_t Tracker::getCellsConnect(const ROframe& event, const Cell& cell1, const Cell& cell2) const +inline const Bool_t Tracker::getCellsConnect(const Cell& cell1, const Cell& cell2) const { - Int_t cell1layer1 = cell1.getFirstLayerId(); - Int_t cell1layer2 = cell1.getSecondLayerId(); - - Int_t cell2layer1 = cell2.getFirstLayerId(); - Int_t cell2layer2 = cell2.getSecondLayerId(); - - Int_t cell1cls1 = cell1.getFirstClusterIndex(); - Int_t cell1cls2 = cell1.getSecondClusterIndex(); - - Int_t cell2cls1 = cell2.getFirstClusterIndex(); - Int_t cell2cls2 = cell2.getSecondClusterIndex(); - - auto cluster11 = event.getClustersInLayer(cell1layer1)[cell1cls1]; - auto cluster12 = event.getClustersInLayer(cell1layer2)[cell1cls2]; - auto cluster21 = event.getClustersInLayer(cell2layer1)[cell2cls1]; - auto cluster22 = event.getClustersInLayer(cell2layer2)[cell2cls2]; - - Float_t cell1x1 = cluster11.getX(); - Float_t cell1y1 = cluster11.getY(); - //Float_t cell1z1 = cluster11.getZ(); - - Float_t cell1x2 = cluster12.getX(); - Float_t cell1y2 = cluster12.getY(); - //Float_t cell1z2 = cluster12.getZ(); - - Float_t cell2x1 = cluster21.getX(); - Float_t cell2y1 = cluster21.getY(); - //Float_t cell2z1 = cluster21.getZ(); - - Float_t cell2x2 = cluster22.getX(); - Float_t cell2y2 = cluster22.getY(); - //Float_t cell2z2 = cluster22.getZ(); - - Float_t cell1dx = cell1x2 - cell1x1; - Float_t cell1dy = cell1y2 - cell1y1; - //Float_t cell1dz = cell1z2 - cell1z1; - - Float_t cell2dx = cell2x2 - cell2x1; - Float_t cell2dy = cell2y2 - cell2y1; - //Float_t cell2dz = cell2z2 - cell2z1; - + Float_t cell1x2 = cell1.getX2(); + Float_t cell1y2 = cell1.getY2(); + Float_t cell2x1 = cell2.getX1(); + Float_t cell2y1 = cell2.getY1(); Float_t dx = cell1x2 - cell2x1; Float_t dy = cell1y2 - cell2y1; - Float_t dr = std::sqrt(dx * dx + dy * dy); + Float_t dr2 = dx * dx + dy * dy; - if (dr > constants::mft::Resolution) { + if (dr2 > (constants::mft::Resolution * constants::mft::Resolution)) { return kFALSE; } return kTRUE; @@ -284,7 +216,7 @@ inline void Tracker::computeTracksMClabels(const T& tracks) isFakeTrack = true; maxOccurrencesValue.setFakeFlag(); } - mTrackLabels.addElement(mTrackLabels.getIndexedSize(), maxOccurrencesValue); + mTrackLabels.emplace_back(maxOccurrencesValue); } } diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackerConfig.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackerConfig.h new file mode 100644 index 0000000000000..6933d1564aac2 --- /dev/null +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackerConfig.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.h +/// \brief Definition of the GeometryTGeo class +/// \author bogdan.vulpescu@clermont.in2p3.fr - adapted from ITS, 21.09.2017 + +#ifndef ALICEO2_MFT_TRACKERCONFIG_H_ +#define ALICEO2_MFT_TRACKERCONFIG_H_ + +#include "MFTTracking/Constants.h" +#include "MFTTracking/MFTTrackingParam.h" + +namespace o2 +{ +namespace mft +{ +class TrackerConfig +{ + public: + TrackerConfig(); + TrackerConfig(const TrackerConfig& conf) = default; + TrackerConfig& operator=(const TrackerConfig& conf) = default; + + void initialize(const MFTTrackingParam& trkParam); + + const Int_t getRBinIndex(const Float_t r) const; + const Int_t getPhiBinIndex(const Float_t phi) const; + const Int_t getBinIndex(const Int_t rIndex, const Int_t phiIndex) const; + + // tracking configuration parameters + Int_t mMinTrackPointsLTF = 5; + Int_t mMinTrackPointsCA = 4; + Int_t mMinTrackStationsLTF = 4; + Int_t mMinTrackStationsCA = 4; + Float_t mLTFclsRCut = 0.0100; + Float_t mLTFclsR2Cut = 0.0100 * 0.0100; + Float_t mROADclsRCut = 0.0400; + Float_t mROADclsR2Cut = 0.0400 * 0.0400; + Int_t mLTFseed2BinWin = 3; + Int_t mLTFinterBinWin = 3; + Int_t mRBins = 50; + Int_t mPhiBins = 50; + Int_t mRPhiBins = 50 * 50; + Float_t mRBinSize = (constants::index_table::RMax - constants::index_table::RMin) / 50.; + Float_t mPhiBinSize = constants::index_table::PhiMax / 50.; + Float_t mInverseRBinSize = 50. / (constants::index_table::RMax - constants::index_table::RMin); + Float_t mInversePhiBinSize = 50. / constants::index_table::PhiMax; + Bool_t mLTFConeRadius = kFALSE; + Bool_t mCAConeRadius = kFALSE; + + private: + ClassDefNV(TrackerConfig, 1); +}; + +inline const Int_t TrackerConfig::getRBinIndex(const Float_t r) const +{ + return (Int_t)((r - constants::index_table::RMin) * mInverseRBinSize); +} + +inline const Int_t TrackerConfig::getPhiBinIndex(const Float_t phi) const +{ + return (Int_t)((phi - constants::index_table::PhiMin) * mInversePhiBinSize); +} + +inline const Int_t TrackerConfig::getBinIndex(const Int_t rIndex, const Int_t phiIndex) const +{ + if (0 <= rIndex && rIndex < mRBins && + 0 <= phiIndex && phiIndex < mPhiBins) { + return (phiIndex * mRBins + rIndex); + } + return (mRBins * mPhiBins); +} + +} // namespace mft +} // namespace o2 + +#endif diff --git a/Detectors/ITSMFT/MFT/tracking/src/Cluster.cxx b/Detectors/ITSMFT/MFT/tracking/src/Cluster.cxx index 5a81fba5d29a8..c31fb5b6cfa78 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/Cluster.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,6 @@ /// #include "MFTTracking/Cluster.h" -#include "MFTTracking/IndexTableUtils.h" #include "MathUtils/Utils.h" #include "MathUtils/Cartesian.h" @@ -35,19 +35,5 @@ Cluster::Cluster(const Float_t x, const Float_t y, const Float_t z, const Int_t o2::math_utils::bringTo02PiGen(phiCoordinate); } -Cluster::Cluster(const Int_t layerIndex, const Cluster& other) - : BaseCluster(1, other.getXYZ()), - phiCoordinate{0.}, - rCoordinate{0.}, - clusterId{other.clusterId}, - indexTableBin{index_table_utils::getBinIndex(index_table_utils::getRBinIndex(layerIndex, rCoordinate), - index_table_utils::getPhiBinIndex(phiCoordinate))} -{ - auto clsPoint2D = math_utils::Point2D<Float_t>(other.getX(), other.getY()); - rCoordinate = clsPoint2D.R(); - phiCoordinate = clsPoint2D.Phi(); - o2::math_utils::bringTo02PiGen(phiCoordinate); -} - } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx b/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx index 4bc5cbb72a854..67f4545085bf3 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,8 +35,8 @@ namespace o2 namespace mft { -int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, - const dataformats::MCTruthContainer<MCCompLabel>* mcLabels) +//_________________________________________________________ +int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, gsl::span<const itsmft::CompClusterExt> clusters, gsl::span<const unsigned char>::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer<MCCompLabel>* mcLabels, const o2::mft::Tracker* tracker) { event.clear(); GeometryTGeo* geom = GeometryTGeo::Instance(); @@ -44,16 +45,14 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g auto first = rof.getFirstEntry(); auto clusters_in_frame = rof.getROFData(clusters); for (auto& c : clusters_in_frame) { - int layer = geom->getLayer(c.getSensorID()); + auto sensorID = c.getSensorID(); + int layer = geom->getLayer(sensorID); auto pattID = c.getPatternID(); o2::math_utils::Point3D<float> locXYZ; float sigmaX2 = ioutils::DefClusError2Row, sigmaY2 = ioutils::DefClusError2Col; //Dummy COG errors (about half pixel size) if (pattID != itsmft::CompCluster::InvalidPatternID) { - //sigmaX2 = dict.getErr2X(pattID); // ALPIDE local X coordinate => MFT global X coordinate (ALPIDE rows) - //sigmaY2 = dict.getErr2Z(pattID); // ALPIDE local Z coordinate => MFT global Y coordinate (ALPIDE columns) - // temporary, until ITS bug fix - sigmaX2 = dict.getErrX(pattID) * dict.getErrX(pattID); - sigmaY2 = dict.getErrZ(pattID) * dict.getErrZ(pattID); + sigmaX2 = dict.getErr2X(pattID); // ALPIDE local X coordinate => MFT global X coordinate (ALPIDE rows) + sigmaY2 = dict.getErr2Z(pattID); // ALPIDE local Z coordinate => MFT global Y coordinate (ALPIDE columns) if (!dict.isGroup(pattID)) { locXYZ = dict.getClusterCoordinates(c); } else { @@ -62,9 +61,8 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g } } else { o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict.getClusterCoordinates(c, patt); + locXYZ = dict.getClusterCoordinates(c, patt, false); } - auto sensorID = c.getSensorID(); // Transformation to the local --> global auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; @@ -72,10 +70,9 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g Float_t rCoord = clsPoint2D.R(); Float_t phiCoord = clsPoint2D.Phi(); o2::math_utils::bringTo02PiGen(phiCoord); - int rBinIndex = constants::index_table::getRBinIndex(rCoord); - int phiBinIndex = constants::index_table::getPhiBinIndex(phiCoord); - int binIndex = constants::index_table::getBinIndex(rBinIndex, phiBinIndex); - // TODO: Check consistency of sigmaX2 and sigmaY2 + int rBinIndex = tracker->getRBinIndex(rCoord); + int phiBinIndex = tracker->getPhiBinIndex(phiCoord); + int binIndex = tracker->getBinIndex(rBinIndex, phiBinIndex); event.addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), phiCoord, rCoord, event.getClustersInLayer(layer).size(), binIndex, sigmaX2, sigmaY2, sensorID); if (mcLabels) { event.addClusterLabelToLayer(layer, *(mcLabels->getLabels(first + clusterId).begin())); @@ -86,5 +83,42 @@ int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, g return clusters_in_frame.size(); } +//_________________________________________________________ +/// convert compact clusters to 3D spacepoints into std::vector<o2::BaseCluster<float>> +void ioutils::convertCompactClusters(gsl::span<const itsmft::CompClusterExt> clusters, + gsl::span<const unsigned char>::iterator& pattIt, + std::vector<o2::BaseCluster<float>>& output, + const itsmft::TopologyDictionary& dict) +{ + GeometryTGeo* geom = GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + + for (auto& c : clusters) { + auto chipID = c.getChipID(); + auto pattID = c.getPatternID(); + o2::math_utils::Point3D<float> locXYZ; + float sigmaX2 = DefClusError2Row, sigmaY2 = DefClusError2Col; + if (pattID != itsmft::CompCluster::InvalidPatternID) { + sigmaX2 = dict.getErr2X(pattID); // ALPIDE local Y coordinate => MFT global X coordinate (ALPIDE rows) + sigmaY2 = dict.getErr2Z(pattID); // ALPIDE local Z coordinate => MFT global Y coordinate (ALPIDE columns) + if (!dict.isGroup(pattID)) { + locXYZ = dict.getClusterCoordinates(c); + } else { + o2::itsmft::ClusterPattern patt(pattIt); + locXYZ = dict.getClusterCoordinates(c, patt); + } + } else { + o2::itsmft::ClusterPattern patt(pattIt); + locXYZ = dict.getClusterCoordinates(c, patt, false); + } + + // Transformation to the local --> global + auto gloXYZ = geom->getMatrixL2G(chipID) * locXYZ; + + auto& cl3d = output.emplace_back(c.getSensorID(), gloXYZ); // local --> global + cl3d.setErrors(sigmaX2, sigmaY2, 0); + } +} + } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h index f5f83773097fb..e281b4247a44f 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h +++ b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #pragma link C++ class o2::mft::TrackCA + ; #pragma link C++ class std::vector < o2::mft::TrackLTF> + ; #pragma link C++ class std::vector < o2::mft::TrackCA> + ; +#pragma link C++ class o2::mft::TrackerConfig + ; #pragma link C++ class o2::mft::MFTTrackingParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mft::MFTTrackingParam> + ; diff --git a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingParam.cxx b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingParam.cxx index 1cdd66033c9de..79e7f2aac664a 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingParam.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx b/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx index 78aedf7fea6d3..fc4d75fca59de 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,13 +34,10 @@ Int_t ROframe::getTotalClusters() const return Int_t(totalClusters); } -void ROframe::initialise() +void ROframe::initialize(bool fullClusterScan) { - sortClusters(); - - for (Int_t layer = 0; layer < constants::mft::LayersNumber; ++layer) { - mUsedClusters[layer].clear(); - mUsedClusters[layer].resize(mClusters[layer].size(), kFALSE); + if (!fullClusterScan) { + sortClusters(); } } @@ -55,7 +53,7 @@ void ROframe::sortClusters() sort(mClusters[iLayer].begin(), mClusters[iLayer].end(), [](Cluster& c1, Cluster& c2) { return c1.indexTableBin < c2.indexTableBin; }); // find the cluster local index range in each bin - // index = element position vector in the vector + // index = element position in the vector nClsInLayer = mClusters[iLayer].size(); binPrevIndex = mClusters[iLayer].at(0).indexTableBin; clsMinIndex = 0; @@ -63,16 +61,19 @@ void ROframe::sortClusters() if (mClusters[iLayer].at(jClsLayer).indexTableBin == binPrevIndex) { continue; } + clsMaxIndex = jClsLayer - 1; - std::pair<Int_t, Int_t> pair1(clsMinIndex, clsMaxIndex); - mClusterBinIndexRange[iLayer].insert(std::pair<Int_t, std::pair<Int_t, Int_t>>(binPrevIndex, pair1)); + + mClusterBinIndexRange[iLayer][binPrevIndex] = std::pair<Int_t, Int_t>(clsMinIndex, clsMaxIndex); + binPrevIndex = mClusters[iLayer].at(jClsLayer).indexTableBin; clsMinIndex = jClsLayer; } // clusters + // last cluster clsMaxIndex = jClsLayer - 1; - std::pair<Int_t, Int_t> pair1(clsMinIndex, clsMaxIndex); - mClusterBinIndexRange[iLayer].insert(std::pair<Int_t, std::pair<Int_t, Int_t>>(binPrevIndex, pair1)); + + mClusterBinIndexRange[iLayer][binPrevIndex] = std::pair<Int_t, Int_t>(clsMinIndex, clsMaxIndex); } // layers } diff --git a/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx b/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx index e21d0bc11c2bd..75b0f0c2e5c0c 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,30 +37,16 @@ namespace o2 namespace mft { -//_________________________________________________________________________________________________ -void TrackFitter::setBz(float bZ) -{ - auto& mftTrackingParam = MFTTrackingParam::Instance(); - - /// Set the magnetic field for the MFT - mBZField = bZ; - - if (mftTrackingParam.verbose) { - LOG(INFO) << "Setting Fitter field = " << bZ; - } -} - //_________________________________________________________________________________________________ bool TrackFitter::fit(TrackLTF& track, bool outward) { - /// Fit a track using its attached clusters /// Returns false in case of failure - auto& mftTrackingParam = MFTTrackingParam::Instance(); auto nClusters = track.getNumberOfPoints(); + auto lastLayer = track.getLayers()[(outward ? 0 : nClusters - 1)]; - if (mftTrackingParam.verbose) { + if (mVerbose) { std::cout << "Seed covariances: \n" << track.getCovariances() << std::endl << std::endl; @@ -67,23 +54,21 @@ bool TrackFitter::fit(TrackLTF& track, bool outward) // recursively compute clusters, updating the track parameters if (!outward) { // Inward for vertexing - nClusters--; while (nClusters-- > 0) { - if (!computeCluster(track, nClusters)) { + if (!computeCluster(track, nClusters, lastLayer)) { return false; } } } else { // Outward for MCH matching - int ncl = 1; + int ncl = 0; while (ncl < nClusters) { - if (!computeCluster(track, ncl)) { + if (!computeCluster(track, ncl, lastLayer)) { return false; } ncl++; } } - if (mftTrackingParam.verbose) { - // Print final covariances? std::cout << "Track covariances:"; track->getCovariances().Print(); + if (mVerbose) { std::cout << "Track Chi2 = " << track.getTrackChi2() << std::endl; std::cout << " ***************************** Done fitting *****************************\n"; } @@ -95,17 +80,18 @@ bool TrackFitter::fit(TrackLTF& track, bool outward) bool TrackFitter::initTrack(TrackLTF& track, bool outward) { - auto& mftTrackingParam = MFTTrackingParam::Instance(); - // initialize the starting track parameters and cluster double sigmainvQPtsq; double chi2invqptquad; auto invQPt0 = invQPtFromFCF(track, mBZField, sigmainvQPtsq); + if (std::abs(mBZField) < 0.5) { // Temporary workaround for MFT tracking with magnet off; + invQPt0 = 1e-5; + } auto nPoints = track.getNumberOfPoints(); auto k = TMath::Abs(o2::constants::math::B2C * mBZField); auto Hz = std::copysign(1, mBZField); - if (mftTrackingParam.verbose) { + if (mVerbose) { std::cout << "\n ***************************** Start Fitting new track ***************************** \n"; std::cout << "N Clusters = " << nPoints << std::endl; } @@ -115,26 +101,32 @@ bool TrackFitter::initTrack(TrackLTF& track, bool outward) track.setInvQPt(invQPt0); /// Compute the initial track parameters to seed the Kalman filter - int first_cls, last_cls; if (outward) { // MCH matching - first_cls = 0; - last_cls = nPoints - 1; + first_cls = 1; + last_cls = 0; } else { // Vertexing first_cls = nPoints - 1; - last_cls = 0; + last_cls = nPoints - 2; } auto x0 = track.getXCoordinates()[first_cls]; auto y0 = track.getYCoordinates()[first_cls]; auto z0 = track.getZCoordinates()[first_cls]; - auto deltaX = track.getXCoordinates()[nPoints - 1] - track.getXCoordinates()[0]; - auto deltaY = track.getYCoordinates()[nPoints - 1] - track.getYCoordinates()[0]; - auto deltaZ = track.getZCoordinates()[nPoints - 1] - track.getZCoordinates()[0]; + //Compute tanl using first two clusters + auto deltaX = track.getXCoordinates()[1] - track.getXCoordinates()[0]; + auto deltaY = track.getYCoordinates()[1] - track.getYCoordinates()[0]; + auto deltaZ = track.getZCoordinates()[1] - track.getZCoordinates()[0]; auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY); auto tanl0 = 0.5 * TMath::Sqrt2() * (deltaZ / deltaR) * TMath::Sqrt(TMath::Sqrt((invQPt0 * deltaR * k) * (invQPt0 * deltaR * k) + 1) + 1); + + // Compute phi at the last cluster using two last clusters + deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[last_cls]; + deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[last_cls]; + deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[last_cls]; + deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY); auto phi0 = TMath::ATan2(deltaY, deltaX) - 0.5 * Hz * invQPt0 * deltaZ * k / tanl0; auto sigmax0sq = track.getSigmasX2()[first_cls]; auto sigmay0sq = track.getSigmasY2()[first_cls]; @@ -149,71 +141,24 @@ bool TrackFitter::initTrack(TrackLTF& track, bool outward) track.setPhi(phi0); track.setTanl(tanl0); - if (mftTrackingParam.verbose) { + if (mVerbose) { std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << std::endl; - auto model = (mftTrackingParam.trackmodel == Helix) ? "Helix" : (mftTrackingParam.trackmodel == Quadratic) ? "Quadratic" : "Linear"; + auto model = (mTrackModel == Helix) ? "Helix" : (mTrackModel == Quadratic) ? "Quadratic" + : (mTrackModel == Optimized) ? "Optimized" + : "Linear"; std::cout << "Track Model: " << model << std::endl; - std::cout << " initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << " Phi = " << phi0 << " pz = " << track.getPz() << " qpt = " << 1.0 / track.getInvQPt() << std::endl; - std::cout << " Variances: sigma2_x0 = " << TMath::Sqrt(sigmax0sq) << " sigma2_y0 = " << TMath::Sqrt(sigmay0sq) << " sigma2_q/pt = " << TMath::Sqrt(sigmainvQPtsq) << std::endl; + std::cout << " initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << " Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl; } - auto deltaR2 = deltaR * deltaR; - auto deltaR3 = deltaR2 * deltaR; - auto deltaR4 = deltaR2 * deltaR2; - auto k2 = k * k; - auto A = TMath::Sqrt(track.getInvQPt() * track.getInvQPt() * deltaR2 * k2 + 1); - auto A2 = A * A; - auto B = A + 1.0; - auto B2 = B * B; - auto B3 = B * B * B; - auto B12 = TMath::Sqrt(B); - auto B32 = B * B12; - auto B52 = B * B32; - auto C = invQPt0 * k; - auto C2 = C * C; - auto C3 = C * C2; - auto D = 1.0 / (A2 * B2 * B2 * deltaR4); - auto E = D * deltaZ / (B * deltaR); - auto F = deltaR * deltaX * C3 * Hz / (A * B32); - auto G = 0.5 * TMath::Sqrt2() * A * B32 * C * Hz * deltaR; - auto Gx = G * deltaX; - auto Gy = G * deltaY; - auto H = -0.25 * TMath::Sqrt2() * B12 * C3 * Hz * deltaR3; - auto Hx = H * deltaX; - auto Hy = H * deltaY; - auto I = A * B2; - auto Ix = I * deltaX; - auto Iy = I * deltaY; - auto J = 2 * B * deltaR3 * deltaR3 * k2; - auto K = 0.5 * A * B - 0.25 * C2 * deltaR2; - auto L0 = Gx + Hx + Iy; - auto M0 = -Gy - Hy + Ix; - auto N = -0.5 * B3 * C * Hz * deltaR3 * deltaR4 * k2; - auto O = 0.125 * C2 * deltaR4 * deltaR4 * k2; - auto P = -K * k * Hz * deltaR / A; - auto Q = deltaZ * deltaZ / (A2 * B * deltaR3 * deltaR3); - auto R = 0.25 * C * deltaZ * TMath::Sqrt2() * deltaR * k / (A * B12); - - SMatrix55 lastParamCov; - lastParamCov(0, 0) = sigmax0sq; // <X,X> - lastParamCov(0, 1) = 0; // <Y,X> - lastParamCov(0, 2) = 0; // <PHI,X> - lastParamCov(0, 3) = 0; // <TANL,X> - lastParamCov(0, 4) = 0; // <INVQPT,X> - - lastParamCov(1, 1) = sigmay0sq; // <Y,Y> - lastParamCov(1, 2) = 0; // <PHI,Y> - lastParamCov(1, 3) = 0; // <TANL,Y> - lastParamCov(1, 4) = 0; // <INVQPT,Y> - - lastParamCov(2, 2) = D * (J * K * K * sigmainvQPtsq + L0 * L0 * sigmaDeltaXsq + M0 * M0 * sigmaDeltaYsq); // <PHI,PHI> - lastParamCov(2, 3) = E * K * (TMath::Sqrt2() * B52 * (L0 * deltaX * sigmaDeltaXsq - deltaY * sigmaDeltaYsq * M0) + N * sigmainvQPtsq); // <TANL,PHI> - lastParamCov(2, 4) = P * sigmainvQPtsq * TMath::Sqrt2() / B32; // <INVQPT,PHI> - - lastParamCov(3, 3) = Q * (2 * K * K * (deltaX * deltaX * sigmaDeltaXsq + deltaY * deltaY * sigmaDeltaYsq) + O * sigmainvQPtsq); // <TANL,TANL> - lastParamCov(3, 4) = R * sigmainvQPtsq; // <INVQPT,TANL> - - lastParamCov(4, 4) = sigmainvQPtsq; // <INVQPT,INVQPT> + SMatrix55Sym lastParamCov; + float qptsigma = TMath::Max(std::abs(track.getInvQPt()), .5); + float tanlsigma = TMath::Max(std::abs(track.getTanl()), .5); + + lastParamCov(0, 0) = 1; // <X,X> + lastParamCov(1, 1) = 1; // <Y,X> + lastParamCov(2, 2) = TMath::Pi() * TMath::Pi() / 16; // <PHI,X> + lastParamCov(3, 3) = 10 * tanlsigma * tanlsigma; // <TANL,X> + lastParamCov(4, 4) = 10 * qptsigma * qptsigma; // <INVQPT,X> track.setCovariances(lastParamCov); track.setTrackChi2(0.); @@ -222,89 +167,140 @@ bool TrackFitter::initTrack(TrackLTF& track, bool outward) } //_________________________________________________________________________________________________ -bool TrackFitter::computeCluster(TrackLTF& track, int cluster) +bool TrackFitter::propagateToZ(TrackLTF& track, double z) { - /// Propagate track to the z position of the new cluster - /// accounting for MCS dispersion in the current layer and the other(s) crossed - /// Recompute the parameters adding the cluster constraint with the Kalman filter - /// Returns false in case of failure + // Propagate track to the z position of the new cluster + switch (mTrackModel) { + case Linear: + track.propagateToZlinear(z); + break; + case Quadratic: + track.propagateToZquadratic(z, mBZField); + break; + case Helix: + track.propagateToZhelix(z, mBZField); + break; + case Optimized: + track.propagateToZ(z, mBZField); + break; + default: + std::cout << " Invalid track model.\n"; + return false; + break; + } + return true; +} - auto& mftTrackingParam = MFTTrackingParam::Instance(); - const auto& clx = track.getXCoordinates()[cluster]; - const auto& cly = track.getYCoordinates()[cluster]; - const auto& clz = track.getZCoordinates()[cluster]; - const auto& sigmaX2 = track.getSigmasX2()[cluster]; - const auto& sigmaY2 = track.getSigmasY2()[cluster]; +//_________________________________________________________________________________________________ +bool TrackFitter::propagateToNextClusterWithMCS(TrackLTF& track, double z, int& startingLayerID, const int& newLayerID) +{ - if (track.getZ() == clz) { - LOG(INFO) << "AddCluster ERROR: The new cluster must be upstream! Bug on TrackFinder. " << (track.isCA() ? " CATrack" : "LTFTrack"); - LOG(INFO) << "track.getZ() = " << track.getZ() << " ; newClusterZ = " << clz << " ==> Skipping point."; + // Propagate track to the next cluster z position, adding angular MCS effects at the center of + // each disk crossed by the track. This method is valid only for track propagation between + // clusters at MFT layers positions. + + if (startingLayerID == newLayerID) { // Same layer, nothing to do. + if (mVerbose) { + std::cout << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > " + << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID); + std::cout << ") ; track.getZ() = " << track.getZ() << " => "; + std::cout << "destination cluster z = " << z << " ; => Same layer: no MCS effects." << std::endl; + } + if (z != track.getZ()) { + propagateToZ(track, z); + } return true; } - if (mftTrackingParam.verbose) { - std::cout << "computeCluster: X = " << clx << " Y = " << cly << " Z = " << clz << " nCluster = " << cluster << std::endl; - } - // add MCS effects for the new cluster using o2::mft::constants::LayerZPosition; - int startingLayerID, newLayerID; + auto startingZ = track.getZ(); + + //https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c + auto signum = [](auto a) { + return (0 < a) - (a < 0); + }; + int direction = signum(newLayerID - startingLayerID); // takes values +1, 0, -1 + auto currentLayer = startingLayerID; + + if (mVerbose) { + std::cout << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > " + << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID); + std::cout << ") ; track.getZ() = " << track.getZ() << " => "; + std::cout << "destination cluster z = " << z << " ; " << std::endl; + } - auto dZ = clz - track.getZ(); - //LayerID of each cluster from ZPosition // TODO: Use ChipMapping - for (auto layer = 10; layer--;) { - if (track.getZ() < LayerZPosition[layer] + .3 & track.getZ() > LayerZPosition[layer] - .3) { - startingLayerID = layer; + // Number of disks crossed by this track segment + while (currentLayer != newLayerID) { + auto nextlayer = currentLayer + direction; + auto nextZ = LayerZPosition[nextlayer]; + + int NDisksMS; + if (nextZ - track.getZ() > 0) { + NDisksMS = (currentLayer % 2 == 0) ? (currentLayer - nextlayer) / 2 : (currentLayer - nextlayer + 1) / 2; + } else { + NDisksMS = (currentLayer % 2 == 0) ? (nextlayer - currentLayer + 1) / 2 : (nextlayer - currentLayer) / 2; } - } - for (auto layer = 10; layer--;) { - if (clz<LayerZPosition[layer] + .3 & clz> LayerZPosition[layer] - .3) { - newLayerID = layer; + + if (mVerbose) { + std::cout << "currentLayer = " << currentLayer << " ; " + << "nextlayer = " << nextlayer << " ; "; + std::cout << "track.getZ() = " << track.getZ() << " ; "; + std::cout << "nextZ = " << nextZ << " ; "; + std::cout << "NDisksMS = " << NDisksMS << std::endl; + } + + if ((NDisksMS * mMFTDiskThicknessInX0) != 0) { + track.addMCSEffect(NDisksMS * mMFTDiskThicknessInX0); + if (mVerbose) { + std::cout << "Track covariances after MCS effects: \n" + << track.getCovariances() << std::endl + << std::endl; + } + } + + if (mVerbose) { + std::cout << " BeforeExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl; } + + propagateToZ(track, nextZ); + + currentLayer = nextlayer; } - // Number of disks crossed by this tracklet - int NDisksMS; - if (clz - track.getZ() > 0) { - NDisksMS = (startingLayerID % 2 == 0) ? (startingLayerID - newLayerID) / 2 : (startingLayerID - newLayerID + 1) / 2; - } else { - NDisksMS = (startingLayerID % 2 == 0) ? (newLayerID - startingLayerID + 1) / 2 : (newLayerID - startingLayerID) / 2; + if (z != track.getZ()) { + propagateToZ(track, z); } + startingLayerID = newLayerID; + return true; +} - auto MFTDiskThicknessInX0 = mftTrackingParam.MFTRadLength / 5.0; - if (mftTrackingParam.verbose) { - std::cout << "startingLayerID = " << startingLayerID << " ; " - << "newLayerID = " << newLayerID << " ; "; - std::cout << "cl.getZ() = " << clz << " ; "; - std::cout << "startingParam.getZ() = " << track.getZ() << " ; "; - std::cout << "NDisksMS = " << NDisksMS << std::endl; - } +//_________________________________________________________________________________________________ +bool TrackFitter::computeCluster(TrackLTF& track, int cluster, int& startingLayerID) +{ + /// Propagate track to the z position of the new cluster + /// accounting for MCS dispersion in the current layer and the other(s) crossed + /// Recompute the parameters adding the cluster constraint with the Kalman filter + /// Returns false in case of failure - if ((NDisksMS * MFTDiskThicknessInX0) != 0) { - track.addMCSEffect(-1, NDisksMS * MFTDiskThicknessInX0); - } + const auto& clx = track.getXCoordinates()[cluster]; + const auto& cly = track.getYCoordinates()[cluster]; + const auto& clz = track.getZCoordinates()[cluster]; + const auto& sigmaX2 = track.getSigmasX2()[cluster]; + const auto& sigmaY2 = track.getSigmasY2()[cluster]; + const auto& newLayerID = track.getLayers()[cluster]; - if (mftTrackingParam.verbose) { - std::cout << " BeforeExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " qpt = " << 1.0 / track.getInvQPt() << std::endl; + if (mVerbose) { + std::cout << "computeCluster: X = " << clx << " Y = " << cly << " Z = " << clz << " nCluster = " << cluster << " Layer = " << newLayerID << std::endl; } - // Propagate track to the z position of the new cluster - switch (mftTrackingParam.trackmodel) { - case Linear: - track.propagateToZlinear(clz); - break; - case Quadratic: - track.propagateToZquadratic(clz, mBZField); - break; - case Helix: - track.propagateToZhelix(clz, mBZField); - break; - default: - std::cout << " Invalid track model.\n"; - return false; - break; + if (!propagateToNextClusterWithMCS(track, clz, startingLayerID, newLayerID)) { + return false; } - if (mftTrackingParam.verbose) { - std::cout << " AfterExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " qpt = " << 1.0 / track.getInvQPt() << std::endl; + if (mVerbose) { + std::cout << " AfterExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl; + std::cout << "Track covariances after extrap: \n" + << track.getCovariances() << std::endl + << std::endl; } // recompute parameters @@ -312,12 +308,13 @@ bool TrackFitter::computeCluster(TrackLTF& track, int cluster) const std::array<float, 2>& cov = {sigmaX2, sigmaY2}; if (track.update(pos, cov)) { - if (mftTrackingParam.verbose) { + if (mVerbose) { std::cout << " New Cluster: X = " << clx << " Y = " << cly << " Z = " << clz << std::endl; - std::cout << " AfterKalman: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " qpt = " << 1.0 / track.getInvQPt() << std::endl; + std::cout << " AfterKalman: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl; std::cout << std::endl; - // Outputs track covariance matrix: - // param.getCovariances().Print(); + std::cout << "Track covariances after Kalman update: \n" + << track.getCovariances() << std::endl + << std::endl; } return true; } @@ -336,17 +333,17 @@ Double_t invQPtFromFCF(const TrackLTF& track, Double_t bFieldZ, Double_t& sigmai // Fast Circle Fit (Hansroul, Jeremie, Savard, 1987) auto nPoints = track.getNumberOfPoints(); - Double_t* xVal = new Double_t[nPoints]; - Double_t* yVal = new Double_t[nPoints]; - Double_t* zVal = new Double_t[nPoints]; - Double_t* xErr = new Double_t[nPoints]; - Double_t* yErr = new Double_t[nPoints]; - Double_t* uVal = new Double_t[nPoints - 1]; - Double_t* vVal = new Double_t[nPoints - 1]; - Double_t* vErr = new Double_t[nPoints - 1]; - Double_t* fweight = new Double_t[nPoints - 1]; - Double_t* Rn = new Double_t[nPoints - 1]; - Double_t* Pn = new Double_t[nPoints - 1]; + std::vector<double> xVal(nPoints); + std::vector<double> yVal(nPoints); + std::vector<double> zVal(nPoints); + std::vector<double> xErr(nPoints); + std::vector<double> yErr(nPoints); + std::vector<double> uVal(nPoints - 1); + std::vector<double> vVal(nPoints - 1); + std::vector<double> vErr(nPoints - 1); + std::vector<double> fweight(nPoints - 1); + std::vector<double> Rn(nPoints - 1); + std::vector<double> Pn(nPoints - 1); Double_t A, Aerr, B, Berr, x2, y2, invx2y2, a, b, r, sigmaRsq, u2, sigma; Double_t F0, F1, F2, F3, F4, SumSRn, SumSPn, SumRn, SumUPn, SumRP; @@ -465,7 +462,7 @@ Double_t invQPtFromFCF(const TrackLTF& track, Double_t bFieldZ, Double_t& sigmai } ////_________________________________________________________________________________________________ -Bool_t LinearRegression(Int_t nVal, Double_t* xVal, Double_t* yVal, Double_t* yErr, Double_t& B, Double_t& Berr, Double_t& A, Double_t& Aerr) +Bool_t LinearRegression(Int_t nVal, std::vector<double>& xVal, std::vector<double>& yVal, std::vector<double>& yErr, Double_t& B, Double_t& Berr, Double_t& A, Double_t& Aerr) { // linear regression y = B * x + A diff --git a/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx b/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx index acc564d173544..8d6cc0782c3c4 100644 --- a/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,6 @@ namespace mft //_________________________________________________________________________________________________ Tracker::Tracker(bool useMC) : mUseMC{useMC} { - mTrackFitter = std::make_unique<o2::mft::TrackFitter>(); } @@ -40,6 +40,156 @@ void Tracker::setBz(Float_t bz) mTrackFitter->setBz(bz); } +//_________________________________________________________________________________________________ +void Tracker::initConfig(const MFTTrackingParam& trkParam, bool printConfig) +{ + /// initialize from MFTTrackingParam (command line configuration parameters) + + mTrackFitter->setMFTRadLength(trkParam.MFTRadLength); + mTrackFitter->setVerbosity(trkParam.verbose); + mTrackFitter->setTrackModel(trkParam.trackmodel); + + mMinTrackPointsLTF = trkParam.MinTrackPointsLTF; + mMinTrackPointsCA = trkParam.MinTrackPointsCA; + mMinTrackStationsLTF = trkParam.MinTrackStationsLTF; + mMinTrackStationsCA = trkParam.MinTrackStationsCA; + mLTFclsRCut = trkParam.LTFclsRCut; + mLTFclsR2Cut = mLTFclsRCut * mLTFclsRCut; + mROADclsRCut = trkParam.ROADclsRCut; + mROADclsR2Cut = mROADclsRCut * mROADclsRCut; + mLTFseed2BinWin = trkParam.LTFseed2BinWin; + mLTFinterBinWin = trkParam.LTFinterBinWin; + mLTFConeRadius = trkParam.LTFConeRadius; + mCAConeRadius = trkParam.CAConeRadius; + + mRBins = trkParam.RBins; + mPhiBins = trkParam.PhiBins; + mRPhiBins = trkParam.RBins * trkParam.PhiBins; + if (mRPhiBins > constants::index_table::MaxRPhiBins) { + LOG(WARN) << "To many RPhiBins for this configuration!"; + mRPhiBins = constants::index_table::MaxRPhiBins; + mRBins = sqrt(constants::index_table::MaxRPhiBins); + mPhiBins = sqrt(constants::index_table::MaxRPhiBins); + LOG(WARN) << "Using instead RBins " << mRBins << " and PhiBins " << mPhiBins; + } + mRBinSize = (constants::index_table::RMax - constants::index_table::RMin) / mRBins; + mPhiBinSize = (constants::index_table::PhiMax - constants::index_table::PhiMin) / mPhiBins; + + if (printConfig) { + LOG(INFO) << "Configurable tracker parameters:"; + LOG(INFO) << "MinTrackPointsLTF = " << mMinTrackPointsLTF; + LOG(INFO) << "MinTrackPointsCA = " << mMinTrackPointsCA; + LOG(INFO) << "MinTrackStationsLTF = " << mMinTrackStationsLTF; + LOG(INFO) << "MinTrackStationsCA = " << mMinTrackStationsCA; + LOG(INFO) << "LTFclsRCut = " << mLTFclsRCut; + LOG(INFO) << "ROADclsRCut = " << mROADclsRCut; + LOG(INFO) << "RBins = " << mRBins; + LOG(INFO) << "PhiBins = " << mPhiBins; + LOG(INFO) << "LTFseed2BinWin = " << mLTFseed2BinWin; + LOG(INFO) << "LTFinterBinWin = " << mLTFinterBinWin; + } +} + +//_________________________________________________________________________________________________ +void Tracker::initialize(bool fullClusterScan) +{ + mRoad.initialize(); + + if (fullClusterScan) { + mFullClusterScan = true; + return; + } + + /// calculate Look-Up-Table of the R-Phi bins projection from one layer to another + /// layer1 + global R-Phi bin index ---> layer2 + R bin index + Phi bin index + + Float_t dz, x, y, r, phi, x_proj, y_proj, r_proj, phi_proj; + Int_t binIndex1, binIndex2, binIndex2S, binR_proj, binPhi_proj; + + for (Int_t layer1 = 0; layer1 < (constants::mft::LayersNumber - 1); ++layer1) { + + for (Int_t iRBin = 0; iRBin < mRBins; ++iRBin) { + + r = (iRBin + 0.5) * mRBinSize + constants::index_table::RMin; + + for (Int_t iPhiBin = 0; iPhiBin < mPhiBins; ++iPhiBin) { + + phi = (iPhiBin + 0.5) * mPhiBinSize + constants::index_table::PhiMin; + + binIndex1 = getBinIndex(iRBin, iPhiBin); + + x = r * TMath::Cos(phi); + y = r * TMath::Sin(phi); + + for (Int_t layer2 = (layer1 + 1); layer2 < constants::mft::LayersNumber; ++layer2) { + + dz = constants::mft::LayerZCoordinate()[layer2] - constants::mft::LayerZCoordinate()[layer1]; + x_proj = x + dz * x * constants::mft::InverseLayerZCoordinate()[layer1]; + y_proj = y + dz * y * constants::mft::InverseLayerZCoordinate()[layer1]; + auto clsPoint2D = math_utils::Point2D<Float_t>(x_proj, y_proj); + r_proj = clsPoint2D.R(); + phi_proj = clsPoint2D.Phi(); + o2::math_utils::bringTo02PiGen(phi_proj); + + binR_proj = getRBinIndex(r_proj); + binPhi_proj = getPhiBinIndex(phi_proj); + + int binRS, binPhiS; + + int binwRS = mLTFseed2BinWin; + int binhwRS = binwRS / 2; + + int binwPhiS = mLTFseed2BinWin; + int binhwPhiS = binwPhiS / 2; + + for (Int_t iR = 0; iR < binwRS; ++iR) { + binRS = binR_proj + (iR - binhwRS); + if (binRS < 0) { + continue; + } + + for (Int_t iPhi = 0; iPhi < binwPhiS; ++iPhi) { + binPhiS = binPhi_proj + (iPhi - binhwPhiS); + if (binPhiS < 0) { + continue; + } + + binIndex2S = getBinIndex(binRS, binPhiS); + mBinsS[layer1][layer2 - 1][binIndex1].emplace_back(binIndex2S); + } + } + + int binR, binPhi; + + int binwR = mLTFinterBinWin; + int binhwR = binwR / 2; + + int binwPhi = mLTFinterBinWin; + int binhwPhi = binwPhi / 2; + + for (Int_t iR = 0; iR < binwR; ++iR) { + binR = binR_proj + (iR - binhwR); + if (binR < 0) { + continue; + } + + for (Int_t iPhi = 0; iPhi < binwPhi; ++iPhi) { + binPhi = binPhi_proj + (iPhi - binhwPhi); + if (binPhi < 0) { + continue; + } + + binIndex2 = getBinIndex(binR, binPhi); + mBins[layer1][layer2 - 1][binIndex1].emplace_back(binIndex2); + } + } + + } // end loop layer2 + } // end loop PhiBinIndex + } // end loop RBinIndex + } // end loop layer1 +} + //_________________________________________________________________________________________________ void Tracker::clustersToTracks(ROframe& event, std::ostream& timeBenchmarkOutputStream) { @@ -52,231 +202,432 @@ void Tracker::clustersToTracks(ROframe& event, std::ostream& timeBenchmarkOutput //_________________________________________________________________________________________________ void Tracker::findTracks(ROframe& event) { - //computeCells(event); - findTracksLTF(event); - findTracksCA(event); + if (!mFullClusterScan) { + findTracksLTF(event); + findTracksCA(event); + } else { + findTracksLTFfcs(event); + findTracksCAfcs(event); + } } //_________________________________________________________________________________________________ -void Tracker::computeCells(ROframe& event) +void Tracker::findTracksLTF(ROframe& event) { + // find (high momentum) tracks by the Linear Track Finder (LTF) method + MCCompLabel mcCompLabel; - Int_t layer1, layer2; - Int_t nClsInLayer1, nClsInLayer2; - Int_t disk1, disk2; + Int_t layer1, layer2, nPointDisks; Int_t binR_proj, binPhi_proj, bin; - Int_t binIndex, clsMinIndex, clsMaxIndex; - std::array<Int_t, 3> binsR, binsPhi; - Int_t cellId = 0; - for (layer1 = 0; layer1 < (constants::mft::LayersNumber - 1); ++layer1) { - nClsInLayer1 = event.getClustersInLayer(layer1).size(); - disk1 = layer1 / 2; - layer2 = layer1 + 1; // only (L+1) tracklets ! - disk2 = layer2 / 2; - nClsInLayer2 = event.getClustersInLayer(layer2).size(); - for (Int_t clsLayer1 = 0; clsLayer1 < nClsInLayer1; ++clsLayer1) { - const Cluster& cluster1 = event.getClustersInLayer(layer1).at(clsLayer1); - // project to next layer and get the bin index in R and Phi - getRPhiProjectionBin(cluster1, layer1, layer2, binR_proj, binPhi_proj); - // define the search window in bins x bins (3x3, 5x5, etc.) - for (Int_t i = 0; i < constants::index_table::LTFinterBinWin; ++i) { - binsR[i] = binR_proj + (i - constants::index_table::LTFinterBinWin / 2); - binsPhi[i] = binPhi_proj + (i - constants::index_table::LTFinterBinWin / 2); + Int_t binIndex, clsMinIndex, clsMaxIndex, clsMinIndexS, clsMaxIndexS; + Int_t extClsIndex; + Float_t dz = 0., dRCone = 1.; + Float_t dR2, dR2min, dR2cut = mLTFclsR2Cut; + Bool_t hasDisk[constants::mft::DisksNumber], newPoint; + + Int_t clsInLayer1, clsInLayer2, clsInLayer; + + Int_t nPoints; + TrackElement trackPoints[constants::mft::LayersNumber]; + + Int_t step = 0; + layer1 = 0; + + while (true) { + + layer2 = (step == 0) ? (constants::mft::LayersNumber - 1) : (layer2 - 1); + step++; + + if (layer2 < layer1 + (mMinTrackPointsLTF - 1)) { + ++layer1; + if (layer1 > (constants::mft::LayersNumber - (mMinTrackPointsLTF - 1))) { + break; } + step = 0; + continue; + } + + for (std::vector<Cluster>::iterator it1 = event.getClustersInLayer(layer1).begin(); it1 != event.getClustersInLayer(layer1).end(); ++it1) { + Cluster& cluster1 = *it1; + if (cluster1.getUsed()) { + continue; + } + clsInLayer1 = it1 - event.getClustersInLayer(layer1).begin(); + // loop over the bins in the search window - for (auto binR : binsR) { - for (auto binPhi : binsPhi) { - // the global bin index - bin = constants::index_table::getBinIndex(binR, binPhi); - if (!getBinClusterRange(event, layer2, bin, clsMinIndex, clsMaxIndex)) { + for (auto& binS : mBinsS[layer1][layer2 - 1][cluster1.indexTableBin]) { + + getBinClusterRange(event, layer2, binS, clsMinIndexS, clsMaxIndexS); + + for (std::vector<Cluster>::iterator it2 = (event.getClustersInLayer(layer2).begin() + clsMinIndexS); it2 != (event.getClustersInLayer(layer2).begin() + clsMaxIndexS + 1); ++it2) { + Cluster& cluster2 = *it2; + if (cluster2.getUsed()) { + continue; + } + clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin(); + + // start a TrackLTF + nPoints = 0; + + // add the first seed point + trackPoints[nPoints].layer = layer1; + trackPoints[nPoints].idInLayer = clsInLayer1; + nPoints++; + + // intermediate layers + for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { + + newPoint = kTRUE; + + //check if road is a cylinder or a cone + dz = constants::mft::LayerZCoordinate()[layer2] - constants::mft::LayerZCoordinate()[layer1]; + dRCone = 1 + dz * constants::mft::InverseLayerZCoordinate()[layer1]; + + // loop over the bins in the search window + dR2min = mLTFConeRadius ? dR2cut * dRCone * dRCone : dR2cut; + for (auto& bin : mBins[layer1][layer - 1][cluster1.indexTableBin]) { + + getBinClusterRange(event, layer, bin, clsMinIndex, clsMaxIndex); + + for (std::vector<Cluster>::iterator it = (event.getClustersInLayer(layer).begin() + clsMinIndex); it != (event.getClustersInLayer(layer).begin() + clsMaxIndex + 1); ++it) { + Cluster& cluster = *it; + if (cluster.getUsed()) { + continue; + } + clsInLayer = it - event.getClustersInLayer(layer).begin(); + + dR2 = getDistanceToSeed(cluster1, cluster2, cluster); + // retain the closest point within a radius dR2cut + if (dR2 >= dR2min) { + continue; + } + dR2min = dR2; + + if (newPoint) { + trackPoints[nPoints].layer = layer; + trackPoints[nPoints].idInLayer = clsInLayer; + nPoints++; + } + // retain only the closest point in DistanceToSeed + newPoint = false; + } // end clusters bin intermediate layer + } // end intermediate layers + } // end binRPhi + + // add the second seed point + trackPoints[nPoints].layer = layer2; + trackPoints[nPoints].idInLayer = clsInLayer2; + nPoints++; + + // keep only tracks fulfilling the minimum length condition + if (nPoints < mMinTrackPointsLTF) { continue; } - for (Int_t clsLayer2 = clsMinIndex; clsLayer2 <= clsMaxIndex; ++clsLayer2) { - event.addCellToLayer(layer1, layer2, clsLayer1, clsLayer2, cellId++); - } // end clusters bin layer2 - } // end binPhi - } // end binR - } // end clusters layer1 - } // end layers + for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { + hasDisk[i] = kFALSE; + } + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = trackPoints[point].layer; + hasDisk[layer / 2] = kTRUE; + } + nPointDisks = 0; + for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { + if (hasDisk[disk]) { + ++nPointDisks; + } + } + if (nPointDisks < mMinTrackStationsLTF) { + continue; + } + + // add a new TrackLTF + event.addTrackLTF(); + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = trackPoints[point].layer; + auto clsInLayer = trackPoints[point].idInLayer; + Cluster& cluster = event.getClustersInLayer(layer)[clsInLayer]; + mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel(); + extClsIndex = event.getClusterExternalIndex(layer, cluster.clusterId); + event.getCurrentTrackLTF().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex); + // mark the used clusters + cluster.setUsed(true); + } + } // end seed clusters bin layer2 + } // end binRPhi + } // end clusters layer1 + + } // end seeding } //_________________________________________________________________________________________________ -void Tracker::findTracksLTF(ROframe& event) +void Tracker::findTracksLTFfcs(ROframe& event) { // find (high momentum) tracks by the Linear Track Finder (LTF) method + // with full scan of the clusters in the target plane MCCompLabel mcCompLabel; Int_t layer1, layer2, nPointDisks; - Int_t nClsInLayer1, nClsInLayer2, nClsInLayer; Int_t binR_proj, binPhi_proj, bin; Int_t binIndex, clsMinIndex, clsMaxIndex, clsMinIndexS, clsMaxIndexS; Int_t extClsIndex; - Float_t dR, dRmin, dRcut = constants::mft::LTFclsRCut; - std::vector<Int_t> binsR, binsPhi, binsRS, binsPhiS; - Bool_t hasDisk[constants::mft::DisksNumber], newPoint, seed = kTRUE; + Float_t dR2, dR2min, dR2cut = mLTFclsR2Cut; + Bool_t hasDisk[constants::mft::DisksNumber], newPoint; - binsRS.resize(constants::index_table::LTFseed2BinWin); - binsPhiS.resize(constants::index_table::LTFseed2BinWin); + Int_t clsInLayer1, clsInLayer2, clsInLayer; - binsR.resize(constants::index_table::LTFinterBinWin); - binsPhi.resize(constants::index_table::LTFinterBinWin); + Int_t nPoints; + TrackElement trackPoints[constants::mft::LayersNumber]; Int_t step = 0; - layer1 = 0; - while (seed) { - - if (step == 0) { - layer2 = constants::mft::LayersNumber - 1; - } else { - layer2--; - } + while (true) { + layer2 = (step == 0) ? (constants::mft::LayersNumber - 1) : (layer2 - 1); step++; - if (layer2 < layer1 + (constants::mft::MinTrackPoints - 1)) { + if (layer2 < layer1 + (mMinTrackPointsLTF - 1)) { ++layer1; - if (layer1 > (constants::mft::LayersNumber - (constants::mft::MinTrackPoints - 1))) { + if (layer1 > (constants::mft::LayersNumber - (mMinTrackPointsLTF - 1))) { break; } step = 0; continue; } - nClsInLayer1 = event.getClustersInLayer(layer1).size(); - nClsInLayer2 = event.getClustersInLayer(layer2).size(); - - for (Int_t clsLayer1 = 0; clsLayer1 < nClsInLayer1; ++clsLayer1) { - if (event.isClusterUsed(layer1, clsLayer1)) { + for (std::vector<Cluster>::iterator it1 = event.getClustersInLayer(layer1).begin(); it1 != event.getClustersInLayer(layer1).end(); ++it1) { + Cluster& cluster1 = *it1; + if (cluster1.getUsed()) { continue; } - const Cluster& cluster1 = event.getClustersInLayer(layer1)[clsLayer1]; - - // project to the second seed layer and get the bin index in R and Phi - getRPhiProjectionBin(cluster1, layer1, layer2, binR_proj, binPhi_proj); - // define the search window in bins x bins (3x3, 5x5, etc.) - for (Int_t i = 0; i < constants::index_table::LTFseed2BinWin; ++i) { - binsRS[i] = binR_proj + (i - constants::index_table::LTFseed2BinWin / 2); - binsPhiS[i] = binPhi_proj + (i - constants::index_table::LTFseed2BinWin / 2); - } - // loop over the bins in the search window - for (auto binRS : binsRS) { - for (auto binPhiS : binsPhiS) { - // the global bin index - bin = constants::index_table::getBinIndex(binRS, binPhiS); - if (!getBinClusterRange(event, layer2, bin, clsMinIndexS, clsMaxIndexS)) { - continue; - } - for (Int_t clsLayer2 = clsMinIndexS; clsLayer2 <= clsMaxIndexS; ++clsLayer2) { - if (event.isClusterUsed(layer2, clsLayer2)) { + clsInLayer1 = it1 - event.getClustersInLayer(layer1).begin(); + + for (std::vector<Cluster>::iterator it2 = event.getClustersInLayer(layer2).begin(); it2 != event.getClustersInLayer(layer2).end(); ++it2) { + Cluster& cluster2 = *it2; + if (cluster2.getUsed()) { + continue; + } + clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin(); + + // start a TrackLTF + nPoints = 0; + + // add the first seed point + trackPoints[nPoints].layer = layer1; + trackPoints[nPoints].idInLayer = clsInLayer1; + nPoints++; + + // intermediate layers + for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { + + newPoint = kTRUE; + + // loop over the bins in the search window + dR2min = dR2cut; + for (std::vector<Cluster>::iterator it = event.getClustersInLayer(layer).begin(); it != event.getClustersInLayer(layer).end(); ++it) { + Cluster& cluster = *it; + if (cluster.getUsed()) { continue; } - const Cluster& cluster2 = event.getClustersInLayer(layer2)[clsLayer2]; + clsInLayer = it - event.getClustersInLayer(layer).begin(); - for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { - hasDisk[i] = kFALSE; + dR2 = getDistanceToSeed(cluster1, cluster2, cluster); + // retain the closest point within a radius dR2cut + if (dR2 >= dR2min) { + continue; } + dR2min = dR2; - hasDisk[layer1 / 2] = kTRUE; - hasDisk[layer2 / 2] = kTRUE; + if (newPoint) { + trackPoints[nPoints].layer = layer; + trackPoints[nPoints].idInLayer = clsInLayer; + nPoints++; + } + // retain only the closest point in DistanceToSeed + newPoint = false; + } // end clusters bin intermediate layer + } // end intermediate layers + + // add the second seed point + trackPoints[nPoints].layer = layer2; + trackPoints[nPoints].idInLayer = clsInLayer2; + nPoints++; + + // keep only tracks fulfilling the minimum length condition + if (nPoints < mMinTrackPointsLTF) { + continue; + } + for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { + hasDisk[i] = kFALSE; + } + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = trackPoints[point].layer; + hasDisk[layer / 2] = kTRUE; + } + nPointDisks = 0; + for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { + if (hasDisk[disk]) { + ++nPointDisks; + } + } + if (nPointDisks < mMinTrackStationsLTF) { + continue; + } - // start a track LTF - event.addTrackLTF(); + // add a new TrackLTF + event.addTrackLTF(); + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = trackPoints[point].layer; + auto clsInLayer = trackPoints[point].idInLayer; + Cluster& cluster = event.getClustersInLayer(layer)[clsInLayer]; + mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel(); + extClsIndex = event.getClusterExternalIndex(layer, cluster.clusterId); + event.getCurrentTrackLTF().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex); + // mark the used clusters + cluster.setUsed(true); + } + } // end seed clusters bin layer2 + } // end clusters layer1 - // add the first seed-point - mcCompLabel = mUseMC ? event.getClusterLabels(layer1, cluster1.clusterId) : MCCompLabel(); - newPoint = kTRUE; - extClsIndex = event.getClusterExternalIndex(layer1, cluster1.clusterId); - event.getCurrentTrackLTF().setPoint(cluster1, layer1, clsLayer1, mcCompLabel, extClsIndex, newPoint); + } // end seeding +} - for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { +//_________________________________________________________________________________________________ +void Tracker::findTracksCA(ROframe& event) +{ + // layers: 0, 1, 2, ..., 9 + // rules for combining first/last plane in a road: + // 0 with 6, 7, 8, 9 + // 1 with 6, 7, 8, 9 + // 2 with 8, 9 + // 3 with 8, 9 + Int_t layer1Min = 0, layer1Max = 3; + Int_t layer2Min[4] = {6, 6, 8, 8}; + constexpr Int_t layer2Max = constants::mft::LayersNumber - 1; - nClsInLayer = event.getClustersInLayer(layer).size(); + MCCompLabel mcCompLabel; + Int_t roadId, nPointDisks; + Int_t binR_proj, binPhi_proj, bin; + Int_t binIndex, clsMinIndex, clsMaxIndex, clsMinIndexS, clsMaxIndexS; + Float_t dz = 0., dRCone = 1.; + Float_t dR2, dR2min, dR2cut = mROADclsR2Cut; + Bool_t hasDisk[constants::mft::DisksNumber]; - newPoint = kTRUE; + Int_t clsInLayer1, clsInLayer2, clsInLayer; - // project to the intermediate layer and get the bin index in R and Phi - getRPhiProjectionBin(cluster1, layer1, layer, binR_proj, binPhi_proj); + Int_t nPoints; + std::vector<TrackElement> roadPoints; + + roadId = 0; + + for (Int_t layer1 = layer1Min; layer1 <= layer1Max; ++layer1) { + + for (Int_t layer2 = layer2Max; layer2 >= layer2Min[layer1]; --layer2) { + + for (std::vector<Cluster>::iterator it1 = event.getClustersInLayer(layer1).begin(); it1 != event.getClustersInLayer(layer1).end(); ++it1) { + Cluster& cluster1 = *it1; + if (cluster1.getUsed()) { + continue; + } + clsInLayer1 = it1 - event.getClustersInLayer(layer1).begin(); + + // loop over the bins in the search window + for (auto& binS : mBinsS[layer1][layer2 - 1][cluster1.indexTableBin]) { + + getBinClusterRange(event, layer2, binS, clsMinIndexS, clsMaxIndexS); + + for (std::vector<Cluster>::iterator it2 = (event.getClustersInLayer(layer2).begin() + clsMinIndexS); it2 != (event.getClustersInLayer(layer2).begin() + clsMaxIndexS + 1); ++it2) { + Cluster& cluster2 = *it2; + if (cluster2.getUsed()) { + continue; + } + clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin(); + + // start a road + roadPoints.clear(); + + // add the first seed point + roadPoints.emplace_back(layer1, clsInLayer1); + + for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { + + //check if road is a cylinder or a cone + dz = constants::mft::LayerZCoordinate()[layer2] - constants::mft::LayerZCoordinate()[layer1]; + dRCone = 1 + dz * constants::mft::InverseLayerZCoordinate()[layer1]; + + dR2min = mLTFConeRadius ? dR2cut * dRCone * dRCone : dR2cut; - // define the search window in bins x bins (3x3, 5x5, etc.) - for (Int_t i = 0; i < constants::index_table::LTFinterBinWin; ++i) { - binsR[i] = binR_proj + (i - constants::index_table::LTFinterBinWin / 2); - binsPhi[i] = binPhi_proj + (i - constants::index_table::LTFinterBinWin / 2); - } // loop over the bins in the search window - dRmin = dRcut; - for (auto binR : binsR) { - for (auto binPhi : binsPhi) { - // the global bin index - bin = constants::index_table::getBinIndex(binR, binPhi); - if (!getBinClusterRange(event, layer, bin, clsMinIndex, clsMaxIndex)) { + for (auto& bin : mBins[layer1][layer - 1][cluster1.indexTableBin]) { + + getBinClusterRange(event, layer, bin, clsMinIndex, clsMaxIndex); + + for (std::vector<Cluster>::iterator it = (event.getClustersInLayer(layer).begin() + clsMinIndex); it != (event.getClustersInLayer(layer).begin() + clsMaxIndex + 1); ++it) { + Cluster& cluster = *it; + if (cluster.getUsed()) { continue; } - for (Int_t clsLayer = clsMinIndex; clsLayer <= clsMaxIndex; ++clsLayer) { - if (event.isClusterUsed(layer, clsLayer)) { - continue; - } - const Cluster& cluster = event.getClustersInLayer(layer)[clsLayer]; - - dR = getDistanceToSeed(cluster1, cluster2, cluster); - // retain the closest point within a radius dRcut - if (dR >= dRmin) { - continue; - } - dRmin = dR; - - hasDisk[layer / 2] = kTRUE; - mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel(); - extClsIndex = event.getClusterExternalIndex(layer, cluster.clusterId); - event.getCurrentTrackLTF().setPoint(cluster, layer, clsLayer, mcCompLabel, extClsIndex, newPoint); - // retain only the closest point in DistanceToSeed - newPoint = false; - } // end clusters bin intermediate layer - } // end intermediate layers - } // end binPhi - } // end binR - - // add the second seed-point - mcCompLabel = mUseMC ? event.getClusterLabels(layer2, cluster2.clusterId) : MCCompLabel(); - newPoint = kTRUE; - extClsIndex = event.getClusterExternalIndex(layer2, cluster2.clusterId); - event.getCurrentTrackLTF().setPoint(cluster2, layer2, clsLayer2, mcCompLabel, extClsIndex, newPoint); + clsInLayer = it - event.getClustersInLayer(layer).begin(); + + dR2 = getDistanceToSeed(cluster1, cluster2, cluster); + // add all points within a radius dR2cut + if (dR2 >= dR2min) { + continue; + } + + roadPoints.emplace_back(layer, clsInLayer); - // keep only tracks fulfilling the minimum length condition - if (event.getCurrentTrackLTF().getNumberOfPoints() < constants::mft::MinTrackPoints) { - event.removeCurrentTrackLTF(); + } // end clusters bin intermediate layer + } // end intermediate layers + } // end binR + + // add the second seed point + roadPoints.emplace_back(layer2, clsInLayer2); + nPoints = roadPoints.size(); + + // keep only roads fulfilling the minimum length condition + if (nPoints < mMinTrackPointsCA) { continue; } + for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { + hasDisk[i] = kFALSE; + } + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = roadPoints[point].layer; + hasDisk[layer / 2] = kTRUE; + } nPointDisks = 0; for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { if (hasDisk[disk]) { ++nPointDisks; } } - if (nPointDisks < constants::mft::MinTrackPoints) { - event.removeCurrentTrackLTF(); + if (nPointDisks < mMinTrackStationsCA) { continue; } - // mark the used clusters - //Int_t lay, layMin = 10, layMax = -1; - for (Int_t point = 0; point < event.getCurrentTrackLTF().getNumberOfPoints(); ++point) { - event.markUsedCluster(event.getCurrentTrackLTF().getLayers()[point], event.getCurrentTrackLTF().getClustersId()[point]); - //lay = event.getCurrentTrackLTF().getLayers()[point]; - //layMin = (lay < layMin) ? lay : layMin; - //layMax = (lay > layMax) ? lay : layMax; + mRoad.reset(); + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = roadPoints[point].layer; + auto clsInLayer = roadPoints[point].idInLayer; + mRoad.setPoint(layer, clsInLayer); } - } // end seed clusters bin layer2 - } // end binPhi - } // end binR - } // end clusters layer1 - - } // end seeding + mRoad.setRoadId(roadId); + ++roadId; + + computeCellsInRoad(event); + runForwardInRoad(); + runBackwardInRoad(event); + + } // end clusters in layer2 + } // end binRPhi + } // end clusters in layer1 + } // end layer2 + } // end layer1 } //_________________________________________________________________________________________________ -void Tracker::findTracksCA(ROframe& event) +void Tracker::findTracksCAfcs(ROframe& event) { // layers: 0, 1, 2, ..., 9 // rules for combining first/last plane in a road: @@ -286,202 +637,168 @@ void Tracker::findTracksCA(ROframe& event) // 3 with 8, 9 Int_t layer1Min = 0, layer1Max = 3; Int_t layer2Min[4] = {6, 6, 8, 8}; - Int_t layer2Max[4] = {9, 9, 9, 9}; + constexpr Int_t layer2Max = constants::mft::LayersNumber - 1; MCCompLabel mcCompLabel; Int_t roadId, nPointDisks; - Int_t nClsInLayer1, nClsInLayer2, nClsInLayer; Int_t binR_proj, binPhi_proj, bin; Int_t binIndex, clsMinIndex, clsMaxIndex, clsMinIndexS, clsMaxIndexS; - Float_t dR, dRcut = constants::mft::ROADclsRCut; - std::vector<Int_t> binsR, binsPhi, binsRS, binsPhiS; - Bool_t hasDisk[constants::mft::DisksNumber], newPoint; + Float_t dR2, dR2cut = mROADclsR2Cut; + Bool_t hasDisk[constants::mft::DisksNumber]; - binsRS.resize(constants::index_table::LTFseed2BinWin); - binsPhiS.resize(constants::index_table::LTFseed2BinWin); + Int_t clsInLayer1, clsInLayer2, clsInLayer; - binsR.resize(constants::index_table::LTFinterBinWin); - binsPhi.resize(constants::index_table::LTFinterBinWin); + Int_t nPoints; + std::vector<TrackElement> roadPoints; roadId = 0; for (Int_t layer1 = layer1Min; layer1 <= layer1Max; ++layer1) { - nClsInLayer1 = event.getClustersInLayer(layer1).size(); + for (Int_t layer2 = layer2Max; layer2 >= layer2Min[layer1]; --layer2) { - for (Int_t layer2 = layer2Max[layer1]; layer2 >= layer2Min[layer1]; --layer2) { + for (std::vector<Cluster>::iterator it1 = event.getClustersInLayer(layer1).begin(); it1 != event.getClustersInLayer(layer1).end(); ++it1) { + Cluster& cluster1 = *it1; + if (cluster1.getUsed()) { + continue; + } + clsInLayer1 = it1 - event.getClustersInLayer(layer1).begin(); - nClsInLayer2 = event.getClustersInLayer(layer2).size(); + for (std::vector<Cluster>::iterator it2 = event.getClustersInLayer(layer2).begin(); it2 != event.getClustersInLayer(layer2).end(); ++it2) { + Cluster& cluster2 = *it2; + if (cluster2.getUsed()) { + continue; + } + clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin(); - for (Int_t clsLayer1 = 0; clsLayer1 < nClsInLayer1; ++clsLayer1) { + // start a road + roadPoints.clear(); - if (event.isClusterUsed(layer1, clsLayer1)) { - continue; - } - const Cluster& cluster1 = event.getClustersInLayer(layer1)[clsLayer1]; - - // project to the second seed layer and get the bin index in R and Phi - getRPhiProjectionBin(cluster1, layer1, layer2, binR_proj, binPhi_proj); - // define the search window in bins x bins (3x3, 5x5, etc.) - for (Int_t i = 0; i < constants::index_table::LTFseed2BinWin; ++i) { - binsRS[i] = binR_proj + (i - constants::index_table::LTFseed2BinWin / 2); - binsPhiS[i] = binPhi_proj + (i - constants::index_table::LTFseed2BinWin / 2); - } + // add the first seed point + roadPoints.emplace_back(layer1, clsInLayer1); - // loop over the bins in the search window - for (auto binRS : binsRS) { - for (auto binPhiS : binsPhiS) { - // the global bin index - bin = constants::index_table::getBinIndex(binRS, binPhiS); - if (!getBinClusterRange(event, layer2, bin, clsMinIndexS, clsMaxIndexS)) { - continue; - } - for (Int_t clsLayer2 = clsMinIndexS; clsLayer2 <= clsMaxIndexS; ++clsLayer2) { - if (event.isClusterUsed(layer2, clsLayer2)) { + for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { + + for (std::vector<Cluster>::iterator it = event.getClustersInLayer(layer).begin(); it != event.getClustersInLayer(layer).end(); ++it) { + Cluster& cluster = *it; + if (cluster.getUsed()) { continue; } - const Cluster& cluster2 = event.getClustersInLayer(layer2)[clsLayer2]; + clsInLayer = it - event.getClustersInLayer(layer).begin(); - for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { - hasDisk[i] = kFALSE; + dR2 = getDistanceToSeed(cluster1, cluster2, cluster); + // add all points within a radius dR2cut + if (dR2 >= dR2cut) { + continue; } - hasDisk[layer1 / 2] = kTRUE; - hasDisk[layer2 / 2] = kTRUE; + roadPoints.emplace_back(layer, clsInLayer); - // start a road - event.addRoad(); + } // end clusters bin intermediate layer + } // end intermediate layers - // add the 1st/2nd road points - mcCompLabel = mUseMC ? event.getClusterLabels(layer1, cluster1.clusterId) : MCCompLabel(); - newPoint = kTRUE; - event.getCurrentRoad().setPoint(cluster1.getX(), cluster1.getY(), cluster1.getZ(), layer1, clsLayer1, mcCompLabel, newPoint); + // add the second seed point + roadPoints.emplace_back(layer2, clsInLayer2); + nPoints = roadPoints.size(); - for (Int_t layer = (layer1 + 1); layer <= (layer2 - 1); ++layer) { + // keep only roads fulfilling the minimum length condition + if (nPoints < mMinTrackPointsCA) { + continue; + } + for (Int_t i = 0; i < (constants::mft::DisksNumber); i++) { + hasDisk[i] = kFALSE; + } + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = roadPoints[point].layer; + hasDisk[layer / 2] = kTRUE; + } + nPointDisks = 0; + for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { + if (hasDisk[disk]) { + ++nPointDisks; + } + } + if (nPointDisks < mMinTrackStationsCA) { + continue; + } - nClsInLayer = event.getClustersInLayer(layer).size(); + mRoad.reset(); + for (Int_t point = 0; point < nPoints; ++point) { + auto layer = roadPoints[point].layer; + auto clsInLayer = roadPoints[point].idInLayer; + mRoad.setPoint(layer, clsInLayer); + } + mRoad.setRoadId(roadId); + ++roadId; - // project to the intermediate layer and get the bin index in R and Phi - getRPhiProjectionBin(cluster1, layer1, layer, binR_proj, binPhi_proj); - // define the search window in bins x bins (3x3, 5x5, etc.) - for (Int_t i = 0; i < constants::index_table::LTFinterBinWin; ++i) { - binsR[i] = binR_proj + (i - constants::index_table::LTFinterBinWin / 2); - binsPhi[i] = binPhi_proj + (i - constants::index_table::LTFinterBinWin / 2); - } + computeCellsInRoad(event); + runForwardInRoad(); + runBackwardInRoad(event); - // loop over the bins in the search window - for (auto binR : binsR) { - for (auto binPhi : binsPhi) { - // the global bin index - bin = constants::index_table::getBinIndex(binR, binPhi); - if (!getBinClusterRange(event, layer, bin, clsMinIndex, clsMaxIndex)) { - continue; - } - for (Int_t clsLayer = clsMinIndex; clsLayer <= clsMaxIndex; ++clsLayer) { - if (event.isClusterUsed(layer, clsLayer)) { - continue; - } - const Cluster& cluster = event.getClustersInLayer(layer)[clsLayer]; - - dR = getDistanceToSeed(cluster1, cluster2, cluster); - // add all points within a radius dRcut - if (dR >= dRcut) { - continue; - } - hasDisk[layer / 2] = kTRUE; - mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel(); - newPoint = kTRUE; - event.getCurrentRoad().setPoint(cluster.getX(), cluster.getY(), cluster.getZ(), layer, clsLayer, mcCompLabel, newPoint); - - } // end clusters bin intermediate layer - } // end intermediate layers - } // end binPhi - } // end binR - - // add the second seed-point - mcCompLabel = mUseMC ? event.getClusterLabels(layer2, cluster2.clusterId) : MCCompLabel(); - newPoint = kTRUE; - event.getCurrentRoad().setPoint(cluster2.getX(), cluster2.getY(), cluster2.getZ(), layer2, clsLayer2, mcCompLabel, newPoint); - - // keep only roads fulfilling the minimum length condition - if (event.getCurrentRoad().getNPoints() < constants::mft::MinTrackPoints) { - event.removeCurrentRoad(); - continue; - } - nPointDisks = 0; - for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { - if (hasDisk[disk]) { - ++nPointDisks; - } - } - if (nPointDisks < constants::mft::MinTrackPoints) { - event.removeCurrentRoad(); - continue; - } - event.getCurrentRoad().setNDisks(nPointDisks); - event.getCurrentRoad().setRoadId(roadId); - ++roadId; - - computeCellsInRoad(event.getCurrentRoad()); - runForwardInRoad(event); - runBackwardInRoad(event); - - } // end clusters bin layer2 - } // end binPhiS - } // end binRS - } // end clusters in layer1 - } // end layer2 - } // end layer1 + } // end clusters in layer2 + } // end clusters in layer1 + } // end layer2 + } // end layer1 } //_________________________________________________________________________________________________ -void Tracker::computeCellsInRoad(Road& road) +void Tracker::computeCellsInRoad(ROframe& event) { Int_t layer1, layer1min, layer1max, layer2, layer2min, layer2max; Int_t nPtsInLayer1, nPtsInLayer2; - Int_t clsLayer1, clsLayer2; + Int_t clsInLayer1, clsInLayer2; + Int_t cellId; Bool_t noCell; - road.getLength(layer1min, layer1max); + mRoad.getLength(layer1min, layer1max); --layer1max; - Int_t cellId = 0; for (layer1 = layer1min; layer1 <= layer1max; ++layer1) { + + cellId = 0; + layer2min = layer1 + 1; layer2max = std::min(layer1 + (constants::mft::DisksNumber - isDiskFace(layer1)), constants::mft::LayersNumber - 1); - nPtsInLayer1 = road.getNPointsInLayer(layer1); + + nPtsInLayer1 = mRoad.getNPointsInLayer(layer1); + for (Int_t point1 = 0; point1 < nPtsInLayer1; ++point1) { - clsLayer1 = road.getClustersIdInLayer(layer1)[point1]; + + clsInLayer1 = mRoad.getClustersIdInLayer(layer1)[point1]; + layer2 = layer2min; + noCell = kTRUE; while (noCell && (layer2 <= layer2max)) { - nPtsInLayer2 = road.getNPointsInLayer(layer2); + + nPtsInLayer2 = mRoad.getNPointsInLayer(layer2); /* if (nPtsInLayer2 > 1) { - LOG(INFO) << "BV===== more than one point in road " << road.getRoadId() << " in layer " << layer2 << " : " << nPtsInLayer2 << "\n"; + LOG(INFO) << "BV===== more than one point in road " << mRoad.getRoadId() << " in layer " << layer2 << " : " << nPtsInLayer2 << "\n"; } - */ + */ for (Int_t point2 = 0; point2 < nPtsInLayer2; ++point2) { - clsLayer2 = road.getClustersIdInLayer(layer2)[point2]; + + clsInLayer2 = mRoad.getClustersIdInLayer(layer2)[point2]; + noCell = kFALSE; // create a cell - road.addCellToLayer(layer1, layer2, clsLayer1, clsLayer2, cellId++); + addCellToCurrentRoad(event, layer1, layer2, clsInLayer1, clsInLayer2, cellId); } // end points in layer2 ++layer2; + } // end while(noCell && (layer2 <= layer2max)) } // end points in layer1 } // end layer1 } //_________________________________________________________________________________________________ -void Tracker::runForwardInRoad(ROframe& event) +void Tracker::runForwardInRoad() { Int_t layerR, layerL, icellR, icellL; Int_t iter = 0; Bool_t levelChange = kTRUE; - Road& road = event.getCurrentRoad(); - while (levelChange) { levelChange = kFALSE; @@ -490,39 +807,36 @@ void Tracker::runForwardInRoad(ROframe& event) // R = right, L = left for (layerL = 0; layerL < (constants::mft::LayersNumber - 2); ++layerL) { - for (icellL = 0; icellL < road.getCellsInLayer(layerL).size(); ++icellL) { - const Cell& cellL = road.getCellsInLayer(layerL)[icellL]; + for (icellL = 0; icellL < mRoad.getCellsInLayer(layerL).size(); ++icellL) { - if (cellL.getLevel() == 0) { - continue; - } + Cell& cellL = mRoad.getCellsInLayer(layerL)[icellL]; layerR = cellL.getSecondLayerId(); - if (layerR >= (constants::mft::LayersNumber - 1)) { + + if (layerR == (constants::mft::LayersNumber - 1)) { continue; } - for (icellR = 0; icellR < road.getCellsInLayer(layerR).size(); ++icellR) { - const Cell& cellR = road.getCellsInLayer(layerR)[icellR]; + for (icellR = 0; icellR < mRoad.getCellsInLayer(layerR).size(); ++icellR) { - if (cellR.getLevel() == 0) { - continue; - } - if ((cellL.getLevel() == cellR.getLevel()) && getCellsConnect(event, cellL, cellR)) { + Cell& cellR = mRoad.getCellsInLayer(layerR)[icellR]; + + if ((cellL.getLevel() == cellR.getLevel()) && getCellsConnect(cellL, cellR)) { if (iter == 1) { - road.addRightNeighbourToCell(layerL, icellL, layerR, icellR); - road.addLeftNeighbourToCell(layerR, icellR, layerL, icellL); + mRoad.addRightNeighbourToCell(layerL, icellL, layerR, icellR); + mRoad.addLeftNeighbourToCell(layerR, icellR, layerL, icellL); } - road.incrementCellLevel(layerR, icellR); + mRoad.incrementCellLevel(layerR, icellR); levelChange = kTRUE; + } // end matching cells } // end loop cellR } // end loop cellL } // end loop layer - updateCellStatusInRoad(road); + updateCellStatusInRoad(); - } // end while (step) + } // end while (levelChange) } //_________________________________________________________________________________________________ @@ -534,107 +848,74 @@ void Tracker::runBackwardInRoad(ROframe& event) Bool_t addCellToNewTrack, hasDisk[constants::mft::DisksNumber]; - Int_t iSelectChisquare, iSelectDeviation, lastCellLayer, lastCellId; - Int_t icell, layerC, cellIdC, nPointDisks; - Float_t chisquarePrev, deviationPrev, deviation, chisquare; + Int_t lastCellLayer, lastCellId, icell; + Int_t cellId, layerC, cellIdC, layerRC, cellIdRC, layerL, cellIdL; + Int_t nPointDisks; + Float_t deviationPrev, deviation; - // start layer Int_t minLayer = 6; Int_t maxLayer = 8; - Road& road = event.getCurrentRoad(); + Int_t nCells; + TrackElement trackCells[constants::mft::LayersNumber - 1]; for (Int_t layer = maxLayer; layer >= minLayer; --layer) { - for (icell = 0; icell < road.getCellsInLayer(layer).size(); ++icell) { - if (road.getCellLevel(layer, icell) == 0) { - continue; - } - if (road.isCellUsed(layer, icell)) { - continue; - } - if (road.getCellLevel(layer, icell) < (constants::mft::MinTrackPoints - 1)) { + for (cellId = 0; cellId < mRoad.getCellsInLayer(layer).size(); ++cellId) { + + if (mRoad.isCellUsed(layer, cellId) || (mRoad.getCellLevel(layer, cellId) < (mMinTrackPointsCA - 1))) { continue; } - // start a track CA - event.addTrackCA(); - event.getCurrentTrackCA().setRoadId(road.getRoadId()); - event.getCurrentTrackCA().setCA(); - if (addCellToCurrentTrackCA(layer, icell, event)) { - road.setCellUsed(layer, icell, kTRUE); - } + // start a TrackCA + nCells = 0; - // add cells to new track + trackCells[nCells].layer = layer; + trackCells[nCells].idInLayer = cellId; + nCells++; + + // add cells to the new track addCellToNewTrack = kTRUE; while (addCellToNewTrack) { - Int_t layerRC = event.getCurrentTrackCA().getCellsLayer()[event.getCurrentTrackCA().getNCells() - 1]; - Int_t cellIdRC = event.getCurrentTrackCA().getCellsId()[event.getCurrentTrackCA().getNCells() - 1]; - const Cell& cellRC = road.getCellsInLayer(layerRC)[cellIdRC]; - addCellToNewTrack = kFALSE; - // find the left neighbor giving the smalles chisquare - iSelectChisquare = 0; - chisquarePrev = 0.; + layerRC = trackCells[nCells - 1].layer; + cellIdRC = trackCells[nCells - 1].idInLayer; - // ... or + const Cell& cellRC = mRoad.getCellsInLayer(layerRC)[cellIdRC]; - // find the left neighbor giving the smallest deviation - iSelectDeviation = 0; - deviationPrev = -1.; + addCellToNewTrack = kFALSE; // loop over left neighbours deviationPrev = o2::constants::math::TwoPI; - chisquarePrev = 1.E5; for (Int_t iLN = 0; iLN < cellRC.getNLeftNeighbours(); ++iLN) { + auto leftNeighbour = cellRC.getLeftNeighbours()[iLN]; - Int_t layerL = leftNeighbour.first; - Int_t cellIdL = leftNeighbour.second; + layerL = leftNeighbour.first; + cellIdL = leftNeighbour.second; - const Cell& cellL = road.getCellsInLayer(layerL)[cellIdL]; + const Cell& cellL = mRoad.getCellsInLayer(layerL)[cellIdL]; - if (road.getCellLevel(layerL, cellIdL) == 0) { - continue; - } - if (road.isCellUsed(layerL, cellIdL)) { - continue; - } - if (road.getCellLevel(layerL, cellIdL) != (road.getCellLevel(layerRC, cellIdRC) - 1)) { + if (mRoad.isCellUsed(layerL, cellIdL) || (mRoad.getCellLevel(layerL, cellIdL) != (mRoad.getCellLevel(layerRC, cellIdRC) - 1))) { continue; } - /* - // ... smallest deviation - deviation = getCellDeviation(event, cellL, cellRC); + + deviation = getCellDeviation(cellL, cellRC); + if (deviation < deviationPrev) { + deviationPrev = deviation; - if (leftNeighbour != cellRC.getLeftNeighbours().front()) { - event.getCurrentTrackCA().removeLastCell(lastCellLayer, lastCellId); - road.setCellUsed(lastCellLayer, lastCellId, kFALSE); - road.setCellLevel(lastCellLayer, lastCellId, 1); - } - if (addCellToCurrentTrackCA(layerL, cellIdL, event)) { - addCellToNewTrack = kTRUE; - road.setCellUsed(layerL, cellIdL, kTRUE); - } - } - */ - // ... smallest chisquare - chisquare = getCellChisquare(event, cellL); - if (chisquare > 0.0 && chisquare < chisquarePrev) { - chisquarePrev = chisquare; - - if (leftNeighbour != cellRC.getLeftNeighbours().front()) { - event.getCurrentTrackCA().removeLastCell(lastCellLayer, lastCellId); - road.setCellUsed(lastCellLayer, lastCellId, kFALSE); - road.setCellLevel(lastCellLayer, lastCellId, 1); - } - if (addCellToCurrentTrackCA(layerL, cellIdL, event)) { - addCellToNewTrack = kTRUE; - road.setCellUsed(layerL, cellIdL, kTRUE); - } else { - //LOG(INFO) << "***** Failed to add cell to the current CA track! *****\n"; + + if (iLN > 0) { + // delete the last added cell + nCells--; } + + trackCells[nCells].layer = layerL; + trackCells[nCells].idInLayer = cellIdL; + nCells++; + + addCellToNewTrack = kTRUE; } } // end loop left neighbour @@ -644,237 +925,101 @@ void Tracker::runBackwardInRoad(ROframe& event) for (Int_t i = 0; i < (constants::mft::DisksNumber); ++i) { hasDisk[i] = kFALSE; } - for (icell = 0; icell < event.getCurrentTrackCA().getNCells(); ++icell) { - layerC = event.getCurrentTrackCA().getCellsLayer()[icell]; - cellIdC = event.getCurrentTrackCA().getCellsId()[icell]; - const Cell& cellC = road.getCellsInLayer(layerC)[cellIdC]; - hasDisk[cellC.getFirstLayerId() / 2] = kTRUE; - hasDisk[cellC.getSecondLayerId() / 2] = kTRUE; + + layerC = trackCells[0].layer; + cellIdC = trackCells[0].idInLayer; + const Cell& cellC = mRoad.getCellsInLayer(layerC)[cellIdC]; + hasDisk[cellC.getSecondLayerId() / 2] = kTRUE; + for (icell = 0; icell < nCells; ++icell) { + layerC = trackCells[icell].layer; + cellIdC = trackCells[icell].idInLayer; + hasDisk[layerC / 2] = kTRUE; } + nPointDisks = 0; for (Int_t disk = 0; disk < (constants::mft::DisksNumber); ++disk) { if (hasDisk[disk]) { ++nPointDisks; } } - if (nPointDisks < constants::mft::MinTrackPoints) { - for (icell = 0; icell < event.getCurrentTrackCA().getNCells(); ++icell) { - layerC = event.getCurrentTrackCA().getCellsLayer()[icell]; - cellIdC = event.getCurrentTrackCA().getCellsId()[icell]; - road.setCellUsed(layerC, cellIdC, kFALSE); - road.setCellLevel(layerC, cellIdC, 1); - } - event.removeCurrentTrackCA(); + + if (nPointDisks < mMinTrackStationsCA) { continue; } - // marked the used clusters - for (icell = 0; icell < event.getCurrentTrackCA().getNCells(); ++icell) { - layerC = event.getCurrentTrackCA().getCellsLayer()[icell]; - cellIdC = event.getCurrentTrackCA().getCellsId()[icell]; - const Cell& cellC = event.getCurrentRoad().getCellsInLayer(layerC)[cellIdC]; - event.markUsedCluster(cellC.getFirstLayerId(), cellC.getFirstClusterIndex()); - event.markUsedCluster(cellC.getSecondLayerId(), cellC.getSecondClusterIndex()); + + // add a new TrackCA + event.addTrackCA(mRoad.getRoadId()); + for (icell = 0; icell < nCells; ++icell) { + layerC = trackCells[icell].layer; + cellIdC = trackCells[icell].idInLayer; + addCellToCurrentTrackCA(layerC, cellIdC, event); + mRoad.setCellUsed(layerC, cellIdC, kTRUE); + // marked the used clusters + const Cell& cellC = mRoad.getCellsInLayer(layerC)[cellIdC]; + event.getClustersInLayer(cellC.getFirstLayerId())[cellC.getFirstClusterIndex()].setUsed(true); + event.getClustersInLayer(cellC.getSecondLayerId())[cellC.getSecondClusterIndex()].setUsed(true); } } // end loop cells } // end loop start layer } //_________________________________________________________________________________________________ -void Tracker::updateCellStatusInRoad(Road& road) +void Tracker::updateCellStatusInRoad() { - for (Int_t layer = 0; layer < (constants::mft::LayersNumber - 1); ++layer) { - for (Int_t icell = 0; icell < road.getCellsInLayer(layer).size(); ++icell) { - road.updateCellLevel(layer, icell); - mMaxCellLevel = std::max(mMaxCellLevel, road.getCellLevel(layer, icell)); + Int_t layerMin, layerMax; + mRoad.getLength(layerMin, layerMax); + for (Int_t layer = layerMin; layer < layerMax; ++layer) { + for (Int_t icell = 0; icell < mRoad.getCellsInLayer(layer).size(); ++icell) { + mRoad.updateCellLevel(layer, icell); + mMaxCellLevel = std::max(mMaxCellLevel, mRoad.getCellLevel(layer, icell)); } } } //_________________________________________________________________________________________________ -const Float_t Tracker::getCellChisquare(ROframe& event, const Cell& cell) const +void Tracker::addCellToCurrentRoad(ROframe& event, const Int_t layer1, const Int_t layer2, const Int_t clsInLayer1, const Int_t clsInLayer2, Int_t& cellId) { - // returns the new chisquare of the previous cells plus the new one - TrackCA& trackCA = event.getCurrentTrackCA(); - const Int_t layer2 = cell.getSecondLayerId(); - const Int_t cls2Id = cell.getSecondClusterIndex(); - const Cluster& cluster2 = event.getClustersInLayer(layer2)[cls2Id]; + Cell& cell = mRoad.addCellInLayer(layer1, layer2, clsInLayer1, clsInLayer2, cellId); - Float_t x[constants::mft::MaxTrackPoints], y[constants::mft::MaxTrackPoints], z[constants::mft::MaxTrackPoints], err[constants::mft::MaxTrackPoints]; - Int_t point; + Cluster& cluster1 = event.getClustersInLayer(layer1)[clsInLayer1]; + Cluster& cluster2 = event.getClustersInLayer(layer2)[clsInLayer2]; - for (point = 0; point < trackCA.getNumberOfPoints(); ++point) { - x[point] = trackCA.getXCoordinates()[point]; - y[point] = trackCA.getYCoordinates()[point]; - z[point] = trackCA.getZCoordinates()[point]; - err[point] = constants::mft::Resolution; // FIXME - } - x[point] = cluster2.getX(); - y[point] = cluster2.getY(); - z[point] = cluster2.getZ(); - err[point] = constants::mft::Resolution; // FIXME - - // linear regression in the plane z:x - // x = zxApar * z + zxBpar - Float_t zxApar, zxBpar, zxAparErr, zxBparErr, chisqZX = 0.0; - if (!LinearRegression(trackCA.getNumberOfPoints() + 1, z, x, err, zxApar, zxAparErr, zxBpar, zxBparErr, chisqZX)) { - return -1.0; - } - // linear regression in the plane z:y - // y = zyApar * z + zyBpar - Float_t zyApar, zyBpar, zyAparErr, zyBparErr, chisqZY = 0.0; - if (!LinearRegression(trackCA.getNumberOfPoints() + 1, z, y, err, zyApar, zyAparErr, zyBpar, zyBparErr, chisqZY)) { - return -1.0; - } + Float_t coord[6]; + coord[0] = cluster1.getX(); + coord[1] = cluster1.getY(); + coord[2] = cluster1.getZ(); + coord[3] = cluster2.getX(); + coord[4] = cluster2.getY(); + coord[5] = cluster2.getZ(); - Int_t nDegFree = 2 * (trackCA.getNumberOfPoints() + 1) - 4; - return (chisqZX + chisqZY) / (Float_t)nDegFree; + cell.setCoordinates(coord); + cellId++; } //_________________________________________________________________________________________________ -const Bool_t Tracker::addCellToCurrentTrackCA(const Int_t layer1, const Int_t cellId, ROframe& event) +void Tracker::addCellToCurrentTrackCA(const Int_t layer1, const Int_t cellId, ROframe& event) { TrackCA& trackCA = event.getCurrentTrackCA(); - Road& road = event.getCurrentRoad(); - const Cell& cell = road.getCellsInLayer(layer1)[cellId]; + const Cell& cell = mRoad.getCellsInLayer(layer1)[cellId]; const Int_t layer2 = cell.getSecondLayerId(); - const Int_t clsLayer1 = cell.getFirstClusterIndex(); - const Int_t clsLayer2 = cell.getSecondClusterIndex(); - - const Cluster& cluster1 = event.getClustersInLayer(layer1)[clsLayer1]; - const Cluster& cluster2 = event.getClustersInLayer(layer2)[clsLayer2]; - - if (trackCA.getNumberOfPoints() > 0) { - const Float_t xLast = trackCA.getXCoordinates()[trackCA.getNumberOfPoints() - 1]; - const Float_t yLast = trackCA.getYCoordinates()[trackCA.getNumberOfPoints() - 1]; - Float_t dx = xLast - cluster2.getX(); - Float_t dy = yLast - cluster2.getY(); - Float_t dr = std::sqrt(dx * dx + dy * dy); - if (dr > constants::mft::Resolution) { - return kFALSE; - } - } + const Int_t clsInLayer1 = cell.getFirstClusterIndex(); + const Int_t clsInLayer2 = cell.getSecondClusterIndex(); + + Cluster& cluster1 = event.getClustersInLayer(layer1)[clsInLayer1]; + Cluster& cluster2 = event.getClustersInLayer(layer2)[clsInLayer2]; MCCompLabel mcCompLabel1 = mUseMC ? event.getClusterLabels(layer1, cluster1.clusterId) : MCCompLabel(); MCCompLabel mcCompLabel2 = mUseMC ? event.getClusterLabels(layer2, cluster2.clusterId) : MCCompLabel(); - Bool_t newPoint; Int_t extClsIndex; if (trackCA.getNumberOfPoints() == 0) { - newPoint = kTRUE; extClsIndex = event.getClusterExternalIndex(layer2, cluster2.clusterId); - trackCA.setPoint(cluster2, layer2, clsLayer2, mcCompLabel2, extClsIndex, newPoint); + trackCA.setPoint(cluster2, layer2, clsInLayer2, mcCompLabel2, extClsIndex); } - newPoint = kTRUE; extClsIndex = event.getClusterExternalIndex(layer1, cluster1.clusterId); - trackCA.setPoint(cluster1, layer1, clsLayer1, mcCompLabel1, extClsIndex, newPoint); - - trackCA.addCell(layer1, cellId); - - // update the chisquare - if (trackCA.getNumberOfPoints() == 2) { - trackCA.setChiSquareZX(0.0); - trackCA.setChiSquareZY(0.0); - return kTRUE; - } - - Float_t x[constants::mft::MaxTrackPoints], y[constants::mft::MaxTrackPoints], z[constants::mft::MaxTrackPoints], err[constants::mft::MaxTrackPoints]; - for (Int_t point = 0; point < trackCA.getNumberOfPoints(); ++point) { - x[point] = trackCA.getXCoordinates()[point]; - y[point] = trackCA.getYCoordinates()[point]; - z[point] = trackCA.getZCoordinates()[point]; - err[point] = constants::mft::Resolution; // FIXME - } - - // linear regression in the plane z:x - // x = zxApar * z + zxBpar - Float_t zxApar, zxBpar, zxAparErr, zxBparErr, chisqZX = 0.0; - if (LinearRegression(trackCA.getNumberOfPoints(), z, x, err, zxApar, zxAparErr, zxBpar, zxBparErr, chisqZX)) { - trackCA.setChiSquareZX(chisqZX); - } else { - return kFALSE; - } - - // linear regression in the plane z:y - // y = zyApar * z + zyBpar - Float_t zyApar, zyBpar, zyAparErr, zyBparErr, chisqZY = 0.0; - if (LinearRegression(trackCA.getNumberOfPoints(), z, y, err, zyApar, zyAparErr, zyBpar, zyBparErr, chisqZY)) { - trackCA.setChiSquareZY(chisqZY); - } else { - return kFALSE; - } - - return kTRUE; -} - -const Bool_t Tracker::LinearRegression(Int_t npoints, Float_t* x, Float_t* y, Float_t* yerr, Float_t& apar, Float_t& aparerr, Float_t& bpar, Float_t& bparerr, Float_t& chisq, Int_t skippoint) const -{ - // y = apar * x + bpar - - // work with only part of the points - Float_t xCl[constants::mft::MaxTrackPoints], yCl[constants::mft::MaxTrackPoints], yClErr[constants::mft::MaxTrackPoints]; - Int_t ipoints = 0; - for (Int_t i = 0; i < npoints; ++i) { - if (i == skippoint) { - continue; - } - xCl[ipoints] = x[i]; - yCl[ipoints] = y[i]; - yClErr[ipoints] = yerr[i]; - ipoints++; - } - - // calculate the regression parameters - Float_t S1, SXY, SX, SY, SXX, SsXY, SsXX, SsYY, Xm, Ym, s, delta, difx; - S1 = SXY = SX = SY = SXX = 0.0; - SsXX = SsYY = SsXY = Xm = Ym = 0.0; - difx = 0.; - for (Int_t i = 0; i < ipoints; ++i) { - S1 += 1.0 / (yClErr[i] * yClErr[i]); - SXY += xCl[i] * yCl[i] / (yClErr[i] * yClErr[i]); - SX += xCl[i] / (yClErr[i] * yClErr[i]); - SY += yCl[i] / (yClErr[i] * yClErr[i]); - SXX += xCl[i] * xCl[i] / (yClErr[i] * yClErr[i]); - if (i > 0) { - difx += TMath::Abs(xCl[i] - xCl[i - 1]); - } - Xm += xCl[i]; - Ym += yCl[i]; - SsXX += xCl[i] * xCl[i]; - SsYY += yCl[i] * yCl[i]; - SsXY += xCl[i] * yCl[i]; - } - delta = SXX * S1 - SX * SX; - if (delta == 0.) { - return kFALSE; - } - apar = (SXY * S1 - SX * SY) / delta; - bpar = (SY * SXX - SX * SXY) / delta; - - // calculate the chisquare - chisq = 0.0; - for (Int_t i = 0; i < ipoints; ++i) { - chisq += (yCl[i] - (apar * xCl[i] + bpar)) * (yCl[i] - (apar * xCl[i] + bpar)) / (yerr[i] * yerr[i]); - } - - // calculate the errors of the regression parameters - Ym /= (Float_t)ipoints; - Xm /= (Float_t)ipoints; - SsYY -= (Float_t)ipoints * (Ym * Ym); - SsXX -= (Float_t)ipoints * (Xm * Xm); - SsXY -= (Float_t)ipoints * (Ym * Xm); - Float_t eps = 1.E-24; - if ((ipoints > 2) && (TMath::Abs(difx) > eps) && ((SsYY - (SsXY * SsXY) / SsXX) > 0.0)) { - s = std::sqrt((SsYY - (SsXY * SsXY) / SsXX) / (ipoints - 2)); - bparerr = s * std::sqrt(1. / (Float_t)ipoints + (Xm * Xm) / SsXX); - aparerr = s / std::sqrt(SsXX); - } else { - bparerr = 0.; - aparerr = 0.; - } - - return kTRUE; + trackCA.setPoint(cluster1, layer1, clsInLayer1, mcCompLabel1, extClsIndex); } //_________________________________________________________________________________________________ diff --git a/Detectors/ITSMFT/MFT/tracking/src/TrackerConfig.cxx b/Detectors/ITSMFT/MFT/tracking/src/TrackerConfig.cxx new file mode 100644 index 0000000000000..4bb0263d8fcbf --- /dev/null +++ b/Detectors/ITSMFT/MFT/tracking/src/TrackerConfig.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.cxx +/// \brief Implementation of the GeometryTGeo class +/// \author bogdan.vulpescu@clermont.in2p3.fr - adapted from ITS, 21.09.2017 + +#include "MFTTracking/TrackerConfig.h" + +#include <fairlogger/Logger.h> + +//__________________________________________________________________________ +o2::mft::TrackerConfig::TrackerConfig() + : mMinTrackPointsLTF{5}, + mMinTrackPointsCA{4}, + mMinTrackStationsLTF{4}, + mMinTrackStationsCA{4}, + mLTFclsRCut{0.0100}, + mLTFclsR2Cut{0.0100 * 0.0100}, + mROADclsRCut{0.0400}, + mROADclsR2Cut{0.0400 * 0.0400}, + mLTFseed2BinWin{3}, + mLTFinterBinWin{3}, + mRBins{50}, + mPhiBins{50}, + mRPhiBins{50 * 50}, + mRBinSize{(constants::index_table::RMax - constants::index_table::RMin) / 50.}, + mPhiBinSize{(constants::index_table::PhiMax - constants::index_table::PhiMin) / 50.}, + mInverseRBinSize{50. / (constants::index_table::RMax - constants::index_table::RMin)}, + mInversePhiBinSize{50. / (constants::index_table::PhiMax - constants::index_table::PhiMin)} +{ + /// default constructor +} + +//__________________________________________________________________________ +void o2::mft::TrackerConfig::initialize(const MFTTrackingParam& trkParam) +{ + /// initialize from MFTTrackingParam (command line configuration parameters) + + mMinTrackPointsLTF = trkParam.MinTrackPointsLTF; + mMinTrackPointsCA = trkParam.MinTrackPointsCA; + mMinTrackStationsLTF = trkParam.MinTrackStationsLTF; + mMinTrackStationsCA = trkParam.MinTrackStationsCA; + mLTFclsRCut = trkParam.LTFclsRCut; + mLTFclsR2Cut = mLTFclsRCut * mLTFclsRCut; + mROADclsRCut = trkParam.ROADclsRCut; + mROADclsR2Cut = mROADclsRCut * mROADclsRCut; + mLTFseed2BinWin = trkParam.LTFseed2BinWin; + mLTFinterBinWin = trkParam.LTFinterBinWin; + + mRBins = trkParam.RBins; + mPhiBins = trkParam.PhiBins; + mRPhiBins = trkParam.RBins * trkParam.PhiBins; + if (mRPhiBins > constants::index_table::MaxRPhiBins) { + LOG(WARN) << "To many RPhiBins for this configuration!"; + mRPhiBins = constants::index_table::MaxRPhiBins; + mRBins = sqrt(constants::index_table::MaxRPhiBins); + mPhiBins = sqrt(constants::index_table::MaxRPhiBins); + LOG(WARN) << "Using instead RBins " << mRBins << " and PhiBins " << mPhiBins; + } + mRBinSize = (constants::index_table::RMax - constants::index_table::RMin) / mRBins; + mPhiBinSize = (constants::index_table::PhiMax - constants::index_table::PhiMin) / mPhiBins; +} diff --git a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt index ebfe2f71cebdc..6dd34a4d8b2de 100644 --- a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt @@ -1,30 +1,35 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MFTWorkflow TARGETVARNAME targetName SOURCES src/RecoWorkflow.cxx - src/DigitReaderSpec.cxx - src/ClustererSpec.cxx - src/ClusterWriterSpec.cxx - src/ClusterReaderSpec.cxx - src/TrackerSpec.cxx - src/TrackWriterSpec.cxx + src/ClustererSpec.cxx + src/ClusterWriterSpec.cxx + src/TrackerSpec.cxx + src/TrackReaderSpec.cxx + src/TrackWriterSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimConfig O2::SimulationDataFormat - O2::ITSMFTReconstruction + O2::ITSMFTReconstruction O2::MFTTracking - O2::DataFormatsMFT) - + O2::DataFormatsMFT + O2::ITSMFTWorkflow) o2_add_executable(reco-workflow SOURCES src/mft-reco-workflow.cxx COMPONENT_NAME mft PUBLIC_LINK_LIBRARIES O2::MFTWorkflow) + +o2_add_executable(cluster-reader-workflow + SOURCES src/mft-cluster-reader-workflow.cxx + COMPONENT_NAME mft + PUBLIC_LINK_LIBRARIES O2::MFTWorkflow) diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterReaderSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterReaderSpec.h deleted file mode 100644 index e660512a243fe..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterReaderSpec.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterReaderSpec.h - -#ifndef O2_MFT_CLUSTERREADER_H_ -#define O2_MFT_CLUSTERREADER_H_ - -#include "TFile.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -namespace o2 -{ -namespace mft -{ - -class ClusterReader : public o2::framework::Task -{ - public: - ClusterReader(bool useMC) : mUseMC(useMC) {} - ~ClusterReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - int mState = 0; - bool mUseMC = true; - std::unique_ptr<TFile> mFile = nullptr; -}; - -/// create a processor spec -/// read simulated MFT digits from a root file -o2::framework::DataProcessorSpec getClusterReaderSpec(bool useMC); - -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_CLUSTERREADER */ diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h index c4d3614806ece..51dc5a6481eb5 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h index ab3da58143de9..c63ff6bea51db 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/DigitReaderSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/DigitReaderSpec.h deleted file mode 100644 index 586ffa4fb84ef..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/DigitReaderSpec.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.h - -#ifndef O2_MFT_DIGITREADER_H_ -#define O2_MFT_DIGITREADER_H_ - -#include "TFile.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -namespace o2 -{ -namespace mft -{ - -class DigitReader : public o2::framework::Task -{ - public: - DigitReader(bool useMC) : mUseMC(useMC) {} - ~DigitReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - int mState = 0; - bool mUseMC = true; - std::unique_ptr<TFile> mFile = nullptr; -}; - -/// create a processor spec -/// read simulated MFT digits from a root file -o2::framework::DataProcessorSpec getDigitReaderSpec(bool useMC); - -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_DIGITREADER */ diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/RecoWorkflow.h index 90db32cff2bfe..60504d651bd08 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackReaderSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackReaderSpec.h new file mode 100644 index 0000000000000..e18e17f6880f2 --- /dev/null +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackReaderSpec.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackReaderSpec.h + +#ifndef O2_MFT_TRACKREADER +#define O2_MFT_TRACKREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsMFT/TrackMFT.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsITSMFT/ROFRecord.h" + +namespace o2 +{ +namespace mft +{ + +class TrackReader : public o2::framework::Task +{ + + public: + TrackReader(bool useMC = true); + ~TrackReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector<o2::itsmft::ROFRecord> mROFRec, *mROFRecInp = &mROFRec; + std::vector<o2::mft::TrackMFT> mTracks, *mTracksInp = &mTracks; + std::vector<int> mClusInd, *mClusIndInp = &mClusInd; + std::vector<o2::MCCompLabel> mMCTruth, *mMCTruthInp = &mMCTruth; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginMFT; + + bool mUseMC = true; // use MC truth + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mInputFileName = ""; + std::string mTrackTreeName = "o2sim"; + std::string mROFBranchName = "MFTTracksROF"; + std::string mTrackBranchName = "MFTTrack"; + std::string mClusIdxBranchName = "MFTTrackClusIdx"; + std::string mTrackMCTruthBranchName = "MFTTrackMCTruth"; +}; + +/// create a processor spec +/// read MFT track data from a root file +framework::DataProcessorSpec getMFTTrackReaderSpec(bool useMC = true); + +} // namespace mft +} // namespace o2 + +#endif /* O2_MFT_TRACKREADER */ diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackWriterSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackWriterSpec.h index df01bfbda4fbb..5a8d50939a25a 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackWriterSpec.h +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h index a18f2f37a766a..971886b25cb57 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h +++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx deleted file mode 100644 index 896aacf27d59b..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterReaderSpec.cxx - -#include <vector> - -#include "MFTWorkflow/ClusterReaderSpec.h" - -#include "TTree.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace mft -{ - -void ClusterReader::init(InitContext& ic) -{ - auto filename = ic.options().get<std::string>("mft-cluster-infile"); - mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); - if (!mFile->IsOpen()) { - LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; - mState = 0; - return; - } - mState = 1; -} - -void ClusterReader::run(ProcessingContext& pc) -{ - if (mState != 1) { - return; - } - - std::unique_ptr<TTree> tree((TTree*)mFile->Get("o2sim")); - - if (tree) { - - std::vector<o2::itsmft::CompClusterExt> compClusters, *pcompClusters = &compClusters; - std::vector<ROFRecord> rofs, *profs = &rofs; - - tree->SetBranchAddress("MFTClusterComp", &pcompClusters); - tree->SetBranchAddress("MFTClusterROF", &profs); - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels, *plabels = &labels; - std::vector<MC2ROFRecord> mc2rofs, *pmc2rofs = &mc2rofs; - if (mUseMC) { - tree->SetBranchAddress("MFTClusterMCTruth", &plabels); - tree->SetBranchAddress("MFTDigitMC2ROF", &pmc2rofs); - } - tree->GetEntry(0); - - LOG(INFO) << "MFTClusterReader pulled " << compClusters.size() << " compressed clusters, in " - << rofs.size() << " RO frames"; - - pc.outputs().snapshot(Output{"MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe}, compClusters); - pc.outputs().snapshot(Output{"MFT", "CLUSTERSROF", 0, Lifetime::Timeframe}, rofs); - if (mUseMC) { - pc.outputs().snapshot(Output{"MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe}, labels); - pc.outputs().snapshot(Output{"MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); - } - } else { - LOG(ERROR) << "Cannot read the MFT clusters !"; - return; - } - mState = 2; - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); -} - -DataProcessorSpec getClusterReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSROF", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back("MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "mft-cluster-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<ClusterReader>(useMC)}, - Options{ - {"mft-cluster-infile", VariantType::String, "mftclusters.root", {"Name of the input file"}}}}; -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx index 00eb69f8def94..3c66c349232a8 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx index 388f18514b414..64bb585383486 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -69,8 +70,8 @@ void ClustererDPL::init(InitContext& ic) mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); std::string dictPath = ic.options().get<std::string>("mft-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::MFT, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::MFT, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mClusterer->loadDictionary(dictFile); LOG(INFO) << "MFTClusterer running with a provided dictionary: " << dictFile; } else { diff --git a/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx deleted file mode 100644 index 7baf9b858ab9a..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.cxx - -#include <vector> - -#include "MFTWorkflow/DigitReaderSpec.h" - -#include "TTree.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "DataFormatsITSMFT/Digit.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/IOMCTruthContainerView.h" -#include "DataFormatsITSMFT/ROFRecord.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace mft -{ - -void DigitReader::init(InitContext& ic) -{ - auto filename = ic.options().get<std::string>("mft-digit-infile"); - mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); - if (!mFile->IsOpen()) { - LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; - mState = 0; - return; - } - mState = 1; -} - -void DigitReader::run(ProcessingContext& pc) -{ - if (mState != 1) { - return; - } - - std::unique_ptr<TTree> treeDig((TTree*)mFile->Get("o2sim")); - - if (treeDig) { - - std::vector<o2::itsmft::Digit> digits, *pdigits = &digits; - treeDig->SetBranchAddress("MFTDigit", &pdigits); - - std::vector<ROFRecord> rofs, *profs = &rofs; - treeDig->SetBranchAddress("MFTDigitROF", &profs); - - o2::dataformats::IOMCTruthContainerView* plabels = nullptr; - std::vector<MC2ROFRecord> mc2rofs, *pmc2rofs = &mc2rofs; - if (mUseMC) { - treeDig->SetBranchAddress("MFTDigitMCTruth", &plabels); - treeDig->SetBranchAddress("MFTDigitMC2ROF", &pmc2rofs); - } - treeDig->GetEntry(0); - - LOG(INFO) << "MFTDigitReader pushed " << digits.size() << " digits, in " - << profs->size() << " RO frames"; - - pc.outputs().snapshot(Output{"MFT", "DIGITS", 0, Lifetime::Timeframe}, digits); - pc.outputs().snapshot(Output{"MFT", "DIGITSROF", 0, Lifetime::Timeframe}, *profs); - if (mUseMC) { - auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"MFT", "DIGITSMCTR", 0, Lifetime::Timeframe}); - plabels->copyandflatten(sharedlabels); - delete plabels; - pc.outputs().snapshot(Output{"MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe}, *pmc2rofs); - } - } else { - LOG(ERROR) << "Cannot read the MFT digits !"; - return; - } - mState = 2; - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); -} - -DataProcessorSpec getDigitReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back("MFT", "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "DIGITSROF", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back("MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - } - return DataProcessorSpec{ - "mft-digit-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, - Options{ - {"mft-digit-infile", VariantType::String, "mftdigits.root", {"Name of the input file"}}}}; -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx index 055820074eb96..551ab273c6f20 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,13 +13,11 @@ #include <TTree.h> #include "MFTWorkflow/RecoWorkflow.h" - -#include "MFTWorkflow/DigitReaderSpec.h" #include "MFTWorkflow/ClustererSpec.h" #include "MFTWorkflow/ClusterWriterSpec.h" -#include "MFTWorkflow/ClusterReaderSpec.h" #include "MFTWorkflow/TrackerSpec.h" #include "MFTWorkflow/TrackWriterSpec.h" +#include "ITSMFTWorkflow/DigitReaderSpec.h" namespace o2 { @@ -33,7 +32,7 @@ framework::WorkflowSpec getWorkflow(bool useMC, bool upstreamDigits, bool upstre framework::WorkflowSpec specs; if (!(upstreamDigits || upstreamClusters)) { - specs.emplace_back(o2::mft::getDigitReaderSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTDigitReaderSpec(useMC, false, "mftdigits.root")); } if (!upstreamClusters) { specs.emplace_back(o2::mft::getClustererSpec(useMC)); diff --git a/Detectors/ITSMFT/MFT/workflow/src/TrackReaderSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/TrackReaderSpec.cxx new file mode 100644 index 0000000000000..1a3e294d8f248 --- /dev/null +++ b/Detectors/ITSMFT/MFT/workflow/src/TrackReaderSpec.cxx @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackReaderSpec.cxx + +#include <vector> +#include <cassert> +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "MFTWorkflow/TrackReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::mft; + +namespace o2 +{ +namespace mft +{ + +TrackReader::TrackReader(bool useMC) +{ + mUseMC = useMC; +} + +void TrackReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("mft-tracks-infile")); + connectTree(mInputFileName); +} + +void TrackReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mTracks.size() << " track in " << mROFRec.size() << " ROFs at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "MFTTrackROF", 0, Lifetime::Timeframe}, mROFRec); + pc.outputs().snapshot(Output{mOrigin, "TRACKS", 0, Lifetime::Timeframe}, mTracks); + pc.outputs().snapshot(Output{mOrigin, "TRACKCLSID", 0, Lifetime::Timeframe}, mClusInd); + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "TRACKSMCTR", 0, Lifetime::Timeframe}, mMCTruth); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void TrackReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mTrackTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mROFBranchName.c_str())); + + mTree->SetBranchAddress(mROFBranchName.c_str(), &mROFRecInp); + mTree->SetBranchAddress(mTrackBranchName.c_str(), &mTracksInp); + mTree->SetBranchAddress(mClusIdxBranchName.c_str(), &mClusIndInp); + + if (mUseMC) { + if (mTree->GetBranch(mTrackMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mTrackMCTruthBranchName.c_str(), &mMCTruthInp); + } else { + LOG(WARNING) << "MC-truth is missing, message will be empty"; + } + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getMFTTrackReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("MFT", "MFTTrackROF", 0, Lifetime::Timeframe); + outputSpec.emplace_back("MFT", "TRACKS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("MFT", "TRACKCLSID", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("MFT", "TRACKSMCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "mft-track-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<TrackReader>(useMC)}, + Options{ + {"mft-tracks-infile", VariantType::String, "mfttracks.root", {"Name of the input track file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace mft +} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx index 25ee745f2bb9d..99beec65b57ec 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,8 @@ #include "SimulationDataFormat/MCTruthContainer.h" using namespace o2::framework; +using LabelsType = std::vector<o2::MCCompLabel>; +using ROFRecLblT = std::vector<o2::itsmft::MC2ROFRecord>; namespace o2 { @@ -51,17 +54,17 @@ DataProcessorSpec getTrackWriterSpec(bool useMC) tracksSizeGetter}, BranchDefinition<std::vector<int>>{InputSpec{"trackClIdx", "MFT", "TRACKCLSID", 0}, "MFTTrackClusIdx"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"labels", "MFT", "TRACKSMCTR", 0}, - "MFTTrackMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition<std::vector<o2::itsmft::ROFRecord>>{InputSpec{"ROframes", "MFT", "TRACKSROF", 0}, + BranchDefinition<LabelsType>{InputSpec{"labels", "MFT", "TRACKSMCTR", 0}, + "MFTTrackMCTruth", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""}, + BranchDefinition<std::vector<o2::itsmft::ROFRecord>>{InputSpec{"ROframes", "MFT", "MFTTrackROF", 0}, "MFTTracksROF", logger}, - BranchDefinition<std::vector<o2::itsmft::MC2ROFRecord>>{InputSpec{"MC2ROframes", "MFT", "TRACKSMC2ROF", 0}, - "MFTTracksMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); + BranchDefinition<ROFRecLblT>{InputSpec{"MC2ROframes", "MFT", "TRACKSMC2ROF", 0}, + "MFTTracksMC2ROF", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""})(); } } // namespace mft diff --git a/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx index ba62e01740dea..670bdbf9848bc 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -57,16 +58,26 @@ void TrackerDPL::init(InitContext& ic) geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); + // tracking configuration parameters + auto& trackingParam = MFTTrackingParam::Instance(); + // create the tracker: set the B-field, the configuration and initialize mTracker = std::make_unique<o2::mft::Tracker>(mUseMC); double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT - mTracker->setBz(field->getBz(centerMFT)); + auto Bz = field->getBz(centerMFT); + if (Bz == 0) { + Bz = 0.1; // Temporary workaround for MFT tracking with magnet off; + LOG(INFO) << " Temporary workaround for MFT tracking with magnet off. Bz = " << Bz; + } + mTracker->setBz(Bz); + mTracker->initConfig(trackingParam, true); + mTracker->initialize(trackingParam.FullClusterScan); } else { - throw std::runtime_error(o2::utils::concat_string("Cannot retrieve GRP from the ", filename)); + throw std::runtime_error(o2::utils::Str::concat_string("Cannot retrieve GRP from the ", filename)); } - std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); - std::string dictFile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::MFT, dictPath, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { + std::string dictPath = ic.options().get<std::string>("mft-dictionary-path"); + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::MFT, dictPath, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { mDict.readBinaryFile(dictFile); LOG(INFO) << "Tracker running with a provided dictionary: " << dictFile; } else { @@ -87,7 +98,7 @@ void TrackerDPL::run(ProcessingContext& pc) // the output vector however is created directly inside the message memory thus avoiding copy by // snapshot auto rofsinput = pc.inputs().get<const std::vector<o2::itsmft::ROFRecord>>("ROframes"); - auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(Output{"MFT", "TRACKSROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); + auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(Output{"MFT", "MFTTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); LOG(INFO) << "MFTTracker pulled " << compClusters.size() << " compressed clusters in " << rofsinput.size() << " RO frames"; @@ -103,8 +114,8 @@ void TrackerDPL::run(ProcessingContext& pc) //std::vector<o2::mft::TrackMFTExt> tracks; auto& allClusIdx = pc.outputs().make<std::vector<int>>(Output{"MFT", "TRACKCLSID", 0, Lifetime::Timeframe}); - o2::dataformats::MCTruthContainer<o2::MCCompLabel> trackLabels; - o2::dataformats::MCTruthContainer<o2::MCCompLabel> allTrackLabels; + std::vector<o2::MCCompLabel> trackLabels; + std::vector<o2::MCCompLabel> allTrackLabels; std::vector<o2::mft::TrackLTF> tracksLTF; std::vector<o2::mft::TrackCA> tracksCA; auto& allTracksMFT = pc.outputs().make<std::vector<o2::mft::TrackMFT>>(Output{"MFT", "TRACKS", 0, Lifetime::Timeframe}); @@ -115,6 +126,9 @@ void TrackerDPL::run(ProcessingContext& pc) Bool_t continuous = mGRP->isDetContinuousReadOut("MFT"); LOG(INFO) << "MFTTracker RO: continuous=" << continuous; + // tracking configuration parameters + auto& trackingParam = MFTTrackingParam::Instance(); + // snippet to convert found tracks to final output tracks with separate cluster indices auto copyTracks = [&event](auto& tracks, auto& allTracks, auto& allClusIdx) { for (auto& trc : tracks) { @@ -129,38 +143,37 @@ void TrackerDPL::run(ProcessingContext& pc) }; gsl::span<const unsigned char>::iterator pattIt = patterns.begin(); - if (continuous) { - for (auto& rof : rofs) { - int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels); - if (nclUsed) { - event.setROFrameId(roFrame); - event.initialise(); - LOG(INFO) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed; - mTracker->setROFrame(roFrame); - mTracker->clustersToTracks(event); - tracksLTF.swap(event.getTracksLTF()); - tracksCA.swap(event.getTracksCA()); - nTracksLTF += tracksLTF.size(); - nTracksCA += tracksCA.size(); - - if (mUseMC) { - mTracker->computeTracksMClabels(tracksLTF); - mTracker->computeTracksMClabels(tracksCA); - trackLabels = mTracker->getTrackLabels(); /// FIXME: assignment ctor is not optimal. - allTrackLabels.mergeAtBack(trackLabels); - } - - LOG(INFO) << "Found tracks LTF: " << tracksLTF.size(); - LOG(INFO) << "Found tracks CA: " << tracksCA.size(); - int first = allTracksMFT.size(); - int number = tracksLTF.size() + tracksCA.size(); - rof.setFirstEntry(first); - rof.setNEntries(number); - copyTracks(tracksLTF, allTracksMFT, allClusIdx); - copyTracks(tracksCA, allTracksMFT, allClusIdx); + for (auto& rof : rofs) { + int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels, mTracker.get()); + if (nclUsed) { + event.setROFrameId(roFrame); + event.initialize(trackingParam.FullClusterScan); + LOG(INFO) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed; + mTracker->setROFrame(roFrame); + mTracker->clustersToTracks(event); + tracksLTF.swap(event.getTracksLTF()); + tracksCA.swap(event.getTracksCA()); + nTracksLTF += tracksLTF.size(); + nTracksCA += tracksCA.size(); + + if (mUseMC) { + mTracker->computeTracksMClabels(tracksLTF); + mTracker->computeTracksMClabels(tracksCA); + trackLabels.swap(mTracker->getTrackLabels()); + std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); + trackLabels.clear(); } - roFrame++; + + LOG(INFO) << "Found tracks LTF: " << tracksLTF.size(); + LOG(INFO) << "Found tracks CA: " << tracksCA.size(); + int first = allTracksMFT.size(); + int number = tracksLTF.size() + tracksCA.size(); + rof.setFirstEntry(first); + rof.setNEntries(number); + copyTracks(tracksLTF, allTracksMFT, allClusIdx); + copyTracks(tracksCA, allTracksMFT, allClusIdx); } + roFrame++; } LOG(INFO) << "MFTTracker found " << nTracksLTF << " tracks LTF"; @@ -189,7 +202,7 @@ DataProcessorSpec getTrackerSpec(bool useMC) std::vector<OutputSpec> outputs; outputs.emplace_back("MFT", "TRACKS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "TRACKSROF", 0, Lifetime::Timeframe); + outputs.emplace_back("MFT", "MFTTrackROF", 0, Lifetime::Timeframe); outputs.emplace_back("MFT", "TRACKCLSID", 0, Lifetime::Timeframe); if (useMC) { @@ -206,7 +219,7 @@ DataProcessorSpec getTrackerSpec(bool useMC) AlgorithmSpec{adaptFromTask<TrackerDPL>(useMC)}, Options{ {"grp-file", VariantType::String, "o2sim_grp.root", {"Name of the output file"}}, - {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}}}; + {"mft-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}}}; } } // namespace mft diff --git a/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-reader-workflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-reader-workflow.cxx new file mode 100644 index 0000000000000..f934eb4adfe73 --- /dev/null +++ b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-reader-workflow.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "with-mc", + o2::framework::VariantType::Bool, + false, + {"propagate MC labels"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "without-patterns", + o2::framework::VariantType::Bool, + false, + {"do not propagate pixel patterns"}}); +} + +#include "Framework/runDataProcessing.h" +#include "ITSMFTWorkflow/ClusterReaderSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cc) +{ + WorkflowSpec specs; + auto withMC = cc.options().get<bool>("with-mc"); + auto withPatterns = !cc.options().get<bool>("without-patterns"); + + specs.emplace_back(o2::itsmft::getMFTClusterReaderSpec(withMC, withPatterns)); + + return specs; +} diff --git a/Detectors/ITSMFT/MFT/workflow/src/mft-reco-workflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/mft-reco-workflow.cxx index b0a2776d132cc..a4157376b1dc0 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/mft-reco-workflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/mft-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "MFTWorkflow/RecoWorkflow.h" #include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" using namespace o2::framework; @@ -21,13 +23,12 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) {"digits-from-upstream", o2::framework::VariantType::Bool, false, {"digits will be provided from upstream, skip digits reader"}}, {"clusters-from-upstream", o2::framework::VariantType::Bool, false, {"clusters will be provided from upstream, skip clusterizer"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, - {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}}; + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; - std::swap(workflowOptions, options); - - std::string keyvaluehelp("Semicolon separated key=value strings (e.g.: 'ITSDigitizerParam.roFrameLength=6000.;...')"); + o2::raw::HBFUtilsInitializer::addConfigOption(options); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::swap(workflowOptions, options); } #include "Framework/runDataProcessing.h" @@ -44,5 +45,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto extClusters = configcontext.options().get<bool>("clusters-from-upstream"); auto disableRootOutput = configcontext.options().get<bool>("disable-root-output"); - return std::move(o2::mft::reco_workflow::getWorkflow(useMC, extDigits, extClusters, disableRootOutput)); + auto wf = o2::mft::reco_workflow::getWorkflow(useMC, extDigits, extClusters, disableRootOutput); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); } diff --git a/Detectors/ITSMFT/common/CMakeLists.txt b/Detectors/ITSMFT/common/CMakeLists.txt index 6c0adc0758148..42f580d5ab301 100644 --- a/Detectors/ITSMFT/common/CMakeLists.txt +++ b/Detectors/ITSMFT/common/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(simulation) diff --git a/Detectors/ITSMFT/common/base/CMakeLists.txt b/Detectors/ITSMFT/common/base/CMakeLists.txt index 711683fe88625..a3e0718d64a6b 100644 --- a/Detectors/ITSMFT/common/base/CMakeLists.txt +++ b/Detectors/ITSMFT/common/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSMFTBase SOURCES src/SegmentationAlpide.cxx diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h index 324bffd7da5f1..a7c74f8864e6d 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/GeometryTGeo.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/GeometryTGeo.h index f83554e17e1bb..d6f32fcdb13eb 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/GeometryTGeo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/SegmentationAlpide.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/SegmentationAlpide.h index 394aa268d410c..6394794f3a553 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/SegmentationAlpide.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/SegmentationAlpide.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx b/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx index 77e7934b0a849..1cb9bdf997d68 100644 --- a/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx +++ b/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/src/GeometryTGeo.cxx b/Detectors/ITSMFT/common/base/src/GeometryTGeo.cxx index 4d63b3e245c73..da477a4d30f34 100644 --- a/Detectors/ITSMFT/common/base/src/GeometryTGeo.cxx +++ b/Detectors/ITSMFT/common/base/src/GeometryTGeo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/src/ITSMFTBaseLinkDef.h b/Detectors/ITSMFT/common/base/src/ITSMFTBaseLinkDef.h index 1ceb005986ec2..6202f372cf2d3 100644 --- a/Detectors/ITSMFT/common/base/src/ITSMFTBaseLinkDef.h +++ b/Detectors/ITSMFT/common/base/src/ITSMFTBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/base/src/SegmentationAlpide.cxx b/Detectors/ITSMFT/common/base/src/SegmentationAlpide.cxx index 41b7d6dd162e8..301cc81d3f2f3 100644 --- a/Detectors/ITSMFT/common/base/src/SegmentationAlpide.cxx +++ b/Detectors/ITSMFT/common/base/src/SegmentationAlpide.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt index a1de05e673e1a..89eed96a4107b 100644 --- a/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSMFTReconstruction TARGETVARNAME targetName @@ -23,17 +24,17 @@ o2_add_library(ITSMFTReconstruction src/PayLoadCont.cxx src/GBTWord.cxx src/RUInfo.cxx - src/GBTLink.cxx - src/RUDecodeData.cxx - src/RawPixelDecoder.cxx + src/GBTLink.cxx + src/RUDecodeData.cxx + src/RawPixelDecoder.cxx src/CTFCoder.cxx src/DecodingStat.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTBase O2::CommonDataFormat - O2::DetectorsRaw + O2::DetectorsRaw O2::SimulationDataFormat O2::DataFormatsITSMFT - O2::DPLUtils + O2::DPLUtils O2::rANS O2::Headers) @@ -42,7 +43,6 @@ o2_target_root_dictionary( HEADERS include/ITSMFTReconstruction/PixelReader.h include/ITSMFTReconstruction/GBTLink.h include/ITSMFTReconstruction/RUDecodeData.h - include/ITSMFTReconstruction/RawPixelDecoder.h include/ITSMFTReconstruction/DigitPixelReader.h include/ITSMFTReconstruction/RawPixelReader.h include/ITSMFTReconstruction/PixelData.h diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index 6a11db0fa8e1a..028d061e62388 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,6 @@ #ifndef ALICEO2_ITSMFT_ALPIDE_CODER_H #define ALICEO2_ITSMFT_ALPIDE_CODER_H - #include <Rtypes.h> #include <cstdio> #include <cstdint> @@ -73,6 +73,7 @@ class AlpideCoder static constexpr uint32_t ExpectData = 0x1 << 4; static constexpr uint32_t ExpectBUSY = 0x1 << 5; static constexpr int NRows = 512; + static constexpr int RowMask = NRows - 1; static constexpr int NCols = 1024; static constexpr int NRegions = 32; static constexpr int NDColInReg = NCols / NRegions / 2; @@ -123,8 +124,23 @@ class AlpideCoder // read record for single non-empty chip, updating on change module and cycle. // return number of records filled (>0), EOFFlag or Error // + auto roErrHandler = [&chipData](uint8_t roErr) { +#ifdef ALPIDE_DECODING_STAT + if (roErr == MaskErrBusyViolation) { + chipData.setError(ChipStat::BusyViolation); + } else if (roErr == MaskErrDataOverrun) { + chipData.setError(ChipStat::DataOverrun); + } else if (roErr == MaskErrFatal) { + chipData.setError(ChipStat::Fatal); + } +#endif + }; + uint8_t dataC = 0, timestamp = 0; uint16_t dataS = 0, region = 0; +#ifdef ALPIDE_DECODING_STAT + uint16_t rowPrev = 0xffff; +#endif // int nRightCHits = 0; // counter for the hits in the right column of the current double column std::uint16_t rightColHits[NRows]; // buffer for the accumulation of hits in the right column @@ -133,7 +149,6 @@ class AlpideCoder uint32_t expectInp = ExpectChipHeader | ExpectChipEmpty; // data must always start with chip header or chip empty flag chipData.clear(); - while (buffer.next(dataC)) { // // ---------- chip info ? @@ -147,6 +162,7 @@ class AlpideCoder #endif return unexpectedEOF("CHIP_EMPTY:Timestamp"); } + chipData.resetChipID(); expectInp = ExpectChipHeader | ExpectChipEmpty; continue; } @@ -176,13 +192,7 @@ class AlpideCoder #ifdef ALPIDE_DECODING_STAT uint8_t roErr = dataC & MaskROFlags; if (roErr) { - if (roErr == MaskErrBusyViolation) { - chipData.setError(ChipStat::BusyViolation); - } else if (roErr == MaskErrDataOverrun) { - chipData.setError(ChipStat::DataOverrun); - } else if (roErr == MaskErrFatal) { - chipData.setError(ChipStat::Fatal); - } + roErrHandler(roErr); } #endif // in case there are entries in the "right" columns buffer, add them to the container @@ -192,6 +202,13 @@ class AlpideCoder addHit(chipData, rightColHits[ihr], colDPrev); } } + + if (!chipData.getData().size() && !chipData.isErrorSet()) { + nRightCHits = 0; + colDPrev = 0xffff; + chipData.clear(); + continue; + } break; } @@ -215,7 +232,7 @@ class AlpideCoder uint16_t row = pixID >> 1; // abs id of left column in double column uint16_t colD = (region * NDColInReg + dColID) << 1; // TODO consider <<4 instead of *NDColInReg? - + bool rightC = (row & 0x1) ? !(pixID & 0x1) : (pixID & 0x1); // true for right column / lalse for left // if we start new double column, transfer the hits accumulated in the right column buffer of prev. double column if (colD != colDPrev) { colDPrev++; @@ -224,9 +241,29 @@ class AlpideCoder } colDPrev = colD; nRightCHits = 0; // reset the buffer +#ifdef ALPIDE_DECODING_STAT + rowPrev = 0xffff; + } + // this is a special test to exclude repeated data of the same pixel fired + else if (row == rowPrev) { // same row/column fired repeatedly, hope this check is temporary + chipData.setError(ChipStat::RepeatingPixel); + chipData.addErrorInfo((uint64_t(colD + rightC) << 16) | uint64_t(row)); + if ((dataS & (~MaskDColID)) == DATALONG) { // skip pattern w/o decoding + uint8_t hitsPattern = 0; + if (!buffer.next(hitsPattern)) { + chipData.setError(ChipStat::TruncatedLondData); + return unexpectedEOF("CHIP_DATA_LONG:Pattern"); + } + if (hitsPattern & (~MaskHitMap)) { + return unexpectedEOF("CHIP_DATA_LONG:Pattern"); + } + } + expectInp = ExpectChipTrailer | ExpectData | ExpectRegion; + continue; // end of DATA(SHORT or LONG) processing + } else { + rowPrev = row; +#endif } - - bool rightC = (row & 0x1) ? !(pixID & 0x1) : (pixID & 0x1); // true for right column / lalse for left // we want to have hits sorted in column/row, so the hits in right column of given double column // are first collected in the temporary buffer @@ -245,14 +282,21 @@ class AlpideCoder #endif return unexpectedEOF("CHIP_DATA_LONG:Pattern"); } -#ifdef ALPIDE_DECODING_STAT if (hitsPattern & (~MaskHitMap)) { +#ifdef ALPIDE_DECODING_STAT chipData.setError(ChipStat::WrongDataLongPattern); - } #endif + return unexpectedEOF("CHIP_DATA_LONG:Pattern"); + } for (int ip = 0; ip < HitMapSize; ip++) { if (hitsPattern & (0x1 << ip)) { uint16_t addr = pixID + ip + 1, rowE = addr >> 1; + if (addr & ~MaskPixID) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::WrongRow); +#endif + return unexpectedEOF(fmt::format("Non-existing encoder {} decoded, DataLong was {:x}", pixID, dataS)); + } rightC = ((rowE & 0x1) ? !(addr & 0x1) : (addr & 0x1)); // true for right column / lalse for left // the real columnt is int colE = colD + rightC; if (rightC) { // same as above @@ -267,8 +311,7 @@ class AlpideCoder #ifdef ALPIDE_DECODING_STAT chipData.setError(ChipStat::NoDataFound); #endif - LOG(ERROR) << "Expected DataShort or DataLong mask, got : " << dataS; - return Error; + return unexpectedEOF(fmt::format("Expected DataShort or DataLong mask, got {:x}", dataS)); } expectInp = ExpectChipTrailer | ExpectData | ExpectRegion; continue; // end of DATA(SHORT or LONG) processing @@ -291,12 +334,47 @@ class AlpideCoder buffer.clear(); // 0 padding reached (end of the cable data), no point in continuing break; } + + // in case of BUSY VIOLATION the Trailer may come directly after the Header + if ((expectInp & ExpectRegion) && (dataCM == CHIPTRAILER) && (dataC & MaskROFlags)) { + expectInp = ExpectChipHeader | ExpectChipEmpty; + chipData.setROFlags(dataC & MaskROFlags); + roErrHandler(dataC & MaskROFlags); + break; + } + + // check for APE errors, see https://alice.its.cern.ch/jira/browse/O2-1717?focusedCommentId=274714&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-274714 + bool fatalAPE = false; + auto codeAPE = ChipStat::getAPECode(dataC, fatalAPE); + if (codeAPE >= 0) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::DecErrors(codeAPE)); +#endif + if (fatalAPE) { + buffer.clear(); // no point in contiunuing with this cable data + } else { // skip eventual padding + while (buffer.next(dataC)) { + if (dataC) { // padding is over, make 1 step back in the buffer + auto currPtr = buffer.getPtr(); + buffer.setPtr(--currPtr); + } + } + } + return unexpectedEOF(fmt::format("APE error {:#02x} [expectation = 0x{:#02x}]", int(dataC), int(expectInp))); + } #ifdef ALPIDE_DECODING_STAT chipData.setError(ChipStat::UnknownWord); + // fill the error buffer with a few bytes of wrong data + const uint8_t* begPtr = buffer.data(); + const uint8_t* endPtr = buffer.getEnd(); + const uint8_t* curPtr = buffer.getPtr(); + size_t offsBack = std::min(ChipPixelData::MAXDATAERRBYTES - ChipPixelData::MAXDATAERRBYTES_AFTER, size_t(curPtr - begPtr)); + size_t offsAfter = std::min(ChipPixelData::MAXDATAERRBYTES_AFTER, size_t(endPtr - curPtr)); + std::memcpy(chipData.getRawErrBuff().data(), curPtr - offsBack, offsBack + offsAfter); + chipData.setNBytesInRawBuff(offsBack + offsAfter); #endif return unexpectedEOF(fmt::format("Unknown word 0x{:x} [expectation = 0x{:x}]", int(dataC), int(expectInp))); // error } - return chipData.getData().size(); } @@ -409,7 +487,11 @@ class AlpideCoder void resetMap(); ///< error message on unexpected EOF - static int unexpectedEOF(const std::string& message); + static int unexpectedEOF(const std::string& message) + { + LOG(DEBUG) << message; + return Error; + } // ===================================================================== // diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/BuildTopologyDictionary.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/BuildTopologyDictionary.h index 97d28e542bd1b..559f1a14b1c8f 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/BuildTopologyDictionary.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/BuildTopologyDictionary.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h index 3934e84220578..98cdf41660c3b 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,10 +22,17 @@ #include "DataFormatsITSMFT/CTF.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "ITSMFTReconstruction/LookUp.h" +#include "ITSMFTReconstruction/PixelData.h" +#include "ITSMFTReconstruction/Clusterer.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/CTFCoderBase.h" #include "rANS/rans.h" +//#define _CHECK_INCREMENTES_ // Uncoment this the check the incremements being non-negative + class TTree; namespace o2 @@ -35,6 +43,9 @@ namespace itsmft class CTFCoder : public o2::ctf::CTFCoderBase { public: + using PMatrix = std::array<std::array<bool, ClusterPattern::MaxRowSpan + 2>, ClusterPattern::MaxColSpan + 2>; + using RowColBuff = std::vector<PixelData>; + CTFCoder(o2::detectors::DetID det) : o2::ctf::CTFCoderBase(CTF::getNBlocks(), det) {} ~CTFCoder() = default; @@ -44,23 +55,32 @@ class CTFCoder : public o2::ctf::CTFCoderBase /// entropy decode clusters from buffer with CTF template <typename VROF, typename VCLUS, typename VPAT> - void decode(const CTF::base& ec, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec); + void decode(const CTF::base& ec, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup); + + /// entropy decode digits from buffer with CTF + template <typename VROF, typename VDIG> + void decode(const CTF::base& ec, VROF& rofRecVec, VDIG& digVec, const NoiseMap* noiseMap, const LookUp& clPattLookup); void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); private: + CompressedClusters decodeCompressedClusters(const CTF::base& ec); + /// compres compact clusters to CompressedClusters - void compress(CompressedClusters& cc, const gsl::span<const ROFRecord>& rofRecVec, const gsl::span<const CompClusterExt>& cclusVec, const gsl::span<const unsigned char>& pattVec); - size_t estimateCompressedSize(const CompressedClusters& cc); + void compress(CompressedClusters& compCl, const gsl::span<const ROFRecord>& rofRecVec, const gsl::span<const CompClusterExt>& cclusVec, const gsl::span<const unsigned char>& pattVec); + size_t estimateCompressedSize(const CompressedClusters& compCl); /// decompress CompressedClusters to compact clusters template <typename VROF, typename VCLUS, typename VPAT> - void decompress(const CompressedClusters& cc, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec); + void decompress(const CompressedClusters& compCl, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup); + + /// decompress CompressedClusters to digits + template <typename VROF, typename VDIG> + void decompress(const CompressedClusters& compCl, VROF& rofRecVec, VDIG& digVec, const NoiseMap* noiseMap, const LookUp& clPattLookup); void appendToTree(TTree& tree, CTF& ec); - void readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofRecVec, std::vector<CompClusterExt>& cclusVec, std::vector<unsigned char>& pattVec); + void readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofRecVec, std::vector<CompClusterExt>& cclusVec, std::vector<unsigned char>& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup); - protected: ClassDefNV(CTFCoder, 1); }; @@ -82,134 +102,325 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const ROFRecord>& rofRecVec, co MD::EENCODE, //BLCpattID MD::EENCODE //BLCpattMap }; - CompressedClusters cc; - compress(cc, rofRecVec, cclusVec, pattVec); + CompressedClusters compCl; + compress(compCl, rofRecVec, cclusVec, pattVec); // book output size with some margin - auto szIni = estimateCompressedSize(cc); + auto szIni = estimateCompressedSize(compCl); buff.resize(szIni); auto ec = CTF::create(buff); using ECB = CTF::base; - ec->setHeader(cc.header); + ec->setHeader(compCl.header); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec #define ENCODEITSMFT(part, slot, bits) CTF::get(buff.data())->encode(part, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); // clang-format off - ENCODEITSMFT(cc.firstChipROF, CTF::BLCfirstChipROF, 0); - ENCODEITSMFT(cc.bcIncROF, CTF::BLCbcIncROF, 0); - ENCODEITSMFT(cc.orbitIncROF, CTF::BLCorbitIncROF, 0); - ENCODEITSMFT(cc.nclusROF, CTF::BLCnclusROF, 0); + ENCODEITSMFT(compCl.firstChipROF, CTF::BLCfirstChipROF, 0); + ENCODEITSMFT(compCl.bcIncROF, CTF::BLCbcIncROF, 0); + ENCODEITSMFT(compCl.orbitIncROF, CTF::BLCorbitIncROF, 0); + ENCODEITSMFT(compCl.nclusROF, CTF::BLCnclusROF, 0); // - ENCODEITSMFT(cc.chipInc, CTF::BLCchipInc, 0); - ENCODEITSMFT(cc.chipMul, CTF::BLCchipMul, 0); - ENCODEITSMFT(cc.row, CTF::BLCrow, 0); - ENCODEITSMFT(cc.colInc, CTF::BLCcolInc, 0); - ENCODEITSMFT(cc.pattID, CTF::BLCpattID, 0); - ENCODEITSMFT(cc.pattMap, CTF::BLCpattMap, 0); + ENCODEITSMFT(compCl.chipInc, CTF::BLCchipInc, 0); + ENCODEITSMFT(compCl.chipMul, CTF::BLCchipMul, 0); + ENCODEITSMFT(compCl.row, CTF::BLCrow, 0); + ENCODEITSMFT(compCl.colInc, CTF::BLCcolInc, 0); + ENCODEITSMFT(compCl.pattID, CTF::BLCpattID, 0); + ENCODEITSMFT(compCl.pattMap, CTF::BLCpattMap, 0); // clang-format on CTF::get(buff.data())->print(getPrefix()); } /// decode entropy-encoded clusters to standard compact clusters template <typename VROF, typename VCLUS, typename VPAT> -void CTFCoder::decode(const CTF::base& ec, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec) +void CTFCoder::decode(const CTF::base& ec, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup) { - CompressedClusters cc; - cc.header = ec.getHeader(); - ec.print(getPrefix()); -#define DECODEITSMFT(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) - // clang-format off - DECODEITSMFT(cc.firstChipROF, CTF::BLCfirstChipROF); - DECODEITSMFT(cc.bcIncROF, CTF::BLCbcIncROF); - DECODEITSMFT(cc.orbitIncROF, CTF::BLCorbitIncROF); - DECODEITSMFT(cc.nclusROF, CTF::BLCnclusROF); - // - DECODEITSMFT(cc.chipInc, CTF::BLCchipInc); - DECODEITSMFT(cc.chipMul, CTF::BLCchipMul); - DECODEITSMFT(cc.row, CTF::BLCrow); - DECODEITSMFT(cc.colInc, CTF::BLCcolInc); - DECODEITSMFT(cc.pattID, CTF::BLCpattID); - DECODEITSMFT(cc.pattMap, CTF::BLCpattMap); - // clang-format on - // - decompress(cc, rofRecVec, cclusVec, pattVec); + auto compCl = decodeCompressedClusters(ec); + decompress(compCl, rofRecVec, cclusVec, pattVec, noiseMap, clPattLookup); +} + +/// decode entropy-encoded clusters to digits +template <typename VROF, typename VDIG> +void CTFCoder::decode(const CTF::base& ec, VROF& rofRecVec, VDIG& digVec, const NoiseMap* noiseMap, const LookUp& clPattLookup) +{ + auto compCl = decodeCompressedClusters(ec); + decompress(compCl, rofRecVec, digVec, noiseMap, clPattLookup); } /// decompress compressed clusters to standard compact clusters template <typename VROF, typename VCLUS, typename VPAT> -void CTFCoder::decompress(const CompressedClusters& cc, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec) +void CTFCoder::decompress(const CompressedClusters& compCl, VROF& rofRecVec, VCLUS& cclusVec, VPAT& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup) { - rofRecVec.resize(cc.header.nROFs); - cclusVec.resize(cc.header.nClusters); - pattVec.resize(cc.header.nPatternBytes); + PMatrix pmat{}; + RowColBuff firedPixBuff{}, maskedPixBuff{}; + rofRecVec.resize(compCl.header.nROFs); + cclusVec.clear(); + cclusVec.reserve(compCl.header.nClusters); + pattVec.clear(); + pattVec.reserve(compCl.header.nPatternBytes); + o2::InteractionRecord prevIR(compCl.header.firstBC, compCl.header.firstOrbit); + uint32_t clCount = 0, chipCount = 0; + auto pattIt = compCl.pattMap.begin(); + auto pattItStored = pattIt; + + // >> ====== Helper functions for reclusterization after masking some pixels in decoded clusters ====== + // clusterize the pmat matrix holding pixels of the single cluster after masking the noisy ones + + auto clusterize = [&](uint16_t chipID, int16_t row, int16_t col, int leftFired) { +#ifdef _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_ + const std::array<int16_t, 8> walkRow = {1, -1, 0, 0, 1, 1, -1, -1}; + const std::array<int16_t, 8> walkCol = {0, 0, -1, 1, 1, -1, 1, 1}; +#else + const std::array<int16_t, 4> walkRow = {1, -1, 0, 0}; + const std::array<int16_t, 4> walkCol = {0, 0, -1, 1}; +#endif + Clusterer::BBox bbox(chipID); + // check and add to new cluster seed fired pixels around ir1, ic1, return true if there are still fired pixels left + std::function<bool(int16_t, int16_t)> checkPixelAndNeighbours = [&](int16_t ir1, int16_t ic1) { + // if pixel in pmat is fired, add it to new cluster seed and adjust the BBox, decreasing the number of fired pixels left + auto checkPixel = [&](int16_t ir1, int16_t ic1) { + if (pmat[ir1][ic1]) { + pmat[ir1][ic1] = false; + uint16_t r = row + ir1 - 1, c = col + ic1 - 1; + firedPixBuff.emplace_back(r, c); + bbox.adjust(r, c); + leftFired--; + return true; + } + return false; + }; + // check and add to new cluster seed fired pixels at and around ir1, ic1, return true if there are still fired pixels left + if (checkPixel(ir1, ic1) && leftFired) { + uint16_t iw = 0; + while (checkPixelAndNeighbours(ir1 + walkRow[iw], ic1 + walkCol[iw]) && ++iw < walkRow.size()) { + } + } + return leftFired; + }; + // true will be returned if after incremental check of neighbours fired pixels are still left - o2::InteractionRecord prevIR(cc.header.firstBC, cc.header.firstOrbit); - uint32_t firstEntry = 0, clCount = 0, chipCount = 0; - for (uint32_t irof = 0; irof < cc.header.nROFs; irof++) { + firedPixBuff.clear(); // start new cluster seed + for (auto s : maskedPixBuff) { // we start checking from the holes remaining from the masked pixels + uint16_t iw = 0; + do { + checkPixelAndNeighbours(s.getRowDirect() + walkRow[iw], s.getCol() + walkCol[iw]); + if (!firedPixBuff.empty()) { + bbox.chipID = chipID; + Clusterer::streamCluster(firedPixBuff, nullptr, bbox, clPattLookup, &cclusVec, &pattVec, nullptr, 0); + firedPixBuff.clear(); + bbox.clear(); + } + } while (leftFired && ++iw < walkRow.size()); + if (!leftFired) { + break; + } + } + }; + + auto reclusterize = [&]() { + auto clus = cclusVec.back(); // original newly added cluster + // acquire pattern + o2::itsmft::ClusterPattern patt; + auto pattItPrev = pattIt; + maskedPixBuff.clear(); + if (clPattLookup.size() == 0 && clus.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) { + throw std::runtime_error("Clusters contain pattern IDs, but no dictionary is provided..."); + } + if (clus.getPatternID() == o2::itsmft::CompCluster::InvalidPatternID || clPattLookup.isGroup(clus.getPatternID())) { + patt.acquirePattern(pattIt); + } else { + patt = clPattLookup.getPattern(clus.getPatternID()); + } + int rowSpan = patt.getRowSpan(), colSpan = patt.getColumnSpan(), nMasked = 0; + if (rowSpan == 1 && colSpan == 1) { // easy case: 1 pixel cluster + if (noiseMap->isNoisy(clus.getChipID(), clus.getRow(), clus.getCol())) { // just kill the cluster + std::copy(pattItStored, pattItPrev, back_inserter(pattVec)); // save patterns from after last saved to the one before killing this + pattItStored = pattIt; // advance to the head of the pattern iterator + cclusVec.pop_back(); + } + // otherwise do nothing: cluster was already added, eventual patterns will be copied in large block at next modified cluster writing + } else { + int rowSpan = patt.getRowSpan(), colSpan = patt.getColumnSpan(), nMasked = 0, nPixels = 0; // apply noise and fill hits matrix + for (int ir = 0; ir < rowSpan; ir++) { + int row = clus.getRow() + ir; + for (int ic = 0; ic < colSpan; ic++) { + if (patt.isSet(ir, ic)) { + if (noiseMap->isNoisy(clus.getChipID(), row, ic + clus.getCol())) { + maskedPixBuff.emplace_back(ir + 1, ic + 1); + pmat[ir + 1][ic + 1] = false; // reset since might be left from prev cluster + nMasked++; + } else { + pmat[ir + 1][ic + 1] = true; + nPixels++; + } + } else { + pmat[ir + 1][ic + 1] = false; // reset since might be left from prev cluster + } + } + } + + if (nMasked) { + cclusVec.pop_back(); // remove added cluster + std::copy(pattItStored, pattItPrev, back_inserter(pattVec)); // save patterns from after last saved to the one before killing this + pattItStored = pattIt; // advance to the head of the pattern iterator + if (nPixels) { // need to reclusterize remaining pixels + clusterize(clus.getChipID(), clus.getRow(), clus.getCol(), nPixels); + } + } + } + }; + // << ====== Helper functions for reclusterization after masking some pixels in decoded clusters ====== + + for (uint32_t irof = 0; irof < compCl.header.nROFs; irof++) { // restore ROFRecord auto& rofRec = rofRecVec[irof]; - if (cc.orbitIncROF[irof]) { // new orbit - prevIR.bc = cc.bcIncROF[irof]; // bcInc has absolute meaning - prevIR.orbit += cc.orbitIncROF[irof]; + if (compCl.orbitIncROF[irof]) { // new orbit + prevIR.bc = compCl.bcIncROF[irof]; // bcInc has absolute meaning + prevIR.orbit += compCl.orbitIncROF[irof]; } else { - prevIR.bc += cc.bcIncROF[irof]; + prevIR.bc += compCl.bcIncROF[irof]; } rofRec.setBCData(prevIR); - rofRec.setFirstEntry(firstEntry); - rofRec.setNEntries(cc.nclusROF[irof]); - firstEntry += cc.nclusROF[irof]; + rofRec.setFirstEntry(cclusVec.size()); // resrore chips data - auto prevChip = cc.firstChipROF[irof]; - uint16_t prevCol = 0, prevRow = 0; - - // >> this is the version with chipInc stored once per new chip + auto chipID = compCl.firstChipROF[irof]; + uint16_t col = 0; int inChip = 0; - for (uint32_t icl = 0; icl < cc.nclusROF[irof]; icl++) { - auto& clus = cclusVec[clCount]; - if (inChip++ < cc.chipMul[chipCount]) { // still the same chip - clus.setCol((prevCol += cc.colInc[clCount])); + for (uint32_t icl = 0; icl < compCl.nclusROF[irof]; icl++) { + auto& clus = cclusVec.emplace_back(); + if (inChip++ < compCl.chipMul[chipCount]) { // still the same chip + clus.setCol((col += compCl.colInc[clCount])); } else { // new chip starts - prevChip += cc.chipInc[++chipCount]; + chipID += compCl.chipInc[++chipCount]; inChip = 1; - clus.setCol((prevCol = cc.colInc[clCount])); // colInc has abs. col meaning + clus.setCol((col = compCl.colInc[clCount])); // colInc has abs. col meaning + } + clus.setRow(compCl.row[clCount]); + clus.setPatternID(compCl.pattID[clCount]); + clus.setChipID(chipID); + if (noiseMap) { // noise masking was requested + reclusterize(); } - clus.setChipID(prevChip); - clus.setRow(cc.row[clCount]); - clus.setPatternID(cc.pattID[clCount]); clCount++; } - if (cc.nclusROF[irof]) { + if (compCl.nclusROF[irof]) { chipCount++; // since next chip for sure will be new and inChip will be 0... } - // << this is the version with chipInc stored once per new chip - - /* - // >> this is the version with chipInc stored for every pixel, requires entropy compression dealing with repeating symbols - for (uint32_t icl = 0; icl < cc.nclusROF[irof]; icl++) { - auto& clus = cclusVec[clCount]; - if (cc.chipInc[clCount]) { // new chip - prevChip += cc.chipInc[clCount]; - clus.setCol((prevCol = cc.colInc[clCount])); // colInc has abs. col meaning + rofRec.setNEntries(cclusVec.size() - rofRec.getFirstEntry()); + } + if (noiseMap) { // reclusterization was requested + if (pattItStored != pattIt) { // copy unsaved patterns + std::copy(pattItStored, pattIt, back_inserter(pattVec)); + } + } else { // copy decoded patterns as they are + pattVec.resize(compCl.header.nPatternBytes); + memcpy(pattVec.data(), compCl.pattMap.data(), compCl.header.nPatternBytes); + } + assert(chipCount == compCl.header.nChips); + + if (clCount != compCl.header.nClusters) { + LOG(ERROR) << "expected " << compCl.header.nClusters << " but counted " << clCount << " in ROFRecords"; + throw std::runtime_error("mismatch between expected and counter number of clusters"); + } +} + +/// decompress compressed clusters to digits +template <typename VROF, typename VDIG> +void CTFCoder::decompress(const CompressedClusters& compCl, VROF& rofRecVec, VDIG& digVec, const NoiseMap* noiseMap, const LookUp& clPattLookup) +{ + rofRecVec.resize(compCl.header.nROFs); + digVec.reserve(compCl.header.nClusters * 2); + o2::InteractionRecord prevIR(compCl.header.firstBC, compCl.header.firstOrbit); + uint32_t clCount = 0, chipCount = 0; + auto pattIt = compCl.pattMap.begin(); + o2::itsmft::ClusterPattern patt; + for (uint32_t irof = 0; irof < compCl.header.nROFs; irof++) { + size_t chipStartNDig = digVec.size(); + // restore ROFRecord + auto& rofRec = rofRecVec[irof]; + if (compCl.orbitIncROF[irof]) { // new orbit + prevIR.bc = compCl.bcIncROF[irof]; // bcInc has absolute meaning + prevIR.orbit += compCl.orbitIncROF[irof]; } else { - clus.setCol((prevCol += cc.colInc[clCount])); + prevIR.bc += compCl.bcIncROF[irof]; } - clus.setChipID(prevChip); - clus.setRow(cc.row[clCount]); - clus.setPatternID(cc.pattID[clCount]); - clCount++; + rofRec.setBCData(prevIR); + rofRec.setFirstEntry(digVec.size()); + + // resrore chips data + uint16_t chipID = compCl.firstChipROF[irof], col = 0; + int inChip = 0; + for (uint32_t icl = 0; icl < compCl.nclusROF[irof]; icl++) { + if (inChip++ < compCl.chipMul[chipCount]) { // still the same chip + col += compCl.colInc[clCount]; +#ifdef _CHECK_INCREMENTES_ // RS FIXME with current clusterization column increment can be slightly negative +// if (int16_t(compCl.colInc[clCount])<0) { +// LOG(WARNING) << "Negative column increment " << int16_t(compCl.colInc[clCount]) << " -> " << col << " in chip " << chipID; +// } +#endif + } else { // new chip starts + // sort digits of previous chip in col/row + auto added = digVec.size() - chipStartNDig; + if (added > 1) { // we need to sort digits in colums and in rows within a column + std::sort(digVec.end() - added, digVec.end(), + [](Digit& a, Digit& b) { return a.getColumn() < b.getColumn() || (a.getColumn() == b.getColumn() && a.getRow() < b.getRow()); }); + } + chipStartNDig = digVec.size(); + chipID += compCl.chipInc[++chipCount]; +#ifdef _CHECK_INCREMENTES_ + if (int16_t(compCl.chipInc[chipCount]) < 0) { + LOG(WARNING) << "Negative chip increment " << int16_t(compCl.chipInc[chipCount]) << " -> " << chipID; + } +#endif + inChip = 1; + col = compCl.colInc[clCount]; // colInc has abs. col meaning + } + uint16_t row = compCl.row[clCount]; + auto pattID = compCl.pattID[clCount]; + if (pattID == o2::itsmft::CompCluster::InvalidPatternID) { + patt.acquirePattern(pattIt); + } else { + if (clPattLookup.size() == 0) { + throw std::runtime_error("Clusters contain pattern IDs, but no dictionary is provided..."); + } + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || clPattLookup.isGroup(pattID)) { + patt.acquirePattern(pattIt); + } else { + patt = clPattLookup.getPattern(pattID); + } + } + clCount++; + + auto fillRowCol = [&digVec, chipID, row, col, noiseMap](int r, int c) { + r += row; + c += col; + if (noiseMap && noiseMap->isNoisy(chipID, r, c)) { + return; + } + digVec.emplace_back(chipID, uint16_t(r), uint16_t(c)); + }; + patt.process(fillRowCol); + } + auto added = digVec.size() - chipStartNDig; + if (added > 1) { // Last chip of the ROF: we need to sort digits in colums and in rows within a column + std::sort(digVec.end() - added, digVec.end(), + [](Digit& a, Digit& b) { return a.getColumn() < b.getColumn() || (a.getColumn() == b.getColumn() && a.getRow() < b.getRow()); }); + } + + if (compCl.nclusROF[irof]) { + chipCount++; // since next chip for sure will be new and incChip will be 0... } - // << this is the version with chipInc stored for every pixel, requires entropy compression dealing with repeating symbols - */ + rofRec.setNEntries(digVec.size() - rofRec.getFirstEntry()); } // explicit patterns - memcpy(pattVec.data(), cc.pattMap.data(), cc.header.nPatternBytes); // RSTODO use swap? - assert(chipCount == cc.header.nChips); + assert(pattIt == compCl.pattMap.end()); + assert(chipCount == compCl.header.nChips); - if (clCount != cc.header.nClusters) { - LOG(ERROR) << "expected " << cc.header.nClusters << " but counted " << clCount << " in ROFRecords"; + if (clCount != compCl.header.nClusters) { + LOG(ERROR) << "expected " << compCl.header.nClusters << " but counted " << clCount << " in ROFRecords"; throw std::runtime_error("mismatch between expected and counter number of clusters"); } } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingITS.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingITS.h index feafb6298bf23..d941c40a14dd2 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingITS.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -51,6 +52,9 @@ class ChipMappingITS ///< total number of chips static constexpr int getNChips() { return NChipsSB[IB] + NChipsSB[MB] + NChipsSB[OB]; } + ///< number of chips per barrel + static constexpr int getNChips(int b) { return NChipsSB[b]; } + ///< number of staves on layer static constexpr int getNStavesOnLr(int l) { return NStavesOnLr[l]; } @@ -172,6 +176,9 @@ class ChipMappingITS ///< convert HW cable ID to SW ID for given RU type (see ChipOnRUInfo.cableSW explanation) uint8_t cableHW2SW(uint8_t ruType, uint8_t hwid) const { return mCableHW2SW[ruType][hwid]; } + ///< convert cable iterator ID to the position on the ActiveLanes word in the GBT.header for given RU type; MFT lanes position compatible + uint8_t cablePos(uint8_t ruType, uint8_t id) const { return mCablePos[ruType][id]; } + ///< get number of chips served by single cable on given RU type int getNChipsPerCable(int ruType) { return NChipsPerCableSB[ruType]; } @@ -294,7 +301,8 @@ class ChipMappingITS int mChipInfoEntrySB[NSubB] = {0}; std::vector<uint8_t> mCableHW2SW[NSubB]; ///< table of cables HW to SW conversion for each RU type - std::vector<uint8_t> mCableHW2Pos[NSubB]; ///< table of cables positions in the ActiveLanes mask for each RU type + std::vector<uint8_t> mCableHW2Pos[NSubB]; ///< table of cables positions in the ActiveLanes mask for each RU type (HW numbering) + std::vector<uint8_t> mCablePos[NSubB]; ///< table of cables positions in the ActiveLanes mask for each RU type (sequential numbering) std::vector<uint8_t> mCableHWFirstChip[NSubB]; ///< 1st chip of module (relative to the 1st chip of the stave) served by each cable std::array<int, NSubB> mCablesOnStaveSB = {0}; ///< pattern of cables per stave of sub-barrel diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingMFT.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingMFT.h index e87c5b44be6c2..cd0bf58ae47ce 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingMFT.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ChipMappingMFT.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,10 +28,22 @@ namespace itsmft { struct MFTChipMappingData { - UShort_t module = 0; // global module ID - UChar_t chipOnModule = 0; // chip within the module - UChar_t cable = 0; // cable in the connector - UChar_t chipOnRU = 0; // chip within the RU (SW) + UShort_t module = 0; // global module ID + UChar_t chipOnModule = 0; // chip within the module + UChar_t cable = 0; // cable in the connector + UChar_t chipOnRU = 0; // chip within the RU (SW) + UShort_t globalChipSWID = 0; // global software chip ID + UShort_t localChipSWID = 0; // local software chip ID + UShort_t localChipHWID = 0; // local hardware chip ID + UChar_t connector = 0; // cable connector in a zone + UChar_t zone = 0; // read-out zone id + UChar_t ruOnLayer = 0; // read-out-unit index on layer + UChar_t ruType = 0; // read-out-unit type + UChar_t ruSWID = 0; // read-out-unit hardware ID + UChar_t ruHWID = 0; // read-out-unit software ID + UChar_t layer = 0; // MFT layer + UChar_t disk = 0; // MFT disk + UChar_t half = 0; // MFT half ClassDefNV(MFTChipMappingData, 1); }; @@ -108,6 +121,9 @@ class ChipMappingMFT ///< convert HW cable ID to SW ID for give RU type uint8_t cableHW2SW(uint8_t ruType, uint8_t hwid) const { return mCableHW2SW[ruType][hwid]; } + ///< convert cable iterator ID to its position on the ActiveLanes word in the GBT.header for given RU type + uint8_t cablePos(uint8_t ruType, uint8_t id) const { return mCablePos[ruType][id]; } + ///< get chip global SW ID from chipID on module, cable SW ID and stave (RU) info uint16_t getGlobalChipID(uint16_t chOnModuleHW, int cableHW, const RUInfo& ruInfo) const { @@ -198,8 +214,14 @@ class ChipMappingMFT static constexpr std::int16_t getRUDetectorField() { return 0x0; } - ///< get pattern of lanes on the RU served by a given RU type - Int_t getCablesOnRUType(Int_t ruType) const { return (0x1 << NChipsOnRUType[ruType]) - 1; } + uint32_t getCablesOnRUType(Int_t ruType) const + { + uint32_t pattern = 0; + for (Int_t i = 0; i < NRUCables; i++) { + pattern |= (0x1 << mCableHW2Pos[ruType][i]); + } + return pattern; + } ///< get info on sw RU const RUInfo* getRUInfoSW(int ruSW) const { return &mRUInfo[ruSW]; } @@ -223,13 +245,50 @@ class ChipMappingMFT ///< convert zone number [0...8] and layer number [0...10] to RU type int getRUType(int zone, int layer) const { return ZoneRUType[zone % 4][layer / 2]; } - static constexpr int NLayers = 10, NZonesPerLayer = 2 * 4, NRUTypes = 13; + static constexpr int NChips = 936, NLayers = 10, NZonesPerLayer = 2 * 4, NRUTypes = 13; + + const std::array<MFTChipMappingData, NChips>& getChipMappingData() const { return ChipMappingData; } + + void print() const; + + ///< LayerID of each MFT chip + static constexpr std::array<int, NChips> ChipID2Layer{ + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9}; private: Int_t invalid() const; static constexpr Int_t NRUs = NLayers * NZonesPerLayer; static constexpr Int_t NModules = 280; - static constexpr Int_t NChips = 936; static constexpr Int_t NChipsInfo = 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 16 + 17 + 18 + 19 + 14; static constexpr Int_t NChipsPerCable = 1; static constexpr Int_t NLinks = 1; @@ -277,6 +336,7 @@ class ChipMappingMFT std::vector<uint8_t> mCableHW2SW[NRUs]; ///< table of cables HW to SW conversion for each RU type std::vector<uint8_t> mCableHW2Pos[NRUs]; ///< table of cables positions in the ActiveLanes mask for each RU type + std::vector<uint8_t> mCablePos[NRUs]; ///< reverse table of cables positions in the ActiveLanes mask for each RU type std::vector<uint8_t> mCableHWFirstChip[NRUs]; ///< 1st chip of module (relative to the 1st chip of the stave) served by each cable std::array<std::vector<uint16_t>, NRUs> mRUGlobalChipID; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h index c2c9a3333cb07..26d6ef55b1582 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,10 @@ #define _PERFORM_TIMING_ +// uncomment this to not allow diagonal clusters, e.g. like |* | +// | *| +#define _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_ + #include <utility> #include <vector> #include <cstring> @@ -69,6 +74,40 @@ class Clusterer public: static constexpr int MaxLabels = 10; + + struct BBox { + uint16_t chipID = 0xffff; + uint16_t rowMin = 0xffff; + uint16_t colMin = 0xffff; + uint16_t rowMax = 0; + uint16_t colMax = 0; + BBox(uint16_t c) : chipID(c) {} + bool isInside(uint16_t row, uint16_t col) const { return row >= rowMin && row <= rowMax && col >= colMin && col <= colMax; } + auto rowSpan() const { return rowMax - rowMin + 1; } + auto colSpan() const { return colMax - colMin + 1; } + bool isAcceptableSize() const { return colMax - colMin < o2::itsmft::ClusterPattern::MaxColSpan && rowMax - rowMin < o2::itsmft::ClusterPattern::MaxRowSpan; } + void clear() + { + rowMin = colMin = 0xffff; + rowMax = colMax = 0; + } + void adjust(uint16_t row, uint16_t col) + { + if (row < rowMin) { + rowMin = row; + } + if (row > rowMax) { + rowMax = row; + } + if (col < colMin) { + colMin = col; + } + if (col > colMax) { + colMax = col; + } + } + }; + //========================================================= /// methods and transient data used within a thread struct ThreadStat { @@ -132,11 +171,6 @@ class Clusterer curr[row] = lastIndex; // store index of the new precluster in the current column buffer } - void streamCluster(const std::vector<PixelData>& pixbuf, uint16_t rowMin, uint16_t rowSpanW, uint16_t colMin, uint16_t colSpanW, - uint16_t chipID, - CompClusCont* compClusPtr, PatternCont* patternsPtr, - MCTruth* labelsClusPtr, int nlab, bool isHuge = false); - void fetchMCLabels(int digID, const ConstMCTruth* labelsDig, int& nfilled); void initChip(const ChipPixelData* curChipData, uint32_t first); void updateChip(const ChipPixelData* curChipData, uint32_t ip); @@ -163,6 +197,10 @@ class Clusterer void process(int nThreads, PixelReader& r, CompClusCont* compClus, PatternCont* patterns, ROFRecCont* vecROFRec, MCTruth* labelsCl = nullptr); + template <typename VCLUS, typename VPAT> + static void streamCluster(const std::vector<PixelData>& pixbuf, const std::array<Label, MaxLabels>* lblBuff, const BBox& bbox, const LookUp& pattIdConverter, + VCLUS* compClusPtr, VPAT* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isHuge = false); + bool isContinuousReadOut() const { return mContinuousReadout; } void setContinuousReadOut(bool v) { mContinuousReadout = v; } @@ -189,23 +227,6 @@ class Clusterer private: - ///< recalculate min max row and column of the cluster accounting for the position of pix - static void adjustBoundingBox(uint16_t row, uint16_t col, uint16_t& rMin, uint16_t& rMax, uint16_t& cMin, uint16_t& cMax) - { - if (row < rMin) { - rMin = row; - } - if (row > rMax) { - rMax = row; - } - if (col < cMin) { - cMin = col; - } - if (col > cMax) { - cMax = col; - } - } - void flushClusters(CompClusCont* compClus, MCTruth* labels); // clusterization options @@ -226,6 +247,47 @@ class Clusterer TStopwatch mTimerMerge; }; +template <typename VCLUS, typename VPAT> +void Clusterer::streamCluster(const std::vector<PixelData>& pixbuf, const std::array<Label, MaxLabels>* lblBuff, const Clusterer::BBox& bbox, const LookUp& pattIdConverter, + VCLUS* compClusPtr, VPAT* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isHuge) +{ + if (labelsClusPtr && lblBuff) { // MC labels were requested + auto cnt = compClusPtr->size(); + for (int i = nlab; i--;) { + labelsClusPtr->addElement(cnt, (*lblBuff)[i]); + } + } + auto colSpanW = bbox.colSpan(); + auto rowSpanW = bbox.rowSpan(); + // add to compact clusters, which must be always filled + std::array<unsigned char, ClusterPattern::MaxPatternBytes> patt{}; + for (const auto& pix : pixbuf) { + uint32_t ir = pix.getRowDirect() - bbox.rowMin, ic = pix.getCol() - bbox.colMin; + int nbits = ir * colSpanW + ic; + patt[nbits >> 3] |= (0x1 << (7 - (nbits % 8))); + } + uint16_t pattID = (isHuge || pattIdConverter.size() == 0) ? CompCluster::InvalidPatternID : pattIdConverter.findGroupID(rowSpanW, colSpanW, patt.data()); + uint16_t row = bbox.rowMin, col = bbox.colMin; + if (pattID == CompCluster::InvalidPatternID || pattIdConverter.isGroup(pattID)) { + if (pattID != CompCluster::InvalidPatternID) { + //For groupped topologies, the reference pixel is the COG pixel + float xCOG = 0., zCOG = 0.; + ClusterPattern::getCOG(rowSpanW, colSpanW, patt.data(), xCOG, zCOG); + row += round(xCOG); + col += round(zCOG); + } + if (patternsPtr) { + patternsPtr->emplace_back((unsigned char)rowSpanW); + patternsPtr->emplace_back((unsigned char)colSpanW); + int nBytes = rowSpanW * colSpanW / 8; + if (((rowSpanW * colSpanW) % 8) != 0) { + nBytes++; + } + patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + nBytes); + } + } + compClusPtr->emplace_back(row, col, pattID, bbox.chipID); +} } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h index 0de3494988e4a..988443513fcba 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h index f93d17141eb28..8489971edc195 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ namespace o2 { namespace itsmft { +class ChipPixelData; struct ChipStat { @@ -32,13 +34,24 @@ struct ChipStat { Fatal, BusyOn, BusyOff, - TruncatedChipEmpty, // Data was truncated after ChipEmpty - TruncatedChipHeader, // Data was truncated after ChipHeader - TruncatedRegion, // Data was truncated after Region record - TruncatedLondData, // Data was truncated in the LongData record - WrongDataLongPattern, // LongData pattern has highest bit set - NoDataFound, // Region is not followed by Short or Long data - UnknownWord, // Unknow word was seen + TruncatedChipEmpty, // Data was truncated after ChipEmpty + TruncatedChipHeader, // Data was truncated after ChipHeader + TruncatedRegion, // Data was truncated after Region record + TruncatedLondData, // Data was truncated in the LongData record + WrongDataLongPattern, // LongData pattern has highest bit set + NoDataFound, // Region is not followed by Short or Long data + UnknownWord, // Unknown word was seen + RepeatingPixel, // Same pixel fired more than once + WrongRow, // Non-existing row decoded + APE_STRIP_START, // lane entering strip data mode | See https://alice.its.cern.ch/jira/browse/O2-1717 + APE_STRIP_STOP, // lane exiting strip data mode + APE_DET_TIMEOUT, // detector timeout (FATAL) + APE_OOT_START, // 8b10b OOT (FATAL, start) + APE_PROTOCOL_ERROR, // event protocol error marker (FATAL, start) + APE_LANE_FIFO_OVERFLOW_ERROR, // lane FIFO overflow error (FATAL) + APE_FSM_ERROR, // FSM error (FATAL, SEU error, reached an unknown state) + APE_OCCUPANCY_RATE_LIMIT, // pending detector events limit (FATAL) + APE_OCCUPANCY_RATE_LIMIT_2, // pending detector events limit in packager(FATAL) NErrorsDefined }; @@ -54,35 +67,44 @@ struct ChipStat { "Data truncated after LongData", // TruncatedLondData "LongData pattern has highest bit set", // WrongDataLongPattern "Region is not followed by Short or Long data", // NoDataFound - "Unknow word" // UnknownWord - }; - - uint16_t chipID = 0; + "Unknown word", // UnknownWord + "Same pixel fired multiple times", // RepeatingPixel + "Non-existing row decoded", // WrongRow + "APE_STRIP_START", + "APE_STRIP_STOP", + "APE_DET_TIMEOUT", + "APE_OOT_START", + "APE_PROTOCOL_ERROR", + "APE_LANE_FIFO_OVERFLOW_ERROR", + "APE_FSM_ERROR", + "APE_OCCUPANCY_RATE_LIMIT", + "APE_OCCUPANCY_RATE_LIMIT_2"}; + + uint16_t feeID = -1; size_t nHits = 0; std::array<uint32_t, NErrorsDefined> errorCounts = {}; ChipStat() = default; - ChipStat(uint16_t id) : chipID(id) {} + ChipStat(uint16_t _feeID) : feeID(_feeID) {} void clear() { memset(errorCounts.data(), 0, sizeof(uint32_t) * errorCounts.size()); nHits = 0; } - - uint32_t getNErrors() const; - - void addErrors(uint32_t mask) + // return APE DecErrors code or -1 if not APE error, set fatal flag if needd + static int getAPECode(uint8_t c, bool& ft) { - if (mask) { - for (int i = NErrorsDefined; i--;) { - if (mask & (0x1 << i)) { - errorCounts[i]++; - } - } + if (c < 0xf2 || c > 0xfa) { + ft = false; + return -1; } + ft = c >= 0xf4; + return APE_STRIP_START + c - 0xf2; } - - void print(bool skipEmpty = true) const; + uint32_t getNErrors() const; + void addErrors(uint32_t mask, uint16_t chID, int verbosity); + void addErrors(const ChipPixelData& d, int verbosity); + void print(bool skipNoErr = true, const std::string& pref = "FEEID") const; ClassDefNV(ChipStat, 1); }; @@ -138,20 +160,22 @@ struct GBTLinkDecodingStat { uint32_t ruLinkID = 0; // Link ID within RU // Note: packet here is meant as a group of CRU pages belonging to the same trigger - uint32_t nPackets = 0; // total number of packets + uint32_t nPackets = 0; // total number of packets (RDH pages) + uint32_t nTriggers = 0; // total number of triggers (ROFs) std::array<uint32_t, NErrorsDefined> errorCounts = {}; // error counters std::array<uint32_t, GBTDataTrailer::MaxStateCombinations> packetStates = {}; // packet status from the trailer void clear() { nPackets = 0; + nTriggers = 0; errorCounts.fill(0); packetStates.fill(0); } - void print(bool skipEmpty = true) const; + void print(bool skipNoErr = true) const; - ClassDefNV(GBTLinkDecodingStat, 1); + ClassDefNV(GBTLinkDecodingStat, 2); }; } // namespace itsmft diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h index 165d149810ed3..a4dd5df32d03f 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsITSMFT/Digit.h" #include "DetectorsCommonDataFormats/DetID.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include <TTree.h> @@ -99,7 +101,7 @@ class DigitPixelReader : public PixelReader std::vector<o2::itsmft::Digit>* mDigitsSelf = nullptr; std::vector<o2::itsmft::ROFRecord>* mROFRecVecSelf = nullptr; std::vector<o2::itsmft::MC2ROFRecord>* mMC2ROFRecVecSelf = nullptr; - const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>* mDigitsMCTruthSelf = nullptr; + const o2::dataformats::IOMCTruthContainerView* mDigitsMCTruthSelf = nullptr; gsl::span<const o2::itsmft::Digit> mDigits; gsl::span<const o2::itsmft::ROFRecord> mROFRecVec; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h index f8e459f31d407..48c7f96d1bc48 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -123,6 +124,7 @@ struct GBTLink { } private: + bool needToPrintError(uint32_t count) { return verbosity == Silent ? false : (verbosity >= VerboseErrors || count == 1); } void discardData() { rawData.setDone(); } void printTrigger(const GBTTrigger* gbtTrg); void printHeader(const GBTDataHeader* gbtH); @@ -249,6 +251,7 @@ GBTLink::CollectedDataStatus GBTLink::collectROFCableData(const Mapping& chmap) printTrigger(gbtTrg); } GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsTriggerWord(gbtTrg)); + statistics.nTriggers++; if (gbtTrg->noData) { // emtpy trigger return status; } @@ -262,6 +265,7 @@ GBTLink::CollectedDataStatus GBTLink::collectROFCableData(const Mapping& chmap) printCalibrationWord(gbtC); } dataOffset += GBTPaddedWordLength; + ruPtr->calibData = {gbtC->calibCounter, gbtC->calibUserField}; } } auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(&currRawPiece->data[dataOffset]); @@ -309,6 +313,7 @@ GBTLink::CollectedDataStatus GBTLink::collectROFCableData(const Mapping& chmap) ir = RDHUtils::getTriggerIR(*lastRDH); trigger = RDHUtils::getTriggerType(*lastRDH); } + return (status = DataSeen); } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTWord.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTWord.h index 43b063ed4baef..d139fbe1641e3 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTWord.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTWord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/LookUp.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/LookUp.h index 44594da48d07b..e0b56ccc3d573 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/LookUp.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/LookUp.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,11 +36,13 @@ class LookUp LookUp(); LookUp(std::string fileName); static int groupFinder(int nRow, int nCol); - int findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPattern::MaxPatternBytes]); - int getTopologiesOverThreshold() { return mTopologiesOverThreshold; } + int findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPattern::MaxPatternBytes]) const; + int getTopologiesOverThreshold() const { return mTopologiesOverThreshold; } void loadDictionary(std::string fileName); - bool isGroup(int id) const; + bool isGroup(int id) const { return mDictionary.isGroup(id); } int size() const { return mDictionary.getSize(); } + auto getPattern(int id) const { return mDictionary.getPattern(id); } + auto getDictionaty() const { return mDictionary; } private: TopologyDictionary mDictionary; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h index f42464c353fe5..adb0339930843 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h index 5b9ea8a7ba906..43d6cedeb7817 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h index 9472b40263bfd..7f0b7aad09611 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "CommonDataFormat/InteractionRecord.h" #include "ITSMFTReconstruction/DecodingStat.h" +#include <string> #include <vector> #include <utility> #include <cstdint> @@ -84,8 +86,8 @@ class PixelData private: void sanityCheck() const; - static constexpr int RowMask = 0x1ff; ///< 512 rows are supported - static constexpr int MaskBit = 0x200; ///< 10-th bit is used to flag masked pixel + static constexpr int RowMask = 0x7FFF; ///< 32768 rows are supported + static constexpr int MaskBit = 0x8000; ///< 16-th bit is used to flag masked pixel uint16_t mRow = 0; ///< pixel row uint16_t mCol = 0; ///< pixel column @@ -98,6 +100,8 @@ class ChipPixelData { public: + // total number of raw data bytes to save in case of error and number of bytes (if any) after problematic one + static constexpr size_t MAXDATAERRBYTES = 16, MAXDATAERRBYTES_AFTER = 2; ChipPixelData() = default; ~ChipPixelData() = default; uint8_t getROFlags() const { return mROFlags; } @@ -119,31 +123,45 @@ class ChipPixelData void setTrigger(uint32_t t) { mTrigger = t; } void setError(ChipStat::DecErrors i) { mErrors |= 0x1 << i; } + void addErrorInfo(uint64_t b) { mErrorInfo |= b; } void setErrorFlags(uint32_t f) { mErrors |= f; } bool isErrorSet(ChipStat::DecErrors i) const { return mErrors & (0x1 << i); } bool isErrorSet() const { return mErrors != 0; } - uint32_t getErrorFlags() const { return mErrors; } + auto getErrorFlags() const { return mErrors; } + auto getErrorInfo() const { return mErrorInfo; } + auto getNBytesInRawBuff() const { return int(mErrorInfo >> 32) & 0xff; } + void setNBytesInRawBuff(int n) { mErrorInfo |= (uint64_t(n & 0xff)) << 32; } + auto& getRawErrBuff() { return mRawBuff; } + auto& getRawErrBuff() const { return mRawBuff; } + std::string getErrorDetails(int pos) const; + + void resetChipID() + { + mChipID = -1; + } void clear() { + resetChipID(); mPixels.clear(); mROFlags = 0; mFirstUnmasked = 0; mErrors = 0; + mErrorInfo = 0; } void swap(ChipPixelData& other) { // swap content of two objects - mPixels.swap(other.mPixels); - std::swap(mROFrame, other.mROFrame); std::swap(mROFlags, other.mROFlags); + std::swap(mChipID, other.mChipID); + std::swap(mROFrame, other.mROFrame); + std::swap(mFirstUnmasked, other.mFirstUnmasked); // strictly speaking, not needed + std::swap(mStartID, other.mStartID); // strictly speaking, not needed std::swap(mTrigger, other.mTrigger); + std::swap(mErrors, other.mErrors); std::swap(mInteractionRecord, other.mInteractionRecord); - std::swap(mChipID, other.mChipID); - // strictly speaking, swapping the data below is not needed - std::swap(mStartID, other.mStartID); - std::swap(mFirstUnmasked, other.mFirstUnmasked); + mPixels.swap(other.mPixels); } void maskFiredInSample(const ChipPixelData& sample) @@ -225,15 +243,17 @@ class ChipPixelData void print() const; private: - uint8_t mROFlags = 0; // readout flags from the chip trailer - uint16_t mChipID = 0; // chip id within the detector - uint32_t mROFrame = 0; // readout frame ID - uint32_t mFirstUnmasked = 0; // first unmasked entry in the mPixels - uint32_t mStartID = 0; // entry of the 1st pixel data in the whole detector data, for MCtruth access - uint32_t mTrigger = 0; // trigger pattern - uint32_t mErrors = 0; // errors set during decoding - o2::InteractionRecord mInteractionRecord = {}; // interaction record - std::vector<PixelData> mPixels; // vector of pixeld + uint8_t mROFlags = 0; // readout flags from the chip trailer + uint16_t mChipID = 0; // chip id within the detector + uint32_t mROFrame = 0; // readout frame ID + uint32_t mFirstUnmasked = 0; // first unmasked entry in the mPixels + uint32_t mStartID = 0; // entry of the 1st pixel data in the whole detector data, for MCtruth access + uint32_t mTrigger = 0; // trigger pattern + uint32_t mErrors = 0; // errors set during decoding + uint64_t mErrorInfo = 0; // optional extra info on the error + std::array<uint8_t, MAXDATAERRBYTES> mRawBuff{}; // buffer for raw data showing an error + o2::InteractionRecord mInteractionRecord = {}; // interaction record + std::vector<PixelData> mPixels; // vector of pixeld ClassDefNV(ChipPixelData, 1); }; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h index 6a34bd5d1b08a..8eea34ec39bd6 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h index e8cda7a633bd4..fdbda35de3013 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "ITSMFTReconstruction/PixelData.h" #include "ITSMFTReconstruction/PayLoadCont.h" #include "ITSMFTReconstruction/AlpideCoder.h" +#include "DataFormatsITSMFT/GBTCalibData.h" namespace o2 { @@ -43,6 +45,9 @@ struct RUDecodeData { int nCables = 0; // total number of cables decoded for single trigger int nChipsFired = 0; // number of chips with data or with errors int lastChipChecked = 0; // last chips checked among nChipsFired + int verbosity = 0; // verbosity level, for -1,0 print only summary data, for 1: print once every error + GBTCalibData calibData{}; // calibration info from GBT calibration word + const RUInfo* ruInfo = nullptr; RUDecodeData() @@ -57,7 +62,7 @@ struct RUDecodeData { int decodeROF(const Mapping& mp); void fillChipStatistics(int icab, const ChipPixelData* chipData); - ClassDefNV(RUDecodeData, 1); + ClassDefNV(RUDecodeData, 2); }; ///_________________________________________________________________ @@ -75,18 +80,23 @@ int RUDecodeData::decodeROF(const Mapping& mp) } auto cabHW = cableHWID[icab]; auto chIdGetter = [this, &mp, cabHW](int cid) { - return mp.getGlobalChipID(cid, cabHW, *this->ruInfo); + //return mp.getGlobalChipID(cid, cabHW, *this->ruInfo); + auto chip = mp.getGlobalChipID(cid, cabHW, *this->ruInfo); + return chip; }; - while (AlpideCoder::decodeChip(*chipData, cableData[icab], chIdGetter) || chipData->isErrorSet()) { // we register only chips with hits or errors flags set + int ret = 0; + while ((ret = AlpideCoder::decodeChip(*chipData, cableData[icab], chIdGetter)) || chipData->isErrorSet()) { // we register only chips with hits or errors flags set setROFInfo(chipData, cableLinkPtr[icab]); - ntot += chipData->getData().size(); #ifdef ALPIDE_DECODING_STAT fillChipStatistics(icab, chipData); #endif - if (++nChipsFired < chipsData.size()) { // fetch next free chip - chipData = &chipsData[nChipsFired]; - } else { - break; // last chip decoded + if (ret >= 0 && !chipData->isErrorSet()) { // make sure there was no error + ntot += chipData->getData().size(); + if (++nChipsFired < chipsData.size()) { // fetch next free chip + chipData = &chipsData[nChipsFired]; + } else { + break; // last chip decoded + } } } } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUInfo.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUInfo.h index aad60cdc0909d..18eaba47b6190 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUInfo.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include <Rtypes.h> #include <cstdint> +#include <string> namespace o2 { @@ -47,6 +49,7 @@ struct ChipOnRUInfo { std::uint8_t cableHWPos = DUMMY8; // position of the bit of this cable in the activeLanes std::uint8_t chipOnCable = DUMMY8; // chip within the cable (0 = master) + std::string asString() const; void print() const; }; @@ -60,6 +63,7 @@ struct ChipInfo { std::uint16_t ru = DUMMY16; // RU sequential id std::uint16_t ruType = DUMMY16; // RU (or subBarrel) type + std::string asString() const; void print() const; }; } // namespace itsmft diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h index 0b6467b84b6a7..20626f4017f0b 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,7 +55,7 @@ class RawPixelDecoder final : public PixelReader void init() final {} bool getNextChipData(ChipPixelData& chipData) final; ChipPixelData* getNextChipData(std::vector<ChipPixelData>& chipDataVec) final; - + void ensureChipOrdering() {} void startNewTF(o2::framework::InputRecord& inputs); int decodeNextTrigger() final; @@ -63,6 +64,9 @@ class RawPixelDecoder final : public PixelReader template <class DigitContainer, class ROFContainer> int fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs); + template <class CalibContainer> + void fillCalibData(CalibContainer& calib); + const RUDecodeData* getRUDecode(int ruSW) const { return mRUEntry[ruSW] < 0 ? nullptr : &mRUDecodeVec[mRUEntry[ruSW]]; } const GBTLink* getGBTLink(int i) const { return i < 0 ? nullptr : &mGBTLinks[i]; } int getNLinks() const { return mGBTLinks.size(); } @@ -76,10 +80,13 @@ class RawPixelDecoder final : public PixelReader void setNThreads(int n); int getNThreads() const { return mNThreads; } + void setFillCalibData(bool v) { mFillCalibData = v; } + bool getFillCalibData() const { return mFillCalibData; } + void setVerbosity(int v); int getVerbosity() const { return mVerbosity; } - void printReport(bool decstat = false, bool skipEmpty = true) const; + void printReport(bool decstat = true, bool skipNoErr = true) const; void clearStat(); @@ -91,6 +98,11 @@ class RawPixelDecoder final : public PixelReader size_t getNChipsFired() const { return mNChipsFired; } size_t getNPixelsFired() const { return mNPixelsFired; } + void setInstanceID(size_t i) { mInstanceID = i; } + void setNInstances(size_t n) { mNInstances = n; } + auto getInstanceID() const { return mInstanceID; } + auto getNInstances() const { return mNInstances; } + struct LinkEntry { int entry = -1; }; @@ -108,12 +120,14 @@ class RawPixelDecoder final : public PixelReader std::unordered_map<uint32_t, LinkEntry> mSubsSpec2LinkID; // link subspec to link entry in the pool mapping std::vector<RUDecodeData> mRUDecodeVec; // set of active RUs std::array<short, Mapping::getNRUs()> mRUEntry; // entry of the RU with given SW ID in the mRUDecodeVec + std::vector<ChipPixelData*> mOrderedChipsPtr; // special ordering helper used for the MFT (its chipID is not contiguous in RU) std::string mSelfName; // self name header::DataOrigin mUserDataOrigin = o2::header::gDataOriginInvalid; // alternative user-provided data origin to pick header::DataDescription mUserDataDescription = o2::header::gDataDescriptionInvalid; // alternative user-provided description to pick uint16_t mCurRUDecodeID = NORUDECODED; // index of currently processed RUDecode container int mLastReadChipID = -1; // chip ID returned by previous getNextChipData call, used for ordering checks Mapping mMAP; // chip mapping + bool mFillCalibData = false; // request to fill calib data from GBT int mVerbosity = 0; int mNThreads = 1; // number of decoding threads GBTLink::Format mFormat = GBTLink::NewFormat; // ITS Data Format (old: 1 ROF per CRU page) @@ -124,11 +138,11 @@ class RawPixelDecoder final : public PixelReader uint32_t mNLinksDone = 0; // number of links reached end of data size_t mNChipsFired = 0; // global counter size_t mNPixelsFired = 0; // global counter + size_t mInstanceID = 0; // pipeline instance + size_t mNInstances = 1; // total number of pipelines TStopwatch mTimerTFStart; TStopwatch mTimerDecode; TStopwatch mTimerFetchData; - - ClassDefOverride(RawPixelDecoder, 1); }; ///______________________________________________________________ @@ -156,6 +170,47 @@ int RawPixelDecoder<Mapping>::fillDecodedDigits(DigitContainer& digits, ROFConta return nFilled; } +///______________________________________________________________ +/// Fill decoded digits to global vector +template <> +template <class DigitContainer, class ROFContainer> +int RawPixelDecoder<ChipMappingMFT>::fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs) +{ + if (mInteractionRecord.isDummy()) { + return 0; // nothing was decoded + } + mTimerFetchData.Start(false); + int ref = digits.size(); + while (!mOrderedChipsPtr.empty()) { + const auto& chipData = *mOrderedChipsPtr.back(); + assert(mLastReadChipID < chipData.getChipID()); + mLastReadChipID = chipData.getChipID(); + for (const auto& hit : chipData.getData()) { + digits.emplace_back(mLastReadChipID, hit.getRow(), hit.getCol()); + } + mOrderedChipsPtr.pop_back(); + } + int nFilled = digits.size() - ref; + rofs.emplace_back(mInteractionRecord, mROFCounter, ref, nFilled); + mTimerFetchData.Stop(); + return nFilled; +} + +///______________________________________________________________ +/// Fill decoded digits to global vector +template <class Mapping> +template <class CalibContainer> +void RawPixelDecoder<Mapping>::fillCalibData(CalibContainer& calib) +{ + if (!mInteractionRecord.isDummy()) { + auto curSize = calib.size(); + calib.resize(curSize + Mapping::getNRUs()); + for (unsigned int iru = 0; iru < mRUDecodeVec.size(); iru++) { + calib[curSize + mRUDecodeVec[iru].ruSWID] = mRUDecodeVec[iru].calibData; + } + } +} + using RawDecoderITS = RawPixelDecoder<ChipMappingITS>; using RawDecoderMFT = RawPixelDecoder<ChipMappingMFT>; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index baca178dfd0f6..02e1bc0507b5c 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -85,7 +86,7 @@ struct RawDecodingStat { errorCounts.fill(0); } - void print(bool skipEmpty = true) const + void print(bool skipNoErr = true) const { printf("\nDecoding statistics\n"); printf("%llu bytes for %llu RUs processed in %llu pages for %llu triggers\n", (ULL)nBytesProcessed, (ULL)nRUsProcessed, @@ -97,7 +98,7 @@ struct RawDecodingStat { } printf("Decoding errors: %d\n", nErr); for (int i = 0; i < NErrorsDefined; i++) { - if (!skipEmpty || errorCounts[i]) { + if (!skipNoErr || errorCounts[i]) { printf("%-70s: %d\n", ErrNames[i].data(), errorCounts[i]); } } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/TopologyFastSimulation.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/TopologyFastSimulation.h index 6c0303b707e39..618a4c5b2024a 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/TopologyFastSimulation.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/TopologyFastSimulation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx index 8008767b69d08..f557e1141fd2f 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,8 +13,6 @@ /// \brief Implementation of the ALPIDE data decoding/encoding #include "ITSMFTReconstruction/AlpideCoder.h" -#include <TClass.h> -#include <TFile.h> using namespace o2::itsmft; @@ -146,10 +145,3 @@ void AlpideCoder::resetMap() mFirstInRow.clear(); mPix2Encode.clear(); } - -//_____________________________________ -int AlpideCoder::unexpectedEOF(const std::string& message) -{ - LOG(ERROR) << message; - return Error; -} diff --git a/Detectors/ITSMFT/common/reconstruction/src/BuildTopologyDictionary.cxx b/Detectors/ITSMFT/common/reconstruction/src/BuildTopologyDictionary.cxx index 0e553517db7de..8d810256e3baa 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/BuildTopologyDictionary.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/BuildTopologyDictionary.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/src/CTFCoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/CTFCoder.cxx index c06dc9c60f555..f5a09d31e2787 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/CTFCoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,12 +28,13 @@ void CTFCoder::appendToTree(TTree& tree, CTF& ec) ///___________________________________________________________________________________ // extract and decode data from the tree -void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofRecVec, std::vector<CompClusterExt>& cclusVec, std::vector<unsigned char>& pattVec) +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofRecVec, + std::vector<CompClusterExt>& cclusVec, std::vector<unsigned char>& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup) { assert(entry >= 0 && entry < tree.GetEntries()); CTF ec; ec.readFromTree(tree, mDet.getName(), entry); - decode(ec, rofRecVec, cclusVec, pattVec); + decode(ec, rofRecVec, cclusVec, pattVec, noiseMap, clPattLookup); } ///________________________________ @@ -75,9 +77,19 @@ void CTFCoder::compress(CompressedClusters& cc, const auto& intRec = rofRec.getBCData(); if (intRec.orbit == prevOrbit) { cc.orbitIncROF[irof] = 0; +#ifdef _CHECK_INCREMENTES_ + if (intRec.bc < prevBC) { + LOG(WARNING) << "Negative BC increment " << intRec.bc << " -> " << prevBC; + } +#endif cc.bcIncROF[irof] = intRec.bc - prevBC; // store increment of BC if in the same orbit } else { cc.orbitIncROF[irof] = intRec.orbit - prevOrbit; +#ifdef _CHECK_INCREMENTES_ + if (intRec.orbit < prevOrbit) { + LOG(WARNING) << "Negative Orbit increment " << intRec.orbit << " -> " << prevOrbit; + } +#endif cc.bcIncROF[irof] = intRec.bc; // otherwise, store absolute bc prevOrbit = intRec.orbit; } @@ -92,7 +104,7 @@ void CTFCoder::compress(CompressedClusters& cc, int icl = rofRec.getFirstEntry(), iclMax = icl + ncl; uint16_t prevChip = cc.firstChipROF[irof], prevCol = 0; - if (icl != iclMax) { // there still clusters to store + if (icl != iclMax) { // there are still clusters to store cc.chipMul.push_back(0); cc.chipInc.push_back(0); } @@ -103,11 +115,21 @@ void CTFCoder::compress(CompressedClusters& cc, if (cl.getChipID() == prevChip) { // for the same chip store column increment // cc.chipInc[icl] = 0; // this is the version with chipInc stored for every pixel cc.chipMul.back()++; // this is the version with chipInc stored once per new chip +#ifdef _CHECK_INCREMENTES_ // RS FIXME with current clusterization column increment can be slightly negative +// if (cl.getCol() < prevCol) { +// LOG(WARNING) << "Negative Column increment " << cl.getCol() << " -> " << prevCol << " in chip " << prevChip << " of ROF " << irof; +// } +#endif cc.colInc[icl] = cl.getCol() - prevCol; prevCol = cl.getCol(); } else { // for new chips store chipID increment and abs. column // cc.chipInc[icl] = cl.getChipID() - prevChip; // this is the version with chipInc stored for every pixel cc.chipInc.push_back(cl.getChipID() - prevChip); // this is the version with chipInc stored once per new chip +#ifdef _CHECK_INCREMENTES_ + if (cl.getChipID() < prevChip) { + LOG(WARNING) << "Negative Chip increment " << cl.getChipID() << " -> " << prevChip; + } +#endif cc.chipMul.push_back(1); // this is the version with chipInc stored once per new chip prevCol = cc.colInc[icl] = cl.getCol(); prevChip = cl.getChipID(); @@ -182,7 +204,31 @@ size_t CTFCoder::estimateCompressedSize(const CompressedClusters& cc) sz += ESTSIZE(cc.pattMap, CTF::BLCpattMap ); // clang-format on - + sz *= 2. / 3; // if needed, will be autoexpanded LOG(INFO) << "Estimated output size is " << sz << " bytes"; return sz; } + +///________________________________ +CompressedClusters CTFCoder::decodeCompressedClusters(const CTF::base& ec) +{ + CompressedClusters cc; + cc.header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cc.header)); + ec.print(getPrefix()); +#define DECODEITSMFT(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODEITSMFT(cc.firstChipROF, CTF::BLCfirstChipROF); + DECODEITSMFT(cc.bcIncROF, CTF::BLCbcIncROF); + DECODEITSMFT(cc.orbitIncROF, CTF::BLCorbitIncROF); + DECODEITSMFT(cc.nclusROF, CTF::BLCnclusROF); + // + DECODEITSMFT(cc.chipInc, CTF::BLCchipInc); + DECODEITSMFT(cc.chipMul, CTF::BLCchipMul); + DECODEITSMFT(cc.row, CTF::BLCrow); + DECODEITSMFT(cc.colInc, CTF::BLCcolInc); + DECODEITSMFT(cc.pattID, CTF::BLCpattID); + DECODEITSMFT(cc.pattMap, CTF::BLCpattMap); + // clang-format on + return cc; +} \ No newline at end of file diff --git a/Detectors/ITSMFT/common/reconstruction/src/ChipMappingITS.cxx b/Detectors/ITSMFT/common/reconstruction/src/ChipMappingITS.cxx index 4e78c426392ff..73aafefe0a239 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/ChipMappingITS.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/ChipMappingITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,32 +39,27 @@ constexpr std::array<uint8_t, ChipMappingITS::NSubB> ChipMappingITS::GBTHeaderFl constexpr std::uint8_t ChipMappingITS::ChipOBModSW2HW[14]; constexpr std::uint8_t ChipMappingITS::ChipOBModHW2SW[15]; -//______________________________________________ ChipMappingITS::ChipMappingITS() { - // init chips info - - /* - FEE ID field in RDH is 16-bit wide - Each RU has 10-bit DIPSWITCH, use bits 9:2 as an 8bit ID field to be mapped to FEE ID field in RDH - - | Lr |Stave Count| Bin. pref | Range of Binary Addresses - | |= RU Count | Stave addr| - |---------------------------------------------------------- - | L0 | 12 |b 0000xxxx | 0000_0000 : 0000_1011 (0 – 11) - | L1 | 16 |b 0001xxxx | 0001_0000 : 0001_1111 (0 – 15) - | L2 | 20 |b 001xxxxx | 001_00000 : 001_10011 (0 – 19) - | L3 | 24 |b 010xxxxx | 010_00000 : 010_10111 (0 – 23) - | L4 | 30 |b 011xxxxx | 011_00000 : 011_11101 (0 – 29) - | L5 | 42 |b 10xxxxxx | 10_000000 : 10_101001 (0 – 41) - | L6 | 48 |b 11xxxxxx | 11_000000 : 11_101111 (0 – 47) - - FEEId format: - 15|14 12|11 10 |9 8|7 6|5 0| - 0| Layer | Reserve | Fiber | 00 | StaveNumber | - - */ + // FEE ID field in RDH is 16-bit wide + // Each RU has 10-bit DIPSWITCH, use bits 9:2 as an 8bit ID field to be mapped to FEE ID field in RDH + + // | Lr |Stave Count| Bin. pref | Range of Binary Addresses + // | |= RU Count | Stave addr| + // |---------------------------------------------------------- + // | L0 | 12 |b 0000xxxx | 0000_0000 : 0000_1011 (0 – 11) + // | L1 | 16 |b 0001xxxx | 0001_0000 : 0001_1111 (0 – 15) + // | L2 | 20 |b 001xxxxx | 001_00000 : 001_10011 (0 – 19) + // | L3 | 24 |b 010xxxxx | 010_00000 : 010_10111 (0 – 23) + // | L4 | 30 |b 011xxxxx | 011_00000 : 011_11101 (0 – 29) + // | L5 | 42 |b 10xxxxxx | 10_000000 : 10_101001 (0 – 41) + // | L6 | 48 |b 11xxxxxx | 11_000000 : 11_101111 (0 – 47) + + // FEEId format: + // 15|14 12|11 10 |9 8|7 6|5 0| + // 0| Layer | Reserve | Fiber | 00 | StaveNumber | + // init chips info uint32_t maxRUHW = composeFEEId(NLayers - 1, NStavesOnLr[NLayers - 1], NLinks - 1); // Max possible FEE ID assert(maxRUHW < 0xffff); mFEEId2RUSW.resize(maxRUHW + 1, 0xff); @@ -71,6 +67,7 @@ ChipMappingITS::ChipMappingITS() // IB: single cable per chip int ctrChip = 0; mChipInfoEntrySB[IB] = ctrChip; + mCablePos[IB].resize(NChipsPerStaveSB[IB], 0xff); mCableHW2SW[IB].resize(NChipsPerStaveSB[IB], 0xff); mCableHW2Pos[IB].resize(NChipsPerStaveSB[IB], 0xff); mCableHWFirstChip[IB].resize(NChipsPerStaveSB[IB], 0xff); @@ -92,15 +89,15 @@ ChipMappingITS::ChipMappingITS() } // [i][j] gives lane id for lowest(i=0) and highest(i=1) 7 chips of HW module (j+1) (1-4 for ML, 1-7 for OL) - const int LANEID[2][7] = {{6, 5, 4, 3, 2, 1, 0}, {0, 1, 2, 3, 4, 5, 6}}; + const int LANEID[2][7] = {{0, 1, 2, 3, 4, 5, 6}, {6, 5, 4, 3, 2, 1, 0}}; const int maxModulesPerStave = NModulesPerStaveSB[OB]; const int chipsOnCable = 7; for (int bid = MB; bid <= OB; bid++) { // MB and OB staves have similar layout mChipInfoEntrySB[bid] = ctrChip; - mCableHW2SW[bid].resize(0xff, 0xff); - mCableHW2Pos[bid].resize(0xff, 0xff); - mCableHWFirstChip[bid].resize(0xff, 0xff); - + mCablePos[bid].resize(NChipsPerStaveSB[bid], 0xff); + mCableHW2SW[bid].resize(NChipsPerStaveSB[bid], 0xff); + mCableHW2Pos[bid].resize(NChipsPerStaveSB[bid], 0xff); + mCableHWFirstChip[bid].resize(NChipsPerStaveSB[bid], 0xff); for (int i = 0; i < NChipsPerStaveSB[bid]; i++) { auto& cInfo = mChipsInfo[ctrChip++]; int hstave = i / (NChipsPerStaveSB[bid] / 2); @@ -111,12 +108,12 @@ ChipMappingITS::ChipMappingITS() cInfo.chipOnModuleSW = i % NChipsPerModuleSB[bid]; cInfo.chipOnModuleHW = ChipOBModSW2HW[cInfo.chipOnModuleSW]; - bool upper7 = cInfo.chipOnModuleSW >= (NChipsPerModuleSB[bid] / 2); + bool lower7 = cInfo.chipOnModuleSW < (NChipsPerModuleSB[bid] / 2); - uint8_t connector = 2 * hstave + upper7; - cInfo.cableHW = (connector << 3) + LANEID[upper7][cInfo.moduleHW - 1]; + uint8_t connector = 2 * hstave + lower7, connectorInv = 2 * hstave + (!lower7); + cInfo.cableHW = (connector << 3) + LANEID[!lower7][cInfo.moduleHW - 1]; cInfo.cableSW = i / chipsOnCable; - cInfo.cableHWPos = LANEID[upper7][cInfo.moduleHW - 1] + connector * maxModulesPerStave / 2; + cInfo.cableHWPos = LANEID[lower7][cInfo.moduleHW - 1] + connectorInv * maxModulesPerStave / 2; mCablesOnStaveSB[bid] |= 0x1 << cInfo.cableHWPos; // account in lanes pattern cInfo.chipOnCable = cInfo.chipOnModuleSW % (NChipsPerModuleSB[bid] / 2); // each cable serves half module mCableHW2SW[bid][cInfo.cableHW] = cInfo.cableSW; @@ -126,6 +123,17 @@ ChipMappingITS::ChipMappingITS() } } } + for (int bid = 0; bid < NSubB; bid++) { + int pos = 0; + for (int ic = 0; ic < 32; ic++) { + if (mCablesOnStaveSB[bid] & (0x1 << ic)) { + mCablePos[bid][pos++] = ic; + } + } + if (pos != NCablesPerStaveSB[bid]) { + throw std::runtime_error(fmt::format("counted number of cables {} does not match expected {} on subBarel{}", pos, NCablesPerStaveSB[bid], bid)); + } + } int ctrStv = 0; uint16_t chipCount = 0; @@ -154,17 +162,14 @@ ChipMappingITS::ChipMappingITS() void ChipMappingITS::print() const { int ctrChip = 0; - printf("\n\nSubBarrel IB\n"); - for (int i = 0; i < NChipsPerStaveSB[IB]; i++) { - mChipsInfo[ctrChip++].print(); - } - printf("\n\nSubBarrel MB\n"); - for (int i = 0; i < NChipsPerStaveSB[MB]; i++) { - mChipsInfo[ctrChip++].print(); - } - printf("\n\nSubBarrel OB\n"); - for (int i = 0; i < NChipsPerStaveSB[OB]; i++) { - mChipsInfo[ctrChip++].print(); + const std::string bnames[3] = {"IB", "MB", "OB"}; + const int lrpr[3] = {0, 3, 5}; + for (int ib = 0; ib < NSubB; ib++) { + printf("\n\nSubBarrel %s\nCablesPattern %s\n", bnames[ib].c_str(), std::bitset<32>(mCablesOnStaveSB[ib]).to_string().c_str()); + const auto ruInfo = getRUInfoSW(getFirstStavesOnLr(lrpr[ib])); + for (int i = 0; i < NChipsPerStaveSB[ib]; i++) { + printf("%s | %s\n", mChipsInfo[ctrChip++].asString().c_str(), getChipNameHW(i + ruInfo->firstChipIDSW).c_str()); + } } } diff --git a/Detectors/ITSMFT/common/reconstruction/src/ChipMappingMFT.cxx b/Detectors/ITSMFT/common/reconstruction/src/ChipMappingMFT.cxx index 5f777fc8c3faf..90a862996a490 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/ChipMappingMFT.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/ChipMappingMFT.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,1224 +18,1224 @@ using namespace o2::itsmft; const std::array<MFTChipMappingData, ChipMappingMFT::NChips> ChipMappingMFT::ChipMappingData{{ - // { module, chipOnModule, cable, chipOnRU } - - // chip: 0 (2), ladder: 0 ( 0), layer: 0, disk: 0, half: 0, zone: 0 - {0, 0, 5, 0}, - {0, 1, 6, 1}, - // chip: 2 (2), ladder: 1 (10), layer: 0, disk: 0, half: 0, zone: 3 - {1, 0, 0, 0}, - {1, 1, 1, 1}, - // chip: 4 (2), ladder: 2 (11), layer: 0, disk: 0, half: 0, zone: 3 - {2, 0, 17, 2}, - {2, 1, 16, 3}, - // chip: 6 (2), ladder: 3 (12), layer: 1, disk: 0, half: 0, zone: 3 - {3, 0, 17, 2}, - {3, 1, 16, 3}, - // chip: 8 (2), ladder: 4 (13), layer: 1, disk: 0, half: 0, zone: 3 - {4, 0, 0, 0}, - {4, 1, 1, 1}, - // chip: 10 (2), ladder: 5 (23), layer: 1, disk: 0, half: 0, zone: 0 - {5, 0, 5, 0}, - {5, 1, 6, 1}, - // chip: 12 (3), ladder: 6 ( 1), layer: 0, disk: 0, half: 0, zone: 0 - {6, 0, 0, 2}, - {6, 1, 1, 3}, - {6, 2, 2, 4}, - // chip: 15 (3), ladder: 7 ( 2), layer: 0, disk: 0, half: 0, zone: 0 - {7, 0, 17, 5}, - {7, 1, 16, 6}, - {7, 2, 15, 7}, - // chip: 18 (3), ladder: 8 ( 3), layer: 0, disk: 0, half: 0, zone: 1 - {8, 0, 5, 0}, - {8, 1, 6, 1}, - {8, 2, 7, 2}, - // chip: 21 (3), ladder: 9 ( 4), layer: 0, disk: 0, half: 0, zone: 1 - {9, 0, 0, 3}, - {9, 1, 1, 4}, - {9, 2, 2, 5}, - // chip: 24 (3), ladder: 10 ( 5), layer: 0, disk: 0, half: 0, zone: 1 - {10, 0, 17, 6}, - {10, 1, 16, 7}, - {10, 2, 15, 8}, - // chip: 27 (3), ladder: 11 ( 6), layer: 0, disk: 0, half: 0, zone: 2 - {11, 0, 5, 0}, - {11, 1, 6, 1}, - {11, 2, 7, 2}, - // chip: 30 (3), ladder: 12 ( 7), layer: 0, disk: 0, half: 0, zone: 2 - {12, 0, 0, 3}, - {12, 1, 1, 4}, - {12, 2, 2, 5}, - // chip: 33 (3), ladder: 13 ( 8), layer: 0, disk: 0, half: 0, zone: 2 - {13, 0, 17, 6}, - {13, 1, 16, 7}, - {13, 2, 15, 8}, - // chip: 36 (3), ladder: 14 ( 9), layer: 0, disk: 0, half: 0, zone: 3 - {14, 0, 5, 4}, - {14, 1, 6, 5}, - {14, 2, 7, 6}, - // chip: 39 (3), ladder: 15 (14), layer: 1, disk: 0, half: 0, zone: 3 - {15, 0, 5, 4}, - {15, 1, 6, 5}, - {15, 2, 7, 6}, - // chip: 42 (3), ladder: 16 (15), layer: 1, disk: 0, half: 0, zone: 2 - {16, 0, 17, 6}, - {16, 1, 16, 7}, - {16, 2, 15, 8}, - // chip: 45 (3), ladder: 17 (16), layer: 1, disk: 0, half: 0, zone: 2 - {17, 0, 0, 3}, - {17, 1, 1, 4}, - {17, 2, 2, 5}, - // chip: 48 (3), ladder: 18 (17), layer: 1, disk: 0, half: 0, zone: 2 - {18, 0, 5, 0}, - {18, 1, 6, 1}, - {18, 2, 7, 2}, - // chip: 51 (3), ladder: 19 (18), layer: 1, disk: 0, half: 0, zone: 1 - {19, 0, 17, 6}, - {19, 1, 16, 7}, - {19, 2, 15, 8}, - // chip: 54 (3), ladder: 20 (19), layer: 1, disk: 0, half: 0, zone: 1 - {20, 0, 0, 3}, - {20, 1, 1, 4}, - {20, 2, 2, 5}, - // chip: 57 (3), ladder: 21 (20), layer: 1, disk: 0, half: 0, zone: 1 - {21, 0, 5, 0}, - {21, 1, 6, 1}, - {21, 2, 7, 2}, - // chip: 60 (3), ladder: 22 (21), layer: 1, disk: 0, half: 0, zone: 0 - {22, 0, 17, 5}, - {22, 1, 16, 6}, - {22, 2, 15, 7}, - // chip: 63 (3), ladder: 23 (22), layer: 1, disk: 0, half: 0, zone: 0 - {23, 0, 0, 2}, - {23, 1, 1, 3}, - {23, 2, 2, 4}, - // chip: 66 (2), ladder: 0 ( 0), layer: 2, disk: 1, half: 0, zone: 0 - {24, 0, 5, 0}, - {24, 1, 6, 1}, - // chip: 68 (2), ladder: 1 (10), layer: 2, disk: 1, half: 0, zone: 3 - {25, 0, 0, 0}, - {25, 1, 1, 1}, - // chip: 70 (2), ladder: 2 (11), layer: 2, disk: 1, half: 0, zone: 3 - {26, 0, 17, 2}, - {26, 1, 16, 3}, - // chip: 72 (2), ladder: 3 (12), layer: 3, disk: 1, half: 0, zone: 3 - {27, 0, 17, 2}, - {27, 1, 16, 3}, - // chip: 74 (2), ladder: 4 (13), layer: 3, disk: 1, half: 0, zone: 3 - {28, 0, 0, 0}, - {28, 1, 1, 1}, - // chip: 76 (2), ladder: 5 (23), layer: 3, disk: 1, half: 0, zone: 0 - {29, 0, 5, 0}, - {29, 1, 6, 1}, - // chip: 78 (3), ladder: 6 ( 1), layer: 2, disk: 1, half: 0, zone: 0 - {30, 0, 0, 2}, - {30, 1, 1, 3}, - {30, 2, 2, 4}, - // chip: 81 (3), ladder: 7 ( 2), layer: 2, disk: 1, half: 0, zone: 0 - {31, 0, 17, 5}, - {31, 1, 16, 6}, - {31, 2, 15, 7}, - // chip: 84 (3), ladder: 8 ( 3), layer: 2, disk: 1, half: 0, zone: 1 - {32, 0, 5, 0}, - {32, 1, 6, 1}, - {32, 2, 7, 2}, - // chip: 87 (3), ladder: 9 ( 4), layer: 2, disk: 1, half: 0, zone: 1 - {33, 0, 0, 3}, - {33, 1, 1, 4}, - {33, 2, 2, 5}, - // chip: 90 (3), ladder: 10 ( 5), layer: 2, disk: 1, half: 0, zone: 1 - {34, 0, 17, 6}, - {34, 1, 16, 7}, - {34, 2, 15, 8}, - // chip: 93 (3), ladder: 11 ( 6), layer: 2, disk: 1, half: 0, zone: 2 - {35, 0, 5, 0}, - {35, 1, 6, 1}, - {35, 2, 7, 2}, - // chip: 96 (3), ladder: 12 ( 7), layer: 2, disk: 1, half: 0, zone: 2 - {36, 0, 0, 3}, - {36, 1, 1, 4}, - {36, 2, 2, 5}, - // chip: 99 (3), ladder: 13 ( 8), layer: 2, disk: 1, half: 0, zone: 2 - {37, 0, 17, 6}, - {37, 1, 16, 7}, - {37, 2, 15, 8}, - // chip: 102 (3), ladder: 14 ( 9), layer: 2, disk: 1, half: 0, zone: 3 - {38, 0, 5, 4}, - {38, 1, 6, 5}, - {38, 2, 7, 6}, - // chip: 105 (3), ladder: 15 (14), layer: 3, disk: 1, half: 0, zone: 3 - {39, 0, 5, 4}, - {39, 1, 6, 5}, - {39, 2, 7, 6}, - // chip: 108 (3), ladder: 16 (15), layer: 3, disk: 1, half: 0, zone: 2 - {40, 0, 17, 6}, - {40, 1, 16, 7}, - {40, 2, 15, 8}, - // chip: 111 (3), ladder: 17 (16), layer: 3, disk: 1, half: 0, zone: 2 - {41, 0, 0, 3}, - {41, 1, 1, 4}, - {41, 2, 2, 5}, - // chip: 114 (3), ladder: 18 (17), layer: 3, disk: 1, half: 0, zone: 2 - {42, 0, 5, 0}, - {42, 1, 6, 1}, - {42, 2, 7, 2}, - // chip: 117 (3), ladder: 19 (18), layer: 3, disk: 1, half: 0, zone: 1 - {43, 0, 17, 6}, - {43, 1, 16, 7}, - {43, 2, 15, 8}, - // chip: 120 (3), ladder: 20 (19), layer: 3, disk: 1, half: 0, zone: 1 - {44, 0, 0, 3}, - {44, 1, 1, 4}, - {44, 2, 2, 5}, - // chip: 123 (3), ladder: 21 (20), layer: 3, disk: 1, half: 0, zone: 1 - {45, 0, 5, 0}, - {45, 1, 6, 1}, - {45, 2, 7, 2}, - // chip: 126 (3), ladder: 22 (21), layer: 3, disk: 1, half: 0, zone: 0 - {46, 0, 17, 5}, - {46, 1, 16, 6}, - {46, 2, 15, 7}, - // chip: 129 (3), ladder: 23 (22), layer: 3, disk: 1, half: 0, zone: 0 - {47, 0, 0, 2}, - {47, 1, 1, 3}, - {47, 2, 2, 4}, - // chip: 132 (2), ladder: 0 ( 0), layer: 4, disk: 2, half: 0, zone: 0 - {48, 0, 5, 0}, - {48, 1, 6, 1}, - // chip: 134 (2), ladder: 1 (12), layer: 4, disk: 2, half: 0, zone: 3 - {49, 0, 22, 0}, - {49, 1, 21, 1}, - // chip: 136 (2), ladder: 2 (13), layer: 5, disk: 2, half: 0, zone: 3 - {50, 0, 22, 0}, - {50, 1, 21, 1}, - // chip: 138 (2), ladder: 3 (25), layer: 5, disk: 2, half: 0, zone: 0 - {51, 0, 5, 0}, - {51, 1, 6, 1}, - // chip: 140 (3), ladder: 4 ( 1), layer: 4, disk: 2, half: 0, zone: 0 - {52, 0, 0, 2}, - {52, 1, 1, 3}, - {52, 2, 2, 4}, - // chip: 143 (3), ladder: 5 ( 2), layer: 4, disk: 2, half: 0, zone: 0 - {53, 0, 17, 5}, - {53, 1, 16, 6}, - {53, 2, 15, 7}, - // chip: 146 (3), ladder: 6 ( 5), layer: 4, disk: 2, half: 0, zone: 1 - {54, 0, 17, 0}, - {54, 1, 16, 1}, - {54, 2, 15, 2}, - // chip: 149 (3), ladder: 7 ( 6), layer: 4, disk: 2, half: 0, zone: 2 - {55, 0, 5, 0}, - {55, 1, 6, 1}, - {55, 2, 7, 2}, - // chip: 152 (3), ladder: 8 ( 7), layer: 4, disk: 2, half: 0, zone: 2 - {56, 0, 0, 3}, - {56, 1, 1, 4}, - {56, 2, 2, 5}, - // chip: 155 (3), ladder: 9 (10), layer: 4, disk: 2, half: 0, zone: 3 - {57, 0, 0, 2}, - {57, 1, 1, 3}, - {57, 2, 2, 4}, - // chip: 158 (3), ladder: 10 (11), layer: 4, disk: 2, half: 0, zone: 3 - {58, 0, 17, 5}, - {58, 1, 16, 6}, - {58, 2, 15, 7}, - // chip: 161 (3), ladder: 11 (14), layer: 5, disk: 2, half: 0, zone: 3 - {59, 0, 17, 5}, - {59, 1, 16, 6}, - {59, 2, 15, 7}, - // chip: 164 (3), ladder: 12 (15), layer: 5, disk: 2, half: 0, zone: 3 - {60, 0, 0, 2}, - {60, 1, 1, 3}, - {60, 2, 2, 4}, - // chip: 167 (3), ladder: 13 (18), layer: 5, disk: 2, half: 0, zone: 2 - {61, 0, 0, 3}, - {61, 1, 1, 4}, - {61, 2, 2, 5}, - // chip: 170 (3), ladder: 14 (19), layer: 5, disk: 2, half: 0, zone: 2 - {62, 0, 5, 0}, - {62, 1, 6, 1}, - {62, 2, 7, 2}, - // chip: 173 (3), ladder: 15 (20), layer: 5, disk: 2, half: 0, zone: 1 - {63, 0, 17, 0}, - {63, 1, 16, 1}, - {63, 2, 15, 2}, - // chip: 176 (3), ladder: 16 (23), layer: 5, disk: 2, half: 0, zone: 0 - {64, 0, 17, 5}, - {64, 1, 16, 6}, - {64, 2, 15, 7}, - // chip: 179 (3), ladder: 17 (24), layer: 5, disk: 2, half: 0, zone: 0 - {65, 0, 0, 2}, - {65, 1, 1, 3}, - {65, 2, 2, 4}, - // chip: 182 (4), ladder: 18 ( 3), layer: 4, disk: 2, half: 0, zone: 1 - {66, 0, 5, 3}, - {66, 1, 6, 4}, - {66, 2, 7, 5}, - {66, 3, 24, 6}, - // chip: 186 (4), ladder: 19 ( 4), layer: 4, disk: 2, half: 0, zone: 1 - {67, 0, 0, 7}, - {67, 1, 1, 8}, - {67, 2, 2, 9}, - {67, 3, 3, 10}, - // chip: 190 (4), ladder: 20 ( 8), layer: 4, disk: 2, half: 0, zone: 2 - {68, 0, 17, 6}, - {68, 1, 16, 7}, - {68, 2, 15, 8}, - {68, 3, 14, 9}, - // chip: 194 (4), ladder: 21 ( 9), layer: 4, disk: 2, half: 0, zone: 3 - {69, 0, 5, 8}, - {69, 1, 6, 9}, - {69, 2, 7, 10}, - {69, 3, 24, 11}, - // chip: 198 (4), ladder: 22 (16), layer: 5, disk: 2, half: 0, zone: 3 - {70, 0, 5, 8}, - {70, 1, 6, 9}, - {70, 2, 7, 10}, - {70, 3, 24, 11}, - // chip: 202 (4), ladder: 23 (17), layer: 5, disk: 2, half: 0, zone: 2 - {71, 0, 17, 6}, - {71, 1, 16, 7}, - {71, 2, 15, 8}, - {71, 3, 14, 9}, - // chip: 206 (4), ladder: 24 (21), layer: 5, disk: 2, half: 0, zone: 1 - {72, 0, 0, 7}, - {72, 1, 1, 8}, - {72, 2, 2, 9}, - {72, 3, 3, 10}, - // chip: 210 (4), ladder: 25 (22), layer: 5, disk: 2, half: 0, zone: 1 - {73, 0, 5, 3}, - {73, 1, 6, 4}, - {73, 2, 7, 5}, - {73, 3, 24, 6}, - // chip: 214 (3), ladder: 0 ( 0), layer: 6, disk: 3, half: 0, zone: 0 - {74, 0, 5, 0}, - {74, 1, 6, 1}, - {74, 2, 7, 2}, - // chip: 217 (3), ladder: 1 ( 1), layer: 6, disk: 3, half: 0, zone: 0 - {75, 0, 0, 3}, - {75, 1, 1, 4}, - {75, 2, 2, 5}, - // chip: 220 (3), ladder: 2 (13), layer: 6, disk: 3, half: 0, zone: 3 - {76, 0, 0, 0}, - {76, 1, 1, 1}, - {76, 2, 2, 2}, - // chip: 223 (3), ladder: 3 (14), layer: 6, disk: 3, half: 0, zone: 3 - {77, 0, 17, 3}, - {77, 1, 16, 4}, - {77, 2, 15, 5}, - // chip: 226 (3), ladder: 4 (15), layer: 6, disk: 3, half: 0, zone: 3 - {78, 0, 22, 6}, - {78, 1, 21, 7}, - {78, 2, 20, 8}, - // chip: 229 (3), ladder: 5 (16), layer: 7, disk: 3, half: 0, zone: 3 - {79, 0, 22, 6}, - {79, 1, 21, 7}, - {79, 2, 20, 8}, - // chip: 232 (3), ladder: 6 (17), layer: 7, disk: 3, half: 0, zone: 3 - {80, 0, 17, 3}, - {80, 1, 16, 4}, - {80, 2, 15, 5}, - // chip: 235 (3), ladder: 7 (18), layer: 7, disk: 3, half: 0, zone: 3 - {81, 0, 0, 0}, - {81, 1, 1, 1}, - {81, 2, 2, 2}, - // chip: 238 (3), ladder: 8 (30), layer: 7, disk: 3, half: 0, zone: 0 - {82, 0, 0, 3}, - {82, 1, 1, 4}, - {82, 2, 2, 5}, - // chip: 241 (3), ladder: 9 (31), layer: 7, disk: 3, half: 0, zone: 0 - {83, 0, 5, 0}, - {83, 1, 6, 1}, - {83, 2, 7, 2}, - // chip: 244 (4), ladder: 10 ( 2), layer: 6, disk: 3, half: 0, zone: 0 - {84, 0, 17, 6}, - {84, 1, 16, 7}, - {84, 2, 15, 8}, - {84, 3, 14, 9}, - // chip: 248 (4), ladder: 11 ( 3), layer: 6, disk: 3, half: 0, zone: 0 - {85, 0, 22, 10}, - {85, 1, 21, 11}, - {85, 2, 20, 12}, - {85, 3, 19, 13}, - // chip: 252 (4), ladder: 12 ( 4), layer: 6, disk: 3, half: 0, zone: 1 - {86, 0, 5, 0}, - {86, 1, 6, 1}, - {86, 2, 7, 2}, - {86, 3, 24, 3}, - // chip: 256 (4), ladder: 13 ( 5), layer: 6, disk: 3, half: 0, zone: 1 - {87, 0, 0, 4}, - {87, 1, 1, 5}, - {87, 2, 2, 6}, - {87, 3, 3, 7}, - // chip: 260 (4), ladder: 14 ( 6), layer: 6, disk: 3, half: 0, zone: 1 - {88, 0, 17, 8}, - {88, 1, 16, 9}, - {88, 2, 15, 10}, - {88, 3, 14, 11}, - // chip: 264 (4), ladder: 15 ( 7), layer: 6, disk: 3, half: 0, zone: 1 - {89, 0, 22, 12}, - {89, 1, 21, 13}, - {89, 2, 20, 14}, - {89, 3, 19, 15}, - // chip: 268 (4), ladder: 16 ( 8), layer: 6, disk: 3, half: 0, zone: 2 - {90, 0, 5, 0}, - {90, 1, 6, 1}, - {90, 2, 7, 2}, - {90, 3, 24, 3}, - // chip: 272 (4), ladder: 17 ( 9), layer: 6, disk: 3, half: 0, zone: 2 - {91, 0, 0, 4}, - {91, 1, 1, 5}, - {91, 2, 2, 6}, - {91, 3, 3, 7}, - // chip: 276 (4), ladder: 18 (10), layer: 6, disk: 3, half: 0, zone: 2 - {92, 0, 17, 8}, - {92, 1, 16, 9}, - {92, 2, 15, 10}, - {92, 3, 14, 11}, - // chip: 280 (4), ladder: 19 (11), layer: 6, disk: 3, half: 0, zone: 2 - {93, 0, 22, 12}, - {93, 1, 21, 13}, - {93, 2, 20, 14}, - {93, 3, 19, 15}, - // chip: 284 (4), ladder: 20 (12), layer: 6, disk: 3, half: 0, zone: 3 - {94, 0, 5, 9}, - {94, 1, 6, 10}, - {94, 2, 7, 11}, - {94, 3, 24, 12}, - // chip: 288 (4), ladder: 21 (19), layer: 7, disk: 3, half: 0, zone: 3 - {95, 0, 5, 9}, - {95, 1, 6, 10}, - {95, 2, 7, 11}, - {95, 3, 24, 12}, - // chip: 292 (4), ladder: 22 (20), layer: 7, disk: 3, half: 0, zone: 2 - {96, 0, 22, 12}, - {96, 1, 21, 13}, - {96, 2, 20, 14}, - {96, 3, 19, 15}, - // chip: 296 (4), ladder: 23 (21), layer: 7, disk: 3, half: 0, zone: 2 - {97, 0, 17, 8}, - {97, 1, 16, 9}, - {97, 2, 15, 10}, - {97, 3, 14, 11}, - // chip: 300 (4), ladder: 24 (22), layer: 7, disk: 3, half: 0, zone: 2 - {98, 0, 0, 4}, - {98, 1, 1, 5}, - {98, 2, 2, 6}, - {98, 3, 3, 7}, - // chip: 304 (4), ladder: 25 (23), layer: 7, disk: 3, half: 0, zone: 2 - {99, 0, 5, 0}, - {99, 1, 6, 1}, - {99, 2, 7, 2}, - {99, 3, 24, 3}, - // chip: 308 (4), ladder: 26 (24), layer: 7, disk: 3, half: 0, zone: 1 - {100, 0, 22, 12}, - {100, 1, 21, 13}, - {100, 2, 20, 14}, - {100, 3, 19, 15}, - // chip: 312 (4), ladder: 27 (25), layer: 7, disk: 3, half: 0, zone: 1 - {101, 0, 17, 8}, - {101, 1, 16, 9}, - {101, 2, 15, 10}, - {101, 3, 14, 11}, - // chip: 316 (4), ladder: 28 (26), layer: 7, disk: 3, half: 0, zone: 1 - {102, 0, 0, 4}, - {102, 1, 1, 5}, - {102, 2, 2, 6}, - {102, 3, 3, 7}, - // chip: 320 (4), ladder: 29 (27), layer: 7, disk: 3, half: 0, zone: 1 - {103, 0, 5, 0}, - {103, 1, 6, 1}, - {103, 2, 7, 2}, - {103, 3, 24, 3}, - // chip: 324 (4), ladder: 30 (28), layer: 7, disk: 3, half: 0, zone: 0 - {104, 0, 22, 10}, - {104, 1, 21, 11}, - {104, 2, 20, 12}, - {104, 3, 19, 13}, - // chip: 328 (4), ladder: 31 (29), layer: 7, disk: 3, half: 0, zone: 0 - {105, 0, 17, 6}, - {105, 1, 16, 7}, - {105, 2, 15, 8}, - {105, 3, 14, 9}, - // chip: 332 (3), ladder: 0 ( 0), layer: 8, disk: 4, half: 0, zone: 0 - {106, 0, 5, 0}, - {106, 1, 6, 1}, - {106, 2, 7, 2}, - // chip: 335 (3), ladder: 1 ( 1), layer: 8, disk: 4, half: 0, zone: 0 - {107, 0, 0, 3}, - {107, 1, 1, 4}, - {107, 2, 2, 5}, - // chip: 338 (3), ladder: 2 (15), layer: 8, disk: 4, half: 0, zone: 3 - {108, 0, 17, 0}, - {108, 1, 16, 1}, - {108, 2, 15, 2}, - // chip: 341 (3), ladder: 3 (16), layer: 8, disk: 4, half: 0, zone: 3 - {109, 0, 22, 3}, - {109, 1, 21, 4}, - {109, 2, 20, 5}, - // chip: 344 (3), ladder: 4 (17), layer: 9, disk: 4, half: 0, zone: 3 - {110, 0, 22, 3}, - {110, 1, 21, 4}, - {110, 2, 20, 5}, - // chip: 347 (3), ladder: 5 (18), layer: 9, disk: 4, half: 0, zone: 3 - {111, 0, 17, 0}, - {111, 1, 16, 1}, - {111, 2, 15, 2}, - // chip: 350 (3), ladder: 6 (32), layer: 9, disk: 4, half: 0, zone: 0 - {112, 0, 0, 3}, - {112, 1, 1, 4}, - {112, 2, 2, 5}, - // chip: 353 (3), ladder: 7 (33), layer: 9, disk: 4, half: 0, zone: 0 - {113, 0, 5, 0}, - {113, 1, 6, 1}, - {113, 2, 7, 2}, - // chip: 356 (4), ladder: 8 ( 2), layer: 8, disk: 4, half: 0, zone: 0 - {114, 0, 17, 6}, - {114, 1, 16, 7}, - {114, 2, 15, 8}, - {114, 3, 14, 9}, - // chip: 360 (4), ladder: 9 ( 3), layer: 8, disk: 4, half: 0, zone: 0 - {115, 0, 22, 10}, - {115, 1, 21, 11}, - {115, 2, 20, 12}, - {115, 3, 19, 13}, - // chip: 364 (4), ladder: 10 ( 6), layer: 8, disk: 4, half: 0, zone: 1 - {116, 0, 0, 0}, - {116, 1, 1, 1}, - {116, 2, 2, 2}, - {116, 3, 3, 3}, - // chip: 368 (4), ladder: 11 ( 7), layer: 8, disk: 4, half: 0, zone: 1 - {117, 0, 17, 4}, - {117, 1, 16, 5}, - {117, 2, 15, 6}, - {117, 3, 14, 7}, - // chip: 372 (4), ladder: 12 ( 8), layer: 8, disk: 4, half: 0, zone: 1 - {118, 0, 22, 8}, - {118, 1, 21, 9}, - {118, 2, 20, 10}, - {118, 3, 19, 11}, - // chip: 376 (4), ladder: 13 ( 9), layer: 8, disk: 4, half: 0, zone: 2 - {119, 0, 5, 0}, - {119, 1, 6, 1}, - {119, 2, 7, 2}, - {119, 3, 24, 3}, - // chip: 380 (4), ladder: 14 (10), layer: 8, disk: 4, half: 0, zone: 2 - {120, 0, 0, 4}, - {120, 1, 1, 5}, - {120, 2, 2, 6}, - {120, 3, 3, 7}, - // chip: 384 (4), ladder: 15 (13), layer: 8, disk: 4, half: 0, zone: 3 - {121, 0, 5, 6}, - {121, 1, 6, 7}, - {121, 2, 7, 8}, - {121, 3, 24, 9}, - // chip: 388 (4), ladder: 16 (14), layer: 8, disk: 4, half: 0, zone: 3 - {122, 0, 0, 10}, - {122, 1, 1, 11}, - {122, 2, 2, 12}, - {122, 3, 3, 13}, - // chip: 392 (4), ladder: 17 (19), layer: 9, disk: 4, half: 0, zone: 3 - {123, 0, 0, 10}, - {123, 1, 1, 11}, - {123, 2, 2, 12}, - {123, 3, 3, 13}, - // chip: 396 (4), ladder: 18 (20), layer: 9, disk: 4, half: 0, zone: 3 - {124, 0, 5, 6}, - {124, 1, 6, 7}, - {124, 2, 7, 8}, - {124, 3, 24, 9}, - // chip: 400 (4), ladder: 19 (23), layer: 9, disk: 4, half: 0, zone: 2 - {125, 0, 0, 4}, - {125, 1, 1, 5}, - {125, 2, 2, 6}, - {125, 3, 3, 7}, - // chip: 404 (4), ladder: 20 (24), layer: 9, disk: 4, half: 0, zone: 2 - {126, 0, 5, 0}, - {126, 1, 6, 1}, - {126, 2, 7, 2}, - {126, 3, 24, 3}, - // chip: 408 (4), ladder: 21 (25), layer: 9, disk: 4, half: 0, zone: 1 - {127, 0, 22, 8}, - {127, 1, 21, 9}, - {127, 2, 20, 10}, - {127, 3, 19, 11}, - // chip: 412 (4), ladder: 22 (26), layer: 9, disk: 4, half: 0, zone: 1 - {128, 0, 17, 4}, - {128, 1, 16, 5}, - {128, 2, 15, 6}, - {128, 3, 14, 7}, - // chip: 416 (4), ladder: 23 (27), layer: 9, disk: 4, half: 0, zone: 1 - {129, 0, 0, 0}, - {129, 1, 1, 1}, - {129, 2, 2, 2}, - {129, 3, 3, 3}, - // chip: 420 (4), ladder: 24 (30), layer: 9, disk: 4, half: 0, zone: 0 - {130, 0, 22, 10}, - {130, 1, 21, 11}, - {130, 2, 20, 12}, - {130, 3, 19, 13}, - // chip: 424 (4), ladder: 25 (31), layer: 9, disk: 4, half: 0, zone: 0 - {131, 0, 17, 6}, - {131, 1, 16, 7}, - {131, 2, 15, 8}, - {131, 3, 14, 9}, - // chip: 428 (5), ladder: 26 ( 4), layer: 8, disk: 4, half: 0, zone: 0 - {132, 0, 12, 14}, - {132, 1, 11, 15}, - {132, 2, 10, 16}, - {132, 3, 9, 17}, - {132, 4, 8, 18}, - // chip: 433 (5), ladder: 27 ( 5), layer: 8, disk: 4, half: 0, zone: 1 - {133, 0, 5, 12}, - {133, 1, 6, 13}, - {133, 2, 7, 14}, - {133, 3, 24, 15}, - {133, 4, 23, 16}, - // chip: 438 (5), ladder: 28 (11), layer: 8, disk: 4, half: 0, zone: 2 - {134, 0, 17, 8}, - {134, 1, 16, 9}, - {134, 2, 15, 10}, - {134, 3, 14, 11}, - {134, 4, 13, 12}, - // chip: 443 (5), ladder: 29 (12), layer: 8, disk: 4, half: 0, zone: 2 - {135, 0, 22, 13}, - {135, 1, 21, 14}, - {135, 2, 20, 15}, - {135, 3, 19, 16}, - {135, 4, 18, 17}, - // chip: 448 (5), ladder: 30 (21), layer: 9, disk: 4, half: 0, zone: 2 - {136, 0, 22, 13}, - {136, 1, 21, 14}, - {136, 2, 20, 15}, - {136, 3, 19, 16}, - {136, 4, 18, 17}, - // chip: 453 (5), ladder: 31 (22), layer: 9, disk: 4, half: 0, zone: 2 - {137, 0, 17, 8}, - {137, 1, 16, 9}, - {137, 2, 15, 10}, - {137, 3, 14, 11}, - {137, 4, 13, 12}, - // chip: 458 (5), ladder: 32 (28), layer: 9, disk: 4, half: 0, zone: 1 - {138, 0, 5, 12}, - {138, 1, 6, 13}, - {138, 2, 7, 14}, - {138, 3, 24, 15}, - {138, 4, 23, 16}, + // { module, chipOnModule, cable, chipOnRU, globalChipSWID, localChipSWID, localChipHWID, connector, zone, ruOnLayer, ruType, ruSWID, ruHWID, layer, disk, half } + + // chip: 0 (5), ladder: 0 (29), layer: 0, disk: 0, half: 0, zone: 0 + {0, 0, 5, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + {0, 1, 6, 1, 1, 1, 7, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + // chip: 2 (5), ladder: 1 (29), layer: 0, disk: 0, half: 0, zone: 0 + {1, 0, 0, 0, 2, 0, 8, 1, 3, 3, 0, 3, 3, 0, 0, 0}, + {1, 1, 1, 1, 3, 1, 7, 1, 3, 3, 0, 3, 3, 0, 0, 0}, + // chip: 4 (5), ladder: 2 (29), layer: 0, disk: 0, half: 0, zone: 0 + {2, 0, 17, 2, 4, 0, 8, 2, 3, 3, 0, 3, 3, 0, 0, 0}, + {2, 1, 16, 3, 5, 1, 7, 2, 3, 3, 0, 3, 3, 0, 0, 0}, + // chip: 6 (5), ladder: 3 (29), layer: 1, disk: 0, half: 0, zone: 0 + {3, 0, 17, 2, 6, 0, 8, 2, 3, 3, 0, 11, 7, 1, 0, 0}, + {3, 1, 16, 3, 7, 1, 7, 2, 3, 3, 0, 11, 7, 1, 0, 0}, + // chip: 8 (5), ladder: 4 (29), layer: 1, disk: 0, half: 0, zone: 0 + {4, 0, 0, 0, 8, 0, 8, 1, 3, 3, 0, 11, 7, 1, 0, 0}, + {4, 1, 1, 1, 9, 1, 7, 1, 3, 3, 0, 11, 7, 1, 0, 0}, + // chip: 10 (5), ladder: 5 (29), layer: 1, disk: 0, half: 0, zone: 0 + {5, 0, 5, 0, 10, 0, 8, 0, 0, 0, 1, 8, 4, 1, 0, 0}, + {5, 1, 6, 1, 11, 1, 7, 0, 0, 0, 1, 8, 4, 1, 0, 0}, + // chip: 12 (5), ladder: 6 (29), layer: 0, disk: 0, half: 0, zone: 0 + {6, 0, 0, 2, 12, 0, 8, 1, 0, 0, 1, 0, 0, 0, 0, 0}, + {6, 1, 1, 3, 13, 1, 7, 1, 0, 0, 1, 0, 0, 0, 0, 0}, + {6, 2, 2, 4, 14, 2, 6, 1, 0, 0, 1, 0, 0, 0, 0, 0}, + // chip: 15 (5), ladder: 7 (29), layer: 0, disk: 0, half: 0, zone: 0 + {7, 0, 17, 5, 15, 0, 8, 2, 0, 0, 1, 0, 0, 0, 0, 0}, + {7, 1, 16, 6, 16, 1, 7, 2, 0, 0, 1, 0, 0, 0, 0, 0}, + {7, 2, 15, 7, 17, 2, 6, 2, 0, 0, 1, 0, 0, 0, 0, 0}, + // chip: 18 (5), ladder: 8 (29), layer: 0, disk: 0, half: 0, zone: 0 + {8, 0, 5, 0, 18, 0, 8, 0, 1, 1, 2, 1, 1, 0, 0, 0}, + {8, 1, 6, 1, 19, 1, 7, 0, 1, 1, 2, 1, 1, 0, 0, 0}, + {8, 2, 7, 2, 20, 2, 6, 0, 1, 1, 2, 1, 1, 0, 0, 0}, + // chip: 21 (5), ladder: 9 (29), layer: 0, disk: 0, half: 0, zone: 0 + {9, 0, 0, 3, 21, 0, 8, 1, 1, 1, 2, 1, 1, 0, 0, 0}, + {9, 1, 1, 4, 22, 1, 7, 1, 1, 1, 2, 1, 1, 0, 0, 0}, + {9, 2, 2, 5, 23, 2, 6, 1, 1, 1, 2, 1, 1, 0, 0, 0}, + // chip: 24 (5), ladder: 10 (29), layer: 0, disk: 0, half: 0, zone: 0 + {10, 0, 17, 6, 24, 0, 8, 2, 1, 1, 2, 1, 1, 0, 0, 0}, + {10, 1, 16, 7, 25, 1, 7, 2, 1, 1, 2, 1, 1, 0, 0, 0}, + {10, 2, 15, 8, 26, 2, 6, 2, 1, 1, 2, 1, 1, 0, 0, 0}, + // chip: 27 (5), ladder: 11 (29), layer: 0, disk: 0, half: 0, zone: 0 + {11, 0, 5, 0, 27, 0, 8, 0, 2, 2, 2, 2, 2, 0, 0, 0}, + {11, 1, 6, 1, 28, 1, 7, 0, 2, 2, 2, 2, 2, 0, 0, 0}, + {11, 2, 7, 2, 29, 2, 6, 0, 2, 2, 2, 2, 2, 0, 0, 0}, + // chip: 30 (5), ladder: 12 (29), layer: 0, disk: 0, half: 0, zone: 0 + {12, 0, 0, 3, 30, 0, 8, 1, 2, 2, 2, 2, 2, 0, 0, 0}, + {12, 1, 1, 4, 31, 1, 7, 1, 2, 2, 2, 2, 2, 0, 0, 0}, + {12, 2, 2, 5, 32, 2, 6, 1, 2, 2, 2, 2, 2, 0, 0, 0}, + // chip: 33 (5), ladder: 13 (29), layer: 0, disk: 0, half: 0, zone: 0 + {13, 0, 17, 6, 33, 0, 8, 2, 2, 2, 2, 2, 2, 0, 0, 0}, + {13, 1, 16, 7, 34, 1, 7, 2, 2, 2, 2, 2, 2, 0, 0, 0}, + {13, 2, 15, 8, 35, 2, 6, 2, 2, 2, 2, 2, 2, 0, 0, 0}, + // chip: 36 (5), ladder: 14 (29), layer: 0, disk: 0, half: 0, zone: 0 + {14, 0, 5, 4, 36, 0, 8, 0, 3, 3, 0, 3, 3, 0, 0, 0}, + {14, 1, 6, 5, 37, 1, 7, 0, 3, 3, 0, 3, 3, 0, 0, 0}, + {14, 2, 7, 6, 38, 2, 6, 0, 3, 3, 0, 3, 3, 0, 0, 0}, + // chip: 39 (5), ladder: 15 (29), layer: 1, disk: 0, half: 0, zone: 0 + {15, 0, 5, 4, 39, 0, 8, 0, 3, 3, 0, 11, 7, 1, 0, 0}, + {15, 1, 6, 5, 40, 1, 7, 0, 3, 3, 0, 11, 7, 1, 0, 0}, + {15, 2, 7, 6, 41, 2, 6, 0, 3, 3, 0, 11, 7, 1, 0, 0}, + // chip: 42 (5), ladder: 16 (29), layer: 1, disk: 0, half: 0, zone: 0 + {16, 0, 17, 6, 42, 0, 8, 2, 2, 2, 2, 10, 6, 1, 0, 0}, + {16, 1, 16, 7, 43, 1, 7, 2, 2, 2, 2, 10, 6, 1, 0, 0}, + {16, 2, 15, 8, 44, 2, 6, 2, 2, 2, 2, 10, 6, 1, 0, 0}, + // chip: 45 (5), ladder: 17 (29), layer: 1, disk: 0, half: 0, zone: 0 + {17, 0, 0, 3, 45, 0, 8, 1, 2, 2, 2, 10, 6, 1, 0, 0}, + {17, 1, 1, 4, 46, 1, 7, 1, 2, 2, 2, 10, 6, 1, 0, 0}, + {17, 2, 2, 5, 47, 2, 6, 1, 2, 2, 2, 10, 6, 1, 0, 0}, + // chip: 48 (5), ladder: 18 (29), layer: 1, disk: 0, half: 0, zone: 0 + {18, 0, 5, 0, 48, 0, 8, 0, 2, 2, 2, 10, 6, 1, 0, 0}, + {18, 1, 6, 1, 49, 1, 7, 0, 2, 2, 2, 10, 6, 1, 0, 0}, + {18, 2, 7, 2, 50, 2, 6, 0, 2, 2, 2, 10, 6, 1, 0, 0}, + // chip: 51 (5), ladder: 19 (29), layer: 1, disk: 0, half: 0, zone: 0 + {19, 0, 17, 6, 51, 0, 8, 2, 1, 1, 2, 9, 5, 1, 0, 0}, + {19, 1, 16, 7, 52, 1, 7, 2, 1, 1, 2, 9, 5, 1, 0, 0}, + {19, 2, 15, 8, 53, 2, 6, 2, 1, 1, 2, 9, 5, 1, 0, 0}, + // chip: 54 (5), ladder: 20 (29), layer: 1, disk: 0, half: 0, zone: 0 + {20, 0, 0, 3, 54, 0, 8, 1, 1, 1, 2, 9, 5, 1, 0, 0}, + {20, 1, 1, 4, 55, 1, 7, 1, 1, 1, 2, 9, 5, 1, 0, 0}, + {20, 2, 2, 5, 56, 2, 6, 1, 1, 1, 2, 9, 5, 1, 0, 0}, + // chip: 57 (5), ladder: 21 (29), layer: 1, disk: 0, half: 0, zone: 0 + {21, 0, 5, 0, 57, 0, 8, 0, 1, 1, 2, 9, 5, 1, 0, 0}, + {21, 1, 6, 1, 58, 1, 7, 0, 1, 1, 2, 9, 5, 1, 0, 0}, + {21, 2, 7, 2, 59, 2, 6, 0, 1, 1, 2, 9, 5, 1, 0, 0}, + // chip: 60 (5), ladder: 22 (29), layer: 1, disk: 0, half: 0, zone: 0 + {22, 0, 17, 5, 60, 0, 8, 2, 0, 0, 1, 8, 4, 1, 0, 0}, + {22, 1, 16, 6, 61, 1, 7, 2, 0, 0, 1, 8, 4, 1, 0, 0}, + {22, 2, 15, 7, 62, 2, 6, 2, 0, 0, 1, 8, 4, 1, 0, 0}, + // chip: 63 (5), ladder: 23 (29), layer: 1, disk: 0, half: 0, zone: 0 + {23, 0, 0, 2, 63, 0, 8, 1, 0, 0, 1, 8, 4, 1, 0, 0}, + {23, 1, 1, 3, 64, 1, 7, 1, 0, 0, 1, 8, 4, 1, 0, 0}, + {23, 2, 2, 4, 65, 2, 6, 1, 0, 0, 1, 8, 4, 1, 0, 0}, + // chip: 66 (5), ladder: 0 (29), layer: 2, disk: 1, half: 0, zone: 0 + {24, 0, 5, 0, 66, 0, 8, 0, 0, 0, 1, 16, 8, 2, 1, 0}, + {24, 1, 6, 1, 67, 1, 7, 0, 0, 0, 1, 16, 8, 2, 1, 0}, + // chip: 68 (5), ladder: 1 (29), layer: 2, disk: 1, half: 0, zone: 0 + {25, 0, 0, 0, 68, 0, 8, 1, 3, 3, 0, 19, 11, 2, 1, 0}, + {25, 1, 1, 1, 69, 1, 7, 1, 3, 3, 0, 19, 11, 2, 1, 0}, + // chip: 70 (5), ladder: 2 (29), layer: 2, disk: 1, half: 0, zone: 0 + {26, 0, 17, 2, 70, 0, 8, 2, 3, 3, 0, 19, 11, 2, 1, 0}, + {26, 1, 16, 3, 71, 1, 7, 2, 3, 3, 0, 19, 11, 2, 1, 0}, + // chip: 72 (5), ladder: 3 (29), layer: 3, disk: 1, half: 0, zone: 0 + {27, 0, 17, 2, 72, 0, 8, 2, 3, 3, 0, 27, 15, 3, 1, 0}, + {27, 1, 16, 3, 73, 1, 7, 2, 3, 3, 0, 27, 15, 3, 1, 0}, + // chip: 74 (5), ladder: 4 (29), layer: 3, disk: 1, half: 0, zone: 0 + {28, 0, 0, 0, 74, 0, 8, 1, 3, 3, 0, 27, 15, 3, 1, 0}, + {28, 1, 1, 1, 75, 1, 7, 1, 3, 3, 0, 27, 15, 3, 1, 0}, + // chip: 76 (5), ladder: 5 (29), layer: 3, disk: 1, half: 0, zone: 0 + {29, 0, 5, 0, 76, 0, 8, 0, 0, 0, 1, 24, 12, 3, 1, 0}, + {29, 1, 6, 1, 77, 1, 7, 0, 0, 0, 1, 24, 12, 3, 1, 0}, + // chip: 78 (5), ladder: 6 (29), layer: 2, disk: 1, half: 0, zone: 0 + {30, 0, 0, 2, 78, 0, 8, 1, 0, 0, 1, 16, 8, 2, 1, 0}, + {30, 1, 1, 3, 79, 1, 7, 1, 0, 0, 1, 16, 8, 2, 1, 0}, + {30, 2, 2, 4, 80, 2, 6, 1, 0, 0, 1, 16, 8, 2, 1, 0}, + // chip: 81 (5), ladder: 7 (29), layer: 2, disk: 1, half: 0, zone: 0 + {31, 0, 17, 5, 81, 0, 8, 2, 0, 0, 1, 16, 8, 2, 1, 0}, + {31, 1, 16, 6, 82, 1, 7, 2, 0, 0, 1, 16, 8, 2, 1, 0}, + {31, 2, 15, 7, 83, 2, 6, 2, 0, 0, 1, 16, 8, 2, 1, 0}, + // chip: 84 (5), ladder: 8 (29), layer: 2, disk: 1, half: 0, zone: 0 + {32, 0, 5, 0, 84, 0, 8, 0, 1, 1, 2, 17, 9, 2, 1, 0}, + {32, 1, 6, 1, 85, 1, 7, 0, 1, 1, 2, 17, 9, 2, 1, 0}, + {32, 2, 7, 2, 86, 2, 6, 0, 1, 1, 2, 17, 9, 2, 1, 0}, + // chip: 87 (5), ladder: 9 (29), layer: 2, disk: 1, half: 0, zone: 0 + {33, 0, 0, 3, 87, 0, 8, 1, 1, 1, 2, 17, 9, 2, 1, 0}, + {33, 1, 1, 4, 88, 1, 7, 1, 1, 1, 2, 17, 9, 2, 1, 0}, + {33, 2, 2, 5, 89, 2, 6, 1, 1, 1, 2, 17, 9, 2, 1, 0}, + // chip: 90 (5), ladder: 10 (29), layer: 2, disk: 1, half: 0, zone: 0 + {34, 0, 17, 6, 90, 0, 8, 2, 1, 1, 2, 17, 9, 2, 1, 0}, + {34, 1, 16, 7, 91, 1, 7, 2, 1, 1, 2, 17, 9, 2, 1, 0}, + {34, 2, 15, 8, 92, 2, 6, 2, 1, 1, 2, 17, 9, 2, 1, 0}, + // chip: 93 (5), ladder: 11 (29), layer: 2, disk: 1, half: 0, zone: 0 + {35, 0, 5, 0, 93, 0, 8, 0, 2, 2, 2, 18, 10, 2, 1, 0}, + {35, 1, 6, 1, 94, 1, 7, 0, 2, 2, 2, 18, 10, 2, 1, 0}, + {35, 2, 7, 2, 95, 2, 6, 0, 2, 2, 2, 18, 10, 2, 1, 0}, + // chip: 96 (5), ladder: 12 (29), layer: 2, disk: 1, half: 0, zone: 0 + {36, 0, 0, 3, 96, 0, 8, 1, 2, 2, 2, 18, 10, 2, 1, 0}, + {36, 1, 1, 4, 97, 1, 7, 1, 2, 2, 2, 18, 10, 2, 1, 0}, + {36, 2, 2, 5, 98, 2, 6, 1, 2, 2, 2, 18, 10, 2, 1, 0}, + // chip: 99 (5), ladder: 13 (29), layer: 2, disk: 1, half: 0, zone: 0 + {37, 0, 17, 6, 99, 0, 8, 2, 2, 2, 2, 18, 10, 2, 1, 0}, + {37, 1, 16, 7, 100, 1, 7, 2, 2, 2, 2, 18, 10, 2, 1, 0}, + {37, 2, 15, 8, 101, 2, 6, 2, 2, 2, 2, 18, 10, 2, 1, 0}, + // chip: 102 (5), ladder: 14 (29), layer: 2, disk: 1, half: 0, zone: 0 + {38, 0, 5, 4, 102, 0, 8, 0, 3, 3, 0, 19, 11, 2, 1, 0}, + {38, 1, 6, 5, 103, 1, 7, 0, 3, 3, 0, 19, 11, 2, 1, 0}, + {38, 2, 7, 6, 104, 2, 6, 0, 3, 3, 0, 19, 11, 2, 1, 0}, + // chip: 105 (5), ladder: 15 (29), layer: 3, disk: 1, half: 0, zone: 0 + {39, 0, 5, 4, 105, 0, 8, 0, 3, 3, 0, 27, 15, 3, 1, 0}, + {39, 1, 6, 5, 106, 1, 7, 0, 3, 3, 0, 27, 15, 3, 1, 0}, + {39, 2, 7, 6, 107, 2, 6, 0, 3, 3, 0, 27, 15, 3, 1, 0}, + // chip: 108 (5), ladder: 16 (29), layer: 3, disk: 1, half: 0, zone: 0 + {40, 0, 17, 6, 108, 0, 8, 2, 2, 2, 2, 26, 14, 3, 1, 0}, + {40, 1, 16, 7, 109, 1, 7, 2, 2, 2, 2, 26, 14, 3, 1, 0}, + {40, 2, 15, 8, 110, 2, 6, 2, 2, 2, 2, 26, 14, 3, 1, 0}, + // chip: 111 (5), ladder: 17 (29), layer: 3, disk: 1, half: 0, zone: 0 + {41, 0, 0, 3, 111, 0, 8, 1, 2, 2, 2, 26, 14, 3, 1, 0}, + {41, 1, 1, 4, 112, 1, 7, 1, 2, 2, 2, 26, 14, 3, 1, 0}, + {41, 2, 2, 5, 113, 2, 6, 1, 2, 2, 2, 26, 14, 3, 1, 0}, + // chip: 114 (5), ladder: 18 (29), layer: 3, disk: 1, half: 0, zone: 0 + {42, 0, 5, 0, 114, 0, 8, 0, 2, 2, 2, 26, 14, 3, 1, 0}, + {42, 1, 6, 1, 115, 1, 7, 0, 2, 2, 2, 26, 14, 3, 1, 0}, + {42, 2, 7, 2, 116, 2, 6, 0, 2, 2, 2, 26, 14, 3, 1, 0}, + // chip: 117 (5), ladder: 19 (29), layer: 3, disk: 1, half: 0, zone: 0 + {43, 0, 17, 6, 117, 0, 8, 2, 1, 1, 2, 25, 13, 3, 1, 0}, + {43, 1, 16, 7, 118, 1, 7, 2, 1, 1, 2, 25, 13, 3, 1, 0}, + {43, 2, 15, 8, 119, 2, 6, 2, 1, 1, 2, 25, 13, 3, 1, 0}, + // chip: 120 (5), ladder: 20 (29), layer: 3, disk: 1, half: 0, zone: 0 + {44, 0, 0, 3, 120, 0, 8, 1, 1, 1, 2, 25, 13, 3, 1, 0}, + {44, 1, 1, 4, 121, 1, 7, 1, 1, 1, 2, 25, 13, 3, 1, 0}, + {44, 2, 2, 5, 122, 2, 6, 1, 1, 1, 2, 25, 13, 3, 1, 0}, + // chip: 123 (5), ladder: 21 (29), layer: 3, disk: 1, half: 0, zone: 0 + {45, 0, 5, 0, 123, 0, 8, 0, 1, 1, 2, 25, 13, 3, 1, 0}, + {45, 1, 6, 1, 124, 1, 7, 0, 1, 1, 2, 25, 13, 3, 1, 0}, + {45, 2, 7, 2, 125, 2, 6, 0, 1, 1, 2, 25, 13, 3, 1, 0}, + // chip: 126 (5), ladder: 22 (29), layer: 3, disk: 1, half: 0, zone: 0 + {46, 0, 17, 5, 126, 0, 8, 2, 0, 0, 1, 24, 12, 3, 1, 0}, + {46, 1, 16, 6, 127, 1, 7, 2, 0, 0, 1, 24, 12, 3, 1, 0}, + {46, 2, 15, 7, 128, 2, 6, 2, 0, 0, 1, 24, 12, 3, 1, 0}, + // chip: 129 (5), ladder: 23 (29), layer: 3, disk: 1, half: 0, zone: 0 + {47, 0, 0, 2, 129, 0, 8, 1, 0, 0, 1, 24, 12, 3, 1, 0}, + {47, 1, 1, 3, 130, 1, 7, 1, 0, 0, 1, 24, 12, 3, 1, 0}, + {47, 2, 2, 4, 131, 2, 6, 1, 0, 0, 1, 24, 12, 3, 1, 0}, + // chip: 132 (5), ladder: 0 (29), layer: 4, disk: 2, half: 0, zone: 0 + {48, 0, 5, 0, 132, 0, 8, 0, 0, 0, 1, 32, 16, 4, 2, 0}, + {48, 1, 6, 1, 133, 1, 7, 0, 0, 0, 1, 32, 16, 4, 2, 0}, + // chip: 134 (5), ladder: 1 (29), layer: 4, disk: 2, half: 0, zone: 0 + {49, 0, 22, 0, 134, 0, 8, 3, 3, 3, 5, 35, 19, 4, 2, 0}, + {49, 1, 21, 1, 135, 1, 7, 3, 3, 3, 5, 35, 19, 4, 2, 0}, + // chip: 136 (5), ladder: 2 (29), layer: 5, disk: 2, half: 0, zone: 0 + {50, 0, 22, 0, 136, 0, 8, 3, 3, 3, 5, 43, 23, 5, 2, 0}, + {50, 1, 21, 1, 137, 1, 7, 3, 3, 3, 5, 43, 23, 5, 2, 0}, + // chip: 138 (5), ladder: 3 (29), layer: 5, disk: 2, half: 0, zone: 0 + {51, 0, 5, 0, 138, 0, 8, 0, 0, 0, 1, 40, 20, 5, 2, 0}, + {51, 1, 6, 1, 139, 1, 7, 0, 0, 0, 1, 40, 20, 5, 2, 0}, + // chip: 140 (5), ladder: 4 (29), layer: 4, disk: 2, half: 0, zone: 0 + {52, 0, 0, 2, 140, 0, 8, 1, 0, 0, 1, 32, 16, 4, 2, 0}, + {52, 1, 1, 3, 141, 1, 7, 1, 0, 0, 1, 32, 16, 4, 2, 0}, + {52, 2, 2, 4, 142, 2, 6, 1, 0, 0, 1, 32, 16, 4, 2, 0}, + // chip: 143 (5), ladder: 5 (29), layer: 4, disk: 2, half: 0, zone: 0 + {53, 0, 17, 5, 143, 0, 8, 2, 0, 0, 1, 32, 16, 4, 2, 0}, + {53, 1, 16, 6, 144, 1, 7, 2, 0, 0, 1, 32, 16, 4, 2, 0}, + {53, 2, 15, 7, 145, 2, 6, 2, 0, 0, 1, 32, 16, 4, 2, 0}, + // chip: 146 (5), ladder: 6 (29), layer: 4, disk: 2, half: 0, zone: 0 + {54, 0, 17, 0, 146, 0, 8, 2, 1, 1, 4, 33, 17, 4, 2, 0}, + {54, 1, 16, 1, 147, 1, 7, 2, 1, 1, 4, 33, 17, 4, 2, 0}, + {54, 2, 15, 2, 148, 2, 6, 2, 1, 1, 4, 33, 17, 4, 2, 0}, + // chip: 149 (5), ladder: 7 (29), layer: 4, disk: 2, half: 0, zone: 0 + {55, 0, 5, 0, 149, 0, 8, 0, 2, 2, 3, 34, 18, 4, 2, 0}, + {55, 1, 6, 1, 150, 1, 7, 0, 2, 2, 3, 34, 18, 4, 2, 0}, + {55, 2, 7, 2, 151, 2, 6, 0, 2, 2, 3, 34, 18, 4, 2, 0}, + // chip: 152 (5), ladder: 8 (29), layer: 4, disk: 2, half: 0, zone: 0 + {56, 0, 0, 3, 152, 0, 8, 1, 2, 2, 3, 34, 18, 4, 2, 0}, + {56, 1, 1, 4, 153, 1, 7, 1, 2, 2, 3, 34, 18, 4, 2, 0}, + {56, 2, 2, 5, 154, 2, 6, 1, 2, 2, 3, 34, 18, 4, 2, 0}, + // chip: 155 (5), ladder: 9 (29), layer: 4, disk: 2, half: 0, zone: 0 + {57, 0, 0, 2, 155, 0, 8, 1, 3, 3, 5, 35, 19, 4, 2, 0}, + {57, 1, 1, 3, 156, 1, 7, 1, 3, 3, 5, 35, 19, 4, 2, 0}, + {57, 2, 2, 4, 157, 2, 6, 1, 3, 3, 5, 35, 19, 4, 2, 0}, + // chip: 158 (5), ladder: 10 (29), layer: 4, disk: 2, half: 0, zone: 0 + {58, 0, 17, 5, 158, 0, 8, 2, 3, 3, 5, 35, 19, 4, 2, 0}, + {58, 1, 16, 6, 159, 1, 7, 2, 3, 3, 5, 35, 19, 4, 2, 0}, + {58, 2, 15, 7, 160, 2, 6, 2, 3, 3, 5, 35, 19, 4, 2, 0}, + // chip: 161 (5), ladder: 11 (29), layer: 5, disk: 2, half: 0, zone: 0 + {59, 0, 17, 5, 161, 0, 8, 2, 3, 3, 5, 43, 23, 5, 2, 0}, + {59, 1, 16, 6, 162, 1, 7, 2, 3, 3, 5, 43, 23, 5, 2, 0}, + {59, 2, 15, 7, 163, 2, 6, 2, 3, 3, 5, 43, 23, 5, 2, 0}, + // chip: 164 (5), ladder: 12 (29), layer: 5, disk: 2, half: 0, zone: 0 + {60, 0, 0, 2, 164, 0, 8, 1, 3, 3, 5, 43, 23, 5, 2, 0}, + {60, 1, 1, 3, 165, 1, 7, 1, 3, 3, 5, 43, 23, 5, 2, 0}, + {60, 2, 2, 4, 166, 2, 6, 1, 3, 3, 5, 43, 23, 5, 2, 0}, + // chip: 167 (5), ladder: 13 (29), layer: 5, disk: 2, half: 0, zone: 0 + {61, 0, 0, 3, 167, 0, 8, 1, 2, 2, 3, 42, 22, 5, 2, 0}, + {61, 1, 1, 4, 168, 1, 7, 1, 2, 2, 3, 42, 22, 5, 2, 0}, + {61, 2, 2, 5, 169, 2, 6, 1, 2, 2, 3, 42, 22, 5, 2, 0}, + // chip: 170 (5), ladder: 14 (29), layer: 5, disk: 2, half: 0, zone: 0 + {62, 0, 5, 0, 170, 0, 8, 0, 2, 2, 3, 42, 22, 5, 2, 0}, + {62, 1, 6, 1, 171, 1, 7, 0, 2, 2, 3, 42, 22, 5, 2, 0}, + {62, 2, 7, 2, 172, 2, 6, 0, 2, 2, 3, 42, 22, 5, 2, 0}, + // chip: 173 (5), ladder: 15 (29), layer: 5, disk: 2, half: 0, zone: 0 + {63, 0, 17, 0, 173, 0, 8, 2, 1, 1, 4, 41, 21, 5, 2, 0}, + {63, 1, 16, 1, 174, 1, 7, 2, 1, 1, 4, 41, 21, 5, 2, 0}, + {63, 2, 15, 2, 175, 2, 6, 2, 1, 1, 4, 41, 21, 5, 2, 0}, + // chip: 176 (5), ladder: 16 (29), layer: 5, disk: 2, half: 0, zone: 0 + {64, 0, 17, 5, 176, 0, 8, 2, 0, 0, 1, 40, 20, 5, 2, 0}, + {64, 1, 16, 6, 177, 1, 7, 2, 0, 0, 1, 40, 20, 5, 2, 0}, + {64, 2, 15, 7, 178, 2, 6, 2, 0, 0, 1, 40, 20, 5, 2, 0}, + // chip: 179 (5), ladder: 17 (29), layer: 5, disk: 2, half: 0, zone: 0 + {65, 0, 0, 2, 179, 0, 8, 1, 0, 0, 1, 40, 20, 5, 2, 0}, + {65, 1, 1, 3, 180, 1, 7, 1, 0, 0, 1, 40, 20, 5, 2, 0}, + {65, 2, 2, 4, 181, 2, 6, 1, 0, 0, 1, 40, 20, 5, 2, 0}, + // chip: 182 (5), ladder: 18 (29), layer: 4, disk: 2, half: 0, zone: 0 + {66, 0, 5, 3, 182, 0, 8, 0, 1, 1, 4, 33, 17, 4, 2, 0}, + {66, 1, 6, 4, 183, 1, 7, 0, 1, 1, 4, 33, 17, 4, 2, 0}, + {66, 2, 7, 5, 184, 2, 6, 0, 1, 1, 4, 33, 17, 4, 2, 0}, + {66, 3, 24, 6, 185, 3, 5, 0, 1, 1, 4, 33, 17, 4, 2, 0}, + // chip: 186 (5), ladder: 19 (29), layer: 4, disk: 2, half: 0, zone: 0 + {67, 0, 0, 7, 186, 0, 8, 1, 1, 1, 4, 33, 17, 4, 2, 0}, + {67, 1, 1, 8, 187, 1, 7, 1, 1, 1, 4, 33, 17, 4, 2, 0}, + {67, 2, 2, 9, 188, 2, 6, 1, 1, 1, 4, 33, 17, 4, 2, 0}, + {67, 3, 3, 10, 189, 3, 5, 1, 1, 1, 4, 33, 17, 4, 2, 0}, + // chip: 190 (5), ladder: 20 (29), layer: 4, disk: 2, half: 0, zone: 0 + {68, 0, 17, 6, 190, 0, 8, 2, 2, 2, 3, 34, 18, 4, 2, 0}, + {68, 1, 16, 7, 191, 1, 7, 2, 2, 2, 3, 34, 18, 4, 2, 0}, + {68, 2, 15, 8, 192, 2, 6, 2, 2, 2, 3, 34, 18, 4, 2, 0}, + {68, 3, 14, 9, 193, 3, 5, 2, 2, 2, 3, 34, 18, 4, 2, 0}, + // chip: 194 (5), ladder: 21 (29), layer: 4, disk: 2, half: 0, zone: 0 + {69, 0, 5, 8, 194, 0, 8, 0, 3, 3, 5, 35, 19, 4, 2, 0}, + {69, 1, 6, 9, 195, 1, 7, 0, 3, 3, 5, 35, 19, 4, 2, 0}, + {69, 2, 7, 10, 196, 2, 6, 0, 3, 3, 5, 35, 19, 4, 2, 0}, + {69, 3, 24, 11, 197, 3, 5, 0, 3, 3, 5, 35, 19, 4, 2, 0}, + // chip: 198 (5), ladder: 22 (29), layer: 5, disk: 2, half: 0, zone: 0 + {70, 0, 5, 8, 198, 0, 8, 0, 3, 3, 5, 43, 23, 5, 2, 0}, + {70, 1, 6, 9, 199, 1, 7, 0, 3, 3, 5, 43, 23, 5, 2, 0}, + {70, 2, 7, 10, 200, 2, 6, 0, 3, 3, 5, 43, 23, 5, 2, 0}, + {70, 3, 24, 11, 201, 3, 5, 0, 3, 3, 5, 43, 23, 5, 2, 0}, + // chip: 202 (5), ladder: 23 (29), layer: 5, disk: 2, half: 0, zone: 0 + {71, 0, 17, 6, 202, 0, 8, 2, 2, 2, 3, 42, 22, 5, 2, 0}, + {71, 1, 16, 7, 203, 1, 7, 2, 2, 2, 3, 42, 22, 5, 2, 0}, + {71, 2, 15, 8, 204, 2, 6, 2, 2, 2, 3, 42, 22, 5, 2, 0}, + {71, 3, 14, 9, 205, 3, 5, 2, 2, 2, 3, 42, 22, 5, 2, 0}, + // chip: 206 (5), ladder: 24 (29), layer: 5, disk: 2, half: 0, zone: 0 + {72, 0, 0, 7, 206, 0, 8, 1, 1, 1, 4, 41, 21, 5, 2, 0}, + {72, 1, 1, 8, 207, 1, 7, 1, 1, 1, 4, 41, 21, 5, 2, 0}, + {72, 2, 2, 9, 208, 2, 6, 1, 1, 1, 4, 41, 21, 5, 2, 0}, + {72, 3, 3, 10, 209, 3, 5, 1, 1, 1, 4, 41, 21, 5, 2, 0}, + // chip: 210 (5), ladder: 25 (29), layer: 5, disk: 2, half: 0, zone: 0 + {73, 0, 5, 3, 210, 0, 8, 0, 1, 1, 4, 41, 21, 5, 2, 0}, + {73, 1, 6, 4, 211, 1, 7, 0, 1, 1, 4, 41, 21, 5, 2, 0}, + {73, 2, 7, 5, 212, 2, 6, 0, 1, 1, 4, 41, 21, 5, 2, 0}, + {73, 3, 24, 6, 213, 3, 5, 0, 1, 1, 4, 41, 21, 5, 2, 0}, + // chip: 214 (5), ladder: 0 (29), layer: 6, disk: 3, half: 0, zone: 0 + {74, 0, 5, 0, 214, 0, 8, 0, 0, 0, 7, 48, 24, 6, 3, 0}, + {74, 1, 6, 1, 215, 1, 7, 0, 0, 0, 7, 48, 24, 6, 3, 0}, + {74, 2, 7, 2, 216, 2, 6, 0, 0, 0, 7, 48, 24, 6, 3, 0}, + // chip: 217 (5), ladder: 1 (29), layer: 6, disk: 3, half: 0, zone: 0 + {75, 0, 0, 3, 217, 0, 8, 1, 0, 0, 7, 48, 24, 6, 3, 0}, + {75, 1, 1, 4, 218, 1, 7, 1, 0, 0, 7, 48, 24, 6, 3, 0}, + {75, 2, 2, 5, 219, 2, 6, 1, 0, 0, 7, 48, 24, 6, 3, 0}, + // chip: 220 (5), ladder: 2 (29), layer: 6, disk: 3, half: 0, zone: 0 + {76, 0, 0, 0, 220, 0, 8, 1, 3, 3, 6, 51, 27, 6, 3, 0}, + {76, 1, 1, 1, 221, 1, 7, 1, 3, 3, 6, 51, 27, 6, 3, 0}, + {76, 2, 2, 2, 222, 2, 6, 1, 3, 3, 6, 51, 27, 6, 3, 0}, + // chip: 223 (5), ladder: 3 (29), layer: 6, disk: 3, half: 0, zone: 0 + {77, 0, 17, 3, 223, 0, 8, 2, 3, 3, 6, 51, 27, 6, 3, 0}, + {77, 1, 16, 4, 224, 1, 7, 2, 3, 3, 6, 51, 27, 6, 3, 0}, + {77, 2, 15, 5, 225, 2, 6, 2, 3, 3, 6, 51, 27, 6, 3, 0}, + // chip: 226 (5), ladder: 4 (29), layer: 6, disk: 3, half: 0, zone: 0 + {78, 0, 22, 6, 226, 0, 8, 3, 3, 3, 6, 51, 27, 6, 3, 0}, + {78, 1, 21, 7, 227, 1, 7, 3, 3, 3, 6, 51, 27, 6, 3, 0}, + {78, 2, 20, 8, 228, 2, 6, 3, 3, 3, 6, 51, 27, 6, 3, 0}, + // chip: 229 (5), ladder: 5 (29), layer: 7, disk: 3, half: 0, zone: 0 + {79, 0, 22, 6, 229, 0, 8, 3, 3, 3, 6, 59, 31, 7, 3, 0}, + {79, 1, 21, 7, 230, 1, 7, 3, 3, 3, 6, 59, 31, 7, 3, 0}, + {79, 2, 20, 8, 231, 2, 6, 3, 3, 3, 6, 59, 31, 7, 3, 0}, + // chip: 232 (5), ladder: 6 (29), layer: 7, disk: 3, half: 0, zone: 0 + {80, 0, 17, 3, 232, 0, 8, 2, 3, 3, 6, 59, 31, 7, 3, 0}, + {80, 1, 16, 4, 233, 1, 7, 2, 3, 3, 6, 59, 31, 7, 3, 0}, + {80, 2, 15, 5, 234, 2, 6, 2, 3, 3, 6, 59, 31, 7, 3, 0}, + // chip: 235 (5), ladder: 7 (29), layer: 7, disk: 3, half: 0, zone: 0 + {81, 0, 0, 0, 235, 0, 8, 1, 3, 3, 6, 59, 31, 7, 3, 0}, + {81, 1, 1, 1, 236, 1, 7, 1, 3, 3, 6, 59, 31, 7, 3, 0}, + {81, 2, 2, 2, 237, 2, 6, 1, 3, 3, 6, 59, 31, 7, 3, 0}, + // chip: 238 (5), ladder: 8 (29), layer: 7, disk: 3, half: 0, zone: 0 + {82, 0, 0, 3, 238, 0, 8, 1, 0, 0, 7, 56, 28, 7, 3, 0}, + {82, 1, 1, 4, 239, 1, 7, 1, 0, 0, 7, 56, 28, 7, 3, 0}, + {82, 2, 2, 5, 240, 2, 6, 1, 0, 0, 7, 56, 28, 7, 3, 0}, + // chip: 241 (5), ladder: 9 (29), layer: 7, disk: 3, half: 0, zone: 0 + {83, 0, 5, 0, 241, 0, 8, 0, 0, 0, 7, 56, 28, 7, 3, 0}, + {83, 1, 6, 1, 242, 1, 7, 0, 0, 0, 7, 56, 28, 7, 3, 0}, + {83, 2, 7, 2, 243, 2, 6, 0, 0, 0, 7, 56, 28, 7, 3, 0}, + // chip: 244 (5), ladder: 10 (29), layer: 6, disk: 3, half: 0, zone: 0 + {84, 0, 17, 6, 244, 0, 8, 2, 0, 0, 7, 48, 24, 6, 3, 0}, + {84, 1, 16, 7, 245, 1, 7, 2, 0, 0, 7, 48, 24, 6, 3, 0}, + {84, 2, 15, 8, 246, 2, 6, 2, 0, 0, 7, 48, 24, 6, 3, 0}, + {84, 3, 14, 9, 247, 3, 5, 2, 0, 0, 7, 48, 24, 6, 3, 0}, + // chip: 248 (5), ladder: 11 (29), layer: 6, disk: 3, half: 0, zone: 0 + {85, 0, 22, 10, 248, 0, 8, 3, 0, 0, 7, 48, 24, 6, 3, 0}, + {85, 1, 21, 11, 249, 1, 7, 3, 0, 0, 7, 48, 24, 6, 3, 0}, + {85, 2, 20, 12, 250, 2, 6, 3, 0, 0, 7, 48, 24, 6, 3, 0}, + {85, 3, 19, 13, 251, 3, 5, 3, 0, 0, 7, 48, 24, 6, 3, 0}, + // chip: 252 (5), ladder: 12 (29), layer: 6, disk: 3, half: 0, zone: 0 + {86, 0, 5, 0, 252, 0, 8, 0, 1, 1, 8, 49, 25, 6, 3, 0}, + {86, 1, 6, 1, 253, 1, 7, 0, 1, 1, 8, 49, 25, 6, 3, 0}, + {86, 2, 7, 2, 254, 2, 6, 0, 1, 1, 8, 49, 25, 6, 3, 0}, + {86, 3, 24, 3, 255, 3, 5, 0, 1, 1, 8, 49, 25, 6, 3, 0}, + // chip: 256 (5), ladder: 13 (29), layer: 6, disk: 3, half: 0, zone: 0 + {87, 0, 0, 4, 256, 0, 8, 1, 1, 1, 8, 49, 25, 6, 3, 0}, + {87, 1, 1, 5, 257, 1, 7, 1, 1, 1, 8, 49, 25, 6, 3, 0}, + {87, 2, 2, 6, 258, 2, 6, 1, 1, 1, 8, 49, 25, 6, 3, 0}, + {87, 3, 3, 7, 259, 3, 5, 1, 1, 1, 8, 49, 25, 6, 3, 0}, + // chip: 260 (5), ladder: 14 (29), layer: 6, disk: 3, half: 0, zone: 0 + {88, 0, 17, 8, 260, 0, 8, 2, 1, 1, 8, 49, 25, 6, 3, 0}, + {88, 1, 16, 9, 261, 1, 7, 2, 1, 1, 8, 49, 25, 6, 3, 0}, + {88, 2, 15, 10, 262, 2, 6, 2, 1, 1, 8, 49, 25, 6, 3, 0}, + {88, 3, 14, 11, 263, 3, 5, 2, 1, 1, 8, 49, 25, 6, 3, 0}, + // chip: 264 (5), ladder: 15 (29), layer: 6, disk: 3, half: 0, zone: 0 + {89, 0, 22, 12, 264, 0, 8, 3, 1, 1, 8, 49, 25, 6, 3, 0}, + {89, 1, 21, 13, 265, 1, 7, 3, 1, 1, 8, 49, 25, 6, 3, 0}, + {89, 2, 20, 14, 266, 2, 6, 3, 1, 1, 8, 49, 25, 6, 3, 0}, + {89, 3, 19, 15, 267, 3, 5, 3, 1, 1, 8, 49, 25, 6, 3, 0}, + // chip: 268 (5), ladder: 16 (29), layer: 6, disk: 3, half: 0, zone: 0 + {90, 0, 5, 0, 268, 0, 8, 0, 2, 2, 8, 50, 26, 6, 3, 0}, + {90, 1, 6, 1, 269, 1, 7, 0, 2, 2, 8, 50, 26, 6, 3, 0}, + {90, 2, 7, 2, 270, 2, 6, 0, 2, 2, 8, 50, 26, 6, 3, 0}, + {90, 3, 24, 3, 271, 3, 5, 0, 2, 2, 8, 50, 26, 6, 3, 0}, + // chip: 272 (5), ladder: 17 (29), layer: 6, disk: 3, half: 0, zone: 0 + {91, 0, 0, 4, 272, 0, 8, 1, 2, 2, 8, 50, 26, 6, 3, 0}, + {91, 1, 1, 5, 273, 1, 7, 1, 2, 2, 8, 50, 26, 6, 3, 0}, + {91, 2, 2, 6, 274, 2, 6, 1, 2, 2, 8, 50, 26, 6, 3, 0}, + {91, 3, 3, 7, 275, 3, 5, 1, 2, 2, 8, 50, 26, 6, 3, 0}, + // chip: 276 (5), ladder: 18 (29), layer: 6, disk: 3, half: 0, zone: 0 + {92, 0, 17, 8, 276, 0, 8, 2, 2, 2, 8, 50, 26, 6, 3, 0}, + {92, 1, 16, 9, 277, 1, 7, 2, 2, 2, 8, 50, 26, 6, 3, 0}, + {92, 2, 15, 10, 278, 2, 6, 2, 2, 2, 8, 50, 26, 6, 3, 0}, + {92, 3, 14, 11, 279, 3, 5, 2, 2, 2, 8, 50, 26, 6, 3, 0}, + // chip: 280 (5), ladder: 19 (29), layer: 6, disk: 3, half: 0, zone: 0 + {93, 0, 22, 12, 280, 0, 8, 3, 2, 2, 8, 50, 26, 6, 3, 0}, + {93, 1, 21, 13, 281, 1, 7, 3, 2, 2, 8, 50, 26, 6, 3, 0}, + {93, 2, 20, 14, 282, 2, 6, 3, 2, 2, 8, 50, 26, 6, 3, 0}, + {93, 3, 19, 15, 283, 3, 5, 3, 2, 2, 8, 50, 26, 6, 3, 0}, + // chip: 284 (5), ladder: 20 (29), layer: 6, disk: 3, half: 0, zone: 0 + {94, 0, 5, 9, 284, 0, 8, 0, 3, 3, 6, 51, 27, 6, 3, 0}, + {94, 1, 6, 10, 285, 1, 7, 0, 3, 3, 6, 51, 27, 6, 3, 0}, + {94, 2, 7, 11, 286, 2, 6, 0, 3, 3, 6, 51, 27, 6, 3, 0}, + {94, 3, 24, 12, 287, 3, 5, 0, 3, 3, 6, 51, 27, 6, 3, 0}, + // chip: 288 (5), ladder: 21 (29), layer: 7, disk: 3, half: 0, zone: 0 + {95, 0, 5, 9, 288, 0, 8, 0, 3, 3, 6, 59, 31, 7, 3, 0}, + {95, 1, 6, 10, 289, 1, 7, 0, 3, 3, 6, 59, 31, 7, 3, 0}, + {95, 2, 7, 11, 290, 2, 6, 0, 3, 3, 6, 59, 31, 7, 3, 0}, + {95, 3, 24, 12, 291, 3, 5, 0, 3, 3, 6, 59, 31, 7, 3, 0}, + // chip: 292 (5), ladder: 22 (29), layer: 7, disk: 3, half: 0, zone: 0 + {96, 0, 22, 12, 292, 0, 8, 3, 2, 2, 8, 58, 30, 7, 3, 0}, + {96, 1, 21, 13, 293, 1, 7, 3, 2, 2, 8, 58, 30, 7, 3, 0}, + {96, 2, 20, 14, 294, 2, 6, 3, 2, 2, 8, 58, 30, 7, 3, 0}, + {96, 3, 19, 15, 295, 3, 5, 3, 2, 2, 8, 58, 30, 7, 3, 0}, + // chip: 296 (5), ladder: 23 (29), layer: 7, disk: 3, half: 0, zone: 0 + {97, 0, 17, 8, 296, 0, 8, 2, 2, 2, 8, 58, 30, 7, 3, 0}, + {97, 1, 16, 9, 297, 1, 7, 2, 2, 2, 8, 58, 30, 7, 3, 0}, + {97, 2, 15, 10, 298, 2, 6, 2, 2, 2, 8, 58, 30, 7, 3, 0}, + {97, 3, 14, 11, 299, 3, 5, 2, 2, 2, 8, 58, 30, 7, 3, 0}, + // chip: 300 (5), ladder: 24 (29), layer: 7, disk: 3, half: 0, zone: 0 + {98, 0, 0, 4, 300, 0, 8, 1, 2, 2, 8, 58, 30, 7, 3, 0}, + {98, 1, 1, 5, 301, 1, 7, 1, 2, 2, 8, 58, 30, 7, 3, 0}, + {98, 2, 2, 6, 302, 2, 6, 1, 2, 2, 8, 58, 30, 7, 3, 0}, + {98, 3, 3, 7, 303, 3, 5, 1, 2, 2, 8, 58, 30, 7, 3, 0}, + // chip: 304 (5), ladder: 25 (29), layer: 7, disk: 3, half: 0, zone: 0 + {99, 0, 5, 0, 304, 0, 8, 0, 2, 2, 8, 58, 30, 7, 3, 0}, + {99, 1, 6, 1, 305, 1, 7, 0, 2, 2, 8, 58, 30, 7, 3, 0}, + {99, 2, 7, 2, 306, 2, 6, 0, 2, 2, 8, 58, 30, 7, 3, 0}, + {99, 3, 24, 3, 307, 3, 5, 0, 2, 2, 8, 58, 30, 7, 3, 0}, + // chip: 308 (5), ladder: 26 (29), layer: 7, disk: 3, half: 0, zone: 0 + {100, 0, 22, 12, 308, 0, 8, 3, 1, 1, 8, 57, 29, 7, 3, 0}, + {100, 1, 21, 13, 309, 1, 7, 3, 1, 1, 8, 57, 29, 7, 3, 0}, + {100, 2, 20, 14, 310, 2, 6, 3, 1, 1, 8, 57, 29, 7, 3, 0}, + {100, 3, 19, 15, 311, 3, 5, 3, 1, 1, 8, 57, 29, 7, 3, 0}, + // chip: 312 (5), ladder: 27 (29), layer: 7, disk: 3, half: 0, zone: 0 + {101, 0, 17, 8, 312, 0, 8, 2, 1, 1, 8, 57, 29, 7, 3, 0}, + {101, 1, 16, 9, 313, 1, 7, 2, 1, 1, 8, 57, 29, 7, 3, 0}, + {101, 2, 15, 10, 314, 2, 6, 2, 1, 1, 8, 57, 29, 7, 3, 0}, + {101, 3, 14, 11, 315, 3, 5, 2, 1, 1, 8, 57, 29, 7, 3, 0}, + // chip: 316 (5), ladder: 28 (29), layer: 7, disk: 3, half: 0, zone: 0 + {102, 0, 0, 4, 316, 0, 8, 1, 1, 1, 8, 57, 29, 7, 3, 0}, + {102, 1, 1, 5, 317, 1, 7, 1, 1, 1, 8, 57, 29, 7, 3, 0}, + {102, 2, 2, 6, 318, 2, 6, 1, 1, 1, 8, 57, 29, 7, 3, 0}, + {102, 3, 3, 7, 319, 3, 5, 1, 1, 1, 8, 57, 29, 7, 3, 0}, + // chip: 320 (5), ladder: 29 (29), layer: 7, disk: 3, half: 0, zone: 0 + {103, 0, 5, 0, 320, 0, 8, 0, 1, 1, 8, 57, 29, 7, 3, 0}, + {103, 1, 6, 1, 321, 1, 7, 0, 1, 1, 8, 57, 29, 7, 3, 0}, + {103, 2, 7, 2, 322, 2, 6, 0, 1, 1, 8, 57, 29, 7, 3, 0}, + {103, 3, 24, 3, 323, 3, 5, 0, 1, 1, 8, 57, 29, 7, 3, 0}, + // chip: 324 (5), ladder: 30 (29), layer: 7, disk: 3, half: 0, zone: 0 + {104, 0, 22, 10, 324, 0, 8, 3, 0, 0, 7, 56, 28, 7, 3, 0}, + {104, 1, 21, 11, 325, 1, 7, 3, 0, 0, 7, 56, 28, 7, 3, 0}, + {104, 2, 20, 12, 326, 2, 6, 3, 0, 0, 7, 56, 28, 7, 3, 0}, + {104, 3, 19, 13, 327, 3, 5, 3, 0, 0, 7, 56, 28, 7, 3, 0}, + // chip: 328 (5), ladder: 31 (29), layer: 7, disk: 3, half: 0, zone: 0 + {105, 0, 17, 6, 328, 0, 8, 2, 0, 0, 7, 56, 28, 7, 3, 0}, + {105, 1, 16, 7, 329, 1, 7, 2, 0, 0, 7, 56, 28, 7, 3, 0}, + {105, 2, 15, 8, 330, 2, 6, 2, 0, 0, 7, 56, 28, 7, 3, 0}, + {105, 3, 14, 9, 331, 3, 5, 2, 0, 0, 7, 56, 28, 7, 3, 0}, + // chip: 332 (5), ladder: 0 (29), layer: 8, disk: 4, half: 0, zone: 0 + {106, 0, 5, 0, 332, 0, 8, 0, 0, 0, 11, 64, 32, 8, 4, 0}, + {106, 1, 6, 1, 333, 1, 7, 0, 0, 0, 11, 64, 32, 8, 4, 0}, + {106, 2, 7, 2, 334, 2, 6, 0, 0, 0, 11, 64, 32, 8, 4, 0}, + // chip: 335 (5), ladder: 1 (29), layer: 8, disk: 4, half: 0, zone: 0 + {107, 0, 0, 3, 335, 0, 8, 1, 0, 0, 11, 64, 32, 8, 4, 0}, + {107, 1, 1, 4, 336, 1, 7, 1, 0, 0, 11, 64, 32, 8, 4, 0}, + {107, 2, 2, 5, 337, 2, 6, 1, 0, 0, 11, 64, 32, 8, 4, 0}, + // chip: 338 (5), ladder: 2 (29), layer: 8, disk: 4, half: 0, zone: 0 + {108, 0, 17, 0, 338, 0, 8, 2, 3, 3, 12, 67, 35, 8, 4, 0}, + {108, 1, 16, 1, 339, 1, 7, 2, 3, 3, 12, 67, 35, 8, 4, 0}, + {108, 2, 15, 2, 340, 2, 6, 2, 3, 3, 12, 67, 35, 8, 4, 0}, + // chip: 341 (5), ladder: 3 (29), layer: 8, disk: 4, half: 0, zone: 0 + {109, 0, 22, 3, 341, 0, 8, 3, 3, 3, 12, 67, 35, 8, 4, 0}, + {109, 1, 21, 4, 342, 1, 7, 3, 3, 3, 12, 67, 35, 8, 4, 0}, + {109, 2, 20, 5, 343, 2, 6, 3, 3, 3, 12, 67, 35, 8, 4, 0}, + // chip: 344 (5), ladder: 4 (29), layer: 9, disk: 4, half: 0, zone: 0 + {110, 0, 22, 3, 344, 0, 8, 3, 3, 3, 12, 75, 39, 9, 4, 0}, + {110, 1, 21, 4, 345, 1, 7, 3, 3, 3, 12, 75, 39, 9, 4, 0}, + {110, 2, 20, 5, 346, 2, 6, 3, 3, 3, 12, 75, 39, 9, 4, 0}, + // chip: 347 (5), ladder: 5 (29), layer: 9, disk: 4, half: 0, zone: 0 + {111, 0, 17, 0, 347, 0, 8, 2, 3, 3, 12, 75, 39, 9, 4, 0}, + {111, 1, 16, 1, 348, 1, 7, 2, 3, 3, 12, 75, 39, 9, 4, 0}, + {111, 2, 15, 2, 349, 2, 6, 2, 3, 3, 12, 75, 39, 9, 4, 0}, + // chip: 350 (5), ladder: 6 (29), layer: 9, disk: 4, half: 0, zone: 0 + {112, 0, 0, 3, 350, 0, 8, 1, 0, 0, 11, 72, 36, 9, 4, 0}, + {112, 1, 1, 4, 351, 1, 7, 1, 0, 0, 11, 72, 36, 9, 4, 0}, + {112, 2, 2, 5, 352, 2, 6, 1, 0, 0, 11, 72, 36, 9, 4, 0}, + // chip: 353 (5), ladder: 7 (29), layer: 9, disk: 4, half: 0, zone: 0 + {113, 0, 5, 0, 353, 0, 8, 0, 0, 0, 11, 72, 36, 9, 4, 0}, + {113, 1, 6, 1, 354, 1, 7, 0, 0, 0, 11, 72, 36, 9, 4, 0}, + {113, 2, 7, 2, 355, 2, 6, 0, 0, 0, 11, 72, 36, 9, 4, 0}, + // chip: 356 (5), ladder: 8 (29), layer: 8, disk: 4, half: 0, zone: 0 + {114, 0, 17, 6, 356, 0, 8, 2, 0, 0, 11, 64, 32, 8, 4, 0}, + {114, 1, 16, 7, 357, 1, 7, 2, 0, 0, 11, 64, 32, 8, 4, 0}, + {114, 2, 15, 8, 358, 2, 6, 2, 0, 0, 11, 64, 32, 8, 4, 0}, + {114, 3, 14, 9, 359, 3, 5, 2, 0, 0, 11, 64, 32, 8, 4, 0}, + // chip: 360 (5), ladder: 9 (29), layer: 8, disk: 4, half: 0, zone: 0 + {115, 0, 22, 10, 360, 0, 8, 3, 0, 0, 11, 64, 32, 8, 4, 0}, + {115, 1, 21, 11, 361, 1, 7, 3, 0, 0, 11, 64, 32, 8, 4, 0}, + {115, 2, 20, 12, 362, 2, 6, 3, 0, 0, 11, 64, 32, 8, 4, 0}, + {115, 3, 19, 13, 363, 3, 5, 3, 0, 0, 11, 64, 32, 8, 4, 0}, + // chip: 364 (5), ladder: 10 (29), layer: 8, disk: 4, half: 0, zone: 0 + {116, 0, 0, 0, 364, 0, 8, 1, 1, 1, 9, 65, 33, 8, 4, 0}, + {116, 1, 1, 1, 365, 1, 7, 1, 1, 1, 9, 65, 33, 8, 4, 0}, + {116, 2, 2, 2, 366, 2, 6, 1, 1, 1, 9, 65, 33, 8, 4, 0}, + {116, 3, 3, 3, 367, 3, 5, 1, 1, 1, 9, 65, 33, 8, 4, 0}, + // chip: 368 (5), ladder: 11 (29), layer: 8, disk: 4, half: 0, zone: 0 + {117, 0, 17, 4, 368, 0, 8, 2, 1, 1, 9, 65, 33, 8, 4, 0}, + {117, 1, 16, 5, 369, 1, 7, 2, 1, 1, 9, 65, 33, 8, 4, 0}, + {117, 2, 15, 6, 370, 2, 6, 2, 1, 1, 9, 65, 33, 8, 4, 0}, + {117, 3, 14, 7, 371, 3, 5, 2, 1, 1, 9, 65, 33, 8, 4, 0}, + // chip: 372 (5), ladder: 12 (29), layer: 8, disk: 4, half: 0, zone: 0 + {118, 0, 22, 8, 372, 0, 8, 3, 1, 1, 9, 65, 33, 8, 4, 0}, + {118, 1, 21, 9, 373, 1, 7, 3, 1, 1, 9, 65, 33, 8, 4, 0}, + {118, 2, 20, 10, 374, 2, 6, 3, 1, 1, 9, 65, 33, 8, 4, 0}, + {118, 3, 19, 11, 375, 3, 5, 3, 1, 1, 9, 65, 33, 8, 4, 0}, + // chip: 376 (5), ladder: 13 (29), layer: 8, disk: 4, half: 0, zone: 0 + {119, 0, 5, 0, 376, 0, 8, 0, 2, 2, 10, 66, 34, 8, 4, 0}, + {119, 1, 6, 1, 377, 1, 7, 0, 2, 2, 10, 66, 34, 8, 4, 0}, + {119, 2, 7, 2, 378, 2, 6, 0, 2, 2, 10, 66, 34, 8, 4, 0}, + {119, 3, 24, 3, 379, 3, 5, 0, 2, 2, 10, 66, 34, 8, 4, 0}, + // chip: 380 (5), ladder: 14 (29), layer: 8, disk: 4, half: 0, zone: 0 + {120, 0, 0, 4, 380, 0, 8, 1, 2, 2, 10, 66, 34, 8, 4, 0}, + {120, 1, 1, 5, 381, 1, 7, 1, 2, 2, 10, 66, 34, 8, 4, 0}, + {120, 2, 2, 6, 382, 2, 6, 1, 2, 2, 10, 66, 34, 8, 4, 0}, + {120, 3, 3, 7, 383, 3, 5, 1, 2, 2, 10, 66, 34, 8, 4, 0}, + // chip: 384 (5), ladder: 15 (29), layer: 8, disk: 4, half: 0, zone: 0 + {121, 0, 5, 6, 384, 0, 8, 0, 3, 3, 12, 67, 35, 8, 4, 0}, + {121, 1, 6, 7, 385, 1, 7, 0, 3, 3, 12, 67, 35, 8, 4, 0}, + {121, 2, 7, 8, 386, 2, 6, 0, 3, 3, 12, 67, 35, 8, 4, 0}, + {121, 3, 24, 9, 387, 3, 5, 0, 3, 3, 12, 67, 35, 8, 4, 0}, + // chip: 388 (5), ladder: 16 (29), layer: 8, disk: 4, half: 0, zone: 0 + {122, 0, 0, 10, 388, 0, 8, 1, 3, 3, 12, 67, 35, 8, 4, 0}, + {122, 1, 1, 11, 389, 1, 7, 1, 3, 3, 12, 67, 35, 8, 4, 0}, + {122, 2, 2, 12, 390, 2, 6, 1, 3, 3, 12, 67, 35, 8, 4, 0}, + {122, 3, 3, 13, 391, 3, 5, 1, 3, 3, 12, 67, 35, 8, 4, 0}, + // chip: 392 (5), ladder: 17 (29), layer: 9, disk: 4, half: 0, zone: 0 + {123, 0, 0, 10, 392, 0, 8, 1, 3, 3, 12, 75, 39, 9, 4, 0}, + {123, 1, 1, 11, 393, 1, 7, 1, 3, 3, 12, 75, 39, 9, 4, 0}, + {123, 2, 2, 12, 394, 2, 6, 1, 3, 3, 12, 75, 39, 9, 4, 0}, + {123, 3, 3, 13, 395, 3, 5, 1, 3, 3, 12, 75, 39, 9, 4, 0}, + // chip: 396 (5), ladder: 18 (29), layer: 9, disk: 4, half: 0, zone: 0 + {124, 0, 5, 6, 396, 0, 8, 0, 3, 3, 12, 75, 39, 9, 4, 0}, + {124, 1, 6, 7, 397, 1, 7, 0, 3, 3, 12, 75, 39, 9, 4, 0}, + {124, 2, 7, 8, 398, 2, 6, 0, 3, 3, 12, 75, 39, 9, 4, 0}, + {124, 3, 24, 9, 399, 3, 5, 0, 3, 3, 12, 75, 39, 9, 4, 0}, + // chip: 400 (5), ladder: 19 (29), layer: 9, disk: 4, half: 0, zone: 0 + {125, 0, 0, 4, 400, 0, 8, 1, 2, 2, 10, 74, 38, 9, 4, 0}, + {125, 1, 1, 5, 401, 1, 7, 1, 2, 2, 10, 74, 38, 9, 4, 0}, + {125, 2, 2, 6, 402, 2, 6, 1, 2, 2, 10, 74, 38, 9, 4, 0}, + {125, 3, 3, 7, 403, 3, 5, 1, 2, 2, 10, 74, 38, 9, 4, 0}, + // chip: 404 (5), ladder: 20 (29), layer: 9, disk: 4, half: 0, zone: 0 + {126, 0, 5, 0, 404, 0, 8, 0, 2, 2, 10, 74, 38, 9, 4, 0}, + {126, 1, 6, 1, 405, 1, 7, 0, 2, 2, 10, 74, 38, 9, 4, 0}, + {126, 2, 7, 2, 406, 2, 6, 0, 2, 2, 10, 74, 38, 9, 4, 0}, + {126, 3, 24, 3, 407, 3, 5, 0, 2, 2, 10, 74, 38, 9, 4, 0}, + // chip: 408 (5), ladder: 21 (29), layer: 9, disk: 4, half: 0, zone: 0 + {127, 0, 22, 8, 408, 0, 8, 3, 1, 1, 9, 73, 37, 9, 4, 0}, + {127, 1, 21, 9, 409, 1, 7, 3, 1, 1, 9, 73, 37, 9, 4, 0}, + {127, 2, 20, 10, 410, 2, 6, 3, 1, 1, 9, 73, 37, 9, 4, 0}, + {127, 3, 19, 11, 411, 3, 5, 3, 1, 1, 9, 73, 37, 9, 4, 0}, + // chip: 412 (5), ladder: 22 (29), layer: 9, disk: 4, half: 0, zone: 0 + {128, 0, 17, 4, 412, 0, 8, 2, 1, 1, 9, 73, 37, 9, 4, 0}, + {128, 1, 16, 5, 413, 1, 7, 2, 1, 1, 9, 73, 37, 9, 4, 0}, + {128, 2, 15, 6, 414, 2, 6, 2, 1, 1, 9, 73, 37, 9, 4, 0}, + {128, 3, 14, 7, 415, 3, 5, 2, 1, 1, 9, 73, 37, 9, 4, 0}, + // chip: 416 (5), ladder: 23 (29), layer: 9, disk: 4, half: 0, zone: 0 + {129, 0, 0, 0, 416, 0, 8, 1, 1, 1, 9, 73, 37, 9, 4, 0}, + {129, 1, 1, 1, 417, 1, 7, 1, 1, 1, 9, 73, 37, 9, 4, 0}, + {129, 2, 2, 2, 418, 2, 6, 1, 1, 1, 9, 73, 37, 9, 4, 0}, + {129, 3, 3, 3, 419, 3, 5, 1, 1, 1, 9, 73, 37, 9, 4, 0}, + // chip: 420 (5), ladder: 24 (29), layer: 9, disk: 4, half: 0, zone: 0 + {130, 0, 22, 10, 420, 0, 8, 3, 0, 0, 11, 72, 36, 9, 4, 0}, + {130, 1, 21, 11, 421, 1, 7, 3, 0, 0, 11, 72, 36, 9, 4, 0}, + {130, 2, 20, 12, 422, 2, 6, 3, 0, 0, 11, 72, 36, 9, 4, 0}, + {130, 3, 19, 13, 423, 3, 5, 3, 0, 0, 11, 72, 36, 9, 4, 0}, + // chip: 424 (5), ladder: 25 (29), layer: 9, disk: 4, half: 0, zone: 0 + {131, 0, 17, 6, 424, 0, 8, 2, 0, 0, 11, 72, 36, 9, 4, 0}, + {131, 1, 16, 7, 425, 1, 7, 2, 0, 0, 11, 72, 36, 9, 4, 0}, + {131, 2, 15, 8, 426, 2, 6, 2, 0, 0, 11, 72, 36, 9, 4, 0}, + {131, 3, 14, 9, 427, 3, 5, 2, 0, 0, 11, 72, 36, 9, 4, 0}, + // chip: 428 (5), ladder: 26 (29), layer: 8, disk: 4, half: 0, zone: 0 + {132, 0, 12, 14, 428, 0, 8, 4, 0, 0, 11, 64, 32, 8, 4, 0}, + {132, 1, 11, 15, 429, 1, 7, 4, 0, 0, 11, 64, 32, 8, 4, 0}, + {132, 2, 10, 16, 430, 2, 6, 4, 0, 0, 11, 64, 32, 8, 4, 0}, + {132, 3, 9, 17, 431, 3, 5, 4, 0, 0, 11, 64, 32, 8, 4, 0}, + {132, 4, 8, 18, 432, 4, 4, 4, 0, 0, 11, 64, 32, 8, 4, 0}, + // chip: 433 (5), ladder: 27 (29), layer: 8, disk: 4, half: 0, zone: 0 + {133, 0, 5, 12, 433, 0, 8, 0, 1, 1, 9, 65, 33, 8, 4, 0}, + {133, 1, 6, 13, 434, 1, 7, 0, 1, 1, 9, 65, 33, 8, 4, 0}, + {133, 2, 7, 14, 435, 2, 6, 0, 1, 1, 9, 65, 33, 8, 4, 0}, + {133, 3, 24, 15, 436, 3, 5, 0, 1, 1, 9, 65, 33, 8, 4, 0}, + {133, 4, 23, 16, 437, 4, 4, 0, 1, 1, 9, 65, 33, 8, 4, 0}, + // chip: 438 (5), ladder: 28 (29), layer: 8, disk: 4, half: 0, zone: 0 + {134, 0, 17, 8, 438, 0, 8, 2, 2, 2, 10, 66, 34, 8, 4, 0}, + {134, 1, 16, 9, 439, 1, 7, 2, 2, 2, 10, 66, 34, 8, 4, 0}, + {134, 2, 15, 10, 440, 2, 6, 2, 2, 2, 10, 66, 34, 8, 4, 0}, + {134, 3, 14, 11, 441, 3, 5, 2, 2, 2, 10, 66, 34, 8, 4, 0}, + {134, 4, 13, 12, 442, 4, 4, 2, 2, 2, 10, 66, 34, 8, 4, 0}, + // chip: 443 (5), ladder: 29 (29), layer: 8, disk: 4, half: 0, zone: 0 + {135, 0, 22, 13, 443, 0, 8, 3, 2, 2, 10, 66, 34, 8, 4, 0}, + {135, 1, 21, 14, 444, 1, 7, 3, 2, 2, 10, 66, 34, 8, 4, 0}, + {135, 2, 20, 15, 445, 2, 6, 3, 2, 2, 10, 66, 34, 8, 4, 0}, + {135, 3, 19, 16, 446, 3, 5, 3, 2, 2, 10, 66, 34, 8, 4, 0}, + {135, 4, 18, 17, 447, 4, 4, 3, 2, 2, 10, 66, 34, 8, 4, 0}, + // chip: 448 (5), ladder: 30 (29), layer: 9, disk: 4, half: 0, zone: 0 + {136, 0, 22, 13, 448, 0, 8, 3, 2, 2, 10, 74, 38, 9, 4, 0}, + {136, 1, 21, 14, 449, 1, 7, 3, 2, 2, 10, 74, 38, 9, 4, 0}, + {136, 2, 20, 15, 450, 2, 6, 3, 2, 2, 10, 74, 38, 9, 4, 0}, + {136, 3, 19, 16, 451, 3, 5, 3, 2, 2, 10, 74, 38, 9, 4, 0}, + {136, 4, 18, 17, 452, 4, 4, 3, 2, 2, 10, 74, 38, 9, 4, 0}, + // chip: 453 (5), ladder: 31 (29), layer: 9, disk: 4, half: 0, zone: 0 + {137, 0, 17, 8, 453, 0, 8, 2, 2, 2, 10, 74, 38, 9, 4, 0}, + {137, 1, 16, 9, 454, 1, 7, 2, 2, 2, 10, 74, 38, 9, 4, 0}, + {137, 2, 15, 10, 455, 2, 6, 2, 2, 2, 10, 74, 38, 9, 4, 0}, + {137, 3, 14, 11, 456, 3, 5, 2, 2, 2, 10, 74, 38, 9, 4, 0}, + {137, 4, 13, 12, 457, 4, 4, 2, 2, 2, 10, 74, 38, 9, 4, 0}, + // chip: 458 (5), ladder: 32 (29), layer: 9, disk: 4, half: 0, zone: 0 + {138, 0, 5, 12, 458, 0, 8, 0, 1, 1, 9, 73, 37, 9, 4, 0}, + {138, 1, 6, 13, 459, 1, 7, 0, 1, 1, 9, 73, 37, 9, 4, 0}, + {138, 2, 7, 14, 460, 2, 6, 0, 1, 1, 9, 73, 37, 9, 4, 0}, + {138, 3, 24, 15, 461, 3, 5, 0, 1, 1, 9, 73, 37, 9, 4, 0}, + {138, 4, 23, 16, 462, 4, 4, 0, 1, 1, 9, 73, 37, 9, 4, 0}, // chip: 463 (5), ladder: 33 (29), layer: 9, disk: 4, half: 0, zone: 0 - {139, 0, 12, 14}, - {139, 1, 11, 15}, - {139, 2, 10, 16}, - {139, 3, 9, 17}, - {139, 4, 8, 18}, - // chip: 468 (2), ladder: 0 ( 0), layer: 0, disk: 0, half: 1, zone: 0 - {140, 0, 5, 0}, - {140, 1, 6, 1}, - // chip: 470 (2), ladder: 1 (10), layer: 0, disk: 0, half: 1, zone: 3 - {141, 0, 0, 0}, - {141, 1, 1, 1}, - // chip: 472 (2), ladder: 2 (11), layer: 0, disk: 0, half: 1, zone: 3 - {142, 0, 17, 2}, - {142, 1, 16, 3}, - // chip: 474 (2), ladder: 3 (12), layer: 1, disk: 0, half: 1, zone: 3 - {143, 0, 17, 2}, - {143, 1, 16, 3}, - // chip: 476 (2), ladder: 4 (13), layer: 1, disk: 0, half: 1, zone: 3 - {144, 0, 0, 0}, - {144, 1, 1, 1}, - // chip: 478 (2), ladder: 5 (23), layer: 1, disk: 0, half: 1, zone: 0 - {145, 0, 5, 0}, - {145, 1, 6, 1}, - // chip: 480 (3), ladder: 6 ( 1), layer: 0, disk: 0, half: 1, zone: 0 - {146, 0, 0, 2}, - {146, 1, 1, 3}, - {146, 2, 2, 4}, - // chip: 483 (3), ladder: 7 ( 2), layer: 0, disk: 0, half: 1, zone: 0 - {147, 0, 17, 5}, - {147, 1, 16, 6}, - {147, 2, 15, 7}, - // chip: 486 (3), ladder: 8 ( 3), layer: 0, disk: 0, half: 1, zone: 1 - {148, 0, 5, 0}, - {148, 1, 6, 1}, - {148, 2, 7, 2}, - // chip: 489 (3), ladder: 9 ( 4), layer: 0, disk: 0, half: 1, zone: 1 - {149, 0, 0, 3}, - {149, 1, 1, 4}, - {149, 2, 2, 5}, - // chip: 492 (3), ladder: 10 ( 5), layer: 0, disk: 0, half: 1, zone: 1 - {150, 0, 17, 6}, - {150, 1, 16, 7}, - {150, 2, 15, 8}, - // chip: 495 (3), ladder: 11 ( 6), layer: 0, disk: 0, half: 1, zone: 2 - {151, 0, 5, 0}, - {151, 1, 6, 1}, - {151, 2, 7, 2}, - // chip: 498 (3), ladder: 12 ( 7), layer: 0, disk: 0, half: 1, zone: 2 - {152, 0, 0, 3}, - {152, 1, 1, 4}, - {152, 2, 2, 5}, - // chip: 501 (3), ladder: 13 ( 8), layer: 0, disk: 0, half: 1, zone: 2 - {153, 0, 17, 6}, - {153, 1, 16, 7}, - {153, 2, 15, 8}, - // chip: 504 (3), ladder: 14 ( 9), layer: 0, disk: 0, half: 1, zone: 3 - {154, 0, 5, 4}, - {154, 1, 6, 5}, - {154, 2, 7, 6}, - // chip: 507 (3), ladder: 15 (14), layer: 1, disk: 0, half: 1, zone: 3 - {155, 0, 5, 4}, - {155, 1, 6, 5}, - {155, 2, 7, 6}, - // chip: 510 (3), ladder: 16 (15), layer: 1, disk: 0, half: 1, zone: 2 - {156, 0, 17, 6}, - {156, 1, 16, 7}, - {156, 2, 15, 8}, - // chip: 513 (3), ladder: 17 (16), layer: 1, disk: 0, half: 1, zone: 2 - {157, 0, 0, 3}, - {157, 1, 1, 4}, - {157, 2, 2, 5}, - // chip: 516 (3), ladder: 18 (17), layer: 1, disk: 0, half: 1, zone: 2 - {158, 0, 5, 0}, - {158, 1, 6, 1}, - {158, 2, 7, 2}, - // chip: 519 (3), ladder: 19 (18), layer: 1, disk: 0, half: 1, zone: 1 - {159, 0, 17, 6}, - {159, 1, 16, 7}, - {159, 2, 15, 8}, - // chip: 522 (3), ladder: 20 (19), layer: 1, disk: 0, half: 1, zone: 1 - {160, 0, 0, 3}, - {160, 1, 1, 4}, - {160, 2, 2, 5}, - // chip: 525 (3), ladder: 21 (20), layer: 1, disk: 0, half: 1, zone: 1 - {161, 0, 5, 0}, - {161, 1, 6, 1}, - {161, 2, 7, 2}, - // chip: 528 (3), ladder: 22 (21), layer: 1, disk: 0, half: 1, zone: 0 - {162, 0, 17, 5}, - {162, 1, 16, 6}, - {162, 2, 15, 7}, - // chip: 531 (3), ladder: 23 (22), layer: 1, disk: 0, half: 1, zone: 0 - {163, 0, 0, 2}, - {163, 1, 1, 3}, - {163, 2, 2, 4}, - // chip: 534 (2), ladder: 0 ( 0), layer: 2, disk: 1, half: 1, zone: 0 - {164, 0, 5, 0}, - {164, 1, 6, 1}, - // chip: 536 (2), ladder: 1 (10), layer: 2, disk: 1, half: 1, zone: 3 - {165, 0, 0, 0}, - {165, 1, 1, 1}, - // chip: 538 (2), ladder: 2 (11), layer: 2, disk: 1, half: 1, zone: 3 - {166, 0, 17, 2}, - {166, 1, 16, 3}, - // chip: 540 (2), ladder: 3 (12), layer: 3, disk: 1, half: 1, zone: 3 - {167, 0, 17, 2}, - {167, 1, 16, 3}, - // chip: 542 (2), ladder: 4 (13), layer: 3, disk: 1, half: 1, zone: 3 - {168, 0, 0, 0}, - {168, 1, 1, 1}, - // chip: 544 (2), ladder: 5 (23), layer: 3, disk: 1, half: 1, zone: 0 - {169, 0, 5, 0}, - {169, 1, 6, 1}, - // chip: 546 (3), ladder: 6 ( 1), layer: 2, disk: 1, half: 1, zone: 0 - {170, 0, 0, 2}, - {170, 1, 1, 3}, - {170, 2, 2, 4}, - // chip: 549 (3), ladder: 7 ( 2), layer: 2, disk: 1, half: 1, zone: 0 - {171, 0, 17, 5}, - {171, 1, 16, 6}, - {171, 2, 15, 7}, - // chip: 552 (3), ladder: 8 ( 3), layer: 2, disk: 1, half: 1, zone: 1 - {172, 0, 5, 0}, - {172, 1, 6, 1}, - {172, 2, 7, 2}, - // chip: 555 (3), ladder: 9 ( 4), layer: 2, disk: 1, half: 1, zone: 1 - {173, 0, 0, 3}, - {173, 1, 1, 4}, - {173, 2, 2, 5}, - // chip: 558 (3), ladder: 10 ( 5), layer: 2, disk: 1, half: 1, zone: 1 - {174, 0, 17, 6}, - {174, 1, 16, 7}, - {174, 2, 15, 8}, - // chip: 561 (3), ladder: 11 ( 6), layer: 2, disk: 1, half: 1, zone: 2 - {175, 0, 5, 0}, - {175, 1, 6, 1}, - {175, 2, 7, 2}, - // chip: 564 (3), ladder: 12 ( 7), layer: 2, disk: 1, half: 1, zone: 2 - {176, 0, 0, 3}, - {176, 1, 1, 4}, - {176, 2, 2, 5}, - // chip: 567 (3), ladder: 13 ( 8), layer: 2, disk: 1, half: 1, zone: 2 - {177, 0, 17, 6}, - {177, 1, 16, 7}, - {177, 2, 15, 8}, - // chip: 570 (3), ladder: 14 ( 9), layer: 2, disk: 1, half: 1, zone: 3 - {178, 0, 5, 4}, - {178, 1, 6, 5}, - {178, 2, 7, 6}, - // chip: 573 (3), ladder: 15 (14), layer: 3, disk: 1, half: 1, zone: 3 - {179, 0, 5, 4}, - {179, 1, 6, 5}, - {179, 2, 7, 6}, - // chip: 576 (3), ladder: 16 (15), layer: 3, disk: 1, half: 1, zone: 2 - {180, 0, 17, 6}, - {180, 1, 16, 7}, - {180, 2, 15, 8}, - // chip: 579 (3), ladder: 17 (16), layer: 3, disk: 1, half: 1, zone: 2 - {181, 0, 0, 3}, - {181, 1, 1, 4}, - {181, 2, 2, 5}, - // chip: 582 (3), ladder: 18 (17), layer: 3, disk: 1, half: 1, zone: 2 - {182, 0, 5, 0}, - {182, 1, 6, 1}, - {182, 2, 7, 2}, - // chip: 585 (3), ladder: 19 (18), layer: 3, disk: 1, half: 1, zone: 1 - {183, 0, 17, 6}, - {183, 1, 16, 7}, - {183, 2, 15, 8}, - // chip: 588 (3), ladder: 20 (19), layer: 3, disk: 1, half: 1, zone: 1 - {184, 0, 0, 3}, - {184, 1, 1, 4}, - {184, 2, 2, 5}, - // chip: 591 (3), ladder: 21 (20), layer: 3, disk: 1, half: 1, zone: 1 - {185, 0, 5, 0}, - {185, 1, 6, 1}, - {185, 2, 7, 2}, - // chip: 594 (3), ladder: 22 (21), layer: 3, disk: 1, half: 1, zone: 0 - {186, 0, 17, 5}, - {186, 1, 16, 6}, - {186, 2, 15, 7}, - // chip: 597 (3), ladder: 23 (22), layer: 3, disk: 1, half: 1, zone: 0 - {187, 0, 0, 2}, - {187, 1, 1, 3}, - {187, 2, 2, 4}, - // chip: 600 (2), ladder: 0 ( 0), layer: 4, disk: 2, half: 1, zone: 0 - {188, 0, 5, 0}, - {188, 1, 6, 1}, - // chip: 602 (2), ladder: 1 (12), layer: 4, disk: 2, half: 1, zone: 3 - {189, 0, 22, 0}, - {189, 1, 21, 1}, - // chip: 604 (2), ladder: 2 (13), layer: 5, disk: 2, half: 1, zone: 3 - {190, 0, 22, 0}, - {190, 1, 21, 1}, - // chip: 606 (2), ladder: 3 (25), layer: 5, disk: 2, half: 1, zone: 0 - {191, 0, 5, 0}, - {191, 1, 6, 1}, - // chip: 608 (3), ladder: 4 ( 1), layer: 4, disk: 2, half: 1, zone: 0 - {192, 0, 0, 2}, - {192, 1, 1, 3}, - {192, 2, 2, 4}, - // chip: 611 (3), ladder: 5 ( 2), layer: 4, disk: 2, half: 1, zone: 0 - {193, 0, 17, 5}, - {193, 1, 16, 6}, - {193, 2, 15, 7}, - // chip: 614 (3), ladder: 6 ( 5), layer: 4, disk: 2, half: 1, zone: 1 - {194, 0, 17, 0}, - {194, 1, 16, 1}, - {194, 2, 15, 2}, - // chip: 617 (3), ladder: 7 ( 6), layer: 4, disk: 2, half: 1, zone: 2 - {195, 0, 5, 0}, - {195, 1, 6, 1}, - {195, 2, 7, 2}, - // chip: 620 (3), ladder: 8 ( 7), layer: 4, disk: 2, half: 1, zone: 2 - {196, 0, 0, 3}, - {196, 1, 1, 4}, - {196, 2, 2, 5}, - // chip: 623 (3), ladder: 9 (10), layer: 4, disk: 2, half: 1, zone: 3 - {197, 0, 0, 2}, - {197, 1, 1, 3}, - {197, 2, 2, 4}, - // chip: 626 (3), ladder: 10 (11), layer: 4, disk: 2, half: 1, zone: 3 - {198, 0, 17, 5}, - {198, 1, 16, 6}, - {198, 2, 15, 7}, - // chip: 629 (3), ladder: 11 (14), layer: 5, disk: 2, half: 1, zone: 3 - {199, 0, 17, 5}, - {199, 1, 16, 6}, - {199, 2, 15, 7}, - // chip: 632 (3), ladder: 12 (15), layer: 5, disk: 2, half: 1, zone: 3 - {200, 0, 0, 2}, - {200, 1, 1, 3}, - {200, 2, 2, 4}, - // chip: 635 (3), ladder: 13 (18), layer: 5, disk: 2, half: 1, zone: 2 - {201, 0, 0, 3}, - {201, 1, 1, 4}, - {201, 2, 2, 5}, - // chip: 638 (3), ladder: 14 (19), layer: 5, disk: 2, half: 1, zone: 2 - {202, 0, 5, 0}, - {202, 1, 6, 1}, - {202, 2, 7, 2}, - // chip: 641 (3), ladder: 15 (20), layer: 5, disk: 2, half: 1, zone: 1 - {203, 0, 17, 0}, - {203, 1, 16, 1}, - {203, 2, 15, 2}, - // chip: 644 (3), ladder: 16 (23), layer: 5, disk: 2, half: 1, zone: 0 - {204, 0, 17, 5}, - {204, 1, 16, 6}, - {204, 2, 15, 7}, - // chip: 647 (3), ladder: 17 (24), layer: 5, disk: 2, half: 1, zone: 0 - {205, 0, 0, 2}, - {205, 1, 1, 3}, - {205, 2, 2, 4}, - // chip: 650 (4), ladder: 18 ( 3), layer: 4, disk: 2, half: 1, zone: 1 - {206, 0, 5, 3}, - {206, 1, 6, 4}, - {206, 2, 7, 5}, - {206, 3, 24, 6}, - // chip: 654 (4), ladder: 19 ( 4), layer: 4, disk: 2, half: 1, zone: 1 - {207, 0, 0, 7}, - {207, 1, 1, 8}, - {207, 2, 2, 9}, - {207, 3, 3, 10}, - // chip: 658 (4), ladder: 20 ( 8), layer: 4, disk: 2, half: 1, zone: 2 - {208, 0, 17, 6}, - {208, 1, 16, 7}, - {208, 2, 15, 8}, - {208, 3, 14, 9}, - // chip: 662 (4), ladder: 21 ( 9), layer: 4, disk: 2, half: 1, zone: 3 - {209, 0, 5, 8}, - {209, 1, 6, 9}, - {209, 2, 7, 10}, - {209, 3, 24, 11}, - // chip: 666 (4), ladder: 22 (16), layer: 5, disk: 2, half: 1, zone: 3 - {210, 0, 5, 8}, - {210, 1, 6, 9}, - {210, 2, 7, 10}, - {210, 3, 24, 11}, - // chip: 670 (4), ladder: 23 (17), layer: 5, disk: 2, half: 1, zone: 2 - {211, 0, 17, 6}, - {211, 1, 16, 7}, - {211, 2, 15, 8}, - {211, 3, 14, 9}, - // chip: 674 (4), ladder: 24 (21), layer: 5, disk: 2, half: 1, zone: 1 - {212, 0, 0, 7}, - {212, 1, 1, 8}, - {212, 2, 2, 9}, - {212, 3, 3, 10}, - // chip: 678 (4), ladder: 25 (22), layer: 5, disk: 2, half: 1, zone: 1 - {213, 0, 5, 3}, - {213, 1, 6, 4}, - {213, 2, 7, 5}, - {213, 3, 24, 6}, - // chip: 682 (3), ladder: 0 ( 0), layer: 6, disk: 3, half: 1, zone: 0 - {214, 0, 5, 0}, - {214, 1, 6, 1}, - {214, 2, 7, 2}, - // chip: 685 (3), ladder: 1 ( 1), layer: 6, disk: 3, half: 1, zone: 0 - {215, 0, 0, 3}, - {215, 1, 1, 4}, - {215, 2, 2, 5}, - // chip: 688 (3), ladder: 2 (13), layer: 6, disk: 3, half: 1, zone: 3 - {216, 0, 0, 0}, - {216, 1, 1, 1}, - {216, 2, 2, 2}, - // chip: 691 (3), ladder: 3 (14), layer: 6, disk: 3, half: 1, zone: 3 - {217, 0, 17, 3}, - {217, 1, 16, 4}, - {217, 2, 15, 5}, - // chip: 694 (3), ladder: 4 (15), layer: 6, disk: 3, half: 1, zone: 3 - {218, 0, 22, 6}, - {218, 1, 21, 7}, - {218, 2, 20, 8}, - // chip: 697 (3), ladder: 5 (16), layer: 7, disk: 3, half: 1, zone: 3 - {219, 0, 22, 6}, - {219, 1, 21, 7}, - {219, 2, 20, 8}, - // chip: 700 (3), ladder: 6 (17), layer: 7, disk: 3, half: 1, zone: 3 - {220, 0, 17, 3}, - {220, 1, 16, 4}, - {220, 2, 15, 5}, - // chip: 703 (3), ladder: 7 (18), layer: 7, disk: 3, half: 1, zone: 3 - {221, 0, 0, 0}, - {221, 1, 1, 1}, - {221, 2, 2, 2}, - // chip: 706 (3), ladder: 8 (30), layer: 7, disk: 3, half: 1, zone: 0 - {222, 0, 0, 3}, - {222, 1, 1, 4}, - {222, 2, 2, 5}, - // chip: 709 (3), ladder: 9 (31), layer: 7, disk: 3, half: 1, zone: 0 - {223, 0, 5, 0}, - {223, 1, 6, 1}, - {223, 2, 7, 2}, - // chip: 712 (4), ladder: 10 ( 2), layer: 6, disk: 3, half: 1, zone: 0 - {224, 0, 17, 6}, - {224, 1, 16, 7}, - {224, 2, 15, 8}, - {224, 3, 14, 9}, - // chip: 716 (4), ladder: 11 ( 3), layer: 6, disk: 3, half: 1, zone: 0 - {225, 0, 22, 10}, - {225, 1, 21, 11}, - {225, 2, 20, 12}, - {225, 3, 19, 13}, - // chip: 720 (4), ladder: 12 ( 4), layer: 6, disk: 3, half: 1, zone: 1 - {226, 0, 5, 0}, - {226, 1, 6, 1}, - {226, 2, 7, 2}, - {226, 3, 24, 3}, - // chip: 724 (4), ladder: 13 ( 5), layer: 6, disk: 3, half: 1, zone: 1 - {227, 0, 0, 4}, - {227, 1, 1, 5}, - {227, 2, 2, 6}, - {227, 3, 3, 7}, - // chip: 728 (4), ladder: 14 ( 6), layer: 6, disk: 3, half: 1, zone: 1 - {228, 0, 17, 8}, - {228, 1, 16, 9}, - {228, 2, 15, 10}, - {228, 3, 14, 11}, - // chip: 732 (4), ladder: 15 ( 7), layer: 6, disk: 3, half: 1, zone: 1 - {229, 0, 22, 12}, - {229, 1, 21, 13}, - {229, 2, 20, 14}, - {229, 3, 19, 15}, - // chip: 736 (4), ladder: 16 ( 8), layer: 6, disk: 3, half: 1, zone: 2 - {230, 0, 5, 0}, - {230, 1, 6, 1}, - {230, 2, 7, 2}, - {230, 3, 24, 3}, - // chip: 740 (4), ladder: 17 ( 9), layer: 6, disk: 3, half: 1, zone: 2 - {231, 0, 0, 4}, - {231, 1, 1, 5}, - {231, 2, 2, 6}, - {231, 3, 3, 7}, - // chip: 744 (4), ladder: 18 (10), layer: 6, disk: 3, half: 1, zone: 2 - {232, 0, 17, 8}, - {232, 1, 16, 9}, - {232, 2, 15, 10}, - {232, 3, 14, 11}, - // chip: 748 (4), ladder: 19 (11), layer: 6, disk: 3, half: 1, zone: 2 - {233, 0, 22, 12}, - {233, 1, 21, 13}, - {233, 2, 20, 14}, - {233, 3, 19, 15}, - // chip: 752 (4), ladder: 20 (12), layer: 6, disk: 3, half: 1, zone: 3 - {234, 0, 5, 9}, - {234, 1, 6, 10}, - {234, 2, 7, 11}, - {234, 3, 24, 12}, - // chip: 756 (4), ladder: 21 (19), layer: 7, disk: 3, half: 1, zone: 3 - {235, 0, 5, 9}, - {235, 1, 6, 10}, - {235, 2, 7, 11}, - {235, 3, 24, 12}, - // chip: 760 (4), ladder: 22 (20), layer: 7, disk: 3, half: 1, zone: 2 - {236, 0, 22, 12}, - {236, 1, 21, 13}, - {236, 2, 20, 14}, - {236, 3, 19, 15}, - // chip: 764 (4), ladder: 23 (21), layer: 7, disk: 3, half: 1, zone: 2 - {237, 0, 17, 8}, - {237, 1, 16, 9}, - {237, 2, 15, 10}, - {237, 3, 14, 11}, - // chip: 768 (4), ladder: 24 (22), layer: 7, disk: 3, half: 1, zone: 2 - {238, 0, 0, 4}, - {238, 1, 1, 5}, - {238, 2, 2, 6}, - {238, 3, 3, 7}, - // chip: 772 (4), ladder: 25 (23), layer: 7, disk: 3, half: 1, zone: 2 - {239, 0, 5, 0}, - {239, 1, 6, 1}, - {239, 2, 7, 2}, - {239, 3, 24, 3}, - // chip: 776 (4), ladder: 26 (24), layer: 7, disk: 3, half: 1, zone: 1 - {240, 0, 22, 12}, - {240, 1, 21, 13}, - {240, 2, 20, 14}, - {240, 3, 19, 15}, - // chip: 780 (4), ladder: 27 (25), layer: 7, disk: 3, half: 1, zone: 1 - {241, 0, 17, 8}, - {241, 1, 16, 9}, - {241, 2, 15, 10}, - {241, 3, 14, 11}, - // chip: 784 (4), ladder: 28 (26), layer: 7, disk: 3, half: 1, zone: 1 - {242, 0, 0, 4}, - {242, 1, 1, 5}, - {242, 2, 2, 6}, - {242, 3, 3, 7}, - // chip: 788 (4), ladder: 29 (27), layer: 7, disk: 3, half: 1, zone: 1 - {243, 0, 5, 0}, - {243, 1, 6, 1}, - {243, 2, 7, 2}, - {243, 3, 24, 3}, - // chip: 792 (4), ladder: 30 (28), layer: 7, disk: 3, half: 1, zone: 0 - {244, 0, 22, 10}, - {244, 1, 21, 11}, - {244, 2, 20, 12}, - {244, 3, 19, 13}, - // chip: 796 (4), ladder: 31 (29), layer: 7, disk: 3, half: 1, zone: 0 - {245, 0, 17, 6}, - {245, 1, 16, 7}, - {245, 2, 15, 8}, - {245, 3, 14, 9}, - // chip: 800 (3), ladder: 0 ( 0), layer: 8, disk: 4, half: 1, zone: 0 - {246, 0, 5, 0}, - {246, 1, 6, 1}, - {246, 2, 7, 2}, - // chip: 803 (3), ladder: 1 ( 1), layer: 8, disk: 4, half: 1, zone: 0 - {247, 0, 0, 3}, - {247, 1, 1, 4}, - {247, 2, 2, 5}, - // chip: 806 (3), ladder: 2 (15), layer: 8, disk: 4, half: 1, zone: 3 - {248, 0, 17, 0}, - {248, 1, 16, 1}, - {248, 2, 15, 2}, - // chip: 809 (3), ladder: 3 (16), layer: 8, disk: 4, half: 1, zone: 3 - {249, 0, 22, 3}, - {249, 1, 21, 4}, - {249, 2, 20, 5}, - // chip: 812 (3), ladder: 4 (17), layer: 9, disk: 4, half: 1, zone: 3 - {250, 0, 22, 3}, - {250, 1, 21, 4}, - {250, 2, 20, 5}, - // chip: 815 (3), ladder: 5 (18), layer: 9, disk: 4, half: 1, zone: 3 - {251, 0, 17, 0}, - {251, 1, 16, 1}, - {251, 2, 15, 2}, - // chip: 818 (3), ladder: 6 (32), layer: 9, disk: 4, half: 1, zone: 0 - {252, 0, 0, 3}, - {252, 1, 1, 4}, - {252, 2, 2, 5}, - // chip: 821 (3), ladder: 7 (33), layer: 9, disk: 4, half: 1, zone: 0 - {253, 0, 5, 0}, - {253, 1, 6, 1}, - {253, 2, 7, 2}, - // chip: 824 (4), ladder: 8 ( 2), layer: 8, disk: 4, half: 1, zone: 0 - {254, 0, 17, 6}, - {254, 1, 16, 7}, - {254, 2, 15, 8}, - {254, 3, 14, 9}, - // chip: 828 (4), ladder: 9 ( 3), layer: 8, disk: 4, half: 1, zone: 0 - {255, 0, 22, 10}, - {255, 1, 21, 11}, - {255, 2, 20, 12}, - {255, 3, 19, 13}, - // chip: 832 (4), ladder: 10 ( 6), layer: 8, disk: 4, half: 1, zone: 1 - {256, 0, 0, 0}, - {256, 1, 1, 1}, - {256, 2, 2, 2}, - {256, 3, 3, 3}, - // chip: 836 (4), ladder: 11 ( 7), layer: 8, disk: 4, half: 1, zone: 1 - {257, 0, 17, 4}, - {257, 1, 16, 5}, - {257, 2, 15, 6}, - {257, 3, 14, 7}, - // chip: 840 (4), ladder: 12 ( 8), layer: 8, disk: 4, half: 1, zone: 1 - {258, 0, 22, 8}, - {258, 1, 21, 9}, - {258, 2, 20, 10}, - {258, 3, 19, 11}, - // chip: 844 (4), ladder: 13 ( 9), layer: 8, disk: 4, half: 1, zone: 2 - {259, 0, 5, 0}, - {259, 1, 6, 1}, - {259, 2, 7, 2}, - {259, 3, 24, 3}, - // chip: 848 (4), ladder: 14 (10), layer: 8, disk: 4, half: 1, zone: 2 - {260, 0, 0, 4}, - {260, 1, 1, 5}, - {260, 2, 2, 6}, - {260, 3, 3, 7}, - // chip: 852 (4), ladder: 15 (13), layer: 8, disk: 4, half: 1, zone: 3 - {261, 0, 5, 6}, - {261, 1, 6, 7}, - {261, 2, 7, 8}, - {261, 3, 24, 9}, - // chip: 856 (4), ladder: 16 (14), layer: 8, disk: 4, half: 1, zone: 3 - {262, 0, 0, 10}, - {262, 1, 1, 11}, - {262, 2, 2, 12}, - {262, 3, 3, 13}, - // chip: 860 (4), ladder: 17 (19), layer: 9, disk: 4, half: 1, zone: 3 - {263, 0, 0, 10}, - {263, 1, 1, 11}, - {263, 2, 2, 12}, - {263, 3, 3, 13}, - // chip: 864 (4), ladder: 18 (20), layer: 9, disk: 4, half: 1, zone: 3 - {264, 0, 5, 6}, - {264, 1, 6, 7}, - {264, 2, 7, 8}, - {264, 3, 24, 9}, - // chip: 868 (4), ladder: 19 (23), layer: 9, disk: 4, half: 1, zone: 2 - {265, 0, 0, 4}, - {265, 1, 1, 5}, - {265, 2, 2, 6}, - {265, 3, 3, 7}, - // chip: 872 (4), ladder: 20 (24), layer: 9, disk: 4, half: 1, zone: 2 - {266, 0, 5, 0}, - {266, 1, 6, 1}, - {266, 2, 7, 2}, - {266, 3, 24, 3}, - // chip: 876 (4), ladder: 21 (25), layer: 9, disk: 4, half: 1, zone: 1 - {267, 0, 22, 8}, - {267, 1, 21, 9}, - {267, 2, 20, 10}, - {267, 3, 19, 11}, - // chip: 880 (4), ladder: 22 (26), layer: 9, disk: 4, half: 1, zone: 1 - {268, 0, 17, 4}, - {268, 1, 16, 5}, - {268, 2, 15, 6}, - {268, 3, 14, 7}, - // chip: 884 (4), ladder: 23 (27), layer: 9, disk: 4, half: 1, zone: 1 - {269, 0, 0, 0}, - {269, 1, 1, 1}, - {269, 2, 2, 2}, - {269, 3, 3, 3}, - // chip: 888 (4), ladder: 24 (30), layer: 9, disk: 4, half: 1, zone: 0 - {270, 0, 22, 10}, - {270, 1, 21, 11}, - {270, 2, 20, 12}, - {270, 3, 19, 13}, - // chip: 892 (4), ladder: 25 (31), layer: 9, disk: 4, half: 1, zone: 0 - {271, 0, 17, 6}, - {271, 1, 16, 7}, - {271, 2, 15, 8}, - {271, 3, 14, 9}, - // chip: 896 (5), ladder: 26 ( 4), layer: 8, disk: 4, half: 1, zone: 0 - {272, 0, 12, 14}, - {272, 1, 11, 15}, - {272, 2, 10, 16}, - {272, 3, 9, 17}, - {272, 4, 8, 18}, - // chip: 901 (5), ladder: 27 ( 5), layer: 8, disk: 4, half: 1, zone: 1 - {273, 0, 5, 12}, - {273, 1, 6, 13}, - {273, 2, 7, 14}, - {273, 3, 24, 15}, - {273, 4, 23, 16}, - // chip: 906 (5), ladder: 28 (11), layer: 8, disk: 4, half: 1, zone: 2 - {274, 0, 17, 8}, - {274, 1, 16, 9}, - {274, 2, 15, 10}, - {274, 3, 14, 11}, - {274, 4, 13, 12}, - // chip: 911 (5), ladder: 29 (12), layer: 8, disk: 4, half: 1, zone: 2 - {275, 0, 22, 13}, - {275, 1, 21, 14}, - {275, 2, 20, 15}, - {275, 3, 19, 16}, - {275, 4, 18, 17}, - // chip: 916 (5), ladder: 30 (21), layer: 9, disk: 4, half: 1, zone: 2 - {276, 0, 22, 13}, - {276, 1, 21, 14}, - {276, 2, 20, 15}, - {276, 3, 19, 16}, - {276, 4, 18, 17}, - // chip: 921 (5), ladder: 31 (22), layer: 9, disk: 4, half: 1, zone: 2 - {277, 0, 17, 8}, - {277, 1, 16, 9}, - {277, 2, 15, 10}, - {277, 3, 14, 11}, - {277, 4, 13, 12}, - // chip: 926 (5), ladder: 32 (28), layer: 9, disk: 4, half: 1, zone: 1 - {278, 0, 5, 12}, - {278, 1, 6, 13}, - {278, 2, 7, 14}, - {278, 3, 24, 15}, - {278, 4, 23, 16}, + {139, 0, 12, 14, 463, 0, 8, 4, 0, 0, 11, 72, 36, 9, 4, 0}, + {139, 1, 11, 15, 464, 1, 7, 4, 0, 0, 11, 72, 36, 9, 4, 0}, + {139, 2, 10, 16, 465, 2, 6, 4, 0, 0, 11, 72, 36, 9, 4, 0}, + {139, 3, 9, 17, 466, 3, 5, 4, 0, 0, 11, 72, 36, 9, 4, 0}, + {139, 4, 8, 18, 467, 4, 4, 4, 0, 0, 11, 72, 36, 9, 4, 0}, + // chip: 468 (5), ladder: 0 (29), layer: 0, disk: 0, half: 1, zone: 0 + {140, 0, 5, 0, 468, 0, 8, 0, 0, 4, 1, 4, 64, 0, 0, 1}, + {140, 1, 6, 1, 469, 1, 7, 0, 0, 4, 1, 4, 64, 0, 0, 1}, + // chip: 470 (5), ladder: 1 (29), layer: 0, disk: 0, half: 1, zone: 0 + {141, 0, 0, 0, 470, 0, 8, 1, 3, 7, 0, 7, 67, 0, 0, 1}, + {141, 1, 1, 1, 471, 1, 7, 1, 3, 7, 0, 7, 67, 0, 0, 1}, + // chip: 472 (5), ladder: 2 (29), layer: 0, disk: 0, half: 1, zone: 0 + {142, 0, 17, 2, 472, 0, 8, 2, 3, 7, 0, 7, 67, 0, 0, 1}, + {142, 1, 16, 3, 473, 1, 7, 2, 3, 7, 0, 7, 67, 0, 0, 1}, + // chip: 474 (5), ladder: 3 (29), layer: 1, disk: 0, half: 1, zone: 0 + {143, 0, 17, 2, 474, 0, 8, 2, 3, 7, 0, 15, 71, 1, 0, 1}, + {143, 1, 16, 3, 475, 1, 7, 2, 3, 7, 0, 15, 71, 1, 0, 1}, + // chip: 476 (5), ladder: 4 (29), layer: 1, disk: 0, half: 1, zone: 0 + {144, 0, 0, 0, 476, 0, 8, 1, 3, 7, 0, 15, 71, 1, 0, 1}, + {144, 1, 1, 1, 477, 1, 7, 1, 3, 7, 0, 15, 71, 1, 0, 1}, + // chip: 478 (5), ladder: 5 (29), layer: 1, disk: 0, half: 1, zone: 0 + {145, 0, 5, 0, 478, 0, 8, 0, 0, 4, 1, 12, 68, 1, 0, 1}, + {145, 1, 6, 1, 479, 1, 7, 0, 0, 4, 1, 12, 68, 1, 0, 1}, + // chip: 480 (5), ladder: 6 (29), layer: 0, disk: 0, half: 1, zone: 0 + {146, 0, 0, 2, 480, 0, 8, 1, 0, 4, 1, 4, 64, 0, 0, 1}, + {146, 1, 1, 3, 481, 1, 7, 1, 0, 4, 1, 4, 64, 0, 0, 1}, + {146, 2, 2, 4, 482, 2, 6, 1, 0, 4, 1, 4, 64, 0, 0, 1}, + // chip: 483 (5), ladder: 7 (29), layer: 0, disk: 0, half: 1, zone: 0 + {147, 0, 17, 5, 483, 0, 8, 2, 0, 4, 1, 4, 64, 0, 0, 1}, + {147, 1, 16, 6, 484, 1, 7, 2, 0, 4, 1, 4, 64, 0, 0, 1}, + {147, 2, 15, 7, 485, 2, 6, 2, 0, 4, 1, 4, 64, 0, 0, 1}, + // chip: 486 (5), ladder: 8 (29), layer: 0, disk: 0, half: 1, zone: 0 + {148, 0, 5, 0, 486, 0, 8, 0, 1, 5, 2, 5, 65, 0, 0, 1}, + {148, 1, 6, 1, 487, 1, 7, 0, 1, 5, 2, 5, 65, 0, 0, 1}, + {148, 2, 7, 2, 488, 2, 6, 0, 1, 5, 2, 5, 65, 0, 0, 1}, + // chip: 489 (5), ladder: 9 (29), layer: 0, disk: 0, half: 1, zone: 0 + {149, 0, 0, 3, 489, 0, 8, 1, 1, 5, 2, 5, 65, 0, 0, 1}, + {149, 1, 1, 4, 490, 1, 7, 1, 1, 5, 2, 5, 65, 0, 0, 1}, + {149, 2, 2, 5, 491, 2, 6, 1, 1, 5, 2, 5, 65, 0, 0, 1}, + // chip: 492 (5), ladder: 10 (29), layer: 0, disk: 0, half: 1, zone: 0 + {150, 0, 17, 6, 492, 0, 8, 2, 1, 5, 2, 5, 65, 0, 0, 1}, + {150, 1, 16, 7, 493, 1, 7, 2, 1, 5, 2, 5, 65, 0, 0, 1}, + {150, 2, 15, 8, 494, 2, 6, 2, 1, 5, 2, 5, 65, 0, 0, 1}, + // chip: 495 (5), ladder: 11 (29), layer: 0, disk: 0, half: 1, zone: 0 + {151, 0, 5, 0, 495, 0, 8, 0, 2, 6, 2, 6, 66, 0, 0, 1}, + {151, 1, 6, 1, 496, 1, 7, 0, 2, 6, 2, 6, 66, 0, 0, 1}, + {151, 2, 7, 2, 497, 2, 6, 0, 2, 6, 2, 6, 66, 0, 0, 1}, + // chip: 498 (5), ladder: 12 (29), layer: 0, disk: 0, half: 1, zone: 0 + {152, 0, 0, 3, 498, 0, 8, 1, 2, 6, 2, 6, 66, 0, 0, 1}, + {152, 1, 1, 4, 499, 1, 7, 1, 2, 6, 2, 6, 66, 0, 0, 1}, + {152, 2, 2, 5, 500, 2, 6, 1, 2, 6, 2, 6, 66, 0, 0, 1}, + // chip: 501 (5), ladder: 13 (29), layer: 0, disk: 0, half: 1, zone: 0 + {153, 0, 17, 6, 501, 0, 8, 2, 2, 6, 2, 6, 66, 0, 0, 1}, + {153, 1, 16, 7, 502, 1, 7, 2, 2, 6, 2, 6, 66, 0, 0, 1}, + {153, 2, 15, 8, 503, 2, 6, 2, 2, 6, 2, 6, 66, 0, 0, 1}, + // chip: 504 (5), ladder: 14 (29), layer: 0, disk: 0, half: 1, zone: 0 + {154, 0, 5, 4, 504, 0, 8, 0, 3, 7, 0, 7, 67, 0, 0, 1}, + {154, 1, 6, 5, 505, 1, 7, 0, 3, 7, 0, 7, 67, 0, 0, 1}, + {154, 2, 7, 6, 506, 2, 6, 0, 3, 7, 0, 7, 67, 0, 0, 1}, + // chip: 507 (5), ladder: 15 (29), layer: 1, disk: 0, half: 1, zone: 0 + {155, 0, 5, 4, 507, 0, 8, 0, 3, 7, 0, 15, 71, 1, 0, 1}, + {155, 1, 6, 5, 508, 1, 7, 0, 3, 7, 0, 15, 71, 1, 0, 1}, + {155, 2, 7, 6, 509, 2, 6, 0, 3, 7, 0, 15, 71, 1, 0, 1}, + // chip: 510 (5), ladder: 16 (29), layer: 1, disk: 0, half: 1, zone: 0 + {156, 0, 17, 6, 510, 0, 8, 2, 2, 6, 2, 14, 70, 1, 0, 1}, + {156, 1, 16, 7, 511, 1, 7, 2, 2, 6, 2, 14, 70, 1, 0, 1}, + {156, 2, 15, 8, 512, 2, 6, 2, 2, 6, 2, 14, 70, 1, 0, 1}, + // chip: 513 (5), ladder: 17 (29), layer: 1, disk: 0, half: 1, zone: 0 + {157, 0, 0, 3, 513, 0, 8, 1, 2, 6, 2, 14, 70, 1, 0, 1}, + {157, 1, 1, 4, 514, 1, 7, 1, 2, 6, 2, 14, 70, 1, 0, 1}, + {157, 2, 2, 5, 515, 2, 6, 1, 2, 6, 2, 14, 70, 1, 0, 1}, + // chip: 516 (5), ladder: 18 (29), layer: 1, disk: 0, half: 1, zone: 0 + {158, 0, 5, 0, 516, 0, 8, 0, 2, 6, 2, 14, 70, 1, 0, 1}, + {158, 1, 6, 1, 517, 1, 7, 0, 2, 6, 2, 14, 70, 1, 0, 1}, + {158, 2, 7, 2, 518, 2, 6, 0, 2, 6, 2, 14, 70, 1, 0, 1}, + // chip: 519 (5), ladder: 19 (29), layer: 1, disk: 0, half: 1, zone: 0 + {159, 0, 17, 6, 519, 0, 8, 2, 1, 5, 2, 13, 69, 1, 0, 1}, + {159, 1, 16, 7, 520, 1, 7, 2, 1, 5, 2, 13, 69, 1, 0, 1}, + {159, 2, 15, 8, 521, 2, 6, 2, 1, 5, 2, 13, 69, 1, 0, 1}, + // chip: 522 (5), ladder: 20 (29), layer: 1, disk: 0, half: 1, zone: 0 + {160, 0, 0, 3, 522, 0, 8, 1, 1, 5, 2, 13, 69, 1, 0, 1}, + {160, 1, 1, 4, 523, 1, 7, 1, 1, 5, 2, 13, 69, 1, 0, 1}, + {160, 2, 2, 5, 524, 2, 6, 1, 1, 5, 2, 13, 69, 1, 0, 1}, + // chip: 525 (5), ladder: 21 (29), layer: 1, disk: 0, half: 1, zone: 0 + {161, 0, 5, 0, 525, 0, 8, 0, 1, 5, 2, 13, 69, 1, 0, 1}, + {161, 1, 6, 1, 526, 1, 7, 0, 1, 5, 2, 13, 69, 1, 0, 1}, + {161, 2, 7, 2, 527, 2, 6, 0, 1, 5, 2, 13, 69, 1, 0, 1}, + // chip: 528 (5), ladder: 22 (29), layer: 1, disk: 0, half: 1, zone: 0 + {162, 0, 17, 5, 528, 0, 8, 2, 0, 4, 1, 12, 68, 1, 0, 1}, + {162, 1, 16, 6, 529, 1, 7, 2, 0, 4, 1, 12, 68, 1, 0, 1}, + {162, 2, 15, 7, 530, 2, 6, 2, 0, 4, 1, 12, 68, 1, 0, 1}, + // chip: 531 (5), ladder: 23 (29), layer: 1, disk: 0, half: 1, zone: 0 + {163, 0, 0, 2, 531, 0, 8, 1, 0, 4, 1, 12, 68, 1, 0, 1}, + {163, 1, 1, 3, 532, 1, 7, 1, 0, 4, 1, 12, 68, 1, 0, 1}, + {163, 2, 2, 4, 533, 2, 6, 1, 0, 4, 1, 12, 68, 1, 0, 1}, + // chip: 534 (5), ladder: 0 (29), layer: 2, disk: 1, half: 1, zone: 0 + {164, 0, 5, 0, 534, 0, 8, 0, 0, 4, 1, 20, 72, 2, 1, 1}, + {164, 1, 6, 1, 535, 1, 7, 0, 0, 4, 1, 20, 72, 2, 1, 1}, + // chip: 536 (5), ladder: 1 (29), layer: 2, disk: 1, half: 1, zone: 0 + {165, 0, 0, 0, 536, 0, 8, 1, 3, 7, 0, 23, 75, 2, 1, 1}, + {165, 1, 1, 1, 537, 1, 7, 1, 3, 7, 0, 23, 75, 2, 1, 1}, + // chip: 538 (5), ladder: 2 (29), layer: 2, disk: 1, half: 1, zone: 0 + {166, 0, 17, 2, 538, 0, 8, 2, 3, 7, 0, 23, 75, 2, 1, 1}, + {166, 1, 16, 3, 539, 1, 7, 2, 3, 7, 0, 23, 75, 2, 1, 1}, + // chip: 540 (5), ladder: 3 (29), layer: 3, disk: 1, half: 1, zone: 0 + {167, 0, 17, 2, 540, 0, 8, 2, 3, 7, 0, 31, 79, 3, 1, 1}, + {167, 1, 16, 3, 541, 1, 7, 2, 3, 7, 0, 31, 79, 3, 1, 1}, + // chip: 542 (5), ladder: 4 (29), layer: 3, disk: 1, half: 1, zone: 0 + {168, 0, 0, 0, 542, 0, 8, 1, 3, 7, 0, 31, 79, 3, 1, 1}, + {168, 1, 1, 1, 543, 1, 7, 1, 3, 7, 0, 31, 79, 3, 1, 1}, + // chip: 544 (5), ladder: 5 (29), layer: 3, disk: 1, half: 1, zone: 0 + {169, 0, 5, 0, 544, 0, 8, 0, 0, 4, 1, 28, 76, 3, 1, 1}, + {169, 1, 6, 1, 545, 1, 7, 0, 0, 4, 1, 28, 76, 3, 1, 1}, + // chip: 546 (5), ladder: 6 (29), layer: 2, disk: 1, half: 1, zone: 0 + {170, 0, 0, 2, 546, 0, 8, 1, 0, 4, 1, 20, 72, 2, 1, 1}, + {170, 1, 1, 3, 547, 1, 7, 1, 0, 4, 1, 20, 72, 2, 1, 1}, + {170, 2, 2, 4, 548, 2, 6, 1, 0, 4, 1, 20, 72, 2, 1, 1}, + // chip: 549 (5), ladder: 7 (29), layer: 2, disk: 1, half: 1, zone: 0 + {171, 0, 17, 5, 549, 0, 8, 2, 0, 4, 1, 20, 72, 2, 1, 1}, + {171, 1, 16, 6, 550, 1, 7, 2, 0, 4, 1, 20, 72, 2, 1, 1}, + {171, 2, 15, 7, 551, 2, 6, 2, 0, 4, 1, 20, 72, 2, 1, 1}, + // chip: 552 (5), ladder: 8 (29), layer: 2, disk: 1, half: 1, zone: 0 + {172, 0, 5, 0, 552, 0, 8, 0, 1, 5, 2, 21, 73, 2, 1, 1}, + {172, 1, 6, 1, 553, 1, 7, 0, 1, 5, 2, 21, 73, 2, 1, 1}, + {172, 2, 7, 2, 554, 2, 6, 0, 1, 5, 2, 21, 73, 2, 1, 1}, + // chip: 555 (5), ladder: 9 (29), layer: 2, disk: 1, half: 1, zone: 0 + {173, 0, 0, 3, 555, 0, 8, 1, 1, 5, 2, 21, 73, 2, 1, 1}, + {173, 1, 1, 4, 556, 1, 7, 1, 1, 5, 2, 21, 73, 2, 1, 1}, + {173, 2, 2, 5, 557, 2, 6, 1, 1, 5, 2, 21, 73, 2, 1, 1}, + // chip: 558 (5), ladder: 10 (29), layer: 2, disk: 1, half: 1, zone: 0 + {174, 0, 17, 6, 558, 0, 8, 2, 1, 5, 2, 21, 73, 2, 1, 1}, + {174, 1, 16, 7, 559, 1, 7, 2, 1, 5, 2, 21, 73, 2, 1, 1}, + {174, 2, 15, 8, 560, 2, 6, 2, 1, 5, 2, 21, 73, 2, 1, 1}, + // chip: 561 (5), ladder: 11 (29), layer: 2, disk: 1, half: 1, zone: 0 + {175, 0, 5, 0, 561, 0, 8, 0, 2, 6, 2, 22, 74, 2, 1, 1}, + {175, 1, 6, 1, 562, 1, 7, 0, 2, 6, 2, 22, 74, 2, 1, 1}, + {175, 2, 7, 2, 563, 2, 6, 0, 2, 6, 2, 22, 74, 2, 1, 1}, + // chip: 564 (5), ladder: 12 (29), layer: 2, disk: 1, half: 1, zone: 0 + {176, 0, 0, 3, 564, 0, 8, 1, 2, 6, 2, 22, 74, 2, 1, 1}, + {176, 1, 1, 4, 565, 1, 7, 1, 2, 6, 2, 22, 74, 2, 1, 1}, + {176, 2, 2, 5, 566, 2, 6, 1, 2, 6, 2, 22, 74, 2, 1, 1}, + // chip: 567 (5), ladder: 13 (29), layer: 2, disk: 1, half: 1, zone: 0 + {177, 0, 17, 6, 567, 0, 8, 2, 2, 6, 2, 22, 74, 2, 1, 1}, + {177, 1, 16, 7, 568, 1, 7, 2, 2, 6, 2, 22, 74, 2, 1, 1}, + {177, 2, 15, 8, 569, 2, 6, 2, 2, 6, 2, 22, 74, 2, 1, 1}, + // chip: 570 (5), ladder: 14 (29), layer: 2, disk: 1, half: 1, zone: 0 + {178, 0, 5, 4, 570, 0, 8, 0, 3, 7, 0, 23, 75, 2, 1, 1}, + {178, 1, 6, 5, 571, 1, 7, 0, 3, 7, 0, 23, 75, 2, 1, 1}, + {178, 2, 7, 6, 572, 2, 6, 0, 3, 7, 0, 23, 75, 2, 1, 1}, + // chip: 573 (5), ladder: 15 (29), layer: 3, disk: 1, half: 1, zone: 0 + {179, 0, 5, 4, 573, 0, 8, 0, 3, 7, 0, 31, 79, 3, 1, 1}, + {179, 1, 6, 5, 574, 1, 7, 0, 3, 7, 0, 31, 79, 3, 1, 1}, + {179, 2, 7, 6, 575, 2, 6, 0, 3, 7, 0, 31, 79, 3, 1, 1}, + // chip: 576 (5), ladder: 16 (29), layer: 3, disk: 1, half: 1, zone: 0 + {180, 0, 17, 6, 576, 0, 8, 2, 2, 6, 2, 30, 78, 3, 1, 1}, + {180, 1, 16, 7, 577, 1, 7, 2, 2, 6, 2, 30, 78, 3, 1, 1}, + {180, 2, 15, 8, 578, 2, 6, 2, 2, 6, 2, 30, 78, 3, 1, 1}, + // chip: 579 (5), ladder: 17 (29), layer: 3, disk: 1, half: 1, zone: 0 + {181, 0, 0, 3, 579, 0, 8, 1, 2, 6, 2, 30, 78, 3, 1, 1}, + {181, 1, 1, 4, 580, 1, 7, 1, 2, 6, 2, 30, 78, 3, 1, 1}, + {181, 2, 2, 5, 581, 2, 6, 1, 2, 6, 2, 30, 78, 3, 1, 1}, + // chip: 582 (5), ladder: 18 (29), layer: 3, disk: 1, half: 1, zone: 0 + {182, 0, 5, 0, 582, 0, 8, 0, 2, 6, 2, 30, 78, 3, 1, 1}, + {182, 1, 6, 1, 583, 1, 7, 0, 2, 6, 2, 30, 78, 3, 1, 1}, + {182, 2, 7, 2, 584, 2, 6, 0, 2, 6, 2, 30, 78, 3, 1, 1}, + // chip: 585 (5), ladder: 19 (29), layer: 3, disk: 1, half: 1, zone: 0 + {183, 0, 17, 6, 585, 0, 8, 2, 1, 5, 2, 29, 77, 3, 1, 1}, + {183, 1, 16, 7, 586, 1, 7, 2, 1, 5, 2, 29, 77, 3, 1, 1}, + {183, 2, 15, 8, 587, 2, 6, 2, 1, 5, 2, 29, 77, 3, 1, 1}, + // chip: 588 (5), ladder: 20 (29), layer: 3, disk: 1, half: 1, zone: 0 + {184, 0, 0, 3, 588, 0, 8, 1, 1, 5, 2, 29, 77, 3, 1, 1}, + {184, 1, 1, 4, 589, 1, 7, 1, 1, 5, 2, 29, 77, 3, 1, 1}, + {184, 2, 2, 5, 590, 2, 6, 1, 1, 5, 2, 29, 77, 3, 1, 1}, + // chip: 591 (5), ladder: 21 (29), layer: 3, disk: 1, half: 1, zone: 0 + {185, 0, 5, 0, 591, 0, 8, 0, 1, 5, 2, 29, 77, 3, 1, 1}, + {185, 1, 6, 1, 592, 1, 7, 0, 1, 5, 2, 29, 77, 3, 1, 1}, + {185, 2, 7, 2, 593, 2, 6, 0, 1, 5, 2, 29, 77, 3, 1, 1}, + // chip: 594 (5), ladder: 22 (29), layer: 3, disk: 1, half: 1, zone: 0 + {186, 0, 17, 5, 594, 0, 8, 2, 0, 4, 1, 28, 76, 3, 1, 1}, + {186, 1, 16, 6, 595, 1, 7, 2, 0, 4, 1, 28, 76, 3, 1, 1}, + {186, 2, 15, 7, 596, 2, 6, 2, 0, 4, 1, 28, 76, 3, 1, 1}, + // chip: 597 (5), ladder: 23 (29), layer: 3, disk: 1, half: 1, zone: 0 + {187, 0, 0, 2, 597, 0, 8, 1, 0, 4, 1, 28, 76, 3, 1, 1}, + {187, 1, 1, 3, 598, 1, 7, 1, 0, 4, 1, 28, 76, 3, 1, 1}, + {187, 2, 2, 4, 599, 2, 6, 1, 0, 4, 1, 28, 76, 3, 1, 1}, + // chip: 600 (5), ladder: 0 (29), layer: 4, disk: 2, half: 1, zone: 0 + {188, 0, 5, 0, 600, 0, 8, 0, 0, 4, 1, 36, 80, 4, 2, 1}, + {188, 1, 6, 1, 601, 1, 7, 0, 0, 4, 1, 36, 80, 4, 2, 1}, + // chip: 602 (5), ladder: 1 (29), layer: 4, disk: 2, half: 1, zone: 0 + {189, 0, 22, 0, 602, 0, 8, 3, 3, 7, 5, 39, 83, 4, 2, 1}, + {189, 1, 21, 1, 603, 1, 7, 3, 3, 7, 5, 39, 83, 4, 2, 1}, + // chip: 604 (5), ladder: 2 (29), layer: 5, disk: 2, half: 1, zone: 0 + {190, 0, 22, 0, 604, 0, 8, 3, 3, 7, 5, 47, 87, 5, 2, 1}, + {190, 1, 21, 1, 605, 1, 7, 3, 3, 7, 5, 47, 87, 5, 2, 1}, + // chip: 606 (5), ladder: 3 (29), layer: 5, disk: 2, half: 1, zone: 0 + {191, 0, 5, 0, 606, 0, 8, 0, 0, 4, 1, 44, 84, 5, 2, 1}, + {191, 1, 6, 1, 607, 1, 7, 0, 0, 4, 1, 44, 84, 5, 2, 1}, + // chip: 608 (5), ladder: 4 (29), layer: 4, disk: 2, half: 1, zone: 0 + {192, 0, 0, 2, 608, 0, 8, 1, 0, 4, 1, 36, 80, 4, 2, 1}, + {192, 1, 1, 3, 609, 1, 7, 1, 0, 4, 1, 36, 80, 4, 2, 1}, + {192, 2, 2, 4, 610, 2, 6, 1, 0, 4, 1, 36, 80, 4, 2, 1}, + // chip: 611 (5), ladder: 5 (29), layer: 4, disk: 2, half: 1, zone: 0 + {193, 0, 17, 5, 611, 0, 8, 2, 0, 4, 1, 36, 80, 4, 2, 1}, + {193, 1, 16, 6, 612, 1, 7, 2, 0, 4, 1, 36, 80, 4, 2, 1}, + {193, 2, 15, 7, 613, 2, 6, 2, 0, 4, 1, 36, 80, 4, 2, 1}, + // chip: 614 (5), ladder: 6 (29), layer: 4, disk: 2, half: 1, zone: 0 + {194, 0, 17, 0, 614, 0, 8, 2, 1, 5, 4, 37, 81, 4, 2, 1}, + {194, 1, 16, 1, 615, 1, 7, 2, 1, 5, 4, 37, 81, 4, 2, 1}, + {194, 2, 15, 2, 616, 2, 6, 2, 1, 5, 4, 37, 81, 4, 2, 1}, + // chip: 617 (5), ladder: 7 (29), layer: 4, disk: 2, half: 1, zone: 0 + {195, 0, 5, 0, 617, 0, 8, 0, 2, 6, 3, 38, 82, 4, 2, 1}, + {195, 1, 6, 1, 618, 1, 7, 0, 2, 6, 3, 38, 82, 4, 2, 1}, + {195, 2, 7, 2, 619, 2, 6, 0, 2, 6, 3, 38, 82, 4, 2, 1}, + // chip: 620 (5), ladder: 8 (29), layer: 4, disk: 2, half: 1, zone: 0 + {196, 0, 0, 3, 620, 0, 8, 1, 2, 6, 3, 38, 82, 4, 2, 1}, + {196, 1, 1, 4, 621, 1, 7, 1, 2, 6, 3, 38, 82, 4, 2, 1}, + {196, 2, 2, 5, 622, 2, 6, 1, 2, 6, 3, 38, 82, 4, 2, 1}, + // chip: 623 (5), ladder: 9 (29), layer: 4, disk: 2, half: 1, zone: 0 + {197, 0, 0, 2, 623, 0, 8, 1, 3, 7, 5, 39, 83, 4, 2, 1}, + {197, 1, 1, 3, 624, 1, 7, 1, 3, 7, 5, 39, 83, 4, 2, 1}, + {197, 2, 2, 4, 625, 2, 6, 1, 3, 7, 5, 39, 83, 4, 2, 1}, + // chip: 626 (5), ladder: 10 (29), layer: 4, disk: 2, half: 1, zone: 0 + {198, 0, 17, 5, 626, 0, 8, 2, 3, 7, 5, 39, 83, 4, 2, 1}, + {198, 1, 16, 6, 627, 1, 7, 2, 3, 7, 5, 39, 83, 4, 2, 1}, + {198, 2, 15, 7, 628, 2, 6, 2, 3, 7, 5, 39, 83, 4, 2, 1}, + // chip: 629 (5), ladder: 11 (29), layer: 5, disk: 2, half: 1, zone: 0 + {199, 0, 17, 5, 629, 0, 8, 2, 3, 7, 5, 47, 87, 5, 2, 1}, + {199, 1, 16, 6, 630, 1, 7, 2, 3, 7, 5, 47, 87, 5, 2, 1}, + {199, 2, 15, 7, 631, 2, 6, 2, 3, 7, 5, 47, 87, 5, 2, 1}, + // chip: 632 (5), ladder: 12 (29), layer: 5, disk: 2, half: 1, zone: 0 + {200, 0, 0, 2, 632, 0, 8, 1, 3, 7, 5, 47, 87, 5, 2, 1}, + {200, 1, 1, 3, 633, 1, 7, 1, 3, 7, 5, 47, 87, 5, 2, 1}, + {200, 2, 2, 4, 634, 2, 6, 1, 3, 7, 5, 47, 87, 5, 2, 1}, + // chip: 635 (5), ladder: 13 (29), layer: 5, disk: 2, half: 1, zone: 0 + {201, 0, 0, 3, 635, 0, 8, 1, 2, 6, 3, 46, 86, 5, 2, 1}, + {201, 1, 1, 4, 636, 1, 7, 1, 2, 6, 3, 46, 86, 5, 2, 1}, + {201, 2, 2, 5, 637, 2, 6, 1, 2, 6, 3, 46, 86, 5, 2, 1}, + // chip: 638 (5), ladder: 14 (29), layer: 5, disk: 2, half: 1, zone: 0 + {202, 0, 5, 0, 638, 0, 8, 0, 2, 6, 3, 46, 86, 5, 2, 1}, + {202, 1, 6, 1, 639, 1, 7, 0, 2, 6, 3, 46, 86, 5, 2, 1}, + {202, 2, 7, 2, 640, 2, 6, 0, 2, 6, 3, 46, 86, 5, 2, 1}, + // chip: 641 (5), ladder: 15 (29), layer: 5, disk: 2, half: 1, zone: 0 + {203, 0, 17, 0, 641, 0, 8, 2, 1, 5, 4, 45, 85, 5, 2, 1}, + {203, 1, 16, 1, 642, 1, 7, 2, 1, 5, 4, 45, 85, 5, 2, 1}, + {203, 2, 15, 2, 643, 2, 6, 2, 1, 5, 4, 45, 85, 5, 2, 1}, + // chip: 644 (5), ladder: 16 (29), layer: 5, disk: 2, half: 1, zone: 0 + {204, 0, 17, 5, 644, 0, 8, 2, 0, 4, 1, 44, 84, 5, 2, 1}, + {204, 1, 16, 6, 645, 1, 7, 2, 0, 4, 1, 44, 84, 5, 2, 1}, + {204, 2, 15, 7, 646, 2, 6, 2, 0, 4, 1, 44, 84, 5, 2, 1}, + // chip: 647 (5), ladder: 17 (29), layer: 5, disk: 2, half: 1, zone: 0 + {205, 0, 0, 2, 647, 0, 8, 1, 0, 4, 1, 44, 84, 5, 2, 1}, + {205, 1, 1, 3, 648, 1, 7, 1, 0, 4, 1, 44, 84, 5, 2, 1}, + {205, 2, 2, 4, 649, 2, 6, 1, 0, 4, 1, 44, 84, 5, 2, 1}, + // chip: 650 (5), ladder: 18 (29), layer: 4, disk: 2, half: 1, zone: 0 + {206, 0, 5, 3, 650, 0, 8, 0, 1, 5, 4, 37, 81, 4, 2, 1}, + {206, 1, 6, 4, 651, 1, 7, 0, 1, 5, 4, 37, 81, 4, 2, 1}, + {206, 2, 7, 5, 652, 2, 6, 0, 1, 5, 4, 37, 81, 4, 2, 1}, + {206, 3, 24, 6, 653, 3, 5, 0, 1, 5, 4, 37, 81, 4, 2, 1}, + // chip: 654 (5), ladder: 19 (29), layer: 4, disk: 2, half: 1, zone: 0 + {207, 0, 0, 7, 654, 0, 8, 1, 1, 5, 4, 37, 81, 4, 2, 1}, + {207, 1, 1, 8, 655, 1, 7, 1, 1, 5, 4, 37, 81, 4, 2, 1}, + {207, 2, 2, 9, 656, 2, 6, 1, 1, 5, 4, 37, 81, 4, 2, 1}, + {207, 3, 3, 10, 657, 3, 5, 1, 1, 5, 4, 37, 81, 4, 2, 1}, + // chip: 658 (5), ladder: 20 (29), layer: 4, disk: 2, half: 1, zone: 0 + {208, 0, 17, 6, 658, 0, 8, 2, 2, 6, 3, 38, 82, 4, 2, 1}, + {208, 1, 16, 7, 659, 1, 7, 2, 2, 6, 3, 38, 82, 4, 2, 1}, + {208, 2, 15, 8, 660, 2, 6, 2, 2, 6, 3, 38, 82, 4, 2, 1}, + {208, 3, 14, 9, 661, 3, 5, 2, 2, 6, 3, 38, 82, 4, 2, 1}, + // chip: 662 (5), ladder: 21 (29), layer: 4, disk: 2, half: 1, zone: 0 + {209, 0, 5, 8, 662, 0, 8, 0, 3, 7, 5, 39, 83, 4, 2, 1}, + {209, 1, 6, 9, 663, 1, 7, 0, 3, 7, 5, 39, 83, 4, 2, 1}, + {209, 2, 7, 10, 664, 2, 6, 0, 3, 7, 5, 39, 83, 4, 2, 1}, + {209, 3, 24, 11, 665, 3, 5, 0, 3, 7, 5, 39, 83, 4, 2, 1}, + // chip: 666 (5), ladder: 22 (29), layer: 5, disk: 2, half: 1, zone: 0 + {210, 0, 5, 8, 666, 0, 8, 0, 3, 7, 5, 47, 87, 5, 2, 1}, + {210, 1, 6, 9, 667, 1, 7, 0, 3, 7, 5, 47, 87, 5, 2, 1}, + {210, 2, 7, 10, 668, 2, 6, 0, 3, 7, 5, 47, 87, 5, 2, 1}, + {210, 3, 24, 11, 669, 3, 5, 0, 3, 7, 5, 47, 87, 5, 2, 1}, + // chip: 670 (5), ladder: 23 (29), layer: 5, disk: 2, half: 1, zone: 0 + {211, 0, 17, 6, 670, 0, 8, 2, 2, 6, 3, 46, 86, 5, 2, 1}, + {211, 1, 16, 7, 671, 1, 7, 2, 2, 6, 3, 46, 86, 5, 2, 1}, + {211, 2, 15, 8, 672, 2, 6, 2, 2, 6, 3, 46, 86, 5, 2, 1}, + {211, 3, 14, 9, 673, 3, 5, 2, 2, 6, 3, 46, 86, 5, 2, 1}, + // chip: 674 (5), ladder: 24 (29), layer: 5, disk: 2, half: 1, zone: 0 + {212, 0, 0, 7, 674, 0, 8, 1, 1, 5, 4, 45, 85, 5, 2, 1}, + {212, 1, 1, 8, 675, 1, 7, 1, 1, 5, 4, 45, 85, 5, 2, 1}, + {212, 2, 2, 9, 676, 2, 6, 1, 1, 5, 4, 45, 85, 5, 2, 1}, + {212, 3, 3, 10, 677, 3, 5, 1, 1, 5, 4, 45, 85, 5, 2, 1}, + // chip: 678 (5), ladder: 25 (29), layer: 5, disk: 2, half: 1, zone: 0 + {213, 0, 5, 3, 678, 0, 8, 0, 1, 5, 4, 45, 85, 5, 2, 1}, + {213, 1, 6, 4, 679, 1, 7, 0, 1, 5, 4, 45, 85, 5, 2, 1}, + {213, 2, 7, 5, 680, 2, 6, 0, 1, 5, 4, 45, 85, 5, 2, 1}, + {213, 3, 24, 6, 681, 3, 5, 0, 1, 5, 4, 45, 85, 5, 2, 1}, + // chip: 682 (5), ladder: 0 (29), layer: 6, disk: 3, half: 1, zone: 0 + {214, 0, 5, 0, 682, 0, 8, 0, 0, 4, 7, 52, 88, 6, 3, 1}, + {214, 1, 6, 1, 683, 1, 7, 0, 0, 4, 7, 52, 88, 6, 3, 1}, + {214, 2, 7, 2, 684, 2, 6, 0, 0, 4, 7, 52, 88, 6, 3, 1}, + // chip: 685 (5), ladder: 1 (29), layer: 6, disk: 3, half: 1, zone: 0 + {215, 0, 0, 3, 685, 0, 8, 1, 0, 4, 7, 52, 88, 6, 3, 1}, + {215, 1, 1, 4, 686, 1, 7, 1, 0, 4, 7, 52, 88, 6, 3, 1}, + {215, 2, 2, 5, 687, 2, 6, 1, 0, 4, 7, 52, 88, 6, 3, 1}, + // chip: 688 (5), ladder: 2 (29), layer: 6, disk: 3, half: 1, zone: 0 + {216, 0, 0, 0, 688, 0, 8, 1, 3, 7, 6, 55, 91, 6, 3, 1}, + {216, 1, 1, 1, 689, 1, 7, 1, 3, 7, 6, 55, 91, 6, 3, 1}, + {216, 2, 2, 2, 690, 2, 6, 1, 3, 7, 6, 55, 91, 6, 3, 1}, + // chip: 691 (5), ladder: 3 (29), layer: 6, disk: 3, half: 1, zone: 0 + {217, 0, 17, 3, 691, 0, 8, 2, 3, 7, 6, 55, 91, 6, 3, 1}, + {217, 1, 16, 4, 692, 1, 7, 2, 3, 7, 6, 55, 91, 6, 3, 1}, + {217, 2, 15, 5, 693, 2, 6, 2, 3, 7, 6, 55, 91, 6, 3, 1}, + // chip: 694 (5), ladder: 4 (29), layer: 6, disk: 3, half: 1, zone: 0 + {218, 0, 22, 6, 694, 0, 8, 3, 3, 7, 6, 55, 91, 6, 3, 1}, + {218, 1, 21, 7, 695, 1, 7, 3, 3, 7, 6, 55, 91, 6, 3, 1}, + {218, 2, 20, 8, 696, 2, 6, 3, 3, 7, 6, 55, 91, 6, 3, 1}, + // chip: 697 (5), ladder: 5 (29), layer: 7, disk: 3, half: 1, zone: 0 + {219, 0, 22, 6, 697, 0, 8, 3, 3, 7, 6, 63, 95, 7, 3, 1}, + {219, 1, 21, 7, 698, 1, 7, 3, 3, 7, 6, 63, 95, 7, 3, 1}, + {219, 2, 20, 8, 699, 2, 6, 3, 3, 7, 6, 63, 95, 7, 3, 1}, + // chip: 700 (5), ladder: 6 (29), layer: 7, disk: 3, half: 1, zone: 0 + {220, 0, 17, 3, 700, 0, 8, 2, 3, 7, 6, 63, 95, 7, 3, 1}, + {220, 1, 16, 4, 701, 1, 7, 2, 3, 7, 6, 63, 95, 7, 3, 1}, + {220, 2, 15, 5, 702, 2, 6, 2, 3, 7, 6, 63, 95, 7, 3, 1}, + // chip: 703 (5), ladder: 7 (29), layer: 7, disk: 3, half: 1, zone: 0 + {221, 0, 0, 0, 703, 0, 8, 1, 3, 7, 6, 63, 95, 7, 3, 1}, + {221, 1, 1, 1, 704, 1, 7, 1, 3, 7, 6, 63, 95, 7, 3, 1}, + {221, 2, 2, 2, 705, 2, 6, 1, 3, 7, 6, 63, 95, 7, 3, 1}, + // chip: 706 (5), ladder: 8 (29), layer: 7, disk: 3, half: 1, zone: 0 + {222, 0, 0, 3, 706, 0, 8, 1, 0, 4, 7, 60, 92, 7, 3, 1}, + {222, 1, 1, 4, 707, 1, 7, 1, 0, 4, 7, 60, 92, 7, 3, 1}, + {222, 2, 2, 5, 708, 2, 6, 1, 0, 4, 7, 60, 92, 7, 3, 1}, + // chip: 709 (5), ladder: 9 (29), layer: 7, disk: 3, half: 1, zone: 0 + {223, 0, 5, 0, 709, 0, 8, 0, 0, 4, 7, 60, 92, 7, 3, 1}, + {223, 1, 6, 1, 710, 1, 7, 0, 0, 4, 7, 60, 92, 7, 3, 1}, + {223, 2, 7, 2, 711, 2, 6, 0, 0, 4, 7, 60, 92, 7, 3, 1}, + // chip: 712 (5), ladder: 10 (29), layer: 6, disk: 3, half: 1, zone: 0 + {224, 0, 17, 6, 712, 0, 8, 2, 0, 4, 7, 52, 88, 6, 3, 1}, + {224, 1, 16, 7, 713, 1, 7, 2, 0, 4, 7, 52, 88, 6, 3, 1}, + {224, 2, 15, 8, 714, 2, 6, 2, 0, 4, 7, 52, 88, 6, 3, 1}, + {224, 3, 14, 9, 715, 3, 5, 2, 0, 4, 7, 52, 88, 6, 3, 1}, + // chip: 716 (5), ladder: 11 (29), layer: 6, disk: 3, half: 1, zone: 0 + {225, 0, 22, 10, 716, 0, 8, 3, 0, 4, 7, 52, 88, 6, 3, 1}, + {225, 1, 21, 11, 717, 1, 7, 3, 0, 4, 7, 52, 88, 6, 3, 1}, + {225, 2, 20, 12, 718, 2, 6, 3, 0, 4, 7, 52, 88, 6, 3, 1}, + {225, 3, 19, 13, 719, 3, 5, 3, 0, 4, 7, 52, 88, 6, 3, 1}, + // chip: 720 (5), ladder: 12 (29), layer: 6, disk: 3, half: 1, zone: 0 + {226, 0, 5, 0, 720, 0, 8, 0, 1, 5, 8, 53, 89, 6, 3, 1}, + {226, 1, 6, 1, 721, 1, 7, 0, 1, 5, 8, 53, 89, 6, 3, 1}, + {226, 2, 7, 2, 722, 2, 6, 0, 1, 5, 8, 53, 89, 6, 3, 1}, + {226, 3, 24, 3, 723, 3, 5, 0, 1, 5, 8, 53, 89, 6, 3, 1}, + // chip: 724 (5), ladder: 13 (29), layer: 6, disk: 3, half: 1, zone: 0 + {227, 0, 0, 4, 724, 0, 8, 1, 1, 5, 8, 53, 89, 6, 3, 1}, + {227, 1, 1, 5, 725, 1, 7, 1, 1, 5, 8, 53, 89, 6, 3, 1}, + {227, 2, 2, 6, 726, 2, 6, 1, 1, 5, 8, 53, 89, 6, 3, 1}, + {227, 3, 3, 7, 727, 3, 5, 1, 1, 5, 8, 53, 89, 6, 3, 1}, + // chip: 728 (5), ladder: 14 (29), layer: 6, disk: 3, half: 1, zone: 0 + {228, 0, 17, 8, 728, 0, 8, 2, 1, 5, 8, 53, 89, 6, 3, 1}, + {228, 1, 16, 9, 729, 1, 7, 2, 1, 5, 8, 53, 89, 6, 3, 1}, + {228, 2, 15, 10, 730, 2, 6, 2, 1, 5, 8, 53, 89, 6, 3, 1}, + {228, 3, 14, 11, 731, 3, 5, 2, 1, 5, 8, 53, 89, 6, 3, 1}, + // chip: 732 (5), ladder: 15 (29), layer: 6, disk: 3, half: 1, zone: 0 + {229, 0, 22, 12, 732, 0, 8, 3, 1, 5, 8, 53, 89, 6, 3, 1}, + {229, 1, 21, 13, 733, 1, 7, 3, 1, 5, 8, 53, 89, 6, 3, 1}, + {229, 2, 20, 14, 734, 2, 6, 3, 1, 5, 8, 53, 89, 6, 3, 1}, + {229, 3, 19, 15, 735, 3, 5, 3, 1, 5, 8, 53, 89, 6, 3, 1}, + // chip: 736 (5), ladder: 16 (29), layer: 6, disk: 3, half: 1, zone: 0 + {230, 0, 5, 0, 736, 0, 8, 0, 2, 6, 8, 54, 90, 6, 3, 1}, + {230, 1, 6, 1, 737, 1, 7, 0, 2, 6, 8, 54, 90, 6, 3, 1}, + {230, 2, 7, 2, 738, 2, 6, 0, 2, 6, 8, 54, 90, 6, 3, 1}, + {230, 3, 24, 3, 739, 3, 5, 0, 2, 6, 8, 54, 90, 6, 3, 1}, + // chip: 740 (5), ladder: 17 (29), layer: 6, disk: 3, half: 1, zone: 0 + {231, 0, 0, 4, 740, 0, 8, 1, 2, 6, 8, 54, 90, 6, 3, 1}, + {231, 1, 1, 5, 741, 1, 7, 1, 2, 6, 8, 54, 90, 6, 3, 1}, + {231, 2, 2, 6, 742, 2, 6, 1, 2, 6, 8, 54, 90, 6, 3, 1}, + {231, 3, 3, 7, 743, 3, 5, 1, 2, 6, 8, 54, 90, 6, 3, 1}, + // chip: 744 (5), ladder: 18 (29), layer: 6, disk: 3, half: 1, zone: 0 + {232, 0, 17, 8, 744, 0, 8, 2, 2, 6, 8, 54, 90, 6, 3, 1}, + {232, 1, 16, 9, 745, 1, 7, 2, 2, 6, 8, 54, 90, 6, 3, 1}, + {232, 2, 15, 10, 746, 2, 6, 2, 2, 6, 8, 54, 90, 6, 3, 1}, + {232, 3, 14, 11, 747, 3, 5, 2, 2, 6, 8, 54, 90, 6, 3, 1}, + // chip: 748 (5), ladder: 19 (29), layer: 6, disk: 3, half: 1, zone: 0 + {233, 0, 22, 12, 748, 0, 8, 3, 2, 6, 8, 54, 90, 6, 3, 1}, + {233, 1, 21, 13, 749, 1, 7, 3, 2, 6, 8, 54, 90, 6, 3, 1}, + {233, 2, 20, 14, 750, 2, 6, 3, 2, 6, 8, 54, 90, 6, 3, 1}, + {233, 3, 19, 15, 751, 3, 5, 3, 2, 6, 8, 54, 90, 6, 3, 1}, + // chip: 752 (5), ladder: 20 (29), layer: 6, disk: 3, half: 1, zone: 0 + {234, 0, 5, 9, 752, 0, 8, 0, 3, 7, 6, 55, 91, 6, 3, 1}, + {234, 1, 6, 10, 753, 1, 7, 0, 3, 7, 6, 55, 91, 6, 3, 1}, + {234, 2, 7, 11, 754, 2, 6, 0, 3, 7, 6, 55, 91, 6, 3, 1}, + {234, 3, 24, 12, 755, 3, 5, 0, 3, 7, 6, 55, 91, 6, 3, 1}, + // chip: 756 (5), ladder: 21 (29), layer: 7, disk: 3, half: 1, zone: 0 + {235, 0, 5, 9, 756, 0, 8, 0, 3, 7, 6, 63, 95, 7, 3, 1}, + {235, 1, 6, 10, 757, 1, 7, 0, 3, 7, 6, 63, 95, 7, 3, 1}, + {235, 2, 7, 11, 758, 2, 6, 0, 3, 7, 6, 63, 95, 7, 3, 1}, + {235, 3, 24, 12, 759, 3, 5, 0, 3, 7, 6, 63, 95, 7, 3, 1}, + // chip: 760 (5), ladder: 22 (29), layer: 7, disk: 3, half: 1, zone: 0 + {236, 0, 22, 12, 760, 0, 8, 3, 2, 6, 8, 62, 94, 7, 3, 1}, + {236, 1, 21, 13, 761, 1, 7, 3, 2, 6, 8, 62, 94, 7, 3, 1}, + {236, 2, 20, 14, 762, 2, 6, 3, 2, 6, 8, 62, 94, 7, 3, 1}, + {236, 3, 19, 15, 763, 3, 5, 3, 2, 6, 8, 62, 94, 7, 3, 1}, + // chip: 764 (5), ladder: 23 (29), layer: 7, disk: 3, half: 1, zone: 0 + {237, 0, 17, 8, 764, 0, 8, 2, 2, 6, 8, 62, 94, 7, 3, 1}, + {237, 1, 16, 9, 765, 1, 7, 2, 2, 6, 8, 62, 94, 7, 3, 1}, + {237, 2, 15, 10, 766, 2, 6, 2, 2, 6, 8, 62, 94, 7, 3, 1}, + {237, 3, 14, 11, 767, 3, 5, 2, 2, 6, 8, 62, 94, 7, 3, 1}, + // chip: 768 (5), ladder: 24 (29), layer: 7, disk: 3, half: 1, zone: 0 + {238, 0, 0, 4, 768, 0, 8, 1, 2, 6, 8, 62, 94, 7, 3, 1}, + {238, 1, 1, 5, 769, 1, 7, 1, 2, 6, 8, 62, 94, 7, 3, 1}, + {238, 2, 2, 6, 770, 2, 6, 1, 2, 6, 8, 62, 94, 7, 3, 1}, + {238, 3, 3, 7, 771, 3, 5, 1, 2, 6, 8, 62, 94, 7, 3, 1}, + // chip: 772 (5), ladder: 25 (29), layer: 7, disk: 3, half: 1, zone: 0 + {239, 0, 5, 0, 772, 0, 8, 0, 2, 6, 8, 62, 94, 7, 3, 1}, + {239, 1, 6, 1, 773, 1, 7, 0, 2, 6, 8, 62, 94, 7, 3, 1}, + {239, 2, 7, 2, 774, 2, 6, 0, 2, 6, 8, 62, 94, 7, 3, 1}, + {239, 3, 24, 3, 775, 3, 5, 0, 2, 6, 8, 62, 94, 7, 3, 1}, + // chip: 776 (5), ladder: 26 (29), layer: 7, disk: 3, half: 1, zone: 0 + {240, 0, 22, 12, 776, 0, 8, 3, 1, 5, 8, 61, 93, 7, 3, 1}, + {240, 1, 21, 13, 777, 1, 7, 3, 1, 5, 8, 61, 93, 7, 3, 1}, + {240, 2, 20, 14, 778, 2, 6, 3, 1, 5, 8, 61, 93, 7, 3, 1}, + {240, 3, 19, 15, 779, 3, 5, 3, 1, 5, 8, 61, 93, 7, 3, 1}, + // chip: 780 (5), ladder: 27 (29), layer: 7, disk: 3, half: 1, zone: 0 + {241, 0, 17, 8, 780, 0, 8, 2, 1, 5, 8, 61, 93, 7, 3, 1}, + {241, 1, 16, 9, 781, 1, 7, 2, 1, 5, 8, 61, 93, 7, 3, 1}, + {241, 2, 15, 10, 782, 2, 6, 2, 1, 5, 8, 61, 93, 7, 3, 1}, + {241, 3, 14, 11, 783, 3, 5, 2, 1, 5, 8, 61, 93, 7, 3, 1}, + // chip: 784 (5), ladder: 28 (29), layer: 7, disk: 3, half: 1, zone: 0 + {242, 0, 0, 4, 784, 0, 8, 1, 1, 5, 8, 61, 93, 7, 3, 1}, + {242, 1, 1, 5, 785, 1, 7, 1, 1, 5, 8, 61, 93, 7, 3, 1}, + {242, 2, 2, 6, 786, 2, 6, 1, 1, 5, 8, 61, 93, 7, 3, 1}, + {242, 3, 3, 7, 787, 3, 5, 1, 1, 5, 8, 61, 93, 7, 3, 1}, + // chip: 788 (5), ladder: 29 (29), layer: 7, disk: 3, half: 1, zone: 0 + {243, 0, 5, 0, 788, 0, 8, 0, 1, 5, 8, 61, 93, 7, 3, 1}, + {243, 1, 6, 1, 789, 1, 7, 0, 1, 5, 8, 61, 93, 7, 3, 1}, + {243, 2, 7, 2, 790, 2, 6, 0, 1, 5, 8, 61, 93, 7, 3, 1}, + {243, 3, 24, 3, 791, 3, 5, 0, 1, 5, 8, 61, 93, 7, 3, 1}, + // chip: 792 (5), ladder: 30 (29), layer: 7, disk: 3, half: 1, zone: 0 + {244, 0, 22, 10, 792, 0, 8, 3, 0, 4, 7, 60, 92, 7, 3, 1}, + {244, 1, 21, 11, 793, 1, 7, 3, 0, 4, 7, 60, 92, 7, 3, 1}, + {244, 2, 20, 12, 794, 2, 6, 3, 0, 4, 7, 60, 92, 7, 3, 1}, + {244, 3, 19, 13, 795, 3, 5, 3, 0, 4, 7, 60, 92, 7, 3, 1}, + // chip: 796 (5), ladder: 31 (29), layer: 7, disk: 3, half: 1, zone: 0 + {245, 0, 17, 6, 796, 0, 8, 2, 0, 4, 7, 60, 92, 7, 3, 1}, + {245, 1, 16, 7, 797, 1, 7, 2, 0, 4, 7, 60, 92, 7, 3, 1}, + {245, 2, 15, 8, 798, 2, 6, 2, 0, 4, 7, 60, 92, 7, 3, 1}, + {245, 3, 14, 9, 799, 3, 5, 2, 0, 4, 7, 60, 92, 7, 3, 1}, + // chip: 800 (5), ladder: 0 (29), layer: 8, disk: 4, half: 1, zone: 0 + {246, 0, 5, 0, 800, 0, 8, 0, 0, 4, 11, 68, 96, 8, 4, 1}, + {246, 1, 6, 1, 801, 1, 7, 0, 0, 4, 11, 68, 96, 8, 4, 1}, + {246, 2, 7, 2, 802, 2, 6, 0, 0, 4, 11, 68, 96, 8, 4, 1}, + // chip: 803 (5), ladder: 1 (29), layer: 8, disk: 4, half: 1, zone: 0 + {247, 0, 0, 3, 803, 0, 8, 1, 0, 4, 11, 68, 96, 8, 4, 1}, + {247, 1, 1, 4, 804, 1, 7, 1, 0, 4, 11, 68, 96, 8, 4, 1}, + {247, 2, 2, 5, 805, 2, 6, 1, 0, 4, 11, 68, 96, 8, 4, 1}, + // chip: 806 (5), ladder: 2 (29), layer: 8, disk: 4, half: 1, zone: 0 + {248, 0, 17, 0, 806, 0, 8, 2, 3, 7, 12, 71, 99, 8, 4, 1}, + {248, 1, 16, 1, 807, 1, 7, 2, 3, 7, 12, 71, 99, 8, 4, 1}, + {248, 2, 15, 2, 808, 2, 6, 2, 3, 7, 12, 71, 99, 8, 4, 1}, + // chip: 809 (5), ladder: 3 (29), layer: 8, disk: 4, half: 1, zone: 0 + {249, 0, 22, 3, 809, 0, 8, 3, 3, 7, 12, 71, 99, 8, 4, 1}, + {249, 1, 21, 4, 810, 1, 7, 3, 3, 7, 12, 71, 99, 8, 4, 1}, + {249, 2, 20, 5, 811, 2, 6, 3, 3, 7, 12, 71, 99, 8, 4, 1}, + // chip: 812 (5), ladder: 4 (29), layer: 9, disk: 4, half: 1, zone: 0 + {250, 0, 22, 3, 812, 0, 8, 3, 3, 7, 12, 79, 103, 9, 4, 1}, + {250, 1, 21, 4, 813, 1, 7, 3, 3, 7, 12, 79, 103, 9, 4, 1}, + {250, 2, 20, 5, 814, 2, 6, 3, 3, 7, 12, 79, 103, 9, 4, 1}, + // chip: 815 (5), ladder: 5 (29), layer: 9, disk: 4, half: 1, zone: 0 + {251, 0, 17, 0, 815, 0, 8, 2, 3, 7, 12, 79, 103, 9, 4, 1}, + {251, 1, 16, 1, 816, 1, 7, 2, 3, 7, 12, 79, 103, 9, 4, 1}, + {251, 2, 15, 2, 817, 2, 6, 2, 3, 7, 12, 79, 103, 9, 4, 1}, + // chip: 818 (5), ladder: 6 (29), layer: 9, disk: 4, half: 1, zone: 0 + {252, 0, 0, 3, 818, 0, 8, 1, 0, 4, 11, 76, 100, 9, 4, 1}, + {252, 1, 1, 4, 819, 1, 7, 1, 0, 4, 11, 76, 100, 9, 4, 1}, + {252, 2, 2, 5, 820, 2, 6, 1, 0, 4, 11, 76, 100, 9, 4, 1}, + // chip: 821 (5), ladder: 7 (29), layer: 9, disk: 4, half: 1, zone: 0 + {253, 0, 5, 0, 821, 0, 8, 0, 0, 4, 11, 76, 100, 9, 4, 1}, + {253, 1, 6, 1, 822, 1, 7, 0, 0, 4, 11, 76, 100, 9, 4, 1}, + {253, 2, 7, 2, 823, 2, 6, 0, 0, 4, 11, 76, 100, 9, 4, 1}, + // chip: 824 (5), ladder: 8 (29), layer: 8, disk: 4, half: 1, zone: 0 + {254, 0, 17, 6, 824, 0, 8, 2, 0, 4, 11, 68, 96, 8, 4, 1}, + {254, 1, 16, 7, 825, 1, 7, 2, 0, 4, 11, 68, 96, 8, 4, 1}, + {254, 2, 15, 8, 826, 2, 6, 2, 0, 4, 11, 68, 96, 8, 4, 1}, + {254, 3, 14, 9, 827, 3, 5, 2, 0, 4, 11, 68, 96, 8, 4, 1}, + // chip: 828 (5), ladder: 9 (29), layer: 8, disk: 4, half: 1, zone: 0 + {255, 0, 22, 10, 828, 0, 8, 3, 0, 4, 11, 68, 96, 8, 4, 1}, + {255, 1, 21, 11, 829, 1, 7, 3, 0, 4, 11, 68, 96, 8, 4, 1}, + {255, 2, 20, 12, 830, 2, 6, 3, 0, 4, 11, 68, 96, 8, 4, 1}, + {255, 3, 19, 13, 831, 3, 5, 3, 0, 4, 11, 68, 96, 8, 4, 1}, + // chip: 832 (5), ladder: 10 (29), layer: 8, disk: 4, half: 1, zone: 0 + {256, 0, 0, 0, 832, 0, 8, 1, 1, 5, 9, 69, 97, 8, 4, 1}, + {256, 1, 1, 1, 833, 1, 7, 1, 1, 5, 9, 69, 97, 8, 4, 1}, + {256, 2, 2, 2, 834, 2, 6, 1, 1, 5, 9, 69, 97, 8, 4, 1}, + {256, 3, 3, 3, 835, 3, 5, 1, 1, 5, 9, 69, 97, 8, 4, 1}, + // chip: 836 (5), ladder: 11 (29), layer: 8, disk: 4, half: 1, zone: 0 + {257, 0, 17, 4, 836, 0, 8, 2, 1, 5, 9, 69, 97, 8, 4, 1}, + {257, 1, 16, 5, 837, 1, 7, 2, 1, 5, 9, 69, 97, 8, 4, 1}, + {257, 2, 15, 6, 838, 2, 6, 2, 1, 5, 9, 69, 97, 8, 4, 1}, + {257, 3, 14, 7, 839, 3, 5, 2, 1, 5, 9, 69, 97, 8, 4, 1}, + // chip: 840 (5), ladder: 12 (29), layer: 8, disk: 4, half: 1, zone: 0 + {258, 0, 22, 8, 840, 0, 8, 3, 1, 5, 9, 69, 97, 8, 4, 1}, + {258, 1, 21, 9, 841, 1, 7, 3, 1, 5, 9, 69, 97, 8, 4, 1}, + {258, 2, 20, 10, 842, 2, 6, 3, 1, 5, 9, 69, 97, 8, 4, 1}, + {258, 3, 19, 11, 843, 3, 5, 3, 1, 5, 9, 69, 97, 8, 4, 1}, + // chip: 844 (5), ladder: 13 (29), layer: 8, disk: 4, half: 1, zone: 0 + {259, 0, 5, 0, 844, 0, 8, 0, 2, 6, 10, 70, 98, 8, 4, 1}, + {259, 1, 6, 1, 845, 1, 7, 0, 2, 6, 10, 70, 98, 8, 4, 1}, + {259, 2, 7, 2, 846, 2, 6, 0, 2, 6, 10, 70, 98, 8, 4, 1}, + {259, 3, 24, 3, 847, 3, 5, 0, 2, 6, 10, 70, 98, 8, 4, 1}, + // chip: 848 (5), ladder: 14 (29), layer: 8, disk: 4, half: 1, zone: 0 + {260, 0, 0, 4, 848, 0, 8, 1, 2, 6, 10, 70, 98, 8, 4, 1}, + {260, 1, 1, 5, 849, 1, 7, 1, 2, 6, 10, 70, 98, 8, 4, 1}, + {260, 2, 2, 6, 850, 2, 6, 1, 2, 6, 10, 70, 98, 8, 4, 1}, + {260, 3, 3, 7, 851, 3, 5, 1, 2, 6, 10, 70, 98, 8, 4, 1}, + // chip: 852 (5), ladder: 15 (29), layer: 8, disk: 4, half: 1, zone: 0 + {261, 0, 5, 6, 852, 0, 8, 0, 3, 7, 12, 71, 99, 8, 4, 1}, + {261, 1, 6, 7, 853, 1, 7, 0, 3, 7, 12, 71, 99, 8, 4, 1}, + {261, 2, 7, 8, 854, 2, 6, 0, 3, 7, 12, 71, 99, 8, 4, 1}, + {261, 3, 24, 9, 855, 3, 5, 0, 3, 7, 12, 71, 99, 8, 4, 1}, + // chip: 856 (5), ladder: 16 (29), layer: 8, disk: 4, half: 1, zone: 0 + {262, 0, 0, 10, 856, 0, 8, 1, 3, 7, 12, 71, 99, 8, 4, 1}, + {262, 1, 1, 11, 857, 1, 7, 1, 3, 7, 12, 71, 99, 8, 4, 1}, + {262, 2, 2, 12, 858, 2, 6, 1, 3, 7, 12, 71, 99, 8, 4, 1}, + {262, 3, 3, 13, 859, 3, 5, 1, 3, 7, 12, 71, 99, 8, 4, 1}, + // chip: 860 (5), ladder: 17 (29), layer: 9, disk: 4, half: 1, zone: 0 + {263, 0, 0, 10, 860, 0, 8, 1, 3, 7, 12, 79, 103, 9, 4, 1}, + {263, 1, 1, 11, 861, 1, 7, 1, 3, 7, 12, 79, 103, 9, 4, 1}, + {263, 2, 2, 12, 862, 2, 6, 1, 3, 7, 12, 79, 103, 9, 4, 1}, + {263, 3, 3, 13, 863, 3, 5, 1, 3, 7, 12, 79, 103, 9, 4, 1}, + // chip: 864 (5), ladder: 18 (29), layer: 9, disk: 4, half: 1, zone: 0 + {264, 0, 5, 6, 864, 0, 8, 0, 3, 7, 12, 79, 103, 9, 4, 1}, + {264, 1, 6, 7, 865, 1, 7, 0, 3, 7, 12, 79, 103, 9, 4, 1}, + {264, 2, 7, 8, 866, 2, 6, 0, 3, 7, 12, 79, 103, 9, 4, 1}, + {264, 3, 24, 9, 867, 3, 5, 0, 3, 7, 12, 79, 103, 9, 4, 1}, + // chip: 868 (5), ladder: 19 (29), layer: 9, disk: 4, half: 1, zone: 0 + {265, 0, 0, 4, 868, 0, 8, 1, 2, 6, 10, 78, 102, 9, 4, 1}, + {265, 1, 1, 5, 869, 1, 7, 1, 2, 6, 10, 78, 102, 9, 4, 1}, + {265, 2, 2, 6, 870, 2, 6, 1, 2, 6, 10, 78, 102, 9, 4, 1}, + {265, 3, 3, 7, 871, 3, 5, 1, 2, 6, 10, 78, 102, 9, 4, 1}, + // chip: 872 (5), ladder: 20 (29), layer: 9, disk: 4, half: 1, zone: 0 + {266, 0, 5, 0, 872, 0, 8, 0, 2, 6, 10, 78, 102, 9, 4, 1}, + {266, 1, 6, 1, 873, 1, 7, 0, 2, 6, 10, 78, 102, 9, 4, 1}, + {266, 2, 7, 2, 874, 2, 6, 0, 2, 6, 10, 78, 102, 9, 4, 1}, + {266, 3, 24, 3, 875, 3, 5, 0, 2, 6, 10, 78, 102, 9, 4, 1}, + // chip: 876 (5), ladder: 21 (29), layer: 9, disk: 4, half: 1, zone: 0 + {267, 0, 22, 8, 876, 0, 8, 3, 1, 5, 9, 77, 101, 9, 4, 1}, + {267, 1, 21, 9, 877, 1, 7, 3, 1, 5, 9, 77, 101, 9, 4, 1}, + {267, 2, 20, 10, 878, 2, 6, 3, 1, 5, 9, 77, 101, 9, 4, 1}, + {267, 3, 19, 11, 879, 3, 5, 3, 1, 5, 9, 77, 101, 9, 4, 1}, + // chip: 880 (5), ladder: 22 (29), layer: 9, disk: 4, half: 1, zone: 0 + {268, 0, 17, 4, 880, 0, 8, 2, 1, 5, 9, 77, 101, 9, 4, 1}, + {268, 1, 16, 5, 881, 1, 7, 2, 1, 5, 9, 77, 101, 9, 4, 1}, + {268, 2, 15, 6, 882, 2, 6, 2, 1, 5, 9, 77, 101, 9, 4, 1}, + {268, 3, 14, 7, 883, 3, 5, 2, 1, 5, 9, 77, 101, 9, 4, 1}, + // chip: 884 (5), ladder: 23 (29), layer: 9, disk: 4, half: 1, zone: 0 + {269, 0, 0, 0, 884, 0, 8, 1, 1, 5, 9, 77, 101, 9, 4, 1}, + {269, 1, 1, 1, 885, 1, 7, 1, 1, 5, 9, 77, 101, 9, 4, 1}, + {269, 2, 2, 2, 886, 2, 6, 1, 1, 5, 9, 77, 101, 9, 4, 1}, + {269, 3, 3, 3, 887, 3, 5, 1, 1, 5, 9, 77, 101, 9, 4, 1}, + // chip: 888 (5), ladder: 24 (29), layer: 9, disk: 4, half: 1, zone: 0 + {270, 0, 22, 10, 888, 0, 8, 3, 0, 4, 11, 76, 100, 9, 4, 1}, + {270, 1, 21, 11, 889, 1, 7, 3, 0, 4, 11, 76, 100, 9, 4, 1}, + {270, 2, 20, 12, 890, 2, 6, 3, 0, 4, 11, 76, 100, 9, 4, 1}, + {270, 3, 19, 13, 891, 3, 5, 3, 0, 4, 11, 76, 100, 9, 4, 1}, + // chip: 892 (5), ladder: 25 (29), layer: 9, disk: 4, half: 1, zone: 0 + {271, 0, 17, 6, 892, 0, 8, 2, 0, 4, 11, 76, 100, 9, 4, 1}, + {271, 1, 16, 7, 893, 1, 7, 2, 0, 4, 11, 76, 100, 9, 4, 1}, + {271, 2, 15, 8, 894, 2, 6, 2, 0, 4, 11, 76, 100, 9, 4, 1}, + {271, 3, 14, 9, 895, 3, 5, 2, 0, 4, 11, 76, 100, 9, 4, 1}, + // chip: 896 (5), ladder: 26 (29), layer: 8, disk: 4, half: 1, zone: 0 + {272, 0, 12, 14, 896, 0, 8, 4, 0, 4, 11, 68, 96, 8, 4, 1}, + {272, 1, 11, 15, 897, 1, 7, 4, 0, 4, 11, 68, 96, 8, 4, 1}, + {272, 2, 10, 16, 898, 2, 6, 4, 0, 4, 11, 68, 96, 8, 4, 1}, + {272, 3, 9, 17, 899, 3, 5, 4, 0, 4, 11, 68, 96, 8, 4, 1}, + {272, 4, 8, 18, 900, 4, 4, 4, 0, 4, 11, 68, 96, 8, 4, 1}, + // chip: 901 (5), ladder: 27 (29), layer: 8, disk: 4, half: 1, zone: 0 + {273, 0, 5, 12, 901, 0, 8, 0, 1, 5, 9, 69, 97, 8, 4, 1}, + {273, 1, 6, 13, 902, 1, 7, 0, 1, 5, 9, 69, 97, 8, 4, 1}, + {273, 2, 7, 14, 903, 2, 6, 0, 1, 5, 9, 69, 97, 8, 4, 1}, + {273, 3, 24, 15, 904, 3, 5, 0, 1, 5, 9, 69, 97, 8, 4, 1}, + {273, 4, 23, 16, 905, 4, 4, 0, 1, 5, 9, 69, 97, 8, 4, 1}, + // chip: 906 (5), ladder: 28 (29), layer: 8, disk: 4, half: 1, zone: 0 + {274, 0, 17, 8, 906, 0, 8, 2, 2, 6, 10, 70, 98, 8, 4, 1}, + {274, 1, 16, 9, 907, 1, 7, 2, 2, 6, 10, 70, 98, 8, 4, 1}, + {274, 2, 15, 10, 908, 2, 6, 2, 2, 6, 10, 70, 98, 8, 4, 1}, + {274, 3, 14, 11, 909, 3, 5, 2, 2, 6, 10, 70, 98, 8, 4, 1}, + {274, 4, 13, 12, 910, 4, 4, 2, 2, 6, 10, 70, 98, 8, 4, 1}, + // chip: 911 (5), ladder: 29 (29), layer: 8, disk: 4, half: 1, zone: 0 + {275, 0, 22, 13, 911, 0, 8, 3, 2, 6, 10, 70, 98, 8, 4, 1}, + {275, 1, 21, 14, 912, 1, 7, 3, 2, 6, 10, 70, 98, 8, 4, 1}, + {275, 2, 20, 15, 913, 2, 6, 3, 2, 6, 10, 70, 98, 8, 4, 1}, + {275, 3, 19, 16, 914, 3, 5, 3, 2, 6, 10, 70, 98, 8, 4, 1}, + {275, 4, 18, 17, 915, 4, 4, 3, 2, 6, 10, 70, 98, 8, 4, 1}, + // chip: 916 (5), ladder: 30 (29), layer: 9, disk: 4, half: 1, zone: 0 + {276, 0, 22, 13, 916, 0, 8, 3, 2, 6, 10, 78, 102, 9, 4, 1}, + {276, 1, 21, 14, 917, 1, 7, 3, 2, 6, 10, 78, 102, 9, 4, 1}, + {276, 2, 20, 15, 918, 2, 6, 3, 2, 6, 10, 78, 102, 9, 4, 1}, + {276, 3, 19, 16, 919, 3, 5, 3, 2, 6, 10, 78, 102, 9, 4, 1}, + {276, 4, 18, 17, 920, 4, 4, 3, 2, 6, 10, 78, 102, 9, 4, 1}, + // chip: 921 (5), ladder: 31 (29), layer: 9, disk: 4, half: 1, zone: 0 + {277, 0, 17, 8, 921, 0, 8, 2, 2, 6, 10, 78, 102, 9, 4, 1}, + {277, 1, 16, 9, 922, 1, 7, 2, 2, 6, 10, 78, 102, 9, 4, 1}, + {277, 2, 15, 10, 923, 2, 6, 2, 2, 6, 10, 78, 102, 9, 4, 1}, + {277, 3, 14, 11, 924, 3, 5, 2, 2, 6, 10, 78, 102, 9, 4, 1}, + {277, 4, 13, 12, 925, 4, 4, 2, 2, 6, 10, 78, 102, 9, 4, 1}, + // chip: 926 (5), ladder: 32 (29), layer: 9, disk: 4, half: 1, zone: 0 + {278, 0, 5, 12, 926, 0, 8, 0, 1, 5, 9, 77, 101, 9, 4, 1}, + {278, 1, 6, 13, 927, 1, 7, 0, 1, 5, 9, 77, 101, 9, 4, 1}, + {278, 2, 7, 14, 928, 2, 6, 0, 1, 5, 9, 77, 101, 9, 4, 1}, + {278, 3, 24, 15, 929, 3, 5, 0, 1, 5, 9, 77, 101, 9, 4, 1}, + {278, 4, 23, 16, 930, 4, 4, 0, 1, 5, 9, 77, 101, 9, 4, 1}, // chip: 931 (5), ladder: 33 (29), layer: 9, disk: 4, half: 1, zone: 0 - {279, 0, 12, 14}, - {279, 1, 11, 15}, - {279, 2, 10, 16}, - {279, 3, 9, 17}, - {279, 4, 8, 18}}}; + {279, 0, 12, 14, 931, 0, 8, 4, 0, 4, 11, 76, 100, 9, 4, 1}, + {279, 1, 11, 15, 932, 1, 7, 4, 0, 4, 11, 76, 100, 9, 4, 1}, + {279, 2, 10, 16, 933, 2, 6, 4, 0, 4, 11, 76, 100, 9, 4, 1}, + {279, 3, 9, 17, 934, 3, 5, 4, 0, 4, 11, 76, 100, 9, 4, 1}, + {279, 4, 8, 18, 935, 4, 4, 4, 0, 4, 11, 76, 100, 9, 4, 1}}}; const std::array<MFTModuleMappingData, ChipMappingMFT::NModules> ChipMappingMFT::ModuleMappingData{{ @@ -1652,6 +1653,7 @@ ChipMappingMFT::ChipMappingMFT() mChipInfoEntryRU[iRU] = ctrChip; mCableHW2SW[iRU].resize(NRUCables, 0xff); mCableHW2Pos[iRU].resize(NRUCables, 0xff); + mCablePos[iRU].resize(NRUCables, 0xff); mCableHWFirstChip[iRU].resize(NRUCables, 0xff); } else { if ((layer != curLayer) || (zone != curZone) || (half != curHalf)) { @@ -1676,10 +1678,11 @@ ChipMappingMFT::ChipMappingMFT() chInfo.cableHW = ChipConnectorCable[chInfo.moduleHW][chInfo.chipOnModuleSW]; chInfo.cableSW = chipOnRU; - chInfo.cableHWPos = chipOnRU; + chInfo.cableHWPos = chInfo.cableHW; chInfo.chipOnCable = 0; + mCablePos[iRU][chInfo.id] = chInfo.cableHWPos; mCableHW2Pos[iRU][chInfo.cableHW] = chInfo.cableHWPos; mCableHW2SW[iRU][chInfo.cableHW] = chInfo.cableSW; mCableHWFirstChip[iRU][chInfo.cableHW] = 0; @@ -1727,3 +1730,26 @@ ChipMappingMFT::ChipMappingMFT() } } } + +//_____________________________________________________________________________ +void ChipMappingMFT::print() const +{ + printf("ChipIDglo ChipIDlocSW ChipIDlocHW Half Disk Layer RUIDSW RUIDHW Type RUonLayer Zone Cnct CableHW ChipOnRU \n"); + for (int iChip = 0; iChip < NChips; ++iChip) { + printf("%-12d%-14d%-14d%-7d%-7d%-8d%-9d0x%-7x%-7d%-12d%-7d%-7d%-10d%-12d\n", + ChipMappingData[iChip].globalChipSWID, + ChipMappingData[iChip].localChipSWID, + ChipMappingData[iChip].localChipHWID, + ChipMappingData[iChip].half, + ChipMappingData[iChip].disk, + ChipMappingData[iChip].layer, + ChipMappingData[iChip].ruSWID, + ChipMappingData[iChip].ruHWID, + ChipMappingData[iChip].ruType, + ChipMappingData[iChip].ruOnLayer, + ChipMappingData[iChip].zone, + ChipMappingData[iChip].connector, + ChipMappingData[iChip].cable, + ChipMappingData[iChip].chipOnRU); + } +} diff --git a/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx b/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx index 741b0fd28d6fc..1ef185219692c 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,6 @@ #ifdef WITH_OPENMP #include <omp.h> #endif - using namespace o2::itsmft; //__________________________________________________ @@ -161,7 +161,6 @@ void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClu if (stats.empty() || stats.back().firstChip + stats.back().nChips < chip) { // there is a jump, register new block stats.emplace_back(ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0}); } - for (int ic = 0; ic < nChips; ic++) { auto* curChipData = parent->mFiredChipsPtr[chip + ic]; auto chipID = curChipData->getChipID(); @@ -171,6 +170,7 @@ void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClu parent->mMaxRowColDiffToMask ? curChipData->maskFiredInSample(parent->mChipsOld[chipID], parent->mMaxRowColDiffToMask) : curChipData->maskFiredInSample(parent->mChipsOld[chipID]); } } + auto nclus0 = compClusPtr->size(); auto validPixID = curChipData->getFirstUnmasked(); auto npix = curChipData->getData().size(); if (validPixID < npix) { // chip data may have all of its pixels masked! @@ -208,8 +208,7 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus if (ci < 0) { continue; } - uint16_t rowMax = 0, rowMin = 65535; - uint16_t colMax = 0, colMin = 65535; + BBox bbox(curChipData->getChipID()); int nlab = 0; int next = preClusterHeads[i1]; pixArrBuff.clear(); @@ -217,7 +216,7 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus const auto& pixEntry = pixels[next]; const auto pix = pixData[pixEntry.second]; pixArrBuff.push_back(pix); // needed for cluster topology - adjustBoundingBox(pix.getRowDirect(), pix.getCol(), rowMin, rowMax, colMin, colMax); + bbox.adjust(pix.getRowDirect(), pix.getCol()); if (labelsClusPtr) { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab); } @@ -233,7 +232,7 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus const auto& pixEntry = pixels[next]; const auto pix = pixData[pixEntry.second]; // PixelData pixArrBuff.push_back(pix); // needed for cluster topology - adjustBoundingBox(pix.getRowDirect(), pix.getCol(), rowMin, rowMax, colMin, colMax); + bbox.adjust(pix.getRowDirect(), pix.getCol()); if (labelsClusPtr) { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab); } @@ -242,91 +241,32 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus preClusterIndices[i2] = -1; } - auto chipID = curChipData->getChipID(); - uint16_t colSpan = (colMax - colMin + 1); - uint16_t rowSpan = (rowMax - rowMin + 1); - if (colSpan <= o2::itsmft::ClusterPattern::MaxColSpan && - rowSpan <= o2::itsmft::ClusterPattern::MaxRowSpan) { - streamCluster(pixArrBuff, rowMin, rowSpan, colMin, colSpan, chipID, - compClusPtr, patternsPtr, labelsClusPtr, nlab); + if (bbox.isAcceptableSize()) { + parent->streamCluster(pixArrBuff, &labelsBuff, bbox, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab); } else { - LOG(WARNING) << "Splitting a huge cluster ! ChipID: " << chipID; - - colSpan %= o2::itsmft::ClusterPattern::MaxColSpan; - if (colSpan == 0) { - colSpan = o2::itsmft::ClusterPattern::MaxColSpan; - } - - rowSpan %= o2::itsmft::ClusterPattern::MaxRowSpan; - if (rowSpan == 0) { - rowSpan = o2::itsmft::ClusterPattern::MaxRowSpan; - } - + LOGP(warning, "Splitting a huge cluster: chipID {}, rows {}:{} cols {}:{}", bbox.chipID, bbox.rowMin, bbox.rowMax, bbox.colMin, bbox.colMax); + BBox bboxT(bbox); // truncated box + std::vector<PixelData> pixbuf; do { - uint16_t r = rowMin, rsp = rowSpan; - - do { - // Select a subset of pixels fitting the reduced bounding box - std::vector<PixelData> pixbuf; - auto colMax = colMin + colSpan, rowMax = r + rsp; + bboxT.rowMin = bbox.rowMin; + bboxT.colMax = std::min(bbox.colMax, uint16_t(bboxT.colMin + o2::itsmft::ClusterPattern::MaxColSpan - 1)); + do { // Select a subset of pixels fitting the reduced bounding box + bboxT.rowMax = std::min(bbox.rowMax, uint16_t(bboxT.rowMin + o2::itsmft::ClusterPattern::MaxRowSpan - 1)); for (const auto& pix : pixArrBuff) { - if (pix.getRowDirect() >= r && pix.getRowDirect() < rowMax && - pix.getCol() >= colMin && pix.getCol() < colMax) { + if (bboxT.isInside(pix.getRowDirect(), pix.getCol())) { pixbuf.push_back(pix); } } - // Stream a piece of cluster only if the reduced bounding box is not empty - if (!pixbuf.empty()) { - streamCluster(pixbuf, r, rsp, colMin, colSpan, chipID, - compClusPtr, patternsPtr, labelsClusPtr, nlab, true); + if (!pixbuf.empty()) { // Stream a piece of cluster only if the reduced bounding box is not empty + parent->streamCluster(pixbuf, &labelsBuff, bboxT, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab, true); + pixbuf.clear(); } - r += rsp; - rsp = o2::itsmft::ClusterPattern::MaxRowSpan; - } while (r < rowMax); - - colMin += colSpan; - colSpan = o2::itsmft::ClusterPattern::MaxColSpan; - } while (colMin < colMax); - } - } -} - -void Clusterer::ClustererThread::streamCluster(const std::vector<PixelData>& pixbuf, uint16_t rowMin, uint16_t rowSpanW, uint16_t colMin, uint16_t colSpanW, uint16_t chipID, CompClusCont* compClusPtr, PatternCont* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isHuge) -{ - if (labelsClusPtr) { // MC labels were requested - auto cnt = compClusPtr->size(); - for (int i = nlab; i--;) { - labelsClusPtr->addElement(cnt, labelsBuff[i]); - } - } - - // add to compact clusters, which must be always filled - unsigned char patt[ClusterPattern::MaxPatternBytes] = {0}; // RSTODO FIX pattern filling - for (const auto& pix : pixbuf) { - unsigned short ir = pix.getRowDirect() - rowMin, ic = pix.getCol() - colMin; - int nbits = ir * colSpanW + ic; - patt[nbits >> 3] |= (0x1 << (7 - (nbits % 8))); - } - uint16_t pattID = (isHuge || parent->mPattIdConverter.size() == 0) ? CompCluster::InvalidPatternID : parent->mPattIdConverter.findGroupID(rowSpanW, colSpanW, patt); - if (pattID == CompCluster::InvalidPatternID || parent->mPattIdConverter.isGroup(pattID)) { - if (pattID != CompCluster::InvalidPatternID) { - //For groupped topologies, the reference pixel is the COG pixel - float xCOG = 0., zCOG = 0.; - ClusterPattern::getCOG(rowSpanW, colSpanW, patt, xCOG, zCOG); - rowMin += round(xCOG); - colMin += round(zCOG); - } - if (patternsPtr) { - patternsPtr->emplace_back((unsigned char)rowSpanW); - patternsPtr->emplace_back((unsigned char)colSpanW); - int nBytes = rowSpanW * colSpanW / 8; - if (((rowSpanW * colSpanW) % 8) != 0) { - nBytes++; - } - patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + nBytes); + bboxT.rowMin = bboxT.rowMax + 1; + } while (bboxT.rowMin < bbox.rowMax); + bboxT.colMin = bboxT.colMax + 1; + } while (bboxT.colMin < bbox.colMax); } } - compClusPtr->emplace_back(rowMin, colMin, pattID, chipID); } //__________________________________________________ @@ -417,7 +357,11 @@ void Clusterer::ClustererThread::updateChip(const ChipPixelData* curChipData, ui return; } } else { +#ifdef _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_ int neighbours[]{curr[row - 1], prev[row], prev[row + 1], prev[row - 1]}; +#else + int neighbours[]{curr[row - 1], prev[row]}; +#endif for (auto pci : neighbours) { if (pci < 0) { continue; diff --git a/Detectors/ITSMFT/common/reconstruction/src/ClustererParam.cxx b/Detectors/ITSMFT/common/reconstruction/src/ClustererParam.cxx index 05b6123411572..ab7fe235a159d 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/ClustererParam.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/ClustererParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx b/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx index 270b6bd129c44..656f3f546b6ab 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,56 +14,93 @@ #include <bitset> #include "ITSMFTReconstruction/DecodingStat.h" +#include "ITSMFTReconstruction/PixelData.h" #include "Framework/Logger.h" using namespace o2::itsmft; constexpr std::array<std::string_view, ChipStat::NErrorsDefined> ChipStat::ErrNames; ///_________________________________________________________________ -/// print chip decoding statistics -void ChipStat::print(bool skipEmpty) const +uint32_t ChipStat::getNErrors() const { - uint32_t nErr = 0; + uint32_t nerr = 0; for (int i = NErrorsDefined; i--;) { - nErr += errorCounts[i]; + nerr += errorCounts[i]; } - LOGF(INFO, "Chip#%5d NHits: %9zu errors: %u", chipID, nHits, nErr); - for (int i = 0; i < NErrorsDefined; i++) { - if (!skipEmpty || errorCounts[i]) { - LOGF(INFO, "%-70s: %u", ErrNames[i].data(), errorCounts[i]); + return nerr; +} + +///_________________________________________________________________ +/// print link decoding statistics +void ChipStat::addErrors(uint32_t mask, uint16_t chID, int verbosity) +{ + if (mask) { + for (int i = NErrorsDefined; i--;) { + if (mask & (0x1 << i)) { + if (verbosity > -1 && (!errorCounts[i] || verbosity > 1)) { + LOGP(ERROR, "New error registered on the FEEID:{:#04x}: chip#{}: {}", feeID, chID, ErrNames[i]); + } + errorCounts[i]++; + } } } } ///_________________________________________________________________ -uint32_t ChipStat::getNErrors() const +/// print link decoding statistics +void ChipStat::addErrors(const ChipPixelData& d, int verbosity) { - uint32_t nerr = 0; + if (d.getErrorFlags()) { + for (int i = NErrorsDefined; i--;) { + if (d.getErrorFlags() & (0x1 << i)) { + if (verbosity > -1 && (!errorCounts[i] || verbosity > 1)) { + LOGP(ERROR, "New error registered on the FEEID:{:#04x} chip#{}: {}{}", feeID, int16_t(d.getChipID()), ErrNames[i], d.getErrorDetails(i)); + } + errorCounts[i]++; + } + } + } +} + +///_________________________________________________________________ +/// print chip decoding statistics +void ChipStat::print(bool skipNoErr, const std::string& pref) const +{ + uint32_t nErr = 0; for (int i = NErrorsDefined; i--;) { - nerr += errorCounts[i]; + nErr += errorCounts[i]; + } + if (!skipNoErr || nErr) { + LOGP(INFO, "{}#{:x} NHits: {} errors: {}", pref.c_str(), feeID, nHits, nErr); + for (int i = 0; i < NErrorsDefined; i++) { + if (!skipNoErr || errorCounts[i]) { + LOGP(INFO, "Err.: {}: {}", ErrNames[i].data(), errorCounts[i]); + } + } } - return nerr; } ///_________________________________________________________________ /// print link decoding statistics -void GBTLinkDecodingStat::print(bool skipEmpty) const +void GBTLinkDecodingStat::print(bool skipNoErr) const { int nErr = 0; for (int i = NErrorsDefined; i--;) { nErr += errorCounts[i]; } - LOGF(INFO, "GBTLink#0x%d Packet States Statistics (total packets: %d)", ruLinkID, nPackets); - for (int i = 0; i < GBTDataTrailer::MaxStateCombinations; i++) { - if (packetStates[i]) { - std::bitset<GBTDataTrailer::NStatesDefined> patt(i); - LOGF(INFO, "counts for triggers B[%s] : %d", patt.to_string().c_str(), packetStates[i]); + if (!skipNoErr || nErr) { + LOGP(INFO, "FEEID#{%s} Packet States Statistics (total packets: {}, triggers: {})", ruLinkID, nPackets, nTriggers); + for (int i = 0; i < GBTDataTrailer::MaxStateCombinations; i++) { + if (packetStates[i]) { + std::bitset<GBTDataTrailer::NStatesDefined> patt(i); + LOGP(INFO, "counts for triggers B{:s}: {}", patt.to_string().c_str(), packetStates[i]); + } } - } - LOGF(INFO, "Decoding errors: %u", nErr); - for (int i = 0; i < NErrorsDefined; i++) { - if (!skipEmpty || errorCounts[i]) { - LOGF(INFO, "%-70s: %u", ErrNames[i].data(), errorCounts[i]); + LOGP(INFO, "Decoding errors: {}", nErr); + for (int i = 0; i < NErrorsDefined; i++) { + if (!skipNoErr || errorCounts[i]) { + LOGF(INFO, "{<}: {}", ErrNames[i].data(), errorCounts[i]); + } } } } diff --git a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx index 44fd0cb25f224..a0c8116816320 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -116,7 +117,7 @@ void DigitPixelReader::openInput(const std::string inpName, o2::detectors::DetID } mInputTree->SetBranchAddress((detName + "DigitMCTruth").data(), &mDigitsMCTruthSelf); - setDigitsMCTruth(mDigitsMCTruthSelf); // it will be assigned again at the reading, this is just to signal that the MCtruth is there + //setDigitsMCTruth(mDigitsMCTruthSelf); // it will be assigned again at the reading, this is just to signal that the MCtruth is there } //______________________________________________________________________________ @@ -134,7 +135,7 @@ bool DigitPixelReader::readNextEntry() setDigits(gsl::span(mDigitsSelf->data(), mDigitsSelf->size())); setROFRecords(gsl::span(mROFRecVecSelf->data(), mROFRecVecSelf->size())); setMC2ROFRecords(gsl::span(mMC2ROFRecVecSelf->data(), mMC2ROFRecVecSelf->size())); - setDigitsMCTruth(mDigitsMCTruthSelf); + //setDigitsMCTruth(mDigitsMCTruthSelf); return true; } else { return false; diff --git a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx index efafcf3422abc..f1e9452ef1ce3 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,6 +33,7 @@ using RDH = o2::header::RAWDataHeader; /// create link with given ids GBTLink::GBTLink(uint16_t _cru, uint16_t _fee, uint8_t _ep, uint8_t _idInCru, uint16_t _chan) : idInCRU(_idInCru), cruID(_cru), feeID(_fee), endPointID(_ep), channelID(_chan) { + chipStat.feeID = _fee; } ///_________________________________________________________________ @@ -40,8 +42,10 @@ std::string GBTLink::describe() const { std::stringstream ss; ss << "Link cruID=0x" << std::hex << std::setw(4) << std::setfill('0') << cruID << std::dec - << "/lID=" << int(idInCRU) << "/feeID=0x" << std::hex << std::setw(4) << std::setfill('0') << feeID << std::dec - << " lanes: " << std::bitset<28>(lanes).to_string(); + << "/lID=" << int(idInCRU) << "/feeID=0x" << std::hex << std::setw(4) << std::setfill('0') << feeID << std::dec; + if (lanes) { + ss << " lanes: " << std::bitset<28>(lanes).to_string(); + } return ss.str(); } @@ -137,7 +141,7 @@ GBTLink::ErrorType GBTLink::checkErrorsRDH(const RDH& rdh) ErrorType err = NoError; if (!RDHUtils::checkRDH(rdh, true)) { statistics.errorCounts[GBTLinkDecodingStat::ErrNoRDHAtStart]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrNoRDHAtStart])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNoRDHAtStart]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrNoRDHAtStart); @@ -154,7 +158,7 @@ GBTLink::ErrorType GBTLink::checkErrorsRDH(const RDH& rdh) } if ((RDHUtils::getPacketCounter(rdh) > packetCounter + 1) && packetCounter >= 0) { statistics.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump] << " : jump from " << int(packetCounter) << " to " << int(RDHUtils::getPacketCounter(rdh)); } @@ -172,7 +176,7 @@ GBTLink::ErrorType GBTLink::checkErrorsRDHStop(const RDH& rdh) if (format == NewFormat && lastRDH && RDHUtils::getHeartBeatOrbit(*lastRDH) != RDHUtils::getHeartBeatOrbit(rdh) // new HB starts && !RDHUtils::getStop(*lastRDH)) { statistics.errorCounts[GBTLinkDecodingStat::ErrPageNotStopped]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrPageNotStopped])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPageNotStopped]; RDHUtils::printRDH(*lastRDH); RDHUtils::printRDH(rdh); @@ -189,7 +193,7 @@ GBTLink::ErrorType GBTLink::checkErrorsRDHStopPageEmpty(const RDH& rdh) { if (format == NewFormat && RDHUtils::getStop(rdh) && RDHUtils::getMemorySize(rdh) != sizeof(RDH) + sizeof(GBTDiagnostic)) { statistics.errorCounts[GBTLinkDecodingStat::ErrStopPageNotEmpty]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrStopPageNotEmpty])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrStopPageNotEmpty]; RDHUtils::printRDH(rdh); } @@ -204,9 +208,9 @@ GBTLink::ErrorType GBTLink::checkErrorsRDHStopPageEmpty(const RDH& rdh) GBTLink::ErrorType GBTLink::checkErrorsTriggerWord(const GBTTrigger* gbtTrg) { if (!gbtTrg->isTriggerWord()) { // check trigger word - gbtTrg->printX(); statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrigger]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrigger])) { + gbtTrg->printX(); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTTrigger]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTTrigger); @@ -229,8 +233,8 @@ GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeader* gbtH) { if (!gbtH->isDataHeader()) { // check header word statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++; - gbtH->printX(); - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader])) { + gbtH->printX(); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTHeader]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTHeader); @@ -245,8 +249,8 @@ GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeaderL* gbtH) { if (!gbtH->isDataHeader()) { // check header word statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++; - gbtH->printX(); if (verbosity >= VerboseErrors) { + gbtH->printX(); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTHeader]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTHeader); @@ -256,7 +260,7 @@ GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeaderL* gbtH) // RSTODO: this makes sense only for old format, where every trigger has its RDH if (gbtH->packetIdx != cnt) { statistics.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt] << ": diff in GBT header " << gbtH->packetIdx << " and RDH page " << cnt << " counters"; } @@ -268,7 +272,7 @@ GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeaderL* gbtH) //if (cnt) { // makes sens for old format only if (gbtH->packetIdx) { statistics.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNonZeroPageAfterStop] << ": Non-0 page counter (" << cnt << ") while all lanes were stopped"; } @@ -285,8 +289,8 @@ GBTLink::ErrorType GBTLink::checkErrorsActiveLanes(int cbl) { if (~cbl & lanesActive) { // are there wrong lanes? statistics.errorCounts[GBTLinkDecodingStat::ErrInvalidActiveLanes]++; - std::bitset<32> expectL(cbl), gotL(lanesActive); - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrInvalidActiveLanes])) { + std::bitset<32> expectL(cbl), gotL(lanesActive); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrInvalidActiveLanes] << ' ' << gotL << " vs " << expectL << " skip page"; } @@ -303,7 +307,7 @@ GBTLink::ErrorType GBTLink::checkErrorsGBTData(int cablePos) lanesWithData |= 0x1 << cablePos; // flag that the data was seen on this lane if (lanesStop & (0x1 << cablePos)) { // make sure stopped lanes do not transmit the data statistics.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrDataForStoppedLane] << cablePos; } @@ -321,14 +325,16 @@ GBTLink::ErrorType GBTLink::checkErrorsGBTDataID(const GBTData* gbtD) if (gbtD->isData()) { return NoError; } - if (gbtD->isCableDiagnostic()) { - printCableDiagnostic((GBTCableDiagnostic*)gbtD); - } else if (gbtD->isStatus()) { - printCableStatus((GBTCableStatus*)gbtD); - } - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrGBTWordNotRecognized]; - gbtD->printX(true); statistics.errorCounts[GBTLinkDecodingStat::ErrGBTWordNotRecognized]++; + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrGBTWordNotRecognized])) { + if (gbtD->isCableDiagnostic()) { + printCableDiagnostic((GBTCableDiagnostic*)gbtD); + } else if (gbtD->isStatus()) { + printCableStatus((GBTCableStatus*)gbtD); + } + gbtD->printX(true); + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrGBTWordNotRecognized]; + } return Skip; } @@ -339,7 +345,7 @@ GBTLink::ErrorType GBTLink::checkErrorsTrailerWord(const GBTDataTrailer* gbtT) if (!gbtT->isDataTrailer()) { gbtT->printX(); statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTTrailer]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTTrailer); @@ -356,7 +362,7 @@ GBTLink::ErrorType GBTLink::checkErrorsPacketDoneMissing(const GBTDataTrailer* g { if (!gbtT->packetDone && notEnd) { // Done may be missing only in case of carry-over to new CRU page statistics.errorCounts[GBTLinkDecodingStat::ErrPacketDoneMissing]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrPacketDoneMissing])) { LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPacketDoneMissing]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrPacketDoneMissing); @@ -374,8 +380,8 @@ GBTLink::ErrorType GBTLink::checkErrorsLanesStops() if ((lanesActive & ~lanesStop)) { if (RDHUtils::getTriggerType(*lastRDH) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes? statistics.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++; - std::bitset<32> active(lanesActive), stopped(lanesStop); - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes])) { + std::bitset<32> active(lanesActive), stopped(lanesStop); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrUnstoppedLanes] << " | active: " << active << " stopped: " << stopped; } @@ -385,9 +391,9 @@ GBTLink::ErrorType GBTLink::checkErrorsLanesStops() } // make sure all active lanes (except those in time-out) have sent some data if ((~lanesWithData & lanesActive) != lanesTimeOut) { - std::bitset<32> withData(lanesWithData), active(lanesActive), timeOut(lanesTimeOut); statistics.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++; - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane])) { + std::bitset<32> withData(lanesWithData), active(lanesActive), timeOut(lanesTimeOut); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNoDataForActiveLane] << " | with data: " << withData << " active: " << active << " timeOut: " << timeOut; } @@ -403,8 +409,8 @@ GBTLink::ErrorType GBTLink::checkErrorsDiagnosticWord(const GBTDiagnostic* gbtD) { if (RDHUtils::getMemorySize(lastRDH) != sizeof(RDH) + sizeof(GBTDiagnostic) || !gbtD->isDiagnosticWord()) { // statistics.errorCounts[GBTLinkDecodingStat::ErrMissingDiagnosticWord]++; - gbtD->printX(); - if (verbosity >= VerboseErrors) { + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrMissingDiagnosticWord])) { + gbtD->printX(); LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingDiagnosticWord]; } errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingDiagnosticWord); diff --git a/Detectors/ITSMFT/common/reconstruction/src/GBTWord.cxx b/Detectors/ITSMFT/common/reconstruction/src/GBTWord.cxx index f11e857fde59f..9970ffa05b307 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/GBTWord.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/GBTWord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h b/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h index 168ba17660404..b3eadad76ac6c 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h +++ b/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,9 +15,6 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::itsmft::RawPixelDecoder < o2::itsmft::ChipMappingITS> + ; -#pragma link C++ class o2::itsmft::RawPixelDecoder < o2::itsmft::ChipMappingMFT> + ; - #pragma link C++ class o2::itsmft::Clusterer + ; #pragma link C++ class o2::itsmft::PixelReader + ; #pragma link C++ class o2::itsmft::DigitPixelReader + ; diff --git a/Detectors/ITSMFT/common/reconstruction/src/LookUp.cxx b/Detectors/ITSMFT/common/reconstruction/src/LookUp.cxx index ee7f6be12ee32..b2efb46026b89 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/LookUp.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/LookUp.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,7 +57,7 @@ int LookUp::groupFinder(int nRow, int nCol) return grNum; } -int LookUp::findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPattern::MaxPatternBytes]) +int LookUp::findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPattern::MaxPatternBytes]) const { int nBits = nRow * nCol; // Small topology @@ -66,7 +67,8 @@ int LookUp::findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPatt return ID; } else { //small rare topology (inside groups) int index = groupFinder(nRow, nCol); - return mDictionary.mGroupMap[index]; + auto res = mDictionary.mGroupMap.find(index); + return res == mDictionary.mGroupMap.end() ? -1 : res->second; } } // Big topology @@ -76,14 +78,10 @@ int LookUp::findGroupID(int nRow, int nCol, const unsigned char patt[ClusterPatt return ret->second; } else { // Big rare topology (inside groups) int index = groupFinder(nRow, nCol); - return mDictionary.mGroupMap[index]; + auto res = mDictionary.mGroupMap.find(index); + return res == mDictionary.mGroupMap.end() ? -1 : res->second; } } -bool LookUp::isGroup(int id) const -{ - return mDictionary.isGroup(id); -} - } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx b/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx index b38212cc9715a..e3d4cd59d8355 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/reconstruction/src/PixelData.cxx b/Detectors/ITSMFT/common/reconstruction/src/PixelData.cxx index e488c93a9214c..a643f6fc4af1d 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/PixelData.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/PixelData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "ITSMFTReconstruction/PixelData.h" #include "ITSMFTBase/SegmentationAlpide.h" +#include "Framework/Logger.h" #include <cassert> #include <bitset> @@ -35,3 +37,21 @@ void ChipPixelData::print() const printf("#%4d C:%4d R: %3d %s\n", i, mPixels[i].getCol(), mPixels[i].getRow(), mPixels[i].isMasked() ? "*" : ""); } } + +std::string ChipPixelData::getErrorDetails(int pos) const +{ + // if possible, extract more detailed info about the error + if (pos == int(ChipStat::RepeatingPixel)) { + return fmt::format(": row{}/col{}", mErrorInfo & 0xffff, (mErrorInfo >> 16) & 0xffff); + } + if (pos == int(ChipStat::UnknownWord)) { + std::string rbuf = ": 0x<"; + int nc = getNBytesInRawBuff(); + for (int i = 0; i < nc; i++) { + rbuf += fmt::format(i ? " {:02x}" : "{:02x}", (int)getRawErrBuff()[i]); + } + rbuf += '>'; + return rbuf; + } + return {}; +} diff --git a/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx b/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx index 3641991899487..9b684d2c7c0d2 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,6 +37,7 @@ void RUDecodeData::clear() } nCables = 0; nChipsFired = 0; + calibData.clear(); } ///_________________________________________________________________ @@ -52,7 +54,8 @@ void RUDecodeData::setROFInfo(ChipPixelData* chipData, const GBTLink* lnk) void RUDecodeData::fillChipStatistics(int icab, const ChipPixelData* chipData) { cableLinkPtr[icab]->chipStat.nHits += chipData->getData().size(); - cableLinkPtr[icab]->chipStat.addErrors(chipData->getErrorFlags()); + //cableLinkPtr[icab]->chipStat.addErrors(chipData->getErrorFlags(), chipData->getChipID(), verbosity); + cableLinkPtr[icab]->chipStat.addErrors(*chipData, verbosity); } } // namespace itsmft diff --git a/Detectors/ITSMFT/common/reconstruction/src/RUInfo.cxx b/Detectors/ITSMFT/common/reconstruction/src/RUInfo.cxx index 3e6e6bbb2ea12..7a5df3d766084 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RUInfo.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RUInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,24 +13,27 @@ // \brief Transient structures for ITS and MFT HW -> SW mapping #include "ITSMFTReconstruction/RUInfo.h" -#include <bitset> +#include "Framework/Logger.h" using namespace o2::itsmft; +std::string ChipOnRUInfo::asString() const +{ + return fmt::format("ChonRu:{:3d} ModSW:{:2d} ChOnModSW:{:2d} CabSW:{:3d}| ChOnCab:{:1d} | CabHW:{:2d} | CabPos:{:2d} | ModHW:{:2d} | ChOnModHW:{:2d}", + int(id), int(moduleSW), int(chipOnModuleSW), int(cableSW), int(chipOnCable), int(cableHW), int(cableHWPos), int(moduleHW), int(chipOnModuleHW)); +} + void ChipOnRUInfo::print() const { - std::bitset<8> chw(cableHW), mhw(moduleHW); - printf("ChonRu:%3d ModSW:%2d ChOnModSW:%2d CabSW:%3d| ChOnCab:%d | CabHW: %8s (%2d) | ModHW: %8s | ChOnModHW: %2d\n", - id, moduleSW, chipOnModuleSW, cableSW, chipOnCable, chw.to_string().c_str(), cableHWPos, - mhw.to_string().c_str(), chipOnModuleHW); + LOG(INFO) << asString(); +} + +std::string ChipInfo::asString() const +{ + return fmt::format("CH{:5d} RUTyp:{:d} RU:{:3d} | {}", int(id), int(ruType), int(ru), chOnRU ? chOnRU->asString() : std::string{}); } void ChipInfo::print() const { - printf("CH%5d RUTyp:%d RU:%3d | ", id, ruType, ru); - if (chOnRU) { - chOnRU->print(); - } else { - printf("\n"); - } + LOGP(INFO, asString()); } diff --git a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx index 24710c25b7209..d0870f7f6b2c1 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "ITSMFTReconstruction/RawPixelDecoder.h" #include "DPLUtils/DPLRawParser.h" +#include "Framework/InputRecordWalker.h" #include "CommonUtils/StringUtils.h" #ifdef WITH_OPENMP @@ -33,13 +35,13 @@ RawPixelDecoder<Mapping>::RawPixelDecoder() mTimerTFStart.Stop(); mTimerDecode.Stop(); mTimerFetchData.Stop(); - mSelfName = o2::utils::concat_string(Mapping::getName(), "Decoder"); + mSelfName = o2::utils::Str::concat_string(Mapping::getName(), "Decoder"); } ///______________________________________________________________ /// template <class Mapping> -void RawPixelDecoder<Mapping>::printReport(bool decstat, bool skipEmpty) const +void RawPixelDecoder<Mapping>::printReport(bool decstat, bool skipNoErr) const { LOGF(INFO, "%s Decoded %zu hits in %zu non-empty chips in %u ROFs with %d threads", mSelfName, mNPixelsFired, mNChipsFired, mROFCounter, mNThreads); double cpu = 0, real = 0; @@ -59,11 +61,10 @@ void RawPixelDecoder<Mapping>::printReport(bool decstat, bool skipEmpty) const mDecodeNextAuto ? "AutoDecode" : "ExternalCall"); if (decstat) { - LOG(INFO) << "GBT Links decoding statistics"; + LOG(INFO) << "GBT Links decoding statistics" << (skipNoErr ? " (only links with errors are reported)" : ""); for (auto& lnk : mGBTLinks) { - LOG(INFO) << lnk.describe(); - lnk.statistics.print(skipEmpty); - lnk.chipStat.print(skipEmpty); + lnk.statistics.print(skipNoErr); + lnk.chipStat.print(skipNoErr); } } } @@ -113,8 +114,9 @@ int RawPixelDecoder<Mapping>::decodeNextTrigger() } } while (mNLinksDone < mGBTLinks.size()); + + ensureChipOrdering(); mTimerDecode.Stop(); - // LOG(INFO) << "Chips Fired: " << mNChipsFiredROF << " NPixels: " << mNPixelsFiredROF << " at IR " << mInteractionRecord << " of HBF " << mInteractionRecordHB; return nLinksWithData; } @@ -171,6 +173,21 @@ void RawPixelDecoder<Mapping>::setupLinks(InputRecord& inputs) auto origin = (mUserDataOrigin == o2::header::gDataOriginInvalid) ? mMAP.getOrigin() : mUserDataOrigin; auto datadesc = (mUserDataDescription == o2::header::gDataDescriptionInvalid) ? o2::header::gDataDescriptionRawData : mUserDataDescription; std::vector<InputSpec> filter{InputSpec{"filter", ConcreteDataTypeMatcher{origin, datadesc}, Lifetime::Timeframe}}; + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{origin, datadesc, 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return; + } + } + } + DPLRawParser parser(inputs, filter); uint32_t currSSpec = 0xffffffff; // dummy starting subspec int linksAdded = 0; @@ -238,6 +255,7 @@ RUDecodeData& RawPixelDecoder<Mapping>::getCreateRUDecode(int ruSW) ru.ruSWID = ruSW; ru.ruInfo = mMAP.getRUInfoSW(ruSW); // info on the stave/RU ru.chipsData.resize(mMAP.getNChipsOnRUType(ru.ruInfo->ruType)); + ru.verbosity = mVerbosity; LOG(INFO) << mSelfName << " Defining container for RU " << ruSW << " at slot " << mRUEntry[ruSW]; } return mRUDecodeVec[mRUEntry[ruSW]]; @@ -287,6 +305,62 @@ bool RawPixelDecoder<Mapping>::getNextChipData(ChipPixelData& chipData) return getNextChipData(chipData); // is it ok to use recursion here? } +///______________________________________________________________________ +template <> +void RawPixelDecoder<ChipMappingMFT>::ensureChipOrdering() +{ + mOrderedChipsPtr.clear(); + // define looping order, if mCurRUDecodeID < mRUDecodeVec.size(), this means that decodeNextTrigger() was called before + if (mCurRUDecodeID < mRUDecodeVec.size()) { // define sort order + for (; mCurRUDecodeID < mRUDecodeVec.size(); mCurRUDecodeID++) { + auto& ru = mRUDecodeVec[mCurRUDecodeID]; + while (ru.lastChipChecked < ru.nChipsFired) { + mOrderedChipsPtr.push_back(&ru.chipsData[ru.lastChipChecked++]); + } + } + // sort in decreasing order + std::sort(mOrderedChipsPtr.begin(), mOrderedChipsPtr.end(), [](const ChipPixelData* a, const ChipPixelData* b) { return a->getChipID() > b->getChipID(); }); + } +} + +///______________________________________________________________________ +template <> +ChipPixelData* RawPixelDecoder<ChipMappingMFT>::getNextChipData(std::vector<ChipPixelData>& chipDataVec) +{ + if (!mOrderedChipsPtr.empty()) { + auto chipData = *mOrderedChipsPtr.back(); + assert(mLastReadChipID < chipData.getChipID()); + mLastReadChipID = chipData.getChipID(); + chipDataVec[mLastReadChipID].swap(chipData); + mOrderedChipsPtr.pop_back(); + return &chipDataVec[mLastReadChipID]; + } + // will need to decode new trigger + if (!mDecodeNextAuto || !decodeNextTrigger()) { // no more data to decode + return nullptr; + } + return getNextChipData(chipDataVec); +} + +///______________________________________________________________________ +template <> +bool RawPixelDecoder<ChipMappingMFT>::getNextChipData(ChipPixelData& chipData) +{ + if (!mOrderedChipsPtr.empty()) { + auto ruChip = *mOrderedChipsPtr.back(); + assert(mLastReadChipID < ruChip.getChipID()); + mLastReadChipID = ruChip.getChipID(); + ruChip.swap(chipData); + mOrderedChipsPtr.pop_back(); + return true; + } + // will need to decode new trigger + if (!mDecodeNextAuto || !decodeNextTrigger()) { // no more data to decode + return false; + } + return getNextChipData(chipData); // is it ok to use recursion here? +} + ///______________________________________________________________________ template <class Mapping> void RawPixelDecoder<Mapping>::setVerbosity(int v) diff --git a/Detectors/ITSMFT/common/reconstruction/src/TopologyFastSimulation.cxx b/Detectors/ITSMFT/common/reconstruction/src/TopologyFastSimulation.cxx index cf27dea465f4f..35e3967b923d8 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/TopologyFastSimulation.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/TopologyFastSimulation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/CMakeLists.txt b/Detectors/ITSMFT/common/simulation/CMakeLists.txt index d5f828a460399..3ce3d8b9ab0d6 100644 --- a/Detectors/ITSMFT/common/simulation/CMakeLists.txt +++ b/Detectors/ITSMFT/common/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSMFTSimulation SOURCES src/Hit.cxx diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideChip.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideChip.h index 190ecba04cded..71d3079204f74 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideChip.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideChip.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSignalTrapezoid.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSignalTrapezoid.h index 404a3fd336541..d95ac5c39b5da 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSignalTrapezoid.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSignalTrapezoid.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSimResponse.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSimResponse.h index 0f82c7a7fffd2..0fd27712e03bf 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSimResponse.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/AlpideSimResponse.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,8 @@ #include <vector> #include <Rtypes.h> +#include "ITSMFTBase/SegmentationAlpide.h" + namespace o2 { namespace itsmft @@ -93,8 +96,8 @@ class AlpideSimResponse int mNBinDpt = 0; /// number of bins in Z(sensor dept) int mMaxBinCol = 0; /// max allowed Xb (to avoid subtraction) int mMaxBinRow = 0; /// max allowed Yb (to avoid subtraction) - float mColMax = 14.62e-4; /// upper boundary of Col - float mRowMax = 13.44e-4; /// upper boundary of Row + float mColMax = SegmentationAlpide::PitchCol / 2.f; /// upper boundary of Col + float mRowMax = SegmentationAlpide::PitchRow / 2.f; /// upper boundary of Row float mDptMin = 0.f; /// lower boundary of Dpt float mDptMax = 0.f; /// upper boundary of Dpt float mDptShift = 0.f; /// shift of the depth center wrt 0 @@ -116,6 +119,7 @@ class AlpideSimResponse bool getResponse(float vRow, float vCol, float cDepth, AlpideRespSimMat& dest) const; const AlpideRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol) const; + const AlpideRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const; static int constexpr getNPix() { return AlpideRespSimMat::getNPix(); } int getNBinCol() const { return mNBinCol; } int getNBinRow() const { return mNBinRow; } @@ -138,7 +142,7 @@ class AlpideSimResponse const std::string& getColRowDataFmt() const { return mColRowDataFmt; } void print() const; - ClassDef(AlpideSimResponse, 1); + ClassDefNV(AlpideSimResponse, 1); }; //----------------------------------------------------- diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ChipDigitsContainer.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ChipDigitsContainer.h index f73dd1f5327c5..0d00d187e8ea2 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ChipDigitsContainer.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ChipDigitsContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #define ALICEO2_ITSMFT_CHIPDIGITSCONTAINER_ #include "SimulationDataFormat/MCCompLabel.h" +#include "ITSMFTBase/SegmentationAlpide.h" #include "ITSMFTSimulation/PreDigit.h" #include <map> #include <vector> @@ -47,7 +49,7 @@ class ChipDigitsContainer o2::itsmft::PreDigit* findDigit(ULong64_t key); void addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, int charge, o2::MCCompLabel lbl); - void addNoise(UInt_t rofMin, UInt_t rofMax, const o2::itsmft::DigiParams* params); + void addNoise(UInt_t rofMin, UInt_t rofMax, const o2::itsmft::DigiParams* params, int maxRows = o2::itsmft::SegmentationAlpide::NRows, int maxCols = o2::itsmft::SegmentationAlpide::NCols); /// Get global ordering key made of readout frame, column and row static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col) diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ClusterShape.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ClusterShape.h index 3d6b85a459fcc..1d81e09979292 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ClusterShape.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/ClusterShape.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DPLDigitizerParam.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DPLDigitizerParam.h index 46a514a93eb21..cba38a0e27d3e 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DPLDigitizerParam.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DPLDigitizerParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DigiParams.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DigiParams.h index 96d805e5907f2..fe4bb2b8519b3 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DigiParams.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/DigiParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h index dca57e4e353ad..590f78c91f755 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #include <deque> #include <memory> -#include "Rtypes.h" // for Digitizer::Class, Double_t, ClassDef, etc +#include "Rtypes.h" // for Digitizer::Class #include "TObject.h" // for TObject #include "ITSMFTSimulation/ChipDigitsContainer.h" @@ -71,7 +72,7 @@ class Digitizer : public TObject void setContinuous(bool v) { mParams.setContinuous(v); } bool isContinuous() const { return mParams.isContinuous(); } - void fillOutputContainer(UInt_t maxFrame = 0xffffffff); + void fillOutputContainer(uint32_t maxFrame = 0xffffffff); void setDigiParams(const o2::itsmft::DigiParams& par) { mParams = par; } const o2::itsmft::DigiParams& getDigitParams() const { return mParams; } @@ -79,8 +80,8 @@ class Digitizer : public TObject // provide the common itsmft::GeometryTGeo to access matrices and segmentation void setGeometry(const o2::itsmft::GeometryTGeo* gm) { mGeometry = gm; } - UInt_t getEventROFrameMin() const { return mEventROFrameMin; } - UInt_t getEventROFrameMax() const { return mEventROFrameMax; } + uint32_t getEventROFrameMin() const { return mEventROFrameMin; } + uint32_t getEventROFrameMax() const { return mEventROFrameMax; } void resetEventROFrames() { mEventROFrameMin = 0xffffffff; @@ -88,11 +89,11 @@ class Digitizer : public TObject } private: - void processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, int srcID); - void registerDigits(ChipDigitsContainer& chip, UInt_t roFrame, float tInROF, int nROF, - UShort_t row, UShort_t col, int nEle, o2::MCCompLabel& lbl); + void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID); + void registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl); - ExtraDig* getExtraDigBuffer(UInt_t roFrame) + ExtraDig* getExtraDigBuffer(uint32_t roFrame) { if (mROFrameMin > roFrame) { return nullptr; // nothing to do @@ -108,13 +109,14 @@ class Digitizer : public TObject o2::itsmft::DigiParams mParams; ///< digitization parameters o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record + o2::InteractionRecord mIRFirstSampledTF; ///< IR of the 1st sampled IR, noise-only ROFs will be inserted till this IR only double mCollisionTimeWrtROF; - UInt_t mROFrameMin = 0; ///< lowest RO frame of current digits - UInt_t mROFrameMax = 0; ///< highest RO frame of current digits - UInt_t mNewROFrame = 0; ///< ROFrame corresponding to provided time + uint32_t mROFrameMin = 0; ///< lowest RO frame of current digits + uint32_t mROFrameMax = 0; ///< highest RO frame of current digits + uint32_t mNewROFrame = 0; ///< ROFrame corresponding to provided time - UInt_t mEventROFrameMin = 0xffffffff; ///< lowest RO frame for processed events (w/o automatic noise ROFs) - UInt_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) + uint32_t mEventROFrameMin = 0xffffffff; ///< lowest RO frame for processed events (w/o automatic noise ROFs) + uint32_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) std::unique_ptr<o2::itsmft::AlpideSimResponse> mAlpSimResp; // simulated response diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Hit.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Hit.h index 5ee373f84a9c1..012849d131aa4 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Hit.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/MC2RawEncoder.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/MC2RawEncoder.h index d91b677989c79..b702ba89018e5 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/MC2RawEncoder.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/MC2RawEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/PreDigit.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/PreDigit.h index 22df78910a44e..aac9078ecf060 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/PreDigit.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/PreDigit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/AlpideChip.cxx b/Detectors/ITSMFT/common/simulation/src/AlpideChip.cxx index 6b643b7d0a01f..d35d907e988bf 100644 --- a/Detectors/ITSMFT/common/simulation/src/AlpideChip.cxx +++ b/Detectors/ITSMFT/common/simulation/src/AlpideChip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/AlpideSignalTrapezoid.cxx b/Detectors/ITSMFT/common/simulation/src/AlpideSignalTrapezoid.cxx index 139f2fbf13b0b..882a815fcebc0 100644 --- a/Detectors/ITSMFT/common/simulation/src/AlpideSignalTrapezoid.cxx +++ b/Detectors/ITSMFT/common/simulation/src/AlpideSignalTrapezoid.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/AlpideSimResponse.cxx b/Detectors/ITSMFT/common/simulation/src/AlpideSimResponse.cxx index 4557bc97b1ebf..bef083b11c6ac 100644 --- a/Detectors/ITSMFT/common/simulation/src/AlpideSimResponse.cxx +++ b/Detectors/ITSMFT/common/simulation/src/AlpideSimResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -244,6 +245,12 @@ bool AlpideSimResponse::getResponse(float vRow, float vCol, float vDepth, Alpide //____________________________________________________________ const AlpideRespSimMat* AlpideSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol) const +{ + return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMax, mColMax); +} + +//____________________________________________________________ +const AlpideRespSimMat* AlpideSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const { /* * get linearized NPix*NPix matrix for response at point vRow(sensor local X, along row) @@ -261,7 +268,7 @@ const AlpideRespSimMat* AlpideSimResponse::getResponse(float vRow, float vCol, f } else { flipCol = false; } - if (vCol > mColMax) { + if (vCol > colMax) { return nullptr; } if (vRow < 0) { @@ -270,7 +277,7 @@ const AlpideRespSimMat* AlpideSimResponse::getResponse(float vRow, float vCol, f } else { flipRow = true; } - if (vRow > mRowMax) { + if (vRow > rowMax) { return nullptr; } diff --git a/Detectors/ITSMFT/common/simulation/src/ChipDigitsContainer.cxx b/Detectors/ITSMFT/common/simulation/src/ChipDigitsContainer.cxx index df7bbaf2d563c..026b67a00ec99 100644 --- a/Detectors/ITSMFT/common/simulation/src/ChipDigitsContainer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/ChipDigitsContainer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,6 @@ #include "ITSMFTSimulation/ChipDigitsContainer.h" #include "ITSMFTSimulation/DigiParams.h" -#include "ITSMFTBase/SegmentationAlpide.h" #include <TRandom.h> using namespace o2::itsmft; @@ -24,7 +24,7 @@ using Segmentation = o2::itsmft::SegmentationAlpide; ClassImp(o2::itsmft::ChipDigitsContainer); //______________________________________________________________________ -void ChipDigitsContainer::addNoise(UInt_t rofMin, UInt_t rofMax, const o2::itsmft::DigiParams* params) +void ChipDigitsContainer::addNoise(UInt_t rofMin, UInt_t rofMax, const o2::itsmft::DigiParams* params, int maxRows, int maxCols) { UInt_t row = 0; UInt_t col = 0; @@ -37,8 +37,8 @@ void ChipDigitsContainer::addNoise(UInt_t rofMin, UInt_t rofMax, const o2::itsmf for (UInt_t rof = rofMin; rof <= rofMax; rof++) { nhits = gRandom->Poisson(mean); for (Int_t i = 0; i < nhits; ++i) { - row = gRandom->Integer(Segmentation::NRows); - col = gRandom->Integer(Segmentation::NCols); + row = gRandom->Integer(maxRows); + col = gRandom->Integer(maxCols); // RS TODO: why the noise was added with 0 charge? It should be above the threshold! auto key = getOrderingKey(rof, row, col); if (!findDigit(key)) { diff --git a/Detectors/ITSMFT/common/simulation/src/ClusterShape.cxx b/Detectors/ITSMFT/common/simulation/src/ClusterShape.cxx index 0a0b2f0cdde37..b633691e529e5 100644 --- a/Detectors/ITSMFT/common/simulation/src/ClusterShape.cxx +++ b/Detectors/ITSMFT/common/simulation/src/ClusterShape.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/DPLDigitizerParam.cxx b/Detectors/ITSMFT/common/simulation/src/DPLDigitizerParam.cxx index 15b3175f605b9..99eb30edc0369 100644 --- a/Detectors/ITSMFT/common/simulation/src/DPLDigitizerParam.cxx +++ b/Detectors/ITSMFT/common/simulation/src/DPLDigitizerParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx index 86023fff83424..a6d958e8a3635 100644 --- a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx +++ b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx index d18d55d1476b7..b249eedd1b959 100644 --- a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "ITSMFTSimulation/Digitizer.h" #include "MathUtils/Cartesian.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsRaw/HBFUtils.h" #include <TRandom.h> #include <climits> @@ -44,6 +46,7 @@ void Digitizer::init() mParams.setAlpSimResponse(mAlpSimResp.get()); } mParams.print(); + mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); } //_______________________________________________________________________ @@ -92,7 +95,7 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) // RO frame corresponding to provided time mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?) if (mParams.isContinuous()) { - auto nbc = mEventTime.toLong(); + auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF); if (mCollisionTimeWrtROF < 0 && nbc > 0) { nbc--; } @@ -114,7 +117,7 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) } //_______________________________________________________________________ -void Digitizer::fillOutputContainer(UInt_t frameLast) +void Digitizer::fillOutputContainer(uint32_t frameLast) { // fill output with digits from min.cached up to requested frame, generating the noise beforehand if (frameLast > mROFrameMax) { @@ -164,7 +167,7 @@ void Digitizer::fillOutputContainer(UInt_t frameLast) // finalize ROF record rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits if (isContinuous()) { - rcROF.getBCData().setFromLong(mROFrameMin * mParams.getROFrameLengthInBC()); + rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); } else { rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? } @@ -179,7 +182,7 @@ void Digitizer::fillOutputContainer(UInt_t frameLast) } //_______________________________________________________________________ -void Digitizer::processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, int srcID) +void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) { // convert single hit to digits float timeInROF = hit.GetTime() * sec2ns; @@ -203,9 +206,9 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, // frame of the hit signal start wrt event ROFrame int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame - UInt_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; + uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; int nFrames = roFrameRelMax + 1 - roFrameRel; - UInt_t roFrameMax = mNewROFrame + roFrameRelMax; + uint32_t roFrameMax = mNewROFrame + roFrameRelMax; if (roFrameMax > maxFr) { maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter } @@ -325,7 +328,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, auto& chip = mChips[hit.GetDetectorID()]; auto roFrameAbs = mNewROFrame + roFrameRel; for (int irow = rowSpan; irow--;) { - UShort_t rowIS = irow + rowS; + uint16_t rowIS = irow + rowS; for (int icol = colSpan; icol--;) { float nEleResp = respMatrix[irow][icol]; if (!nEleResp) { @@ -336,7 +339,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, if (nEle < mParams.getMinChargeToAccount()) { continue; } - UShort_t colIS = icol + colS; + uint16_t colIS = icol + colS; // registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); } @@ -344,8 +347,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, UInt_t& maxFr, int evID, } //________________________________________________________________________________ -void Digitizer::registerDigits(ChipDigitsContainer& chip, UInt_t roFrame, float tInROF, int nROF, - UShort_t row, UShort_t col, int nEle, o2::MCCompLabel& lbl) +void Digitizer::registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl) { // Register digits for given pixel, accounting for the possible signal contribution to // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame @@ -353,7 +356,7 @@ void Digitizer::registerDigits(ChipDigitsContainer& chip, UInt_t roFrame, float float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start for (int i = 0; i < nROF; i++) { - UInt_t roFr = roFrame + i; + uint32_t roFr = roFrame + i; int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); tStrobe += mParams.getROFrameLength(); // for the next ROF diff --git a/Detectors/ITSMFT/common/simulation/src/Hit.cxx b/Detectors/ITSMFT/common/simulation/src/Hit.cxx index 8c9501b5e1219..ddfe1a05f741a 100644 --- a/Detectors/ITSMFT/common/simulation/src/Hit.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/ITSMFTSimulationLinkDef.h b/Detectors/ITSMFT/common/simulation/src/ITSMFTSimulationLinkDef.h index cf5c0ddffcd0b..ead8ba6e6b1ff 100644 --- a/Detectors/ITSMFT/common/simulation/src/ITSMFTSimulationLinkDef.h +++ b/Detectors/ITSMFT/common/simulation/src/ITSMFTSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/simulation/src/MC2RawEncoder.cxx b/Detectors/ITSMFT/common/simulation/src/MC2RawEncoder.cxx index adee01a9a9c34..59377c4e55296 100644 --- a/Detectors/ITSMFT/common/simulation/src/MC2RawEncoder.cxx +++ b/Detectors/ITSMFT/common/simulation/src/MC2RawEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -180,8 +181,8 @@ void MC2RawEncoder<Mapping>::fillGBTLinks(RUDecodeData& ru) // estimate real payload size in GBT words int nPayLoadWordsNeeded = 0; // number of payload words filled to link buffer (RDH not included) for current IR for (int icab = ru.nCables; icab--;) { // calculate number of GBT words per link - if ((link->lanes & (0x1 << icab))) { - int nb = ru.cableData[icab].getSize(); + if ((link->lanes & (0x1 << mMAP.cablePos(ru.ruInfo->ruType, icab)))) { + int nb = ru.cableData[mMAP.cablePos(ru.ruInfo->ruType, icab)].getSize(); nPayLoadWordsNeeded += nb ? 1 + (nb - 1) / 9 : 0; // single GBT word carries at most 9 payload bytes } } @@ -195,8 +196,8 @@ void MC2RawEncoder<Mapping>::fillGBTLinks(RUDecodeData& ru) while (hasData) { hasData = false; for (int icab = 0; icab < ru.nCables; icab++) { - if ((link->lanes & (0x1 << icab))) { - auto& cableData = ru.cableData[icab]; + if ((link->lanes & (0x1 << mMAP.cablePos(ru.ruInfo->ruType, icab)))) { + auto& cableData = ru.cableData[mMAP.cablePos(ru.ruInfo->ruType, icab)]; int nb = cableData.getUnusedSize(); if (!nb) { continue; // write 80b word only if there is something to write @@ -204,10 +205,10 @@ void MC2RawEncoder<Mapping>::fillGBTLinks(RUDecodeData& ru) if (nb > 9) { nb = 9; } - int gbtWordStart = link->data.getSize(); // beginning of the current GBT word in the link - link->data.addFast(cableData.getPtr(), nb); // fill payload of cable - link->data.addFast(zero16, GBTPaddedWordLength - nb); // fill the rest of the GBT word by 0 - link->data[gbtWordStart + 9] = mMAP.getGBTHeaderRUType(ru.ruInfo->ruType, ru.cableHWID[icab]); // set cable flag + int gbtWordStart = link->data.getSize(); // beginning of the current GBT word in the link + link->data.addFast(cableData.getPtr(), nb); // fill payload of cable + link->data.addFast(zero16, GBTPaddedWordLength - nb); // fill the rest of the GBT word by 0 + link->data[gbtWordStart + 9] = mMAP.getGBTHeaderRUType(ru.ruInfo->ruType, ru.cableHWID[mMAP.cablePos(ru.ruInfo->ruType, icab)]); // set cable flag cableData.setPtr(cableData.getPtr() + nb); hasData = true; } // storing data of single cable diff --git a/Detectors/ITSMFT/common/simulation/test/testAlpideSimResponse.cxx b/Detectors/ITSMFT/common/simulation/test/testAlpideSimResponse.cxx index c74983807c234..14b7ccedaae37 100644 --- a/Detectors/ITSMFT/common/simulation/test/testAlpideSimResponse.cxx +++ b/Detectors/ITSMFT/common/simulation/test/testAlpideSimResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/workflow/CMakeLists.txt b/Detectors/ITSMFT/common/workflow/CMakeLists.txt index 5f603926bf979..1c2d2ed27919d 100644 --- a/Detectors/ITSMFT/common/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/common/workflow/CMakeLists.txt @@ -1,16 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITSMFTWorkflow SOURCES src/ClusterReaderSpec.cxx src/DigitWriterSpec.cxx + src/DigitReaderSpec.cxx src/STFDecoderSpec.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx @@ -38,3 +40,8 @@ o2_add_executable(digit-writer-workflow SOURCES src/digit-writer-workflow.cxx COMPONENT_NAME itsmft PUBLIC_LINK_LIBRARIES O2::ITSMFTWorkflow) + +o2_add_executable(digit-reader-workflow + SOURCES src/digit-reader-workflow.cxx + COMPONENT_NAME itsmft + PUBLIC_LINK_LIBRARIES O2::ITSMFTWorkflow) diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h index 1003b8f677f3e..fe6dfd6c75cc7 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h new file mode 100644 index 0000000000000..ac9d02ff693f4 --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h + +#ifndef O2_ITSMFT_DIGITREADER +#define O2_ITSMFT_DIGITREADER + +#include "TFile.h" +#include "TTree.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/GBTCalibData.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace itsmft +{ + +class DigitReader : public Task +{ + public: + DigitReader() = delete; + DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib); + ~DigitReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector<o2::itsmft::Digit> mDigits, *mDigitsPtr = &mDigits; + std::vector<o2::itsmft::GBTCalibData> mCalib, *mCalibPtr = &mCalib; + std::vector<o2::itsmft::ROFRecord> mDigROFRec, *mDigROFRecPtr = &mDigROFRec; + std::vector<o2::itsmft::MC2ROFRecord> mDigMC2ROFs, *mDigMC2ROFsPtr = &mDigMC2ROFs; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + bool mUseCalib = true; // send calib data + + std::string mDetName = ""; + std::string mDetNameLC = ""; + std::string mFileName = ""; + std::string mDigTreeName = "o2sim"; + std::string mDigitBranchName = "Digit"; + std::string mDigROFBranchName = "DigitROF"; + std::string mCalibBranchName = "Calib"; + + std::string mDigtMCTruthBranchName = "DigitMCTruth"; + std::string mDigtMC2ROFBranchName = "DigitMC2ROF"; +}; + +class ITSDigitReader : public DigitReader +{ + public: + ITSDigitReader(bool useMC = true, bool useCalib = false) + : DigitReader(o2::detectors::DetID::ITS, useMC, useCalib) + { + mOrigin = o2::header::gDataOriginITS; + } +}; + +class MFTDigitReader : public DigitReader +{ + public: + MFTDigitReader(bool useMC = true, bool useCalib = false) + : DigitReader(o2::detectors::DetID::MFT, useMC, useCalib) + { + mOrigin = o2::header::gDataOriginMFT; + } +}; + +/// create a processor spec +/// read ITS/MFT Digit data from a root file +framework::DataProcessorSpec getITSDigitReaderSpec(bool useMC = true, bool useCalib = false, std::string defname = "o2_itsdigits.root"); +framework::DataProcessorSpec getMFTDigitReaderSpec(bool useMC = true, bool useCalib = false, std::string defname = "o2_mftdigits.root"); + +} // namespace itsmft +} // namespace o2 + +#endif /* O2_ITSMFT_DigitREADER */ diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitWriterSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitWriterSpec.h index 338b45d3b6f47..7bef1643ddcbb 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitWriterSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,8 +19,8 @@ namespace o2 namespace itsmft { -o2::framework::DataProcessorSpec getITSDigitWriterSpec(bool mctruth = true); -o2::framework::DataProcessorSpec getMFTDigitWriterSpec(bool mctruth = true); +o2::framework::DataProcessorSpec getITSDigitWriterSpec(bool mctruth = true, bool dec = false, bool calib = false); +o2::framework::DataProcessorSpec getMFTDigitWriterSpec(bool mctruth = true, bool dec = false, bool calib = false); } // end namespace itsmft } // end namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h index f624eb1781b1f..3c481a9514355 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,10 @@ #include "Framework/Task.h" #include "Headers/DataHeader.h" #include "ITSMFTReconstruction/CTFCoder.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "ITSMFTReconstruction/LookUp.h" #include <TStopwatch.h> +#include <memory> namespace o2 { @@ -28,20 +32,33 @@ namespace itsmft class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(o2::header::DataOrigin orig); + EntropyDecoderSpec(o2::header::DataOrigin orig, bool getDigits = false); ~EntropyDecoderSpec() override = default; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; void endOfStream(o2::framework::EndOfStreamContext& ec) final; + static auto getName(o2::header::DataOrigin orig) { return std::string{orig == o2::header::gDataOriginITS ? ITSDeviceName : MFTDeviceName}; } + private: + void updateTimeDependentParams(o2::framework::ProcessingContext& pc); + + static constexpr std::string_view ITSDeviceName = "its-entropy-decoder"; + static constexpr std::string_view MFTDeviceName = "mft-entropy-decoder"; o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; o2::itsmft::CTFCoder mCTFCoder; + std::unique_ptr<NoiseMap> mNoiseMap; + LookUp mPattIdConverter; + bool mGetDigits{false}; + bool mMaskNoise{false}; + std::string mCTFDictPath{}; + std::string mClusDictPath{}; + std::string mNoiseFilePath{}; TStopwatch mTimer; }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig); +framework::DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, bool getDigits = false); } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h index 997f0f5eb192b..8ed8276dc2f07 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h index 66567aa47a32c..1c700125574ca 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,11 +34,25 @@ namespace itsmft { class Clusterer; +struct STFDecoderInp { + bool doClusters = true; + bool doPatterns = true; + bool doDigits = false; + bool doCalib = false; + bool askSTFDist = true; + o2::header::DataOrigin origin{"NIL"}; + std::string deviceName{}; + std::string dict{}; + std::string noise{}; + std::string inputSpec{}; +}; + template <class Mapping> class STFDecoder : public Task { public: - STFDecoder(bool clusters = true, bool pattern = true, bool digits = false, std::string_view dict = "", std::string_view noise = ""); + STFDecoder(const STFDecoderInp& inp); + STFDecoder() = default; ~STFDecoder() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -49,8 +64,16 @@ class STFDecoder : public Task bool mDoClusters = false; bool mDoPatterns = false; bool mDoDigits = false; + bool mDoCalibData = false; + bool mUnmutExtraLanes = false; int mNThreads = 1; + int mVerbosity = 0; size_t mTFCounter = 0; + size_t mEstNDig = 0; + size_t mEstNClus = 0; + size_t mEstNClusPatt = 0; + size_t mEstNCalib = 0; + size_t mEstNROF = 0; std::string mSelfName; std::string mDictName; std::string mNoiseName; @@ -61,9 +84,7 @@ class STFDecoder : public Task using STFDecoderITS = STFDecoder<ChipMappingITS>; using STFDecoderMFT = STFDecoder<ChipMappingMFT>; -/// create a processor spec -o2::framework::DataProcessorSpec getSTFDecoderITSSpec(bool doClusters, bool doPatterns, bool doDigits, const std::string& dict, const std::string& noise); -o2::framework::DataProcessorSpec getSTFDecoderMFTSpec(bool doClusters, bool doPatterns, bool doDigits, const std::string& dict, const std::string& noise); +o2::framework::DataProcessorSpec getSTFDecoderSpec(const STFDecoderInp& inp); } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx index 5047a52807531..e6f93fee4e6bc 100644 --- a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "Framework/Logger.h" #include "ITSMFTWorkflow/ClusterReaderSpec.h" #include <cassert> +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; using namespace o2::itsmft; @@ -39,7 +41,8 @@ ClusterReader::ClusterReader(o2::detectors::DetID id, bool useMC, bool usePatter void ClusterReader::init(InitContext& ic) { - mFileName = ic.options().get<std::string>((mDetNameLC + "-cluster-infile").c_str()); + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>((mDetNameLC + "-cluster-infile").c_str())); connectTree(mFileName); } @@ -114,7 +117,8 @@ DataProcessorSpec getITSClusterReaderSpec(bool useMC, bool usePatterns) outputSpec, AlgorithmSpec{adaptFromTask<ITSClusterReader>(useMC, usePatterns)}, Options{ - {"its-cluster-infile", VariantType::String, "o2clus_its.root", {"Name of the input cluster file"}}}}; + {"its-cluster-infile", VariantType::String, "o2clus_its.root", {"Name of the input cluster file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } DataProcessorSpec getMFTClusterReaderSpec(bool useMC, bool usePatterns) @@ -136,7 +140,8 @@ DataProcessorSpec getMFTClusterReaderSpec(bool useMC, bool usePatterns) outputSpec, AlgorithmSpec{adaptFromTask<MFTClusterReader>(useMC, usePatterns)}, Options{ - {"mft-cluster-infile", VariantType::String, "o2clus_mft.root", {"Name of the input cluster file"}}}}; + {"mft-cluster-infile", VariantType::String, "mftclusters.root", {"Name of the input cluster file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..6fca828591263 --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,167 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include <vector> + +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "ITSMFTWorkflow/DigitReaderSpec.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <cassert> + +using namespace o2::framework; +using namespace o2::itsmft; + +namespace o2 +{ +namespace itsmft +{ + +DigitReader::DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib) +{ + assert(id == o2::detectors::DetID::ITS || id == o2::detectors::DetID::MFT); + mDetNameLC = mDetName = id.getName(); + mDigTreeName = "o2sim"; + + mDigitBranchName = mDetName + mDigitBranchName; + mDigROFBranchName = mDetName + mDigROFBranchName; + mCalibBranchName = mDetName + mCalibBranchName; + + mDigtMCTruthBranchName = mDetName + mDigtMCTruthBranchName; + mDigtMC2ROFBranchName = mDetName + mDigtMC2ROFBranchName; + + mUseMC = useMC; + mUseCalib = useCalib; + std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); +} + +void DigitReader::init(InitContext& ic) +{ + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>((mDetNameLC + "-digit-infile").c_str())); + connectTree(mFileName); +} + +void DigitReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + + o2::dataformats::IOMCTruthContainerView* plabels = nullptr; + if (mUseMC) { + mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); + } + mTree->GetEntry(ent); + LOG(INFO) << mDetName << "DigitReader pushes " << mDigROFRec.size() << " ROFRecords, " + << mDigits.size() << " digits at entry " << ent; + + // This is a very ugly way of providing DataDescription, which anyway does not need to contain detector name. + // To be fixed once the names-definition class is ready + pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0, Lifetime::Timeframe}, mDigROFRec); + pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0, Lifetime::Timeframe}, mDigits); + if (mUseCalib) { + pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0, Lifetime::Timeframe}, mCalib); + } + + if (mUseMC) { + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", 0, Lifetime::Timeframe}); + plabels->copyandflatten(sharedlabels); + delete plabels; + pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0, Lifetime::Timeframe}, mDigMC2ROFs); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void DigitReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str())); + assert(mTree); + + mTree->SetBranchAddress(mDigROFBranchName.c_str(), &mDigROFRecPtr); + mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsPtr); + if (mUseCalib) { + if (!mTree->GetBranch(mCalibBranchName.c_str())) { + throw std::runtime_error("GBT calibration data requested but not found in the tree"); + } + mTree->SetBranchAddress(mCalibBranchName.c_str(), &mCalibPtr); + } + if (mUseMC) { + if (!mTree->GetBranch(mDigtMC2ROFBranchName.c_str()) || !mTree->GetBranch(mDigtMCTruthBranchName.c_str())) { + throw std::runtime_error("MC data requested but not found in the tree"); + } + mTree->SetBranchAddress(mDigtMC2ROFBranchName.c_str(), &mDigMC2ROFsPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool useCalib, std::string defname) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("ITS", "DIGITS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("ITS", "DIGITSROF", 0, Lifetime::Timeframe); + if (useCalib) { + outputSpec.emplace_back("ITS", "GBTCALIB", 0, Lifetime::Timeframe); + } + if (useMC) { + outputSpec.emplace_back("ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); + outputSpec.emplace_back("ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "its-digit-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<ITSDigitReader>(useMC, useCalib)}, + Options{ + {"its-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +DataProcessorSpec getMFTDigitReaderSpec(bool useMC, bool useCalib, std::string defname) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("MFT", "DIGITS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("MFT", "DIGITSROF", 0, Lifetime::Timeframe); + if (useCalib) { + outputSpec.emplace_back("MFT", "GBTCALIB", 0, Lifetime::Timeframe); + } + if (useMC) { + outputSpec.emplace_back("MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); + outputSpec.emplace_back("MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "mft-digit-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<MFTDigitReader>(useMC, useCalib)}, + Options{ + {"mft-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace itsmft +} // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx index f01f6ae485031..3b4ed14092cba 100644 --- a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "ITSMFTWorkflow/DigitWriterSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/GBTCalibData.h" #include "Headers/DataHeader.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DataFormatsITSMFT/ROFRecord.h" @@ -37,10 +39,11 @@ using MCCont = o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>; /// create the processor spec /// describing a processor receiving digits for ITS/MFT and writing them to file -DataProcessorSpec getDigitWriterSpec(bool mctruth, o2::header::DataOrigin detOrig, o2::detectors::DetID detId) +DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::header::DataOrigin detOrig, o2::detectors::DetID detId) { std::string detStr = o2::detectors::DetID::getName(detId); - std::string detStrL = detStr; + std::string detStrL = dec ? "o2_" : ""; // for decoded digits prepend by o2 + detStrL += detStr; std::transform(detStrL.begin(), detStrL.end(), detStrL.begin(), ::tolower); auto logger = [](std::vector<o2::itsmft::Digit> const& inDigits) { LOG(INFO) << "RECEIVED DIGITS SIZE " << inDigits.size(); @@ -70,13 +73,14 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, o2::header::DataOrigin detOri LOG(INFO) << "WRITING " << labels.getNElements() << " LABELS "; o2::dataformats::IOMCTruthContainerView outputcontainer; - auto br = framework::RootTreeWriter::remapBranch(branch, &outputcontainer); + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); outputcontainer.adopt(labelbuffer); br->Fill(); br->ResetAddress(); }; - return MakeRootTreeWriterSpec((detStr + "DigitWriter").c_str(), + return MakeRootTreeWriterSpec((detStr + "DigitWriter" + (dec ? "_dec" : "")).c_str(), (detStrL + "digits.root").c_str(), MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Digits tree"}, MakeRootTreeWriterSpec::CustomClose(finishWriting), @@ -90,18 +94,21 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, o2::header::DataOrigin detOri BranchDefinition<std::vector<itsmft::Digit>>{InputSpec{"digits", detOrig, "DIGITS", 0}, (detStr + "Digit").c_str(), logger}, + BranchDefinition<std::vector<itsmft::GBTCalibData>>{InputSpec{"calib", detOrig, "GBTCALIB", 0}, + (detStr + "Calib").c_str(), + (calib ? 1 : 0)}, BranchDefinition<std::vector<itsmft::ROFRecord>>{InputSpec{"digitsROF", detOrig, "DIGITSROF", 0}, (detStr + "DigitROF").c_str()})(); } -DataProcessorSpec getITSDigitWriterSpec(bool mctruth) +DataProcessorSpec getITSDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, o2::header::gDataOriginITS, o2::detectors::DetID::ITS); + return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginITS, o2::detectors::DetID::ITS); } -DataProcessorSpec getMFTDigitWriterSpec(bool mctruth) +DataProcessorSpec getMFTDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, o2::header::gDataOriginMFT, o2::detectors::DetID::MFT); + return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginMFT, o2::detectors::DetID::MFT); } } // end namespace itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx index ffd61641dfd4b..15b253f2f5eeb 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,8 +25,8 @@ namespace o2 namespace itsmft { -EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig) - : mOrigin(orig), mCTFCoder(orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT) +EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig, bool getDigits) + : mOrigin(orig), mCTFCoder(orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT), mGetDigits(getDigits) { assert(orig == o2::header::gDataOriginITS || orig == o2::header::gDataOriginMFT); mTimer.Stop(); @@ -34,29 +35,35 @@ EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig) void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>((mOrigin == o2::header::gDataOriginITS) ? "its-ctf-dictionary" : "mft-ctf-dictionary"); - if (!dictPath.empty() && dictPath != "none") { - mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); - } + auto detID = mOrigin == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT; + mCTFDictPath = ic.options().get<std::string>("ctf-dict"); + mClusDictPath = o2::base::NameConf::getAlpideClusterDictionaryFileName(detID, ic.options().get<std::string>("cluster-dict-file"), "bin"); + mMaskNoise = ic.options().get<bool>("mask-noise"); + mNoiseFilePath = o2::base::NameConf::getNoiseFileName(detID, ic.options().get<std::string>("noise-file"), "root"); } void EntropyDecoderSpec::run(ProcessingContext& pc) { auto cput = mTimer.CpuTime(); mTimer.Start(false); + updateTimeDependentParams(pc); auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); - - auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(OutputRef{"ROframes"}); - auto& compcl = pc.outputs().make<std::vector<o2::itsmft::CompClusterExt>>(OutputRef{"compClusters"}); - auto& patterns = pc.outputs().make<std::vector<unsigned char>>(OutputRef{"patterns"}); - // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object const auto ctfImage = o2::itsmft::CTF::getImage(buff.data()); - mCTFCoder.decode(ctfImage, rofs, compcl, patterns); - mTimer.Stop(); - LOG(INFO) << "Decoded " << compcl.size() << " clusters in " << rofs.size() << " RO frames in " << mTimer.CpuTime() - cput << " s"; + if (mGetDigits) { + auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(OutputRef{"ROframes"}); + auto& digits = pc.outputs().make<std::vector<o2::itsmft::Digit>>(OutputRef{"Digits"}); + mCTFCoder.decode(ctfImage, rofs, digits, mNoiseMap.get(), mPattIdConverter); + } else { + auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(OutputRef{"ROframes"}); + auto& compcl = pc.outputs().make<std::vector<o2::itsmft::CompClusterExt>>(OutputRef{"compClusters"}); + auto& patterns = pc.outputs().make<std::vector<unsigned char>>(OutputRef{"patterns"}); + mCTFCoder.decode(ctfImage, rofs, compcl, patterns, mNoiseMap.get(), mPattIdConverter); + mTimer.Stop(); + LOG(INFO) << "Decoded " << compcl.size() << " clusters in " << rofs.size() << " RO frames in " << mTimer.CpuTime() - cput << " s"; + } } void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) @@ -65,21 +72,59 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mOrigin.as<std::string>(), mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig) +void EntropyDecoderSpec::updateTimeDependentParams(ProcessingContext& pc) { - std::vector<OutputSpec> outputs{ - OutputSpec{{"compClusters"}, orig, "COMPCLUSTERS", 0, Lifetime::Timeframe}, - OutputSpec{{"patterns"}, orig, "PATTERNS", 0, Lifetime::Timeframe}, - OutputSpec{{"ROframes"}, orig, "CLUSTERSROF", 0, Lifetime::Timeframe}}; + static bool coderUpdated = false; // with dicts loaded from CCDB one should check also the validity of current object + if (!coderUpdated) { + coderUpdated = true; + if (!mCTFDictPath.empty() && mCTFDictPath != "none") { + mCTFCoder.createCoders(mCTFDictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } + + if (mMaskNoise) { + if (o2::utils::Str::pathExists(mNoiseFilePath)) { + TFile* f = TFile::Open(mNoiseFilePath.data(), "old"); + mNoiseMap.reset((NoiseMap*)f->Get("ccdb_object")); + LOG(INFO) << "Loaded noise map from " << mNoiseFilePath; + } + if (!mNoiseMap) { + throw std::runtime_error("Noise masking was requested but noise mask was not provided"); + } + } + + if (mGetDigits || mMaskNoise) { + if (o2::utils::Str::pathExists(mClusDictPath)) { + mPattIdConverter.loadDictionary(mClusDictPath); + LOG(INFO) << "Loaded cluster topology dictionary from " << mClusDictPath; + } else { + LOG(INFO) << "Cluster topology dictionary is absent, all cluster patterns expected to be stored explicitly"; + } + } + } +} - std::string dictOptName = (orig == o2::header::gDataOriginITS) ? "its-ctf-dictionary" : "mft-ctf-dictionary"; +DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, bool getDigits) +{ + std::vector<OutputSpec> outputs; + if (getDigits) { + outputs.emplace_back(OutputSpec{{"Digits"}, orig, "DIGITS", 0, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"ROframes"}, orig, "DIGITSROF", 0, Lifetime::Timeframe}); + } else { + outputs.emplace_back(OutputSpec{{"compClusters"}, orig, "COMPCLUSTERS", 0, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"ROframes"}, orig, "CLUSTERSROF", 0, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"patterns"}, orig, "PATTERNS", 0, Lifetime::Timeframe}); + } return DataProcessorSpec{ - orig == o2::header::gDataOriginITS ? "its-entropy-decoder" : "mft-entropy-decoder", + EntropyDecoderSpec::getName(orig), Inputs{InputSpec{"ctf", orig, "CTFDATA", 0, Lifetime::Timeframe}}, outputs, - AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>(orig)}, - Options{{dictOptName, VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>(orig, getDigits)}, + Options{ + {"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}, + {"mask-noise", VariantType::Bool, false, {"apply noise mask to digits or clusters (involves reclusterization)"}}, + {"noise-file", VariantType::String, "", {"name of the noise map file"}}, + {"cluster-dict-file", VariantType::String, "", {"name of the cluster-topology dictionary file"}}}}; } } // namespace itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx index cb9af0129f9ab..6b04de5cddd4c 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ EntropyEncoderSpec::EntropyEncoderSpec(o2::header::DataOrigin orig) void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>((mOrigin == o2::header::gDataOriginITS) ? "its-ctf-dictionary" : "mft-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -72,14 +73,12 @@ DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig) inputs.emplace_back("patterns", orig, "PATTERNS", 0, Lifetime::Timeframe); inputs.emplace_back("ROframes", orig, "CLUSTERSROF", 0, Lifetime::Timeframe); - std::string dictOptName = (orig == o2::header::gDataOriginITS) ? "its-ctf-dictionary" : "mft-ctf-dictionary"; - return DataProcessorSpec{ orig == o2::header::gDataOriginITS ? "its-entropy-encoder" : "mft-entropy-encoder", inputs, Outputs{{orig, "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>(orig)}, - Options{{dictOptName, VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx index 224a0ada3a283..4cbc60b61ccef 100644 --- a/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "Framework/WorkflowSpec.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/DeviceSpec.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "ITSMFTReconstruction/RawPixelDecoder.h" @@ -40,10 +42,10 @@ using namespace o2::framework; ///_______________________________________ template <class Mapping> -STFDecoder<Mapping>::STFDecoder(bool doClusters, bool doPatterns, bool doDigits, std::string_view dict, std::string_view noise) - : mDoClusters(doClusters), mDoPatterns(doPatterns), mDoDigits(doDigits), mDictName(dict), mNoiseName(noise) +STFDecoder<Mapping>::STFDecoder(const STFDecoderInp& inp) + : mDoClusters(inp.doClusters), mDoPatterns(inp.doPatterns), mDoDigits(inp.doDigits), mDoCalibData(inp.doCalib), mDictName(inp.dict), mNoiseName(inp.noise) { - mSelfName = o2::utils::concat_string(Mapping::getName(), "STFDecoder"); + mSelfName = o2::utils::Str::concat_string(Mapping::getName(), "STFDecoder"); mTimer.Stop(); mTimer.Reset(); } @@ -52,51 +54,76 @@ STFDecoder<Mapping>::STFDecoder(bool doClusters, bool doPatterns, bool doDigits, template <class Mapping> void STFDecoder<Mapping>::init(InitContext& ic) { - mDecoder = std::make_unique<RawPixelDecoder<Mapping>>(); - mDecoder->init(); + try { + mDecoder = std::make_unique<RawPixelDecoder<Mapping>>(); + mDecoder->init(); + } catch (const std::exception& e) { + LOG(ERROR) << "exception was thrown in decoder creation: " << e.what(); + throw; + } catch (...) { + LOG(ERROR) << "non-std::exception was thrown in decoder creation"; + throw; + } auto detID = Mapping::getDetID(); - mNThreads = std::max(1, ic.options().get<int>("nthreads")); - mDecoder->setNThreads(mNThreads); - mDecoder->setFormat(ic.options().get<bool>("old-format") ? GBTLink::OldFormat : GBTLink::NewFormat); - mDecoder->setVerbosity(ic.options().get<int>("decoder-verbosity")); - - std::string noiseFile = o2::base::NameConf::getDictionaryFileName(detID, mNoiseName, ".root"); - if (o2::base::NameConf::pathExists(noiseFile)) { - TFile* f = TFile::Open(noiseFile.data(), "old"); - auto pnoise = (NoiseMap*)f->Get("Noise"); - AlpideCoder::setNoisyPixels(pnoise); - LOG(INFO) << mSelfName << " loading noise map file: " << noiseFile; - } else { - LOG(INFO) << mSelfName << " Noise file " << noiseFile << " is absent, " << Mapping::getName() << " running without noise suppression"; + try { + mNThreads = std::max(1, ic.options().get<int>("nthreads")); + mDecoder->setNThreads(mNThreads); + mDecoder->setFormat(ic.options().get<bool>("old-format") ? GBTLink::OldFormat : GBTLink::NewFormat); + mUnmutExtraLanes = ic.options().get<bool>("unmute-extra-lanes"); + mVerbosity = ic.options().get<int>("decoder-verbosity"); + mDecoder->setFillCalibData(mDoCalibData); + std::string noiseFile = o2::base::NameConf::getNoiseFileName(detID, mNoiseName, "root"); + if (o2::utils::Str::pathExists(noiseFile)) { + TFile* f = TFile::Open(noiseFile.data(), "old"); + auto pnoise = (NoiseMap*)f->Get("ccdb_object"); + AlpideCoder::setNoisyPixels(pnoise); + LOG(INFO) << mSelfName << " loading noise map file: " << noiseFile; + } else { + LOG(INFO) << mSelfName << " Noise file " << noiseFile << " is absent, " << Mapping::getName() << " running without noise suppression"; + } + } catch (const std::exception& e) { + LOG(ERROR) << "exception was thrown in decoder configuration: " << e.what(); + throw; + } catch (...) { + LOG(ERROR) << "non-std::exception was thrown in decoder configuration"; + throw; } if (mDoClusters) { - mClusterer = std::make_unique<Clusterer>(); - mClusterer->setNChips(Mapping::getNChips()); - const auto grp = o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName()); - if (grp) { - mClusterer->setContinuousReadOut(grp->isDetContinuousReadOut(detID)); - } else { - throw std::runtime_error("failed to retrieve GRP"); - } + try { + mClusterer = std::make_unique<Clusterer>(); + mClusterer->setNChips(Mapping::getNChips()); + const auto grp = o2::parameters::GRPObject::loadFrom(); + if (grp) { + mClusterer->setContinuousReadOut(grp->isDetContinuousReadOut(detID)); + } else { + throw std::runtime_error("failed to retrieve GRP"); + } - // settings for the fired pixel overflow masking - const auto& alpParams = DPLAlpideParam<Mapping::getDetID()>::Instance(); - const auto& clParams = ClustererParam<Mapping::getDetID()>::Instance(); - auto nbc = clParams.maxBCDiffToMaskBias; - nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); - mClusterer->setMaxBCSeparationToMask(nbc); - mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); - - std::string dictFile = o2::base::NameConf::getDictionaryFileName(detID, mDictName, ".bin"); - if (o2::base::NameConf::pathExists(dictFile)) { - mClusterer->loadDictionary(dictFile); - LOG(INFO) << mSelfName << " clusterer running with a provided dictionary: " << dictFile; - } else { - LOG(INFO) << mSelfName << " Dictionary " << dictFile << " is absent, " << Mapping::getName() << " clusterer expects cluster patterns"; + // settings for the fired pixel overflow masking + const auto& alpParams = DPLAlpideParam<Mapping::getDetID()>::Instance(); + const auto& clParams = ClustererParam<Mapping::getDetID()>::Instance(); + auto nbc = clParams.maxBCDiffToMaskBias; + nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); + mClusterer->setMaxBCSeparationToMask(nbc); + mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); + + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(detID, mDictName, "bin"); + if (o2::utils::Str::pathExists(dictFile)) { + mClusterer->loadDictionary(dictFile); + LOG(INFO) << mSelfName << " clusterer running with a provided dictionary: " << dictFile; + } else { + LOG(INFO) << mSelfName << " Dictionary " << dictFile << " is absent, " << Mapping::getName() << " clusterer expects cluster patterns"; + } + mClusterer->print(); + } catch (const std::exception& e) { + LOG(ERROR) << "exception was thrown in clustrizer configuration: " << e.what(); + throw; + } catch (...) { + LOG(ERROR) << "non-std::exception was thrown in clusterizer configuration"; + throw; } - mClusterer->print(); } } @@ -104,6 +131,13 @@ void STFDecoder<Mapping>::init(InitContext& ic) template <class Mapping> void STFDecoder<Mapping>::run(ProcessingContext& pc) { + static bool firstCall = true; + if (firstCall) { + firstCall = false; + mDecoder->setInstanceID(pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId); + mDecoder->setNInstances(pc.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices); + mDecoder->setVerbosity(mDecoder->getInstanceID() == 0 ? mVerbosity : (mUnmutExtraLanes ? mVerbosity : -1)); + } int nSlots = pc.inputs().getNofParts(0); double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime(); mTimer.Start(false); @@ -112,12 +146,31 @@ void STFDecoder<Mapping>::run(ProcessingContext& pc) std::vector<o2::itsmft::CompClusterExt> clusCompVec; std::vector<o2::itsmft::ROFRecord> clusROFVec; std::vector<unsigned char> clusPattVec; + std::vector<Digit> digVec; + std::vector<GBTCalibData> calVec; std::vector<ROFRecord> digROFVec; + + if (mDoDigits) { + digVec.reserve(mEstNDig); + digROFVec.reserve(mEstNROF); + } + if (mDoClusters) { + clusCompVec.reserve(mEstNClus); + clusROFVec.reserve(mEstNROF); + clusPattVec.reserve(mEstNClusPatt); + } + if (mDoCalibData) { + calVec.reserve(mEstNCalib); + } + mDecoder->setDecodeNextAuto(false); while (mDecoder->decodeNextTrigger()) { if (mDoDigits) { // call before clusterization, since the latter will hide the digits mDecoder->fillDecodedDigits(digVec, digROFVec); // lot of copying involved + if (mDoCalibData) { + mDecoder->fillCalibData(calVec); + } } if (mDoClusters) { // !!! THREADS !!! mClusterer->process(mNThreads, *mDecoder.get(), &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec); @@ -127,11 +180,21 @@ void STFDecoder<Mapping>::run(ProcessingContext& pc) if (mDoDigits) { pc.outputs().snapshot(Output{orig, "DIGITS", 0, Lifetime::Timeframe}, digVec); pc.outputs().snapshot(Output{orig, "DIGITSROF", 0, Lifetime::Timeframe}, digROFVec); + mEstNDig = std::max(mEstNDig, size_t(digVec.size() * 1.2)); + mEstNROF = std::max(mEstNROF, size_t(digROFVec.size() * 1.2)); + if (mDoCalibData) { + pc.outputs().snapshot(Output{orig, "GBTCALIB", 0, Lifetime::Timeframe}, calVec); + mEstNCalib = std::max(mEstNCalib, size_t(calVec.size() * 1.2)); + } } + if (mDoClusters) { // we are not obliged to create vectors which are not requested, but other devices might not know the options of this one pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0, Lifetime::Timeframe}, clusCompVec); pc.outputs().snapshot(Output{orig, "PATTERNS", 0, Lifetime::Timeframe}, clusPattVec); pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0, Lifetime::Timeframe}, clusROFVec); + mEstNClus = std::max(mEstNClus, size_t(clusCompVec.size() * 1.2)); + mEstNClusPatt = std::max(mEstNClusPatt, size_t(clusPattVec.size() * 1.2)); + mEstNROF = std::max(mEstNROF, size_t(clusROFVec.size() * 1.2)); } if (mDoClusters) { @@ -141,7 +204,8 @@ void STFDecoder<Mapping>::run(ProcessingContext& pc) LOG(INFO) << mSelfName << " Decoded " << digVec.size() << " Digits in " << digROFVec.size() << " ROFs"; } mTimer.Stop(); - LOG(INFO) << mSelfName << " Total time for TF " << mTFCounter << " : CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0; + auto tfID = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; + LOG(INFO) << mSelfName << " Total time for TF " << tfID << '(' << mTFCounter << ") : CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0; mTFCounter++; } @@ -160,58 +224,44 @@ void STFDecoder<Mapping>::endOfStream(EndOfStreamContext& ec) } } -DataProcessorSpec getSTFDecoderITSSpec(bool doClusters, bool doPatterns, bool doDigits, const std::string& dict, const std::string& noise) +DataProcessorSpec getSTFDecoderSpec(const STFDecoderInp& inp) { std::vector<OutputSpec> outputs; - auto orig = o2::header::gDataOriginITS; - - if (doDigits) { - outputs.emplace_back(orig, "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back(orig, "DIGITSROF", 0, Lifetime::Timeframe); - } - if (doClusters) { - outputs.emplace_back(orig, "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back(orig, "CLUSTERSROF", 0, Lifetime::Timeframe); - outputs.emplace_back(orig, "PATTERNS", 0, Lifetime::Timeframe); + if (inp.doDigits) { + outputs.emplace_back(inp.origin, "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back(inp.origin, "DIGITSROF", 0, Lifetime::Timeframe); + if (inp.doCalib) { + outputs.emplace_back(inp.origin, "GBTCALIB", 0, Lifetime::Timeframe); + } } - - return DataProcessorSpec{ - "its-stf-decoder", - Inputs{{"stf", ConcreteDataTypeMatcher{orig, "RAWDATA"}, Lifetime::Timeframe}}, - outputs, - AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingITS>>(doClusters, doPatterns, doDigits, dict, noise)}, - Options{ - {"nthreads", VariantType::Int, 1, {"Number of decoding/clustering threads"}}, - {"old-format", VariantType::Bool, false, {"Use old format (1 trigger per CRU page)"}}, - {"decoder-verbosity", VariantType::Int, 0, {"Verbosity level (-1: silent, 0: errors, 1: headers, 2: data)"}}}}; -} - -DataProcessorSpec getSTFDecoderMFTSpec(bool doClusters, bool doPatterns, bool doDigits, const std::string& dict, const std::string& noise) -{ - std::vector<OutputSpec> outputs; - auto orig = o2::header::gDataOriginMFT; - if (doDigits) { - outputs.emplace_back(orig, "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back(orig, "DIGITSROF", 0, Lifetime::Timeframe); - } - if (doClusters) { - outputs.emplace_back(orig, "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back(orig, "CLUSTERSROF", 0, Lifetime::Timeframe); + if (inp.doClusters) { + outputs.emplace_back(inp.origin, "COMPCLUSTERS", 0, Lifetime::Timeframe); + outputs.emplace_back(inp.origin, "CLUSTERSROF", 0, Lifetime::Timeframe); // in principle, we don't need to open this input if we don't need to send real data, // but other devices expecting it do not know about options of this device: problem? // if (doClusters && doPatterns) - outputs.emplace_back(orig, "PATTERNS", 0, Lifetime::Timeframe); + outputs.emplace_back(inp.origin, "PATTERNS", 0, Lifetime::Timeframe); + } + + auto inputs = o2::framework::select(inp.inputSpec.c_str()); + if (inp.askSTFDist) { + for (auto& ins : inputs) { // mark input as optional in order not to block the workflow if our raw data happen to be missing in some TFs + ins.lifetime = Lifetime::Optional; + } + // request the input FLP/DISTSUBTIMEFRAME/0 that is _guaranteed_ to be present, even if none of our raw data is present. + inputs.emplace_back("stfDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); } return DataProcessorSpec{ - "mft-stf-decoder", - Inputs{{"stf", ConcreteDataTypeMatcher{orig, "RAWDATA"}, Lifetime::Timeframe}}, + inp.deviceName, + inputs, outputs, - AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingMFT>>(doClusters, doPatterns, doDigits, dict, noise)}, + inp.origin == o2::header::gDataOriginITS ? AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingITS>>(inp)} : AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingMFT>>(inp)}, Options{ {"nthreads", VariantType::Int, 1, {"Number of decoding/clustering threads"}}, {"old-format", VariantType::Bool, false, {"Use old format (1 trigger per CRU page)"}}, - {"decoder-verbosity", VariantType::Int, 0, {"Verbosity level (-1: silent, 0: errors, 1: headers, 2: data)"}}}}; + {"decoder-verbosity", VariantType::Int, 0, {"Verbosity level (-1: silent, 0: errors, 1: headers, 2: data) of 1st lane"}}, + {"unmute-extra-lanes", VariantType::Bool, false, {"allow extra lanes to be as verbose as 1st one"}}}}; } } // namespace itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/digit-reader-workflow.cxx b/Detectors/ITSMFT/common/workflow/src/digit-reader-workflow.cxx new file mode 100644 index 0000000000000..7ebef7b4bbc5b --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/digit-reader-workflow.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSMFTWorkflow/DigitReaderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ + ConfigParamSpec{"disable-mc", VariantType::Bool, false, {"disable mc truth"}}, + ConfigParamSpec{"enable-calib-data", VariantType::Bool, false, {"enable writing GBT calibration data"}}, + ConfigParamSpec{"runmft", VariantType::Bool, false, {"expect MFT data"}}, + ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + bool useMC = !cfgc.options().get<bool>("disable-mc"); + bool calib = cfgc.options().get<bool>("enable-calib-data"); + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + if (cfgc.options().get<bool>("runmft")) { + wf.emplace_back(o2::itsmft::getMFTDigitReaderSpec(useMC, calib)); + } else { + wf.emplace_back(o2::itsmft::getITSDigitReaderSpec(useMC, calib)); + } + return wf; +} diff --git a/Detectors/ITSMFT/common/workflow/src/digit-writer-workflow.cxx b/Detectors/ITSMFT/common/workflow/src/digit-writer-workflow.cxx index f969f197380af..1ec097fa5d7ee 100644 --- a/Detectors/ITSMFT/common/workflow/src/digit-writer-workflow.cxx +++ b/Detectors/ITSMFT/common/workflow/src/digit-writer-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) // option allowing to set parameters std::vector<ConfigParamSpec> options{ ConfigParamSpec{"disable-mc", VariantType::Bool, false, {"disable mc truth"}}, + ConfigParamSpec{"enable-calib-data", VariantType::Bool, false, {"enable writing GBT calibration data"}}, ConfigParamSpec{"runmft", VariantType::Bool, false, {"expect MFT data"}}, ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}}; @@ -36,14 +38,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec wf; bool useMC = !cfgc.options().get<bool>("disable-mc"); - + bool calib = cfgc.options().get<bool>("enable-calib-data"); // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); if (cfgc.options().get<bool>("runmft")) { - wf.emplace_back(o2::itsmft::getMFTDigitWriterSpec(useMC)); + wf.emplace_back(o2::itsmft::getMFTDigitWriterSpec(useMC, true, calib)); } else { - wf.emplace_back(o2::itsmft::getITSDigitWriterSpec(useMC)); + wf.emplace_back(o2::itsmft::getITSDigitWriterSpec(useMC, true, calib)); } return wf; } diff --git a/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx b/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx index 2859ab6bcd0c3..0383458602b02 100644 --- a/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/common/workflow/src/stf-decoder-workflow.cxx b/Detectors/ITSMFT/common/workflow/src/stf-decoder-workflow.cxx index 55992bcce62be..0c3ca2c5fa64f 100644 --- a/Detectors/ITSMFT/common/workflow/src/stf-decoder-workflow.cxx +++ b/Detectors/ITSMFT/common/workflow/src/stf-decoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,8 +26,11 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) ConfigParamSpec{"no-clusters", VariantType::Bool, false, {"do not produce clusters (def: produce)"}}, ConfigParamSpec{"no-cluster-patterns", VariantType::Bool, false, {"do not produce clusters patterns (def: produce)"}}, ConfigParamSpec{"digits", VariantType::Bool, false, {"produce digits (def: skip)"}}, + ConfigParamSpec{"enable-calib-data", VariantType::Bool, false, {"produce GBT calibration stream (def: skip)"}}, ConfigParamSpec{"dict-file", VariantType::String, "", {"name of the cluster-topology dictionary file"}}, ConfigParamSpec{"noise-file", VariantType::String, "", {"name of the noise map file"}}, + ConfigParamSpec{"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + ConfigParamSpec{"dataspec", VariantType::String, "", {"selection string for the input data, if not provided <DET>Raw:<DET>/RAWDATA with DET=ITS or MFT will be used"}}, ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; std::swap(workflowOptions, options); @@ -39,19 +43,32 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec wf; - auto doClusters = !cfgc.options().get<bool>("no-clusters"); - auto doPatterns = doClusters && !cfgc.options().get<bool>("no-cluster-patterns"); - auto doDigits = cfgc.options().get<bool>("digits"); - auto dict = cfgc.options().get<std::string>("dict-file"); - auto noise = cfgc.options().get<std::string>("noise-file"); - + o2::itsmft::STFDecoderInp inp; + inp.doClusters = !cfgc.options().get<bool>("no-clusters"); + inp.doPatterns = inp.doClusters && !cfgc.options().get<bool>("no-cluster-patterns"); + inp.doDigits = cfgc.options().get<bool>("digits"); + inp.doCalib = cfgc.options().get<bool>("enable-calib-data"); + inp.dict = cfgc.options().get<std::string>("dict-file"); + inp.noise = cfgc.options().get<std::string>("noise-file"); + inp.askSTFDist = !cfgc.options().get<bool>("ignore-dist-stf"); + inp.inputSpec = cfgc.options().get<std::string>("dataspec"); // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); if (cfgc.options().get<bool>("runmft")) { - wf.emplace_back(o2::itsmft::getSTFDecoderMFTSpec(doClusters, doPatterns, doDigits, dict, noise)); + if (inp.inputSpec.empty()) { + inp.inputSpec = "mftRAW:MFT/RAWDATA"; + } + inp.origin = o2::header::gDataOriginMFT; + inp.deviceName = "mft-stf-decoder"; } else { - wf.emplace_back(o2::itsmft::getSTFDecoderITSSpec(doClusters, doPatterns, doDigits, dict, noise)); + if (inp.inputSpec.empty()) { + inp.inputSpec = "itsRAW:ITS/RAWDATA"; + } + inp.origin = o2::header::gDataOriginITS; + inp.deviceName = "its-stf-decoder"; } + wf.emplace_back(o2::itsmft::getSTFDecoderSpec(inp)); + return wf; } diff --git a/Detectors/ITSMFT/test/CMakeLists.txt b/Detectors/ITSMFT/test/CMakeLists.txt index 1f39c887404f9..58feb83e80816 100644 --- a/Detectors/ITSMFT/test/CMakeLists.txt +++ b/Detectors/ITSMFT/test/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(HitAnalysis) diff --git a/Detectors/ITSMFT/test/HitAnalysis/CMakeLists.txt b/Detectors/ITSMFT/test/HitAnalysis/CMakeLists.txt index afc16d98a495d..4155023626774 100644 --- a/Detectors/ITSMFT/test/HitAnalysis/CMakeLists.txt +++ b/Detectors/ITSMFT/test/HitAnalysis/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(HitAnalysis SOURCES src/HitAnalysis.cxx diff --git a/Detectors/ITSMFT/test/HitAnalysis/include/HitAnalysis/HitAnalysis.h b/Detectors/ITSMFT/test/HitAnalysis/include/HitAnalysis/HitAnalysis.h index 35fb89fd71202..a4d8fca7dc41f 100644 --- a/Detectors/ITSMFT/test/HitAnalysis/include/HitAnalysis/HitAnalysis.h +++ b/Detectors/ITSMFT/test/HitAnalysis/include/HitAnalysis/HitAnalysis.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx index 2b8ce3edbd0f6..036e95bee2664 100644 --- a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx +++ b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysisLinkDef.h b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysisLinkDef.h index 179c50e10befb..ee87d6e3c6c62 100644 --- a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysisLinkDef.h +++ b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysisLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/CMakeLists.txt b/Detectors/MUON/CMakeLists.txt index 29c99f261cd86..9638a3dd5278d 100644 --- a/Detectors/MUON/CMakeLists.txt +++ b/Detectors/MUON/CMakeLists.txt @@ -1,12 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +add_subdirectory(Common) +add_subdirectory(Matching) add_subdirectory(MCH) add_subdirectory(MID) +add_subdirectory(Workflow) diff --git a/Detectors/MUON/Common/CMakeLists.txt b/Detectors/MUON/Common/CMakeLists.txt new file mode 100644 index 0000000000000..fc4856172633d --- /dev/null +++ b/Detectors/MUON/Common/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +set(subsystems "mch;mid") + +foreach(det IN LISTS subsystems) + string(TOUPPER ${det} DET) + o2_add_executable(dcs-ccdb + COMPONENT_NAME ${det} + SOURCES src/dcs-ccdb.cxx src/aliasFixer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsDCS O2::CCDB O2::${DET}Conditions + TARGETVARNAME exe-dcs-ccdb) + target_compile_definitions(${exe-dcs-ccdb} PRIVATE "MUON_SUBSYSTEM_${DET}") + + o2_add_executable(${det}-dcs-processor-workflow + COMPONENT_NAME calibration + SOURCES src/dcs-processor-workflow.cxx src/aliasFixer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsDCS O2::${DET}Conditions + TARGETVARNAME exe-dcs-processor-workflow) + target_compile_definitions(${exe-dcs-processor-workflow} PRIVATE "MUON_SUBSYSTEM_${DET}") + + o2_add_executable(${det}-dcs-sim-workflow + COMPONENT_NAME calibration + SOURCES src/${det}-dcs-sim-workflow.cxx src/aliasFixer.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow O2::${DET}Conditions) +endforeach() + diff --git a/Detectors/MUON/Common/README.md b/Detectors/MUON/Common/README.md new file mode 100644 index 0000000000000..fc18b7b18dc7b --- /dev/null +++ b/Detectors/MUON/Common/README.md @@ -0,0 +1,82 @@ +<!-- doxy +\page refDetectorsMUONCommon Common +/doxy --> + +# Common code for MID and MCH + +For the moment the only commonality stems from the DCS to CCDB part, as +both subsystems only transmit DCS datapoints to CCDB, without any particular +treatment. So we use almost the same source code, but generate separate +executables, e.g. to ease the integration with `dcs-proxy`-based workflows. + +Note that MCH transmit both the HV and LV values to CCDB, while MID only +transmit HV values. + +## DCS to CCDB + +To test the DCS to CCDB route you can use the following 3 parts worfklow pipeline : + +```shell +o2-calibration-mch-dcs-sim-workflow --max-timeframes 600 --max-cycles-no-full-map 10 -b | \ +o2-calibration-mch-dcs-processor-workflow --hv-max-size 0 --hv-max-duration 300 --lv-max-size 0 --lv-max-duration 300 -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:6464" -b +``` + +```shell +o2-calibration-mid-dcs-sim-workflow --max-timeframes 600 --max-cycles-no-full-map 10 -b | \ +o2-calibration-mid-dcs-processor-workflow --hv-max-size 0 --hv-max-duration 300 -b | \ +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:6464" -b +``` + +Note that the only difference (besides the mid vs mch naming) is the set of + options of the `processor` device (handling just hv for mid and hv+lv for mch). + +- `o2-calibration-[mch|mid]-dcs-sim-worfklow` is just generating fake random MCH or MID DCS data points, +- `o2-calibration-[mch|mid]-dcs-processor-workflow` gathers the received data points into a container object +- `o2-calibration-ccdb-populator-workflow` uploads the container object to the CCDB (in this example a local dev ccdb). + + The container object that groups the datapoints is considered ready to be shipped either when the data points span a long enough duration (see the `--xxx-max-duration` option(s) of the `o2-calibration-[mch|mid]-dcs-processor-workflow`) or is big enough (see the `--xxx-max-size` option(s)). + +## MCH DCS Data Points + +### HV + +The MCH high voltage (HV) system is composed of 188 channels : + +- 48 channels for stations 1 and 2 (3 HV channel per quadrant x 16 quadrants) +- 140 channels for stations 3, 4, 5 (1 HV channel per slat x 140 slats) + +### LV + +The MCH low voltage (LV) system is composed of 328 channels : + +- 216 channels (108 x 2 different voltage values) to power up the front-end + electronics (dualsampas) +- 112 channels to power up the readout crates hosting the solar (readout) cards + +## MID DCS Data Points + +### HV + +The MID high voltage (HV) system is composed of 72 channels, one channel per RPC. + +## CCDB quick check + +Besides the web browsing of the CCDB, another quick check can be performed with + the `o2-[mch|mid]-dcs-ccdb` program to dump the DCS datapoints (hv, lv, or both) or + the datapoint config valid at a given timestamp. + +``` +$ o2-mch-dcs-ccdb --help +$ o2-mch-dcs-ccdb --ccdb http://localhost:6464 --query hv --query lv --query dpconf +$ o2-mid-dcs-ccdb --ccdb http://localhost:6464 --query hv --query dpconf +``` + +The same programs can be used to upload to CCDB the DCS data point configuration + for the dcs-proxy : + +``` +$ o2-mch-dcs-ccdb --put-datapoint-config --ccdb http://localhost:8080 +$ o2-mid-dcs-ccdb --put-datapoint-config --ccdb http://localhost:8080 +``` + diff --git a/Detectors/MUON/Common/src/aliasFixer.cxx b/Detectors/MUON/Common/src/aliasFixer.cxx new file mode 100644 index 0000000000000..a7744a143ec8c --- /dev/null +++ b/Detectors/MUON/Common/src/aliasFixer.cxx @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "aliasFixer.h" +#include <algorithm> + +namespace o2::muon +{ +std::string replaceDotByUnderscore(const std::string& alias) +{ + std::string a{alias}; + std::transform(a.begin(), a.end(), a.begin(), [](unsigned char c) { + if (c == '.') { + return '_'; + } + return (char)c; + }); + return a; +} + +} // namespace o2::muon diff --git a/Detectors/MUON/Common/src/aliasFixer.h b/Detectors/MUON/Common/src/aliasFixer.h new file mode 100644 index 0000000000000..b48883e63466b --- /dev/null +++ b/Detectors/MUON/Common/src/aliasFixer.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MUON_COMMON_ALIASFIXER_H +#define O2_MUON_COMMON_ALIASFIXER_H + +#include <string> + +namespace o2::muon +{ +/** For some reason linked to ADAPOS (or underlying ORACLE ?) + * datapoints we get from there cannot contain the dot character, + * so we replace it by an underscore. + */ +std::string replaceDotByUnderscore(const std::string& alias); +}; // namespace o2::muon + +#endif diff --git a/Detectors/MUON/Common/src/dcs-ccdb.cxx b/Detectors/MUON/Common/src/dcs-ccdb.cxx new file mode 100644 index 0000000000000..306f727e85d1a --- /dev/null +++ b/Detectors/MUON/Common/src/dcs-ccdb.cxx @@ -0,0 +1,212 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "aliasFixer.h" +#if defined(MUON_SUBSYSTEM_MCH) +#include "MCHConditions/DCSNamer.h" +#elif defined(MUON_SUBSYSTEM_MID) +#include "MIDConditions/DCSNamer.h" +#endif +#include <boost/program_options.hpp> +#include <ctime> +#include <iostream> +#include <map> +#include <numeric> +#include <regex> +#include <string> +#include <unordered_map> +#include <vector> +#include "subsysname.h" + +namespace po = boost::program_options; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPMAP = std::unordered_map<DPID, std::vector<DPVAL>>; + +std::string CcdbDpConfName() +{ + return fmt::format("{}/Config/DCSDPconfig", o2::muon::subsysname()); +} + +bool verbose; + +void doQueryHVLV(const std::string ccdbUrl, uint64_t timestamp, bool hv, bool lv) +{ + std::vector<std::string> what; + if (hv) { + what.emplace_back(fmt::format("{}/HV", o2::muon::subsysname())); + } + if (lv) { + what.emplace_back(fmt::format("{}/LV", o2::muon::subsysname())); + } + + auto sum = + [](float s, o2::dcs::DataPointValue v) { + union Converter { + uint64_t raw_data; + double value; + } converter; + converter.raw_data = v.payload_pt1; + return s + converter.value; + }; + + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + for (auto w : what) { + std::map<std::string, std::string> metadata; + auto* m = api.retrieveFromTFileAny<DPMAP>(w, metadata, timestamp); + std::cout << "size of " << w << " map = " << m->size() << std::endl; + if (verbose) { + for (auto& i : *m) { + auto v = i.second; + auto mean = std::accumulate(v.begin(), v.end(), 0.0, sum); + if (v.size()) { + mean /= v.size(); + } + std::cout << fmt::format("{:64s} {:4d} values of mean {:7.2f}\n", i.first.get_alias(), v.size(), + mean); + } + } + } +} + +void doQueryDataPointConfig(const std::string ccdbUrl, uint64_t timestamp, + const std::string dpConfName) +{ + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + using DPCONF = std::unordered_map<DPID, std::string>; + std::map<std::string, std::string> metadata; + auto* m = api.retrieveFromTFileAny<DPCONF>(dpConfName.c_str(), metadata, timestamp); + std::cout << "size of dpconf map = " << m->size() << std::endl; + if (verbose) { + for (auto& i : *m) { + std::cout << i.second << " " << i.first << "\n"; + } + } +} + +void makeCCDBEntryForDCS(const std::string ccdbUrl, uint64_t timestamp) +{ + std::unordered_map<DPID, std::string> dpid2DataDesc; +#if defined(MUON_SUBSYSTEM_MCH) + auto aliases = o2::mch::dcs::aliases(); +#elif defined(MUON_SUBSYSTEM_MID) + auto aliases = o2::mid::dcs::aliases(); +#endif + + DPID dpidtmp; + for (const auto& a : aliases) { + auto legitName = o2::muon::replaceDotByUnderscore(a); + DPID::FILL(dpidtmp, legitName, o2::dcs::DeliveryType::RAW_DOUBLE); + dpid2DataDesc[dpidtmp] = fmt::format("{}DATAPOINTS", o2::muon ::subsysname()); + } + + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + std::map<std::string, std::string> md; + std::cout << "storing config of " << dpid2DataDesc.size() + << o2::muon::subsysname() << " data points to " + << CcdbDpConfName() << "\n"; + + api.storeAsTFileAny(&dpid2DataDesc, CcdbDpConfName(), md, timestamp); +} + +bool match(const std::vector<std::string>& queries, const char* pattern) +{ + return std::find_if(queries.begin(), queries.end(), [pattern](std::string s) { return std::regex_match(s, std::regex(pattern, std::regex::extended | std::regex::icase)); }) != queries.end(); +} + +int main(int argc, char** argv) +{ + po::variables_map vm; + po::options_description usage("Usage"); + + std::string ccdbUrl; + std::string dpConfName; + uint64_t timestamp; + bool lv; + bool hv; + bool dpconf; + bool put; + + uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + + // clang-format off + usage.add_options() + ("help,h", "produce help message") + ("ccdb,c",po::value<std::string>(&ccdbUrl)->default_value("http://localhost:6464"),"ccdb url") + ("query,q",po::value<std::vector<std::string>>(),"what to query (if anything)") + ("timestamp,t",po::value<uint64_t>(×tamp)->default_value(now),"timestamp for query or put") + ("put-datapoint-config,p",po::bool_switch(&put),"upload datapoint configuration") + ("verbose,v",po::bool_switch(&verbose),"verbose output") + ("datapoint-conf-name",po::value<std::string>(&dpConfName)->default_value(CcdbDpConfName()),"dp conf name (only if not from mch or mid)") + ; + // clang-format on + + po::options_description cmdline; + cmdline.add(usage); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << "This program printout summary information from " + << o2::muon::subsysname() << " DCS entries.\n"; + std::cout << usage << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + if (vm.count("query")) { + auto query = vm["query"].as<std::vector<std::string>>(); + + hv = match(query, ".*(hv)"); +#if defined(MUON_SUBSYSTEM_MCH) + lv = match(query, ".*(lv)"); +#else + lv = false; +#endif + dpconf = match(query, ".*(dpconf)"); + + if (!hv && !lv && !dpconf) { + std::cout << "Must specify at least one of dpconf,hv"; +#if defined(MUON_SUBSYSTEM_MCH) + std::cout << ",lv"; +#endif + std::cout << " parameter to --query option\n"; + std::cout + << usage << "\n"; + return 3; + } + + if (hv || lv) { + doQueryHVLV(ccdbUrl, timestamp, hv, lv); + } + + if (dpconf) { + doQueryDataPointConfig(ccdbUrl, timestamp, dpConfName); + } + } + + if (put) { + makeCCDBEntryForDCS(ccdbUrl, timestamp); + } + return 0; +} diff --git a/Detectors/MUON/Common/src/dcs-processor-workflow.cxx b/Detectors/MUON/Common/src/dcs-processor-workflow.cxx new file mode 100644 index 0000000000000..f86b3c19bd370 --- /dev/null +++ b/Detectors/MUON/Common/src/dcs-processor-workflow.cxx @@ -0,0 +1,389 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "DetectorsCalibration/Utils.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/runDataProcessing.h" +#include "aliasFixer.h" +#include "subsysname.h" +#include <array> +#include <gsl/span> +#include <iostream> +#include <unordered_map> +#include <vector> +#include "CommonUtils/ConfigurableParam.h" +#if defined(MUON_SUBSYSTEM_MCH) +#include "MCHConditions/DCSNamer.h" +#define CCDBOBJ "MCH_DPS" +#endif +#if defined(MUON_SUBSYSTEM_MID) +#include "MIDConditions/DCSNamer.h" +#define CCDBOBJ "MID_DPS" +#endif + +namespace +{ + +using DPID = o2::dcs::DataPointIdentifier; // aka alias name +using DPVAL = o2::dcs::DataPointValue; +using DPMAP = std::unordered_map<DPID, std::vector<DPVAL>>; + +using namespace o2::calibration; +std::vector<o2::framework::OutputSpec> calibrationOutputs{ + o2::framework::ConcreteDataTypeMatcher{Utils::gDataOriginCDBPayload, CCDBOBJ}, + o2::framework::ConcreteDataTypeMatcher{Utils::gDataOriginCDBWrapper, CCDBOBJ}}; + +/* +* Create a default CCDB Object Info that will be used as a template. +* +* @param path describes the CCDB data path used (e.g. MCH/LV or MID/HV) +* +* The start and end validity times are supposed to be updated from this template, +* as well as the metadata (if needed). The rest of the information should +* be taken as is. +*/ +o2::ccdb::CcdbObjectInfo createDefaultInfo(const char* path) +{ + DPMAP obj; + auto clName = o2::utils::MemFileHelper::getClassName(obj); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + o2::ccdb::CcdbObjectInfo info; + info.setPath(path); + info.setObjectType(clName); + info.setFileName(flName); + info.setStartValidityTimestamp(0); + info.setEndValidityTimestamp(99999999999999); + std::map<std::string, std::string> md; + info.setMetaData(md); + return info; +} + +#if defined(MUON_SUBSYSTEM_MCH) +#define NOBJECTS 2 +std::array<o2::ccdb::CcdbObjectInfo, NOBJECTS> info{createDefaultInfo("MCH/Calib/HV"), createDefaultInfo("MCH/Calib/LV")}; +#elif defined(MUON_SUBSYSTEM_MID) +#define NOBJECTS 1 +std::array<o2::ccdb::CcdbObjectInfo, NOBJECTS> info{createDefaultInfo("MID/Calib/HV")}; +#endif + +std::array<DPMAP, NOBJECTS> dataPoints; + +int t0{-1}; + +/* +* Send a DPMAP to the output. +* +* @param dpmap a map of string to vector of DataPointValue +* @param output a DPL data allocator +* @param info a CCDB object info describing the dpmap +* @param reason (optional, can be empty) a string description why the dpmap +* was ready to be shipped (e.g. big enough, long enough, end of process, etc...) +*/ +void sendOutput(const DPMAP& dpmap, o2::framework::DataAllocator& output, o2::ccdb::CcdbObjectInfo info, const std::string& reason) +{ + if (dpmap.empty()) { + // we do _not_ write empty objects + return; + } + auto md = info.getMetaData(); + md["upload reason"] = reason; + info.setMetaData(md); + auto image = o2::ccdb::CcdbApi::createObjectImage(&dpmap, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" + << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp() + << " | reason: " << reason; + output.snapshot(o2::framework::Output{Utils::gDataOriginCDBPayload, CCDBOBJ, 0}, *image.get()); + output.snapshot(o2::framework::Output{Utils::gDataOriginCDBWrapper, CCDBOBJ, 0}, info); +} + +/* +* Implementation of DPL end of stream callback. +* +* We send the remaining datapoints at the end of the processing. +*/ +void endOfStream(o2::framework::EndOfStreamContext& eosc) +{ + LOG(DEBUG) << "This is the end. Must write what we have left ?\n"; + for (auto i = 0; i < NOBJECTS; i++) { + sendOutput(dataPoints[i], eosc.outputs(), info[i], "end of stream"); + } +} + +/* +* Compute the (approximate) size (in KB) of a dpmap. +*/ +size_t computeSize(const DPMAP& dpmap) +{ + constexpr int itemSize = 64; // DataPointIdentifier or DataPointValue have the same size = 64 bytes + constexpr float byte2KB = 1.0 / 1024; + + size_t nofItems = 0; + for (auto did : dpmap) { + nofItems++; // +1 for the DataPointIdentifier itself + nofItems += did.second.size(); // +number of DataPointValues + } + return static_cast<size_t>(std::floor(nofItems * itemSize * byte2KB)); +} + +/* +* Compute the duration (in seconds) span by the datapoints in the dpmap. +*/ +int computeDuration(const DPMAP& dpmap) +{ + uint64_t minTime{std::numeric_limits<uint64_t>::max()}; + uint64_t maxTime{0}; + + for (auto did : dpmap) { + for (auto d : did.second) { + minTime = std::min(minTime, d.get_epoch_time()); + maxTime = std::max(maxTime, d.get_epoch_time()); + } + } + return static_cast<int>((maxTime - minTime) / 1000); +} + +/* +* Decides whether or not the dpmap should be sent to the output. +* +* @param maxSize if the dpmap size is above this size, +* then it should go to output +* @param maxDuration if the dpmap spans more than this duration, +* then it should go to output +* +* @returns a boolean stating if the dpmap should be output and a string +* describing why it should be output. +*/ +std::tuple<bool, std::string> needOutput(const DPMAP& dpmap, int maxSize, int maxDuration) +{ + std::string reason; + + if (dpmap.empty()) { + return {false, reason}; + } + + bool bigEnough{false}; + bool longEnough{false}; + bool complete{true}; // FIXME: should check here that we indeed have all our dataPoints + + if (maxSize && (computeSize(dpmap) > maxSize)) { + bigEnough = true; + reason += "[big enough]"; + } + + if (maxDuration) { + auto seconds = computeDuration(dpmap); + if (seconds > maxDuration) { + longEnough = true; + reason += fmt::format("[long enough ({} s)]", seconds); + } + } + + return {complete && (bigEnough || longEnough), reason}; +} + +o2::ccdb::CcdbObjectInfo addTFInfo(o2::ccdb::CcdbObjectInfo inf, + uint64_t t0, uint64_t t1) +{ + auto md = inf.getMetaData(); + md["tf range"] = fmt::format("{}-{}", t0, t1); + inf.setMetaData(md); + inf.setStartValidityTimestamp(t0); + //inf.setEndValidityTimestamp(t1); + return inf; +} + +/* +* Process the datapoints received. +* +* The datapoints are accumulated into one (MID) or two (MCH) DPMAPs (map from +* alias names to vector of DataPointValue) : one for HV values (MID and MCH) +* and one for LV values (MCH only). +* +* If the DPMAPs satisfy certain conditions (@see needOutput) they are sent to +* the output. +* +* @param aliases an array of one or two vectors of aliases (one for HV values, +* one for LV values) +* @param maxSize an array of one or two values for the +* maxsizes of the HV and LV values respectively +* @param maxDuration an array of +* one or two values for the max durations of the HV and LV values respectively +*/ +void processDataPoints(o2::framework::ProcessingContext& pc, + std::array<std::vector<std::string>, NOBJECTS> aliases, + std::array<int, NOBJECTS> maxSize, + std::array<int, NOBJECTS> maxDuration) +{ + + auto tfid = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + if (t0 < 0) { + t0 = tfid; + } + auto dps = pc.inputs().get<gsl::span<o2::dcs::DataPointCompositeObject>>("input"); + for (auto dp : dps) { + //FIXME: check we're not adding twice the same dp (i.e. check timestamp ?) + for (auto i = 0; i < NOBJECTS; i++) { + if (std::find(aliases[i].begin(), aliases[i].end(), dp.id.get_alias()) != aliases[i].end()) { + dataPoints[i][dp.id].emplace_back(dp.data); + } + } + } + for (auto i = 0; i < NOBJECTS; i++) { + auto [shouldOutput, reason] = needOutput(dataPoints[i], maxSize[i], maxDuration[i]); + if (shouldOutput) { + auto inf = addTFInfo(info[i], t0, tfid); + sendOutput(dataPoints[i], pc.outputs(), inf, reason); + t0 = tfid; + dataPoints[i].clear(); //FIXME: here the clear should be more clever and keep at least one value per dp ? + } + } +} + +std::vector<std::string> replaceDotByUnderscore(const std::vector<std::string>& aliases) +{ + std::vector<std::string> fixed; + for (const auto& a : aliases) { + fixed.emplace_back(o2::muon::replaceDotByUnderscore(a)); + } + return fixed; +} + +/* +* Creates the main processing function. +* +* @param ic InitContext which is used to get the options and set the end of +* stream callback +*/ +o2::framework::AlgorithmSpec::ProcessCallback createProcessFunction(o2::framework::InitContext& ic) +{ + auto& callbacks = ic.services().get<o2::framework::CallbackService>(); + callbacks.set(o2::framework::CallbackService::Id::EndOfStream, endOfStream); + + // the aliases arrays contain all the names of the MCH or MID data points + // we are interested to transit to the CCDB +#if defined(MUON_SUBSYSTEM_MCH) + std::array<std::vector<std::string>, NOBJECTS> aliases = { + replaceDotByUnderscore(o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::HV_V, + o2::mch::dcs::MeasurementType::HV_I})), + replaceDotByUnderscore(o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::LV_V_FEE_ANALOG, + o2::mch::dcs::MeasurementType::LV_V_FEE_DIGITAL, + o2::mch::dcs::MeasurementType::LV_V_SOLAR}))}; + std::array<int, 2> maxSize{ + ic.options().get<int>("hv-max-size"), + ic.options().get<int>("lv-max-size")}; + + std::array<int, 2> maxDuration{ + ic.options().get<int>("hv-max-duration"), + ic.options().get<int>("lv-max-duration")}; +#elif defined(MUON_SUBSYSTEM_MID) + std::array<std::vector<std::string>, NOBJECTS> aliases = { + replaceDotByUnderscore(o2::mid::dcs::aliases({o2::mid::dcs::MeasurementType::HV_V, + o2::mid::dcs::MeasurementType::HV_I}))}; + std::array<int, NOBJECTS> maxSize{ic.options().get<int>("hv-max-size")}; + std::array<int, NOBJECTS> maxDuration{ic.options().get<int>("hv-max-duration")}; +#endif + + for (auto i = 0; i < NOBJECTS; i++) { + dataPoints[i].clear(); + } + + return [aliases, maxSize, maxDuration](o2::framework::ProcessingContext& pc) { + processDataPoints(pc, aliases, maxSize, maxDuration); + }; +} + +/* Helper function to create a ConfigParamSpec option object. +* +* @param name is either 'size' or 'duration' +* @param value is the default value to be used (i.e. when the option is not +* specified on the command line) +* @param what is either 'hv' or 'lv' +* @param unit is the unit in which the values are given +*/ +o2::framework::ConfigParamSpec whenToSendOption(const char* name, int value, + const char* what, const char* unit) +{ + std::string uname(name); + o2::dcs::to_upper_case(uname); + + std::string description = fmt::format(R"(max {} calibration object {} (in {}). +When that {} is reached the object is shipped. Use 0 to disable this check.)", + uname, what, unit, what); + + return {fmt::format("{}-max-{}", name, what), + o2::framework::VariantType::Int, + value, + {description}}; +} + +} // namespace + +using o2::framework::AlgorithmSpec; +using o2::framework::ConfigContext; +using o2::framework::DataProcessorSpec; +using o2::framework::WorkflowSpec; + +/** +* DPL Workflow to process MCH or MID DCS data points. +* +* The expected input is a vector of DataPointCompositeObject containing +* only MCH (or only MID) data points. +* +* Those datapoints are accumulated into DPMAPs (map from alias names to +* vector of DataPointValue). +* +* The accumulated DPMAPs are sent to the output whenever : +* - they reach a given size (--xx-max-size option(s)) +* - they span a given duration (--xx-max-duration option(s)) +* - the workflow is ended +* +*/ +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + DataProcessorSpec dcsProcessor; + + AlgorithmSpec algo(createProcessFunction); + + dcsProcessor.name = fmt::format("{}-dcs-processor", o2::muon::subsysname()); + dcsProcessor.inputs = o2::framework::Inputs + { +#if defined(MUON_SUBSYSTEM_MCH) + { + "input", "DCS", "MCHDATAPOINTS" + } + }; +#elif defined(MUON_SUBSYSTEM_MID) + { + "input", "DCS", "MIDDATAPOINTS" + } + }; +#endif + dcsProcessor.outputs = calibrationOutputs; + dcsProcessor.algorithm = algo; + dcsProcessor.options = { +#if defined(MUON_SUBSYSTEM_MCH) + whenToSendOption("lv", 128, "size", "KB"), + whenToSendOption("lv", 8 * 3600, "duration", "seconds"), +#endif + whenToSendOption("hv", 128, "size", "KB"), + whenToSendOption("hv", 8 * 3600, "duration", "seconds")}; + + return {dcsProcessor}; +} diff --git a/Detectors/MUON/Common/src/mch-dcs-sim-workflow.cxx b/Detectors/MUON/Common/src/mch-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..ca341054cd322 --- /dev/null +++ b/Detectors/MUON/Common/src/mch-dcs-sim-workflow.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" +#include "MCHConditions/DCSNamer.h" +#include "aliasFixer.h" + +/** +* DPL workflow which generates fake random MCH DCS data points. +* +* Data points are generated for HV (currents and voltages) as well as +* for LV (DualSampa analog and digital voltages, and SOLAR voltages). +*/ +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + + for (auto a : o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::HV_V})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 1630, 1670}); + } + + for (auto a : o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::HV_I})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 0.1, 10}); + } + + for (auto a : o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::LV_V_FEE_DIGITAL})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 1.15, 1.25}); + } + + for (auto a : o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::LV_V_FEE_ANALOG})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 1.15, 1.25}); + } + + for (auto a : o2::mch::dcs::aliases({o2::mch::dcs::MeasurementType::LV_V_SOLAR})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 2.4, 2.6}); + } + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "MCH")); + return specs; +} diff --git a/Detectors/MUON/Common/src/mid-dcs-sim-workflow.cxx b/Detectors/MUON/Common/src/mid-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..38c7af7ad9bcc --- /dev/null +++ b/Detectors/MUON/Common/src/mid-dcs-sim-workflow.cxx @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" +#include "MIDConditions/DCSNamer.h" +#include "aliasFixer.h" + +/** +* DPL workflow which generates fake random MID DCS data points. +* +* Data points are generated for HV (currents and voltages). +*/ +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + + for (auto a : o2::mid::dcs::aliases({o2::mid::dcs::MeasurementType::HV_V})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 9200, 9800}); + } + + for (auto a : o2::mid::dcs::aliases({o2::mid::dcs::MeasurementType::HV_I})) { + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{o2::muon::replaceDotByUnderscore(a), 2, 10}); + } + + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "MID")); + return specs; +} diff --git a/Detectors/MUON/Common/src/subsysname.h b/Detectors/MUON/Common/src/subsysname.h new file mode 100644 index 0000000000000..4d0dc79dfc529 --- /dev/null +++ b/Detectors/MUON/Common/src/subsysname.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MUON_COMMON_SUBSYSNAME_H +#define O2_MUON_COMMON_SUBSYSNAME_H + +namespace o2::muon +{ +const char* subsysname() +{ +#if defined(MUON_SUBSYSTEM_MCH) && !defined(MUON_SUBSYSTEM_MID) + return "MCH"; +#elif defined(MUON_SUBSYSTEM_MID) && !defined(MUON_SUBSYSTEM_MCH) + return "MID"; +#else +#error "Must define one and only one of MUON_SUBSYSTEM_MCH or MUON_SUBSYSTEM_MID" +#endif +} +} // namespace o2::muon + +#endif diff --git a/Detectors/MUON/MCH/Base/CMakeLists.txt b/Detectors/MUON/MCH/Base/CMakeLists.txt index c586850ba1c9f..95497aee43905 100644 --- a/Detectors/MUON/MCH/Base/CMakeLists.txt +++ b/Detectors/MUON/MCH/Base/CMakeLists.txt @@ -1,20 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHBase SOURCES - src/ClusterBlock.cxx - src/Digit.cxx src/PreCluster.cxx src/TrackBlock.cxx - PUBLIC_LINK_LIBRARIES ROOT::Core FairRoot::Base FairMQ::FairMQ ms_gsl::ms_gsl) + PUBLIC_LINK_LIBRARIES O2::DataFormatsMCH) o2_target_root_dictionary(MCHBase - HEADERS include/MCHBase/Digit.h) + HEADERS include/MCHBase/DecoderError.h) diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/ClusterBlock.h b/Detectors/MUON/MCH/Base/include/MCHBase/ClusterBlock.h deleted file mode 100644 index f1459cef35e13..0000000000000 --- a/Detectors/MUON/MCH/Base/include/MCHBase/ClusterBlock.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterBlock.h -/// \brief Definition of the MCH cluster minimal structure -/// -/// \author Philippe Pillot, Subatech - -#ifndef ALICEO2_MCH_CLUSTERBLOCK_H_ -#define ALICEO2_MCH_CLUSTERBLOCK_H_ - -#include <iostream> - -namespace o2 -{ -namespace mch -{ - -/// cluster minimal structure -struct ClusterStruct { - float x; ///< cluster position along x - float y; ///< cluster position along y - float z; ///< cluster position along z - float ex; ///< cluster resolution along x - float ey; ///< cluster resolution along y - uint32_t uid; ///< cluster unique ID - uint32_t firstDigit; ///< index of first associated digit in the ordered vector of digits - uint32_t nDigits; ///< number of digits attached to this cluster - - /// Return the chamber ID (0..), part of the unique ID - int getChamberId() const { return getChamberId(uid); } - /// Return the detection element ID, part of the unique ID - int getDEId() const { return getDEId(uid); } - /// Return the index of this cluster (0..), part of the unique ID - int getClusterIndex() const { return getClusterIndex(uid); } - - /// Return the chamber ID of the cluster, part of its unique ID - static int getChamberId(uint32_t clusterId) { return (clusterId & 0xF0000000) >> 28; } - /// Return the detection element ID of the cluster, part of its unique ID - static int getDEId(uint32_t clusterId) { return (clusterId & 0x0FFE0000) >> 17; } - /// Return the index of the cluster, part of its unique ID - static int getClusterIndex(uint32_t clusterId) { return (clusterId & 0x0001FFFF); } - - /// Build the unique ID of the cluster from the chamber ID, detection element ID and cluster index - static uint32_t buildUniqueId(int chamberId, int deId, int clusterIndex) - { - return (((chamberId & 0xF) << 28) | ((deId & 0x7FF) << 17) | (clusterIndex & 0x1FFFF)); - } -}; - -std::ostream& operator<<(std::ostream& stream, const ClusterStruct& cluster); - -} // namespace mch -} // namespace o2 - -#endif // ALICEO2_MCH_CLUSTERBLOCK_H_ diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/DecoderError.h b/Detectors/MUON/MCH/Base/include/MCHBase/DecoderError.h new file mode 100644 index 0000000000000..eae663d46bccb --- /dev/null +++ b/Detectors/MUON/MCH/Base/include/MCHBase/DecoderError.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** @file DecoderError.h + * C++ definition of a decoder error + * @author Andrea Ferrero, CEE-Saclay + */ + +#ifndef ALICEO2_MCH_BASE_DECODERERROR_H_ +#define ALICEO2_MCH_BASE_DECODERERROR_H_ + +#include "Rtypes.h" + +namespace o2 +{ +namespace mch +{ + +// \class DecoderError +/// \brief MCH decoder error implementation +class DecoderError +{ + public: + DecoderError() = default; + + DecoderError(int solarid, int dsid, int chip, uint32_t error) : mSolarID(solarid), mChipID(dsid * 2 + chip), mError(error) {} + ~DecoderError() = default; + + uint16_t getSolarID() const { return mSolarID; } + uint8_t getDsID() const { return mChipID / 2; } + uint8_t getChip() const { return mChipID % 2; } + + uint32_t getError() const { return mError; } + + private: + uint16_t mSolarID; + uint8_t mChipID; + uint32_t mError; + + ClassDefNV(DecoderError, 1); +}; //class DecoderError + +} //namespace mch +} //namespace o2 +#endif // ALICEO2_MCH_BASE_DECODERERROR_H_ diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/Digit.h b/Detectors/MUON/MCH/Base/include/MCHBase/Digit.h deleted file mode 100644 index 4029a28a06a37..0000000000000 --- a/Detectors/MUON/MCH/Base/include/MCHBase/Digit.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/** @file Digit.h - * C++ simple Muon MCH digit. - * @author Michael Winn - */ - -#ifndef ALICEO2_MCH_BASE_DIGIT_H_ -#define ALICEO2_MCH_BASE_DIGIT_H_ - -#include "Rtypes.h" - -namespace o2 -{ -namespace mch -{ - -// \class Digit -/// \brief MCH digit implementation -class Digit -{ - public: - struct Time { - union { - // default value - uint64_t time = 0x0000000000000000; - struct { /// - uint32_t sampaTime : 10; /// bit 0 to 9: sampa time - uint32_t bunchCrossing : 20; /// bit 10 to 29: bunch crossing counter - uint32_t reserved : 2; /// bit 30 to 31: reserved - uint32_t orbit; /// bit 32 to 63: orbit - }; /// - }; - uint64_t getBXTime() - { - return (bunchCrossing + (sampaTime * 4)); - } - }; - - Digit() = default; - - Digit(int detid, int pad, unsigned long adc, Time time, uint16_t nSamples = 1); - ~Digit() = default; - - bool operator==(const Digit&) const; - - Time getTime() const { return mTime; } - - uint16_t nofSamples() const { return mNofSamples; } - void setNofSamples(uint16_t n) { mNofSamples = n; } - - int getDetID() const { return mDetID; } - - int getPadID() const { return mPadID; } - void setPadID(int padID) { mPadID = padID; } - - unsigned long getADC() const { return mADC; } - void setADC(unsigned long adc) { mADC = adc; } - - private: - Time mTime; - uint16_t mNofSamples; /// number of samples in the signal - int mDetID; - int mPadID; /// PadIndex to which the digit corresponds to - unsigned long mADC; /// Amplitude of signal - - ClassDefNV(Digit, 2); -}; //class Digit - -} //namespace mch -} //namespace o2 -#endif // ALICEO2_MCH_DIGIT_H_ diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h b/Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h index 59d1adc045a04..46c83e3c570b9 100644 --- a/Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h +++ b/Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ #include <gsl/span> -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" namespace o2 { @@ -29,11 +30,11 @@ namespace mch /// precluster minimal structure struct PreCluster { - uint16_t firstDigit; ///< index of first associated digit in the ordered vector of digits - uint16_t nDigits; ///< number of digits attached to this precluster + uint32_t firstDigit; ///< index of first associated digit in the ordered vector of digits + uint32_t nDigits; ///< number of digits attached to this precluster /// return the index of last associated digit in the ordered vector of digits - uint16_t lastDigit() const { return firstDigit + nDigits - 1; } + uint32_t lastDigit() const { return firstDigit + nDigits - 1; } void print(std::ostream& stream, gsl::span<const Digit> digits) const; }; diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/TrackBlock.h b/Detectors/MUON/MCH/Base/include/MCHBase/TrackBlock.h index 2b9b609ca3237..186d70997b33f 100644 --- a/Detectors/MUON/MCH/Base/include/MCHBase/TrackBlock.h +++ b/Detectors/MUON/MCH/Base/include/MCHBase/TrackBlock.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Base/src/ClusterBlock.cxx b/Detectors/MUON/MCH/Base/src/ClusterBlock.cxx deleted file mode 100644 index 45e51556a7d6a..0000000000000 --- a/Detectors/MUON/MCH/Base/src/ClusterBlock.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterBlock.cxx -/// \brief Implementation of the MCH cluster minimal structure -/// -/// \author Philippe Pillot, Subatech - -#include "MCHBase/ClusterBlock.h" - -namespace o2 -{ -namespace mch -{ - -//_________________________________________________________________________ -std::ostream& operator<<(std::ostream& stream, const ClusterStruct& cluster) -{ - auto oldflags = stream.flags(); - stream << "{x = " << cluster.x << ", y = " << cluster.y << ", z = " << cluster.z << ", ex = " << cluster.ex - << ", ey = " << cluster.ey << ", uid = " << cluster.uid << "}"; - stream.flags(oldflags); - return stream; -} - -} // namespace mch -} // namespace o2 diff --git a/Detectors/MUON/MCH/Base/src/Digit.cxx b/Detectors/MUON/MCH/Base/src/Digit.cxx deleted file mode 100644 index 5bb21f766c900..0000000000000 --- a/Detectors/MUON/MCH/Base/src/Digit.cxx +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "MCHBase/Digit.h" -#include <cmath> - -namespace o2::mch -{ - -bool closeEnough(double x, double y, double eps = 1E-6) -{ - return std::fabs(x - y) <= eps * std::max(1.0, std::max(std::fabs(x), std::fabs(y))); -} - -Digit::Digit(int detid, int pad, unsigned long adc, Time time, uint16_t nSamples) - : mDetID(detid), mPadID(pad), mADC(adc), mTime(time), mNofSamples(nSamples) -{ -} - -bool Digit::operator==(const Digit& other) const -{ - return mDetID == other.mDetID && - mPadID == other.mPadID && - mADC == other.mADC && - mTime.time == other.mTime.time && - mNofSamples == other.mNofSamples; -} - -} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h b/Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h index b2afadd958883..ee0562a8c88f1 100644 --- a/Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h +++ b/Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,4 @@ #pragma link C++ namespace o2; #pragma link C++ namespace o2::mch; -#pragma link C++ class o2::mch::Digit + ; -#pragma link C++ class std::vector < o2::mch::Digit> + ; - #endif diff --git a/Detectors/MUON/MCH/Base/src/PreCluster.cxx b/Detectors/MUON/MCH/Base/src/PreCluster.cxx index 4f976ce952df0..58381f66ccade 100644 --- a/Detectors/MUON/MCH/Base/src/PreCluster.cxx +++ b/Detectors/MUON/MCH/Base/src/PreCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Base/src/TrackBlock.cxx b/Detectors/MUON/MCH/Base/src/TrackBlock.cxx index b0cd0806925ab..2b5a7d0440611 100644 --- a/Detectors/MUON/MCH/Base/src/TrackBlock.cxx +++ b/Detectors/MUON/MCH/Base/src/TrackBlock.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/CMakeLists.txt b/Detectors/MUON/MCH/CMakeLists.txt index a4cf37dfb10d3..06d61ef83cf2d 100644 --- a/Detectors/MUON/MCH/CMakeLists.txt +++ b/Detectors/MUON/MCH/CMakeLists.txt @@ -1,19 +1,26 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Base) add_subdirectory(Contour) add_subdirectory(Mapping) +add_subdirectory(TimeClustering) add_subdirectory(PreClustering) +add_subdirectory(Geometry) add_subdirectory(Clustering) add_subdirectory(Simulation) add_subdirectory(Tracking) add_subdirectory(Raw) +add_subdirectory(CTF) add_subdirectory(Workflow) +add_subdirectory(Conditions) +add_subdirectory(Calibration) +add_subdirectory(DevIO) diff --git a/Detectors/MUON/MCH/CTF/CMakeLists.txt b/Detectors/MUON/MCH/CTF/CMakeLists.txt new file mode 100644 index 0000000000000..9addbd36bd09a --- /dev/null +++ b/Detectors/MUON/MCH/CTF/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MCHCTF + SOURCES src/CTFCoder.cxx src/CTFHelper.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsMCH + O2::MCHBase + O2::DetectorsBase + O2::CommonDataFormat + O2::DetectorsCommonDataFormats + O2::rANS + Microsoft.GSL::GSL) diff --git a/Detectors/MUON/MCH/CTF/README.md b/Detectors/MUON/MCH/CTF/README.md new file mode 100644 index 0000000000000..42c5977b291f7 --- /dev/null +++ b/Detectors/MUON/MCH/CTF/README.md @@ -0,0 +1,78 @@ +<!-- doxy +\page refDetectorsMUONMCHCTF MCH CTF encoding library +/doxy --> + +# MCH CTF + +This directory contains the classes to handle entropy encoding and decoding of +MCH digits (and their associated ROFRecord). + +# Circular test + +To idea of this test is to check that digits data stays unaltered when they go +through the encoding/decoding processing. + +``` +circular-test.sh [NROFPERTF] [NTF] [OCC] [SEED] +``` + +The [circular-test.sh](./test/circular-test.sh) script performs for a given set of +{ number of timeframes, number of rofs per timeframe, occupancy, seed }, a +variation of the operations described below. + +## Generate random digits and write them (debug binary format) + +``` +o2-mch-digits-random-generator-workflow -b + --nof-rofs-per-tf 3 + --max-nof-tfs 5 + --occupancy 0.01 + --seed 1 +| o2-mch-digits-writer-workflow -b + --binary-file-format 1 + --outfile digits_ref_rof_3_tf_5_occ_0.01_seed_1.data +``` + +Note the `--seed` option that _must_ be non-zero if you want to get +reproducible results when running several times. + + +## Read those digits and encode them in a CTF + +``` +o2-mch-digits-file-reader-workflow -b + --infile digits_ref.data +| o2-mch-entropy-encoder-workflow -b +| o2-ctf-writer-workflow -b + --onlyDet MCH --no-grp +``` + +## Read back the CTF, decode the digits, write them + +``` +o2-ctf-reader-workflow -b + --ctf-input o2_ctf_run00000000_orbit0000000000_tf0000000000.root +| o2-mch-digits-writer-workflow -b + --binary-file-format 1 + --outfile digits.data +``` + +## Dump the written digits in text form + +``` +o2-mch-digits-file-reader-workflow -b + --infile digits_ref.data +| o2-mch-digits-writer-workflow -b + --no-file + --txt + --print-digits +``` + +## Compare digits before after ctf encoding/decoding + +``` +ls -al digits.*data +shasum -a 256 digits*.data +``` + + diff --git a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h new file mode 100644 index 0000000000000..f732ca96c1dca --- /dev/null +++ b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h @@ -0,0 +1,166 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of MCH digit data + +#ifndef O2_MCH_CTFCODER_H +#define O2_MCH_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsMCH/CTF.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "MCHCTF/CTFHelper.h" +#include "rANS/rans.h" + +class TTree; + +namespace o2 +{ +namespace mch +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::MCH) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, const gsl::span<const Digit>& digData); + + /// entropy decode data from buffer with CTF + template <typename VROF, typename VCOL> + void decode(const CTF::base& ec, VROF& rofVec, VCOL& digVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofVec, std::vector<Digit>& digVec); +}; + +/// entropy-encode clusters to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, const gsl::span<const Digit>& digData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncROF + MD::EENCODE, // BLC_orbitIncROF + MD::EENCODE, // BLC_nDigitsROF + MD::EENCODE, // BLC_tfTime + MD::EENCODE, // BLC_nSamples + MD::EENCODE, // BLC_isSaturated + MD::EENCODE, // BLC_detID + MD::EENCODE, // BLC_padID + MD::EENCODE // BLC_ADC + }; + CTFHelper helper(rofData, digData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODEMCH(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODEMCH(helper.begin_bcIncROF(), helper.end_bcIncROF(), CTF::BLC_bcIncROF, 0); + ENCODEMCH(helper.begin_orbitIncROF(), helper.end_orbitIncROF(), CTF::BLC_orbitIncROF, 0); + ENCODEMCH(helper.begin_nDigitsROF(), helper.end_nDigitsROF(), CTF::BLC_nDigitsROF, 0); + + ENCODEMCH(helper.begin_tfTime(), helper.end_tfTime(), CTF::BLC_tfTime, 0); + ENCODEMCH(helper.begin_nSamples(), helper.end_nSamples(), CTF::BLC_nSamples, 0); + ENCODEMCH(helper.begin_isSaturated(), helper.end_isSaturated(), CTF::BLC_isSaturated, 0); + ENCODEMCH(helper.begin_detID(), helper.end_detID(), CTF::BLC_detID, 0); + ENCODEMCH(helper.begin_padID(), helper.end_padID(), CTF::BLC_padID, 0); + ENCODEMCH(helper.begin_ADC() , helper.end_ADC(), CTF::BLC_ADC, 0); + // clang-format on + // CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded clusters to standard compact clusters +template <typename VROF, typename VCOL> +void CTFCoder::decode(const CTF::base& ec, VROF& rofVec, VCOL& digVec) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + + std::vector<uint16_t> bcInc, nSamples; + std::vector<uint32_t> orbitInc, ADC, nDigits; + std::vector<int32_t> tfTime; + std::vector<int16_t> detID, padID; + std::vector<uint8_t> isSaturated; + +#define DECODEMCH(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODEMCH(bcInc, CTF::BLC_bcIncROF); + DECODEMCH(orbitInc, CTF::BLC_orbitIncROF); + DECODEMCH(nDigits, CTF::BLC_nDigitsROF); + + DECODEMCH(tfTime, CTF::BLC_tfTime); + DECODEMCH(nSamples, CTF::BLC_nSamples); + DECODEMCH(isSaturated, CTF::BLC_isSaturated); + DECODEMCH(detID, CTF::BLC_detID); + DECODEMCH(padID, CTF::BLC_padID); + DECODEMCH(ADC, CTF::BLC_ADC); + // clang-format on + // + rofVec.clear(); + digVec.clear(); + rofVec.reserve(header.nROFs); + digVec.reserve(header.nDigits); + + uint32_t firstEntry = 0, rofCount = 0, digCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + + for (uint32_t irof = 0; irof < header.nROFs; irof++) { + // restore ROFRecord + if (orbitInc[irof]) { // non-0 increment => new orbit + ir.bc = bcInc[irof]; // bcInc has absolute meaning + ir.orbit += orbitInc[irof]; + } else { + ir.bc += bcInc[irof]; + } + + firstEntry = digVec.size(); + for (auto ic = 0; ic < nDigits[irof]; ic++) { + digVec.emplace_back(Digit{detID[digCount], padID[digCount], ADC[digCount], tfTime[digCount], nSamples[digCount]}); + digVec.back().setSaturated(isSaturated[digCount]); + digCount++; + } + rofVec.emplace_back(ROFRecord{ir, int(firstEntry), static_cast<int>(nDigits[irof])}); + } + assert(rofVec.size() == header.nROFs); + assert(digCount == header.nDigits); +} + +} // namespace mch +} // namespace o2 + +#endif // O2_MCH_CTFCODER_H diff --git a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFHelper.h b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFHelper.h new file mode 100644 index 0000000000000..8c1aa99a3eb6a --- /dev/null +++ b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFHelper.h @@ -0,0 +1,219 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for MCH CTF creation + +#ifndef O2_MCH_CTF_HELPER_H +#define O2_MCH_CTF_HELPER_H + +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/CTF.h" +#include <gsl/span> + +namespace o2 +{ +namespace mch +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const o2::mch::ROFRecord>& rofData, const gsl::span<const o2::mch::Digit>& digData) + : mROFData(rofData), mDigData(digData) {} + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mROFData.size()), uint32_t(mDigData.size()), 0, 0}; + if (mROFData.size()) { + h.firstOrbit = mROFData[0].getBCData().orbit; + h.firstBC = mROFData[0].getBCData().bc; + } + return h; + } + + size_t getSize() const { return mROFData.size() * sizeof(o2::mch::ROFRecord) + mDigData.size() * sizeof(o2::mch::Digit); } + + //>>> =========================== ITERATORS ======================================== + + template <typename I, typename D, typename T, int M = 1> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncROF : public _Iter<Iter_bcIncROF, ROFRecord, uint16_t> + { + public: + using _Iter<Iter_bcIncROF, ROFRecord, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].getBCData().orbit == mData[mIndex - 1].getBCData().orbit) { + return mData[mIndex].getBCData().bc - mData[mIndex - 1].getBCData().bc; + } else { + return mData[mIndex].getBCData().bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncROF : public _Iter<Iter_orbitIncROF, ROFRecord, uint32_t> + { + public: + using _Iter<Iter_orbitIncROF, ROFRecord, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].getBCData().orbit - mData[mIndex - 1].getBCData().orbit : 0; } + }; + + //_______________________________________________ + // Number of entries in the ROF + class Iter_nDigitsROF : public _Iter<Iter_nDigitsROF, ROFRecord, uint32_t> + { + public: + using _Iter<Iter_nDigitsROF, ROFRecord, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNEntries(); } + }; + + //_______________________________________________ + class Iter_tfTime : public _Iter<Iter_tfTime, Digit, int32_t> + { + public: + using _Iter<Iter_tfTime, Digit, int32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getTime(); } + }; + + //_______________________________________________ + class Iter_nSamples : public _Iter<Iter_nSamples, Digit, uint16_t> + { + public: + using _Iter<Iter_nSamples, Digit, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNofSamples(); } + }; + + //_______________________________________________ + class Iter_isSaturated : public _Iter<Iter_isSaturated, Digit, uint8_t> + { + public: + using _Iter<Iter_isSaturated, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].isSaturated(); } + }; + + //_______________________________________________ + class Iter_detID : public _Iter<Iter_detID, Digit, int16_t> + { + public: + using _Iter<Iter_detID, Digit, int16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getDetID(); } + }; + + //_______________________________________________ + class Iter_padID : public _Iter<Iter_padID, Digit, int16_t> + { + public: + using _Iter<Iter_padID, Digit, int16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPadID(); } + }; + + //_______________________________________________ + class Iter_ADC : public _Iter<Iter_ADC, Digit, uint32_t> + { + public: + using _Iter<Iter_ADC, Digit, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getADC(); } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncROF begin_bcIncROF() const { return Iter_bcIncROF(mROFData, false); } + Iter_bcIncROF end_bcIncROF() const { return Iter_bcIncROF(mROFData, true); } + + Iter_orbitIncROF begin_orbitIncROF() const { return Iter_orbitIncROF(mROFData, false); } + Iter_orbitIncROF end_orbitIncROF() const { return Iter_orbitIncROF(mROFData, true); } + + Iter_nDigitsROF begin_nDigitsROF() const { return Iter_nDigitsROF(mROFData, false); } + Iter_nDigitsROF end_nDigitsROF() const { return Iter_nDigitsROF(mROFData, true); } + + Iter_tfTime begin_tfTime() const { return Iter_tfTime(mDigData, false); } + Iter_tfTime end_tfTime() const { return Iter_tfTime(mDigData, true); } + + Iter_nSamples begin_nSamples() const { return Iter_nSamples(mDigData, false); } + Iter_nSamples end_nSamples() const { return Iter_nSamples(mDigData, true); } + + Iter_isSaturated begin_isSaturated() const { return Iter_isSaturated(mDigData, false); } + Iter_isSaturated end_isSaturated() const { return Iter_isSaturated(mDigData, true); } + + Iter_detID begin_detID() const { return Iter_detID(mDigData, false); } + Iter_detID end_detID() const { return Iter_detID(mDigData, true); } + + Iter_padID begin_padID() const { return Iter_padID(mDigData, false); } + Iter_padID end_padID() const { return Iter_padID(mDigData, true); } + + Iter_ADC begin_ADC() const { return Iter_ADC(mDigData, false); } + Iter_ADC end_ADC() const { return Iter_ADC(mDigData, true); } + + private: + const gsl::span<const o2::mch::ROFRecord> mROFData; + const gsl::span<const o2::mch::Digit> mDigData; +}; + +} // namespace mch +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/CTF/src/CTFCoder.cxx b/Detectors/MUON/MCH/CTF/src/CTFCoder.cxx new file mode 100644 index 0000000000000..4e01dc3c49f77 --- /dev/null +++ b/Detectors/MUON/MCH/CTF/src/CTFCoder.cxx @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of MCH data + +#include "MCHCTF/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::mch; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofVec, std::vector<Digit>& digVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, rofVec, digVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc, nDigits, nSamples; + uint32_t orbitInc, ADC; + int32_t tfTime; + int16_t detID, padID; + uint8_t isSaturated; +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncROF); + MAKECODER(orbitInc, CTF::BLC_orbitIncROF); + MAKECODER(nDigits, CTF::BLC_nDigitsROF); + MAKECODER(tfTime, CTF::BLC_tfTime); + MAKECODER(nSamples, CTF::BLC_nSamples); + MAKECODER(isSaturated, CTF::BLC_isSaturated); + MAKECODER(detID, CTF::BLC_detID); + MAKECODER(padID, CTF::BLC_padID); + MAKECODER(ADC, CTF::BLC_ADC); + // clang-format on +} diff --git a/Detectors/MUON/MCH/CTF/src/CTFHelper.cxx b/Detectors/MUON/MCH/CTF/src/CTFHelper.cxx new file mode 100644 index 0000000000000..5d1f58cc5623a --- /dev/null +++ b/Detectors/MUON/MCH/CTF/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for MCH CTF creation + +#include "MCHCTF/CTFHelper.h" diff --git a/Detectors/MUON/MCH/CTF/test/circular-test.sh b/Detectors/MUON/MCH/CTF/test/circular-test.sh new file mode 100644 index 0000000000000..57fc974b49ff3 --- /dev/null +++ b/Detectors/MUON/MCH/CTF/test/circular-test.sh @@ -0,0 +1,221 @@ +#!/bin/sh + +get_cmd_write_digits() { + if [ $# -eq 0 ]; then + echo "must at least specify the destination of the dump" + return + fi + local dest=$1 + local output=$2 + local format=${3:-missing} + local opt="" + local cmd="" + + if [ "$dest" = "binary" ]; then + opt="--binary-file-format $format" + elif [ "$dest" = "text" ]; then + opt="--txt" + elif [ "$dest" = "screen" ]; then + opt="--txt" + else + echo "dest=$dest is not one of {binary,text,screen}" + return + fi + + cmd="o2-mch-digits-writer-workflow -b " + cmd+=" $opt" + if [ $output ]; then + cmd+=" --outfile $output" + else + cmd+=" --no-file" + fi + echo $cmd +} + +run_workflow() { + local cmd=$1 + local msg=$2 + local verbose=$3 + + if [ ! -z $VERBOSE ]; then + verbose="verbose" + fi + + cmd+=" | o2-dpl-run --run -b" + + echo "#############" + echo "# $2" + echo "$cmd" + echo "#############" + + if [ "$verbose" = "verbose" ]; then + eval $cmd + else + eval $cmd &>/dev/null + fi +} + +generate_digits() { + local NROFPERTOF=${1:-1} + local NTF=${2:-1} + local OCC=${3:-0.0001} + local SEED=${4:-1} + local digitFile=${5:-UNKNOWN} + local format=${6:-3} + local cmd="" + + cmd="o2-mch-digits-random-generator-workflow -b " + cmd+="--nof-rofs-per-tf $NROFPERTF " + cmd+="--max-nof-tfs $NTF " + cmd+="--occupancy $OCC " + cmd+="--seed $SEED " + cmd+="| " + cmd+=$(get_cmd_write_digits binary $digitFile $format) + + run_workflow $cmd "Generate random digits and save them" verbose +} + +dump_digits() { + if [ $# -eq 0 ]; then + echo "must specify the name of the digit file to dump" + return + fi + local digitFile=${1:-digits.dump} + local dest=${2:-invalid} + local output=$3 + local format=$4 + local cmd="" + local verbose="" + + if [ "$dest" = "screen" ]; then + verbose=verbose + fi + + cmd="o2-mch-digits-file-reader-workflow -b --infile $digitFile | " + cmd+=$(get_cmd_write_digits $dest $output $format) + + run_workflow $cmd "Dump digits" $verbose +} + +create_ctf() { + if [ $# -eq 0 ]; then + echo "must specify the name of the digit file to compress" + return + fi + local digitsFile=$1 + local outputType=${2:-ctf} + local cmd="" + + cmd="o2-mch-digits-file-reader-workflow --infile ${digitsFile} -b | " + cmd+="o2-mch-entropy-encoder-workflow -b |" + cmd+="o2-ctf-writer-workflow --onlyDet MCH --no-grp --output-type $outputType -b" + + run_workflow $cmd "Read digits and create $outputType" +} + +get_ctfs() { + if [ $# -eq 0 ]; then + echo "must specify the number of tfs to look for" + return + fi + local ntf=$1 + local ctfs="" + local run=0 + local orbit=0 + + for tf in $(seq 0 $(($ntf - 1))); do + ctfs+=$(printf "o2_ctf_run%08d_orbit%010d_tf%010d.root " $run $orbit $tf) + done + ctfs=$(echo $ctfs | sed 's/.$//') # remove trailing coma + + echo "$ctfs" +} + +read_ctf() { + if [ $# -lt 2 ]; then + echo "must specify the CTF(s) to read and output digit filename" + return + fi + local ctfs=$1 + local ctfdigitfile=$2 + local format=$3 + local cmd="" + + cmd="o2-ctf-reader-workflow --onlyDet MCH --ctf-input ${ctfs} -b | " + cmd+=$(get_cmd_write_digits binary $ctfdigitfile $format) + + run_workflow $cmd "Read CTF and write digits" +} + +NROFPERTF=${1:-128} +NTF=${2:-1} +OCC=${3:-0.1} +SEED=${4:-1} +BINARY_FILE_FORMAT=${5:-3} +textDump=0 + +COUNT=$(( $NROFPERTF * $NTF * $OCC * 1064008 )) +COUNT=$(echo $COUNT | awk '{print int($0)}') + +if [ $COUNT -lt 100000 ]; then + # activate text dump if we don't have too many digits + textDump=1 +fi + +refdigits=digits_ref_rof_${NROFPERTF}_tf_${NTF}_occ_${OCC}_seed_${SEED} + +# Generate digits +generate_digits $NROFPERTF $NTF $OCC $SEED $refdigits.orig.data $BINARY_FILE_FORMAT + +# Dump the digits to verify sample-sink couple +dump_digits ${refdigits}.orig.data binary ${refdigits}.check.data $BINARY_FILE_FORMAT + +echo '# Remove dictionary data if any' +rm -f ctf_dictionary.root + +# read Digits and create CTF(s) files +create_ctf ${refdigits}.orig.data + +ctfs=$(get_ctfs $NTF) + +# read CTF and write digits +read_ctf $ctfs ${refdigits}.ctf.data $BINARY_FILE_FORMAT + +# # Dump the digits on screen' +# dump_digits ${refdigits}.ctf.data screen + +mkdir nodict && pushd nodict + +# Read digits and encode them, but only write out the frequencies dictionary +create_ctf ../${refdigits}.orig.data dict + +# Read digits and encode them in a CTF with external dict +create_ctf ../${refdigits}.orig.data + +ctfs=$(get_ctfs $NTF) + +# read CTF and write digits +read_ctf $ctfs ${refdigits}.nodict.ctf.data $BINARY_FILE_FORMAT + +popd + +if [ $textDump -eq 1 ]; then +# Make a text version of all digit files + for d in $(find . -name "digits*"); + do + dump_digits $d text $d.txt + done +fi + +echo '# Compare digits before after ctf encoding/decoding' +if [ $textDump -eq 1 ]; then + echo '# Text versions' + find . -name "digits*.txt" -exec shasum -a 256 {} \; | sort +fi +echo '# Binary versions' +find . -name "digits*.data" -exec shasum -a 256 {} \; | sort + +echo '# Sizes' +find . -name '*ctf_*' -exec ls -alh {} \; +find . -name 'digits*.data' -exec ls -alh {} \; + diff --git a/Detectors/MUON/MCH/Calibration/CMakeLists.txt b/Detectors/MUON/MCH/Calibration/CMakeLists.txt new file mode 100644 index 0000000000000..f62f0abc2838b --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MCHCalibration + SOURCES + src/PedestalDigit.cxx + src/PedestalProcessor.cxx + src/PedestalCalibrator.cxx + PUBLIC_LINK_LIBRARIES Microsoft.GSL::GSL O2::DetectorsCalibration O2::CCDB O2::MCHBase O2::MCHRawDecoder O2::DataFormatsMCH) + +o2_target_root_dictionary(MCHCalibration + HEADERS include/MCHCalibration/PedestalDigit.h include/MCHCalibration/PedestalProcessor.h include/MCHCalibration/PedestalCalibrator.h) + +o2_add_executable(pedestal-decoding-workflow + SOURCES src/pedestal-decoding-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES Boost::program_options O2::Framework O2::DPLUtils O2::MCHCalibration) + +o2_add_executable(mch-pedestal-calib-workflow + COMPONENT_NAME calibration + SOURCES src/pedestal-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::MCHCalibration O2::DetectorsCalibration) + + diff --git a/Detectors/MUON/MCH/Calibration/include/MCHCalibration/MCHChannelCalibrator.h b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/MCHChannelCalibrator.h new file mode 100644 index 0000000000000..ad1e17862179d --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/MCHChannelCalibrator.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MCHChannelCalibrator.h +/// \brief Transitional compatibility header +/// +/// \author Andrea Ferrero + +#ifndef ALICEO2_MCH_CALIBRATION_CHANNELCALIBRATOR_H +#define ALICEO2_MCH_CALIBRATION_CHANNELCALIBRATOR_H + +#include "MCHCalibration/PedestalCalibrator.h" + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +using MCHChannelCalibrator = PedestalCalibrator; + +} // end namespace calibration +} // end namespace mch +} // end namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalCalibrator.h b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalCalibrator.h new file mode 100644 index 0000000000000..eaf71555a6d4c --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalCalibrator.h @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file PedestalCalibrator.h +/// \brief Implementation of the MCH calibrator using pedestal data +/// +/// \author Andrea Ferrero, CEA-Saclay + +#ifndef MCH_CHANNEL_CALIBRATOR_H_ +#define MCH_CHANNEL_CALIBRATOR_H_ + +#include "DataFormatsMCH/DsChannelGroup.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "CCDB/CcdbObjectInfo.h" +#include "MCHCalibration/PedestalDigit.h" +#include "MCHCalibration/PedestalProcessor.h" + +#include <array> + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +/// Implementation of the processor that computes the mean and RMS of the channel-by-channel pedestals +/// from the data corresponding to a time slot. +/// In the MCH case the time slot has by default an infinite duration, therefore there is only a single +/// set of pedestal values for each calibration run. +class PedestalData +{ + using Slot = o2::calibration::TimeSlot<o2::mch::calibration::PedestalData>; + + public: + PedestalData() = default; + ~PedestalData() = default; + + void print() const; + + /// function to update the pedestal values from the data of a single TimeFrame + void fill(const gsl::span<const o2::mch::calibration::PedestalDigit> data); + void merge(const PedestalData* prev); + + /// function to access the table of computed pedestals for each readout channel + const PedestalProcessor::PedestalsMap& getPedestals() { return mPedestalProcessor.getPedestals(); } + + private: + /// helper class that performs the actual computation of the pedestals from the input digits + PedestalProcessor mPedestalProcessor; + + ClassDefNV(PedestalData, 1); +}; + +/// Implementation of a calibrator object that checks the computed mean and RMS of the pedestals and compares the +/// values with user-supplied thresholds. +/// The channels whose values exceed one of the thresholds are considered bad/noisy and they are stored into a +/// "bad channels" list that is sent to the CDDB populator. +class PedestalCalibrator final : public o2::calibration::TimeSlotCalibration<o2::mch::calibration::PedestalDigit, o2::mch::calibration::PedestalData> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<o2::mch::calibration::PedestalData>; + using BadChannelsVector = o2::mch::DsChannelGroup; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + + public: + struct ChannelPedestal { + ChannelPedestal() = default; + ChannelPedestal(o2::mch::DsChannelId chid, double mean, double rms) : mDsChId(chid), mPedMean(mean), mPedRms(rms) {} + + o2::mch::DsChannelId mDsChId; + double mPedMean{0}; + double mPedRms{0}; + }; + using PedestalsVector = std::vector<ChannelPedestal>; + + PedestalCalibrator(float pedThreshold, float noiseThreshold) : mPedestalThreshold(pedThreshold), mNoiseThreshold(noiseThreshold), mTFStart(0xffffffffffffffff){}; + + ~PedestalCalibrator() final = default; + + bool hasEnoughData(const Slot& slot) const final; + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + void endOfStream(); + + const BadChannelsVector& getBadChannelsVector() const { return mBadChannelsVector; } + const CcdbObjectInfo& getBadChannelsInfo() const { return mBadChannelsInfo; } + CcdbObjectInfo& getBadChannelsInfo() { return mBadChannelsInfo; } + + const PedestalsVector& getPedestalsVector() const { return mPedestalsVector; } + + private: + float mNoiseThreshold; + float mPedestalThreshold; + + TFType mTFStart; + + // output + BadChannelsVector mBadChannelsVector; /// vector containing the unique IDs of the bad/noisy channels + CcdbObjectInfo mBadChannelsInfo; /// vector of CCDB Infos , each element is filled with the CCDB description of the accompanying BadChannelsVector object + PedestalsVector mPedestalsVector; + + ClassDefOverride(PedestalCalibrator, 1); +}; + +} // end namespace calibration +} // end namespace mch +} // end namespace o2 + +#endif /* MCH_CHANNEL_CALIBRATOR_H_ */ diff --git a/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalDigit.h b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalDigit.h new file mode 100644 index 0000000000000..9436a2ffc26f4 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalDigit.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** @file PedestalDigit.h + * C++ Muon MCH digit with ADC samples information. + * @author Andrea Ferrero + */ + +#ifndef ALICEO2_MCH_PEDESTAL_DIGIT_H_ +#define ALICEO2_MCH_PEDESTAL_DIGIT_H_ + +#include <vector> +#include "Rtypes.h" + +#define MCH_PEDESTALS_MAX_SAMPLES 20 + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +// \class PedestalDigit +/// \brief MCH "fat" digit implementation for pedestal data +class PedestalDigit +{ + public: + PedestalDigit() = default; + + PedestalDigit(int solarid, int ds, int ch, uint32_t trigTime, uint32_t time, std::vector<uint16_t> samples); + ~PedestalDigit() = default; + + uint32_t getTime() const { return mTime; } + uint32_t getTriggerTime() const { return mTrigTime; } + + uint16_t nofSamples() const { return mNofSamples; } + int16_t getSample(uint16_t s) const; + + int getSolarId() const { return mSolarId; } + int getDsId() const { return mDsId; } + int getChannel() const { return mChannel; } + + private: + uint32_t mTime{0}; + uint32_t mTrigTime{0}; + uint16_t mNofSamples{0}; /// number of samples in the signal + uint16_t mSamples[MCH_PEDESTALS_MAX_SAMPLES]; + int mSolarId; + int mDsId; /// PadIndex to which the digit corresponds to + int mChannel; /// Amplitude of signal + + ClassDefNV(PedestalDigit, 1); +}; //class PedestalDigit + +} //namespace calibration +} //namespace mch +} //namespace o2 +#endif // ALICEO2_MCH_PEDESTAL_DIGIT_H_ diff --git a/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalProcessor.h b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalProcessor.h new file mode 100644 index 0000000000000..a9ff8a6e83518 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalProcessor.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** @file PedestalsProcessor.h + * C++ helper class to compute the mean and RMS of the pedestals + * @author Andrea Ferrero + */ + +#ifndef ALICEO2_MCH_CALIBRATION_PEDESTAL_PROCESSOR_H_ +#define ALICEO2_MCH_CALIBRATION_PEDESTAL_PROCESSOR_H_ + +#include <array> +#include <unordered_map> +#include <gsl/span> + +#include "Rtypes.h" +#include "MCHCalibration/PedestalDigit.h" + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +// \class PedestalProcessor +/// \brief helper class to compute the mean and RMS of the pedestals +class PedestalProcessor +{ + public: + struct PedestalRecord { + int mEntries{0}; + double mPedestal{0}; + double mVariance{0}; + + double getRms(); + }; + + using PedestalMatrix = std::array<std::array<PedestalRecord, 64>, 40>; + using PedestalsMap = std::unordered_map<int, PedestalMatrix>; + + PedestalProcessor(); + + ~PedestalProcessor() = default; + + void process(gsl::span<const PedestalDigit> digits); + void reset(); + + const PedestalsMap& getPedestals() const { return mPedestals; } + + uint32_t getMaxDsId() { return 39; } + uint32_t getMaxChannel() { return 63; } + + private: + PedestalsMap mPedestals; +}; //class PedestalProcessor + +} //namespace calibration +} //namespace mch +} //namespace o2 +#endif // ALICEO2_MCH_CALIBRATION_PEDESTAL_PROCESSOR_H_ diff --git a/Detectors/MUON/MCH/Calibration/src/MCHCalibrationLinkDef.h b/Detectors/MUON/MCH/Calibration/src/MCHCalibrationLinkDef.h new file mode 100644 index 0000000000000..d15871f55e4fb --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/MCHCalibrationLinkDef.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::mch::calibration::PedestalDigit + ; +#pragma link C++ class std::vector < o2::mch::calibration::PedestalDigit> + ; + +#pragma link C++ class o2::mch::calibration::PedestalData + ; +#pragma link C++ class o2::mch::calibration::PedestalCalibrator + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::mch::calibration::PedestalData> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::mch::calibration::PedestalDigit, o2::mch::calibration::PedestalData> + ; + +#endif diff --git a/Detectors/MUON/MCH/Calibration/src/PedestalCalibSpec.h b/Detectors/MUON/MCH/Calibration/src/PedestalCalibSpec.h new file mode 100644 index 0000000000000..2dfe51dee1833 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/PedestalCalibSpec.h @@ -0,0 +1,189 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_MCH_PEDESTAL_CALIB_SPEC_H +#define O2_CALIBRATION_MCH_PEDESTAL_CALIB_SPEC_H + +/// @file PedestalCalibSpec.h +/// @brief Device to calibrate MCH channles (offsets) + +#include <chrono> + +#include "MCHCalibration/PedestalCalibrator.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +class PedestalCalibDevice : public o2::framework::Task +{ + public: + explicit PedestalCalibDevice() = default; + + //_________________________________________________________________________________________________ + void init(o2::framework::InitContext& ic) final + { + float pedThreshold = ic.options().get<float>("pedestal-threshold"); + float noiseThreshold = ic.options().get<float>("noise-threshold"); + mLoggingInterval = ic.options().get<int>("logging-interval") * 1000; + + mCalibrator = std::make_unique<o2::mch::calibration::PedestalCalibrator>(pedThreshold, noiseThreshold); + + int slotL = ic.options().get<int>("tf-per-slot"); + int delay = ic.options().get<int>("max-delay"); + mCalibrator->setSlotLength(slotL); + mCalibrator->setMaxSlotsDelay(delay); + mCalibrator->setUpdateAtTheEndOfRunOnly(); + } + + //_________________________________________________________________________________________________ + void logStats(size_t dataSize) + { + static auto loggerStart = std::chrono::high_resolution_clock::now(); + static auto loggerEnd = loggerStart; + static size_t nDigits = 0; + static size_t nTF = 0; + + if (mLoggingInterval == 0) { + return; + } + + nDigits += dataSize; + nTF += 1; + + loggerEnd = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::milli> loggerElapsed = loggerEnd - loggerStart; + if (loggerElapsed.count() > 1000) { + LOG(INFO) << "received " << nDigits << " digits in " << nTF << " time frames"; + nDigits = 0; + nTF = 0; + loggerStart = std::chrono::high_resolution_clock::now(); + } + } + + //_________________________________________________________________________________________________ + void run(o2::framework::ProcessingContext& pc) final + { + const o2::framework::DataProcessingHeader* header = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("digits").header); + if (!header) { + return; + } + auto tfcounter = header->startTime; // is this the timestamp of the current TF? + + auto data = pc.inputs().get<gsl::span<o2::mch::calibration::PedestalDigit>>("digits"); + mCalibrator->process(tfcounter, data); + + logStats(data.size()); + } + + //_________________________________________________________________________________________________ + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + mCalibrator->endOfStream(); + LOG(INFO) << "End of stream reached, sending output to CCDB"; + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<o2::mch::calibration::PedestalCalibrator> mCalibrator; + + int mLoggingInterval = {0}; /// time interval between statistics logging messages + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + auto createBuffer = [&](auto& vec, size_t& size) { + size = vec.empty() ? 0 : sizeof(*(vec.begin())) * vec.size(); + char* buf = nullptr; + if (size > 0) { + buf = (char*)malloc(size); + if (buf) { + char* p = buf; + size_t sizeofElement = sizeof(*(vec.begin())); + for (auto& element : vec) { + memcpy(p, &element, sizeofElement); + p += sizeofElement; + } + } + } + return buf; + }; + + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + using clbUtils = o2::calibration::Utils; + const auto& payload = mCalibrator->getBadChannelsVector(); + auto& info = mCalibrator->getBadChannelsInfo(); // use non-const version as we update it + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "MCH_BADCHAN", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "MCH_BADCHAN", 0}, info); // root-serialized + + size_t pedestalsSize; + char* pedestalsBuffer = createBuffer(mCalibrator->getPedestalsVector(), pedestalsSize); + auto freefct = [](void* data, void*) { free(data); }; + output.adoptChunk(Output{"MCH", "PEDESTALS", 0}, pedestalsBuffer, pedestalsSize, freefct, nullptr); + + mCalibrator->initOutput(); // reset the outputs once they are already sent + } +}; + +} // namespace calibration +} // namespace mch + +namespace framework +{ + +DataProcessorSpec getMCHPedestalCalibSpec(const char* specName, const std::string inputSpec) +{ + constexpr int64_t INFINITE_TF = 0xffffffffffffffff; + using device = o2::mch::calibration::PedestalCalibDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "MCH_BADCHAN"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "MCH_BADCHAN"}); + outputs.emplace_back(OutputSpec{"MCH", "PEDESTALS", 0, Lifetime::Timeframe}); + + return DataProcessorSpec{ + specName, + select(inputSpec.data()), + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"logging-interval", VariantType::Int, 0, {"time interval in seconds between logging messages (set to zero to disable)"}}, + {"tf-per-slot", VariantType::Int64, INFINITE_TF - 10, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int, 1, {"number of slots in past to consider"}}, + {"pedestal-threshold", VariantType::Float, 200.0f, {"maximum allowed pedestal value"}}, + {"noise-threshold", VariantType::Float, 2.0f, {"maximum allowed noise value"}}, + {"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/Calibration/src/PedestalCalibrator.cxx b/Detectors/MUON/MCH/Calibration/src/PedestalCalibrator.cxx new file mode 100644 index 0000000000000..191e7cebeb77e --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/PedestalCalibrator.cxx @@ -0,0 +1,139 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHCalibration/PedestalCalibrator.h" +#include "Framework/Logger.h" +#include "MathUtils/fit.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include <cassert> +#include <iostream> +#include <sstream> +//#include <TStopwatch.h> + +namespace o2 +{ +namespace mch +{ +namespace calibration +{ + +using Slot = o2::calibration::TimeSlot<o2::mch::calibration::PedestalData>; +using clbUtils = o2::calibration::Utils; + +//_____________________________________________ +void PedestalData::fill(const gsl::span<const o2::mch::calibration::PedestalDigit> digits) +{ + mPedestalProcessor.process(digits); +} + +//_____________________________________________ +void PedestalData::merge(const PedestalData* prev) +{ + // merge data of 2 slots +} + +//_____________________________________________ +void PedestalData::print() const +{ + LOG(INFO) << "Printing MCH pedestals:"; + std::ostringstream os; +} + +//=================================================================== + +//_____________________________________________ +void PedestalCalibrator::initOutput() +{ + // Here we initialize the vector of our output objects + mBadChannelsVector.reset(); + return; +} + +//_____________________________________________ +bool PedestalCalibrator::hasEnoughData(const Slot& slot) const +{ + + // Checking if all channels have enough data to do calibration. + // Delegating this to PedestalData + + const o2::mch::calibration::PedestalData* c = slot.getContainer(); + LOG(INFO) << "Checking statistics"; + return (true); +} + +//_____________________________________________ +void PedestalCalibrator::finalizeSlot(Slot& slot) +{ + // Extract results for the single slot + o2::mch::calibration::PedestalData* c = slot.getContainer(); + LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + + // keep track of first TimeFrame + if (slot.getTFStart() < mTFStart) { + mTFStart = slot.getTFStart(); + } + + auto pedestals = c->getPedestals(); + for (auto& p : pedestals) { + auto& pMat = p.second; + for (size_t dsId = 0; dsId < pMat.size(); dsId++) { + auto& pRow = pMat[dsId]; + for (size_t ch = 0; ch < pRow.size(); ch++) { + auto& pRecord = pRow[ch]; + + if (pRecord.mEntries == 0) { + continue; + } + + mPedestalsVector.emplace_back(DsChannelId::make(p.first, dsId, ch), pRecord.mPedestal, pRecord.getRms()); + + bool bad = true; + if (pRecord.mPedestal < mPedestalThreshold) { + if (pRecord.getRms() < mNoiseThreshold) { + bad = false; + } + } + + if (bad) { + LOG(INFO) << "S " << p.first << " DS " << dsId << " CH " << ch + << " ENTRIES " << pRecord.mEntries << " PED " << pRecord.mPedestal << " RMS " << pRecord.getRms(); + mBadChannelsVector.getChannels().emplace_back(p.first, dsId, ch); + } + } + } + } +} + +//_____________________________________________ +Slot& PedestalCalibrator::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<PedestalData>()); + return slot; +} + +//_____________________________________________ +void PedestalCalibrator::endOfStream() +{ + // create the CCDB entry + auto clName = o2::utils::MemFileHelper::getClassName(mBadChannelsVector); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + std::map<std::string, std::string> md; + mBadChannelsInfo = CcdbObjectInfo("MCH/BadChannelCalib", clName, flName, md, mTFStart, 99999999999999); +} + +} // end namespace calibration +} // end namespace mch +} // end namespace o2 diff --git a/Detectors/MUON/MCH/Calibration/src/PedestalDigit.cxx b/Detectors/MUON/MCH/Calibration/src/PedestalDigit.cxx new file mode 100644 index 0000000000000..d6e37db92d5b4 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/PedestalDigit.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHCalibration/PedestalDigit.h" +#include <cmath> + +namespace o2::mch::calibration +{ + +PedestalDigit::PedestalDigit(int solarid, int dsid, int ch, uint32_t trigTime, uint32_t time, std::vector<uint16_t> samples) + : mSolarId(solarid), mDsId(dsid), mChannel(ch), mTrigTime(trigTime), mTime(time), mNofSamples(samples.size()) +{ + mNofSamples = samples.size(); + if (mNofSamples > MCH_PEDESTALS_MAX_SAMPLES) { + mNofSamples = MCH_PEDESTALS_MAX_SAMPLES; + } + + for (uint16_t s = 0; s < mNofSamples; s++) { + mSamples[s] = samples[s]; + } +} + +int16_t PedestalDigit::getSample(uint16_t s) const +{ + int16_t result = -1; + if (s < mNofSamples) { + result = static_cast<int16_t>(mSamples[s]); + } + + return result; +} + +} // namespace o2::mch::calibration diff --git a/Detectors/MUON/MCH/Calibration/src/PedestalProcessor.cxx b/Detectors/MUON/MCH/Calibration/src/PedestalProcessor.cxx new file mode 100644 index 0000000000000..f64ea53df2d1e --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/PedestalProcessor.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHCalibration/PedestalProcessor.h" +#include <cmath> +#include <iostream> + +namespace o2::mch::calibration +{ + +double PedestalProcessor::PedestalRecord::getRms() +{ + double rms = std::sqrt(mVariance / mEntries); + return rms; +} + +PedestalProcessor::PedestalProcessor() +{ + reset(); +} + +void PedestalProcessor::reset() +{ + mPedestals.clear(); +} + +void PedestalProcessor::process(gsl::span<const PedestalDigit> digits) +{ + bool mDebug = false; + + for (auto& d : digits) { + auto solarId = d.getSolarId(); + auto dsId = d.getDsId(); + auto channel = d.getChannel(); + + auto iPedestal = mPedestals.find(solarId); + + if (iPedestal == mPedestals.end()) { + auto iPedestalsNew = mPedestals.emplace(std::make_pair(solarId, PedestalMatrix())); + iPedestal = iPedestalsNew.first; + } + + if (iPedestal == mPedestals.end()) { + std::cout << "[PedestalProcessor::process] failed to insert new element\n"; + break; + } + + auto& ped = iPedestal->second[dsId][channel]; + + for (uint16_t i = 0; i < d.nofSamples(); i++) { + auto s = d.getSample(i); + + ped.mEntries += 1; + uint64_t N = ped.mEntries; + + double p0 = ped.mPedestal; + double p = p0 + (s - p0) / N; + ped.mPedestal = p; + + double M0 = ped.mVariance; + double M = M0 + (s - p0) * (s - p); + ped.mVariance = M; + } + + if (mDebug) { + std::cout << "solarId " << (int)solarId << " dsId " << (int)dsId << " ch " << (int)channel << " nsamples " << d.nofSamples() + << " entries " << ped.mEntries << " ped " << ped.mPedestal << " variance " << ped.mVariance << std::endl; + } + } +} + +} // namespace o2::mch::calibration diff --git a/Detectors/MUON/MCH/Calibration/src/pedestal-calib-workflow.cxx b/Detectors/MUON/MCH/Calibration/src/pedestal-calib-workflow.cxx new file mode 100644 index 0000000000000..d2abddb4d7006 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/pedestal-calib-workflow.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PedestalCalibSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +const char* specName = "mch-calib-pedestals"; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName(specName, CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"input-spec", VariantType::String, "digits:MCH/PDIGITS", {"selection string input specs"}}); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + const std::string inputSpec = configcontext.options().get<std::string>("input-spec"); + WorkflowSpec specs; + specs.emplace_back(getMCHPedestalCalibSpec(specName, inputSpec)); + return specs; +} diff --git a/Detectors/MUON/MCH/Calibration/src/pedestal-decoding-workflow.cxx b/Detectors/MUON/MCH/Calibration/src/pedestal-decoding-workflow.cxx new file mode 100644 index 0000000000000..33eb4cad21bab --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/src/pedestal-decoding-workflow.cxx @@ -0,0 +1,441 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DatDecoderSpec.cxx +/// \author Andrea Ferrero +/// +/// \brief Implementation of a data processor to run the raw decoding +/// + +#include <random> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <array> +#include <functional> +#include <chrono> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DataRefUtils.h" + +#include "Headers/RDHAny.h" +#include "MCHRawDecoder/PageDecoder.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "MCHRawCommon/DataFormats.h" +#include "MCHRawElecMap/Mapper.h" +#include "MCHMappingInterface/Segmentation.h" + +#include "MCHBase/DecoderError.h" +#include "MCHCalibration/PedestalDigit.h" + +#include "CommonUtils/ConfigurableParam.h" + +static const size_t SOLAR_ID_MAX = 100 * 8; + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +using namespace o2; +using namespace o2::framework; +using namespace o2::mch::mapping; +using RDH = o2::header::RDHAny; + +static std::string readFileContent(std::string& filename) +{ + std::string content; + std::string s; + std::ifstream in(filename); + while (std::getline(in, s)) { + content += s; + content += "\n"; + } + return content; +}; + +static bool isValidDeID(int deId) +{ + for (auto id : deIdsForAllMCH) { + if (id == deId) { + return true; + } + } + + return false; +} + +static void patchPage(gsl::span<const std::byte> rdhBuffer, bool verbose) +{ + static int sNrdhs = 0; + auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(rdhBuffer[0]))); + sNrdhs++; + + auto existingFeeId = o2::raw::RDHUtils::getFEEID(rdhAny); + if (existingFeeId == 0) { + // early versions of raw data did not set the feeId + // which we need to select the right decoder + auto cruId = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF; + auto flags = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF00; + auto endpoint = o2::raw::RDHUtils::getEndPointID(rdhAny); + uint32_t feeId = cruId * 2 + endpoint + flags; + o2::raw::RDHUtils::setFEEID(rdhAny, feeId); + } + + if (verbose) { + std::cout << "RDH number " << sNrdhs << "--\n"; + o2::raw::RDHUtils::printRDH(rdhAny); + } +}; + +//======================= +// Data decoder +class PedestalsTask +{ + public: + PedestalsTask(std::string spec) : mInputSpec(spec) {} + + void initElec2DetMapper(std::string filename) + { + LOG(INFO) << "[initElec2DetMapper] filename=" << filename; + if (filename.empty()) { + mElec2Det = createElec2DetMapper<ElectronicMapperGenerated>(); + } else { + ElectronicMapperString::sFecMap = readFileContent(filename); + mElec2Det = createElec2DetMapper<ElectronicMapperString>(); + } + }; + + void initFee2SolarMapper(std::string filename) + { + LOG(INFO) << "[initFee2SolarMapper] filename=" << filename; + if (filename.empty()) { + mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperGenerated>(); + } else { + ElectronicMapperString::sCruMap = readFileContent(filename); + mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperString>(); + } + }; + + //_________________________________________________________________________________________________ + void init(framework::InitContext& ic) + { + mDebug = ic.options().get<bool>("debug"); + mLoggingInterval = ic.options().get<int>("logging-interval") * 1000; + + auto mapCRUfile = ic.options().get<std::string>("cru-map"); + auto mapFECfile = ic.options().get<std::string>("fec-map"); + initFee2SolarMapper(mMapCRUfile); + initElec2DetMapper(mMapFECfile); + auto stop = [this]() { + if (mTFcount > 0) { + LOG(INFO) << "time spent for decoding (ms): min=" << mTimeDecoderMin->count() << ", max=" + << mTimeDecoderMax->count() << ", mean=" << mTimeDecoder.count() / mTFcount; + } + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + ic.services().get<CallbackService>().set(CallbackService::Id::Reset, [this]() { reset(); }); + } + + //_________________________________________________________________________________________________ + void reset() + { + mDigits.clear(); + mErrors.clear(); + } + + //_________________________________________________________________________________________________ + void decodePage(gsl::span<const std::byte> page) + { + static int Nrdhs = 0; + size_t ndigits{0}; + + uint32_t orbit; + + auto tStart = std::chrono::high_resolution_clock::now(); + + auto channelHandler = [&](DsElecId dsElecId, uint8_t channel, o2::mch::raw::SampaCluster sc) { + auto solarId = dsElecId.solarId(); + auto dsId = dsElecId.elinkId(); + if (mDebug) { + std::cout << "New digit: SOLAR " << (int)solarId << " DS " << (int)dsId << " CH " << (int)channel << std::endl; + } + + mDigits.emplace_back(o2::mch::calibration::PedestalDigit(solarId, dsId, channel, sc.bunchCrossing, 0, sc.samples)); + ++ndigits; + }; + + auto errorHandler = [&](DsElecId dsElecId, int8_t chip, uint32_t error) { + auto solarId = dsElecId.solarId(); + auto dsId = dsElecId.elinkId(); + + mErrors.emplace_back(o2::mch::DecoderError(solarId, dsId, chip, error)); + }; + + patchPage(page, mDebug); + + if (mDebug) { + auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(page[0]))); + Nrdhs += 1; + std::cout << Nrdhs << "--\n"; + o2::raw::RDHUtils::printRDH(rdhAny); + } + + if (!mDecoder) { + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = channelHandler; + handlers.sampaErrorHandler = errorHandler; + mDecoder = mFee2Solar ? o2::mch::raw::createPageDecoder(page, handlers, mFee2Solar) + : o2::mch::raw::createPageDecoder(page, handlers); + } + try { + mDecoder(page); + } catch (std::exception& e) { + std::cout << e.what() << '\n'; + } + } + + //_________________________________________________________________________________________________ + void decodeBuffer(gsl::span<const std::byte> buf) + { + if (mDebug) { + std::cout << "\n\n============================\nStart of new buffer\n"; + } + size_t bufSize = buf.size(); + size_t pageStart = 0; + while (bufSize > pageStart) { + RDH* rdh = reinterpret_cast<RDH*>(const_cast<std::byte*>(&(buf[pageStart]))); + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + if (rdhHeaderSize != 64) { + break; + } + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + + gsl::span<const std::byte> page(reinterpret_cast<const std::byte*>(rdh), pageSize); + decodePage(page); + + pageStart += pageSize; + } + } + + //_________________________________________________________________________________________________ + // the decodeTF() function processes the messages generated by the (sub)TimeFrame builder + void decodeTF(framework::ProcessingContext& pc) + { + // get the input buffer + auto& inputs = pc.inputs(); + std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginMCH, "RAWDATA"}, Lifetime::Timeframe}}; + DPLRawParser parser(inputs, filter); + + auto tStart = std::chrono::high_resolution_clock::now(); + size_t totPayloadSize = 0; + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto const* raw = it.raw(); + if (!raw) { + continue; + } + size_t payloadSize = it.size(); + totPayloadSize += payloadSize; + + gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(raw), sizeof(RDH) + payloadSize); + decodeBuffer(buffer); + } + auto tEnd = std::chrono::high_resolution_clock::now(); + + if (totPayloadSize > 0) { + std::chrono::duration<double, std::milli> elapsed = tEnd - tStart; + mTimeDecoder += elapsed; + if (!mTimeDecoderMin || (elapsed < mTimeDecoderMin)) { + mTimeDecoderMin = elapsed; + } + if (!mTimeDecoderMax || (elapsed > mTimeDecoderMax)) { + mTimeDecoderMax = elapsed; + } + mTFcount += 1; + } + } + + //_________________________________________________________________________________________________ + // the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow + void decodeReadout(const o2::framework::DataRef& input) + { + // Note: DPL allows to extract the san directly from the input + // this would make this function obsolete + auto const* raw = input.payload; + size_t payloadSize = DataRefUtils::getPayloadSize(input); + + gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(raw), payloadSize); + decodeBuffer(buffer); + } + + //_________________________________________________________________________________________________ + void logStats() + { + static auto loggerStart = std::chrono::high_resolution_clock::now(); + static auto loggerEnd = loggerStart; + static uint64_t nDigits = 0; + static uint64_t nTF = 0; + + if (mLoggingInterval == 0) { + return; + } + + nDigits += mDigits.size(); + nTF += 1; + + loggerEnd = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::milli> loggerElapsed = loggerEnd - loggerStart; + if (loggerElapsed.count() > mLoggingInterval) { + LOG(INFO) << "Processed " << nDigits << " digits in " << nTF << " time frames"; + nDigits = 0; + nTF = 0; + loggerStart = std::chrono::high_resolution_clock::now(); + } + } + + //_________________________________________________________________________________________________ + void run(framework::ProcessingContext& pc) + { + auto createBuffer = [&](auto& vec, size_t& size) { + size = vec.empty() ? 0 : sizeof(*(vec.begin())) * vec.size(); + char* buf = nullptr; + if (size > 0) { + buf = (char*)malloc(size); + if (buf) { + char* p = buf; + size_t sizeofElement = sizeof(*(vec.begin())); + for (auto& element : vec) { + memcpy(p, &element, sizeofElement); + p += sizeofElement; + } + } + } + return buf; + }; + + reset(); + for (auto&& input : pc.inputs()) { + if (input.spec->binding == "TF") { + decodeTF(pc); + } + if (input.spec->binding == "readout") { + decodeReadout(input); + } + } + + size_t digitsSize; + char* digitsBuffer = createBuffer(mDigits, digitsSize); + + size_t errorsSize; + char* errorsBuffer = createBuffer(mErrors, errorsSize); + + // create the output message + auto freefct = [](void* data, void*) { free(data); }; + pc.outputs().adoptChunk(Output{header::gDataOriginMCH, "PDIGITS", 0}, digitsBuffer, digitsSize, freefct, nullptr); + pc.outputs().adoptChunk(Output{header::gDataOriginMCH, "ERRORS", 0}, errorsBuffer, errorsSize, freefct, nullptr); + + logStats(); + } + + private: + o2::mch::raw::PageDecoder mDecoder; + SampaChannelHandler mChannelHandler; + std::vector<o2::mch::calibration::PedestalDigit> mDigits; + std::vector<o2::mch::DecoderError> mErrors; + + Elec2DetMapper mElec2Det{nullptr}; + FeeLink2SolarMapper mFee2Solar{nullptr}; + std::string mMapCRUfile; + std::string mMapFECfile; + + std::string mInputSpec; /// selection string for the input data + bool mDebug = {false}; /// flag to enable verbose output + int mLoggingInterval = {0}; /// time interval between statistics logging messages + + std::chrono::duration<double, std::milli> mTimeDecoder{}; + std::optional<std::chrono::duration<double, std::milli>> mTimeDecoderMin{}; + std::optional<std::chrono::duration<double, std::milli>> mTimeDecoderMax{}; + size_t mTFcount{0}; +}; + +} // namespace raw +} // namespace mch +} // end namespace o2 + +using namespace o2::framework; + +const char* specName = "mch-pedestal-decoder"; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName(specName, CompletionPolicy::CompletionOp::Consume)); +} + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"input-spec", VariantType::String, "TF:MCH/RAWDATA", {"selection string for the input data"}}); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); +} + +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getMCHPedestalDecodingSpec(const char* specName, std::string inputSpec) +{ + //o2::mch::raw::PedestalsTask task(); + return DataProcessorSpec{ + specName, + o2::framework::select(inputSpec.c_str()), + Outputs{OutputSpec{header::gDataOriginMCH, "PDIGITS", 0, Lifetime::Timeframe}, + OutputSpec{header::gDataOriginMCH, "ERRORS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<o2::mch::raw::PedestalsTask>(inputSpec)}, + Options{{"debug", VariantType::Bool, false, {"enable verbose output"}}, + {"logging-interval", VariantType::Int, 0, {"time interval in seconds between logging messages (set to zero to disable)"}}, + {"noise-threshold", VariantType::Float, (float)2.0, {"maximum acceptable noise value"}}, + {"pedestal-threshold", VariantType::Float, (float)150, {"maximum acceptable pedestal value"}}, + {"cru-map", VariantType::String, "", {"custom CRU mapping"}}, + {"fec-map", VariantType::String, "", {"custom FEC mapping"}}}}; +} + +WorkflowSpec defineDataProcessing(const ConfigContext& config) +{ + auto inputSpec = config.options().get<std::string>("input-spec"); + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + + WorkflowSpec specs; + + DataProcessorSpec producer = getMCHPedestalDecodingSpec(specName, inputSpec); + specs.push_back(producer); + + return specs; +} diff --git a/Detectors/MUON/MCH/Calibration/test/qc-pedestals.json b/Detectors/MUON/MCH/Calibration/test/qc-pedestals.json new file mode 100644 index 0000000000000..828c0e4913876 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/test/qc-pedestals.json @@ -0,0 +1,35 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + } + }, + "tasks": { + "QcTaskMCHPreclusters": { + "active": "true", + "className": "o2::quality_control_modules::muonchambers::PedestalsTask", + "moduleName": "QcMuonChambers", + "detectorName": "MCH", + "cycleDurationSeconds": "100", + "maxNumberCycles": "-1", + "dataSource": { + "type": "direct", + "query" : "pedestals:MCH/PEDESTALS" + }, + "location": "remote" + } + } + }, + "dataSamplingPolicies": [ + + ] +} diff --git a/Detectors/MUON/MCH/Calibration/test/run-tfbuilder.sh b/Detectors/MUON/MCH/Calibration/test/run-tfbuilder.sh new file mode 100755 index 0000000000000..4d1cda5645abc --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/test/run-tfbuilder.sh @@ -0,0 +1,5 @@ +#! /bin/bash +TRANSPORT=shmem +#TRANSPORT=zeromq + +StfBuilder --id stf_builder-0 --transport $TRANSPORT --detector MCH --dpl-channel-name=dpl-chan --channel-config "name=dpl-chan,type=push,method=bind,address=ipc://@tf-builder-pipe-0,transport=$TRANSPORT,rateLogging=1" --data-source-dir="$1" --data-source-enable --control=static #--max-built-stfs 10 diff --git a/Detectors/MUON/MCH/Calibration/test/test-mch-pedestal-calibration.sh b/Detectors/MUON/MCH/Calibration/test/test-mch-pedestal-calibration.sh new file mode 100755 index 0000000000000..fbbbb8c5622e5 --- /dev/null +++ b/Detectors/MUON/MCH/Calibration/test/test-mch-pedestal-calibration.sh @@ -0,0 +1,26 @@ +#! /bin/bash + +export O2_INFOLOGGER_MODE=stdout +export SCRIPTDIR=$(readlink -f $(dirname $0)) + +INPUT="$1" + +ARGS_ALL="-b --session default" +PROXY_INSPEC="A:MCH/RAWDATA;dd:FLP/DISTSUBTIMEFRAME/0;eos:***/INFORMATION" +DECOD_INSPEC="TF:MCH/RAWDATA;dd:FLP/DISTSUBTIMEFRAME/0;eos:***/INFORMATION" +CALIB_INSPEC="digits:MCH/PDIGITS;dd:FLP/DISTSUBTIMEFRAME/0;eos:***/INFORMATION" + +xterm -bg black -fg white -geometry 100x50+0+100 -e ./run-tfbuilder.sh "$INPUT" & + +sleep 10 + +o2-dpl-raw-proxy ${ARGS_ALL} --dataspec "${PROXY_INSPEC}" \ + --readout-proxy '--channel-config "name=readout-proxy,type=pull,method=connect,address=ipc://@tf-builder-pipe-0,transport=shmem,rateLogging=1"' \ + | o2-mch-pedestal-decoding-workflow ${ARGS_ALL} --input-spec "${DECOD_INSPEC}" --logging-interval 1 \ + | o2-calibration-mch-pedestal-calib-workflow ${ARGS_ALL} --input-spec "${CALIB_INSPEC}" \ + --pedestal-threshold 200 --noise-threshold 2.0 --logging-interval 1 \ + | o2-dpl-run ${ARGS_ALL} --run + +# outputs to QC and CCDB +#| o2-qc -b --config json:/${SCRIPTDIR}/qc-pedestals.json +#| o2-calibration-ccdb-populator-workflow -b --session default diff --git a/Detectors/MUON/MCH/Clustering/CMakeLists.txt b/Detectors/MUON/MCH/Clustering/CMakeLists.txt index a87b574567d8e..1ad9526ab091f 100644 --- a/Detectors/MUON/MCH/Clustering/CMakeLists.txt +++ b/Detectors/MUON/MCH/Clustering/CMakeLists.txt @@ -1,15 +1,21 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHClustering SOURCES src/ClusterOriginal.cxx src/ClusterFinderOriginal.cxx src/MathiesonOriginal.cxx - PUBLIC_LINK_LIBRARIES O2::MCHMappingInterface O2::MCHBase O2::MCHPreClustering O2::Framework) + src/ClusterizerParam.cxx + PUBLIC_LINK_LIBRARIES O2::MCHMappingInterface O2::MCHBase O2::MCHPreClustering + O2::Framework O2::CommonUtils) + +o2_target_root_dictionary(MCHClustering + HEADERS include/MCHClustering/ClusterizerParam.h) diff --git a/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h index 657cfcc1a54ef..fdad9758f505a 100644 --- a/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h +++ b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,8 +27,8 @@ #include <TH2D.h> -#include "MCHBase/Digit.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHMappingInterface/Segmentation.h" #include "MCHPreClustering/PreClusterFinder.h" @@ -51,7 +52,7 @@ class ClusterFinderOriginal ClusterFinderOriginal(ClusterFinderOriginal&&) = delete; ClusterFinderOriginal& operator=(ClusterFinderOriginal&&) = delete; - void init(); + void init(bool run2Config); void deinit(); void reset(); @@ -63,13 +64,10 @@ class ClusterFinderOriginal const std::vector<Digit>& getUsedDigits() const { return mUsedDigits; } private: - static constexpr double SDistancePrecision = 1.e-3; ///< precision used to check overlaps and so on (cm) - static constexpr double SLowestPadCharge = 4.f * 0.22875f; ///< minimum charge of a pad - static constexpr double SLowestPixelCharge = SLowestPadCharge / 12.; ///< minimum charge of a pixel - static constexpr double SLowestClusterCharge = 2. * SLowestPadCharge; ///< minimum charge of a cluster - static constexpr int SNFitClustersMax = 3; ///< maximum number of clusters fitted at the same time - static constexpr int SNFitParamMax = 3 * SNFitClustersMax - 1; ///< maximum number of fit parameters - static constexpr double SLowestCoupling = 1.e-2; ///< minimum coupling between clusters of pixels and pads + static constexpr double SDistancePrecision = 1.e-3; ///< precision used to check overlaps and so on (cm) + static constexpr int SNFitClustersMax = 3; ///< maximum number of clusters fitted at the same time + static constexpr int SNFitParamMax = 3 * SNFitClustersMax - 1; ///< maximum number of fit parameters + static constexpr double SLowestCoupling = 1.e-2; ///< minimum coupling between clusters of pixels and pads void resetPreCluster(gsl::span<const Digit>& digits); void simplifyPreCluster(std::vector<int>& removedDigits); @@ -89,7 +87,6 @@ class ClusterFinderOriginal double mlem(const std::vector<double>& coef, const std::vector<double>& prob, int nIter); void findCOG(const TH2D& histMLEM, double xy[2]) const; void refinePixelArray(const double xyCOG[2], size_t nPixMax, double& xMin, double& xMax, double& yMin, double& yMax); - void shiftPixelsToKeep(double charge); void cleanPixelArray(double threshold, std::vector<double>& prob); int fit(const std::vector<const std::vector<int>*>& clustersOfPixels, const double fitRange[2][2], double fitParam[SNFitParamMax + 1]); @@ -111,6 +108,15 @@ class ClusterFinderOriginal std::vector<std::vector<double>>& couplingClCl, std::vector<std::vector<double>>& couplingClPad) const; void updatePads(const double fitParam[SNFitParamMax + 1], int nParamUsed); + void setClusterResolution(ClusterStruct& cluster) const; + + /// function to reinterpret digit ADC as charge + std::function<double(uint32_t)> mADCToCharge = [](uint32_t adc) { return static_cast<double>(adc); }; + + double mLowestPadCharge = 0.; ///< minimum charge of a pad + double mLowestPixelCharge = 0.; ///< minimum charge of a pixel + double mLowestClusterCharge = 0.; ///< minimum charge of a cluster + std::unique_ptr<MathiesonOriginal[]> mMathiesons; ///< Mathieson functions for station 1 and the others MathiesonOriginal* mMathieson = nullptr; ///< pointer to the Mathieson function currently used diff --git a/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterizerParam.h b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterizerParam.h new file mode 100644 index 0000000000000..24f8322fc9dc9 --- /dev/null +++ b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterizerParam.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ClusterizerParam.h +/// \brief Configurable parameters for MCH clustering +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MCH_CLUSTERIZERPARAM_H_ +#define ALICEO2_MCH_CLUSTERIZERPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace mch +{ + +/// Configurable parameters for MCH clustering +struct ClusterizerParam : public o2::conf::ConfigurableParamHelper<ClusterizerParam> { + + double lowestPadCharge = 4.f * 0.22875f; ///< minimum charge of a pad + + double pitchSt1 = 0.21; ///< anode-cathode pitch (cm) for station 1 + double pitchSt2345 = 0.25; ///< anode-cathode pitch (cm) for station 2 to 5 + + double mathiesonSqrtKx3St1 = 0.7000; ///< Mathieson parameter sqrt(K3) in x direction for station 1 + double mathiesonSqrtKx3St2345 = 0.7131; ///< Mathieson parameter sqrt(K3) in x direction for station 2 to 5 + + double mathiesonSqrtKy3St1 = 0.7550; ///< Mathieson parameter sqrt(K3) in y direction for station 1 + double mathiesonSqrtKy3St2345 = 0.7642; ///< Mathieson parameter sqrt(K3) in y direction for station 2 to 5 + + double defaultClusterResolution = 0.2; ///< default cluster resolution (cm) + double badClusterResolution = 10.; ///< bad (e.g. mono-cathode) cluster resolution (cm) + + O2ParamDef(ClusterizerParam, "MCHClustering"); +}; + +} // namespace mch +} // end namespace o2 + +#endif // ALICEO2_MCH_CLUSTERIZERPARAM_H_ diff --git a/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx b/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx index 065d50fb6e9d1..e9966a0e8efb1 100644 --- a/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx +++ b/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "MCHClustering/ClusterFinderOriginal.h" #include <algorithm> +#include <cstring> #include <iterator> #include <limits> #include <numeric> @@ -33,6 +35,7 @@ #include <FairMQLogger.h> +#include "MCHClustering/ClusterizerParam.h" #include "PadOriginal.h" #include "ClusterOriginal.h" #include "MathiesonOriginal.h" @@ -48,26 +51,59 @@ ClusterFinderOriginal::ClusterFinderOriginal() mPreCluster(std::make_unique<ClusterOriginal>()) { /// default constructor - - // Mathieson function for station 1 - mMathiesons[0].setPitch(0.21); - mMathiesons[0].setSqrtKx3AndDeriveKx2Kx4(0.7000); - mMathiesons[0].setSqrtKy3AndDeriveKy2Ky4(0.7550); - - // Mathieson function for other stations - mMathiesons[1].setPitch(0.25); - mMathiesons[1].setSqrtKx3AndDeriveKx2Kx4(0.7131); - mMathiesons[1].setSqrtKy3AndDeriveKy2Ky4(0.7642); } //_________________________________________________________________________________________________ ClusterFinderOriginal::~ClusterFinderOriginal() = default; //_________________________________________________________________________________________________ -void ClusterFinderOriginal::init() +void ClusterFinderOriginal::init(bool run2Config) { - /// initialize the clustering + /// initialize the clustering for run2 or run3 data + mPreClusterFinder.init(); + + if (run2Config) { + + // function to reinterpret digit ADC as calibrated charge + mADCToCharge = [](uint32_t adc) { + float charge(0.); + std::memcpy(&charge, &adc, sizeof(adc)); + return static_cast<double>(charge); + }; + + // minimum charge of pad, pixel and cluster + mLowestPadCharge = 4.f * 0.22875f; + mLowestPixelCharge = mLowestPadCharge / 12.; + mLowestClusterCharge = 2. * mLowestPadCharge; + + // Mathieson function for station 1 + mMathiesons[0].setPitch(0.21); + mMathiesons[0].setSqrtKx3AndDeriveKx2Kx4(0.7000); + mMathiesons[0].setSqrtKy3AndDeriveKy2Ky4(0.7550); + + // Mathieson function for other stations + mMathiesons[1].setPitch(0.25); + mMathiesons[1].setSqrtKx3AndDeriveKx2Kx4(0.7131); + mMathiesons[1].setSqrtKy3AndDeriveKy2Ky4(0.7642); + + } else { + + // minimum charge of pad, pixel and cluster + mLowestPadCharge = ClusterizerParam::Instance().lowestPadCharge; + mLowestPixelCharge = mLowestPadCharge / 12.; + mLowestClusterCharge = 2. * mLowestPadCharge; + + // Mathieson function for station 1 + mMathiesons[0].setPitch(ClusterizerParam::Instance().pitchSt1); + mMathiesons[0].setSqrtKx3AndDeriveKx2Kx4(ClusterizerParam::Instance().mathiesonSqrtKx3St1); + mMathiesons[0].setSqrtKy3AndDeriveKy2Ky4(ClusterizerParam::Instance().mathiesonSqrtKy3St1); + + // Mathieson function for other stations + mMathiesons[1].setPitch(ClusterizerParam::Instance().pitchSt2345); + mMathiesons[1].setSqrtKx3AndDeriveKx2Kx4(ClusterizerParam::Instance().mathiesonSqrtKx3St2345); + mMathiesons[1].setSqrtKy3AndDeriveKy2Ky4(ClusterizerParam::Instance().mathiesonSqrtKy3St2345); + } } //_________________________________________________________________________________________________ @@ -123,11 +159,12 @@ void ClusterFinderOriginal::findClusters(gsl::span<const Digit> digits) } int nNewDigits = mUsedDigits.size() - iFirstNewDigit; - // give the new clusters a unique ID and make them point to these digits + // give the new clusters a unique ID, make them point to these digits then set their resolution for (; iNewCluster < mClusters.size(); ++iNewCluster) { mClusters[iNewCluster].uid = ClusterStruct::buildUniqueId(digits[0].getDetID() / 100 - 1, digits[0].getDetID(), iNewCluster); mClusters[iNewCluster].firstDigit = iFirstNewDigit; mClusters[iNewCluster].nDigits = nNewDigits; + setClusterResolution(mClusters[iNewCluster]); } } } @@ -173,8 +210,8 @@ void ClusterFinderOriginal::resetPreCluster(gsl::span<const Digit>& digits) double y = mSegmentation->padPositionY(padID); double dx = mSegmentation->padSizeX(padID) / 2.; double dy = mSegmentation->padSizeY(padID) / 2.; - double charge = static_cast<double>(digit.getADC()) / static_cast<double>(std::numeric_limits<unsigned long>::max()) * 1024; - bool isSaturated = digit.getTime().time > 0; + double charge = mADCToCharge(digit.getADC()); + bool isSaturated = digit.isSaturated(); int plane = mSegmentation->isBendingPad(padID) ? 0 : 1; if (charge <= 0.) { @@ -194,7 +231,7 @@ void ClusterFinderOriginal::simplifyPreCluster(std::vector<int>& removedDigits) /// return true if the precluster has been simplified // discard small clusters (leftovers from splitting or noise) - if (mPreCluster->multiplicity() < 3 && mPreCluster->charge() < SLowestClusterCharge) { + if (mPreCluster->multiplicity() < 3 && mPreCluster->charge() < mLowestClusterCharge) { mPreCluster->clear(); return; } @@ -237,7 +274,7 @@ void ClusterFinderOriginal::simplifyPreCluster(std::vector<int>& removedDigits) continue; } const auto& pad = mPreCluster->pad(i); - if (nNotOverlapping == 1 && pad.charge() < SLowestPadCharge) { + if (nNotOverlapping == 1 && pad.charge() < mLowestPadCharge) { break; // there is only one } int cathPadIdx = cathSeg[1 - pad.plane()]->findPadByPosition(pad.x(), pad.y()); @@ -546,7 +583,7 @@ void ClusterFinderOriginal::findLocalMaxima(std::unique_ptr<TH2D>& histAnode, std::vector<std::vector<int>> isLocalMax(nBinsX, std::vector<int>(nBinsY, 0)); for (int j = 1; j <= nBinsY; ++j) { for (int i = 1; i <= nBinsX; ++i) { - if (isLocalMax[i - 1][j - 1] == 0 && histAnode->GetBinContent(i, j) >= SLowestPixelCharge) { + if (isLocalMax[i - 1][j - 1] == 0 && histAnode->GetBinContent(i, j) >= mLowestPixelCharge) { flagLocalMaxima(*histAnode, i, j, isLocalMax); } } @@ -559,7 +596,7 @@ void ClusterFinderOriginal::findLocalMaxima(std::unique_ptr<TH2D>& histAnode, for (int i = 1; i <= nBinsX; ++i) { if (isLocalMax[i - 1][j - 1] > 0) { localMaxima.emplace(histAnode->GetBinContent(i, j), std::make_pair(i, j)); - auto itPixel = findPad(mPixels, xAxis->GetBinCenter(i), yAxis->GetBinCenter(j), SLowestPixelCharge); + auto itPixel = findPad(mPixels, xAxis->GetBinCenter(i), yAxis->GetBinCenter(j), mLowestPixelCharge); itPixel->setStatus(PadOriginal::kMustKeep); if (localMaxima.size() > 99) { break; @@ -638,7 +675,7 @@ void ClusterFinderOriginal::restrictPreCluster(const TH2D& histAnode, int i0, in for (int j = jMin; j <= jMax; ++j) { for (int i = iMin; i <= iMax; ++i) { double charge = histAnode.GetBinContent(i, j); - if (charge >= SLowestPixelCharge && charge <= charge0) { + if (charge >= mLowestPixelCharge && charge <= charge0) { mPixels.emplace_back(xAxis->GetBinCenter(i), yAxis->GetBinCenter(j), dx, dy, charge); } } @@ -682,7 +719,7 @@ void ClusterFinderOriginal::processSimple() double qTot = mlem(coef, prob, 15); // abort if the total charge of the pixels is too low - if (qTot < 1.e-4 || (mPreCluster->multiplicity() < 3 && qTot < SLowestClusterCharge)) { + if (qTot < 1.e-4 || (mPreCluster->multiplicity() < 3 && qTot < mLowestClusterCharge)) { return; } @@ -760,7 +797,7 @@ void ClusterFinderOriginal::process() double qTot = mlem(coef, prob, 15); // abort if the total charge of the pixels is too low - if (qTot < 1.e-4 || (npadOK < 3 && qTot < SLowestClusterCharge)) { + if (qTot < 1.e-4 || (npadOK < 3 && qTot < mLowestClusterCharge)) { return; } @@ -788,14 +825,14 @@ void ClusterFinderOriginal::process() } // discard pixels with low visibility by moving their charge to their nearest neighbour (cuts are empirical !!!) - double threshold = TMath::Min(TMath::Max(histMLEM->GetMaximum() / 100., 2.0 * SLowestPixelCharge), 100.0 * SLowestPixelCharge); + double threshold = TMath::Min(TMath::Max(histMLEM->GetMaximum() / 100., 2.0 * mLowestPixelCharge), 100.0 * mLowestPixelCharge); cleanPixelArray(threshold, prob); // re-run the MLEM algorithm with 2 iterations double qTot = mlem(coef, prob, 2); // abort if the total charge of the pixels is too low - if (qTot < 2. * SLowestPixelCharge) { + if (qTot < 2. * mLowestPixelCharge) { return; } @@ -907,7 +944,7 @@ void ClusterFinderOriginal::addVirtualPad() } // add the virtual pad - double charge = TMath::Max(TMath::Min(chargeMax[i] / chargeReduction[ixy], SLowestPadCharge), 2. * SLowestPixelCharge); + double charge = TMath::Max(TMath::Min(chargeMax[i] / chargeReduction[ixy], mLowestPadCharge), 2. * mLowestPixelCharge); mPreCluster->addPad(cathSeg[iPlaneXY[ixy]]->padPositionX(cathPadIdx), cathSeg[iPlaneXY[ixy]]->padPositionY(cathPadIdx), cathSeg[iPlaneXY[ixy]]->padSizeX(cathPadIdx) / 2., cathSeg[iPlaneXY[ixy]]->padSizeY(cathPadIdx) / 2., charge, false, iPlaneXY[ixy], -1, pad.status()); @@ -1114,20 +1151,19 @@ void ClusterFinderOriginal::refinePixelArray(const double xyCOG[2], size_t nPixM /// shift the pixels to align the array with the center of gravity around the /// maximum pixel charge and update the current pixel array and its limits. /// nPixMax is the maximum number of new pixels that can be produced. - /// all pixels have the same charge (SLowestPadCharge) in the end + /// all pixels have the same charge (mLowestPadCharge) in the end xMin = std::numeric_limits<double>::max(); xMax = -std::numeric_limits<double>::max(); yMin = std::numeric_limits<double>::max(); yMax = -std::numeric_limits<double>::max(); - // sort pixels according to the charge and move all pixels that must be kept at the begining - shiftPixelsToKeep(10000.); + // sort pixels according to the charge and move all pixels that must be kept at the beginning std::stable_sort(mPixels.begin(), mPixels.end(), [](const PadOriginal& pixel1, const PadOriginal& pixel2) { - return pixel1.charge() > pixel2.charge(); + return (pixel1.status() == PadOriginal::kMustKeep && pixel2.status() != PadOriginal::kMustKeep) || + (pixel1.status() == pixel2.status() && pixel1.charge() > pixel2.charge()); }); - shiftPixelsToKeep(-10000.); - double pixMinCharge = TMath::Min(0.01 * mPixels.front().charge(), 100. * SLowestPixelCharge); + double pixMinCharge = TMath::Min(0.01 * mPixels.front().charge(), 100. * mLowestPixelCharge); // define the half-size and shift of the new pixels depending on the direction of splitting double width[2] = {mPixels.front().dx(), mPixels.front().dy()}; @@ -1164,7 +1200,7 @@ void ClusterFinderOriginal::refinePixelArray(const double xyCOG[2], size_t nPixM pixel.sety(pixel.y() + shift[1] - shiftToCOG[1]); pixel.setdx(width[0]); pixel.setdy(width[1]); - pixel.setCharge(SLowestPadCharge); + pixel.setCharge(mLowestPadCharge); xMin = TMath::Min(xMin, pixel.x()); yMin = TMath::Min(yMin, pixel.y()); ++nNewPixels; @@ -1214,19 +1250,6 @@ void ClusterFinderOriginal::refinePixelArray(const double xyCOG[2], size_t nPixM } } -//_________________________________________________________________________________________________ -void ClusterFinderOriginal::shiftPixelsToKeep(double charge) -{ - /// add the given charge to the pixels tagged as kMustKeep - /// (just a trick to put them in front when sorting pixels by charge) - - for (auto& pixel : mPixels) { - if (pixel.status() == PadOriginal::kMustKeep) { - pixel.setCharge(pixel.charge() + charge); - } - } -} - //_________________________________________________________________________________________________ void ClusterFinderOriginal::cleanPixelArray(double threshold, std::vector<double>& prob) { @@ -1423,7 +1446,7 @@ int ClusterFinderOriginal::fit(const std::vector<const std::vector<int>*>& clust double chargeFraction[SNFitClustersMax] = {0.}; param2ChargeFraction(fitParam, nParamUsed, chargeFraction); for (int iParam = 0; iParam < nParamUsed; iParam += 3) { - if (chargeFraction[iParam / 3] * fitParam[SNFitParamMax] >= SLowestClusterCharge) { + if (chargeFraction[iParam / 3] * fitParam[SNFitParamMax] >= mLowestClusterCharge) { mClusters.push_back({static_cast<float>(fitParam[iParam]), static_cast<float>(fitParam[iParam + 1]), 0., 0., 0., 0, 0, 0}); } } @@ -1693,7 +1716,7 @@ void ClusterFinderOriginal::split(const TH2D& histMLEM, const std::vector<double std::vector<std::vector<bool>> isUsed(nBinsX, std::vector<bool>(nBinsY, false)); for (int j = 1; j <= nBinsY; ++j) { for (int i = 1; i <= nBinsX; ++i) { - if (!isUsed[i - 1][j - 1] && histMLEM.GetBinContent(i, j) >= SLowestPixelCharge) { + if (!isUsed[i - 1][j - 1] && histMLEM.GetBinContent(i, j) >= mLowestPixelCharge) { // add a new cluster of pixels and the associated pixels recursively clustersOfPixels.emplace_back(); addPixel(histMLEM, i, j, clustersOfPixels.back(), isUsed); @@ -1811,9 +1834,9 @@ void ClusterFinderOriginal::split(const TH2D& histMLEM, const std::vector<double void ClusterFinderOriginal::addPixel(const TH2D& histMLEM, int i0, int j0, std::vector<int>& pixels, std::vector<std::vector<bool>>& isUsed) { /// add a pixel to the cluster of pixels then add recursively its neighbours, - /// if their charge is higher than SLowestPixelCharge and excluding corners + /// if their charge is higher than mLowestPixelCharge and excluding corners - auto itPixel = findPad(mPixels, histMLEM.GetXaxis()->GetBinCenter(i0), histMLEM.GetYaxis()->GetBinCenter(j0), SLowestPixelCharge); + auto itPixel = findPad(mPixels, histMLEM.GetXaxis()->GetBinCenter(i0), histMLEM.GetYaxis()->GetBinCenter(j0), mLowestPixelCharge); pixels.push_back(std::distance(mPixels.begin(), itPixel)); isUsed[i0 - 1][j0 - 1] = true; @@ -1823,7 +1846,7 @@ void ClusterFinderOriginal::addPixel(const TH2D& histMLEM, int i0, int j0, std:: int jMax = TMath::Min(histMLEM.GetNbinsY(), j0 + 1); for (int j = jMin; j <= jMax; ++j) { for (int i = iMin; i <= iMax; ++i) { - if (!isUsed[i - 1][j - 1] && (i == i0 || j == j0) && histMLEM.GetBinContent(i, j) >= SLowestPixelCharge) { + if (!isUsed[i - 1][j - 1] && (i == i0 || j == j0) && histMLEM.GetBinContent(i, j) >= mLowestPixelCharge) { addPixel(histMLEM, i, j, pixels, isUsed); } } @@ -2026,10 +2049,48 @@ void ClusterFinderOriginal::updatePads(const double fitParam[SNFitParamMax + 1], } // reset the pad status to further use it if its charge is high enough - pad.setStatus((pad.charge() > SLowestPadCharge) ? PadOriginal::kZero : PadOriginal::kOver); + pad.setStatus((pad.charge() > mLowestPadCharge) ? PadOriginal::kZero : PadOriginal::kOver); } } } +//_________________________________________________________________________________________________ +void ClusterFinderOriginal::setClusterResolution(ClusterStruct& cluster) const +{ + /// set the cluster resolution in both directions depending on whether its position + /// lies on top of a fired digit in both planes or not (e.g. mono-cathode) + + if (cluster.getChamberId() < 4) { + + // do not consider mono-cathode clusters in stations 1 and 2 + cluster.ex = ClusterizerParam::Instance().defaultClusterResolution; + cluster.ey = ClusterizerParam::Instance().defaultClusterResolution; + + } else { + + // find pads below the cluster + int padIDNB(-1), padIDB(-1); + bool padsFound = mSegmentation->findPadPairByPosition(cluster.x, cluster.y, padIDB, padIDNB); + + // look for these pads (if any) in the list of digits associated to this cluster + auto itPadNB = mUsedDigits.end(); + if (padsFound || mSegmentation->isValid(padIDNB)) { + itPadNB = std::find_if(mUsedDigits.begin() + cluster.firstDigit, mUsedDigits.end(), + [padIDNB](const Digit& digit) { return digit.getPadID() == padIDNB; }); + } + auto itPadB = mUsedDigits.end(); + if (padsFound || mSegmentation->isValid(padIDB)) { + itPadB = std::find_if(mUsedDigits.begin() + cluster.firstDigit, mUsedDigits.end(), + [padIDB](const Digit& digit) { return digit.getPadID() == padIDB; }); + } + + // set the cluster resolution accordingly + cluster.ex = (itPadNB == mUsedDigits.end()) ? ClusterizerParam::Instance().badClusterResolution + : ClusterizerParam::Instance().defaultClusterResolution; + cluster.ey = (itPadB == mUsedDigits.end()) ? ClusterizerParam::Instance().badClusterResolution + : ClusterizerParam::Instance().defaultClusterResolution; + } +} + } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.cxx b/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.cxx index ba873f4dff52f..3fb005feaf80f 100644 --- a/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.cxx +++ b/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.h b/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.h index e0378123ddf95..1292e4341b3a7 100644 --- a/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.h +++ b/Detectors/MUON/MCH/Clustering/src/ClusterOriginal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Clustering/src/ClusterizerParam.cxx b/Detectors/MUON/MCH/Clustering/src/ClusterizerParam.cxx new file mode 100644 index 0000000000000..562ed953c6956 --- /dev/null +++ b/Detectors/MUON/MCH/Clustering/src/ClusterizerParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ClusterizerParam.cxx +/// \brief Configurable parameters for MCH clustering +/// \author Philippe Pillot, Subatech + +#include "MCHClustering/ClusterizerParam.h" + +O2ParamImpl(o2::mch::ClusterizerParam); diff --git a/Detectors/MUON/MCH/Clustering/src/MCHClusteringLinkDef.h b/Detectors/MUON/MCH/Clustering/src/MCHClusteringLinkDef.h new file mode 100644 index 0000000000000..d6d754b70bd6d --- /dev/null +++ b/Detectors/MUON/MCH/Clustering/src/MCHClusteringLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::mch::ClusterizerParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mch::ClusterizerParam> + ; + +#endif diff --git a/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.cxx b/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.cxx index fad01e306743b..d79735faed549 100644 --- a/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.cxx +++ b/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.h b/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.h index 2a06045e66e78..51effdffea0f4 100644 --- a/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.h +++ b/Detectors/MUON/MCH/Clustering/src/MathiesonOriginal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Clustering/src/PadOriginal.h b/Detectors/MUON/MCH/Clustering/src/PadOriginal.h index 307f72f5d6bcf..6bea8168bbb2f 100644 --- a/Detectors/MUON/MCH/Clustering/src/PadOriginal.h +++ b/Detectors/MUON/MCH/Clustering/src/PadOriginal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Conditions/CMakeLists.txt b/Detectors/MUON/MCH/Conditions/CMakeLists.txt new file mode 100644 index 0000000000000..ea084fef7e489 --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + MCHConditions + SOURCES src/DCSNamer.cxx + PUBLIC_LINK_LIBRARIES fmt::fmt) + +if(BUILD_TESTING) + o2_add_test( + dcs-namer + SOURCES test/testDCSNamer.cxx test/HVAliases.cxx test/LVAliases.cxx + COMPONENT_NAME mch + LABELS "muon;mch;dcs" + PUBLIC_LINK_LIBRARIES O2::MCHConditions) +endif() + diff --git a/Detectors/MUON/MCH/Conditions/README.md b/Detectors/MUON/MCH/Conditions/README.md new file mode 100644 index 0000000000000..8f803d27dc7ab --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/README.md @@ -0,0 +1,8 @@ +<!-- doxy +\page refDetectorsMUONMCHConditions Conditions +/doxy --> + +# MCH Conditions + +So far the only "condition" data we have are the DCS datapoints. + diff --git a/Detectors/MUON/MCH/Conditions/include/MCHConditions/DCSNamer.h b/Detectors/MUON/MCH/Conditions/include/MCHConditions/DCSNamer.h new file mode 100644 index 0000000000000..79d09f01f0a7a --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/include/MCHConditions/DCSNamer.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_CONDITIONS_DCS_NAMER_H +#define O2_MCH_CONDITIONS_DCS_NAMER_H + +#include <vector> +#include <string> +#include <optional> +#include <cstdint> + +namespace o2::mch::dcs +{ +// The list of MCH DCS measurements that are of interest for reconstruction +enum class MeasurementType { + HV_V, // HV voltage + HV_I, // HV current + LV_V_FEE_ANALOG, // FEE (dualsampa) analog voltage + LV_V_FEE_DIGITAL, // FEE (dualsampa) digital voltage + LV_V_SOLAR // Solar crate voltage +}; + +// Side describes on which side (inside or outside) a detection element +// (slat or quadrant) is. +// Note that MCH DCS uses the very old left-right convention instead of the +// agreed-upon inside-outside. +enum class Side { + Left, + Right +}; + +// ID is used to reference a particular device in MCH DCS, +// like a detection element or solar crate for instance. +struct ID { + int number; + Side side; + int chamberId; // 0..9 +}; + +// detElemId2DCS converts a detection element id into a dcs-id. +// @returns an ID if deId is a valid the MCH detID, std::nullopt otherwise. +std::optional<ID> detElemId2DCS(int deId); + +// aliases gets a list of MCH DCS aliases for the given measurement type(s). +// @param types a vector of the measurement types for which the aliases should +// be returned. +// @returns a list of MCH DCS alias names. +std::vector<std::string> aliases(std::vector<MeasurementType> types = { + MeasurementType::HV_V, + MeasurementType::HV_I, + MeasurementType::LV_V_FEE_ANALOG, + MeasurementType::LV_V_FEE_DIGITAL, + MeasurementType::LV_V_SOLAR}); + +} // namespace o2::mch::dcs + +#endif diff --git a/Detectors/MUON/MCH/Conditions/src/DCSNamer.cxx b/Detectors/MUON/MCH/Conditions/src/DCSNamer.cxx new file mode 100644 index 0000000000000..b781381698ff1 --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/src/DCSNamer.cxx @@ -0,0 +1,417 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHConditions/DCSNamer.h" + +#include <array> +#include <fmt/printf.h> +#include <iostream> +#include <set> + +namespace +{ +const uint8_t invalidGroup{99}; + +std::array<int, 156> detElemIds = { + 100, 101, 102, 103, + 200, 201, 202, 203, + 300, 301, 302, 303, + 400, 401, 402, 403, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, + 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, + 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, + 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025}; +bool isQuadrant(int deId) +{ + return deId < 500; +} + +bool isSlat(int deId) +{ + return deId >= 500; +} + +int nofDetectionElementsInChamber(int chamberId) +{ + // chamberId must be between 4 and 9 (i.e. slats) + if (chamberId < 6) { + return 18; + } + return 26; +} + +std::string basePattern(o2::mch::dcs::Side side) +{ + std::string sside = side == o2::mch::dcs::Side::Left ? "Left" : "Right"; + return "MchHvLv" + sside + "/Chamber%02d" + sside + "/"; +} + +std::string basePattern(o2::mch::dcs::ID id) +{ + return basePattern(id.side); +} + +std::string quadrantHV(int deId, o2::mch::dcs::ID id, int sector) +{ + const auto pattern = basePattern(id) + "Quad%dSect%d"; + return fmt::sprintf(pattern, id.chamberId, id.number, sector); +} + +std::string slatHV(int deId, o2::mch::dcs::ID id) +{ + const auto pattern = basePattern(id) + "Slat%02d"; + return fmt::sprintf(pattern, id.chamberId, id.number); +} + +std::string hvPattern(int deId, int sector = -1) +{ + auto id = o2::mch::dcs::detElemId2DCS(deId); + if (!id.has_value()) { + return "INVALID"; + } + std::string base; + if (isQuadrant(deId)) { + base = quadrantHV(deId, id.value(), sector); + } else { + base = slatHV(deId, id.value()); + } + return base + ".actual.%s"; +} + +uint8_t quadrantLVGroup(int deId, bool bending) +{ + uint8_t group{invalidGroup}; + + // For Chamber 1 to 4 Left the relationship between DCS GUI names and groups is: + // Quad2B --> Group3 = DE x01 Non Bending + // Quad2F --> Group1 = DE x01 Bending + // Quad3B --> Group4 = DE x02 Bending + // Quad3F --> Group2 = DE x02 Non Bending + // for Chamber 1 to 4 Right the relationship is: + // Quad1B --> Group3 = DE x00 Bending + // Quad1F --> Group1 = DE x00 Non Bending + // Quad4B --> Group4 = DE x03 Non Bending + // Quad4F --> Group2 = DE x03 Bending + // where x = 1,2,3,4 + // and Quad#B = Back = towards IP = cath1 + // while Quad#F = Front = towards muon trigger = cath0 + // + int remnant = deId % 100; + switch (remnant) { + case 0: // DE x00 + group = bending ? 3 : 1; + break; + case 1: // DE x01 + group = bending ? 1 : 3; + break; + case 2: // DE x02 + group = bending ? 4 : 2; + break; + case 3: // DE x03 + group = bending ? 2 : 4; + break; + default: + break; + } + return group; +} + +uint8_t slatLVGroup(int deId) +{ + uint8_t group{invalidGroup}; + auto id = o2::mch::dcs::detElemId2DCS(deId).value(); + int dcsSlatNumber = 1 + id.number; + if (id.chamberId == 4 || id.chamberId == 5) { + switch (dcsSlatNumber) { + case 1: + case 2: + case 3: + group = 1; + break; + case 4: + case 5: + case 6: + group = dcsSlatNumber - 2; + break; + case 7: + case 8: + case 9: + group = 5; + break; + default: + break; + } + } else { + switch (dcsSlatNumber) { + case 1: + case 2: + case 3: + case 4: + group = 1; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + group = dcsSlatNumber - 3; + break; + case 10: + case 11: + case 12: + case 13: + group = 7; + break; + default: + break; + } + } + return group; +} + +std::string lvFEEPattern(int deId, bool bending = true) +{ + auto group = isQuadrant(deId) ? quadrantLVGroup(deId, bending) : slatLVGroup(deId); + auto id = o2::mch::dcs::detElemId2DCS(deId); + if (!id.has_value()) { + return "INVALID"; + } + auto base = basePattern(id.value()) + "Group%02d"; + auto pattern = fmt::sprintf(base, id->chamberId, group); + pattern += "%s.SenseVoltage"; + return pattern; +} + +std::string measurementName(o2::mch::dcs::MeasurementType m) +{ + switch (m) { + case o2::mch::dcs::MeasurementType::HV_V: + return "vMon"; + case o2::mch::dcs::MeasurementType::HV_I: + return "iMon"; + case o2::mch::dcs::MeasurementType::LV_V_FEE_ANALOG: + return "an"; + case o2::mch::dcs::MeasurementType::LV_V_FEE_DIGITAL: + return "di"; + case o2::mch::dcs::MeasurementType::LV_V_SOLAR: + return "Sol"; + } + return "INVALID"; +} + +std::vector<std::string> lvSolarPattern(int chamberId) +{ + std::vector<std::string> patterns; + + int nofCrates{0}; + switch (chamberId / 2) { + case 0: + case 1: + nofCrates = 4; + break; + case 2: + nofCrates = 5; + break; + case 3: + nofCrates = 7; + break; + case 4: + nofCrates = 8; + break; + }; + + for (int i = 1; i <= nofCrates; i++) { + for (auto side : {o2::mch::dcs::Side::Left, o2::mch::dcs::Side::Right}) { + auto sideLetter = (side == o2::mch::dcs::Side::Left ? 'L' : 'R'); + auto base = basePattern(side) + "%sCh%02d%cCr%02d.SenseVoltage"; + patterns.emplace_back(fmt::sprintf(base, chamberId, measurementName(o2::mch::dcs::MeasurementType::LV_V_SOLAR), chamberId, sideLetter, i)); + } + } + + return patterns; +} + +std::vector<std::string> measurement(const std::vector<std::string>& patterns, + o2::mch::dcs::MeasurementType m) +{ + std::vector<std::string> result; + + result.resize(patterns.size()); + + std::transform(patterns.begin(), patterns.end(), result.begin(), [&m](std::string s) { + auto name = fmt::sprintf(s, measurementName(m)); + return name.substr(0, 62); // name coming from ADAPOS are <= 62 characters + }); + + std::sort(result.begin(), result.end()); + return result; +} + +std::vector<std::string> aliasesForHV(std::vector<o2::mch::dcs::MeasurementType> types) +{ + std::vector<std::string> patterns; + + /// 188 HV channels + /// + /// St 1 ch 1 : 12 channels + /// ch 2 : 12 channels + /// St 2 ch 3 : 12 channels + /// ch 4 : 12 channels + /// St 3 ch 5 : 18 channels + /// ch 6 : 18 channels + /// St 4 ch 7 : 26 channels + /// ch 8 : 26 channels + /// St 5 ch 9 : 26 channels + /// ch 10 : 26 channels + /// + for (auto deId : detElemIds) { + if (isQuadrant(deId)) { + for (auto sector = 0; sector < 3; ++sector) { + patterns.emplace_back(hvPattern(deId, sector)); + } + } else { + patterns.emplace_back(hvPattern(deId)); + } + } + + std::vector<std::string> aliases; + + for (auto m : types) { + if (m == o2::mch::dcs::MeasurementType::HV_V || m == o2::mch::dcs::MeasurementType::HV_I) { + auto aliasPerType = measurement(patterns, m); + aliases.insert(aliases.begin(), aliasPerType.begin(), aliasPerType.end()); + } + } + + return aliases; +} + +std::vector<std::string> aliasesForLVFEE(std::vector<o2::mch::dcs::MeasurementType> types) +{ + std::set<std::string> patterns; + + /// 108 aliases per voltage (analog or digital) for front end card + /// + /// St 1 ch 1 left or right : 4 groups + /// ch 2 left or right : 4 groups + /// St 2 ch 3 left or right : 4 groups + /// ch 4 left or right : 4 groups + /// St 3 ch 5 left or right : 5 groups + /// ch 6 left or right : 5 groups + /// St 4 ch 7 left or right : 7 groups + /// ch 8 left or right : 7 groups + /// St 5 ch 9 left or right : 7 groups + /// ch 10 left or right : 7 groups + /// + for (auto deId : detElemIds) { + if (isQuadrant(deId)) { + for (auto bending : {true, false}) { + patterns.insert(lvFEEPattern(deId, bending)); + } + } else { + patterns.insert(lvFEEPattern(deId)); + } + } + + std::vector<std::string> uniquePatterns(patterns.begin(), patterns.end()); + std::vector<std::string> aliases; + + for (auto m : types) { + if (m == o2::mch::dcs::MeasurementType::LV_V_FEE_ANALOG || m == o2::mch::dcs::MeasurementType::LV_V_FEE_DIGITAL) { + auto aliasPerType = measurement(uniquePatterns, m); + aliases.insert(aliases.begin(), aliasPerType.begin(), aliasPerType.end()); + } + } + + return aliases; +} + +std::vector<std::string> aliasesForLVSolar(std::vector<o2::mch::dcs::MeasurementType> types) +{ + if (std::find(types.begin(), types.end(), o2::mch::dcs::MeasurementType::LV_V_SOLAR) != types.end()) { + std::vector<std::string> patterns; + + /// 112 voltages for SOLAR cards + for (auto chamberId = 0; chamberId < 10; chamberId++) { + auto pats = lvSolarPattern(chamberId); + patterns.insert(patterns.begin(), pats.begin(), pats.end()); + } + + return measurement(patterns, o2::mch::dcs::MeasurementType::LV_V_SOLAR); + } + return {}; +} + +std::vector<std::string> aliasesForLV(std::vector<o2::mch::dcs::MeasurementType> types) +{ + auto fee = aliasesForLVFEE(types); + auto solar = aliasesForLVSolar(types); + + std::vector<std::string> aliases{fee}; + aliases.insert(aliases.begin(), solar.begin(), solar.end()); + return aliases; +} +} // namespace + +namespace o2::mch::dcs +{ +std::optional<ID> detElemId2DCS(int deId) +{ + if (std::find(detElemIds.begin(), detElemIds.end(), deId) == detElemIds.end()) { + return std::nullopt; + } + int chamberId = deId / 100 - 1; + int id = deId - (chamberId + 1) * 100; + + Side side = Side::Left; + + if (isQuadrant(deId)) { + if (id == 0 || id == 3) { + side = Side::Right; + } else { + side = Side::Left; + } + } else { + int nofDe = nofDetectionElementsInChamber(chamberId); + int quarter = nofDe / 4; + int half = nofDe / 2; + int threeQuarter = quarter + half; + if (id <= quarter) { + id += quarter + 1; + side = Side::Right; + } else if (id <= threeQuarter) { + id = (threeQuarter - id + 1); + side = Side::Left; + } else { + id -= threeQuarter; + side = Side::Right; + } + // dcs convention change : numbering from top, not from bottom + id = half - id; + } + + return std::optional<ID>{{id, side, chamberId}}; +} + +std::vector<std::string> aliases(std::vector<MeasurementType> types) +{ + auto hv = aliasesForHV(types); + auto lv = aliasesForLV(types); + + auto aliases = hv; + aliases.insert(aliases.begin(), lv.begin(), lv.end()); + + return aliases; +} + +} // namespace o2::mch::dcs diff --git a/Detectors/MUON/MCH/Conditions/test/HVAliases.cxx b/Detectors/MUON/MCH/Conditions/test/HVAliases.cxx new file mode 100644 index 0000000000000..f3022d90e205f --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/test/HVAliases.cxx @@ -0,0 +1,392 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "HVAliases.h" + +std::vector<std::string> expectedHVAliasesVoltages = { + "MchHvLvLeft/Chamber00Left/Quad1Sect0.actual.vMon", + "MchHvLvLeft/Chamber00Left/Quad1Sect1.actual.vMon", + "MchHvLvLeft/Chamber00Left/Quad1Sect2.actual.vMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect0.actual.vMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect1.actual.vMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect2.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect0.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect1.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect2.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect0.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect1.actual.vMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect2.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect0.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect1.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect2.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect0.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect1.actual.vMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect2.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect0.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect1.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect2.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect0.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect1.actual.vMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect2.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber04Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber05Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat09.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat10.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat11.actual.vMon", + "MchHvLvLeft/Chamber06Left/Slat12.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat09.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat10.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat11.actual.vMon", + "MchHvLvLeft/Chamber07Left/Slat12.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat09.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat10.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat11.actual.vMon", + "MchHvLvLeft/Chamber08Left/Slat12.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat00.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat01.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat02.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat03.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat04.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat05.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat06.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat07.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat08.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat09.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat10.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat11.actual.vMon", + "MchHvLvLeft/Chamber09Left/Slat12.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad0Sect0.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad0Sect1.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad0Sect2.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad3Sect0.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad3Sect1.actual.vMon", + "MchHvLvRight/Chamber00Right/Quad3Sect2.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad0Sect0.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad0Sect1.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad0Sect2.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad3Sect0.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad3Sect1.actual.vMon", + "MchHvLvRight/Chamber01Right/Quad3Sect2.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad0Sect0.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad0Sect1.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad0Sect2.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad3Sect0.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad3Sect1.actual.vMon", + "MchHvLvRight/Chamber02Right/Quad3Sect2.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad0Sect0.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad0Sect1.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad0Sect2.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad3Sect0.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad3Sect1.actual.vMon", + "MchHvLvRight/Chamber03Right/Quad3Sect2.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber04Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber05Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat09.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat10.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat11.actual.vMon", + "MchHvLvRight/Chamber06Right/Slat12.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat09.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat10.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat11.actual.vMon", + "MchHvLvRight/Chamber07Right/Slat12.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat09.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat10.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat11.actual.vMon", + "MchHvLvRight/Chamber08Right/Slat12.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat00.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat01.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat02.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat03.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat04.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat05.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat06.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat07.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat08.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat09.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat10.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat11.actual.vMon", + "MchHvLvRight/Chamber09Right/Slat12.actual.vMon"}; + +std::vector<std::string> expectedHVAliasesCurrents = { + "MchHvLvLeft/Chamber00Left/Quad1Sect0.actual.iMon", + "MchHvLvLeft/Chamber00Left/Quad1Sect1.actual.iMon", + "MchHvLvLeft/Chamber00Left/Quad1Sect2.actual.iMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect0.actual.iMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect1.actual.iMon", + "MchHvLvLeft/Chamber00Left/Quad2Sect2.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect0.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect1.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad1Sect2.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect0.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect1.actual.iMon", + "MchHvLvLeft/Chamber01Left/Quad2Sect2.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect0.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect1.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad1Sect2.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect0.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect1.actual.iMon", + "MchHvLvLeft/Chamber02Left/Quad2Sect2.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect0.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect1.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad1Sect2.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect0.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect1.actual.iMon", + "MchHvLvLeft/Chamber03Left/Quad2Sect2.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber04Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber05Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat09.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat10.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat11.actual.iMon", + "MchHvLvLeft/Chamber06Left/Slat12.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat09.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat10.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat11.actual.iMon", + "MchHvLvLeft/Chamber07Left/Slat12.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat09.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat10.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat11.actual.iMon", + "MchHvLvLeft/Chamber08Left/Slat12.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat00.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat01.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat02.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat03.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat04.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat05.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat06.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat07.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat08.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat09.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat10.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat11.actual.iMon", + "MchHvLvLeft/Chamber09Left/Slat12.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad0Sect0.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad0Sect1.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad0Sect2.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad3Sect0.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad3Sect1.actual.iMon", + "MchHvLvRight/Chamber00Right/Quad3Sect2.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad0Sect0.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad0Sect1.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad0Sect2.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad3Sect0.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad3Sect1.actual.iMon", + "MchHvLvRight/Chamber01Right/Quad3Sect2.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad0Sect0.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad0Sect1.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad0Sect2.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad3Sect0.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad3Sect1.actual.iMon", + "MchHvLvRight/Chamber02Right/Quad3Sect2.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad0Sect0.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad0Sect1.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad0Sect2.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad3Sect0.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad3Sect1.actual.iMon", + "MchHvLvRight/Chamber03Right/Quad3Sect2.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber04Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber05Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat09.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat10.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat11.actual.iMon", + "MchHvLvRight/Chamber06Right/Slat12.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat09.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat10.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat11.actual.iMon", + "MchHvLvRight/Chamber07Right/Slat12.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat09.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat10.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat11.actual.iMon", + "MchHvLvRight/Chamber08Right/Slat12.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat00.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat01.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat02.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat03.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat04.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat05.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat06.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat07.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat08.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat09.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat10.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat11.actual.iMon", + "MchHvLvRight/Chamber09Right/Slat12.actual.iMon"}; diff --git a/Detectors/MUON/MCH/Conditions/test/HVAliases.h b/Detectors/MUON/MCH/Conditions/test/HVAliases.h new file mode 100644 index 0000000000000..ce756c7213332 --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/test/HVAliases.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_CONDITIONS_DCS_HV_ALIASES_H +#define O2_MCH_CONDITIONS_DCS_HV_ALIASES_H + +#include <vector> +#include <string> + +extern std::vector<std::string> expectedHVAliasesVoltages; +extern std::vector<std::string> expectedHVAliasesCurrents; + +#endif diff --git a/Detectors/MUON/MCH/Conditions/test/LVAliases.cxx b/Detectors/MUON/MCH/Conditions/test/LVAliases.cxx new file mode 100644 index 0000000000000..cd58c7cc98185 --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/test/LVAliases.cxx @@ -0,0 +1,354 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "LVAliases.h" + +std::vector<std::string> expectedLVAliasesFeeDigital = { + "MchHvLvLeft/Chamber00Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group06di.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group07di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group06di.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group07di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group06di.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group07di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group01di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group02di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group03di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group04di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group05di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group06di.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group07di.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group06di.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group07di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group06di.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group07di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group06di.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group07di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group01di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group02di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group03di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group04di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group05di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group06di.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group07di.SenseVoltage"}; + +std::vector<std::string> expectedLVAliasesFeeAnalog = { + + "MchHvLvLeft/Chamber00Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber00Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber01Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber02Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber03Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber04Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber05Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group06an.SenseVoltage", + "MchHvLvLeft/Chamber06Left/Group07an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group06an.SenseVoltage", + "MchHvLvLeft/Chamber07Left/Group07an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group06an.SenseVoltage", + "MchHvLvLeft/Chamber08Left/Group07an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group01an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group02an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group03an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group04an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group05an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group06an.SenseVoltage", + "MchHvLvLeft/Chamber09Left/Group07an.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber00Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber01Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber02Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber03Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber04Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber05Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group06an.SenseVoltage", + "MchHvLvRight/Chamber06Right/Group07an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group06an.SenseVoltage", + "MchHvLvRight/Chamber07Right/Group07an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group06an.SenseVoltage", + "MchHvLvRight/Chamber08Right/Group07an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group01an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group02an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group03an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group04an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group05an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group06an.SenseVoltage", + "MchHvLvRight/Chamber09Right/Group07an.SenseVoltage"}; + +std::vector<std::string> expectedLVAliasesSolar = { + "MchHvLvLeft/Chamber00Left/SolCh00LCr01.SenseVoltage", + "MchHvLvLeft/Chamber00Left/SolCh00LCr02.SenseVoltage", + "MchHvLvLeft/Chamber00Left/SolCh00LCr03.SenseVoltage", + "MchHvLvLeft/Chamber00Left/SolCh00LCr04.SenseVoltage", + "MchHvLvLeft/Chamber01Left/SolCh01LCr01.SenseVoltage", + "MchHvLvLeft/Chamber01Left/SolCh01LCr02.SenseVoltage", + "MchHvLvLeft/Chamber01Left/SolCh01LCr03.SenseVoltage", + "MchHvLvLeft/Chamber01Left/SolCh01LCr04.SenseVoltage", + "MchHvLvLeft/Chamber02Left/SolCh02LCr01.SenseVoltage", + "MchHvLvLeft/Chamber02Left/SolCh02LCr02.SenseVoltage", + "MchHvLvLeft/Chamber02Left/SolCh02LCr03.SenseVoltage", + "MchHvLvLeft/Chamber02Left/SolCh02LCr04.SenseVoltage", + "MchHvLvLeft/Chamber03Left/SolCh03LCr01.SenseVoltage", + "MchHvLvLeft/Chamber03Left/SolCh03LCr02.SenseVoltage", + "MchHvLvLeft/Chamber03Left/SolCh03LCr03.SenseVoltage", + "MchHvLvLeft/Chamber03Left/SolCh03LCr04.SenseVoltage", + + "MchHvLvLeft/Chamber04Left/SolCh04LCr01.SenseVoltage", + "MchHvLvLeft/Chamber04Left/SolCh04LCr02.SenseVoltage", + "MchHvLvLeft/Chamber04Left/SolCh04LCr03.SenseVoltage", + "MchHvLvLeft/Chamber04Left/SolCh04LCr04.SenseVoltage", + "MchHvLvLeft/Chamber04Left/SolCh04LCr05.SenseVoltage", + "MchHvLvLeft/Chamber05Left/SolCh05LCr01.SenseVoltage", + "MchHvLvLeft/Chamber05Left/SolCh05LCr02.SenseVoltage", + "MchHvLvLeft/Chamber05Left/SolCh05LCr03.SenseVoltage", + "MchHvLvLeft/Chamber05Left/SolCh05LCr04.SenseVoltage", + "MchHvLvLeft/Chamber05Left/SolCh05LCr05.SenseVoltage", + + "MchHvLvLeft/Chamber06Left/SolCh06LCr01.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr02.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr03.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr04.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr05.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr06.SenseVoltage", + "MchHvLvLeft/Chamber06Left/SolCh06LCr07.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr01.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr02.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr03.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr04.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr05.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr06.SenseVoltage", + "MchHvLvLeft/Chamber07Left/SolCh07LCr07.SenseVoltage", + + "MchHvLvLeft/Chamber08Left/SolCh08LCr01.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr02.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr03.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr04.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr05.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr06.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr07.SenseVoltage", + "MchHvLvLeft/Chamber08Left/SolCh08LCr08.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr01.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr02.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr03.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr04.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr05.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr06.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr07.SenseVoltage", + "MchHvLvLeft/Chamber09Left/SolCh09LCr08.SenseVoltage", + + "MchHvLvRight/Chamber00Right/SolCh00RCr01.SenseVoltage", + "MchHvLvRight/Chamber00Right/SolCh00RCr02.SenseVoltage", + "MchHvLvRight/Chamber00Right/SolCh00RCr03.SenseVoltage", + "MchHvLvRight/Chamber00Right/SolCh00RCr04.SenseVoltage", + "MchHvLvRight/Chamber01Right/SolCh01RCr01.SenseVoltage", + "MchHvLvRight/Chamber01Right/SolCh01RCr02.SenseVoltage", + "MchHvLvRight/Chamber01Right/SolCh01RCr03.SenseVoltage", + "MchHvLvRight/Chamber01Right/SolCh01RCr04.SenseVoltage", + "MchHvLvRight/Chamber02Right/SolCh02RCr01.SenseVoltage", + "MchHvLvRight/Chamber02Right/SolCh02RCr02.SenseVoltage", + "MchHvLvRight/Chamber02Right/SolCh02RCr03.SenseVoltage", + "MchHvLvRight/Chamber02Right/SolCh02RCr04.SenseVoltage", + "MchHvLvRight/Chamber03Right/SolCh03RCr01.SenseVoltage", + "MchHvLvRight/Chamber03Right/SolCh03RCr02.SenseVoltage", + "MchHvLvRight/Chamber03Right/SolCh03RCr03.SenseVoltage", + "MchHvLvRight/Chamber03Right/SolCh03RCr04.SenseVoltage", + + "MchHvLvRight/Chamber04Right/SolCh04RCr01.SenseVoltage", + "MchHvLvRight/Chamber04Right/SolCh04RCr02.SenseVoltage", + "MchHvLvRight/Chamber04Right/SolCh04RCr03.SenseVoltage", + "MchHvLvRight/Chamber04Right/SolCh04RCr04.SenseVoltage", + "MchHvLvRight/Chamber04Right/SolCh04RCr05.SenseVoltage", + "MchHvLvRight/Chamber05Right/SolCh05RCr01.SenseVoltage", + "MchHvLvRight/Chamber05Right/SolCh05RCr02.SenseVoltage", + "MchHvLvRight/Chamber05Right/SolCh05RCr03.SenseVoltage", + "MchHvLvRight/Chamber05Right/SolCh05RCr04.SenseVoltage", + "MchHvLvRight/Chamber05Right/SolCh05RCr05.SenseVoltage", + + "MchHvLvRight/Chamber06Right/SolCh06RCr01.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr02.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr03.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr04.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr05.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr06.SenseVoltage", + "MchHvLvRight/Chamber06Right/SolCh06RCr07.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr01.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr02.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr03.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr04.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr05.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr06.SenseVoltage", + "MchHvLvRight/Chamber07Right/SolCh07RCr07.SenseVoltage", + + "MchHvLvRight/Chamber08Right/SolCh08RCr01.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr02.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr03.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr04.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr05.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr06.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr07.SenseVoltage", + "MchHvLvRight/Chamber08Right/SolCh08RCr08.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr01.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr02.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr03.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr04.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr05.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr06.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr07.SenseVoltage", + "MchHvLvRight/Chamber09Right/SolCh09RCr08.SenseVoltage"}; diff --git a/Detectors/MUON/MCH/Conditions/test/LVAliases.h b/Detectors/MUON/MCH/Conditions/test/LVAliases.h new file mode 100644 index 0000000000000..83cec1dc95f5e --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/test/LVAliases.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_CONDITIONS_DCS_LV_ALIASES_H +#define O2_MCH_CONDITIONS_DCS_LV_ALIASES_H + +#include <vector> +#include <string> + +extern std::vector<std::string> expectedLVAliasesFeeAnalog; +extern std::vector<std::string> expectedLVAliasesFeeDigital; +extern std::vector<std::string> expectedLVAliasesSolar; + +#endif diff --git a/Detectors/MUON/MCH/Conditions/test/testDCSNamer.cxx b/Detectors/MUON/MCH/Conditions/test/testDCSNamer.cxx new file mode 100644 index 0000000000000..02984214855dd --- /dev/null +++ b/Detectors/MUON/MCH/Conditions/test/testDCSNamer.cxx @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHConditions DCSNamer +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "MCHConditions/DCSNamer.h" +#include "HVAliases.h" +#include "LVAliases.h" +#include <algorithm> +#include <fmt/format.h> + +using namespace o2::mch::dcs; + +BOOST_AUTO_TEST_SUITE(o2_mch_conditions) + +BOOST_AUTO_TEST_SUITE(dcsnamer) + +BOOST_AUTO_TEST_CASE(detElemId2DCSMustReturnNothingIfDetElemIdIsNotValid) +{ + BOOST_CHECK_EQUAL(detElemId2DCS(0).has_value(), false); + BOOST_CHECK_EQUAL(detElemId2DCS(10).has_value(), false); + BOOST_CHECK_EQUAL(detElemId2DCS(1026).has_value(), false); + BOOST_CHECK_EQUAL(detElemId2DCS(-1).has_value(), false); +} + +BOOST_AUTO_TEST_CASE(DE100isRight) +{ + BOOST_CHECK(detElemId2DCS(100)->side == Side::Right); +} +BOOST_AUTO_TEST_CASE(DE102isLeft) +{ + BOOST_CHECK(detElemId2DCS(102)->side == Side::Left); +} + +BOOST_AUTO_TEST_CASE(detElemId2DCSMustReturnChamberIdAndSideIfDetElemIdIsValid) +{ + auto v = detElemId2DCS(1025); + BOOST_CHECK_EQUAL(v.has_value(), true); + BOOST_CHECK_EQUAL(v->chamberId, 9); + BOOST_CHECK(v->side == Side::Right); +} + +BOOST_AUTO_TEST_CASE(NumberOfHVAliasesVoltagesIs188) +{ + auto result = aliases({MeasurementType::HV_V}); + BOOST_CHECK_EQUAL(result.size(), expectedHVAliasesVoltages.size()); + BOOST_CHECK_EQUAL(188, expectedHVAliasesVoltages.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedHVAliasesVoltages)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(NumberOfHVAliasesCurrentsIs188) +{ + auto result = aliases({MeasurementType::HV_I}); + BOOST_CHECK_EQUAL(result.size(), expectedHVAliasesCurrents.size()); + BOOST_CHECK_EQUAL(188, expectedHVAliasesCurrents.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedHVAliasesCurrents)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(NumberOfLVAliasesFeeAnalogIs108) +{ + auto result = aliases({MeasurementType::LV_V_FEE_ANALOG}); + BOOST_CHECK_EQUAL(result.size(), expectedLVAliasesFeeAnalog.size()); + BOOST_CHECK_EQUAL(108, expectedLVAliasesFeeAnalog.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedLVAliasesFeeAnalog)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(NumberOfLVAliasesFeeDigitalIs108) +{ + auto result = aliases({MeasurementType::LV_V_FEE_DIGITAL}); + BOOST_CHECK_EQUAL(result.size(), expectedLVAliasesFeeDigital.size()); + BOOST_CHECK_EQUAL(108, expectedLVAliasesFeeDigital.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedLVAliasesFeeDigital)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(NumberOfLVAliasesSolarIs112) +{ + auto result = aliases({MeasurementType::LV_V_SOLAR}); + BOOST_CHECK_EQUAL(result.size(), expectedLVAliasesSolar.size()); + BOOST_CHECK_EQUAL(112, expectedLVAliasesSolar.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedLVAliasesSolar)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(AliasNameIsShortEnough) +{ + auto result = aliases(); + std::map<size_t, int> sizes; + constexpr size_t maxLen{62}; + for (auto& a : result) { + sizes[a.size()]++; + if (a.size() > maxLen) { + std::cout << fmt::format("Alias is too long : {:2d} characters, while {:2d} max are allowed : {}\n", + a.size(), maxLen, a); + } + } + size_t len{0}; + + for (auto p : sizes) { + std::cout << fmt::format("{:3d} aliases of size {:2d}\n", + p.second, p.first); + len = std::max(len, p.first); + } + BOOST_CHECK(len <= 62); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Contour/CMakeLists.txt b/Detectors/MUON/MCH/Contour/CMakeLists.txt index bef75cce0587b..c6ca3b82c39b9 100644 --- a/Detectors/MUON/MCH/Contour/CMakeLists.txt +++ b/Detectors/MUON/MCH/Contour/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(MCHContour) diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/BBox.h b/Detectors/MUON/MCH/Contour/include/MCHContour/BBox.h index 542d810afe77c..bec5ddb63cd02 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/BBox.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/BBox.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Contour.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Contour.h index c271467a4a4ca..3f0c85d71f647 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Contour.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Contour.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.h b/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.h index 890b998ddb760..a600749d210b6 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.inl b/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.inl index 67f8e141f8bf3..6d827e2fc5f93 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.inl +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/ContourCreator.inl @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Edge.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Edge.h index fc6936bd05b15..89b95e69a9fa2 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Edge.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Edge.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Helper.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Helper.h index 50e89e62d9608..87f52835e0ab3 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Helper.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Helper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Interval.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Interval.h index 41d8ad01de501..63ef1a70a86b4 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Interval.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Interval.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Polygon.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Polygon.h index e42ad8b005fce..f2c5c1158f072 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Polygon.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Polygon.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/SVGWriter.h b/Detectors/MUON/MCH/Contour/include/MCHContour/SVGWriter.h index e9cf3a0544a57..dec93eb5622d0 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/SVGWriter.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/SVGWriter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/SegmentTree.h b/Detectors/MUON/MCH/Contour/include/MCHContour/SegmentTree.h index 172dcf89cbf68..ad072aa373825 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/SegmentTree.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/SegmentTree.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/include/MCHContour/Vertex.h b/Detectors/MUON/MCH/Contour/include/MCHContour/Vertex.h index f7691d1f5bd48..484a42f1e02b3 100644 --- a/Detectors/MUON/MCH/Contour/include/MCHContour/Vertex.h +++ b/Detectors/MUON/MCH/Contour/include/MCHContour/Vertex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/BBox.cxx b/Detectors/MUON/MCH/Contour/test/BBox.cxx index c765ba22f7084..6ccce3a3db2c7 100644 --- a/Detectors/MUON/MCH/Contour/test/BBox.cxx +++ b/Detectors/MUON/MCH/Contour/test/BBox.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/Contour.cxx b/Detectors/MUON/MCH/Contour/test/Contour.cxx index 05d89bfcb55ed..710598ede487e 100644 --- a/Detectors/MUON/MCH/Contour/test/Contour.cxx +++ b/Detectors/MUON/MCH/Contour/test/Contour.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/ContourCreator.cxx b/Detectors/MUON/MCH/Contour/test/ContourCreator.cxx index ae19e93a3a8aa..a8e10bcba384d 100644 --- a/Detectors/MUON/MCH/Contour/test/ContourCreator.cxx +++ b/Detectors/MUON/MCH/Contour/test/ContourCreator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/Edge.cxx b/Detectors/MUON/MCH/Contour/test/Edge.cxx index ccb14da6b69b3..168d42ddfc307 100644 --- a/Detectors/MUON/MCH/Contour/test/Edge.cxx +++ b/Detectors/MUON/MCH/Contour/test/Edge.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/Interval.cxx b/Detectors/MUON/MCH/Contour/test/Interval.cxx index d35b007d50296..e6028f25e2e98 100644 --- a/Detectors/MUON/MCH/Contour/test/Interval.cxx +++ b/Detectors/MUON/MCH/Contour/test/Interval.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/Polygon.cxx b/Detectors/MUON/MCH/Contour/test/Polygon.cxx index 1f2b9b8d4226e..9cfae0c720b29 100644 --- a/Detectors/MUON/MCH/Contour/test/Polygon.cxx +++ b/Detectors/MUON/MCH/Contour/test/Polygon.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/SegmentTree.cxx b/Detectors/MUON/MCH/Contour/test/SegmentTree.cxx index 3b6d680bcb590..a5daf8df8645a 100644 --- a/Detectors/MUON/MCH/Contour/test/SegmentTree.cxx +++ b/Detectors/MUON/MCH/Contour/test/SegmentTree.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Contour/test/Vertex.cxx b/Detectors/MUON/MCH/Contour/test/Vertex.cxx index 8a53a0011e943..30f820ef730b2 100644 --- a/Detectors/MUON/MCH/Contour/test/Vertex.cxx +++ b/Detectors/MUON/MCH/Contour/test/Vertex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/DevIO/CMakeLists.txt b/Detectors/MUON/MCH/DevIO/CMakeLists.txt new file mode 100644 index 0000000000000..3001c21ea1312 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(Digits) diff --git a/Detectors/MUON/MCH/DevIO/Digits/CMakeLists.txt b/Detectors/MUON/MCH/DevIO/Digits/CMakeLists.txt new file mode 100644 index 0000000000000..8dcd04f895b81 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MCHDigitIO + SOURCES DigitWriter.cxx DigitReader.cxx DigitFileFormat.cxx + DigitReaderImpl.cxx DigitWriterImpl.cxx + DigitIOV0.cxx DigitIOV1.cxx + DigitIOV2.cxx DigitIOV3.cxx + DigitIOV4.cxx + IO.cxx + PUBLIC_LINK_LIBRARIES Microsoft.GSL::GSL fmt::fmt O2::DataFormatsMCH) + +o2_add_test(digits-io + SOURCES testDigitIO.cxx + COMPONENT_NAME mch + LABELS muon;mch + PUBLIC_LINK_LIBRARIES O2::MCHDigitIO) + +o2_add_test(digits-io-v0 + SOURCES testDigitIOV0.cxx TestFileV0.cxx + COMPONENT_NAME mch + LABELS muon;mch + PUBLIC_LINK_LIBRARIES O2::MCHDigitIO) + +o2_add_executable(digits-r23-workflow + SOURCES digits-r23-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH + O2::MCHBase O2::MCHMappingImpl3) + +add_library(MCHDigitIOBaseTask OBJECT) +add_library(O2::MCHDigitIOBaseTask ALIAS MCHDigitIOBaseTask) +target_link_libraries(MCHDigitIOBaseTask PUBLIC O2::DataFormatsMCH O2::Framework) + +target_sources(MCHDigitIOBaseTask PRIVATE DigitIOBaseTask.cxx) + +o2_add_executable( + digits-writer-workflow + SOURCES digits-writer-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::DPLUtils Boost::program_options + O2::MCHBase O2::MCHRawDecoder + O2::MCHDigitIO O2::MCHDigitIOBaseTask) + +o2_add_executable( + digits-file-reader-workflow + SOURCES digits-file-reader-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHBase O2::MCHDigitIO O2::MCHDigitIOBaseTask) + +o2_add_executable( + digits-random-generator-workflow + SOURCES digits-random-generator-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHBase O2::MCHMappingImpl4 O2::MCHDigitIO O2::MCHDigitIOBaseTask) + +o2_add_executable( + digits-file-dumper + SOURCES digits-file-dumper.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHDigitIO O2::MCHMappingImpl3 Boost::program_options) + diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitD0.h b/Detectors/MUON/MCH/DevIO/Digits/DigitD0.h new file mode 100644 index 0000000000000..8083ab3608b19 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitD0.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_D0_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_D0_H + +#include <fstream> +#include <vector> + +namespace o2::mch::io::impl +{ +struct DigitD0 { + int32_t tfTime{0}; /// time since the beginning of the time frame, in bunch crossing units + uint16_t nofSamples{0}; /// number of samples in the signal + saturated bit + int detID{0}; /// ID of the Detection Element to which the digit corresponds to + int padID{0}; /// PadIndex to which the digit corresponds to + uint32_t adc{0}; /// Amplitude of signal + + void setNofSamples(uint16_t n) { nofSamples = (nofSamples & 0x8000) + (n & 0x7FFF); } + uint16_t getNofSamples() const { return (nofSamples & 0x7FFF); } + + void setSaturated(bool sat) { nofSamples = sat ? nofSamples | 0x8000 : nofSamples & 0x7FFF; } + bool isSaturated() const { return ((nofSamples & 0x8000) > 0); } +}; + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.cxx new file mode 100644 index 0000000000000..df95bf650d999 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.cxx @@ -0,0 +1,79 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitFileFormat.h" +#include <fmt/format.h> +#include <iostream> +#include <algorithm> +#include <string> +#include <stdexcept> + +namespace o2::mch::io +{ + +std::array<DigitFileFormat, 5> digitFileFormats = { + DigitFileFormat{2305844383603244847}, /* v0 */ + DigitFileFormat{1224998065220435759}, /* v1 */ + DigitFileFormat{63069292639436591}, /* v2 */ + DigitFileFormat{1215990797246349103}, /* v3 */ + DigitFileFormat{1234022787941941039}}; /* v4 */ + +std::ostream& operator<<(std::ostream& os, const DigitFileFormat& dff) +{ + os << fmt::format( + "[ file version {} digit version {} size {} " + "rof version {} size {} hasRof {} run2ids {} ] formatWord {}", + dff.fileVersion, + dff.digitVersion, + dff.digitSize, + dff.rofVersion, + dff.rofSize, + static_cast<bool>(dff.hasRof), + static_cast<bool>(dff.run2ids), + dff.format); + return os; +} + +bool operator==(const DigitFileFormat& dff1, const DigitFileFormat& dff2) +{ + return dff1.format == dff2.format; +} + +bool operator!=(const DigitFileFormat& dff1, const DigitFileFormat& dff2) +{ + return !(dff1 == dff2); +} + +/* Read the file format from the stream. +* +* Every digit file should start with 8 bytes of format identifier. +*/ +DigitFileFormat readDigitFileFormat(std::istream& in) +{ + uint64_t fileFormat{0}; + in.read(reinterpret_cast<char*>(&fileFormat), sizeof(uint64_t)); + if (in.gcount() < sizeof(DigitFileFormat)) { + throw std::ios_base::failure("could not get a valid digit file format in this stream (too short)"); + } + DigitFileFormat df{fileFormat}; + if (!isValid(df)) { + throw std::ios_base::failure("could not get a valid digit file format in this stream"); + } + return df; +} + +bool isValid(DigitFileFormat dff) +{ + auto exists = std::find(digitFileFormats.begin(), + digitFileFormats.end(), dff); + return exists != digitFileFormats.end(); +} +} // namespace o2::mch::io diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.h b/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.h new file mode 100644 index 0000000000000..b4f9e4f31d358 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitFileFormat.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_FILE_FORMAT_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_FILE_FORMAT_H + +#include <cstdint> +#include <iosfwd> +#include <array> + +namespace o2::mch::io +{ + +constexpr uint64_t TAG_DIGITS = 0x3F2F; // = 016175 = 0.1.6.1.7.5 = D.I.G.I.T.S + +struct DigitFileFormat { + union { + uint64_t format = TAG_DIGITS; + struct { + uint64_t tag : 16; + uint64_t fileVersion : 8; + uint64_t reserved : 4; + uint64_t digitVersion : 8; + uint64_t digitSize : 8; + uint64_t rofVersion : 8; + uint64_t rofSize : 8; + uint64_t hasRof : 1; + uint64_t run2ids : 1; + }; + }; +}; + +extern std::array<DigitFileFormat, 5> digitFileFormats; + +std::ostream& operator<<(std::ostream&, const DigitFileFormat&); + +bool operator==(const DigitFileFormat& dff1, const DigitFileFormat& dff2); +bool operator!=(const DigitFileFormat& dff1, const DigitFileFormat& dff2); + +DigitFileFormat readDigitFileFormat(std::istream& in); + +bool isValid(DigitFileFormat dff); + +} // namespace o2::mch::io +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIO.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIO.h new file mode 100644 index 0000000000000..64e39b673cb19 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIO.h @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_H + +#include "DigitReader.h" +#include "DigitWriter.h" + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.cxx new file mode 100644 index 0000000000000..83b281a98a02f --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitIOBaseTask.h" +#include "DigitWriter.h" +#include <fmt/format.h> +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/Logger.h" +#include "Framework/Variant.h" +#include "ProgOptions.h" +#include <iostream> +#include <sstream> +#include <string> + +using namespace o2::framework; + +namespace o2::mch::io +{ +void DigitIOBaseTask::init(InitContext& ic) +{ + mMaxNofTimeFrames = ic.options().get<int>(OPTNAME_MAX_NOF_TFS); + mFirstTF = ic.options().get<int>(OPTNAME_FIRST_TF); + mNofProcessedTFs = 0; + mPrintDigits = ic.options().get<bool>(OPTNAME_PRINT_DIGITS); + mPrintTFs = ic.options().get<bool>(OPTNAME_PRINT_TFS); + if (mPrintDigits || mPrintTFs) { + fair::Logger::SetConsoleColor(true); + } +} + +void DigitIOBaseTask::printFull(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) const +{ + if (mPrintDigits) { + std::stringstream str; + o2::mch::io::DigitWriter dw(str); + dw.write(digits, rofs); + for (std::string line; std::getline(str, line);) { + LOG(INFO) << line; + } + } +} + +void DigitIOBaseTask::printSummary(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs, + const char* suffix) const +{ + if (mPrintTFs) { + LOGP(INFO, "TF {:5d} {:4d} rofs - {:6d} digits - {}", mTFid, rofs.size(), digits.size(), suffix); + } +} + +bool DigitIOBaseTask::shouldProcess() const +{ + return (mTFid >= mFirstTF && mNofProcessedTFs < mMaxNofTimeFrames); +} + +void DigitIOBaseTask::incNofProcessedTFs() +{ + ++mNofProcessedTFs; +} + +void DigitIOBaseTask::incTFid() +{ + ++mTFid; +} + +std::vector<ConfigParamSpec> getCommonOptions() +{ + return { + {OPTNAME_MAX_NOF_TFS, VariantType::Int, std::numeric_limits<int>::max(), {OPTHELP_MAX_NOF_TFS}}, + {OPTNAME_FIRST_TF, VariantType::Int, 0, {OPTHELP_FIRST_TF}}, + {OPTNAME_PRINT_DIGITS, VariantType::Bool, false, {OPTHELP_PRINT_DIGITS}}, + {OPTNAME_PRINT_TFS, VariantType::Bool, false, {OPTHELP_PRINT_TFS}}}; +} + +} // namespace o2::mch::io diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.h new file mode 100644 index 0000000000000..3967995132617 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOBaseTask.h @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_BASE_TASK_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_BASE_TASK_H + +#include "Framework/ConfigParamSpec.h" +#include <cstdint> +#include <gsl/span> +#include <numeric> +#include <vector> + +namespace o2::framework +{ +class InitContext; +} // namespace o2::framework + +namespace o2::mch +{ +class Digit; +class ROFRecord; +}; // namespace o2::mch + +namespace o2::mch::io +{ + +/** + * DigitIOBaseTask implements the commonalities between reader and writer + * tasks, like the handling of the common options. + */ + +class DigitIOBaseTask +{ + protected: + size_t mMaxNofTimeFrames{std::numeric_limits<size_t>::max()}; // max number of timeframes to process + size_t mNofProcessedTFs{0}; // actual number of timeframes processed so far + size_t mFirstTF{0}; // first timeframe to process + size_t mTFid{0}; // current timeframe index + bool mPrintDigits = false; // print digits + bool mPrintTFs = false; // print number of rofs and digits per tf + + public: + /** + * Init data members from options + */ + void init(o2::framework::InitContext& ic); + + /** + * Make a full screen dump of the digits and rofs arrays. + */ + void printFull(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) const; + + /** + * Make a brief screen dump of the digits and rofs arrays (just showing + * number of items in each) + */ + void printSummary(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs, + const char* suffix = "") const; + + /** + * Decide, depending on the current TFid being processed, if it should + * be processed or not. + */ + bool shouldProcess() const; + + /** + * Increment the number of timeframes that have been processed so far. + */ + void incNofProcessedTFs(); + + /** + * Increment the timeframe id (last one that has been processed). + */ + void incTFid(); +}; + +/** + * Define commonly used options, like max number of tfs, first tf, etc... + */ +std::vector<o2::framework::ConfigParamSpec> getCommonOptions(); + +} // namespace o2::mch::io +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.cxx new file mode 100644 index 0000000000000..07a97ee922f7b --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.cxx @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitIOV0.h" +#include "DigitD0.h" +#include <stdexcept> +#include <vector> +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <iostream> +#include <fmt/format.h> +#include "DigitFileFormat.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "IOStruct.h" + +// +// V0 was prior to the introduction of rofs, so the file format is +// simply a set of consecutive [nofDigits|list of digits] blocks +// + +namespace o2::mch::io::impl +{ +void DigitReaderV0::count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) +{ + rewind(in); + ndigits = 0; + nrofs = 0; + ntfs = 0; + int ndig{0}; + auto dff = digitFileFormats[0]; + + while ((ndig = advance(in, dff.digitSize, "digits")) >= 0) { + ndigits += ndig; + ++nrofs; + ++ntfs; + } + rewind(in); +} + +bool DigitReaderV0::read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + // note the input vectors are not cleared as this is the responsability + // of the calling class, if need be. + std::vector<DigitD0> digitsd0; + bool ok = readBinaryStruct(in, digitsd0, "digits"); + if (!ok) { + return false; + } + + for (auto d0 : digitsd0) { + Digit d(d0.detID, d0.padID, d0.adc, d0.tfTime, d0.getNofSamples(), d0.isSaturated()); + digits.push_back(d); + } + + rofs.emplace_back(o2::InteractionRecord(0, mCurrentROF), 0, digits.size()); + ++mCurrentROF; + return true; +} + +void DigitReaderV0::rewind(std::istream& in) +{ + DigitReaderImpl::rewind(in); + mCurrentROF = 0; +} + +bool DigitWriterV0::write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + // V0 format had no notion of rofs, so we strip them + for (auto r : rofs) { + std::vector<DigitD0> digitsd0; + for (int i = r.getFirstIdx(); i <= r.getLastIdx(); i++) { + const Digit& d = digits[i]; + digitsd0.push_back(DigitD0{d.getTime(), d.getNofSamples(), d.getDetID(), d.getPadID(), d.getADC()}); + digitsd0.back().setSaturated(d.isSaturated()); + } + gsl::span<const DigitD0> d0(digitsd0); + bool ok = writeBinaryStruct(out, d0); + if (!ok) { + return false; + } + } + return true; +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.h new file mode 100644 index 0000000000000..2998c423bbb38 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV0.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_H + +#include "DigitReaderImpl.h" +#include "DigitWriterImpl.h" +#include <utility> +#include <vector> + +/* + * Digit file format 0 is storing Digits version D0 + * with no ROF (i.e. just a set of nDigits|DigitsD0|...) + */ + +namespace o2::mch::io::impl +{ +/** + * Reader for digit file format 0 + */ +class DigitReaderV0 : public DigitReaderImpl +{ + public: + void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) override; + bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) override; + void rewind(std::istream& in); + + private: + int mCurrentROF{0}; +}; + +/** + * Writer for digit file format 0 + */ +struct DigitWriterV0 : public DigitWriterImpl { + + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) override; + + bool mBinary; +}; + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.cxx new file mode 100644 index 0000000000000..b51f02a33448c --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.cxx @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitIOV1.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitD0.h" +#include "DigitFileFormat.h" +#include "DigitReader.h" +#include "IO.h" +#include "IOStruct.h" +#include "ROFRecordR0.h" +#include <iostream> + +namespace o2::mch::io::impl +{ +void DigitReaderV1::count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) +{ + rewind(in); + ndigits = 0; + nrofs = 0; + ntfs = 0; + std::pair<int, int> pairs; + std::pair<int, int> invalid{-1, -1}; + + while ((pairs = advanceOneEvent(in, 1)) != invalid) { + ndigits += pairs.second; + nrofs += pairs.first; + ++ntfs; + } + rewind(in); +} + +bool DigitReaderV1::read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + // note the input vectors are not cleared as this is the responsability + // of the calling class, if need be. + + std::vector<ROFRecordR0> rofsr0; + + bool ok = readBinaryStruct(in, rofsr0, "rofs"); + if (!ok) { + return false; + } + for (auto r0 : rofsr0) { + ROFRecord r(r0.ir, r0.ref.getFirstEntry(), r0.ref.getEntries(), 4); + rofs.push_back(r); + } + + std::vector<DigitD0> digitsd0; + + ok = readBinaryStruct(in, digitsd0, "digits"); + if (!ok) { + return false; + } + + for (auto d0 : digitsd0) { + Digit d(d0.detID, d0.padID, d0.adc, d0.tfTime, d0.getNofSamples(), d0.isSaturated()); + digits.push_back(d); + } + return true; +} + +void DigitReaderV1::rewind(std::istream& in) +{ + DigitReaderImpl::rewind(in); +} + +bool DigitWriterV1::write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + if (rofs.empty()) { + return false; + } + std::vector<ROFRecordR0> rofsr0; + for (const auto& r : rofs) { + rofsr0.push_back(ROFRecordR0{r.getBCData(), {r.getFirstIdx(), r.getNEntries()}}); + } + gsl::span<const ROFRecordR0> r0(rofsr0); + + bool ok = writeBinaryStruct(out, r0); + + std::vector<DigitD0> digitsd0; + for (const auto& d : digits) { + digitsd0.push_back(DigitD0{d.getTime(), d.getNofSamples(), d.getDetID(), d.getPadID(), d.getADC()}); + digitsd0.back().setSaturated(d.isSaturated()); + } + gsl::span<const DigitD0> d0(digitsd0); + ok &= writeBinaryStruct(out, d0); + return ok; +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.h new file mode 100644 index 0000000000000..a5cab602fee4a --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV1.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_V1_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_V1_H + +#include "DigitReaderImpl.h" +#include <vector> +#include "DataFormatsMCH/ROFRecord.h" +#include <utility> +#include "DigitWriterImpl.h" + +namespace o2::mch::io::impl +{ +class DigitReaderV1 : public DigitReaderImpl +{ + public: + void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) override; + bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) override; + void rewind(std::istream& in); +}; + +struct DigitWriterV1 : public DigitWriterImpl { + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) override; +}; + +} // namespace o2::mch::io::impl +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.cxx new file mode 100644 index 0000000000000..385320fc91635 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.cxx @@ -0,0 +1,111 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitIOV2.h" +#include <stdexcept> +#include <vector> +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <iostream> +#include <fmt/format.h> +#include "DigitFileFormat.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "IO.h" + +// +// V2 was prior to the introduction of rofs, so the file format is +// simply a set of consecutive [nofDigits|list of digits] blocks +// + +namespace o2::mch::io::impl +{ +void DigitReaderV2::count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) +{ + auto dff = digitFileFormats[2]; + rewind(in); + ndigits = 0; + nrofs = 0; + ntfs = 0; + int ndig{0}; + + while ((ndig = advance(in, dff.digitSize, "digits")) >= 0) { + ndigits += ndig; + ++nrofs; + ++ntfs; + } + rewind(in); +} + +bool DigitReaderV2::read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + if (in.peek() == EOF) { + return false; + } + // note the input vectors are not cleared as this is the responsability + // of the calling class, if need be. + int ndigits = readNofItems(in, "digits"); + + for (int i = 0; i < ndigits; i++) { + uint32_t tfTime; + uint16_t nofSamples; + uint8_t sat; + uint32_t deID; + uint32_t padID; + uint32_t adc; + in.read(reinterpret_cast<char*>(&tfTime), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&nofSamples), sizeof(uint16_t)); + in.read(reinterpret_cast<char*>(&sat), sizeof(uint8_t)); + in.read(reinterpret_cast<char*>(&deID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&padID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&adc), sizeof(uint32_t)); + digits.emplace_back(deID, padID, adc, tfTime, nofSamples, sat > 0); + } + + rofs.emplace_back(o2::InteractionRecord(0, mCurrentROF), 0, ndigits); + ++mCurrentROF; + return !in.fail(); +} + +void DigitReaderV2::rewind(std::istream& in) +{ + DigitReaderImpl::rewind(in); + mCurrentROF = 0; +} + +bool DigitWriterV2::write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + // V2 format had no notion of rofs, so we strip them + for (auto r : rofs) { + writeNofItems(out, r.getNEntries()); + for (int i = r.getFirstIdx(); i <= r.getLastIdx(); i++) { + const Digit& d = digits[i]; + uint32_t tfTime = d.getTime(); + uint16_t nofSamples = d.getNofSamples(); + uint32_t deID = d.getDetID(); + uint32_t padID = d.getPadID(); + uint32_t adc = d.getADC(); + uint8_t sat = d.isSaturated(); + out.write(reinterpret_cast<const char*>(&tfTime), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&nofSamples), sizeof(uint16_t)); + out.write(reinterpret_cast<const char*>(&sat), sizeof(uint8_t)); + out.write(reinterpret_cast<const char*>(&deID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&padID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&adc), sizeof(uint32_t)); + } + } + return !out.fail(); +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.h new file mode 100644 index 0000000000000..8794750913e80 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV2.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_V2_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_V2_H + +#include "DigitReaderImpl.h" +#include "DigitWriterImpl.h" +#include <utility> +#include <vector> + +/* + * Digit file format 0 is storing Digits version D0 + * with no ROF (i.e. just a set of nDigits|DigitsD0|...) + */ + +namespace o2::mch::io::impl +{ +/** + * Reader for digit file format 0 + */ +class DigitReaderV2 : public DigitReaderImpl +{ + public: + void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) override; + bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) override; + void rewind(std::istream& in); + + private: + int mCurrentROF{0}; +}; + +/** + * Writer for digit file format 0 + */ +struct DigitWriterV2 : public DigitWriterImpl { + + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) override; + + bool mBinary; +}; + +} // namespace o2::mch::io::impl +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.cxx new file mode 100644 index 0000000000000..39f922df3df3a --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.cxx @@ -0,0 +1,151 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitIOV3.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitFileFormat.h" +#include "DigitReader.h" +#include "IO.h" +#include "IOStruct.h" +#include <iostream> + +namespace o2::mch::io::impl +{ + +void DigitReaderV3::count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) +{ + rewind(in); + ndigits = 0; + nrofs = 0; + ntfs = 0; + std::pair<int, int> pairs; + std::pair<int, int> invalid{-1, -1}; + + while ((pairs = advanceOneEvent(in, 3)) != invalid) { + ndigits += pairs.second; + nrofs += pairs.first; + ++ntfs; + } + rewind(in); +} + +bool DigitReaderV3::read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + if (in.peek() == EOF) { + return false; + } + // note the input vectors are not cleared as this is the responsability + // of the calling class, if need be. + + int nrofs = readNofItems(in, "rofs"); + if (in.fail()) { + return false; + } + + for (auto i = 0; i < nrofs; i++) { + uint16_t bc; + uint32_t orbit; + uint32_t firstIdx; + uint32_t nentries; + in.read(reinterpret_cast<char*>(&bc), sizeof(uint16_t)); + in.read(reinterpret_cast<char*>(&orbit), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&firstIdx), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&nentries), sizeof(uint32_t)); + rofs.emplace_back(o2::InteractionRecord{bc, orbit}, firstIdx, nentries); + if (in.fail()) { + return false; + } + } + + int ndigits = readNofItems(in, "digits"); + if (in.fail()) { + return false; + } + + for (int i = 0; i < ndigits; i++) { + uint32_t tfTime; + uint16_t nofSamples; + uint32_t deID; + uint32_t padID; + uint32_t adc; + uint8_t sat; + in.read(reinterpret_cast<char*>(&tfTime), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&nofSamples), sizeof(uint16_t)); + in.read(reinterpret_cast<char*>(&sat), sizeof(uint8_t)); + in.read(reinterpret_cast<char*>(&deID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&padID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&adc), sizeof(uint32_t)); + digits.emplace_back(deID, padID, adc, tfTime, nofSamples, sat > 0); + if (in.fail()) { + return false; + } + } + return true; +} + +void DigitReaderV3::rewind(std::istream& in) +{ + DigitReaderImpl::rewind(in); +} + +bool DigitWriterV3::write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + if (rofs.empty()) { + return false; + } + writeNofItems(out, rofs.size()); + if (out.fail()) { + return false; + } + for (auto r : rofs) { + uint16_t bc = r.getBCData().bc; + uint32_t orbit = r.getBCData().orbit; + uint32_t firstIdx = r.getFirstIdx(); + uint32_t nentries = r.getNEntries(); + out.write(reinterpret_cast<const char*>(&bc), sizeof(uint16_t)); + out.write(reinterpret_cast<const char*>(&orbit), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&firstIdx), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&nentries), sizeof(uint32_t)); + if (out.fail()) { + return false; + } + } + + writeNofItems(out, digits.size()); + if (out.fail()) { + return false; + } + for (const auto& d : digits) { + uint32_t tfTime = d.getTime(); + uint16_t nofSamples = d.getNofSamples(); + uint32_t deID = d.getDetID(); + uint32_t padID = d.getPadID(); + uint32_t adc = d.getADC(); + uint8_t sat = d.isSaturated(); + out.write(reinterpret_cast<const char*>(&tfTime), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&nofSamples), sizeof(uint16_t)); + out.write(reinterpret_cast<const char*>(&sat), sizeof(uint8_t)); + out.write(reinterpret_cast<const char*>(&deID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&padID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&adc), sizeof(uint32_t)); + if (out.fail()) { + return false; + } + } + return true; +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.h new file mode 100644 index 0000000000000..344544ec6326e --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV3.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_V3_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_V3_H + +#include "DigitReaderImpl.h" +#include <vector> +#include "DataFormatsMCH/ROFRecord.h" +#include <utility> +#include "DigitWriterImpl.h" + +namespace o2::mch::io::impl +{ +class DigitReaderV3 : public DigitReaderImpl +{ + public: + void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) override; + bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) override; + void rewind(std::istream& in); +}; + +struct DigitWriterV3 : public DigitWriterImpl { + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) override; +}; + +} // namespace o2::mch::io::impl +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.cxx new file mode 100644 index 0000000000000..0af0b8330c505 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.cxx @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitIOV4.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitFileFormat.h" +#include "DigitReader.h" +#include "IO.h" +#include "IOStruct.h" +#include <iostream> + +namespace o2::mch::io::impl +{ + +void DigitReaderV4::count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) +{ + rewind(in); + ndigits = 0; + nrofs = 0; + ntfs = 0; + std::pair<int, int> pairs; + std::pair<int, int> invalid{-1, -1}; + + while ((pairs = advanceOneEvent(in, 4)) != invalid) { + ndigits += pairs.second; + nrofs += pairs.first; + ++ntfs; + } + rewind(in); +} + +bool DigitReaderV4::read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + if (in.peek() == EOF) { + return false; + } + // note the input vectors are not cleared as this is the responsability + // of the calling class, if need be. + + int nrofs = readNofItems(in, "rofs"); + if (in.fail()) { + return false; + } + + for (auto i = 0; i < nrofs; i++) { + uint16_t bc; + uint32_t orbit; + uint32_t firstIdx; + uint32_t nentries; + uint32_t bcWidth; + in.read(reinterpret_cast<char*>(&bc), sizeof(uint16_t)); + in.read(reinterpret_cast<char*>(&orbit), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&firstIdx), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&nentries), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&bcWidth), sizeof(uint32_t)); + rofs.emplace_back(o2::InteractionRecord{bc, orbit}, firstIdx, nentries, bcWidth); + if (in.fail()) { + return false; + } + } + + int ndigits = readNofItems(in, "digits"); + if (in.fail()) { + return false; + } + + for (int i = 0; i < ndigits; i++) { + uint32_t tfTime; + uint16_t nofSamples; + uint32_t deID; + uint32_t padID; + uint32_t adc; + uint8_t sat; + in.read(reinterpret_cast<char*>(&tfTime), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&nofSamples), sizeof(uint16_t)); + in.read(reinterpret_cast<char*>(&sat), sizeof(uint8_t)); + in.read(reinterpret_cast<char*>(&deID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&padID), sizeof(uint32_t)); + in.read(reinterpret_cast<char*>(&adc), sizeof(uint32_t)); + digits.emplace_back(deID, padID, adc, tfTime, nofSamples, sat > 0); + if (in.fail()) { + return false; + } + } + return true; +} + +void DigitReaderV4::rewind(std::istream& in) +{ + DigitReaderImpl::rewind(in); +} + +bool DigitWriterV4::write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + if (rofs.empty()) { + return false; + } + writeNofItems(out, rofs.size()); + if (out.fail()) { + return false; + } + for (auto r : rofs) { + uint16_t bc = r.getBCData().bc; + uint32_t orbit = r.getBCData().orbit; + uint32_t firstIdx = r.getFirstIdx(); + uint32_t nentries = r.getNEntries(); + uint32_t bcWidth = r.getBCWidth(); + out.write(reinterpret_cast<const char*>(&bc), sizeof(uint16_t)); + out.write(reinterpret_cast<const char*>(&orbit), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&firstIdx), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&nentries), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&bcWidth), sizeof(uint32_t)); + if (out.fail()) { + return false; + } + } + + writeNofItems(out, digits.size()); + if (out.fail()) { + return false; + } + for (const auto& d : digits) { + uint32_t tfTime = d.getTime(); + uint16_t nofSamples = d.getNofSamples(); + uint32_t deID = d.getDetID(); + uint32_t padID = d.getPadID(); + uint32_t adc = d.getADC(); + uint8_t sat = d.isSaturated(); + out.write(reinterpret_cast<const char*>(&tfTime), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&nofSamples), sizeof(uint16_t)); + out.write(reinterpret_cast<const char*>(&sat), sizeof(uint8_t)); + out.write(reinterpret_cast<const char*>(&deID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&padID), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&adc), sizeof(uint32_t)); + if (out.fail()) { + return false; + } + } + return true; +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.h b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.h new file mode 100644 index 0000000000000..86dcf743923ee --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitIOV4.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_IO_V4_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_IO_V4_H + +#include "DigitReaderImpl.h" +#include <vector> +#include "DataFormatsMCH/ROFRecord.h" +#include <utility> +#include "DigitWriterImpl.h" + +namespace o2::mch::io::impl +{ +class DigitReaderV4 : public DigitReaderImpl +{ + public: + void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) override; + bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) override; + void rewind(std::istream& in); +}; + +struct DigitWriterV4 : public DigitWriterImpl { + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) override; +}; + +} // namespace o2::mch::io::impl +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitReader.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitReader.cxx new file mode 100644 index 0000000000000..733c6171c0e67 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitReader.cxx @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitReader.h" +#include <istream> +#include "DigitFileFormat.h" +#include <iostream> +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <fmt/format.h> +#include "DigitReaderImpl.h" + +namespace o2::mch::io +{ + +DigitReader::DigitReader(std::istream& in) : mInput{in} +{ + mFileFormat = readDigitFileFormat(mInput); + mImpl = impl::createDigitReaderImpl(mFileFormat.fileVersion); +} + +DigitReader::~DigitReader() = default; + +bool DigitReader::read(std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) +{ + digits.clear(); + rofs.clear(); + bool ok = mImpl->read(mInput, digits, rofs); + return ok; +} + +void DigitReader::rewind() +{ + mImpl->rewind(mInput); +} + +void DigitReader::count() const +{ + if (mCountDone) { + return; + } + mImpl->count(mInput, mNofTimeFrames, mNofROFs, mNofDigits); + mCountDone = true; +} + +size_t DigitReader::nofTimeFrames() const +{ + count(); + return mNofTimeFrames; +} + +size_t DigitReader::nofROFs() const +{ + count(); + return mNofROFs; +} + +size_t DigitReader::nofDigits() const +{ + count(); + return mNofDigits; +} + +} // namespace o2::mch::io diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitReader.h b/Detectors/MUON/MCH/DevIO/Digits/DigitReader.h new file mode 100644 index 0000000000000..9a90648b399e9 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitReader.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_READER_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_READER_H + +#include <iosfwd> +#include "DigitFileFormat.h" +#include <vector> +#include <memory> + +namespace o2::mch +{ +class Digit; +class ROFRecord; +} // namespace o2::mch + +namespace o2::mch::io +{ +namespace impl +{ +class DigitReaderImpl; +} +class DigitReader +{ + public: + DigitReader(std::istream& in); + + /* defined in the implementation file, where mImpl is a complete type */ + ~DigitReader(); + + /** Which file format has been detected */ + DigitFileFormat fileFormat() const { return mFileFormat; } + + /** read rofs, digits at the current position in the input stream. + * i.e. reads one full time frame. + * + * @param digits vector of Digits + * @param rofs vector of ROFRecord + * @returns true if reading was successull, false otherwise + */ + bool read(std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs); + + /** Count the number of timeframes in the input stream. + * WARNING : depending on the size of the input this might be a + * costly operation */ + size_t nofTimeFrames() const; + + /** Count the number of ROFRecords in the input stream + * WARNING : depending on the size of the input this might be a + * costly operation */ + size_t nofROFs() const; + + /** Count the number of digits in the input stream + * WARNING : depending on the size of the input this might be a + * costly operation */ + size_t nofDigits() const; + + /** Rewind, aka restart reading from the beginning of the stream */ + void rewind(); + + private: + void count() const; + + private: + std::istream& mInput; + DigitFileFormat mFileFormat; + std::unique_ptr<impl::DigitReaderImpl> mImpl; + mutable size_t mNofTimeFrames{0}; + mutable size_t mNofROFs{0}; + mutable size_t mNofDigits{0}; + mutable bool mCountDone{false}; +}; + +} // namespace o2::mch::io + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.cxx new file mode 100644 index 0000000000000..fae077d4e22c5 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitReaderImpl.h" +#include <istream> +#include "DigitFileFormat.h" +#include <map> +#include "DigitIOV0.h" +#include "DigitIOV1.h" +#include "DigitIOV2.h" +#include "DigitIOV3.h" +#include "DigitIOV4.h" +#include <memory> + +namespace o2::mch::io::impl +{ + +std::unique_ptr<DigitReaderImpl> createDigitReaderImpl(int version) +{ + switch (version) { + case 0: + return std::make_unique<DigitReaderV0>(); + case 1: + return std::make_unique<DigitReaderV1>(); + case 2: + return std::make_unique<DigitReaderV2>(); + case 3: + return std::make_unique<DigitReaderV3>(); + case 4: + return std::make_unique<DigitReaderV4>(); + default: + break; + }; + throw std::invalid_argument(fmt::format("DigitFileFormat version {} not implemented yet", + version)); + return nullptr; +} + +void DigitReaderImpl::rewind(std::istream& in) +{ + in.clear(); + in.seekg(sizeof(DigitFileFormat)); +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.h b/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.h new file mode 100644 index 0000000000000..d1a13f4201494 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitReaderImpl.h @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_READER_IMPL_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_READER_IMPL_H + +#include <istream> +#include "DigitFileFormat.h" +#include <fmt/format.h> +#include <memory> +#include <vector> + +namespace o2::mch +{ +class Digit; +class ROFRecord; +} // namespace o2::mch + +namespace o2::mch::io::impl +{ + +struct DigitReaderImpl { + virtual ~DigitReaderImpl() = default; + virtual void count(std::istream& in, size_t& ntfs, size_t& nrofs, size_t& ndigits) = 0; + virtual bool read(std::istream& in, + std::vector<Digit>& digits, + std::vector<ROFRecord>& rofs) = 0; + + void rewind(std::istream& in); +}; + +std::unique_ptr<DigitReaderImpl> createDigitReaderImpl(int version); + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.cxx new file mode 100644 index 0000000000000..3b33ccbeca34d --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.cxx @@ -0,0 +1,163 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" +#include <set> +#include <fmt/format.h> +#include "DigitWriter.h" +#include <iostream> +#include "DigitWriterImpl.h" +#include <map> +#include <algorithm> +#include <limits> + +namespace +{ +template <typename T> +std::string asString(T t); + +template <> +std::string asString(o2::mch::ROFRecord rof) +{ + return fmt::format("{} FirstIdx: {:5d} LastIdx: {:5d}", + rof.getBCData().asString(), rof.getFirstIdx(), rof.getLastIdx()); +} +template <> +std::string asString(o2::mch::Digit d) +{ + return fmt::format("DetID {:4d} PadId {:10d} ADC {:10d} TFtime {:10d} NofSamples {:5d} {}", + d.getDetID(), d.getPadID(), d.getADC(), d.getTime(), d.getNofSamples(), + d.isSaturated() ? "(S)" : ""); +} + +std::map<o2::mch::ROFRecord, int64_t> computeMinTimeDistances(gsl::span<const o2::mch::ROFRecord> rofs) +{ + std::map<o2::mch::ROFRecord, int64_t> minTimeDistances; + + for (auto i = 0; i < rofs.size() - 1; i++) { + auto const& r = rofs[i]; + o2::InteractionRecord iri{r.getBCData().bc, + r.getBCData().orbit}; + minTimeDistances[r] = std::numeric_limits<int64_t>::max(); + auto j = i + 1; + o2::InteractionRecord irj{rofs[j].getBCData().bc, + rofs[j].getBCData().orbit}; + auto d = irj.differenceInBC(iri); + if (d >= 0) { + minTimeDistances[rofs[i]] = std::min(minTimeDistances[rofs[i]], d); + } + } + return minTimeDistances; +} + +void printRofs(std::ostream& os, gsl::span<const o2::mch::ROFRecord> rofs) +{ + auto minTimeDistances = computeMinTimeDistances(rofs); + + os << fmt::format("{:=^70}\n", fmt::format("{} rofs", rofs.size())); + size_t i{0}; + for (const auto& r : rofs) { + os << fmt::format("[{:6d}] {}", i, asString(r)); + if (minTimeDistances[r] < 4) { + os << fmt::format(" min distance {} !", minTimeDistances[r]); + } + os << "\n"; + ++i; + } +} + +struct DigitIdComparator { + bool operator()(const o2::mch::Digit& d1, const o2::mch::Digit& d2) const + { + if (d1.getDetID() == d2.getDetID()) { + return d1.getPadID() < d2.getPadID(); + } + return d1.getDetID() < d2.getDetID(); + } +}; + +void printDigitsAndRofs(std::ostream& os, + gsl::span<const o2::mch::Digit> digits, + gsl::span<const o2::mch::ROFRecord> rofs) +{ + printRofs(os, rofs); + os << fmt::format("{:=^70}\n", fmt::format("{} digits", digits.size())); + size_t irof{0}; + size_t digitIndex{0}; + for (const auto& r : rofs) { + os << fmt::format("{:-^95}\n", fmt::format("ROF {:4d} with {:5d} digits", + irof, r.getNEntries())); + ++irof; + std::map<o2::mch::Digit, uint16_t, DigitIdComparator> dids; + for (auto j = r.getFirstIdx(); j <= r.getLastIdx(); j++) { + const auto& d = digits[j]; + dids[d]++; + } + size_t i{0}; + for (auto& p : dids) { + const auto& d = p.first; + os << fmt::format("[{:6d}] ({:6d}) {}\n", digitIndex, i, asString(d)); + ++digitIndex; + ++i; + } + // check that, within a rof, each digit appears only once. + // if not, report that as an error + for (auto& p : dids) { + if (p.second != 1) { + os << "!!! ERROR : got a duplicated digit (not merged?) : " << p.first << " appears " << p.second << " times\n"; + } + } + } +} + +} // namespace + +namespace o2::mch::io +{ + +DigitWriter::DigitWriter(std::ostream& os, DigitFileFormat format, size_t maxSize) : mOutput(os), mBinary(true), mFileFormat(format), mMaxSize(maxSize) +{ + // write the tag to identify the file + os.write(reinterpret_cast<char*>(&mFileFormat), sizeof(DigitFileFormat)); + mImpl = impl::createDigitWriterImpl(mFileFormat.fileVersion); +} + +DigitWriter::DigitWriter(std::ostream& os) : mOutput(os), mBinary(false), mImpl{} +{ +} + +DigitWriter::~DigitWriter() = default; + +bool DigitWriter::write(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) +{ + if (digits.empty()) { + return false; + } + + bool ok{true}; + + if (mBinary) { + auto pos = static_cast<size_t>(mOutput.tellp()); + auto newSize = (pos + digits.size_bytes() + rofs.size_bytes()) / 1024; + if (newSize >= mMaxSize) { + return false; + } + ok = mImpl->write(mOutput, digits, rofs); + } else { + printDigitsAndRofs(mOutput, digits, rofs); + } + return ok; +} + +} // namespace o2::mch::io diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.h b/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.h new file mode 100644 index 0000000000000..5153098240645 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitWriter.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_WRITER_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_WRITER_H + +#include <iosfwd> +#include <gsl/span> +#include "DigitFileFormat.h" +#include <memory> +#include <numeric> + +namespace o2::mch +{ +class ROFRecord; +class Digit; + +namespace io +{ +namespace impl +{ +class DigitWriterImpl; +} +class DigitWriter +{ + public: + /** Create a text digit writer + * @param os output stream to write to + */ + DigitWriter(std::ostream& os); + + /** Create a binary digit writer + * @param os output stream to write to + * @param dff the digit file format to be used + * @param maxSize if not zero indicate that writing should stop past + * this size, expressed in KB. + */ + DigitWriter(std::ostream& os, DigitFileFormat format, + size_t maxSize = std::numeric_limits<size_t>::max()); + + /* defined in the implementation file, where mImpl is a complete type */ + ~DigitWriter(); + + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + bool write(gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs = {}); + + private: + std::ostream& mOutput; // underlying stream used for output + bool mBinary; // whether to output in binary mode or text mode + DigitFileFormat mFileFormat{}; // version information for the binary case + std::unique_ptr<impl::DigitWriterImpl> mImpl; // actual implementation of the writer + size_t mMaxSize; // max size written to output +}; +} // namespace io +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.cxx b/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.cxx new file mode 100644 index 0000000000000..2a5b11340f4df --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitWriterImpl.h" +#include "DigitIOV0.h" +#include "DigitIOV1.h" +#include "DigitIOV2.h" +#include "DigitIOV3.h" +#include "DigitIOV4.h" +#include <fmt/format.h> + +namespace o2::mch::io::impl +{ +std::unique_ptr<DigitWriterImpl> createDigitWriterImpl(int version) +{ + switch (version) { + case 0: + return std::make_unique<DigitWriterV0>(); + case 1: + return std::make_unique<DigitWriterV1>(); + case 2: + return std::make_unique<DigitWriterV2>(); + case 3: + return std::make_unique<DigitWriterV3>(); + case 4: + return std::make_unique<DigitWriterV4>(); + default: + break; + }; + throw std::invalid_argument(fmt::format("DigitFileFormat version {} not implemented yet", + version)); + return nullptr; +} + +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.h b/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.h new file mode 100644 index 0000000000000..171dcb8caead7 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/DigitWriterImpl.h @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_DIGIT_WRITER_IMPL_H +#define O2_MCH_DEVIO_DIGITS_DIGIT_WRITER_IMPL_H + +#include <ostream> +#include <gsl/span> +#include <memory> + +namespace o2::mch +{ +class Digit; +class ROFRecord; +} // namespace o2::mch + +namespace o2::mch::io::impl +{ + +struct DigitWriterImpl { + virtual ~DigitWriterImpl() = default; + + /** write rofs, digits at the current position in the output stream + * @param digits vector of Digits, must not be empty + * @param rofs vector of ROFRecord, might be empty + * @returns true if writing was successull, false otherwise + */ + virtual bool write(std::ostream& out, + gsl::span<const Digit> digits, + gsl::span<const ROFRecord> rofs) = 0; +}; + +std::unique_ptr<DigitWriterImpl> createDigitWriterImpl(int version); +} // namespace o2::mch::io::impl +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/IO.cxx b/Detectors/MUON/MCH/DevIO/Digits/IO.cxx new file mode 100644 index 0000000000000..1bbc5787a31c7 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/IO.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "IO.h" +#include <stdexcept> +#include <fmt/format.h> +#include <iostream> +#include "DigitFileFormat.h" + +namespace o2::mch::io::impl +{ +int readNofItems(std::istream& in, const char* itemName) +{ + int nitems(-1); + in.read(reinterpret_cast<char*>(&nitems), sizeof(int)); + if (in.fail() || nitems < 0) { + throw std::length_error(fmt::format("invalid input : cannot get number of {}", itemName)); + } + return nitems; +} + +void writeNofItems(std::ostream& out, uint32_t nofItems) +{ + out.write(reinterpret_cast<const char*>(&nofItems), sizeof(uint32_t)); +} + +int advance(std::istream& in, size_t itemByteSize, const char* itemName) +{ + if (in.peek() == EOF) { + return -1; + } + // get the number of items + int nitems = readNofItems(in, itemName); + // move forward of n items + auto current = in.tellg(); + in.seekg(current + static_cast<decltype(current)>(nitems * itemByteSize)); + return nitems; +} + +std::pair<int, int> advanceOneEvent(std::istream& in, int fileFormatVersion) +{ + auto dff = digitFileFormats[fileFormatVersion]; + int nrofs = advance(in, dff.rofSize, "rofs"); + if (nrofs < 0) { + return std::make_pair(-1, -1); + } + int ndigits = advance(in, dff.digitSize, "digits"); + return std::make_pair(nrofs, ndigits); +} +} // namespace o2::mch::io::impl diff --git a/Detectors/MUON/MCH/DevIO/Digits/IO.h b/Detectors/MUON/MCH/DevIO/Digits/IO.h new file mode 100644 index 0000000000000..11bfa739ab37b --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/IO.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_IO_H +#define O2_MCH_DEVIO_DIGITS_IO_H + +#include <iosfwd> +#include <cstdint> +#include <utility> + +namespace o2::mch::io::impl +{ +int readNofItems(std::istream& in, const char* itemName); +void writeNofItems(std::ostream& out, uint32_t nofItems); +int advance(std::istream& in, size_t itemByteSize, const char* itemName); +std::pair<int, int> advanceOneEvent(std::istream& in, int fileFormatVersion); + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/IOStruct.h b/Detectors/MUON/MCH/DevIO/Digits/IOStruct.h new file mode 100644 index 0000000000000..40ae6ccfabf60 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/IOStruct.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_IO_STRUCT_H +#define O2_MCH_DEVIO_DIGITS_IO_STRUCT_H + +#include <gsl/span> +#include <iostream> +#include "IO.h" +#include <fmt/format.h> + +namespace o2::mch::io::impl +{ +template <typename T> +bool writeBinaryStruct(std::ostream& os, + gsl::span<const T> items) +{ + uint32_t nofItems = static_cast<uint32_t>(items.size()); + if (!nofItems) { + return !os.bad(); + } + writeNofItems(os, nofItems); + os.write(reinterpret_cast<const char*>(items.data()), items.size_bytes()); + return !os.bad(); +} +template <typename T> +bool readBinaryStruct(std::istream& in, std::vector<T>& items, const char* itemName) +{ + if (in.peek() == EOF) { + return false; + } + // get the number of items + int nitems = readNofItems(in, itemName); + // get the items if any + if (nitems > 0) { + auto offset = items.size(); + items.resize(offset + nitems); + in.read(reinterpret_cast<char*>(&items[offset]), nitems * sizeof(T)); + if (in.fail()) { + throw std::length_error(fmt::format("invalid input : cannot read {} {}", nitems, itemName)); + } + } + return true; +} + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/ProgOptions.h b/Detectors/MUON/MCH/DevIO/Digits/ProgOptions.h new file mode 100644 index 0000000000000..1c55c8dc67730 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/ProgOptions.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_PROG_OPTIONS_H +#define O2_MCH_DEVIO_DIGITS_PROG_OPTIONS_H + +/* Command line option names that are used by at least two + * executables (workflow or not). + */ + +constexpr const char* OPTNAME_MAX_NOF_TFS = "max-nof-tfs"; +constexpr const char* OPTHELP_MAX_NOF_TFS = "max number of timeframes to process"; + +constexpr const char* OPTNAME_FIRST_TF = "first-tf"; +constexpr const char* OPTHELP_FIRST_TF = "first timeframe to process"; + +constexpr const char* OPTNAME_PRINT_DIGITS = "print-digits"; +constexpr const char* OPTHELP_PRINT_DIGITS = "print digits"; + +constexpr const char* OPTNAME_PRINT_TFS = "print-tfs"; +constexpr const char* OPTHELP_PRINT_TFS = "print number of digits and rofs per tf"; + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/README.md b/Detectors/MUON/MCH/DevIO/Digits/README.md new file mode 100644 index 0000000000000..5a51f2538e499 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/README.md @@ -0,0 +1,146 @@ +<!-- doxy +\page refDetectorsMUONMCHDevIODigits DigitsIO +/doxy --> + +<!-- vim-markdown-toc GFM --> + +* [Utilities to read and write MCH Digits in non-CTF formats (mostly for debug)](#utilities-to-read-and-write-mch-digits-in-non-ctf-formats-mostly-for-debug) + * [Standalone programs (i.e. not DPL devices)](#standalone-programs-ie-not-dpl-devices) + * [Digit file dumper](#digit-file-dumper) + * [DPL devices](#dpl-devices) + * [Digit file reader (aka sampler) device](#digit-file-reader-aka-sampler-device) + * [Digit writer (aka sink) device](#digit-writer-aka-sink-device) + * [Digit ID converter (from Run2 to Run3)](#digit-id-converter-from-run2-to-run3) + * [Digit random generator](#digit-random-generator) + +<!-- vim-markdown-toc --> +# Utilities to read and write MCH Digits in non-CTF formats (mostly for debug) + +The MCH digits can be stored in binary format for debug purpose. + +The file they are stored in can currently be of two different formats : with or +without associated ROFRecord. In both cases the digits themselves (currently) +have the same version (named D0). The file version number changes whenever the + file structure changes or the format of the objects it contain changes. + +| File version | Digit version | contains ROF | ROF version | support | +|:------------:|:-------------:|:------------:|:-----------:|:---------:| +| 0 | 0 | no | (0) | yes | +| 1 | 0 | yes | 1 | yes | +| 2 | 1 | yes | 1 | planned | + +## Standalone programs (i.e. not DPL devices) + +### Digit file dumper + +```shell +options: + -h [ --help ] produce help message + -i [ --infile ] arg input file name + -c [ --count ] count items (rofs, tfs, etc...) + -d [ --describe ] describe file format + -p [ --print-digits ] print digits + -t [ --print-tfs ] print number of digits and rofs per tf + --max-nof-tfs arg max number of timeframes to process + --first-tf arg first timeframe to process +``` + +## DPL devices + +Those are (partial) DPL workflows to be used to form bigger workflows + using pipes. + +### Digit file reader (aka sampler) device + +Reads a binary file containing digits. The binary format should be embedded +in the file directly. If the reader cannot identify the format it will assume +it is the V0 version, which might or not might be the case... + +``` +o2-mch-digits-file-reader-workflow + --infile arg input file name + [--max-nof-tfs] max number of timeframes to process + [--first-tf] first timeframe to process + [--max-nof-rofs] max number of ROFs to process + [--repack-rofs] number of rofs to repack into a timeframe + (aka min number of rofs per timeframe) + [--print-digits] print digits + [--print-tfs] print number of digits and rofs per tf +``` + +### Digit writer (aka sink) device + +``` +o2-mch-digits-file-writer-workflow + [--outfile] arg (=digits.out) output file name + [--max-nof-tfs] arg (=2147483647) max number of timeframes to process + [--first-tf] arg (=0) first timeframe to process + [--no-file] no output to file + [--binary-file-format] arg (=v1) digit binary format to use + [--print-digits] print digits + [--print-tfs] print number of digits and rofs per tf + [--txt] output digits in text format + [--max-size] arg (=2147483647) max output size (in KB) +``` + +Take as input a list of digits in timeframes (and optionally their associated +Orbits) and dump them into a file (binary or text if `--txt` +option is used) or to screen (if `--no-file` option is used) + +### Digit ID converter (from Run2 to Run3) + +``` +o2-mch-digits-r23-workflow + [--verbose] print ids being converted +``` + +A device that reads digits with ids in Run2 convention and outputs digits with + ids in Run3 convention. Note that expected input spec is `MCH/DIGITSRUN2` and + the output one is `MCH/DIGITS` + +### Digit random generator + +``` +o2-mch-digits-random-generator-workflow + [--first-tf] arg (=0) first timeframe to generate + [--max-nof-tfs] arg (=2147483647) max number of timeframes to generate + [--nof-rofs-per-tf] number of ROFs to generate in each timeframe + [--occupancy] fraction of pads to generate digits for + [--print-digits] print digits + [--print-tfs] print number of digits and rofs per tf +``` + +Generate a fixed number of digits (equal to the total number of MCH pads +times the occupancy) per ROFRecord for a fixed number of ROFRecord per time frames, + for a fixed number of timeframes. + +Note that the occupancy **must** be strictly positive and less than or equal to 1. + +Example of use : generate digits (with 1% occupancy, 128 ROFs per TF, 10 TFs) and +dump them into debug binary form : + +``` +o2-mch-digits-random-generator-workflow -b + --max-nof-tfs 10 + --nof-rofs-per-tf 128 + --occupancy 0.01 | +o2-mch-digits-writer-workflow -b + --print-tfs + --binary-file-format 1 + --outfile digits.v1.out +``` + +``` +$ ls -alrth digits.v1.out +-rw-r--r-- 1 laurent staff 258M 15 avr 10:30 digits.v1.out + +$ o2-mch-digits-file-dumper --infile digits.v1.out -c -d +[ file version 1 digit version 0 size 20 rof version 1 size 16 hasRof true run2ids false ] formatWord 1224998065220435759 +nTFs 10 nROFs 1280 nDigits 13506560 +``` + +The generated digit file can then be injected into other workflows using +`o2-mch-digits-file-reader-workflow` described above. +(digits do not _need_ to be written to disc, the `o2-mch-digits-random-generator-workflow` + can of course also be used as the first stage of a multi device workflow + using pipes). diff --git a/Detectors/MUON/MCH/DevIO/Digits/ROFRecordR0.h b/Detectors/MUON/MCH/DevIO/Digits/ROFRecordR0.h new file mode 100644 index 0000000000000..e27765c81cd6f --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/ROFRecordR0.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_ROFRECORD_R0_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" + +namespace o2::mch::io::impl +{ + +struct ROFRecordR0 { + o2::InteractionRecord ir; + o2::dataformats::RangeReference<int, int> ref; +}; + +} // namespace o2::mch::io::impl + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.cxx b/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.cxx new file mode 100644 index 0000000000000..2b41081fd7c04 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <array> +#include <cstdint> + +std::array<uint8_t, 1276> v0_buffer = { + 0x2F, 0x3F, 0x00, 0x00, 0x40, 0x01, 0x00, 0x20, + 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x67, 0x30, 0x09, 0x54, 0xB7, 0x79, 0x31, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x00, 0x00, 0x00, 0x67, 0x60, 0x47, 0x0A, 0xD2, 0x18, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x67, 0x20, 0x01, 0x5D, 0x64, 0xC0, 0x2C, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x20, 0x49, 0x6F, + 0x24, 0x41, 0x5E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, + 0xC8, 0xB0, 0x0E, 0x18, 0x9F, 0x55, 0x32, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCB, 0x00, 0x00, 0x00, 0xCB, 0xF0, 0x47, 0x13, 0x19, 0xB1, 0x1B, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0xC9, 0x20, 0x07, 0x41, 0x19, 0xF6, 0x06, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x01, 0x00, 0x00, 0x2D, 0x81, 0x43, 0x3C, + 0x6F, 0xDE, 0x2C, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, + 0x92, 0xF1, 0x0A, 0x11, 0xD1, 0x65, 0x6E, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x01, 0x00, 0x00, 0x92, 0xF1, 0x0A, 0x14, 0x24, 0xFC, 0x35, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x92, 0xF1, 0x0A, 0x3F, 0xE5, 0xE5, 0x37, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x92, 0xF1, 0x4A, 0x61, + 0xA4, 0x2A, 0x51, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, + 0x92, 0xF1, 0x4A, 0x62, 0xC5, 0x0E, 0xCD, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x01, 0x00, 0x00, 0x92, 0xF1, 0x4A, 0x4F, 0xCF, 0xCD, 0x71, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x92, 0x41, 0x42, 0x65, 0xCE, 0x29, 0x31, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x92, 0x21, 0x04, 0x13, + 0x3D, 0x50, 0x21, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0xFF, 0x71, 0x46, 0x0E, 0xEE, 0x75, 0x05, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x81, 0x06, 0x61, 0xB7, 0xAA, 0xEF, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x03, 0x22, 0x07, 0x40, 0x8B, 0xC8, 0x25, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 0x67, 0xF2, 0x00, 0x56, + 0x24, 0x25, 0x8F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x02, 0x00, 0x00, + 0xC8, 0xC2, 0x06, 0x63, 0x22, 0xFC, 0x65, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x03, 0x00, 0x00, 0x28, 0xE3, 0x46, 0x5C, 0x8F, 0xE5, 0x83, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x38, 0x13, 0x0D, 0x14, 0x7C, 0xCE, 0x47, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x03, 0x00, 0x00, 0x39, 0x93, 0x01, 0x51, + 0x14, 0xDD, 0xB6, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x03, 0x00, 0x00, + 0x37, 0x23, 0x07, 0x62, 0x7B, 0x42, 0x3A, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x03, 0x00, 0x00, 0x21, 0x43, 0x53, 0x6A, 0x1E, 0x27, 0x6C, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9D, 0x03, 0x00, 0x00, 0x9D, 0x83, 0x46, 0x3D, 0x89, 0x84, 0x2C, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0xF8, 0xF3, 0x40, 0x7E, + 0xE2, 0x7A, 0x23, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x03, 0x00, 0x00, + 0xFD, 0xE3, 0x46, 0x07, 0xB6, 0x1C, 0xAB, 0x3F, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x67, 0xF0, 0x01, 0x46, 0xB0, 0x31, 0x40, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x65, 0x60, 0x03, 0x7A, + 0xC0, 0x50, 0x02, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, + 0xC8, 0xD0, 0x0E, 0x3D, 0xF5, 0xB4, 0x1C, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x00, 0x00, 0x00, 0xC8, 0xD0, 0x0A, 0x2B, 0x9C, 0xB2, 0x1E, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0xCA, 0xB0, 0x00, 0x31, 0xDE, 0x04, 0x1D, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0xCA, 0x70, 0x04, 0x22, + 0xB5, 0xD6, 0x1D, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x01, 0x00, 0x00, + 0x2D, 0x51, 0x4F, 0x02, 0xB5, 0x90, 0x1D, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x93, 0x01, 0x00, 0x00, 0x93, 0xA1, 0x0B, 0x58, 0xB0, 0x30, 0x2B, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x00, 0x5A, 0xC2, 0x0D, 0x2A, 0x55, 0x47, 0x43, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0x64, 0x72, 0x06, 0x04, + 0x5D, 0xEE, 0x64, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, + 0x03, 0x22, 0x07, 0x40, 0x9A, 0x7C, 0xFD, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x00, 0x00, 0x05, 0xE2, 0x0C, 0x6A, 0x11, 0x96, 0x87, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC7, 0x02, 0x00, 0x00, 0xC7, 0x82, 0x00, 0x76, 0x08, 0x1A, 0x73, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x02, 0x00, 0x00, 0xC8, 0xC2, 0x00, 0x6A, + 0x3F, 0xDD, 0x50, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, + 0x28, 0xC3, 0x06, 0x2D, 0x9B, 0x19, 0xA5, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x03, 0x00, 0x00, 0x31, 0x23, 0x13, 0x58, 0x23, 0x12, 0x4A, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x95, 0x03, 0x00, 0x00, 0x95, 0x53, 0x00, 0x4C, 0x42, 0xDE, 0x7F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x03, 0x00, 0x00, 0x91, 0x43, 0x00, 0x70, + 0x01, 0xA3, 0x7A, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x03, 0x00, 0x00, + 0x93, 0x33, 0x00, 0x78, 0xE3, 0x33, 0x4B, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x03, 0x00, 0x00, 0x85, 0xB3, 0x14, 0x22, 0xDB, 0x13, 0x0B, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x85, 0x03, 0x00, 0x00, 0x85, 0xB3, 0x14, 0x23, 0x22, 0x08, 0x4E, 0x42, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x03, 0x00, 0x00, 0x85, 0xB3, 0x14, 0x24, + 0xF8, 0xB4, 0x4E, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x03, 0x00, 0x00, + 0x85, 0xE3, 0x54, 0x71, 0x27, 0xFC, 0x55, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x03, 0x00, 0x00, 0x85, 0xE3, 0x54, 0x76, 0x95, 0x8A, 0xB3, 0x41, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, 0x88, 0xB3, 0x00, 0x16, 0x93, 0x95, 0x83, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x03, 0x00, 0x00, 0x98, 0x83, 0x46, 0x51, + 0x4C, 0x85, 0xB4, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x03, 0x00, 0x00, + 0x98, 0x83, 0x46, 0x59, 0xFC, 0xFD, 0xA2, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF7, 0x03, 0x00, 0x00, 0xF7, 0x13, 0x42, 0x12, 0x10, 0x65, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF7, 0x03, 0x00, 0x00, 0xF7, 0x23, 0x07, 0x73, 0xB0, 0x19, 0x32, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x03, 0x00, 0x00, 0xF4, 0x63, 0x06, 0x78, + 0xD9, 0xBB, 0xA3, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x03, 0x00, 0x00, + 0xF4, 0x73, 0x06, 0x6E, 0xA7, 0x88, 0xA4, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x10, 0xFB, 0xB6, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x14, 0x29, 0x11, 0xD9, 0x35, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x00, 0x00, 0xEA, 0xF3, 0x52, 0x7D, + 0x44, 0x19, 0x09, 0x40}; diff --git a/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.h b/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.h new file mode 100644 index 0000000000000..b39b9bc2a8837 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/TestFileV0.h @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DEVIO_DIGITS_TEST_FILE_V0_H +#define O2_MCH_DEVIO_DIGITS_TEST_FILE_V0_H + +#include <array> + +extern std::array<uint8_t, 1276> v0_buffer; + +#endif diff --git a/Detectors/MUON/MCH/DevIO/Digits/digits-file-dumper.cxx b/Detectors/MUON/MCH/DevIO/Digits/digits-file-dumper.cxx new file mode 100644 index 0000000000000..7301ff219b305 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/digits-file-dumper.cxx @@ -0,0 +1,108 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "boost/program_options.hpp" +#include <iostream> +#include <fstream> +#include "DigitReader.h" +#include "DigitWriter.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <fmt/format.h> +#include "ProgOptions.h" + +namespace po = boost::program_options; + +/** + * o2-mch-digits-file-dumper is a small helper program to inspect + * MCH digit binary files (the ones that are not in CTF format) + */ + +int main(int argc, char* argv[]) +{ + std::string inputFile; + po::variables_map vm; + po::options_description options("options"); + bool count{false}; + bool describe{false}; + bool printDigits{false}; + bool printTFs{false}; + int maxNofTimeFrames{std::numeric_limits<int>::max()}; + int firstTimeFrame{0}; + + // clang-format off + // clang-format off + options.add_options() + ("help,h", "produce help message") + ("infile,i", po::value<std::string>(&inputFile)->required(), "input file name") + ("count,c",po::bool_switch(&count),"count items (rofs, tfs, etc...)") + ("describe,d",po::bool_switch(&describe),"describe file format") + (OPTNAME_PRINT_DIGITS,po::bool_switch(&printDigits),OPTHELP_PRINT_DIGITS) + (OPTNAME_PRINT_TFS,po::bool_switch(&printTFs),OPTHELP_PRINT_TFS) + (OPTNAME_MAX_NOF_TFS,po::value<int>(&maxNofTimeFrames),OPTHELP_MAX_NOF_TFS) + (OPTNAME_FIRST_TF,po::value<int>(&firstTimeFrame),OPTHELP_FIRST_TF) + ; + // clang-format on + + po::options_description cmdline; + cmdline.add(options); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << options << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + std::ifstream in(inputFile.c_str()); + if (!in.is_open()) { + std::cerr << "cannot open input file " << inputFile << "\n"; + return 3; + } + o2::mch::io::DigitReader dr(in); + + if (describe) { + std::cout << dr.fileFormat() << "\n"; + } + if (count) { + std::cout << fmt::format("nTFs {} nROFs {} nDigits {}\n", + dr.nofTimeFrames(), dr.nofROFs(), dr.nofDigits()); + } + + if (printTFs || printDigits) { + int tfid{0}; + int tfcount{0}; + o2::mch::io::DigitWriter dump(std::cout); + std::vector<o2::mch::Digit> digits; + std::vector<o2::mch::ROFRecord> rofs; + while (dr.read(digits, rofs)) { + if (tfid >= firstTimeFrame && tfcount < maxNofTimeFrames) { + if (printTFs) { + std::cout << fmt::format("TF {:5d} {:4d} rofs {:5d} digits\n", + tfid, rofs.size(), digits.size()); + } + if (printDigits) { + dump.write(digits, rofs); + } + ++tfcount; + } + ++tfid; + } + } + return 0; +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/digits-file-reader-workflow.cxx b/Detectors/MUON/MCH/DevIO/Digits/digits-file-reader-workflow.cxx new file mode 100644 index 0000000000000..8b25f2a304300 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/digits-file-reader-workflow.cxx @@ -0,0 +1,160 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitIOBaseTask.h" +#include "DigitReader.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" +#include "ProgOptions.h" +#include <algorithm> +#include <fmt/format.h> +#include <fstream> +#include <iostream> +#include <memory> +#include <string> + +using namespace o2::framework; + +constexpr const char* OPTNAME_INFILE = "infile"; +constexpr const char* OPTNAME_MAX_NOF_ROFS = "max-nof-rofs"; +constexpr const char* OPTNAME_REPACK_ROFS = "repack-rofs"; +constexpr const char* OPTNAME_RUN2 = "run2"; + +using namespace o2::mch; + +class DigitSamplerTask : public io::DigitIOBaseTask +{ + private: + std::unique_ptr<io::DigitReader> mDigitReader; + std::ifstream mInput; + bool mReadIsOk = true; + size_t mMaxNofROFs; + size_t mNofProcessedROFs{0}; + size_t mMinNumberOfROFsPerTF{1}; + std::vector<ROFRecord> mROFs; + std::vector<Digit> mDigits; + + public: + void init(InitContext& ic) + { + io::DigitIOBaseTask::init(ic); // init common options + auto inputFileName = ic.options().get<std::string>(OPTNAME_INFILE); + mInput.open(inputFileName); + mDigitReader = std::make_unique<io::DigitReader>(mInput); + mNofProcessedTFs = 0; + mMaxNofROFs = ic.options().get<int>(OPTNAME_MAX_NOF_ROFS); + mMinNumberOfROFsPerTF = ic.options().get<int>(OPTNAME_REPACK_ROFS); + } + + void outputAndClear(DataAllocator& out) + { + printSummary(mDigits, mROFs, "-> to output"); + out.snapshot(OutputRef{"rofs"}, mROFs); + out.snapshot(OutputRef{"digits"}, mDigits); + mDigits.clear(); + mROFs.clear(); + } + + bool shouldEnd() const + { + bool maxTFreached = mNofProcessedTFs >= mMaxNofTimeFrames; + bool maxROFreached = mNofProcessedROFs >= mMaxNofROFs; + return !mReadIsOk || maxTFreached || maxROFreached; + } + + void run(ProcessingContext& pc) + { + if (shouldEnd()) { + // output remaining data if any + if (mROFs.size() > 0) { + --mTFid; + outputAndClear(pc.outputs()); + } + pc.services().get<ControlService>().endOfStream(); + return; + } + + std::vector<ROFRecord> rofs; + std::vector<Digit> digits; + mReadIsOk = mDigitReader->read(digits, rofs); + if (!mReadIsOk) { + return; + } + + if (shouldProcess()) { + incNofProcessedTFs(); + mNofProcessedROFs += rofs.size(); + // append rofs to mROFs, but shift the indices by the amount of digits + // we have read so far. + auto offset = mDigits.size(); + std::transform(rofs.begin(), rofs.end(), std::back_inserter(mROFs), + [offset](ROFRecord r) { + r.setDataRef(r.getFirstIdx() + offset, r.getNEntries()); + return r; + }); + mDigits.insert(mDigits.end(), digits.begin(), digits.end()); + printSummary(mDigits, mROFs); + printFull(mDigits, mROFs); + } + + // output if we've accumulated enough ROFs + if (mROFs.size() >= mMinNumberOfROFsPerTF) { + outputAndClear(pc.outputs()); + } + + incTFid(); + } +}; + +o2::framework::DataProcessorSpec getDigitsFileReaderSpec(const char* specName, bool run2) +{ + std::string spec = fmt::format("digits:MCH/DIGITS{}/0", run2 ? "R2" : ""); + InputSpec itmp = o2::framework::select(spec.c_str())[0]; + + auto commonOptions = o2::mch::io::getCommonOptions(); + auto options = Options{ + {OPTNAME_INFILE, VariantType::String, "", {"input file name"}}, + {OPTNAME_MAX_NOF_ROFS, VariantType::Int, std::numeric_limits<int>::max(), {"max number of ROFs to process"}}, + {OPTNAME_REPACK_ROFS, VariantType::Int, 1, {"number of rofs to repack into a timeframe (aka min number of rofs per timeframe"}}}; + options.insert(options.end(), commonOptions.begin(), commonOptions.end()); + + return DataProcessorSpec{ + specName, + Inputs{}, + Outputs{{DataSpecUtils::asOutputSpec(itmp)}, + OutputSpec{{"rofs"}, "MCH", "DIGITROFS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<DigitSamplerTask>()}, + options}; +} + +/** add workflow options. Note that customization needs to be declared +* before including Framework/runDataProcessing +*/ +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back(OPTNAME_RUN2, VariantType::Bool, false, + ConfigParamSpec::HelpString{"input digits use Run2 padIds"}); +} + +#include "Framework/runDataProcessing.h" + +//_________________________________________________________________________________________________ +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + return WorkflowSpec{getDigitsFileReaderSpec("mch-digits-file-reader", cc.options().get<bool>(OPTNAME_RUN2))}; +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/digits-r23-workflow.cxx b/Detectors/MUON/MCH/DevIO/Digits/digits-r23-workflow.cxx new file mode 100644 index 0000000000000..cb23fe3bd9831 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/digits-r23-workflow.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** Convert Digit's padID from Run2 to Run3. +*/ + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "DataFormatsMCH/Digit.h" +#include "MCHMappingInterface/Segmentation.h" +#include <fmt/format.h> +#include "Framework/Logger.h" + +using namespace o2::framework; + +#include "Framework/runDataProcessing.h" + +struct DigitConverter { + bool mVerbose{false}; + + void init(InitContext& ic) + { + mVerbose = ic.options().get<bool>("verbose"); + fair::Logger::SetConsoleColor(true); + } + + void run(ProcessingContext& pc) + { + auto digitsR2 = pc.inputs().get<gsl::span<o2::mch::Digit>>("digits"); + auto& digitsR3 = pc.outputs().make<std::vector<o2::mch::Digit>>(OutputRef{"digits"}); + for (const auto d2 : digitsR2) { + auto digit = d2; + int deID = digit.getDetID(); + int digitID = digit.getPadID(); + int manuID = (digitID & 0xFFF000) >> 12; + int manuCh = (digitID & 0x3F000000) >> 24; + + int padID = o2::mch::mapping::segmentation(deID).findPadByFEE(manuID, manuCh); + if (mVerbose) { + LOGP(warn, "DEID {:4d} DIGITID {:10d} MANUID {:4d} CH {:2} PADID {:10d}", + deID, digitID, manuID, manuCh, padID); + } + if (padID < 0) { + throw std::runtime_error(fmt::format("digitID {} does not exist in the mapping", digitID)); + } + digit.setPadID(padID); + digitsR3.push_back(digit); + } + } +}; + +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + WorkflowSpec specs; + + std::string inputConfig = fmt::format("digits:MCH/DIGITSR2/0"); + inputConfig += ";rofs:MCH/DIGITROFS/0"; + + DataProcessorSpec padIdConverter{ + "mch-digits-r23", + Inputs{o2::framework::select(inputConfig.c_str())}, + Outputs{OutputSpec{{"digits"}, "MCH", "DIGITS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<DigitConverter>()}, + Options{ + {"verbose", VariantType::Bool, false, {"print ids being converted"}}}}; + specs.push_back(padIdConverter); + return specs; +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/digits-random-generator-workflow.cxx b/Detectors/MUON/MCH/DevIO/Digits/digits-random-generator-workflow.cxx new file mode 100644 index 0000000000000..c27869caa5bd7 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/digits-random-generator-workflow.cxx @@ -0,0 +1,211 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitIOBaseTask.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Lifetime.h" +#include "Framework/Logger.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "MCHMappingInterface/Segmentation.h" +#include "ProgOptions.h" +#include <array> +#include <chrono> +#include <cstring> +#include <fmt/format.h> +#include <fstream> +#include <iostream> +#include <random> +#include <stdexcept> +#include <vector> + +/** + * This executable generate random MCH digits and their associated ROFRecords. + * + */ + +using namespace o2::framework; + +using namespace o2::mch; + +namespace +{ +std::array<int, 156> getDeIds() +{ + static std::array<int, 156> deids; + static bool first = true; + if (first) { + int i{0}; + o2::mch::mapping::forEachDetectionElement([&](int deid) { + deids[i++] = deid; + }); + first = false; + } + return deids; +} + +std::array<int, 156> getNofPads() +{ + static bool first = true; + static std::array<int, 156> npads; + if (first) { + int i{0}; + auto deids = getDeIds(); + for (auto deid : deids) { + o2::mch::mapping::Segmentation seg(deid); + int16_t nofPads = static_cast<int16_t>(seg.nofPads()); + npads[i++] = nofPads; + } + first = false; + } + return npads; +} +} // namespace + +constexpr const char* OPTNAME_NOF_ROFS_PER_TF = "nof-rofs-per-tf"; +constexpr const char* OPTNAME_OCCUPANCY = "occupancy"; +constexpr const char* OPTNAME_SEED = "seed"; + +class DigitGenerator : public o2::mch::io::DigitIOBaseTask +{ + public: + void init(InitContext& ic) + { + io::DigitIOBaseTask::init(ic); // init common options + mOccupancy = ic.options().get<float>(OPTNAME_OCCUPANCY); + if (mOccupancy <= 0.0 || mOccupancy > 1.0) { + throw std::invalid_argument("occupancy must be between >0 and <=1"); + } + mNofRofPerTimeFrame = ic.options().get<int>(OPTNAME_NOF_ROFS_PER_TF); + mSeed = ic.options().get<int>(OPTNAME_SEED); + + if (!mSeed) { + std::random_device rd; + mSeed = rd(); + } + mMersenneTwister.seed(mSeed); + + LOGP(INFO, + "Will generate {:7.2f}% of pads in {:4d} ROFs " + "per timeframe, for {:4d} timeframes", + mOccupancy * 100.0, mNofRofPerTimeFrame, mMaxNofTimeFrames); + } + + void run(ProcessingContext& pc) + { + if (mNofProcessedTFs >= mMaxNofTimeFrames) { + pc.services().get<ControlService>().endOfStream(); + return; + } + + if (shouldProcess()) { + incNofProcessedTFs(); + std::vector<Digit> digits; + std::vector<ROFRecord> rofs; + int ndigits{0}; + + for (auto i = 0; i < mNofRofPerTimeFrame; i++) { + auto n = generateRandomDigits(mOccupancy, digits); + o2::InteractionRecord ir{mBC, mOrbit}; + rofs.emplace_back(ir, ndigits, n); + ndigits += n; + mOrbit++; + } + pc.outputs().snapshot(OutputRef{"rofs"}, rofs); + pc.outputs().snapshot(OutputRef{"digits"}, digits); + printSummary(digits, rofs); + printFull(digits, rofs); + } + incTFid(); + } + + /** + * Populate the digits vector with (Nmch * occupancy) digits + * where Nmch is the total number of channels in MCH (1064008) + * + * Each member variable of the digit is uniformly distributed within + * its expected range, as an attempt to maximize the entropy of the + * generated digits, which can be handy to test the efficiency of the + * entropy encoder used to create the Compressed Time Frame (CTF) for instance. + * + * @param occupancy is a number between 0 and 1. + * @digits a vector where the generated digits will be appended. + * That vector is not cleared by this function, so digits can + * be accumulated if need be. + * @returns the number of digits added to the input digits vector. + */ + int generateRandomDigits(float occupancy, + std::vector<Digit>& digits) + { + int n{0}; + std::uniform_int_distribution<int32_t> adc{0, 1024 * 1024}; + std::uniform_int_distribution<int32_t> tfTime{0, 512 * 3564}; + std::uniform_int_distribution<int32_t> nofSamples{0, 1023}; + std::uniform_real_distribution<float> sat{0.0, 1.0}; + + auto deids = getDeIds(); + auto nofPadsPerDe = getNofPads(); + auto& mt = mMersenneTwister; + + for (auto i = 0; i < deids.size(); i++) { + auto deid = deids[i]; + int16_t nofPads = static_cast<int16_t>(nofPadsPerDe[i]); + std::uniform_int_distribution<int16_t> padid{0, nofPads}; + int nch = nofPads * occupancy; + for (int i = 0; i < nch; i++) { + auto p = padid(mt); + bool isSaturated = (sat(mt) > 0.9); + digits.emplace_back(deid, p, tfTime(mt), adc(mt), nofSamples(mt), isSaturated); + ++n; + } + } + return n; + } + + private: + float mOccupancy = 1.0; + uint16_t mBC = 0; + uint32_t mOrbit = 0; + int mNofRofPerTimeFrame = 100; + int mSeed = 0; + std::mt19937 mMersenneTwister; +}; + +#include "Framework/runDataProcessing.h" + +using namespace o2::mch; + +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + auto commonOptions = o2::mch::io::getCommonOptions(); + auto options = Options{ + {OPTNAME_OCCUPANCY, VariantType::Float, 0.01f, {"occupancy (fraction of fired pad per DE per ROF)"}}, + {OPTNAME_SEED, VariantType::Int, 0, {"seed for number generator (if 0 use default_seed)"}}, + {OPTNAME_NOF_ROFS_PER_TF, VariantType::Int, 100, {"number of ROFs per timeframe"}}}; + options.insert(options.end(), commonOptions.begin(), commonOptions.end()); + + return WorkflowSpec{ + DataProcessorSpec{ + "mch-digits-random-generator", + Inputs{}, + Outputs{OutputSpec{{"digits"}, "MCH", "DIGITS", 0, Lifetime::Timeframe}, + OutputSpec{{"rofs"}, "MCH", "DIGITROFS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<DigitGenerator>()}, + options}}; +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/digits-writer-workflow.cxx b/Detectors/MUON/MCH/DevIO/Digits/digits-writer-workflow.cxx new file mode 100644 index 0000000000000..b361f650bb3a3 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/digits-writer-workflow.cxx @@ -0,0 +1,177 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** + * o2-mch-digits-writer-workflow dumps to a file on disk the digits received + * via DPL, mainly in binary format (but txt is possible as well). + */ + +#include "DPLUtils/DPLRawParser.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitFileFormat.h" +#include "DigitIOBaseTask.h" +#include "DigitWriter.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "MCHRawDecoder/OrbitInfo.h" +#include <fstream> +#include <iostream> +#include <random> +#include <set> +#include <sstream> +#include <stdexcept> +#include <string> + +using namespace o2::framework; +using namespace o2::mch; + +constexpr const char* OPTNAME_OUTFILE = "outfile"; +constexpr const char* OPTNAME_TXT = "txt"; +constexpr const char* OPTNAME_NO_FILE = "no-file"; +constexpr const char* OPTNAME_BINARY_FORMAT = "binary-file-format"; +constexpr const char* OPTNAME_WITHOUT_ORBITS = "without-orbits"; +constexpr const char* OPTNAME_MAX_SIZE = "max-size"; + +class DigitsSinkTask : public io::DigitIOBaseTask +{ + public: + DigitsSinkTask(bool withOrbits) : mWithOrbits{withOrbits} {} + + //_________________________________________________________________________________________________ + void init(InitContext& ic) + { + /** + * init e.g. the options that are common to reading and writing + * like max number of timeframes to process, first time frame to process, etc... + */ + DigitIOBaseTask::init(ic); + + mNoFile = ic.options().get<bool>(OPTNAME_NO_FILE); + mBinary = not ic.options().get<bool>(OPTNAME_TXT); + + if (!mNoFile) { + auto outputFileName = ic.options().get<std::string>(OPTNAME_OUTFILE); + mStream = std::make_unique<std::fstream>(outputFileName, mBinary ? std::ios::out | std::ios::binary : std::ios::out); + if (mBinary) { + auto binaryFileFormat = ic.options().get<int>(OPTNAME_BINARY_FORMAT); + if (binaryFileFormat >= o2::mch::io::digitFileFormats.size()) { + throw std::invalid_argument(fmt::format("file version {} is unknown", binaryFileFormat)); + } + auto maxsize = ic.options().get<int>(OPTNAME_MAX_SIZE); + LOGP(warn, + "Will dump binary information (version {}) up to a maximum size of {} KB", + binaryFileFormat, maxsize); + mWriter = std::make_unique<io::DigitWriter>(*mStream, + io::digitFileFormats[binaryFileFormat], + static_cast<size_t>(maxsize)); + } else { + LOGP(warn, "Will dump textual information"); + mWriter = std::make_unique<io::DigitWriter>(*mStream); + } + } + } + + void writeOrbits(gsl::span<const o2::mch::OrbitInfo> orbits) + { + if (orbits.size() && !mBinary) { + std::set<OrbitInfo> orderedOrbits(orbits.begin(), orbits.end()); + for (auto o : orderedOrbits) { + (*mStream) << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl; + } + } + } + + void write(gsl::span<const o2::mch::Digit> digits, + gsl::span<const o2::mch::ROFRecord> rofs, + gsl::span<const o2::mch::OrbitInfo> orbits) + { + if (mNoFile) { + return; + } + writeOrbits(orbits); + mWriter->write(digits, rofs); + } + + void run(ProcessingContext& pc) + { + gsl::span<o2::mch::OrbitInfo> voidOrbitInfos; + + auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + auto rofs = pc.inputs().get<gsl::span<o2::mch::ROFRecord>>("rofs"); + auto orbits = mWithOrbits ? pc.inputs().get<gsl::span<o2::mch::OrbitInfo>>("orbits") : voidOrbitInfos; + + if (shouldProcess()) { + incNofProcessedTFs(); + printSummary(digits, rofs, fmt::format("{:4d} orbits", orbits.size()).c_str()); + printFull(digits, rofs); + write(digits, rofs, orbits); + } + incTFid(); + } + + private: + std::unique_ptr<io::DigitWriter> mWriter = nullptr; // actual digit writer + std::unique_ptr<std::iostream> mStream = nullptr; // output stream + bool mNoFile = false; // disable output to file + bool mWithOrbits = false; // expect ORBITs as input (in addition to just digits) + bool mBinary = true; // output is a binary file +}; + +/** + * Add workflow options. Note that customization needs to be declared + * before including Framework/runDataProcessing. + */ +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back(OPTNAME_WITHOUT_ORBITS, VariantType::Bool, true, + ConfigParamSpec::HelpString{"do not expect, in addition to digits and rofs, to get Orbits at the input"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + WorkflowSpec specs; + + bool withOrbits = not cc.options().get<bool>(OPTNAME_WITHOUT_ORBITS); + + std::string inputConfig = fmt::format("digits:MCH/DIGITS/0"); + inputConfig += ";rofs:MCH/DIGITROFS/0"; + if (withOrbits) { + inputConfig += ";orbits:MCH/ORBITS/0"; + } + + auto commonOptions = o2::mch::io::getCommonOptions(); + auto options = Options{ + {OPTNAME_OUTFILE, VariantType::String, "digits.out", {"output file name"}}, + {OPTNAME_NO_FILE, VariantType::Bool, false, {"no output to file"}}, + {OPTNAME_BINARY_FORMAT, VariantType::Int, 0, {"digit binary format to use"}}, + {OPTNAME_TXT, VariantType::Bool, false, {"output digits in text format"}}, + {OPTNAME_MAX_SIZE, VariantType::Int, std::numeric_limits<int>::max(), {"max output size (in KB)"}}}; + options.insert(options.end(), commonOptions.begin(), commonOptions.end()); + + DataProcessorSpec producer{ + "mch-digits-writer", + Inputs{o2::framework::select(inputConfig.c_str())}, + Outputs{}, + AlgorithmSpec{adaptFromTask<DigitsSinkTask>(withOrbits)}, + options}; + specs.push_back(producer); + + return specs; +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/testDigitIO.cxx b/Detectors/MUON/MCH/DevIO/Digits/testDigitIO.cxx new file mode 100644 index 0000000000000..ddf03c70ee712 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/testDigitIO.cxx @@ -0,0 +1,312 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/test/tools/old/interface.hpp> +#include <sstream> +#include "DigitFileFormat.h" +#define BOOST_TEST_MODULE Test MCHWorkflow DigitsIO +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/test/data/test_case.hpp> +#include "DigitIO.h" +#include <algorithm> +#include <fmt/format.h> +#include <fstream> +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <cassert> +#include <array> +#include <stdexcept> +#include "DigitReaderImpl.h" +#include "IO.h" + +using namespace o2::mch; +using namespace o2::mch::io; + +DigitFileFormat createFormat(uint8_t fileVersion, + uint8_t digitVersion, + uint8_t digitSize, + uint8_t rofVersion, + uint8_t rofSize, + bool run2ids, + bool hasRof) +{ + DigitFileFormat df; + df.fileVersion = fileVersion; + df.digitVersion = digitVersion; + df.digitSize = digitSize; + df.rofVersion = rofVersion; + df.rofSize = rofSize; + df.run2ids = run2ids; + df.hasRof = hasRof; + return df; +} + +BOOST_AUTO_TEST_CASE(DigitFileFormatV0Value) +{ + DigitFileFormat v0 = createFormat(0, 0, 20, 0, 0, true, false); + BOOST_CHECK_EQUAL(isValid(v0), true); +} + +BOOST_AUTO_TEST_CASE(DigitFileFormatV1Value) +{ + DigitFileFormat v1 = createFormat(1, 0, 20, 1, 16, false, true); + BOOST_CHECK_EQUAL(isValid(v1), true); +} + +BOOST_AUTO_TEST_CASE(DigitFileFormatV2Value) +{ + DigitFileFormat v2 = createFormat(2, 0, 19, 1, 14, false, false); + BOOST_CHECK_EQUAL(isValid(v2), true); +} + +BOOST_AUTO_TEST_CASE(DigitFileFormatV3Value) +{ + DigitFileFormat v3 = createFormat(3, 0, 19, 1, 14, false, true); + BOOST_CHECK_EQUAL(isValid(v3), true); +} + +BOOST_AUTO_TEST_CASE(DigitFileFormatV4Value) +{ + DigitFileFormat v4 = createFormat(4, 0, 19, 2, 18, false, true); + BOOST_CHECK_EQUAL(isValid(v4), true); +} + +BOOST_DATA_TEST_CASE(WriteMustReturnFalseIfDigitVectorIsEmpty, digitFileFormats, digitFileFormat) +{ + std::ostringstream str; + std::vector<ROFRecord> rofs; + std::vector<Digit> digits; + + rofs.push_back({}); + + DigitWriter dwText(str); + bool ok = dwText.write(digits, rofs); + + BOOST_CHECK_EQUAL(ok, false); + + DigitWriter dwBinary(str, digitFileFormat); + ok = dwBinary.write(digits, rofs); + + BOOST_CHECK_EQUAL(ok, false); +} + +BOOST_DATA_TEST_CASE(BinaryWriteMustReturnFalseIfRofVectorIsEmpty, digitFileFormats, digitFileFormat) +{ + if (not digitFileFormat.hasRof) { + return; + } + std::ostringstream str; + std::vector<ROFRecord> rofs; + std::vector<Digit> digits; + + digits.push_back({}); + + DigitWriter dwBinary(str, digitFileFormat); + bool ok = dwBinary.write(digits, rofs); + + BOOST_CHECK_EQUAL(ok, false); +} + +BOOST_AUTO_TEST_CASE(DefaultFormatIsTheTag) +{ + o2::mch::io::DigitFileFormat dff; + BOOST_CHECK_EQUAL(dff.format, o2::mch::io::TAG_DIGITS); +} + +BOOST_DATA_TEST_CASE(ReaderMustIdentifyFileFormat, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + buffer.write(reinterpret_cast<const char*>(&digitFileFormat), sizeof(uint64_t)); + buffer.clear(); + buffer.seekg(0); + DigitReader dr(buffer); + BOOST_CHECK_EQUAL(dr.fileFormat(), digitFileFormat); +} + +BOOST_DATA_TEST_CASE(BinaryWriterMustTagCorrectly, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + DigitWriter dw(buffer, digitFileFormat); + DigitReader dr(buffer); + BOOST_CHECK_EQUAL(dr.fileFormat(), digitFileFormat); +} + +std::vector<o2::mch::Digit> createDummyFixedDigits(int n) +{ + assert(n < 100); + std::vector<Digit> digits; + int dummyADC{40}; + int32_t dummyTime{1000}; + uint16_t dummySamples{10}; + for (int i = 0; i < n; i++) { + auto& d = digits.emplace_back(100, i, dummyADC + i, dummyTime + i * 100, dummySamples + i * 10); + if (i == 7 || i == 23) { + d.setSaturated(true); + } + } + return digits; +} + +struct TF { + std::vector<Digit> digits; + std::vector<ROFRecord> rofs; +}; + +TF createDummyData(int ndigits, int nrofs, uint32_t firstOrbit) +{ + if (nrofs >= ndigits) { + throw std::invalid_argument("cannot have more rofs than digits!"); + } + TF tf; + tf.digits = createDummyFixedDigits(ndigits); + int step = ndigits / nrofs; + for (int i = 0; i < nrofs; i++) { + o2::InteractionRecord ir(0, firstOrbit + i); + tf.rofs.emplace_back(ir, step * i, i == nrofs - 1 ? ndigits - step * i : step); + }; + return tf; +} + +/** The test data is used to check the internal consistency + * of the reader and writer (i.e. data written by the writer must be readable + * by the reader). + * A complete test requires, in addition, the usage of externally created data + * (see for instance V0File in testDigitIOV0) + */ +constexpr int NROF_1 = 1; +constexpr int NROF_2 = 1; +constexpr int NROF_3 = 1; +constexpr int NROF_4 = 3; +constexpr int NROFS = NROF_1 + NROF_2 + NROF_3 + NROF_4; + +std::vector<TF> testData{ + createDummyData(3, NROF_1, 0), + createDummyData(5, NROF_2, 10), + createDummyData(13, NROF_3, 20), + createDummyData(26, NROF_4, 20), +}; + +void writeTestData(std::ostream& out, DigitFileFormat dff) +{ + auto tfs = testData; + DigitWriter dw(out, dff); + for (auto tf : tfs) { + dw.write(tf.digits, tf.rofs); + } +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_DATA_TEST_CASE(TestDataDump, digitFileFormats, digitFileFormat) +{ + auto tfs = testData; + DigitWriter dw(std::cout); + for (auto tf : tfs) { + dw.write(tf.digits, tf.rofs); + } + BOOST_CHECK_EQUAL(tfs.size(), testData.size()); +} + +BOOST_DATA_TEST_CASE(TestDataIsOfExpectedFormat, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + BOOST_CHECK_EQUAL(dr.fileFormat(), digitFileFormat); +} + +BOOST_DATA_TEST_CASE(TestDataHasExpectedNofROFs, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + BOOST_CHECK_EQUAL(dr.nofROFs(), NROFS); +} + +BOOST_DATA_TEST_CASE(TestDataHasExpectedNofTFs, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + if (not digitFileFormat.hasRof) { + BOOST_CHECK_EQUAL(dr.nofTimeFrames(), NROFS); + } else { + BOOST_CHECK_EQUAL(dr.nofTimeFrames(), testData.size()); + } +} + +BOOST_DATA_TEST_CASE(TestDataHasExpectedNumberOfDigitsWhenReading, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + std::vector<Digit> digits; + std::vector<ROFRecord> rofs; + int ndigits{0}; + while (dr.read(digits, rofs)) { + ndigits += digits.size(); + } + BOOST_CHECK_EQUAL(ndigits, 47); +} + +BOOST_DATA_TEST_CASE(TestDataHasExpectedNumberOfDigitsWhenCounting, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + BOOST_CHECK_EQUAL(dr.nofDigits(), 47); +} + +BOOST_DATA_TEST_CASE(CheckReader, digitFileFormats, digitFileFormat) +{ + std::stringstream buffer; + writeTestData(buffer, digitFileFormat); + DigitReader dr(buffer); + + std::vector<Digit> digits; + std::vector<ROFRecord> rofs; + + std::array<int, 3> digits_per_tf = {3, 5, 13}; + for (int itf = 0; itf < 3; ++itf) { + dr.read(digits, rofs); + BOOST_CHECK_EQUAL(digits.size(), digits_per_tf[itf]); + BOOST_CHECK_EQUAL(rofs.size(), 1); + BOOST_CHECK_EQUAL(rofs[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofs[0].getLastIdx(), digits_per_tf[itf] - 1); + } + dr.read(digits, rofs); + int ndigits_4th_tf = not digitFileFormat.hasRof ? 8 : 26; + BOOST_CHECK_EQUAL(digits.size(), ndigits_4th_tf); + if (not digitFileFormat.hasRof) { + BOOST_CHECK_EQUAL(rofs.size(), 1); + BOOST_CHECK_EQUAL(rofs[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofs[0].getLastIdx(), 7); + BOOST_CHECK_EQUAL(digits[7].getADC(), 47); + BOOST_CHECK_EQUAL(digits[7].isSaturated(), true); + } else { + BOOST_CHECK_EQUAL(rofs.size(), 3); + BOOST_CHECK_EQUAL(rofs[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofs[0].getLastIdx(), 7); + BOOST_CHECK_EQUAL(rofs[1].getFirstIdx(), 8); + BOOST_CHECK_EQUAL(rofs[1].getLastIdx(), 15); + BOOST_CHECK_EQUAL(rofs[2].getFirstIdx(), 16); + BOOST_CHECK_EQUAL(rofs[2].getLastIdx(), 25); + BOOST_CHECK_EQUAL(digits[23].getADC(), 63); + BOOST_CHECK_EQUAL(digits[23].isSaturated(), true); + } +} diff --git a/Detectors/MUON/MCH/DevIO/Digits/testDigitIOV0.cxx b/Detectors/MUON/MCH/DevIO/Digits/testDigitIOV0.cxx new file mode 100644 index 0000000000000..0f721b92daf94 --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/Digits/testDigitIOV0.cxx @@ -0,0 +1,154 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/test/tools/old/interface.hpp> +#include <sstream> +#include "DigitFileFormat.h" +#define BOOST_TEST_MODULE Test MCHWorkflow DigitsIO - V0 +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/test/data/test_case.hpp> +#include "DigitIO.h" +#include <algorithm> +#include <fmt/format.h> +#include <fstream> +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <cassert> +#include <array> +#include <stdexcept> +#include "DigitReaderImpl.h" +#include "TestFileV0.h" +#include "DigitD0.h" +#include "IO.h" + +using namespace o2::mch; +using namespace o2::mch::io; + +void bin2cpp(const char* filename = "digits.v3.in") +{ + // filename must point to a V0 format + std::ifstream in(filename); + int ndig; + int pos{8}; + int event{0}; + in.seekg(8); + while ((ndig = o2::mch::io::impl::advance(in, digitFileFormats[0].digitSize, "digits")) >= 0) { + int next = in.tellg(); + if (ndig < 40 || ndig == 96) { + std::cout << fmt::format("Event {:4d} {} ndigits between {} and {}\n", event, ndig, pos, next); + } + pos = next; + event++; + } + struct a { + int start, end; + }; + std::array<a, 2> positions = {a{17707576, 17708160}, a{38707380, 38708064}}; + std::vector<uint8_t> bytes; + int i{1}; + for (auto p : positions) { + in.seekg(p.start); + int n = p.end - p.start; + bytes.resize(n); + in.read(reinterpret_cast<char*>(&bytes[0]), n); + if (in.tellg() != p.end) { + std::cout << "lost in file!\n"; + exit(1); + } + for (auto b : bytes) { + std::cout << fmt::format("0x{:02X},", b); + if (i % 16 == 0) { + std::cout << "\n"; + } + i++; + } + } + std::cout << "i=" << i << "\n"; +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE(Bin2Cpp) +{ + bin2cpp(); +} +struct V0File { + V0File() + { + std::ostringstream buffer; + for (auto b : v0_buffer) { + buffer << b; + } + std::istringstream in(buffer.str()); + DigitReader r(in); + r.read(digits[0], rofs[0]); + r.read(digits[1], rofs[1]); + } + std::array<std::vector<o2::mch::Digit>, 2> digits; + std::array<std::vector<o2::mch::ROFRecord>, 2> rofs; +}; + +BOOST_AUTO_TEST_CASE(CheckStructOffsets) +{ + BOOST_CHECK_EQUAL(offsetof(o2::mch::io::impl::DigitD0, tfTime), 0); + BOOST_CHECK_EQUAL(offsetof(o2::mch::io::impl::DigitD0, nofSamples), 4); + BOOST_CHECK_EQUAL(offsetof(o2::mch::io::impl::DigitD0, detID), 8); + BOOST_CHECK_EQUAL(offsetof(o2::mch::io::impl::DigitD0, padID), 12); + BOOST_CHECK_EQUAL(offsetof(o2::mch::io::impl::DigitD0, adc), 16); + BOOST_CHECK_EQUAL(sizeof(o2::mch::io::impl::DigitD0), 20); +} + +BOOST_FIXTURE_TEST_SUITE(SpotCheckV0, V0File) + +BOOST_AUTO_TEST_CASE(SpotCheckSizesV0) +{ + BOOST_CHECK_EQUAL(digits[0].size(), 29); + BOOST_CHECK_EQUAL(digits[1].size(), 34); + + BOOST_CHECK_EQUAL(rofs[0].size(), 1); + BOOST_CHECK_EQUAL(rofs[1].size(), 1); + + BOOST_CHECK_EQUAL(digits[0][20].getDetID(), 712); + BOOST_CHECK_EQUAL(digits[1][31].getDetID(), 1024); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE(SpotCheckDumpV0) +{ + DigitWriter w(std::cout); + w.write(digits[0], rofs[0]); + w.write(digits[1], rofs[1]); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE(SpotCheckDetIDV0) +{ + BOOST_CHECK_EQUAL(digits[0][20].getDetID(), 712); + BOOST_CHECK_EQUAL(digits[1][31].getDetID(), 1024); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE(SpotCheckPadIDV0) +{ + BOOST_CHECK_EQUAL(digits[0][20].getPadID(), 1661387464); + BOOST_CHECK_EQUAL(digits[1][31].getPadID(), 268444672); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE(SpotCheckADCV0) +{ + BOOST_CHECK_EQUAL(digits[0][20].getADC(), 1063648290); + BOOST_CHECK_EQUAL(digits[1][31].getADC(), 1065400059); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/DevIO/README.md b/Detectors/MUON/MCH/DevIO/README.md new file mode 100644 index 0000000000000..6c140a792ccfd --- /dev/null +++ b/Detectors/MUON/MCH/DevIO/README.md @@ -0,0 +1,9 @@ +<!-- doxy +\page refDetectorsMUONMCHDevIO DevIO +/doxy --> + +I/O tools for reading and writing MCH data in custom debug formats + +<!-- doxy +\subpage refDetectorsMUONMCHDevIODigits DigitsIO +/doxy --> diff --git a/Detectors/MUON/MCH/Geometry/CMakeLists.txt b/Detectors/MUON/MCH/Geometry/CMakeLists.txt new file mode 100644 index 0000000000000..a9f6ffc50e062 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(Transformer) +add_subdirectory(Creator) +if (BUILD_TESTING) +add_subdirectory(Test) +endif() + diff --git a/Detectors/MUON/MCH/Geometry/Creator/CMakeLists.txt b/Detectors/MUON/MCH/Geometry/Creator/CMakeLists.txt new file mode 100644 index 0000000000000..d638562d00707 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + MCHGeometryCreator + SOURCES src/Geometry.cxx + src/Materials.cxx + src/Materials.h + src/Station1Geometry.cxx + src/Station1Geometry.h + src/Station2Geometry.cxx + src/Station2Geometry.h + src/Station345Geometry.cxx + src/Station345Geometry.h + PUBLIC_LINK_LIBRARIES ROOT::Geom RapidJSON::RapidJSON + O2::MCHGeometryTransformer O2::DetectorsBase) + +o2_target_root_dictionary(MCHGeometryCreator + HEADERS include/MCHGeometryCreator/Geometry.h) diff --git a/Detectors/MUON/MCH/Geometry/Creator/README.md b/Detectors/MUON/MCH/Geometry/Creator/README.md new file mode 100644 index 0000000000000..619b98b3e666d --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/README.md @@ -0,0 +1,9 @@ +<!-- doxy +\page refDetectorsMUONMCHGeometryCreator Creation +/doxy --> + +# MUON MCH Geometry Creator + +This package hosts the functions to create, from scratch, the TGeo-based + geometry for MCH. + diff --git a/Detectors/MUON/MCH/Geometry/Creator/include/MCHGeometryCreator/Geometry.h b/Detectors/MUON/MCH/Geometry/Creator/include/MCHGeometryCreator/Geometry.h new file mode 100644 index 0000000000000..5e8f58cae6031 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/include/MCHGeometryCreator/Geometry.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file Geometry.h +/// @brief Interface for MCH geometry creation + +#ifndef O2_MCH_GEOMETRY_CREATOR_GEOMETRY_H +#define O2_MCH_GEOMETRY_CREATOR_GEOMETRY_H + +#include <vector> +#include <iostream> + +class TGeoVolume; +class TGeoManager; + +namespace o2::mch::geo +{ + +/** createGeometry creates MCH geometry. + * + * Geometry comprises volumes, materials and alignable volumes. + * + * Note that the geometry of stations 1 and 2 is attached to volume YOUT1 + * if it exist, or to topVolume otherwise. + * + * Geometry for stations 3, 4 and 5 are always attached to topVolume. + * + * @param topVolume the volume the MCH geometry is attached topVolume + */ +void createGeometry(TGeoManager& geom, TGeoVolume& topVolume); + +/** get a list of MCH sensitive volumes. + * @returns a vector of all the MCH volumes that participate in the + * particle tracking (in the transport sense). + */ +std::vector<TGeoVolume*> getSensitiveVolumes(); + +/** Add alignable MCH volumes to the global geometry. + * + * Creates entries for alignable volumes associating symbolic volume + * names with corresponding volume paths. + * + * @warning It also closes the geometry if it is not yet closed. + * + * @param geoManager the (global) TGeoManager instance, which thus + * must exist before calling this function. + * + */ +void addAlignableVolumes(TGeoManager& geom); + +} // namespace o2::mch::geo + +#endif diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/Geometry.cxx b/Detectors/MUON/MCH/Geometry/Creator/src/Geometry.cxx new file mode 100644 index 0000000000000..eafd7af68505d --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Geometry.cxx @@ -0,0 +1,140 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHGeometryCreator/Geometry.h" +#include "MCHGeometryTransformer/VolumePaths.h" +#include "Station1Geometry.h" +#include "Station2Geometry.h" +#include "Station345Geometry.h" +#include "Materials.h" +#include <iostream> +#include <TGeoPhysicalNode.h> +#include <fmt/format.h> +#include "TGeoVolume.h" +#include "TGeoManager.h" +#include "Framework/Logger.h" + +namespace impl +{ +void addAlignableVolumesHalfChamber(TGeoManager& geom, int hc, std::string& parent) +{ + // + // Add alignable volumes for a half chamber and its daughters + // + std::vector<std::vector<int>> DEofHC{{100, 103}, + {101, 102}, + {200, 203}, + {201, 202}, + {300, 303}, + {301, 302}, + {400, 403}, + {401, 402}, + {500, 501, 502, 503, 504, 514, 515, 516, 517}, + {505, 506, 507, 508, 509, 510, 511, 512, 513}, + {600, 601, 602, 603, 604, 614, 615, 616, 617}, + {605, 606, 607, 608, 609, 610, 611, 612, 613}, + {700, 701, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725}, + {707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719}, + {800, 801, 802, 803, 804, 805, 806, 820, 821, 822, 823, 824, 825}, + {807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819}, + {900, 901, 902, 903, 904, 905, 906, 920, 921, 922, 923, 924, 925}, + {907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919}, + {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1020, 1021, 1022, 1023, 1024, 1025}, + {1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019}}; + + for (int i = 0; i < DEofHC[hc].size(); i++) { + std::string volPathName = o2::mch::geo::volumePathName(DEofHC[hc][i]); + + TString path = Form("%s%s", parent.c_str(), volPathName.c_str()); + TString sname = Form("MCH/HC%d/DE%d", hc, DEofHC[hc][i]); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!geom.SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + } + + return; +} + +} // namespace impl + +namespace o2::mch::geo +{ + +void createGeometry(TGeoManager& geom, TGeoVolume& topVolume) +{ + createMaterials(); + + auto volYOUT1 = geom.GetVolume("YOUT1"); + + createStation1Geometry((volYOUT1) ? *volYOUT1 : topVolume); + createStation2Geometry((volYOUT1) ? *volYOUT1 : topVolume); + + createStation345Geometry(topVolume); +} + +std::vector<TGeoVolume*> getSensitiveVolumes() +{ + auto st1 = getStation1SensitiveVolumes(); + auto st2 = getStation2SensitiveVolumes(); + auto st345 = getStation345SensitiveVolumes(); + + auto vol = st1; + vol.insert(vol.end(), st2.begin(), st2.end()); + vol.insert(vol.end(), st345.begin(), st345.end()); + + return vol; +} + +void addAlignableVolumes(TGeoManager& geom) +{ + if (!geom.IsClosed()) { + geom.CloseGeometry(); + } + + LOG(INFO) << "Add MCH alignable volumes"; + + for (int hc = 0; hc < 20; hc++) { + int nCh = hc / 2 + 1; + + std::string volPathName = geom.GetTopVolume()->GetName(); + + if (nCh <= 4 && geom.GetVolume("YOUT1")) { + volPathName += "/YOUT1_1/"; + } else if ((nCh == 5 || nCh == 6) && geom.GetVolume("DDIP")) { + volPathName += "/DDIP_1/"; + } else if (nCh >= 7 && geom.GetVolume("YOUT2")) { + volPathName += "/YOUT2_1/"; + } else { + volPathName += "/"; + } + + std::string path = fmt::format("{0}SC{1}{2}{3}_{4}", volPathName.c_str(), nCh < 10 ? "0" : "", nCh, hc % 2 ? "O" : "I", hc); + std::string sname = fmt::format("MCH/HC{}", hc); + + LOG(DEBUG) << sname << " <-> " << path; + + auto ae = geom.SetAlignableEntry(sname.c_str(), path.c_str()); + if (!ae) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t lastUID = 0; + + impl::addAlignableVolumesHalfChamber(geom, hc, volPathName); + } + + return; +} + +} // namespace o2::mch::geo diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/MCHGeometryCreatorLinkDef.h b/Detectors/MUON/MCH/Geometry/Creator/src/MCHGeometryCreatorLinkDef.h new file mode 100644 index 0000000000000..f8d4a9d535d03 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/MCHGeometryCreatorLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ namespace o2::mch::geo; + +#pragma link C++ function o2::mch::geo::addAlignableVolumes; +#pragma link C++ function o2::mch::geo::createGeometry; +#pragma link C++ function o2::mch::geo::getSensitiveVolumes; + +#endif diff --git a/Detectors/MUON/MCH/Simulation/src/Materials.cxx b/Detectors/MUON/MCH/Geometry/Creator/src/Materials.cxx similarity index 96% rename from Detectors/MUON/MCH/Simulation/src/Materials.cxx rename to Detectors/MUON/MCH/Geometry/Creator/src/Materials.cxx index fab03522b401c..97aa94d00237b 100644 --- a/Detectors/MUON/MCH/Simulation/src/Materials.cxx +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Materials.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/Materials.h b/Detectors/MUON/MCH/Geometry/Creator/src/Materials.h new file mode 100644 index 0000000000000..a854a10a04fdd --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Materials.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Materials.h +/// \brief Implementation of the MCH materials definitions +/// \author Florian Damas <florian.damas@cern.ch> +/// \date 22 march 2018 + +#ifndef O2_MCH_GEOMETRY_CREATOR_MATERIALS_H +#define O2_MCH_GEOMETRY_CREATOR_MATERIALS_H + +class TGeoMedium; + +namespace o2::mch +{ + +enum Medium { + Gas, + Carbon, + HoneyNomex, + BulkNomex, + Noryl, + Copper, + FR4, + Rohacell, + Glue, + Plastic, + Epoxy, + Inox, + St1Rohacell, + Aluminium +}; + +// Return a pointer to the mch medium number imed. +// Throws an exception if imed is not within Medium enum +// and / or medium has not been defined yet. +TGeoMedium* assertMedium(int imed); + +void createMaterials(); + +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/Simulation/src/Station1Geometry.cxx b/Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.cxx similarity index 99% rename from Detectors/MUON/MCH/Simulation/src/Station1Geometry.cxx rename to Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.cxx index 046f16d23f5f0..1820f22afe25d 100644 --- a/Detectors/MUON/MCH/Simulation/src/Station1Geometry.cxx +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.h b/Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.h new file mode 100644 index 0000000000000..ea17e406b7e82 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station1Geometry.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Station1Geometry.h +/// \brief Implementation of the station 1 geometry +/// \author Florian Damas <florian.damas@cern.ch> +/// \date 16 mai 2018 + +#ifndef O2_MCH_GEOMETRY_CREATOR_STATION1GEOMETRY_H +#define O2_MCH_GEOMETRY_CREATOR_STATION1GEOMETRY_H + +#include <vector> + +class TGeoVolume; + +namespace o2::mch +{ + +void createStation1Geometry(TGeoVolume& topVolume); + +std::vector<TGeoVolume*> getStation1SensitiveVolumes(); + +} // namespace o2::mch +#endif diff --git a/Detectors/MUON/MCH/Simulation/src/Station2Geometry.cxx b/Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.cxx similarity index 97% rename from Detectors/MUON/MCH/Simulation/src/Station2Geometry.cxx rename to Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.cxx index db98d78535296..e65c832e412de 100644 --- a/Detectors/MUON/MCH/Simulation/src/Station2Geometry.cxx +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.h b/Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.h new file mode 100644 index 0000000000000..59ecfc8c1e383 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station2Geometry.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Station2Geometry.h +/// \brief Implementation of the station 2 geometry +/// \author Florian Damas <florian.damas@cern.ch> +/// \date 23 mai 2018 + +#ifndef O2_MCH_GEOMETRY_CREATOR_STATION2GEOMETRY_H +#define O2_MCH_GEOMETRY_CREATOR_STATION2GEOMETRY_H + +#include <vector> + +class TGeoVolume; + +namespace o2::mch +{ +void createStation2Geometry(TGeoVolume& topVolume); + +std::vector<TGeoVolume*> getStation2SensitiveVolumes(); + +} // namespace o2::mch +#endif diff --git a/Detectors/MUON/MCH/Simulation/src/Station345Geometry.cxx b/Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.cxx similarity index 99% rename from Detectors/MUON/MCH/Simulation/src/Station345Geometry.cxx rename to Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.cxx index d672a32f66039..fbfea72ed1ef3 100644 --- a/Detectors/MUON/MCH/Simulation/src/Station345Geometry.cxx +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.h b/Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.h new file mode 100644 index 0000000000000..21a803661bfcc --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Creator/src/Station345Geometry.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Station345Geometry.h +/// \brief Implementation of the slat-stations geometry +/// \author Florian Damas <florian.damas@cern.ch> +/// \date 22 march 2018 + +#ifndef O2_MCH_GEOMETRY_CREATOR_STATION345GEOMETRY_H +#define O2_MCH_GEOMETRY_CREATOR_STATION345GEOMETRY_H + +#include <vector> + +class TGeoVolume; + +namespace o2::mch +{ +void createStation345Geometry(TGeoVolume& topVolume); + +std::vector<TGeoVolume*> getStation345SensitiveVolumes(); + +} // namespace o2::mch +#endif diff --git a/Detectors/MUON/MCH/Geometry/README.md b/Detectors/MUON/MCH/Geometry/README.md new file mode 100644 index 0000000000000..7ceb822f51c85 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/README.md @@ -0,0 +1,15 @@ +<!-- doxy +\page refDetectorsMUONMCHGeometry Geometry +/doxy --> + +# MUON MCH Geometry + +The Geometry package is split in two parts : the [creation part](./Creator) (to +be used only for simulation) and the [transformation part](./Transformer) (to +be used from both simulation and reconstruction). + +<!-- doxy +\subpage refDetectorsMUONMCHGeometryTransformer +\subpage refDetectorsMUONMCHGeometryCreator +\subpage refDetectorsMUONMCHGeometryTest +/doxy --> diff --git a/Detectors/MUON/MCH/Geometry/Test/CMakeLists.txt b/Detectors/MUON/MCH/Geometry/Test/CMakeLists.txt new file mode 100644 index 0000000000000..382f8700a544c --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + MCHGeometryTest + SOURCES Helpers.cxx + PUBLIC_LINK_LIBRARIES O2::MCHGeometryCreator ROOT::RGL) + +o2_target_root_dictionary(MCHGeometryTest HEADERS include/MCHGeometryTest/Helpers.h LINKDEF LinkDef.h) + +o2_add_test( + geometry-creator + COMPONENT_NAME mch + SOURCES testGeometryCreator.cxx + PUBLIC_LINK_LIBRARIES O2::MCHGeometryTest + LABELS muon mch) + +o2_add_test( + geometry-transformer NAME mch/geometry-transformer + COMPONENT_NAME mch + SOURCES testGeometryTransformer.cxx + PUBLIC_LINK_LIBRARIES O2::MCHGeometryTest + COMMAND_LINE_ARGS ${CMAKE_CURRENT_LIST_DIR}/ideal-geometry-o2.json + LABELS muon mch) + +o2_add_test( + geometry-transformer-legacy NAME mch/geometry-transformer-legacy + COMPONENT_NAME mch + SOURCES testGeometryTransformer.cxx + PUBLIC_LINK_LIBRARIES O2::MCHGeometryTest + COMMAND_LINE_ARGS ${CMAKE_CURRENT_LIST_DIR}/ideal-geometry-aliroot.json + LABELS muon mch) + +o2_add_test_root_macro( + drawMCHGeometry.C + PUBLIC_LINK_LIBRARIES O2::MCHGeometryCreator O2::MathUtils + LABELS muon mch) diff --git a/Detectors/MUON/MCH/Geometry/Test/Helpers.cxx b/Detectors/MUON/MCH/Geometry/Test/Helpers.cxx new file mode 100644 index 0000000000000..1ca1aa76c5124 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/Helpers.cxx @@ -0,0 +1,242 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/MaterialManager.h" +#include "MCHGeometryCreator/Geometry.h" +#include "MCHGeometryTest/Helpers.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "Math/GenVector/Cartesian3D.h" +#include "TGLRnrCtx.h" +#include "TGLViewer.h" +#include "TGeoManager.h" +#include "TGeoVolume.h" +#include "TH2F.h" +#include "TPRegexp.h" +#include "TVirtualPad.h" +#include <iostream> + +namespace o2 +{ +namespace mch +{ +namespace test +{ + +TGeoVolume* createAirVacuumCave(const char* name) +{ + // create the air medium (only used for the geometry test) + auto& mgr = o2::base::MaterialManager::Instance(); + + const int nAir = 4; + Float_t aAir[nAir] = {12.0107, 14.0067, 15.9994, 39.948}; + Float_t zAir[nAir] = {6., 7., 8., 18.}; + Float_t wAir[nAir] = {0.000124, 0.755267, 0.231781, 0.012827}; + Float_t dAirVacuum = 1.20479E-10; + const int kID = 90; // to avoid conflicts with definitions of other MCH materials + + mgr.Mixture("MCH", kID, "Air", aAir, zAir, dAirVacuum, nAir, wAir); + mgr.Medium("MCH", kID, "Air", kID, + false, /* isvol */ + 0, /* ifield */ + -1.0, /* fieldm */ + -1.0, /* tmaxfd */ + -1.0, /* stemax */ + -1.0, /* deemax */ + -1.0, /* epsil */ + -1.0 /* stmin */); + return gGeoManager->MakeBox(name, gGeoManager->GetMedium("MCH_Air"), 2000.0, 2000.0, 3000.0); +} + +void dump(std::ostream& out, const TGeoNode& n, int level, int maxdepth, std::string prefix) +{ + if (level >= maxdepth) { + return; + } + + if (level == 0) { + out << n.GetName() << "\n"; + } + + if (level < maxdepth) { + for (int i = 0; i < n.GetNdaughters(); i++) { + TGeoNode* d = n.GetDaughter(i); + if (i == n.GetNdaughters() - 1) { + out << prefix + "└──" << d->GetName() + << "\n"; + dump(out, *d, level + 1, maxdepth, prefix + " "); + } else { + out << prefix + "├──" << d->GetName() + << "\n"; + dump(out, *d, level + 1, maxdepth, prefix + "│ "); + } + } + } +} + +void showGeometryAsTextTree(const char* fromPath, int maxdepth, std::ostream& out) +{ + if (!gGeoManager) { + return; + } + + TGeoNavigator* nav = gGeoManager->GetCurrentNavigator(); + + if (strlen(fromPath)) { + if (!nav->cd(fromPath)) { + std::cerr << "Could not get path " << fromPath << "\n"; + return; + } + } + + TGeoNode* node = nav->GetCurrentNode(); + + dump(out, *node, 0, maxdepth, ""); +} + +void createStandaloneGeometry() +{ + if (gGeoManager && gGeoManager->GetTopVolume()) { + std::cerr << "Can only call this function with an empty geometry, i.e. gGeoManager==nullptr " + << " or gGeoManager->GetTopVolume()==nullptr\n"; + } + TGeoManager* g = new TGeoManager("MCH-ONLY", "ALICE MCH Standalone Geometry"); + TGeoVolume* top = createAirVacuumCave("cave"); + g->SetTopVolume(top); + o2::mch::geo::createGeometry(*g, *top); +} + +void setVolumeVisibility(const char* pattern, bool visible, bool visibleDaughters) +{ + TPRegexp re(pattern); + TIter next(gGeoManager->GetListOfVolumes()); + TGeoVolume* vol; + + while ((vol = static_cast<TGeoVolume*>(next()))) { + if (TString(vol->GetName()).Contains(re)) { + vol->SetVisibility(visible); + vol->SetVisDaughters(visibleDaughters); + } + } +} + +void setVolumeColor(const char* pattern, int lineColor, int fillColor) +{ + TPRegexp re(pattern); + TIter next(gGeoManager->GetListOfVolumes()); + TGeoVolume* vol; + + while ((vol = static_cast<TGeoVolume*>(next()))) { + if (TString(vol->GetName()).Contains(re)) { + vol->SetFillColor(fillColor); + vol->SetLineColor(lineColor); + } + } +} + +void drawOptionPresetBasic() +{ + gGeoManager->SetVisLevel(4); + + setVolumeVisibility("cave", false, true); + + // Hide to half-chamber top volumes + setVolumeVisibility("^SC", false, true); + + // Hide St345 support panels + setVolumeVisibility("support panel", false, false); + + // Hide St345 LV wires + setVolumeVisibility(" LV ", false, false); + + // Make St345 carbon panels dark gray + setVolumeColor("panel carbon", kGray + 3); + + // Make St345 insulators dark green + setVolumeColor("insulator", kGreen + 3); + + // Hide most of St1 + setVolumeVisibility("SQ", false, true); + + // Only reveal gas module + setVolumeVisibility("SA", true, true); + setVolumeColor("SA", kCyan - 10); +} + +void drawGeometry() +{ + // minimal macro to test setup of the geometry + + createStandaloneGeometry(); + + drawOptionPresetBasic(); + + gGeoManager->GetTopVolume()->Draw("ogl"); + + TGLViewer* gl = static_cast<TGLViewer*>(gPad->GetViewer3D("ogl")); + TGLCamera& c = gl->CurrentCamera(); + + // gl->SetStyle(TGLRnrCtx::kWireFrame); + gl->SetStyle(TGLRnrCtx::kOutline); + // gl->SetStyle(TGLRnrCtx::kFill); +} + +o2::base::GeometryManager::MatBudgetExt getMatBudgetExt(const o2::math_utils::Transform3D& t, math_utils::Vector3D<double>& n, float x, float y, float thickness) +{ + math_utils::Point3D<double> point; + t.LocalToMaster(math_utils::Point3D<double>{x, y, 0}, point); + return o2::base::GeometryManager::meanMaterialBudgetExt(math_utils::Point3D<double>{point + n * thickness / 2.0}, math_utils::Point3D<double>{point - n * thickness / 2.0}); +} + +std::ostream& operator<<(std::ostream& os, o2::base::GeometryManager::MatBudgetExt m) +{ + os << "L=" << m.length << " <Rho>=" << m.meanRho << " <A>=" << m.meanA + << " <Z>=" << m.meanZ << " <x/x0>=" << m.meanX2X0 << " nCross=" << m.nCross; + return os; +} + +math_utils::Vector3D<double> getNormalVector(const o2::math_utils::Transform3D& t) +{ + math_utils::Point3D<double> px, py, po; + t.LocalToMaster(math_utils::Point3D<double>{0, 1, 0}, py); + t.LocalToMaster(math_utils::Point3D<double>{1, 0, 0}, px); + t.LocalToMaster(math_utils::Point3D<double>{0, 0, 0}, po); + math_utils::Vector3D<double> a{px - po}; + math_utils::Vector3D<double> b{py - po}; + return a.Cross(b).Unit(); +} + +TH2* getRadio(int detElemId, float xmin, float ymin, float xmax, float ymax, float xstep, float ystep, float thickness) +{ + if (xmin >= xmax || ymin >= ymax) { + std::cerr << "incorrect limits\n"; + return nullptr; + } + TH2* hmatb = new TH2F("hmatb", "hmatb", (int)((xmax - xmin) / xstep), xmin, xmax, (int)((ymax - ymin) / ystep), ymin, ymax); + + auto transformation = o2::mch::geo::transformationFromTGeoManager(*gGeoManager); + auto t = transformation(detElemId); + + auto normal = getNormalVector(t); + + for (auto x = xmin; x < xmax; x += xstep) { + for (auto y = ymin; y < ymax; y += ystep) { + auto matb = getMatBudgetExt(t, normal, x, y, thickness); + if (std::isfinite(matb.meanX2X0)) { + hmatb->Fill(x, y, matb.meanX2X0); + } + } + } + return hmatb; +} +} // namespace test +} // namespace mch +} // namespace o2 diff --git a/Detectors/MUON/MCH/Geometry/Test/LinkDef.h b/Detectors/MUON/MCH/Geometry/Test/LinkDef.h new file mode 100644 index 0000000000000..f46333ca54ea1 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/LinkDef.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ namespace o2::mch::test; + +#pragma link C++ class o2::mch::test::Dummy; + +#pragma link C++ function o2::mch::test::createStandaloneGeometry; +#pragma link C++ function o2::mch::test::createRegularGeometry; +#pragma link C++ function o2::mch::test::drawGeometry; +#pragma link C++ function o2::mch::test::getRadio; +#pragma link C++ function o2::mch::test::showGeometryAsTextTree; +#pragma link C++ function o2::mch::test::setVolumeVisibility; +#pragma link C++ function o2::mch::test::setVolumeColor; + +#endif diff --git a/Detectors/MUON/MCH/Geometry/Test/README.md b/Detectors/MUON/MCH/Geometry/Test/README.md new file mode 100644 index 0000000000000..2ccf93b48c1fa --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/README.md @@ -0,0 +1,13 @@ +<!-- doxy +\page refDetectorsMUONMCHGeometryTest Test +/doxy --> + +# MCH Geometry Helpers + +The [MCHGeometryTest](./include/MCHGeometryTest/Helpers.h) library offers a few +utility functions to help debug the MCH geometry : [draw +it](./drawMCHGeometry.C), dump it as text, create a standalone version of it +(i.e. without other ALICE volumes) + +Also provides a `getRadio` function to get a radiation length plot of a given +detection element. diff --git a/Detectors/MUON/MCH/Geometry/Test/drawMCHGeometry.C b/Detectors/MUON/MCH/Geometry/Test/drawMCHGeometry.C new file mode 100644 index 0000000000000..80235f0bb4ff6 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/drawMCHGeometry.C @@ -0,0 +1,8 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "MCHGeometryTest/Helpers.h" +#endif + +void drawMCHGeometry() +{ + o2::mch::test::drawGeometry(); +} diff --git a/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-aliroot.json b/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-aliroot.json new file mode 100644 index 0000000000000..e12ccadb6d8cd --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-aliroot.json @@ -0,0 +1,2224 @@ +{ + "alignables": [ + { + "symname": "/MUON/GM0", + "transform": { + "tx": 0, + "ty": 0, + "tz": -526.1599731445312, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "symname": "/MUON/GM1", + "transform": { + "tx": 0, + "ty": 0, + "tz": -545.239990234375, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "symname": "/MUON/GM2", + "transform": { + "tx": 0, + "ty": 0, + "tz": -676.4000244140625, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "symname": "/MUON/GM3", + "transform": { + "tx": 0, + "ty": 0, + "tz": -695.4000244140625, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "symname": "/MUON/GM4", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -967.4988477676281, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM5", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -967.5011522323719, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM6", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -998.4988477676281, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM7", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -998.5011522323719, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM8", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -1276.4988477676281, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM9", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -1276.5011522323719, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM10", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -1307.4988477676281, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM11", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -1307.5011522323719, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM12", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -1406.5988233535656, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM13", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -1406.6011278183094, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM14", + "transform": { + "tx": 0, + "ty": -0.16628965477512675, + "tz": -1437.5988233535656, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "symname": "/MUON/GM15", + "transform": { + "tx": 0, + "ty": 0.16628965477512675, + "tz": -1437.6011278183094, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 100, + "symname": "/MUON/GM0/DE100", + "transform": { + "tx": 0.185, + "ty": -0.52, + "tz": -529.9099731445312, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 101, + "symname": "/MUON/GM0/DE101", + "transform": { + "tx": -0.185, + "ty": -0.52, + "tz": -522.4099731445312, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 102, + "symname": "/MUON/GM0/DE102", + "transform": { + "tx": -0.185, + "ty": 0.52, + "tz": -529.9099731445312, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 103, + "symname": "/MUON/GM0/DE103", + "transform": { + "tx": 0.185, + "ty": 0.52, + "tz": -522.4099731445312, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 200, + "symname": "/MUON/GM1/DE200", + "transform": { + "tx": 0.185, + "ty": -0.52, + "tz": -548.989990234375, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 201, + "symname": "/MUON/GM1/DE201", + "transform": { + "tx": -0.185, + "ty": -0.52, + "tz": -541.489990234375, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 202, + "symname": "/MUON/GM1/DE202", + "transform": { + "tx": -0.185, + "ty": 0.52, + "tz": -548.989990234375, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 203, + "symname": "/MUON/GM1/DE203", + "transform": { + "tx": 0.185, + "ty": 0.52, + "tz": -541.489990234375, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 300, + "symname": "/MUON/GM2/DE300", + "transform": { + "tx": 0, + "ty": 0, + "tz": -679.8000245094299, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 301, + "symname": "/MUON/GM2/DE301", + "transform": { + "tx": 0, + "ty": 0, + "tz": -673.0000243186951, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 302, + "symname": "/MUON/GM2/DE302", + "transform": { + "tx": 0, + "ty": 0, + "tz": -679.8000245094299, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 303, + "symname": "/MUON/GM2/DE303", + "transform": { + "tx": 0, + "ty": 0, + "tz": -673.0000243186951, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 400, + "symname": "/MUON/GM3/DE400", + "transform": { + "tx": 0, + "ty": 0, + "tz": -698.8000245094299, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 401, + "symname": "/MUON/GM3/DE401", + "transform": { + "tx": 0, + "ty": 0, + "tz": -692.0000243186951, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 402, + "symname": "/MUON/GM3/DE402", + "transform": { + "tx": 0, + "ty": 0, + "tz": -698.8000245094299, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": true + }, + { + "deid": 403, + "symname": "/MUON/GM3/DE403", + "transform": { + "tx": 0, + "ty": 0, + "tz": -692.0000243186951, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": true + }, + { + "deid": 500, + "symname": "/MUON/GM4/DE500", + "transform": { + "tx": 81.25, + "ty": -0.003464367807815144, + "tz": -955.7499759951589, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 501, + "symname": "/MUON/GM4/DE501", + "transform": { + "tx": 81.25, + "ty": 37.68204556750454, + "tz": -964.2730202422136, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 502, + "symname": "/MUON/GM4/DE502", + "transform": { + "tx": 81.25, + "ty": 75.48928617018588, + "tz": -956.7962150731191, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 503, + "symname": "/MUON/GM4/DE503", + "transform": { + "tx": 61.25, + "ty": 112.67484792951139, + "tz": -965.3123306374202, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 504, + "symname": "/MUON/GM4/DE504", + "transform": { + "tx": 41.25, + "ty": 146.48246879531905, + "tz": -957.7800955305386, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 505, + "symname": "/MUON/GM5/DE505", + "transform": { + "tx": -41.25, + "ty": 146.48939753093464, + "tz": -981.2801435402207, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 506, + "symname": "/MUON/GM5/DE506", + "transform": { + "tx": -61.25, + "ty": 112.90349620482719, + "tz": -972.8139149569315, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 507, + "symname": "/MUON/GM5/DE507", + "transform": { + "tx": -81.25, + "ty": 75.49621490580152, + "tz": -980.2962630828013, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 508, + "symname": "/MUON/GM5/DE508", + "transform": { + "tx": -81.25, + "ty": 37.91069384282034, + "tz": -971.7746045617249, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 509, + "symname": "/MUON/GM5/DE509", + "transform": { + "tx": -81.25, + "ty": 0.003464367807815144, + "tz": -979.2500240048411, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 510, + "symname": "/MUON/GM5/DE510", + "transform": { + "tx": -81.25, + "ty": -37.68204556750454, + "tz": -970.7269797577864, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 511, + "symname": "/MUON/GM5/DE511", + "transform": { + "tx": -81.25, + "ty": -75.48928617018588, + "tz": -978.2037849268809, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 512, + "symname": "/MUON/GM5/DE512", + "transform": { + "tx": -61.25, + "ty": -112.67484792951139, + "tz": -969.6876693625798, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 513, + "symname": "/MUON/GM5/DE513", + "transform": { + "tx": -41.25, + "ty": -146.48246879531905, + "tz": -977.2199044694614, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 514, + "symname": "/MUON/GM4/DE514", + "transform": { + "tx": 41.25, + "ty": -146.48939753093464, + "tz": -953.7198564597793, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 515, + "symname": "/MUON/GM4/DE515", + "transform": { + "tx": 61.25, + "ty": -112.90349620482719, + "tz": -962.1860850430685, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 516, + "symname": "/MUON/GM4/DE516", + "transform": { + "tx": 81.25, + "ty": -75.49621490580152, + "tz": -954.7037369171987, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 517, + "symname": "/MUON/GM4/DE517", + "transform": { + "tx": 81.25, + "ty": -37.91069384282034, + "tz": -963.2253954382751, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 600, + "symname": "/MUON/GM6/DE600", + "transform": { + "tx": 81.25, + "ty": -0.003464367807815144, + "tz": -986.7499759951589, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 601, + "symname": "/MUON/GM6/DE601", + "transform": { + "tx": 81.25, + "ty": 37.68204556750454, + "tz": -995.2730202422136, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 602, + "symname": "/MUON/GM6/DE602", + "transform": { + "tx": 81.25, + "ty": 75.48928617018588, + "tz": -987.7962150731191, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 603, + "symname": "/MUON/GM6/DE603", + "transform": { + "tx": 61.25, + "ty": 112.67484792951139, + "tz": -996.3123306374202, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 604, + "symname": "/MUON/GM6/DE604", + "transform": { + "tx": 41.25, + "ty": 146.48246879531905, + "tz": -988.7800955305386, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 605, + "symname": "/MUON/GM7/DE605", + "transform": { + "tx": -41.25, + "ty": 146.48939753093464, + "tz": -1012.2801435402207, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 606, + "symname": "/MUON/GM7/DE606", + "transform": { + "tx": -61.25, + "ty": 112.90349620482719, + "tz": -1003.8139149569315, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 607, + "symname": "/MUON/GM7/DE607", + "transform": { + "tx": -81.25, + "ty": 75.49621490580152, + "tz": -1011.2962630828013, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 608, + "symname": "/MUON/GM7/DE608", + "transform": { + "tx": -81.25, + "ty": 37.91069384282034, + "tz": -1002.7746045617249, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 609, + "symname": "/MUON/GM7/DE609", + "transform": { + "tx": -81.25, + "ty": 0.003464367807815144, + "tz": -1010.2500240048411, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 610, + "symname": "/MUON/GM7/DE610", + "transform": { + "tx": -81.25, + "ty": -37.68204556750454, + "tz": -1001.7269797577864, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 611, + "symname": "/MUON/GM7/DE611", + "transform": { + "tx": -81.25, + "ty": -75.48928617018588, + "tz": -1009.2037849268809, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 612, + "symname": "/MUON/GM7/DE612", + "transform": { + "tx": -61.25, + "ty": -112.67484792951139, + "tz": -1000.6876693625798, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 613, + "symname": "/MUON/GM7/DE613", + "transform": { + "tx": -41.25, + "ty": -146.48246879531905, + "tz": -1008.2199044694614, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 614, + "symname": "/MUON/GM6/DE614", + "transform": { + "tx": 41.25, + "ty": -146.48939753093464, + "tz": -984.7198564597793, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 615, + "symname": "/MUON/GM6/DE615", + "transform": { + "tx": 61.25, + "ty": -112.90349620482719, + "tz": -993.1860850430685, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 616, + "symname": "/MUON/GM6/DE616", + "transform": { + "tx": 81.25, + "ty": -75.49621490580152, + "tz": -985.7037369171987, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 617, + "symname": "/MUON/GM6/DE617", + "transform": { + "tx": 81.25, + "ty": -37.91069384282034, + "tz": -994.2253954382751, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 700, + "symname": "/MUON/GM8/DE700", + "transform": { + "tx": 140, + "ty": 0, + "tz": -1264.5, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 701, + "symname": "/MUON/GM8/DE701", + "transform": { + "tx": 121.25, + "ty": 38.07854431768339, + "tz": -1273.5285392470098, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 702, + "symname": "/MUON/GM8/DE702", + "transform": { + "tx": 101.25, + "ty": 72.5930350970798, + "tz": -1265.5060524959688, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 703, + "symname": "/MUON/GM8/DE703", + "transform": { + "tx": 101.25, + "ty": 109.07173075714752, + "tz": -1274.5124197572914, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 704, + "symname": "/MUON/GM8/DE704", + "transform": { + "tx": 81.25, + "ty": 138.48670131804144, + "tz": -1266.4192597655297, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 705, + "symname": "/MUON/GM8/DE705", + "transform": { + "tx": 61.25, + "ty": 175.36536009609583, + "tz": -1275.4311700364894, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 706, + "symname": "/MUON/GM8/DE706", + "transform": { + "tx": 41.25, + "ty": 204.08040855067148, + "tz": -1267.3283099628795, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 707, + "symname": "/MUON/GM9/DE707", + "transform": { + "tx": -41.25, + "ty": 204.08040855067148, + "tz": -1291.3283099628795, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 708, + "symname": "/MUON/GM9/DE708", + "transform": { + "tx": -61.25, + "ty": 175.60093710702725, + "tz": -1282.4328023656828, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 709, + "symname": "/MUON/GM9/DE709", + "transform": { + "tx": -81.25, + "ty": 138.48670131804144, + "tz": -1290.4192597655297, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 710, + "symname": "/MUON/GM9/DE710", + "transform": { + "tx": -101.25, + "ty": 109.30730776807894, + "tz": -1281.5140520864848, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 711, + "symname": "/MUON/GM9/DE711", + "transform": { + "tx": -101.25, + "ty": 72.5930350970798, + "tz": -1289.5060524959688, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 712, + "symname": "/MUON/GM9/DE712", + "transform": { + "tx": -121.25, + "ty": 38.314121328614824, + "tz": -1280.5301715762032, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 713, + "symname": "/MUON/GM9/DE713", + "transform": { + "tx": -140, + "ty": 0, + "tz": -1288.5, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 714, + "symname": "/MUON/GM9/DE714", + "transform": { + "tx": -121.25, + "ty": -38.07854431768339, + "tz": -1279.4714607529902, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 715, + "symname": "/MUON/GM9/DE715", + "transform": { + "tx": -101.25, + "ty": -72.5930350970798, + "tz": -1287.4939475040312, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 716, + "symname": "/MUON/GM9/DE716", + "transform": { + "tx": -101.25, + "ty": -109.07173075714752, + "tz": -1278.4875802427086, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 717, + "symname": "/MUON/GM9/DE717", + "transform": { + "tx": -81.25, + "ty": -138.48670131804144, + "tz": -1286.5807402344703, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 718, + "symname": "/MUON/GM9/DE718", + "transform": { + "tx": -61.25, + "ty": -175.36536009609583, + "tz": -1277.5688299635106, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 719, + "symname": "/MUON/GM9/DE719", + "transform": { + "tx": -41.25, + "ty": -204.08040855067148, + "tz": -1285.6716900371205, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 720, + "symname": "/MUON/GM8/DE720", + "transform": { + "tx": 41.25, + "ty": -204.08040855067148, + "tz": -1261.6716900371205, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 721, + "symname": "/MUON/GM8/DE721", + "transform": { + "tx": 61.25, + "ty": -175.60093710702725, + "tz": -1270.5671976343172, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 722, + "symname": "/MUON/GM8/DE722", + "transform": { + "tx": 81.25, + "ty": -138.48670131804144, + "tz": -1262.5807402344703, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 723, + "symname": "/MUON/GM8/DE723", + "transform": { + "tx": 101.25, + "ty": -109.30730776807894, + "tz": -1271.4859479135152, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 724, + "symname": "/MUON/GM8/DE724", + "transform": { + "tx": 101.25, + "ty": -72.5930350970798, + "tz": -1263.4939475040312, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 725, + "symname": "/MUON/GM8/DE725", + "transform": { + "tx": 121.25, + "ty": -38.314121328614824, + "tz": -1272.4698284237968, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 800, + "symname": "/MUON/GM10/DE800", + "transform": { + "tx": 140, + "ty": 0, + "tz": -1295.5, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 801, + "symname": "/MUON/GM10/DE801", + "transform": { + "tx": 121.25, + "ty": 38.07854431768339, + "tz": -1304.5285392470098, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 802, + "symname": "/MUON/GM10/DE802", + "transform": { + "tx": 101.25, + "ty": 76.04270077880811, + "tz": -1296.553860729427, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 803, + "symname": "/MUON/GM10/DE803", + "transform": { + "tx": 101.25, + "ty": 113.4713097976769, + "tz": -1305.5733926518537, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 804, + "symname": "/MUON/GM10/DE804", + "transform": { + "tx": 81.25, + "ty": 142.986269230902, + "tz": -1297.4816183860703, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 805, + "symname": "/MUON/GM10/DE805", + "transform": { + "tx": 61.25, + "ty": 179.86492800895635, + "tz": -1306.49352865703, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 806, + "symname": "/MUON/GM10/DE806", + "transform": { + "tx": 41.25, + "ty": 208.57997646353203, + "tz": -1298.3906685834202, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 807, + "symname": "/MUON/GM11/DE807", + "transform": { + "tx": -41.25, + "ty": 208.57997646353203, + "tz": -1322.3906685834202, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 808, + "symname": "/MUON/GM11/DE808", + "transform": { + "tx": -61.25, + "ty": 180.10050501988778, + "tz": -1313.4951609862237, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 809, + "symname": "/MUON/GM11/DE809", + "transform": { + "tx": -81.25, + "ty": 142.986269230902, + "tz": -1321.4816183860703, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 810, + "symname": "/MUON/GM11/DE810", + "transform": { + "tx": -101.25, + "ty": 113.70688680860832, + "tz": -1312.5750249810471, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 811, + "symname": "/MUON/GM11/DE811", + "transform": { + "tx": -101.25, + "ty": 76.04270077880811, + "tz": -1320.553860729427, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 812, + "symname": "/MUON/GM11/DE812", + "transform": { + "tx": -121.25, + "ty": 38.314121328614824, + "tz": -1311.5301715762032, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 813, + "symname": "/MUON/GM11/DE813", + "transform": { + "tx": -140, + "ty": 0, + "tz": -1319.5, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 814, + "symname": "/MUON/GM11/DE814", + "transform": { + "tx": -121.25, + "ty": -38.07854431768339, + "tz": -1310.4714607529902, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 815, + "symname": "/MUON/GM11/DE815", + "transform": { + "tx": -101.25, + "ty": -76.04270077880811, + "tz": -1318.446139270573, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 816, + "symname": "/MUON/GM11/DE816", + "transform": { + "tx": -101.25, + "ty": -113.4713097976769, + "tz": -1309.4266073481463, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 817, + "symname": "/MUON/GM11/DE817", + "transform": { + "tx": -81.25, + "ty": -142.986269230902, + "tz": -1317.5183816139297, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 818, + "symname": "/MUON/GM11/DE818", + "transform": { + "tx": -61.25, + "ty": -179.86492800895635, + "tz": -1308.50647134297, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 819, + "symname": "/MUON/GM11/DE819", + "transform": { + "tx": -41.25, + "ty": -208.57997646353203, + "tz": -1316.6093314165798, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 820, + "symname": "/MUON/GM10/DE820", + "transform": { + "tx": 41.25, + "ty": -208.57997646353203, + "tz": -1292.6093314165798, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 821, + "symname": "/MUON/GM10/DE821", + "transform": { + "tx": 61.25, + "ty": -180.10050501988778, + "tz": -1301.5048390137763, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 822, + "symname": "/MUON/GM10/DE822", + "transform": { + "tx": 81.25, + "ty": -142.986269230902, + "tz": -1293.5183816139297, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 823, + "symname": "/MUON/GM10/DE823", + "transform": { + "tx": 101.25, + "ty": -113.70688680860832, + "tz": -1302.4249750189529, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 824, + "symname": "/MUON/GM10/DE824", + "transform": { + "tx": 101.25, + "ty": -76.04270077880811, + "tz": -1294.446139270573, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 825, + "symname": "/MUON/GM10/DE825", + "transform": { + "tx": 121.25, + "ty": -38.314121328614824, + "tz": -1303.4698284237968, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 900, + "symname": "/MUON/GM12/DE900", + "transform": { + "tx": 140, + "ty": 0, + "tz": -1394.5999755859375, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 901, + "symname": "/MUON/GM12/DE901", + "transform": { + "tx": 121.25, + "ty": 38.07854431768339, + "tz": -1403.6285148329473, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 902, + "symname": "/MUON/GM12/DE902", + "transform": { + "tx": 121.25, + "ty": 76.09269902930468, + "tz": -1395.6545292312157, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 903, + "symname": "/MUON/GM12/DE903", + "transform": { + "tx": 121.25, + "ty": 113.57129867000808, + "tz": -1404.6747539637695, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 904, + "symname": "/MUON/GM12/DE904", + "transform": { + "tx": 101.25, + "ty": 150.9855010759874, + "tz": -1396.692453741858, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 905, + "symname": "/MUON/GM12/DE905", + "transform": { + "tx": 81.25, + "ty": 187.91415810453836, + "tz": -1405.705056928669, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 906, + "symname": "/MUON/GM12/DE906", + "transform": { + "tx": 61.25, + "ty": 224.77841789836523, + "tz": -1397.7151351610146, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 907, + "symname": "/MUON/GM13/DE907", + "transform": { + "tx": -61.25, + "ty": 224.77841789836523, + "tz": -1421.7151351610146, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 908, + "symname": "/MUON/GM13/DE908", + "transform": { + "tx": -81.25, + "ty": 188.14973511546978, + "tz": -1412.7066892578623, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 909, + "symname": "/MUON/GM13/DE909", + "transform": { + "tx": -101.25, + "ty": 150.9855010759874, + "tz": -1420.692453741858, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 910, + "symname": "/MUON/GM13/DE910", + "transform": { + "tx": -121.25, + "ty": 113.8068756809395, + "tz": -1411.6763862929631, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 911, + "symname": "/MUON/GM13/DE911", + "transform": { + "tx": -121.25, + "ty": 76.09269902930468, + "tz": -1419.6545292312157, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 912, + "symname": "/MUON/GM13/DE912", + "transform": { + "tx": -121.25, + "ty": 38.314121328614824, + "tz": -1410.6301471621407, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 913, + "symname": "/MUON/GM13/DE913", + "transform": { + "tx": -140, + "ty": 0, + "tz": -1418.5999755859375, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 914, + "symname": "/MUON/GM13/DE914", + "transform": { + "tx": -121.25, + "ty": -38.07854431768339, + "tz": -1409.5714363389277, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 915, + "symname": "/MUON/GM13/DE915", + "transform": { + "tx": -121.25, + "ty": -76.09269902930468, + "tz": -1417.5454219406593, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 916, + "symname": "/MUON/GM13/DE916", + "transform": { + "tx": -121.25, + "ty": -113.57129867000808, + "tz": -1408.5251972081055, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 917, + "symname": "/MUON/GM13/DE917", + "transform": { + "tx": -101.25, + "ty": -150.9855010759874, + "tz": -1416.507497430017, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 918, + "symname": "/MUON/GM13/DE918", + "transform": { + "tx": -81.25, + "ty": -187.91415810453836, + "tz": -1407.494894243206, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 919, + "symname": "/MUON/GM13/DE919", + "transform": { + "tx": -61.25, + "ty": -224.77841789836523, + "tz": -1415.4848160108604, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 920, + "symname": "/MUON/GM12/DE920", + "transform": { + "tx": 61.25, + "ty": -224.77841789836523, + "tz": -1391.4848160108604, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 921, + "symname": "/MUON/GM12/DE921", + "transform": { + "tx": 81.25, + "ty": -188.14973511546978, + "tz": -1400.4932619140127, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 922, + "symname": "/MUON/GM12/DE922", + "transform": { + "tx": 101.25, + "ty": -150.9855010759874, + "tz": -1392.507497430017, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 923, + "symname": "/MUON/GM12/DE923", + "transform": { + "tx": 121.25, + "ty": -113.8068756809395, + "tz": -1401.5235648789119, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 924, + "symname": "/MUON/GM12/DE924", + "transform": { + "tx": 121.25, + "ty": -76.09269902930468, + "tz": -1393.5454219406593, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 925, + "symname": "/MUON/GM12/DE925", + "transform": { + "tx": 121.25, + "ty": -38.314121328614824, + "tz": -1402.5698040097343, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1000, + "symname": "/MUON/GM14/DE1000", + "transform": { + "tx": 140, + "ty": 0, + "tz": -1425.5999755859375, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1001, + "symname": "/MUON/GM14/DE1001", + "transform": { + "tx": 121.25, + "ty": 38.07854431768339, + "tz": -1434.6285148329473, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1002, + "symname": "/MUON/GM14/DE1002", + "transform": { + "tx": 121.25, + "ty": 76.09269902930468, + "tz": -1426.6545292312157, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1003, + "symname": "/MUON/GM14/DE1003", + "transform": { + "tx": 121.25, + "ty": 113.57129867000808, + "tz": -1435.6747539637695, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1004, + "symname": "/MUON/GM14/DE1004", + "transform": { + "tx": 101.25, + "ty": 150.9855010759874, + "tz": -1427.692453741858, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1005, + "symname": "/MUON/GM14/DE1005", + "transform": { + "tx": 81.25, + "ty": 187.91415810453836, + "tz": -1436.705056928669, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1006, + "symname": "/MUON/GM14/DE1006", + "transform": { + "tx": 61.25, + "ty": 224.77841789836523, + "tz": -1428.7151351610146, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1007, + "symname": "/MUON/GM15/DE1007", + "transform": { + "tx": -61.25, + "ty": 224.77841789836523, + "tz": -1452.7151351610146, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1008, + "symname": "/MUON/GM15/DE1008", + "transform": { + "tx": -81.25, + "ty": 188.14973511546978, + "tz": -1443.7066892578623, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1009, + "symname": "/MUON/GM15/DE1009", + "transform": { + "tx": -101.25, + "ty": 150.9855010759874, + "tz": -1451.692453741858, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1010, + "symname": "/MUON/GM15/DE1010", + "transform": { + "tx": -121.25, + "ty": 113.8068756809395, + "tz": -1442.6763862929631, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1011, + "symname": "/MUON/GM15/DE1011", + "transform": { + "tx": -121.25, + "ty": 76.09269902930468, + "tz": -1450.6545292312157, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1012, + "symname": "/MUON/GM15/DE1012", + "transform": { + "tx": -121.25, + "ty": 38.314121328614824, + "tz": -1441.6301471621407, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1013, + "symname": "/MUON/GM15/DE1013", + "transform": { + "tx": -140, + "ty": 0, + "tz": -1449.5999755859375, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1014, + "symname": "/MUON/GM15/DE1014", + "transform": { + "tx": -121.25, + "ty": -38.07854431768339, + "tz": -1440.5714363389277, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1015, + "symname": "/MUON/GM15/DE1015", + "transform": { + "tx": -121.25, + "ty": -76.09269902930468, + "tz": -1448.5454219406593, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1016, + "symname": "/MUON/GM15/DE1016", + "transform": { + "tx": -121.25, + "ty": -113.57129867000808, + "tz": -1439.5251972081055, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1017, + "symname": "/MUON/GM15/DE1017", + "transform": { + "tx": -101.25, + "ty": -150.9855010759874, + "tz": -1447.507497430017, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1018, + "symname": "/MUON/GM15/DE1018", + "transform": { + "tx": -81.25, + "ty": -187.91415810453836, + "tz": -1438.494894243206, + "yaw": -180, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1019, + "symname": "/MUON/GM15/DE1019", + "transform": { + "tx": -61.25, + "ty": -224.77841789836523, + "tz": -1446.4848160108604, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1020, + "symname": "/MUON/GM14/DE1020", + "transform": { + "tx": 61.25, + "ty": -224.77841789836523, + "tz": -1422.4848160108604, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1021, + "symname": "/MUON/GM14/DE1021", + "transform": { + "tx": 81.25, + "ty": -188.14973511546978, + "tz": -1431.4932619140127, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1022, + "symname": "/MUON/GM14/DE1022", + "transform": { + "tx": 101.25, + "ty": -150.9855010759874, + "tz": -1423.507497430017, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1023, + "symname": "/MUON/GM14/DE1023", + "transform": { + "tx": 121.25, + "ty": -113.8068756809395, + "tz": -1432.5235648789119, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + }, + { + "deid": 1024, + "symname": "/MUON/GM14/DE1024", + "transform": { + "tx": 121.25, + "ty": -76.09269902930468, + "tz": -1424.5454219406593, + "yaw": -0, + "pitch": 0, + "roll": 179.2059999704361 + }, + "aligned": true + }, + { + "deid": 1025, + "symname": "/MUON/GM14/DE1025", + "transform": { + "tx": 121.25, + "ty": -38.314121328614824, + "tz": -1433.5698040097343, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000295639039 + }, + "aligned": true + } + ] +} diff --git a/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-o2.json b/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-o2.json new file mode 100644 index 0000000000000..a385539ed7e07 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/ideal-geometry-o2.json @@ -0,0 +1,2272 @@ +{ + "alignables": [ + { + "symname": "MCH/HC0", + "transform": { + "tx": 0, + "ty": 0, + "tz": -526.1599731445312, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC1", + "transform": { + "tx": 0, + "ty": 0, + "tz": -526.1599731445312, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC2", + "transform": { + "tx": 0, + "ty": 0, + "tz": -545.239990234375, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC3", + "transform": { + "tx": 0, + "ty": 0, + "tz": -545.239990234375, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC4", + "transform": { + "tx": 0, + "ty": 0, + "tz": -676.4, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC5", + "transform": { + "tx": 0, + "ty": 0, + "tz": -676.4, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC6", + "transform": { + "tx": 0, + "ty": 0, + "tz": -695.4, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC7", + "transform": { + "tx": 0, + "ty": 0, + "tz": -695.4, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "symname": "MCH/HC8", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -959.75, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC9", + "transform": { + "tx": 0, + "ty": 0.1074, + "tz": -975.25, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC10", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -990.75, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC11", + "transform": { + "tx": 0, + "ty": 0.1074, + "tz": -1006.25, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC12", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1259.75, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC13", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1284.25, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC14", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1299.75, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC15", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1315.25, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC16", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1398.85, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC17", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1414.35, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC18", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1429.85, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "symname": "MCH/HC19", + "transform": { + "tx": 0, + "ty": -0.1074, + "tz": -1445.35, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 100, + "symname": "MCH/HC0/DE100", + "transform": { + "tx": 0.1850000023841858, + "ty": -0.5199999809265137, + "tz": -529.9099731445312, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 101, + "symname": "MCH/HC1/DE101", + "transform": { + "tx": -0.1850000023841858, + "ty": -0.5199999809265137, + "tz": -522.4099731445312, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 102, + "symname": "MCH/HC1/DE102", + "transform": { + "tx": -0.1850000023841858, + "ty": 0.5199999809265137, + "tz": -529.9099731445312, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 103, + "symname": "MCH/HC0/DE103", + "transform": { + "tx": 0.1850000023841858, + "ty": 0.5199999809265137, + "tz": -522.4099731445312, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 200, + "symname": "MCH/HC2/DE200", + "transform": { + "tx": 0.1850000023841858, + "ty": -0.5199999809265137, + "tz": -548.989990234375, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 201, + "symname": "MCH/HC3/DE201", + "transform": { + "tx": -0.1850000023841858, + "ty": -0.5199999809265137, + "tz": -541.489990234375, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 202, + "symname": "MCH/HC3/DE202", + "transform": { + "tx": -0.1850000023841858, + "ty": 0.5199999809265137, + "tz": -548.989990234375, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 203, + "symname": "MCH/HC2/DE203", + "transform": { + "tx": 0.1850000023841858, + "ty": 0.5199999809265137, + "tz": -541.489990234375, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 300, + "symname": "MCH/HC4/DE300", + "transform": { + "tx": 0, + "ty": 0, + "tz": -680.3, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 301, + "symname": "MCH/HC5/DE301", + "transform": { + "tx": 0, + "ty": 0, + "tz": -672.5, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 302, + "symname": "MCH/HC5/DE302", + "transform": { + "tx": 0, + "ty": 0, + "tz": -680.3, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 303, + "symname": "MCH/HC4/DE303", + "transform": { + "tx": 0, + "ty": 0, + "tz": -672.5, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 400, + "symname": "MCH/HC6/DE400", + "transform": { + "tx": 0, + "ty": 0, + "tz": -699.3, + "yaw": -0, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 401, + "symname": "MCH/HC7/DE401", + "transform": { + "tx": 0, + "ty": 0, + "tz": -691.5, + "yaw": -180, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 402, + "symname": "MCH/HC7/DE402", + "transform": { + "tx": 0, + "ty": 0, + "tz": -699.3, + "yaw": -180, + "pitch": 0, + "roll": -0 + }, + "aligned": false + }, + { + "deid": 403, + "symname": "MCH/HC6/DE403", + "transform": { + "tx": 0, + "ty": 0, + "tz": -691.5, + "yaw": -0, + "pitch": 0, + "roll": -180 + }, + "aligned": false + }, + { + "deid": 500, + "symname": "MCH/HC8/DE500", + "transform": { + "tx": 81.25, + "ty": -0.05197011713870941, + "tz": -955.7503840774286, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 501, + "symname": "MCH/HC8/DE501", + "transform": { + "tx": 81.25, + "ty": 37.63354058543762, + "tz": -964.2734283156105, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 502, + "symname": "MCH/HC8/DE502", + "transform": { + "tx": 81.25, + "ty": 75.44078042139485, + "tz": -956.7966231164355, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 503, + "symname": "MCH/HC8/DE503", + "transform": { + "tx": 61.25, + "ty": 112.62633913364976, + "tz": -965.3127386192597, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 504, + "symname": "MCH/HC8/DE504", + "transform": { + "tx": 41.25, + "ty": 146.43396304703566, + "tz": -957.7805035372235, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 505, + "symname": "MCH/HC9/DE505", + "transform": { + "tx": -41.25, + "ty": 146.5379032813131, + "tz": -981.2797353823661, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 506, + "symname": "MCH/HC9/DE506", + "transform": { + "tx": -61.25, + "ty": 112.95199889937234, + "tz": -972.8135067741171, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 507, + "symname": "MCH/HC9/DE507", + "transform": { + "tx": -81.25, + "ty": 75.54472065567226, + "tz": -980.2958549615781, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 508, + "symname": "MCH/HC9/DE508", + "transform": { + "tx": -81.25, + "ty": 37.9592003511602, + "tz": -971.7741964704679, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 509, + "symname": "MCH/HC9/DE509", + "transform": { + "tx": -81.25, + "ty": 0.05197011713870941, + "tz": -979.2496159225714, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 510, + "symname": "MCH/HC9/DE510", + "transform": { + "tx": -81.25, + "ty": -37.63354058543762, + "tz": -970.7265716843895, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 511, + "symname": "MCH/HC9/DE511", + "transform": { + "tx": -81.25, + "ty": -75.44078042139485, + "tz": -978.2033768835645, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 512, + "symname": "MCH/HC9/DE512", + "transform": { + "tx": -61.25, + "ty": -112.62633913364976, + "tz": -969.6872613807403, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 513, + "symname": "MCH/HC9/DE513", + "transform": { + "tx": -41.25, + "ty": -146.43396304703566, + "tz": -977.2194964627765, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 514, + "symname": "MCH/HC8/DE514", + "transform": { + "tx": 41.25, + "ty": -146.5379032813131, + "tz": -953.7202646176339, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 515, + "symname": "MCH/HC8/DE515", + "transform": { + "tx": 61.25, + "ty": -112.95199889937234, + "tz": -962.1864932258829, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 516, + "symname": "MCH/HC8/DE516", + "transform": { + "tx": 81.25, + "ty": -75.54472065567226, + "tz": -954.7041450384219, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 517, + "symname": "MCH/HC8/DE517", + "transform": { + "tx": 81.25, + "ty": -37.9592003511602, + "tz": -963.2258035295321, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 600, + "symname": "MCH/HC10/DE600", + "transform": { + "tx": 81.25, + "ty": -0.05197011713870941, + "tz": -986.7503840774286, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 601, + "symname": "MCH/HC10/DE601", + "transform": { + "tx": 81.25, + "ty": 37.63354058543762, + "tz": -995.2734283156105, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 602, + "symname": "MCH/HC10/DE602", + "transform": { + "tx": 81.25, + "ty": 75.44078042139485, + "tz": -987.7966231164355, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 603, + "symname": "MCH/HC10/DE603", + "transform": { + "tx": 61.25, + "ty": 112.62633913364976, + "tz": -996.3127386192597, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 604, + "symname": "MCH/HC10/DE604", + "transform": { + "tx": 41.25, + "ty": 146.43396304703566, + "tz": -988.7805035372235, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 605, + "symname": "MCH/HC11/DE605", + "transform": { + "tx": -41.25, + "ty": 146.5379032813131, + "tz": -1012.2797353823661, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 606, + "symname": "MCH/HC11/DE606", + "transform": { + "tx": -61.25, + "ty": 112.95199889937234, + "tz": -1003.8135067741171, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 607, + "symname": "MCH/HC11/DE607", + "transform": { + "tx": -81.25, + "ty": 75.54472065567226, + "tz": -1011.2958549615781, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 608, + "symname": "MCH/HC11/DE608", + "transform": { + "tx": -81.25, + "ty": 37.9592003511602, + "tz": -1002.7741964704679, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 609, + "symname": "MCH/HC11/DE609", + "transform": { + "tx": -81.25, + "ty": 0.05197011713870941, + "tz": -1010.2496159225714, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 610, + "symname": "MCH/HC11/DE610", + "transform": { + "tx": -81.25, + "ty": -37.63354058543762, + "tz": -1001.7265716843895, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 611, + "symname": "MCH/HC11/DE611", + "transform": { + "tx": -81.25, + "ty": -75.44078042139485, + "tz": -1009.2033768835645, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 612, + "symname": "MCH/HC11/DE612", + "transform": { + "tx": -61.25, + "ty": -112.62633913364976, + "tz": -1000.6872613807403, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 613, + "symname": "MCH/HC11/DE613", + "transform": { + "tx": -41.25, + "ty": -146.43396304703566, + "tz": -1008.2194964627765, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 614, + "symname": "MCH/HC10/DE614", + "transform": { + "tx": 41.25, + "ty": -146.5379032813131, + "tz": -984.7202646176339, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 615, + "symname": "MCH/HC10/DE615", + "transform": { + "tx": 61.25, + "ty": -112.95199889937234, + "tz": -993.1864932258829, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 616, + "symname": "MCH/HC10/DE616", + "transform": { + "tx": 81.25, + "ty": -75.54472065567226, + "tz": -985.7041450384219, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 617, + "symname": "MCH/HC10/DE617", + "transform": { + "tx": 81.25, + "ty": -37.9592003511602, + "tz": -994.2258035295321, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 700, + "symname": "MCH/HC12/DE700", + "transform": { + "tx": 140, + "ty": -0.04850574945987875, + "tz": -1255.500408082268, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 701, + "symname": "MCH/HC12/DE701", + "transform": { + "tx": 121.25, + "ty": 38.03003781001593, + "tz": -1264.5289472990573, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 702, + "symname": "MCH/HC12/DE702", + "transform": { + "tx": 101.25, + "ty": 72.54452324520946, + "tz": -1256.5064604562003, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 703, + "symname": "MCH/HC12/DE703", + "transform": { + "tx": 101.25, + "ty": 109.02322043565675, + "tz": -1265.5128277198453, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 704, + "symname": "MCH/HC12/DE704", + "transform": { + "tx": 81.25, + "ty": 138.43819556957186, + "tz": -1257.4196677763402, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 705, + "symname": "MCH/HC12/DE705", + "transform": { + "tx": 61.25, + "ty": 175.31685435227624, + "tz": -1266.4315780282711, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 706, + "symname": "MCH/HC12/DE706", + "transform": { + "tx": 41.25, + "ty": 204.43185829199854, + "tz": -1258.3342608435514, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 707, + "symname": "MCH/HC13/DE707", + "transform": { + "tx": -41.25, + "ty": 204.31406979091827, + "tz": -1291.3334446790154, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 708, + "symname": "MCH/HC13/DE708", + "transform": { + "tx": -61.25, + "ty": 175.4346428533565, + "tz": -1282.4323941928071, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 709, + "symname": "MCH/HC13/DE709", + "transform": { + "tx": -81.25, + "ty": 138.3204070684916, + "tz": -1290.4188516118043, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 710, + "symname": "MCH/HC13/DE710", + "transform": { + "tx": -101.25, + "ty": 109.141008936737, + "tz": -1281.5136438843813, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 711, + "symname": "MCH/HC13/DE711", + "transform": { + "tx": -101.25, + "ty": 72.42673474412922, + "tz": -1289.5056442916643, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 712, + "symname": "MCH/HC13/DE712", + "transform": { + "tx": -121.25, + "ty": 38.147826311096175, + "tz": -1280.5297634635933, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 713, + "symname": "MCH/HC13/DE713", + "transform": { + "tx": -140, + "ty": -0.16629425054012126, + "tz": -1288.499591917732, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 714, + "symname": "MCH/HC13/DE714", + "transform": { + "tx": -121.25, + "ty": -38.24483781001593, + "tz": -1279.4710527009427, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 715, + "symname": "MCH/HC13/DE715", + "transform": { + "tx": -101.25, + "ty": -72.75932324520946, + "tz": -1287.4935395437997, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 716, + "symname": "MCH/HC13/DE716", + "transform": { + "tx": -101.25, + "ty": -109.23802043565675, + "tz": -1278.4871722801547, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 717, + "symname": "MCH/HC13/DE717", + "transform": { + "tx": -81.25, + "ty": -138.65299556957189, + "tz": -1286.5803322236598, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 718, + "symname": "MCH/HC13/DE718", + "transform": { + "tx": -61.25, + "ty": -175.53165435227626, + "tz": -1277.5684219717289, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 719, + "symname": "MCH/HC13/DE719", + "transform": { + "tx": -41.25, + "ty": -204.64665829199856, + "tz": -1285.6657391564486, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 720, + "symname": "MCH/HC12/DE720", + "transform": { + "tx": 41.25, + "ty": -204.5288697909183, + "tz": -1252.6665553209846, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 721, + "symname": "MCH/HC12/DE721", + "transform": { + "tx": 61.25, + "ty": -175.64944285335653, + "tz": -1261.5676058071929, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 722, + "symname": "MCH/HC12/DE722", + "transform": { + "tx": 81.25, + "ty": -138.53520706849162, + "tz": -1253.5811483881957, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 723, + "symname": "MCH/HC12/DE723", + "transform": { + "tx": 101.25, + "ty": -109.35580893673699, + "tz": -1262.4863561156187, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 724, + "symname": "MCH/HC12/DE724", + "transform": { + "tx": 101.25, + "ty": -72.64153474412922, + "tz": -1254.4943557083357, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 725, + "symname": "MCH/HC12/DE725", + "transform": { + "tx": 121.25, + "ty": -38.36262631109617, + "tz": -1263.4702365364067, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 800, + "symname": "MCH/HC14/DE800", + "transform": { + "tx": 140, + "ty": -0.04850574945987875, + "tz": -1295.500408082268, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 801, + "symname": "MCH/HC14/DE801", + "transform": { + "tx": 121.25, + "ty": 38.03003781001593, + "tz": -1304.5289472990573, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 802, + "symname": "MCH/HC14/DE802", + "transform": { + "tx": 101.25, + "ty": 75.99419197842722, + "tz": -1296.5542687301684, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 803, + "symname": "MCH/HC14/DE803", + "transform": { + "tx": 101.25, + "ty": 113.42279795048519, + "tz": -1305.5738005909927, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 804, + "symname": "MCH/HC14/DE804", + "transform": { + "tx": 81.25, + "ty": 142.9377634824646, + "tz": -1297.4820263945592, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 805, + "symname": "MCH/HC14/DE805", + "transform": { + "tx": 61.25, + "ty": 179.81642226516897, + "tz": -1306.49393664649, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 806, + "symname": "MCH/HC14/DE806", + "transform": { + "tx": 41.25, + "ty": 208.53146461263412, + "tz": -1298.3910764734842, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 807, + "symname": "MCH/HC15/DE807", + "transform": { + "tx": -41.25, + "ty": 208.41367611155385, + "tz": -1322.3902603089484, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 808, + "symname": "MCH/HC15/DE808", + "transform": { + "tx": -61.25, + "ty": 179.93421076624924, + "tz": -1313.494752811026, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 809, + "symname": "MCH/HC15/DE809", + "transform": { + "tx": -81.25, + "ty": 142.81997498138432, + "tz": -1321.4812102300232, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 810, + "symname": "MCH/HC15/DE810", + "transform": { + "tx": -101.25, + "ty": 113.54058645156543, + "tz": -1312.5746167555287, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 811, + "symname": "MCH/HC15/DE811", + "transform": { + "tx": -101.25, + "ty": 75.87640347734698, + "tz": -1320.5534525656324, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 812, + "symname": "MCH/HC15/DE812", + "transform": { + "tx": -121.25, + "ty": 38.147826311096175, + "tz": -1311.5297634635933, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 813, + "symname": "MCH/HC15/DE813", + "transform": { + "tx": -140, + "ty": -0.16629425054012126, + "tz": -1319.499591917732, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 814, + "symname": "MCH/HC15/DE814", + "transform": { + "tx": -121.25, + "ty": -38.24483781001593, + "tz": -1310.4710527009427, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 815, + "symname": "MCH/HC15/DE815", + "transform": { + "tx": -101.25, + "ty": -76.20899197842722, + "tz": -1318.4457312698316, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 816, + "symname": "MCH/HC15/DE816", + "transform": { + "tx": -101.25, + "ty": -113.63759795048519, + "tz": -1309.4261994090073, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 817, + "symname": "MCH/HC15/DE817", + "transform": { + "tx": -81.25, + "ty": -143.15256348246461, + "tz": -1317.5179736054408, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 818, + "symname": "MCH/HC15/DE818", + "transform": { + "tx": -61.25, + "ty": -180.031222265169, + "tz": -1308.50606335351, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 819, + "symname": "MCH/HC15/DE819", + "transform": { + "tx": -41.25, + "ty": -208.74626461263415, + "tz": -1316.6089235265158, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 820, + "symname": "MCH/HC14/DE820", + "transform": { + "tx": 41.25, + "ty": -208.62847611155388, + "tz": -1292.6097396910516, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 821, + "symname": "MCH/HC14/DE821", + "transform": { + "tx": 61.25, + "ty": -180.14901076624926, + "tz": -1301.505247188974, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 822, + "symname": "MCH/HC14/DE822", + "transform": { + "tx": 81.25, + "ty": -143.03477498138434, + "tz": -1293.5187897699768, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 823, + "symname": "MCH/HC14/DE823", + "transform": { + "tx": 101.25, + "ty": -113.75538645156543, + "tz": -1302.4253832444713, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 824, + "symname": "MCH/HC14/DE824", + "transform": { + "tx": 101.25, + "ty": -76.09120347734698, + "tz": -1294.4465474343676, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 825, + "symname": "MCH/HC14/DE825", + "transform": { + "tx": 121.25, + "ty": -38.36262631109617, + "tz": -1303.4702365364067, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 900, + "symname": "MCH/HC16/DE900", + "transform": { + "tx": 140, + "ty": -0.04850574945987875, + "tz": -1394.600408082268, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 901, + "symname": "MCH/HC16/DE901", + "transform": { + "tx": 121.25, + "ty": 38.03003781001593, + "tz": -1403.6289472990572, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 902, + "symname": "MCH/HC16/DE902", + "transform": { + "tx": 121.25, + "ty": 76.04418717745936, + "tz": -1395.654961603704, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 903, + "symname": "MCH/HC16/DE903", + "transform": { + "tx": 121.25, + "ty": 113.52278834854948, + "tz": -1404.6751863380641, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 904, + "symname": "MCH/HC16/DE904", + "transform": { + "tx": 101.25, + "ty": 150.93699532760724, + "tz": -1396.6928861602817, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 905, + "symname": "MCH/HC16/DE905", + "transform": { + "tx": 81.25, + "ty": 187.86564930934375, + "tz": -1405.7054892857484, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 906, + "symname": "MCH/HC16/DE906", + "transform": { + "tx": 61.25, + "ty": 224.72990909904797, + "tz": -1397.7155674990724, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 907, + "symname": "MCH/HC17/DE907", + "transform": { + "tx": -61.25, + "ty": 224.6121205979677, + "tz": -1421.7147513345365, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 908, + "symname": "MCH/HC17/DE908", + "transform": { + "tx": -81.25, + "ty": 187.98343781042402, + "tz": -1412.7063054502844, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 909, + "symname": "MCH/HC17/DE909", + "transform": { + "tx": -101.25, + "ty": 150.81920682652697, + "tz": -1420.6920699957457, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 910, + "symname": "MCH/HC17/DE910", + "transform": { + "tx": -121.25, + "ty": 113.64057684962972, + "tz": -1411.6760025026, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 911, + "symname": "MCH/HC17/DE911", + "transform": { + "tx": -121.25, + "ty": 75.92639867637912, + "tz": -1419.654145439168, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 912, + "symname": "MCH/HC17/DE912", + "transform": { + "tx": -121.25, + "ty": 38.147826311096175, + "tz": -1410.6297634635932, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 913, + "symname": "MCH/HC17/DE913", + "transform": { + "tx": -140, + "ty": -0.16629425054012126, + "tz": -1418.599591917732, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 914, + "symname": "MCH/HC17/DE914", + "transform": { + "tx": -121.25, + "ty": -38.24483781001593, + "tz": -1409.5710527009426, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 915, + "symname": "MCH/HC17/DE915", + "transform": { + "tx": -121.25, + "ty": -76.25898717745936, + "tz": -1417.545038396296, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 916, + "symname": "MCH/HC17/DE916", + "transform": { + "tx": -121.25, + "ty": -113.73758834854948, + "tz": -1408.5248136619357, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 917, + "symname": "MCH/HC17/DE917", + "transform": { + "tx": -101.25, + "ty": -151.15179532760726, + "tz": -1416.5071138397182, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 918, + "symname": "MCH/HC17/DE918", + "transform": { + "tx": -81.25, + "ty": -188.08044930934378, + "tz": -1407.4945107142514, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 919, + "symname": "MCH/HC17/DE919", + "transform": { + "tx": -61.25, + "ty": -224.944709099048, + "tz": -1415.4844325009274, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 920, + "symname": "MCH/HC16/DE920", + "transform": { + "tx": 61.25, + "ty": -224.82692059796773, + "tz": -1391.4852486654634, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 921, + "symname": "MCH/HC16/DE921", + "transform": { + "tx": 81.25, + "ty": -188.19823781042405, + "tz": -1400.4936945497154, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 922, + "symname": "MCH/HC16/DE922", + "transform": { + "tx": 101.25, + "ty": -151.034006826527, + "tz": -1392.5079300042541, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 923, + "symname": "MCH/HC16/DE923", + "transform": { + "tx": 121.25, + "ty": -113.85537684962972, + "tz": -1401.5239974973997, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 924, + "symname": "MCH/HC16/DE924", + "transform": { + "tx": 121.25, + "ty": -76.14119867637912, + "tz": -1393.545854560832, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 925, + "symname": "MCH/HC16/DE925", + "transform": { + "tx": 121.25, + "ty": -38.36262631109617, + "tz": -1402.5702365364066, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1000, + "symname": "MCH/HC18/DE1000", + "transform": { + "tx": 140, + "ty": -0.04850574945987875, + "tz": -1425.600408082268, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1001, + "symname": "MCH/HC18/DE1001", + "transform": { + "tx": 121.25, + "ty": 38.03003781001593, + "tz": -1434.6289472990572, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1002, + "symname": "MCH/HC18/DE1002", + "transform": { + "tx": 121.25, + "ty": 76.04418717745936, + "tz": -1426.654961603704, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1003, + "symname": "MCH/HC18/DE1003", + "transform": { + "tx": 121.25, + "ty": 113.52278834854948, + "tz": -1435.6751863380641, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1004, + "symname": "MCH/HC18/DE1004", + "transform": { + "tx": 101.25, + "ty": 150.93699532760724, + "tz": -1427.6928861602817, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1005, + "symname": "MCH/HC18/DE1005", + "transform": { + "tx": 81.25, + "ty": 187.86564930934375, + "tz": -1436.7054892857484, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1006, + "symname": "MCH/HC18/DE1006", + "transform": { + "tx": 61.25, + "ty": 224.72990909904797, + "tz": -1428.7155674990724, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1007, + "symname": "MCH/HC19/DE1007", + "transform": { + "tx": -61.25, + "ty": 224.6121205979677, + "tz": -1452.7147513345365, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1008, + "symname": "MCH/HC19/DE1008", + "transform": { + "tx": -81.25, + "ty": 187.98343781042402, + "tz": -1443.7063054502844, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1009, + "symname": "MCH/HC19/DE1009", + "transform": { + "tx": -101.25, + "ty": 150.81920682652697, + "tz": -1451.6920699957457, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1010, + "symname": "MCH/HC19/DE1010", + "transform": { + "tx": -121.25, + "ty": 113.64057684962972, + "tz": -1442.6760025026, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1011, + "symname": "MCH/HC19/DE1011", + "transform": { + "tx": -121.25, + "ty": 75.92639867637912, + "tz": -1450.654145439168, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1012, + "symname": "MCH/HC19/DE1012", + "transform": { + "tx": -121.25, + "ty": 38.147826311096175, + "tz": -1441.6297634635932, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1013, + "symname": "MCH/HC19/DE1013", + "transform": { + "tx": -140, + "ty": -0.16629425054012126, + "tz": -1449.599591917732, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1014, + "symname": "MCH/HC19/DE1014", + "transform": { + "tx": -121.25, + "ty": -38.24483781001593, + "tz": -1440.5710527009426, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1015, + "symname": "MCH/HC19/DE1015", + "transform": { + "tx": -121.25, + "ty": -76.25898717745936, + "tz": -1448.545038396296, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1016, + "symname": "MCH/HC19/DE1016", + "transform": { + "tx": -121.25, + "ty": -113.73758834854948, + "tz": -1439.5248136619357, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1017, + "symname": "MCH/HC19/DE1017", + "transform": { + "tx": -101.25, + "ty": -151.15179532760726, + "tz": -1447.5071138397182, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1018, + "symname": "MCH/HC19/DE1018", + "transform": { + "tx": -81.25, + "ty": -188.08044930934378, + "tz": -1438.4945107142514, + "yaw": -180, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1019, + "symname": "MCH/HC19/DE1019", + "transform": { + "tx": -61.25, + "ty": -224.944709099048, + "tz": -1446.4844325009274, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1020, + "symname": "MCH/HC18/DE1020", + "transform": { + "tx": 61.25, + "ty": -224.82692059796773, + "tz": -1422.4852486654634, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1021, + "symname": "MCH/HC18/DE1021", + "transform": { + "tx": 81.25, + "ty": -188.19823781042405, + "tz": -1431.4936945497154, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1022, + "symname": "MCH/HC18/DE1022", + "transform": { + "tx": 101.25, + "ty": -151.034006826527, + "tz": -1423.5079300042541, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1023, + "symname": "MCH/HC18/DE1023", + "transform": { + "tx": 121.25, + "ty": -113.85537684962972, + "tz": -1432.5239974973997, + "yaw": -0, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + }, + { + "deid": 1024, + "symname": "MCH/HC18/DE1024", + "transform": { + "tx": 121.25, + "ty": -76.14119867637912, + "tz": -1424.545854560832, + "yaw": -0, + "pitch": 0, + "roll": 179.20600000000002 + }, + "aligned": false + }, + { + "deid": 1025, + "symname": "MCH/HC18/DE1025", + "transform": { + "tx": 121.25, + "ty": -38.36262631109617, + "tz": -1433.5702365364066, + "yaw": -180, + "pitch": 0, + "roll": -0.7940000000000002 + }, + "aligned": false + } + ] +} diff --git a/Detectors/MUON/MCH/Geometry/Test/include/MCHGeometryTest/Helpers.h b/Detectors/MUON/MCH/Geometry/Test/include/MCHGeometryTest/Helpers.h new file mode 100644 index 0000000000000..a13b7b21350c7 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/include/MCHGeometryTest/Helpers.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_GEOMETRY_TEST_HELPERS_H +#define O2_MCH_GEOMETRY_TEST_HELPERS_H + +#include <iostream> + +class TH2; + +namespace o2::mch::test +{ + +/// creates MCH geometry from scratch (i.e. from a null TGeoManager) +/// usefull for tests or drawing for instance. +void createStandaloneGeometry(); + +/// tree like textual dump of the geometry nodes +void showGeometryAsTextTree(const char* fromPath = "", int maxdepth = 2, std::ostream& out = std::cout); + +/// basic drawing of the geometry +void drawGeometry(); + +/// set the volume and daughter visibility for all volumes with a name matching the regexp pattern +void setVolumeVisibility(const char* pattern, bool visible, bool visibleDaughters); + +/// set the volume line and fill for all volumes with a name matching the regexp pattern +void setVolumeColor(const char* pattern, int lineColor, int fillColor); +inline void setVolumeColor(const char* pattern, int color) +{ + setVolumeColor(pattern, color, color); +} + +/// get a radlen radiograph of a given detection element within box with the given granularity +TH2* getRadio(int detElemId, float xmin, float ymin, float xmax, float ymax, float xstep, float ystep, float thickness = 5 /* cm */); + +class Dummy +{ + // to force Root produce a dictionary for namespace test (seems it is doing it fully if there are only functions in the namespace) +}; +} // namespace o2::mch::test + +#endif diff --git a/Detectors/MUON/MCH/Simulation/macros/rootlogon.C b/Detectors/MUON/MCH/Geometry/Test/rootlogon.C similarity index 100% rename from Detectors/MUON/MCH/Simulation/macros/rootlogon.C rename to Detectors/MUON/MCH/Geometry/Test/rootlogon.C diff --git a/Detectors/MUON/MCH/Geometry/Test/testGeometryCreator.cxx b/Detectors/MUON/MCH/Geometry/Test/testGeometryCreator.cxx new file mode 100644 index 0000000000000..890ace8795815 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/testGeometryCreator.cxx @@ -0,0 +1,373 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// @author Laurent Aphecetche + +#define BOOST_TEST_MODULE Test MCHSimulation Geometry +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN + +#include <boost/test/unit_test.hpp> + +#include "MCHGeometryCreator/Geometry.h" +#include "MCHGeometryTest/Helpers.h" +#include "TGeoManager.h" +#include "boost/format.hpp" +#include <boost/test/data/test_case.hpp> +#include <iomanip> +#include <iostream> +#include <fmt/format.h> + +namespace bdata = boost::unit_test::data; + +struct GEOMETRY { + GEOMETRY() + { + if (!gGeoManager) { + o2::mch::test::createStandaloneGeometry(); + o2::mch::geo::addAlignableVolumes(*gGeoManager); + } + }; +}; + +const std::array<std::string, 8> quadrantChamberNames{"SC01I", "SC01O", "SC02I", "SC02O", "SC03I", "SC03O", + "SC04I", "SC04O"}; + +const std::array<std::string, 12> slatChamberNames{"SC05I", "SC05O", "SC06I", "SC06O", "SC07I", "SC07O", + "SC08I", "SC08O", "SC09I", "SC09O", "SC10I", "SC10O"}; + +const std::vector<std::vector<std::string>> deSymNames{ + {"DE100", "DE103"}, + {"DE101", "DE102"}, + {"DE200", "DE203"}, + {"DE201", "DE202"}, + {"DE300", "DE303"}, + {"DE301", "DE302"}, + {"DE400", "DE403"}, + {"DE401", "DE402"}, + {"DE500", "DE501", "DE502", "DE503", "DE504", "DE514", "DE515", "DE516", "DE517"}, + {"DE505", "DE506", "DE507", "DE508", "DE509", "DE510", "DE511", "DE512", "DE513"}, + {"DE600", "DE601", "DE602", "DE603", "DE604", "DE614", "DE615", "DE616", "DE617"}, + {"DE605", "DE606", "DE607", "DE608", "DE609", "DE610", "DE611", "DE612", "DE613"}, + {"DE700", "DE701", "DE702", "DE703", "DE704", "DE705", "DE706", "DE720", "DE721", "DE722", "DE723", "DE724", "DE725"}, + {"DE707", "DE708", "DE709", "DE710", "DE711", "DE712", "DE713", "DE714", "DE715", "DE716", "DE717", "DE718", "DE719"}, + {"DE800", "DE801", "DE802", "DE803", "DE804", "DE805", "DE806", "DE820", "DE821", "DE822", "DE823", "DE824", "DE825"}, + {"DE807", "DE808", "DE809", "DE810", "DE811", "DE812", "DE813", "DE814", "DE815", "DE816", "DE817", "DE818", "DE819"}, + {"DE900", "DE901", "DE902", "DE903", "DE904", "DE905", "DE906", "DE920", "DE921", "DE922", "DE923", "DE924", "DE925"}, + {"DE907", "DE908", "DE909", "DE910", "DE911", "DE912", "DE913", "DE914", "DE915", "DE916", "DE917", "DE918", "DE919"}, + {"DE1000", "DE1001", "DE1002", "DE1003", "DE1004", "DE1005", "DE1006", "DE1020", "DE1021", "DE1022", "DE1023", "DE1024", "DE1025"}, + {"DE1007", "DE1008", "DE1009", "DE1010", "DE1011", "DE1012", "DE1013", "DE1014", "DE1015", "DE1016", "DE1017", "DE1018", "DE1019"}}; + +BOOST_FIXTURE_TEST_SUITE(geometrycreator, GEOMETRY) + +BOOST_AUTO_TEST_CASE(CanGetAllChambers) +{ + std::vector<std::string> chamberNames{quadrantChamberNames.begin(), quadrantChamberNames.end()}; + + chamberNames.insert(chamberNames.end(), slatChamberNames.begin(), slatChamberNames.end()); + + for (auto chname : chamberNames) { + auto vol = gGeoManager->GetVolume(chname.c_str()); + BOOST_TEST_REQUIRE((vol != nullptr)); + } +} + +std::vector<TGeoNode*> getSlatNodes() +{ + std::vector<TGeoNode*> slats; + for (auto chname : slatChamberNames) { + auto vol = gGeoManager->GetVolume(chname.c_str()); + TIter next(vol->GetNodes()); + while (TGeoNode* node = static_cast<TGeoNode*>(next())) { + if (strstr(node->GetName(), "support") == nullptr) { + slats.push_back(node); + } + } + } + return slats; +} + +std::vector<TGeoNode*> getQuadrantNodes() +{ + std::vector<TGeoNode*> quadrants; + for (auto chname : quadrantChamberNames) { + auto vol = gGeoManager->GetVolume(chname.c_str()); + TIter next(vol->GetNodes()); + while (TGeoNode* node = static_cast<TGeoNode*>(next())) { + quadrants.push_back(node); + } + } + return quadrants; +} + +BOOST_AUTO_TEST_CASE(GetRightNumberOfSlats) +{ + auto slats = getSlatNodes(); + BOOST_CHECK_EQUAL(slats.size(), 140); +} + +BOOST_AUTO_TEST_CASE(GetRightNumberOfQuadrants) +{ + auto quadrants = getQuadrantNodes(); + BOOST_CHECK_EQUAL(quadrants.size(), 16); +} + +BOOST_AUTO_TEST_CASE(GetDetElemVolumePath, *boost::unit_test::disabled() * boost::unit_test::label("debug")) +{ + TIter next(gGeoManager->GetTopNode()->GetNodes()); + TGeoNode* node; + TGeoNode* n2; + + std::vector<std::string> codeLines; + + while ((node = static_cast<TGeoNode*>(next()))) { + std::cout << node->GetName() << "\n"; + TIter next2(node->GetNodes()); + while ((n2 = static_cast<TGeoNode*>(next2()))) { + std::string n2name{n2->GetName()}; + auto index = n2name.find_last_of('_'); + int detElemId = std::atoi(n2name.substr(index + 1).c_str()); + if (detElemId >= 100) { + std::stringstream s; + s << "if (detElemId==" << detElemId << ") {\n"; + s << R"( return ")" << node->GetName() << "/" << n2name << "\";\n"; + s << "}\n"; + codeLines.push_back(s.str()); + } + } + } + + for (auto s : codeLines) { + std::cout << s; + } + BOOST_CHECK_EQUAL(codeLines.size(), 156); +} + +BOOST_AUTO_TEST_CASE(TextualTreeDump) +{ + const std::string expected = + R"(cave_1 +├──SC01I_0 +│ ├──Quadrant (chamber 1)_100 +│ └──Quadrant (chamber 1)_103 +├──SC01O_1 +│ ├──Quadrant (chamber 1)_101 +│ └──Quadrant (chamber 1)_102 +├──SC02I_2 +│ ├──Quadrant (chamber 2)_200 +│ └──Quadrant (chamber 2)_203 +├──SC02O_3 +│ ├──Quadrant (chamber 2)_201 +│ └──Quadrant (chamber 2)_202 +├──SC03I_4 +│ ├──Station 2 quadrant_300 +│ └──Station 2 quadrant_303 +├──SC03O_5 +│ ├──Station 2 quadrant_301 +│ └──Station 2 quadrant_302 +├──SC04I_6 +│ ├──Station 2 quadrant_400 +│ └──Station 2 quadrant_403 +├──SC04O_7 +│ ├──Station 2 quadrant_401 +│ └──Station 2 quadrant_402 +├──SC05I_8 +│ ├──Chamber 5 support panel_8 +│ ├──122000SR1_500 +│ ├──112200SR2_501 +│ ├──122200S_502 +│ ├──222000N_503 +│ ├──220000N_504 +│ ├──220000N_514 +│ ├──222000N_515 +│ ├──122200S_516 +│ └──112200SR2_517 +├──SC05O_9 +│ ├──Chamber 5 support panel_9 +│ ├──220000N_505 +│ ├──222000N_506 +│ ├──122200S_507 +│ ├──112200SR2_508 +│ ├──122000SR1_509 +│ ├──112200SR2_510 +│ ├──122200S_511 +│ ├──222000N_512 +│ └──220000N_513 +├──SC06I_10 +│ ├──Chamber 6 support panel_10 +│ ├──122000NR1_600 +│ ├──112200NR2_601 +│ ├──122200N_602 +│ ├──222000N_603 +│ ├──220000N_604 +│ ├──220000N_614 +│ ├──222000N_615 +│ ├──122200N_616 +│ └──112200NR2_617 +├──SC06O_11 +│ ├──Chamber 6 support panel_11 +│ ├──220000N_605 +│ ├──222000N_606 +│ ├──122200N_607 +│ ├──112200NR2_608 +│ ├──122000NR1_609 +│ ├──112200NR2_610 +│ ├──122200N_611 +│ ├──222000N_612 +│ └──220000N_613 +├──SC07I_12 +│ ├──Chamber 7 support panel_12 +│ ├──122330N_700 +│ ├──112233NR3_701 +│ ├──112230N_702 +│ ├──222330N_703 +│ ├──223300N_704 +│ ├──333000N_705 +│ ├──330000N_706 +│ ├──330000N_720 +│ ├──333000N_721 +│ ├──223300N_722 +│ ├──222330N_723 +│ ├──112230N_724 +│ └──112233NR3_725 +├──SC07O_13 +│ ├──Chamber 7 support panel_13 +│ ├──330000N_707 +│ ├──333000N_708 +│ ├──223300N_709 +│ ├──222330N_710 +│ ├──112230N_711 +│ ├──112233NR3_712 +│ ├──122330N_713 +│ ├──112233NR3_714 +│ ├──112230N_715 +│ ├──222330N_716 +│ ├──223300N_717 +│ ├──333000N_718 +│ └──330000N_719 +├──SC08I_14 +│ ├──Chamber 8 support panel_14 +│ ├──122330N_800 +│ ├──112233NR3_801 +│ ├──112230N_802 +│ ├──222330N_803 +│ ├──223300N_804 +│ ├──333000N_805 +│ ├──330000N_806 +│ ├──330000N_820 +│ ├──333000N_821 +│ ├──223300N_822 +│ ├──222330N_823 +│ ├──112230N_824 +│ └──112233NR3_825 +├──SC08O_15 +│ ├──Chamber 8 support panel_15 +│ ├──330000N_807 +│ ├──333000N_808 +│ ├──223300N_809 +│ ├──222330N_810 +│ ├──112230N_811 +│ ├──112233NR3_812 +│ ├──122330N_813 +│ ├──112233NR3_814 +│ ├──112230N_815 +│ ├──222330N_816 +│ ├──223300N_817 +│ ├──333000N_818 +│ └──330000N_819 +├──SC09I_16 +│ ├──Chamber 9 support panel_16 +│ ├──122330N_900 +│ ├──112233NR3_901 +│ ├──112233N_902 +│ ├──222333N_903 +│ ├──223330N_904 +│ ├──333300N_905 +│ ├──333000N_906 +│ ├──333000N_920 +│ ├──333300N_921 +│ ├──223330N_922 +│ ├──222333N_923 +│ ├──112233N_924 +│ └──112233NR3_925 +├──SC09O_17 +│ ├──Chamber 9 support panel_17 +│ ├──333000N_907 +│ ├──333300N_908 +│ ├──223330N_909 +│ ├──222333N_910 +│ ├──112233N_911 +│ ├──112233NR3_912 +│ ├──122330N_913 +│ ├──112233NR3_914 +│ ├──112233N_915 +│ ├──222333N_916 +│ ├──223330N_917 +│ ├──333300N_918 +│ └──333000N_919 +├──SC10I_18 +│ ├──Chamber 10 support panel_18 +│ ├──122330N_1000 +│ ├──112233NR3_1001 +│ ├──112233N_1002 +│ ├──222333N_1003 +│ ├──223330N_1004 +│ ├──333300N_1005 +│ ├──333000N_1006 +│ ├──333000N_1020 +│ ├──333300N_1021 +│ ├──223330N_1022 +│ ├──222333N_1023 +│ ├──112233N_1024 +│ └──112233NR3_1025 +└──SC10O_19 + ├──Chamber 10 support panel_19 + ├──333000N_1007 + ├──333300N_1008 + ├──223330N_1009 + ├──222333N_1010 + ├──112233N_1011 + ├──112233NR3_1012 + ├──122330N_1013 + ├──112233NR3_1014 + ├──112233N_1015 + ├──222333N_1016 + ├──223330N_1017 + ├──333300N_1018 + └──333000N_1019 +)"; + + std::ostringstream str; + o2::mch::test::showGeometryAsTextTree("/cave_1", 2, str); + BOOST_CHECK(expected == str.str()); +} + +BOOST_AUTO_TEST_CASE(GetAlignableHalfChambers) +{ + BOOST_REQUIRE(gGeoManager != nullptr); + + for (int i = 0; i < 20; i++) { + BOOST_CHECK((gGeoManager->GetAlignableEntry((fmt::format("MCH/HC{}", i)).c_str()))); + } +} + +BOOST_AUTO_TEST_CASE(GetAlignableDetectionElements) +{ + BOOST_REQUIRE(gGeoManager != nullptr); + + for (int hc = 0; hc < 20; hc++) { + for (int de = 0; de < deSymNames[hc].size(); de++) { + BOOST_CHECK((gGeoManager->GetAlignableEntry((fmt::format("MCH/HC{}/{}", hc, deSymNames[hc][de].c_str())).c_str()))); + } + } +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Geometry/Test/testGeometryTransformer.cxx b/Detectors/MUON/MCH/Geometry/Test/testGeometryTransformer.cxx new file mode 100644 index 0000000000000..b950c417a51fa --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Test/testGeometryTransformer.cxx @@ -0,0 +1,228 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// @author Laurent Aphecetche + +#define BOOST_TEST_MODULE Test MCHSimulation GeometryTransformer +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include "MCHGeometryCreator/Geometry.h" +#include "MCHGeometryTest/Helpers.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "TGeoManager.h" +#include "boost/format.hpp" +#include <boost/test/data/test_case.hpp> +#include <fstream> +#include <iomanip> +#include <iostream> +#include <fmt/format.h> +#include <random> + +namespace bdata = boost::unit_test::data; + +BOOST_TEST_DONT_PRINT_LOG_VALUE(o2::mch::geo::TransformationCreator) + +constexpr int ntrans{2}; + +o2::mch::geo::TransformationCreator transformation(int i) +{ + static std::vector<o2::mch::geo::TransformationCreator> vtrans; + + BOOST_REQUIRE(boost::unit_test::framework::master_test_suite().argc == 2); + + if (vtrans.empty()) { + if (!gGeoManager) { + o2::mch::test::createStandaloneGeometry(); + o2::mch::geo::addAlignableVolumes(*gGeoManager); + } + BOOST_TEST_REQUIRE(boost::unit_test::framework::master_test_suite().argc == 2); + std::string jsonInput = boost::unit_test::framework::master_test_suite().argv[1]; + std::ifstream in(jsonInput); + vtrans = { + o2::mch::geo::transformationFromJSON(in), + o2::mch::geo::transformationFromTGeoManager(*gGeoManager)}; + } + return vtrans[i]; +} + +constexpr double rad2deg = 180.0 / 3.14159265358979323846; +constexpr double deg2rad = 3.14159265358979323846 / 180.0; + +void dumpMat(gsl::span<double> m) +{ + std::cout << fmt::format( + "{:7.3f} {:7.3f} {:7.3f}\n" + "{:7.3f} {:7.3f} {:7.3f}\n" + "{:7.3f} {:7.3f} {:7.3f}\n", + m[0], m[1], m[2], + m[3], m[4], m[5], + m[6], m[7], m[8]); +} + +BOOST_DATA_TEST_CASE(GetTransformationMustNotThrowForValidDetElemId, bdata::xrange(ntrans), tindex) +{ + for (auto detElemId : o2::mch::geo::allDeIds) { + BOOST_REQUIRE_NO_THROW((transformation(tindex))(detElemId)); + } +} + +BOOST_DATA_TEST_CASE(GetTransformationMustThrowForInvalidDetElemId, bdata::xrange(ntrans), tindex) +{ + const auto someInvalidDetElemIds = {99, 105, 1026}; + + for (auto detElemId : someInvalidDetElemIds) { + BOOST_CHECK_THROW((transformation(tindex)(detElemId)), std::runtime_error); + } +} + +struct CoarseLocation { + bool isRight; + bool isTop; +}; + +constexpr CoarseLocation topRight{true, true}; +constexpr CoarseLocation topLeft{false, true}; +constexpr CoarseLocation bottomRight{true, false}; +constexpr CoarseLocation bottomLeft{false, false}; + +std::string asString(const CoarseLocation& q) +{ + std::string s = q.isTop ? "TOP" : "BOTTOM"; + s += q.isRight ? "RIGHT" : "LEFT"; + return s; +} + +bool operator==(const CoarseLocation& a, const CoarseLocation& b) +{ + return a.isRight == b.isRight && a.isTop == b.isTop; +} + +CoarseLocation getDetElemCoarseLocation(int detElemId, o2::mch::geo::TransformationCreator transformation) +{ + auto t = transformation(detElemId); + + o2::math_utils::Point3D<double> localTestPos{0.0, 0.0, 0.0}; // slat center + + if (detElemId < 500) { + // in the rough ballpark of the center + // of the quadrants + localTestPos.SetXYZ(60, 60, 0); + } + + // for slats around the middle (y closest to 0) we have to be a bit + // more precise, so take a given pad reference, chosen to be + // the most top right or most top left pad + + switch (detElemId) { + case 500: + case 509: + localTestPos.SetXYZ(-72.50, 19.75, 0.0); // ds 107 + break; + case 600: + case 609: + localTestPos.SetXYZ(-77.50, 19.75, 0.0); // ds 108 + break; + case 700: + case 713: + case 800: + case 813: + case 900: + case 913: + case 1000: + case 1013: + localTestPos.SetXYZ(95.0, -19.75, 0); // ds 104 + break; + } + o2::math_utils::Point3D<double> master; + + t.LocalToMaster(localTestPos, master); + bool right = master.x() > 10.; + bool top = master.y() > -10.; + + return CoarseLocation{right, top}; +} + +void setExpectation(int firstDeId, int lastDeId, CoarseLocation q, std::map<int, CoarseLocation>& expected) +{ + for (int deid = firstDeId; deid <= lastDeId; deid++) { + expected.emplace(deid, q); + } +} + +BOOST_DATA_TEST_CASE(DetectionElementMustBeInTheRightCoarseLocation, bdata::xrange(ntrans), tindex) +{ + std::map<int, CoarseLocation> expected; + + for (int i = 0; i < 4; i++) { + expected[100 + i * 100] = topRight; + expected[101 + i * 100] = topLeft; + expected[102 + i * 100] = bottomLeft; + expected[103 + i * 100] = bottomRight; + } + + // note that by convention we consider slats in the middle to be "top" + for (int i = 0; i < 2; i++) { + setExpectation(500 + i * 100, 504 + i * 100, topRight, expected); + setExpectation(505 + i * 100, 509 + i * 100, topLeft, expected); + setExpectation(510 + i * 100, 513 + i * 100, bottomLeft, expected); + setExpectation(514 + i * 100, 517 + i * 100, bottomRight, expected); + } + + for (int i = 0; i < 4; i++) { + setExpectation(700 + i * 100, 706 + i * 100, topRight, expected); + setExpectation(707 + i * 100, 713 + i * 100, topLeft, expected); + setExpectation(714 + i * 100, 719 + i * 100, bottomLeft, expected); + setExpectation(720 + i * 100, 725 + i * 100, bottomRight, expected); + } + + for (auto detElemId : o2::mch::geo::allDeIds) { + if (expected.find(detElemId) == expected.end()) { + std::cout << "got no expectation for DE=" << detElemId << "\n"; + return; + } + BOOST_TEST_INFO_SCOPE(fmt::format("DeId {}", detElemId)); + BOOST_CHECK_EQUAL(asString(getDetElemCoarseLocation(detElemId, transformation(tindex))), asString(expected[detElemId])); + }; +} + +BOOST_AUTO_TEST_CASE(Angle2Matrix2Angle) +{ + std::random_device rd; + std::mt19937 mt(rd()); + std::vector<std::tuple<double, double, double>> testAngles; + int n{100}; + + testAngles.resize(n); + constexpr double pi = 3.14159265358979323846; + std::uniform_real_distribution<double> dist{-pi / 2.0, pi / 2.0}; + std::uniform_real_distribution<double> dist2{-pi, pi}; + std::generate(testAngles.begin(), testAngles.end(), [&dist, &dist2, &mt] { + return std::tuple<double, double, double>{dist2(mt), dist(mt), dist2(mt)}; + }); + + testAngles.emplace_back(-pi, pi / 2.0, 0); + for (auto a : testAngles) { + auto [yaw, pitch, roll] = a; + auto m = o2::mch::geo::angles2matrix(yaw, pitch, roll); + auto [y, p, r] = o2::mch::geo::matrix2angles(m); + BOOST_TEST_INFO_SCOPE(fmt::format( + " input yaw {:7.2f} pitch {:7.2f} roll {:7.2f}\n" + "output yaw {:7.2f} pitch {:7.2f} roll {:7.2f}\n", + yaw, pitch, roll, + y, p, r)); + BOOST_CHECK_CLOSE(y, yaw, 1E-6); + BOOST_CHECK_CLOSE(p, pitch, 1E-6); + BOOST_CHECK_CLOSE(r, roll, 1E-6); + } +} diff --git a/Detectors/MUON/MCH/Geometry/Transformer/CMakeLists.txt b/Detectors/MUON/MCH/Geometry/Transformer/CMakeLists.txt new file mode 100644 index 0000000000000..538546db6eb44 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + MCHGeometryTransformer + SOURCES src/Transformations.cxx src/VolumePaths.cxx + PUBLIC_LINK_LIBRARIES ROOT::Geom O2::MathUtils Microsoft.GSL::GSL + RapidJSON::RapidJSON) + +o2_add_executable( + convert-geometry + SOURCES src/convert-geometry.cxx + PUBLIC_LINK_LIBRARIES ROOT::Geom Microsoft.GSL::GSL Boost::program_options + O2::MCHGeometryTransformer + COMPONENT_NAME mch) diff --git a/Detectors/MUON/MCH/Geometry/Transformer/README.md b/Detectors/MUON/MCH/Geometry/Transformer/README.md new file mode 100644 index 0000000000000..8bca4d3263281 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/README.md @@ -0,0 +1,36 @@ +<!-- doxy +\page refDetectorsMUONMCHGeometryTransformer Transformations +/doxy --> + +# MCH Geometry Transformations + +Here you will find functions to perform transformations on MCH geometry : local +to global, global to local, and various (mis)alignement ones. + +## MCH Transformations in JSON format + +Also available is a CLI utility to extract MCH transformations (rotations and +translations) from a Root geometry file and export them in JSON format : + +```shell +o2-mch-convert-geometry --geom o2sim_geometry.root > geom.json +``` + +The JSON output is compact on purpose, to save some space (e.g. on github). + +But as any JSON it can be manipulated further with e.g. [jq](https://stedolan.github.io/jq/) + +For instance you can pretty-print it : + +```shell +cat output.json | jq . +``` + +Or sort the output per detection element id : + +```shell +cat output.json | jq '.alignables|=sort_by(.deid)' +``` + +That last command being the one that was used to produce the example [ideal-geometry-o2.json](../Test/ideal-geometry-o2.json) file. + diff --git a/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/Transformations.h b/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/Transformations.h new file mode 100644 index 0000000000000..922c53fcf0dd0 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/Transformations.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// get the local-to-global transformation for a given detection element + +#ifndef O2_MCH_GEOMETRY_TRANSFORMER_TRANSFORMATIONS_H +#define O2_MCH_GEOMETRY_TRANSFORMER_TRANSFORMATIONS_H + +#include "MathUtils/Cartesian.h" +#include <array> +#include <tuple> +#include <gsl/span> +#include <functional> + +class TGeoManager; + +namespace o2::mch::geo +{ + +/** A geometry transformation creator must be able to + * create a transformation for any valid MCH detection element id. + * + * That transformation is used to convert coordinates from local + * (x,y in detection element plane) to global (x,y,z in Alice Coordinate + * System) and vice-versa + * + * @param detElemId must be a valid detection element + * @param geo a reference to a GeoManager that must contain MCH volumes + * + * @throw if detElemId is not valid + */ +using TransformationCreator = std::function<o2::math_utils::Transform3D(int detElemId)>; + +/** Tranformation creator using TGeoManager. + * + * @param geo a reference to a GeoManager that must contain MCH volumes + */ +TransformationCreator transformationFromTGeoManager(const TGeoManager& geo); + +TransformationCreator transformationFromJSON(std::istream& in); + +/** The list of detection element identifiers for MCH + */ +extern std::array<int, 156> allDeIds; + +/** Convert the 3 Tait–Bryan angles (yaw,pitch,roll) into the 9 matrix + * elements of a rotation matrix. + * + * @param yaw rotation around z-axis, in radian + * @param pitch rotation around y'-axis (new y-axis resulting from yaw + * rotation), in radian + * @param roll rotation around x''-axis (new x-axis resulting from yaw + * and pitch rotations), in radian + */ +std::array<double, 9> angles2matrix(double yaw, double pitch, double roll); + +/** Convert the 9 matrix elements of a rotation matrix + * into 3 Tait-Bryan angles (yaw,pitch,roll). + * + * @param rot a 9-elements vector + * @returns a tuple of the 3 angles <yaw,pitch,roll>. The angles are + * expressed in radian + */ +std::tuple<double, double, double> matrix2angles(gsl::span<double> rot); +} // namespace o2::mch::geo + +#endif diff --git a/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/VolumePaths.h b/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/VolumePaths.h new file mode 100644 index 0000000000000..8e7c15d192aa6 --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/include/MCHGeometryTransformer/VolumePaths.h @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// get the local-to-global transformation for a given detection element + +#ifndef O2_MCH_GEOMETRY_TRANSFORMER_VOLUME_PATHS_H +#define O2_MCH_GEOMETRY_TRANSFORMER_VOLUME_PATHS_H + +#include <string> + +namespace o2::mch::geo +{ +std::string volumePathName(int deId); +} + +#endif diff --git a/Detectors/MUON/MCH/Geometry/Transformer/src/Transformations.cxx b/Detectors/MUON/MCH/Geometry/Transformer/src/Transformations.cxx new file mode 100644 index 0000000000000..399054d9807dd --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/src/Transformations.cxx @@ -0,0 +1,154 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHGeometryTransformer/VolumePaths.h" +#include <array> +#include <string> +#include <vector> +#include <TGeoManager.h> +#include <TGeoMatrix.h> +#include <rapidjson/document.h> +#include <rapidjson/istreamwrapper.h> +#include <fmt/format.h> +namespace o2::mch::geo +{ + +std::array<int, 156> allDeIds = { + 100, 101, 102, 103, + 200, 201, 202, 203, + 300, 301, 302, 303, + 400, 401, 402, 403, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, + 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, + 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, + 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025}; + +TransformationCreator transformationFromTGeoManager(const TGeoManager& geo) +{ + return [&geo](int detElemId) -> o2::math_utils::Transform3D { + if (std::find(begin(allDeIds), end(allDeIds), detElemId) == end(allDeIds)) { + throw std::runtime_error("Wrong detection element Id"); + } + + std::string volPathName = geo.GetTopVolume()->GetName(); + + int nCh = detElemId / 100; + + if (nCh <= 4 && geo.GetVolume("YOUT1")) { + volPathName += "/YOUT1_1/"; + } else if ((nCh == 5 || nCh == 6) && geo.GetVolume("DDIP")) { + volPathName += "/DDIP_1/"; + } else if (nCh >= 7 && geo.GetVolume("YOUT2")) { + volPathName += "/YOUT2_1/"; + } else { + volPathName += "/"; + } + + volPathName += volumePathName(detElemId); + + TGeoNavigator* navig = gGeoManager->GetCurrentNavigator(); + + if (!navig->cd(volPathName.c_str())) { + throw std::runtime_error("could not get to volPathName=" + volPathName); + } + + return o2::math_utils::Transform3D{*(navig->GetCurrentMatrix())}; + }; +} + +TransformationCreator transformationFromJSON(std::istream& in) +{ + rapidjson::IStreamWrapper isw(in); + + rapidjson::Document d; + d.ParseStream(isw); + + rapidjson::Value& alignables = d["alignables"]; + assert(alignables.IsArray()); + + std::map<int, std::tuple<double, double, double>> angles; + std::map<int, std::tuple<double, double, double>> translations; + + // loop over json document and extract Tait-Bryan angles (yaw,pitch,roll) + // as well as translation vector (tx,ty,tz) + // for each detection element + + constexpr double deg2rad = 3.14159265358979323846 / 180.0; + + for (auto& al : alignables.GetArray()) { + auto itr = al.FindMember("deid"); + if (itr != al.MemberEnd()) { + int deid = itr->value.GetInt(); + auto t = al["transform"].GetObject(); + angles[deid] = { + deg2rad * t["yaw"].GetDouble(), + deg2rad * t["pitch"].GetDouble(), + deg2rad * t["roll"].GetDouble()}; + translations[deid] = { + t["tx"].GetDouble(), + t["ty"].GetDouble(), + t["tz"].GetDouble()}; + } + } + + return [angles, translations](int detElemId) -> o2::math_utils::Transform3D { + if (std::find(begin(allDeIds), end(allDeIds), detElemId) == end(allDeIds)) { + throw std::runtime_error("Wrong detection element Id"); + } + auto [yaw, pitch, roll] = angles.at(detElemId); + auto [tx, ty, tz] = translations.at(detElemId); + double tr[3] = {tx, ty, tz}; + // get the angles, convert them to a matrix and build a Transform3D + // from it + auto rot = o2::mch::geo::angles2matrix(yaw, pitch, roll); + TGeoHMatrix m; + m.SetRotation(&rot[0]); + m.SetTranslation(tr); + return o2::math_utils::Transform3D(m); + }; +} // namespace o2::mch::geo + +std::array<double, 9> angles2matrix(double yaw, double pitch, double roll) +{ + std::array<double, 9> rot; + + double sinpsi = std::sin(roll); + double cospsi = std::cos(roll); + double sinthe = std::sin(pitch); + double costhe = std::cos(pitch); + double sinphi = std::sin(yaw); + double cosphi = std::cos(yaw); + rot[0] = costhe * cosphi; + rot[1] = -costhe * sinphi; + rot[2] = sinthe; + rot[3] = sinpsi * sinthe * cosphi + cospsi * sinphi; + rot[4] = -sinpsi * sinthe * sinphi + cospsi * cosphi; + rot[5] = -costhe * sinpsi; + rot[6] = -cospsi * sinthe * cosphi + sinpsi * sinphi; + rot[7] = cospsi * sinthe * sinphi + sinpsi * cosphi; + rot[8] = costhe * cospsi; + return rot; +} + +std::tuple<double, double, double> matrix2angles(gsl::span<double> rot) +{ + double roll = std::atan2(-rot[5], rot[8]); + double pitch = std::asin(rot[2]); + double yaw = std::atan2(-rot[1], rot[0]); + return std::make_tuple(yaw, + pitch, + roll); +} + +} // namespace o2::mch::geo diff --git a/Detectors/MUON/MCH/Geometry/Transformer/src/VolumePaths.cxx b/Detectors/MUON/MCH/Geometry/Transformer/src/VolumePaths.cxx new file mode 100644 index 0000000000000..c26b6b72e702e --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/src/VolumePaths.cxx @@ -0,0 +1,493 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHGeometryTransformer/VolumePaths.h" + +namespace o2::mch::geo +{ +// return the path of the mother volume of detElemId, relative to MCH geometry +// (i.e. excluding general top node) +std::string volumePathName(int detElemId) +{ + std::string vp{"incorrect detElemId"}; + + if (detElemId == 100) { + return "SC01I_0/Quadrant (chamber 1)_100"; + } + if (detElemId == 103) { + return "SC01I_0/Quadrant (chamber 1)_103"; + } + if (detElemId == 101) { + return "SC01O_1/Quadrant (chamber 1)_101"; + } + if (detElemId == 102) { + return "SC01O_1/Quadrant (chamber 1)_102"; + } + if (detElemId == 200) { + return "SC02I_2/Quadrant (chamber 2)_200"; + } + if (detElemId == 203) { + return "SC02I_2/Quadrant (chamber 2)_203"; + } + if (detElemId == 201) { + return "SC02O_3/Quadrant (chamber 2)_201"; + } + if (detElemId == 202) { + return "SC02O_3/Quadrant (chamber 2)_202"; + } + if (detElemId == 300) { + return "SC03I_4/Station 2 quadrant_300"; + } + if (detElemId == 303) { + return "SC03I_4/Station 2 quadrant_303"; + } + if (detElemId == 301) { + return "SC03O_5/Station 2 quadrant_301"; + } + if (detElemId == 302) { + return "SC03O_5/Station 2 quadrant_302"; + } + if (detElemId == 400) { + return "SC04I_6/Station 2 quadrant_400"; + } + if (detElemId == 403) { + return "SC04I_6/Station 2 quadrant_403"; + } + if (detElemId == 401) { + return "SC04O_7/Station 2 quadrant_401"; + } + if (detElemId == 402) { + return "SC04O_7/Station 2 quadrant_402"; + } + if (detElemId == 500) { + return "SC05I_8/122000SR1_500"; + } + if (detElemId == 501) { + return "SC05I_8/112200SR2_501"; + } + if (detElemId == 502) { + return "SC05I_8/122200S_502"; + } + if (detElemId == 503) { + return "SC05I_8/222000N_503"; + } + if (detElemId == 504) { + return "SC05I_8/220000N_504"; + } + if (detElemId == 514) { + return "SC05I_8/220000N_514"; + } + if (detElemId == 515) { + return "SC05I_8/222000N_515"; + } + if (detElemId == 516) { + return "SC05I_8/122200S_516"; + } + if (detElemId == 517) { + return "SC05I_8/112200SR2_517"; + } + if (detElemId == 505) { + return "SC05O_9/220000N_505"; + } + if (detElemId == 506) { + return "SC05O_9/222000N_506"; + } + if (detElemId == 507) { + return "SC05O_9/122200S_507"; + } + if (detElemId == 508) { + return "SC05O_9/112200SR2_508"; + } + if (detElemId == 509) { + return "SC05O_9/122000SR1_509"; + } + if (detElemId == 510) { + return "SC05O_9/112200SR2_510"; + } + if (detElemId == 511) { + return "SC05O_9/122200S_511"; + } + if (detElemId == 512) { + return "SC05O_9/222000N_512"; + } + if (detElemId == 513) { + return "SC05O_9/220000N_513"; + } + if (detElemId == 600) { + return "SC06I_10/122000NR1_600"; + } + if (detElemId == 601) { + return "SC06I_10/112200NR2_601"; + } + if (detElemId == 602) { + return "SC06I_10/122200N_602"; + } + if (detElemId == 603) { + return "SC06I_10/222000N_603"; + } + if (detElemId == 604) { + return "SC06I_10/220000N_604"; + } + if (detElemId == 614) { + return "SC06I_10/220000N_614"; + } + if (detElemId == 615) { + return "SC06I_10/222000N_615"; + } + if (detElemId == 616) { + return "SC06I_10/122200N_616"; + } + if (detElemId == 617) { + return "SC06I_10/112200NR2_617"; + } + if (detElemId == 605) { + return "SC06O_11/220000N_605"; + } + if (detElemId == 606) { + return "SC06O_11/222000N_606"; + } + if (detElemId == 607) { + return "SC06O_11/122200N_607"; + } + if (detElemId == 608) { + return "SC06O_11/112200NR2_608"; + } + if (detElemId == 609) { + return "SC06O_11/122000NR1_609"; + } + if (detElemId == 610) { + return "SC06O_11/112200NR2_610"; + } + if (detElemId == 611) { + return "SC06O_11/122200N_611"; + } + if (detElemId == 612) { + return "SC06O_11/222000N_612"; + } + if (detElemId == 613) { + return "SC06O_11/220000N_613"; + } + if (detElemId == 700) { + return "SC07I_12/122330N_700"; + } + if (detElemId == 701) { + return "SC07I_12/112233NR3_701"; + } + if (detElemId == 702) { + return "SC07I_12/112230N_702"; + } + if (detElemId == 703) { + return "SC07I_12/222330N_703"; + } + if (detElemId == 704) { + return "SC07I_12/223300N_704"; + } + if (detElemId == 705) { + return "SC07I_12/333000N_705"; + } + if (detElemId == 706) { + return "SC07I_12/330000N_706"; + } + if (detElemId == 720) { + return "SC07I_12/330000N_720"; + } + if (detElemId == 721) { + return "SC07I_12/333000N_721"; + } + if (detElemId == 722) { + return "SC07I_12/223300N_722"; + } + if (detElemId == 723) { + return "SC07I_12/222330N_723"; + } + if (detElemId == 724) { + return "SC07I_12/112230N_724"; + } + if (detElemId == 725) { + return "SC07I_12/112233NR3_725"; + } + if (detElemId == 707) { + return "SC07O_13/330000N_707"; + } + if (detElemId == 708) { + return "SC07O_13/333000N_708"; + } + if (detElemId == 709) { + return "SC07O_13/223300N_709"; + } + if (detElemId == 710) { + return "SC07O_13/222330N_710"; + } + if (detElemId == 711) { + return "SC07O_13/112230N_711"; + } + if (detElemId == 712) { + return "SC07O_13/112233NR3_712"; + } + if (detElemId == 713) { + return "SC07O_13/122330N_713"; + } + if (detElemId == 714) { + return "SC07O_13/112233NR3_714"; + } + if (detElemId == 715) { + return "SC07O_13/112230N_715"; + } + if (detElemId == 716) { + return "SC07O_13/222330N_716"; + } + if (detElemId == 717) { + return "SC07O_13/223300N_717"; + } + if (detElemId == 718) { + return "SC07O_13/333000N_718"; + } + if (detElemId == 719) { + return "SC07O_13/330000N_719"; + } + if (detElemId == 800) { + return "SC08I_14/122330N_800"; + } + if (detElemId == 801) { + return "SC08I_14/112233NR3_801"; + } + if (detElemId == 802) { + return "SC08I_14/112230N_802"; + } + if (detElemId == 803) { + return "SC08I_14/222330N_803"; + } + if (detElemId == 804) { + return "SC08I_14/223300N_804"; + } + if (detElemId == 805) { + return "SC08I_14/333000N_805"; + } + if (detElemId == 806) { + return "SC08I_14/330000N_806"; + } + if (detElemId == 820) { + return "SC08I_14/330000N_820"; + } + if (detElemId == 821) { + return "SC08I_14/333000N_821"; + } + if (detElemId == 822) { + return "SC08I_14/223300N_822"; + } + if (detElemId == 823) { + return "SC08I_14/222330N_823"; + } + if (detElemId == 824) { + return "SC08I_14/112230N_824"; + } + if (detElemId == 825) { + return "SC08I_14/112233NR3_825"; + } + if (detElemId == 807) { + return "SC08O_15/330000N_807"; + } + if (detElemId == 808) { + return "SC08O_15/333000N_808"; + } + if (detElemId == 809) { + return "SC08O_15/223300N_809"; + } + if (detElemId == 810) { + return "SC08O_15/222330N_810"; + } + if (detElemId == 811) { + return "SC08O_15/112230N_811"; + } + if (detElemId == 812) { + return "SC08O_15/112233NR3_812"; + } + if (detElemId == 813) { + return "SC08O_15/122330N_813"; + } + if (detElemId == 814) { + return "SC08O_15/112233NR3_814"; + } + if (detElemId == 815) { + return "SC08O_15/112230N_815"; + } + if (detElemId == 816) { + return "SC08O_15/222330N_816"; + } + if (detElemId == 817) { + return "SC08O_15/223300N_817"; + } + if (detElemId == 818) { + return "SC08O_15/333000N_818"; + } + if (detElemId == 819) { + return "SC08O_15/330000N_819"; + } + if (detElemId == 900) { + return "SC09I_16/122330N_900"; + } + if (detElemId == 901) { + return "SC09I_16/112233NR3_901"; + } + if (detElemId == 902) { + return "SC09I_16/112233N_902"; + } + if (detElemId == 903) { + return "SC09I_16/222333N_903"; + } + if (detElemId == 904) { + return "SC09I_16/223330N_904"; + } + if (detElemId == 905) { + return "SC09I_16/333300N_905"; + } + if (detElemId == 906) { + return "SC09I_16/333000N_906"; + } + if (detElemId == 920) { + return "SC09I_16/333000N_920"; + } + if (detElemId == 921) { + return "SC09I_16/333300N_921"; + } + if (detElemId == 922) { + return "SC09I_16/223330N_922"; + } + if (detElemId == 923) { + return "SC09I_16/222333N_923"; + } + if (detElemId == 924) { + return "SC09I_16/112233N_924"; + } + if (detElemId == 925) { + return "SC09I_16/112233NR3_925"; + } + if (detElemId == 907) { + return "SC09O_17/333000N_907"; + } + if (detElemId == 908) { + return "SC09O_17/333300N_908"; + } + if (detElemId == 909) { + return "SC09O_17/223330N_909"; + } + if (detElemId == 910) { + return "SC09O_17/222333N_910"; + } + if (detElemId == 911) { + return "SC09O_17/112233N_911"; + } + if (detElemId == 912) { + return "SC09O_17/112233NR3_912"; + } + if (detElemId == 913) { + return "SC09O_17/122330N_913"; + } + if (detElemId == 914) { + return "SC09O_17/112233NR3_914"; + } + if (detElemId == 915) { + return "SC09O_17/112233N_915"; + } + if (detElemId == 916) { + return "SC09O_17/222333N_916"; + } + if (detElemId == 917) { + return "SC09O_17/223330N_917"; + } + if (detElemId == 918) { + return "SC09O_17/333300N_918"; + } + if (detElemId == 919) { + return "SC09O_17/333000N_919"; + } + if (detElemId == 1000) { + return "SC10I_18/122330N_1000"; + } + if (detElemId == 1001) { + return "SC10I_18/112233NR3_1001"; + } + if (detElemId == 1002) { + return "SC10I_18/112233N_1002"; + } + if (detElemId == 1003) { + return "SC10I_18/222333N_1003"; + } + if (detElemId == 1004) { + return "SC10I_18/223330N_1004"; + } + if (detElemId == 1005) { + return "SC10I_18/333300N_1005"; + } + if (detElemId == 1006) { + return "SC10I_18/333000N_1006"; + } + if (detElemId == 1020) { + return "SC10I_18/333000N_1020"; + } + if (detElemId == 1021) { + return "SC10I_18/333300N_1021"; + } + if (detElemId == 1022) { + return "SC10I_18/223330N_1022"; + } + if (detElemId == 1023) { + return "SC10I_18/222333N_1023"; + } + if (detElemId == 1024) { + return "SC10I_18/112233N_1024"; + } + if (detElemId == 1025) { + return "SC10I_18/112233NR3_1025"; + } + if (detElemId == 1007) { + return "SC10O_19/333000N_1007"; + } + if (detElemId == 1008) { + return "SC10O_19/333300N_1008"; + } + if (detElemId == 1009) { + return "SC10O_19/223330N_1009"; + } + if (detElemId == 1010) { + return "SC10O_19/222333N_1010"; + } + if (detElemId == 1011) { + return "SC10O_19/112233N_1011"; + } + if (detElemId == 1012) { + return "SC10O_19/112233NR3_1012"; + } + if (detElemId == 1013) { + return "SC10O_19/122330N_1013"; + } + if (detElemId == 1014) { + return "SC10O_19/112233NR3_1014"; + } + if (detElemId == 1015) { + return "SC10O_19/112233N_1015"; + } + if (detElemId == 1016) { + return "SC10O_19/222333N_1016"; + } + if (detElemId == 1017) { + return "SC10O_19/223330N_1017"; + } + if (detElemId == 1018) { + return "SC10O_19/333300N_1018"; + } + if (detElemId == 1019) { + return "SC10O_19/333000N_1019"; + } + + return vp; +} +} // namespace o2::mch::geo diff --git a/Detectors/MUON/MCH/Geometry/Transformer/src/convert-geometry.cxx b/Detectors/MUON/MCH/Geometry/Transformer/src/convert-geometry.cxx new file mode 100644 index 0000000000000..74bb7a1b04dbe --- /dev/null +++ b/Detectors/MUON/MCH/Geometry/Transformer/src/convert-geometry.cxx @@ -0,0 +1,215 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/program_options.hpp> +#include <iostream> +#include <stdexcept> +#include <TGeoManager.h> +#include <TFile.h> +#include <sstream> +#include <tuple> +#include <vector> +#include <string> +#include "TGeoPhysicalNode.h" +#include <rapidjson/document.h> +#include <rapidjson/ostreamwrapper.h> +#include <rapidjson/stringbuffer.h> +#include <rapidjson/writer.h> +#include <gsl/span> +#include <cmath> +#include <array> +#include "MCHGeometryTransformer/Transformations.h" + +namespace po = boost::program_options; + +std::vector<std::string> splitString(const std::string& src, char delim) +{ + std::stringstream ss(src); + std::string token; + std::vector<std::string> tokens; + + while (std::getline(ss, token, delim)) { + if (!token.empty()) { + tokens.push_back(std::move(token)); + } + } + + return tokens; +} + +TGeoManager* readFromFile(std::string filename) +{ + TFile* f = TFile::Open(filename.c_str()); + if (f->IsZombie()) { + throw std::runtime_error("can not open " + filename); + } + + auto possibleGeoNames = {"ALICE", "FAIRGeom", "MCH-ONLY", "MCH-BASICS"}; + + TGeoManager* geo{nullptr}; + + for (auto name : possibleGeoNames) { + geo = static_cast<TGeoManager*>(f->Get(name)); + if (geo) { + break; + } + } + if (!geo) { + f->ls(); + throw std::runtime_error("could not find ALICE geometry (using ALICE or FAIRGeom names)"); + } + return geo; +} + +template <typename WRITER> +void matrix2json(const TGeoHMatrix& matrix, WRITER& w) +{ + + constexpr double rad2deg = 180.0 / 3.14159265358979323846; + + const Double_t* t = matrix.GetTranslation(); + const Double_t* m = matrix.GetRotationMatrix(); + gsl::span<double> mat(const_cast<double*>(m), 9); + auto [yaw, pitch, roll] = o2::mch::geo::matrix2angles(mat); + w.Key("tx"); + w.Double(t[0]); + w.Key("ty"); + w.Double(t[1]); + w.Key("tz"); + w.Double(t[2]); + w.Key("yaw"); + w.Double(rad2deg * yaw); + w.Key("pitch"); + w.Double(rad2deg * pitch); + w.Key("roll"); + w.Double(rad2deg * roll); +} + +std::tuple<bool, uint16_t> isMCH(std::string alignableName) +{ + auto parts = splitString(alignableName, '/'); + bool aliroot = parts[0] == "MUON"; + bool o2 = parts[0] == "MCH"; + if (!o2 && !aliroot) { + return {false, 0}; + } + auto id = std::stoi(parts[1].substr(2)); + bool ok = (aliroot && (id <= 15)) || (o2 && (id <= 19)); + uint16_t deId{0}; + if (ok && parts.size() > 2) { + deId = std::stoi(parts[2].substr(2)); + } + return {ok, deId}; +} + +template <typename WRITER> +void writeMatrix(const char* name, const TGeoHMatrix* matrix, WRITER& w) +{ + if (matrix) { + w.Key(name); + w.StartObject(); + matrix2json(*matrix, w); + w.EndObject(); + } +} + +/** convert geometry into a json document. + */ +void convertGeom(const TGeoManager& geom) +{ + rapidjson::OStreamWrapper osw(std::cout); + rapidjson::Writer<rapidjson::OStreamWrapper> writer(osw); + + writer.StartObject(); + writer.Key("alignables"); + writer.StartArray(); + + for (auto i = 0; i < geom.GetNAlignable(); i++) { + auto ae = geom.GetAlignableEntry(i); + std::string symname = ae->GetName(); + auto [mch, deId] = isMCH(symname); + if (!mch) { + continue; + } + writer.StartObject(); + if (deId > 0) { + writer.Key("deid"); + writer.Int(deId); + } + writer.Key("symname"); + writer.String(symname.c_str()); + auto pn = ae->GetPhysicalNode(); + const TGeoHMatrix* matrix{nullptr}; + bool aligned{false}; + if (pn) { + matrix = pn->GetMatrix(); + aligned = pn->IsAligned(); + } else { + matrix = ae->GetGlobalOrig(); + aligned = false; + } + writeMatrix("transform", matrix, writer); + writer.Key("aligned"); + writer.Bool(aligned); + writer.EndObject(); + } + writer.EndArray(); + writer.EndObject(); +} + +int main(int argc, char** argv) +{ + po::variables_map vm; + po::options_description options; + + // clang-format off + options.add_options() + ("help,h","help") + ("geom",po::value<std::string>()->required(),"geometry.root file"); + // clang-format on + + po::options_description cmdline; + cmdline.add(options); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << "This program extract MCH geometry transformation from " + "a geometry root file and write them in json format.\n"; + std::cout << "\n"; + std::cout << options << "\n"; + std::cout << "\n"; + std::cout << "Note that the json format can then be further manipulated using e.g." + "the jq utility\n"; + std::cout << "For instance sorting by deid:\n"; + std::cout << "cat output.json | jq '.alignables|=sort_by(.deid)'\n"; + std::cout << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + std::cout << options << "\n"; + exit(1); + } + + TGeoManager* geom = readFromFile(vm["geom"].as<std::string>()); + + if (geom) { + convertGeom(*geom); + return 0; + } else { + return 3; + } + return 0; +} diff --git a/Detectors/MUON/MCH/Mapping/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/CMakeLists.txt index fdfacfe4f702b..99ff094d140d0 100644 --- a/Detectors/MUON/MCH/Mapping/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Interface) add_subdirectory(Impl3) diff --git a/Detectors/MUON/MCH/Mapping/Impl3/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/Impl3/CMakeLists.txt index a0440e2ee8480..787c2550f8797 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/Impl3/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHMappingImpl3 SOURCES src/CreateSegmentation.cxx @@ -21,7 +22,7 @@ o2_add_library(MCHMappingImpl3 src/CathodeSegmentationImpl3.cxx src/CathodeSegmentationImpl3.h PUBLIC_LINK_LIBRARIES Boost::boost O2::MCHMappingInterface - ms_gsl::ms_gsl fmt::fmt + Microsoft.GSL::GSL fmt::fmt TARGETVARNAME targetName) # We add all segmentation creators by default, but the final goal would be to diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCImpl3.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCImpl3.cxx index b52d0dfb8b25d..8072584e0be25 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCImpl3.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCImpl3.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -89,7 +90,7 @@ void mchCathodeSegmentationForOneDetectionElementOfEachSegmentationType(MchDetec O2MCHMAPPINGIMPL3_EXPORT int mchCathodeSegmentationIsPadValid(MchCathodeSegmentationHandle segHandle, int catPadIndex) { - return catPadIndex != segHandle->impl->InvalidCatPadIndex; + return segHandle->impl->isValid(catPadIndex); } O2MCHMAPPINGIMPL3_EXPORT diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.cxx index 141c089b85d36..930c9c03b6fdd 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.h b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.h index b85acd0a4e034..d2d2f67d51799 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCreator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx index b7fd6d8548dd9..a7d1620fe2449 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "CathodeSegmentationImpl3.h" #include "boost/format.hpp" +#include <boost/geometry.hpp> #include "GenDetElemId2SegType.h" #include "PadGroup.h" #include "PadSize.h" @@ -160,6 +162,11 @@ std::vector<int> CathodeSegmentation::getNeighbouringCatPadIndexs(int catPadInde return pads; } +bool CathodeSegmentation::isValid(int catPadIndex) const +{ + return catPadIndex >= 0 && catPadIndex < static_cast<int>(mCatPadIndex2PadGroupIndex.size()); +} + double CathodeSegmentation::squaredDistance(int catPadIndex, double x, double y) const { double px = padPositionX(catPadIndex) - x; diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.h b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.h index e334affb63284..f0e96dc35ce11 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -78,6 +79,8 @@ class CathodeSegmentation int padDualSampaChannel(int catPadIndex) const; + bool isValid(int catPadIndex) const; + private: int dualSampaIndex(int dualSampaId) const; diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/CreateSegmentation.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/CreateSegmentation.cxx index d994edcbfdbb5..0cd34afcdf1ac 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/CreateSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/CreateSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType0.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType0.cxx index 15b36dc3c5524..92fa5d8fb0bfe 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType0.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType1.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType1.cxx index 9a608ea97ce20..249d7054bb2af 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType1.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType10.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType10.cxx index 7624f047a1047..b47db85dc3006 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType10.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType10.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType11.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType11.cxx index 832565ded63da..e3efe0fa52d27 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType11.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType11.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType12.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType12.cxx index dd91595b2428f..1596850aa91cb 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType12.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType12.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType13.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType13.cxx index f92253b998558..56fbbfc081c00 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType13.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType13.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType14.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType14.cxx index cea554c2e023b..6be508a34fb39 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType14.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType14.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType15.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType15.cxx index eb0bae3cf42af..9f57033f95a35 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType15.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType15.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType16.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType16.cxx index 41e65095503a5..293e3b49bc94d 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType16.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType16.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType17.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType17.cxx index 83c4a295b7f53..53b106c41c99f 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType17.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType17.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType18.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType18.cxx index 324995381c22d..819eeaba739b9 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType18.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType18.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType19.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType19.cxx index bbc2a29176613..36ca1b7ec99e0 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType19.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType19.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType2.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType2.cxx index 1af01c32f202a..54a14cd8ab956 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType2.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType20.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType20.cxx index 5ce4c88f26a0e..0f8937a45255c 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType20.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType20.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType3.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType3.cxx index fdf1ad5c2c638..a90c98325559d 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType3.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType3.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType4.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType4.cxx index 01864e7b30675..0a1c5e8363677 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType4.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType4.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType5.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType5.cxx index 399c5e62e6b0e..5decf94b6ae63 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType5.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType5.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType6.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType6.cxx index acb2c2c1ce3a9..005d902a2ff84 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType6.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType6.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType7.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType7.cxx index c8641400387a3..ac483c6a99419 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType7.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType7.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType8.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType8.cxx index 222dc877775e4..6ac5ffb4191b6 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType8.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType8.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType9.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType9.cxx index 432c4677fdc44..e4f9b18cfd2cc 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType9.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenCathodeSegmentationCreatorForSegType9.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.cxx index 32751381ac448..d545aeaeb3029 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.h b/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.h index 1a5ef89be1ac9..c9b6376824639 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/GenDetElemId2SegType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroup.h b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroup.h index 5c52b093c5562..a171d5104ac4f 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroup.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroup.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.cxx b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.cxx index d233ee4abd4b2..66a5b65af465f 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.h b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.h index 44a8c6d11d811..84527a2c4a71e 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/PadGroupType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl3/src/PadSize.h b/Detectors/MUON/MCH/Mapping/Impl3/src/PadSize.h index 669482ee524c6..529f3d26775c1 100644 --- a/Detectors/MUON/MCH/Mapping/Impl3/src/PadSize.h +++ b/Detectors/MUON/MCH/Mapping/Impl3/src/PadSize.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/Impl4/CMakeLists.txt index 54a08d54a4558..fc41989642955 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/Impl4/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHMappingImpl4 SOURCES src/CreateSegmentation.cxx @@ -21,7 +22,7 @@ o2_add_library(MCHMappingImpl4 src/CathodeSegmentationImpl4.cxx src/CathodeSegmentationImpl4.h PUBLIC_LINK_LIBRARIES Boost::boost O2::MCHMappingInterface - ms_gsl::ms_gsl fmt::fmt + Microsoft.GSL::GSL fmt::fmt TARGETVARNAME targetName) # We add all segmentation creators by default, but the final goal would be to diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCImpl4.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCImpl4.cxx index 89a3fad70c517..729f06f6548f4 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCImpl4.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCImpl4.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -107,14 +108,14 @@ O2MCHMAPPINGIMPL4_EXPORT void O2MCHMAPPINGIMPL4_EXPORT int mchCathodeSegmentationIsPadValid( MchCathodeSegmentationHandle segHandle, int catPadIndex) { - return catPadIndex != segHandle->impl->InvalidCatPadIndex; + return segHandle->impl->isValid(catPadIndex); } O2MCHMAPPINGIMPL4_EXPORT void mchCathodeSegmentationForEachPadInDualSampa( MchCathodeSegmentationHandle segHandle, int dualSampaId, MchPadHandler handler, void* clientData) { - for (auto p : segHandle->impl->getCatPadIndexs(dualSampaId)) { + for (auto p : segHandle->impl->getCatPadIndices(dualSampaId)) { handler(clientData, p); } } @@ -159,7 +160,7 @@ O2MCHMAPPINGIMPL4_EXPORT void mchCathodeSegmentationForEachPadInArea( MchCathodeSegmentationHandle segHandle, double xmin, double ymin, double xmax, double ymax, MchPadHandler handler, void* clientData) { - for (auto p : segHandle->impl->getCatPadIndexs(xmin, ymin, xmax, ymax)) { + for (auto p : segHandle->impl->getCatPadIndices(xmin, ymin, xmax, ymax)) { handler(clientData, p); } } @@ -168,7 +169,7 @@ O2MCHMAPPINGIMPL4_EXPORT void mchCathodeSegmentationForEachNeighbouringPad( MchCathodeSegmentationHandle segHandle, int catPadIndex, MchPadHandler handler, void* userData) { - for (auto p : segHandle->impl->getNeighbouringCatPadIndexs(catPadIndex)) { + for (auto p : segHandle->impl->getNeighbouringCatPadIndices(catPadIndex)) { handler(userData, p); } } diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.cxx index 018ee4af36dff..6f370a0896ec6 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.h b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.h index b09aaba64f4b8..8a9b6adb95d92 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCreator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx index 6f3322f7c1953..d79f953f5b323 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "CathodeSegmentationImpl4.h" #include "boost/format.hpp" +#include <boost/geometry.hpp> #include "GenDetElemId2SegType.h" #include "PadGroup.h" #include "PadSize.h" @@ -27,6 +29,7 @@ #include <string> #include <vector> #include <gsl/gsl> +#include <fmt/format.h> using namespace o2::mch::mapping::impl4; @@ -118,45 +121,48 @@ CathodeSegmentation::CathodeSegmentation( mPadSizes{std::move(padSizes)}, mCatPadIndex2PadGroupIndex{}, mCatPadIndex2PadGroupTypeFastIndex{}, - mPadGroupIndex2CatPadIndexIndex{} + mPadGroupIndex2CatPadIndexIndex{}, + mDualSampaId2CatPadIndices{} { fillRtree(); + for (auto dualSampaId : mDualSampaIds) { + mDualSampaId2CatPadIndices.emplace(dualSampaId, getCatPadIndices(dualSampaId)); + } } -std::vector<int> CathodeSegmentation::getCatPadIndexs(int dualSampaId) const +std::vector<int> CathodeSegmentation::getCatPadIndices(int dualSampaId) const { std::vector<int> pi; for (auto padGroupIndex = 0; padGroupIndex < mPadGroups.size(); ++padGroupIndex) { if (mPadGroups[padGroupIndex].mFECId == dualSampaId) { - auto& pgt = mPadGroupTypes[mPadGroups[padGroupIndex].mPadGroupTypeId]; - auto i1 = mPadGroupIndex2CatPadIndexIndex[padGroupIndex]; + const auto& pgt = mPadGroupTypes[mPadGroups[padGroupIndex].mPadGroupTypeId]; + const auto& i1 = mPadGroupIndex2CatPadIndexIndex[padGroupIndex]; for (auto i = i1; i < i1 + pgt.getNofPads(); ++i) { - pi.push_back(i); + pi.emplace_back(i); } } } - return pi; } -std::vector<int> CathodeSegmentation::getCatPadIndexs(double xmin, double ymin, - double xmax, - double ymax) const +std::vector<int> CathodeSegmentation::getCatPadIndices(double xmin, double ymin, + double xmax, + double ymax) const { std::vector<CathodeSegmentation::Value> result_n; mRtree.query(boost::geometry::index::intersects( CathodeSegmentation::Box({xmin, ymin}, {xmax, ymax})), std::back_inserter(result_n)); - std::vector<int> catPadIndexs; + std::vector<int> catPadIndices; for (auto& r : result_n) { - catPadIndexs.push_back(r.second); + catPadIndices.push_back(r.second); } - return catPadIndexs; + return catPadIndices; } -std::vector<int> CathodeSegmentation::getNeighbouringCatPadIndexs( +std::vector<int> CathodeSegmentation::getNeighbouringCatPadIndices( int catPadIndex) const { double x = padPositionX(catPadIndex); @@ -166,12 +172,17 @@ std::vector<int> CathodeSegmentation::getNeighbouringCatPadIndexs( const double offset{0.1}; // 1 mm - auto pads = getCatPadIndexs(x - dx - offset, y - dy - offset, x + dx + offset, - y + dy + offset); + auto pads = getCatPadIndices(x - dx - offset, y - dy - offset, x + dx + offset, + y + dy + offset); pads.erase(std::remove(begin(pads), end(pads), catPadIndex), end(pads)); return pads; } +bool CathodeSegmentation::isValid(int catPadIndex) const +{ + return catPadIndex >= 0 && catPadIndex < static_cast<int>(mCatPadIndex2PadGroupIndex.size()); +} + double CathodeSegmentation::squaredDistance(int catPadIndex, double x, double y) const { @@ -184,7 +195,7 @@ int CathodeSegmentation::findPadByPosition(double x, double y) const { const double epsilon{1E-4}; auto pads = - getCatPadIndexs(x - epsilon, y - epsilon, x + epsilon, y + epsilon); + getCatPadIndices(x - epsilon, y - epsilon, x + epsilon, y + epsilon); double dmin{std::numeric_limits<double>::max()}; int catPadIndex{InvalidCatPadIndex}; @@ -213,7 +224,12 @@ const PadGroupType& CathodeSegmentation::padGroupType(int catPadIndex) const int CathodeSegmentation::findPadByFEE(int dualSampaId, int dualSampaChannel) const { - for (auto catPadIndex : getCatPadIndexs(dualSampaId)) { + auto it = mDualSampaId2CatPadIndices.find(dualSampaId); + if (it == mDualSampaId2CatPadIndices.end()) { + return InvalidCatPadIndex; + } + const auto& padIndices = it->second; + for (const auto& catPadIndex : padIndices) { if (padGroupType(catPadIndex) .id(mCatPadIndex2PadGroupTypeFastIndex[catPadIndex]) == dualSampaChannel) { diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h index 58770c4b9f03f..3482bf6b3fbee 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include <set> #include <ostream> #include <boost/geometry/index/rtree.hpp> +#include <map> namespace o2 { @@ -45,17 +47,17 @@ class CathodeSegmentation std::vector<PadGroupType> padGroupTypes, std::vector<std::pair<float, float>> padSizes); - /// Return the list of catPadIndexs for the pads of the given dual sampa. - std::vector<int> getCatPadIndexs(int dualSampaIds) const; + /// Return the list of catPadIndices for the pads of the given dual sampa. + std::vector<int> getCatPadIndices(int dualSampaIds) const; - /// Return the list of catPadIndexs for the pads contained in the box + /// Return the list of catPadIndices for the pads contained in the box /// {xmin,ymin,xmax,ymax}. - std::vector<int> getCatPadIndexs(double xmin, double ymin, double xmax, - double ymax) const; + std::vector<int> getCatPadIndices(double xmin, double ymin, double xmax, + double ymax) const; - /// Return the list of catPadIndexs of the pads which are neighbours to + /// Return the list of catPadIndices of the pads which are neighbours to /// catPadIndex - std::vector<int> getNeighbouringCatPadIndexs(int catPadIndex) const; + std::vector<int> getNeighbouringCatPadIndices(int catPadIndex) const; std::set<int> dualSampaIds() const { return mDualSampaIds; } @@ -88,6 +90,8 @@ class CathodeSegmentation int padDualSampaChannel(int catPadIndex) const; + bool isValid(int catPadIndex) const; + private: int dualSampaIndex(int dualSampaId) const; @@ -113,6 +117,7 @@ class CathodeSegmentation std::vector<int> mCatPadIndex2PadGroupIndex; std::vector<int> mCatPadIndex2PadGroupTypeFastIndex; std::vector<int> mPadGroupIndex2CatPadIndexIndex; + std::map<int, std::vector<int>> mDualSampaId2CatPadIndices; }; CathodeSegmentation* createCathodeSegmentation(int detElemId, diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CreateSegmentation.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/CreateSegmentation.cxx index 17505226ca56c..927e4d94ba052 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CreateSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CreateSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType0.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType0.cxx index 93c9ddfbeff43..58e2eaf5477b6 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType0.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType1.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType1.cxx index c5663474610bc..95acf6a02ece4 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType1.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType10.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType10.cxx index cc8a508df6ea4..7aa9994c436f4 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType10.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType10.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType11.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType11.cxx index 9d3e9b9375fd3..376447f9c78a2 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType11.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType11.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType12.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType12.cxx index 497d17e2bde5c..83db3a7b77399 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType12.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType12.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType13.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType13.cxx index c100848566938..e1acc4ba2c4f3 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType13.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType13.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType14.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType14.cxx index 7dc264b59d8d6..c7cf594bf0769 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType14.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType14.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType15.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType15.cxx index 76caa9d6d3d31..a9d03a72d8dff 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType15.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType15.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType16.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType16.cxx index 0bb65407a0377..cf884ef4cb265 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType16.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType16.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType17.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType17.cxx index fb6fb148bfee3..adeb2a7a1f3c7 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType17.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType17.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType18.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType18.cxx index f70b3e049834d..74cd7c6c52cab 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType18.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType18.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType19.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType19.cxx index 422b8177fa047..8ad57f452001a 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType19.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType19.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType2.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType2.cxx index 5d1f58ec73d10..2e9c9d146d155 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType2.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType20.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType20.cxx index 4b4c0ab8a8c2e..b4f58cd366888 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType20.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType20.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType3.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType3.cxx index cf5c8aa9725c8..e5f88c6ad0c84 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType3.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType3.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType4.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType4.cxx index a10fbc8595681..11a1b04709fb4 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType4.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType4.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType5.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType5.cxx index 0557f72a75b25..d20301c88b869 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType5.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType5.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType6.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType6.cxx index d9ba07f21d6fd..41b8cfdb9b1cb 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType6.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType6.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType7.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType7.cxx index e6c1eb4964040..f9ec568acee5e 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType7.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType7.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType8.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType8.cxx index b67dbadd22884..01414acfd81fd 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType8.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType8.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType9.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType9.cxx index a00748da0ebb7..3c0d6f24138e8 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType9.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenCathodeSegmentationCreatorForSegType9.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.cxx index f49a3d7f5a1a9..83ffe2722148e 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.h b/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.h index 18ebde9a1cdbe..6c7f0cef68627 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/GenDetElemId2SegType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroup.h b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroup.h index efbaa8a2e545b..e13a091dd7181 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroup.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroup.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.cxx index 7b72626fb2f89..5d0d2372f33b7 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.h b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.h index 23ed313b60360..d616e973dceaa 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/PadGroupType.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/PadSize.h b/Detectors/MUON/MCH/Mapping/Impl4/src/PadSize.h index 2b9411af876be..4641b1c382f37 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/PadSize.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/PadSize.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Interface/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/Interface/CMakeLists.txt index 6dda214ccc02f..04e0a69e892d2 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/Interface/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(MCHMappingInterface) diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentation.h b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentation.h index c5964dc790024..8c800edcb0376 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentation.h +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentationCInterface.h b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentationCInterface.h index 82dfd08f99842..384bed5641e14 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentationCInterface.h +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/CathodeSegmentationCInterface.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h index e3a15a88fce55..d269677947f2f 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl index 2dd0d5685bc84..717ed8fb72128 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -65,10 +66,7 @@ inline int Segmentation::findPadByFEE(int dualSampaId, int dualSampaChannel) con inline bool Segmentation::isValid(int dePadIndex) const { - if (dePadIndex < mPadIndexOffset) { - return mBending.isValid(dePadIndex); - } - return mNonBending.isValid(dePadIndex - mPadIndexOffset); + return dePadIndex >= 0 && dePadIndex < nofPads(); } inline int Segmentation::padC2DE(int catPadIndex, bool isBending) const @@ -99,7 +97,9 @@ inline bool Segmentation::findPadPairByPosition(double x, double y, int& b, int& b = mBending.findPadByPosition(x, y); nb = mNonBending.findPadByPosition(x, y); if (!mBending.isValid(b)) { - nb = padC2DE(nb, false); + if (mNonBending.isValid(nb)) { + nb = padC2DE(nb, false); + } return false; } if (!mNonBending.isValid(nb)) { diff --git a/Detectors/MUON/MCH/Mapping/SegContour/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/SegContour/CMakeLists.txt index 583e67067370d..595083c5c6af2 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/SegContour/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHMappingSegContour SOURCES src/CathodeSegmentationContours.cxx diff --git a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationContours.h b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationContours.h index e1e31c8046c9e..7c2ffcb6659b8 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationContours.h +++ b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationContours.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationSVGWriter.h b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationSVGWriter.h index 7fba578c08b2b..b127da99469e5 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationSVGWriter.h +++ b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/CathodeSegmentationSVGWriter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/SegmentationContours.h b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/SegmentationContours.h index 5ddbdf786c0ed..c86472ecdc4d7 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/SegmentationContours.h +++ b/Detectors/MUON/MCH/Mapping/SegContour/include/MCHMappingSegContour/SegmentationContours.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationContours.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationContours.cxx index ecd6bc3328390..e74f406ede1fd 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationContours.cxx +++ b/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationContours.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationSVGWriter.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationSVGWriter.cxx index 545814a3cf37c..b614346f1a42a 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationSVGWriter.cxx +++ b/Detectors/MUON/MCH/Mapping/SegContour/src/CathodeSegmentationSVGWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/SVGSegmentation.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/SVGSegmentation.cxx index 8fea20ecbcb3b..52daf0fa4df59 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/SVGSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/SegContour/src/SVGSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationContours.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationContours.cxx index 88a4e82e9dc87..ce4fbd7760318 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationContours.cxx +++ b/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationContours.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx index 545814a3cf37c..b614346f1a42a 100644 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx +++ b/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/cli/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/cli/CMakeLists.txt index 558df952a47d6..2a3ce658c3d32 100644 --- a/Detectors/MUON/MCH/Mapping/cli/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/cli/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. foreach(impl RANGE 3 4) o2_add_executable(mapping-cli${impl} @@ -14,3 +15,16 @@ foreach(impl RANGE 3 4) COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl${impl} Boost::program_options) endforeach() + +foreach(impl RANGE 3 4) + o2_add_executable(mapping-export-to-tree${impl} + SOURCES export-to-tree.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl${impl} Boost::program_options + ROOT::Tree + TARGETVARNAME targetName) + if(impl EQUAL 3) + target_compile_definitions(${targetName} PRIVATE RUN2) + endif() +endforeach() + diff --git a/Detectors/MUON/MCH/Mapping/cli/cli.cxx b/Detectors/MUON/MCH/Mapping/cli/cli.cxx index e2d98756d68f9..2bcbb036f8b8f 100644 --- a/Detectors/MUON/MCH/Mapping/cli/cli.cxx +++ b/Detectors/MUON/MCH/Mapping/cli/cli.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/cli/export-to-tree.cxx b/Detectors/MUON/MCH/Mapping/cli/export-to-tree.cxx new file mode 100644 index 0000000000000..73dc034fdff66 --- /dev/null +++ b/Detectors/MUON/MCH/Mapping/cli/export-to-tree.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHMappingInterface/Segmentation.h" +#include <iostream> +#include <fmt/format.h> +#include <boost/program_options.hpp> +#include <TTree.h> +#include <TFile.h> +#include <stdexcept> + +namespace po = boost::program_options; +using namespace o2::mch::mapping; + +#ifdef RUN2 +constexpr bool run2{true}; +#else +constexpr bool run2{false}; +#endif + +constexpr int MaxNofPadsPerDE{28672}; +struct DePads { + int nDePad; + int deid; + int dsid[MaxNofPadsPerDE]; + int dsch[MaxNofPadsPerDE]; + float x[MaxNofPadsPerDE]; + float y[MaxNofPadsPerDE]; + float dx[MaxNofPadsPerDE]; + float dy[MaxNofPadsPerDE]; +}; + +void createPadBranches(TTree& tree, DePads& depads) +{ + tree.Branch("nDePad", &depads.nDePad, "nDePad/I") + ->SetTitle("Number of pads in detection element"); + tree.Branch("deid", &depads.deid, "deid/I") + ->SetTitle("Detection element id"); + tree.Branch(fmt::format("DePad_{}", run2 ? "manu" : "dsid").c_str(), + &depads.dsid, + fmt::format("DePad_{}[nDePad]/I", run2 ? "manu" : "dsid").c_str()) + ->SetTitle("FEE id of n-th pad of this detection element (cm)"); + tree.Branch(fmt::format("DePad_{}", run2 ? "ch" : "dsch").c_str(), + &depads.dsch, + fmt::format("DePad_{}[nDePad]/I", run2 ? "ch" : "dsch").c_str()) + ->SetTitle("FEE channel of n-th pad of this detection element (cm)"); + tree.Branch("DePad_x", &depads.x, "DePad_x[nDePad]/F") + ->SetTitle("x position of n-th pad of this detection element (cm)"); + tree.Branch("DePad_y", &depads.y, "DePad_y[nDePad]/F") + ->SetTitle("y position of n-th pad of this detection element (cm)"); + tree.Branch("DePad_dx", &depads.dx, "DePad_dx[nDePad]/F") + ->SetTitle("half size in x direction of n-th pad of this detection element (cm)"); + tree.Branch("DePad_dy", &depads.dy, "DePad_dy[nDePad]/F") + ->SetTitle("half size in y direction of n-th pad of this detection element (cm)"); +} + +/** + * This small program creates a Root TTree with MCH mapping. + * + * There is one entry per MCH detection element, describing the + * basic features of all the pads of that detection element : + * + * - electronic location : FEE board id (aka dual sampa id + * and FEE channel id (aka dual sampa channel) + * - geometric location : (x,y) positions (cm) within the detection element + * - geometric size : (dx,dy) half-sizes (cm) + * + */ + +int main(int argc, char** argv) +{ + std::string outputFileName; + po::variables_map vm; + po::options_description options("options"); + std::string defaultName = fmt::format("mch-mapping{}-tree.root", run2 ? "-run2" : ""); + // clang-format off + options.add_options() + ("help,h", "produce help message") + ("outfile,o",po::value<std::string>(&outputFileName)->default_value(defaultName),"path to output file") + ; + // clang-format on + + po::options_description cmdline; + cmdline.add(options); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << fmt::format("This program exports the MCH {}mapping to a Root tree\n", + run2 ? "(Run2 version) " : ""); + std::cout << " --outfile path to the output file containing the Root tree"; + std::cout << options << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + TFile fout(outputFileName.c_str(), "RECREATE"); + if (!fout.IsOpen()) { + std::cout << "Cannot open output file " << outputFileName << "\n"; + exit(2); + } + + TTree tree("mchpads", "Muon Chamber Pads"); + DePads depads; + createPadBranches(tree, depads); + + forEachDetectionElement([&depads, &tree](int deid) { + Segmentation seg{deid}; + if (seg.nofPads() > MaxNofPadsPerDE) { + throw std::logic_error(fmt::format("Something is wrong : max number of pads should be below {} but got {}", MaxNofPadsPerDE, seg.nofPads())); + } + depads.nDePad = seg.nofPads(); + depads.deid = deid; + for (auto padid = 0; padid < depads.nDePad; padid++) { + depads.dsid[padid] = seg.padDualSampaId(padid); + depads.dsch[padid] = seg.padDualSampaChannel(padid); + depads.x[padid] = seg.padPositionX(padid); + depads.y[padid] = seg.padPositionY(padid); + depads.dx[padid] = seg.padSizeX(padid) / 2.0; + depads.dy[padid] = seg.padSizeY(padid) / 2.0; + } + tree.Fill(); + }); + + tree.Write(); + return 0; +} diff --git a/Detectors/MUON/MCH/Mapping/test/CMakeLists.txt b/Detectors/MUON/MCH/Mapping/test/CMakeLists.txt index ae49dee4867b0..a6e121dcdf39c 100644 --- a/Detectors/MUON/MCH/Mapping/test/CMakeLists.txt +++ b/Detectors/MUON/MCH/Mapping/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. foreach(impl RANGE 3 4) @@ -20,7 +21,6 @@ foreach(impl RANGE 3 4) NAME o2-test-mchmapping-pad-indices-impl${impl} SOURCES src/testPadIndices.cxx COMPONENT_NAME mchmapping - MAX_ATTEMPTS 1 COMMAND_LINE_ARGS --filepattern ${CMAKE_CURRENT_LIST_DIR}/data/test_pad_indices_de{}.json --de 100 --de 300 @@ -55,10 +55,10 @@ o2_add_test(StressTest3 SOURCES src/CathodeSegmentation.cxx src/CathodeSegmentationLong.cxx src/Segmentation.cxx src/TestParameters.cxx COMPONENT_NAME mchmapping - MAX_ATTEMPTS 1 COMMAND_LINE_ARGS --testpos ${CMAKE_CURRENT_LIST_DIR}/data/test_random_pos.json --run2 --manunumbering PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl3 O2::MCHMappingSegContour RapidJSON::RapidJSON + CONFIGURATIONS RelWithDebInfo Release MinSizeRel LABELS "muon;mch;long") o2_add_test(StressTest4 @@ -66,10 +66,10 @@ o2_add_test(StressTest4 SOURCES src/CathodeSegmentation.cxx src/CathodeSegmentationLong.cxx src/Segmentation.cxx src/TestParameters.cxx COMPONENT_NAME mchmapping - MAX_ATTEMPTS 1 COMMAND_LINE_ARGS --testpos ${CMAKE_CURRENT_LIST_DIR}/data/test_random_pos.json --manunumbering PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl4 O2::MCHMappingSegContour RapidJSON::RapidJSON + CONFIGURATIONS RelWithDebInfo Release MinSizeRel LABELS "muon;mch;long") if(benchmark_FOUND) diff --git a/Detectors/MUON/MCH/Mapping/test/src/BenchCathodeSegmentation.cxx b/Detectors/MUON/MCH/Mapping/test/src/BenchCathodeSegmentation.cxx index 03cb1531a2fa6..2d09a06292731 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/BenchCathodeSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/BenchCathodeSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -83,6 +84,28 @@ static void benchCathodeSegmentationConstructionAll(benchmark::State& state) } } +BENCHMARK_DEFINE_F(BenchO2, findPadByFEE) +(benchmark::State& state) +{ + int detElemId = state.range(0); + bool isBendingPlane = state.range(1); + o2::mch::mapping::CathodeSegmentation seg{detElemId, isBendingPlane}; + + int ntp{0}; + for (auto _ : state) { + ntp = 0; + int nds = seg.nofDualSampas(); + for (int ds = 0; ds < nds; ++ds) { + auto dualSampaId = seg.dualSampaId(ds); + for (int ch = 0; ch < 64; ch++) { + seg.findPadByFEE(dualSampaId, ch); + } + ++ntp; + } + } + state.counters["ntp"] = ntp; +} + // note: a bench is not a test, so here we assume findPadByPosition is correct, // we just time it. // so you must have a test of it somewhere else. @@ -111,6 +134,7 @@ BENCHMARK_DEFINE_F(BenchO2, findPadByPosition) BENCHMARK(benchCathodeSegmentationConstructionAll)->Unit(benchmark::kMillisecond); BENCHMARK_REGISTER_F(BenchO2, findPadByPosition)->Apply(segmentationList)->Unit(benchmark::kMillisecond); +BENCHMARK_REGISTER_F(BenchO2, findPadByFEE)->Apply(segmentationList)->Unit(benchmark::kMillisecond); BENCHMARK_REGISTER_F(BenchO2, ctor)->Apply(segmentationList)->Unit(benchmark::kMicrosecond); diff --git a/Detectors/MUON/MCH/Mapping/test/src/BenchSegmentation.cxx b/Detectors/MUON/MCH/Mapping/test/src/BenchSegmentation.cxx index 1c1fbe50ad090..9bb117d4158a2 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/BenchSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/BenchSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentation.cxx b/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentation.cxx index c211e64b93f29..db796e5084d9a 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,6 +30,7 @@ #include <fstream> #include <iostream> #include "TestParameters.h" +#include <fmt/format.h> using namespace o2::mch::mapping; namespace bdata = boost::unit_test::data; @@ -299,6 +301,20 @@ BOOST_AUTO_TEST_CASE(ThrowsIfDualSampaChannelIsNotBetween0And63) BOOST_CHECK_THROW(seg.findPadByFEE(102, 64), std::out_of_range); } +BOOST_AUTO_TEST_CASE(ReturnsFalseIfCatPadIdIsOutOfRange) +{ + forOneDetectionElementOfEachSegmentationType([](int detElemId) { + for (auto plane : {true, false}) { + CathodeSegmentation seg{detElemId, plane}; + BOOST_TEST_INFO_SCOPE(fmt::format("DeId {} Bending {}", detElemId, plane)); + BOOST_CHECK_EQUAL(seg.isValid(0), true); + BOOST_CHECK_EQUAL(seg.isValid(seg.nofPads() - 1), true); + BOOST_CHECK_EQUAL(seg.isValid(-1), false); + BOOST_CHECK_EQUAL(seg.isValid(seg.nofPads()), false); + } + }); +} + BOOST_AUTO_TEST_CASE(ReturnsTrueIfPadIsConnected) { BOOST_CHECK_EQUAL(seg.isValid(seg.findPadByFEE(102, 3)), true); diff --git a/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentationLong.cxx b/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentationLong.cxx index 6b67af10fe298..062b262f457ba 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentationLong.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentationLong.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/InputDocument.h b/Detectors/MUON/MCH/Mapping/test/src/InputDocument.h index 5386a92161d23..98e5ace886827 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/InputDocument.h +++ b/Detectors/MUON/MCH/Mapping/test/src/InputDocument.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/Segmentation.cxx b/Detectors/MUON/MCH/Mapping/test/src/Segmentation.cxx index b56742ae5da8a..200bad5e70118 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/Segmentation.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/Segmentation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,7 @@ #include <fstream> #include <iostream> #include "TestParameters.h" +#include <fmt/format.h> using namespace o2::mch::mapping; namespace bdata = boost::unit_test::data; @@ -186,7 +188,7 @@ BOOST_AUTO_TEST_CASE(CheckPadOffsetsAfterCopy) }); } -struct SEG { +struct SEG100 { Segmentation seg{100}; }; @@ -210,9 +212,60 @@ BOOST_AUTO_TEST_CASE(TestForEachPadAndPadIndexRange) }); } -// All the remaining tests of this file are using seg (DE100). +BOOST_AUTO_TEST_CASE(CheckOnePadPositionPresentOnOnlyBendingPlaneDE600) +{ + Segmentation de600(600); + double x = 54.34; + double y = -12.40; + int b, nb; + bool ok = de600.findPadPairByPosition(x, y, b, nb); + TestParameters params; + int testChannel = 12; + if (params.isSegmentationRun3) { + testChannel = 44; + } + BOOST_CHECK_EQUAL(ok, false); + int p = de600.findPadByFEE(307, testChannel); + BOOST_CHECK_EQUAL(p, b); + BOOST_CHECK_EQUAL(de600.isValid(b), true); + BOOST_CHECK_EQUAL(de600.isValid(nb), false); +} + +BOOST_AUTO_TEST_CASE(CheckOnePadPositionPresentOnOnlyBendingPlaneDE825) +{ + Segmentation de825(825); + double x = 110.09; + double y = -1.25; + int b, nb; + bool ok = de825.findPadPairByPosition(x, y, b, nb); + TestParameters params; + int testChannel{55}; + if (params.isSegmentationRun3) { + testChannel = 23; + } + BOOST_CHECK_EQUAL(ok, false); + int p = de825.findPadByFEE(1333, testChannel); + BOOST_CHECK_EQUAL(p, nb); + BOOST_CHECK_EQUAL(de825.isValid(b), false); + BOOST_CHECK_EQUAL(de825.isValid(nb), true); +} + +BOOST_AUTO_TEST_CASE(CheckOnePadPositionTotallyAbsentDE604) +{ + Segmentation de604(604); + double x = -19.25; + double y = 20.04; + int b, nb; + bool ok = de604.findPadPairByPosition(x, y, b, nb); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(de604.isValid(nb), false); + BOOST_CHECK_EQUAL(de604.isValid(b), false); +} -BOOST_FIXTURE_TEST_SUITE(DE100, SEG) +// All the remaining tests of this file are using specific +// detection elements DE100 + +BOOST_FIXTURE_TEST_SUITE(DE100, SEG100) BOOST_TEST_DECORATOR(*boost::unit_test::tolerance(1E-3)) BOOST_AUTO_TEST_CASE(CheckOnePosition) @@ -373,6 +426,17 @@ BOOST_AUTO_TEST_CASE(ReturnsFalseIfPadIsNotConnected) BOOST_CHECK_EQUAL(seg.isValid(seg.findPadByFEE(214, testChannel)), false); } +BOOST_AUTO_TEST_CASE(ReturnsFalseIfCatPadIdIsOutOfRange) +{ + forOneDetectionElementOfEachSegmentationType([](int detElemId) { + Segmentation seg{detElemId}; + BOOST_TEST_INFO_SCOPE(fmt::format("DeId {}", detElemId)); + BOOST_CHECK_EQUAL(seg.isValid(0), true); + BOOST_CHECK_EQUAL(seg.isValid(seg.nofPads() - 1), true); + BOOST_CHECK_EQUAL(seg.isValid(-1), false); + BOOST_CHECK_EQUAL(seg.isValid(seg.nofPads()), false); + }); +} BOOST_AUTO_TEST_CASE(HasPadByPosition) { int b, nb; diff --git a/Detectors/MUON/MCH/Mapping/test/src/TestParameters.cxx b/Detectors/MUON/MCH/Mapping/test/src/TestParameters.cxx index 22214a75a4d4f..bbd2dcf99a2fa 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/TestParameters.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/TestParameters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/TestParameters.h b/Detectors/MUON/MCH/Mapping/test/src/TestParameters.h index 617aee19bf8e9..a2d24d4130032 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/TestParameters.h +++ b/Detectors/MUON/MCH/Mapping/test/src/TestParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/generatePadIndices.cxx b/Detectors/MUON/MCH/Mapping/test/src/generatePadIndices.cxx index 96c952616ce08..3ab340ab7cb69 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/generatePadIndices.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/generatePadIndices.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Mapping/test/src/testPadIndices.cxx b/Detectors/MUON/MCH/Mapping/test/src/testPadIndices.cxx index b1cd88307686b..cc9d504d92e50 100644 --- a/Detectors/MUON/MCH/Mapping/test/src/testPadIndices.cxx +++ b/Detectors/MUON/MCH/Mapping/test/src/testPadIndices.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/PreClustering/CMakeLists.txt b/Detectors/MUON/MCH/PreClustering/CMakeLists.txt index 76c13dd887f24..ce3665e040e38 100644 --- a/Detectors/MUON/MCH/PreClustering/CMakeLists.txt +++ b/Detectors/MUON/MCH/PreClustering/CMakeLists.txt @@ -1,14 +1,15 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHPreClustering SOURCES src/PreClusterFinder.cxx src/PreClusterFinderMapping.cxx - PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl3 O2::MCHBase O2::Framework) + PUBLIC_LINK_LIBRARIES O2::MCHMappingImpl4 O2::MCHBase O2::Framework) diff --git a/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h b/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h index 53ed4c5378e71..1f8707ab5b502 100644 --- a/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h +++ b/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,10 +20,11 @@ #include <cstdint> #include <unordered_map> #include <vector> +#include <memory> #include <gsl/span> -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" #include "MCHBase/PreCluster.h" namespace o2 @@ -48,6 +50,8 @@ class PreClusterFinder void loadDigits(gsl::span<const Digit> digits); void loadDigit(const Digit& digit); + int discardHighOccupancy(bool perDE, bool perEvent); + int run(); void getPreClusters(std::vector<o2::mch::PreCluster>& preClusters, std::vector<Digit>& digits); @@ -63,6 +67,8 @@ class PreClusterFinder bool storeMe; // true if precluster to be saved (merging result) }; + void reset(int deIndex); + void preClusterizeRecursive(); void addPad(DetectionElement& de, uint16_t iPad, PreCluster& cluster); diff --git a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx index 608aef049b23f..652dd83c08eb0 100644 --- a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx +++ b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -74,36 +75,40 @@ void PreClusterFinder::deinit() void PreClusterFinder::reset() { /// reset fired pad and precluster information - - Mapping::MpPad* pad(nullptr); - - // loop over DEs for (int iDE = 0; iDE < SNDEs; ++iDE) { + reset(iDE); + } +} - DetectionElement& de(*(mDEs[iDE])); +//_________________________________________________________________________________________________ +void PreClusterFinder::reset(int deIndex) +{ + /// reset fired pad and precluster information of this DE - // loop over planes - for (int iPlane = 0; iPlane < 2; ++iPlane) { + Mapping::MpPad* pad(nullptr); + DetectionElement& de(*(mDEs[deIndex])); - // clear number of preclusters - mNPreClusters[iDE][iPlane] = 0; + // loop over planes + for (int iPlane = 0; iPlane < 2; ++iPlane) { - // loop over fired pads - for (int iFiredPad = 0; iFiredPad < de.nFiredPads[iPlane]; ++iFiredPad) { + // clear number of preclusters + mNPreClusters[deIndex][iPlane] = 0; - pad = &de.mapping->pads[de.firedPads[iPlane][iFiredPad]]; - pad->iDigit = 0; - pad->useMe = false; - } + // loop over fired pads + for (int iFiredPad = 0; iFiredPad < de.nFiredPads[iPlane]; ++iFiredPad) { - // clear number of fired pads - de.nFiredPads[iPlane] = 0; + pad = &de.mapping->pads[de.firedPads[iPlane][iFiredPad]]; + pad->iDigit = 0; + pad->useMe = false; } - // clear ordered number of fired pads - de.nOrderedPads[0] = 0; - de.nOrderedPads[1] = 0; + // clear number of fired pads + de.nFiredPads[iPlane] = 0; } + + // clear ordered number of fired pads + de.nOrderedPads[0] = 0; + de.nOrderedPads[1] = 0; } //_________________________________________________________________________________________________ @@ -147,6 +152,45 @@ void PreClusterFinder::loadDigit(const Digit& digit) ++de.nFiredPads[iPlane]; } +//_________________________________________________________________________________________________ +int PreClusterFinder::discardHighOccupancy(bool perDE, bool perEvent) +{ + /// discard high-occupancy (noisy) DE and/or event + + static constexpr double maxOccupancy = 0.2; + static constexpr int maxHighOccupancyDE = 4; + + if (!perDE && !perEvent) { + return 0; + } + + // discard DE with high occupancy in either bending or non-bending plane on stations 3-4-5 + int nDigits(0); + int nRemovedDigits(0); + int nHighOccupancyDE(0); + for (int iDE = 0; iDE < SNDEs; ++iDE) { + DetectionElement& de(*(mDEs[iDE])); + nDigits += de.nFiredPads[0] + de.nFiredPads[1]; + if (de.mapping->uid >= 500 && + (de.nFiredPads[0] > maxOccupancy * de.mapping->nPads[0] || + de.nFiredPads[1] > maxOccupancy * de.mapping->nPads[1])) { + ++nHighOccupancyDE; + if (perDE) { + nRemovedDigits += de.nFiredPads[0] + de.nFiredPads[1]; + reset(iDE); + } + } + } + + // discard events with too many high-occupancy DE + if (perEvent && nHighOccupancyDE > maxHighOccupancyDE) { + nRemovedDigits = nDigits; + reset(); + } + + return nRemovedDigits; +} + //_________________________________________________________________________________________________ int PreClusterFinder::run() { @@ -178,8 +222,8 @@ void PreClusterFinder::getPreClusters(std::vector<o2::mch::PreCluster>& preClust } // add this precluster - uint16_t firstDigit = digits.size(); - uint16_t nDigits = cluster->lastPad - cluster->firstPad + 1; + uint32_t firstDigit = digits.size(); + uint32_t nDigits = cluster->lastPad - cluster->firstPad + 1; preClusters.push_back({firstDigit, nDigits}); // add the digits of this precluster diff --git a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.cxx b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.cxx index e5fd7ee3fa773..a29cd2a58064b 100644 --- a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.cxx +++ b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.h b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.h index eabb626fd48e6..b67cee6d555f0 100644 --- a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.h +++ b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderMapping.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/README.md b/Detectors/MUON/MCH/README.md index 6f2ebf1975925..240418cc970a5 100644 --- a/Detectors/MUON/MCH/README.md +++ b/Detectors/MUON/MCH/README.md @@ -9,8 +9,12 @@ This is a top page for the MCH detector documentation. <!-- doxy \subpage refDetectorsMUONMCHContour \subpage refDetectorsMUONMCHClustering +\subpage refDetectorsMUONMCHCTF \subpage refDetectorsMUONMCHRaw \subpage refDetectorsMUONMCHMapping \subpage refDetectorsMUONMCHTracking \subpage refDetectorsMUONMCHWorkflow +\subpage refDetectorsMUONMCHGeometry +\subpage refDetectorsMUONMCHConditions +\subpage refDetectorsMUONMCHDevIO /doxy --> diff --git a/Detectors/MUON/MCH/Raw/CMakeLists.txt b/Detectors/MUON/MCH/Raw/CMakeLists.txt index 24c792259d0ff..24e08c92fcccf 100644 --- a/Detectors/MUON/MCH/Raw/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(ImplHelpers) add_subdirectory(ElecMap) diff --git a/Detectors/MUON/MCH/Raw/Common/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Common/CMakeLists.txt index ab29a45217243..b9958f6bbddc5 100644 --- a/Detectors/MUON/MCH/Raw/Common/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Common/CMakeLists.txt @@ -1,19 +1,27 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHRawCommon - SOURCES src/SampaHeader.cxx src/SampaCluster.cxx - PUBLIC_LINK_LIBRARIES fmt::fmt ms_gsl::ms_gsl Boost::boost O2::Headers O2::CommonConstants - O2::DetectorsRaw - PRIVATE_LINK_LIBRARIES O2::MCHRawImplHelpers) + SOURCES src/CoDecParam.cxx + src/DataFormats.cxx + src/SampaBunchCrossingCounter.cxx + src/SampaCluster.cxx + src/SampaHeader.cxx + PUBLIC_LINK_LIBRARIES fmt::fmt Microsoft.GSL::GSL Boost::boost + O2::Headers O2::CommonConstants + O2::DetectorsRaw + PRIVATE_LINK_LIBRARIES O2::MCHRawImplHelpers) +o2_target_root_dictionary(MCHRawCommon + HEADERS include/MCHRawCommon/CoDecParam.h) if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/CoDecParam.h b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/CoDecParam.h new file mode 100644 index 0000000000000..0018278afbc3f --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/CoDecParam.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_CODEC_PARAM_H +#define O2_MCH_RAW_CODEC_PARAM_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2::mch +{ + +struct CoDecParam : public o2::conf::ConfigurableParamHelper<CoDecParam> { + + int sampaBcOffset = 0; // default global sampa bunch-crossing offset + + O2ParamDef(CoDecParam, "MCHCoDecParam") +}; + +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/DataFormats.h b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/DataFormats.h index 70dc4b8db43fe..a42d5a0630ed1 100644 --- a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/DataFormats.h +++ b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/DataFormats.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #define O2_MCH_RAW_DATA_FORMATS_H #include <cstdint> +#include <iosfwd> namespace o2::mch::raw { @@ -30,10 +32,100 @@ struct SampleMode { bool operator()() const { return false; } }; +template <typename FORMAT> +struct isUserLogicFormat; // only defined (on purpose) for two types below + +template <> +struct isUserLogicFormat<UserLogicFormat> { + static constexpr bool value = true; +}; + +template <> +struct isUserLogicFormat<BareFormat> { + static constexpr bool value = false; +}; + +template <typename CHARGESUM> +struct isChargeSumMode; // only defined (on purpose) for two types below + +template <> +struct isChargeSumMode<ChargeSumMode> { + static constexpr bool value = true; +}; + +template <> +struct isChargeSumMode<SampleMode> { + static constexpr bool value = false; +}; + +using uint5_t = uint8_t; +using uint6_t = uint8_t; + +using SampaChannelAddress = uint5_t; // 0..31 channel of a Sampa +using DualSampaChannelId = uint6_t; // 0..63 channel of a *Dual* Sampa + using uint10_t = uint16_t; using uint20_t = uint32_t; using uint50_t = uint64_t; -}; // namespace o2::mch::raw +// Format of 64 bits-words of the UserLogicFormat +template <int VERSION> +struct ULHeaderWord; + +// initial UL format (2020) +template <> +struct ULHeaderWord<0> { + union { + uint64_t word; + struct { + uint64_t data : 50; + uint64_t error : 2; + uint64_t incomplete : 1; + uint64_t dsID : 6; + uint64_t linkID : 5; + }; + }; +}; + +// version 1 of UL format (2021) +// = as initial version with 1 bit less for linkID and 1 bit more for error +template <> +struct ULHeaderWord<1> { + union { + uint64_t word; + struct { + uint64_t data : 50; + uint64_t error : 3; + uint64_t incomplete : 1; + uint64_t dsID : 6; + uint64_t linkID : 4; + }; + }; +}; + +// structure of the FEEID field (16 bits) in the MCH Raw Data RDH +struct FEEID { + union { + uint16_t word; + struct { + uint16_t id : 8; + uint16_t chargeSum : 1; + uint16_t reserved : 3; + uint16_t ulFormatVersion : 4; + }; + }; +}; + +template <typename CHARGESUM> +uint16_t extraFeeIdChargeSumMask(); + +template <int VERSION> +uint16_t extraFeeIdVersionMask(); + +template <typename FORMAT> +uint8_t linkRemapping(uint8_t linkID); + +std::ostream& operator<<(std::ostream& os, const FEEID& f); +} // namespace o2::mch::raw #endif diff --git a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaBunchCrossingCounter.h b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaBunchCrossingCounter.h new file mode 100644 index 0000000000000..e488cdf47e5f3 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaBunchCrossingCounter.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_SAMPA_TIME_H +#define O2_MCH_RAW_SAMPA_TIME_H + +#include "MCHRawCommon/DataFormats.h" +#include <tuple> + +/** SampaBunchCrossingCounter is the internal Sampa counter at 40MHz, + * and coded in 20 bits */ + +namespace o2::mch::raw +{ + +uint20_t sampaBunchCrossingCounter(uint32_t orbit, uint16_t bc, uint32_t firstOrbit); + +std::tuple<uint32_t, uint16_t> orbitBC(uint20_t bunchCrossing, uint32_t firstOrbit); + +} // namespace o2::mch::raw + +#endif diff --git a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaCluster.h b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaCluster.h index 28f14f04332c0..d21b487e2dcb4 100644 --- a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaCluster.h +++ b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -67,6 +68,9 @@ struct SampaCluster { /// needed to store this cluster uint16_t nof10BitWords() const; + /// sum returns the total charge in the cluster + uint32_t sum() const; + uint10_t sampaTime; //< 10 bits for a local time stamp uint20_t bunchCrossing; //< 20 bits for bunch crossing counter uint20_t chargeSum; //< 20 bits for a cluster sum diff --git a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaHeader.h b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaHeader.h old mode 100755 new mode 100644 index 07f1686d42c0b..bc1882cb36f20 --- a/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaHeader.h +++ b/Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/SampaHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include <cstdlib> #include <iostream> +#include "MCHRawCommon/DataFormats.h" namespace o2 { @@ -67,7 +69,7 @@ class SampaHeader SampaPacketType pkt, uint16_t numWords, uint8_t h, - uint8_t ch, + SampaChannelAddress ch, uint32_t bx, bool dp); @@ -91,7 +93,7 @@ class SampaHeader SampaPacketType packetType() const; uint16_t nof10BitWords() const; uint8_t chipAddress() const; - uint8_t channelAddress() const; + SampaChannelAddress channelAddress() const; uint32_t bunchCrossingCounter() const; bool payloadParity() const; ///@} @@ -105,7 +107,7 @@ class SampaHeader void packetType(SampaPacketType pkt); void nof10BitWords(uint16_t nofwords); void chipAddress(uint8_t h); - void channelAddress(uint8_t ch); + void channelAddress(SampaChannelAddress ch); void bunchCrossingCounter(uint32_t bx); void payloadParity(bool dp); ///@} @@ -135,8 +137,11 @@ constexpr bool isSampaSync(uint64_t w) /// The 50-bits Sampa SYNC word. SampaHeader sampaSync(); +/// Heartbeat packet +SampaHeader sampaHeartbeat(uint8_t elinkId, uint20_t bunchCrossing); + /// Return channel number (0..63) -uint8_t channelNumber64(const SampaHeader& sh); +DualSampaChannelId getDualSampaChannelId(const SampaHeader& sh); /// packetTypeName returns a string representation of the given packet type. std::string packetTypeName(SampaPacketType pkt); diff --git a/Detectors/MUON/MCH/Raw/Common/src/CoDecParam.cxx b/Detectors/MUON/MCH/Raw/Common/src/CoDecParam.cxx new file mode 100644 index 0000000000000..56804ab99b516 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/src/CoDecParam.cxx @@ -0,0 +1,15 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawCommon/CoDecParam.h" + +using namespace o2::mch; +O2ParamImpl(o2::mch::CoDecParam); diff --git a/Detectors/MUON/MCH/Raw/Common/src/DataFormats.cxx b/Detectors/MUON/MCH/Raw/Common/src/DataFormats.cxx new file mode 100644 index 0000000000000..51f103ca51bd8 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/src/DataFormats.cxx @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawCommon/DataFormats.h" +#include <fmt/format.h> +#include <iostream> + +namespace o2::mch::raw +{ + +template <> +uint16_t extraFeeIdChargeSumMask<ChargeSumMode>() +{ + FEEID f{0}; + f.chargeSum = 1; + return f.word; +} + +template <> +uint16_t extraFeeIdChargeSumMask<SampleMode>() +{ + return 0; +} +template <int VERSION> +uint16_t extraFeeIdVersionMask() +{ + FEEID f{0}; + f.ulFormatVersion = VERSION; + return f.word; +} + +template uint16_t extraFeeIdVersionMask<0>(); +template uint16_t extraFeeIdVersionMask<1>(); + +template <> +uint8_t linkRemapping<UserLogicFormat>(uint8_t linkID) +{ + return 15; +} + +template <> +uint8_t linkRemapping<BareFormat>(uint8_t linkID) +{ + return linkID; +} + +std::ostream& operator<<(std::ostream& os, const FEEID& f) +{ + os << fmt::format("FEEID {} [id:{},chargeSum:{} ulVersion:{}]", + f.word, f.id, f.chargeSum, f.ulFormatVersion); + return os; +} +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Common/src/MCHRawCommonLinkDef.h b/Detectors/MUON/MCH/Raw/Common/src/MCHRawCommonLinkDef.h new file mode 100644 index 0000000000000..8adc3abaaeb8a --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/src/MCHRawCommonLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ namespace o2; +#pragma link C++ namespace o2::mch; + +#pragma link C++ class o2::mch::CoDecParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mch::CoDecParam> + ; + +#endif diff --git a/Detectors/MUON/MCH/Raw/Common/src/SampaBunchCrossingCounter.cxx b/Detectors/MUON/MCH/Raw/Common/src/SampaBunchCrossingCounter.cxx new file mode 100644 index 0000000000000..8dd617eef119b --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/src/SampaBunchCrossingCounter.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawCommon/SampaBunchCrossingCounter.h" +#include "CommonConstants/LHCConstants.h" +#include "NofBits.h" +#include "MCHRawCommon/CoDecParam.h" + +using namespace o2::constants::lhc; + +namespace o2::mch::raw +{ + +constexpr int BCINORBIT = o2::constants::lhc::LHCMaxBunches; + +uint20_t sampaBunchCrossingCounter(uint32_t orbit, uint16_t bc, + uint32_t firstOrbit) +{ + auto offset = CoDecParam::Instance().sampaBcOffset; + orbit -= firstOrbit; + auto bunchCrossingCounter = (orbit * LHCMaxBunches + bc + offset) % ((1 << 20) - 1); + impl::assertNofBits("bunchCrossingCounter", bunchCrossingCounter, 20); + return bunchCrossingCounter; +} + +std::tuple<uint32_t, uint16_t> orbitBC(uint20_t bunchCrossingCounter, + uint32_t firstOrbit) +{ + auto offset = CoDecParam::Instance().sampaBcOffset; + impl::assertNofBits("bunchCrossingCounter", bunchCrossingCounter, 20); + uint32_t orbit = (bunchCrossingCounter - offset) / LHCMaxBunches + firstOrbit; + int32_t bc = bunchCrossingCounter % LHCMaxBunches; + return {orbit, bc}; +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Common/src/SampaCluster.cxx b/Detectors/MUON/MCH/Raw/Common/src/SampaCluster.cxx index 256a7afc1e863..dab3445e4be3b 100644 --- a/Detectors/MUON/MCH/Raw/Common/src/SampaCluster.cxx +++ b/Detectors/MUON/MCH/Raw/Common/src/SampaCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -65,13 +66,25 @@ uint16_t SampaCluster::nof10BitWords() const if (isClusterSum()) { n10 += 2; // 20 bits (chargesum) } else { - for (auto s : samples) { - ++n10; // 10 bits for each sample - } + n10 += samples.size(); } return n10; } +uint32_t SampaCluster::sum() const +{ + uint32_t tot(0); + if (isClusterSum()) { + tot = chargeSum; + } else { + for (const auto& s : samples) { + tot += s; + } + } + + return tot; +} + std::ostream& operator<<(std::ostream& os, const SampaCluster& sc) { os << fmt::format("ts {:4d} ", sc.sampaTime); diff --git a/Detectors/MUON/MCH/Raw/Common/src/SampaHeader.cxx b/Detectors/MUON/MCH/Raw/Common/src/SampaHeader.cxx index 3a1fca07a8d18..e5db6c93643a8 100644 --- a/Detectors/MUON/MCH/Raw/Common/src/SampaHeader.cxx +++ b/Detectors/MUON/MCH/Raw/Common/src/SampaHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -67,8 +68,6 @@ struct CHECKNOFBITS { } if (PARITY_NOFBITS != 1) { throw std::invalid_argument(fmt::format("PARITY_NOFBITS is {0}. Should be 1", PARITY_NOFBITS)); - - throw; } } }; @@ -374,6 +373,19 @@ SampaHeader sampaSync() 0); } +SampaHeader sampaHeartbeat(uint8_t chipAddress, uint20_t bunchCrossing) +{ + SampaHeader sh; + sh.packetType(SampaPacketType::HeartBeat); + sh.nof10BitWords(0); + sh.chipAddress(chipAddress); + sh.channelAddress(21); + sh.bunchCrossingCounter(bunchCrossing); + sh.hammingCode(computeHammingCode(sh.uint64())); + sh.headerParity(computeHeaderParity(sh.uint64())); + return sh; +} + std::string asString(const SampaHeader& sh) { std::stringstream os; @@ -387,7 +399,7 @@ std::string asString(const SampaHeader& sh) } } os << "\n"; - os << fmt::sprintf("%6x %d %3x %10x %4x %5x %20x %d (0x%x) | %s %s", + os << fmt::sprintf("%6x %d %3x %10x %4x %5x %20x %d (0x%x) | HeaderType: %s %s", sh.hammingCode(), sh.headerParity(), static_cast<uint8_t>(sh.packetType()), @@ -398,7 +410,8 @@ std::string asString(const SampaHeader& sh) sh.payloadParity(), sh.uint64(), packetTypeName(sh.packetType()), - sh.hasError() ? "ERROR" : "") + sh.hasHammingError() ? " | HAMMING_ERROR" : "", + sh.hasParityError() ? "| PARITY ERROR" : "") << "\n"; return os.str(); } @@ -620,7 +633,7 @@ int computeHeaderParity4(uint64_t no) return computeParity(no); } -uint8_t channelNumber64(const SampaHeader& sh) +DualSampaChannelId getDualSampaChannelId(const SampaHeader& sh) { return sh.channelAddress() + (sh.chipAddress() % 2) * 32; } diff --git a/Detectors/MUON/MCH/Raw/Common/test/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Common/test/CMakeLists.txt index 86a639d5465de..63627e95563b1 100644 --- a/Detectors/MUON/MCH/Raw/Common/test/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Common/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(sampa-header SOURCES testSampaHeader.cxx @@ -20,6 +21,12 @@ o2_add_test(sampa-cluster LABELS "muon;mch;raw" PUBLIC_LINK_LIBRARIES O2::MCHRawCommon Boost::boost) +o2_add_test(sampa-bx-count + SOURCES testSampaBunchCrossingCounter.cxx + COMPONENT_NAME mchraw + LABELS "muon;mch;raw" + PUBLIC_LINK_LIBRARIES O2::MCHRawCommon Boost::boost) + if(benchmark_FOUND) o2_add_executable(sampa-header COMPONENT_NAME mch diff --git a/Detectors/MUON/MCH/Raw/Common/test/benchSampaHeader.cxx b/Detectors/MUON/MCH/Raw/Common/test/benchSampaHeader.cxx index 748058bff4b1f..dc435f82551ae 100644 --- a/Detectors/MUON/MCH/Raw/Common/test/benchSampaHeader.cxx +++ b/Detectors/MUON/MCH/Raw/Common/test/benchSampaHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Common/test/testSampaBunchCrossingCounter.cxx b/Detectors/MUON/MCH/Raw/Common/test/testSampaBunchCrossingCounter.cxx new file mode 100644 index 0000000000000..bf01bbd7d129d --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Common/test/testSampaBunchCrossingCounter.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// @author Laurent Aphecetche + +#define BOOST_TEST_MODULE Test MCHRaw SampaBunchCrossingCounter +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "MCHRawCommon/SampaBunchCrossingCounter.h" +#include "MCHRawCommon/CoDecParam.h" + +using namespace o2::mch::raw; + +constexpr uint32_t BXMAX = (1 << 20) - 1; + +BOOST_AUTO_TEST_SUITE(o2_mch_raw) + +BOOST_AUTO_TEST_SUITE(sampatime) + +BOOST_AUTO_TEST_CASE(SampaBunchCrossingCounterToIRConversionMustThrowIfBxDoesNotFitIn20Bits) +{ + uint32_t bx = BXMAX + 1; + BOOST_CHECK_THROW(orbitBC(bx, 0), + std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(SampaBunchCrossingCounterToIRConversionMustNotThrowIfBxFitIn20Bits) +{ + uint32_t bx = BXMAX; + BOOST_CHECK_NO_THROW(orbitBC(bx, 0)); +} + +BOOST_AUTO_TEST_CASE(SampaBunchCrossingCounterSpansABitLessThan294Orbits) +{ + o2::conf::ConfigurableParam::setValue("MCHCoDecParam", "sampaBcOffset", 0); + uint32_t bx = BXMAX; + auto [orbit, bc] = orbitBC(bx, 0); + BOOST_CHECK_EQUAL(orbit, 294); + BOOST_CHECK_EQUAL(bc, 759); +} + +BOOST_AUTO_TEST_CASE(Orbit294BC759MakesSampaBXCounterRolloverFromFirstOrbitZero) +{ + auto bx = sampaBunchCrossingCounter(294, 759, 0); + BOOST_CHECK_EQUAL(bx, 0); +} + +BOOST_AUTO_TEST_CASE(Orbit294BC759MakesSampaBXCounterRolloverFromAnyFirstOrbit) +{ + uint32_t firstOrbit = 12345; + auto bx = sampaBunchCrossingCounter(294 + firstOrbit, 759, firstOrbit); + BOOST_CHECK_EQUAL(bx, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/Common/test/testSampaCluster.cxx b/Detectors/MUON/MCH/Raw/Common/test/testSampaCluster.cxx index 610e9efdf3529..f03b8f1b3f07e 100644 --- a/Detectors/MUON/MCH/Raw/Common/test/testSampaCluster.cxx +++ b/Detectors/MUON/MCH/Raw/Common/test/testSampaCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Common/test/testSampaHeader.cxx b/Detectors/MUON/MCH/Raw/Common/test/testSampaHeader.cxx index fa7dc1dcd6a66..f81b57932e73e 100644 --- a/Detectors/MUON/MCH/Raw/Common/test/testSampaHeader.cxx +++ b/Detectors/MUON/MCH/Raw/Common/test/testSampaHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -275,5 +276,12 @@ BOOST_AUTO_TEST_CASE(CheckHeaderParity4) BOOST_CHECK_EQUAL(computeHeaderParity4(0x1722e9f00327d), 1); // 101101 P1 } +BOOST_AUTO_TEST_CASE(CreateHearbeat) +{ + SampaHeader h = sampaHeartbeat(0, 0); + BOOST_CHECK_EQUAL(h.isHeartbeat(), true); + h = sampaHeartbeat(39, 12345); + BOOST_CHECK_EQUAL(h.isHeartbeat(), true); +} BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/Decoder/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Decoder/CMakeLists.txt index 1c56998c73e51..b12f0d7ad8805 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Decoder/CMakeLists.txt @@ -1,16 +1,29 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHRawDecoder - SOURCES src/PageDecoder.cxx src/RDHManip.cxx src/OrbitInfo.cxx - PUBLIC_LINK_LIBRARIES O2::MCHRawCommon O2::MCHRawElecMap O2::DetectorsRaw + SOURCES src/BareELinkDecoder.cxx + src/DataDecoder.cxx + src/OrbitInfo.cxx + src/PageDecoder.cxx + src/ROFFinder.cxx + src/UserLogicElinkDecoder.cxx + src/RDHManip.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsRaw + O2::MCHBase + O2::MCHMappingImpl4 + O2::MCHMappingInterface + O2::MCHRawCommon + O2::MCHRawElecMap + O2::DataFormatsMCH PRIVATE_LINK_LIBRARIES O2::MCHRawImplHelpers) if(BUILD_TESTING) @@ -34,4 +47,16 @@ if(BUILD_TESTING) LABELS "muon;mch;raw" PUBLIC_LINK_LIBRARIES O2::MCHRawDecoder Boost::boost) + o2_add_test(digits-time-computation + SOURCES src/testDigitsTimeComputation.cxx + COMPONENT_NAME mchraw + LABELS "muon;mch;raw" + PUBLIC_LINK_LIBRARIES O2::MCHRawDecoder Boost::boost) + + o2_add_test(rof-finder + SOURCES src/testROFFinder.cxx + COMPONENT_NAME mchraw + LABELS "muon;mch;raw" + PUBLIC_LINK_LIBRARIES O2::MCHRawDecoder Boost::boost) + endif() diff --git a/Detectors/MUON/MCH/Raw/Decoder/README.md b/Detectors/MUON/MCH/Raw/Decoder/README.md index 39a1d6b5d3b8f..0e4ab6a5187c5 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/README.md +++ b/Detectors/MUON/MCH/Raw/Decoder/README.md @@ -16,61 +16,65 @@ called a (CRU) page. How the loop on the raw pages is done is *not* the decoder ## createPageDecoder -On the reading/consumer/decoding end, the choice of the internal decoder to use is made -using the data itself. You must give (at least) a part of a raw data buffer that contains - a (valid) RawDataHeader. That RDH is used to deduce which implementation is picked. +On the reading/consumer/decoding end, the choice of the internal decoder to use +is made using the data itself. You must give (at least) a part of a raw data +buffer that contains a (valid) RawDataHeader. That RDH is used to deduce which +implementation is picked. gsl::span<const std::byte> rawbuffer = ... ; auto pageDecoder = o2::mch::raw::createPageDecoder(rawbuffer,channelHandler); The `pageDecoder` that is returned is a function that you have to call on each -data page that you want to decode : +data page that you want to decode : while(some_data_is_available) { // get some memory buffer from somewhere ... - buffer = ... + buffer = ... // decode that buffer pageDecode(buffer); } -Internally the implementation is using templatized implementation, `PageDecoderImpl<FORMAT,CHARGESUM>`. -Currently the following template parameters combinations have been tested : +Internally the implementation is using templatized implementation, `PageDecoderImpl<FORMAT,CHARGESUM,VERSION>`. +Currently the following template parameters combinations have been tested : -| FORMAT | CHARGESUM | -| :-------------: | :-----------: | -| BareFormat | ChargeSumMode | -| BareFormat | SampleMode | -| UserLogicFormat | ChargeSumMode | -| UserLogicFormat | SampleMode | +| FORMAT | CHARGESUM | VERSION | +| :-------------: | :-----------: | :-----: | +| BareFormat | ChargeSumMode | 0 | +| BareFormat | SampleMode | 0 | +| UserLogicFormat | ChargeSumMode | 0 | +| UserLogicFormat | SampleMode | 0 | +| UserLogicFormat | ChargeSumMode | 1 | +| UserLogicFormat | SampleMode | 1 | -The `createPageDecoder` function requires two parameters : a raw memory buffer -(in the form of a `gsl::span<const std::byte>` (note that the span is on constant bytes, -i.e. the input buffer is read-only) -and a `SampaChannelHandler`. +The `createPageDecoder` function requires two parameters : a raw memory buffer +(in the form of a `gsl::span<const std::byte>` (note that the span is on +constant bytes, i.e. the input buffer is read-only) and a +`SampaChannelHandler`. ## SampaChannelHandler -The `SampaChannelHandler` is a function, that takes a dual sampa -identifier (in electronics realm, aka solar,group,index tuple), a channel -identifier within that dual sampa, a `SampaCluster` and returns nothing, i.e. : +The `SampaChannelHandler` is a function, that takes a dual sampa identifier +(in electronics realm, aka solar,group,index tuple), a channel identifier +within that dual sampa (in the 0..63 range), a `SampaCluster` and returns +nothing, i.e. : > A word of caution here about the naming. A `SampaCluster` is a group of raw > data samples of *one* dual sampa channel, and has nothing to do with a -> cluster of pads or something alike. +> cluster of pads or something alike. ```.cpp using SampaChannelHandler = std::function<void(DsElecId dsId, - uint8_t channel, + DualSampaChannelId channel, SampaCluster)>; ``` That function is called by the raw data decoder for each `SampaCluster` that it finds in the data. -A very simple example would be a function to dump the SampaClusters : +A very simple example would be a function to dump the SampaClusters : ```.cpp -SampaChannelHandler handlePacket(DsElecId dsId, uint8_t channel, SampaCluster sc) { +SampaChannelHandler handlePacket(DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { std::cout << fmt::format("{}-ch-{}-ts-{}-q-{}", asString(dsId), channel, sc.timestamp, sc.chargeSum)); } // (note that this particular function only correctly handles the SampaCluster in ChargeSum Mode) @@ -78,5 +82,5 @@ SampaChannelHandler handlePacket(DsElecId dsId, uint8_t channel, SampaCluster sc ## Example of decoding raw data -A (not particularly clean) example of how to decode raw data can be found in the source of the `o2-mchraw-dump` - executable [rawdump](../Tools/rawdump.cxx) +A (not particularly clean) example of how to decode raw data can be found in +the source of the `o2-mchraw-dump` executable [rawdump](../Tools/rawdump.cxx) diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h new file mode 100644 index 0000000000000..f3637f1e1d87f --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h @@ -0,0 +1,244 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DataDecoder.h +/// \author Andrea Ferrero +/// +/// \brief Definition of the decoder for the MCH data +/// + +#ifndef O2_MCH_DATADECODER_H_ +#define O2_MCH_DATADECODER_H_ + +#include <gsl/span> +#include <unordered_set> +#include <unordered_map> +#include <fstream> + +#include "Headers/RDHAny.h" +#include "DataFormatsMCH/Digit.h" +#include "MCHRawDecoder/OrbitInfo.h" +#include "MCHRawDecoder/PageDecoder.h" + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +using RdhHandler = std::function<void(o2::header::RDHAny*)>; + +// custom hash for OrbitInfo objects +struct OrbitInfoHash { + std::size_t operator()(const OrbitInfo& info) const noexcept + { + return std::hash<uint64_t>{}(info.get()); + } +}; + +void dumpOrbits(const std::unordered_set<OrbitInfo, OrbitInfoHash>& mOrbits); + +//_________________________________________________________________ +// +// Data decoder +//_________________________________________________________________ +class DataDecoder +{ + public: + static constexpr int32_t tfTimeMax{0x7FFFFFFF}; + static constexpr int32_t tfTimeInvalid{-tfTimeMax}; + + /// Structure storing the raw SAMPA information + struct SampaInfo { + union { + uint32_t id = 0; + struct { + uint32_t chip : 1; + uint32_t ds : 6; + uint32_t solar : 16; + uint32_t unused : 9; + }; + }; + + union { + // default value + uint64_t time = 0x0000000000000000; + struct { /// + uint32_t sampaTime : 10; /// bit 0 to 9: sampa time + uint32_t bunchCrossing : 20; /// bit 10 to 29: bunch crossing counter + uint32_t reserved : 2; /// bit 30 to 31: reserved + uint32_t orbit; /// bit 32 to 63: orbit + }; /// + }; + uint32_t getBXTime() const + { + return (bunchCrossing + (sampaTime * 4)); + } + int32_t tfTime; + bool timeValid() const + { + return (tfTime != tfTimeInvalid); + } + + bool operator==(const SampaInfo&) const; + bool operator<(const SampaInfo& rhs) const + { + if (id < rhs.id) { + return true; + } else if (time < rhs.time) { + return true; + } + return false; + } + }; + + /// Structure holding the value of the BC counter from the last decoded Heartbeat packet + /// from a given SAMPA chip, as well as the value of the first orbit in the corresponding TimeFrame + /// The structure also keeps track of the previous orbit/bc pair, in order to perform consistency checks + struct TimeFrameStartRecord { + TimeFrameStartRecord() = default; + + /// store the new orbit/bc pair, and copy the existing one in the "*Prev" data members + void update(uint32_t orbit, uint32_t bunchCrossing); + bool check(); + + int64_t mOrbit{-1}; + int64_t mBunchCrossing{-1}; + + int64_t mOrbitPrev{-1}; + int64_t mBunchCrossingPrev{-1}; + }; + + /// Structure used internally to store the information of the decoded digits. + /// In addition to the standard Digit structure, it also keeps the raw SAMPA information + struct RawDigit { + o2::mch::Digit digit; + SampaInfo info; + auto getDetID() const { return digit.getDetID(); } + auto getPadID() const { return digit.getPadID(); } + uint32_t getADC() const { return digit.getADC(); } + auto getTime() const { return info.tfTime; } + bool timeValid() const { return info.timeValid(); } + auto getOrbit() const { return info.orbit; } + auto getBunchCrossing() const { return info.bunchCrossing; } + auto getSampaTime() const { return info.sampaTime; } + auto getBXTime() const { return info.getBXTime(); } + + bool operator==(const RawDigit&) const; + }; + + using RawDigitVector = std::vector<RawDigit>; + + DataDecoder(SampaChannelHandler channelHandler, RdhHandler rdhHandler, + uint32_t sampaBcOffset, + std::string mapCRUfile, std::string mapFECfile, + bool ds2manu, bool verbose, bool useDummyElecMap); + + void reset(); + + /// Store the value of the first orbit in the TimeFrame to be processed + /// Must be called before processing the TmeFrame buffer + void setFirstOrbitInTF(uint32_t orbit); + + /// Decode one TimeFrame buffer and fill the vector of digits + void decodeBuffer(gsl::span<const std::byte> buf); + + /// Functions to set and get the calibration offset for the SAMPA time computation + void setSampaBcOffset(uint32_t offset) { mSampaTimeOffset = offset; } + uint32_t getSampaBcOffset() const { return mSampaTimeOffset; } + /// Helper function for subtracting the calibration offset from a given BC counter value + /// Returns the BC counter value after the offset correction + static uint32_t subtractBcOffset(uint32_t bc, uint32_t offset); + + /// For a given SAMPA chip, update the information about the BC counter value at the beginning of the TimeFrame + void updateTimeFrameStartRecord(uint64_t chipId, uint32_t mFirstOrbitInTF, uint32_t bcTF); + /// Convert a Solar/Ds/Chip triplet into an unique chip index + static uint64_t getChipId(uint32_t solar, uint32_t ds, uint32_t chip); + /// Helper function for computing the digit time relative to the beginning of the TimeFrame + static int32_t getDigitTime(uint32_t orbitTF, uint32_t bcTF, uint32_t orbitDigit, uint32_t bcDigit); + /// Compute the time of all the digits that have been decoded in the current TimeFrame + void computeDigitsTime(); + + /// Get the vector of digits that have been decoded in the current TimeFrame + const RawDigitVector& getDigits() const { return mDigits; } + /// Get the list of orbits that have been found in the current TimeFrame for each CRU link + const std::unordered_set<OrbitInfo, OrbitInfoHash>& getOrbits() const { return mOrbits; } + /// Initialize the digits from an external vector. To be only used for unit tests. + void setDigits(const RawDigitVector& digits) { mDigits = digits; } + + private: + void initElec2DetMapper(std::string filename); + void initFee2SolarMapper(std::string filename); + void init(); + void decodePage(gsl::span<const std::byte> page); + void dumpDigits(); + bool getPadMapping(const DsElecId& dsElecId, DualSampaChannelId channel, int& deId, int& dsIddet, int& padId); + bool addDigit(const DsElecId& dsElecId, DualSampaChannelId channel, const o2::mch::raw::SampaCluster& sc); + bool getTimeFrameStartRecord(const RawDigit& digit, uint32_t& orbit, uint32_t& bc); + bool getMergerChannelId(const DsElecId& dsElecId, DualSampaChannelId channel, uint32_t& chId, uint32_t& dsId); + uint64_t getMergerChannelBitmask(DualSampaChannelId channel); + void updateMergerRecord(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, uint32_t digitId); + bool mergeDigits(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, o2::mch::raw::SampaCluster& sc); + + // structure that stores the index of the last decoded digit for a given readout channel, + // as well as the time stamp of the last ADC sample of the digit + struct MergerChannelRecord { + MergerChannelRecord() = default; + uint32_t digitId{0xFFFF}; + uint32_t bcEnd{0xFFFF}; + }; + + static constexpr uint32_t sMaxSolarId = 200 * 8 - 1; + static constexpr uint32_t sReadoutBoardsNum = (sMaxSolarId + 1) * 40; + static constexpr uint32_t sReadoutChipsNum = sReadoutBoardsNum * 2; + static constexpr uint32_t sReadoutChannelsNum = sReadoutChipsNum * 32; + // table storing the last recorded TF time stamp in SAMPA BC counter units + std::vector<TimeFrameStartRecord> mTimeFrameStartRecords; + + // table storing the digits merging information for each readout channel in the MCH system + std::vector<MergerChannelRecord> mMergerRecords; ///< merger records for all MCH readout channels + std::vector<uint64_t> mMergerRecordsReady; ///< merger status flags, one bit for one DS channel + + Elec2DetMapper mElec2Det{nullptr}; ///< front-end electronics mapping + FeeLink2SolarMapper mFee2Solar{nullptr}; ///< CRU electronics mapping + std::string mMapFECfile; ///< optional text file with custom front-end electronics mapping + std::string mMapCRUfile; ///< optional text file with custom CRU mapping + + o2::mch::raw::PageDecoder mDecoder; ///< CRU page decoder + + RawDigitVector mDigits; ///< vector of decoded digits + std::unordered_set<OrbitInfo, OrbitInfoHash> mOrbits; ///< list of orbits in the processed buffer + + uint32_t mFirstOrbitInTF; ///< first orbit in the processed time-frame + uint32_t mSampaTimeOffset{0}; ///< SAMPA BC counter value to be subtracted from the HBPacket BC at the TF start + + SampaChannelHandler mChannelHandler; ///< optional user function to be called for each decoded SAMPA hit + std::function<void(o2::header::RDHAny*)> mRdhHandler; ///< optional user function to be called for each RDH + + bool mDebug{false}; + int mErrorCount{0}; + bool mDs2manu{false}; + uint32_t mOrbit{0}; + bool mUseDummyElecMap{false}; +}; + +bool operator<(const DataDecoder::RawDigit& d1, const DataDecoder::RawDigit& d2); + +std::ostream& operator<<(std::ostream& os, const DataDecoder::RawDigit& d); + +std::string asString(const DataDecoder::RawDigit& d); + +} // namespace raw +} // namespace mch +} // end namespace o2 +#endif //O2_MCH_DATADECODER_H_ diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DecodedDataHandlers.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DecodedDataHandlers.h new file mode 100644 index 0000000000000..8fb7f45902f21 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DecodedDataHandlers.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_DECODED_DATA_HANDLES_H +#define O2_MCH_DECODED_DATA_HANDLES_H + +#include <functional> + +#include "MCHRawCommon/SampaCluster.h" +#include "MCHRawElecMap/DsElecId.h" + +namespace o2 +{ +namespace mch +{ +namespace raw +{ +/// A SampaChannelHandler is a function that takes a pair to identify +/// a readout dual sampa channel and a SampaCluster containing the channel data. +using SampaChannelHandler = std::function<void(DsElecId dsId, + DualSampaChannelId channel, + SampaCluster)>; + +/// A SampaHeartBeatHandler is a function that takes a chip index and +/// a bunch crossing counter value found in a HeartBeat packet +using SampaHeartBeatHandler = std::function<void(DsElecId dsId, + uint8_t chip, + uint20_t bunchCrossing)>; + +/// A SampaErrorHandler is a function that takes a chip index and +/// a numerical code describing the error encountered during the decoding +using SampaErrorHandler = std::function<void(DsElecId dsId, + int8_t chip, + uint32_t error)>; + +struct DecodedDataHandlers { + SampaChannelHandler sampaChannelHandler; + SampaHeartBeatHandler sampaHeartBeatHandler; + SampaErrorHandler sampaErrorHandler; +}; + +} // namespace raw +} // namespace mch +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h new file mode 100644 index 0000000000000..8bbcf33b5560c --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_ERROR_CODES_H +#define O2_MCH_RAW_ERROR_CODES_H + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +enum ErrorCodes { + ErrorParity = 1, // 1 + ErrorHammingCorrectable = 1 << 1, // 2 + ErrorHammingUncorrectable = 1 << 2, // 4 + ErrorBadClusterSize = 1 << 3, // 8 + ErrorBadPacketType = 1 << 4, // 16 + ErrorBadHeartBeatPacket = 1 << 5, // 32 + ErrorBadIncompleteWord = 1 << 6, // 64 + ErrorTruncatedData = 1 << 7, // 128 + ErrorBadELinkID = 1 << 8, // 256 + ErrorBadLinkID = 1 << 9, // 512 + ErrorUnknownLinkID = 1 << 10 // 1024 +}; + +} // namespace raw +} // namespace mch +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/OrbitInfo.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/OrbitInfo.h index 87f0944456ae7..17a6dbc2cb5ed 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/OrbitInfo.h +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/OrbitInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,6 +43,7 @@ class OrbitInfo friend bool operator==(const OrbitInfo& o1, const OrbitInfo& o2); friend bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2); + friend bool operator<(const OrbitInfo& o1, const OrbitInfo& o2); private: uint64_t mOrbitInfo = {0}; @@ -51,6 +53,7 @@ class OrbitInfo bool operator==(const OrbitInfo& o1, const OrbitInfo& o2); bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2); +bool operator<(const OrbitInfo& o1, const OrbitInfo& o2); } //namespace mch } //namespace o2 diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/PageDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/PageDecoder.h index 42abc29c69987..62c142f89e5b5 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/PageDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/PageDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include <functional> #include <gsl/span> #include <map> -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include "MCHRawElecMap/Mapper.h" namespace o2::mch::raw @@ -32,11 +33,11 @@ using RawBuffer = gsl::span<const std::byte>; // // @param rdhBuffer a raw memory buffer containing (at least) one RDH // which information is used to decide which PageDecoder implementation to choose -// @param channelHandler (optional) a callable object that will be called for each -// decoded SampaCluster +// @param decodedDataHandlers a structure with various callable objects (optional) that +/// will be called for each decoded Sampa packet and in case of decoding errors // PageDecoder createPageDecoder(RawBuffer rdhBuffer, - SampaChannelHandler channelHandler); + DecodedDataHandlers decodedDataHandlers); // Same as above but only to be used for special cases, e.g. when // trying to decode test beam data with an electronic mapping that @@ -46,9 +47,17 @@ PageDecoder createPageDecoder(RawBuffer rdhBuffer, // object into a solarId. // PageDecoder createPageDecoder(RawBuffer rdhBuffer, - SampaChannelHandler channelHandler, + DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar); +// Alternative versions of the same functions, taking a SampaChannelHandler as parameter. +[[deprecated("Use createPageDecoder(RawBuffer,DecodedDataHandlers) instead.")]] PageDecoder createPageDecoder(RawBuffer rdhBuffer, + SampaChannelHandler channelHandler); + +[[deprecated("Use createPageDecoder(RawBuffer,DecodedDataHandlers,fee2solar) instead.")]] PageDecoder createPageDecoder(RawBuffer rdhBuffer, + SampaChannelHandler channelHandler, + FeeLink2SolarMapper fee2solar); + // A PageParser loops over the given buffer and apply the given page decoder // to each page. using PageParser = std::function<void(RawBuffer buffer, PageDecoder pageDecoder)>; diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ROFFinder.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ROFFinder.h new file mode 100644 index 0000000000000..cf80323c30022 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ROFFinder.h @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ROFFinder.h +/// \brief Class to group the fired pads according to their time stamp +/// +/// \author Andrea Ferrero, CEA + +#ifndef ALICEO2_MCH_ROFFINDER_H_ +#define ALICEO2_MCH_ROFFINDER_H_ + +#include <cassert> +#include <cstdint> +#include <unordered_map> +#include <vector> + +#include <gsl/span> + +#include "DataFormatsMCH/Digit.h" +#include "MCHRawDecoder/DataDecoder.h" +#include "DataFormatsMCH/ROFRecord.h" + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +class ROFFinder +{ + public: + using RawDigit = DataDecoder::RawDigit; + using RawDigitId = size_t; + using RawDigitIdVector = std::vector<RawDigitId>; + + ROFFinder(const DataDecoder::RawDigitVector& digits, uint32_t firstTForbit); + ~ROFFinder(); + + void process(bool dummyROFs = false); + + o2::InteractionRecord digitTime2IR(const RawDigit& digit); + + std::optional<DataDecoder::RawDigit> getOrderedDigit(int i); + RawDigitIdVector getOrderedDigits() { return mOrderedDigits; } + std::vector<o2::mch::ROFRecord> getROFRecords() { return mOutputROFs; } + + char* saveDigitsToBuffer(size_t& bufSize); + char* saveROFRsToBuffer(size_t& bufSize); + + bool isRofTimeMonotonic(); + bool isDigitsTimeAligned(); + void dumpOutputDigits(); + void dumpOutputROFs(); + + private: + void sortDigits(); + void storeROF(); + + const DataDecoder::RawDigitVector& mInputDigits; + uint32_t mFirstTForbit; + + int mFirstIdx{-1}; + int mEntries{0}; + o2::InteractionRecord mIR; + + RawDigitIdVector mOrderedDigits; + std::vector<o2::mch::ROFRecord> mOutputROFs{}; +}; + +} // namespace raw +} // namespace mch +} // namespace o2 + +#endif // ALICEO2_MCH_ROFFINDERSIMPLE_H_ diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/SampaChannelHandler.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/SampaChannelHandler.h deleted file mode 100644 index 58470c4bc772c..0000000000000 --- a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/SampaChannelHandler.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MCH_RAW_SAMPA_CHANNEL_HANDLER_H -#define O2_MCH_RAW_SAMPA_CHANNEL_HANDLER_H - -#include <functional> - -#include "MCHRawCommon/SampaCluster.h" -#include "MCHRawElecMap/DsElecId.h" - -namespace o2 -{ -namespace mch -{ -namespace raw -{ -/// A SampaChannelHandler is a function that takes a pair to identify -/// a readout sampa channel and a SampaCluster containing the channel data. -using SampaChannelHandler = std::function<void(DsElecId dsId, - uint8_t channel, - SampaCluster)>; -} // namespace raw -} // namespace mch -} // namespace o2 - -#endif diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/BareELinkDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/BareELinkDecoder.cxx new file mode 100644 index 0000000000000..b007fd2398586 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/BareELinkDecoder.cxx @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "BareElinkDecoder.h" + +namespace o2::mch::raw +{ +template <> +void BareElinkDecoder<ChargeSumMode>::sendCluster() +{ + SampaChannelHandler handler = mDecodedDataHandlers.sampaChannelHandler; + if (handler) { + handler(mDsId, getDualSampaChannelId(mSampaHeader), + SampaCluster(mTimestamp, mSampaHeader.bunchCrossingCounter(), mClusterSum, mClusterSize)); + } +} + +template <> +void BareElinkDecoder<SampleMode>::sendCluster() +{ + SampaChannelHandler handler = mDecodedDataHandlers.sampaChannelHandler; + if (handler) { + handler(mDsId, getDualSampaChannelId(mSampaHeader), + SampaCluster(mTimestamp, mSampaHeader.bunchCrossingCounter(), mSamples)); + } + mSamples.clear(); +} +template <> +void BareElinkDecoder<ChargeSumMode>::changeToReadingData() +{ + changeState(State::ReadingClusterSum, 20); +} + +template <> +void BareElinkDecoder<SampleMode>::changeToReadingData() +{ + changeState(State::ReadingSample, 10); +} + +std::string bitBufferString(const std::bitset<50>& bs, int imax) +{ + std::string s; + for (int i = 0; i < 64; i++) { + if ((static_cast<uint64_t>(1) << i) > imax) { + break; + } + if (bs.test(i)) { + s += "1"; + } else { + s += "0"; + } + } + return s; +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/BareElinkDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/BareElinkDecoder.h index 04a455ae9b3ca..86e384eecd439 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/BareElinkDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/BareElinkDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include "Assertions.h" #include "MCHRawCommon/DataFormats.h" #include "MCHRawCommon/SampaHeader.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include <bitset> #include <fmt/format.h> #include <fmt/printf.h> @@ -33,7 +34,7 @@ namespace o2::mch::raw /// /// Bits coming from parts of the GBT words are added to the Elink using the /// append() method and each time a SampaCluster is decoded, -/// it is passed to the SampaChannelHandler for further processing (or none). +/// it is passed to the DecodedDataHandlers for further processing (or none). /// /// \nosubgrouping /// @@ -44,11 +45,11 @@ class BareElinkDecoder /// Constructor. /// \param dsId the (electronic) id of the dual sampa this elink /// is connected to - /// \param sampaChannelHandler a callable that is passed - /// each SampaCluster that will be decoded - BareElinkDecoder(DsElecId dsId, SampaChannelHandler sampaChannelHandler); + /// \param decodedDataHandlers a structure with various callable that + /// handle the Sampa packets and decoding errors + BareElinkDecoder(DsElecId dsId, DecodedDataHandlers decodedDataHandlers); - /** @name Main interface + /** @name Main interface */ ///@{ @@ -97,6 +98,7 @@ class BareElinkDecoder void oneLess10BitWord(); void process(); void sendCluster(); + void sendHBPacket(); void softReset(); template <typename T> @@ -104,7 +106,7 @@ class BareElinkDecoder private: DsElecId mDsId; - SampaChannelHandler mSampaChannelHandler; //< The callable that will deal with the SampaCluster objects we decode + DecodedDataHandlers mDecodedDataHandlers; //< The structure with the callables that deal with the Sampa packets and the decoding errors SampaHeader mSampaHeader; //< Current SampaHeader uint64_t mBitBuffer; //< Our internal bit stream buffer /** @name internal global counters @@ -133,30 +135,13 @@ class BareElinkDecoder constexpr int HEADERSIZE = 50; -namespace -{ -std::string bitBufferString(const std::bitset<50>& bs, int imax) -{ - std::string s; - for (int i = 0; i < 64; i++) { - if ((static_cast<uint64_t>(1) << i) > imax) { - break; - } - if (bs.test(i)) { - s += "1"; - } else { - s += "0"; - } - } - return s; -} -} // namespace +std::string bitBufferString(const std::bitset<50>& bs, int imax); template <typename CHARGESUM> BareElinkDecoder<CHARGESUM>::BareElinkDecoder(DsElecId dsId, - SampaChannelHandler sampaChannelHandler) + DecodedDataHandlers decodedDataHandlers) : mDsId{dsId}, - mSampaChannelHandler{sampaChannelHandler}, + mDecodedDataHandlers{decodedDataHandlers}, mSampaHeader{}, mBitBuffer{}, mNofSync{}, @@ -260,8 +245,12 @@ void BareElinkDecoder<CHARGESUM>::handleHeader() softReset(); break; case SampaPacketType::HeartBeat: - fmt::printf("BareElinkDecoder %d: HEARTBEAT found. Should be doing sth about it ?\n", mDsId); - softReset(); + if (mSampaHeader.isHeartbeat()) { + sendHBPacket(); + changeState(State::LookingForHeader, HEADERSIZE); + } else { + softReset(); + } break; default: throw std::logic_error("that should not be possible"); @@ -419,37 +408,13 @@ std::ostream& operator<<(std::ostream& os, const o2::mch::raw::BareElinkDecoder< return os; } -template <> -void BareElinkDecoder<ChargeSumMode>::sendCluster() -{ - if (mSampaChannelHandler) { - mSampaChannelHandler(mDsId, - channelNumber64(mSampaHeader), - SampaCluster(mTimestamp, mSampaHeader.bunchCrossingCounter(), mClusterSum, mClusterSize)); - } -} - -template <> -void BareElinkDecoder<SampleMode>::sendCluster() +template <typename CHARGESUM> +void BareElinkDecoder<CHARGESUM>::sendHBPacket() { - if (mSampaChannelHandler) { - mSampaChannelHandler(mDsId, - channelNumber64(mSampaHeader), - SampaCluster(mTimestamp, mSampaHeader.bunchCrossingCounter(), mSamples)); + SampaHeartBeatHandler handler = mDecodedDataHandlers.sampaHeartBeatHandler; + if (handler) { + handler(mDsId, mSampaHeader.chipAddress() % 2, mSampaHeader.bunchCrossingCounter()); } - mSamples.clear(); -} - -template <> -void BareElinkDecoder<ChargeSumMode>::changeToReadingData() -{ - changeState(State::ReadingClusterSum, 20); -} - -template <> -void BareElinkDecoder<SampleMode>::changeToReadingData() -{ - changeState(State::ReadingSample, 10); } } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/BareGBTDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/BareGBTDecoder.h index 2699e7b2b0d4f..97a9c91c9f3ce 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/BareGBTDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/BareGBTDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include <array> #include "BareElinkDecoder.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include <gsl/span> #include <fmt/printf.h> #include <fmt/format.h> @@ -40,8 +41,9 @@ class BareGBTDecoder : public PayloadDecoder<BareGBTDecoder<CHARGESUM>> public: /// Constructor. /// \param solarId - /// \param sampaChannelHandler the callable that will handle each SampaCluster - BareGBTDecoder(uint16_t solarId, SampaChannelHandler sampaChannelHandler); + /// \param decodedDataHandlers a structure with various callable that + /// handle the Sampa packets and decoding errors + BareGBTDecoder(uint16_t solarId, DecodedDataHandlers decodedDataHandlers); /** @name Main interface */ @@ -81,10 +83,10 @@ using namespace boost::multiprecision; template <typename CHARGESUM> BareGBTDecoder<CHARGESUM>::BareGBTDecoder(uint16_t solarId, - SampaChannelHandler sampaChannelHandler) - : PayloadDecoder<BareGBTDecoder<CHARGESUM>>(sampaChannelHandler), + DecodedDataHandlers decodedDataHandlers) + : PayloadDecoder<BareGBTDecoder<CHARGESUM>>(decodedDataHandlers), mSolarId{solarId}, - mElinks{impl::makeArray<40>([=](uint8_t i) { return BareElinkDecoder<CHARGESUM>(DsElecId{solarId, static_cast<uint8_t>(i / 5), static_cast<uint8_t>(i % 5)}, sampaChannelHandler); })}, + mElinks{impl::makeArray<40>([=](uint8_t i) { return BareElinkDecoder<CHARGESUM>(DsElecId{solarId, static_cast<uint8_t>(i / 5), static_cast<uint8_t>(i % 5)}, decodedDataHandlers); })}, mNofGbtWordsSeens{0} { } diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx new file mode 100644 index 0000000000000..b0d28a373e2cb --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx @@ -0,0 +1,761 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DataDecoder.cxx +/// \author Andrea Ferrero +/// +/// \brief Implementation of a data processor to run the raw decoding +/// + +#include "MCHRawDecoder/DataDecoder.h" + +#include <fstream> +#include <FairMQLogger.h> +#include "Headers/RAWDataHeader.h" +#include "CommonConstants/LHCConstants.h" +#include "DetectorsRaw/RDHUtils.h" +#include "MCHMappingInterface/Segmentation.h" +#include "Framework/Logger.h" + +#define MCH_DECODER_MAX_ERROR_COUNT 100 + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +using namespace o2; +//using namespace o2::framework; +using namespace o2::mch::mapping; +using RDH = o2::header::RDHAny; + +static constexpr uint32_t bcRollOver = (1 << 20); +static constexpr uint32_t twentyBitsAtOne = 0xFFFFF; +static constexpr uint32_t bcInOrbit = o2::constants::lhc::LHCMaxBunches; + +// conversion matrix between the original channels numbering of the RUN2 readout electronics and the final version of the RUN3 DualSAMPA-based readout +static std::array<int, 64> refManu2ds_st345_v5 = { + 63, 62, 61, 60, 59, 57, 56, 53, 51, 50, 47, 45, 44, 41, 38, 35, + 36, 33, 34, 37, 32, 39, 40, 42, 43, 46, 48, 49, 52, 54, 55, 58, + 7, 8, 5, 2, 6, 1, 3, 0, 4, 9, 10, 15, 17, 18, 22, 25, + 31, 30, 29, 28, 27, 26, 24, 23, 20, 21, 16, 19, 12, 14, 11, 13}; + +// conversion matrix between the original channels numbering of the RUN2 readout electronics and the intermediate version of the RUN3 DualSAMPA-based readout +static std::array<int, 64> refManu2ds_st345_v2 = { + 62, 61, 63, 60, 59, 55, 58, 57, 56, 54, 50, 46, 42, 39, 37, 41, + 35, 36, 33, 34, 32, 38, 43, 40, 45, 44, 47, 48, 49, 52, 51, 53, + 7, 6, 5, 4, 2, 3, 1, 0, 9, 11, 13, 15, 17, 19, 21, 23, + 31, 30, 29, 28, 27, 26, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8}; + +#define refManu2ds_st345 refManu2ds_st345_v5 + +// inverse channel conversion matrix +static std::array<int, 64> refDs2manu_st345; + +// function returning the RUN3 DualSAMPA channel number given the original RUN2 channel +static int manu2ds(int i) +{ + return refManu2ds_st345[i]; +} + +// function returning the original RUN2 channel number given the RUN3 DualSAMPA channel +static int ds2manu(int i) +{ + return refDs2manu_st345[i]; +} + +//_________________________________________________________________________________________________ + +static void patchPage(gsl::span<const std::byte> rdhBuffer, bool verbose) +{ + auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(rdhBuffer[0]))); + + auto existingFeeId = o2::raw::RDHUtils::getFEEID(rdhAny); + if (existingFeeId == 0) { + // early versions of raw data did not set the feeId + // which we need to select the right decoder + + auto cruId = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF; + auto endpoint = o2::raw::RDHUtils::getEndPointID(rdhAny); + auto flags = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF00; + + uint32_t feeId = cruId * 2 + endpoint + flags; + o2::raw::RDHUtils::setFEEID(rdhAny, feeId); + } +}; + +//_________________________________________________________________________________________________ + +bool operator<(const DataDecoder::RawDigit& d1, const DataDecoder::RawDigit& d2) +{ + if (d1.getTime() == d2.getTime()) { + if (d1.getDetID() == d2.getDetID()) { + return d1.getPadID() < d2.getPadID(); + } + return d1.getDetID() < d2.getDetID(); + } + return (d1.getTime() < d2.getTime()); +} + +std::string asString(const DataDecoder::RawDigit& d) +{ + return fmt::format("DE {:4d} PADID {:5d} ADC {:5d} TIME {} BX {}", + d.getDetID(), d.getPadID(), d.getADC(), d.getTime(), d.getBunchCrossing()); +} + +std::ostream& operator<<(std::ostream& os, const DataDecoder::RawDigit& d) +{ + os << asString(d); + return os; +} + +//_________________________________________________________________________________________________ + +static bool isValidDeID(int deId) +{ + for (auto id : deIdsForAllMCH) { + if (id == deId) { + return true; + } + } + + return false; +} + +//======================= +// Data decoder + +bool DataDecoder::SampaInfo::operator==(const DataDecoder::SampaInfo& other) const +{ + return chip == other.chip && + ds == other.ds && + solar == other.solar && + sampaTime == other.sampaTime && + bunchCrossing == other.bunchCrossing && + orbit == other.orbit && + tfTime == other.tfTime; + ; +} + +bool DataDecoder::RawDigit::operator==(const DataDecoder::RawDigit& other) const +{ + return digit == other.digit && info == other.info; +} + +void DataDecoder::TimeFrameStartRecord::update(uint32_t orbit, uint32_t bunchCrossing) +{ + mOrbitPrev = mOrbit; + mBunchCrossingPrev = mBunchCrossing; + + mOrbit = orbit; + mBunchCrossing = bunchCrossing; +} + +bool DataDecoder::TimeFrameStartRecord::check() +{ + if (mOrbitPrev < 0) { + return true; + } + + if (mOrbit < mOrbitPrev) { + return false; + } + + uint64_t dOrbit = mOrbit - mOrbitPrev; + uint64_t bcExpected = dOrbit * bcInOrbit + mBunchCrossingPrev; + + uint64_t bcExpected20bits = bcExpected & twentyBitsAtOne; + + return (bcExpected20bits == mBunchCrossing); +} + +//_________________________________________________________________________________________________ + +DataDecoder::DataDecoder(SampaChannelHandler channelHandler, RdhHandler rdhHandler, + uint32_t sampaBcOffset, + std::string mapCRUfile, std::string mapFECfile, + bool ds2manu, bool verbose, bool useDummyElecMap) + : mChannelHandler(channelHandler), mRdhHandler(rdhHandler), mSampaTimeOffset(sampaBcOffset), mMapCRUfile(mapCRUfile), mMapFECfile(mapFECfile), mDs2manu(ds2manu), mDebug(verbose), mUseDummyElecMap(useDummyElecMap) +{ + init(); +} + +//_________________________________________________________________________________________________ + +void DataDecoder::setFirstOrbitInTF(uint32_t orbit) +{ + mFirstOrbitInTF = orbit; +} + +//_________________________________________________________________________________________________ + +void DataDecoder::decodeBuffer(gsl::span<const std::byte> buf) +{ + if (mDebug) { + std::cout << "\n\n============================\nStart of new buffer\n"; + } + size_t bufSize = buf.size(); + size_t pageStart = 0; + while (bufSize > pageStart) { + RDH* rdh = reinterpret_cast<RDH*>(const_cast<std::byte*>(&(buf[pageStart]))); + if (mDebug) { + if (pageStart == 0) { + std::cout << "+++\n[decodeBuffer]" << std::endl; + } else { + std::cout << "---\n[decodeBuffer]" << std::endl; + } + o2::raw::RDHUtils::printRDH(rdh); + } + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + if (rdhHeaderSize != 64) { + break; + } + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + + gsl::span<const std::byte> page(reinterpret_cast<const std::byte*>(rdh), pageSize); + decodePage(page); + + pageStart += pageSize; + } + + if (mDebug) { + std::cout << "[decodeBuffer] mOrbits size: " << mOrbits.size() << std::endl; + dumpOrbits(mOrbits); + std::cout << "[decodeBuffer] mDigits size: " << mDigits.size() << std::endl; + dumpDigits(); + } +} + +//_________________________________________________________________________________________________ + +void DataDecoder::dumpDigits() +{ + for (size_t di = 0; di < mDigits.size(); di++) { + auto& d = mDigits[di]; + auto detID = d.getDetID(); + auto padID = d.getPadID(); + if (padID < 0) { + continue; + } + const Segmentation& segment = segmentation(detID); + bool bend = segment.isBendingPad(padID); + float X = segment.padPositionX(padID); + float Y = segment.padPositionY(padID); + uint32_t orbit = d.getOrbit(); + uint32_t bunchCrossing = d.getBunchCrossing(); + uint32_t sampaTime = d.getSampaTime(); + std::cout << fmt::format(" DE {:4d} PAD {:5d} ADC {:6d} TIME ({} {} {:4d})", + detID, padID, d.getADC(), orbit, bunchCrossing, sampaTime); + std::cout << fmt::format("\tC {} PAD_XY {:+2.2f} , {:+2.2f}", (bend ? (int)0 : (int)1), X, Y); + std::cout << std::endl; + } +}; + +//_________________________________________________________________________________________________ + +void dumpOrbits(const std::unordered_set<OrbitInfo, OrbitInfoHash>& mOrbits) +{ + std::set<OrbitInfo> ordered_orbits(mOrbits.begin(), mOrbits.end()); + for (auto o : ordered_orbits) { + std::cout << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl; + } +}; + +//_________________________________________________________________________________________________ + +bool DataDecoder::getMergerChannelId(const DsElecId& dsElecId, DualSampaChannelId channel, uint32_t& chId, uint32_t& boardId) +{ + static constexpr uint32_t sChannelsInOneDs = 64; + static constexpr uint32_t sDsInOneSolar = 40; + static constexpr uint32_t sChannelsInOneSolar = sChannelsInOneDs * sDsInOneSolar; + auto solarId = dsElecId.solarId(); + uint32_t dsId = static_cast<uint32_t>(dsElecId.elinkGroupId()) * 5 + dsElecId.elinkIndexInGroup(); + if (solarId > DataDecoder::sMaxSolarId || dsId >= 40 || channel >= 64) { + return false; + } + + boardId = solarId * sDsInOneSolar + dsId; + chId = boardId * sChannelsInOneDs + channel; + return true; +} + +//_________________________________________________________________________________________________ + +uint64_t DataDecoder::getMergerChannelBitmask(DualSampaChannelId channel) +{ + uint64_t result{1}; + + if (channel >= 64) { + return 0; + } + + result <<= channel; + + return result; +} + +//_________________________________________________________________________________________________ + +bool DataDecoder::mergeDigits(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, o2::mch::raw::SampaCluster& sc) +{ + static constexpr uint32_t BCROLLOVER = (1 << 20); + static constexpr uint32_t ONEADCCLOCK = 4; + static constexpr uint32_t MAXNOFSAMPLES = 0x3FF; + static constexpr uint32_t TWENTYBITSATONE = 0xFFFFF; + + // only digits that start at the beginning of the SAMPA window can be merged + if (sc.sampaTime != 0) { + return false; + } + + // if there is not previous digit for this channel then no merging is possible + if ((mMergerRecordsReady[mergerBoardId] & mergerChannelBitmask) == 0) { + return false; + } + + auto& mergerCh = mMergerRecords[mergerChannelId]; + + // time stamp of the digits to be merged + uint32_t bcStart = sc.bunchCrossing; + // correct for bunch crossing counter rollover if needed + if (bcStart < mergerCh.bcEnd) { + bcStart += BCROLLOVER; + } + + // if the new digit starts just one ADC clock cycle after the end of the previous, + // the it can be merged into the existing one + if ((bcStart - mergerCh.bcEnd) != ONEADCCLOCK) { + return false; + } + + // add total charge and number of samples to existing digit + auto& digit = mDigits[mergerCh.digitId].digit; + + digit.setADC(digit.getADC() + sc.sum()); + uint32_t newNofSamples = digit.getNofSamples() + sc.nofSamples(); + if (newNofSamples > MAXNOFSAMPLES) { + newNofSamples = MAXNOFSAMPLES; + } + digit.setNofSamples(newNofSamples); + + // update the time stamp of the signal's end + mergerCh.bcEnd = (bcStart & TWENTYBITSATONE) + (sc.nofSamples() - 1) * 4; + + return true; +} + +//_________________________________________________________________________________________________ + +void DataDecoder::updateMergerRecord(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, uint32_t digitId) +{ + auto& mergerCh = mMergerRecords[mergerChannelId]; + auto& digit = mDigits[digitId]; + mergerCh.digitId = digitId; + mergerCh.bcEnd = digit.info.bunchCrossing + (digit.info.sampaTime + digit.digit.getNofSamples() - 1) * 4; + mMergerRecordsReady[mergerBoardId] |= mergerChannelBitmask; +} + +//_________________________________________________________________________________________________ + +bool DataDecoder::getPadMapping(const DsElecId& dsElecId, DualSampaChannelId channel, int& deId, int& dsIddet, int& padId) +{ + deId = -1; + dsIddet = -1; + padId = -1; + + if (auto opt = mElec2Det(dsElecId); opt.has_value()) { + DsDetId dsDetId = opt.value(); + dsIddet = dsDetId.dsId(); + deId = dsDetId.deId(); + } + if (mDebug) { + auto s = asString(dsElecId); + auto ch = fmt::format("{}-CH{:02d}", s, channel); + std::cout << ch << " " + << "deId " << deId << " dsIddet " << dsIddet << std::endl; + } + + if (deId < 0 || dsIddet < 0 || !isValidDeID(deId)) { + LOGP(error, "got invalid DsDetId from dsElecId={}", asString(dsElecId)); + return false; + } + + const Segmentation& segment = segmentation(deId); + padId = segment.findPadByFEE(dsIddet, int(channel)); + + if (padId < 0) { + return false; + } + return true; +} + +//_________________________________________________________________________________________________ + +bool DataDecoder::addDigit(const DsElecId& dsElecId, DualSampaChannelId channel, const o2::mch::raw::SampaCluster& sc) +{ + int deId, dsIddet, padId; + if (!getPadMapping(dsElecId, channel, deId, dsIddet, padId)) { + return false; + } + + uint32_t digitadc = sc.sum(); + + if (mDebug) { + auto s = asString(dsElecId); + auto ch = fmt::format("{}-CH{:02d}", s, channel); + LOG(info) << ch << " " + << fmt::format("PAD ({:04d} {:04d} {:04d})\tADC {:06d} TIME ({} {} {:02d}) SIZE {} END {}", + deId, dsIddet, padId, digitadc, mOrbit, sc.bunchCrossing, sc.sampaTime, sc.nofSamples(), (sc.sampaTime + sc.nofSamples() - 1)) + << (((sc.sampaTime + sc.nofSamples() - 1) >= 98) ? " *" : ""); + } + + // skip channels not associated to any pad + if (padId < 0) { + LOGP(error, "got invalid padId from dsElecId={} dualSampaId={} channel={}", asString(dsElecId), dsIddet, channel); + return false; + } + + RawDigit digit; + digit.digit = o2::mch::Digit(deId, padId, digitadc, 0, sc.nofSamples()); + digit.info.chip = channel / 32; + digit.info.ds = dsElecId.elinkId(); + digit.info.solar = dsElecId.solarId(); + digit.info.sampaTime = sc.sampaTime; + digit.info.bunchCrossing = sc.bunchCrossing; + digit.info.orbit = mOrbit; + + mDigits.emplace_back(digit); + + if (mDebug) { + RawDigit& lastDigit = mDigits.back(); + LOGP(info, "DIGIT STORED: ORBIT {} ADC {} DE {} PADID {} TIME {} BXCOUNT {}", + mOrbit, lastDigit.getADC(), lastDigit.getDetID(), lastDigit.getPadID(), + lastDigit.getSampaTime(), lastDigit.getBunchCrossing()); + } + return true; +} + +uint64_t DataDecoder::getChipId(uint32_t solar, uint32_t ds, uint32_t chip) +{ + return solar * 40 * 2 + ds * 2 + chip; +} + +//_________________________________________________________________________________________________ + +uint32_t DataDecoder::subtractBcOffset(uint32_t bc, uint32_t offset) +{ + int64_t bcTF = static_cast<int64_t>(bc) - offset; + + if (bcTF < 0) { + bcTF += bcRollOver; + } + uint32_t bc20bits = static_cast<uint32_t>(bcTF & twentyBitsAtOne); + + return bc20bits; +} + +//_________________________________________________________________________________________________ + +void DataDecoder::updateTimeFrameStartRecord(uint64_t chipId, uint32_t mFirstOrbitInTF, uint32_t bcTF) +{ + if (chipId < DataDecoder::sReadoutChipsNum) { + mTimeFrameStartRecords[chipId].update(mFirstOrbitInTF, bcTF); + } +} + +//_________________________________________________________________________________________________ + +void DataDecoder::decodePage(gsl::span<const std::byte> page) +{ + uint8_t isStopRDH = 0; + uint32_t orbit; + uint32_t feeId; + uint32_t linkId; + + auto heartBeatHandler = [&](DsElecId dsElecId, uint8_t chip, uint32_t bunchCrossing) { + auto ds = dsElecId.elinkId(); + auto solar = dsElecId.solarId(); + uint64_t chipId = getChipId(solar, ds, chip); + + uint32_t bcTF = subtractBcOffset(bunchCrossing, mSampaTimeOffset); + + updateTimeFrameStartRecord(chipId, mFirstOrbitInTF, bcTF); + + if (mDebug) { + auto s = asString(dsElecId); + LOGP(info, "HeartBeat: {}-CHIP{} -> {}/{} offset {} -> bcTF {}", + s, chip, mFirstOrbitInTF, bunchCrossing, mSampaTimeOffset, bcTF); + } + + if (!mTimeFrameStartRecords[chipId].check()) { + if (mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) { + auto s = asString(dsElecId); + LOGP(warning, "Inconsistent HeartBeat packet received: {}-CHIP{} {}/{} (last {}/{})", + s, chip, mFirstOrbitInTF, bcTF, mTimeFrameStartRecords[chipId].mOrbitPrev, mTimeFrameStartRecords[chipId].mBunchCrossingPrev); + mErrorCount += 1; + } + } + }; + + auto channelHandler = [&](DsElecId dsElecId, DualSampaChannelId channel, + o2::mch::raw::SampaCluster sc) { + if (mChannelHandler) { + mChannelHandler(dsElecId, channel, sc); + } + + if (mDs2manu) { + LOGP(error, "using ds2manu"); + channel = ds2manu(int(channel)); + } + + uint32_t mergerChannelId; + uint32_t mergerBoardId; + if (!getMergerChannelId(dsElecId, channel, mergerChannelId, mergerBoardId)) { + LOGP(error, "dsElecId={} is out-of-bounds", asString(dsElecId)); + return; + } + uint64_t mergerChannelBitmask = getMergerChannelBitmask(channel); + + if (mergeDigits(mergerChannelId, mergerBoardId, mergerChannelBitmask, sc)) { + return; + } + + if (!addDigit(dsElecId, channel, sc)) { + return; + } + + updateMergerRecord(mergerChannelId, mergerBoardId, mergerChannelBitmask, mDigits.size() - 1); + }; + + patchPage(page, mDebug); + + auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(page[0]))); + mOrbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdhAny); + if (mDebug) { + LOGP(info, "[decodeBuffer] mOrbit set to {}", mOrbit); + } + + if (mRdhHandler) { + mRdhHandler(&rdhAny); + } + + // add orbit to vector if not present yet + mOrbits.emplace(page); + + if (!mDecoder) { + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = channelHandler; + handlers.sampaHeartBeatHandler = heartBeatHandler; + mDecoder = mFee2Solar ? o2::mch::raw::createPageDecoder(page, handlers, mFee2Solar) + : o2::mch::raw::createPageDecoder(page, handlers); + } + + mDecoder(page); +}; + +//_________________________________________________________________________________________________ + +int32_t DataDecoder::getDigitTime(uint32_t orbitStart, uint32_t bcStart, uint32_t orbitDigit, uint32_t bcDigit) +{ + // We use the difference of orbits values to estimate the minimum and maximum allowed + // difference in bunch crossings + int64_t dOrbit = static_cast<int64_t>(orbitDigit) - static_cast<int64_t>(orbitStart); + + // Digits might be sent out later than the orbit in which they were recorded. + // We account for this by allowing an extra -3 / +10 orbits when converting the + // difference from orbit numbers to bunch crossings. + int64_t dBcMin = (dOrbit - 10) * bcInOrbit; + int64_t dBcMax = (dOrbit + 3) * bcInOrbit; + + // Difference in bunch crossing values + int64_t dBc = static_cast<int64_t>(bcDigit) - static_cast<int64_t>(bcStart); + + if (dBc < dBcMin) { + // the difference is too small, so we assume that it needs to be + // incremented by one rollover factor + dBc += bcRollOver; + } else if (dBc > dBcMax) { + // the difference is too big, so we assume that it needs to be + // decremented by one rollover factor + dBc -= bcRollOver; + } + + return static_cast<int32_t>(dBc); +} + +//_________________________________________________________________________________________________ + +bool DataDecoder::getTimeFrameStartRecord(const RawDigit& digit, uint32_t& orbitTF, uint32_t& bcTF) +{ + static constexpr uint32_t bcInOrbit = o2::constants::lhc::LHCMaxBunches; + static constexpr uint32_t twentyBitsAtOne = 0xFFFFF; + + // first orbit of the current TF + orbitTF = mFirstOrbitInTF; + + auto& d = digit.digit; + auto& info = digit.info; + + auto chipId = getChipId(info.solar, info.ds, info.chip); + auto& tfStart = mTimeFrameStartRecords[chipId]; + + if (tfStart.mOrbit < 0) { + if (mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) { + LOGP(warning, "Missing TF start record for S{}-J{}-DS{}-CHIP{}", info.solar, info.ds / 5 + 1, info.ds % 5, info.chip); + mErrorCount += 1; + } + return false; + } + + // orbit and BC from the last received HB packet + uint32_t orbitHBP = tfStart.mOrbit; + // SAMPA BC at the beginning of the current TF + bcTF = tfStart.mBunchCrossing; + + if (orbitHBP != orbitTF) { + // we correct the BC from the last received HB packet, if it was recorded from an older TF + bcTF += (orbitTF - orbitHBP) * bcInOrbit; + // only keep 20 bits + bcTF &= twentyBitsAtOne; + + // update the time frame start information for this chip, to speed-up the computations + // in case another digit from the same chip is found in the same time frame. + tfStart.update(orbitTF, bcTF); + } + + return true; +} + +//_________________________________________________________________________________________________ + +void DataDecoder::computeDigitsTime() +{ + static constexpr int32_t timeInvalid = DataDecoder::tfTimeInvalid; + + auto setDigitTime = [&](Digit& d, int32_t tfTime) { + d.setTime(tfTime); + }; + + for (auto& digit : mDigits) { + auto& d = digit.digit; + auto& info = digit.info; + + uint32_t orbitTF; + uint32_t bcTF; + int32_t tfTime = timeInvalid; + + auto orbitDigit = info.orbit; + auto bcDigit = info.getBXTime(); + + if (getTimeFrameStartRecord(digit, orbitTF, bcTF)) { + int solar = info.solar; + int ds = info.ds; + int chip = info.chip; + tfTime = DataDecoder::getDigitTime(orbitTF, bcTF, orbitDigit, bcDigit); + } + + setDigitTime(d, tfTime); + info.tfTime = tfTime; + } +} + +//_________________________________________________________________________________________________ + +static std::string readFileContent(std::string& filename) +{ + std::string content; + std::string s; + std::ifstream in(filename); + while (std::getline(in, s)) { + content += s; + content += "\n"; + } + return content; +}; + +//_________________________________________________________________________________________________ + +void DataDecoder::initElec2DetMapper(std::string filename) +{ + if (filename.empty()) { + if (mUseDummyElecMap) { + LOGP(warning, "[initElec2DetMapper] Using dummy electronic mapping"); + mElec2Det = createElec2DetMapper<ElectronicMapperDummy>(); + } else { + mElec2Det = createElec2DetMapper<ElectronicMapperGenerated>(); + } + } else { + LOGP(info, "[initElec2DetMapper] filename={}", filename); + ElectronicMapperString::sFecMap = readFileContent(filename); + mElec2Det = createElec2DetMapper<ElectronicMapperString>(); + } +}; + +//_________________________________________________________________________________________________ + +void DataDecoder::initFee2SolarMapper(std::string filename) +{ + if (filename.empty()) { + if (mUseDummyElecMap) { + LOGP(warning, "[initFee2SolarMapper] Using dummy electronic mapping"); + mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperDummy>(); + } else { + mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperGenerated>(); + } + } else { + LOGP(info, "[initFee2SolarMapper] filename={}", filename); + ElectronicMapperString::sCruMap = readFileContent(filename); + mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperString>(); + } +}; + +//_________________________________________________________________________________________________ + +void DataDecoder::init() +{ + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + if (refManu2ds_st345[j] != i) { + continue; + } + refDs2manu_st345[i] = j; + break; + } + } + + initFee2SolarMapper(mMapCRUfile); + initElec2DetMapper(mMapFECfile); + + mTimeFrameStartRecords.resize(sReadoutChipsNum); + std::fill(mTimeFrameStartRecords.begin(), mTimeFrameStartRecords.end(), TimeFrameStartRecord()); + + mMergerRecords.resize(sReadoutChannelsNum); + mMergerRecordsReady.resize(sReadoutBoardsNum); + + reset(); +}; + +//_________________________________________________________________________________________________ + +void DataDecoder::reset() +{ + mDigits.clear(); + mOrbits.clear(); + memset(mMergerRecordsReady.data(), 0, sizeof(uint64_t) * mMergerRecordsReady.size()); +} + +} // namespace raw +} // namespace mch +} // end namespace o2 diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/Debug.h b/Detectors/MUON/MCH/Raw/Decoder/src/Debug.h index a7f2940dc2d30..9177d13736ed6 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/Debug.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/Debug.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/OrbitInfo.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/OrbitInfo.cxx index df9f12de6d43d..1ffb082694239 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/OrbitInfo.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/OrbitInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,4 +40,9 @@ bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2) return !(o1 == o2); } +bool operator<(const OrbitInfo& o1, const OrbitInfo& o2) +{ + return (o1.mOrbitInfo < o2.mOrbitInfo); +} + } // namespace o2::mch diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/PageDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/PageDecoder.cxx index 975360cb98e2d..d5a47ab70f6ec 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/PageDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/PageDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,48 +21,46 @@ namespace o2::mch::raw { namespace impl { -uint16_t CRUID_MASK = 0xFF; -uint16_t CHARGESUM_MASK = 0x100; -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION = 0> struct PayloadDecoderImpl { - using type = struct { + using type = struct PayloadDecoderImplReturnType { void process(uint32_t, gsl::span<const std::byte>); }; - type operator()(const FeeLinkId& feeLinkId, SampaChannelHandler sampaChannelHandler, FeeLink2SolarMapper fee2solar); + type operator()(const FeeLinkId& feeLinkId, DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar); }; -template <typename CHARGESUM> -struct PayloadDecoderImpl<UserLogicFormat, CHARGESUM> { - using type = UserLogicEndpointDecoder<CHARGESUM>; +template <typename CHARGESUM, int VERSION> +struct PayloadDecoderImpl<UserLogicFormat, CHARGESUM, VERSION> { + using type = UserLogicEndpointDecoder<CHARGESUM, VERSION>; - type operator()(const FeeLinkId& feeLinkId, SampaChannelHandler sampaChannelHandler, FeeLink2SolarMapper fee2solar) + type operator()(const FeeLinkId& feeLinkId, DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar) { - return std::move(UserLogicEndpointDecoder<CHARGESUM>(feeLinkId.feeId(), fee2solar, sampaChannelHandler)); + return std::move(UserLogicEndpointDecoder<CHARGESUM, VERSION>(feeLinkId.feeId(), fee2solar, decodedDataHandlers)); } }; template <typename CHARGESUM> -struct PayloadDecoderImpl<BareFormat, CHARGESUM> { +struct PayloadDecoderImpl<BareFormat, CHARGESUM, 0> { using type = BareGBTDecoder<CHARGESUM>; - type operator()(const FeeLinkId& feeLinkId, SampaChannelHandler sampaChannelHandler, FeeLink2SolarMapper fee2solar) + type operator()(const FeeLinkId& feeLinkId, DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar) { auto solarId = fee2solar(feeLinkId); if (!solarId.has_value()) { - throw std::logic_error(fmt::format("{} could not get solarId from feelinkid={}\n", __PRETTY_FUNCTION__, feeLinkId)); + throw std::logic_error(fmt::format("{} could not get solarId from feelinkid={}\n", __PRETTY_FUNCTION__, asString(feeLinkId))); } - return std::move(BareGBTDecoder<CHARGESUM>(solarId.value(), sampaChannelHandler)); + return std::move(BareGBTDecoder<CHARGESUM>(solarId.value(), decodedDataHandlers)); } }; -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION = 0> class PageDecoderImpl { public: - PageDecoderImpl(SampaChannelHandler sampaChannelHandler, FeeLink2SolarMapper fee2solar) : mSampaChannelHandler{sampaChannelHandler}, + PageDecoderImpl(DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar) : mDecodedDataHandlers{decodedDataHandlers}, mFee2SolarMapper(fee2solar) { } @@ -75,29 +74,33 @@ class PageDecoderImpl auto feeId = o2::raw::RDHUtils::getFEEID(rdhP); auto linkId = o2::raw::RDHUtils::getLinkID(rdhP); - FeeLinkId feeLinkId(feeId & CRUID_MASK, linkId); + FEEID f{feeId}; + FeeLinkId feeLinkId(f.id, linkId); auto p = mPayloadDecoders.find(feeLinkId); if (p == mPayloadDecoders.end()) { - mPayloadDecoders.emplace(feeLinkId, PayloadDecoderImpl<FORMAT, CHARGESUM>()(feeLinkId, mSampaChannelHandler, mFee2SolarMapper)); + mPayloadDecoders.emplace(feeLinkId, PayloadDecoderImpl<FORMAT, CHARGESUM, VERSION>()(feeLinkId, mDecodedDataHandlers, mFee2SolarMapper)); p = mPayloadDecoders.find(feeLinkId); } uint32_t orbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdhP); auto rdhSize = o2::raw::RDHUtils::getHeaderSize(rdhP); auto payloadSize = o2::raw::RDHUtils::getMemorySize(rdhP) - rdhSize; - p->second.process(orbit, page.subspan(rdhSize, payloadSize)); + // skip empty payloads, otherwise the orbit jumps are not correctly detected + if (payloadSize > 0) { + p->second.process(orbit, page.subspan(rdhSize, payloadSize)); + } } private: - SampaChannelHandler mSampaChannelHandler; + DecodedDataHandlers mDecodedDataHandlers; FeeLink2SolarMapper mFee2SolarMapper; - std::map<FeeLinkId, typename PayloadDecoderImpl<FORMAT, CHARGESUM>::type> mPayloadDecoders; + std::map<FeeLinkId, typename PayloadDecoderImpl<FORMAT, CHARGESUM, VERSION>::type> mPayloadDecoders; }; } // namespace impl -PageDecoder createPageDecoder(RawBuffer rdhBuffer, SampaChannelHandler channelHandler, FeeLink2SolarMapper fee2solar) +PageDecoder createPageDecoder(RawBuffer rdhBuffer, DecodedDataHandlers decodedDataHandlers, FeeLink2SolarMapper fee2solar) { const void* rdhP = reinterpret_cast<const void*>(rdhBuffer.data()); bool ok = o2::raw::RDHUtils::checkRDH(rdhP, true); @@ -106,25 +109,52 @@ PageDecoder createPageDecoder(RawBuffer rdhBuffer, SampaChannelHandler channelHa } auto linkId = o2::raw::RDHUtils::getLinkID(rdhP); auto feeId = o2::raw::RDHUtils::getFEEID(rdhP); + FEEID f{feeId}; if (linkId == 15) { - if (feeId & impl::CHARGESUM_MASK) { - return impl::PageDecoderImpl<UserLogicFormat, ChargeSumMode>(channelHandler, fee2solar); + if (f.ulFormatVersion != 0 && f.ulFormatVersion != 1) { + throw std::logic_error(fmt::format("ulFormatVersion {} is unknown", static_cast<int>(f.ulFormatVersion))); + } + if (f.chargeSum) { + if (f.ulFormatVersion == 0) { + return impl::PageDecoderImpl<UserLogicFormat, ChargeSumMode, 0>(decodedDataHandlers, fee2solar); + } else if (f.ulFormatVersion == 1) { + return impl::PageDecoderImpl<UserLogicFormat, ChargeSumMode, 1>(decodedDataHandlers, fee2solar); + } } else { - return impl::PageDecoderImpl<UserLogicFormat, SampleMode>(channelHandler, fee2solar); + if (f.ulFormatVersion == 0) { + return impl::PageDecoderImpl<UserLogicFormat, SampleMode, 0>(decodedDataHandlers, fee2solar); + } else if (f.ulFormatVersion == 1) { + return impl::PageDecoderImpl<UserLogicFormat, SampleMode, 1>(decodedDataHandlers, fee2solar); + } } } else { - if (feeId & impl::CHARGESUM_MASK) { - return impl::PageDecoderImpl<BareFormat, ChargeSumMode>(channelHandler, fee2solar); + if (f.chargeSum) { + return impl::PageDecoderImpl<BareFormat, ChargeSumMode>(decodedDataHandlers, fee2solar); } else { - return impl::PageDecoderImpl<BareFormat, SampleMode>(channelHandler, fee2solar); + return impl::PageDecoderImpl<BareFormat, SampleMode>(decodedDataHandlers, fee2solar); } } + return nullptr; } -PageDecoder createPageDecoder(RawBuffer rdhBuffer, SampaChannelHandler channelHandler) +PageDecoder createPageDecoder(RawBuffer rdhBuffer, DecodedDataHandlers decodedDataHandlers) { auto fee2solar = createFeeLink2SolarMapper<ElectronicMapperGenerated>(); - return createPageDecoder(rdhBuffer, channelHandler, fee2solar); + return createPageDecoder(rdhBuffer, decodedDataHandlers, fee2solar); +} + +PageDecoder createPageDecoder(RawBuffer rdhBuffer, SampaChannelHandler channelHandler) +{ + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = channelHandler; + return createPageDecoder(rdhBuffer, handlers); +} + +PageDecoder createPageDecoder(RawBuffer rdhBuffer, SampaChannelHandler channelHandler, FeeLink2SolarMapper fee2solar) +{ + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = channelHandler; + return createPageDecoder(rdhBuffer, handlers, fee2solar); } PageParser createPageParser() diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/PayloadDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/PayloadDecoder.h index 1b5adddc542cb..c7f4605feb014 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/PayloadDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/PayloadDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #define O2_MCH_RAW_PAYLOAD_DECODER_H #include "Headers/RAWDataHeader.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include "MCHRawDecoder/PageDecoder.h" #include <map> #include <cstdlib> @@ -38,9 +39,9 @@ class PayloadDecoder { public: /// Constructs a decoder - /// \param channelHandler the handler that will be called for each - /// piece of sampa data (a SampaCluster, i.e. a part of a time window) - PayloadDecoder(SampaChannelHandler channelHandler); + /// \param decodedDataHandlers decodedDataHandlers a structure with various callable objects that + /// will be called for each decoded Sampa packet and in case of decoding errors + PayloadDecoder(DecodedDataHandlers decodedDataHandlers); /// decode the buffer (=payload only) /// \return the number of bytes used from the buffer @@ -48,12 +49,12 @@ class PayloadDecoder private: uint32_t mOrbit; - SampaChannelHandler mChannelHandler; + DecodedDataHandlers mDecodedDataHandlers; }; template <typename T> -PayloadDecoder<T>::PayloadDecoder(SampaChannelHandler channelHandler) - : mChannelHandler(channelHandler) +PayloadDecoder<T>::PayloadDecoder(DecodedDataHandlers decodedDataHandlers) + : mDecodedDataHandlers(decodedDataHandlers) { } diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.cxx index 3481b52754b5b..11a69525ce472 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.h b/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.h index 09963fc2b87fe..6ec2ffb301370 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/RDHManip.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/ROFFinder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/ROFFinder.cxx new file mode 100644 index 0000000000000..556594f3b3d78 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/ROFFinder.cxx @@ -0,0 +1,372 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawDecoder/ROFFinder.h" + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <vector> +#include <map> +#include <algorithm> +#include <numeric> +#include <fmt/format.h> + +#include <fairmq/Tools.h> +#include <FairMQLogger.h> + +#include "MCHMappingInterface/Segmentation.h" +#include "CommonConstants/LHCConstants.h" + +//#define ROFDEBUG 1 + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +using namespace std; + +static constexpr int sBcInOneADCclock = 4; + +//_________________________________________________________________________________________________ +ROFFinder::ROFFinder(const DataDecoder::RawDigitVector& digits, uint32_t firstTForbit) : mInputDigits(digits), mFirstTForbit(firstTForbit) +{ +} + +//_________________________________________________________________________________________________ +ROFFinder::~ROFFinder() = default; + +//_________________________________________________________________________________________________ +void ROFFinder::process(bool dummyROFs) +{ + if (dummyROFs) { + if (!mInputDigits.empty()) { + mOrderedDigits.resize(mInputDigits.size()); + // fill the ordered vector with indexes in ascending order (no time sorting) + std::iota(mOrderedDigits.begin(), mOrderedDigits.end(), 0); + mOutputROFs.emplace_back(digitTime2IR(mInputDigits[0]), 0, mInputDigits.size()); + } + return; + } + + // helper function to check if a given digit index is within the limits of the input vector + auto checkDigitId = [&](RawDigitId id) -> bool { + bool ok = id < mInputDigits.size(); + if (!ok) { + LOG(ERROR) << "Invalid digit ID " << id << " (digits vector size is " << mInputDigits.size() << ")\n"; + } + return ok; + }; + + // helper function to retrieve the digit at a given index + auto getDigit = [&](RawDigitId id) -> const RawDigit& { + return mInputDigits[id]; + }; + + // helper function to initialize the parameters of the next ROF + auto startNewROF = [&](const RawDigit& digit, int id) { + mFirstIdx = id; + mEntries = 1; + mIR = digitTime2IR(digit); + }; + + // fill the time-ordered digit vector + sortDigits(); + + // loop on time-ordered digits, grouping together in one ROF all those whose time stamp + // differs by less than 4 bunch crossings (1 ADC clock cycle) + for (size_t id = 0; id < mOrderedDigits.size(); id++) { + + // index of the current digit in the input vector + RawDigitId inputId = mOrderedDigits[id]; + + // mak sure the index is valid + if (!checkDigitId(inputId)) { + break; + } + // get a reference to the current digit, which marks the beginning of a new ROF + auto& rofSeed = getDigit(inputId); + startNewROF(rofSeed, id); + +#ifdef ROFDEBUG + std::cout << fmt::format("starting new ROF from {} -> {}\n", id, inputId); +#endif + + for (size_t id2 = id + 1; id2 < mOrderedDigits.size(); id2++) { + + // index of the current digit in the input vector + RawDigitId inputId2 = mOrderedDigits[id2]; + + if (!checkDigitId(inputId2)) { + break; + } + auto& digit = getDigit(inputId2); + +#ifdef ROFDEBUG + std::cout << fmt::format(" checking digit {} -> {}\n", id2, inputId2); +#endif + + auto tdiff = digit.getTime() - rofSeed.getTime(); + if (std::abs(tdiff) < sBcInOneADCclock) { + mEntries += 1; +#ifdef ROFDEBUG + std::cout << fmt::format(" digit {} -> {} added to current ROF\n", id2, inputId2); +#endif + } else { + // terminate and store the current ROF and stop the inner loop + storeROF(); + break; + } + } + + // increment the outer loop index by the number of digits added to the ROF in the inner loop + id += mEntries - 1; + } + + // terminate and store the last ROF + storeROF(); +} + +//_________________________________________________________________________________________________ +void ROFFinder::sortDigits() +{ + mOrderedDigits.reserve(mInputDigits.size()); + for (size_t i = 0; i < mInputDigits.size(); i++) { + auto& digit = mInputDigits[i]; + if (!digit.timeValid()) { +#ifdef ROFDEBUG + LOG(ERROR) << "Digit with invalid time, DS " << digit.info.solar << "," << digit.info.ds << "," << digit.info.chip + << " pad " << digit.getDetID() << "," << digit.getPadID() << " " + << digit.getOrbit() << " (" << mFirstTForbit << ") time " + << digit.getTime() << " SAMPA time " << digit.getBXTime(); +#endif + continue; + } + + auto orbit = digit.getOrbit(); + if (orbit < mFirstTForbit) { + LOG(ERROR) << "[ROFFinder::fillDigitsArray] orbit smaller than first TF orbit: " << orbit << ", " << mFirstTForbit; + continue; + } + +#ifdef ROFDEBUG + std::cout << "Inserting digit: " + << "pad " << digit.getDetID() << "," << digit.getPadID() << " " + << digit.getOrbit() << " " << digit.getTime() << " " << digit.getBXTime() << std::endl; +#endif + + mOrderedDigits.emplace_back(i); + } + + auto rawDigitIdComp = [&](const RawDigitId& id1, const RawDigitId& id2) -> bool { + const RawDigit& d1 = mInputDigits[id1]; + const RawDigit& d2 = mInputDigits[id2]; + return (d1 < d2); + }; + std::sort(mOrderedDigits.begin(), mOrderedDigits.end(), rawDigitIdComp); +} + +//_________________________________________________________________________________________________ +o2::InteractionRecord ROFFinder::digitTime2IR(const RawDigit& digit) +{ + constexpr int BCINORBIT = o2::constants::lhc::LHCMaxBunches; + auto time = digit.getTime(); + auto firstOrbit = mFirstTForbit; + + // make sure the interaction record is not initialized with negative BC values + while (time < 0) { + time += BCINORBIT; + firstOrbit -= 1; + } + + uint32_t orbit = digit.getTime() / BCINORBIT + firstOrbit; + int32_t bc = time % BCINORBIT; + return o2::InteractionRecord(bc, orbit); +} + +//_________________________________________________________________________________________________ +void ROFFinder::storeROF() +{ + if (mEntries > 0) { + mOutputROFs.emplace_back(mIR, mFirstIdx, mEntries, sBcInOneADCclock); + } +} + +//_________________________________________________________________________________________________ +char* ROFFinder::saveDigitsToBuffer(size_t& bufSize) +{ + static constexpr size_t sizeOfDigit = sizeof(o2::mch::Digit); + +#ifdef ROFDEBUG + dumpOutputDigits(); +#endif + + bufSize = mOrderedDigits.size() * sizeOfDigit; + o2::mch::Digit* buf = reinterpret_cast<o2::mch::Digit*>(malloc(bufSize)); + if (!buf) { + bufSize = 0; + return nullptr; + } + + o2::mch::Digit* p = buf; + for (auto& id : mOrderedDigits) { + const auto& d = mInputDigits[id]; + memcpy(p, &(d.digit), sizeOfDigit); + p += 1; + } + + return reinterpret_cast<char*>(buf); +} + +//_________________________________________________________________________________________________ +char* ROFFinder::saveROFRsToBuffer(size_t& bufSize) +{ + static constexpr size_t sizeOfROFRecord = sizeof(o2::mch::ROFRecord); + +#ifdef ROFDEBUG + dumpOutputROFs(); +#endif + + bufSize = mOutputROFs.size() * sizeOfROFRecord; + o2::mch::ROFRecord* buf = reinterpret_cast<o2::mch::ROFRecord*>(malloc(bufSize)); + if (!buf) { + bufSize = 0; + return nullptr; + } + + o2::mch::ROFRecord* p = buf; + for (size_t i = 0; i < mOutputROFs.size(); i++) { + auto& rof = mOutputROFs[i]; + memcpy(p, &(rof), sizeOfROFRecord); + p += 1; + } + + return reinterpret_cast<char*>(buf); +} + +//_________________________________________________________________________________________________ +bool ROFFinder::isRofTimeMonotonic() +{ + // number of bunch crossings in one orbit + static const int32_t BCINORBIT = o2::constants::lhc::LHCMaxBunches; + + bool result = true; + for (size_t i = 1; i < mOutputROFs.size(); i++) { + const auto& rof = mOutputROFs[i]; + const auto& rofPrev = mOutputROFs[i - 1]; + int64_t delta = rof.getBCData().differenceInBC(rofPrev.getBCData()); + if (rof.getBCData() < rofPrev.getBCData()) { + LOG(ERROR) << "Non-monotonic ROFs encountered:"; + LOG(ERROR) << fmt::format("ROF1 {}-{} {},{} ", rofPrev.getFirstIdx(), rofPrev.getLastIdx(), + rofPrev.getBCData().orbit, rofPrev.getBCData().bc) + << fmt::format("ROF2 {}-{} {},{}", rof.getFirstIdx(), rof.getLastIdx(), + rof.getBCData().orbit, rof.getBCData().bc); + result = false; + } + if ((delta % 4) != 0) { + LOG(ERROR) << "Mis-aligned ROFs encountered:"; + LOG(ERROR) << fmt::format("ROF1 {}-{} {},{} ", rofPrev.getFirstIdx(), rofPrev.getLastIdx(), + rofPrev.getBCData().orbit, rofPrev.getBCData().bc) + << fmt::format("ROF2 {}-{} {},{}", rof.getFirstIdx(), rof.getLastIdx(), + rof.getBCData().orbit, rof.getBCData().bc); + result = false; + } + } + return result; +} + +//_________________________________________________________________________________________________ +bool ROFFinder::isDigitsTimeAligned() +{ + for (size_t i = 0; i < mOutputROFs.size(); i++) { + auto& rof = mOutputROFs[i]; + for (int j = rof.getFirstIdx() + 1; j <= rof.getLastIdx(); j++) { + auto id = mOrderedDigits[j]; + auto idPrev = mOrderedDigits[j - 1]; + const auto& digit = mInputDigits[id]; + const auto& digitPrev = mInputDigits[idPrev]; + if (digit.getTime() != digitPrev.getTime()) { + LOG(ERROR) << "Mis-aligned digits encountered:"; + LOG(ERROR) << fmt::format("TIME1 {} ", digitPrev.getTime()) << fmt::format("TIME2 {}", digit.getTime()); + return false; + } + } + } + return true; +} + +//_________________________________________________________________________________________________ +std::optional<DataDecoder::RawDigit> ROFFinder::getOrderedDigit(int i) +{ + if (i < 0 || i >= mOrderedDigits.size()) { + return std::nullopt; + } + + auto id = mOrderedDigits[i]; + if (id >= mInputDigits.size()) { + return std::nullopt; + } + + return mInputDigits[id]; +} + +//_________________________________________________________________________________________________ +void ROFFinder::dumpOutputDigits() +{ + std::cout << "OUTPUT DIGITS:\n"; + for (size_t i = 0; i < mOrderedDigits.size(); i++) { + const auto id = mOrderedDigits[i]; + const auto& digit = mInputDigits[id]; + const auto& d = digit.digit; + const auto& t = digit.info; + + if (d.getPadID() < 0) { + continue; + } + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(d.getDetID()); + bool bending = segment.isBendingPad(d.getPadID()); + float X = segment.padPositionX(d.getPadID()); + float Y = segment.padPositionY(d.getPadID()); + uint32_t orbit = t.orbit; + uint32_t bunchCrossing = t.bunchCrossing; + uint32_t sampaTime = t.sampaTime; + auto tfTime = digit.getTime(); + + int iROF = -1; + for (size_t j = 0; j < mOutputROFs.size(); j++) { + const auto& rof = mOutputROFs[j]; + if (rof.getFirstIdx() <= i && rof.getLastIdx() >= i) { + iROF = j; + } + } + std::cout << fmt::format(" DIGIT [{} -> {}] ROF {} DE {:4d} PAD {:5d} ADC {:6d} TIME {} ({} {} {:4d} {})", + i, id, iROF, d.getDetID(), d.getPadID(), d.getADC(), tfTime, orbit, bunchCrossing, sampaTime, t.getBXTime()); + std::cout << fmt::format("\tC {} PAD_XY {:+2.2f} , {:+2.2f}\n", (bending ? (int)0 : (int)1), X, Y); + } +} + +//_________________________________________________________________________________________________ +void ROFFinder::dumpOutputROFs() +{ + std::cout << "OUTPUT ROFs:\n"; + for (size_t i = 0; i < mOutputROFs.size(); i++) { + auto& rof = mOutputROFs[i]; + std::cout << fmt::format(" ROF {} {}-{} {},{}\n", i, rof.getFirstIdx(), rof.getLastIdx(), + rof.getBCData().orbit, rof.getBCData().bc); + } +} + +} // namespace raw +} // namespace mch +} // namespace o2 diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx new file mode 100644 index 0000000000000..86eb5477d1ef7 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "UserLogicElinkDecoder.h" + +namespace o2::mch::raw +{ + +template <> +void UserLogicElinkDecoder<SampleMode>::prepareAndSendCluster() +{ + if (mDecodedDataHandlers.sampaChannelHandler) { + SampaCluster sc(mClusterTime, mSampaHeader.bunchCrossingCounter(), mSamples); + sendCluster(sc); + } + mSamples.clear(); +} + +template <> +void UserLogicElinkDecoder<ChargeSumMode>::prepareAndSendCluster() +{ + if (mSamples.size() != 2) { + throw std::invalid_argument(fmt::format("expected sample size to be 2 but it is {}", mSamples.size())); + } + if (mDecodedDataHandlers.sampaChannelHandler) { + uint32_t q = (((static_cast<uint32_t>(mSamples[1]) & 0x3FF) << 10) | (static_cast<uint32_t>(mSamples[0]) & 0x3FF)); + SampaCluster sc(mClusterTime, mSampaHeader.bunchCrossingCounter(), q, mClusterSize); + sendCluster(sc); + } + mSamples.clear(); +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h index f53dac245abbd..bba31cdaf94a7 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,8 @@ #include "Debug.h" #include "MCHRawCommon/DataFormats.h" #include "MCHRawCommon/SampaHeader.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" +#include "MCHRawDecoder/ErrorCodes.h" #include "MCHRawElecMap/DsElecId.h" #include <bitset> #include <fmt/format.h> @@ -24,6 +26,7 @@ #include <stdexcept> #include <vector> #include <sstream> +#include <set> namespace o2::mch::raw { @@ -32,10 +35,10 @@ template <typename CHARGESUM> class UserLogicElinkDecoder { public: - UserLogicElinkDecoder(DsElecId dsId, SampaChannelHandler sampaChannelHandler); + UserLogicElinkDecoder(DsElecId dsId, DecodedDataHandlers decodedDataHandlers); /// Append 50 bits-worth of data - void append(uint64_t data50, uint8_t error); + void append(uint64_t data50, uint8_t error, bool incomplete); /// Reset our internal state /// i.e. assume the sync has to be found again @@ -57,6 +60,8 @@ class UserLogicElinkDecoder template <typename T> friend std::ostream& operator<<(std::ostream& os, const o2::mch::raw::UserLogicElinkDecoder<T>& e); + const DsElecId& dsId() const { return mDsId; } + void clear(); bool hasError() const; bool isHeaderComplete() const { return mHeaderParts.size() == 5; } @@ -69,6 +74,8 @@ class UserLogicElinkDecoder void oneLess10BitWord(); void prepareAndSendCluster(); void sendCluster(const SampaCluster& sc) const; + void sendHBPacket(); + void sendError(int8_t chip, uint32_t error) const; void setClusterSize(uint10_t value); void setClusterTime(uint10_t value); void setHeaderPart(uint10_t data10); @@ -77,7 +84,7 @@ class UserLogicElinkDecoder private: DsElecId mDsId; - SampaChannelHandler mSampaChannelHandler; + DecodedDataHandlers mDecodedDataHandlers; State mState; std::vector<uint10_t> mSamples{}; std::vector<uint10_t> mHeaderParts{}; @@ -95,23 +102,18 @@ constexpr bool isSync(uint64_t data) return data == sampaSyncWord; }; -constexpr bool isIncomplete(uint8_t error) -{ - return (error & 0x4) > 0; -} - template <typename CHARGESUM> UserLogicElinkDecoder<CHARGESUM>::UserLogicElinkDecoder(DsElecId dsId, - SampaChannelHandler sampaChannelHandler) - : mDsId{dsId}, mSampaChannelHandler{sampaChannelHandler}, mState{State::WaitingSync} + DecodedDataHandlers decodedDataHandlers) + : mDsId{dsId}, mDecodedDataHandlers{decodedDataHandlers}, mState{State::WaitingSync} { } template <typename CHARGESUM> -void UserLogicElinkDecoder<CHARGESUM>::append(uint64_t data50, uint8_t error) +void UserLogicElinkDecoder<CHARGESUM>::append(uint64_t data50, uint8_t error, bool incomplete) { #ifdef ULDEBUG - debugHeader() << (*this) << fmt::format(" --> append50 {:013x} error {} incomplete {} data10={:d} {:d} {:d} {:d} {:d}\n", data50, error, (int)isIncomplete(error), static_cast<uint10_t>(data50 & 0x3FF), static_cast<uint10_t>((data50 & 0xFFC00) >> 10), static_cast<uint10_t>((data50 & 0x3FF00000) >> 20), static_cast<uint10_t>((data50 & 0xFFC0000000) >> 30), static_cast<uint10_t>((data50 & 0x3FF0000000000) >> 40)); + debugHeader() << (*this) << fmt::format(" --> append50 {:013x} error {} incomplete {} data10={:d} {:d} {:d} {:d} {:d}\n", data50, error, incomplete, static_cast<uint10_t>(data50 & 0x3FF), static_cast<uint10_t>((data50 & 0xFFC00) >> 10), static_cast<uint10_t>((data50 & 0x3FF00000) >> 20), static_cast<uint10_t>((data50 & 0xFFC0000000) >> 30), static_cast<uint10_t>((data50 & 0x3FF0000000000) >> 40)); #endif if (isSync(data50)) { @@ -130,8 +132,8 @@ void UserLogicElinkDecoder<CHARGESUM>::append(uint64_t data50, uint8_t error) bool packetEnd = append10(static_cast<uint10_t>(data & 0x3FF)); data >>= 10; #ifdef ULDEBUG - if (isIncomplete(error)) { - debugHeader() << (*this) << fmt::format(" --> incomplete {} packetEnd @i={}\n", (int)isIncomplete(error), packetEnd, i); + if (incomplete) { + debugHeader() << (*this) << fmt::format(" --> incomplete {} packetEnd @i={}\n", incomplete, packetEnd, i); } #endif if (hasError()) { @@ -141,7 +143,7 @@ void UserLogicElinkDecoder<CHARGESUM>::append(uint64_t data50, uint8_t error) reset(); break; } - if (isIncomplete(error) && packetEnd) { + if (incomplete && packetEnd) { #ifdef ULDEBUG debugHeader() << (*this) << " stop due to isIncomplete\n"; #endif @@ -149,10 +151,11 @@ void UserLogicElinkDecoder<CHARGESUM>::append(uint64_t data50, uint8_t error) } } - if (isIncomplete(error) && (i == 5)) { + if (incomplete && (i == 5) && (mState != State::WaitingSync)) { #ifdef ULDEBUG debugHeader() << (*this) << " data packet end not found when isIncomplete --> resetting\n"; #endif + sendError(static_cast<int8_t>(mSampaHeader.chipAddress()), static_cast<uint32_t>(ErrorBadIncompleteWord)); reset(); } } // namespace o2::mch::raw @@ -185,8 +188,15 @@ bool UserLogicElinkDecoder<CHARGESUM>::append10(uint10_t data10) if (isSync(mSampaHeader.uint64())) { reset(); } else if (mSampaHeader.packetType() == SampaPacketType::HeartBeat) { - transition(State::WaitingHeader); - result = true; + if (mSampaHeader.isHeartbeat()) { + sendHBPacket(); + transition(State::WaitingHeader); + result = true; + } else { + mErrorMessage = "badly formatted Heartbeat packet"; + sendError(static_cast<int8_t>(mSampaHeader.chipAddress()), static_cast<uint32_t>(ErrorBadHeartBeatPacket)); + reset(); + } } else { if (mSampaHeader.nof10BitWords() > 2) { transition(State::WaitingSize); @@ -328,10 +338,24 @@ void UserLogicElinkDecoder<CHARGESUM>::sendCluster(const SampaCluster& sc) const debugHeader() << (*this) << " --> " << fmt::format(" calling channelHandler for {} ch {} = {}\n", o2::mch::raw::asString(mDsId), - channelNumber64(mSampaHeader), + getDualSampaChannelId(mSampaHeader), o2::mch::raw::asString(sc)); #endif - mSampaChannelHandler(mDsId, channelNumber64(mSampaHeader), sc); + mDecodedDataHandlers.sampaChannelHandler(mDsId, getDualSampaChannelId(mSampaHeader), sc); +} + +template <typename CHARGESUM> +void UserLogicElinkDecoder<CHARGESUM>::sendError(int8_t chip, uint32_t error) const +{ +#ifdef ULDEBUG + debugHeader() << (*this) << " --> " + << fmt::format(" calling errorHandler for {} chip {} = {}\n", + o2::mch::raw::asString(mDsId), chip, error); +#endif + SampaErrorHandler handler = mDecodedDataHandlers.sampaErrorHandler; + if (handler) { + handler(mDsId, chip, error); + } } template <typename CHARGESUM> @@ -354,9 +378,11 @@ void UserLogicElinkDecoder<CHARGESUM>::setClusterSize(uint10_t value) mErrorMessage = std::nullopt; if (mClusterSize == 0) { mErrorMessage = "cluster size is zero"; + sendError(static_cast<int8_t>(mSampaHeader.chipAddress()), static_cast<uint32_t>(ErrorBadClusterSize)); } if (checkSize > 0) { mErrorMessage = "number of samples bigger than nof10BitWords"; + sendError(static_cast<int8_t>(mSampaHeader.chipAddress()), static_cast<uint32_t>(ErrorBadClusterSize)); } #ifdef ULDEBUG debugHeader() << (*this) << " --> size=" << mClusterSize << " samples=" << mSamplesToRead << "\n"; @@ -398,26 +424,13 @@ void UserLogicElinkDecoder<CHARGESUM>::setSample(uint10_t sample) } } -template <> -void UserLogicElinkDecoder<SampleMode>::prepareAndSendCluster() -{ - if (mSampaChannelHandler) { - SampaCluster sc(mClusterTime, mSampaHeader.bunchCrossingCounter(), mSamples); - sendCluster(sc); - } - mSamples.clear(); -} - -template <> -void UserLogicElinkDecoder<ChargeSumMode>::prepareAndSendCluster() +template <typename CHARGESUM> +void UserLogicElinkDecoder<CHARGESUM>::sendHBPacket() { - if (mSamples.size() != 2) { - throw std::invalid_argument(fmt::format("expected sample size to be 2 but it is {}", mSamples.size())); + SampaHeartBeatHandler handler = mDecodedDataHandlers.sampaHeartBeatHandler; + if (handler) { + handler(mDsId, mSampaHeader.chipAddress() % 2, mSampaHeader.bunchCrossingCounter()); } - uint32_t q = (((static_cast<uint32_t>(mSamples[1]) & 0x3FF) << 10) | (static_cast<uint32_t>(mSamples[0]) & 0x3FF)); - SampaCluster sc(mClusterTime, mSampaHeader.bunchCrossingCounter(), q, mClusterSize); - sendCluster(sc); - mSamples.clear(); } template <typename CHARGESUM> @@ -441,7 +454,7 @@ std::ostream& operator<<(std::ostream& os, const o2::mch::raw::UserLogicElinkDec for (auto s : e.mSamples) { os << fmt::format("{:4d} ", s); } - if (!e.mSampaChannelHandler) { + if (!e.mDecodedDataHandlers.sampaChannelHandler) { os << " empty handler "; } diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicEndpointDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicEndpointDecoder.h index 8eefdf5d3348d..e61007de52691 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicEndpointDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicEndpointDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include <array> #include "UserLogicElinkDecoder.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include <gsl/span> #include <fmt/printf.h> #include <fmt/format.h> @@ -24,11 +25,7 @@ #include "MCHRawElecMap/FeeLinkId.h" #include "PayloadDecoder.h" #include "Debug.h" - -namespace -{ -constexpr uint64_t FIFTYBITSATONE = (static_cast<uint64_t>(1) << 50) - 1; -} +#include "MCHRawCommon/DataFormats.h" namespace o2::mch::raw { @@ -37,8 +34,8 @@ namespace o2::mch::raw /// @brief A UserLogicEndpointDecoder groups 12 x (40 UserLogicElinkDecoder objects) /// -template <typename CHARGESUM> -class UserLogicEndpointDecoder : public PayloadDecoder<UserLogicEndpointDecoder<CHARGESUM>> +template <typename CHARGESUM, int VERSION> +class UserLogicEndpointDecoder : public PayloadDecoder<UserLogicEndpointDecoder<CHARGESUM, VERSION>> { public: using ElinkDecoder = UserLogicElinkDecoder<CHARGESUM>; @@ -48,13 +45,13 @@ class UserLogicEndpointDecoder : public PayloadDecoder<UserLogicEndpointDecoder< /// \param sampaChannelHandler the callable that will handle each SampaCluster UserLogicEndpointDecoder(uint16_t feeId, std::function<std::optional<uint16_t>(FeeLinkId id)> fee2SolarMapper, - SampaChannelHandler sampaChannelHandler); + DecodedDataHandlers decodedDataHandlers); - /** @name Main interface + /** @name Main interface */ ///@{ - /** @brief Append the equivalent n 64-bits words + /** @brief Append the equivalent n 64-bits words * bytes size (=n) must be a multiple of 8 * * @return the number of bytes used in the bytes span @@ -74,7 +71,7 @@ class UserLogicEndpointDecoder : public PayloadDecoder<UserLogicEndpointDecoder< private: uint16_t mFeeId; std::function<std::optional<uint16_t>(FeeLinkId id)> mFee2SolarMapper; - SampaChannelHandler mChannelHandler; + DecodedDataHandlers mDecodedDataHandlers; std::map<uint16_t, std::array<ElinkDecoder, 40>> mElinkDecoders; int mNofGbtWordsSeens; }; @@ -82,20 +79,20 @@ class UserLogicEndpointDecoder : public PayloadDecoder<UserLogicEndpointDecoder< using namespace o2::mch::raw; using namespace boost::multiprecision; -template <typename CHARGESUM> -UserLogicEndpointDecoder<CHARGESUM>::UserLogicEndpointDecoder(uint16_t feeId, - std::function<std::optional<uint16_t>(FeeLinkId id)> fee2SolarMapper, - SampaChannelHandler sampaChannelHandler) - : PayloadDecoder<UserLogicEndpointDecoder<CHARGESUM>>(sampaChannelHandler), +template <typename CHARGESUM, int VERSION> +UserLogicEndpointDecoder<CHARGESUM, VERSION>::UserLogicEndpointDecoder(uint16_t feeId, + std::function<std::optional<uint16_t>(FeeLinkId id)> fee2SolarMapper, + DecodedDataHandlers decodedDataHandlers) + : PayloadDecoder<UserLogicEndpointDecoder<CHARGESUM, VERSION>>(decodedDataHandlers), mFeeId{feeId}, mFee2SolarMapper{fee2SolarMapper}, - mChannelHandler(sampaChannelHandler), + mDecodedDataHandlers(decodedDataHandlers), mNofGbtWordsSeens{0} { } -template <typename CHARGESUM> -size_t UserLogicEndpointDecoder<CHARGESUM>::append(Payload buffer) +template <typename CHARGESUM, int VERSION> +size_t UserLogicEndpointDecoder<CHARGESUM, VERSION>::append(Payload buffer) { if (buffer.size() % 8) { throw std::invalid_argument("buffer size should be a multiple of 8"); @@ -119,11 +116,27 @@ size_t UserLogicEndpointDecoder<CHARGESUM>::append(Payload buffer) continue; } - // Get the GBT link associated to this word - int gbt = (word >> 59) & 0x1F; + ULHeaderWord<VERSION> ulword{word}; + + int gbt = ulword.linkID; - if (gbt < 0 || gbt > 11) { - throw fmt::format("warning : out-of-range gbt {} word={:08X}\n", gbt, word); + // The User Logic uses the condition gbt=15 to identify special control and diagnostics words + // that are generated internally and do not contain data coming from the front-end electronics. + if (gbt == 15) { + // TODO: the exact format of the UL control words is still being defined and tested, + // hence proper decoding will be implemented once the format is finalized. + // For the moment we simply avoid throwing an exception when linkID is equal to 15 + continue; + } else { + if (gbt < 0 || gbt > 11) { + SampaErrorHandler handler = mDecodedDataHandlers.sampaErrorHandler; + if (handler) { + DsElecId dsId{static_cast<uint16_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0)}; + handler(dsId, -1, ErrorBadLinkID); + } else { + throw fmt::format("warning : out-of-range gbt {} word={:08X}\n", gbt, word); + } + } } // Get the corresponding decoders array, or allocate it if does not exist yet @@ -136,33 +149,46 @@ size_t UserLogicEndpointDecoder<CHARGESUM>::append(Payload buffer) auto solarId = mFee2SolarMapper(feeLinkId); if (!solarId.has_value()) { - throw std::logic_error(fmt::format("{} Could not get solarId from feeLinkId={}\n", __PRETTY_FUNCTION__, asString(feeLinkId))); + SampaErrorHandler handler = mDecodedDataHandlers.sampaErrorHandler; + if (handler) { + DsElecId dsId{static_cast<uint16_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0)}; + handler(dsId, -1, ErrorUnknownLinkID); + } else { + throw std::logic_error(fmt::format("{} Could not get solarId from feeLinkId={}\n", __PRETTY_FUNCTION__, asString(feeLinkId))); + } } mElinkDecoders.emplace(static_cast<uint16_t>(gbt), impl::makeArray<40>([=](size_t i) { DsElecId dselec{solarId.value(), static_cast<uint8_t>(i / 5), static_cast<uint8_t>(i % 5)}; - return ElinkDecoder(dselec, mChannelHandler); + return ElinkDecoder(dselec, mDecodedDataHandlers); })); d = mElinkDecoders.find(gbt); } - // in the 14 MSB(Most Significant Bits) 6 are used to specify the Dual Sampa index (0..39) - uint16_t dsid = (word >> 53) & 0x3F; + uint16_t dsid = ulword.dsID; + if (dsid > 39) { + SampaErrorHandler handler = mDecodedDataHandlers.sampaErrorHandler; + if (handler) { + DsElecId dsId{static_cast<uint16_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0)}; + handler(dsId, -1, ErrorBadELinkID); + } else { + throw fmt::format("warning : out-of-range DS ID {} word={:08X}\n", dsid, word); + } + } - // bits 50..52 are error bits - int8_t error = static_cast<uint8_t>((word >> 50) & 0x7); + int8_t error = ulword.error; + bool incomplete = ulword.incomplete > 0; + uint64_t data50 = ulword.data; - // the remaining (LSB) 50 bits represents the actual data to passed to the ElinkDecoder - uint64_t data50 = word & FIFTYBITSATONE; - d->second.at(dsid).append(data50, error); + d->second.at(dsid).append(data50, error, incomplete); n += 8; } return n; } -template <typename CHARGESUM> -void UserLogicEndpointDecoder<CHARGESUM>::reset() +template <typename CHARGESUM, int VERSION> +void UserLogicEndpointDecoder<CHARGESUM, VERSION>::reset() { for (auto& arrays : mElinkDecoders) { for (auto& d : arrays.second) { diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testBareElinkDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testBareElinkDecoder.cxx index e8447c580a14c..bc4632fd5065b 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/testBareElinkDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testBareElinkDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,7 @@ using ::operator<<; SampaChannelHandler handlePacketPrint(std::string_view msg) { - return [msg](DsElecId dsId, uint8_t channel, SampaCluster sc) { + return [msg](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { std::stringstream s; s << dsId; std::cout << fmt::format("{} {} ch={:2d} ", msg, s.str(), channel); @@ -44,12 +45,14 @@ BOOST_AUTO_TEST_CASE(Decoding10) int npackets{0}; auto helper = handlePacketPrint("Decoding10:"); - auto hp = [&npackets, helper](DsElecId dsId, uint8_t channel, SampaCluster sh) { + auto hp = [&npackets, helper](DsElecId dsId, DualSampaChannelId channel, SampaCluster sh) { npackets++; helper(dsId, channel, sh); }; - BareElinkDecoder<SampleMode> e(DsElecId{0, 0, 0}, hp); + DecodedDataHandlers rh; + rh.sampaChannelHandler = hp; + BareElinkDecoder<SampleMode> e(DsElecId{0, 0, 0}, rh); std::string enc("1100100010000000000011110000001010101010101010101011111010011100000000000010000000000000000000000000100000000000101000000010100000010000100100100000000000101000000000000000000000000100000000001001100000100110001010011000111110100110100000000000101100000000000000000000001100000000001000001000100000101010000010011000001001001000010110000000000011111000000000000000000000001000000000110110010011011001101101100101110110011111011001"); @@ -65,12 +68,14 @@ BOOST_AUTO_TEST_CASE(Decoding20) int npackets{0}; auto helper = handlePacketPrint("Decoding20:"); - auto hp = [&npackets, helper](DsElecId dsId, uint8_t channel, SampaCluster sh) { + auto hp = [&npackets, helper](DsElecId dsId, DualSampaChannelId channel, SampaCluster sh) { npackets++; helper(dsId, channel, sh); }; - BareElinkDecoder<ChargeSumMode> e(DsElecId{0, 0, 0}, hp); + DecodedDataHandlers rh; + rh.sampaChannelHandler = hp; + BareElinkDecoder<ChargeSumMode> e(DsElecId{0, 0, 0}, rh); std::string enc("11001000100000000000111100000010101010101010101010110110100100100000000000100000000000000000000000001000000000001010000010100110000000000000010000100100100000000000101000000000000000000000001000000000001001100010011111100000000000000110100100100000000000101100000000000000000000001000000000001000001010000100101000000000110110100100100000000000111110000000000000000000001000000000001101100111011100001100000000"); for (int i = 0; i < enc.size() - 1; i += 2) { @@ -82,7 +87,7 @@ BOOST_AUTO_TEST_CASE(Decoding20) // same thing but with a decoder without a channel handler // so we don't "see" any packet in this case npackets = 0; - BareElinkDecoder<ChargeSumMode> e2(DsElecId{0, 0, 0}, nullptr); + BareElinkDecoder<ChargeSumMode> e2(DsElecId{0, 0, 0}, DecodedDataHandlers{}); for (int i = 0; i < enc.size() - 1; i += 2) { e2.append(enc[i] == 1, enc[i + 1] == 1); } diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testDigitsTimeComputation.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testDigitsTimeComputation.cxx new file mode 100644 index 0000000000000..3cd4c16b4cd44 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testDigitsTimeComputation.cxx @@ -0,0 +1,160 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHRaw DigitsTimeComputation +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "MCHRawDecoder/DataDecoder.h" + +using namespace o2::mch::raw; + +BOOST_AUTO_TEST_SUITE(o2_mch_raw) + +BOOST_AUTO_TEST_SUITE(digitstimecomputation) + +static const int32_t BCINORBIT = 3564; +static const int32_t BCROLLOVER = (1 << 20); +using RawDigit = DataDecoder::RawDigit; + +BOOST_AUTO_TEST_CASE(TimeDiffSameOrbitNoRollover) +{ + uint32_t orbit1 = 1; + uint32_t orbit2 = 1; + uint32_t bc1 = 0; + uint32_t bc2 = BCINORBIT - 10; + auto diff = DataDecoder::getDigitTime(orbit1, bc1, orbit2, bc2); + BOOST_CHECK_EQUAL(diff, bc2); +} + +BOOST_AUTO_TEST_CASE(TimeDiffSameOrbitWithRollover) +{ + uint32_t orbit1 = 1; + uint32_t orbit2 = 1; + uint32_t bc1 = BCROLLOVER - 10; + uint32_t bc2 = 10; + auto diff = DataDecoder::getDigitTime(orbit1, bc1, orbit2, bc2); + BOOST_CHECK_EQUAL(diff, 20); +} + +BOOST_AUTO_TEST_CASE(TimeDiffSameOrbitWithRollover2) +{ + uint32_t orbit1 = 1; + uint32_t orbit2 = 1; + uint32_t bc1 = 10; + uint32_t bc2 = BCROLLOVER - 10; + auto diff = DataDecoder::getDigitTime(orbit1, bc1, orbit2, bc2); + BOOST_CHECK_EQUAL(diff, -20); +} + +static std::vector<RawDigit> makeDigitsVector(uint32_t sampaTime, uint32_t bunchCrossing, uint32_t orbit) +{ + RawDigit digit; + digit.digit = o2::mch::Digit(100, 10, 1000, 0x7FFFFFFF, 10); + digit.info.chip = 1; + digit.info.ds = 2; + digit.info.solar = 80; + digit.info.sampaTime = sampaTime; + digit.info.bunchCrossing = bunchCrossing; + digit.info.orbit = orbit; + + std::vector<RawDigit> digits; + digits.push_back(digit); + return digits; +} + +static std::vector<RawDigit> processDigits(const std::vector<RawDigit>& digits, uint32_t tfOrbit, uint32_t tfBunchCrossing) +{ + SampaChannelHandler channelHandler; + RdhHandler rdhHandler; + + bool ds2manu = false; + uint32_t sampaBcOffset = 0; + bool mDebug = true; + bool mCheckROFs = false; + bool mDummyROFs = true; + bool useDummyElecMap = false; + DataDecoder decoder{channelHandler, rdhHandler, sampaBcOffset, "", "", ds2manu, mDebug, useDummyElecMap}; + + decoder.setFirstOrbitInTF(tfOrbit); + decoder.setDigits(digits); + + for (auto& digit : digits) { + auto& info = digit.info; + auto chipId = DataDecoder::getChipId(info.solar, info.ds, info.chip); + decoder.updateTimeFrameStartRecord(chipId, tfOrbit, tfBunchCrossing); + } + decoder.computeDigitsTime(); + + auto& digitsOut = decoder.getDigits(); + return digitsOut; +} + +BOOST_AUTO_TEST_CASE(ComputeDigitsTime) +{ + uint32_t sampaTime = 10; + uint32_t bunchCrossing = BCINORBIT - 100; + uint32_t orbit = 1; + + std::vector<RawDigit> digits = makeDigitsVector(sampaTime, bunchCrossing, orbit); + + uint32_t tfOrbit = 1; + uint32_t tfBunchCrossing = 0; + + auto digitsOut = processDigits(digits, tfOrbit, tfBunchCrossing); + + int32_t digitTime = static_cast<int32_t>(bunchCrossing) + static_cast<int32_t>(sampaTime * 4) - + static_cast<int32_t>(tfBunchCrossing); + + BOOST_CHECK_EQUAL(digitsOut[0].getTime(), digitTime); +} + +BOOST_AUTO_TEST_CASE(ComputeDigitsTimeWithRollover) +{ + uint32_t sampaTime = 10; + uint32_t bunchCrossing = 100; + uint32_t orbit = 1; + + std::vector<RawDigit> digits = makeDigitsVector(sampaTime, bunchCrossing, orbit); + + uint32_t tfOrbit = 1; + uint32_t tfBunchCrossing = BCROLLOVER - 100; + + auto digitsOut = processDigits(digits, tfOrbit, tfBunchCrossing); + + int32_t digitTime = static_cast<int32_t>(bunchCrossing) + static_cast<int32_t>(sampaTime * 4) - + static_cast<int32_t>(tfBunchCrossing) + BCROLLOVER; + + BOOST_CHECK_EQUAL(digitsOut[0].getTime(), digitTime); +} + +BOOST_AUTO_TEST_CASE(ComputeDigitsTimeWithRollover2) +{ + uint32_t sampaTime = 10; + uint32_t bunchCrossing = BCROLLOVER - 100; + uint32_t orbit = 1; + + std::vector<RawDigit> digits = makeDigitsVector(sampaTime, bunchCrossing, orbit); + + uint32_t tfOrbit = 1; + uint32_t tfBunchCrossing = 100; + + auto digitsOut = processDigits(digits, tfOrbit, tfBunchCrossing); + + int32_t digitTime = static_cast<int32_t>(bunchCrossing) + static_cast<int32_t>(sampaTime * 4) - + static_cast<int32_t>(tfBunchCrossing) - BCROLLOVER; + + BOOST_CHECK_EQUAL(digitsOut[0].getTime(), digitTime); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testRDHManip.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testRDHManip.cxx index 34ce4ce93a299..abcd32d9d8be0 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/testRDHManip.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testRDHManip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testROFFinder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testROFFinder.cxx new file mode 100644 index 0000000000000..bd95b5be1e2ae --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testROFFinder.cxx @@ -0,0 +1,223 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHRaw ROFFinder +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "MCHRawDecoder/ROFFinder.h" + +using namespace o2::mch::raw; + +BOOST_AUTO_TEST_SUITE(o2_mch_raw) + +BOOST_AUTO_TEST_SUITE(roffinder) + +static const int32_t BCINORBIT = 3564; +static const int32_t BCROLLOVER = (1 << 20); +using RawDigit = DataDecoder::RawDigit; +using RawDigitVector = DataDecoder::RawDigitVector; + +static RawDigit makeDigit(int ds, uint32_t tfTime, uint32_t orbit) +{ + RawDigit digit; + digit.digit = o2::mch::Digit(100, 10, 1000, 0x7FFFFFFF, 10); + digit.info.chip = 1; + digit.info.ds = ds; + digit.info.solar = 80; + digit.info.tfTime = tfTime; + digit.info.orbit = orbit; + digit.info.sampaTime = 0; + digit.info.bunchCrossing = 0; + + return digit; +} + +static RawDigitVector makeDigitsVector(uint32_t tfTime1, uint32_t orbit1, uint32_t tfTime2, uint32_t orbit2) +{ + RawDigit digit1 = makeDigit(1, tfTime1, orbit1); + RawDigit digit2 = makeDigit(2, tfTime2, orbit2); + + RawDigitVector digits; + digits.push_back(digit1); + digits.push_back(digit2); + return digits; +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoDigitsInOneROF) +{ + uint32_t tfTime1 = 100; + uint32_t orbit1 = 1; + uint32_t tfTime2 = tfTime1; + uint32_t orbit2 = orbit1; + + auto digits = makeDigitsVector(tfTime1, orbit1, tfTime2, orbit2); + + ROFFinder rofFinder(digits, orbit1); + rofFinder.process(); + + const auto& rofDigits = rofFinder.getOrderedDigits(); + const auto& rofRecords = rofFinder.getROFRecords(); + + BOOST_CHECK_EQUAL(rofDigits.size(), 2); + BOOST_CHECK_EQUAL(rofRecords.size(), 1); + + BOOST_CHECK_EQUAL(rofRecords[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofRecords[0].getNEntries(), 2); + + BOOST_CHECK_EQUAL(rofRecords[0].getBCData(), rofFinder.digitTime2IR(digits[0])); + BOOST_CHECK_EQUAL(rofRecords[0].getBCWidth(), 4); + + BOOST_CHECK_EQUAL(rofFinder.isDigitsTimeAligned(), true); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoDigitsInOneROFUnaligned) +{ + uint32_t tfTime1 = 100; + uint32_t orbit1 = 1; + uint32_t tfTime2 = tfTime1 + 1; + uint32_t orbit2 = orbit1; + + auto digits = makeDigitsVector(tfTime1, orbit1, tfTime2, orbit2); + + ROFFinder rofFinder(digits, orbit1); + rofFinder.process(); + + const auto& rofDigits = rofFinder.getOrderedDigits(); + const auto& rofRecords = rofFinder.getROFRecords(); + + BOOST_CHECK_EQUAL(rofDigits.size(), 2); + BOOST_CHECK_EQUAL(rofRecords.size(), 1); + + BOOST_CHECK_EQUAL(rofRecords[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofRecords[0].getNEntries(), 2); + + BOOST_CHECK_EQUAL(rofRecords[0].getBCData(), rofFinder.digitTime2IR(digits[0])); + BOOST_CHECK_EQUAL(rofRecords[0].getBCWidth(), 4); + + BOOST_CHECK_EQUAL(rofFinder.isDigitsTimeAligned(), false); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoDigitsInOneROFsConsecutiveOrbits) +{ + uint32_t tfTime1 = 100; + uint32_t orbit1 = 1; + uint32_t tfTime2 = tfTime1; + uint32_t orbit2 = orbit1 + 1; + + auto digits = makeDigitsVector(tfTime1, orbit1, tfTime2, orbit2); + + ROFFinder rofFinder(digits, orbit1); + rofFinder.process(); + + const auto& rofDigits = rofFinder.getOrderedDigits(); + const auto& rofRecords = rofFinder.getROFRecords(); + + BOOST_CHECK_EQUAL(rofDigits.size(), 2); + BOOST_CHECK_EQUAL(rofRecords.size(), 1); + + BOOST_CHECK_EQUAL(rofRecords[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofRecords[0].getNEntries(), 2); + + BOOST_CHECK_EQUAL(rofRecords[0].getBCData(), rofFinder.digitTime2IR(digits[0])); + BOOST_CHECK_EQUAL(rofRecords[0].getBCWidth(), 4); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoDigitsInTwoROFs) +{ + uint32_t tfTime1 = 100; + uint32_t orbit1 = 1; + uint32_t tfTime2 = tfTime1 + 4; + uint32_t orbit2 = orbit1; + + auto digits = makeDigitsVector(tfTime1, orbit1, tfTime2, orbit2); + + ROFFinder rofFinder(digits, orbit1); + rofFinder.process(); + + const auto& rofDigits = rofFinder.getOrderedDigits(); + const auto& rofRecords = rofFinder.getROFRecords(); + + BOOST_CHECK_EQUAL(rofDigits.size(), 2); + BOOST_CHECK_EQUAL(rofRecords.size(), 2); + + BOOST_CHECK_EQUAL(rofRecords[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofRecords[0].getNEntries(), 1); + BOOST_CHECK_EQUAL(rofRecords[0].getBCData(), rofFinder.digitTime2IR(digits[0])); + BOOST_CHECK_EQUAL(rofRecords[0].getBCWidth(), 4); + + BOOST_CHECK_EQUAL(rofRecords[1].getFirstIdx(), 1); + BOOST_CHECK_EQUAL(rofRecords[1].getNEntries(), 1); + BOOST_CHECK_EQUAL(rofRecords[1].getBCData(), rofFinder.digitTime2IR(digits[1])); + BOOST_CHECK_EQUAL(rofRecords[1].getBCWidth(), 4); + + const auto rofDigit1 = rofFinder.getOrderedDigit(rofRecords[0].getFirstIdx()); + const auto rofDigit2 = rofFinder.getOrderedDigit(rofRecords[1].getFirstIdx()); + + BOOST_CHECK_EQUAL(rofDigit1.has_value(), true); + BOOST_CHECK_EQUAL(rofDigit2.has_value(), true); + + BOOST_CHECK_EQUAL(digits[0], rofDigit1.value()); + BOOST_CHECK_EQUAL(digits[1], rofDigit2.value()); + + BOOST_CHECK_EQUAL(rofFinder.isRofTimeMonotonic(), true); + BOOST_CHECK_EQUAL(rofFinder.isDigitsTimeAligned(), true); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoDigitsInTwoROFsConsecutiveOrbits) +{ + uint32_t tfTime1 = 100; + uint32_t orbit1 = 1; + uint32_t tfTime2 = tfTime1 - 4; + uint32_t orbit2 = orbit1 + 1; + + auto digits = makeDigitsVector(tfTime1, orbit1, tfTime2, orbit2); + + ROFFinder rofFinder(digits, orbit1); + rofFinder.process(); + + const auto& rofDigits = rofFinder.getOrderedDigits(); + const auto& rofRecords = rofFinder.getROFRecords(); + + BOOST_CHECK_EQUAL(rofDigits.size(), 2); + BOOST_CHECK_EQUAL(rofRecords.size(), 2); + + BOOST_CHECK_EQUAL(rofRecords[0].getFirstIdx(), 0); + BOOST_CHECK_EQUAL(rofRecords[0].getNEntries(), 1); + BOOST_CHECK_EQUAL(rofRecords[0].getBCData(), rofFinder.digitTime2IR(digits[1])); + BOOST_CHECK_EQUAL(rofRecords[0].getBCWidth(), 4); + + BOOST_CHECK_EQUAL(rofRecords[1].getFirstIdx(), 1); + BOOST_CHECK_EQUAL(rofRecords[1].getNEntries(), 1); + BOOST_CHECK_EQUAL(rofRecords[1].getBCData(), rofFinder.digitTime2IR(digits[0])); + BOOST_CHECK_EQUAL(rofRecords[1].getBCWidth(), 4); + + const auto rofDigit1 = rofFinder.getOrderedDigit(rofRecords[0].getFirstIdx()); + const auto rofDigit2 = rofFinder.getOrderedDigit(rofRecords[1].getFirstIdx()); + + BOOST_CHECK_EQUAL(rofDigit1.has_value(), true); + BOOST_CHECK_EQUAL(rofDigit2.has_value(), true); + + BOOST_CHECK_EQUAL(digits[1], rofDigit1.value()); + BOOST_CHECK_EQUAL(digits[0], rofDigit2.value()); + + BOOST_CHECK_EQUAL(rofFinder.isRofTimeMonotonic(), true); + BOOST_CHECK_EQUAL(rofFinder.isDigitsTimeAligned(), true); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx index 80e3e60cf0117..750808aaeb5c7 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include "MCHRawCommon/DataFormats.h" #include "MCHRawCommon/SampaHeader.h" #include "MCHRawDecoder/PageDecoder.h" -#include "MCHRawDecoder/SampaChannelHandler.h" +#include "MCHRawDecoder/DecodedDataHandlers.h" #include "MCHRawEncoderPayload/DataBlock.h" #include "MCHRawEncoderPayload/PayloadEncoder.h" #include "MoveBuffer.h" @@ -31,13 +32,83 @@ #include <fmt/printf.h> #include <fstream> #include <iostream> +#include <boost/test/data/test_case.hpp> +#include <boost/mpl/list.hpp> using namespace o2::mch::raw; -using o2::header::RAWDataHeaderV4; +namespace bdata = boost::unit_test::data; + +const uint64_t CruPageOK[] = { + 0x00000A0000124006ul, + 0x000C4C0F00A000A0ul, + 0x010E853D00000570ul, + 0x0000000000000000ul, + 0x0000000000006000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x3F04ECA103E5Cul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x0000040215C0Dul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x00000C0301004ul, + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x0000000000400ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1F080CA100E4Dul, + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x00044C0100001ul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul}; + +const uint64_t CruPageBadClusterSize[] = { + 0x00000A0000124006ul, + 0x000C4C0F00A000A0ul, + 0x010E853D00000570ul, + 0x0000000000000000ul, + 0x0000000000006000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x3F04ECA103E5Cul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x0000040215C0Eul, // <== the cluster size is increased from 13 (0xD) to 14 (0xE) + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x00000C0301004ul, // now the cluster size does not match anymore with the + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x0000000000400ul, // number of 10-bit words in the SAMPA header, which will trigger + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, // a ErrorBadClusterSize error. + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1F080CA100E4Dul, + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x00044C0100001ul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul}; + +const uint64_t CruPageBadN10bitWords[] = { + 0x00000A0000124006ul, + 0x000C4C0F00A000A0ul, + 0x010E853D00000570ul, + 0x0000000000000000ul, + 0x0000000000006000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + 0x0000000000000000ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x3F04ECA103E5Cul, + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x0000040215C08ul, // <== the cluster size is decreased from 13 (0xD) to 8 (0x8) + //((0x0200ul<<50)&0xFFFC000000000000ul) + 0x00000C0301004ul, // and one 50-bit word is removed. In this case the cluster + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x0000000000400ul, // size matches the number of samples in the data, but the + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1555540F00113ul, // end of the SAMPA packet arrives too early with respect to + ((0x0200ul << 50) & 0xFFFC000000000000ul) + 0x1F080CA100E4Dul, // the number of 10-bit words in the SAMPA header. This will + ((0x0204ul << 50) & 0xFFFC000000000000ul) + 0x00044C0100001ul, // trigger a ErrorBadIncompleteWord error. + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul, // <== a word is added at the end in order to match the + ((0x3FBBul << 50) & 0xFFFC000000000000ul) + 0x1DEEDFEEDDEEDul // payload size in the RDH +}; SampaChannelHandler handlePacket(std::string& result) { - return [&result](DsElecId dsId, uint8_t channel, SampaCluster sc) { + return [&result](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { result += fmt::format("{}-ch-{}-ts-{}-q", asString(dsId), channel, sc.sampaTime); if (sc.isClusterSum()) { result += fmt::format("-{}-cs-{}", sc.chargeSum, sc.clusterSize); @@ -50,6 +121,14 @@ SampaChannelHandler handlePacket(std::string& result) }; } +SampaErrorHandler handleError(std::string& result) +{ + return [&result](DsElecId dsId, int8_t chip, uint32_t error) { + result += fmt::format("{}-chip-{}-error-{}", asString(dsId), chip, error); + result += "\n"; + }; +} + std::vector<std::byte> convertBuffer2PayloadBuffer(gsl::span<const std::byte> buffer, std::optional<size_t> insertSync = std::nullopt) { @@ -76,39 +155,41 @@ std::vector<std::byte> convertBuffer2PayloadBuffer(gsl::span<const std::byte> bu b64.insert(b64.begin() + insertSync.value(), prefix | sampaSyncWord); } - impl::dumpBuffer<o2::mch::raw::UserLogicFormat>(b64); - // get back to byte buffer to return std::vector<std::byte> bytes; impl::copyBuffer(b64, bytes); return bytes; } -template <typename CHARGESUM> +template <typename CHARGESUM, int VERSION> std::string decodeBuffer(int feeId, gsl::span<const std::byte> buffer) { std::string results; auto fee2solar = createFeeLink2SolarMapper<ElectronicMapperGenerated>(); - UserLogicEndpointDecoder<CHARGESUM> dec(feeId, fee2solar, handlePacket(results)); + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = handlePacket(results); + handlers.sampaErrorHandler = handleError(results); + UserLogicEndpointDecoder<CHARGESUM, VERSION> dec(feeId, fee2solar, handlers); dec.append(buffer); return results; } -template <typename CHARGESUM> +template <typename CHARGESUM, int VERSION> std::string testPayloadDecode(DsElecId ds1, - int ch1, + DualSampaChannelId ch1, const std::vector<SampaCluster>& clustersFirstChannel, DsElecId ds2 = DsElecId{0, 0, 0}, - int ch2 = 47, + DualSampaChannelId ch2 = 47, const std::vector<SampaCluster>& clustersSecondChannel = {}, std::optional<size_t> insertSync = std::nullopt) { - auto encoder = createPayloadEncoder<UserLogicFormat, CHARGESUM, true>(); - - encoder->startHeartbeatFrame(0, 0); auto solar2feelink = createSolar2FeeLinkMapper<ElectronicMapperGenerated>(); + auto encoder = createPayloadEncoder(solar2feelink, true, VERSION, isChargeSumMode<CHARGESUM>::value); + + encoder->startHeartbeatFrame(0, 0); + uint16_t feeId{0}; auto f1 = solar2feelink(ds1.solarId()); @@ -136,71 +217,135 @@ std::string testPayloadDecode(DsElecId ds1, encoder->moveToBuffer(buffer); auto payloadBuffer = convertBuffer2PayloadBuffer(buffer, insertSync); - return decodeBuffer<CHARGESUM>(feeId, payloadBuffer); + return decodeBuffer<CHARGESUM, VERSION>(feeId, payloadBuffer); +} + +template <int VERSION> +std::vector<uint64_t> convert(gsl::span<const uint64_t> page); + +template <> +std::vector<uint64_t> convert<0>(gsl::span<const uint64_t> page) +{ + return {page.begin(), page.end()}; +} + +template <> +std::vector<uint64_t> convert<1>(gsl::span<const uint64_t> page) +{ + // convert the 14 MSB bits of page, expressed using V0 spec, + // to match the V1 spec + std::vector<uint64_t> pagev1{page.begin(), page.end()}; + constexpr int rdhSize{8}; + for (int i = rdhSize; i < pagev1.size(); i++) { + if (pagev1[i] == 0xFEEDDEEDFEEDDEED || pagev1[i] == 0) { + // do not mess with padding words + continue; + } + ULHeaderWord<0> v0{pagev1[i]}; + ULHeaderWord<1> v1; + v1.data = v0.data; + v1.error = v0.error; + v1.incomplete = v0.incomplete; + v1.dsID = v0.dsID; + v1.linkID = v0.linkID; + pagev1[i] = v1.word; + } + return pagev1; +} + +template <int VERSION = 0> +std::string testPayloadDecodeCruPages(gsl::span<const uint64_t> ipage) +{ + std::vector<uint64_t> page = convert<VERSION>(ipage); + + const void* rdhP = reinterpret_cast<const void*>(page.data()); + uint16_t feeId = o2::raw::RDHUtils::getFEEID(rdhP); + auto rdhSize = o2::raw::RDHUtils::getHeaderSize(rdhP); + auto payloadSize = o2::raw::RDHUtils::getMemorySize(rdhP) - rdhSize; + + gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(page.data()), page.size() * 8); + gsl::span<const std::byte> payloadBuffer = buffer.subspan(rdhSize, payloadSize); + + o2::mch::raw::FEEID f{feeId}; + + if (f.chargeSum) { + return decodeBuffer<ChargeSumMode, VERSION>(f.id, payloadBuffer); + } else { + return decodeBuffer<SampleMode, VERSION>(f.id, payloadBuffer); + } } +struct V0 { + static constexpr int value = 0; +}; +struct V1 { + static constexpr int value = 1; +}; + +typedef boost::mpl::list<V0, V1> testTypes; + BOOST_AUTO_TEST_SUITE(o2_mch_raw) BOOST_AUTO_TEST_SUITE(userlogicdsdecoder) -BOOST_AUTO_TEST_CASE(SampleModeSimplest) +BOOST_AUTO_TEST_CASE_TEMPLATE(SampleModeSimplest, V, testTypes) { // only one channel with one very small cluster // fitting within one 64-bits word SampaCluster cl(345, 6789, {123, 456}); - auto r = testPayloadDecode<SampleMode>(DsElecId{728, 1, 0}, 63, {cl}); + auto r = testPayloadDecode<SampleMode, V::value>(DsElecId{728, 1, 0}, 63, {cl}); BOOST_CHECK_EQUAL(r, "S728-J1-DS0-ch-63-ts-345-q-123-456\n"); } -BOOST_AUTO_TEST_CASE(SampleModeSimple) +BOOST_AUTO_TEST_CASE_TEMPLATE(SampleModeSimple, V, testTypes) { // only one channel with one cluster, but the cluster // spans 2 64-bits words. SampaCluster cl(345, 6789, {123, 456, 789, 901, 902}); - auto r = testPayloadDecode<SampleMode>(DsElecId{448, 6, 4}, 63, {cl}); + auto r = testPayloadDecode<SampleMode, V::value>(DsElecId{448, 6, 4}, 63, {cl}); BOOST_CHECK_EQUAL(r, "S448-J6-DS4-ch-63-ts-345-q-123-456-789-901-902\n"); } -BOOST_AUTO_TEST_CASE(SampleModeTwoChannels) +BOOST_AUTO_TEST_CASE_TEMPLATE(SampleModeTwoChannels, V, testTypes) { // 2 channels with one cluster SampaCluster cl(345, 6789, {123, 456, 789, 901, 902}); SampaCluster cl2(346, 6789, {1001, 1002, 1003, 1004, 1005, 1006, 1007}); - auto r = testPayloadDecode<SampleMode>(DsElecId{361, 6, 2}, 63, {cl}, DsElecId{361, 6, 2}, 47, {cl2}); + auto r = testPayloadDecode<SampleMode, V::value>(DsElecId{361, 6, 2}, 63, {cl}, DsElecId{361, 6, 2}, 47, {cl2}); BOOST_CHECK_EQUAL(r, "S361-J6-DS2-ch-63-ts-345-q-123-456-789-901-902\n" "S361-J6-DS2-ch-47-ts-346-q-1001-1002-1003-1004-1005-1006-1007\n"); } -BOOST_AUTO_TEST_CASE(ChargeSumModeSimplest) +BOOST_AUTO_TEST_CASE_TEMPLATE(ChargeSumModeSimplest, V, testTypes) { // only one channel with one cluster // (hence fitting within one 64 bits word) SampaCluster cl(345, 6789, 123456, 789); - auto r = testPayloadDecode<ChargeSumMode>(DsElecId{728, 1, 0}, 63, {cl}); + auto r = testPayloadDecode<ChargeSumMode, V::value>(DsElecId{728, 1, 0}, 63, {cl}); BOOST_CHECK_EQUAL(r, "S728-J1-DS0-ch-63-ts-345-q-123456-cs-789\n"); } -BOOST_AUTO_TEST_CASE(ChargeSumModeSimple) +BOOST_AUTO_TEST_CASE_TEMPLATE(ChargeSumModeSimple, V, testTypes) { // only one channel with 2 clusters // (hence spanning 2 64-bits words) SampaCluster cl1(345, 6789, 123456, 789); SampaCluster cl2(346, 6789, 789012, 345); - auto r = testPayloadDecode<ChargeSumMode>(DsElecId{448, 6, 4}, 63, {cl1, cl2}); + auto r = testPayloadDecode<ChargeSumMode, V::value>(DsElecId{448, 6, 4}, 63, {cl1, cl2}); BOOST_CHECK_EQUAL(r, "S448-J6-DS4-ch-63-ts-345-q-123456-cs-789\n" "S448-J6-DS4-ch-63-ts-346-q-789012-cs-345\n"); } -BOOST_AUTO_TEST_CASE(ChargeSumModeTwoChannels) +BOOST_AUTO_TEST_CASE_TEMPLATE(ChargeSumModeTwoChannels, V, testTypes) { // two channels with 2 clusters SampaCluster cl1(345, 6789, 123456, 789); SampaCluster cl2(346, 6789, 789012, 345); SampaCluster cl3(347, 6789, 1357, 890); SampaCluster cl4(348, 6789, 7912, 345); - auto r = testPayloadDecode<ChargeSumMode>(DsElecId{361, 6, 2}, 63, {cl1, cl2}, DsElecId{361, 6, 2}, 47, {cl3, cl4}); + auto r = testPayloadDecode<ChargeSumMode, V::value>(DsElecId{361, 6, 2}, 63, {cl1, cl2}, DsElecId{361, 6, 2}, 47, {cl3, cl4}); BOOST_CHECK_EQUAL(r, "S361-J6-DS2-ch-63-ts-345-q-123456-cs-789\n" "S361-J6-DS2-ch-63-ts-346-q-789012-cs-345\n" @@ -208,7 +353,7 @@ BOOST_AUTO_TEST_CASE(ChargeSumModeTwoChannels) "S361-J6-DS2-ch-47-ts-348-q-7912-cs-345\n"); } -BOOST_AUTO_TEST_CASE(SyncInTheMiddleChargeSumModeTwoChannels) +BOOST_AUTO_TEST_CASE_TEMPLATE(SyncInTheMiddleChargeSumModeTwoChannels, V, testTypes) { // Insert a sync word in the middle of // the TwoChannels case and check the decoder is handling this fine @@ -218,7 +363,7 @@ BOOST_AUTO_TEST_CASE(SyncInTheMiddleChargeSumModeTwoChannels) SampaCluster cl2(346, 6789, 789012, 345); SampaCluster cl3(347, 6789, 1357, 890); SampaCluster cl4(348, 6789, 7912, 345); - auto r = testPayloadDecode<ChargeSumMode>( + auto r = testPayloadDecode<ChargeSumMode, V::value>( DsElecId{361, 6, 2}, 63, {cl1, cl2}, DsElecId{361, 6, 2}, 47, {cl3, cl4}, 5); @@ -227,5 +372,32 @@ BOOST_AUTO_TEST_CASE(SyncInTheMiddleChargeSumModeTwoChannels) "S361-J6-DS2-ch-63-ts-346-q-789012-cs-345\n"); } +BOOST_AUTO_TEST_CASE_TEMPLATE(TestCruPageOK, V, testTypes) +{ + gsl::span<const uint64_t> page = CruPageOK; + std::string r = testPayloadDecodeCruPages<V::value>(page); + BOOST_CHECK_EQUAL(r, + "S81-J0-DS0-ch-42-ts-87-q-2-1-0-4-4-3-3-0-0-1-0-0-0\n" + "S81-J0-DS0-ch-42-ts-0-q-1\n"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(TestCruPageBadClusterSize, V, testTypes) +{ + gsl::span<const uint64_t> page = CruPageBadClusterSize; + std::string r = testPayloadDecodeCruPages<V::value>(page); + BOOST_CHECK_EQUAL(r, + fmt::format("S81-J0-DS0-chip-1-error-{}\nS81-J0-DS0-ch-42-ts-0-q-1\n", ErrorBadClusterSize)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(TestCruPageBadN10bitWords, V, testTypes) +{ + gsl::span<const uint64_t> page = CruPageBadN10bitWords; + std::string r = testPayloadDecodeCruPages<V::value>(page); + std::string expected = + fmt::format("S81-J0-DS0-ch-42-ts-87-q-2-1-0-0-1-0-0-0\nS81-J0-DS0-chip-1-error-{}\nS81-J0-DS0-ch-42-ts-0-q-1\n", + ErrorBadIncompleteWord); + BOOST_CHECK_EQUAL(r, expected); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/ElecMap/CMakeLists.txt b/Detectors/MUON/MCH/Raw/ElecMap/CMakeLists.txt index d0092a6edbfee..e4f90494e7432 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/ElecMap/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHRawElecMap SOURCES @@ -17,6 +18,11 @@ o2_add_library(MCHRawElecMap src/CH7L.cxx src/CH7R.cxx src/CH8L.cxx + src/CH8R.cxx + src/CH9L.cxx + src/CH9R.cxx + src/CH10L.cxx + src/CH10R.cxx src/DsDetId.cxx src/DsElecId.cxx src/ElectronicMapperDummy.cxx @@ -27,7 +33,7 @@ o2_add_library(MCHRawElecMap src/MapFEC.cxx src/Mapper.cxx src/dslist.cxx - PUBLIC_LINK_LIBRARIES O2::MCHRawImplHelpers ms_gsl::ms_gsl) + PUBLIC_LINK_LIBRARIES O2::MCHRawImplHelpers Microsoft.GSL::GSL) o2_add_executable(elecmap-cli diff --git a/Detectors/MUON/MCH/Raw/ElecMap/README.md b/Detectors/MUON/MCH/Raw/ElecMap/README.md index 7391c0613f1e8..b1cababd6ab90 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/README.md +++ b/Detectors/MUON/MCH/Raw/ElecMap/README.md @@ -23,8 +23,8 @@ the 24 of a CRU). As the time of this writing the electronic mapping is still a bit in flux, as : -- the detector electronic is still being (re)installed -- the FeeId,LinkId to Solar part is still to be implemented at Pt2 +- the detector electronic is still being (re)installed +- the FeeId,LinkId to Solar part is still to be implemented at Pt2 so things might evolve... @@ -36,7 +36,7 @@ The API is to be found in [Mapper.h](include/MCHRawElecMap/Mapper.h) file. ## Generation of electronic mapping -The code generation uses the [gen.sh](src/gen.sh) script which basically loops +The code generation uses the [gen.sh](src/gen.sh) script which basically loops on all chambers and call `elecmap.py` for each one, e.g. ```bash @@ -45,3 +45,25 @@ on all chambers and call `elecmap.py` for each one, e.g. (for the moment a credential JSON file is required, we'll try to remove that constraint as soon as possible) + +The `elecmap.py` python script requires a number of python modules to be +installed to be able to run : + +```shell +pip install oauth2client +pip install gspread +pip install numpy +pip install pandas +``` + +Or, if you use `conda` (e.g. + [miniforge](https://github.com/conda-forge/miniforge)), +a [environment.yml](src/environment.yml) is provided so that : + +```shell +conda env create +conda env activate mch-elecmap +``` + +should bring you all you need to execute the script. + diff --git a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsDetId.h b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsDetId.h index 3b3160d9986d0..cc7163edcb2f1 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsDetId.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsDetId.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsElecId.h b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsElecId.h index 1e276c4968376..5f7ad86b555cc 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsElecId.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/DsElecId.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -51,13 +52,25 @@ class DsElecId return mSolarId; } - bool operator==(const DsElecId& rhs) + bool operator<(const DsElecId& rhs) const + { + if (mSolarId < rhs.mSolarId) { + return true; + } else if (mElinkIndexInGroup < rhs.mElinkIndexInGroup) { + return true; + } else if (mElinkGroupId < rhs.mElinkGroupId) { + return true; + } + return false; + } + + bool operator==(const DsElecId& rhs) const { return mSolarId == rhs.mSolarId && mElinkIndexInGroup == rhs.mElinkIndexInGroup && mElinkGroupId == rhs.mElinkGroupId; } - bool operator!=(const DsElecId& rhs) + bool operator!=(const DsElecId& rhs) const { return !(*this == rhs); } diff --git a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/FeeLinkId.h b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/FeeLinkId.h index b9358340ba489..f7a5aee5369a5 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/FeeLinkId.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/FeeLinkId.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/Mapper.h b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/Mapper.h index 1673d26192b02..12ce4b048e397 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/Mapper.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/Mapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,17 +12,19 @@ #ifndef O2_MCH_RAW_ELECMAP_MAPPER_H #define O2_MCH_RAW_ELECMAP_MAPPER_H -#include <functional> -#include <optional> -#include <set> -#include <stdexcept> -#include <cstdint> #include "MCHRawElecMap/DsDetId.h" #include "MCHRawElecMap/DsElecId.h" #include "MCHRawElecMap/FeeLinkId.h" -#include <fmt/format.h> #include <array> +#include <cstdint> +#include <fmt/format.h> +#include <functional> #include <gsl/span> +#include <optional> +#include <set> +#include <stdexcept> +#include <string> +#include <vector> namespace o2::mch::raw { @@ -30,7 +33,7 @@ extern std::array<int, 156> deIdsForAllMCH; /**@name Mapper templates. - Those creator functions return functions that can do the mapping to/from + Those creator functions return functions that can do the mapping to/from DsElecId to DsDetId and to/from FeeLinkId to solarId. */ ///@{ @@ -58,6 +61,14 @@ template <typename T> Solar2FeeLinkMapper createSolar2FeeLinkMapper(); ///@} +/// List of Solar Unique Ids for a given detection element id +template <typename T> +std::set<uint16_t> getSolarUIDs(int deid); + +/// List of Solar Unique Ids for all MCH +template <typename T> +std::set<uint16_t> getSolarUIDs(); + /**@name Actual mapper types. */ ///@{ @@ -72,6 +83,11 @@ struct ElectronicMapperString { }; ///@} +/** Return the full set of Dual Sampa Electronic Id of MCH, + * for a given electronic mapping */ +template <typename T> +std::set<DsElecId> getAllDs(); + extern std::array<int, 9> deIdsOfCH5R; extern std::array<int, 9> deIdsOfCH5L; extern std::array<int, 9> deIdsOfCH6R; @@ -80,6 +96,16 @@ extern std::array<int, 13> deIdsOfCH7R; extern std::array<int, 13> deIdsOfCH7L; extern std::array<int, 13> deIdsOfCH8R; extern std::array<int, 13> deIdsOfCH8L; +extern std::array<int, 13> deIdsOfCH9R; +extern std::array<int, 13> deIdsOfCH9L; +extern std::array<int, 13> deIdsOfCH10R; +extern std::array<int, 13> deIdsOfCH10L; + +// test whether all solars have a corresponding FeeLinkId +// and the reverse as well. +// @returns vector of error messages. If empty the check is ok +template <typename T> +std::vector<std::string> solar2FeeLinkConsistencyCheck(); } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH.cxx index cb956d08d4a0e..eca3dd865aa4a 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH10L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH10L.cxx new file mode 100644 index 0000000000000..37b884f371070 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH10L.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// GENERATED CODE ! DO NOT EDIT ! +/// + +#include <map> +#include <cstdint> +#include "MCHRawElecMap/DsElecId.h" +#include "MCHRawElecMap/DsDetId.h" +using namespace o2::mch::raw; + +void fillElec2DetCH10L(std::map<uint32_t, uint32_t>& e2d) +{ +} +void fillSolar2FeeLinkCH10L(std::map<uint16_t, uint32_t>& s2c) {} diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH10R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH10R.cxx new file mode 100644 index 0000000000000..6bfa4b5ec5bf2 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH10R.cxx @@ -0,0 +1,1018 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// GENERATED CODE ! DO NOT EDIT ! +/// + +#include "CH.cxx" +void fillElec2DetCH10R(std::map<uint32_t, uint32_t>& e2d) +{ + add(e2d, 1006, 12, 648, 0, 0); + add(e2d, 1006, 11, 648, 0, 1); + add(e2d, 1006, 8, 648, 2, 0); + add(e2d, 1006, 7, 648, 2, 1); + add(e2d, 1006, 4, 648, 4, 0); + add(e2d, 1006, 3, 648, 4, 1); + add(e2d, 1006, 1033, 648, 1, 0); + add(e2d, 1006, 1034, 648, 1, 1); + add(e2d, 1006, 1029, 648, 3, 0); + add(e2d, 1006, 1030, 648, 3, 1); + add(e2d, 1006, 1025, 648, 5, 0); + add(e2d, 1006, 1026, 648, 5, 1); + add(e2d, 1006, 111, 649, 0, 0); + add(e2d, 1006, 112, 649, 0, 1); + add(e2d, 1006, 113, 649, 0, 2); + add(e2d, 1006, 106, 649, 2, 0); + add(e2d, 1006, 107, 649, 2, 1); + add(e2d, 1006, 108, 649, 2, 2); + add(e2d, 1006, 101, 649, 4, 0); + add(e2d, 1006, 102, 649, 4, 1); + add(e2d, 1006, 103, 649, 4, 2); + add(e2d, 1006, 1139, 649, 1, 0); + add(e2d, 1006, 1138, 649, 1, 1); + add(e2d, 1006, 1134, 649, 3, 0); + add(e2d, 1006, 1133, 649, 3, 1); + add(e2d, 1006, 1129, 649, 5, 0); + add(e2d, 1006, 1128, 649, 5, 1); + add(e2d, 1005, 304, 650, 0, 0); + add(e2d, 1005, 303, 650, 0, 1); + add(e2d, 1005, 211, 650, 2, 0); + add(e2d, 1005, 212, 650, 2, 1); + add(e2d, 1005, 213, 650, 2, 2); + add(e2d, 1005, 206, 650, 4, 0); + add(e2d, 1005, 207, 650, 4, 1); + add(e2d, 1005, 208, 650, 4, 2); + add(e2d, 1005, 201, 650, 6, 0); + add(e2d, 1005, 202, 650, 6, 1); + add(e2d, 1005, 203, 650, 6, 2); + add(e2d, 1005, 1325, 650, 1, 0); + add(e2d, 1005, 1326, 650, 1, 1); + add(e2d, 1005, 1239, 650, 3, 0); + add(e2d, 1005, 1238, 650, 3, 1); + add(e2d, 1005, 1234, 650, 5, 0); + add(e2d, 1005, 1233, 650, 5, 1); + add(e2d, 1005, 1229, 650, 7, 0); + add(e2d, 1005, 1228, 650, 7, 1); + add(e2d, 1005, 1, 651, 0, 0); + add(e2d, 1005, 2, 651, 0, 1); + add(e2d, 1005, 3, 651, 0, 2); + add(e2d, 1005, 112, 651, 2, 0); + add(e2d, 1005, 111, 651, 2, 1); + add(e2d, 1005, 108, 651, 4, 0); + add(e2d, 1005, 107, 651, 4, 1); + add(e2d, 1005, 104, 651, 6, 0); + add(e2d, 1005, 103, 651, 6, 1); + add(e2d, 1005, 1029, 651, 1, 0); + add(e2d, 1005, 1028, 651, 1, 1); + add(e2d, 1005, 1133, 651, 3, 0); + add(e2d, 1005, 1134, 651, 3, 1); + add(e2d, 1005, 1129, 651, 5, 0); + add(e2d, 1005, 1130, 651, 5, 1); + add(e2d, 1005, 1125, 651, 7, 0); + add(e2d, 1005, 1126, 651, 7, 1); + add(e2d, 1004, 1, 664, 0, 0); + add(e2d, 1004, 2, 664, 0, 1); + add(e2d, 1004, 3, 664, 0, 2); + add(e2d, 1004, 4, 664, 0, 3); + add(e2d, 1004, 5, 664, 0, 4); + add(e2d, 1004, 10, 664, 2, 0); + add(e2d, 1004, 11, 664, 2, 1); + add(e2d, 1004, 12, 664, 2, 2); + add(e2d, 1004, 13, 664, 2, 3); + add(e2d, 1004, 14, 664, 2, 4); + add(e2d, 1004, 112, 664, 4, 0); + add(e2d, 1004, 111, 664, 4, 1); + add(e2d, 1004, 108, 664, 1, 0); + add(e2d, 1004, 107, 664, 1, 1); + add(e2d, 1004, 104, 664, 3, 0); + add(e2d, 1004, 103, 664, 3, 1); + add(e2d, 1004, 1033, 665, 0, 0); + add(e2d, 1004, 1032, 665, 0, 1); + add(e2d, 1004, 1031, 665, 0, 2); + add(e2d, 1004, 1030, 665, 0, 3); + add(e2d, 1004, 1042, 665, 2, 0); + add(e2d, 1004, 1041, 665, 2, 1); + add(e2d, 1004, 1040, 665, 2, 2); + add(e2d, 1004, 1039, 665, 2, 3); + add(e2d, 1004, 1133, 665, 4, 0); + add(e2d, 1004, 1134, 665, 4, 1); + add(e2d, 1004, 1129, 665, 1, 0); + add(e2d, 1004, 1130, 665, 1, 1); + add(e2d, 1004, 1125, 665, 3, 0); + add(e2d, 1004, 1126, 665, 3, 1); + add(e2d, 1004, 308, 666, 0, 0); + add(e2d, 1004, 307, 666, 0, 1); + add(e2d, 1004, 306, 666, 0, 2); + add(e2d, 1004, 305, 666, 0, 3); + add(e2d, 1004, 304, 666, 0, 4); + add(e2d, 1004, 316, 666, 2, 0); + add(e2d, 1004, 315, 666, 2, 1); + add(e2d, 1004, 314, 666, 2, 2); + add(e2d, 1004, 313, 666, 2, 3); + add(e2d, 1004, 312, 666, 2, 4); + add(e2d, 1004, 211, 666, 4, 0); + add(e2d, 1004, 212, 666, 4, 1); + add(e2d, 1004, 213, 666, 4, 2); + add(e2d, 1004, 206, 666, 1, 0); + add(e2d, 1004, 207, 666, 1, 1); + add(e2d, 1004, 208, 666, 1, 2); + add(e2d, 1004, 201, 666, 3, 0); + add(e2d, 1004, 202, 666, 3, 1); + add(e2d, 1004, 203, 666, 3, 2); + add(e2d, 1004, 1325, 667, 0, 0); + add(e2d, 1004, 1326, 667, 0, 1); + add(e2d, 1004, 1327, 667, 0, 2); + add(e2d, 1004, 1333, 667, 2, 0); + add(e2d, 1004, 1334, 667, 2, 1); + add(e2d, 1004, 1335, 667, 2, 2); + add(e2d, 1004, 1239, 667, 4, 0); + add(e2d, 1004, 1238, 667, 4, 1); + add(e2d, 1004, 1234, 667, 1, 0); + add(e2d, 1004, 1233, 667, 1, 1); + add(e2d, 1004, 1229, 667, 3, 0); + add(e2d, 1004, 1228, 667, 3, 1); + add(e2d, 1003, 308, 668, 0, 0); + add(e2d, 1003, 307, 668, 0, 1); + add(e2d, 1003, 306, 668, 0, 2); + add(e2d, 1003, 305, 668, 0, 3); + add(e2d, 1003, 304, 668, 0, 4); + add(e2d, 1003, 316, 668, 2, 0); + add(e2d, 1003, 315, 668, 2, 1); + add(e2d, 1003, 314, 668, 2, 2); + add(e2d, 1003, 313, 668, 2, 3); + add(e2d, 1003, 312, 668, 2, 4); + add(e2d, 1003, 324, 668, 4, 0); + add(e2d, 1003, 323, 668, 4, 1); + add(e2d, 1003, 322, 668, 4, 2); + add(e2d, 1003, 321, 668, 4, 3); + add(e2d, 1003, 320, 668, 4, 4); + add(e2d, 1003, 211, 668, 1, 0); + add(e2d, 1003, 212, 668, 1, 1); + add(e2d, 1003, 213, 668, 1, 2); + add(e2d, 1003, 206, 668, 3, 0); + add(e2d, 1003, 207, 668, 3, 1); + add(e2d, 1003, 208, 668, 3, 2); + add(e2d, 1003, 201, 668, 5, 0); + add(e2d, 1003, 202, 668, 5, 1); + add(e2d, 1003, 203, 668, 5, 2); + add(e2d, 1003, 1325, 669, 0, 0); + add(e2d, 1003, 1326, 669, 0, 1); + add(e2d, 1003, 1327, 669, 0, 2); + add(e2d, 1003, 1333, 669, 2, 0); + add(e2d, 1003, 1334, 669, 2, 1); + add(e2d, 1003, 1335, 669, 2, 2); + add(e2d, 1003, 1341, 669, 4, 0); + add(e2d, 1003, 1342, 669, 4, 1); + add(e2d, 1003, 1343, 669, 4, 2); + add(e2d, 1003, 1239, 669, 1, 0); + add(e2d, 1003, 1238, 669, 1, 1); + add(e2d, 1003, 1234, 669, 3, 0); + add(e2d, 1003, 1233, 669, 3, 1); + add(e2d, 1003, 1229, 669, 5, 0); + add(e2d, 1003, 1228, 669, 5, 1); + add(e2d, 1003, 1, 552, 0, 0); + add(e2d, 1003, 2, 552, 0, 1); + add(e2d, 1003, 3, 552, 0, 2); + add(e2d, 1003, 4, 552, 0, 3); + add(e2d, 1003, 5, 552, 0, 4); + add(e2d, 1003, 10, 552, 2, 0); + add(e2d, 1003, 11, 552, 2, 1); + add(e2d, 1003, 12, 552, 2, 2); + add(e2d, 1003, 13, 552, 2, 3); + add(e2d, 1003, 14, 552, 2, 4); + add(e2d, 1003, 19, 552, 4, 0); + add(e2d, 1003, 20, 552, 4, 1); + add(e2d, 1003, 21, 552, 4, 2); + add(e2d, 1003, 22, 552, 4, 3); + add(e2d, 1003, 23, 552, 4, 4); + add(e2d, 1003, 112, 552, 1, 0); + add(e2d, 1003, 111, 552, 1, 1); + add(e2d, 1003, 108, 552, 3, 0); + add(e2d, 1003, 107, 552, 3, 1); + add(e2d, 1003, 103, 552, 5, 0); + add(e2d, 1003, 104, 552, 5, 1); + add(e2d, 1003, 1033, 553, 0, 0); + add(e2d, 1003, 1032, 553, 0, 1); + add(e2d, 1003, 1031, 553, 0, 2); + add(e2d, 1003, 1030, 553, 0, 3); + add(e2d, 1003, 1042, 553, 2, 0); + add(e2d, 1003, 1041, 553, 2, 1); + add(e2d, 1003, 1040, 553, 2, 2); + add(e2d, 1003, 1039, 553, 2, 3); + add(e2d, 1003, 1051, 553, 4, 0); + add(e2d, 1003, 1050, 553, 4, 1); + add(e2d, 1003, 1049, 553, 4, 2); + add(e2d, 1003, 1048, 553, 4, 3); + add(e2d, 1003, 1125, 553, 1, 0); + add(e2d, 1003, 1126, 553, 1, 1); + add(e2d, 1003, 1129, 553, 3, 0); + add(e2d, 1003, 1130, 553, 3, 1); + add(e2d, 1003, 1133, 553, 5, 0); + add(e2d, 1003, 1134, 553, 5, 1); + add(e2d, 1002, 5, 554, 0, 0); + add(e2d, 1002, 4, 554, 0, 1); + add(e2d, 1002, 3, 554, 0, 2); + add(e2d, 1002, 2, 554, 0, 3); + add(e2d, 1002, 1, 554, 0, 4); + add(e2d, 1002, 10, 554, 2, 0); + add(e2d, 1002, 9, 554, 2, 1); + add(e2d, 1002, 8, 554, 2, 2); + add(e2d, 1002, 7, 554, 2, 3); + add(e2d, 1002, 6, 554, 2, 4); + add(e2d, 1002, 22, 554, 4, 0); + add(e2d, 1002, 21, 554, 4, 1); + add(e2d, 1002, 20, 554, 4, 2); + add(e2d, 1002, 19, 554, 4, 3); + add(e2d, 1002, 18, 554, 4, 4); + add(e2d, 1002, 27, 554, 6, 0); + add(e2d, 1002, 26, 554, 6, 1); + add(e2d, 1002, 25, 554, 6, 2); + add(e2d, 1002, 24, 554, 6, 3); + add(e2d, 1002, 23, 554, 6, 4); + add(e2d, 1002, 39, 554, 1, 0); + add(e2d, 1002, 38, 554, 1, 1); + add(e2d, 1002, 37, 554, 1, 2); + add(e2d, 1002, 36, 554, 1, 3); + add(e2d, 1002, 35, 554, 1, 4); + add(e2d, 1002, 116, 554, 3, 0); + add(e2d, 1002, 115, 554, 3, 1); + add(e2d, 1002, 114, 554, 3, 2); + add(e2d, 1002, 113, 554, 3, 3); + add(e2d, 1002, 112, 554, 3, 4); + add(e2d, 1002, 108, 554, 5, 0); + add(e2d, 1002, 107, 554, 5, 1); + add(e2d, 1002, 104, 554, 7, 0); + add(e2d, 1002, 103, 554, 7, 1); + add(e2d, 1002, 1039, 555, 0, 0); + add(e2d, 1002, 1040, 555, 0, 1); + add(e2d, 1002, 1041, 555, 0, 2); + add(e2d, 1002, 1035, 555, 2, 0); + add(e2d, 1002, 1036, 555, 2, 1); + add(e2d, 1002, 1037, 555, 2, 2); + add(e2d, 1002, 1038, 555, 2, 3); + add(e2d, 1002, 1056, 555, 4, 0); + add(e2d, 1002, 1057, 555, 4, 1); + add(e2d, 1002, 1058, 555, 4, 2); + add(e2d, 1002, 1052, 555, 6, 0); + add(e2d, 1002, 1053, 555, 6, 1); + add(e2d, 1002, 1054, 555, 6, 2); + add(e2d, 1002, 1055, 555, 6, 3); + add(e2d, 1002, 1067, 555, 1, 0); + add(e2d, 1002, 1066, 555, 1, 1); + add(e2d, 1002, 1065, 555, 1, 2); + add(e2d, 1002, 1064, 555, 1, 3); + add(e2d, 1002, 1133, 555, 3, 0); + add(e2d, 1002, 1134, 555, 3, 1); + add(e2d, 1002, 1135, 555, 3, 2); + add(e2d, 1002, 1129, 555, 5, 0); + add(e2d, 1002, 1130, 555, 5, 1); + add(e2d, 1002, 1125, 555, 7, 0); + add(e2d, 1002, 1126, 555, 7, 1); + add(e2d, 1002, 313, 556, 0, 0); + add(e2d, 1002, 314, 556, 0, 1); + add(e2d, 1002, 315, 556, 0, 2); + add(e2d, 1002, 316, 556, 0, 3); + add(e2d, 1002, 317, 556, 0, 4); + add(e2d, 1002, 308, 556, 2, 0); + add(e2d, 1002, 309, 556, 2, 1); + add(e2d, 1002, 310, 556, 2, 2); + add(e2d, 1002, 311, 556, 2, 3); + add(e2d, 1002, 312, 556, 2, 4); + add(e2d, 1002, 330, 556, 4, 0); + add(e2d, 1002, 331, 556, 4, 1); + add(e2d, 1002, 332, 556, 4, 2); + add(e2d, 1002, 333, 556, 4, 3); + add(e2d, 1002, 334, 556, 4, 4); + add(e2d, 1002, 325, 556, 6, 0); + add(e2d, 1002, 326, 556, 6, 1); + add(e2d, 1002, 327, 556, 6, 2); + add(e2d, 1002, 328, 556, 6, 3); + add(e2d, 1002, 329, 556, 6, 4); + add(e2d, 1002, 338, 556, 1, 0); + add(e2d, 1002, 339, 556, 1, 1); + add(e2d, 1002, 340, 556, 1, 2); + add(e2d, 1002, 341, 556, 1, 3); + add(e2d, 1002, 342, 556, 1, 4); + add(e2d, 1002, 211, 556, 3, 0); + add(e2d, 1002, 212, 556, 3, 1); + add(e2d, 1002, 213, 556, 3, 2); + add(e2d, 1002, 214, 556, 3, 3); + add(e2d, 1002, 215, 556, 3, 4); + add(e2d, 1002, 206, 556, 5, 0); + add(e2d, 1002, 207, 556, 5, 1); + add(e2d, 1002, 208, 556, 5, 2); + add(e2d, 1002, 201, 556, 7, 0); + add(e2d, 1002, 202, 556, 7, 1); + add(e2d, 1002, 203, 556, 7, 2); + add(e2d, 1002, 1327, 557, 0, 0); + add(e2d, 1002, 1326, 557, 0, 1); + add(e2d, 1002, 1325, 557, 0, 2); + add(e2d, 1002, 1331, 557, 2, 0); + add(e2d, 1002, 1330, 557, 2, 1); + add(e2d, 1002, 1329, 557, 2, 2); + add(e2d, 1002, 1328, 557, 2, 3); + add(e2d, 1002, 1344, 557, 4, 0); + add(e2d, 1002, 1343, 557, 4, 1); + add(e2d, 1002, 1342, 557, 4, 2); + add(e2d, 1002, 1348, 557, 6, 0); + add(e2d, 1002, 1347, 557, 6, 1); + add(e2d, 1002, 1346, 557, 6, 2); + add(e2d, 1002, 1345, 557, 6, 3); + add(e2d, 1002, 1359, 557, 1, 0); + add(e2d, 1002, 1360, 557, 1, 1); + add(e2d, 1002, 1361, 557, 1, 2); + add(e2d, 1002, 1243, 557, 3, 0); + add(e2d, 1002, 1242, 557, 3, 1); + add(e2d, 1002, 1241, 557, 3, 2); + add(e2d, 1002, 1240, 557, 3, 3); + add(e2d, 1002, 1234, 557, 5, 0); + add(e2d, 1002, 1233, 557, 5, 1); + add(e2d, 1002, 1229, 557, 7, 0); + add(e2d, 1002, 1228, 557, 7, 1); + add(e2d, 1001, 403, 504, 0, 0); + add(e2d, 1001, 402, 504, 0, 1); + add(e2d, 1001, 401, 504, 0, 2); + add(e2d, 1001, 408, 504, 2, 0); + add(e2d, 1001, 407, 504, 2, 1); + add(e2d, 1001, 406, 504, 2, 2); + add(e2d, 1001, 405, 504, 2, 3); + add(e2d, 1001, 404, 504, 2, 4); + add(e2d, 1001, 413, 504, 4, 0); + add(e2d, 1001, 412, 504, 4, 1); + add(e2d, 1001, 411, 504, 4, 2); + add(e2d, 1001, 410, 504, 4, 3); + add(e2d, 1001, 409, 504, 4, 4); + add(e2d, 1001, 315, 504, 6, 0); + add(e2d, 1001, 314, 504, 6, 1); + add(e2d, 1001, 313, 504, 6, 2); + add(e2d, 1001, 312, 504, 6, 3); + add(e2d, 1001, 311, 504, 6, 4); + add(e2d, 1001, 320, 504, 1, 0); + add(e2d, 1001, 319, 504, 1, 1); + add(e2d, 1001, 318, 504, 1, 2); + add(e2d, 1001, 317, 504, 1, 3); + add(e2d, 1001, 316, 504, 1, 4); + add(e2d, 1001, 332, 504, 3, 0); + add(e2d, 1001, 331, 504, 3, 1); + add(e2d, 1001, 330, 504, 3, 2); + add(e2d, 1001, 329, 504, 3, 3); + add(e2d, 1001, 328, 504, 3, 4); + add(e2d, 1001, 216, 504, 5, 0); + add(e2d, 1001, 215, 504, 5, 1); + add(e2d, 1001, 214, 504, 5, 2); + add(e2d, 1001, 213, 504, 5, 3); + add(e2d, 1001, 212, 504, 5, 4); + add(e2d, 1001, 208, 504, 7, 0); + add(e2d, 1001, 207, 504, 7, 1); + add(e2d, 1001, 1329, 505, 0, 0); + add(e2d, 1001, 1328, 505, 0, 1); + add(e2d, 1001, 1327, 505, 0, 2); + add(e2d, 1001, 1326, 505, 0, 3); + add(e2d, 1001, 1325, 505, 0, 4); + add(e2d, 1001, 1334, 505, 2, 0); + add(e2d, 1001, 1333, 505, 2, 1); + add(e2d, 1001, 1332, 505, 2, 2); + add(e2d, 1001, 1331, 505, 2, 3); + add(e2d, 1001, 1330, 505, 2, 4); + add(e2d, 1001, 1345, 505, 4, 0); + add(e2d, 1001, 1346, 505, 4, 1); + add(e2d, 1001, 1347, 505, 4, 2); + add(e2d, 1001, 1348, 505, 6, 0); + add(e2d, 1001, 1349, 505, 6, 1); + add(e2d, 1001, 1350, 505, 6, 2); + add(e2d, 1001, 1351, 505, 6, 3); + add(e2d, 1001, 1360, 505, 1, 0); + add(e2d, 1001, 1359, 505, 1, 1); + add(e2d, 1001, 1358, 505, 1, 2); + add(e2d, 1001, 1357, 505, 1, 3); + add(e2d, 1001, 1233, 505, 3, 0); + add(e2d, 1001, 1234, 505, 3, 1); + add(e2d, 1001, 1235, 505, 3, 2); + add(e2d, 1001, 1229, 505, 5, 0); + add(e2d, 1001, 1230, 505, 5, 1); + add(e2d, 1001, 1225, 505, 7, 0); + add(e2d, 1001, 1226, 505, 7, 1); + add(e2d, 1001, 204, 506, 0, 0); + add(e2d, 1001, 203, 506, 0, 1); + add(e2d, 1001, 1, 506, 2, 0); + add(e2d, 1001, 0, 506, 2, 1); + add(e2d, 1001, 9, 506, 4, 0); + add(e2d, 1001, 10, 506, 4, 1); + add(e2d, 1001, 11, 506, 4, 2); + add(e2d, 1001, 12, 506, 4, 3); + add(e2d, 1001, 13, 506, 4, 4); + add(e2d, 1001, 14, 506, 6, 0); + add(e2d, 1001, 15, 506, 6, 1); + add(e2d, 1001, 16, 506, 6, 2); + add(e2d, 1001, 17, 506, 6, 3); + add(e2d, 1001, 18, 506, 6, 4); + add(e2d, 1001, 22, 506, 1, 0); + add(e2d, 1001, 23, 506, 1, 1); + add(e2d, 1001, 24, 506, 1, 2); + add(e2d, 1001, 25, 506, 1, 3); + add(e2d, 1001, 26, 506, 1, 4); + add(e2d, 1001, 111, 506, 3, 0); + add(e2d, 1001, 112, 506, 3, 1); + add(e2d, 1001, 113, 506, 3, 2); + add(e2d, 1001, 114, 506, 3, 3); + add(e2d, 1001, 115, 506, 3, 4); + add(e2d, 1001, 106, 506, 5, 0); + add(e2d, 1001, 107, 506, 5, 1); + add(e2d, 1001, 108, 506, 5, 2); + add(e2d, 1001, 101, 506, 7, 0); + add(e2d, 1001, 102, 506, 7, 1); + add(e2d, 1001, 103, 506, 7, 2); + add(e2d, 1001, 1028, 507, 0, 0); + add(e2d, 1001, 1027, 507, 0, 1); + add(e2d, 1001, 1026, 507, 0, 2); + add(e2d, 1001, 1032, 507, 2, 0); + add(e2d, 1001, 1031, 507, 2, 1); + add(e2d, 1001, 1030, 507, 2, 2); + add(e2d, 1001, 1029, 507, 2, 3); + add(e2d, 1001, 1043, 507, 4, 0); + add(e2d, 1001, 1044, 507, 4, 1); + add(e2d, 1001, 1045, 507, 4, 2); + add(e2d, 1001, 1143, 507, 1, 0); + add(e2d, 1001, 1142, 507, 1, 1); + add(e2d, 1001, 1141, 507, 1, 2); + add(e2d, 1001, 1140, 507, 1, 3); + add(e2d, 1001, 1134, 507, 3, 0); + add(e2d, 1001, 1133, 507, 3, 1); + add(e2d, 1001, 1129, 507, 5, 0); + add(e2d, 1001, 1128, 507, 5, 1); + add(e2d, 1000, 5, 508, 0, 0); + add(e2d, 1000, 4, 508, 0, 1); + add(e2d, 1000, 3, 508, 0, 2); + add(e2d, 1000, 2, 508, 0, 3); + add(e2d, 1000, 1, 508, 0, 4); + add(e2d, 1000, 10, 508, 2, 0); + add(e2d, 1000, 9, 508, 2, 1); + add(e2d, 1000, 8, 508, 2, 2); + add(e2d, 1000, 7, 508, 2, 3); + add(e2d, 1000, 6, 508, 2, 4); + add(e2d, 1000, 22, 508, 4, 0); + add(e2d, 1000, 21, 508, 4, 1); + add(e2d, 1000, 20, 508, 4, 2); + add(e2d, 1000, 19, 508, 4, 3); + add(e2d, 1000, 18, 508, 4, 4); + add(e2d, 1000, 116, 508, 1, 0); + add(e2d, 1000, 115, 508, 1, 1); + add(e2d, 1000, 114, 508, 1, 2); + add(e2d, 1000, 113, 508, 1, 3); + add(e2d, 1000, 112, 508, 1, 4); + add(e2d, 1000, 108, 508, 3, 0); + add(e2d, 1000, 107, 508, 3, 1); + add(e2d, 1000, 104, 508, 5, 0); + add(e2d, 1000, 103, 508, 5, 1); + add(e2d, 1000, 1039, 509, 0, 0); + add(e2d, 1000, 1040, 509, 0, 1); + add(e2d, 1000, 1041, 509, 0, 2); + add(e2d, 1000, 1035, 509, 2, 0); + add(e2d, 1000, 1036, 509, 2, 1); + add(e2d, 1000, 1037, 509, 2, 2); + add(e2d, 1000, 1038, 509, 2, 3); + add(e2d, 1000, 1050, 509, 4, 0); + add(e2d, 1000, 1049, 509, 4, 1); + add(e2d, 1000, 1048, 509, 4, 2); + add(e2d, 1000, 1047, 509, 4, 3); + add(e2d, 1000, 1133, 509, 1, 0); + add(e2d, 1000, 1134, 509, 1, 1); + add(e2d, 1000, 1135, 509, 1, 2); + add(e2d, 1000, 1129, 509, 3, 0); + add(e2d, 1000, 1130, 509, 3, 1); + add(e2d, 1000, 1125, 509, 5, 0); + add(e2d, 1000, 1126, 509, 5, 1); + add(e2d, 1000, 313, 536, 0, 0); + add(e2d, 1000, 314, 536, 0, 1); + add(e2d, 1000, 315, 536, 0, 2); + add(e2d, 1000, 316, 536, 0, 3); + add(e2d, 1000, 317, 536, 0, 4); + add(e2d, 1000, 308, 536, 2, 0); + add(e2d, 1000, 309, 536, 2, 1); + add(e2d, 1000, 310, 536, 2, 2); + add(e2d, 1000, 311, 536, 2, 3); + add(e2d, 1000, 312, 536, 2, 4); + add(e2d, 1000, 321, 536, 4, 0); + add(e2d, 1000, 322, 536, 4, 1); + add(e2d, 1000, 323, 536, 4, 2); + add(e2d, 1000, 324, 536, 4, 3); + add(e2d, 1000, 325, 536, 4, 4); + add(e2d, 1000, 211, 536, 1, 0); + add(e2d, 1000, 212, 536, 1, 1); + add(e2d, 1000, 213, 536, 1, 2); + add(e2d, 1000, 214, 536, 1, 3); + add(e2d, 1000, 215, 536, 1, 4); + add(e2d, 1000, 206, 536, 3, 0); + add(e2d, 1000, 207, 536, 3, 1); + add(e2d, 1000, 208, 536, 3, 2); + add(e2d, 1000, 201, 536, 5, 0); + add(e2d, 1000, 202, 536, 5, 1); + add(e2d, 1000, 203, 536, 5, 2); + add(e2d, 1000, 1327, 537, 0, 0); + add(e2d, 1000, 1326, 537, 0, 1); + add(e2d, 1000, 1325, 537, 0, 2); + add(e2d, 1000, 1331, 537, 2, 0); + add(e2d, 1000, 1330, 537, 2, 1); + add(e2d, 1000, 1329, 537, 2, 2); + add(e2d, 1000, 1328, 537, 2, 3); + add(e2d, 1000, 1342, 537, 4, 0); + add(e2d, 1000, 1343, 537, 4, 1); + add(e2d, 1000, 1344, 537, 4, 2); + add(e2d, 1000, 1243, 537, 1, 0); + add(e2d, 1000, 1242, 537, 1, 1); + add(e2d, 1000, 1241, 537, 1, 2); + add(e2d, 1000, 1240, 537, 1, 3); + add(e2d, 1000, 1234, 537, 3, 0); + add(e2d, 1000, 1233, 537, 3, 1); + add(e2d, 1000, 1229, 537, 5, 0); + add(e2d, 1000, 1228, 537, 5, 1); + add(e2d, 1025, 204, 538, 0, 0); + add(e2d, 1025, 203, 538, 0, 1); + add(e2d, 1025, 1, 538, 2, 0); + add(e2d, 1025, 0, 538, 2, 1); + add(e2d, 1025, 9, 538, 4, 0); + add(e2d, 1025, 10, 538, 4, 1); + add(e2d, 1025, 11, 538, 4, 2); + add(e2d, 1025, 12, 538, 4, 3); + add(e2d, 1025, 13, 538, 4, 4); + add(e2d, 1025, 14, 538, 6, 0); + add(e2d, 1025, 15, 538, 6, 1); + add(e2d, 1025, 16, 538, 6, 2); + add(e2d, 1025, 17, 538, 6, 3); + add(e2d, 1025, 18, 538, 6, 4); + add(e2d, 1025, 22, 538, 1, 0); + add(e2d, 1025, 23, 538, 1, 1); + add(e2d, 1025, 24, 538, 1, 2); + add(e2d, 1025, 25, 538, 1, 3); + add(e2d, 1025, 26, 538, 1, 4); + add(e2d, 1025, 111, 538, 3, 0); + add(e2d, 1025, 112, 538, 3, 1); + add(e2d, 1025, 113, 538, 3, 2); + add(e2d, 1025, 114, 538, 3, 3); + add(e2d, 1025, 115, 538, 3, 4); + add(e2d, 1025, 106, 538, 5, 0); + add(e2d, 1025, 107, 538, 5, 1); + add(e2d, 1025, 108, 538, 5, 2); + add(e2d, 1025, 101, 538, 7, 0); + add(e2d, 1025, 102, 538, 7, 1); + add(e2d, 1025, 103, 538, 7, 2); + add(e2d, 1025, 1028, 539, 0, 0); + add(e2d, 1025, 1027, 539, 0, 1); + add(e2d, 1025, 1026, 539, 0, 2); + add(e2d, 1025, 1032, 539, 2, 0); + add(e2d, 1025, 1031, 539, 2, 1); + add(e2d, 1025, 1030, 539, 2, 2); + add(e2d, 1025, 1029, 539, 2, 3); + add(e2d, 1025, 1043, 539, 4, 0); + add(e2d, 1025, 1044, 539, 4, 1); + add(e2d, 1025, 1045, 539, 4, 2); + add(e2d, 1025, 1143, 539, 1, 0); + add(e2d, 1025, 1142, 539, 1, 1); + add(e2d, 1025, 1141, 539, 1, 2); + add(e2d, 1025, 1140, 539, 1, 3); + add(e2d, 1025, 1134, 539, 3, 0); + add(e2d, 1025, 1133, 539, 3, 1); + add(e2d, 1025, 1129, 539, 5, 0); + add(e2d, 1025, 1128, 539, 5, 1); + add(e2d, 1025, 403, 540, 0, 0); + add(e2d, 1025, 402, 540, 0, 1); + add(e2d, 1025, 401, 540, 0, 2); + add(e2d, 1025, 408, 540, 2, 0); + add(e2d, 1025, 407, 540, 2, 1); + add(e2d, 1025, 406, 540, 2, 2); + add(e2d, 1025, 405, 540, 2, 3); + add(e2d, 1025, 404, 540, 2, 4); + add(e2d, 1025, 413, 540, 4, 0); + add(e2d, 1025, 412, 540, 4, 1); + add(e2d, 1025, 411, 540, 4, 2); + add(e2d, 1025, 410, 540, 4, 3); + add(e2d, 1025, 409, 540, 4, 4); + add(e2d, 1025, 315, 540, 6, 0); + add(e2d, 1025, 314, 540, 6, 1); + add(e2d, 1025, 313, 540, 6, 2); + add(e2d, 1025, 312, 540, 6, 3); + add(e2d, 1025, 311, 540, 6, 4); + add(e2d, 1025, 320, 540, 1, 0); + add(e2d, 1025, 319, 540, 1, 1); + add(e2d, 1025, 318, 540, 1, 2); + add(e2d, 1025, 317, 540, 1, 3); + add(e2d, 1025, 316, 540, 1, 4); + add(e2d, 1025, 332, 540, 3, 0); + add(e2d, 1025, 331, 540, 3, 1); + add(e2d, 1025, 330, 540, 3, 2); + add(e2d, 1025, 329, 540, 3, 3); + add(e2d, 1025, 328, 540, 3, 4); + add(e2d, 1025, 216, 540, 5, 0); + add(e2d, 1025, 215, 540, 5, 1); + add(e2d, 1025, 214, 540, 5, 2); + add(e2d, 1025, 213, 540, 5, 3); + add(e2d, 1025, 212, 540, 5, 4); + add(e2d, 1025, 208, 540, 7, 0); + add(e2d, 1025, 207, 540, 7, 1); + add(e2d, 1025, 1329, 541, 0, 0); + add(e2d, 1025, 1328, 541, 0, 1); + add(e2d, 1025, 1327, 541, 0, 2); + add(e2d, 1025, 1326, 541, 0, 3); + add(e2d, 1025, 1325, 541, 0, 4); + add(e2d, 1025, 1334, 541, 2, 0); + add(e2d, 1025, 1333, 541, 2, 1); + add(e2d, 1025, 1332, 541, 2, 2); + add(e2d, 1025, 1331, 541, 2, 3); + add(e2d, 1025, 1330, 541, 2, 4); + add(e2d, 1025, 1345, 541, 4, 0); + add(e2d, 1025, 1346, 541, 4, 1); + add(e2d, 1025, 1347, 541, 4, 2); + add(e2d, 1025, 1348, 541, 6, 0); + add(e2d, 1025, 1349, 541, 6, 1); + add(e2d, 1025, 1350, 541, 6, 2); + add(e2d, 1025, 1351, 541, 6, 3); + add(e2d, 1025, 1360, 541, 1, 0); + add(e2d, 1025, 1359, 541, 1, 1); + add(e2d, 1025, 1358, 541, 1, 2); + add(e2d, 1025, 1357, 541, 1, 3); + add(e2d, 1025, 1233, 541, 3, 0); + add(e2d, 1025, 1234, 541, 3, 1); + add(e2d, 1025, 1235, 541, 3, 2); + add(e2d, 1025, 1229, 541, 5, 0); + add(e2d, 1025, 1230, 541, 5, 1); + add(e2d, 1025, 1225, 541, 7, 0); + add(e2d, 1025, 1226, 541, 7, 1); + add(e2d, 1024, 5, 544, 0, 0); + add(e2d, 1024, 4, 544, 0, 1); + add(e2d, 1024, 3, 544, 0, 2); + add(e2d, 1024, 2, 544, 0, 3); + add(e2d, 1024, 1, 544, 0, 4); + add(e2d, 1024, 10, 544, 2, 0); + add(e2d, 1024, 9, 544, 2, 1); + add(e2d, 1024, 8, 544, 2, 2); + add(e2d, 1024, 7, 544, 2, 3); + add(e2d, 1024, 6, 544, 2, 4); + add(e2d, 1024, 22, 544, 4, 0); + add(e2d, 1024, 21, 544, 4, 1); + add(e2d, 1024, 20, 544, 4, 2); + add(e2d, 1024, 19, 544, 4, 3); + add(e2d, 1024, 18, 544, 4, 4); + add(e2d, 1024, 27, 544, 6, 0); + add(e2d, 1024, 26, 544, 6, 1); + add(e2d, 1024, 25, 544, 6, 2); + add(e2d, 1024, 24, 544, 6, 3); + add(e2d, 1024, 23, 544, 6, 4); + add(e2d, 1024, 39, 544, 1, 0); + add(e2d, 1024, 38, 544, 1, 1); + add(e2d, 1024, 37, 544, 1, 2); + add(e2d, 1024, 36, 544, 1, 3); + add(e2d, 1024, 35, 544, 1, 4); + add(e2d, 1024, 116, 544, 3, 0); + add(e2d, 1024, 115, 544, 3, 1); + add(e2d, 1024, 114, 544, 3, 2); + add(e2d, 1024, 113, 544, 3, 3); + add(e2d, 1024, 112, 544, 3, 4); + add(e2d, 1024, 108, 544, 5, 0); + add(e2d, 1024, 107, 544, 5, 1); + add(e2d, 1024, 104, 544, 7, 0); + add(e2d, 1024, 103, 544, 7, 1); + add(e2d, 1024, 1039, 545, 0, 0); + add(e2d, 1024, 1040, 545, 0, 1); + add(e2d, 1024, 1041, 545, 0, 2); + add(e2d, 1024, 1035, 545, 2, 0); + add(e2d, 1024, 1036, 545, 2, 1); + add(e2d, 1024, 1037, 545, 2, 2); + add(e2d, 1024, 1038, 545, 2, 3); + add(e2d, 1024, 1056, 545, 4, 0); + add(e2d, 1024, 1057, 545, 4, 1); + add(e2d, 1024, 1058, 545, 4, 2); + add(e2d, 1024, 1052, 545, 6, 0); + add(e2d, 1024, 1053, 545, 6, 1); + add(e2d, 1024, 1054, 545, 6, 2); + add(e2d, 1024, 1055, 545, 6, 3); + add(e2d, 1024, 1067, 545, 1, 0); + add(e2d, 1024, 1066, 545, 1, 1); + add(e2d, 1024, 1065, 545, 1, 2); + add(e2d, 1024, 1064, 545, 1, 3); + add(e2d, 1024, 1133, 545, 3, 0); + add(e2d, 1024, 1134, 545, 3, 1); + add(e2d, 1024, 1135, 545, 3, 2); + add(e2d, 1024, 1129, 545, 5, 0); + add(e2d, 1024, 1130, 545, 5, 1); + add(e2d, 1024, 1125, 545, 7, 0); + add(e2d, 1024, 1126, 545, 7, 1); + add(e2d, 1024, 313, 546, 0, 0); + add(e2d, 1024, 314, 546, 0, 1); + add(e2d, 1024, 315, 546, 0, 2); + add(e2d, 1024, 316, 546, 0, 3); + add(e2d, 1024, 317, 546, 0, 4); + add(e2d, 1024, 308, 546, 2, 0); + add(e2d, 1024, 309, 546, 2, 1); + add(e2d, 1024, 310, 546, 2, 2); + add(e2d, 1024, 311, 546, 2, 3); + add(e2d, 1024, 312, 546, 2, 4); + add(e2d, 1024, 330, 546, 4, 0); + add(e2d, 1024, 331, 546, 4, 1); + add(e2d, 1024, 332, 546, 4, 2); + add(e2d, 1024, 333, 546, 4, 3); + add(e2d, 1024, 334, 546, 4, 4); + add(e2d, 1024, 325, 546, 6, 0); + add(e2d, 1024, 326, 546, 6, 1); + add(e2d, 1024, 327, 546, 6, 2); + add(e2d, 1024, 328, 546, 6, 3); + add(e2d, 1024, 329, 546, 6, 4); + add(e2d, 1024, 338, 546, 1, 0); + add(e2d, 1024, 339, 546, 1, 1); + add(e2d, 1024, 340, 546, 1, 2); + add(e2d, 1024, 341, 546, 1, 3); + add(e2d, 1024, 342, 546, 1, 4); + add(e2d, 1024, 211, 546, 3, 0); + add(e2d, 1024, 212, 546, 3, 1); + add(e2d, 1024, 213, 546, 3, 2); + add(e2d, 1024, 214, 546, 3, 3); + add(e2d, 1024, 215, 546, 3, 4); + add(e2d, 1024, 206, 546, 5, 0); + add(e2d, 1024, 207, 546, 5, 1); + add(e2d, 1024, 208, 546, 5, 2); + add(e2d, 1024, 201, 546, 7, 0); + add(e2d, 1024, 202, 546, 7, 1); + add(e2d, 1024, 203, 546, 7, 2); + add(e2d, 1024, 1327, 547, 0, 0); + add(e2d, 1024, 1326, 547, 0, 1); + add(e2d, 1024, 1325, 547, 0, 2); + add(e2d, 1024, 1331, 547, 2, 0); + add(e2d, 1024, 1330, 547, 2, 1); + add(e2d, 1024, 1329, 547, 2, 2); + add(e2d, 1024, 1328, 547, 2, 3); + add(e2d, 1024, 1344, 547, 4, 0); + add(e2d, 1024, 1343, 547, 4, 1); + add(e2d, 1024, 1342, 547, 4, 2); + add(e2d, 1024, 1348, 547, 6, 0); + add(e2d, 1024, 1347, 547, 6, 1); + add(e2d, 1024, 1346, 547, 6, 2); + add(e2d, 1024, 1345, 547, 6, 3); + add(e2d, 1024, 1359, 547, 1, 0); + add(e2d, 1024, 1360, 547, 1, 1); + add(e2d, 1024, 1361, 547, 1, 2); + add(e2d, 1024, 1243, 547, 3, 0); + add(e2d, 1024, 1242, 547, 3, 1); + add(e2d, 1024, 1241, 547, 3, 2); + add(e2d, 1024, 1240, 547, 3, 3); + add(e2d, 1024, 1234, 547, 5, 0); + add(e2d, 1024, 1233, 547, 5, 1); + add(e2d, 1024, 1229, 547, 7, 0); + add(e2d, 1024, 1228, 547, 7, 1); + add(e2d, 1023, 308, 548, 0, 0); + add(e2d, 1023, 307, 548, 0, 1); + add(e2d, 1023, 306, 548, 0, 2); + add(e2d, 1023, 305, 548, 0, 3); + add(e2d, 1023, 304, 548, 0, 4); + add(e2d, 1023, 316, 548, 2, 0); + add(e2d, 1023, 315, 548, 2, 1); + add(e2d, 1023, 314, 548, 2, 2); + add(e2d, 1023, 313, 548, 2, 3); + add(e2d, 1023, 312, 548, 2, 4); + add(e2d, 1023, 324, 548, 4, 0); + add(e2d, 1023, 323, 548, 4, 1); + add(e2d, 1023, 322, 548, 4, 2); + add(e2d, 1023, 321, 548, 4, 3); + add(e2d, 1023, 320, 548, 4, 4); + add(e2d, 1023, 211, 548, 1, 0); + add(e2d, 1023, 212, 548, 1, 1); + add(e2d, 1023, 213, 548, 1, 2); + add(e2d, 1023, 206, 548, 3, 0); + add(e2d, 1023, 207, 548, 3, 1); + add(e2d, 1023, 208, 548, 3, 2); + add(e2d, 1023, 201, 548, 5, 0); + add(e2d, 1023, 202, 548, 5, 1); + add(e2d, 1023, 203, 548, 5, 2); + add(e2d, 1023, 1325, 549, 0, 0); + add(e2d, 1023, 1326, 549, 0, 1); + add(e2d, 1023, 1327, 549, 0, 2); + add(e2d, 1023, 1333, 549, 2, 0); + add(e2d, 1023, 1334, 549, 2, 1); + add(e2d, 1023, 1335, 549, 2, 2); + add(e2d, 1023, 1341, 549, 4, 0); + add(e2d, 1023, 1342, 549, 4, 1); + add(e2d, 1023, 1343, 549, 4, 2); + add(e2d, 1023, 1239, 549, 1, 0); + add(e2d, 1023, 1238, 549, 1, 1); + add(e2d, 1023, 1234, 549, 3, 0); + add(e2d, 1023, 1233, 549, 3, 1); + add(e2d, 1023, 1229, 549, 5, 0); + add(e2d, 1023, 1228, 549, 5, 1); + add(e2d, 1023, 1, 520, 0, 0); + add(e2d, 1023, 2, 520, 0, 1); + add(e2d, 1023, 3, 520, 0, 2); + add(e2d, 1023, 4, 520, 0, 3); + add(e2d, 1023, 5, 520, 0, 4); + add(e2d, 1023, 10, 520, 2, 0); + add(e2d, 1023, 11, 520, 2, 1); + add(e2d, 1023, 12, 520, 2, 2); + add(e2d, 1023, 13, 520, 2, 3); + add(e2d, 1023, 14, 520, 2, 4); + add(e2d, 1023, 19, 520, 4, 0); + add(e2d, 1023, 20, 520, 4, 1); + add(e2d, 1023, 21, 520, 4, 2); + add(e2d, 1023, 22, 520, 4, 3); + add(e2d, 1023, 23, 520, 4, 4); + add(e2d, 1023, 112, 520, 1, 0); + add(e2d, 1023, 111, 520, 1, 1); + add(e2d, 1023, 108, 520, 3, 0); + add(e2d, 1023, 107, 520, 3, 1); + add(e2d, 1023, 103, 520, 5, 0); + add(e2d, 1023, 104, 520, 5, 1); + add(e2d, 1023, 1033, 521, 0, 0); + add(e2d, 1023, 1032, 521, 0, 1); + add(e2d, 1023, 1031, 521, 0, 2); + add(e2d, 1023, 1030, 521, 0, 3); + add(e2d, 1023, 1042, 521, 2, 0); + add(e2d, 1023, 1041, 521, 2, 1); + add(e2d, 1023, 1040, 521, 2, 2); + add(e2d, 1023, 1039, 521, 2, 3); + add(e2d, 1023, 1051, 521, 4, 0); + add(e2d, 1023, 1050, 521, 4, 1); + add(e2d, 1023, 1049, 521, 4, 2); + add(e2d, 1023, 1048, 521, 4, 3); + add(e2d, 1023, 1125, 521, 1, 0); + add(e2d, 1023, 1126, 521, 1, 1); + add(e2d, 1023, 1129, 521, 3, 0); + add(e2d, 1023, 1130, 521, 3, 1); + add(e2d, 1023, 1133, 521, 5, 0); + add(e2d, 1023, 1134, 521, 5, 1); + add(e2d, 1022, 1, 522, 0, 0); + add(e2d, 1022, 2, 522, 0, 1); + add(e2d, 1022, 3, 522, 0, 2); + add(e2d, 1022, 4, 522, 0, 3); + add(e2d, 1022, 5, 522, 0, 4); + add(e2d, 1022, 10, 522, 2, 0); + add(e2d, 1022, 11, 522, 2, 1); + add(e2d, 1022, 12, 522, 2, 2); + add(e2d, 1022, 13, 522, 2, 3); + add(e2d, 1022, 14, 522, 2, 4); + add(e2d, 1022, 112, 522, 4, 0); + add(e2d, 1022, 111, 522, 4, 1); + add(e2d, 1022, 108, 522, 1, 0); + add(e2d, 1022, 107, 522, 1, 1); + add(e2d, 1022, 104, 522, 3, 0); + add(e2d, 1022, 103, 522, 3, 1); + add(e2d, 1022, 1033, 523, 0, 0); + add(e2d, 1022, 1032, 523, 0, 1); + add(e2d, 1022, 1031, 523, 0, 2); + add(e2d, 1022, 1030, 523, 0, 3); + add(e2d, 1022, 1042, 523, 2, 0); + add(e2d, 1022, 1041, 523, 2, 1); + add(e2d, 1022, 1040, 523, 2, 2); + add(e2d, 1022, 1039, 523, 2, 3); + add(e2d, 1022, 1133, 523, 4, 0); + add(e2d, 1022, 1134, 523, 4, 1); + add(e2d, 1022, 1129, 523, 1, 0); + add(e2d, 1022, 1130, 523, 1, 1); + add(e2d, 1022, 1125, 523, 3, 0); + add(e2d, 1022, 1126, 523, 3, 1); + add(e2d, 1022, 308, 524, 0, 0); + add(e2d, 1022, 307, 524, 0, 1); + add(e2d, 1022, 306, 524, 0, 2); + add(e2d, 1022, 305, 524, 0, 3); + add(e2d, 1022, 304, 524, 0, 4); + add(e2d, 1022, 316, 524, 2, 0); + add(e2d, 1022, 315, 524, 2, 1); + add(e2d, 1022, 314, 524, 2, 2); + add(e2d, 1022, 313, 524, 2, 3); + add(e2d, 1022, 312, 524, 2, 4); + add(e2d, 1022, 211, 524, 4, 0); + add(e2d, 1022, 212, 524, 4, 1); + add(e2d, 1022, 213, 524, 4, 2); + add(e2d, 1022, 206, 524, 1, 0); + add(e2d, 1022, 207, 524, 1, 1); + add(e2d, 1022, 208, 524, 1, 2); + add(e2d, 1022, 201, 524, 3, 0); + add(e2d, 1022, 202, 524, 3, 1); + add(e2d, 1022, 203, 524, 3, 2); + add(e2d, 1022, 1325, 525, 0, 0); + add(e2d, 1022, 1326, 525, 0, 1); + add(e2d, 1022, 1327, 525, 0, 2); + add(e2d, 1022, 1333, 525, 2, 0); + add(e2d, 1022, 1334, 525, 2, 1); + add(e2d, 1022, 1335, 525, 2, 2); + add(e2d, 1022, 1239, 525, 4, 0); + add(e2d, 1022, 1238, 525, 4, 1); + add(e2d, 1022, 1234, 525, 1, 0); + add(e2d, 1022, 1233, 525, 1, 1); + add(e2d, 1022, 1229, 525, 3, 0); + add(e2d, 1022, 1228, 525, 3, 1); + add(e2d, 1021, 304, 472, 0, 0); + add(e2d, 1021, 303, 472, 0, 1); + add(e2d, 1021, 211, 472, 2, 0); + add(e2d, 1021, 212, 472, 2, 1); + add(e2d, 1021, 213, 472, 2, 2); + add(e2d, 1021, 206, 472, 4, 0); + add(e2d, 1021, 207, 472, 4, 1); + add(e2d, 1021, 208, 472, 4, 2); + add(e2d, 1021, 201, 472, 6, 0); + add(e2d, 1021, 202, 472, 6, 1); + add(e2d, 1021, 203, 472, 6, 2); + add(e2d, 1021, 1325, 472, 1, 0); + add(e2d, 1021, 1326, 472, 1, 1); + add(e2d, 1021, 1239, 472, 3, 0); + add(e2d, 1021, 1238, 472, 3, 1); + add(e2d, 1021, 1234, 472, 5, 0); + add(e2d, 1021, 1233, 472, 5, 1); + add(e2d, 1021, 1229, 472, 7, 0); + add(e2d, 1021, 1228, 472, 7, 1); + add(e2d, 1021, 1, 473, 0, 0); + add(e2d, 1021, 2, 473, 0, 1); + add(e2d, 1021, 3, 473, 0, 2); + add(e2d, 1021, 112, 473, 2, 0); + add(e2d, 1021, 111, 473, 2, 1); + add(e2d, 1021, 108, 473, 4, 0); + add(e2d, 1021, 107, 473, 4, 1); + add(e2d, 1021, 104, 473, 6, 0); + add(e2d, 1021, 103, 473, 6, 1); + add(e2d, 1021, 1029, 473, 1, 0); + add(e2d, 1021, 1028, 473, 1, 1); + add(e2d, 1021, 1133, 473, 3, 0); + add(e2d, 1021, 1134, 473, 3, 1); + add(e2d, 1021, 1129, 473, 5, 0); + add(e2d, 1021, 1130, 473, 5, 1); + add(e2d, 1021, 1125, 473, 7, 0); + add(e2d, 1021, 1126, 473, 7, 1); + add(e2d, 1020, 12, 474, 0, 0); + add(e2d, 1020, 11, 474, 0, 1); + add(e2d, 1020, 8, 474, 2, 0); + add(e2d, 1020, 7, 474, 2, 1); + add(e2d, 1020, 4, 474, 4, 0); + add(e2d, 1020, 3, 474, 4, 1); + add(e2d, 1020, 1033, 474, 1, 0); + add(e2d, 1020, 1034, 474, 1, 1); + add(e2d, 1020, 1029, 474, 3, 0); + add(e2d, 1020, 1030, 474, 3, 1); + add(e2d, 1020, 1025, 474, 5, 0); + add(e2d, 1020, 1026, 474, 5, 1); + add(e2d, 1020, 111, 475, 0, 0); + add(e2d, 1020, 112, 475, 0, 1); + add(e2d, 1020, 113, 475, 0, 2); + add(e2d, 1020, 106, 475, 2, 0); + add(e2d, 1020, 107, 475, 2, 1); + add(e2d, 1020, 108, 475, 2, 2); + add(e2d, 1020, 101, 475, 4, 0); + add(e2d, 1020, 102, 475, 4, 1); + add(e2d, 1020, 103, 475, 4, 2); + add(e2d, 1020, 1139, 475, 1, 0); + add(e2d, 1020, 1138, 475, 1, 1); + add(e2d, 1020, 1134, 475, 3, 0); + add(e2d, 1020, 1133, 475, 3, 1); + add(e2d, 1020, 1129, 475, 5, 0); + add(e2d, 1020, 1128, 475, 5, 1); +} +void fillSolar2FeeLinkCH10R(std::map<uint16_t, uint32_t>& s2f) +{ + add_cru(s2f, 60, 0, 648); + add_cru(s2f, 60, 1, 649); + add_cru(s2f, 60, 2, 650); + add_cru(s2f, 60, 3, 651); + add_cru(s2f, 60, 6, 664); + add_cru(s2f, 60, 7, 665); + add_cru(s2f, 60, 8, 666); + add_cru(s2f, 60, 9, 667); + add_cru(s2f, 60, 10, 668); + add_cru(s2f, 60, 11, 669); + add_cru(s2f, 61, 0, 552); + add_cru(s2f, 61, 1, 553); + add_cru(s2f, 61, 2, 554); + add_cru(s2f, 61, 3, 555); + add_cru(s2f, 61, 4, 556); + add_cru(s2f, 61, 5, 557); + add_cru(s2f, 61, 6, 504); + add_cru(s2f, 61, 7, 505); + add_cru(s2f, 61, 8, 506); + add_cru(s2f, 61, 9, 507); + add_cru(s2f, 61, 10, 508); + add_cru(s2f, 61, 11, 509); + add_cru(s2f, 62, 0, 536); + add_cru(s2f, 62, 1, 537); + add_cru(s2f, 62, 2, 538); + add_cru(s2f, 62, 3, 539); + add_cru(s2f, 62, 4, 540); + add_cru(s2f, 62, 5, 541); + add_cru(s2f, 62, 6, 544); + add_cru(s2f, 62, 7, 545); + add_cru(s2f, 62, 8, 546); + add_cru(s2f, 62, 9, 547); + add_cru(s2f, 62, 10, 548); + add_cru(s2f, 62, 11, 549); + add_cru(s2f, 63, 0, 520); + add_cru(s2f, 63, 1, 521); + add_cru(s2f, 63, 2, 522); + add_cru(s2f, 63, 3, 523); + add_cru(s2f, 63, 4, 524); + add_cru(s2f, 63, 5, 525); + add_cru(s2f, 63, 6, 472); + add_cru(s2f, 63, 7, 473); + add_cru(s2f, 63, 8, 474); + add_cru(s2f, 63, 9, 475); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH5L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH5L.cxx index e1b3be52ccc3c..c4642284af61d 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH5L.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH5L.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH5R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH5R.cxx index 332c585cdb801..5c9d62faca2af 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH5R.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH5R.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH6L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH6L.cxx index d5883b888d440..7afd178780e6d 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH6L.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH6L.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,13 +13,650 @@ /// GENERATED CODE ! DO NOT EDIT ! /// -#include <map> -#include <cstdint> -#include "MCHRawElecMap/DsElecId.h" -#include "MCHRawElecMap/DsDetId.h" -using namespace o2::mch::raw; - +#include "CH.cxx" void fillElec2DetCH6L(std::map<uint32_t, uint32_t>& e2d) { + add(e2d, 605, 16, 312, 0, 0); + add(e2d, 605, 15, 312, 0, 1); + add(e2d, 605, 14, 312, 0, 2); + add(e2d, 605, 13, 312, 0, 3); + add(e2d, 605, 12, 312, 0, 4); + add(e2d, 605, 8, 312, 2, 0); + add(e2d, 605, 7, 312, 2, 1); + add(e2d, 605, 6, 312, 2, 2); + add(e2d, 605, 5, 312, 2, 3); + add(e2d, 605, 4, 312, 2, 4); + add(e2d, 605, 1033, 312, 4, 0); + add(e2d, 605, 1034, 312, 4, 1); + add(e2d, 605, 1035, 312, 4, 2); + add(e2d, 605, 1025, 312, 6, 0); + add(e2d, 605, 1026, 312, 6, 1); + add(e2d, 605, 1027, 312, 6, 2); + add(e2d, 605, 110, 312, 1, 0); + add(e2d, 605, 111, 312, 1, 1); + add(e2d, 605, 112, 312, 1, 2); + add(e2d, 605, 113, 312, 1, 3); + add(e2d, 605, 114, 312, 1, 4); + add(e2d, 605, 101, 312, 3, 0); + add(e2d, 605, 102, 312, 3, 1); + add(e2d, 605, 103, 312, 3, 2); + add(e2d, 605, 104, 312, 3, 3); + add(e2d, 605, 105, 312, 3, 4); + add(e2d, 605, 1142, 312, 5, 0); + add(e2d, 605, 1141, 312, 5, 1); + add(e2d, 605, 1140, 312, 5, 2); + add(e2d, 605, 1139, 312, 5, 3); + add(e2d, 605, 1133, 312, 7, 0); + add(e2d, 605, 1132, 312, 7, 1); + add(e2d, 605, 1131, 312, 7, 2); + add(e2d, 605, 1130, 312, 7, 3); + add(e2d, 606, 119, 313, 1, 0); + add(e2d, 606, 120, 313, 1, 1); + add(e2d, 606, 121, 313, 1, 2); + add(e2d, 606, 122, 313, 1, 3); + add(e2d, 606, 123, 313, 1, 4); + add(e2d, 606, 110, 313, 3, 0); + add(e2d, 606, 111, 313, 3, 1); + add(e2d, 606, 112, 313, 3, 2); + add(e2d, 606, 113, 313, 3, 3); + add(e2d, 606, 114, 313, 3, 4); + add(e2d, 606, 101, 313, 5, 0); + add(e2d, 606, 102, 313, 5, 1); + add(e2d, 606, 103, 313, 5, 2); + add(e2d, 606, 104, 313, 5, 3); + add(e2d, 606, 105, 313, 5, 4); + add(e2d, 606, 1151, 313, 0, 0); + add(e2d, 606, 1150, 313, 0, 1); + add(e2d, 606, 1149, 313, 0, 2); + add(e2d, 606, 1148, 313, 0, 3); + add(e2d, 606, 1142, 313, 2, 0); + add(e2d, 606, 1141, 313, 2, 1); + add(e2d, 606, 1140, 313, 2, 2); + add(e2d, 606, 1139, 313, 2, 3); + add(e2d, 606, 1133, 313, 4, 0); + add(e2d, 606, 1132, 313, 4, 1); + add(e2d, 606, 1131, 313, 4, 2); + add(e2d, 606, 1130, 313, 4, 3); + add(e2d, 606, 24, 314, 1, 0); + add(e2d, 606, 23, 314, 1, 1); + add(e2d, 606, 22, 314, 1, 2); + add(e2d, 606, 21, 314, 1, 3); + add(e2d, 606, 20, 314, 1, 4); + add(e2d, 606, 16, 314, 3, 0); + add(e2d, 606, 15, 314, 3, 1); + add(e2d, 606, 14, 314, 3, 2); + add(e2d, 606, 13, 314, 3, 3); + add(e2d, 606, 12, 314, 3, 4); + add(e2d, 606, 8, 314, 5, 0); + add(e2d, 606, 7, 314, 5, 1); + add(e2d, 606, 6, 314, 5, 2); + add(e2d, 606, 5, 314, 5, 3); + add(e2d, 606, 4, 314, 5, 4); + add(e2d, 606, 1041, 314, 0, 0); + add(e2d, 606, 1042, 314, 0, 1); + add(e2d, 606, 1043, 314, 0, 2); + add(e2d, 606, 1033, 314, 2, 0); + add(e2d, 606, 1034, 314, 2, 1); + add(e2d, 606, 1035, 314, 2, 2); + add(e2d, 606, 1025, 314, 4, 0); + add(e2d, 606, 1026, 314, 4, 1); + add(e2d, 606, 1027, 314, 4, 2); + add(e2d, 607, 1039, 8, 0, 0); + add(e2d, 607, 1040, 8, 0, 1); + add(e2d, 607, 1041, 8, 0, 2); + add(e2d, 607, 1035, 8, 2, 0); + add(e2d, 607, 1036, 8, 2, 1); + add(e2d, 607, 1037, 8, 2, 2); + add(e2d, 607, 1038, 8, 2, 3); + add(e2d, 607, 1141, 8, 4, 0); + add(e2d, 607, 1142, 8, 4, 1); + add(e2d, 607, 1143, 8, 4, 2); + add(e2d, 607, 1133, 8, 1, 0); + add(e2d, 607, 1134, 8, 1, 1); + add(e2d, 607, 1135, 8, 1, 2); + add(e2d, 607, 1125, 8, 3, 0); + add(e2d, 607, 1126, 8, 3, 1); + add(e2d, 607, 1127, 8, 3, 2); + add(e2d, 607, 5, 9, 0, 0); + add(e2d, 607, 4, 9, 0, 1); + add(e2d, 607, 3, 9, 0, 2); + add(e2d, 607, 2, 9, 0, 3); + add(e2d, 607, 1, 9, 0, 4); + add(e2d, 607, 10, 9, 2, 0); + add(e2d, 607, 9, 9, 2, 1); + add(e2d, 607, 8, 9, 2, 2); + add(e2d, 607, 7, 9, 2, 3); + add(e2d, 607, 6, 9, 2, 4); + add(e2d, 607, 124, 9, 4, 0); + add(e2d, 607, 123, 9, 4, 1); + add(e2d, 607, 122, 9, 4, 2); + add(e2d, 607, 121, 9, 4, 3); + add(e2d, 607, 120, 9, 4, 4); + add(e2d, 607, 116, 9, 1, 0); + add(e2d, 607, 115, 9, 1, 1); + add(e2d, 607, 114, 9, 1, 2); + add(e2d, 607, 113, 9, 1, 3); + add(e2d, 607, 112, 9, 1, 4); + add(e2d, 607, 108, 9, 3, 0); + add(e2d, 607, 107, 9, 3, 1); + add(e2d, 607, 106, 9, 3, 2); + add(e2d, 607, 105, 9, 3, 3); + add(e2d, 607, 104, 9, 3, 4); + add(e2d, 607, 1327, 10, 0, 0); + add(e2d, 607, 1326, 10, 0, 1); + add(e2d, 607, 1325, 10, 0, 2); + add(e2d, 607, 1331, 10, 2, 0); + add(e2d, 607, 1330, 10, 2, 1); + add(e2d, 607, 1329, 10, 2, 2); + add(e2d, 607, 1328, 10, 2, 3); + add(e2d, 607, 1251, 10, 4, 0); + add(e2d, 607, 1250, 10, 4, 1); + add(e2d, 607, 1249, 10, 4, 2); + add(e2d, 607, 1248, 10, 4, 3); + add(e2d, 607, 1242, 10, 1, 0); + add(e2d, 607, 1241, 10, 1, 1); + add(e2d, 607, 1240, 10, 1, 2); + add(e2d, 607, 1239, 10, 1, 3); + add(e2d, 607, 1233, 10, 3, 0); + add(e2d, 607, 1232, 10, 3, 1); + add(e2d, 607, 1231, 10, 3, 2); + add(e2d, 607, 1230, 10, 3, 3); + add(e2d, 607, 313, 11, 0, 0); + add(e2d, 607, 314, 11, 0, 1); + add(e2d, 607, 315, 11, 0, 2); + add(e2d, 607, 316, 11, 0, 3); + add(e2d, 607, 317, 11, 0, 4); + add(e2d, 607, 308, 11, 2, 0); + add(e2d, 607, 309, 11, 2, 1); + add(e2d, 607, 310, 11, 2, 2); + add(e2d, 607, 311, 11, 2, 3); + add(e2d, 607, 312, 11, 2, 4); + add(e2d, 607, 219, 11, 4, 0); + add(e2d, 607, 220, 11, 4, 1); + add(e2d, 607, 221, 11, 4, 2); + add(e2d, 607, 222, 11, 4, 3); + add(e2d, 607, 223, 11, 4, 4); + add(e2d, 607, 210, 11, 1, 0); + add(e2d, 607, 211, 11, 1, 1); + add(e2d, 607, 212, 11, 1, 2); + add(e2d, 607, 213, 11, 1, 3); + add(e2d, 607, 214, 11, 1, 4); + add(e2d, 607, 201, 11, 3, 0); + add(e2d, 607, 202, 11, 3, 1); + add(e2d, 607, 203, 11, 3, 2); + add(e2d, 607, 204, 11, 3, 3); + add(e2d, 607, 205, 11, 3, 4); + add(e2d, 608, 405, 12, 0, 0); + add(e2d, 608, 404, 12, 0, 1); + add(e2d, 608, 403, 12, 0, 2); + add(e2d, 608, 402, 12, 0, 3); + add(e2d, 608, 401, 12, 0, 4); + add(e2d, 608, 410, 12, 2, 0); + add(e2d, 608, 409, 12, 2, 1); + add(e2d, 608, 408, 12, 2, 2); + add(e2d, 608, 407, 12, 2, 3); + add(e2d, 608, 406, 12, 2, 4); + add(e2d, 608, 413, 12, 4, 0); + add(e2d, 608, 412, 12, 4, 1); + add(e2d, 608, 411, 12, 4, 2); + add(e2d, 608, 228, 12, 6, 0); + add(e2d, 608, 227, 12, 6, 1); + add(e2d, 608, 226, 12, 6, 2); + add(e2d, 608, 225, 12, 6, 3); + add(e2d, 608, 224, 12, 6, 4); + add(e2d, 608, 233, 12, 1, 0); + add(e2d, 608, 232, 12, 1, 1); + add(e2d, 608, 231, 12, 1, 2); + add(e2d, 608, 230, 12, 1, 3); + add(e2d, 608, 229, 12, 1, 4); + add(e2d, 608, 216, 12, 3, 0); + add(e2d, 608, 215, 12, 3, 1); + add(e2d, 608, 214, 12, 3, 2); + add(e2d, 608, 213, 12, 3, 3); + add(e2d, 608, 212, 12, 3, 4); + add(e2d, 608, 208, 12, 5, 0); + add(e2d, 608, 207, 12, 5, 1); + add(e2d, 608, 206, 12, 5, 2); + add(e2d, 608, 205, 12, 5, 3); + add(e2d, 608, 204, 12, 5, 4); + add(e2d, 608, 1329, 13, 0, 0); + add(e2d, 608, 1330, 13, 0, 1); + add(e2d, 608, 1331, 13, 0, 2); + add(e2d, 608, 1332, 13, 0, 3); + add(e2d, 608, 1333, 13, 0, 4); + add(e2d, 608, 1325, 13, 2, 0); + add(e2d, 608, 1326, 13, 2, 1); + add(e2d, 608, 1327, 13, 2, 2); + add(e2d, 608, 1328, 13, 2, 3); + add(e2d, 608, 1245, 13, 4, 0); + add(e2d, 608, 1246, 13, 4, 1); + add(e2d, 608, 1247, 13, 4, 2); + add(e2d, 608, 1241, 13, 1, 0); + add(e2d, 608, 1242, 13, 1, 1); + add(e2d, 608, 1243, 13, 1, 2); + add(e2d, 608, 1244, 13, 1, 3); + add(e2d, 608, 1233, 13, 3, 0); + add(e2d, 608, 1234, 13, 3, 1); + add(e2d, 608, 1235, 13, 3, 2); + add(e2d, 608, 1225, 13, 5, 0); + add(e2d, 608, 1226, 13, 5, 1); + add(e2d, 608, 1227, 13, 5, 2); + add(e2d, 608, 4, 56, 0, 0); + add(e2d, 608, 5, 56, 0, 1); + add(e2d, 608, 6, 56, 0, 2); + add(e2d, 608, 7, 56, 0, 3); + add(e2d, 608, 124, 56, 2, 0); + add(e2d, 608, 125, 56, 2, 1); + add(e2d, 608, 126, 56, 2, 2); + add(e2d, 608, 127, 56, 2, 3); + add(e2d, 608, 128, 56, 2, 4); + add(e2d, 608, 119, 56, 4, 0); + add(e2d, 608, 120, 56, 4, 1); + add(e2d, 608, 121, 56, 4, 2); + add(e2d, 608, 122, 56, 4, 3); + add(e2d, 608, 123, 56, 4, 4); + add(e2d, 608, 110, 56, 1, 0); + add(e2d, 608, 111, 56, 1, 1); + add(e2d, 608, 112, 56, 1, 2); + add(e2d, 608, 113, 56, 1, 3); + add(e2d, 608, 114, 56, 1, 4); + add(e2d, 608, 101, 56, 3, 0); + add(e2d, 608, 102, 56, 3, 1); + add(e2d, 608, 103, 56, 3, 2); + add(e2d, 608, 104, 56, 3, 3); + add(e2d, 608, 105, 56, 3, 4); + add(e2d, 608, 1027, 57, 0, 0); + add(e2d, 608, 1026, 57, 0, 1); + add(e2d, 608, 1025, 57, 0, 2); + add(e2d, 608, 1155, 57, 2, 0); + add(e2d, 608, 1154, 57, 2, 1); + add(e2d, 608, 1153, 57, 2, 2); + add(e2d, 608, 1159, 57, 4, 0); + add(e2d, 608, 1158, 57, 4, 1); + add(e2d, 608, 1157, 57, 4, 2); + add(e2d, 608, 1156, 57, 4, 3); + add(e2d, 608, 1142, 57, 1, 0); + add(e2d, 608, 1141, 57, 1, 1); + add(e2d, 608, 1140, 57, 1, 2); + add(e2d, 608, 1139, 57, 1, 3); + add(e2d, 608, 1133, 57, 3, 0); + add(e2d, 608, 1132, 57, 3, 1); + add(e2d, 608, 1131, 57, 3, 2); + add(e2d, 608, 1130, 57, 3, 3); + add(e2d, 609, 3, 58, 0, 0); + add(e2d, 609, 2, 58, 0, 1); + add(e2d, 609, 1, 58, 0, 2); + add(e2d, 609, 10, 58, 2, 0); + add(e2d, 609, 9, 58, 2, 1); + add(e2d, 609, 8, 58, 2, 2); + add(e2d, 609, 7, 58, 2, 3); + add(e2d, 609, 6, 58, 2, 4); + add(e2d, 609, 15, 58, 4, 0); + add(e2d, 609, 14, 58, 4, 1); + add(e2d, 609, 13, 58, 4, 2); + add(e2d, 609, 12, 58, 4, 3); + add(e2d, 609, 11, 58, 4, 4); + add(e2d, 609, 116, 58, 1, 0); + add(e2d, 609, 115, 58, 1, 1); + add(e2d, 609, 114, 58, 1, 2); + add(e2d, 609, 113, 58, 1, 3); + add(e2d, 609, 112, 58, 1, 4); + add(e2d, 609, 108, 58, 3, 0); + add(e2d, 609, 107, 58, 3, 1); + add(e2d, 609, 106, 58, 3, 2); + add(e2d, 609, 105, 58, 3, 3); + add(e2d, 609, 104, 58, 3, 4); + add(e2d, 609, 1028, 59, 0, 0); + add(e2d, 609, 1029, 59, 0, 1); + add(e2d, 609, 1044, 59, 2, 0); + add(e2d, 609, 1045, 59, 2, 1); + add(e2d, 609, 1046, 59, 2, 2); + add(e2d, 609, 1040, 59, 4, 0); + add(e2d, 609, 1041, 59, 4, 1); + add(e2d, 609, 1042, 59, 4, 2); + add(e2d, 609, 1043, 59, 4, 3); + add(e2d, 609, 1133, 59, 1, 0); + add(e2d, 609, 1134, 59, 1, 1); + add(e2d, 609, 1135, 59, 1, 2); + add(e2d, 609, 1125, 59, 3, 0); + add(e2d, 609, 1126, 59, 3, 1); + add(e2d, 609, 1127, 59, 3, 2); + add(e2d, 609, 304, 60, 0, 0); + add(e2d, 609, 305, 60, 0, 1); + add(e2d, 609, 306, 60, 0, 2); + add(e2d, 609, 307, 60, 0, 3); + add(e2d, 609, 320, 60, 2, 0); + add(e2d, 609, 321, 60, 2, 1); + add(e2d, 609, 322, 60, 2, 2); + add(e2d, 609, 323, 60, 2, 3); + add(e2d, 609, 324, 60, 2, 4); + add(e2d, 609, 315, 60, 4, 0); + add(e2d, 609, 316, 60, 4, 1); + add(e2d, 609, 317, 60, 4, 2); + add(e2d, 609, 318, 60, 4, 3); + add(e2d, 609, 319, 60, 4, 4); + add(e2d, 609, 210, 60, 1, 0); + add(e2d, 609, 211, 60, 1, 1); + add(e2d, 609, 212, 60, 1, 2); + add(e2d, 609, 213, 60, 1, 3); + add(e2d, 609, 214, 60, 1, 4); + add(e2d, 609, 201, 60, 3, 0); + add(e2d, 609, 202, 60, 3, 1); + add(e2d, 609, 203, 60, 3, 2); + add(e2d, 609, 204, 60, 3, 3); + add(e2d, 609, 205, 60, 3, 4); + add(e2d, 609, 1327, 61, 0, 0); + add(e2d, 609, 1326, 61, 0, 1); + add(e2d, 609, 1325, 61, 0, 2); + add(e2d, 609, 1334, 61, 2, 0); + add(e2d, 609, 1333, 61, 2, 1); + add(e2d, 609, 1332, 61, 2, 2); + add(e2d, 609, 1338, 61, 4, 0); + add(e2d, 609, 1337, 61, 4, 1); + add(e2d, 609, 1336, 61, 4, 2); + add(e2d, 609, 1335, 61, 4, 3); + add(e2d, 609, 1242, 61, 1, 0); + add(e2d, 609, 1241, 61, 1, 1); + add(e2d, 609, 1240, 61, 1, 2); + add(e2d, 609, 1239, 61, 1, 3); + add(e2d, 609, 1233, 61, 3, 0); + add(e2d, 609, 1232, 61, 3, 1); + add(e2d, 609, 1231, 61, 3, 2); + add(e2d, 609, 1230, 61, 3, 3); + add(e2d, 610, 4, 32, 0, 0); + add(e2d, 610, 5, 32, 0, 1); + add(e2d, 610, 6, 32, 0, 2); + add(e2d, 610, 7, 32, 0, 3); + add(e2d, 610, 124, 32, 2, 0); + add(e2d, 610, 125, 32, 2, 1); + add(e2d, 610, 126, 32, 2, 2); + add(e2d, 610, 127, 32, 2, 3); + add(e2d, 610, 128, 32, 2, 4); + add(e2d, 610, 119, 32, 4, 0); + add(e2d, 610, 120, 32, 4, 1); + add(e2d, 610, 121, 32, 4, 2); + add(e2d, 610, 122, 32, 4, 3); + add(e2d, 610, 123, 32, 4, 4); + add(e2d, 610, 110, 32, 1, 0); + add(e2d, 610, 111, 32, 1, 1); + add(e2d, 610, 112, 32, 1, 2); + add(e2d, 610, 113, 32, 1, 3); + add(e2d, 610, 114, 32, 1, 4); + add(e2d, 610, 101, 32, 3, 0); + add(e2d, 610, 102, 32, 3, 1); + add(e2d, 610, 103, 32, 3, 2); + add(e2d, 610, 104, 32, 3, 3); + add(e2d, 610, 105, 32, 3, 4); + add(e2d, 610, 1027, 33, 0, 0); + add(e2d, 610, 1026, 33, 0, 1); + add(e2d, 610, 1025, 33, 0, 2); + add(e2d, 610, 1155, 33, 2, 0); + add(e2d, 610, 1154, 33, 2, 1); + add(e2d, 610, 1153, 33, 2, 2); + add(e2d, 610, 1159, 33, 4, 0); + add(e2d, 610, 1158, 33, 4, 1); + add(e2d, 610, 1157, 33, 4, 2); + add(e2d, 610, 1156, 33, 4, 3); + add(e2d, 610, 1142, 33, 1, 0); + add(e2d, 610, 1141, 33, 1, 1); + add(e2d, 610, 1140, 33, 1, 2); + add(e2d, 610, 1139, 33, 1, 3); + add(e2d, 610, 1133, 33, 3, 0); + add(e2d, 610, 1132, 33, 3, 1); + add(e2d, 610, 1131, 33, 3, 2); + add(e2d, 610, 1130, 33, 3, 3); + add(e2d, 610, 405, 34, 0, 0); + add(e2d, 610, 404, 34, 0, 1); + add(e2d, 610, 403, 34, 0, 2); + add(e2d, 610, 402, 34, 0, 3); + add(e2d, 610, 401, 34, 0, 4); + add(e2d, 610, 410, 34, 2, 0); + add(e2d, 610, 409, 34, 2, 1); + add(e2d, 610, 408, 34, 2, 2); + add(e2d, 610, 407, 34, 2, 3); + add(e2d, 610, 406, 34, 2, 4); + add(e2d, 610, 413, 34, 4, 0); + add(e2d, 610, 412, 34, 4, 1); + add(e2d, 610, 411, 34, 4, 2); + add(e2d, 610, 228, 34, 6, 0); + add(e2d, 610, 227, 34, 6, 1); + add(e2d, 610, 226, 34, 6, 2); + add(e2d, 610, 225, 34, 6, 3); + add(e2d, 610, 224, 34, 6, 4); + add(e2d, 610, 233, 34, 1, 0); + add(e2d, 610, 232, 34, 1, 1); + add(e2d, 610, 231, 34, 1, 2); + add(e2d, 610, 230, 34, 1, 3); + add(e2d, 610, 229, 34, 1, 4); + add(e2d, 610, 216, 34, 3, 0); + add(e2d, 610, 215, 34, 3, 1); + add(e2d, 610, 214, 34, 3, 2); + add(e2d, 610, 213, 34, 3, 3); + add(e2d, 610, 212, 34, 3, 4); + add(e2d, 610, 208, 34, 5, 0); + add(e2d, 610, 207, 34, 5, 1); + add(e2d, 610, 206, 34, 5, 2); + add(e2d, 610, 205, 34, 5, 3); + add(e2d, 610, 204, 34, 5, 4); + add(e2d, 610, 1329, 35, 0, 0); + add(e2d, 610, 1330, 35, 0, 1); + add(e2d, 610, 1331, 35, 0, 2); + add(e2d, 610, 1332, 35, 0, 3); + add(e2d, 610, 1333, 35, 0, 4); + add(e2d, 610, 1325, 35, 2, 0); + add(e2d, 610, 1326, 35, 2, 1); + add(e2d, 610, 1327, 35, 2, 2); + add(e2d, 610, 1328, 35, 2, 3); + add(e2d, 610, 1245, 35, 4, 0); + add(e2d, 610, 1246, 35, 4, 1); + add(e2d, 610, 1247, 35, 4, 2); + add(e2d, 610, 1241, 35, 1, 0); + add(e2d, 610, 1242, 35, 1, 1); + add(e2d, 610, 1243, 35, 1, 2); + add(e2d, 610, 1244, 35, 1, 3); + add(e2d, 610, 1233, 35, 3, 0); + add(e2d, 610, 1234, 35, 3, 1); + add(e2d, 610, 1235, 35, 3, 2); + add(e2d, 610, 1225, 35, 5, 0); + add(e2d, 610, 1226, 35, 5, 1); + add(e2d, 610, 1227, 35, 5, 2); + add(e2d, 611, 5, 36, 0, 0); + add(e2d, 611, 4, 36, 0, 1); + add(e2d, 611, 3, 36, 0, 2); + add(e2d, 611, 2, 36, 0, 3); + add(e2d, 611, 1, 36, 0, 4); + add(e2d, 611, 10, 36, 2, 0); + add(e2d, 611, 9, 36, 2, 1); + add(e2d, 611, 8, 36, 2, 2); + add(e2d, 611, 7, 36, 2, 3); + add(e2d, 611, 6, 36, 2, 4); + add(e2d, 611, 124, 36, 4, 0); + add(e2d, 611, 123, 36, 4, 1); + add(e2d, 611, 122, 36, 4, 2); + add(e2d, 611, 121, 36, 4, 3); + add(e2d, 611, 120, 36, 4, 4); + add(e2d, 611, 116, 36, 1, 0); + add(e2d, 611, 115, 36, 1, 1); + add(e2d, 611, 114, 36, 1, 2); + add(e2d, 611, 113, 36, 1, 3); + add(e2d, 611, 112, 36, 1, 4); + add(e2d, 611, 108, 36, 3, 0); + add(e2d, 611, 107, 36, 3, 1); + add(e2d, 611, 106, 36, 3, 2); + add(e2d, 611, 105, 36, 3, 3); + add(e2d, 611, 104, 36, 3, 4); + add(e2d, 611, 1039, 37, 0, 0); + add(e2d, 611, 1040, 37, 0, 1); + add(e2d, 611, 1041, 37, 0, 2); + add(e2d, 611, 1035, 37, 2, 0); + add(e2d, 611, 1036, 37, 2, 1); + add(e2d, 611, 1037, 37, 2, 2); + add(e2d, 611, 1038, 37, 2, 3); + add(e2d, 611, 1141, 37, 4, 0); + add(e2d, 611, 1142, 37, 4, 1); + add(e2d, 611, 1143, 37, 4, 2); + add(e2d, 611, 1133, 37, 1, 0); + add(e2d, 611, 1134, 37, 1, 1); + add(e2d, 611, 1135, 37, 1, 2); + add(e2d, 611, 1125, 37, 3, 0); + add(e2d, 611, 1126, 37, 3, 1); + add(e2d, 611, 1127, 37, 3, 2); + add(e2d, 611, 313, 24, 0, 0); + add(e2d, 611, 314, 24, 0, 1); + add(e2d, 611, 315, 24, 0, 2); + add(e2d, 611, 316, 24, 0, 3); + add(e2d, 611, 317, 24, 0, 4); + add(e2d, 611, 308, 24, 2, 0); + add(e2d, 611, 309, 24, 2, 1); + add(e2d, 611, 310, 24, 2, 2); + add(e2d, 611, 311, 24, 2, 3); + add(e2d, 611, 312, 24, 2, 4); + add(e2d, 611, 219, 24, 4, 0); + add(e2d, 611, 220, 24, 4, 1); + add(e2d, 611, 221, 24, 4, 2); + add(e2d, 611, 222, 24, 4, 3); + add(e2d, 611, 223, 24, 4, 4); + add(e2d, 611, 210, 24, 1, 0); + add(e2d, 611, 211, 24, 1, 1); + add(e2d, 611, 212, 24, 1, 2); + add(e2d, 611, 213, 24, 1, 3); + add(e2d, 611, 214, 24, 1, 4); + add(e2d, 611, 201, 24, 3, 0); + add(e2d, 611, 202, 24, 3, 1); + add(e2d, 611, 203, 24, 3, 2); + add(e2d, 611, 204, 24, 3, 3); + add(e2d, 611, 205, 24, 3, 4); + add(e2d, 611, 1327, 25, 0, 0); + add(e2d, 611, 1326, 25, 0, 1); + add(e2d, 611, 1325, 25, 0, 2); + add(e2d, 611, 1331, 25, 2, 0); + add(e2d, 611, 1330, 25, 2, 1); + add(e2d, 611, 1329, 25, 2, 2); + add(e2d, 611, 1328, 25, 2, 3); + add(e2d, 611, 1251, 25, 4, 0); + add(e2d, 611, 1250, 25, 4, 1); + add(e2d, 611, 1249, 25, 4, 2); + add(e2d, 611, 1248, 25, 4, 3); + add(e2d, 611, 1242, 25, 1, 0); + add(e2d, 611, 1241, 25, 1, 1); + add(e2d, 611, 1240, 25, 1, 2); + add(e2d, 611, 1239, 25, 1, 3); + add(e2d, 611, 1233, 25, 3, 0); + add(e2d, 611, 1232, 25, 3, 1); + add(e2d, 611, 1231, 25, 3, 2); + add(e2d, 611, 1230, 25, 3, 3); + add(e2d, 612, 119, 26, 1, 0); + add(e2d, 612, 120, 26, 1, 1); + add(e2d, 612, 121, 26, 1, 2); + add(e2d, 612, 122, 26, 1, 3); + add(e2d, 612, 123, 26, 1, 4); + add(e2d, 612, 110, 26, 3, 0); + add(e2d, 612, 111, 26, 3, 1); + add(e2d, 612, 112, 26, 3, 2); + add(e2d, 612, 113, 26, 3, 3); + add(e2d, 612, 114, 26, 3, 4); + add(e2d, 612, 101, 26, 5, 0); + add(e2d, 612, 102, 26, 5, 1); + add(e2d, 612, 103, 26, 5, 2); + add(e2d, 612, 104, 26, 5, 3); + add(e2d, 612, 105, 26, 5, 4); + add(e2d, 612, 1151, 26, 0, 0); + add(e2d, 612, 1150, 26, 0, 1); + add(e2d, 612, 1149, 26, 0, 2); + add(e2d, 612, 1148, 26, 0, 3); + add(e2d, 612, 1142, 26, 2, 0); + add(e2d, 612, 1141, 26, 2, 1); + add(e2d, 612, 1140, 26, 2, 2); + add(e2d, 612, 1139, 26, 2, 3); + add(e2d, 612, 1133, 26, 4, 0); + add(e2d, 612, 1132, 26, 4, 1); + add(e2d, 612, 1131, 26, 4, 2); + add(e2d, 612, 1130, 26, 4, 3); + add(e2d, 612, 24, 27, 1, 0); + add(e2d, 612, 23, 27, 1, 1); + add(e2d, 612, 22, 27, 1, 2); + add(e2d, 612, 21, 27, 1, 3); + add(e2d, 612, 20, 27, 1, 4); + add(e2d, 612, 16, 27, 3, 0); + add(e2d, 612, 15, 27, 3, 1); + add(e2d, 612, 14, 27, 3, 2); + add(e2d, 612, 13, 27, 3, 3); + add(e2d, 612, 12, 27, 3, 4); + add(e2d, 612, 8, 27, 5, 0); + add(e2d, 612, 7, 27, 5, 1); + add(e2d, 612, 6, 27, 5, 2); + add(e2d, 612, 5, 27, 5, 3); + add(e2d, 612, 4, 27, 5, 4); + add(e2d, 612, 1041, 27, 0, 0); + add(e2d, 612, 1042, 27, 0, 1); + add(e2d, 612, 1043, 27, 0, 2); + add(e2d, 612, 1033, 27, 2, 0); + add(e2d, 612, 1034, 27, 2, 1); + add(e2d, 612, 1035, 27, 2, 2); + add(e2d, 612, 1025, 27, 4, 0); + add(e2d, 612, 1026, 27, 4, 1); + add(e2d, 612, 1027, 27, 4, 2); + add(e2d, 613, 16, 28, 0, 0); + add(e2d, 613, 15, 28, 0, 1); + add(e2d, 613, 14, 28, 0, 2); + add(e2d, 613, 13, 28, 0, 3); + add(e2d, 613, 12, 28, 0, 4); + add(e2d, 613, 8, 28, 2, 0); + add(e2d, 613, 7, 28, 2, 1); + add(e2d, 613, 6, 28, 2, 2); + add(e2d, 613, 5, 28, 2, 3); + add(e2d, 613, 4, 28, 2, 4); + add(e2d, 613, 1033, 28, 4, 0); + add(e2d, 613, 1034, 28, 4, 1); + add(e2d, 613, 1035, 28, 4, 2); + add(e2d, 613, 1025, 28, 6, 0); + add(e2d, 613, 1026, 28, 6, 1); + add(e2d, 613, 1027, 28, 6, 2); + add(e2d, 613, 110, 28, 1, 0); + add(e2d, 613, 111, 28, 1, 1); + add(e2d, 613, 112, 28, 1, 2); + add(e2d, 613, 113, 28, 1, 3); + add(e2d, 613, 114, 28, 1, 4); + add(e2d, 613, 101, 28, 3, 0); + add(e2d, 613, 102, 28, 3, 1); + add(e2d, 613, 103, 28, 3, 2); + add(e2d, 613, 104, 28, 3, 3); + add(e2d, 613, 105, 28, 3, 4); + add(e2d, 613, 1142, 28, 5, 0); + add(e2d, 613, 1141, 28, 5, 1); + add(e2d, 613, 1140, 28, 5, 2); + add(e2d, 613, 1139, 28, 5, 3); + add(e2d, 613, 1133, 28, 7, 0); + add(e2d, 613, 1132, 28, 7, 1); + add(e2d, 613, 1131, 28, 7, 2); + add(e2d, 613, 1130, 28, 7, 3); } -void fillSolar2FeeLinkCH6L(std::map<uint16_t, uint32_t>& s2c) {} +void fillSolar2FeeLinkCH6L(std::map<uint16_t, uint32_t>& s2f) +{ + add_cru(s2f, 24, 0, 312); + add_cru(s2f, 24, 1, 313); + add_cru(s2f, 24, 2, 314); + add_cru(s2f, 24, 6, 8); + add_cru(s2f, 24, 7, 9); + add_cru(s2f, 24, 8, 10); + add_cru(s2f, 24, 9, 11); + add_cru(s2f, 24, 10, 12); + add_cru(s2f, 24, 11, 13); + add_cru(s2f, 25, 0, 56); + add_cru(s2f, 25, 1, 57); + add_cru(s2f, 25, 2, 58); + add_cru(s2f, 25, 3, 59); + add_cru(s2f, 25, 4, 60); + add_cru(s2f, 25, 5, 61); + add_cru(s2f, 26, 0, 32); + add_cru(s2f, 26, 1, 33); + add_cru(s2f, 26, 2, 34); + add_cru(s2f, 26, 3, 35); + add_cru(s2f, 26, 4, 36); + add_cru(s2f, 26, 5, 37); + add_cru(s2f, 26, 6, 24); + add_cru(s2f, 26, 7, 25); + add_cru(s2f, 26, 8, 26); + add_cru(s2f, 26, 9, 27); + add_cru(s2f, 26, 10, 28); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH6R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH6R.cxx index 88a32de96f0dc..ff6d6863d2f02 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH6R.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH6R.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -641,21 +642,21 @@ void fillSolar2FeeLinkCH6R(std::map<uint16_t, uint32_t>& s2f) add_cru(s2f, 27, 9, 363); add_cru(s2f, 27, 10, 364); add_cru(s2f, 27, 11, 365); - add_cru(s2f, 29, 0, 216); - add_cru(s2f, 29, 1, 217); - add_cru(s2f, 29, 2, 218); - add_cru(s2f, 29, 3, 219); - add_cru(s2f, 29, 4, 220); - add_cru(s2f, 29, 5, 221); - add_cru(s2f, 28, 0, 432); - add_cru(s2f, 28, 1, 433); - add_cru(s2f, 28, 2, 434); - add_cru(s2f, 28, 3, 435); - add_cru(s2f, 28, 4, 436); - add_cru(s2f, 28, 5, 437); - add_cru(s2f, 28, 6, 408); - add_cru(s2f, 28, 7, 409); - add_cru(s2f, 28, 8, 410); - add_cru(s2f, 28, 9, 411); - add_cru(s2f, 28, 10, 412); + add_cru(s2f, 28, 0, 216); + add_cru(s2f, 28, 1, 217); + add_cru(s2f, 28, 2, 218); + add_cru(s2f, 28, 3, 219); + add_cru(s2f, 28, 4, 220); + add_cru(s2f, 28, 5, 221); + add_cru(s2f, 29, 0, 432); + add_cru(s2f, 29, 1, 433); + add_cru(s2f, 29, 2, 434); + add_cru(s2f, 29, 3, 435); + add_cru(s2f, 29, 4, 436); + add_cru(s2f, 29, 5, 437); + add_cru(s2f, 29, 6, 408); + add_cru(s2f, 29, 7, 409); + add_cru(s2f, 29, 8, 410); + add_cru(s2f, 29, 9, 411); + add_cru(s2f, 29, 10, 412); } \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH7L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH7L.cxx index 42cf0de2d8c6f..1e8675bc340ba 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH7L.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH7L.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,908 +16,907 @@ #include "CH.cxx" void fillElec2DetCH7L(std::map<uint32_t, uint32_t>& e2d) { - add(e2d, 707, 8, 728, 0, 0); - add(e2d, 707, 7, 728, 0, 1); - add(e2d, 707, 4, 728, 2, 0); - add(e2d, 707, 3, 728, 2, 1); - add(e2d, 707, 1029, 728, 4, 0); - add(e2d, 707, 1030, 728, 4, 1); - add(e2d, 707, 1025, 728, 6, 0); - add(e2d, 707, 1026, 728, 6, 1); - add(e2d, 707, 106, 728, 1, 0); - add(e2d, 707, 107, 728, 1, 1); - add(e2d, 707, 108, 728, 1, 2); - add(e2d, 707, 101, 728, 3, 0); - add(e2d, 707, 102, 728, 3, 1); - add(e2d, 707, 103, 728, 3, 2); - add(e2d, 707, 1134, 728, 5, 0); - add(e2d, 707, 1133, 728, 5, 1); - add(e2d, 707, 1129, 728, 7, 0); - add(e2d, 707, 1128, 728, 7, 1); - add(e2d, 708, 111, 729, 1, 0); - add(e2d, 708, 112, 729, 1, 1); - add(e2d, 708, 113, 729, 1, 2); - add(e2d, 708, 106, 729, 3, 0); - add(e2d, 708, 107, 729, 3, 1); - add(e2d, 708, 108, 729, 3, 2); - add(e2d, 708, 101, 729, 5, 0); - add(e2d, 708, 102, 729, 5, 1); - add(e2d, 708, 103, 729, 5, 2); - add(e2d, 708, 1138, 729, 0, 0); - add(e2d, 708, 1139, 729, 0, 1); - add(e2d, 708, 1133, 729, 2, 0); - add(e2d, 708, 1134, 729, 2, 1); - add(e2d, 708, 1128, 729, 4, 0); - add(e2d, 708, 1129, 729, 4, 1); - add(e2d, 708, 12, 730, 1, 0); - add(e2d, 708, 11, 730, 1, 1); - add(e2d, 708, 8, 730, 3, 0); - add(e2d, 708, 7, 730, 3, 1); - add(e2d, 708, 4, 730, 5, 0); - add(e2d, 708, 3, 730, 5, 1); - add(e2d, 708, 1033, 730, 0, 0); - add(e2d, 708, 1034, 730, 0, 1); - add(e2d, 708, 1029, 730, 2, 0); - add(e2d, 708, 1030, 730, 2, 1); - add(e2d, 708, 1025, 730, 4, 0); - add(e2d, 708, 1026, 730, 4, 1); - add(e2d, 709, 1, 731, 1, 0); - add(e2d, 709, 2, 731, 1, 1); - add(e2d, 709, 3, 731, 1, 2); - add(e2d, 709, 4, 731, 1, 3); - add(e2d, 709, 5, 731, 1, 4); - add(e2d, 709, 116, 731, 3, 0); - add(e2d, 709, 115, 731, 3, 1); - add(e2d, 709, 114, 731, 3, 2); - add(e2d, 709, 113, 731, 3, 3); - add(e2d, 709, 112, 731, 3, 4); - add(e2d, 709, 108, 731, 5, 0); - add(e2d, 709, 107, 731, 5, 1); - add(e2d, 709, 104, 731, 7, 0); - add(e2d, 709, 103, 731, 7, 1); - add(e2d, 709, 1033, 731, 0, 0); - add(e2d, 709, 1032, 731, 0, 1); - add(e2d, 709, 1031, 731, 0, 2); - add(e2d, 709, 1030, 731, 0, 3); - add(e2d, 709, 1133, 731, 2, 0); - add(e2d, 709, 1134, 731, 2, 1); - add(e2d, 709, 1135, 731, 2, 2); - add(e2d, 709, 1129, 731, 4, 0); - add(e2d, 709, 1130, 731, 4, 1); - add(e2d, 709, 1125, 731, 6, 0); - add(e2d, 709, 1126, 731, 6, 1); - add(e2d, 709, 308, 732, 1, 0); - add(e2d, 709, 307, 732, 1, 1); - add(e2d, 709, 306, 732, 1, 2); - add(e2d, 709, 305, 732, 1, 3); - add(e2d, 709, 304, 732, 1, 4); - add(e2d, 709, 211, 732, 3, 0); - add(e2d, 709, 212, 732, 3, 1); - add(e2d, 709, 213, 732, 3, 2); - add(e2d, 709, 214, 732, 3, 3); - add(e2d, 709, 215, 732, 3, 4); - add(e2d, 709, 206, 732, 5, 0); - add(e2d, 709, 207, 732, 5, 1); - add(e2d, 709, 208, 732, 5, 2); - add(e2d, 709, 201, 732, 7, 0); - add(e2d, 709, 202, 732, 7, 1); - add(e2d, 709, 203, 732, 7, 2); - add(e2d, 709, 1325, 732, 0, 0); - add(e2d, 709, 1326, 732, 0, 1); - add(e2d, 709, 1327, 732, 0, 2); - add(e2d, 709, 1243, 732, 2, 0); - add(e2d, 709, 1242, 732, 2, 1); - add(e2d, 709, 1241, 732, 2, 2); - add(e2d, 709, 1240, 732, 2, 3); - add(e2d, 709, 1234, 732, 4, 0); - add(e2d, 709, 1233, 732, 4, 1); - add(e2d, 709, 1229, 732, 6, 0); - add(e2d, 709, 1228, 732, 6, 1); - add(e2d, 710, 308, 736, 1, 0); - add(e2d, 710, 307, 736, 1, 1); - add(e2d, 710, 306, 736, 1, 2); - add(e2d, 710, 305, 736, 1, 3); - add(e2d, 710, 304, 736, 1, 4); - add(e2d, 710, 316, 736, 3, 0); - add(e2d, 710, 315, 736, 3, 1); - add(e2d, 710, 314, 736, 3, 2); - add(e2d, 710, 313, 736, 3, 3); - add(e2d, 710, 312, 736, 3, 4); - add(e2d, 710, 211, 736, 5, 0); - add(e2d, 710, 212, 736, 5, 1); - add(e2d, 710, 213, 736, 5, 2); - add(e2d, 710, 214, 736, 5, 3); - add(e2d, 710, 215, 736, 5, 4); - add(e2d, 710, 206, 736, 0, 0); - add(e2d, 710, 207, 736, 0, 1); - add(e2d, 710, 208, 736, 0, 2); - add(e2d, 710, 201, 736, 2, 0); - add(e2d, 710, 202, 736, 2, 1); - add(e2d, 710, 203, 736, 2, 2); - add(e2d, 710, 1325, 737, 0, 0); - add(e2d, 710, 1326, 737, 0, 1); - add(e2d, 710, 1327, 737, 0, 2); - add(e2d, 710, 1333, 737, 2, 0); - add(e2d, 710, 1334, 737, 2, 1); - add(e2d, 710, 1335, 737, 2, 2); - add(e2d, 710, 1243, 737, 4, 0); - add(e2d, 710, 1242, 737, 4, 1); - add(e2d, 710, 1241, 737, 4, 2); - add(e2d, 710, 1240, 737, 4, 3); - add(e2d, 710, 1234, 737, 1, 0); - add(e2d, 710, 1233, 737, 1, 1); - add(e2d, 710, 1229, 737, 3, 0); - add(e2d, 710, 1228, 737, 3, 1); - add(e2d, 710, 1, 738, 1, 0); - add(e2d, 710, 2, 738, 1, 1); - add(e2d, 710, 3, 738, 1, 2); - add(e2d, 710, 4, 738, 1, 3); - add(e2d, 710, 5, 738, 1, 4); - add(e2d, 710, 10, 738, 3, 0); - add(e2d, 710, 11, 738, 3, 1); - add(e2d, 710, 12, 738, 3, 2); - add(e2d, 710, 13, 738, 3, 3); - add(e2d, 710, 14, 738, 3, 4); - add(e2d, 710, 116, 738, 5, 0); - add(e2d, 710, 115, 738, 5, 1); - add(e2d, 710, 114, 738, 5, 2); - add(e2d, 710, 113, 738, 5, 3); - add(e2d, 710, 112, 738, 5, 4); - add(e2d, 710, 108, 738, 0, 0); - add(e2d, 710, 107, 738, 0, 1); - add(e2d, 710, 104, 738, 2, 0); - add(e2d, 710, 103, 738, 2, 1); - add(e2d, 710, 1033, 739, 0, 0); - add(e2d, 710, 1032, 739, 0, 1); - add(e2d, 710, 1031, 739, 0, 2); - add(e2d, 710, 1030, 739, 0, 3); - add(e2d, 710, 1042, 739, 2, 0); - add(e2d, 710, 1041, 739, 2, 1); - add(e2d, 710, 1040, 739, 2, 2); - add(e2d, 710, 1039, 739, 2, 3); - add(e2d, 710, 1133, 739, 4, 0); - add(e2d, 710, 1134, 739, 4, 1); - add(e2d, 710, 1135, 739, 4, 2); - add(e2d, 710, 1129, 739, 1, 0); - add(e2d, 710, 1130, 739, 1, 1); - add(e2d, 710, 1125, 739, 3, 0); - add(e2d, 710, 1126, 739, 3, 1); - add(e2d, 711, 5, 740, 1, 0); - add(e2d, 711, 4, 740, 1, 1); - add(e2d, 711, 3, 740, 1, 2); - add(e2d, 711, 2, 740, 1, 3); - add(e2d, 711, 1, 740, 1, 4); - add(e2d, 711, 10, 740, 3, 0); - add(e2d, 711, 9, 740, 3, 1); - add(e2d, 711, 8, 740, 3, 2); - add(e2d, 711, 7, 740, 3, 3); - add(e2d, 711, 6, 740, 3, 4); - add(e2d, 711, 22, 740, 5, 0); - add(e2d, 711, 21, 740, 5, 1); - add(e2d, 711, 20, 740, 5, 2); - add(e2d, 711, 19, 740, 5, 3); - add(e2d, 711, 18, 740, 5, 4); - add(e2d, 711, 27, 740, 7, 0); - add(e2d, 711, 26, 740, 7, 1); - add(e2d, 711, 25, 740, 7, 2); - add(e2d, 711, 24, 740, 7, 3); - add(e2d, 711, 23, 740, 7, 4); - add(e2d, 711, 120, 740, 0, 0); - add(e2d, 711, 119, 740, 0, 1); - add(e2d, 711, 118, 740, 0, 2); - add(e2d, 711, 117, 740, 0, 3); - add(e2d, 711, 116, 740, 0, 4); - add(e2d, 711, 112, 740, 2, 0); - add(e2d, 711, 111, 740, 2, 1); - add(e2d, 711, 110, 740, 2, 2); - add(e2d, 711, 109, 740, 2, 3); - add(e2d, 711, 108, 740, 2, 4); - add(e2d, 711, 104, 740, 4, 0); - add(e2d, 711, 103, 740, 4, 1); - add(e2d, 711, 1039, 741, 0, 0); - add(e2d, 711, 1040, 741, 0, 1); - add(e2d, 711, 1041, 741, 0, 2); - add(e2d, 711, 1035, 741, 2, 0); - add(e2d, 711, 1036, 741, 2, 1); - add(e2d, 711, 1037, 741, 2, 2); - add(e2d, 711, 1038, 741, 2, 3); - add(e2d, 711, 1056, 741, 4, 0); - add(e2d, 711, 1057, 741, 4, 1); - add(e2d, 711, 1058, 741, 4, 2); - add(e2d, 711, 1052, 741, 6, 0); - add(e2d, 711, 1053, 741, 6, 1); - add(e2d, 711, 1054, 741, 6, 2); - add(e2d, 711, 1055, 741, 6, 3); - add(e2d, 711, 1137, 741, 1, 0); - add(e2d, 711, 1138, 741, 1, 1); - add(e2d, 711, 1139, 741, 1, 2); - add(e2d, 711, 1129, 741, 3, 0); - add(e2d, 711, 1130, 741, 3, 1); - add(e2d, 711, 1131, 741, 3, 2); - add(e2d, 711, 1125, 741, 5, 0); - add(e2d, 711, 1126, 741, 5, 1); - add(e2d, 711, 313, 776, 1, 0); - add(e2d, 711, 314, 776, 1, 1); - add(e2d, 711, 315, 776, 1, 2); - add(e2d, 711, 316, 776, 1, 3); - add(e2d, 711, 317, 776, 1, 4); - add(e2d, 711, 308, 776, 3, 0); - add(e2d, 711, 309, 776, 3, 1); - add(e2d, 711, 310, 776, 3, 2); - add(e2d, 711, 311, 776, 3, 3); - add(e2d, 711, 312, 776, 3, 4); - add(e2d, 711, 330, 776, 5, 0); - add(e2d, 711, 331, 776, 5, 1); - add(e2d, 711, 332, 776, 5, 2); - add(e2d, 711, 333, 776, 5, 3); - add(e2d, 711, 334, 776, 5, 4); - add(e2d, 711, 325, 776, 7, 0); - add(e2d, 711, 326, 776, 7, 1); - add(e2d, 711, 327, 776, 7, 2); - add(e2d, 711, 328, 776, 7, 3); - add(e2d, 711, 329, 776, 7, 4); - add(e2d, 711, 215, 776, 0, 0); - add(e2d, 711, 216, 776, 0, 1); - add(e2d, 711, 217, 776, 0, 2); - add(e2d, 711, 218, 776, 0, 3); - add(e2d, 711, 219, 776, 0, 4); - add(e2d, 711, 206, 776, 2, 0); - add(e2d, 711, 207, 776, 2, 1); - add(e2d, 711, 208, 776, 2, 2); - add(e2d, 711, 209, 776, 2, 3); - add(e2d, 711, 210, 776, 2, 4); - add(e2d, 711, 201, 776, 4, 0); - add(e2d, 711, 202, 776, 4, 1); - add(e2d, 711, 203, 776, 4, 2); - add(e2d, 711, 1327, 777, 0, 0); - add(e2d, 711, 1326, 777, 0, 1); - add(e2d, 711, 1325, 777, 0, 2); - add(e2d, 711, 1331, 777, 2, 0); - add(e2d, 711, 1330, 777, 2, 1); - add(e2d, 711, 1329, 777, 2, 2); - add(e2d, 711, 1328, 777, 2, 3); - add(e2d, 711, 1344, 777, 4, 0); - add(e2d, 711, 1343, 777, 4, 1); - add(e2d, 711, 1342, 777, 4, 2); - add(e2d, 711, 1348, 777, 6, 0); - add(e2d, 711, 1347, 777, 6, 1); - add(e2d, 711, 1346, 777, 6, 2); - add(e2d, 711, 1345, 777, 6, 3); - add(e2d, 711, 1247, 777, 1, 0); - add(e2d, 711, 1246, 777, 1, 1); - add(e2d, 711, 1245, 777, 1, 2); - add(e2d, 711, 1244, 777, 1, 3); - add(e2d, 711, 1238, 777, 3, 0); - add(e2d, 711, 1237, 777, 3, 1); - add(e2d, 711, 1236, 777, 3, 2); - add(e2d, 711, 1235, 777, 3, 3); - add(e2d, 711, 1229, 777, 5, 0); - add(e2d, 711, 1228, 777, 5, 1); - add(e2d, 712, 403, 778, 1, 0); - add(e2d, 712, 402, 778, 1, 1); - add(e2d, 712, 401, 778, 1, 2); - add(e2d, 712, 408, 778, 3, 0); - add(e2d, 712, 407, 778, 3, 1); - add(e2d, 712, 406, 778, 3, 2); - add(e2d, 712, 405, 778, 3, 3); - add(e2d, 712, 404, 778, 3, 4); - add(e2d, 712, 413, 778, 5, 0); - add(e2d, 712, 412, 778, 5, 1); - add(e2d, 712, 411, 778, 5, 2); - add(e2d, 712, 410, 778, 5, 3); - add(e2d, 712, 409, 778, 5, 4); - add(e2d, 712, 315, 778, 7, 0); - add(e2d, 712, 314, 778, 7, 1); - add(e2d, 712, 313, 778, 7, 2); - add(e2d, 712, 312, 778, 7, 3); - add(e2d, 712, 311, 778, 7, 4); - add(e2d, 712, 320, 778, 0, 0); - add(e2d, 712, 319, 778, 0, 1); - add(e2d, 712, 318, 778, 0, 2); - add(e2d, 712, 317, 778, 0, 3); - add(e2d, 712, 316, 778, 0, 4); - add(e2d, 712, 328, 778, 2, 0); - add(e2d, 712, 329, 778, 2, 1); - add(e2d, 712, 330, 778, 2, 2); - add(e2d, 712, 331, 778, 2, 3); - add(e2d, 712, 332, 778, 2, 4); - add(e2d, 712, 216, 778, 4, 0); - add(e2d, 712, 215, 778, 4, 1); - add(e2d, 712, 214, 778, 4, 2); - add(e2d, 712, 213, 778, 4, 3); - add(e2d, 712, 212, 778, 4, 4); - add(e2d, 712, 208, 778, 6, 0); - add(e2d, 712, 207, 778, 6, 1); - add(e2d, 712, 1330, 779, 0, 0); - add(e2d, 712, 1331, 779, 0, 1); - add(e2d, 712, 1332, 779, 0, 2); - add(e2d, 712, 1333, 779, 0, 3); - add(e2d, 712, 1334, 779, 0, 4); - add(e2d, 712, 1325, 779, 2, 0); - add(e2d, 712, 1326, 779, 2, 1); - add(e2d, 712, 1327, 779, 2, 2); - add(e2d, 712, 1328, 779, 2, 3); - add(e2d, 712, 1329, 779, 2, 4); - add(e2d, 712, 1349, 779, 4, 0); - add(e2d, 712, 1350, 779, 4, 1); - add(e2d, 712, 1351, 779, 4, 2); - add(e2d, 712, 1345, 779, 6, 0); - add(e2d, 712, 1346, 779, 6, 1); - add(e2d, 712, 1347, 779, 6, 2); - add(e2d, 712, 1348, 779, 6, 3); - add(e2d, 712, 1360, 779, 1, 0); - add(e2d, 712, 1359, 779, 1, 1); - add(e2d, 712, 1358, 779, 1, 2); - add(e2d, 712, 1357, 779, 1, 3); - add(e2d, 712, 1233, 779, 3, 0); - add(e2d, 712, 1234, 779, 3, 1); - add(e2d, 712, 1235, 779, 3, 2); - add(e2d, 712, 1229, 779, 5, 0); - add(e2d, 712, 1230, 779, 5, 1); - add(e2d, 712, 1225, 779, 7, 0); - add(e2d, 712, 1226, 779, 7, 1); - add(e2d, 712, 204, 780, 1, 0); - add(e2d, 712, 203, 780, 1, 1); - add(e2d, 712, 1, 780, 3, 0); - add(e2d, 712, 0, 780, 3, 1); - add(e2d, 712, 14, 780, 5, 0); - add(e2d, 712, 15, 780, 5, 1); - add(e2d, 712, 16, 780, 5, 2); - add(e2d, 712, 17, 780, 5, 3); - add(e2d, 712, 18, 780, 5, 4); - add(e2d, 712, 9, 780, 7, 0); - add(e2d, 712, 10, 780, 7, 1); - add(e2d, 712, 11, 780, 7, 2); - add(e2d, 712, 12, 780, 7, 3); - add(e2d, 712, 13, 780, 7, 4); - add(e2d, 712, 26, 780, 0, 0); - add(e2d, 712, 25, 780, 0, 1); - add(e2d, 712, 24, 780, 0, 2); - add(e2d, 712, 23, 780, 0, 3); - add(e2d, 712, 22, 780, 0, 4); - add(e2d, 712, 111, 780, 2, 0); - add(e2d, 712, 112, 780, 2, 1); - add(e2d, 712, 113, 780, 2, 2); - add(e2d, 712, 114, 780, 2, 3); - add(e2d, 712, 115, 780, 2, 4); - add(e2d, 712, 106, 780, 4, 0); - add(e2d, 712, 107, 780, 4, 1); - add(e2d, 712, 108, 780, 4, 2); - add(e2d, 712, 101, 780, 6, 0); - add(e2d, 712, 102, 780, 6, 1); - add(e2d, 712, 103, 780, 6, 2); - add(e2d, 712, 1028, 781, 0, 0); - add(e2d, 712, 1027, 781, 0, 1); - add(e2d, 712, 1026, 781, 0, 2); - add(e2d, 712, 1032, 781, 2, 0); - add(e2d, 712, 1031, 781, 2, 1); - add(e2d, 712, 1030, 781, 2, 2); - add(e2d, 712, 1029, 781, 2, 3); - add(e2d, 712, 1043, 781, 4, 0); - add(e2d, 712, 1044, 781, 4, 1); - add(e2d, 712, 1045, 781, 4, 2); - add(e2d, 712, 1143, 781, 1, 0); - add(e2d, 712, 1142, 781, 1, 1); - add(e2d, 712, 1141, 781, 1, 2); - add(e2d, 712, 1140, 781, 1, 3); - add(e2d, 712, 1134, 781, 3, 0); - add(e2d, 712, 1133, 781, 3, 1); - add(e2d, 712, 1129, 781, 5, 0); - add(e2d, 712, 1128, 781, 5, 1); - add(e2d, 713, 5, 864, 1, 0); - add(e2d, 713, 4, 864, 1, 1); - add(e2d, 713, 3, 864, 1, 2); - add(e2d, 713, 2, 864, 1, 3); - add(e2d, 713, 1, 864, 1, 4); - add(e2d, 713, 10, 864, 3, 0); - add(e2d, 713, 9, 864, 3, 1); - add(e2d, 713, 8, 864, 3, 2); - add(e2d, 713, 7, 864, 3, 3); - add(e2d, 713, 6, 864, 3, 4); - add(e2d, 713, 18, 864, 5, 0); - add(e2d, 713, 19, 864, 5, 1); - add(e2d, 713, 20, 864, 5, 2); - add(e2d, 713, 21, 864, 5, 3); - add(e2d, 713, 22, 864, 5, 4); - add(e2d, 713, 116, 864, 0, 0); - add(e2d, 713, 115, 864, 0, 1); - add(e2d, 713, 114, 864, 0, 2); - add(e2d, 713, 113, 864, 0, 3); - add(e2d, 713, 112, 864, 0, 4); - add(e2d, 713, 108, 864, 2, 0); - add(e2d, 713, 107, 864, 2, 1); - add(e2d, 713, 104, 864, 4, 0); - add(e2d, 713, 103, 864, 4, 1); - add(e2d, 713, 1039, 865, 0, 0); - add(e2d, 713, 1040, 865, 0, 1); - add(e2d, 713, 1041, 865, 0, 2); - add(e2d, 713, 1035, 865, 2, 0); - add(e2d, 713, 1036, 865, 2, 1); - add(e2d, 713, 1037, 865, 2, 2); - add(e2d, 713, 1038, 865, 2, 3); - add(e2d, 713, 1050, 865, 4, 0); - add(e2d, 713, 1049, 865, 4, 1); - add(e2d, 713, 1048, 865, 4, 2); - add(e2d, 713, 1047, 865, 4, 3); - add(e2d, 713, 1133, 865, 1, 0); - add(e2d, 713, 1134, 865, 1, 1); - add(e2d, 713, 1135, 865, 1, 2); - add(e2d, 713, 1129, 865, 3, 0); - add(e2d, 713, 1130, 865, 3, 1); - add(e2d, 713, 1125, 865, 5, 0); - add(e2d, 713, 1126, 865, 5, 1); - add(e2d, 713, 313, 866, 1, 0); - add(e2d, 713, 314, 866, 1, 1); - add(e2d, 713, 315, 866, 1, 2); - add(e2d, 713, 316, 866, 1, 3); - add(e2d, 713, 317, 866, 1, 4); - add(e2d, 713, 308, 866, 3, 0); - add(e2d, 713, 309, 866, 3, 1); - add(e2d, 713, 310, 866, 3, 2); - add(e2d, 713, 311, 866, 3, 3); - add(e2d, 713, 312, 866, 3, 4); - add(e2d, 713, 325, 866, 5, 0); - add(e2d, 713, 324, 866, 5, 1); - add(e2d, 713, 323, 866, 5, 2); - add(e2d, 713, 322, 866, 5, 3); - add(e2d, 713, 321, 866, 5, 4); - add(e2d, 713, 211, 866, 0, 0); - add(e2d, 713, 212, 866, 0, 1); - add(e2d, 713, 213, 866, 0, 2); - add(e2d, 713, 214, 866, 0, 3); - add(e2d, 713, 215, 866, 0, 4); - add(e2d, 713, 206, 866, 2, 0); - add(e2d, 713, 207, 866, 2, 1); - add(e2d, 713, 208, 866, 2, 2); - add(e2d, 713, 201, 866, 4, 0); - add(e2d, 713, 202, 866, 4, 1); - add(e2d, 713, 203, 866, 4, 2); - add(e2d, 713, 1327, 867, 0, 0); - add(e2d, 713, 1326, 867, 0, 1); - add(e2d, 713, 1325, 867, 0, 2); - add(e2d, 713, 1331, 867, 2, 0); - add(e2d, 713, 1330, 867, 2, 1); - add(e2d, 713, 1329, 867, 2, 2); - add(e2d, 713, 1328, 867, 2, 3); - add(e2d, 713, 1342, 867, 4, 0); - add(e2d, 713, 1343, 867, 4, 1); - add(e2d, 713, 1344, 867, 4, 2); - add(e2d, 713, 1243, 867, 1, 0); - add(e2d, 713, 1242, 867, 1, 1); - add(e2d, 713, 1241, 867, 1, 2); - add(e2d, 713, 1240, 867, 1, 3); - add(e2d, 713, 1234, 867, 3, 0); - add(e2d, 713, 1233, 867, 3, 1); - add(e2d, 713, 1229, 867, 5, 0); - add(e2d, 713, 1228, 867, 5, 1); - add(e2d, 714, 1, 352, 1, 0); - add(e2d, 714, 0, 352, 1, 1); - add(e2d, 714, 204, 352, 3, 0); - add(e2d, 714, 203, 352, 3, 1); - add(e2d, 714, 14, 352, 5, 0); - add(e2d, 714, 15, 352, 5, 1); - add(e2d, 714, 16, 352, 5, 2); - add(e2d, 714, 17, 352, 5, 3); - add(e2d, 714, 18, 352, 5, 4); - add(e2d, 714, 9, 352, 7, 0); - add(e2d, 714, 10, 352, 7, 1); - add(e2d, 714, 11, 352, 7, 2); - add(e2d, 714, 12, 352, 7, 3); - add(e2d, 714, 13, 352, 7, 4); - add(e2d, 714, 26, 352, 0, 0); - add(e2d, 714, 25, 352, 0, 1); - add(e2d, 714, 24, 352, 0, 2); - add(e2d, 714, 23, 352, 0, 3); - add(e2d, 714, 22, 352, 0, 4); - add(e2d, 714, 111, 352, 2, 0); - add(e2d, 714, 112, 352, 2, 1); - add(e2d, 714, 113, 352, 2, 2); - add(e2d, 714, 114, 352, 2, 3); - add(e2d, 714, 115, 352, 2, 4); - add(e2d, 714, 106, 352, 4, 0); - add(e2d, 714, 107, 352, 4, 1); - add(e2d, 714, 108, 352, 4, 2); - add(e2d, 714, 101, 352, 6, 0); - add(e2d, 714, 102, 352, 6, 1); - add(e2d, 714, 103, 352, 6, 2); - add(e2d, 714, 1028, 353, 0, 0); - add(e2d, 714, 1027, 353, 0, 1); - add(e2d, 714, 1026, 353, 0, 2); - add(e2d, 714, 1032, 353, 2, 0); - add(e2d, 714, 1031, 353, 2, 1); - add(e2d, 714, 1030, 353, 2, 2); - add(e2d, 714, 1029, 353, 2, 3); - add(e2d, 714, 1043, 353, 4, 0); - add(e2d, 714, 1044, 353, 4, 1); - add(e2d, 714, 1045, 353, 4, 2); - add(e2d, 714, 1143, 353, 1, 0); - add(e2d, 714, 1142, 353, 1, 1); - add(e2d, 714, 1141, 353, 1, 2); - add(e2d, 714, 1140, 353, 1, 3); - add(e2d, 714, 1134, 353, 3, 0); - add(e2d, 714, 1133, 353, 3, 1); - add(e2d, 714, 1129, 353, 5, 0); - add(e2d, 714, 1128, 353, 5, 1); - add(e2d, 714, 403, 354, 1, 0); - add(e2d, 714, 402, 354, 1, 1); - add(e2d, 714, 401, 354, 1, 2); - add(e2d, 714, 408, 354, 3, 0); - add(e2d, 714, 407, 354, 3, 1); - add(e2d, 714, 406, 354, 3, 2); - add(e2d, 714, 405, 354, 3, 3); - add(e2d, 714, 404, 354, 3, 4); - add(e2d, 714, 413, 354, 5, 0); - add(e2d, 714, 412, 354, 5, 1); - add(e2d, 714, 411, 354, 5, 2); - add(e2d, 714, 410, 354, 5, 3); - add(e2d, 714, 409, 354, 5, 4); - add(e2d, 714, 315, 354, 7, 0); - add(e2d, 714, 314, 354, 7, 1); - add(e2d, 714, 313, 354, 7, 2); - add(e2d, 714, 312, 354, 7, 3); - add(e2d, 714, 311, 354, 7, 4); - add(e2d, 714, 320, 354, 0, 0); - add(e2d, 714, 319, 354, 0, 1); - add(e2d, 714, 318, 354, 0, 2); - add(e2d, 714, 317, 354, 0, 3); - add(e2d, 714, 316, 354, 0, 4); - add(e2d, 714, 328, 354, 2, 0); - add(e2d, 714, 329, 354, 2, 1); - add(e2d, 714, 330, 354, 2, 2); - add(e2d, 714, 331, 354, 2, 3); - add(e2d, 714, 332, 354, 2, 4); - add(e2d, 714, 216, 354, 4, 0); - add(e2d, 714, 215, 354, 4, 1); - add(e2d, 714, 214, 354, 4, 2); - add(e2d, 714, 213, 354, 4, 3); - add(e2d, 714, 212, 354, 4, 4); - add(e2d, 714, 208, 354, 6, 0); - add(e2d, 714, 207, 354, 6, 1); - add(e2d, 714, 1330, 355, 0, 0); - add(e2d, 714, 1331, 355, 0, 1); - add(e2d, 714, 1332, 355, 0, 2); - add(e2d, 714, 1333, 355, 0, 3); - add(e2d, 714, 1334, 355, 0, 4); - add(e2d, 714, 1325, 355, 2, 0); - add(e2d, 714, 1326, 355, 2, 1); - add(e2d, 714, 1327, 355, 2, 2); - add(e2d, 714, 1328, 355, 2, 3); - add(e2d, 714, 1329, 355, 2, 4); - add(e2d, 714, 1349, 355, 4, 0); - add(e2d, 714, 1350, 355, 4, 1); - add(e2d, 714, 1351, 355, 4, 2); - add(e2d, 714, 1345, 355, 6, 0); - add(e2d, 714, 1346, 355, 6, 1); - add(e2d, 714, 1347, 355, 6, 2); - add(e2d, 714, 1348, 355, 6, 3); - add(e2d, 714, 1360, 355, 1, 0); - add(e2d, 714, 1359, 355, 1, 1); - add(e2d, 714, 1358, 355, 1, 2); - add(e2d, 714, 1357, 355, 1, 3); - add(e2d, 714, 1233, 355, 3, 0); - add(e2d, 714, 1234, 355, 3, 1); - add(e2d, 714, 1235, 355, 3, 2); - add(e2d, 714, 1229, 355, 5, 0); - add(e2d, 714, 1230, 355, 5, 1); - add(e2d, 714, 1225, 355, 7, 0); - add(e2d, 714, 1226, 355, 7, 1); - add(e2d, 715, 5, 356, 1, 0); - add(e2d, 715, 4, 356, 1, 1); - add(e2d, 715, 3, 356, 1, 2); - add(e2d, 715, 2, 356, 1, 3); - add(e2d, 715, 1, 356, 1, 4); - add(e2d, 715, 10, 356, 3, 0); - add(e2d, 715, 9, 356, 3, 1); - add(e2d, 715, 8, 356, 3, 2); - add(e2d, 715, 7, 356, 3, 3); - add(e2d, 715, 6, 356, 3, 4); - add(e2d, 715, 22, 356, 5, 0); - add(e2d, 715, 21, 356, 5, 1); - add(e2d, 715, 20, 356, 5, 2); - add(e2d, 715, 19, 356, 5, 3); - add(e2d, 715, 18, 356, 5, 4); - add(e2d, 715, 27, 356, 7, 0); - add(e2d, 715, 26, 356, 7, 1); - add(e2d, 715, 25, 356, 7, 2); - add(e2d, 715, 24, 356, 7, 3); - add(e2d, 715, 23, 356, 7, 4); - add(e2d, 715, 120, 356, 0, 0); - add(e2d, 715, 119, 356, 0, 1); - add(e2d, 715, 118, 356, 0, 2); - add(e2d, 715, 117, 356, 0, 3); - add(e2d, 715, 116, 356, 0, 4); - add(e2d, 715, 112, 356, 2, 0); - add(e2d, 715, 111, 356, 2, 1); - add(e2d, 715, 110, 356, 2, 2); - add(e2d, 715, 109, 356, 2, 3); - add(e2d, 715, 108, 356, 2, 4); - add(e2d, 715, 104, 356, 4, 0); - add(e2d, 715, 103, 356, 4, 1); - add(e2d, 715, 1039, 357, 0, 0); - add(e2d, 715, 1040, 357, 0, 1); - add(e2d, 715, 1041, 357, 0, 2); - add(e2d, 715, 1035, 357, 2, 0); - add(e2d, 715, 1036, 357, 2, 1); - add(e2d, 715, 1037, 357, 2, 2); - add(e2d, 715, 1038, 357, 2, 3); - add(e2d, 715, 1056, 357, 4, 0); - add(e2d, 715, 1057, 357, 4, 1); - add(e2d, 715, 1058, 357, 4, 2); - add(e2d, 715, 1052, 357, 6, 0); - add(e2d, 715, 1053, 357, 6, 1); - add(e2d, 715, 1054, 357, 6, 2); - add(e2d, 715, 1055, 357, 6, 3); - add(e2d, 715, 1137, 357, 1, 0); - add(e2d, 715, 1138, 357, 1, 1); - add(e2d, 715, 1139, 357, 1, 2); - add(e2d, 715, 1129, 357, 3, 0); - add(e2d, 715, 1130, 357, 3, 1); - add(e2d, 715, 1131, 357, 3, 2); - add(e2d, 715, 1125, 357, 5, 0); - add(e2d, 715, 1126, 357, 5, 1); - add(e2d, 715, 1127, 357, 5, 2); - add(e2d, 715, 313, 304, 1, 0); - add(e2d, 715, 314, 304, 1, 1); - add(e2d, 715, 315, 304, 1, 2); - add(e2d, 715, 316, 304, 1, 3); - add(e2d, 715, 317, 304, 1, 4); - add(e2d, 715, 308, 304, 3, 0); - add(e2d, 715, 309, 304, 3, 1); - add(e2d, 715, 310, 304, 3, 2); - add(e2d, 715, 311, 304, 3, 3); - add(e2d, 715, 312, 304, 3, 4); - add(e2d, 715, 330, 304, 5, 0); - add(e2d, 715, 331, 304, 5, 1); - add(e2d, 715, 332, 304, 5, 2); - add(e2d, 715, 333, 304, 5, 3); - add(e2d, 715, 334, 304, 5, 4); - add(e2d, 715, 325, 304, 7, 0); - add(e2d, 715, 326, 304, 7, 1); - add(e2d, 715, 327, 304, 7, 2); - add(e2d, 715, 328, 304, 7, 3); - add(e2d, 715, 329, 304, 7, 4); - add(e2d, 715, 215, 304, 0, 0); - add(e2d, 715, 216, 304, 0, 1); - add(e2d, 715, 217, 304, 0, 2); - add(e2d, 715, 218, 304, 0, 3); - add(e2d, 715, 219, 304, 0, 4); - add(e2d, 715, 206, 304, 2, 0); - add(e2d, 715, 207, 304, 2, 1); - add(e2d, 715, 208, 304, 2, 2); - add(e2d, 715, 209, 304, 2, 3); - add(e2d, 715, 210, 304, 2, 4); - add(e2d, 715, 201, 304, 4, 0); - add(e2d, 715, 202, 304, 4, 1); - add(e2d, 715, 203, 304, 4, 2); - add(e2d, 715, 1327, 305, 0, 0); - add(e2d, 715, 1326, 305, 0, 1); - add(e2d, 715, 1325, 305, 0, 2); - add(e2d, 715, 1331, 305, 2, 0); - add(e2d, 715, 1330, 305, 2, 1); - add(e2d, 715, 1329, 305, 2, 2); - add(e2d, 715, 1328, 305, 2, 3); - add(e2d, 715, 1344, 305, 4, 0); - add(e2d, 715, 1343, 305, 4, 1); - add(e2d, 715, 1342, 305, 4, 2); - add(e2d, 715, 1348, 305, 6, 0); - add(e2d, 715, 1347, 305, 6, 1); - add(e2d, 715, 1346, 305, 6, 2); - add(e2d, 715, 1345, 305, 6, 3); - add(e2d, 715, 1247, 305, 1, 0); - add(e2d, 715, 1246, 305, 1, 1); - add(e2d, 715, 1245, 305, 1, 2); - add(e2d, 715, 1244, 305, 1, 3); - add(e2d, 715, 1238, 305, 3, 0); - add(e2d, 715, 1237, 305, 3, 1); - add(e2d, 715, 1236, 305, 3, 2); - add(e2d, 715, 1235, 305, 3, 3); - add(e2d, 715, 1229, 305, 5, 0); - add(e2d, 715, 1228, 305, 5, 1); - add(e2d, 716, 308, 306, 1, 0); - add(e2d, 716, 307, 306, 1, 1); - add(e2d, 716, 306, 306, 1, 2); - add(e2d, 716, 305, 306, 1, 3); - add(e2d, 716, 304, 306, 1, 4); - add(e2d, 716, 316, 306, 3, 0); - add(e2d, 716, 315, 306, 3, 1); - add(e2d, 716, 314, 306, 3, 2); - add(e2d, 716, 313, 306, 3, 3); - add(e2d, 716, 312, 306, 3, 4); - add(e2d, 716, 211, 306, 5, 0); - add(e2d, 716, 212, 306, 5, 1); - add(e2d, 716, 213, 306, 5, 2); - add(e2d, 716, 214, 306, 5, 3); - add(e2d, 716, 215, 306, 5, 4); - add(e2d, 716, 206, 306, 0, 0); - add(e2d, 716, 207, 306, 0, 1); - add(e2d, 716, 208, 306, 0, 2); - add(e2d, 716, 201, 306, 2, 0); - add(e2d, 716, 202, 306, 2, 1); - add(e2d, 716, 203, 306, 2, 2); - add(e2d, 716, 1325, 307, 0, 0); - add(e2d, 716, 1326, 307, 0, 1); - add(e2d, 716, 1327, 307, 0, 2); - add(e2d, 716, 1333, 307, 2, 0); - add(e2d, 716, 1334, 307, 2, 1); - add(e2d, 716, 1335, 307, 2, 2); - add(e2d, 716, 1243, 307, 4, 0); - add(e2d, 716, 1242, 307, 4, 1); - add(e2d, 716, 1241, 307, 4, 2); - add(e2d, 716, 1240, 307, 4, 3); - add(e2d, 716, 1234, 307, 1, 0); - add(e2d, 716, 1233, 307, 1, 1); - add(e2d, 716, 1229, 307, 3, 0); - add(e2d, 716, 1228, 307, 3, 1); - add(e2d, 716, 1, 308, 1, 0); - add(e2d, 716, 2, 308, 1, 1); - add(e2d, 716, 3, 308, 1, 2); - add(e2d, 716, 4, 308, 1, 3); - add(e2d, 716, 5, 308, 1, 4); - add(e2d, 716, 10, 308, 3, 0); - add(e2d, 716, 11, 308, 3, 1); - add(e2d, 716, 12, 308, 3, 2); - add(e2d, 716, 13, 308, 3, 3); - add(e2d, 716, 14, 308, 3, 4); - add(e2d, 716, 116, 308, 5, 0); - add(e2d, 716, 115, 308, 5, 1); - add(e2d, 716, 114, 308, 5, 2); - add(e2d, 716, 113, 308, 5, 3); - add(e2d, 716, 112, 308, 5, 4); - add(e2d, 716, 108, 308, 0, 0); - add(e2d, 716, 107, 308, 0, 1); - add(e2d, 716, 104, 308, 2, 0); - add(e2d, 716, 103, 308, 2, 1); - add(e2d, 716, 1033, 309, 0, 0); - add(e2d, 716, 1032, 309, 0, 1); - add(e2d, 716, 1031, 309, 0, 2); - add(e2d, 716, 1030, 309, 0, 3); - add(e2d, 716, 1042, 309, 2, 0); - add(e2d, 716, 1041, 309, 2, 1); - add(e2d, 716, 1040, 309, 2, 2); - add(e2d, 716, 1039, 309, 2, 3); - add(e2d, 716, 1133, 309, 4, 0); - add(e2d, 716, 1134, 309, 4, 1); - add(e2d, 716, 1135, 309, 4, 2); - add(e2d, 716, 1129, 309, 1, 0); - add(e2d, 716, 1130, 309, 1, 1); - add(e2d, 716, 1125, 309, 3, 0); - add(e2d, 716, 1126, 309, 3, 1); - add(e2d, 717, 1, 856, 1, 0); - add(e2d, 717, 2, 856, 1, 1); - add(e2d, 717, 3, 856, 1, 2); - add(e2d, 717, 4, 856, 1, 3); - add(e2d, 717, 5, 856, 1, 4); - add(e2d, 717, 116, 856, 3, 0); - add(e2d, 717, 115, 856, 3, 1); - add(e2d, 717, 114, 856, 3, 2); - add(e2d, 717, 113, 856, 3, 3); - add(e2d, 717, 112, 856, 3, 4); - add(e2d, 717, 108, 856, 5, 0); - add(e2d, 717, 107, 856, 5, 1); - add(e2d, 717, 104, 856, 7, 0); - add(e2d, 717, 103, 856, 7, 1); - add(e2d, 717, 1033, 856, 0, 0); - add(e2d, 717, 1032, 856, 0, 1); - add(e2d, 717, 1031, 856, 0, 2); - add(e2d, 717, 1030, 856, 0, 3); - add(e2d, 717, 1133, 856, 2, 0); - add(e2d, 717, 1134, 856, 2, 1); - add(e2d, 717, 1135, 856, 2, 2); - add(e2d, 717, 1129, 856, 4, 0); - add(e2d, 717, 1130, 856, 4, 1); - add(e2d, 717, 1125, 856, 6, 0); - add(e2d, 717, 1126, 856, 6, 1); - add(e2d, 717, 308, 857, 1, 0); - add(e2d, 717, 307, 857, 1, 1); - add(e2d, 717, 306, 857, 1, 2); - add(e2d, 717, 305, 857, 1, 3); - add(e2d, 717, 304, 857, 1, 4); - add(e2d, 717, 211, 857, 3, 0); - add(e2d, 717, 212, 857, 3, 1); - add(e2d, 717, 213, 857, 3, 2); - add(e2d, 717, 214, 857, 3, 3); - add(e2d, 717, 215, 857, 3, 4); - add(e2d, 717, 206, 857, 5, 0); - add(e2d, 717, 207, 857, 5, 1); - add(e2d, 717, 208, 857, 5, 2); - add(e2d, 717, 201, 857, 7, 0); - add(e2d, 717, 202, 857, 7, 1); - add(e2d, 717, 203, 857, 7, 2); - add(e2d, 717, 1325, 857, 0, 0); - add(e2d, 717, 1326, 857, 0, 1); - add(e2d, 717, 1327, 857, 0, 2); - add(e2d, 717, 1243, 857, 2, 0); - add(e2d, 717, 1242, 857, 2, 1); - add(e2d, 717, 1241, 857, 2, 2); - add(e2d, 717, 1240, 857, 2, 3); - add(e2d, 717, 1234, 857, 4, 0); - add(e2d, 717, 1233, 857, 4, 1); - add(e2d, 717, 1229, 857, 6, 0); - add(e2d, 717, 1228, 857, 6, 1); - add(e2d, 718, 111, 858, 1, 0); - add(e2d, 718, 112, 858, 1, 1); - add(e2d, 718, 113, 858, 1, 2); - add(e2d, 718, 106, 858, 3, 0); - add(e2d, 718, 107, 858, 3, 1); - add(e2d, 718, 108, 858, 3, 2); - add(e2d, 718, 101, 858, 5, 0); - add(e2d, 718, 102, 858, 5, 1); - add(e2d, 718, 103, 858, 5, 2); - add(e2d, 718, 1138, 858, 0, 0); - add(e2d, 718, 1139, 858, 0, 1); - add(e2d, 718, 1133, 858, 2, 0); - add(e2d, 718, 1134, 858, 2, 1); - add(e2d, 718, 1128, 858, 4, 0); - add(e2d, 718, 1129, 858, 4, 1); - add(e2d, 718, 12, 859, 1, 0); - add(e2d, 718, 11, 859, 1, 1); - add(e2d, 718, 8, 859, 3, 0); - add(e2d, 718, 7, 859, 3, 1); - add(e2d, 718, 4, 859, 5, 0); - add(e2d, 718, 3, 859, 5, 1); - add(e2d, 718, 1033, 859, 0, 0); - add(e2d, 718, 1034, 859, 0, 1); - add(e2d, 718, 1029, 859, 2, 0); - add(e2d, 718, 1030, 859, 2, 1); - add(e2d, 718, 1025, 859, 4, 0); - add(e2d, 718, 1026, 859, 4, 1); - add(e2d, 719, 8, 860, 1, 0); - add(e2d, 719, 7, 860, 1, 1); - add(e2d, 719, 4, 860, 3, 0); - add(e2d, 719, 3, 860, 3, 1); - add(e2d, 719, 1029, 860, 5, 0); - add(e2d, 719, 1030, 860, 5, 1); - add(e2d, 719, 1025, 860, 7, 0); - add(e2d, 719, 1026, 860, 7, 1); - add(e2d, 719, 106, 860, 0, 0); - add(e2d, 719, 107, 860, 0, 1); - add(e2d, 719, 108, 860, 0, 2); - add(e2d, 719, 101, 860, 2, 0); - add(e2d, 719, 102, 860, 2, 1); - add(e2d, 719, 103, 860, 2, 2); - add(e2d, 719, 1134, 860, 4, 0); - add(e2d, 719, 1133, 860, 4, 1); - add(e2d, 719, 1129, 860, 6, 0); - add(e2d, 719, 1128, 860, 6, 1); + add(e2d, 707, 8, 720, 0, 0); + add(e2d, 707, 7, 720, 0, 1); + add(e2d, 707, 4, 720, 2, 0); + add(e2d, 707, 3, 720, 2, 1); + add(e2d, 707, 1029, 720, 4, 0); + add(e2d, 707, 1030, 720, 4, 1); + add(e2d, 707, 1025, 720, 6, 0); + add(e2d, 707, 1026, 720, 6, 1); + add(e2d, 707, 106, 720, 1, 0); + add(e2d, 707, 107, 720, 1, 1); + add(e2d, 707, 108, 720, 1, 2); + add(e2d, 707, 101, 720, 3, 0); + add(e2d, 707, 102, 720, 3, 1); + add(e2d, 707, 103, 720, 3, 2); + add(e2d, 707, 1134, 720, 5, 0); + add(e2d, 707, 1133, 720, 5, 1); + add(e2d, 707, 1129, 720, 7, 0); + add(e2d, 707, 1128, 720, 7, 1); + add(e2d, 708, 111, 721, 1, 0); + add(e2d, 708, 112, 721, 1, 1); + add(e2d, 708, 113, 721, 1, 2); + add(e2d, 708, 106, 721, 3, 0); + add(e2d, 708, 107, 721, 3, 1); + add(e2d, 708, 108, 721, 3, 2); + add(e2d, 708, 101, 721, 5, 0); + add(e2d, 708, 102, 721, 5, 1); + add(e2d, 708, 103, 721, 5, 2); + add(e2d, 708, 1139, 721, 0, 0); + add(e2d, 708, 1138, 721, 0, 1); + add(e2d, 708, 1134, 721, 2, 0); + add(e2d, 708, 1133, 721, 2, 1); + add(e2d, 708, 1129, 721, 4, 0); + add(e2d, 708, 1128, 721, 4, 1); + add(e2d, 708, 12, 722, 1, 0); + add(e2d, 708, 11, 722, 1, 1); + add(e2d, 708, 8, 722, 3, 0); + add(e2d, 708, 7, 722, 3, 1); + add(e2d, 708, 4, 722, 5, 0); + add(e2d, 708, 3, 722, 5, 1); + add(e2d, 708, 1033, 722, 0, 0); + add(e2d, 708, 1034, 722, 0, 1); + add(e2d, 708, 1029, 722, 2, 0); + add(e2d, 708, 1030, 722, 2, 1); + add(e2d, 708, 1025, 722, 4, 0); + add(e2d, 708, 1026, 722, 4, 1); + add(e2d, 709, 1, 723, 0, 0); + add(e2d, 709, 2, 723, 0, 1); + add(e2d, 709, 3, 723, 0, 2); + add(e2d, 709, 4, 723, 0, 3); + add(e2d, 709, 5, 723, 0, 4); + add(e2d, 709, 116, 723, 2, 0); + add(e2d, 709, 115, 723, 2, 1); + add(e2d, 709, 114, 723, 2, 2); + add(e2d, 709, 113, 723, 2, 3); + add(e2d, 709, 112, 723, 2, 4); + add(e2d, 709, 108, 723, 4, 0); + add(e2d, 709, 107, 723, 4, 1); + add(e2d, 709, 104, 723, 6, 0); + add(e2d, 709, 103, 723, 6, 1); + add(e2d, 709, 1033, 723, 1, 0); + add(e2d, 709, 1032, 723, 1, 1); + add(e2d, 709, 1031, 723, 1, 2); + add(e2d, 709, 1030, 723, 1, 3); + add(e2d, 709, 1133, 723, 3, 0); + add(e2d, 709, 1134, 723, 3, 1); + add(e2d, 709, 1135, 723, 3, 2); + add(e2d, 709, 1129, 723, 5, 0); + add(e2d, 709, 1130, 723, 5, 1); + add(e2d, 709, 1125, 723, 7, 0); + add(e2d, 709, 1126, 723, 7, 1); + add(e2d, 709, 308, 724, 0, 0); + add(e2d, 709, 307, 724, 0, 1); + add(e2d, 709, 306, 724, 0, 2); + add(e2d, 709, 305, 724, 0, 3); + add(e2d, 709, 304, 724, 0, 4); + add(e2d, 709, 211, 724, 2, 0); + add(e2d, 709, 212, 724, 2, 1); + add(e2d, 709, 213, 724, 2, 2); + add(e2d, 709, 214, 724, 2, 3); + add(e2d, 709, 215, 724, 2, 4); + add(e2d, 709, 206, 724, 4, 0); + add(e2d, 709, 207, 724, 4, 1); + add(e2d, 709, 208, 724, 4, 2); + add(e2d, 709, 201, 724, 6, 0); + add(e2d, 709, 202, 724, 6, 1); + add(e2d, 709, 203, 724, 6, 2); + add(e2d, 709, 1325, 724, 1, 0); + add(e2d, 709, 1326, 724, 1, 1); + add(e2d, 709, 1327, 724, 1, 2); + add(e2d, 709, 1243, 724, 3, 0); + add(e2d, 709, 1242, 724, 3, 1); + add(e2d, 709, 1241, 724, 3, 2); + add(e2d, 709, 1240, 724, 3, 3); + add(e2d, 709, 1234, 724, 5, 0); + add(e2d, 709, 1233, 724, 5, 1); + add(e2d, 709, 1229, 724, 7, 0); + add(e2d, 709, 1228, 724, 7, 1); + add(e2d, 710, 308, 920, 0, 0); + add(e2d, 710, 307, 920, 0, 1); + add(e2d, 710, 306, 920, 0, 2); + add(e2d, 710, 305, 920, 0, 3); + add(e2d, 710, 304, 920, 0, 4); + add(e2d, 710, 316, 920, 2, 0); + add(e2d, 710, 315, 920, 2, 1); + add(e2d, 710, 314, 920, 2, 2); + add(e2d, 710, 313, 920, 2, 3); + add(e2d, 710, 312, 920, 2, 4); + add(e2d, 710, 211, 920, 4, 0); + add(e2d, 710, 212, 920, 4, 1); + add(e2d, 710, 213, 920, 4, 2); + add(e2d, 710, 214, 920, 4, 3); + add(e2d, 710, 215, 920, 4, 4); + add(e2d, 710, 206, 920, 1, 0); + add(e2d, 710, 207, 920, 1, 1); + add(e2d, 710, 208, 920, 1, 2); + add(e2d, 710, 201, 920, 3, 0); + add(e2d, 710, 202, 920, 3, 1); + add(e2d, 710, 203, 920, 3, 2); + add(e2d, 710, 1325, 921, 0, 0); + add(e2d, 710, 1326, 921, 0, 1); + add(e2d, 710, 1327, 921, 0, 2); + add(e2d, 710, 1333, 921, 2, 0); + add(e2d, 710, 1334, 921, 2, 1); + add(e2d, 710, 1335, 921, 2, 2); + add(e2d, 710, 1243, 921, 4, 0); + add(e2d, 710, 1242, 921, 4, 1); + add(e2d, 710, 1241, 921, 4, 2); + add(e2d, 710, 1240, 921, 4, 3); + add(e2d, 710, 1234, 921, 1, 0); + add(e2d, 710, 1233, 921, 1, 1); + add(e2d, 710, 1229, 921, 3, 0); + add(e2d, 710, 1228, 921, 3, 1); + add(e2d, 710, 1, 922, 0, 0); + add(e2d, 710, 2, 922, 0, 1); + add(e2d, 710, 3, 922, 0, 2); + add(e2d, 710, 4, 922, 0, 3); + add(e2d, 710, 5, 922, 0, 4); + add(e2d, 710, 10, 922, 2, 0); + add(e2d, 710, 11, 922, 2, 1); + add(e2d, 710, 12, 922, 2, 2); + add(e2d, 710, 13, 922, 2, 3); + add(e2d, 710, 14, 922, 2, 4); + add(e2d, 710, 116, 922, 4, 0); + add(e2d, 710, 115, 922, 4, 1); + add(e2d, 710, 114, 922, 4, 2); + add(e2d, 710, 113, 922, 4, 3); + add(e2d, 710, 112, 922, 4, 4); + add(e2d, 710, 108, 922, 1, 0); + add(e2d, 710, 107, 922, 1, 1); + add(e2d, 710, 104, 922, 3, 0); + add(e2d, 710, 103, 922, 3, 1); + add(e2d, 710, 1033, 923, 0, 0); + add(e2d, 710, 1032, 923, 0, 1); + add(e2d, 710, 1031, 923, 0, 2); + add(e2d, 710, 1030, 923, 0, 3); + add(e2d, 710, 1042, 923, 2, 0); + add(e2d, 710, 1041, 923, 2, 1); + add(e2d, 710, 1040, 923, 2, 2); + add(e2d, 710, 1039, 923, 2, 3); + add(e2d, 710, 1133, 923, 4, 0); + add(e2d, 710, 1134, 923, 4, 1); + add(e2d, 710, 1135, 923, 4, 2); + add(e2d, 710, 1129, 923, 1, 0); + add(e2d, 710, 1130, 923, 1, 1); + add(e2d, 710, 1125, 923, 3, 0); + add(e2d, 710, 1126, 923, 3, 1); + add(e2d, 711, 5, 924, 0, 0); + add(e2d, 711, 4, 924, 0, 1); + add(e2d, 711, 3, 924, 0, 2); + add(e2d, 711, 2, 924, 0, 3); + add(e2d, 711, 1, 924, 0, 4); + add(e2d, 711, 10, 924, 2, 0); + add(e2d, 711, 9, 924, 2, 1); + add(e2d, 711, 8, 924, 2, 2); + add(e2d, 711, 7, 924, 2, 3); + add(e2d, 711, 6, 924, 2, 4); + add(e2d, 711, 22, 924, 4, 0); + add(e2d, 711, 21, 924, 4, 1); + add(e2d, 711, 20, 924, 4, 2); + add(e2d, 711, 19, 924, 4, 3); + add(e2d, 711, 18, 924, 4, 4); + add(e2d, 711, 27, 924, 6, 0); + add(e2d, 711, 26, 924, 6, 1); + add(e2d, 711, 25, 924, 6, 2); + add(e2d, 711, 24, 924, 6, 3); + add(e2d, 711, 23, 924, 6, 4); + add(e2d, 711, 120, 924, 1, 0); + add(e2d, 711, 119, 924, 1, 1); + add(e2d, 711, 118, 924, 1, 2); + add(e2d, 711, 117, 924, 1, 3); + add(e2d, 711, 116, 924, 1, 4); + add(e2d, 711, 112, 924, 3, 0); + add(e2d, 711, 111, 924, 3, 1); + add(e2d, 711, 110, 924, 3, 2); + add(e2d, 711, 109, 924, 3, 3); + add(e2d, 711, 108, 924, 3, 4); + add(e2d, 711, 104, 924, 5, 0); + add(e2d, 711, 103, 924, 5, 1); + add(e2d, 711, 1039, 925, 0, 0); + add(e2d, 711, 1040, 925, 0, 1); + add(e2d, 711, 1041, 925, 0, 2); + add(e2d, 711, 1035, 925, 2, 0); + add(e2d, 711, 1036, 925, 2, 1); + add(e2d, 711, 1037, 925, 2, 2); + add(e2d, 711, 1038, 925, 2, 3); + add(e2d, 711, 1056, 925, 4, 0); + add(e2d, 711, 1057, 925, 4, 1); + add(e2d, 711, 1058, 925, 4, 2); + add(e2d, 711, 1052, 925, 6, 0); + add(e2d, 711, 1053, 925, 6, 1); + add(e2d, 711, 1054, 925, 6, 2); + add(e2d, 711, 1055, 925, 6, 3); + add(e2d, 711, 1137, 925, 1, 0); + add(e2d, 711, 1138, 925, 1, 1); + add(e2d, 711, 1139, 925, 1, 2); + add(e2d, 711, 1129, 925, 3, 0); + add(e2d, 711, 1130, 925, 3, 1); + add(e2d, 711, 1131, 925, 3, 2); + add(e2d, 711, 1125, 925, 5, 0); + add(e2d, 711, 1126, 925, 5, 1); + add(e2d, 711, 313, 784, 0, 0); + add(e2d, 711, 314, 784, 0, 1); + add(e2d, 711, 315, 784, 0, 2); + add(e2d, 711, 316, 784, 0, 3); + add(e2d, 711, 317, 784, 0, 4); + add(e2d, 711, 308, 784, 2, 0); + add(e2d, 711, 309, 784, 2, 1); + add(e2d, 711, 310, 784, 2, 2); + add(e2d, 711, 311, 784, 2, 3); + add(e2d, 711, 312, 784, 2, 4); + add(e2d, 711, 330, 784, 4, 0); + add(e2d, 711, 331, 784, 4, 1); + add(e2d, 711, 332, 784, 4, 2); + add(e2d, 711, 333, 784, 4, 3); + add(e2d, 711, 334, 784, 4, 4); + add(e2d, 711, 325, 784, 6, 0); + add(e2d, 711, 326, 784, 6, 1); + add(e2d, 711, 327, 784, 6, 2); + add(e2d, 711, 328, 784, 6, 3); + add(e2d, 711, 329, 784, 6, 4); + add(e2d, 711, 215, 784, 1, 0); + add(e2d, 711, 216, 784, 1, 1); + add(e2d, 711, 217, 784, 1, 2); + add(e2d, 711, 218, 784, 1, 3); + add(e2d, 711, 219, 784, 1, 4); + add(e2d, 711, 206, 784, 3, 0); + add(e2d, 711, 207, 784, 3, 1); + add(e2d, 711, 208, 784, 3, 2); + add(e2d, 711, 209, 784, 3, 3); + add(e2d, 711, 210, 784, 3, 4); + add(e2d, 711, 201, 784, 5, 0); + add(e2d, 711, 202, 784, 5, 1); + add(e2d, 711, 203, 784, 5, 2); + add(e2d, 711, 1327, 785, 0, 0); + add(e2d, 711, 1326, 785, 0, 1); + add(e2d, 711, 1325, 785, 0, 2); + add(e2d, 711, 1331, 785, 2, 0); + add(e2d, 711, 1330, 785, 2, 1); + add(e2d, 711, 1329, 785, 2, 2); + add(e2d, 711, 1328, 785, 2, 3); + add(e2d, 711, 1344, 785, 4, 0); + add(e2d, 711, 1343, 785, 4, 1); + add(e2d, 711, 1342, 785, 4, 2); + add(e2d, 711, 1348, 785, 6, 0); + add(e2d, 711, 1347, 785, 6, 1); + add(e2d, 711, 1346, 785, 6, 2); + add(e2d, 711, 1345, 785, 6, 3); + add(e2d, 711, 1247, 785, 1, 0); + add(e2d, 711, 1246, 785, 1, 1); + add(e2d, 711, 1245, 785, 1, 2); + add(e2d, 711, 1244, 785, 1, 3); + add(e2d, 711, 1238, 785, 3, 0); + add(e2d, 711, 1237, 785, 3, 1); + add(e2d, 711, 1236, 785, 3, 2); + add(e2d, 711, 1235, 785, 3, 3); + add(e2d, 711, 1229, 785, 5, 0); + add(e2d, 711, 1228, 785, 5, 1); + add(e2d, 712, 403, 786, 0, 0); + add(e2d, 712, 402, 786, 0, 1); + add(e2d, 712, 401, 786, 0, 2); + add(e2d, 712, 408, 786, 2, 0); + add(e2d, 712, 407, 786, 2, 1); + add(e2d, 712, 406, 786, 2, 2); + add(e2d, 712, 405, 786, 2, 3); + add(e2d, 712, 404, 786, 2, 4); + add(e2d, 712, 413, 786, 4, 0); + add(e2d, 712, 412, 786, 4, 1); + add(e2d, 712, 411, 786, 4, 2); + add(e2d, 712, 410, 786, 4, 3); + add(e2d, 712, 409, 786, 4, 4); + add(e2d, 712, 315, 786, 6, 0); + add(e2d, 712, 314, 786, 6, 1); + add(e2d, 712, 313, 786, 6, 2); + add(e2d, 712, 312, 786, 6, 3); + add(e2d, 712, 311, 786, 6, 4); + add(e2d, 712, 320, 786, 1, 0); + add(e2d, 712, 319, 786, 1, 1); + add(e2d, 712, 318, 786, 1, 2); + add(e2d, 712, 317, 786, 1, 3); + add(e2d, 712, 316, 786, 1, 4); + add(e2d, 712, 328, 786, 3, 0); + add(e2d, 712, 329, 786, 3, 1); + add(e2d, 712, 330, 786, 3, 2); + add(e2d, 712, 331, 786, 3, 3); + add(e2d, 712, 332, 786, 3, 4); + add(e2d, 712, 216, 786, 5, 0); + add(e2d, 712, 215, 786, 5, 1); + add(e2d, 712, 214, 786, 5, 2); + add(e2d, 712, 213, 786, 5, 3); + add(e2d, 712, 212, 786, 5, 4); + add(e2d, 712, 208, 786, 7, 0); + add(e2d, 712, 207, 786, 7, 1); + add(e2d, 712, 1330, 787, 0, 0); + add(e2d, 712, 1331, 787, 0, 1); + add(e2d, 712, 1332, 787, 0, 2); + add(e2d, 712, 1333, 787, 0, 3); + add(e2d, 712, 1334, 787, 0, 4); + add(e2d, 712, 1325, 787, 2, 0); + add(e2d, 712, 1326, 787, 2, 1); + add(e2d, 712, 1327, 787, 2, 2); + add(e2d, 712, 1328, 787, 2, 3); + add(e2d, 712, 1329, 787, 2, 4); + add(e2d, 712, 1349, 787, 4, 0); + add(e2d, 712, 1350, 787, 4, 1); + add(e2d, 712, 1351, 787, 4, 2); + add(e2d, 712, 1345, 787, 6, 0); + add(e2d, 712, 1346, 787, 6, 1); + add(e2d, 712, 1347, 787, 6, 2); + add(e2d, 712, 1348, 787, 6, 3); + add(e2d, 712, 1360, 787, 1, 0); + add(e2d, 712, 1359, 787, 1, 1); + add(e2d, 712, 1358, 787, 1, 2); + add(e2d, 712, 1357, 787, 1, 3); + add(e2d, 712, 1233, 787, 3, 0); + add(e2d, 712, 1234, 787, 3, 1); + add(e2d, 712, 1235, 787, 3, 2); + add(e2d, 712, 1229, 787, 5, 0); + add(e2d, 712, 1230, 787, 5, 1); + add(e2d, 712, 1225, 787, 7, 0); + add(e2d, 712, 1226, 787, 7, 1); + add(e2d, 712, 204, 788, 0, 0); + add(e2d, 712, 203, 788, 0, 1); + add(e2d, 712, 1, 788, 2, 0); + add(e2d, 712, 0, 788, 2, 1); + add(e2d, 712, 14, 788, 4, 0); + add(e2d, 712, 15, 788, 4, 1); + add(e2d, 712, 16, 788, 4, 2); + add(e2d, 712, 17, 788, 4, 3); + add(e2d, 712, 18, 788, 4, 4); + add(e2d, 712, 9, 788, 6, 0); + add(e2d, 712, 10, 788, 6, 1); + add(e2d, 712, 11, 788, 6, 2); + add(e2d, 712, 12, 788, 6, 3); + add(e2d, 712, 13, 788, 6, 4); + add(e2d, 712, 26, 788, 1, 0); + add(e2d, 712, 25, 788, 1, 1); + add(e2d, 712, 24, 788, 1, 2); + add(e2d, 712, 23, 788, 1, 3); + add(e2d, 712, 22, 788, 1, 4); + add(e2d, 712, 111, 788, 3, 0); + add(e2d, 712, 112, 788, 3, 1); + add(e2d, 712, 113, 788, 3, 2); + add(e2d, 712, 114, 788, 3, 3); + add(e2d, 712, 115, 788, 3, 4); + add(e2d, 712, 106, 788, 5, 0); + add(e2d, 712, 107, 788, 5, 1); + add(e2d, 712, 108, 788, 5, 2); + add(e2d, 712, 101, 788, 7, 0); + add(e2d, 712, 102, 788, 7, 1); + add(e2d, 712, 103, 788, 7, 2); + add(e2d, 712, 1028, 789, 0, 0); + add(e2d, 712, 1027, 789, 0, 1); + add(e2d, 712, 1026, 789, 0, 2); + add(e2d, 712, 1032, 789, 2, 0); + add(e2d, 712, 1031, 789, 2, 1); + add(e2d, 712, 1030, 789, 2, 2); + add(e2d, 712, 1029, 789, 2, 3); + add(e2d, 712, 1043, 789, 4, 0); + add(e2d, 712, 1044, 789, 4, 1); + add(e2d, 712, 1045, 789, 4, 2); + add(e2d, 712, 1143, 789, 1, 0); + add(e2d, 712, 1142, 789, 1, 1); + add(e2d, 712, 1141, 789, 1, 2); + add(e2d, 712, 1140, 789, 1, 3); + add(e2d, 712, 1134, 789, 3, 0); + add(e2d, 712, 1133, 789, 3, 1); + add(e2d, 712, 1129, 789, 5, 0); + add(e2d, 712, 1128, 789, 5, 1); + add(e2d, 713, 5, 912, 0, 0); + add(e2d, 713, 4, 912, 0, 1); + add(e2d, 713, 3, 912, 0, 2); + add(e2d, 713, 2, 912, 0, 3); + add(e2d, 713, 1, 912, 0, 4); + add(e2d, 713, 10, 912, 2, 0); + add(e2d, 713, 9, 912, 2, 1); + add(e2d, 713, 8, 912, 2, 2); + add(e2d, 713, 7, 912, 2, 3); + add(e2d, 713, 6, 912, 2, 4); + add(e2d, 713, 18, 912, 4, 0); + add(e2d, 713, 19, 912, 4, 1); + add(e2d, 713, 20, 912, 4, 2); + add(e2d, 713, 21, 912, 4, 3); + add(e2d, 713, 22, 912, 4, 4); + add(e2d, 713, 116, 912, 1, 0); + add(e2d, 713, 115, 912, 1, 1); + add(e2d, 713, 114, 912, 1, 2); + add(e2d, 713, 113, 912, 1, 3); + add(e2d, 713, 112, 912, 1, 4); + add(e2d, 713, 108, 912, 3, 0); + add(e2d, 713, 107, 912, 3, 1); + add(e2d, 713, 104, 912, 5, 0); + add(e2d, 713, 103, 912, 5, 1); + add(e2d, 713, 1039, 913, 0, 0); + add(e2d, 713, 1040, 913, 0, 1); + add(e2d, 713, 1041, 913, 0, 2); + add(e2d, 713, 1035, 913, 2, 0); + add(e2d, 713, 1036, 913, 2, 1); + add(e2d, 713, 1037, 913, 2, 2); + add(e2d, 713, 1038, 913, 2, 3); + add(e2d, 713, 1050, 913, 4, 0); + add(e2d, 713, 1049, 913, 4, 1); + add(e2d, 713, 1048, 913, 4, 2); + add(e2d, 713, 1047, 913, 4, 3); + add(e2d, 713, 1133, 913, 1, 0); + add(e2d, 713, 1134, 913, 1, 1); + add(e2d, 713, 1135, 913, 1, 2); + add(e2d, 713, 1129, 913, 3, 0); + add(e2d, 713, 1130, 913, 3, 1); + add(e2d, 713, 1125, 913, 5, 0); + add(e2d, 713, 1126, 913, 5, 1); + add(e2d, 713, 313, 914, 0, 0); + add(e2d, 713, 314, 914, 0, 1); + add(e2d, 713, 315, 914, 0, 2); + add(e2d, 713, 316, 914, 0, 3); + add(e2d, 713, 317, 914, 0, 4); + add(e2d, 713, 308, 914, 2, 0); + add(e2d, 713, 309, 914, 2, 1); + add(e2d, 713, 310, 914, 2, 2); + add(e2d, 713, 311, 914, 2, 3); + add(e2d, 713, 312, 914, 2, 4); + add(e2d, 713, 325, 914, 4, 0); + add(e2d, 713, 324, 914, 4, 1); + add(e2d, 713, 323, 914, 4, 2); + add(e2d, 713, 322, 914, 4, 3); + add(e2d, 713, 321, 914, 4, 4); + add(e2d, 713, 211, 914, 1, 0); + add(e2d, 713, 212, 914, 1, 1); + add(e2d, 713, 213, 914, 1, 2); + add(e2d, 713, 214, 914, 1, 3); + add(e2d, 713, 215, 914, 1, 4); + add(e2d, 713, 206, 914, 3, 0); + add(e2d, 713, 207, 914, 3, 1); + add(e2d, 713, 208, 914, 3, 2); + add(e2d, 713, 201, 914, 5, 0); + add(e2d, 713, 202, 914, 5, 1); + add(e2d, 713, 203, 914, 5, 2); + add(e2d, 713, 1327, 915, 0, 0); + add(e2d, 713, 1326, 915, 0, 1); + add(e2d, 713, 1325, 915, 0, 2); + add(e2d, 713, 1331, 915, 2, 0); + add(e2d, 713, 1330, 915, 2, 1); + add(e2d, 713, 1329, 915, 2, 2); + add(e2d, 713, 1328, 915, 2, 3); + add(e2d, 713, 1342, 915, 4, 0); + add(e2d, 713, 1343, 915, 4, 1); + add(e2d, 713, 1344, 915, 4, 2); + add(e2d, 713, 1243, 915, 1, 0); + add(e2d, 713, 1242, 915, 1, 1); + add(e2d, 713, 1241, 915, 1, 2); + add(e2d, 713, 1240, 915, 1, 3); + add(e2d, 713, 1234, 915, 3, 0); + add(e2d, 713, 1233, 915, 3, 1); + add(e2d, 713, 1229, 915, 5, 0); + add(e2d, 713, 1228, 915, 5, 1); + add(e2d, 714, 1, 328, 2, 0); + add(e2d, 714, 0, 328, 2, 1); + add(e2d, 714, 204, 328, 0, 0); + add(e2d, 714, 203, 328, 0, 1); + add(e2d, 714, 14, 328, 4, 0); + add(e2d, 714, 15, 328, 4, 1); + add(e2d, 714, 16, 328, 4, 2); + add(e2d, 714, 17, 328, 4, 3); + add(e2d, 714, 18, 328, 4, 4); + add(e2d, 714, 9, 328, 6, 0); + add(e2d, 714, 10, 328, 6, 1); + add(e2d, 714, 11, 328, 6, 2); + add(e2d, 714, 12, 328, 6, 3); + add(e2d, 714, 13, 328, 6, 4); + add(e2d, 714, 26, 328, 1, 0); + add(e2d, 714, 25, 328, 1, 1); + add(e2d, 714, 24, 328, 1, 2); + add(e2d, 714, 23, 328, 1, 3); + add(e2d, 714, 22, 328, 1, 4); + add(e2d, 714, 111, 328, 3, 0); + add(e2d, 714, 112, 328, 3, 1); + add(e2d, 714, 113, 328, 3, 2); + add(e2d, 714, 114, 328, 3, 3); + add(e2d, 714, 115, 328, 3, 4); + add(e2d, 714, 106, 328, 5, 0); + add(e2d, 714, 107, 328, 5, 1); + add(e2d, 714, 108, 328, 5, 2); + add(e2d, 714, 101, 328, 7, 0); + add(e2d, 714, 102, 328, 7, 1); + add(e2d, 714, 103, 328, 7, 2); + add(e2d, 714, 1028, 329, 0, 0); + add(e2d, 714, 1027, 329, 0, 1); + add(e2d, 714, 1026, 329, 0, 2); + add(e2d, 714, 1032, 329, 2, 0); + add(e2d, 714, 1031, 329, 2, 1); + add(e2d, 714, 1030, 329, 2, 2); + add(e2d, 714, 1029, 329, 2, 3); + add(e2d, 714, 1043, 329, 4, 0); + add(e2d, 714, 1044, 329, 4, 1); + add(e2d, 714, 1045, 329, 4, 2); + add(e2d, 714, 1143, 329, 1, 0); + add(e2d, 714, 1142, 329, 1, 1); + add(e2d, 714, 1141, 329, 1, 2); + add(e2d, 714, 1140, 329, 1, 3); + add(e2d, 714, 1134, 329, 3, 0); + add(e2d, 714, 1133, 329, 3, 1); + add(e2d, 714, 1129, 329, 5, 0); + add(e2d, 714, 1128, 329, 5, 1); + add(e2d, 714, 403, 330, 0, 0); + add(e2d, 714, 402, 330, 0, 1); + add(e2d, 714, 401, 330, 0, 2); + add(e2d, 714, 408, 330, 2, 0); + add(e2d, 714, 407, 330, 2, 1); + add(e2d, 714, 406, 330, 2, 2); + add(e2d, 714, 405, 330, 2, 3); + add(e2d, 714, 404, 330, 2, 4); + add(e2d, 714, 413, 330, 4, 0); + add(e2d, 714, 412, 330, 4, 1); + add(e2d, 714, 411, 330, 4, 2); + add(e2d, 714, 410, 330, 4, 3); + add(e2d, 714, 409, 330, 4, 4); + add(e2d, 714, 315, 330, 6, 0); + add(e2d, 714, 314, 330, 6, 1); + add(e2d, 714, 313, 330, 6, 2); + add(e2d, 714, 312, 330, 6, 3); + add(e2d, 714, 311, 330, 6, 4); + add(e2d, 714, 320, 330, 1, 0); + add(e2d, 714, 319, 330, 1, 1); + add(e2d, 714, 318, 330, 1, 2); + add(e2d, 714, 317, 330, 1, 3); + add(e2d, 714, 316, 330, 1, 4); + add(e2d, 714, 328, 330, 3, 0); + add(e2d, 714, 329, 330, 3, 1); + add(e2d, 714, 330, 330, 3, 2); + add(e2d, 714, 331, 330, 3, 3); + add(e2d, 714, 332, 330, 3, 4); + add(e2d, 714, 216, 330, 5, 0); + add(e2d, 714, 215, 330, 5, 1); + add(e2d, 714, 214, 330, 5, 2); + add(e2d, 714, 213, 330, 5, 3); + add(e2d, 714, 212, 330, 5, 4); + add(e2d, 714, 208, 330, 7, 0); + add(e2d, 714, 207, 330, 7, 1); + add(e2d, 714, 1330, 331, 0, 0); + add(e2d, 714, 1331, 331, 0, 1); + add(e2d, 714, 1332, 331, 0, 2); + add(e2d, 714, 1333, 331, 0, 3); + add(e2d, 714, 1334, 331, 0, 4); + add(e2d, 714, 1325, 331, 2, 0); + add(e2d, 714, 1326, 331, 2, 1); + add(e2d, 714, 1327, 331, 2, 2); + add(e2d, 714, 1328, 331, 2, 3); + add(e2d, 714, 1329, 331, 2, 4); + add(e2d, 714, 1349, 331, 4, 0); + add(e2d, 714, 1350, 331, 4, 1); + add(e2d, 714, 1351, 331, 4, 2); + add(e2d, 714, 1345, 331, 6, 0); + add(e2d, 714, 1346, 331, 6, 1); + add(e2d, 714, 1347, 331, 6, 2); + add(e2d, 714, 1348, 331, 6, 3); + add(e2d, 714, 1360, 331, 1, 0); + add(e2d, 714, 1359, 331, 1, 1); + add(e2d, 714, 1358, 331, 1, 2); + add(e2d, 714, 1357, 331, 1, 3); + add(e2d, 714, 1233, 331, 3, 0); + add(e2d, 714, 1234, 331, 3, 1); + add(e2d, 714, 1235, 331, 3, 2); + add(e2d, 714, 1229, 331, 5, 0); + add(e2d, 714, 1230, 331, 5, 1); + add(e2d, 714, 1225, 331, 7, 0); + add(e2d, 714, 1226, 331, 7, 1); + add(e2d, 715, 5, 332, 0, 0); + add(e2d, 715, 4, 332, 0, 1); + add(e2d, 715, 3, 332, 0, 2); + add(e2d, 715, 2, 332, 0, 3); + add(e2d, 715, 1, 332, 0, 4); + add(e2d, 715, 10, 332, 2, 0); + add(e2d, 715, 9, 332, 2, 1); + add(e2d, 715, 8, 332, 2, 2); + add(e2d, 715, 7, 332, 2, 3); + add(e2d, 715, 6, 332, 2, 4); + add(e2d, 715, 22, 332, 4, 0); + add(e2d, 715, 21, 332, 4, 1); + add(e2d, 715, 20, 332, 4, 2); + add(e2d, 715, 19, 332, 4, 3); + add(e2d, 715, 18, 332, 4, 4); + add(e2d, 715, 27, 332, 6, 0); + add(e2d, 715, 26, 332, 6, 1); + add(e2d, 715, 25, 332, 6, 2); + add(e2d, 715, 24, 332, 6, 3); + add(e2d, 715, 23, 332, 6, 4); + add(e2d, 715, 120, 332, 1, 0); + add(e2d, 715, 119, 332, 1, 1); + add(e2d, 715, 118, 332, 1, 2); + add(e2d, 715, 117, 332, 1, 3); + add(e2d, 715, 116, 332, 1, 4); + add(e2d, 715, 112, 332, 3, 0); + add(e2d, 715, 111, 332, 3, 1); + add(e2d, 715, 110, 332, 3, 2); + add(e2d, 715, 109, 332, 3, 3); + add(e2d, 715, 108, 332, 3, 4); + add(e2d, 715, 104, 332, 5, 0); + add(e2d, 715, 103, 332, 5, 1); + add(e2d, 715, 1039, 333, 0, 0); + add(e2d, 715, 1040, 333, 0, 1); + add(e2d, 715, 1041, 333, 0, 2); + add(e2d, 715, 1035, 333, 2, 0); + add(e2d, 715, 1036, 333, 2, 1); + add(e2d, 715, 1037, 333, 2, 2); + add(e2d, 715, 1038, 333, 2, 3); + add(e2d, 715, 1056, 333, 4, 0); + add(e2d, 715, 1057, 333, 4, 1); + add(e2d, 715, 1058, 333, 4, 2); + add(e2d, 715, 1052, 333, 6, 0); + add(e2d, 715, 1053, 333, 6, 1); + add(e2d, 715, 1054, 333, 6, 2); + add(e2d, 715, 1055, 333, 6, 3); + add(e2d, 715, 1137, 333, 1, 0); + add(e2d, 715, 1138, 333, 1, 1); + add(e2d, 715, 1139, 333, 1, 2); + add(e2d, 715, 1129, 333, 3, 0); + add(e2d, 715, 1130, 333, 3, 1); + add(e2d, 715, 1131, 333, 3, 2); + add(e2d, 715, 1125, 333, 5, 0); + add(e2d, 715, 1126, 333, 5, 1); + add(e2d, 715, 313, 344, 0, 0); + add(e2d, 715, 314, 344, 0, 1); + add(e2d, 715, 315, 344, 0, 2); + add(e2d, 715, 316, 344, 0, 3); + add(e2d, 715, 317, 344, 0, 4); + add(e2d, 715, 308, 344, 2, 0); + add(e2d, 715, 309, 344, 2, 1); + add(e2d, 715, 310, 344, 2, 2); + add(e2d, 715, 311, 344, 2, 3); + add(e2d, 715, 312, 344, 2, 4); + add(e2d, 715, 330, 344, 4, 0); + add(e2d, 715, 331, 344, 4, 1); + add(e2d, 715, 332, 344, 4, 2); + add(e2d, 715, 333, 344, 4, 3); + add(e2d, 715, 334, 344, 4, 4); + add(e2d, 715, 325, 344, 6, 0); + add(e2d, 715, 326, 344, 6, 1); + add(e2d, 715, 327, 344, 6, 2); + add(e2d, 715, 328, 344, 6, 3); + add(e2d, 715, 329, 344, 6, 4); + add(e2d, 715, 215, 344, 1, 0); + add(e2d, 715, 216, 344, 1, 1); + add(e2d, 715, 217, 344, 1, 2); + add(e2d, 715, 218, 344, 1, 3); + add(e2d, 715, 219, 344, 1, 4); + add(e2d, 715, 206, 344, 3, 0); + add(e2d, 715, 207, 344, 3, 1); + add(e2d, 715, 208, 344, 3, 2); + add(e2d, 715, 209, 344, 3, 3); + add(e2d, 715, 210, 344, 3, 4); + add(e2d, 715, 201, 344, 5, 0); + add(e2d, 715, 202, 344, 5, 1); + add(e2d, 715, 203, 344, 5, 2); + add(e2d, 715, 1327, 345, 0, 0); + add(e2d, 715, 1326, 345, 0, 1); + add(e2d, 715, 1325, 345, 0, 2); + add(e2d, 715, 1331, 345, 2, 0); + add(e2d, 715, 1330, 345, 2, 1); + add(e2d, 715, 1329, 345, 2, 2); + add(e2d, 715, 1328, 345, 2, 3); + add(e2d, 715, 1344, 345, 4, 0); + add(e2d, 715, 1343, 345, 4, 1); + add(e2d, 715, 1342, 345, 4, 2); + add(e2d, 715, 1348, 345, 6, 0); + add(e2d, 715, 1347, 345, 6, 1); + add(e2d, 715, 1346, 345, 6, 2); + add(e2d, 715, 1345, 345, 6, 3); + add(e2d, 715, 1247, 345, 1, 0); + add(e2d, 715, 1246, 345, 1, 1); + add(e2d, 715, 1245, 345, 1, 2); + add(e2d, 715, 1244, 345, 1, 3); + add(e2d, 715, 1238, 345, 3, 0); + add(e2d, 715, 1237, 345, 3, 1); + add(e2d, 715, 1236, 345, 3, 2); + add(e2d, 715, 1235, 345, 3, 3); + add(e2d, 715, 1229, 345, 5, 0); + add(e2d, 715, 1228, 345, 5, 1); + add(e2d, 716, 308, 346, 0, 0); + add(e2d, 716, 307, 346, 0, 1); + add(e2d, 716, 306, 346, 0, 2); + add(e2d, 716, 305, 346, 0, 3); + add(e2d, 716, 304, 346, 0, 4); + add(e2d, 716, 316, 346, 2, 0); + add(e2d, 716, 315, 346, 2, 1); + add(e2d, 716, 314, 346, 2, 2); + add(e2d, 716, 313, 346, 2, 3); + add(e2d, 716, 312, 346, 2, 4); + add(e2d, 716, 211, 346, 4, 0); + add(e2d, 716, 212, 346, 4, 1); + add(e2d, 716, 213, 346, 4, 2); + add(e2d, 716, 214, 346, 4, 3); + add(e2d, 716, 215, 346, 4, 4); + add(e2d, 716, 206, 346, 1, 0); + add(e2d, 716, 207, 346, 1, 1); + add(e2d, 716, 208, 346, 1, 2); + add(e2d, 716, 201, 346, 3, 0); + add(e2d, 716, 202, 346, 3, 1); + add(e2d, 716, 203, 346, 3, 2); + add(e2d, 716, 1325, 347, 0, 0); + add(e2d, 716, 1326, 347, 0, 1); + add(e2d, 716, 1327, 347, 0, 2); + add(e2d, 716, 1333, 347, 2, 0); + add(e2d, 716, 1334, 347, 2, 1); + add(e2d, 716, 1335, 347, 2, 2); + add(e2d, 716, 1243, 347, 4, 0); + add(e2d, 716, 1242, 347, 4, 1); + add(e2d, 716, 1241, 347, 4, 2); + add(e2d, 716, 1240, 347, 4, 3); + add(e2d, 716, 1234, 347, 1, 0); + add(e2d, 716, 1233, 347, 1, 1); + add(e2d, 716, 1229, 347, 3, 0); + add(e2d, 716, 1228, 347, 3, 1); + add(e2d, 716, 1, 348, 0, 0); + add(e2d, 716, 2, 348, 0, 1); + add(e2d, 716, 3, 348, 0, 2); + add(e2d, 716, 4, 348, 0, 3); + add(e2d, 716, 5, 348, 0, 4); + add(e2d, 716, 10, 348, 2, 0); + add(e2d, 716, 11, 348, 2, 1); + add(e2d, 716, 12, 348, 2, 2); + add(e2d, 716, 13, 348, 2, 3); + add(e2d, 716, 14, 348, 2, 4); + add(e2d, 716, 116, 348, 4, 0); + add(e2d, 716, 115, 348, 4, 1); + add(e2d, 716, 114, 348, 4, 2); + add(e2d, 716, 113, 348, 4, 3); + add(e2d, 716, 112, 348, 4, 4); + add(e2d, 716, 108, 348, 1, 0); + add(e2d, 716, 107, 348, 1, 1); + add(e2d, 716, 104, 348, 3, 0); + add(e2d, 716, 103, 348, 3, 1); + add(e2d, 716, 1033, 349, 0, 0); + add(e2d, 716, 1032, 349, 0, 1); + add(e2d, 716, 1031, 349, 0, 2); + add(e2d, 716, 1030, 349, 0, 3); + add(e2d, 716, 1042, 349, 2, 0); + add(e2d, 716, 1041, 349, 2, 1); + add(e2d, 716, 1040, 349, 2, 2); + add(e2d, 716, 1039, 349, 2, 3); + add(e2d, 716, 1133, 349, 4, 0); + add(e2d, 716, 1134, 349, 4, 1); + add(e2d, 716, 1135, 349, 4, 2); + add(e2d, 716, 1129, 349, 1, 0); + add(e2d, 716, 1130, 349, 1, 1); + add(e2d, 716, 1125, 349, 3, 0); + add(e2d, 716, 1126, 349, 3, 1); + add(e2d, 717, 1, 848, 0, 0); + add(e2d, 717, 2, 848, 0, 1); + add(e2d, 717, 3, 848, 0, 2); + add(e2d, 717, 4, 848, 0, 3); + add(e2d, 717, 5, 848, 0, 4); + add(e2d, 717, 116, 848, 2, 0); + add(e2d, 717, 115, 848, 2, 1); + add(e2d, 717, 114, 848, 2, 2); + add(e2d, 717, 113, 848, 2, 3); + add(e2d, 717, 112, 848, 2, 4); + add(e2d, 717, 108, 848, 4, 0); + add(e2d, 717, 107, 848, 4, 1); + add(e2d, 717, 104, 848, 6, 0); + add(e2d, 717, 103, 848, 6, 1); + add(e2d, 717, 1033, 848, 1, 0); + add(e2d, 717, 1032, 848, 1, 1); + add(e2d, 717, 1031, 848, 1, 2); + add(e2d, 717, 1030, 848, 1, 3); + add(e2d, 717, 1133, 848, 3, 0); + add(e2d, 717, 1134, 848, 3, 1); + add(e2d, 717, 1135, 848, 3, 2); + add(e2d, 717, 1129, 848, 5, 0); + add(e2d, 717, 1130, 848, 5, 1); + add(e2d, 717, 1125, 848, 7, 0); + add(e2d, 717, 1126, 848, 7, 1); + add(e2d, 717, 308, 849, 0, 0); + add(e2d, 717, 307, 849, 0, 1); + add(e2d, 717, 306, 849, 0, 2); + add(e2d, 717, 305, 849, 0, 3); + add(e2d, 717, 304, 849, 0, 4); + add(e2d, 717, 211, 849, 2, 0); + add(e2d, 717, 212, 849, 2, 1); + add(e2d, 717, 213, 849, 2, 2); + add(e2d, 717, 214, 849, 2, 3); + add(e2d, 717, 215, 849, 2, 4); + add(e2d, 717, 206, 849, 4, 0); + add(e2d, 717, 207, 849, 4, 1); + add(e2d, 717, 208, 849, 4, 2); + add(e2d, 717, 201, 849, 6, 0); + add(e2d, 717, 202, 849, 6, 1); + add(e2d, 717, 203, 849, 6, 2); + add(e2d, 717, 1325, 849, 1, 0); + add(e2d, 717, 1326, 849, 1, 1); + add(e2d, 717, 1327, 849, 1, 2); + add(e2d, 717, 1243, 849, 3, 0); + add(e2d, 717, 1242, 849, 3, 1); + add(e2d, 717, 1241, 849, 3, 2); + add(e2d, 717, 1240, 849, 3, 3); + add(e2d, 717, 1234, 849, 5, 0); + add(e2d, 717, 1233, 849, 5, 1); + add(e2d, 717, 1229, 849, 7, 0); + add(e2d, 717, 1228, 849, 7, 1); + add(e2d, 718, 111, 850, 0, 0); + add(e2d, 718, 112, 850, 0, 1); + add(e2d, 718, 113, 850, 0, 2); + add(e2d, 718, 106, 850, 2, 0); + add(e2d, 718, 107, 850, 2, 1); + add(e2d, 718, 108, 850, 2, 2); + add(e2d, 718, 101, 850, 4, 0); + add(e2d, 718, 102, 850, 4, 1); + add(e2d, 718, 103, 850, 4, 2); + add(e2d, 718, 1139, 850, 1, 0); + add(e2d, 718, 1138, 850, 1, 1); + add(e2d, 718, 1134, 850, 3, 0); + add(e2d, 718, 1133, 850, 3, 1); + add(e2d, 718, 1129, 850, 5, 0); + add(e2d, 718, 1128, 850, 5, 1); + add(e2d, 718, 12, 851, 0, 0); + add(e2d, 718, 11, 851, 0, 1); + add(e2d, 718, 8, 851, 2, 0); + add(e2d, 718, 7, 851, 2, 1); + add(e2d, 718, 4, 851, 4, 0); + add(e2d, 718, 3, 851, 4, 1); + add(e2d, 718, 1033, 851, 1, 0); + add(e2d, 718, 1034, 851, 1, 1); + add(e2d, 718, 1029, 851, 3, 0); + add(e2d, 718, 1030, 851, 3, 1); + add(e2d, 718, 1025, 851, 5, 0); + add(e2d, 718, 1026, 851, 5, 1); + add(e2d, 719, 8, 852, 0, 0); + add(e2d, 719, 7, 852, 0, 1); + add(e2d, 719, 4, 852, 2, 0); + add(e2d, 719, 3, 852, 2, 1); + add(e2d, 719, 1029, 852, 4, 0); + add(e2d, 719, 1030, 852, 4, 1); + add(e2d, 719, 1025, 852, 6, 0); + add(e2d, 719, 1026, 852, 6, 1); + add(e2d, 719, 106, 852, 1, 0); + add(e2d, 719, 107, 852, 1, 1); + add(e2d, 719, 108, 852, 1, 2); + add(e2d, 719, 101, 852, 3, 0); + add(e2d, 719, 102, 852, 3, 1); + add(e2d, 719, 103, 852, 3, 2); + add(e2d, 719, 1134, 852, 5, 0); + add(e2d, 719, 1133, 852, 5, 1); + add(e2d, 719, 1129, 852, 7, 0); + add(e2d, 719, 1128, 852, 7, 1); } void fillSolar2FeeLinkCH7L(std::map<uint16_t, uint32_t>& s2f) { - add_cru(s2f, 30, 0, 728); - add_cru(s2f, 30, 1, 729); - add_cru(s2f, 30, 2, 730); - add_cru(s2f, 30, 3, 731); - add_cru(s2f, 30, 4, 732); - add_cru(s2f, 30, 5, 736); - add_cru(s2f, 30, 6, 737); - add_cru(s2f, 30, 7, 738); - add_cru(s2f, 30, 8, 739); - add_cru(s2f, 30, 9, 740); - add_cru(s2f, 30, 10, 741); - add_cru(s2f, 30, 11, 776); - add_cru(s2f, 31, 0, 777); - add_cru(s2f, 31, 1, 778); - add_cru(s2f, 31, 2, 779); - add_cru(s2f, 31, 3, 780); - add_cru(s2f, 31, 4, 781); - add_cru(s2f, 31, 5, 864); - add_cru(s2f, 31, 6, 865); - add_cru(s2f, 31, 7, 866); - add_cru(s2f, 31, 8, 867); - add_cru(s2f, 31, 9, 352); - add_cru(s2f, 31, 10, 353); - add_cru(s2f, 31, 11, 354); - add_cru(s2f, 32, 0, 355); - add_cru(s2f, 32, 1, 356); - add_cru(s2f, 32, 2, 357); - add_cru(s2f, 32, 3, 304); - add_cru(s2f, 32, 4, 305); - add_cru(s2f, 32, 5, 306); - add_cru(s2f, 32, 6, 307); - add_cru(s2f, 32, 7, 308); - add_cru(s2f, 32, 8, 309); - add_cru(s2f, 32, 9, 856); - add_cru(s2f, 32, 10, 857); - add_cru(s2f, 32, 11, 858); - add_cru(s2f, 33, 0, 859); - add_cru(s2f, 33, 1, 860); + add_cru(s2f, 30, 0, 720); + add_cru(s2f, 30, 1, 721); + add_cru(s2f, 30, 2, 722); + add_cru(s2f, 30, 3, 723); + add_cru(s2f, 30, 4, 724); + add_cru(s2f, 31, 0, 920); + add_cru(s2f, 31, 1, 921); + add_cru(s2f, 31, 2, 922); + add_cru(s2f, 31, 3, 923); + add_cru(s2f, 31, 4, 924); + add_cru(s2f, 31, 5, 925); + add_cru(s2f, 31, 6, 784); + add_cru(s2f, 31, 7, 785); + add_cru(s2f, 31, 8, 786); + add_cru(s2f, 31, 9, 787); + add_cru(s2f, 31, 10, 788); + add_cru(s2f, 31, 11, 789); + add_cru(s2f, 32, 0, 912); + add_cru(s2f, 32, 1, 913); + add_cru(s2f, 32, 2, 914); + add_cru(s2f, 32, 3, 915); + add_cru(s2f, 32, 6, 328); + add_cru(s2f, 32, 7, 329); + add_cru(s2f, 32, 8, 330); + add_cru(s2f, 32, 9, 331); + add_cru(s2f, 32, 10, 332); + add_cru(s2f, 32, 11, 333); + add_cru(s2f, 33, 0, 344); + add_cru(s2f, 33, 1, 345); + add_cru(s2f, 33, 2, 346); + add_cru(s2f, 33, 3, 347); + add_cru(s2f, 33, 4, 348); + add_cru(s2f, 33, 5, 349); + add_cru(s2f, 33, 6, 848); + add_cru(s2f, 33, 7, 849); + add_cru(s2f, 33, 8, 850); + add_cru(s2f, 33, 9, 851); + add_cru(s2f, 33, 10, 852); } \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH7R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH7R.cxx index 71cb44f105ecd..7be7368e2bc2f 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH7R.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH7R.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,12 +43,12 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 705, 101, 841, 5, 0); add(e2d, 705, 102, 841, 5, 1); add(e2d, 705, 103, 841, 5, 2); - add(e2d, 705, 1138, 841, 0, 0); - add(e2d, 705, 1139, 841, 0, 1); - add(e2d, 705, 1133, 841, 2, 0); - add(e2d, 705, 1134, 841, 2, 1); - add(e2d, 705, 1128, 841, 4, 0); - add(e2d, 705, 1129, 841, 4, 1); + add(e2d, 705, 1139, 841, 0, 0); + add(e2d, 705, 1138, 841, 0, 1); + add(e2d, 705, 1134, 841, 2, 0); + add(e2d, 705, 1133, 841, 2, 1); + add(e2d, 705, 1129, 841, 4, 0); + add(e2d, 705, 1128, 841, 4, 1); add(e2d, 705, 12, 842, 1, 0); add(e2d, 705, 11, 842, 1, 1); add(e2d, 705, 8, 842, 3, 0); @@ -60,79 +61,79 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 705, 1030, 842, 2, 1); add(e2d, 705, 1025, 842, 4, 0); add(e2d, 705, 1026, 842, 4, 1); - add(e2d, 704, 1, 843, 1, 0); - add(e2d, 704, 2, 843, 1, 1); - add(e2d, 704, 3, 843, 1, 2); - add(e2d, 704, 4, 843, 1, 3); - add(e2d, 704, 5, 843, 1, 4); - add(e2d, 704, 116, 843, 3, 0); - add(e2d, 704, 115, 843, 3, 1); - add(e2d, 704, 114, 843, 3, 2); - add(e2d, 704, 113, 843, 3, 3); - add(e2d, 704, 112, 843, 3, 4); - add(e2d, 704, 108, 843, 5, 0); - add(e2d, 704, 107, 843, 5, 1); - add(e2d, 704, 104, 843, 7, 0); - add(e2d, 704, 103, 843, 7, 1); - add(e2d, 704, 1033, 843, 0, 0); - add(e2d, 704, 1032, 843, 0, 1); - add(e2d, 704, 1031, 843, 0, 2); - add(e2d, 704, 1030, 843, 0, 3); - add(e2d, 704, 1133, 843, 2, 0); - add(e2d, 704, 1134, 843, 2, 1); - add(e2d, 704, 1135, 843, 2, 2); - add(e2d, 704, 1129, 843, 4, 0); - add(e2d, 704, 1130, 843, 4, 1); - add(e2d, 704, 1125, 843, 6, 0); - add(e2d, 704, 1126, 843, 6, 1); - add(e2d, 704, 308, 844, 1, 0); - add(e2d, 704, 307, 844, 1, 1); - add(e2d, 704, 306, 844, 1, 2); - add(e2d, 704, 305, 844, 1, 3); - add(e2d, 704, 304, 844, 1, 4); - add(e2d, 704, 211, 844, 3, 0); - add(e2d, 704, 212, 844, 3, 1); - add(e2d, 704, 213, 844, 3, 2); - add(e2d, 704, 214, 844, 3, 3); - add(e2d, 704, 215, 844, 3, 4); - add(e2d, 704, 206, 844, 5, 0); - add(e2d, 704, 207, 844, 5, 1); - add(e2d, 704, 208, 844, 5, 2); - add(e2d, 704, 201, 844, 7, 0); - add(e2d, 704, 202, 844, 7, 1); - add(e2d, 704, 203, 844, 7, 2); - add(e2d, 704, 1325, 844, 0, 0); - add(e2d, 704, 1326, 844, 0, 1); - add(e2d, 704, 1327, 844, 0, 2); - add(e2d, 704, 1243, 844, 2, 0); - add(e2d, 704, 1242, 844, 2, 1); - add(e2d, 704, 1241, 844, 2, 2); - add(e2d, 704, 1240, 844, 2, 3); - add(e2d, 704, 1234, 844, 4, 0); - add(e2d, 704, 1233, 844, 4, 1); - add(e2d, 704, 1229, 844, 6, 0); - add(e2d, 704, 1228, 844, 6, 1); - add(e2d, 703, 308, 800, 1, 0); - add(e2d, 703, 307, 800, 1, 1); - add(e2d, 703, 306, 800, 1, 2); - add(e2d, 703, 305, 800, 1, 3); - add(e2d, 703, 304, 800, 1, 4); - add(e2d, 703, 316, 800, 3, 0); - add(e2d, 703, 315, 800, 3, 1); - add(e2d, 703, 314, 800, 3, 2); - add(e2d, 703, 313, 800, 3, 3); - add(e2d, 703, 312, 800, 3, 4); - add(e2d, 703, 211, 800, 5, 0); - add(e2d, 703, 212, 800, 5, 1); - add(e2d, 703, 213, 800, 5, 2); - add(e2d, 703, 214, 800, 5, 3); - add(e2d, 703, 215, 800, 5, 4); - add(e2d, 703, 206, 800, 0, 0); - add(e2d, 703, 207, 800, 0, 1); - add(e2d, 703, 208, 800, 0, 2); - add(e2d, 703, 201, 800, 2, 0); - add(e2d, 703, 202, 800, 2, 1); - add(e2d, 703, 203, 800, 2, 2); + add(e2d, 704, 1, 843, 0, 0); + add(e2d, 704, 2, 843, 0, 1); + add(e2d, 704, 3, 843, 0, 2); + add(e2d, 704, 4, 843, 0, 3); + add(e2d, 704, 5, 843, 0, 4); + add(e2d, 704, 116, 843, 2, 0); + add(e2d, 704, 115, 843, 2, 1); + add(e2d, 704, 114, 843, 2, 2); + add(e2d, 704, 113, 843, 2, 3); + add(e2d, 704, 112, 843, 2, 4); + add(e2d, 704, 108, 843, 4, 0); + add(e2d, 704, 107, 843, 4, 1); + add(e2d, 704, 104, 843, 6, 0); + add(e2d, 704, 103, 843, 6, 1); + add(e2d, 704, 1033, 843, 1, 0); + add(e2d, 704, 1032, 843, 1, 1); + add(e2d, 704, 1031, 843, 1, 2); + add(e2d, 704, 1030, 843, 1, 3); + add(e2d, 704, 1133, 843, 3, 0); + add(e2d, 704, 1134, 843, 3, 1); + add(e2d, 704, 1135, 843, 3, 2); + add(e2d, 704, 1129, 843, 5, 0); + add(e2d, 704, 1130, 843, 5, 1); + add(e2d, 704, 1125, 843, 7, 0); + add(e2d, 704, 1126, 843, 7, 1); + add(e2d, 704, 308, 844, 0, 0); + add(e2d, 704, 307, 844, 0, 1); + add(e2d, 704, 306, 844, 0, 2); + add(e2d, 704, 305, 844, 0, 3); + add(e2d, 704, 304, 844, 0, 4); + add(e2d, 704, 211, 844, 2, 0); + add(e2d, 704, 212, 844, 2, 1); + add(e2d, 704, 213, 844, 2, 2); + add(e2d, 704, 214, 844, 2, 3); + add(e2d, 704, 215, 844, 2, 4); + add(e2d, 704, 206, 844, 4, 0); + add(e2d, 704, 207, 844, 4, 1); + add(e2d, 704, 208, 844, 4, 2); + add(e2d, 704, 201, 844, 6, 0); + add(e2d, 704, 202, 844, 6, 1); + add(e2d, 704, 203, 844, 6, 2); + add(e2d, 704, 1325, 844, 1, 0); + add(e2d, 704, 1326, 844, 1, 1); + add(e2d, 704, 1327, 844, 1, 2); + add(e2d, 704, 1243, 844, 3, 0); + add(e2d, 704, 1242, 844, 3, 1); + add(e2d, 704, 1241, 844, 3, 2); + add(e2d, 704, 1240, 844, 3, 3); + add(e2d, 704, 1234, 844, 5, 0); + add(e2d, 704, 1233, 844, 5, 1); + add(e2d, 704, 1229, 844, 7, 0); + add(e2d, 704, 1228, 844, 7, 1); + add(e2d, 703, 308, 800, 0, 0); + add(e2d, 703, 307, 800, 0, 1); + add(e2d, 703, 306, 800, 0, 2); + add(e2d, 703, 305, 800, 0, 3); + add(e2d, 703, 304, 800, 0, 4); + add(e2d, 703, 316, 800, 2, 0); + add(e2d, 703, 315, 800, 2, 1); + add(e2d, 703, 314, 800, 2, 2); + add(e2d, 703, 313, 800, 2, 3); + add(e2d, 703, 312, 800, 2, 4); + add(e2d, 703, 211, 800, 4, 0); + add(e2d, 703, 212, 800, 4, 1); + add(e2d, 703, 213, 800, 4, 2); + add(e2d, 703, 214, 800, 4, 3); + add(e2d, 703, 215, 800, 4, 4); + add(e2d, 703, 206, 800, 1, 0); + add(e2d, 703, 207, 800, 1, 1); + add(e2d, 703, 208, 800, 1, 2); + add(e2d, 703, 201, 800, 3, 0); + add(e2d, 703, 202, 800, 3, 1); + add(e2d, 703, 203, 800, 3, 2); add(e2d, 703, 1325, 801, 0, 0); add(e2d, 703, 1326, 801, 0, 1); add(e2d, 703, 1327, 801, 0, 2); @@ -147,25 +148,25 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 703, 1233, 801, 1, 1); add(e2d, 703, 1229, 801, 3, 0); add(e2d, 703, 1228, 801, 3, 1); - add(e2d, 703, 1, 802, 1, 0); - add(e2d, 703, 2, 802, 1, 1); - add(e2d, 703, 3, 802, 1, 2); - add(e2d, 703, 4, 802, 1, 3); - add(e2d, 703, 5, 802, 1, 4); - add(e2d, 703, 10, 802, 3, 0); - add(e2d, 703, 11, 802, 3, 1); - add(e2d, 703, 12, 802, 3, 2); - add(e2d, 703, 13, 802, 3, 3); - add(e2d, 703, 14, 802, 3, 4); - add(e2d, 703, 116, 802, 5, 0); - add(e2d, 703, 115, 802, 5, 1); - add(e2d, 703, 114, 802, 5, 2); - add(e2d, 703, 113, 802, 5, 3); - add(e2d, 703, 112, 802, 5, 4); - add(e2d, 703, 108, 802, 0, 0); - add(e2d, 703, 107, 802, 0, 1); - add(e2d, 703, 104, 802, 2, 0); - add(e2d, 703, 103, 802, 2, 1); + add(e2d, 703, 1, 802, 0, 0); + add(e2d, 703, 2, 802, 0, 1); + add(e2d, 703, 3, 802, 0, 2); + add(e2d, 703, 4, 802, 0, 3); + add(e2d, 703, 5, 802, 0, 4); + add(e2d, 703, 10, 802, 2, 0); + add(e2d, 703, 11, 802, 2, 1); + add(e2d, 703, 12, 802, 2, 2); + add(e2d, 703, 13, 802, 2, 3); + add(e2d, 703, 14, 802, 2, 4); + add(e2d, 703, 116, 802, 4, 0); + add(e2d, 703, 115, 802, 4, 1); + add(e2d, 703, 114, 802, 4, 2); + add(e2d, 703, 113, 802, 4, 3); + add(e2d, 703, 112, 802, 4, 4); + add(e2d, 703, 108, 802, 1, 0); + add(e2d, 703, 107, 802, 1, 1); + add(e2d, 703, 104, 802, 3, 0); + add(e2d, 703, 103, 802, 3, 1); add(e2d, 703, 1033, 803, 0, 0); add(e2d, 703, 1032, 803, 0, 1); add(e2d, 703, 1031, 803, 0, 2); @@ -181,38 +182,38 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 703, 1130, 803, 1, 1); add(e2d, 703, 1125, 803, 3, 0); add(e2d, 703, 1126, 803, 3, 1); - add(e2d, 702, 5, 804, 1, 0); - add(e2d, 702, 4, 804, 1, 1); - add(e2d, 702, 3, 804, 1, 2); - add(e2d, 702, 2, 804, 1, 3); - add(e2d, 702, 1, 804, 1, 4); - add(e2d, 702, 10, 804, 3, 0); - add(e2d, 702, 9, 804, 3, 1); - add(e2d, 702, 8, 804, 3, 2); - add(e2d, 702, 7, 804, 3, 3); - add(e2d, 702, 6, 804, 3, 4); - add(e2d, 702, 22, 804, 5, 0); - add(e2d, 702, 21, 804, 5, 1); - add(e2d, 702, 20, 804, 5, 2); - add(e2d, 702, 19, 804, 5, 3); - add(e2d, 702, 18, 804, 5, 4); - add(e2d, 702, 27, 804, 7, 0); - add(e2d, 702, 26, 804, 7, 1); - add(e2d, 702, 25, 804, 7, 2); - add(e2d, 702, 24, 804, 7, 3); - add(e2d, 702, 23, 804, 7, 4); - add(e2d, 702, 120, 804, 0, 0); - add(e2d, 702, 119, 804, 0, 1); - add(e2d, 702, 118, 804, 0, 2); - add(e2d, 702, 117, 804, 0, 3); - add(e2d, 702, 116, 804, 0, 4); - add(e2d, 702, 112, 804, 2, 0); - add(e2d, 702, 111, 804, 2, 1); - add(e2d, 702, 110, 804, 2, 2); - add(e2d, 702, 109, 804, 2, 3); - add(e2d, 702, 108, 804, 2, 4); - add(e2d, 702, 104, 804, 4, 0); - add(e2d, 702, 103, 804, 4, 1); + add(e2d, 702, 5, 804, 0, 0); + add(e2d, 702, 4, 804, 0, 1); + add(e2d, 702, 3, 804, 0, 2); + add(e2d, 702, 2, 804, 0, 3); + add(e2d, 702, 1, 804, 0, 4); + add(e2d, 702, 10, 804, 2, 0); + add(e2d, 702, 9, 804, 2, 1); + add(e2d, 702, 8, 804, 2, 2); + add(e2d, 702, 7, 804, 2, 3); + add(e2d, 702, 6, 804, 2, 4); + add(e2d, 702, 22, 804, 4, 0); + add(e2d, 702, 21, 804, 4, 1); + add(e2d, 702, 20, 804, 4, 2); + add(e2d, 702, 19, 804, 4, 3); + add(e2d, 702, 18, 804, 4, 4); + add(e2d, 702, 27, 804, 6, 0); + add(e2d, 702, 26, 804, 6, 1); + add(e2d, 702, 25, 804, 6, 2); + add(e2d, 702, 24, 804, 6, 3); + add(e2d, 702, 23, 804, 6, 4); + add(e2d, 702, 120, 804, 1, 0); + add(e2d, 702, 119, 804, 1, 1); + add(e2d, 702, 118, 804, 1, 2); + add(e2d, 702, 117, 804, 1, 3); + add(e2d, 702, 116, 804, 1, 4); + add(e2d, 702, 112, 804, 3, 0); + add(e2d, 702, 111, 804, 3, 1); + add(e2d, 702, 110, 804, 3, 2); + add(e2d, 702, 109, 804, 3, 3); + add(e2d, 702, 108, 804, 3, 4); + add(e2d, 702, 104, 804, 5, 0); + add(e2d, 702, 103, 804, 5, 1); add(e2d, 702, 1039, 805, 0, 0); add(e2d, 702, 1040, 805, 0, 1); add(e2d, 702, 1041, 805, 0, 2); @@ -235,39 +236,39 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 702, 1131, 805, 3, 2); add(e2d, 702, 1125, 805, 5, 0); add(e2d, 702, 1126, 805, 5, 1); - add(e2d, 702, 313, 816, 1, 0); - add(e2d, 702, 314, 816, 1, 1); - add(e2d, 702, 315, 816, 1, 2); - add(e2d, 702, 316, 816, 1, 3); - add(e2d, 702, 317, 816, 1, 4); - add(e2d, 702, 308, 816, 3, 0); - add(e2d, 702, 309, 816, 3, 1); - add(e2d, 702, 310, 816, 3, 2); - add(e2d, 702, 311, 816, 3, 3); - add(e2d, 702, 312, 816, 3, 4); - add(e2d, 702, 330, 816, 5, 0); - add(e2d, 702, 331, 816, 5, 1); - add(e2d, 702, 332, 816, 5, 2); - add(e2d, 702, 333, 816, 5, 3); - add(e2d, 702, 334, 816, 5, 4); - add(e2d, 702, 325, 816, 7, 0); - add(e2d, 702, 326, 816, 7, 1); - add(e2d, 702, 327, 816, 7, 2); - add(e2d, 702, 328, 816, 7, 3); - add(e2d, 702, 329, 816, 7, 4); - add(e2d, 702, 215, 816, 0, 0); - add(e2d, 702, 216, 816, 0, 1); - add(e2d, 702, 217, 816, 0, 2); - add(e2d, 702, 218, 816, 0, 3); - add(e2d, 702, 219, 816, 0, 4); - add(e2d, 702, 206, 816, 2, 0); - add(e2d, 702, 207, 816, 2, 1); - add(e2d, 702, 208, 816, 2, 2); - add(e2d, 702, 209, 816, 2, 3); - add(e2d, 702, 210, 816, 2, 4); - add(e2d, 702, 201, 816, 4, 0); - add(e2d, 702, 202, 816, 4, 1); - add(e2d, 702, 203, 816, 4, 2); + add(e2d, 702, 313, 816, 0, 0); + add(e2d, 702, 314, 816, 0, 1); + add(e2d, 702, 315, 816, 0, 2); + add(e2d, 702, 316, 816, 0, 3); + add(e2d, 702, 317, 816, 0, 4); + add(e2d, 702, 308, 816, 2, 0); + add(e2d, 702, 309, 816, 2, 1); + add(e2d, 702, 310, 816, 2, 2); + add(e2d, 702, 311, 816, 2, 3); + add(e2d, 702, 312, 816, 2, 4); + add(e2d, 702, 330, 816, 4, 0); + add(e2d, 702, 331, 816, 4, 1); + add(e2d, 702, 332, 816, 4, 2); + add(e2d, 702, 333, 816, 4, 3); + add(e2d, 702, 334, 816, 4, 4); + add(e2d, 702, 325, 816, 6, 0); + add(e2d, 702, 326, 816, 6, 1); + add(e2d, 702, 327, 816, 6, 2); + add(e2d, 702, 328, 816, 6, 3); + add(e2d, 702, 329, 816, 6, 4); + add(e2d, 702, 215, 816, 1, 0); + add(e2d, 702, 216, 816, 1, 1); + add(e2d, 702, 217, 816, 1, 2); + add(e2d, 702, 218, 816, 1, 3); + add(e2d, 702, 219, 816, 1, 4); + add(e2d, 702, 206, 816, 3, 0); + add(e2d, 702, 207, 816, 3, 1); + add(e2d, 702, 208, 816, 3, 2); + add(e2d, 702, 209, 816, 3, 3); + add(e2d, 702, 210, 816, 3, 4); + add(e2d, 702, 201, 816, 5, 0); + add(e2d, 702, 202, 816, 5, 1); + add(e2d, 702, 203, 816, 5, 2); add(e2d, 702, 1327, 817, 0, 0); add(e2d, 702, 1326, 817, 0, 1); add(e2d, 702, 1325, 817, 0, 2); @@ -292,41 +293,41 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 702, 1235, 817, 3, 3); add(e2d, 702, 1229, 817, 5, 0); add(e2d, 702, 1228, 817, 5, 1); - add(e2d, 701, 403, 818, 1, 0); - add(e2d, 701, 402, 818, 1, 1); - add(e2d, 701, 401, 818, 1, 2); - add(e2d, 701, 408, 818, 3, 0); - add(e2d, 701, 407, 818, 3, 1); - add(e2d, 701, 406, 818, 3, 2); - add(e2d, 701, 405, 818, 3, 3); - add(e2d, 701, 404, 818, 3, 4); - add(e2d, 701, 413, 818, 5, 0); - add(e2d, 701, 412, 818, 5, 1); - add(e2d, 701, 411, 818, 5, 2); - add(e2d, 701, 410, 818, 5, 3); - add(e2d, 701, 409, 818, 5, 4); - add(e2d, 701, 315, 818, 7, 0); - add(e2d, 701, 314, 818, 7, 1); - add(e2d, 701, 313, 818, 7, 2); - add(e2d, 701, 312, 818, 7, 3); - add(e2d, 701, 311, 818, 7, 4); - add(e2d, 701, 320, 818, 0, 0); - add(e2d, 701, 319, 818, 0, 1); - add(e2d, 701, 318, 818, 0, 2); - add(e2d, 701, 317, 818, 0, 3); - add(e2d, 701, 316, 818, 0, 4); - add(e2d, 701, 328, 818, 2, 0); - add(e2d, 701, 329, 818, 2, 1); - add(e2d, 701, 330, 818, 2, 2); - add(e2d, 701, 331, 818, 2, 3); - add(e2d, 701, 332, 818, 2, 4); - add(e2d, 701, 216, 818, 4, 0); - add(e2d, 701, 215, 818, 4, 1); - add(e2d, 701, 214, 818, 4, 2); - add(e2d, 701, 213, 818, 4, 3); - add(e2d, 701, 212, 818, 4, 4); - add(e2d, 701, 208, 818, 6, 0); - add(e2d, 701, 207, 818, 6, 1); + add(e2d, 701, 403, 818, 0, 0); + add(e2d, 701, 402, 818, 0, 1); + add(e2d, 701, 401, 818, 0, 2); + add(e2d, 701, 408, 818, 2, 0); + add(e2d, 701, 407, 818, 2, 1); + add(e2d, 701, 406, 818, 2, 2); + add(e2d, 701, 405, 818, 2, 3); + add(e2d, 701, 404, 818, 2, 4); + add(e2d, 701, 413, 818, 4, 0); + add(e2d, 701, 412, 818, 4, 1); + add(e2d, 701, 411, 818, 4, 2); + add(e2d, 701, 410, 818, 4, 3); + add(e2d, 701, 409, 818, 4, 4); + add(e2d, 701, 315, 818, 6, 0); + add(e2d, 701, 314, 818, 6, 1); + add(e2d, 701, 313, 818, 6, 2); + add(e2d, 701, 312, 818, 6, 3); + add(e2d, 701, 311, 818, 6, 4); + add(e2d, 701, 320, 818, 1, 0); + add(e2d, 701, 319, 818, 1, 1); + add(e2d, 701, 318, 818, 1, 2); + add(e2d, 701, 317, 818, 1, 3); + add(e2d, 701, 316, 818, 1, 4); + add(e2d, 701, 328, 818, 3, 0); + add(e2d, 701, 329, 818, 3, 1); + add(e2d, 701, 330, 818, 3, 2); + add(e2d, 701, 331, 818, 3, 3); + add(e2d, 701, 332, 818, 3, 4); + add(e2d, 701, 216, 818, 5, 0); + add(e2d, 701, 215, 818, 5, 1); + add(e2d, 701, 214, 818, 5, 2); + add(e2d, 701, 213, 818, 5, 3); + add(e2d, 701, 212, 818, 5, 4); + add(e2d, 701, 208, 818, 7, 0); + add(e2d, 701, 207, 818, 7, 1); add(e2d, 701, 1330, 819, 0, 0); add(e2d, 701, 1331, 819, 0, 1); add(e2d, 701, 1332, 819, 0, 2); @@ -355,36 +356,36 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 701, 1230, 819, 5, 1); add(e2d, 701, 1225, 819, 7, 0); add(e2d, 701, 1226, 819, 7, 1); - add(e2d, 701, 204, 820, 1, 0); - add(e2d, 701, 203, 820, 1, 1); - add(e2d, 701, 1, 820, 3, 0); - add(e2d, 701, 0, 820, 3, 1); - add(e2d, 701, 14, 820, 5, 0); - add(e2d, 701, 15, 820, 5, 1); - add(e2d, 701, 16, 820, 5, 2); - add(e2d, 701, 17, 820, 5, 3); - add(e2d, 701, 18, 820, 5, 4); - add(e2d, 701, 9, 820, 7, 0); - add(e2d, 701, 10, 820, 7, 1); - add(e2d, 701, 11, 820, 7, 2); - add(e2d, 701, 12, 820, 7, 3); - add(e2d, 701, 13, 820, 7, 4); - add(e2d, 701, 26, 820, 0, 0); - add(e2d, 701, 25, 820, 0, 1); - add(e2d, 701, 24, 820, 0, 2); - add(e2d, 701, 23, 820, 0, 3); - add(e2d, 701, 22, 820, 0, 4); - add(e2d, 701, 111, 820, 2, 0); - add(e2d, 701, 112, 820, 2, 1); - add(e2d, 701, 113, 820, 2, 2); - add(e2d, 701, 114, 820, 2, 3); - add(e2d, 701, 115, 820, 2, 4); - add(e2d, 701, 106, 820, 4, 0); - add(e2d, 701, 107, 820, 4, 1); - add(e2d, 701, 108, 820, 4, 2); - add(e2d, 701, 101, 820, 6, 0); - add(e2d, 701, 102, 820, 6, 1); - add(e2d, 701, 103, 820, 6, 2); + add(e2d, 701, 204, 820, 0, 0); + add(e2d, 701, 203, 820, 0, 1); + add(e2d, 701, 1, 820, 2, 0); + add(e2d, 701, 0, 820, 2, 1); + add(e2d, 701, 14, 820, 4, 0); + add(e2d, 701, 15, 820, 4, 1); + add(e2d, 701, 16, 820, 4, 2); + add(e2d, 701, 17, 820, 4, 3); + add(e2d, 701, 18, 820, 4, 4); + add(e2d, 701, 9, 820, 6, 0); + add(e2d, 701, 10, 820, 6, 1); + add(e2d, 701, 11, 820, 6, 2); + add(e2d, 701, 12, 820, 6, 3); + add(e2d, 701, 13, 820, 6, 4); + add(e2d, 701, 26, 820, 1, 0); + add(e2d, 701, 25, 820, 1, 1); + add(e2d, 701, 24, 820, 1, 2); + add(e2d, 701, 23, 820, 1, 3); + add(e2d, 701, 22, 820, 1, 4); + add(e2d, 701, 111, 820, 3, 0); + add(e2d, 701, 112, 820, 3, 1); + add(e2d, 701, 113, 820, 3, 2); + add(e2d, 701, 114, 820, 3, 3); + add(e2d, 701, 115, 820, 3, 4); + add(e2d, 701, 106, 820, 5, 0); + add(e2d, 701, 107, 820, 5, 1); + add(e2d, 701, 108, 820, 5, 2); + add(e2d, 701, 101, 820, 7, 0); + add(e2d, 701, 102, 820, 7, 1); + add(e2d, 701, 103, 820, 7, 2); add(e2d, 701, 1028, 821, 0, 0); add(e2d, 701, 1027, 821, 0, 1); add(e2d, 701, 1026, 821, 0, 2); @@ -403,30 +404,30 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 701, 1133, 821, 3, 1); add(e2d, 701, 1129, 821, 5, 0); add(e2d, 701, 1128, 821, 5, 1); - add(e2d, 700, 5, 624, 1, 0); - add(e2d, 700, 4, 624, 1, 1); - add(e2d, 700, 3, 624, 1, 2); - add(e2d, 700, 2, 624, 1, 3); - add(e2d, 700, 1, 624, 1, 4); - add(e2d, 700, 10, 624, 3, 0); - add(e2d, 700, 9, 624, 3, 1); - add(e2d, 700, 8, 624, 3, 2); - add(e2d, 700, 7, 624, 3, 3); - add(e2d, 700, 6, 624, 3, 4); - add(e2d, 700, 18, 624, 5, 0); - add(e2d, 700, 19, 624, 5, 1); - add(e2d, 700, 20, 624, 5, 2); - add(e2d, 700, 21, 624, 5, 3); - add(e2d, 700, 22, 624, 5, 4); - add(e2d, 700, 116, 624, 0, 0); - add(e2d, 700, 115, 624, 0, 1); - add(e2d, 700, 114, 624, 0, 2); - add(e2d, 700, 113, 624, 0, 3); - add(e2d, 700, 112, 624, 0, 4); - add(e2d, 700, 108, 624, 2, 0); - add(e2d, 700, 107, 624, 2, 1); - add(e2d, 700, 104, 624, 4, 0); - add(e2d, 700, 103, 624, 4, 1); + add(e2d, 700, 5, 624, 0, 0); + add(e2d, 700, 4, 624, 0, 1); + add(e2d, 700, 3, 624, 0, 2); + add(e2d, 700, 2, 624, 0, 3); + add(e2d, 700, 1, 624, 0, 4); + add(e2d, 700, 10, 624, 2, 0); + add(e2d, 700, 9, 624, 2, 1); + add(e2d, 700, 8, 624, 2, 2); + add(e2d, 700, 7, 624, 2, 3); + add(e2d, 700, 6, 624, 2, 4); + add(e2d, 700, 18, 624, 4, 0); + add(e2d, 700, 19, 624, 4, 1); + add(e2d, 700, 20, 624, 4, 2); + add(e2d, 700, 21, 624, 4, 3); + add(e2d, 700, 22, 624, 4, 4); + add(e2d, 700, 116, 624, 1, 0); + add(e2d, 700, 115, 624, 1, 1); + add(e2d, 700, 114, 624, 1, 2); + add(e2d, 700, 113, 624, 1, 3); + add(e2d, 700, 112, 624, 1, 4); + add(e2d, 700, 108, 624, 3, 0); + add(e2d, 700, 107, 624, 3, 1); + add(e2d, 700, 104, 624, 5, 0); + add(e2d, 700, 103, 624, 5, 1); add(e2d, 700, 1039, 625, 0, 0); add(e2d, 700, 1040, 625, 0, 1); add(e2d, 700, 1041, 625, 0, 2); @@ -445,32 +446,32 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 700, 1130, 625, 3, 1); add(e2d, 700, 1125, 625, 5, 0); add(e2d, 700, 1126, 625, 5, 1); - add(e2d, 700, 313, 626, 1, 0); - add(e2d, 700, 314, 626, 1, 1); - add(e2d, 700, 315, 626, 1, 2); - add(e2d, 700, 316, 626, 1, 3); - add(e2d, 700, 317, 626, 1, 4); - add(e2d, 700, 308, 626, 3, 0); - add(e2d, 700, 309, 626, 3, 1); - add(e2d, 700, 310, 626, 3, 2); - add(e2d, 700, 311, 626, 3, 3); - add(e2d, 700, 312, 626, 3, 4); - add(e2d, 700, 325, 626, 5, 0); - add(e2d, 700, 324, 626, 5, 1); - add(e2d, 700, 323, 626, 5, 2); - add(e2d, 700, 322, 626, 5, 3); - add(e2d, 700, 321, 626, 5, 4); - add(e2d, 700, 211, 626, 0, 0); - add(e2d, 700, 212, 626, 0, 1); - add(e2d, 700, 213, 626, 0, 2); - add(e2d, 700, 214, 626, 0, 3); - add(e2d, 700, 215, 626, 0, 4); - add(e2d, 700, 206, 626, 2, 0); - add(e2d, 700, 207, 626, 2, 1); - add(e2d, 700, 208, 626, 2, 2); - add(e2d, 700, 201, 626, 4, 0); - add(e2d, 700, 202, 626, 4, 1); - add(e2d, 700, 203, 626, 4, 2); + add(e2d, 700, 313, 626, 0, 0); + add(e2d, 700, 314, 626, 0, 1); + add(e2d, 700, 315, 626, 0, 2); + add(e2d, 700, 316, 626, 0, 3); + add(e2d, 700, 317, 626, 0, 4); + add(e2d, 700, 308, 626, 2, 0); + add(e2d, 700, 309, 626, 2, 1); + add(e2d, 700, 310, 626, 2, 2); + add(e2d, 700, 311, 626, 2, 3); + add(e2d, 700, 312, 626, 2, 4); + add(e2d, 700, 325, 626, 4, 0); + add(e2d, 700, 324, 626, 4, 1); + add(e2d, 700, 323, 626, 4, 2); + add(e2d, 700, 322, 626, 4, 3); + add(e2d, 700, 321, 626, 4, 4); + add(e2d, 700, 211, 626, 1, 0); + add(e2d, 700, 212, 626, 1, 1); + add(e2d, 700, 213, 626, 1, 2); + add(e2d, 700, 214, 626, 1, 3); + add(e2d, 700, 215, 626, 1, 4); + add(e2d, 700, 206, 626, 3, 0); + add(e2d, 700, 207, 626, 3, 1); + add(e2d, 700, 208, 626, 3, 2); + add(e2d, 700, 201, 626, 5, 0); + add(e2d, 700, 202, 626, 5, 1); + add(e2d, 700, 203, 626, 5, 2); add(e2d, 700, 1327, 627, 0, 0); add(e2d, 700, 1326, 627, 0, 1); add(e2d, 700, 1325, 627, 0, 2); @@ -489,36 +490,36 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 700, 1233, 627, 3, 1); add(e2d, 700, 1229, 627, 5, 0); add(e2d, 700, 1228, 627, 5, 1); - add(e2d, 725, 1, 528, 1, 0); - add(e2d, 725, 0, 528, 1, 1); - add(e2d, 725, 204, 528, 3, 0); - add(e2d, 725, 203, 528, 3, 1); - add(e2d, 725, 14, 528, 5, 0); - add(e2d, 725, 15, 528, 5, 1); - add(e2d, 725, 16, 528, 5, 2); - add(e2d, 725, 17, 528, 5, 3); - add(e2d, 725, 18, 528, 5, 4); - add(e2d, 725, 9, 528, 7, 0); - add(e2d, 725, 10, 528, 7, 1); - add(e2d, 725, 11, 528, 7, 2); - add(e2d, 725, 12, 528, 7, 3); - add(e2d, 725, 13, 528, 7, 4); - add(e2d, 725, 26, 528, 0, 0); - add(e2d, 725, 25, 528, 0, 1); - add(e2d, 725, 24, 528, 0, 2); - add(e2d, 725, 23, 528, 0, 3); - add(e2d, 725, 22, 528, 0, 4); - add(e2d, 725, 111, 528, 2, 0); - add(e2d, 725, 112, 528, 2, 1); - add(e2d, 725, 113, 528, 2, 2); - add(e2d, 725, 114, 528, 2, 3); - add(e2d, 725, 115, 528, 2, 4); - add(e2d, 725, 106, 528, 4, 0); - add(e2d, 725, 107, 528, 4, 1); - add(e2d, 725, 108, 528, 4, 2); - add(e2d, 725, 101, 528, 6, 0); - add(e2d, 725, 102, 528, 6, 1); - add(e2d, 725, 103, 528, 6, 2); + add(e2d, 725, 1, 528, 2, 0); + add(e2d, 725, 0, 528, 2, 1); + add(e2d, 725, 204, 528, 0, 0); + add(e2d, 725, 203, 528, 0, 1); + add(e2d, 725, 14, 528, 4, 0); + add(e2d, 725, 15, 528, 4, 1); + add(e2d, 725, 16, 528, 4, 2); + add(e2d, 725, 17, 528, 4, 3); + add(e2d, 725, 18, 528, 4, 4); + add(e2d, 725, 9, 528, 6, 0); + add(e2d, 725, 10, 528, 6, 1); + add(e2d, 725, 11, 528, 6, 2); + add(e2d, 725, 12, 528, 6, 3); + add(e2d, 725, 13, 528, 6, 4); + add(e2d, 725, 26, 528, 1, 0); + add(e2d, 725, 25, 528, 1, 1); + add(e2d, 725, 24, 528, 1, 2); + add(e2d, 725, 23, 528, 1, 3); + add(e2d, 725, 22, 528, 1, 4); + add(e2d, 725, 111, 528, 3, 0); + add(e2d, 725, 112, 528, 3, 1); + add(e2d, 725, 113, 528, 3, 2); + add(e2d, 725, 114, 528, 3, 3); + add(e2d, 725, 115, 528, 3, 4); + add(e2d, 725, 106, 528, 5, 0); + add(e2d, 725, 107, 528, 5, 1); + add(e2d, 725, 108, 528, 5, 2); + add(e2d, 725, 101, 528, 7, 0); + add(e2d, 725, 102, 528, 7, 1); + add(e2d, 725, 103, 528, 7, 2); add(e2d, 725, 1028, 529, 0, 0); add(e2d, 725, 1027, 529, 0, 1); add(e2d, 725, 1026, 529, 0, 2); @@ -537,41 +538,41 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 725, 1133, 529, 3, 1); add(e2d, 725, 1129, 529, 5, 0); add(e2d, 725, 1128, 529, 5, 1); - add(e2d, 725, 403, 530, 1, 0); - add(e2d, 725, 402, 530, 1, 1); - add(e2d, 725, 401, 530, 1, 2); - add(e2d, 725, 408, 530, 3, 0); - add(e2d, 725, 407, 530, 3, 1); - add(e2d, 725, 406, 530, 3, 2); - add(e2d, 725, 405, 530, 3, 3); - add(e2d, 725, 404, 530, 3, 4); - add(e2d, 725, 413, 530, 5, 0); - add(e2d, 725, 412, 530, 5, 1); - add(e2d, 725, 411, 530, 5, 2); - add(e2d, 725, 410, 530, 5, 3); - add(e2d, 725, 409, 530, 5, 4); - add(e2d, 725, 315, 530, 7, 0); - add(e2d, 725, 314, 530, 7, 1); - add(e2d, 725, 313, 530, 7, 2); - add(e2d, 725, 312, 530, 7, 3); - add(e2d, 725, 311, 530, 7, 4); - add(e2d, 725, 320, 530, 0, 0); - add(e2d, 725, 319, 530, 0, 1); - add(e2d, 725, 318, 530, 0, 2); - add(e2d, 725, 317, 530, 0, 3); - add(e2d, 725, 316, 530, 0, 4); - add(e2d, 725, 328, 530, 2, 0); - add(e2d, 725, 329, 530, 2, 1); - add(e2d, 725, 330, 530, 2, 2); - add(e2d, 725, 331, 530, 2, 3); - add(e2d, 725, 332, 530, 2, 4); - add(e2d, 725, 216, 530, 4, 0); - add(e2d, 725, 215, 530, 4, 1); - add(e2d, 725, 214, 530, 4, 2); - add(e2d, 725, 213, 530, 4, 3); - add(e2d, 725, 212, 530, 4, 4); - add(e2d, 725, 208, 530, 6, 0); - add(e2d, 725, 207, 530, 6, 1); + add(e2d, 725, 403, 530, 0, 0); + add(e2d, 725, 402, 530, 0, 1); + add(e2d, 725, 401, 530, 0, 2); + add(e2d, 725, 408, 530, 2, 0); + add(e2d, 725, 407, 530, 2, 1); + add(e2d, 725, 406, 530, 2, 2); + add(e2d, 725, 405, 530, 2, 3); + add(e2d, 725, 404, 530, 2, 4); + add(e2d, 725, 413, 530, 4, 0); + add(e2d, 725, 412, 530, 4, 1); + add(e2d, 725, 411, 530, 4, 2); + add(e2d, 725, 410, 530, 4, 3); + add(e2d, 725, 409, 530, 4, 4); + add(e2d, 725, 315, 530, 6, 0); + add(e2d, 725, 314, 530, 6, 1); + add(e2d, 725, 313, 530, 6, 2); + add(e2d, 725, 312, 530, 6, 3); + add(e2d, 725, 311, 530, 6, 4); + add(e2d, 725, 320, 530, 1, 0); + add(e2d, 725, 319, 530, 1, 1); + add(e2d, 725, 318, 530, 1, 2); + add(e2d, 725, 317, 530, 1, 3); + add(e2d, 725, 316, 530, 1, 4); + add(e2d, 725, 328, 530, 3, 0); + add(e2d, 725, 329, 530, 3, 1); + add(e2d, 725, 330, 530, 3, 2); + add(e2d, 725, 331, 530, 3, 3); + add(e2d, 725, 332, 530, 3, 4); + add(e2d, 725, 216, 530, 5, 0); + add(e2d, 725, 215, 530, 5, 1); + add(e2d, 725, 214, 530, 5, 2); + add(e2d, 725, 213, 530, 5, 3); + add(e2d, 725, 212, 530, 5, 4); + add(e2d, 725, 208, 530, 7, 0); + add(e2d, 725, 207, 530, 7, 1); add(e2d, 725, 1330, 531, 0, 0); add(e2d, 725, 1331, 531, 0, 1); add(e2d, 725, 1332, 531, 0, 2); @@ -600,38 +601,38 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 725, 1230, 531, 5, 1); add(e2d, 725, 1225, 531, 7, 0); add(e2d, 725, 1226, 531, 7, 1); - add(e2d, 724, 5, 532, 1, 0); - add(e2d, 724, 4, 532, 1, 1); - add(e2d, 724, 3, 532, 1, 2); - add(e2d, 724, 2, 532, 1, 3); - add(e2d, 724, 1, 532, 1, 4); - add(e2d, 724, 10, 532, 3, 0); - add(e2d, 724, 9, 532, 3, 1); - add(e2d, 724, 8, 532, 3, 2); - add(e2d, 724, 7, 532, 3, 3); - add(e2d, 724, 6, 532, 3, 4); - add(e2d, 724, 22, 532, 5, 0); - add(e2d, 724, 21, 532, 5, 1); - add(e2d, 724, 20, 532, 5, 2); - add(e2d, 724, 19, 532, 5, 3); - add(e2d, 724, 18, 532, 5, 4); - add(e2d, 724, 27, 532, 7, 0); - add(e2d, 724, 26, 532, 7, 1); - add(e2d, 724, 25, 532, 7, 2); - add(e2d, 724, 24, 532, 7, 3); - add(e2d, 724, 23, 532, 7, 4); - add(e2d, 724, 120, 532, 0, 0); - add(e2d, 724, 119, 532, 0, 1); - add(e2d, 724, 118, 532, 0, 2); - add(e2d, 724, 117, 532, 0, 3); - add(e2d, 724, 116, 532, 0, 4); - add(e2d, 724, 112, 532, 2, 0); - add(e2d, 724, 111, 532, 2, 1); - add(e2d, 724, 110, 532, 2, 2); - add(e2d, 724, 109, 532, 2, 3); - add(e2d, 724, 108, 532, 2, 4); - add(e2d, 724, 104, 532, 4, 0); - add(e2d, 724, 103, 532, 4, 1); + add(e2d, 724, 5, 532, 0, 0); + add(e2d, 724, 4, 532, 0, 1); + add(e2d, 724, 3, 532, 0, 2); + add(e2d, 724, 2, 532, 0, 3); + add(e2d, 724, 1, 532, 0, 4); + add(e2d, 724, 10, 532, 2, 0); + add(e2d, 724, 9, 532, 2, 1); + add(e2d, 724, 8, 532, 2, 2); + add(e2d, 724, 7, 532, 2, 3); + add(e2d, 724, 6, 532, 2, 4); + add(e2d, 724, 22, 532, 4, 0); + add(e2d, 724, 21, 532, 4, 1); + add(e2d, 724, 20, 532, 4, 2); + add(e2d, 724, 19, 532, 4, 3); + add(e2d, 724, 18, 532, 4, 4); + add(e2d, 724, 27, 532, 6, 0); + add(e2d, 724, 26, 532, 6, 1); + add(e2d, 724, 25, 532, 6, 2); + add(e2d, 724, 24, 532, 6, 3); + add(e2d, 724, 23, 532, 6, 4); + add(e2d, 724, 120, 532, 1, 0); + add(e2d, 724, 119, 532, 1, 1); + add(e2d, 724, 118, 532, 1, 2); + add(e2d, 724, 117, 532, 1, 3); + add(e2d, 724, 116, 532, 1, 4); + add(e2d, 724, 112, 532, 3, 0); + add(e2d, 724, 111, 532, 3, 1); + add(e2d, 724, 110, 532, 3, 2); + add(e2d, 724, 109, 532, 3, 3); + add(e2d, 724, 108, 532, 3, 4); + add(e2d, 724, 104, 532, 5, 0); + add(e2d, 724, 103, 532, 5, 1); add(e2d, 724, 1039, 533, 0, 0); add(e2d, 724, 1040, 533, 0, 1); add(e2d, 724, 1041, 533, 0, 2); @@ -654,40 +655,39 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 724, 1131, 533, 3, 2); add(e2d, 724, 1125, 533, 5, 0); add(e2d, 724, 1126, 533, 5, 1); - add(e2d, 724, 1127, 533, 5, 2); - add(e2d, 724, 313, 512, 1, 0); - add(e2d, 724, 314, 512, 1, 1); - add(e2d, 724, 315, 512, 1, 2); - add(e2d, 724, 316, 512, 1, 3); - add(e2d, 724, 317, 512, 1, 4); - add(e2d, 724, 308, 512, 3, 0); - add(e2d, 724, 309, 512, 3, 1); - add(e2d, 724, 310, 512, 3, 2); - add(e2d, 724, 311, 512, 3, 3); - add(e2d, 724, 312, 512, 3, 4); - add(e2d, 724, 330, 512, 5, 0); - add(e2d, 724, 331, 512, 5, 1); - add(e2d, 724, 332, 512, 5, 2); - add(e2d, 724, 333, 512, 5, 3); - add(e2d, 724, 334, 512, 5, 4); - add(e2d, 724, 325, 512, 7, 0); - add(e2d, 724, 326, 512, 7, 1); - add(e2d, 724, 327, 512, 7, 2); - add(e2d, 724, 328, 512, 7, 3); - add(e2d, 724, 329, 512, 7, 4); - add(e2d, 724, 215, 512, 0, 0); - add(e2d, 724, 216, 512, 0, 1); - add(e2d, 724, 217, 512, 0, 2); - add(e2d, 724, 218, 512, 0, 3); - add(e2d, 724, 219, 512, 0, 4); - add(e2d, 724, 206, 512, 2, 0); - add(e2d, 724, 207, 512, 2, 1); - add(e2d, 724, 208, 512, 2, 2); - add(e2d, 724, 209, 512, 2, 3); - add(e2d, 724, 210, 512, 2, 4); - add(e2d, 724, 201, 512, 4, 0); - add(e2d, 724, 202, 512, 4, 1); - add(e2d, 724, 203, 512, 4, 2); + add(e2d, 724, 313, 512, 0, 0); + add(e2d, 724, 314, 512, 0, 1); + add(e2d, 724, 315, 512, 0, 2); + add(e2d, 724, 316, 512, 0, 3); + add(e2d, 724, 317, 512, 0, 4); + add(e2d, 724, 308, 512, 2, 0); + add(e2d, 724, 309, 512, 2, 1); + add(e2d, 724, 310, 512, 2, 2); + add(e2d, 724, 311, 512, 2, 3); + add(e2d, 724, 312, 512, 2, 4); + add(e2d, 724, 330, 512, 4, 0); + add(e2d, 724, 331, 512, 4, 1); + add(e2d, 724, 332, 512, 4, 2); + add(e2d, 724, 333, 512, 4, 3); + add(e2d, 724, 334, 512, 4, 4); + add(e2d, 724, 325, 512, 6, 0); + add(e2d, 724, 326, 512, 6, 1); + add(e2d, 724, 327, 512, 6, 2); + add(e2d, 724, 328, 512, 6, 3); + add(e2d, 724, 329, 512, 6, 4); + add(e2d, 724, 215, 512, 1, 0); + add(e2d, 724, 216, 512, 1, 1); + add(e2d, 724, 217, 512, 1, 2); + add(e2d, 724, 218, 512, 1, 3); + add(e2d, 724, 219, 512, 1, 4); + add(e2d, 724, 206, 512, 3, 0); + add(e2d, 724, 207, 512, 3, 1); + add(e2d, 724, 208, 512, 3, 2); + add(e2d, 724, 209, 512, 3, 3); + add(e2d, 724, 210, 512, 3, 4); + add(e2d, 724, 201, 512, 5, 0); + add(e2d, 724, 202, 512, 5, 1); + add(e2d, 724, 203, 512, 5, 2); add(e2d, 724, 1327, 513, 0, 0); add(e2d, 724, 1326, 513, 0, 1); add(e2d, 724, 1325, 513, 0, 2); @@ -712,27 +712,27 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 724, 1235, 513, 3, 3); add(e2d, 724, 1229, 513, 5, 0); add(e2d, 724, 1228, 513, 5, 1); - add(e2d, 723, 308, 514, 1, 0); - add(e2d, 723, 307, 514, 1, 1); - add(e2d, 723, 306, 514, 1, 2); - add(e2d, 723, 305, 514, 1, 3); - add(e2d, 723, 304, 514, 1, 4); - add(e2d, 723, 316, 514, 3, 0); - add(e2d, 723, 315, 514, 3, 1); - add(e2d, 723, 314, 514, 3, 2); - add(e2d, 723, 313, 514, 3, 3); - add(e2d, 723, 312, 514, 3, 4); - add(e2d, 723, 211, 514, 5, 0); - add(e2d, 723, 212, 514, 5, 1); - add(e2d, 723, 213, 514, 5, 2); - add(e2d, 723, 214, 514, 5, 3); - add(e2d, 723, 215, 514, 5, 4); - add(e2d, 723, 206, 514, 0, 0); - add(e2d, 723, 207, 514, 0, 1); - add(e2d, 723, 208, 514, 0, 2); - add(e2d, 723, 201, 514, 2, 0); - add(e2d, 723, 202, 514, 2, 1); - add(e2d, 723, 203, 514, 2, 2); + add(e2d, 723, 308, 514, 0, 0); + add(e2d, 723, 307, 514, 0, 1); + add(e2d, 723, 306, 514, 0, 2); + add(e2d, 723, 305, 514, 0, 3); + add(e2d, 723, 304, 514, 0, 4); + add(e2d, 723, 316, 514, 2, 0); + add(e2d, 723, 315, 514, 2, 1); + add(e2d, 723, 314, 514, 2, 2); + add(e2d, 723, 313, 514, 2, 3); + add(e2d, 723, 312, 514, 2, 4); + add(e2d, 723, 211, 514, 4, 0); + add(e2d, 723, 212, 514, 4, 1); + add(e2d, 723, 213, 514, 4, 2); + add(e2d, 723, 214, 514, 4, 3); + add(e2d, 723, 215, 514, 4, 4); + add(e2d, 723, 206, 514, 1, 0); + add(e2d, 723, 207, 514, 1, 1); + add(e2d, 723, 208, 514, 1, 2); + add(e2d, 723, 201, 514, 3, 0); + add(e2d, 723, 202, 514, 3, 1); + add(e2d, 723, 203, 514, 3, 2); add(e2d, 723, 1325, 515, 0, 0); add(e2d, 723, 1326, 515, 0, 1); add(e2d, 723, 1327, 515, 0, 2); @@ -747,25 +747,25 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 723, 1233, 515, 1, 1); add(e2d, 723, 1229, 515, 3, 0); add(e2d, 723, 1228, 515, 3, 1); - add(e2d, 723, 1, 516, 1, 0); - add(e2d, 723, 2, 516, 1, 1); - add(e2d, 723, 3, 516, 1, 2); - add(e2d, 723, 4, 516, 1, 3); - add(e2d, 723, 5, 516, 1, 4); - add(e2d, 723, 10, 516, 3, 0); - add(e2d, 723, 11, 516, 3, 1); - add(e2d, 723, 12, 516, 3, 2); - add(e2d, 723, 13, 516, 3, 3); - add(e2d, 723, 14, 516, 3, 4); - add(e2d, 723, 116, 516, 5, 0); - add(e2d, 723, 115, 516, 5, 1); - add(e2d, 723, 114, 516, 5, 2); - add(e2d, 723, 113, 516, 5, 3); - add(e2d, 723, 112, 516, 5, 4); - add(e2d, 723, 108, 516, 0, 0); - add(e2d, 723, 107, 516, 0, 1); - add(e2d, 723, 104, 516, 2, 0); - add(e2d, 723, 103, 516, 2, 1); + add(e2d, 723, 1, 516, 0, 0); + add(e2d, 723, 2, 516, 0, 1); + add(e2d, 723, 3, 516, 0, 2); + add(e2d, 723, 4, 516, 0, 3); + add(e2d, 723, 5, 516, 0, 4); + add(e2d, 723, 10, 516, 2, 0); + add(e2d, 723, 11, 516, 2, 1); + add(e2d, 723, 12, 516, 2, 2); + add(e2d, 723, 13, 516, 2, 3); + add(e2d, 723, 14, 516, 2, 4); + add(e2d, 723, 116, 516, 4, 0); + add(e2d, 723, 115, 516, 4, 1); + add(e2d, 723, 114, 516, 4, 2); + add(e2d, 723, 113, 516, 4, 3); + add(e2d, 723, 112, 516, 4, 4); + add(e2d, 723, 108, 516, 1, 0); + add(e2d, 723, 107, 516, 1, 1); + add(e2d, 723, 104, 516, 3, 0); + add(e2d, 723, 103, 516, 3, 1); add(e2d, 723, 1033, 517, 0, 0); add(e2d, 723, 1032, 517, 0, 1); add(e2d, 723, 1031, 517, 0, 2); @@ -781,142 +781,142 @@ void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d) add(e2d, 723, 1130, 517, 1, 1); add(e2d, 723, 1125, 517, 3, 0); add(e2d, 723, 1126, 517, 3, 1); - add(e2d, 722, 1, 584, 1, 0); - add(e2d, 722, 2, 584, 1, 1); - add(e2d, 722, 3, 584, 1, 2); - add(e2d, 722, 4, 584, 1, 3); - add(e2d, 722, 5, 584, 1, 4); - add(e2d, 722, 116, 584, 3, 0); - add(e2d, 722, 115, 584, 3, 1); - add(e2d, 722, 114, 584, 3, 2); - add(e2d, 722, 113, 584, 3, 3); - add(e2d, 722, 112, 584, 3, 4); - add(e2d, 722, 108, 584, 5, 0); - add(e2d, 722, 107, 584, 5, 1); - add(e2d, 722, 104, 584, 7, 0); - add(e2d, 722, 103, 584, 7, 1); - add(e2d, 722, 1033, 584, 0, 0); - add(e2d, 722, 1032, 584, 0, 1); - add(e2d, 722, 1031, 584, 0, 2); - add(e2d, 722, 1030, 584, 0, 3); - add(e2d, 722, 1133, 584, 2, 0); - add(e2d, 722, 1134, 584, 2, 1); - add(e2d, 722, 1135, 584, 2, 2); - add(e2d, 722, 1129, 584, 4, 0); - add(e2d, 722, 1130, 584, 4, 1); - add(e2d, 722, 1125, 584, 6, 0); - add(e2d, 722, 1126, 584, 6, 1); - add(e2d, 722, 308, 585, 1, 0); - add(e2d, 722, 307, 585, 1, 1); - add(e2d, 722, 306, 585, 1, 2); - add(e2d, 722, 305, 585, 1, 3); - add(e2d, 722, 304, 585, 1, 4); - add(e2d, 722, 211, 585, 3, 0); - add(e2d, 722, 212, 585, 3, 1); - add(e2d, 722, 213, 585, 3, 2); - add(e2d, 722, 214, 585, 3, 3); - add(e2d, 722, 215, 585, 3, 4); - add(e2d, 722, 206, 585, 5, 0); - add(e2d, 722, 207, 585, 5, 1); - add(e2d, 722, 208, 585, 5, 2); - add(e2d, 722, 201, 585, 7, 0); - add(e2d, 722, 202, 585, 7, 1); - add(e2d, 722, 203, 585, 7, 2); - add(e2d, 722, 1325, 585, 0, 0); - add(e2d, 722, 1326, 585, 0, 1); - add(e2d, 722, 1327, 585, 0, 2); - add(e2d, 722, 1243, 585, 2, 0); - add(e2d, 722, 1242, 585, 2, 1); - add(e2d, 722, 1241, 585, 2, 2); - add(e2d, 722, 1240, 585, 2, 3); - add(e2d, 722, 1234, 585, 4, 0); - add(e2d, 722, 1233, 585, 4, 1); - add(e2d, 722, 1229, 585, 6, 0); - add(e2d, 722, 1228, 585, 6, 1); - add(e2d, 721, 111, 586, 1, 0); - add(e2d, 721, 112, 586, 1, 1); - add(e2d, 721, 113, 586, 1, 2); - add(e2d, 721, 106, 586, 3, 0); - add(e2d, 721, 107, 586, 3, 1); - add(e2d, 721, 108, 586, 3, 2); - add(e2d, 721, 101, 586, 5, 0); - add(e2d, 721, 102, 586, 5, 1); - add(e2d, 721, 103, 586, 5, 2); - add(e2d, 721, 1138, 586, 0, 0); - add(e2d, 721, 1139, 586, 0, 1); - add(e2d, 721, 1133, 586, 2, 0); - add(e2d, 721, 1134, 586, 2, 1); - add(e2d, 721, 1128, 586, 4, 0); - add(e2d, 721, 1129, 586, 4, 1); - add(e2d, 721, 12, 587, 1, 0); - add(e2d, 721, 11, 587, 1, 1); - add(e2d, 721, 8, 587, 3, 0); - add(e2d, 721, 7, 587, 3, 1); - add(e2d, 721, 4, 587, 5, 0); - add(e2d, 721, 3, 587, 5, 1); - add(e2d, 721, 1033, 587, 0, 0); - add(e2d, 721, 1034, 587, 0, 1); - add(e2d, 721, 1029, 587, 2, 0); - add(e2d, 721, 1030, 587, 2, 1); - add(e2d, 721, 1025, 587, 4, 0); - add(e2d, 721, 1026, 587, 4, 1); - add(e2d, 720, 8, 588, 1, 0); - add(e2d, 720, 7, 588, 1, 1); - add(e2d, 720, 4, 588, 3, 0); - add(e2d, 720, 3, 588, 3, 1); - add(e2d, 720, 1029, 588, 5, 0); - add(e2d, 720, 1030, 588, 5, 1); - add(e2d, 720, 1025, 588, 7, 0); - add(e2d, 720, 1026, 588, 7, 1); - add(e2d, 720, 106, 588, 0, 0); - add(e2d, 720, 107, 588, 0, 1); - add(e2d, 720, 108, 588, 0, 2); - add(e2d, 720, 101, 588, 2, 0); - add(e2d, 720, 102, 588, 2, 1); - add(e2d, 720, 103, 588, 2, 2); - add(e2d, 720, 1134, 588, 4, 0); - add(e2d, 720, 1133, 588, 4, 1); - add(e2d, 720, 1129, 588, 6, 0); - add(e2d, 720, 1128, 588, 6, 1); + add(e2d, 722, 1, 584, 0, 0); + add(e2d, 722, 2, 584, 0, 1); + add(e2d, 722, 3, 584, 0, 2); + add(e2d, 722, 4, 584, 0, 3); + add(e2d, 722, 5, 584, 0, 4); + add(e2d, 722, 116, 584, 2, 0); + add(e2d, 722, 115, 584, 2, 1); + add(e2d, 722, 114, 584, 2, 2); + add(e2d, 722, 113, 584, 2, 3); + add(e2d, 722, 112, 584, 2, 4); + add(e2d, 722, 108, 584, 4, 0); + add(e2d, 722, 107, 584, 4, 1); + add(e2d, 722, 104, 584, 6, 0); + add(e2d, 722, 103, 584, 6, 1); + add(e2d, 722, 1033, 584, 1, 0); + add(e2d, 722, 1032, 584, 1, 1); + add(e2d, 722, 1031, 584, 1, 2); + add(e2d, 722, 1030, 584, 1, 3); + add(e2d, 722, 1133, 584, 3, 0); + add(e2d, 722, 1134, 584, 3, 1); + add(e2d, 722, 1135, 584, 3, 2); + add(e2d, 722, 1129, 584, 5, 0); + add(e2d, 722, 1130, 584, 5, 1); + add(e2d, 722, 1125, 584, 7, 0); + add(e2d, 722, 1126, 584, 7, 1); + add(e2d, 722, 308, 585, 0, 0); + add(e2d, 722, 307, 585, 0, 1); + add(e2d, 722, 306, 585, 0, 2); + add(e2d, 722, 305, 585, 0, 3); + add(e2d, 722, 304, 585, 0, 4); + add(e2d, 722, 211, 585, 2, 0); + add(e2d, 722, 212, 585, 2, 1); + add(e2d, 722, 213, 585, 2, 2); + add(e2d, 722, 214, 585, 2, 3); + add(e2d, 722, 215, 585, 2, 4); + add(e2d, 722, 206, 585, 4, 0); + add(e2d, 722, 207, 585, 4, 1); + add(e2d, 722, 208, 585, 4, 2); + add(e2d, 722, 201, 585, 6, 0); + add(e2d, 722, 202, 585, 6, 1); + add(e2d, 722, 203, 585, 6, 2); + add(e2d, 722, 1325, 585, 1, 0); + add(e2d, 722, 1326, 585, 1, 1); + add(e2d, 722, 1327, 585, 1, 2); + add(e2d, 722, 1243, 585, 3, 0); + add(e2d, 722, 1242, 585, 3, 1); + add(e2d, 722, 1241, 585, 3, 2); + add(e2d, 722, 1240, 585, 3, 3); + add(e2d, 722, 1234, 585, 5, 0); + add(e2d, 722, 1233, 585, 5, 1); + add(e2d, 722, 1229, 585, 7, 0); + add(e2d, 722, 1228, 585, 7, 1); + add(e2d, 721, 111, 586, 0, 0); + add(e2d, 721, 112, 586, 0, 1); + add(e2d, 721, 113, 586, 0, 2); + add(e2d, 721, 106, 586, 2, 0); + add(e2d, 721, 107, 586, 2, 1); + add(e2d, 721, 108, 586, 2, 2); + add(e2d, 721, 101, 586, 4, 0); + add(e2d, 721, 102, 586, 4, 1); + add(e2d, 721, 103, 586, 4, 2); + add(e2d, 721, 1139, 586, 1, 0); + add(e2d, 721, 1138, 586, 1, 1); + add(e2d, 721, 1134, 586, 3, 0); + add(e2d, 721, 1133, 586, 3, 1); + add(e2d, 721, 1129, 586, 5, 0); + add(e2d, 721, 1128, 586, 5, 1); + add(e2d, 721, 12, 587, 0, 0); + add(e2d, 721, 11, 587, 0, 1); + add(e2d, 721, 8, 587, 2, 0); + add(e2d, 721, 7, 587, 2, 1); + add(e2d, 721, 4, 587, 4, 0); + add(e2d, 721, 3, 587, 4, 1); + add(e2d, 721, 1033, 587, 1, 0); + add(e2d, 721, 1034, 587, 1, 1); + add(e2d, 721, 1029, 587, 3, 0); + add(e2d, 721, 1030, 587, 3, 1); + add(e2d, 721, 1025, 587, 5, 0); + add(e2d, 721, 1026, 587, 5, 1); + add(e2d, 720, 8, 588, 0, 0); + add(e2d, 720, 7, 588, 0, 1); + add(e2d, 720, 4, 588, 2, 0); + add(e2d, 720, 3, 588, 2, 1); + add(e2d, 720, 1029, 588, 4, 0); + add(e2d, 720, 1030, 588, 4, 1); + add(e2d, 720, 1025, 588, 6, 0); + add(e2d, 720, 1026, 588, 6, 1); + add(e2d, 720, 106, 588, 1, 0); + add(e2d, 720, 107, 588, 1, 1); + add(e2d, 720, 108, 588, 1, 2); + add(e2d, 720, 101, 588, 3, 0); + add(e2d, 720, 102, 588, 3, 1); + add(e2d, 720, 103, 588, 3, 2); + add(e2d, 720, 1134, 588, 5, 0); + add(e2d, 720, 1133, 588, 5, 1); + add(e2d, 720, 1129, 588, 7, 0); + add(e2d, 720, 1128, 588, 7, 1); } void fillSolar2FeeLinkCH7R(std::map<uint16_t, uint32_t>& s2f) { - add_cru(s2f, 33, 2, 840); - add_cru(s2f, 33, 3, 841); - add_cru(s2f, 33, 4, 842); - add_cru(s2f, 33, 5, 843); - add_cru(s2f, 33, 6, 844); - add_cru(s2f, 33, 7, 800); - add_cru(s2f, 33, 8, 801); - add_cru(s2f, 33, 9, 802); - add_cru(s2f, 33, 10, 803); - add_cru(s2f, 33, 11, 804); - add_cru(s2f, 34, 0, 805); - add_cru(s2f, 34, 1, 816); - add_cru(s2f, 34, 2, 817); - add_cru(s2f, 34, 3, 818); - add_cru(s2f, 34, 4, 819); - add_cru(s2f, 34, 5, 820); - add_cru(s2f, 34, 6, 821); - add_cru(s2f, 34, 7, 624); - add_cru(s2f, 34, 8, 625); - add_cru(s2f, 34, 9, 626); - add_cru(s2f, 34, 10, 627); - add_cru(s2f, 34, 11, 528); - add_cru(s2f, 35, 0, 529); - add_cru(s2f, 35, 1, 530); - add_cru(s2f, 35, 2, 531); - add_cru(s2f, 35, 3, 532); - add_cru(s2f, 35, 4, 533); - add_cru(s2f, 35, 5, 512); - add_cru(s2f, 35, 6, 513); - add_cru(s2f, 35, 7, 514); - add_cru(s2f, 35, 8, 515); - add_cru(s2f, 35, 9, 516); - add_cru(s2f, 35, 10, 517); - add_cru(s2f, 35, 11, 584); - add_cru(s2f, 36, 0, 585); - add_cru(s2f, 36, 1, 586); - add_cru(s2f, 36, 2, 587); - add_cru(s2f, 36, 3, 588); + add_cru(s2f, 36, 0, 840); + add_cru(s2f, 36, 1, 841); + add_cru(s2f, 36, 2, 842); + add_cru(s2f, 36, 3, 843); + add_cru(s2f, 36, 4, 844); + add_cru(s2f, 37, 0, 800); + add_cru(s2f, 37, 1, 801); + add_cru(s2f, 37, 2, 802); + add_cru(s2f, 37, 3, 803); + add_cru(s2f, 37, 4, 804); + add_cru(s2f, 37, 5, 805); + add_cru(s2f, 37, 6, 816); + add_cru(s2f, 37, 7, 817); + add_cru(s2f, 37, 8, 818); + add_cru(s2f, 37, 9, 819); + add_cru(s2f, 37, 10, 820); + add_cru(s2f, 37, 11, 821); + add_cru(s2f, 38, 0, 624); + add_cru(s2f, 38, 1, 625); + add_cru(s2f, 38, 2, 626); + add_cru(s2f, 38, 3, 627); + add_cru(s2f, 38, 6, 528); + add_cru(s2f, 38, 7, 529); + add_cru(s2f, 38, 8, 530); + add_cru(s2f, 38, 9, 531); + add_cru(s2f, 38, 10, 532); + add_cru(s2f, 38, 11, 533); + add_cru(s2f, 39, 0, 512); + add_cru(s2f, 39, 1, 513); + add_cru(s2f, 39, 2, 514); + add_cru(s2f, 39, 3, 515); + add_cru(s2f, 39, 4, 516); + add_cru(s2f, 39, 5, 517); + add_cru(s2f, 39, 6, 584); + add_cru(s2f, 39, 7, 585); + add_cru(s2f, 39, 8, 586); + add_cru(s2f, 39, 9, 587); + add_cru(s2f, 39, 10, 588); } \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH8L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH8L.cxx index 64e133ffe8d6b..9a4cd4e8eef7c 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/CH8L.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH8L.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,909 +16,907 @@ #include "CH.cxx" void fillElec2DetCH8L(std::map<uint32_t, uint32_t>& e2d) { - add(e2d, 807, 8, 968, 0, 0); - add(e2d, 807, 7, 968, 0, 1); - add(e2d, 807, 4, 968, 2, 0); - add(e2d, 807, 3, 968, 2, 1); - add(e2d, 807, 1029, 968, 4, 0); - add(e2d, 807, 1030, 968, 4, 1); - add(e2d, 807, 1025, 968, 6, 0); - add(e2d, 807, 1026, 968, 6, 1); - add(e2d, 807, 106, 968, 1, 0); - add(e2d, 807, 107, 968, 1, 1); - add(e2d, 807, 108, 968, 1, 2); - add(e2d, 807, 101, 968, 3, 0); - add(e2d, 807, 102, 968, 3, 1); - add(e2d, 807, 103, 968, 3, 2); - add(e2d, 807, 1134, 968, 5, 0); - add(e2d, 807, 1133, 968, 5, 1); - add(e2d, 807, 1129, 968, 7, 0); - add(e2d, 807, 1128, 968, 7, 1); - add(e2d, 808, 111, 969, 1, 0); - add(e2d, 808, 112, 969, 1, 1); - add(e2d, 808, 113, 969, 1, 2); - add(e2d, 808, 106, 969, 3, 0); - add(e2d, 808, 107, 969, 3, 1); - add(e2d, 808, 108, 969, 3, 2); - add(e2d, 808, 101, 969, 5, 0); - add(e2d, 808, 102, 969, 5, 1); - add(e2d, 808, 103, 969, 5, 2); - add(e2d, 808, 1138, 969, 0, 0); - add(e2d, 808, 1139, 969, 0, 1); - add(e2d, 808, 1133, 969, 2, 0); - add(e2d, 808, 1134, 969, 2, 1); - add(e2d, 808, 1128, 969, 4, 0); - add(e2d, 808, 1129, 969, 4, 1); - add(e2d, 808, 12, 970, 1, 0); - add(e2d, 808, 11, 970, 1, 1); - add(e2d, 808, 8, 970, 3, 0); - add(e2d, 808, 7, 970, 3, 1); - add(e2d, 808, 4, 970, 5, 0); - add(e2d, 808, 3, 970, 5, 1); - add(e2d, 808, 1033, 970, 0, 0); - add(e2d, 808, 1034, 970, 0, 1); - add(e2d, 808, 1029, 970, 2, 0); - add(e2d, 808, 1030, 970, 2, 1); - add(e2d, 808, 1025, 970, 4, 0); - add(e2d, 808, 1026, 970, 4, 1); - add(e2d, 809, 1, 971, 1, 0); - add(e2d, 809, 2, 971, 1, 1); - add(e2d, 809, 3, 971, 1, 2); - add(e2d, 809, 4, 971, 1, 3); - add(e2d, 809, 5, 971, 1, 4); - add(e2d, 809, 116, 971, 3, 0); - add(e2d, 809, 115, 971, 3, 1); - add(e2d, 809, 114, 971, 3, 2); - add(e2d, 809, 113, 971, 3, 3); - add(e2d, 809, 112, 971, 3, 4); - add(e2d, 809, 108, 971, 5, 0); - add(e2d, 809, 107, 971, 5, 1); - add(e2d, 809, 104, 971, 7, 0); - add(e2d, 809, 103, 971, 7, 1); - add(e2d, 809, 1033, 971, 0, 0); - add(e2d, 809, 1032, 971, 0, 1); - add(e2d, 809, 1031, 971, 0, 2); - add(e2d, 809, 1030, 971, 0, 3); - add(e2d, 809, 1133, 971, 2, 0); - add(e2d, 809, 1134, 971, 2, 1); - add(e2d, 809, 1135, 971, 2, 2); - add(e2d, 809, 1129, 971, 4, 0); - add(e2d, 809, 1130, 971, 4, 1); - add(e2d, 809, 1125, 971, 6, 0); - add(e2d, 809, 1126, 971, 6, 1); - add(e2d, 809, 308, 972, 1, 0); - add(e2d, 809, 307, 972, 1, 1); - add(e2d, 809, 306, 972, 1, 2); - add(e2d, 809, 305, 972, 1, 3); - add(e2d, 809, 304, 972, 1, 4); - add(e2d, 809, 211, 972, 3, 0); - add(e2d, 809, 212, 972, 3, 1); - add(e2d, 809, 213, 972, 3, 2); - add(e2d, 809, 214, 972, 3, 3); - add(e2d, 809, 215, 972, 3, 4); - add(e2d, 809, 206, 972, 5, 0); - add(e2d, 809, 207, 972, 5, 1); - add(e2d, 809, 208, 972, 5, 2); - add(e2d, 809, 201, 972, 7, 0); - add(e2d, 809, 202, 972, 7, 1); - add(e2d, 809, 203, 972, 7, 2); - add(e2d, 809, 1325, 972, 0, 0); - add(e2d, 809, 1326, 972, 0, 1); - add(e2d, 809, 1327, 972, 0, 2); - add(e2d, 809, 1243, 972, 2, 0); - add(e2d, 809, 1242, 972, 2, 1); - add(e2d, 809, 1241, 972, 2, 2); - add(e2d, 809, 1240, 972, 2, 3); - add(e2d, 809, 1234, 972, 4, 0); - add(e2d, 809, 1233, 972, 4, 1); - add(e2d, 809, 1229, 972, 6, 0); - add(e2d, 809, 1228, 972, 6, 1); - add(e2d, 810, 308, 976, 1, 0); - add(e2d, 810, 307, 976, 1, 1); - add(e2d, 810, 306, 976, 1, 2); - add(e2d, 810, 305, 976, 1, 3); - add(e2d, 810, 304, 976, 1, 4); - add(e2d, 810, 316, 976, 3, 0); - add(e2d, 810, 315, 976, 3, 1); - add(e2d, 810, 314, 976, 3, 2); - add(e2d, 810, 313, 976, 3, 3); - add(e2d, 810, 312, 976, 3, 4); - add(e2d, 810, 211, 976, 5, 0); - add(e2d, 810, 212, 976, 5, 1); - add(e2d, 810, 213, 976, 5, 2); - add(e2d, 810, 214, 976, 5, 3); - add(e2d, 810, 215, 976, 5, 4); - add(e2d, 810, 206, 976, 0, 0); - add(e2d, 810, 207, 976, 0, 1); - add(e2d, 810, 208, 976, 0, 2); - add(e2d, 810, 201, 976, 2, 0); - add(e2d, 810, 202, 976, 2, 1); - add(e2d, 810, 203, 976, 2, 2); - add(e2d, 810, 1325, 977, 0, 0); - add(e2d, 810, 1326, 977, 0, 1); - add(e2d, 810, 1327, 977, 0, 2); - add(e2d, 810, 1333, 977, 2, 0); - add(e2d, 810, 1334, 977, 2, 1); - add(e2d, 810, 1335, 977, 2, 2); - add(e2d, 810, 1243, 977, 4, 0); - add(e2d, 810, 1242, 977, 4, 1); - add(e2d, 810, 1241, 977, 4, 2); - add(e2d, 810, 1240, 977, 4, 3); - add(e2d, 810, 1234, 977, 1, 0); - add(e2d, 810, 1233, 977, 1, 1); - add(e2d, 810, 1229, 977, 3, 0); - add(e2d, 810, 1228, 977, 3, 1); - add(e2d, 810, 1, 978, 1, 0); - add(e2d, 810, 2, 978, 1, 1); - add(e2d, 810, 3, 978, 1, 2); - add(e2d, 810, 4, 978, 1, 3); - add(e2d, 810, 5, 978, 1, 4); - add(e2d, 810, 10, 978, 3, 0); - add(e2d, 810, 11, 978, 3, 1); - add(e2d, 810, 12, 978, 3, 2); - add(e2d, 810, 13, 978, 3, 3); - add(e2d, 810, 14, 978, 3, 4); - add(e2d, 810, 116, 978, 5, 0); - add(e2d, 810, 115, 978, 5, 1); - add(e2d, 810, 114, 978, 5, 2); - add(e2d, 810, 113, 978, 5, 3); - add(e2d, 810, 112, 978, 5, 4); - add(e2d, 810, 108, 978, 0, 0); - add(e2d, 810, 107, 978, 0, 1); - add(e2d, 810, 104, 978, 2, 0); - add(e2d, 810, 103, 978, 2, 1); - add(e2d, 810, 1033, 979, 0, 0); - add(e2d, 810, 1032, 979, 0, 1); - add(e2d, 810, 1031, 979, 0, 2); - add(e2d, 810, 1030, 979, 0, 3); - add(e2d, 810, 1042, 979, 2, 0); - add(e2d, 810, 1041, 979, 2, 1); - add(e2d, 810, 1040, 979, 2, 2); - add(e2d, 810, 1039, 979, 2, 3); - add(e2d, 810, 1133, 979, 4, 0); - add(e2d, 810, 1134, 979, 4, 1); - add(e2d, 810, 1135, 979, 4, 2); - add(e2d, 810, 1129, 979, 1, 0); - add(e2d, 810, 1130, 979, 1, 1); - add(e2d, 810, 1125, 979, 3, 0); - add(e2d, 810, 1126, 979, 3, 1); - add(e2d, 811, 5, 980, 1, 0); - add(e2d, 811, 4, 980, 1, 1); - add(e2d, 811, 3, 980, 1, 2); - add(e2d, 811, 2, 980, 1, 3); - add(e2d, 811, 1, 980, 1, 4); - add(e2d, 811, 10, 980, 3, 0); - add(e2d, 811, 9, 980, 3, 1); - add(e2d, 811, 8, 980, 3, 2); - add(e2d, 811, 7, 980, 3, 3); - add(e2d, 811, 6, 980, 3, 4); - add(e2d, 811, 22, 980, 5, 0); - add(e2d, 811, 21, 980, 5, 1); - add(e2d, 811, 20, 980, 5, 2); - add(e2d, 811, 19, 980, 5, 3); - add(e2d, 811, 18, 980, 5, 4); - add(e2d, 811, 27, 980, 7, 0); - add(e2d, 811, 26, 980, 7, 1); - add(e2d, 811, 25, 980, 7, 2); - add(e2d, 811, 24, 980, 7, 3); - add(e2d, 811, 23, 980, 7, 4); - add(e2d, 811, 120, 980, 0, 0); - add(e2d, 811, 119, 980, 0, 1); - add(e2d, 811, 118, 980, 0, 2); - add(e2d, 811, 117, 980, 0, 3); - add(e2d, 811, 116, 980, 0, 4); - add(e2d, 811, 112, 980, 2, 0); - add(e2d, 811, 111, 980, 2, 1); - add(e2d, 811, 110, 980, 2, 2); - add(e2d, 811, 109, 980, 2, 3); - add(e2d, 811, 108, 980, 2, 4); - add(e2d, 811, 104, 980, 4, 0); - add(e2d, 811, 103, 980, 4, 1); - add(e2d, 811, 1039, 981, 0, 0); - add(e2d, 811, 1040, 981, 0, 1); - add(e2d, 811, 1041, 981, 0, 2); - add(e2d, 811, 1035, 981, 2, 0); - add(e2d, 811, 1036, 981, 2, 1); - add(e2d, 811, 1037, 981, 2, 2); - add(e2d, 811, 1038, 981, 2, 3); - add(e2d, 811, 1056, 981, 4, 0); - add(e2d, 811, 1057, 981, 4, 1); - add(e2d, 811, 1058, 981, 4, 2); - add(e2d, 811, 1052, 981, 6, 0); - add(e2d, 811, 1053, 981, 6, 1); - add(e2d, 811, 1054, 981, 6, 2); - add(e2d, 811, 1055, 981, 6, 3); - add(e2d, 811, 1137, 981, 1, 0); - add(e2d, 811, 1138, 981, 1, 1); - add(e2d, 811, 1139, 981, 1, 2); - add(e2d, 811, 1129, 981, 3, 0); - add(e2d, 811, 1130, 981, 3, 1); - add(e2d, 811, 1131, 981, 3, 2); - add(e2d, 811, 1125, 981, 5, 0); - add(e2d, 811, 1126, 981, 5, 1); - add(e2d, 811, 1127, 981, 5, 2); - add(e2d, 811, 313, 984, 1, 0); - add(e2d, 811, 314, 984, 1, 1); - add(e2d, 811, 315, 984, 1, 2); - add(e2d, 811, 316, 984, 1, 3); - add(e2d, 811, 317, 984, 1, 4); - add(e2d, 811, 308, 984, 3, 0); - add(e2d, 811, 309, 984, 3, 1); - add(e2d, 811, 310, 984, 3, 2); - add(e2d, 811, 311, 984, 3, 3); - add(e2d, 811, 312, 984, 3, 4); - add(e2d, 811, 330, 984, 5, 0); - add(e2d, 811, 331, 984, 5, 1); - add(e2d, 811, 332, 984, 5, 2); - add(e2d, 811, 333, 984, 5, 3); - add(e2d, 811, 334, 984, 5, 4); - add(e2d, 811, 325, 984, 7, 0); - add(e2d, 811, 326, 984, 7, 1); - add(e2d, 811, 327, 984, 7, 2); - add(e2d, 811, 328, 984, 7, 3); - add(e2d, 811, 329, 984, 7, 4); - add(e2d, 811, 215, 984, 0, 0); - add(e2d, 811, 216, 984, 0, 1); - add(e2d, 811, 217, 984, 0, 2); - add(e2d, 811, 218, 984, 0, 3); - add(e2d, 811, 219, 984, 0, 4); - add(e2d, 811, 206, 984, 2, 0); - add(e2d, 811, 207, 984, 2, 1); - add(e2d, 811, 208, 984, 2, 2); - add(e2d, 811, 209, 984, 2, 3); - add(e2d, 811, 210, 984, 2, 4); - add(e2d, 811, 201, 984, 4, 0); - add(e2d, 811, 202, 984, 4, 1); - add(e2d, 811, 203, 984, 4, 2); - add(e2d, 811, 1327, 985, 0, 0); - add(e2d, 811, 1326, 985, 0, 1); - add(e2d, 811, 1325, 985, 0, 2); - add(e2d, 811, 1331, 985, 2, 0); - add(e2d, 811, 1330, 985, 2, 1); - add(e2d, 811, 1329, 985, 2, 2); - add(e2d, 811, 1328, 985, 2, 3); - add(e2d, 811, 1344, 985, 4, 0); - add(e2d, 811, 1343, 985, 4, 1); - add(e2d, 811, 1342, 985, 4, 2); - add(e2d, 811, 1348, 985, 6, 0); - add(e2d, 811, 1347, 985, 6, 1); - add(e2d, 811, 1346, 985, 6, 2); - add(e2d, 811, 1345, 985, 6, 3); - add(e2d, 811, 1247, 985, 1, 0); - add(e2d, 811, 1246, 985, 1, 1); - add(e2d, 811, 1245, 985, 1, 2); - add(e2d, 811, 1244, 985, 1, 3); - add(e2d, 811, 1238, 985, 3, 0); - add(e2d, 811, 1237, 985, 3, 1); - add(e2d, 811, 1236, 985, 3, 2); - add(e2d, 811, 1235, 985, 3, 3); - add(e2d, 811, 1229, 985, 5, 0); - add(e2d, 811, 1228, 985, 5, 1); - add(e2d, 812, 403, 986, 1, 0); - add(e2d, 812, 402, 986, 1, 1); - add(e2d, 812, 401, 986, 1, 2); - add(e2d, 812, 408, 986, 3, 0); - add(e2d, 812, 407, 986, 3, 1); - add(e2d, 812, 406, 986, 3, 2); - add(e2d, 812, 405, 986, 3, 3); - add(e2d, 812, 404, 986, 3, 4); - add(e2d, 812, 413, 986, 5, 0); - add(e2d, 812, 412, 986, 5, 1); - add(e2d, 812, 411, 986, 5, 2); - add(e2d, 812, 410, 986, 5, 3); - add(e2d, 812, 409, 986, 5, 4); - add(e2d, 812, 315, 986, 7, 0); - add(e2d, 812, 314, 986, 7, 1); - add(e2d, 812, 313, 986, 7, 2); - add(e2d, 812, 312, 986, 7, 3); - add(e2d, 812, 311, 986, 7, 4); - add(e2d, 812, 320, 986, 0, 0); - add(e2d, 812, 319, 986, 0, 1); - add(e2d, 812, 318, 986, 0, 2); - add(e2d, 812, 317, 986, 0, 3); - add(e2d, 812, 316, 986, 0, 4); - add(e2d, 812, 328, 986, 2, 0); - add(e2d, 812, 329, 986, 2, 1); - add(e2d, 812, 330, 986, 2, 2); - add(e2d, 812, 331, 986, 2, 3); - add(e2d, 812, 332, 986, 2, 4); - add(e2d, 812, 216, 986, 4, 0); - add(e2d, 812, 215, 986, 4, 1); - add(e2d, 812, 214, 986, 4, 2); - add(e2d, 812, 213, 986, 4, 3); - add(e2d, 812, 212, 986, 4, 4); - add(e2d, 812, 208, 986, 6, 0); - add(e2d, 812, 207, 986, 6, 1); - add(e2d, 812, 1330, 987, 0, 0); - add(e2d, 812, 1331, 987, 0, 1); - add(e2d, 812, 1332, 987, 0, 2); - add(e2d, 812, 1333, 987, 0, 3); - add(e2d, 812, 1334, 987, 0, 4); - add(e2d, 812, 1325, 987, 2, 0); - add(e2d, 812, 1326, 987, 2, 1); - add(e2d, 812, 1327, 987, 2, 2); - add(e2d, 812, 1328, 987, 2, 3); - add(e2d, 812, 1329, 987, 2, 4); - add(e2d, 812, 1349, 987, 4, 0); - add(e2d, 812, 1350, 987, 4, 1); - add(e2d, 812, 1351, 987, 4, 2); - add(e2d, 812, 1345, 987, 6, 0); - add(e2d, 812, 1346, 987, 6, 1); - add(e2d, 812, 1347, 987, 6, 2); - add(e2d, 812, 1348, 987, 6, 3); - add(e2d, 812, 1360, 987, 1, 0); - add(e2d, 812, 1359, 987, 1, 1); - add(e2d, 812, 1358, 987, 1, 2); - add(e2d, 812, 1357, 987, 1, 3); - add(e2d, 812, 1233, 987, 3, 0); - add(e2d, 812, 1234, 987, 3, 1); - add(e2d, 812, 1235, 987, 3, 2); - add(e2d, 812, 1229, 987, 5, 0); - add(e2d, 812, 1230, 987, 5, 1); - add(e2d, 812, 1225, 987, 7, 0); - add(e2d, 812, 1226, 987, 7, 1); - add(e2d, 812, 204, 988, 1, 0); - add(e2d, 812, 203, 988, 1, 1); - add(e2d, 812, 1, 988, 3, 0); - add(e2d, 812, 0, 988, 3, 1); - add(e2d, 812, 14, 988, 5, 0); - add(e2d, 812, 15, 988, 5, 1); - add(e2d, 812, 16, 988, 5, 2); - add(e2d, 812, 17, 988, 5, 3); - add(e2d, 812, 18, 988, 5, 4); - add(e2d, 812, 9, 988, 7, 0); - add(e2d, 812, 10, 988, 7, 1); - add(e2d, 812, 11, 988, 7, 2); - add(e2d, 812, 12, 988, 7, 3); - add(e2d, 812, 13, 988, 7, 4); - add(e2d, 812, 26, 988, 0, 0); - add(e2d, 812, 25, 988, 0, 1); - add(e2d, 812, 24, 988, 0, 2); - add(e2d, 812, 23, 988, 0, 3); - add(e2d, 812, 22, 988, 0, 4); - add(e2d, 812, 111, 988, 2, 0); - add(e2d, 812, 112, 988, 2, 1); - add(e2d, 812, 113, 988, 2, 2); - add(e2d, 812, 114, 988, 2, 3); - add(e2d, 812, 115, 988, 2, 4); - add(e2d, 812, 106, 988, 4, 0); - add(e2d, 812, 107, 988, 4, 1); - add(e2d, 812, 108, 988, 4, 2); - add(e2d, 812, 101, 988, 6, 0); - add(e2d, 812, 102, 988, 6, 1); - add(e2d, 812, 103, 988, 6, 2); - add(e2d, 812, 1028, 989, 0, 0); - add(e2d, 812, 1027, 989, 0, 1); - add(e2d, 812, 1026, 989, 0, 2); - add(e2d, 812, 1032, 989, 2, 0); - add(e2d, 812, 1031, 989, 2, 1); - add(e2d, 812, 1030, 989, 2, 2); - add(e2d, 812, 1029, 989, 2, 3); - add(e2d, 812, 1043, 989, 4, 0); - add(e2d, 812, 1044, 989, 4, 1); - add(e2d, 812, 1045, 989, 4, 2); - add(e2d, 812, 1143, 989, 1, 0); - add(e2d, 812, 1142, 989, 1, 1); - add(e2d, 812, 1141, 989, 1, 2); - add(e2d, 812, 1140, 989, 1, 3); - add(e2d, 812, 1134, 989, 3, 0); - add(e2d, 812, 1133, 989, 3, 1); - add(e2d, 812, 1129, 989, 5, 0); - add(e2d, 812, 1128, 989, 5, 1); - add(e2d, 813, 5, 992, 1, 0); - add(e2d, 813, 4, 992, 1, 1); - add(e2d, 813, 3, 992, 1, 2); - add(e2d, 813, 2, 992, 1, 3); - add(e2d, 813, 1, 992, 1, 4); - add(e2d, 813, 10, 992, 3, 0); - add(e2d, 813, 9, 992, 3, 1); - add(e2d, 813, 8, 992, 3, 2); - add(e2d, 813, 7, 992, 3, 3); - add(e2d, 813, 6, 992, 3, 4); - add(e2d, 813, 18, 992, 5, 0); - add(e2d, 813, 19, 992, 5, 1); - add(e2d, 813, 20, 992, 5, 2); - add(e2d, 813, 21, 992, 5, 3); - add(e2d, 813, 22, 992, 5, 4); - add(e2d, 813, 116, 992, 0, 0); - add(e2d, 813, 115, 992, 0, 1); - add(e2d, 813, 114, 992, 0, 2); - add(e2d, 813, 113, 992, 0, 3); - add(e2d, 813, 112, 992, 0, 4); - add(e2d, 813, 108, 992, 2, 0); - add(e2d, 813, 107, 992, 2, 1); - add(e2d, 813, 104, 992, 4, 0); - add(e2d, 813, 103, 992, 4, 1); - add(e2d, 813, 1039, 993, 0, 0); - add(e2d, 813, 1040, 993, 0, 1); - add(e2d, 813, 1041, 993, 0, 2); - add(e2d, 813, 1035, 993, 2, 0); - add(e2d, 813, 1036, 993, 2, 1); - add(e2d, 813, 1037, 993, 2, 2); - add(e2d, 813, 1038, 993, 2, 3); - add(e2d, 813, 1050, 993, 4, 0); - add(e2d, 813, 1049, 993, 4, 1); - add(e2d, 813, 1048, 993, 4, 2); - add(e2d, 813, 1047, 993, 4, 3); - add(e2d, 813, 1133, 993, 1, 0); - add(e2d, 813, 1134, 993, 1, 1); - add(e2d, 813, 1135, 993, 1, 2); - add(e2d, 813, 1129, 993, 3, 0); - add(e2d, 813, 1130, 993, 3, 1); - add(e2d, 813, 1125, 993, 5, 0); - add(e2d, 813, 1126, 993, 5, 1); - add(e2d, 813, 313, 994, 1, 0); - add(e2d, 813, 314, 994, 1, 1); - add(e2d, 813, 315, 994, 1, 2); - add(e2d, 813, 316, 994, 1, 3); - add(e2d, 813, 317, 994, 1, 4); - add(e2d, 813, 308, 994, 3, 0); - add(e2d, 813, 309, 994, 3, 1); - add(e2d, 813, 310, 994, 3, 2); - add(e2d, 813, 311, 994, 3, 3); - add(e2d, 813, 312, 994, 3, 4); - add(e2d, 813, 325, 994, 5, 0); - add(e2d, 813, 324, 994, 5, 1); - add(e2d, 813, 323, 994, 5, 2); - add(e2d, 813, 322, 994, 5, 3); - add(e2d, 813, 321, 994, 5, 4); - add(e2d, 813, 211, 994, 0, 0); - add(e2d, 813, 212, 994, 0, 1); - add(e2d, 813, 213, 994, 0, 2); - add(e2d, 813, 214, 994, 0, 3); - add(e2d, 813, 215, 994, 0, 4); - add(e2d, 813, 206, 994, 2, 0); - add(e2d, 813, 207, 994, 2, 1); - add(e2d, 813, 208, 994, 2, 2); - add(e2d, 813, 201, 994, 4, 0); - add(e2d, 813, 202, 994, 4, 1); - add(e2d, 813, 203, 994, 4, 2); - add(e2d, 813, 1327, 995, 0, 0); - add(e2d, 813, 1326, 995, 0, 1); - add(e2d, 813, 1325, 995, 0, 2); - add(e2d, 813, 1331, 995, 2, 0); - add(e2d, 813, 1330, 995, 2, 1); - add(e2d, 813, 1329, 995, 2, 2); - add(e2d, 813, 1328, 995, 2, 3); - add(e2d, 813, 1342, 995, 4, 0); - add(e2d, 813, 1343, 995, 4, 1); - add(e2d, 813, 1344, 995, 4, 2); - add(e2d, 813, 1243, 995, 1, 0); - add(e2d, 813, 1242, 995, 1, 1); - add(e2d, 813, 1241, 995, 1, 2); - add(e2d, 813, 1240, 995, 1, 3); - add(e2d, 813, 1234, 995, 3, 0); - add(e2d, 813, 1233, 995, 3, 1); - add(e2d, 813, 1229, 995, 5, 0); - add(e2d, 813, 1228, 995, 5, 1); - add(e2d, 814, 1, 1000, 1, 0); - add(e2d, 814, 0, 1000, 1, 1); - add(e2d, 814, 204, 1000, 3, 0); - add(e2d, 814, 203, 1000, 3, 1); - add(e2d, 814, 14, 1000, 5, 0); - add(e2d, 814, 15, 1000, 5, 1); - add(e2d, 814, 16, 1000, 5, 2); - add(e2d, 814, 17, 1000, 5, 3); - add(e2d, 814, 18, 1000, 5, 4); - add(e2d, 814, 9, 1000, 7, 0); - add(e2d, 814, 10, 1000, 7, 1); - add(e2d, 814, 11, 1000, 7, 2); - add(e2d, 814, 12, 1000, 7, 3); - add(e2d, 814, 13, 1000, 7, 4); - add(e2d, 814, 26, 1000, 0, 0); - add(e2d, 814, 25, 1000, 0, 1); - add(e2d, 814, 24, 1000, 0, 2); - add(e2d, 814, 23, 1000, 0, 3); - add(e2d, 814, 22, 1000, 0, 4); - add(e2d, 814, 111, 1000, 2, 0); - add(e2d, 814, 112, 1000, 2, 1); - add(e2d, 814, 113, 1000, 2, 2); - add(e2d, 814, 114, 1000, 2, 3); - add(e2d, 814, 115, 1000, 2, 4); - add(e2d, 814, 106, 1000, 4, 0); - add(e2d, 814, 107, 1000, 4, 1); - add(e2d, 814, 108, 1000, 4, 2); - add(e2d, 814, 101, 1000, 6, 0); - add(e2d, 814, 102, 1000, 6, 1); - add(e2d, 814, 103, 1000, 6, 2); - add(e2d, 814, 1028, 1001, 0, 0); - add(e2d, 814, 1027, 1001, 0, 1); - add(e2d, 814, 1026, 1001, 0, 2); - add(e2d, 814, 1032, 1001, 2, 0); - add(e2d, 814, 1031, 1001, 2, 1); - add(e2d, 814, 1030, 1001, 2, 2); - add(e2d, 814, 1029, 1001, 2, 3); - add(e2d, 814, 1043, 1001, 4, 0); - add(e2d, 814, 1044, 1001, 4, 1); - add(e2d, 814, 1045, 1001, 4, 2); - add(e2d, 814, 1143, 1001, 1, 0); - add(e2d, 814, 1142, 1001, 1, 1); - add(e2d, 814, 1141, 1001, 1, 2); - add(e2d, 814, 1140, 1001, 1, 3); - add(e2d, 814, 1134, 1001, 3, 0); - add(e2d, 814, 1133, 1001, 3, 1); - add(e2d, 814, 1129, 1001, 5, 0); - add(e2d, 814, 1128, 1001, 5, 1); - add(e2d, 814, 403, 1002, 1, 0); - add(e2d, 814, 402, 1002, 1, 1); - add(e2d, 814, 401, 1002, 1, 2); - add(e2d, 814, 408, 1002, 3, 0); - add(e2d, 814, 407, 1002, 3, 1); - add(e2d, 814, 406, 1002, 3, 2); - add(e2d, 814, 405, 1002, 3, 3); - add(e2d, 814, 404, 1002, 3, 4); - add(e2d, 814, 413, 1002, 5, 0); - add(e2d, 814, 412, 1002, 5, 1); - add(e2d, 814, 411, 1002, 5, 2); - add(e2d, 814, 410, 1002, 5, 3); - add(e2d, 814, 409, 1002, 5, 4); - add(e2d, 814, 315, 1002, 7, 0); - add(e2d, 814, 314, 1002, 7, 1); - add(e2d, 814, 313, 1002, 7, 2); - add(e2d, 814, 312, 1002, 7, 3); - add(e2d, 814, 311, 1002, 7, 4); - add(e2d, 814, 320, 1002, 0, 0); - add(e2d, 814, 319, 1002, 0, 1); - add(e2d, 814, 318, 1002, 0, 2); - add(e2d, 814, 317, 1002, 0, 3); - add(e2d, 814, 316, 1002, 0, 4); - add(e2d, 814, 328, 1002, 2, 0); - add(e2d, 814, 329, 1002, 2, 1); - add(e2d, 814, 330, 1002, 2, 2); - add(e2d, 814, 331, 1002, 2, 3); - add(e2d, 814, 332, 1002, 2, 4); - add(e2d, 814, 216, 1002, 4, 0); - add(e2d, 814, 215, 1002, 4, 1); - add(e2d, 814, 214, 1002, 4, 2); - add(e2d, 814, 213, 1002, 4, 3); - add(e2d, 814, 212, 1002, 4, 4); - add(e2d, 814, 208, 1002, 6, 0); - add(e2d, 814, 207, 1002, 6, 1); - add(e2d, 814, 1330, 1003, 0, 0); - add(e2d, 814, 1331, 1003, 0, 1); - add(e2d, 814, 1332, 1003, 0, 2); - add(e2d, 814, 1333, 1003, 0, 3); - add(e2d, 814, 1334, 1003, 0, 4); - add(e2d, 814, 1325, 1003, 2, 0); - add(e2d, 814, 1326, 1003, 2, 1); - add(e2d, 814, 1327, 1003, 2, 2); - add(e2d, 814, 1328, 1003, 2, 3); - add(e2d, 814, 1329, 1003, 2, 4); - add(e2d, 814, 1349, 1003, 4, 0); - add(e2d, 814, 1350, 1003, 4, 1); - add(e2d, 814, 1351, 1003, 4, 2); - add(e2d, 814, 1345, 1003, 6, 0); - add(e2d, 814, 1346, 1003, 6, 1); - add(e2d, 814, 1347, 1003, 6, 2); - add(e2d, 814, 1348, 1003, 6, 3); - add(e2d, 814, 1360, 1003, 1, 0); - add(e2d, 814, 1359, 1003, 1, 1); - add(e2d, 814, 1358, 1003, 1, 2); - add(e2d, 814, 1357, 1003, 1, 3); - add(e2d, 814, 1233, 1003, 3, 0); - add(e2d, 814, 1234, 1003, 3, 1); - add(e2d, 814, 1235, 1003, 3, 2); - add(e2d, 814, 1229, 1003, 5, 0); - add(e2d, 814, 1230, 1003, 5, 1); - add(e2d, 814, 1225, 1003, 7, 0); - add(e2d, 814, 1226, 1003, 7, 1); - add(e2d, 815, 5, 1004, 1, 0); - add(e2d, 815, 4, 1004, 1, 1); - add(e2d, 815, 3, 1004, 1, 2); - add(e2d, 815, 2, 1004, 1, 3); - add(e2d, 815, 1, 1004, 1, 4); - add(e2d, 815, 10, 1004, 3, 0); - add(e2d, 815, 9, 1004, 3, 1); - add(e2d, 815, 8, 1004, 3, 2); - add(e2d, 815, 7, 1004, 3, 3); - add(e2d, 815, 6, 1004, 3, 4); - add(e2d, 815, 22, 1004, 5, 0); - add(e2d, 815, 21, 1004, 5, 1); - add(e2d, 815, 20, 1004, 5, 2); - add(e2d, 815, 19, 1004, 5, 3); - add(e2d, 815, 18, 1004, 5, 4); - add(e2d, 815, 27, 1004, 7, 0); - add(e2d, 815, 26, 1004, 7, 1); - add(e2d, 815, 25, 1004, 7, 2); - add(e2d, 815, 24, 1004, 7, 3); - add(e2d, 815, 23, 1004, 7, 4); - add(e2d, 815, 120, 1004, 0, 0); - add(e2d, 815, 119, 1004, 0, 1); - add(e2d, 815, 118, 1004, 0, 2); - add(e2d, 815, 117, 1004, 0, 3); - add(e2d, 815, 116, 1004, 0, 4); - add(e2d, 815, 112, 1004, 2, 0); - add(e2d, 815, 111, 1004, 2, 1); - add(e2d, 815, 110, 1004, 2, 2); - add(e2d, 815, 109, 1004, 2, 3); - add(e2d, 815, 108, 1004, 2, 4); - add(e2d, 815, 104, 1004, 4, 0); - add(e2d, 815, 103, 1004, 4, 1); - add(e2d, 815, 1039, 1005, 0, 0); - add(e2d, 815, 1040, 1005, 0, 1); - add(e2d, 815, 1041, 1005, 0, 2); - add(e2d, 815, 1035, 1005, 2, 0); - add(e2d, 815, 1036, 1005, 2, 1); - add(e2d, 815, 1037, 1005, 2, 2); - add(e2d, 815, 1038, 1005, 2, 3); - add(e2d, 815, 1056, 1005, 4, 0); - add(e2d, 815, 1057, 1005, 4, 1); - add(e2d, 815, 1058, 1005, 4, 2); - add(e2d, 815, 1052, 1005, 6, 0); - add(e2d, 815, 1053, 1005, 6, 1); - add(e2d, 815, 1054, 1005, 6, 2); - add(e2d, 815, 1055, 1005, 6, 3); - add(e2d, 815, 1137, 1005, 1, 0); - add(e2d, 815, 1138, 1005, 1, 1); - add(e2d, 815, 1139, 1005, 1, 2); - add(e2d, 815, 1129, 1005, 3, 0); - add(e2d, 815, 1130, 1005, 3, 1); - add(e2d, 815, 1131, 1005, 3, 2); - add(e2d, 815, 1125, 1005, 5, 0); - add(e2d, 815, 1126, 1005, 5, 1); - add(e2d, 815, 1127, 1005, 5, 2); - add(e2d, 815, 313, 1008, 1, 0); - add(e2d, 815, 314, 1008, 1, 1); - add(e2d, 815, 315, 1008, 1, 2); - add(e2d, 815, 316, 1008, 1, 3); - add(e2d, 815, 317, 1008, 1, 4); - add(e2d, 815, 308, 1008, 3, 0); - add(e2d, 815, 309, 1008, 3, 1); - add(e2d, 815, 310, 1008, 3, 2); - add(e2d, 815, 311, 1008, 3, 3); - add(e2d, 815, 312, 1008, 3, 4); - add(e2d, 815, 330, 1008, 5, 0); - add(e2d, 815, 331, 1008, 5, 1); - add(e2d, 815, 332, 1008, 5, 2); - add(e2d, 815, 333, 1008, 5, 3); - add(e2d, 815, 334, 1008, 5, 4); - add(e2d, 815, 325, 1008, 7, 0); - add(e2d, 815, 326, 1008, 7, 1); - add(e2d, 815, 327, 1008, 7, 2); - add(e2d, 815, 328, 1008, 7, 3); - add(e2d, 815, 329, 1008, 7, 4); - add(e2d, 815, 215, 1008, 0, 0); - add(e2d, 815, 216, 1008, 0, 1); - add(e2d, 815, 217, 1008, 0, 2); - add(e2d, 815, 218, 1008, 0, 3); - add(e2d, 815, 219, 1008, 0, 4); - add(e2d, 815, 206, 1008, 2, 0); - add(e2d, 815, 207, 1008, 2, 1); - add(e2d, 815, 208, 1008, 2, 2); - add(e2d, 815, 209, 1008, 2, 3); - add(e2d, 815, 210, 1008, 2, 4); - add(e2d, 815, 201, 1008, 4, 0); - add(e2d, 815, 202, 1008, 4, 1); - add(e2d, 815, 203, 1008, 4, 2); - add(e2d, 815, 1327, 1009, 0, 0); - add(e2d, 815, 1326, 1009, 0, 1); - add(e2d, 815, 1325, 1009, 0, 2); - add(e2d, 815, 1331, 1009, 2, 0); - add(e2d, 815, 1330, 1009, 2, 1); - add(e2d, 815, 1329, 1009, 2, 2); - add(e2d, 815, 1328, 1009, 2, 3); - add(e2d, 815, 1344, 1009, 4, 0); - add(e2d, 815, 1343, 1009, 4, 1); - add(e2d, 815, 1342, 1009, 4, 2); - add(e2d, 815, 1348, 1009, 6, 0); - add(e2d, 815, 1347, 1009, 6, 1); - add(e2d, 815, 1346, 1009, 6, 2); - add(e2d, 815, 1345, 1009, 6, 3); - add(e2d, 815, 1247, 1009, 1, 0); - add(e2d, 815, 1246, 1009, 1, 1); - add(e2d, 815, 1245, 1009, 1, 2); - add(e2d, 815, 1244, 1009, 1, 3); - add(e2d, 815, 1238, 1009, 3, 0); - add(e2d, 815, 1237, 1009, 3, 1); - add(e2d, 815, 1236, 1009, 3, 2); - add(e2d, 815, 1235, 1009, 3, 3); - add(e2d, 815, 1229, 1009, 5, 0); - add(e2d, 815, 1228, 1009, 5, 1); - add(e2d, 816, 308, 1010, 1, 0); - add(e2d, 816, 307, 1010, 1, 1); - add(e2d, 816, 306, 1010, 1, 2); - add(e2d, 816, 305, 1010, 1, 3); - add(e2d, 816, 304, 1010, 1, 4); - add(e2d, 816, 316, 1010, 3, 0); - add(e2d, 816, 315, 1010, 3, 1); - add(e2d, 816, 314, 1010, 3, 2); - add(e2d, 816, 313, 1010, 3, 3); - add(e2d, 816, 312, 1010, 3, 4); - add(e2d, 816, 211, 1010, 5, 0); - add(e2d, 816, 212, 1010, 5, 1); - add(e2d, 816, 213, 1010, 5, 2); - add(e2d, 816, 214, 1010, 5, 3); - add(e2d, 816, 215, 1010, 5, 4); - add(e2d, 816, 206, 1010, 0, 0); - add(e2d, 816, 207, 1010, 0, 1); - add(e2d, 816, 208, 1010, 0, 2); - add(e2d, 816, 201, 1010, 2, 0); - add(e2d, 816, 202, 1010, 2, 1); - add(e2d, 816, 203, 1010, 2, 2); - add(e2d, 816, 1325, 1011, 0, 0); - add(e2d, 816, 1326, 1011, 0, 1); - add(e2d, 816, 1327, 1011, 0, 2); - add(e2d, 816, 1333, 1011, 2, 0); - add(e2d, 816, 1334, 1011, 2, 1); - add(e2d, 816, 1335, 1011, 2, 2); - add(e2d, 816, 1243, 1011, 4, 0); - add(e2d, 816, 1242, 1011, 4, 1); - add(e2d, 816, 1241, 1011, 4, 2); - add(e2d, 816, 1240, 1011, 4, 3); - add(e2d, 816, 1234, 1011, 1, 0); - add(e2d, 816, 1233, 1011, 1, 1); - add(e2d, 816, 1229, 1011, 3, 0); - add(e2d, 816, 1228, 1011, 3, 1); - add(e2d, 816, 1, 1012, 1, 0); - add(e2d, 816, 2, 1012, 1, 1); - add(e2d, 816, 3, 1012, 1, 2); - add(e2d, 816, 4, 1012, 1, 3); - add(e2d, 816, 5, 1012, 1, 4); - add(e2d, 816, 10, 1012, 3, 0); - add(e2d, 816, 11, 1012, 3, 1); - add(e2d, 816, 12, 1012, 3, 2); - add(e2d, 816, 13, 1012, 3, 3); - add(e2d, 816, 14, 1012, 3, 4); - add(e2d, 816, 116, 1012, 5, 0); - add(e2d, 816, 115, 1012, 5, 1); - add(e2d, 816, 114, 1012, 5, 2); - add(e2d, 816, 113, 1012, 5, 3); - add(e2d, 816, 112, 1012, 5, 4); - add(e2d, 816, 108, 1012, 0, 0); - add(e2d, 816, 107, 1012, 0, 1); - add(e2d, 816, 104, 1012, 2, 0); - add(e2d, 816, 103, 1012, 2, 1); - add(e2d, 816, 1033, 1013, 0, 0); - add(e2d, 816, 1032, 1013, 0, 1); - add(e2d, 816, 1031, 1013, 0, 2); - add(e2d, 816, 1030, 1013, 0, 3); - add(e2d, 816, 1042, 1013, 2, 0); - add(e2d, 816, 1041, 1013, 2, 1); - add(e2d, 816, 1040, 1013, 2, 2); - add(e2d, 816, 1039, 1013, 2, 3); - add(e2d, 816, 1133, 1013, 4, 0); - add(e2d, 816, 1134, 1013, 4, 1); - add(e2d, 816, 1135, 1013, 4, 2); - add(e2d, 816, 1129, 1013, 1, 0); - add(e2d, 816, 1130, 1013, 1, 1); - add(e2d, 816, 1125, 1013, 3, 0); - add(e2d, 816, 1126, 1013, 3, 1); - add(e2d, 817, 1, 1016, 1, 0); - add(e2d, 817, 2, 1016, 1, 1); - add(e2d, 817, 3, 1016, 1, 2); - add(e2d, 817, 4, 1016, 1, 3); - add(e2d, 817, 5, 1016, 1, 4); - add(e2d, 817, 116, 1016, 3, 0); - add(e2d, 817, 115, 1016, 3, 1); - add(e2d, 817, 114, 1016, 3, 2); - add(e2d, 817, 113, 1016, 3, 3); - add(e2d, 817, 112, 1016, 3, 4); - add(e2d, 817, 108, 1016, 5, 0); - add(e2d, 817, 107, 1016, 5, 1); - add(e2d, 817, 104, 1016, 7, 0); - add(e2d, 817, 103, 1016, 7, 1); - add(e2d, 817, 1033, 1016, 0, 0); - add(e2d, 817, 1032, 1016, 0, 1); - add(e2d, 817, 1031, 1016, 0, 2); - add(e2d, 817, 1030, 1016, 0, 3); - add(e2d, 817, 1133, 1016, 2, 0); - add(e2d, 817, 1134, 1016, 2, 1); - add(e2d, 817, 1135, 1016, 2, 2); - add(e2d, 817, 1129, 1016, 4, 0); - add(e2d, 817, 1130, 1016, 4, 1); - add(e2d, 817, 1125, 1016, 6, 0); - add(e2d, 817, 1126, 1016, 6, 1); - add(e2d, 817, 308, 1017, 1, 0); - add(e2d, 817, 307, 1017, 1, 1); - add(e2d, 817, 306, 1017, 1, 2); - add(e2d, 817, 305, 1017, 1, 3); - add(e2d, 817, 304, 1017, 1, 4); - add(e2d, 817, 211, 1017, 3, 0); - add(e2d, 817, 212, 1017, 3, 1); - add(e2d, 817, 213, 1017, 3, 2); - add(e2d, 817, 214, 1017, 3, 3); - add(e2d, 817, 215, 1017, 3, 4); - add(e2d, 817, 206, 1017, 5, 0); - add(e2d, 817, 207, 1017, 5, 1); - add(e2d, 817, 208, 1017, 5, 2); - add(e2d, 817, 201, 1017, 7, 0); - add(e2d, 817, 202, 1017, 7, 1); - add(e2d, 817, 203, 1017, 7, 2); - add(e2d, 817, 1325, 1017, 0, 0); - add(e2d, 817, 1326, 1017, 0, 1); - add(e2d, 817, 1327, 1017, 0, 2); - add(e2d, 817, 1243, 1017, 2, 0); - add(e2d, 817, 1242, 1017, 2, 1); - add(e2d, 817, 1241, 1017, 2, 2); - add(e2d, 817, 1240, 1017, 2, 3); - add(e2d, 817, 1234, 1017, 4, 0); - add(e2d, 817, 1233, 1017, 4, 1); - add(e2d, 817, 1229, 1017, 6, 0); - add(e2d, 817, 1228, 1017, 6, 1); - add(e2d, 818, 111, 1018, 1, 0); - add(e2d, 818, 112, 1018, 1, 1); - add(e2d, 818, 113, 1018, 1, 2); - add(e2d, 818, 106, 1018, 3, 0); - add(e2d, 818, 107, 1018, 3, 1); - add(e2d, 818, 108, 1018, 3, 2); - add(e2d, 818, 101, 1018, 5, 0); - add(e2d, 818, 102, 1018, 5, 1); - add(e2d, 818, 103, 1018, 5, 2); - add(e2d, 818, 1138, 1018, 0, 0); - add(e2d, 818, 1139, 1018, 0, 1); - add(e2d, 818, 1133, 1018, 2, 0); - add(e2d, 818, 1134, 1018, 2, 1); - add(e2d, 818, 1128, 1018, 4, 0); - add(e2d, 818, 1129, 1018, 4, 1); - add(e2d, 818, 12, 1019, 1, 0); - add(e2d, 818, 11, 1019, 1, 1); - add(e2d, 818, 8, 1019, 3, 0); - add(e2d, 818, 7, 1019, 3, 1); - add(e2d, 818, 4, 1019, 5, 0); - add(e2d, 818, 3, 1019, 5, 1); - add(e2d, 818, 1033, 1019, 0, 0); - add(e2d, 818, 1034, 1019, 0, 1); - add(e2d, 818, 1029, 1019, 2, 0); - add(e2d, 818, 1030, 1019, 2, 1); - add(e2d, 818, 1025, 1019, 4, 0); - add(e2d, 818, 1026, 1019, 4, 1); - add(e2d, 819, 8, 1020, 1, 0); - add(e2d, 819, 7, 1020, 1, 1); - add(e2d, 819, 4, 1020, 3, 0); - add(e2d, 819, 3, 1020, 3, 1); - add(e2d, 819, 1029, 1020, 5, 0); - add(e2d, 819, 1030, 1020, 5, 1); - add(e2d, 819, 1025, 1020, 7, 0); - add(e2d, 819, 1026, 1020, 7, 1); - add(e2d, 819, 106, 1020, 0, 0); - add(e2d, 819, 107, 1020, 0, 1); - add(e2d, 819, 108, 1020, 0, 2); - add(e2d, 819, 101, 1020, 2, 0); - add(e2d, 819, 102, 1020, 2, 1); - add(e2d, 819, 103, 1020, 2, 2); - add(e2d, 819, 1134, 1020, 4, 0); - add(e2d, 819, 1133, 1020, 4, 1); - add(e2d, 819, 1129, 1020, 6, 0); - add(e2d, 819, 1128, 1020, 6, 1); + add(e2d, 807, 8, 728, 0, 0); + add(e2d, 807, 7, 728, 0, 1); + add(e2d, 807, 4, 728, 2, 0); + add(e2d, 807, 3, 728, 2, 1); + add(e2d, 807, 1029, 728, 4, 0); + add(e2d, 807, 1030, 728, 4, 1); + add(e2d, 807, 1025, 728, 6, 0); + add(e2d, 807, 1026, 728, 6, 1); + add(e2d, 807, 106, 728, 1, 0); + add(e2d, 807, 107, 728, 1, 1); + add(e2d, 807, 108, 728, 1, 2); + add(e2d, 807, 101, 728, 3, 0); + add(e2d, 807, 102, 728, 3, 1); + add(e2d, 807, 103, 728, 3, 2); + add(e2d, 807, 1134, 728, 5, 0); + add(e2d, 807, 1133, 728, 5, 1); + add(e2d, 807, 1129, 728, 7, 0); + add(e2d, 807, 1128, 728, 7, 1); + add(e2d, 808, 111, 729, 1, 0); + add(e2d, 808, 112, 729, 1, 1); + add(e2d, 808, 113, 729, 1, 2); + add(e2d, 808, 106, 729, 3, 0); + add(e2d, 808, 107, 729, 3, 1); + add(e2d, 808, 108, 729, 3, 2); + add(e2d, 808, 101, 729, 5, 0); + add(e2d, 808, 102, 729, 5, 1); + add(e2d, 808, 103, 729, 5, 2); + add(e2d, 808, 1139, 729, 0, 0); + add(e2d, 808, 1138, 729, 0, 1); + add(e2d, 808, 1134, 729, 2, 0); + add(e2d, 808, 1133, 729, 2, 1); + add(e2d, 808, 1129, 729, 4, 0); + add(e2d, 808, 1128, 729, 4, 1); + add(e2d, 808, 12, 730, 1, 0); + add(e2d, 808, 11, 730, 1, 1); + add(e2d, 808, 8, 730, 3, 0); + add(e2d, 808, 7, 730, 3, 1); + add(e2d, 808, 4, 730, 5, 0); + add(e2d, 808, 3, 730, 5, 1); + add(e2d, 808, 1033, 730, 0, 0); + add(e2d, 808, 1034, 730, 0, 1); + add(e2d, 808, 1029, 730, 2, 0); + add(e2d, 808, 1030, 730, 2, 1); + add(e2d, 808, 1025, 730, 4, 0); + add(e2d, 808, 1026, 730, 4, 1); + add(e2d, 809, 1, 731, 0, 0); + add(e2d, 809, 2, 731, 0, 1); + add(e2d, 809, 3, 731, 0, 2); + add(e2d, 809, 4, 731, 0, 3); + add(e2d, 809, 5, 731, 0, 4); + add(e2d, 809, 116, 731, 2, 0); + add(e2d, 809, 115, 731, 2, 1); + add(e2d, 809, 114, 731, 2, 2); + add(e2d, 809, 113, 731, 2, 3); + add(e2d, 809, 112, 731, 2, 4); + add(e2d, 809, 108, 731, 4, 0); + add(e2d, 809, 107, 731, 4, 1); + add(e2d, 809, 104, 731, 6, 0); + add(e2d, 809, 103, 731, 6, 1); + add(e2d, 809, 1033, 731, 1, 0); + add(e2d, 809, 1032, 731, 1, 1); + add(e2d, 809, 1031, 731, 1, 2); + add(e2d, 809, 1030, 731, 1, 3); + add(e2d, 809, 1133, 731, 3, 0); + add(e2d, 809, 1134, 731, 3, 1); + add(e2d, 809, 1135, 731, 3, 2); + add(e2d, 809, 1129, 731, 5, 0); + add(e2d, 809, 1130, 731, 5, 1); + add(e2d, 809, 1125, 731, 7, 0); + add(e2d, 809, 1126, 731, 7, 1); + add(e2d, 809, 308, 732, 0, 0); + add(e2d, 809, 307, 732, 0, 1); + add(e2d, 809, 306, 732, 0, 2); + add(e2d, 809, 305, 732, 0, 3); + add(e2d, 809, 304, 732, 0, 4); + add(e2d, 809, 211, 732, 2, 0); + add(e2d, 809, 212, 732, 2, 1); + add(e2d, 809, 213, 732, 2, 2); + add(e2d, 809, 214, 732, 2, 3); + add(e2d, 809, 215, 732, 2, 4); + add(e2d, 809, 206, 732, 4, 0); + add(e2d, 809, 207, 732, 4, 1); + add(e2d, 809, 208, 732, 4, 2); + add(e2d, 809, 201, 732, 6, 0); + add(e2d, 809, 202, 732, 6, 1); + add(e2d, 809, 203, 732, 6, 2); + add(e2d, 809, 1325, 732, 1, 0); + add(e2d, 809, 1326, 732, 1, 1); + add(e2d, 809, 1327, 732, 1, 2); + add(e2d, 809, 1243, 732, 3, 0); + add(e2d, 809, 1242, 732, 3, 1); + add(e2d, 809, 1241, 732, 3, 2); + add(e2d, 809, 1240, 732, 3, 3); + add(e2d, 809, 1234, 732, 5, 0); + add(e2d, 809, 1233, 732, 5, 1); + add(e2d, 809, 1229, 732, 7, 0); + add(e2d, 809, 1228, 732, 7, 1); + add(e2d, 810, 308, 736, 0, 0); + add(e2d, 810, 307, 736, 0, 1); + add(e2d, 810, 306, 736, 0, 2); + add(e2d, 810, 305, 736, 0, 3); + add(e2d, 810, 304, 736, 0, 4); + add(e2d, 810, 316, 736, 2, 0); + add(e2d, 810, 315, 736, 2, 1); + add(e2d, 810, 314, 736, 2, 2); + add(e2d, 810, 313, 736, 2, 3); + add(e2d, 810, 312, 736, 2, 4); + add(e2d, 810, 211, 736, 4, 0); + add(e2d, 810, 212, 736, 4, 1); + add(e2d, 810, 213, 736, 4, 2); + add(e2d, 810, 214, 736, 4, 3); + add(e2d, 810, 215, 736, 4, 4); + add(e2d, 810, 206, 736, 1, 0); + add(e2d, 810, 207, 736, 1, 1); + add(e2d, 810, 208, 736, 1, 2); + add(e2d, 810, 201, 736, 3, 0); + add(e2d, 810, 202, 736, 3, 1); + add(e2d, 810, 203, 736, 3, 2); + add(e2d, 810, 1325, 737, 0, 0); + add(e2d, 810, 1326, 737, 0, 1); + add(e2d, 810, 1327, 737, 0, 2); + add(e2d, 810, 1333, 737, 2, 0); + add(e2d, 810, 1334, 737, 2, 1); + add(e2d, 810, 1335, 737, 2, 2); + add(e2d, 810, 1243, 737, 4, 0); + add(e2d, 810, 1242, 737, 4, 1); + add(e2d, 810, 1241, 737, 4, 2); + add(e2d, 810, 1240, 737, 4, 3); + add(e2d, 810, 1234, 737, 1, 0); + add(e2d, 810, 1233, 737, 1, 1); + add(e2d, 810, 1229, 737, 3, 0); + add(e2d, 810, 1228, 737, 3, 1); + add(e2d, 810, 1, 738, 0, 0); + add(e2d, 810, 2, 738, 0, 1); + add(e2d, 810, 3, 738, 0, 2); + add(e2d, 810, 4, 738, 0, 3); + add(e2d, 810, 5, 738, 0, 4); + add(e2d, 810, 10, 738, 2, 0); + add(e2d, 810, 11, 738, 2, 1); + add(e2d, 810, 12, 738, 2, 2); + add(e2d, 810, 13, 738, 2, 3); + add(e2d, 810, 14, 738, 2, 4); + add(e2d, 810, 116, 738, 4, 0); + add(e2d, 810, 115, 738, 4, 1); + add(e2d, 810, 114, 738, 4, 2); + add(e2d, 810, 113, 738, 4, 3); + add(e2d, 810, 112, 738, 4, 4); + add(e2d, 810, 108, 738, 1, 0); + add(e2d, 810, 107, 738, 1, 1); + add(e2d, 810, 104, 738, 3, 0); + add(e2d, 810, 103, 738, 3, 1); + add(e2d, 810, 1033, 739, 0, 0); + add(e2d, 810, 1032, 739, 0, 1); + add(e2d, 810, 1031, 739, 0, 2); + add(e2d, 810, 1030, 739, 0, 3); + add(e2d, 810, 1042, 739, 2, 0); + add(e2d, 810, 1041, 739, 2, 1); + add(e2d, 810, 1040, 739, 2, 2); + add(e2d, 810, 1039, 739, 2, 3); + add(e2d, 810, 1133, 739, 4, 0); + add(e2d, 810, 1134, 739, 4, 1); + add(e2d, 810, 1135, 739, 4, 2); + add(e2d, 810, 1129, 739, 1, 0); + add(e2d, 810, 1130, 739, 1, 1); + add(e2d, 810, 1125, 739, 3, 0); + add(e2d, 810, 1126, 739, 3, 1); + add(e2d, 811, 5, 740, 0, 0); + add(e2d, 811, 4, 740, 0, 1); + add(e2d, 811, 3, 740, 0, 2); + add(e2d, 811, 2, 740, 0, 3); + add(e2d, 811, 1, 740, 0, 4); + add(e2d, 811, 10, 740, 2, 0); + add(e2d, 811, 9, 740, 2, 1); + add(e2d, 811, 8, 740, 2, 2); + add(e2d, 811, 7, 740, 2, 3); + add(e2d, 811, 6, 740, 2, 4); + add(e2d, 811, 22, 740, 4, 0); + add(e2d, 811, 21, 740, 4, 1); + add(e2d, 811, 20, 740, 4, 2); + add(e2d, 811, 19, 740, 4, 3); + add(e2d, 811, 18, 740, 4, 4); + add(e2d, 811, 27, 740, 6, 0); + add(e2d, 811, 26, 740, 6, 1); + add(e2d, 811, 25, 740, 6, 2); + add(e2d, 811, 24, 740, 6, 3); + add(e2d, 811, 23, 740, 6, 4); + add(e2d, 811, 120, 740, 1, 0); + add(e2d, 811, 119, 740, 1, 1); + add(e2d, 811, 118, 740, 1, 2); + add(e2d, 811, 117, 740, 1, 3); + add(e2d, 811, 116, 740, 1, 4); + add(e2d, 811, 112, 740, 3, 0); + add(e2d, 811, 111, 740, 3, 1); + add(e2d, 811, 110, 740, 3, 2); + add(e2d, 811, 109, 740, 3, 3); + add(e2d, 811, 108, 740, 3, 4); + add(e2d, 811, 104, 740, 5, 0); + add(e2d, 811, 103, 740, 5, 1); + add(e2d, 811, 1039, 741, 0, 0); + add(e2d, 811, 1040, 741, 0, 1); + add(e2d, 811, 1041, 741, 0, 2); + add(e2d, 811, 1035, 741, 2, 0); + add(e2d, 811, 1036, 741, 2, 1); + add(e2d, 811, 1037, 741, 2, 2); + add(e2d, 811, 1038, 741, 2, 3); + add(e2d, 811, 1056, 741, 4, 0); + add(e2d, 811, 1057, 741, 4, 1); + add(e2d, 811, 1058, 741, 4, 2); + add(e2d, 811, 1052, 741, 6, 0); + add(e2d, 811, 1053, 741, 6, 1); + add(e2d, 811, 1054, 741, 6, 2); + add(e2d, 811, 1055, 741, 6, 3); + add(e2d, 811, 1137, 741, 1, 0); + add(e2d, 811, 1138, 741, 1, 1); + add(e2d, 811, 1139, 741, 1, 2); + add(e2d, 811, 1129, 741, 3, 0); + add(e2d, 811, 1130, 741, 3, 1); + add(e2d, 811, 1131, 741, 3, 2); + add(e2d, 811, 1125, 741, 5, 0); + add(e2d, 811, 1126, 741, 5, 1); + add(e2d, 811, 313, 776, 0, 0); + add(e2d, 811, 314, 776, 0, 1); + add(e2d, 811, 315, 776, 0, 2); + add(e2d, 811, 316, 776, 0, 3); + add(e2d, 811, 317, 776, 0, 4); + add(e2d, 811, 308, 776, 2, 0); + add(e2d, 811, 309, 776, 2, 1); + add(e2d, 811, 310, 776, 2, 2); + add(e2d, 811, 311, 776, 2, 3); + add(e2d, 811, 312, 776, 2, 4); + add(e2d, 811, 330, 776, 4, 0); + add(e2d, 811, 331, 776, 4, 1); + add(e2d, 811, 332, 776, 4, 2); + add(e2d, 811, 333, 776, 4, 3); + add(e2d, 811, 334, 776, 4, 4); + add(e2d, 811, 325, 776, 6, 0); + add(e2d, 811, 326, 776, 6, 1); + add(e2d, 811, 327, 776, 6, 2); + add(e2d, 811, 328, 776, 6, 3); + add(e2d, 811, 329, 776, 6, 4); + add(e2d, 811, 215, 776, 1, 0); + add(e2d, 811, 216, 776, 1, 1); + add(e2d, 811, 217, 776, 1, 2); + add(e2d, 811, 218, 776, 1, 3); + add(e2d, 811, 219, 776, 1, 4); + add(e2d, 811, 206, 776, 3, 0); + add(e2d, 811, 207, 776, 3, 1); + add(e2d, 811, 208, 776, 3, 2); + add(e2d, 811, 209, 776, 3, 3); + add(e2d, 811, 210, 776, 3, 4); + add(e2d, 811, 201, 776, 5, 0); + add(e2d, 811, 202, 776, 5, 1); + add(e2d, 811, 203, 776, 5, 2); + add(e2d, 811, 1327, 777, 0, 0); + add(e2d, 811, 1326, 777, 0, 1); + add(e2d, 811, 1325, 777, 0, 2); + add(e2d, 811, 1331, 777, 2, 0); + add(e2d, 811, 1330, 777, 2, 1); + add(e2d, 811, 1329, 777, 2, 2); + add(e2d, 811, 1328, 777, 2, 3); + add(e2d, 811, 1344, 777, 4, 0); + add(e2d, 811, 1343, 777, 4, 1); + add(e2d, 811, 1342, 777, 4, 2); + add(e2d, 811, 1348, 777, 6, 0); + add(e2d, 811, 1347, 777, 6, 1); + add(e2d, 811, 1346, 777, 6, 2); + add(e2d, 811, 1345, 777, 6, 3); + add(e2d, 811, 1247, 777, 1, 0); + add(e2d, 811, 1246, 777, 1, 1); + add(e2d, 811, 1245, 777, 1, 2); + add(e2d, 811, 1244, 777, 1, 3); + add(e2d, 811, 1238, 777, 3, 0); + add(e2d, 811, 1237, 777, 3, 1); + add(e2d, 811, 1236, 777, 3, 2); + add(e2d, 811, 1235, 777, 3, 3); + add(e2d, 811, 1229, 777, 5, 0); + add(e2d, 811, 1228, 777, 5, 1); + add(e2d, 812, 403, 778, 0, 0); + add(e2d, 812, 402, 778, 0, 1); + add(e2d, 812, 401, 778, 0, 2); + add(e2d, 812, 408, 778, 2, 0); + add(e2d, 812, 407, 778, 2, 1); + add(e2d, 812, 406, 778, 2, 2); + add(e2d, 812, 405, 778, 2, 3); + add(e2d, 812, 404, 778, 2, 4); + add(e2d, 812, 413, 778, 4, 0); + add(e2d, 812, 412, 778, 4, 1); + add(e2d, 812, 411, 778, 4, 2); + add(e2d, 812, 410, 778, 4, 3); + add(e2d, 812, 409, 778, 4, 4); + add(e2d, 812, 315, 778, 6, 0); + add(e2d, 812, 314, 778, 6, 1); + add(e2d, 812, 313, 778, 6, 2); + add(e2d, 812, 312, 778, 6, 3); + add(e2d, 812, 311, 778, 6, 4); + add(e2d, 812, 320, 778, 1, 0); + add(e2d, 812, 319, 778, 1, 1); + add(e2d, 812, 318, 778, 1, 2); + add(e2d, 812, 317, 778, 1, 3); + add(e2d, 812, 316, 778, 1, 4); + add(e2d, 812, 328, 778, 3, 0); + add(e2d, 812, 329, 778, 3, 1); + add(e2d, 812, 330, 778, 3, 2); + add(e2d, 812, 331, 778, 3, 3); + add(e2d, 812, 332, 778, 3, 4); + add(e2d, 812, 216, 778, 5, 0); + add(e2d, 812, 215, 778, 5, 1); + add(e2d, 812, 214, 778, 5, 2); + add(e2d, 812, 213, 778, 5, 3); + add(e2d, 812, 212, 778, 5, 4); + add(e2d, 812, 208, 778, 7, 0); + add(e2d, 812, 207, 778, 7, 1); + add(e2d, 812, 1330, 779, 0, 0); + add(e2d, 812, 1331, 779, 0, 1); + add(e2d, 812, 1332, 779, 0, 2); + add(e2d, 812, 1333, 779, 0, 3); + add(e2d, 812, 1334, 779, 0, 4); + add(e2d, 812, 1325, 779, 2, 0); + add(e2d, 812, 1326, 779, 2, 1); + add(e2d, 812, 1327, 779, 2, 2); + add(e2d, 812, 1328, 779, 2, 3); + add(e2d, 812, 1329, 779, 2, 4); + add(e2d, 812, 1349, 779, 4, 0); + add(e2d, 812, 1350, 779, 4, 1); + add(e2d, 812, 1351, 779, 4, 2); + add(e2d, 812, 1345, 779, 6, 0); + add(e2d, 812, 1346, 779, 6, 1); + add(e2d, 812, 1347, 779, 6, 2); + add(e2d, 812, 1348, 779, 6, 3); + add(e2d, 812, 1360, 779, 1, 0); + add(e2d, 812, 1359, 779, 1, 1); + add(e2d, 812, 1358, 779, 1, 2); + add(e2d, 812, 1357, 779, 1, 3); + add(e2d, 812, 1233, 779, 3, 0); + add(e2d, 812, 1234, 779, 3, 1); + add(e2d, 812, 1235, 779, 3, 2); + add(e2d, 812, 1229, 779, 5, 0); + add(e2d, 812, 1230, 779, 5, 1); + add(e2d, 812, 1225, 779, 7, 0); + add(e2d, 812, 1226, 779, 7, 1); + add(e2d, 812, 204, 780, 0, 0); + add(e2d, 812, 203, 780, 0, 1); + add(e2d, 812, 1, 780, 2, 0); + add(e2d, 812, 0, 780, 2, 1); + add(e2d, 812, 14, 780, 4, 0); + add(e2d, 812, 15, 780, 4, 1); + add(e2d, 812, 16, 780, 4, 2); + add(e2d, 812, 17, 780, 4, 3); + add(e2d, 812, 18, 780, 4, 4); + add(e2d, 812, 9, 780, 6, 0); + add(e2d, 812, 10, 780, 6, 1); + add(e2d, 812, 11, 780, 6, 2); + add(e2d, 812, 12, 780, 6, 3); + add(e2d, 812, 13, 780, 6, 4); + add(e2d, 812, 26, 780, 1, 0); + add(e2d, 812, 25, 780, 1, 1); + add(e2d, 812, 24, 780, 1, 2); + add(e2d, 812, 23, 780, 1, 3); + add(e2d, 812, 22, 780, 1, 4); + add(e2d, 812, 111, 780, 3, 0); + add(e2d, 812, 112, 780, 3, 1); + add(e2d, 812, 113, 780, 3, 2); + add(e2d, 812, 114, 780, 3, 3); + add(e2d, 812, 115, 780, 3, 4); + add(e2d, 812, 106, 780, 5, 0); + add(e2d, 812, 107, 780, 5, 1); + add(e2d, 812, 108, 780, 5, 2); + add(e2d, 812, 101, 780, 7, 0); + add(e2d, 812, 102, 780, 7, 1); + add(e2d, 812, 103, 780, 7, 2); + add(e2d, 812, 1028, 781, 0, 0); + add(e2d, 812, 1027, 781, 0, 1); + add(e2d, 812, 1026, 781, 0, 2); + add(e2d, 812, 1032, 781, 2, 0); + add(e2d, 812, 1031, 781, 2, 1); + add(e2d, 812, 1030, 781, 2, 2); + add(e2d, 812, 1029, 781, 2, 3); + add(e2d, 812, 1043, 781, 4, 0); + add(e2d, 812, 1044, 781, 4, 1); + add(e2d, 812, 1045, 781, 4, 2); + add(e2d, 812, 1143, 781, 1, 0); + add(e2d, 812, 1142, 781, 1, 1); + add(e2d, 812, 1141, 781, 1, 2); + add(e2d, 812, 1140, 781, 1, 3); + add(e2d, 812, 1134, 781, 3, 0); + add(e2d, 812, 1133, 781, 3, 1); + add(e2d, 812, 1129, 781, 5, 0); + add(e2d, 812, 1128, 781, 5, 1); + add(e2d, 813, 5, 864, 0, 0); + add(e2d, 813, 4, 864, 0, 1); + add(e2d, 813, 3, 864, 0, 2); + add(e2d, 813, 2, 864, 0, 3); + add(e2d, 813, 1, 864, 0, 4); + add(e2d, 813, 10, 864, 2, 0); + add(e2d, 813, 9, 864, 2, 1); + add(e2d, 813, 8, 864, 2, 2); + add(e2d, 813, 7, 864, 2, 3); + add(e2d, 813, 6, 864, 2, 4); + add(e2d, 813, 18, 864, 4, 0); + add(e2d, 813, 19, 864, 4, 1); + add(e2d, 813, 20, 864, 4, 2); + add(e2d, 813, 21, 864, 4, 3); + add(e2d, 813, 22, 864, 4, 4); + add(e2d, 813, 116, 864, 1, 0); + add(e2d, 813, 115, 864, 1, 1); + add(e2d, 813, 114, 864, 1, 2); + add(e2d, 813, 113, 864, 1, 3); + add(e2d, 813, 112, 864, 1, 4); + add(e2d, 813, 108, 864, 3, 0); + add(e2d, 813, 107, 864, 3, 1); + add(e2d, 813, 104, 864, 5, 0); + add(e2d, 813, 103, 864, 5, 1); + add(e2d, 813, 1039, 865, 0, 0); + add(e2d, 813, 1040, 865, 0, 1); + add(e2d, 813, 1041, 865, 0, 2); + add(e2d, 813, 1035, 865, 2, 0); + add(e2d, 813, 1036, 865, 2, 1); + add(e2d, 813, 1037, 865, 2, 2); + add(e2d, 813, 1038, 865, 2, 3); + add(e2d, 813, 1050, 865, 4, 0); + add(e2d, 813, 1049, 865, 4, 1); + add(e2d, 813, 1048, 865, 4, 2); + add(e2d, 813, 1047, 865, 4, 3); + add(e2d, 813, 1133, 865, 1, 0); + add(e2d, 813, 1134, 865, 1, 1); + add(e2d, 813, 1135, 865, 1, 2); + add(e2d, 813, 1129, 865, 3, 0); + add(e2d, 813, 1130, 865, 3, 1); + add(e2d, 813, 1125, 865, 5, 0); + add(e2d, 813, 1126, 865, 5, 1); + add(e2d, 813, 313, 866, 0, 0); + add(e2d, 813, 314, 866, 0, 1); + add(e2d, 813, 315, 866, 0, 2); + add(e2d, 813, 316, 866, 0, 3); + add(e2d, 813, 317, 866, 0, 4); + add(e2d, 813, 308, 866, 2, 0); + add(e2d, 813, 309, 866, 2, 1); + add(e2d, 813, 310, 866, 2, 2); + add(e2d, 813, 311, 866, 2, 3); + add(e2d, 813, 312, 866, 2, 4); + add(e2d, 813, 325, 866, 4, 0); + add(e2d, 813, 324, 866, 4, 1); + add(e2d, 813, 323, 866, 4, 2); + add(e2d, 813, 322, 866, 4, 3); + add(e2d, 813, 321, 866, 4, 4); + add(e2d, 813, 211, 866, 1, 0); + add(e2d, 813, 212, 866, 1, 1); + add(e2d, 813, 213, 866, 1, 2); + add(e2d, 813, 214, 866, 1, 3); + add(e2d, 813, 215, 866, 1, 4); + add(e2d, 813, 206, 866, 3, 0); + add(e2d, 813, 207, 866, 3, 1); + add(e2d, 813, 208, 866, 3, 2); + add(e2d, 813, 201, 866, 5, 0); + add(e2d, 813, 202, 866, 5, 1); + add(e2d, 813, 203, 866, 5, 2); + add(e2d, 813, 1327, 867, 0, 0); + add(e2d, 813, 1326, 867, 0, 1); + add(e2d, 813, 1325, 867, 0, 2); + add(e2d, 813, 1331, 867, 2, 0); + add(e2d, 813, 1330, 867, 2, 1); + add(e2d, 813, 1329, 867, 2, 2); + add(e2d, 813, 1328, 867, 2, 3); + add(e2d, 813, 1342, 867, 4, 0); + add(e2d, 813, 1343, 867, 4, 1); + add(e2d, 813, 1344, 867, 4, 2); + add(e2d, 813, 1243, 867, 1, 0); + add(e2d, 813, 1242, 867, 1, 1); + add(e2d, 813, 1241, 867, 1, 2); + add(e2d, 813, 1240, 867, 1, 3); + add(e2d, 813, 1234, 867, 3, 0); + add(e2d, 813, 1233, 867, 3, 1); + add(e2d, 813, 1229, 867, 5, 0); + add(e2d, 813, 1228, 867, 5, 1); + add(e2d, 814, 1, 352, 2, 0); + add(e2d, 814, 0, 352, 2, 1); + add(e2d, 814, 204, 352, 0, 0); + add(e2d, 814, 203, 352, 0, 1); + add(e2d, 814, 14, 352, 4, 0); + add(e2d, 814, 15, 352, 4, 1); + add(e2d, 814, 16, 352, 4, 2); + add(e2d, 814, 17, 352, 4, 3); + add(e2d, 814, 18, 352, 4, 4); + add(e2d, 814, 9, 352, 6, 0); + add(e2d, 814, 10, 352, 6, 1); + add(e2d, 814, 11, 352, 6, 2); + add(e2d, 814, 12, 352, 6, 3); + add(e2d, 814, 13, 352, 6, 4); + add(e2d, 814, 26, 352, 1, 0); + add(e2d, 814, 25, 352, 1, 1); + add(e2d, 814, 24, 352, 1, 2); + add(e2d, 814, 23, 352, 1, 3); + add(e2d, 814, 22, 352, 1, 4); + add(e2d, 814, 111, 352, 3, 0); + add(e2d, 814, 112, 352, 3, 1); + add(e2d, 814, 113, 352, 3, 2); + add(e2d, 814, 114, 352, 3, 3); + add(e2d, 814, 115, 352, 3, 4); + add(e2d, 814, 106, 352, 5, 0); + add(e2d, 814, 107, 352, 5, 1); + add(e2d, 814, 108, 352, 5, 2); + add(e2d, 814, 101, 352, 7, 0); + add(e2d, 814, 102, 352, 7, 1); + add(e2d, 814, 103, 352, 7, 2); + add(e2d, 814, 1028, 353, 0, 0); + add(e2d, 814, 1027, 353, 0, 1); + add(e2d, 814, 1026, 353, 0, 2); + add(e2d, 814, 1032, 353, 2, 0); + add(e2d, 814, 1031, 353, 2, 1); + add(e2d, 814, 1030, 353, 2, 2); + add(e2d, 814, 1029, 353, 2, 3); + add(e2d, 814, 1043, 353, 4, 0); + add(e2d, 814, 1044, 353, 4, 1); + add(e2d, 814, 1045, 353, 4, 2); + add(e2d, 814, 1143, 353, 1, 0); + add(e2d, 814, 1142, 353, 1, 1); + add(e2d, 814, 1141, 353, 1, 2); + add(e2d, 814, 1140, 353, 1, 3); + add(e2d, 814, 1134, 353, 3, 0); + add(e2d, 814, 1133, 353, 3, 1); + add(e2d, 814, 1129, 353, 5, 0); + add(e2d, 814, 1128, 353, 5, 1); + add(e2d, 814, 403, 354, 0, 0); + add(e2d, 814, 402, 354, 0, 1); + add(e2d, 814, 401, 354, 0, 2); + add(e2d, 814, 408, 354, 2, 0); + add(e2d, 814, 407, 354, 2, 1); + add(e2d, 814, 406, 354, 2, 2); + add(e2d, 814, 405, 354, 2, 3); + add(e2d, 814, 404, 354, 2, 4); + add(e2d, 814, 413, 354, 4, 0); + add(e2d, 814, 412, 354, 4, 1); + add(e2d, 814, 411, 354, 4, 2); + add(e2d, 814, 410, 354, 4, 3); + add(e2d, 814, 409, 354, 4, 4); + add(e2d, 814, 315, 354, 6, 0); + add(e2d, 814, 314, 354, 6, 1); + add(e2d, 814, 313, 354, 6, 2); + add(e2d, 814, 312, 354, 6, 3); + add(e2d, 814, 311, 354, 6, 4); + add(e2d, 814, 320, 354, 1, 0); + add(e2d, 814, 319, 354, 1, 1); + add(e2d, 814, 318, 354, 1, 2); + add(e2d, 814, 317, 354, 1, 3); + add(e2d, 814, 316, 354, 1, 4); + add(e2d, 814, 328, 354, 3, 0); + add(e2d, 814, 329, 354, 3, 1); + add(e2d, 814, 330, 354, 3, 2); + add(e2d, 814, 331, 354, 3, 3); + add(e2d, 814, 332, 354, 3, 4); + add(e2d, 814, 216, 354, 5, 0); + add(e2d, 814, 215, 354, 5, 1); + add(e2d, 814, 214, 354, 5, 2); + add(e2d, 814, 213, 354, 5, 3); + add(e2d, 814, 212, 354, 5, 4); + add(e2d, 814, 208, 354, 7, 0); + add(e2d, 814, 207, 354, 7, 1); + add(e2d, 814, 1330, 355, 0, 0); + add(e2d, 814, 1331, 355, 0, 1); + add(e2d, 814, 1332, 355, 0, 2); + add(e2d, 814, 1333, 355, 0, 3); + add(e2d, 814, 1334, 355, 0, 4); + add(e2d, 814, 1325, 355, 2, 0); + add(e2d, 814, 1326, 355, 2, 1); + add(e2d, 814, 1327, 355, 2, 2); + add(e2d, 814, 1328, 355, 2, 3); + add(e2d, 814, 1329, 355, 2, 4); + add(e2d, 814, 1349, 355, 4, 0); + add(e2d, 814, 1350, 355, 4, 1); + add(e2d, 814, 1351, 355, 4, 2); + add(e2d, 814, 1345, 355, 6, 0); + add(e2d, 814, 1346, 355, 6, 1); + add(e2d, 814, 1347, 355, 6, 2); + add(e2d, 814, 1348, 355, 6, 3); + add(e2d, 814, 1360, 355, 1, 0); + add(e2d, 814, 1359, 355, 1, 1); + add(e2d, 814, 1358, 355, 1, 2); + add(e2d, 814, 1357, 355, 1, 3); + add(e2d, 814, 1233, 355, 3, 0); + add(e2d, 814, 1234, 355, 3, 1); + add(e2d, 814, 1235, 355, 3, 2); + add(e2d, 814, 1229, 355, 5, 0); + add(e2d, 814, 1230, 355, 5, 1); + add(e2d, 814, 1225, 355, 7, 0); + add(e2d, 814, 1226, 355, 7, 1); + add(e2d, 815, 5, 356, 0, 0); + add(e2d, 815, 4, 356, 0, 1); + add(e2d, 815, 3, 356, 0, 2); + add(e2d, 815, 2, 356, 0, 3); + add(e2d, 815, 1, 356, 0, 4); + add(e2d, 815, 10, 356, 2, 0); + add(e2d, 815, 9, 356, 2, 1); + add(e2d, 815, 8, 356, 2, 2); + add(e2d, 815, 7, 356, 2, 3); + add(e2d, 815, 6, 356, 2, 4); + add(e2d, 815, 22, 356, 4, 0); + add(e2d, 815, 21, 356, 4, 1); + add(e2d, 815, 20, 356, 4, 2); + add(e2d, 815, 19, 356, 4, 3); + add(e2d, 815, 18, 356, 4, 4); + add(e2d, 815, 27, 356, 6, 0); + add(e2d, 815, 26, 356, 6, 1); + add(e2d, 815, 25, 356, 6, 2); + add(e2d, 815, 24, 356, 6, 3); + add(e2d, 815, 23, 356, 6, 4); + add(e2d, 815, 120, 356, 1, 0); + add(e2d, 815, 119, 356, 1, 1); + add(e2d, 815, 118, 356, 1, 2); + add(e2d, 815, 117, 356, 1, 3); + add(e2d, 815, 116, 356, 1, 4); + add(e2d, 815, 112, 356, 3, 0); + add(e2d, 815, 111, 356, 3, 1); + add(e2d, 815, 110, 356, 3, 2); + add(e2d, 815, 109, 356, 3, 3); + add(e2d, 815, 108, 356, 3, 4); + add(e2d, 815, 104, 356, 5, 0); + add(e2d, 815, 103, 356, 5, 1); + add(e2d, 815, 1039, 357, 0, 0); + add(e2d, 815, 1040, 357, 0, 1); + add(e2d, 815, 1041, 357, 0, 2); + add(e2d, 815, 1035, 357, 2, 0); + add(e2d, 815, 1036, 357, 2, 1); + add(e2d, 815, 1037, 357, 2, 2); + add(e2d, 815, 1038, 357, 2, 3); + add(e2d, 815, 1056, 357, 4, 0); + add(e2d, 815, 1057, 357, 4, 1); + add(e2d, 815, 1058, 357, 4, 2); + add(e2d, 815, 1052, 357, 6, 0); + add(e2d, 815, 1053, 357, 6, 1); + add(e2d, 815, 1054, 357, 6, 2); + add(e2d, 815, 1055, 357, 6, 3); + add(e2d, 815, 1137, 357, 1, 0); + add(e2d, 815, 1138, 357, 1, 1); + add(e2d, 815, 1139, 357, 1, 2); + add(e2d, 815, 1129, 357, 3, 0); + add(e2d, 815, 1130, 357, 3, 1); + add(e2d, 815, 1131, 357, 3, 2); + add(e2d, 815, 1125, 357, 5, 0); + add(e2d, 815, 1126, 357, 5, 1); + add(e2d, 815, 313, 304, 0, 0); + add(e2d, 815, 314, 304, 0, 1); + add(e2d, 815, 315, 304, 0, 2); + add(e2d, 815, 316, 304, 0, 3); + add(e2d, 815, 317, 304, 0, 4); + add(e2d, 815, 308, 304, 2, 0); + add(e2d, 815, 309, 304, 2, 1); + add(e2d, 815, 310, 304, 2, 2); + add(e2d, 815, 311, 304, 2, 3); + add(e2d, 815, 312, 304, 2, 4); + add(e2d, 815, 330, 304, 4, 0); + add(e2d, 815, 331, 304, 4, 1); + add(e2d, 815, 332, 304, 4, 2); + add(e2d, 815, 333, 304, 4, 3); + add(e2d, 815, 334, 304, 4, 4); + add(e2d, 815, 325, 304, 6, 0); + add(e2d, 815, 326, 304, 6, 1); + add(e2d, 815, 327, 304, 6, 2); + add(e2d, 815, 328, 304, 6, 3); + add(e2d, 815, 329, 304, 6, 4); + add(e2d, 815, 215, 304, 1, 0); + add(e2d, 815, 216, 304, 1, 1); + add(e2d, 815, 217, 304, 1, 2); + add(e2d, 815, 218, 304, 1, 3); + add(e2d, 815, 219, 304, 1, 4); + add(e2d, 815, 206, 304, 3, 0); + add(e2d, 815, 207, 304, 3, 1); + add(e2d, 815, 208, 304, 3, 2); + add(e2d, 815, 209, 304, 3, 3); + add(e2d, 815, 210, 304, 3, 4); + add(e2d, 815, 201, 304, 5, 0); + add(e2d, 815, 202, 304, 5, 1); + add(e2d, 815, 203, 304, 5, 2); + add(e2d, 815, 1327, 305, 0, 0); + add(e2d, 815, 1326, 305, 0, 1); + add(e2d, 815, 1325, 305, 0, 2); + add(e2d, 815, 1331, 305, 2, 0); + add(e2d, 815, 1330, 305, 2, 1); + add(e2d, 815, 1329, 305, 2, 2); + add(e2d, 815, 1328, 305, 2, 3); + add(e2d, 815, 1344, 305, 4, 0); + add(e2d, 815, 1343, 305, 4, 1); + add(e2d, 815, 1342, 305, 4, 2); + add(e2d, 815, 1348, 305, 6, 0); + add(e2d, 815, 1347, 305, 6, 1); + add(e2d, 815, 1346, 305, 6, 2); + add(e2d, 815, 1345, 305, 6, 3); + add(e2d, 815, 1247, 305, 1, 0); + add(e2d, 815, 1246, 305, 1, 1); + add(e2d, 815, 1245, 305, 1, 2); + add(e2d, 815, 1244, 305, 1, 3); + add(e2d, 815, 1238, 305, 3, 0); + add(e2d, 815, 1237, 305, 3, 1); + add(e2d, 815, 1236, 305, 3, 2); + add(e2d, 815, 1235, 305, 3, 3); + add(e2d, 815, 1229, 305, 5, 0); + add(e2d, 815, 1228, 305, 5, 1); + add(e2d, 816, 308, 306, 0, 0); + add(e2d, 816, 307, 306, 0, 1); + add(e2d, 816, 306, 306, 0, 2); + add(e2d, 816, 305, 306, 0, 3); + add(e2d, 816, 304, 306, 0, 4); + add(e2d, 816, 316, 306, 2, 0); + add(e2d, 816, 315, 306, 2, 1); + add(e2d, 816, 314, 306, 2, 2); + add(e2d, 816, 313, 306, 2, 3); + add(e2d, 816, 312, 306, 2, 4); + add(e2d, 816, 211, 306, 4, 0); + add(e2d, 816, 212, 306, 4, 1); + add(e2d, 816, 213, 306, 4, 2); + add(e2d, 816, 214, 306, 4, 3); + add(e2d, 816, 215, 306, 4, 4); + add(e2d, 816, 206, 306, 1, 0); + add(e2d, 816, 207, 306, 1, 1); + add(e2d, 816, 208, 306, 1, 2); + add(e2d, 816, 201, 306, 3, 0); + add(e2d, 816, 202, 306, 3, 1); + add(e2d, 816, 203, 306, 3, 2); + add(e2d, 816, 1325, 307, 0, 0); + add(e2d, 816, 1326, 307, 0, 1); + add(e2d, 816, 1327, 307, 0, 2); + add(e2d, 816, 1333, 307, 2, 0); + add(e2d, 816, 1334, 307, 2, 1); + add(e2d, 816, 1335, 307, 2, 2); + add(e2d, 816, 1243, 307, 4, 0); + add(e2d, 816, 1242, 307, 4, 1); + add(e2d, 816, 1241, 307, 4, 2); + add(e2d, 816, 1240, 307, 4, 3); + add(e2d, 816, 1234, 307, 1, 0); + add(e2d, 816, 1233, 307, 1, 1); + add(e2d, 816, 1229, 307, 3, 0); + add(e2d, 816, 1228, 307, 3, 1); + add(e2d, 816, 1, 308, 0, 0); + add(e2d, 816, 2, 308, 0, 1); + add(e2d, 816, 3, 308, 0, 2); + add(e2d, 816, 4, 308, 0, 3); + add(e2d, 816, 5, 308, 0, 4); + add(e2d, 816, 10, 308, 2, 0); + add(e2d, 816, 11, 308, 2, 1); + add(e2d, 816, 12, 308, 2, 2); + add(e2d, 816, 13, 308, 2, 3); + add(e2d, 816, 14, 308, 2, 4); + add(e2d, 816, 116, 308, 4, 0); + add(e2d, 816, 115, 308, 4, 1); + add(e2d, 816, 114, 308, 4, 2); + add(e2d, 816, 113, 308, 4, 3); + add(e2d, 816, 112, 308, 4, 4); + add(e2d, 816, 108, 308, 1, 0); + add(e2d, 816, 107, 308, 1, 1); + add(e2d, 816, 104, 308, 3, 0); + add(e2d, 816, 103, 308, 3, 1); + add(e2d, 816, 1033, 309, 0, 0); + add(e2d, 816, 1032, 309, 0, 1); + add(e2d, 816, 1031, 309, 0, 2); + add(e2d, 816, 1030, 309, 0, 3); + add(e2d, 816, 1042, 309, 2, 0); + add(e2d, 816, 1041, 309, 2, 1); + add(e2d, 816, 1040, 309, 2, 2); + add(e2d, 816, 1039, 309, 2, 3); + add(e2d, 816, 1133, 309, 4, 0); + add(e2d, 816, 1134, 309, 4, 1); + add(e2d, 816, 1135, 309, 4, 2); + add(e2d, 816, 1129, 309, 1, 0); + add(e2d, 816, 1130, 309, 1, 1); + add(e2d, 816, 1125, 309, 3, 0); + add(e2d, 816, 1126, 309, 3, 1); + add(e2d, 817, 1, 856, 0, 0); + add(e2d, 817, 2, 856, 0, 1); + add(e2d, 817, 3, 856, 0, 2); + add(e2d, 817, 4, 856, 0, 3); + add(e2d, 817, 5, 856, 0, 4); + add(e2d, 817, 116, 856, 2, 0); + add(e2d, 817, 115, 856, 2, 1); + add(e2d, 817, 114, 856, 2, 2); + add(e2d, 817, 113, 856, 2, 3); + add(e2d, 817, 112, 856, 2, 4); + add(e2d, 817, 108, 856, 4, 0); + add(e2d, 817, 107, 856, 4, 1); + add(e2d, 817, 104, 856, 6, 0); + add(e2d, 817, 103, 856, 6, 1); + add(e2d, 817, 1033, 856, 1, 0); + add(e2d, 817, 1032, 856, 1, 1); + add(e2d, 817, 1031, 856, 1, 2); + add(e2d, 817, 1030, 856, 1, 3); + add(e2d, 817, 1133, 856, 3, 0); + add(e2d, 817, 1134, 856, 3, 1); + add(e2d, 817, 1135, 856, 3, 2); + add(e2d, 817, 1129, 856, 5, 0); + add(e2d, 817, 1130, 856, 5, 1); + add(e2d, 817, 1125, 856, 7, 0); + add(e2d, 817, 1126, 856, 7, 1); + add(e2d, 817, 308, 857, 0, 0); + add(e2d, 817, 307, 857, 0, 1); + add(e2d, 817, 306, 857, 0, 2); + add(e2d, 817, 305, 857, 0, 3); + add(e2d, 817, 304, 857, 0, 4); + add(e2d, 817, 211, 857, 2, 0); + add(e2d, 817, 212, 857, 2, 1); + add(e2d, 817, 213, 857, 2, 2); + add(e2d, 817, 214, 857, 2, 3); + add(e2d, 817, 215, 857, 2, 4); + add(e2d, 817, 206, 857, 4, 0); + add(e2d, 817, 207, 857, 4, 1); + add(e2d, 817, 208, 857, 4, 2); + add(e2d, 817, 201, 857, 6, 0); + add(e2d, 817, 202, 857, 6, 1); + add(e2d, 817, 203, 857, 6, 2); + add(e2d, 817, 1325, 857, 1, 0); + add(e2d, 817, 1326, 857, 1, 1); + add(e2d, 817, 1327, 857, 1, 2); + add(e2d, 817, 1243, 857, 3, 0); + add(e2d, 817, 1242, 857, 3, 1); + add(e2d, 817, 1241, 857, 3, 2); + add(e2d, 817, 1240, 857, 3, 3); + add(e2d, 817, 1234, 857, 5, 0); + add(e2d, 817, 1233, 857, 5, 1); + add(e2d, 817, 1229, 857, 7, 0); + add(e2d, 817, 1228, 857, 7, 1); + add(e2d, 818, 111, 858, 0, 0); + add(e2d, 818, 112, 858, 0, 1); + add(e2d, 818, 113, 858, 0, 2); + add(e2d, 818, 106, 858, 2, 0); + add(e2d, 818, 107, 858, 2, 1); + add(e2d, 818, 108, 858, 2, 2); + add(e2d, 818, 101, 858, 4, 0); + add(e2d, 818, 102, 858, 4, 1); + add(e2d, 818, 103, 858, 4, 2); + add(e2d, 818, 1139, 858, 1, 0); + add(e2d, 818, 1138, 858, 1, 1); + add(e2d, 818, 1134, 858, 3, 0); + add(e2d, 818, 1133, 858, 3, 1); + add(e2d, 818, 1129, 858, 5, 0); + add(e2d, 818, 1128, 858, 5, 1); + add(e2d, 818, 12, 859, 0, 0); + add(e2d, 818, 11, 859, 0, 1); + add(e2d, 818, 8, 859, 2, 0); + add(e2d, 818, 7, 859, 2, 1); + add(e2d, 818, 4, 859, 4, 0); + add(e2d, 818, 3, 859, 4, 1); + add(e2d, 818, 1033, 859, 1, 0); + add(e2d, 818, 1034, 859, 1, 1); + add(e2d, 818, 1029, 859, 3, 0); + add(e2d, 818, 1030, 859, 3, 1); + add(e2d, 818, 1025, 859, 5, 0); + add(e2d, 818, 1026, 859, 5, 1); + add(e2d, 819, 8, 860, 0, 0); + add(e2d, 819, 7, 860, 0, 1); + add(e2d, 819, 4, 860, 2, 0); + add(e2d, 819, 3, 860, 2, 1); + add(e2d, 819, 1029, 860, 4, 0); + add(e2d, 819, 1030, 860, 4, 1); + add(e2d, 819, 1025, 860, 6, 0); + add(e2d, 819, 1026, 860, 6, 1); + add(e2d, 819, 106, 860, 1, 0); + add(e2d, 819, 107, 860, 1, 1); + add(e2d, 819, 108, 860, 1, 2); + add(e2d, 819, 101, 860, 3, 0); + add(e2d, 819, 102, 860, 3, 1); + add(e2d, 819, 103, 860, 3, 2); + add(e2d, 819, 1134, 860, 5, 0); + add(e2d, 819, 1133, 860, 5, 1); + add(e2d, 819, 1129, 860, 7, 0); + add(e2d, 819, 1128, 860, 7, 1); } void fillSolar2FeeLinkCH8L(std::map<uint16_t, uint32_t>& s2f) { - add_cru(s2f, 37, 4, 968); - add_cru(s2f, 37, 5, 969); - add_cru(s2f, 37, 6, 970); - add_cru(s2f, 37, 7, 971); - add_cru(s2f, 37, 8, 972); - add_cru(s2f, 37, 9, 976); - add_cru(s2f, 37, 10, 977); - add_cru(s2f, 37, 11, 978); - add_cru(s2f, 39, 0, 979); - add_cru(s2f, 39, 1, 980); - add_cru(s2f, 38, 2, 981); - add_cru(s2f, 38, 3, 984); - add_cru(s2f, 38, 4, 985); - add_cru(s2f, 38, 5, 986); - add_cru(s2f, 38, 6, 987); - add_cru(s2f, 38, 7, 988); - add_cru(s2f, 38, 8, 989); - add_cru(s2f, 38, 9, 992); - add_cru(s2f, 38, 10, 993); - add_cru(s2f, 38, 11, 994); - add_cru(s2f, 40, 0, 995); - add_cru(s2f, 40, 1, 1000); - add_cru(s2f, 41, 2, 1001); - add_cru(s2f, 41, 3, 1002); - add_cru(s2f, 41, 4, 1003); - add_cru(s2f, 41, 5, 1004); - add_cru(s2f, 41, 6, 1005); - add_cru(s2f, 41, 7, 1008); - add_cru(s2f, 41, 8, 1009); - add_cru(s2f, 41, 9, 1010); - add_cru(s2f, 41, 10, 1011); - add_cru(s2f, 41, 11, 1012); - add_cru(s2f, 43, 0, 1013); - add_cru(s2f, 43, 1, 1016); - add_cru(s2f, 42, 2, 1017); - add_cru(s2f, 42, 3, 1018); - add_cru(s2f, 42, 4, 1019); - add_cru(s2f, 44, 0, 1020); + add_cru(s2f, 34, 0, 728); + add_cru(s2f, 34, 1, 729); + add_cru(s2f, 34, 2, 730); + add_cru(s2f, 34, 3, 731); + add_cru(s2f, 34, 4, 732); + add_cru(s2f, 35, 0, 736); + add_cru(s2f, 35, 1, 737); + add_cru(s2f, 35, 2, 738); + add_cru(s2f, 35, 3, 739); + add_cru(s2f, 35, 4, 740); + add_cru(s2f, 35, 5, 741); + add_cru(s2f, 35, 6, 776); + add_cru(s2f, 35, 7, 777); + add_cru(s2f, 35, 8, 778); + add_cru(s2f, 35, 9, 779); + add_cru(s2f, 35, 10, 780); + add_cru(s2f, 35, 11, 781); + add_cru(s2f, 42, 0, 864); + add_cru(s2f, 42, 1, 865); + add_cru(s2f, 42, 2, 866); + add_cru(s2f, 42, 3, 867); + add_cru(s2f, 42, 6, 352); + add_cru(s2f, 42, 7, 353); + add_cru(s2f, 42, 8, 354); + add_cru(s2f, 42, 9, 355); + add_cru(s2f, 42, 10, 356); + add_cru(s2f, 42, 11, 357); + add_cru(s2f, 43, 0, 304); + add_cru(s2f, 43, 1, 305); + add_cru(s2f, 43, 2, 306); + add_cru(s2f, 43, 3, 307); + add_cru(s2f, 43, 4, 308); + add_cru(s2f, 43, 5, 309); + add_cru(s2f, 43, 6, 856); + add_cru(s2f, 43, 7, 857); + add_cru(s2f, 43, 8, 858); + add_cru(s2f, 43, 9, 859); + add_cru(s2f, 43, 10, 860); } \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH8R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH8R.cxx new file mode 100644 index 0000000000000..4cb0ac2a9330f --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH8R.cxx @@ -0,0 +1,922 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// GENERATED CODE ! DO NOT EDIT ! +/// + +#include "CH.cxx" +void fillElec2DetCH8R(std::map<uint32_t, uint32_t>& e2d) +{ + add(e2d, 806, 8, 824, 0, 0); + add(e2d, 806, 7, 824, 0, 1); + add(e2d, 806, 4, 824, 2, 0); + add(e2d, 806, 3, 824, 2, 1); + add(e2d, 806, 1029, 824, 4, 0); + add(e2d, 806, 1030, 824, 4, 1); + add(e2d, 806, 1025, 824, 6, 0); + add(e2d, 806, 1026, 824, 6, 1); + add(e2d, 806, 106, 824, 1, 0); + add(e2d, 806, 107, 824, 1, 1); + add(e2d, 806, 108, 824, 1, 2); + add(e2d, 806, 101, 824, 3, 0); + add(e2d, 806, 102, 824, 3, 1); + add(e2d, 806, 103, 824, 3, 2); + add(e2d, 806, 1134, 824, 5, 0); + add(e2d, 806, 1133, 824, 5, 1); + add(e2d, 806, 1129, 824, 7, 0); + add(e2d, 806, 1128, 824, 7, 1); + add(e2d, 805, 111, 825, 1, 0); + add(e2d, 805, 112, 825, 1, 1); + add(e2d, 805, 113, 825, 1, 2); + add(e2d, 805, 106, 825, 3, 0); + add(e2d, 805, 107, 825, 3, 1); + add(e2d, 805, 108, 825, 3, 2); + add(e2d, 805, 101, 825, 5, 0); + add(e2d, 805, 102, 825, 5, 1); + add(e2d, 805, 103, 825, 5, 2); + add(e2d, 805, 1139, 825, 0, 0); + add(e2d, 805, 1138, 825, 0, 1); + add(e2d, 805, 1134, 825, 2, 0); + add(e2d, 805, 1133, 825, 2, 1); + add(e2d, 805, 1129, 825, 4, 0); + add(e2d, 805, 1128, 825, 4, 1); + add(e2d, 805, 12, 826, 1, 0); + add(e2d, 805, 11, 826, 1, 1); + add(e2d, 805, 8, 826, 3, 0); + add(e2d, 805, 7, 826, 3, 1); + add(e2d, 805, 4, 826, 5, 0); + add(e2d, 805, 3, 826, 5, 1); + add(e2d, 805, 1033, 826, 0, 0); + add(e2d, 805, 1034, 826, 0, 1); + add(e2d, 805, 1029, 826, 2, 0); + add(e2d, 805, 1030, 826, 2, 1); + add(e2d, 805, 1025, 826, 4, 0); + add(e2d, 805, 1026, 826, 4, 1); + add(e2d, 804, 1, 827, 0, 0); + add(e2d, 804, 2, 827, 0, 1); + add(e2d, 804, 3, 827, 0, 2); + add(e2d, 804, 4, 827, 0, 3); + add(e2d, 804, 5, 827, 0, 4); + add(e2d, 804, 116, 827, 2, 0); + add(e2d, 804, 115, 827, 2, 1); + add(e2d, 804, 114, 827, 2, 2); + add(e2d, 804, 113, 827, 2, 3); + add(e2d, 804, 112, 827, 2, 4); + add(e2d, 804, 108, 827, 4, 0); + add(e2d, 804, 107, 827, 4, 1); + add(e2d, 804, 104, 827, 6, 0); + add(e2d, 804, 103, 827, 6, 1); + add(e2d, 804, 1033, 827, 1, 0); + add(e2d, 804, 1032, 827, 1, 1); + add(e2d, 804, 1031, 827, 1, 2); + add(e2d, 804, 1030, 827, 1, 3); + add(e2d, 804, 1133, 827, 3, 0); + add(e2d, 804, 1134, 827, 3, 1); + add(e2d, 804, 1135, 827, 3, 2); + add(e2d, 804, 1129, 827, 5, 0); + add(e2d, 804, 1130, 827, 5, 1); + add(e2d, 804, 1125, 827, 7, 0); + add(e2d, 804, 1126, 827, 7, 1); + add(e2d, 804, 308, 828, 0, 0); + add(e2d, 804, 307, 828, 0, 1); + add(e2d, 804, 306, 828, 0, 2); + add(e2d, 804, 305, 828, 0, 3); + add(e2d, 804, 304, 828, 0, 4); + add(e2d, 804, 211, 828, 2, 0); + add(e2d, 804, 212, 828, 2, 1); + add(e2d, 804, 213, 828, 2, 2); + add(e2d, 804, 214, 828, 2, 3); + add(e2d, 804, 215, 828, 2, 4); + add(e2d, 804, 206, 828, 4, 0); + add(e2d, 804, 207, 828, 4, 1); + add(e2d, 804, 208, 828, 4, 2); + add(e2d, 804, 201, 828, 6, 0); + add(e2d, 804, 202, 828, 6, 1); + add(e2d, 804, 203, 828, 6, 2); + add(e2d, 804, 1325, 828, 1, 0); + add(e2d, 804, 1326, 828, 1, 1); + add(e2d, 804, 1327, 828, 1, 2); + add(e2d, 804, 1243, 828, 3, 0); + add(e2d, 804, 1242, 828, 3, 1); + add(e2d, 804, 1241, 828, 3, 2); + add(e2d, 804, 1240, 828, 3, 3); + add(e2d, 804, 1234, 828, 5, 0); + add(e2d, 804, 1233, 828, 5, 1); + add(e2d, 804, 1229, 828, 7, 0); + add(e2d, 804, 1228, 828, 7, 1); + add(e2d, 803, 308, 808, 0, 0); + add(e2d, 803, 307, 808, 0, 1); + add(e2d, 803, 306, 808, 0, 2); + add(e2d, 803, 305, 808, 0, 3); + add(e2d, 803, 304, 808, 0, 4); + add(e2d, 803, 316, 808, 2, 0); + add(e2d, 803, 315, 808, 2, 1); + add(e2d, 803, 314, 808, 2, 2); + add(e2d, 803, 313, 808, 2, 3); + add(e2d, 803, 312, 808, 2, 4); + add(e2d, 803, 211, 808, 4, 0); + add(e2d, 803, 212, 808, 4, 1); + add(e2d, 803, 213, 808, 4, 2); + add(e2d, 803, 214, 808, 4, 3); + add(e2d, 803, 215, 808, 4, 4); + add(e2d, 803, 206, 808, 1, 0); + add(e2d, 803, 207, 808, 1, 1); + add(e2d, 803, 208, 808, 1, 2); + add(e2d, 803, 201, 808, 3, 0); + add(e2d, 803, 202, 808, 3, 1); + add(e2d, 803, 203, 808, 3, 2); + add(e2d, 803, 1325, 809, 0, 0); + add(e2d, 803, 1326, 809, 0, 1); + add(e2d, 803, 1327, 809, 0, 2); + add(e2d, 803, 1333, 809, 2, 0); + add(e2d, 803, 1334, 809, 2, 1); + add(e2d, 803, 1335, 809, 2, 2); + add(e2d, 803, 1243, 809, 4, 0); + add(e2d, 803, 1242, 809, 4, 1); + add(e2d, 803, 1241, 809, 4, 2); + add(e2d, 803, 1240, 809, 4, 3); + add(e2d, 803, 1234, 809, 1, 0); + add(e2d, 803, 1233, 809, 1, 1); + add(e2d, 803, 1229, 809, 3, 0); + add(e2d, 803, 1228, 809, 3, 1); + add(e2d, 803, 1, 810, 0, 0); + add(e2d, 803, 2, 810, 0, 1); + add(e2d, 803, 3, 810, 0, 2); + add(e2d, 803, 4, 810, 0, 3); + add(e2d, 803, 5, 810, 0, 4); + add(e2d, 803, 10, 810, 2, 0); + add(e2d, 803, 11, 810, 2, 1); + add(e2d, 803, 12, 810, 2, 2); + add(e2d, 803, 13, 810, 2, 3); + add(e2d, 803, 14, 810, 2, 4); + add(e2d, 803, 116, 810, 4, 0); + add(e2d, 803, 115, 810, 4, 1); + add(e2d, 803, 114, 810, 4, 2); + add(e2d, 803, 113, 810, 4, 3); + add(e2d, 803, 112, 810, 4, 4); + add(e2d, 803, 108, 810, 1, 0); + add(e2d, 803, 107, 810, 1, 1); + add(e2d, 803, 104, 810, 3, 0); + add(e2d, 803, 103, 810, 3, 1); + add(e2d, 803, 1033, 811, 0, 0); + add(e2d, 803, 1032, 811, 0, 1); + add(e2d, 803, 1031, 811, 0, 2); + add(e2d, 803, 1030, 811, 0, 3); + add(e2d, 803, 1042, 811, 2, 0); + add(e2d, 803, 1041, 811, 2, 1); + add(e2d, 803, 1040, 811, 2, 2); + add(e2d, 803, 1039, 811, 2, 3); + add(e2d, 803, 1133, 811, 4, 0); + add(e2d, 803, 1134, 811, 4, 1); + add(e2d, 803, 1135, 811, 4, 2); + add(e2d, 803, 1129, 811, 1, 0); + add(e2d, 803, 1130, 811, 1, 1); + add(e2d, 803, 1125, 811, 3, 0); + add(e2d, 803, 1126, 811, 3, 1); + add(e2d, 802, 5, 812, 0, 0); + add(e2d, 802, 4, 812, 0, 1); + add(e2d, 802, 3, 812, 0, 2); + add(e2d, 802, 2, 812, 0, 3); + add(e2d, 802, 1, 812, 0, 4); + add(e2d, 802, 10, 812, 2, 0); + add(e2d, 802, 9, 812, 2, 1); + add(e2d, 802, 8, 812, 2, 2); + add(e2d, 802, 7, 812, 2, 3); + add(e2d, 802, 6, 812, 2, 4); + add(e2d, 802, 22, 812, 4, 0); + add(e2d, 802, 21, 812, 4, 1); + add(e2d, 802, 20, 812, 4, 2); + add(e2d, 802, 19, 812, 4, 3); + add(e2d, 802, 18, 812, 4, 4); + add(e2d, 802, 27, 812, 6, 0); + add(e2d, 802, 26, 812, 6, 1); + add(e2d, 802, 25, 812, 6, 2); + add(e2d, 802, 24, 812, 6, 3); + add(e2d, 802, 23, 812, 6, 4); + add(e2d, 802, 120, 812, 1, 0); + add(e2d, 802, 119, 812, 1, 1); + add(e2d, 802, 118, 812, 1, 2); + add(e2d, 802, 117, 812, 1, 3); + add(e2d, 802, 116, 812, 1, 4); + add(e2d, 802, 112, 812, 3, 0); + add(e2d, 802, 111, 812, 3, 1); + add(e2d, 802, 110, 812, 3, 2); + add(e2d, 802, 109, 812, 3, 3); + add(e2d, 802, 108, 812, 3, 4); + add(e2d, 802, 104, 812, 5, 0); + add(e2d, 802, 103, 812, 5, 1); + add(e2d, 802, 1039, 813, 0, 0); + add(e2d, 802, 1040, 813, 0, 1); + add(e2d, 802, 1041, 813, 0, 2); + add(e2d, 802, 1035, 813, 2, 0); + add(e2d, 802, 1036, 813, 2, 1); + add(e2d, 802, 1037, 813, 2, 2); + add(e2d, 802, 1038, 813, 2, 3); + add(e2d, 802, 1056, 813, 4, 0); + add(e2d, 802, 1057, 813, 4, 1); + add(e2d, 802, 1058, 813, 4, 2); + add(e2d, 802, 1052, 813, 6, 0); + add(e2d, 802, 1053, 813, 6, 1); + add(e2d, 802, 1054, 813, 6, 2); + add(e2d, 802, 1055, 813, 6, 3); + add(e2d, 802, 1137, 813, 1, 0); + add(e2d, 802, 1138, 813, 1, 1); + add(e2d, 802, 1139, 813, 1, 2); + add(e2d, 802, 1129, 813, 3, 0); + add(e2d, 802, 1130, 813, 3, 1); + add(e2d, 802, 1131, 813, 3, 2); + add(e2d, 802, 1125, 813, 5, 0); + add(e2d, 802, 1126, 813, 5, 1); + add(e2d, 802, 313, 832, 0, 0); + add(e2d, 802, 314, 832, 0, 1); + add(e2d, 802, 315, 832, 0, 2); + add(e2d, 802, 316, 832, 0, 3); + add(e2d, 802, 317, 832, 0, 4); + add(e2d, 802, 308, 832, 2, 0); + add(e2d, 802, 309, 832, 2, 1); + add(e2d, 802, 310, 832, 2, 2); + add(e2d, 802, 311, 832, 2, 3); + add(e2d, 802, 312, 832, 2, 4); + add(e2d, 802, 330, 832, 4, 0); + add(e2d, 802, 331, 832, 4, 1); + add(e2d, 802, 332, 832, 4, 2); + add(e2d, 802, 333, 832, 4, 3); + add(e2d, 802, 334, 832, 4, 4); + add(e2d, 802, 325, 832, 6, 0); + add(e2d, 802, 326, 832, 6, 1); + add(e2d, 802, 327, 832, 6, 2); + add(e2d, 802, 328, 832, 6, 3); + add(e2d, 802, 329, 832, 6, 4); + add(e2d, 802, 215, 832, 1, 0); + add(e2d, 802, 216, 832, 1, 1); + add(e2d, 802, 217, 832, 1, 2); + add(e2d, 802, 218, 832, 1, 3); + add(e2d, 802, 219, 832, 1, 4); + add(e2d, 802, 206, 832, 3, 0); + add(e2d, 802, 207, 832, 3, 1); + add(e2d, 802, 208, 832, 3, 2); + add(e2d, 802, 209, 832, 3, 3); + add(e2d, 802, 210, 832, 3, 4); + add(e2d, 802, 201, 832, 5, 0); + add(e2d, 802, 202, 832, 5, 1); + add(e2d, 802, 203, 832, 5, 2); + add(e2d, 802, 1327, 833, 0, 0); + add(e2d, 802, 1326, 833, 0, 1); + add(e2d, 802, 1325, 833, 0, 2); + add(e2d, 802, 1331, 833, 2, 0); + add(e2d, 802, 1330, 833, 2, 1); + add(e2d, 802, 1329, 833, 2, 2); + add(e2d, 802, 1328, 833, 2, 3); + add(e2d, 802, 1344, 833, 4, 0); + add(e2d, 802, 1343, 833, 4, 1); + add(e2d, 802, 1342, 833, 4, 2); + add(e2d, 802, 1348, 833, 6, 0); + add(e2d, 802, 1347, 833, 6, 1); + add(e2d, 802, 1346, 833, 6, 2); + add(e2d, 802, 1345, 833, 6, 3); + add(e2d, 802, 1247, 833, 1, 0); + add(e2d, 802, 1246, 833, 1, 1); + add(e2d, 802, 1245, 833, 1, 2); + add(e2d, 802, 1244, 833, 1, 3); + add(e2d, 802, 1238, 833, 3, 0); + add(e2d, 802, 1237, 833, 3, 1); + add(e2d, 802, 1236, 833, 3, 2); + add(e2d, 802, 1235, 833, 3, 3); + add(e2d, 802, 1229, 833, 5, 0); + add(e2d, 802, 1228, 833, 5, 1); + add(e2d, 801, 403, 834, 0, 0); + add(e2d, 801, 402, 834, 0, 1); + add(e2d, 801, 401, 834, 0, 2); + add(e2d, 801, 408, 834, 2, 0); + add(e2d, 801, 407, 834, 2, 1); + add(e2d, 801, 406, 834, 2, 2); + add(e2d, 801, 405, 834, 2, 3); + add(e2d, 801, 404, 834, 2, 4); + add(e2d, 801, 413, 834, 4, 0); + add(e2d, 801, 412, 834, 4, 1); + add(e2d, 801, 411, 834, 4, 2); + add(e2d, 801, 410, 834, 4, 3); + add(e2d, 801, 409, 834, 4, 4); + add(e2d, 801, 315, 834, 6, 0); + add(e2d, 801, 314, 834, 6, 1); + add(e2d, 801, 313, 834, 6, 2); + add(e2d, 801, 312, 834, 6, 3); + add(e2d, 801, 311, 834, 6, 4); + add(e2d, 801, 320, 834, 1, 0); + add(e2d, 801, 319, 834, 1, 1); + add(e2d, 801, 318, 834, 1, 2); + add(e2d, 801, 317, 834, 1, 3); + add(e2d, 801, 316, 834, 1, 4); + add(e2d, 801, 328, 834, 3, 0); + add(e2d, 801, 329, 834, 3, 1); + add(e2d, 801, 330, 834, 3, 2); + add(e2d, 801, 331, 834, 3, 3); + add(e2d, 801, 332, 834, 3, 4); + add(e2d, 801, 216, 834, 5, 0); + add(e2d, 801, 215, 834, 5, 1); + add(e2d, 801, 214, 834, 5, 2); + add(e2d, 801, 213, 834, 5, 3); + add(e2d, 801, 212, 834, 5, 4); + add(e2d, 801, 208, 834, 7, 0); + add(e2d, 801, 207, 834, 7, 1); + add(e2d, 801, 1330, 835, 0, 0); + add(e2d, 801, 1331, 835, 0, 1); + add(e2d, 801, 1332, 835, 0, 2); + add(e2d, 801, 1333, 835, 0, 3); + add(e2d, 801, 1334, 835, 0, 4); + add(e2d, 801, 1325, 835, 2, 0); + add(e2d, 801, 1326, 835, 2, 1); + add(e2d, 801, 1327, 835, 2, 2); + add(e2d, 801, 1328, 835, 2, 3); + add(e2d, 801, 1329, 835, 2, 4); + add(e2d, 801, 1349, 835, 4, 0); + add(e2d, 801, 1350, 835, 4, 1); + add(e2d, 801, 1351, 835, 4, 2); + add(e2d, 801, 1345, 835, 6, 0); + add(e2d, 801, 1346, 835, 6, 1); + add(e2d, 801, 1347, 835, 6, 2); + add(e2d, 801, 1348, 835, 6, 3); + add(e2d, 801, 1360, 835, 1, 0); + add(e2d, 801, 1359, 835, 1, 1); + add(e2d, 801, 1358, 835, 1, 2); + add(e2d, 801, 1357, 835, 1, 3); + add(e2d, 801, 1233, 835, 3, 0); + add(e2d, 801, 1234, 835, 3, 1); + add(e2d, 801, 1235, 835, 3, 2); + add(e2d, 801, 1229, 835, 5, 0); + add(e2d, 801, 1230, 835, 5, 1); + add(e2d, 801, 1225, 835, 7, 0); + add(e2d, 801, 1226, 835, 7, 1); + add(e2d, 801, 204, 836, 0, 0); + add(e2d, 801, 203, 836, 0, 1); + add(e2d, 801, 1, 836, 2, 0); + add(e2d, 801, 0, 836, 2, 1); + add(e2d, 801, 14, 836, 4, 0); + add(e2d, 801, 15, 836, 4, 1); + add(e2d, 801, 16, 836, 4, 2); + add(e2d, 801, 17, 836, 4, 3); + add(e2d, 801, 18, 836, 4, 4); + add(e2d, 801, 9, 836, 6, 0); + add(e2d, 801, 10, 836, 6, 1); + add(e2d, 801, 11, 836, 6, 2); + add(e2d, 801, 12, 836, 6, 3); + add(e2d, 801, 13, 836, 6, 4); + add(e2d, 801, 26, 836, 1, 0); + add(e2d, 801, 25, 836, 1, 1); + add(e2d, 801, 24, 836, 1, 2); + add(e2d, 801, 23, 836, 1, 3); + add(e2d, 801, 22, 836, 1, 4); + add(e2d, 801, 111, 836, 3, 0); + add(e2d, 801, 112, 836, 3, 1); + add(e2d, 801, 113, 836, 3, 2); + add(e2d, 801, 114, 836, 3, 3); + add(e2d, 801, 115, 836, 3, 4); + add(e2d, 801, 106, 836, 5, 0); + add(e2d, 801, 107, 836, 5, 1); + add(e2d, 801, 108, 836, 5, 2); + add(e2d, 801, 101, 836, 7, 0); + add(e2d, 801, 102, 836, 7, 1); + add(e2d, 801, 103, 836, 7, 2); + add(e2d, 801, 1028, 837, 0, 0); + add(e2d, 801, 1027, 837, 0, 1); + add(e2d, 801, 1026, 837, 0, 2); + add(e2d, 801, 1032, 837, 2, 0); + add(e2d, 801, 1031, 837, 2, 1); + add(e2d, 801, 1030, 837, 2, 2); + add(e2d, 801, 1029, 837, 2, 3); + add(e2d, 801, 1043, 837, 4, 0); + add(e2d, 801, 1044, 837, 4, 1); + add(e2d, 801, 1045, 837, 4, 2); + add(e2d, 801, 1143, 837, 1, 0); + add(e2d, 801, 1142, 837, 1, 1); + add(e2d, 801, 1141, 837, 1, 2); + add(e2d, 801, 1140, 837, 1, 3); + add(e2d, 801, 1134, 837, 3, 0); + add(e2d, 801, 1133, 837, 3, 1); + add(e2d, 801, 1129, 837, 5, 0); + add(e2d, 801, 1128, 837, 5, 1); + add(e2d, 800, 5, 600, 0, 0); + add(e2d, 800, 4, 600, 0, 1); + add(e2d, 800, 3, 600, 0, 2); + add(e2d, 800, 2, 600, 0, 3); + add(e2d, 800, 1, 600, 0, 4); + add(e2d, 800, 10, 600, 2, 0); + add(e2d, 800, 9, 600, 2, 1); + add(e2d, 800, 8, 600, 2, 2); + add(e2d, 800, 7, 600, 2, 3); + add(e2d, 800, 6, 600, 2, 4); + add(e2d, 800, 18, 600, 4, 0); + add(e2d, 800, 19, 600, 4, 1); + add(e2d, 800, 20, 600, 4, 2); + add(e2d, 800, 21, 600, 4, 3); + add(e2d, 800, 22, 600, 4, 4); + add(e2d, 800, 116, 600, 1, 0); + add(e2d, 800, 115, 600, 1, 1); + add(e2d, 800, 114, 600, 1, 2); + add(e2d, 800, 113, 600, 1, 3); + add(e2d, 800, 112, 600, 1, 4); + add(e2d, 800, 108, 600, 3, 0); + add(e2d, 800, 107, 600, 3, 1); + add(e2d, 800, 104, 600, 5, 0); + add(e2d, 800, 103, 600, 5, 1); + add(e2d, 800, 1039, 601, 0, 0); + add(e2d, 800, 1040, 601, 0, 1); + add(e2d, 800, 1041, 601, 0, 2); + add(e2d, 800, 1035, 601, 2, 0); + add(e2d, 800, 1036, 601, 2, 1); + add(e2d, 800, 1037, 601, 2, 2); + add(e2d, 800, 1038, 601, 2, 3); + add(e2d, 800, 1050, 601, 4, 0); + add(e2d, 800, 1049, 601, 4, 1); + add(e2d, 800, 1048, 601, 4, 2); + add(e2d, 800, 1047, 601, 4, 3); + add(e2d, 800, 1133, 601, 1, 0); + add(e2d, 800, 1134, 601, 1, 1); + add(e2d, 800, 1135, 601, 1, 2); + add(e2d, 800, 1129, 601, 3, 0); + add(e2d, 800, 1130, 601, 3, 1); + add(e2d, 800, 1125, 601, 5, 0); + add(e2d, 800, 1126, 601, 5, 1); + add(e2d, 800, 313, 602, 0, 0); + add(e2d, 800, 314, 602, 0, 1); + add(e2d, 800, 315, 602, 0, 2); + add(e2d, 800, 316, 602, 0, 3); + add(e2d, 800, 317, 602, 0, 4); + add(e2d, 800, 308, 602, 2, 0); + add(e2d, 800, 309, 602, 2, 1); + add(e2d, 800, 310, 602, 2, 2); + add(e2d, 800, 311, 602, 2, 3); + add(e2d, 800, 312, 602, 2, 4); + add(e2d, 800, 325, 602, 4, 0); + add(e2d, 800, 324, 602, 4, 1); + add(e2d, 800, 323, 602, 4, 2); + add(e2d, 800, 322, 602, 4, 3); + add(e2d, 800, 321, 602, 4, 4); + add(e2d, 800, 211, 602, 1, 0); + add(e2d, 800, 212, 602, 1, 1); + add(e2d, 800, 213, 602, 1, 2); + add(e2d, 800, 214, 602, 1, 3); + add(e2d, 800, 215, 602, 1, 4); + add(e2d, 800, 206, 602, 3, 0); + add(e2d, 800, 207, 602, 3, 1); + add(e2d, 800, 208, 602, 3, 2); + add(e2d, 800, 201, 602, 5, 0); + add(e2d, 800, 202, 602, 5, 1); + add(e2d, 800, 203, 602, 5, 2); + add(e2d, 800, 1327, 603, 0, 0); + add(e2d, 800, 1326, 603, 0, 1); + add(e2d, 800, 1325, 603, 0, 2); + add(e2d, 800, 1331, 603, 2, 0); + add(e2d, 800, 1330, 603, 2, 1); + add(e2d, 800, 1329, 603, 2, 2); + add(e2d, 800, 1328, 603, 2, 3); + add(e2d, 800, 1342, 603, 4, 0); + add(e2d, 800, 1343, 603, 4, 1); + add(e2d, 800, 1344, 603, 4, 2); + add(e2d, 800, 1243, 603, 1, 0); + add(e2d, 800, 1242, 603, 1, 1); + add(e2d, 800, 1241, 603, 1, 2); + add(e2d, 800, 1240, 603, 1, 3); + add(e2d, 800, 1234, 603, 3, 0); + add(e2d, 800, 1233, 603, 3, 1); + add(e2d, 800, 1229, 603, 5, 0); + add(e2d, 800, 1228, 603, 5, 1); + add(e2d, 825, 1, 576, 2, 0); + add(e2d, 825, 0, 576, 2, 1); + add(e2d, 825, 204, 576, 0, 0); + add(e2d, 825, 203, 576, 0, 1); + add(e2d, 825, 14, 576, 4, 0); + add(e2d, 825, 15, 576, 4, 1); + add(e2d, 825, 16, 576, 4, 2); + add(e2d, 825, 17, 576, 4, 3); + add(e2d, 825, 18, 576, 4, 4); + add(e2d, 825, 9, 576, 6, 0); + add(e2d, 825, 10, 576, 6, 1); + add(e2d, 825, 11, 576, 6, 2); + add(e2d, 825, 12, 576, 6, 3); + add(e2d, 825, 13, 576, 6, 4); + add(e2d, 825, 26, 576, 1, 0); + add(e2d, 825, 25, 576, 1, 1); + add(e2d, 825, 24, 576, 1, 2); + add(e2d, 825, 23, 576, 1, 3); + add(e2d, 825, 22, 576, 1, 4); + add(e2d, 825, 111, 576, 3, 0); + add(e2d, 825, 112, 576, 3, 1); + add(e2d, 825, 113, 576, 3, 2); + add(e2d, 825, 114, 576, 3, 3); + add(e2d, 825, 115, 576, 3, 4); + add(e2d, 825, 106, 576, 5, 0); + add(e2d, 825, 107, 576, 5, 1); + add(e2d, 825, 108, 576, 5, 2); + add(e2d, 825, 101, 576, 7, 0); + add(e2d, 825, 102, 576, 7, 1); + add(e2d, 825, 103, 576, 7, 2); + add(e2d, 825, 1028, 577, 0, 0); + add(e2d, 825, 1027, 577, 0, 1); + add(e2d, 825, 1026, 577, 0, 2); + add(e2d, 825, 1029, 577, 2, 0); + add(e2d, 825, 1030, 577, 2, 1); + add(e2d, 825, 1031, 577, 2, 2); + add(e2d, 825, 1032, 577, 2, 3); + add(e2d, 825, 1043, 577, 4, 0); + add(e2d, 825, 1044, 577, 4, 1); + add(e2d, 825, 1045, 577, 4, 2); + add(e2d, 825, 1143, 577, 1, 0); + add(e2d, 825, 1142, 577, 1, 1); + add(e2d, 825, 1141, 577, 1, 2); + add(e2d, 825, 1140, 577, 1, 3); + add(e2d, 825, 1134, 577, 3, 0); + add(e2d, 825, 1133, 577, 3, 1); + add(e2d, 825, 1129, 577, 5, 0); + add(e2d, 825, 1128, 577, 5, 1); + add(e2d, 825, 403, 578, 0, 0); + add(e2d, 825, 402, 578, 0, 1); + add(e2d, 825, 401, 578, 0, 2); + add(e2d, 825, 408, 578, 2, 0); + add(e2d, 825, 407, 578, 2, 1); + add(e2d, 825, 406, 578, 2, 2); + add(e2d, 825, 405, 578, 2, 3); + add(e2d, 825, 404, 578, 2, 4); + add(e2d, 825, 413, 578, 4, 0); + add(e2d, 825, 412, 578, 4, 1); + add(e2d, 825, 411, 578, 4, 2); + add(e2d, 825, 410, 578, 4, 3); + add(e2d, 825, 409, 578, 4, 4); + add(e2d, 825, 315, 578, 6, 0); + add(e2d, 825, 314, 578, 6, 1); + add(e2d, 825, 313, 578, 6, 2); + add(e2d, 825, 312, 578, 6, 3); + add(e2d, 825, 311, 578, 6, 4); + add(e2d, 825, 320, 578, 1, 0); + add(e2d, 825, 319, 578, 1, 1); + add(e2d, 825, 318, 578, 1, 2); + add(e2d, 825, 317, 578, 1, 3); + add(e2d, 825, 316, 578, 1, 4); + add(e2d, 825, 328, 578, 3, 0); + add(e2d, 825, 329, 578, 3, 1); + add(e2d, 825, 330, 578, 3, 2); + add(e2d, 825, 331, 578, 3, 3); + add(e2d, 825, 332, 578, 3, 4); + add(e2d, 825, 216, 578, 5, 0); + add(e2d, 825, 215, 578, 5, 1); + add(e2d, 825, 214, 578, 5, 2); + add(e2d, 825, 213, 578, 5, 3); + add(e2d, 825, 212, 578, 5, 4); + add(e2d, 825, 208, 578, 7, 0); + add(e2d, 825, 207, 578, 7, 1); + add(e2d, 825, 1330, 579, 0, 0); + add(e2d, 825, 1331, 579, 0, 1); + add(e2d, 825, 1332, 579, 0, 2); + add(e2d, 825, 1333, 579, 0, 3); + add(e2d, 825, 1334, 579, 0, 4); + add(e2d, 825, 1325, 579, 2, 0); + add(e2d, 825, 1326, 579, 2, 1); + add(e2d, 825, 1327, 579, 2, 2); + add(e2d, 825, 1328, 579, 2, 3); + add(e2d, 825, 1329, 579, 2, 4); + add(e2d, 825, 1349, 579, 4, 0); + add(e2d, 825, 1350, 579, 4, 1); + add(e2d, 825, 1351, 579, 4, 2); + add(e2d, 825, 1345, 579, 6, 0); + add(e2d, 825, 1346, 579, 6, 1); + add(e2d, 825, 1347, 579, 6, 2); + add(e2d, 825, 1348, 579, 6, 3); + add(e2d, 825, 1360, 579, 1, 0); + add(e2d, 825, 1359, 579, 1, 1); + add(e2d, 825, 1358, 579, 1, 2); + add(e2d, 825, 1357, 579, 1, 3); + add(e2d, 825, 1233, 579, 3, 0); + add(e2d, 825, 1234, 579, 3, 1); + add(e2d, 825, 1235, 579, 3, 2); + add(e2d, 825, 1229, 579, 5, 0); + add(e2d, 825, 1230, 579, 5, 1); + add(e2d, 825, 1225, 579, 7, 0); + add(e2d, 825, 1226, 579, 7, 1); + add(e2d, 824, 5, 580, 0, 0); + add(e2d, 824, 4, 580, 0, 1); + add(e2d, 824, 3, 580, 0, 2); + add(e2d, 824, 2, 580, 0, 3); + add(e2d, 824, 1, 580, 0, 4); + add(e2d, 824, 10, 580, 2, 0); + add(e2d, 824, 9, 580, 2, 1); + add(e2d, 824, 8, 580, 2, 2); + add(e2d, 824, 7, 580, 2, 3); + add(e2d, 824, 6, 580, 2, 4); + add(e2d, 824, 22, 580, 4, 0); + add(e2d, 824, 21, 580, 4, 1); + add(e2d, 824, 20, 580, 4, 2); + add(e2d, 824, 19, 580, 4, 3); + add(e2d, 824, 18, 580, 4, 4); + add(e2d, 824, 27, 580, 6, 0); + add(e2d, 824, 26, 580, 6, 1); + add(e2d, 824, 25, 580, 6, 2); + add(e2d, 824, 24, 580, 6, 3); + add(e2d, 824, 23, 580, 6, 4); + add(e2d, 824, 120, 580, 1, 0); + add(e2d, 824, 119, 580, 1, 1); + add(e2d, 824, 118, 580, 1, 2); + add(e2d, 824, 117, 580, 1, 3); + add(e2d, 824, 116, 580, 1, 4); + add(e2d, 824, 112, 580, 3, 0); + add(e2d, 824, 111, 580, 3, 1); + add(e2d, 824, 110, 580, 3, 2); + add(e2d, 824, 109, 580, 3, 3); + add(e2d, 824, 108, 580, 3, 4); + add(e2d, 824, 104, 580, 5, 0); + add(e2d, 824, 103, 580, 5, 1); + add(e2d, 824, 1039, 581, 0, 0); + add(e2d, 824, 1040, 581, 0, 1); + add(e2d, 824, 1041, 581, 0, 2); + add(e2d, 824, 1035, 581, 2, 0); + add(e2d, 824, 1036, 581, 2, 1); + add(e2d, 824, 1037, 581, 2, 2); + add(e2d, 824, 1038, 581, 2, 3); + add(e2d, 824, 1056, 581, 4, 0); + add(e2d, 824, 1057, 581, 4, 1); + add(e2d, 824, 1058, 581, 4, 2); + add(e2d, 824, 1052, 581, 6, 0); + add(e2d, 824, 1053, 581, 6, 1); + add(e2d, 824, 1054, 581, 6, 2); + add(e2d, 824, 1055, 581, 6, 3); + add(e2d, 824, 1137, 581, 1, 0); + add(e2d, 824, 1138, 581, 1, 1); + add(e2d, 824, 1139, 581, 1, 2); + add(e2d, 824, 1129, 581, 3, 0); + add(e2d, 824, 1130, 581, 3, 1); + add(e2d, 824, 1131, 581, 3, 2); + add(e2d, 824, 1125, 581, 5, 0); + add(e2d, 824, 1126, 581, 5, 1); + add(e2d, 824, 313, 592, 0, 0); + add(e2d, 824, 314, 592, 0, 1); + add(e2d, 824, 315, 592, 0, 2); + add(e2d, 824, 316, 592, 0, 3); + add(e2d, 824, 317, 592, 0, 4); + add(e2d, 824, 308, 592, 2, 0); + add(e2d, 824, 309, 592, 2, 1); + add(e2d, 824, 310, 592, 2, 2); + add(e2d, 824, 311, 592, 2, 3); + add(e2d, 824, 312, 592, 2, 4); + add(e2d, 824, 330, 592, 4, 0); + add(e2d, 824, 331, 592, 4, 1); + add(e2d, 824, 332, 592, 4, 2); + add(e2d, 824, 333, 592, 4, 3); + add(e2d, 824, 334, 592, 4, 4); + add(e2d, 824, 325, 592, 6, 0); + add(e2d, 824, 326, 592, 6, 1); + add(e2d, 824, 327, 592, 6, 2); + add(e2d, 824, 328, 592, 6, 3); + add(e2d, 824, 329, 592, 6, 4); + add(e2d, 824, 215, 592, 1, 0); + add(e2d, 824, 216, 592, 1, 1); + add(e2d, 824, 217, 592, 1, 2); + add(e2d, 824, 218, 592, 1, 3); + add(e2d, 824, 219, 592, 1, 4); + add(e2d, 824, 206, 592, 3, 0); + add(e2d, 824, 207, 592, 3, 1); + add(e2d, 824, 208, 592, 3, 2); + add(e2d, 824, 209, 592, 3, 3); + add(e2d, 824, 210, 592, 3, 4); + add(e2d, 824, 201, 592, 5, 0); + add(e2d, 824, 202, 592, 5, 1); + add(e2d, 824, 203, 592, 5, 2); + add(e2d, 824, 1327, 593, 0, 0); + add(e2d, 824, 1326, 593, 0, 1); + add(e2d, 824, 1325, 593, 0, 2); + add(e2d, 824, 1331, 593, 2, 0); + add(e2d, 824, 1330, 593, 2, 1); + add(e2d, 824, 1329, 593, 2, 2); + add(e2d, 824, 1328, 593, 2, 3); + add(e2d, 824, 1344, 593, 4, 0); + add(e2d, 824, 1343, 593, 4, 1); + add(e2d, 824, 1342, 593, 4, 2); + add(e2d, 824, 1348, 593, 6, 0); + add(e2d, 824, 1347, 593, 6, 1); + add(e2d, 824, 1346, 593, 6, 2); + add(e2d, 824, 1345, 593, 6, 3); + add(e2d, 824, 1247, 593, 1, 0); + add(e2d, 824, 1246, 593, 1, 1); + add(e2d, 824, 1245, 593, 1, 2); + add(e2d, 824, 1244, 593, 1, 3); + add(e2d, 824, 1238, 593, 3, 0); + add(e2d, 824, 1237, 593, 3, 1); + add(e2d, 824, 1236, 593, 3, 2); + add(e2d, 824, 1235, 593, 3, 3); + add(e2d, 824, 1229, 593, 5, 0); + add(e2d, 824, 1228, 593, 5, 1); + add(e2d, 823, 308, 594, 0, 0); + add(e2d, 823, 307, 594, 0, 1); + add(e2d, 823, 306, 594, 0, 2); + add(e2d, 823, 305, 594, 0, 3); + add(e2d, 823, 304, 594, 0, 4); + add(e2d, 823, 316, 594, 2, 0); + add(e2d, 823, 315, 594, 2, 1); + add(e2d, 823, 314, 594, 2, 2); + add(e2d, 823, 313, 594, 2, 3); + add(e2d, 823, 312, 594, 2, 4); + add(e2d, 823, 211, 594, 4, 0); + add(e2d, 823, 212, 594, 4, 1); + add(e2d, 823, 213, 594, 4, 2); + add(e2d, 823, 214, 594, 4, 3); + add(e2d, 823, 215, 594, 4, 4); + add(e2d, 823, 206, 594, 1, 0); + add(e2d, 823, 207, 594, 1, 1); + add(e2d, 823, 208, 594, 1, 2); + add(e2d, 823, 201, 594, 3, 0); + add(e2d, 823, 202, 594, 3, 1); + add(e2d, 823, 203, 594, 3, 2); + add(e2d, 823, 1325, 595, 0, 0); + add(e2d, 823, 1326, 595, 0, 1); + add(e2d, 823, 1327, 595, 0, 2); + add(e2d, 823, 1333, 595, 2, 0); + add(e2d, 823, 1334, 595, 2, 1); + add(e2d, 823, 1335, 595, 2, 2); + add(e2d, 823, 1243, 595, 4, 0); + add(e2d, 823, 1242, 595, 4, 1); + add(e2d, 823, 1241, 595, 4, 2); + add(e2d, 823, 1240, 595, 4, 3); + add(e2d, 823, 1234, 595, 1, 0); + add(e2d, 823, 1233, 595, 1, 1); + add(e2d, 823, 1229, 595, 3, 0); + add(e2d, 823, 1228, 595, 3, 1); + add(e2d, 823, 1, 596, 0, 0); + add(e2d, 823, 2, 596, 0, 1); + add(e2d, 823, 3, 596, 0, 2); + add(e2d, 823, 4, 596, 0, 3); + add(e2d, 823, 5, 596, 0, 4); + add(e2d, 823, 10, 596, 2, 0); + add(e2d, 823, 11, 596, 2, 1); + add(e2d, 823, 12, 596, 2, 2); + add(e2d, 823, 13, 596, 2, 3); + add(e2d, 823, 14, 596, 2, 4); + add(e2d, 823, 116, 596, 4, 0); + add(e2d, 823, 115, 596, 4, 1); + add(e2d, 823, 114, 596, 4, 2); + add(e2d, 823, 113, 596, 4, 3); + add(e2d, 823, 112, 596, 4, 4); + add(e2d, 823, 108, 596, 1, 0); + add(e2d, 823, 107, 596, 1, 1); + add(e2d, 823, 104, 596, 3, 0); + add(e2d, 823, 103, 596, 3, 1); + add(e2d, 823, 1033, 597, 0, 0); + add(e2d, 823, 1032, 597, 0, 1); + add(e2d, 823, 1031, 597, 0, 2); + add(e2d, 823, 1030, 597, 0, 3); + add(e2d, 823, 1042, 597, 2, 0); + add(e2d, 823, 1041, 597, 2, 1); + add(e2d, 823, 1040, 597, 2, 2); + add(e2d, 823, 1039, 597, 2, 3); + add(e2d, 823, 1133, 597, 4, 0); + add(e2d, 823, 1134, 597, 4, 1); + add(e2d, 823, 1135, 597, 4, 2); + add(e2d, 823, 1129, 597, 1, 0); + add(e2d, 823, 1130, 597, 1, 1); + add(e2d, 823, 1125, 597, 3, 0); + add(e2d, 823, 1126, 597, 3, 1); + add(e2d, 822, 1, 496, 0, 0); + add(e2d, 822, 2, 496, 0, 1); + add(e2d, 822, 3, 496, 0, 2); + add(e2d, 822, 4, 496, 0, 3); + add(e2d, 822, 5, 496, 0, 4); + add(e2d, 822, 116, 496, 2, 0); + add(e2d, 822, 115, 496, 2, 1); + add(e2d, 822, 114, 496, 2, 2); + add(e2d, 822, 113, 496, 2, 3); + add(e2d, 822, 112, 496, 2, 4); + add(e2d, 822, 108, 496, 4, 0); + add(e2d, 822, 107, 496, 4, 1); + add(e2d, 822, 104, 496, 6, 0); + add(e2d, 822, 103, 496, 6, 1); + add(e2d, 822, 1033, 496, 1, 0); + add(e2d, 822, 1032, 496, 1, 1); + add(e2d, 822, 1031, 496, 1, 2); + add(e2d, 822, 1030, 496, 1, 3); + add(e2d, 822, 1133, 496, 3, 0); + add(e2d, 822, 1134, 496, 3, 1); + add(e2d, 822, 1135, 496, 3, 2); + add(e2d, 822, 1129, 496, 5, 0); + add(e2d, 822, 1130, 496, 5, 1); + add(e2d, 822, 1125, 496, 7, 0); + add(e2d, 822, 1126, 496, 7, 1); + add(e2d, 822, 308, 497, 0, 0); + add(e2d, 822, 307, 497, 0, 1); + add(e2d, 822, 306, 497, 0, 2); + add(e2d, 822, 305, 497, 0, 3); + add(e2d, 822, 304, 497, 0, 4); + add(e2d, 822, 211, 497, 2, 0); + add(e2d, 822, 212, 497, 2, 1); + add(e2d, 822, 213, 497, 2, 2); + add(e2d, 822, 214, 497, 2, 3); + add(e2d, 822, 215, 497, 2, 4); + add(e2d, 822, 206, 497, 4, 0); + add(e2d, 822, 207, 497, 4, 1); + add(e2d, 822, 208, 497, 4, 2); + add(e2d, 822, 201, 497, 6, 0); + add(e2d, 822, 202, 497, 6, 1); + add(e2d, 822, 203, 497, 6, 2); + add(e2d, 822, 1325, 497, 1, 0); + add(e2d, 822, 1326, 497, 1, 1); + add(e2d, 822, 1327, 497, 1, 2); + add(e2d, 822, 1243, 497, 3, 0); + add(e2d, 822, 1242, 497, 3, 1); + add(e2d, 822, 1241, 497, 3, 2); + add(e2d, 822, 1240, 497, 3, 3); + add(e2d, 822, 1234, 497, 5, 0); + add(e2d, 822, 1233, 497, 5, 1); + add(e2d, 822, 1229, 497, 7, 0); + add(e2d, 822, 1228, 497, 7, 1); + add(e2d, 821, 111, 498, 0, 0); + add(e2d, 821, 112, 498, 0, 1); + add(e2d, 821, 113, 498, 0, 2); + add(e2d, 821, 106, 498, 2, 0); + add(e2d, 821, 107, 498, 2, 1); + add(e2d, 821, 108, 498, 2, 2); + add(e2d, 821, 101, 498, 4, 0); + add(e2d, 821, 102, 498, 4, 1); + add(e2d, 821, 103, 498, 4, 2); + add(e2d, 821, 1139, 498, 1, 0); + add(e2d, 821, 1138, 498, 1, 1); + add(e2d, 821, 1134, 498, 3, 0); + add(e2d, 821, 1133, 498, 3, 1); + add(e2d, 821, 1129, 498, 5, 0); + add(e2d, 821, 1128, 498, 5, 1); + add(e2d, 821, 12, 499, 0, 0); + add(e2d, 821, 11, 499, 0, 1); + add(e2d, 821, 8, 499, 2, 0); + add(e2d, 821, 7, 499, 2, 1); + add(e2d, 821, 4, 499, 4, 0); + add(e2d, 821, 3, 499, 4, 1); + add(e2d, 821, 1033, 499, 1, 0); + add(e2d, 821, 1034, 499, 1, 1); + add(e2d, 821, 1029, 499, 3, 0); + add(e2d, 821, 1030, 499, 3, 1); + add(e2d, 821, 1025, 499, 5, 0); + add(e2d, 821, 1026, 499, 5, 1); + add(e2d, 820, 8, 500, 0, 0); + add(e2d, 820, 7, 500, 0, 1); + add(e2d, 820, 4, 500, 2, 0); + add(e2d, 820, 3, 500, 2, 1); + add(e2d, 820, 1029, 500, 4, 0); + add(e2d, 820, 1030, 500, 4, 1); + add(e2d, 820, 1025, 500, 6, 0); + add(e2d, 820, 1026, 500, 6, 1); + add(e2d, 820, 106, 500, 1, 0); + add(e2d, 820, 107, 500, 1, 1); + add(e2d, 820, 108, 500, 1, 2); + add(e2d, 820, 101, 500, 3, 0); + add(e2d, 820, 102, 500, 3, 1); + add(e2d, 820, 103, 500, 3, 2); + add(e2d, 820, 1134, 500, 5, 0); + add(e2d, 820, 1133, 500, 5, 1); + add(e2d, 820, 1129, 500, 7, 0); + add(e2d, 820, 1128, 500, 7, 1); +} +void fillSolar2FeeLinkCH8R(std::map<uint16_t, uint32_t>& s2f) +{ + add_cru(s2f, 40, 0, 824); + add_cru(s2f, 40, 1, 825); + add_cru(s2f, 40, 2, 826); + add_cru(s2f, 40, 3, 827); + add_cru(s2f, 40, 4, 828); + add_cru(s2f, 41, 0, 808); + add_cru(s2f, 41, 1, 809); + add_cru(s2f, 41, 2, 810); + add_cru(s2f, 41, 3, 811); + add_cru(s2f, 41, 4, 812); + add_cru(s2f, 41, 5, 813); + add_cru(s2f, 41, 6, 832); + add_cru(s2f, 41, 7, 833); + add_cru(s2f, 41, 8, 834); + add_cru(s2f, 41, 9, 835); + add_cru(s2f, 41, 10, 836); + add_cru(s2f, 41, 11, 837); + add_cru(s2f, 48, 0, 600); + add_cru(s2f, 48, 1, 601); + add_cru(s2f, 48, 2, 602); + add_cru(s2f, 48, 3, 603); + add_cru(s2f, 48, 6, 576); + add_cru(s2f, 48, 7, 577); + add_cru(s2f, 48, 8, 578); + add_cru(s2f, 48, 9, 579); + add_cru(s2f, 48, 10, 580); + add_cru(s2f, 48, 11, 581); + add_cru(s2f, 49, 0, 592); + add_cru(s2f, 49, 1, 593); + add_cru(s2f, 49, 2, 594); + add_cru(s2f, 49, 3, 595); + add_cru(s2f, 49, 4, 596); + add_cru(s2f, 49, 5, 597); + add_cru(s2f, 49, 6, 496); + add_cru(s2f, 49, 7, 497); + add_cru(s2f, 49, 8, 498); + add_cru(s2f, 49, 9, 499); + add_cru(s2f, 49, 10, 500); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH9L.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH9L.cxx new file mode 100644 index 0000000000000..c29453fdbfddb --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH9L.cxx @@ -0,0 +1,1018 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// GENERATED CODE ! DO NOT EDIT ! +/// + +#include "CH.cxx" +void fillElec2DetCH9L(std::map<uint32_t, uint32_t>& e2d) +{ + add(e2d, 907, 12, 680, 0, 0); + add(e2d, 907, 11, 680, 0, 1); + add(e2d, 907, 8, 680, 2, 0); + add(e2d, 907, 7, 680, 2, 1); + add(e2d, 907, 4, 680, 4, 0); + add(e2d, 907, 3, 680, 4, 1); + add(e2d, 907, 1033, 680, 1, 0); + add(e2d, 907, 1034, 680, 1, 1); + add(e2d, 907, 1029, 680, 3, 0); + add(e2d, 907, 1030, 680, 3, 1); + add(e2d, 907, 1025, 680, 5, 0); + add(e2d, 907, 1026, 680, 5, 1); + add(e2d, 907, 111, 681, 0, 0); + add(e2d, 907, 112, 681, 0, 1); + add(e2d, 907, 113, 681, 0, 2); + add(e2d, 907, 106, 681, 2, 0); + add(e2d, 907, 107, 681, 2, 1); + add(e2d, 907, 108, 681, 2, 2); + add(e2d, 907, 101, 681, 4, 0); + add(e2d, 907, 102, 681, 4, 1); + add(e2d, 907, 103, 681, 4, 2); + add(e2d, 907, 1139, 681, 1, 0); + add(e2d, 907, 1138, 681, 1, 1); + add(e2d, 907, 1134, 681, 3, 0); + add(e2d, 907, 1133, 681, 3, 1); + add(e2d, 907, 1129, 681, 5, 0); + add(e2d, 907, 1128, 681, 5, 1); + add(e2d, 908, 304, 682, 0, 0); + add(e2d, 908, 303, 682, 0, 1); + add(e2d, 908, 211, 682, 2, 0); + add(e2d, 908, 212, 682, 2, 1); + add(e2d, 908, 213, 682, 2, 2); + add(e2d, 908, 206, 682, 4, 0); + add(e2d, 908, 207, 682, 4, 1); + add(e2d, 908, 208, 682, 4, 2); + add(e2d, 908, 201, 682, 6, 0); + add(e2d, 908, 202, 682, 6, 1); + add(e2d, 908, 203, 682, 6, 2); + add(e2d, 908, 1325, 682, 1, 0); + add(e2d, 908, 1326, 682, 1, 1); + add(e2d, 908, 1239, 682, 3, 0); + add(e2d, 908, 1238, 682, 3, 1); + add(e2d, 908, 1234, 682, 5, 0); + add(e2d, 908, 1233, 682, 5, 1); + add(e2d, 908, 1229, 682, 7, 0); + add(e2d, 908, 1228, 682, 7, 1); + add(e2d, 908, 1, 683, 0, 0); + add(e2d, 908, 2, 683, 0, 1); + add(e2d, 908, 3, 683, 0, 2); + add(e2d, 908, 112, 683, 2, 0); + add(e2d, 908, 111, 683, 2, 1); + add(e2d, 908, 108, 683, 4, 0); + add(e2d, 908, 107, 683, 4, 1); + add(e2d, 908, 104, 683, 6, 0); + add(e2d, 908, 103, 683, 6, 1); + add(e2d, 908, 1029, 683, 1, 0); + add(e2d, 908, 1028, 683, 1, 1); + add(e2d, 908, 1133, 683, 3, 0); + add(e2d, 908, 1134, 683, 3, 1); + add(e2d, 908, 1129, 683, 5, 0); + add(e2d, 908, 1130, 683, 5, 1); + add(e2d, 908, 1125, 683, 7, 0); + add(e2d, 908, 1126, 683, 7, 1); + add(e2d, 909, 1, 744, 0, 0); + add(e2d, 909, 2, 744, 0, 1); + add(e2d, 909, 3, 744, 0, 2); + add(e2d, 909, 4, 744, 0, 3); + add(e2d, 909, 5, 744, 0, 4); + add(e2d, 909, 10, 744, 2, 0); + add(e2d, 909, 11, 744, 2, 1); + add(e2d, 909, 12, 744, 2, 2); + add(e2d, 909, 13, 744, 2, 3); + add(e2d, 909, 14, 744, 2, 4); + add(e2d, 909, 112, 744, 4, 0); + add(e2d, 909, 111, 744, 4, 1); + add(e2d, 909, 108, 744, 1, 0); + add(e2d, 909, 107, 744, 1, 1); + add(e2d, 909, 104, 744, 3, 0); + add(e2d, 909, 103, 744, 3, 1); + add(e2d, 909, 1033, 745, 0, 0); + add(e2d, 909, 1032, 745, 0, 1); + add(e2d, 909, 1031, 745, 0, 2); + add(e2d, 909, 1030, 745, 0, 3); + add(e2d, 909, 1042, 745, 2, 0); + add(e2d, 909, 1041, 745, 2, 1); + add(e2d, 909, 1040, 745, 2, 2); + add(e2d, 909, 1039, 745, 2, 3); + add(e2d, 909, 1133, 745, 4, 0); + add(e2d, 909, 1134, 745, 4, 1); + add(e2d, 909, 1129, 745, 1, 0); + add(e2d, 909, 1130, 745, 1, 1); + add(e2d, 909, 1125, 745, 3, 0); + add(e2d, 909, 1126, 745, 3, 1); + add(e2d, 909, 308, 746, 0, 0); + add(e2d, 909, 307, 746, 0, 1); + add(e2d, 909, 306, 746, 0, 2); + add(e2d, 909, 305, 746, 0, 3); + add(e2d, 909, 304, 746, 0, 4); + add(e2d, 909, 316, 746, 2, 0); + add(e2d, 909, 315, 746, 2, 1); + add(e2d, 909, 314, 746, 2, 2); + add(e2d, 909, 313, 746, 2, 3); + add(e2d, 909, 312, 746, 2, 4); + add(e2d, 909, 211, 746, 4, 0); + add(e2d, 909, 212, 746, 4, 1); + add(e2d, 909, 213, 746, 4, 2); + add(e2d, 909, 206, 746, 1, 0); + add(e2d, 909, 207, 746, 1, 1); + add(e2d, 909, 208, 746, 1, 2); + add(e2d, 909, 201, 746, 3, 0); + add(e2d, 909, 202, 746, 3, 1); + add(e2d, 909, 203, 746, 3, 2); + add(e2d, 909, 1325, 747, 0, 0); + add(e2d, 909, 1326, 747, 0, 1); + add(e2d, 909, 1327, 747, 0, 2); + add(e2d, 909, 1333, 747, 2, 0); + add(e2d, 909, 1334, 747, 2, 1); + add(e2d, 909, 1335, 747, 2, 2); + add(e2d, 909, 1239, 747, 4, 0); + add(e2d, 909, 1238, 747, 4, 1); + add(e2d, 909, 1234, 747, 1, 0); + add(e2d, 909, 1233, 747, 1, 1); + add(e2d, 909, 1229, 747, 3, 0); + add(e2d, 909, 1228, 747, 3, 1); + add(e2d, 910, 308, 748, 0, 0); + add(e2d, 910, 307, 748, 0, 1); + add(e2d, 910, 306, 748, 0, 2); + add(e2d, 910, 305, 748, 0, 3); + add(e2d, 910, 304, 748, 0, 4); + add(e2d, 910, 316, 748, 2, 0); + add(e2d, 910, 315, 748, 2, 1); + add(e2d, 910, 314, 748, 2, 2); + add(e2d, 910, 313, 748, 2, 3); + add(e2d, 910, 312, 748, 2, 4); + add(e2d, 910, 324, 748, 4, 0); + add(e2d, 910, 323, 748, 4, 1); + add(e2d, 910, 322, 748, 4, 2); + add(e2d, 910, 321, 748, 4, 3); + add(e2d, 910, 320, 748, 4, 4); + add(e2d, 910, 211, 748, 1, 0); + add(e2d, 910, 212, 748, 1, 1); + add(e2d, 910, 213, 748, 1, 2); + add(e2d, 910, 206, 748, 3, 0); + add(e2d, 910, 207, 748, 3, 1); + add(e2d, 910, 208, 748, 3, 2); + add(e2d, 910, 201, 748, 5, 0); + add(e2d, 910, 202, 748, 5, 1); + add(e2d, 910, 203, 748, 5, 2); + add(e2d, 910, 1325, 749, 0, 0); + add(e2d, 910, 1326, 749, 0, 1); + add(e2d, 910, 1327, 749, 0, 2); + add(e2d, 910, 1333, 749, 2, 0); + add(e2d, 910, 1334, 749, 2, 1); + add(e2d, 910, 1335, 749, 2, 2); + add(e2d, 910, 1341, 749, 4, 0); + add(e2d, 910, 1342, 749, 4, 1); + add(e2d, 910, 1343, 749, 4, 2); + add(e2d, 910, 1239, 749, 1, 0); + add(e2d, 910, 1238, 749, 1, 1); + add(e2d, 910, 1234, 749, 3, 0); + add(e2d, 910, 1233, 749, 3, 1); + add(e2d, 910, 1229, 749, 5, 0); + add(e2d, 910, 1228, 749, 5, 1); + add(e2d, 910, 1, 752, 0, 0); + add(e2d, 910, 2, 752, 0, 1); + add(e2d, 910, 3, 752, 0, 2); + add(e2d, 910, 4, 752, 0, 3); + add(e2d, 910, 5, 752, 0, 4); + add(e2d, 910, 10, 752, 2, 0); + add(e2d, 910, 11, 752, 2, 1); + add(e2d, 910, 12, 752, 2, 2); + add(e2d, 910, 13, 752, 2, 3); + add(e2d, 910, 14, 752, 2, 4); + add(e2d, 910, 19, 752, 4, 0); + add(e2d, 910, 20, 752, 4, 1); + add(e2d, 910, 21, 752, 4, 2); + add(e2d, 910, 22, 752, 4, 3); + add(e2d, 910, 23, 752, 4, 4); + add(e2d, 910, 112, 752, 1, 0); + add(e2d, 910, 111, 752, 1, 1); + add(e2d, 910, 108, 752, 3, 0); + add(e2d, 910, 107, 752, 3, 1); + add(e2d, 910, 103, 752, 5, 0); + add(e2d, 910, 104, 752, 5, 1); + add(e2d, 910, 1033, 753, 0, 0); + add(e2d, 910, 1032, 753, 0, 1); + add(e2d, 910, 1031, 753, 0, 2); + add(e2d, 910, 1030, 753, 0, 3); + add(e2d, 910, 1042, 753, 2, 0); + add(e2d, 910, 1041, 753, 2, 1); + add(e2d, 910, 1040, 753, 2, 2); + add(e2d, 910, 1039, 753, 2, 3); + add(e2d, 910, 1051, 753, 4, 0); + add(e2d, 910, 1050, 753, 4, 1); + add(e2d, 910, 1049, 753, 4, 2); + add(e2d, 910, 1048, 753, 4, 3); + add(e2d, 910, 1125, 753, 1, 0); + add(e2d, 910, 1126, 753, 1, 1); + add(e2d, 910, 1129, 753, 3, 0); + add(e2d, 910, 1130, 753, 3, 1); + add(e2d, 910, 1133, 753, 5, 0); + add(e2d, 910, 1134, 753, 5, 1); + add(e2d, 911, 5, 754, 0, 0); + add(e2d, 911, 4, 754, 0, 1); + add(e2d, 911, 3, 754, 0, 2); + add(e2d, 911, 2, 754, 0, 3); + add(e2d, 911, 1, 754, 0, 4); + add(e2d, 911, 10, 754, 2, 0); + add(e2d, 911, 9, 754, 2, 1); + add(e2d, 911, 8, 754, 2, 2); + add(e2d, 911, 7, 754, 2, 3); + add(e2d, 911, 6, 754, 2, 4); + add(e2d, 911, 22, 754, 4, 0); + add(e2d, 911, 21, 754, 4, 1); + add(e2d, 911, 20, 754, 4, 2); + add(e2d, 911, 19, 754, 4, 3); + add(e2d, 911, 18, 754, 4, 4); + add(e2d, 911, 27, 754, 6, 0); + add(e2d, 911, 26, 754, 6, 1); + add(e2d, 911, 25, 754, 6, 2); + add(e2d, 911, 24, 754, 6, 3); + add(e2d, 911, 23, 754, 6, 4); + add(e2d, 911, 39, 754, 1, 0); + add(e2d, 911, 38, 754, 1, 1); + add(e2d, 911, 37, 754, 1, 2); + add(e2d, 911, 36, 754, 1, 3); + add(e2d, 911, 35, 754, 1, 4); + add(e2d, 911, 116, 754, 3, 0); + add(e2d, 911, 115, 754, 3, 1); + add(e2d, 911, 114, 754, 3, 2); + add(e2d, 911, 113, 754, 3, 3); + add(e2d, 911, 112, 754, 3, 4); + add(e2d, 911, 108, 754, 5, 0); + add(e2d, 911, 107, 754, 5, 1); + add(e2d, 911, 104, 754, 7, 0); + add(e2d, 911, 103, 754, 7, 1); + add(e2d, 911, 1039, 755, 0, 0); + add(e2d, 911, 1040, 755, 0, 1); + add(e2d, 911, 1041, 755, 0, 2); + add(e2d, 911, 1035, 755, 2, 0); + add(e2d, 911, 1036, 755, 2, 1); + add(e2d, 911, 1037, 755, 2, 2); + add(e2d, 911, 1038, 755, 2, 3); + add(e2d, 911, 1056, 755, 4, 0); + add(e2d, 911, 1057, 755, 4, 1); + add(e2d, 911, 1058, 755, 4, 2); + add(e2d, 911, 1052, 755, 6, 0); + add(e2d, 911, 1053, 755, 6, 1); + add(e2d, 911, 1054, 755, 6, 2); + add(e2d, 911, 1055, 755, 6, 3); + add(e2d, 911, 1067, 755, 1, 0); + add(e2d, 911, 1066, 755, 1, 1); + add(e2d, 911, 1065, 755, 1, 2); + add(e2d, 911, 1064, 755, 1, 3); + add(e2d, 911, 1133, 755, 3, 0); + add(e2d, 911, 1134, 755, 3, 1); + add(e2d, 911, 1135, 755, 3, 2); + add(e2d, 911, 1129, 755, 5, 0); + add(e2d, 911, 1130, 755, 5, 1); + add(e2d, 911, 1125, 755, 7, 0); + add(e2d, 911, 1126, 755, 7, 1); + add(e2d, 911, 313, 756, 0, 0); + add(e2d, 911, 314, 756, 0, 1); + add(e2d, 911, 315, 756, 0, 2); + add(e2d, 911, 316, 756, 0, 3); + add(e2d, 911, 317, 756, 0, 4); + add(e2d, 911, 308, 756, 2, 0); + add(e2d, 911, 309, 756, 2, 1); + add(e2d, 911, 310, 756, 2, 2); + add(e2d, 911, 311, 756, 2, 3); + add(e2d, 911, 312, 756, 2, 4); + add(e2d, 911, 330, 756, 4, 0); + add(e2d, 911, 331, 756, 4, 1); + add(e2d, 911, 332, 756, 4, 2); + add(e2d, 911, 333, 756, 4, 3); + add(e2d, 911, 334, 756, 4, 4); + add(e2d, 911, 325, 756, 6, 0); + add(e2d, 911, 326, 756, 6, 1); + add(e2d, 911, 327, 756, 6, 2); + add(e2d, 911, 328, 756, 6, 3); + add(e2d, 911, 329, 756, 6, 4); + add(e2d, 911, 338, 756, 1, 0); + add(e2d, 911, 339, 756, 1, 1); + add(e2d, 911, 340, 756, 1, 2); + add(e2d, 911, 341, 756, 1, 3); + add(e2d, 911, 342, 756, 1, 4); + add(e2d, 911, 211, 756, 3, 0); + add(e2d, 911, 212, 756, 3, 1); + add(e2d, 911, 213, 756, 3, 2); + add(e2d, 911, 214, 756, 3, 3); + add(e2d, 911, 215, 756, 3, 4); + add(e2d, 911, 206, 756, 5, 0); + add(e2d, 911, 207, 756, 5, 1); + add(e2d, 911, 208, 756, 5, 2); + add(e2d, 911, 201, 756, 7, 0); + add(e2d, 911, 202, 756, 7, 1); + add(e2d, 911, 203, 756, 7, 2); + add(e2d, 911, 1327, 757, 0, 0); + add(e2d, 911, 1326, 757, 0, 1); + add(e2d, 911, 1325, 757, 0, 2); + add(e2d, 911, 1331, 757, 2, 0); + add(e2d, 911, 1330, 757, 2, 1); + add(e2d, 911, 1329, 757, 2, 2); + add(e2d, 911, 1328, 757, 2, 3); + add(e2d, 911, 1344, 757, 4, 0); + add(e2d, 911, 1343, 757, 4, 1); + add(e2d, 911, 1342, 757, 4, 2); + add(e2d, 911, 1348, 757, 6, 0); + add(e2d, 911, 1347, 757, 6, 1); + add(e2d, 911, 1346, 757, 6, 2); + add(e2d, 911, 1345, 757, 6, 3); + add(e2d, 911, 1359, 757, 1, 0); + add(e2d, 911, 1360, 757, 1, 1); + add(e2d, 911, 1361, 757, 1, 2); + add(e2d, 911, 1243, 757, 3, 0); + add(e2d, 911, 1242, 757, 3, 1); + add(e2d, 911, 1241, 757, 3, 2); + add(e2d, 911, 1240, 757, 3, 3); + add(e2d, 911, 1234, 757, 5, 0); + add(e2d, 911, 1233, 757, 5, 1); + add(e2d, 911, 1229, 757, 7, 0); + add(e2d, 911, 1228, 757, 7, 1); + add(e2d, 912, 403, 696, 0, 0); + add(e2d, 912, 402, 696, 0, 1); + add(e2d, 912, 401, 696, 0, 2); + add(e2d, 912, 408, 696, 2, 0); + add(e2d, 912, 407, 696, 2, 1); + add(e2d, 912, 406, 696, 2, 2); + add(e2d, 912, 405, 696, 2, 3); + add(e2d, 912, 404, 696, 2, 4); + add(e2d, 912, 413, 696, 4, 0); + add(e2d, 912, 412, 696, 4, 1); + add(e2d, 912, 411, 696, 4, 2); + add(e2d, 912, 410, 696, 4, 3); + add(e2d, 912, 409, 696, 4, 4); + add(e2d, 912, 315, 696, 6, 0); + add(e2d, 912, 314, 696, 6, 1); + add(e2d, 912, 313, 696, 6, 2); + add(e2d, 912, 312, 696, 6, 3); + add(e2d, 912, 311, 696, 6, 4); + add(e2d, 912, 320, 696, 1, 0); + add(e2d, 912, 319, 696, 1, 1); + add(e2d, 912, 318, 696, 1, 2); + add(e2d, 912, 317, 696, 1, 3); + add(e2d, 912, 316, 696, 1, 4); + add(e2d, 912, 332, 696, 3, 0); + add(e2d, 912, 331, 696, 3, 1); + add(e2d, 912, 330, 696, 3, 2); + add(e2d, 912, 329, 696, 3, 3); + add(e2d, 912, 328, 696, 3, 4); + add(e2d, 912, 216, 696, 5, 0); + add(e2d, 912, 215, 696, 5, 1); + add(e2d, 912, 214, 696, 5, 2); + add(e2d, 912, 213, 696, 5, 3); + add(e2d, 912, 212, 696, 5, 4); + add(e2d, 912, 208, 696, 7, 0); + add(e2d, 912, 207, 696, 7, 1); + add(e2d, 912, 1329, 697, 0, 0); + add(e2d, 912, 1328, 697, 0, 1); + add(e2d, 912, 1327, 697, 0, 2); + add(e2d, 912, 1326, 697, 0, 3); + add(e2d, 912, 1325, 697, 0, 4); + add(e2d, 912, 1334, 697, 2, 0); + add(e2d, 912, 1333, 697, 2, 1); + add(e2d, 912, 1332, 697, 2, 2); + add(e2d, 912, 1331, 697, 2, 3); + add(e2d, 912, 1330, 697, 2, 4); + add(e2d, 912, 1345, 697, 4, 0); + add(e2d, 912, 1346, 697, 4, 1); + add(e2d, 912, 1347, 697, 4, 2); + add(e2d, 912, 1348, 697, 6, 0); + add(e2d, 912, 1349, 697, 6, 1); + add(e2d, 912, 1350, 697, 6, 2); + add(e2d, 912, 1351, 697, 6, 3); + add(e2d, 912, 1360, 697, 1, 0); + add(e2d, 912, 1359, 697, 1, 1); + add(e2d, 912, 1358, 697, 1, 2); + add(e2d, 912, 1357, 697, 1, 3); + add(e2d, 912, 1233, 697, 3, 0); + add(e2d, 912, 1234, 697, 3, 1); + add(e2d, 912, 1235, 697, 3, 2); + add(e2d, 912, 1229, 697, 5, 0); + add(e2d, 912, 1230, 697, 5, 1); + add(e2d, 912, 1225, 697, 7, 0); + add(e2d, 912, 1226, 697, 7, 1); + add(e2d, 912, 204, 698, 0, 0); + add(e2d, 912, 203, 698, 0, 1); + add(e2d, 912, 1, 698, 2, 0); + add(e2d, 912, 0, 698, 2, 1); + add(e2d, 912, 9, 698, 4, 0); + add(e2d, 912, 10, 698, 4, 1); + add(e2d, 912, 11, 698, 4, 2); + add(e2d, 912, 12, 698, 4, 3); + add(e2d, 912, 13, 698, 4, 4); + add(e2d, 912, 14, 698, 6, 0); + add(e2d, 912, 15, 698, 6, 1); + add(e2d, 912, 16, 698, 6, 2); + add(e2d, 912, 17, 698, 6, 3); + add(e2d, 912, 18, 698, 6, 4); + add(e2d, 912, 22, 698, 1, 0); + add(e2d, 912, 23, 698, 1, 1); + add(e2d, 912, 24, 698, 1, 2); + add(e2d, 912, 25, 698, 1, 3); + add(e2d, 912, 26, 698, 1, 4); + add(e2d, 912, 111, 698, 3, 0); + add(e2d, 912, 112, 698, 3, 1); + add(e2d, 912, 113, 698, 3, 2); + add(e2d, 912, 114, 698, 3, 3); + add(e2d, 912, 115, 698, 3, 4); + add(e2d, 912, 106, 698, 5, 0); + add(e2d, 912, 107, 698, 5, 1); + add(e2d, 912, 108, 698, 5, 2); + add(e2d, 912, 101, 698, 7, 0); + add(e2d, 912, 102, 698, 7, 1); + add(e2d, 912, 103, 698, 7, 2); + add(e2d, 912, 1028, 699, 0, 0); + add(e2d, 912, 1027, 699, 0, 1); + add(e2d, 912, 1026, 699, 0, 2); + add(e2d, 912, 1032, 699, 2, 0); + add(e2d, 912, 1031, 699, 2, 1); + add(e2d, 912, 1030, 699, 2, 2); + add(e2d, 912, 1029, 699, 2, 3); + add(e2d, 912, 1043, 699, 4, 0); + add(e2d, 912, 1044, 699, 4, 1); + add(e2d, 912, 1045, 699, 4, 2); + add(e2d, 912, 1143, 699, 1, 0); + add(e2d, 912, 1142, 699, 1, 1); + add(e2d, 912, 1141, 699, 1, 2); + add(e2d, 912, 1140, 699, 1, 3); + add(e2d, 912, 1134, 699, 3, 0); + add(e2d, 912, 1133, 699, 3, 1); + add(e2d, 912, 1129, 699, 5, 0); + add(e2d, 912, 1128, 699, 5, 1); + add(e2d, 913, 5, 700, 0, 0); + add(e2d, 913, 4, 700, 0, 1); + add(e2d, 913, 3, 700, 0, 2); + add(e2d, 913, 2, 700, 0, 3); + add(e2d, 913, 1, 700, 0, 4); + add(e2d, 913, 10, 700, 2, 0); + add(e2d, 913, 9, 700, 2, 1); + add(e2d, 913, 8, 700, 2, 2); + add(e2d, 913, 7, 700, 2, 3); + add(e2d, 913, 6, 700, 2, 4); + add(e2d, 913, 22, 700, 4, 0); + add(e2d, 913, 21, 700, 4, 1); + add(e2d, 913, 20, 700, 4, 2); + add(e2d, 913, 19, 700, 4, 3); + add(e2d, 913, 18, 700, 4, 4); + add(e2d, 913, 116, 700, 1, 0); + add(e2d, 913, 115, 700, 1, 1); + add(e2d, 913, 114, 700, 1, 2); + add(e2d, 913, 113, 700, 1, 3); + add(e2d, 913, 112, 700, 1, 4); + add(e2d, 913, 108, 700, 3, 0); + add(e2d, 913, 107, 700, 3, 1); + add(e2d, 913, 104, 700, 5, 0); + add(e2d, 913, 103, 700, 5, 1); + add(e2d, 913, 1039, 701, 0, 0); + add(e2d, 913, 1040, 701, 0, 1); + add(e2d, 913, 1041, 701, 0, 2); + add(e2d, 913, 1035, 701, 2, 0); + add(e2d, 913, 1036, 701, 2, 1); + add(e2d, 913, 1037, 701, 2, 2); + add(e2d, 913, 1038, 701, 2, 3); + add(e2d, 913, 1050, 701, 4, 0); + add(e2d, 913, 1049, 701, 4, 1); + add(e2d, 913, 1048, 701, 4, 2); + add(e2d, 913, 1047, 701, 4, 3); + add(e2d, 913, 1133, 701, 1, 0); + add(e2d, 913, 1134, 701, 1, 1); + add(e2d, 913, 1135, 701, 1, 2); + add(e2d, 913, 1129, 701, 3, 0); + add(e2d, 913, 1130, 701, 3, 1); + add(e2d, 913, 1125, 701, 5, 0); + add(e2d, 913, 1126, 701, 5, 1); + add(e2d, 913, 313, 704, 0, 0); + add(e2d, 913, 314, 704, 0, 1); + add(e2d, 913, 315, 704, 0, 2); + add(e2d, 913, 316, 704, 0, 3); + add(e2d, 913, 317, 704, 0, 4); + add(e2d, 913, 308, 704, 2, 0); + add(e2d, 913, 309, 704, 2, 1); + add(e2d, 913, 310, 704, 2, 2); + add(e2d, 913, 311, 704, 2, 3); + add(e2d, 913, 312, 704, 2, 4); + add(e2d, 913, 321, 704, 4, 0); + add(e2d, 913, 322, 704, 4, 1); + add(e2d, 913, 323, 704, 4, 2); + add(e2d, 913, 324, 704, 4, 3); + add(e2d, 913, 325, 704, 4, 4); + add(e2d, 913, 211, 704, 1, 0); + add(e2d, 913, 212, 704, 1, 1); + add(e2d, 913, 213, 704, 1, 2); + add(e2d, 913, 214, 704, 1, 3); + add(e2d, 913, 215, 704, 1, 4); + add(e2d, 913, 206, 704, 3, 0); + add(e2d, 913, 207, 704, 3, 1); + add(e2d, 913, 208, 704, 3, 2); + add(e2d, 913, 201, 704, 5, 0); + add(e2d, 913, 202, 704, 5, 1); + add(e2d, 913, 203, 704, 5, 2); + add(e2d, 913, 1327, 705, 0, 0); + add(e2d, 913, 1326, 705, 0, 1); + add(e2d, 913, 1325, 705, 0, 2); + add(e2d, 913, 1331, 705, 2, 0); + add(e2d, 913, 1330, 705, 2, 1); + add(e2d, 913, 1329, 705, 2, 2); + add(e2d, 913, 1328, 705, 2, 3); + add(e2d, 913, 1342, 705, 4, 0); + add(e2d, 913, 1343, 705, 4, 1); + add(e2d, 913, 1344, 705, 4, 2); + add(e2d, 913, 1243, 705, 1, 0); + add(e2d, 913, 1242, 705, 1, 1); + add(e2d, 913, 1241, 705, 1, 2); + add(e2d, 913, 1240, 705, 1, 3); + add(e2d, 913, 1234, 705, 3, 0); + add(e2d, 913, 1233, 705, 3, 1); + add(e2d, 913, 1229, 705, 5, 0); + add(e2d, 913, 1228, 705, 5, 1); + add(e2d, 914, 204, 706, 0, 0); + add(e2d, 914, 203, 706, 0, 1); + add(e2d, 914, 1, 706, 2, 0); + add(e2d, 914, 0, 706, 2, 1); + add(e2d, 914, 9, 706, 4, 0); + add(e2d, 914, 10, 706, 4, 1); + add(e2d, 914, 11, 706, 4, 2); + add(e2d, 914, 12, 706, 4, 3); + add(e2d, 914, 13, 706, 4, 4); + add(e2d, 914, 14, 706, 6, 0); + add(e2d, 914, 15, 706, 6, 1); + add(e2d, 914, 16, 706, 6, 2); + add(e2d, 914, 17, 706, 6, 3); + add(e2d, 914, 18, 706, 6, 4); + add(e2d, 914, 22, 706, 1, 0); + add(e2d, 914, 23, 706, 1, 1); + add(e2d, 914, 24, 706, 1, 2); + add(e2d, 914, 25, 706, 1, 3); + add(e2d, 914, 26, 706, 1, 4); + add(e2d, 914, 111, 706, 3, 0); + add(e2d, 914, 112, 706, 3, 1); + add(e2d, 914, 113, 706, 3, 2); + add(e2d, 914, 114, 706, 3, 3); + add(e2d, 914, 115, 706, 3, 4); + add(e2d, 914, 106, 706, 5, 0); + add(e2d, 914, 107, 706, 5, 1); + add(e2d, 914, 108, 706, 5, 2); + add(e2d, 914, 101, 706, 7, 0); + add(e2d, 914, 102, 706, 7, 1); + add(e2d, 914, 103, 706, 7, 2); + add(e2d, 914, 1028, 707, 0, 0); + add(e2d, 914, 1027, 707, 0, 1); + add(e2d, 914, 1026, 707, 0, 2); + add(e2d, 914, 1032, 707, 2, 0); + add(e2d, 914, 1031, 707, 2, 1); + add(e2d, 914, 1030, 707, 2, 2); + add(e2d, 914, 1029, 707, 2, 3); + add(e2d, 914, 1043, 707, 4, 0); + add(e2d, 914, 1044, 707, 4, 1); + add(e2d, 914, 1045, 707, 4, 2); + add(e2d, 914, 1143, 707, 1, 0); + add(e2d, 914, 1142, 707, 1, 1); + add(e2d, 914, 1141, 707, 1, 2); + add(e2d, 914, 1140, 707, 1, 3); + add(e2d, 914, 1134, 707, 3, 0); + add(e2d, 914, 1133, 707, 3, 1); + add(e2d, 914, 1129, 707, 5, 0); + add(e2d, 914, 1128, 707, 5, 1); + add(e2d, 914, 403, 708, 0, 0); + add(e2d, 914, 402, 708, 0, 1); + add(e2d, 914, 401, 708, 0, 2); + add(e2d, 914, 408, 708, 2, 0); + add(e2d, 914, 407, 708, 2, 1); + add(e2d, 914, 406, 708, 2, 2); + add(e2d, 914, 405, 708, 2, 3); + add(e2d, 914, 404, 708, 2, 4); + add(e2d, 914, 413, 708, 4, 0); + add(e2d, 914, 412, 708, 4, 1); + add(e2d, 914, 411, 708, 4, 2); + add(e2d, 914, 410, 708, 4, 3); + add(e2d, 914, 409, 708, 4, 4); + add(e2d, 914, 315, 708, 6, 0); + add(e2d, 914, 314, 708, 6, 1); + add(e2d, 914, 313, 708, 6, 2); + add(e2d, 914, 312, 708, 6, 3); + add(e2d, 914, 311, 708, 6, 4); + add(e2d, 914, 320, 708, 1, 0); + add(e2d, 914, 319, 708, 1, 1); + add(e2d, 914, 318, 708, 1, 2); + add(e2d, 914, 317, 708, 1, 3); + add(e2d, 914, 316, 708, 1, 4); + add(e2d, 914, 332, 708, 3, 0); + add(e2d, 914, 331, 708, 3, 1); + add(e2d, 914, 330, 708, 3, 2); + add(e2d, 914, 329, 708, 3, 3); + add(e2d, 914, 328, 708, 3, 4); + add(e2d, 914, 216, 708, 5, 0); + add(e2d, 914, 215, 708, 5, 1); + add(e2d, 914, 214, 708, 5, 2); + add(e2d, 914, 213, 708, 5, 3); + add(e2d, 914, 212, 708, 5, 4); + add(e2d, 914, 208, 708, 7, 0); + add(e2d, 914, 207, 708, 7, 1); + add(e2d, 914, 1329, 709, 0, 0); + add(e2d, 914, 1328, 709, 0, 1); + add(e2d, 914, 1327, 709, 0, 2); + add(e2d, 914, 1326, 709, 0, 3); + add(e2d, 914, 1325, 709, 0, 4); + add(e2d, 914, 1334, 709, 2, 0); + add(e2d, 914, 1333, 709, 2, 1); + add(e2d, 914, 1332, 709, 2, 2); + add(e2d, 914, 1331, 709, 2, 3); + add(e2d, 914, 1330, 709, 2, 4); + add(e2d, 914, 1345, 709, 4, 0); + add(e2d, 914, 1346, 709, 4, 1); + add(e2d, 914, 1347, 709, 4, 2); + add(e2d, 914, 1348, 709, 6, 0); + add(e2d, 914, 1349, 709, 6, 1); + add(e2d, 914, 1350, 709, 6, 2); + add(e2d, 914, 1351, 709, 6, 3); + add(e2d, 914, 1360, 709, 1, 0); + add(e2d, 914, 1359, 709, 1, 1); + add(e2d, 914, 1358, 709, 1, 2); + add(e2d, 914, 1357, 709, 1, 3); + add(e2d, 914, 1233, 709, 3, 0); + add(e2d, 914, 1234, 709, 3, 1); + add(e2d, 914, 1235, 709, 3, 2); + add(e2d, 914, 1229, 709, 5, 0); + add(e2d, 914, 1230, 709, 5, 1); + add(e2d, 914, 1225, 709, 7, 0); + add(e2d, 914, 1226, 709, 7, 1); + add(e2d, 915, 5, 632, 0, 0); + add(e2d, 915, 4, 632, 0, 1); + add(e2d, 915, 3, 632, 0, 2); + add(e2d, 915, 2, 632, 0, 3); + add(e2d, 915, 1, 632, 0, 4); + add(e2d, 915, 10, 632, 2, 0); + add(e2d, 915, 9, 632, 2, 1); + add(e2d, 915, 8, 632, 2, 2); + add(e2d, 915, 7, 632, 2, 3); + add(e2d, 915, 6, 632, 2, 4); + add(e2d, 915, 22, 632, 4, 0); + add(e2d, 915, 21, 632, 4, 1); + add(e2d, 915, 20, 632, 4, 2); + add(e2d, 915, 19, 632, 4, 3); + add(e2d, 915, 18, 632, 4, 4); + add(e2d, 915, 27, 632, 6, 0); + add(e2d, 915, 26, 632, 6, 1); + add(e2d, 915, 25, 632, 6, 2); + add(e2d, 915, 24, 632, 6, 3); + add(e2d, 915, 23, 632, 6, 4); + add(e2d, 915, 39, 632, 1, 0); + add(e2d, 915, 38, 632, 1, 1); + add(e2d, 915, 37, 632, 1, 2); + add(e2d, 915, 36, 632, 1, 3); + add(e2d, 915, 35, 632, 1, 4); + add(e2d, 915, 116, 632, 3, 0); + add(e2d, 915, 115, 632, 3, 1); + add(e2d, 915, 114, 632, 3, 2); + add(e2d, 915, 113, 632, 3, 3); + add(e2d, 915, 112, 632, 3, 4); + add(e2d, 915, 108, 632, 5, 0); + add(e2d, 915, 107, 632, 5, 1); + add(e2d, 915, 104, 632, 7, 0); + add(e2d, 915, 103, 632, 7, 1); + add(e2d, 915, 1039, 633, 0, 0); + add(e2d, 915, 1040, 633, 0, 1); + add(e2d, 915, 1041, 633, 0, 2); + add(e2d, 915, 1035, 633, 2, 0); + add(e2d, 915, 1036, 633, 2, 1); + add(e2d, 915, 1037, 633, 2, 2); + add(e2d, 915, 1038, 633, 2, 3); + add(e2d, 915, 1056, 633, 4, 0); + add(e2d, 915, 1057, 633, 4, 1); + add(e2d, 915, 1058, 633, 4, 2); + add(e2d, 915, 1052, 633, 6, 0); + add(e2d, 915, 1053, 633, 6, 1); + add(e2d, 915, 1054, 633, 6, 2); + add(e2d, 915, 1055, 633, 6, 3); + add(e2d, 915, 1067, 633, 1, 0); + add(e2d, 915, 1066, 633, 1, 1); + add(e2d, 915, 1065, 633, 1, 2); + add(e2d, 915, 1064, 633, 1, 3); + add(e2d, 915, 1133, 633, 3, 0); + add(e2d, 915, 1134, 633, 3, 1); + add(e2d, 915, 1135, 633, 3, 2); + add(e2d, 915, 1129, 633, 5, 0); + add(e2d, 915, 1130, 633, 5, 1); + add(e2d, 915, 1125, 633, 7, 0); + add(e2d, 915, 1126, 633, 7, 1); + add(e2d, 915, 313, 634, 0, 0); + add(e2d, 915, 314, 634, 0, 1); + add(e2d, 915, 315, 634, 0, 2); + add(e2d, 915, 316, 634, 0, 3); + add(e2d, 915, 317, 634, 0, 4); + add(e2d, 915, 308, 634, 2, 0); + add(e2d, 915, 309, 634, 2, 1); + add(e2d, 915, 310, 634, 2, 2); + add(e2d, 915, 311, 634, 2, 3); + add(e2d, 915, 312, 634, 2, 4); + add(e2d, 915, 330, 634, 4, 0); + add(e2d, 915, 331, 634, 4, 1); + add(e2d, 915, 332, 634, 4, 2); + add(e2d, 915, 333, 634, 4, 3); + add(e2d, 915, 334, 634, 4, 4); + add(e2d, 915, 325, 634, 6, 0); + add(e2d, 915, 326, 634, 6, 1); + add(e2d, 915, 327, 634, 6, 2); + add(e2d, 915, 328, 634, 6, 3); + add(e2d, 915, 329, 634, 6, 4); + add(e2d, 915, 338, 634, 1, 0); + add(e2d, 915, 339, 634, 1, 1); + add(e2d, 915, 340, 634, 1, 2); + add(e2d, 915, 341, 634, 1, 3); + add(e2d, 915, 342, 634, 1, 4); + add(e2d, 915, 211, 634, 3, 0); + add(e2d, 915, 212, 634, 3, 1); + add(e2d, 915, 213, 634, 3, 2); + add(e2d, 915, 214, 634, 3, 3); + add(e2d, 915, 215, 634, 3, 4); + add(e2d, 915, 206, 634, 5, 0); + add(e2d, 915, 207, 634, 5, 1); + add(e2d, 915, 208, 634, 5, 2); + add(e2d, 915, 201, 634, 7, 0); + add(e2d, 915, 202, 634, 7, 1); + add(e2d, 915, 203, 634, 7, 2); + add(e2d, 915, 1327, 635, 0, 0); + add(e2d, 915, 1326, 635, 0, 1); + add(e2d, 915, 1325, 635, 0, 2); + add(e2d, 915, 1331, 635, 2, 0); + add(e2d, 915, 1330, 635, 2, 1); + add(e2d, 915, 1329, 635, 2, 2); + add(e2d, 915, 1328, 635, 2, 3); + add(e2d, 915, 1344, 635, 4, 0); + add(e2d, 915, 1343, 635, 4, 1); + add(e2d, 915, 1342, 635, 4, 2); + add(e2d, 915, 1348, 635, 6, 0); + add(e2d, 915, 1347, 635, 6, 1); + add(e2d, 915, 1346, 635, 6, 2); + add(e2d, 915, 1345, 635, 6, 3); + add(e2d, 915, 1359, 635, 1, 0); + add(e2d, 915, 1360, 635, 1, 1); + add(e2d, 915, 1361, 635, 1, 2); + add(e2d, 915, 1243, 635, 3, 0); + add(e2d, 915, 1242, 635, 3, 1); + add(e2d, 915, 1241, 635, 3, 2); + add(e2d, 915, 1240, 635, 3, 3); + add(e2d, 915, 1234, 635, 5, 0); + add(e2d, 915, 1233, 635, 5, 1); + add(e2d, 915, 1229, 635, 7, 0); + add(e2d, 915, 1228, 635, 7, 1); + add(e2d, 916, 308, 636, 0, 0); + add(e2d, 916, 307, 636, 0, 1); + add(e2d, 916, 306, 636, 0, 2); + add(e2d, 916, 305, 636, 0, 3); + add(e2d, 916, 304, 636, 0, 4); + add(e2d, 916, 316, 636, 2, 0); + add(e2d, 916, 315, 636, 2, 1); + add(e2d, 916, 314, 636, 2, 2); + add(e2d, 916, 313, 636, 2, 3); + add(e2d, 916, 312, 636, 2, 4); + add(e2d, 916, 324, 636, 4, 0); + add(e2d, 916, 323, 636, 4, 1); + add(e2d, 916, 322, 636, 4, 2); + add(e2d, 916, 321, 636, 4, 3); + add(e2d, 916, 320, 636, 4, 4); + add(e2d, 916, 211, 636, 1, 0); + add(e2d, 916, 212, 636, 1, 1); + add(e2d, 916, 213, 636, 1, 2); + add(e2d, 916, 206, 636, 3, 0); + add(e2d, 916, 207, 636, 3, 1); + add(e2d, 916, 208, 636, 3, 2); + add(e2d, 916, 201, 636, 5, 0); + add(e2d, 916, 202, 636, 5, 1); + add(e2d, 916, 203, 636, 5, 2); + add(e2d, 916, 1325, 637, 0, 0); + add(e2d, 916, 1326, 637, 0, 1); + add(e2d, 916, 1327, 637, 0, 2); + add(e2d, 916, 1333, 637, 2, 0); + add(e2d, 916, 1334, 637, 2, 1); + add(e2d, 916, 1335, 637, 2, 2); + add(e2d, 916, 1341, 637, 4, 0); + add(e2d, 916, 1342, 637, 4, 1); + add(e2d, 916, 1343, 637, 4, 2); + add(e2d, 916, 1239, 637, 1, 0); + add(e2d, 916, 1238, 637, 1, 1); + add(e2d, 916, 1234, 637, 3, 0); + add(e2d, 916, 1233, 637, 3, 1); + add(e2d, 916, 1229, 637, 5, 0); + add(e2d, 916, 1228, 637, 5, 1); + add(e2d, 916, 1, 880, 0, 0); + add(e2d, 916, 2, 880, 0, 1); + add(e2d, 916, 3, 880, 0, 2); + add(e2d, 916, 4, 880, 0, 3); + add(e2d, 916, 5, 880, 0, 4); + add(e2d, 916, 10, 880, 2, 0); + add(e2d, 916, 11, 880, 2, 1); + add(e2d, 916, 12, 880, 2, 2); + add(e2d, 916, 13, 880, 2, 3); + add(e2d, 916, 14, 880, 2, 4); + add(e2d, 916, 19, 880, 4, 0); + add(e2d, 916, 20, 880, 4, 1); + add(e2d, 916, 21, 880, 4, 2); + add(e2d, 916, 22, 880, 4, 3); + add(e2d, 916, 23, 880, 4, 4); + add(e2d, 916, 112, 880, 1, 0); + add(e2d, 916, 111, 880, 1, 1); + add(e2d, 916, 108, 880, 3, 0); + add(e2d, 916, 107, 880, 3, 1); + add(e2d, 916, 103, 880, 5, 0); + add(e2d, 916, 104, 880, 5, 1); + add(e2d, 916, 1033, 881, 0, 0); + add(e2d, 916, 1032, 881, 0, 1); + add(e2d, 916, 1031, 881, 0, 2); + add(e2d, 916, 1030, 881, 0, 3); + add(e2d, 916, 1042, 881, 2, 0); + add(e2d, 916, 1041, 881, 2, 1); + add(e2d, 916, 1040, 881, 2, 2); + add(e2d, 916, 1039, 881, 2, 3); + add(e2d, 916, 1051, 881, 4, 0); + add(e2d, 916, 1050, 881, 4, 1); + add(e2d, 916, 1049, 881, 4, 2); + add(e2d, 916, 1048, 881, 4, 3); + add(e2d, 916, 1125, 881, 1, 0); + add(e2d, 916, 1126, 881, 1, 1); + add(e2d, 916, 1129, 881, 3, 0); + add(e2d, 916, 1130, 881, 3, 1); + add(e2d, 916, 1133, 881, 5, 0); + add(e2d, 916, 1134, 881, 5, 1); + add(e2d, 917, 1, 882, 0, 0); + add(e2d, 917, 2, 882, 0, 1); + add(e2d, 917, 3, 882, 0, 2); + add(e2d, 917, 4, 882, 0, 3); + add(e2d, 917, 5, 882, 0, 4); + add(e2d, 917, 10, 882, 2, 0); + add(e2d, 917, 11, 882, 2, 1); + add(e2d, 917, 12, 882, 2, 2); + add(e2d, 917, 13, 882, 2, 3); + add(e2d, 917, 14, 882, 2, 4); + add(e2d, 917, 112, 882, 4, 0); + add(e2d, 917, 111, 882, 4, 1); + add(e2d, 917, 108, 882, 1, 0); + add(e2d, 917, 107, 882, 1, 1); + add(e2d, 917, 104, 882, 3, 0); + add(e2d, 917, 103, 882, 3, 1); + add(e2d, 917, 1033, 883, 0, 0); + add(e2d, 917, 1032, 883, 0, 1); + add(e2d, 917, 1031, 883, 0, 2); + add(e2d, 917, 1030, 883, 0, 3); + add(e2d, 917, 1042, 883, 2, 0); + add(e2d, 917, 1041, 883, 2, 1); + add(e2d, 917, 1040, 883, 2, 2); + add(e2d, 917, 1039, 883, 2, 3); + add(e2d, 917, 1133, 883, 4, 0); + add(e2d, 917, 1134, 883, 4, 1); + add(e2d, 917, 1129, 883, 1, 0); + add(e2d, 917, 1130, 883, 1, 1); + add(e2d, 917, 1125, 883, 3, 0); + add(e2d, 917, 1126, 883, 3, 1); + add(e2d, 917, 308, 884, 0, 0); + add(e2d, 917, 307, 884, 0, 1); + add(e2d, 917, 306, 884, 0, 2); + add(e2d, 917, 305, 884, 0, 3); + add(e2d, 917, 304, 884, 0, 4); + add(e2d, 917, 316, 884, 2, 0); + add(e2d, 917, 315, 884, 2, 1); + add(e2d, 917, 314, 884, 2, 2); + add(e2d, 917, 313, 884, 2, 3); + add(e2d, 917, 312, 884, 2, 4); + add(e2d, 917, 211, 884, 4, 0); + add(e2d, 917, 212, 884, 4, 1); + add(e2d, 917, 213, 884, 4, 2); + add(e2d, 917, 206, 884, 1, 0); + add(e2d, 917, 207, 884, 1, 1); + add(e2d, 917, 208, 884, 1, 2); + add(e2d, 917, 201, 884, 3, 0); + add(e2d, 917, 202, 884, 3, 1); + add(e2d, 917, 203, 884, 3, 2); + add(e2d, 917, 1325, 885, 0, 0); + add(e2d, 917, 1326, 885, 0, 1); + add(e2d, 917, 1327, 885, 0, 2); + add(e2d, 917, 1333, 885, 2, 0); + add(e2d, 917, 1334, 885, 2, 1); + add(e2d, 917, 1335, 885, 2, 2); + add(e2d, 917, 1239, 885, 4, 0); + add(e2d, 917, 1238, 885, 4, 1); + add(e2d, 917, 1234, 885, 1, 0); + add(e2d, 917, 1233, 885, 1, 1); + add(e2d, 917, 1229, 885, 3, 0); + add(e2d, 917, 1228, 885, 3, 1); + add(e2d, 918, 304, 872, 0, 0); + add(e2d, 918, 303, 872, 0, 1); + add(e2d, 918, 211, 872, 2, 0); + add(e2d, 918, 212, 872, 2, 1); + add(e2d, 918, 213, 872, 2, 2); + add(e2d, 918, 206, 872, 4, 0); + add(e2d, 918, 207, 872, 4, 1); + add(e2d, 918, 208, 872, 4, 2); + add(e2d, 918, 201, 872, 6, 0); + add(e2d, 918, 202, 872, 6, 1); + add(e2d, 918, 203, 872, 6, 2); + add(e2d, 918, 1325, 872, 1, 0); + add(e2d, 918, 1326, 872, 1, 1); + add(e2d, 918, 1239, 872, 3, 0); + add(e2d, 918, 1238, 872, 3, 1); + add(e2d, 918, 1234, 872, 5, 0); + add(e2d, 918, 1233, 872, 5, 1); + add(e2d, 918, 1229, 872, 7, 0); + add(e2d, 918, 1228, 872, 7, 1); + add(e2d, 918, 1, 873, 0, 0); + add(e2d, 918, 2, 873, 0, 1); + add(e2d, 918, 3, 873, 0, 2); + add(e2d, 918, 112, 873, 2, 0); + add(e2d, 918, 111, 873, 2, 1); + add(e2d, 918, 108, 873, 4, 0); + add(e2d, 918, 107, 873, 4, 1); + add(e2d, 918, 104, 873, 6, 0); + add(e2d, 918, 103, 873, 6, 1); + add(e2d, 918, 1029, 873, 1, 0); + add(e2d, 918, 1028, 873, 1, 1); + add(e2d, 918, 1133, 873, 3, 0); + add(e2d, 918, 1134, 873, 3, 1); + add(e2d, 918, 1129, 873, 5, 0); + add(e2d, 918, 1130, 873, 5, 1); + add(e2d, 918, 1125, 873, 7, 0); + add(e2d, 918, 1126, 873, 7, 1); + add(e2d, 919, 12, 874, 0, 0); + add(e2d, 919, 11, 874, 0, 1); + add(e2d, 919, 8, 874, 2, 0); + add(e2d, 919, 7, 874, 2, 1); + add(e2d, 919, 4, 874, 4, 0); + add(e2d, 919, 3, 874, 4, 1); + add(e2d, 919, 1033, 874, 1, 0); + add(e2d, 919, 1034, 874, 1, 1); + add(e2d, 919, 1029, 874, 3, 0); + add(e2d, 919, 1030, 874, 3, 1); + add(e2d, 919, 1025, 874, 5, 0); + add(e2d, 919, 1026, 874, 5, 1); + add(e2d, 919, 111, 875, 0, 0); + add(e2d, 919, 112, 875, 0, 1); + add(e2d, 919, 113, 875, 0, 2); + add(e2d, 919, 106, 875, 2, 0); + add(e2d, 919, 107, 875, 2, 1); + add(e2d, 919, 108, 875, 2, 2); + add(e2d, 919, 101, 875, 4, 0); + add(e2d, 919, 102, 875, 4, 1); + add(e2d, 919, 103, 875, 4, 2); + add(e2d, 919, 1139, 875, 1, 0); + add(e2d, 919, 1138, 875, 1, 1); + add(e2d, 919, 1134, 875, 3, 0); + add(e2d, 919, 1133, 875, 3, 1); + add(e2d, 919, 1129, 875, 5, 0); + add(e2d, 919, 1128, 875, 5, 1); +} +void fillSolar2FeeLinkCH9L(std::map<uint16_t, uint32_t>& s2f) +{ + add_cru(s2f, 44, 0, 680); + add_cru(s2f, 44, 1, 681); + add_cru(s2f, 44, 2, 682); + add_cru(s2f, 44, 3, 683); + add_cru(s2f, 44, 6, 744); + add_cru(s2f, 44, 7, 745); + add_cru(s2f, 44, 8, 746); + add_cru(s2f, 44, 9, 747); + add_cru(s2f, 44, 10, 748); + add_cru(s2f, 44, 11, 749); + add_cru(s2f, 45, 0, 752); + add_cru(s2f, 45, 1, 753); + add_cru(s2f, 45, 2, 754); + add_cru(s2f, 45, 3, 755); + add_cru(s2f, 45, 4, 756); + add_cru(s2f, 45, 5, 757); + add_cru(s2f, 45, 6, 696); + add_cru(s2f, 45, 7, 697); + add_cru(s2f, 45, 8, 698); + add_cru(s2f, 45, 9, 699); + add_cru(s2f, 45, 10, 700); + add_cru(s2f, 45, 11, 701); + add_cru(s2f, 46, 0, 704); + add_cru(s2f, 46, 1, 705); + add_cru(s2f, 46, 2, 706); + add_cru(s2f, 46, 3, 707); + add_cru(s2f, 46, 4, 708); + add_cru(s2f, 46, 5, 709); + add_cru(s2f, 46, 6, 632); + add_cru(s2f, 46, 7, 633); + add_cru(s2f, 46, 8, 634); + add_cru(s2f, 46, 9, 635); + add_cru(s2f, 46, 10, 636); + add_cru(s2f, 46, 11, 637); + add_cru(s2f, 47, 0, 880); + add_cru(s2f, 47, 1, 881); + add_cru(s2f, 47, 2, 882); + add_cru(s2f, 47, 3, 883); + add_cru(s2f, 47, 4, 884); + add_cru(s2f, 47, 5, 885); + add_cru(s2f, 47, 6, 872); + add_cru(s2f, 47, 7, 873); + add_cru(s2f, 47, 8, 874); + add_cru(s2f, 47, 9, 875); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/CH9R.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/CH9R.cxx new file mode 100644 index 0000000000000..d8621eaa4679c --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/CH9R.cxx @@ -0,0 +1,1018 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// GENERATED CODE ! DO NOT EDIT ! +/// + +#include "CH.cxx" +void fillElec2DetCH9R(std::map<uint32_t, uint32_t>& e2d) +{ + add(e2d, 906, 12, 688, 0, 0); + add(e2d, 906, 11, 688, 0, 1); + add(e2d, 906, 8, 688, 2, 0); + add(e2d, 906, 7, 688, 2, 1); + add(e2d, 906, 4, 688, 4, 0); + add(e2d, 906, 3, 688, 4, 1); + add(e2d, 906, 1033, 688, 1, 0); + add(e2d, 906, 1034, 688, 1, 1); + add(e2d, 906, 1029, 688, 3, 0); + add(e2d, 906, 1030, 688, 3, 1); + add(e2d, 906, 1025, 688, 5, 0); + add(e2d, 906, 1026, 688, 5, 1); + add(e2d, 906, 111, 689, 0, 0); + add(e2d, 906, 112, 689, 0, 1); + add(e2d, 906, 113, 689, 0, 2); + add(e2d, 906, 106, 689, 2, 0); + add(e2d, 906, 107, 689, 2, 1); + add(e2d, 906, 108, 689, 2, 2); + add(e2d, 906, 101, 689, 4, 0); + add(e2d, 906, 102, 689, 4, 1); + add(e2d, 906, 103, 689, 4, 2); + add(e2d, 906, 1139, 689, 1, 0); + add(e2d, 906, 1138, 689, 1, 1); + add(e2d, 906, 1134, 689, 3, 0); + add(e2d, 906, 1133, 689, 3, 1); + add(e2d, 906, 1129, 689, 5, 0); + add(e2d, 906, 1128, 689, 5, 1); + add(e2d, 905, 304, 690, 0, 0); + add(e2d, 905, 303, 690, 0, 1); + add(e2d, 905, 211, 690, 2, 0); + add(e2d, 905, 212, 690, 2, 1); + add(e2d, 905, 213, 690, 2, 2); + add(e2d, 905, 206, 690, 4, 0); + add(e2d, 905, 207, 690, 4, 1); + add(e2d, 905, 208, 690, 4, 2); + add(e2d, 905, 201, 690, 6, 0); + add(e2d, 905, 202, 690, 6, 1); + add(e2d, 905, 203, 690, 6, 2); + add(e2d, 905, 1325, 690, 1, 0); + add(e2d, 905, 1326, 690, 1, 1); + add(e2d, 905, 1239, 690, 3, 0); + add(e2d, 905, 1238, 690, 3, 1); + add(e2d, 905, 1234, 690, 5, 0); + add(e2d, 905, 1233, 690, 5, 1); + add(e2d, 905, 1229, 690, 7, 0); + add(e2d, 905, 1228, 690, 7, 1); + add(e2d, 905, 1, 691, 0, 0); + add(e2d, 905, 2, 691, 0, 1); + add(e2d, 905, 3, 691, 0, 2); + add(e2d, 905, 112, 691, 2, 0); + add(e2d, 905, 111, 691, 2, 1); + add(e2d, 905, 108, 691, 4, 0); + add(e2d, 905, 107, 691, 4, 1); + add(e2d, 905, 104, 691, 6, 0); + add(e2d, 905, 103, 691, 6, 1); + add(e2d, 905, 1029, 691, 1, 0); + add(e2d, 905, 1028, 691, 1, 1); + add(e2d, 905, 1133, 691, 3, 0); + add(e2d, 905, 1134, 691, 3, 1); + add(e2d, 905, 1129, 691, 5, 0); + add(e2d, 905, 1130, 691, 5, 1); + add(e2d, 905, 1125, 691, 7, 0); + add(e2d, 905, 1126, 691, 7, 1); + add(e2d, 904, 1, 672, 0, 0); + add(e2d, 904, 2, 672, 0, 1); + add(e2d, 904, 3, 672, 0, 2); + add(e2d, 904, 4, 672, 0, 3); + add(e2d, 904, 5, 672, 0, 4); + add(e2d, 904, 10, 672, 2, 0); + add(e2d, 904, 11, 672, 2, 1); + add(e2d, 904, 12, 672, 2, 2); + add(e2d, 904, 13, 672, 2, 3); + add(e2d, 904, 14, 672, 2, 4); + add(e2d, 904, 112, 672, 4, 0); + add(e2d, 904, 111, 672, 4, 1); + add(e2d, 904, 108, 672, 1, 0); + add(e2d, 904, 107, 672, 1, 1); + add(e2d, 904, 104, 672, 3, 0); + add(e2d, 904, 103, 672, 3, 1); + add(e2d, 904, 1033, 673, 0, 0); + add(e2d, 904, 1032, 673, 0, 1); + add(e2d, 904, 1031, 673, 0, 2); + add(e2d, 904, 1030, 673, 0, 3); + add(e2d, 904, 1042, 673, 2, 0); + add(e2d, 904, 1041, 673, 2, 1); + add(e2d, 904, 1040, 673, 2, 2); + add(e2d, 904, 1039, 673, 2, 3); + add(e2d, 904, 1133, 673, 4, 0); + add(e2d, 904, 1134, 673, 4, 1); + add(e2d, 904, 1129, 673, 1, 0); + add(e2d, 904, 1130, 673, 1, 1); + add(e2d, 904, 1125, 673, 3, 0); + add(e2d, 904, 1126, 673, 3, 1); + add(e2d, 904, 308, 674, 0, 0); + add(e2d, 904, 307, 674, 0, 1); + add(e2d, 904, 306, 674, 0, 2); + add(e2d, 904, 305, 674, 0, 3); + add(e2d, 904, 304, 674, 0, 4); + add(e2d, 904, 316, 674, 2, 0); + add(e2d, 904, 315, 674, 2, 1); + add(e2d, 904, 314, 674, 2, 2); + add(e2d, 904, 313, 674, 2, 3); + add(e2d, 904, 312, 674, 2, 4); + add(e2d, 904, 211, 674, 4, 0); + add(e2d, 904, 212, 674, 4, 1); + add(e2d, 904, 213, 674, 4, 2); + add(e2d, 904, 206, 674, 1, 0); + add(e2d, 904, 207, 674, 1, 1); + add(e2d, 904, 208, 674, 1, 2); + add(e2d, 904, 201, 674, 3, 0); + add(e2d, 904, 202, 674, 3, 1); + add(e2d, 904, 203, 674, 3, 2); + add(e2d, 904, 1325, 675, 0, 0); + add(e2d, 904, 1326, 675, 0, 1); + add(e2d, 904, 1327, 675, 0, 2); + add(e2d, 904, 1333, 675, 2, 0); + add(e2d, 904, 1334, 675, 2, 1); + add(e2d, 904, 1335, 675, 2, 2); + add(e2d, 904, 1239, 675, 4, 0); + add(e2d, 904, 1238, 675, 4, 1); + add(e2d, 904, 1234, 675, 1, 0); + add(e2d, 904, 1233, 675, 1, 1); + add(e2d, 904, 1229, 675, 3, 0); + add(e2d, 904, 1228, 675, 3, 1); + add(e2d, 903, 308, 676, 0, 0); + add(e2d, 903, 307, 676, 0, 1); + add(e2d, 903, 306, 676, 0, 2); + add(e2d, 903, 305, 676, 0, 3); + add(e2d, 903, 304, 676, 0, 4); + add(e2d, 903, 316, 676, 2, 0); + add(e2d, 903, 315, 676, 2, 1); + add(e2d, 903, 314, 676, 2, 2); + add(e2d, 903, 313, 676, 2, 3); + add(e2d, 903, 312, 676, 2, 4); + add(e2d, 903, 324, 676, 4, 0); + add(e2d, 903, 323, 676, 4, 1); + add(e2d, 903, 322, 676, 4, 2); + add(e2d, 903, 321, 676, 4, 3); + add(e2d, 903, 320, 676, 4, 4); + add(e2d, 903, 211, 676, 1, 0); + add(e2d, 903, 212, 676, 1, 1); + add(e2d, 903, 213, 676, 1, 2); + add(e2d, 903, 206, 676, 3, 0); + add(e2d, 903, 207, 676, 3, 1); + add(e2d, 903, 208, 676, 3, 2); + add(e2d, 903, 201, 676, 5, 0); + add(e2d, 903, 202, 676, 5, 1); + add(e2d, 903, 203, 676, 5, 2); + add(e2d, 903, 1325, 677, 0, 0); + add(e2d, 903, 1326, 677, 0, 1); + add(e2d, 903, 1327, 677, 0, 2); + add(e2d, 903, 1333, 677, 2, 0); + add(e2d, 903, 1334, 677, 2, 1); + add(e2d, 903, 1335, 677, 2, 2); + add(e2d, 903, 1341, 677, 4, 0); + add(e2d, 903, 1342, 677, 4, 1); + add(e2d, 903, 1343, 677, 4, 2); + add(e2d, 903, 1239, 677, 1, 0); + add(e2d, 903, 1238, 677, 1, 1); + add(e2d, 903, 1234, 677, 3, 0); + add(e2d, 903, 1233, 677, 3, 1); + add(e2d, 903, 1229, 677, 5, 0); + add(e2d, 903, 1228, 677, 5, 1); + add(e2d, 903, 1, 560, 0, 0); + add(e2d, 903, 2, 560, 0, 1); + add(e2d, 903, 3, 560, 0, 2); + add(e2d, 903, 4, 560, 0, 3); + add(e2d, 903, 5, 560, 0, 4); + add(e2d, 903, 10, 560, 2, 0); + add(e2d, 903, 11, 560, 2, 1); + add(e2d, 903, 12, 560, 2, 2); + add(e2d, 903, 13, 560, 2, 3); + add(e2d, 903, 14, 560, 2, 4); + add(e2d, 903, 19, 560, 4, 0); + add(e2d, 903, 20, 560, 4, 1); + add(e2d, 903, 21, 560, 4, 2); + add(e2d, 903, 22, 560, 4, 3); + add(e2d, 903, 23, 560, 4, 4); + add(e2d, 903, 112, 560, 1, 0); + add(e2d, 903, 111, 560, 1, 1); + add(e2d, 903, 108, 560, 3, 0); + add(e2d, 903, 107, 560, 3, 1); + add(e2d, 903, 103, 560, 5, 0); + add(e2d, 903, 104, 560, 5, 1); + add(e2d, 903, 1033, 561, 0, 0); + add(e2d, 903, 1032, 561, 0, 1); + add(e2d, 903, 1031, 561, 0, 2); + add(e2d, 903, 1030, 561, 0, 3); + add(e2d, 903, 1042, 561, 2, 0); + add(e2d, 903, 1041, 561, 2, 1); + add(e2d, 903, 1040, 561, 2, 2); + add(e2d, 903, 1039, 561, 2, 3); + add(e2d, 903, 1051, 561, 4, 0); + add(e2d, 903, 1050, 561, 4, 1); + add(e2d, 903, 1049, 561, 4, 2); + add(e2d, 903, 1048, 561, 4, 3); + add(e2d, 903, 1125, 561, 1, 0); + add(e2d, 903, 1126, 561, 1, 1); + add(e2d, 903, 1129, 561, 3, 0); + add(e2d, 903, 1130, 561, 3, 1); + add(e2d, 903, 1133, 561, 5, 0); + add(e2d, 903, 1134, 561, 5, 1); + add(e2d, 902, 5, 562, 0, 0); + add(e2d, 902, 4, 562, 0, 1); + add(e2d, 902, 3, 562, 0, 2); + add(e2d, 902, 2, 562, 0, 3); + add(e2d, 902, 1, 562, 0, 4); + add(e2d, 902, 10, 562, 2, 0); + add(e2d, 902, 9, 562, 2, 1); + add(e2d, 902, 8, 562, 2, 2); + add(e2d, 902, 7, 562, 2, 3); + add(e2d, 902, 6, 562, 2, 4); + add(e2d, 902, 22, 562, 4, 0); + add(e2d, 902, 21, 562, 4, 1); + add(e2d, 902, 20, 562, 4, 2); + add(e2d, 902, 19, 562, 4, 3); + add(e2d, 902, 18, 562, 4, 4); + add(e2d, 902, 27, 562, 6, 0); + add(e2d, 902, 26, 562, 6, 1); + add(e2d, 902, 25, 562, 6, 2); + add(e2d, 902, 24, 562, 6, 3); + add(e2d, 902, 23, 562, 6, 4); + add(e2d, 902, 39, 562, 1, 0); + add(e2d, 902, 38, 562, 1, 1); + add(e2d, 902, 37, 562, 1, 2); + add(e2d, 902, 36, 562, 1, 3); + add(e2d, 902, 35, 562, 1, 4); + add(e2d, 902, 116, 562, 3, 0); + add(e2d, 902, 115, 562, 3, 1); + add(e2d, 902, 114, 562, 3, 2); + add(e2d, 902, 113, 562, 3, 3); + add(e2d, 902, 112, 562, 3, 4); + add(e2d, 902, 108, 562, 5, 0); + add(e2d, 902, 107, 562, 5, 1); + add(e2d, 902, 104, 562, 7, 0); + add(e2d, 902, 103, 562, 7, 1); + add(e2d, 902, 1039, 563, 0, 0); + add(e2d, 902, 1040, 563, 0, 1); + add(e2d, 902, 1041, 563, 0, 2); + add(e2d, 902, 1035, 563, 2, 0); + add(e2d, 902, 1036, 563, 2, 1); + add(e2d, 902, 1037, 563, 2, 2); + add(e2d, 902, 1038, 563, 2, 3); + add(e2d, 902, 1056, 563, 4, 0); + add(e2d, 902, 1057, 563, 4, 1); + add(e2d, 902, 1058, 563, 4, 2); + add(e2d, 902, 1052, 563, 6, 0); + add(e2d, 902, 1053, 563, 6, 1); + add(e2d, 902, 1054, 563, 6, 2); + add(e2d, 902, 1055, 563, 6, 3); + add(e2d, 902, 1067, 563, 1, 0); + add(e2d, 902, 1066, 563, 1, 1); + add(e2d, 902, 1065, 563, 1, 2); + add(e2d, 902, 1064, 563, 1, 3); + add(e2d, 902, 1133, 563, 3, 0); + add(e2d, 902, 1134, 563, 3, 1); + add(e2d, 902, 1135, 563, 3, 2); + add(e2d, 902, 1129, 563, 5, 0); + add(e2d, 902, 1130, 563, 5, 1); + add(e2d, 902, 1125, 563, 7, 0); + add(e2d, 902, 1126, 563, 7, 1); + add(e2d, 902, 313, 564, 0, 0); + add(e2d, 902, 314, 564, 0, 1); + add(e2d, 902, 315, 564, 0, 2); + add(e2d, 902, 316, 564, 0, 3); + add(e2d, 902, 317, 564, 0, 4); + add(e2d, 902, 308, 564, 2, 0); + add(e2d, 902, 309, 564, 2, 1); + add(e2d, 902, 310, 564, 2, 2); + add(e2d, 902, 311, 564, 2, 3); + add(e2d, 902, 312, 564, 2, 4); + add(e2d, 902, 330, 564, 4, 0); + add(e2d, 902, 331, 564, 4, 1); + add(e2d, 902, 332, 564, 4, 2); + add(e2d, 902, 333, 564, 4, 3); + add(e2d, 902, 334, 564, 4, 4); + add(e2d, 902, 325, 564, 6, 0); + add(e2d, 902, 326, 564, 6, 1); + add(e2d, 902, 327, 564, 6, 2); + add(e2d, 902, 328, 564, 6, 3); + add(e2d, 902, 329, 564, 6, 4); + add(e2d, 902, 338, 564, 1, 0); + add(e2d, 902, 339, 564, 1, 1); + add(e2d, 902, 340, 564, 1, 2); + add(e2d, 902, 341, 564, 1, 3); + add(e2d, 902, 342, 564, 1, 4); + add(e2d, 902, 211, 564, 3, 0); + add(e2d, 902, 212, 564, 3, 1); + add(e2d, 902, 213, 564, 3, 2); + add(e2d, 902, 214, 564, 3, 3); + add(e2d, 902, 215, 564, 3, 4); + add(e2d, 902, 206, 564, 5, 0); + add(e2d, 902, 207, 564, 5, 1); + add(e2d, 902, 208, 564, 5, 2); + add(e2d, 902, 201, 564, 7, 0); + add(e2d, 902, 202, 564, 7, 1); + add(e2d, 902, 203, 564, 7, 2); + add(e2d, 902, 1327, 565, 0, 0); + add(e2d, 902, 1326, 565, 0, 1); + add(e2d, 902, 1325, 565, 0, 2); + add(e2d, 902, 1331, 565, 2, 0); + add(e2d, 902, 1330, 565, 2, 1); + add(e2d, 902, 1329, 565, 2, 2); + add(e2d, 902, 1328, 565, 2, 3); + add(e2d, 902, 1344, 565, 4, 0); + add(e2d, 902, 1343, 565, 4, 1); + add(e2d, 902, 1342, 565, 4, 2); + add(e2d, 902, 1348, 565, 6, 0); + add(e2d, 902, 1347, 565, 6, 1); + add(e2d, 902, 1346, 565, 6, 2); + add(e2d, 902, 1345, 565, 6, 3); + add(e2d, 902, 1359, 565, 1, 0); + add(e2d, 902, 1360, 565, 1, 1); + add(e2d, 902, 1361, 565, 1, 2); + add(e2d, 902, 1243, 565, 3, 0); + add(e2d, 902, 1242, 565, 3, 1); + add(e2d, 902, 1241, 565, 3, 2); + add(e2d, 902, 1240, 565, 3, 3); + add(e2d, 902, 1234, 565, 5, 0); + add(e2d, 902, 1233, 565, 5, 1); + add(e2d, 902, 1229, 565, 7, 0); + add(e2d, 902, 1228, 565, 7, 1); + add(e2d, 901, 403, 568, 0, 0); + add(e2d, 901, 402, 568, 0, 1); + add(e2d, 901, 401, 568, 0, 2); + add(e2d, 901, 408, 568, 2, 0); + add(e2d, 901, 407, 568, 2, 1); + add(e2d, 901, 406, 568, 2, 2); + add(e2d, 901, 405, 568, 2, 3); + add(e2d, 901, 404, 568, 2, 4); + add(e2d, 901, 413, 568, 4, 0); + add(e2d, 901, 412, 568, 4, 1); + add(e2d, 901, 411, 568, 4, 2); + add(e2d, 901, 410, 568, 4, 3); + add(e2d, 901, 409, 568, 4, 4); + add(e2d, 901, 315, 568, 6, 0); + add(e2d, 901, 314, 568, 6, 1); + add(e2d, 901, 313, 568, 6, 2); + add(e2d, 901, 312, 568, 6, 3); + add(e2d, 901, 311, 568, 6, 4); + add(e2d, 901, 320, 568, 1, 0); + add(e2d, 901, 319, 568, 1, 1); + add(e2d, 901, 318, 568, 1, 2); + add(e2d, 901, 317, 568, 1, 3); + add(e2d, 901, 316, 568, 1, 4); + add(e2d, 901, 332, 568, 3, 0); + add(e2d, 901, 331, 568, 3, 1); + add(e2d, 901, 330, 568, 3, 2); + add(e2d, 901, 329, 568, 3, 3); + add(e2d, 901, 328, 568, 3, 4); + add(e2d, 901, 216, 568, 5, 0); + add(e2d, 901, 215, 568, 5, 1); + add(e2d, 901, 214, 568, 5, 2); + add(e2d, 901, 213, 568, 5, 3); + add(e2d, 901, 212, 568, 5, 4); + add(e2d, 901, 208, 568, 7, 0); + add(e2d, 901, 207, 568, 7, 1); + add(e2d, 901, 1329, 569, 0, 0); + add(e2d, 901, 1328, 569, 0, 1); + add(e2d, 901, 1327, 569, 0, 2); + add(e2d, 901, 1326, 569, 0, 3); + add(e2d, 901, 1325, 569, 0, 4); + add(e2d, 901, 1334, 569, 2, 0); + add(e2d, 901, 1333, 569, 2, 1); + add(e2d, 901, 1332, 569, 2, 2); + add(e2d, 901, 1331, 569, 2, 3); + add(e2d, 901, 1330, 569, 2, 4); + add(e2d, 901, 1345, 569, 4, 0); + add(e2d, 901, 1346, 569, 4, 1); + add(e2d, 901, 1347, 569, 4, 2); + add(e2d, 901, 1348, 569, 6, 0); + add(e2d, 901, 1349, 569, 6, 1); + add(e2d, 901, 1350, 569, 6, 2); + add(e2d, 901, 1351, 569, 6, 3); + add(e2d, 901, 1360, 569, 1, 0); + add(e2d, 901, 1359, 569, 1, 1); + add(e2d, 901, 1358, 569, 1, 2); + add(e2d, 901, 1357, 569, 1, 3); + add(e2d, 901, 1233, 569, 3, 0); + add(e2d, 901, 1234, 569, 3, 1); + add(e2d, 901, 1235, 569, 3, 2); + add(e2d, 901, 1229, 569, 5, 0); + add(e2d, 901, 1230, 569, 5, 1); + add(e2d, 901, 1225, 569, 7, 0); + add(e2d, 901, 1226, 569, 7, 1); + add(e2d, 901, 204, 570, 0, 0); + add(e2d, 901, 203, 570, 0, 1); + add(e2d, 901, 1, 570, 2, 0); + add(e2d, 901, 0, 570, 2, 1); + add(e2d, 901, 9, 570, 4, 0); + add(e2d, 901, 10, 570, 4, 1); + add(e2d, 901, 11, 570, 4, 2); + add(e2d, 901, 12, 570, 4, 3); + add(e2d, 901, 13, 570, 4, 4); + add(e2d, 901, 14, 570, 6, 0); + add(e2d, 901, 15, 570, 6, 1); + add(e2d, 901, 16, 570, 6, 2); + add(e2d, 901, 17, 570, 6, 3); + add(e2d, 901, 18, 570, 6, 4); + add(e2d, 901, 22, 570, 1, 0); + add(e2d, 901, 23, 570, 1, 1); + add(e2d, 901, 24, 570, 1, 2); + add(e2d, 901, 25, 570, 1, 3); + add(e2d, 901, 26, 570, 1, 4); + add(e2d, 901, 111, 570, 3, 0); + add(e2d, 901, 112, 570, 3, 1); + add(e2d, 901, 113, 570, 3, 2); + add(e2d, 901, 114, 570, 3, 3); + add(e2d, 901, 115, 570, 3, 4); + add(e2d, 901, 106, 570, 5, 0); + add(e2d, 901, 107, 570, 5, 1); + add(e2d, 901, 108, 570, 5, 2); + add(e2d, 901, 101, 570, 7, 0); + add(e2d, 901, 102, 570, 7, 1); + add(e2d, 901, 103, 570, 7, 2); + add(e2d, 901, 1028, 571, 0, 0); + add(e2d, 901, 1027, 571, 0, 1); + add(e2d, 901, 1026, 571, 0, 2); + add(e2d, 901, 1032, 571, 2, 0); + add(e2d, 901, 1031, 571, 2, 1); + add(e2d, 901, 1030, 571, 2, 2); + add(e2d, 901, 1029, 571, 2, 3); + add(e2d, 901, 1043, 571, 4, 0); + add(e2d, 901, 1044, 571, 4, 1); + add(e2d, 901, 1045, 571, 4, 2); + add(e2d, 901, 1143, 571, 1, 0); + add(e2d, 901, 1142, 571, 1, 1); + add(e2d, 901, 1141, 571, 1, 2); + add(e2d, 901, 1140, 571, 1, 3); + add(e2d, 901, 1134, 571, 3, 0); + add(e2d, 901, 1133, 571, 3, 1); + add(e2d, 901, 1129, 571, 5, 0); + add(e2d, 901, 1128, 571, 5, 1); + add(e2d, 900, 5, 572, 0, 0); + add(e2d, 900, 4, 572, 0, 1); + add(e2d, 900, 3, 572, 0, 2); + add(e2d, 900, 2, 572, 0, 3); + add(e2d, 900, 1, 572, 0, 4); + add(e2d, 900, 10, 572, 2, 0); + add(e2d, 900, 9, 572, 2, 1); + add(e2d, 900, 8, 572, 2, 2); + add(e2d, 900, 7, 572, 2, 3); + add(e2d, 900, 6, 572, 2, 4); + add(e2d, 900, 22, 572, 4, 0); + add(e2d, 900, 21, 572, 4, 1); + add(e2d, 900, 20, 572, 4, 2); + add(e2d, 900, 19, 572, 4, 3); + add(e2d, 900, 18, 572, 4, 4); + add(e2d, 900, 116, 572, 1, 0); + add(e2d, 900, 115, 572, 1, 1); + add(e2d, 900, 114, 572, 1, 2); + add(e2d, 900, 113, 572, 1, 3); + add(e2d, 900, 112, 572, 1, 4); + add(e2d, 900, 108, 572, 3, 0); + add(e2d, 900, 107, 572, 3, 1); + add(e2d, 900, 104, 572, 5, 0); + add(e2d, 900, 103, 572, 5, 1); + add(e2d, 900, 1039, 573, 0, 0); + add(e2d, 900, 1040, 573, 0, 1); + add(e2d, 900, 1041, 573, 0, 2); + add(e2d, 900, 1035, 573, 2, 0); + add(e2d, 900, 1036, 573, 2, 1); + add(e2d, 900, 1037, 573, 2, 2); + add(e2d, 900, 1038, 573, 2, 3); + add(e2d, 900, 1050, 573, 4, 0); + add(e2d, 900, 1049, 573, 4, 1); + add(e2d, 900, 1048, 573, 4, 2); + add(e2d, 900, 1047, 573, 4, 3); + add(e2d, 900, 1133, 573, 1, 0); + add(e2d, 900, 1134, 573, 1, 1); + add(e2d, 900, 1135, 573, 1, 2); + add(e2d, 900, 1129, 573, 3, 0); + add(e2d, 900, 1130, 573, 3, 1); + add(e2d, 900, 1125, 573, 5, 0); + add(e2d, 900, 1126, 573, 5, 1); + add(e2d, 900, 313, 608, 0, 0); + add(e2d, 900, 314, 608, 0, 1); + add(e2d, 900, 315, 608, 0, 2); + add(e2d, 900, 316, 608, 0, 3); + add(e2d, 900, 317, 608, 0, 4); + add(e2d, 900, 308, 608, 2, 0); + add(e2d, 900, 309, 608, 2, 1); + add(e2d, 900, 310, 608, 2, 2); + add(e2d, 900, 311, 608, 2, 3); + add(e2d, 900, 312, 608, 2, 4); + add(e2d, 900, 321, 608, 4, 0); + add(e2d, 900, 322, 608, 4, 1); + add(e2d, 900, 323, 608, 4, 2); + add(e2d, 900, 324, 608, 4, 3); + add(e2d, 900, 325, 608, 4, 4); + add(e2d, 900, 211, 608, 1, 0); + add(e2d, 900, 212, 608, 1, 1); + add(e2d, 900, 213, 608, 1, 2); + add(e2d, 900, 214, 608, 1, 3); + add(e2d, 900, 215, 608, 1, 4); + add(e2d, 900, 206, 608, 3, 0); + add(e2d, 900, 207, 608, 3, 1); + add(e2d, 900, 208, 608, 3, 2); + add(e2d, 900, 201, 608, 5, 0); + add(e2d, 900, 202, 608, 5, 1); + add(e2d, 900, 203, 608, 5, 2); + add(e2d, 900, 1327, 609, 0, 0); + add(e2d, 900, 1326, 609, 0, 1); + add(e2d, 900, 1325, 609, 0, 2); + add(e2d, 900, 1331, 609, 2, 0); + add(e2d, 900, 1330, 609, 2, 1); + add(e2d, 900, 1329, 609, 2, 2); + add(e2d, 900, 1328, 609, 2, 3); + add(e2d, 900, 1342, 609, 4, 0); + add(e2d, 900, 1343, 609, 4, 1); + add(e2d, 900, 1344, 609, 4, 2); + add(e2d, 900, 1243, 609, 1, 0); + add(e2d, 900, 1242, 609, 1, 1); + add(e2d, 900, 1241, 609, 1, 2); + add(e2d, 900, 1240, 609, 1, 3); + add(e2d, 900, 1234, 609, 3, 0); + add(e2d, 900, 1233, 609, 3, 1); + add(e2d, 900, 1229, 609, 5, 0); + add(e2d, 900, 1228, 609, 5, 1); + add(e2d, 925, 204, 610, 0, 0); + add(e2d, 925, 203, 610, 0, 1); + add(e2d, 925, 1, 610, 2, 0); + add(e2d, 925, 0, 610, 2, 1); + add(e2d, 925, 9, 610, 4, 0); + add(e2d, 925, 10, 610, 4, 1); + add(e2d, 925, 11, 610, 4, 2); + add(e2d, 925, 12, 610, 4, 3); + add(e2d, 925, 13, 610, 4, 4); + add(e2d, 925, 14, 610, 6, 0); + add(e2d, 925, 15, 610, 6, 1); + add(e2d, 925, 16, 610, 6, 2); + add(e2d, 925, 17, 610, 6, 3); + add(e2d, 925, 18, 610, 6, 4); + add(e2d, 925, 22, 610, 1, 0); + add(e2d, 925, 23, 610, 1, 1); + add(e2d, 925, 24, 610, 1, 2); + add(e2d, 925, 25, 610, 1, 3); + add(e2d, 925, 26, 610, 1, 4); + add(e2d, 925, 111, 610, 3, 0); + add(e2d, 925, 112, 610, 3, 1); + add(e2d, 925, 113, 610, 3, 2); + add(e2d, 925, 114, 610, 3, 3); + add(e2d, 925, 115, 610, 3, 4); + add(e2d, 925, 106, 610, 5, 0); + add(e2d, 925, 107, 610, 5, 1); + add(e2d, 925, 108, 610, 5, 2); + add(e2d, 925, 101, 610, 7, 0); + add(e2d, 925, 102, 610, 7, 1); + add(e2d, 925, 103, 610, 7, 2); + add(e2d, 925, 1028, 611, 0, 0); + add(e2d, 925, 1027, 611, 0, 1); + add(e2d, 925, 1026, 611, 0, 2); + add(e2d, 925, 1032, 611, 2, 0); + add(e2d, 925, 1031, 611, 2, 1); + add(e2d, 925, 1030, 611, 2, 2); + add(e2d, 925, 1029, 611, 2, 3); + add(e2d, 925, 1043, 611, 4, 0); + add(e2d, 925, 1044, 611, 4, 1); + add(e2d, 925, 1045, 611, 4, 2); + add(e2d, 925, 1143, 611, 1, 0); + add(e2d, 925, 1142, 611, 1, 1); + add(e2d, 925, 1141, 611, 1, 2); + add(e2d, 925, 1140, 611, 1, 3); + add(e2d, 925, 1134, 611, 3, 0); + add(e2d, 925, 1133, 611, 3, 1); + add(e2d, 925, 1129, 611, 5, 0); + add(e2d, 925, 1128, 611, 5, 1); + add(e2d, 925, 403, 612, 0, 0); + add(e2d, 925, 402, 612, 0, 1); + add(e2d, 925, 401, 612, 0, 2); + add(e2d, 925, 408, 612, 2, 0); + add(e2d, 925, 407, 612, 2, 1); + add(e2d, 925, 406, 612, 2, 2); + add(e2d, 925, 405, 612, 2, 3); + add(e2d, 925, 404, 612, 2, 4); + add(e2d, 925, 413, 612, 4, 0); + add(e2d, 925, 412, 612, 4, 1); + add(e2d, 925, 411, 612, 4, 2); + add(e2d, 925, 410, 612, 4, 3); + add(e2d, 925, 409, 612, 4, 4); + add(e2d, 925, 315, 612, 6, 0); + add(e2d, 925, 314, 612, 6, 1); + add(e2d, 925, 313, 612, 6, 2); + add(e2d, 925, 312, 612, 6, 3); + add(e2d, 925, 311, 612, 6, 4); + add(e2d, 925, 320, 612, 1, 0); + add(e2d, 925, 319, 612, 1, 1); + add(e2d, 925, 318, 612, 1, 2); + add(e2d, 925, 317, 612, 1, 3); + add(e2d, 925, 316, 612, 1, 4); + add(e2d, 925, 332, 612, 3, 0); + add(e2d, 925, 331, 612, 3, 1); + add(e2d, 925, 330, 612, 3, 2); + add(e2d, 925, 329, 612, 3, 3); + add(e2d, 925, 328, 612, 3, 4); + add(e2d, 925, 216, 612, 5, 0); + add(e2d, 925, 215, 612, 5, 1); + add(e2d, 925, 214, 612, 5, 2); + add(e2d, 925, 213, 612, 5, 3); + add(e2d, 925, 212, 612, 5, 4); + add(e2d, 925, 208, 612, 7, 0); + add(e2d, 925, 207, 612, 7, 1); + add(e2d, 925, 1329, 613, 0, 0); + add(e2d, 925, 1328, 613, 0, 1); + add(e2d, 925, 1327, 613, 0, 2); + add(e2d, 925, 1326, 613, 0, 3); + add(e2d, 925, 1325, 613, 0, 4); + add(e2d, 925, 1334, 613, 2, 0); + add(e2d, 925, 1333, 613, 2, 1); + add(e2d, 925, 1332, 613, 2, 2); + add(e2d, 925, 1331, 613, 2, 3); + add(e2d, 925, 1330, 613, 2, 4); + add(e2d, 925, 1345, 613, 4, 0); + add(e2d, 925, 1346, 613, 4, 1); + add(e2d, 925, 1347, 613, 4, 2); + add(e2d, 925, 1348, 613, 6, 0); + add(e2d, 925, 1349, 613, 6, 1); + add(e2d, 925, 1350, 613, 6, 2); + add(e2d, 925, 1351, 613, 6, 3); + add(e2d, 925, 1360, 613, 1, 0); + add(e2d, 925, 1359, 613, 1, 1); + add(e2d, 925, 1358, 613, 1, 2); + add(e2d, 925, 1357, 613, 1, 3); + add(e2d, 925, 1233, 613, 3, 0); + add(e2d, 925, 1234, 613, 3, 1); + add(e2d, 925, 1235, 613, 3, 2); + add(e2d, 925, 1229, 613, 5, 0); + add(e2d, 925, 1230, 613, 5, 1); + add(e2d, 925, 1225, 613, 7, 0); + add(e2d, 925, 1226, 613, 7, 1); + add(e2d, 924, 5, 616, 0, 0); + add(e2d, 924, 4, 616, 0, 1); + add(e2d, 924, 3, 616, 0, 2); + add(e2d, 924, 2, 616, 0, 3); + add(e2d, 924, 1, 616, 0, 4); + add(e2d, 924, 10, 616, 2, 0); + add(e2d, 924, 9, 616, 2, 1); + add(e2d, 924, 8, 616, 2, 2); + add(e2d, 924, 7, 616, 2, 3); + add(e2d, 924, 6, 616, 2, 4); + add(e2d, 924, 22, 616, 4, 0); + add(e2d, 924, 21, 616, 4, 1); + add(e2d, 924, 20, 616, 4, 2); + add(e2d, 924, 19, 616, 4, 3); + add(e2d, 924, 18, 616, 4, 4); + add(e2d, 924, 27, 616, 6, 0); + add(e2d, 924, 26, 616, 6, 1); + add(e2d, 924, 25, 616, 6, 2); + add(e2d, 924, 24, 616, 6, 3); + add(e2d, 924, 23, 616, 6, 4); + add(e2d, 924, 39, 616, 1, 0); + add(e2d, 924, 38, 616, 1, 1); + add(e2d, 924, 37, 616, 1, 2); + add(e2d, 924, 36, 616, 1, 3); + add(e2d, 924, 35, 616, 1, 4); + add(e2d, 924, 116, 616, 3, 0); + add(e2d, 924, 115, 616, 3, 1); + add(e2d, 924, 114, 616, 3, 2); + add(e2d, 924, 113, 616, 3, 3); + add(e2d, 924, 112, 616, 3, 4); + add(e2d, 924, 108, 616, 5, 0); + add(e2d, 924, 107, 616, 5, 1); + add(e2d, 924, 104, 616, 7, 0); + add(e2d, 924, 103, 616, 7, 1); + add(e2d, 924, 1039, 617, 0, 0); + add(e2d, 924, 1040, 617, 0, 1); + add(e2d, 924, 1041, 617, 0, 2); + add(e2d, 924, 1035, 617, 2, 0); + add(e2d, 924, 1036, 617, 2, 1); + add(e2d, 924, 1037, 617, 2, 2); + add(e2d, 924, 1038, 617, 2, 3); + add(e2d, 924, 1056, 617, 4, 0); + add(e2d, 924, 1057, 617, 4, 1); + add(e2d, 924, 1058, 617, 4, 2); + add(e2d, 924, 1052, 617, 6, 0); + add(e2d, 924, 1053, 617, 6, 1); + add(e2d, 924, 1054, 617, 6, 2); + add(e2d, 924, 1055, 617, 6, 3); + add(e2d, 924, 1067, 617, 1, 0); + add(e2d, 924, 1066, 617, 1, 1); + add(e2d, 924, 1065, 617, 1, 2); + add(e2d, 924, 1064, 617, 1, 3); + add(e2d, 924, 1133, 617, 3, 0); + add(e2d, 924, 1134, 617, 3, 1); + add(e2d, 924, 1135, 617, 3, 2); + add(e2d, 924, 1129, 617, 5, 0); + add(e2d, 924, 1130, 617, 5, 1); + add(e2d, 924, 1125, 617, 7, 0); + add(e2d, 924, 1126, 617, 7, 1); + add(e2d, 924, 313, 618, 0, 0); + add(e2d, 924, 314, 618, 0, 1); + add(e2d, 924, 315, 618, 0, 2); + add(e2d, 924, 316, 618, 0, 3); + add(e2d, 924, 317, 618, 0, 4); + add(e2d, 924, 308, 618, 2, 0); + add(e2d, 924, 309, 618, 2, 1); + add(e2d, 924, 310, 618, 2, 2); + add(e2d, 924, 311, 618, 2, 3); + add(e2d, 924, 312, 618, 2, 4); + add(e2d, 924, 330, 618, 4, 0); + add(e2d, 924, 331, 618, 4, 1); + add(e2d, 924, 332, 618, 4, 2); + add(e2d, 924, 333, 618, 4, 3); + add(e2d, 924, 334, 618, 4, 4); + add(e2d, 924, 325, 618, 6, 0); + add(e2d, 924, 326, 618, 6, 1); + add(e2d, 924, 327, 618, 6, 2); + add(e2d, 924, 328, 618, 6, 3); + add(e2d, 924, 329, 618, 6, 4); + add(e2d, 924, 338, 618, 1, 0); + add(e2d, 924, 339, 618, 1, 1); + add(e2d, 924, 340, 618, 1, 2); + add(e2d, 924, 341, 618, 1, 3); + add(e2d, 924, 342, 618, 1, 4); + add(e2d, 924, 211, 618, 3, 0); + add(e2d, 924, 212, 618, 3, 1); + add(e2d, 924, 213, 618, 3, 2); + add(e2d, 924, 214, 618, 3, 3); + add(e2d, 924, 215, 618, 3, 4); + add(e2d, 924, 206, 618, 5, 0); + add(e2d, 924, 207, 618, 5, 1); + add(e2d, 924, 208, 618, 5, 2); + add(e2d, 924, 201, 618, 7, 0); + add(e2d, 924, 202, 618, 7, 1); + add(e2d, 924, 203, 618, 7, 2); + add(e2d, 924, 1327, 619, 0, 0); + add(e2d, 924, 1326, 619, 0, 1); + add(e2d, 924, 1325, 619, 0, 2); + add(e2d, 924, 1331, 619, 2, 0); + add(e2d, 924, 1330, 619, 2, 1); + add(e2d, 924, 1329, 619, 2, 2); + add(e2d, 924, 1328, 619, 2, 3); + add(e2d, 924, 1344, 619, 4, 0); + add(e2d, 924, 1343, 619, 4, 1); + add(e2d, 924, 1342, 619, 4, 2); + add(e2d, 924, 1348, 619, 6, 0); + add(e2d, 924, 1347, 619, 6, 1); + add(e2d, 924, 1346, 619, 6, 2); + add(e2d, 924, 1345, 619, 6, 3); + add(e2d, 924, 1359, 619, 1, 0); + add(e2d, 924, 1360, 619, 1, 1); + add(e2d, 924, 1361, 619, 1, 2); + add(e2d, 924, 1243, 619, 3, 0); + add(e2d, 924, 1242, 619, 3, 1); + add(e2d, 924, 1241, 619, 3, 2); + add(e2d, 924, 1240, 619, 3, 3); + add(e2d, 924, 1234, 619, 5, 0); + add(e2d, 924, 1233, 619, 5, 1); + add(e2d, 924, 1229, 619, 7, 0); + add(e2d, 924, 1228, 619, 7, 1); + add(e2d, 923, 308, 620, 0, 0); + add(e2d, 923, 307, 620, 0, 1); + add(e2d, 923, 306, 620, 0, 2); + add(e2d, 923, 305, 620, 0, 3); + add(e2d, 923, 304, 620, 0, 4); + add(e2d, 923, 316, 620, 2, 0); + add(e2d, 923, 315, 620, 2, 1); + add(e2d, 923, 314, 620, 2, 2); + add(e2d, 923, 313, 620, 2, 3); + add(e2d, 923, 312, 620, 2, 4); + add(e2d, 923, 324, 620, 4, 0); + add(e2d, 923, 323, 620, 4, 1); + add(e2d, 923, 322, 620, 4, 2); + add(e2d, 923, 321, 620, 4, 3); + add(e2d, 923, 320, 620, 4, 4); + add(e2d, 923, 211, 620, 1, 0); + add(e2d, 923, 212, 620, 1, 1); + add(e2d, 923, 213, 620, 1, 2); + add(e2d, 923, 206, 620, 3, 0); + add(e2d, 923, 207, 620, 3, 1); + add(e2d, 923, 208, 620, 3, 2); + add(e2d, 923, 201, 620, 5, 0); + add(e2d, 923, 202, 620, 5, 1); + add(e2d, 923, 203, 620, 5, 2); + add(e2d, 923, 1325, 621, 0, 0); + add(e2d, 923, 1326, 621, 0, 1); + add(e2d, 923, 1327, 621, 0, 2); + add(e2d, 923, 1333, 621, 2, 0); + add(e2d, 923, 1334, 621, 2, 1); + add(e2d, 923, 1335, 621, 2, 2); + add(e2d, 923, 1341, 621, 4, 0); + add(e2d, 923, 1342, 621, 4, 1); + add(e2d, 923, 1343, 621, 4, 2); + add(e2d, 923, 1239, 621, 1, 0); + add(e2d, 923, 1238, 621, 1, 1); + add(e2d, 923, 1234, 621, 3, 0); + add(e2d, 923, 1233, 621, 3, 1); + add(e2d, 923, 1229, 621, 5, 0); + add(e2d, 923, 1228, 621, 5, 1); + add(e2d, 923, 1, 480, 0, 0); + add(e2d, 923, 2, 480, 0, 1); + add(e2d, 923, 3, 480, 0, 2); + add(e2d, 923, 4, 480, 0, 3); + add(e2d, 923, 5, 480, 0, 4); + add(e2d, 923, 10, 480, 2, 0); + add(e2d, 923, 11, 480, 2, 1); + add(e2d, 923, 12, 480, 2, 2); + add(e2d, 923, 13, 480, 2, 3); + add(e2d, 923, 14, 480, 2, 4); + add(e2d, 923, 19, 480, 4, 0); + add(e2d, 923, 20, 480, 4, 1); + add(e2d, 923, 21, 480, 4, 2); + add(e2d, 923, 22, 480, 4, 3); + add(e2d, 923, 23, 480, 4, 4); + add(e2d, 923, 112, 480, 1, 0); + add(e2d, 923, 111, 480, 1, 1); + add(e2d, 923, 108, 480, 3, 0); + add(e2d, 923, 107, 480, 3, 1); + add(e2d, 923, 103, 480, 5, 0); + add(e2d, 923, 104, 480, 5, 1); + add(e2d, 923, 1033, 481, 0, 0); + add(e2d, 923, 1032, 481, 0, 1); + add(e2d, 923, 1031, 481, 0, 2); + add(e2d, 923, 1030, 481, 0, 3); + add(e2d, 923, 1042, 481, 2, 0); + add(e2d, 923, 1041, 481, 2, 1); + add(e2d, 923, 1040, 481, 2, 2); + add(e2d, 923, 1039, 481, 2, 3); + add(e2d, 923, 1051, 481, 4, 0); + add(e2d, 923, 1050, 481, 4, 1); + add(e2d, 923, 1049, 481, 4, 2); + add(e2d, 923, 1048, 481, 4, 3); + add(e2d, 923, 1125, 481, 1, 0); + add(e2d, 923, 1126, 481, 1, 1); + add(e2d, 923, 1129, 481, 3, 0); + add(e2d, 923, 1130, 481, 3, 1); + add(e2d, 923, 1133, 481, 5, 0); + add(e2d, 923, 1134, 481, 5, 1); + add(e2d, 922, 1, 482, 0, 0); + add(e2d, 922, 2, 482, 0, 1); + add(e2d, 922, 3, 482, 0, 2); + add(e2d, 922, 4, 482, 0, 3); + add(e2d, 922, 5, 482, 0, 4); + add(e2d, 922, 10, 482, 2, 0); + add(e2d, 922, 11, 482, 2, 1); + add(e2d, 922, 12, 482, 2, 2); + add(e2d, 922, 13, 482, 2, 3); + add(e2d, 922, 14, 482, 2, 4); + add(e2d, 922, 112, 482, 4, 0); + add(e2d, 922, 111, 482, 4, 1); + add(e2d, 922, 108, 482, 1, 0); + add(e2d, 922, 107, 482, 1, 1); + add(e2d, 922, 104, 482, 3, 0); + add(e2d, 922, 103, 482, 3, 1); + add(e2d, 922, 1033, 483, 0, 0); + add(e2d, 922, 1032, 483, 0, 1); + add(e2d, 922, 1031, 483, 0, 2); + add(e2d, 922, 1030, 483, 0, 3); + add(e2d, 922, 1042, 483, 2, 0); + add(e2d, 922, 1041, 483, 2, 1); + add(e2d, 922, 1040, 483, 2, 2); + add(e2d, 922, 1039, 483, 2, 3); + add(e2d, 922, 1133, 483, 4, 0); + add(e2d, 922, 1134, 483, 4, 1); + add(e2d, 922, 1129, 483, 1, 0); + add(e2d, 922, 1130, 483, 1, 1); + add(e2d, 922, 1125, 483, 3, 0); + add(e2d, 922, 1126, 483, 3, 1); + add(e2d, 922, 308, 484, 0, 0); + add(e2d, 922, 307, 484, 0, 1); + add(e2d, 922, 306, 484, 0, 2); + add(e2d, 922, 305, 484, 0, 3); + add(e2d, 922, 304, 484, 0, 4); + add(e2d, 922, 316, 484, 2, 0); + add(e2d, 922, 315, 484, 2, 1); + add(e2d, 922, 314, 484, 2, 2); + add(e2d, 922, 313, 484, 2, 3); + add(e2d, 922, 312, 484, 2, 4); + add(e2d, 922, 211, 484, 4, 0); + add(e2d, 922, 212, 484, 4, 1); + add(e2d, 922, 213, 484, 4, 2); + add(e2d, 922, 206, 484, 1, 0); + add(e2d, 922, 207, 484, 1, 1); + add(e2d, 922, 208, 484, 1, 2); + add(e2d, 922, 201, 484, 3, 0); + add(e2d, 922, 202, 484, 3, 1); + add(e2d, 922, 203, 484, 3, 2); + add(e2d, 922, 1325, 485, 0, 0); + add(e2d, 922, 1326, 485, 0, 1); + add(e2d, 922, 1327, 485, 0, 2); + add(e2d, 922, 1333, 485, 2, 0); + add(e2d, 922, 1334, 485, 2, 1); + add(e2d, 922, 1335, 485, 2, 2); + add(e2d, 922, 1239, 485, 4, 0); + add(e2d, 922, 1238, 485, 4, 1); + add(e2d, 922, 1234, 485, 1, 0); + add(e2d, 922, 1233, 485, 1, 1); + add(e2d, 922, 1229, 485, 3, 0); + add(e2d, 922, 1228, 485, 3, 1); + add(e2d, 921, 304, 488, 0, 0); + add(e2d, 921, 303, 488, 0, 1); + add(e2d, 921, 211, 488, 2, 0); + add(e2d, 921, 212, 488, 2, 1); + add(e2d, 921, 213, 488, 2, 2); + add(e2d, 921, 206, 488, 4, 0); + add(e2d, 921, 207, 488, 4, 1); + add(e2d, 921, 208, 488, 4, 2); + add(e2d, 921, 201, 488, 6, 0); + add(e2d, 921, 202, 488, 6, 1); + add(e2d, 921, 203, 488, 6, 2); + add(e2d, 921, 1325, 488, 1, 0); + add(e2d, 921, 1326, 488, 1, 1); + add(e2d, 921, 1239, 488, 3, 0); + add(e2d, 921, 1238, 488, 3, 1); + add(e2d, 921, 1234, 488, 5, 0); + add(e2d, 921, 1233, 488, 5, 1); + add(e2d, 921, 1229, 488, 7, 0); + add(e2d, 921, 1228, 488, 7, 1); + add(e2d, 921, 1, 489, 0, 0); + add(e2d, 921, 2, 489, 0, 1); + add(e2d, 921, 3, 489, 0, 2); + add(e2d, 921, 112, 489, 2, 0); + add(e2d, 921, 111, 489, 2, 1); + add(e2d, 921, 108, 489, 4, 0); + add(e2d, 921, 107, 489, 4, 1); + add(e2d, 921, 104, 489, 6, 0); + add(e2d, 921, 103, 489, 6, 1); + add(e2d, 921, 1029, 489, 1, 0); + add(e2d, 921, 1028, 489, 1, 1); + add(e2d, 921, 1133, 489, 3, 0); + add(e2d, 921, 1134, 489, 3, 1); + add(e2d, 921, 1129, 489, 5, 0); + add(e2d, 921, 1130, 489, 5, 1); + add(e2d, 921, 1125, 489, 7, 0); + add(e2d, 921, 1126, 489, 7, 1); + add(e2d, 920, 12, 490, 0, 0); + add(e2d, 920, 11, 490, 0, 1); + add(e2d, 920, 8, 490, 2, 0); + add(e2d, 920, 7, 490, 2, 1); + add(e2d, 920, 4, 490, 4, 0); + add(e2d, 920, 3, 490, 4, 1); + add(e2d, 920, 1033, 490, 1, 0); + add(e2d, 920, 1034, 490, 1, 1); + add(e2d, 920, 1029, 490, 3, 0); + add(e2d, 920, 1030, 490, 3, 1); + add(e2d, 920, 1025, 490, 5, 0); + add(e2d, 920, 1026, 490, 5, 1); + add(e2d, 920, 111, 491, 0, 0); + add(e2d, 920, 112, 491, 0, 1); + add(e2d, 920, 113, 491, 0, 2); + add(e2d, 920, 106, 491, 2, 0); + add(e2d, 920, 107, 491, 2, 1); + add(e2d, 920, 108, 491, 2, 2); + add(e2d, 920, 101, 491, 4, 0); + add(e2d, 920, 102, 491, 4, 1); + add(e2d, 920, 103, 491, 4, 2); + add(e2d, 920, 1139, 491, 1, 0); + add(e2d, 920, 1138, 491, 1, 1); + add(e2d, 920, 1134, 491, 3, 0); + add(e2d, 920, 1133, 491, 3, 1); + add(e2d, 920, 1129, 491, 5, 0); + add(e2d, 920, 1128, 491, 5, 1); +} +void fillSolar2FeeLinkCH9R(std::map<uint16_t, uint32_t>& s2f) +{ + add_cru(s2f, 50, 0, 688); + add_cru(s2f, 50, 1, 689); + add_cru(s2f, 50, 2, 690); + add_cru(s2f, 50, 3, 691); + add_cru(s2f, 50, 6, 672); + add_cru(s2f, 50, 7, 673); + add_cru(s2f, 50, 8, 674); + add_cru(s2f, 50, 9, 675); + add_cru(s2f, 50, 10, 676); + add_cru(s2f, 50, 11, 677); + add_cru(s2f, 51, 0, 560); + add_cru(s2f, 51, 1, 561); + add_cru(s2f, 51, 2, 562); + add_cru(s2f, 51, 3, 563); + add_cru(s2f, 51, 4, 564); + add_cru(s2f, 51, 5, 565); + add_cru(s2f, 51, 6, 568); + add_cru(s2f, 51, 7, 569); + add_cru(s2f, 51, 8, 570); + add_cru(s2f, 51, 9, 571); + add_cru(s2f, 51, 10, 572); + add_cru(s2f, 50, 4, 573); + add_cru(s2f, 52, 0, 608); + add_cru(s2f, 52, 1, 609); + add_cru(s2f, 52, 2, 610); + add_cru(s2f, 52, 3, 611); + add_cru(s2f, 52, 4, 612); + add_cru(s2f, 52, 5, 613); + add_cru(s2f, 52, 6, 616); + add_cru(s2f, 52, 7, 617); + add_cru(s2f, 52, 8, 618); + add_cru(s2f, 52, 9, 619); + add_cru(s2f, 52, 10, 620); + add_cru(s2f, 53, 10, 621); + add_cru(s2f, 53, 0, 480); + add_cru(s2f, 53, 1, 481); + add_cru(s2f, 53, 2, 482); + add_cru(s2f, 53, 3, 483); + add_cru(s2f, 53, 4, 484); + add_cru(s2f, 53, 5, 485); + add_cru(s2f, 53, 6, 488); + add_cru(s2f, 53, 7, 489); + add_cru(s2f, 53, 8, 490); + add_cru(s2f, 53, 9, 491); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/DsDetId.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/DsDetId.cxx index f33608b6a2268..51bb864f02adf 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/DsDetId.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/DsDetId.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/DsElecId.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/DsElecId.cxx index 6df4aac5b211d..dbd2dcd6f5f1a 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/DsElecId.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/DsElecId.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperDummy.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperDummy.cxx index c780b2a766581..c53f86167c980 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperDummy.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperDummy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,8 @@ namespace { +constexpr int firstSolarId{360}; // so at least we get some overlap with real solarIds + // build the map to go from electronic ds id to detector ds id std::map<uint32_t, uint32_t> buildDsElecId2DsDetIdMap() { @@ -28,7 +31,7 @@ std::map<uint32_t, uint32_t> buildDsElecId2DsDetIdMap() auto dslist = createDualSampaMapper(); uint16_t n{0}; - uint16_t solarId{0}; + uint16_t solarId{firstSolarId}; uint8_t groupId{0}; uint8_t index{0}; @@ -66,25 +69,27 @@ std::map<uint32_t, uint16_t> buildFeeLinkId2SolarIdMap() std::map<uint32_t, uint16_t> c2s; uint16_t n{0}; - uint16_t solarId{0}; + uint16_t solarId{firstSolarId}; auto dslist = createDualSampaMapper(); + std::set<uint16_t> solarIds; + for (auto deId : o2::mch::raw::deIdsForAllMCH) { // assign a tuple (fee,link) to each solarId for (auto dsId : dslist(deId)) { if (n % 40 == 0) { solarId++; - auto feeId = solarId / 12; - auto linkId = solarId - feeId * 12; - c2s[encode(o2::mch::raw::FeeLinkId(feeId, linkId))] = solarId; + solarIds.insert(solarId); } n++; - }; - }; - auto feeId = solarId / 12; - auto linkId = solarId - feeId * 12; - c2s[encode(o2::mch::raw::FeeLinkId(feeId, linkId))] = solarId; + } + } + for (auto solarId : solarIds) { + auto feeId = solarId / 12; + auto linkId = solarId - feeId * 12; + c2s[encode(o2::mch::raw::FeeLinkId(feeId, linkId))] = solarId; + } return c2s; } } // namespace @@ -123,4 +128,29 @@ std::function<std::optional<FeeLinkId>(uint16_t)> static auto s2f = impl::inverseMap(buildFeeLinkId2SolarIdMap()); return impl::mapperSolar2FeeLink<ElectronicMapperDummy>(s2f); } + +template <> +std::set<uint16_t> getSolarUIDs<ElectronicMapperDummy>(int deid) +{ + return impl::getSolarUIDs<ElectronicMapperDummy>(deid); +} + +template <> +std::set<uint16_t> getSolarUIDs<ElectronicMapperDummy>() +{ + return impl::getSolarUIDs<ElectronicMapperDummy>(); +} + +template <> +std::vector<std::string> solar2FeeLinkConsistencyCheck<ElectronicMapperDummy>() +{ + return impl::solar2FeeLinkConsistencyCheck<ElectronicMapperDummy>(); +} + +template <> +std::set<DsElecId> getAllDs<ElectronicMapperDummy>() +{ + return impl::getAllDs<ElectronicMapperDummy>(); +} + } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperGenerated.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperGenerated.cxx index 469007ee9b74d..1c85c90faaa00 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperGenerated.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperGenerated.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,11 @@ extern void fillElec2DetCH6L(std::map<uint32_t, uint32_t>& e2d); extern void fillElec2DetCH7R(std::map<uint32_t, uint32_t>& e2d); extern void fillElec2DetCH7L(std::map<uint32_t, uint32_t>& e2d); extern void fillElec2DetCH8L(std::map<uint32_t, uint32_t>& e2d); +extern void fillElec2DetCH8R(std::map<uint32_t, uint32_t>& e2d); +extern void fillElec2DetCH9L(std::map<uint32_t, uint32_t>& e2d); +extern void fillElec2DetCH9R(std::map<uint32_t, uint32_t>& e2d); +extern void fillElec2DetCH10L(std::map<uint32_t, uint32_t>& e2d); +extern void fillElec2DetCH10R(std::map<uint32_t, uint32_t>& e2d); extern void fillSolar2FeeLinkCH5R(std::map<uint16_t, uint32_t>& s2c); extern void fillSolar2FeeLinkCH5L(std::map<uint16_t, uint32_t>& s2c); @@ -31,6 +37,11 @@ extern void fillSolar2FeeLinkCH6L(std::map<uint16_t, uint32_t>& s2c); extern void fillSolar2FeeLinkCH7R(std::map<uint16_t, uint32_t>& s2c); extern void fillSolar2FeeLinkCH7L(std::map<uint16_t, uint32_t>& s2c); extern void fillSolar2FeeLinkCH8L(std::map<uint16_t, uint32_t>& s2c); +extern void fillSolar2FeeLinkCH8R(std::map<uint16_t, uint32_t>& s2c); +extern void fillSolar2FeeLinkCH9L(std::map<uint16_t, uint32_t>& s2c); +extern void fillSolar2FeeLinkCH9R(std::map<uint16_t, uint32_t>& s2c); +extern void fillSolar2FeeLinkCH10L(std::map<uint16_t, uint32_t>& s2c); +extern void fillSolar2FeeLinkCH10R(std::map<uint16_t, uint32_t>& s2c); namespace { @@ -51,7 +62,12 @@ std::map<uint32_t, uint32_t> buildDsElecId2DsDetIdMap() fillElec2DetCH6L(e2d); fillElec2DetCH7R(e2d); fillElec2DetCH7L(e2d); + fillElec2DetCH8R(e2d); fillElec2DetCH8L(e2d); + fillElec2DetCH9R(e2d); + fillElec2DetCH9L(e2d); + fillElec2DetCH10R(e2d); + fillElec2DetCH10L(e2d); return e2d; } @@ -64,7 +80,12 @@ std::map<uint16_t, uint32_t> buildSolarId2FeeLinkIdMap() fillSolar2FeeLinkCH6L(s2f); fillSolar2FeeLinkCH7R(s2f); fillSolar2FeeLinkCH7L(s2f); + fillSolar2FeeLinkCH8R(s2f); fillSolar2FeeLinkCH8L(s2f); + fillSolar2FeeLinkCH9R(s2f); + fillSolar2FeeLinkCH9L(s2f); + fillSolar2FeeLinkCH10R(s2f); + fillSolar2FeeLinkCH10L(s2f); return s2f; } @@ -105,4 +126,28 @@ std::function<std::optional<uint16_t>(FeeLinkId)> return impl::mapperFeeLink2Solar<ElectronicMapperGenerated>(feeLinkId2SolarId); } +template <> +std::set<uint16_t> getSolarUIDs<ElectronicMapperGenerated>(int deid) +{ + return impl::getSolarUIDs<ElectronicMapperGenerated>(deid); +} + +template <> +std::set<uint16_t> getSolarUIDs<ElectronicMapperGenerated>() +{ + return impl::getSolarUIDs<ElectronicMapperGenerated>(); +} + +template <> +std::vector<std::string> solar2FeeLinkConsistencyCheck<ElectronicMapperGenerated>() +{ + return impl::solar2FeeLinkConsistencyCheck<ElectronicMapperGenerated>(); +} + +template <> +std::set<DsElecId> getAllDs<ElectronicMapperGenerated>() +{ + return impl::getAllDs<ElectronicMapperGenerated>(); +} + } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperImplHelper.h b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperImplHelper.h index 736ef82c00ab8..4783c3bdda819 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperImplHelper.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperImplHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,8 @@ #include <set> #include <fmt/format.h> #include <iostream> +#include "MCHRawElecMap/Mapper.h" +#include "dslist.h" namespace o2::mch::raw::impl { @@ -85,6 +88,86 @@ std::map<VALUE, KEY> inverseMap(const std::map<KEY, VALUE>& src) } return dest; } + +template <typename T> +std::set<uint16_t> getSolarUIDs(int deid) +{ + auto d2e = o2::mch::raw::createDet2ElecMapper<T>(); + std::set<uint16_t> solarsForDE; + auto dslist = createDualSampaMapper(); + for (auto dsid : dslist(deid)) { + DsDetId id{static_cast<uint16_t>(deid), static_cast<uint16_t>(dsid)}; + auto dsel = d2e(id); + if (dsel.has_value()) { + solarsForDE.insert(dsel->solarId()); + } + } + return solarsForDE; +} + +template <typename T> +std::set<uint16_t> getSolarUIDs() +{ + std::set<uint16_t> solarUIDs; + + for (auto deid : deIdsForAllMCH) { + std::set<uint16_t> solarsForDE = getSolarUIDs<T>(deid); + for (auto s : solarsForDE) { + solarUIDs.insert(s); + } + } + return solarUIDs; +} + +template <typename T> +std::vector<std::string> solar2FeeLinkConsistencyCheck() +{ + std::vector<std::string> errors; + + // All solars must have a FeeLinkId + std::set<uint16_t> solarIds = getSolarUIDs<T>(); + auto solar2feeLink = createSolar2FeeLinkMapper<T>(); + std::vector<o2::mch::raw::FeeLinkId> feeLinkIds; + for (auto s : solarIds) { + auto p = solar2feeLink(s); + if (!p.has_value()) { + errors.push_back(fmt::format("Got no feelinkId for solarId {}", s)); + } else { + feeLinkIds.push_back(p.value()); + } + } + + // All FeeLinkId must have a SolarId + auto feeLinkId2SolarId = createFeeLink2SolarMapper<T>(); + for (auto f : feeLinkIds) { + auto p = feeLinkId2SolarId(f); + if (!p.has_value()) { + errors.push_back(fmt::format("Got no solarId for FeeLinkId {}", asString(f))); + } + } + return errors; +} + +template <typename T> +std::set<DsElecId> getAllDs() +{ + std::set<DsElecId> dsElecIds; + + auto dslist = createDualSampaMapper(); + auto det2ElecMapper = createDet2ElecMapper<T>(); + + for (auto deId : o2::mch::raw::deIdsForAllMCH) { + for (auto dsId : dslist(deId)) { + auto dsElecId = det2ElecMapper(DsDetId{deId, dsId}); + if (dsElecId.has_value()) { + dsElecIds.insert(dsElecId.value()); + } + } + } + + return dsElecIds; +} + } // namespace o2::mch::raw::impl #endif diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperString.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperString.cxx index 1a0416b6702a4..f62a03ddcc87b 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperString.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperString.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/FeeLinkId.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/FeeLinkId.cxx index 94730272aa2f3..5d39c6fc68d22 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/FeeLinkId.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/FeeLinkId.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.cxx index 97f1d89e80176..30eb8fa265514 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.h b/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.h index c2dbec1baa4b0..ae073486e60c0 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/MapCRU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.cxx index 13f05d1c8622e..d369c8b360570 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.h b/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.h index e25c5bd11aba1..7077b2bb4b2da 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/MapFEC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/Mapper.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/Mapper.cxx index 1181ecd28c2e1..a0a0e57ea24e5 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/Mapper.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/Mapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,14 +13,18 @@ namespace o2::mch::raw { -std::array<int, 9> deIdsOfCH5R{504, 503, 502, 501, 500, 517, 516, 515, 514}; // from top to bottom -std::array<int, 9> deIdsOfCH5L{505, 506, 507, 508, 509, 510, 511, 512, 513}; // from top to bottom -std::array<int, 9> deIdsOfCH6R{604, 603, 602, 601, 600, 617, 616, 615, 614}; // from top to bottom -std::array<int, 9> deIdsOfCH6L{605, 606, 607, 608, 609, 610, 611, 612, 613}; // from top to bottom -std::array<int, 13> deIdsOfCH7R{706, 705, 704, 703, 702, 701, 700, 725, 724, 723, 722, 721, 720}; // from top to bottom -std::array<int, 13> deIdsOfCH7L{707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719}; // from top to bottom -std::array<int, 13> deIdsOfCH8R{806, 805, 804, 803, 802, 801, 800, 825, 824, 823, 822, 821, 820}; // from top to bottom -std::array<int, 13> deIdsOfCH8L{807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819}; // from top to bottom +std::array<int, 9> deIdsOfCH5R{504, 503, 502, 501, 500, 517, 516, 515, 514}; // from top to bottom +std::array<int, 9> deIdsOfCH5L{505, 506, 507, 508, 509, 510, 511, 512, 513}; // from top to bottom +std::array<int, 9> deIdsOfCH6R{604, 603, 602, 601, 600, 617, 616, 615, 614}; // from top to bottom +std::array<int, 9> deIdsOfCH6L{605, 606, 607, 608, 609, 610, 611, 612, 613}; // from top to bottom +std::array<int, 13> deIdsOfCH7R{706, 705, 704, 703, 702, 701, 700, 725, 724, 723, 722, 721, 720}; // from top to bottom +std::array<int, 13> deIdsOfCH7L{707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719}; // from top to bottom +std::array<int, 13> deIdsOfCH8R{806, 805, 804, 803, 802, 801, 800, 825, 824, 823, 822, 821, 820}; // from top to bottom +std::array<int, 13> deIdsOfCH8L{807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819}; // from top to bottom +std::array<int, 13> deIdsOfCH9R{906, 905, 904, 903, 902, 901, 900, 925, 924, 923, 922, 921, 920}; // from top to bottom +std::array<int, 13> deIdsOfCH9L{907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919}; // from top to bottom +std::array<int, 13> deIdsOfCH10R{1006, 1005, 1004, 1003, 1002, 1001, 1000, 1025, 1024, 1023, 1022, 1021, 1020}; // from top to bottom +std::array<int, 13> deIdsOfCH10L{1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019}; // from top to bottom std::array<int, 156> deIdsForAllMCH = { 100, 101, 102, 103, @@ -32,4 +37,5 @@ std::array<int, 156> deIdsForAllMCH = { 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025}; + } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/cli.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/cli.cxx index 8d464a488491b..ce0c97e267043 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/cli.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/cli.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,10 +17,11 @@ namespace po = boost::program_options; +template <typename ELECMAP> int dump(const o2::mch::raw::DsElecId& dsElecId, const o2::mch::raw::DsDetId& dsDetId) { - auto solar2fee = o2::mch::raw::createSolar2FeeLinkMapper<o2::mch::raw::ElectronicMapperGenerated>(); + auto solar2fee = o2::mch::raw::createSolar2FeeLinkMapper<ELECMAP>(); auto feelink = solar2fee(dsElecId.solarId()); if (!feelink.has_value()) { std::cout << "Could not get FeeLinkId for solarId " << dsElecId.solarId() << "\n"; @@ -33,36 +35,38 @@ int dump(const o2::mch::raw::DsElecId& dsElecId, return 0; } +template <typename ELECMAP> int convertElec2Det(uint16_t solarId, uint8_t groupId, uint8_t indexId) { try { std::cout << fmt::format("solarId {} groupId {} indexId {}\n", solarId, groupId, indexId); o2::mch::raw::DsElecId dsElecId(solarId, groupId, indexId); - auto elec2det = o2::mch::raw::createElec2DetMapper<o2::mch::raw::ElectronicMapperGenerated>(); + auto elec2det = o2::mch::raw::createElec2DetMapper<ELECMAP>(); auto dsDetId = elec2det(dsElecId); if (!dsDetId.has_value()) { std::cout << o2::mch::raw::asString(dsElecId) << " is not (yet?) known to the electronic mapper\n"; return 3; } - return dump(dsElecId, dsDetId.value()); + return dump<ELECMAP>(dsElecId, dsDetId.value()); } catch (const std::exception& e) { std::cout << e.what() << "\n"; return 4; } } +template <typename ELECMAP> int convertDet2Elec(int deId, int dsId) { try { o2::mch::raw::DsDetId dsDetId(deId, dsId); - auto det2elec = o2::mch::raw::createDet2ElecMapper<o2::mch::raw::ElectronicMapperGenerated>(); + auto det2elec = o2::mch::raw::createDet2ElecMapper<ELECMAP>(); auto dsElecId = det2elec(dsDetId); if (!dsElecId.has_value()) { std::cout << o2::mch::raw::asString(dsDetId) << " is not (yet?) known to the electronic mapper\n"; return 3; } - return dump(dsElecId.value(), dsDetId); + return dump<ELECMAP>(dsElecId.value(), dsDetId); } catch (const std::exception& e) { std::cout << e.what() << "\n"; return 5; @@ -85,6 +89,7 @@ int main(int argc, char** argv) int indexId; int deId; int dsId; + bool dummyElecMap; po::variables_map vm; po::options_description generic("Generic options"); @@ -97,6 +102,7 @@ int main(int argc, char** argv) ("indexId,i",po::value<int>(&indexId),"index id") ("dsId,d",po::value<int>(&dsId),"dual sampa id") ("deId,e",po::value<int>(&deId),"detection element id") + ("dummy-elecmap",po::value<bool>(&dummyElecMap)->default_value(false),"use dummy electronic mapping (only for debug!)") ; // clang-format on @@ -117,11 +123,21 @@ int main(int argc, char** argv) } if (vm.count("solarId") && vm.count("groupId") && vm.count("indexId")) { - return convertElec2Det(static_cast<uint16_t>(solarId), - static_cast<uint8_t>(groupId), - static_cast<uint8_t>(indexId)); + if (dummyElecMap) { + return convertElec2Det<o2::mch::raw::ElectronicMapperDummy>(static_cast<uint16_t>(solarId), + static_cast<uint8_t>(groupId), + static_cast<uint8_t>(indexId)); + } else { + return convertElec2Det<o2::mch::raw::ElectronicMapperGenerated>(static_cast<uint16_t>(solarId), + static_cast<uint8_t>(groupId), + static_cast<uint8_t>(indexId)); + } } else if (vm.count("deId") && vm.count("dsId")) { - return convertDet2Elec(deId, dsId); + if (dummyElecMap) { + return convertDet2Elec<o2::mch::raw::ElectronicMapperDummy>(deId, dsId); + } else { + return convertDet2Elec<o2::mch::raw::ElectronicMapperGenerated>(deId, dsId); + } } else { std::cout << "Incorrect mix of options\n"; return usage(generic); diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.cxx index 4fd225c735bba..b149b5907ebc1 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.h b/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.h index 0475e34604d15..f2f560639099b 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.h +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/dslist.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/elecmap.py b/Detectors/MUON/MCH/Raw/ElecMap/src/elecmap.py index 3f246c98c6cae..203d7ff04989f 100755 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/elecmap.py +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/elecmap.py @@ -30,11 +30,12 @@ def gencode_close_generated(out): def gencode_generated_code(out): """ Add full O2 Copyright to out""" - out.write('''// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". + out.write('''// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -87,7 +88,7 @@ def gencode_do(df, df_cru, solar_map, chamber): for row in df_cru.itertuples(): if len(row.solar_id) > 0: out.write("add_cru(s2f,{},{},{});\n".format( - row.fee_id, row.link_id, row.solar_id)) + row.fee_id, int(row.link_id)%12, row.solar_id)) out.write("}") gencode_close_generated(out) @@ -135,7 +136,7 @@ def gs_read_sheet_cru(credential_file, workbook, sheet_name): data = wks.get_all_values() -# LINK ID CRU ID CRU LINK DWP CRU ADDR DW ADDR FEE ID +# LINK ID CRU ID CRU LINK DWP CRU ADDR DW ADDR FEE ID cols = np.array([0, 1, 2, 3, 4, 5,6,7]) df = pd.DataFrame(np.asarray(data)[:, cols], @@ -181,7 +182,7 @@ def _simplify_dataframe(df): solar_map = {} for row in df.itertuples(): - # print(row) + #print(row) crate = int(str(row.crate).strip('C ')) solar_pos = int(row.solar.split('-')[2].strip('S '))-1 group_id = int(row.solar.split('-')[3].strip('J '))-1 @@ -253,6 +254,7 @@ def _simplify_dataframe(df): if args.gs_name: df = df.append(gs_read_sheet(args.credentials, args.gs_name, args.sheet)) + print(df) df, solar_map = _simplify_dataframe(df) df_cru = df_cru.append(gs_read_sheet_cru(args.credentials, args.gs_name, args.sheet+" CRU map")) diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/environment.yml b/Detectors/MUON/MCH/Raw/ElecMap/src/environment.yml new file mode 100644 index 0000000000000..d9b93d2c16d6d --- /dev/null +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/environment.yml @@ -0,0 +1,9 @@ +name: mch-elecmap +channels: + - conda-forge +dependencies: + - oauth2client + - gspread + - numpy + - pandas + - clang-tools diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/gen.sh b/Detectors/MUON/MCH/Raw/ElecMap/src/gen.sh index 2b1adbfb034e2..b8205e60ff349 100755 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/gen.sh +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/gen.sh @@ -1,6 +1,7 @@ #!/bin/sh -for chamber in CH5R CH5L CH6R CH7R CH7L CH8L; do +for chamber in CH5R CH5L CH6R CH7R CH7L CH8L CH8R CH9L CH9R CH10R; do + # srcdir=/Users/laurent/ownCloud/archive/2019/MRRTF/raw-data-encdec # ./elecmap.py -i ${srcdir}/Mapping-${chamber}.xlsx -c ${chamber} echo "Generating ${chamber}" diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/testDsElecId.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/testDsElecId.cxx index 552977def8e51..ef2ac2f45f14d 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/testDsElecId.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/testDsElecId.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapper.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapper.cxx index 2745693c4c113..00af5af55ecfa 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapper.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,10 +32,7 @@ typedef boost::mpl::list<o2::mch::raw::ElectronicMapperDummy, typedef boost::mpl::list<o2::mch::raw::ElectronicMapperGenerated> realTypes; -BOOST_AUTO_TEST_SUITE(o2_mch_raw) - -BOOST_AUTO_TEST_SUITE(electronicmapperdummy) - +// // Used to generate dslist.cxx // BOOST_AUTO_TEST_CASE(dumpseg) // { // std::map<int, std::vector<int>> dsids; @@ -101,35 +99,6 @@ std::set<int> nofDualSampasFromMapper(gsl::span<int> deids) } return ds; } -template <typename T> -std::set<uint16_t> getSolarUIDs(int deid) -{ - auto d2e = o2::mch::raw::createDet2ElecMapper<T>(); - std::set<uint16_t> solarsForDE; - for (auto dsid : dslist(deid)) { - DsDetId id{static_cast<uint16_t>(deid), static_cast<uint16_t>(dsid)}; - auto dsel = d2e(id); - if (dsel.has_value()) { - solarsForDE.insert(dsel->solarId()); - } - } - return solarsForDE; -} - -template <typename T> -std::set<uint16_t> getSolarUIDs() -{ - std::set<uint16_t> solarUIDs; - - for (auto deid : deIdsForAllMCH) { - std::set<uint16_t> solarsForDE = getSolarUIDs<T>(deid); - for (auto s : solarsForDE) { - solarUIDs.insert(s); - } - } - return solarUIDs; -} - BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH5R, T, testTypes) { auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH5R); @@ -152,14 +121,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH6R, T, testTypes) BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); } -// BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) -// BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH6L, T, testTypes) -// { -// auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH6L); -// auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH6L); -// BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); -// } -// +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH6L, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH6L); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH6L); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} + BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH7R, T, testTypes) { auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH7R); @@ -174,12 +143,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH7L, T, testTypes) BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); } -// BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH8R, T, testTypes) -// { -// auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH8R); -// auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH8R); -// BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); -// } +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH8R, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH8R); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH8R); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH8L, T, testTypes) { @@ -188,6 +157,38 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH8L, T, testTypes) BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); } +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH9R, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH9R); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH9R); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH9L, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH9L); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH9L); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH10R, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH10R); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH10R); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) +BOOST_AUTO_TEST_CASE_TEMPLATE(MustContainAllSampaCH10L, T, testTypes) +{ + auto check = nofDualSampasFromMapper<T>(o2::mch::raw::deIdsOfCH10L); + auto expected = nofDualSampas(o2::mch::raw::deIdsOfCH10L); + BOOST_CHECK(std::equal(expected.begin(), expected.end(), check.begin())); +} + +// this check depends on the installation status at Pt2, i.e. +// not yet fullly installed chambers have an expected number of solarIds +// set to zero BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolarsPerDetectionElement, T, realTypes) { // Chamber 1 @@ -248,15 +249,15 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolarsPerDetectionElement, T, realTyp BOOST_CHECK_EQUAL(getSolarUIDs<T>(616).size(), 4); BOOST_CHECK_EQUAL(getSolarUIDs<T>(617).size(), 4); // 6L = 6O - BOOST_CHECK_EQUAL(getSolarUIDs<T>(605).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(606).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(607).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(608).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(609).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(610).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(611).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(612).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(613).size(), 0); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(605).size(), 1); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(606).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(607).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(608).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(609).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(610).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(611).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(612).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(613).size(), 1); // Chamber 7 // 7R = 7I @@ -290,19 +291,19 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolarsPerDetectionElement, T, realTyp // Chamber 8 // 8R = 8I - BOOST_CHECK_EQUAL(getSolarUIDs<T>(800).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(801).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(802).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(803).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(804).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(805).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(806).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(820).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(821).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(822).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(823).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(824).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(825).size(), 0); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(800).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(801).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(802).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(803).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(804).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(805).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(806).size(), 1); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(820).size(), 1); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(821).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(822).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(823).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(824).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(825).size(), 4); // 8L = 8O BOOST_CHECK_EQUAL(getSolarUIDs<T>(807).size(), 1); BOOST_CHECK_EQUAL(getSolarUIDs<T>(808).size(), 2); @@ -320,49 +321,49 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolarsPerDetectionElement, T, realTyp // Chamber 9 // 9R = 9I - BOOST_CHECK_EQUAL(getSolarUIDs<T>(900).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(901).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(902).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(903).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(904).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(905).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(906).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(920).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(921).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(922).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(923).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(924).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(925).size(), 0); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(900).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(901).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(902).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(903).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(904).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(905).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(906).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(920).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(921).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(922).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(923).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(924).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(925).size(), 4); // 9L = 9O - BOOST_CHECK_EQUAL(getSolarUIDs<T>(907).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(908).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(909).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(910).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(911).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(912).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(913).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(914).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(915).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(916).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(917).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(918).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(919).size(), 0); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(907).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(908).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(909).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(910).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(911).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(912).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(913).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(914).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(915).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(916).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(917).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(918).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(919).size(), 2); // Chamber 10 // 10R = 10I - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1000).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1001).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1002).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1003).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1004).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1005).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1006).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1020).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1021).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1022).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1023).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1024).size(), 0); - BOOST_CHECK_EQUAL(getSolarUIDs<T>(1025).size(), 0); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1000).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1001).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1002).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1003).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1004).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1005).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1006).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1020).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1021).size(), 2); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1022).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1023).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1024).size(), 4); + BOOST_CHECK_EQUAL(getSolarUIDs<T>(1025).size(), 4); // 10L = 10O BOOST_CHECK_EQUAL(getSolarUIDs<T>(1007).size(), 0); BOOST_CHECK_EQUAL(getSolarUIDs<T>(1008).size(), 0); @@ -379,20 +380,69 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolarsPerDetectionElement, T, realTyp BOOST_CHECK_EQUAL(getSolarUIDs<T>(1019).size(), 0); } -BOOST_AUTO_TEST_CASE_TEMPLATE(AllSolarsMustGetAFeeLink, T, realTypes) +template <typename T> +int expectedNumberOfSolars(); + +template <> +int expectedNumberOfSolars<ElectronicMapperDummy>() +{ + return 421; +} +template <> +int expectedNumberOfSolars<ElectronicMapperGenerated>() +{ + return 388; +} + +template <typename T> +int expectedNumberOfDs(); + +template <> +int expectedNumberOfDs<ElectronicMapperDummy>() { - std::set<uint16_t> solarIds = getSolarUIDs<T>(); - auto solar2feeLink = o2::mch::raw::createSolar2FeeLinkMapper<T>(); - int nbad{0}; - for (auto s : solarIds) { - auto p = solar2feeLink(s); - if (!p.has_value()) { - ++nbad; - std::cout << "Got no feelinkId for solarId " << s << "\n"; + return 16828; +} + +template <> +int expectedNumberOfDs<ElectronicMapperGenerated>() +{ + return 8726; +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(AllSolarsMustGetAFeeLinkAndTheReverse, T, testTypes) +{ + auto errors = solar2FeeLinkConsistencyCheck<T>(); + BOOST_CHECK_EQUAL(errors.size(), 0); + if (!errors.empty()) { + for (auto msg : errors) { + std::cout << "ERROR: " << msg << "\n"; } } - BOOST_CHECK_EQUAL(nbad, 0); - BOOST_CHECK_EQUAL(solarIds.size(), 192); // must be updated when adding more chambers +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfSolars, T, testTypes) +{ + std::set<uint16_t> solarIds = getSolarUIDs<T>(); + BOOST_CHECK_EQUAL(solarIds.size(), expectedNumberOfSolars<T>()); // must be updated when adding more chambers +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfDsElecId, T, testTypes) +{ + std::set<DsElecId> dsElecIds = getAllDs<T>(); + BOOST_CHECK_EQUAL(dsElecIds.size(), expectedNumberOfDs<T>()); // must be updated when adding more chambers +} + +// Spot check (on a few selected ones, e.g. the ones used in some unit tests) +// solars actually have an associated FeeLinkId. +BOOST_AUTO_TEST_CASE_TEMPLATE(CheckAFewSolarIdThatMustHaveAFeeLinkd, T, testTypes) +{ + auto solarIds = {361, 448, 728}; + for (auto solarId : solarIds) { + BOOST_TEST_INFO(fmt::format("solarId={}", solarId)); + auto s2f = o2::mch::raw::createSolar2FeeLinkMapper<T>(); + auto f = s2f(solarId); + BOOST_CHECK_EQUAL(f.has_value(), true); + } } BOOST_AUTO_TEST_CASE(SpotCheck) @@ -402,6 +452,3 @@ BOOST_AUTO_TEST_CASE(SpotCheck) auto s = f2s(id); BOOST_CHECK_EQUAL(s.has_value(), true); } - -BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapperString.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapperString.cxx index 1fab95e751cd0..cce332cbf3ce6 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapperString.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapperString.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ElecMap/src/testFeeLinkId.cxx b/Detectors/MUON/MCH/Raw/ElecMap/src/testFeeLinkId.cxx index 21b01565be15b..ed08c3bac8b0e 100644 --- a/Detectors/MUON/MCH/Raw/ElecMap/src/testFeeLinkId.cxx +++ b/Detectors/MUON/MCH/Raw/ElecMap/src/testFeeLinkId.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Encoder/CMakeLists.txt index 75134367fe1e8..28900428b55fe 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Encoder/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Payload) add_subdirectory(Digit) diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Encoder/Digit/CMakeLists.txt index 436b2785f423e..6052c7d9fcbdd 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/CMakeLists.txt @@ -1,34 +1,38 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHRawEncoderDigit SOURCES - DigitEncoder.cxx - DigitReader.cxx + Digit2ElecMapper.cxx + DigitPayloadEncoder.cxx + DigitRawEncoder.cxx + DigitTreeReader.cxx PUBLIC_LINK_LIBRARIES + O2::DataFormatsParameters O2::MCHRawEncoderPayload) -o2_add_executable(digit2json - SOURCES digit2json.cxx +o2_add_executable(digits-to-json + SOURCES digits-to-json.cxx COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES Boost::program_options O2::MCHMappingImpl4 O2::MCHRawElecMap - O2::MCHSimulation O2::MCHRawEncoderDigit + O2::MCHSimulation O2::Steer fmt::fmt) -o2_add_executable(digit2raw - SOURCES digit2raw.cxx +o2_add_executable(digits-to-raw + SOURCES digits-to-raw.cxx COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES Boost::program_options @@ -40,3 +44,9 @@ o2_add_executable(digit2raw O2::MCHSimulation O2::Steer fmt::fmt) + +o2_add_test(digit-tree-reader + SOURCES testDigitTreeReader.cxx + COMPONENT_NAME mch + LABELS muon mch + PUBLIC_LINK_LIBRARIES O2::MCHRawEncoderDigit) diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/Digit2ElecMapper.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/Digit2ElecMapper.cxx new file mode 100644 index 0000000000000..d75195d14aec5 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/Digit2ElecMapper.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawEncoderDigit/Digit2ElecMapper.h" + +#include "MCHMappingInterface/Segmentation.h" +#include "Framework/Logger.h" +#include "MCHRawCommon/DataFormats.h" + +namespace o2::mch::raw +{ +// create a function that return the (DsElecId,dualSampaChannelId) of a digit +Digit2ElecMapper createDigit2ElecMapper(Det2ElecMapper det2elec) +{ + return [det2elec](const o2::mch::Digit& digit) -> std::optional<std::pair<DsElecId, DualSampaChannelId>> { + auto deid = digit.getDetID(); + auto dsid = mapping::segmentation(deid).padDualSampaId(digit.getPadID()); + DsDetId detId{deid, dsid}; + auto dselocopt = det2elec(DsDetId(deid, dsid)); + if (!dselocopt.has_value()) { + LOGP(warning, "got no location for (de,ds)=({},{})", deid, dsid); + return std::nullopt; + } + DsElecId elecId = dselocopt.value(); + auto dualSampaChannelId = mapping::segmentation(deid).padDualSampaChannel(digit.getPadID()); + return std::make_pair(dselocopt.value(), dualSampaChannelId); + }; +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.cxx deleted file mode 100644 index fc7ea392f3273..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.cxx +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "MCHBase/Digit.h" -#include "MCHMappingInterface/Segmentation.h" -#include "MCHRawCommon/DataFormats.h" -#include "MCHRawElecMap/DsDetId.h" -#include "DigitEncoder.h" -#include "MCHRawEncoderPayload/PayloadEncoder.h" -#include <cstdint> -#include <fmt/printf.h> -#include <functional> -#include <gsl/span> -#include <memory> - -namespace o2::mch::raw -{ - -template <typename CHARGESUM> -std::vector<SampaCluster> createSampaClusters(uint16_t ts, float adc); - -template <> -std::vector<SampaCluster> createSampaClusters<raw::ChargeSumMode>(uint16_t ts, float adc) -{ - uint32_t cs = 2; - return {raw::SampaCluster(ts, 0, static_cast<uint32_t>(adc), cs)}; -} - -template <> -std::vector<SampaCluster> createSampaClusters<raw::SampleMode>(uint16_t ts, float adc) -{ - uint32_t a = static_cast<uint32_t>(adc); - std::vector<uint16_t> samples; - - samples.emplace_back(static_cast<uint16_t>((a & 0xFFC00) >> 10)); - samples.emplace_back(static_cast<uint16_t>(a & 0x3FF)); - return {raw::SampaCluster(ts, 0, samples)}; -} - -// create a function that return the (DsElecId,chid) of a digit -Digit2ElecMapper createDigit2ElecMapper(Det2ElecMapper det2elec) -{ - return [det2elec](const o2::mch::Digit& digit) -> std::optional<std::pair<DsElecId, int>> { - int deid = digit.getDetID(); - int dsid = mapping::segmentation(deid).padDualSampaId(digit.getPadID()); - DsDetId detId{deid, dsid}; - auto dselocopt = det2elec(DsDetId(deid, dsid)); - if (!dselocopt.has_value()) { - //std::cout << fmt::format("WARNING : got no location for (de,ds)=({},{})\n", deid, dsid); - return std::nullopt; - } - DsElecId elecId = dselocopt.value(); - int dschid = mapping::segmentation(deid).padDualSampaChannel(digit.getPadID()); - return std::make_pair(dselocopt.value(), dschid); - }; -} - -template <typename FORMAT, typename CHARGESUM> -DigitEncoder createDigitEncoder(Det2ElecMapper det2elec) -{ - auto encoder = createPayloadEncoder<FORMAT, CHARGESUM>().release(); - auto digit2elec = createDigit2ElecMapper(det2elec); - - return [encoder, digit2elec](gsl::span<o2::mch::Digit> digits, - std::vector<std::byte>& buffer, - uint32_t orbit, - uint16_t bc) { - static int nadd{0}; - encoder->startHeartbeatFrame(orbit, bc); - - for (auto d : digits) { - auto optElecId = digit2elec(d); - if (!optElecId.has_value()) { - continue; - } - auto elecId = optElecId.value().first; - int dschid = optElecId.value().second; - // FIXME: add a warning if timestamp is not in range - uint16_t ts(static_cast<int>(d.getTime().sampaTime) & 0x3FF); - int sampachid = dschid % 32; - // FIXME: add a warning if ADC is not in range - auto clusters = createSampaClusters<CHARGESUM>(ts, d.getADC() & 0xFFFFF); - encoder->addChannelData(elecId, sampachid, clusters); - } - encoder->moveToBuffer(buffer); - }; -} - -DigitEncoder createDigitEncoder(bool userLogic, Det2ElecMapper det2elec) -{ - if (userLogic) { - return createDigitEncoder<UserLogicFormat, ChargeSumMode>(det2elec); - } - return createDigitEncoder<BareFormat, ChargeSumMode>(det2elec); -} -} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.h deleted file mode 100644 index 51328ae6a5fe2..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitEncoder.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MCH_RAW_ENCODER_DIGIT_ENCODER_H -#define O2_MCH_RAW_ENCODER_DIGIT_ENCODER_H - -#include "MCHBase/Digit.h" -#include "MCHRawElecMap/DsDetId.h" -#include "MCHRawElecMap/DsElecId.h" -#include "MCHRawElecMap/Mapper.h" -#include <cstdint> -#include <functional> -#include <gsl/span> -#include <optional> - -namespace o2::mch::raw -{ - -using DigitEncoder = std::function<void(gsl::span<o2::mch::Digit> digits, - std::vector<std::byte>& buffer, - uint32_t orbit, - uint16_t bc)>; - -DigitEncoder createDigitEncoder(bool userLogic, Det2ElecMapper det2elec); - -using Digit2ElecMapper = std::function<std::optional<std::pair<DsElecId, int>>(const o2::mch::Digit& digit)>; - -Digit2ElecMapper createDigit2ElecMapper(Det2ElecMapper); - -} // namespace o2::mch::raw -#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitPayloadEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitPayloadEncoder.cxx new file mode 100644 index 0000000000000..a5dec7c1f985b --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitPayloadEncoder.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawEncoderDigit/DigitPayloadEncoder.h" + +#include "DataFormatsMCH/Digit.h" +#include "DetectorsRaw/HBFUtils.h" +#include "MCHRawEncoderDigit/Digit2ElecMapper.h" +#include "Framework/Logger.h" +#include "MCHRawCommon/DataFormats.h" +#include "MCHRawCommon/SampaBunchCrossingCounter.h" +#include "MCHRawElecMap/DsDetId.h" +#include "MCHRawEncoderPayload/PayloadEncoder.h" +#include <cstdint> +#include <fmt/printf.h> +#include <functional> +#include <gsl/span> +#include <memory> +#include "Framework/Logger.h" + +namespace o2::mch::raw +{ +std::string asString(o2::mch::Digit d) +{ + return fmt::format("DetID {:4d} PadId {:10d} ADC {:10d} TFtime {:10d} NofSamples {:5d} {}", + d.getDetID(), d.getPadID(), d.getADC(), d.getTime(), d.getNofSamples(), + d.isSaturated() ? "(S)" : ""); +} + +DigitPayloadEncoder::DigitPayloadEncoder(Digit2ElecMapper digit2elec, + PayloadEncoder& encoder) + : mDigit2ElecMapper{digit2elec}, mEncoder{encoder} +{ +} + +void DigitPayloadEncoder::encodeDigits(gsl::span<o2::mch::Digit> digits, + uint32_t orbit, + uint16_t bc, + std::vector<std::byte>& buffer) +{ + mEncoder.startHeartbeatFrame(orbit, bc); + for (auto d : digits) { + auto optElecId = mDigit2ElecMapper(d); + if (!optElecId.has_value()) { + LOGP(warning, "could not get elecId for digit {}", asString(d)); + continue; + } + auto elecId = optElecId.value().first; + int dualSampaChannelId = optElecId.value().second; + // FIXME : what to put as rel time ? + uint10_t ts = 0; + auto firstIR = o2::raw::HBFUtils::Instance().getFirstIR(); + uint20_t bxCount = sampaBunchCrossingCounter(orbit, bc, firstIR.orbit); + auto clusters = {raw::SampaCluster(ts, bxCount, d.getADC(), d.getNofSamples())}; + mEncoder.addChannelData(elecId, dualSampaChannelId, clusters); + } + mEncoder.moveToBuffer(buffer); +} +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitRawEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitRawEncoder.cxx new file mode 100644 index 0000000000000..133127bb268ca --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitRawEncoder.cxx @@ -0,0 +1,197 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHRawEncoderDigit/DigitRawEncoder.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/Logger.h" +#include "Headers/DAQID.h" +#include "MCHRawCommon/DataFormats.h" +#include "MCHRawElecMap/Mapper.h" +#include "MCHRawEncoderDigit/Digit2ElecMapper.h" +#include "MCHRawEncoderPayload/PayloadPaginator.h" +#include <filesystem> +#include <fmt/format.h> +#include <iostream> +#include <set> + +namespace o2::mch::raw +{ +/** Prepare the rawfilewriter for work. + * + * @tparam ELECMAP : a type describing the electronic mapping of MCH + * @tparam FORMAT : the output raw data format (Bare or UserLogic) + * @tparam CHARGESUM : the output raw data mode (Sample or ChargeSum Mode) + * + * @param fw : the rawFileWriter to configure + * @param opts : processing options + */ +void setupRawFileWriter(o2::raw::RawFileWriter& fw, const std::set<LinkInfo>& links, DigitRawEncoderOptions opt) +{ + fw.useRDHVersion(opt.rdhVersion); + fw.setVerbosity(opt.rawFileWriterVerbosity); + + bool continuous = true; + if (!opt.noGRP) { + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(inputGRP)}; + continuous = grp->isDetContinuousReadOut(o2::detectors::DetID::MCH); + } + fw.setContinuousReadout(continuous); // must be set explicitly + + if (opt.noEmptyHBF) { + fw.setDontFillEmptyHBF(true); + } + + if (!std::filesystem::exists(opt.outputDir)) { + if (!std::filesystem::create_directories(opt.outputDir)) { + LOGP(fatal, "could not create output directory {}", opt.outputDir); + } else { + LOGP(info, "created output directory {}", opt.outputDir); + } + } + + std::string output = fmt::format("{:s}/mch", opt.outputDir); + + // Register the corresponding links (might have several solars for 1 link) + registerLinks(fw, output, links, + opt.splitMode == OutputSplit::PerLink, + opt.splitMode == OutputSplit::PerCruEndpoint); +} + +Solar2LinkInfo getSolar2LinkInfo(bool userLogic, bool dummyElecMap, int userLogicVersion) +{ + // the following cascade is not pretty, but the non-negociable intent is + // to avoid exposing templates to the DigitRawEncoder interface, hence + // this bool to template argument dance. + + if (dummyElecMap) { + if (userLogic) { + if (userLogicVersion == 0) { + return createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, ChargeSumMode, 0>(); + } else if (userLogicVersion == 1) { + return createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, ChargeSumMode, 1>(); + } else { + throw std::invalid_argument("Version can only be 0 or 1"); + } + } else { + return createSolar2LinkInfo<ElectronicMapperDummy, BareFormat, ChargeSumMode, 0>(); + } + } + if (userLogic) { + if (userLogicVersion == 0) { + return createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, ChargeSumMode, 0>(); + } else if (userLogicVersion == 1) { + return createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, ChargeSumMode, 1>(); + } else { + throw std::invalid_argument("Version can only be 0 or 1"); + } + } else { + return createSolar2LinkInfo<ElectronicMapperGenerated, BareFormat, ChargeSumMode, 0>(); + } +} + +Solar2FeeLinkMapper getSolar2FeeLink(bool dummyElecMap) +{ + if (dummyElecMap) { + return createSolar2FeeLinkMapper<ElectronicMapperDummy>(); + } + return createSolar2FeeLinkMapper<ElectronicMapperGenerated>(); +} + +std::set<uint16_t> getSolarUIDs(bool dummyElecMap) +{ + if (dummyElecMap) { + return getSolarUIDs<ElectronicMapperDummy>(); + } + return getSolarUIDs<ElectronicMapperGenerated>(); +} + +std::set<o2::mch::raw::LinkInfo> getLinks(Solar2LinkInfo solar2LinkInfo, bool dummyElecMap) +{ + // Get the list of solarIds and convert it to a list of unique RDH(Any)s + // + // Note that there's not necessarily a one to one correspondence + // between solarIds and FEEID (hence RDH) : + // the most probable format is UserLogic and in that case several + // solars end up in the same RDH/FEEID (readout is basically + // gathering solars per CRU endpoint) + auto solarIds = getSolarUIDs(dummyElecMap); + std::set<LinkInfo> links; + for (auto solarId : solarIds) { + auto li = solar2LinkInfo(solarId); + if (!li.has_value()) { + LOGP(FATAL, "Could not find information about solarId {:d}", solarId); + } + links.insert(li.value()); + } + + LOGP(INFO, "MCH: registered {:d} links for {:d} solars", + links.size(), + solarIds.size()); + return links; +} + +Digit2ElecMapper getDigit2Elec(bool dummyElecMap) +{ + if (dummyElecMap) { + return createDigit2ElecMapper(createDet2ElecMapper<ElectronicMapperDummy>()); + } + return createDigit2ElecMapper(createDet2ElecMapper<ElectronicMapperGenerated>()); +} + +std::ostream& operator<<(std::ostream& os, const DigitRawEncoderOptions& opt) +{ + os << fmt::format("output dir {} filePerLink {} filePerCruEndpoint {} userLogic {} dummyElecMap {} ulVersion {}\n", + opt.outputDir, + opt.splitMode == OutputSplit::PerLink, + opt.splitMode == OutputSplit::PerCruEndpoint, + opt.userLogic, opt.dummyElecMap, opt.userLogicVersion); + return os; +} + +DigitRawEncoder::DigitRawEncoder(DigitRawEncoderOptions opts) + : mOptions{opts}, + mRawFileWriter{o2::header::DAQID(o2::header::DAQID::MCH).getO2Origin()}, + mSolar2LinkInfo{getSolar2LinkInfo(opts.userLogic, opts.dummyElecMap, opts.userLogicVersion)}, + mLinks{getLinks(mSolar2LinkInfo, opts.dummyElecMap)}, + mPayloadEncoder{createPayloadEncoder( + getSolar2FeeLink(opts.dummyElecMap), + opts.userLogic, + opts.userLogicVersion, + opts.chargeSumMode)}, + mDigitPayloadEncoder{getDigit2Elec(opts.dummyElecMap), *(mPayloadEncoder.get())} +{ + setupRawFileWriter(mRawFileWriter, mLinks, opts); +} + +void DigitRawEncoder::addHeartbeats(std::set<DsElecId> dsElecIds, uint32_t orbit) +{ + LOGP(info, "Adding heartbeats for orbit={}", orbit); + mPayloadEncoder->startHeartbeatFrame(orbit, 0); + mPayloadEncoder->addHeartbeatHeaders(dsElecIds); +} + +void DigitRawEncoder::encodeDigits(gsl::span<o2::mch::Digit> digits, uint32_t orbit, uint16_t bc) +{ + LOGP(info, "Encoding {} MCH digits for orbit {} bc {}", digits.size(), orbit, bc); + std::vector<std::byte> buffer; + mDigitPayloadEncoder.encodeDigits(digits, orbit, bc, buffer); + paginate(mRawFileWriter, buffer, mLinks, mSolar2LinkInfo); +} + +void DigitRawEncoder::writeConfig() +{ + mRawFileWriter.writeConfFile("MCH", "RAWDATA", fmt::format("{:s}/MCHraw.cfg", mOptions.outputDir)); +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.cxx deleted file mode 100644 index 1145854439f94..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.cxx +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DigitReader.h" -#include <TFile.h> -#include <TTree.h> -#include <TBranch.h> -#include <limits> -#include "DetectorsRaw/HBFUtils.h" - -namespace o2::mch::raw -{ - -DigitReader::DigitReader(const char* digitTreeFileName) - : mFile(digitTreeFileName) -{ - mFile.GetObject("o2sim", mTree); - mDigitBranch = mTree->GetBranch("MCHDigit"); - mDigitBranch->SetAddress(&mDigits); -} - -void DigitReader::readNextEntry() -{ - assert(mDigitsPerIR.empty()); - - mDigitBranch->GetEntry(mEntry); - mEntry++; - - // builds a list of digits per HBF - const o2::raw::HBFUtils& hbfutils = o2::raw::HBFUtils::Instance(); - - for (auto d : (*mDigits)) { - o2::InteractionTimeRecord ir(d.getTime().sampaTime); - // get the closest (previous) HBF from this IR - // and assign the digits to that one - auto hbf = hbfutils.getIRHBF(hbfutils.getHBF(ir)); - mDigitsPerIR[hbf].push_back(d); - } -} - -bool DigitReader::nextDigits(InteractionRecord& ir, std::vector<o2::mch::Digit>& digits) -{ - if (mIterator == mDigitsPerIR.end()) { - if (mEntry >= mDigitBranch->GetEntries()) { - return false; - } - readNextEntry(); - mIterator = mDigitsPerIR.begin(); - } - ir = mIterator->first; - digits = mIterator->second; - mIterator++; - return true; -} -} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.h deleted file mode 100644 index c8175d5e7dc7c..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitReader.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MCH_RAW_ENCODER_DIGIT_READER_H -#define O2_MCH_RAW_ENCODER_DIGIT_READER_H - -#include <map> -#include <vector> -#include "MCHBase/Digit.h" -#include "CommonDataFormat/InteractionRecord.h" -#include <TFile.h> - -class TTree; -class TBranch; - -namespace o2::mch::raw -{ -class DigitReader -{ - - public: - DigitReader(const char* digitTreeFileName); - - bool nextDigits(InteractionRecord& ir, std::vector<o2::mch::Digit>& digits); - - private: - void readNextEntry(); - - private: - TFile mFile; - TTree* mTree{nullptr}; - TBranch* mDigitBranch{nullptr}; - std::vector<o2::mch::Digit>* mDigits{nullptr}; - size_t mEntry{0}; - std::map<o2::InteractionRecord, std::vector<o2::mch::Digit>> mDigitsPerIR; - std::map<o2::InteractionRecord, std::vector<o2::mch::Digit>>::iterator mIterator{mDigitsPerIR.end()}; -}; -} // namespace o2::mch::raw - -#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.cxx new file mode 100644 index 0000000000000..7b63ac2969e56 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.cxx @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DigitTreeReader.h" +#include <limits> +#include <fmt/format.h> + +namespace o2::mch::raw +{ + +void AssertBranch(ROOT::Internal::TTreeReaderValueBase& value) +{ + if (value.GetSetupStatus() < 0) { + throw std::invalid_argument(fmt::format("Error {} setting up tree reader for branch {}", + value.GetSetupStatus(), value.GetBranchName())); + } +} + +DigitTreeReader::DigitTreeReader(TTree* tree) : mCurrentRof{std::numeric_limits<size_t>::max()} +{ + if (!tree) { + throw std::invalid_argument("cannot work with a null tree pointer"); + } + mTreeReader.SetTree(tree); + mTreeReader.Restart(); + mTreeReader.Next(); + mCurrentRof = 0; + AssertBranch(mDigits); + AssertBranch(mRofs); +} + +bool DigitTreeReader::nextDigits(o2::mch::ROFRecord& rof, std::vector<o2::mch::Digit>& digits) +{ + if (mCurrentRof >= mRofs->size()) { + if (!mTreeReader.Next()) { + return false; + } + mCurrentRof = 0; + } + + if (mRofs->empty()) { + return false; + } + rof = (*mRofs)[mCurrentRof]; + digits.clear(); + auto& tfDigits = *mDigits; + digits.insert(digits.begin(), tfDigits.begin() + rof.getFirstIdx(), tfDigits.begin() + rof.getLastIdx() + 1); + ++mCurrentRof; + return true; +} +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.h new file mode 100644 index 0000000000000..d7845c539caf9 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/DigitTreeReader.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_ENCODER_DIGIT_TREE_READER_H +#define O2_MCH_RAW_ENCODER_DIGIT_TREE_READER_H + +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include <TTreeReader.h> +#include <vector> + +namespace o2::mch::raw +{ +class DigitTreeReader +{ + public: + DigitTreeReader(TTree* tree); + + bool nextDigits(o2::mch::ROFRecord& rof, std::vector<o2::mch::Digit>& digits); + + private: + TTreeReader mTreeReader; + TTreeReaderValue<std::vector<o2::mch::Digit>> mDigits = {mTreeReader, "MCHDigit"}; + TTreeReaderValue<std::vector<o2::mch::ROFRecord>> mRofs = {mTreeReader, "MCHROFRecords"}; + size_t mCurrentRof; +}; +} // namespace o2::mch::raw + +#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/README.md b/Detectors/MUON/MCH/Raw/Encoder/Digit/README.md index e68ec344bb7a2..5a49cfefd68b0 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/README.md +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/README.md @@ -2,16 +2,19 @@ \page refDetectorsMUONMCHRawEncoderDigit Digit Conversion /doxy --> -## Basic usage +# MCH Digit to Raw Conversion - o2-mch-digit2raw --input-file mchdigits.root + o2-mch-digits-to-raw --input-file mchdigits.root By default (at least currently) there's only one output file, named `mch.raw` in the current directory. The output directory can be changed using the `--output-dir` option. +You can also get one file per link using the `--file-per-link` option, in which + case the output files are named `mch_feeid####.raw`. + If you do not have a digit file at hand, for testing purposes you can do any kind of simulation and digitization containing MCH, e.g. o2-sim -g fwmugen -m MCH -n 10 - o2-sim-digitizer-workflow + o2-sim-digitizer-workflow --onlyDet MCH -b diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2json.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2json.cxx deleted file mode 100644 index 2defbeb30ef7f..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2json.cxx +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "MCHBase/Digit.h" -#include "MCHRawElecMap/Mapper.h" -#include <boost/program_options.hpp> -#include <fmt/format.h> -#include <iostream> -#include <rapidjson/document.h> -#include <rapidjson/ostreamwrapper.h> -#include <rapidjson/stringbuffer.h> -#include <rapidjson/writer.h> -#include <string> -#include "DigitEncoder.h" -#include "DigitReader.h" - -namespace po = boost::program_options; -using namespace o2::mch::raw; - -std::string digitIdAsString(const o2::mch::Digit& digit, - const Digit2ElecMapper& digit2elec) -{ - auto optElecId = digit2elec(digit); - if (!optElecId.has_value()) { - return "UNKNOWN"; - } - auto dsElecId = optElecId.value().first; - auto dschid = optElecId.value().second; - return fmt::format("{}-CH{}", asString(dsElecId), dschid); -} - -void outputToJson(const std::vector<o2::mch::Digit>& digits, - std::function<std::optional<DsElecId>(DsDetId)> det2elec, - rapidjson::Writer<rapidjson::OStreamWrapper>& writer) - -{ - - auto digit2elec = createDigit2ElecMapper(det2elec); - - writer.StartArray(); - for (auto d : digits) { - auto sid = digitIdAsString(d, digit2elec); - if (sid == "UNKNOWN") { - continue; - } - writer.StartObject(); - writer.Key("id"); - writer.String(sid.c_str()); - writer.Key("adc"); - writer.Int(d.getADC()); - writer.EndObject(); - } - writer.EndArray(); -} - -int main(int argc, char* argv[]) -{ - po::options_description generic("options"); - bool dummyElecMap{false}; - std::string input; - po::variables_map vm; - - // clang-format off - generic.add_options() - ("help,h", "produce help message") - ("dummyElecMap,d",po::bool_switch(&dummyElecMap),"use a dummy electronic mapping (for testing only)") - ("infile,i",po::value<std::string>(&input)->required(),"input file name"); - // clang-format on - - po::options_description cmdline; - cmdline.add(generic); - - po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); - - if (vm.count("help")) { - std::cout << generic << "\n"; - return 2; - } - - try { - po::notify(vm); - } catch (boost::program_options::error& e) { - std::cout << "Error: " << e.what() << "\n"; - exit(1); - } - - po::notify(vm); - - auto det2elec = (dummyElecMap ? createDet2ElecMapper<ElectronicMapperDummy>() : createDet2ElecMapper<ElectronicMapperGenerated>()); - - rapidjson::OStreamWrapper osw(std::cout); - rapidjson::Writer<rapidjson::OStreamWrapper> writer(osw); - - o2::InteractionRecord ir; - std::vector<o2::mch::Digit> digits; - DigitReader dr(input.c_str()); - - while (dr.nextDigits(ir, digits)) { - writer.StartObject(); - writer.Key("orbit"); - writer.Int(ir.orbit); - writer.Key("bc"); - writer.Int(ir.bc); - writer.Key("digits"); - outputToJson(digits, det2elec, writer); - writer.EndObject(); - return 0; - } -} diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2raw.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2raw.cxx deleted file mode 100644 index df1c9d4d01ab1..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Digit/digit2raw.cxx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "CommonDataFormat/InteractionRecord.h" -#include "DetectorsRaw/RawFileWriter.h" -#include "DigitEncoder.h" -#include "DigitReader.h" -#include "Framework/Logger.h" -#include "Headers/RAWDataHeader.h" -#include "MCHBase/Digit.h" -#include "MCHRawCommon/DataFormats.h" -#include "MCHRawElecMap/Mapper.h" -#include "MCHRawEncoderPayload/DataBlock.h" -#include "MCHRawEncoderPayload/PayloadPaginator.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsCommonDataFormats/NameConf.h" - -#include <TBranch.h> -#include <TFile.h> -#include <TSystem.h> -#include <TTree.h> -#include <boost/program_options.hpp> -#include <fmt/format.h> -#include <fstream> -#include <iostream> -#include <limits> -#include <string> - -namespace po = boost::program_options; -using namespace o2::mch::raw; - -namespace -{ -std::string asString(const o2::InteractionRecord& ir) -{ - return fmt::format("ORB {:6d} BC {:4d}", - ir.orbit, ir.bc); -} - -std::string asString(const o2::InteractionTimeRecord& ir) -{ - return asString(static_cast<o2::InteractionRecord>(ir)); -} -} // namespace - -std::ostream& operator<<(std::ostream& os, const o2::mch::Digit& d) -{ - os << fmt::format("DE {:4d} PADUID {:8d} ADC {:6d} TS {:g}", - d.getDetID(), d.getPadID(), d.getADC(), - d.getTime().sampaTime); - return os; -} - -void digit2raw(const std::string& input, - DigitEncoder& encoder, - PayloadPaginator& paginate) -{ - o2::InteractionRecord ir; - std::vector<o2::mch::Digit> digits; - DigitReader dr(input.c_str()); - - while (dr.nextDigits(ir, digits)) { - - std::vector<std::byte> buffer; - - encoder(digits, buffer, ir.orbit, ir.bc); - - paginate(buffer); - } -} - -int main(int argc, char* argv[]) -{ - po::options_description generic("options"); - bool userLogic{false}; - bool dummyElecMap{false}; - bool chargeSumMode{true}; - std::string input; - po::variables_map vm; - - // clang-format off - generic.add_options() - ("help,h", "produce help message") - ("userLogic,u",po::bool_switch(&userLogic),"user logic format") - ("dummyElecMap,d",po::bool_switch(&dummyElecMap),"use a dummy electronic mapping (for testing only)") - ("output-dir,o",po::value<std::string>()->default_value("./"),"output directory for file(s)") - ("input-file,i",po::value<std::string>(&input)->default_value("mchdigits.root"),"input file name") - ("configKeyValues", po::value<std::string>()->default_value(""), "comma-separated configKeyValues") - ("no-empty-hbf,e", po::value<bool>()->default_value(true), "do not create empty HBF pages (except for HBF starting TF)") - ("verbosity,v",po::value<std::string>()->default_value("verylow"), "(fair)logger verbosity"); - // clang-format on - - po::options_description cmdline; - cmdline.add(generic); - - po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); - - if (vm.count("help")) { - std::cout << generic << "\n"; - return 2; - } - - try { - po::notify(vm); - } catch (boost::program_options::error& e) { - std::cout << "Error: " << e.what() << "\n"; - exit(1); - } - - po::notify(vm); - - o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); - - if (vm.count("verbosity")) { - fair::Logger::SetVerbosity(vm["verbosity"].as<std::string>()); - } - - if (dummyElecMap) { - std::cout << "WARNING: using dummy electronic mapping\n"; - } - - auto det2elec = (dummyElecMap ? createDet2ElecMapper<ElectronicMapperDummy>() : createDet2ElecMapper<ElectronicMapperGenerated>()); - - DigitEncoder encoder = createDigitEncoder(userLogic, det2elec); - - auto solar2feelink = (dummyElecMap ? createSolar2FeeLinkMapper<ElectronicMapperDummy>() : createSolar2FeeLinkMapper<ElectronicMapperGenerated>()); - - o2::raw::RawFileWriter fw(o2::header::DAQID(o2::header::DAQID::MCH).getO2Origin()); - - std::string inputGRP = o2::base::NameConf::getGRPFileName(); - std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(inputGRP)}; - fw.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::MCH)); // must be set explicitly - - if (vm["no-empty-hbf"].as<bool>()) { - fw.setDontFillEmptyHBF(true); - } - - auto outDirName = vm["output-dir"].as<std::string>(); - - if (gSystem->AccessPathName(outDirName.c_str())) { - if (gSystem->mkdir(outDirName.c_str(), kTRUE)) { - LOG(FATAL) << "could not create output directory " << outDirName; - } else { - LOG(INFO) << "created output directory " << outDirName; - } - } - - fw.writeConfFile("MCH", "RAWDATA", fmt::format("{}/MCHraw.cfg", outDirName)); - - std::string output = fmt::format("{}/mch.raw", outDirName); - PayloadPaginator paginator(fw, output, solar2feelink, userLogic, chargeSumMode); - - digit2raw(input, encoder, paginator); - - return 0; -} diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-json.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-json.cxx new file mode 100644 index 0000000000000..3ac08ab8aab55 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-json.cxx @@ -0,0 +1,126 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsMCH/Digit.h" +#include "MCHRawEncoderDigit/Digit2ElecMapper.h" +#include "DigitTreeReader.h" +#include "MCHRawElecMap/Mapper.h" +#include <TFile.h> +#include <boost/program_options.hpp> +#include <fmt/format.h> +#include <iostream> +#include <rapidjson/document.h> +#include <rapidjson/ostreamwrapper.h> +#include <rapidjson/stringbuffer.h> +#include <rapidjson/writer.h> +#include <string> + +namespace po = boost::program_options; +using namespace o2::mch::raw; + +std::string digitIdAsString(const o2::mch::Digit& digit, + const Digit2ElecMapper& digit2elec) +{ + auto optElecId = digit2elec(digit); + if (!optElecId.has_value()) { + return "UNKNOWN"; + } + auto dsElecId = optElecId.value().first; + auto dschid = optElecId.value().second; + return fmt::format("{}-CH{}", asString(dsElecId), dschid); +} + +void outputToJson(const std::vector<o2::mch::Digit>& digits, + std::function<std::optional<DsElecId>(DsDetId)> det2elec, + rapidjson::Writer<rapidjson::OStreamWrapper>& writer) + +{ + + auto digit2elec = createDigit2ElecMapper(det2elec); + + writer.StartArray(); + for (auto d : digits) { + auto sid = digitIdAsString(d, digit2elec); + if (sid == "UNKNOWN") { + continue; + } + writer.StartObject(); + writer.Key("id"); + writer.String(sid.c_str()); + writer.Key("adc"); + writer.Int(d.getADC()); + writer.EndObject(); + } + writer.EndArray(); +} + +int main(int argc, char* argv[]) +{ + po::options_description generic("options"); + bool dummyElecMap{false}; + std::string input; + po::variables_map vm; + + // clang-format off + generic.add_options() + ("help,h", "produce help message") + ("dummyElecMap,d",po::bool_switch(&dummyElecMap),"use a dummy electronic mapping (for testing only)") + ("infile,i",po::value<std::string>(&input)->required(),"input file name"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << generic << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + po::notify(vm); + + auto det2elec = (dummyElecMap ? createDet2ElecMapper<ElectronicMapperDummy>() : createDet2ElecMapper<ElectronicMapperGenerated>()); + + rapidjson::OStreamWrapper osw(std::cout); + rapidjson::Writer<rapidjson::OStreamWrapper> writer(osw); + + TFile fin(input.c_str()); + if (!fin.IsOpen()) { + return 3; + } + TTree* tree = static_cast<TTree*>(fin.Get("o2sim")); + if (!tree) { + return 4; + } + o2::mch::ROFRecord rof; + std::vector<o2::mch::Digit> digits; + DigitTreeReader dr(tree); + + while (dr.nextDigits(rof, digits)) { + writer.StartObject(); + writer.Key("orbit"); + writer.Int(rof.getBCData().orbit); + writer.Key("bc"); + writer.Int(rof.getBCData().bc); + writer.Key("digits"); + outputToJson(digits, det2elec, writer); + writer.EndObject(); + } + return 0; +} diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-raw.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-raw.cxx new file mode 100644 index 0000000000000..aafc058de3fe4 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/digits-to-raw.cxx @@ -0,0 +1,159 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DigitTreeReader.h" +#include "Framework/Logger.h" +#include "MCHRawEncoderDigit/DigitRawEncoder.h" +#include <TBranch.h> +#include <TFile.h> +#include <TTree.h> +#include <boost/program_options.hpp> +#include <filesystem> +#include <fmt/format.h> +#include <fstream> +#include <iostream> +#include <limits> +#include <string> + +/** Program to convert MCH digits to MCH Raw data. +* +* Typical usage : +* +* o2-mch-digits-to-raw --input-file mchdigits.root --file-for link +* +* Note: the dummy-elecmap adds some complexity here, +* but is used as a mean to get the electronic mapping for the whole detector +* (as opposed to just the parts that are currently installed at Pt2). +* It will be removed when the actual electronic mapping +* (ElectronicMapperGenerated) is completed. +* +*/ + +namespace po = boost::program_options; +using namespace o2::mch::raw; + +int main(int argc, char* argv[]) +{ + po::options_description generic("options"); + std::string input; + po::variables_map vm; + + // clang-format off + generic.add_options() + ("help,h", "produce help message") + ("userLogic,u",po::bool_switch()->default_value(true),"user logic format") + ("dummy-elecmap,d",po::bool_switch()->default_value(false),"use a dummy electronic mapping (for testing only, to be removed at some point)") + ("output-dir,o",po::value<std::string>()->default_value("./"),"output directory for file(s)") + ("file-for,f", po::value<std::string>()->default_value("all"), "output one file (file-for=all), per link (file-for=link) or per cru end point (file-for=cru)") + ("input-file,i",po::value<std::string>(&input)->default_value("mchdigits.root"),"input file name") + ("configKeyValues", po::value<std::string>()->default_value(""), "comma-separated configKeyValues") + ("no-empty-hbf,e", po::value<bool>()->default_value(false), "do not create empty HBF pages (except for HBF starting TF)") + ("raw-file-writer-verbosity,v", po::value<int>()->default_value(0), "verbosity level of the RawFileWriter") + ("hbfutils-config", po::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)") + ("rdh-version,r", po::value<int>()->default_value(o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>()), "RDH version to use") + ("verbosity,v",po::value<std::string>()->default_value("verylow"), "(fair)logger verbosity"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << generic << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + po::notify(vm); + + // first things first : check the input path actually exists + std::ifstream in(input); + if (!in) { + LOGF(FATAL, "could not open input file {}", input); + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + + if (vm.count("verbosity")) { + fair::Logger::SetVerbosity(vm["verbosity"].as<std::string>()); + } + + o2::mch::raw::DigitRawEncoderOptions opts; + + opts.noEmptyHBF = vm["no-empty-hbf"].as<bool>(); + opts.outputDir = vm["output-dir"].as<std::string>(); + auto fileFor = vm["file-for"].as<std::string>(); + if (fileFor == "link") { + opts.splitMode = OutputSplit::PerLink; + } else if (fileFor == "cru") { + opts.splitMode = OutputSplit::PerCruEndpoint; + } else if (fileFor == "all") { + opts.splitMode = OutputSplit::None; + } else { + throw po::validation_error(po::validation_error::invalid_option_value, "file-for"); + } + opts.userLogic = vm["userLogic"].as<bool>(); + opts.dummyElecMap = vm["dummy-elecmap"].as<bool>(); + opts.rawFileWriterVerbosity = vm["raw-file-writer-verbosity"].as<int>(); + opts.rdhVersion = vm["rdh-version"].as<int>(); + + o2::mch::raw::DigitRawEncoder dre(opts); + + TFile fin(input.c_str()); + if (!fin.IsOpen()) { + std::cout << "Can not open Root input file " << input << "\n"; + return -1; + } + TTree* tree = static_cast<TTree*>(fin.Get("o2sim")); + if (!tree) { + std::cout << "Can not get input tree o2sim from file " << input << "\n"; + return -2; + } + + DigitTreeReader dr(tree); + + // here we implicitely assume that this digits-to-raw is only called for + // one timeframe so it's easy to detect the TF start... + uint32_t firstOrbitOfRun = o2::raw::HBFUtils::Instance().orbitFirst; + auto dsElecIds = opts.dummyElecMap ? getAllDs<ElectronicMapperDummy>() : getAllDs<ElectronicMapperGenerated>(); + dre.addHeartbeats(dsElecIds, firstOrbitOfRun); + + o2::mch::ROFRecord rof; + std::vector<o2::mch::Digit> digits; + + // Loop over digits (grouped per ROF) and encode them + while (dr.nextDigits(rof, digits)) { + if (rof.getNEntries() != digits.size()) { + LOGP(error, "Inconsistent rof number of entries {} != number of digits {}", rof.getNEntries(), digits.size()); + } + dre.encodeDigits(digits, rof.getBCData().orbit, rof.getBCData().bc); + } + + // write raw files configuration so it can be used to easily read them back + dre.writeConfig(); + + return 0; +} diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/Digit2ElecMapper.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/Digit2ElecMapper.h new file mode 100644 index 0000000000000..f4f7003dbcc79 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/Digit2ElecMapper.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_ENCODER_DIGIT_TO_ELECMAPPER_H +#define O2_MCH_RAW_ENCODER_DIGIT_TO_ELECMAPPER_H + +#include "MCHRawElecMap/Mapper.h" +#include "MCHRawElecMap/DsDetId.h" +#include "MCHRawElecMap/DsElecId.h" +#include "DataFormatsMCH/Digit.h" +#include <cstdint> +#include <functional> +#include <optional> +#include <utility> + +namespace o2::mch::raw +{ + +using Digit2ElecMapper = std::function<std::optional<std::pair<DsElecId, int>>(const o2::mch::Digit& digit)>; + +Digit2ElecMapper createDigit2ElecMapper(Det2ElecMapper d2e); +} // namespace o2::mch::raw + +#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitPayloadEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitPayloadEncoder.h new file mode 100644 index 0000000000000..011cf94f95172 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitPayloadEncoder.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_ENCODER_DIGIT_PAYLOAD_ENCODER_H +#define O2_MCH_RAW_ENCODER_DIGIT_PAYLOAD_ENCODER_H + +#include "DataFormatsMCH/Digit.h" +#include "MCHRawElecMap/Mapper.h" +#include <cstdint> +#include <functional> +#include <gsl/span> +#include <optional> +#include "MCHRawEncoderPayload/PayloadEncoder.h" +#include "MCHRawEncoderDigit/Digit2ElecMapper.h" + +/** DigitPayloadEncoder encodes MCH digits into memory buffers that + * contain the MCH RawData Payload and a very slim information + * about the {orbit,bc} for each payload. That {orbit,bc} is then + * used by the PayloadPaginator to create Raw Data in the actual + * Alice format, i.e. using RDH (RawDataHeader) + payload blocks. + */ + +namespace o2::mch::raw +{ + +class DigitPayloadEncoder +{ + public: + DigitPayloadEncoder(Digit2ElecMapper digit2elec, PayloadEncoder& encoder); + + void encodeDigits(gsl::span<o2::mch::Digit> digits, + uint32_t orbit, + uint16_t bc, + std::vector<std::byte>& buffer); + + private: + Digit2ElecMapper mDigit2ElecMapper; + PayloadEncoder& mEncoder; +}; + +} // namespace o2::mch::raw +#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitRawEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitRawEncoder.h new file mode 100644 index 0000000000000..8d8273b41b965 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/include/MCHRawEncoderDigit/DigitRawEncoder.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_RAW_ENCODER_DIGIT_RAW_ENCODER_H +#define O2_MCH_RAW_ENCODER_DIGIT_RAW_ENCODER_H + +#include "DataFormatsMCH/Digit.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "MCHRawElecMap/DsElecId.h" +#include "MCHRawEncoderPayload/PayloadEncoder.h" +#include "MCHRawEncoderDigit/DigitPayloadEncoder.h" +#include "MCHRawEncoderPayload/PayloadPaginator.h" +#include <cstdint> +#include <functional> +#include <gsl/span> +#include <set> +#include <string> + +/** DigitRawEncoder converts MCH digits into raw data. */ + +namespace o2::mch::raw +{ + +enum class OutputSplit : int { + None, // no splitting, i.e. one file for all + PerLink, // one file per link + PerCruEndpoint // one file per CRU endpoint +}; + +struct DigitRawEncoderOptions { + std::string outputDir = "."; // directory where the raw data files will be written + bool chargeSumMode = true; // whether to encode only charge sum or all samples (usually true) + OutputSplit splitMode = OutputSplit::PerLink; // how to organize raw output file(s) + bool userLogic = true; // whether or not to use user logic (usually true) + int userLogicVersion = 1; // UL version (only relevant if userLogic=true) + bool noEmptyHBF = false; // disable writing of empty HBFs (for debug) + bool noGRP = false; // do not try to read GRP information (for debug or unit tests) + bool dummyElecMap = false; // use dummy electronic mapping (for debug only, temporary) + bool writeHB = true; // write Heatbeat headers at start of time frame + int rawFileWriterVerbosity = 0; // verbosity of the RawFileWriter + int rdhVersion = 6; // RDH version to use +}; + +class DigitRawEncoder +{ + public: + DigitRawEncoder(DigitRawEncoderOptions opt = {}); + + void addHeartbeats(std::set<DsElecId> dsElecIds, uint32_t orbit); + + void encodeDigits(gsl::span<o2::mch::Digit> digits, uint32_t orbit, uint16_t bc); + + void writeConfig(); + + private: + DigitRawEncoderOptions mOptions; + o2::raw::RawFileWriter mRawFileWriter; + Solar2LinkInfo mSolar2LinkInfo; + std::set<LinkInfo> mLinks; + std::unique_ptr<PayloadEncoder> mPayloadEncoder; + DigitPayloadEncoder mDigitPayloadEncoder; +}; + +} // namespace o2::mch::raw +#endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Digit/testDigitTreeReader.cxx b/Detectors/MUON/MCH/Raw/Encoder/Digit/testDigitTreeReader.cxx new file mode 100644 index 0000000000000..12d2dddfdd326 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Digit/testDigitTreeReader.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE MCH DigitTreeReader +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include "DigitTreeReader.h" +#include <TFile.h> +#include <TTree.h> +#include "CommonDataFormat/InteractionRecord.h" +#include <vector> +#include <memory> + +using namespace o2::mch; +using namespace o2::mch::raw; + +std::unique_ptr<TTree> createTestTree() +{ + auto tree = std::make_unique<TTree>(); + + tree->SetName("o2sim"); + + std::vector<Digit>* digits = new std::vector<Digit>(); + std::vector<ROFRecord>* rofs = new std::vector<ROFRecord>(); + + tree->Branch("MCHDigit", digits); + tree->Branch("MCHROFRecords", rofs); + + constexpr int ndigits{10}; + + for (auto i = 0; i < ndigits; i++) { + digits->emplace_back(100, i, i * 10, 0); + } + + rofs->emplace_back(o2::InteractionRecord{1234, 42}, 0, 2); + rofs->emplace_back(o2::InteractionRecord{1234, 43}, 4, 3); + rofs->emplace_back(o2::InteractionRecord{1234, 44}, 7, 4); + + tree->Fill(); + + digits->clear(); + rofs->clear(); + tree->Fill(); + tree->Fill(); + return tree; +} + +BOOST_AUTO_TEST_CASE(NofEntriesIsNumberOfTFIs3) +{ + auto tree = createTestTree(); + BOOST_CHECK_EQUAL(tree->GetEntries(), 3); + TFile f("toto.root", "RECREATE"); + tree->Write("o2sim"); +} + +BOOST_AUTO_TEST_CASE(NofDigitsOfFirstRofIs2) +{ + std::vector<Digit> digits; + o2::mch::ROFRecord rof; + auto tree = createTestTree(); + DigitTreeReader dtr(tree.get()); + dtr.nextDigits(rof, digits); + BOOST_CHECK_EQUAL(digits.size(), 2); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfDigitAndRofBranchesDoNotExist) +{ + TTree emptyTree("emptyTree", "no branch at all"); + BOOST_CHECK_THROW(DigitTreeReader dtr(&emptyTree), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfInputTreeIsNullptr) +{ + BOOST_CHECK_THROW(DigitTreeReader dtr(nullptr), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfRofBranchIsMissing) +{ + TTree missingRofs("missingRofs", "MCHDigit branch alone"); + std::vector<o2::mch::Digit> digits; + missingRofs.Branch("MCHDigit", &digits); + BOOST_CHECK_THROW(DigitTreeReader dtr(&missingRofs), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfDigitBranchIsMissing) +{ + TTree missingDigits("missingDigits", "MCHROFRecords branch alone"); + std::vector<o2::mch::ROFRecord> rofs; + missingDigits.Branch("MCHROFRecords", &rofs); + BOOST_CHECK_THROW(DigitTreeReader dtr(&missingDigits), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfDigitBranchIsOfTheWrongType) +{ + TTree invalidDigits("invalidDigits", "MCHDigit branch present but of wrong type"); + std::vector<o2::mch::ROFRecord> rofs; + invalidDigits.Branch("MCHDigit", &rofs); // setting wrong type on purpose + invalidDigits.Branch("MCHROFRecords", &rofs); + invalidDigits.Fill(); + BOOST_CHECK_THROW(DigitTreeReader dtr(&invalidDigits), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfRofBranchIsOfTheWrongType) +{ + TTree invalidRofs("invalidRofs", "MCHROFRecords branch present but of wrong type"); + std::vector<o2::mch::Digit> digits; + invalidRofs.Branch("MCHDigit", &digits); + invalidRofs.Branch("MCHROFRecords", &digits); // setting wrong type on purpose + invalidRofs.Fill(); + BOOST_CHECK_THROW(DigitTreeReader dtr(&invalidRofs), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustThrowIfNoEntry) +{ + TTree noEntry("noEntry", "All branches correct but no entry"); + std::vector<o2::mch::Digit> digits; + std::vector<o2::mch::ROFRecord> rofs; + noEntry.Branch("MCHDigit", &digits); + noEntry.Branch("MCHROFRecords", &rofs); + BOOST_CHECK_THROW(DigitTreeReader dtr(&noEntry), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(DigitTreeReaderMustNotThrowIfInputTreeHasAllBranchesAndAtLeastOneEntry) +{ + TTree correct("noEntry", "All branches correct but no entry"); + std::vector<o2::mch::Digit> digits; + std::vector<o2::mch::ROFRecord> rofs; + correct.Branch("MCHDigit", &digits); + correct.Branch("MCHROFRecords", &rofs); + correct.Fill(); + BOOST_CHECK_NO_THROW(DigitTreeReader dtr(&correct)); +} diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.cxx new file mode 100644 index 0000000000000..ae0d49d21c3d9 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.cxx @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "BareElinkEncoder.h" + +namespace o2::mch::raw +{ + +template <> +void ElinkEncoder<BareFormat, ChargeSumMode>::appendCharges(const SampaCluster& sc) +{ + append20(sc.chargeSum); +} + +template <> +void ElinkEncoder<BareFormat, SampleMode>::appendCharges(const SampaCluster& sc) +{ + for (auto& s : sc.samples) { + append10(s); + } +} + +} // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.h index 479f7b36ad2b9..766f1fe6a91fa 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -53,6 +54,8 @@ class ElinkEncoder<BareFormat, CHARGESUM> /// of this channel within one Sampa time window. void addChannelData(uint8_t chId, const std::vector<SampaCluster>& data); + void addHeartbeat(uint20_t bunchCrossing); + /// Empty the bit stream. void clear(); @@ -142,6 +145,14 @@ void ElinkEncoder<BareFormat, CHARGESUM>::addChannelData(uint8_t chId, const std } } +template <typename CHARGESUM> +void ElinkEncoder<BareFormat, CHARGESUM>::addHeartbeat(uint20_t bunchCrossing) +{ + uint8_t chipAddress = impl::computeChipAddress(mElinkId, 0); + SampaHeader sh = sampaHeartbeat(chipAddress, bunchCrossing); + append50(sh.uint64()); +} + /// append the data of a SampaCluster template <typename CHARGESUM> void ElinkEncoder<BareFormat, CHARGESUM>::append(const SampaCluster& sc) @@ -151,20 +162,6 @@ void ElinkEncoder<BareFormat, CHARGESUM>::append(const SampaCluster& sc) appendCharges(sc); } -template <> -void ElinkEncoder<BareFormat, ChargeSumMode>::appendCharges(const SampaCluster& sc) -{ - append20(sc.chargeSum); -} - -template <> -void ElinkEncoder<BareFormat, SampleMode>::appendCharges(const SampaCluster& sc) -{ - for (auto& s : sc.samples) { - append10(s); - } -} - /// append one bit (either set or unset) template <typename CHARGESUM> void ElinkEncoder<BareFormat, CHARGESUM>::append(bool value) diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoderMerger.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoderMerger.h index b599eebefadd7..182736e724b6c 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoderMerger.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/BareElinkEncoderMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.cxx index e1c8908439509..e614cbd75a18b 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.h index 3de2bf6fe0b47..5ddacf92bb739 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/BitSet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Encoder/Payload/CMakeLists.txt index 45fab4e318dd9..fc6f7b1fa6cc5 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/CMakeLists.txt @@ -1,15 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHRawEncoderPayload SOURCES + BareElinkEncoder.cxx BitSet.cxx DataBlock.cxx PayloadEncoder.cxx diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/DataBlock.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/DataBlock.cxx index b0181c87c5086..604b8c8b9e708 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/DataBlock.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/DataBlock.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoder.h index 91beb82a42fb3..4e7c1047ffa5a 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoder.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ namespace o2::mch::raw { -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION = 0> class ElinkEncoder; } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoderMerger.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoderMerger.h index e1bd00c38194c..a57b9f6bb54d0 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoderMerger.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoderMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,13 +18,13 @@ namespace o2::mch::raw { -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION> struct ElinkEncoder; -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION = 0> struct ElinkEncoderMerger { void operator()(uint16_t gbtId, - gsl::span<ElinkEncoder<FORMAT, CHARGESUM>> elinks, + gsl::span<ElinkEncoder<FORMAT, CHARGESUM, VERSION>> elinks, std::vector<uint64_t>& b64); }; diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.cxx index 7430009764cc0..12d6d6cbe6bea 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ namespace o2::mch::raw::impl { -uint16_t chipAddress(uint8_t elinkId, uint8_t chId) +uint16_t computeChipAddress(uint8_t elinkId, DualSampaChannelId chId) { auto opt = o2::mch::raw::indexFromElinkId(elinkId); if (!opt.has_value()) { @@ -30,7 +31,7 @@ uint16_t chipAddress(uint8_t elinkId, uint8_t chId) /// The vector of SampaCluster is assumed to be valid, i.e. : /// - all clusters are all of the same kind (ChargeSumMode or SampleMode) /// - all clusters have the same bunchCrossingCounter -SampaHeader buildSampaHeader(uint8_t elinkId, uint8_t chId, gsl::span<const SampaCluster> data) +SampaHeader buildSampaHeader(uint8_t elinkId, DualSampaChannelId chId, gsl::span<const SampaCluster> data) { assertIsInRange("chId", chId, 0, 63); @@ -47,14 +48,13 @@ SampaHeader buildSampaHeader(uint8_t elinkId, uint8_t chId, gsl::span<const Samp } assertNofBits("nof10BitWords", n10, 10); header.nof10BitWords(n10); - header.chipAddress(chipAddress(elinkId, chId)); + header.chipAddress(computeChipAddress(elinkId, chId)); header.channelAddress(chId % 32); - header.hammingCode(computeHammingCode(header.uint64())); - header.headerParity(computeHeaderParity(header.uint64())); assertNofBits("bunchCrossingCounter", bunchCrossingCounter, 20); header.bunchCrossingCounter(bunchCrossingCounter); - - // FIXME: compute payload parity + // compute the hamming code and parity at last + header.headerParity(computeHeaderParity(header.uint64())); + header.hammingCode(computeHammingCode(header.uint64())); return header; } @@ -72,7 +72,6 @@ uint64_t build64(uint16_t a10, uint16_t b10 = 0, uint16_t c10 = 0, uint16_t d10 (static_cast<uint64_t>(e10)); } -// ensures the buffer size is a multiple of 5 void addPadding(std::vector<uint10_t>& b10) { while (b10.size() % 5) { @@ -118,16 +117,21 @@ void append(std::vector<uint10_t>& b10, uint50_t value) b10.emplace_back((value & 0x3FF0000000000) >> 40); } +void appendSync(std::vector<uint10_t>& b10) +{ + addPadding(b10); + append(b10, sampaSyncWord); +} + void fillUserLogicBuffer10(std::vector<uint10_t>& b10, gsl::span<const SampaCluster> clusters, uint8_t elinkId, - uint8_t chId, + DualSampaChannelId chId, bool addSync) { auto sh = buildSampaHeader(elinkId, chId, clusters); if (addSync) { - addPadding(b10); - append(b10, sampaSyncWord); + appendSync(b10); } append(b10, sh.uint64()); bufferizeClusters(clusters, b10); diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.h index f1072aad1c5d6..8fb1265123ca7 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/EncoderImplHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,16 +26,25 @@ namespace impl { void append(std::vector<uint10_t>& b10, uint50_t value); -SampaHeader buildSampaHeader(uint8_t elinkId, uint8_t chId, gsl::span<const SampaCluster> data); +SampaHeader buildSampaHeader(uint8_t elinkId, DualSampaChannelId chId, + gsl::span<const SampaCluster> data); void fillUserLogicBuffer10(std::vector<uint10_t>& b10, gsl::span<const SampaCluster> clusters, uint8_t elinkId, - uint8_t chId, + DualSampaChannelId chId, bool addSync); void b10to64(std::vector<uint10_t> b10, std::vector<uint64_t>& b64, uint16_t prefix14); +uint16_t computeChipAddress(uint8_t elinkId, DualSampaChannelId chId); + +// ensures the buffer size is a multiple of 50 bits +void addPadding(std::vector<uint10_t>& b10); + +// append Sampa sync word to the 10-bits buffer +void appendSync(std::vector<uint10_t>& b10); + } // namespace impl } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/GBTEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/GBTEncoder.h index 9577bdeaed034..ead33bd3e5f7c 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/GBTEncoder.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/GBTEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ namespace o2::mch::raw /// /// \nosubgrouping -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION = 0> class GBTEncoder { public: @@ -57,6 +58,12 @@ class GBTEncoder /// \param data vector of SampaCluster objects void addChannelData(uint8_t elinkGroupId, uint8_t elinkIndexInGroup, uint8_t chId, const std::vector<SampaCluster>& data); + /// add a Heartbeat (HB) packet for a given dual sampa + /// \param elinkGroupId 0..7 + /// \param elinkIndexInGroup 0..4 + /// \param bunchcrossing local (to sampa) bunch crossing + void addHeartbeat(uint8_t elinkGroupId, uint8_t elinkIndexInGroup, uint20_t bunchCrossing); + /// reset local bunch-crossing counter. /// /// (the one that is used in the sampa headers) @@ -84,10 +91,10 @@ class GBTEncoder size_t size() const { return mGbtWords.size(); } private: - uint16_t mLinkId; //< id of this GBT (0..11) - std::array<ElinkEncoder<FORMAT, CHARGESUM>, 40> mElinks; //< the 40 Elinks we manage - std::vector<uint64_t> mGbtWords; //< the GBT words (each GBT word of 80 bits is represented by 2 64 bits words) we've accumulated so far - ElinkEncoderMerger<FORMAT, CHARGESUM> mElinkMerger; + uint16_t mLinkId; //< id of this GBT (0..11) + std::array<ElinkEncoder<FORMAT, CHARGESUM, VERSION>, 40> mElinks; //< the 40 Elinks we manage + std::vector<uint64_t> mGbtWords; //< the GBT words (each GBT word of 80 bits is represented by 2 64 bits words) we've accumulated so far + ElinkEncoderMerger<FORMAT, CHARGESUM, VERSION> mElinkMerger; }; inline int phase(int i, bool forceNoPhase) @@ -107,22 +114,22 @@ inline int phase(int i, bool forceNoPhase) return -1; } -template <typename FORMAT, typename CHARGESUM> -bool GBTEncoder<FORMAT, CHARGESUM>::forceNoPhase = false; +template <typename FORMAT, typename CHARGESUM, int VERSION> +bool GBTEncoder<FORMAT, CHARGESUM, VERSION>::forceNoPhase = false; -template <typename FORMAT, typename CHARGESUM> -GBTEncoder<FORMAT, CHARGESUM>::GBTEncoder(uint16_t linkId) +template <typename FORMAT, typename CHARGESUM, int VERSION> +GBTEncoder<FORMAT, CHARGESUM, VERSION>::GBTEncoder(uint16_t linkId) : mLinkId(linkId), - mElinks{impl::makeArray<40>([](size_t i) { return ElinkEncoder<FORMAT, CHARGESUM>(i, phase(i, GBTEncoder<FORMAT, CHARGESUM>::forceNoPhase)); })}, + mElinks{impl::makeArray<40>([](size_t i) { return ElinkEncoder<FORMAT, CHARGESUM, VERSION>(i, phase(i, GBTEncoder<FORMAT, CHARGESUM, VERSION>::forceNoPhase)); })}, mGbtWords{}, mElinkMerger{} { impl::assertIsInRange("linkId", linkId, 0, 11); } -template <typename FORMAT, typename CHARGESUM> -void GBTEncoder<FORMAT, CHARGESUM>::addChannelData(uint8_t elinkGroupId, uint8_t elinkIndexInGroup, uint8_t chId, - const std::vector<SampaCluster>& data) +template <typename FORMAT, typename CHARGESUM, int VERSION> +void GBTEncoder<FORMAT, CHARGESUM, VERSION>::addChannelData(uint8_t elinkGroupId, uint8_t elinkIndexInGroup, uint8_t chId, + const std::vector<SampaCluster>& data) { impl::assertIsInRange("elinkGroupId", elinkGroupId, 0, 7); @@ -130,8 +137,17 @@ void GBTEncoder<FORMAT, CHARGESUM>::addChannelData(uint8_t elinkGroupId, uint8_t mElinks.at(elinkGroupId * 5 + elinkIndexInGroup).addChannelData(chId, data); } -template <typename FORMAT, typename CHARGESUM> -size_t GBTEncoder<FORMAT, CHARGESUM>::moveToBuffer(std::vector<std::byte>& buffer) +template <typename FORMAT, typename CHARGESUM, int VERSION> +void GBTEncoder<FORMAT, CHARGESUM, VERSION>::addHeartbeat(uint8_t elinkGroupId, uint8_t elinkIndexInGroup, uint20_t bunchCrossing) +{ + + impl::assertIsInRange("elinkGroupId", elinkGroupId, 0, 7); + impl::assertIsInRange("elinkIndexInGroup", elinkIndexInGroup, 0, 4); + mElinks.at(elinkGroupId * 5 + elinkIndexInGroup).addHeartbeat(bunchCrossing); +} + +template <typename FORMAT, typename CHARGESUM, int VERSION> +size_t GBTEncoder<FORMAT, CHARGESUM, VERSION>::moveToBuffer(std::vector<std::byte>& buffer) { auto s = gsl::span(mElinks.begin(), mElinks.end()); mElinkMerger(mLinkId, s, mGbtWords); diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoder.cxx index 13902f320dd21..2a284b851dae1 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoder.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "BareElinkEncoder.h" #include "BareElinkEncoderMerger.h" +#include "MCHRawCommon/DataFormats.h" #include "PayloadEncoderImpl.h" #include "MCHRawEncoderPayload/PayloadEncoder.h" #include "UserLogicElinkEncoder.h" @@ -20,37 +22,48 @@ namespace o2::mch::raw { namespace impl { -// cannot partially specialize a function, so create a struct (which can -// be specialized) and use it within the function below. -template <typename FORMAT, typename CHARGESUM, bool forceNoPhase> +template <typename FORMAT, typename CHARGESUM, int VERSION, bool forceNoPhase> struct PayloadEncoderCreator { static std::unique_ptr<PayloadEncoder> _(Solar2FeeLinkMapper solar2feelink) { - GBTEncoder<FORMAT, CHARGESUM>::forceNoPhase = forceNoPhase; - return std::make_unique<PayloadEncoderImpl<FORMAT, CHARGESUM>>(solar2feelink); + GBTEncoder<FORMAT, CHARGESUM, VERSION>::forceNoPhase = forceNoPhase; + return std::make_unique<PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>>(solar2feelink); } }; } // namespace impl -template <typename FORMAT, typename CHARGESUM, bool forceNoPhase> +template <typename FORMAT, typename CHARGESUM, int VERSION, bool forceNoPhase = true> std::unique_ptr<PayloadEncoder> createPayloadEncoder(Solar2FeeLinkMapper solar2feelink) { - return impl::PayloadEncoderCreator<FORMAT, CHARGESUM, forceNoPhase>::_(solar2feelink); + return impl::PayloadEncoderCreator<FORMAT, CHARGESUM, VERSION, forceNoPhase>::_(solar2feelink); } -std::unique_ptr<PayloadEncoder> createPayloadEncoder(Solar2FeeLinkMapper); - -// define only the specializations we use - -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<BareFormat, SampleMode, true>(Solar2FeeLinkMapper); -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<BareFormat, SampleMode, false>(Solar2FeeLinkMapper); - -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<BareFormat, ChargeSumMode, true>(Solar2FeeLinkMapper); -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<BareFormat, ChargeSumMode, false>(Solar2FeeLinkMapper); - -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<UserLogicFormat, SampleMode, true>(Solar2FeeLinkMapper); -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<UserLogicFormat, SampleMode, false>(Solar2FeeLinkMapper); - -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<UserLogicFormat, ChargeSumMode, true>(Solar2FeeLinkMapper); -template std::unique_ptr<PayloadEncoder> createPayloadEncoder<UserLogicFormat, ChargeSumMode, false>(Solar2FeeLinkMapper); +std::unique_ptr<PayloadEncoder> createPayloadEncoder(Solar2FeeLinkMapper solar2feelink, + bool userLogic, int version, bool chargeSumMode) +{ + if (version != 0 && version != 1) { + throw std::invalid_argument("Only version 0 or 1 are supported"); + } + if (userLogic) { + if (version == 0) { + if (chargeSumMode) { + return createPayloadEncoder<UserLogicFormat, ChargeSumMode, 0>(solar2feelink); + } else { + return createPayloadEncoder<UserLogicFormat, SampleMode, 0>(solar2feelink); + } + } else { + if (chargeSumMode) { + return createPayloadEncoder<UserLogicFormat, ChargeSumMode, 1>(solar2feelink); + } else { + return createPayloadEncoder<UserLogicFormat, SampleMode, 1>(solar2feelink); + } + } + } else { + if (chargeSumMode) { + return createPayloadEncoder<BareFormat, ChargeSumMode, 0>(solar2feelink); + } else { + return createPayloadEncoder<BareFormat, SampleMode, 0>(solar2feelink); + } + } +} } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoderImpl.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoderImpl.h index 4e9c811716efd..76a7c668f2577 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoderImpl.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoderImpl.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,11 +14,13 @@ #include "Assertions.h" #include "GBTEncoder.h" +#include "MCHRawCommon/SampaBunchCrossingCounter.h" +#include "MCHRawElecMap/Mapper.h" #include "MCHRawEncoderPayload/DataBlock.h" #include "MCHRawEncoderPayload/PayloadEncoder.h" -#include "MCHRawElecMap/Mapper.h" #include "MakeArray.h" #include <algorithm> +#include <cassert> #include <cstdlib> #include <fmt/format.h> #include <functional> @@ -27,9 +30,11 @@ #include <memory> #include <optional> #include <set> -#include <vector> -#include <cassert> #include <stdexcept> +#include <vector> +#include "DetectorsRaw/HBFUtils.h" +#include "NofBits.h" +#include "Framework/Logger.h" namespace o2::mch::raw { @@ -38,33 +43,39 @@ namespace o2::mch::raw /// /// \nosubgrouping -template <typename FORMAT, typename CHARGESUM> +template <typename FORMAT, typename CHARGESUM, int VERSION> class PayloadEncoderImpl : public PayloadEncoder { public: PayloadEncoderImpl(Solar2FeeLinkMapper solar2feelink); - void addChannelData(DsElecId dsId, uint8_t chId, const std::vector<SampaCluster>& data) override; + void addChannelData(DsElecId dsId, DualSampaChannelId dsChId, + const std::vector<SampaCluster>& data) override; void startHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) override; size_t moveToBuffer(std::vector<std::byte>& buffer) override; + void addHeartbeatHeaders(const std::set<DsElecId>& dsids) override; + + using ElementaryEncoder = GBTEncoder<FORMAT, CHARGESUM, VERSION>; + private: void closeHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing); void gbts2buffer(uint32_t orbit, uint16_t bunchCrossing); + std::unique_ptr<ElementaryEncoder>& assertGBT(uint16_t solarId); private: uint32_t mOrbit; uint16_t mBunchCrossing; std::vector<std::byte> mBuffer; - std::map<uint16_t, std::unique_ptr<GBTEncoder<FORMAT, CHARGESUM>>> mGBTs; + std::map<uint16_t, std::unique_ptr<ElementaryEncoder>> mGBTs; bool mFirstHBFrame; Solar2FeeLinkMapper mSolar2FeeLink; }; -template <typename FORMAT, typename CHARGESUM> -PayloadEncoderImpl<FORMAT, CHARGESUM>::PayloadEncoderImpl(Solar2FeeLinkMapper solar2feelink) +template <typename FORMAT, typename CHARGESUM, int VERSION> +PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::PayloadEncoderImpl(Solar2FeeLinkMapper solar2feelink) : mOrbit{}, mBunchCrossing{}, mBuffer{}, @@ -74,24 +85,33 @@ PayloadEncoderImpl<FORMAT, CHARGESUM>::PayloadEncoderImpl(Solar2FeeLinkMapper so { } -template <typename FORMAT, typename CHARGESUM> -void PayloadEncoderImpl<FORMAT, CHARGESUM>::addChannelData(DsElecId dsId, uint8_t chId, const std::vector<SampaCluster>& data) +template <typename FORMAT, typename CHARGESUM, int VERSION> +std::unique_ptr<typename PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::ElementaryEncoder>& + PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::assertGBT(uint16_t solarId) { - auto solarId = dsId.solarId(); auto gbt = mGBTs.find(solarId); if (gbt == mGBTs.end()) { auto f = mSolar2FeeLink(solarId); if (!f.has_value()) { throw std::invalid_argument(fmt::format("Could not get fee,link for solarId={}\n", solarId)); } - mGBTs.emplace(solarId, std::make_unique<GBTEncoder<FORMAT, CHARGESUM>>(f->linkId())); + mGBTs.emplace(solarId, std::make_unique<ElementaryEncoder>(f->linkId())); gbt = mGBTs.find(solarId); } - gbt->second->addChannelData(dsId.elinkGroupId(), dsId.elinkIndexInGroup(), chId, data); + return gbt->second; } -template <typename FORMAT, typename CHARGESUM> -void PayloadEncoderImpl<FORMAT, CHARGESUM>::gbts2buffer(uint32_t orbit, uint16_t bunchCrossing) +template <typename FORMAT, typename CHARGESUM, int VERSION> +void PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::addChannelData(DsElecId dsId, DualSampaChannelId dsChId, const std::vector<SampaCluster>& data) +{ + auto solarId = dsId.solarId(); + auto& gbt = assertGBT(solarId); + impl::assertNofBits("dualSampaChannelId", dsChId, 6); + gbt->addChannelData(dsId.elinkGroupId(), dsId.elinkIndexInGroup(), dsChId, data); +} + +template <typename FORMAT, typename CHARGESUM, int VERSION> +void PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::gbts2buffer(uint32_t orbit, uint16_t bunchCrossing) { // append to our own buffer all the words buffers from all our gbts, // prepending each one with a corresponding payload header @@ -110,8 +130,8 @@ void PayloadEncoderImpl<FORMAT, CHARGESUM>::gbts2buffer(uint32_t orbit, uint16_t } } -template <typename FORMAT, typename CHARGESUM> -size_t PayloadEncoderImpl<FORMAT, CHARGESUM>::moveToBuffer(std::vector<std::byte>& buffer) +template <typename FORMAT, typename CHARGESUM, int VERSION> +size_t PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::moveToBuffer(std::vector<std::byte>& buffer) { closeHeartbeatFrame(mOrbit, mBunchCrossing); buffer.insert(buffer.end(), mBuffer.begin(), mBuffer.end()); @@ -120,14 +140,14 @@ size_t PayloadEncoderImpl<FORMAT, CHARGESUM>::moveToBuffer(std::vector<std::byte return s; } -template <typename FORMAT, typename CHARGESUM> -void PayloadEncoderImpl<FORMAT, CHARGESUM>::closeHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) +template <typename FORMAT, typename CHARGESUM, int VERSION> +void PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::closeHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) { gbts2buffer(orbit, bunchCrossing); } -template <typename FORMAT, typename CHARGESUM> -void PayloadEncoderImpl<FORMAT, CHARGESUM>::startHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) +template <typename FORMAT, typename CHARGESUM, int VERSION> +void PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::startHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) { impl::assertIsInRange("bunchCrossing", bunchCrossing, 0, 0xFFF); // build a buffer with the _previous_ (orbit,bx) @@ -140,5 +160,24 @@ void PayloadEncoderImpl<FORMAT, CHARGESUM>::startHeartbeatFrame(uint32_t orbit, mBunchCrossing = bunchCrossing; } +/** addHeartbeatHeaders generate one hearbeat header for each dual sampa + * present in the mDsElecIds set. Might be called e.g. at the beginning + * of each time frame + */ +template <typename FORMAT, typename CHARGESUM, int VERSION> +void PayloadEncoderImpl<FORMAT, CHARGESUM, VERSION>::addHeartbeatHeaders(const std::set<DsElecId>& dsids) +{ + if (dsids.empty()) { + return; + } + // get first orbit of the run + auto firstIR = o2::raw::HBFUtils::Instance().getFirstIR(); + auto sampaBXCount = sampaBunchCrossingCounter(firstIR.orbit, firstIR.bc, firstIR.orbit); + for (auto dsElecId : dsids) { + auto solarId = dsElecId.solarId(); + auto& gbt = assertGBT(solarId); + gbt->addHeartbeat(dsElecId.elinkGroupId(), dsElecId.elinkIndexInGroup(), sampaBXCount); + } +} } // namespace o2::mch::raw #endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadPaginator.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadPaginator.cxx index a4bd952b7184c..f11467098945e 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadPaginator.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadPaginator.cxx @@ -1,14 +1,21 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "MCHRawEncoderPayload/PayloadPaginator.h" +#include <optional> +#include "MCHRawElecMap/Mapper.h" +#include "MCHRawCommon/DataFormats.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Headers/RDHAny.h" +#include <iostream> #include "DetectorsRaw/RawFileWriter.h" #include "MCHRawEncoderPayload/DataBlock.h" #include "Framework/Logger.h" @@ -16,28 +23,98 @@ namespace o2::mch::raw { -PayloadPaginator::PayloadPaginator(o2::raw::RawFileWriter& fw, - const std::string outputFileName, - Solar2FeeLinkMapper solar2feelink, - bool userLogic, - bool chargeSumMode) : mRawFileWriter(fw), - mOutputFileName{outputFileName}, - mSolar2FeeLink{solar2feelink}, - mExtraFeeIdMask{chargeSumMode ? static_cast<uint16_t>(0x100) : static_cast<uint16_t>(0)} +uint64_t encode(const LinkInfo& li) { - if (userLogic) { - mSolar2FeeLink = [solar2feelink](uint16_t solarId) -> std::optional<FeeLinkId> { - static auto s2f = solar2feelink; - auto f = s2f(solarId); - if (!f.has_value()) { - return std::nullopt; - } - return FeeLinkId(f->feeId(), 15); + return static_cast<uint64_t>(li.endPoint) | + static_cast<uint64_t>(li.linkId) << 8 | + static_cast<uint64_t>(li.cruId) << 24 | + static_cast<uint64_t>(li.feeId) << 40; +} + +bool operator<(const LinkInfo& li1, const LinkInfo& li2) +{ + return encode(li1) < encode(li2); +} + +std::ostream& operator<<(std::ostream& os, const LinkInfo& li) +{ + os << fmt::format("FEEID {:6d} CRU {:4d} LINK {:4d} EP {:1d}", + li.feeId, li.cruId, li.linkId, li.endPoint); + return os; +} + +template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION> +Solar2LinkInfo createSolar2LinkInfo() +{ + auto s2f = createSolar2FeeLinkMapper<ELECMAP>(); + return [s2f](uint16_t solarId) -> std::optional<LinkInfo> { + auto f = s2f(solarId); + if (!f.has_value()) { + return std::nullopt; }; + LinkInfo li; + li.endPoint = f->feeId() % 2; + li.cruId = (f->feeId() - li.endPoint) / 2; + li.feeId = f->feeId() | extraFeeIdChargeSumMask<CHARGESUM>() | extraFeeIdVersionMask<VERSION>(); + li.linkId = linkRemapping<FORMAT>(f->linkId()); + return li; + }; +} + +o2::header::RDHAny rdhFromLinkInfo(LinkInfo li) +{ + o2::header::RDHAny rdh; + o2::raw::RDHUtils::setFEEID(rdh, li.feeId); + o2::raw::RDHUtils::setCRUID(rdh, li.cruId); + o2::raw::RDHUtils::setEndPointID(rdh, li.endPoint); + o2::raw::RDHUtils::setLinkID(rdh, li.linkId); + return rdh; +} + +std::string flpName(LinkInfo li) +{ + static std::array<int, 33> cru2flp = { + 148, 148, 148, // 0, 1, 2 // FIXME: to be x-checked for St12 + 149, 149, 149, // 3, 4, 5 // FIXME: to be x-checked for St12 + 150, 150, 150, // 6, 7, 8 // FIXME: to be x-checked for St12 + 151, 151, 151, // 9,10,11 CH5 + 152, 152, 152, // 12,13,14 CH6 + 153, 153, 153, // 15,16,17 CH7o+CH8o (L) + 154, 154, 154, // 18,19,20 CH7i+CH8i (R) + 155, 155, 155, // 21,22,23 CH8i+CH9i (L) + 156, 156, 156, // 24,25,26 CH8o+CH9o (R) + 157, 157, 0, // 27,28,xx CH10o (L) + 158, 158, 0 // 30,31,xx CH10i (R) + }; + if (li.cruId > 32) { + throw std::invalid_argument("cruId should be <= 32"); } + return fmt::format("alio2-cr1-flp{}", cru2flp[li.cruId]); } -void PayloadPaginator::operator()(gsl::span<const std::byte> buffer) +void registerLinks(o2::raw::RawFileWriter& rawFileWriter, + std::string outputBase, + const std::set<LinkInfo>& links, + bool filePerLink, + bool filePerCru) +{ + std::string output = fmt::format("{:s}.raw", outputBase); + for (auto li : links) { + if (filePerLink || filePerCru) { + output = fmt::format("{:s}_{:s}_cru{:d}_{:d}", outputBase, flpName(li), li.cruId, li.endPoint); + if (filePerLink) { + output += fmt::format("_feedid{:d}", li.feeId); + } + output += ".raw"; + } + rawFileWriter.registerLink(rdhFromLinkInfo(li), output); + } +} + +void paginate(o2::raw::RawFileWriter& rawFileWriter, + gsl::span<const std::byte> buffer, + const std::set<LinkInfo>& links, + Solar2LinkInfo solar2LinkInfo) { std::set<DataBlockRef> dataBlockRefs; forEachDataBlockRef( @@ -45,51 +122,56 @@ void PayloadPaginator::operator()(gsl::span<const std::byte> buffer) dataBlockRefs.insert(ref); }); + std::map<o2::InteractionRecord, std::set<LinkInfo>> filled; + + // fill output buffer with actual data for (auto r : dataBlockRefs) { auto& b = r.block; auto& h = b.header; - auto feelink = mSolar2FeeLink(r.block.header.solarId).value(); - int endpoint = feelink.feeId() % 2; - int cru = (feelink.feeId() - endpoint) / 2; - auto feeId = feelink.feeId() | mExtraFeeIdMask; - if (mFeeLinkIds.find(feelink) == mFeeLinkIds.end()) { - mRawFileWriter.registerLink(feeId, cru, feelink.linkId(), endpoint, mOutputFileName); - mFeeLinkIds.insert(feelink); + auto solarId = r.block.header.solarId; + auto li = solar2LinkInfo(solarId); + if (!li.has_value()) { + throw std::runtime_error(fmt::format("Could not get fee,cru,link,endpoint for solarId {}", solarId)); } - mRawFileWriter.addData(feeId, cru, feelink.linkId(), endpoint, - {h.bc, h.orbit}, - gsl::span<char>(const_cast<char*>(reinterpret_cast<const char*>(&b.payload[0])), - b.payload.size())); + filled[o2::InteractionRecord{h.bc, h.orbit}].insert(li.value()); + rawFileWriter.addData(rdhFromLinkInfo(li.value()), + {h.bc, h.orbit}, + gsl::span<char>(const_cast<char*>(reinterpret_cast<const char*>(&b.payload[0])), + b.payload.size())); } -} -std::vector<std::byte> paginate(gsl::span<const std::byte> buffer, bool userLogic, - bool chargeSumMode, const std::string& tmpfilename) -{ - fair::Logger::SetConsoleSeverity("nolog"); - o2::raw::RawFileWriter fw; - - fw.setVerbosity(1); - fw.setDontFillEmptyHBF(true); + // loop over the used interaction records and ensure that we call + // addData for each link where it was not already called. - Solar2FeeLinkMapper solar2feelink = createSolar2FeeLinkMapper<ElectronicMapperGenerated>(); + static std::array<char, 64> nothing; - { - PayloadPaginator p(fw, tmpfilename, solar2feelink, userLogic, chargeSumMode); - p(buffer); - fw.close(); + for (auto p : filled) { + auto ir = p.first; + auto& filledLinks = p.second; + std::set<LinkInfo> addDataNotAlreadyCalled; + std::set_difference(links.begin(), links.end(), filledLinks.begin(), filledLinks.end(), + std::inserter(addDataNotAlreadyCalled, addDataNotAlreadyCalled.end())); + for (auto li : addDataNotAlreadyCalled) { + rawFileWriter.addData(rdhFromLinkInfo(li), ir, nothing); + } } +} - std::ifstream in(tmpfilename, std::ifstream::binary); - // get length of file: - in.seekg(0, in.end); - int length = in.tellg(); - in.seekg(0, in.beg); - std::vector<std::byte> pages(length); +// instanciate only the specializations that actually make sense. +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, BareFormat, SampleMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, BareFormat, ChargeSumMode, 0>(); - // read data as a block: - in.read(reinterpret_cast<char*>(&pages[0]), length); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, SampleMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, ChargeSumMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, SampleMode, 1>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperGenerated, UserLogicFormat, ChargeSumMode, 1>(); + +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, BareFormat, SampleMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, BareFormat, ChargeSumMode, 0>(); + +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, SampleMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, ChargeSumMode, 0>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, SampleMode, 1>(); +template Solar2LinkInfo createSolar2LinkInfo<ElectronicMapperDummy, UserLogicFormat, ChargeSumMode, 1>(); - return pages; -} } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx index 1881213c77a7a..52e4581da1a71 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx index 84a3788b81fa4..3c3781460f4d1 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx index 6673e943a121c..89b1602cb0489 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx index a79d047f73d6b..9487037328ad2 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoder.h index d424aa120f00a..679c0a2c7e5d9 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoder.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,18 +23,21 @@ #include <cstdlib> #include <fmt/printf.h> #include <vector> +#include "Framework/Logger.h" namespace o2::mch::raw { -template <typename CHARGESUM> -class ElinkEncoder<UserLogicFormat, CHARGESUM> +template <typename CHARGESUM, int VERSION> +class ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION> { public: explicit ElinkEncoder(uint8_t elinkId, int phase = 0); void addChannelData(uint8_t chId, const std::vector<SampaCluster>& data); + void addHeartbeat(uint20_t bunchCrossing); + size_t moveToBuffer(std::vector<uint64_t>& buffer, uint16_t gbtId); void clear(); @@ -44,9 +48,9 @@ class ElinkEncoder<UserLogicFormat, CHARGESUM> std::vector<uint10_t> mBuffer; }; -template <typename CHARGESUM> -ElinkEncoder<UserLogicFormat, CHARGESUM>::ElinkEncoder(uint8_t elinkId, - int phase) +template <typename CHARGESUM, int VERSION> +ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>::ElinkEncoder(uint8_t elinkId, + int phase) : mElinkId{elinkId}, mHasSync{false}, mBuffer{} @@ -54,9 +58,9 @@ ElinkEncoder<UserLogicFormat, CHARGESUM>::ElinkEncoder(uint8_t elinkId, impl::assertIsInRange("elinkId", elinkId, 0, 39); } -template <typename CHARGESUM> -void ElinkEncoder<UserLogicFormat, CHARGESUM>::addChannelData(uint8_t chId, - const std::vector<SampaCluster>& data) +template <typename CHARGESUM, int VERSION> +void ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>::addChannelData(uint8_t chId, + const std::vector<SampaCluster>& data) { if (data.empty()) { throw std::invalid_argument("cannot add empty data"); @@ -73,29 +77,45 @@ void ElinkEncoder<UserLogicFormat, CHARGESUM>::addChannelData(uint8_t chId, } } -template <typename CHARGESUM> -void ElinkEncoder<UserLogicFormat, CHARGESUM>::clear() +template <typename CHARGESUM, int VERSION> +void ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>::addHeartbeat(uint20_t bunchCrossing) +{ + if (!mHasSync) { + impl::appendSync(mBuffer); + mHasSync = true; + } + for (auto chipAddress : std::array<uint8_t, 2>{0, 1}) { + SampaHeader sh = sampaHeartbeat(chipAddress, bunchCrossing); + impl::addPadding(mBuffer); + impl::append(mBuffer, sh.uint64()); + } +} + +template <typename CHARGESUM, int VERSION> +void ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>::clear() { mBuffer.clear(); mHasSync = false; } -template <typename CHARGESUM> -size_t ElinkEncoder<UserLogicFormat, CHARGESUM>::moveToBuffer(std::vector<uint64_t>& buffer, uint16_t gbtId) +template <typename CHARGESUM, int VERSION> +size_t ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>::moveToBuffer(std::vector<uint64_t>& buffer, uint16_t gbtId) { if (mBuffer.empty()) { return 0; } - int error{0}; // FIXME: what to do with error ? - uint16_t b9{0}; + ULHeaderWord<VERSION> header{0}; + + header.linkID = gbtId; + header.dsID = mElinkId; + header.incomplete = 0; // FIXME: what to do with incomplete ? + header.error = 0; // FIXME: what to do with error ? - b9 |= static_cast<uint64_t>(gbtId & 0x1F) << 9; - b9 |= static_cast<uint64_t>(mElinkId & 0x3F) << 3; - b9 |= static_cast<uint64_t>(error & 0x3); + uint16_t b14 = static_cast<uint16_t>((header.word >> 50) & 0xFFFF); // keep only 14 most significant bits of header word auto n = buffer.size(); - impl::b10to64(mBuffer, buffer, b9); + impl::b10to64(mBuffer, buffer, b14); clear(); return buffer.size() - n; } diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoderMerger.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoderMerger.h index 260b1ba398ec6..fe3d78cd2c85c 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoderMerger.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoderMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,11 +19,11 @@ namespace o2::mch::raw { -template <typename CHARGESUM> -struct ElinkEncoderMerger<UserLogicFormat, CHARGESUM> { +template <typename CHARGESUM, int VERSION> +struct ElinkEncoderMerger<UserLogicFormat, CHARGESUM, VERSION> { void operator()(uint16_t gbtId, - gsl::span<ElinkEncoder<UserLogicFormat, CHARGESUM>> elinks, + gsl::span<ElinkEncoder<UserLogicFormat, CHARGESUM, VERSION>> elinks, std::vector<uint64_t>& b64) { for (auto& elink : elinks) { diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/benchBitSet.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/benchBitSet.cxx index 7a694f670bd41..94174ffd0a5ab 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/benchBitSet.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/benchBitSet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/DataBlock.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/DataBlock.h index 8e2b6fb6bea6d..0803759e880a0 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/DataBlock.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/DataBlock.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadEncoder.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadEncoder.h index 9a5aa029016b0..d510a97387e0e 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadEncoder.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "MCHRawElecMap/Mapper.h" #include <functional> #include <optional> +#include <set> namespace o2::mch::raw { @@ -43,13 +45,18 @@ class PayloadEncoder /// \param dsId is the (electronic) identifier of a dual sampa /// \param chId dual sampa channel id 0..63 /// \param data the actual data to be added - virtual void addChannelData(DsElecId dsId, uint8_t chId, const std::vector<SampaCluster>& data) = 0; + virtual void addChannelData(DsElecId dsId, DualSampaChannelId chId, + const std::vector<SampaCluster>& data) = 0; // startHeartbeatFrame sets the trigger (orbit,bunchCrossing) to be used // for all generated payload headers (until next call to this method). // Causes the alignment of the underlying gbts. virtual void startHeartbeatFrame(uint32_t orbit, uint16_t bunchCrossing) = 0; + // addHeartbeatHeaders adds Heartbeat Sampa headers for each dual sampa in the + // given set. + virtual void addHeartbeatHeaders(const std::set<DsElecId>& dsids) = 0; + /// Export our encoded data. /// /// The internal words that have been accumulated so far are @@ -61,15 +68,15 @@ class PayloadEncoder /// createPayloadEncoder creates a payload encoder /// -/// template parameters : -/// -/// \tparam FORMAT defines the data format (either BareFormat or UserLogic) -/// \tparam CHARGESUM defines the data format mode (either SampleMode or ChargeSumMode) -/// \tparam forceNoPhase to be deprecated ? +/// \param userLogic whether to encode in UserLogic (true) or BareFormat (false) +/// \param version defines the version of the encoding format +/// (currently 0 or 1 are possible, just for UserLogic) +/// \param chargeSumMode whether to encode in charge sum mode (true) or sample mode (false) /// \param solar2feelink a mapper to convert solarId values into FeeLinkId objects -/// -template <typename FORMAT, typename CHARGESUM, bool forceNoPhase = false> -std::unique_ptr<PayloadEncoder> createPayloadEncoder(Solar2FeeLinkMapper solar2feelink = - createSolar2FeeLinkMapper<ElectronicMapperGenerated>()); +std::unique_ptr<PayloadEncoder> createPayloadEncoder(Solar2FeeLinkMapper solar2feelink, + bool userLogic, + int version, + bool chargeSumMode); + } // namespace o2::mch::raw #endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadPaginator.h b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadPaginator.h index 9f6c044ab779a..43925a7cd0a74 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadPaginator.h +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadPaginator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,59 +12,49 @@ #ifndef O2_MCH_RAW_PAYLOAD_PAGINATOR_H #define O2_MCH_RAW_PAYLOAD_PAGINATOR_H +#include <string> +#include <gsl/span> +#include <functional> +#include <optional> +#include <set> +#include <iostream> + namespace o2::raw { class RawFileWriter; } -#include <string> -#include <gsl/span> -#include <set> -#include "MCHRawElecMap/Mapper.h" -#include <vector> - namespace o2::mch::raw { -/// @brief Converts (DataBlockHeader,payload) pairs into RAW data (RDH,payload) -/// -/// \nosubgrouping -class PayloadPaginator -{ - public: - /// @param fw a RawFileWriter instance, that should be - /// properly configured (once) _before_ calling the () operator - /// @param outputFileName the name of the single output file - /// used to store the produced RAW data - /// @param solar2feelink a mapper that converts a solarId value into - /// a FeeLinkId object - /// @param userLogic whether or not the format to emulate is UL - /// @param chargeSumMode whether or not the format to emulate is in chargeSumMode - PayloadPaginator(o2::raw::RawFileWriter& fw, - const std::string outputFileName, - Solar2FeeLinkMapper solar2feelink, - bool userLogic, - bool chargeSumMode); +// helper struct with the smallest information to uniquely identify +// one data link +struct LinkInfo { + uint16_t feeId; + uint16_t cruId; + uint8_t linkId; + uint8_t endPoint; +}; - /// Convert the buffer to raw data - /// - /// @param buffer a buffer of (DataBlockHeader,payload) MCH raw data - /// (e.g. produced by a PayloadEncoder) - void operator()(gsl::span<const std::byte> buffer); +bool operator<(const LinkInfo&, const LinkInfo&); +std::ostream& operator<<(std::ostream& os, const LinkInfo& li); - private: - o2::raw::RawFileWriter& mRawFileWriter; - Solar2FeeLinkMapper mSolar2FeeLink; - std::string mOutputFileName; - std::set<FeeLinkId> mFeeLinkIds{}; - uint16_t mExtraFeeIdMask{0}; -}; +using Solar2LinkInfo = std::function<std::optional<LinkInfo>(uint16_t)>; + +/** Creates a function that is able to convert a solarId into a LinkInfo */ +template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION> +Solar2LinkInfo createSolar2LinkInfo(); + +void registerLinks(o2::raw::RawFileWriter& rawFileWriter, + std::string outputBase, + const std::set<LinkInfo>& links, + bool filePerLink, + bool filePerCru); + +void paginate(o2::raw::RawFileWriter& rawFileWriter, + gsl::span<const std::byte> buffer, + const std::set<LinkInfo>& links, + Solar2LinkInfo solar2LinkInfo); -/// helper function to wrap usage of PayloadPaginator class to -/// directly get memory representation of the buffer -/// (still creates a file as it's using RawFileWriter internally, -/// but that file is temporary) -std::vector<std::byte> paginate(gsl::span<const std::byte> buffer, bool userLogic, bool chargeSumMode, - const std::string& tmpfilename); } // namespace o2::mch::raw #endif diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/testBareElinkEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/testBareElinkEncoder.cxx index 16e62f227e2d4..a85564c749043 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/testBareElinkEncoder.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/testBareElinkEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/testBitSet.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/testBitSet.cxx index 18632438ec3fb..181b2ef08c449 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/testBitSet.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/testBitSet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/testElinkEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/testElinkEncoder.cxx index 2787b24d3c3c5..6e0395c893410 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/testElinkEncoder.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/testElinkEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/testGBTEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/testGBTEncoder.cxx index 2920f67f114f1..acaffe27357da 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/testGBTEncoder.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/testGBTEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/testPayloadEncoder.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/testPayloadEncoder.cxx index 2354ed6708d98..c88a598c5b987 100644 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/testPayloadEncoder.cxx +++ b/Detectors/MUON/MCH/Raw/Encoder/Payload/testPayloadEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ /// In those tests we are mainly concerned about testinng /// whether the payloads are actually properly simulated. /// +#include "MCHRawElecMap/Mapper.h" #define BOOST_TEST_MODULE Test MCHRaw Encoder #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK @@ -24,7 +26,6 @@ #include "EncoderImplHelper.h" #include "GBTEncoder.h" #include "MCHRawCommon/DataFormats.h" -#include "MCHRawCommon/DataFormats.h" #include "MCHRawEncoderPayload/DataBlock.h" #include "MCHRawEncoderPayload/PayloadEncoder.h" #include "UserLogicElinkEncoder.h" @@ -36,70 +37,123 @@ using namespace o2::mch::raw; -template <typename FORMAT, typename CHARGESUM> -struct CruBufferCreator { - static std::vector<std::byte> makeBuffer(int norbit, uint32_t firstOrbit, uint16_t firstBC); -}; - -template <typename FORMAT> -struct CruBufferCreator<FORMAT, ChargeSumMode> { - static std::vector<std::byte> makeBuffer(int norbit = 1, - uint32_t firstOrbit = 12345, - uint16_t firstBC = 678) - { - auto encoder = createPayloadEncoder<FORMAT, ChargeSumMode, true>(); - - uint16_t sampaTime{24}; - uint32_t bunchCrossing = 567; - uint16_t bc(firstBC); - - encoder->startHeartbeatFrame(firstOrbit, bc); - - encoder->addChannelData(DsElecId{728, 1, 0}, 3, {SampaCluster(sampaTime, bunchCrossing, 13, 14)}); - encoder->addChannelData(DsElecId{728, 1, 0}, 13, {SampaCluster(sampaTime, bunchCrossing, 133, 134)}); - encoder->addChannelData(DsElecId{728, 1, 0}, 23, {SampaCluster(sampaTime, bunchCrossing, 163, 164)}); - - encoder->addChannelData(DsElecId{361, 0, 4}, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 1, {SampaCluster(sampaTime, bunchCrossing, 20, 21)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 2, {SampaCluster(sampaTime, bunchCrossing, 30, 31)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 3, {SampaCluster(sampaTime, bunchCrossing, 40, 41)}); - - encoder->addChannelData(DsElecId{448, 6, 2}, 22, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); - encoder->addChannelData(DsElecId{448, 6, 2}, 23, {SampaCluster(sampaTime, bunchCrossing, 430, 431)}); - encoder->addChannelData(DsElecId{448, 6, 2}, 24, {SampaCluster(sampaTime, bunchCrossing, 440, 441)}); - encoder->addChannelData(DsElecId{448, 6, 2}, 25, {SampaCluster(sampaTime, bunchCrossing, 450, 451)}); - encoder->addChannelData(DsElecId{448, 6, 2}, 26, {SampaCluster(sampaTime, bunchCrossing, 460, 461)}); - encoder->addChannelData(DsElecId{448, 6, 2}, 42, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); - +template <typename ELECMAP, typename FORMAT, int VERSION = 0> +std::vector<std::byte> makeBuffer(int norbit = 1, + uint32_t firstOrbit = 12345, + uint16_t firstBC = 678, + bool withHB = false) +{ + const DsElecId ds1{728, 1, 0}; + const DsElecId ds2{361, 0, 4}; + const DsElecId ds3{448, 6, 2}; + const DsElecId ds4{728, 1, 2}; + + std::set<DsElecId> dsElecIds; + if (withHB) { + dsElecIds.insert(ds1); + dsElecIds.insert(ds2); + dsElecIds.insert(ds3); if (norbit > 1) { - encoder->startHeartbeatFrame(firstOrbit + 1, bc); - encoder->addChannelData(DsElecId{728, 1, 2}, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); - encoder->addChannelData(DsElecId{728, 1, 2}, 1, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 1, {SampaCluster(sampaTime, bunchCrossing, 20, 21)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 2, {SampaCluster(sampaTime, bunchCrossing, 30, 31)}); - encoder->addChannelData(DsElecId{361, 0, 4}, 3, {SampaCluster(sampaTime, bunchCrossing, 40, 41)}); - } - - if (norbit > 2) { - encoder->startHeartbeatFrame(firstOrbit + 2, bc); - encoder->addChannelData(DsElecId{448, 6, 2}, 12, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); + dsElecIds.insert(ds4); } + } + auto encoder = createPayloadEncoder(createSolar2FeeLinkMapper<ELECMAP>(), + isUserLogicFormat<FORMAT>::value, + VERSION, + isChargeSumMode<ChargeSumMode>::value); + + uint16_t sampaTime{24}; + uint32_t bunchCrossing = 567; + uint16_t bc(firstBC); + + encoder->startHeartbeatFrame(firstOrbit, bc); + if (withHB) { + encoder->addHeartbeatHeaders(dsElecIds); + } - std::vector<std::byte> buffer; - encoder->moveToBuffer(buffer); + encoder->addChannelData(ds1, 3, {SampaCluster(sampaTime, bunchCrossing, 13, 14)}); + encoder->addChannelData(ds1, 13, {SampaCluster(sampaTime, bunchCrossing, 133, 134)}); + encoder->addChannelData(ds1, 23, {SampaCluster(sampaTime, bunchCrossing, 163, 164)}); + + encoder->addChannelData(ds2, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); + encoder->addChannelData(ds2, 1, {SampaCluster(sampaTime, bunchCrossing, 20, 21)}); + encoder->addChannelData(ds2, 2, {SampaCluster(sampaTime, bunchCrossing, 30, 31)}); + encoder->addChannelData(ds2, 3, {SampaCluster(sampaTime, bunchCrossing, 40, 41)}); + + encoder->addChannelData(ds3, 22, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); + encoder->addChannelData(ds3, 23, {SampaCluster(sampaTime, bunchCrossing, 430, 431)}); + encoder->addChannelData(ds3, 24, {SampaCluster(sampaTime, bunchCrossing, 440, 441)}); + encoder->addChannelData(ds3, 25, {SampaCluster(sampaTime, bunchCrossing, 450, 451)}); + encoder->addChannelData(ds3, 26, {SampaCluster(sampaTime, bunchCrossing, 460, 461)}); + encoder->addChannelData(ds3, 42, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); + + if (norbit > 1) { + encoder->startHeartbeatFrame(firstOrbit + 1, bc); + encoder->addChannelData(ds4, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); + encoder->addChannelData(ds4, 1, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); + encoder->addChannelData(ds2, 0, {SampaCluster(sampaTime, bunchCrossing, 10, 11)}); + encoder->addChannelData(ds2, 1, {SampaCluster(sampaTime, bunchCrossing, 20, 21)}); + encoder->addChannelData(ds2, 2, {SampaCluster(sampaTime, bunchCrossing, 30, 31)}); + encoder->addChannelData(ds2, 3, {SampaCluster(sampaTime, bunchCrossing, 40, 41)}); + } - return buffer; + if (norbit > 2) { + encoder->startHeartbeatFrame(firstOrbit + 2, bc); + encoder->addChannelData(ds3, 12, {SampaCluster(sampaTime, bunchCrossing, 420, 421)}); } -}; -template <typename FORMAT> + std::vector<std::byte> buffer; + encoder->moveToBuffer(buffer); + + return buffer; +} + +template <typename ELECMAP, typename FORMAT> std::unique_ptr<PayloadEncoder> defaultEncoder() { - return createPayloadEncoder<FORMAT, SampleMode, true>(); + return createPayloadEncoder(createSolar2FeeLinkMapper<ELECMAP>(), + isUserLogicFormat<FORMAT>::value, + 0, + isChargeSumMode<SampleMode>::value /* i.e. use sample mode */); } -typedef boost::mpl::list<BareFormat, UserLogicFormat> testTypes; +struct BareGen { + using format = BareFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 0; +}; + +struct UserLogicGen { + using format = UserLogicFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 0; +}; + +struct UserLogicGen1 { + using format = UserLogicFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 1; +}; + +struct BareDummy { + using format = BareFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 0; +}; + +struct UserLogicDummy { + using format = UserLogicFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 0; +}; + +struct UserLogicDummy1 { + using format = UserLogicFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 1; +}; + +typedef boost::mpl::list<BareGen, UserLogicGen, UserLogicGen1, BareDummy, UserLogicDummy, UserLogicDummy1> testTypes; BOOST_AUTO_TEST_SUITE(o2_mch_raw) @@ -107,7 +161,7 @@ BOOST_AUTO_TEST_SUITE(encoder) BOOST_AUTO_TEST_CASE_TEMPLATE(StartHBFrameBunchCrossingMustBe12Bits, T, testTypes) { - auto encoder = defaultEncoder<T>(); + auto encoder = defaultEncoder<typename T::elecmap, typename T::format>(); BOOST_CHECK_THROW(encoder->startHeartbeatFrame(0, 1 << 12), std::invalid_argument); BOOST_CHECK_NO_THROW(encoder->startHeartbeatFrame(0, 0xFFF)); } @@ -115,27 +169,17 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(StartHBFrameBunchCrossingMustBe12Bits, T, testType BOOST_AUTO_TEST_CASE_TEMPLATE(EmptyEncoderHasEmptyBufferIfPhaseIsZero, T, testTypes) { srand(time(nullptr)); - auto encoder = defaultEncoder<T>(); + auto encoder = defaultEncoder<typename T::elecmap, typename T::format>(); encoder->startHeartbeatFrame(12345, 123); std::vector<std::byte> buffer; encoder->moveToBuffer(buffer); BOOST_CHECK_EQUAL(buffer.size(), 0); } -BOOST_AUTO_TEST_CASE_TEMPLATE(EmptyEncodeIsNotNecessarilyEmptyDependingOnPhase, T, testTypes) -{ - srand(time(nullptr)); - auto encoder = createPayloadEncoder<T, SampleMode, false>(); - encoder->startHeartbeatFrame(12345, 123); - std::vector<std::byte> buffer; - encoder->moveToBuffer(buffer); - BOOST_CHECK_GE(buffer.size(), 0); -} - BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleOrbitsWithNoDataIsAnEmptyBufferIfPhaseIsZero, T, testTypes) { srand(time(nullptr)); - auto encoder = defaultEncoder<T>(); + auto encoder = defaultEncoder<typename T::elecmap, typename T::format>(); encoder->startHeartbeatFrame(12345, 123); encoder->startHeartbeatFrame(12345, 125); encoder->startHeartbeatFrame(12345, 312); @@ -170,36 +214,51 @@ int estimateBareSize(int nofDS, int maxNofChPerGBT) } template <typename FORMAT> -int estimateSize(); +int estimateSize(bool withHB = false); template <> -int estimateSize<BareFormat>() +int estimateSize<BareFormat>(bool withHB) { - return estimateBareSize(1, 3) + - estimateBareSize(1, 4) + - estimateBareSize(1, 6); + int size = estimateBareSize(1, 3) + + estimateBareSize(1, 4) + + estimateBareSize(1, 6); + if (withHB) { + size += 3 * 50 * 8; + } + return size; // in bytes } template <> -int estimateSize<UserLogicFormat>() +int estimateSize<UserLogicFormat>(bool withHB) { - return estimateUserLogicSize(1, 3) + - estimateUserLogicSize(1, 4) + - estimateUserLogicSize(1, 6) + - 2 * 8; // 8 bytes per FEE (to ensure the payload size is a multiple of 128 bits = 1 GBT word) + int size = estimateUserLogicSize(1, 3) + + estimateUserLogicSize(1, 4) + + estimateUserLogicSize(1, 6) + + 2 * 8; // 8 bytes per FEE (to ensure the payload size is a multiple of 128 bits = 1 GBT word) + if (withHB) { + size += 6 * 8; + } + return size; // in bytes } BOOST_AUTO_TEST_CASE_TEMPLATE(CheckNumberOfPayloadHeaders, T, testTypes) { - auto buffer = CruBufferCreator<T, ChargeSumMode>::makeBuffer(); + auto buffer = makeBuffer<typename T::elecmap, typename T::format, T::version>(); int nheaders = o2::mch::raw::countHeaders(buffer); BOOST_CHECK_EQUAL(nheaders, 3); } BOOST_AUTO_TEST_CASE_TEMPLATE(CheckSize, T, testTypes) { - auto buffer = CruBufferCreator<T, ChargeSumMode>::makeBuffer(); - size_t expectedSize = estimateSize<T>(); + auto buffer = makeBuffer<typename T::elecmap, typename T::format, T::version>(); + size_t expectedSize = estimateSize<typename T::format>(); + BOOST_CHECK_EQUAL(buffer.size(), expectedSize); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(CheckSizeWithHB, T, testTypes) +{ + auto buffer = makeBuffer<typename T::elecmap, typename T::format, T::version>(1, 12345, 678, true); + size_t expectedSize = estimateSize<typename T::format>(true); BOOST_CHECK_EQUAL(buffer.size(), expectedSize); } diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/Assertions.h b/Detectors/MUON/MCH/Raw/ImplHelpers/Assertions.h index 9f12b49abbd8e..af13a2e4f1080 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/Assertions.h +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/Assertions.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/CMakeLists.txt b/Detectors/MUON/MCH/Raw/ImplHelpers/CMakeLists.txt index ab39aef6cb6d9..f7a49f46c74c5 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library( - MCHRawImplHelpers - INTERFACE_LINK_LIBRARIES fmt::fmt ms_gsl::ms_gsl + MCHRawImplHelpers + INTERFACE_LINK_LIBRARIES fmt::fmt Microsoft.GSL::GSL INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIRECTORY}) o2_add_test(movebuffer diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/DumpBuffer.h b/Detectors/MUON/MCH/Raw/ImplHelpers/DumpBuffer.h index b3f6ea354d1b5..7d5bf9b2ceb05 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/DumpBuffer.h +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/DumpBuffer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,15 +53,9 @@ inline void append(std::vector<std::byte>& buffer, uint64_t w) buffer.emplace_back(std::byte{static_cast<uint8_t>((w & UINT64_C(0xFF00000000000000)) >> 56)}); } -template <typename FORMAT> -void dumpBuffer(gsl::span<const std::byte> buffer, std::ostream& out = std::cout, size_t maxbytes = std::numeric_limits<size_t>::max()); - template <typename FORMAT> void dumpWord(std::ostream& out, uint64_t w); -template <typename FORMAT> -void dumpWordInfo(std::ostream& out, uint64_t w, const char* spacer = ""); - template <> void dumpWord<o2::mch::raw::BareFormat>(std::ostream& out, uint64_t w) { @@ -80,8 +75,11 @@ void dumpWord<o2::mch::raw::UserLogicFormat>(std::ostream& out, uint64_t w) out << fmt::format("{:016X} ", w); } +template <typename FORMAT, int VERSION = 0> +void dumpWordInfo(std::ostream& out, uint64_t w, const char* spacer = ""); + template <> -void dumpWordInfo<o2::mch::raw::BareFormat>(std::ostream& out, uint64_t w, const char* /*spacer*/) +void dumpWordInfo<o2::mch::raw::BareFormat, 0>(std::ostream& out, uint64_t w, const char* /*spacer*/) { static constexpr uint64_t FIFTYBITSATONE = (static_cast<uint64_t>(1) << 50) - 1; SampaHeader h(w & FIFTYBITSATONE); @@ -95,9 +93,8 @@ void dumpWordInfo<o2::mch::raw::BareFormat>(std::ostream& out, uint64_t w, const } } -template <> -void dumpWordInfo<o2::mch::raw::UserLogicFormat>(std::ostream& out, uint64_t w, - const char* spacer) +template <int VERSION> +void dumpUserLogicWordInfo(std::ostream& out, uint64_t w, const char* spacer) { if (o2::mch::raw::isSampaSync(w)) { out << "SYNC "; @@ -106,10 +103,13 @@ void dumpWordInfo<o2::mch::raw::UserLogicFormat>(std::ostream& out, uint64_t w, if (!o2::mch::raw::isSampaSync(w)) { out << spacer; } - out << fmt::format("GBT(0.11) {:2d} ELINKID(0..39) {:2d} ERR {:1d}", - (w >> 59) & 0x1F, - (w >> 53) & 0x3F, - (w >> 50) & 0x7); + ULHeaderWord<VERSION> header{w}; + int gbt = header.linkID; + int elinkid = header.dsID; + int error = header.error; + bool incomplete = header.incomplete > 0; + out << fmt::format("GBT(0.11) {:2d} ELINKID(0..39) {:2d} ERR {:1d} INCOMPLETE {}", + gbt, elinkid, error, incomplete); if (!o2::mch::raw::isSampaSync(w)) { out << fmt::format("{:4d} {:4d} {:4d} {:4d} {:4d} ", (w & 0x3FF0000000000) >> 40, @@ -119,10 +119,24 @@ void dumpWordInfo<o2::mch::raw::UserLogicFormat>(std::ostream& out, uint64_t w, (w & 0x3FF)); } } -} // namespace o2::mch::raw::impl +} -template <typename FORMAT> -void dumpBuffer(gsl::span<const std::byte> buffer, std::ostream& out, size_t maxbytes) +template <> +void dumpWordInfo<o2::mch::raw::UserLogicFormat, 0>(std::ostream& out, uint64_t w, + const char* spacer) +{ + dumpUserLogicWordInfo<0>(out, w, spacer); +} + +template <> +void dumpWordInfo<o2::mch::raw::UserLogicFormat, 1>(std::ostream& out, uint64_t w, + const char* spacer) +{ + dumpUserLogicWordInfo<1>(out, w, spacer); +} + +template <typename FORMAT, int VERSION> +void dumpBuffer(gsl::span<const std::byte> buffer, std::ostream& out = std::cout, size_t maxbytes = std::numeric_limits<size_t>::max()) { int i{0}; int inRDH{-1}; @@ -197,22 +211,21 @@ void dumpBuffer(gsl::span<const std::byte> buffer, std::ostream& out, size_t max } if (inRDH <= 0) { - dumpWordInfo<FORMAT>(out, w, spacer); + dumpWordInfo<FORMAT, VERSION>(out, w, spacer); } i += 8; } out << "\n"; -} // namespace o2::mch::raw::impl +} -template <typename FORMAT> +template <typename FORMAT, int VERSION> void dumpBuffer(const std::vector<uint64_t>& buffer, std::ostream& out = std::cout, size_t maxbytes = std::numeric_limits<size_t>::max()) { std::vector<std::byte> b8; for (auto w : buffer) { append(b8, w); } - dumpBuffer<FORMAT>(b8, out, maxbytes); + dumpBuffer<FORMAT, VERSION>(b8, out, maxbytes); } - } // namespace o2::mch::raw::impl #endif diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/MakeArray.h b/Detectors/MUON/MCH/Raw/ImplHelpers/MakeArray.h index 16b1cc9931dd7..3c94905696278 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/MakeArray.h +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/MakeArray.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/MoveBuffer.h b/Detectors/MUON/MCH/Raw/ImplHelpers/MoveBuffer.h index dcf36f17e12d0..82579a64deaf1 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/MoveBuffer.h +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/MoveBuffer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/NofBits.h b/Detectors/MUON/MCH/Raw/ImplHelpers/NofBits.h index 767572f5c3be0..8d4ab5d92aaf2 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/NofBits.h +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/NofBits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/ImplHelpers/testMoveBuffer.cxx b/Detectors/MUON/MCH/Raw/ImplHelpers/testMoveBuffer.cxx index dadf6ba283c2c..8c6abd755c1e7 100644 --- a/Detectors/MUON/MCH/Raw/ImplHelpers/testMoveBuffer.cxx +++ b/Detectors/MUON/MCH/Raw/ImplHelpers/testMoveBuffer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Raw/Tools/CMakeLists.txt b/Detectors/MUON/MCH/Raw/Tools/CMakeLists.txt index c92bc33677886..a7fb535137c96 100644 --- a/Detectors/MUON/MCH/Raw/Tools/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/Tools/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_executable( dump diff --git a/Detectors/MUON/MCH/Raw/Tools/rawdump.cxx b/Detectors/MUON/MCH/Raw/Tools/rawdump.cxx index 2f5a5a3380647..7892be92f2541 100644 --- a/Detectors/MUON/MCH/Raw/Tools/rawdump.cxx +++ b/Detectors/MUON/MCH/Raw/Tools/rawdump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -177,7 +178,9 @@ std::map<std::string, ChannelStat> rawdump(std::string input, DumpOptions opt) npages++; bytesRead += in.gcount(); if (!decode) { - decode = createPageDecoder(page, channelHandler); + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = channelHandler; + decode = createPageDecoder(page, handlers); } patchPage(buffer); decode(page); diff --git a/Detectors/MUON/MCH/Raw/test/CMakeLists.txt b/Detectors/MUON/MCH/Raw/test/CMakeLists.txt index 855d910f9528b..3f62acb21a5ea 100644 --- a/Detectors/MUON/MCH/Raw/test/CMakeLists.txt +++ b/Detectors/MUON/MCH/Raw/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # closure tests, thus depending on both Encoder and Decoder @@ -15,3 +16,9 @@ o2_add_test(closure-codec COMPONENT_NAME mchraw LABELS "muon;mch;raw" PUBLIC_LINK_LIBRARIES O2::MCHRawEncoderPayload O2::MCHRawDecoder) + +o2_add_test(closure-codec-digit + SOURCES testClosureCoDecDigit.cxx + COMPONENT_NAME mchraw + LABELS "muon;mch;raw" + PUBLIC_LINK_LIBRARIES O2::MCHRawEncoderDigit O2::MCHRawDecoder) diff --git a/Detectors/MUON/MCH/Raw/test/codec-closure-test.sh b/Detectors/MUON/MCH/Raw/test/codec-closure-test.sh new file mode 100755 index 0000000000000..7982b4665306a --- /dev/null +++ b/Detectors/MUON/MCH/Raw/test/codec-closure-test.sh @@ -0,0 +1,44 @@ +option="--dummy-elecmap" +nevents=30 + +# first orbit of the run +orbitFirst=0 +# first orbit to sample +orbitFirstSampled=0 +# interactionRate (default 50000) +interactionRate=50000 + +echo "=== Performing simulation (aka hit creation)" +o2-sim-serial --seed 4242 -n ${nevents} -g fwmugen -e TGeant3 -j 1 -m MCH &> sim-serial.log + +echo "=== Digitizing..." +o2-sim-digitizer-workflow \ +--configKeyValues "HBFUtils.orbitFirst=${orbitFirst};HBFUtils.orbitFirstSampled=${orbitFirstSampled}" \ +--onlyDet MCH -b &> sim-digitizer.log + +echo "=== Convert sim digits to mch binary format" +o2-mch-sim-digits-reader-workflow --mch-digit-infile mchdigits.root | \ +o2-mch-digits-writer-workflow -b --binary-file-format 3 --outfile \ +digits.sim.out &> /dev/null + +echo "=== Textual dump of sim digits" +o2-mch-digits-file-dumper --infile digits.sim.out \ +--print-digits &> digits.sim.txt + +echo "=== Conversion digits -> raw (MCH)" +o2-mch-digits-to-raw --input-file mchdigits.root \ +--configKeyValues="MCHCoDecParam.sampaBcOffset=12345" \ +--output-dir ./raw/MCH --file-per-link $option &> \ +digits-to-raw.log + +echo "=== Conversion raw -> digit + real digits to mch binary format" +o2-raw-file-reader-workflow --input-conf raw/MCH/MCHraw.cfg -b | \ +o2-mch-raw-to-digits-workflow ${option} \ +--configKeyValues="MCHCoDecParam.sampaBcOffset=12345" -b | \ +o2-mch-digits-writer-workflow -b --binary-file-format 3 --outfile \ +digits.real.out &> raw-to-digits.log + +echo "=== Textual dump of real digits" +o2-mch-digits-file-dumper --infile digits.real.out \ +--print-digits &> digits.real.txt + diff --git a/Detectors/MUON/MCH/Raw/test/testClosureCoDec.cxx b/Detectors/MUON/MCH/Raw/test/testClosureCoDec.cxx index e5727cdc8acee..602a1c47d1bac 100644 --- a/Detectors/MUON/MCH/Raw/test/testClosureCoDec.cxx +++ b/Detectors/MUON/MCH/Raw/test/testClosureCoDec.cxx @@ -1,50 +1,110 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "MCHRawElecMap/Mapper.h" +#include "MCHRawEncoderPayload/DataBlock.h" #define BOOST_TEST_MODULE Test MCHRaw Closure #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "Framework/Logger.h" #include "MCHRawCommon/DataFormats.h" #include "MCHRawDecoder/PageDecoder.h" #include "MCHRawEncoderPayload/PayloadEncoder.h" #include "MCHRawEncoderPayload/PayloadPaginator.h" +#include <boost/mpl/list.hpp> #include <fmt/format.h> #include <iostream> -#include <boost/mpl/list.hpp> -#include "DetectorsRaw/HBFUtils.h" using namespace o2::mch::raw; -const char* sampaClusterFormat = "{}-CH{}-{}"; +std::vector<std::string> chargeSumInput = { + "S728-J1-DS0-CH3-ts-24-bc-0-cs-14-q-13", + "S728-J1-DS0-CH13-ts-24-bc-0-cs-134-q-133", + "S728-J1-DS0-CH23-ts-24-bc-0-cs-164-q-163", -template <typename FORMAT> -struct isUserLogicFormat { - static constexpr bool value = false; -}; + "S361-J0-DS4-CH0-ts-24-bc-0-cs-11-q-10", + "S361-J0-DS4-CH1-ts-24-bc-0-cs-21-q-20", + "S361-J0-DS4-CH2-ts-24-bc-0-cs-31-q-30", + "S361-J0-DS4-CH3-ts-24-bc-0-cs-41-q-40", -template <> -struct isUserLogicFormat<UserLogicFormat> { - static constexpr bool value = true; -}; + "S448-J6-DS2-CH22-ts-24-bc-0-cs-421-q-420", + "S448-J6-DS2-CH23-ts-24-bc-0-cs-431-q-430", + "S448-J6-DS2-CH24-ts-24-bc-0-cs-441-q-440", + "S448-J6-DS2-CH25-ts-24-bc-0-cs-451-q-450", + "S448-J6-DS2-CH26-ts-24-bc-0-cs-461-q-460", + "S448-J6-DS2-CH42-ts-24-bc-0-cs-421-q-420"}; -template <typename CHARGESUM> -struct isChargeSumMode { - static constexpr bool value = false; -}; +std::vector<std::string> sampleInput = { + "S728-J1-DS0-CH3-ts-24-bc-0-cs-3-q-13-15-17", + "S728-J1-DS0-CH13-ts-24-bc-0-cs-3-q-133-135-137", + "S728-J1-DS0-CH23-ts-24-bc-0-cs-2-q-163-165", -template <> -struct isChargeSumMode<ChargeSumMode> { - static constexpr bool value = true; -}; + "S361-J0-DS4-CH0-ts-24-bc-0-cs-3-q-10-12-14", + "S361-J0-DS4-CH1-ts-24-bc-0-cs-3-q-20-22-24", + "S361-J0-DS4-CH2-ts-24-bc-0-cs-3-q-30-32-34", + "S361-J0-DS4-CH3-ts-24-bc-0-cs-3-q-40-42-44", + + "S448-J6-DS2-CH22-ts-24-bc-0-cs-3-q-420-422-424", + "S448-J6-DS2-CH23-ts-24-bc-0-cs-3-q-430-432-434", + "S448-J6-DS2-CH24-ts-24-bc-0-cs-3-q-440-442-444", + "S448-J6-DS2-CH25-ts-24-bc-0-cs-3-q-450-452-454", + "S448-J6-DS2-CH26-ts-24-bc-0-cs-3-q-460-462-464", + "S448-J6-DS2-CH42-ts-24-bc-0-cs-5-q-420-422-424-426-428"}; + +template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION> +std::vector<std::byte> paginate(gsl::span<const std::byte> buffer, const std::string& tmpbasename) +{ + fair::Logger::SetConsoleSeverity("nolog"); + o2::raw::RawFileWriter fw; + + fw.setVerbosity(1); + fw.setDontFillEmptyHBF(true); + + auto solar2LinkInfo = createSolar2LinkInfo<ELECMAP, FORMAT, CHARGESUM, VERSION>(); + + // only use the solarIds that are actually in this test buffer + // (to speed up the test) + std::set<LinkInfo> links; + for (auto solarId : {361, 448, 728}) { + links.insert(solar2LinkInfo(solarId).value()); + } + + registerLinks(fw, tmpbasename, links, false, false); + + paginate(fw, buffer, links, solar2LinkInfo); + + fw.close(); + + auto filename = fmt::format("{:s}.raw", tmpbasename); + std::ifstream in(filename, std::ifstream::binary); + if (in.fail()) { + throw std::runtime_error(fmt::format("could not open ", filename)); + } + // get length of file: + in.seekg(0, in.end); + int length = in.tellg(); + in.seekg(0, in.beg); + std::vector<std::byte> pages(length); + + // read data as a block: + in.read(reinterpret_cast<char*>(&pages[0]), length); + + return pages; +} + +const char* sampaClusterFormat = "{}-CH{}-{}"; // Create a vector of SampaCluster from a string d // where d is of the form ts-#-bc-#-cs-#-q-# or @@ -55,7 +115,7 @@ std::vector<SampaCluster> getSampaClusters(const std::string& d) { std::vector<SampaCluster> clusters; - std::cout << "d: " << d << std::endl; + //std::cout << "d: " << d << std::endl; auto index = d.find("ts-"); auto ts = std::stoi(d.substr(index + 3)); @@ -80,6 +140,20 @@ std::vector<SampaCluster> getSampaClusters(const std::string& d) return clusters; } +std::set<DsElecId> getDs(gsl::span<std::string> data) +{ + std::set<DsElecId> dsids; + for (auto d : data) { + auto dsElecId = decodeDsElecId(d); + if (!dsElecId) { + std::cout << "Could not get dsElecId for " << d << "\n"; + continue; + } + dsids.insert(dsElecId.value()); + } + return dsids; +} + // create a raw data buffer from a list of strings // where each string is of the form // S#-J#-DS#-CH#-ts-#-bc-#-q-# @@ -89,12 +163,20 @@ std::vector<SampaCluster> getSampaClusters(const std::string& d) // - first create a buffer of payloads using a PayloadEncoder // - then create the raw data itself (with proper RDHs) from the payload buffer // -template <typename FORMAT, typename CHARGESUM> +template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION> std::vector<std::byte> createBuffer(gsl::span<std::string> data, uint32_t orbit = 12345, uint16_t bc = 678) { - auto encoder = createPayloadEncoder<FORMAT, CHARGESUM, true>(); + const o2::raw::HBFUtils& hbfutils = o2::raw::HBFUtils::Instance(); + o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirst", orbit); + + auto encoder = createPayloadEncoder(createSolar2FeeLinkMapper<ELECMAP>(), + isUserLogicFormat<FORMAT>::value, + VERSION, + isChargeSumMode<CHARGESUM>::value); encoder->startHeartbeatFrame(orbit, bc); + std::set<DsElecId> dsElecIds = getDs(data); + encoder->addHeartbeatHeaders(dsElecIds); for (auto d : data) { auto dsElecId = decodeDsElecId(d); if (!dsElecId) { @@ -110,32 +192,34 @@ std::vector<std::byte> createBuffer(gsl::span<std::string> data, std::vector<std::byte> buffer; encoder->moveToBuffer(buffer); - const o2::raw::HBFUtils& hbfutils = o2::raw::HBFUtils::Instance(); o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirst", orbit); - o2::conf::ConfigurableParam::setValue<uint16_t>("HBFUtils", "bcFirst", bc); - std::vector<std::byte> out = o2::mch::raw::paginate(buffer, - isUserLogicFormat<FORMAT>::value, - isChargeSumMode<CHARGESUM>::value, - fmt::format("mch-closure-codec-{}-{}.raw", - orbit, bc)); + o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirstSampled", orbit); + + std::vector<std::byte> out = + paginate<ELECMAP, FORMAT, CHARGESUM, VERSION>(buffer, + fmt::format("mch-closure-codec-{}-{}.raw", + orbit, bc)); return out; } // method that is called by the decoder each time a SampaCluster is decoded. SampaChannelHandler handlePacketStoreAsVec(std::vector<std::string>& result) { - return [&result](DsElecId dsId, uint8_t channel, SampaCluster sc) { + return [&result](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { result.emplace_back(fmt::format(sampaClusterFormat, asString(dsId), channel, asString(sc))); }; } // decode the buffer and check its content against the expected vector of strings +template <typename ELECMAP> bool testDecode(gsl::span<const std::byte> testBuffer, gsl::span<std::string> expected) { std::vector<std::string> result; - auto pageDecoder = createPageDecoder(testBuffer, handlePacketStoreAsVec(result)); - + DecodedDataHandlers handlers; + handlers.sampaChannelHandler = handlePacketStoreAsVec(result); + auto pageDecoder = createPageDecoder(testBuffer, handlers, + createFeeLink2SolarMapper<ELECMAP>()); auto parser = createPageParser(); parser(testBuffer, pageDecoder); @@ -155,60 +239,62 @@ bool testDecode(gsl::span<const std::byte> testBuffer, gsl::span<std::string> ex } return false; } + return true; } -BOOST_AUTO_TEST_SUITE(o2_mch_raw) +struct BareGen { + using format = BareFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 0; +}; -BOOST_AUTO_TEST_SUITE(closure) +struct UserLogicGen { + using format = UserLogicFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 0; +}; -std::vector<std::string> chargeSumInput = { - "S728-J1-DS0-CH3-ts-24-bc-0-cs-14-q-13", - "S728-J1-DS0-CH13-ts-24-bc-0-cs-134-q-133", - "S728-J1-DS0-CH23-ts-24-bc-0-cs-164-q-163", +struct UserLogicGen1 { + using format = UserLogicFormat; + using elecmap = ElectronicMapperGenerated; + static constexpr int version = 1; +}; - "S361-J0-DS4-CH0-ts-24-bc-0-cs-11-q-10", - "S361-J0-DS4-CH1-ts-24-bc-0-cs-21-q-20", - "S361-J0-DS4-CH2-ts-24-bc-0-cs-31-q-30", - "S361-J0-DS4-CH3-ts-24-bc-0-cs-41-q-40", +struct BareDummy { + using format = BareFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 0; +}; - "S448-J6-DS2-CH22-ts-24-bc-0-cs-421-q-420", - "S448-J6-DS2-CH23-ts-24-bc-0-cs-431-q-430", - "S448-J6-DS2-CH24-ts-24-bc-0-cs-441-q-440", - "S448-J6-DS2-CH25-ts-24-bc-0-cs-451-q-450", - "S448-J6-DS2-CH26-ts-24-bc-0-cs-461-q-460", - "S448-J6-DS2-CH42-ts-24-bc-0-cs-421-q-420"}; +struct UserLogicDummy { + using format = UserLogicFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 0; +}; -typedef boost::mpl::list<BareFormat, UserLogicFormat> testTypes; +struct UserLogicDummy1 { + using format = UserLogicFormat; + using elecmap = ElectronicMapperDummy; + static constexpr int version = 1; +}; + +typedef boost::mpl::list<BareGen, UserLogicGen, UserLogicGen1, BareDummy, UserLogicDummy, UserLogicDummy1> testTypes; -BOOST_AUTO_TEST_CASE_TEMPLATE(ClosureChargeSum, FORMAT, testTypes) +BOOST_AUTO_TEST_CASE_TEMPLATE(ClosureChargeSum, T, testTypes) { - auto buffer = createBuffer<FORMAT, ChargeSumMode>(chargeSumInput); - testDecode(buffer, chargeSumInput); + auto buffer = createBuffer<typename T::elecmap, + typename T::format, + ChargeSumMode, + T::version>(chargeSumInput); + testDecode<typename T::elecmap>(buffer, chargeSumInput); } -std::vector<std::string> sampleInput = { - "S728-J1-DS0-CH3-ts-24-bc-0-cs-3-q-13-15-17", - "S728-J1-DS0-CH13-ts-24-bc-0-cs-3-q-133-135-137", - "S728-J1-DS0-CH23-ts-24-bc-0-cs-2-q-163-165", - - "S361-J0-DS4-CH0-ts-24-bc-0-cs-3-q-10-12-14", - "S361-J0-DS4-CH1-ts-24-bc-0-cs-3-q-20-22-24", - "S361-J0-DS4-CH2-ts-24-bc-0-cs-3-q-30-32-34", - "S361-J0-DS4-CH3-ts-24-bc-0-cs-3-q-40-42-44", - - "S448-J6-DS2-CH22-ts-24-bc-0-cs-3-q-420-422-424", - "S448-J6-DS2-CH23-ts-24-bc-0-cs-3-q-430-432-434", - "S448-J6-DS2-CH24-ts-24-bc-0-cs-3-q-440-442-444", - "S448-J6-DS2-CH25-ts-24-bc-0-cs-3-q-450-452-454", - "S448-J6-DS2-CH26-ts-24-bc-0-cs-3-q-460-462-464", - "S448-J6-DS2-CH42-ts-24-bc-0-cs-5-q-420-422-424-426-428"}; - -BOOST_AUTO_TEST_CASE_TEMPLATE(ClosureSample, FORMAT, testTypes) +BOOST_AUTO_TEST_CASE_TEMPLATE(ClosureSample, T, testTypes) { - auto buffer = createBuffer<FORMAT, SampleMode>(sampleInput); - testDecode(buffer, sampleInput); + auto buffer = createBuffer<typename T::elecmap, + typename T::format, + SampleMode, + T::version>(sampleInput); + testDecode<typename T::elecmap>(buffer, sampleInput); } - -BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Raw/test/testClosureCoDecDigit.cxx b/Detectors/MUON/MCH/Raw/test/testClosureCoDecDigit.cxx new file mode 100644 index 0000000000000..044b19a319113 --- /dev/null +++ b/Detectors/MUON/MCH/Raw/test/testClosureCoDecDigit.cxx @@ -0,0 +1,193 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHRaw ClosureDigit +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/mpl/list.hpp> +#include <fstream> +#include "MCHRawDecoder/DataDecoder.h" +#include "MCHRawEncoderDigit/DigitRawEncoder.h" +#include "DataFormatsMCH/Digit.h" +#include "Framework/Logger.h" +#include <boost/test/data/test_case.hpp> +#include <boost/test/data/monomorphic.hpp> +#include <array> +#include "MCHMappingInterface/Segmentation.h" +#include "MCHRawCommon/CoDecParam.h" + +using namespace o2::mch::raw; + +const char* sampaClusterFormat = "{}-CH{}-{}"; + +struct DePadId { + int deid; + int padid; + bool operator==(const DePadId& other) const + { + return deid == other.deid && padid == other.padid; + } + bool operator<(const DePadId& other) const + { + if (deid == other.padid) { + return padid < other.padid; + } + return deid < other.padid; + } +}; + +std::ostream& operator<<(std::ostream& os, const DePadId& dpi) +{ + os << fmt::format("DE {:4d} PADID {:4d}", dpi.deid, dpi.padid); + return os; +} + +template <typename T> +SampaChannelHandler handlePacketStoreAsVec(std::vector<T>& result); + +// method that is called by the decoder each time a SampaCluster is decoded. +template <> +SampaChannelHandler handlePacketStoreAsVec(std::vector<std::string>& result) +{ + return [&result](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { + result.emplace_back(fmt::format(sampaClusterFormat, asString(dsId), channel, asString(sc))); + }; +} + +template <> +SampaChannelHandler handlePacketStoreAsVec(std::vector<DePadId>& result) +{ + auto elec2det = o2::mch::raw::createElec2DetMapper<ElectronicMapperDummy>(); + return [&result, elec2det](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) { + auto dsDet = elec2det(dsId); + auto deId = dsDet->deId(); + auto seg = o2::mch::mapping::segmentation(deId); + auto padId = seg.findPadByFEE(dsDet->dsId(), channel); + result.emplace_back(DePadId{dsDet->deId(), padId}); + }; +} + +void writeDigits(bool useDummyElecMap) +{ + std::cout << fmt::format("BEGIN writeDigits({})\n", useDummyElecMap); + fair::Logger::SetConsoleSeverity("nolog"); + { + std::vector<o2::mch::Digit> digits; + digits.emplace_back(923, 3959, 959, 123, 1); + digits.emplace_back(923, 3974, 974, 123, 1); + digits.emplace_back(100, 6664, 664, 123, 1); + + DigitRawEncoderOptions opts; + opts.splitMode = OutputSplit::None; // to get only one file + opts.noGRP = true; // as we don't have a GRP at hand + opts.noEmptyHBF = true; // as we don't want to create big files + opts.writeHB = false; // as we'd like to keep it simple + opts.userLogicVersion = 1; // test only the latest version + opts.dummyElecMap = useDummyElecMap; + + DigitRawEncoder dre(opts); + + uint32_t orbit{0}; + uint16_t bc{3456}; + + fair::Logger::SetConsoleSeverity("info"); + dre.encodeDigits(digits, orbit, bc); + //dre.addHeartbeats(std::set<DsElecId> dsElecIds, uint32_t orbit); + } + std::cout << fmt::format("END writeDigits({})\n", useDummyElecMap); +} + +std::vector<std::byte> getBuffer(const char* filename) +{ + std::vector<std::byte> buffer; + std::ifstream is(filename, std::ifstream::binary); + + is.seekg(0, is.end); + int length = is.tellg(); + is.seekg(0, is.beg); + + buffer.resize(length); + + is.read(reinterpret_cast<char*>(&buffer[0]), length); + is.close(); + return buffer; +} + +template <typename T> +std::vector<T> readDigits() +{ + std::vector<T> result; + DataDecoder dd(handlePacketStoreAsVec<T>(result), nullptr, 0, "", "", false, false, true); + + auto buffer = getBuffer("mch.raw"); + dd.decodeBuffer(buffer); + return result; +} + +BOOST_AUTO_TEST_CASE(WrittenAndReadBackDigitsShouldBeTheSameStringVersion) +{ + o2::conf::ConfigurableParam::setValue("MCHCoDecParam", "sampaBcOffset", 0); + std::vector<std::string> expected = { + "S728-J0-DS2-CH58-ts-0-bc-3456-cs-1-q-959", + "S728-J0-DS2-CH11-ts-0-bc-3456-cs-1-q-974", + "S363-J4-DS4-CH35-ts-0-bc-3456-cs-1-q-664"}; + writeDigits(true); + auto result = readDigits<std::string>(); + + bool sameSize = result.size() == expected.size(); + BOOST_CHECK_EQUAL(sameSize, true); + bool permutation = false; + if (sameSize) { + permutation = std::is_permutation(begin(result), end(result), begin(expected)); + BOOST_CHECK_EQUAL(permutation, true); + } + if (!permutation || !sameSize) { + std::cout << "Got " << result.size() << " results:\n"; + for (auto s : result) { + std::cout << s << "\n"; + } + std::cout << "Expected " << expected.size() << ":\n"; + for (auto s : expected) { + std::cout << s << "\n"; + } + } +} + +BOOST_AUTO_TEST_CASE(WrittenAndReadBackDigitsShouldBeTheSame) +{ + o2::conf::ConfigurableParam::setValue("MCHCoDecParam", "sampaBcOffset", 0); + std::vector<DePadId> expected = { + DePadId{923, 3959}, + DePadId{923, 3974}, + DePadId{100, 6664}}; + writeDigits(true); + auto result = readDigits<DePadId>(); + + bool sameSize = result.size() == expected.size(); + BOOST_CHECK_EQUAL(sameSize, true); + bool permutation = false; + if (sameSize) { + permutation = std::is_permutation(begin(result), end(result), begin(expected)); + BOOST_CHECK_EQUAL(permutation, true); + } + if (!permutation || !sameSize) { + std::cout << "Got " << result.size() << " results:\n"; + for (auto s : result) { + std::cout << s << "\n"; + } + std::cout << "Expected " << expected.size() << ":\n"; + for (auto s : expected) { + std::cout << s << "\n"; + } + } +} diff --git a/Detectors/MUON/MCH/Simulation/CMakeLists.txt b/Detectors/MUON/MCH/Simulation/CMakeLists.txt index 3cc9ca36c5694..d0692d1f9f20e 100644 --- a/Detectors/MUON/MCH/Simulation/CMakeLists.txt +++ b/Detectors/MUON/MCH/Simulation/CMakeLists.txt @@ -1,48 +1,46 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHSimulation SOURCES src/Detector.cxx + src/DEDigitizer.cxx src/Digitizer.cxx - src/Geometry.cxx - src/GeometryTest.cxx + src/DigitizerParam.cxx src/Hit.cxx - src/Materials.cxx - src/Materials.h - src/Response.cxx - src/Station1Geometry.cxx - src/Station1Geometry.h - src/Station2Geometry.cxx - src/Station2Geometry.h - src/Station345Geometry.cxx - src/Station345Geometry.h src/Stepper.cxx src/Stepper.h - PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat - O2::MCHBase O2::DetectorsPassive - O2::MCHMappingImpl4 O2::DetectorsBase - RapidJSON::RapidJSON) + src/Response.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsMCH + O2::DetectorsBase + O2::DetectorsPassive + O2::DetectorsRaw + O2::MCHBase + O2::MCHGeometryCreator + O2::MCHMappingImpl4 + O2::SimulationDataFormat) o2_target_root_dictionary(MCHSimulation HEADERS include/MCHSimulation/Detector.h include/MCHSimulation/Digitizer.h - include/MCHSimulation/Geometry.h - include/MCHSimulation/GeometryTest.h + include/MCHSimulation/DigitizerParam.h include/MCHSimulation/Hit.h include/MCHSimulation/Response.h) +o2_add_executable(inspect-collision-context + COMPONENT_NAME mch + SOURCES src/inspect-collision-context.cxx + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat) + o2_data_file(COPY data DESTINATION Detectors/MCH/simulation) if(BUILD_TESTING) add_subdirectory(test) - o2_add_test_root_macro(macros/drawMCHGeometry.C - PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase - LABELS "muon;mch") endif() diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DEDigitizer.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DEDigitizer.h new file mode 100644 index 0000000000000..6433386ab995e --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DEDigitizer.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_SIMULATION_DE_DIGITIZER_H +#define O2_MCH_SIMULATION_DE_DIGITIZER_H + +#include "DataFormatsMCH/Digit.h" +#include "MCHMappingInterface/Segmentation.h" +#include "MCHSimulation/Hit.h" +#include "MCHSimulation/Response.h" +#include "MathUtils/Cartesian.h" +#include <vector> +#include "SimulationDataFormat/MCTruthContainer.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2::mch +{ + +/** MCH Digitizer dealing with a single detection element. */ + +class DEDigitizer +{ + public: + DEDigitizer(int deId, o2::math_utils::Transform3D transformation); + + /** startCollision sets the current IR under consideration. + * + * All the digits created between a call to this one and clear() + * will be associated to a MCH ROFRecord == collisionTime + */ + void startCollision(o2::InteractionRecord collisionTime); + + /** Add some noise to the current collision */ + void addNoise(float noiseProba); + + /** process one MCH Hit. + * + * This will convert the hit eloss into a charge and spread (according + * to a Mathieson 2D distribution) that charge among several pads, + * that will become digits eventually + * + * @param hit the input hit to be digitized + * @param evID the event identifier of the hit in the sim chain within srcID + * @param srcID the origin (signal, background) of the hit + * @see o2::steer::EventPart + */ + void process(const Hit& hit, int evID, int srcID); + + /** extractDigitsAndLabels appends digits and labels to given containers. + * + * This function copies our internal information into the parameter vectors + * + * @param digits vector of digits where we append our internal digits. + * @param labels MCTruthContainer where we append our internal labels. + */ + void extractDigitsAndLabels(std::vector<Digit>& digits, + o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels); + + /** Clear resets our internal lists of digits and labels. */ + void clear(); + + private: + int mDeId; // detection element id + Response mResponse; // response function (Mathieson parameters, ...) + o2::math_utils::Transform3D mTransformation; // from local to global and reverse + mapping::Segmentation mSegmentation; // mapping of this detection element + o2::InteractionRecord mIR; // interaction record to associate charges and labels to + std::vector<float> mCharges; // pad charges (fixed size = number of pads in this DE) + std::vector<std::vector<o2::MCCompLabel>> mLabels; // mLabels.size()==mCharges.size() +}; + +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Detector.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Detector.h index ed97a16a40975..2c378e0a8e805 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Detector.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Digitizer.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Digitizer.h index 72d727241d9c3..61b19ef9e3b67 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Digitizer.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Digitizer.h @@ -1,100 +1,74 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/** @file Digitizer.h - * C++ MCH Digitizer. - * @author Michael Winn, Laurent Aphecetche - */ - -#ifndef O2_MCH_SIMULATION_MCHDIGITIZER_H_ -#define O2_MCH_SIMULATION_MCHDIGITIZER_H_ +#ifndef O2_MCH_SIMULATION_DIGITIZER_H +#define O2_MCH_SIMULATION_DIGITIZER_H -#include "MCHBase/Digit.h" #include "MCHSimulation/Hit.h" - +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHSimulation/DEDigitizer.h" +#include <map> +#include <gsl/span> #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" -namespace o2 +namespace o2::mch { -namespace mch -{ - +/** MCH Digitizer. + * + * This class is just steering the usage of o2::mch::DEDigitizer + * + */ class Digitizer { public: - Digitizer(int mode = 0); - - ~Digitizer() = default; - - void init(); - - //process hits: fill digit vector with digits - void process(const std::vector<Hit> hits, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer); - void provideMC(o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer); - void mergeDigits(); - void generateNoiseDigits(); - //external pile-up adding up - void mergeDigits(std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer); - - void fillOutputContainer(std::vector<Digit>& digits); + /** Constructor. + * @param transformationCreator is a function that is able to create + * a geo::TransformationCreator + */ + Digitizer(geo::TransformationCreator transformationCreator); - void setEventTime(double timeNS) { mEventTime = timeNS; } + // @see DEDigitizer::addNoise + void addNoise(float noiseProba); - void setContinuous(bool val) { mContinuous = val; } - bool isContinuous() const { return mContinuous; } + // @see DEDigitizer::startCollision + void startCollision(o2::InteractionRecord collisionTime); - void setSrcID(int v); - int getSrcID() const { return mSrcID; } + // @see DEDigitizer::processHit + void processHits(gsl::span<Hit> hits, int evID, int srcID); - void setEventID(int v); - int getEventID() const { return mEventID; } + // @see DEDigitizer::extractDigitsAndLabels + void extractDigitsAndLabels(std::vector<Digit>& digits, + o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels); - void setNoise(bool val) { mNoise = val; } - bool isNoise() const { return mNoise; } - - //for debugging - std::vector<Digit> getDigits() { return mDigits; } - std::vector<o2::MCCompLabel> getTrackLabels() { return mTrackLabels; } + // @see DEDigitizer:clear + void clear(); private: - int mEventTime; - int mEventID = 0; - int mSrcID = 0; - - bool mContinuous = false; - bool mNoise = true; - - //time difference allowed for pileup (in ns (assuming that event time is in ns)) - float mDeltat = 100.; - - //number of detector elements - const static int mNdE = 156; - - //noise above threshold probability within read-out window - float mProbNoise = 1e-5; - //sum_i 1/padcount_i where i is the detelemID - float mInvPadSum = 0.0450832; - float mNormProbNoise = mProbNoise / mInvPadSum; - - // digit per pad - std::vector<Digit> mDigits; + std::map<int, std::unique_ptr<DEDigitizer>> mDEDigitizers; // list of workers +}; - //MCLabel container (transient) - std::vector<o2::MCCompLabel> mTrackLabels; - //MCLabel container (output) - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mMCTruthOutputContainer; +/** Group Interaction Record that are "too close" in time (BC). + * + * @param records : a list of input IR to group + * @param width (in BC unit) : all IRs within this distance will be considered + * to be a single group + * + * @returns a map of IRs->{index} where index is relative to input records + * + */ +std::map<o2::InteractionRecord, std::vector<int>> groupIR(gsl::span<const o2::InteractionRecord> records, uint32_t width = 4); - int processHit(const Hit& hit, int detID, int event_time); -}; +/** Same as above for InteractionTimeRecord. */ +std::map<o2::InteractionRecord, std::vector<int>> groupIR(gsl::span<const o2::InteractionTimeRecord> records, uint32_t width = 4); -} // namespace mch -} // namespace o2 +} // namespace o2::mch #endif diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DigitizerParam.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DigitizerParam.h new file mode 100644 index 0000000000000..d632625e5fdc8 --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/DigitizerParam.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_SIMULATION_DIGITIZER_PARAM_H_ +#define O2_MCH_SIMULATION_DIGITIZER_PARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2::mch +{ + +struct DigitizerParam : public o2::conf::ConfigurableParamHelper<DigitizerParam> { + + bool continuous = true; // whether we assume continuous mode or not + float noiseProba = 3.1671242e-05; // by default = proba to be above 4*sigma of a gaussian noise + + O2ParamDef(DigitizerParam, "MCHDigitizerParam") +}; + +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Geometry.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Geometry.h deleted file mode 100644 index 4857f8a3032cd..0000000000000 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Geometry.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file Geometry.h -/// @brief Interface for MCH geometry creation - -#ifndef O2_MCH_SIMULATION_GEOMETRY_H -#define O2_MCH_SIMULATION_GEOMETRY_H - -#include <vector> -#include <iostream> -#include "MathUtils/Cartesian.h" - -class TGeoVolume; -class TGeoManager; - -namespace o2 -{ -namespace mch -{ - -/// createGeometry creates MCH geometry and attach it to existing topVolume -void createGeometry(TGeoVolume& topVolume); - -/// get a list of MCH sensitive volumes -std::vector<TGeoVolume*> getSensitiveVolumes(); - -/// Add alignable mch volumes -void addAlignableVolumesMCH(); - -/// get the local-to-global transformation for a given detection element -o2::math_utils::Transform3D getTransformation(int detElemId, const TGeoManager& geo); - -} // namespace mch -} // namespace o2 - -#endif // O2_MCH_SIMULATION_GEOMETRY_H diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/GeometryTest.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/GeometryTest.h deleted file mode 100644 index 52815f9d5e14b..0000000000000 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/GeometryTest.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_MCH_SIMULATION_GEOMETRYTEST_H -#define O2_MCH_SIMULATION_GEOMETRYTEST_H - -#include <iostream> - -class TH2; - -namespace o2 -{ -namespace mch -{ -namespace test -{ - -/// creates MCH geometry from scratch (i.e. from a null TGeoManager) -/// usefull for tests or drawing for instance. -void createStandaloneGeometry(); - -/// creates MCH geometry with the beam shielding and the dipole -/// from scratch (i.e. from a null TGeoManager). -/// usefull for tests. -void createRegularGeometry(); - -/// creates MCH regular geometry and adds alignable volumes -/// useull for tests. -void addAlignableVolumes(); - -/// tree like textual dump of the geometry nodes -void showGeometryAsTextTree(const char* fromPath = "", int maxdepth = 2, std::ostream& out = std::cout); - -/// basic drawing of the geometry -void drawGeometry(); - -/// set the volume and daughter visibility for all volumes with a name matching the regexp pattern -void setVolumeVisibility(const char* pattern, bool visible, bool visibleDaughters); - -/// set the volume line and fill for all volumes with a name matching the regexp pattern -void setVolumeColor(const char* pattern, int lineColor, int fillColor); -inline void setVolumeColor(const char* pattern, int color) -{ - setVolumeColor(pattern, color, color); -} - -/// get a radlen radiograph of a given detection element within box with the given granularity -TH2* getRadio(int detElemId, float xmin, float ymin, float xmax, float ymax, float xstep, float ystep, float thickness = 5 /* cm */); - -class Dummy -{ - // to force Root produce a dictionary for namespace test (seems it is doing it fully if there are only functions in the namespace) -}; -} // namespace test -} // namespace mch -} // namespace o2 - -#endif diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h index 8d0d639b39271..d216654a36add 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h index 7d5aff87cedb6..f20643bfe76a5 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,7 @@ #ifndef O2_MCH_SIMULATION_RESPONSE_H_ #define O2_MCH_SIMULATION_RESPONSE_H_ -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" #include "MCHSimulation/Detector.h" #include "MCHSimulation/Hit.h" @@ -38,7 +39,7 @@ class Response float etocharge(float edepos); double chargePadfraction(float xmin, float xmax, float ymin, float ymax); double chargefrac1d(float min, float max, double k2, double sqrtk3, double k4); - unsigned long response(unsigned long adc); + uint32_t response(uint32_t adc); float getAnod(float x); float chargeCorr(); bool aboveThreshold(float charge) { return charge > mChargeThreshold; }; diff --git a/Detectors/MUON/MCH/Simulation/macros/drawMCHGeometry.C b/Detectors/MUON/MCH/Simulation/macros/drawMCHGeometry.C deleted file mode 100644 index 82b56b2fafbdd..0000000000000 --- a/Detectors/MUON/MCH/Simulation/macros/drawMCHGeometry.C +++ /dev/null @@ -1,8 +0,0 @@ -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include "MCHSimulation/GeometryTest.h" -#endif - -void drawMCHGeometry() -{ - o2::mch::test::drawGeometry(); -} diff --git a/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx new file mode 100644 index 0000000000000..b687ecdf13e87 --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx @@ -0,0 +1,166 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHSimulation/DEDigitizer.h" +#include "DetectorsRaw/HBFUtils.h" +#include <cmath> +#include <random> + +using o2::math_utils::Point3D; + +namespace o2::mch +{ + +DEDigitizer::DEDigitizer(int deId, o2::math_utils::Transform3D transformation) + : mDeId{deId}, + mResponse{deId < 300 ? Station::Type1 : Station::Type2345}, + mTransformation{transformation}, + mSegmentation{o2::mch::mapping::segmentation(deId)}, + mCharges(mSegmentation.nofPads()), + mLabels(mSegmentation.nofPads()) +{ +} + +void DEDigitizer::startCollision(o2::InteractionRecord collisionTime) +{ + mIR = collisionTime; + clear(); +} + +void DEDigitizer::process(const Hit& hit, int evID, int srcID) +{ + MCCompLabel label(hit.GetTrackID(), evID, srcID); + Point3D<float> pos(hit.GetX(), hit.GetY(), hit.GetZ()); + + //convert energy to charge + auto charge = mResponse.etocharge(hit.GetEnergyLoss()); + + auto time = mIR.differenceInBC(o2::raw::HBFUtils::Instance().orbitFirst); + // digit time will disappear anyway ? (same information in ROFRecord) + + //transformation from global to local + Point3D<float> lpos; + mTransformation.MasterToLocal(pos, lpos); + + auto anodpos = mResponse.getAnod(lpos.X()); + auto fracplane = mResponse.chargeCorr(); + auto chargebend = fracplane * charge; + auto chargenon = charge / fracplane; + + //borders of charge gen. + auto xMin = anodpos - mResponse.getQspreadX() * mResponse.getSigmaIntegration() * 0.5; + auto xMax = anodpos + mResponse.getQspreadX() * mResponse.getSigmaIntegration() * 0.5; + auto yMin = lpos.Y() - mResponse.getQspreadY() * mResponse.getSigmaIntegration() * 0.5; + auto yMax = lpos.Y() + mResponse.getQspreadY() * mResponse.getSigmaIntegration() * 0.5; + + //get segmentation for detector element + auto localX = anodpos; + auto localY = lpos.Y(); + + //get area for signal induction from segmentation + //single pad as check + int padidbendcent = 0; + int padidnoncent = 0; + int ndigits = 0; + + bool padexists = mSegmentation.findPadPairByPosition(localX, localY, padidbendcent, padidnoncent); + if (!padexists) { + LOGP(warning, "Did not find _any_ pad for localX,Y={},{} for DeId {}", localX, localY, mDeId); + return; + } + + std::vector<int> padids; + + // get all pads within the defined bounding box ... + mSegmentation.forEachPadInArea(xMin, yMin, xMax, yMax, [&padids](int padid) { + padids.emplace_back(padid); + }); + + // ... and loop over all those pads to compute the charge on each of them + for (auto padid : padids) { + auto dx = mSegmentation.padSizeX(padid) * 0.5; + auto dy = mSegmentation.padSizeY(padid) * 0.5; + auto xmin = (localX - mSegmentation.padPositionX(padid)) - dx; + auto xmax = xmin + 2 * dx; + auto ymin = (localY - mSegmentation.padPositionY(padid)) - dy; + auto ymax = ymin + 2 * dy; + auto q = mResponse.chargePadfraction(xmin, xmax, ymin, ymax); + if (mResponse.aboveThreshold(q)) { + if (mSegmentation.isBendingPad(padid)) { + q *= chargebend; + } else { + q *= chargenon; + } + if (q > 0) { + mCharges[padid] += q; + mLabels[padid].emplace_back(label); + } + } + } +} + +void DEDigitizer::addNoise(float noiseProba) +{ + std::random_device rd; + std::mt19937 mt(rd()); + + float mean = noiseProba * mSegmentation.nofPads(); + float sigma = mean / std::sqrt(mean); + + std::normal_distribution<float> gaus(mean, sigma); + + int nofNoisyPads = std::ceil(gaus(mt)); + + std::uniform_int_distribution<int> ids(0, mSegmentation.nofPads() - 1); + + float chargeNoise = 1.2; + // FIXME: draw this also from some distribution (according to + // some parameters in DigitizerParam) + for (auto i = 0; i < nofNoisyPads; i++) { + auto padid = ids(mt); + mCharges[padid] += chargeNoise; + mLabels[padid].emplace_back(true); + } +} + +void DEDigitizer::extractDigitsAndLabels(std::vector<Digit>& digits, + o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels) +{ + int dataindex = labels.getIndexedSize(); + for (auto padid = 0; padid < mCharges.size(); ++padid) { + auto q = mCharges[padid]; + if (q <= 0) { + continue; + } + // FIXME: this is just to compare with previous MCHDigitizer + auto signal = (uint32_t)q * mResponse.getInverseChargeThreshold(); + auto padc = signal * mResponse.getChargeThreshold(); + auto adc = mResponse.response(TMath::Nint(padc)); + if (adc > 0) { + auto time = mIR.differenceInBC(o2::raw::HBFUtils::Instance().orbitFirst); + digits.emplace_back(mDeId, padid, adc, time, 1); + for (auto element : mLabels[padid]) { + labels.addElement(dataindex, element); + } + ++dataindex; + } + } +} + +void DEDigitizer::clear() +{ + std::fill(mCharges.begin(), mCharges.end(), 0); + for (auto& label : mLabels) { + label.clear(); + } +} + +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Simulation/src/Detector.cxx b/Detectors/MUON/MCH/Simulation/src/Detector.cxx index 6d244e77a4151..b27cd1106cf0a 100644 --- a/Detectors/MUON/MCH/Simulation/src/Detector.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Detector.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "MCHSimulation/Detector.h" -#include "MCHSimulation/Geometry.h" +#include "MCHGeometryCreator/Geometry.h" #include "SimulationDataFormat/Stack.h" #include "Stepper.h" #include "TGeoManager.h" @@ -42,7 +43,7 @@ Detector::~Detector() void Detector::defineSensitiveVolumes() { - for (auto* vol : getSensitiveVolumes()) { + for (auto* vol : geo::getSensitiveVolumes()) { AddSensitiveVolume(vol); } } @@ -58,7 +59,7 @@ void Detector::ConstructGeometry() if (!top) { throw std::runtime_error("Cannot create MCH geometry without a top volume"); } - createGeometry(*top); + geo::createGeometry(*gGeoManager, *top); } void Detector::addAlignableVolumes() const @@ -66,7 +67,7 @@ void Detector::addAlignableVolumes() const if (!gGeoManager) { throw std::runtime_error("Cannot add alignable volumes without TGeoManager"); } - addAlignableVolumesMCH(); + geo::addAlignableVolumes(*gGeoManager); } Bool_t Detector::ProcessHits(FairVolume* v) diff --git a/Detectors/MUON/MCH/Simulation/src/Digitizer.cxx b/Detectors/MUON/MCH/Simulation/src/Digitizer.cxx index 9d9b3ccc9ef21..b92de2432a6fa 100644 --- a/Detectors/MUON/MCH/Simulation/src/Digitizer.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Digitizer.cxx @@ -1,338 +1,93 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "MCHSimulation/Digitizer.h" - #include "MCHMappingInterface/Segmentation.h" -#include "MCHSimulation/Geometry.h" -#include "MCHSimulation/Response.h" -#include "TGeoManager.h" -#include "TMath.h" -#include "TRandom.h" +#include "CommonDataFormat/InteractionRecord.h" #include <algorithm> -#include <cassert> -#include <fairlogger/Logger.h> - -#include <iostream> -using namespace std; - -using namespace o2::mch; -namespace +namespace o2::mch { -std::map<int, int> createDEMap() +Digitizer::Digitizer(geo::TransformationCreator transformationCreator) { - std::map<int, int> m; - int i{0}; - o2::mch::mapping::forEachDetectionElement([&m, &i](int deid) { - m[deid] = i++; + mapping::forEachDetectionElement([&transformation = transformationCreator, &digitizers = this->mDEDigitizers](int deId) { + digitizers[deId] = std::make_unique<DEDigitizer>(deId, transformation(deId)); }); - return m; } -int deId2deIndex(int detElemId) +void Digitizer::addNoise(float noiseProba) { - static std::map<int, int> m = createDEMap(); - return m[detElemId]; -} - -std::vector<o2::mch::mapping::Segmentation> createSegmentations() -{ - std::vector<o2::mch::mapping::Segmentation> segs; - o2::mch::mapping::forEachDetectionElement([&segs](int deid) { - segs.emplace_back(deid); - }); - return segs; -} - -const o2::mch::mapping::Segmentation& segmentation(int detElemId) -{ - static auto segs = createSegmentations(); - return segs[deId2deIndex(detElemId)]; -} - -bool isStation1(int detID) -{ - return detID < 300; -} - -Response& response(bool isStation1) -{ - static std::array<Response, 2> resp = {Response(Station::Type2345), Response(Station::Type1)}; - return resp[isStation1]; + if (noiseProba > 0) { + for (auto& d : mDEDigitizers) { + d.second->addNoise(noiseProba); + } + } } -int getGlobalDigit(int detID, int padID) +void Digitizer::startCollision(o2::InteractionRecord collisionTime) { - //calculate global index - return detID * 100000 + padID; + for (auto& d : mDEDigitizers) { + d.second->startCollision(collisionTime); + } } -} // namespace - -Digitizer::Digitizer(int) {} - -void Digitizer::init() +void Digitizer::processHits(gsl::span<Hit> hits, int evID, int srcID) { + for (const auto& hit : hits) { + mDEDigitizers[hit.detElemId()]->process(hit, evID, srcID); + } } -//______________________________________________________________________ -void Digitizer::process(const std::vector<Hit> hits, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer) +void Digitizer::extractDigitsAndLabels(std::vector<Digit>& digits, + o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels) { - digits.clear(); - mDigits.clear(); - mTrackLabels.clear(); - mcContainer.clear(); - //array of MCH hits for a given simulated event - for (auto& hit : hits) { - int detID = hit.GetDetectorID(); - int ndigits = processHit(hit, detID, mEventTime); - MCCompLabel label(hit.GetTrackID(), mEventID, mSrcID, false); - for (int i = 0; i < ndigits; ++i) { - int digitIndex = mDigits.size() - ndigits + i; - mMCTruthOutputContainer.addElement(digitIndex, label); - } //loop over digits to generate MCdigits - } //loop over hits - - //generate noise-only digits - if (mNoise) { - generateNoiseDigits(); + for (auto& d : mDEDigitizers) { + d.second->extractDigitsAndLabels(digits, labels); } - - fillOutputContainer(digits); - provideMC(mcContainer); } -//______________________________________________________________________ -int Digitizer::processHit(const Hit& hit, int detID, int event_time) -{ - math_utils::Point3D<float> pos(hit.GetX(), hit.GetY(), hit.GetZ()); - - Response& resp = response(isStation1(detID)); - //convert energy to charge - auto charge = resp.etocharge(hit.GetEnergyLoss()); - - //convert float ns time to BC counts - auto time = event_time & int(hit.GetTime() / 25.); - - //transformation from global to local - auto t = o2::mch::getTransformation(detID, *gGeoManager); - math_utils::Point3D<float> lpos; - t.MasterToLocal(pos, lpos); - - auto anodpos = resp.getAnod(lpos.X()); - auto fracplane = resp.chargeCorr(); - auto chargebend = fracplane * charge; - auto chargenon = charge / fracplane; - - //borders of charge gen. - auto xMin = anodpos - resp.getQspreadX() * resp.getSigmaIntegration() * 0.5; - auto xMax = anodpos + resp.getQspreadX() * resp.getSigmaIntegration() * 0.5; - auto yMin = lpos.Y() - resp.getQspreadY() * resp.getSigmaIntegration() * 0.5; - auto yMax = lpos.Y() + resp.getQspreadY() * resp.getSigmaIntegration() * 0.5; - - //get segmentation for detector element - auto& seg = segmentation(detID); - auto localX = anodpos; - auto localY = lpos.Y(); - - //get area for signal induction from segmentation - //single pad as check - int padidbendcent = 0; - int padidnoncent = 0; - int ndigits = 0; - - bool padexists = seg.findPadPairByPosition(localX, localY, padidbendcent, padidnoncent); - if (!padexists) { - LOG(WARNING) << "Did not find _any_ pad for localX,Y=" << localX << "," << localY << ", for detID: " << detID; - return 0; +void Digitizer::clear() +{ + for (auto& d : mDEDigitizers) { + d.second->clear(); } - - seg.forEachPadInArea(xMin, yMin, xMax, yMax, [&resp, &digits = this->mDigits, chargebend, chargenon, localX, localY, &seg, &ndigits, detID, time](int padid) { - auto dx = seg.padSizeX(padid) * 0.5; - auto dy = seg.padSizeY(padid) * 0.5; - auto xmin = (localX - seg.padPositionX(padid)) - dx; - auto xmax = xmin + 2 * dx; - auto ymin = (localY - seg.padPositionY(padid)) - dy; - auto ymax = ymin + 2 * dy; - auto q = resp.chargePadfraction(xmin, xmax, ymin, ymax); - if (resp.aboveThreshold(q)) { - if (seg.isBendingPad(padid)) { - q *= chargebend; - } else { - q *= chargenon; - } - auto signal = (unsigned long)q * resp.getInverseChargeThreshold(); - if (signal > 0) { - Digit::Time dtime; - dtime.sampaTime = static_cast<uint16_t>(time) & 0x3FF; - digits.emplace_back(detID, padid, signal, dtime); - ++ndigits; - } - } - }); - return ndigits; } -//______________________________________________________________________ -void Digitizer::generateNoiseDigits() -{ - o2::mch::mapping::forEachDetectionElement([& digits = this->mDigits, &normProbNoise = this->mNormProbNoise, - &eventTime = this->mEventTime, &eventID = this->mEventID, - &srcID = this->mSrcID, &mcTruthOutputContainer = this->mMCTruthOutputContainer](int detID) { - auto& seg = segmentation(detID); - auto nPads = seg.nofPads(); - auto nNoisyPadsAv = (float)nPads * normProbNoise; - int nNoisyPads = TMath::Nint(gRandom->Gaus(nNoisyPadsAv, TMath::Sqrt(nNoisyPadsAv))); - for (int i = 0; i < nNoisyPads; i++) { - int padid = gRandom->Integer(nNoisyPads + 1); - Digit::Time dtime; - dtime.sampaTime = static_cast<uint16_t>(eventTime) & 0x3FF; - digits.emplace_back(detID, padid, 0.6, dtime); - //just to roun adbove threshold when added - MCCompLabel label(-1, eventID, srcID, true); - mcTruthOutputContainer.addElement(digits.size() - 1, label); - } - }); - //not clear how to normalise to time: - //assume that only "one" event equivalent, - //otherwise the probability will strongly depend on read-out-frame time length -} -//______________________________________________________________________ -void Digitizer::mergeDigits() +std::map<o2::InteractionRecord, std::vector<int>> groupIR(gsl::span<const o2::InteractionTimeRecord> records, uint32_t width) { - std::vector<int> indices(mDigits.size()); - std::iota(begin(indices), end(indices), 0); - std::sort(indices.begin(), indices.end(), [& digits = this->mDigits, this](int a, int b) { - return (getGlobalDigit(digits[a].getDetID(), digits[a].getPadID()) < getGlobalDigit(digits[b].getDetID(), digits[b].getPadID())); - }); - - auto sortedDigits = [digits = this->mDigits, &indices](int i) { - return digits[indices[i]]; - }; - - auto sortedLabels = [labels = this->mTrackLabels, &indices](int i) { - return labels[indices[i]]; - }; - - auto sizedigits = mDigits.size(); - - mDigits.clear(); - mDigits.reserve(sizedigits); - mMCTruthOutputContainer.clear(); - - int count = 0; - - int i = 0; - while (i < indices.size()) { - int j = i + 1; - while (j < indices.size() && (getGlobalDigit(sortedDigits(i).getDetID(), sortedDigits(i).getPadID())) == (getGlobalDigit(sortedDigits(j).getDetID(), sortedDigits(j).getPadID())) && (std::fabs(sortedDigits(i).getTime().sampaTime - sortedDigits(j).getTime().sampaTime) < mDeltat)) { - j++; - } - unsigned long adc{0}; - float padc{0}; - Response& resp = response(isStation1(sortedDigits(i).getDetID())); - - for (int k = i; k < j; k++) { - adc += sortedDigits(k).getADC(); - if (k == i) { - MCCompLabel label(sortedLabels(i).getTrackID(), sortedLabels(i).getEventID(), sortedLabels(i).getSourceID(), false); - mMCTruthOutputContainer.addElement(count, label); - } else { - if ((sortedLabels(k).getTrackID() != sortedLabels(k - 1).getTrackID()) || (sortedLabels(k).getSourceID() != sortedLabels(k - 1).getSourceID())) { - MCCompLabel label(sortedLabels(k).getTrackID(), sortedLabels(k).getEventID(), sortedLabels(k).getSourceID(), false); - mMCTruthOutputContainer.addElement(count, label); - } - } - } - padc = adc * resp.getChargeThreshold(); - adc = TMath::Nint(padc); - adc = resp.response(adc); - mDigits.emplace_back(sortedDigits(i).getDetID(), sortedDigits(i).getPadID(), adc, sortedDigits(i).getTime()); - i = j; - ++count; + std::vector<o2::InteractionRecord> irs; + for (const auto& ir : records) { + irs.emplace_back(ir.bc, ir.orbit); } - mDigits.resize(mDigits.size()); + return groupIR(irs, width); } -//______________________________________________________________________ -void Digitizer::mergeDigits(std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer) -{ - mDigits.clear(); - mDigits.reserve(digits.size()); - mTrackLabels.clear(); - for (int index = 0; index < digits.size(); ++index) { - auto digit = digits.at(index); - mDigits.emplace_back(digit.getDetID(), digit.getPadID(), digit.getADC(), digit.getTime()); - } - for (int index = 0; index < mcContainer.getNElements(); ++index) { - auto label = mcContainer.getElement(index); - mTrackLabels.emplace_back(label.getTrackID(), label.getEventID(), label.getSourceID(), false); - } - - mergeDigits(); - fillOutputContainer(digits); - provideMC(mcContainer); -} -//______________________________________________________________________ -void Digitizer::fillOutputContainer(std::vector<Digit>& digits) +std::map<o2::InteractionRecord, std::vector<int>> groupIR(gsl::span<const o2::InteractionRecord> records, uint32_t width) { - // filling the digit container - if (mDigits.empty()) { - return; + if (!std::is_sorted(records.begin(), records.end())) { + throw std::invalid_argument("input records must be sorted"); } - - digits.clear(); - digits.reserve(mDigits.size()); - - auto itBeg = mDigits.begin(); - auto iter = itBeg; - for (; iter != mDigits.end(); ++iter) { - digits.emplace_back(*iter); + if (width < 1) { + throw std::invalid_argument("width must be >=1"); } - mDigits.erase(itBeg, iter); -} -//______________________________________________________________________ -void Digitizer::setSrcID(int v) -{ - //set current MC source ID - if (v > MCCompLabel::maxSourceID()) { - LOG(FATAL) << "MC source id " << v << " exceeds max storable in the label " << MCCompLabel::maxSourceID(); + std::map<o2::InteractionRecord, std::vector<int>> binned; + auto ir0 = records[0]; + for (auto i = 0; i < records.size(); ++i) { + auto ir = records[i]; + auto mchIR = ir; + mchIR.bc = mchIR.bc - mchIR.bc % width; + binned[mchIR].emplace_back(i); } - mSrcID = v; + return binned; } -//______________________________________________________________________ -void Digitizer::setEventID(int v) -{ - // set current MC event ID - if (v > MCCompLabel::maxEventID()) { - LOG(FATAL) << "MC event id " << v << " exceeds max storabel in the label " << MCCompLabel::maxEventID(); - } - mEventID = v; -} -//______________________________________________________________________ -void Digitizer::provideMC(o2::dataformats::MCTruthContainer<o2::MCCompLabel>& mcContainer) -{ - //fill MCtruth info - mcContainer.clear(); - if (mMCTruthOutputContainer.getNElements() == 0) { - return; - } - - //need to fill groups of labels not only single labels, since index in addElements - // is the data index - //write a map that fixes? - for (int index = 0; index < mMCTruthOutputContainer.getIndexedSize(); ++index) { - mcContainer.addElements(index, mMCTruthOutputContainer.getLabels(index)); - } - mMCTruthOutputContainer.clear(); -} +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Simulation/src/DigitizerParam.cxx b/Detectors/MUON/MCH/Simulation/src/DigitizerParam.cxx new file mode 100644 index 0000000000000..14a2bd2509730 --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/src/DigitizerParam.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ParameterGas.cxx +/// \brief Implementation of the parameter class for the detector gas +/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de + +#include "MCHSimulation/DigitizerParam.h" + +using namespace o2::mch; +O2ParamImpl(o2::mch::DigitizerParam); diff --git a/Detectors/MUON/MCH/Simulation/src/Geometry.cxx b/Detectors/MUON/MCH/Simulation/src/Geometry.cxx deleted file mode 100644 index a5f6a82541f78..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/Geometry.cxx +++ /dev/null @@ -1,654 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "MCHSimulation/Geometry.h" - -#include "Station1Geometry.h" -#include "Station2Geometry.h" -#include "Station345Geometry.h" -#include "Materials.h" -#include <iostream> -#include <fmt/format.h> -#include "TGeoVolume.h" -#include "TGeoManager.h" -#include "Framework/Logger.h" - -namespace o2 -{ -namespace mch -{ -void createGeometry(TGeoVolume& topVolume) -{ - createMaterials(); - - auto volYOUT1 = gGeoManager->GetVolume("YOUT1"); - - createStation1Geometry((volYOUT1) ? *volYOUT1 : topVolume); - createStation2Geometry((volYOUT1) ? *volYOUT1 : topVolume); - - createStation345Geometry(topVolume); -} - -std::vector<TGeoVolume*> getSensitiveVolumes() -{ - auto st1 = getStation1SensitiveVolumes(); - auto st2 = getStation2SensitiveVolumes(); - auto st345 = getStation345SensitiveVolumes(); - - auto vol = st1; - vol.insert(vol.end(), st2.begin(), st2.end()); - vol.insert(vol.end(), st345.begin(), st345.end()); - - return vol; -} - -namespace impl -{ -// return the path of the mother volume of detElemId, relative to MCH geometry -// (i.e. excluding general top node) -std::string getVolumePathName(int detElemId) -{ - std::string vp{"incorrect detElemId"}; - - if (detElemId == 100) { - return "SC01I_0/Quadrant (chamber 1)_100"; - } - if (detElemId == 103) { - return "SC01I_0/Quadrant (chamber 1)_103"; - } - if (detElemId == 101) { - return "SC01O_1/Quadrant (chamber 1)_101"; - } - if (detElemId == 102) { - return "SC01O_1/Quadrant (chamber 1)_102"; - } - if (detElemId == 200) { - return "SC02I_2/Quadrant (chamber 2)_200"; - } - if (detElemId == 203) { - return "SC02I_2/Quadrant (chamber 2)_203"; - } - if (detElemId == 201) { - return "SC02O_3/Quadrant (chamber 2)_201"; - } - if (detElemId == 202) { - return "SC02O_3/Quadrant (chamber 2)_202"; - } - if (detElemId == 300) { - return "SC03I_4/Station 2 quadrant_300"; - } - if (detElemId == 303) { - return "SC03I_4/Station 2 quadrant_303"; - } - if (detElemId == 301) { - return "SC03O_5/Station 2 quadrant_301"; - } - if (detElemId == 302) { - return "SC03O_5/Station 2 quadrant_302"; - } - if (detElemId == 400) { - return "SC04I_6/Station 2 quadrant_400"; - } - if (detElemId == 403) { - return "SC04I_6/Station 2 quadrant_403"; - } - if (detElemId == 401) { - return "SC04O_7/Station 2 quadrant_401"; - } - if (detElemId == 402) { - return "SC04O_7/Station 2 quadrant_402"; - } - if (detElemId == 500) { - return "SC05I_8/122000SR1_500"; - } - if (detElemId == 501) { - return "SC05I_8/112200SR2_501"; - } - if (detElemId == 502) { - return "SC05I_8/122200S_502"; - } - if (detElemId == 503) { - return "SC05I_8/222000N_503"; - } - if (detElemId == 504) { - return "SC05I_8/220000N_504"; - } - if (detElemId == 514) { - return "SC05I_8/220000N_514"; - } - if (detElemId == 515) { - return "SC05I_8/222000N_515"; - } - if (detElemId == 516) { - return "SC05I_8/122200S_516"; - } - if (detElemId == 517) { - return "SC05I_8/112200SR2_517"; - } - if (detElemId == 505) { - return "SC05O_9/220000N_505"; - } - if (detElemId == 506) { - return "SC05O_9/222000N_506"; - } - if (detElemId == 507) { - return "SC05O_9/122200S_507"; - } - if (detElemId == 508) { - return "SC05O_9/112200SR2_508"; - } - if (detElemId == 509) { - return "SC05O_9/122000SR1_509"; - } - if (detElemId == 510) { - return "SC05O_9/112200SR2_510"; - } - if (detElemId == 511) { - return "SC05O_9/122200S_511"; - } - if (detElemId == 512) { - return "SC05O_9/222000N_512"; - } - if (detElemId == 513) { - return "SC05O_9/220000N_513"; - } - if (detElemId == 600) { - return "SC06I_10/122000NR1_600"; - } - if (detElemId == 601) { - return "SC06I_10/112200NR2_601"; - } - if (detElemId == 602) { - return "SC06I_10/122200N_602"; - } - if (detElemId == 603) { - return "SC06I_10/222000N_603"; - } - if (detElemId == 604) { - return "SC06I_10/220000N_604"; - } - if (detElemId == 614) { - return "SC06I_10/220000N_614"; - } - if (detElemId == 615) { - return "SC06I_10/222000N_615"; - } - if (detElemId == 616) { - return "SC06I_10/122200N_616"; - } - if (detElemId == 617) { - return "SC06I_10/112200NR2_617"; - } - if (detElemId == 605) { - return "SC06O_11/220000N_605"; - } - if (detElemId == 606) { - return "SC06O_11/222000N_606"; - } - if (detElemId == 607) { - return "SC06O_11/122200N_607"; - } - if (detElemId == 608) { - return "SC06O_11/112200NR2_608"; - } - if (detElemId == 609) { - return "SC06O_11/122000NR1_609"; - } - if (detElemId == 610) { - return "SC06O_11/112200NR2_610"; - } - if (detElemId == 611) { - return "SC06O_11/122200N_611"; - } - if (detElemId == 612) { - return "SC06O_11/222000N_612"; - } - if (detElemId == 613) { - return "SC06O_11/220000N_613"; - } - if (detElemId == 700) { - return "SC07I_12/122330N_700"; - } - if (detElemId == 701) { - return "SC07I_12/112233NR3_701"; - } - if (detElemId == 702) { - return "SC07I_12/112230N_702"; - } - if (detElemId == 703) { - return "SC07I_12/222330N_703"; - } - if (detElemId == 704) { - return "SC07I_12/223300N_704"; - } - if (detElemId == 705) { - return "SC07I_12/333000N_705"; - } - if (detElemId == 706) { - return "SC07I_12/330000N_706"; - } - if (detElemId == 720) { - return "SC07I_12/330000N_720"; - } - if (detElemId == 721) { - return "SC07I_12/333000N_721"; - } - if (detElemId == 722) { - return "SC07I_12/223300N_722"; - } - if (detElemId == 723) { - return "SC07I_12/222330N_723"; - } - if (detElemId == 724) { - return "SC07I_12/112230N_724"; - } - if (detElemId == 725) { - return "SC07I_12/112233NR3_725"; - } - if (detElemId == 707) { - return "SC07O_13/330000N_707"; - } - if (detElemId == 708) { - return "SC07O_13/333000N_708"; - } - if (detElemId == 709) { - return "SC07O_13/223300N_709"; - } - if (detElemId == 710) { - return "SC07O_13/222330N_710"; - } - if (detElemId == 711) { - return "SC07O_13/112230N_711"; - } - if (detElemId == 712) { - return "SC07O_13/112233NR3_712"; - } - if (detElemId == 713) { - return "SC07O_13/122330N_713"; - } - if (detElemId == 714) { - return "SC07O_13/112233NR3_714"; - } - if (detElemId == 715) { - return "SC07O_13/112230N_715"; - } - if (detElemId == 716) { - return "SC07O_13/222330N_716"; - } - if (detElemId == 717) { - return "SC07O_13/223300N_717"; - } - if (detElemId == 718) { - return "SC07O_13/333000N_718"; - } - if (detElemId == 719) { - return "SC07O_13/330000N_719"; - } - if (detElemId == 800) { - return "SC08I_14/122330N_800"; - } - if (detElemId == 801) { - return "SC08I_14/112233NR3_801"; - } - if (detElemId == 802) { - return "SC08I_14/112230N_802"; - } - if (detElemId == 803) { - return "SC08I_14/222330N_803"; - } - if (detElemId == 804) { - return "SC08I_14/223300N_804"; - } - if (detElemId == 805) { - return "SC08I_14/333000N_805"; - } - if (detElemId == 806) { - return "SC08I_14/330000N_806"; - } - if (detElemId == 820) { - return "SC08I_14/330000N_820"; - } - if (detElemId == 821) { - return "SC08I_14/333000N_821"; - } - if (detElemId == 822) { - return "SC08I_14/223300N_822"; - } - if (detElemId == 823) { - return "SC08I_14/222330N_823"; - } - if (detElemId == 824) { - return "SC08I_14/112230N_824"; - } - if (detElemId == 825) { - return "SC08I_14/112233NR3_825"; - } - if (detElemId == 807) { - return "SC08O_15/330000N_807"; - } - if (detElemId == 808) { - return "SC08O_15/333000N_808"; - } - if (detElemId == 809) { - return "SC08O_15/223300N_809"; - } - if (detElemId == 810) { - return "SC08O_15/222330N_810"; - } - if (detElemId == 811) { - return "SC08O_15/112230N_811"; - } - if (detElemId == 812) { - return "SC08O_15/112233NR3_812"; - } - if (detElemId == 813) { - return "SC08O_15/122330N_813"; - } - if (detElemId == 814) { - return "SC08O_15/112233NR3_814"; - } - if (detElemId == 815) { - return "SC08O_15/112230N_815"; - } - if (detElemId == 816) { - return "SC08O_15/222330N_816"; - } - if (detElemId == 817) { - return "SC08O_15/223300N_817"; - } - if (detElemId == 818) { - return "SC08O_15/333000N_818"; - } - if (detElemId == 819) { - return "SC08O_15/330000N_819"; - } - if (detElemId == 900) { - return "SC09I_16/122330N_900"; - } - if (detElemId == 901) { - return "SC09I_16/112233NR3_901"; - } - if (detElemId == 902) { - return "SC09I_16/112233N_902"; - } - if (detElemId == 903) { - return "SC09I_16/222333N_903"; - } - if (detElemId == 904) { - return "SC09I_16/223330N_904"; - } - if (detElemId == 905) { - return "SC09I_16/333300N_905"; - } - if (detElemId == 906) { - return "SC09I_16/333000N_906"; - } - if (detElemId == 920) { - return "SC09I_16/333000N_920"; - } - if (detElemId == 921) { - return "SC09I_16/333300N_921"; - } - if (detElemId == 922) { - return "SC09I_16/223330N_922"; - } - if (detElemId == 923) { - return "SC09I_16/222333N_923"; - } - if (detElemId == 924) { - return "SC09I_16/112233N_924"; - } - if (detElemId == 925) { - return "SC09I_16/112233NR3_925"; - } - if (detElemId == 907) { - return "SC09O_17/333000N_907"; - } - if (detElemId == 908) { - return "SC09O_17/333300N_908"; - } - if (detElemId == 909) { - return "SC09O_17/223330N_909"; - } - if (detElemId == 910) { - return "SC09O_17/222333N_910"; - } - if (detElemId == 911) { - return "SC09O_17/112233N_911"; - } - if (detElemId == 912) { - return "SC09O_17/112233NR3_912"; - } - if (detElemId == 913) { - return "SC09O_17/122330N_913"; - } - if (detElemId == 914) { - return "SC09O_17/112233NR3_914"; - } - if (detElemId == 915) { - return "SC09O_17/112233N_915"; - } - if (detElemId == 916) { - return "SC09O_17/222333N_916"; - } - if (detElemId == 917) { - return "SC09O_17/223330N_917"; - } - if (detElemId == 918) { - return "SC09O_17/333300N_918"; - } - if (detElemId == 919) { - return "SC09O_17/333000N_919"; - } - if (detElemId == 1000) { - return "SC10I_18/122330N_1000"; - } - if (detElemId == 1001) { - return "SC10I_18/112233NR3_1001"; - } - if (detElemId == 1002) { - return "SC10I_18/112233N_1002"; - } - if (detElemId == 1003) { - return "SC10I_18/222333N_1003"; - } - if (detElemId == 1004) { - return "SC10I_18/223330N_1004"; - } - if (detElemId == 1005) { - return "SC10I_18/333300N_1005"; - } - if (detElemId == 1006) { - return "SC10I_18/333000N_1006"; - } - if (detElemId == 1020) { - return "SC10I_18/333000N_1020"; - } - if (detElemId == 1021) { - return "SC10I_18/333300N_1021"; - } - if (detElemId == 1022) { - return "SC10I_18/223330N_1022"; - } - if (detElemId == 1023) { - return "SC10I_18/222333N_1023"; - } - if (detElemId == 1024) { - return "SC10I_18/112233N_1024"; - } - if (detElemId == 1025) { - return "SC10I_18/112233NR3_1025"; - } - if (detElemId == 1007) { - return "SC10O_19/333000N_1007"; - } - if (detElemId == 1008) { - return "SC10O_19/333300N_1008"; - } - if (detElemId == 1009) { - return "SC10O_19/223330N_1009"; - } - if (detElemId == 1010) { - return "SC10O_19/222333N_1010"; - } - if (detElemId == 1011) { - return "SC10O_19/112233N_1011"; - } - if (detElemId == 1012) { - return "SC10O_19/112233NR3_1012"; - } - if (detElemId == 1013) { - return "SC10O_19/122330N_1013"; - } - if (detElemId == 1014) { - return "SC10O_19/112233NR3_1014"; - } - if (detElemId == 1015) { - return "SC10O_19/112233N_1015"; - } - if (detElemId == 1016) { - return "SC10O_19/222333N_1016"; - } - if (detElemId == 1017) { - return "SC10O_19/223330N_1017"; - } - if (detElemId == 1018) { - return "SC10O_19/333300N_1018"; - } - if (detElemId == 1019) { - return "SC10O_19/333000N_1019"; - } - - return vp; -} - -void addAlignableVolumesHalfChamber(int hc, std::string& parent) -{ - // - // Add alignable volumes for a half chamber and its daughters - // - std::vector<std::vector<int>> DEofHC{{100, 103}, - {101, 102}, - {200, 203}, - {201, 202}, - {300, 303}, - {301, 302}, - {400, 403}, - {401, 402}, - {500, 501, 502, 503, 504, 514, 515, 516, 517}, - {505, 506, 507, 508, 509, 510, 511, 512, 513}, - {600, 601, 602, 603, 604, 614, 615, 616, 617}, - {605, 606, 607, 608, 609, 610, 611, 612, 613}, - {700, 701, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725}, - {707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719}, - {800, 801, 802, 803, 804, 805, 806, 820, 821, 822, 823, 824, 825}, - {807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819}, - {900, 901, 902, 903, 904, 905, 906, 920, 921, 922, 923, 924, 925}, - {907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919}, - {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1020, 1021, 1022, 1023, 1024, 1025}, - {1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019}}; - - for (int i = 0; i < DEofHC[hc].size(); i++) { - std::string volPathName = impl::getVolumePathName(DEofHC[hc][i]); - - TString path = Form("%s%s", parent.c_str(), volPathName.c_str()); - TString sname = Form("MCH/HC%d/DE%d", hc, DEofHC[hc][i]); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - } - - return; -} - -} // namespace impl - -o2::math_utils::Transform3D getTransformation(int detElemId, const TGeoManager& geo) -{ - - int nCh = detElemId / 100; - - if (nCh < 1 || nCh > 10) { - throw std::runtime_error("Wrong detection element Id"); - } - - std::string volPathName = geo.GetTopVolume()->GetName(); - - if (nCh <= 4 && geo.GetVolume("YOUT1")) { - volPathName += "/YOUT1_1/"; - } else if ((nCh == 5 || nCh == 6) && geo.GetVolume("DDIP")) { - volPathName += "/DDIP_1/"; - } else if (nCh >= 7 && geo.GetVolume("YOUT2")) { - volPathName += "/YOUT2_1/"; - } else { - volPathName += "/"; - } - - volPathName += impl::getVolumePathName(detElemId); - - TGeoNavigator* navig = gGeoManager->GetCurrentNavigator(); - - if (!navig->cd(volPathName.c_str())) { - throw std::runtime_error("could not get to volPathName=" + volPathName); - } - - return o2::math_utils::Transform3D{*(navig->GetCurrentMatrix())}; -} - -void addAlignableVolumesMCH() -{ - // - // Creates entries for alignable volumes associating the symbolic volume - // name with the corresponding volume path. - // - - LOG(INFO) << "Add MCH alignable volumes"; - - for (int hc = 0; hc < 20; hc++) { - int nCh = hc / 2 + 1; - - if (nCh < 1 || nCh > 10) { - throw std::runtime_error("Wrong detection element Id"); - } - - std::string volPathName = gGeoManager->GetTopVolume()->GetName(); - - if (nCh <= 4 && gGeoManager->GetVolume("YOUT1")) { - volPathName += "/YOUT1_1/"; - } else if ((nCh == 5 || nCh == 6) && gGeoManager->GetVolume("DDIP")) { - volPathName += "/DDIP_1/"; - } else if (nCh >= 7 && gGeoManager->GetVolume("YOUT2")) { - volPathName += "/YOUT2_1/"; - } else { - volPathName += "/"; - } - - std::string path = fmt::format("{0}SC{1}{2}{3}_{4}", volPathName.c_str(), nCh < 10 ? "0" : "", nCh, hc % 2 ? "O" : "I", hc); - std::string sname = fmt::format("MCH/HC{}", hc); - - LOG(DEBUG) << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.c_str(), path.c_str())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - - Int_t lastUID = 0; - - impl::addAlignableVolumesHalfChamber(hc, volPathName); - } - - return; -} - -} // namespace mch -} // namespace o2 diff --git a/Detectors/MUON/MCH/Simulation/src/GeometryTest.cxx b/Detectors/MUON/MCH/Simulation/src/GeometryTest.cxx deleted file mode 100644 index 42aa7dc8302b0..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/GeometryTest.cxx +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "MCHSimulation/GeometryTest.h" - -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/MaterialManager.h" -#include "MCHSimulation/Geometry.h" -#include "Math/GenVector/Cartesian3D.h" -#include "TGeoManager.h" -#include "TGeoVolume.h" -#include "TH2F.h" -#include <iostream> -#include "TPRegexp.h" -#include "TGLViewer.h" -#include "TGLRnrCtx.h" -#include "TVirtualPad.h" -#include "DetectorsPassive/Cave.h" -#include "DetectorsPassive/Dipole.h" -#include "DetectorsPassive/Absorber.h" -#include "DetectorsPassive/Compensator.h" -#include "DetectorsPassive/Shil.h" -#include "DetectorsPassive/Pipe.h" -#include "MCHSimulation/Detector.h" - -namespace o2 -{ -namespace mch -{ -namespace test -{ - -TGeoVolume* createAirVacuumCave(const char* name) -{ - // create the air medium (only used for the geometry test) - auto& mgr = o2::base::MaterialManager::Instance(); - - const int nAir = 4; - Float_t aAir[nAir] = {12.0107, 14.0067, 15.9994, 39.948}; - Float_t zAir[nAir] = {6., 7., 8., 18.}; - Float_t wAir[nAir] = {0.000124, 0.755267, 0.231781, 0.012827}; - Float_t dAirVacuum = 1.20479E-10; - const int kID = 90; // to avoid conflicts with definitions of other MCH materials - - mgr.Mixture("MCH", kID, "Air", aAir, zAir, dAirVacuum, nAir, wAir); - mgr.Medium("MCH", kID, "Air", kID, - false, /* isvol */ - 0, /* ifield */ - -1.0, /* fieldm */ - -1.0, /* tmaxfd */ - -1.0, /* stemax */ - -1.0, /* deemax */ - -1.0, /* epsil */ - -1.0 /* stmin */); - return gGeoManager->MakeBox(name, gGeoManager->GetMedium("MCH_Air"), 2000.0, 2000.0, 3000.0); -} - -void dump(std::ostream& out, const TGeoNode& n, int level, int maxdepth, std::string prefix) -{ - if (level >= maxdepth) { - return; - } - - if (level == 0) { - out << n.GetName() << "\n"; - } - - if (level < maxdepth) { - for (int i = 0; i < n.GetNdaughters(); i++) { - TGeoNode* d = n.GetDaughter(i); - if (i == n.GetNdaughters() - 1) { - out << prefix + "└──" << d->GetName() - << "\n"; - dump(out, *d, level + 1, maxdepth, prefix + " "); - } else { - out << prefix + "├──" << d->GetName() - << "\n"; - dump(out, *d, level + 1, maxdepth, prefix + "│ "); - } - } - } -} - -void showGeometryAsTextTree(const char* fromPath, int maxdepth, std::ostream& out) -{ - if (!gGeoManager) { - return; - } - - TGeoNavigator* nav = gGeoManager->GetCurrentNavigator(); - - if (strlen(fromPath)) { - if (!nav->cd(fromPath)) { - std::cerr << "Could not get path " << fromPath << "\n"; - return; - } - } - - TGeoNode* node = nav->GetCurrentNode(); - - dump(out, *node, 0, maxdepth, ""); -} - -void createStandaloneGeometry() -{ - if (gGeoManager && gGeoManager->GetTopVolume()) { - std::cerr << "Can only call this function with an empty geometry, i.e. gGeoManager==nullptr " - << " or gGeoManager->GetTopVolume()==nullptr\n"; - } - TGeoManager* g = new TGeoManager("MCH-ONLY", "ALICE MCH Standalone Geometry"); - TGeoVolume* top = createAirVacuumCave("cave"); - g->SetTopVolume(top); - o2::mch::createGeometry(*top); -} - -void createRegularGeometry() -{ - if (gGeoManager && gGeoManager->GetTopVolume()) { - std::cerr << "Can only call this function with an empty geometry, i.e. gGeoManager==nullptr " - << " or gGeoManager->GetTopVolume()==nullptr\n"; - } - TGeoManager* g = new TGeoManager("MCH-BASICS", "ALICE MCH Regular Geometry"); - o2::passive::Cave("CAVE", "Cave (for MCH Basics)").ConstructGeometry(); - o2::passive::Dipole("DIPO", "Alice Dipole (for MCH Basics)").ConstructGeometry(); - o2::passive::Compensator("COMP", "Alice Compensator Dipole (for MCH Basics)").ConstructGeometry(); - o2::passive::Pipe("PIPE", "Beam pipe (for MCH Basics)").ConstructGeometry(); - o2::passive::Shil("SHIL", "Small angle beam shield (for MCH Basics)").ConstructGeometry(); - o2::passive::Absorber("ABSO", "Absorber (for MCH Basics)").ConstructGeometry(); - o2::mch::Detector(true).ConstructGeometry(); -} - -void addAlignableVolumes() -{ - if (!gGeoManager) { - std::cerr << "gGeoManager == nullptr, must create a geometry first\n"; - return; - } - // If not closed, we need to close it - if (!gGeoManager->IsClosed()) { - gGeoManager->CloseGeometry(); - } - // Then add the alignable volumes - o2::mch::Detector(true).addAlignableVolumes(); -} - -void setVolumeVisibility(const char* pattern, bool visible, bool visibleDaughters) -{ - TPRegexp re(pattern); - TIter next(gGeoManager->GetListOfVolumes()); - TGeoVolume* vol; - - while ((vol = static_cast<TGeoVolume*>(next()))) { - if (TString(vol->GetName()).Contains(re)) { - vol->SetVisibility(visible); - vol->SetVisDaughters(visibleDaughters); - } - } -} - -void setVolumeColor(const char* pattern, int lineColor, int fillColor) -{ - TPRegexp re(pattern); - TIter next(gGeoManager->GetListOfVolumes()); - TGeoVolume* vol; - - while ((vol = static_cast<TGeoVolume*>(next()))) { - if (TString(vol->GetName()).Contains(re)) { - vol->SetFillColor(fillColor); - vol->SetLineColor(lineColor); - } - } -} - -void drawOptionPresetBasic() -{ - gGeoManager->SetVisLevel(4); - - setVolumeVisibility("cave", false, true); - - // Hide to half-chamber top volumes - setVolumeVisibility("^SC", false, true); - - // Hide St345 support panels - setVolumeVisibility("support panel", false, false); - - // Hide St345 LV wires - setVolumeVisibility(" LV ", false, false); - - // Make St345 carbon panels dark gray - setVolumeColor("panel carbon", kGray + 3); - - // Make St345 insulators dark green - setVolumeColor("insulator", kGreen + 3); - - // Hide most of St1 - setVolumeVisibility("SQ", false, true); - - // Only reveal gas module - setVolumeVisibility("SA", true, true); - setVolumeColor("SA", kCyan - 10); -} - -void drawGeometry() -{ - // minimal macro to test setup of the geometry - - createStandaloneGeometry(); - - drawOptionPresetBasic(); - - gGeoManager->GetTopVolume()->Draw("ogl"); - - TGLViewer* gl = static_cast<TGLViewer*>(gPad->GetViewer3D("ogl")); - TGLCamera& c = gl->CurrentCamera(); - - // gl->SetStyle(TGLRnrCtx::kWireFrame); - gl->SetStyle(TGLRnrCtx::kOutline); - // gl->SetStyle(TGLRnrCtx::kFill); -} - -o2::base::GeometryManager::MatBudgetExt getMatBudgetExt(const o2::math_utils::Transform3D& t, math_utils::Vector3D<double>& n, float x, float y, float thickness) -{ - math_utils::Point3D<double> point; - t.LocalToMaster(math_utils::Point3D<double>{x, y, 0}, point); - return o2::base::GeometryManager::meanMaterialBudgetExt(math_utils::Point3D<double>{point + n * thickness / 2.0}, math_utils::Point3D<double>{point - n * thickness / 2.0}); -} - -std::ostream& operator<<(std::ostream& os, o2::base::GeometryManager::MatBudgetExt m) -{ - os << "L=" << m.length << " <Rho>=" << m.meanRho << " <A>=" << m.meanA - << " <Z>=" << m.meanZ << " <x/x0>=" << m.meanX2X0 << " nCross=" << m.nCross; - return os; -} - -math_utils::Vector3D<double> getNormalVector(const o2::math_utils::Transform3D& t) -{ - math_utils::Point3D<double> px, py, po; - t.LocalToMaster(math_utils::Point3D<double>{0, 1, 0}, py); - t.LocalToMaster(math_utils::Point3D<double>{1, 0, 0}, px); - t.LocalToMaster(math_utils::Point3D<double>{0, 0, 0}, po); - math_utils::Vector3D<double> a{px - po}; - math_utils::Vector3D<double> b{py - po}; - return a.Cross(b).Unit(); -} - -TH2* getRadio(int detElemId, float xmin, float ymin, float xmax, float ymax, float xstep, float ystep, float thickness) -{ - if (xmin >= xmax || ymin >= ymax) { - std::cerr << "incorrect limits\n"; - return nullptr; - } - TH2* hmatb = new TH2F("hmatb", "hmatb", (int)((xmax - xmin) / xstep), xmin, xmax, (int)((ymax - ymin) / ystep), ymin, ymax); - - auto t = o2::mch::getTransformation(detElemId, *gGeoManager); - - auto normal = getNormalVector(t); - - for (auto x = xmin; x < xmax; x += xstep) { - for (auto y = ymin; y < ymax; y += ystep) { - auto matb = getMatBudgetExt(t, normal, x, y, thickness); - if (std::isfinite(matb.meanX2X0)) { - hmatb->Fill(x, y, matb.meanX2X0); - } - } - } - return hmatb; -} -} // namespace test -} // namespace mch -} // namespace o2 diff --git a/Detectors/MUON/MCH/Simulation/src/Hit.cxx b/Detectors/MUON/MCH/Simulation/src/Hit.cxx index bbb80641fc424..820cac53b54e8 100644 --- a/Detectors/MUON/MCH/Simulation/src/Hit.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Simulation/src/MCHSimulationLinkDef.h b/Detectors/MUON/MCH/Simulation/src/MCHSimulationLinkDef.h index 723051d17c642..af02450b9a19f 100644 --- a/Detectors/MUON/MCH/Simulation/src/MCHSimulationLinkDef.h +++ b/Detectors/MUON/MCH/Simulation/src/MCHSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,25 +17,12 @@ #pragma link C++ namespace o2; #pragma link C++ namespace o2::mch; -#pragma link C++ namespace o2::mch::test; -#pragma link C++ class o2::mch::test::Dummy; #pragma link C++ class o2::mch::Detector + ; #pragma link C++ class o2::mch::Hit + ; #pragma link C++ class std::vector < o2::mch::Hit> + ; #pragma link C++ class o2::base::DetImpl < o2::mch::Detector> + ; - -#pragma link C++ function o2::mch::addAlignableVolumesMCH; -#pragma link C++ function o2::mch::createGeometry; -#pragma link C++ function o2::mch::getSensitiveVolumes; - -#pragma link C++ function o2::mch::test::addAlignableVolumes; -#pragma link C++ function o2::mch::test::createStandaloneGeometry; -#pragma link C++ function o2::mch::test::createRegularGeometry; -#pragma link C++ function o2::mch::test::drawGeometry; -#pragma link C++ function o2::mch::test::getRadio; -#pragma link C++ function o2::mch::test::showGeometryAsTextTree; -#pragma link C++ function o2::mch::test::setVolumeVisibility; -#pragma link C++ function o2::mch::test::setVolumeColor; +#pragma link C++ class o2::mch::DigitizerParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mch::DigitizerParam> + ; #endif diff --git a/Detectors/MUON/MCH/Simulation/src/Materials.h b/Detectors/MUON/MCH/Simulation/src/Materials.h deleted file mode 100644 index acb3480688326..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/Materials.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Materials.h -/// \brief Implementation of the MCH materials definitions -/// \author Florian Damas <florian.damas@cern.ch> -/// \date 22 march 2018 - -#ifndef O2_MCH_SIMULATION_MATERIALS_H -#define O2_MCH_SIMULATION_MATERIALS_H - -#include <TGeoMedium.h> - -namespace o2 -{ - -namespace mch -{ - -enum Medium { - Gas, - Carbon, - HoneyNomex, - BulkNomex, - Noryl, - Copper, - FR4, - Rohacell, - Glue, - Plastic, - Epoxy, - Inox, - St1Rohacell, - Aluminium -}; - -// Return a pointer to the mch medium number imed. -// Throws an exception if imed is not within Medium enum -// and / or medium has not been defined yet. -TGeoMedium* assertMedium(int imed); - -void createMaterials(); - -} // namespace mch -} // namespace o2 - -#endif // O2_MCH_SIMULATION_MATERIALS_H diff --git a/Detectors/MUON/MCH/Simulation/src/Response.cxx b/Detectors/MUON/MCH/Simulation/src/Response.cxx index 4bb0c73703ab5..4307d53ceb9d9 100644 --- a/Detectors/MUON/MCH/Simulation/src/Response.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Response.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -105,7 +106,7 @@ double Response::chargefrac1d(float min, float max, double k2, double sqrtk3, do return 2. * k4 * (TMath::ATan(u2) - TMath::ATan(u1)); } //______________________________________________________________________ -unsigned long Response::response(unsigned long adc) +uint32_t Response::response(uint32_t adc) { //DecalibrateTrackerDigit functionality from //AliMuonDigitizerV3 in aliroot diff --git a/Detectors/MUON/MCH/Simulation/src/Station1Geometry.h b/Detectors/MUON/MCH/Simulation/src/Station1Geometry.h deleted file mode 100644 index 5137e1bf93a93..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/Station1Geometry.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Station1Geometry.h -/// \brief Implementation of the station 1 geometry -/// \author Florian Damas <florian.damas@cern.ch> -/// \date 16 mai 2018 - -#ifndef O2_MCH_SIMULATION_STATION1GEOMETRY_H -#define O2_MCH_SIMULATION_STATION1GEOMETRY_H - -#include <vector> - -class TGeoVolume; - -namespace o2 -{ -namespace mch -{ - -void createStation1Geometry(TGeoVolume& topVolume); - -std::vector<TGeoVolume*> getStation1SensitiveVolumes(); - -} // namespace mch -} // namespace o2 -#endif // O2_MCH_SIMULATION_STATION1GEOMETRY_H diff --git a/Detectors/MUON/MCH/Simulation/src/Station2Geometry.h b/Detectors/MUON/MCH/Simulation/src/Station2Geometry.h deleted file mode 100644 index ad87a22be83f9..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/Station2Geometry.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Station2Geometry.h -/// \brief Implementation of the station 2 geometry -/// \author Florian Damas <florian.damas@cern.ch> -/// \date 23 mai 2018 - -#ifndef O2_MCH_SIMULATION_STATION2GEOMETRY_H -#define O2_MCH_SIMULATION_STATION2GEOMETRY_H - -#include <vector> - -class TGeoVolume; - -namespace o2 -{ -namespace mch -{ - -void createStation2Geometry(TGeoVolume& topVolume); - -std::vector<TGeoVolume*> getStation2SensitiveVolumes(); - -} // namespace mch -} // namespace o2 -#endif // O2_MCH_SIMULATION_STATION2GEOMETRY_H diff --git a/Detectors/MUON/MCH/Simulation/src/Station345Geometry.h b/Detectors/MUON/MCH/Simulation/src/Station345Geometry.h deleted file mode 100644 index f538dd240d4ce..0000000000000 --- a/Detectors/MUON/MCH/Simulation/src/Station345Geometry.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Station345Geometry.h -/// \brief Implementation of the slat-stations geometry -/// \author Florian Damas <florian.damas@cern.ch> -/// \date 22 march 2018 - -#ifndef O2_MCH_SIMULATION_STATION345GEOMETRY_H -#define O2_MCH_SIMULATION_STATION345GEOMETRY_H - -#include <vector> - -class TGeoVolume; - -namespace o2 -{ -namespace mch -{ - -void createStation345Geometry(TGeoVolume& topVolume); - -std::vector<TGeoVolume*> getStation345SensitiveVolumes(); - -} // namespace mch -} // namespace o2 -#endif diff --git a/Detectors/MUON/MCH/Simulation/src/Stepper.cxx b/Detectors/MUON/MCH/Simulation/src/Stepper.cxx index 67c50340f2ac9..f7bbbe84c6207 100644 --- a/Detectors/MUON/MCH/Simulation/src/Stepper.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Stepper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "Stepper.h" +#include "DetectorsCommonDataFormats/DetID.h" #include "SimulationDataFormat/Stack.h" #include "SimulationDataFormat/TrackReference.h" #include "TGeoManager.h" @@ -49,7 +51,8 @@ void Stepper::process(const TVirtualMC& vmc) if (t.isEntering() || t.isExiting()) { // generate a track referenced - o2::TrackReference tr{vmc, detElemId}; + o2::TrackReference tr{vmc, o2::detectors::DetID::MCH}; + tr.setUserId(detElemId); stack->addTrackReference(tr); } diff --git a/Detectors/MUON/MCH/Simulation/src/Stepper.h b/Detectors/MUON/MCH/Simulation/src/Stepper.h index 02837f32be475..26298ca8fa4de 100644 --- a/Detectors/MUON/MCH/Simulation/src/Stepper.h +++ b/Detectors/MUON/MCH/Simulation/src/Stepper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Simulation/src/inspect-collision-context.cxx b/Detectors/MUON/MCH/Simulation/src/inspect-collision-context.cxx new file mode 100644 index 0000000000000..49fa1f16dd89d --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/src/inspect-collision-context.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/program_options.hpp> +#include <string> +#include <iostream> +#include "Framework/Logger.h" +#include <TFile.h> +#include "SimulationDataFormat/DigitizationContext.h" +#include <gsl/span> +#include "CommonDataFormat/InteractionRecord.h" +#include <limits> + +namespace po = boost::program_options; + +void report(gsl::span<o2::InteractionTimeRecord> irs, int threshold, bool verbose) +{ + o2::InteractionTimeRecord ir0(std::numeric_limits<double>::max()); + int tooClose{0}; + for (auto ir : irs) { + if (verbose) { + std::cout << ir; + } + auto d = ir.differenceInBC(ir0); + if (d >= 0 && d < threshold) { + if (verbose) { + std::cout << " **** BC distance to previous " << d; + } + ++tooClose; + } + if (verbose) { + std::cout << "\n"; + } + ir0 = ir; + } + if (verbose) { + std::cout << "Number of IR(s) strictly below the " << threshold << " BC distance limit : " + << tooClose << "\n"; + } else { + std::cout << tooClose << "\n"; + } +} + +int main(int argc, char* argv[]) +{ + po::options_description generic("options"); + po::variables_map vm; + + // clang-format off + generic.add_options() + ("help,h", "produce help message") + ("input-file,i",po::value<std::string>()->default_value("collisioncontext.root"),"input file name") + ("min-distance,d",po::value<int>()->default_value(4), "min distance between IRs to consider as a problem") + ("verbose,v",po::value<bool>()->default_value(false),"verbose output"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << generic << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + po::notify(vm); + + // first things first : check the input path actually exists + std::string input = vm["input-file"].as<std::string>(); + + TFile fin(input.c_str()); + if (!fin.IsOpen()) { + LOGP(fatal, "could not open input file {}", input); + return -1; + } + auto context = fin.Get<o2::steer::DigitizationContext>("DigitizationContext"); + if (!context) { + std::cout << "Could not get context\n"; + return 1; + } + report(context->getEventRecords(), vm["min-distance"].as<int>(), vm["verbose"].as<bool>()); + return 0; +} diff --git a/Detectors/MUON/MCH/Simulation/test/CMakeLists.txt b/Detectors/MUON/MCH/Simulation/test/CMakeLists.txt index 9e0508c8e0d5b..68770197e253e 100644 --- a/Detectors/MUON/MCH/Simulation/test/CMakeLists.txt +++ b/Detectors/MUON/MCH/Simulation/test/CMakeLists.txt @@ -1,35 +1,41 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_test(geometry-standalone - NAME o2-test-mch-geometry-standalone +o2_add_test(digit-merging COMPONENT_NAME mch - SOURCES testGeometry.cxx - PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase - COMMAND_LINE_ARGS standalone + SOURCES testDigitMerging.cxx DigitMerging.cxx + PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase O2::DetectorsPassive LABELS muon mch sim) -o2_add_test(geometry-regular - NAME o2-test-mch-geometry-regular +o2_add_test(digitizer COMPONENT_NAME mch - SOURCES testGeometry.cxx - PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase - COMMAND_LINE_ARGS regular - LABELS muon mch sim) + SOURCES testDigitizer.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsPassive + O2::MCHBase + O2::MCHGeometryTest + O2::MCHSimulation + LABELS muon mch long sim) + +# o2_add_test(response +# COMPONENT_NAME mch +# SOURCES testResponse.cxx +# PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase O2::DetectorsPassive +# LABELS muon mch sim) -o2_add_test(simulation +o2_add_test(regular-geometry COMPONENT_NAME mch - SOURCES testDigitMerging.cxx DigitMerging.cxx - testDigitization.cxx testResponse.cxx - PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase - LABELS muon mch long sim) + SOURCES + testRegularGeometry.cxx + PUBLIC_LINK_LIBRARIES O2::MCHSimulation O2::MCHBase O2::DetectorsPassive + LABELS muon mch sim) if(benchmark_FOUND) o2_add_executable( diff --git a/Detectors/MUON/MCH/Simulation/test/DigitMerging.cxx b/Detectors/MUON/MCH/Simulation/test/DigitMerging.cxx index 3fef1b9193a86..d0d5730dd3a45 100644 --- a/Detectors/MUON/MCH/Simulation/test/DigitMerging.cxx +++ b/Detectors/MUON/MCH/Simulation/test/DigitMerging.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Simulation/test/DigitMerging.h b/Detectors/MUON/MCH/Simulation/test/DigitMerging.h index 1809135c659bc..ac24148b04acc 100644 --- a/Detectors/MUON/MCH/Simulation/test/DigitMerging.h +++ b/Detectors/MUON/MCH/Simulation/test/DigitMerging.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #define O2_MCH_SIMULATION_TEST_DIGITMERGING_H #include <vector> -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" #include "SimulationDataFormat/MCCompLabel.h" std::vector<o2::mch::Digit> mergeDigitsMW(const std::vector<o2::mch::Digit>& inputDigits, const std::vector<o2::MCCompLabel>& labels); diff --git a/Detectors/MUON/MCH/Simulation/test/benchDigitMerging.cxx b/Detectors/MUON/MCH/Simulation/test/benchDigitMerging.cxx index 9e5af94359fb6..0cf9a0d442bd6 100644 --- a/Detectors/MUON/MCH/Simulation/test/benchDigitMerging.cxx +++ b/Detectors/MUON/MCH/Simulation/test/benchDigitMerging.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "benchmark/benchmark.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" #include "DigitMerging.h" #include <ctime> #include <cstdlib> @@ -23,12 +24,11 @@ std::vector<Digit> createDigits(int N) std::vector<Digit> digits; float dummyadc{42.0}; std::srand(std::time(nullptr)); // use current time as seed for random generator - Digit::Time dummytime; int dummydetID = 100; //to be improved, timing depending on that for (auto i = 0; i < N; i++) { int randomPadID = std::rand() * N; - digits.emplace_back(dummydetID, randomPadID, dummyadc, dummytime); + digits.emplace_back(dummydetID, randomPadID, dummyadc, 0); } return digits; diff --git a/Detectors/MUON/MCH/Simulation/test/testDigitMerging.cxx b/Detectors/MUON/MCH/Simulation/test/testDigitMerging.cxx index 9fde668423ca0..2afe53ac38b1c 100644 --- a/Detectors/MUON/MCH/Simulation/test/testDigitMerging.cxx +++ b/Detectors/MUON/MCH/Simulation/test/testDigitMerging.cxx @@ -1,20 +1,20 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#define BOOST_TEST_MODULE Test MCHSimulation Digitization +#define BOOST_TEST_MODULE Test MCHSimulation DigitMerging #define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MAIN #include <boost/test/unit_test.hpp> -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" #include "SimulationDataFormat/MCCompLabel.h" #include "DigitMerging.h" #include "boost/format.hpp" @@ -25,15 +25,13 @@ using o2::mch::Digit; -BOOST_AUTO_TEST_SUITE(o2_mch_simulation) - std::vector<Digit> createNonOverlappingDigits() { return std::vector<Digit>{ - {100, 2, 5, Digit::Time{}}, - {100, 3, 6, Digit::Time{}}, - {100, 1, 2, Digit::Time{}}, - {100, 0, 1, Digit::Time{}}}; + {100, 2, 5, 0}, + {100, 3, 6, 0}, + {100, 1, 2, 0}, + {100, 0, 1, 0}}; } std::vector<o2::MCCompLabel> createLabelsNonOverlappingDigits() @@ -48,14 +46,14 @@ std::vector<o2::MCCompLabel> createLabelsNonOverlappingDigits() std::vector<Digit> createOverlappingDigits() { return std::vector<Digit>{ - {100, 2, 5, Digit::Time{}}, - {100, 3, 6, Digit::Time{}}, - {100, 1, 2, Digit::Time{}}, - {100, 0, 0, Digit::Time{}}, - {100, 0, 1, Digit::Time{}}, - {100, 1, 3, Digit::Time{}}, - {100, 3, 7, Digit::Time{}}, - {100, 1, 4, Digit::Time{}}}; + {100, 2, 5, 0}, + {100, 3, 6, 0}, + {100, 1, 2, 0}, + {100, 0, 0, 0}, + {100, 0, 1, 0}, + {100, 1, 3, 0}, + {100, 3, 7, 0}, + {100, 1, 4, 0}}; } std::vector<o2::MCCompLabel> createLabelsOverlappingDigits() @@ -75,10 +73,10 @@ std::vector<o2::MCCompLabel> createLabelsOverlappingDigits() std::vector<Digit> expected() { return std::vector<Digit>{ - {100, 0, 1, Digit::Time{}}, - {100, 1, 9, Digit::Time{}}, - {100, 2, 5, Digit::Time{}}, - {100, 3, 13, Digit::Time{}}}; + {100, 0, 1, 0}, + {100, 1, 9, 0}, + {100, 2, 5, 0}, + {100, 3, 13, 0}}; } std::vector<o2::MCCompLabel> labelexpected() @@ -102,5 +100,3 @@ BOOST_DATA_TEST_CASE(DigitMerging, boost::unit_test::data::make(mergingFunctions auto m = mergingFunction(createOverlappingDigits(), createLabelsOverlappingDigits()); BOOST_CHECK(std::is_permutation(m.begin(), m.end(), expected().begin())); } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Simulation/test/testDigitization.cxx b/Detectors/MUON/MCH/Simulation/test/testDigitization.cxx deleted file mode 100644 index 5bde3ab89b307..0000000000000 --- a/Detectors/MUON/MCH/Simulation/test/testDigitization.cxx +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// \file testDigitisation.cxx -/// \brief This task tests the Digitizer and the Response of the MCH digitization -/// \author Michael Winn, DPhN/IRFU/CEA, michael.winn@cern.ch - -#define BOOST_TEST_DYN_LINK - -#include <boost/test/unit_test.hpp> - -#include "TGeoManager.h" -#include "MCHBase/Digit.h" -#include "MCHSimulation/Digitizer.h" -#include "MCHSimulation/Hit.h" -#include "MCHSimulation/Geometry.h" -#include "MCHSimulation/GeometryTest.h" -#include "MCHMappingInterface/Segmentation.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "TGeoManager.h" -#include "boost/format.hpp" -#include <boost/test/data/test_case.hpp> - -struct GEOMETRY { - GEOMETRY() - { - if (!gGeoManager) { - o2::mch::test::createStandaloneGeometry(); - } - } -}; - -namespace -{ -o2::math_utils::Point3D<float> entrancePoint1(-17.7993, 8.929883, -522.201); //x,y,z coordinates in cm -o2::math_utils::Point3D<float> exitPoint1(-17.8136, 8.93606, -522.62); -o2::math_utils::Point3D<float> entrancePoint2(-49.2793, 28.8673, -1441.25); -o2::math_utils::Point3D<float> exitPoint2(-49.2965, 28.8806, -1441.75); -} // namespace - -/// \brief Test of the Digitization -/// A couple of values are filled into Hits and we check whether we get reproducible output in terms of digits -/// and MClabels - -BOOST_AUTO_TEST_SUITE(o2_mch_simulation) - -BOOST_FIXTURE_TEST_SUITE(digitization, GEOMETRY) - -BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) -BOOST_AUTO_TEST_CASE(DigitizerTest) -{ - - o2::mch::Digitizer digitizer; - int trackId1 = 0; - int trackId2 = 1; - short detElemId1 = 101; - short detElemId2 = 1012; - - float eloss1 = 1e-6; - float eloss2 = 1e-6; - float length = 0.f; - float tof = 0.0; - - std::vector<o2::mch::Hit> hits(2); - hits.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss1, length, tof); - hits.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss2, length, tof); - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mctruthcontainer; - std::vector<o2::mch::Digit> digits; - o2::mch::mapping::Segmentation seg1{detElemId1}; - o2::mch::mapping::Segmentation seg2{detElemId2}; - digitizer.process(hits, digits, mctruthcontainer); - - int digitcounter1 = 0; - int digitcounter2 = 0; - int count = 0; - - for (auto& digit : digits) { - - int padid = digit.getPadID(); - auto label = (mctruthcontainer.getLabels(count))[0]; - int trackID = label.getTrackID(); - ++count; - - if (trackID == trackId1) { - bool check = seg1.isValid(digit.getPadID()); - if (!check) { - BOOST_FAIL(" digit-pad not belonging to hit det-element-ID "); - } - double padposX = seg1.padPositionX(padid); - double padsizeX = seg1.padSizeX(padid); - double padposY = seg1.padPositionY(padid); - double padsizeY = seg1.padSizeY(padid); - auto t = o2::mch::getTransformation(detElemId1, *gGeoManager); - - o2::math_utils::Point3D<float> pos(hits.at(0).GetX(), hits.at(0).GetY(), hits.at(0).GetZ()); - o2::math_utils::Point3D<float> lpos; - t.MasterToLocal(pos, lpos); - - BOOST_CHECK_CLOSE(lpos.x(), padposX, padsizeX * 4.0); - BOOST_CHECK_CLOSE(lpos.y(), padposY, padsizeY * 10.0); - //non uniform pad sizes? - digitcounter1++; - } else if (trackID == trackId2) { - bool check = seg2.isValid(digit.getPadID()); - if (!check) { - BOOST_FAIL(" digit-pad not belonging to hit det-element-ID "); - } - double padposX = seg2.padPositionX(padid); - double padsizeX = seg2.padSizeX(padid); - double padposY = seg2.padPositionY(padid); - double padsizeY = seg2.padSizeY(padid); - auto t = o2::mch::getTransformation(detElemId2, *gGeoManager); - - o2::math_utils::Point3D<float> pos(hits.at(1).GetX(), hits.at(1).GetY(), hits.at(1).GetZ()); - o2::math_utils::Point3D<float> lpos; - t.MasterToLocal(pos, lpos); - - BOOST_CHECK_CLOSE(lpos.x(), padposX, padsizeX * 4.0); - BOOST_CHECK_CLOSE(lpos.y(), padposY, padsizeY * 10.0); - digitcounter2++; - - } else { - BOOST_FAIL(" MC-labels not matching between hit and digit "); - }; - } - - if (digitcounter1 == 0) { - BOOST_FAIL(" no digit at all from hit in station 1 "); - } - if (digitcounter1 > 9) { - BOOST_FAIL("more than 10 digits for one hit in station 1 "); - } - if (digitcounter2 == 0) { - BOOST_FAIL(" no digit at all from hit in station 2 "); - } - if (digitcounter2 > 9) { - BOOST_FAIL(" more than 10 digits for one hit in station 2 "); - } -} - -BOOST_TEST_DECORATOR(*boost::unit_test::disabled()) -BOOST_AUTO_TEST_CASE(mergingDigitizer) -{ - //merging - o2::mch::Digitizer digitizer; - int trackId1 = 0; - int trackId2 = 1; - short detElemId1 = 101; - short detElemId2 = 1012; - float eloss1 = 1e-6; - float eloss2 = 1e-6; - float length = 0.f; - float tof = 0.0; - - std::vector<o2::mch::Hit> hits(2); - hits.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss1, length, tof); - hits.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss2, length, tof); - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mctruthcontainer; - std::vector<o2::mch::Digit> digits; - - digitizer.process(hits, digits, mctruthcontainer); - - std::vector<o2::MCCompLabel> labels = digitizer.getTrackLabels(); - - int rep1 = 9; - int rep2 = 9; - - for (int i = 0; i < rep1; i++) { - digits.emplace_back(digits.at(0).getDetID(), digits.at(0).getPadID(), digits.at(0).getADC(), digits.at(0).getTime()); - labels.emplace_back(labels.at(0).getTrackID(), labels.at(0).getEventID(), labels.at(0).getSourceID(), false); - } - for (int i = 0; i < rep2; i++) { - digits.emplace_back(digits.at(0).getDetID(), digits.at(1).getPadID(), digits.at(1).getADC(), digits.at(1).getTime()); - labels.emplace_back(labels.at(1).getTrackID(), labels.at(1).getEventID(), labels.at(1).getSourceID(), false); - } - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> container; - - for (int index = 0; index < labels.size(); ++index) { - container.addElement(index, labels.at(index)); - } - - digitizer.mergeDigits(digits, container); - - std::vector<o2::mch::Digit> mergeddigits = digitizer.getDigits(); - std::vector<o2::MCCompLabel> mergedlabels = digitizer.getTrackLabels(); - - BOOST_CHECK_CLOSE(mergeddigits.at(0).getADC(), digits.at(0).getADC() * (float)(rep1 + 1), digits.at(0).getADC() / 10000.); - BOOST_CHECK_CLOSE(mergeddigits.at(1).getADC(), digits.at(1).getADC() * (float)(rep2 + 1), digits.at(1).getADC() / 10000.); - BOOST_CHECK_CLOSE((float)mergedlabels.at(0).getTrackID(), (float)labels.at(0).getTrackID(), 0.1); - BOOST_CHECK_CLOSE((float)mergedlabels.at(1).getTrackID(), (float)labels.at(1).getTrackID(), 0.1); - - BOOST_CHECK_CLOSE((float)(digits.size() - rep1 - rep2), (float)mergeddigits.size(), 0.1); - -} //testing - -BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx b/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx new file mode 100644 index 0000000000000..26d195da4ccad --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx @@ -0,0 +1,240 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file testDigitisation.cxx +/// \brief This task tests the Digitizer and the Response of the MCH digitization +/// \author Michael Winn, DPhN/IRFU/CEA, michael.winn@cern.ch + +#define BOOST_TEST_MODULE Test MCHSimulation Digitization +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/Digit.h" +#include "MCHGeometryCreator/Geometry.h" +#include "MCHGeometryTest/Helpers.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHMappingInterface/Segmentation.h" +#include "MCHSimulation/Digitizer.h" +#include "MCHSimulation/Hit.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "TGeoManager.h" +#include "boost/format.hpp" +#include <boost/test/data/test_case.hpp> + +using IR = o2::InteractionRecord; +using o2::mch::Digit; +using o2::mch::groupIR; +using o2::mch::Hit; +using o2::mch::mapping::Segmentation; + +struct GEOMETRY { + GEOMETRY() + { + if (!gGeoManager) { + o2::mch::test::createStandaloneGeometry(); + } + } +}; + +namespace +{ +o2::math_utils::Point3D<float> entrancePoint1(-17.7993, 8.929883, -522.201); //x,y,z coordinates in cm +o2::math_utils::Point3D<float> exitPoint1(-17.8136, 8.93606, -522.62); +o2::math_utils::Point3D<float> entrancePoint2(-49.2793, 28.8673, -1441.25); +o2::math_utils::Point3D<float> exitPoint2(-49.2965, 28.8806, -1441.75); + +int check(const Hit& hit, const Digit& digit, Segmentation& seg, o2::mch::geo::TransformationCreator transformation) +{ + int padid = digit.getPadID(); + bool check = seg.isValid(padid); + if (!check) { + BOOST_FAIL(" digit-pad not belonging to hit det-element-ID "); + return 0; + } + double padposX = seg.padPositionX(padid); + double padsizeX = seg.padSizeX(padid); + double padposY = seg.padPositionY(padid); + double padsizeY = seg.padSizeY(padid); + auto t = transformation(digit.getDetID()); + + o2::math_utils::Point3D<float> pos(hit.GetX(), hit.GetY(), hit.GetZ()); + o2::math_utils::Point3D<float> lpos; + t.MasterToLocal(pos, lpos); + + // very loose check : check that digit position is within 10 pads of the + // hit center in both directions + BOOST_CHECK(std::abs(lpos.x() - padposX) < padsizeX * 10); + BOOST_CHECK(std::abs(lpos.y() - padposY) < padsizeY * 10); + return 1; +} +} // namespace + +/// \brief Test of the Digitization +/// A couple of values are filled into Hits and we check whether we get reproducible output in terms of digits +/// and MClabels + +BOOST_FIXTURE_TEST_SUITE(digitization, GEOMETRY) + +BOOST_AUTO_TEST_CASE(DigitizerTest) +{ + // FIXME: must set a (global) seed here to get reproducible results + + auto transformation = o2::mch::geo::transformationFromTGeoManager(*gGeoManager); + + o2::mch::Digitizer digitizer(transformation); + int trackId1 = 0; + int trackId2 = 1; + short detElemId1 = 101; + short detElemId2 = 1012; + + float eloss1 = 1e-6; + float eloss2 = 1e-6; + float length = 0.f; + float tof = 0.0; + + std::vector<o2::mch::Hit> hits(2); + hits.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss1, length, tof); + hits.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss2, length, tof); + + Segmentation seg1{detElemId1}; + Segmentation seg2{detElemId2}; + + digitizer.startCollision({0, 0}); + + o2::conf::ConfigurableParam::setValue("MCHDigitizer", "noiseProba", 0.0); + digitizer.processHits(hits, 0, 0); + + std::vector<Digit> digits; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels; + + digitizer.extractDigitsAndLabels(digits, labels); + + int digitcounter1 = 0; + int digitcounter2 = 0; + int count = 0; + + for (const auto& digit : digits) { + auto label = (labels.getLabels(count))[0]; + int trackID = label.getTrackID(); + ++count; + + if (trackID == trackId1) { + digitcounter1 += check(hits.at(0), digit, seg1, transformation); + } else if (trackID == trackId2) { + digitcounter2 += check(hits.at(1), digit, seg2, transformation); + } else { + BOOST_FAIL(" MC-labels not matching between hit and digit "); + } + } + BOOST_TEST(digitcounter1 > 0); + BOOST_TEST(digitcounter1 < 20); + BOOST_TEST(digitcounter2 > 0); + BOOST_TEST(digitcounter2 < 10); +} + +bool isSame(const std::map<IR, std::vector<int>>& result, + const std::map<IR, std::vector<int>>& expected) +{ + if (result == expected) { + return true; + } + std::cout << result.size() << " " << expected.size() << "\n"; + + std::cout << "Expected:\n"; + for (auto p : expected) { + std::cout << p.first << "-> "; + for (auto v : p.second) { + std::cout << v << ","; + } + std::cout << "\n"; + } + std::cout << "Got:\n"; + for (auto p : result) { + std::cout << p.first << "-> "; + for (auto v : p.second) { + std::cout << v << ","; + } + std::cout << "\n"; + } + return false; +} + +const std::vector<IR> testIRs = { + /* bc, orbit */ + {123, 0}, + {125, 0}, + {125, 0}, + {125, 1}, + {130, 1}, + {134, 1}, + {135, 1}, + {137, 1}, +}; + +BOOST_AUTO_TEST_CASE(GroupIRMustBeAlignedOn4BCMarks) +{ + std::map<IR, std::vector<int>> expected; + expected[IR{120, 0}] = {0}; + expected[IR{124, 0}] = {1, 2}; + expected[IR{124, 1}] = {3}; + expected[IR{128, 1}] = {4}; + expected[IR{132, 1}] = {5, 6}; + expected[IR{136, 1}] = {7}; + + auto g = groupIR(testIRs, 4); + BOOST_CHECK_EQUAL(isSame(g, expected), true); +} + +BOOST_AUTO_TEST_CASE(GroupIRMustThrowOnNonSortedRecords) +{ + const std::vector<IR> notSorted = { + {125, 0}, + {123, 0}, + }; + BOOST_CHECK_THROW(groupIR(notSorted), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(GroupIRInvalidWidthMustThrow) +{ + BOOST_CHECK_THROW(groupIR(testIRs, 0), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(IdenticalIRsShouldBeMerged) +{ + std::map<IR, std::vector<int>> expected; + expected[IR{123, 0}] = {0}; + expected[IR{125, 0}] = {1, 2}; + expected[IR{125, 1}] = {3}; + expected[IR{130, 1}] = {4}; + expected[IR{134, 1}] = {5}; + expected[IR{135, 1}] = {6}; + expected[IR{137, 1}] = {7}; + + auto g = groupIR(testIRs, 1); + BOOST_CHECK_EQUAL(isSame(g, expected), true); +} + +BOOST_AUTO_TEST_CASE(IRSeparatedByLessThan4BCShouldBeMerged) +{ + std::map<IR, std::vector<int>> expected; + expected[IR{120, 0}] = {0}; + expected[IR{124, 0}] = {1, 2}; + expected[IR{124, 1}] = {3}; + expected[IR{128, 1}] = {4}; + expected[IR{132, 1}] = {5, 6}; + expected[IR{136, 1}] = {7}; + + auto g = groupIR(testIRs, 4); + BOOST_CHECK_EQUAL(isSame(g, expected), true); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Simulation/test/testGeometry.cxx b/Detectors/MUON/MCH/Simulation/test/testGeometry.cxx deleted file mode 100644 index bb8a8a583f2d4..0000000000000 --- a/Detectors/MUON/MCH/Simulation/test/testGeometry.cxx +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// @author Laurent Aphecetche - -#define BOOST_TEST_MODULE Test MCHSimulation Geometry -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MAIN - -#include <boost/test/unit_test.hpp> - -#include "MCHMappingInterface/CathodeSegmentation.h" -#include "MCHSimulation/Geometry.h" -#include "MCHSimulation/GeometryTest.h" -#include "TGeoManager.h" -#include "boost/format.hpp" -#include <boost/test/data/test_case.hpp> -#include <fstream> -#include <iomanip> -#include <iostream> -#include <fmt/format.h> - -namespace bdata = boost::unit_test::data; - -struct GEOMETRY { - GEOMETRY() - { - if (!gGeoManager) { - std::string param = boost::unit_test::framework::master_test_suite().argv[1]; - if (param == "standalone") { - o2::mch::test::createStandaloneGeometry(); - } else if (param == "regular") { - o2::mch::test::createRegularGeometry(); - } else { - throw std::invalid_argument(fmt::format("only possible argument value are 'regular' or 'standalone', not {}", param.c_str())); - } - o2::mch::test::addAlignableVolumes(); - } - } -}; - -const std::array<std::string, 8> quadrantChamberNames{"SC01I", "SC01O", "SC02I", "SC02O", "SC03I", "SC03O", - "SC04I", "SC04O"}; - -const std::array<std::string, 12> slatChamberNames{"SC05I", "SC05O", "SC06I", "SC06O", "SC07I", "SC07O", - "SC08I", "SC08O", "SC09I", "SC09O", "SC10I", "SC10O"}; - -const std::vector<std::vector<std::string>> deSymNames{ - {"DE100", "DE103"}, - {"DE101", "DE102"}, - {"DE200", "DE203"}, - {"DE201", "DE202"}, - {"DE300", "DE303"}, - {"DE301", "DE302"}, - {"DE400", "DE403"}, - {"DE401", "DE402"}, - {"DE500", "DE501", "DE502", "DE503", "DE504", "DE514", "DE515", "DE516", "DE517"}, - {"DE505", "DE506", "DE507", "DE508", "DE509", "DE510", "DE511", "DE512", "DE513"}, - {"DE600", "DE601", "DE602", "DE603", "DE604", "DE614", "DE615", "DE616", "DE617"}, - {"DE605", "DE606", "DE607", "DE608", "DE609", "DE610", "DE611", "DE612", "DE613"}, - {"DE700", "DE701", "DE702", "DE703", "DE704", "DE705", "DE706", "DE720", "DE721", "DE722", "DE723", "DE724", "DE725"}, - {"DE707", "DE708", "DE709", "DE710", "DE711", "DE712", "DE713", "DE714", "DE715", "DE716", "DE717", "DE718", "DE719"}, - {"DE800", "DE801", "DE802", "DE803", "DE804", "DE805", "DE806", "DE820", "DE821", "DE822", "DE823", "DE824", "DE825"}, - {"DE807", "DE808", "DE809", "DE810", "DE811", "DE812", "DE813", "DE814", "DE815", "DE816", "DE817", "DE818", "DE819"}, - {"DE900", "DE901", "DE902", "DE903", "DE904", "DE905", "DE906", "DE920", "DE921", "DE922", "DE923", "DE924", "DE925"}, - {"DE907", "DE908", "DE909", "DE910", "DE911", "DE912", "DE913", "DE914", "DE915", "DE916", "DE917", "DE918", "DE919"}, - {"DE1000", "DE1001", "DE1002", "DE1003", "DE1004", "DE1005", "DE1006", "DE1020", "DE1021", "DE1022", "DE1023", "DE1024", "DE1025"}, - {"DE1007", "DE1008", "DE1009", "DE1010", "DE1011", "DE1012", "DE1013", "DE1014", "DE1015", "DE1016", "DE1017", "DE1018", "DE1019"}}; - -BOOST_AUTO_TEST_SUITE(o2_mch_simulation) - -BOOST_FIXTURE_TEST_SUITE(geometrytransformer, GEOMETRY) - -BOOST_AUTO_TEST_CASE(CanGetAllChambers) -{ - std::vector<std::string> chamberNames{quadrantChamberNames.begin(), quadrantChamberNames.end()}; - - chamberNames.insert(chamberNames.end(), slatChamberNames.begin(), slatChamberNames.end()); - - for (auto chname : chamberNames) { - auto vol = gGeoManager->GetVolume(chname.c_str()); - BOOST_TEST_REQUIRE((vol != nullptr)); - } -} - -std::vector<TGeoNode*> getSlatNodes() -{ - std::vector<TGeoNode*> slats; - for (auto chname : slatChamberNames) { - auto vol = gGeoManager->GetVolume(chname.c_str()); - TIter next(vol->GetNodes()); - while (TGeoNode* node = static_cast<TGeoNode*>(next())) { - if (strstr(node->GetName(), "support") == nullptr) { - slats.push_back(node); - } - } - } - return slats; -} - -std::vector<TGeoNode*> getQuadrantNodes() -{ - std::vector<TGeoNode*> quadrants; - for (auto chname : quadrantChamberNames) { - auto vol = gGeoManager->GetVolume(chname.c_str()); - TIter next(vol->GetNodes()); - while (TGeoNode* node = static_cast<TGeoNode*>(next())) { - quadrants.push_back(node); - } - } - return quadrants; -} - -BOOST_AUTO_TEST_CASE(GetRightNumberOfSlats) -{ - auto slats = getSlatNodes(); - BOOST_CHECK_EQUAL(slats.size(), 140); -} - -BOOST_AUTO_TEST_CASE(GetRightNumberOfQuadrants) -{ - auto quadrants = getQuadrantNodes(); - BOOST_CHECK_EQUAL(quadrants.size(), 16); -} - -BOOST_AUTO_TEST_CASE(GetDetElemVolumePath, *boost::unit_test::disabled() * boost::unit_test::label("debug")) -{ - TIter next(gGeoManager->GetTopNode()->GetNodes()); - TGeoNode* node; - TGeoNode* n2; - - std::vector<std::string> codeLines; - - while ((node = static_cast<TGeoNode*>(next()))) { - std::cout << node->GetName() << "\n"; - TIter next2(node->GetNodes()); - while ((n2 = static_cast<TGeoNode*>(next2()))) { - std::string n2name{n2->GetName()}; - auto index = n2name.find_last_of('_'); - int detElemId = std::atoi(n2name.substr(index + 1).c_str()); - if (detElemId >= 100) { - std::stringstream s; - s << "if (detElemId==" << detElemId << ") {\n"; - s << R"( return ")" << node->GetName() << "/" << n2name << "\";\n"; - s << "}\n"; - codeLines.push_back(s.str()); - } - } - } - - for (auto s : codeLines) { - std::cout << s; - } - BOOST_CHECK_EQUAL(codeLines.size(), 156); -} - -BOOST_AUTO_TEST_CASE(GetTransformationMustNotThrowForValidDetElemId) -{ - BOOST_REQUIRE(gGeoManager != nullptr); - - o2::mch::mapping::forEachDetectionElement([](int detElemId) { - BOOST_CHECK_NO_THROW((o2::mch::getTransformation(detElemId, *gGeoManager))); - }); -} - -struct CoarseLocation { - bool isRight; - bool isTop; -}; - -constexpr CoarseLocation topRight{true, true}; -constexpr CoarseLocation topLeft{false, true}; -constexpr CoarseLocation bottomRight{true, false}; -constexpr CoarseLocation bottomLeft{false, false}; - -std::string asString(const CoarseLocation& q) -{ - std::string s = q.isTop ? "TOP" : "BOTTOM"; - s += q.isRight ? "RIGHT" : "LEFT"; - return s; -} - -bool operator==(const CoarseLocation& a, const CoarseLocation& b) -{ - return a.isRight == b.isRight && a.isTop == b.isTop; -} - -CoarseLocation getDetElemCoarseLocation(int detElemId) -{ - auto t = o2::mch::getTransformation(detElemId, *gGeoManager); - o2::math_utils::Point3D<double> localTestPos{0.0, 0.0, 0.0}; // slat center - - if (detElemId < 500) { - // in the rough ballpark of the center - // of the quadrants - localTestPos.SetXYZ(60, 60, 0); - } - - // for slats around the middle (y closest to 0) we have to be a bit - // more precise, so take a given pad reference, chosen to be - // the most top right or most top left pad - - switch (detElemId) { - case 500: - case 509: - localTestPos.SetXYZ(-72.50, 19.75, 0.0); // ds 107 - break; - case 600: - case 609: - localTestPos.SetXYZ(-77.50, 19.75, 0.0); // ds 108 - break; - case 700: - case 713: - case 800: - case 813: - case 900: - case 913: - case 1000: - case 1013: - localTestPos.SetXYZ(95.0, -19.75, 0); // ds 104 - break; - } - o2::math_utils::Point3D<double> master; - - t.LocalToMaster(localTestPos, master); - bool right = master.x() > 10.; - bool top = master.y() > -10.; - - return CoarseLocation{right, top}; -} - -void setExpectation(int firstDeId, int lastDeId, CoarseLocation q, std::map<int, CoarseLocation>& expected) -{ - for (int deid = firstDeId; deid <= lastDeId; deid++) { - expected.emplace(deid, q); - } -} - -BOOST_AUTO_TEST_CASE(DetectionElementMustBeInTheRightCoarseLocation) -{ - std::map<int, CoarseLocation> expected; - - for (int i = 0; i < 4; i++) { - expected[100 + i * 100] = topRight; - expected[101 + i * 100] = topLeft; - expected[102 + i * 100] = bottomLeft; - expected[103 + i * 100] = bottomRight; - } - - // note that by convention we consider slats in the middle to be "top" - for (int i = 0; i < 2; i++) { - setExpectation(500 + i * 100, 504 + i * 100, topRight, expected); - setExpectation(505 + i * 100, 509 + i * 100, topLeft, expected); - setExpectation(510 + i * 100, 513 + i * 100, bottomLeft, expected); - setExpectation(514 + i * 100, 517 + i * 100, bottomRight, expected); - } - - for (int i = 0; i < 4; i++) { - setExpectation(700 + i * 100, 706 + i * 100, topRight, expected); - setExpectation(707 + i * 100, 713 + i * 100, topLeft, expected); - setExpectation(714 + i * 100, 719 + i * 100, bottomLeft, expected); - setExpectation(720 + i * 100, 725 + i * 100, bottomRight, expected); - } - - o2::mch::mapping::forEachDetectionElement([&expected](int detElemId) { - if (expected.find(detElemId) == expected.end()) { - std::cout << "got no expectation for DE=" << detElemId << "\n"; - return; - } - BOOST_TEST_INFO(fmt::format("DeId {}", detElemId)); - BOOST_CHECK_EQUAL(asString(getDetElemCoarseLocation(detElemId)), asString(expected[detElemId])); - }); -} - -BOOST_AUTO_TEST_CASE(TextualTreeDump) -{ - std::string param = boost::unit_test::framework::master_test_suite().argv[1]; - if (param != "standalone") { - // no point in checking the full hierarchy and have this test - // depending on all the details of the geometry of all detectors, - // so this test only makes sense for standalone geometry - BOOST_CHECK(true); - return; - } - - const std::string expected = - R"(cave_1 -├──SC01I_0 -│ ├──Quadrant (chamber 1)_100 -│ └──Quadrant (chamber 1)_103 -├──SC01O_1 -│ ├──Quadrant (chamber 1)_101 -│ └──Quadrant (chamber 1)_102 -├──SC02I_2 -│ ├──Quadrant (chamber 2)_200 -│ └──Quadrant (chamber 2)_203 -├──SC02O_3 -│ ├──Quadrant (chamber 2)_201 -│ └──Quadrant (chamber 2)_202 -├──SC03I_4 -│ ├──Station 2 quadrant_300 -│ └──Station 2 quadrant_303 -├──SC03O_5 -│ ├──Station 2 quadrant_301 -│ └──Station 2 quadrant_302 -├──SC04I_6 -│ ├──Station 2 quadrant_400 -│ └──Station 2 quadrant_403 -├──SC04O_7 -│ ├──Station 2 quadrant_401 -│ └──Station 2 quadrant_402 -├──SC05I_8 -│ ├──Chamber 5 support panel_8 -│ ├──122000SR1_500 -│ ├──112200SR2_501 -│ ├──122200S_502 -│ ├──222000N_503 -│ ├──220000N_504 -│ ├──220000N_514 -│ ├──222000N_515 -│ ├──122200S_516 -│ └──112200SR2_517 -├──SC05O_9 -│ ├──Chamber 5 support panel_9 -│ ├──220000N_505 -│ ├──222000N_506 -│ ├──122200S_507 -│ ├──112200SR2_508 -│ ├──122000SR1_509 -│ ├──112200SR2_510 -│ ├──122200S_511 -│ ├──222000N_512 -│ └──220000N_513 -├──SC06I_10 -│ ├──Chamber 6 support panel_10 -│ ├──122000NR1_600 -│ ├──112200NR2_601 -│ ├──122200N_602 -│ ├──222000N_603 -│ ├──220000N_604 -│ ├──220000N_614 -│ ├──222000N_615 -│ ├──122200N_616 -│ └──112200NR2_617 -├──SC06O_11 -│ ├──Chamber 6 support panel_11 -│ ├──220000N_605 -│ ├──222000N_606 -│ ├──122200N_607 -│ ├──112200NR2_608 -│ ├──122000NR1_609 -│ ├──112200NR2_610 -│ ├──122200N_611 -│ ├──222000N_612 -│ └──220000N_613 -├──SC07I_12 -│ ├──Chamber 7 support panel_12 -│ ├──122330N_700 -│ ├──112233NR3_701 -│ ├──112230N_702 -│ ├──222330N_703 -│ ├──223300N_704 -│ ├──333000N_705 -│ ├──330000N_706 -│ ├──330000N_720 -│ ├──333000N_721 -│ ├──223300N_722 -│ ├──222330N_723 -│ ├──112230N_724 -│ └──112233NR3_725 -├──SC07O_13 -│ ├──Chamber 7 support panel_13 -│ ├──330000N_707 -│ ├──333000N_708 -│ ├──223300N_709 -│ ├──222330N_710 -│ ├──112230N_711 -│ ├──112233NR3_712 -│ ├──122330N_713 -│ ├──112233NR3_714 -│ ├──112230N_715 -│ ├──222330N_716 -│ ├──223300N_717 -│ ├──333000N_718 -│ └──330000N_719 -├──SC08I_14 -│ ├──Chamber 8 support panel_14 -│ ├──122330N_800 -│ ├──112233NR3_801 -│ ├──112230N_802 -│ ├──222330N_803 -│ ├──223300N_804 -│ ├──333000N_805 -│ ├──330000N_806 -│ ├──330000N_820 -│ ├──333000N_821 -│ ├──223300N_822 -│ ├──222330N_823 -│ ├──112230N_824 -│ └──112233NR3_825 -├──SC08O_15 -│ ├──Chamber 8 support panel_15 -│ ├──330000N_807 -│ ├──333000N_808 -│ ├──223300N_809 -│ ├──222330N_810 -│ ├──112230N_811 -│ ├──112233NR3_812 -│ ├──122330N_813 -│ ├──112233NR3_814 -│ ├──112230N_815 -│ ├──222330N_816 -│ ├──223300N_817 -│ ├──333000N_818 -│ └──330000N_819 -├──SC09I_16 -│ ├──Chamber 9 support panel_16 -│ ├──122330N_900 -│ ├──112233NR3_901 -│ ├──112233N_902 -│ ├──222333N_903 -│ ├──223330N_904 -│ ├──333300N_905 -│ ├──333000N_906 -│ ├──333000N_920 -│ ├──333300N_921 -│ ├──223330N_922 -│ ├──222333N_923 -│ ├──112233N_924 -│ └──112233NR3_925 -├──SC09O_17 -│ ├──Chamber 9 support panel_17 -│ ├──333000N_907 -│ ├──333300N_908 -│ ├──223330N_909 -│ ├──222333N_910 -│ ├──112233N_911 -│ ├──112233NR3_912 -│ ├──122330N_913 -│ ├──112233NR3_914 -│ ├──112233N_915 -│ ├──222333N_916 -│ ├──223330N_917 -│ ├──333300N_918 -│ └──333000N_919 -├──SC10I_18 -│ ├──Chamber 10 support panel_18 -│ ├──122330N_1000 -│ ├──112233NR3_1001 -│ ├──112233N_1002 -│ ├──222333N_1003 -│ ├──223330N_1004 -│ ├──333300N_1005 -│ ├──333000N_1006 -│ ├──333000N_1020 -│ ├──333300N_1021 -│ ├──223330N_1022 -│ ├──222333N_1023 -│ ├──112233N_1024 -│ └──112233NR3_1025 -└──SC10O_19 - ├──Chamber 10 support panel_19 - ├──333000N_1007 - ├──333300N_1008 - ├──223330N_1009 - ├──222333N_1010 - ├──112233N_1011 - ├──112233NR3_1012 - ├──122330N_1013 - ├──112233NR3_1014 - ├──112233N_1015 - ├──222333N_1016 - ├──223330N_1017 - ├──333300N_1018 - └──333000N_1019 -)"; - - std::ostringstream str; - o2::mch::test::showGeometryAsTextTree("/cave_1", 2, str); - BOOST_CHECK(expected == str.str()); -} - -BOOST_AUTO_TEST_CASE(GetAlignableHalfChambers) -{ - BOOST_REQUIRE(gGeoManager != nullptr); - - for (int i = 0; i < 20; i++) { - BOOST_CHECK((gGeoManager->GetAlignableEntry((fmt::format("MCH/HC{}", i)).c_str()))); - } -} - -BOOST_AUTO_TEST_CASE(GetAlignableDetectionElements) -{ - BOOST_REQUIRE(gGeoManager != nullptr); - - for (int hc = 0; hc < 20; hc++) { - for (int de = 0; de < deSymNames[hc].size(); de++) { - BOOST_CHECK((gGeoManager->GetAlignableEntry((fmt::format("MCH/HC{}/{}", hc, deSymNames[hc][de].c_str())).c_str()))); - } - } -} -BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Simulation/test/testRegularGeometry.cxx b/Detectors/MUON/MCH/Simulation/test/testRegularGeometry.cxx new file mode 100644 index 0000000000000..e99e186226dc6 --- /dev/null +++ b/Detectors/MUON/MCH/Simulation/test/testRegularGeometry.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHSimulation RegularGeometry +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "DetectorsPassive/Absorber.h" +#include "DetectorsPassive/Cave.h" +#include "DetectorsPassive/Compensator.h" +#include "DetectorsPassive/Dipole.h" +#include "DetectorsPassive/Pipe.h" +#include "DetectorsPassive/Shil.h" +#include "MCHSimulation/Detector.h" +#include "TGeoManager.h" +#include <boost/test/data/test_case.hpp> +#include <fstream> +#include <iomanip> +#include <iostream> + +BOOST_AUTO_TEST_CASE(DoNotThrow) +{ + if (gGeoManager && gGeoManager->GetTopVolume()) { + std::cerr << "Can only call this function with an empty geometry, i.e. gGeoManager==nullptr " + << " or gGeoManager->GetTopVolume()==nullptr\n"; + } + TGeoManager* g = new TGeoManager("MCH-BASICS", "ALICE MCH Regular Geometry"); + o2::passive::Cave("CAVE", "Cave (for MCH Basics)").ConstructGeometry(); + o2::passive::Dipole("DIPO", "Alice Dipole (for MCH Basics)").ConstructGeometry(); + o2::passive::Compensator("COMP", "Alice Compensator Dipole (for MCH Basics)").ConstructGeometry(); + o2::passive::Pipe("PIPE", "Beam pipe (for MCH Basics)").ConstructGeometry(); + o2::passive::Shil("SHIL", "Small angle beam shield (for MCH Basics)").ConstructGeometry(); + o2::passive::Absorber("ABSO", "Absorber (for MCH Basics)").ConstructGeometry(); + BOOST_CHECK_NO_THROW((o2::mch::Detector(true).ConstructGeometry())); +} diff --git a/Detectors/MUON/MCH/Simulation/test/testResponse.cxx b/Detectors/MUON/MCH/Simulation/test/testResponse.cxx index d87a52b10cdc6..eaba42b48cde7 100644 --- a/Detectors/MUON/MCH/Simulation/test/testResponse.cxx +++ b/Detectors/MUON/MCH/Simulation/test/testResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,9 @@ /// \brief This task tests of the Response of the MCH digitization /// \author Michael Winn, DPhN/IRFU/CEA, michael.winn@cern.ch +#define BOOST_TEST_MODULE Test MCHSimulation Response #define BOOST_TEST_DYN_LINK + #include <boost/test/unit_test.hpp> #include <memory> #include <vector> diff --git a/Detectors/MUON/MCH/TimeClustering/CMakeLists.txt b/Detectors/MUON/MCH/TimeClustering/CMakeLists.txt new file mode 100644 index 0000000000000..25abab56d2a03 --- /dev/null +++ b/Detectors/MUON/MCH/TimeClustering/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MCHTimeClustering + SOURCES src/ROFTimeClusterFinder.cxx + PUBLIC_LINK_LIBRARIES O2::MCHBase O2::Framework) + +if(BUILD_TESTING) + + o2_add_test(time-cluster-finder + SOURCES src/testROFTimeClusterFinder.cxx + COMPONENT_NAME mchtimeclustering + LABELS "muon;mch;timeclustering" + PUBLIC_LINK_LIBRARIES O2::MCHRawDecoder O2::MCHTimeClustering Boost::boost) + +endif() diff --git a/Detectors/MUON/MCH/TimeClustering/include/MCHTimeClustering/ROFTimeClusterFinder.h b/Detectors/MUON/MCH/TimeClustering/include/MCHTimeClustering/ROFTimeClusterFinder.h new file mode 100644 index 0000000000000..647e99ad41fe7 --- /dev/null +++ b/Detectors/MUON/MCH/TimeClustering/include/MCHTimeClustering/ROFTimeClusterFinder.h @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ROFTimeClusterFinder.h +/// \brief Class to group the fired pads according to their time stamp +/// +/// \author Andrea Ferrero, CEA + +#ifndef ALICEO2_MCH_ROFTIMECLUSTERFINDER_H_ +#define ALICEO2_MCH_ROFTIMECLUSTERFINDER_H_ + +#include <cassert> +#include <cstdint> +#include <vector> +#include <gsl/span> + +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" + +namespace o2 +{ +namespace mch +{ + +class ROFTimeClusterFinder +{ + public: + using ROFVector = std::vector<o2::mch::ROFRecord>; + + ROFTimeClusterFinder(gsl::span<const o2::mch::ROFRecord> rof, uint32_t timeClusterSize, uint32_t nBins, int debug); + ~ROFTimeClusterFinder() = default; + + /// process the digit ROFs and create the time clusters + void process(); + + /// return the vector of time-cluster ROFs + const ROFVector& getROFRecords() const { return mOutputROFs; } + + /// stores the output ROFs into a flat memory buffer + char* saveROFRsToBuffer(size_t& bufSize); + + /// debugging output + void dumpInputROFs(); + void dumpOutputROFs(); + + private: + /// structure representing one bin in the time histogram used for the peak search algorithm + struct TimeBin { + int32_t mFirstIdx{-1}; ///< index of the first digit ROF in the bin + int32_t mLastIdx{-1}; ///< index of the last digit ROF in the bin + uint32_t mSize{0}; ///< number of digit ROFs in the bin + uint32_t mNDigits{0}; ///< number of digits in the bin + + TimeBin() = default; + + bool empty() { return mNDigits == 0; } + + bool operator<(const TimeBin& other) { return (mNDigits < other.mNDigits); } + bool operator>(const TimeBin& other) { return (mNDigits > other.mNDigits); } + bool operator<=(const TimeBin& other) { return (mNDigits <= other.mNDigits); } + bool operator>=(const TimeBin& other) { return (mNDigits >= other.mNDigits); } + }; + + // peak search parameters + static constexpr uint32_t sMaxOrbitsInTF = 256; ///< upper limit of the time frame size + static constexpr uint32_t sBcInOneOrbit = o2::constants::lhc::LHCMaxBunches; ///< number of bunch-crossings in one orbit + static constexpr uint32_t sBcInOneTF = sBcInOneOrbit * sMaxOrbitsInTF; ///< maximum number of bunch-crossings in one time frame + + uint32_t mTimeClusterSize; ///< maximum size of one time cluster, in bunch crossings + uint32_t mNbinsInOneWindow; ///< number of time bins considered for the peak search + double mBinWidth; ///< width of one time bin in the peak search algorithm, in bunch crossings + uint32_t mNbinsInOneTF; ///< maximum number of peak search bins in one time frame + + /// fill the time histogram for the peak search algorithm + void initTimeBins(); + /// search for the next peak in the time histogram + int32_t getNextPeak(); + /// create an output ROF containing all the digits in the [firstBin,lastBin] range of the time histogram + void storeROF(int32_t firstBin, int32_t lastBin); + + std::vector<TimeBin> mTimeBins; ///< time histogram for the peak search algorithm + int32_t mLastSavedTimeBin; ///< index of the last bin that has been stored in the output ROFs + + gsl::span<const o2::mch::ROFRecord> mInputROFs; ///< input digit ROFs + ROFVector mOutputROFs{}; ///< output time cluster ROFs + //o2::InteractionRecord mTFstart; ///< beginning of the time frame being processed + int mDebug{true}; +}; + +} // namespace mch +} // namespace o2 + +#endif // ALICEO2_MCH_ROFTIMECLUSTERFINDER_H_ diff --git a/Detectors/MUON/MCH/TimeClustering/src/ROFTimeClusterFinder.cxx b/Detectors/MUON/MCH/TimeClustering/src/ROFTimeClusterFinder.cxx new file mode 100644 index 0000000000000..b6ccb7baa31f3 --- /dev/null +++ b/Detectors/MUON/MCH/TimeClustering/src/ROFTimeClusterFinder.cxx @@ -0,0 +1,278 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHTimeClustering/ROFTimeClusterFinder.h" + +#include <iostream> +#include <fmt/format.h> + +namespace o2 +{ +namespace mch +{ + +using namespace std; + +//_________________________________________________________________________________________________ + +ROFTimeClusterFinder::ROFTimeClusterFinder(gsl::span<const o2::mch::ROFRecord> rofs, uint32_t timeClusterSize, uint32_t nBins, int debug) : mInputROFs(rofs), mTimeClusterSize(timeClusterSize), mNbinsInOneWindow(nBins), mDebug(debug) +{ + // bin width in bunch crossing units + mBinWidth = mTimeClusterSize / mNbinsInOneWindow; + mNbinsInOneTF = sBcInOneTF / mBinWidth + 1; + + mTimeBins.resize(mNbinsInOneTF); +} + +//_________________________________________________________________________________________________ + +void ROFTimeClusterFinder::initTimeBins() +{ + // initialize the time bins vector + std::fill(mTimeBins.begin(), mTimeBins.end(), TimeBin()); + + if (mInputROFs.empty()) { + return; + } + + o2::InteractionRecord mFirstIR = mInputROFs.front().getBCData(); + + // store the number of digits in each bin + for (size_t iRof = 0; iRof < mInputROFs.size(); iRof++) { + const auto& rof = mInputROFs[iRof]; + const auto& ir = rof.getBCData(); + auto rofBc = ir.differenceInBC(mFirstIR); + auto binIdx = rofBc / mBinWidth; + + if (binIdx < 0) { + continue; + } else if (binIdx >= mNbinsInOneTF) { + break; + } + + auto& timeBin = mTimeBins[binIdx]; + + if (timeBin.mFirstIdx < 0) { + timeBin.mFirstIdx = iRof; + } + timeBin.mLastIdx = iRof; + timeBin.mSize += 1; + timeBin.mNDigits += rof.getNEntries(); + } + + if (mDebug) { + std::cout << "Peak search histogram:" << std::endl; + for (int32_t i = 0; i < mNbinsInOneTF; i++) { + if (mTimeBins[i].mNDigits > 0) { + std::cout << fmt::format("bin {}: {}", i, mTimeBins[i].mNDigits) << std::endl; + } + } + } +} + +//_________________________________________________________________________________________________ + +int32_t ROFTimeClusterFinder::getNextPeak() +{ + int32_t sPadding = mNbinsInOneWindow / 2; + + if (mDebug) { + std::cout << "Searching peak from " << mLastSavedTimeBin + 1 << std::endl; + } + + // loop over the bins and search for local maxima + // a local maxima is defined as a bin tht is higher than all the surrounding 4 bins (2 below and 2 above) + for (int32_t i = mLastSavedTimeBin + sPadding + 1; i < mNbinsInOneTF; i++) { + auto& peak = mTimeBins[i]; + if (peak.empty()) { + continue; + } + + bool found{true}; + // the peak must be strictly higher than previous bins + for (int j = i - sPadding; j < i; j++) { + if (j >= 0 && peak <= mTimeBins[j]) { + found = false; + break; + } + } + // the peak must be higher than or equal to next bins + for (int j = i + 1; j <= i + sPadding; j++) { + if (j < mNbinsInOneTF && peak < mTimeBins[j]) { + found = false; + break; + } + } + + if (!found) { + continue; + } + + if (mDebug) { + std::cout << fmt::format("new peak found at bin {}, entries = {}", i, mTimeBins[i].mNDigits) << std::endl; + } + + return i; + } + return -1; +} + +//_________________________________________________________________________________________________ + +void ROFTimeClusterFinder::storeROF(int32_t firstBin, int32_t lastBin) +{ + if (mDebug) { + std::cout << fmt::format("Storing ROF from bin range [{},{}]", firstBin, lastBin) << std::endl; + } + + if (firstBin < 0) { + firstBin = 0; + } + if (lastBin >= mNbinsInOneTF) { + lastBin = mNbinsInOneTF - 1; + } + + int32_t rofFirstIdx{-1}; + int32_t rofLastIdx{-1}; + uint32_t nDigits{0}; + uint32_t nROFs{0}; + for (int32_t j = firstBin; j <= lastBin; j++) { + auto& timeBin = mTimeBins[j]; + if (timeBin.mFirstIdx < 0) { + continue; + } + + if (rofFirstIdx < 0) { + rofFirstIdx = timeBin.mFirstIdx; + }; + rofLastIdx = timeBin.mLastIdx; + + nROFs += timeBin.mSize; + nDigits += timeBin.mNDigits; + + if (mDebug) { + std::cout << fmt::format(" bin {}: firstIdx={} size={} ndigits={}", j, timeBin.mFirstIdx, timeBin.mSize, timeBin.mNDigits) << std::endl; + } + } + + // a new time ROF is stored only if there are some digit ROFs in the interval + if (rofFirstIdx >= 0) { + // get the indexes of the first and last ROFs in this time cluster, and the corresponding interaction records + auto& firstRofInCluster = mInputROFs[rofFirstIdx]; + auto& irFirst = firstRofInCluster.getBCData(); + auto& lastRofInCluster = mInputROFs[rofLastIdx]; + auto& irLast = lastRofInCluster.getBCData(); + + // get the index of the first digit in this time cluster + auto firstDigitIdx = firstRofInCluster.getFirstIdx(); + + // compute the width in BC units of the time-cluster ROF + auto bcDiff = irLast.differenceInBC(irFirst); + auto bcWidth = bcDiff + lastRofInCluster.getBCWidth(); + + // create a ROF that includes all the digits in this time cluster + mOutputROFs.emplace_back(irFirst, firstDigitIdx, nDigits, bcWidth); + + if (mDebug) { + std::cout << fmt::format("new ROF stored: firstDigitIdx={} size={} bcWidth={}", firstDigitIdx, nDigits, bcWidth) << std::endl; + } + } + + mLastSavedTimeBin = lastBin; +} + +//_________________________________________________________________________________________________ + +void ROFTimeClusterFinder::process() +{ + if (mDebug) { + std::cout << "\n\n==================\n[ROFTimeClusterFinder] processing new TF\n" + << std::endl; + } + + initTimeBins(); + + mLastSavedTimeBin = -1; + int32_t peak{-1}; + while ((peak = getNextPeak()) >= 0) { + int32_t peakStart = peak - mNbinsInOneWindow / 2; + int32_t peakEnd = peakStart + mNbinsInOneWindow - 1; + + // peak found, we add the corresponding rof(s) + // first we fill the gap between the last peak and the current one, if needed + if (mDebug) { + std::cout << fmt::format("peakStart={} mLastSavedTimeBin={}", peakStart, mLastSavedTimeBin) << std::endl; + } + while ((peakStart - mLastSavedTimeBin) > 1) { + int32_t firstBin = mLastSavedTimeBin + 1; + int32_t lastBin = firstBin + mNbinsInOneWindow - 1; + if (lastBin >= peakStart) { + lastBin = peakStart - 1; + } + + storeROF(firstBin, lastBin); + } + storeROF(peakStart, peakEnd); + } +} + +//_________________________________________________________________________________________________ + +char* ROFTimeClusterFinder::saveROFRsToBuffer(size_t& bufSize) +{ + static constexpr size_t sizeOfROFRecord = sizeof(o2::mch::ROFRecord); + + if (mDebug) { + dumpOutputROFs(); + } + + bufSize = mOutputROFs.size() * sizeOfROFRecord; + o2::mch::ROFRecord* buf = reinterpret_cast<o2::mch::ROFRecord*>(malloc(bufSize)); + if (!buf) { + bufSize = 0; + return nullptr; + } + + o2::mch::ROFRecord* p = buf; + for (size_t i = 0; i < mOutputROFs.size(); i++) { + auto& rof = mOutputROFs[i]; + memcpy(p, &(rof), sizeOfROFRecord); + p += 1; + } + + return reinterpret_cast<char*>(buf); +} + +//_________________________________________________________________________________________________ + +void ROFTimeClusterFinder::dumpInputROFs() +{ + for (size_t i = 0; i < mInputROFs.size(); i++) { + auto& rof = mInputROFs[i]; + const auto ir = rof.getBCData(); + std::cout << fmt::format(" ROF {} RANGE {}-{} SIZE {} IR {}-{},{}\n", i, rof.getFirstIdx(), rof.getLastIdx(), + rof.getNEntries(), ir.orbit, ir.bc, ir.toLong()); + } +} + +//_________________________________________________________________________________________________ + +void ROFTimeClusterFinder::dumpOutputROFs() +{ + for (size_t i = 0; i < mOutputROFs.size(); i++) { + auto& rof = mOutputROFs[i]; + std::cout << fmt::format(" ROF {} RANGE {}-{} SIZE {} IR {}-{},{}\n", i, rof.getFirstIdx(), rof.getLastIdx(), + rof.getNEntries(), rof.getBCData().orbit, rof.getBCData().bc, rof.getBCData().toLong()); + } +} + +} // namespace mch +} // namespace o2 diff --git a/Detectors/MUON/MCH/TimeClustering/src/testROFTimeClusterFinder.cxx b/Detectors/MUON/MCH/TimeClustering/src/testROFTimeClusterFinder.cxx new file mode 100644 index 0000000000000..6f00e113f7c39 --- /dev/null +++ b/Detectors/MUON/MCH/TimeClustering/src/testROFTimeClusterFinder.cxx @@ -0,0 +1,247 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MCHRaw ROFFinder +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <vector> +#include <boost/test/unit_test.hpp> +#include <fmt/format.h> +#include "MCHTimeClustering/ROFTimeClusterFinder.h" + +BOOST_AUTO_TEST_SUITE(o2_mch_raw) + +BOOST_AUTO_TEST_SUITE(timeclustering) + +using ROFRecord = o2::mch::ROFRecord; +using ROFVector = std::vector<ROFRecord>; + +//static constexpr uint32_t sWinSize = 1000 / 25; // number of BC in 1 us +//static constexpr uint32_t sBinsInOneWindow = 5; // number of bins in wich the 1 us window is divided for the peak search +//static constexpr uint32_t sBinWidth = sWinSize / sBinsInOneWindow; // 5 bins in one 1 us window + +static ROFVector makeROFs(std::vector<int> binEntries, uint32_t winSize, uint32_t nBinsInOneWindow) +{ + uint32_t binWidth = winSize / nBinsInOneWindow; + uint32_t orbit = 1; + uint32_t tfTime = 0; + size_t nBins = binEntries.size(); + ROFVector rofRecords; + + int firstDigitIdx = 0; + for (int bin = 0; bin < nBins; bin++) { + // one ROF in each peak search bin, for simplicity + // skip empty bins + if (binEntries[bin] == 0) { + continue; + } + o2::InteractionRecord ir(tfTime + bin * binWidth, orbit); + rofRecords.emplace_back(ir, firstDigitIdx, binEntries[bin], 4); + firstDigitIdx += binEntries[bin]; + } + return rofRecords; +} + +//---------------------------------------------------------------------------- +static ROFVector makeTimeROFs(std::vector<int> binEntries, uint32_t winSize, uint32_t nBinsInOneWindow) +{ + const auto& rofRecords = makeROFs(binEntries, winSize, nBinsInOneWindow); + + o2::mch::ROFTimeClusterFinder rofProcessor(rofRecords, winSize, nBinsInOneWindow, 1); + rofProcessor.process(); + + const auto& rofTimeRecords = rofProcessor.getROFRecords(); + + return rofTimeRecords; +} + +//---------------------------------------------------------------------------- +static std::vector<int> getBinIntegral(std::vector<int> binEntries) +{ + std::vector<int> integral = binEntries; + for (size_t i = 1; i < integral.size(); i++) { + integral[i] += integral[i - 1]; + std::cout << fmt::format("bin[{}]={} integral[{}]={}", i, binEntries[i], i, integral[i]) << std::endl; + } + return integral; +} + +//---------------------------------------------------------------------------- +static void checkROF(const ROFRecord rof, std::vector<int> binEntries, uint32_t winSize, uint32_t nBinsInOneWindow, int start, int width) +{ + uint32_t binWidth = winSize / nBinsInOneWindow; + uint32_t orbit = 1; + uint32_t tfTime = 0; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + // checks of indexes and sizes + int firstIdx = binIntegral[start] - binEntries[start]; + int size = binIntegral[start + width - 1] - firstIdx; + BOOST_CHECK_EQUAL(rof.getFirstIdx(), firstIdx); + BOOST_CHECK_EQUAL(rof.getNEntries(), size); + + // checks of interaction records and BC widths + o2::InteractionRecord irStart(tfTime + start * binWidth, orbit); + BOOST_CHECK_EQUAL(rof.getBCData(), irStart); + int bcWidth = (width - 1) * binWidth + 4; + BOOST_CHECK_EQUAL(rof.getBCWidth(), bcWidth); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeCluster) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 2}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 1); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 5); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeClusterLargeWin) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1500 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 2}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 1); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 5); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeCluster7bins) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1200 / 25; + uint32_t nBins = 7; + std::vector<int> binEntries = {1, 2, 1, 5, 1, 3, 2}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 1); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 7); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeClusterEmptyStart) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {0, 1, 2, 5, 1}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 1); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 1, 4); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeClusterEmptyEnd) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 0}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 1); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 4); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoTimeClusters) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 2, 2, 1, 6, 3, 1}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 2); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 5); + checkROF(rofTimeRecords[1], binEntries, winSize, nBins, 5, 5); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoTimeClustersWithEmptyGap) +{ + uint32_t orbit = 1; + uint32_t tfTime = 0; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 2, 0, 2, 1, 6, 3, 1}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 2); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 5); + checkROF(rofTimeRecords[1], binEntries, winSize, nBins, 6, 5); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(TwoTimeClustersWithNonEmptyGap) +{ + uint32_t orbit = 1; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 2, 4, 5, 2, 1, 6, 3, 1}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 3); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 5); + checkROF(rofTimeRecords[1], binEntries, winSize, nBins, 5, 2); + checkROF(rofTimeRecords[2], binEntries, winSize, nBins, 7, 5); +} + +//---------------------------------------------------------------------------- +BOOST_AUTO_TEST_CASE(OneTimeClusterWithGapAtBeginning) +{ + uint32_t orbit = 1; + uint32_t winSize = 1000 / 25; + uint32_t nBins = 5; + std::vector<int> binEntries = {1, 2, 5, 1, 6, 4, 5}; + std::vector<int> binIntegral = getBinIntegral(binEntries); + + const auto& rofTimeRecords = makeTimeROFs(binEntries, winSize, nBins); + BOOST_CHECK_EQUAL(rofTimeRecords.size(), 2); + + checkROF(rofTimeRecords[0], binEntries, winSize, nBins, 0, 2); + checkROF(rofTimeRecords[1], binEntries, winSize, nBins, 2, 5); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MCH/Tracking/CMakeLists.txt b/Detectors/MUON/MCH/Tracking/CMakeLists.txt index 9aee91ff5e676..35ba67421bbf5 100644 --- a/Detectors/MUON/MCH/Tracking/CMakeLists.txt +++ b/Detectors/MUON/MCH/Tracking/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MCHTracking SOURCES @@ -17,4 +18,8 @@ o2_add_library(MCHTracking src/TrackFitter.cxx src/TrackFinderOriginal.cxx src/TrackFinder.cxx - PUBLIC_LINK_LIBRARIES O2::Field O2::MCHBase) + src/TrackerParam.cxx + PUBLIC_LINK_LIBRARIES O2::Field O2::MCHBase O2::Framework O2::CommonUtils) + +o2_target_root_dictionary(MCHTracking + HEADERS include/MCHTracking/TrackerParam.h) diff --git a/Detectors/MUON/MCH/Tracking/README.md b/Detectors/MUON/MCH/Tracking/README.md index df99f211f7559..966daef78d2af 100644 --- a/Detectors/MUON/MCH/Tracking/README.md +++ b/Detectors/MUON/MCH/Tracking/README.md @@ -97,9 +97,11 @@ attached to the new track. Clusters that drive the track parameters outside of a are discarded. - Improve the tracks: run the smoother to recompute the local chi2 at each cluster, remove the worst cluster if it does not pass a stricter chi2 cut, refit the track and repeat the procedure until all clusters pass the cut or one of them -cannot be removed (the track must contain at least 1 cluster per station), in which case the track is removed. +cannot be removed without violating the tracking conditions (by default, the track must contain at least 1 cluster per +station and both chambers fired on station 4 or 5), in which case the track is removed. - Remove connected tracks in station 3, 4 and 5. If two tracks share at least one cluster in these stations, remove the -one with the smallest number of clusters or with the highest chi2 in case of equality, assuming it is a fake track. +one with the smallest number of fired chambers or with the highest chi2/(ndf-1) in case of equality, assuming it is a +fake track. In all stations, the search for compatible clusters is done in a way to consider every possibilities, i.e. every combinations of 1 to 4 clusters, while skipping the already tested combinations. This includes subsets of previously diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/Cluster.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/Cluster.h index d31e907f26c1b..db708297cdf98 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/Cluster.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/Cluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include <iostream> #include <string> -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" namespace o2 { diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/Track.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/Track.h index 9d32daa8b5fd6..3f6df03b542e4 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/Track.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/Track.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,12 +40,12 @@ class Track Track(Track&&) = delete; Track& operator=(Track&&) = delete; - /// Return a reference to the track parameters at vertex - const TrackParam& getParamAtVertex() const { return mParamAtVertex; } - /// Return the number of attached clusters int getNClusters() const { return mParamAtClusters.size(); } + /// Return the number of degrees of freedom of the track + int getNDF() const { return 2 * getNClusters() - 5; } + /// Return a reference to the track parameters at first cluster const TrackParam& first() const { return mParamAtClusters.front(); } /// Return a reference to the track parameters at last cluster @@ -72,7 +73,7 @@ class Track bool isBetter(const Track& track) const; - void tagRemovableClusters(uint8_t requestedStationMask); + void tagRemovableClusters(uint8_t requestedStationMask, bool request2ChInSameSt45); void setCurrentParam(const TrackParam& param, int chamber); TrackParam& getCurrentParam(); @@ -98,7 +99,6 @@ class Track void print() const; private: - TrackParam mParamAtVertex{}; ///< track parameters at vertex std::list<TrackParam> mParamAtClusters{}; ///< list of track parameters at each cluster std::unique_ptr<TrackParam> mCurrentParam{}; ///< current track parameters used during tracking int mCurrentChamber = -1; ///< current chamber on which the current parameters are given diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackExtrap.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackExtrap.h index 659f6fe0f68b7..0ebeef4674939 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackExtrap.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackExtrap.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,72 +47,74 @@ class TrackExtrap static bool isFieldON() { return sFieldON; } /// Switch to Runge-Kutta extrapolation v2 - static void useExtrapV2() { sExtrapV2 = true; } + static void useExtrapV2(bool extrapV2 = true) { sExtrapV2 = extrapV2; } static double getImpactParamFromBendingMomentum(double bendingMomentum); static double getBendingMomentumFromImpactParam(double impactParam); - static void linearExtrapToZ(TrackParam* trackParam, double zEnd); - static void linearExtrapToZCov(TrackParam* trackParam, double zEnd, bool updatePropagator = false); + static void linearExtrapToZ(TrackParam& trackParam, double zEnd); + static void linearExtrapToZCov(TrackParam& trackParam, double zEnd, bool updatePropagator = false); - static bool extrapToZ(TrackParam* trackParam, double zEnd); - static bool extrapToZCov(TrackParam* trackParam, double zEnd, bool updatePropagator = false); + static bool extrapToZ(TrackParam& trackParam, double zEnd); + static bool extrapToZCov(TrackParam& trackParam, double zEnd, bool updatePropagator = false); - static bool extrapToVertex(TrackParam* trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx) + static bool extrapToVertex(TrackParam& trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx) { /// Extrapolate track parameters to vertex, corrected for multiple scattering and energy loss effects /// Add branson correction resolution and energy loss fluctuation to parameter covariances return extrapToVertex(trackParam, xVtx, yVtx, zVtx, errXVtx, errYVtx, true, true); } - static bool extrapToVertexWithoutELoss(TrackParam* trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx) + static bool extrapToVertexWithoutELoss(TrackParam& trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx) { /// Extrapolate track parameters to vertex, corrected for multiple scattering effects only /// Add branson correction resolution to parameter covariances return extrapToVertex(trackParam, xVtx, yVtx, zVtx, errXVtx, errYVtx, true, false); } - static bool extrapToVertexWithoutBranson(TrackParam* trackParam, double zVtx) + static bool extrapToVertexWithoutBranson(TrackParam& trackParam, double zVtx) { /// Extrapolate track parameters to vertex, corrected for energy loss effects only /// Add dispersion due to multiple scattering and energy loss fluctuation to parameter covariances return extrapToVertex(trackParam, 0., 0., zVtx, 0., 0., false, true); } - static bool extrapToVertexUncorrected(TrackParam* trackParam, double zVtx) + static bool extrapToVertexUncorrected(TrackParam& trackParam, double zVtx) { /// Extrapolate track parameters to vertex without multiple scattering and energy loss corrections /// Add dispersion due to multiple scattering to parameter covariances return extrapToVertex(trackParam, 0., 0., zVtx, 0., 0., false, false); } + static bool extrapToMID(TrackParam& trackParam); + static double getMCSAngle2(const TrackParam& param, double dZ, double x0); - static void addMCSEffect(TrackParam* trackParam, double dZ, double x0); + static void addMCSEffect(TrackParam& trackParam, double dZ, double x0); static void printNCalls(); private: - static bool extrapToVertex(TrackParam* trackParam, double xVtx, double yVtx, double zVtx, + static bool extrapToVertex(TrackParam& trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, bool correctForMCS, bool correctForEnergyLoss); static bool getAbsorberCorrectionParam(double trackXYZIn[3], double trackXYZOut[3], double pTotal, double& pathLength, double& f0, double& f1, double& f2, double& meanRho, double& totalELoss, double& sigmaELoss2); - static void addMCSEffectInAbsorber(TrackParam* param, double signedPathLength, double f0, double f1, double f2); + static void addMCSEffectInAbsorber(TrackParam& param, double signedPathLength, double f0, double f1, double f2); static double betheBloch(double pTotal, double pathLength, double rho, double atomicZ, double atomicZoverA); static double energyLossFluctuation(double pTotal, double pathLength, double rho, double atomicZoverA); - static bool correctMCSEffectInAbsorber(TrackParam* param, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, + static bool correctMCSEffectInAbsorber(TrackParam& param, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, double absZBeg, double pathLength, double f0, double f1, double f2); - static void correctELossEffectInAbsorber(TrackParam* param, double eLoss, double sigmaELoss2); + static void correctELossEffectInAbsorber(TrackParam& param, double eLoss, double sigmaELoss2); static void cov2CovP(const TMatrixD& param, TMatrixD& cov); static void covP2Cov(const TMatrixD& param, TMatrixD& covP); - static void convertTrackParamForExtrap(TrackParam* trackParam, double forwardBackward, double* v3); - static void recoverTrackParam(double* v3, double Charge, TrackParam* trackParam); + static void convertTrackParamForExtrap(TrackParam& trackParam, double forwardBackward, double* v3); + static void recoverTrackParam(double* v3, double Charge, TrackParam& trackParam); - static bool extrapToZRungekutta(TrackParam* trackParam, double zEnd); - static bool extrapToZRungekuttaV2(TrackParam* trackParam, double zEnd); + static bool extrapToZRungekutta(TrackParam& trackParam, double zEnd); + static bool extrapToZRungekuttaV2(TrackParam& trackParam, double zEnd); static bool extrapOneStepRungekutta(double charge, double step, const double* vect, double* vout); static constexpr double SMuMass = 0.105658; ///< Muon mass (GeV/c2) @@ -125,6 +128,12 @@ class TrackExtrap /// Most probable value (GeV/c) of muon momentum in bending plane (used when B = 0) /// Needed to get some "reasonable" corrections for MCS and E loss even if B = 0 static constexpr double SMostProbBendingMomentum = 2.; + static constexpr double SMuonFilterZBeg = -1471.; ///< Position of the begining of the muon filter (cm) + static constexpr double SMuonFilterThickness = 120.; ///< Thickness of the muon filter (cm) + /// Position of the end of the muon filter (cm) + static constexpr double SMuonFilterZEnd = SMuonFilterZBeg - SMuonFilterThickness; + static constexpr double SMuonFilterX0 = 1.76; ///< Radiation length of the muon filter (cm) + static constexpr double SMIDZ = -1603.5; ///< Position of the first MID chamber (cm) static bool sExtrapV2; ///< switch to Runge-Kutta extrapolation v2 diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h index 6970810810665..dab59c5a5b966 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,9 +50,6 @@ class TrackFinder const std::list<Track>& findTracks(const std::unordered_map<int, std::list<Cluster>>& clusters); - /// set the flag to try to find more track candidates starting from 1 cluster in each of station (1..) 4 and 5 - void findMoreTrackCandidates(bool moreCandidates) { mMoreCandidates = moreCandidates; } - /// set the debug level defining the verbosity void debug(int debugLevel) { mDebugLevel = debugLevel; } @@ -80,6 +78,8 @@ class TrackFinder void removeConnectedTracks(int stMin, int stMax); + void refineTracks(); + void finalize(); void createTrack(const Cluster& cl1, const Cluster& cl2); @@ -113,25 +113,17 @@ class TrackFinder /// return the chamber to which this plane belong to int getChamberId(int plane) { return (plane < 8) ? plane / 2 : 4 + (plane - 8) / 4; } - /// sigma cut to select clusters (local chi2) and tracks (global chi2) during tracking - static constexpr double SSigmaCutForTracking = 5.; - /// sigma cut to select clusters (local chi2) and tracks (global chi2) during improvement - static constexpr double SSigmaCutForImprovement = 4.; ///< maximum distance to the track to search for compatible cluster(s) in non bending direction static constexpr double SMaxNonBendingDistanceToTrack = 1.; ///< maximum distance to the track to search for compatible cluster(s) in bending direction static constexpr double SMaxBendingDistanceToTrack = 1.; - static constexpr double SNonBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in non bending plane - static constexpr double SBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in bending plane - static constexpr double SMinBendingMomentum = 0.8; ///< minimum value (GeV/c) of momentum in bending plane + static constexpr double SMinBendingMomentum = 0.8; ///< minimum value (GeV/c) of momentum in bending plane /// z position of the chambers - static constexpr float SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, - -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; + static constexpr double SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, + -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; /// default chamber thickness in X0 for reconstruction static constexpr double SChamberThicknessInX0[10] = {0.065, 0.065, 0.075, 0.075, 0.035, 0.035, 0.035, 0.035, 0.035, 0.035}; - /// if true, at least one cluster in the station is requested to validate the track - static constexpr bool SRequestStation[5] = {true, true, true, true, true}; static constexpr int SNDE[10] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; ///< number of DE per chamber TrackFitter mTrackFitter{}; /// track fitter @@ -140,9 +132,13 @@ class TrackFinder std::list<Track> mTracks{}; ///< list of reconstructed tracks - double mMaxMCSAngle2[10]{}; ///< maximum angle dispersion due to MCS + double mChamberResolutionX2 = 0.; ///< chamber resolution square (cm^2) in x direction + double mChamberResolutionY2 = 0.; ///< chamber resolution square (cm^2) in y direction + double mBendingVertexDispersion2 = 0.; ///< vertex dispersion square (cm^2) in y direction + double mMaxChi2ForTracking = 0.; ///< maximum chi2 to accept a cluster candidate during tracking + double mMaxChi2ForImprovement = 0.; ///< maximum chi2 to accept a cluster candidate during improvement - bool mMoreCandidates = false; ///< try to find more track candidates starting from 1 cluster in each of station (1..) 4 and 5 + double mMaxMCSAngle2[10]{}; ///< maximum angle dispersion due to MCS int mDebugLevel = 0; ///< debug level defining the verbosity @@ -155,6 +151,7 @@ class TrackFinder std::chrono::duration<double> mTimeFollowTracks{}; ///< timer std::chrono::duration<double> mTimeImproveTracks{}; ///< timer std::chrono::duration<double> mTimeCleanTracks{}; ///< timer + std::chrono::duration<double> mTimeRefineTracks{}; ///< timer }; } // namespace mch diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h index f2c412c65d0a4..cb7469873f976 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,9 +43,6 @@ class TrackFinderOriginal void init(float l3Current, float dipoleCurrent); const std::list<Track>& findTracks(const std::array<std::list<Cluster>, 10>* clusters); - /// set the flag to try to find more track candidates starting from 1 cluster in each of station (1..) 4 and 5 - void findMoreTrackCandidates(bool moreCandidates) { mMoreCandidates = moreCandidates; } - /// set the debug level defining the verbosity void debug(int debugLevel) { mDebugLevel = debugLevel; } @@ -70,6 +68,7 @@ class TrackFinderOriginal std::list<Track>::iterator recoverTrack(std::list<Track>::iterator& itTrack, int nextStation); bool completeTracks(); void improveTracks(); + void refineTracks(); void finalize(); uint8_t requestedStationMask() const; int getTrackIndex(const std::list<Track>::iterator& itCurrentTrack) const; @@ -78,34 +77,30 @@ class TrackFinderOriginal template <class... Args> void print(Args... args) const; - /// sigma cut to select clusters (local chi2) and tracks (global chi2) during tracking - static constexpr double SSigmaCutForTracking = 5.; - /// sigma cut to select clusters (local chi2) and tracks (global chi2) during improvement - static constexpr double SSigmaCutForImprovement = 4.; - ///< maximum distance to the track to search for compatible cluster(s) in non bending direction + /// maximum distance to the track to search for compatible cluster(s) in non bending direction static constexpr double SMaxNonBendingDistanceToTrack = 1.; - ///< maximum distance to the track to search for compatible cluster(s) in bending direction + /// maximum distance to the track to search for compatible cluster(s) in bending direction static constexpr double SMaxBendingDistanceToTrack = 1.; - static constexpr double SNonBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in non bending plane - static constexpr double SBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in bending plane - static constexpr double SMinBendingMomentum = 0.8; ///< minimum value (GeV/c) of momentum in bending plane + static constexpr double SMinBendingMomentum = 0.8; ///< minimum value (GeV/c) of momentum in bending plane /// z position of the chambers - static constexpr float SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, - -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; + static constexpr double SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, + -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; /// default chamber thickness in X0 for reconstruction static constexpr double SChamberThicknessInX0[10] = {0.065, 0.065, 0.075, 0.075, 0.035, 0.035, 0.035, 0.035, 0.035, 0.035}; - ///< if true, at least one cluster in the station is requested to validate the track - static constexpr bool SRequestStation[5] = {true, true, true, true, true}; TrackFitter mTrackFitter{}; /// track fitter const std::array<std::list<Cluster>, 10>* mClusters = nullptr; ///< pointer to the lists of clusters std::list<Track> mTracks{}; ///< list of reconstructed tracks - double mMaxMCSAngle2[10]{}; ///< maximum angle dispersion due to MCS + double mChamberResolutionX2 = 0.; ///< chamber resolution square (cm^2) in x direction + double mChamberResolutionY2 = 0.; ///< chamber resolution square (cm^2) in y direction + double mBendingVertexDispersion2 = 0.; ///< vertex dispersion square (cm^2) in y direction + double mMaxChi2ForTracking = 0.; ///< maximum chi2 to accept a cluster candidate during tracking + double mMaxChi2ForImprovement = 0.; ///< maximum chi2 to accept a cluster candidate during improvement - bool mMoreCandidates = false; ///< try to find more track candidates starting from 1 cluster in each of station (1..) 4 and 5 + double mMaxMCSAngle2[10]{}; ///< maximum angle dispersion due to MCS int mDebugLevel = 0; ///< debug level defining the verbosity @@ -119,6 +114,7 @@ class TrackFinderOriginal std::chrono::duration<double> mTimeCompleteTracks{}; ///< timer std::chrono::duration<double> mTimeImproveTracks{}; ///< timer std::chrono::duration<double> mTimeCleanTracks{}; ///< timer + std::chrono::duration<double> mTimeRefineTracks{}; ///< timer }; } // namespace mch diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFitter.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFitter.h index 1f95cd4d25385..a494e24d75539 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFitter.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFitter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,11 +40,21 @@ class TrackFitter void initField(float l3Current, float dipoleCurrent); + /// Set the vertex dispersion in y direction used for the track covariance seed + void setBendingVertexDispersion(double ey) { mBendingVertexDispersion2 = ey * ey; } + /// Enable/disable the smoother (and the saving of related parameters) void smoothTracks(bool smooth) { mSmooth = smooth; } /// Return the smoother enable/disable flag bool isSmootherEnabled() { return mSmooth; } + /// Use the own resolution of each cluster during the fit (default) + void useClusterResolution() { mUseChamberResolution = false; } + /// Use the chamber resolution instead of cluster resolution during the fit + void useChamberResolution() { mUseChamberResolution = true; } + // Set the chamber resolution in x and y directions + void setChamberResolution(double ex, double ey); + void fit(Track& track, bool smooth = true, bool finalize = true, std::list<TrackParam>::reverse_iterator* itStartingParam = nullptr); @@ -58,18 +69,31 @@ class TrackFitter void smoothTrack(Track& track, bool finalize); void runSmoother(const TrackParam& previousParam, TrackParam& param); - static constexpr double SMaxChi2 = 2.e10; ///< maximum chi2 above which the track can be considered as abnormal - static constexpr double SBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in bending plane + static constexpr double SMaxChi2 = 2.e10; ///< maximum chi2 above which the track can be considered as abnormal /// z position of the chambers - static constexpr float SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, - -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; + static constexpr double SDefaultChamberZ[10] = {-526.16, -545.24, -676.4, -695.4, -967.5, + -998.5, -1276.5, -1307.5, -1406.6, -1437.6}; /// default chamber thickness in X0 for reconstruction static constexpr double SChamberThicknessInX0[10] = {0.065, 0.065, 0.075, 0.075, 0.035, 0.035, 0.035, 0.035, 0.035, 0.035}; + double mBendingVertexDispersion2 = 4900.; ///< vertex dispersion square (cm^2) in y direction + bool mSmooth = false; ///< switch ON/OFF the smoother + + bool mUseChamberResolution = false; ///< switch between using chamber or cluster resolution + double mChamberResolutionX2 = 0.04; ///< chamber resolution square in x direction + double mChamberResolutionY2 = 0.04; ///< chamber resolution square in y direction }; +//_________________________________________________________________________________________________ +inline void TrackFitter::setChamberResolution(double ex, double ey) +{ + /// Set the chamber resolution in x and y directions + mChamberResolutionX2 = ex * ex; + mChamberResolutionY2 = ey * ey; +} + } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackParam.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackParam.h index 9415f238b54a6..ceaed6dfa9e84 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackParam.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackerParam.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackerParam.h new file mode 100644 index 0000000000000..d85b470989ad8 --- /dev/null +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackerParam.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackerParam.h +/// \brief Configurable parameters for MCH tracking +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MCH_TRACKERPARAM_H_ +#define ALICEO2_MCH_TRACKERPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace mch +{ + +/// Configurable parameters for MCH tracking +struct TrackerParam : public o2::conf::ConfigurableParamHelper<TrackerParam> { + + double chamberResolutionX = 0.2; ///< chamber resolution (cm) in x used as cluster resolution during tracking + double chamberResolutionY = 0.2; ///< chamber resolution (cm) in y used as cluster resolution during tracking + + double sigmaCutForTracking = 5.; ///< to select clusters (local chi2) and tracks (global chi2) during tracking + double sigmaCutForImprovement = 4.; ///< to select clusters (local chi2) and tracks (global chi2) during improvement + + double nonBendingVertexDispersion = 70.; ///< vertex dispersion (cm) in non bending plane + double bendingVertexDispersion = 70.; ///< vertex dispersion (cm) in bending plane + + /// if true, at least one cluster in the station is requested to validate the track + bool requestStation[5] = {true, true, true, true, true}; + + bool moreCandidates = false; ///< find more track candidates starting from 1 cluster in each of station (1..) 4 and 5 + bool refineTracks = true; ///< refine the tracks in the end using cluster resolution + + O2ParamDef(TrackerParam, "MCHTracking"); +}; + +} // namespace mch +} // end namespace o2 + +#endif // ALICEO2_MCH_TRACKERPARAM_H_ diff --git a/Detectors/MUON/MCH/Tracking/src/Cluster.cxx b/Detectors/MUON/MCH/Tracking/src/Cluster.cxx index 45068974dfd4b..672065f9cd2bf 100644 --- a/Detectors/MUON/MCH/Tracking/src/Cluster.cxx +++ b/Detectors/MUON/MCH/Tracking/src/Cluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Tracking/src/MCHTrackingLinkDef.h b/Detectors/MUON/MCH/Tracking/src/MCHTrackingLinkDef.h new file mode 100644 index 0000000000000..21a3c5a8c71ee --- /dev/null +++ b/Detectors/MUON/MCH/Tracking/src/MCHTrackingLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::mch::TrackerParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mch::TrackerParam> + ; + +#endif diff --git a/Detectors/MUON/MCH/Tracking/src/Track.cxx b/Detectors/MUON/MCH/Tracking/src/Track.cxx index 2787cdc1c0fa3..10a16942b47d3 100644 --- a/Detectors/MUON/MCH/Tracking/src/Track.cxx +++ b/Detectors/MUON/MCH/Tracking/src/Track.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #include <iostream> -#include <FairMQLogger.h> +#include "Framework/Logger.h" namespace o2 { @@ -28,8 +29,7 @@ using namespace std; //__________________________________________________________________________ Track::Track(const Track& track) - : mParamAtVertex(track.mParamAtVertex), - mParamAtClusters(track.mParamAtClusters), + : mParamAtClusters(track.mParamAtClusters), mCurrentParam(nullptr), mCurrentChamber(-1), mConnected(track.mConnected), @@ -133,63 +133,61 @@ bool Track::isBetter(const Track& track) const } //__________________________________________________________________________ -void Track::tagRemovableClusters(uint8_t requestedStationMask) +void Track::tagRemovableClusters(uint8_t requestedStationMask, bool request2ChInSameSt45) { - /// Identify clusters that can be removed from the track, - /// with the only requirements to have at least 1 cluster per requested station - /// and at least 2 chambers over 4 in stations 4 & 5 that contain cluster(s) - - int previousCh(-1), previousSt(-1), nChHitInSt45(0); - TrackParam* previousParam(nullptr); + /// Identify clusters that can be removed from the track, with the requirement + /// to have enough chambers fired to fulfill the tracking criteria + // count the number of clusters in each chamber and the number of chambers fired on stations 4 and 5 + int nClusters[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; for (auto& param : *this) { + ++nClusters[param.getClusterPtr()->getChamberId()]; + } + int nChFiredInSt4 = (nClusters[6] > 0) ? 1 : 0; + if (nClusters[7] > 0) { + ++nChFiredInSt4; + } + int nChFiredInSt5 = (nClusters[8] > 0) ? 1 : 0; + if (nClusters[9] > 0) { + ++nChFiredInSt5; + } + int nChFiredInSt45 = nChFiredInSt4 + nChFiredInSt5; - int currentCh = param.getClusterPtr()->getChamberId(); - int currentSt = currentCh / 2; - - // set the cluster as removable if the station is not requested or if it is not alone in the station - if (((1 << currentSt) & requestedStationMask) == 0) { - param.setRemovable(true); - } else if (currentSt == previousSt) { - previousParam->setRemovable(true); - param.setRemovable(true); - } else { - param.setRemovable(false); - previousSt = currentSt; - previousParam = ¶m; - } + bool removable[10] = {false, false, false, false, false, false, false, false, false, false}; - // count the number of chambers in station 4 & 5 that contain cluster(s) - if (currentCh > 5 && currentCh != previousCh) { - ++nChHitInSt45; - previousCh = currentCh; + // for station 1, 2 and 3, there must be at least one cluster per requested station + for (int iCh = 0; iCh < 6; iCh += 2) { + if (nClusters[iCh] + nClusters[iCh + 1] > 1 || (requestedStationMask & (1 << (iCh / 2))) == 0) { + removable[iCh] = removable[iCh + 1] = true; } } - // if there are less than 3 chambers containing cluster(s) in station 4 & 5 - if (nChHitInSt45 < 3) { - - previousCh = -1; - previousParam = nullptr; - - for (auto itParam = this->rbegin(); itParam != this->rend(); ++itParam) { - - int currentCh = itParam->getClusterPtr()->getChamberId(); - - if (currentCh < 6) { - break; - } - - // set the cluster as not removable unless it is not alone in the chamber - if (currentCh == previousCh) { - previousParam->setRemovable(true); - itParam->setRemovable(true); - } else { - itParam->setRemovable(false); - previousCh = currentCh; - previousParam = &*itParam; - } + // for station 4 and 5, there must be at least one cluster per requested station and + // at least 2 chambers fired (on the same station or not depending on the requirement) + if (nChFiredInSt45 == 4) { + removable[6] = removable[7] = removable[8] = removable[9] = true; + } else if (nChFiredInSt45 == 3) { + if (nChFiredInSt4 == 2 && request2ChInSameSt45) { + removable[6] = (nClusters[6] > 1); + removable[7] = (nClusters[7] > 1); + } else if (nClusters[6] + nClusters[7] > 1 || (requestedStationMask & 0x8) == 0) { + removable[6] = removable[7] = true; } + if (nChFiredInSt5 == 2 && request2ChInSameSt45) { + removable[8] = (nClusters[8] > 1); + removable[9] = (nClusters[9] > 1); + } else if (nClusters[8] + nClusters[9] > 1 || (requestedStationMask & 0x10) == 0) { + removable[8] = removable[9] = true; + } + } else { + for (int iCh = 6; iCh < 10; ++iCh) { + removable[iCh] = (nClusters[iCh] > 1); + } + } + + // tag the removable clusters + for (auto& param : *this) { + param.setRemovable(removable[param.getClusterPtr()->getChamberId()]); } } diff --git a/Detectors/MUON/MCH/Tracking/src/TrackExtrap.cxx b/Detectors/MUON/MCH/Tracking/src/TrackExtrap.cxx index 9fe21ca5a455f..d82e2e6548c17 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackExtrap.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackExtrap.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include <TGeoShape.h> #include <TMath.h> -#include <FairMQLogger.h> +#include "Framework/Logger.h" #include "MCHTracking/TrackParam.h" @@ -83,34 +84,34 @@ double TrackExtrap::getBendingMomentumFromImpactParam(double impactParam) } //__________________________________________________________________________ -void TrackExtrap::linearExtrapToZ(TrackParam* trackParam, double zEnd) +void TrackExtrap::linearExtrapToZ(TrackParam& trackParam, double zEnd) { /// Track parameters linearly extrapolated to the plane at "zEnd". /// On return, results from the extrapolation are updated in trackParam. - if (trackParam->getZ() == zEnd) { + if (trackParam.getZ() == zEnd) { return; // nothing to be done if same z } // Compute track parameters - double dZ = zEnd - trackParam->getZ(); - trackParam->setNonBendingCoor(trackParam->getNonBendingCoor() + trackParam->getNonBendingSlope() * dZ); - trackParam->setBendingCoor(trackParam->getBendingCoor() + trackParam->getBendingSlope() * dZ); - trackParam->setZ(zEnd); + double dZ = zEnd - trackParam.getZ(); + trackParam.setNonBendingCoor(trackParam.getNonBendingCoor() + trackParam.getNonBendingSlope() * dZ); + trackParam.setBendingCoor(trackParam.getBendingCoor() + trackParam.getBendingSlope() * dZ); + trackParam.setZ(zEnd); } //__________________________________________________________________________ -void TrackExtrap::linearExtrapToZCov(TrackParam* trackParam, double zEnd, bool updatePropagator) +void TrackExtrap::linearExtrapToZCov(TrackParam& trackParam, double zEnd, bool updatePropagator) { /// Track parameters and their covariances linearly extrapolated to the plane at "zEnd". /// On return, results from the extrapolation are updated in trackParam. - if (trackParam->getZ() == zEnd) { + if (trackParam.getZ() == zEnd) { return; // nothing to be done if same z } // No need to propagate the covariance matrix if it does not exist - if (!trackParam->hasCovariances()) { + if (!trackParam.hasCovariances()) { LOG(WARNING) << "Covariance matrix does not exist"; // Extrapolate linearly track parameters to "zEnd" linearExtrapToZ(trackParam, zEnd); @@ -118,10 +119,10 @@ void TrackExtrap::linearExtrapToZCov(TrackParam* trackParam, double zEnd, bool u } // Compute track parameters - double dZ = zEnd - trackParam->getZ(); - trackParam->setNonBendingCoor(trackParam->getNonBendingCoor() + trackParam->getNonBendingSlope() * dZ); - trackParam->setBendingCoor(trackParam->getBendingCoor() + trackParam->getBendingSlope() * dZ); - trackParam->setZ(zEnd); + double dZ = zEnd - trackParam.getZ(); + trackParam.setNonBendingCoor(trackParam.getNonBendingCoor() + trackParam.getNonBendingSlope() * dZ); + trackParam.setBendingCoor(trackParam.getBendingCoor() + trackParam.getBendingSlope() * dZ); + trackParam.setZ(zEnd); // Calculate the jacobian related to the track parameters linear extrapolation to "zEnd" TMatrixD jacob(5, 5); @@ -130,18 +131,18 @@ void TrackExtrap::linearExtrapToZCov(TrackParam* trackParam, double zEnd, bool u jacob(2, 3) = dZ; // Extrapolate track parameter covariances to "zEnd" - TMatrixD tmp(trackParam->getCovariances(), TMatrixD::kMultTranspose, jacob); + TMatrixD tmp(trackParam.getCovariances(), TMatrixD::kMultTranspose, jacob); TMatrixD tmp2(jacob, TMatrixD::kMult, tmp); - trackParam->setCovariances(tmp2); + trackParam.setCovariances(tmp2); // Update the propagator if required if (updatePropagator) { - trackParam->updatePropagator(jacob); + trackParam.updatePropagator(jacob); } } //__________________________________________________________________________ -bool TrackExtrap::extrapToZ(TrackParam* trackParam, double zEnd) +bool TrackExtrap::extrapToZ(TrackParam& trackParam, double zEnd) { /// Interface to track parameter extrapolation to the plane at "Z" using Helix or Rungekutta algorithm. /// On return, the track parameters resulting from the extrapolation are updated in trackParam. @@ -156,14 +157,14 @@ bool TrackExtrap::extrapToZ(TrackParam* trackParam, double zEnd) } //__________________________________________________________________________ -bool TrackExtrap::extrapToZCov(TrackParam* trackParam, double zEnd, bool updatePropagator) +bool TrackExtrap::extrapToZCov(TrackParam& trackParam, double zEnd, bool updatePropagator) { /// Track parameters and their covariances extrapolated to the plane at "zEnd". /// On return, results from the extrapolation are updated in trackParam. ++sNCallExtrapToZCov; - if (trackParam->getZ() == zEnd) { + if (trackParam.getZ() == zEnd) { return true; // nothing to be done if same z } @@ -173,19 +174,19 @@ bool TrackExtrap::extrapToZCov(TrackParam* trackParam, double zEnd, bool updateP } // No need to propagate the covariance matrix if it does not exist - if (!trackParam->hasCovariances()) { + if (!trackParam.hasCovariances()) { LOG(WARNING) << "Covariance matrix does not exist"; // Extrapolate track parameters to "zEnd" return extrapToZ(trackParam, zEnd); } // Save the actual track parameters - TrackParam trackParamSave(*trackParam); + TrackParam trackParamSave(trackParam); TMatrixD paramSave(trackParamSave.getParameters()); double zBegin = trackParamSave.getZ(); // Get reference to the parameter covariance matrix - const TMatrixD& kParamCov = trackParam->getCovariances(); + const TMatrixD& kParamCov = trackParam.getCovariances(); // Extrapolate track parameters to "zEnd" // Do not update the covariance matrix if the extrapolation failed @@ -194,7 +195,7 @@ bool TrackExtrap::extrapToZCov(TrackParam* trackParam, double zEnd, bool updateP } // Get reference to the extrapolated parameters - const TMatrixD& extrapParam = trackParam->getParameters(); + const TMatrixD& extrapParam = trackParam.getParameters(); // Calculate the jacobian related to the track parameters extrapolation to "zEnd" TMatrixD jacob(5, 5); @@ -223,7 +224,7 @@ bool TrackExtrap::extrapToZCov(TrackParam* trackParam, double zEnd, bool updateP trackParamSave.setZ(zBegin); // Extrapolate new track parameters to "zEnd" - if (!extrapToZ(&trackParamSave, zEnd)) { + if (!extrapToZ(trackParamSave, zEnd)) { LOG(WARNING) << "Bad covariance matrix"; return false; } @@ -237,18 +238,44 @@ bool TrackExtrap::extrapToZCov(TrackParam* trackParam, double zEnd, bool updateP // Extrapolate track parameter covariances to "zEnd" TMatrixD tmp(kParamCov, TMatrixD::kMultTranspose, jacob); TMatrixD tmp2(jacob, TMatrixD::kMult, tmp); - trackParam->setCovariances(tmp2); + trackParam.setCovariances(tmp2); // Update the propagator if required if (updatePropagator) { - trackParam->updatePropagator(jacob); + trackParam.updatePropagator(jacob); } return true; } //__________________________________________________________________________ -bool TrackExtrap::extrapToVertex(TrackParam* trackParam, double xVtx, double yVtx, double zVtx, +bool TrackExtrap::extrapToMID(TrackParam& trackParam) +{ + /// Extrapolate the track parameters and their covariances to the z position of the first MID chamber + /// Add to the track parameter covariances the effects of multiple Coulomb scattering in the muon filter + + if (trackParam.getZ() == SMIDZ) { + return true; // nothing to be done + } + + // check the track position with respect to the muon filter (spectro z<0) + if (trackParam.getZ() < SMuonFilterZBeg) { + LOG(WARNING) << "The track already passed the beginning of the muon filter"; + return false; + } + + // propagate through the muon filter and add MCS effets + if (!extrapToZCov(trackParam, SMuonFilterZEnd)) { + return false; + } + addMCSEffect(trackParam, -SMuonFilterThickness, SMuonFilterX0); + + // propagate to the first MID chamber + return extrapToZCov(trackParam, SMIDZ); +} + +//__________________________________________________________________________ +bool TrackExtrap::extrapToVertex(TrackParam& trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, bool correctForMCS, bool correctForEnergyLoss) { /// Main method for extrapolation to the vertex: @@ -259,7 +286,7 @@ bool TrackExtrap::extrapToVertex(TrackParam* trackParam, double xVtx, double yVt /// if correctForEnergyLoss=true: correct parameters for energy loss and add energy loss fluctuation to covariances /// if correctForEnergyLoss=false: do nothing about energy loss - if (trackParam->getZ() == zVtx) { + if (trackParam.getZ() == zVtx) { return true; // nothing to be done if already at vertex } @@ -275,42 +302,42 @@ bool TrackExtrap::extrapToVertex(TrackParam* trackParam, double xVtx, double yVt } // Check the track position with respect to the vertex and the absorber (spectro z<0) - if (trackParam->getZ() > SAbsZEnd) { - if (trackParam->getZ() > zVtx) { - LOG(WARNING) << "Starting Z (" << trackParam->getZ() << ") upstream the vertex (zVtx = " << zVtx << ")"; + if (trackParam.getZ() > SAbsZEnd) { + if (trackParam.getZ() > zVtx) { + LOG(WARNING) << "Starting Z (" << trackParam.getZ() << ") upstream the vertex (zVtx = " << zVtx << ")"; return false; - } else if (trackParam->getZ() > SAbsZBeg) { - LOG(WARNING) << "Starting Z (" << trackParam->getZ() << ") upstream the front absorber (zAbsorberBegin = " << SAbsZBeg << ")"; + } else if (trackParam.getZ() > SAbsZBeg) { + LOG(WARNING) << "Starting Z (" << trackParam.getZ() << ") upstream the front absorber (zAbsorberBegin = " << SAbsZBeg << ")"; return false; } else { - LOG(WARNING) << "Starting Z (" << trackParam->getZ() << ") inside the front absorber (" << SAbsZBeg << ", " << SAbsZEnd << ")"; + LOG(WARNING) << "Starting Z (" << trackParam.getZ() << ") inside the front absorber (" << SAbsZBeg << ", " << SAbsZEnd << ")"; return false; } } // Extrapolate track parameters (and covariances if any) to the end of the absorber - if ((trackParam->hasCovariances() && !extrapToZCov(trackParam, SAbsZEnd)) || - (!trackParam->hasCovariances() && !extrapToZ(trackParam, SAbsZEnd))) { + if ((trackParam.hasCovariances() && !extrapToZCov(trackParam, SAbsZEnd)) || + (!trackParam.hasCovariances() && !extrapToZ(trackParam, SAbsZEnd))) { return false; } // Get absorber correction parameters assuming linear propagation in absorber - double trackXYZOut[3] = {trackParam->getNonBendingCoor(), trackParam->getBendingCoor(), trackParam->getZ()}; + double trackXYZOut[3] = {trackParam.getNonBendingCoor(), trackParam.getBendingCoor(), trackParam.getZ()}; double trackXYZIn[3] = {0., 0., 0.}; if (correctForMCS) { // assume linear propagation to the vertex trackXYZIn[2] = SAbsZBeg; trackXYZIn[0] = trackXYZOut[0] + (xVtx - trackXYZOut[0]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]); trackXYZIn[1] = trackXYZOut[1] + (yVtx - trackXYZOut[1]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]); } else { // or standard propagation without vertex constraint - TrackParam trackParamIn(*trackParam); - if (!extrapToZ(&trackParamIn, SAbsZBeg)) { + TrackParam trackParamIn(trackParam); + if (!extrapToZ(trackParamIn, SAbsZBeg)) { return false; } trackXYZIn[0] = trackParamIn.getNonBendingCoor(); trackXYZIn[1] = trackParamIn.getBendingCoor(); trackXYZIn[2] = trackParamIn.getZ(); } - double pTot = trackParam->p(); + double pTot = trackParam.p(); double pathLength(0.), f0(0.), f1(0.), f2(0.), meanRho(0.), totalELoss(0.), sigmaELoss2(0.); if (!getAbsorberCorrectionParam(trackXYZIn, trackXYZOut, pTot, pathLength, f0, f1, f2, meanRho, totalELoss, sigmaELoss2)) { return false; @@ -483,7 +510,7 @@ double TrackExtrap::getMCSAngle2(const TrackParam& param, double dZ, double x0) } //__________________________________________________________________________ -void TrackExtrap::addMCSEffect(TrackParam* trackParam, double dZ, double x0) +void TrackExtrap::addMCSEffect(TrackParam& trackParam, double dZ, double x0) { /// Add to the track parameter covariances the effects of multiple Coulomb scattering /// through a material of thickness "abs(dZ)" and of radiation length "x0" @@ -491,9 +518,9 @@ void TrackExtrap::addMCSEffect(TrackParam* trackParam, double dZ, double x0) /// dZ = zOut - zIn (sign is important) and "param" is assumed to be given zOut. /// If x0 <= 0., assume dZ = pathLength/x0 and consider the material thickness as negligible. - double bendingSlope = trackParam->getBendingSlope(); - double nonBendingSlope = trackParam->getNonBendingSlope(); - double inverseBendingMomentum = trackParam->getInverseBendingMomentum(); + double bendingSlope = trackParam.getBendingSlope(); + double nonBendingSlope = trackParam.getNonBendingSlope(); + double inverseBendingMomentum = trackParam.getInverseBendingMomentum(); double inverseTotalMomentum2 = inverseBendingMomentum * inverseBendingMomentum * (1.0 + bendingSlope * bendingSlope) / (1.0 + bendingSlope * bendingSlope + nonBendingSlope * nonBendingSlope); // Path length in the material @@ -510,7 +537,7 @@ void TrackExtrap::addMCSEffect(TrackParam* trackParam, double dZ, double x0) double covCorrSlope = (x0 > 0.) ? signedPathLength * theta02 / 2. : 0.; // Set MCS covariance matrix - TMatrixD newParamCov(trackParam->getCovariances()); + TMatrixD newParamCov(trackParam.getCovariances()); // Non bending plane newParamCov(0, 0) += varCoor; newParamCov(0, 1) += covCorrSlope; @@ -543,19 +570,19 @@ void TrackExtrap::addMCSEffect(TrackParam* trackParam, double dZ, double x0) } // Set new covariances - trackParam->setCovariances(newParamCov); + trackParam.setCovariances(newParamCov); } //__________________________________________________________________________ -void TrackExtrap::addMCSEffectInAbsorber(TrackParam* param, double signedPathLength, double f0, double f1, double f2) +void TrackExtrap::addMCSEffectInAbsorber(TrackParam& param, double signedPathLength, double f0, double f1, double f2) { /// Add to the track parameter covariances the effects of multiple Coulomb scattering /// signedPathLength must have the sign of (zOut - zIn) where all other parameters are assumed to be given at zOut. // absorber related covariance parameters - double bendingSlope = param->getBendingSlope(); - double nonBendingSlope = param->getNonBendingSlope(); - double inverseBendingMomentum = param->getInverseBendingMomentum(); + double bendingSlope = param.getBendingSlope(); + double nonBendingSlope = param.getNonBendingSlope(); + double inverseBendingMomentum = param.getInverseBendingMomentum(); double alpha2 = 0.0136 * 0.0136 * inverseBendingMomentum * inverseBendingMomentum * (1.0 + bendingSlope * bendingSlope) / (1.0 + bendingSlope * bendingSlope + nonBendingSlope * nonBendingSlope); // velocity = 1 double pathLength = TMath::Abs(signedPathLength); @@ -564,7 +591,7 @@ void TrackExtrap::addMCSEffectInAbsorber(TrackParam* param, double signedPathLen double varSlop = alpha2 * f0; // Set MCS covariance matrix - TMatrixD newParamCov(param->getCovariances()); + TMatrixD newParamCov(param.getCovariances()); // Non bending plane newParamCov(0, 0) += varCoor; newParamCov(0, 1) += covCorrSlope; @@ -595,7 +622,7 @@ void TrackExtrap::addMCSEffectInAbsorber(TrackParam* param, double signedPathLen } // Set new covariances - param->setCovariances(newParamCov); + param.setCovariances(newParamCov); } //__________________________________________________________________________ @@ -648,7 +675,7 @@ double TrackExtrap::energyLossFluctuation(double pTotal, double pathLength, doub } //__________________________________________________________________________ -bool TrackExtrap::correctMCSEffectInAbsorber(TrackParam* param, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, +bool TrackExtrap::correctMCSEffectInAbsorber(TrackParam& param, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx, double absZBeg, double pathLength, double f0, double f1, double f2) { /// Correct parameters and corresponding covariances using Branson correction @@ -671,16 +698,16 @@ bool TrackExtrap::correctMCSEffectInAbsorber(TrackParam* param, double xVtx, dou // compute track parameters at vertex TMatrixD newParam(5, 1); newParam(0, 0) = xVtx; - newParam(1, 0) = (param->getNonBendingCoor() - xVtx) / (zB - zVtx); + newParam(1, 0) = (param.getNonBendingCoor() - xVtx) / (zB - zVtx); newParam(2, 0) = yVtx; - newParam(3, 0) = (param->getBendingCoor() - yVtx) / (zB - zVtx); - newParam(4, 0) = param->getCharge() / param->p() * + newParam(3, 0) = (param.getBendingCoor() - yVtx) / (zB - zVtx); + newParam(4, 0) = param.getCharge() / param.p() * TMath::Sqrt(1.0 + newParam(1, 0) * newParam(1, 0) + newParam(3, 0) * newParam(3, 0)) / TMath::Sqrt(1.0 + newParam(3, 0) * newParam(3, 0)); // Get covariances in (X, SlopeX, Y, SlopeY, q*PTot) coordinate system - TMatrixD paramCovP(param->getCovariances()); - cov2CovP(param->getParameters(), paramCovP); + TMatrixD paramCovP(param.getCovariances()); + cov2CovP(param.getParameters(), paramCovP); // Get the covariance matrix in the (XVtx, X, YVtx, Y, q*PTot) coordinate system TMatrixD paramCovVtx(5, 5); @@ -713,41 +740,41 @@ bool TrackExtrap::correctMCSEffectInAbsorber(TrackParam* param, double xVtx, dou covP2Cov(newParam, newParamCov); // Set parameters and covariances at vertex - param->setParameters(newParam); - param->setZ(zVtx); - param->setCovariances(newParamCov); + param.setParameters(newParam); + param.setZ(zVtx); + param.setCovariances(newParamCov); return true; } //__________________________________________________________________________ -void TrackExtrap::correctELossEffectInAbsorber(TrackParam* param, double eLoss, double sigmaELoss2) +void TrackExtrap::correctELossEffectInAbsorber(TrackParam& param, double eLoss, double sigmaELoss2) { /// Correct parameters for energy loss and add energy loss fluctuation effect to covariances // Get parameter covariances in (X, SlopeX, Y, SlopeY, q*PTot) coordinate system - TMatrixD newParamCov(param->getCovariances()); - cov2CovP(param->getParameters(), newParamCov); + TMatrixD newParamCov(param.getCovariances()); + cov2CovP(param.getParameters(), newParamCov); // Compute new parameters corrected for energy loss - double p = param->p(); + double p = param.p(); double e = TMath::Sqrt(p * p + SMuMass * SMuMass); double eCorr = e + eLoss; double pCorr = TMath::Sqrt(eCorr * eCorr - SMuMass * SMuMass); - double nonBendingSlope = param->getNonBendingSlope(); - double bendingSlope = param->getBendingSlope(); - param->setInverseBendingMomentum(param->getCharge() / pCorr * - TMath::Sqrt(1.0 + nonBendingSlope * nonBendingSlope + bendingSlope * bendingSlope) / - TMath::Sqrt(1.0 + bendingSlope * bendingSlope)); + double nonBendingSlope = param.getNonBendingSlope(); + double bendingSlope = param.getBendingSlope(); + param.setInverseBendingMomentum(param.getCharge() / pCorr * + TMath::Sqrt(1.0 + nonBendingSlope * nonBendingSlope + bendingSlope * bendingSlope) / + TMath::Sqrt(1.0 + bendingSlope * bendingSlope)); // Add effects of energy loss fluctuation to covariances newParamCov(4, 4) += eCorr * eCorr / pCorr / pCorr * sigmaELoss2; // Get new parameter covariances in (X, SlopeX, Y, SlopeY, q/Pyz) coordinate system - covP2Cov(param->getParameters(), newParamCov); + covP2Cov(param.getParameters(), newParamCov); // Set new parameter covariances - param->setCovariances(newParamCov); + param.setCovariances(newParamCov); } //__________________________________________________________________________ @@ -797,67 +824,67 @@ void TrackExtrap::covP2Cov(const TMatrixD& param, TMatrixD& covP) } //__________________________________________________________________________ -void TrackExtrap::convertTrackParamForExtrap(TrackParam* trackParam, double forwardBackward, double* v3) +void TrackExtrap::convertTrackParamForExtrap(TrackParam& trackParam, double forwardBackward, double* v3) { /// Set vector of Geant3 parameters pointed to by "v3" from track parameters in trackParam. /// Since TrackParam is only geometry, one uses "forwardBackward" /// to know whether the particle is going forward (+1) or backward (-1). - v3[0] = trackParam->getNonBendingCoor(); // X - v3[1] = trackParam->getBendingCoor(); // Y - v3[2] = trackParam->getZ(); // Z - double pYZ = TMath::Abs(1.0 / trackParam->getInverseBendingMomentum()); - double pZ = pYZ / TMath::Sqrt(1.0 + trackParam->getBendingSlope() * trackParam->getBendingSlope()); - v3[6] = TMath::Sqrt(pYZ * pYZ + pZ * pZ * trackParam->getNonBendingSlope() * trackParam->getNonBendingSlope()); // P - v3[5] = -forwardBackward * pZ / v3[6]; // PZ/P spectro. z<0 - v3[3] = trackParam->getNonBendingSlope() * v3[5]; // PX/P - v3[4] = trackParam->getBendingSlope() * v3[5]; // PY/P + v3[0] = trackParam.getNonBendingCoor(); // X + v3[1] = trackParam.getBendingCoor(); // Y + v3[2] = trackParam.getZ(); // Z + double pYZ = TMath::Abs(1.0 / trackParam.getInverseBendingMomentum()); + double pZ = pYZ / TMath::Sqrt(1.0 + trackParam.getBendingSlope() * trackParam.getBendingSlope()); + v3[6] = TMath::Sqrt(pYZ * pYZ + pZ * pZ * trackParam.getNonBendingSlope() * trackParam.getNonBendingSlope()); // P + v3[5] = -forwardBackward * pZ / v3[6]; // PZ/P spectro. z<0 + v3[3] = trackParam.getNonBendingSlope() * v3[5]; // PX/P + v3[4] = trackParam.getBendingSlope() * v3[5]; // PY/P } //__________________________________________________________________________ -void TrackExtrap::recoverTrackParam(double* v3, double charge, TrackParam* trackParam) +void TrackExtrap::recoverTrackParam(double* v3, double charge, TrackParam& trackParam) { /// Set track parameters in trackParam from Geant3 parameters pointed to by "v3", /// assumed to be calculated for forward motion in Z. /// "InverseBendingMomentum" is signed with "charge". - trackParam->setNonBendingCoor(v3[0]); // X - trackParam->setBendingCoor(v3[1]); // Y - trackParam->setZ(v3[2]); // Z + trackParam.setNonBendingCoor(v3[0]); // X + trackParam.setBendingCoor(v3[1]); // Y + trackParam.setZ(v3[2]); // Z double pYZ = v3[6] * TMath::Sqrt((1. - v3[3]) * (1. + v3[3])); - trackParam->setInverseBendingMomentum(charge / pYZ); - trackParam->setBendingSlope(v3[4] / v3[5]); - trackParam->setNonBendingSlope(v3[3] / v3[5]); + trackParam.setInverseBendingMomentum(charge / pYZ); + trackParam.setBendingSlope(v3[4] / v3[5]); + trackParam.setNonBendingSlope(v3[3] / v3[5]); } //__________________________________________________________________________ -bool TrackExtrap::extrapToZRungekutta(TrackParam* trackParam, double zEnd) +bool TrackExtrap::extrapToZRungekutta(TrackParam& trackParam, double zEnd) { /// Track parameter extrapolation to the plane at "Z" using Rungekutta algorithm. /// On return, the track parameters resulting from the extrapolation are updated in trackParam. /// Return false in case of failure and let the trackParam as they were when that happened - if (trackParam->getZ() == zEnd) { + if (trackParam.getZ() == zEnd) { return true; // nothing to be done if same Z } double forwardBackward; // +1 if forward, -1 if backward - if (zEnd < trackParam->getZ()) { + if (zEnd < trackParam.getZ()) { forwardBackward = 1.0; // spectro. z<0 } else { forwardBackward = -1.0; } // sign of charge (sign of fInverseBendingMomentum if forward motion) // must be changed if backward extrapolation - double chargeExtrap = forwardBackward * TMath::Sign(double(1.0), trackParam->getInverseBendingMomentum()); + double chargeExtrap = forwardBackward * TMath::Sign(double(1.0), trackParam.getInverseBendingMomentum()); double v3[7] = {0.}, v3New[7] = {0.}; double dZ(0.), step(0.); int stepNumber = 0; // Extrapolation loop (until within tolerance or the track turn around) - double residue = zEnd - trackParam->getZ(); + double residue = zEnd - trackParam.getZ(); while (TMath::Abs(residue) > SRungeKuttaMaxResidue) { - dZ = zEnd - trackParam->getZ(); + dZ = zEnd - trackParam.getZ(); // step length assuming linear trajectory - step = dZ * TMath::Sqrt(1.0 + trackParam->getBendingSlope() * trackParam->getBendingSlope() + - trackParam->getNonBendingSlope() * trackParam->getNonBendingSlope()); + step = dZ * TMath::Sqrt(1.0 + trackParam.getBendingSlope() * trackParam.getBendingSlope() + + trackParam.getNonBendingSlope() * trackParam.getNonBendingSlope()); convertTrackParamForExtrap(trackParam, forwardBackward, v3); do { // reduce step length while zEnd overstepped @@ -870,7 +897,7 @@ bool TrackExtrap::extrapToZRungekutta(TrackParam* trackParam, double zEnd) return false; } residue = zEnd - v3New[2]; - step *= dZ / (v3New[2] - trackParam->getZ()); + step *= dZ / (v3New[2] - trackParam.getZ()); } while (residue * dZ < 0 && TMath::Abs(residue) > SRungeKuttaMaxResidue); if (v3New[5] * v3[5] < 0) { // the track turned around @@ -882,29 +909,29 @@ bool TrackExtrap::extrapToZRungekutta(TrackParam* trackParam, double zEnd) } // terminate the extropolation with a straight line up to the exact "zEnd" value - trackParam->setNonBendingCoor(trackParam->getNonBendingCoor() + residue * trackParam->getNonBendingSlope()); - trackParam->setBendingCoor(trackParam->getBendingCoor() + residue * trackParam->getBendingSlope()); - trackParam->setZ(zEnd); + trackParam.setNonBendingCoor(trackParam.getNonBendingCoor() + residue * trackParam.getNonBendingSlope()); + trackParam.setBendingCoor(trackParam.getBendingCoor() + residue * trackParam.getBendingSlope()); + trackParam.setZ(zEnd); return true; } //__________________________________________________________________________ -bool TrackExtrap::extrapToZRungekuttaV2(TrackParam* trackParam, double zEnd) +bool TrackExtrap::extrapToZRungekuttaV2(TrackParam& trackParam, double zEnd) { /// Track parameter extrapolation to the plane at "Z" using Rungekutta algorithm. /// On return, the track parameters resulting from the extrapolation are updated in trackParam. /// Return false in case of failure and let the trackParam as they were when that happened - if (trackParam->getZ() == zEnd) { + if (trackParam.getZ() == zEnd) { return true; // nothing to be done if same Z } - double residue = zEnd - trackParam->getZ(); + double residue = zEnd - trackParam.getZ(); double forwardBackward = (residue < 0) ? 1. : -1.; // +1 if forward, -1 if backward double v3[7] = {0.}; convertTrackParamForExtrap(trackParam, forwardBackward, v3); - double charge = TMath::Sign(double(1.), trackParam->getInverseBendingMomentum()); + double charge = TMath::Sign(double(1.), trackParam.getInverseBendingMomentum()); // Extrapolation loop (until within tolerance or the track turn around) double v3New[7] = {0.}; @@ -951,9 +978,9 @@ bool TrackExtrap::extrapToZRungekuttaV2(TrackParam* trackParam, double zEnd) recoverTrackParam(v3New, charge, trackParam); // terminate the extrapolation with a straight line up to the exact "zEnd" value - trackParam->setNonBendingCoor(trackParam->getNonBendingCoor() + residue * trackParam->getNonBendingSlope()); - trackParam->setBendingCoor(trackParam->getBendingCoor() + residue * trackParam->getBendingSlope()); - trackParam->setZ(zEnd); + trackParam.setNonBendingCoor(trackParam.getNonBendingCoor() + residue * trackParam.getNonBendingSlope()); + trackParam.setBendingCoor(trackParam.getBendingCoor() + residue * trackParam.getBendingSlope()); + trackParam.setZ(zEnd); return true; } diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx index c5db52bf5246c..9aa067764df88 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,6 +26,7 @@ #include "Field/MagneticField.h" #include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackerParam.h" namespace o2 { @@ -33,9 +35,8 @@ namespace mch using namespace std; -constexpr float TrackFinder::SDefaultChamberZ[10]; +constexpr double TrackFinder::SDefaultChamberZ[10]; constexpr double TrackFinder::SChamberThicknessInX0[10]; -constexpr bool TrackFinder::SRequestStation[5]; constexpr int TrackFinder::SNDE[10]; //_________________________________________________________________________________________________ @@ -46,12 +47,22 @@ void TrackFinder::init(float l3Current, float dipoleCurrent) // create the magnetic field map if not already done mTrackFitter.initField(l3Current, dipoleCurrent); - // enable the track smoother + // Set the parameters used for fitting the tracks during the tracking + const auto& trackerParam = TrackerParam::Instance(); + mTrackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + mTrackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY); mTrackFitter.smoothTracks(true); // use the Runge-Kutta extrapolation v2 TrackExtrap::useExtrapV2(); + // Pre-compute some parameters used during the tracking + mChamberResolutionX2 = trackerParam.chamberResolutionX * trackerParam.chamberResolutionX; + mChamberResolutionY2 = trackerParam.chamberResolutionY * trackerParam.chamberResolutionY; + mBendingVertexDispersion2 = trackerParam.bendingVertexDispersion * trackerParam.bendingVertexDispersion; + mMaxChi2ForTracking = 2. * trackerParam.sigmaCutForTracking * trackerParam.sigmaCutForTracking; + mMaxChi2ForImprovement = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement; + // set the maximum MCS angle in chamber from the minimum acceptable momentum TrackParam param{}; double inverseBendingP = (SMinBendingMomentum > 0.) ? 1. / SMinBendingMomentum : 1.; @@ -147,12 +158,15 @@ const std::list<Track>& TrackFinder::findTracks(const std::unordered_map<int, st } } + // use the chamber resolution when fitting the tracks during the tracking + mTrackFitter.useChamberResolution(); + // find track candidates on stations 4 and 5 auto tStart = std::chrono::high_resolution_clock::now(); findTrackCandidates(); auto tEnd = std::chrono::high_resolution_clock::now(); mTimeFindCandidates += tEnd - tStart; - if (mMoreCandidates) { + if (TrackerParam::Instance().moreCandidates) { tStart = std::chrono::high_resolution_clock::now(); findMoreTrackCandidates(); tEnd = std::chrono::high_resolution_clock::now(); @@ -181,14 +195,22 @@ const std::list<Track>& TrackFinder::findTracks(const std::unordered_map<int, st tEnd = std::chrono::high_resolution_clock::now(); mTimeImproveTracks += tEnd - tStart; - // Remove connected tracks in stations(1..) 3, 4 and 5 + // remove connected tracks in stations(1..) 3, 4 and 5 tStart = std::chrono::high_resolution_clock::now(); removeConnectedTracks(2, 4); tEnd = std::chrono::high_resolution_clock::now(); mTimeCleanTracks += tEnd - tStart; - // Set the final track parameters and covariances - finalize(); + // refine the tracks using cluster resolution or just finalize them + if (TrackerParam::Instance().refineTracks) { + tStart = std::chrono::high_resolution_clock::now(); + mTrackFitter.useClusterResolution(); + refineTracks(); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeRefineTracks += tEnd - tStart; + } else { + finalize(); + } return mTracks; } @@ -215,7 +237,7 @@ void TrackFinder::findTrackCandidates() auto itNewTrack = followTrackInChamber(itTrack, 7, 6, false, excludedClusters); // keep the current candidate only if no compatible cluster is found and the station is not requested - if (!SRequestStation[3] && excludedClusters.empty() && itTrack->areCurrentParamValid()) { + if (!TrackerParam::Instance().requestStation[3] && excludedClusters.empty() && itTrack->areCurrentParamValid()) { ++itTrack; } else { print("findTrackCandidates: removing candidate at position #", getTrackIndex(itTrack)); @@ -260,7 +282,7 @@ void TrackFinder::findTrackCandidates() } // keep the current candidate only if no compatible cluster is found and the station is not requested - if (!SRequestStation[4] && excludedClusters.empty()) { + if (!TrackerParam::Instance().requestStation[4] && excludedClusters.empty()) { itFirstNewTrack = itTrack; ++itTrack; } else { @@ -585,7 +607,7 @@ std::list<Track>::iterator TrackFinder::findTrackCandidates(int plane1, int plan /// New candidates are added at the end of the track list /// Return an iterator to the first candidate found - static const double bendingVertexDispersion2 = SBendingVertexDispersion * SBendingVertexDispersion; + const auto& trackerParam = TrackerParam::Instance(); // maximum impact parameter dispersion**2 due to MCS in chambers double impactMCS2(0.); @@ -628,8 +650,8 @@ std::list<Track>::iterator TrackFinder::findTrackCandidates(int plane1, int plan // check if non bending impact parameter is within tolerances double nonBendingSlope = (cluster1.getX() - cluster2.getX()) / dZ; double nonBendingImpactParam = TMath::Abs(cluster1.getX() - cluster1.getZ() * nonBendingSlope); - double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2.getEx2() + z2 * z2 * cluster1.getEx2()) / dZ / dZ + impactMCS2); - if ((nonBendingImpactParam - SSigmaCutForTracking * nonBendingImpactParamErr) > (3. * SNonBendingVertexDispersion)) { + double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionX2 + z2 * z2 * mChamberResolutionX2) / dZ / dZ + impactMCS2); + if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) { continue; } @@ -637,17 +659,17 @@ std::list<Track>::iterator TrackFinder::findTrackCandidates(int plane1, int plan if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF // check if bending momentum is within tolerances double bendingImpactParam = cluster1.getY() - cluster1.getZ() * bendingSlope; - double bendingImpactParamErr2 = (z1 * z1 * cluster2.getEy2() + z2 * z2 * cluster1.getEy2()) / dZ / dZ + impactMCS2; + double bendingImpactParamErr2 = (z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2; double bendingMomentum = TMath::Abs(TrackExtrap::getBendingMomentumFromImpactParam(bendingImpactParam)); - double bendingMomentumErr = TMath::Sqrt((bendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum; + double bendingMomentumErr = TMath::Sqrt((mBendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum; if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) { continue; } } else { // or check if bending impact parameter is within tolerances double bendingImpactParam = TMath::Abs(cluster1.getY() - cluster1.getZ() * bendingSlope); - double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2.getEy2() + z2 * z2 * cluster1.getEy2()) / dZ / dZ + impactMCS2); - if ((bendingImpactParam - SSigmaCutForTracking * bendingImpactParamErr) > (3. * SBendingVertexDispersion)) { + double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2); + if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) { continue; } } @@ -764,7 +786,7 @@ std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::i // add MCS effects in that chamber before going further with this track or stop here if the track could not reach that chamber if (itTrack->areCurrentParamValid()) { - TrackExtrap::addMCSEffect(&(itTrack->getCurrentParam()), SChamberThicknessInX0[chamber], -1.); + TrackExtrap::addMCSEffect(itTrack->getCurrentParam(), SChamberThicknessInX0[chamber], -1.); } else { return itFirstNewTrack; } @@ -785,7 +807,7 @@ std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::i } // consider the possibility to skip the entire station if not requested and not the last one - if (isFirstOnStation && !SRequestStation[chamber / 2] && chamber / 2 != lastChamber / 2) { + if (isFirstOnStation && !TrackerParam::Instance().requestStation[chamber / 2] && chamber / 2 != lastChamber / 2) { int nextChamber = (chamber > lastChamber) ? chamber - 2 : chamber + 2; auto itNewTrack = followTrackInChamber(itTrack, nextChamber, lastChamber, false, excludedClusters); if (itFirstNewTrack == mTracks.end()) { @@ -803,7 +825,7 @@ std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::i // add a new track if a cluster has been found on the first chamber of the station but not on the second and last one // or if one reaches station 1 and it is not requested, whether a cluster has been found on it or not if ((!isFirstOnStation && canSkip && excludedClusters.empty()) || - (chamber / 2 == 0 && !SRequestStation[0] && (isFirstOnStation || !canSkip))) { + (chamber / 2 == 0 && !TrackerParam::Instance().requestStation[0] && (isFirstOnStation || !canSkip))) { itFirstNewTrack = mTracks.emplace(itTrack, *itTrack); print("followTrackInChamber: duplicating candidate at position #", getTrackIndex(itFirstNewTrack)); } @@ -849,7 +871,7 @@ std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::i // extrapolate the candidate to the chamber if not already there TrackParam paramAtChamber = itTrack->getCurrentParam(); - if (itTrack->getCurrentChamber() != chamber && !TrackExtrap::extrapToZCov(¶mAtChamber, SDefaultChamberZ[chamber], true)) { + if (itTrack->getCurrentChamber() != chamber && !TrackExtrap::extrapToZCov(paramAtChamber, SDefaultChamberZ[chamber], true)) { itTrack->invalidateCurrentParam(); return mTracks.end(); } @@ -900,7 +922,7 @@ std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::i // save the current parameters at cluster1, reset the propagator and add MCS effects before going to plane2 currentParamAtCluster1 = paramAtCluster1; currentParamAtCluster1.resetPropagator(); - TrackExtrap::addMCSEffect(¤tParamAtCluster1, SChamberThicknessInX0[chamber], -1.); + TrackExtrap::addMCSEffect(currentParamAtCluster1, SChamberThicknessInX0[chamber], -1.); // loop over all DEs of plane2 bool cluster2Found(false); @@ -1087,9 +1109,6 @@ void TrackFinder::improveTracks() /// Recompute track parameters and covariances at the remaining clusters /// Remove the track if it cannot be improved or in case of failure - // Maximum chi2 to keep a cluster (the factor 2 is for the 2 degrees of freedom: x and y) - static const double maxChi2OfCluster = 2. * SSigmaCutForImprovement * SSigmaCutForImprovement; - for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) { bool removeTrack(false); @@ -1108,7 +1127,7 @@ void TrackFinder::improveTracks() } // Identify removable clusters - itTrack->tagRemovableClusters(requestedStationMask()); + itTrack->tagRemovableClusters(requestedStationMask(), !TrackerParam::Instance().moreCandidates); // Look for the cluster with the worst local chi2 double worstLocalChi2(-1.); @@ -1121,7 +1140,7 @@ void TrackFinder::improveTracks() } // If the worst chi2 is under requirement then the track is improved - if (worstLocalChi2 < maxChi2OfCluster) { + if (worstLocalChi2 < mMaxChi2ForImprovement) { break; } @@ -1162,7 +1181,7 @@ void TrackFinder::removeConnectedTracks(int stMin, int stMax) { /// Find and remove tracks sharing 1 cluster or more in station(s) [stMin, stMax] /// For each couple of connected tracks, one removes the one with the smallest - /// number of clusters or with the highest chi2 value in case of equality + /// number of fired chambers or with the highest chi2/(ndf-1) value in case of equality if (mTracks.size() < 2) { return; @@ -1172,30 +1191,36 @@ void TrackFinder::removeConnectedTracks(int stMin, int stMax) int chMax = 2 * stMax + 1; int nPlane = 2 * (chMax - chMin + 1); - // first loop to fill the array of cluster Ids - std::vector<uint32_t> ClIds{}; - ClIds.resize(nPlane * mTracks.size()); + // first loop to fill the arrays of cluster Ids and number of fired chambers + std::vector<uint32_t> ClIds(nPlane * mTracks.size()); + std::vector<uint8_t> nFiredCh(mTracks.size()); + int previousCh(-1); int iTrack(0); for (auto itTrack = mTracks.begin(); itTrack != mTracks.end(); ++itTrack, ++iTrack) { for (auto itParam = itTrack->rbegin(); itParam != itTrack->rend(); ++itParam) { int ch = itParam->getClusterPtr()->getChamberId(); - if (ch > chMax) { - continue; - } else if (ch < chMin) { - break; + if (ch != previousCh) { + ++nFiredCh[iTrack]; + previousCh = ch; + } + if (ch >= chMin && ch <= chMax) { + ClIds[nPlane * iTrack + 2 * (ch - chMin) + itParam->getClusterPtr()->getDEId() % 2] = itParam->getClusterPtr()->getUniqueId(); } - ClIds[nPlane * iTrack + 2 * (ch - chMin) + itParam->getClusterPtr()->getDEId() % 2] = itParam->getClusterPtr()->getUniqueId(); } } // second loop to tag the tracks to remove + int iTrack1 = mTracks.size() - 1; int iindex = ClIds.size() - 1; - for (auto itTrack1 = mTracks.rbegin(); itTrack1 != mTracks.rend(); ++itTrack1, iindex -= nPlane) { + for (auto itTrack1 = mTracks.rbegin(); itTrack1 != mTracks.rend(); ++itTrack1, iindex -= nPlane, --iTrack1) { + int iTrack2 = iTrack1 - 1; int jindex = iindex - nPlane; - for (auto itTrack2 = std::next(itTrack1); itTrack2 != mTracks.rend(); ++itTrack2) { + for (auto itTrack2 = std::next(itTrack1); itTrack2 != mTracks.rend(); ++itTrack2, --iTrack2) { for (int iPlane = nPlane; iPlane > 0; --iPlane) { if (ClIds[iindex] > 0 && ClIds[iindex] == ClIds[jindex]) { - if (itTrack2->isBetter(*itTrack1)) { + if ((nFiredCh[iTrack2] > nFiredCh[iTrack1]) || + ((nFiredCh[iTrack2] == nFiredCh[iTrack1]) && + (itTrack2->first().getTrackChi2() / (itTrack2->getNDF() - 1) < itTrack1->first().getTrackChi2() / (itTrack1->getNDF() - 1)))) { itTrack1->connected(); } else { itTrack2->connected(); @@ -1222,6 +1247,22 @@ void TrackFinder::removeConnectedTracks(int stMin, int stMax) } } +//_________________________________________________________________________________________________ +void TrackFinder::refineTracks() +{ + /// Refit, smooth and finalize the reconstructed tracks + + for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) { + try { + mTrackFitter.fit(*itTrack); + ++itTrack; + } catch (exception const&) { + print("refineTracks: removing candidate at position #", getTrackIndex(itTrack)); + itTrack = mTracks.erase(itTrack); + } + } +} + //_________________________________________________________________________________________________ void TrackFinder::finalize() { @@ -1276,13 +1317,14 @@ bool TrackFinder::isAcceptable(const TrackParam& param) const } } + const auto& trackerParam = TrackerParam::Instance(); const TMatrixD& paramCov = param.getCovariances(); double z = param.getZ(); // check if non bending impact parameter is within tolerances double nonBendingImpactParam = TMath::Abs(param.getNonBendingCoor() - z * param.getNonBendingSlope()); double nonBendingImpactParamErr = TMath::Sqrt(paramCov(0, 0) + z * z * paramCov(1, 1) - 2. * z * paramCov(0, 1) + impactMCS2); - if ((nonBendingImpactParam - SSigmaCutForTracking * nonBendingImpactParamErr) > (3. * SNonBendingVertexDispersion)) { + if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) { return false; } @@ -1290,7 +1332,7 @@ bool TrackFinder::isAcceptable(const TrackParam& param) const // check if bending momentum is within tolerances double bendingMomentum = TMath::Abs(1. / param.getInverseBendingMomentum()); double bendingMomentumErr = TMath::Sqrt(paramCov(4, 4)) * bendingMomentum * bendingMomentum; - if (chamber < 6 && (bendingMomentum + SSigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) { + if (chamber < 6 && (bendingMomentum + trackerParam.sigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) { return false; } else if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) { return false; @@ -1299,7 +1341,7 @@ bool TrackFinder::isAcceptable(const TrackParam& param) const // or check if bending impact parameter is within tolerances double bendingImpactParam = TMath::Abs(param.getBendingCoor() - z * param.getBendingSlope()); double bendingImpactParamErr = TMath::Sqrt(paramCov(2, 2) + z * z * paramCov(3, 3) - 2. * z * paramCov(2, 3) + impactMCS2); - if ((bendingImpactParam - SSigmaCutForTracking * bendingImpactParamErr) > (3. * SBendingVertexDispersion)) { + if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) { return false; } } @@ -1353,7 +1395,7 @@ void TrackFinder::setCurrentParam(Track& track, const TrackParam& param, int cha if (param.getClusterPtr()) { TrackParam& currentParam = track.getCurrentParam(); currentParam.resetPropagator(); - TrackExtrap::addMCSEffect(¤tParam, SChamberThicknessInX0[chamber], -1.); + TrackExtrap::addMCSEffect(currentParam, SChamberThicknessInX0[chamber], -1.); } } @@ -1370,12 +1412,12 @@ bool TrackFinder::propagateCurrentParam(Track& track, int chamber) currentChamber += (chamber < currentChamber) ? -1 : 1; - if (!TrackExtrap::extrapToZCov(¤tParam, SDefaultChamberZ[currentChamber], true)) { + if (!TrackExtrap::extrapToZCov(currentParam, SDefaultChamberZ[currentChamber], true)) { track.invalidateCurrentParam(); return false; } - TrackExtrap::addMCSEffect(¤tParam, SChamberThicknessInX0[currentChamber], -1.); + TrackExtrap::addMCSEffect(currentParam, SChamberThicknessInX0[currentChamber], -1.); } return true; @@ -1448,16 +1490,13 @@ bool TrackFinder::isCompatible(const TrackParam& param, const Cluster& cluster, /// Test the compatibility between the track and the cluster /// If compatible, paramAtCluster contains the new track parameters at this cluster - // maximum chi2 to accept a cluster candidate (the factor 2 is for the 2 degrees of freedom: x and y) - static const double maxChi2OfCluster = 2. * SSigmaCutForTracking * SSigmaCutForTracking; - // fast try to add the current cluster if (!tryOneClusterFast(param, cluster)) { return false; } // try to add the current cluster accurately - if (tryOneCluster(param, cluster, paramAtCluster) >= maxChi2OfCluster) { + if (tryOneCluster(param, cluster, paramAtCluster) >= mMaxChi2ForTracking) { return false; } @@ -1489,11 +1528,11 @@ bool TrackFinder::tryOneClusterFast(const TrackParam& param, const Cluster& clus double dX = cluster.getX() - (param.getNonBendingCoor() + param.getNonBendingSlope() * dZ); double dY = cluster.getY() - (param.getBendingCoor() + param.getBendingSlope() * dZ); const TMatrixD& paramCov = param.getCovariances(); - double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + cluster.getEx2(); - double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + cluster.getEy2(); + double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + mChamberResolutionX2; + double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + mChamberResolutionY2; - double dXmax = SSigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack; - double dYmax = SSigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack; + double dXmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack; + double dYmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack; if (TMath::Abs(dX) > dXmax || TMath::Abs(dY) > dYmax) { return false; @@ -1514,7 +1553,7 @@ double TrackFinder::tryOneCluster(const TrackParam& param, const Cluster& cluste // Extrapolate the track parameters and covariances at the z position of the cluster paramAtCluster = param; paramAtCluster.setClusterPtr(&cluster); - if (!TrackExtrap::extrapToZCov(¶mAtCluster, cluster.getZ(), true)) { + if (!TrackExtrap::extrapToZCov(paramAtCluster, cluster.getZ(), true)) { return mTrackFitter.getMaxChi2(); } @@ -1524,8 +1563,8 @@ double TrackFinder::tryOneCluster(const TrackParam& param, const Cluster& cluste // Combine the cluster and track resolutions and covariances const TMatrixD& paramCov = paramAtCluster.getCovariances(); - double sigmaX2 = paramCov(0, 0) + cluster.getEx2(); - double sigmaY2 = paramCov(2, 2) + cluster.getEy2(); + double sigmaX2 = paramCov(0, 0) + mChamberResolutionX2; + double sigmaY2 = paramCov(2, 2) + mChamberResolutionY2; double covXY = paramCov(0, 2); double det = sigmaX2 * sigmaY2 - covXY * covXY; @@ -1543,7 +1582,7 @@ uint8_t TrackFinder::requestedStationMask() const /// bit n is set to 1 if the station n was requested uint8_t mask(0); for (int i = 0; i < 5; ++i) { - if (SRequestStation[i]) { + if (TrackerParam::Instance().requestStation[i]) { mask |= (1 << i); } } @@ -1635,6 +1674,7 @@ void TrackFinder::printTimers() const LOG(INFO) << "followTracks duration = " << mTimeFollowTracks.count() << " s"; LOG(INFO) << "improveTracks duration = " << mTimeImproveTracks.count() << " s"; LOG(INFO) << "removeConnectedTracks duration = " << mTimeCleanTracks.count() << " s"; + LOG(INFO) << "refineTracks duration = " << mTimeRefineTracks.count() << " s"; } } // namespace mch diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx index 2af108313e62d..4ba3c75bfb1a1 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,7 @@ #include "Field/MagneticField.h" #include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackerParam.h" namespace o2 { @@ -32,9 +34,8 @@ namespace mch using namespace std; -constexpr float TrackFinderOriginal::SDefaultChamberZ[10]; +constexpr double TrackFinderOriginal::SDefaultChamberZ[10]; constexpr double TrackFinderOriginal::SChamberThicknessInX0[10]; -constexpr bool TrackFinderOriginal::SRequestStation[5]; //_________________________________________________________________________________________________ void TrackFinderOriginal::init(float l3Current, float dipoleCurrent) @@ -44,9 +45,19 @@ void TrackFinderOriginal::init(float l3Current, float dipoleCurrent) // Create the magnetic field map if not already done mTrackFitter.initField(l3Current, dipoleCurrent); - // Enable the track smoother + // Set the parameters used for fitting the tracks during the tracking + const auto& trackerParam = TrackerParam::Instance(); + mTrackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + mTrackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY); mTrackFitter.smoothTracks(true); + // Pre-compute some parameters used during the tracking + mChamberResolutionX2 = trackerParam.chamberResolutionX * trackerParam.chamberResolutionX; + mChamberResolutionY2 = trackerParam.chamberResolutionY * trackerParam.chamberResolutionY; + mBendingVertexDispersion2 = trackerParam.bendingVertexDispersion * trackerParam.bendingVertexDispersion; + mMaxChi2ForTracking = 2. * trackerParam.sigmaCutForTracking * trackerParam.sigmaCutForTracking; + mMaxChi2ForImprovement = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement; + // Set the maximum MCS angle in chamber from the minimum acceptable momentum TrackParam param{}; double inverseBendingP = (SMinBendingMomentum > 0.) ? 1. / SMinBendingMomentum : 1.; @@ -59,19 +70,22 @@ void TrackFinderOriginal::init(float l3Current, float dipoleCurrent) //_________________________________________________________________________________________________ const std::list<Track>& TrackFinderOriginal::findTracks(const std::array<std::list<Cluster>, 10>* clusters) { - /// Run the orginal track finder algorithm + /// Run the original track finder algorithm print("\n------------------ Start the original track finder ------------------"); mClusters = clusters; mTracks.clear(); + // Use the chamber resolution when fitting the tracks during the tracking + mTrackFitter.useChamberResolution(); + // Look for candidates from clusters in stations(1..) 4 and 5 print("\n--> Step 1: find track candidates\n"); auto tStart = std::chrono::high_resolution_clock::now(); findTrackCandidates(); auto tEnd = std::chrono::high_resolution_clock::now(); mTimeFindCandidates += tEnd - tStart; - if (mMoreCandidates) { + if (TrackerParam::Instance().moreCandidates) { tStart = std::chrono::high_resolution_clock::now(); findMoreTrackCandidates(); tEnd = std::chrono::high_resolution_clock::now(); @@ -117,13 +131,18 @@ const std::list<Track>& TrackFinderOriginal::findTracks(const std::array<std::li tEnd = std::chrono::high_resolution_clock::now(); mTimeCleanTracks += tEnd - tStart; - // Set the final track parameters and covariances - finalize(); + // Refine the tracks using cluster resolution or just finalize them + if (TrackerParam::Instance().refineTracks) { + tStart = std::chrono::high_resolution_clock::now(); + mTrackFitter.useClusterResolution(); + refineTracks(); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeRefineTracks += tEnd - tStart; + } else { + finalize(); + } printTracks(); - /* - // Refit the reconstructed tracks with a different resolution for mono-cathod clusters - discardMonoCathodClusters(); -*/ + return mTracks; } @@ -145,7 +164,7 @@ void TrackFinderOriginal::findTrackCandidates() print("new candidates starting at position #", getTrackIndex(itNewTrack)); // Keep the current candidate only if no compatible cluster is found and the station is not requested - if (!SRequestStation[7 - iSt] && itNewTrack == mTracks.end()) { + if (!TrackerParam::Instance().requestStation[7 - iSt] && itNewTrack == mTracks.end()) { ++itTrack; } else { print("Removing original candidate now at position #", getTrackIndex(itTrack)); @@ -276,7 +295,7 @@ std::list<Track>::iterator TrackFinderOriginal::findTrackCandidates(int ch1, int print("Looking for candidates between chamber ", ch1, " and ", ch2); - double bendingVertexDispersion2 = SBendingVertexDispersion * SBendingVertexDispersion; + const auto& trackerParam = TrackerParam::Instance(); // maximum impact parameter dispersion**2 due to MCS in chambers double impactMCS2(0.); @@ -304,8 +323,8 @@ std::list<Track>::iterator TrackFinderOriginal::findTrackCandidates(int ch1, int // check if non bending impact parameter is within tolerances double nonBendingSlope = (cluster1.getX() - cluster2.getX()) / dZ; double nonBendingImpactParam = TMath::Abs(cluster1.getX() - cluster1.getZ() * nonBendingSlope); - double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2.getEx2() + z2 * z2 * cluster1.getEx2()) / dZ / dZ + impactMCS2); - if ((nonBendingImpactParam - SSigmaCutForTracking * nonBendingImpactParamErr) > (3. * SNonBendingVertexDispersion)) { + double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionX2 + z2 * z2 * mChamberResolutionX2) / dZ / dZ + impactMCS2); + if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) { continue; } @@ -313,17 +332,17 @@ std::list<Track>::iterator TrackFinderOriginal::findTrackCandidates(int ch1, int if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF // check if bending momentum is within tolerances double bendingImpactParam = cluster1.getY() - cluster1.getZ() * bendingSlope; - double bendingImpactParamErr2 = (z1 * z1 * cluster2.getEy2() + z2 * z2 * cluster1.getEy2()) / dZ / dZ + impactMCS2; + double bendingImpactParamErr2 = (z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2; double bendingMomentum = TMath::Abs(TrackExtrap::getBendingMomentumFromImpactParam(bendingImpactParam)); - double bendingMomentumErr = TMath::Sqrt((bendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum; + double bendingMomentumErr = TMath::Sqrt((mBendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum; if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) { continue; } } else { // or check if bending impact parameter is within tolerances double bendingImpactParam = TMath::Abs(cluster1.getY() - cluster1.getZ() * bendingSlope); - double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2.getEy2() + z2 * z2 * cluster1.getEy2()) / dZ / dZ + impactMCS2); - if ((bendingImpactParam - SSigmaCutForTracking * bendingImpactParamErr) > (3. * SBendingVertexDispersion)) { + double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2); + if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) { continue; } } @@ -402,22 +421,22 @@ void TrackFinderOriginal::createTrack(const Cluster& cl1, const Cluster& cl2) TMatrixD paramCov(5, 5); paramCov.Zero(); // Non bending plane - double cl1Ex2 = cl1.getEx2(); - double cl2Ex2 = cl2.getEx2(); + double cl1Ex2 = mChamberResolutionX2; + double cl2Ex2 = mChamberResolutionX2; paramCov(0, 0) = cl1Ex2; paramCov(0, 1) = cl1Ex2 / dZ; paramCov(1, 0) = paramCov(0, 1); paramCov(1, 1) = (cl1Ex2 + cl2Ex2) / dZ / dZ; // Bending plane - double cl1Ey2 = cl1.getEy2(); - double cl2Ey2 = cl2.getEy2(); + double cl1Ey2 = mChamberResolutionY2; + double cl2Ey2 = mChamberResolutionY2; paramCov(2, 2) = cl1Ey2; paramCov(2, 3) = cl1Ey2 / dZ; paramCov(3, 2) = paramCov(2, 3); paramCov(3, 3) = (cl1Ey2 + cl2Ey2) / dZ / dZ; // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field) if (TrackExtrap::isFieldON()) { - paramCov(4, 4) = ((SBendingVertexDispersion * SBendingVertexDispersion + + paramCov(4, 4) = ((mBendingVertexDispersion2 + (cl1.getZ() * cl1.getZ() * cl2Ey2 + cl2.getZ() * cl2.getZ() * cl1Ey2) / dZ / dZ) / bendingImpact / bendingImpact + 0.1 * 0.1) * @@ -455,6 +474,7 @@ bool TrackFinderOriginal::isAcceptable(const TrackParam& param) const { /// Return true if the track is within given limits on momentum/angle/origin + const auto& trackerParam = TrackerParam::Instance(); const TMatrixD& paramCov = param.getCovariances(); int chamber = param.getClusterPtr()->getChamberId(); double z = param.getZ(); @@ -476,7 +496,7 @@ bool TrackFinderOriginal::isAcceptable(const TrackParam& param) const // check if non bending impact parameter is within tolerances double nonBendingImpactParam = TMath::Abs(param.getNonBendingCoor() - z * param.getNonBendingSlope()); double nonBendingImpactParamErr = TMath::Sqrt(paramCov(0, 0) + z * z * paramCov(1, 1) - 2. * z * paramCov(0, 1) + impactMCS2); - if ((nonBendingImpactParam - SSigmaCutForTracking * nonBendingImpactParamErr) > (3. * SNonBendingVertexDispersion)) { + if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) { return false; } @@ -484,7 +504,7 @@ bool TrackFinderOriginal::isAcceptable(const TrackParam& param) const // check if bending momentum is within tolerances double bendingMomentum = TMath::Abs(1. / param.getInverseBendingMomentum()); double bendingMomentumErr = TMath::Sqrt(paramCov(4, 4)) * bendingMomentum * bendingMomentum; - if (chamber < 6 && (bendingMomentum + SSigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) { + if (chamber < 6 && (bendingMomentum + trackerParam.sigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) { return false; } else if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) { return false; @@ -493,7 +513,7 @@ bool TrackFinderOriginal::isAcceptable(const TrackParam& param) const // or check if bending impact parameter is within tolerances double bendingImpactParam = TMath::Abs(param.getBendingCoor() - z * param.getBendingSlope()); double bendingImpactParamErr = TMath::Sqrt(paramCov(2, 2) + z * z * paramCov(3, 3) - 2. * z * paramCov(2, 3) + impactMCS2); - if ((bendingImpactParam - SSigmaCutForTracking * bendingImpactParamErr) > (3. * SBendingVertexDispersion)) { + if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) { return false; } } @@ -595,7 +615,7 @@ void TrackFinderOriginal::followTracks(const std::list<Track>::iterator& itTrack if (itNewTrack == mTracks.end()) { // Keep the case where no cluster is found as a possible candidate if the next station is not requested - if (!SRequestStation[nextStation]) { + if (!TrackerParam::Instance().requestStation[nextStation]) { print("Duplicate original candidate"); itTrack = mTracks.emplace(itTrack, *itTrack); } @@ -609,7 +629,7 @@ void TrackFinderOriginal::followTracks(const std::list<Track>::iterator& itTrack itTrack = mTracks.erase(itTrack); // If the next station is not requested, we can at minimum continue with the initial candidate - if (!SRequestStation[nextStation]) { + if (!TrackerParam::Instance().requestStation[nextStation]) { if (itNewTrack == mTracks.end()) { itNewTrack = itTrack; } @@ -662,15 +682,12 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: ch2 = 2 * nextStation + 1; } - // Maximum chi2 to accept a cluster candidate (the factor 2 is for the 2 degrees of freedom: x and y) - double maxChi2OfCluster = 2. * SSigmaCutForTracking * SSigmaCutForTracking; - // Get the current track parameters according to the propagation direction TrackParam extrapTrackParamAtCh = (nextStation == 4) ? itTrack->last() : itTrack->first(); // Add MCS effects in the current chamber int currentChamber(extrapTrackParamAtCh.getClusterPtr()->getChamberId()); - TrackExtrap::addMCSEffect(&extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.); + TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.); // Reset the propagator for the smoother if (mTrackFitter.isSmootherEnabled()) { @@ -680,15 +697,15 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: // Add MCS effects in the missing chamber(s) if any while (ch1 < ch2 && currentChamber > ch2 + 1) { --currentChamber; - if (!TrackExtrap::extrapToZCov(&extrapTrackParamAtCh, SDefaultChamberZ[currentChamber], + if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[currentChamber], mTrackFitter.isSmootherEnabled())) { return mTracks.end(); } - TrackExtrap::addMCSEffect(&extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.); + TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.); } //Extrapolate the track candidate to chamber 2 - if (!TrackExtrap::extrapToZCov(&extrapTrackParamAtCh, SDefaultChamberZ[ch2], mTrackFitter.isSmootherEnabled())) { + if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[ch2], mTrackFitter.isSmootherEnabled())) { return mTracks.end(); } @@ -705,7 +722,7 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: // Try to add the current cluster accurately if (tryOneCluster(extrapTrackParamAtCh, clusterCh2, extrapTrackParamAtCluster2, - mTrackFitter.isSmootherEnabled()) >= maxChi2OfCluster) { + mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) { continue; } @@ -729,7 +746,7 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: // copy the new track parameters for the next step and add MCS effects in chamber 2 extrapTrackParam = extrapTrackParamAtCluster2; - TrackExtrap::addMCSEffect(&extrapTrackParam, SChamberThicknessInX0[ch2], -1.); + TrackExtrap::addMCSEffect(extrapTrackParam, SChamberThicknessInX0[ch2], -1.); // Reset the propagator for the smoother if (mTrackFitter.isSmootherEnabled()) { @@ -738,7 +755,7 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: //Extrapolate the track candidate to chamber 1 bool foundSecondCluster(false); - if (TrackExtrap::extrapToZCov(&extrapTrackParam, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) { + if (TrackExtrap::extrapToZCov(extrapTrackParam, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) { // look for second cluster candidates in chamber 1 int iCluster1(-1); @@ -753,7 +770,7 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: // Try to add the current cluster accurately if (tryOneCluster(extrapTrackParam, clusterCh1, extrapTrackParamAtCluster1, - mTrackFitter.isSmootherEnabled()) >= maxChi2OfCluster) { + mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) { continue; } @@ -795,10 +812,10 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: } // Add MCS effects in chamber 2 - TrackExtrap::addMCSEffect(&extrapTrackParamAtCh, SChamberThicknessInX0[ch2], -1.); + TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[ch2], -1.); //Extrapolate the track candidate to chamber 1 - if (!TrackExtrap::extrapToZCov(&extrapTrackParamAtCh, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) { + if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) { return (itNewTrack == itTrack) ? mTracks.end() : itNewTrack; } @@ -818,7 +835,7 @@ std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std:: // Try to add the current cluster accurately if (tryOneCluster(extrapTrackParamAtCh, clusterCh1, extrapTrackParamAtCluster1, - mTrackFitter.isSmootherEnabled()) >= maxChi2OfCluster) { + mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) { continue; } @@ -864,14 +881,11 @@ std::list<Track>::iterator TrackFinderOriginal::followLinearTrackInChamber(const auto itNewTrack(itTrack); TrackParam extrapTrackParamAtCluster{}; - // Maximum chi2 to accept a cluster candidate (the factor 2 is for the 2 degrees of freedom: x and y) - double maxChi2OfCluster = 2. * SSigmaCutForTracking * SSigmaCutForTracking; - // Get the current track parameters according to the propagation direction TrackParam trackParam = (nextChamber > 7) ? itTrack->last() : itTrack->first(); // Add MCS effects in the current chamber - TrackExtrap::addMCSEffect(&trackParam, SChamberThicknessInX0[trackParam.getClusterPtr()->getChamberId()], -1.); + TrackExtrap::addMCSEffect(trackParam, SChamberThicknessInX0[trackParam.getClusterPtr()->getChamberId()], -1.); // Look for cluster candidates in the next chamber for (const auto& cluster : mClusters->at(nextChamber)) { @@ -883,10 +897,10 @@ std::list<Track>::iterator TrackFinderOriginal::followLinearTrackInChamber(const // propagate linearly the track to the z position of the current cluster extrapTrackParamAtCluster = trackParam; - TrackExtrap::linearExtrapToZCov(&extrapTrackParamAtCluster, cluster.getZ()); + TrackExtrap::linearExtrapToZCov(extrapTrackParamAtCluster, cluster.getZ()); // Try to add the current cluster accurately - if (tryOneCluster(extrapTrackParamAtCluster, cluster, extrapTrackParamAtCluster, false) >= maxChi2OfCluster) { + if (tryOneCluster(extrapTrackParamAtCluster, cluster, extrapTrackParamAtCluster, false) >= mMaxChi2ForTracking) { continue; } @@ -913,11 +927,11 @@ bool TrackFinderOriginal::tryOneClusterFast(const TrackParam& param, const Clust double dX = cluster.getX() - (param.getNonBendingCoor() + param.getNonBendingSlope() * dZ); double dY = cluster.getY() - (param.getBendingCoor() + param.getBendingSlope() * dZ); const TMatrixD& paramCov = param.getCovariances(); - double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + cluster.getEx2(); - double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + cluster.getEy2(); + double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + mChamberResolutionX2; + double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + mChamberResolutionY2; - double dXmax = SSigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack; - double dYmax = SSigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack; + double dXmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack; + double dYmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack; if (TMath::Abs(dX) > dXmax || TMath::Abs(dY) > dYmax) { return false; @@ -939,7 +953,7 @@ double TrackFinderOriginal::tryOneCluster(const TrackParam& param, const Cluster // Extrapolate the track parameters and covariances at the z position of the cluster paramAtCluster = param; paramAtCluster.setClusterPtr(&cluster); - if (!TrackExtrap::extrapToZCov(¶mAtCluster, cluster.getZ(), updatePropagator)) { + if (!TrackExtrap::extrapToZCov(paramAtCluster, cluster.getZ(), updatePropagator)) { return mTrackFitter.getMaxChi2(); } @@ -949,8 +963,8 @@ double TrackFinderOriginal::tryOneCluster(const TrackParam& param, const Cluster // Combine the cluster and track resolutions and covariances const TMatrixD& paramCov = paramAtCluster.getCovariances(); - double sigmaX2 = paramCov(0, 0) + cluster.getEx2(); - double sigmaY2 = paramCov(2, 2) + cluster.getEy2(); + double sigmaX2 = paramCov(0, 0) + mChamberResolutionX2; + double sigmaY2 = paramCov(2, 2) + mChamberResolutionY2; double covXY = paramCov(0, 2); double det = sigmaX2 * sigmaY2 - covXY * covXY; @@ -967,7 +981,7 @@ void TrackFinderOriginal::updateTrack(Track& track, TrackParam& trackParamAtClus /// Add to the track candidate the track parameters computed at the new cluster found in the station // Flag the cluster as being (not) removable - if (SRequestStation[trackParamAtCluster.getClusterPtr()->getChamberId() / 2]) { + if (TrackerParam::Instance().requestStation[trackParamAtCluster.getClusterPtr()->getChamberId() / 2]) { trackParamAtCluster.setRemovable(false); } else { trackParamAtCluster.setRemovable(true); @@ -994,16 +1008,16 @@ void TrackFinderOriginal::updateTrack(Track& track, TrackParam& trackParamAtClus const Cluster* cluster1(trackParamAtCluster1.getClusterPtr()); double deltaX = trackParamAtCluster1.getNonBendingCoor() - cluster1->getX(); double deltaY = trackParamAtCluster1.getBendingCoor() - cluster1->getY(); - double localChi2 = deltaX * deltaX / cluster1->getEx2() + deltaY * deltaY / cluster1->getEy2(); + double localChi2 = deltaX * deltaX / mChamberResolutionX2 + deltaY * deltaY / mChamberResolutionY2; trackParamAtCluster1.setLocalChi2(localChi2); // Compute the local chi2 at cluster2 const Cluster* cluster2(trackParamAtCluster2.getClusterPtr()); TrackParam extrapTrackParamAtCluster2(trackParamAtCluster1); - TrackExtrap::extrapToZ(&extrapTrackParamAtCluster2, trackParamAtCluster2.getZ()); + TrackExtrap::extrapToZ(extrapTrackParamAtCluster2, trackParamAtCluster2.getZ()); deltaX = extrapTrackParamAtCluster2.getNonBendingCoor() - cluster2->getX(); deltaY = extrapTrackParamAtCluster2.getBendingCoor() - cluster2->getY(); - localChi2 = deltaX * deltaX / cluster2->getEx2() + deltaY * deltaY / cluster2->getEy2(); + localChi2 = deltaX * deltaX / mChamberResolutionX2 + deltaY * deltaY / mChamberResolutionY2; trackParamAtCluster2.setLocalChi2(localChi2); // Add the parameters at the new clusters @@ -1042,7 +1056,7 @@ std::list<Track>::iterator TrackFinderOriginal::recoverTrack(std::list<Track>::i } // Reset the current cluster as being not removable if it is on a requested station - if (SRequestStation[nextStation + 1]) { + if (TrackerParam::Instance().requestStation[nextStation + 1]) { itParam->setRemovable(false); } @@ -1093,9 +1107,6 @@ bool TrackFinderOriginal::completeTracks() TrackParam paramAtCluster{}; TrackParam bestParamAtCluster{}; - // Maximum chi2 to accept a cluster candidate (the factor 2 is for the 2 degrees of freedom: x and y) - double maxChi2OfCluster = 2. * SSigmaCutForTracking * SSigmaCutForTracking; - for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) { bool trackCompleted(false); @@ -1124,7 +1135,7 @@ bool TrackFinderOriginal::completeTracks() } // Try to add the current cluster accurately - if (tryOneCluster(*param, cluster, paramAtCluster, false) >= maxChi2OfCluster) { + if (tryOneCluster(*param, cluster, paramAtCluster, false) >= mMaxChi2ForTracking) { continue; } @@ -1189,9 +1200,6 @@ void TrackFinderOriginal::improveTracks() return; } - // Maximum chi2 to keep a cluster (the factor 2 is for the 2 degrees of freedom: x and y) - double maxChi2OfCluster = 2. * SSigmaCutForImprovement * SSigmaCutForImprovement; - for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) { bool removeTrack(false); @@ -1210,7 +1218,7 @@ void TrackFinderOriginal::improveTracks() } // Identify removable clusters - itTrack->tagRemovableClusters(requestedStationMask()); + itTrack->tagRemovableClusters(requestedStationMask(), false); // Look for the cluster with the worst local chi2 double worstLocalChi2(-1.); @@ -1223,7 +1231,7 @@ void TrackFinderOriginal::improveTracks() } // If the worst chi2 is under requirement then the track is improved - if (worstLocalChi2 < maxChi2OfCluster) { + if (worstLocalChi2 < mMaxChi2ForImprovement) { break; } @@ -1260,6 +1268,28 @@ void TrackFinderOriginal::improveTracks() } } +//_________________________________________________________________________________________________ +void TrackFinderOriginal::refineTracks() +{ + /// Refit, improve and finalize the reconstructed tracks + + print("Refine tracks"); + + for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) { + try { + mTrackFitter.fit(*itTrack, false); + ++itTrack; + } catch (exception const&) { + print("Removing candidate at position #", getTrackIndex(itTrack)); + itTrack = mTracks.erase(itTrack); + } + } + + improveTracks(); + + finalize(); +} + //_________________________________________________________________________________________________ void TrackFinderOriginal::finalize() { @@ -1290,7 +1320,7 @@ uint8_t TrackFinderOriginal::requestedStationMask() const uint8_t mask(0); for (int i = 0; i < 5; ++i) { - if (SRequestStation[i]) { + if (TrackerParam::Instance().requestStation[i]) { mask |= (1 << i); } } @@ -1375,6 +1405,7 @@ void TrackFinderOriginal::printTimers() const LOG(INFO) << "completeTracks duration = " << mTimeCompleteTracks.count() << " s"; LOG(INFO) << "improveTracks duration = " << mTimeImproveTracks.count() << " s"; LOG(INFO) << "removeConnectedTracks duration = " << mTimeCleanTracks.count() << " s"; + LOG(INFO) << "refineTracks duration = " << mTimeRefineTracks.count() << " s"; } } // namespace mch diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFitter.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFitter.cxx index c845c2b8279cb..7b81ab887e70e 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFitter.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,7 +31,7 @@ namespace mch using namespace std; -constexpr float TrackFitter::SDefaultChamberZ[10]; +constexpr double TrackFitter::SDefaultChamberZ[10]; constexpr double TrackFitter::SChamberThicknessInX0[10]; //_________________________________________________________________________________________________ @@ -117,21 +118,33 @@ void TrackFitter::initTrack(const Cluster& cl1, const Cluster& cl2, TrackParam& // compute the track parameter covariances at the last cluster (as if the other clusters did not exist) TMatrixD lastParamCov(5, 5); lastParamCov.Zero(); + double cl1Ey2(0.); + if (mUseChamberResolution) { + // Non bending plane + lastParamCov(0, 0) = mChamberResolutionX2; + lastParamCov(1, 1) = (1000. * mChamberResolutionX2 + lastParamCov(0, 0)) / dZ / dZ; + // Bending plane + lastParamCov(2, 2) = mChamberResolutionY2; + cl1Ey2 = mChamberResolutionY2; + } else { + // Non bending plane + lastParamCov(0, 0) = cl2.getEx2(); + lastParamCov(1, 1) = (1000. * cl1.getEx2() + lastParamCov(0, 0)) / dZ / dZ; + // Bending plane + lastParamCov(2, 2) = cl2.getEy2(); + cl1Ey2 = cl1.getEy2(); + } // Non bending plane - lastParamCov(0, 0) = cl2.getEx2(); lastParamCov(0, 1) = -lastParamCov(0, 0) / dZ; lastParamCov(1, 0) = lastParamCov(0, 1); - lastParamCov(1, 1) = (1000. * cl1.getEx2() + lastParamCov(0, 0)) / dZ / dZ; // Bending plane - double cl1Ey2 = cl1.getEy2(); - lastParamCov(2, 2) = cl2.getEy2(); lastParamCov(2, 3) = -lastParamCov(2, 2) / dZ; lastParamCov(3, 2) = lastParamCov(2, 3); lastParamCov(3, 3) = (1000. * cl1Ey2 + lastParamCov(2, 2)) / dZ / dZ; // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field) if (TrackExtrap::isFieldON()) { lastParamCov(4, 4) = - ((SBendingVertexDispersion * SBendingVertexDispersion + + ((mBendingVertexDispersion2 + (cl1.getZ() * cl1.getZ() * lastParamCov(2, 2) + cl2.getZ() * cl2.getZ() * 1000. * cl1Ey2) / dZ / dZ) / bendingImpact / bendingImpact + 0.1 * 0.1) * @@ -171,7 +184,7 @@ void TrackFitter::addCluster(const TrackParam& startingParam, const Cluster& cl, // add MCS effect in the current chamber int currentChamber(startingParam.getClusterPtr()->getChamberId()); - TrackExtrap::addMCSEffect(¶m, SChamberThicknessInX0[currentChamber], -1.); + TrackExtrap::addMCSEffect(param, SChamberThicknessInX0[currentChamber], -1.); // reset propagator for smoother if (mSmooth) { @@ -182,15 +195,15 @@ void TrackFitter::addCluster(const TrackParam& startingParam, const Cluster& cl, int expectedChamber(currentChamber - 1); currentChamber = cl.getChamberId(); while (currentChamber < expectedChamber) { - if (!TrackExtrap::extrapToZCov(¶m, SDefaultChamberZ[expectedChamber], mSmooth)) { + if (!TrackExtrap::extrapToZCov(param, SDefaultChamberZ[expectedChamber], mSmooth)) { throw runtime_error("Track extrapolation failed"); } - TrackExtrap::addMCSEffect(¶m, SChamberThicknessInX0[expectedChamber], -1.); + TrackExtrap::addMCSEffect(param, SChamberThicknessInX0[expectedChamber], -1.); expectedChamber--; } // extrapolate to the z position of the new cluster - if (!TrackExtrap::extrapToZCov(¶m, cl.getZ(), mSmooth)) { + if (!TrackExtrap::extrapToZCov(param, cl.getZ(), mSmooth)) { throw runtime_error("Track extrapolation failed"); } @@ -267,8 +280,13 @@ void TrackFitter::runKalmanFilter(TrackParam& trackParam) // compute the new cluster weight (U) TMatrixD clusterWeight(5, 5); clusterWeight.Zero(); - clusterWeight(0, 0) = 1. / cluster->getEx2(); - clusterWeight(2, 2) = 1. / cluster->getEy2(); + if (mUseChamberResolution) { + clusterWeight(0, 0) = 1. / mChamberResolutionX2; + clusterWeight(2, 2) = 1. / mChamberResolutionY2; + } else { + clusterWeight(0, 0) = 1. / cluster->getEx2(); + clusterWeight(2, 2) = 1. / cluster->getEy2(); + } // compute the new parameters covariance matrix ((W+U)^-1) TMatrixD newParamCov(paramWeight, TMatrixD::kPlus, clusterWeight); @@ -345,10 +363,15 @@ void TrackFitter::runSmoother(const TrackParam& previousParam, TrackParam& param // compute weight of smoothed residual: W(k n) = (clusterCov - C(k n))^-1 TMatrixD smoothResidualWeight(2, 2); - smoothResidualWeight(0, 0) = cluster->getEx2() - smoothCovariances(0, 0); + if (mUseChamberResolution) { + smoothResidualWeight(0, 0) = mChamberResolutionX2 - smoothCovariances(0, 0); + smoothResidualWeight(1, 1) = mChamberResolutionY2 - smoothCovariances(2, 2); + } else { + smoothResidualWeight(0, 0) = cluster->getEx2() - smoothCovariances(0, 0); + smoothResidualWeight(1, 1) = cluster->getEy2() - smoothCovariances(2, 2); + } smoothResidualWeight(0, 1) = -smoothCovariances(0, 2); smoothResidualWeight(1, 0) = -smoothCovariances(2, 0); - smoothResidualWeight(1, 1) = cluster->getEy2() - smoothCovariances(2, 2); if (smoothResidualWeight.Determinant() != 0) { smoothResidualWeight.Invert(); } else { diff --git a/Detectors/MUON/MCH/Tracking/src/TrackParam.cxx b/Detectors/MUON/MCH/Tracking/src/TrackParam.cxx index b445f660f7178..76c0542017106 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackParam.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ #include <TMath.h> -#include <FairMQLogger.h> +#include "Framework/Logger.h" #include "MCHTracking/Cluster.h" diff --git a/Detectors/MUON/MCH/Tracking/src/TrackerParam.cxx b/Detectors/MUON/MCH/Tracking/src/TrackerParam.cxx new file mode 100644 index 0000000000000..ca6786711340b --- /dev/null +++ b/Detectors/MUON/MCH/Tracking/src/TrackerParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackerParam.cxx +/// \brief Configurable parameters for MCH tracking +/// \author Philippe Pillot, Subatech + +#include "MCHTracking/TrackerParam.h" + +O2ParamImpl(o2::mch::TrackerParam); diff --git a/Detectors/MUON/MCH/Workflow/CMakeLists.txt b/Detectors/MUON/MCH/Workflow/CMakeLists.txt index 80022eab2b4de..ca5ce06c1c219 100644 --- a/Detectors/MUON/MCH/Workflow/CMakeLists.txt +++ b/Detectors/MUON/MCH/Workflow/CMakeLists.txt @@ -1,20 +1,38 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +# MCHWorkflow library is (at least) needed by Detectors/CTF/workflow o2_add_library(MCHWorkflow - SOURCES src/DataDecoderSpec.cxx src/PreClusterFinderSpec.cxx src/ClusterFinderOriginalSpec.cxx - TARGETVARNAME targetName - PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::MCHRawDecoder Boost::program_options - O2::MCHRawImplHelpers RapidJSON::RapidJSON O2::MCHMappingInterface - O2::MCHPreClustering O2::MCHMappingImpl4 O2::MCHRawElecMap O2::MCHBase - O2::MCHClustering) + SOURCES + src/ClusterFinderOriginalSpec.cxx + src/DataDecoderSpec.cxx + src/EntropyDecoderSpec.cxx + src/TimeClusterFinderSpec.cxx + src/PreClusterFinderSpec.cxx + src/TrackReaderSpec.cxx + src/TrackTreeReader.cxx + src/TrackWriterSpec.cxx + PUBLIC_LINK_LIBRARIES + O2::CommonUtils + O2::DPLUtils + O2::DataFormatsParameters + O2::SimulationDataFormat + O2::DetectorsRaw + O2::MCHCTF + O2::MCHClustering + O2::MCHPreClustering + O2::MCHTimeClustering + O2::MCHRawCommon + O2::MCHRawDecoder + ) o2_add_executable( cru-page-reader-workflow @@ -22,6 +40,7 @@ o2_add_executable( COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsRaw O2::DPLUtils Boost::program_options) +# to be deprecated : use DevIO/digits-writer instead o2_add_executable( digits-sink-workflow SOURCES src/digits-sink-workflow.cxx @@ -34,12 +53,24 @@ o2_add_executable( COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) +o2_add_executable( + raw-debug-workflow + SOURCES src/raw-debug-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + o2_add_executable( cru-page-to-digits-workflow SOURCES src/cru-page-to-digits-workflow.cxx COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) +o2_add_executable( + digits-to-timeclusters-workflow + SOURCES src/digits-to-timeclusters-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + o2_add_executable( digits-to-preclusters-workflow SOURCES src/digits-to-preclusters-workflow.cxx @@ -50,13 +81,19 @@ o2_add_executable( digits-reader-workflow SOURCES src/DigitSamplerSpec.cxx src/digits-reader-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsRaw O2::DataFormatsMCH O2::MCHBase O2::MCHMappingImpl3) + +o2_add_executable( + sim-digits-reader-workflow + SOURCES src/DigitReaderSpec.cxx src/sim-digits-reader-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::DataFormatsMCH O2::MCHBase O2::MCHMappingImpl3 O2::SimulationDataFormat) o2_add_executable( preclusters-sink-workflow SOURCES src/PreClusterSinkSpec.cxx src/preclusters-sink-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHBase O2::MCHMappingImpl3) o2_add_executable( preclusters-to-clusters-original-workflow @@ -66,15 +103,15 @@ o2_add_executable( o2_add_executable( clusters-sink-workflow - SOURCES src/ClusterSinkSpec.cxx src/clusters-sink-workflow.cxx + SOURCES src/clusters-sink-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHBase O2::MCHMappingImpl3) o2_add_executable( clusters-sampler-workflow - SOURCES src/ClusterSamplerSpec.cxx src/clusters-sampler-workflow.cxx + SOURCES src/clusters-sampler-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::Framework O2::MCHBase) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHBase) o2_add_executable( clusters-to-tracks-original-workflow @@ -86,13 +123,24 @@ o2_add_executable( clusters-to-tracks-workflow SOURCES src/TrackFinderSpec.cxx src/clusters-to-tracks-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHTracking) + PUBLIC_LINK_LIBRARIES O2::DataFormatsParameters O2::Framework O2::DataFormatsMCH O2::MCHTracking O2::DataFormatsParameters) + +o2_add_executable( + clusters-transformer-workflow + SOURCES src/clusters-transformer-workflow.cxx src/ClusterTransformerSpec.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES + O2::DetectorsBase + O2::Framework + O2::MCHBase + O2::MCHGeometryTransformer + ) o2_add_executable( vertex-sampler-workflow SOURCES src/VertexSamplerSpec.cxx src/vertex-sampler-workflow.cxx COMPONENT_NAME mch - PUBLIC_LINK_LIBRARIES O2::Framework) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH) o2_add_executable( tracks-to-tracks-at-vertex-workflow @@ -106,6 +154,18 @@ o2_add_executable( COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHBase) +o2_add_executable( + tracks-writer-workflow + SOURCES src/tracks-writer-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + +o2_add_executable( + tracks-reader-workflow + SOURCES src/tracks-reader-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + o2_add_executable( tracks-sampler-workflow SOURCES src/TrackSamplerSpec.cxx src/tracks-sampler-workflow.cxx @@ -117,3 +177,46 @@ o2_add_executable( SOURCES src/TrackFitterSpec.cxx src/tracks-to-tracks-workflow.cxx COMPONENT_NAME mch PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH O2::MCHTracking) + +o2_add_executable( + entropy-encoder-workflow + SOURCES src/entropy-encoder-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHWorkflow) + +o2_add_executable( + reco-workflow + SOURCES + src/ClusterTransformerSpec.cxx + src/DigitReaderSpec.cxx + src/TrackAtVertexSpec.cxx + src/TrackFinderSpec.cxx + src/TrackMCLabelFinderSpec.cxx + src/VertexSamplerSpec.cxx + src/reco-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES + O2::MCHGeometryTransformer + O2::MCHTracking + O2::MCHWorkflow + O2::SimulationDataFormat + O2::Steer + ) + +o2_add_executable(tracks-file-dumper + SOURCES src/tracks-file-dumper.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES Boost::program_options O2::MCHWorkflow) + +o2_add_executable( + tracks-mc-label-finder-workflow + SOURCES src/TrackMCLabelFinderSpec.cxx src/tracks-mc-label-finder-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::Framework O2::Steer O2::DataFormatsMCH O2::MCHBase) + +o2_add_executable(rofs-histogrammer + SOURCES src/rofs-histogrammer.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsMCH) + + diff --git a/Detectors/MUON/MCH/Workflow/README.md b/Detectors/MUON/MCH/Workflow/README.md index 1ed6fd6dd6bd8..1b66e3c2e6f2e 100644 --- a/Detectors/MUON/MCH/Workflow/README.md +++ b/Detectors/MUON/MCH/Workflow/README.md @@ -6,35 +6,61 @@ <!-- vim-markdown-toc GFM --> +* [A note for developers](#a-note-for-developers) * [Raw to digits](#raw-to-digits) -* [Digits to preclusters](#digits-to-preclusters) +* [Time clustering](#time-clustering) +* [Preclustering](#preclustering) +* [Clustering](#clustering) +* [CTF encoding/decoding](#ctf-encodingdecoding) +* [Local to global cluster transformation](#local-to-global-cluster-transformation) * [Tracking](#tracking) * [Original track finder](#original-track-finder) * [New track finder](#new-track-finder) * [Track extrapolation to vertex](#track-extrapolation-to-vertex) * [Track fitter](#track-fitter) * [Samplers](#samplers) + * [Digit sampler](#digit-sampler) * [Cluster sampler](#cluster-sampler) * [Track sampler](#track-sampler) + * [Track reader](#track-reader) * [Vertex sampler](#vertex-sampler) * [Sinks](#sinks) - * [Preclusters sink](#preclusters-sink) + * [Precluster sink](#precluster-sink) + * [Cluster sink](#cluster-sink) * [Track sink](#track-sink) + * [Track writer](#track-writer) <!-- vim-markdown-toc --> + +## A note for developers + +When defining a function that returns a `DataProcessorSpec`, please stick to the following pattern for its parameters : + + DataProcessorSpec getXXX([bool useMC], const char* specName="mch-xxx", other parameters); + +* first parameter, if relevant, should be a boolean indicating whether the processor has to deal with Monte Carlo data or not. For a processor that never has to deal with MC, leave that parameter out +* second parameter is the name by which that device will be referenced in all log files, so, in order to be easily recognizable, it *must* start with the prefix `mch-` +* the rest of the parameters (if any) is specific to each device + ## Raw to digits -`o2-mch-raw-to-digits-workflow` +```shell +o2-mch-raw-to-digits-workflow +``` -## Digits to preclusters +The workflow accepts the following options: -`o2-mch-digits-to-preclusters-workflow` +* `--debug`: enable verbose output +* `--dataspec`: selection string for the input data (default: `"TF:MCH/RAWDATA"`) +* `--cru-map`: path to custom CRU mapping file +* `--fec-map`: path to custom FEC mapping file +* `--ds2manu`: convert channel numbering from Run3 to Run1-2 order Example of a DPL chain to go from a raw data file to a file of preclusters : ```shell -o2-raw-file-reader-workflow --conf file-reader.cfg --loop 0 -b | +o2-raw-file-sampler-workflow --input-conf file-reader.cfg --loop 0 -b | o2-mch-raw-to-digits-workflow -b | o2-mch-digits-to-preclusters-workflow -b | o2-mch-preclusters-sink-workflow -b @@ -49,31 +75,149 @@ dataDescription = RAWDATA filePath = /home/data/data-de819-ped-raw.raw ``` +## Time clustering + +```shell +o2-mch-digits-to-timeclusters-workflow +``` + +Take as input the list of all digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) in the current time frame, with the data description "DIGITS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the digits associated to each interaction, with the data description "DIGITROFS". Send a new list of ROF records that combine all the digits correlated in time within a user-defined time window, with the data description "TIMECLUSTERROFS". + +The option `--time-cluster-width xxx` allows to set the width of the time correlation window. + +The time clustering is based on a brute-force peak search algorithm, which arranges the input digits into coarse time bins. The number of bins in one time cluster window can be set via the `--peak-search-nbins` option. + +## Preclustering + +```shell +o2-mch-digits-to-preclusters-workflow +``` + +Take as input the list of all digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) in the current time frame, with the data description "DIGITS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the digits associated to each interaction. +The ROF records input can have the data description "inputrofs:MCH/DIGITROFS" if the direct output of the raw decoder is used, or "inputrofs:MCH/TIMECLUSTERROFS" if the time clustering output is used (default option). The ROF input description can be set on the command line via the `rof-spec` option. + +Send the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction in three separate messages with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively. + +Option `--check-no-leftover-digits xxx` allows to drop an error message (`xxx = "error"` (default)) or an exception (`xxx = "fatal"`) in case not all the input digits end up in a precluster, or to disable this check (`xxx = "off"`). + +## Clustering + +```shell +o2-mch-preclusters-to-clusters-original-workflow +``` + +Take as input the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the current time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction, with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively. Send the list of all clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction in three separate messages with the data description "CLUSTERS", "CLUSTERDIGITS" and "CLUSTERROFS", respectively. + +Option `--run2-config` allows to configure the clustering to process run2 data. + +Option `--config "file.json"` or `--config "file.ini"` allows to change the clustering parameters from a configuration file. This file can be either in JSON or in INI format, as described below: + +* Example of configuration file in JSON format: +```json +{ + "MCHClustering": { + "lowestPadCharge": "4.", + "defaultClusterResolution": "0.4" + } +} +``` +* Example of configuration file in INI format: +```ini +[MCHClustering] +lowestPadCharge=4. +defaultClusterResolution=0.4 +``` + +Option `--configKeyValues "key1=value1;key2=value2;..."` allows to change the clustering parameters from the command line. The parameters changed from the command line will supersede the ones changed from a configuration file. + +* Example of parameters changed from the command line: +```shell +--configKeyValues "MCHClustering.lowestPadCharge=4.;MCHClustering.defaultClusterResolution=0.4" +``` + +## CTF encoding/decoding + +Entropy encoding is done be attaching the `o2-mch-entropy-encoder-workflow` to the output of `DIGITS` and `DIGITROF` data-descriptions, providing `Digit` and `ROFRecord` respectively. Afterwards the encoded data can be stored by the `o2-ctf-writer-workflow`. + +```shell +o2-raw-file-reader-workflow --input-conf raw/MCH/MCHraw.cfg | o2-mch-raw-to-digits-workflow | o2-mch-entropy-encoder-workflow | o2-ctf-writer-workflow --onlyDet MCH +``` + +The decoding is done automatically by the `o2-ctf-reader-workflow`. + +## Local to global cluster transformation + +The `o2-mch-clusters-transformer-workflow` takes as input the list of all clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)), in local reference frame, in the current time frame, with the data description "CLUSTERS". + +It sends the list of the same clusters, but converted in global reference frame, with the data description "GLOBALCLUSTERS". + +To test it one can use e.g. a sampler-transformer-sink pipeline as such : + +``` +o2-mch-clusters-sampler-workflow + -b --nEventsPerTF 1000 --infile someclusters.data | +o2-mch-clusters-transformer-workflow + -b --geometry Detectors/MUON/MCH/Geometry/Test/ideal-geometry-o2.json | +o2-mch-clusters-sink-workflow + -b --txt --outfile global-clusters.txt --no-digits --global +``` + ## Tracking ### Original track finder -`o2-mch-clusters-to-tracks-original-workflow` +```shell +o2-mch-clusters-to-tracks-original-workflow +``` -Take as input the list of clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) of the current event with the data description "CLUSTERS" and send the list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) and the list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) in two separate messages with the data description "TRACKS" and "TRACKCLUSTERS", respectively. +Take as input the list of all clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) in the current time frame, with the data description "CLUSTERS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction, with the data description "CLUSTERROFS". Send the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the time frame, the list of all associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction in three separate messages with the data description "TRACKS", "TRACKCLUSTERS" and "TRACKROFS", respectively. Options `--l3Current xxx` and `--dipoleCurrent yyy` allow to specify the current in L3 and in the dipole to be used to set the magnetic field. -Option `--moreCandidates` allows to enable the search for more track candidates in stations 4 & 5. - Option `--debug x` allows to enable the debug level x (0 = no debug, 1 or 2). +Option `--config "file.json"` or `--config "file.ini"` allows to change the tracking parameters from a configuration file. This file can be either in JSON or in INI format, as described below: + +* Example of configuration file in JSON format: +```json +{ + "MCHTracking": { + "chamberResolutionY": "0.1", + "requestStation[1]": "false", + "moreCandidates": "true" + } +} +``` +* Example of configuration file in INI format: +```ini +[MCHTracking] +chamberResolutionY=0.1 +requestStation[1]=false +moreCandidates=true +``` + +Option `--configKeyValues "key1=value1;key2=value2;..."` allows to change the tracking parameters from the command line. The parameters changed from the command line will supersede the ones changed from a configuration file. + +* Example of parameters changed from the command line: +```shell +--configKeyValues "MCHTracking.chamberResolutionY=0.1;MCHTracking.requestStation[1]=false;MCHTracking.moreCandidates=true" +``` + ### New track finder -`o2-mch-clusters-to-tracks-workflow` +```shell +o2-mch-clusters-to-tracks-workflow +``` Same behavior and options as [Original track finder](#original-track-finder) ## Track extrapolation to vertex -`o2-mch-tracks-to-tracks-at-vertex-workflow` +```shell +o2-mch-tracks-to-tracks-at-vertex-workflow +``` -Take as input the vertex position (`Point3D<double>`) and the list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) of the current event with the data description "VERTEX" and "TRACKS", respectively, and send the list of tracks at vertex (`TrackAtVtxStruct` as described below) with the data description "TRACKSATVERTEX". +Take as input the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the current time frame, the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction and their vertex position (`Point3D<double>`), with the data description "TRACKS", "TRACKROFS" and "VERTICES", respectively. Send the list of all tracks at vertex (`TrackAtVtxStruct` as described below) in the time frame with the data description "TRACKSATVERTEX". ```c++ struct TrackAtVtxStruct { @@ -88,44 +232,86 @@ Options `--l3Current xxx` and `--dipoleCurrent yyy` allow to specify the current ## Track fitter -`o2-mch-tracks-to-tracks-workflow` +```shell +o2-mch-tracks-to-tracks-workflow +``` -Take as input the list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) and the list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) of the current event with the data description "TRACKSIN" and "TRACKCLUSTERSIN", respectively, and send the list of refitted MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) and the list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) in two separate messages with the data description "TRACKS" and "TRACKCLUSTERS", respectively. +Take as input the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the current time frame, the list of all associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction, with the data description "TRACKSIN", "TRACKCLUSTERSIN" and "TRACKROFSIN", respectively. Send the list of all refitted MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the time frame, the list of all associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction in three separate messages with the data description "TRACKS", "TRACKCLUSTERS" and "TRACKROFS", respectively. Options `--l3Current xxx` and `--dipoleCurrent yyy` allow to specify the current in L3 and in the dipole to be used to set the magnetic field. ## Samplers +### Digit sampler + +```shell +o2-mch-digits-sampler-workflow --infile "digits.in" +``` + +where `digits.in` is a binary file containing for each event: + +* number of digits (int) +* list of digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) + +Send the list of all digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) in the current time frame, with the data description "DIGITS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the digits associated to each interaction, with the data description "DIGITROFS". + +Option `--useRun2DigitUID` allows to specify that the input digits data member mPadID contains the digit UID in run2 format and need to be converted in the corresponding run3 pad ID. + +Option `--print` allows to print the digitUID - padID conversion in the terminal. + +Option `--nEvents xxx` allows to limit the number of events to process (all by default). + +Option `--event xxx` allows to process only this event. + +Option `--nEventsPerTF xxx` allows to set the number of events (i.e. ROF records) to send per time frame (default = 1). + ### Cluster sampler ```shell -o2-mch-clusters-sampler-workflow --infile "clusters.in" +o2-mch-clusters-sampler-workflow --infile "clusters.in" [--global] ``` where `clusters.in` is a binary file containing for each event: * number of clusters (int) * number of associated digits (int) -* list of clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) -* list of associated digits ([Digit](../Base/include/MCHBase/Digit.h)) +* list of clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) +* list of associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) + +Send the list of all clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) in the current time frame, with the data description "CLUSTERS" (or "GLOBALCLUSTERS" if `--global` option is used), and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction, with the data description "CLUSTERROFS". -Send the list of clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) of the current event with the data description "CLUSTERS". +Option `--nEventsPerTF xxx` allows to set the number of events (i.e. ROF records) to send per time frame (default = 1). ### Track sampler -`o2-mch-tracks-sampler-workflow --infile "tracks.in"` +```shell +o2-mch-tracks-sampler-workflow --infile "tracks.in" +``` where `tracks.in` is a binary file with the same format as the one written by the workflow [o2-mch-tracks-sink-workflow](#track-sink) -Send the list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) and the list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) in two separate messages with the data description "TRACKS" and "TRACKCLUSTERS", respectively. +Send the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the current time frame, the list of all associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction in three separate messages with the data description "TRACKS", "TRACKCLUSTERS" and "TRACKROFS", respectively. + +Option `--forTrackFitter` allows to send the messages with the data description "TRACKSIN", "TRACKCLUSTERSIN" and TRACKROFSIN, respectively, as expected by the workflow [o2-mch-tracks-to-tracks-workflow](#track-fitter). + +Option `--nEventsPerTF xxx` allows to set the number of events (i.e. ROF records) to send per time frame (default = 1). + +### Track reader -Option `--forTrackFitter` allows to send the messages with the data description "TRACKSIN" and "TRACKCLUSTERSIN", respectively, as expected by the workflow `o2-mch-tracks-to-tracks-workflow` described below. +``` +o2-mch-tracks-reader-workflow --infile mchtracks.root +``` + +Does the same work as the [Track sampler](#track-sampler) but starting from a Root file (`mchtracks.root`) containing `TRACKS`, `TRACKROFS` and `TRACKCLUSTERS` containers written e.g. by the [o2-mch-tracks-writer-workflow](#track-writer). +Note that a very basic utility also exists to get a textual dump of a Root tracks file : `o2-mch-tracks-file-dumper`. ### Vertex sampler -`o2-mch-vertex-sampler-workflow` +```shell +o2-mch-vertex-sampler-workflow +``` -Send the vertex position (`Point3D<double>`) of the current event with the data description "VERTEX". +Take as input the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) in the current time frame, with the data description "TRACKROFS". Send the list of all vertex positions (`Point3D<double>`) in the time frame, one per interaction, with the data description "VERTICES". Option `--infile "vertices.in"` allows to read the position of the vertex from the binary file `vertices.in` containing for each event: @@ -138,23 +324,63 @@ If no binary file is provided, the vertex is always set to (0,0,0). ## Sinks -### Preclusters sink +### Precluster sink + +```shell +o2-mch-preclusters-sink-workflow --outfile "preclusters.out" +``` + +Take as input the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the current time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction, with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively, and write them event-by-event in the binary file `preclusters.out` with the following format for each event: + +* number of preclusters (int) +* number of associated digits (int) +* list of preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) +* list of associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) + +Option `--txt` allows to write the preclusters in the output file in text format. + +Option `--useRun2DigitUID` allows to convert the run3 pad ID stored in the digit data member mPadID into a digit UID in run2 format. + +### Cluster sink -`o2-mch-preclusters-sink-workflow` +```shell +o2-mch-clusters-sink-workflow --outfile "clusters.out" [--txt] [--no-digits] [--global] +``` + +Take as input the list of all clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) in the current time frame, and, optionnally, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction, with the data description "CLUSTERS" (or "GLOBALCLUSTERS" if `--global` option is used), "CLUSTERDIGITS" (unless `--no-digits` option is used) and "CLUSTERROFS", respectively, and write them event-by-event in the binary file `clusters.out` with the following format for each event: + +* number of clusters (int) +* number of associated digits (int) (= 0 if `--no-digits` is used) +* list of clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) +* list of associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h))(unless option `--no-digits` is used) + +Option `--txt` allows to write the clusters in the output file in text format. + +Option `--useRun2DigitUID` allows to convert the run3 pad ID stored in the digit data member mPadID into a digit UID in run2 format. ### Track sink -`o2-mch-tracks-sink-workflow --outfile "tracks.out"` +```shell +o2-mch-tracks-sink-workflow --outfile "tracks.out" +``` -Take as input the list of tracks at vertex (`TrackAtVtxStruct` as described above), the list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) and the list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) of the current event with the data description "TRACKSATVERTEX", "TRACKS" and "TRACKCLUSTERS", respectively, and write them in the binary file `tracks.out` with the following format: +Take as input the list of all tracks at vertex ([TrackAtVtxStruct](#track-extrapolation-to-vertex)) in the current time frame, the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)), the list of all associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the MCH tracks associated to each interaction, with the data description "TRACKSATVERTEX", "TRACKS", "TRACKCLUSTERS" and "TRACKROFS", respectively, and write them event-by-event in the binary file `tracks.out` with the following format for each event: * number of tracks at vertex (int) * number of MCH tracks (int) * number of associated clusters (int) -* list of tracks at vertex (`TrackAtVtxStruct` as described above) +* list of tracks at vertex ([TrackAtVtxStruct](#track-extrapolation-to-vertex)) * list of MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) -* list of associated clusters ([ClusterStruct](../Base/include/MCHBase/ClusterBlock.h)) +* list of associated clusters ([ClusterStruct](../include/DataFormatsMCH/ClusterBlock.h)) Option `--tracksAtVertexOnly` allows to take as input and write only the tracks at vertex (number of MCH tracks and number of associated clusters = 0). Option `--mchTracksOnly` allows to take as input and write only the MCH tracks and associated clusters (number of tracks at vertex = 0). + +### Track writer + +```shell +o2-mch-tracks-writer-workflow --outfile "mchtracks.root" +``` + +Does the same kind of work as the [track sink](#track-sink) but the output is in Root format instead of custom binary one. It is implemented using the generic [MakeRootTreeWriterSpec](/DPLUtils/MakeRootTreeWriterSpec.h) and thus offers the same options. diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/ClusterFinderOriginalSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/ClusterFinderOriginalSpec.h index bf6aabcdf7f8e..5d6524cc37d5d 100644 --- a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/ClusterFinderOriginalSpec.h +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/ClusterFinderOriginalSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getClusterFinderOriginalSpec(); +o2::framework::DataProcessorSpec getClusterFinderOriginalSpec(const char* specName = "mch-cluster-finder-original"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/DataDecoderSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/DataDecoderSpec.h index 57820cd722f47..7d28d09db18b1 100644 --- a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/DataDecoderSpec.h +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/DataDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,8 @@ namespace mch namespace raw { -o2::framework::DataProcessorSpec getDecodingSpec(std::string inputSpec = "TF:MCH/RAWDATA"); +o2::framework::DataProcessorSpec getDecodingSpec(const char* specName = "mch-data-decoder", std::string inputSpec = "TF:MCH/RAWDATA", + bool askDISTSTF = false); } // end namespace raw } // end namespace mch diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/EntropyDecoderSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..580f7a8486ce1 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to MCH {Digit,ROFRecord} stream + +#ifndef O2_MCH_ENTROPYDECODER_SPEC +#define O2_MCH_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mch +{ +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(const char* specName = "mch-entropy-decoder"); + +} // namespace mch +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/PreClusterFinderSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/PreClusterFinderSpec.h index 586b458688d45..28136d106820d 100644 --- a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/PreClusterFinderSpec.h +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/PreClusterFinderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,9 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getPreClusterFinderSpec(); +o2::framework::DataProcessorSpec + getPreClusterFinderSpec(const char* specName = "PreClusterFinder", + const char* digitRofDataDescription = "DIGITROFS"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TimeClusterFinderSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TimeClusterFinderSpec.h new file mode 100644 index 0000000000000..87817bf3defc6 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TimeClusterFinderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TimeClusterFinderSpec.h +/// \brief Definition of a data processor to run the time clusterizer +/// +/// \author Andrea Ferrero, CEA + +#ifndef O2_MCH_TIMECLUSTERFINDERSPEC_H_ +#define O2_MCH_TIMECLUSTERFINDERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mch +{ + +o2::framework::DataProcessorSpec getTimeClusterFinderSpec(const char* specName = "mch-time-cluster-finder"); + +} // end namespace mch +} // end namespace o2 + +#endif // O2_MCH_TIMECLUSTERFINDERSPEC_H_ diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackReaderSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackReaderSpec.h new file mode 100644 index 0000000000000..3f21e8dd4f96e --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackReaderSpec.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_WORKFLOW_TRACK_READER_SPEC_H +#define O2_MCH_WORKFLOW_TRACK_READER_SPEC_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2::mch +{ +o2::framework::DataProcessorSpec getTrackReaderSpec(bool useMC, const char* specName = "mch-tracks-reader"); +} + +#endif diff --git a/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackWriterSpec.h b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackWriterSpec.h new file mode 100644 index 0000000000000..562ae5c794cb8 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/include/MCHWorkflow/TrackWriterSpec.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_WORKFLOW_TRACK_WRITER_SPEC_H +#define O2_MCH_WORKFLOW_TRACK_WRITER_SPEC_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2::mch +{ +o2::framework::DataProcessorSpec getTrackWriterSpec(bool useMC, const char* specName = "mch-track-writer", const char* fileName = "mchtracks.root"); +} + +#endif diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx index 1b18156c737b3..16a065e8d38bc 100644 --- a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,8 +20,10 @@ #include <fstream> #include <chrono> #include <vector> - #include <stdexcept> +#include <string> + +#include <gsl/span> #include "Framework/CallbackService.h" #include "Framework/ConfigParamRegistry.h" @@ -31,9 +34,11 @@ #include "Framework/Task.h" #include "Framework/Logger.h" -#include "MCHBase/Digit.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" #include "MCHBase/PreCluster.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHClustering/ClusterFinderOriginal.h" namespace o2 @@ -53,7 +58,12 @@ class ClusterFinderOriginalTask /// Prepare the clusterizer LOG(INFO) << "initializing cluster finder"; - mClusterFinder.init(); + auto config = ic.options().get<std::string>("config"); + if (!config.empty()) { + o2::conf::ConfigurableParam::updateFromFile(config, "MCHClustering", true); + } + bool run2Config = ic.options().get<bool>("run2-config"); + mClusterFinder.init(run2Config); /// Print the timer and clear the clusterizer when the processing is over ic.services().get<CallbackService>().set(CallbackService::Id::Stop, [this]() { @@ -65,42 +75,81 @@ class ClusterFinderOriginalTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// read the preclusters and associated digits, clusterize and send the clusters + /// read the preclusters and associated digits, clusterize and send the clusters for all events in the TF // get the input preclusters and associated digits + auto preClusterROFs = pc.inputs().get<gsl::span<ROFRecord>>("preclusterrofs"); auto preClusters = pc.inputs().get<gsl::span<PreCluster>>("preclusters"); auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); - // clusterize every preclusters - auto tStart = std::chrono::high_resolution_clock::now(); - mClusterFinder.reset(); - for (const auto& preCluster : preClusters) { - mClusterFinder.findClusters(digits.subspan(preCluster.firstDigit, preCluster.nDigits)); + //LOG(INFO) << "received time frame with " << preClusterROFs.size() << " interactions"; + + // create the output messages for clusters and attached digits + auto& clusterROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"clusterrofs"}); + auto& clusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"clusters"}); + auto& usedDigits = pc.outputs().make<std::vector<Digit>>(OutputRef{"clusterdigits"}); + + clusterROFs.reserve(preClusterROFs.size()); + for (const auto& preClusterROF : preClusterROFs) { + + //LOG(INFO) << "processing interaction: " << preClusterROF.getBCData() << "..."; + + // clusterize every preclusters + auto tStart = std::chrono::high_resolution_clock::now(); + mClusterFinder.reset(); + for (const auto& preCluster : preClusters.subspan(preClusterROF.getFirstIdx(), preClusterROF.getNEntries())) { + mClusterFinder.findClusters(digits.subspan(preCluster.firstDigit, preCluster.nDigits)); + } + auto tEnd = std::chrono::high_resolution_clock::now(); + mTimeClusterFinder += tEnd - tStart; + + // fill the ouput messages + clusterROFs.emplace_back(preClusterROF.getBCData(), clusters.size(), mClusterFinder.getClusters().size(), + preClusterROF.getBCWidth()); + writeClusters(clusters, usedDigits); } - auto tEnd = std::chrono::high_resolution_clock::now(); - mTimeClusterFinder += tEnd - tStart; - // send the output messages - pc.outputs().snapshot(Output{"MCH", "CLUSTERS", 0, Lifetime::Timeframe}, mClusterFinder.getClusters()); - pc.outputs().snapshot(Output{"MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}, mClusterFinder.getUsedDigits()); + LOGP(info, "Found {:4d} clusters from {:4d} preclusters in {:2d} ROFs", + clusters.size(), preClusters.size(), preClusterROFs.size()); } private: + //_________________________________________________________________________________________________ + void writeClusters(std::vector<ClusterStruct, o2::pmr::polymorphic_allocator<ClusterStruct>>& clusters, + std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>& usedDigits) const + { + /// fill the output messages with clusters and attached digits of the current event + /// modify the references to the attached digits according to their position in the global vector + + auto clusterOffset = clusters.size(); + clusters.insert(clusters.end(), mClusterFinder.getClusters().begin(), mClusterFinder.getClusters().end()); + + auto digitOffset = usedDigits.size(); + usedDigits.insert(usedDigits.end(), mClusterFinder.getUsedDigits().begin(), mClusterFinder.getUsedDigits().end()); + + for (auto itCluster = clusters.begin() + clusterOffset; itCluster < clusters.end(); ++itCluster) { + itCluster->firstDigit += digitOffset; + } + } + ClusterFinderOriginal mClusterFinder{}; ///< clusterizer std::chrono::duration<double> mTimeClusterFinder{}; ///< timer }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getClusterFinderOriginalSpec() +o2::framework::DataProcessorSpec getClusterFinderOriginalSpec(const char* specName) { return DataProcessorSpec{ - "ClusterFinderOriginal", - Inputs{InputSpec{"preclusters", "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, + specName, + Inputs{InputSpec{"preclusterrofs", "MCH", "PRECLUSTERROFS", 0, Lifetime::Timeframe}, + InputSpec{"preclusters", "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, InputSpec{"digits", "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "CLUSTERS", 0, Lifetime::Timeframe}, - OutputSpec{"MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"clusterrofs"}, "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"clusters"}, "MCH", "CLUSTERS", 0, Lifetime::Timeframe}, + OutputSpec{{"clusterdigits"}, "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<ClusterFinderOriginalTask>()}, - Options{}}; + Options{{"config", VariantType::String, "", {"JSON or INI file with clustering parameters"}}, + {"run2-config", VariantType::Bool, false, {"setup for run2 data"}}}}; } } // end namespace mch diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.cxx deleted file mode 100644 index 77ae8cdcac199..0000000000000 --- a/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterSamplerSpec.cxx -/// \brief Implementation of a data processor to read and send clusters -/// -/// \author Philippe Pillot, Subatech - -#include "ClusterSamplerSpec.h" - -#include <iostream> -#include <fstream> - -#include <stdexcept> - -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Lifetime.h" -#include "Framework/Output.h" -#include "Framework/Task.h" -#include "Framework/Logger.h" - -#include "MCHBase/ClusterBlock.h" -#include "MCHBase/Digit.h" - -namespace o2 -{ -namespace mch -{ - -using namespace std; -using namespace o2::framework; - -class ClusterSamplerTask -{ - public: - //_________________________________________________________________________________________________ - void init(framework::InitContext& ic) - { - /// Get the input file from the context - LOG(INFO) << "initializing cluster sampler"; - - auto inputFileName = ic.options().get<std::string>("infile"); - mInputFile.open(inputFileName, ios::binary); - if (!mInputFile.is_open()) { - throw invalid_argument("Cannot open input file" + inputFileName); - } - - auto stop = [this]() { - /// close the input file - LOG(INFO) << "stop cluster sampler"; - this->mInputFile.close(); - }; - ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); - } - - //_________________________________________________________________________________________________ - void run(framework::ProcessingContext& pc) - { - /// send the clusters of the current event - - // get the number of clusters and associated digits - int nClusters(0); - mInputFile.read(reinterpret_cast<char*>(&nClusters), sizeof(int)); - if (mInputFile.fail()) { - pc.services().get<ControlService>().endOfStream(); - return; // probably reached eof - } - int nDigits(0); - mInputFile.read(reinterpret_cast<char*>(&nDigits), sizeof(int)); - - if (nClusters < 0 || nDigits < 0) { - throw length_error("incorrect message payload"); - } - - // create the output message - auto clusters = pc.outputs().make<ClusterStruct>(Output{"MCH", "CLUSTERS", 0, Lifetime::Timeframe}, nClusters); - - // fill clusters in O2 format, if any - if (nClusters > 0) { - mInputFile.read(reinterpret_cast<char*>(clusters.data()), clusters.size_bytes()); - for (auto& cluster : clusters) { - cluster.ex = 0.2f; - cluster.ey = 0.2f; - } - } else { - LOG(INFO) << "event is empty"; - } - - // skip the digits if any - if (nDigits > 0) { - mInputFile.seekg(nDigits * sizeof(Digit), std::ios::cur); - } - } - - private: - std::ifstream mInputFile{}; ///< input file -}; - -//_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getClusterSamplerSpec() -{ - return DataProcessorSpec{ - "ClusterSampler", - Inputs{}, - Outputs{OutputSpec{"MCH", "CLUSTERS", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask<ClusterSamplerTask>()}, - Options{{"infile", VariantType::String, "", {"input filename"}}}}; -} - -} // end namespace mch -} // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.h b/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.h deleted file mode 100644 index 3d6739bf662df..0000000000000 --- a/Detectors/MUON/MCH/Workflow/src/ClusterSamplerSpec.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterSamplerSpec.h -/// \brief Definition of a data processor to read and send clusters -/// -/// \author Philippe Pillot, Subatech - -#ifndef O2_MCH_CLUSTERSAMPLERSPEC_H_ -#define O2_MCH_CLUSTERSAMPLERSPEC_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mch -{ - -o2::framework::DataProcessorSpec getClusterSamplerSpec(); - -} // end namespace mch -} // end namespace o2 - -#endif // O2_MCH_CLUSTERSAMPLERSPEC_H_ diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx deleted file mode 100644 index d8ed38121c68b..0000000000000 --- a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterSinkSpec.cxx -/// \brief Implementation of a data processor to write clusters -/// -/// \author Philippe Pillot, Subatech - -#include "ClusterSinkSpec.h" - -#include <iostream> -#include <fstream> - -#include <array> -#include <stdexcept> -#include <vector> - -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Lifetime.h" -#include "Framework/Task.h" -#include "Framework/Logger.h" - -#include "MCHBase/Digit.h" -#include "MCHBase/ClusterBlock.h" -#include "MCHMappingInterface/Segmentation.h" - -namespace o2 -{ -namespace mch -{ - -using namespace std; -using namespace o2::framework; - -class ClusterSinkTask -{ - public: - //_________________________________________________________________________________________________ - void init(framework::InitContext& ic) - { - /// Get the output file from the context - LOG(INFO) << "initializing cluster sink"; - - mText = ic.options().get<bool>("txt"); - - auto outputFileName = ic.options().get<std::string>("outfile"); - mOutputFile.open(outputFileName, (mText ? ios::out : (ios::out | ios::binary))); - if (!mOutputFile.is_open()) { - throw invalid_argument("Cannot open output file" + outputFileName); - } - - mUseRun2DigitUID = ic.options().get<bool>("useRun2DigitUID"); - - auto stop = [this]() { - /// close the output file - LOG(INFO) << "stop cluster sink"; - this->mOutputFile.close(); - }; - ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); - } - - //_________________________________________________________________________________________________ - void run(framework::ProcessingContext& pc) - { - /// dump the clusters with associated digits of the current event - - // get the input clusters and associated digits - auto clusters = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); - auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); - - if (mText) { - // write the clusters in ascii format - mOutputFile << clusters.size() << " clusters:" << endl; - for (const auto& cluster : clusters) { - mOutputFile << cluster << endl; - } - } else { - // write the number of clusters - int nClusters = clusters.size(); - mOutputFile.write(reinterpret_cast<char*>(&nClusters), sizeof(int)); - - // write the total number of digits in these clusters - int nDigits = digits.size(); - mOutputFile.write(reinterpret_cast<char*>(&nDigits), sizeof(int)); - - // write the clusters - mOutputFile.write(reinterpret_cast<const char*>(clusters.data()), clusters.size_bytes()); - - // write the digits (after converting the pad ID into a digit UID if requested) - if (mUseRun2DigitUID) { - std::vector<Digit> digitsCopy(digits.begin(), digits.end()); - convertPadID2DigitUID(digitsCopy); - mOutputFile.write(reinterpret_cast<char*>(digitsCopy.data()), digitsCopy.size() * sizeof(Digit)); - } else { - mOutputFile.write(reinterpret_cast<const char*>(digits.data()), digits.size_bytes()); - } - } - } - - private: - //_________________________________________________________________________________________________ - void convertPadID2DigitUID(std::vector<Digit>& digits) - { - /// convert the pad ID (i.e. index) in O2 mapping into a digit UID in run2 format - - // cathode number of the bending plane for each DE - static const std::array<std::vector<int>, 10> bendingCathodes{ - {{0, 1, 0, 1}, - {0, 1, 0, 1}, - {0, 1, 0, 1}, - {0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, - {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}}; - - for (auto& digit : digits) { - - int deID = digit.getDetID(); - auto& segmentation = mapping::segmentation(deID); - int padID = digit.getPadID(); - int cathode = bendingCathodes[deID / 100 - 1][deID % 100]; - if (!segmentation.isBendingPad(padID)) { - cathode = 1 - cathode; - } - int manuID = segmentation.padDualSampaId(padID); - int manuCh = segmentation.padDualSampaChannel(padID); - - int digitID = (deID) | (manuID << 12) | (manuCh << 24) | (cathode << 30); - digit.setPadID(digitID); - } - } - - std::ofstream mOutputFile{}; ///< output file - bool mText = false; ///< output clusters in text format - bool mUseRun2DigitUID = false; ///< true if Digit.mPadID = digit UID in run2 format -}; - -//_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getClusterSinkSpec() -{ - return DataProcessorSpec{ - "ClusterSink", - Inputs{InputSpec{"clusters", "MCH", "CLUSTERS", 0, Lifetime::Timeframe}, - InputSpec{"digits", "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}}, - Outputs{}, - AlgorithmSpec{adaptFromTask<ClusterSinkTask>()}, - Options{{"outfile", VariantType::String, "clusters.out", {"output filename"}}, - {"txt", VariantType::Bool, false, {"output clusters in text format"}}, - {"useRun2DigitUID", VariantType::Bool, false, {"mPadID = digit UID in run2 format"}}}}; -} - -} // end namespace mch -} // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.h b/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.h deleted file mode 100644 index 20ea0deac3191..0000000000000 --- a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterSinkSpec.h -/// \brief Definition of a data processor to write clusters -/// -/// \author Philippe Pillot, Subatech - -#ifndef O2_MCH_CLUSTERSINKSPEC_H_ -#define O2_MCH_CLUSTERSINKSPEC_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mch -{ - -o2::framework::DataProcessorSpec getClusterSinkSpec(); - -} // end namespace mch -} // end namespace o2 - -#endif // O2_MCH_CLUSTERSINKSPEC_H_ diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.cxx new file mode 100644 index 0000000000000..db0f154af442b --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.cxx @@ -0,0 +1,113 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ClusterTransformerSpec.h" + +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Logger.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "MathUtils/Cartesian.h" +#include <algorithm> +#include <chrono> +#include <filesystem> +#include <fstream> +#include <vector> + +using namespace std; +using namespace o2::framework; +namespace fs = std::filesystem; + +namespace o2::mch +{ + +// convert all clusters from local to global reference frames +void local2global(geo::TransformationCreator transformation, + gsl::span<const ClusterStruct> localClusters, + std::vector<ClusterStruct, o2::pmr::polymorphic_allocator<ClusterStruct>>& globalClusters) +{ + int i{0}; + globalClusters.insert(globalClusters.end(), localClusters.begin(), localClusters.end()); + for (auto& c : localClusters) { + auto deId = c.getDEId(); + o2::math_utils::Point3D<float> local{c.x, c.y, c.z}; + auto t = transformation(deId); + auto global = t(local); + auto& gcluster = globalClusters[i]; + gcluster.x = global.x(); + gcluster.y = global.y(); + gcluster.z = global.z(); + i++; + } +} + +class ClusterTransformerTask +{ + public: + void init(InitContext& ic) + { + auto geoFile = ic.options().get<std::string>("geometry"); + std::string ext = fs::path(geoFile).extension(); + std::transform(ext.begin(), ext.begin(), ext.end(), [](unsigned char c) { return std::tolower(c); }); + + if (ext == ".json") { + std::ifstream in(geoFile); + if (!in.is_open()) { + throw std::invalid_argument("cannot open geometry file" + geoFile); + } + transformation = o2::mch::geo::transformationFromJSON(in); + } else if (ext == ".root") { + o2::base::GeometryManager::loadGeometry(geoFile); + transformation = o2::mch::geo::transformationFromTGeoManager(*gGeoManager); + } else { + throw std::invalid_argument("Geometry can only be in JSON or Root format"); + } + } + + // read the clusters (assumed to be in local reference frame) and + // tranform them into master reference frame. + void run(ProcessingContext& pc) + { + // get the input clusters + auto localClusters = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); + + // create the output message + auto& globalClusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"globalclusters"}); + + local2global(transformation, localClusters, globalClusters); + } + + public: + o2::mch::geo::TransformationCreator transformation; +}; + +DataProcessorSpec getClusterTransformerSpec(const char* specName) +{ + std::string inputConfig = fmt::format("rofs:MCH/CLUSTERROFS;clusters:MCH/CLUSTERS"); + return DataProcessorSpec{ + specName, + Inputs{o2::framework::select(inputConfig.c_str())}, + Outputs{OutputSpec{{"globalclusters"}, "MCH", "GLOBALCLUSTERS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<ClusterTransformerTask>()}, + Options{ + {"geometry", VariantType::String, o2::base::NameConf::getGeomFileName(), {"input geometry file (JSON or Root format)"}}}}; +} + +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.h b/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.h new file mode 100644 index 0000000000000..88ed7519aacc6 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/ClusterTransformerSpec.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_WORKFLOW_CLUSTER_TRANSFORMER_SPEC_H +#define O2_MCH_WORKFLOW_CLUSTER_TRANSFORMER_SPEC_H +#include "Framework/DataProcessorSpec.h" + +namespace o2::mch +{ +o2::framework::DataProcessorSpec getClusterTransformerSpec(const char* specName = "mch-cluster-transformer"); +}; + +#endif diff --git a/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx index e763d202f1d66..dfd0ec029a0d8 100644 --- a/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx @@ -1,14 +1,14 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// /// /// \file DatDecoderSpec.cxx /// \author Andrea Ferrero @@ -19,6 +19,7 @@ #include <random> #include <iostream> #include <fstream> +#include <chrono> #include <stdexcept> #include <array> #include <functional> @@ -27,21 +28,29 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" #include "Framework/WorkflowSpec.h" +#include "Framework/DataRefUtils.h" -#include "DPLUtils/DPLRawParser.h" -#include "MCHBase/Digit.h" #include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" +#include "CommonConstants/LHCConstants.h" +#include "DetectorsRaw/HBFUtils.h" + +#include "DataFormatsMCH/Digit.h" #include "MCHRawCommon/DataFormats.h" -#include "MCHRawDecoder/OrbitInfo.h" -#include "MCHRawDecoder/PageDecoder.h" +#include "MCHRawCommon/CoDecParam.h" +#include "MCHRawDecoder/DataDecoder.h" +#include "MCHRawDecoder/ROFFinder.h" #include "MCHRawElecMap/Mapper.h" #include "MCHMappingInterface/Segmentation.h" #include "MCHWorkflow/DataDecoderSpec.h" -#include "DetectorsRaw/RDHUtils.h" + +//#define MCH_RAW_DATADECODER_DEBUG_DIGIT_TIME 1 namespace o2 { @@ -55,210 +64,68 @@ using namespace o2::framework; using namespace o2::mch::mapping; using RDH = o2::header::RDHAny; -std::array<int, 64> refManu2ds_st345 = { - 63, 62, 61, 60, 59, 57, 56, 53, 51, 50, 47, 45, 44, 41, 38, 35, - 36, 33, 34, 37, 32, 39, 40, 42, 43, 46, 48, 49, 52, 54, 55, 58, - 7, 8, 5, 2, 6, 1, 3, 0, 4, 9, 10, 15, 17, 18, 22, 25, - 31, 30, 29, 28, 27, 26, 24, 23, 20, 21, 16, 19, 12, 14, 11, 13}; -std::array<int, 64> refDs2manu_st345; - -int manu2ds(int i) -{ - return refManu2ds_st345[i]; -} - -int ds2manu(int i) -{ - return refDs2manu_st345[i]; -} - -// custom hash can be a standalone function object: -struct OrbitInfoHash { - std::size_t operator()(OrbitInfo const& info) const noexcept - { - return std::hash<uint64_t>{}(info.get()); - } -}; - //======================= // Data decoder class DataDecoderTask { - private: - void decodeBuffer(gsl::span<const std::byte> page, std::vector<o2::mch::Digit>& digits) - { - size_t ndigits{0}; - - uint32_t orbit; - - auto channelHandler = [&](DsElecId dsElecId, uint8_t channel, o2::mch::raw::SampaCluster sc) { - if (mDs2manu) { - channel = ds2manu(int(channel)); - } - if (mPrint) { - auto s = asString(dsElecId); - auto ch = fmt::format("{}-CH{}", s, channel); - std::cout << "dsElecId: " << ch << std::endl; - } - uint32_t digitadc(0); - if (sc.isClusterSum()) { - digitadc = sc.chargeSum; - } else { - for (auto& s : sc.samples) { - digitadc += s; - } - } - - int deId{-1}; - int dsIddet{-1}; - if (auto opt = mElec2Det(dsElecId); opt.has_value()) { - DsDetId dsDetId = opt.value(); - dsIddet = dsDetId.dsId(); - deId = dsDetId.deId(); - } - if (mPrint) { - std::cout << "deId " << deId << " dsIddet " << dsIddet << " channel " << (int)channel << std::endl; - } - - if (deId < 0 || dsIddet < 0) { - return; - } - - int padId = -1; - try { - const Segmentation& segment = segmentation(deId); - padId = segment.findPadByFEE(dsIddet, int(channel)); - if (mPrint) { - std::cout << "DS " << (int)dsElecId.elinkId() << " CHIP " << ((int)channel) / 32 << " CH " << ((int)channel) % 32 << " ADC " << digitadc << " DE# " << deId << " DSid " << dsIddet << " PadId " << padId << std::endl; - } - } catch (const std::exception& e) { - std::cout << "Failed to get padId: " << e.what() << std::endl; - return; - } - - Digit::Time time; - time.sampaTime = sc.sampaTime; - time.bunchCrossing = sc.bunchCrossing; - time.orbit = orbit; - - digits.emplace_back(o2::mch::Digit(deId, padId, digitadc, time, sc.nofSamples())); - - if (mPrint) { - std::cout << "DIGIT STORED:\nADC " << digits.back().getADC() << " DE# " << digits.back().getDetID() << " PadId " << digits.back().getPadID() << " time " << digits.back().getTime().sampaTime << std::endl; - } - ++ndigits; - }; - - const auto patchPage = [&](gsl::span<const std::byte> rdhBuffer) { - auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(rdhBuffer[0]))); - mNrdhs++; - auto cruId = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF; - auto flags = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF00; - auto endpoint = o2::raw::RDHUtils::getEndPointID(rdhAny); - auto feeId = cruId * 2 + endpoint + flags; - auto linkId = o2::raw::RDHUtils::getLinkID(rdhAny); - o2::raw::RDHUtils::setFEEID(rdhAny, feeId); - orbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdhAny); - if (mPrint) { - std::cout << mNrdhs << "--\n"; - o2::raw::RDHUtils::printRDH(rdhAny); - } - }; - - patchPage(page); - - // add orbit to vector if not present yet - mOrbits.emplace(page); - - if (!mDecoder) { - mDecoder = mFee2Solar ? o2::mch::raw::createPageDecoder(page, channelHandler, mFee2Solar) - : o2::mch::raw::createPageDecoder(page, channelHandler); - } - mDecoder(page); - } - - private: - std::string readFileContent(const std::string& filename) - { - std::string content; - std::string s; - std::ifstream in(filename); - while (std::getline(in, s)) { - content += s; - content += " "; - } - return content; - } - - void initElec2DetMapper(const std::string& filename) - { - if (filename.empty()) { - mElec2Det = createElec2DetMapper<ElectronicMapperGenerated>(); - } else { - ElectronicMapperString::sFecMap = readFileContent(filename); - mElec2Det = createElec2DetMapper<ElectronicMapperString>(); - } - } - - void initFee2SolarMapper(const std::string& filename) - { - if (filename.empty()) { - mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperGenerated>(); - } else { - ElectronicMapperString::sCruMap = readFileContent(filename); - mFee2Solar = createFeeLink2SolarMapper<ElectronicMapperString>(); - } - } - public: + DataDecoderTask(std::string spec) : mInputSpec(spec) {} + //_________________________________________________________________________________________________ void init(framework::InitContext& ic) { - mNrdhs = 0; - - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - if (refManu2ds_st345[j] != i) { - continue; - } - refDs2manu_st345[i] = j; - break; - } - } - - mDs2manu = ic.options().get<bool>("ds2manu"); - mPrint = ic.options().get<bool>("print"); - + SampaChannelHandler channelHandler; + RdhHandler rdhHandler; + + auto ds2manu = ic.options().get<bool>("ds2manu"); + auto sampaBcOffset = CoDecParam::Instance().sampaBcOffset; + mDebug = ic.options().get<bool>("debug"); + mCheckROFs = ic.options().get<bool>("check-rofs"); + mDummyROFs = ic.options().get<bool>("dummy-rofs"); auto mapCRUfile = ic.options().get<std::string>("cru-map"); auto mapFECfile = ic.options().get<std::string>("fec-map"); + auto useDummyElecMap = ic.options().get<bool>("dummy-elecmap"); + mDecoder = new DataDecoder(channelHandler, rdhHandler, sampaBcOffset, mapCRUfile, mapFECfile, ds2manu, mDebug, + useDummyElecMap); - initFee2SolarMapper(mapCRUfile); - initElec2DetMapper(mapFECfile); + auto stop = [this]() { + LOG(info) << "mch-data-decoder: decoding duration = " << mTimeDecoding.count() * 1000 / mTFcount << " us / TF"; + LOG(info) << "mch-data-decoder: ROF finder duration = " << mTimeROFFinder.count() * 1000 / mTFcount << " us / TF"; + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); } //_________________________________________________________________________________________________ - void - decodeTF(framework::ProcessingContext& pc, std::vector<o2::mch::Digit>& digits) + // the decodeTF() function processes the messages generated by the (sub)TimeFrame builder + void decodeTF(framework::ProcessingContext& pc) { + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + mFirstTForbit = dh->firstTForbit; + + mDecoder->setFirstOrbitInTF(mFirstTForbit); + + if (mDebug) { + LOG(INFO) << "[DataDecoderSpec::run] first TF orbit is " << mFirstTForbit; + } + // get the input buffer auto& inputs = pc.inputs(); - DPLRawParser parser(inputs, o2::framework::select("TF:MCH/RAWDATA")); - + DPLRawParser parser(inputs, o2::framework::select(mInputSpec.c_str())); for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - auto const* rdh = it.get_if<RDH>(); auto const* raw = it.raw(); - size_t payloadSize = it.size(); - if (payloadSize == 0) { + if (!raw) { continue; } + size_t payloadSize = it.size(); gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(raw), sizeof(RDH) + payloadSize); - decodeBuffer(buffer, digits); + mDecoder->decodeBuffer(buffer); } } //_________________________________________________________________________________________________ - void decodeReadout(const o2::framework::DataRef& input, std::vector<o2::mch::Digit>& digits) + // the decodeReadout() function processes the messages generated by o2-mch-cru-page-reader-workflow + void decodeReadout(const o2::framework::DataRef& input) { static int nFrame = 1; // get the input buffer @@ -266,16 +133,11 @@ class DataDecoderTask return; } - const auto* header = o2::header::get<header::DataHeader*>(input.header); - if (!header) { - return; - } - auto const* raw = input.payload; // size of payload - size_t payloadSize = header->payloadSize; + size_t payloadSize = DataRefUtils::getPayloadSize(input); - if (mPrint) { + if (mDebug) { std::cout << nFrame << " payloadSize=" << payloadSize << std::endl; } nFrame += 1; @@ -283,30 +145,54 @@ class DataDecoderTask return; } + const RDH* rdh = reinterpret_cast<const RDH*>(raw); + mFirstTForbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdh); + mDecoder->setFirstOrbitInTF(mFirstTForbit); + gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(raw), payloadSize); - decodeBuffer(buffer, digits); + mDecoder->decodeBuffer(buffer); } - //_________________________________________________________________________________________________ - void run(framework::ProcessingContext& pc) + void sendEmptyOutput(framework::DataAllocator& output) { - std::vector<o2::mch::Digit> digits; - - mOrbits.clear(); + decltype(mDecoder->getOrbits()) orbits{}; + decltype(mDecoder->getDigits()) digits{}; + std::vector<ROFRecord> rofs; + output.snapshot(Output{header::gDataOriginMCH, "DIGITS", 0}, digits); + output.snapshot(Output{header::gDataOriginMCH, "DIGITROFS", 0}, rofs); + output.snapshot(Output{header::gDataOriginMCH, "ORBITS", 0}, orbits); + } - decodeTF(pc, digits); - for (auto&& input : pc.inputs()) { - if (input.spec->binding == "readout") { - decodeReadout(input, digits); + bool isDroppedTF(framework::ProcessingContext& pc) + { + /// If we see requested data type input + /// with 0xDEADBEEF subspec and 0 payload this means that the + /// "delayed message" mechanism created it in absence of real data + /// from upstream, i.e. the TF was dropped. + constexpr auto origin = header::gDataOriginMCH; + o2::framework::InputSpec dummy{"dummy", + framework::ConcreteDataMatcher{origin, + header::gDataDescriptionRawData, + 0xDEADBEEF}}; + for (const auto& ref : o2::framework::InputRecordWalker(pc.inputs(), {dummy})) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + return true; } } + return false; + } - if (mPrint) { - for (auto d : digits) { - std::cout << " DE# " << d.getDetID() << " PadId " << d.getPadID() << " ADC " << d.getADC() << " time " << d.getTime().sampaTime << std::endl; - } + //_________________________________________________________________________________________________ + void run(framework::ProcessingContext& pc) + { + if (isDroppedTF(pc)) { + sendEmptyOutput(pc.outputs()); + return; } + static int32_t deltaMax = 0; + auto createBuffer = [&](auto& vec, size_t& size) { size = vec.empty() ? 0 : sizeof(*(vec.begin())) * vec.size(); char* buf = nullptr; @@ -324,41 +210,117 @@ class DataDecoderTask return buf; }; + auto tStart = std::chrono::high_resolution_clock::now(); + mDecoder->reset(); + for (auto&& input : pc.inputs()) { + if (input.spec->binding == "readout") { + decodeReadout(input); + } + if (input.spec->binding == "TF") { + decodeTF(pc); + } + } + mDecoder->computeDigitsTime(); + auto tEnd = std::chrono::high_resolution_clock::now(); + mTimeDecoding += tEnd - tStart; + + auto& digits = mDecoder->getDigits(); + auto& orbits = mDecoder->getOrbits(); + +#ifdef MCH_RAW_DATADECODER_DEBUG_DIGIT_TIME + constexpr int BCINORBIT = o2::constants::lhc::LHCMaxBunches; + int32_t bcMax = mNHBPerTF * 3564 - 1; + for (auto d : digits) { + if (d.getTime() < 0 || d.getTime() > bcMax) { + int32_t delta = d.getTime() - bcMax; + if (delta > deltaMax) { + deltaMax = delta; + std::cout << "Max digit time exceeded: TF ORBIT " << mDecoder->getFirstOrbitInTF().value() << " DE# " << d.getDetID() << " PadId " << d.getPadID() << " ADC " << d.getADC() + << " time " << d.getTime() << " (" << bcMax << ", delta=" << delta << ")" << std::endl; + } + } + } +#endif + + tStart = std::chrono::high_resolution_clock::now(); + ROFFinder rofFinder(digits, mFirstTForbit); + rofFinder.process(mDummyROFs); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeROFFinder += tEnd - tStart; + + if (mDebug) { + rofFinder.dumpOutputDigits(); + rofFinder.dumpOutputROFs(); + } + + if (mCheckROFs) { + rofFinder.isRofTimeMonotonic(); + rofFinder.isDigitsTimeAligned(); + } + // send the output buffer via DPL - size_t digitsSize, orbitsSize; - char* digitsBuffer = createBuffer(digits, digitsSize); - char* orbitsBuffer = createBuffer(mOrbits, orbitsSize); + size_t digitsSize, rofsSize, orbitsSize; + char* digitsBuffer = rofFinder.saveDigitsToBuffer(digitsSize); + char* rofsBuffer = rofFinder.saveROFRsToBuffer(rofsSize); + char* orbitsBuffer = createBuffer(orbits, orbitsSize); + + if (mDebug) { + std::cout << "digitsSize " << digitsSize << " rofsSize " << rofsSize << " orbitsSize " << orbitsSize << std::endl; + } // create the output message auto freefct = [](void* data, void*) { free(data); }; - pc.outputs().adoptChunk(Output{"MCH", "DIGITS", 0}, digitsBuffer, digitsSize, freefct, nullptr); - pc.outputs().adoptChunk(Output{"MCH", "ORBITS", 0}, orbitsBuffer, orbitsSize, freefct, nullptr); + pc.outputs().adoptChunk(Output{header::gDataOriginMCH, "DIGITS", 0}, digitsBuffer, digitsSize, freefct, nullptr); + pc.outputs().adoptChunk(Output{header::gDataOriginMCH, "DIGITROFS", 0}, rofsBuffer, rofsSize, freefct, nullptr); + pc.outputs().adoptChunk(Output{header::gDataOriginMCH, "ORBITS", 0}, orbitsBuffer, orbitsSize, freefct, nullptr); + + mTFcount += 1; } private: - Elec2DetMapper mElec2Det{nullptr}; - FeeLink2SolarMapper mFee2Solar{nullptr}; - o2::mch::raw::PageDecoder mDecoder; - size_t mNrdhs{0}; - std::unordered_set<OrbitInfo, OrbitInfoHash> mOrbits; ///< list of orbits in the processed buffer + std::string mInputSpec; /// selection string for the input data + bool mDebug = {false}; /// flag to enable verbose output + bool mCheckROFs = {false}; /// flag to enable consistency checks on the output ROFs + bool mDummyROFs = {false}; /// flag to disable the ROFs finding + uint32_t mFirstTForbit{0}; /// first orbit of the time frame being processed + DataDecoder* mDecoder = {nullptr}; /// pointer to the data decoder instance - std::ifstream mInputFile{}; ///< input file - bool mDs2manu = false; ///< print convert channel numbering from Run3 to Run1-2 order - bool mPrint = false; ///< print digits -}; // namespace raw + uint32_t mTFcount{0}; + + std::chrono::duration<double, std::milli> mTimeDecoding{}; ///< timer + std::chrono::duration<double, std::milli> mTimeROFFinder{}; ///< timer +}; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getDecodingSpec(std::string inputSpec) +o2::framework::DataProcessorSpec getDecodingSpec(const char* specName, std::string inputSpec, + bool askSTFDist) { + auto inputs = o2::framework::select(inputSpec.c_str()); + for (auto& inp : inputs) { + // mark input as optional in order not to block the workflow + // if our raw data happen to be missing in some TFs + inp.lifetime = Lifetime::Optional; + } + if (askSTFDist) { + // request the input FLP/DISTSUBTIMEFRAME/0 that is _guaranteed_ + // to be present, even if none of our raw data is present. + inputs.emplace_back("stfDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } + o2::mch::raw::DataDecoderTask task(inputSpec); return DataProcessorSpec{ - "DataDecoder", - o2::framework::select(inputSpec.c_str()), - Outputs{OutputSpec{"MCH", "DIGITS", 0, Lifetime::Timeframe}, OutputSpec{"MCH", "ORBITS", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask<DataDecoderTask>()}, - Options{{"print", VariantType::Bool, false, {"print digits"}}, + specName, + inputs, + Outputs{OutputSpec{header::gDataOriginMCH, "DIGITS", 0, Lifetime::Timeframe}, + OutputSpec{header::gDataOriginMCH, "DIGITROFS", 0, Lifetime::Timeframe}, + OutputSpec{header::gDataOriginMCH, "ORBITS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<DataDecoderTask>(std::move(task))}, + Options{{"debug", VariantType::Bool, false, {"enable verbose output"}}, {"cru-map", VariantType::String, "", {"custom CRU mapping"}}, {"fec-map", VariantType::String, "", {"custom FEC mapping"}}, - {"ds2manu", VariantType::Bool, false, {"convert channel numbering from Run3 to Run1-2 order"}}}}; + {"dummy-elecmap", VariantType::Bool, false, {"use dummy electronic mapping (for debug, temporary)"}}, + {"ds2manu", VariantType::Bool, false, {"convert channel numbering from Run3 to Run1-2 order"}}, + {"check-rofs", VariantType::Bool, false, {"perform consistency checks on the output ROFs"}}, + {"dummy-rofs", VariantType::Bool, false, {"disable the ROFs finding algorithm"}}}}; } } // namespace raw diff --git a/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..90ede773504f2 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MCH/Workflow/src/DigitReaderSpec.cxx +/// \brief Data processor spec for MCH digits reader device +/// \author Michael Winn <Michael.Winn at cern.ch> +/// \date 17 April 2021 + +#include "DigitReaderSpec.h" + +#include <memory> +#include <sstream> +#include <string> +#include "DPLUtils/RootTreeReader.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Logger.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace mch +{ + +class DigitsReaderDeviceDPL +{ + public: + DigitsReaderDeviceDPL(bool useMC, const std::vector<header::DataDescription>& descriptions) + : mUseMC(useMC), mDescriptions(descriptions) {} + + void init(InitContext& ic) + { + auto filename = ic.options().get<std::string>("mch-digit-infile"); + if (mUseMC) { + mReader = std::make_unique<RootTreeReader>("o2sim", filename.c_str(), -1, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<Digit>>{ + Output{header::gDataOriginMCH, mDescriptions[0], 0, Lifetime::Timeframe}, "MCHDigit"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{ + Output{header::gDataOriginMCH, mDescriptions[1], 0, Lifetime::Timeframe}, "MCHROFRecords"}, + RootTreeReader::BranchDefinition<dataformats::MCTruthContainer<MCCompLabel>>{ + Output{header::gDataOriginMCH, mDescriptions[2], 0, Lifetime::Timeframe}, "MCHMCLabels"}); + } else { + mReader = std::make_unique<RootTreeReader>("o2sim", filename.c_str(), -1, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<Digit>>{ + Output{header::gDataOriginMCH, mDescriptions[0], 0, Lifetime::Timeframe}, "MCHDigit"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{ + Output{header::gDataOriginMCH, mDescriptions[1], 0, Lifetime::Timeframe}, "MCHROFRecords"}); + } + } + + void run(ProcessingContext& pc) + { + if ((++(*mReader))(pc) == false) { + pc.services().get<ControlService>().endOfStream(); + } + } + + private: + std::unique_ptr<RootTreeReader> mReader{}; + std::vector<header::DataDescription> mDescriptions{}; + bool mUseMC = true; +}; + +framework::DataProcessorSpec getDigitReaderSpec(bool useMC, const char* specName) +{ + std::vector<OutputSpec> outputs; + std::vector<header::DataDescription> descriptions; + std::stringstream ss; + ss << "A:" << header::gDataOriginMCH.as<std::string>() << "/DIGITS/0"; + ss << ";B:" << header::gDataOriginMCH.as<std::string>() << "/DIGITROFS/0"; + if (useMC) { + ss << ";C:" << header::gDataOriginMCH.as<std::string>() << "/DIGITLABELS/0"; + } + auto matchers = select(ss.str().c_str()); + for (auto& matcher : matchers) { + outputs.emplace_back(DataSpecUtils::asOutputSpec(matcher)); + descriptions.emplace_back(DataSpecUtils::asConcreteDataDescription(matcher)); + } + + return DataProcessorSpec{ + specName, + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC, descriptions)}, + Options{{"mch-digit-infile", VariantType::String, "mchdigits.root", {"Name of the input file"}}}}; +} +} // namespace mch +} // namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.h b/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.h new file mode 100644 index 0000000000000..33d60ee9d6a14 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/DigitReaderSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MCHWorkflow/DigitReaderSpec.h +/// \brief Data processor specs for MCH digits reader device +/// \author Michael Winn <Michael.Winn at cern.ch> +/// \date 17 April 2021 + +#ifndef O2_MCH_DIGITREADERSPEC_H +#define O2_MCH_DIGITREADERSPEC_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mch +{ +framework::DataProcessorSpec getDigitReaderSpec(bool useMC, const char* specName = "mch-sim-digit-reader"); +} +} // namespace o2 + +#endif diff --git a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx index 0d5338affcaaf..0f7cd51cde55e 100644 --- a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,6 @@ #include <iostream> #include <fstream> - #include <string> #include <stdexcept> #include <vector> @@ -33,7 +33,8 @@ #include "Framework/Task.h" #include "Framework/Logger.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" #include "MCHMappingInterface/Segmentation.h" @@ -59,11 +60,18 @@ class DigitSamplerTask if (!mInputFile.is_open()) { throw invalid_argument("Cannot open input file " + inputFileName); } + if (mInputFile.peek() == EOF) { + throw length_error("input file is empty"); + } mUseRun2DigitUID = ic.options().get<bool>("useRun2DigitUID"); mPrint = ic.options().get<bool>("print"); mNevents = ic.options().get<int>("nevents"); mEvent = ic.options().get<int>("event"); + mNEventsPerTF = ic.options().get<int>("nEventsPerTF"); + if (mNEventsPerTF < 1) { + throw invalid_argument("number of events per time frame must be >= 1"); + } auto stop = [this]() { // close the input file @@ -76,56 +84,104 @@ class DigitSamplerTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// check the number of processed events + /// send the digits of the next event(s) in the current TF + + // skip events until the requested one, if any + while (mCurrentEvent < mEvent && mInputFile.peek() != EOF) { + LOG(INFO) << "skipping event " << mCurrentEvent; + skipOneEvent(); + ++mCurrentEvent; + } - if (mNevents == 0) { + // stop if requested event(s) already processed or eof reached + if (mNevents == 0 || (mEvent >= 0 && mCurrentEvent > mEvent) || mInputFile.peek() == EOF) { pc.services().get<ControlService>().endOfStream(); + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); return; - } else if (mNevents > 0) { - mNevents -= 1; } - // send the digits of the current event - int nDigits(0); + // create the output messages + auto& rofs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofs"}); + auto& digits = pc.outputs().make<std::vector<Digit>>(OutputRef{"digits"}); + + if (mCurrentEvent == mEvent) { + + // send only the requested event + int nDigits = readOneEvent(digits); + rofs.emplace_back(o2::InteractionRecord{0, static_cast<uint32_t>(mCurrentEvent)}, + digits.size() - nDigits, nDigits); + ++mCurrentEvent; + + } else { + + // or loop over the requested number of events (or until eof) and send all of them + rofs.reserve(mNEventsPerTF); + for (int iEvt = 0; iEvt < mNEventsPerTF && mNevents != 0 && mInputFile.peek() != EOF; ++iEvt, --mNevents) { + int nDigits = readOneEvent(digits); + rofs.emplace_back(o2::InteractionRecord{0, static_cast<uint32_t>(mCurrentEvent)}, + digits.size() - nDigits, nDigits); + ++mCurrentEvent; + } + rofs.shrink_to_fit(); // fix error "could not set used size: boost::interprocess::bad_alloc" for some sizes + } + + // convert the digits UID if needed + if (mUseRun2DigitUID) { + convertDigitUID2PadID(digits); + } + } + + private: + //_________________________________________________________________________________________________ + void skipOneEvent() + { + /// drop one event from the input file + + // get the number of digits + int nDigits(-1); mInputFile.read(reinterpret_cast<char*>(&nDigits), sizeof(int)); - if (mInputFile.fail()) { - pc.services().get<ControlService>().endOfStream(); - return; // probably reached eof + if (mInputFile.fail() || nDigits < 0) { + throw length_error("invalid input"); } - // send only the requested event, if any - if (mEvent >= 0) { - ++mCurrentEvent; - if (mCurrentEvent < mEvent) { - std::vector<Digit> digits(nDigits); - mInputFile.read(reinterpret_cast<char*>(digits.data()), nDigits * sizeof(Digit)); - return; - } else if (mCurrentEvent > mEvent) { - pc.services().get<ControlService>().endOfStream(); - return; + // skip the digits if any + if (nDigits > 0) { + mInputFile.seekg(nDigits * sizeof(Digit), std::ios::cur); + if (mInputFile.fail()) { + throw length_error("invalid input"); } } + } + + //_________________________________________________________________________________________________ + int readOneEvent(std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>& digits) + { + /// fill the internal buffer with the digits of the current event - // create the output message - auto digits = pc.outputs().make<Digit>(Output{"MCH", "DIGITS", 0, Lifetime::Timeframe}, nDigits); - if (digits.size() != nDigits) { - throw length_error("incorrect message payload"); + // get the number of digits + int nDigits(-1); + mInputFile.read(reinterpret_cast<char*>(&nDigits), sizeof(int)); + if (mInputFile.fail() || nDigits < 0) { + throw length_error("invalid input"); } - // fill digits in O2 format, if any + // get the digits if any if (nDigits > 0) { - mInputFile.read(reinterpret_cast<char*>(digits.data()), digits.size_bytes()); - if (mUseRun2DigitUID) { - convertDigitUID2PadID(digits); + auto digitOffset = digits.size(); + digits.resize(digitOffset + nDigits); + mInputFile.read(reinterpret_cast<char*>(&digits[digitOffset]), nDigits * sizeof(Digit)); + if (mInputFile.fail()) { + throw length_error("invalid input"); } } else { LOG(INFO) << "event is empty"; } + + return nDigits; } - private: //_________________________________________________________________________________________________ - void convertDigitUID2PadID(gsl::span<Digit> digits) + void convertDigitUID2PadID(std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>& digits) { /// convert the digit UID in run2 format into a pad ID (i.e. index) in O2 mapping @@ -153,22 +209,25 @@ class DigitSamplerTask bool mPrint = false; ///< print digits to terminal int mNevents = -1; ///< number of events to process int mEvent = -1; ///< if mEvent >= 0, process only this event - int mCurrentEvent = -1; ///< current event number + int mCurrentEvent = 0; ///< current event number + int mNEventsPerTF = 1; ///< number of events per time frame }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getDigitSamplerSpec() +o2::framework::DataProcessorSpec getDigitSamplerSpec(const char* specName) { return DataProcessorSpec{ - "DigitSampler", + specName, Inputs{}, - Outputs{OutputSpec{"MCH", "DIGITS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"rofs"}, "MCH", "DIGITROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"digits"}, "MCH", "DIGITS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<DigitSamplerTask>()}, Options{{"infile", VariantType::String, "", {"input file name"}}, {"useRun2DigitUID", VariantType::Bool, false, {"mPadID = digit UID in run2 format"}}, {"print", VariantType::Bool, false, {"print digits"}}, {"nevents", VariantType::Int, -1, {"number of events to process (-1 = all events in the file)"}}, - {"event", VariantType::Int, -1, {"event to process"}}}}; + {"event", VariantType::Int, -1, {"event to process"}}, + {"nEventsPerTF", VariantType::Int, 1, {"number of events per time frame"}}}}; } } // end namespace mch diff --git a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.h b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.h index bc073d1865520..4a6786d02e628 100644 --- a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getDigitSamplerSpec(); +o2::framework::DataProcessorSpec getDigitSamplerSpec(const char* specName = "mch-digit-sampler"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/EntropyDecoderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..8d164c4c09502 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "MCHWorkflow/EntropyDecoderSpec.h" +#include "Framework/Task.h" +#include "MCHCTF/CTFCoder.h" +#include <TStopwatch.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace mch +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::mch::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& rofs = pc.outputs().make<std::vector<o2::mch::ROFRecord>>(OutputRef{"rofs"}); + auto& digits = pc.outputs().make<std::vector<o2::mch::Digit>>(OutputRef{"digits"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::mch::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, rofs, digits); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << digits.size() << " MCH digits in " << rofs.size() << " ROFRecords in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "MCH Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec(const char* specName) +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"rofs"}, "MCH", "DIGITROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"digits"}, "MCH", "DIGITS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + specName, + Inputs{InputSpec{"ctf", "MCH", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace mch +} // namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx index 6e833233243c3..f80b77ab95004 100644 --- a/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,10 @@ #include <fstream> #include <chrono> #include <vector> - #include <stdexcept> +#include <gsl/span> + #include "Framework/CallbackService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" @@ -30,8 +32,10 @@ #include "Framework/Output.h" #include "Framework/Task.h" #include "Framework/Logger.h" +#include "Framework/WorkflowSpec.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" #include "MCHBase/PreCluster.h" #include "MCHPreClustering/PreClusterFinder.h" @@ -63,6 +67,7 @@ class PreClusterFinderTask auto stop = [this]() { LOG(INFO) << "reset precluster finder duration = " << mTimeResetPreClusterFinder.count() << " ms"; LOG(INFO) << "load digits duration = " << mTimeLoadDigits.count() << " ms"; + LOG(INFO) << "discard high occupancy duration = " << mTimeDiscardHighOccupancy.count() << " ms"; LOG(INFO) << "precluster finder duration = " << mTimePreClusterFinder.count() << " ms"; LOG(INFO) << "store precluster duration = " << mTimeStorePreClusters.count() << " ms"; /// Clear the preclusterizer @@ -82,44 +87,69 @@ class PreClusterFinderTask } else if (checkNoLeftoverDigits == "fatal") { mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_FATAL; } + mDiscardHighOccDEs = ic.options().get<bool>("discard-high-occupancy-des"); + mDiscardHighOccEvents = ic.options().get<bool>("discard-high-occupancy-events"); } //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// read the digits, preclusterize and send the preclusters + /// read the digits, preclusterize and send the preclusters for each event in the current TF + + // get the input messages with digits + auto digitROFs = pc.inputs().get<gsl::span<ROFRecord>>("digitrofs"); + auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + + //LOG(INFO) << "received time frame with " << digitROFs.size() << " interactions"; + + // create the output message for precluster ROFs + auto& preClusterROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"preclusterrofs"}); + preClusterROFs.reserve(digitROFs.size()); // prepare to receive new data - auto tStart = std::chrono::high_resolution_clock::now(); - mPreClusterFinder.reset(); mPreClusters.clear(); mUsedDigits.clear(); - auto tEnd = std::chrono::high_resolution_clock::now(); - mTimeResetPreClusterFinder += tEnd - tStart; + mUsedDigits.reserve(digits.size()); + int nRemovedDigits(0); - // get the input digits - auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + for (const auto& digitROF : digitROFs) { - // load the digits to get the fired pads - tStart = std::chrono::high_resolution_clock::now(); - mPreClusterFinder.loadDigits(digits); - tEnd = std::chrono::high_resolution_clock::now(); - mTimeLoadDigits += tEnd - tStart; + //LOG(INFO) << "processing interaction: " << digitROF.getBCData() << "..."; - // preclusterize - tStart = std::chrono::high_resolution_clock::now(); - int nPreClusters = mPreClusterFinder.run(); - tEnd = std::chrono::high_resolution_clock::now(); - mTimePreClusterFinder += tEnd - tStart; - - // get the preclusters and associated digits - tStart = std::chrono::high_resolution_clock::now(); - mPreClusters.reserve(nPreClusters); // to avoid reallocation if - mUsedDigits.reserve(digits.size()); // the capacity is exceeded - mPreClusterFinder.getPreClusters(mPreClusters, mUsedDigits); + // prepare to receive new data + auto tStart = std::chrono::high_resolution_clock::now(); + mPreClusterFinder.reset(); + auto tEnd = std::chrono::high_resolution_clock::now(); + mTimeResetPreClusterFinder += tEnd - tStart; + + // load the digits to get the fired pads + tStart = std::chrono::high_resolution_clock::now(); + mPreClusterFinder.loadDigits(digits.subspan(digitROF.getFirstIdx(), digitROF.getNEntries())); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeLoadDigits += tEnd - tStart; + + // discard high-occupancy (noisy) DEs and/or events + tStart = std::chrono::high_resolution_clock::now(); + nRemovedDigits += mPreClusterFinder.discardHighOccupancy(mDiscardHighOccDEs, mDiscardHighOccEvents); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeDiscardHighOccupancy += tEnd - tStart; + + // preclusterize + tStart = std::chrono::high_resolution_clock::now(); + int nPreClusters = mPreClusterFinder.run(); + tEnd = std::chrono::high_resolution_clock::now(); + mTimePreClusterFinder += tEnd - tStart; + + // get the preclusters and associated digits + tStart = std::chrono::high_resolution_clock::now(); + preClusterROFs.emplace_back(digitROF.getBCData(), mPreClusters.size(), nPreClusters, digitROF.getBCWidth()); + mPreClusterFinder.getPreClusters(mPreClusters, mUsedDigits); + tEnd = std::chrono::high_resolution_clock::now(); + mTimeStorePreClusters += tEnd - tStart; + } // check sizes of input and output digits vectors - bool digitsSizesDiffer = (mUsedDigits.size() != digits.size()); + bool digitsSizesDiffer = (nRemovedDigits + mUsedDigits.size() != digits.size()); switch (mCheckNoLeftoverDigits) { case CHECK_NO_LEFTOVER_DIGITS_OFF: break; @@ -135,12 +165,9 @@ class PreClusterFinderTask break; }; - tEnd = std::chrono::high_resolution_clock::now(); - mTimeStorePreClusters += tEnd - tStart; - - // send the output messages - pc.outputs().snapshot(Output{"MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, mPreClusters); - pc.outputs().snapshot(Output{"MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}, mUsedDigits); + // create the output messages for preclusters and associated digits + pc.outputs().snapshot(OutputRef{"preclusters"}, mPreClusters); + pc.outputs().snapshot(OutputRef{"preclusterdigits"}, mUsedDigits); } private: @@ -149,24 +176,34 @@ class PreClusterFinderTask std::vector<Digit> mUsedDigits{}; ///< vector of digits in the preclusters int mCheckNoLeftoverDigits{CHECK_NO_LEFTOVER_DIGITS_ERROR}; ///< digits vector size check option + bool mDiscardHighOccDEs = false; ///< discard DEs with occupancy > 20% + bool mDiscardHighOccEvents = false; ///< discard events with >= 5 DEs above 20% occupancy std::chrono::duration<double, std::milli> mTimeResetPreClusterFinder{}; ///< timer std::chrono::duration<double, std::milli> mTimeLoadDigits{}; ///< timer + std::chrono::duration<double, std::milli> mTimeDiscardHighOccupancy{}; ///< timer std::chrono::duration<double, std::milli> mTimePreClusterFinder{}; ///< timer std::chrono::duration<double, std::milli> mTimeStorePreClusters{}; ///< timer }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getPreClusterFinderSpec() +o2::framework::DataProcessorSpec getPreClusterFinderSpec(const char* specName, + const char* digitRofDataDescription) { - std::string helpstr = "check that all digits are included in pre-clusters"; + std::string input = "digits:MCH/DIGITS/0;"; + input += fmt::format("digitrofs:MCH/{}/0", digitRofDataDescription); + + std::string helpstr = "[off/error/fatal] check that all digits are included in pre-clusters"; return DataProcessorSpec{ - "PreClusterFinder", - Inputs{InputSpec{"digits", "MCH", "DIGITS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, - OutputSpec{"MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, + specName, + o2::framework::select(input.c_str()), + Outputs{OutputSpec{{"preclusterrofs"}, "MCH", "PRECLUSTERROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"preclusters"}, "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, + OutputSpec{{"preclusterdigits"}, "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<PreClusterFinderTask>()}, - Options{{"check-no-leftover-digits", VariantType::String, "error", {helpstr}}}}; + Options{{"check-no-leftover-digits", VariantType::String, "error", {helpstr}}, + {"discard-high-occupancy-des", VariantType::Bool, false, {"discard DEs with occupancy > 20%"}}, + {"discard-high-occupancy-events", VariantType::Bool, false, {"discard events with >= 5 DEs above 20% occupancy"}}}}; } } // end namespace mch diff --git a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx index 2721d8c624a2b..296263ba237fb 100644 --- a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,11 +18,12 @@ #include <iostream> #include <fstream> - #include <array> #include <stdexcept> #include <vector> +#include <gsl/span> + #include "Framework/CallbackService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" @@ -30,7 +32,8 @@ #include "Framework/Task.h" #include "Framework/Logger.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" #include "MCHBase/PreCluster.h" #include "MCHMappingInterface/Segmentation.h" @@ -72,49 +75,86 @@ class PreClusterSinkTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// dump the preclusters with associated digits of the current event + /// dump the preclusters with associated digits of all events in the current TF // get the input preclusters and associated digits + auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs"); auto preClusters = pc.inputs().get<gsl::span<PreCluster>>("preclusters"); auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); - if (mText) { - mOutputFile << preClusters.size() << " preclusters:" << endl; - if (mUseRun2DigitUID) { - std::vector<Digit> digitsCopy(digits.begin(), digits.end()); - convertPadID2DigitUID(digitsCopy); - for (const auto& precluster : preClusters) { - precluster.print(mOutputFile, digitsCopy); - } - } else { - for (const auto& precluster : preClusters) { + // convert the pad ID into a digit UID if requested (need to copy the digits to modify them) + std::vector<Digit> digitsCopy{}; + if (mUseRun2DigitUID) { + digitsCopy.insert(digitsCopy.end(), digits.begin(), digits.end()); + convertPadID2DigitUID(digitsCopy); + digits = gsl::span<const Digit>(digitsCopy); + } + + std::vector<PreCluster> eventPreClusters{}; + for (const auto& rof : rofs) { + + if (mText) { + + // write the preclusters of the current event in text format + mOutputFile << rof.getNEntries() << " preclusters:" << endl; + for (const auto& precluster : preClusters.subspan(rof.getFirstIdx(), rof.getNEntries())) { precluster.print(mOutputFile, digits); } - } - } else { - // write the number of preclusters - int nPreClusters = preClusters.size(); - mOutputFile.write(reinterpret_cast<char*>(&nPreClusters), sizeof(int)); - - // write the total number of digits in these preclusters - int nDigits = digits.size(); - mOutputFile.write(reinterpret_cast<char*>(&nDigits), sizeof(int)); - - // write the preclusters - mOutputFile.write(reinterpret_cast<const char*>(preClusters.data()), preClusters.size_bytes()); - - // write the digits (after converting the pad ID into a digit UID if requested) - if (mUseRun2DigitUID) { - std::vector<Digit> digitsCopy(digits.begin(), digits.end()); - convertPadID2DigitUID(digitsCopy); - mOutputFile.write(reinterpret_cast<char*>(digitsCopy.data()), digitsCopy.size() * sizeof(Digit)); + } else { - mOutputFile.write(reinterpret_cast<const char*>(digits.data()), digits.size_bytes()); + + // get the preclusters and associated digits of the current event + auto eventDigits = getEventPreClustersAndDigits(rof, preClusters, digits, eventPreClusters); + + // write the number of preclusters and the total number of digits in these preclusters + int nPreClusters = eventPreClusters.size(); + mOutputFile.write(reinterpret_cast<char*>(&nPreClusters), sizeof(int)); + int nDigits = eventDigits.size(); + mOutputFile.write(reinterpret_cast<char*>(&nDigits), sizeof(int)); + + // write the preclusters and the digits + mOutputFile.write(reinterpret_cast<const char*>(eventPreClusters.data()), + eventPreClusters.size() * sizeof(PreCluster)); + mOutputFile.write(reinterpret_cast<const char*>(eventDigits.data()), eventDigits.size_bytes()); } } } private: + //_________________________________________________________________________________________________ + gsl::span<const Digit> getEventPreClustersAndDigits(const ROFRecord& rof, gsl::span<const PreCluster> preClusters, + gsl::span<const Digit> digits, + std::vector<PreCluster>& eventPreClusters) const + { + /// copy the preclusters of the current event (needed to edit the preclusters) + /// modify the references to the associated digits to start the indexing from 0 + /// return a sub-span with the associated digits + + eventPreClusters.clear(); + + if (rof.getNEntries() < 1) { + return {}; + } + + if (rof.getLastIdx() >= preClusters.size()) { + throw length_error("missing preclusters"); + } + + eventPreClusters.insert(eventPreClusters.end(), preClusters.begin() + rof.getFirstIdx(), + preClusters.begin() + rof.getLastIdx() + 1); + + auto digitOffset = eventPreClusters.front().firstDigit; + for (auto& preCluster : eventPreClusters) { + preCluster.firstDigit -= digitOffset; + } + + if (eventPreClusters.back().lastDigit() + digitOffset >= digits.size()) { + throw length_error("missing digits"); + } + + return digits.subspan(digitOffset, eventPreClusters.back().lastDigit() + 1); + } + //_________________________________________________________________________________________________ void convertPadID2DigitUID(std::vector<Digit>& digits) { @@ -156,11 +196,12 @@ class PreClusterSinkTask }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getPreClusterSinkSpec() +o2::framework::DataProcessorSpec getPreClusterSinkSpec(const char* specName) { return DataProcessorSpec{ - "PreClusterSink", - Inputs{InputSpec{"preclusters", "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, + specName, + Inputs{InputSpec{"rofs", "MCH", "PRECLUSTERROFS", 0, Lifetime::Timeframe}, + InputSpec{"preclusters", "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, InputSpec{"digits", "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, Outputs{}, AlgorithmSpec{adaptFromTask<PreClusterSinkTask>()}, diff --git a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.h b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.h index 8c8481f16a698..bde6a27bbd38b 100644 --- a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getPreClusterSinkSpec(); +o2::framework::DataProcessorSpec getPreClusterSinkSpec(const char* specName = "mch-precluster-sink"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TimeClusterFinderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TimeClusterFinderSpec.cxx new file mode 100644 index 0000000000000..6e5805327ca12 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TimeClusterFinderSpec.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TimeClusterFinderSpec.cxx +/// \brief Implementation of a data processor to run the time clusterizer +/// +/// \author Andrea Ferrero, CEA + +#include "MCHWorkflow/TimeClusterFinderSpec.h" + +#include <iostream> +#include <fstream> +#include <chrono> +#include <vector> + +#include <stdexcept> + +#include <fmt/core.h> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +#include "MCHRawDecoder/OrbitInfo.h" +#include "MCHTimeClustering/ROFTimeClusterFinder.h" + +namespace o2 +{ +namespace mch +{ + +using namespace std; +using namespace o2::framework; + +class TimeClusterFinderTask +{ + public: + //_________________________________________________________________________________________________ + void init(framework::InitContext& ic) + { + mTimeClusterWidth = ic.options().get<int>("max-cluster-width"); + mNbinsInOneWindow = ic.options().get<int>("peak-search-nbins"); + mMinDigitPerROF = ic.options().get<int>("min-digits-per-rof"); + mDebug = ic.options().get<bool>("debug"); + + if (mDebug) { + fair::Logger::SetConsoleColor(true); + } + // number of bins must be >= 3 + if (mNbinsInOneWindow < 3) { + mNbinsInOneWindow = 3; + } + // number of bins must be odd + if ((mNbinsInOneWindow % 2) == 0) { + mNbinsInOneWindow += 1; + } + + LOGP(info, "mTimeClusterWidth={} mNbinsInOneWindow={} mMinDigitPerROF={} mDebug={}", + mTimeClusterWidth, mNbinsInOneWindow, mMinDigitPerROF, mDebug); + auto stop = [this]() { + LOGP(info, "\nfinder duration = {} us / TF\n", mTimeProcess.count() * 1000 / mTFcount); + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + } + + //_________________________________________________________________________________________________ + void run(framework::ProcessingContext& pc) + { + auto rofs = pc.inputs().get<gsl::span<o2::mch::ROFRecord>>("rofs"); + + o2::mch::ROFTimeClusterFinder rofProcessor(rofs, mTimeClusterWidth, mNbinsInOneWindow, 0); + + if (mDebug) { + LOGP(warning, "{:=>60} ", fmt::format("{:6d} Input ROFS", rofs.size())); + //rofProcessor.dumpInputROFs(); + } + + auto tStart = std::chrono::high_resolution_clock::now(); + rofProcessor.process(); + auto tEnd = std::chrono::high_resolution_clock::now(); + mTimeProcess += tEnd - tStart; + + if (mDebug) { + LOGP(warning, "{:=>60} ", fmt::format("{:6d} Output ROFS", rofProcessor.getROFRecords().size())); + //rofProcessor.dumpOutputROFs(); + } + + auto& outRofs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofs"}); + std::copy_if(rofProcessor.getROFRecords().begin(), + rofProcessor.getROFRecords().end(), + std::back_inserter(outRofs), + [this](const o2::mch::ROFRecord& rof) { + return rof.getNEntries() > mMinDigitPerROF; + }); + mTFcount += 1; + } + + private: + std::chrono::duration<double, std::milli> mTimeProcess{}; ///< timer + + uint32_t mTimeClusterWidth; ///< maximum size of one time cluster, in bunch crossings + uint32_t mNbinsInOneWindow; ///< number of time bins considered for the peak search + int mTFcount{0}; ///< number of processed time frames + int mDebug{0}; ///< verbosity flag + int mMinDigitPerROF; // minimum digit per ROF threshold +}; + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getTimeClusterFinderSpec(const char* specName) +{ + return DataProcessorSpec{ + specName, + Inputs{InputSpec{"rofs", header::gDataOriginMCH, "DIGITROFS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"rofs"}, header::gDataOriginMCH, "TIMECLUSTERROFS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<TimeClusterFinderTask>()}, + Options{{"debug", VariantType::Bool, false, {"enable verbose output"}}, + {"max-cluster-width", VariantType::Int, 1000 / 25, {"maximum time width of time clusters, in BC units"}}, + {"peak-search-nbins", VariantType::Int, 5, {"number of time bins for the peak search algorithm (must be an odd number >= 3)"}}, + {"min-digits-per-rof", VariantType::Int, 0, {"minimum number of digits per ROF (below that threshold ROF is discarded)"}}}}; +} + +} // end namespace mch +} // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.cxx index b52e5677f026f..8b80bd4312dda 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,11 +21,15 @@ #include <list> #include <gsl/span> +#include <filesystem> #include <TMath.h> #include <TGeoManager.h> #include <TGeoGlobalMagField.h> +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" @@ -32,13 +37,16 @@ #include "Framework/Output.h" #include "Framework/Task.h" +#include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" #include "MathUtils/Cartesian.h" #include "Field/MagneticField.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" #include "MCHBase/TrackBlock.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/TrackExtrap.h" +#include "TrackAtVtxStruct.h" namespace o2 { @@ -51,13 +59,16 @@ using namespace o2::framework; class TrackAtVertexTask { public: - //_________________________________________________________________________________________________ - void init(framework::InitContext& ic) + void initFromGRP(std::string grpFile) { - /// Prepare the track extrapolation tools - - LOG(INFO) << "initializing track extrapolation to vertex"; + const auto grp = o2::parameters::GRPObject::loadFrom(grpFile); + base::Propagator::initFieldFromGRP(grp); + TrackExtrap::setField(); + base::GeometryManager::loadGeometry(); + } + void initCustom(framework::InitContext& ic) + { if (!gGeoManager) { o2::base::GeometryManager::loadGeometry("O2geometry.root"); if (!gGeoManager) { @@ -74,6 +85,21 @@ class TrackAtVertexTask TGeoGlobalMagField::Instance()->Lock(); TrackExtrap::setField(); } + } + + //_________________________________________________________________________________________________ + void init(framework::InitContext& ic) + { + /// Prepare the track extrapolation tools + + LOG(INFO) << "initializing track extrapolation to vertex"; + + auto grpFile = ic.options().get<std::string>("grp-file"); + if (std::filesystem::exists(grpFile)) { + initFromGRP(grpFile); + } else { + initCustom(ic); + } auto stop = [this]() { LOG(INFO) << "track propagation to vertex duration = " << mElapsedTime.count() << " s"; @@ -84,55 +110,56 @@ class TrackAtVertexTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// propagate the MCH tracks to the vertex and send the results - - // get the vertex - auto vertex = pc.inputs().get<math_utils::Point3D<double>>("vertex"); + /// propagate the MCH tracks to the vertex for each event in the TF and send the results - // get the tracks + // get the ROFs, tracks and vertices + auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs"); auto tracks = pc.inputs().get<gsl::span<TrackMCH>>("tracks"); + auto vertices = pc.inputs().get<gsl::span<math_utils::Point3D<double>>>("vertices"); - // propagate the tracks to the vertex - auto tStart = std::chrono::high_resolution_clock::now(); - extrapTracksToVertex(tracks, vertex); - auto tEnd = std::chrono::high_resolution_clock::now(); - mElapsedTime += tEnd - tStart; + if (vertices.size() != rofs.size()) { + throw length_error("number of vertices different from number of events"); + } + + // for each event, propagate the tracks to the vertex + mTracksAtVtx.clear(); + int iVertex(-1); + int nTracksTot(0); + for (const auto& rof : rofs) { + auto tStart = std::chrono::high_resolution_clock::now(); + nTracksTot += extrapTracksToVertex(tracks.subspan(rof.getFirstIdx(), rof.getNEntries()), vertices[++iVertex]); + auto tEnd = std::chrono::high_resolution_clock::now(); + mElapsedTime += tEnd - tStart; + } // create the output message auto msgOut = pc.outputs().make<char>(Output{"MCH", "TRACKSATVERTEX", 0, Lifetime::Timeframe}, - sizeof(int) + mTracksAtVtx.size() * sizeof(TrackAtVtxStruct)); + mTracksAtVtx.size() * sizeof(int) + nTracksTot * sizeof(TrackAtVtxStruct)); // write the tracks writeTracks(msgOut.data()); } private: - struct TrackAtVtxStruct { - TrackParamStruct paramAtVertex{}; - double dca = 0.; - double rAbs = 0.; - int mchTrackIdx = 0; - }; - //_________________________________________________________________________________________________ - void extrapTracksToVertex(gsl::span<const TrackMCH>& tracks, const math_utils::Point3D<double>& vertex) + int extrapTracksToVertex(gsl::span<const TrackMCH> tracks, const math_utils::Point3D<double>& vertex) { /// compute the tracks parameters at vertex, at DCA and at the end of the absorber + /// return the number of tracks successfully propagated to the vertex - mTracksAtVtx.clear(); + auto& tracksAtVtx = mTracksAtVtx.emplace_back(); int trackIdx(-1); for (const auto& track : tracks) { - // create a new track at vertex pointing to the current track - mTracksAtVtx.emplace_back(); - auto& trackAtVtx = mTracksAtVtx.back(); + // create a new track at vertex pointing to the current track (index within the current event) + auto& trackAtVtx = tracksAtVtx.emplace_back(); trackAtVtx.mchTrackIdx = ++trackIdx; // extrapolate to vertex TrackParam trackParamAtVertex(track.getZ(), track.getParameters()); - if (!TrackExtrap::extrapToVertex(&trackParamAtVertex, vertex.x(), vertex.y(), vertex.z(), 0., 0.)) { - mTracksAtVtx.pop_back(); + if (!TrackExtrap::extrapToVertex(trackParamAtVertex, vertex.x(), vertex.y(), vertex.z(), 0., 0.)) { + tracksAtVtx.pop_back(); continue; } trackAtVtx.paramAtVertex.x = trackParamAtVertex.getNonBendingCoor(); @@ -145,8 +172,8 @@ class TrackAtVertexTask // extrapolate to DCA TrackParam trackParamAtDCA(track.getZ(), track.getParameters()); - if (!TrackExtrap::extrapToVertexWithoutBranson(&trackParamAtDCA, vertex.z())) { - mTracksAtVtx.pop_back(); + if (!TrackExtrap::extrapToVertexWithoutBranson(trackParamAtDCA, vertex.z())) { + tracksAtVtx.pop_back(); continue; } double dcaX = trackParamAtDCA.getNonBendingCoor() - vertex.x(); @@ -155,48 +182,57 @@ class TrackAtVertexTask // extrapolate to the end of the absorber TrackParam trackParamAtRAbs(track.getZ(), track.getParameters()); - if (!TrackExtrap::extrapToZ(&trackParamAtRAbs, -505.)) { - mTracksAtVtx.pop_back(); + if (!TrackExtrap::extrapToZ(trackParamAtRAbs, -505.)) { + tracksAtVtx.pop_back(); continue; } double xAbs = trackParamAtRAbs.getNonBendingCoor(); double yAbs = trackParamAtRAbs.getBendingCoor(); trackAtVtx.rAbs = TMath::Sqrt(xAbs * xAbs + yAbs * yAbs); } + + return tracksAtVtx.size(); } //_________________________________________________________________________________________________ void writeTracks(char* bufferPtr) const { - /// write the track informations in the message payload + /// write the track informations for each event in the message payload - // write the number of tracks - int nTracks = mTracksAtVtx.size(); - memcpy(bufferPtr, &nTracks, sizeof(int)); - bufferPtr += sizeof(int); + for (const auto& tracksAtVtx : mTracksAtVtx) { - // write the tracks - if (nTracks > 0) { - memcpy(bufferPtr, mTracksAtVtx.data(), nTracks * sizeof(TrackAtVtxStruct)); + // write the number of tracks + int nTracks = tracksAtVtx.size(); + memcpy(bufferPtr, &nTracks, sizeof(int)); + bufferPtr += sizeof(int); + + // write the tracks + if (nTracks > 0) { + memcpy(bufferPtr, tracksAtVtx.data(), nTracks * sizeof(TrackAtVtxStruct)); + bufferPtr += nTracks * sizeof(TrackAtVtxStruct); + } } } - std::vector<TrackAtVtxStruct> mTracksAtVtx{}; ///< list of tracks extrapolated to vertex - std::chrono::duration<double> mElapsedTime{}; ///< timer + std::vector<std::vector<TrackAtVtxStruct>> mTracksAtVtx{}; ///< list of tracks extrapolated to vertex for each event + std::chrono::duration<double> mElapsedTime{}; ///< timer }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackAtVertexSpec() +o2::framework::DataProcessorSpec getTrackAtVertexSpec(const char* specName) { return DataProcessorSpec{ - "TrackAtVertex", - Inputs{InputSpec{"vertex", "MCH", "VERTEX", 0, Lifetime::Timeframe}, + specName, + Inputs{InputSpec{"vertices", "MCH", "VERTICES", 0, Lifetime::Timeframe}, + InputSpec{"rofs", "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, InputSpec{"tracks", "MCH", "TRACKS", 0, Lifetime::Timeframe}, InputSpec{"clusters", "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "TRACKSATVERTEX", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"tracksatvertex"}, "MCH", "TRACKSATVERTEX", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<TrackAtVertexTask>()}, - Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}}, - {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}}}}; + Options{ + {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}}, + {"l3Current", VariantType::Float, -30000.0f, {"L3 current"}}, + {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}}}}; } } // namespace mch diff --git a/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.h index d311ae4ec3adf..bf5942e0503fa 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackAtVertexSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackAtVertexSpec(); +o2::framework::DataProcessorSpec getTrackAtVertexSpec(const char* specName = "mch-track-at-vertex"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackAtVtxStruct.h b/Detectors/MUON/MCH/Workflow/src/TrackAtVtxStruct.h new file mode 100644 index 0000000000000..3ca6d8cbbde79 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackAtVtxStruct.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_TRACK_AT_VTX_STRUCT_H +#define O2_MCH_TRACK_AT_VTX_STRUCT_H + +#include "MCHBase/TrackBlock.h" + +namespace o2::mch +{ +struct TrackAtVtxStruct { + TrackParamStruct paramAtVertex{}; + double dca = 0.; + double rAbs = 0.; + int mchTrackIdx = 0; +}; +} // namespace o2::mch + +#endif diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.cxx index a30b8b8027cbe..cd173fcd78a3c 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include <array> #include <list> #include <stdexcept> +#include <string> #include <gsl/span> @@ -31,12 +33,15 @@ #include "Framework/Task.h" #include "Framework/Logger.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/Cluster.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackFinderOriginal.h" +#include "MCHTracking/TrackExtrap.h" namespace o2 { @@ -58,11 +63,12 @@ class TrackFinderTask auto l3Current = ic.options().get<float>("l3Current"); auto dipoleCurrent = ic.options().get<float>("dipoleCurrent"); + auto config = ic.options().get<std::string>("config"); + if (!config.empty()) { + o2::conf::ConfigurableParam::updateFromFile(config, "MCHTracking", true); + } mTrackFinder.init(l3Current, dipoleCurrent); - auto moreCandidates = ic.options().get<bool>("moreCandidates"); - mTrackFinder.findMoreTrackCandidates(moreCandidates); - auto debugLevel = ic.options().get<int>("debug"); mTrackFinder.debug(debugLevel); @@ -77,28 +83,41 @@ class TrackFinderTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// read the clusters of the current event, find tracks and send them + /// for each event in the current TF, read the clusters and find tracks, then send them all - // get the input clusters + // get the input messages with clusters + auto clusterROFs = pc.inputs().get<gsl::span<ROFRecord>>("clusterrofs"); auto clustersIn = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); - std::array<std::list<Cluster>, 10> clusters{}; - for (const auto& cluster : clustersIn) { - clusters[cluster.getChamberId()].emplace_back(cluster); - } - // run the track finder - auto tStart = std::chrono::high_resolution_clock::now(); - const auto& tracks = mTrackFinder.findTracks(&clusters); - auto tEnd = std::chrono::high_resolution_clock::now(); - mElapsedTime += tEnd - tStart; + //LOG(INFO) << "received time frame with " << clusterROFs.size() << " interactions"; // create the output messages for tracks and attached clusters - auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(Output{"MCH", "TRACKS", 0, Lifetime::Timeframe}); - auto& usedClusters = pc.outputs().make<std::vector<ClusterStruct>>(Output{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}); + auto& trackROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"trackrofs"}); + auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracks"}); + auto& usedClusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"trackclusters"}); - // write the messages - if (tracks.size() > 0) { + trackROFs.reserve(clusterROFs.size()); + for (const auto& clusterROF : clusterROFs) { + + //LOG(INFO) << "processing interaction: " << clusterROF.getBCData() << "..."; + + // get the input clusters of the current event + std::array<std::list<Cluster>, 10> clusters{}; + for (const auto& cluster : clustersIn.subspan(clusterROF.getFirstIdx(), clusterROF.getNEntries())) { + clusters[cluster.getChamberId()].emplace_back(cluster); + } + + // run the track finder + auto tStart = std::chrono::high_resolution_clock::now(); + const auto& tracks = mTrackFinder.findTracks(&clusters); + auto tEnd = std::chrono::high_resolution_clock::now(); + mElapsedTime += tEnd - tStart; + + // fill the ouput messages + int trackOffset(mchTracks.size()); writeTracks(tracks, mchTracks, usedClusters); + trackROFs.emplace_back(clusterROF.getBCData(), trackOffset, mchTracks.size() - trackOffset, + clusterROF.getBCWidth()); } } @@ -110,15 +129,18 @@ class TrackFinderTask { /// fill the output messages with tracks and attached clusters - // avoid memory reallocation - mchTracks.reserve(tracks.size()); - usedClusters.reserve(20. * tracks.size()); - for (const auto& track : tracks) { + TrackParam paramAtMID(track.last()); + if (!TrackExtrap::extrapToMID(paramAtMID)) { + LOG(WARNING) << "propagation to MID failed --> track discarded"; + continue; + } + const auto& param = track.first(); mchTracks.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(), - param.getTrackChi2(), usedClusters.size(), track.getNClusters()); + param.getTrackChi2(), usedClusters.size(), track.getNClusters(), + paramAtMID.getZ(), paramAtMID.getParameters(), paramAtMID.getCovariances()); for (const auto& param : track) { usedClusters.emplace_back(param.getClusterPtr()->getClusterStruct()); @@ -131,17 +153,19 @@ class TrackFinderTask }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackFinderOriginalSpec() +o2::framework::DataProcessorSpec getTrackFinderOriginalSpec(const char* specName) { return DataProcessorSpec{ - "TrackFinderOriginal", - Inputs{InputSpec{"clusters", "MCH", "CLUSTERS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "TRACKS", 0, Lifetime::Timeframe}, - OutputSpec{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, + specName, + Inputs{InputSpec{"clusterrofs", "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe}, + InputSpec{"clusters", "MCH", "GLOBALCLUSTERS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"trackrofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe}, + OutputSpec{{"trackclusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<TrackFinderTask>()}, Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}}, {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}}, - {"moreCandidates", VariantType::Bool, false, {"Find more track candidates"}}, + {"config", VariantType::String, "", {"JSON or INI file with tracking parameters"}}, {"debug", VariantType::Int, 0, {"debug level"}}}}; } diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.h index 3861554c661ee..518041dc004f3 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackFinderOriginalSpec(); +o2::framework::DataProcessorSpec getTrackFinderOriginalSpec(const char* specName = "mch-track-finder-original"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.cxx index 430be7df506d4..200718e2e0e31 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,14 @@ #include <unordered_map> #include <list> #include <stdexcept> +#include <string> +#include <filesystem> #include <gsl/span> +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + #include "Framework/CallbackService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" @@ -31,12 +37,15 @@ #include "Framework/Task.h" #include "Framework/Logger.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/Cluster.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackFinder.h" +#include "MCHTracking/TrackExtrap.h" namespace o2 { @@ -56,12 +65,26 @@ class TrackFinderTask LOG(INFO) << "initializing track finder"; - auto l3Current = ic.options().get<float>("l3Current"); - auto dipoleCurrent = ic.options().get<float>("dipoleCurrent"); - mTrackFinder.init(l3Current, dipoleCurrent); + const auto& options = ic.options(); - auto moreCandidates = ic.options().get<bool>("moreCandidates"); - mTrackFinder.findMoreTrackCandidates(moreCandidates); + float l3Current{-3000}; + float dipoleCurrent{-6000}; + + auto grpFile = ic.options().get<std::string>("grp-file"); + if (std::filesystem::exists(grpFile)) { + const auto grp = o2::parameters::GRPObject::loadFrom(grpFile); + l3Current = grp->getL3Current(); + dipoleCurrent = grp->getDipoleCurrent(); + } else { + l3Current = ic.options().get<float>("l3Current"); + dipoleCurrent = ic.options().get<float>("dipoleCurrent"); + } + + auto config = ic.options().get<std::string>("config"); + if (!config.empty()) { + o2::conf::ConfigurableParam::updateFromFile(config, "MCHTracking", true); + } + mTrackFinder.init(l3Current, dipoleCurrent); auto debugLevel = ic.options().get<int>("debug"); mTrackFinder.debug(debugLevel); @@ -77,29 +100,45 @@ class TrackFinderTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// read the clusters of the current event, find tracks and send them + /// for each event in the current TF, read the clusters and find tracks, then send them all - // get the input clusters + // get the input messages with clusters + auto clusterROFs = pc.inputs().get<gsl::span<ROFRecord>>("clusterrofs"); auto clustersIn = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); - std::unordered_map<int, std::list<Cluster>> clusters{}; - for (const auto& cluster : clustersIn) { - clusters[cluster.getDEId()].emplace_back(cluster); - } - // run the track finder - auto tStart = std::chrono::high_resolution_clock::now(); - const auto& tracks = mTrackFinder.findTracks(clusters); - auto tEnd = std::chrono::high_resolution_clock::now(); - mElapsedTime += tEnd - tStart; + //LOG(INFO) << "received time frame with " << clusterROFs.size() << " interactions"; // create the output messages for tracks and attached clusters - auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(Output{"MCH", "TRACKS", 0, Lifetime::Timeframe}); - auto& usedClusters = pc.outputs().make<std::vector<ClusterStruct>>(Output{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}); + auto& trackROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"trackrofs"}); + auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracks"}); + auto& usedClusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"trackclusters"}); + + trackROFs.reserve(clusterROFs.size()); + for (const auto& clusterROF : clusterROFs) { - // write the messages - if (tracks.size() > 0) { + //LOG(INFO) << "processing interaction: " << clusterROF.getBCData() << "..."; + + // get the input clusters of the current event + std::unordered_map<int, std::list<Cluster>> clusters{}; + for (const auto& cluster : clustersIn.subspan(clusterROF.getFirstIdx(), clusterROF.getNEntries())) { + clusters[cluster.getDEId()].emplace_back(cluster); + } + + // run the track finder + auto tStart = std::chrono::high_resolution_clock::now(); + const auto& tracks = mTrackFinder.findTracks(clusters); + auto tEnd = std::chrono::high_resolution_clock::now(); + mElapsedTime += tEnd - tStart; + + // fill the ouput messages + int trackOffset(mchTracks.size()); writeTracks(tracks, mchTracks, usedClusters); + trackROFs.emplace_back(clusterROF.getBCData(), trackOffset, mchTracks.size() - trackOffset, + clusterROF.getBCWidth()); } + + LOGP(info, "Found {:3d} MCH tracks from {:4d} clusters in {:2d} ROFs", + mchTracks.size(), clustersIn.size(), clusterROFs.size()); } private: @@ -110,15 +149,18 @@ class TrackFinderTask { /// fill the output messages with tracks and attached clusters - // avoid memory reallocation - mchTracks.reserve(tracks.size()); - usedClusters.reserve(20. * tracks.size()); - for (const auto& track : tracks) { + TrackParam paramAtMID(track.last()); + if (!TrackExtrap::extrapToMID(paramAtMID)) { + LOG(WARNING) << "propagation to MID failed --> track discarded"; + continue; + } + const auto& param = track.first(); mchTracks.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(), - param.getTrackChi2(), usedClusters.size(), track.getNClusters()); + param.getTrackChi2(), usedClusters.size(), track.getNClusters(), + paramAtMID.getZ(), paramAtMID.getParameters(), paramAtMID.getCovariances()); for (const auto& param : track) { usedClusters.emplace_back(param.getClusterPtr()->getClusterStruct()); @@ -131,17 +173,20 @@ class TrackFinderTask }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackFinderSpec() +o2::framework::DataProcessorSpec getTrackFinderSpec(const char* specName) { return DataProcessorSpec{ - "TrackFinder", - Inputs{InputSpec{"clusters", "MCH", "CLUSTERS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "TRACKS", 0, Lifetime::Timeframe}, - OutputSpec{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, + specName, + Inputs{InputSpec{"clusterrofs", "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe}, + InputSpec{"clusters", "MCH", "GLOBALCLUSTERS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"trackrofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, + OutputSpec{{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe}, + OutputSpec{{"trackclusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<TrackFinderTask>()}, Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}}, {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}}, - {"moreCandidates", VariantType::Bool, false, {"Find more track candidates"}}, + {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}}, + {"config", VariantType::String, "", {"JSON or INI file with tracking parameters"}}, {"debug", VariantType::Int, 0, {"debug level"}}}}; } diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.h index 3f116286e59f5..c2729084c4858 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackFinderSpec(); +o2::framework::DataProcessorSpec getTrackFinderSpec(const char* specName = "mch-track-finder"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.cxx index 30c23b87daf3f..9dbb48164dd69 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,8 +30,9 @@ #include "Framework/Task.h" #include "Framework/Logger.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/Cluster.h" #include "MCHTracking/Track.h" @@ -63,46 +65,61 @@ class TrackFitterTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// read the tracks with attached clusters, refit them and send the new version - - // get the input tracks and attached clusters - auto tracksIn = pc.inputs().get<gsl::span<TrackMCH>>("tracks"); - auto clustersIn = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); - - // create the output messages for refitted tracks and attached clusters - auto& tracksOut = pc.outputs().make<std::vector<TrackMCH>>(Output{"MCH", "TRACKS", 0, Lifetime::Timeframe}); - auto& clustersOut = pc.outputs().make<std::vector<ClusterStruct>>(Output{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}); - - // avoid memory reallocation - tracksOut.reserve(tracksIn.size()); - clustersOut.reserve(clustersIn.size()); - - for (const auto& mchTrack : tracksIn) { - - // get the clusters attached to the track - auto trackClusters = clustersIn.subspan(mchTrack.getFirstClusterIdx(), mchTrack.getNClusters()); - - // create the internal track - Track track{}; - std::list<Cluster> clusters{}; - for (const auto& cluster : trackClusters) { - clusters.emplace_back(cluster); - track.createParamAtCluster(clusters.back()); - } - - // refit the track - try { - mTrackFitter.fit(track); - } catch (exception const& e) { - LOG(ERROR) << "Track fit failed: " << e.what(); - continue; + /// for each event in the current TF, read the tracks with attached clusters, refit them and send the new version + + // get the input ROFs, tracks and attached clusters + auto rofsIn = pc.inputs().get<gsl::span<ROFRecord>>("rofsin"); + auto tracksIn = pc.inputs().get<gsl::span<TrackMCH>>("tracksin"); + auto clustersIn = pc.inputs().get<gsl::span<ClusterStruct>>("clustersin"); + + // create the output messages for ROFs, refitted tracks and attached clusters + auto& rofsOut = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofsout"}); + auto& tracksOut = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracksout"}); + auto& clustersOut = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"clustersout"}); + + rofsOut.reserve(rofsIn.size()); + for (const auto& rof : rofsIn) { + + // loop over tracks of the current ROF + int trackOffset(tracksOut.size()); + for (const auto& mchTrack : tracksIn.subspan(rof.getFirstIdx(), rof.getNEntries())) { + + // get the clusters attached to the track + auto trackClusters = clustersIn.subspan(mchTrack.getFirstClusterIdx(), mchTrack.getNClusters()); + + // create the internal track + Track track{}; + std::list<Cluster> clusters{}; + for (const auto& cluster : trackClusters) { + clusters.emplace_back(cluster); + track.createParamAtCluster(clusters.back()); + } + + // refit the track + try { + mTrackFitter.fit(track); + } catch (exception const& e) { + LOG(ERROR) << "Track fit failed: " << e.what(); + continue; + } + + // propagate the parameters to the MID + TrackParam paramAtMID(track.last()); + if (!TrackExtrap::extrapToMID(paramAtMID)) { + LOG(ERROR) << "propagation to MID failed --> track discarded"; + continue; + } + + // write the refitted track and attached clusters (same as those of the input track) + const auto& param = track.first(); + tracksOut.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(), + param.getTrackChi2(), clustersOut.size(), track.getNClusters(), + paramAtMID.getZ(), paramAtMID.getParameters(), paramAtMID.getCovariances()); + clustersOut.insert(clustersOut.end(), trackClusters.begin(), trackClusters.end()); } - // write the refitted track and attached clusters (same as those of the input track) - const auto& param = track.first(); - tracksOut.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(), - param.getTrackChi2(), clustersOut.size(), track.getNClusters()); - clustersOut.insert(clustersOut.end(), trackClusters.begin(), trackClusters.end()); + // write the current ROF with references to the associated tracks + rofsOut.emplace_back(rof.getBCData(), trackOffset, tracksOut.size() - trackOffset, rof.getBCWidth()); } } @@ -111,14 +128,16 @@ class TrackFitterTask }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackFitterSpec() +o2::framework::DataProcessorSpec getTrackFitterSpec(const char* specName) { return DataProcessorSpec{ - "TrackFitter", - Inputs{InputSpec{"tracks", "MCH", "TRACKSIN", 0, Lifetime::Timeframe}, - InputSpec{"clusters", "MCH", "TRACKCLUSTERSIN", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "TRACKS", 0, Lifetime::Timeframe}, - OutputSpec{"MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, + specName, + Inputs{InputSpec{"rofsin", "MCH", "TRACKROFSIN", 0, Lifetime::Timeframe}, + InputSpec{"tracksin", "MCH", "TRACKSIN", 0, Lifetime::Timeframe}, + InputSpec{"clustersin", "MCH", "TRACKCLUSTERSIN", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{OutputLabel{"rofsout"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, + OutputSpec{OutputLabel{"tracksout"}, "MCH", "TRACKS", 0, Lifetime::Timeframe}, + OutputSpec{OutputLabel{"clustersout"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<TrackFitterTask>()}, Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}}, {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}}}}; diff --git a/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.h index af75dea54db91..565441a6d2d00 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackFitterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackFitterSpec(); +o2::framework::DataProcessorSpec getTrackFitterSpec(const char* specName = "mch-track-fitter"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.cxx new file mode 100644 index 0000000000000..a61efb09a476a --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.cxx @@ -0,0 +1,204 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMCLabelFinderSpec.cxx +/// \brief Implementation of a data processor to match the reconstructed tracks with the simulated ones +/// +/// \author Philippe Pillot, Subatech + +#include "TrackMCLabelFinderSpec.h" + +#include <string> +#include <stdexcept> +#include <unordered_map> +#include <vector> + +#include <gsl/span> + +#include "DetectorsCommonDataFormats/DetID.h" + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/WorkflowSpec.h" + +#include "Steer/MCKinematicsReader.h" + +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/TrackReference.h" + +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/ClusterBlock.h" + +namespace o2 +{ +namespace mch +{ + +using namespace std; +using namespace o2::framework; + +class TrackMCLabelFinderTask +{ + public: + //_________________________________________________________________________________________________ + /// prepare the task from the context + void init(framework::InitContext& ic) + { + LOG(INFO) << "initializing track MC label finder"; + if (!mMCReader.initFromDigitContext(ic.options().get<std::string>("incontext").c_str())) { + throw invalid_argument("initialization of MCKinematicsReader failed"); + } + double sigmaCut = ic.options().get<double>("sigma-cut"); + mMaxMatchingChi2 = 2. * sigmaCut * sigmaCut; + } + + //_________________________________________________________________________________________________ + /// assign every reconstructed track a MC label, pointing to the corresponding particle or fake + void run(framework::ProcessingContext& pc) + { + // get the input messages + auto digitROFs = pc.inputs().get<gsl::span<ROFRecord>>("digitrofs"); + auto digitlabels = pc.inputs().get<const dataformats::MCTruthContainer<MCCompLabel>*>("digitlabels"); + auto trackROFs = pc.inputs().get<gsl::span<ROFRecord>>("trackrofs"); + auto tracks = pc.inputs().get<gsl::span<TrackMCH>>("tracks"); + auto clusters = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); + + // digit and track ROFs must be synchronized + int nROFs = digitROFs.size(); + if (trackROFs.size() != nROFs) { + throw length_error(fmt::format("inconsistent ROFs: {} tracksROFs vs {} digitROFs", trackROFs.size(), nROFs)); + } + + std::vector<o2::MCCompLabel> tracklabels; + + for (int iROF = 0; iROF < nROFs; ++iROF) { + + // skip interation records with no reconstructed tracks + auto trackROF = trackROFs[iROF]; + if (trackROF.getNEntries() == 0) { + continue; + } + + // digits and tracks must belong to the same IR + auto digitROF = digitROFs[iROF]; + if (digitROF.getBCData() != trackROF.getBCData()) { + throw logic_error("inconsistent ROF"); + } + + // get the MC labels of every particles contributing to that IR and produce the associated MC clusters + std::unordered_map<MCCompLabel, std::vector<ClusterStruct>> mcClusterMap{}; + for (int iDigit = digitROF.getFirstIdx(); iDigit <= digitROF.getLastIdx(); ++iDigit) { + for (const auto& label : digitlabels->getLabels(iDigit)) { + if (label.isCorrect() && mcClusterMap.count(label) == 0) { + makeMCClusters(mMCReader.getTrackRefs(label.getSourceID(), label.getEventID(), label.getTrackID()), + mcClusterMap[label]); + } + } + } + + // try to pair every reconstructed tracks with every MC tracks to set MC labels + for (int iTrack = trackROF.getFirstIdx(); iTrack <= trackROF.getLastIdx(); ++iTrack) { + for (const auto& [label, mcClusters] : mcClusterMap) { + if (match(clusters.subspan(tracks[iTrack].getFirstClusterIdx(), tracks[iTrack].getNClusters()), mcClusters)) { + tracklabels.push_back(label); + break; + } + } + if (tracklabels.size() != iTrack + 1) { + tracklabels.push_back(MCCompLabel()); + } + } + } + + // send the track MC labels + pc.outputs().snapshot(OutputRef{"tracklabels"}, tracklabels); + } + + private: + //_________________________________________________________________________________________________ + /// produce the MC clusters by taking the average position of the trackRefs at the entry and exit of each DE + void makeMCClusters(gsl::span<const TrackReference> mcTrackRefs, std::vector<ClusterStruct>& mcClusters) const + { + int deId(-1); + int clusterIdx(0); + for (const auto& trackRef : mcTrackRefs) { + if (trackRef.getDetectorId() != o2::detectors::DetID::MCH) { + deId = -1; + continue; + } + if (trackRef.getUserId() == deId) { + auto& cluster = mcClusters.back(); + cluster.x = (cluster.x + trackRef.X()) / 2.; + cluster.y = (cluster.y + trackRef.Y()) / 2.; + cluster.z = (cluster.z + trackRef.Z()) / 2.; + deId = -1; // to create a new cluster in case the track re-enter the DE (loop) + } else { + deId = trackRef.getUserId(); + mcClusters.push_back({trackRef.X(), trackRef.Y(), trackRef.Z(), 0.f, 0.f, + ClusterStruct::buildUniqueId(deId / 100 - 1, deId, clusterIdx++), 0u, 0u}); + } + } + } + + //_________________________________________________________________________________________________ + /// try to match a reconstructed track with a MC track. Matching conditions: + /// - more than 50% of reconstructed clusters matched with MC clusters + /// - at least 1 matched cluster before and 1 after the dipole + bool match(gsl::span<const ClusterStruct> clusters, const std::vector<ClusterStruct>& mcClusters) const + { + int nMatched(0); + bool hasMatched[5] = {false, false, false, false, false}; + for (const auto& cluster : clusters) { + for (const auto& mcCluster : mcClusters) { + if (cluster.getDEId() == mcCluster.getDEId()) { + double dx = cluster.x - mcCluster.x; + double dy = cluster.y - mcCluster.y; + double chi2 = dx * dx / (cluster.ex * cluster.ex) + dy * dy / (cluster.ey * cluster.ey); + if (chi2 <= mMaxMatchingChi2) { + hasMatched[cluster.getChamberId() / 2] = true; + ++nMatched; + break; + } + } + } + } + return ((hasMatched[0] || hasMatched[1]) && (hasMatched[3] || hasMatched[4]) && 2 * nMatched > clusters.size()); + } + + steer::MCKinematicsReader mMCReader{}; ///< MC reader to retrieve the trackRefs + double mMaxMatchingChi2 = 32.; ///< maximum chi2 to match simulated and reconstructed clusters +}; + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getTrackMCLabelFinderSpec(const char* specName, + const char* digitRofDataDescription) +{ + std::string input = + fmt::format("digitrofs:MCH/{}/0;", digitRofDataDescription); + input += + "digitlabels:MCH/DIGITLABELS/0;" + "trackrofs:MCH/TRACKROFS/0;" + "tracks:MCH/TRACKS/0;" + "clusters:MCH/TRACKCLUSTERS/0"; + return DataProcessorSpec{ + specName, + o2::framework::select(input.c_str()), + Outputs{OutputSpec{{"tracklabels"}, "MCH", "TRACKLABELS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<TrackMCLabelFinderTask>()}, + Options{{"incontext", VariantType::String, "collisioncontext.root", {"Take collision context from this file"}}, + {"sigma-cut", VariantType::Double, 4., {"Sigma cut to match simulated and reconstructed clusters"}}}}; +} + +} // end namespace mch +} // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.h new file mode 100644 index 0000000000000..c7e8aad2554bd --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackMCLabelFinderSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMCLabelFinderSpec.h +/// \brief Definition of a data processor to match the reconstructed tracks with the simulated ones +/// +/// \author Philippe Pillot, Subatech + +#ifndef O2_MCH_TRACKMCLABELFINDERSPEC_H_ +#define O2_MCH_TRACKMCLABELFINDERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mch +{ + +o2::framework::DataProcessorSpec + getTrackMCLabelFinderSpec(const char* specName = "TrackMCLabelFinder", + const char* digitRofDataDescription = "DIGITROFS"); + +} // end namespace mch +} // end namespace o2 + +#endif // O2_MCH_TRACKMCLABELFINDERSPEC_H_ diff --git a/Detectors/MUON/MCH/Workflow/src/TrackReaderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackReaderSpec.cxx new file mode 100644 index 0000000000000..1d6639a9ba41e --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackReaderSpec.cxx @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHWorkflow/TrackReaderSpec.h" + +#include "DPLUtils/RootTreeReader.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Lifetime.h" +#include "Framework/Logger.h" +#include "Framework/Task.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include <iostream> +#include <vector> + +using namespace o2::framework; + +namespace o2::mch +{ + +template <typename T> +void printBranch(char* data, const char* what) +{ + auto tdata = reinterpret_cast<std::vector<T>*>(data); + LOGP(info, "MCH {:d} {:s}", tdata->size(), what); +} + +RootTreeReader::SpecialPublishHook logging{ + [](std::string_view name, ProcessingContext&, Output const&, char* data) -> bool { + if (name == "trackrofs") { + printBranch<ROFRecord>(data, "ROFS"); + } + if (name == "trackclusters") { + printBranch<ClusterStruct>(data, "CLUSTERS"); + } + if (name == "tracks") { + printBranch<TrackMCH>(data, "TRACKS"); + } + if (name == "tracklabels") { + auto tdata = reinterpret_cast<std::vector<o2::MCCompLabel>*>(data); + LOGP(info, "MCH {:d} {:s}", tdata->size(), "LABELS"); + } + return false; + }}; + +struct TrackReader { + std::unique_ptr<RootTreeReader> mTreeReader; + bool mUseMC = false; + TrackReader(bool useMC = false) : mUseMC(useMC) {} + void init(InitContext& ic) + { + if (!mUseMC) { + LOGP(warning, "Not reading MCH Track Labels"); + } + auto treeName = "o2sim"; + auto fileName = ic.options().get<std::string>("infile"); + auto nofEntries{-1}; + if (mUseMC) { + mTreeReader = std::make_unique<RootTreeReader>( + treeName, + fileName.c_str(), + nofEntries, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<TrackMCH>>{Output{"MCH", "TRACKS", 0}, "tracks"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{Output{"MCH", "TRACKROFS", 0}, "trackrofs"}, + RootTreeReader::BranchDefinition<std::vector<ClusterStruct>>{Output{"MCH", "TRACKCLUSTERS", 0}, "trackclusters"}, + RootTreeReader::BranchDefinition<std::vector<o2::MCCompLabel>>{Output{"MCH", "TRACKLABELS", 0}, "tracklabels"}, + &logging); + } else { + mTreeReader = std::make_unique<RootTreeReader>( + treeName, + fileName.c_str(), + nofEntries, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<TrackMCH>>{Output{"MCH", "TRACKS", 0}, "tracks"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{Output{"MCH", "TRACKROFS", 0}, "trackrofs"}, + RootTreeReader::BranchDefinition<std::vector<ClusterStruct>>{Output{"MCH", "TRACKCLUSTERS", 0}, "trackclusters"}, + &logging); + } + } + + void + run(ProcessingContext& pc) + { + if (mTreeReader->next()) { + (*mTreeReader)(pc); + } else { + pc.services().get<ControlService>().endOfStream(); + } + } +}; + +DataProcessorSpec getTrackReaderSpec(bool useMC, const char* specName) +{ + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"trackrofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"trackclusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}); + if (useMC) { + outputSpecs.emplace_back(OutputSpec{{"tracklabels"}, "MCH", "TRACKLABELS", 0, Lifetime::Timeframe}); + } + + auto options = Options{ + {"infile", VariantType::String, "mchtracks.root", {"name of the input track file"}}, + }; + + return DataProcessorSpec{ + specName, + Inputs{}, + outputSpecs, + adaptFromTask<TrackReader>(useMC), + options}; +} +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.cxx index 3c46fc36bce87..25bea40dd84a2 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,9 +30,11 @@ #include "Framework/Task.h" #include "Framework/Logger.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" #include "MCHBase/TrackBlock.h" +#include "TrackAtVtxStruct.h" namespace o2 { @@ -53,7 +56,15 @@ class TrackSamplerTask auto inputFileName = ic.options().get<std::string>("infile"); mInputFile.open(inputFileName, ios::binary); if (!mInputFile.is_open()) { - throw invalid_argument("Cannot open input file" + inputFileName); + throw invalid_argument("cannot open input file" + inputFileName); + } + if (mInputFile.peek() == EOF) { + throw length_error("input file is empty"); + } + + mNEventsPerTF = ic.options().get<int>("nEventsPerTF"); + if (mNEventsPerTF < 1) { + throw invalid_argument("number of events per time frame must be >= 1"); } auto stop = [this]() { @@ -67,72 +78,124 @@ class TrackSamplerTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// send the tracks with attached clusters of the current event + /// send the tracks with attached clusters of the next events in the current TF + + static uint32_t event(0); + + // reached eof + if (mInputFile.peek() == EOF) { + pc.services().get<ControlService>().endOfStream(); + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + return; + } + + // create the output messages + auto& rofs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofs"}); + auto& tracks = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracks"}); + auto& clusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"clusters"}); + + // loop over the requested number of events (or until eof) and fill the messages + for (int iEvt = 0; iEvt < mNEventsPerTF && mInputFile.peek() != EOF; ++iEvt) { + int nTracks = readOneEvent(tracks, clusters); + rofs.emplace_back(o2::InteractionRecord{0, event++}, tracks.size() - nTracks, nTracks); + } + } + + //_________________________________________________________________________________________________ + int readOneEvent(std::vector<TrackMCH, o2::pmr::polymorphic_allocator<TrackMCH>>& tracks, + std::vector<ClusterStruct, o2::pmr::polymorphic_allocator<ClusterStruct>>& clusters) + { + /// fill the output messages with the tracks and attached clusters of the current event + /// modify the references to the attached clusters according to their position in the global vector // read the number of tracks at vertex, MCH tracks and attached clusters int nTracksAtVtx(-1); mInputFile.read(reinterpret_cast<char*>(&nTracksAtVtx), sizeof(int)); if (mInputFile.fail()) { - pc.services().get<ControlService>().endOfStream(); - return; // probably reached eof + throw length_error("invalid input"); } int nMCHTracks(-1); mInputFile.read(reinterpret_cast<char*>(&nMCHTracks), sizeof(int)); + if (mInputFile.fail()) { + throw length_error("invalid input"); + } int nClusters(-1); mInputFile.read(reinterpret_cast<char*>(&nClusters), sizeof(int)); + if (mInputFile.fail()) { + throw length_error("invalid input"); + } if (nTracksAtVtx < 0 || nMCHTracks < 0 || nClusters < 0) { - throw length_error("invalid data input"); + throw length_error("invalid input"); } if (nMCHTracks > 0 && nClusters == 0) { - throw out_of_range("clusters are missing"); + throw length_error("clusters are missing"); } - // create the output messages - auto tracks = pc.outputs().make<TrackMCH>(OutputRef{"tracks"}, nMCHTracks); - auto clusters = pc.outputs().make<ClusterStruct>(OutputRef{"clusters"}, nClusters); - // skip the tracks at vertex if any if (nTracksAtVtx > 0) { mInputFile.seekg(nTracksAtVtx * sizeof(TrackAtVtxStruct), std::ios::cur); + if (mInputFile.fail()) { + throw length_error("invalid input"); + } } - // read the MCH tracks and the attached clusters if (nMCHTracks > 0) { - mInputFile.read(reinterpret_cast<char*>(tracks.data()), tracks.size_bytes()); - mInputFile.read(reinterpret_cast<char*>(clusters.data()), clusters.size_bytes()); + + // read the MCH tracks + int trackOffset = tracks.size(); + tracks.resize(trackOffset + nMCHTracks); + mInputFile.read(reinterpret_cast<char*>(&tracks[trackOffset]), nMCHTracks * sizeof(TrackMCH)); + if (mInputFile.fail()) { + throw length_error("invalid input"); + } + + // read the attached clusters + int clusterOffset = clusters.size(); + clusters.resize(clusterOffset + nClusters); + mInputFile.read(reinterpret_cast<char*>(&clusters[clusterOffset]), nClusters * sizeof(ClusterStruct)); + if (mInputFile.fail()) { + throw length_error("invalid input"); + } + + // modify the cluster references + for (auto itTrack = tracks.begin() + trackOffset; itTrack < tracks.end(); ++itTrack) { + itTrack->setClusterRef(clusterOffset, itTrack->getNClusters()); + clusterOffset += itTrack->getNClusters(); + } + if (clusterOffset != clusters.size()) { + throw length_error("inconsistent cluster references"); + } } - } - private: - struct TrackAtVtxStruct { - TrackParamStruct paramAtVertex{}; - double dca = 0.; - double rAbs = 0.; - int mchTrackIdx = 0; - }; + return nMCHTracks; + } std::ifstream mInputFile{}; ///< input file + int mNEventsPerTF = 1; ///< number of events per time frame }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackSamplerSpec(bool forTrackFitter) +o2::framework::DataProcessorSpec getTrackSamplerSpec(const char* specName, bool forTrackFitter) { Outputs outputs{}; if (forTrackFitter) { + outputs.emplace_back(OutputLabel{"rofs"}, "MCH", "TRACKROFSIN", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"tracks"}, "MCH", "TRACKSIN", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"clusters"}, "MCH", "TRACKCLUSTERSIN", 0, Lifetime::Timeframe); } else { + outputs.emplace_back(OutputLabel{"rofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe); outputs.emplace_back(OutputLabel{"clusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe); } return DataProcessorSpec{ - "TrackSampler", + specName, Inputs{}, outputs, AlgorithmSpec{adaptFromTask<TrackSamplerTask>()}, - Options{{"infile", VariantType::String, "", {"input filename"}}}}; + Options{{"infile", VariantType::String, "", {"input filename"}}, + {"nEventsPerTF", VariantType::Int, 1, {"number of events per time frame"}}}}; } } // end namespace mch diff --git a/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.h index 993d514dbeac8..264d367588e35 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackSamplerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackSamplerSpec(bool forTrackFitter); +o2::framework::DataProcessorSpec getTrackSamplerSpec(const char* specName, bool forTrackFitter); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.cxx index 30efb7d8eadc3..07bdcf2b10c10 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include <iostream> #include <fstream> #include <stdexcept> +#include <vector> #include <gsl/span> @@ -29,8 +31,11 @@ #include "Framework/Task.h" #include "Framework/Logger.h" +#include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/TrackMCH.h" -#include "MCHBase/ClusterBlock.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "MCHBase/TrackBlock.h" +#include "TrackAtVtxStruct.h" namespace o2 { @@ -66,15 +71,15 @@ class TrackSinkTask //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// dump the tracks with attached clusters of the current event + /// dump the tracks and attached clusters for each event in the TF // get the input messages + gsl::span<const ROFRecord> rofs{}; gsl::span<const TrackMCH> tracks{}; - if (pc.inputs().getPos("tracks") >= 0) { - tracks = pc.inputs().get<gsl::span<TrackMCH>>("tracks"); - } gsl::span<const ClusterStruct> clusters{}; - if (pc.inputs().getPos("clusters") >= 0) { + if (pc.inputs().getPos("rofs") >= 0) { + rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs"); + tracks = pc.inputs().get<gsl::span<TrackMCH>>("tracks"); clusters = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); } gsl::span<const char> tracksAtVtx{}; @@ -82,31 +87,128 @@ class TrackSinkTask tracksAtVtx = pc.inputs().get<gsl::span<char>>("tracksAtVtx"); } - // write the number of tracks at vertex, MCH tracks and attached clusters - int nTracksAtVtx = tracksAtVtx.empty() ? 0 : *reinterpret_cast<const int*>(tracksAtVtx.data()); - mOutputFile.write(reinterpret_cast<char*>(&nTracksAtVtx), sizeof(int)); - int nTracks = tracks.size(); - mOutputFile.write(reinterpret_cast<char*>(&nTracks), sizeof(int)); - int nClusters = clusters.size(); - mOutputFile.write(reinterpret_cast<char*>(&nClusters), sizeof(int)); - - // write the tracks at vertex, MCH tracks and attached clusters - if (tracksAtVtx.size() > sizeof(int)) { - mOutputFile.write(&tracksAtVtx[sizeof(int)], tracksAtVtx.size() - sizeof(int)); + // loop over events based on ROF records, if any, or based on the tracks-at-vertex message otherwise + if (!rofs.empty()) { + + int tracksAtVtxOffset(0); + std::vector<TrackMCH> eventTracks{}; + for (const auto& rof : rofs) { + + // get the MCH tracks, attached clusters and corresponding tracks at vertex (if any) + auto eventClusters = getEventTracksAndClusters(rof, tracks, clusters, eventTracks); + auto eventTracksAtVtx = getEventTracksAtVtx(tracksAtVtx, tracksAtVtxOffset); + + // write the number of tracks at vertex, MCH tracks and attached clusters + int nEventTracksAtVtx = eventTracksAtVtx.size() / sizeof(TrackAtVtxStruct); + mOutputFile.write(reinterpret_cast<char*>(&nEventTracksAtVtx), sizeof(int)); + int nEventTracks = eventTracks.size(); + mOutputFile.write(reinterpret_cast<char*>(&nEventTracks), sizeof(int)); + int nEventClusters = eventClusters.size(); + mOutputFile.write(reinterpret_cast<char*>(&nEventClusters), sizeof(int)); + + // write the tracks at vertex, MCH tracks and attached clusters + mOutputFile.write(eventTracksAtVtx.data(), eventTracksAtVtx.size()); + mOutputFile.write(reinterpret_cast<const char*>(eventTracks.data()), eventTracks.size() * sizeof(TrackMCH)); + mOutputFile.write(reinterpret_cast<const char*>(eventClusters.data()), eventClusters.size_bytes()); + } + + // at this point we should have dumped all the tracks at vertex, if any + if (tracksAtVtxOffset != tracksAtVtx.size()) { + throw length_error("inconsistent payload"); + } + + } else if (!tracksAtVtx.empty()) { + + int tracksAtVtxOffset(0); + int zero(0); + while (tracksAtVtxOffset != tracksAtVtx.size()) { + + // get the tracks at vertex + auto eventTracksAtVtx = getEventTracksAtVtx(tracksAtVtx, tracksAtVtxOffset); + + // write the number of tracks at vertex (number of MCH tracks and attached clusters = 0) + int nEventTracksAtVtx = eventTracksAtVtx.size() / sizeof(TrackAtVtxStruct); + mOutputFile.write(reinterpret_cast<char*>(&nEventTracksAtVtx), sizeof(int)); + mOutputFile.write(reinterpret_cast<char*>(&zero), sizeof(int)); + mOutputFile.write(reinterpret_cast<char*>(&zero), sizeof(int)); + + // write the tracks at vertex + mOutputFile.write(eventTracksAtVtx.data(), eventTracksAtVtx.size()); + } + + } else { + throw length_error("empty time frame"); + } + } + + //_________________________________________________________________________________________________ + gsl::span<const ClusterStruct> getEventTracksAndClusters(const ROFRecord& rof, gsl::span<const TrackMCH> tracks, + gsl::span<const ClusterStruct> clusters, + std::vector<TrackMCH>& eventTracks) const + { + /// copy the MCH tracks of the current event (needed to edit the tracks) + /// modify the references to the attached clusters to start the indexing from 0 + /// return a sub-span with the attached clusters + + eventTracks.clear(); + + if (rof.getNEntries() < 1) { + return {}; + } + + if (rof.getLastIdx() >= tracks.size()) { + throw length_error("missing tracks"); + } + + eventTracks.insert(eventTracks.end(), tracks.begin() + rof.getFirstIdx(), tracks.begin() + rof.getLastIdx() + 1); + + int clusterIdxOffset = eventTracks.front().getFirstClusterIdx(); + for (auto& track : eventTracks) { + track.setClusterRef(track.getFirstClusterIdx() - clusterIdxOffset, track.getNClusters()); + } + + if (eventTracks.back().getLastClusterIdx() + clusterIdxOffset >= clusters.size()) { + throw length_error("missing clusters"); } - mOutputFile.write(reinterpret_cast<const char*>(tracks.data()), tracks.size_bytes()); - mOutputFile.write(reinterpret_cast<const char*>(clusters.data()), clusters.size_bytes()); + + return clusters.subspan(clusterIdxOffset, eventTracks.back().getLastClusterIdx() + 1); + } + + //_________________________________________________________________________________________________ + gsl::span<const char> getEventTracksAtVtx(gsl::span<const char> tracksAtVtx, int& tracksAtVtxOffset) const + { + /// return a sub-span with the tracks at vertex of the current event, if any, + /// and move forward the tracksAtVtxOffset to point to the next event + + if (tracksAtVtx.empty()) { + return {}; + } + + if (tracksAtVtx.size() - tracksAtVtxOffset < sizeof(int)) { + throw length_error("inconsistent payload"); + } + + int nEventTracksAtVtx = *reinterpret_cast<const int*>(&tracksAtVtx[tracksAtVtxOffset]); + tracksAtVtxOffset += sizeof(int); + + int payloadSize = nEventTracksAtVtx * sizeof(TrackAtVtxStruct); + if (tracksAtVtx.size() - tracksAtVtxOffset < payloadSize) { + throw length_error("inconsistent payload"); + } + + tracksAtVtxOffset += payloadSize; + return tracksAtVtx.subspan(tracksAtVtxOffset - payloadSize, payloadSize); } - private: std::ofstream mOutputFile{}; ///< output file }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getTrackSinkSpec(bool mchTracks, bool tracksAtVtx) +o2::framework::DataProcessorSpec getTrackSinkSpec(const char* specName, bool mchTracks, bool tracksAtVtx) { Inputs inputs{}; if (mchTracks) { + inputs.emplace_back("rofs", "MCH", "TRACKROFS", 0, Lifetime::Timeframe); inputs.emplace_back("tracks", "MCH", "TRACKS", 0, Lifetime::Timeframe); inputs.emplace_back("clusters", "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe); } @@ -118,7 +220,7 @@ o2::framework::DataProcessorSpec getTrackSinkSpec(bool mchTracks, bool tracksAtV } return DataProcessorSpec{ - "TrackSink", + specName, inputs, Outputs{}, AlgorithmSpec{adaptFromTask<TrackSinkTask>()}, diff --git a/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.h b/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.h index 64e9ba6af64ac..f370e447d84ce 100644 --- a/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/TrackSinkSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getTrackSinkSpec(bool mchTracks, bool tracksAtVtx); +o2::framework::DataProcessorSpec getTrackSinkSpec(const char* specName, bool mchTracks, bool tracksAtVtx); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.cxx b/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.cxx new file mode 100644 index 0000000000000..a864060231513 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TrackTreeReader.h" +#include <limits> +#include <fmt/format.h> + +namespace o2::mch +{ +void AssertBranch(ROOT::Internal::TTreeReaderValueBase& value) +{ + if (value.GetSetupStatus() < 0) { + throw std::invalid_argument(fmt::format("Error {} setting up tree reader for branch {}", + value.GetSetupStatus(), value.GetBranchName())); + } +} + +TrackTreeReader::TrackTreeReader(TTree* tree) : mCurrentRof{std::numeric_limits<size_t>::max()} +{ + if (!tree) { + throw std::invalid_argument("cannot work with a null tree pointer"); + } + if (tree->GetBranchStatus("tracklabels")) { + mLabels = std::make_unique<TTreeReaderValue<std::vector<o2::MCCompLabel>>>(mTreeReader, "tracklabels"); + } + mTreeReader.SetTree(tree); + mTreeReader.Restart(); + mTreeReader.Next(); + mCurrentRof = 0; + AssertBranch(mTracks); + AssertBranch(mRofs); + AssertBranch(mClusters); + if (hasLabels()) { + AssertBranch(*mLabels); + } +} + +bool TrackTreeReader::next(o2::mch::ROFRecord& rof, std::vector<o2::mch::TrackMCH>& tracks, + std::vector<o2::mch::ClusterStruct>& clusters, + std::vector<o2::MCCompLabel>& labels) +{ + if (mCurrentRof >= mRofs->size()) { + if (!mTreeReader.Next()) { + return false; + } + mCurrentRof = 0; + } + + if (mRofs->empty()) { + return false; + } + rof = (*mRofs)[mCurrentRof]; + tracks.clear(); + clusters.clear(); + labels.clear(); + auto& tfTracks = *mTracks; + tracks.insert(tracks.begin(), tfTracks.begin() + rof.getFirstIdx(), tfTracks.begin() + rof.getLastIdx() + 1); + if (!tracks.empty()) { + auto& tfClusters = *mClusters; + clusters.insert(clusters.begin(), tfClusters.begin() + tracks.front().getFirstClusterIdx(), + tfClusters.begin() + tracks.back().getLastClusterIdx() + 1); + } + if (hasLabels()) { + auto& tfLabels = **mLabels; + labels.insert(labels.begin(), tfLabels.begin() + rof.getFirstIdx(), tfLabels.begin() + rof.getLastIdx() + 1); + } + ++mCurrentRof; + return true; +} +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.h b/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.h new file mode 100644 index 0000000000000..5eb0d5943b037 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackTreeReader.h @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MCH_WORKFLOW_TRACK_TREE_READER_H +#define O2_MCH_WORKFLOW_TRACK_TREE_READER_H + +#include "DataFormatsMCH/ClusterBlock.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include <TTreeReader.h> +#include <memory> +#include <vector> + +namespace o2::mch +{ + +class TrackTreeReader +{ + public: + TrackTreeReader(TTree* tree); + + bool next(ROFRecord& rof, + std::vector<TrackMCH>& tracks, + std::vector<ClusterStruct>& clusters, + std::vector<o2::MCCompLabel>& labels); + + bool hasLabels() { return mLabels.get() != nullptr; } + + private: + TTreeReader mTreeReader; + TTreeReaderValue<std::vector<o2::mch::TrackMCH>> mTracks = {mTreeReader, "tracks"}; + TTreeReaderValue<std::vector<o2::mch::ROFRecord>> mRofs = {mTreeReader, "trackrofs"}; + TTreeReaderValue<std::vector<o2::mch::ClusterStruct>> mClusters = {mTreeReader, "trackclusters"}; + std::unique_ptr<TTreeReaderValue<std::vector<o2::MCCompLabel>>> mLabels{}; + size_t mCurrentRof; +}; +} // namespace o2::mch +#endif diff --git a/Detectors/MUON/MCH/Workflow/src/TrackWriterSpec.cxx b/Detectors/MUON/MCH/Workflow/src/TrackWriterSpec.cxx new file mode 100644 index 0000000000000..2e6bb37dd3f42 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/TrackWriterSpec.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MCHWorkflow/TrackWriterSpec.h" + +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "Framework/Logger.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include <vector> + +using namespace o2::framework; + +namespace o2::mch +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +DataProcessorSpec getTrackWriterSpec(bool useMC, const char* specName, const char* fileName) +{ + return MakeRootTreeWriterSpec(specName, + fileName, + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree MCH Standalone Tracks"}, + BranchDefinition<std::vector<TrackMCH>>{InputSpec{"tracks", "MCH", "TRACKS"}, "tracks"}, + BranchDefinition<std::vector<ROFRecord>>{InputSpec{"trackrofs", "MCH", "TRACKROFS"}, "trackrofs"}, + BranchDefinition<std::vector<ClusterStruct>>{InputSpec{"trackclusters", "MCH", "TRACKCLUSTERS"}, "trackclusters"}, + BranchDefinition<std::vector<o2::MCCompLabel>>{InputSpec{"tracklabels", "MCH", "TRACKLABELS"}, "tracklabels", useMC ? 1 : 0})(); +} + +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.cxx index 541ad1568f692..15ae73d0a15d9 100644 --- a/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,6 +32,7 @@ #include "Framework/Logger.h" #include "MathUtils/Cartesian.h" +#include "DataFormatsMCH/ROFRecord.h" namespace o2 { @@ -70,24 +72,31 @@ class VertexSamplerSpec //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { - /// send the vertex of the current event if an input file is provided - /// or the default vertex (0.,0.,0.) otherwise + /// send the vertex of each event in the current TF if an input file is provided + /// or the default vertex (0,0,0) for all events otherwise - // read the corresponding vertex or set it to (0,0,0) - math_utils::Point3D<double> vertex(0., 0., 0.); + // get the track ROFs for each event in the TF + auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs"); + + // create the output message to hold vertices + auto& vertices = pc.outputs().make<std::vector<math_utils::Point3D<double>>>(OutputRef{"vertices"}); + + // read the vertex of each event or set it to (0,0,0) if (mInputFile.is_open()) { int event(-1); - mInputFile.read(reinterpret_cast<char*>(&event), sizeof(int)); - if (mInputFile.fail()) { - throw out_of_range("missing vertex"); - } VertexStruct vtx{}; - mInputFile.read(reinterpret_cast<char*>(&vtx), sizeof(VertexStruct)); - vertex.SetCoordinates(vtx.x, vtx.y, vtx.z); + vertices.reserve(rofs.size()); + for (const auto& rof : rofs) { + mInputFile.read(reinterpret_cast<char*>(&event), sizeof(int)); + if (mInputFile.fail() || event != rof.getBCData().orbit) { + throw out_of_range(std::string("missing vertex for event ") + rof.getBCData().orbit); + } + mInputFile.read(reinterpret_cast<char*>(&vtx), sizeof(VertexStruct)); + vertices.emplace_back(vtx.x, vtx.y, vtx.z); + } + } else { + vertices.resize(rofs.size(), math_utils::Point3D<double>(0., 0., 0.)); } - - // create the output message - pc.outputs().snapshot(Output{"MCH", "VERTEX", 0, Lifetime::Timeframe}, vertex); } private: @@ -101,14 +110,15 @@ class VertexSamplerSpec }; //_________________________________________________________________________________________________ -o2::framework::DataProcessorSpec getVertexSamplerSpec() +o2::framework::DataProcessorSpec getVertexSamplerSpec(const char* specName) { return DataProcessorSpec{ - "VertexSampler", - // the input message is just used to synchronize the sending of the vertex with the track reconstruction - Inputs{InputSpec{"tracks", "MCH", "TRACKS", 0, Lifetime::Timeframe}, + specName, + Inputs{InputSpec{"rofs", "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, + // track and cluster messages are there just to keep things synchronized + InputSpec{"tracks", "MCH", "TRACKS", 0, Lifetime::Timeframe}, InputSpec{"clusters", "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe}}, - Outputs{OutputSpec{"MCH", "VERTEX", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"vertices"}, "MCH", "VERTICES", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<VertexSamplerSpec>()}, Options{{"infile", VariantType::String, "", {"input filename"}}}}; } diff --git a/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.h b/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.h index 2447dd05bf49a..6e311ffe946e3 100644 --- a/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.h +++ b/Detectors/MUON/MCH/Workflow/src/VertexSamplerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,8 +24,7 @@ namespace o2 namespace mch { -o2::framework::DataProcessorSpec getVertexSamplerSpec(); - +o2::framework::DataProcessorSpec getVertexSamplerSpec(const char* specName = "mch-vertex-sampler"); } // end namespace mch } // end namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/clusters-sampler-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/clusters-sampler-workflow.cxx index ed21436dc0bb9..918967d65f005 100644 --- a/Detectors/MUON/MCH/Workflow/src/clusters-sampler-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/clusters-sampler-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,167 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <vector> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" -#include "ClusterSamplerSpec.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "DataFormatsMCH/Digit.h" using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +//_________________________________________________________________________________________________ +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + /// add workflow options. Note that customization needs to be declared before including Framework/runDataProcessing + workflowOptions.emplace_back("global", VariantType::Bool, false, + ConfigParamSpec::HelpString{"assume the read clusters are in global reference frame"}); +} + +#include "Framework/runDataProcessing.h" + +using namespace o2::mch; + +class ClusterSamplerTask +{ + public: + //_________________________________________________________________________________________________ + void init(InitContext& ic) + { + /// Get the input file from the context + LOG(INFO) << "initializing cluster sampler"; + + auto inputFileName = ic.options().get<std::string>("infile"); + mInputFile.open(inputFileName, std::ios::binary); + if (!mInputFile.is_open()) { + throw std::invalid_argument("cannot open input file" + inputFileName); + } + if (mInputFile.peek() == EOF) { + throw std::length_error("input file is empty"); + } + + mNEventsPerTF = ic.options().get<int>("nEventsPerTF"); + if (mNEventsPerTF < 1) { + throw std::invalid_argument("number of events per time frame must be >= 1"); + } + + auto stop = [this]() { + /// close the input file + LOG(INFO) << "stop cluster sampler"; + this->mInputFile.close(); + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + } + + //_________________________________________________________________________________________________ + void run(ProcessingContext& pc) + { + /// send the clusters of the next events in the current TF + + static uint32_t event(0); + + // reached eof + if (mInputFile.peek() == EOF) { + pc.services().get<ControlService>().endOfStream(); + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + return; + } + + // create the output messages + auto& rofs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofs"}); + auto& clusters = pc.outputs().make<std::vector<ClusterStruct>>(OutputRef{"clusters"}); + + // loop over the requested number of events (or until eof) and fill the messages + for (int iEvt = 0; iEvt < mNEventsPerTF && mInputFile.peek() != EOF; ++iEvt) { + int nClusters = readOneEvent(clusters); + rofs.emplace_back(o2::InteractionRecord{0, event++}, clusters.size() - nClusters, nClusters); + } + } + + private: + //_________________________________________________________________________________________________ + int readOneEvent(std::vector<ClusterStruct, o2::pmr::polymorphic_allocator<ClusterStruct>>& clusters) + { + /// fill the internal buffer with the clusters of the current event + + // get the number of clusters + int nClusters(-1); + mInputFile.read(reinterpret_cast<char*>(&nClusters), sizeof(int)); + if (mInputFile.fail()) { + throw std::length_error("invalid input"); + } + + // get the number of associated digits + int nDigits(-1); + mInputFile.read(reinterpret_cast<char*>(&nDigits), sizeof(int)); + if (mInputFile.fail()) { + throw std::length_error("invalid input"); + } + + if (nClusters < 0 || nDigits < 0) { + throw std::length_error("invalid input"); + } + + // fill clusters in O2 format, if any + if (nClusters > 0) { + int clusterOffset = clusters.size(); + clusters.resize(clusterOffset + nClusters); + mInputFile.read(reinterpret_cast<char*>(&clusters[clusterOffset]), nClusters * sizeof(ClusterStruct)); + if (mInputFile.fail()) { + throw std::length_error("invalid input"); + } + } else { + LOG(INFO) << "event is empty"; + } + + // skip the digits if any + if (nDigits > 0) { + mInputFile.seekg(nDigits * sizeof(Digit), std::ios::cur); + if (mInputFile.fail()) { + throw std::length_error("invalid input"); + } + } + + return nClusters; + } + + std::ifstream mInputFile{}; ///< input file + int mNEventsPerTF = 1; ///< number of events per time frame +}; + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getClusterSamplerSpec(const char* specName, bool globalReferenceSystem) +{ + + std::string spec = fmt::format("clusters:MCH/{}CLUSTERS/0", globalReferenceSystem ? "GLOBAL" : ""); + InputSpec itmp = o2::framework::select(spec.c_str())[0]; + + return DataProcessorSpec{ + specName, + Inputs{}, + Outputs{OutputSpec{{"rofs"}, "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe}, + DataSpecUtils::asOutputSpec(itmp)}, + AlgorithmSpec{adaptFromTask<ClusterSamplerTask>()}, + Options{{"infile", VariantType::String, "", {"input filename"}}, + {"nEventsPerTF", VariantType::Int, 1, {"number of events per time frame"}}}}; +} + +//_________________________________________________________________________________________________ +WorkflowSpec defineDataProcessing(const ConfigContext& cc) { - return WorkflowSpec{o2::mch::getClusterSamplerSpec()}; + return WorkflowSpec{getClusterSamplerSpec("mch-cluster-sampler", cc.options().get<bool>("global"))}; } diff --git a/Detectors/MUON/MCH/Workflow/src/clusters-sink-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/clusters-sink-workflow.cxx index 7e4b048e78679..ea81a1f569449 100644 --- a/Detectors/MUON/MCH/Workflow/src/clusters-sink-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/clusters-sink-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,234 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" +#include <iostream> +#include <fstream> +#include <array> +#include <stdexcept> +#include <vector> + +#include <fmt/format.h> + +#include <gsl/span> -#include "ClusterSinkSpec.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "MCHMappingInterface/Segmentation.h" + +using namespace std; using namespace o2::framework; +using namespace o2::mch; + +class ClusterSinkTask +{ + public: + ClusterSinkTask(bool doDigits = true) : mDoDigits{doDigits} {} + + //_________________________________________________________________________________________________ + void init(InitContext& ic) + { + /// Get the output file from the context + LOG(INFO) << "initializing cluster sink"; + + mText = ic.options().get<bool>("txt"); + + auto outputFileName = ic.options().get<std::string>("outfile"); + mOutputFile.open(outputFileName, (mText ? ios::out : (ios::out | ios::binary))); + if (!mOutputFile.is_open()) { + throw invalid_argument("Cannot open output file" + outputFileName); + } + + mUseRun2DigitUID = ic.options().get<bool>("useRun2DigitUID"); + + auto stop = [this]() { + /// close the output file + LOG(INFO) << "stop cluster sink"; + this->mOutputFile.close(); + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + } + + //_________________________________________________________________________________________________ + void run(ProcessingContext& pc) + { + /// dump the clusters with associated digits of all events in the current TF + + // get the input clusters and associated digits + auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs"); + auto clusters = pc.inputs().get<gsl::span<ClusterStruct>>("clusters"); + gsl::span<const Digit> digits; + if (mDoDigits) { + digits = pc.inputs().get<gsl::span<Digit>>("digits"); + } + + std::vector<ClusterStruct> eventClusters{}; + for (const auto& rof : rofs) { + + if (mText) { + + // write the clusters in ascii format + mOutputFile << rof.getNEntries() << " clusters:" << endl; + for (const auto& cluster : clusters.subspan(rof.getFirstIdx(), rof.getNEntries())) { + mOutputFile << cluster << endl; + } + + } else { + + // get the clusters and associated digits of the current event + auto eventDigits = getEventClustersAndDigits(rof, clusters, digits, eventClusters); + + // write the number of clusters + int nClusters = eventClusters.size(); + mOutputFile.write(reinterpret_cast<char*>(&nClusters), sizeof(int)); + + // write the total number of digits in these clusters + int nDigits = eventDigits.size(); + mOutputFile.write(reinterpret_cast<char*>(&nDigits), sizeof(int)); + + // write the clusters + mOutputFile.write(reinterpret_cast<const char*>(eventClusters.data()), + eventClusters.size() * sizeof(ClusterStruct)); + + // write the digits (after converting the pad ID into a digit UID if requested) + if (nDigits > 0) { + if (mUseRun2DigitUID) { + std::vector<Digit> digitsCopy(eventDigits.begin(), eventDigits.end()); + convertPadID2DigitUID(digitsCopy); + mOutputFile.write(reinterpret_cast<char*>(digitsCopy.data()), digitsCopy.size() * sizeof(Digit)); + } else { + mOutputFile.write(reinterpret_cast<const char*>(eventDigits.data()), eventDigits.size_bytes()); + } + } + } + } + } + + private: + //_________________________________________________________________________________________________ + gsl::span<const Digit> getEventClustersAndDigits(const ROFRecord& rof, gsl::span<const ClusterStruct> clusters, + gsl::span<const Digit> digits, + std::vector<ClusterStruct>& eventClusters) const + { + /// copy the clusters of the current event (needed to edit the clusters) + /// modify the references to the associated digits to start the indexing from 0 + /// return a sub-span with the associated digits -WorkflowSpec defineDataProcessing(const ConfigContext&) + eventClusters.clear(); + + if (rof.getNEntries() < 1) { + return {}; + } + + if (rof.getLastIdx() >= clusters.size()) { + throw length_error("missing clusters"); + } + + eventClusters.insert(eventClusters.end(), clusters.begin() + rof.getFirstIdx(), + clusters.begin() + rof.getLastIdx() + 1); + + if (mDoDigits) { + + auto digitOffset = eventClusters.front().firstDigit; + for (auto& cluster : eventClusters) { + cluster.firstDigit -= digitOffset; + } + + auto nDigits = eventClusters.back().firstDigit + eventClusters.back().nDigits; + if (digitOffset + nDigits > digits.size()) { + throw length_error("missing digits"); + } + + return digits.subspan(digitOffset, nDigits); + } + + return {}; + } + + //_________________________________________________________________________________________________ + void convertPadID2DigitUID(std::vector<Digit>& digits) + { + /// convert the pad ID (i.e. index) in O2 mapping into a digit UID in run2 format + + // cathode number of the bending plane for each DE + static const std::array<std::vector<int>, 10> bendingCathodes{ + {{0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}}; + + for (auto& digit : digits) { + + int deID = digit.getDetID(); + auto& segmentation = mapping::segmentation(deID); + int padID = digit.getPadID(); + int cathode = bendingCathodes[deID / 100 - 1][deID % 100]; + if (!segmentation.isBendingPad(padID)) { + cathode = 1 - cathode; + } + int manuID = segmentation.padDualSampaId(padID); + int manuCh = segmentation.padDualSampaChannel(padID); + + int digitID = (deID) | (manuID << 12) | (manuCh << 24) | (cathode << 30); + digit.setPadID(digitID); + } + } + + std::ofstream mOutputFile{}; ///< output file + bool mText = false; ///< output clusters in text format + bool mUseRun2DigitUID = false; ///< true if Digit.mPadID = digit UID in run2 format + bool mDoDigits = true; ///< whether or not we deal with digits +}; + +//_________________________________________________________________________________________________ +void customize(std::vector<ConfigParamSpec>& workflowOptions) { - return WorkflowSpec{o2::mch::getClusterSinkSpec()}; + /// add workflow options. Note that customization needs to be declared before including Framework/runDataProcessing + workflowOptions.emplace_back("global", VariantType::Bool, false, + ConfigParamSpec::HelpString{"read clusters with positions expressed in global reference frame"}); + workflowOptions.emplace_back("no-digits", VariantType::Bool, false, + ConfigParamSpec::HelpString{"do not look for digits"}); +} + +//_________________________________________________________________________________________________ +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + std::string inputConfig = fmt::format("rofs:MCH/CLUSTERROFS/0;clusters:MCH/{}CLUSTERS/0", + cc.options().get<bool>("global") ? "GLOBAL" : ""); + + bool doDigits = not cc.options().get<bool>("no-digits"); + + if (doDigits) { + inputConfig += ";digits:MCH/CLUSTERDIGITS/0"; + } + std::cout << "inputConfig=" << inputConfig << "\n"; + + return WorkflowSpec{ + DataProcessorSpec{ + "ClusterSink", + Inputs{o2::framework::select(inputConfig.c_str())}, + Outputs{}, + AlgorithmSpec{adaptFromTask<ClusterSinkTask>(doDigits)}, + Options{ + {"outfile", VariantType::String, "clusters.out", {"output filename"}}, + {"txt", VariantType::Bool, false, {"output clusters in text format"}}, + {"useRun2DigitUID", VariantType::Bool, false, {"mPadID = digit UID in run2 format"}}}}}; } diff --git a/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-original-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-original-workflow.cxx index a5b0e2ab7e65d..4c7a552a9fec9 100644 --- a/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-original-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-original-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,22 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" - +#include "CommonUtils/ConfigurableParam.h" #include "TrackFinderOriginalSpec.h" using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("configKeyValues", VariantType::String, "", + ConfigParamSpec::HelpString{"Semicolon separated key=value strings"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) { + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); return WorkflowSpec{o2::mch::getTrackFinderOriginalSpec()}; } diff --git a/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-workflow.cxx index b999e23056d41..d63e67647af1c 100644 --- a/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/clusters-to-tracks-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,22 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" - +#include "CommonUtils/ConfigurableParam.h" #include "TrackFinderSpec.h" using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("configKeyValues", VariantType::String, "", + ConfigParamSpec::HelpString{"Semicolon separated key=value strings"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) { + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); return WorkflowSpec{o2::mch::getTrackFinderSpec()}; } diff --git a/Detectors/MUON/MCH/Workflow/src/clusters-transformer-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/clusters-transformer-workflow.cxx new file mode 100644 index 0000000000000..e71a21750578b --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/clusters-transformer-workflow.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ClusterTransformerSpec.h" + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigContext.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("configKeyValues", + o2::framework::VariantType::String, "", + o2::framework::ConfigParamSpec::HelpString{"Semicolon separated key=value strings"}); +} + +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(const o2::framework::ConfigContext& configContext) +{ + o2::conf::ConfigurableParam::updateFromString(configContext.options().get<std::string>("configKeyValues")); + return o2::framework::WorkflowSpec{o2::mch::getClusterTransformerSpec()}; +} diff --git a/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx index ab31062abb47b..a6329d0282b3f 100644 --- a/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include <random> #include <iostream> +#include <queue> #include <fstream> #include <stdexcept> #include "Framework/CallbackService.h" @@ -42,6 +44,7 @@ using namespace o2; using namespace o2::framework; +using namespace o2::raw; namespace o2 { @@ -52,6 +55,111 @@ namespace raw using RDH = o2::header::RDHAny; +static const int NFEEID = 64; +static const int NLINKS = 16; + +struct TimeFrame { + char* buf{nullptr}; + size_t tfSize{0}; + size_t totalSize{0}; + size_t payloadSize{0}; + std::vector<std::pair<size_t, size_t>> hbframes; + + void computePayloadSize() + { + payloadSize = 0; + if (buf == nullptr) { + return; + } + + size_t offset = 0; + while (offset < totalSize) { + char* ptr = buf + offset; + RDH* rdh = (RDH*)ptr; + + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + auto memorySize = o2::raw::RDHUtils::getMemorySize(rdh); + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + + payloadSize += memorySize - rdhHeaderSize; + + offset += pageSize; + } + } + + void print() + { + if (buf == nullptr) { + return; + } + + int nPrinted = 0; + + printf("\n//////////////////////\n"); + size_t offset = 0; + size_t nStop = 0; + while (offset < totalSize) { + char* ptr = buf + offset; + RDH* rdh = (RDH*)ptr; + + auto stopBit = o2::raw::RDHUtils::getStop(rdh); + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + if (stopBit > 0) { + nStop += 1; + } + + offset += pageSize; + } + + offset = 0; + bool doPrint = false; + size_t iStop = 0; + while (offset < totalSize) { + char* ptr = buf + offset; + RDH* rdh = (RDH*)ptr; + + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + uint16_t cruID = o2::raw::RDHUtils::getCRUID(rdh) & 0x3F; + uint8_t endPointID = o2::raw::RDHUtils::getEndPointID(rdh); + uint8_t linkID = o2::raw::RDHUtils::getLinkID(rdh); + uint16_t feeID = cruID * 2 + endPointID; + auto stopBit = o2::raw::RDHUtils::getStop(rdh); + auto triggerType = o2::raw::RDHUtils::getTriggerType(rdh); + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + + if (iStop < 2 || iStop > (nStop - 3)) { + + printf("%6d: version %X offset %4d packet %3d srcID %d cruID %2d dp %d link %2d orbit %u bc %4d trig 0x%08X page %d stop %d", + (int)0, (int)rdhVersion, (int)pageSize, + (int)RDHUtils::getPacketCounter(rdh), (int)RDHUtils::getSourceID(rdh), + (int)cruID, (int)endPointID, (int)linkID, + (uint32_t)RDHUtils::getHeartBeatOrbit(rdh), (int)RDHUtils::getTriggerBC(rdh), + (int)triggerType, (int)RDHUtils::getPageCounter(rdh), (int)stopBit); + if ((triggerType & 0x800) != 0) { + printf(" <==="); + } + printf("\n"); + } + if (stopBit > 0 && iStop == 3) { + printf("........................\n"); + } + + if (stopBit > 0) { + iStop += 1; + } + + offset += pageSize; + } + fmt::printf("total size: {}\n", totalSize); + printf("//////////////////////\n"); + } +}; + +using TFQueue = std::queue<TimeFrame>; + +TFQueue tfQueues[NFEEID][NLINKS]; + class FileReaderTask { public: @@ -61,8 +169,12 @@ class FileReaderTask /// Get the input file and other options from the context LOG(INFO) << "initializing file reader"; mFrameMax = ic.options().get<int>("nframes"); + mTimeFrameMax = ic.options().get<int>("max-time-frame"); mPrint = ic.options().get<bool>("print"); mFullHBF = ic.options().get<bool>("full-hbf"); + mFullTF = ic.options().get<bool>("full-tf"); + mSaveTF = ic.options().get<bool>("save-tf"); + mOverlap = ic.options().get<int>("overlap"); auto inputFileName = ic.options().get<std::string>("infile"); mInputFile.open(inputFileName, std::ios::binary); @@ -78,9 +190,292 @@ class FileReaderTask ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); } + void printHBF(char* framePtr, size_t frameSize) + { + size_t pageStart = 0; + std::cout << "----\n"; + while (pageStart < frameSize) { + RDH* rdh = (RDH*)(&(framePtr[pageStart])); + // check that the RDH version is ok (only RDH versions from 4 to 6 are supported at the moment) + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + uint16_t cruID = o2::raw::RDHUtils::getCRUID(rdh) & 0x3F; + uint8_t endPointID = o2::raw::RDHUtils::getEndPointID(rdh); + uint8_t linkID = o2::raw::RDHUtils::getLinkID(rdh); + uint16_t feeID = cruID * 2 + endPointID; + auto stopBit = o2::raw::RDHUtils::getStop(rdh); + auto triggerType = o2::raw::RDHUtils::getTriggerType(rdh); + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + auto pageCounter = RDHUtils::getPageCounter(rdh); + + printf("%6d: V %X offset %4d packet %3d srcID %d cruID %2d dp %d link %2d orbit %u bc %4d trig 0x%08X p %d s %d", + (int)0, (int)rdhVersion, (int)pageSize, + (int)RDHUtils::getPacketCounter(rdh), (int)RDHUtils::getSourceID(rdh), + (int)cruID, (int)endPointID, (int)linkID, + (uint32_t)RDHUtils::getHeartBeatOrbit(rdh), (int)RDHUtils::getTriggerBC(rdh), + (int)triggerType, (int)pageCounter, (int)stopBit); + if ((triggerType & 0x800) != 0) { + printf(" <==="); + } + printf("\n"); + pageStart += pageSize; + } + std::cout << "----\n"; + } + + bool appendHBF(TimeFrame& tf, char* framePtr, size_t frameSize, bool addHBF) + { + // new size of the TimeFrame buffer after appending the HBFrame + size_t newSize = tf.totalSize + frameSize; + // increase the size of the memory buffer + tf.buf = (char*)realloc(tf.buf, newSize); + if (tf.buf == nullptr) { + std::cout << "failed to allocate TimeFrame buffer" << std::endl; + return false; + } + + // copy the HBFrame into the TimeFrame buffer + char* bufPtr = tf.buf + tf.totalSize; + memcpy(bufPtr, framePtr, frameSize); + + if (addHBF) { + // add the offset and size of the HBFrame to the vector + tf.hbframes.emplace_back(std::make_pair(tf.totalSize, frameSize)); + // increase the TimeFrame sizes + tf.tfSize += frameSize; + } + + // increase the total buffer sizes + tf.totalSize += frameSize; + + return true; + } + + //_________________________________________________________________________________________________ + void sendTF(framework::ProcessingContext& pc) + { + /// send one RDH block via DPL + RDH rdh; + char* buf{nullptr}; + size_t frameSize{0}; + + static int TFid = 0; + + if (mTimeFrameMax > 0 && TFid == mTimeFrameMax) { + pc.services().get<ControlService>().endOfStream(); + return; + } + + while (true) { + + // stop if the required number of frames has been reached + if (mFrameMax == 0) { + pc.services().get<ControlService>().endOfStream(); + return; + } + + if (mPrint && false) { + printf("mFrameMax: %d\n", mFrameMax); + } + if (mFrameMax > 0) { + mFrameMax -= 1; + } + + // read the next RDH, stop if no more data is available + if (mPrint) { + std::cout << "Reading " << sizeof(RDH) << " for RDH from input file\n"; + } + mInputFile.read((char*)(&rdh), sizeof(RDH)); + if (mInputFile.fail()) { + if (mPrint) { + std::cout << "end of file reached" << std::endl; + } + pc.services().get<ControlService>().endOfStream(); + return; // probably reached eof + } + + // check that the RDH version is ok (only RDH versions from 4 to 6 are supported at the moment) + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + uint16_t cruID = o2::raw::RDHUtils::getCRUID(rdh) & 0x3F; + uint8_t endPointID = o2::raw::RDHUtils::getEndPointID(rdh); + uint8_t linkID = o2::raw::RDHUtils::getLinkID(rdh); + uint16_t feeID = cruID * 2 + endPointID; + auto stopBit = o2::raw::RDHUtils::getStop(rdh); + auto triggerType = o2::raw::RDHUtils::getTriggerType(rdh); + auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + auto pageCounter = RDHUtils::getPageCounter(rdh); + + if (mPrint) { + printf("%6d: V %X offset %4d packet %3d srcID %d cruID %2d dp %d link %2d orbit %u bc %4d trig 0x%08X p %d s %d", + (int)0, (int)rdhVersion, (int)pageSize, + (int)RDHUtils::getPacketCounter(rdh), (int)RDHUtils::getSourceID(rdh), + (int)cruID, (int)endPointID, (int)linkID, + (uint32_t)RDHUtils::getHeartBeatOrbit(rdh), (int)RDHUtils::getTriggerBC(rdh), + (int)triggerType, (int)pageCounter, (int)stopBit); + if ((triggerType & 0x800) != 0) { + printf(" <==="); + } + printf("\n"); + } + if (rdhVersion < 4 || rdhVersion > 6 || rdhHeaderSize != 64) { + return; + } + + TFQueue& tfQueue = tfQueues[feeID][linkID]; + + // get the frame size from the RDH offsetToNext field + if (mPrint && false) { + std::cout << "pageSize=" << pageSize << std::endl; + } + + // stop if the frame size is too small + if (pageSize < rdhHeaderSize) { + std::cout << mFrameMax << " - pageSize too small: " << pageSize << std::endl; + pc.services().get<ControlService>().endOfStream(); + return; + } + + // allocate or extend the output buffer + buf = (char*)realloc(buf, frameSize + pageSize); + if (buf == nullptr) { + std::cout << mFrameMax << " - failed to allocate buffer" << std::endl; + pc.services().get<ControlService>().endOfStream(); + return; + } + + // copy the RDH into the output buffer + memcpy(buf + frameSize, &rdh, rdhHeaderSize); + + // read the frame payload into the output buffer + if (mPrint) { + std::cout << "Reading " << pageSize - rdhHeaderSize << " for payload from input file\n"; + } + mInputFile.read(buf + frameSize + rdhHeaderSize, pageSize - rdhHeaderSize); + + // stop if data cannot be read completely + if (mInputFile.fail()) { + if (mPrint) { + std::cout << "end of file reached" << std::endl; + } + free(buf); + pc.services().get<ControlService>().endOfStream(); + return; // probably reached eof + } + + // increment the total buffer size + frameSize += pageSize; + + if ((triggerType & 0x800) != 0 && stopBit == 0 && pageCounter == 0) { + // This is the start of a new TimeFrame, so we need to take some actions: + // - push a new TimeFrame in the queue + // - append the last N HBFrames of the previous TimeFrame at the beginning of the current one + // - set the initial total size of the TimeFrame buffer + char* prevTFptr{nullptr}; + size_t prevTFsize{0}; + + if (mPrint) { + std::cout << "tfQueue.size(): " << tfQueue.size() << std::endl; + } + if (!tfQueue.empty()) { + TimeFrame& prevTF = tfQueue.back(); + size_t nhbf = prevTF.hbframes.size(); + if ((mOverlap > 0) && (nhbf >= mOverlap)) { + size_t hbfID = nhbf - mOverlap; + prevTFptr = prevTF.buf + prevTF.hbframes[hbfID].first; + for (size_t i = hbfID; i < nhbf; i++) { + prevTFsize += prevTF.hbframes[i].second; + } + } + } + + tfQueue.emplace(); + + if (prevTFsize > 0) { + tfQueue.back().buf = (char*)malloc(prevTFsize); + if (tfQueue.back().buf == nullptr) { + std::cout << mFrameMax << " - failed to allocate TimeFrame buffer" << std::endl; + pc.services().get<ControlService>().endOfStream(); + return; + } + + memcpy(tfQueue.back().buf, prevTFptr, prevTFsize); + } + + tfQueue.back().totalSize = prevTFsize; + } + + if (stopBit && tfQueue.size() > 0) { + // we reached the end of the current HBFrame, we need to append it to the TimeFrame + + if (mPrint) { + std::cout << "Appending HBF to TF #" << tfQueue.size() << std::endl; + printHBF(buf, frameSize); + } + if (!appendHBF(tfQueue.back(), buf, frameSize, true)) { + std::cout << mFrameMax << " - failed to append HBframe" << std::endl; + pc.services().get<ControlService>().endOfStream(); + return; + } + + if (tfQueue.size() == 2) { + // we have two TimeFrames in the queue, we also append mOverlap HBFrames to the first one + if (tfQueue.back().hbframes.size() <= mOverlap) { + if (mPrint) { + std::cout << "Appending HBF to TF #1" << std::endl; + printHBF(buf, frameSize); + } + if (!appendHBF(tfQueue.front(), buf, frameSize, false)) { + std::cout << mFrameMax << " - failed to append HBframe" << std::endl; + pc.services().get<ControlService>().endOfStream(); + return; + } + } + } + + // free the HBFrame buffer + free(buf); + buf = nullptr; + frameSize = 0; + + if (tfQueue.size() == 2 && tfQueue.back().hbframes.size() >= mOverlap) { + // we collected enough HBFrames after the last fully recorded TimeFrame, so we can send it + tfQueue.front().computePayloadSize(); + if (mPrint) { + tfQueue.front().print(); + sleep(1); + } + if (tfQueue.front().payloadSize > 0) { + if (mSaveTF && TFid < 100) { + char fname[500]; + snprintf(fname, 499, "tf-%03d.raw", TFid); + FILE* fout = fopen(fname, "wb"); + if (fout) { + fwrite(tfQueue.front().buf, tfQueue.front().totalSize, 1, fout); + fclose(fout); + } + } + + auto freefct = [](void* data, void* /*hint*/) { free(data); }; + pc.outputs().adoptChunk(Output{"RDT", "RAWDATA"}, tfQueue.front().buf, tfQueue.front().totalSize, freefct, nullptr); + TFid += 1; + } + tfQueue.pop(); + break; + } + } + } + } + //_________________________________________________________________________________________________ void run(framework::ProcessingContext& pc) { + if (mFullTF) { + sendTF(pc); + //pc.services().get<ControlService>().endOfStream(); + return; + } + /// send one RDH block via DPL RDH rdh; char* buf{nullptr}; @@ -168,7 +563,7 @@ class FileReaderTask if ((stopBit != 0) || (mFullHBF == false)) { // create the output message auto freefct = [](void* data, void* /*hint*/) { free(data); }; - pc.outputs().adoptChunk(Output{"ROUT", "RAWDATA"}, buf, bufSize, freefct, nullptr); + pc.outputs().adoptChunk(Output{"RDT", "RAWDATA"}, buf, bufSize, freefct, nullptr); // stop the readout loop break; @@ -179,22 +574,30 @@ class FileReaderTask private: std::ifstream mInputFile{}; ///< input file int mFrameMax; ///< number of frames to process + int mTimeFrameMax; ///< number of frames to process bool mFullHBF; ///< send full HeartBeat frames + bool mFullTF; ///< send full time frames + bool mSaveTF; ///< save individual time frames to file + int mOverlap; ///< overlap between contiguous TimeFrames bool mPrint = false; ///< print debug messages }; //_________________________________________________________________________________________________ // clang-format off -o2::framework::DataProcessorSpec getFileReaderSpec() +o2::framework::DataProcessorSpec getFileReaderSpec(const char* specName) { return DataProcessorSpec{ - "FileReader", + specName, Inputs{}, - Outputs{OutputSpec{"ROUT", "RAWDATA", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{"RDT", "RAWDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<FileReaderTask>()}, Options{{"infile", VariantType::String, "", {"input file name"}}, {"nframes", VariantType::Int, -1, {"number of frames to process"}}, + {"max-time-frame", VariantType::Int, -1, {"number of time frames to process"}}, {"full-hbf", VariantType::Bool, false, {"send full HeartBeat frames"}}, + {"full-tf", VariantType::Bool, false, {"send full time frames"}}, + {"save-tf", VariantType::Bool, false, {"save individual time frames to file"}}, + {"overlap", VariantType::Int, 0, {"overlap between contiguous TimeFrames"}}, {"print", VariantType::Bool, false, {"verbose output"}}}}; } // clang-format on @@ -211,7 +614,7 @@ WorkflowSpec defineDataProcessing(const ConfigContext&) WorkflowSpec specs; // The producer to generate some data in the workflow - DataProcessorSpec producer = mch::raw::getFileReaderSpec(); + DataProcessorSpec producer = mch::raw::getFileReaderSpec("mch-cru-page-reader"); specs.push_back(producer); return specs; diff --git a/Detectors/MUON/MCH/Workflow/src/cru-page-to-digits-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/cru-page-to-digits-workflow.cxx index 2c73d33108a41..e255bdfc4ca7d 100644 --- a/Detectors/MUON/MCH/Workflow/src/cru-page-to-digits-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/cru-page-to-digits-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,7 +34,7 @@ WorkflowSpec defineDataProcessing(const ConfigContext&) { WorkflowSpec specs; - DataProcessorSpec producer = o2::mch::raw::getDecodingSpec("readout:ROUT/RAWDATA"); + DataProcessorSpec producer = o2::mch::raw::getDecodingSpec("mch-data-decoder", "readout:RDT/RAWDATA"); specs.push_back(producer); return specs; diff --git a/Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx index 0d3306f75d03f..a518b324956cb 100644 --- a/Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,21 +15,34 @@ /// \author Philippe Pillot, Subatech /// \author Andrea Ferrero, CEA -#include "Framework/CallbackService.h" -#include "Framework/ControlService.h" -#include "Framework/Task.h" #include "Framework/runDataProcessing.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include "DigitSamplerSpec.h" -using namespace o2; using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) { - WorkflowSpec specs; + std::vector<ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; - DataProcessorSpec producer = o2::mch::getDigitSamplerSpec(); - specs.push_back(producer); + o2::raw::HBFUtilsInitializer::addConfigOption(options); - return specs; + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + WorkflowSpec wf{o2::mch::getDigitSamplerSpec()}; + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); } diff --git a/Detectors/MUON/MCH/Workflow/src/digits-sink-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/digits-sink-workflow.cxx index 9fcd58628ce44..7edb94f4b12ba 100644 --- a/Detectors/MUON/MCH/Workflow/src/digits-sink-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/digits-sink-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,7 +38,8 @@ #include "Framework/runDataProcessing.h" #include "DPLUtils/DPLRawParser.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" #include "MCHRawDecoder/OrbitInfo.h" using namespace o2; @@ -84,15 +86,22 @@ class DigitsSinkTask // get the input digits auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); auto orbits = pc.inputs().get<gsl::span<OrbitInfo>>("orbits"); + auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("digitrofs"); + std::set<OrbitInfo> ordered_orbits(orbits.begin(), orbits.end()); if (mText) { - for (auto o : orbits) { - mOutputFile << std::endl - << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl; + mOutputFile << std::endl + << "=======================" << std::endl; + for (const auto& o : ordered_orbits) { + mOutputFile << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl; } mOutputFile << "---------------" << std::endl; - for (auto d : digits) { - mOutputFile << " DE# " << d.getDetID() << " PadId " << d.getPadID() << " ADC " << d.getADC() << " time " << d.getTime().sampaTime << std::endl; + for (const auto& d : digits) { + mOutputFile << " DE# " << d.getDetID() << " PadId " << d.getPadID() << " ADC " << d.getADC() << std::endl; + } + mOutputFile << "---------------" << std::endl; + for (const auto& rof : rofs) { + mOutputFile << " IR " << rof.getBCData() << " first " << rof.getFirstIdx() << " size " << rof.getNEntries() << std::endl; } } else { int nDigits = digits.size(); @@ -118,7 +127,9 @@ WorkflowSpec defineDataProcessing(const ConfigContext&) // The producer to generate some data in the workflow DataProcessorSpec producer{ "DigitsSink", - Inputs{InputSpec{"digits", "MCH", "DIGITS", 0, Lifetime::Timeframe}, InputSpec{"orbits", "MCH", "ORBITS", 0, Lifetime::Timeframe}}, + Inputs{InputSpec{"digits", header::gDataOriginMCH, "DIGITS", 0, Lifetime::Timeframe}, + InputSpec{"orbits", header::gDataOriginMCH, "ORBITS", 0, Lifetime::Timeframe}, + InputSpec{"digitrofs", header::gDataOriginMCH, "DIGITROFS", 0, Lifetime::Timeframe}}, Outputs{}, AlgorithmSpec{adaptFromTask<o2::mch::raw::DigitsSinkTask>()}, Options{ { "outfile", VariantType::String, "digits.out", { "output file name" } }, diff --git a/Detectors/MUON/MCH/Workflow/src/digits-to-preclusters-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/digits-to-preclusters-workflow.cxx index 9101823200614..a2f5ddde3cfe8 100644 --- a/Detectors/MUON/MCH/Workflow/src/digits-to-preclusters-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/digits-to-preclusters-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,18 +20,20 @@ #include "Framework/CallbackService.h" #include "Framework/ControlService.h" #include "Framework/Task.h" -#include "Framework/runDataProcessing.h" #include "MCHWorkflow/PreClusterFinderSpec.h" using namespace o2; using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +void customize(std::vector<ConfigParamSpec>& workflowOptions) { - WorkflowSpec specs; + workflowOptions.push_back(ConfigParamSpec{"input-digitrofs-data-description", VariantType::String, "TIMECLUSTERROFS", {"description string for the input ROF data"}}); +} - DataProcessorSpec producer = o2::mch::getPreClusterFinderSpec(); - specs.push_back(producer); +#include "Framework/runDataProcessing.h" - return specs; +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + auto rofDesc = configcontext.options().get<std::string>("input-digitrofs-data-description"); + return {o2::mch::getPreClusterFinderSpec(rofDesc.c_str())}; } diff --git a/Detectors/MUON/MCH/Workflow/src/digits-to-timeclusters-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/digits-to-timeclusters-workflow.cxx new file mode 100644 index 0000000000000..295fb2e31f03c --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/digits-to-timeclusters-workflow.cxx @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digits-to-timeclusters-workflow.cxx +/// \brief This is an executable that runs the time clusterization via DPL. +/// +/// This is an executable that takes digits from the Data Processing Layer, runs the time clusterization and sends the time clusters via the Data Processing Layer. +/// +/// \author Andrea Ferrero, CEA + +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/runDataProcessing.h" +#include "MCHWorkflow/TimeClusterFinderSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext&) +{ + return {o2::mch::getTimeClusterFinderSpec()}; +} diff --git a/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..50d9681fcfdf7 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "MCHCTF/CTFCoder.h" +#include <TStopwatch.h> +#include <vector> + +using namespace o2::framework; + +namespace o2 +{ +namespace mch +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::mch::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto rofs = pc.inputs().get<gsl::span<o2::mch::ROFRecord>>("rofs"); + auto digits = pc.inputs().get<gsl::span<o2::mch::Digit>>("digits"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"MCH", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, rofs, digits); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << fmt::format("Created encoded data ({} digits and {} rofs) of size {} ({:5.1f} MB) for MCH in {:5.1f} s ", + digits.size(), rofs.size(), eeb->size(), eeb->size() / 1024.0 / 1024, mTimer.CpuTime() - cput); +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "MCH Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec(const char* specName) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("rofs", "MCH", "DIGITROFS", 0, Lifetime::Timeframe); + inputs.emplace_back("digits", "MCH", "DIGITS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + specName, + inputs, + Outputs{{"MCH", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"Path to pre-computed CTF encoding dictionary to be used for encoding"}}}}; +} + +} // namespace mch +} // namespace o2 + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::mch::getEntropyEncoderSpec("mch-entropy-encoder")); + return wf; +} diff --git a/Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx index 13e4b650a039c..b83cbb1d6485b 100644 --- a/Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,21 +22,13 @@ /// \endcode /// -#include "Framework/CallbackService.h" -#include "Framework/ControlService.h" -#include "Framework/Task.h" #include "Framework/runDataProcessing.h" + #include "PreClusterSinkSpec.h" -using namespace o2; using namespace o2::framework; WorkflowSpec defineDataProcessing(const ConfigContext&) { - WorkflowSpec specs; - - DataProcessorSpec producer = o2::mch::getPreClusterSinkSpec(); - specs.push_back(producer); - - return specs; + return WorkflowSpec{o2::mch::getPreClusterSinkSpec()}; } diff --git a/Detectors/MUON/MCH/Workflow/src/preclusters-to-clusters-original-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/preclusters-to-clusters-original-workflow.cxx index d2bd00d6f3233..7fa4e91b552a2 100644 --- a/Detectors/MUON/MCH/Workflow/src/preclusters-to-clusters-original-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/preclusters-to-clusters-original-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,22 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" - +#include "CommonUtils/ConfigurableParam.h" #include "MCHWorkflow/ClusterFinderOriginalSpec.h" using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("configKeyValues", VariantType::String, "", + ConfigParamSpec::HelpString{"Semicolon separated key=value strings"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) { + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); return WorkflowSpec{o2::mch::getClusterFinderOriginalSpec()}; } diff --git a/Detectors/MUON/MCH/Workflow/src/raw-debug-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/raw-debug-workflow.cxx new file mode 100644 index 0000000000000..719440d354368 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/raw-debug-workflow.cxx @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file raw-parser.cxx +/// \author Andrea Ferrero +/// +/// \brief This is an executable that receives the TimeFrames from the raw proxy and prints the sequence of RDHs. +/// +/// This is an executable that receives the TimeFrames from the raw proxy and prints the sequence of RDHs. +/// Useful for debugging the DPL workflows involving input RAW data. +/// + +#include <iostream> +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" + +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +using namespace o2::framework; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"dataspec", VariantType::String, "TF:MCH/RAWDATA", {"selection string for the input data"}}); +} + +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +namespace o2 +{ +namespace mch +{ +namespace raw +{ + +//======================= +// Data parser +class DataParserTask +{ + public: + DataParserTask(std::string spec) : mInputSpec(spec) {} + + //_________________________________________________________________________________________________ + void init(framework::InitContext& ic) + { + } + + void decodeBuffer(gsl::span<const std::byte> page){}; + + //_________________________________________________________________________________________________ + void run(framework::ProcessingContext& pc) + { + // get the input buffer + DPLRawParser parser(pc.inputs(), o2::framework::select(mInputSpec.c_str())); + + int nRDH = 0; + + const std::byte* raw = nullptr; + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + raw = reinterpret_cast<const std::byte*>(it.raw()); + if (!raw) { + continue; + } + + auto* rdh = reinterpret_cast<const RDH*>(raw); + + if (nRDH == 0) { + std::cout << std::endl + << "---------------" << std::endl; + o2::raw::RDHUtils::printRDH(rdh); + //std::cout << "......." << std::endl; + } + nRDH += 1; + } + + if (false && raw) { + auto* rdh = reinterpret_cast<const RDH*>(raw); + o2::raw::RDHUtils::printRDH(rdh); + } + std::cout << "---------------" << std::endl; + } + + private: + std::string mInputSpec; +}; + +} // namespace raw +} // namespace mch +} // end namespace o2 + +WorkflowSpec defineDataProcessing(const ConfigContext& config) +{ + auto inputSpec = config.options().get<std::string>("dataspec"); + + WorkflowSpec specs; + + o2::mch::raw::DataParserTask task(inputSpec); + DataProcessorSpec parser{ + "RawParser", + o2::framework::select(inputSpec.c_str()), + Outputs{}, + AlgorithmSpec{adaptFromTask<o2::mch::raw::DataParserTask>(std::move(task))}, + Options{}}; + + specs.push_back(parser); + + return specs; +} diff --git a/Detectors/MUON/MCH/Workflow/src/raw-to-digits-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/raw-to-digits-workflow.cxx index 2cad8309540fd..62f025a1a7921 100644 --- a/Detectors/MUON/MCH/Workflow/src/raw-to-digits-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/raw-to-digits-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,18 +24,44 @@ #include "Framework/CallbackService.h" #include "Framework/ControlService.h" #include "Framework/Task.h" -#include "Framework/runDataProcessing.h" + +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include "MCHWorkflow/DataDecoderSpec.h" +using namespace o2::framework; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); + workflowOptions.push_back(ConfigParamSpec{"dataspec", VariantType::String, "TF:MCH/RAWDATA", {"selection string for the input data"}}); + workflowOptions.push_back(o2::framework::ConfigParamSpec{"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}); +} + +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) { - WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + auto inputSpec = configcontext.options().get<std::string>("dataspec"); + + auto askSTFDist = !configcontext.options().get<bool>("ignore-dist-stf"); + + WorkflowSpec wf{o2::mch::raw::getDecodingSpec("mch-data-decoder", inputSpec, askSTFDist)}; - DataProcessorSpec producer = o2::mch::raw::getDecodingSpec(); - specs.push_back(producer); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); - return specs; + return std::move(wf); } diff --git a/Detectors/MUON/MCH/Workflow/src/reco-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/reco-workflow.cxx new file mode 100644 index 0000000000000..d64770d29cfb3 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/reco-workflow.cxx @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ClusterTransformerSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DigitReaderSpec.h" +#include "Framework/ConfigContext.h" +#include "Framework/Logger.h" +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" +#include "MCHWorkflow/ClusterFinderOriginalSpec.h" +#include "MCHWorkflow/PreClusterFinderSpec.h" +#include "MCHWorkflow/TimeClusterFinderSpec.h" +#include "MCHWorkflow/TrackWriterSpec.h" +#include "TrackFinderSpec.h" +#include "TrackFitterSpec.h" +#include "TrackMCLabelFinderSpec.h" + +using o2::framework::ConfigContext; +using o2::framework::ConfigParamSpec; +using o2::framework::VariantType; +using o2::framework::WorkflowSpec; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"disable-time-clustering", o2::framework::VariantType::Bool, false, {"disable time clustering step (for debug only)"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + + auto disableRootOutput = configcontext.options().get<bool>("disable-root-output"); + auto disableRootInput = configcontext.options().get<bool>("disable-root-input"); + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto enableTimeClustering = !configcontext.options().get<bool>("disable-time-clustering"); + + const char* digitRofDataDescription = + enableTimeClustering ? "TIMECLUSTERROFS" : "DIGITROFS"; + + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + if (!disableRootInput) { + specs.emplace_back(o2::mch::getDigitReaderSpec(useMC, "mch-sim-digit-reader")); + } + if (enableTimeClustering) { + specs.emplace_back(o2::mch::getTimeClusterFinderSpec("mch-time-cluster-finder")); + } + + specs.emplace_back(o2::mch::getPreClusterFinderSpec("mch-precluster-finder", + digitRofDataDescription)); + specs.emplace_back(o2::mch::getClusterFinderOriginalSpec("mch-cluster-finder")); + specs.emplace_back(o2::mch::getClusterTransformerSpec()); + specs.emplace_back(o2::mch::getTrackFinderSpec("mch-track-finder")); + + if (!disableRootOutput) { + if (useMC) { + specs.emplace_back(o2::mch::getTrackMCLabelFinderSpec("mch-track-mc-label-finder", digitRofDataDescription)); + } + specs.emplace_back(o2::mch::getTrackWriterSpec(useMC, "mch-track-writer", "mchtracks.root")); + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + // write the configuration used for the reco workflow + o2::conf::ConfigurableParam::writeINI("o2mchrecoflow_configuration.ini"); + + return specs; +} diff --git a/Detectors/MUON/MCH/Workflow/src/rofs-histogrammer.cxx b/Detectors/MUON/MCH/Workflow/src/rofs-histogrammer.cxx new file mode 100644 index 0000000000000..ceed135431e58 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/rofs-histogrammer.cxx @@ -0,0 +1,150 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "Framework/ConfigContext.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Logger.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include <TFile.h> +#include <THnSparse.h> +#include <fmt/format.h> +#include <iostream> +#include <limits> +#include <map> +#include <stdexcept> + +/** +* `o2-mch-rofs-histogrammer` creates a 1D histogram of MCH ROF Records. +* +* The ROFs used are described using the `--rofs-name` option which shouldEnd +* describe the expected DPL input message name (default is `MCH/DIGITROFS`) +* +* The produced 1D histogram is a sparse one (THnSparseL of dimension 1) +* and is written in a Root file named with the `--outfile` option (default +* is `rofs-times.root`). +* +*/ + +using o2::framework::adaptFromTask; +using o2::framework::AlgorithmSpec; +using o2::framework::ConfigContext; +using o2::framework::ConfigParamSpec; +using o2::framework::ControlService; +using o2::framework::DataProcessorSpec; +using o2::framework::InitContext; +using o2::framework::Inputs; +using o2::framework::Options; +using o2::framework::Outputs; +using o2::framework::ProcessingContext; +using o2::framework::VariantType; +using o2::framework::WorkflowSpec; + +struct Histogrammer { + void init(o2::framework::InitContext& ic) + { + mMaxNofTimeFrames = ic.options().get<int>("max-nof-tfs"); + mFirstTF = ic.options().get<int>("first-tf"); + mNofProcessedTFs = 0; + auto fileName = ic.options().get<std::string>("outfile"); + mHistoFile = std::make_unique<TFile>(fileName.c_str(), "RECREATE"); + if (ic.options().get<bool>("verbose")) { + fair::Logger::SetConsoleColor(true); + } + mFirstOrbit = ic.options().get<int>("first-orbit"); + mLastOrbit = ic.options().get<int>("last-orbit"); + } + + void writeHisto() + { + auto firstRof = (mFirstOrbit >= 0) ? o2::InteractionRecord(0, mFirstOrbit) : mRofs.begin()->first.getBCData(); + + auto lastRof = (mLastOrbit >= 0) ? o2::InteractionRecord(o2::constants::lhc::LHCMaxBunches, mLastOrbit) : mRofs.rbegin()->first.getBCData(); + auto nbins = static_cast<Int_t>(lastRof.differenceInBC(firstRof)); + Int_t bins[1] = {nbins}; + Double_t xmin[1] = {0.0}; + Double_t xmax[1] = {nbins * 1.0 + 1}; + THnSparseL h("rof_times", "rof times", 1, bins, xmin, xmax); + for (const auto& p : mRofs) { + const auto& rof = p.first; + Double_t x[1] = {1.0 * rof.getBCData().differenceInBC(firstRof)}; + Double_t w = rof.getNEntries(); + h.Fill(x, w); + h.SetBinError(h.GetBin(x), sqrt(w)); + } + h.Write("", TObject::kWriteDelete); + } + + void run(ProcessingContext& pc) + { + bool shouldEnd = mNofProcessedTFs >= mMaxNofTimeFrames; + if (shouldEnd) { + pc.services().get<ControlService>().endOfStream(); + return; + } + + bool shouldProcess = (mTFid >= mFirstTF && mNofProcessedTFs < mMaxNofTimeFrames); + if (!shouldProcess) { + return; + } + + mTFid++; + auto rofs = pc.inputs().get<gsl::span<o2::mch::ROFRecord>>("rofs"); + for (const auto& rof : rofs) { + mRofs[rof] += rof.getNEntries(); + } + writeHisto(); + } + size_t mFirstTF{0}; // first timeframe to process + size_t mMaxNofTimeFrames{std::numeric_limits<size_t>::max()}; // max number of timeframes to process + size_t mNofProcessedTFs{0}; // actual number of timeframes processed so far + size_t mTFid{0}; // current timeframe index + std::unique_ptr<TFile> mHistoFile; // output histogram file + std::map<o2::mch::ROFRecord, int> mRofs; // accumulation of rofs + uint32_t mFirstOrbit; + uint16_t mLastOrbit; +}; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"rofs-name", VariantType::String, "MCH/DIGITROFS", {"name of the input rofs"}}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& cc) +{ + WorkflowSpec specs; + + auto rofName = cc.options().get<std::string>("rofs-name"); + std::string inputConfig = "rofs:" + rofName; + + DataProcessorSpec rofHistogrammer{ + "mch-rofs-histogrammer", + Inputs{o2::framework::select(inputConfig.c_str())}, + Outputs{}, + AlgorithmSpec{adaptFromTask<Histogrammer>()}, + Options{ + {"verbose", VariantType::Bool, false, {"verbose output"}}, + {"max-nof-tfs", VariantType::Int, 10, {"max number of timeframes to process"}}, + {"first-tf", VariantType::Int, 0, {"first timeframe to process"}}, + {"first-orbit", VariantType::Int, 0, {"force first orbit to use as first orbit (for histogram) (default=-1=auto)"}}, + {"last-orbit", VariantType::Int, 0, {"force last orbit to use as last orbit (for histogram) (default=-1=auto)"}}, + {"outfile", VariantType::String, "rofs-times.root", {"name of the histogram output file"}}}}; + + specs.push_back(rofHistogrammer); + return specs; +} diff --git a/Detectors/MUON/MCH/Workflow/src/sim-digits-reader-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/sim-digits-reader-workflow.cxx new file mode 100644 index 0000000000000..e950823567486 --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/sim-digits-reader-workflow.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MCH/Workflow/src/sim-digits-reader-workflow.cxx +/// \brief MCH digits reader workflow +/// \author Michael Winn <Michael.Winn at cern.ch> +/// \date 17 April 2021 + +#include <string> +#include <vector> +#include "Framework/Variant.h" +#include "Framework/ConfigParamSpec.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DigitReaderSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"disable-mc", VariantType::Bool, false, {"Do not propagate MC info"}}}; + workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + bool useMC = !cfgc.options().get<bool>("disable-mc"); + + WorkflowSpec specs; + specs.emplace_back(o2::mch::getDigitReaderSpec(useMC)); + + return specs; +} diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-file-dumper.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-file-dumper.cxx new file mode 100644 index 0000000000000..80c319517e83a --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/tracks-file-dumper.cxx @@ -0,0 +1,198 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/ClusterBlock.h" +#include "MCHBase/TrackBlock.h" +#include "TrackAtVtxStruct.h" +#include "TrackTreeReader.h" +#include "boost/program_options.hpp" +#include <TFile.h> +#include <TTree.h> +#include <filesystem> +#include <fmt/format.h> +#include <fstream> +#include <gsl/span> +#include <iostream> + +namespace po = boost::program_options; +namespace fs = std::filesystem; + +using o2::mch::ClusterStruct; +using o2::mch::ROFRecord; +using o2::mch::TrackAtVtxStruct; +using o2::mch::TrackMCH; +using o2::mch::TrackTreeReader; + +template <typename T> +bool readBinaryStruct(std::istream& in, int nitems, std::vector<T>& items, const char* itemName) +{ + if (in.peek() == EOF) { + return false; + } + // get the items if any + if (nitems > 0) { + auto offset = items.size(); + items.resize(offset + nitems); + in.read(reinterpret_cast<char*>(&items[offset]), nitems * sizeof(T)); + if (in.fail()) { + throw std::length_error(fmt::format("invalid input : cannot read {} {}", nitems, itemName)); + } + } + return true; +} + +void dump(std::ostream& os, const o2::mch::TrackParamStruct& t) +{ + auto pt2 = t.px * t.px + t.py * t.py; + auto p2 = t.pz * t.pz + pt2; + auto pt = std::sqrt(pt2); + auto p = std::sqrt(p2); + os << fmt::format("({:s}) p {:7.2f} pt {:7.2f}", t.sign == -1 ? "-" : "+", p, pt); +} + +void dump(std::ostream& os, gsl::span<o2::mch::TrackAtVtxStruct> tracksAtVertex) +{ + for (const auto& tv : tracksAtVertex) { + os << fmt::format("id {:4d} ", tv.mchTrackIdx); + dump(os, tv.paramAtVertex); + os << fmt::format(" dca {:7.2f} rabs {:7.2f}", tv.dca, tv.rAbs) + << "\n"; + } +} + +void dump(std::ostream& os, const o2::mch::TrackMCH& t) +{ + auto pt = std::sqrt(t.getPx() * t.getPx() + t.getPy() * t.getPy()); + os << fmt::format("({:s}) p {:7.2f} pt {:7.2f} nclusters: {} \n", t.getSign() == -1 ? "-" : "+", t.getP(), pt, t.getNClusters()); +} + +int dumpBinary(std::string inputFile) +{ + std::ifstream in(inputFile.c_str()); + if (!in.is_open()) { + std::cerr << "cannot open input file " << inputFile << "\n"; + return 3; + } + + while (in.good()) { + int nofTracksAtVertex{-1}; + int nofTracks{-1}; + int nofAttachedClusters{-1}; + // read the number of tracks at vertex, MCH tracks and attached clusters + if (!in.read(reinterpret_cast<char*>(&nofTracksAtVertex), sizeof(int))) { + return -1; + } + if (!in.read(reinterpret_cast<char*>(&nofTracks), sizeof(int))) { + return -1; + } + if (!in.read(reinterpret_cast<char*>(&nofAttachedClusters), sizeof(int))) { + return -1; + } + std::cout << fmt::format("=== nof MCH tracks: {:2d} at vertex: {:2d} w/ {:4d} attached clusters\n", + nofTracks, nofTracksAtVertex, nofAttachedClusters); + std::vector<TrackAtVtxStruct> tracksAtVertex; + std::vector<TrackMCH> tracks; + std::vector<ClusterStruct> clusters; + // read the tracks, tracks at vertex and clusters (mind the reverse order of tracks + // compared to the numbers above) + if (!readBinaryStruct<TrackAtVtxStruct>(in, nofTracksAtVertex, tracksAtVertex, "TracksAtVertex")) { + return -1; + } + if (!readBinaryStruct<TrackMCH>(in, nofTracks, tracks, "Tracks")) { + return -1; + } + if (!readBinaryStruct<ClusterStruct>(in, nofAttachedClusters, clusters, "AttachedClusters")) { + return -1; + } + + dump(std::cout, tracksAtVertex); + } + return 0; +} + +int dumpRoot(std::string inputFile) +{ + std::unique_ptr<TFile> fin(TFile::Open(inputFile.c_str())); + TTree* tree = static_cast<TTree*>(fin->Get("o2sim")); + + TrackTreeReader tr(tree); + + ROFRecord rof; + std::vector<TrackMCH> tracks; + std::vector<ClusterStruct> clusters; + std::vector<o2::MCCompLabel> labels; + + while (tr.next(rof, tracks, clusters, labels)) { + std::cout << rof << "\n"; + if (tr.hasLabels() && labels.size() != tracks.size()) { + std::cerr << "the number of labels do not match the number of tracks\n"; + return -1; + } + int it(0); + for (const auto& t : tracks) { + std::cout << " "; + dump(std::cout, t); + if (tr.hasLabels()) { + std::cout << " MC label: "; + labels[it++].print(); + } + } + } + return 0; +} + +/** + * o2-mch-tracks-file-dumper is a small helper program to inspect + * track binary files (mch custom binary format for debug only) + */ + +int main(int argc, char* argv[]) +{ + std::string inputFile; + po::variables_map vm; + po::options_description options("options"); + + // clang-format off + // clang-format off + options.add_options() + ("help,h", "produce help message") + ("infile,i", po::value<std::string>(&inputFile)->required(), "input file name") + ; + // clang-format on + + po::options_description cmdline; + cmdline.add(options); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + + if (vm.count("help")) { + std::cout << options << "\n"; + return 2; + } + + try { + po::notify(vm); + } catch (boost::program_options::error& e) { + std::cout << "Error: " << e.what() << "\n"; + exit(1); + } + + std::string ext = fs::path(inputFile).extension(); + std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); + + if (ext == ".root") { + return dumpRoot(inputFile); + } + return dumpBinary(inputFile); +} diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-mc-label-finder-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-mc-label-finder-workflow.cxx new file mode 100644 index 0000000000000..35274276275ae --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/tracks-mc-label-finder-workflow.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file tracks-mc-label-finder-workflow.cxx +/// \brief Implementation of a DPL device to match the reconstructed tracks with the simulated ones +/// +/// \author Philippe Pillot, Subatech + +#include "TrackMCLabelFinderSpec.h" +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext&) +{ + return WorkflowSpec{o2::mch::getTrackMCLabelFinderSpec()}; +} diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-reader-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-reader-workflow.cxx new file mode 100644 index 0000000000000..93e5a3e99566e --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/tracks-reader-workflow.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include "Framework/ConfigParamSpec.h" +#include "MCHWorkflow/TrackReaderSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("enable-mc", VariantType::Bool, false, ConfigParamSpec::HelpString{"Propagate MC info"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& config) +{ + bool useMC = config.options().get<bool>("enable-mc"); + return WorkflowSpec{o2::mch::getTrackReaderSpec(useMC)}; +} diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-sampler-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-sampler-workflow.cxx index 1f1c59af61ff9..adba3c2e941ff 100644 --- a/Detectors/MUON/MCH/Workflow/src/tracks-sampler-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/tracks-sampler-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,5 +34,5 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(const ConfigContext& config) { bool forTrackFitter = config.options().get<bool>("forTrackFitter"); - return WorkflowSpec{o2::mch::getTrackSamplerSpec(forTrackFitter)}; + return WorkflowSpec{o2::mch::getTrackSamplerSpec("mch-track-sampler", forTrackFitter)}; } diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-sink-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-sink-workflow.cxx index 16e3b9572f39d..f27a54df56e8e 100644 --- a/Detectors/MUON/MCH/Workflow/src/tracks-sink-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/tracks-sink-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,5 +37,5 @@ WorkflowSpec defineDataProcessing(const ConfigContext& config) { bool mchTracks = !config.options().get<bool>("tracksAtVertexOnly"); bool tracksAtVtx = !config.options().get<bool>("mchTracksOnly"); - return WorkflowSpec{o2::mch::getTrackSinkSpec(mchTracks, tracksAtVtx)}; + return WorkflowSpec{o2::mch::getTrackSinkSpec("mch-track-sink", mchTracks, tracksAtVtx)}; } diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-at-vertex-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-at-vertex-workflow.cxx index 4f5d55ca857a0..87288a800092c 100644 --- a/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-at-vertex-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-at-vertex-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,25 @@ /// /// \author Philippe Pillot, Subatech -#include "Framework/runDataProcessing.h" - +#include "CommonUtils/ConfigurableParam.h" #include "TrackAtVertexSpec.h" using namespace o2::framework; -WorkflowSpec defineDataProcessing(const ConfigContext&) +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) { + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); return WorkflowSpec{o2::mch::getTrackAtVertexSpec()}; } diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-workflow.cxx index 6f3673cd35f7d..ee9ade4eac73f 100644 --- a/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/tracks-to-tracks-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MCH/Workflow/src/tracks-writer-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/tracks-writer-workflow.cxx new file mode 100644 index 0000000000000..aae99315121ca --- /dev/null +++ b/Detectors/MUON/MCH/Workflow/src/tracks-writer-workflow.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include "Framework/ConfigParamSpec.h" +#include "MCHWorkflow/TrackWriterSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.emplace_back("enable-mc", VariantType::Bool, false, ConfigParamSpec::HelpString{"Propagate MC info"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& config) +{ + bool useMC = config.options().get<bool>("enable-mc"); + return WorkflowSpec{o2::mch::getTrackWriterSpec(useMC)}; +} diff --git a/Detectors/MUON/MCH/Workflow/src/vertex-sampler-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/vertex-sampler-workflow.cxx index f43ded9067fc2..4a6a79d7af0e1 100644 --- a/Detectors/MUON/MCH/Workflow/src/vertex-sampler-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/vertex-sampler-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/CMakeLists.txt b/Detectors/MUON/MID/Base/CMakeLists.txt index e67fab19f958d..e835a5ecad1c5 100644 --- a/Detectors/MUON/MID/Base/CMakeLists.txt +++ b/Detectors/MUON/MID/Base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MIDBase SOURCES src/ChamberEfficiency.cxx diff --git a/Detectors/MUON/MID/Base/include/MIDBase/ChamberEfficiency.h b/Detectors/MUON/MID/Base/include/MIDBase/ChamberEfficiency.h index 171e01189c7ad..9052411206093 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/ChamberEfficiency.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/ChamberEfficiency.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/include/MIDBase/DetectorParameters.h b/Detectors/MUON/MID/Base/include/MIDBase/DetectorParameters.h index 4eb21d8f9aab4..383c4f1a921df 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/DetectorParameters.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/DetectorParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/include/MIDBase/GeometryParameters.h b/Detectors/MUON/MID/Base/include/MIDBase/GeometryParameters.h index ba36354a65444..cb2407a533038 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/GeometryParameters.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/GeometryParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/include/MIDBase/GeometryTransformer.h b/Detectors/MUON/MID/Base/include/MIDBase/GeometryTransformer.h index 141f936d14da0..877f08faa6590 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/GeometryTransformer.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/GeometryTransformer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/include/MIDBase/Mapping.h b/Detectors/MUON/MID/Base/include/MIDBase/Mapping.h index 4a86e286ff5b3..d0844087fc137 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/Mapping.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/Mapping.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/include/MIDBase/MpArea.h b/Detectors/MUON/MID/Base/include/MIDBase/MpArea.h index 963a935f962ef..ee86ca30a04a5 100644 --- a/Detectors/MUON/MID/Base/include/MIDBase/MpArea.h +++ b/Detectors/MUON/MID/Base/include/MIDBase/MpArea.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/ChamberEfficiency.cxx b/Detectors/MUON/MID/Base/src/ChamberEfficiency.cxx index de29dffa37a06..59e3582000c59 100644 --- a/Detectors/MUON/MID/Base/src/ChamberEfficiency.cxx +++ b/Detectors/MUON/MID/Base/src/ChamberEfficiency.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/DetectorParameters.cxx b/Detectors/MUON/MID/Base/src/DetectorParameters.cxx index 07d7c7b3105ad..cf5b42bef913f 100644 --- a/Detectors/MUON/MID/Base/src/DetectorParameters.cxx +++ b/Detectors/MUON/MID/Base/src/DetectorParameters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/GeometryParameters.cxx b/Detectors/MUON/MID/Base/src/GeometryParameters.cxx index 97631fa9f60d4..61ea4b13bba46 100644 --- a/Detectors/MUON/MID/Base/src/GeometryParameters.cxx +++ b/Detectors/MUON/MID/Base/src/GeometryParameters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/GeometryTransformer.cxx b/Detectors/MUON/MID/Base/src/GeometryTransformer.cxx index a379ec2d646ee..7d1836744c953 100644 --- a/Detectors/MUON/MID/Base/src/GeometryTransformer.cxx +++ b/Detectors/MUON/MID/Base/src/GeometryTransformer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/Mapping.cxx b/Detectors/MUON/MID/Base/src/Mapping.cxx index 43c2723355b68..b2f1be0596f7b 100644 --- a/Detectors/MUON/MID/Base/src/Mapping.cxx +++ b/Detectors/MUON/MID/Base/src/Mapping.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/src/MpArea.cxx b/Detectors/MUON/MID/Base/src/MpArea.cxx index cc8880339ab15..e82abeded5a52 100644 --- a/Detectors/MUON/MID/Base/src/MpArea.cxx +++ b/Detectors/MUON/MID/Base/src/MpArea.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/test/CMakeLists.txt b/Detectors/MUON/MID/Base/test/CMakeLists.txt index d86f7fd6d8b76..ca3d5c02497f5 100644 --- a/Detectors/MUON/MID/Base/test/CMakeLists.txt +++ b/Detectors/MUON/MID/Base/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(Mapping SOURCES src/testMapping.cxx diff --git a/Detectors/MUON/MID/Base/test/src/Positions.cxx b/Detectors/MUON/MID/Base/test/src/Positions.cxx index 26f4af756d6cc..e060d708c8e6f 100644 --- a/Detectors/MUON/MID/Base/test/src/Positions.cxx +++ b/Detectors/MUON/MID/Base/test/src/Positions.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Base/test/src/testMapping.cxx b/Detectors/MUON/MID/Base/test/src/testMapping.cxx index ba17be2bec33b..86565dc4cc2e3 100644 --- a/Detectors/MUON/MID/Base/test/src/testMapping.cxx +++ b/Detectors/MUON/MID/Base/test/src/testMapping.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/CMakeLists.txt b/Detectors/MUON/MID/CMakeLists.txt index f24f88c11354c..bf9591a2287b9 100644 --- a/Detectors/MUON/MID/CMakeLists.txt +++ b/Detectors/MUON/MID/CMakeLists.txt @@ -1,18 +1,21 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Base) add_subdirectory(Clustering) +add_subdirectory(Conditions) +add_subdirectory(CTF) +add_subdirectory(Filtering) add_subdirectory(QC) add_subdirectory(Raw) -add_subdirectory(CTF) add_subdirectory(Simulation) add_subdirectory(TestingSimTools) add_subdirectory(Tracking) diff --git a/Detectors/MUON/MID/CTF/CMakeLists.txt b/Detectors/MUON/MID/CTF/CMakeLists.txt index 2f0fc3b383a68..af8333651cbb6 100644 --- a/Detectors/MUON/MID/CTF/CMakeLists.txt +++ b/Detectors/MUON/MID/CTF/CMakeLists.txt @@ -1,19 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MIDCTF SOURCES src/CTFCoder.cxx src/CTFHelper.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsMID O2::DetectorsBase O2::CommonDataFormat - O2::DetectorsCommonDataFormats + O2::DetectorsCommonDataFormats O2::rANS - ms_gsl::ms_gsl) + Microsoft.GSL::GSL) diff --git a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h index da7a2cd56ba9a..8fe4b45184502 100644 --- a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h +++ b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,22 +43,22 @@ class CTFCoder : public o2::ctf::CTFCoderBase /// entropy-encode data to buffer with CTF template <typename VEC> - void encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, const gsl::span<const ColumnData>& colData); + void encode(VEC& buff, const CTFHelper::TFData& tfData); /// entropy decode data from buffer with CTF template <typename VROF, typename VCOL> - void decode(const CTF::base& ec, VROF& rofVec, VCOL& colVec); + void decode(const CTF::base& ec, std::array<VROF, NEvTypes>& rofVec, std::array<VCOL, NEvTypes>& colVec); void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); private: void appendToTree(TTree& tree, CTF& ec); - void readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofVec, std::vector<ColumnData>& colVec); + void readFromTree(TTree& tree, int entry, std::array<std::vector<ROFRecord>, NEvTypes>& rofVec, std::array<std::vector<ColumnData>, NEvTypes>& colVec); }; /// entropy-encode clusters to buffer with CTF template <typename VEC> -void CTFCoder::encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, const gsl::span<const ColumnData>& colData) +void CTFCoder::encode(VEC& buff, const CTFHelper::TFData& tfData) { using MD = o2::ctf::Metadata::OptStore; // what to do which each field: see o2::ctd::Metadata explanation @@ -70,16 +71,17 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, cons MD::EENCODE, // BLC_deId MD::EENCODE // BLC_colId }; - CTFHelper helper(rofData, colData); + CTFHelper helper(tfData); // book output size with some margin - auto szIni = sizeof(CTFHeader) + helper.getSize() / 4; // will be autoexpanded if needed + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed buff.resize(szIni); auto ec = CTF::create(buff); using ECB = CTF::base; ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -99,9 +101,10 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const ROFRecord>& rofData, cons /// decode entropy-encoded clusters to standard compact clusters template <typename VROF, typename VCOL> -void CTFCoder::decode(const CTF::base& ec, VROF& rofVec, VCOL& colVec) +void CTFCoder::decode(const CTF::base& ec, std::array<VROF, NEvTypes>& rofVec, std::array<VCOL, NEvTypes>& colVec) { auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); ec.print(getPrefix()); std::vector<uint16_t> bcInc, entries, pattern; std::vector<uint32_t> orbitInc; @@ -119,10 +122,12 @@ void CTFCoder::decode(const CTF::base& ec, VROF& rofVec, VCOL& colVec) DECODEMID(colId, CTF::BLC_colId); // clang-format on // - rofVec.clear(); - colVec.clear(); - rofVec.reserve(header.nROFs); - colVec.reserve(header.nColumns); + for (uint32_t i = 0; i < NEvTypes; i++) { + rofVec[i].clear(); + colVec[i].clear(); + rofVec[i].reserve(header.nROFs); + colVec[i].reserve(header.nColumns); + } uint32_t firstEntry = 0, rofCount = 0, colCount = 0, pCount = 0; o2::InteractionRecord ir(header.firstBC, header.firstOrbit); @@ -135,14 +140,14 @@ void CTFCoder::decode(const CTF::base& ec, VROF& rofVec, VCOL& colVec) } else { ir.bc += bcInc[irof]; } - - firstEntry = colVec.size(); + auto& cv = colVec[evType[irof]]; + firstEntry = cv.size(); for (uint8_t ic = 0; ic < entries[irof]; ic++) { - colVec.emplace_back(ColumnData{deId[colCount], colId[colCount], std::array{pattern[pCount], pattern[pCount + 1], pattern[pCount + 2], pattern[pCount + 3], pattern[pCount + 4]}}); + cv.emplace_back(ColumnData{deId[colCount], colId[colCount], std::array{pattern[pCount], pattern[pCount + 1], pattern[pCount + 2], pattern[pCount + 3], pattern[pCount + 4]}}); pCount += 5; colCount++; } - rofVec.emplace_back(ROFRecord{ir, EventType(evType[irof]), firstEntry, entries[irof]}); + rofVec[evType[irof]].emplace_back(ROFRecord{ir, EventType(evType[irof]), firstEntry, entries[irof]}); } assert(colCount == header.nColumns); } diff --git a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFHelper.h b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFHelper.h index 832870fa9f5e5..22695cc87a5ea 100644 --- a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFHelper.h +++ b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "DataFormatsMID/ROFRecord.h" #include "DataFormatsMID/ColumnData.h" #include "DataFormatsMID/CTF.h" +#include "CommonDataFormat/AbstractRef.h" #include <gsl/span> namespace o2 @@ -29,20 +31,32 @@ class CTFHelper { public: - CTFHelper(const gsl::span<const o2::mid::ROFRecord>& rofData, const gsl::span<const o2::mid::ColumnData>& colData) - : mROFData(rofData), mColData(colData) {} + using OrderRef = o2::dataformats::AbstractRef<29, 2, 1>; // 29 bits for index in event type span, 2 bits for event type, 1 bit flag + struct TFData { + std::vector<OrderRef> colDataRefs{}; + std::vector<OrderRef> rofDataRefs{}; + std::array<gsl::span<const o2::mid::ColumnData>, NEvTypes> colData{}; + std::array<gsl::span<const o2::mid::ROFRecord>, NEvTypes> rofData{}; + void buildReferences(); + }; + + CTFHelper(const TFData& data) : mTFData(data) {} + CTFHelper() = delete; CTFHeader createHeader() { - CTFHeader h{uint32_t(mROFData.size()), uint32_t(mColData.size()), 0, 0}; - if (mROFData.size()) { - h.firstOrbit = mROFData[0].interactionRecord.orbit; - h.firstBC = mROFData[0].interactionRecord.bc; + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTFData.rofDataRefs.size()), uint32_t(mTFData.colDataRefs.size()), 0, 0}; + if (h.nROFs) { + auto id0 = mTFData.rofDataRefs.front(); + const auto& rof = mTFData.rofData[id0.getSource()][id0.getIndex()]; + h.firstOrbit = rof.interactionRecord.orbit; + h.firstBC = rof.interactionRecord.bc; } return h; } - size_t getSize() const { return mROFData.size() * sizeof(o2::mid::ROFRecord) + mColData.size() * sizeof(o2::mid::ColumnData); } + size_t getSize() const { return mTFData.rofDataRefs.size() * sizeof(o2::mid::ROFRecord) + mTFData.colDataRefs.size() * sizeof(o2::mid::ColumnData); } //>>> =========================== ITERATORS ======================================== @@ -56,7 +70,7 @@ class CTFHelper using reference = const T&; using iterator_category = std::random_access_iterator_tag; - _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter(const std::vector<OrderRef>& ord, const std::array<gsl::span<const D>, NEvTypes>& data, bool end = false) : mOrder(ord), mData(&data), mIndex(end ? M * ord.size() : 0) {} _Iter() = default; const I& operator++() @@ -87,7 +101,8 @@ class CTFHelper bool operator<(const I& other) const { return mIndex < other.mIndex; } protected: - gsl::span<const D> mData{}; + gsl::span<const OrderRef> mOrder{}; + const std::array<gsl::span<const D>, NEvTypes>* mData{}; size_t mIndex = 0; }; @@ -100,11 +115,13 @@ class CTFHelper using _Iter<Iter_bcIncROF, ROFRecord, uint16_t>::_Iter; value_type operator*() const { + const auto ir = (*mData)[mOrder[mIndex].getSource()][mOrder[mIndex].getIndex()].interactionRecord; if (mIndex) { - if (mData[mIndex].interactionRecord.orbit == mData[mIndex - 1].interactionRecord.orbit) { - return mData[mIndex].interactionRecord.bc - mData[mIndex - 1].interactionRecord.bc; + const auto irP = (*mData)[mOrder[mIndex - 1].getSource()][mOrder[mIndex - 1].getIndex()].interactionRecord; + if (ir.orbit == irP.orbit) { + return ir.bc - irP.bc; } else { - return mData[mIndex].interactionRecord.bc; + return ir.bc; } } return 0; @@ -117,7 +134,15 @@ class CTFHelper { public: using _Iter<Iter_orbitIncROF, ROFRecord, uint32_t>::_Iter; - value_type operator*() const { return mIndex ? mData[mIndex].interactionRecord.orbit - mData[mIndex - 1].interactionRecord.orbit : 0; } + value_type operator*() const + { + if (mIndex) { + const auto ir = (*mData)[mOrder[mIndex].getSource()][mOrder[mIndex].getIndex()].interactionRecord; + const auto irP = (*mData)[mOrder[mIndex - 1].getSource()][mOrder[mIndex - 1].getIndex()].interactionRecord; + return ir.orbit - irP.orbit; + } + return 0; + } }; //_______________________________________________ @@ -126,7 +151,7 @@ class CTFHelper { public: using _Iter<Iter_entriesROF, ROFRecord, uint16_t>::_Iter; - value_type operator*() const { return mData[mIndex].nEntries; } + value_type operator*() const { return (*mData)[mOrder[mIndex].getSource()][mOrder[mIndex].getIndex()].nEntries; } }; //_______________________________________________ @@ -135,7 +160,7 @@ class CTFHelper { public: using _Iter<Iter_evtypeROF, ROFRecord, uint8_t>::_Iter; - value_type operator*() const { return value_type(mData[mIndex].eventType); } + value_type operator*() const { return value_type((*mData)[mOrder[mIndex].getSource()][mOrder[mIndex].getIndex()].eventType); } }; //_______________________________________________ @@ -143,7 +168,11 @@ class CTFHelper { public: using _Iter<Iter_pattern, ColumnData, uint16_t, 5>::_Iter; - value_type operator*() const { return mData[mIndex / 5].patterns[mIndex % 5]; } + value_type operator*() const + { + auto idx = mOrder[mIndex / 5]; + return (*mData)[idx.getSource()][idx.getIndex()].patterns[mIndex % 5]; + } }; //_______________________________________________ @@ -151,7 +180,11 @@ class CTFHelper { public: using _Iter<Iter_deId, ColumnData, uint8_t>::_Iter; - value_type operator*() const { return mData[mIndex].deId; } + value_type operator*() const + { + auto idx = mOrder[mIndex]; + return (*mData)[idx.getSource()][idx.getIndex()].deId; + } }; //_______________________________________________ @@ -159,35 +192,38 @@ class CTFHelper { public: using _Iter<Iter_colId, ColumnData, uint8_t>::_Iter; - value_type operator*() const { return mData[mIndex].columnId; } + value_type operator*() const + { + auto idx = mOrder[mIndex]; + return (*mData)[idx.getSource()][idx.getIndex()].columnId; + } }; //<<< =========================== ITERATORS ======================================== - Iter_bcIncROF begin_bcIncROF() const { return Iter_bcIncROF(mROFData, false); } - Iter_bcIncROF end_bcIncROF() const { return Iter_bcIncROF(mROFData, true); } + Iter_bcIncROF begin_bcIncROF() const { return Iter_bcIncROF(mTFData.rofDataRefs, mTFData.rofData, false); } + Iter_bcIncROF end_bcIncROF() const { return Iter_bcIncROF(mTFData.rofDataRefs, mTFData.rofData, true); } - Iter_orbitIncROF begin_orbitIncROF() const { return Iter_orbitIncROF(mROFData, false); } - Iter_orbitIncROF end_orbitIncROF() const { return Iter_orbitIncROF(mROFData, true); } + Iter_orbitIncROF begin_orbitIncROF() const { return Iter_orbitIncROF(mTFData.rofDataRefs, mTFData.rofData, false); } + Iter_orbitIncROF end_orbitIncROF() const { return Iter_orbitIncROF(mTFData.rofDataRefs, mTFData.rofData, true); } - Iter_entriesROF begin_entriesROF() const { return Iter_entriesROF(mROFData, false); } - Iter_entriesROF end_entriesROF() const { return Iter_entriesROF(mROFData, true); } + Iter_entriesROF begin_entriesROF() const { return Iter_entriesROF(mTFData.rofDataRefs, mTFData.rofData, false); } + Iter_entriesROF end_entriesROF() const { return Iter_entriesROF(mTFData.rofDataRefs, mTFData.rofData, true); } - Iter_evtypeROF begin_evtypeROF() const { return Iter_evtypeROF(mROFData, false); } - Iter_evtypeROF end_evtypeROF() const { return Iter_evtypeROF(mROFData, true); } + Iter_evtypeROF begin_evtypeROF() const { return Iter_evtypeROF(mTFData.rofDataRefs, mTFData.rofData, false); } + Iter_evtypeROF end_evtypeROF() const { return Iter_evtypeROF(mTFData.rofDataRefs, mTFData.rofData, true); } - Iter_pattern begin_pattern() const { return Iter_pattern(mColData, false); } - Iter_pattern end_pattern() const { return Iter_pattern(mColData, true); } + Iter_pattern begin_pattern() const { return Iter_pattern(mTFData.colDataRefs, mTFData.colData, false); } + Iter_pattern end_pattern() const { return Iter_pattern(mTFData.colDataRefs, mTFData.colData, true); } - Iter_deId begin_deId() const { return Iter_deId(mColData, false); } - Iter_deId end_deId() const { return Iter_deId(mColData, true); } + Iter_deId begin_deId() const { return Iter_deId(mTFData.colDataRefs, mTFData.colData, false); } + Iter_deId end_deId() const { return Iter_deId(mTFData.colDataRefs, mTFData.colData, true); } - Iter_colId begin_colId() const { return Iter_colId(mColData, false); } - Iter_colId end_colId() const { return Iter_colId(mColData, true); } + Iter_colId begin_colId() const { return Iter_colId(mTFData.colDataRefs, mTFData.colData, false); } + Iter_colId end_colId() const { return Iter_colId(mTFData.colDataRefs, mTFData.colData, true); } private: - const gsl::span<const o2::mid::ROFRecord> mROFData; - const gsl::span<const o2::mid::ColumnData> mColData; + const TFData& mTFData; }; } // namespace mid diff --git a/Detectors/MUON/MID/CTF/src/CTFCoder.cxx b/Detectors/MUON/MID/CTF/src/CTFCoder.cxx index 0dc55d6763ae1..3ed8c384a4223 100644 --- a/Detectors/MUON/MID/CTF/src/CTFCoder.cxx +++ b/Detectors/MUON/MID/CTF/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,8 @@ void CTFCoder::appendToTree(TTree& tree, CTF& ec) ///___________________________________________________________________________________ // extract and decode data from the tree -void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ROFRecord>& rofVec, std::vector<ColumnData>& colVec) +void CTFCoder::readFromTree(TTree& tree, int entry, std::array<std::vector<ROFRecord>, NEvTypes>& rofVec, + std::array<std::vector<ColumnData>, NEvTypes>& colVec) { assert(entry >= 0 && entry < tree.GetEntries()); CTF ec; @@ -65,7 +67,7 @@ void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase:: uint8_t evType = 0, deId = 0, colId = 0; #define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) // clang-format off - MAKECODER(bcInc, CTF::BLC_bcIncROF); + MAKECODER(bcInc, CTF::BLC_bcIncROF); MAKECODER(orbitInc, CTF::BLC_orbitIncROF); MAKECODER(entries, CTF::BLC_entriesROF); MAKECODER(evType, CTF::BLC_evtypeROF); diff --git a/Detectors/MUON/MID/CTF/src/CTFHelper.cxx b/Detectors/MUON/MID/CTF/src/CTFHelper.cxx index e512ac535fff4..83fb7da3368c7 100644 --- a/Detectors/MUON/MID/CTF/src/CTFHelper.cxx +++ b/Detectors/MUON/MID/CTF/src/CTFHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,3 +14,35 @@ /// \brief Helper for MID CTF creation #include "MIDCTF/CTFHelper.h" + +using namespace o2::mid; + +void CTFHelper::TFData::buildReferences() +{ + uint32_t nDone = 0, idx[NEvTypes] = {}; + uint32_t sizes[NEvTypes] = { + uint32_t(rofData[size_t(EventType::Standard)].size()), + uint32_t(rofData[size_t(EventType::Calib)].size()), + uint32_t(rofData[size_t(EventType::FET)].size())}; + uint64_t rofBC[NEvTypes] = {}; + auto fillNextROFBC = [&nDone, &rofBC, &idx, &sizes, this](int it) { + if (idx[it] < sizes[it]) { + rofBC[it] = this->rofData[it][idx[it]].interactionRecord.toLong(); + } else { + rofBC[it] = -1; + nDone++; + } + }; + for (uint32_t it = 0; it < NEvTypes; it++) { + fillNextROFBC(it); + } + while (nDone < NEvTypes) { // find next ROFRecord with smallest BC, untill all 3 spans are traversed + int selT = rofBC[0] <= rofBC[1] ? (rofBC[0] <= rofBC[2] ? 0 : 2) : (rofBC[1] <= rofBC[2] ? 1 : 2); + rofDataRefs.emplace_back(idx[selT], selT); + for (uint32_t ic = rofData[selT][idx[selT]].firstEntry; ic < rofData[selT][idx[selT]].getEndIndex(); ic++) { + colDataRefs.emplace_back(ic, selT); // register indices of corresponding column data + } + ++idx[selT]; // increment used index + fillNextROFBC(selT); + } +} \ No newline at end of file diff --git a/Detectors/MUON/MID/Clustering/CMakeLists.txt b/Detectors/MUON/MID/Clustering/CMakeLists.txt index 2a2d546d4039b..e44586ca9e762 100644 --- a/Detectors/MUON/MID/Clustering/CMakeLists.txt +++ b/Detectors/MUON/MID/Clustering/CMakeLists.txt @@ -1,18 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MIDClustering SOURCES src/Clusterizer.cxx src/PreClusterizer.cxx src/PreCluster.cxx src/PreClusterHelper.cxx src/PreClustersDE.cxx - PUBLIC_LINK_LIBRARIES O2::MIDBase ms_gsl::ms_gsl) + PUBLIC_LINK_LIBRARIES O2::MIDBase Microsoft.GSL::GSL) if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/Detectors/MUON/MID/Clustering/include/MIDClustering/Clusterizer.h b/Detectors/MUON/MID/Clustering/include/MIDClustering/Clusterizer.h index 99a97c8f78c9f..a35480948308b 100644 --- a/Detectors/MUON/MID/Clustering/include/MIDClustering/Clusterizer.h +++ b/Detectors/MUON/MID/Clustering/include/MIDClustering/Clusterizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,7 +61,8 @@ class Clusterizer std::vector<Cluster2D> mClusters{}; ///< List of clusters std::vector<ROFRecord> mROFRecords{}; ///< List of cluster RO frame records size_t mPreClusterOffset{0}; //!< RO offset for pre-cluster - std::function<void(size_t, size_t)> mFunction; ///! Function to keep track of input-output relation + + std::function<void(size_t, size_t)> mFunction{[](size_t, size_t) {}}; ///! Function to keep track of input-output relation }; } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreCluster.h b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreCluster.h index c72cf7a7164d3..51390cafa4841 100644 --- a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreCluster.h +++ b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterHelper.h b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterHelper.h index 55b831ef728ae..f6f57e03bf5c2 100644 --- a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterHelper.h +++ b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterizer.h b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterizer.h index dcdef95c2d909..3da3421c37e30 100644 --- a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterizer.h +++ b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClusterizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -44,8 +45,8 @@ class PreClusterizer private: struct PatternStruct { - int deId; ///< Detection element ID - int firedColumns; ///< Fired columns + int deId = 0; ///< Detection element ID + int firedColumns = 0; ///< Fired columns std::array<ColumnData, 7> columns; ///< Array of strip patterns }; diff --git a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClustersDE.h b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClustersDE.h index c5e5db1eb9ed8..d560d9b9404c6 100644 --- a/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClustersDE.h +++ b/Detectors/MUON/MID/Clustering/include/MIDClustering/PreClustersDE.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #ifndef O2_MID_PRECLUSTERSDE_H #define O2_MID_PRECLUSTERSDE_H +#include <cstddef> #include <array> #include <vector> #include "MIDBase/MpArea.h" @@ -51,8 +53,7 @@ class PreClustersDE BP& getPreClusterBP(int icolumn, int idx) { return mPreClustersBP[icolumn][idx]; } /// Gets pre-cluster in the BP (const version) - const BP& - getPreClusterBP(int icolumn, int idx) const { return mPreClustersBP[icolumn][idx]; } + const BP& getPreClusterBP(int icolumn, int idx) const { return mPreClustersBP[icolumn][idx]; } /// Gets the number of pre-clusters in the NBP size_t getNPreClustersNBP() const { return mPreClustersNBP.size(); } diff --git a/Detectors/MUON/MID/Clustering/src/Clusterizer.cxx b/Detectors/MUON/MID/Clustering/src/Clusterizer.cxx index e841b3b0cd105..c1a9e7718e833 100644 --- a/Detectors/MUON/MID/Clustering/src/Clusterizer.cxx +++ b/Detectors/MUON/MID/Clustering/src/Clusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/src/PreCluster.cxx b/Detectors/MUON/MID/Clustering/src/PreCluster.cxx index edb055f9a9db9..8510a25987d32 100644 --- a/Detectors/MUON/MID/Clustering/src/PreCluster.cxx +++ b/Detectors/MUON/MID/Clustering/src/PreCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/src/PreClusterHelper.cxx b/Detectors/MUON/MID/Clustering/src/PreClusterHelper.cxx index b0c90c065769d..6612bbe92439f 100644 --- a/Detectors/MUON/MID/Clustering/src/PreClusterHelper.cxx +++ b/Detectors/MUON/MID/Clustering/src/PreClusterHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/src/PreClusterizer.cxx b/Detectors/MUON/MID/Clustering/src/PreClusterizer.cxx index e4fa364ce6d27..43d60f2ce490e 100644 --- a/Detectors/MUON/MID/Clustering/src/PreClusterizer.cxx +++ b/Detectors/MUON/MID/Clustering/src/PreClusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/src/PreClustersDE.cxx b/Detectors/MUON/MID/Clustering/src/PreClustersDE.cxx index 7f68b22fa7f8c..86c05f82b634e 100644 --- a/Detectors/MUON/MID/Clustering/src/PreClustersDE.cxx +++ b/Detectors/MUON/MID/Clustering/src/PreClustersDE.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ std::vector<int> PreClustersDE::getNeighbours(int icolumn, int idx) const } const BP& pcB = mPreClustersBP[icolumn][idx]; for (int ib = 0; ib < mPreClustersBP[icolumn + 1].size(); ++ib) { - const BP& neigh = mPreClustersBP[icolumn + 1][idx]; + const BP& neigh = mPreClustersBP[icolumn + 1][ib]; if (neigh.area.getYmin() > pcB.area.getYmax()) { continue; } diff --git a/Detectors/MUON/MID/Clustering/test/CMakeLists.txt b/Detectors/MUON/MID/Clustering/test/CMakeLists.txt index 3ccd5f4155621..6c995c18fa658 100644 --- a/Detectors/MUON/MID/Clustering/test/CMakeLists.txt +++ b/Detectors/MUON/MID/Clustering/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(Clusterizer SOURCES testClusterizer.cxx diff --git a/Detectors/MUON/MID/Clustering/test/bench_Clusterizer.cxx b/Detectors/MUON/MID/Clustering/test/bench_Clusterizer.cxx index 5903155066e42..9a3c34ee252d5 100644 --- a/Detectors/MUON/MID/Clustering/test/bench_Clusterizer.cxx +++ b/Detectors/MUON/MID/Clustering/test/bench_Clusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Clustering/test/testClusterizer.cxx b/Detectors/MUON/MID/Clustering/test/testClusterizer.cxx index 16b7b52053e4d..a0d76d10f62d5 100644 --- a/Detectors/MUON/MID/Clustering/test/testClusterizer.cxx +++ b/Detectors/MUON/MID/Clustering/test/testClusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Conditions/CMakeLists.txt b/Detectors/MUON/MID/Conditions/CMakeLists.txt new file mode 100644 index 0000000000000..49234661d6de7 --- /dev/null +++ b/Detectors/MUON/MID/Conditions/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library( + MIDConditions + SOURCES src/DCSNamer.cxx + PUBLIC_LINK_LIBRARIES O2::MIDBase fmt::fmt) + +if(BUILD_TESTING) + o2_add_test( + dcs-namer + SOURCES test/testDCSNamer.cxx test/HVAliases.cxx + COMPONENT_NAME mid + LABELS "muon;mid;dcs" + PUBLIC_LINK_LIBRARIES O2::MIDConditions) +endif() + diff --git a/Detectors/MUON/MID/Conditions/include/MIDConditions/DCSNamer.h b/Detectors/MUON/MID/Conditions/include/MIDConditions/DCSNamer.h new file mode 100644 index 0000000000000..cf862ba4472a5 --- /dev/null +++ b/Detectors/MUON/MID/Conditions/include/MIDConditions/DCSNamer.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MID_CONDITIONS_DCS_NAMER_H +#define O2_MID_CONDITIONS_DCS_NAMER_H + +#include <vector> +#include <string> +#include <optional> +#include <cstdint> + +namespace o2::mid::dcs +{ +// The two types of MID DCS measurements that are of interest for reconstruction +enum class MeasurementType { + HV_V, // HV voltage + HV_I // HV current +}; + +// Side describes on which side (inside or outside) a RPC is. +enum class Side { + Inside, + Outside +}; + +// ID is used to reference a RPC in MID DCS. +struct ID { + int number; + Side side; + int chamberId; // 11,12,21,22 +}; + +// detElemId2DCS converts a detection element id into a dcs-id. +// @returns an ID if deId is a valid the MID detID, std::nullopt otherwise. +std::optional<ID> detElemId2DCS(int deId); + +// aliases gets a list of MID DCS aliases for the given measurement type(s). +// @param types a vector of the measurement types for which the aliases should +// be returned. +// @returns a list of MID DCS alias names. +std::vector<std::string> aliases(std::vector<MeasurementType> types = { + MeasurementType::HV_V, + MeasurementType::HV_I}); + +} // namespace o2::mid::dcs + +#endif diff --git a/Detectors/MUON/MID/Conditions/src/DCSNamer.cxx b/Detectors/MUON/MID/Conditions/src/DCSNamer.cxx new file mode 100644 index 0000000000000..e70ec743bc4dd --- /dev/null +++ b/Detectors/MUON/MID/Conditions/src/DCSNamer.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "MIDConditions/DCSNamer.h" +#include "MIDBase/DetectorParameters.h" +#include <array> +#include <fmt/printf.h> +#include <iostream> +#include <set> +#include <optional> +#include <stdexcept> +#include <fmt/format.h> + +namespace +{ +const std::string detPrefix = "MID"; + +// Run2 (0..71) vs Run3 (11xx, 12xx, 13xx, 14xx) detection element ids +// +// INSIDE: 0..35 +// +// 1100,1101,1102,1103,1104, +// 4, 5, 6, 7, 8, +// 1114,1115,1116,1117, +// 0, 1, 2, 3, +// 1200,1201,1202,1203,1204, +// 17, 16, 15, 14, 13, +// 1214,1215,1216,1217, +// 9, 10, 11, 12, +// 1300,1301,1302,1303,1304, +// 26, 25, 24, 23, 22, +// 1314,1315,1316,1317, +// 18, 19, 20, 21, +// 1400,1401,1402,1403,1404, +// 35, 34, 33, 32, 31, +// 1414,1415,1416,1417, +// 27, 28, 29, 30, +// +// OUTSIDE : 36..71 +// +// 1105,1106,1107,1108,1109, +// 44, 43, 42, 41, 40, +// 1110,1111,1112,1113, +// 39, 38, 37, 36 +// 1205,1206,1207,1208,1209, +// 53, 52, 51, 50, 49, +// 1210,1211,1212,1213, +// 48, 47, 46, 45, +// 1305,1306,1307,1308,1309, +// 62, 61, 60, 59, +// 1310,1311,1312,1313, +// 58, 57, 56, 55, 54, +// 1405,1406,1407,1408,1409, +// 71, 70, 69, 68, 67, +// 1410,1411,1412,1413, +// 66, 65, 64, 63, + +std::string sideName(o2::mid::dcs::Side side) +{ + if (side == o2::mid::dcs::Side::Inside) { + return "INSIDE"; + } + if (side == o2::mid::dcs::Side::Outside) { + return "OUTSIDE"; + } + return "INVALID"; +} + +std::string measurementName(o2::mid::dcs::MeasurementType m) +{ + switch (m) { + case o2::mid::dcs::MeasurementType::HV_V: + return "vEff"; + case o2::mid::dcs::MeasurementType::HV_I: + return "actual.iMon"; + } + return "INVALID"; +} + +std::vector<std::string> measurement(const std::vector<std::string>& patterns, + o2::mid::dcs::MeasurementType m) +{ + std::vector<std::string> result; + + result.resize(patterns.size()); + + std::transform(patterns.begin(), patterns.end(), result.begin(), [&m](std::string s) { + return fmt::sprintf(s, measurementName(m)); + }); + + std::sort(result.begin(), result.end()); + return result; +} + +} // namespace + +namespace o2::mid::dcs +{ +std::optional<ID> detElemId2DCS(int deId) +{ + if (deId < 0 || deId > 71) { + return std::nullopt; + } + int chamberId = detparams::getChamber(deId); + int id = 1 + detparams::getRPCLine(deId); + Side side = detparams::isRightSide(deId) ? Side::Inside : Side::Outside; + + switch (chamberId) { + case 0: + chamberId = 11; + break; + case 1: + chamberId = 12; + break; + case 2: + chamberId = 21; + break; + case 3: + chamberId = 22; + break; + default: + throw std::runtime_error(fmt::format("invalid chamberId={} : expected between 0 and 3", chamberId)); + } + + return std::optional<ID>{{id, side, chamberId}}; +} + +std::vector<std::string> aliases(std::vector<MeasurementType> types) +{ + + std::vector<std::string> patterns; + for (auto deId = 0; deId < detparams::NDetectionElements; ++deId) { + auto id = detElemId2DCS(deId); + auto pattern = fmt::format("{}_{}_MT{}_RPC{}_HV.", detPrefix, + sideName(id->side), id->chamberId, id->number) + + "%s"; + patterns.emplace_back(pattern); + } + std::vector<std::string> aliases; + + for (auto m : types) { + if (m == MeasurementType::HV_V || m == MeasurementType::HV_I) { + auto aliasPerType = measurement(patterns, m); + aliases.insert(aliases.begin(), aliasPerType.begin(), aliasPerType.end()); + } + } + return aliases; +} + +} // namespace o2::mid::dcs diff --git a/Detectors/MUON/MID/Conditions/test/HVAliases.cxx b/Detectors/MUON/MID/Conditions/test/HVAliases.cxx new file mode 100644 index 0000000000000..244223a0532ec --- /dev/null +++ b/Detectors/MUON/MID/Conditions/test/HVAliases.cxx @@ -0,0 +1,160 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "HVAliases.h" + +std::vector<std::string> expectedHVAliasesVoltages = { + "MID_INSIDE_MT11_RPC1_HV.vEff", + "MID_INSIDE_MT11_RPC2_HV.vEff", + "MID_INSIDE_MT11_RPC3_HV.vEff", + "MID_INSIDE_MT11_RPC4_HV.vEff", + "MID_INSIDE_MT11_RPC5_HV.vEff", + "MID_INSIDE_MT11_RPC6_HV.vEff", + "MID_INSIDE_MT11_RPC7_HV.vEff", + "MID_INSIDE_MT11_RPC8_HV.vEff", + "MID_INSIDE_MT11_RPC9_HV.vEff", + "MID_INSIDE_MT12_RPC1_HV.vEff", + "MID_INSIDE_MT12_RPC2_HV.vEff", + "MID_INSIDE_MT12_RPC3_HV.vEff", + "MID_INSIDE_MT12_RPC4_HV.vEff", + "MID_INSIDE_MT12_RPC5_HV.vEff", + "MID_INSIDE_MT12_RPC6_HV.vEff", + "MID_INSIDE_MT12_RPC7_HV.vEff", + "MID_INSIDE_MT12_RPC8_HV.vEff", + "MID_INSIDE_MT12_RPC9_HV.vEff", + "MID_INSIDE_MT21_RPC1_HV.vEff", + "MID_INSIDE_MT21_RPC2_HV.vEff", + "MID_INSIDE_MT21_RPC3_HV.vEff", + "MID_INSIDE_MT21_RPC4_HV.vEff", + "MID_INSIDE_MT21_RPC5_HV.vEff", + "MID_INSIDE_MT21_RPC6_HV.vEff", + "MID_INSIDE_MT21_RPC7_HV.vEff", + "MID_INSIDE_MT21_RPC8_HV.vEff", + "MID_INSIDE_MT21_RPC9_HV.vEff", + "MID_INSIDE_MT22_RPC1_HV.vEff", + "MID_INSIDE_MT22_RPC2_HV.vEff", + "MID_INSIDE_MT22_RPC3_HV.vEff", + "MID_INSIDE_MT22_RPC4_HV.vEff", + "MID_INSIDE_MT22_RPC5_HV.vEff", + "MID_INSIDE_MT22_RPC6_HV.vEff", + "MID_INSIDE_MT22_RPC7_HV.vEff", + "MID_INSIDE_MT22_RPC8_HV.vEff", + "MID_INSIDE_MT22_RPC9_HV.vEff", + "MID_OUTSIDE_MT11_RPC1_HV.vEff", + "MID_OUTSIDE_MT11_RPC2_HV.vEff", + "MID_OUTSIDE_MT11_RPC3_HV.vEff", + "MID_OUTSIDE_MT11_RPC4_HV.vEff", + "MID_OUTSIDE_MT11_RPC5_HV.vEff", + "MID_OUTSIDE_MT11_RPC6_HV.vEff", + "MID_OUTSIDE_MT11_RPC7_HV.vEff", + "MID_OUTSIDE_MT11_RPC8_HV.vEff", + "MID_OUTSIDE_MT11_RPC9_HV.vEff", + "MID_OUTSIDE_MT12_RPC1_HV.vEff", + "MID_OUTSIDE_MT12_RPC2_HV.vEff", + "MID_OUTSIDE_MT12_RPC3_HV.vEff", + "MID_OUTSIDE_MT12_RPC4_HV.vEff", + "MID_OUTSIDE_MT12_RPC5_HV.vEff", + "MID_OUTSIDE_MT12_RPC6_HV.vEff", + "MID_OUTSIDE_MT12_RPC7_HV.vEff", + "MID_OUTSIDE_MT12_RPC8_HV.vEff", + "MID_OUTSIDE_MT12_RPC9_HV.vEff", + "MID_OUTSIDE_MT21_RPC1_HV.vEff", + "MID_OUTSIDE_MT21_RPC2_HV.vEff", + "MID_OUTSIDE_MT21_RPC3_HV.vEff", + "MID_OUTSIDE_MT21_RPC4_HV.vEff", + "MID_OUTSIDE_MT21_RPC5_HV.vEff", + "MID_OUTSIDE_MT21_RPC6_HV.vEff", + "MID_OUTSIDE_MT21_RPC7_HV.vEff", + "MID_OUTSIDE_MT21_RPC8_HV.vEff", + "MID_OUTSIDE_MT21_RPC9_HV.vEff", + "MID_OUTSIDE_MT22_RPC1_HV.vEff", + "MID_OUTSIDE_MT22_RPC2_HV.vEff", + "MID_OUTSIDE_MT22_RPC3_HV.vEff", + "MID_OUTSIDE_MT22_RPC4_HV.vEff", + "MID_OUTSIDE_MT22_RPC5_HV.vEff", + "MID_OUTSIDE_MT22_RPC6_HV.vEff", + "MID_OUTSIDE_MT22_RPC7_HV.vEff", + "MID_OUTSIDE_MT22_RPC8_HV.vEff", + "MID_OUTSIDE_MT22_RPC9_HV.vEff"}; + +std::vector<std::string> expectedHVAliasesCurrents = { + "MID_INSIDE_MT11_RPC1_HV.actual.iMon", + "MID_INSIDE_MT11_RPC2_HV.actual.iMon", + "MID_INSIDE_MT11_RPC3_HV.actual.iMon", + "MID_INSIDE_MT11_RPC4_HV.actual.iMon", + "MID_INSIDE_MT11_RPC5_HV.actual.iMon", + "MID_INSIDE_MT11_RPC6_HV.actual.iMon", + "MID_INSIDE_MT11_RPC7_HV.actual.iMon", + "MID_INSIDE_MT11_RPC8_HV.actual.iMon", + "MID_INSIDE_MT11_RPC9_HV.actual.iMon", + "MID_INSIDE_MT12_RPC1_HV.actual.iMon", + "MID_INSIDE_MT12_RPC2_HV.actual.iMon", + "MID_INSIDE_MT12_RPC3_HV.actual.iMon", + "MID_INSIDE_MT12_RPC4_HV.actual.iMon", + "MID_INSIDE_MT12_RPC5_HV.actual.iMon", + "MID_INSIDE_MT12_RPC6_HV.actual.iMon", + "MID_INSIDE_MT12_RPC7_HV.actual.iMon", + "MID_INSIDE_MT12_RPC8_HV.actual.iMon", + "MID_INSIDE_MT12_RPC9_HV.actual.iMon", + "MID_INSIDE_MT21_RPC1_HV.actual.iMon", + "MID_INSIDE_MT21_RPC2_HV.actual.iMon", + "MID_INSIDE_MT21_RPC3_HV.actual.iMon", + "MID_INSIDE_MT21_RPC4_HV.actual.iMon", + "MID_INSIDE_MT21_RPC5_HV.actual.iMon", + "MID_INSIDE_MT21_RPC6_HV.actual.iMon", + "MID_INSIDE_MT21_RPC7_HV.actual.iMon", + "MID_INSIDE_MT21_RPC8_HV.actual.iMon", + "MID_INSIDE_MT21_RPC9_HV.actual.iMon", + "MID_INSIDE_MT22_RPC1_HV.actual.iMon", + "MID_INSIDE_MT22_RPC2_HV.actual.iMon", + "MID_INSIDE_MT22_RPC3_HV.actual.iMon", + "MID_INSIDE_MT22_RPC4_HV.actual.iMon", + "MID_INSIDE_MT22_RPC5_HV.actual.iMon", + "MID_INSIDE_MT22_RPC6_HV.actual.iMon", + "MID_INSIDE_MT22_RPC7_HV.actual.iMon", + "MID_INSIDE_MT22_RPC8_HV.actual.iMon", + "MID_INSIDE_MT22_RPC9_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC1_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC2_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC3_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC4_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC5_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC6_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC7_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC8_HV.actual.iMon", + "MID_OUTSIDE_MT11_RPC9_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC1_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC2_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC3_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC4_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC5_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC6_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC7_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC8_HV.actual.iMon", + "MID_OUTSIDE_MT12_RPC9_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC1_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC2_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC3_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC4_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC5_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC6_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC7_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC8_HV.actual.iMon", + "MID_OUTSIDE_MT21_RPC9_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC1_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC2_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC3_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC4_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC5_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC6_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC7_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC8_HV.actual.iMon", + "MID_OUTSIDE_MT22_RPC9_HV.actual.iMon"}; diff --git a/Detectors/MUON/MID/Conditions/test/HVAliases.h b/Detectors/MUON/MID/Conditions/test/HVAliases.h new file mode 100644 index 0000000000000..b4561fa9631d2 --- /dev/null +++ b/Detectors/MUON/MID/Conditions/test/HVAliases.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_MID_CONDITIONS_DCS_EXPECTED_ALIASES_H +#define O2_MID_CONDITIONS_DCS_EXPECTED_ALIASES_H + +#include <vector> +#include <string> + +extern std::vector<std::string> expectedHVAliasesVoltages; +extern std::vector<std::string> expectedHVAliasesCurrents; + +#endif diff --git a/Detectors/MUON/MID/Conditions/test/testDCSNamer.cxx b/Detectors/MUON/MID/Conditions/test/testDCSNamer.cxx new file mode 100644 index 0000000000000..f0a136add20ce --- /dev/null +++ b/Detectors/MUON/MID/Conditions/test/testDCSNamer.cxx @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test MIDConditions DCSNamer +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "MIDConditions/DCSNamer.h" +#include "MIDBase/DetectorParameters.h" +#include "HVAliases.h" +#include <algorithm> +#include <fmt/format.h> + +using namespace o2::mid::dcs; + +BOOST_AUTO_TEST_SUITE(o2_mid_conditions) + +BOOST_AUTO_TEST_SUITE(dcsnamer) + +BOOST_AUTO_TEST_CASE(detElemId2DCSMustReturnNothingIfDetElemIdIsNotValid) +{ + BOOST_CHECK_EQUAL(detElemId2DCS(72).has_value(), false); + BOOST_CHECK_EQUAL(detElemId2DCS(1026).has_value(), false); + BOOST_CHECK_EQUAL(detElemId2DCS(-1).has_value(), false); +} + +BOOST_AUTO_TEST_CASE(DE4isInside) +{ + BOOST_CHECK(detElemId2DCS(4)->side == Side::Inside); +} +BOOST_AUTO_TEST_CASE(DE36isOutside) +{ + BOOST_CHECK(detElemId2DCS(36)->side == Side::Outside); +} + +BOOST_AUTO_TEST_CASE(detElemId2DCSMustReturnChamberIdAndSideIfDetElemIdIsValid) +{ + auto v = detElemId2DCS(24); + BOOST_CHECK_EQUAL(v.has_value(), true); + BOOST_CHECK_EQUAL(v->chamberId, 21); + BOOST_CHECK(v->side == Side::Inside); +} + +BOOST_AUTO_TEST_CASE(NumberOfHVAliasesVoltagesIs72) +{ + auto result = aliases({MeasurementType::HV_V}); + BOOST_CHECK_EQUAL(result.size(), expectedHVAliasesVoltages.size()); + BOOST_CHECK_EQUAL(72, expectedHVAliasesVoltages.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedHVAliasesVoltages)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(NumberOfHVAliasesCurrentsIs72) +{ + auto result = aliases({MeasurementType::HV_I}); + BOOST_CHECK_EQUAL(result.size(), expectedHVAliasesCurrents.size()); + BOOST_CHECK_EQUAL(72, expectedHVAliasesCurrents.size()); + bool permutation = std::is_permutation(begin(result), end(result), begin(expectedHVAliasesCurrents)); + BOOST_CHECK_EQUAL(permutation, true); +} + +BOOST_AUTO_TEST_CASE(AliasNameIsShortEnough) +{ + auto result = aliases(); + std::map<size_t, int> sizes; + constexpr size_t maxLen{62}; + for (auto& a : result) { + sizes[a.size()]++; + if (a.size() > maxLen) { + std::cout << fmt::format("Alias is too long : {:2d} characters, while {:2d} max are allowed : {}\n", + a.size(), maxLen, a); + } + } + size_t len{0}; + + for (auto p : sizes) { + std::cout << fmt::format("{:3d} aliases of size {:2d}\n", + p.second, p.first); + len = std::max(len, p.first); + } + BOOST_CHECK(len <= 62); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() diff --git a/Detectors/MUON/MID/Filtering/CMakeLists.txt b/Detectors/MUON/MID/Filtering/CMakeLists.txt new file mode 100644 index 0000000000000..bac06cae2be44 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_library( + MIDFiltering + SOURCES src/ChannelMasksHandler.cxx src/ChannelScalers.cxx src/FetToDead.cxx + src/MaskMaker.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsMID O2::MIDBase O2::MIDRaw + Microsoft.GSL::GSL) + +add_subdirectory(exe) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/Detectors/MUON/MID/Filtering/exe/CMakeLists.txt b/Detectors/MUON/MID/Filtering/exe/CMakeLists.txt new file mode 100644 index 0000000000000..eae70f867f4b8 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/exe/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_executable( + mask-maker + COMPONENT_NAME mid + SOURCES mask-maker.cxx + PUBLIC_LINK_LIBRARIES O2::MIDFiltering O2::MIDRaw) diff --git a/Detectors/MUON/MID/Filtering/exe/README.md b/Detectors/MUON/MID/Filtering/exe/README.md new file mode 100644 index 0000000000000..3ce9665e39615 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/exe/README.md @@ -0,0 +1,25 @@ +<!-- doxy +\page refMUONMIDFilteringExe MID Filtering executable +/doxy --> + +# MID filtering + +This directory contains executable code to analyse calibration triggers and the subsequent FET event in order to produce masks. + +## MID mask maker + +This utility allows produce the MID masks +Basic usage: + +```bash +o2-mid-mask-maker --feeId-config-file feeId_filename filename [filename_2 filename_3 ...] +``` + +The `feeId_filename` is a file allowing to tell which feeId is readout by the configured GBT. +The file should be in the form explained [here](../../Raw/README.md) + +The executable prints the (possible) list of noisy channels and dead channels and the corresponding masks. +The mask is provided in two formats: + +- a digit masks in the form of a ColumnData +- the corresponding masks at the Local Board level. This is useful because it allows to more easily identify the masks to be set in the electronics via DCS. \ No newline at end of file diff --git a/Detectors/MUON/MID/Filtering/exe/mask-maker.cxx b/Detectors/MUON/MID/Filtering/exe/mask-maker.cxx new file mode 100644 index 0000000000000..0444dc654d76d --- /dev/null +++ b/Detectors/MUON/MID/Filtering/exe/mask-maker.cxx @@ -0,0 +1,175 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/exe/mask-maker.cxx +/// \brief Utility to build masks from data +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 12 March 2020 + +#include <iostream> +#include <vector> +#include "boost/program_options.hpp" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/DecodedDataAggregator.h" +#include "MIDRaw/Decoder.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/FEEIdConfig.h" +#include "DataFormatsMID/ROBoard.h" +#include "MIDRaw/RawFileReader.h" +#include "MIDRaw/ColumnDataToLocalBoard.h" +#include "MIDFiltering/ChannelMasksHandler.h" +#include "MIDFiltering/ChannelScalers.h" +#include "MIDFiltering/FetToDead.h" +#include "MIDFiltering/MaskMaker.h" + +namespace po = boost::program_options; + +bool processScalers(const o2::mid::ChannelScalers& scalers, unsigned long nEvents, double threshold, const std::vector<o2::mid::ColumnData>& refMasks) +{ + auto masks = o2::mid::makeMasks(scalers, nEvents, threshold, refMasks); + if (masks.empty()) { + std::cout << "No problematic digit found" << std::endl; + return true; + } + + std::cout << "Problematic digits found. Corresponding masks:" << std::endl; + for (auto& mask : masks) { + std::cout << mask << std::endl; + } + + std::cout << "\nCorresponding boards masks:" << std::endl; + o2::mid::ColumnDataToLocalBoard colToBoard; + colToBoard.setDebugMode(true); + colToBoard.process(masks); + for (auto& mapIt : colToBoard.getData()) { + for (auto& board : mapIt.second) { + std::cout << board << std::endl; + } + } + return false; +} + +int main(int argc, char* argv[]) +{ + po::variables_map vm; + po::options_description generic("Generic options"); + + // clang-format off + generic.add_options() + ("help", "produce help message") + ("feeId-config-file", po::value<std::string>(),"Filename with crate FEE ID correspondence") + ("crate-masks-file", po::value<std::string>(),"Filename with crate masks") + ("electronics-delay-file", po::value<std::string>(),"Filename with electronics delay") + ("occupancy-threshold", po::value<double>()->default_value(0.9),"Occupancy threshold"); + + + po::options_description hidden("hidden options"); + hidden.add_options() + ("input", po::value<std::vector<std::string>>(),"Input filename"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic).add(hidden); + + po::positional_options_description pos; + pos.add("input", -1); + + po::store(po::command_line_parser(argc, argv).options(cmdline).positional(pos).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << "Usage: " << argv[0] << " <input_raw_filename> [input_raw_filename_1 ...]\n"; + std::cout << generic << std::endl; + return 2; + } + if (vm.count("input") == 0) { + std::cout << "no input file specified" << std::endl; + return 1; + } + + std::vector<std::string> inputfiles{vm["input"].as<std::vector<std::string>>()}; + + std::unique_ptr<o2::mid::Decoder> decoder{nullptr}; + + o2::mid::FEEIdConfig feeIdConfig; + if (vm.count("feeId-config-file")) { + feeIdConfig = o2::mid::FEEIdConfig(vm["feeId-config-file"].as<std::string>().c_str()); + } + + o2::mid::ElectronicsDelay electronicsDelay; + if (vm.count("electronics-delay-file")) { + electronicsDelay = o2::mid::readElectronicsDelay(vm["electronics-delay-file"].as<std::string>().c_str()); + } + + o2::mid::CrateMasks crateMasks; + if (vm.count("crate-masks-file")) { + crateMasks = o2::mid::CrateMasks(vm["crate-masks-file"].as<std::string>().c_str()); + } + + auto threshold = vm["occupancy-threshold"].as<double>(); + + std::vector<o2::mid::ROBoard> data; + std::vector<o2::mid::ROFRecord> rofRecords; + + for (auto& filename : inputfiles) { + o2::mid::RawFileReader rawFileReader; + if (!rawFileReader.init(filename.c_str())) { + return 2; + } + + while (rawFileReader.readHB() > 0) { + if (!decoder) { + auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(rawFileReader.getData().data()); + decoder = o2::mid::createDecoder(*rdhPtr, false, electronicsDelay, crateMasks, feeIdConfig); + } + decoder->process(rawFileReader.getData()); + rawFileReader.clear(); + size_t offset = data.size(); + data.insert(data.end(), decoder->getData().begin(), decoder->getData().end()); + for (auto& rof : decoder->getROFRecords()) { + rofRecords.emplace_back(rof.interactionRecord, rof.eventType, rof.firstEntry + offset, rof.nEntries); + } + } + } + + o2::mid::DecodedDataAggregator aggregator; + aggregator.process(data, rofRecords); + std::array<o2::mid::ChannelScalers, 2> scalers; + for (auto& noisy : aggregator.getData(o2::mid::EventType::Calib)) { + scalers[0].count(noisy); + } + + unsigned long nEvents = aggregator.getROFRecords(o2::mid::EventType::Calib).size(); + auto refMasks = makeDefaultMasksFromCrateConfig(feeIdConfig, crateMasks); + + bool isOk = true; + std::cout << "\nCHECKING NOISY CHANNELS:" << std::endl; + isOk &= processScalers(scalers[0], nEvents, threshold, refMasks); + + o2::mid::FetToDead fetToDead; + fetToDead.setMasks(refMasks); + auto fetRofs = aggregator.getROFRecords(o2::mid::EventType::FET); + auto fets = aggregator.getData(o2::mid::EventType::FET); + + for (auto& rof : fetRofs) { + std::vector<o2::mid::ColumnData> eventFets(fets.begin() + rof.firstEntry, fets.begin() + rof.getEndIndex()); + auto deadChannels = fetToDead.process(eventFets); + for (auto& dead : deadChannels) { + scalers[1].count(dead); + } + } + std::cout << "\nCHECKING DEAD CHANNELS:" << std::endl; + isOk &= processScalers(scalers[1], nEvents, threshold, refMasks); + + return isOk ? 0 : 1; +} diff --git a/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelMasksHandler.h b/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelMasksHandler.h new file mode 100644 index 0000000000000..7dbb291c00136 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelMasksHandler.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDFiltering/ChannelMasksHandler.h +/// \brief MID channels masks handler +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 09 January 2020 +#ifndef O2_MID_CHANNELMASKSHANDLER_H +#define O2_MID_CHANNELMASKSHANDLER_H + +#include <cstdint> +#include <vector> +#include <unordered_map> +#include "DataFormatsMID/ColumnData.h" + +namespace o2 +{ +namespace mid +{ + +class ChannelMasksHandler +{ + public: + void switchOffChannel(uint8_t deId, uint8_t columnId, int lineId, int strip, int cathode); + void switchOffChannels(const ColumnData& dead); + bool setFromChannelMask(const ColumnData& mask); + bool setFromChannelMasks(const std::vector<ColumnData>& masks); + // void setReferenceMasks(const std::vector<ColumnData>& masks); + bool applyMask(ColumnData& data) const; + + std::vector<ColumnData> getMasks() const; + std::vector<ColumnData> getReferenceMasks() const; + + /// Comparison operator + bool operator==(const ChannelMasksHandler& right) const { return mMasks == right.mMasks; } + + private: + ColumnData& getMask(uint8_t deId, uint8_t columnId); + std::unordered_map<uint16_t, ColumnData> mMasks{}; // Channel masks + // std::unordered_map<uint16_t, ColumnData> mReferenceMasks{}; // Channel masks reference +}; + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_CHANNELMASKSHANDLER_H */ diff --git a/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelScalers.h b/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelScalers.h new file mode 100644 index 0000000000000..83fbe462d50c0 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/include/MIDFiltering/ChannelScalers.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDFiltering/ChannelScalers.h +/// \brief MID channel scalers +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 05 March 2020 +#ifndef O2_MID_CHANNELSCALERS_H +#define O2_MID_CHANNELSCALERS_H + +#include <cstdint> +#include <unordered_map> +#include "DataFormatsMID/ColumnData.h" + +namespace o2 +{ +namespace mid +{ + +class ChannelScalers +{ + public: + void count(const ColumnData& patterns); + + /// Resets scalers + void reset() { mScalers.clear(); } + + /// Gets deId from unique Id + inline uint8_t getDeId(uint32_t uniqueId) const { return ((uniqueId >> 12) & 0x7F); } + /// Gets columnId from unique Id + inline uint8_t getColumnId(uint32_t uniqueId) const { return ((uniqueId >> 8) & 0xF); } + /// Gets cathode from unique Id + inline uint8_t getCathode(uint32_t uniqueId) const { return ((uniqueId >> 6) & 0x1); } + /// Gets lineId from unique Id + inline uint8_t getLineId(uint32_t uniqueId) const { return ((uniqueId >> 4) & 0x3); } + /// Gets strip from unique Id + inline uint8_t getStrip(uint32_t uniqueId) const { return (uniqueId & 0xF); } + + /// Gets the scalers + const std::unordered_map<uint32_t, uint32_t>& getScalers() const { return mScalers; } + + private: + void count(uint8_t deId, uint8_t columnId, int lineId, int cathode, uint16_t pattern); + /// Returns a unique ID for the channel + inline uint32_t getChannelId(uint8_t deId, uint8_t columnId, int lineId, int strip, int cathode) { return strip | (lineId << 4) | (cathode << 6) | (static_cast<uint32_t>(columnId) << 8) | (static_cast<uint32_t>(deId) << 12); } + std::unordered_map<uint32_t, uint32_t> mScalers{}; // Channel scalers +}; + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_CHANNELSCALERS_H */ diff --git a/Detectors/MUON/MID/Filtering/include/MIDFiltering/FetToDead.h b/Detectors/MUON/MID/Filtering/include/MIDFiltering/FetToDead.h new file mode 100644 index 0000000000000..528d76d781688 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/include/MIDFiltering/FetToDead.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDFiltering/FetToDead.h +/// \brief Class to convert the FEE test event into dead channels +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 10 May 2021 +#ifndef O2_MID_FETTODEAD_H +#define O2_MID_FETTODEAD_H + +#include <cstdint> +#include <gsl/span> +#include "DataFormatsMID/ColumnData.h" +#include "MIDFiltering/ChannelMasksHandler.h" + +namespace o2 +{ +namespace mid +{ + +class FetToDead +{ + public: + FetToDead(); + ~FetToDead() = default; + + FetToDead(const FetToDead&) = default; + FetToDead(FetToDead&&) = default; + + std::vector<ColumnData> process(gsl::span<const ColumnData> fetData); + + /// Sets the masks + void setMasks(std::vector<ColumnData> masks); + + private: + bool invertPattern(const ColumnData& col, std::vector<ColumnData>& invertedData); + + ChannelMasksHandler mMasksHandler{}; // Masks handler + std::unordered_map<uint16_t, ColumnData> mInvertedActive; // Map of inverted active channels +}; + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_FETTODEAD_H */ diff --git a/Detectors/MUON/MID/Filtering/include/MIDFiltering/MaskMaker.h b/Detectors/MUON/MID/Filtering/include/MIDFiltering/MaskMaker.h new file mode 100644 index 0000000000000..a4f993718ee53 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/include/MIDFiltering/MaskMaker.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDFiltering/MaskMaker.h +/// \brief Function to produce the MID masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 09 January 2020 +#ifndef O2_MID_MASKMAKER_H +#define O2_MID_MASKMAKER_H + +#include <cstdint> +#include "MIDFiltering/ChannelScalers.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/FEEIdConfig.h" + +namespace o2 +{ +namespace mid +{ + +std::vector<ColumnData> makeMasks(const ChannelScalers& scalers, unsigned long nEvents, double threshold = 0.9, const std::vector<ColumnData>& refMasks = {}); +std::vector<ColumnData> makeDefaultMasks(); +std::vector<ColumnData> makeDefaultMasksFromCrateConfig(const FEEIdConfig& feeIdConfig = FEEIdConfig(), const CrateMasks& crateMasks = CrateMasks()); + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_MASKMAKER_H */ diff --git a/Detectors/MUON/MID/Filtering/src/ChannelMasksHandler.cxx b/Detectors/MUON/MID/Filtering/src/ChannelMasksHandler.cxx new file mode 100644 index 0000000000000..498ccdae0bb45 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/src/ChannelMasksHandler.cxx @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/src/ChannelMasksHandler.cxx +/// \brief MID channels masks handler +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 09 January 2020 + +#include "MIDFiltering/ChannelMasksHandler.h" + +namespace o2 +{ +namespace mid +{ + +ColumnData& ChannelMasksHandler::getMask(uint8_t deId, uint8_t columnId) +{ + /// Gets the mask + auto uniqueId = getColumnDataUniqueId(deId, columnId); + auto maskIt = mMasks.find(uniqueId); + if (maskIt == mMasks.end()) { + auto& newMask = mMasks[uniqueId]; + newMask.deId = deId; + newMask.columnId = columnId; + newMask.patterns.fill(0xFFFF); + return newMask; + + // newMask = mReferenceMasks[uniqueId]; + // return newMask; + } + return maskIt->second; +} + +void ChannelMasksHandler::switchOffChannel(uint8_t deId, uint8_t columnId, int lineId, int strip, int cathode) +{ + /// Switches off one channel + auto& mask = getMask(deId, columnId); + uint16_t pattern = (1 << strip); + if (cathode == 0) { + mask.setBendPattern(mask.getBendPattern(lineId) & ~pattern, lineId); + } else { + mask.setNonBendPattern(mask.getNonBendPattern() & ~pattern); + } +} + +void ChannelMasksHandler::switchOffChannels(const ColumnData& dead) +{ + /// Switches off the dead channels + auto& mask = getMask(dead.deId, dead.columnId); + mask.setNonBendPattern(mask.getNonBendPattern() & (~dead.getNonBendPattern())); + for (int iline = 0; iline < 4; ++iline) { + mask.setBendPattern(mask.getBendPattern(iline) & (~dead.getBendPattern(iline)), iline); + } +} + +bool ChannelMasksHandler::applyMask(ColumnData& data) const +{ + /// Applies the mask to the data + /// Returns false if the data is completely masked + auto uniqueId = getColumnDataUniqueId(data.deId, data.columnId); + auto maskIt = mMasks.find(uniqueId); + if (maskIt == mMasks.end()) { + return true; + } + uint16_t allPatterns = 0; + data.setNonBendPattern(data.getNonBendPattern() & maskIt->second.getNonBendPattern()); + allPatterns |= data.getNonBendPattern(); + for (int iline = 0; iline < 4; ++iline) { + data.setBendPattern(data.getBendPattern(iline) & maskIt->second.getBendPattern(iline), iline); + allPatterns |= data.getBendPattern(iline); + } + return (allPatterns != 0); +} + +std::vector<ColumnData> ChannelMasksHandler::getMasks() const +{ + /// Gets the masks + std::vector<ColumnData> masks; + for (auto& maskIt : mMasks) { + masks.emplace_back(maskIt.second); + } + return masks; +} + +// std::vector<ColumnData> ChannelMasksHandler::getReferenceMasks() const +// { +// /// Gets the masks +// std::vector<ColumnData> masks; +// for (auto& maskIt : mReferenceMasks) { +// masks.emplace_back(maskIt.second); +// } +// return masks; +// } + +bool ChannelMasksHandler::setFromChannelMask(const ColumnData& mask) +{ + /// Sets the mask from a channel mask + auto uniqueColumnId = getColumnDataUniqueId(mask.deId, mask.columnId); + // auto ref = mReferenceMasks.find(uniqueColumnId); + // if (mask == ref->second) { + // return false; + // } + mMasks[uniqueColumnId] = mask; + return true; +} + +bool ChannelMasksHandler::setFromChannelMasks(const std::vector<ColumnData>& masks) +{ + /// Sets the mask from a vector of channel masks + bool isDone = false; + for (auto& mask : masks) { + isDone |= setFromChannelMask(mask); + } + return isDone; +} + +// void ChannelMasksHandler::setReferenceMasks(const std::vector<ColumnData>& masks) +// { +// /// Sets the reference mask +// for (auto& mask : masks) { +// mReferenceMasks[getColumnDataUniqueId(mask.deId, mask.columnId)] = mask; +// } +// } + +// ChannelMasksHandler buildDefaultChannelMasksHandler() +// { +// /// Builds the default channel mask +// Mapping mapping; +// ChannelMasksHandler ChannelMasksHandler; +// for (int ide = 0; ide < detparams::NDetectionElements; ++ide) { +// for (int icol = mapping.getFirstColumn(ide); icol < 7; ++icol) { +// ColumnData mask; +// mask.deId = ide; +// mask.columnId = icol; +// for (int iline = mapping.getFirstBoardBP(icol, ide); iline <= mapping.getLastBoardBP(icol, ide); ++iline) { +// mask.setBendPattern(0xFFFF, iline); +// } +// for (int istrip = 0; istrip < mapping.getNStripsNBP(icol, ide); ++istrip) { +// mask.addStrip(istrip, 1, 0); +// } +// ChannelMasksHandler.setFromChannelMasksHandler(mask); +// } +// } +// return ChannelMasksHandler; +// } +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Filtering/src/ChannelScalers.cxx b/Detectors/MUON/MID/Filtering/src/ChannelScalers.cxx new file mode 100644 index 0000000000000..92eb1ffbf8abb --- /dev/null +++ b/Detectors/MUON/MID/Filtering/src/ChannelScalers.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/src/ChannelScalers.cxx +/// \brief MID channel scalers +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 05 March 2021 + +#include "MIDFiltering/ChannelScalers.h" + +namespace o2 +{ +namespace mid +{ +void ChannelScalers::count(uint8_t deId, uint8_t columnId, int lineId, int cathode, uint16_t pattern) +{ + /// Increases strip counter + for (int istrip = 0; istrip < 16; ++istrip) { + if (pattern & (1 << istrip)) { + ++mScalers[getChannelId(deId, columnId, lineId, istrip, cathode)]; + } + } +} + +void ChannelScalers::count(const ColumnData& patterns) +{ + //// Increases strip counter + count(patterns.deId, patterns.columnId, 0, 1, patterns.getNonBendPattern()); + for (int iline = 0; iline < 4; ++iline) { + count(patterns.deId, patterns.columnId, iline, 0, patterns.getBendPattern(iline)); + } +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Filtering/src/FetToDead.cxx b/Detectors/MUON/MID/Filtering/src/FetToDead.cxx new file mode 100644 index 0000000000000..0b4fca13ce438 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/src/FetToDead.cxx @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/src/FetToDead.cxx +/// \brief Class to convert the FEE test event into dead channels +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 10 May 2021 + +#include "MIDFiltering/FetToDead.h" + +#include "MIDFiltering/MaskMaker.h" + +namespace o2 +{ +namespace mid +{ +FetToDead::FetToDead() +{ + /// Default ctr. + setMasks(makeDefaultMasks()); +} + +void FetToDead::setMasks(std::vector<ColumnData> masks) +{ + /// Sets the default masks reflecting the active channels from the mapping + mMasksHandler.setFromChannelMasks(masks); + mInvertedActive.clear(); + std::vector<ColumnData> inverted; + for (auto& col : masks) { + invertPattern(col, inverted); + } + for (auto& col : inverted) { + mInvertedActive[getColumnDataUniqueId(col.deId, col.columnId)] = col; + } +} + +std::vector<ColumnData> FetToDead::process(gsl::span<const ColumnData> fetData) +{ + /// Converts the FET result to a list of dead channels + std::vector<ColumnData> deadChannels; + std::unordered_map<uint16_t, bool> dataIds; + // First we loop on FET output and returns the empty strips + for (auto& col : fetData) { + invertPattern(col, deadChannels); + dataIds[getColumnDataUniqueId(col.deId, col.columnId)] = true; + } + + // Then we loop on the active channels and check if they where among the FET data. + // If they are not there, it means that non of the channels answered. + // So the full board was dead. + for (auto& item : mInvertedActive) { + auto found = dataIds.find(item.first); + if (found == dataIds.end()) { + deadChannels.emplace_back(item.second); + } + } + return deadChannels; +} + +bool FetToDead::invertPattern(const ColumnData& col, std::vector<ColumnData>& invertedData) +{ + /// Inverts the pattern and add it to the output data + ColumnData invertedCol{col.deId, col.columnId}; + invertedCol.setNonBendPattern(~col.getNonBendPattern()); + for (int iline = 0; iline < 4; ++iline) { + invertedCol.setBendPattern(~col.getBendPattern(iline), iline); + } + mMasksHandler.applyMask(invertedCol); + if (invertedCol.isEmpty()) { + return false; + } + invertedData.emplace_back(invertedCol); + return true; +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Filtering/src/MaskMaker.cxx b/Detectors/MUON/MID/Filtering/src/MaskMaker.cxx new file mode 100644 index 0000000000000..aa0942b5c0c67 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/src/MaskMaker.cxx @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/src/MaskMaker.cxx +/// \brief Function to produce the MID masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 05 March 2021 + +#include "MIDFiltering/MaskMaker.h" +#include "MIDFiltering/ChannelMasksHandler.h" +#include "MIDBase/Mapping.h" +#include "MIDBase/DetectorParameters.h" +#include "DataFormatsMID/ROFRecord.h" +#include "DataFormatsMID/ROBoard.h" +#include "MIDRaw/DecodedDataAggregator.h" + +namespace o2 +{ +namespace mid +{ +std::vector<ColumnData> makeMasks(const ChannelScalers& scalers, unsigned long nEvents, double threshold, const std::vector<ColumnData>& refMasks) +{ + /// Makes the mask from the scalers + uint32_t nThresholdEvents = static_cast<uint32_t>(threshold * nEvents); + ChannelMasksHandler maskHandler; + for (const auto scaler : scalers.getScalers()) { + if (scaler.second >= nThresholdEvents) { + maskHandler.switchOffChannel(scalers.getDeId(scaler.first), scalers.getColumnId(scaler.first), scalers.getLineId(scaler.first), scalers.getStrip(scaler.first), scalers.getCathode(scaler.first)); + } + } + std::vector<ColumnData> masks(maskHandler.getMasks()); + + if (!refMasks.empty()) { + ChannelMasksHandler defaultMaskHandler; + defaultMaskHandler.setFromChannelMasks(refMasks); + + for (auto& mask : masks) { + defaultMaskHandler.applyMask(mask); + } + } + + return masks; +} + +std::vector<ColumnData> makeDefaultMasks() +{ + /// Makes the default mask from the mapping + Mapping mapping; + ChannelMasksHandler masksHandler; + uint16_t fullPattern = 0xFFFF; + for (int ide = 0; ide < detparams::NDetectionElements; ++ide) { + for (int icol = mapping.getFirstColumn(ide); icol < 7; ++icol) { + ColumnData mask; + mask.deId = static_cast<uint8_t>(ide); + mask.columnId = static_cast<uint8_t>(icol); + // int nFullPatterns = 0; + for (int iline = mapping.getFirstBoardBP(icol, ide), lastLine = mapping.getLastBoardBP(icol, ide); iline <= lastLine; ++iline) { + mask.setBendPattern(fullPattern, iline); + // ++nFullPatterns; + } + for (int istrip = 0; istrip < mapping.getNStripsNBP(icol, ide); ++istrip) { + mask.addStrip(istrip, 1, 0); + } + masksHandler.setFromChannelMask(mask); + } + } + + return masksHandler.getMasks(); +} + +std::vector<ROBoard> getActiveBoards(const FEEIdConfig& feeIdConfig, const CrateMasks& masks) +{ + /// Gets the list of the active boards from the crate configuration + std::vector<ROBoard> activeBoards; + auto gbtUniqueIds = feeIdConfig.getConfiguredGBTUniqueIDs(); + ROBoard board; + board.statusWord = raw::sCARDTYPE; + board.patternsBP.fill(0xFFFF); + board.patternsNBP.fill(0xFFFF); + board.firedChambers = 0xF; + for (auto& gbtUniqueId : gbtUniqueIds) { + auto mask = masks.getMask(gbtUniqueId); + auto crateId = crateparams::getCrateIdFromGBTUniqueId(gbtUniqueId); + for (int iloc = 0; iloc < 8; ++iloc) { + if ((mask >> iloc) & 0x1) { + board.boardId = raw::makeUniqueLocID(crateId, crateparams::getLocIdInCrate(gbtUniqueId, iloc)); + activeBoards.emplace_back(board); + } + } + } + return activeBoards; +} + +std::vector<ColumnData> makeDefaultMasksFromCrateConfig(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks) +{ + /// Makes the default masks from the crate configuration + auto activeBoards = getActiveBoards(feeIdConfig, crateMasks); + std::vector<ROFRecord> rofs; + rofs.push_back({InteractionRecord(), EventType::Standard, 0, activeBoards.size()}); + DecodedDataAggregator aggregator; + aggregator.process(activeBoards, rofs); + std::vector<ColumnData> maskedBoards(aggregator.getData()); + ChannelMasksHandler masksHandler; + masksHandler.setFromChannelMasks(makeDefaultMasks()); + for (auto col : maskedBoards) { + masksHandler.applyMask(col); + } + + return maskedBoards; +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Filtering/test/CMakeLists.txt b/Detectors/MUON/MID/Filtering/test/CMakeLists.txt new file mode 100644 index 0000000000000..eea36844c0aa0 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/test/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +o2_add_test( + Filtering + SOURCES testFilter.cxx + LABELS mid + COMPONENT_NAME mid + PUBLIC_LINK_LIBRARIES O2::MIDFiltering O2::MIDBase) + +# if(benchmark_FOUND) o2_add_executable( tracker COMPONENT_NAME mid SOURCES +# bench_Tracker.cxx IS_BENCHMARK PUBLIC_LINK_LIBRARIES O2::MIDTracking +# benchmark::benchmark) endif() diff --git a/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx b/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx new file mode 100644 index 0000000000000..1d90dc7351018 --- /dev/null +++ b/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Tracking/test/bench_Tracker.cxx +/// \brief Benchmark tracker device for MID +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 17 March 2018 + +#include "benchmark/benchmark.h" +#include <random> +#include "DataFormatsMID/Cluster2D.h" +#include "DataFormatsMID/Track.h" +#include "MIDBase/Mapping.h" +#include "MIDBase/MpArea.h" +#include "MIDTestingSimTools/HitFinder.h" +#include "MIDTestingSimTools/TrackGenerator.h" +#include "MIDTracking/Tracker.h" + +std::vector<o2::mid::Cluster2D> generateTestData(int nTracks, o2::mid::TrackGenerator& trackGen, + const o2::mid::HitFinder& hitFinder, const o2::mid::Mapping& mapping) +{ + o2::mid::Mapping::MpStripIndex stripIndex; + o2::mid::MpArea area; + std::vector<o2::mid::Cluster2D> clusters; + o2::mid::Cluster2D cl; + std::vector<o2::mid::Track> tracks = trackGen.generate(nTracks); + for (auto& track : tracks) { + for (int ich = 0; ich < 4; ++ich) { + auto hits = hitFinder.getLocalPositions(track, ich); + bool isFired = false; + for (auto& hit : hits) { + int deId = hit.deId; + float xPos = hit.xCoor; + float yPos = hit.yCoor; + stripIndex = mapping.stripByPosition(xPos, yPos, 0, deId, false); + if (!stripIndex.isValid()) { + continue; + } + cl.deId = deId; + area = mapping.stripByLocation(stripIndex.strip, 0, stripIndex.line, stripIndex.column, deId); + cl.yCoor = area.getCenterY(); + float halfSize = area.getHalfSizeY(); + cl.sigmaY2 = halfSize * halfSize / 3.; + stripIndex = mapping.stripByPosition(xPos, yPos, 1, deId, false); + area = mapping.stripByLocation(stripIndex.strip, 1, stripIndex.line, stripIndex.column, deId); + cl.xCoor = area.getCenterX(); + halfSize = area.getHalfSizeX(); + cl.sigmaX2 = halfSize * halfSize / 3.; + clusters.push_back(cl); + } // loop on fired pos + } // loop on chambers + } // loop on tracks + return clusters; +} + +static void BM_TRACKER(benchmark::State& state) +{ + o2::mid::GeometryTransformer geoTrans = o2::mid::createDefaultTransformer(); + o2::mid::TrackGenerator trackGen; + o2::mid::HitFinder hitFinder(geoTrans); + o2::mid::Mapping mapping; + o2::mid::Tracker tracker(geoTrans); + + int nTracksPerEvent = state.range(0); + tracker.init((state.range(1) == 1)); + double num{0}; + + std::vector<o2::mid::Cluster2D> inputData; + + for (auto _ : state) { + state.PauseTiming(); + inputData = generateTestData(nTracksPerEvent, trackGen, hitFinder, mapping); + state.ResumeTiming(); + tracker.process(inputData); + ++num; + } + + state.counters["num"] = benchmark::Counter(num, benchmark::Counter::kIsRate); +} + +static void CustomArguments(benchmark::internal::Benchmark* bench) +{ + for (int itrack = 1; itrack <= 8; ++itrack) { + for (int imethod = 0; imethod < 2; ++imethod) { + bench->Args({itrack, imethod}); + } + } +} + +BENCHMARK(BM_TRACKER)->Apply(CustomArguments)->Unit(benchmark::kNanosecond); + +BENCHMARK_MAIN(); diff --git a/Detectors/MUON/MID/Filtering/test/testFilter.cxx b/Detectors/MUON/MID/Filtering/test/testFilter.cxx new file mode 100644 index 0000000000000..e8f6617900adf --- /dev/null +++ b/Detectors/MUON/MID/Filtering/test/testFilter.cxx @@ -0,0 +1,172 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Filtering/test/testFilter.cxx +/// \brief Test Filtering device for MID +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 15 March 2018 + +#define BOOST_TEST_MODULE midFiltering +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include <boost/test/data/test_case.hpp> +#include <cstdint> +#include <random> +#include <string> +#include <sstream> +#include <vector> +#include "DataFormatsMID/ColumnData.h" +#include "MIDFiltering/ChannelMasksHandler.h" +#include "MIDFiltering/ChannelScalers.h" +#include "MIDFiltering/FetToDead.h" +#include "MIDFiltering/MaskMaker.h" + +namespace o2 +{ +namespace mid +{ + +std::vector<ColumnData> generateData(size_t nData = 10) +{ + + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_int_distribution<uint8_t> deIds(0, 71); + std::uniform_int_distribution<uint8_t> colIds(0, 6); + std::uniform_int_distribution<uint16_t> patterns(0, 0xFFFF); + + std::vector<o2::mid::ColumnData> data; + for (size_t idata = 0; idata < nData; ++idata) { + ColumnData col; + col.deId = deIds(mt); + col.columnId = colIds(mt); + for (int iline = 0; iline < 4; ++iline) { + col.setBendPattern(patterns(mt), iline); + } + col.setNonBendPattern(patterns(mt)); + data.emplace_back(col); + } + return data; +} + +BOOST_AUTO_TEST_CASE(mask) +{ + o2::mid::ColumnData col1; + col1.deId = 71; + col1.columnId = 6; + col1.setNonBendPattern(0x8000); + + ChannelMasksHandler masksHandler; + masksHandler.switchOffChannels(col1); + auto maskVec = masksHandler.getMasks(); + BOOST_TEST(maskVec.size() == 1); + for (auto mask : maskVec) { + for (int iline = 0; iline < 4; ++iline) { + BOOST_TEST(mask.getBendPattern(iline) == static_cast<uint16_t>(~col1.getBendPattern(iline))); + } + BOOST_TEST(mask.getNonBendPattern() == static_cast<uint16_t>(~col1.getNonBendPattern())); + } +} + +BOOST_AUTO_TEST_CASE(scalers) +{ + + o2::mid::ColumnData col1; + col1.deId = 71; + col1.columnId = 6; + col1.setNonBendPattern(0x8000); + + o2::mid::ChannelScalers cs; + cs.count(col1); + auto sc1 = cs.getScalers(); + BOOST_REQUIRE(sc1.size() == 1); + for (auto& sc : sc1) { + BOOST_TEST(cs.getDeId(sc.first) = col1.deId); + BOOST_TEST(cs.getColumnId(sc.first) = col1.columnId); + BOOST_TEST(cs.getLineId(sc.first) == 0); + BOOST_TEST(cs.getCathode(sc.first) == 1); + BOOST_TEST(cs.getStrip(sc.first) == 15); + } + cs.reset(); + + o2::mid::ColumnData col2; + col2.deId = 25; + col2.columnId = 3; + col2.setBendPattern(0x0100, 3); + cs.count(col2); + auto sc2 = cs.getScalers(); + BOOST_REQUIRE(sc2.size() == 1); + for (auto& sc : sc2) { + BOOST_TEST(cs.getDeId(sc.first) = col2.deId); + BOOST_TEST(cs.getColumnId(sc.first) = col2.columnId); + BOOST_TEST(cs.getLineId(sc.first) == 3); + BOOST_TEST(cs.getCathode(sc.first) == 0); + BOOST_TEST(cs.getStrip(sc.first) == 8); + } +} + +BOOST_AUTO_TEST_CASE(maskMaker) +{ + auto data = generateData(); + o2::mid::ChannelScalers cs; + std::vector<o2::mid::ColumnData> refMasks{}; + for (auto col : data) { + cs.reset(); + cs.count(col); + auto masks = o2::mid::makeMasks(cs, 1, 0., refMasks); + BOOST_TEST(masks.size() == 1); + for (auto& mask : masks) { + for (int iline = 0; iline < 4; ++iline) { + BOOST_TEST(mask.getBendPattern(iline) == static_cast<uint16_t>(~col.getBendPattern(iline))); + } + BOOST_TEST(mask.getNonBendPattern() == static_cast<uint16_t>(~col.getNonBendPattern())); + } + } +} + +BOOST_AUTO_TEST_CASE(FETConversion) +{ + /// Tests the conversion of Fet data to dead channels + + // Use the masks as FET: all channels should answer + auto fets = makeDefaultMasks(); + + // We now modify one FET data + uint16_t fullPattern = 0xFFFF; + for (auto& col : fets) { + if (col.deId == 3 && col.columnId == 0) { + col.setBendPattern(fullPattern & ~0x1, 0); + col.setBendPattern(fullPattern, 1); + col.setBendPattern(fullPattern, 2); + // The following does not exist in deId 3, col 0 + col.setBendPattern(fullPattern & ~0x1, 3); + col.setNonBendPattern(fullPattern); + } + } + + FetToDead fetToDead; + auto inverted = fetToDead.process(fets); + + BOOST_TEST(inverted.size() == 1); + BOOST_TEST(inverted.back().deId == 3); + BOOST_TEST(inverted.back().columnId == 0); + BOOST_TEST(inverted.back().getBendPattern(0) == 1); + BOOST_TEST(inverted.back().getBendPattern(1) == 0); + BOOST_TEST(inverted.back().getBendPattern(2) == 0); + // Test that the non-existing pattern was not converted + // Since the mask in the FET conversion takes care of removing it + BOOST_TEST(inverted.back().getBendPattern(3) == 0); + BOOST_TEST(inverted.back().getNonBendPattern() == 0); +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/QC/CMakeLists.txt b/Detectors/MUON/MID/QC/CMakeLists.txt index d7440379f2571..f87af8930f243 100644 --- a/Detectors/MUON/MID/QC/CMakeLists.txt +++ b/Detectors/MUON/MID/QC/CMakeLists.txt @@ -1,16 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( MIDQC SOURCES src/GBTRawDataChecker.cxx src/RawDataChecker.cxx - PUBLIC_LINK_LIBRARIES ms_gsl::ms_gsl O2::MIDRaw) + src/UserLogicChecker.cxx + PUBLIC_LINK_LIBRARIES Microsoft.GSL::GSL O2::MIDRaw) add_subdirectory(exe) diff --git a/Detectors/MUON/MID/QC/exe/CMakeLists.txt b/Detectors/MUON/MID/QC/exe/CMakeLists.txt index 87be3a2e49bbf..083e5febeacff 100644 --- a/Detectors/MUON/MID/QC/exe/CMakeLists.txt +++ b/Detectors/MUON/MID/QC/exe/CMakeLists.txt @@ -1,15 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_executable( raw-checker COMPONENT_NAME mid SOURCES raw-checker.cxx - PUBLIC_LINK_LIBRARIES O2::MIDQC) + PUBLIC_LINK_LIBRARIES O2::MIDQC O2::MIDRaw) + +o2_add_executable( + raw-ul-checker + COMPONENT_NAME mid + SOURCES raw-ul-checker.cxx + PUBLIC_LINK_LIBRARIES O2::MIDQC O2::MIDRaw) diff --git a/Detectors/MUON/MID/QC/exe/README.md b/Detectors/MUON/MID/QC/exe/README.md index 05068536f3268..c1c1477794031 100644 --- a/Detectors/MUON/MID/QC/exe/README.md +++ b/Detectors/MUON/MID/QC/exe/README.md @@ -3,21 +3,26 @@ /doxy --> # Checkers for MID RAW data + This directory contains executable code to verify the raw data. This is particularly important for testing and debugging the MID read-out. ## MID raw file checker + This utility allows to test files produced by the CRU w/o using the User Logic. Basic usage: + ```bash o2-mid-raw-checker --feeId-config-file feeId_filename filename [filename_2 filename_3 ...] ``` + The `feeId_filename` is a file allowing to tell which feeId is readout by the configured GBT. The file should be in the form explained [here](../../Raw/README.md) The output is a file (or a series of files if a list of inputs is provided), named after the input file as `check_filename.txt`, so that it is easy to understand to which input file the output is referring to. The different e-links are read out and then grouped according to their interaction record. The output file contains: + - a list of possible problems (if any) for each event processed - a summary with the number of faulty events @@ -30,17 +35,57 @@ We therefore print the interaction records and the corresponding pages (HB), tog The line is counted assuming that one reads the file as a series of 4 words of 32 bits each (this is the typical way the binary file is converted into text during the tests). For a list of the other available options: + ```bash o2-mid-raw-checker --help ``` + ### Performed checks + The decoded information is read HB per HB (multiple pages are read out when needed). For each HB, the decoded information are gathered according to their interaction. Notice that, in principle, events belonging to different HBs should have different interaction records, so one could in principle read the full file and then perform the check. However, in the tests the RDH is not always correctly set, and the orbit number might not increase. That is why we read the HB one by one, and limit the tests to 1 HB at the time. This makes it easier to tag HBs with issues in the RO. For each interaction record, a number of checks are performed: + - The number of local cards read must be compatible with the number of non-null cards provided by the regional cards. Notice that a mismatch can occur when the local board is busy (but does not correctly signal it) and we therefore get the regional info but not the corresponding local card. An incompatibility can also appear in case of corrupted data reading. - The word describing the event (SOX, EOX, HC, Calibration, etc.) should be the same for all cards in the interaction record. - The number of non-zero patterns read must match the information written in the corresponding word that indicates the non-zero detector planes. - For each card we check that the information is consistent. For example we cannot have SOX and Calibration bits fired at the same time. Also, during an HC, we expect to have no chamber fired for the local boards. Notice that during tests this information is added by hand, so we should not have any issue by design. - When the overwritten bit is fired, the readout data is actually filled with the masks. In this case we therefore check that the masks are as expected (i.e. they are compatible with the masks that are transmitted at the SOX) + +## MID user logic checker + +The aim of this utility is to validate the user logic. +In the simulations of the CRU user logic, the electronic input is read out from an input file. +The raw data are then processed by the CRU user logic, that performs the zero suppression, and an output file is generated. +This utility decodes both the simulation inputs and outputs and compares them, in order to spot any difference. + +The utility can be launched with: + +```bash +o2-mid-raw-ul-decoder-checker --bare-filename <raw_input_data.dat> --ul-filename <raw_ul_output_data.dat> --feeId-config-file <feeId_config_file.txt> +``` + +where: + +- *raw_input_data.dat* is the input to the user logic simulation +- *raw_ul_output_data.dat* is the output of the simulation +- *feeId_config_file* is the file specifying which GBT links are simulated (see [here](../../Raw/README.md) for details) + +The program decodes the data, and ranges them according to the local/regional board that produces them. +In principle, the data of one single board is taken in a sequential way, and this sequence must be respected also in the user logic output. +The check consists of comparing the information of each local/regional board, searching for a mismatch between the input data and the CRU user logic output. +As soon as a difference is found, the check for that board stops and an error is raised. +This check is done for all of the boards. +In this way we know, for each board, the first time when an error occurred (but there might be others after it). + +### Checker output + +The checker writes a file (default name: *check_ul.txt*) containing the number of errors found. +The error typically consists of the timestamp of the event, in the form of orbit and bunch crossing id, the type of error and the corresponding decoded board information. +The errors can be: + +- *only in bare* (the event or board was found in the input file, but not on the output) +- *only in ul* (the event or board was found in the output file, but not on the input) +- *difference* (the board was found in both the input and the output, but some bytes where different) diff --git a/Detectors/MUON/MID/QC/exe/raw-checker.cxx b/Detectors/MUON/MID/QC/exe/raw-checker.cxx index 733d8310bafd0..0a1c1342902fa 100644 --- a/Detectors/MUON/MID/QC/exe/raw-checker.cxx +++ b/Detectors/MUON/MID/QC/exe/raw-checker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,13 +16,19 @@ #include <iostream> #include <fstream> +#include <sstream> +#include <string> +#include <vector> #include "boost/program_options.hpp" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDQC/RawDataChecker.h" #include "MIDRaw/CrateMasks.h" +#include "MIDRaw/Decoder.h" #include "MIDRaw/ElectronicsDelay.h" #include "MIDRaw/FEEIdConfig.h" -#include "MIDRaw/Decoder.h" +#include "DataFormatsMID/ROBoard.h" #include "MIDRaw/RawFileReader.h" -#include "MIDQC/RawDataChecker.h" namespace po = boost::program_options; @@ -48,32 +55,33 @@ std::string getOutFilename(const char* inFilename, const char* outDir) return outFilename; } -template <typename GBTDECODER> int process(po::variables_map& vm) { std::vector<std::string> inputfiles{vm["input"].as<std::vector<std::string>>()}; - o2::mid::Decoder<GBTDECODER> decoder; + std::unique_ptr<o2::mid::Decoder> decoder{nullptr}; o2::mid::RawDataChecker checker; + + o2::mid::FEEIdConfig feeIdConfig; if (vm.count("feeId-config-file")) { - o2::mid::FEEIdConfig feeIdConfig(vm["feeId-config-file"].as<std::string>().c_str()); - decoder.setFeeIdConfig(feeIdConfig); + feeIdConfig = o2::mid::FEEIdConfig(vm["feeId-config-file"].as<std::string>().c_str()); } + o2::mid::ElectronicsDelay electronicsDelay; if (vm.count("electronics-delay-file")) { - o2::mid::ElectronicsDelay electronicsDelay = o2::mid::readElectronicsDelay(vm["electronics-delay-file"].as<std::string>().c_str()); - decoder.setElectronicsDelay(electronicsDelay); + electronicsDelay = o2::mid::readElectronicsDelay(vm["electronics-delay-file"].as<std::string>().c_str()); checker.setElectronicsDelay(electronicsDelay); } + if (vm.count("sync-trigger")) { + checker.setSyncTrigger(vm["sync-trigger"].as<uint32_t>()); + } + + o2::mid::CrateMasks crateMasks; if (vm.count("crate-masks-file")) { - o2::mid::CrateMasks crateMasks(vm["crate-masks-file"].as<std::string>().c_str()); - decoder.setCrateMasks(crateMasks); - checker.init(crateMasks); - } else { - checker.init(o2::mid::CrateMasks()); + crateMasks = o2::mid::CrateMasks(vm["crate-masks-file"].as<std::string>().c_str()); } - decoder.init(true); + checker.init(crateMasks); auto nHBs = vm["nHBs"].as<unsigned long int>(); auto nMaxErrors = vm["max-errors"].as<unsigned long int>(); @@ -94,7 +102,7 @@ int process(po::variables_map& vm) } std::cout << "Writing output to: " << outFilename << " ..." << std::endl; - std::vector<o2::mid::LocalBoardRO> data; + std::vector<o2::mid::ROBoard> data; std::vector<o2::mid::ROFRecord> rofRecords; std::vector<o2::mid::ROFRecord> hbRecords; @@ -102,36 +110,33 @@ int process(po::variables_map& vm) unsigned long int iHB = 0; std::stringstream summary; while (rawFileReader.readHB(vm.count("only-closed-HBs") > 0)) { - decoder.process(rawFileReader.getData()); + if (!decoder) { + auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(rawFileReader.getData().data()); + decoder = o2::mid::createDecoder(*rdhPtr, true, electronicsDelay, crateMasks, feeIdConfig); + } + decoder->process(rawFileReader.getData()); rawFileReader.clear(); size_t offset = data.size(); - data.insert(data.end(), decoder.getData().begin(), decoder.getData().end()); - for (auto& rof : decoder.getROFRecords()) { + data.insert(data.end(), decoder->getData().begin(), decoder->getData().end()); + for (auto& rof : decoder->getROFRecords()) { rofRecords.emplace_back(rof.interactionRecord, rof.eventType, rof.firstEntry + offset, rof.nEntries); } o2::InteractionRecord hb(0, iHB); - hbRecords.emplace_back(hb, o2::mid::EventType::Noise, offset, decoder.getData().size()); + hbRecords.emplace_back(hb, o2::mid::EventType::Calib, offset, decoder->getData().size()); ++iHB; if ((nHBs > 0 && iHB >= nHBs)) { break; } - bool isComplete = true; //(vm.count("bare") && decoder.isComplete()); - // Partial check - if (isComplete) { - // The check assumes that we have all data corresponding to one event. - // However this might not be true since we read one HB at the time. - // So we must test that the event was fully read before running the check. - if (!checker.process(data, rofRecords, hbRecords)) { - outFile << checker.getDebugMessage() << "\n"; - } - data.clear(); - rofRecords.clear(); - hbRecords.clear(); - - if (checker.getNEventsFaulty() >= nMaxErrors) { - summary << "Too many errors found: abort check!\n"; - break; - } + if (!checker.process(data, rofRecords, hbRecords)) { + outFile << checker.getDebugMessage() << "\n"; + } + data.clear(); + rofRecords.clear(); + hbRecords.clear(); + + if (checker.getNEventsFaulty() >= nMaxErrors) { + summary << "Too many errors found: abort check!\n"; + break; } } // Check the remaining data @@ -165,7 +170,7 @@ int main(int argc, char* argv[]) ("crate-masks-file", po::value<std::string>(),"Filename with crate masks") ("electronics-delay-file", po::value<std::string>(),"Filename with electronics delay") ("output-dir", po::value<std::string>()->default_value(""),"Output directory") - ("bare", po::value<bool>()->implicit_value(true),"Use bare decoder"); + ("sync-trigger", po::value<unsigned int>(),"Trigger used for synchronisation (default is orbit 0x1)"); po::options_description hidden("hidden options"); @@ -192,8 +197,5 @@ int main(int argc, char* argv[]) return 1; } - if (vm.count("bare")) { - return process<o2::mid::GBTBareDecoder>(vm); - } - return process<o2::mid::GBTUserLogicDecoder>(vm); + return process(vm); } diff --git a/Detectors/MUON/MID/QC/exe/raw-ul-checker.cxx b/Detectors/MUON/MID/QC/exe/raw-ul-checker.cxx new file mode 100644 index 0000000000000..1d52eacf2053a --- /dev/null +++ b/Detectors/MUON/MID/QC/exe/raw-ul-checker.cxx @@ -0,0 +1,182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/QC/exe/raw-ul-checker.cxx +/// \brief Compares the user logic output with the raw input +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 09 December 2019 + +#include <cstdint> +#include <iostream> +#include <fstream> +#include <unordered_map> +#include <vector> +#include <fmt/format.h> +#include "boost/program_options.hpp" +#include "MIDQC/UserLogicChecker.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/FEEIdConfig.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/Decoder.h" +#include "MIDRaw/RawFileReader.h" + +namespace po = boost::program_options; + +bool readFile(std::string filename, o2::mid::Decoder& decoder, std::vector<o2::mid::ROBoard>& data, std::vector<o2::mid::ROFRecord>& rofRecords, unsigned long int nHBFs) +{ + std::cout << "Reading " << filename << std::endl; + o2::mid::RawFileReader rawFileReader; + if (!rawFileReader.init(filename.c_str())) { + std::cout << "Cannot initialize file reader with " << filename << std::endl; + return false; + } + long int hbfsRead = 0; + while (rawFileReader.readHB(true)) { + decoder.process(rawFileReader.getData()); + rawFileReader.clear(); + size_t offset = data.size(); + data.insert(data.end(), decoder.getData().begin(), decoder.getData().end()); + for (auto& rof : decoder.getROFRecords()) { + rofRecords.emplace_back(rof.interactionRecord, rof.eventType, rof.firstEntry + offset, rof.nEntries); + } + ++hbfsRead; + if (hbfsRead == nHBFs) { + break; + } + } + if (data.empty()) { + std::cout << "No data found in " << filename << std::endl; + return false; + } + return true; +} + +std::vector<std::string> split(const std::string& str, char delimiter = ',') +{ + std::vector<std::string> tokens; + std::string token; + std::istringstream tokenStream(str); + while (std::getline(tokenStream, token, delimiter)) { + tokens.push_back(token); + } + return tokens; +} + +int main(int argc, char* argv[]) +{ + po::variables_map vm; + po::options_description generic("Generic options"); + std::string ulFilenames, bareFilenames, feeIdConfigFilename, crateMasksFilename; + std::string outFilename = "check_ul.txt"; + unsigned long int nHBFs = 0; + + // clang-format off + generic.add_options() + ("help", "produce help message") + ("ul-filenames", po::value<std::string>(&ulFilenames),"Comma-separated input raw filenames with CRU User Logic") + ("bare-filenames", po::value<std::string>(&bareFilenames),"Comma-separated input raw filenames with bare CRU") + ("feeId-config-file", po::value<std::string>(&feeIdConfigFilename),"Filename with crate FEE ID correspondence") + ("crate-masks-file", po::value<std::string>(&crateMasksFilename),"Filename with crate masks") + ("electronics-delay-file", po::value<std::string>(),"Filename with electronics delay") + ("outFilename", po::value<std::string>(&outFilename),"Output filename") + ("nHBFs", po::value<unsigned long int>(&nHBFs),"Number of HBFs to test") + ("full", po::value<bool>()->implicit_value(true),"Full check"); + + + po::options_description hidden("hidden options"); + hidden.add_options() + ("input", po::value<std::vector<std::string>>(),"Input filename"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic).add(hidden); + + po::store(po::command_line_parser(argc, argv).options(cmdline).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << "Usage: " << argv[0] << "\n"; + std::cout << generic << std::endl; + return 2; + } + if (ulFilenames.empty() || bareFilenames.empty()) { + std::cout << "Please specify ul-filenames and bare-filenames" << std::endl; + return 1; + } + + o2::mid::FEEIdConfig feeIdConfig; + if (!feeIdConfigFilename.empty()) { + feeIdConfig = o2::mid::FEEIdConfig(feeIdConfigFilename.c_str()); + } + + o2::mid::CrateMasks crateMasks; + if (!crateMasksFilename.empty()) { + crateMasks = o2::mid::CrateMasks(crateMasksFilename.c_str()); + } + + o2::mid::ElectronicsDelay electronicsDelay; + if (vm.count("electronics-delay-file")) { + electronicsDelay = o2::mid::readElectronicsDelay(vm["electronics-delay-file"].as<std::string>().c_str()); + } + + auto bareDecoder = o2::mid::Decoder(true, true, electronicsDelay, crateMasks, feeIdConfig); + auto ulDecoder = o2::mid::Decoder(true, false, electronicsDelay, crateMasks, feeIdConfig); + + std::vector<o2::mid::ROBoard> bareData, ulData; + std::vector<o2::mid::ROFRecord> bareRofs, ulRofs; + + auto bareFnames = split(bareFilenames); + auto ulFnames = split(ulFilenames); + + o2::mid::UserLogicChecker checker; + + for (auto& fname : bareFnames) { + if (!readFile(fname, bareDecoder, bareData, bareRofs, nHBFs)) { + return 3; + } + } + + for (auto& fname : ulFnames) { + if (!readFile(fname, ulDecoder, ulData, ulRofs, bareFnames.size() * nHBFs)) { + return 3; + } + } + + if (false) { + // The orbit information in the UL is not correctly treated + // This means that its orbit will always be 0, unlike the bare data orbit + // Let us set the orbit of the raw data to 0 so that the results can be synchronized + for (auto& rof : bareRofs) { + rof.interactionRecord.orbit = 0; + } + + for (auto& rof : ulRofs) { + rof.interactionRecord.orbit = 0; + } + } + + std::ofstream outFile(outFilename.c_str()); + if (!outFile.is_open()) { + std::cout << "Cannot open output file " << outFilename << std::endl; + return 3; + } + + if (checker.process(bareData, bareRofs, ulData, ulRofs, vm.count("full"))) { + std::cout << "Everything ok!" << std::endl; + } else { + std::cout << "Problems found. See " << outFilename << " for details" << std::endl; + outFile << checker.getDebugMessage() << std::endl; + } + outFile << checker.getSummary() << std::endl; + outFile.close(); + + return 0; +} diff --git a/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h b/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h index 38b85395510a8..7113a7074db58 100644 --- a/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h +++ b/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,12 +19,12 @@ #include <cstdint> #include <map> #include <string> -#include <vector> #include <unordered_map> +#include <vector> #include <gsl/gsl> +#include "DataFormatsMID/ROBoard.h" #include "DataFormatsMID/ROFRecord.h" #include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/LocalBoardRO.h" namespace o2 { @@ -33,7 +34,7 @@ class GBTRawDataChecker { public: void init(uint16_t feeId, uint8_t mask); - bool process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords); + bool process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords); /// Gets the number of processed events unsigned int getNEventsProcessed() const { return mStatistics[0]; } /// Gets the number of faulty events @@ -42,11 +43,14 @@ class GBTRawDataChecker unsigned int getNBusyRaised() const { return mStatistics[2]; } /// Gets the std::string getDebugMessage() const { return mDebugMsg; } - void clear(); + void clear(bool all = false); /// Sets the delay in the electronics void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mElectronicsDelay = electronicsDelay; } + /// Sets the trigger use to verify if all data of an event where received + void setSyncTrigger(uint32_t syncTrigger) { mSyncTrigger = syncTrigger; } + private: struct Mask { std::array<uint16_t, 4> patternsBP{}; /// Bending plane mask @@ -54,30 +58,37 @@ class GBTRawDataChecker }; struct GBT { - std::vector<LocalBoardRO> regs{}; /// Regional boards - std::vector<LocalBoardRO> locs{}; /// Local boards - std::vector<long int> pages{}; /// Pages information + std::vector<ROBoard> regs{}; /// Regional boards + std::vector<ROBoard> locs{}; /// Local boards + std::vector<long int> pages{}; /// Pages information }; struct BoardInfo { - LocalBoardRO board{}; + ROBoard board{}; o2::InteractionRecord interactionRecord{}; long int page{-1}; }; + struct BusyInfo { + bool isBusy{0}; + o2::InteractionRecord interactionRecord{}; + }; + void clearChecked(bool isTriggered, bool clearTrigEvents); - bool checkEvent(bool isTriggered, const std::vector<LocalBoardRO>& regs, const std::vector<LocalBoardRO>& locs); + bool checkEvent(bool isTriggered, const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir); bool checkEvents(bool isTriggered); - bool checkConsistency(const LocalBoardRO& board); - bool checkConsistency(const std::vector<LocalBoardRO>& boards); - bool checkMasks(const std::vector<LocalBoardRO>& locs); - bool checkLocalBoardSize(const LocalBoardRO& board); - bool checkLocalBoardSize(const std::vector<LocalBoardRO>& boards); - bool checkRegLocConsistency(const std::vector<LocalBoardRO>& regs, const std::vector<LocalBoardRO>& locs); - uint8_t getElinkId(const LocalBoardRO& board) const; + bool checkConsistency(const ROBoard& board); + bool checkConsistency(const std::vector<ROBoard>& boards); + bool checkMasks(const std::vector<ROBoard>& locs); + bool checkLocalBoardSize(const ROBoard& board); + bool checkLocalBoardSize(const std::vector<ROBoard>& boards); + bool checkRegLocConsistency(const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir); + uint8_t getElinkId(const ROBoard& board) const; + InteractionRecord getRawIR(uint8_t id, bool isTrigger, InteractionRecord ir) const; unsigned int getLastCompleteTrigEvent(); bool isCompleteSelfTrigEvent(const o2::InteractionRecord& ir) const; - std::string printBoards(const std::vector<LocalBoardRO>& boards) const; + std::string printBoards(const std::vector<ROBoard>& boards) const; + bool runCheckEvents(unsigned int completeMask); void sortEvents(bool isTriggered); std::string mEventDebugMsg{}; /// Debug message for the event @@ -88,20 +99,20 @@ class GBTRawDataChecker uint16_t mFeeId{0}; /// FeeId uint16_t mResetVal{0}; /// Reset value ElectronicsDelay mElectronicsDelay{}; /// Delays in the electronics + uint32_t mSyncTrigger{raw::sORB}; /// Trigger for synchronization std::map<o2::InteractionRecord, uint16_t> mTrigEvents{}; ///! Index of triggered events - std::unordered_map<uint8_t, bool> mBusyFlagTrig; /// Busy flag for triggered events - std::unordered_map<uint8_t, bool> mBusyFlagSelfTrig; /// Busy flag for self-triggered events + std::array<std::vector<BusyInfo>, 10> mBusyPeriods{}; /// Busy flag for triggered events - std::unordered_map<uint8_t, std::vector<BoardInfo>> mBoardsTrig{}; ///! Boards with triggered events - std::unordered_map<uint8_t, std::vector<BoardInfo>> mBoardsSelfTrig{}; ///! Boards with self-triggered events + std::array<std::vector<BoardInfo>, 10> mBoardsTrig{}; ///! Boards with triggered events + std::array<std::vector<BoardInfo>, 10> mBoardsSelfTrig{}; ///! Boards with self-triggered events - std::map<o2::InteractionRecord, std::vector<std::pair<uint8_t, size_t>>> mOrderedIndexesTrig{}; ///! Ordered indexes for triggered boards - std::map<o2::InteractionRecord, std::vector<std::pair<uint8_t, size_t>>> mOrderedIndexesSelfTrig{}; ///! Ordered indexes for self-triggered boards + std::unordered_map<uint64_t, std::vector<std::pair<uint8_t, size_t>>> mOrderedIndexesTrig{}; ///! Ordered indexes for triggered boards + std::unordered_map<uint64_t, std::vector<std::pair<uint8_t, size_t>>> mOrderedIndexesSelfTrig{}; ///! Ordered indexes for self-triggered boards - std::unordered_map<uint8_t, size_t> mLastIndexTrig{}; ///! Last checked index for triggered boards - std::unordered_map<uint8_t, size_t> mLastIndexSelfTrig{}; ///! Last checked index for self-triggered boards + std::unordered_map<uint8_t, long int> mLastIndexTrig{}; ///! Last checked index for triggered boards + std::unordered_map<uint8_t, long int> mLastIndexSelfTrig{}; ///! Last checked index for self-triggered boards o2::InteractionRecord mLastCompleteIRTrig{}; ///! Last complete IR for triggered boards o2::InteractionRecord mLastCompleteIRSelfTrig{}; ///! Last complete IR for self-triggered boards diff --git a/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h b/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h index d761bde848ee9..75327eaac8445 100644 --- a/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h +++ b/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ #include "DataFormatsMID/ROFRecord.h" #include "MIDRaw/CrateMasks.h" #include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/LocalBoardRO.h" +#include "DataFormatsMID/ROBoard.h" #include "MIDQC/GBTRawDataChecker.h" namespace o2 @@ -32,7 +33,7 @@ class RawDataChecker { public: void init(const CrateMasks& masks); - bool process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords); + bool process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords); /// Gets the number of processed events unsigned int getNEventsProcessed() const; /// Gets the number of faulty events @@ -41,11 +42,13 @@ class RawDataChecker unsigned int getNBusyRaised() const; /// Gets the debug message std::string getDebugMessage() const { return mDebugMsg; } - void clear(); + void clear(bool all = false); /// Sets the delay in the electronics void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mElectronicsDelay = electronicsDelay; } + void setSyncTrigger(uint32_t syncTrigger); + private: std::array<GBTRawDataChecker, crateparams::sNGBTs> mCheckers{}; /// GBT raw data checker std::string mDebugMsg{}; /// Debug message diff --git a/Detectors/MUON/MID/QC/include/MIDQC/UserLogicChecker.h b/Detectors/MUON/MID/QC/include/MIDQC/UserLogicChecker.h new file mode 100644 index 0000000000000..c1eed36a99427 --- /dev/null +++ b/Detectors/MUON/MID/QC/include/MIDQC/UserLogicChecker.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDQC/UserLogicChecker.h +/// \brief Class to check the CRU user logic +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 02 November 2020 +#ifndef O2_MID_USERLOGICCHECKER_H +#define O2_MID_USERLOGICCHECKER_H + +#include <cstdint> +#include <string> +#include <unordered_map> +#include <gsl/gsl> +#include "DataFormatsMID/ROBoard.h" +#include "DataFormatsMID/ROFRecord.h" + +namespace o2 +{ +namespace mid +{ +class UserLogicChecker +{ + public: + bool process(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs, bool isFull = false); + + /// Gets the debug message + std::string getDebugMessage() const { return mDebugMsg; } + std::string getSummary() const; + void clear(); + + private: + bool checkAll(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs); + bool checkBoards(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs); + void clearBoards(); + void fillBoards(gsl::span<const ROBoard> data, gsl::span<const ROFRecord> rofRecords, bool isUL); + uint32_t getId(const ROBoard& board) const; + + std::unordered_map<uint64_t, std::vector<size_t>> getOrderedIndexes(gsl::span<const ROFRecord> rofRecords) const; + + bool isSame(const o2::mid::ROBoard& loc1, const o2::mid::ROBoard& loc2) const; + std::string printIRHex(const o2::InteractionRecord& ir) const; + + std::string mDebugMsg{}; /// Debug message + + std::unordered_map<uint32_t, bool> mInsideDataTaking{}; /// Flag to assess if we are inside SOX-EOX + + std::unordered_map<uint32_t, std::array<unsigned long int, 2>> mStatistics{}; /// Board statistics + + struct boardInfo { + InteractionRecord interactionRecord; + ROBoard board; + }; + + std::unordered_map<uint32_t, std::vector<boardInfo>> mBoardsBare; //! Bare boards info + std::unordered_map<uint32_t, std::vector<boardInfo>> mBoardsUL; //! UL Boards info + std::unordered_map<uint32_t, size_t> mLastCheckedBare; //! Last checked bare + std::unordered_map<uint32_t, size_t> mLastCheckedUL; //! Last checked UL +}; +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_USERLOGICCHECKER_H */ diff --git a/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx b/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx index d1def0c8d06de..cecd0cc22afe7 100644 --- a/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx +++ b/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ void GBTRawDataChecker::init(uint16_t feeId, uint8_t mask) mCrateMask = mask; } -bool GBTRawDataChecker::checkLocalBoardSize(const LocalBoardRO& board) +bool GBTRawDataChecker::checkLocalBoardSize(const ROBoard& board) { /// Checks that the board has the expected non-null patterns @@ -52,7 +53,7 @@ bool GBTRawDataChecker::checkLocalBoardSize(const LocalBoardRO& board) return true; } -bool GBTRawDataChecker::checkLocalBoardSize(const std::vector<LocalBoardRO>& boards) +bool GBTRawDataChecker::checkLocalBoardSize(const std::vector<ROBoard>& boards) { /// Checks that the boards have the expected non-null patterns for (auto& board : boards) { @@ -63,7 +64,7 @@ bool GBTRawDataChecker::checkLocalBoardSize(const std::vector<LocalBoardRO>& boa return true; } -bool GBTRawDataChecker::checkConsistency(const LocalBoardRO& board) +bool GBTRawDataChecker::checkConsistency(const ROBoard& board) { /// Checks that the event information is consistent @@ -71,18 +72,23 @@ bool GBTRawDataChecker::checkConsistency(const LocalBoardRO& board) bool isCalib = raw::isCalibration(board.triggerWord); bool isPhys = board.triggerWord & raw::sPHY; - if (isPhys) { - if (isCalib) { - mEventDebugMsg += "inconsistent trigger: calibration and physics trigger cannot be fired together\n"; - return false; - } - if (raw::isLoc(board.statusWord)) { - if (board.firedChambers) { - mEventDebugMsg += "inconsistent trigger: fired chambers should be 0\n"; - return false; - } - } - } + // FIXME: During data acquisition we do not expect a calibration trigger + // in coincidence with a physics trigger. + // However, this situation can happen in the tests with the LTU. + // So, let us remove these tests for the time being + + // if (isPhys) { + // if (isCalib) { + // mEventDebugMsg += "inconsistent trigger: calibration and physics trigger cannot be fired together\n"; + // return false; + // } + // if (raw::isLoc(board.statusWord)) { + // if (board.firedChambers) { + // mEventDebugMsg += "inconsistent trigger: fired chambers should be 0\n"; + // return false; + // } + // } + // } if (isSoxOrReset && (isCalib || isPhys)) { mEventDebugMsg += "inconsistent trigger: cannot be SOX and calibration\n"; return false; @@ -91,7 +97,7 @@ bool GBTRawDataChecker::checkConsistency(const LocalBoardRO& board) return true; } -bool GBTRawDataChecker::checkConsistency(const std::vector<LocalBoardRO>& boards) +bool GBTRawDataChecker::checkConsistency(const std::vector<ROBoard>& boards) { /// Checks that the event information is consistent for (auto& board : boards) { @@ -105,7 +111,7 @@ bool GBTRawDataChecker::checkConsistency(const std::vector<LocalBoardRO>& boards return true; } -bool GBTRawDataChecker::checkMasks(const std::vector<LocalBoardRO>& locs) +bool GBTRawDataChecker::checkMasks(const std::vector<ROBoard>& locs) { /// Checks the masks for (auto loc : locs) { @@ -132,22 +138,23 @@ bool GBTRawDataChecker::checkMasks(const std::vector<LocalBoardRO>& locs) return true; } -bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<LocalBoardRO>& regs, const std::vector<LocalBoardRO>& locs) +bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir) { /// Checks consistency between local and regional info uint8_t regFired{0}; + bool isTrig = false; for (auto& reg : regs) { - uint8_t ireg = crateparams::getLocId(reg.boardId) % 2; - auto busyItem = mBusyFlagSelfTrig.find(8 + ireg); + uint8_t ireg = raw::getLocId(reg.boardId) % 2; if (reg.triggerWord == 0) { // Self-triggered event: check the decision regFired |= (reg.firedChambers << (4 * ireg)); } else { // Triggered event: all active boards must answer regFired |= (mCrateMask & (0xF << (4 * ireg))); + isTrig = true; } } - uint8_t locFired{0}, locBusy{0}; + uint8_t locFired{0}; for (auto& loc : locs) { auto linkId = getElinkId(loc); uint8_t mask = (1 << linkId); @@ -159,6 +166,7 @@ bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<LocalBoardRO>& } else { // Triggered event: all active boards must answer locFired |= mask; + isTrig = true; } } @@ -170,8 +178,15 @@ bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<LocalBoardRO>& // If the board is still busy it will not answer. uint8_t busy{0}; for (uint8_t iboard = 0; iboard < crateparams::sNELinksPerGBT; ++iboard) { - auto busyItem = mBusyFlagSelfTrig.find(iboard); - if (busyItem != mBusyFlagSelfTrig.end() && busyItem->second) { + auto rawIr = getRawIR(iboard, isTrig, ir); + bool isBusy = false; + for (auto& busyInfo : mBusyPeriods[iboard]) { + if (busyInfo.interactionRecord > rawIr) { + break; + } + isBusy = busyInfo.isBusy; + } + if (isBusy) { busy |= (iboard < crateparams::sMaxNBoardsInLink) ? (1 << iboard) : (0xF << (4 * (iboard % 2))); } } @@ -188,7 +203,7 @@ bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<LocalBoardRO>& return true; } -std::string GBTRawDataChecker::printBoards(const std::vector<LocalBoardRO>& boards) const +std::string GBTRawDataChecker::printBoards(const std::vector<ROBoard>& boards) const { /// Prints the boards std::stringstream ss; @@ -198,11 +213,11 @@ std::string GBTRawDataChecker::printBoards(const std::vector<LocalBoardRO>& boar return ss.str(); } -bool GBTRawDataChecker::checkEvent(bool isTriggered, const std::vector<LocalBoardRO>& regs, const std::vector<LocalBoardRO>& locs) +bool GBTRawDataChecker::checkEvent(bool isTriggered, const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir) { /// Checks the cards belonging to the same BC mEventDebugMsg.clear(); - if (!checkRegLocConsistency(regs, locs)) { + if (!checkRegLocConsistency(regs, locs, ir)) { return false; } @@ -223,7 +238,24 @@ bool GBTRawDataChecker::checkEvent(bool isTriggered, const std::vector<LocalBoar return true; } -uint8_t GBTRawDataChecker::getElinkId(const LocalBoardRO& board) const +InteractionRecord GBTRawDataChecker::getRawIR(uint8_t id, bool isTrigger, InteractionRecord ir) const +{ + /// Returns the bc as it was set by electronics (before corrections) + if (isTrigger) { + return ir; + } + ir.bc += mElectronicsDelay.BCToLocal; + if (id >= crateparams::sMaxNBoardsInLink) { + ir.bc += mElectronicsDelay.regToLocal; + } + if (ir.bc >= mResetVal) { + ir.bc = ir.bc % mResetVal; + ++ir.orbit; + } + return ir; +} + +uint8_t GBTRawDataChecker::getElinkId(const ROBoard& board) const { /// Returns the e-link ID if (raw::isLoc(board.statusWord)) { @@ -239,23 +271,24 @@ void GBTRawDataChecker::clearChecked(bool isTriggered, bool clearTrigEvents) auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig; auto& lastIndexes = isTriggered ? mLastIndexTrig : mLastIndexSelfTrig; // Create a new board map with the checked events stripped - std::unordered_map<uint8_t, std::vector<BoardInfo>> newBoards{}; for (auto& lastIdxItem : lastIndexes) { auto firstIdx = lastIdxItem.second + 1; auto& boardVec = boards[lastIdxItem.first]; - if (firstIdx < boardVec.size()) { - auto& newVec = newBoards[lastIdxItem.first]; - newVec.insert(newVec.end(), boardVec.begin() + firstIdx, boardVec.end()); - } + boards[lastIdxItem.first].erase(boardVec.begin(), boardVec.begin() + firstIdx); } - boards.swap(newBoards); if (clearTrigEvents) { // Clears the map with the processed triggers auto& lastCompleteTrigIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig; - auto low = mTrigEvents.begin(); auto up = mTrigEvents.upper_bound(lastCompleteTrigIR); - mTrigEvents.erase(low, up); + mTrigEvents.erase(mTrigEvents.begin(), up); + for (auto& busyInfoVec : mBusyPeriods) { + auto upBusy = std::upper_bound(busyInfoVec.begin(), busyInfoVec.end(), lastCompleteTrigIR, [](const InteractionRecord& ir, const BusyInfo& busyInfo) { return ir <= busyInfo.interactionRecord; }); + if (upBusy != busyInfoVec.begin()) { + --upBusy; + } + busyInfoVec.erase(busyInfoVec.begin(), upBusy); + } } } @@ -267,16 +300,17 @@ bool GBTRawDataChecker::isCompleteSelfTrigEvent(const o2::InteractionRecord& ir) // compared to triggered events. // So, we expect information from a previous orbit after having received an orbit trigger. // Let us check that we have all boards with the same orbit + bool isIncluded = false; - for (uint8_t ireg = 8; ireg < 10; ++ireg) { - auto item = mBoardsSelfTrig.find(ireg); - if (item != mBoardsSelfTrig.end()) { - if (item->second.front().interactionRecord.orbit <= ir.orbit) { - isIncluded = true; - } - if (item->second.back().interactionRecord.orbit <= ir.orbit) { + for (uint8_t ireg = 8; ireg < crateparams::sNELinksPerGBT; ++ireg) { + auto& boards = mBoardsSelfTrig[ireg]; + if (!boards.empty()) { + if (boards.back().interactionRecord.orbit == ir.orbit) { return false; } + if (boards.front().interactionRecord.orbit <= ir.orbit) { + isIncluded = true; + } } } return isIncluded; @@ -304,7 +338,7 @@ unsigned int GBTRawDataChecker::getLastCompleteTrigEvent() for (; trigEventIt != end; ++trigEventIt) { if ((trigEventIt->second & fullMask) == fullMask) { // The trigger events contain the unprocessed events for both triggered and self-triggered events - // These might not be synchronized (typically the latest complete self-triggered events lies behind) + // These might not be synchronized (typically the latest complete self-triggered events lie behind) // If the latest IR in memory is more recent than the current complete event found, // then it means that we need to wait for more HBs. if (mLastCompleteIRTrig.isDummy() || mLastCompleteIRTrig < trigEventIt->first) { @@ -320,6 +354,7 @@ unsigned int GBTRawDataChecker::getLastCompleteTrigEvent() } ++trIt; } + return completeMask; } } @@ -327,6 +362,35 @@ unsigned int GBTRawDataChecker::getLastCompleteTrigEvent() return completeMask; } +bool GBTRawDataChecker::runCheckEvents(unsigned int completeMask) +{ + /// Runs the checker if needed + + bool isOk = true; + + if (completeMask & 0x1) { + sortEvents(true); + isOk &= checkEvents(true); + // This is needed to clear vectors in runs with no self-triggered events + bool clearTrigger = true; + for (auto infos : mBoardsSelfTrig) { + if (!infos.empty()) { + clearTrigger = false; + break; + } + } + clearChecked(true, clearTrigger); + } + + if (completeMask & 0x2) { + sortEvents(false); + isOk &= checkEvents(false); + clearChecked(false, true); + } + + return isOk; +} + void GBTRawDataChecker::sortEvents(bool isTriggered) { /// Sorts the event in time @@ -336,16 +400,16 @@ void GBTRawDataChecker::sortEvents(bool isTriggered) auto& lastCompleteTrigEventIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig; orderedIndexes.clear(); lastIndexes.clear(); - for (auto& boardItem : boards) { - size_t lastIdx = 0; - for (auto boardIt = boardItem.second.begin(), end = boardItem.second.end(); boardIt != end; ++boardIt) { + for (uint8_t ilink = 0; ilink < crateparams::sNELinksPerGBT; ++ilink) { + long int lastIdx = -1; + for (auto boardIt = boards[ilink].begin(), end = boards[ilink].end(); boardIt != end; ++boardIt) { if (boardIt->interactionRecord > lastCompleteTrigEventIR) { break; } - lastIdx = std::distance(boardItem.second.begin(), boardIt); - orderedIndexes[boardIt->interactionRecord].emplace_back(boardItem.first, lastIdx); + lastIdx = std::distance(boards[ilink].begin(), boardIt); + orderedIndexes[boardIt->interactionRecord.toLong()].emplace_back(ilink, lastIdx); } - lastIndexes[boardItem.first] = lastIdx; + lastIndexes[ilink] = lastIdx; } } @@ -355,26 +419,17 @@ bool GBTRawDataChecker::checkEvents(bool isTriggered) bool isOk = true; auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig; auto& orderedIndexes = isTriggered ? mOrderedIndexesTrig : mOrderedIndexesSelfTrig; - auto& busyFlag = isTriggered ? mBusyFlagTrig : mBusyFlagSelfTrig; // Loop on the event indexes + o2::InteractionRecord ir; for (auto& evtIdxItem : orderedIndexes) { // All of these boards have the same timestamp GBT gbtEvent; - bool busyRaised = false; + // bool busyRaised = false; for (auto& evtPair : evtIdxItem.second) { auto& boardInfo = boards[evtPair.first][evtPair.second]; uint8_t triggerId = boardInfo.board.triggerWord; auto elinkId = getElinkId(boardInfo.board); - bool isBusy = ((boardInfo.board.statusWord & raw::sREJECTING) != 0); - busyRaised |= isBusy; - busyFlag[elinkId] = isBusy; - if (isBusy && !isTriggered) { - // This is a special event that just signals a busy. - // Do not add the board to the events to be tested. - // Even because this event can have the same IR and triggerWord (0) of a self-triggered event - continue; - } if (raw::isLoc(boardInfo.board.statusWord)) { gbtEvent.locs.push_back(boardInfo.board); } else { @@ -386,13 +441,11 @@ bool GBTRawDataChecker::checkEvents(bool isTriggered) } } } - if (busyRaised && !isTriggered) { - ++mStatistics[2]; - } ++mStatistics[0]; - if (!checkEvent(isTriggered, gbtEvent.regs, gbtEvent.locs)) { + ir.setFromLong(evtIdxItem.first); + if (!checkEvent(isTriggered, gbtEvent.regs, gbtEvent.locs, ir)) { std::stringstream ss; - ss << fmt::format("BCid: 0x{:x} Orbit: 0x{:x}", evtIdxItem.first.bc, evtIdxItem.first.orbit); + ss << fmt::format("BCid: 0x{:x} Orbit: 0x{:x}", ir.bc, ir.orbit); if (!gbtEvent.pages.empty()) { ss << " [in"; for (auto& page : gbtEvent.pages) { @@ -411,13 +464,17 @@ bool GBTRawDataChecker::checkEvents(bool isTriggered) return isOk; } -bool GBTRawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords) +bool GBTRawDataChecker::process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords) { /// Checks the raw data mDebugMsg.clear(); // Fill board information for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) { + if (rofIt->interactionRecord.orbit == 0xffffffff) { + // Protection for event with orbit 0 + continue; + } for (auto locIt = localBoards.begin() + rofIt->firstEntry; locIt != localBoards.begin() + rofIt->firstEntry + rofIt->nEntries; ++locIt) { // Find what page this event corresponds to. // This is useful for debugging. @@ -435,30 +492,26 @@ bool GBTRawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl:: auto& elinkVec = (locIt->triggerWord == 0) ? mBoardsSelfTrig[id] : mBoardsTrig[id]; elinkVec.push_back({*locIt, rofIt->interactionRecord, page}); + auto& busyVec = mBusyPeriods[id]; + bool wasBusy = !busyVec.empty() && busyVec.back().isBusy; + bool isBusy = locIt->statusWord & raw::sREJECTING; + if (isBusy != wasBusy) { + if (isBusy) { + ++mStatistics[2]; + } + busyVec.push_back({isBusy, getRawIR(id, locIt->triggerWord != 0, rofIt->interactionRecord)}); + } + if (locIt->triggerWord == 0) { continue; } - // Keep track of the busy - if (locIt->statusWord & raw::sREJECTING) { - auto& selfVec = mBoardsSelfTrig[id]; - auto board = *locIt; - board.triggerWord = 0; - auto ir = rofIt->interactionRecord; - if (id >= crateparams::sMaxNBoardsInLink) { - uint16_t delayRegLocal = mElectronicsDelay.regToLocal; - if (rofIt->interactionRecord.bc < delayRegLocal) { - ir -= (constants::lhc::LHCMaxBunches - mResetVal - 1); - } - ir -= delayRegLocal; - } - selfVec.push_back({*locIt, ir, page}); + // Keep track of the trigger chosen for synchronisation + if (locIt->triggerWord & mSyncTrigger) { + mTrigEvents[rofIt->interactionRecord] |= (1 << id); } - - // Keep track of the orbit triggers if (locIt->triggerWord & raw::sORB) { - mTrigEvents[rofIt->interactionRecord] |= (1 << id); - mResetVal = rofIt->interactionRecord.bc; + mResetVal = rofIt->interactionRecord.bc + 1; } // Compute the masks @@ -479,31 +532,15 @@ bool GBTRawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl:: } // loop on local boards } // loop on ROF records - auto completeMask = getLastCompleteTrigEvent(); - - bool isOk = true; - - if (completeMask & 0x1) { - sortEvents(true); - isOk &= checkEvents(true); - clearChecked(true, mBoardsSelfTrig.empty()); - } - - if (completeMask & 0x2) { - sortEvents(false); - isOk &= checkEvents(false); - clearChecked(false, true); - } - - return isOk; + return runCheckEvents(getLastCompleteTrigEvent()); } -void GBTRawDataChecker::clear() +void GBTRawDataChecker::clear(bool all) { /// Resets the masks and flags - mMasks.clear(); - mBusyFlagTrig.clear(); - mBusyFlagSelfTrig.clear(); + if (all) { + mMasks.clear(); + } mStatistics.fill(0); } diff --git a/Detectors/MUON/MID/QC/src/RawDataChecker.cxx b/Detectors/MUON/MID/QC/src/RawDataChecker.cxx index c8e97e10ad6e4..bdb037d1b7891 100644 --- a/Detectors/MUON/MID/QC/src/RawDataChecker.cxx +++ b/Detectors/MUON/MID/QC/src/RawDataChecker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ void RawDataChecker::init(const CrateMasks& crateMasks) } } -bool RawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords) +bool RawDataChecker::process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords) { /// Checks the raw data @@ -41,9 +42,9 @@ bool RawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl::spa std::unordered_map<uint16_t, std::vector<ROFRecord>> rofs; for (auto& rof : rofRecords) { auto& loc = localBoards[rof.firstEntry]; - auto crateId = crateparams::getCrateId(loc.boardId); - auto linkId = crateparams::getGBTIdFromBoardInCrate(crateparams::getLocId(loc.boardId)); - auto feeId = crateparams::makeROId(crateId, linkId); + auto crateId = raw::getCrateId(loc.boardId); + auto linkId = crateparams::getGBTIdFromBoardInCrate(raw::getLocId(loc.boardId)); + auto feeId = crateparams::makeGBTUniqueId(crateId, linkId); rofs[feeId].emplace_back(rof); } @@ -55,6 +56,14 @@ bool RawDataChecker::process(gsl::span<const LocalBoardRO> localBoards, gsl::spa return isOk; } +void RawDataChecker::setSyncTrigger(uint32_t syncTrigger) +{ + /// Sets the trigger use to verify if all data of an event where received + for (auto& checker : mCheckers) { + checker.setSyncTrigger(syncTrigger); + } +} + unsigned int RawDataChecker::getNEventsProcessed() const { /// Gets the number of processed events @@ -85,11 +94,11 @@ unsigned int RawDataChecker::getNBusyRaised() const return sum; } -void RawDataChecker::clear() +void RawDataChecker::clear(bool all) { /// Clears the statistics for (auto& checker : mCheckers) { - checker.clear(); + checker.clear(all); } } diff --git a/Detectors/MUON/MID/QC/src/UserLogicChecker.cxx b/Detectors/MUON/MID/QC/src/UserLogicChecker.cxx new file mode 100644 index 0000000000000..53352dae15deb --- /dev/null +++ b/Detectors/MUON/MID/QC/src/UserLogicChecker.cxx @@ -0,0 +1,258 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/QC/src/UserLogicChecker.cxx +/// \brief Class to check the CRU user logic +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 02 November 2020 + +#include "MIDQC/UserLogicChecker.h" + +#include <sstream> +#include <fmt/format.h> + +namespace o2 +{ +namespace mid +{ + +bool UserLogicChecker::isSame(const o2::mid::ROBoard& loc1, const o2::mid::ROBoard& loc2) const +{ + /// Tests if boards are sames + if (loc1.statusWord == loc2.statusWord && loc1.triggerWord == loc2.triggerWord && loc1.firedChambers == loc2.firedChambers && loc1.boardId == loc2.boardId) { + for (int ich = 0; ich < 4; ++ich) { + if (loc1.patternsBP[ich] != loc2.patternsBP[ich] || loc1.patternsNBP[ich] != loc2.patternsNBP[ich]) { + return false; + } + } + return true; + } + return false; +} + +std::string UserLogicChecker::printIRHex(const o2::InteractionRecord& ir) const +{ + /// Properly format interaction record + return fmt::format("BCid: 0x{:x} Orbit: 0x{:x}", ir.bc, ir.orbit); +} + +uint32_t UserLogicChecker::getId(const ROBoard& board) const +{ + /// Gets the unique ID for internal usage + uint32_t id = static_cast<uint32_t>(board.boardId); + if (!raw::isLoc(board.statusWord)) { + id |= (1 << 16); + } + return id; +} + +void UserLogicChecker::fillBoards(gsl::span<const ROBoard> data, gsl::span<const ROFRecord> rofRecords, bool isUL) +{ + /// Fills the inner structure for checks + + auto& boards = isUL ? mBoardsUL : mBoardsBare; + + // The UL rejects the events outside the SOX/EOX + // So we should do the same + for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) { + auto& loc = data[rofIt->firstEntry]; + auto id = getId(loc); + auto isInside = mInsideDataTaking.find(id); + if (isInside == mInsideDataTaking.end()) { + mInsideDataTaking[id] = false; + isInside = mInsideDataTaking.find(id); + } + if (loc.triggerWord & raw::sSOX) { + isInside->second = true; + } else if (loc.triggerWord & raw::sEOX) { + isInside->second = false; + } + if (isInside->second) { + boards[id].push_back({rofIt->interactionRecord, loc}); + } + } +} + +void UserLogicChecker::clearBoards() +{ + /// Clears the processed boards + + for (int itype = 0; itype < 2; ++itype) { + auto& boards = (itype == 0) ? mBoardsUL : mBoardsBare; + auto& lastChecked = (itype == 0) ? mLastCheckedUL : mLastCheckedBare; + std::unordered_map<uint32_t, std::vector<boardInfo>> newBoards; + for (auto& boardItem : boards) { + auto lastIdxItem = lastChecked.find(boardItem.first); + if (lastIdxItem->second != boardItem.second.size()) { + auto& vec = newBoards[boardItem.first]; + vec.insert(vec.end(), boardItem.second.begin() + lastIdxItem->second, boardItem.second.end()); + } + } + boards.swap(newBoards); + lastChecked.clear(); + } +} + +bool UserLogicChecker::checkBoards(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs) +{ + /// Compares the UL output with the corresponding bare output per board + clearBoards(); + fillBoards(bareData, bareRofs, false); + fillBoards(ulData, ulRofs, true); + bool isOk = true; + + for (auto& bareItem : mBoardsBare) { + std::string boardType = (bareItem.first < 0x10000) ? "Loc" : "Reg"; + auto& lastCheckedBare = mLastCheckedBare[bareItem.first]; + auto& stats = mStatistics[bareItem.first]; + stats[0] += bareItem.second.size(); + std::stringstream ss; + ss << "\n-----------" << std::endl; + uint16_t boardId = (bareItem.first & 0xFFFF); + ss << "Checking crate: " << static_cast<int>(raw::getCrateId(boardId)) + << " " << boardType << " board: " << static_cast<int>(raw::getLocId(boardId)) << std::endl; + auto ulItem = mBoardsUL.find(bareItem.first); + if (ulItem == mBoardsUL.end()) { + ss << " cannot find " << printIRHex(bareItem.second.front().interactionRecord) << " in ul" << std::endl; + isOk = false; + ss << "-----------" << std::endl; + mDebugMsg += ss.str(); + stats[1] += bareItem.second.size(); + continue; + } + auto& lastCheckedUL = mLastCheckedUL[ulItem->first]; + lastCheckedUL = 0; + auto lastOk = lastCheckedUL; + bool isCurrentOk = true; + for (lastCheckedBare = 0; lastCheckedBare < bareItem.second.size(); ++lastCheckedBare) { + if (lastCheckedUL == ulItem->second.size()) { + break; + } else if (!isSame(ulItem->second[lastCheckedUL].board, bareItem.second[lastCheckedBare].board) || ulItem->second[lastCheckedUL].interactionRecord != bareItem.second[lastCheckedBare].interactionRecord) { + ss << "\nFirst divergence at element " << lastCheckedBare + 1 << " / " << bareItem.second.size() << ":" << std::endl; + ss << "bare: " << printIRHex(bareItem.second[lastCheckedBare].interactionRecord) << std::endl; + ss << bareItem.second[lastCheckedBare].board << std::endl; + ss << "ul: " << printIRHex(ulItem->second[lastCheckedUL].interactionRecord) << std::endl; + ss << ulItem->second[lastCheckedUL].board << std::endl; + isCurrentOk = false; + } + if (!isCurrentOk) { + if (lastOk != lastCheckedUL) { + ss << "lastOk: " << printIRHex(ulItem->second[lastOk].interactionRecord) << std::endl; + ss << ulItem->second[lastOk].board << std::endl; + } else { + ss << "lastOk: none. This is the first event!" << std::endl; + } + ss << "-----------" << std::endl; + mDebugMsg += ss.str(); + stats[1] += lastCheckedUL; + lastCheckedUL = ulItem->second.size(); + lastCheckedBare = bareItem.second.size(); + isOk = false; + break; + } + lastOk = lastCheckedUL; + ++lastCheckedUL; + } // loop on bare data for this board ID + } // loop on board IDs + return isOk; +} + +std::unordered_map<uint64_t, std::vector<size_t>> UserLogicChecker::getOrderedIndexes(gsl::span<const ROFRecord> rofRecords) const +{ + // Orders data according to their IR + std::unordered_map<uint64_t, std::vector<size_t>> orderIndexes; + for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) { + // Fill the map with ordered events + orderIndexes[rofIt->interactionRecord.toLong()].emplace_back(rofIt->firstEntry); + } + return orderIndexes; +} + +bool UserLogicChecker::checkAll(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs) +{ + auto bareIndexes = getOrderedIndexes(bareRofs); + auto ulIndexes = getOrderedIndexes(ulRofs); + + bool isOk = true; + std::stringstream ss; + InteractionRecord ir; + for (auto& bareItem : bareIndexes) { + auto ulItem = ulIndexes.find(bareItem.first); + ir.setFromLong(bareItem.first); + if (ulItem == ulIndexes.end()) { + isOk = false; + ss << "\nCannot find: " << printIRHex(ir) << " in ul\n"; + continue; + } + std::vector<size_t> auxVec = ulItem->second; + for (auto& idx1 : bareItem.second) { + bool found = false; + for (auto auxIt = auxVec.begin(); auxIt != auxVec.end(); ++auxIt) { + if (isSame(bareData[idx1], ulData[*auxIt])) { + auxVec.erase(auxIt); + found = true; + break; + } + } + if (!found) { + isOk = false; + ss << "\nOnly in bare: " << printIRHex(ir) << "\n"; + ss << " " << bareData[idx1] << "\n"; + } + } + for (auto& idx2 : auxVec) { + isOk = false; + ss << "\nOnly in ul: " << printIRHex(ir) << "\n"; + ss << " " << ulData[idx2] << "\n"; + } + } + + for (auto& ulItem : ulIndexes) { + auto bareItem = bareIndexes.find(ulItem.first); + if (bareItem == bareIndexes.end()) { + isOk = false; + ir.setFromLong(ulItem.first); + ss << "\nCannot find: " << printIRHex(ir) << " in bare\n"; + } + } + mDebugMsg = ss.str(); + return isOk; +} + +bool UserLogicChecker::process(gsl::span<const ROBoard> bareData, gsl::span<const ROFRecord> bareRofs, gsl::span<const ROBoard> ulData, gsl::span<const ROFRecord> ulRofs, bool isFull) +{ + /// Compares the UL output with the corresponding bare output + mDebugMsg.clear(); + return isFull ? checkAll(bareData, bareRofs, ulData, ulRofs) : checkBoards(bareData, bareRofs, ulData, ulRofs); +} + +void UserLogicChecker::clear() +{ + /// Clears debug message + mInsideDataTaking.clear(); + mStatistics.clear(); +} + +std::string UserLogicChecker::getSummary() const +{ + /// Gets summary message + std::stringstream ss; + for (auto& statItem : mStatistics) { + std::string boardType = (statItem.first < 0x10000) ? "Loc" : "Reg"; + double badFraction = (statItem.second[0] == 0) ? 0. : static_cast<double>(statItem.second[1]) / static_cast<double>(statItem.second[0]); + uint16_t boardId = (statItem.first & 0xFFFF); + ss << "Crate: " << static_cast<int>(raw::getCrateId(boardId)) << " " << boardType << " board: " << static_cast<int>(raw::getLocId(boardId)) << " fraction of events not in sync: " << statItem.second[1] << " / " << statItem.second[0] << " = " << badFraction << std::endl; + } + return ss.str(); +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/CMakeLists.txt b/Detectors/MUON/MID/Raw/CMakeLists.txt index 714fda4cd856c..97c124f1c37df 100644 --- a/Detectors/MUON/MID/Raw/CMakeLists.txt +++ b/Detectors/MUON/MID/Raw/CMakeLists.txt @@ -1,38 +1,41 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( MIDRaw SOURCES src/ColumnDataToLocalBoard.cxx src/CrateMapper.cxx src/CrateMasks.cxx + src/DecodedDataAggregator.cxx src/Decoder.cxx src/ElectronicsDelay.cxx + src/ELinkDataShaper.cxx src/ELinkDecoder.cxx + src/ELinkManager.cxx src/Encoder.cxx src/FEEIdConfig.cxx - src/GBTBareDecoder.cxx src/GBTOutputHandler.cxx - src/GBTUserLogicDecoder.cxx src/GBTUserLogicEncoder.cxx - src/LocalBoardRO.cxx - src/DecodedDataAggregator.cxx + src/LinkDecoder.cxx src/RawFileReader.cxx PUBLIC_LINK_LIBRARIES - ms_gsl::ms_gsl + Microsoft.GSL::GSL O2::DataFormatsMID O2::Headers O2::DPLUtils O2::CommonConstants O2::DetectorsRaw - O2::MIDBase) + O2::MIDBase + TARGETVARNAME midrawtarget) +# target_compile_definitions(${midrawtarget} PRIVATE "MID_RAW_VECTORS") add_subdirectory(exe) diff --git a/Detectors/MUON/MID/Raw/exe/CMakeLists.txt b/Detectors/MUON/MID/Raw/exe/CMakeLists.txt index cd2f0dabeda44..a53f14b809edb 100644 --- a/Detectors/MUON/MID/Raw/exe/CMakeLists.txt +++ b/Detectors/MUON/MID/Raw/exe/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_executable( rawdump diff --git a/Detectors/MUON/MID/Raw/exe/README.md b/Detectors/MUON/MID/Raw/exe/README.md index 1e9bad6ea0a9b..ef57c10dc16ce 100644 --- a/Detectors/MUON/MID/Raw/exe/README.md +++ b/Detectors/MUON/MID/Raw/exe/README.md @@ -15,7 +15,7 @@ o2-mid-rawdump filename [filename_2 filename_3 ...] The output is a file containing a list with: - the interaction record -- the list of decoded [LocalBoardRO](../include/MIDRaw/LocalBoardRO.h) +- the list of decoded [ROBoard](../include/DataFormatsMID/ROBoard.h) For a list of the other available options: ```bash o2-mid-rawdump --help diff --git a/Detectors/MUON/MID/Raw/exe/rawdump.cxx b/Detectors/MUON/MID/Raw/exe/rawdump.cxx index 3210b66b6c440..c539c9c03d092 100644 --- a/Detectors/MUON/MID/Raw/exe/rawdump.cxx +++ b/Detectors/MUON/MID/Raw/exe/rawdump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,47 +18,19 @@ #include "fmt/format.h" #include "boost/program_options.hpp" #include "DPLUtils/RawParser.h" -#include "MIDRaw/FEEIdConfig.h" #include "MIDRaw/Decoder.h" -#include "MIDRaw/GBTBareDecoder.h" -#include "MIDRaw/GBTUserLogicDecoder.h" #include "MIDRaw/RawFileReader.h" +#include "MIDRaw/Utils.h" namespace po = boost::program_options; -std::string getOutFilename(const char* inFilename, const char* outDir) -{ - std::string basename(inFilename); - std::string fdir = "./"; - auto pos = basename.find_last_of("/"); - if (pos != std::string::npos) { - basename.erase(0, pos + 1); - fdir = inFilename; - fdir.erase(pos); - } - basename.insert(0, "dump_"); - basename += ".txt"; - std::string outputDir(outDir); - if (outputDir.empty()) { - outputDir = fdir; - } - if (outputDir.back() != '/') { - outputDir += "/"; - } - std::string outFilename = outputDir + basename; - return outFilename; -} - -template <typename GBTDECODER, typename RDH> -void decode(o2::mid::Decoder<GBTDECODER>& decoder, gsl::span<const uint8_t> payload, const RDH& rdh, std::ostream& out) +template <class RDH> +void decode(o2::mid::Decoder& decoder, gsl::span<const uint8_t> payload, const RDH& rdh, std::ostream& out) { decoder.clear(); decoder.process(payload, rdh); - decoder.flush(); for (auto& rof : decoder.getROFRecords()) { - std::stringstream ss; - ss << std::hex << std::showbase << rof.interactionRecord; - out << ss.str() << std::endl; + out << fmt::format("BCid: 0x{:x} Orbit: 0x{:x} EvtType: {:d}", rof.interactionRecord.bc, rof.interactionRecord.orbit, rof.eventType) << std::endl; for (auto colIt = decoder.getData().begin() + rof.firstEntry; colIt != decoder.getData().begin() + rof.firstEntry + rof.nEntries; ++colIt) { out << *colIt << std::endl; } @@ -68,7 +41,7 @@ int main(int argc, char* argv[]) { po::variables_map vm; po::options_description generic("Generic options"); - std::string outFilename = "", feeIdConfigFilename = ""; + std::string outFilename = ""; unsigned long int nHBs = 0; unsigned long int firstHB = 0; @@ -80,8 +53,8 @@ int main(int argc, char* argv[]) ("nHBs", po::value<unsigned long int>(&nHBs),"Number of HBs read") ("rdh-only", po::value<bool>()->implicit_value(true),"Only show RDHs") ("decode", po::value<bool>()->implicit_value(true),"Decode output") - ("feeId-config-file", po::value<std::string>(&feeIdConfigFilename),"Filename with crate FEE ID correspondence") - ("bare", po::value<bool>()->implicit_value(true),"Bare decoder"); + ("feeId-config-file", po::value<std::string>()->default_value(""),"Filename with crate FEE ID correspondence") + ("electronics-delay-file", po::value<std::string>()->default_value(""),"Filename with electronics delay"); po::options_description hidden("hidden options"); @@ -110,21 +83,8 @@ int main(int argc, char* argv[]) std::vector<std::string> inputfiles{vm["input"].as<std::vector<std::string>>()}; - bool isBare = (vm.count("bare") > 0); - bool runDecoder = (vm.count("decode") > 0); - - o2::mid::Decoder<o2::mid::GBTUserLogicDecoder> ulDecoder; - o2::mid::Decoder<o2::mid::GBTBareDecoder> bareDecoder; - - if (runDecoder) { - if (!feeIdConfigFilename.empty()) { - o2::mid::FEEIdConfig feeIdConfig(feeIdConfigFilename.c_str()); - bareDecoder.setFeeIdConfig(feeIdConfig); - ulDecoder.setFeeIdConfig(feeIdConfig); - } - bareDecoder.init(true); - ulDecoder.init(true); - } + bool runDecoder = (vm.count("decode") > 0 && vm["decode"].as<bool>() == true); + std::unique_ptr<o2::mid::Decoder> decoder{nullptr}; std::ofstream outFile; std::ostream& out = (outFilename.empty()) ? std::cout : (outFile.open(outFilename), outFile); @@ -150,25 +110,30 @@ int main(int argc, char* argv[]) if (it.size() > 0) { gsl::span<const uint8_t> payload(it.data(), it.size()); if (runDecoder) { - if (isBare) { - decode(bareDecoder, payload, *rdhPtr, out); - } else { - decode(ulDecoder, payload, *rdhPtr, out); + if (!decoder) { + decoder = o2::mid::createDecoder(*rdhPtr, true, vm["electronics-delay-file"].as<std::string>().c_str(), "", vm["feeId-config-file"].as<std::string>().c_str()); } + decode(*decoder, payload, *rdhPtr, out); } else if (!isRdhOnly) { - for (size_t iword = 0; iword < payload.size(); iword += 16) { - auto word = payload.subspan(iword, 16); - for (auto it = word.rbegin(); it != word.rend(); ++it) { - auto ibInWord = word.rend() - it; - if (isBare) { + bool isBare = o2::mid::raw::isBare(*rdhPtr); + size_t wordLength = isBare ? 16 : 32; + for (size_t iword = 0; iword < payload.size(); iword += wordLength) { + auto word = payload.subspan(iword, wordLength); + if (isBare) { + for (auto it = word.rbegin(); it != word.rend(); ++it) { + auto ibInWord = word.rend() - it; if (ibInWord == 4 || ibInWord == 9) { out << " "; } if (ibInWord == 5 || ibInWord == 10) { out << " "; } + out << fmt::format("{:02x}", static_cast<int>(*it)); + } + } else { + for (auto it = word.begin(); it != word.end(); ++it) { + out << fmt::format("{:02x}", static_cast<int>(*it)); } - out << fmt::format("{:02x}", static_cast<int>(*it)); } out << "\n"; } diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/ColumnDataToLocalBoard.h b/Detectors/MUON/MID/Raw/include/MIDRaw/ColumnDataToLocalBoard.h index 2df9b6a7acf49..a1f4d4d4e5b81 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/ColumnDataToLocalBoard.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/ColumnDataToLocalBoard.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include "DataFormatsMID/ColumnData.h" #include "MIDBase/Mapping.h" #include "MIDRaw/CrateMapper.h" -#include "MIDRaw/LocalBoardRO.h" +#include "DataFormatsMID/ROBoard.h" namespace o2 { @@ -33,17 +34,17 @@ class ColumnDataToLocalBoard public: void process(gsl::span<const ColumnData> data); /// Gets the output data per GBT link - const std::unordered_map<uint16_t, std::vector<LocalBoardRO>> getData() { return mGBTMap; } + const std::unordered_map<uint16_t, std::vector<ROBoard>> getData() { return mGBTMap; } /// Sets debug mode void setDebugMode(bool debugMode = true) { mDebugMode = debugMode; } private: - bool keepBoard(const LocalBoardRO& loc) const; - std::unordered_map<uint8_t, LocalBoardRO> mLocalBoardsMap{}; /// Map of data per board - std::unordered_map<uint16_t, std::vector<LocalBoardRO>> mGBTMap{}; /// Map of data per GBT link - CrateMapper mCrateMapper{}; /// Crate mapper - Mapping mMapping{}; /// Segmentation - bool mDebugMode{false}; /// Debug mode (no zero suppression) + bool keepBoard(const ROBoard& loc) const; + std::unordered_map<uint8_t, ROBoard> mLocalBoardsMap{}; /// Map of data per board + std::unordered_map<uint16_t, std::vector<ROBoard>> mGBTMap{}; /// Map of data per GBT link + CrateMapper mCrateMapper{}; /// Crate mapper + Mapping mMapping{}; /// Segmentation + bool mDebugMode{false}; /// Debug mode (no zero suppression) }; } // namespace mid diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMapper.h b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMapper.h index dc6a8bda346f2..580702d0b20cb 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMapper.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMasks.h b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMasks.h index 0c94f6dfe7a6e..072bc092e21e5 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMasks.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateMasks.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateParameters.h b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateParameters.h index 2f5b88c3d4081..6e21716acf519 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/CrateParameters.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/CrateParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,24 +34,20 @@ static constexpr unsigned int sMaxNBoardsInLink = 8; static constexpr unsigned int sMaxNBoardsInCrate = sMaxNBoardsInLink * sNGBTsPerCrate; static constexpr unsigned int sNELinksPerGBT = 10; -/// Builds the RO ID from the crate ID and the GBT ID in the crate -inline uint16_t makeROId(uint8_t crateId, uint8_t gbtId) { return sNGBTsPerCrate * crateId + gbtId; } -/// Gets the crate ID from the RO ID -inline uint8_t getCrateIdFromROId(uint16_t roId) { return roId / sNGBTsPerCrate; } +/// Builds the GBT unique ID from the crate ID and the GBT ID in the crate +inline uint16_t makeGBTUniqueId(uint8_t crateId, uint8_t gbtId) { return sNGBTsPerCrate * crateId + gbtId; } +/// Gets the crate ID from the GBT unique ID +inline uint8_t getCrateIdFromGBTUniqueId(uint16_t gbtUniqueId) { return gbtUniqueId / sNGBTsPerCrate; } /// Gets the link ID in crate from the RO ID -inline uint8_t getGBTIdInCrate(uint16_t roId) { return roId % sNGBTsPerCrate; } +inline uint8_t getGBTIdInCrate(uint16_t gbtUniqueId) { return gbtUniqueId % sNGBTsPerCrate; } /// Gets the link ID in crate from the board ID inline uint8_t getGBTIdFromBoardInCrate(uint16_t locId) { return locId / sMaxNBoardsInLink; } /// Gets the absolute crate ID inline uint8_t getCrateId(bool isRightSide, uint8_t crateIdOneSide) { return isRightSide ? crateIdOneSide : crateIdOneSide + sNCratesPerSide; } +// Gets the locId in crate from the loc position in the GBT +inline uint8_t getLocIdInCrate(uint16_t gbtUniqueId, int iloc) { return getGBTIdInCrate(gbtUniqueId) * sMaxNBoardsInLink + iloc; } /// Tests if the crate is in the right side inline bool isRightSide(uint8_t crateId) { return (crateId / sNCratesPerSide) == 0; } -/// Builds the unique loc ID from the crate ID and the loc ID in the crate -inline uint8_t makeUniqueLocID(uint8_t crateId, uint8_t locId) { return locId | (crateId << 4); } -/// Gets the crate ID from the absolute local board ID -inline uint8_t getCrateId(uint8_t uniqueLocId) { return (uniqueLocId >> 4) & 0xF; } -/// Gets the loc ID in the crate from the unique local board ID -inline uint8_t getLocId(uint8_t uniqueLocId) { return uniqueLocId & 0xF; } } // namespace crateparams } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/DecodedDataAggregator.h b/Detectors/MUON/MID/Raw/include/MIDRaw/DecodedDataAggregator.h index 3a5776660c115..b4ca92d0b13c6 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/DecodedDataAggregator.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/DecodedDataAggregator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,9 @@ #include <map> #include <gsl/gsl> #include "DataFormatsMID/ColumnData.h" +#include "DataFormatsMID/ROBoard.h" #include "DataFormatsMID/ROFRecord.h" #include "MIDRaw/CrateMapper.h" -#include "MIDRaw/LocalBoardRO.h" namespace o2 { @@ -30,22 +31,23 @@ namespace mid class DecodedDataAggregator { public: - void process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords); + void process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords); /// Gets the vector of data - const std::vector<ColumnData>& getData() { return mData; } + const std::vector<ColumnData>& getData(EventType eventType = EventType::Standard) { return mData[static_cast<int>(eventType)]; } /// Gets the vector of data RO frame records - const std::vector<ROFRecord>& getROFRecords() { return mROFRecords; } + const std::vector<ROFRecord>& getROFRecords(EventType eventType = EventType::Standard) { return mROFRecords[static_cast<int>(eventType)]; } private: - void addData(const LocalBoardRO& col, size_t firstEntry); - ColumnData& FindColumnData(uint8_t deId, uint8_t columnId, size_t firstEntry); + void addData(const ROBoard& col, size_t firstEntry, size_t evtTypeIdx); + ColumnData& FindColumnData(uint8_t deId, uint8_t columnId, size_t firstEntry, size_t evtTypeIdx); - std::map<uint64_t, std::vector<size_t>> mOrderIndexes; /// Map for time ordering the entries - std::vector<ColumnData> mData{}; /// Vector of output column data - std::vector<ROFRecord> mROFRecords{}; /// Vector of ROF records - CrateMapper mCrateMapper; /// Mapper to convert the RO info to ColumnData + std::array<std::map<uint64_t, std::vector<size_t>>, 3> mEventIndexes{}; /// Event indexes + + std::array<std::vector<ColumnData>, 3> mData{}; /// Vector of output column data + std::array<std::vector<ROFRecord>, 3> mROFRecords{}; /// Vector of ROF records + CrateMapper mCrateMapper; /// Mapper to convert the RO info to ColumnData }; } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/Decoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/Decoder.h index e3312a6c5aab1..3bae82bcc93d9 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/Decoder.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/Decoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,10 @@ #define O2_MID_DECODER_H #include <cstdint> +#if !defined(MID_RAW_VECTORS) +#include <unordered_map> +#endif #include <vector> -#include <array> #include <gsl/gsl> #include "DataFormatsMID/ROFRecord.h" #include "DetectorsRaw/RDHUtils.h" @@ -25,57 +28,55 @@ #include "MIDRaw/CrateParameters.h" #include "MIDRaw/ElectronicsDelay.h" #include "MIDRaw/FEEIdConfig.h" -#include "MIDRaw/GBTBareDecoder.h" -#include "MIDRaw/GBTUserLogicDecoder.h" -#include "MIDRaw/LocalBoardRO.h" +#include "MIDRaw/LinkDecoder.h" +#include "MIDRaw/Utils.h" +#include "DataFormatsMID/ROBoard.h" namespace o2 { namespace mid { -template <typename GBTDECODER> class Decoder { public: - Decoder(); - ~Decoder() = default; - /// Sets the FEE ID config file - void setFeeIdConfig(const FEEIdConfig& feeIdConfig) { mFEEIdConfig = feeIdConfig; } - /// Sets the crate masks - void setCrateMasks(const CrateMasks& masks) { mMasks = masks; } - /// Sets the electronics delays - void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mElectronicsDelay = electronicsDelay; } - void init(bool isDebugMode = false); + Decoder(bool isDebugMode = false, bool isBare = false, const ElectronicsDelay& electronicsDelay = ElectronicsDelay(), const CrateMasks& crateMasks = CrateMasks(), const FEEIdConfig& feeIdConfig = FEEIdConfig()); + virtual ~Decoder() = default; void process(gsl::span<const uint8_t> bytes); - template <typename RDH = o2::header::RAWDataHeader> + template <class RDH> void process(gsl::span<const uint8_t> payload, const RDH& rdh) { /// Processes the page - uint16_t feeId = mFEEIdConfig.getFeeId(o2::raw::RDHUtils::getLinkID(rdh), o2::raw::RDHUtils::getEndPointID(rdh), o2::raw::RDHUtils::getCRUID(rdh)); - mGBTDecoders[feeId].process(payload, o2::raw::RDHUtils::getHeartBeatBC(rdh), o2::raw::RDHUtils::getHeartBeatOrbit(rdh), o2::raw::RDHUtils::getPageCounter(rdh)); + auto feeId = o2::raw::RDHUtils::getFEEID(rdh); +#if defined(MID_RAW_VECTORS) + mLinkDecoders[feeId]->process(payload, o2::raw::RDHUtils::getHeartBeatOrbit(rdh), mData, mROFRecords); +#else + mLinkDecoders.find(feeId)->second->process(payload, o2::raw::RDHUtils::getHeartBeatOrbit(rdh), mData, mROFRecords); +#endif } /// Gets the vector of data - const std::vector<LocalBoardRO>& getData() const { return mData; } + const std::vector<ROBoard>& getData() const { return mData; } /// Gets the vector of data RO frame records const std::vector<ROFRecord>& getROFRecords() const { return mROFRecords; } - void flush(); - void clear(); - bool isComplete() const; + protected: +#if defined(MID_RAW_VECTORS) + std::vector<std::unique_ptr<LinkDecoder>> mLinkDecoders{}; /// GBT decoders +#else + std::unordered_map<uint16_t, std::unique_ptr<LinkDecoder>> mLinkDecoders{}; /// GBT decoders +#endif private: - std::vector<LocalBoardRO> mData{}; /// Vector of output data - std::vector<ROFRecord> mROFRecords{}; /// List of ROF records - std::array<GBTDECODER, crateparams::sNGBTs> mGBTDecoders{}; /// GBT decoders - FEEIdConfig mFEEIdConfig{}; /// Crate FEEID mapper - CrateMasks mMasks{}; /// Crate masks - ElectronicsDelay mElectronicsDelay{}; /// Delay in the electronics + std::vector<ROBoard> mData{}; /// Vector of output data + std::vector<ROFRecord> mROFRecords{}; /// List of ROF records }; +std::unique_ptr<Decoder> createDecoder(const o2::header::RDHAny& rdh, bool isDebugMode, const ElectronicsDelay& electronicsDelay, const CrateMasks& crateMasks, const FEEIdConfig& feeIdConfig); +std::unique_ptr<Decoder> createDecoder(const o2::header::RDHAny& rdh, bool isDebugMode, const char* electronicsDelayFile = "", const char* crateMasksFile = "", const char* feeIdConfigFile = ""); + } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDataShaper.h b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDataShaper.h new file mode 100644 index 0000000000000..037a85f364425 --- /dev/null +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDataShaper.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDRaw/ELinkDataShaper.h +/// \brief Properly formats and sets the absolute timestamp of the raw data +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 18 March 2021 +#ifndef O2_MID_ELINKDATASHAPER_H +#define O2_MID_ELINKDATASHAPER_H + +#include <cstdint> +#include <vector> +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMID/ROBoard.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/ELinkDecoder.h" + +namespace o2 +{ +namespace mid +{ +class ELinkDataShaper +{ + public: + ELinkDataShaper(bool isDebugMode, bool isLoc, uint8_t uniqueId, const ElectronicsDelay& electronicsDelay); + /// Main function to be executed when decoding is done + inline void onDone(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) { std::invoke(mOnDone, this, decoder, data, rofs); } + + void set(uint32_t orbit); + + private: + uint8_t mUniqueId{0}; /// UniqueId + ElectronicsDelay mElectronicsDelay{}; /// Delays in the electronics + uint32_t mRDHOrbit{0}; /// RDH orbit + bool mReceivedCalibration{false}; /// Flag to indicate if the calibration trigger was received + + InteractionRecord mIR{}; /// Interaction record + uint16_t mExpectedFETClock{}; /// Expected FET clock + uint16_t mLastClock{}; /// Last clock + + typedef void (ELinkDataShaper::*OnDoneFunction)(const ELinkDecoder&, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + OnDoneFunction mOnDone{&ELinkDataShaper::onDoneLoc}; ///! Processes the board + + void onDoneLoc(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + void onDoneLocDebug(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + void onDoneReg(const ELinkDecoder&, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs){}; /// Dummy function + void onDoneRegDebug(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + + void addLoc(const ELinkDecoder& decoder, EventType eventType, InteractionRecord ir, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + bool checkLoc(const ELinkDecoder& decoder); + EventType processCalibrationTrigger(uint16_t localClock); + void processOrbitTrigger(uint16_t localClock, uint8_t triggerWord); + EventType processSelfTriggered(uint16_t localClock, InteractionRecord& ir); + bool processTrigger(const ELinkDecoder& decoder, EventType& eventType, InteractionRecord& ir); +}; +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_ELINKDATASHAPER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDecoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDecoder.h index 6d2a081635990..3fce2b1e61822 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDecoder.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,9 @@ #include <cstdint> #include <vector> +#include <gsl/gsl> + +#include "DataFormatsMID/ROBoard.h" namespace o2 { @@ -25,34 +29,84 @@ namespace mid class ELinkDecoder { public: - void add(const uint8_t byte); - bool add(const uint8_t byte, uint8_t expectedStart); + void setBareDecoder(bool isBare); + /// Adds a byte + inline void add(const uint8_t byte) { mBytes.emplace_back(byte); } + void addAndComputeSize(const uint8_t byte); + template <class ITERATOR> + bool addCore(ITERATOR& it, const ITERATOR& end) + { + /// Adds the first 5 bytes + auto remaining = mMinimumSize - mBytes.size(); + return add(it, end, remaining); + } + template <class ITERATOR> + bool add(ITERATOR& it, const ITERATOR& end) + { + /// Adds the board bytes + auto remaining = mTotalSize - mBytes.size(); + if (add(it, end, remaining)) { + if (mTotalSize == mMinimumSize) { + computeSize(); + remaining = mTotalSize - mBytes.size(); + if (remaining) { + return add(it, end, remaining); + } + } + return true; + } + return false; + } + + /// Adds the first 5 bytes + inline bool addCore(size_t& idx, gsl::span<const uint8_t> payload, size_t step) { return add(idx, payload, mMinimumSize - mBytes.size(), step); } + + bool add(size_t& idx, gsl::span<const uint8_t> payload, size_t step); + + /// Checks if this is a zero + inline bool isZero(uint8_t byte) const { return (mBytes.empty() && (byte & raw::sSTARTBIT) == 0); } + /// Checks if we have all of the information needed for the decoding - bool isComplete() const { return mBytes.size() == mTotalSize; }; + inline bool isComplete() const { return mBytes.size() == mTotalSize; }; /// Gets the status word - uint8_t getStatusWord() const { return mBytes[0]; } + inline uint8_t getStatusWord() const { return mBytes[0]; } /// Gets the trigger word - uint8_t getTriggerWord() const { return mBytes[1]; } + inline uint8_t getTriggerWord() const { return mBytes[1]; } /// Gets the counter - uint16_t getCounter() const { return joinBytes(2); } - // uint16_t getCounter() const { return (mBytes[2] << 8) | mBytes[3]; } + inline uint16_t getCounter() const { return joinBytes(2); } /// Gets the card ID - uint8_t getId() const { return (mBytes[4] >> 4) & 0xF; } + inline uint8_t getId() const { return (mBytes[4] >> 4) & 0xF; } /// Gets the inputs - uint8_t getInputs() const { return (mBytes[4] & 0xF); } + inline uint8_t getInputs() const { return (mBytes[4] & 0xF); } + /// Gets the crate ID when available + inline uint8_t getCrateId() const { return (mBytes[5] >> 4) & 0xF; } uint16_t getPattern(int cathode, int chamber) const; /// Gets the number of bytes read - size_t getNBytes() const { return mBytes.size(); } + inline size_t getNBytes() const { return mBytes.size(); } void reset(); private: inline uint16_t joinBytes(int idx) const { return (mBytes[idx] << 8 | mBytes[idx + 1]); }; + template <class ITERATOR> + bool add(ITERATOR& it, const ITERATOR& end, size_t nBytes) + { + /// Fills inner bytes vector + auto nToEnd = std::distance(it, end); + auto nAdded = nBytes < nToEnd ? nBytes : nToEnd; + mBytes.insert(mBytes.end(), it, it + nAdded); + it += nAdded; + return (nAdded == nBytes); + } + + bool add(size_t& idx, gsl::span<const uint8_t> payload, size_t nBytes, size_t step); + + void computeSize(); - static constexpr size_t sMinimumSize{5}; /// Minimum size of the buffer - static constexpr size_t sMaximumSize{21}; /// Maximum size of the buffer - std::vector<uint8_t> mBytes{}; /// Vector with encoded information - size_t mTotalSize{sMinimumSize}; /// Expected size of the read-out buffer + size_t mMinimumSize{5}; /// Minimum size of the buffer + size_t mMaximumSize{21}; /// Maximum size of the buffer + std::vector<uint8_t> mBytes{}; /// Vector with encoded information + size_t mTotalSize{mMinimumSize}; /// Expected size of the read-out buffer }; } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkManager.h b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkManager.h new file mode 100644 index 0000000000000..b7e4315b6bfb7 --- /dev/null +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/ELinkManager.h @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDRaw/ELinkManager.h +/// \brief MID e-link data shaper manager +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 18 March 2021 +#ifndef O2_MID_ELINKMANAGER_H +#define O2_MID_ELINKMANAGER_H + +#include <cstdint> +#if defined(MID_RAW_VECTORS) +#include <vector> +#else +#include <unordered_map> +#endif +#include "MIDRaw/ELinkDataShaper.h" +#include "MIDRaw/ELinkDecoder.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/FEEIdConfig.h" + +namespace o2 +{ +namespace mid +{ +class ELinkManager +{ + public: + void init(uint16_t feeId, bool isDebugMode, bool isBare = false, const ElectronicsDelay& electronicsDelay = ElectronicsDelay(), const FEEIdConfig& feeIdConfig = FEEIdConfig()); + + void set(uint32_t orbit); + + /// Main function to be executed when decoding is done + inline void onDone(const ELinkDecoder& decoder, uint8_t boardUniqueId, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) { return onDone(decoder, raw::getCrateId(boardUniqueId), raw::getLocId(boardUniqueId), data, rofs); } + + /// Main function to be executed when decoding is done + inline void onDone(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) { return onDone(decoder, decoder.getCrateId(), decoder.getId(), data, rofs); } + +#if defined(MID_RAW_VECTORS) + /// Returns the decoder + inline ELinkDecoder& getDecoder(uint8_t boardUniqueId, bool isLoc) { return mDecoders[mIndex(raw::getCrateId(boardUniqueId), raw::getLocId(boardUniqueId), isLoc)]; } + + /// Main function to be executed when decoding is done + inline void onDone(const ELinkDecoder& decoder, uint8_t crateId, uint8_t locId, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + return mDataShapers[mIndex(crateId, locId, raw::isLoc(decoder.getStatusWord()))].onDone(decoder, data, rofs); + } + + private: + std::function<size_t(uint8_t, uint8_t, bool)> mIndex{}; ///! Function that returns the index in the vector + std::vector<ELinkDataShaper> mDataShapers; /// Vector with data shapers for each loc and reg board + std::vector<ELinkDecoder> mDecoders; /// Vector with decoders for each loc and reg board + +#else + /// Returns the decoder + inline ELinkDecoder& getDecoder(uint8_t boardUniqueId, bool isLoc) { return mDecoders.find(makeUniqueId(isLoc, boardUniqueId))->second; } + + /// Main function to be executed when decoding is done + void onDone(const ELinkDecoder& decoder, uint8_t crateId, uint8_t locId, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + + private: + /// Makes a ID which is unique for local and regional board + inline uint16_t makeUniqueId(bool isLoc, uint8_t uniqueId) { return (isLoc ? 0 : (1 << 8)) | uniqueId; } + std::unordered_map<uint16_t, ELinkDataShaper> mDataShapers; /// Data shapers for each loc and reg board + std::unordered_map<uint16_t, ELinkDecoder> mDecoders; /// Decoders for each loc and reg board + +#endif +}; +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_ELINKMANAGER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/ElectronicsDelay.h b/Detectors/MUON/MID/Raw/include/MIDRaw/ElectronicsDelay.h index a689ed2a6d033..bb5adf244994f 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/ElectronicsDelay.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/ElectronicsDelay.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/Encoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/Encoder.h index 871b12546a0d2..b894f3913b06c 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/Encoder.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/Encoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include <cstdint> #include <array> #include <map> +#include <string_view> #include <vector> #include <gsl/gsl> #include "CommonDataFormat/InteractionRecord.h" @@ -27,7 +29,7 @@ #include "MIDRaw/CrateParameters.h" #include "MIDRaw/FEEIdConfig.h" #include "MIDRaw/GBTUserLogicEncoder.h" -#include "MIDRaw/LocalBoardRO.h" +#include "DataFormatsMID/ROBoard.h" class RDHAny; @@ -38,7 +40,7 @@ namespace mid class Encoder { public: - void init(const char* filename, bool perLink = false, int verbosity = 0, bool debugMode = false); + void init(std::string_view outDir = ".", std::string_view fileFor = "all", int verbosity = 0, bool debugMode = false); void process(gsl::span<const ColumnData> data, const InteractionRecord& ir, EventType eventType = EventType::Standard); /// Sets the maximum size of the superpage void setSuperpageSize(int maxSize) { mRawWriter.setSuperPageSize(maxSize); } @@ -51,22 +53,22 @@ class Encoder private: void completeWord(std::vector<char>& buffer); - void writePayload(uint16_t feeId, const InteractionRecord& ir); + void writePayload(uint16_t linkId, const InteractionRecord& ir); void onOrbitChange(uint32_t orbit); - // Returns the interaction record expected for the orbit trigger + /// Returns the interaction record expected for the orbit trigger inline InteractionRecord getOrbitIR(uint32_t orbit) const { return {o2::constants::lhc::LHCMaxBunches - 1, orbit}; } o2::raw::RawFileWriter mRawWriter{o2::header::gDataOriginMID}; /// Raw file writer - std::map<uint16_t, LocalBoardRO> mROData{}; /// Map of data per board - ColumnDataToLocalBoard mConverter{}; /// ColumnData to LocalBoardRO converter - FEEIdConfig mFEEIdConfig{}; /// Crate FEEId mapper - InteractionRecord mLastIR{}; /// Last interaction record + std::map<uint16_t, ROBoard> mROData{}; /// Map of data per board + ColumnDataToLocalBoard mConverter{}; /// ColumnData to ROBoard converter + FEEIdConfig mFEEIdConfig{}; /// Crate FEEId mapper + InteractionRecord mLastIR{}; /// Last interaction record - std::array<GBTUserLogicEncoder, crateparams::sNGBTs> mGBTEncoders{}; /// Array of encoders per link - std::array<std::vector<char>, crateparams::sNGBTs> mOrbitResponse{}; /// Response to orbit trigger - std::array<std::vector<char>, crateparams::sNGBTs> mOrbitResponseWord{}; /// CRU word for response to orbit trigger - std::array<uint32_t, crateparams::sNGBTs> mGBTIds{}; /// Array of GBT Ids + std::array<uint32_t, crateparams::sNGBTs> mGBTIds{}; /// Array of GBT Ids + std::array<GBTUserLogicEncoder, crateparams::sNGBTs> mGBTEncoders{}; /// Array of encoders per link + std::array<std::vector<char>, 4> mOrbitResponse{}; /// Response to orbit trigger + std::array<std::vector<char>, 4> mOrbitResponseWord{}; /// CRU word for response to orbit trigger }; } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/FEEIdConfig.h b/Detectors/MUON/MID/Raw/include/MIDRaw/FEEIdConfig.h index efb24922d6753..29a8dd946fb49 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/FEEIdConfig.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/FEEIdConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,32 +31,40 @@ class FEEIdConfig FEEIdConfig(const char* filename); ~FEEIdConfig() = default; - uint16_t getFeeId(uint32_t uniqueId) const; + uint16_t getGBTUniqueId(uint32_t linkUniqueId) const; - /// Gets the FEE ID from the physical ID of the link - uint16_t getFeeId(uint8_t linkId, uint8_t endPointId, uint16_t cruId) const { return getFeeId(getGBTId(linkId, endPointId, cruId)); } + inline const std::vector<uint16_t>& getGBTUniqueIdsInLink(uint16_t feeId) const { return mGBTUniqueIdsInLink.find(feeId)->second; } + + /// Gets the GBT unique ID from the physical ID of the link + uint16_t getGBTUniqueId(uint8_t linkId, uint8_t endPointId, uint16_t cruId) const { return getGBTUniqueId(getLinkUniqueId(linkId, endPointId, cruId)); } /// Gets a uniqueID from the combination of linkId, endPointId and cruId; - inline uint32_t getGBTId(uint8_t linkId, uint8_t endPointId, uint16_t cruId) const { return (linkId + 1) << ((endPointId == 1) ? 8U : 0U) | (cruId << 16U); } + inline uint32_t getLinkUniqueId(uint8_t linkId, uint8_t endPointId, uint16_t cruId) const { return (linkId + 1) << ((endPointId == 1) ? 8U : 0U) | (cruId << 16U); } /// Gets the CRU ID - inline uint16_t getCRUId(uint32_t gbtId) const { return gbtId >> 16; } + inline uint16_t getCRUId(uint32_t linkUniqueId) const { return linkUniqueId >> 16; } /// Gets the end point id - inline uint8_t getEndPointId(uint32_t gbtId) const { return (gbtId & 0xFF00) ? 1 : 0; } + inline uint8_t getEndPointId(uint32_t linkUniqueId) const { return (linkUniqueId & 0xFF00) ? 1 : 0; } /// Gets the Link ID - inline uint8_t getLinkId(uint32_t gbtId) const { return ((gbtId >> (8U * getEndPointId(gbtId))) & 0xFF) - 1; } + inline uint8_t getLinkId(uint32_t linkUniqueId) const { return ((linkUniqueId >> (8U * getEndPointId(linkUniqueId))) & 0xFF) - 1; } + /// Gets the FEE ID from the GBT unique ID + uint16_t getFEEId(uint16_t gbtUniqueId) const; - std::vector<uint16_t> getConfiguredFeeIds() const; - std::vector<uint32_t> getConfiguredGBTIds() const; + std::vector<uint16_t> getConfiguredGBTUniqueIDs() const; + std::vector<uint32_t> getConfiguredLinkUniqueIDs() const; + std::vector<uint16_t> getConfiguredFEEIDs() const; void write(const char* filename) const; private: bool load(const char* filename); + void add(uint16_t gbtUniqueId, uint8_t linkId, uint8_t epId, uint16_t cruId, uint16_t feeId); + void add(uint16_t gbtUniqueId, uint8_t linkId, uint8_t epId, uint16_t cruId); - std::unordered_map<uint32_t, uint16_t> mGBTIdToFeeId; /// Correspondence between GBT Id and FeeId + std::unordered_map<uint32_t, uint16_t> mLinkUniqueIdToGBTUniqueId{}; /// Correspondence between link unique ID and GBT unique Id + std::unordered_map<uint16_t, uint16_t> mGBTUniqueIdToFeeId{}; /// Correspondence between GBT unique ID and FEE ID + std::unordered_map<uint16_t, std::vector<uint16_t>> mGBTUniqueIdsInLink{}; /// Input GBT links in output link }; - } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTBareDecoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTBareDecoder.h deleted file mode 100644 index b53a2701a091e..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTBareDecoder.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MIDRaw/GBTBareDecoder.h -/// \brief MID GBT decoder without user logic -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 12 March 2020 -#ifndef O2_MID_GBTBAREDECODER_H -#define O2_MID_GBTBAREDECODER_H - -#include <cstdint> -#include <array> -#include <vector> -#include <gsl/gsl> -#include "DataFormatsMID/ROFRecord.h" -#include "MIDRaw/CrateParameters.h" -#include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/ELinkDecoder.h" -#include "MIDRaw/GBTOutputHandler.h" -#include "MIDRaw/LocalBoardRO.h" - -namespace o2 -{ -namespace mid -{ -class GBTBareDecoder -{ - public: - void init(uint16_t feeId, uint8_t mask, bool isDebugMode = false); - void process(gsl::span<const uint8_t> bytes, uint16_t bc, uint32_t orbit, uint16_t pageCnt); - /// Gets the vector of data - const std::vector<LocalBoardRO>& getData() const { return mOutputHandler.getData(); } - - /// Gets the vector of data RO frame records - const std::vector<ROFRecord>& getROFRecords() const { return mOutputHandler.getROFRecords(); } - - bool isComplete() const; - - /// Clears the decoded data - void clear() { mOutputHandler.clear(); } - - /// Sets the delay in the electronics - void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mOutputHandler.setElectronicsDelay(electronicsDelay); } - - private: - GBTOutputHandler mOutputHandler{}; /// GBT output handler - uint8_t mMask{0xFF}; /// GBT mask - uint16_t mIsFeeding{0}; /// Flag to check if the e-link is feeding - - std::array<ELinkDecoder, crateparams::sNELinksPerGBT> mELinkDecoders{}; /// E-link decoders - - // Here we are using a function pointer instead of a std::function because it is faster. - // The std::function adds an overhead at each function call, - // which results in a considerable slowing done of the code if the function is executed often - typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); - typedef void (GBTBareDecoder::*ProcessFunction)(size_t, uint8_t); - - OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board - ProcessFunction mProcessReg{&GBTBareDecoder::processReg}; ///! Processes the regional board - - void processLoc(size_t ilink, uint8_t byte); - void processReg(size_t, uint8_t){}; /// Dummy function. We usually do not process the regional cards, except when we are debugging the code - void processRegDebug(size_t ilink, uint8_t byte); -}; -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_GBTBAREDECODER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTOutputHandler.h b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTOutputHandler.h index e153da3e91536..49cb470fc0dae 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTOutputHandler.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTOutputHandler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ #include "MIDRaw/CrateParameters.h" #include "MIDRaw/ElectronicsDelay.h" #include "MIDRaw/ELinkDecoder.h" -#include "MIDRaw/LocalBoardRO.h" +#include "DataFormatsMID/ROBoard.h" namespace o2 { @@ -33,9 +34,9 @@ class GBTOutputHandler { public: /// Sets the FEE Id - void setFeeId(uint16_t feeId) { mFeeId = feeId; } + void setGBTUniqueId(uint16_t feeId) { mFeeId = feeId; } - void setIR(uint16_t bc, uint32_t orbit, int pageCnt); + void set(uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); void onDoneLoc(size_t ilink, const ELinkDecoder& decoder); void onDoneLocDebug(size_t ilink, const ELinkDecoder& decoder); @@ -45,21 +46,13 @@ class GBTOutputHandler /// Sets the delay in the electronics void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mElectronicsDelay = electronicsDelay; } - /// Gets the vector of data - const std::vector<LocalBoardRO>& getData() const { return mData; } - - /// Gets the vector of data RO frame records - const std::vector<ROFRecord>& getROFRecords() const { return mROFRecords; } - - void clear(); - private: - std::vector<LocalBoardRO> mData{}; /// Vector of output data - std::vector<ROFRecord> mROFRecords{}; /// List of ROF records - uint16_t mFeeId{0}; /// FEE ID - InteractionRecord mIRFirstPage{}; /// Interaction record of the first page - uint16_t mReceivedCalibration{0}; /// Word with one bit per e-link indicating if the calibration trigger was received by the e-link - ElectronicsDelay mElectronicsDelay{}; /// Delays in the electronics + std::vector<ROBoard>* mData{nullptr}; ///! Vector of output data. Not owner + std::vector<ROFRecord>* mROFRecords{nullptr}; /// List of ROF records. Not owner + uint16_t mFeeId{0}; /// FEE ID + uint32_t mOrbit{}; /// RDH orbit + uint16_t mReceivedCalibration{0}; /// Word with one bit per e-link indicating if the calibration trigger was received by the e-link + ElectronicsDelay mElectronicsDelay{}; /// Delays in the electronics std::array<InteractionRecord, crateparams::sNELinksPerGBT> mIRs{}; /// Interaction records per link std::array<uint16_t, crateparams::sNELinksPerGBT> mExpectedFETClock{}; /// Expected FET clock diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicDecoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicDecoder.h deleted file mode 100644 index 8899c0176600d..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicDecoder.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MIDRaw/GBTUserLogicDecoder.h -/// \brief MID GBT decoder with user logic zero suppression -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 15 April 2020 -#ifndef O2_MID_GBTUSERLOGICDECODER_H -#define O2_MID_GBTUSERLOGICDECODER_H - -#include <cstdint> -#include <vector> -#include <gsl/gsl> -#include "DetectorsRaw/RDHUtils.h" -#include "DataFormatsMID/ROFRecord.h" -#include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/ELinkDecoder.h" -#include "MIDRaw/GBTOutputHandler.h" -#include "MIDRaw/LocalBoardRO.h" - -namespace o2 -{ -namespace mid -{ -class GBTUserLogicDecoder -{ - public: - void init(uint16_t feeId, bool isDebugMode = false); - void process(gsl::span<const uint8_t> bytes, uint16_t bc, uint32_t orbit, uint16_t pageCnt); - template <typename RDH> - void process(gsl::span<const uint8_t> bytes, const RDH& rdh) - { - process(bytes, o2::raw::RDHUtils::getHeartBeatBC(rdh), o2::raw::RDHUtils::getHeartBeatOrbit(rdh), o2::raw::RDHUtils::getPageCounter(rdh)); - } - /// Gets the vector of data - const std::vector<LocalBoardRO>& getData() const { return mOutputHandler.getData(); } - - /// Gets the vector of data RO frame records - const std::vector<ROFRecord>& getROFRecords() const { return mOutputHandler.getROFRecords(); } - - /// Checks that the link has finished reading - bool isComplete() const { return mELinkDecoder.isComplete(); } - - /// Clears the decoded data - void clear() { mOutputHandler.clear(); } - - /// Sets the delay in the electronics - void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mOutputHandler.setElectronicsDelay(electronicsDelay); } - - private: - GBTOutputHandler mOutputHandler{}; /// GBT output handler - - ELinkDecoder mELinkDecoder{}; /// E-link decoder - - typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); - - OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board - OnDoneFunction mOnDoneReg{&GBTOutputHandler::onDoneReg}; ///! Processes the regional board -}; -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_GBTUSERLOGICDECODER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicEncoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicEncoder.h index aee2f00a2a278..51f6cc7ffc117 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicEncoder.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/GBTUserLogicEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsMID/ROFRecord.h" #include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/LocalBoardRO.h" +#include "DataFormatsMID/ROBoard.h" namespace o2 { @@ -30,7 +31,7 @@ namespace mid class GBTUserLogicEncoder { public: - void process(gsl::span<const LocalBoardRO> data, const InteractionRecord& ir); + void process(gsl::span<const ROBoard> data, InteractionRecord ir); void processTrigger(const InteractionRecord& ir, uint8_t triggerWord); void flush(std::vector<char>& buffer, const InteractionRecord& ir); @@ -41,8 +42,7 @@ class GBTUserLogicEncoder /// Sets the mask void setMask(uint8_t mask) { mMask = mask; } - /// Sets the feeID - void setFeeId(uint16_t feeId) { mFeeId = feeId; } + void setGBTUniqueId(uint16_t gbtUniqueId); /// Sets the delay in the electronics void setElectronicsDelay(const ElectronicsDelay& electronicsDelay) { mElectronicsDelay = electronicsDelay; } @@ -51,10 +51,11 @@ class GBTUserLogicEncoder void addRegionalBoards(uint8_t activeBoards, InteractionRecord ir); void addShort(std::vector<char>& buffer, uint16_t shortWord) const; - std::map<InteractionRecord, std::vector<LocalBoardRO>> mBoards{}; /// Vector with boards - uint16_t mFeeId{0}; /// FEE ID - uint8_t mMask{0xFF}; /// GBT mask - ElectronicsDelay mElectronicsDelay; /// Delays in the electronics + std::map<InteractionRecord, std::vector<ROBoard>> mBoards{}; /// Vector with boards + uint8_t mCrateId{0}; /// Crate ID + uint8_t mOffset{0}; /// GBT ID offset + uint8_t mMask{0xFF}; /// GBT mask + ElectronicsDelay mElectronicsDelay; /// Delays in the electronics }; } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/LinkDecoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/LinkDecoder.h new file mode 100644 index 0000000000000..8df566f96215a --- /dev/null +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/LinkDecoder.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDRaw/LinkDecoder.h +/// \brief Class interface for the MID link decoder +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 07 November 2020 +#ifndef O2_MID_LINKDECODER_H +#define O2_MID_LINKDECODER_H + +#include <cstdint> +#include <vector> +#include <gsl/gsl> +#include "DetectorsRaw/RDHUtils.h" +#include "Headers/RAWDataHeader.h" +#include "DataFormatsMID/ROBoard.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/FEEIdConfig.h" + +namespace o2 +{ +namespace mid +{ + +class LinkDecoder +{ + public: + LinkDecoder(std::function<void(gsl::span<const uint8_t>, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs)> decode) : mDecode(decode) {} + void process(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs); + + template <class RDH> + void process(gsl::span<const uint8_t> payload, const RDH& rdh, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + process(payload, o2::raw::RDHUtils::getHeartBeatOrbit(rdh), data, rofs); + } + + protected: + std::function<void(gsl::span<const uint8_t>, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs)> mDecode{nullptr}; +}; + +std::unique_ptr<LinkDecoder> createGBTDecoder(const o2::header::RDHAny& rdh, uint16_t feeId, bool isDebugMode, uint8_t mask, const ElectronicsDelay& electronicsDelay); + +std::unique_ptr<LinkDecoder> createLinkDecoder(const o2::header::RDHAny& rdh, uint16_t feeId, bool isDebugMode, uint8_t mask, const ElectronicsDelay& electronicsDelay, const FEEIdConfig& feeIdConfig); +std::unique_ptr<LinkDecoder> createLinkDecoder(uint16_t feeId, bool isBare = false, bool isDebugMode = false, uint8_t mask = 0xFF, const ElectronicsDelay& electronicsDelay = ElectronicsDelay(), const FEEIdConfig& feeIdConfig = FEEIdConfig()); + +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_LINKDECODER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/LocalBoardRO.h b/Detectors/MUON/MID/Raw/include/MIDRaw/LocalBoardRO.h deleted file mode 100644 index 335e5734adb01..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/LocalBoardRO.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MIDRaw/LocalBoardRO.h -/// \brief Structure to store the FEE local board information -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 19 November 2019 -#ifndef O2_MID_LocalBoardRO_H -#define O2_MID_LocalBoardRO_H - -#include <cstdint> -#include <array> -#include <iosfwd> - -namespace o2 -{ -namespace mid -{ -struct LocalBoardRO { - uint8_t statusWord{0}; /// Status word - uint8_t triggerWord{0}; /// Trigger word - uint8_t boardId{0}; /// Board ID in crate - uint8_t firedChambers{0}; /// Fired chambers - std::array<uint16_t, 4> patternsBP{}; /// Bending plane pattern - std::array<uint16_t, 4> patternsNBP{}; /// Non-bending plane pattern -}; - -std::ostream& operator<<(std::ostream& os, const LocalBoardRO& loc); - -namespace raw -{ -static constexpr uint32_t sSTARTBIT = 1 << 7; -static constexpr uint32_t sCARDTYPE = 1 << 6; -static constexpr uint32_t sLOCALBUSY = 1 << 5; -static constexpr uint32_t sLOCALDECISION = 1 << 4; -static constexpr uint32_t sACTIVE = 1 << 3; -static constexpr uint32_t sREJECTING = 1 << 2; -static constexpr uint32_t sMASKED = 1 << 1; -static constexpr uint32_t sOVERWRITTEN = 1; - -static constexpr uint32_t sSOX = 1 << 7; -static constexpr uint32_t sEOX = 1 << 6; -static constexpr uint32_t sPAUSE = 1 << 5; -static constexpr uint32_t sRESUME = 1 << 4; -static constexpr uint32_t sCALIBRATE = 1 << 3; -static constexpr uint32_t sPHY = 1 << 2; -static constexpr uint32_t sRESET = 1 << 1; -static constexpr uint32_t sORB = 1; - -/// Tests the local card bit -inline bool isLoc(uint8_t statusWord) { return (statusWord >> 6) & 0x1; } -/// Tests the calibration bit of the card -inline bool isCalibration(uint8_t triggerWord) { return ((triggerWord & 0xc) == 0x8); } -/// Tests if this is a Front End Test event -inline bool isFET(uint8_t triggerWord) { return ((triggerWord & 0xc) == 0xc); } -} // namespace raw - -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_LocalBoardRO_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h b/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h index 0df1da74bc6c8..9e61d2176141f 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/Utils.h b/Detectors/MUON/MID/Raw/include/MIDRaw/Utils.h new file mode 100644 index 0000000000000..5c79e2ca4bd48 --- /dev/null +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/Utils.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDRaw/Utils.h +/// \brief Raw data utilities for MID +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 19 November 2019 +#ifndef O2_MID_UTILS_H +#define O2_MID_UTILS_H + +#include "Headers/RDHAny.h" +#include "DetectorsRaw/RDHUtils.h" + +namespace o2 +{ +namespace mid +{ +namespace raw +{ +static constexpr uint8_t sUserLogicLinkID = 15; // Link ID for the user logic + +/// Test if the data comes from the common logic +inline bool isBare(const o2::header::RDHAny& rdh) { return (o2::raw::RDHUtils::getLinkID(rdh) != sUserLogicLinkID); } + +} // namespace raw +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_UTILS_H */ diff --git a/Detectors/MUON/MID/Raw/src/ColumnDataToLocalBoard.cxx b/Detectors/MUON/MID/Raw/src/ColumnDataToLocalBoard.cxx index 539f65542d0e5..b1b22504dc84a 100644 --- a/Detectors/MUON/MID/Raw/src/ColumnDataToLocalBoard.cxx +++ b/Detectors/MUON/MID/Raw/src/ColumnDataToLocalBoard.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ namespace o2 namespace mid { -bool ColumnDataToLocalBoard::keepBoard(const LocalBoardRO& loc) const +bool ColumnDataToLocalBoard::keepBoard(const ROBoard& loc) const { for (int ich = 0; ich < 4; ++ich) { if (loc.patternsBP[ich] && loc.patternsNBP[ich]) { @@ -42,7 +43,7 @@ void ColumnDataToLocalBoard::process(gsl::span<const ColumnData> data) // First fill the map with the active local boards. // Each local board gets a unique id. for (auto& col : data) { - for (int iline = mMapping.getFirstBoardBP(col.columnId, col.deId); iline <= mMapping.getLastBoardBP(col.columnId, col.deId); ++iline) { + for (int iline = mMapping.getFirstBoardBP(col.columnId, col.deId), lastLine = mMapping.getLastBoardBP(col.columnId, col.deId); iline <= lastLine; ++iline) { if (col.getBendPattern(iline) || col.getNonBendPattern()) { auto uniqueLocId = mCrateMapper.deLocalBoardToRO(col.deId, col.columnId, iline); auto& roData = mLocalBoardsMap[uniqueLocId]; @@ -59,8 +60,8 @@ void ColumnDataToLocalBoard::process(gsl::span<const ColumnData> data) // Then group the boards belonging to the same GBT link for (auto& item : mLocalBoardsMap) { if (mDebugMode || keepBoard(item.second)) { - auto crateId = crateparams::getCrateId(item.first); - auto feeId = crateparams::makeROId(crateId, crateparams::getGBTIdFromBoardInCrate(crateparams::getLocId(item.second.boardId))); + auto crateId = raw::getCrateId(item.first); + auto feeId = crateparams::makeGBTUniqueId(crateId, crateparams::getGBTIdFromBoardInCrate(raw::getLocId(item.second.boardId))); mGBTMap[feeId].emplace_back(item.second); } } diff --git a/Detectors/MUON/MID/Raw/src/CrateMapper.cxx b/Detectors/MUON/MID/Raw/src/CrateMapper.cxx index 6ad86e3680076..c2a1ab06e8445 100644 --- a/Detectors/MUON/MID/Raw/src/CrateMapper.cxx +++ b/Detectors/MUON/MID/Raw/src/CrateMapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include <sstream> #include <exception> +#include "DataFormatsMID/ROBoard.h" #include "MIDBase/DetectorParameters.h" #include "MIDRaw/CrateParameters.h" @@ -35,93 +37,93 @@ void CrateMapper::init() /// Initalizes the inner mapping // Crate 0 // link 0 - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 0), deBoardId(0, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 1), deBoardId(1, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 2), deBoardId(1, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 3), deBoardId(2, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 4), deBoardId(2, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 5), deBoardId(3, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 6), deBoardId(3, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 7), deBoardId(3, 0, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 0), deBoardId(0, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 1), deBoardId(1, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 2), deBoardId(1, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 3), deBoardId(2, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 4), deBoardId(2, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 5), deBoardId(3, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 6), deBoardId(3, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 7), deBoardId(3, 0, 2)); // link 1 - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 8), deBoardId(5, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 9), deBoardId(5, 0, 2)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 10), deBoardId(5, 0, 3)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 11), deBoardId(6, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 12), deBoardId(6, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 13), deBoardId(7, 0, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 14), deBoardId(7, 0, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(0, 15), deBoardId(8, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 8), deBoardId(5, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 9), deBoardId(5, 0, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 10), deBoardId(5, 0, 3)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 11), deBoardId(6, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 12), deBoardId(6, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 13), deBoardId(7, 0, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 14), deBoardId(7, 0, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(0, 15), deBoardId(8, 0, 0)); // Crate 1, 3 for (int icrate = 0; icrate < 2; ++icrate) { uint8_t crateId = (icrate == 0) ? 1 : 3; uint8_t columnId = (icrate == 0) ? 1 : 2; // link 0 - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 0), deBoardId(0, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 1), deBoardId(1, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 2), deBoardId(1, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 3), deBoardId(2, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 4), deBoardId(2, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 5), deBoardId(3, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 6), deBoardId(3, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 7), deBoardId(3, columnId, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 0), deBoardId(0, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 1), deBoardId(1, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 2), deBoardId(1, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 3), deBoardId(2, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 4), deBoardId(2, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 5), deBoardId(3, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 6), deBoardId(3, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 7), deBoardId(3, columnId, 2)); // link 1 - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 8), deBoardId(3, columnId, 3)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 9), deBoardId(4, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 10), deBoardId(4, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 11), deBoardId(4, columnId, 2)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 12), deBoardId(4, columnId, 3)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 13), deBoardId(5, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 14), deBoardId(5, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 8), deBoardId(3, columnId, 3)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 9), deBoardId(4, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 10), deBoardId(4, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 11), deBoardId(4, columnId, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 12), deBoardId(4, columnId, 3)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 13), deBoardId(5, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 14), deBoardId(5, columnId, 1)); } // Crate 2 // link 0 - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 0), deBoardId(5, 1, 2)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 1), deBoardId(5, 1, 3)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 2), deBoardId(6, 1, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 3), deBoardId(6, 1, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 4), deBoardId(7, 1, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 5), deBoardId(7, 1, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 6), deBoardId(8, 1, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 0), deBoardId(5, 1, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 1), deBoardId(5, 1, 3)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 2), deBoardId(6, 1, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 3), deBoardId(6, 1, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 4), deBoardId(7, 1, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 5), deBoardId(7, 1, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 6), deBoardId(8, 1, 0)); // link 1 - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 8), deBoardId(5, 2, 2)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 9), deBoardId(5, 2, 3)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 10), deBoardId(6, 2, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 11), deBoardId(6, 2, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 12), deBoardId(7, 2, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 13), deBoardId(7, 2, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(2, 14), deBoardId(8, 2, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 8), deBoardId(5, 2, 2)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 9), deBoardId(5, 2, 3)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 10), deBoardId(6, 2, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 11), deBoardId(6, 2, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 12), deBoardId(7, 2, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 13), deBoardId(7, 2, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(2, 14), deBoardId(8, 2, 0)); // Crate 4, 5, 6 for (int icrate = 0; icrate < 3; ++icrate) { uint16_t crateId = icrate + 4; uint8_t columnId = icrate + 3; // link 0 - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 0), deBoardId(0, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 1), deBoardId(1, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 2), deBoardId(1, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 3), deBoardId(2, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 4), deBoardId(2, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 5), deBoardId(3, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 6), deBoardId(3, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 7), deBoardId(4, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 0), deBoardId(0, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 1), deBoardId(1, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 2), deBoardId(1, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 3), deBoardId(2, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 4), deBoardId(2, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 5), deBoardId(3, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 6), deBoardId(3, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 7), deBoardId(4, columnId, 0)); // link 1 - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 8), deBoardId(4, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 9), deBoardId(5, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 10), deBoardId(5, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 11), deBoardId(6, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 12), deBoardId(6, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 13), deBoardId(7, columnId, 0)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 14), deBoardId(7, columnId, 1)); - mROToDEMap.emplace(crateparams::makeUniqueLocID(crateId, 15), deBoardId(8, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 8), deBoardId(4, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 9), deBoardId(5, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 10), deBoardId(5, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 11), deBoardId(6, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 12), deBoardId(6, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 13), deBoardId(7, columnId, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 14), deBoardId(7, columnId, 1)); + mROToDEMap.emplace(raw::makeUniqueLocID(crateId, 15), deBoardId(8, columnId, 0)); } // Crate 7 uint8_t rpcLineId = 0; for (uint8_t iboard = 0; iboard < 9; ++iboard) { - mROToDEMap.emplace(crateparams::makeUniqueLocID(7, iboard), deBoardId(rpcLineId++, 6, 0)); + mROToDEMap.emplace(raw::makeUniqueLocID(7, iboard), deBoardId(rpcLineId++, 6, 0)); } /// Build the inverse map @@ -145,7 +147,7 @@ uint8_t CrateMapper::deLocalBoardToRO(uint8_t deId, uint8_t columnId, uint8_t li uint16_t CrateMapper::roLocalBoardToDE(uint8_t crateId, uint8_t boardId) const { /// Converts the local board ID in FEE to the local board ID in MT11 right - auto item = mROToDEMap.find(crateparams::makeUniqueLocID(crateId % crateparams::sNCratesPerSide, boardId)); + auto item = mROToDEMap.find(raw::makeUniqueLocID(crateId % crateparams::sNCratesPerSide, boardId)); if (item == mROToDEMap.end()) { std::stringstream ss; ss << "Non-existant crateId: " << static_cast<int>(crateId) << " boardId: " << static_cast<int>(boardId); diff --git a/Detectors/MUON/MID/Raw/src/CrateMasks.cxx b/Detectors/MUON/MID/Raw/src/CrateMasks.cxx index 7a03728310ac9..00360711e609f 100644 --- a/Detectors/MUON/MID/Raw/src/CrateMasks.cxx +++ b/Detectors/MUON/MID/Raw/src/CrateMasks.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/src/DecodedDataAggregator.cxx b/Detectors/MUON/MID/Raw/src/DecodedDataAggregator.cxx index e464a6dd3581e..ddb8b4059e8c3 100644 --- a/Detectors/MUON/MID/Raw/src/DecodedDataAggregator.cxx +++ b/Detectors/MUON/MID/Raw/src/DecodedDataAggregator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,6 @@ #include "MIDRaw/DecodedDataAggregator.h" #include "MIDBase/DetectorParameters.h" - #include "MIDRaw/CrateParameters.h" namespace o2 @@ -24,68 +24,80 @@ namespace o2 namespace mid { -ColumnData& DecodedDataAggregator::FindColumnData(uint8_t deId, uint8_t columnId, size_t firstEntry) +ColumnData& DecodedDataAggregator::FindColumnData(uint8_t deId, uint8_t columnId, size_t firstEntry, size_t evtTypeIdx) { /// Gets the matching column data /// Adds one if not found - for (auto colIt = mData.begin() + firstEntry; colIt != mData.end(); ++colIt) { + for (auto colIt = mData[evtTypeIdx].begin() + firstEntry, end = mData[evtTypeIdx].end(); colIt != end; ++colIt) { if (colIt->deId == deId && colIt->columnId == columnId) { return *colIt; } } - mData.push_back({deId, columnId}); - return mData.back(); + mData[evtTypeIdx].push_back({deId, columnId}); + return mData[evtTypeIdx].back(); } -void DecodedDataAggregator::addData(const LocalBoardRO& loc, size_t firstEntry) +void DecodedDataAggregator::addData(const ROBoard& loc, size_t firstEntry, size_t evtTypeIdx) { /// Converts the local board data to ColumnData uint8_t uniqueLocId = loc.boardId; - uint8_t crateId = crateparams::getCrateId(uniqueLocId); + uint8_t crateId = raw::getCrateId(uniqueLocId); bool isRightSide = crateparams::isRightSide(crateId); - uint16_t deBoardId = mCrateMapper.roLocalBoardToDE(crateId, crateparams::getLocId(loc.boardId)); - auto rpcLineId = mCrateMapper.getRPCLine(deBoardId); - auto columnId = mCrateMapper.getColumnId(deBoardId); - auto lineId = mCrateMapper.getLineId(deBoardId); - for (int ich = 0; ich < 4; ++ich) { - if (((loc.firedChambers >> ich) & 0x1) == 0) { - continue; + try { + uint16_t deBoardId = mCrateMapper.roLocalBoardToDE(crateId, raw::getLocId(loc.boardId)); + auto rpcLineId = mCrateMapper.getRPCLine(deBoardId); + auto columnId = mCrateMapper.getColumnId(deBoardId); + auto lineId = mCrateMapper.getLineId(deBoardId); + for (int ich = 0; ich < 4; ++ich) { + if (((loc.firedChambers >> ich) & 0x1) == 0) { + continue; + } + uint8_t deId = detparams::getDEId(isRightSide, ich, rpcLineId); + auto& col = FindColumnData(deId, columnId, firstEntry, evtTypeIdx); + col.setBendPattern(loc.patternsBP[ich], lineId); + col.setNonBendPattern(col.getNonBendPattern() | loc.patternsNBP[ich]); } - uint8_t deId = detparams::getDEId(isRightSide, ich, rpcLineId); - auto& col = FindColumnData(deId, columnId, firstEntry); - col.setBendPattern(loc.patternsBP[ich], lineId); - col.setNonBendPattern(loc.patternsNBP[ich]); + } catch (const std::exception& except) { + std::cerr << except.what() << "\n"; } } -void DecodedDataAggregator::process(gsl::span<const LocalBoardRO> localBoards, gsl::span<const ROFRecord> rofRecords) +void DecodedDataAggregator::process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords) { /// Aggregates the decoded raw data // First clear the output - mData.clear(); - mROFRecords.clear(); + for (auto& data : mData) { + data.clear(); + } + for (auto& rof : mROFRecords) { + rof.clear(); + } // Fill the map with ordered events for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) { - mOrderIndexes[rofIt->interactionRecord.toLong()].emplace_back(rofIt - rofRecords.begin()); + mEventIndexes[static_cast<int>(rofIt->eventType)][rofIt->interactionRecord.toLong()].emplace_back(rofIt - rofRecords.begin()); } const ROFRecord* rof = nullptr; - for (auto& item : mOrderIndexes) { - size_t firstEntry = mData.size(); - for (auto& idx : item.second) { - // In principle all of these ROF records have the same timestamp - rof = &rofRecords[idx]; - for (size_t iloc = rof->firstEntry; iloc < rof->firstEntry + rof->nEntries; ++iloc) { - addData(localBoards[iloc], firstEntry); + for (size_t ievtType = 0; ievtType < mEventIndexes.size(); ++ievtType) { + for (auto& item : mEventIndexes[ievtType]) { + size_t firstEntry = mData[ievtType].size(); + for (auto& idx : item.second) { + // In principle all of these ROF records have the same timestamp + rof = &rofRecords[idx]; + for (size_t iloc = rof->firstEntry; iloc < rof->firstEntry + rof->nEntries; ++iloc) { + addData(localBoards[iloc], firstEntry, ievtType); + } + } + auto nEntries = mData[ievtType].size() - firstEntry; + if (nEntries > 0) { + mROFRecords[ievtType].emplace_back(rof->interactionRecord, rof->eventType, firstEntry, nEntries); } } - mROFRecords.emplace_back(rof->interactionRecord, rof->eventType, firstEntry, mData.size() - firstEntry); - } - - // Clear the inner objects when the computation is done - mOrderIndexes.clear(); + // Clear the inner objects when the computation is done + mEventIndexes[ievtType].clear(); + } // loop on event types } } // namespace mid diff --git a/Detectors/MUON/MID/Raw/src/Decoder.cxx b/Detectors/MUON/MID/Raw/src/Decoder.cxx index 9f71c784047ca..b5d75c47ff6b5 100644 --- a/Detectors/MUON/MID/Raw/src/Decoder.cxx +++ b/Detectors/MUON/MID/Raw/src/Decoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,37 +24,28 @@ namespace o2 namespace mid { -template <typename GBTDECODER> -Decoder<GBTDECODER>::Decoder() : mData(), mROFRecords(), mGBTDecoders(), mFEEIdConfig(), mMasks() +Decoder::Decoder(bool isDebugMode, bool isBare, const ElectronicsDelay& electronicsDelay, const CrateMasks& crateMasks, const FEEIdConfig& feeIdConfig) : mData(), mROFRecords(), mLinkDecoders() { - /// Default constructor - init(); + /// Constructor + auto feeIds = isBare ? feeIdConfig.getConfiguredGBTUniqueIDs() : feeIdConfig.getConfiguredFEEIDs(); + + for (auto& feeId : feeIds) { +#if defined(MID_RAW_VECTORS) + mLinkDecoders.emplace_back(createLinkDecoder(feeId, isBare, isDebugMode, crateMasks.getMask(feeId), electronicsDelay, feeIdConfig)); +#else + mLinkDecoders.emplace(feeId, createLinkDecoder(feeId, isBare, isDebugMode, crateMasks.getMask(feeId), electronicsDelay, feeIdConfig)); +#endif + } } -template <typename GBTDECODER> -void Decoder<GBTDECODER>::clear() +void Decoder::clear() { /// Clears the decoded data mData.clear(); mROFRecords.clear(); } -template <typename GBTDECODER> -void Decoder<GBTDECODER>::init(bool isDebugMode) -{ - /// Initializes the decoder - for (uint16_t igbt = 0; igbt < crateparams::sNGBTs; ++igbt) { - if constexpr (std::is_same_v<GBTDECODER, GBTBareDecoder>) { - mGBTDecoders[igbt].init(igbt, mMasks.getMask(igbt), isDebugMode); - } else { - mGBTDecoders[igbt].init(igbt, isDebugMode); - } - mGBTDecoders[igbt].setElectronicsDelay(mElectronicsDelay); - } -} - -template <typename GBTDECODER> -void Decoder<GBTDECODER>::process(gsl::span<const uint8_t> bytes) +void Decoder::process(gsl::span<const uint8_t> bytes) { /// Decodes the buffer clear(); @@ -66,41 +58,37 @@ void Decoder<GBTDECODER>::process(gsl::span<const uint8_t> bytes) auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(it.raw()); process(payload, *rdhPtr); } - flush(); } -template <typename GBTDECODER> -void Decoder<GBTDECODER>::flush() +std::unique_ptr<Decoder> createDecoder(const o2::header::RDHAny& rdh, bool isDebugMode, const ElectronicsDelay& electronicsDelay, const CrateMasks& crateMasks, const FEEIdConfig& feeIdConfig) { - /// Flushes the GBT data - for (auto& gbtDec : mGBTDecoders) { - if (!gbtDec.getData().empty()) { - size_t firstEntry = mData.size(); - mData.insert(mData.end(), gbtDec.getData().begin(), gbtDec.getData().end()); - size_t lastRof = mROFRecords.size(); - mROFRecords.insert(mROFRecords.end(), gbtDec.getROFRecords().begin(), gbtDec.getROFRecords().end()); - for (auto rofIt = mROFRecords.begin() + lastRof; rofIt != mROFRecords.end(); ++rofIt) { - rofIt->firstEntry += firstEntry; - } - gbtDec.clear(); - } - } + /// Creates the decoder from the RDH info + bool isBare = raw::isBare(rdh); + return std::make_unique<Decoder>(isDebugMode, isBare, electronicsDelay, crateMasks, feeIdConfig); } - -template <typename GBTDECODER> -bool Decoder<GBTDECODER>::isComplete() const +std::unique_ptr<Decoder> createDecoder(const o2::header::RDHAny& rdh, bool isDebugMode, const char* electronicsDelayFile, const char* crateMasksFile, const char* feeIdConfigFile) { - /// Checks that all links have finished reading - for (auto& decoder : mGBTDecoders) { - if (!decoder.isComplete()) { - return false; - } + /// Creates the decoder from the RDH info + o2::mid::ElectronicsDelay electronicsDelay; + std::string filename = electronicsDelayFile; + if (!filename.empty()) { + electronicsDelay = o2::mid::readElectronicsDelay(filename.c_str()); + } + + o2::mid::CrateMasks crateMasks; + filename = crateMasksFile; + if (!filename.empty()) { + crateMasks = o2::mid::CrateMasks(filename.c_str()); + } + + o2::mid::FEEIdConfig feeIdConfig; + filename = feeIdConfigFile; + if (!filename.empty()) { + feeIdConfig = o2::mid::FEEIdConfig(filename.c_str()); } - return true; -} -template class Decoder<GBTBareDecoder>; -template class Decoder<GBTUserLogicDecoder>; + return createDecoder(rdh, isDebugMode, electronicsDelay, crateMasks, feeIdConfig); +} } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/ELinkDataShaper.cxx b/Detectors/MUON/MID/Raw/src/ELinkDataShaper.cxx new file mode 100644 index 0000000000000..edbfb1476347b --- /dev/null +++ b/Detectors/MUON/MID/Raw/src/ELinkDataShaper.cxx @@ -0,0 +1,217 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Raw/src/ELinkDataShaper.cxx +/// \brief Properly formats and sets the absolute timestamp of the raw data +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 18 March 2021 + +#include "MIDRaw/ELinkDataShaper.h" + +#include "CommonConstants/LHCConstants.h" + +namespace o2 +{ +namespace mid +{ + +ELinkDataShaper::ELinkDataShaper(bool isDebugMode, bool isLoc, uint8_t uniqueId, const ElectronicsDelay& electronicsDelay) : mUniqueId(uniqueId), mElectronicsDelay(electronicsDelay) +{ + /// Ctr + if (isDebugMode) { + if (isLoc) { + mOnDone = &ELinkDataShaper::onDoneLocDebug; + } else { + mOnDone = &ELinkDataShaper::onDoneRegDebug; + } + } else { + if (isLoc) { + mOnDone = &ELinkDataShaper::onDoneLoc; + } else { + mOnDone = &ELinkDataShaper::onDoneReg; + } + } + if (!isLoc) { + mElectronicsDelay.BCToLocal += electronicsDelay.regToLocal; + mElectronicsDelay.calibToFET += electronicsDelay.regToLocal; + } +} + +void ELinkDataShaper::set(uint32_t orbit) +{ + /// Sets the orbit and the output data vectors + mRDHOrbit = orbit; + + if (mIR.isDummy()) { + mIR.bc = 0; + // The reset changes depending on the way we synch with the orbit + // (see processOrbitTrigger for details) + // FIXME: pick one of the two + // mIR.orbit = orbit - 1; // with orbit increase + mIR.orbit = orbit; // with reset to RDH + mLastClock = constants::lhc::LHCMaxBunches; + } +} + +bool ELinkDataShaper::checkLoc(const ELinkDecoder& decoder) +{ + /// Performs checks on the local board + return (decoder.getId() == (mUniqueId & 0xF)); +} + +EventType ELinkDataShaper::processSelfTriggered(uint16_t localClock, InteractionRecord& ir) +{ + /// Processes the self-triggered event + + // This is a self-triggered events. + // The physics data arrives with a delay compared to the BC, + // which is due to the travel time of muons up to the MID chambers + // plus the travel time of the signal to the readout electronics. + // In the case of regional cards, a further delay is expected + // since this card needs to wait for the tracklet decision of each local card. + // For simplicity, this delay is added to the BCToLocal in the constructor. + // In both cases, we need to correct for the delay in order to go back to the real BC. + if (ir.bc < mElectronicsDelay.BCToLocal) { + // If the bc is smaller than the delay, it means that the local clock was reset + // This events therefore belongs to the previous orbit. + // We therefore add the value of the last BC (+1 to account for the reset) + // and we decrease the orbit by 1. + ir.bc += mLastClock + 1; + --ir.orbit; + } + // We can now safely subtract the delay, which, thanks to the above protection, + // will not result in a negative number + ir.bc -= mElectronicsDelay.BCToLocal; + if (mReceivedCalibration && (localClock == mExpectedFETClock)) { + // Reset the calibration flag for this e-link + mReceivedCalibration = false; + return EventType::FET; + } + return EventType::Standard; +} + +EventType ELinkDataShaper::processCalibrationTrigger(uint16_t localClock) +{ + /// Processes the calibration event + mExpectedFETClock = localClock + mElectronicsDelay.calibToFET; + mReceivedCalibration = true; + return EventType::Calib; +} + +void ELinkDataShaper::processOrbitTrigger(uint16_t localClock, uint8_t triggerWord) +{ + /// Processes the orbit trigger event + + // The local clock is reset: we are now in synch with the new HB + // We have two ways to account for the orbit change: + // - increase the orbit counter by 1 for this e-link + // (CAVEAT: synch is lost if we lose some orbit) + // - set the orbit to the one found in RDH + // (CAVEAT: synch is lost if we have lot of data, spanning over two orbits) + // FIXME: pick one of the two + // ++mIR.orbit; // orbit increase + mIR.orbit = mRDHOrbit; // reset to RDH + if ((triggerWord & raw::sSOX) == 0) { + mLastClock = localClock; + } + // The orbit trigger resets the clock. + // If we received a calibration trigger, we need to change the value of the expected clock accordingly + if (mReceivedCalibration) { + mExpectedFETClock -= (localClock + 1); + } +} + +bool ELinkDataShaper::processTrigger(const ELinkDecoder& decoder, EventType& eventType, InteractionRecord& ir) +{ + /// Processes the trigger information + /// Returns true if the event should be further processed, + /// returns false otherwise. + auto localClock = decoder.getCounter(); + + // FIXME: So far the bc information is not used + // since it seems that it is always equal to 0 + // (at least in the RDH of the first page, which is what we need). + // In this case the local clock and the BC coincide. + // If this is not the case, the bc of the orbit trigger should be correctly taken into account + ir.bc = localClock; + // ir.bc = mIR.bc + localClock; + ir.orbit = mIR.orbit; + + if (decoder.getTriggerWord() == 0) { + // This is a self-triggered event + eventType = processSelfTriggered(localClock, ir); + return true; + } + + // From here we treat triggered events + bool goOn = false; + eventType = EventType::Standard; + if (decoder.getTriggerWord() & raw::sCALIBRATE) { + // This is an answer to a calibration trigger + eventType = processCalibrationTrigger(localClock); + goOn = true; + } + + if (decoder.getTriggerWord() & raw::sORB) { + // This is the answer to an orbit trigger + processOrbitTrigger(localClock, decoder.getTriggerWord()); + } + + return goOn; +} + +void ELinkDataShaper::addLoc(const ELinkDecoder& decoder, EventType eventType, InteractionRecord ir, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + /// Adds the local board to the output data vector + auto firstEntry = data.size(); + data.push_back({decoder.getStatusWord(), decoder.getTriggerWord(), mUniqueId, decoder.getInputs()}); + rofs.emplace_back(ir, eventType, firstEntry, 1); + for (int ich = 0; ich < 4; ++ich) { + if ((data.back().firedChambers & (1 << ich))) { + data.back().patternsBP[ich] = decoder.getPattern(0, ich); + data.back().patternsNBP[ich] = decoder.getPattern(1, ich); + } + } +} + +void ELinkDataShaper::onDoneLoc(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + /// Performs action on decoded local board + EventType eventType; + InteractionRecord ir; + if (processTrigger(decoder, eventType, ir) && checkLoc(decoder)) { + addLoc(decoder, eventType, ir, data, rofs); + } +} + +void ELinkDataShaper::onDoneLocDebug(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + /// This always adds the local board to the output, without performing tests + EventType eventType; + InteractionRecord ir; + processTrigger(decoder, eventType, ir); + addLoc(decoder, eventType, ir, data, rofs); +} + +void ELinkDataShaper::onDoneRegDebug(const ELinkDecoder& decoder, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + /// Performs action on decoded regional board in debug mode. + EventType eventType; + InteractionRecord ir; + processTrigger(decoder, eventType, ir); + // If we want to distinguish the two regional e-links, we can use the link ID instead + auto firstEntry = data.size(); + data.push_back({decoder.getStatusWord(), decoder.getTriggerWord(), mUniqueId, decoder.getInputs()}); + rofs.emplace_back(ir, eventType, firstEntry, 1); +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/ELinkDecoder.cxx b/Detectors/MUON/MID/Raw/src/ELinkDecoder.cxx index 9ec3c7b9d3c73..e9166702b1622 100644 --- a/Detectors/MUON/MID/Raw/src/ELinkDecoder.cxx +++ b/Detectors/MUON/MID/Raw/src/ELinkDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,46 +16,81 @@ #include "MIDRaw/ELinkDecoder.h" -#include "MIDRaw/LocalBoardRO.h" - namespace o2 { namespace mid { -void ELinkDecoder::add(uint8_t byte) +void ELinkDecoder::setBareDecoder(bool isBare) { - /// Adds next byte - mBytes.emplace_back(byte); - if (mBytes.size() == sMinimumSize) { - if (raw::isLoc(mBytes[0])) { - // This is a local card - uint8_t mask = getInputs(); - for (int ich = 0; ich < 4; ++ich) { - if ((mask >> ich) & 0x1) { - // We expect 2 bytes for the BP and 2 for the NBP - mTotalSize += 4; - } + /// Sets the decoder type + mMinimumSize = isBare ? 5 : 6; + mMaximumSize = isBare ? 21 : 22; + mTotalSize = mMinimumSize; +} + +bool ELinkDecoder::add(size_t& idx, gsl::span<const uint8_t> payload, size_t nBytes, size_t step) +{ + /// Fills inner bytes vector + auto size = payload.size(); + auto end = idx + step * nBytes; + if (size < end) { + end = size; + } + size_t nAdded = 0; + for (; idx < end; idx += step) { + mBytes.emplace_back(payload[idx]); + ++nAdded; + } + return (nAdded == nBytes); +} + +bool ELinkDecoder::add(size_t& idx, gsl::span<const uint8_t> payload, size_t step) +{ + /// Adds the bytes of the board + auto remaining = mTotalSize - mBytes.size(); + if (add(idx, payload, remaining, step)) { + if (mTotalSize == mMinimumSize) { + computeSize(); + remaining = mTotalSize - mBytes.size(); + if (remaining) { + return add(idx, payload, remaining, step); } } + return true; + } + return false; +} + +void ELinkDecoder::addAndComputeSize(uint8_t byte) +{ + /// Adds next byte and computes the expected data size + mBytes.emplace_back(byte); + if (mBytes.size() == mMinimumSize) { + computeSize(); } } -bool ELinkDecoder::add(uint8_t byte, uint8_t expectedStart) +void ELinkDecoder::computeSize() { - /// Adds next byte, checking the first one - if (mBytes.empty() && (byte & 0xc0) != expectedStart) { - return false; + /// Computes the board size + if (raw::isLoc(mBytes[0])) { + // This is a local card + uint8_t mask = getInputs(); + for (int ich = 0; ich < 4; ++ich) { + if ((mask >> ich) & 0x1) { + // We expect 2 bytes for the BP and 2 for the NBP + mTotalSize += 4; + } + } } - add(byte); - return true; } void ELinkDecoder::reset() { /// Reset inner objects mBytes.clear(); - mTotalSize = sMinimumSize; + mTotalSize = mMinimumSize; } uint16_t ELinkDecoder::getPattern(int cathode, int chamber) const diff --git a/Detectors/MUON/MID/Raw/src/ELinkManager.cxx b/Detectors/MUON/MID/Raw/src/ELinkManager.cxx new file mode 100644 index 0000000000000..781fd6bf8cc73 --- /dev/null +++ b/Detectors/MUON/MID/Raw/src/ELinkManager.cxx @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Raw/src/ELinkManager.cxx +/// \brief MID e-link data shaper manager +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 18 March 2021 + +#include "MIDRaw/ELinkManager.h" +#include "MIDRaw/CrateParameters.h" +#include "fmt/format.h" + +namespace o2 +{ +namespace mid +{ +void ELinkManager::init(uint16_t feeId, bool isDebugMode, bool isBare, const ElectronicsDelay& electronicsDelay, const FEEIdConfig& feeIdConfig) +{ + /// Initializer + auto gbtUniqueIds = isBare ? std::vector<uint16_t>{feeId} : feeIdConfig.getGBTUniqueIdsInLink(feeId); + + for (auto& gbtUniqueId : gbtUniqueIds) { + auto crateId = crateparams::getCrateIdFromGBTUniqueId(gbtUniqueId); + uint8_t offset = crateparams::getGBTIdInCrate(gbtUniqueId) * 8; + for (int ilink = 0; ilink < 10; ++ilink) { + bool isLoc = ilink < 8; + auto uniqueId = raw::makeUniqueLocID(crateId, ilink % 8 + offset); + ELinkDataShaper shaper(isDebugMode, isLoc, uniqueId, electronicsDelay); +#if defined(MID_RAW_VECTORS) + mDataShapers.emplace_back(shaper); +#else + auto uniqueRegLocId = makeUniqueId(isLoc, uniqueId); + mDataShapers.emplace(uniqueRegLocId, shaper); +#endif + + if (isBare) { + ELinkDecoder decoder; + decoder.setBareDecoder(true); +#if defined(MID_RAW_VECTORS) + mDecoders.emplace_back(decoder); +#else + mDecoders.emplace(uniqueRegLocId, decoder); +#endif + } + } + } + +#if defined(MID_RAW_VECTORS) + if (isBare) { + mIndex = [](uint8_t, uint8_t locId, bool isLoc) { return 8 * (1 - static_cast<size_t>(isLoc)) + (locId % 8); }; + } else { + mIndex = [](uint8_t crateId, uint8_t locId, bool isLoc) { return 10 * (2 * (crateId % 4) + (locId / 8)) + 8 * (1 - static_cast<size_t>(isLoc)) + (locId % 8); }; + } +#endif +} + +void ELinkManager::onDone(const ELinkDecoder& decoder, uint8_t crateId, uint8_t locId, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + auto ds = mDataShapers.find(makeUniqueId(raw::isLoc(decoder.getStatusWord()), raw::makeUniqueLocID(crateId, locId))); + if (ds == mDataShapers.end()) { + ROBoard board{decoder.getStatusWord(), decoder.getTriggerWord(), raw::makeUniqueLocID(crateId, locId), decoder.getInputs()}; + for (int ich = 0; ich < 4; ++ich) { + board.patternsBP[ich] = decoder.getPattern(0, ich); + board.patternsNBP[ich] = decoder.getPattern(1, ich); + } + std::cerr << "Board not found: " << board << "\n"; + return; + } + return ds->second.onDone(decoder, data, rofs); +} + +void ELinkManager::set(uint32_t orbit) +{ + /// Setup the orbit + for (auto& shaper : mDataShapers) { +#if defined(MID_RAW_VECTORS) + shaper.set(orbit); +#else + shaper.second.set(orbit); +#endif + } +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/ElectronicsDelay.cxx b/Detectors/MUON/MID/Raw/src/ElectronicsDelay.cxx index 48a7955e2ef5d..20a70759e0b68 100644 --- a/Detectors/MUON/MID/Raw/src/ElectronicsDelay.cxx +++ b/Detectors/MUON/MID/Raw/src/ElectronicsDelay.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/src/Encoder.cxx b/Detectors/MUON/MID/Raw/src/Encoder.cxx index e203800c20d05..bed92a3417769 100644 --- a/Detectors/MUON/MID/Raw/src/Encoder.cxx +++ b/Detectors/MUON/MID/Raw/src/Encoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RDHUtils.h" #include "MIDRaw/CrateMasks.h" +#include "MIDRaw/Utils.h" #include <fmt/format.h> namespace o2 @@ -25,29 +27,52 @@ namespace o2 namespace mid { -void Encoder::init(const char* filename, bool perLink, int verbosity, bool debugMode) +void Encoder::init(std::string_view outDir, std::string_view fileFor, int verbosity, bool debugMode) { /// Initializes links CrateMasks masks; - auto gbtIds = mFEEIdConfig.getConfiguredGBTIds(); + auto linkUniqueIds = mFEEIdConfig.getConfiguredLinkUniqueIDs(); + + // Initialises the GBT link encoders + for (auto& linkUniqueId : linkUniqueIds) { + auto gbtUniqueId = mFEEIdConfig.getGBTUniqueId(linkUniqueId); + mGBTEncoders[gbtUniqueId].setGBTUniqueId(gbtUniqueId); + mGBTEncoders[gbtUniqueId].setMask(masks.getMask(gbtUniqueId)); + mGBTIds[gbtUniqueId] = linkUniqueId; + } + // Initializes the output link + auto ir = getOrbitIR(0); mRawWriter.setVerbosity(verbosity); - int lcnt = 0; - for (auto& gbtId : gbtIds) { - auto feeId = mFEEIdConfig.getFeeId(gbtId); - mRawWriter.registerLink(feeId, mFEEIdConfig.getCRUId(gbtId), mFEEIdConfig.getLinkId(gbtId), mFEEIdConfig.getEndPointId(gbtId), perLink ? fmt::format("{:s}_L{:d}.raw", filename, lcnt) : fmt::format("{:s}.raw", filename)); - mGBTEncoders[feeId].setFeeId(feeId); - mGBTEncoders[feeId].setMask(masks.getMask(feeId)); - mGBTIds[feeId] = gbtId; - lcnt++; - - // Initializes the trigger response to be added to the empty HBs - auto ir = getOrbitIR(0); - mGBTEncoders[feeId].processTrigger(ir, raw::sORB); - mGBTEncoders[feeId].flush(mOrbitResponse[feeId], ir); - mOrbitResponseWord[feeId] = mOrbitResponse[feeId]; - completeWord(mOrbitResponseWord[feeId]); + for (uint16_t cruId = 0; cruId < 2; ++cruId) { + for (uint8_t epId = 0; epId < 2; ++epId) { + uint16_t feeId = 2 * cruId + epId; + std::string outFileLink = fmt::format("{}/MID", outDir); + if (fileFor != "all") { // single file for all links + outFileLink += "_alio2-cr1-flp159"; + if (fileFor != "flp") { + outFileLink += fmt::format("_cru{}_{}", cruId, epId); + if (fileFor != "cru") { + outFileLink += fmt::format("_lnk{}_feeid{}", raw::sUserLogicLinkID, feeId); + if (fileFor != "link") { + throw std::runtime_error("invalid option provided for file grouping"); + } + } + } + } + outFileLink += ".raw"; + mRawWriter.registerLink(feeId, cruId, raw::sUserLogicLinkID, epId, outFileLink); + + for (auto gbtUniqueId : mFEEIdConfig.getGBTUniqueIdsInLink(feeId)) { + // Initializes the trigger response to be added to the empty HBs + mGBTEncoders[gbtUniqueId].processTrigger(ir, raw::sORB); + mGBTEncoders[gbtUniqueId].flush(mOrbitResponse[feeId], ir); + } + + mOrbitResponseWord[feeId] = mOrbitResponse[feeId]; + completeWord(mOrbitResponseWord[feeId]); + } } mRawWriter.setEmptyPageCallBack(this); @@ -58,19 +83,16 @@ void Encoder::init(const char* filename, bool perLink, int verbosity, bool debug void Encoder::emptyHBFMethod(const o2::header::RDHAny* rdh, std::vector<char>& toAdd) const { /// Response to orbit triggers in empty HBFs - auto feeId = o2::raw::RDHUtils::getFEEID(rdh); - toAdd = mOrbitResponseWord[feeId]; + toAdd = mOrbitResponseWord[o2::raw::RDHUtils::getFEEID(rdh)]; } void Encoder::onOrbitChange(uint32_t orbit) { /// Performs action when orbit changes auto ir = getOrbitIR(orbit); - for (uint16_t feeId = 0; feeId < crateparams::sNGBTs; ++feeId) { + for (uint16_t feeId = 0; feeId < 4; ++feeId) { // Write the data corresponding to the previous orbit - if (!mGBTEncoders[feeId].isEmpty()) { - writePayload(feeId, ir); - } + writePayload(feeId, ir); } } @@ -90,32 +112,39 @@ void Encoder::writePayload(uint16_t feeId, const InteractionRecord& ir) { /// Writes data - // The first part of data is the answer to the orbit trigger - std::vector<char> buf = mOrbitResponse[feeId]; - // Then we flush the received data - mGBTEncoders[feeId].flush(buf, ir); + std::vector<char> buf; + for (auto& gbtUniqueId : mFEEIdConfig.getGBTUniqueIdsInLink(feeId)) { + if (!mGBTEncoders[gbtUniqueId].isEmpty()) { + mGBTEncoders[gbtUniqueId].flush(buf, ir); + } + } + if (buf.empty()) { + return; + } + + // Add the orbit response + buf.insert(buf.begin(), mOrbitResponse[feeId].begin(), mOrbitResponse[feeId].end()); completeWord(buf); - mRawWriter.addData(feeId, mFEEIdConfig.getCRUId(mGBTIds[feeId]), mFEEIdConfig.getLinkId(mGBTIds[feeId]), mFEEIdConfig.getEndPointId(mGBTIds[feeId]), ir, buf); + mRawWriter.addData(feeId, feeId / 2, raw::sUserLogicLinkID, feeId % 2, ir, buf); } void Encoder::finalize(bool closeFile) { /// Writes remaining data and closes the file if (mLastIR.isDummy()) { - mLastIR.bc = mRawWriter.getHBFUtils().bcFirst; + mLastIR.bc = 0; mLastIR.orbit = mRawWriter.getHBFUtils().orbitFirst; } auto ir = getOrbitIR(mLastIR.orbit); - for (uint16_t feeId = 0; feeId < crateparams::sNGBTs; ++feeId) { + auto nextIr = getOrbitIR(mLastIR.orbit + 1); + for (uint16_t feeId = 0; feeId < 4; ++feeId) { + auto ir = getOrbitIR(mLastIR.orbit); // Write the last payload writePayload(feeId, ir); - if (!mGBTEncoders[feeId].isEmpty()) { - // Since the regional response comes after few clocks, - // we might have the corresponding regional cards in the next orbit. - // If this is the case, we flush all data of the next orbit - ++ir.orbit; - writePayload(feeId, ir); - } + // Since the regional response comes after few clocks, + // we might have the corresponding regional cards in the next orbit. + // If this is the case, we flush all data of the next orbit + writePayload(feeId, nextIr); } if (closeFile) { mRawWriter.close(); diff --git a/Detectors/MUON/MID/Raw/src/FEEIdConfig.cxx b/Detectors/MUON/MID/Raw/src/FEEIdConfig.cxx index 055d4f60251b8..37f762d8e3fe6 100644 --- a/Detectors/MUON/MID/Raw/src/FEEIdConfig.cxx +++ b/Detectors/MUON/MID/Raw/src/FEEIdConfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "MIDRaw/FEEIdConfig.h" +#include <iostream> #include <fstream> #include <sstream> #include <string> @@ -26,49 +28,89 @@ namespace o2 { namespace mid { -FEEIdConfig::FEEIdConfig() : mGBTIdToFeeId() +FEEIdConfig::FEEIdConfig() : mLinkUniqueIdToGBTUniqueId(), mGBTUniqueIdToFeeId(), mGBTUniqueIdsInLink() { /// Default constructor - for (uint16_t iside = 0; iside < 2; ++iside) { - for (uint8_t igbt = 0; igbt < crateparams::sNGBTsPerSide; ++igbt) { - mGBTIdToFeeId[getGBTId(igbt % 12, igbt / 12, iside)] = igbt + crateparams::sNGBTsPerSide * iside; - } + for (uint16_t icru = 0; icru < 2; ++icru) { + uint16_t offset = 16 * icru; + add(offset + 0, 6, 0, icru); + add(offset + 1, 7, 0, icru); + add(offset + 2, 4, 0, icru); + add(offset + 3, 5, 0, icru); + add(offset + 8, 2, 0, icru); + add(offset + 9, 3, 0, icru); + add(offset + 10, 0, 0, icru); + add(offset + 11, 1, 0, icru); + + add(offset + 4, 0, 1, icru); + add(offset + 5, 1, 1, icru); + add(offset + 6, 2, 1, icru); + add(offset + 7, 3, 1, icru); + add(offset + 12, 6, 1, icru); + add(offset + 13, 7, 1, icru); + add(offset + 14, 4, 1, icru); + add(offset + 15, 5, 1, icru); } } -FEEIdConfig::FEEIdConfig(const char* filename) : mGBTIdToFeeId() +FEEIdConfig::FEEIdConfig(const char* filename) : mLinkUniqueIdToGBTUniqueId() { /// Construct from file load(filename); } -uint16_t FEEIdConfig::getFeeId(uint32_t uniqueId) const +void FEEIdConfig::add(uint16_t gbtUniqueId, uint8_t linkId, uint8_t epId, uint16_t cruId, uint16_t feeId) +{ + /// Adds a link + mLinkUniqueIdToGBTUniqueId[getLinkUniqueId(linkId, epId, cruId)] = gbtUniqueId; + mGBTUniqueIdToFeeId[gbtUniqueId] = feeId; + mGBTUniqueIdsInLink[feeId].emplace_back(gbtUniqueId); +} + +void FEEIdConfig::add(uint16_t gbtUniqueId, uint8_t linkId, uint8_t epId, uint16_t cruId) +{ + /// Adds a link assigning the feed from cruId and epId + add(gbtUniqueId, linkId, epId, cruId, 2 * cruId + epId); +} + +uint16_t FEEIdConfig::getGBTUniqueId(uint32_t linkUniqueId) const { /// Gets the feeId from the physical ID of the link - auto feeId = mGBTIdToFeeId.find(uniqueId); - if (feeId == mGBTIdToFeeId.end()) { - LOGF(ERROR, "No FeeId found for: CRUId: %i LinkId: %i EndPointId: %i", getCRUId(uniqueId), getLinkId(uniqueId), getEndPointId(uniqueId)); + auto feeId = mLinkUniqueIdToGBTUniqueId.find(linkUniqueId); + if (feeId == mLinkUniqueIdToGBTUniqueId.end()) { + LOGF(ERROR, "No FeeId found for: CRUId: %i LinkId: %i EndPointId: %i", getCRUId(linkUniqueId), getLinkId(linkUniqueId), getEndPointId(linkUniqueId)); return 0xFFFF; } return feeId->second; } -std::vector<uint16_t> FEEIdConfig::getConfiguredFeeIds() const +std::vector<uint16_t> FEEIdConfig::getConfiguredGBTUniqueIDs() const { /// Returns the sorted list of configured FEE IDs std::vector<uint16_t> configIds; - for (auto& item : mGBTIdToFeeId) { + for (auto& item : mLinkUniqueIdToGBTUniqueId) { configIds.emplace_back(item.second); } std::sort(configIds.begin(), configIds.end()); return configIds; } -std::vector<uint32_t> FEEIdConfig::getConfiguredGBTIds() const +std::vector<uint32_t> FEEIdConfig::getConfiguredLinkUniqueIDs() const { /// Returns the sorted list of configured GBT IDs std::vector<uint32_t> configIds; - for (auto& item : mGBTIdToFeeId) { + for (auto& item : mLinkUniqueIdToGBTUniqueId) { + configIds.emplace_back(item.first); + } + std::sort(configIds.begin(), configIds.end()); + return configIds; +} + +std::vector<uint16_t> FEEIdConfig::getConfiguredFEEIDs() const +{ + /// Returns the sorted list of configured FEE Ids + std::vector<uint16_t> configIds; + for (auto& item : mGBTUniqueIdsInLink) { configIds.emplace_back(item.first); } std::sort(configIds.begin(), configIds.end()); @@ -82,14 +124,17 @@ bool FEEIdConfig::load(const char* filename) /// feeId linkId endPointId cruId /// with one line per link - mGBTIdToFeeId.clear(); + mLinkUniqueIdToGBTUniqueId.clear(); + mGBTUniqueIdToFeeId.clear(); + mGBTUniqueIdsInLink.clear(); std::ifstream inFile(filename); if (!inFile.is_open()) { return false; } std::string line, token; while (std::getline(inFile, line)) { - if (std::count(line.begin(), line.end(), ' ') < 3) { + int nSpaces = std::count(line.begin(), line.end(), ' '); + if (nSpaces < 3) { continue; } if (line.find('#') < line.find(' ')) { @@ -98,25 +143,41 @@ bool FEEIdConfig::load(const char* filename) std::stringstream ss; ss << line; std::getline(ss, token, ' '); - uint16_t feeId = std::atoi(token.c_str()); + uint16_t gbtUniqueId = std::atoi(token.c_str()); std::getline(ss, token, ' '); uint8_t linkId = std::atoi(token.c_str()); std::getline(ss, token, ' '); - uint8_t endPointId = std::atoi(token.c_str()); + uint8_t epId = std::atoi(token.c_str()); std::getline(ss, token, ' '); uint16_t cruId = std::atoi(token.c_str()); - mGBTIdToFeeId[getGBTId(linkId, endPointId, cruId)] = feeId; + std::getline(ss, token, ' '); + if (nSpaces > 3) { + uint16_t feeId = std::atoi(token.c_str()); + add(gbtUniqueId, linkId, epId, cruId, feeId); + } else { + add(gbtUniqueId, linkId, epId, cruId); + } } inFile.close(); return true; } +uint16_t FEEIdConfig::getFEEId(uint16_t gbtUniqueId) const +{ + auto feeId = mGBTUniqueIdToFeeId.find(gbtUniqueId); + if (feeId == mGBTUniqueIdToFeeId.end()) { + std::cout << "Error: GBT ID " << gbtUniqueId << "not found" << std::endl; + return 0; + } + return feeId->second; +} + void FEEIdConfig::write(const char* filename) const { /// Writes the FEE Ids to a configuration file std::ofstream outFile(filename); - for (auto& id : mGBTIdToFeeId) { - outFile << id.first << " " << (id.second & 0xFF) << " " << ((id.second >> 8) & 0xFF) << " " << ((id.second >> 16) & 0xFF) << std::endl; + for (auto& id : mLinkUniqueIdToGBTUniqueId) { + outFile << id.second << " " << getLinkId(id.first) << " " << getEndPointId(id.first) << " " << getCRUId(id.first) << " " << mGBTUniqueIdToFeeId.find(id.second)->second << std::endl; } outFile.close(); } diff --git a/Detectors/MUON/MID/Raw/src/GBTBareDecoder.cxx b/Detectors/MUON/MID/Raw/src/GBTBareDecoder.cxx deleted file mode 100644 index c5f2c8bf7177a..0000000000000 --- a/Detectors/MUON/MID/Raw/src/GBTBareDecoder.cxx +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Raw/src/GBTBareDecoder.cxx -/// \brief MID GBT decoder without user logic -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 12 March 2020 - -#include "MIDRaw/GBTBareDecoder.h" - -namespace o2 -{ -namespace mid -{ - -void GBTBareDecoder::init(uint16_t feeId, uint8_t mask, bool isDebugMode) -{ - /// Initializes the task - mOutputHandler.setFeeId(feeId); - mMask = mask; - if (isDebugMode) { - mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; - mProcessReg = &GBTBareDecoder::processRegDebug; - } -} - -void GBTBareDecoder::process(gsl::span<const uint8_t> bytes, uint16_t bc, uint32_t orbit, uint16_t pageCnt) -{ - /// Decodes the buffer - mOutputHandler.setIR(bc, orbit, pageCnt); - - uint8_t byte = 0; - size_t ilink = 0, linkMask = 0, byteOffset = 0; - - for (int ireg = 0; ireg < 2; ++ireg) { - byteOffset = 5 * ireg; - ilink = 8 + ireg; - linkMask = (1 << ilink); - for (size_t idx = byteOffset + 4; idx < bytes.size(); idx += 16) { - byte = bytes[idx]; - if ((mIsFeeding & linkMask) || byte) { - std::invoke(mProcessReg, this, ilink, byte); - } - } - for (int ib = 0; ib < 4; ++ib) { - ilink = ib + 4 * ireg; - linkMask = (1 << ilink); - if (mMask & linkMask) { - for (size_t idx = byteOffset + ib; idx < bytes.size(); idx += 16) { - byte = bytes[idx]; - if ((mIsFeeding & linkMask) || byte) { - processLoc(ilink, byte); - } - } - } - } - } -} - -void GBTBareDecoder::processLoc(size_t ilink, uint8_t byte) -{ - /// Processes the local board information - if (mELinkDecoders[ilink].getNBytes() > 0) { - mELinkDecoders[ilink].add(byte); - if (mELinkDecoders[ilink].isComplete()) { - std::invoke(mOnDoneLoc, mOutputHandler, ilink, mELinkDecoders[ilink]); - mELinkDecoders[ilink].reset(); - mIsFeeding &= (~(1 << ilink)); - } - } else if ((byte & (raw::sSTARTBIT | raw::sCARDTYPE)) == (raw::sSTARTBIT | raw::sCARDTYPE)) { - mELinkDecoders[ilink].add(byte); - mIsFeeding |= (1 << ilink); - } -} - -void GBTBareDecoder::processRegDebug(size_t ilink, uint8_t byte) -{ - /// Processes the regional board information in debug mode - if (mELinkDecoders[ilink].getNBytes() > 0) { - mELinkDecoders[ilink].add(byte); - if (mELinkDecoders[ilink].isComplete()) { - mOutputHandler.onDoneRegDebug(ilink, mELinkDecoders[ilink]); - mELinkDecoders[ilink].reset(); - mIsFeeding &= (~(1 << ilink)); - } - } else if (byte & raw::sSTARTBIT) { - mELinkDecoders[ilink].add(byte); - mIsFeeding |= (1 << ilink); - } -} - -bool GBTBareDecoder::isComplete() const -{ - /// Checks that all links have finished reading - for (auto& elink : mELinkDecoders) { - if (elink.getNBytes() > 0) { - return false; - } - } - return true; -} - -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/GBTOutputHandler.cxx b/Detectors/MUON/MID/Raw/src/GBTOutputHandler.cxx index b65d4b2934061..b130c3248761f 100644 --- a/Detectors/MUON/MID/Raw/src/GBTOutputHandler.cxx +++ b/Detectors/MUON/MID/Raw/src/GBTOutputHandler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,19 +21,16 @@ namespace o2 namespace mid { -void GBTOutputHandler::clear() +void GBTOutputHandler::set(uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) { - /// Rewind bytes - mData.clear(); - mROFRecords.clear(); -} + /// Sets the orbit and the output data vectors + mOrbit = orbit; + mData = &data; + mROFRecords = &rofs; -void GBTOutputHandler::setIR(uint16_t bc, uint32_t orbit, int pageCnt) -{ - /// Sets the interaction record if needed if (mIRs[0].isDummy()) { for (auto& ir : mIRs) { - ir.bc = bc; + ir.bc = 0; // The reset changes depending on the way we synch with the orbit // (see processOrbitTrigger for details) // FIXME: pick one of the two @@ -41,16 +39,6 @@ void GBTOutputHandler::setIR(uint16_t bc, uint32_t orbit, int pageCnt) } mLastClock.fill(constants::lhc::LHCMaxBunches); } - - if (pageCnt == 0) { - // FIXME: in the tests, the BC counter increases at each RDH - // However, the inner clock of the RO is not reset, - // so if we want to have the absolute BC, - // we need to store only the BC counter of the first page. - // Not sure how it will work on data... - mIRFirstPage.bc = bc; - mIRFirstPage.orbit = orbit; - } } bool GBTOutputHandler::checkLoc(size_t ilink, const ELinkDecoder& decoder) @@ -67,7 +55,7 @@ EventType GBTOutputHandler::processSelfTriggered(size_t ilink, uint16_t localClo if ((mReceivedCalibration & linkMask) && (localClock == mExpectedFETClock[ilink])) { // Reset the calibration flag for this e-link mReceivedCalibration &= ~linkMask; - return EventType::Dead; + return EventType::FET; } return EventType::Standard; } @@ -77,7 +65,7 @@ EventType GBTOutputHandler::processCalibrationTrigger(size_t ilink, uint16_t loc /// Processes the calibration event mExpectedFETClock[ilink] = localClock + mElectronicsDelay.calibToFET; mReceivedCalibration |= (1 << ilink); - return EventType::Noise; + return EventType::Calib; } void GBTOutputHandler::processOrbitTrigger(size_t ilink, uint16_t localClock, uint8_t triggerWord) @@ -92,7 +80,7 @@ void GBTOutputHandler::processOrbitTrigger(size_t ilink, uint16_t localClock, ui // (CAVEAT: synch is lost if we have lot of data, spanning over two orbits) // FIXME: pick one of the two ++mIRs[ilink].orbit; // orbit increase - // mIRs[ilink] = mIRFirstPage; // reset to RDH + // mIRs[ilink].orbit = mOrbit; // reset to RDH if ((triggerWord & raw::sSOX) == 0) { mLastClock[ilink] = localClock; } @@ -138,14 +126,14 @@ bool GBTOutputHandler::processTrigger(size_t ilink, const ELinkDecoder& decoder, void GBTOutputHandler::addLoc(size_t ilink, const ELinkDecoder& decoder, EventType eventType, uint16_t correctedClock) { /// Adds the local board to the output data vector - auto firstEntry = mData.size(); - mData.push_back({decoder.getStatusWord(), decoder.getTriggerWord(), crateparams::makeUniqueLocID(crateparams::getCrateIdFromROId(mFeeId), decoder.getId()), decoder.getInputs()}); + auto firstEntry = mData->size(); + mData->push_back({decoder.getStatusWord(), decoder.getTriggerWord(), raw::makeUniqueLocID(crateparams::getCrateIdFromGBTUniqueId(mFeeId), decoder.getId()), decoder.getInputs()}); InteractionRecord intRec(mIRs[ilink].bc + correctedClock, mIRs[ilink].orbit); - mROFRecords.emplace_back(intRec, eventType, firstEntry, 1); + mROFRecords->emplace_back(intRec, eventType, firstEntry, 1); for (int ich = 0; ich < 4; ++ich) { - if ((mData.back().firedChambers & (1 << ich))) { - mData.back().patternsBP[ich] = decoder.getPattern(0, ich); - mData.back().patternsNBP[ich] = decoder.getPattern(1, ich); + if ((mData->back().firedChambers & (1 << ich))) { + mData->back().patternsBP[ich] = decoder.getPattern(0, ich); + mData->back().patternsNBP[ich] = decoder.getPattern(1, ich); } } } @@ -171,7 +159,7 @@ void GBTOutputHandler::onDoneLocDebug(size_t ilink, const ELinkDecoder& decoder) // The local clock is increased when receiving an orbit trigger, // but the local counter returned in answering the trigger // belongs to the previous orbit - --mROFRecords.back().interactionRecord.orbit; + --mROFRecords->back().interactionRecord.orbit; } } @@ -182,8 +170,8 @@ void GBTOutputHandler::onDoneRegDebug(size_t ilink, const ELinkDecoder& decoder) uint16_t correctedClock; processTrigger(ilink, decoder, eventType, correctedClock); // If we want to distinguish the two regional e-links, we can use the link ID instead - auto firstEntry = mData.size(); - mData.push_back({decoder.getStatusWord(), decoder.getTriggerWord(), crateparams::makeUniqueLocID(crateparams::getCrateIdFromROId(mFeeId), ilink + 8 * (crateparams::getGBTIdInCrate(mFeeId) - 1)), decoder.getInputs()}); + auto firstEntry = mData->size(); + mData->push_back({decoder.getStatusWord(), decoder.getTriggerWord(), raw::makeUniqueLocID(crateparams::getCrateIdFromGBTUniqueId(mFeeId), ilink + 8 * (crateparams::getGBTIdInCrate(mFeeId) - 1)), decoder.getInputs()}); auto orbit = (decoder.getTriggerWord() & raw::sORB) ? mIRs[ilink].orbit - 1 : mIRs[ilink].orbit; @@ -202,7 +190,7 @@ void GBTOutputHandler::onDoneRegDebug(size_t ilink, const ELinkDecoder& decoder) // local and regional cards for the checks intRec -= mElectronicsDelay.regToLocal; } - mROFRecords.emplace_back(intRec, eventType, firstEntry, 1); + mROFRecords->emplace_back(intRec, eventType, firstEntry, 1); } } // namespace mid diff --git a/Detectors/MUON/MID/Raw/src/GBTUserLogicDecoder.cxx b/Detectors/MUON/MID/Raw/src/GBTUserLogicDecoder.cxx deleted file mode 100644 index 0e4e78c14dbd2..0000000000000 --- a/Detectors/MUON/MID/Raw/src/GBTUserLogicDecoder.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Raw/src/GBTUserLogicDecoder.cxx -/// \brief MID GBT decoder with user logic zero suppression -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 15 April 2020 - -#include "MIDRaw/GBTUserLogicDecoder.h" - -namespace o2 -{ -namespace mid -{ - -void GBTUserLogicDecoder::init(uint16_t feeId, bool isDebugMode) -{ - /// Initializes the task - mOutputHandler.setFeeId(feeId); - if (isDebugMode) { - mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; - mOnDoneReg = &GBTOutputHandler::onDoneRegDebug; - } -} - -void GBTUserLogicDecoder::process(gsl::span<const uint8_t> bytes, uint16_t bc, uint32_t orbit, uint16_t pageCnt) -{ - /// Decodes the buffer - mOutputHandler.setIR(bc, orbit, pageCnt); - - bool isFeeding = false; - for (auto& byte : bytes) { - if (mELinkDecoder.getNBytes() == 0 && (byte & raw::sSTARTBIT) == 0) { - // The e-link decoder is empty, meaning that we expect a new board. - // The first byte of the board should have the STARTBIT on. - // If this is not the case, it means that: - // a) there was a problem in the decoding - // b) we reached the end of the payload (and we have zeros until the end of the 256 bits word) - // In both cases, we need to stop - break; - } - mELinkDecoder.add(byte); - if (mELinkDecoder.isComplete()) { - if (raw::isLoc(mELinkDecoder.getStatusWord())) { - std::invoke(mOnDoneLoc, mOutputHandler, mELinkDecoder.getId() % 8, mELinkDecoder); - } else { - size_t ilink = 8 + mELinkDecoder.getId() % 8; - if (ilink > 9) { - continue; - } - std::invoke(mOnDoneReg, mOutputHandler, 8 + mELinkDecoder.getId() % 8, mELinkDecoder); - } - mELinkDecoder.reset(); - } - } -} -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/GBTUserLogicEncoder.cxx b/Detectors/MUON/MID/Raw/src/GBTUserLogicEncoder.cxx index 617ec58e67f29..eca5eaf9881f7 100644 --- a/Detectors/MUON/MID/Raw/src/GBTUserLogicEncoder.cxx +++ b/Detectors/MUON/MID/Raw/src/GBTUserLogicEncoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,13 @@ namespace o2 namespace mid { +void GBTUserLogicEncoder::setGBTUniqueId(uint16_t gbtUniqueId) +{ + /// Sets the information associated to the GBT unique ID + mCrateId = crateparams::getCrateIdFromGBTUniqueId(gbtUniqueId); + mOffset = 8 * crateparams::getGBTIdInCrate(gbtUniqueId); +} + void GBTUserLogicEncoder::addShort(std::vector<char>& buffer, uint16_t shortWord) const { /// Adds a 16 bits word @@ -35,11 +43,11 @@ void GBTUserLogicEncoder::processTrigger(const InteractionRecord& ir, uint8_t tr auto& vec = mBoards[ir]; for (uint8_t ireg = 0; ireg < 2; ++ireg) { uint8_t firedLoc = (mMask >> (4 * ireg)) & 0xF; - vec.push_back({raw::sSTARTBIT, triggerWord, ireg, firedLoc}); + vec.push_back({raw::sSTARTBIT, triggerWord, static_cast<uint8_t>(ireg + mOffset), firedLoc}); } for (uint8_t iloc = 0; iloc < 8; ++iloc) { if (mMask & (1 << iloc)) { - vec.push_back({raw::sSTARTBIT | raw::sCARDTYPE, triggerWord, static_cast<uint8_t>(iloc + 8 * crateparams::getGBTIdInCrate(mFeeId)), 0}); + vec.push_back({raw::sSTARTBIT | raw::sCARDTYPE, triggerWord, static_cast<uint8_t>(iloc + mOffset), 0}); if (triggerWord & (raw::sSOX | raw::sEOX)) { /// Write masks for (int ich = 0; ich < 4; ++ich) { @@ -54,25 +62,26 @@ void GBTUserLogicEncoder::processTrigger(const InteractionRecord& ir, uint8_t tr void GBTUserLogicEncoder::addRegionalBoards(uint8_t activeBoards, InteractionRecord ir) { /// Adds the regional board information - ir += mElectronicsDelay.BCToLocal + mElectronicsDelay.regToLocal; + ir += mElectronicsDelay.regToLocal; auto& vec = mBoards[ir]; for (uint8_t ireg = 0; ireg < 2; ++ireg) { uint8_t firedLoc = (activeBoards >> (4 * ireg)) & 0xF; if (firedLoc > 0) { - vec.push_back({raw::sSTARTBIT, 0, ireg, firedLoc}); + vec.push_back({raw::sSTARTBIT, 0, static_cast<uint8_t>(ireg + mOffset), firedLoc}); } } } -void GBTUserLogicEncoder::process(gsl::span<const LocalBoardRO> data, const InteractionRecord& ir) +void GBTUserLogicEncoder::process(gsl::span<const ROBoard> data, InteractionRecord ir) { /// Encode data + ir += mElectronicsDelay.BCToLocal; auto& vec = mBoards[ir]; uint8_t activeBoards = 0; for (auto& loc : data) { for (int ich = 0; ich < 4; ++ich) { if (loc.patternsBP[ich] && loc.patternsNBP[ich]) { - activeBoards |= (1 << (crateparams::getLocId(loc.boardId) % 8)); + activeBoards |= (1 << (raw::getLocId(loc.boardId) % 8)); } } vec.emplace_back(loc); @@ -83,14 +92,15 @@ void GBTUserLogicEncoder::process(gsl::span<const LocalBoardRO> data, const Inte void GBTUserLogicEncoder::flush(std::vector<char>& buffer, const InteractionRecord& ir) { /// Flush buffer - std::map<InteractionRecord, std::vector<LocalBoardRO>> tmpBoards; + std::map<InteractionRecord, std::vector<ROBoard>> tmpBoards; for (auto& item : mBoards) { if (item.first <= ir) { for (auto& loc : item.second) { buffer.emplace_back(loc.statusWord); buffer.emplace_back(loc.triggerWord); addShort(buffer, item.first.bc); - buffer.emplace_back((crateparams::getLocId(loc.boardId) << 4) | loc.firedChambers); + buffer.emplace_back((raw::getLocId(loc.boardId) << 4) | loc.firedChambers); + buffer.emplace_back(mCrateId << 4); if (raw::isLoc(loc.statusWord)) { for (int ich = 4; ich >= 0; --ich) { if (loc.firedChambers & (1 << ich)) { diff --git a/Detectors/MUON/MID/Raw/src/LinkDecoder.cxx b/Detectors/MUON/MID/Raw/src/LinkDecoder.cxx new file mode 100644 index 0000000000000..59a468c239c03 --- /dev/null +++ b/Detectors/MUON/MID/Raw/src/LinkDecoder.cxx @@ -0,0 +1,554 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Raw/src/LinkDecoder.cxx +/// \brief Class interface for the MID GBT decoder +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 07 November 2020 + +#include "MIDRaw/LinkDecoder.h" + +#include "DataFormatsMID/ROBoard.h" +#include "MIDRaw/ELinkManager.h" +#include "MIDRaw/FEEIdConfig.h" +#include "MIDRaw/GBTOutputHandler.h" +#include "MIDRaw/Utils.h" + +namespace o2 +{ +namespace mid +{ +namespace impl +{ + +class GBTUserLogicDecoderImplV2 +{ + public: + GBTUserLogicDecoderImplV2(uint16_t ulFeeId, bool isDebugMode = false, const ElectronicsDelay& electronicsDelay = ElectronicsDelay(), const FEEIdConfig& feeIdConfig = FEEIdConfig()) + { + mElinkManager.init(ulFeeId, isDebugMode, false, electronicsDelay, feeIdConfig); + mELinkDecoder.setBareDecoder(false); + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mElinkManager.set(orbit); + // for (auto& byte : payload) { + auto it = payload.begin(); + auto end = payload.end(); + while (it != end) { + if (mELinkDecoder.isZero(*it)) { + // The e-link decoder is empty, meaning that we expect a new board. + // The first byte of the board should have the STARTBIT on. + // If this is not the case, we move to the next byte. + // Notice that the payload has zeros until the end of the 256 bits word: + // a) when moving from the regional high to regional low + // b) at the end of the HBF + ++it; + continue; + } + + if (mELinkDecoder.add(it, end)) { + mElinkManager.onDone(mELinkDecoder, data, rofs); + mELinkDecoder.reset(); + } + } + } + + private: + ELinkDecoder mELinkDecoder{}; /// E-link decoder + ELinkManager mElinkManager{}; /// ELinkManager +}; + +class GBTUserLogicDecoderImplV1 +{ + public: + GBTUserLogicDecoderImplV1(uint16_t feeId, bool isDebugMode = false, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) + { + mCrateId = crateparams::getCrateIdFromGBTUniqueId(feeId); + mOffset = 8 * crateparams::getGBTIdInCrate(feeId); + mElinkManager.init(feeId, isDebugMode, true, electronicsDelay); + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mElinkManager.set(orbit); + // for (auto& byte : payload) { + auto it = payload.begin(); + auto end = payload.end(); + while (it != end) { + if (mELinkDecoder.isZero(*it)) { + // The e-link decoder is empty, meaning that we expect a new board. + // The first byte of the board should have the STARTBIT on. + // If this is not the case, we move to the next byte. + // Notice that the payload has zeros until the end of the 256 bits word: + // a) when moving from the regional high to regional low + // b) at the end of the HBF + ++it; + continue; + } + + if (mELinkDecoder.add(it, end)) { + mElinkManager.onDone(mELinkDecoder, mCrateId, mOffset + mELinkDecoder.getId() % 8, data, rofs); + mELinkDecoder.reset(); + } + } + } + + private: + uint8_t mCrateId{0}; /// Crate ID + uint8_t mOffset{0}; /// Loc ID offset + ELinkDecoder mELinkDecoder{}; /// E-link decoder + ELinkManager mElinkManager{}; /// ELinkManager +}; + +class GBTUserLogicDecoderImpl +{ + public: + GBTUserLogicDecoderImpl(uint16_t feeId, bool isDebugMode = false, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) + { + mOutputHandler.setGBTUniqueId(feeId); + mOutputHandler.setElectronicsDelay(electronicsDelay); + if (isDebugMode) { + mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; + mOnDoneReg = &GBTOutputHandler::onDoneRegDebug; + } + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mOutputHandler.set(orbit, data, rofs); + // for (auto& byte : payload) { + auto it = payload.begin(); + auto end = payload.end(); + while (it != end) { + if (mELinkDecoder.isZero(*it)) { + // The e-link decoder is empty, meaning that we expect a new board. + // The first byte of the board should have the STARTBIT on. + // If this is not the case, we move to the next byte. + // Notice that the payload has zeros until the end of the 256 bits word: + // a) when moving from the regional high to regional low + // b) at the end of the HBF + ++it; + continue; + } + if (mELinkDecoder.add(it, end)) { + if (raw::isLoc(mELinkDecoder.getStatusWord())) { + std::invoke(mOnDoneLoc, mOutputHandler, mELinkDecoder.getId() % 8, mELinkDecoder); + } else { + size_t ilink = 8 + mELinkDecoder.getId() % 8; + if (ilink <= 9) { + std::invoke(mOnDoneReg, mOutputHandler, ilink, mELinkDecoder); + } + } + mELinkDecoder.reset(); + } + } + } + + private: + GBTOutputHandler mOutputHandler{}; /// GBT output handler + ELinkDecoder mELinkDecoder{}; /// E-link decoder + + typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); + + OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board + OnDoneFunction mOnDoneReg{&GBTOutputHandler::onDoneReg}; ///! Processes the regional board +}; + +class GBTBareDecoderImplV1 +{ + public: + GBTBareDecoderImplV1(uint16_t feeId, bool isDebugMode = false, uint8_t mask = 0xFF, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) : mIsDebugMode(isDebugMode), mMask(mask) + { + /// Constructors + mElinkManager.init(feeId, isDebugMode, true, electronicsDelay); + auto crateId = crateparams::getCrateIdFromGBTUniqueId(feeId); + auto offset = 8 * crateparams::getGBTIdInCrate(feeId); + for (int ilink = 0; ilink < 10; ++ilink) { + mBoardUniqueIds.emplace_back(raw::makeUniqueLocID(crateId, offset + ilink % 8)); + } + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mElinkManager.set(orbit); + mData = &data; + mROFs = &rofs; + + uint8_t byte = 0; + size_t ilink = 0, linkMask = 0, byteOffset = 0; + + for (int ireg = 0; ireg < 2; ++ireg) { + byteOffset = 5 * ireg; + if (mIsDebugMode) { + ilink = 8 + ireg; + linkMask = (1 << ilink); + for (size_t idx = byteOffset + 4; idx < payload.size(); idx += 16) { + byte = payload[idx]; + if ((mIsFeeding & linkMask) || byte) { + processRegDebug(ilink, byte); + } + } + } + for (int ib = 0; ib < 4; ++ib) { + ilink = ib + 4 * ireg; + linkMask = (1 << ilink); + if (mMask & linkMask) { + for (size_t idx = byteOffset + ib; idx < payload.size(); idx += 16) { + byte = payload[idx]; + if ((mIsFeeding & linkMask) || byte) { + processLoc(ilink, byte); + } + } + } + } + } + } + + private: + void processLoc(size_t ilink, uint8_t byte) + { + /// Processes the local board information + auto& decoder = mElinkManager.getDecoder(mBoardUniqueIds[ilink], true); + if (decoder.getNBytes() > 0) { + decoder.addAndComputeSize(byte); + if (decoder.isComplete()) { + mElinkManager.onDone(decoder, mBoardUniqueIds[ilink], *mData, *mROFs); + decoder.reset(); + mIsFeeding &= (~(1 << ilink)); + } + } else if ((byte & (raw::sSTARTBIT | raw::sCARDTYPE)) == (raw::sSTARTBIT | raw::sCARDTYPE)) { + decoder.add(byte); + mIsFeeding |= (1 << ilink); + } + } + + void processRegDebug(size_t ilink, uint8_t byte) + { + /// Processes the regional board information in debug mode + auto& decoder = mElinkManager.getDecoder(mBoardUniqueIds[ilink], false); + if (decoder.getNBytes() > 0) { + decoder.add(byte); + if (decoder.isComplete()) { + mElinkManager.onDone(decoder, mBoardUniqueIds[ilink], *mData, *mROFs); + decoder.reset(); + mIsFeeding &= (~(1 << ilink)); + } + } else if (byte & raw::sSTARTBIT) { + decoder.add(byte); + mIsFeeding |= (1 << ilink); + } + } + + bool mIsDebugMode{false}; /// Debug mode + uint8_t mMask{0xFF}; /// GBT mask + uint16_t mIsFeeding{0}; /// Flag to check if the e-link is feeding + ELinkManager mElinkManager{}; /// ELinkManager + std::vector<uint8_t> mBoardUniqueIds{}; /// Unique board IDs + std::vector<ROBoard>* mData{nullptr}; ///! Data not owner + std::vector<ROFRecord>* mROFs{nullptr}; ///! ROFRecords not owner +}; + +class GBTBareDecoderImpl +{ + public: + GBTBareDecoderImpl(uint16_t feeId, bool isDebugMode = false, uint8_t mask = 0xFF, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) : mIsDebugMode(isDebugMode), mMask(mask) + { + /// Constructor + mOutputHandler.setGBTUniqueId(feeId); + mOutputHandler.setElectronicsDelay(electronicsDelay); + if (isDebugMode) { + mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; + } + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mOutputHandler.set(orbit, data, rofs); + + uint8_t byte = 0; + size_t ilink = 0, linkMask = 0, byteOffset = 0; + + for (int ireg = 0; ireg < 2; ++ireg) { + byteOffset = 5 * ireg; + if (mIsDebugMode) { + ilink = 8 + ireg; + linkMask = (1 << ilink); + for (size_t idx = byteOffset + 4; idx < payload.size(); idx += 16) { + byte = payload[idx]; + if ((mIsFeeding & linkMask) || byte) { + processRegDebug(ilink, byte); + } + } + } + for (int ib = 0; ib < 4; ++ib) { + ilink = ib + 4 * ireg; + linkMask = (1 << ilink); + if (mMask & linkMask) { + for (size_t idx = byteOffset + ib; idx < payload.size(); idx += 16) { + byte = payload[idx]; + if ((mIsFeeding & linkMask) || byte) { + processLoc(ilink, byte); + } + } + } + } + } + } + + private: + void processLoc(size_t ilink, uint8_t byte) + { + /// Processes the local board information + if (mELinkDecoders[ilink].getNBytes() > 0) { + mELinkDecoders[ilink].addAndComputeSize(byte); + if (mELinkDecoders[ilink].isComplete()) { + std::invoke(mOnDoneLoc, mOutputHandler, ilink, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + mIsFeeding &= (~(1 << ilink)); + } + } else if ((byte & (raw::sSTARTBIT | raw::sCARDTYPE)) == (raw::sSTARTBIT | raw::sCARDTYPE)) { + mELinkDecoders[ilink].add(byte); + mIsFeeding |= (1 << ilink); + } + } + + void processRegDebug(size_t ilink, uint8_t byte) + { + /// Processes the regional board information in debug mode + if (mELinkDecoders[ilink].getNBytes() > 0) { + mELinkDecoders[ilink].add(byte); + if (mELinkDecoders[ilink].isComplete()) { + mOutputHandler.onDoneRegDebug(ilink, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + mIsFeeding &= (~(1 << ilink)); + } + } else if (byte & raw::sSTARTBIT) { + mELinkDecoders[ilink].add(byte); + mIsFeeding |= (1 << ilink); + } + } + + bool mIsDebugMode{false}; /// Debug mode + uint8_t mMask{0xFF}; /// GBT mask + uint16_t mIsFeeding{0}; /// Flag to check if the e-link is feeding + GBTOutputHandler mOutputHandler{}; /// GBT output handler + + std::array<ELinkDecoder, crateparams::sNELinksPerGBT> mELinkDecoders{}; /// E-link decoders + + typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); + + OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board +}; + +/// Alternative bare decoder implementation +/// Data are first ranged per link and then each link is decoded in a similar way to what is done for the user logic +/// CAVEAT: abandoned since filling the vector per link is much slower +/// Kept here for future reference (parallelization?) +class GBTBareDecoderLinkImpl +{ + public: + GBTBareDecoderLinkImpl(uint16_t feeId, bool isDebugMode = false, uint8_t mask = 0xFF, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) : mIsDebugMode(isDebugMode), mMask(mask) + { + /// Constructor + mOutputHandler.setGBTUniqueId(feeId); + mOutputHandler.setElectronicsDelay(electronicsDelay); + mIsDebugMode = isDebugMode; + if (isDebugMode) { + mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; + } + mLinkPayload.reserve(0x20000); + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mOutputHandler.set(orbit, data, rofs); + + for (int ireg = 0; ireg < 2; ++ireg) { + size_t byteOffset = 5 * ireg; + + if (mIsDebugMode) { + // Treat regional cards + size_t ilink = 8 + ireg; + mLinkPayload.clear(); + for (size_t idx = byteOffset + 4, end = payload.size(); idx < end; idx += 16) { + mLinkPayload.emplace_back(payload[idx]); + } + auto it = mLinkPayload.begin(); + auto end = mLinkPayload.end(); + while (it != end) { + if (mELinkDecoders[ilink].isZero(*it)) { + ++it; + continue; + } + if (mELinkDecoders[ilink].addCore(it, end)) { + mOutputHandler.onDoneRegDebug(ilink, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + } + } + } + + // Treat local cards + for (int ib = 0; ib < 4; ++ib) { + size_t ilink = ib + 4 * ireg; + if (mMask & (1 << ilink)) { + mLinkPayload.clear(); + for (size_t idx = byteOffset + ib, end = payload.size(); idx < end; idx += 16) { + mLinkPayload.emplace_back(payload[idx]); + } + auto it = mLinkPayload.begin(); + auto end = mLinkPayload.end(); + while (it != end) { + if (mELinkDecoders[ilink].isZero(*it)) { + ++it; + continue; + } + if (mELinkDecoders[ilink].add(it, end)) { + std::invoke(mOnDoneLoc, mOutputHandler, mELinkDecoders[ilink].getId() % 8, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + } + } + } + } + } + } + + private: + bool mIsDebugMode{false}; /// Debug mode + uint8_t mMask{0xFF}; /// GBT mask + GBTOutputHandler mOutputHandler{}; /// GBT output handler + + std::array<ELinkDecoder, crateparams::sNELinksPerGBT> mELinkDecoders{}; /// E-link decoders + std::vector<uint8_t> mLinkPayload{}; /// Link payload + + typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); + + OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board +}; + +/// Alternative implementation of the bare decoder +/// When a start bit is found, we try to add all of the expected bytes. +/// This should in principle allow to avoid performing a check on the expected data size at each newly added byte. +/// But tests show that the implementation is slightly slower than the standard one. +class GBTBareDecoderInsertImpl +{ + public: + GBTBareDecoderInsertImpl(uint16_t feeId, bool isDebugMode = false, uint8_t mask = 0xFF, const ElectronicsDelay& electronicsDelay = ElectronicsDelay()) : mIsDebugMode(isDebugMode), mMask(mask) + { + /// Constructor + mOutputHandler.setGBTUniqueId(feeId); + mOutputHandler.setElectronicsDelay(electronicsDelay); + if (isDebugMode) { + mOnDoneLoc = &GBTOutputHandler::onDoneLocDebug; + } + } + + void operator()(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) + { + /// Decodes the buffer + mOutputHandler.set(orbit, data, rofs); + + size_t step = 16; + size_t end = payload.size(); + + for (int ireg = 0; ireg < 2; ++ireg) { + size_t byteOffset = 5 * ireg; + + if (mIsDebugMode) { + // Treat regional cards + size_t ilink = 8 + ireg; + size_t idx = byteOffset + 4; + + while (idx < end) { + if (mELinkDecoders[ilink].isZero(payload[idx])) { + idx += step; + } else if (mELinkDecoders[ilink].addCore(idx, payload, step)) { + mOutputHandler.onDoneRegDebug(ilink, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + } + } + } + + // Treat local cards + for (int ib = 0; ib < 4; ++ib) { + size_t ilink = ib + 4 * ireg; + if (mMask & (1 << ilink)) { + size_t idx = byteOffset + ib; + while (idx < end) { + if (mELinkDecoders[ilink].isZero(payload[idx])) { + idx += step; + } else if (mELinkDecoders[ilink].add(idx, payload, step)) { + std::invoke(mOnDoneLoc, mOutputHandler, mELinkDecoders[ilink].getId() % 8, mELinkDecoders[ilink]); + mELinkDecoders[ilink].reset(); + } + } + } + } + } + } + + private: + uint8_t mMask{0xFF}; /// GBT mask + bool mIsDebugMode{false}; /// Debug mode + GBTOutputHandler mOutputHandler{}; /// GBT output handler + + std::array<ELinkDecoder, crateparams::sNELinksPerGBT> mELinkDecoders{}; /// E-link decoders + + typedef void (GBTOutputHandler::*OnDoneFunction)(size_t, const ELinkDecoder&); + + OnDoneFunction mOnDoneLoc{&GBTOutputHandler::onDoneLoc}; ///! Processes the local board +}; + +} // namespace impl + +void LinkDecoder::process(gsl::span<const uint8_t> payload, uint32_t orbit, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs) +{ + /// Decodes the data + mDecode(payload, orbit, data, rofs); +} + +std::unique_ptr<LinkDecoder> createGBTDecoder(const o2::header::RDHAny& rdh, uint16_t feeId, bool isDebugMode, uint8_t mask, const ElectronicsDelay& electronicsDelay) +{ + /// Creates the correct implementation of the GBT decoder + if (raw::isBare(rdh)) { + return std::make_unique<LinkDecoder>(impl::GBTBareDecoderImplV1(feeId, isDebugMode, mask, electronicsDelay)); + } + std::cout << "Error: GBT decoder not defined for UL. Please use Link decoder instead" << std::endl; + return nullptr; +} + +std::unique_ptr<LinkDecoder> createLinkDecoder(const o2::header::RDHAny& rdh, uint16_t feeId, bool isDebugMode, uint8_t mask, const ElectronicsDelay& electronicsDelay, const FEEIdConfig& feeIdConfig) +{ + /// Creates the correct implementation of the GBT decoder + if (raw::isBare(rdh)) { + return std::make_unique<LinkDecoder>(impl::GBTBareDecoderImplV1(feeId, isDebugMode, mask, electronicsDelay)); + } + return std::make_unique<LinkDecoder>(impl::GBTUserLogicDecoderImplV2(feeId, isDebugMode, electronicsDelay, feeIdConfig)); +} + +std::unique_ptr<LinkDecoder> createLinkDecoder(uint16_t feeId, bool isBare, bool isDebugMode, uint8_t mask, const ElectronicsDelay& electronicsDelay, const FEEIdConfig& feeIdConfig) +{ + /// Creates the correct implementation of the GBT decoder + if (isBare) { + return std::make_unique<LinkDecoder>(impl::GBTBareDecoderImplV1(feeId, isDebugMode, mask, electronicsDelay)); + } + return std::make_unique<LinkDecoder>(impl::GBTUserLogicDecoderImplV2(feeId, isDebugMode, electronicsDelay, feeIdConfig)); +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/LocalBoardRO.cxx b/Detectors/MUON/MID/Raw/src/LocalBoardRO.cxx deleted file mode 100644 index 29b5b0c29ad58..0000000000000 --- a/Detectors/MUON/MID/Raw/src/LocalBoardRO.cxx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Raw/src/LocalBoardRO.cxx -/// \brief Structure to store the FEE local board information -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 19 November 2019 - -#include "MIDRaw/LocalBoardRO.h" - -#include <iostream> -#include "fmt/format.h" -#include "MIDRaw/CrateParameters.h" - -namespace o2 -{ -namespace mid -{ -std::ostream& operator<<(std::ostream& os, const LocalBoardRO& loc) -{ - /// Stream operator for LocalBoardRO - os << fmt::format("Crate ID: {:2d} Loc ID: {:2d} status: 0x{:2x} trigger: 0x{:2x} firedChambers: 0x{:1x}", static_cast<int>(crateparams::getCrateId(loc.boardId)), static_cast<int>(crateparams::getLocId(loc.boardId)), static_cast<int>(loc.statusWord), static_cast<int>(loc.triggerWord), static_cast<int>(loc.firedChambers)); - for (int ich = 0; ich < 4; ++ich) { - os << fmt::format(" X: 0x{:4x} Y: 0x{:4x}", loc.patternsBP[ich], loc.patternsNBP[ich]); - } - return os; -} - -} // namespace mid -} // namespace o2 \ No newline at end of file diff --git a/Detectors/MUON/MID/Raw/src/RawFileReader.cxx b/Detectors/MUON/MID/Raw/src/RawFileReader.cxx index a039749839075..96d5b468f189e 100644 --- a/Detectors/MUON/MID/Raw/src/RawFileReader.cxx +++ b/Detectors/MUON/MID/Raw/src/RawFileReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Raw/test/CMakeLists.txt b/Detectors/MUON/MID/Raw/test/CMakeLists.txt index 1099125bfc68c..45ba91f220103 100644 --- a/Detectors/MUON/MID/Raw/test/CMakeLists.txt +++ b/Detectors/MUON/MID/Raw/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test( Raw diff --git a/Detectors/MUON/MID/Raw/test/bench_Raw.cxx b/Detectors/MUON/MID/Raw/test/bench_Raw.cxx index f2a66b98231dd..6c8615fc95156 100644 --- a/Detectors/MUON/MID/Raw/test/bench_Raw.cxx +++ b/Detectors/MUON/MID/Raw/test/bench_Raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,10 +20,11 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DetectorsRaw/RawFileReader.h" #include "DPLUtils/RawParser.h" +#include "DataFormatsMID/ColumnData.h" #include "MIDBase/DetectorParameters.h" #include "MIDRaw/Decoder.h" -#include "MIDRaw/GBTUserLogicDecoder.h" #include "MIDRaw/Encoder.h" +#include "MIDRaw/LinkDecoder.h" o2::mid::ColumnData getColData(uint8_t deId, uint8_t columnId, uint16_t nbp = 0, uint16_t bp1 = 0, uint16_t bp2 = 0, uint16_t bp3 = 0, uint16_t bp4 = 0) { @@ -60,10 +62,10 @@ std::vector<uint8_t> generateTestData(size_t nTF, size_t nDataInTF, size_t nColD auto severity = fair::Logger::GetConsoleSeverity(); fair::Logger::SetConsoleSeverity(fair::Severity::WARNING); - std::string tmpFilename = "tmp_mid_raw.dat"; o2::mid::Encoder encoder; - encoder.init(tmpFilename.c_str()); - + encoder.init(); + std::string tmpConfigFilename = "tmp_MIDConfig.cfg"; + encoder.getWriter().writeConfFile("MID", "RAWDATA", tmpConfigFilename.c_str(), false); // Fill TF for (size_t itf = 0; itf < nTF; ++itf) { for (int ilocal = 0; ilocal < nDataInTF; ++ilocal) { @@ -73,8 +75,7 @@ std::vector<uint8_t> generateTestData(size_t nTF, size_t nDataInTF, size_t nColD } encoder.finalize(); - o2::raw::RawFileReader rawReader; - rawReader.addFile(tmpFilename.c_str()); + o2::raw::RawFileReader rawReader(tmpConfigFilename.c_str()); rawReader.init(); size_t nActiveLinks = rawReader.getNLinks() < nLinks ? rawReader.getNLinks() : nLinks; std::vector<char> buffer; @@ -93,7 +94,8 @@ std::vector<uint8_t> generateTestData(size_t nTF, size_t nDataInTF, size_t nColD } fair::Logger::SetConsoleSeverity(severity); - std::remove(tmpFilename.c_str()); + std::remove("MID.raw"); + std::remove(tmpConfigFilename.c_str()); std::vector<uint8_t> data(buffer.size()); memcpy(data.data(), buffer.data(), buffer.size()); @@ -103,7 +105,7 @@ std::vector<uint8_t> generateTestData(size_t nTF, size_t nDataInTF, size_t nColD static void BM_Decoder(benchmark::State& state) { - o2::mid::Decoder<o2::mid::GBTUserLogicDecoder> decoder; + o2::mid::Decoder decoder; int nTF = state.range(0); int nEventPerTF = state.range(1); @@ -120,10 +122,9 @@ static void BM_Decoder(benchmark::State& state) state.counters["num"] = benchmark::Counter(num, benchmark::Counter::kIsRate); } -static void BM_GBTDecoder(benchmark::State& state) +static void BM_LinkDecoder(benchmark::State& state) { - o2::mid::GBTUserLogicDecoder decoder; - decoder.init(0, false); + auto decoder = o2::mid::createLinkDecoder(0); int nTF = state.range(0); int nEventPerTF = state.range(1); @@ -131,9 +132,12 @@ static void BM_GBTDecoder(benchmark::State& state) double num{0}; auto inputData = generateTestData(nTF, nEventPerTF, nFiredPerEvent, 1); + std::vector<o2::mid::ROBoard> data; + std::vector<o2::mid::ROFRecord> rofs; for (auto _ : state) { - decoder.clear(); + data.clear(); + rofs.clear(); o2::framework::RawParser parser(inputData.data(), inputData.size()); for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { if (it.size() == 0) { @@ -141,7 +145,7 @@ static void BM_GBTDecoder(benchmark::State& state) } auto* rdhPtr = it.template get_if<o2::header::RAWDataHeader>(); gsl::span<const uint8_t> payload(it.data(), it.size()); - decoder.process(payload, *rdhPtr); + decoder->process(payload, *rdhPtr, data, rofs); } ++num; } @@ -160,7 +164,7 @@ static void CustomArguments(benchmark::internal::Benchmark* bench) bench->Args({1, 100, 4}); } -BENCHMARK(BM_GBTDecoder)->Apply(CustomArguments)->Unit(benchmark::kNanosecond); +BENCHMARK(BM_LinkDecoder)->Apply(CustomArguments)->Unit(benchmark::kNanosecond); BENCHMARK(BM_Decoder)->Apply(CustomArguments)->Unit(benchmark::kNanosecond); BENCHMARK_MAIN(); diff --git a/Detectors/MUON/MID/Raw/test/testCrateMapper.cxx b/Detectors/MUON/MID/Raw/test/testCrateMapper.cxx index c00cd61ba0b67..7d5342714d4eb 100644 --- a/Detectors/MUON/MID/Raw/test/testCrateMapper.cxx +++ b/Detectors/MUON/MID/Raw/test/testCrateMapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include <boost/test/data/test_case.hpp> #include <iostream> +#include "DataFormatsMID/ROBoard.h" #include "MIDBase/Mapping.h" #include "MIDBase/DetectorParameters.h" #include "MIDRaw/CrateMapper.h" @@ -80,8 +82,8 @@ BOOST_AUTO_TEST_CASE(Consistency) for (int icol = mapping.getFirstColumn(ide); icol < 7; ++icol) { for (int iline = mapping.getFirstBoardBP(icol, ide); iline <= mapping.getLastBoardBP(icol, ide); ++iline) { auto uniqueLocId = crateMapper.deLocalBoardToRO(ide, icol, iline); - auto crateId = o2::mid::crateparams::getCrateId(uniqueLocId); - auto deBoardId = crateMapper.roLocalBoardToDE(crateId, o2::mid::crateparams::getLocId(uniqueLocId)); + auto crateId = o2::mid::raw::getCrateId(uniqueLocId); + auto deBoardId = crateMapper.roLocalBoardToDE(crateId, o2::mid::raw::getLocId(uniqueLocId)); BOOST_TEST(static_cast<int>(crateMapper.getColumnId(deBoardId)) == icol); BOOST_TEST(static_cast<int>(crateMapper.getLineId(deBoardId)) == iline); int rpcLineId = crateMapper.getRPCLine(deBoardId); diff --git a/Detectors/MUON/MID/Raw/test/testRaw.cxx b/Detectors/MUON/MID/Raw/test/testRaw.cxx index 2859ac6f83b8a..2a931cf322cd7 100644 --- a/Detectors/MUON/MID/Raw/test/testRaw.cxx +++ b/Detectors/MUON/MID/Raw/test/testRaw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,9 +33,9 @@ #include "MIDRaw/CrateParameters.h" #include "MIDRaw/DecodedDataAggregator.h" #include "MIDRaw/Decoder.h" -#include "MIDRaw/GBTUserLogicDecoder.h" -#include "MIDRaw/GBTUserLogicEncoder.h" #include "MIDRaw/Encoder.h" +#include "MIDRaw/GBTUserLogicEncoder.h" +#include "MIDRaw/LinkDecoder.h" BOOST_AUTO_TEST_SUITE(o2_mid_raw) @@ -54,7 +55,7 @@ o2::mid::ColumnData getColData(uint8_t deId, uint8_t columnId, uint16_t nbp = 0, std::vector<o2::mid::ColumnData> sortData(const std::vector<o2::mid::ColumnData>& data, size_t first, size_t last) { std::vector<o2::mid::ColumnData> sortedData(data.begin() + first, data.begin() + last); - std::sort(sortedData.begin(), sortedData.end(), [](o2::mid::ColumnData& a, o2::mid::ColumnData& b) { if (a.deId == b.deId ) { return (a.columnId < b.columnId); + std::sort(sortedData.begin(), sortedData.end(), [](o2::mid::ColumnData& a, o2::mid::ColumnData& b) { if (a.deId == b.deId ) { return (a.columnId < b.columnId); }return (a.deId < b.deId); }); return sortedData; @@ -87,10 +88,8 @@ std::tuple<std::vector<o2::mid::ColumnData>, std::vector<o2::mid::ROFRecord>> en { auto severity = fair::Logger::GetConsoleSeverity(); fair::Logger::SetConsoleSeverity(fair::Severity::WARNING); - std::string tmpFilename0 = "tmp_mid_raw"; - std::string tmpFilename = tmpFilename0 + ".raw"; o2::mid::Encoder encoder; - encoder.init(tmpFilename0.c_str()); + encoder.init(); std::string tmpConfigFilename = "tmp_MIDConfig.cfg"; encoder.getWriter().writeConfFile("MID", "RAWDATA", tmpConfigFilename.c_str(), false); for (auto& item : inData) { @@ -116,10 +115,10 @@ std::tuple<std::vector<o2::mid::ColumnData>, std::vector<o2::mid::ROFRecord>> en } fair::Logger::SetConsoleSeverity(severity); - std::remove(tmpFilename.c_str()); + std::remove("MID.raw"); std::remove(tmpConfigFilename.c_str()); - o2::mid::Decoder<o2::mid::GBTUserLogicDecoder> decoder; + o2::mid::Decoder decoder; gsl::span<const uint8_t> data(reinterpret_cast<uint8_t*>(buffer.data()), buffer.size()); decoder.process(data); @@ -145,7 +144,7 @@ BOOST_AUTO_TEST_CASE(ColumnDataConverter) inData[ir].emplace_back(getColData(14, 1, 0, 0, 0, 0xFF)); std::vector<o2::mid::ROFRecord> rofs; - std::vector<o2::mid::LocalBoardRO> outData; + std::vector<o2::mid::ROBoard> outData; auto inEventType = o2::mid::EventType::Standard; o2::mid::ColumnDataToLocalBoard converter; converter.setDebugMode(true); @@ -170,9 +169,9 @@ BOOST_AUTO_TEST_CASE(GBTUserLogicDecoder) { /// Event with just one link fired - std::map<uint16_t, std::vector<o2::mid::LocalBoardRO>> inData; + std::map<uint16_t, std::vector<o2::mid::ROBoard>> inData; uint16_t bc = 100; - o2::mid::LocalBoardRO loc; + o2::mid::ROBoard loc; // Crate 5 link 0 loc.statusWord = o2::mid::raw::sSTARTBIT | o2::mid::raw::sCARDTYPE; loc.triggerWord = 0; @@ -191,11 +190,12 @@ BOOST_AUTO_TEST_CASE(GBTUserLogicDecoder) loc.patternsNBP[2] = 0x5; inData[bc].emplace_back(loc); + o2::mid::FEEIdConfig feeIdConfig; uint8_t crateId = 5; uint8_t linkInCrate = 0; - uint16_t feeId = o2::mid::crateparams::makeROId(crateId, linkInCrate); + uint16_t gbtUniqueId = o2::mid::crateparams::makeGBTUniqueId(crateId, linkInCrate); o2::mid::GBTUserLogicEncoder encoder; - encoder.setFeeId(feeId); + encoder.setGBTUniqueId(gbtUniqueId); for (auto& item : inData) { encoder.process(item.second, o2::InteractionRecord(item.first, 0)); } @@ -204,23 +204,25 @@ BOOST_AUTO_TEST_CASE(GBTUserLogicDecoder) o2::header::RAWDataHeader rdh; auto memSize = buf.size() + 64; rdh.word1 |= (memSize | (memSize << 16)); - // Sets the feeId - rdh.word0 |= ((5 * 2) << 16); - o2::mid::GBTUserLogicDecoder decoder; - decoder.init(feeId); + // Sets the linkId + uint16_t feeId = feeIdConfig.getFEEId(gbtUniqueId); + rdh.word0 |= (feeId << 16); + auto decoder = o2::mid::createLinkDecoder(feeId); + std::vector<o2::mid::ROBoard> data; + std::vector<o2::mid::ROFRecord> rofs; std::vector<uint8_t> convertedBuffer(buf.size()); memcpy(convertedBuffer.data(), buf.data(), buf.size()); - decoder.process(convertedBuffer, rdh); - BOOST_REQUIRE(decoder.getROFRecords().size() == inData.size()); + decoder->process(convertedBuffer, rdh, data, rofs); + BOOST_REQUIRE(rofs.size() == inData.size()); auto inItMap = inData.begin(); - for (auto rofIt = decoder.getROFRecords().begin(); rofIt != decoder.getROFRecords().end(); ++rofIt) { + for (auto rofIt = rofs.begin(); rofIt != rofs.end(); ++rofIt) { BOOST_TEST(rofIt->interactionRecord.bc == inItMap->first); BOOST_TEST(rofIt->nEntries == inItMap->second.size()); - auto outLoc = decoder.getData().begin() + rofIt->firstEntry; + auto outLoc = data.begin() + rofIt->firstEntry; for (auto inLoc = inItMap->second.begin(); inLoc != inItMap->second.end(); ++inLoc) { BOOST_TEST(inLoc->statusWord == outLoc->statusWord); BOOST_TEST(inLoc->triggerWord == outLoc->triggerWord); - BOOST_TEST(o2::mid::crateparams::makeUniqueLocID(crateId, inLoc->boardId) == outLoc->boardId); + BOOST_TEST(o2::mid::raw::makeUniqueLocID(crateId, inLoc->boardId) == outLoc->boardId); BOOST_TEST(inLoc->firedChambers == outLoc->firedChambers); for (int ich = 0; ich < 4; ++ich) { BOOST_TEST(inLoc->patternsBP[ich] == outLoc->patternsBP[ich]); diff --git a/Detectors/MUON/MID/Simulation/CMakeLists.txt b/Detectors/MUON/MID/Simulation/CMakeLists.txt index 3b0519916d51d..27c65224b42c3 100644 --- a/Detectors/MUON/MID/Simulation/CMakeLists.txt +++ b/Detectors/MUON/MID/Simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( MIDSimulation diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberEfficiencyResponse.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberEfficiencyResponse.h index e60352415286c..5b744654b917c 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberEfficiencyResponse.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberEfficiencyResponse.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberHV.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberHV.h index 6592fd92052af..d6f7667e0624d 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberHV.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberHV.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponse.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponse.h index 8d8fbc4b0f325..550264ceb6306 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponse.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponse.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponseParams.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponseParams.h index ff5569a4801bf..dbbc02ffef691 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponseParams.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ChamberResponseParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ClusterLabeler.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ClusterLabeler.h index bbf0a4db6ecbb..8bd50f078c54d 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ClusterLabeler.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ClusterLabeler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ColumnDataMC.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ColumnDataMC.h index dc3f357357433..903259be608d9 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/ColumnDataMC.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/ColumnDataMC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Detector.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Detector.h index 20a9cb4782278..f44093fce0bfa 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Detector.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Digitizer.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Digitizer.h index e1165f727198d..50f0abbfe4151 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Digitizer.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/DigitsMerger.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/DigitsMerger.h index 4e6d39857867b..4ec957f220bde 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/DigitsMerger.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/DigitsMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Geometry.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Geometry.h index 5938808441fc1..e53d01a4c1a03 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Geometry.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Hit.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Hit.h index 62c5623018a49..01a3bf8d0fab4 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Hit.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCClusterLabel.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCClusterLabel.h index 4c1a625c811ec..2aaa49c7d7a2a 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCClusterLabel.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCClusterLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCLabel.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCLabel.h index 1baf65bac060a..ecc03459406a6 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCLabel.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/PreClusterLabeler.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/PreClusterLabeler.h index 0d2fc7cdf117a..733b29c971fdc 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/PreClusterLabeler.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/PreClusterLabeler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Stepper.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Stepper.h index 1c3551563f930..fdc712ed26496 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/Stepper.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/Stepper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/include/MIDSimulation/TrackLabeler.h b/Detectors/MUON/MID/Simulation/include/MIDSimulation/TrackLabeler.h index 7793d7488d3b4..cb100113b8ff5 100644 --- a/Detectors/MUON/MID/Simulation/include/MIDSimulation/TrackLabeler.h +++ b/Detectors/MUON/MID/Simulation/include/MIDSimulation/TrackLabeler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/ChamberEfficiencyResponse.cxx b/Detectors/MUON/MID/Simulation/src/ChamberEfficiencyResponse.cxx index bc3b6de5751ae..69a8fca3ab6fa 100644 --- a/Detectors/MUON/MID/Simulation/src/ChamberEfficiencyResponse.cxx +++ b/Detectors/MUON/MID/Simulation/src/ChamberEfficiencyResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/ChamberHV.cxx b/Detectors/MUON/MID/Simulation/src/ChamberHV.cxx index b6e4cf5bc8449..78a6d12d37fbc 100644 --- a/Detectors/MUON/MID/Simulation/src/ChamberHV.cxx +++ b/Detectors/MUON/MID/Simulation/src/ChamberHV.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/ChamberResponse.cxx b/Detectors/MUON/MID/Simulation/src/ChamberResponse.cxx index 638f00d791138..fa86401c12b75 100644 --- a/Detectors/MUON/MID/Simulation/src/ChamberResponse.cxx +++ b/Detectors/MUON/MID/Simulation/src/ChamberResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/ChamberResponseParams.cxx b/Detectors/MUON/MID/Simulation/src/ChamberResponseParams.cxx index adb7902bfcffb..11118529ed005 100644 --- a/Detectors/MUON/MID/Simulation/src/ChamberResponseParams.cxx +++ b/Detectors/MUON/MID/Simulation/src/ChamberResponseParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/ClusterLabeler.cxx b/Detectors/MUON/MID/Simulation/src/ClusterLabeler.cxx index f07712770b7e5..ae599f31441c9 100644 --- a/Detectors/MUON/MID/Simulation/src/ClusterLabeler.cxx +++ b/Detectors/MUON/MID/Simulation/src/ClusterLabeler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Detector.cxx b/Detectors/MUON/MID/Simulation/src/Detector.cxx index e25b22ddbd5ef..0f2fc9e3512e1 100644 --- a/Detectors/MUON/MID/Simulation/src/Detector.cxx +++ b/Detectors/MUON/MID/Simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Digitizer.cxx b/Detectors/MUON/MID/Simulation/src/Digitizer.cxx index 210440d9ac147..9001c2cf874d5 100644 --- a/Detectors/MUON/MID/Simulation/src/Digitizer.cxx +++ b/Detectors/MUON/MID/Simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/DigitsMerger.cxx b/Detectors/MUON/MID/Simulation/src/DigitsMerger.cxx index b2dc8c66eb93f..727556228484d 100644 --- a/Detectors/MUON/MID/Simulation/src/DigitsMerger.cxx +++ b/Detectors/MUON/MID/Simulation/src/DigitsMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Geometry.cxx b/Detectors/MUON/MID/Simulation/src/Geometry.cxx index 2376de68794cf..8452d4e5a7f49 100644 --- a/Detectors/MUON/MID/Simulation/src/Geometry.cxx +++ b/Detectors/MUON/MID/Simulation/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Hit.cxx b/Detectors/MUON/MID/Simulation/src/Hit.cxx index 395f7566835a0..cb25b978034dd 100644 --- a/Detectors/MUON/MID/Simulation/src/Hit.cxx +++ b/Detectors/MUON/MID/Simulation/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/MCClusterLabel.cxx b/Detectors/MUON/MID/Simulation/src/MCClusterLabel.cxx index 0c55d19a12f96..eb1625db928ea 100644 --- a/Detectors/MUON/MID/Simulation/src/MCClusterLabel.cxx +++ b/Detectors/MUON/MID/Simulation/src/MCClusterLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/MCLabel.cxx b/Detectors/MUON/MID/Simulation/src/MCLabel.cxx index 89fedb866c719..379d6dffcd320 100644 --- a/Detectors/MUON/MID/Simulation/src/MCLabel.cxx +++ b/Detectors/MUON/MID/Simulation/src/MCLabel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/MIDSimulationLinkDef.h b/Detectors/MUON/MID/Simulation/src/MIDSimulationLinkDef.h index 6e13937856a27..16f7cd630fcb0 100644 --- a/Detectors/MUON/MID/Simulation/src/MIDSimulationLinkDef.h +++ b/Detectors/MUON/MID/Simulation/src/MIDSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Materials.cxx b/Detectors/MUON/MID/Simulation/src/Materials.cxx index 4a9bc172b9976..b6aeac75f8da8 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.cxx +++ b/Detectors/MUON/MID/Simulation/src/Materials.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Materials.h b/Detectors/MUON/MID/Simulation/src/Materials.h index 7662eab694e60..7461669f25e74 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.h +++ b/Detectors/MUON/MID/Simulation/src/Materials.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/PreClusterLabeler.cxx b/Detectors/MUON/MID/Simulation/src/PreClusterLabeler.cxx index 7311d97b70ce3..18021d3c35cb5 100644 --- a/Detectors/MUON/MID/Simulation/src/PreClusterLabeler.cxx +++ b/Detectors/MUON/MID/Simulation/src/PreClusterLabeler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/src/Stepper.cxx b/Detectors/MUON/MID/Simulation/src/Stepper.cxx index 59451eafbc6a8..7a9abbc4adf43 100644 --- a/Detectors/MUON/MID/Simulation/src/Stepper.cxx +++ b/Detectors/MUON/MID/Simulation/src/Stepper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #include "MIDSimulation/Stepper.h" #include "CommonUtils/ShmAllocator.h" +#include "DetectorsCommonDataFormats/DetID.h" #include "SimulationDataFormat/Stack.h" #include "SimulationDataFormat/TrackReference.h" #include "TVirtualMC.h" @@ -46,7 +48,8 @@ bool Stepper::process(const TVirtualMC& vmc) if (ts.isEntering() || ts.isExiting()) { // generate a track referenced - o2::TrackReference tr{vmc, detElemId}; + o2::TrackReference tr{vmc, o2::detectors::DetID::MID}; + tr.setUserId(detElemId); stack->addTrackReference(tr); } diff --git a/Detectors/MUON/MID/Simulation/src/TrackLabeler.cxx b/Detectors/MUON/MID/Simulation/src/TrackLabeler.cxx index 8508e2c2a2680..88abcf7853292 100644 --- a/Detectors/MUON/MID/Simulation/src/TrackLabeler.cxx +++ b/Detectors/MUON/MID/Simulation/src/TrackLabeler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/test/CMakeLists.txt b/Detectors/MUON/MID/Simulation/test/CMakeLists.txt index 124440c7bbbc7..0f12657282388 100644 --- a/Detectors/MUON/MID/Simulation/test/CMakeLists.txt +++ b/Detectors/MUON/MID/Simulation/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(Geometry SOURCES testGeometry.cxx diff --git a/Detectors/MUON/MID/Simulation/test/testGeometry.cxx b/Detectors/MUON/MID/Simulation/test/testGeometry.cxx index 785e030925c3d..3c5a0f99ed379 100644 --- a/Detectors/MUON/MID/Simulation/test/testGeometry.cxx +++ b/Detectors/MUON/MID/Simulation/test/testGeometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Simulation/test/testSimulation.cxx b/Detectors/MUON/MID/Simulation/test/testSimulation.cxx index 47c92c41cf7c6..97402ed0475e1 100644 --- a/Detectors/MUON/MID/Simulation/test/testSimulation.cxx +++ b/Detectors/MUON/MID/Simulation/test/testSimulation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,6 +43,14 @@ namespace o2 namespace mid { +std::vector<ColumnData> getColumnDataNonMC(const o2::mid::DigitsMerger& dm) +{ + std::vector<ColumnData> v; + auto ref = dm.getColumnData(); + v.insert(v.begin(), ref.begin(), ref.end()); + return v; +} + Digitizer createDigitizerNoClusterSize() { /// Returns the default chamber response @@ -395,7 +404,7 @@ BOOST_DATA_TEST_CASE(MID_SingleCluster, boost::unit_test::data::make(getDEList() rofRecords.clear(); rofRecords.emplace_back(o2::constants::lhc::LHCBunchSpacingNS * ievent, EventType::Standard, 0, digitStoreMC.size()); simDigitizer.digitsMerger.process(digitStoreMC, digitLabelsMC, rofRecords); - simClustering.preClusterizer.process(simDigitizer.digitsMerger.getColumnData(), simDigitizer.digitsMerger.getROFRecords()); + simClustering.preClusterizer.process(getColumnDataNonMC(simDigitizer.digitsMerger), simDigitizer.digitsMerger.getROFRecords()); simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords()); nRecoClusters = simClustering.clusterizer.getClusters().size(); ss << "nRecoClusters: " << nRecoClusters << " nGenClusters: " << nGenClusters << "\n"; @@ -438,7 +447,7 @@ BOOST_DATA_TEST_CASE(MID_SimClusters, boost::unit_test::data::make(getDEList()), digitLabelsAccum.mergeAtBack(digitLabelsMC); } simDigitizer.digitsMerger.process(digitsAccum, digitLabelsAccum, digitsROF); - simClustering.preClusterizer.process(simDigitizer.digitsMerger.getColumnData(), simDigitizer.digitsMerger.getROFRecords()); + simClustering.preClusterizer.process(getColumnDataNonMC(simDigitizer.digitsMerger), simDigitizer.digitsMerger.getROFRecords()); simClustering.correlation.clear(); simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords()); simClustering.preClusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simDigitizer.digitsMerger.getMCContainer(), simClustering.preClusterizer.getROFRecords(), simDigitizer.digitsMerger.getROFRecords()); @@ -532,7 +541,7 @@ BOOST_DATA_TEST_CASE(MID_SimTracks, boost::unit_test::data::make({1, 2, 3, 4, 5, } simDigitizer.digitsMerger.process(digitsAccum, digitLabelsAccum, digitsROF); - simClustering.preClusterizer.process(simDigitizer.digitsMerger.getColumnData(), simDigitizer.digitsMerger.getROFRecords()); + simClustering.preClusterizer.process(getColumnDataNonMC(simDigitizer.digitsMerger), simDigitizer.digitsMerger.getROFRecords()); simClustering.correlation.clear(); simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords()); simClustering.preClusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simDigitizer.digitsMerger.getMCContainer(), simClustering.preClusterizer.getROFRecords(), simDigitizer.digitsMerger.getROFRecords()); diff --git a/Detectors/MUON/MID/TestingSimTools/CMakeLists.txt b/Detectors/MUON/MID/TestingSimTools/CMakeLists.txt index e4ee6bc51ab62..fe3eff865f3c0 100644 --- a/Detectors/MUON/MID/TestingSimTools/CMakeLists.txt +++ b/Detectors/MUON/MID/TestingSimTools/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MIDTestingSimTools SOURCES src/HitFinder.cxx src/TrackGenerator.cxx diff --git a/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/HitFinder.h b/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/HitFinder.h index b86ddb96984fa..45ccea9b908d9 100644 --- a/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/HitFinder.h +++ b/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/HitFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/TrackGenerator.h b/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/TrackGenerator.h index 2e2a6869e80bf..8ac849fb54691 100644 --- a/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/TrackGenerator.h +++ b/Detectors/MUON/MID/TestingSimTools/include/MIDTestingSimTools/TrackGenerator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/TestingSimTools/src/HitFinder.cxx b/Detectors/MUON/MID/TestingSimTools/src/HitFinder.cxx index 6f39180deaa2b..5d5cf6fdf4db4 100644 --- a/Detectors/MUON/MID/TestingSimTools/src/HitFinder.cxx +++ b/Detectors/MUON/MID/TestingSimTools/src/HitFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/TestingSimTools/src/TrackGenerator.cxx b/Detectors/MUON/MID/TestingSimTools/src/TrackGenerator.cxx index cc715959f6a6d..a8ed2a69720ef 100644 --- a/Detectors/MUON/MID/TestingSimTools/src/TrackGenerator.cxx +++ b/Detectors/MUON/MID/TestingSimTools/src/TrackGenerator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Tracking/CMakeLists.txt b/Detectors/MUON/MID/Tracking/CMakeLists.txt index 7bdac9d67ce8e..8746383935667 100644 --- a/Detectors/MUON/MID/Tracking/CMakeLists.txt +++ b/Detectors/MUON/MID/Tracking/CMakeLists.txt @@ -1,17 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(MIDTracking SOURCES src/Tracker.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsMID O2::MIDBase - O2::MIDTestingSimTools ms_gsl::ms_gsl) + O2::MIDTestingSimTools Microsoft.GSL::GSL) if(BUILD_TESTING) add_subdirectory(test) diff --git a/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h b/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h index 52fa2a0b8eee2..076a9f21180dc 100644 --- a/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h +++ b/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Tracking/src/Tracker.cxx b/Detectors/MUON/MID/Tracking/src/Tracker.cxx index dc7396f9465f4..7ad27419951f9 100644 --- a/Detectors/MUON/MID/Tracking/src/Tracker.cxx +++ b/Detectors/MUON/MID/Tracking/src/Tracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Tracking/test/CMakeLists.txt b/Detectors/MUON/MID/Tracking/test/CMakeLists.txt index 537f347f8c9fa..996534bcf70b5 100644 --- a/Detectors/MUON/MID/Tracking/test/CMakeLists.txt +++ b/Detectors/MUON/MID/Tracking/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(Tracker SOURCES testTracker.cxx diff --git a/Detectors/MUON/MID/Tracking/test/bench_Tracker.cxx b/Detectors/MUON/MID/Tracking/test/bench_Tracker.cxx index 1ce5c34203959..1d90dc7351018 100644 --- a/Detectors/MUON/MID/Tracking/test/bench_Tracker.cxx +++ b/Detectors/MUON/MID/Tracking/test/bench_Tracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Tracking/test/testTracker.cxx b/Detectors/MUON/MID/Tracking/test/testTracker.cxx index 13d20ef05341b..4ca369664043e 100644 --- a/Detectors/MUON/MID/Tracking/test/testTracker.cxx +++ b/Detectors/MUON/MID/Tracking/test/testTracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/CMakeLists.txt b/Detectors/MUON/MID/Workflow/CMakeLists.txt index 1bb8568e2124d..ac75b182981f3 100644 --- a/Detectors/MUON/MID/Workflow/CMakeLists.txt +++ b/Detectors/MUON/MID/Workflow/CMakeLists.txt @@ -1,48 +1,56 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. See +# https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public License +# v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization or # submit itself to any jurisdiction. -o2_add_library(MIDWorkflow - TARGETVARNAME targetName - SOURCES src/ClusterizerMCSpec.cxx - src/ClusterizerSpec.cxx - src/DigitReaderSpec.cxx - src/EntropyDecoderSpec.cxx - src/EntropyEncoderSpec.cxx - src/RawAggregatorSpec.cxx - src/RawDecoderSpec.cxx - src/RawWriterSpec.cxx - src/TrackerMCSpec.cxx - src/TrackerSpec.cxx - src/ZeroSuppressionSpec.cxx - PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimConfig - ms_gsl::ms_gsl - O2::DetectorsBase - O2::DPLUtils - O2::SimulationDataFormat - O2::DataFormatsMID - O2::MIDClustering - O2::MIDCTF - O2::MIDRaw - O2::MIDSimulation - O2::MIDTracking - ) +o2_add_library( + MIDWorkflow + TARGETVARNAME targetName + SOURCES src/ClusterizerMCSpec.cxx + src/ClusterizerSpec.cxx + src/DecodedDataAggregatorSpec.cxx + src/DigitReaderSpec.cxx + src/EntropyDecoderSpec.cxx + src/EntropyEncoderSpec.cxx + src/MaskHandlerSpec.cxx + src/MaskMakerSpec.cxx + src/RawCheckerSpec.cxx + src/RawDecoderSpec.cxx + src/RawGBTDecoderSpec.cxx + src/RawInputSpecHandler.cxx + src/RawWriterSpec.cxx + src/TrackerMCSpec.cxx + src/TrackerSpec.cxx + src/ZeroSuppressionSpec.cxx + PUBLIC_LINK_LIBRARIES + O2::Framework + O2::SimConfig + Microsoft.GSL::GSL + O2::CommonUtils + O2::DetectorsBase + O2::DetectorsCommonDataFormats + O2::DPLUtils + O2::SimulationDataFormat + O2::DataFormatsMID + O2::MIDClustering + O2::MIDCTF + O2::MIDFiltering + O2::MIDQC + O2::MIDRaw + O2::MIDSimulation + O2::MIDTracking) o2_add_executable( digits-to-raw-workflow COMPONENT_NAME mid - SOURCES src/digits-to-raw-workflow.cxx - TARGETVARNAME exenameraw - PUBLIC_LINK_LIBRARIES - O2::MIDWorkflow) + SOURCES src/digits-to-raw-workflow.cxx TARGETVARNAME exenameraw + PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) target_include_directories( ${exenameraw} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) @@ -50,43 +58,60 @@ target_include_directories( o2_add_executable( entropy-encoder-workflow COMPONENT_NAME mid - SOURCES src/entropy-encoder-workflow.cxx - TARGETVARNAME exenameentropy - PUBLIC_LINK_LIBRARIES - O2::MIDWorkflow) + SOURCES src/entropy-encoder-workflow.cxx TARGETVARNAME exenameentropy + PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) target_include_directories( - ${exenameentropy} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) + ${exenameentropy} + PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) o2_add_executable( raw-to-digits-workflow COMPONENT_NAME mid - SOURCES src/raw-to-digits-workflow.cxx - TARGETVARNAME exanamedigitstoraw + SOURCES src/raw-to-digits-workflow.cxx TARGETVARNAME exenamedigitstoraw PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) target_include_directories( - ${exanamedigitstoraw} + ${exenamedigitstoraw} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) o2_add_executable( reco-workflow COMPONENT_NAME mid - SOURCES src/reco-workflow.cxx - TARGETVARNAME exanamereco + SOURCES src/reco-workflow.cxx TARGETVARNAME exenamereco PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) target_include_directories( - ${exanamereco} - PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) + ${exenamereco} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) o2_add_executable( digits-reader-workflow COMPONENT_NAME mid - SOURCES src/digits-reader-workflow.cxx - TARGETVARNAME exanamedigitsreader + SOURCES src/digits-reader-workflow.cxx TARGETVARNAME exenamedigitsreader PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) target_include_directories( - ${exanamedigitsreader} + ${exenamedigitsreader} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) + +o2_add_executable( + raw-checker-workflow + COMPONENT_NAME mid + SOURCES src/raw-checker-workflow.cxx TARGETVARNAME exenamerawchecker + PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) + +target_include_directories( + ${exenamerawchecker} + PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>) + +o2_add_executable( + tracks-reader-workflow + SOURCES src/tracks-reader-workflow.cxx + COMPONENT_NAME mid + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::DataFormatsMID) + +o2_add_executable( + mask-maker-workflow + COMPONENT_NAME mid + SOURCES src/mask-maker-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::MIDWorkflow) diff --git a/Detectors/MUON/MID/Workflow/README.md b/Detectors/MUON/MID/Workflow/README.md index 219e5b3a87950..9a27bffb644f5 100644 --- a/Detectors/MUON/MID/Workflow/README.md +++ b/Detectors/MUON/MID/Workflow/README.md @@ -2,7 +2,13 @@ \page refMUONMIDWorkflow MID Workflow /doxy --> -# MID reconstruction workflow +# MID workflows + +1. [MID reconstruction workflow](#MID-reconstruction-workflow) +2. [MID raw data checker](#MID-raw-data-checker) +3. [MID mask maker](#MID-mask-maker) + +## MID reconstruction workflow The MID reconstruction starts from the digits and produced MID tracks. The input digits can be: @@ -14,7 +20,7 @@ The input digits can be: In the case of the MC digits, the MC labels are propagated as well, thus allowing to relate the reconstructed tracks with the corresponding generated particles. The procedure to run the reconstruction, either from the digits or from raw data, is detailed in the following. -## Preface: getting the digits +### Preface: getting the digits If you do not have the digits, you can obtain a sample with: @@ -23,7 +29,7 @@ o2-sim -g fwmugen -m MID -n 100 o2-sim-digitizer-workflow ``` -## Reconstruction from MC digits +### Reconstruction from MC digits To reconstruct the MC digits, run: @@ -31,7 +37,7 @@ To reconstruct the MC digits, run: o2-mid-digits-reader-workflow | o2-mid-reco-workflow ``` -### Zero suppression +#### Zero suppression The MID electronics has a default zero suppression mode. Digits are transmitted only if there is at least one strip fired in both the bending and non-bending plane in at least one of the 4 RPCs which are read-out by a local board. The zero suppression is not applied to the MC digits that are stored on disk. @@ -44,7 +50,7 @@ However, one can disable the zero suppression by running the digits reader with: o2-mid-digits-reader-workflow --disable-zero-suppression ``` -## Reconstruction from raw data +### Reconstruction from raw data To reconstruct the raw data (either from converted MC digits or real data), run: @@ -54,7 +60,7 @@ o2-raw-file-reader-workflow --input-conf MIDraw.cfg | o2-mid-raw-to-digits-workf The reconstruction from raw data can also be tested using as input raw data obtained from the MC digits. -### From MC digits to raw data +#### From MC digits to raw data To convert the MC digits into raw data format, run: @@ -65,7 +71,7 @@ o2-mid-digits-to-raw-workflow The output will be a binary file named by default *raw_mid.dat*. Notice that the executable also generates a configuration file that is needed to read the file with the raw reader workflow (see [here](../../../Raw/README.md) for further details) -## From CTF +### From CTF The CTF for MID corresponds to the digit. So one can retrieve the digits from the CTF and run the reconstruction with the usual workflow with: @@ -74,7 +80,7 @@ So one can retrieve the digits from the CTF and run the reconstruction with the o2-ctf-reader-workflow --ctf-input o2_ctf_0000000000.root --onlyDet MID | o2-mid-reco-workflow --disable-mc ``` -### Generate CTF +#### Generate CTF The MID contribution can be added to CTF by attaching the `o2-mid-entropy-encoder-workflow` device to reconstruction workflow ending by CTF writer, e.g.: @@ -82,7 +88,7 @@ The MID contribution can be added to CTF by attaching the `o2-mid-entropy-encode o2-raw-file-reader-workflow --input-conf MIDraw.cfg | o2-mid-raw-to-digits-workflow | o2-mid-entropy-encoder-workflow | o2-ctf-writer-workflow ``` -## Timing +### Timing In each device belonging to the reconstruction workflow, the execution time is measured using the `chrono` c++ library. At the end of the execution, when the *stop* command is launched, the execution time is written to the `LOG(INFO)`. @@ -95,7 +101,7 @@ Processing time / 90 ROFs: full: 3.55542 us tracking: 2.02182 us Two timing values are provided: one is for the full execution of the device (including retrieval and sending of the DPL messages) and one which concerns only the execution of the algorithm (the tracking algorithm in the above example) The timing refers to the time needed to process one read-out-frame, i.e. one event. -## Reconstruction options +### Reconstruction options By default, the reconstruction produces clusters and tracks that are written on file. It is however possible to only run clustering with: @@ -109,3 +115,45 @@ It is also possible to avoid producing a root file with: ```bash o2-mid-reco-workflow --disable-root-output ``` + +## MID raw data checker + +This workflow is used to check the consistency of the raw data produced from the CRU. +The input is provided by either reading a raw file with the file reader workflow or by using the DPL-proxy. +The common usage is: + +```bash +o2-raw-file-reader-workflow --input-conf MIDraw.cfg | o2-mid-raw-checker-workflow --feeId-config-file "feeId_filename" +``` + +The `feeId_filename` is a file allowing to tell which feeId is readout by the configured GBT. +The file should be in the form explained [here](../Raw/README.md)/ + +The workflow generates an output file where one can find: + +- the details of the event where the data from one GBT lnk is not consistent (with the reason of the inconsistency) +- a summary of the number of analysed events and the number of events with errors + +The default output file name is `raw_checker_out.txt`, but it can be changed with the option: `--mid-checker-outfile` + +The decoding and checking of raw data produced without the user logic is time consuming. +In order to be able to speed-up the process, the check can be launch per gbt link. +This is achieved by adding the option: `--per-gbt`. +In this case, the workflow will produce one output per link, which is called: `raw_checker_out_GBT_LINKID.txt`, where `LINKID` is the link number. + +## MID mask maker + +This workflow checks the fired strips in calibration events (when only noisy strips are fired) and during FET events (where all strips alive should fired). +Scalers are filled for the noisy and dead channels, respectively. +The workflow then compares the number of times a noisy channel was fired (or the number of times a channel was dead) to the total number of calibration triggers analysed. +If the fraction is larger than a configurable threshold, a mask is produced to accounts for noisy and dead channels. + +The common usage is: + +```bash +o2-raw-file-reader-workflow --input-conf MIDraw.cfg | o2-mid-raw-to-digits-workflow | o2-mid-mask-maker-workflow +``` + +The fraction of time a strip must be noisy or dead in order to be masked can be adjusted with: `--mid-mask-threshold XX` (with 0<`XX`<= 1). +The scalers are reset from time to time in order to better check the evolution of the noisy/dead channels. +The number of calibration triggers analysed before the scalers are reset can be adjusted with `--mask-mask-reset XX`, where `XX` is a positive integer. diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerMCSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerMCSpec.h index de91d9eb07b70..c46eab712cee5 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerMCSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerMCSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerSpec.h index 4a7ee5691f465..c904dfcf49511 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataAggregatorSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataAggregatorSpec.h new file mode 100644 index 0000000000000..6407b68af3646 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataAggregatorSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/DecodedDataAggregatorSpec.h +/// \brief Data processor spec for MID decoded data aggregator devices +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 26 February 2020 + +#ifndef O2_MID_DecodedDataAggregatorSpec_H +#define O2_MID_DecodedDataAggregatorSpec_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mid +{ +framework::DataProcessorSpec getDecodedDataAggregatorSpec(); +} // namespace mid +} // namespace o2 + +#endif //O2_MID_DecodedDataAggregatorSpec_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DigitReaderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DigitReaderSpec.h index 334e61e1c61c7..f2a91d3ee7808 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DigitReaderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DigitReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h index 97c413ae8b37d..0d206dbd1ed52 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h index 7dc6a90be029d..4784477ab15fc 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskHandlerSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskHandlerSpec.h new file mode 100644 index 0000000000000..e5cb94c3c8977 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskHandlerSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/MaskHandlerSpec.h +/// \brief Processor to handle the masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 13 August 2021 + +#ifndef O2_MID_MASKHANDLERSPEC_H +#define O2_MID_MASKHANDLERSPEC_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace mid +{ +framework::DataProcessorSpec getMaskHandlerSpec(); +} +} // namespace o2 + +#endif //O2_MID_MASKHANDLERSPEC_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskMakerSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskMakerSpec.h new file mode 100644 index 0000000000000..dd5ae8db963d1 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/MaskMakerSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/MaskMakerSpec.h +/// \brief Processor to compute the masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 12 may 2021 + +#ifndef O2_MID_MASKMAKERSPEC_H +#define O2_MID_MASKMAKERSPEC_H + +#include "Framework/DataProcessorSpec.h" + +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/FEEIdConfig.h" + +namespace o2 +{ +namespace mid +{ +framework::DataProcessorSpec getMaskMakerSpec(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks); +} +} // namespace o2 + +#endif //O2_MID_MASKMAKERSPEC_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h index e32e7ab1f2f9b..b5a6b33530c8f 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawCheckerSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawCheckerSpec.h new file mode 100644 index 0000000000000..1d52253291cec --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawCheckerSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/RawCheckerSpec.h +/// \brief Data processor spec for MID raw checker device +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 06 April 2020 + +#ifndef O2_MID_RAWCHECKERSPEC_H +#define O2_MID_RAWCHECKERSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "Framework/WorkflowSpec.h" + +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/ElectronicsDelay.h" + +namespace o2 +{ +namespace mid +{ +framework::DataProcessorSpec getRawCheckerSpec(const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool perGBT = false); +} // namespace mid +} // namespace o2 + +#endif //O2_MID_RAWCHECKERSPEC_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawDecoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawDecoderSpec.h index 43c2c58b791bb..dc40831eef7f3 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawDecoderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,8 +26,9 @@ namespace o2 { namespace mid { -framework::DataProcessorSpec getRawDecoderSpec(bool isBare = false); -framework::DataProcessorSpec getRawDecoderSpec(bool isBare, bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay); +framework::DataProcessorSpec getRawDecoderSpec(bool isDebugMode = false); +framework::DataProcessorSpec getRawDecoderSpec(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool askDISTSTF); +framework::DataProcessorSpec getRawDecoderSpec(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool askDISTSTF, header::DataHeader::SubSpecificationType subSpec); } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawGBTDecoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawGBTDecoderSpec.h new file mode 100644 index 0000000000000..53c527ad06fd7 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawGBTDecoderSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/RawGBTDecoderSpec.h +/// \brief Data processor spec for MID GBT raw decoder device +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 06 April 2020 + +#ifndef O2_MID_RAWGBTDECODERSPEC_H +#define O2_MID_RAWGBTDECODERSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "Framework/WorkflowSpec.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/ElectronicsDelay.h" + +namespace o2 +{ +namespace mid +{ +o2::framework::DataProcessorSpec getRawGBTDecoderSpec(bool isDebugMode, const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay); +} // namespace mid +} // namespace o2 + +#endif //O2_MID_RAWGBTDECODERSPEC_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawInputSpecHandler.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawInputSpecHandler.h new file mode 100644 index 0000000000000..090cd120001a5 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawInputSpecHandler.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIDWorkflow/RawInputSpecHandler.h +/// \brief Handler for raw data input specs +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 17 June 2021 + +#ifndef O2_MID_RAWINPUTSPECHANDLER_H +#define O2_MID_RAWINPUTSPECHANDLER_H + +#include "Framework/InputSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/ProcessingContext.h" +#include "Headers/DataHeader.h" + +namespace o2 +{ +namespace mid +{ +inline o2::framework::InputSpec getDiSTSTFSpec() +{ + return {"stdDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe}; +} + +bool isDroppedTF(o2::framework::ProcessingContext& pc, o2::header::DataOrigin origin = o2::header::gDataOriginMID); + +} // namespace mid +} // namespace o2 + +#endif //O2_MID_RAWINPUTSPECHANDLER_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawWriterSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawWriterSpec.h index 753cd2130df30..e5df6adf0fe57 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawWriterSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerMCSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerMCSpec.h index 38088d9fc0396..2cdbc91a1ea77 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerMCSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerMCSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerSpec.h index f8b31930154a6..c02d27f5cda50 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/TrackerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ZeroSuppressionSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ZeroSuppressionSpec.h index b819acafaccfd..a440397553003 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ZeroSuppressionSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/ZeroSuppressionSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/ClusterizerMCSpec.cxx b/Detectors/MUON/MID/Workflow/src/ClusterizerMCSpec.cxx index 9111e2ad11c89..4621871a2ae71 100644 --- a/Detectors/MUON/MID/Workflow/src/ClusterizerMCSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/ClusterizerMCSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx b/Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx index 67ed691d7a8f0..26b09fc6ced12 100644 --- a/Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/DecodedDataAggregatorSpec.cxx b/Detectors/MUON/MID/Workflow/src/DecodedDataAggregatorSpec.cxx new file mode 100644 index 0000000000000..8323f8bfdcde5 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/DecodedDataAggregatorSpec.cxx @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/DecodedDataAggregatorSpec.cxx +/// \brief Data processor spec for MID decoded data aggregator device +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 26 February 2020 + +#include "MIDWorkflow/DecodedDataAggregatorSpec.h" + +#include <chrono> +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include <Framework/Logger.h> +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "DataFormatsMID/ColumnData.h" +#include "MIDRaw/DecodedDataAggregator.h" + +namespace of = o2::framework; + +namespace o2 +{ +namespace mid +{ + +class DecodedDataAggregatorDeviceDPL +{ + public: + void init(of::InitContext& ic) + { + auto stop = [this]() { + LOG(INFO) << "Capacities: ROFRecords: " << mAggregator.getROFRecords().capacity() << " Data: " << mAggregator.getData().capacity(); + double scaleFactor = 1.e6 / mNROFs; + LOG(INFO) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " aggregating: " << mTimerAlgo.count() * scaleFactor << " us"; + }; + ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); + } + + void run(of::ProcessingContext& pc) + { + auto tStart = std::chrono::high_resolution_clock::now(); + + auto msg = pc.inputs().get("mid_decoded"); + auto data = of::DataRefUtils::as<const ROBoard>(msg); + + auto msgROF = pc.inputs().get("mid_decoded_rof"); + auto inROFRecords = of::DataRefUtils::as<const ROFRecord>(msgROF); + + auto tAlgoStart = std::chrono::high_resolution_clock::now(); + mAggregator.process(data, inROFRecords); + mTimerAlgo += std::chrono::high_resolution_clock::now() - tAlgoStart; + + for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < 3; ++subSpec) { + EventType evtType = static_cast<EventType>(subSpec); + pc.outputs().snapshot(of::Output{o2::header::gDataOriginMID, "DATA", subSpec, of::Lifetime::Timeframe}, mAggregator.getData(evtType)); + pc.outputs().snapshot(of::Output{o2::header::gDataOriginMID, "DATAROF", subSpec, of::Lifetime::Timeframe}, mAggregator.getROFRecords(evtType)); + } + + mTimer += std::chrono::high_resolution_clock::now() - tStart; + mNROFs += mAggregator.getROFRecords().size(); + } + + private: + DecodedDataAggregator mAggregator{}; + std::chrono::duration<double> mTimer{0}; ///< full timer + std::chrono::duration<double> mTimerAlgo{0}; ///< Algorithm timer + unsigned int mNROFs{0}; /// Total number of processed ROFs +}; + +framework::DataProcessorSpec getDecodedDataAggregatorSpec() +{ + std::vector<of::InputSpec> inputSpecs{of::InputSpec{"mid_decoded", header::gDataOriginMID, "DECODED"}, of::InputSpec{"mid_decoded_rof", header::gDataOriginMID, "DECODEDROF"}}; + std::vector<of::OutputSpec> outputSpecs; + for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < 3; ++subSpec) { + outputSpecs.emplace_back(of::OutputSpec{header::gDataOriginMID, "DATA", subSpec}); + outputSpecs.emplace_back(of::OutputSpec{header::gDataOriginMID, "DATAROF", subSpec}); + } + + return of::DataProcessorSpec{ + "MIDDecodedDataAggregator", + {inputSpecs}, + {outputSpecs}, + of::AlgorithmSpec{of::adaptFromTask<o2::mid::DecodedDataAggregatorDeviceDPL>()}}; +} +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/DigitReaderSpec.cxx b/Detectors/MUON/MID/Workflow/src/DigitReaderSpec.cxx index 1e87b11e22648..e92046307e100 100644 --- a/Detectors/MUON/MID/Workflow/src/DigitReaderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/DigitReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,11 +16,10 @@ #include "MIDWorkflow/DigitReaderSpec.h" +#include <memory> #include <sstream> #include <string> -#include "fmt/format.h" -#include "TFile.h" -#include "TTree.h" +#include "DPLUtils/RootTreeReader.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataSpecUtils.h" @@ -32,8 +32,10 @@ #include "DataFormatsMID/ROFRecord.h" #include "MIDSimulation/ColumnDataMC.h" #include "MIDSimulation/MCLabel.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "CommonUtils/StringUtils.h" -namespace of = o2::framework; +using namespace o2::framework; namespace o2 { @@ -43,74 +45,64 @@ namespace mid class DigitsReaderDeviceDPL { public: - DigitsReaderDeviceDPL(bool useMC, const std::vector<header::DataDescription>& descriptions) : mUseMC(useMC), mDescriptions(descriptions) {} - void init(o2::framework::InitContext& ic) + DigitsReaderDeviceDPL(bool useMC, const std::vector<header::DataDescription>& descriptions) + : mUseMC(useMC), mDescriptions(descriptions) {} + + void init(InitContext& ic) { - auto filename = ic.options().get<std::string>("mid-digit-infile"); - mFile = std::make_unique<TFile>(filename.c_str()); - if (!mFile->IsOpen()) { - LOG(ERROR) << "Cannot open the " << filename << " file !"; - mState = 1; - return; - } - mTree = static_cast<TTree*>(mFile->Get("o2sim")); - if (!mTree) { - LOG(ERROR) << "Cannot find tree in " << filename; - mState = 1; - return; - } - mTree->SetBranchAddress("MIDDigit", &mDigits); + auto filename = utils::Str::concat_string(utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("mid-digit-infile")); if (mUseMC) { - mTree->SetBranchAddress("MIDDigitMCLabels", &mMCContainer); + mReader = std::make_unique<RootTreeReader>("o2sim", filename.c_str(), -1, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<ColumnDataMC>>{ + Output{header::gDataOriginMID, mDescriptions[0], 0, Lifetime::Timeframe}, "MIDDigit"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{ + Output{header::gDataOriginMID, mDescriptions[1], 0, Lifetime::Timeframe}, "MIDROFRecords"}, + RootTreeReader::BranchDefinition<dataformats::MCTruthContainer<MCLabel>>{ + Output{header::gDataOriginMID, mDescriptions[2], 0, Lifetime::Timeframe}, "MIDDigitMCLabels"}, + &mPublishDigits); + } else { + mReader = std::make_unique<RootTreeReader>("o2sim", filename.c_str(), -1, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<ColumnDataMC>>{ + Output{header::gDataOriginMID, mDescriptions[0], 0, Lifetime::Timeframe}, "MIDDigit"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{ + Output{header::gDataOriginMID, mDescriptions[1], 0, Lifetime::Timeframe}, "MIDROFRecords"}, + &mPublishDigits); } - mTree->SetBranchAddress("MIDROFRecords", &mROFRecords); - mState = 0; } - void run(o2::framework::ProcessingContext& pc) + void run(ProcessingContext& pc) { - if (mState != 0) { - return; - } - - std::vector<ColumnData> digits; - o2::dataformats::MCTruthContainer<MCLabel> mcContainer; - std::vector<ROFRecord> rofRecords; - - for (auto ientry = 0; ientry < mTree->GetEntries(); ++ientry) { - mTree->GetEntry(ientry); - digits.insert(digits.end(), mDigits->begin(), mDigits->end()); - rofRecords.insert(rofRecords.end(), mROFRecords->begin(), mROFRecords->end()); - if (mUseMC) { - mcContainer.mergeAtBack(*mMCContainer); - } - } - - LOG(DEBUG) << "MIDDigitsReader pushed " << digits.size() << " merged digits"; - pc.outputs().snapshot(of::Output{header::gDataOriginMID, mDescriptions[0], 0, of::Lifetime::Timeframe}, digits); - pc.outputs().snapshot(of::Output{header::gDataOriginMID, mDescriptions[1], 0, of::Lifetime::Timeframe}, rofRecords); - LOG(DEBUG) << "MIDDigitsReader pushed " << digits.size() << " indexed digits"; - if (mUseMC) { - pc.outputs().snapshot(of::Output{header::gDataOriginMID, mDescriptions[2], 0, of::Lifetime::Timeframe}, mcContainer); + if ((++(*mReader))(pc) == false) { + pc.services().get<ControlService>().endOfStream(); } - mState = 2; - pc.services().get<of::ControlService>().endOfStream(); } private: - std::unique_ptr<TFile> mFile{nullptr}; - TTree* mTree{nullptr}; // not owner - std::vector<o2::mid::ColumnDataMC>* mDigits{nullptr}; // not owner - o2::dataformats::MCTruthContainer<MCLabel>* mMCContainer{nullptr}; // not owner - std::vector<o2::mid::ROFRecord>* mROFRecords{nullptr}; // not owner + std::unique_ptr<RootTreeReader> mReader{}; std::vector<header::DataDescription> mDescriptions{}; - int mState = 0; bool mUseMC = true; + + /// structure holding the function to convert and publish the digits + RootTreeReader::SpecialPublishHook mPublishDigits{ + [](std::string_view name, ProcessingContext& pc, Output const& output, char* data) -> bool { + if (name == "MIDDigit") { + auto inputDigits = reinterpret_cast<std::vector<ColumnDataMC>*>(data); + std::vector<ColumnData> digits{}; + digits.insert(digits.end(), inputDigits->begin(), inputDigits->end()); + pc.outputs().snapshot(output, digits); + LOG(DEBUG) << "MIDDigitsReader pushed " << digits.size() << " digits"; + return true; + } + return false; + }}; }; -framework::DataProcessorSpec getDigitReaderSpec(bool useMC, const char* baseDescription) +DataProcessorSpec getDigitReaderSpec(bool useMC, const char* baseDescription) { - std::vector<of::OutputSpec> outputs; + std::vector<OutputSpec> outputs; std::vector<header::DataDescription> descriptions; std::stringstream ss; ss << "A:" << header::gDataOriginMID.as<std::string>() << "/" << baseDescription << "/0"; @@ -118,18 +110,19 @@ framework::DataProcessorSpec getDigitReaderSpec(bool useMC, const char* baseDesc if (useMC) { ss << ";C:" << header::gDataOriginMID.as<std::string>() << "/" << baseDescription << "LABELS/0"; } - auto matchers = of::select(ss.str().c_str()); + auto matchers = select(ss.str().c_str()); for (auto& matcher : matchers) { - outputs.emplace_back(of::DataSpecUtils::asOutputSpec(matcher)); - descriptions.emplace_back(of::DataSpecUtils::asConcreteDataDescription(matcher)); + outputs.emplace_back(DataSpecUtils::asOutputSpec(matcher)); + descriptions.emplace_back(DataSpecUtils::asConcreteDataDescription(matcher)); } - return of::DataProcessorSpec{ + return DataProcessorSpec{ "MIDDigitsReader", - of::Inputs{}, + Inputs{}, outputs, - of::AlgorithmSpec{of::adaptFromTask<o2::mid::DigitsReaderDeviceDPL>(useMC, descriptions)}, - of::Options{{"mid-digit-infile", of::VariantType::String, "middigits.root", {"Name of the input file"}}}}; + AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC, descriptions)}, + Options{{"mid-digit-infile", VariantType::String, "middigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx index ac4f7364faa95..216abb481a795 100644 --- a/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,11 +11,13 @@ /// @file EntropyDecoderSpec.cxx -#include <vector> +#include "MIDWorkflow/EntropyDecoderSpec.h" +#include <vector> #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" -#include "MIDWorkflow/EntropyDecoderSpec.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -31,7 +34,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("mid-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -43,16 +46,22 @@ void EntropyDecoderSpec::run(ProcessingContext& pc) mTimer.Start(false); auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); - - auto& rofs = pc.outputs().make<std::vector<o2::mid::ROFRecord>>(OutputRef{"rofs"}); - auto& cols = pc.outputs().make<std::vector<o2::mid::ColumnData>>(OutputRef{"cols"}); + std::array<std::vector<o2::mid::ROFRecord>, NEvTypes> rofs{}; + std::array<std::vector<o2::mid::ColumnData>, NEvTypes> cols{}; // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object const auto ctfImage = o2::mid::CTF::getImage(buff.data()); mCTFCoder.decode(ctfImage, rofs, cols); + for (uint32_t it = 0; it < NEvTypes; it++) { + pc.outputs().snapshot(Output{o2::header::gDataOriginMID, "DATA", it, Lifetime::Timeframe}, cols[it]); + pc.outputs().snapshot(Output{o2::header::gDataOriginMID, "DATAROF", it, Lifetime::Timeframe}, rofs[it]); + } + mTimer.Stop(); - LOG(INFO) << "Decoded " << cols.size() << " MID columns in " << rofs.size() << " ROFRecords in " << mTimer.CpuTime() - cput << " s"; + LOG(INFO) << "Decoded {" << cols[0].size() << ',' << cols[1].size() << ',' << cols[2].size() + << "} MID columns for {" << rofs[0].size() << ',' << rofs[1].size() << ',' << rofs[2].size() + << "} ROFRecords in " << mTimer.CpuTime() - cput << " s"; } void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) @@ -63,16 +72,18 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) DataProcessorSpec getEntropyDecoderSpec() { - std::vector<OutputSpec> outputs{ - OutputSpec{{"rofs"}, "MID", "DATAROF", 0, Lifetime::Timeframe}, - OutputSpec{{"cols"}, "MID", "DATA", 0, Lifetime::Timeframe}}; + std::vector<OutputSpec> outputs; + for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < NEvTypes; ++subSpec) { + outputs.emplace_back(OutputSpec{header::gDataOriginMID, "DATA", subSpec}); + outputs.emplace_back(OutputSpec{header::gDataOriginMID, "DATAROF", subSpec}); + } return DataProcessorSpec{ "mid-entropy-decoder", Inputs{InputSpec{"ctf", "MID", "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"mid-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace mid diff --git a/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx index e3aca8c542833..0cb355296304c 100644 --- a/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,12 +13,17 @@ /// @brief Convert MID DATA to CTF (EncodedBlocks) /// @author ruben.shahoyan@cern.ch -#include <vector> +#include "MIDWorkflow/EntropyEncoderSpec.h" +#include <vector> +#include <unordered_map> #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" -#include "MIDWorkflow/EntropyEncoderSpec.h" -#include "DetectorsCommonDataFormats/DetID.h" +#include "Framework/DataRef.h" +#include "Framework/InputRecordWalker.h" +#include "Headers/DataHeader.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -34,7 +40,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("mid-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -44,11 +50,30 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) { auto cput = mTimer.CpuTime(); mTimer.Start(false); - auto rofs = pc.inputs().get<gsl::span<o2::mid::ROFRecord>>("rofs"); - auto cols = pc.inputs().get<gsl::span<o2::mid::ColumnData>>("cols"); - auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"MID", "CTFDATA", 0, Lifetime::Timeframe}); - mCTFCoder.encode(buffer, rofs, cols); + CTFHelper::TFData tfData; + std::vector<InputSpec> + filter = { + {"check", ConcreteDataTypeMatcher{header::gDataOriginMID, "DATA"}, Lifetime::Timeframe}, + {"check", ConcreteDataTypeMatcher{header::gDataOriginMID, "DATAROF"}, Lifetime::Timeframe}, + }; + for (auto const& inputRef : InputRecordWalker(pc.inputs(), filter)) { + auto const* dh = framework::DataRefUtils::getHeader<o2::header::DataHeader*>(inputRef); + if (dh->subSpecification >= NEvTypes) { + throw std::runtime_error(fmt::format("SubSpecification={} does not match EvenTypes for {}", dh->subSpecification, dh->dataDescription.as<std::string>())); + } + if (DataRefUtils::match(inputRef, "cols")) { + tfData.colData[dh->subSpecification] = pc.inputs().get<gsl::span<o2::mid::ColumnData>>(inputRef); + } + if (DataRefUtils::match(inputRef, "rofs")) { + tfData.rofData[dh->subSpecification] = pc.inputs().get<gsl::span<o2::mid::ROFRecord>>(inputRef); + } + } + // build references for looping over the data in BC increasing direction + tfData.buildReferences(); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{header::gDataOriginMID, "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, tfData); auto eeb = CTF::get(buffer.data()); // cast to container pointer eeb->compactify(); // eliminate unnecessary padding buffer.resize(eeb->size()); // shrink buffer to strictly necessary size @@ -66,15 +91,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) DataProcessorSpec getEntropyEncoderSpec() { std::vector<InputSpec> inputs; - inputs.emplace_back("rofs", "MID", "DATAROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cols", "MID", "DATA", 0, Lifetime::Timeframe); + inputs.emplace_back("rofs", ConcreteDataTypeMatcher(header::gDataOriginMID, "DATAROF"), Lifetime::Timeframe); + inputs.emplace_back("cols", ConcreteDataTypeMatcher(header::gDataOriginMID, "DATA"), Lifetime::Timeframe); return DataProcessorSpec{ "mid-entropy-encoder", inputs, - Outputs{{"MID", "CTFDATA", 0, Lifetime::Timeframe}}, + Outputs{{header::gDataOriginMID, "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"mid-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace mid diff --git a/Detectors/MUON/MID/Workflow/src/MaskHandlerSpec.cxx b/Detectors/MUON/MID/Workflow/src/MaskHandlerSpec.cxx new file mode 100644 index 0000000000000..0231f1dbb4348 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/MaskHandlerSpec.cxx @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/MaskHandlerSpec.cxx +/// \brief Processor to handle the masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 13 August 2021 + +#include "MIDWorkflow/MaskHandlerSpec.h" + +#include <array> +#include <vector> +#include <chrono> +#include <gsl/gsl> +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/InputSpec.h" +#include "Framework/Logger.h" +#include "Framework/Task.h" +#include "DataFormatsMID/ColumnData.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/ColumnDataToLocalBoard.h" +#include "MIDFiltering/ChannelMasksHandler.h" + +namespace of = o2::framework; + +namespace o2 +{ +namespace mid +{ + +class MaskHandlerDeviceDPL +{ + public: + void init(o2::framework::InitContext& ic) + { + + auto stop = [this]() { + printSummary(); + }; + ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); + } + + void printSummary() + { + std::string name = "calib"; + o2::mid::ColumnDataToLocalBoard colToBoard; + colToBoard.setDebugMode(true); + + for (auto& masks : mMasksHandlers) { + auto maskVec = masks.getMasks(); + if (maskVec.empty()) { + LOG(INFO) << "No problematic digit found in " << name << " events"; + } else { + LOG(INFO) << "Problematic digits found in " << name << " events. Corresponding masks:"; + for (auto& mask : maskVec) { + LOG(INFO) << mask; + } + std::cout << "\nCorresponding boards masks:" << std::endl; + colToBoard.process(maskVec); + for (auto& mapIt : colToBoard.getData()) { + for (auto& board : mapIt.second) { + std::cout << board << std::endl; + } + } + } + name = "FET"; + } + } + + void run(o2::framework::ProcessingContext& pc) + { + auto tStart = std::chrono::high_resolution_clock::now(); + + std::array<gsl::span<const ColumnData>, 2> masks; + + masks[0] = pc.inputs().get<gsl::span<ColumnData>>("mid_noise_mask"); + masks[1] = pc.inputs().get<gsl::span<ColumnData>>("mid_dead_mask"); + + auto tAlgoStart = std::chrono::high_resolution_clock::now(); + + bool isChanged = false; + for (int itype = 0; itype < 2; ++itype) { + ChannelMasksHandler chMasks; + for (auto& mask : masks[itype]) { + chMasks.setFromChannelMask(mask); + } + if (!(chMasks == mMasksHandlers[itype])) { + mMasksHandlers[itype] = chMasks; + isChanged = true; + } + } + + if (isChanged) { + printSummary(); + } + + mTimerMaskHandler += std::chrono::high_resolution_clock::now() - tAlgoStart; + + mTimer += std::chrono::high_resolution_clock::now() - tStart; + } + + private: + std::array<ChannelMasksHandler, 2> mMasksHandlers{}; ///< Output masks + std::chrono::duration<double> mTimer{0}; ///< full timer + std::chrono::duration<double> mTimerMaskHandler{0}; ///< mask handler timer +}; + +framework::DataProcessorSpec getMaskHandlerSpec() +{ + std::vector<of::InputSpec> inputSpecs{ + of::InputSpec{"mid_noise_mask", header::gDataOriginMID, "MASKS", 1}, + of::InputSpec{"mid_dead_mask", header::gDataOriginMID, "MASKS", 2}}; + + return of::DataProcessorSpec{ + "MIDMaskHandler", + {inputSpecs}, + {}, + of::AlgorithmSpec{of::adaptFromTask<o2::mid::MaskHandlerDeviceDPL>()}}; +} +} // namespace mid +} // namespace o2 \ No newline at end of file diff --git a/Detectors/MUON/MID/Workflow/src/MaskMakerSpec.cxx b/Detectors/MUON/MID/Workflow/src/MaskMakerSpec.cxx new file mode 100644 index 0000000000000..88463bb514ab9 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/MaskMakerSpec.cxx @@ -0,0 +1,143 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/MaskMakerSpec.cxx +/// \brief Processor to compute the masks +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 12 may 2021 + +#include "MIDWorkflow/MaskMakerSpec.h" + +#include <array> +#include <vector> +#include <chrono> +#include <gsl/gsl> +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/InputSpec.h" +#include "Framework/Logger.h" +#include "Framework/Task.h" +#include "DataFormatsMID/ColumnData.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDFiltering/ChannelMasksHandler.h" +#include "MIDFiltering/ChannelScalers.h" +#include "MIDFiltering/FetToDead.h" +#include "MIDFiltering/MaskMaker.h" + +namespace of = o2::framework; + +namespace o2 +{ +namespace mid +{ + +class MaskMakerDeviceDPL +{ + public: + MaskMakerDeviceDPL(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks) + { + mRefMasks = makeDefaultMasksFromCrateConfig(feeIdConfig, crateMasks); + mFetToDead.setMasks(mRefMasks); + } + + void init(of::InitContext& ic) + { + mThreshold = ic.options().get<double>("mid-mask-threshold"); + mNReset = ic.options().get<int>("mid-mask-reset"); + + auto stop = [this]() { + double scaleFactor = (mCounter == 0) ? 0 : 1.e6 / mCounter; + LOG(INFO) << "Processing time / " << mCounter << " events: full: " << mTimer.count() * scaleFactor << " us mask maker: " << mTimerMaskMaker.count() * scaleFactor << " us"; + }; + ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); + } + + void run(of::ProcessingContext& pc) + { + auto tStart = std::chrono::high_resolution_clock::now(); + + auto calibData = pc.inputs().get<gsl::span<ColumnData>>("mid_calib"); + auto calibDataRof = pc.inputs().get<gsl::span<ROFRecord>>("mid_calib_rof"); + + auto fetData = pc.inputs().get<gsl::span<ColumnData>>("mid_fet"); + auto fetDataRof = pc.inputs().get<gsl::span<ROFRecord>>("mid_fet_rof"); + + unsigned long nEvents = calibDataRof.size(); + if (nEvents == 0) { + return; + } + + auto tAlgoStart = std::chrono::high_resolution_clock::now(); + + for (auto& col : calibData) { + mScalers[0].count(col); + } + + for (auto& rof : fetDataRof) { + auto subSet = fetData.subspan(rof.firstEntry, rof.nEntries); + auto deadChannels = mFetToDead.process(subSet); + for (auto& col : deadChannels) { + mScalers[1].count(col); + } + } + + mCounter += nEvents; + mCounterSinceReset += nEvents; + + if (mCounterSinceReset >= mNReset) { + for (size_t itype = 0; itype < 2; ++itype) { + auto masks = o2::mid::makeMasks(mScalers[itype], mCounterSinceReset, mThreshold, mRefMasks); + pc.outputs().snapshot(of::Output{header::gDataOriginMID, "MASKS", static_cast<header::DataHeader::SubSpecificationType>(itype + 1), of::Lifetime::Timeframe}, masks); + } + mCounterSinceReset = 0; + for (auto& scaler : mScalers) { + scaler.reset(); + } + } + + mTimerMaskMaker += std::chrono::high_resolution_clock::now() - tAlgoStart; + + mTimer += std::chrono::high_resolution_clock::now() - tStart; + } + + private: + FetToDead mFetToDead{}; ///< FET to dead channels converter + std::vector<ColumnData> mRefMasks{}; ///< Reference masks + std::array<ChannelScalers, 2> mScalers{}; ///< Array fo channel scalers + std::chrono::duration<double> mTimer{0}; ///< full timer + std::chrono::duration<double> mTimerMaskMaker{0}; ///< mask maker timer + unsigned long mCounter{0}; ///< Total number of processed events + unsigned long mCounterSinceReset{0}; ///< Total number of processed events since last reset + double mThreshold{0.9}; ///< Occupancy threshold for producing a mask + int mNReset{1}; ///< Number of calibration events to be tested before checking the scalers +}; + +framework::DataProcessorSpec getMaskMakerSpec(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks) +{ + std::vector<of::InputSpec> inputSpecs{ + of::InputSpec{"mid_calib", header::gDataOriginMID, "DATA", 1}, + of::InputSpec{"mid_calib_rof", header::gDataOriginMID, "DATAROF", 1}, + of::InputSpec{"mid_fet", header::gDataOriginMID, "DATA", 2}, + of::InputSpec{"mid_fet_rof", header::gDataOriginMID, "DATAROF", 2}}; + + std::vector<of::OutputSpec> outputSpecs{ + of::OutputSpec{header::gDataOriginMID, "MASKS", 1}, + of::OutputSpec{header::gDataOriginMID, "MASKS", 2}}; + + return of::DataProcessorSpec{ + "MIDMaskMaker", + {inputSpecs}, + {outputSpecs}, + of::AlgorithmSpec{of::adaptFromTask<o2::mid::MaskMakerDeviceDPL>(feeIdConfig, crateMasks)}, + of::Options{{"mid-mask-threshold", of::VariantType::Double, 0.9, {"Tolerated occupancy before producing a map"}}, {"mid-mask-reset", of::VariantType::Int, 100, {"Number of calibration events to be checked before resetting the scalers"}}}}; +} +} // namespace mid +} // namespace o2 \ No newline at end of file diff --git a/Detectors/MUON/MID/Workflow/src/RawAggregatorSpec.cxx b/Detectors/MUON/MID/Workflow/src/RawAggregatorSpec.cxx deleted file mode 100644 index 56f72f8b6e85b..0000000000000 --- a/Detectors/MUON/MID/Workflow/src/RawAggregatorSpec.cxx +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Workflow/src/RawAggregatorSpec.cxx -/// \brief Data processor spec for MID raw data aggregator device -/// \author Diego Stocco <Diego.Stocco at cern.ch> -/// \date 26 February 2020 - -#include "MIDWorkflow/RawAggregatorSpec.h" - -#include <chrono> -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include <Framework/Logger.h> -#include "Framework/Output.h" -#include "Framework/Task.h" -#include "DataFormatsMID/ColumnData.h" -#include "MIDRaw/DecodedDataAggregator.h" - -namespace of = o2::framework; - -namespace o2 -{ -namespace mid -{ - -class RawAggregatorDeviceDPL -{ - public: - void init(of::InitContext& ic) - { - auto stop = [this]() { - LOG(INFO) << "Capacities: ROFRecords: " << mAggregator.getROFRecords().capacity() << " Data: " << mAggregator.getData().capacity(); - double scaleFactor = 1.e6 / mNROFs; - LOG(INFO) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " aggregating: " << mTimerAlgo.count() * scaleFactor << " us"; - }; - ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); - } - - void run(of::ProcessingContext& pc) - { - auto tStart = std::chrono::high_resolution_clock::now(); - - auto msg = pc.inputs().get("mid_decoded"); - auto data = of::DataRefUtils::as<const LocalBoardRO>(msg); - - auto msgROF = pc.inputs().get("mid_decoded_rof"); - auto inROFRecords = of::DataRefUtils::as<const ROFRecord>(msgROF); - - auto tAlgoStart = std::chrono::high_resolution_clock::now(); - mAggregator.process(data, inROFRecords); - mTimerAlgo += std::chrono::high_resolution_clock::now() - tAlgoStart; - - pc.outputs().snapshot(of::Output{"MID", "DATA", 0, of::Lifetime::Timeframe}, mAggregator.getData()); - pc.outputs().snapshot(of::Output{"MID", "DATAROF", 0, of::Lifetime::Timeframe}, mAggregator.getROFRecords()); - - mTimer += std::chrono::high_resolution_clock::now() - tStart; - mNROFs += mAggregator.getROFRecords().size(); - } - - private: - DecodedDataAggregator mAggregator{}; - std::chrono::duration<double> mTimer{0}; ///< full timer - std::chrono::duration<double> mTimerAlgo{0}; ///< Algorithm timer - unsigned int mNROFs{0}; /// Total number of processed ROFs -}; - -framework::DataProcessorSpec getRawAggregatorSpec() -{ - std::vector<of::InputSpec> inputSpecs{of::InputSpec{"mid_decoded", header::gDataOriginMID, "DECODED"}, of::InputSpec{"mid_decoded_rof", header::gDataOriginMID, "DECODEDROF"}}; - std::vector<of::OutputSpec> outputSpecs{of::OutputSpec{header::gDataOriginMID, "DATA"}, of::OutputSpec{header::gDataOriginMID, "DATAROF"}}; - - return of::DataProcessorSpec{ - "MIDRawAggregator", - {inputSpecs}, - {outputSpecs}, - of::AlgorithmSpec{of::adaptFromTask<o2::mid::RawAggregatorDeviceDPL>()}}; -} -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/RawCheckerSpec.cxx b/Detectors/MUON/MID/Workflow/src/RawCheckerSpec.cxx new file mode 100644 index 0000000000000..490134f084c20 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/RawCheckerSpec.cxx @@ -0,0 +1,142 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/RawCheckerSpec.cxx +/// \brief Data processor spec for MID raw bare checker device +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 06 April 2020 + +#include "MIDWorkflow/RawCheckerSpec.h" + +#include <fstream> +#include <chrono> +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/ParallelContext.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDQC/RawDataChecker.h" + +namespace o2 +{ +namespace mid +{ + +template <typename RAWCHECKER> +std::string getSummary(const RAWCHECKER& checker, size_t maxErrors) +{ + std::stringstream ss; + if (checker.getNEventsFaulty() >= maxErrors) { + ss << "Too many errors found (" << checker.getNEventsFaulty() << "): abort check!\n"; + } + ss << "Number of busy raised: " << checker.getNBusyRaised() << "\n"; + ss << "Fraction of faulty events: " << checker.getNEventsFaulty() << " / " << checker.getNEventsProcessed() << " = " << static_cast<double>(checker.getNEventsFaulty()) / ((checker.getNEventsProcessed() > 0) ? static_cast<double>(checker.getNEventsProcessed()) : 1.); + return ss.str(); +} + +template <typename RAWCHECKER> +class RawCheckerDeviceDPL +{ + public: + RawCheckerDeviceDPL<RAWCHECKER>(const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay) : mFeeIds(feeIds), mCrateMasks(crateMasks), mElectronicsDelay(electronicsDelay) {} + + void init(o2::framework::InitContext& ic) + { + + auto syncTrigger = ic.options().get<int>("mid-checker-sync-trigger"); + mChecker.setSyncTrigger(syncTrigger); + + auto outFilename = ic.options().get<std::string>("mid-checker-outfile"); + mChecker.setElectronicsDelay(mElectronicsDelay); + if constexpr (std::is_same_v<RAWCHECKER, RawDataChecker>) { + mChecker.init(mCrateMasks); + if (outFilename.empty()) { + outFilename = "raw_checker_out.txt"; + } + } else { + auto idx = ic.services().get<o2::framework::ParallelContext>().index1D(); + auto feeId = mFeeIds[idx]; + mChecker.init(feeId, mCrateMasks.getMask(feeId)); + if (outFilename.empty()) { + std::stringstream ss; + ss << "raw_checker_out_GBT_" << feeId << ".txt"; + outFilename = ss.str(); + } + } + + mOutFile.open(outFilename.c_str()); + + auto stop = [this]() { + bool hasProcessed = (mChecker.getNEventsProcessed() > 0); + double scaleFactor = (mChecker.getNEventsProcessed() > 0) ? 1.e6 / static_cast<double>(mChecker.getNEventsProcessed()) : 0.; + LOG(INFO) << "Processing time / " << mChecker.getNEventsProcessed() << " BCs: full: " << mTimer.count() * scaleFactor << " us checker: " << mTimerAlgo.count() * scaleFactor << " us"; + std::string summary = getSummary(mChecker, mMaxErrors); + mOutFile << summary << "\n"; + LOG(INFO) << summary; + }; + ic.services().get<o2::framework::CallbackService>().set(o2::framework::CallbackService::Id::Stop, stop); + + mMaxErrors = ic.options().get<int>("mid-checker-max-errors"); + } + + void run(o2::framework::ProcessingContext& pc) + { + if (mChecker.getNEventsFaulty() >= mMaxErrors) { + // Abort checking: too many errors found + return; + } + + auto tStart = std::chrono::high_resolution_clock::now(); + + auto msg = pc.inputs().getByPos(0); + auto data = o2::framework::DataRefUtils::as<const ROBoard>(msg); + + auto msgROF = pc.inputs().getByPos(1); + auto inROFRecords = o2::framework::DataRefUtils::as<const ROFRecord>(msgROF); + + std::vector<ROFRecord> dummy; + auto tAlgoStart = std::chrono::high_resolution_clock::now(); + if (!mChecker.process(data, inROFRecords, dummy)) { + mOutFile << mChecker.getDebugMessage() << "\n"; + } + mTimerAlgo += std::chrono::high_resolution_clock::now() - tAlgoStart; + mTimer += std::chrono::high_resolution_clock::now() - tStart; + } + + private: + RAWCHECKER mChecker{}; ///< Raw data checker + std::vector<uint16_t> mFeeIds{}; ///< Vector of FEE IDs + CrateMasks mCrateMasks{}; ///< Crate masks file + ElectronicsDelay mElectronicsDelay{}; ///< Delay in the electronics + size_t mMaxErrors{0}; ///< Maximum number of errors + std::ofstream mOutFile{}; ///< Output file + std::chrono::duration<double> mTimer{0}; ///< full timer + std::chrono::duration<double> mTimerAlgo{0}; ///< algorithm timer +}; + +framework::DataProcessorSpec getRawCheckerSpec(const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool perGBT) +{ + std::vector<o2::framework::InputSpec> inputSpecs{o2::framework::InputSpec{"mid_decoded", header::gDataOriginMID, "DECODED", 0, o2::framework::Lifetime::Timeframe}, o2::framework::InputSpec{"mid_decoded_rof", header::gDataOriginMID, "DECODEDROF", 0, o2::framework::Lifetime::Timeframe}}; + + return o2::framework::DataProcessorSpec{ + "MIDRawDataChecker", + {inputSpecs}, + {o2::framework::Outputs{}}, + perGBT ? o2::framework::AlgorithmSpec{ + o2::framework::adaptFromTask<RawCheckerDeviceDPL<GBTRawDataChecker>>(feeIds, crateMasks, electronicsDelay)} + : o2::framework::adaptFromTask<RawCheckerDeviceDPL<RawDataChecker>>(feeIds, crateMasks, electronicsDelay), + o2::framework::Options{{"mid-checker-sync-trigger", o2::framework::VariantType::Int, 0x1, {"Trigger used for synchronisation (default is orbit 0x1)"}}, {"mid-checker-max-errors", o2::framework::VariantType::Int, 10000, {"Maximum number of errors"}}, {"mid-checker-outfile", o2::framework::VariantType::String, "", {"Checker output file"}}}}; +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/RawDecoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/RawDecoderSpec.cxx index 93fbf2bf248f6..21081e7359bfc 100644 --- a/Detectors/MUON/MID/Workflow/src/RawDecoderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/RawDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,10 +21,10 @@ #include "Framework/Logger.h" #include "Framework/Output.h" #include "Framework/Task.h" -#include "Framework/WorkflowSpec.h" #include "DPLUtils/DPLRawParser.h" #include "Headers/RDHAny.h" #include "MIDRaw/Decoder.h" +#include "MIDWorkflow/RawInputSpecHandler.h" namespace of = o2::framework; @@ -32,25 +33,21 @@ namespace o2 namespace mid { -template <typename GBTDECODER> class RawDecoderDeviceDPL { public: - RawDecoderDeviceDPL<GBTDECODER>(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay) : mIsDebugMode(isDebugMode), mFeeIdConfig(feeIdConfig), mCrateMasks(crateMasks), mElectronicsDelay(electronicsDelay) {} + RawDecoderDeviceDPL(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, header::DataHeader::SubSpecificationType subSpec) : mIsDebugMode(isDebugMode), mFeeIdConfig(feeIdConfig), mCrateMasks(crateMasks), mElectronicsDelay(electronicsDelay), mSubSpec(subSpec) {} void init(of::InitContext& ic) { auto stop = [this]() { - LOG(INFO) << "Capacities: ROFRecords: " << mDecoder.getROFRecords().capacity() << " LocalBoards: " << mDecoder.getData().capacity(); - double scaleFactor = 1.e6 / mNROFs; - LOG(INFO) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " us decoding: " << mTimerAlgo.count() * scaleFactor << " us"; + if (mDecoder) { + LOG(INFO) << "Capacities: ROFRecords: " << mDecoder->getROFRecords().capacity() << " LocalBoards: " << mDecoder->getData().capacity(); + double scaleFactor = (mNROFs == 0) ? 0. : 1.e6 / mNROFs; + LOG(INFO) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " us decoding: " << mTimerAlgo.count() * scaleFactor << " us"; + } }; ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); - - mDecoder.setFeeIdConfig(mFeeIdConfig); - mDecoder.setCrateMasks(mCrateMasks); - - mDecoder.init(mIsDebugMode); } void run(of::ProcessingContext& pc) @@ -58,51 +55,82 @@ class RawDecoderDeviceDPL auto tStart = std::chrono::high_resolution_clock::now(); auto tAlgoStart = std::chrono::high_resolution_clock::now(); - of::DPLRawParser parser(pc.inputs(), of::select("mid_raw:MID/RAWDATA")); - mDecoder.clear(); + if (isDroppedTF(pc, header::gDataOriginMID)) { + std::vector<ROBoard> data; + std::vector<ROFRecord> rofs; + pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODED", mSubSpec}, data); + pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODEDROF", mSubSpec}, rofs); + return; + } + + std::vector<of::InputSpec> filter{of::InputSpec{"filter", of::ConcreteDataTypeMatcher{header::gDataOriginMID, header::gDataDescriptionRawData}, of::Lifetime::Timeframe}}; + + of::DPLRawParser parser(pc.inputs(), filter); + + if (!mDecoder) { + auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(parser.begin().raw()); + mDecoder = createDecoder(*rdhPtr, mIsDebugMode, mElectronicsDelay, mCrateMasks, mFeeIdConfig); + } + + mDecoder->clear(); for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(it.raw()); gsl::span<const uint8_t> payload(it.data(), it.size()); - mDecoder.process(payload, *rdhPtr); + mDecoder->process(payload, *rdhPtr); } - mDecoder.flush(); mTimerAlgo += std::chrono::high_resolution_clock::now() - tAlgoStart; - pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODED", 0}, mDecoder.getData()); - pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODEDROF", 0}, mDecoder.getROFRecords()); + pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODED", mSubSpec}, mDecoder->getData()); + pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DECODEDROF", mSubSpec}, mDecoder->getROFRecords()); mTimer += std::chrono::high_resolution_clock::now() - tStart; - mNROFs += mDecoder.getROFRecords().size(); + mNROFs += mDecoder->getROFRecords().size(); } private: - Decoder<GBTDECODER> mDecoder{}; + std::unique_ptr<Decoder> mDecoder{nullptr}; bool mIsDebugMode{false}; FEEIdConfig mFeeIdConfig{}; CrateMasks mCrateMasks{}; ElectronicsDelay mElectronicsDelay{}; + header::DataHeader::SubSpecificationType mSubSpec{0}; std::chrono::duration<double> mTimer{0}; ///< full timer std::chrono::duration<double> mTimerAlgo{0}; ///< algorithm timer unsigned int mNROFs{0}; /// Total number of processed ROFs }; -of::DataProcessorSpec getRawDecoderSpec(bool isBare) -{ - return getRawDecoderSpec(isBare, false, FEEIdConfig(), CrateMasks(), ElectronicsDelay()); -} - -of::DataProcessorSpec getRawDecoderSpec(bool isBare, bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay) +of::DataProcessorSpec getRawDecoderSpec(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, std::vector<of::InputSpec> inputSpecs, bool askDISTSTF, o2::header::DataHeader::SubSpecificationType subSpecType) { - std::vector<of::InputSpec> inputSpecs{of::InputSpec{"mid_raw", of::ConcreteDataTypeMatcher{header::gDataOriginMID, header::gDataDescriptionRawData}, of::Lifetime::Timeframe}}; - std::vector<of::OutputSpec> outputSpecs{of::OutputSpec{header::gDataOriginMID, "DECODED", 0, of::Lifetime::Timeframe}, of::OutputSpec{header::gDataOriginMID, "DECODEDROF", 0, of::Lifetime::Timeframe}}; - + if (askDISTSTF) { + inputSpecs.emplace_back(getDiSTSTFSpec()); + } + std::vector<of::OutputSpec> outputSpecs{of::OutputSpec{header::gDataOriginMID, "DECODED", subSpecType, of::Lifetime::Timeframe}, of::OutputSpec{header::gDataOriginMID, "DECODEDROF", subSpecType, of::Lifetime::Timeframe}}; return of::DataProcessorSpec{ "MIDRawDecoder", {inputSpecs}, {outputSpecs}, - isBare ? of::adaptFromTask<o2::mid::RawDecoderDeviceDPL<o2::mid::GBTBareDecoder>>(isDebugMode, feeIdConfig, crateMasks, electronicsDelay) : of::adaptFromTask<o2::mid::RawDecoderDeviceDPL<o2::mid::GBTUserLogicDecoder>>(isDebugMode, feeIdConfig, crateMasks, electronicsDelay)}; + of::adaptFromTask<o2::mid::RawDecoderDeviceDPL>(isDebugMode, feeIdConfig, crateMasks, electronicsDelay, subSpecType)}; +} + +of::DataProcessorSpec getRawDecoderSpec(bool isDebugMode) +{ + return getRawDecoderSpec(isDebugMode, FEEIdConfig(), CrateMasks(), ElectronicsDelay(), true); +} + +of::DataProcessorSpec getRawDecoderSpec(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool askDISTSTF) +{ + std::vector<of::InputSpec> inputSpecs{{"mid_raw", of::ConcreteDataTypeMatcher{header::gDataOriginMID, header::gDataDescriptionRawData}, of::Lifetime::Optional}}; + header::DataHeader::SubSpecificationType subSpec{0}; + return getRawDecoderSpec(isDebugMode, feeIdConfig, crateMasks, electronicsDelay, inputSpecs, askDISTSTF, subSpec); +} + +of::DataProcessorSpec getRawDecoderSpec(bool isDebugMode, const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay, bool askDISTSTF, header::DataHeader::SubSpecificationType subSpec) +{ + std::vector<of::InputSpec> inputSpecs{{"mid_raw", header::gDataOriginMID, header::gDataDescriptionRawData, subSpec, o2::framework::Lifetime::Optional}}; + + return getRawDecoderSpec(isDebugMode, feeIdConfig, crateMasks, electronicsDelay, inputSpecs, askDISTSTF, subSpec); } } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/RawGBTDecoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/RawGBTDecoderSpec.cxx new file mode 100644 index 0000000000000..01213c57b5aa0 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/RawGBTDecoderSpec.cxx @@ -0,0 +1,117 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/RawGBTDecoderSpec.cxx +/// \brief Data processor spec for MID GBT raw decoder device +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 06 April 2020 + +#include "MIDWorkflow/RawGBTDecoderSpec.h" + +#include <chrono> +#include <vector> +#include "DPLUtils/DPLRawParser.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Logger.h" +#include "Framework/Output.h" +#include "Framework/ParallelContext.h" +#include "Framework/Task.h" +#include "Headers/RDHAny.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DataFormatsMID/ROBoard.h" +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/LinkDecoder.h" + +namespace o2 +{ +namespace mid +{ + +class RawGBTDecoderDeviceDPL +{ + public: + RawGBTDecoderDeviceDPL(bool isDebugMode, const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay) : mIsDebugMode(isDebugMode), mFeeIds(feeIds), mCrateMasks(crateMasks), mElectronicsDelay(electronicsDelay) {} + + void init(o2::framework::InitContext& ic) + { + auto stop = [this]() { + double scaleFactor = 1.e6 / mNROFs; + LOG(INFO) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " us decoding: " << mTimerAlgo.count() * scaleFactor << " us"; + }; + ic.services().get<o2::framework::CallbackService>().set(o2::framework::CallbackService::Id::Stop, stop); + + auto idx = ic.services().get<o2::framework::ParallelContext>().index1D(); + mFeeId = mFeeIds[idx]; + } + + void run(o2::framework::ProcessingContext& pc) + { + auto tStart = std::chrono::high_resolution_clock::now(); + + o2::framework::DPLRawParser parser(pc.inputs()); + + auto tAlgoStart = std::chrono::high_resolution_clock::now(); + + o2::header::DataHeader const* dh = nullptr; + + if (!mDecoder) { + auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(parser.begin().raw()); + mDecoder = createGBTDecoder(*rdhPtr, mFeeId, mIsDebugMode, mCrateMasks.getMask(mFeeId), mElectronicsDelay); + } + + std::vector<ROBoard> data; + std::vector<ROFRecord> rofRecords; + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + dh = it.o2DataHeader(); + auto const* rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(it.raw()); + gsl::span<const uint8_t> payload(it.data(), it.size()); + mDecoder->process(payload, o2::raw::RDHUtils::getHeartBeatOrbit(rdhPtr), data, rofRecords); + } + + mTimerAlgo += std::chrono::high_resolution_clock::now() - tAlgoStart; + + pc.outputs().snapshot(o2::framework::Output{header::gDataOriginMID, "DECODED", dh->subSpecification, o2::framework::Lifetime::Timeframe}, data); + pc.outputs().snapshot(o2::framework::Output{header::gDataOriginMID, "DECODEDROF", dh->subSpecification, o2::framework::Lifetime::Timeframe}, rofRecords); + + mTimer += std::chrono::high_resolution_clock::now() - tStart; + mNROFs += rofRecords.size(); + } + + private: + std::unique_ptr<LinkDecoder> mDecoder{nullptr}; + bool mIsDebugMode{false}; + std::vector<uint16_t> mFeeIds{}; + CrateMasks mCrateMasks{}; + ElectronicsDelay mElectronicsDelay{}; + uint16_t mFeeId{0}; + std::chrono::duration<double> mTimer{0}; ///< full timer + std::chrono::duration<double> mTimerAlgo{0}; ///< algorithm timer + unsigned int mNROFs{0}; /// Total number of processed ROFs +}; + +framework::DataProcessorSpec getRawGBTDecoderSpec(bool isDebugMode, const std::vector<uint16_t>& feeIds, const CrateMasks& crateMasks, const ElectronicsDelay& electronicsDelay) +{ + std::vector<o2::framework::InputSpec> inputSpecs{o2::framework::InputSpec{"mid_raw", header::gDataOriginMID, header::gDataDescriptionRawData, 0, o2::framework::Lifetime::Timeframe}}; + std::vector<o2::framework::OutputSpec> outputSpecs{o2::framework::OutputSpec{header::gDataOriginMID, "DECODED", 0, o2::framework::Lifetime::Timeframe}, o2::framework::OutputSpec{header::gDataOriginMID, "DECODEDROF", 0, o2::framework::Lifetime::Timeframe}}; + + return o2::framework::DataProcessorSpec{ + "MIDRawGBTDecoder", + {inputSpecs}, + {outputSpecs}, + o2::framework::adaptFromTask<RawGBTDecoderDeviceDPL>(isDebugMode, feeIds, crateMasks, electronicsDelay)}; +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/RawInputSpecHandler.cxx b/Detectors/MUON/MID/Workflow/src/RawInputSpecHandler.cxx new file mode 100644 index 0000000000000..961bf14668a8c --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/RawInputSpecHandler.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/RawInputSpecHandler.cxx +/// \brief Handler for raw data input specs +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 17 June 2021 + +#include "MIDWorkflow/RawInputSpecHandler.h" + +#include "Framework/DataRefUtils.h" +#include "Framework/InputRecordWalker.h" + +namespace o2 +{ +namespace mid +{ + +bool isDroppedTF(o2::framework::ProcessingContext& pc, o2::header::DataOrigin origin) +{ + /// Tests it the TF was dropped + std::vector<o2::framework::InputSpec> dummy{o2::framework::InputSpec{"dummy", o2::framework::ConcreteDataMatcher{origin, o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : o2::framework::InputRecordWalker(pc.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + // LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + // dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return true; + } + } + return false; +} +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/RawWriterSpec.cxx b/Detectors/MUON/MID/Workflow/src/RawWriterSpec.cxx index ce4741c29b1b5..37db05c089eb0 100644 --- a/Detectors/MUON/MID/Workflow/src/RawWriterSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/RawWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,8 +15,8 @@ /// \date 02 October 2019 #include "MIDWorkflow/RawWriterSpec.h" -#include <TSystem.h> #include <fstream> +#include <filesystem> #include <gsl/gsl> #include "Framework/CallbackService.h" #include "Framework/ConfigParamRegistry.h" @@ -42,19 +43,17 @@ class RawWriterDeviceDPL public: void init(o2::framework::InitContext& ic) { - auto filename = ic.options().get<std::string>("mid-raw-outfile"); auto dirname = ic.options().get<std::string>("mid-raw-outdir"); - auto perLink = ic.options().get<bool>("mid-raw-perlink"); - if (gSystem->AccessPathName(dirname.c_str())) { - if (gSystem->mkdir(dirname.c_str(), kTRUE)) { + auto fileFor = ic.options().get<std::string>("file-for"); + if (!std::filesystem::exists(dirname)) { + if (!std::filesystem::create_directories(dirname)) { LOG(FATAL) << "could not create output directory " << dirname; } else { LOG(INFO) << "created output directory " << dirname; } } - std::string fullFName = o2::utils::concat_string(dirname, "/", filename); - mEncoder.init(fullFName.c_str(), perLink); + mEncoder.init(dirname.c_str(), fileFor.c_str()); std::string inputGRP = o2::base::NameConf::getGRPFileName(); std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom(inputGRP)}; @@ -66,7 +65,7 @@ class RawWriterDeviceDPL ic.services().get<of::CallbackService>().set(of::CallbackService::Id::Stop, stop); // Write basic config files to be used with raw data reader workflow - mEncoder.getWriter().writeConfFile("MID", "RAWDATA", o2::utils::concat_string(dirname, '/', "MIDraw.cfg")); + mEncoder.getWriter().writeConfFile("MID", "RAWDATA", o2::utils::Str::concat_string(dirname, '/', "MIDraw.cfg")); } void run(o2::framework::ProcessingContext& pc) @@ -98,8 +97,7 @@ framework::DataProcessorSpec getRawWriterSpec() of::AlgorithmSpec{of::adaptFromTask<o2::mid::RawWriterDeviceDPL>()}, of::Options{ {"mid-raw-outdir", of::VariantType::String, ".", {"Raw file output directory"}}, - {"mid-raw-outfile", of::VariantType::String, "mid", {"Raw output file name"}}, - {"mid-raw-perlink", of::VariantType::Bool, false, {"Output file per link"}}, + {"file-for", of::VariantType::String, "all", {"single file per: all,flp,cru,link"}}, {"mid-raw-header-offset", of::VariantType::Bool, false, {"Header offset in bytes"}}}}; } } // namespace mid diff --git a/Detectors/MUON/MID/Workflow/src/TrackerMCSpec.cxx b/Detectors/MUON/MID/Workflow/src/TrackerMCSpec.cxx index 4aa7615651b66..9712ba4660dae 100644 --- a/Detectors/MUON/MID/Workflow/src/TrackerMCSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/TrackerMCSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/TrackerSpec.cxx b/Detectors/MUON/MID/Workflow/src/TrackerSpec.cxx index 8d651ab0fc84e..de43a3af72dfd 100644 --- a/Detectors/MUON/MID/Workflow/src/TrackerSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/TrackerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/ZeroSuppressionSpec.cxx b/Detectors/MUON/MID/Workflow/src/ZeroSuppressionSpec.cxx index 12a7e0940c3e5..3ae1b4d9cde88 100644 --- a/Detectors/MUON/MID/Workflow/src/ZeroSuppressionSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/ZeroSuppressionSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -57,7 +58,7 @@ class ZeroSuppressionDeviceDPL for (auto& rof : inROFRecords) { mConverter.process(patterns.subspan(rof.firstEntry, rof.nEntries)); if (!mConverter.getData().empty()) { - std::vector<LocalBoardRO> decodedData; + std::vector<ROBoard> decodedData; for (auto& item : mConverter.getData()) { decodedData.insert(decodedData.end(), item.second.begin(), item.second.end()); } diff --git a/Detectors/MUON/MID/Workflow/src/digits-reader-workflow.cxx b/Detectors/MUON/MID/Workflow/src/digits-reader-workflow.cxx index fed38802c2c04..4832efafcc1fb 100644 --- a/Detectors/MUON/MID/Workflow/src/digits-reader-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/digits-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,8 @@ #include "MIDSimulation/MCLabel.h" #include "MIDWorkflow/DigitReaderSpec.h" #include "MIDWorkflow/ZeroSuppressionSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; @@ -31,8 +34,12 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) { std::vector<ConfigParamSpec> options{ {"disable-mc", VariantType::Bool, false, {"Do not propagate MC info"}}, - {"disable-zero-suppression", VariantType::Bool, false, {"Do not apply zero suppression"}}}; - workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); + {"disable-zero-suppression", VariantType::Bool, false, {"Do not apply zero suppression"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); } #include "Framework/runDataProcessing.h" @@ -42,11 +49,16 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) bool disableZS = cfgc.options().get<bool>("disable-zero-suppression"); bool useMC = !cfgc.options().get<bool>("disable-mc"); + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + WorkflowSpec specs; specs.emplace_back(o2::mid::getDigitReaderSpec(useMC, disableZS ? "DATA" : "DATAMC")); if (!disableZS) { specs.emplace_back(o2::mid::getZeroSuppressionSpec(useMC)); } + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); + return specs; } diff --git a/Detectors/MUON/MID/Workflow/src/digits-to-raw-workflow.cxx b/Detectors/MUON/MID/Workflow/src/digits-to-raw-workflow.cxx index 385d2735373e8..faa8ccf89a7f7 100644 --- a/Detectors/MUON/MID/Workflow/src/digits-to-raw-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/digits-to-raw-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,10 +16,12 @@ #include <string> #include <vector> +#include "CommonUtils/ConfigurableParam.h" #include "Framework/ConfigParamSpec.h" #include "Framework/Variant.h" #include "MIDWorkflow/DigitReaderSpec.h" #include "MIDWorkflow/RawWriterSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -27,6 +30,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { std::string keyvaluehelp("Semicolon separated key=value strings ..."); workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + workflowOptions.push_back(ConfigParamSpec{"hbfutils-config", o2::framework::VariantType::String, std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE), {"config file for HBFUtils (or none), used for raw output only!!!"}}); } #include "Framework/runDataProcessing.h" @@ -35,6 +39,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; + std::string confDig = configcontext.options().get<std::string>("hbfutils-config"); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); specs.emplace_back(o2::mid::getDigitReaderSpec(false)); specs.emplace_back(o2::mid::getRawWriterSpec()); diff --git a/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx b/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx index 171291272c322..077c44ff0db93 100644 --- a/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/MUON/MID/Workflow/src/mask-maker-workflow.cxx b/Detectors/MUON/MID/Workflow/src/mask-maker-workflow.cxx new file mode 100644 index 0000000000000..d4bf75acc7240 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/mask-maker-workflow.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/decoded-digits-writer-workflow.cxx +/// \brief MID decoded digits writer workflow +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 29 October 2020 + +#include <string> +#include <vector> +#include "Framework/Variant.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"feeId-config-file", VariantType::String, "", {"Filename with crate FEE ID correspondence"}}, + {"crate-masks-file", VariantType::String, "", {"Filename with crate masks"}}}; + workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); +} + +#include "Framework/runDataProcessing.h" +#include "MIDWorkflow/MaskMakerSpec.h" +#include "MIDWorkflow/MaskHandlerSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + auto feeIdConfigFilename = cfgc.options().get<std::string>("feeId-config-file"); + o2::mid::FEEIdConfig feeIdConfig; + if (!feeIdConfigFilename.empty()) { + feeIdConfig = o2::mid::FEEIdConfig(feeIdConfigFilename.c_str()); + } + auto crateMasksFilename = cfgc.options().get<std::string>("crate-masks-file"); + o2::mid::CrateMasks crateMasks; + if (!crateMasksFilename.empty()) { + crateMasks = o2::mid::CrateMasks(crateMasksFilename.c_str()); + } + WorkflowSpec specs; + specs.emplace_back(o2::mid::getMaskMakerSpec(feeIdConfig, crateMasks)); + specs.emplace_back(o2::mid::getMaskHandlerSpec()); + + return specs; +} diff --git a/Detectors/MUON/MID/Workflow/src/raw-checker-workflow.cxx b/Detectors/MUON/MID/Workflow/src/raw-checker-workflow.cxx new file mode 100644 index 0000000000000..04a007c6ccd6d --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/raw-checker-workflow.cxx @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/raw-checker-workflow.cxx +/// \brief MID raw checker workflow +/// \author Diego Stocco <Diego.Stocco at cern.ch> +/// \date 06 April 2020 + +#include <string> +#include <vector> +#include "Framework/Variant.h" +#include "Framework/ConfigParamSpec.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/ElectronicsDelay.h" +#include "MIDRaw/FEEIdConfig.h" +#include "MIDWorkflow/RawCheckerSpec.h" +#include "MIDWorkflow/RawDecoderSpec.h" +#include "MIDWorkflow/RawGBTDecoderSpec.h" + +using namespace o2::framework; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> + options{ + {"feeId-config-file", VariantType::String, "", {"Filename with crate FEE ID correspondence"}}, + {"crate-masks-file", VariantType::String, "", {"Filename with crate masks"}}, + {"electronics-delay-file", VariantType::String, "", {"Filename with electronics delay"}}, + {"per-gbt", VariantType::Bool, false, {"One process per GBT link"}}, + {"per-feeId", VariantType::Bool, false, {"One process per FeeId"}}}; + workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + auto feeIdConfigFilename = cfgc.options().get<std::string>("feeId-config-file"); + o2::mid::FEEIdConfig feeIdConfig; + if (!feeIdConfigFilename.empty()) { + feeIdConfig = o2::mid::FEEIdConfig(feeIdConfigFilename.c_str()); + } + auto crateMasksFilename = cfgc.options().get<std::string>("crate-masks-file"); + o2::mid::CrateMasks crateMasks; + if (!crateMasksFilename.empty()) { + crateMasks = o2::mid::CrateMasks(crateMasksFilename.c_str()); + } + auto electronicsDelayFilename = cfgc.options().get<std::string>("electronics-delay-file"); + o2::mid::ElectronicsDelay electronicsDelay; + if (!electronicsDelayFilename.empty()) { + electronicsDelay = o2::mid::readElectronicsDelay(electronicsDelayFilename.c_str()); + } + + bool perGBT = cfgc.options().get<bool>("per-gbt"); + + bool perFeeId = cfgc.options().get<bool>("per-feeId"); + + std::vector<uint32_t> gbtIds = feeIdConfig.getConfiguredLinkUniqueIDs(); + std::vector<uint16_t> feeIds; + for (auto& gbtId : gbtIds) { + feeIds.emplace_back(feeIdConfig.getGBTUniqueId(gbtId)); + } + + o2::framework::WorkflowSpec specs; + if (perGBT || perFeeId) { + o2::framework::WorkflowSpec templateSpecs; + templateSpecs.emplace_back(o2::mid::getRawGBTDecoderSpec(true, feeIds, crateMasks, electronicsDelay)); + templateSpecs.emplace_back(o2::mid::getRawCheckerSpec(feeIds, crateMasks, electronicsDelay, true)); + + auto parallelSpecs = o2::framework::parallelPipeline( + templateSpecs, gbtIds.size(), + [&gbtIds]() { return gbtIds.size(); }, + [&gbtIds, &feeIdConfig, perFeeId](size_t index) { return perFeeId ? feeIdConfig.getGBTUniqueId(gbtIds[index]) : gbtIds[index]; }); + specs.insert(specs.end(), parallelSpecs.begin(), parallelSpecs.end()); + } else { + specs.emplace_back(o2::mid::getRawDecoderSpec(true, feeIdConfig, crateMasks, electronicsDelay, false)); + specs.emplace_back(o2::mid::getRawCheckerSpec(feeIds, crateMasks, electronicsDelay, false)); + } + return specs; +} diff --git a/Detectors/MUON/MID/Workflow/src/raw-to-digits-workflow.cxx b/Detectors/MUON/MID/Workflow/src/raw-to-digits-workflow.cxx index 8e9e964b11b0e..3a3addb6d8e37 100644 --- a/Detectors/MUON/MID/Workflow/src/raw-to-digits-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/raw-to-digits-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,20 +19,21 @@ #include "Framework/Variant.h" #include "Framework/ConfigParamSpec.h" #include "MIDWorkflow/RawDecoderSpec.h" -#include "MIDWorkflow/RawAggregatorSpec.h" +#include "MIDWorkflow/DecodedDataAggregatorSpec.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { - std::vector<ConfigParamSpec> - options{ - {"feeId-config-file", VariantType::String, "", {"Filename with crate FEE ID correspondence"}}, - {"crate-masks-file", VariantType::String, "", {"Filename with crate masks"}}, - {"electronics-delay-file", VariantType::String, "", {"Filename with electronics delay"}}, - {"bare", VariantType::Bool, false, {"Is bare decoder"}}, - {"decode-only", o2::framework::VariantType::Bool, false, {"Output decoded boards instead of digits"}}}; + std::vector<ConfigParamSpec> options{ + {"feeId-config-file", VariantType::String, "", {"Filename with crate FEE ID correspondence"}}, + {"crate-masks-file", VariantType::String, "", {"Filename with crate masks"}}, + {"electronics-delay-file", VariantType::String, "", {"Filename with electronics delay"}}, + {"decode-only", o2::framework::VariantType::Bool, false, {"Output decoded boards instead of digits"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}}; workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); } @@ -39,6 +41,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); auto feeIdConfigFilename = cfgc.options().get<std::string>("feeId-config-file"); o2::mid::FEEIdConfig feeIdConfig; if (!feeIdConfigFilename.empty()) { @@ -55,13 +58,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) electronicsDelay = o2::mid::readElectronicsDelay(electronicsDelayFilename.c_str()); } - bool isBare = cfgc.options().get<bool>("bare"); bool decodeOnly = cfgc.options().get<bool>("decode-only"); + auto askDISTSTF = !cfgc.options().get<bool>("ignore-dist-stf"); o2::framework::WorkflowSpec specs; - specs.emplace_back(o2::mid::getRawDecoderSpec(isBare, false, feeIdConfig, crateMasks, electronicsDelay)); + specs.emplace_back(o2::mid::getRawDecoderSpec(false, feeIdConfig, crateMasks, electronicsDelay, askDISTSTF)); if (!decodeOnly) { - specs.emplace_back(o2::mid::getRawAggregatorSpec()); + specs.emplace_back(o2::mid::getDecodedDataAggregatorSpec()); } return specs; } diff --git a/Detectors/MUON/MID/Workflow/src/reco-workflow.cxx b/Detectors/MUON/MID/Workflow/src/reco-workflow.cxx index bf4a6167ae181..1727fd8e57644 100644 --- a/Detectors/MUON/MID/Workflow/src/reco-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,12 +22,16 @@ #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsMID/Cluster2D.h" +#include "DataFormatsMID/Cluster3D.h" +#include "DataFormatsMID/Track.h" #include "DataFormatsMID/ROFRecord.h" #include "MIDSimulation/MCClusterLabel.h" #include "MIDWorkflow/ClusterizerMCSpec.h" #include "MIDWorkflow/ClusterizerSpec.h" #include "MIDWorkflow/TrackerMCSpec.h" #include "MIDWorkflow/TrackerSpec.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; @@ -37,7 +42,9 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) options{ {"disable-mc", VariantType::Bool, false, {"Do not propagate MC labels"}}, {"disable-tracking", VariantType::Bool, false, {"Only run clustering"}}, - {"disable-root-output", VariantType::Bool, false, {"Do not write output to file"}}}; + {"disable-root-output", VariantType::Bool, false, {"Do not write output to file"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); } @@ -48,6 +55,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) bool disableMC = cfgc.options().get<bool>("disable-mc"); bool disableTracking = cfgc.options().get<bool>("disable-tracking"); bool disableFile = cfgc.options().get<bool>("disable-root-output"); + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); WorkflowSpec specs; specs.emplace_back(disableMC ? o2::mid::getClusterizerSpec() : o2::mid::getClusterizerMCSpec()); @@ -55,22 +63,25 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) specs.emplace_back(disableMC ? o2::mid::getTrackerSpec() : o2::mid::getTrackerMCSpec()); } if (!disableFile) { - std::array<o2::header::DataDescription, 2> clusterDescriptions{"CLUSTERS", "TRACKCLUSTERS"}; - std::array<o2::header::DataDescription, 2> clusterROFDescriptions{"CLUSTERSROF", "TRCLUSROF"}; - std::array<o2::header::DataDescription, 2> clusterLabelDescriptions{"CLUSTERSLABELS", "TRCLUSLABELS"}; - std::array<std::string, 2> clusterBranch{"MIDCluster", "MIDTrackCluster"}; - std::array<std::string, 2> clusterROFBranch{"MIDClusterROF", "MIDTrackClusterROF"}; - std::array<std::string, 2> clusterLabelBranch{"MIDClusterLabels", "MIDTrackClusterLabels"}; - int idx = disableTracking ? 0 : 1; - specs.emplace_back(MakeRootTreeWriterSpec("MIDRecoWriter", - "mid-reco.root", - "midreco", - MakeRootTreeWriterSpec::BranchDefinition<const char*>{InputSpec{"mid_tracks", o2::header::gDataOriginMID, "TRACKS"}, "MIDTrack", disableTracking ? 0 : 1}, - MakeRootTreeWriterSpec::BranchDefinition<const char*>{InputSpec{"mid_trackClusters", o2::header::gDataOriginMID, clusterDescriptions[idx]}, clusterBranch[idx]}, - MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::ROFRecord>>{InputSpec{"mid_tracks_rof", o2::header::gDataOriginMID, "TRACKSROF"}, "MIDTrackROF", disableTracking ? 0 : 1}, - MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::ROFRecord>>{InputSpec{"mid_trclus_rof", o2::header::gDataOriginMID, clusterROFDescriptions[idx]}, clusterROFBranch[idx]}, - MakeRootTreeWriterSpec::BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"mid_track_labels", o2::header::gDataOriginMID, "TRACKSLABELS"}, "MIDTrackLabels", (disableTracking || disableMC) ? 0 : 1}, - MakeRootTreeWriterSpec::BranchDefinition<o2::dataformats::MCTruthContainer<o2::mid::MCClusterLabel>>{InputSpec{"mid_trclus_labels", o2::header::gDataOriginMID, clusterLabelDescriptions[idx]}, clusterLabelBranch[idx], disableMC ? 0 : 1})()); + if (disableTracking) { + specs.emplace_back(MakeRootTreeWriterSpec("MIDRecoWriter", + "mid-reco.root", + "midreco", + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::Cluster2D>>{InputSpec{"mid_clusters", o2::header::gDataOriginMID, "CLUSTERS"}, "MIDCluster"}, + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::ROFRecord>>{InputSpec{"mid_clusters_rof", o2::header::gDataOriginMID, "CLUSTERSROF"}, "MIDClusterROF"}, + MakeRootTreeWriterSpec::BranchDefinition<o2::dataformats::MCTruthContainer<o2::mid::MCClusterLabel>>{InputSpec{"mid_clusters_labels", o2::header::gDataOriginMID, "CLUSTERSLABELS"}, "MIDClusterLabels", disableMC ? 0 : 1})()); + + } else { + specs.emplace_back(MakeRootTreeWriterSpec("MIDRecoWriter", + "mid-reco.root", + "midreco", + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::Track>>{InputSpec{"mid_tracks", o2::header::gDataOriginMID, "TRACKS"}, "MIDTrack"}, + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::Cluster3D>>{InputSpec{"mid_trclus", o2::header::gDataOriginMID, "TRACKCLUSTERS"}, "MIDTrackCluster"}, + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::ROFRecord>>{InputSpec{"mid_tracks_rof", o2::header::gDataOriginMID, "TRACKSROF"}, "MIDTrackROF"}, + MakeRootTreeWriterSpec::BranchDefinition<std::vector<o2::mid::ROFRecord>>{InputSpec{"mid_trclus_rof", o2::header::gDataOriginMID, "TRCLUSROF"}, "MIDTrackClusterROF"}, + MakeRootTreeWriterSpec::BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"mid_track_labels", o2::header::gDataOriginMID, "TRACKSLABELS"}, "MIDTrackLabels", disableMC ? 0 : 1}, + MakeRootTreeWriterSpec::BranchDefinition<o2::dataformats::MCTruthContainer<o2::mid::MCClusterLabel>>{InputSpec{"mid_trclus_labels", o2::header::gDataOriginMID, "TRCLUSLABELS"}, "MIDTrackClusterLabels", disableMC ? 0 : 1})()); + } } return specs; diff --git a/Detectors/MUON/MID/Workflow/src/tracks-reader-workflow.cxx b/Detectors/MUON/MID/Workflow/src/tracks-reader-workflow.cxx new file mode 100644 index 0000000000000..b4921bb2b8ac1 --- /dev/null +++ b/Detectors/MUON/MID/Workflow/src/tracks-reader-workflow.cxx @@ -0,0 +1,126 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Workflow/src/tracks-reader-workflow.cxx +/// \brief DPL workflow to send MID tracks read from a root file +/// \author Philippe Pillot, Subatech + +#include <algorithm> +#include <functional> +#include <iterator> +#include <memory> +#include <stdexcept> + +#include "Framework/runDataProcessing.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" + +#include "DPLUtils/RootTreeReader.h" + +#include "DataFormatsMID/ROFRecord.h" +#include "DataFormatsMID/Track.h" + +using namespace o2::framework; +using namespace o2::mid; + +class TrackSamplerTask +{ + public: + /// prepare the reader + void init(InitContext& ic) + { + auto inputFileName = ic.options().get<std::string>("infile"); + mMinNumberOfROFsPerTF = ic.options().get<int>("repack-rofs"); + + mReader = std::make_unique<RootTreeReader>("midreco", inputFileName.c_str(), -1, + RootTreeReader::PublishingMode::Single, + RootTreeReader::BranchDefinition<std::vector<Track>>{ + Output{"MID", "TRACKS", 0, Lifetime::Timeframe}, "MIDTrack"}, + RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{ + Output{"MID", "TRACKSROF", 0, Lifetime::Timeframe}, "MIDTrackROF"}, + &mAccumulator); + } + + /// process the next entry + void run(ProcessingContext& pc) + { + if (mReader->next()) { + (*mReader)(pc); + if (mROFs.size() >= mMinNumberOfROFsPerTF) { + publish(pc.outputs()); + } + } else { + if (mROFs.size() > 0) { + publish(pc.outputs()); + } + pc.services().get<ControlService>().endOfStream(); + } + } + + private: + /// accumulate the data + bool accumulate(std::string_view name, char* data) + { + if (name == "MIDTrackROF") { + + auto rofs = reinterpret_cast<std::vector<ROFRecord>*>(data); + + // accumulate the ROFs, shifting the track indexing accordingly + size_t offset = (mROFs.size() > 0) ? mROFs.back().firstEntry + mROFs.back().nEntries : 0; + std::transform(rofs->begin(), rofs->end(), std::back_inserter(mROFs), [offset](const ROFRecord& rof) { + return ROFRecord{rof, rof.firstEntry + offset, rof.nEntries}; + }); + + } else if (name == "MIDTrack") { + + auto tracks = reinterpret_cast<std::vector<Track>*>(data); + + // accumulate the tracks + mTracks.insert(mTracks.end(), tracks->begin(), tracks->end()); + + } else { + throw std::invalid_argument("invalid branch"); + } + + return true; + } + + /// publish the data and clear the internal vector + void publish(DataAllocator& out) + { + out.snapshot(OutputRef{"rofs"}, mROFs); + out.snapshot(OutputRef{"tracks"}, mTracks); + mROFs.clear(); + mTracks.clear(); + } + + size_t mMinNumberOfROFsPerTF = 1; ///< minimum number of ROF to send per TF + std::vector<ROFRecord> mROFs{}; ///< internal vector of ROFs + std::vector<Track> mTracks{}; ///< internal vector of tracks + std::unique_ptr<RootTreeReader> mReader{}; ///< root file reader + /// structure holding the function to accumulate the data + RootTreeReader::SpecialPublishHook mAccumulator{ + [this](std::string_view name, ProcessingContext&, Output const&, char* data) -> bool { + return this->accumulate(name, data); + }}; +}; + +WorkflowSpec defineDataProcessing(const ConfigContext&) +{ + return WorkflowSpec{DataProcessorSpec{ + "TrackSampler", + Inputs{}, + Outputs{OutputSpec{{"rofs"}, "MID", "TRACKSROF", 0, Lifetime::Timeframe}, + OutputSpec{{"tracks"}, "MID", "TRACKS", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<TrackSamplerTask>()}, + Options{{"infile", VariantType::String, "mid-reco.root", {"input filename"}}, + {"repack-rofs", VariantType::Int, 1, {"min number of rofs per timeframe"}}}}}; +} diff --git a/Detectors/MUON/Matching/CMakeLists.txt b/Detectors/MUON/Matching/CMakeLists.txt new file mode 100644 index 0000000000000..3d27e4886ab2b --- /dev/null +++ b/Detectors/MUON/Matching/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(MUONMatching + SOURCES + src/TrackMatcher.cxx + src/TrackMatcherParam.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtils O2::DataFormatsMCH O2::DataFormatsMID O2::ReconstructionDataFormats) + +o2_target_root_dictionary(MUONMatching + HEADERS include/MUONMatching/TrackMatcherParam.h) diff --git a/Detectors/MUON/Matching/README.md b/Detectors/MUON/Matching/README.md new file mode 100644 index 0000000000000..ae2dbb124af6b --- /dev/null +++ b/Detectors/MUON/Matching/README.md @@ -0,0 +1,31 @@ +<!-- doxy +\page refDetectorsMUONMatching Matching +/doxy --> + +# TrackMatcher.h(cxx) + +Implementation of the MCH-MID matching algorithm. + +## Input / Output + +It takes as input the lists or MCH ROFs, MCH tracks, MID ROFs and MID tracks. It returns the list of matched tracks with the data format [TrackMCHMID](../../../DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h). + +## Short description of the algorithm + +The matching of each MCH track in each MCH ROF is done in 2 steps: +1) by time: finding all the MID ROFs (resolution = 1 BC) compatible with the MCH ROF (BC range) +2) by position: finding the MID track in those MID ROFs that is the most compatible (best matching chi2) with the MCH track. The chi2 must be lower than a threshold, defined via TrackMatcherParam (see below), to validate the matching. + +# TrackMatcherParam.h(cxx) + +Definition of the sigma cut used to set the maximum matching chi2 = 4 * (sigma cut)^2. The factor 4 is because the matching is done on 4 track parameters (x, slopex, y, slopey). + +The sigma cut is configurable via the command line or an INI or JSON configuration file (cf. [workflow documentation](../Workflow/README.md)). + +## Example of workflow + +`o2-mch-tracks-reader-workflow | o2-mid-tracks-reader-workflow | o2-muon-tracks-matcher-workflow | o2-muon-tracks-writer-workflow` + +This takes as input the root files with MCH and MID tracks and ROFs and gives as ouput a root file with the matched tracks. + +See the [workflow documentation](../Workflow/README.md) for more details about the track matcher workflow. diff --git a/Detectors/MUON/Matching/include/MUONMatching/TrackMatcher.h b/Detectors/MUON/Matching/include/MUONMatching/TrackMatcher.h new file mode 100644 index 0000000000000..8600a0436f4cd --- /dev/null +++ b/Detectors/MUON/Matching/include/MUONMatching/TrackMatcher.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcher.h +/// \brief Definition of a class to match MCH and MID tracks +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MUON_TRACKMATCHER_H_ +#define ALICEO2_MUON_TRACKMATCHER_H_ + +#include <vector> + +#include <gsl/span> + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMID/ROFRecord.h" +#include "DataFormatsMID/Track.h" +#include "ReconstructionDataFormats/TrackMCHMID.h" + +namespace o2 +{ +namespace muon +{ + +/// Class to match MCH and MID tracks +class TrackMatcher +{ + using TrackMCHMID = o2::dataformats::TrackMCHMID; + + public: + TrackMatcher() = default; + ~TrackMatcher() = default; + + TrackMatcher(const TrackMatcher&) = delete; + TrackMatcher& operator=(const TrackMatcher&) = delete; + TrackMatcher(TrackMatcher&&) = delete; + TrackMatcher& operator=(TrackMatcher&&) = delete; + + void init(); + void match(gsl::span<const mch::ROFRecord>& mchROFs, gsl::span<const mch::TrackMCH>& mchTracks, + gsl::span<const mid::ROFRecord>& midROFs, gsl::span<const mid::Track>& midTracks); + + /// get the MCH-MID matched tracks + const std::vector<TrackMCHMID>& getMuons() const { return mMuons; } + + private: + double match(const mch::TrackMCH& mchTrack, const mid::Track& midTrack); + + double mMaxChi2 = 0.; ///< maximum chi2 to validate a MCH-MID track matching + std::vector<TrackMCHMID> mMuons{}; ///< list of MCH-MID matched tracks +}; + +} // namespace muon +} // namespace o2 + +#endif // ALICEO2_MUON_TRACKMATCHER_H_ diff --git a/Detectors/MUON/Matching/include/MUONMatching/TrackMatcherParam.h b/Detectors/MUON/Matching/include/MUONMatching/TrackMatcherParam.h new file mode 100644 index 0000000000000..72b5a19de4ce6 --- /dev/null +++ b/Detectors/MUON/Matching/include/MUONMatching/TrackMatcherParam.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcherParam.h +/// \brief Configurable parameters for MCH-MID track matching +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MUON_TRACKMATCHERPARAM_H_ +#define ALICEO2_MUON_TRACKMATCHERPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace muon +{ + +/// Configurable parameters for MCH-MID track matching +struct TrackMatcherParam : public o2::conf::ConfigurableParamHelper<TrackMatcherParam> { + + double sigmaCut = 4.; ///< to select compatible MCH and MID tracks according to their matching chi2 + + O2ParamDef(TrackMatcherParam, "MUONMatching"); +}; + +} // namespace muon +} // namespace o2 + +#endif // ALICEO2_MUON_TRACKMATCHERPARAM_H_ diff --git a/Detectors/MUON/Matching/src/MUONMatchingLinkDef.h b/Detectors/MUON/Matching/src/MUONMatchingLinkDef.h new file mode 100644 index 0000000000000..9d5bdc2401ad9 --- /dev/null +++ b/Detectors/MUON/Matching/src/MUONMatchingLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::muon::TrackMatcherParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::muon::TrackMatcherParam> + ; + +#endif diff --git a/Detectors/MUON/Matching/src/TrackMatcher.cxx b/Detectors/MUON/Matching/src/TrackMatcher.cxx new file mode 100644 index 0000000000000..13b26067b790f --- /dev/null +++ b/Detectors/MUON/Matching/src/TrackMatcher.cxx @@ -0,0 +1,139 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcher.cxx +/// \brief Implementation of a class to match MCH and MID tracks +/// +/// \author Philippe Pillot, Subatech + +#include <algorithm> +#include <map> + +#include <Math/SMatrix.h> +#include <Math/SVector.h> + +#include "Framework/Logger.h" +#include "MUONMatching/TrackMatcher.h" +#include "MUONMatching/TrackMatcherParam.h" + +namespace o2 +{ +namespace muon +{ + +using SMatrixSym4 = ROOT::Math::SMatrix<double, 4, 4, ROOT::Math::MatRepSym<double, 4>>; +using SMatrix4 = ROOT::Math::SMatrix<double, 4, 4, ROOT::Math::MatRepStd<double, 4>>; +using SVector4 = ROOT::Math::SVector<double, 4>; + +//_________________________________________________________________________________________________ +/// prepare to run the matching algorithm +void TrackMatcher::init() +{ + // set the maximum chi2 used for matching (4 parameters matched) + const auto& trackMatcherParam = TrackMatcherParam::Instance(); + mMaxChi2 = 4. * trackMatcherParam.sigmaCut * trackMatcherParam.sigmaCut; +} + +//_________________________________________________________________________________________________ +/// run the matching algorithm +void TrackMatcher::match(gsl::span<const mch::ROFRecord>& mchROFs, gsl::span<const mch::TrackMCH>& mchTracks, + gsl::span<const mid::ROFRecord>& midROFs, gsl::span<const mid::Track>& midTracks) +{ + mMuons.clear(); + + if (mchROFs.empty() || midROFs.empty()) { + return; + } + + // sort the MID ROFs in increasing time + std::map<InteractionRecord, int> midSortedROFs{}; + for (int i = 0; i < midROFs.size(); ++i) { + midSortedROFs[midROFs[i].interactionRecord] = i; + } + + for (const auto& mchROF : mchROFs) { + + // find the MID ROFs in time with the MCH ROF + auto itStartMIDROF = midSortedROFs.lower_bound(mchROF.getBCData()); + auto itEndMIDROF = midSortedROFs.upper_bound(mchROF.getBCData() + (mchROF.getBCWidth() - 1)); + + for (auto iMCHTrack = mchROF.getFirstIdx(); iMCHTrack <= mchROF.getLastIdx(); ++iMCHTrack) { + + double bestMatchChi2(mMaxChi2); + int iBestMIDROF(-1); + uint32_t iBestMIDTrack(0); + + for (auto itMIDROF = itStartMIDROF; itMIDROF != itEndMIDROF; ++itMIDROF) { + + const auto& midROF = midROFs[itMIDROF->second]; + for (auto iMIDTrack = midROF.firstEntry; iMIDTrack < midROF.firstEntry + midROF.nEntries; ++iMIDTrack) { + + // try to match the current MCH track with the current MID track and keep the best matching + double matchChi2 = match(mchTracks[iMCHTrack], midTracks[iMIDTrack]); + if (matchChi2 < bestMatchChi2) { + bestMatchChi2 = matchChi2; + iBestMIDROF = itMIDROF->second; + iBestMIDTrack = uint32_t(iMIDTrack); + } + } + } + + // store the muon track if the matching succeeded + if (iBestMIDROF >= 0) { + mMuons.emplace_back(uint32_t(iMCHTrack), iBestMIDTrack, midROFs[iBestMIDROF].interactionRecord, + bestMatchChi2 / 4.); + } + } + } + + // sort the MUON tracks in increasing BC time + std::stable_sort(mMuons.begin(), mMuons.end(), [](const TrackMCHMID& mu1, const TrackMCHMID& mu2) { + return mu1.getIR() < mu2.getIR(); + }); +} + +//_________________________________________________________________________________________________ +/// compute the matching chi2/ndf between these MCH and MID tracks +double TrackMatcher::match(const mch::TrackMCH& mchTrack, const mid::Track& midTrack) +{ + // compute the (X, slopeX, Y, slopeY) parameters difference between the 2 tracks at the z-position of the MID track + const double* mchParam = mchTrack.getParametersAtMID(); + double dZ = midTrack.getPositionZ() - mchTrack.getZAtMID(); + SVector4 paramDiff(mchParam[0] + mchParam[1] * dZ - midTrack.getPositionX(), + mchParam[1] - midTrack.getDirectionX(), + mchParam[2] + mchParam[3] * dZ - midTrack.getPositionY(), + mchParam[3] - midTrack.getDirectionY()); + + // propagate the MCH track covariances to the z-position of the MID track + SMatrixSym4 mchCov(mchTrack.getCovariancesAtMID(), 10); + SMatrix4 jacobian(ROOT::Math::SMatrixIdentity{}); + jacobian(0, 1) = dZ; + jacobian(2, 3) = dZ; + auto sumCov = ROOT::Math::Similarity(jacobian, mchCov); + + // add the MID track covariances + sumCov(0, 0) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::VarX); + sumCov(1, 0) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::CovXSlopeX); + sumCov(1, 1) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::VarSlopeX); + sumCov(2, 2) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::VarY); + sumCov(3, 2) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::CovYSlopeY); + sumCov(3, 3) += midTrack.getCovarianceParameter(mid::Track::CovarianceParamIndex::VarSlopeY); + + // compute the chi2 + if (!sumCov.Invert()) { + LOG(ERROR) << "Covariance matrix inversion failed: " << sumCov; + return mMaxChi2; + } + return ROOT::Math::Similarity(paramDiff, sumCov); +} + +} // namespace muon +} // namespace o2 diff --git a/Detectors/MUON/Matching/src/TrackMatcherParam.cxx b/Detectors/MUON/Matching/src/TrackMatcherParam.cxx new file mode 100644 index 0000000000000..4153dd87960e4 --- /dev/null +++ b/Detectors/MUON/Matching/src/TrackMatcherParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcherParam.cxx +/// \brief Configurable parameters for MCH-MID track matching +/// \author Philippe Pillot, Subatech + +#include "MUONMatching/TrackMatcherParam.h" + +O2ParamImpl(o2::muon::TrackMatcherParam); diff --git a/Detectors/MUON/README.md b/Detectors/MUON/README.md index a3ce303903b38..0451f4d0c537a 100644 --- a/Detectors/MUON/README.md +++ b/Detectors/MUON/README.md @@ -10,4 +10,7 @@ The MUON subsystem is composed of three detectors : [MFT](../ITSMFT/MFT), [MCH]( * \subpage refDetectorsITSMFT * \subpage refDetectorsMUONMID * \subpage refDetectorsMUONMCH +* \subpage refDetectorsMUONCommon +* \subpage refDetectorsMUONMatching +* \subpage refDetectorsMUONWorkflow /doxy --> diff --git a/Detectors/MUON/Workflow/CMakeLists.txt b/Detectors/MUON/Workflow/CMakeLists.txt new file mode 100644 index 0000000000000..7870ed9332b67 --- /dev/null +++ b/Detectors/MUON/Workflow/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_executable( + tracks-matcher-workflow + SOURCES src/TrackMatcherSpec.cxx src/tracks-matcher-workflow.cxx + COMPONENT_NAME muon + PUBLIC_LINK_LIBRARIES O2::Framework O2::MUONMatching) + +o2_add_executable( + tracks-writer-workflow + SOURCES src/TrackWriterSpec.cxx src/tracks-writer-workflow.cxx + COMPONENT_NAME muon + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::ReconstructionDataFormats) diff --git a/Detectors/MUON/Workflow/README.md b/Detectors/MUON/Workflow/README.md new file mode 100644 index 0000000000000..deefc6f3fd3bb --- /dev/null +++ b/Detectors/MUON/Workflow/README.md @@ -0,0 +1,51 @@ +<!-- doxy +\page refDetectorsMUONWorkflow Workflows +/doxy --> + +# MUON Workflows + +<!-- vim-markdown-toc GFM --> + +* [Matching](#matching) +* [Track writer](#track-writer) + +<!-- vim-markdown-toc --> + +## Matching + +```shell +o2-muon-tracks-matcher-workflow +``` + +Take as input the lists of MCH tracks ([TrackMCH](../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)), MCH ROF records ([ROFRecord](../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)), MID tracks ([Track](../../../DataFormats/Detectors/MUON/MID/include/DataFormatsMID/Track.h)) and MID ROF records ([ROFRecord](../../../DataFormats/Detectors/MUON/MID/include/DataFormatsMID/ROFRecord.h)) in the current time frame, with the data descriptions "MCH/TRACKS", "MCH/TRACKROFS", "MID/TRACKS" and "MID/TRACKSROF", respectively. Send the list of matched tracks ([TrackMCHMID](../../../DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h)) in the time frame, with the data description "GLO/MCHMID". + +Option `--config "file.json"` or `--config "file.ini"` allows to change the matching parameters from a configuration file. This file can be either in JSON or in INI format, as described below: + +* Example of configuration file in JSON format: +```json +{ + "MUONMatching": { + "sigmaCut": "4." + } +} +``` +* Example of configuration file in INI format: +```ini +[MUONMatching] +sigmaCut=4. +``` + +Option `--configKeyValues "key1=value1;key2=value2;..."` allows to change the matching parameters from the command line. The parameters changed from the command line will supersede the ones changed from a configuration file. + +* Example of parameters changed from the command line: +```shell +--configKeyValues "MUONMatching.sigmaCut=4." +``` + +## Track writer + +```shell +o2-muon-tracks-writer-workflow --outfile "muontracks.root" +``` + +Take as input the list of matched tracks ([TrackMCHMID](../../../DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackMCHMID.h)) in the current time frame, with the data description "GLO/MCHMID", and write them in a root file. It is implemented using the generic [MakeRootTreeWriterSpec](../../../Framework/Utils/include/DPLUtils/MakeRootTreeWriterSpec.h) and thus offers the same options. diff --git a/Detectors/MUON/Workflow/src/TrackMatcherSpec.cxx b/Detectors/MUON/Workflow/src/TrackMatcherSpec.cxx new file mode 100644 index 0000000000000..8cb8ae6436c84 --- /dev/null +++ b/Detectors/MUON/Workflow/src/TrackMatcherSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcherSpec.cxx +/// \brief Implementation of a data processor to match MCH and MID tracks +/// +/// \author Philippe Pillot, Subatech + +#include "TrackMatcherSpec.h" + +#include <chrono> +#include <string> +#include <vector> + +#include <gsl/span> + +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMID/ROFRecord.h" +#include "DataFormatsMID/Track.h" +#include "ReconstructionDataFormats/TrackMCHMID.h" +#include "MUONMatching/TrackMatcher.h" + +namespace o2 +{ +namespace muon +{ + +using namespace o2::framework; + +class TrackMatcherTask +{ + public: + //_________________________________________________________________________________________________ + /// prepare the track matching + void init(InitContext& ic) + { + LOG(INFO) << "initializing track matching"; + + auto config = ic.options().get<std::string>("config"); + if (!config.empty()) { + conf::ConfigurableParam::updateFromFile(config, "MUONMatching", true); + } + mTrackMatcher.init(); + + auto stop = [this]() { + LOG(INFO) << "track matching duration = " << mElapsedTime.count() << " s"; + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, stop); + } + + //_________________________________________________________________________________________________ + /// run the track matching + void run(ProcessingContext& pc) + { + auto mchROFs = pc.inputs().get<gsl::span<mch::ROFRecord>>("mchrofs"); + auto mchTracks = pc.inputs().get<gsl::span<mch::TrackMCH>>("mchtracks"); + auto midROFs = pc.inputs().get<gsl::span<mid::ROFRecord>>("midrofs"); + auto midTracks = pc.inputs().get<gsl::span<mid::Track>>("midtracks"); + + auto tStart = std::chrono::high_resolution_clock::now(); + mTrackMatcher.match(mchROFs, mchTracks, midROFs, midTracks); + auto tEnd = std::chrono::high_resolution_clock::now(); + mElapsedTime += tEnd - tStart; + + pc.outputs().snapshot(OutputRef{"muontracks"}, mTrackMatcher.getMuons()); + } + + private: + TrackMatcher mTrackMatcher{}; ///< MCH-MID track matcher + std::chrono::duration<double> mElapsedTime{}; ///< timer +}; + +//_________________________________________________________________________________________________ +DataProcessorSpec getTrackMatcherSpec(const char* name) +{ + return DataProcessorSpec{ + name, + Inputs{InputSpec{"mchrofs", "MCH", "TRACKROFS", 0, Lifetime::Timeframe}, + InputSpec{"mchtracks", "MCH", "TRACKS", 0, Lifetime::Timeframe}, + InputSpec{"midrofs", "MID", "TRACKSROF", 0, Lifetime::Timeframe}, + InputSpec{"midtracks", "MID", "TRACKS", 0, Lifetime::Timeframe}}, + Outputs{OutputSpec{{"muontracks"}, "GLO", "MCHMID", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<TrackMatcherTask>()}, + Options{{"config", VariantType::String, "", {"JSON or INI file with matching parameters"}}}}; +} + +} // namespace muon +} // namespace o2 diff --git a/Detectors/MUON/Workflow/src/TrackMatcherSpec.h b/Detectors/MUON/Workflow/src/TrackMatcherSpec.h new file mode 100644 index 0000000000000..4b39a8fa66a97 --- /dev/null +++ b/Detectors/MUON/Workflow/src/TrackMatcherSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackMatcherSpec.h +/// \brief Definition of a data processor to match MCH and MID tracks +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MUON_TRACKMATCHERSPEC_H_ +#define ALICEO2_MUON_TRACKMATCHERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace muon +{ + +framework::DataProcessorSpec getTrackMatcherSpec(const char* name = "TrackMatcher"); + +} // namespace muon +} // namespace o2 + +#endif // ALICEO2_MUON_TRACKMATCHERSPEC_H_ diff --git a/Detectors/MUON/Workflow/src/TrackWriterSpec.cxx b/Detectors/MUON/Workflow/src/TrackWriterSpec.cxx new file mode 100644 index 0000000000000..4a80bdba237d4 --- /dev/null +++ b/Detectors/MUON/Workflow/src/TrackWriterSpec.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackWriterSpec.cxx +/// \brief Implementation of a data processor to write matched MCH-MID tracks in a root file +/// +/// \author Philippe Pillot, Subatech + +#include "TrackWriterSpec.h" + +#include <vector> + +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "ReconstructionDataFormats/TrackMCHMID.h" + +namespace o2 +{ +namespace muon +{ + +using namespace o2::framework; + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +DataProcessorSpec getTrackWriterSpec(const char* specName, const char* fileName) +{ + return MakeRootTreeWriterSpec(specName, + fileName, + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree Matched MCH-MID Tracks"}, + BranchDefinition<std::vector<dataformats::TrackMCHMID>>{InputSpec{"tracks", "GLO", "MCHMID"}, "tracks"})(); +} + +} // namespace muon +} // namespace o2 diff --git a/Detectors/MUON/Workflow/src/TrackWriterSpec.h b/Detectors/MUON/Workflow/src/TrackWriterSpec.h new file mode 100644 index 0000000000000..44cf49c0ba2b5 --- /dev/null +++ b/Detectors/MUON/Workflow/src/TrackWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackWriterSpec.h +/// \brief Definition of a data processor to write matched MCH-MID tracks in a root file +/// +/// \author Philippe Pillot, Subatech + +#ifndef ALICEO2_MUON_TRACKWRITERSPEC_H_ +#define ALICEO2_MUON_TRACKWRITERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace muon +{ + +framework::DataProcessorSpec getTrackWriterSpec(const char* specName = "TrackWriter", + const char* fileName = "muontracks.root"); + +} // namespace muon +} // namespace o2 + +#endif // ALICEO2_MUON_TRACKWRITERSPEC_H_ diff --git a/Detectors/MUON/Workflow/src/tracks-matcher-workflow.cxx b/Detectors/MUON/Workflow/src/tracks-matcher-workflow.cxx new file mode 100644 index 0000000000000..fe333d2ccc3b2 --- /dev/null +++ b/Detectors/MUON/Workflow/src/tracks-matcher-workflow.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file tracks-matcher-workflow.cxx +/// \brief Implementation of a DPL device to run the MCH-MID track matcher +/// +/// \author Philippe Pillot, Subatech + +#include <string> +#include <vector> +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConfigContext.h" +#include "Framework/WorkflowSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TrackMatcherSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.emplace_back("configKeyValues", VariantType::String, "", + ConfigParamSpec::HelpString{"Semicolon separated key=value strings"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + return WorkflowSpec{o2::muon::getTrackMatcherSpec()}; +} diff --git a/Detectors/MUON/Workflow/src/tracks-writer-workflow.cxx b/Detectors/MUON/Workflow/src/tracks-writer-workflow.cxx new file mode 100644 index 0000000000000..07c789c88590c --- /dev/null +++ b/Detectors/MUON/Workflow/src/tracks-writer-workflow.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file tracks-writer-workflow.cxx +/// \brief Implementation of a DPL device to run the MCH-MID track writer +/// +/// \author Philippe Pillot, Subatech + +#include "Framework/runDataProcessing.h" +#include "TrackWriterSpec.h" + +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(const ConfigContext&) +{ + return WorkflowSpec{o2::muon::getTrackWriterSpec()}; +} diff --git a/Detectors/PHOS/CMakeLists.txt b/Detectors/PHOS/CMakeLists.txt index 1a5260de68324..72cfdf2ef2b9c 100644 --- a/Detectors/PHOS/CMakeLists.txt +++ b/Detectors/PHOS/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(calib) diff --git a/Detectors/PHOS/README.md b/Detectors/PHOS/README.md new file mode 100644 index 0000000000000..e3b9d18f86db0 --- /dev/null +++ b/Detectors/PHOS/README.md @@ -0,0 +1,14 @@ +<!-- doxy +\page refDetectorsPHOS PHOS +/doxy --> + +# PHOS + +This is a top page for the PHOS detector documentation. + +<!-- doxy +\subpage refDetectorsPHOSGeometry +*\subpage refDetectorsPHOSsimulation +*\subpage refDetectorsPHOSreconstruction +\subpage refDetectorsPHOScalibration +/doxy --> \ No newline at end of file diff --git a/Detectors/PHOS/base/CMakeLists.txt b/Detectors/PHOS/base/CMakeLists.txt index 7c95cac985a23..93023e90ffd92 100644 --- a/Detectors/PHOS/base/CMakeLists.txt +++ b/Detectors/PHOS/base/CMakeLists.txt @@ -1,21 +1,27 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(PHOSBase SOURCES src/Geometry.cxx src/Hit.cxx src/PHOSSimParams.cxx + src/RCUTrailer.cxx + src/Mapping.cxx PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::SimConfig) o2_target_root_dictionary(PHOSBase HEADERS include/PHOSBase/Geometry.h include/PHOSBase/Hit.h - include/PHOSBase/PHOSSimParams.h) + include/PHOSBase/PHOSSimParams.h + include/PHOSBase/RCUTrailer.h + include/PHOSBase/Mapping.h) +o2_data_file(COPY files DESTINATION Detectors/PHOS) diff --git a/Detectors/PHOS/base/README.md b/Detectors/PHOS/base/README.md new file mode 100644 index 0000000000000..c7d4d441c34f7 --- /dev/null +++ b/Detectors/PHOS/base/README.md @@ -0,0 +1,27 @@ +<!-- doxy +\page refDetectorsPHOSGeometry PHOS Geometry +/doxy --> + +# PHOS geometry + +Module numbering: start from module 0 (non-existing), 1 (half-module), 2 (bottom),... 4(highest) + +All channels have unique absId: start from 1 till 4x64x56 (no absId in non-existing module). Numbering in each module starts at bottom left and first go in z direction: +``` + 56 112 3584 + ... ... ... + 1 57 ...3529 +``` +One can use also relative numbering relid[3]: +(module number[0...3], iphi[1...64], iz[1...56]) + + Then TRU channels go 112 per branch, 2 branches per ddl +tru channels have absId after readout channels: + absId = getTotalNCells() + TRUabsId ; + relId for TRU + relid: [DDL id=0..13] [x in 2x2 system: 0..7] [z in 2x2 system 0..27] + +Mapping is realized with class Mapping and mapping files are stored as MODxRCUy.data + +<!-- doxy +/doxy --> \ No newline at end of file diff --git a/Detectors/PHOS/base/files/Mod0RCU0.data b/Detectors/PHOS/base/files/Mod0RCU0.data new file mode 100644 index 0000000000000..4739df6e3e61e --- /dev/null +++ b/Detectors/PHOS/base/files/Mod0RCU0.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 0 0 2 + 1 0 1 2 + 2 0 2 2 + 3 0 3 2 + 4 0 4 2 + 5 0 5 2 + 6 0 6 2 + 7 0 7 2 + 8 0 8 2 + 9 0 9 2 + 10 0 10 2 + 11 0 11 2 + 12 0 12 2 + 13 0 13 2 + 14 0 14 2 + 15 0 15 2 + 16 0 16 2 + 17 0 17 2 + 18 0 18 2 + 19 0 19 2 + 20 0 20 2 + 21 0 21 2 + 22 0 22 2 + 23 0 23 2 + 24 0 24 2 + 25 0 25 2 + 26 0 26 2 + 27 0 27 2 + 28 0 28 2 + 29 0 29 2 + 30 0 30 2 + 31 0 31 2 + 32 0 32 2 + 33 0 33 2 + 34 0 34 2 + 35 0 35 2 + 36 0 36 2 + 37 0 37 2 + 38 0 38 2 + 39 0 39 2 + 40 0 40 2 + 41 0 41 2 + 42 0 42 2 + 43 0 43 2 + 44 0 44 2 + 45 0 45 2 + 46 0 46 2 + 47 0 47 2 + 48 0 48 2 + 49 0 49 2 + 50 0 50 2 + 51 0 51 2 + 52 0 52 2 + 53 0 53 2 + 54 0 54 2 + 55 0 55 2 + 56 0 56 2 + 57 0 57 2 + 58 0 58 2 + 59 0 59 2 + 60 0 60 2 + 61 0 61 2 + 62 0 62 2 + 63 0 63 2 + 64 0 64 2 + 65 0 65 2 + 66 0 66 2 + 67 0 67 2 + 68 0 68 2 + 69 0 69 2 + 70 0 70 2 + 71 0 71 2 + 72 0 72 2 + 73 0 73 2 + 74 0 74 2 + 75 0 75 2 + 76 0 76 2 + 77 0 77 2 + 78 0 78 2 + 79 0 79 2 + 80 0 80 2 + 81 0 81 2 + 82 0 82 2 + 83 0 83 2 + 84 0 84 2 + 85 0 85 2 + 86 0 86 2 + 87 0 87 2 + 88 0 88 2 + 89 0 89 2 + 90 0 90 2 + 91 0 91 2 + 92 0 92 2 + 93 0 93 2 + 94 0 94 2 + 95 0 95 2 + 96 0 96 2 + 97 0 97 2 + 98 0 98 2 + 99 0 99 2 + 100 0 100 2 + 101 0 101 2 + 102 0 102 2 + 103 0 103 2 + 104 0 104 2 + 105 0 105 2 + 106 0 106 2 + 107 0 107 2 + 108 0 108 2 + 109 0 109 2 + 110 0 110 2 + 111 0 111 2 + 112 0 112 2 + 113 0 113 2 + 114 0 114 2 + 115 0 115 2 + 116 0 116 2 + 117 0 117 2 + 118 0 118 2 + 119 0 119 2 + 120 0 120 2 + 121 0 121 2 + 122 0 122 2 + 123 0 123 2 + 124 0 124 2 + 125 0 125 2 + 126 0 126 2 + 127 0 127 2 +2048 0 2048 2 +2049 0 2049 2 +2050 0 2050 2 +2051 0 2051 2 +2052 0 2052 2 +2053 0 2053 2 +2054 0 2054 2 +2055 0 2055 2 +2056 0 2056 2 +2057 0 2057 2 +2058 0 2058 2 +2059 0 2059 2 +2060 0 2060 2 +2061 0 2061 2 +2062 0 2062 2 +2063 0 2063 2 +2064 0 2064 2 +2065 0 2065 2 +2066 0 2066 2 +2067 0 2067 2 +2068 0 2068 2 +2069 0 2069 2 +2070 0 2070 2 +2071 0 2071 2 +2072 0 2072 2 +2073 0 2073 2 +2074 0 2074 2 +2075 0 2075 2 +2076 0 2076 2 +2077 0 2077 2 +2078 0 2078 2 +2079 0 2079 2 +2080 0 2080 2 +2081 0 2081 2 +2082 0 2082 2 +2083 0 2083 2 +2084 0 2084 2 +2085 0 2085 2 +2086 0 2086 2 +2087 0 2087 2 +2088 0 2088 2 +2089 0 2089 2 +2090 0 2090 2 +2091 0 2091 2 +2092 0 2092 2 +2093 0 2093 2 +2094 0 2094 2 +2095 0 2095 2 +2096 0 2096 2 +2097 0 2097 2 +2098 0 2098 2 +2099 0 2099 2 +2100 0 2100 2 +2101 0 2101 2 +2102 0 2102 2 +2103 0 2103 2 +2104 0 2104 2 +2105 0 2105 2 +2106 0 2106 2 +2107 0 2107 2 +2108 0 2108 2 +2109 0 2109 2 +2110 0 2110 2 +2111 0 2111 2 +2112 0 2112 2 +2113 0 2113 2 +2114 0 2114 2 +2115 0 2115 2 +2116 0 2116 2 +2117 0 2117 2 +2118 0 2118 2 +2119 0 2119 2 +2120 0 2120 2 +2121 0 2121 2 +2122 0 2122 2 +2123 0 2123 2 +2124 0 2124 2 +2125 0 2125 2 +2126 0 2126 2 +2127 0 2127 2 +2128 0 2128 2 +2129 0 2129 2 +2130 0 2130 2 +2131 0 2131 2 +2132 0 2132 2 +2133 0 2133 2 +2134 0 2134 2 +2135 0 2135 2 +2136 0 2136 2 +2137 0 2137 2 +2138 0 2138 2 +2139 0 2139 2 +2140 0 2140 2 +2141 0 2141 2 +2142 0 2142 2 +2143 0 2143 2 +2144 0 2144 2 +2145 0 2145 2 +2146 0 2146 2 +2147 0 2147 2 +2148 0 2148 2 +2149 0 2149 2 +2150 0 2150 2 +2151 0 2151 2 +2152 0 2152 2 +2153 0 2153 2 +2154 0 2154 2 +2155 0 2155 2 +2156 0 2156 2 +2157 0 2157 2 +2158 0 2158 2 +2159 0 2159 2 +2160 0 2160 2 +2161 0 2161 2 +2162 0 2162 2 +2163 0 2163 2 +2164 0 2164 2 +2165 0 2165 2 +2166 0 2166 2 +2167 0 2167 2 +2168 0 2168 2 +2169 0 2169 2 +2170 0 2170 2 +2171 0 2171 2 +2172 0 2172 2 +2173 0 2173 2 +2174 0 2174 2 +2175 0 2175 2 + 128 11 29 0 + 129 11 29 1 + 130 11 28 0 + 131 11 28 1 + 132 10 29 0 + 133 10 29 1 + 134 10 28 0 + 135 10 28 1 + 136 8 28 1 + 137 8 28 0 + 138 8 29 1 + 139 8 29 0 + 140 9 28 1 + 141 9 28 0 + 142 9 29 1 + 143 9 29 0 + 160 3 28 0 + 161 3 28 1 + 162 3 29 0 + 163 3 29 1 + 164 2 28 0 + 165 2 28 1 + 166 2 29 0 + 167 2 29 1 + 168 0 29 1 + 169 0 29 0 + 170 0 28 1 + 171 0 28 0 + 172 1 29 1 + 173 1 29 0 + 174 1 28 1 + 175 1 28 0 + 176 4 28 0 + 177 4 28 1 + 178 4 29 0 + 179 4 29 1 + 180 5 28 0 + 181 5 28 1 + 182 5 29 0 + 183 5 29 1 + 184 7 29 1 + 185 7 29 0 + 186 7 28 1 + 187 7 28 0 + 188 6 29 1 + 189 6 29 0 + 190 6 28 1 + 191 6 28 0 + 192 12 29 0 + 193 12 29 1 + 194 12 28 0 + 195 12 28 1 + 196 13 29 0 + 197 13 29 1 + 198 13 28 0 + 199 13 28 1 + 200 15 28 1 + 201 15 28 0 + 202 15 29 1 + 203 15 29 0 + 204 14 28 1 + 205 14 28 0 + 206 14 29 1 + 207 14 29 0 + 256 11 31 0 + 257 11 31 1 + 258 11 30 0 + 259 11 30 1 + 260 10 31 0 + 261 10 31 1 + 262 10 30 0 + 263 10 30 1 + 264 8 30 1 + 265 8 30 0 + 266 8 31 1 + 267 8 31 0 + 268 9 30 1 + 269 9 30 0 + 270 9 31 1 + 271 9 31 0 + 288 3 30 0 + 289 3 30 1 + 290 3 31 0 + 291 3 31 1 + 292 2 30 0 + 293 2 30 1 + 294 2 31 0 + 295 2 31 1 + 296 0 31 1 + 297 0 31 0 + 298 0 30 1 + 299 0 30 0 + 300 1 31 1 + 301 1 31 0 + 302 1 30 1 + 303 1 30 0 + 304 4 30 0 + 305 4 30 1 + 306 4 31 0 + 307 4 31 1 + 308 5 30 0 + 309 5 30 1 + 310 5 31 0 + 311 5 31 1 + 312 7 31 1 + 313 7 31 0 + 314 7 30 1 + 315 7 30 0 + 316 6 31 1 + 317 6 31 0 + 318 6 30 1 + 319 6 30 0 + 320 12 31 0 + 321 12 31 1 + 322 12 30 0 + 323 12 30 1 + 324 13 31 0 + 325 13 31 1 + 326 13 30 0 + 327 13 30 1 + 328 15 30 1 + 329 15 30 0 + 330 15 31 1 + 331 15 31 0 + 332 14 30 1 + 333 14 30 0 + 334 14 31 1 + 335 14 31 0 + 384 11 33 0 + 385 11 33 1 + 386 11 32 0 + 387 11 32 1 + 388 10 33 0 + 389 10 33 1 + 390 10 32 0 + 391 10 32 1 + 392 8 32 1 + 393 8 32 0 + 394 8 33 1 + 395 8 33 0 + 396 9 32 1 + 397 9 32 0 + 398 9 33 1 + 399 9 33 0 + 416 3 32 0 + 417 3 32 1 + 418 3 33 0 + 419 3 33 1 + 420 2 32 0 + 421 2 32 1 + 422 2 33 0 + 423 2 33 1 + 424 0 33 1 + 425 0 33 0 + 426 0 32 1 + 427 0 32 0 + 428 1 33 1 + 429 1 33 0 + 430 1 32 1 + 431 1 32 0 + 432 4 32 0 + 433 4 32 1 + 434 4 33 0 + 435 4 33 1 + 436 5 32 0 + 437 5 32 1 + 438 5 33 0 + 439 5 33 1 + 440 7 33 1 + 441 7 33 0 + 442 7 32 1 + 443 7 32 0 + 444 6 33 1 + 445 6 33 0 + 446 6 32 1 + 447 6 32 0 + 448 12 33 0 + 449 12 33 1 + 450 12 32 0 + 451 12 32 1 + 452 13 33 0 + 453 13 33 1 + 454 13 32 0 + 455 13 32 1 + 456 15 32 1 + 457 15 32 0 + 458 15 33 1 + 459 15 33 0 + 460 14 32 1 + 461 14 32 0 + 462 14 33 1 + 463 14 33 0 + 512 11 35 0 + 513 11 35 1 + 514 11 34 0 + 515 11 34 1 + 516 10 35 0 + 517 10 35 1 + 518 10 34 0 + 519 10 34 1 + 520 8 34 1 + 521 8 34 0 + 522 8 35 1 + 523 8 35 0 + 524 9 34 1 + 525 9 34 0 + 526 9 35 1 + 527 9 35 0 + 544 3 34 0 + 545 3 34 1 + 546 3 35 0 + 547 3 35 1 + 548 2 34 0 + 549 2 34 1 + 550 2 35 0 + 551 2 35 1 + 552 0 35 1 + 553 0 35 0 + 554 0 34 1 + 555 0 34 0 + 556 1 35 1 + 557 1 35 0 + 558 1 34 1 + 559 1 34 0 + 560 4 34 0 + 561 4 34 1 + 562 4 35 0 + 563 4 35 1 + 564 5 34 0 + 565 5 34 1 + 566 5 35 0 + 567 5 35 1 + 568 7 35 1 + 569 7 35 0 + 570 7 34 1 + 571 7 34 0 + 572 6 35 1 + 573 6 35 0 + 574 6 34 1 + 575 6 34 0 + 576 12 35 0 + 577 12 35 1 + 578 12 34 0 + 579 12 34 1 + 580 13 35 0 + 581 13 35 1 + 582 13 34 0 + 583 13 34 1 + 584 15 34 1 + 585 15 34 0 + 586 15 35 1 + 587 15 35 0 + 588 14 34 1 + 589 14 34 0 + 590 14 35 1 + 591 14 35 0 + 640 11 37 0 + 641 11 37 1 + 642 11 36 0 + 643 11 36 1 + 644 10 37 0 + 645 10 37 1 + 646 10 36 0 + 647 10 36 1 + 648 8 36 1 + 649 8 36 0 + 650 8 37 1 + 651 8 37 0 + 652 9 36 1 + 653 9 36 0 + 654 9 37 1 + 655 9 37 0 + 672 3 36 0 + 673 3 36 1 + 674 3 37 0 + 675 3 37 1 + 676 2 36 0 + 677 2 36 1 + 678 2 37 0 + 679 2 37 1 + 680 0 37 1 + 681 0 37 0 + 682 0 36 1 + 683 0 36 0 + 684 1 37 1 + 685 1 37 0 + 686 1 36 1 + 687 1 36 0 + 688 4 36 0 + 689 4 36 1 + 690 4 37 0 + 691 4 37 1 + 692 5 36 0 + 693 5 36 1 + 694 5 37 0 + 695 5 37 1 + 696 7 37 1 + 697 7 37 0 + 698 7 36 1 + 699 7 36 0 + 700 6 37 1 + 701 6 37 0 + 702 6 36 1 + 703 6 36 0 + 704 12 37 0 + 705 12 37 1 + 706 12 36 0 + 707 12 36 1 + 708 13 37 0 + 709 13 37 1 + 710 13 36 0 + 711 13 36 1 + 712 15 36 1 + 713 15 36 0 + 714 15 37 1 + 715 15 37 0 + 716 14 36 1 + 717 14 36 0 + 718 14 37 1 + 719 14 37 0 + 768 11 39 0 + 769 11 39 1 + 770 11 38 0 + 771 11 38 1 + 772 10 39 0 + 773 10 39 1 + 774 10 38 0 + 775 10 38 1 + 776 8 38 1 + 777 8 38 0 + 778 8 39 1 + 779 8 39 0 + 780 9 38 1 + 781 9 38 0 + 782 9 39 1 + 783 9 39 0 + 800 3 38 0 + 801 3 38 1 + 802 3 39 0 + 803 3 39 1 + 804 2 38 0 + 805 2 38 1 + 806 2 39 0 + 807 2 39 1 + 808 0 39 1 + 809 0 39 0 + 810 0 38 1 + 811 0 38 0 + 812 1 39 1 + 813 1 39 0 + 814 1 38 1 + 815 1 38 0 + 816 4 38 0 + 817 4 38 1 + 818 4 39 0 + 819 4 39 1 + 820 5 38 0 + 821 5 38 1 + 822 5 39 0 + 823 5 39 1 + 824 7 39 1 + 825 7 39 0 + 826 7 38 1 + 827 7 38 0 + 828 6 39 1 + 829 6 39 0 + 830 6 38 1 + 831 6 38 0 + 832 12 39 0 + 833 12 39 1 + 834 12 38 0 + 835 12 38 1 + 836 13 39 0 + 837 13 39 1 + 838 13 38 0 + 839 13 38 1 + 840 15 38 1 + 841 15 38 0 + 842 15 39 1 + 843 15 39 0 + 844 14 38 1 + 845 14 38 0 + 846 14 39 1 + 847 14 39 0 + 896 11 41 0 + 897 11 41 1 + 898 11 40 0 + 899 11 40 1 + 900 10 41 0 + 901 10 41 1 + 902 10 40 0 + 903 10 40 1 + 904 8 40 1 + 905 8 40 0 + 906 8 41 1 + 907 8 41 0 + 908 9 40 1 + 909 9 40 0 + 910 9 41 1 + 911 9 41 0 + 928 3 40 0 + 929 3 40 1 + 930 3 41 0 + 931 3 41 1 + 932 2 40 0 + 933 2 40 1 + 934 2 41 0 + 935 2 41 1 + 936 0 41 1 + 937 0 41 0 + 938 0 40 1 + 939 0 40 0 + 940 1 41 1 + 941 1 41 0 + 942 1 40 1 + 943 1 40 0 + 944 4 40 0 + 945 4 40 1 + 946 4 41 0 + 947 4 41 1 + 948 5 40 0 + 949 5 40 1 + 950 5 41 0 + 951 5 41 1 + 952 7 41 1 + 953 7 41 0 + 954 7 40 1 + 955 7 40 0 + 956 6 41 1 + 957 6 41 0 + 958 6 40 1 + 959 6 40 0 + 960 12 41 0 + 961 12 41 1 + 962 12 40 0 + 963 12 40 1 + 964 13 41 0 + 965 13 41 1 + 966 13 40 0 + 967 13 40 1 + 968 15 40 1 + 969 15 40 0 + 970 15 41 1 + 971 15 41 0 + 972 14 40 1 + 973 14 40 0 + 974 14 41 1 + 975 14 41 0 +1024 11 43 0 +1025 11 43 1 +1026 11 42 0 +1027 11 42 1 +1028 10 43 0 +1029 10 43 1 +1030 10 42 0 +1031 10 42 1 +1032 8 42 1 +1033 8 42 0 +1034 8 43 1 +1035 8 43 0 +1036 9 42 1 +1037 9 42 0 +1038 9 43 1 +1039 9 43 0 +1056 3 42 0 +1057 3 42 1 +1058 3 43 0 +1059 3 43 1 +1060 2 42 0 +1061 2 42 1 +1062 2 43 0 +1063 2 43 1 +1064 0 43 1 +1065 0 43 0 +1066 0 42 1 +1067 0 42 0 +1068 1 43 1 +1069 1 43 0 +1070 1 42 1 +1071 1 42 0 +1072 4 42 0 +1073 4 42 1 +1074 4 43 0 +1075 4 43 1 +1076 5 42 0 +1077 5 42 1 +1078 5 43 0 +1079 5 43 1 +1080 7 43 1 +1081 7 43 0 +1082 7 42 1 +1083 7 42 0 +1084 6 43 1 +1085 6 43 0 +1086 6 42 1 +1087 6 42 0 +1088 12 43 0 +1089 12 43 1 +1090 12 42 0 +1091 12 42 1 +1092 13 43 0 +1093 13 43 1 +1094 13 42 0 +1095 13 42 1 +1096 15 42 1 +1097 15 42 0 +1098 15 43 1 +1099 15 43 0 +1100 14 42 1 +1101 14 42 0 +1102 14 43 1 +1103 14 43 0 +1152 11 45 0 +1153 11 45 1 +1154 11 44 0 +1155 11 44 1 +1156 10 45 0 +1157 10 45 1 +1158 10 44 0 +1159 10 44 1 +1160 8 44 1 +1161 8 44 0 +1162 8 45 1 +1163 8 45 0 +1164 9 44 1 +1165 9 44 0 +1166 9 45 1 +1167 9 45 0 +1184 3 44 0 +1185 3 44 1 +1186 3 45 0 +1187 3 45 1 +1188 2 44 0 +1189 2 44 1 +1190 2 45 0 +1191 2 45 1 +1192 0 45 1 +1193 0 45 0 +1194 0 44 1 +1195 0 44 0 +1196 1 45 1 +1197 1 45 0 +1198 1 44 1 +1199 1 44 0 +1200 4 44 0 +1201 4 44 1 +1202 4 45 0 +1203 4 45 1 +1204 5 44 0 +1205 5 44 1 +1206 5 45 0 +1207 5 45 1 +1208 7 45 1 +1209 7 45 0 +1210 7 44 1 +1211 7 44 0 +1212 6 45 1 +1213 6 45 0 +1214 6 44 1 +1215 6 44 0 +1216 12 45 0 +1217 12 45 1 +1218 12 44 0 +1219 12 44 1 +1220 13 45 0 +1221 13 45 1 +1222 13 44 0 +1223 13 44 1 +1224 15 44 1 +1225 15 44 0 +1226 15 45 1 +1227 15 45 0 +1228 14 44 1 +1229 14 44 0 +1230 14 45 1 +1231 14 45 0 +1280 11 47 0 +1281 11 47 1 +1282 11 46 0 +1283 11 46 1 +1284 10 47 0 +1285 10 47 1 +1286 10 46 0 +1287 10 46 1 +1288 8 46 1 +1289 8 46 0 +1290 8 47 1 +1291 8 47 0 +1292 9 46 1 +1293 9 46 0 +1294 9 47 1 +1295 9 47 0 +1312 3 46 0 +1313 3 46 1 +1314 3 47 0 +1315 3 47 1 +1316 2 46 0 +1317 2 46 1 +1318 2 47 0 +1319 2 47 1 +1320 0 47 1 +1321 0 47 0 +1322 0 46 1 +1323 0 46 0 +1324 1 47 1 +1325 1 47 0 +1326 1 46 1 +1327 1 46 0 +1328 4 46 0 +1329 4 46 1 +1330 4 47 0 +1331 4 47 1 +1332 5 46 0 +1333 5 46 1 +1334 5 47 0 +1335 5 47 1 +1336 7 47 1 +1337 7 47 0 +1338 7 46 1 +1339 7 46 0 +1340 6 47 1 +1341 6 47 0 +1342 6 46 1 +1343 6 46 0 +1344 12 47 0 +1345 12 47 1 +1346 12 46 0 +1347 12 46 1 +1348 13 47 0 +1349 13 47 1 +1350 13 46 0 +1351 13 46 1 +1352 15 46 1 +1353 15 46 0 +1354 15 47 1 +1355 15 47 0 +1356 14 46 1 +1357 14 46 0 +1358 14 47 1 +1359 14 47 0 +1408 11 49 0 +1409 11 49 1 +1410 11 48 0 +1411 11 48 1 +1412 10 49 0 +1413 10 49 1 +1414 10 48 0 +1415 10 48 1 +1416 8 48 1 +1417 8 48 0 +1418 8 49 1 +1419 8 49 0 +1420 9 48 1 +1421 9 48 0 +1422 9 49 1 +1423 9 49 0 +1440 3 48 0 +1441 3 48 1 +1442 3 49 0 +1443 3 49 1 +1444 2 48 0 +1445 2 48 1 +1446 2 49 0 +1447 2 49 1 +1448 0 49 1 +1449 0 49 0 +1450 0 48 1 +1451 0 48 0 +1452 1 49 1 +1453 1 49 0 +1454 1 48 1 +1455 1 48 0 +1456 4 48 0 +1457 4 48 1 +1458 4 49 0 +1459 4 49 1 +1460 5 48 0 +1461 5 48 1 +1462 5 49 0 +1463 5 49 1 +1464 7 49 1 +1465 7 49 0 +1466 7 48 1 +1467 7 48 0 +1468 6 49 1 +1469 6 49 0 +1470 6 48 1 +1471 6 48 0 +1472 12 49 0 +1473 12 49 1 +1474 12 48 0 +1475 12 48 1 +1476 13 49 0 +1477 13 49 1 +1478 13 48 0 +1479 13 48 1 +1480 15 48 1 +1481 15 48 0 +1482 15 49 1 +1483 15 49 0 +1484 14 48 1 +1485 14 48 0 +1486 14 49 1 +1487 14 49 0 +1536 11 51 0 +1537 11 51 1 +1538 11 50 0 +1539 11 50 1 +1540 10 51 0 +1541 10 51 1 +1542 10 50 0 +1543 10 50 1 +1544 8 50 1 +1545 8 50 0 +1546 8 51 1 +1547 8 51 0 +1548 9 50 1 +1549 9 50 0 +1550 9 51 1 +1551 9 51 0 +1568 3 50 0 +1569 3 50 1 +1570 3 51 0 +1571 3 51 1 +1572 2 50 0 +1573 2 50 1 +1574 2 51 0 +1575 2 51 1 +1576 0 51 1 +1577 0 51 0 +1578 0 50 1 +1579 0 50 0 +1580 1 51 1 +1581 1 51 0 +1582 1 50 1 +1583 1 50 0 +1584 4 50 0 +1585 4 50 1 +1586 4 51 0 +1587 4 51 1 +1588 5 50 0 +1589 5 50 1 +1590 5 51 0 +1591 5 51 1 +1592 7 51 1 +1593 7 51 0 +1594 7 50 1 +1595 7 50 0 +1596 6 51 1 +1597 6 51 0 +1598 6 50 1 +1599 6 50 0 +1600 12 51 0 +1601 12 51 1 +1602 12 50 0 +1603 12 50 1 +1604 13 51 0 +1605 13 51 1 +1606 13 50 0 +1607 13 50 1 +1608 15 50 1 +1609 15 50 0 +1610 15 51 1 +1611 15 51 0 +1612 14 50 1 +1613 14 50 0 +1614 14 51 1 +1615 14 51 0 +1664 11 53 0 +1665 11 53 1 +1666 11 52 0 +1667 11 52 1 +1668 10 53 0 +1669 10 53 1 +1670 10 52 0 +1671 10 52 1 +1672 8 52 1 +1673 8 52 0 +1674 8 53 1 +1675 8 53 0 +1676 9 52 1 +1677 9 52 0 +1678 9 53 1 +1679 9 53 0 +1696 3 52 0 +1697 3 52 1 +1698 3 53 0 +1699 3 53 1 +1700 2 52 0 +1701 2 52 1 +1702 2 53 0 +1703 2 53 1 +1704 0 53 1 +1705 0 53 0 +1706 0 52 1 +1707 0 52 0 +1708 1 53 1 +1709 1 53 0 +1710 1 52 1 +1711 1 52 0 +1712 4 52 0 +1713 4 52 1 +1714 4 53 0 +1715 4 53 1 +1716 5 52 0 +1717 5 52 1 +1718 5 53 0 +1719 5 53 1 +1720 7 53 1 +1721 7 53 0 +1722 7 52 1 +1723 7 52 0 +1724 6 53 1 +1725 6 53 0 +1726 6 52 1 +1727 6 52 0 +1728 12 53 0 +1729 12 53 1 +1730 12 52 0 +1731 12 52 1 +1732 13 53 0 +1733 13 53 1 +1734 13 52 0 +1735 13 52 1 +1736 15 52 1 +1737 15 52 0 +1738 15 53 1 +1739 15 53 0 +1740 14 52 1 +1741 14 52 0 +1742 14 53 1 +1743 14 53 0 +1792 11 55 0 +1793 11 55 1 +1794 11 54 0 +1795 11 54 1 +1796 10 55 0 +1797 10 55 1 +1798 10 54 0 +1799 10 54 1 +1800 8 54 1 +1801 8 54 0 +1802 8 55 1 +1803 8 55 0 +1804 9 54 1 +1805 9 54 0 +1806 9 55 1 +1807 9 55 0 +1824 3 54 0 +1825 3 54 1 +1826 3 55 0 +1827 3 55 1 +1828 2 54 0 +1829 2 54 1 +1830 2 55 0 +1831 2 55 1 +1832 0 55 1 +1833 0 55 0 +1834 0 54 1 +1835 0 54 0 +1836 1 55 1 +1837 1 55 0 +1838 1 54 1 +1839 1 54 0 +1840 4 54 0 +1841 4 54 1 +1842 4 55 0 +1843 4 55 1 +1844 5 54 0 +1845 5 54 1 +1846 5 55 0 +1847 5 55 1 +1848 7 55 1 +1849 7 55 0 +1850 7 54 1 +1851 7 54 0 +1852 6 55 1 +1853 6 55 0 +1854 6 54 1 +1855 6 54 0 +1856 12 55 0 +1857 12 55 1 +1858 12 54 0 +1859 12 54 1 +1860 13 55 0 +1861 13 55 1 +1862 13 54 0 +1863 13 54 1 +1864 15 54 1 +1865 15 54 0 +1866 15 55 1 +1867 15 55 0 +1868 14 54 1 +1869 14 54 0 +1870 14 55 1 +1871 14 55 0 +2176 11 27 0 +2177 11 27 1 +2178 11 26 0 +2179 11 26 1 +2180 10 27 0 +2181 10 27 1 +2182 10 26 0 +2183 10 26 1 +2184 8 26 1 +2185 8 26 0 +2186 8 27 1 +2187 8 27 0 +2188 9 26 1 +2189 9 26 0 +2190 9 27 1 +2191 9 27 0 +2208 3 26 0 +2209 3 26 1 +2210 3 27 0 +2211 3 27 1 +2212 2 26 0 +2213 2 26 1 +2214 2 27 0 +2215 2 27 1 +2216 0 27 1 +2217 0 27 0 +2218 0 26 1 +2219 0 26 0 +2220 1 27 1 +2221 1 27 0 +2222 1 26 1 +2223 1 26 0 +2224 4 26 0 +2225 4 26 1 +2226 4 27 0 +2227 4 27 1 +2228 5 26 0 +2229 5 26 1 +2230 5 27 0 +2231 5 27 1 +2232 7 27 1 +2233 7 27 0 +2234 7 26 1 +2235 7 26 0 +2236 6 27 1 +2237 6 27 0 +2238 6 26 1 +2239 6 26 0 +2240 12 27 0 +2241 12 27 1 +2242 12 26 0 +2243 12 26 1 +2244 13 27 0 +2245 13 27 1 +2246 13 26 0 +2247 13 26 1 +2248 15 26 1 +2249 15 26 0 +2250 15 27 1 +2251 15 27 0 +2252 14 26 1 +2253 14 26 0 +2254 14 27 1 +2255 14 27 0 +2304 11 25 0 +2305 11 25 1 +2306 11 24 0 +2307 11 24 1 +2308 10 25 0 +2309 10 25 1 +2310 10 24 0 +2311 10 24 1 +2312 8 24 1 +2313 8 24 0 +2314 8 25 1 +2315 8 25 0 +2316 9 24 1 +2317 9 24 0 +2318 9 25 1 +2319 9 25 0 +2336 3 24 0 +2337 3 24 1 +2338 3 25 0 +2339 3 25 1 +2340 2 24 0 +2341 2 24 1 +2342 2 25 0 +2343 2 25 1 +2344 0 25 1 +2345 0 25 0 +2346 0 24 1 +2347 0 24 0 +2348 1 25 1 +2349 1 25 0 +2350 1 24 1 +2351 1 24 0 +2352 4 24 0 +2353 4 24 1 +2354 4 25 0 +2355 4 25 1 +2356 5 24 0 +2357 5 24 1 +2358 5 25 0 +2359 5 25 1 +2360 7 25 1 +2361 7 25 0 +2362 7 24 1 +2363 7 24 0 +2364 6 25 1 +2365 6 25 0 +2366 6 24 1 +2367 6 24 0 +2368 12 25 0 +2369 12 25 1 +2370 12 24 0 +2371 12 24 1 +2372 13 25 0 +2373 13 25 1 +2374 13 24 0 +2375 13 24 1 +2376 15 24 1 +2377 15 24 0 +2378 15 25 1 +2379 15 25 0 +2380 14 24 1 +2381 14 24 0 +2382 14 25 1 +2383 14 25 0 +2432 11 23 0 +2433 11 23 1 +2434 11 22 0 +2435 11 22 1 +2436 10 23 0 +2437 10 23 1 +2438 10 22 0 +2439 10 22 1 +2440 8 22 1 +2441 8 22 0 +2442 8 23 1 +2443 8 23 0 +2444 9 22 1 +2445 9 22 0 +2446 9 23 1 +2447 9 23 0 +2464 3 22 0 +2465 3 22 1 +2466 3 23 0 +2467 3 23 1 +2468 2 22 0 +2469 2 22 1 +2470 2 23 0 +2471 2 23 1 +2472 0 23 1 +2473 0 23 0 +2474 0 22 1 +2475 0 22 0 +2476 1 23 1 +2477 1 23 0 +2478 1 22 1 +2479 1 22 0 +2480 4 22 0 +2481 4 22 1 +2482 4 23 0 +2483 4 23 1 +2484 5 22 0 +2485 5 22 1 +2486 5 23 0 +2487 5 23 1 +2488 7 23 1 +2489 7 23 0 +2490 7 22 1 +2491 7 22 0 +2492 6 23 1 +2493 6 23 0 +2494 6 22 1 +2495 6 22 0 +2496 12 23 0 +2497 12 23 1 +2498 12 22 0 +2499 12 22 1 +2500 13 23 0 +2501 13 23 1 +2502 13 22 0 +2503 13 22 1 +2504 15 22 1 +2505 15 22 0 +2506 15 23 1 +2507 15 23 0 +2508 14 22 1 +2509 14 22 0 +2510 14 23 1 +2511 14 23 0 +2560 11 21 0 +2561 11 21 1 +2562 11 20 0 +2563 11 20 1 +2564 10 21 0 +2565 10 21 1 +2566 10 20 0 +2567 10 20 1 +2568 8 20 1 +2569 8 20 0 +2570 8 21 1 +2571 8 21 0 +2572 9 20 1 +2573 9 20 0 +2574 9 21 1 +2575 9 21 0 +2592 3 20 0 +2593 3 20 1 +2594 3 21 0 +2595 3 21 1 +2596 2 20 0 +2597 2 20 1 +2598 2 21 0 +2599 2 21 1 +2600 0 21 1 +2601 0 21 0 +2602 0 20 1 +2603 0 20 0 +2604 1 21 1 +2605 1 21 0 +2606 1 20 1 +2607 1 20 0 +2608 4 20 0 +2609 4 20 1 +2610 4 21 0 +2611 4 21 1 +2612 5 20 0 +2613 5 20 1 +2614 5 21 0 +2615 5 21 1 +2616 7 21 1 +2617 7 21 0 +2618 7 20 1 +2619 7 20 0 +2620 6 21 1 +2621 6 21 0 +2622 6 20 1 +2623 6 20 0 +2624 12 21 0 +2625 12 21 1 +2626 12 20 0 +2627 12 20 1 +2628 13 21 0 +2629 13 21 1 +2630 13 20 0 +2631 13 20 1 +2632 15 20 1 +2633 15 20 0 +2634 15 21 1 +2635 15 21 0 +2636 14 20 1 +2637 14 20 0 +2638 14 21 1 +2639 14 21 0 +2688 11 19 0 +2689 11 19 1 +2690 11 18 0 +2691 11 18 1 +2692 10 19 0 +2693 10 19 1 +2694 10 18 0 +2695 10 18 1 +2696 8 18 1 +2697 8 18 0 +2698 8 19 1 +2699 8 19 0 +2700 9 18 1 +2701 9 18 0 +2702 9 19 1 +2703 9 19 0 +2720 3 18 0 +2721 3 18 1 +2722 3 19 0 +2723 3 19 1 +2724 2 18 0 +2725 2 18 1 +2726 2 19 0 +2727 2 19 1 +2728 0 19 1 +2729 0 19 0 +2730 0 18 1 +2731 0 18 0 +2732 1 19 1 +2733 1 19 0 +2734 1 18 1 +2735 1 18 0 +2736 4 18 0 +2737 4 18 1 +2738 4 19 0 +2739 4 19 1 +2740 5 18 0 +2741 5 18 1 +2742 5 19 0 +2743 5 19 1 +2744 7 19 1 +2745 7 19 0 +2746 7 18 1 +2747 7 18 0 +2748 6 19 1 +2749 6 19 0 +2750 6 18 1 +2751 6 18 0 +2752 12 19 0 +2753 12 19 1 +2754 12 18 0 +2755 12 18 1 +2756 13 19 0 +2757 13 19 1 +2758 13 18 0 +2759 13 18 1 +2760 15 18 1 +2761 15 18 0 +2762 15 19 1 +2763 15 19 0 +2764 14 18 1 +2765 14 18 0 +2766 14 19 1 +2767 14 19 0 +2816 11 17 0 +2817 11 17 1 +2818 11 16 0 +2819 11 16 1 +2820 10 17 0 +2821 10 17 1 +2822 10 16 0 +2823 10 16 1 +2824 8 16 1 +2825 8 16 0 +2826 8 17 1 +2827 8 17 0 +2828 9 16 1 +2829 9 16 0 +2830 9 17 1 +2831 9 17 0 +2848 3 16 0 +2849 3 16 1 +2850 3 17 0 +2851 3 17 1 +2852 2 16 0 +2853 2 16 1 +2854 2 17 0 +2855 2 17 1 +2856 0 17 1 +2857 0 17 0 +2858 0 16 1 +2859 0 16 0 +2860 1 17 1 +2861 1 17 0 +2862 1 16 1 +2863 1 16 0 +2864 4 16 0 +2865 4 16 1 +2866 4 17 0 +2867 4 17 1 +2868 5 16 0 +2869 5 16 1 +2870 5 17 0 +2871 5 17 1 +2872 7 17 1 +2873 7 17 0 +2874 7 16 1 +2875 7 16 0 +2876 6 17 1 +2877 6 17 0 +2878 6 16 1 +2879 6 16 0 +2880 12 17 0 +2881 12 17 1 +2882 12 16 0 +2883 12 16 1 +2884 13 17 0 +2885 13 17 1 +2886 13 16 0 +2887 13 16 1 +2888 15 16 1 +2889 15 16 0 +2890 15 17 1 +2891 15 17 0 +2892 14 16 1 +2893 14 16 0 +2894 14 17 1 +2895 14 17 0 +2944 11 15 0 +2945 11 15 1 +2946 11 14 0 +2947 11 14 1 +2948 10 15 0 +2949 10 15 1 +2950 10 14 0 +2951 10 14 1 +2952 8 14 1 +2953 8 14 0 +2954 8 15 1 +2955 8 15 0 +2956 9 14 1 +2957 9 14 0 +2958 9 15 1 +2959 9 15 0 +2976 3 14 0 +2977 3 14 1 +2978 3 15 0 +2979 3 15 1 +2980 2 14 0 +2981 2 14 1 +2982 2 15 0 +2983 2 15 1 +2984 0 15 1 +2985 0 15 0 +2986 0 14 1 +2987 0 14 0 +2988 1 15 1 +2989 1 15 0 +2990 1 14 1 +2991 1 14 0 +2992 4 14 0 +2993 4 14 1 +2994 4 15 0 +2995 4 15 1 +2996 5 14 0 +2997 5 14 1 +2998 5 15 0 +2999 5 15 1 +3000 7 15 1 +3001 7 15 0 +3002 7 14 1 +3003 7 14 0 +3004 6 15 1 +3005 6 15 0 +3006 6 14 1 +3007 6 14 0 +3008 12 15 0 +3009 12 15 1 +3010 12 14 0 +3011 12 14 1 +3012 13 15 0 +3013 13 15 1 +3014 13 14 0 +3015 13 14 1 +3016 15 14 1 +3017 15 14 0 +3018 15 15 1 +3019 15 15 0 +3020 14 14 1 +3021 14 14 0 +3022 14 15 1 +3023 14 15 0 +3072 11 13 0 +3073 11 13 1 +3074 11 12 0 +3075 11 12 1 +3076 10 13 0 +3077 10 13 1 +3078 10 12 0 +3079 10 12 1 +3080 8 12 1 +3081 8 12 0 +3082 8 13 1 +3083 8 13 0 +3084 9 12 1 +3085 9 12 0 +3086 9 13 1 +3087 9 13 0 +3104 3 12 0 +3105 3 12 1 +3106 3 13 0 +3107 3 13 1 +3108 2 12 0 +3109 2 12 1 +3110 2 13 0 +3111 2 13 1 +3112 0 13 1 +3113 0 13 0 +3114 0 12 1 +3115 0 12 0 +3116 1 13 1 +3117 1 13 0 +3118 1 12 1 +3119 1 12 0 +3120 4 12 0 +3121 4 12 1 +3122 4 13 0 +3123 4 13 1 +3124 5 12 0 +3125 5 12 1 +3126 5 13 0 +3127 5 13 1 +3128 7 13 1 +3129 7 13 0 +3130 7 12 1 +3131 7 12 0 +3132 6 13 1 +3133 6 13 0 +3134 6 12 1 +3135 6 12 0 +3136 12 13 0 +3137 12 13 1 +3138 12 12 0 +3139 12 12 1 +3140 13 13 0 +3141 13 13 1 +3142 13 12 0 +3143 13 12 1 +3144 15 12 1 +3145 15 12 0 +3146 15 13 1 +3147 15 13 0 +3148 14 12 1 +3149 14 12 0 +3150 14 13 1 +3151 14 13 0 +3200 11 11 0 +3201 11 11 1 +3202 11 10 0 +3203 11 10 1 +3204 10 11 0 +3205 10 11 1 +3206 10 10 0 +3207 10 10 1 +3208 8 10 1 +3209 8 10 0 +3210 8 11 1 +3211 8 11 0 +3212 9 10 1 +3213 9 10 0 +3214 9 11 1 +3215 9 11 0 +3232 3 10 0 +3233 3 10 1 +3234 3 11 0 +3235 3 11 1 +3236 2 10 0 +3237 2 10 1 +3238 2 11 0 +3239 2 11 1 +3240 0 11 1 +3241 0 11 0 +3242 0 10 1 +3243 0 10 0 +3244 1 11 1 +3245 1 11 0 +3246 1 10 1 +3247 1 10 0 +3248 4 10 0 +3249 4 10 1 +3250 4 11 0 +3251 4 11 1 +3252 5 10 0 +3253 5 10 1 +3254 5 11 0 +3255 5 11 1 +3256 7 11 1 +3257 7 11 0 +3258 7 10 1 +3259 7 10 0 +3260 6 11 1 +3261 6 11 0 +3262 6 10 1 +3263 6 10 0 +3264 12 11 0 +3265 12 11 1 +3266 12 10 0 +3267 12 10 1 +3268 13 11 0 +3269 13 11 1 +3270 13 10 0 +3271 13 10 1 +3272 15 10 1 +3273 15 10 0 +3274 15 11 1 +3275 15 11 0 +3276 14 10 1 +3277 14 10 0 +3278 14 11 1 +3279 14 11 0 +3328 11 9 0 +3329 11 9 1 +3330 11 8 0 +3331 11 8 1 +3332 10 9 0 +3333 10 9 1 +3334 10 8 0 +3335 10 8 1 +3336 8 8 1 +3337 8 8 0 +3338 8 9 1 +3339 8 9 0 +3340 9 8 1 +3341 9 8 0 +3342 9 9 1 +3343 9 9 0 +3360 3 8 0 +3361 3 8 1 +3362 3 9 0 +3363 3 9 1 +3364 2 8 0 +3365 2 8 1 +3366 2 9 0 +3367 2 9 1 +3368 0 9 1 +3369 0 9 0 +3370 0 8 1 +3371 0 8 0 +3372 1 9 1 +3373 1 9 0 +3374 1 8 1 +3375 1 8 0 +3376 4 8 0 +3377 4 8 1 +3378 4 9 0 +3379 4 9 1 +3380 5 8 0 +3381 5 8 1 +3382 5 9 0 +3383 5 9 1 +3384 7 9 1 +3385 7 9 0 +3386 7 8 1 +3387 7 8 0 +3388 6 9 1 +3389 6 9 0 +3390 6 8 1 +3391 6 8 0 +3392 12 9 0 +3393 12 9 1 +3394 12 8 0 +3395 12 8 1 +3396 13 9 0 +3397 13 9 1 +3398 13 8 0 +3399 13 8 1 +3400 15 8 1 +3401 15 8 0 +3402 15 9 1 +3403 15 9 0 +3404 14 8 1 +3405 14 8 0 +3406 14 9 1 +3407 14 9 0 +3456 11 7 0 +3457 11 7 1 +3458 11 6 0 +3459 11 6 1 +3460 10 7 0 +3461 10 7 1 +3462 10 6 0 +3463 10 6 1 +3464 8 6 1 +3465 8 6 0 +3466 8 7 1 +3467 8 7 0 +3468 9 6 1 +3469 9 6 0 +3470 9 7 1 +3471 9 7 0 +3488 3 6 0 +3489 3 6 1 +3490 3 7 0 +3491 3 7 1 +3492 2 6 0 +3493 2 6 1 +3494 2 7 0 +3495 2 7 1 +3496 0 7 1 +3497 0 7 0 +3498 0 6 1 +3499 0 6 0 +3500 1 7 1 +3501 1 7 0 +3502 1 6 1 +3503 1 6 0 +3504 4 6 0 +3505 4 6 1 +3506 4 7 0 +3507 4 7 1 +3508 5 6 0 +3509 5 6 1 +3510 5 7 0 +3511 5 7 1 +3512 7 7 1 +3513 7 7 0 +3514 7 6 1 +3515 7 6 0 +3516 6 7 1 +3517 6 7 0 +3518 6 6 1 +3519 6 6 0 +3520 12 7 0 +3521 12 7 1 +3522 12 6 0 +3523 12 6 1 +3524 13 7 0 +3525 13 7 1 +3526 13 6 0 +3527 13 6 1 +3528 15 6 1 +3529 15 6 0 +3530 15 7 1 +3531 15 7 0 +3532 14 6 1 +3533 14 6 0 +3534 14 7 1 +3535 14 7 0 +3584 11 5 0 +3585 11 5 1 +3586 11 4 0 +3587 11 4 1 +3588 10 5 0 +3589 10 5 1 +3590 10 4 0 +3591 10 4 1 +3592 8 4 1 +3593 8 4 0 +3594 8 5 1 +3595 8 5 0 +3596 9 4 1 +3597 9 4 0 +3598 9 5 1 +3599 9 5 0 +3616 3 4 0 +3617 3 4 1 +3618 3 5 0 +3619 3 5 1 +3620 2 4 0 +3621 2 4 1 +3622 2 5 0 +3623 2 5 1 +3624 0 5 1 +3625 0 5 0 +3626 0 4 1 +3627 0 4 0 +3628 1 5 1 +3629 1 5 0 +3630 1 4 1 +3631 1 4 0 +3632 4 4 0 +3633 4 4 1 +3634 4 5 0 +3635 4 5 1 +3636 5 4 0 +3637 5 4 1 +3638 5 5 0 +3639 5 5 1 +3640 7 5 1 +3641 7 5 0 +3642 7 4 1 +3643 7 4 0 +3644 6 5 1 +3645 6 5 0 +3646 6 4 1 +3647 6 4 0 +3648 12 5 0 +3649 12 5 1 +3650 12 4 0 +3651 12 4 1 +3652 13 5 0 +3653 13 5 1 +3654 13 4 0 +3655 13 4 1 +3656 15 4 1 +3657 15 4 0 +3658 15 5 1 +3659 15 5 0 +3660 14 4 1 +3661 14 4 0 +3662 14 5 1 +3663 14 5 0 +3712 11 3 0 +3713 11 3 1 +3714 11 2 0 +3715 11 2 1 +3716 10 3 0 +3717 10 3 1 +3718 10 2 0 +3719 10 2 1 +3720 8 2 1 +3721 8 2 0 +3722 8 3 1 +3723 8 3 0 +3724 9 2 1 +3725 9 2 0 +3726 9 3 1 +3727 9 3 0 +3744 3 2 0 +3745 3 2 1 +3746 3 3 0 +3747 3 3 1 +3748 2 2 0 +3749 2 2 1 +3750 2 3 0 +3751 2 3 1 +3752 0 3 1 +3753 0 3 0 +3754 0 2 1 +3755 0 2 0 +3756 1 3 1 +3757 1 3 0 +3758 1 2 1 +3759 1 2 0 +3760 4 2 0 +3761 4 2 1 +3762 4 3 0 +3763 4 3 1 +3764 5 2 0 +3765 5 2 1 +3766 5 3 0 +3767 5 3 1 +3768 7 3 1 +3769 7 3 0 +3770 7 2 1 +3771 7 2 0 +3772 6 3 1 +3773 6 3 0 +3774 6 2 1 +3775 6 2 0 +3776 12 3 0 +3777 12 3 1 +3778 12 2 0 +3779 12 2 1 +3780 13 3 0 +3781 13 3 1 +3782 13 2 0 +3783 13 2 1 +3784 15 2 1 +3785 15 2 0 +3786 15 3 1 +3787 15 3 0 +3788 14 2 1 +3789 14 2 0 +3790 14 3 1 +3791 14 3 0 +3840 11 1 0 +3841 11 1 1 +3842 11 0 0 +3843 11 0 1 +3844 10 1 0 +3845 10 1 1 +3846 10 0 0 +3847 10 0 1 +3848 8 0 1 +3849 8 0 0 +3850 8 1 1 +3851 8 1 0 +3852 9 0 1 +3853 9 0 0 +3854 9 1 1 +3855 9 1 0 +3872 3 0 0 +3873 3 0 1 +3874 3 1 0 +3875 3 1 1 +3876 2 0 0 +3877 2 0 1 +3878 2 1 0 +3879 2 1 1 +3880 0 1 1 +3881 0 1 0 +3882 0 0 1 +3883 0 0 0 +3884 1 1 1 +3885 1 1 0 +3886 1 0 1 +3887 1 0 0 +3888 4 0 0 +3889 4 0 1 +3890 4 1 0 +3891 4 1 1 +3892 5 0 0 +3893 5 0 1 +3894 5 1 0 +3895 5 1 1 +3896 7 1 1 +3897 7 1 0 +3898 7 0 1 +3899 7 0 0 +3900 6 1 1 +3901 6 1 0 +3902 6 0 1 +3903 6 0 0 +3904 12 1 0 +3905 12 1 1 +3906 12 0 0 +3907 12 0 1 +3908 13 1 0 +3909 13 1 1 +3910 13 0 0 +3911 13 0 1 +3912 15 0 1 +3913 15 0 0 +3914 15 1 1 +3915 15 1 0 +3916 14 0 1 +3917 14 0 0 +3918 14 1 1 +3919 14 1 0 diff --git a/Detectors/PHOS/base/files/Mod0RCU1.data b/Detectors/PHOS/base/files/Mod0RCU1.data new file mode 100644 index 0000000000000..db125226496cf --- /dev/null +++ b/Detectors/PHOS/base/files/Mod0RCU1.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 1 0 2 + 1 1 1 2 + 2 1 2 2 + 3 1 3 2 + 4 1 4 2 + 5 1 5 2 + 6 1 6 2 + 7 1 7 2 + 8 1 8 2 + 9 1 9 2 + 10 1 10 2 + 11 1 11 2 + 12 1 12 2 + 13 1 13 2 + 14 1 14 2 + 15 1 15 2 + 16 1 16 2 + 17 1 17 2 + 18 1 18 2 + 19 1 19 2 + 20 1 20 2 + 21 1 21 2 + 22 1 22 2 + 23 1 23 2 + 24 1 24 2 + 25 1 25 2 + 26 1 26 2 + 27 1 27 2 + 28 1 28 2 + 29 1 29 2 + 30 1 30 2 + 31 1 31 2 + 32 1 32 2 + 33 1 33 2 + 34 1 34 2 + 35 1 35 2 + 36 1 36 2 + 37 1 37 2 + 38 1 38 2 + 39 1 39 2 + 40 1 40 2 + 41 1 41 2 + 42 1 42 2 + 43 1 43 2 + 44 1 44 2 + 45 1 45 2 + 46 1 46 2 + 47 1 47 2 + 48 1 48 2 + 49 1 49 2 + 50 1 50 2 + 51 1 51 2 + 52 1 52 2 + 53 1 53 2 + 54 1 54 2 + 55 1 55 2 + 56 1 56 2 + 57 1 57 2 + 58 1 58 2 + 59 1 59 2 + 60 1 60 2 + 61 1 61 2 + 62 1 62 2 + 63 1 63 2 + 64 1 64 2 + 65 1 65 2 + 66 1 66 2 + 67 1 67 2 + 68 1 68 2 + 69 1 69 2 + 70 1 70 2 + 71 1 71 2 + 72 1 72 2 + 73 1 73 2 + 74 1 74 2 + 75 1 75 2 + 76 1 76 2 + 77 1 77 2 + 78 1 78 2 + 79 1 79 2 + 80 1 80 2 + 81 1 81 2 + 82 1 82 2 + 83 1 83 2 + 84 1 84 2 + 85 1 85 2 + 86 1 86 2 + 87 1 87 2 + 88 1 88 2 + 89 1 89 2 + 90 1 90 2 + 91 1 91 2 + 92 1 92 2 + 93 1 93 2 + 94 1 94 2 + 95 1 95 2 + 96 1 96 2 + 97 1 97 2 + 98 1 98 2 + 99 1 99 2 + 100 1 100 2 + 101 1 101 2 + 102 1 102 2 + 103 1 103 2 + 104 1 104 2 + 105 1 105 2 + 106 1 106 2 + 107 1 107 2 + 108 1 108 2 + 109 1 109 2 + 110 1 110 2 + 111 1 111 2 + 112 1 112 2 + 113 1 113 2 + 114 1 114 2 + 115 1 115 2 + 116 1 116 2 + 117 1 117 2 + 118 1 118 2 + 119 1 119 2 + 120 1 120 2 + 121 1 121 2 + 122 1 122 2 + 123 1 123 2 + 124 1 124 2 + 125 1 125 2 + 126 1 126 2 + 127 1 127 2 +2048 1 2048 2 +2049 1 2049 2 +2050 1 2050 2 +2051 1 2051 2 +2052 1 2052 2 +2053 1 2053 2 +2054 1 2054 2 +2055 1 2055 2 +2056 1 2056 2 +2057 1 2057 2 +2058 1 2058 2 +2059 1 2059 2 +2060 1 2060 2 +2061 1 2061 2 +2062 1 2062 2 +2063 1 2063 2 +2064 1 2064 2 +2065 1 2065 2 +2066 1 2066 2 +2067 1 2067 2 +2068 1 2068 2 +2069 1 2069 2 +2070 1 2070 2 +2071 1 2071 2 +2072 1 2072 2 +2073 1 2073 2 +2074 1 2074 2 +2075 1 2075 2 +2076 1 2076 2 +2077 1 2077 2 +2078 1 2078 2 +2079 1 2079 2 +2080 1 2080 2 +2081 1 2081 2 +2082 1 2082 2 +2083 1 2083 2 +2084 1 2084 2 +2085 1 2085 2 +2086 1 2086 2 +2087 1 2087 2 +2088 1 2088 2 +2089 1 2089 2 +2090 1 2090 2 +2091 1 2091 2 +2092 1 2092 2 +2093 1 2093 2 +2094 1 2094 2 +2095 1 2095 2 +2096 1 2096 2 +2097 1 2097 2 +2098 1 2098 2 +2099 1 2099 2 +2100 1 2100 2 +2101 1 2101 2 +2102 1 2102 2 +2103 1 2103 2 +2104 1 2104 2 +2105 1 2105 2 +2106 1 2106 2 +2107 1 2107 2 +2108 1 2108 2 +2109 1 2109 2 +2110 1 2110 2 +2111 1 2111 2 +2112 1 2112 2 +2113 1 2113 2 +2114 1 2114 2 +2115 1 2115 2 +2116 1 2116 2 +2117 1 2117 2 +2118 1 2118 2 +2119 1 2119 2 +2120 1 2120 2 +2121 1 2121 2 +2122 1 2122 2 +2123 1 2123 2 +2124 1 2124 2 +2125 1 2125 2 +2126 1 2126 2 +2127 1 2127 2 +2128 1 2128 2 +2129 1 2129 2 +2130 1 2130 2 +2131 1 2131 2 +2132 1 2132 2 +2133 1 2133 2 +2134 1 2134 2 +2135 1 2135 2 +2136 1 2136 2 +2137 1 2137 2 +2138 1 2138 2 +2139 1 2139 2 +2140 1 2140 2 +2141 1 2141 2 +2142 1 2142 2 +2143 1 2143 2 +2144 1 2144 2 +2145 1 2145 2 +2146 1 2146 2 +2147 1 2147 2 +2148 1 2148 2 +2149 1 2149 2 +2150 1 2150 2 +2151 1 2151 2 +2152 1 2152 2 +2153 1 2153 2 +2154 1 2154 2 +2155 1 2155 2 +2156 1 2156 2 +2157 1 2157 2 +2158 1 2158 2 +2159 1 2159 2 +2160 1 2160 2 +2161 1 2161 2 +2162 1 2162 2 +2163 1 2163 2 +2164 1 2164 2 +2165 1 2165 2 +2166 1 2166 2 +2167 1 2167 2 +2168 1 2168 2 +2169 1 2169 2 +2170 1 2170 2 +2171 1 2171 2 +2172 1 2172 2 +2173 1 2173 2 +2174 1 2174 2 +2175 1 2175 2 + 128 27 29 0 + 129 27 29 1 + 130 27 28 0 + 131 27 28 1 + 132 26 29 0 + 133 26 29 1 + 134 26 28 0 + 135 26 28 1 + 136 24 28 1 + 137 24 28 0 + 138 24 29 1 + 139 24 29 0 + 140 25 28 1 + 141 25 28 0 + 142 25 29 1 + 143 25 29 0 + 160 19 28 0 + 161 19 28 1 + 162 19 29 0 + 163 19 29 1 + 164 18 28 0 + 165 18 28 1 + 166 18 29 0 + 167 18 29 1 + 168 16 29 1 + 169 16 29 0 + 170 16 28 1 + 171 16 28 0 + 172 17 29 1 + 173 17 29 0 + 174 17 28 1 + 175 17 28 0 + 176 20 28 0 + 177 20 28 1 + 178 20 29 0 + 179 20 29 1 + 180 21 28 0 + 181 21 28 1 + 182 21 29 0 + 183 21 29 1 + 184 23 29 1 + 185 23 29 0 + 186 23 28 1 + 187 23 28 0 + 188 22 29 1 + 189 22 29 0 + 190 22 28 1 + 191 22 28 0 + 192 28 29 0 + 193 28 29 1 + 194 28 28 0 + 195 28 28 1 + 196 29 29 0 + 197 29 29 1 + 198 29 28 0 + 199 29 28 1 + 200 31 28 1 + 201 31 28 0 + 202 31 29 1 + 203 31 29 0 + 204 30 28 1 + 205 30 28 0 + 206 30 29 1 + 207 30 29 0 + 256 27 31 0 + 257 27 31 1 + 258 27 30 0 + 259 27 30 1 + 260 26 31 0 + 261 26 31 1 + 262 26 30 0 + 263 26 30 1 + 264 24 30 1 + 265 24 30 0 + 266 24 31 1 + 267 24 31 0 + 268 25 30 1 + 269 25 30 0 + 270 25 31 1 + 271 25 31 0 + 288 19 30 0 + 289 19 30 1 + 290 19 31 0 + 291 19 31 1 + 292 18 30 0 + 293 18 30 1 + 294 18 31 0 + 295 18 31 1 + 296 16 31 1 + 297 16 31 0 + 298 16 30 1 + 299 16 30 0 + 300 17 31 1 + 301 17 31 0 + 302 17 30 1 + 303 17 30 0 + 304 20 30 0 + 305 20 30 1 + 306 20 31 0 + 307 20 31 1 + 308 21 30 0 + 309 21 30 1 + 310 21 31 0 + 311 21 31 1 + 312 23 31 1 + 313 23 31 0 + 314 23 30 1 + 315 23 30 0 + 316 22 31 1 + 317 22 31 0 + 318 22 30 1 + 319 22 30 0 + 320 28 31 0 + 321 28 31 1 + 322 28 30 0 + 323 28 30 1 + 324 29 31 0 + 325 29 31 1 + 326 29 30 0 + 327 29 30 1 + 328 31 30 1 + 329 31 30 0 + 330 31 31 1 + 331 31 31 0 + 332 30 30 1 + 333 30 30 0 + 334 30 31 1 + 335 30 31 0 + 384 27 33 0 + 385 27 33 1 + 386 27 32 0 + 387 27 32 1 + 388 26 33 0 + 389 26 33 1 + 390 26 32 0 + 391 26 32 1 + 392 24 32 1 + 393 24 32 0 + 394 24 33 1 + 395 24 33 0 + 396 25 32 1 + 397 25 32 0 + 398 25 33 1 + 399 25 33 0 + 416 19 32 0 + 417 19 32 1 + 418 19 33 0 + 419 19 33 1 + 420 18 32 0 + 421 18 32 1 + 422 18 33 0 + 423 18 33 1 + 424 16 33 1 + 425 16 33 0 + 426 16 32 1 + 427 16 32 0 + 428 17 33 1 + 429 17 33 0 + 430 17 32 1 + 431 17 32 0 + 432 20 32 0 + 433 20 32 1 + 434 20 33 0 + 435 20 33 1 + 436 21 32 0 + 437 21 32 1 + 438 21 33 0 + 439 21 33 1 + 440 23 33 1 + 441 23 33 0 + 442 23 32 1 + 443 23 32 0 + 444 22 33 1 + 445 22 33 0 + 446 22 32 1 + 447 22 32 0 + 448 28 33 0 + 449 28 33 1 + 450 28 32 0 + 451 28 32 1 + 452 29 33 0 + 453 29 33 1 + 454 29 32 0 + 455 29 32 1 + 456 31 32 1 + 457 31 32 0 + 458 31 33 1 + 459 31 33 0 + 460 30 32 1 + 461 30 32 0 + 462 30 33 1 + 463 30 33 0 + 512 27 35 0 + 513 27 35 1 + 514 27 34 0 + 515 27 34 1 + 516 26 35 0 + 517 26 35 1 + 518 26 34 0 + 519 26 34 1 + 520 24 34 1 + 521 24 34 0 + 522 24 35 1 + 523 24 35 0 + 524 25 34 1 + 525 25 34 0 + 526 25 35 1 + 527 25 35 0 + 544 19 34 0 + 545 19 34 1 + 546 19 35 0 + 547 19 35 1 + 548 18 34 0 + 549 18 34 1 + 550 18 35 0 + 551 18 35 1 + 552 16 35 1 + 553 16 35 0 + 554 16 34 1 + 555 16 34 0 + 556 17 35 1 + 557 17 35 0 + 558 17 34 1 + 559 17 34 0 + 560 20 34 0 + 561 20 34 1 + 562 20 35 0 + 563 20 35 1 + 564 21 34 0 + 565 21 34 1 + 566 21 35 0 + 567 21 35 1 + 568 23 35 1 + 569 23 35 0 + 570 23 34 1 + 571 23 34 0 + 572 22 35 1 + 573 22 35 0 + 574 22 34 1 + 575 22 34 0 + 576 28 35 0 + 577 28 35 1 + 578 28 34 0 + 579 28 34 1 + 580 29 35 0 + 581 29 35 1 + 582 29 34 0 + 583 29 34 1 + 584 31 34 1 + 585 31 34 0 + 586 31 35 1 + 587 31 35 0 + 588 30 34 1 + 589 30 34 0 + 590 30 35 1 + 591 30 35 0 + 640 27 37 0 + 641 27 37 1 + 642 27 36 0 + 643 27 36 1 + 644 26 37 0 + 645 26 37 1 + 646 26 36 0 + 647 26 36 1 + 648 24 36 1 + 649 24 36 0 + 650 24 37 1 + 651 24 37 0 + 652 25 36 1 + 653 25 36 0 + 654 25 37 1 + 655 25 37 0 + 672 19 36 0 + 673 19 36 1 + 674 19 37 0 + 675 19 37 1 + 676 18 36 0 + 677 18 36 1 + 678 18 37 0 + 679 18 37 1 + 680 16 37 1 + 681 16 37 0 + 682 16 36 1 + 683 16 36 0 + 684 17 37 1 + 685 17 37 0 + 686 17 36 1 + 687 17 36 0 + 688 20 36 0 + 689 20 36 1 + 690 20 37 0 + 691 20 37 1 + 692 21 36 0 + 693 21 36 1 + 694 21 37 0 + 695 21 37 1 + 696 23 37 1 + 697 23 37 0 + 698 23 36 1 + 699 23 36 0 + 700 22 37 1 + 701 22 37 0 + 702 22 36 1 + 703 22 36 0 + 704 28 37 0 + 705 28 37 1 + 706 28 36 0 + 707 28 36 1 + 708 29 37 0 + 709 29 37 1 + 710 29 36 0 + 711 29 36 1 + 712 31 36 1 + 713 31 36 0 + 714 31 37 1 + 715 31 37 0 + 716 30 36 1 + 717 30 36 0 + 718 30 37 1 + 719 30 37 0 + 768 27 39 0 + 769 27 39 1 + 770 27 38 0 + 771 27 38 1 + 772 26 39 0 + 773 26 39 1 + 774 26 38 0 + 775 26 38 1 + 776 24 38 1 + 777 24 38 0 + 778 24 39 1 + 779 24 39 0 + 780 25 38 1 + 781 25 38 0 + 782 25 39 1 + 783 25 39 0 + 800 19 38 0 + 801 19 38 1 + 802 19 39 0 + 803 19 39 1 + 804 18 38 0 + 805 18 38 1 + 806 18 39 0 + 807 18 39 1 + 808 16 39 1 + 809 16 39 0 + 810 16 38 1 + 811 16 38 0 + 812 17 39 1 + 813 17 39 0 + 814 17 38 1 + 815 17 38 0 + 816 20 38 0 + 817 20 38 1 + 818 20 39 0 + 819 20 39 1 + 820 21 38 0 + 821 21 38 1 + 822 21 39 0 + 823 21 39 1 + 824 23 39 1 + 825 23 39 0 + 826 23 38 1 + 827 23 38 0 + 828 22 39 1 + 829 22 39 0 + 830 22 38 1 + 831 22 38 0 + 832 28 39 0 + 833 28 39 1 + 834 28 38 0 + 835 28 38 1 + 836 29 39 0 + 837 29 39 1 + 838 29 38 0 + 839 29 38 1 + 840 31 38 1 + 841 31 38 0 + 842 31 39 1 + 843 31 39 0 + 844 30 38 1 + 845 30 38 0 + 846 30 39 1 + 847 30 39 0 + 896 27 41 0 + 897 27 41 1 + 898 27 40 0 + 899 27 40 1 + 900 26 41 0 + 901 26 41 1 + 902 26 40 0 + 903 26 40 1 + 904 24 40 1 + 905 24 40 0 + 906 24 41 1 + 907 24 41 0 + 908 25 40 1 + 909 25 40 0 + 910 25 41 1 + 911 25 41 0 + 928 19 40 0 + 929 19 40 1 + 930 19 41 0 + 931 19 41 1 + 932 18 40 0 + 933 18 40 1 + 934 18 41 0 + 935 18 41 1 + 936 16 41 1 + 937 16 41 0 + 938 16 40 1 + 939 16 40 0 + 940 17 41 1 + 941 17 41 0 + 942 17 40 1 + 943 17 40 0 + 944 20 40 0 + 945 20 40 1 + 946 20 41 0 + 947 20 41 1 + 948 21 40 0 + 949 21 40 1 + 950 21 41 0 + 951 21 41 1 + 952 23 41 1 + 953 23 41 0 + 954 23 40 1 + 955 23 40 0 + 956 22 41 1 + 957 22 41 0 + 958 22 40 1 + 959 22 40 0 + 960 28 41 0 + 961 28 41 1 + 962 28 40 0 + 963 28 40 1 + 964 29 41 0 + 965 29 41 1 + 966 29 40 0 + 967 29 40 1 + 968 31 40 1 + 969 31 40 0 + 970 31 41 1 + 971 31 41 0 + 972 30 40 1 + 973 30 40 0 + 974 30 41 1 + 975 30 41 0 +1024 27 43 0 +1025 27 43 1 +1026 27 42 0 +1027 27 42 1 +1028 26 43 0 +1029 26 43 1 +1030 26 42 0 +1031 26 42 1 +1032 24 42 1 +1033 24 42 0 +1034 24 43 1 +1035 24 43 0 +1036 25 42 1 +1037 25 42 0 +1038 25 43 1 +1039 25 43 0 +1056 19 42 0 +1057 19 42 1 +1058 19 43 0 +1059 19 43 1 +1060 18 42 0 +1061 18 42 1 +1062 18 43 0 +1063 18 43 1 +1064 16 43 1 +1065 16 43 0 +1066 16 42 1 +1067 16 42 0 +1068 17 43 1 +1069 17 43 0 +1070 17 42 1 +1071 17 42 0 +1072 20 42 0 +1073 20 42 1 +1074 20 43 0 +1075 20 43 1 +1076 21 42 0 +1077 21 42 1 +1078 21 43 0 +1079 21 43 1 +1080 23 43 1 +1081 23 43 0 +1082 23 42 1 +1083 23 42 0 +1084 22 43 1 +1085 22 43 0 +1086 22 42 1 +1087 22 42 0 +1088 28 43 0 +1089 28 43 1 +1090 28 42 0 +1091 28 42 1 +1092 29 43 0 +1093 29 43 1 +1094 29 42 0 +1095 29 42 1 +1096 31 42 1 +1097 31 42 0 +1098 31 43 1 +1099 31 43 0 +1100 30 42 1 +1101 30 42 0 +1102 30 43 1 +1103 30 43 0 +1152 27 45 0 +1153 27 45 1 +1154 27 44 0 +1155 27 44 1 +1156 26 45 0 +1157 26 45 1 +1158 26 44 0 +1159 26 44 1 +1160 24 44 1 +1161 24 44 0 +1162 24 45 1 +1163 24 45 0 +1164 25 44 1 +1165 25 44 0 +1166 25 45 1 +1167 25 45 0 +1184 19 44 0 +1185 19 44 1 +1186 19 45 0 +1187 19 45 1 +1188 18 44 0 +1189 18 44 1 +1190 18 45 0 +1191 18 45 1 +1192 16 45 1 +1193 16 45 0 +1194 16 44 1 +1195 16 44 0 +1196 17 45 1 +1197 17 45 0 +1198 17 44 1 +1199 17 44 0 +1200 20 44 0 +1201 20 44 1 +1202 20 45 0 +1203 20 45 1 +1204 21 44 0 +1205 21 44 1 +1206 21 45 0 +1207 21 45 1 +1208 23 45 1 +1209 23 45 0 +1210 23 44 1 +1211 23 44 0 +1212 22 45 1 +1213 22 45 0 +1214 22 44 1 +1215 22 44 0 +1216 28 45 0 +1217 28 45 1 +1218 28 44 0 +1219 28 44 1 +1220 29 45 0 +1221 29 45 1 +1222 29 44 0 +1223 29 44 1 +1224 31 44 1 +1225 31 44 0 +1226 31 45 1 +1227 31 45 0 +1228 30 44 1 +1229 30 44 0 +1230 30 45 1 +1231 30 45 0 +1280 27 47 0 +1281 27 47 1 +1282 27 46 0 +1283 27 46 1 +1284 26 47 0 +1285 26 47 1 +1286 26 46 0 +1287 26 46 1 +1288 24 46 1 +1289 24 46 0 +1290 24 47 1 +1291 24 47 0 +1292 25 46 1 +1293 25 46 0 +1294 25 47 1 +1295 25 47 0 +1312 19 46 0 +1313 19 46 1 +1314 19 47 0 +1315 19 47 1 +1316 18 46 0 +1317 18 46 1 +1318 18 47 0 +1319 18 47 1 +1320 16 47 1 +1321 16 47 0 +1322 16 46 1 +1323 16 46 0 +1324 17 47 1 +1325 17 47 0 +1326 17 46 1 +1327 17 46 0 +1328 20 46 0 +1329 20 46 1 +1330 20 47 0 +1331 20 47 1 +1332 21 46 0 +1333 21 46 1 +1334 21 47 0 +1335 21 47 1 +1336 23 47 1 +1337 23 47 0 +1338 23 46 1 +1339 23 46 0 +1340 22 47 1 +1341 22 47 0 +1342 22 46 1 +1343 22 46 0 +1344 28 47 0 +1345 28 47 1 +1346 28 46 0 +1347 28 46 1 +1348 29 47 0 +1349 29 47 1 +1350 29 46 0 +1351 29 46 1 +1352 31 46 1 +1353 31 46 0 +1354 31 47 1 +1355 31 47 0 +1356 30 46 1 +1357 30 46 0 +1358 30 47 1 +1359 30 47 0 +1408 27 49 0 +1409 27 49 1 +1410 27 48 0 +1411 27 48 1 +1412 26 49 0 +1413 26 49 1 +1414 26 48 0 +1415 26 48 1 +1416 24 48 1 +1417 24 48 0 +1418 24 49 1 +1419 24 49 0 +1420 25 48 1 +1421 25 48 0 +1422 25 49 1 +1423 25 49 0 +1440 19 48 0 +1441 19 48 1 +1442 19 49 0 +1443 19 49 1 +1444 18 48 0 +1445 18 48 1 +1446 18 49 0 +1447 18 49 1 +1448 16 49 1 +1449 16 49 0 +1450 16 48 1 +1451 16 48 0 +1452 17 49 1 +1453 17 49 0 +1454 17 48 1 +1455 17 48 0 +1456 20 48 0 +1457 20 48 1 +1458 20 49 0 +1459 20 49 1 +1460 21 48 0 +1461 21 48 1 +1462 21 49 0 +1463 21 49 1 +1464 23 49 1 +1465 23 49 0 +1466 23 48 1 +1467 23 48 0 +1468 22 49 1 +1469 22 49 0 +1470 22 48 1 +1471 22 48 0 +1472 28 49 0 +1473 28 49 1 +1474 28 48 0 +1475 28 48 1 +1476 29 49 0 +1477 29 49 1 +1478 29 48 0 +1479 29 48 1 +1480 31 48 1 +1481 31 48 0 +1482 31 49 1 +1483 31 49 0 +1484 30 48 1 +1485 30 48 0 +1486 30 49 1 +1487 30 49 0 +1536 27 51 0 +1537 27 51 1 +1538 27 50 0 +1539 27 50 1 +1540 26 51 0 +1541 26 51 1 +1542 26 50 0 +1543 26 50 1 +1544 24 50 1 +1545 24 50 0 +1546 24 51 1 +1547 24 51 0 +1548 25 50 1 +1549 25 50 0 +1550 25 51 1 +1551 25 51 0 +1568 19 50 0 +1569 19 50 1 +1570 19 51 0 +1571 19 51 1 +1572 18 50 0 +1573 18 50 1 +1574 18 51 0 +1575 18 51 1 +1576 16 51 1 +1577 16 51 0 +1578 16 50 1 +1579 16 50 0 +1580 17 51 1 +1581 17 51 0 +1582 17 50 1 +1583 17 50 0 +1584 20 50 0 +1585 20 50 1 +1586 20 51 0 +1587 20 51 1 +1588 21 50 0 +1589 21 50 1 +1590 21 51 0 +1591 21 51 1 +1592 23 51 1 +1593 23 51 0 +1594 23 50 1 +1595 23 50 0 +1596 22 51 1 +1597 22 51 0 +1598 22 50 1 +1599 22 50 0 +1600 28 51 0 +1601 28 51 1 +1602 28 50 0 +1603 28 50 1 +1604 29 51 0 +1605 29 51 1 +1606 29 50 0 +1607 29 50 1 +1608 31 50 1 +1609 31 50 0 +1610 31 51 1 +1611 31 51 0 +1612 30 50 1 +1613 30 50 0 +1614 30 51 1 +1615 30 51 0 +1664 27 53 0 +1665 27 53 1 +1666 27 52 0 +1667 27 52 1 +1668 26 53 0 +1669 26 53 1 +1670 26 52 0 +1671 26 52 1 +1672 24 52 1 +1673 24 52 0 +1674 24 53 1 +1675 24 53 0 +1676 25 52 1 +1677 25 52 0 +1678 25 53 1 +1679 25 53 0 +1696 19 52 0 +1697 19 52 1 +1698 19 53 0 +1699 19 53 1 +1700 18 52 0 +1701 18 52 1 +1702 18 53 0 +1703 18 53 1 +1704 16 53 1 +1705 16 53 0 +1706 16 52 1 +1707 16 52 0 +1708 17 53 1 +1709 17 53 0 +1710 17 52 1 +1711 17 52 0 +1712 20 52 0 +1713 20 52 1 +1714 20 53 0 +1715 20 53 1 +1716 21 52 0 +1717 21 52 1 +1718 21 53 0 +1719 21 53 1 +1720 23 53 1 +1721 23 53 0 +1722 23 52 1 +1723 23 52 0 +1724 22 53 1 +1725 22 53 0 +1726 22 52 1 +1727 22 52 0 +1728 28 53 0 +1729 28 53 1 +1730 28 52 0 +1731 28 52 1 +1732 29 53 0 +1733 29 53 1 +1734 29 52 0 +1735 29 52 1 +1736 31 52 1 +1737 31 52 0 +1738 31 53 1 +1739 31 53 0 +1740 30 52 1 +1741 30 52 0 +1742 30 53 1 +1743 30 53 0 +1792 27 55 0 +1793 27 55 1 +1794 27 54 0 +1795 27 54 1 +1796 26 55 0 +1797 26 55 1 +1798 26 54 0 +1799 26 54 1 +1800 24 54 1 +1801 24 54 0 +1802 24 55 1 +1803 24 55 0 +1804 25 54 1 +1805 25 54 0 +1806 25 55 1 +1807 25 55 0 +1824 19 54 0 +1825 19 54 1 +1826 19 55 0 +1827 19 55 1 +1828 18 54 0 +1829 18 54 1 +1830 18 55 0 +1831 18 55 1 +1832 16 55 1 +1833 16 55 0 +1834 16 54 1 +1835 16 54 0 +1836 17 55 1 +1837 17 55 0 +1838 17 54 1 +1839 17 54 0 +1840 20 54 0 +1841 20 54 1 +1842 20 55 0 +1843 20 55 1 +1844 21 54 0 +1845 21 54 1 +1846 21 55 0 +1847 21 55 1 +1848 23 55 1 +1849 23 55 0 +1850 23 54 1 +1851 23 54 0 +1852 22 55 1 +1853 22 55 0 +1854 22 54 1 +1855 22 54 0 +1856 28 55 0 +1857 28 55 1 +1858 28 54 0 +1859 28 54 1 +1860 29 55 0 +1861 29 55 1 +1862 29 54 0 +1863 29 54 1 +1864 31 54 1 +1865 31 54 0 +1866 31 55 1 +1867 31 55 0 +1868 30 54 1 +1869 30 54 0 +1870 30 55 1 +1871 30 55 0 +2176 27 27 0 +2177 27 27 1 +2178 27 26 0 +2179 27 26 1 +2180 26 27 0 +2181 26 27 1 +2182 26 26 0 +2183 26 26 1 +2184 24 26 1 +2185 24 26 0 +2186 24 27 1 +2187 24 27 0 +2188 25 26 1 +2189 25 26 0 +2190 25 27 1 +2191 25 27 0 +2208 19 26 0 +2209 19 26 1 +2210 19 27 0 +2211 19 27 1 +2212 18 26 0 +2213 18 26 1 +2214 18 27 0 +2215 18 27 1 +2216 16 27 1 +2217 16 27 0 +2218 16 26 1 +2219 16 26 0 +2220 17 27 1 +2221 17 27 0 +2222 17 26 1 +2223 17 26 0 +2224 20 26 0 +2225 20 26 1 +2226 20 27 0 +2227 20 27 1 +2228 21 26 0 +2229 21 26 1 +2230 21 27 0 +2231 21 27 1 +2232 23 27 1 +2233 23 27 0 +2234 23 26 1 +2235 23 26 0 +2236 22 27 1 +2237 22 27 0 +2238 22 26 1 +2239 22 26 0 +2240 28 27 0 +2241 28 27 1 +2242 28 26 0 +2243 28 26 1 +2244 29 27 0 +2245 29 27 1 +2246 29 26 0 +2247 29 26 1 +2248 31 26 1 +2249 31 26 0 +2250 31 27 1 +2251 31 27 0 +2252 30 26 1 +2253 30 26 0 +2254 30 27 1 +2255 30 27 0 +2304 27 25 0 +2305 27 25 1 +2306 27 24 0 +2307 27 24 1 +2308 26 25 0 +2309 26 25 1 +2310 26 24 0 +2311 26 24 1 +2312 24 24 1 +2313 24 24 0 +2314 24 25 1 +2315 24 25 0 +2316 25 24 1 +2317 25 24 0 +2318 25 25 1 +2319 25 25 0 +2336 19 24 0 +2337 19 24 1 +2338 19 25 0 +2339 19 25 1 +2340 18 24 0 +2341 18 24 1 +2342 18 25 0 +2343 18 25 1 +2344 16 25 1 +2345 16 25 0 +2346 16 24 1 +2347 16 24 0 +2348 17 25 1 +2349 17 25 0 +2350 17 24 1 +2351 17 24 0 +2352 20 24 0 +2353 20 24 1 +2354 20 25 0 +2355 20 25 1 +2356 21 24 0 +2357 21 24 1 +2358 21 25 0 +2359 21 25 1 +2360 23 25 1 +2361 23 25 0 +2362 23 24 1 +2363 23 24 0 +2364 22 25 1 +2365 22 25 0 +2366 22 24 1 +2367 22 24 0 +2368 28 25 0 +2369 28 25 1 +2370 28 24 0 +2371 28 24 1 +2372 29 25 0 +2373 29 25 1 +2374 29 24 0 +2375 29 24 1 +2376 31 24 1 +2377 31 24 0 +2378 31 25 1 +2379 31 25 0 +2380 30 24 1 +2381 30 24 0 +2382 30 25 1 +2383 30 25 0 +2432 27 23 0 +2433 27 23 1 +2434 27 22 0 +2435 27 22 1 +2436 26 23 0 +2437 26 23 1 +2438 26 22 0 +2439 26 22 1 +2440 24 22 1 +2441 24 22 0 +2442 24 23 1 +2443 24 23 0 +2444 25 22 1 +2445 25 22 0 +2446 25 23 1 +2447 25 23 0 +2464 19 22 0 +2465 19 22 1 +2466 19 23 0 +2467 19 23 1 +2468 18 22 0 +2469 18 22 1 +2470 18 23 0 +2471 18 23 1 +2472 16 23 1 +2473 16 23 0 +2474 16 22 1 +2475 16 22 0 +2476 17 23 1 +2477 17 23 0 +2478 17 22 1 +2479 17 22 0 +2480 20 22 0 +2481 20 22 1 +2482 20 23 0 +2483 20 23 1 +2484 21 22 0 +2485 21 22 1 +2486 21 23 0 +2487 21 23 1 +2488 23 23 1 +2489 23 23 0 +2490 23 22 1 +2491 23 22 0 +2492 22 23 1 +2493 22 23 0 +2494 22 22 1 +2495 22 22 0 +2496 28 23 0 +2497 28 23 1 +2498 28 22 0 +2499 28 22 1 +2500 29 23 0 +2501 29 23 1 +2502 29 22 0 +2503 29 22 1 +2504 31 22 1 +2505 31 22 0 +2506 31 23 1 +2507 31 23 0 +2508 30 22 1 +2509 30 22 0 +2510 30 23 1 +2511 30 23 0 +2560 27 21 0 +2561 27 21 1 +2562 27 20 0 +2563 27 20 1 +2564 26 21 0 +2565 26 21 1 +2566 26 20 0 +2567 26 20 1 +2568 24 20 1 +2569 24 20 0 +2570 24 21 1 +2571 24 21 0 +2572 25 20 1 +2573 25 20 0 +2574 25 21 1 +2575 25 21 0 +2592 19 20 0 +2593 19 20 1 +2594 19 21 0 +2595 19 21 1 +2596 18 20 0 +2597 18 20 1 +2598 18 21 0 +2599 18 21 1 +2600 16 21 1 +2601 16 21 0 +2602 16 20 1 +2603 16 20 0 +2604 17 21 1 +2605 17 21 0 +2606 17 20 1 +2607 17 20 0 +2608 20 20 0 +2609 20 20 1 +2610 20 21 0 +2611 20 21 1 +2612 21 20 0 +2613 21 20 1 +2614 21 21 0 +2615 21 21 1 +2616 23 21 1 +2617 23 21 0 +2618 23 20 1 +2619 23 20 0 +2620 22 21 1 +2621 22 21 0 +2622 22 20 1 +2623 22 20 0 +2624 28 21 0 +2625 28 21 1 +2626 28 20 0 +2627 28 20 1 +2628 29 21 0 +2629 29 21 1 +2630 29 20 0 +2631 29 20 1 +2632 31 20 1 +2633 31 20 0 +2634 31 21 1 +2635 31 21 0 +2636 30 20 1 +2637 30 20 0 +2638 30 21 1 +2639 30 21 0 +2688 27 19 0 +2689 27 19 1 +2690 27 18 0 +2691 27 18 1 +2692 26 19 0 +2693 26 19 1 +2694 26 18 0 +2695 26 18 1 +2696 24 18 1 +2697 24 18 0 +2698 24 19 1 +2699 24 19 0 +2700 25 18 1 +2701 25 18 0 +2702 25 19 1 +2703 25 19 0 +2720 19 18 0 +2721 19 18 1 +2722 19 19 0 +2723 19 19 1 +2724 18 18 0 +2725 18 18 1 +2726 18 19 0 +2727 18 19 1 +2728 16 19 1 +2729 16 19 0 +2730 16 18 1 +2731 16 18 0 +2732 17 19 1 +2733 17 19 0 +2734 17 18 1 +2735 17 18 0 +2736 20 18 0 +2737 20 18 1 +2738 20 19 0 +2739 20 19 1 +2740 21 18 0 +2741 21 18 1 +2742 21 19 0 +2743 21 19 1 +2744 23 19 1 +2745 23 19 0 +2746 23 18 1 +2747 23 18 0 +2748 22 19 1 +2749 22 19 0 +2750 22 18 1 +2751 22 18 0 +2752 28 19 0 +2753 28 19 1 +2754 28 18 0 +2755 28 18 1 +2756 29 19 0 +2757 29 19 1 +2758 29 18 0 +2759 29 18 1 +2760 31 18 1 +2761 31 18 0 +2762 31 19 1 +2763 31 19 0 +2764 30 18 1 +2765 30 18 0 +2766 30 19 1 +2767 30 19 0 +2816 27 17 0 +2817 27 17 1 +2818 27 16 0 +2819 27 16 1 +2820 26 17 0 +2821 26 17 1 +2822 26 16 0 +2823 26 16 1 +2824 24 16 1 +2825 24 16 0 +2826 24 17 1 +2827 24 17 0 +2828 25 16 1 +2829 25 16 0 +2830 25 17 1 +2831 25 17 0 +2848 19 16 0 +2849 19 16 1 +2850 19 17 0 +2851 19 17 1 +2852 18 16 0 +2853 18 16 1 +2854 18 17 0 +2855 18 17 1 +2856 16 17 1 +2857 16 17 0 +2858 16 16 1 +2859 16 16 0 +2860 17 17 1 +2861 17 17 0 +2862 17 16 1 +2863 17 16 0 +2864 20 16 0 +2865 20 16 1 +2866 20 17 0 +2867 20 17 1 +2868 21 16 0 +2869 21 16 1 +2870 21 17 0 +2871 21 17 1 +2872 23 17 1 +2873 23 17 0 +2874 23 16 1 +2875 23 16 0 +2876 22 17 1 +2877 22 17 0 +2878 22 16 1 +2879 22 16 0 +2880 28 17 0 +2881 28 17 1 +2882 28 16 0 +2883 28 16 1 +2884 29 17 0 +2885 29 17 1 +2886 29 16 0 +2887 29 16 1 +2888 31 16 1 +2889 31 16 0 +2890 31 17 1 +2891 31 17 0 +2892 30 16 1 +2893 30 16 0 +2894 30 17 1 +2895 30 17 0 +2944 27 15 0 +2945 27 15 1 +2946 27 14 0 +2947 27 14 1 +2948 26 15 0 +2949 26 15 1 +2950 26 14 0 +2951 26 14 1 +2952 24 14 1 +2953 24 14 0 +2954 24 15 1 +2955 24 15 0 +2956 25 14 1 +2957 25 14 0 +2958 25 15 1 +2959 25 15 0 +2976 19 14 0 +2977 19 14 1 +2978 19 15 0 +2979 19 15 1 +2980 18 14 0 +2981 18 14 1 +2982 18 15 0 +2983 18 15 1 +2984 16 15 1 +2985 16 15 0 +2986 16 14 1 +2987 16 14 0 +2988 17 15 1 +2989 17 15 0 +2990 17 14 1 +2991 17 14 0 +2992 20 14 0 +2993 20 14 1 +2994 20 15 0 +2995 20 15 1 +2996 21 14 0 +2997 21 14 1 +2998 21 15 0 +2999 21 15 1 +3000 23 15 1 +3001 23 15 0 +3002 23 14 1 +3003 23 14 0 +3004 22 15 1 +3005 22 15 0 +3006 22 14 1 +3007 22 14 0 +3008 28 15 0 +3009 28 15 1 +3010 28 14 0 +3011 28 14 1 +3012 29 15 0 +3013 29 15 1 +3014 29 14 0 +3015 29 14 1 +3016 31 14 1 +3017 31 14 0 +3018 31 15 1 +3019 31 15 0 +3020 30 14 1 +3021 30 14 0 +3022 30 15 1 +3023 30 15 0 +3072 27 13 0 +3073 27 13 1 +3074 27 12 0 +3075 27 12 1 +3076 26 13 0 +3077 26 13 1 +3078 26 12 0 +3079 26 12 1 +3080 24 12 1 +3081 24 12 0 +3082 24 13 1 +3083 24 13 0 +3084 25 12 1 +3085 25 12 0 +3086 25 13 1 +3087 25 13 0 +3104 19 12 0 +3105 19 12 1 +3106 19 13 0 +3107 19 13 1 +3108 18 12 0 +3109 18 12 1 +3110 18 13 0 +3111 18 13 1 +3112 16 13 1 +3113 16 13 0 +3114 16 12 1 +3115 16 12 0 +3116 17 13 1 +3117 17 13 0 +3118 17 12 1 +3119 17 12 0 +3120 20 12 0 +3121 20 12 1 +3122 20 13 0 +3123 20 13 1 +3124 21 12 0 +3125 21 12 1 +3126 21 13 0 +3127 21 13 1 +3128 23 13 1 +3129 23 13 0 +3130 23 12 1 +3131 23 12 0 +3132 22 13 1 +3133 22 13 0 +3134 22 12 1 +3135 22 12 0 +3136 28 13 0 +3137 28 13 1 +3138 28 12 0 +3139 28 12 1 +3140 29 13 0 +3141 29 13 1 +3142 29 12 0 +3143 29 12 1 +3144 31 12 1 +3145 31 12 0 +3146 31 13 1 +3147 31 13 0 +3148 30 12 1 +3149 30 12 0 +3150 30 13 1 +3151 30 13 0 +3200 27 11 0 +3201 27 11 1 +3202 27 10 0 +3203 27 10 1 +3204 26 11 0 +3205 26 11 1 +3206 26 10 0 +3207 26 10 1 +3208 24 10 1 +3209 24 10 0 +3210 24 11 1 +3211 24 11 0 +3212 25 10 1 +3213 25 10 0 +3214 25 11 1 +3215 25 11 0 +3232 19 10 0 +3233 19 10 1 +3234 19 11 0 +3235 19 11 1 +3236 18 10 0 +3237 18 10 1 +3238 18 11 0 +3239 18 11 1 +3240 16 11 1 +3241 16 11 0 +3242 16 10 1 +3243 16 10 0 +3244 17 11 1 +3245 17 11 0 +3246 17 10 1 +3247 17 10 0 +3248 20 10 0 +3249 20 10 1 +3250 20 11 0 +3251 20 11 1 +3252 21 10 0 +3253 21 10 1 +3254 21 11 0 +3255 21 11 1 +3256 23 11 1 +3257 23 11 0 +3258 23 10 1 +3259 23 10 0 +3260 22 11 1 +3261 22 11 0 +3262 22 10 1 +3263 22 10 0 +3264 28 11 0 +3265 28 11 1 +3266 28 10 0 +3267 28 10 1 +3268 29 11 0 +3269 29 11 1 +3270 29 10 0 +3271 29 10 1 +3272 31 10 1 +3273 31 10 0 +3274 31 11 1 +3275 31 11 0 +3276 30 10 1 +3277 30 10 0 +3278 30 11 1 +3279 30 11 0 +3328 27 9 0 +3329 27 9 1 +3330 27 8 0 +3331 27 8 1 +3332 26 9 0 +3333 26 9 1 +3334 26 8 0 +3335 26 8 1 +3336 24 8 1 +3337 24 8 0 +3338 24 9 1 +3339 24 9 0 +3340 25 8 1 +3341 25 8 0 +3342 25 9 1 +3343 25 9 0 +3360 19 8 0 +3361 19 8 1 +3362 19 9 0 +3363 19 9 1 +3364 18 8 0 +3365 18 8 1 +3366 18 9 0 +3367 18 9 1 +3368 16 9 1 +3369 16 9 0 +3370 16 8 1 +3371 16 8 0 +3372 17 9 1 +3373 17 9 0 +3374 17 8 1 +3375 17 8 0 +3376 20 8 0 +3377 20 8 1 +3378 20 9 0 +3379 20 9 1 +3380 21 8 0 +3381 21 8 1 +3382 21 9 0 +3383 21 9 1 +3384 23 9 1 +3385 23 9 0 +3386 23 8 1 +3387 23 8 0 +3388 22 9 1 +3389 22 9 0 +3390 22 8 1 +3391 22 8 0 +3392 28 9 0 +3393 28 9 1 +3394 28 8 0 +3395 28 8 1 +3396 29 9 0 +3397 29 9 1 +3398 29 8 0 +3399 29 8 1 +3400 31 8 1 +3401 31 8 0 +3402 31 9 1 +3403 31 9 0 +3404 30 8 1 +3405 30 8 0 +3406 30 9 1 +3407 30 9 0 +3456 27 7 0 +3457 27 7 1 +3458 27 6 0 +3459 27 6 1 +3460 26 7 0 +3461 26 7 1 +3462 26 6 0 +3463 26 6 1 +3464 24 6 1 +3465 24 6 0 +3466 24 7 1 +3467 24 7 0 +3468 25 6 1 +3469 25 6 0 +3470 25 7 1 +3471 25 7 0 +3488 19 6 0 +3489 19 6 1 +3490 19 7 0 +3491 19 7 1 +3492 18 6 0 +3493 18 6 1 +3494 18 7 0 +3495 18 7 1 +3496 16 7 1 +3497 16 7 0 +3498 16 6 1 +3499 16 6 0 +3500 17 7 1 +3501 17 7 0 +3502 17 6 1 +3503 17 6 0 +3504 20 6 0 +3505 20 6 1 +3506 20 7 0 +3507 20 7 1 +3508 21 6 0 +3509 21 6 1 +3510 21 7 0 +3511 21 7 1 +3512 23 7 1 +3513 23 7 0 +3514 23 6 1 +3515 23 6 0 +3516 22 7 1 +3517 22 7 0 +3518 22 6 1 +3519 22 6 0 +3520 28 7 0 +3521 28 7 1 +3522 28 6 0 +3523 28 6 1 +3524 29 7 0 +3525 29 7 1 +3526 29 6 0 +3527 29 6 1 +3528 31 6 1 +3529 31 6 0 +3530 31 7 1 +3531 31 7 0 +3532 30 6 1 +3533 30 6 0 +3534 30 7 1 +3535 30 7 0 +3584 27 5 0 +3585 27 5 1 +3586 27 4 0 +3587 27 4 1 +3588 26 5 0 +3589 26 5 1 +3590 26 4 0 +3591 26 4 1 +3592 24 4 1 +3593 24 4 0 +3594 24 5 1 +3595 24 5 0 +3596 25 4 1 +3597 25 4 0 +3598 25 5 1 +3599 25 5 0 +3616 19 4 0 +3617 19 4 1 +3618 19 5 0 +3619 19 5 1 +3620 18 4 0 +3621 18 4 1 +3622 18 5 0 +3623 18 5 1 +3624 16 5 1 +3625 16 5 0 +3626 16 4 1 +3627 16 4 0 +3628 17 5 1 +3629 17 5 0 +3630 17 4 1 +3631 17 4 0 +3632 20 4 0 +3633 20 4 1 +3634 20 5 0 +3635 20 5 1 +3636 21 4 0 +3637 21 4 1 +3638 21 5 0 +3639 21 5 1 +3640 23 5 1 +3641 23 5 0 +3642 23 4 1 +3643 23 4 0 +3644 22 5 1 +3645 22 5 0 +3646 22 4 1 +3647 22 4 0 +3648 28 5 0 +3649 28 5 1 +3650 28 4 0 +3651 28 4 1 +3652 29 5 0 +3653 29 5 1 +3654 29 4 0 +3655 29 4 1 +3656 31 4 1 +3657 31 4 0 +3658 31 5 1 +3659 31 5 0 +3660 30 4 1 +3661 30 4 0 +3662 30 5 1 +3663 30 5 0 +3712 27 3 0 +3713 27 3 1 +3714 27 2 0 +3715 27 2 1 +3716 26 3 0 +3717 26 3 1 +3718 26 2 0 +3719 26 2 1 +3720 24 2 1 +3721 24 2 0 +3722 24 3 1 +3723 24 3 0 +3724 25 2 1 +3725 25 2 0 +3726 25 3 1 +3727 25 3 0 +3744 19 2 0 +3745 19 2 1 +3746 19 3 0 +3747 19 3 1 +3748 18 2 0 +3749 18 2 1 +3750 18 3 0 +3751 18 3 1 +3752 16 3 1 +3753 16 3 0 +3754 16 2 1 +3755 16 2 0 +3756 17 3 1 +3757 17 3 0 +3758 17 2 1 +3759 17 2 0 +3760 20 2 0 +3761 20 2 1 +3762 20 3 0 +3763 20 3 1 +3764 21 2 0 +3765 21 2 1 +3766 21 3 0 +3767 21 3 1 +3768 23 3 1 +3769 23 3 0 +3770 23 2 1 +3771 23 2 0 +3772 22 3 1 +3773 22 3 0 +3774 22 2 1 +3775 22 2 0 +3776 28 3 0 +3777 28 3 1 +3778 28 2 0 +3779 28 2 1 +3780 29 3 0 +3781 29 3 1 +3782 29 2 0 +3783 29 2 1 +3784 31 2 1 +3785 31 2 0 +3786 31 3 1 +3787 31 3 0 +3788 30 2 1 +3789 30 2 0 +3790 30 3 1 +3791 30 3 0 +3840 27 1 0 +3841 27 1 1 +3842 27 0 0 +3843 27 0 1 +3844 26 1 0 +3845 26 1 1 +3846 26 0 0 +3847 26 0 1 +3848 24 0 1 +3849 24 0 0 +3850 24 1 1 +3851 24 1 0 +3852 25 0 1 +3853 25 0 0 +3854 25 1 1 +3855 25 1 0 +3872 19 0 0 +3873 19 0 1 +3874 19 1 0 +3875 19 1 1 +3876 18 0 0 +3877 18 0 1 +3878 18 1 0 +3879 18 1 1 +3880 16 1 1 +3881 16 1 0 +3882 16 0 1 +3883 16 0 0 +3884 17 1 1 +3885 17 1 0 +3886 17 0 1 +3887 17 0 0 +3888 20 0 0 +3889 20 0 1 +3890 20 1 0 +3891 20 1 1 +3892 21 0 0 +3893 21 0 1 +3894 21 1 0 +3895 21 1 1 +3896 23 1 1 +3897 23 1 0 +3898 23 0 1 +3899 23 0 0 +3900 22 1 1 +3901 22 1 0 +3902 22 0 1 +3903 22 0 0 +3904 28 1 0 +3905 28 1 1 +3906 28 0 0 +3907 28 0 1 +3908 29 1 0 +3909 29 1 1 +3910 29 0 0 +3911 29 0 1 +3912 31 0 1 +3913 31 0 0 +3914 31 1 1 +3915 31 1 0 +3916 30 0 1 +3917 30 0 0 +3918 30 1 1 +3919 30 1 0 diff --git a/Detectors/PHOS/base/files/Mod0RCU2.data b/Detectors/PHOS/base/files/Mod0RCU2.data new file mode 100644 index 0000000000000..21de94d7ace53 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod0RCU2.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 2 0 2 + 1 2 1 2 + 2 2 2 2 + 3 2 3 2 + 4 2 4 2 + 5 2 5 2 + 6 2 6 2 + 7 2 7 2 + 8 2 8 2 + 9 2 9 2 + 10 2 10 2 + 11 2 11 2 + 12 2 12 2 + 13 2 13 2 + 14 2 14 2 + 15 2 15 2 + 16 2 16 2 + 17 2 17 2 + 18 2 18 2 + 19 2 19 2 + 20 2 20 2 + 21 2 21 2 + 22 2 22 2 + 23 2 23 2 + 24 2 24 2 + 25 2 25 2 + 26 2 26 2 + 27 2 27 2 + 28 2 28 2 + 29 2 29 2 + 30 2 30 2 + 31 2 31 2 + 32 2 32 2 + 33 2 33 2 + 34 2 34 2 + 35 2 35 2 + 36 2 36 2 + 37 2 37 2 + 38 2 38 2 + 39 2 39 2 + 40 2 40 2 + 41 2 41 2 + 42 2 42 2 + 43 2 43 2 + 44 2 44 2 + 45 2 45 2 + 46 2 46 2 + 47 2 47 2 + 48 2 48 2 + 49 2 49 2 + 50 2 50 2 + 51 2 51 2 + 52 2 52 2 + 53 2 53 2 + 54 2 54 2 + 55 2 55 2 + 56 2 56 2 + 57 2 57 2 + 58 2 58 2 + 59 2 59 2 + 60 2 60 2 + 61 2 61 2 + 62 2 62 2 + 63 2 63 2 + 64 2 64 2 + 65 2 65 2 + 66 2 66 2 + 67 2 67 2 + 68 2 68 2 + 69 2 69 2 + 70 2 70 2 + 71 2 71 2 + 72 2 72 2 + 73 2 73 2 + 74 2 74 2 + 75 2 75 2 + 76 2 76 2 + 77 2 77 2 + 78 2 78 2 + 79 2 79 2 + 80 2 80 2 + 81 2 81 2 + 82 2 82 2 + 83 2 83 2 + 84 2 84 2 + 85 2 85 2 + 86 2 86 2 + 87 2 87 2 + 88 2 88 2 + 89 2 89 2 + 90 2 90 2 + 91 2 91 2 + 92 2 92 2 + 93 2 93 2 + 94 2 94 2 + 95 2 95 2 + 96 2 96 2 + 97 2 97 2 + 98 2 98 2 + 99 2 99 2 + 100 2 100 2 + 101 2 101 2 + 102 2 102 2 + 103 2 103 2 + 104 2 104 2 + 105 2 105 2 + 106 2 106 2 + 107 2 107 2 + 108 2 108 2 + 109 2 109 2 + 110 2 110 2 + 111 2 111 2 + 112 2 112 2 + 113 2 113 2 + 114 2 114 2 + 115 2 115 2 + 116 2 116 2 + 117 2 117 2 + 118 2 118 2 + 119 2 119 2 + 120 2 120 2 + 121 2 121 2 + 122 2 122 2 + 123 2 123 2 + 124 2 124 2 + 125 2 125 2 + 126 2 126 2 + 127 2 127 2 +2048 2 2048 2 +2049 2 2049 2 +2050 2 2050 2 +2051 2 2051 2 +2052 2 2052 2 +2053 2 2053 2 +2054 2 2054 2 +2055 2 2055 2 +2056 2 2056 2 +2057 2 2057 2 +2058 2 2058 2 +2059 2 2059 2 +2060 2 2060 2 +2061 2 2061 2 +2062 2 2062 2 +2063 2 2063 2 +2064 2 2064 2 +2065 2 2065 2 +2066 2 2066 2 +2067 2 2067 2 +2068 2 2068 2 +2069 2 2069 2 +2070 2 2070 2 +2071 2 2071 2 +2072 2 2072 2 +2073 2 2073 2 +2074 2 2074 2 +2075 2 2075 2 +2076 2 2076 2 +2077 2 2077 2 +2078 2 2078 2 +2079 2 2079 2 +2080 2 2080 2 +2081 2 2081 2 +2082 2 2082 2 +2083 2 2083 2 +2084 2 2084 2 +2085 2 2085 2 +2086 2 2086 2 +2087 2 2087 2 +2088 2 2088 2 +2089 2 2089 2 +2090 2 2090 2 +2091 2 2091 2 +2092 2 2092 2 +2093 2 2093 2 +2094 2 2094 2 +2095 2 2095 2 +2096 2 2096 2 +2097 2 2097 2 +2098 2 2098 2 +2099 2 2099 2 +2100 2 2100 2 +2101 2 2101 2 +2102 2 2102 2 +2103 2 2103 2 +2104 2 2104 2 +2105 2 2105 2 +2106 2 2106 2 +2107 2 2107 2 +2108 2 2108 2 +2109 2 2109 2 +2110 2 2110 2 +2111 2 2111 2 +2112 2 2112 2 +2113 2 2113 2 +2114 2 2114 2 +2115 2 2115 2 +2116 2 2116 2 +2117 2 2117 2 +2118 2 2118 2 +2119 2 2119 2 +2120 2 2120 2 +2121 2 2121 2 +2122 2 2122 2 +2123 2 2123 2 +2124 2 2124 2 +2125 2 2125 2 +2126 2 2126 2 +2127 2 2127 2 +2128 2 2128 2 +2129 2 2129 2 +2130 2 2130 2 +2131 2 2131 2 +2132 2 2132 2 +2133 2 2133 2 +2134 2 2134 2 +2135 2 2135 2 +2136 2 2136 2 +2137 2 2137 2 +2138 2 2138 2 +2139 2 2139 2 +2140 2 2140 2 +2141 2 2141 2 +2142 2 2142 2 +2143 2 2143 2 +2144 2 2144 2 +2145 2 2145 2 +2146 2 2146 2 +2147 2 2147 2 +2148 2 2148 2 +2149 2 2149 2 +2150 2 2150 2 +2151 2 2151 2 +2152 2 2152 2 +2153 2 2153 2 +2154 2 2154 2 +2155 2 2155 2 +2156 2 2156 2 +2157 2 2157 2 +2158 2 2158 2 +2159 2 2159 2 +2160 2 2160 2 +2161 2 2161 2 +2162 2 2162 2 +2163 2 2163 2 +2164 2 2164 2 +2165 2 2165 2 +2166 2 2166 2 +2167 2 2167 2 +2168 2 2168 2 +2169 2 2169 2 +2170 2 2170 2 +2171 2 2171 2 +2172 2 2172 2 +2173 2 2173 2 +2174 2 2174 2 +2175 2 2175 2 + 128 43 29 0 + 129 43 29 1 + 130 43 28 0 + 131 43 28 1 + 132 42 29 0 + 133 42 29 1 + 134 42 28 0 + 135 42 28 1 + 136 40 28 1 + 137 40 28 0 + 138 40 29 1 + 139 40 29 0 + 140 41 28 1 + 141 41 28 0 + 142 41 29 1 + 143 41 29 0 + 160 35 28 0 + 161 35 28 1 + 162 35 29 0 + 163 35 29 1 + 164 34 28 0 + 165 34 28 1 + 166 34 29 0 + 167 34 29 1 + 168 32 29 1 + 169 32 29 0 + 170 32 28 1 + 171 32 28 0 + 172 33 29 1 + 173 33 29 0 + 174 33 28 1 + 175 33 28 0 + 176 36 28 0 + 177 36 28 1 + 178 36 29 0 + 179 36 29 1 + 180 37 28 0 + 181 37 28 1 + 182 37 29 0 + 183 37 29 1 + 184 39 29 1 + 185 39 29 0 + 186 39 28 1 + 187 39 28 0 + 188 38 29 1 + 189 38 29 0 + 190 38 28 1 + 191 38 28 0 + 192 44 29 0 + 193 44 29 1 + 194 44 28 0 + 195 44 28 1 + 196 45 29 0 + 197 45 29 1 + 198 45 28 0 + 199 45 28 1 + 200 47 28 1 + 201 47 28 0 + 202 47 29 1 + 203 47 29 0 + 204 46 28 1 + 205 46 28 0 + 206 46 29 1 + 207 46 29 0 + 256 43 31 0 + 257 43 31 1 + 258 43 30 0 + 259 43 30 1 + 260 42 31 0 + 261 42 31 1 + 262 42 30 0 + 263 42 30 1 + 264 40 30 1 + 265 40 30 0 + 266 40 31 1 + 267 40 31 0 + 268 41 30 1 + 269 41 30 0 + 270 41 31 1 + 271 41 31 0 + 288 35 30 0 + 289 35 30 1 + 290 35 31 0 + 291 35 31 1 + 292 34 30 0 + 293 34 30 1 + 294 34 31 0 + 295 34 31 1 + 296 32 31 1 + 297 32 31 0 + 298 32 30 1 + 299 32 30 0 + 300 33 31 1 + 301 33 31 0 + 302 33 30 1 + 303 33 30 0 + 304 36 30 0 + 305 36 30 1 + 306 36 31 0 + 307 36 31 1 + 308 37 30 0 + 309 37 30 1 + 310 37 31 0 + 311 37 31 1 + 312 39 31 1 + 313 39 31 0 + 314 39 30 1 + 315 39 30 0 + 316 38 31 1 + 317 38 31 0 + 318 38 30 1 + 319 38 30 0 + 320 44 31 0 + 321 44 31 1 + 322 44 30 0 + 323 44 30 1 + 324 45 31 0 + 325 45 31 1 + 326 45 30 0 + 327 45 30 1 + 328 47 30 1 + 329 47 30 0 + 330 47 31 1 + 331 47 31 0 + 332 46 30 1 + 333 46 30 0 + 334 46 31 1 + 335 46 31 0 + 384 43 33 0 + 385 43 33 1 + 386 43 32 0 + 387 43 32 1 + 388 42 33 0 + 389 42 33 1 + 390 42 32 0 + 391 42 32 1 + 392 40 32 1 + 393 40 32 0 + 394 40 33 1 + 395 40 33 0 + 396 41 32 1 + 397 41 32 0 + 398 41 33 1 + 399 41 33 0 + 416 35 32 0 + 417 35 32 1 + 418 35 33 0 + 419 35 33 1 + 420 34 32 0 + 421 34 32 1 + 422 34 33 0 + 423 34 33 1 + 424 32 33 1 + 425 32 33 0 + 426 32 32 1 + 427 32 32 0 + 428 33 33 1 + 429 33 33 0 + 430 33 32 1 + 431 33 32 0 + 432 36 32 0 + 433 36 32 1 + 434 36 33 0 + 435 36 33 1 + 436 37 32 0 + 437 37 32 1 + 438 37 33 0 + 439 37 33 1 + 440 39 33 1 + 441 39 33 0 + 442 39 32 1 + 443 39 32 0 + 444 38 33 1 + 445 38 33 0 + 446 38 32 1 + 447 38 32 0 + 448 44 33 0 + 449 44 33 1 + 450 44 32 0 + 451 44 32 1 + 452 45 33 0 + 453 45 33 1 + 454 45 32 0 + 455 45 32 1 + 456 47 32 1 + 457 47 32 0 + 458 47 33 1 + 459 47 33 0 + 460 46 32 1 + 461 46 32 0 + 462 46 33 1 + 463 46 33 0 + 512 43 35 0 + 513 43 35 1 + 514 43 34 0 + 515 43 34 1 + 516 42 35 0 + 517 42 35 1 + 518 42 34 0 + 519 42 34 1 + 520 40 34 1 + 521 40 34 0 + 522 40 35 1 + 523 40 35 0 + 524 41 34 1 + 525 41 34 0 + 526 41 35 1 + 527 41 35 0 + 544 35 34 0 + 545 35 34 1 + 546 35 35 0 + 547 35 35 1 + 548 34 34 0 + 549 34 34 1 + 550 34 35 0 + 551 34 35 1 + 552 32 35 1 + 553 32 35 0 + 554 32 34 1 + 555 32 34 0 + 556 33 35 1 + 557 33 35 0 + 558 33 34 1 + 559 33 34 0 + 560 36 34 0 + 561 36 34 1 + 562 36 35 0 + 563 36 35 1 + 564 37 34 0 + 565 37 34 1 + 566 37 35 0 + 567 37 35 1 + 568 39 35 1 + 569 39 35 0 + 570 39 34 1 + 571 39 34 0 + 572 38 35 1 + 573 38 35 0 + 574 38 34 1 + 575 38 34 0 + 576 44 35 0 + 577 44 35 1 + 578 44 34 0 + 579 44 34 1 + 580 45 35 0 + 581 45 35 1 + 582 45 34 0 + 583 45 34 1 + 584 47 34 1 + 585 47 34 0 + 586 47 35 1 + 587 47 35 0 + 588 46 34 1 + 589 46 34 0 + 590 46 35 1 + 591 46 35 0 + 640 43 37 0 + 641 43 37 1 + 642 43 36 0 + 643 43 36 1 + 644 42 37 0 + 645 42 37 1 + 646 42 36 0 + 647 42 36 1 + 648 40 36 1 + 649 40 36 0 + 650 40 37 1 + 651 40 37 0 + 652 41 36 1 + 653 41 36 0 + 654 41 37 1 + 655 41 37 0 + 672 35 36 0 + 673 35 36 1 + 674 35 37 0 + 675 35 37 1 + 676 34 36 0 + 677 34 36 1 + 678 34 37 0 + 679 34 37 1 + 680 32 37 1 + 681 32 37 0 + 682 32 36 1 + 683 32 36 0 + 684 33 37 1 + 685 33 37 0 + 686 33 36 1 + 687 33 36 0 + 688 36 36 0 + 689 36 36 1 + 690 36 37 0 + 691 36 37 1 + 692 37 36 0 + 693 37 36 1 + 694 37 37 0 + 695 37 37 1 + 696 39 37 1 + 697 39 37 0 + 698 39 36 1 + 699 39 36 0 + 700 38 37 1 + 701 38 37 0 + 702 38 36 1 + 703 38 36 0 + 704 44 37 0 + 705 44 37 1 + 706 44 36 0 + 707 44 36 1 + 708 45 37 0 + 709 45 37 1 + 710 45 36 0 + 711 45 36 1 + 712 47 36 1 + 713 47 36 0 + 714 47 37 1 + 715 47 37 0 + 716 46 36 1 + 717 46 36 0 + 718 46 37 1 + 719 46 37 0 + 768 43 39 0 + 769 43 39 1 + 770 43 38 0 + 771 43 38 1 + 772 42 39 0 + 773 42 39 1 + 774 42 38 0 + 775 42 38 1 + 776 40 38 1 + 777 40 38 0 + 778 40 39 1 + 779 40 39 0 + 780 41 38 1 + 781 41 38 0 + 782 41 39 1 + 783 41 39 0 + 800 35 38 0 + 801 35 38 1 + 802 35 39 0 + 803 35 39 1 + 804 34 38 0 + 805 34 38 1 + 806 34 39 0 + 807 34 39 1 + 808 32 39 1 + 809 32 39 0 + 810 32 38 1 + 811 32 38 0 + 812 33 39 1 + 813 33 39 0 + 814 33 38 1 + 815 33 38 0 + 816 36 38 0 + 817 36 38 1 + 818 36 39 0 + 819 36 39 1 + 820 37 38 0 + 821 37 38 1 + 822 37 39 0 + 823 37 39 1 + 824 39 39 1 + 825 39 39 0 + 826 39 38 1 + 827 39 38 0 + 828 38 39 1 + 829 38 39 0 + 830 38 38 1 + 831 38 38 0 + 832 44 39 0 + 833 44 39 1 + 834 44 38 0 + 835 44 38 1 + 836 45 39 0 + 837 45 39 1 + 838 45 38 0 + 839 45 38 1 + 840 47 38 1 + 841 47 38 0 + 842 47 39 1 + 843 47 39 0 + 844 46 38 1 + 845 46 38 0 + 846 46 39 1 + 847 46 39 0 + 896 43 41 0 + 897 43 41 1 + 898 43 40 0 + 899 43 40 1 + 900 42 41 0 + 901 42 41 1 + 902 42 40 0 + 903 42 40 1 + 904 40 40 1 + 905 40 40 0 + 906 40 41 1 + 907 40 41 0 + 908 41 40 1 + 909 41 40 0 + 910 41 41 1 + 911 41 41 0 + 928 35 40 0 + 929 35 40 1 + 930 35 41 0 + 931 35 41 1 + 932 34 40 0 + 933 34 40 1 + 934 34 41 0 + 935 34 41 1 + 936 32 41 1 + 937 32 41 0 + 938 32 40 1 + 939 32 40 0 + 940 33 41 1 + 941 33 41 0 + 942 33 40 1 + 943 33 40 0 + 944 36 40 0 + 945 36 40 1 + 946 36 41 0 + 947 36 41 1 + 948 37 40 0 + 949 37 40 1 + 950 37 41 0 + 951 37 41 1 + 952 39 41 1 + 953 39 41 0 + 954 39 40 1 + 955 39 40 0 + 956 38 41 1 + 957 38 41 0 + 958 38 40 1 + 959 38 40 0 + 960 44 41 0 + 961 44 41 1 + 962 44 40 0 + 963 44 40 1 + 964 45 41 0 + 965 45 41 1 + 966 45 40 0 + 967 45 40 1 + 968 47 40 1 + 969 47 40 0 + 970 47 41 1 + 971 47 41 0 + 972 46 40 1 + 973 46 40 0 + 974 46 41 1 + 975 46 41 0 +1024 43 43 0 +1025 43 43 1 +1026 43 42 0 +1027 43 42 1 +1028 42 43 0 +1029 42 43 1 +1030 42 42 0 +1031 42 42 1 +1032 40 42 1 +1033 40 42 0 +1034 40 43 1 +1035 40 43 0 +1036 41 42 1 +1037 41 42 0 +1038 41 43 1 +1039 41 43 0 +1056 35 42 0 +1057 35 42 1 +1058 35 43 0 +1059 35 43 1 +1060 34 42 0 +1061 34 42 1 +1062 34 43 0 +1063 34 43 1 +1064 32 43 1 +1065 32 43 0 +1066 32 42 1 +1067 32 42 0 +1068 33 43 1 +1069 33 43 0 +1070 33 42 1 +1071 33 42 0 +1072 36 42 0 +1073 36 42 1 +1074 36 43 0 +1075 36 43 1 +1076 37 42 0 +1077 37 42 1 +1078 37 43 0 +1079 37 43 1 +1080 39 43 1 +1081 39 43 0 +1082 39 42 1 +1083 39 42 0 +1084 38 43 1 +1085 38 43 0 +1086 38 42 1 +1087 38 42 0 +1088 44 43 0 +1089 44 43 1 +1090 44 42 0 +1091 44 42 1 +1092 45 43 0 +1093 45 43 1 +1094 45 42 0 +1095 45 42 1 +1096 47 42 1 +1097 47 42 0 +1098 47 43 1 +1099 47 43 0 +1100 46 42 1 +1101 46 42 0 +1102 46 43 1 +1103 46 43 0 +1152 43 45 0 +1153 43 45 1 +1154 43 44 0 +1155 43 44 1 +1156 42 45 0 +1157 42 45 1 +1158 42 44 0 +1159 42 44 1 +1160 40 44 1 +1161 40 44 0 +1162 40 45 1 +1163 40 45 0 +1164 41 44 1 +1165 41 44 0 +1166 41 45 1 +1167 41 45 0 +1184 35 44 0 +1185 35 44 1 +1186 35 45 0 +1187 35 45 1 +1188 34 44 0 +1189 34 44 1 +1190 34 45 0 +1191 34 45 1 +1192 32 45 1 +1193 32 45 0 +1194 32 44 1 +1195 32 44 0 +1196 33 45 1 +1197 33 45 0 +1198 33 44 1 +1199 33 44 0 +1200 36 44 0 +1201 36 44 1 +1202 36 45 0 +1203 36 45 1 +1204 37 44 0 +1205 37 44 1 +1206 37 45 0 +1207 37 45 1 +1208 39 45 1 +1209 39 45 0 +1210 39 44 1 +1211 39 44 0 +1212 38 45 1 +1213 38 45 0 +1214 38 44 1 +1215 38 44 0 +1216 44 45 0 +1217 44 45 1 +1218 44 44 0 +1219 44 44 1 +1220 45 45 0 +1221 45 45 1 +1222 45 44 0 +1223 45 44 1 +1224 47 44 1 +1225 47 44 0 +1226 47 45 1 +1227 47 45 0 +1228 46 44 1 +1229 46 44 0 +1230 46 45 1 +1231 46 45 0 +1280 43 47 0 +1281 43 47 1 +1282 43 46 0 +1283 43 46 1 +1284 42 47 0 +1285 42 47 1 +1286 42 46 0 +1287 42 46 1 +1288 40 46 1 +1289 40 46 0 +1290 40 47 1 +1291 40 47 0 +1292 41 46 1 +1293 41 46 0 +1294 41 47 1 +1295 41 47 0 +1312 35 46 0 +1313 35 46 1 +1314 35 47 0 +1315 35 47 1 +1316 34 46 0 +1317 34 46 1 +1318 34 47 0 +1319 34 47 1 +1320 32 47 1 +1321 32 47 0 +1322 32 46 1 +1323 32 46 0 +1324 33 47 1 +1325 33 47 0 +1326 33 46 1 +1327 33 46 0 +1328 36 46 0 +1329 36 46 1 +1330 36 47 0 +1331 36 47 1 +1332 37 46 0 +1333 37 46 1 +1334 37 47 0 +1335 37 47 1 +1336 39 47 1 +1337 39 47 0 +1338 39 46 1 +1339 39 46 0 +1340 38 47 1 +1341 38 47 0 +1342 38 46 1 +1343 38 46 0 +1344 44 47 0 +1345 44 47 1 +1346 44 46 0 +1347 44 46 1 +1348 45 47 0 +1349 45 47 1 +1350 45 46 0 +1351 45 46 1 +1352 47 46 1 +1353 47 46 0 +1354 47 47 1 +1355 47 47 0 +1356 46 46 1 +1357 46 46 0 +1358 46 47 1 +1359 46 47 0 +1408 43 49 0 +1409 43 49 1 +1410 43 48 0 +1411 43 48 1 +1412 42 49 0 +1413 42 49 1 +1414 42 48 0 +1415 42 48 1 +1416 40 48 1 +1417 40 48 0 +1418 40 49 1 +1419 40 49 0 +1420 41 48 1 +1421 41 48 0 +1422 41 49 1 +1423 41 49 0 +1440 35 48 0 +1441 35 48 1 +1442 35 49 0 +1443 35 49 1 +1444 34 48 0 +1445 34 48 1 +1446 34 49 0 +1447 34 49 1 +1448 32 49 1 +1449 32 49 0 +1450 32 48 1 +1451 32 48 0 +1452 33 49 1 +1453 33 49 0 +1454 33 48 1 +1455 33 48 0 +1456 36 48 0 +1457 36 48 1 +1458 36 49 0 +1459 36 49 1 +1460 37 48 0 +1461 37 48 1 +1462 37 49 0 +1463 37 49 1 +1464 39 49 1 +1465 39 49 0 +1466 39 48 1 +1467 39 48 0 +1468 38 49 1 +1469 38 49 0 +1470 38 48 1 +1471 38 48 0 +1472 44 49 0 +1473 44 49 1 +1474 44 48 0 +1475 44 48 1 +1476 45 49 0 +1477 45 49 1 +1478 45 48 0 +1479 45 48 1 +1480 47 48 1 +1481 47 48 0 +1482 47 49 1 +1483 47 49 0 +1484 46 48 1 +1485 46 48 0 +1486 46 49 1 +1487 46 49 0 +1536 43 51 0 +1537 43 51 1 +1538 43 50 0 +1539 43 50 1 +1540 42 51 0 +1541 42 51 1 +1542 42 50 0 +1543 42 50 1 +1544 40 50 1 +1545 40 50 0 +1546 40 51 1 +1547 40 51 0 +1548 41 50 1 +1549 41 50 0 +1550 41 51 1 +1551 41 51 0 +1568 35 50 0 +1569 35 50 1 +1570 35 51 0 +1571 35 51 1 +1572 34 50 0 +1573 34 50 1 +1574 34 51 0 +1575 34 51 1 +1576 32 51 1 +1577 32 51 0 +1578 32 50 1 +1579 32 50 0 +1580 33 51 1 +1581 33 51 0 +1582 33 50 1 +1583 33 50 0 +1584 36 50 0 +1585 36 50 1 +1586 36 51 0 +1587 36 51 1 +1588 37 50 0 +1589 37 50 1 +1590 37 51 0 +1591 37 51 1 +1592 39 51 1 +1593 39 51 0 +1594 39 50 1 +1595 39 50 0 +1596 38 51 1 +1597 38 51 0 +1598 38 50 1 +1599 38 50 0 +1600 44 51 0 +1601 44 51 1 +1602 44 50 0 +1603 44 50 1 +1604 45 51 0 +1605 45 51 1 +1606 45 50 0 +1607 45 50 1 +1608 47 50 1 +1609 47 50 0 +1610 47 51 1 +1611 47 51 0 +1612 46 50 1 +1613 46 50 0 +1614 46 51 1 +1615 46 51 0 +1664 43 53 0 +1665 43 53 1 +1666 43 52 0 +1667 43 52 1 +1668 42 53 0 +1669 42 53 1 +1670 42 52 0 +1671 42 52 1 +1672 40 52 1 +1673 40 52 0 +1674 40 53 1 +1675 40 53 0 +1676 41 52 1 +1677 41 52 0 +1678 41 53 1 +1679 41 53 0 +1696 35 52 0 +1697 35 52 1 +1698 35 53 0 +1699 35 53 1 +1700 34 52 0 +1701 34 52 1 +1702 34 53 0 +1703 34 53 1 +1704 32 53 1 +1705 32 53 0 +1706 32 52 1 +1707 32 52 0 +1708 33 53 1 +1709 33 53 0 +1710 33 52 1 +1711 33 52 0 +1712 36 52 0 +1713 36 52 1 +1714 36 53 0 +1715 36 53 1 +1716 37 52 0 +1717 37 52 1 +1718 37 53 0 +1719 37 53 1 +1720 39 53 1 +1721 39 53 0 +1722 39 52 1 +1723 39 52 0 +1724 38 53 1 +1725 38 53 0 +1726 38 52 1 +1727 38 52 0 +1728 44 53 0 +1729 44 53 1 +1730 44 52 0 +1731 44 52 1 +1732 45 53 0 +1733 45 53 1 +1734 45 52 0 +1735 45 52 1 +1736 47 52 1 +1737 47 52 0 +1738 47 53 1 +1739 47 53 0 +1740 46 52 1 +1741 46 52 0 +1742 46 53 1 +1743 46 53 0 +1792 43 55 0 +1793 43 55 1 +1794 43 54 0 +1795 43 54 1 +1796 42 55 0 +1797 42 55 1 +1798 42 54 0 +1799 42 54 1 +1800 40 54 1 +1801 40 54 0 +1802 40 55 1 +1803 40 55 0 +1804 41 54 1 +1805 41 54 0 +1806 41 55 1 +1807 41 55 0 +1824 35 54 0 +1825 35 54 1 +1826 35 55 0 +1827 35 55 1 +1828 34 54 0 +1829 34 54 1 +1830 34 55 0 +1831 34 55 1 +1832 32 55 1 +1833 32 55 0 +1834 32 54 1 +1835 32 54 0 +1836 33 55 1 +1837 33 55 0 +1838 33 54 1 +1839 33 54 0 +1840 36 54 0 +1841 36 54 1 +1842 36 55 0 +1843 36 55 1 +1844 37 54 0 +1845 37 54 1 +1846 37 55 0 +1847 37 55 1 +1848 39 55 1 +1849 39 55 0 +1850 39 54 1 +1851 39 54 0 +1852 38 55 1 +1853 38 55 0 +1854 38 54 1 +1855 38 54 0 +1856 44 55 0 +1857 44 55 1 +1858 44 54 0 +1859 44 54 1 +1860 45 55 0 +1861 45 55 1 +1862 45 54 0 +1863 45 54 1 +1864 47 54 1 +1865 47 54 0 +1866 47 55 1 +1867 47 55 0 +1868 46 54 1 +1869 46 54 0 +1870 46 55 1 +1871 46 55 0 +2176 43 27 0 +2177 43 27 1 +2178 43 26 0 +2179 43 26 1 +2180 42 27 0 +2181 42 27 1 +2182 42 26 0 +2183 42 26 1 +2184 40 26 1 +2185 40 26 0 +2186 40 27 1 +2187 40 27 0 +2188 41 26 1 +2189 41 26 0 +2190 41 27 1 +2191 41 27 0 +2208 35 26 0 +2209 35 26 1 +2210 35 27 0 +2211 35 27 1 +2212 34 26 0 +2213 34 26 1 +2214 34 27 0 +2215 34 27 1 +2216 32 27 1 +2217 32 27 0 +2218 32 26 1 +2219 32 26 0 +2220 33 27 1 +2221 33 27 0 +2222 33 26 1 +2223 33 26 0 +2224 36 26 0 +2225 36 26 1 +2226 36 27 0 +2227 36 27 1 +2228 37 26 0 +2229 37 26 1 +2230 37 27 0 +2231 37 27 1 +2232 39 27 1 +2233 39 27 0 +2234 39 26 1 +2235 39 26 0 +2236 38 27 1 +2237 38 27 0 +2238 38 26 1 +2239 38 26 0 +2240 44 27 0 +2241 44 27 1 +2242 44 26 0 +2243 44 26 1 +2244 45 27 0 +2245 45 27 1 +2246 45 26 0 +2247 45 26 1 +2248 47 26 1 +2249 47 26 0 +2250 47 27 1 +2251 47 27 0 +2252 46 26 1 +2253 46 26 0 +2254 46 27 1 +2255 46 27 0 +2304 43 25 0 +2305 43 25 1 +2306 43 24 0 +2307 43 24 1 +2308 42 25 0 +2309 42 25 1 +2310 42 24 0 +2311 42 24 1 +2312 40 24 1 +2313 40 24 0 +2314 40 25 1 +2315 40 25 0 +2316 41 24 1 +2317 41 24 0 +2318 41 25 1 +2319 41 25 0 +2336 35 24 0 +2337 35 24 1 +2338 35 25 0 +2339 35 25 1 +2340 34 24 0 +2341 34 24 1 +2342 34 25 0 +2343 34 25 1 +2344 32 25 1 +2345 32 25 0 +2346 32 24 1 +2347 32 24 0 +2348 33 25 1 +2349 33 25 0 +2350 33 24 1 +2351 33 24 0 +2352 36 24 0 +2353 36 24 1 +2354 36 25 0 +2355 36 25 1 +2356 37 24 0 +2357 37 24 1 +2358 37 25 0 +2359 37 25 1 +2360 39 25 1 +2361 39 25 0 +2362 39 24 1 +2363 39 24 0 +2364 38 25 1 +2365 38 25 0 +2366 38 24 1 +2367 38 24 0 +2368 44 25 0 +2369 44 25 1 +2370 44 24 0 +2371 44 24 1 +2372 45 25 0 +2373 45 25 1 +2374 45 24 0 +2375 45 24 1 +2376 47 24 1 +2377 47 24 0 +2378 47 25 1 +2379 47 25 0 +2380 46 24 1 +2381 46 24 0 +2382 46 25 1 +2383 46 25 0 +2432 43 23 0 +2433 43 23 1 +2434 43 22 0 +2435 43 22 1 +2436 42 23 0 +2437 42 23 1 +2438 42 22 0 +2439 42 22 1 +2440 40 22 1 +2441 40 22 0 +2442 40 23 1 +2443 40 23 0 +2444 41 22 1 +2445 41 22 0 +2446 41 23 1 +2447 41 23 0 +2464 35 22 0 +2465 35 22 1 +2466 35 23 0 +2467 35 23 1 +2468 34 22 0 +2469 34 22 1 +2470 34 23 0 +2471 34 23 1 +2472 32 23 1 +2473 32 23 0 +2474 32 22 1 +2475 32 22 0 +2476 33 23 1 +2477 33 23 0 +2478 33 22 1 +2479 33 22 0 +2480 36 22 0 +2481 36 22 1 +2482 36 23 0 +2483 36 23 1 +2484 37 22 0 +2485 37 22 1 +2486 37 23 0 +2487 37 23 1 +2488 39 23 1 +2489 39 23 0 +2490 39 22 1 +2491 39 22 0 +2492 38 23 1 +2493 38 23 0 +2494 38 22 1 +2495 38 22 0 +2496 44 23 0 +2497 44 23 1 +2498 44 22 0 +2499 44 22 1 +2500 45 23 0 +2501 45 23 1 +2502 45 22 0 +2503 45 22 1 +2504 47 22 1 +2505 47 22 0 +2506 47 23 1 +2507 47 23 0 +2508 46 22 1 +2509 46 22 0 +2510 46 23 1 +2511 46 23 0 +2560 43 21 0 +2561 43 21 1 +2562 43 20 0 +2563 43 20 1 +2564 42 21 0 +2565 42 21 1 +2566 42 20 0 +2567 42 20 1 +2568 40 20 1 +2569 40 20 0 +2570 40 21 1 +2571 40 21 0 +2572 41 20 1 +2573 41 20 0 +2574 41 21 1 +2575 41 21 0 +2592 35 20 0 +2593 35 20 1 +2594 35 21 0 +2595 35 21 1 +2596 34 20 0 +2597 34 20 1 +2598 34 21 0 +2599 34 21 1 +2600 32 21 1 +2601 32 21 0 +2602 32 20 1 +2603 32 20 0 +2604 33 21 1 +2605 33 21 0 +2606 33 20 1 +2607 33 20 0 +2608 36 20 0 +2609 36 20 1 +2610 36 21 0 +2611 36 21 1 +2612 37 20 0 +2613 37 20 1 +2614 37 21 0 +2615 37 21 1 +2616 39 21 1 +2617 39 21 0 +2618 39 20 1 +2619 39 20 0 +2620 38 21 1 +2621 38 21 0 +2622 38 20 1 +2623 38 20 0 +2624 44 21 0 +2625 44 21 1 +2626 44 20 0 +2627 44 20 1 +2628 45 21 0 +2629 45 21 1 +2630 45 20 0 +2631 45 20 1 +2632 47 20 1 +2633 47 20 0 +2634 47 21 1 +2635 47 21 0 +2636 46 20 1 +2637 46 20 0 +2638 46 21 1 +2639 46 21 0 +2688 43 19 0 +2689 43 19 1 +2690 43 18 0 +2691 43 18 1 +2692 42 19 0 +2693 42 19 1 +2694 42 18 0 +2695 42 18 1 +2696 40 18 1 +2697 40 18 0 +2698 40 19 1 +2699 40 19 0 +2700 41 18 1 +2701 41 18 0 +2702 41 19 1 +2703 41 19 0 +2720 35 18 0 +2721 35 18 1 +2722 35 19 0 +2723 35 19 1 +2724 34 18 0 +2725 34 18 1 +2726 34 19 0 +2727 34 19 1 +2728 32 19 1 +2729 32 19 0 +2730 32 18 1 +2731 32 18 0 +2732 33 19 1 +2733 33 19 0 +2734 33 18 1 +2735 33 18 0 +2736 36 18 0 +2737 36 18 1 +2738 36 19 0 +2739 36 19 1 +2740 37 18 0 +2741 37 18 1 +2742 37 19 0 +2743 37 19 1 +2744 39 19 1 +2745 39 19 0 +2746 39 18 1 +2747 39 18 0 +2748 38 19 1 +2749 38 19 0 +2750 38 18 1 +2751 38 18 0 +2752 44 19 0 +2753 44 19 1 +2754 44 18 0 +2755 44 18 1 +2756 45 19 0 +2757 45 19 1 +2758 45 18 0 +2759 45 18 1 +2760 47 18 1 +2761 47 18 0 +2762 47 19 1 +2763 47 19 0 +2764 46 18 1 +2765 46 18 0 +2766 46 19 1 +2767 46 19 0 +2816 43 17 0 +2817 43 17 1 +2818 43 16 0 +2819 43 16 1 +2820 42 17 0 +2821 42 17 1 +2822 42 16 0 +2823 42 16 1 +2824 40 16 1 +2825 40 16 0 +2826 40 17 1 +2827 40 17 0 +2828 41 16 1 +2829 41 16 0 +2830 41 17 1 +2831 41 17 0 +2848 35 16 0 +2849 35 16 1 +2850 35 17 0 +2851 35 17 1 +2852 34 16 0 +2853 34 16 1 +2854 34 17 0 +2855 34 17 1 +2856 32 17 1 +2857 32 17 0 +2858 32 16 1 +2859 32 16 0 +2860 33 17 1 +2861 33 17 0 +2862 33 16 1 +2863 33 16 0 +2864 36 16 0 +2865 36 16 1 +2866 36 17 0 +2867 36 17 1 +2868 37 16 0 +2869 37 16 1 +2870 37 17 0 +2871 37 17 1 +2872 39 17 1 +2873 39 17 0 +2874 39 16 1 +2875 39 16 0 +2876 38 17 1 +2877 38 17 0 +2878 38 16 1 +2879 38 16 0 +2880 44 17 0 +2881 44 17 1 +2882 44 16 0 +2883 44 16 1 +2884 45 17 0 +2885 45 17 1 +2886 45 16 0 +2887 45 16 1 +2888 47 16 1 +2889 47 16 0 +2890 47 17 1 +2891 47 17 0 +2892 46 16 1 +2893 46 16 0 +2894 46 17 1 +2895 46 17 0 +2944 43 15 0 +2945 43 15 1 +2946 43 14 0 +2947 43 14 1 +2948 42 15 0 +2949 42 15 1 +2950 42 14 0 +2951 42 14 1 +2952 40 14 1 +2953 40 14 0 +2954 40 15 1 +2955 40 15 0 +2956 41 14 1 +2957 41 14 0 +2958 41 15 1 +2959 41 15 0 +2976 35 14 0 +2977 35 14 1 +2978 35 15 0 +2979 35 15 1 +2980 34 14 0 +2981 34 14 1 +2982 34 15 0 +2983 34 15 1 +2984 32 15 1 +2985 32 15 0 +2986 32 14 1 +2987 32 14 0 +2988 33 15 1 +2989 33 15 0 +2990 33 14 1 +2991 33 14 0 +2992 36 14 0 +2993 36 14 1 +2994 36 15 0 +2995 36 15 1 +2996 37 14 0 +2997 37 14 1 +2998 37 15 0 +2999 37 15 1 +3000 39 15 1 +3001 39 15 0 +3002 39 14 1 +3003 39 14 0 +3004 38 15 1 +3005 38 15 0 +3006 38 14 1 +3007 38 14 0 +3008 44 15 0 +3009 44 15 1 +3010 44 14 0 +3011 44 14 1 +3012 45 15 0 +3013 45 15 1 +3014 45 14 0 +3015 45 14 1 +3016 47 14 1 +3017 47 14 0 +3018 47 15 1 +3019 47 15 0 +3020 46 14 1 +3021 46 14 0 +3022 46 15 1 +3023 46 15 0 +3072 43 13 0 +3073 43 13 1 +3074 43 12 0 +3075 43 12 1 +3076 42 13 0 +3077 42 13 1 +3078 42 12 0 +3079 42 12 1 +3080 40 12 1 +3081 40 12 0 +3082 40 13 1 +3083 40 13 0 +3084 41 12 1 +3085 41 12 0 +3086 41 13 1 +3087 41 13 0 +3104 35 12 0 +3105 35 12 1 +3106 35 13 0 +3107 35 13 1 +3108 34 12 0 +3109 34 12 1 +3110 34 13 0 +3111 34 13 1 +3112 32 13 1 +3113 32 13 0 +3114 32 12 1 +3115 32 12 0 +3116 33 13 1 +3117 33 13 0 +3118 33 12 1 +3119 33 12 0 +3120 36 12 0 +3121 36 12 1 +3122 36 13 0 +3123 36 13 1 +3124 37 12 0 +3125 37 12 1 +3126 37 13 0 +3127 37 13 1 +3128 39 13 1 +3129 39 13 0 +3130 39 12 1 +3131 39 12 0 +3132 38 13 1 +3133 38 13 0 +3134 38 12 1 +3135 38 12 0 +3136 44 13 0 +3137 44 13 1 +3138 44 12 0 +3139 44 12 1 +3140 45 13 0 +3141 45 13 1 +3142 45 12 0 +3143 45 12 1 +3144 47 12 1 +3145 47 12 0 +3146 47 13 1 +3147 47 13 0 +3148 46 12 1 +3149 46 12 0 +3150 46 13 1 +3151 46 13 0 +3200 43 11 0 +3201 43 11 1 +3202 43 10 0 +3203 43 10 1 +3204 42 11 0 +3205 42 11 1 +3206 42 10 0 +3207 42 10 1 +3208 40 10 1 +3209 40 10 0 +3210 40 11 1 +3211 40 11 0 +3212 41 10 1 +3213 41 10 0 +3214 41 11 1 +3215 41 11 0 +3232 35 10 0 +3233 35 10 1 +3234 35 11 0 +3235 35 11 1 +3236 34 10 0 +3237 34 10 1 +3238 34 11 0 +3239 34 11 1 +3240 32 11 1 +3241 32 11 0 +3242 32 10 1 +3243 32 10 0 +3244 33 11 1 +3245 33 11 0 +3246 33 10 1 +3247 33 10 0 +3248 36 10 0 +3249 36 10 1 +3250 36 11 0 +3251 36 11 1 +3252 37 10 0 +3253 37 10 1 +3254 37 11 0 +3255 37 11 1 +3256 39 11 1 +3257 39 11 0 +3258 39 10 1 +3259 39 10 0 +3260 38 11 1 +3261 38 11 0 +3262 38 10 1 +3263 38 10 0 +3264 44 11 0 +3265 44 11 1 +3266 44 10 0 +3267 44 10 1 +3268 45 11 0 +3269 45 11 1 +3270 45 10 0 +3271 45 10 1 +3272 47 10 1 +3273 47 10 0 +3274 47 11 1 +3275 47 11 0 +3276 46 10 1 +3277 46 10 0 +3278 46 11 1 +3279 46 11 0 +3328 43 9 0 +3329 43 9 1 +3330 43 8 0 +3331 43 8 1 +3332 42 9 0 +3333 42 9 1 +3334 42 8 0 +3335 42 8 1 +3336 40 8 1 +3337 40 8 0 +3338 40 9 1 +3339 40 9 0 +3340 41 8 1 +3341 41 8 0 +3342 41 9 1 +3343 41 9 0 +3360 35 8 0 +3361 35 8 1 +3362 35 9 0 +3363 35 9 1 +3364 34 8 0 +3365 34 8 1 +3366 34 9 0 +3367 34 9 1 +3368 32 9 1 +3369 32 9 0 +3370 32 8 1 +3371 32 8 0 +3372 33 9 1 +3373 33 9 0 +3374 33 8 1 +3375 33 8 0 +3376 36 8 0 +3377 36 8 1 +3378 36 9 0 +3379 36 9 1 +3380 37 8 0 +3381 37 8 1 +3382 37 9 0 +3383 37 9 1 +3384 39 9 1 +3385 39 9 0 +3386 39 8 1 +3387 39 8 0 +3388 38 9 1 +3389 38 9 0 +3390 38 8 1 +3391 38 8 0 +3392 44 9 0 +3393 44 9 1 +3394 44 8 0 +3395 44 8 1 +3396 45 9 0 +3397 45 9 1 +3398 45 8 0 +3399 45 8 1 +3400 47 8 1 +3401 47 8 0 +3402 47 9 1 +3403 47 9 0 +3404 46 8 1 +3405 46 8 0 +3406 46 9 1 +3407 46 9 0 +3456 43 7 0 +3457 43 7 1 +3458 43 6 0 +3459 43 6 1 +3460 42 7 0 +3461 42 7 1 +3462 42 6 0 +3463 42 6 1 +3464 40 6 1 +3465 40 6 0 +3466 40 7 1 +3467 40 7 0 +3468 41 6 1 +3469 41 6 0 +3470 41 7 1 +3471 41 7 0 +3488 35 6 0 +3489 35 6 1 +3490 35 7 0 +3491 35 7 1 +3492 34 6 0 +3493 34 6 1 +3494 34 7 0 +3495 34 7 1 +3496 32 7 1 +3497 32 7 0 +3498 32 6 1 +3499 32 6 0 +3500 33 7 1 +3501 33 7 0 +3502 33 6 1 +3503 33 6 0 +3504 36 6 0 +3505 36 6 1 +3506 36 7 0 +3507 36 7 1 +3508 37 6 0 +3509 37 6 1 +3510 37 7 0 +3511 37 7 1 +3512 39 7 1 +3513 39 7 0 +3514 39 6 1 +3515 39 6 0 +3516 38 7 1 +3517 38 7 0 +3518 38 6 1 +3519 38 6 0 +3520 44 7 0 +3521 44 7 1 +3522 44 6 0 +3523 44 6 1 +3524 45 7 0 +3525 45 7 1 +3526 45 6 0 +3527 45 6 1 +3528 47 6 1 +3529 47 6 0 +3530 47 7 1 +3531 47 7 0 +3532 46 6 1 +3533 46 6 0 +3534 46 7 1 +3535 46 7 0 +3584 43 5 0 +3585 43 5 1 +3586 43 4 0 +3587 43 4 1 +3588 42 5 0 +3589 42 5 1 +3590 42 4 0 +3591 42 4 1 +3592 40 4 1 +3593 40 4 0 +3594 40 5 1 +3595 40 5 0 +3596 41 4 1 +3597 41 4 0 +3598 41 5 1 +3599 41 5 0 +3616 35 4 0 +3617 35 4 1 +3618 35 5 0 +3619 35 5 1 +3620 34 4 0 +3621 34 4 1 +3622 34 5 0 +3623 34 5 1 +3624 32 5 1 +3625 32 5 0 +3626 32 4 1 +3627 32 4 0 +3628 33 5 1 +3629 33 5 0 +3630 33 4 1 +3631 33 4 0 +3632 36 4 0 +3633 36 4 1 +3634 36 5 0 +3635 36 5 1 +3636 37 4 0 +3637 37 4 1 +3638 37 5 0 +3639 37 5 1 +3640 39 5 1 +3641 39 5 0 +3642 39 4 1 +3643 39 4 0 +3644 38 5 1 +3645 38 5 0 +3646 38 4 1 +3647 38 4 0 +3648 44 5 0 +3649 44 5 1 +3650 44 4 0 +3651 44 4 1 +3652 45 5 0 +3653 45 5 1 +3654 45 4 0 +3655 45 4 1 +3656 47 4 1 +3657 47 4 0 +3658 47 5 1 +3659 47 5 0 +3660 46 4 1 +3661 46 4 0 +3662 46 5 1 +3663 46 5 0 +3712 43 3 0 +3713 43 3 1 +3714 43 2 0 +3715 43 2 1 +3716 42 3 0 +3717 42 3 1 +3718 42 2 0 +3719 42 2 1 +3720 40 2 1 +3721 40 2 0 +3722 40 3 1 +3723 40 3 0 +3724 41 2 1 +3725 41 2 0 +3726 41 3 1 +3727 41 3 0 +3744 35 2 0 +3745 35 2 1 +3746 35 3 0 +3747 35 3 1 +3748 34 2 0 +3749 34 2 1 +3750 34 3 0 +3751 34 3 1 +3752 32 3 1 +3753 32 3 0 +3754 32 2 1 +3755 32 2 0 +3756 33 3 1 +3757 33 3 0 +3758 33 2 1 +3759 33 2 0 +3760 36 2 0 +3761 36 2 1 +3762 36 3 0 +3763 36 3 1 +3764 37 2 0 +3765 37 2 1 +3766 37 3 0 +3767 37 3 1 +3768 39 3 1 +3769 39 3 0 +3770 39 2 1 +3771 39 2 0 +3772 38 3 1 +3773 38 3 0 +3774 38 2 1 +3775 38 2 0 +3776 44 3 0 +3777 44 3 1 +3778 44 2 0 +3779 44 2 1 +3780 45 3 0 +3781 45 3 1 +3782 45 2 0 +3783 45 2 1 +3784 47 2 1 +3785 47 2 0 +3786 47 3 1 +3787 47 3 0 +3788 46 2 1 +3789 46 2 0 +3790 46 3 1 +3791 46 3 0 +3840 43 1 0 +3841 43 1 1 +3842 43 0 0 +3843 43 0 1 +3844 42 1 0 +3845 42 1 1 +3846 42 0 0 +3847 42 0 1 +3848 40 0 1 +3849 40 0 0 +3850 40 1 1 +3851 40 1 0 +3852 41 0 1 +3853 41 0 0 +3854 41 1 1 +3855 41 1 0 +3872 35 0 0 +3873 35 0 1 +3874 35 1 0 +3875 35 1 1 +3876 34 0 0 +3877 34 0 1 +3878 34 1 0 +3879 34 1 1 +3880 32 1 1 +3881 32 1 0 +3882 32 0 1 +3883 32 0 0 +3884 33 1 1 +3885 33 1 0 +3886 33 0 1 +3887 33 0 0 +3888 36 0 0 +3889 36 0 1 +3890 36 1 0 +3891 36 1 1 +3892 37 0 0 +3893 37 0 1 +3894 37 1 0 +3895 37 1 1 +3896 39 1 1 +3897 39 1 0 +3898 39 0 1 +3899 39 0 0 +3900 38 1 1 +3901 38 1 0 +3902 38 0 1 +3903 38 0 0 +3904 44 1 0 +3905 44 1 1 +3906 44 0 0 +3907 44 0 1 +3908 45 1 0 +3909 45 1 1 +3910 45 0 0 +3911 45 0 1 +3912 47 0 1 +3913 47 0 0 +3914 47 1 1 +3915 47 1 0 +3916 46 0 1 +3917 46 0 0 +3918 46 1 1 +3919 46 1 0 diff --git a/Detectors/PHOS/base/files/Mod0RCU3.data b/Detectors/PHOS/base/files/Mod0RCU3.data new file mode 100644 index 0000000000000..43bd76fc42791 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod0RCU3.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 3 0 2 + 1 3 1 2 + 2 3 2 2 + 3 3 3 2 + 4 3 4 2 + 5 3 5 2 + 6 3 6 2 + 7 3 7 2 + 8 3 8 2 + 9 3 9 2 + 10 3 10 2 + 11 3 11 2 + 12 3 12 2 + 13 3 13 2 + 14 3 14 2 + 15 3 15 2 + 16 3 16 2 + 17 3 17 2 + 18 3 18 2 + 19 3 19 2 + 20 3 20 2 + 21 3 21 2 + 22 3 22 2 + 23 3 23 2 + 24 3 24 2 + 25 3 25 2 + 26 3 26 2 + 27 3 27 2 + 28 3 28 2 + 29 3 29 2 + 30 3 30 2 + 31 3 31 2 + 32 3 32 2 + 33 3 33 2 + 34 3 34 2 + 35 3 35 2 + 36 3 36 2 + 37 3 37 2 + 38 3 38 2 + 39 3 39 2 + 40 3 40 2 + 41 3 41 2 + 42 3 42 2 + 43 3 43 2 + 44 3 44 2 + 45 3 45 2 + 46 3 46 2 + 47 3 47 2 + 48 3 48 2 + 49 3 49 2 + 50 3 50 2 + 51 3 51 2 + 52 3 52 2 + 53 3 53 2 + 54 3 54 2 + 55 3 55 2 + 56 3 56 2 + 57 3 57 2 + 58 3 58 2 + 59 3 59 2 + 60 3 60 2 + 61 3 61 2 + 62 3 62 2 + 63 3 63 2 + 64 3 64 2 + 65 3 65 2 + 66 3 66 2 + 67 3 67 2 + 68 3 68 2 + 69 3 69 2 + 70 3 70 2 + 71 3 71 2 + 72 3 72 2 + 73 3 73 2 + 74 3 74 2 + 75 3 75 2 + 76 3 76 2 + 77 3 77 2 + 78 3 78 2 + 79 3 79 2 + 80 3 80 2 + 81 3 81 2 + 82 3 82 2 + 83 3 83 2 + 84 3 84 2 + 85 3 85 2 + 86 3 86 2 + 87 3 87 2 + 88 3 88 2 + 89 3 89 2 + 90 3 90 2 + 91 3 91 2 + 92 3 92 2 + 93 3 93 2 + 94 3 94 2 + 95 3 95 2 + 96 3 96 2 + 97 3 97 2 + 98 3 98 2 + 99 3 99 2 + 100 3 100 2 + 101 3 101 2 + 102 3 102 2 + 103 3 103 2 + 104 3 104 2 + 105 3 105 2 + 106 3 106 2 + 107 3 107 2 + 108 3 108 2 + 109 3 109 2 + 110 3 110 2 + 111 3 111 2 + 112 3 112 2 + 113 3 113 2 + 114 3 114 2 + 115 3 115 2 + 116 3 116 2 + 117 3 117 2 + 118 3 118 2 + 119 3 119 2 + 120 3 120 2 + 121 3 121 2 + 122 3 122 2 + 123 3 123 2 + 124 3 124 2 + 125 3 125 2 + 126 3 126 2 + 127 3 127 2 +2048 3 2048 2 +2049 3 2049 2 +2050 3 2050 2 +2051 3 2051 2 +2052 3 2052 2 +2053 3 2053 2 +2054 3 2054 2 +2055 3 2055 2 +2056 3 2056 2 +2057 3 2057 2 +2058 3 2058 2 +2059 3 2059 2 +2060 3 2060 2 +2061 3 2061 2 +2062 3 2062 2 +2063 3 2063 2 +2064 3 2064 2 +2065 3 2065 2 +2066 3 2066 2 +2067 3 2067 2 +2068 3 2068 2 +2069 3 2069 2 +2070 3 2070 2 +2071 3 2071 2 +2072 3 2072 2 +2073 3 2073 2 +2074 3 2074 2 +2075 3 2075 2 +2076 3 2076 2 +2077 3 2077 2 +2078 3 2078 2 +2079 3 2079 2 +2080 3 2080 2 +2081 3 2081 2 +2082 3 2082 2 +2083 3 2083 2 +2084 3 2084 2 +2085 3 2085 2 +2086 3 2086 2 +2087 3 2087 2 +2088 3 2088 2 +2089 3 2089 2 +2090 3 2090 2 +2091 3 2091 2 +2092 3 2092 2 +2093 3 2093 2 +2094 3 2094 2 +2095 3 2095 2 +2096 3 2096 2 +2097 3 2097 2 +2098 3 2098 2 +2099 3 2099 2 +2100 3 2100 2 +2101 3 2101 2 +2102 3 2102 2 +2103 3 2103 2 +2104 3 2104 2 +2105 3 2105 2 +2106 3 2106 2 +2107 3 2107 2 +2108 3 2108 2 +2109 3 2109 2 +2110 3 2110 2 +2111 3 2111 2 +2112 3 2112 2 +2113 3 2113 2 +2114 3 2114 2 +2115 3 2115 2 +2116 3 2116 2 +2117 3 2117 2 +2118 3 2118 2 +2119 3 2119 2 +2120 3 2120 2 +2121 3 2121 2 +2122 3 2122 2 +2123 3 2123 2 +2124 3 2124 2 +2125 3 2125 2 +2126 3 2126 2 +2127 3 2127 2 +2128 3 2128 2 +2129 3 2129 2 +2130 3 2130 2 +2131 3 2131 2 +2132 3 2132 2 +2133 3 2133 2 +2134 3 2134 2 +2135 3 2135 2 +2136 3 2136 2 +2137 3 2137 2 +2138 3 2138 2 +2139 3 2139 2 +2140 3 2140 2 +2141 3 2141 2 +2142 3 2142 2 +2143 3 2143 2 +2144 3 2144 2 +2145 3 2145 2 +2146 3 2146 2 +2147 3 2147 2 +2148 3 2148 2 +2149 3 2149 2 +2150 3 2150 2 +2151 3 2151 2 +2152 3 2152 2 +2153 3 2153 2 +2154 3 2154 2 +2155 3 2155 2 +2156 3 2156 2 +2157 3 2157 2 +2158 3 2158 2 +2159 3 2159 2 +2160 3 2160 2 +2161 3 2161 2 +2162 3 2162 2 +2163 3 2163 2 +2164 3 2164 2 +2165 3 2165 2 +2166 3 2166 2 +2167 3 2167 2 +2168 3 2168 2 +2169 3 2169 2 +2170 3 2170 2 +2171 3 2171 2 +2172 3 2172 2 +2173 3 2173 2 +2174 3 2174 2 +2175 3 2175 2 + 128 59 29 0 + 129 59 29 1 + 130 59 28 0 + 131 59 28 1 + 132 58 29 0 + 133 58 29 1 + 134 58 28 0 + 135 58 28 1 + 136 56 28 1 + 137 56 28 0 + 138 56 29 1 + 139 56 29 0 + 140 57 28 1 + 141 57 28 0 + 142 57 29 1 + 143 57 29 0 + 160 51 28 0 + 161 51 28 1 + 162 51 29 0 + 163 51 29 1 + 164 50 28 0 + 165 50 28 1 + 166 50 29 0 + 167 50 29 1 + 168 48 29 1 + 169 48 29 0 + 170 48 28 1 + 171 48 28 0 + 172 49 29 1 + 173 49 29 0 + 174 49 28 1 + 175 49 28 0 + 176 52 28 0 + 177 52 28 1 + 178 52 29 0 + 179 52 29 1 + 180 53 28 0 + 181 53 28 1 + 182 53 29 0 + 183 53 29 1 + 184 55 29 1 + 185 55 29 0 + 186 55 28 1 + 187 55 28 0 + 188 54 29 1 + 189 54 29 0 + 190 54 28 1 + 191 54 28 0 + 192 60 29 0 + 193 60 29 1 + 194 60 28 0 + 195 60 28 1 + 196 61 29 0 + 197 61 29 1 + 198 61 28 0 + 199 61 28 1 + 200 63 28 1 + 201 63 28 0 + 202 63 29 1 + 203 63 29 0 + 204 62 28 1 + 205 62 28 0 + 206 62 29 1 + 207 62 29 0 + 256 59 31 0 + 257 59 31 1 + 258 59 30 0 + 259 59 30 1 + 260 58 31 0 + 261 58 31 1 + 262 58 30 0 + 263 58 30 1 + 264 56 30 1 + 265 56 30 0 + 266 56 31 1 + 267 56 31 0 + 268 57 30 1 + 269 57 30 0 + 270 57 31 1 + 271 57 31 0 + 288 51 30 0 + 289 51 30 1 + 290 51 31 0 + 291 51 31 1 + 292 50 30 0 + 293 50 30 1 + 294 50 31 0 + 295 50 31 1 + 296 48 31 1 + 297 48 31 0 + 298 48 30 1 + 299 48 30 0 + 300 49 31 1 + 301 49 31 0 + 302 49 30 1 + 303 49 30 0 + 304 52 30 0 + 305 52 30 1 + 306 52 31 0 + 307 52 31 1 + 308 53 30 0 + 309 53 30 1 + 310 53 31 0 + 311 53 31 1 + 312 55 31 1 + 313 55 31 0 + 314 55 30 1 + 315 55 30 0 + 316 54 31 1 + 317 54 31 0 + 318 54 30 1 + 319 54 30 0 + 320 60 31 0 + 321 60 31 1 + 322 60 30 0 + 323 60 30 1 + 324 61 31 0 + 325 61 31 1 + 326 61 30 0 + 327 61 30 1 + 328 63 30 1 + 329 63 30 0 + 330 63 31 1 + 331 63 31 0 + 332 62 30 1 + 333 62 30 0 + 334 62 31 1 + 335 62 31 0 + 384 59 33 0 + 385 59 33 1 + 386 59 32 0 + 387 59 32 1 + 388 58 33 0 + 389 58 33 1 + 390 58 32 0 + 391 58 32 1 + 392 56 32 1 + 393 56 32 0 + 394 56 33 1 + 395 56 33 0 + 396 57 32 1 + 397 57 32 0 + 398 57 33 1 + 399 57 33 0 + 416 51 32 0 + 417 51 32 1 + 418 51 33 0 + 419 51 33 1 + 420 50 32 0 + 421 50 32 1 + 422 50 33 0 + 423 50 33 1 + 424 48 33 1 + 425 48 33 0 + 426 48 32 1 + 427 48 32 0 + 428 49 33 1 + 429 49 33 0 + 430 49 32 1 + 431 49 32 0 + 432 52 32 0 + 433 52 32 1 + 434 52 33 0 + 435 52 33 1 + 436 53 32 0 + 437 53 32 1 + 438 53 33 0 + 439 53 33 1 + 440 55 33 1 + 441 55 33 0 + 442 55 32 1 + 443 55 32 0 + 444 54 33 1 + 445 54 33 0 + 446 54 32 1 + 447 54 32 0 + 448 60 33 0 + 449 60 33 1 + 450 60 32 0 + 451 60 32 1 + 452 61 33 0 + 453 61 33 1 + 454 61 32 0 + 455 61 32 1 + 456 63 32 1 + 457 63 32 0 + 458 63 33 1 + 459 63 33 0 + 460 62 32 1 + 461 62 32 0 + 462 62 33 1 + 463 62 33 0 + 512 59 35 0 + 513 59 35 1 + 514 59 34 0 + 515 59 34 1 + 516 58 35 0 + 517 58 35 1 + 518 58 34 0 + 519 58 34 1 + 520 56 34 1 + 521 56 34 0 + 522 56 35 1 + 523 56 35 0 + 524 57 34 1 + 525 57 34 0 + 526 57 35 1 + 527 57 35 0 + 544 51 34 0 + 545 51 34 1 + 546 51 35 0 + 547 51 35 1 + 548 50 34 0 + 549 50 34 1 + 550 50 35 0 + 551 50 35 1 + 552 48 35 1 + 553 48 35 0 + 554 48 34 1 + 555 48 34 0 + 556 49 35 1 + 557 49 35 0 + 558 49 34 1 + 559 49 34 0 + 560 52 34 0 + 561 52 34 1 + 562 52 35 0 + 563 52 35 1 + 564 53 34 0 + 565 53 34 1 + 566 53 35 0 + 567 53 35 1 + 568 55 35 1 + 569 55 35 0 + 570 55 34 1 + 571 55 34 0 + 572 54 35 1 + 573 54 35 0 + 574 54 34 1 + 575 54 34 0 + 576 60 35 0 + 577 60 35 1 + 578 60 34 0 + 579 60 34 1 + 580 61 35 0 + 581 61 35 1 + 582 61 34 0 + 583 61 34 1 + 584 63 34 1 + 585 63 34 0 + 586 63 35 1 + 587 63 35 0 + 588 62 34 1 + 589 62 34 0 + 590 62 35 1 + 591 62 35 0 + 640 59 37 0 + 641 59 37 1 + 642 59 36 0 + 643 59 36 1 + 644 58 37 0 + 645 58 37 1 + 646 58 36 0 + 647 58 36 1 + 648 56 36 1 + 649 56 36 0 + 650 56 37 1 + 651 56 37 0 + 652 57 36 1 + 653 57 36 0 + 654 57 37 1 + 655 57 37 0 + 672 51 36 0 + 673 51 36 1 + 674 51 37 0 + 675 51 37 1 + 676 50 36 0 + 677 50 36 1 + 678 50 37 0 + 679 50 37 1 + 680 48 37 1 + 681 48 37 0 + 682 48 36 1 + 683 48 36 0 + 684 49 37 1 + 685 49 37 0 + 686 49 36 1 + 687 49 36 0 + 688 52 36 0 + 689 52 36 1 + 690 52 37 0 + 691 52 37 1 + 692 53 36 0 + 693 53 36 1 + 694 53 37 0 + 695 53 37 1 + 696 55 37 1 + 697 55 37 0 + 698 55 36 1 + 699 55 36 0 + 700 54 37 1 + 701 54 37 0 + 702 54 36 1 + 703 54 36 0 + 704 60 37 0 + 705 60 37 1 + 706 60 36 0 + 707 60 36 1 + 708 61 37 0 + 709 61 37 1 + 710 61 36 0 + 711 61 36 1 + 712 63 36 1 + 713 63 36 0 + 714 63 37 1 + 715 63 37 0 + 716 62 36 1 + 717 62 36 0 + 718 62 37 1 + 719 62 37 0 + 768 59 39 0 + 769 59 39 1 + 770 59 38 0 + 771 59 38 1 + 772 58 39 0 + 773 58 39 1 + 774 58 38 0 + 775 58 38 1 + 776 56 38 1 + 777 56 38 0 + 778 56 39 1 + 779 56 39 0 + 780 57 38 1 + 781 57 38 0 + 782 57 39 1 + 783 57 39 0 + 800 51 38 0 + 801 51 38 1 + 802 51 39 0 + 803 51 39 1 + 804 50 38 0 + 805 50 38 1 + 806 50 39 0 + 807 50 39 1 + 808 48 39 1 + 809 48 39 0 + 810 48 38 1 + 811 48 38 0 + 812 49 39 1 + 813 49 39 0 + 814 49 38 1 + 815 49 38 0 + 816 52 38 0 + 817 52 38 1 + 818 52 39 0 + 819 52 39 1 + 820 53 38 0 + 821 53 38 1 + 822 53 39 0 + 823 53 39 1 + 824 55 39 1 + 825 55 39 0 + 826 55 38 1 + 827 55 38 0 + 828 54 39 1 + 829 54 39 0 + 830 54 38 1 + 831 54 38 0 + 832 60 39 0 + 833 60 39 1 + 834 60 38 0 + 835 60 38 1 + 836 61 39 0 + 837 61 39 1 + 838 61 38 0 + 839 61 38 1 + 840 63 38 1 + 841 63 38 0 + 842 63 39 1 + 843 63 39 0 + 844 62 38 1 + 845 62 38 0 + 846 62 39 1 + 847 62 39 0 + 896 59 41 0 + 897 59 41 1 + 898 59 40 0 + 899 59 40 1 + 900 58 41 0 + 901 58 41 1 + 902 58 40 0 + 903 58 40 1 + 904 56 40 1 + 905 56 40 0 + 906 56 41 1 + 907 56 41 0 + 908 57 40 1 + 909 57 40 0 + 910 57 41 1 + 911 57 41 0 + 928 51 40 0 + 929 51 40 1 + 930 51 41 0 + 931 51 41 1 + 932 50 40 0 + 933 50 40 1 + 934 50 41 0 + 935 50 41 1 + 936 48 41 1 + 937 48 41 0 + 938 48 40 1 + 939 48 40 0 + 940 49 41 1 + 941 49 41 0 + 942 49 40 1 + 943 49 40 0 + 944 52 40 0 + 945 52 40 1 + 946 52 41 0 + 947 52 41 1 + 948 53 40 0 + 949 53 40 1 + 950 53 41 0 + 951 53 41 1 + 952 55 41 1 + 953 55 41 0 + 954 55 40 1 + 955 55 40 0 + 956 54 41 1 + 957 54 41 0 + 958 54 40 1 + 959 54 40 0 + 960 60 41 0 + 961 60 41 1 + 962 60 40 0 + 963 60 40 1 + 964 61 41 0 + 965 61 41 1 + 966 61 40 0 + 967 61 40 1 + 968 63 40 1 + 969 63 40 0 + 970 63 41 1 + 971 63 41 0 + 972 62 40 1 + 973 62 40 0 + 974 62 41 1 + 975 62 41 0 +1024 59 43 0 +1025 59 43 1 +1026 59 42 0 +1027 59 42 1 +1028 58 43 0 +1029 58 43 1 +1030 58 42 0 +1031 58 42 1 +1032 56 42 1 +1033 56 42 0 +1034 56 43 1 +1035 56 43 0 +1036 57 42 1 +1037 57 42 0 +1038 57 43 1 +1039 57 43 0 +1056 51 42 0 +1057 51 42 1 +1058 51 43 0 +1059 51 43 1 +1060 50 42 0 +1061 50 42 1 +1062 50 43 0 +1063 50 43 1 +1064 48 43 1 +1065 48 43 0 +1066 48 42 1 +1067 48 42 0 +1068 49 43 1 +1069 49 43 0 +1070 49 42 1 +1071 49 42 0 +1072 52 42 0 +1073 52 42 1 +1074 52 43 0 +1075 52 43 1 +1076 53 42 0 +1077 53 42 1 +1078 53 43 0 +1079 53 43 1 +1080 55 43 1 +1081 55 43 0 +1082 55 42 1 +1083 55 42 0 +1084 54 43 1 +1085 54 43 0 +1086 54 42 1 +1087 54 42 0 +1088 60 43 0 +1089 60 43 1 +1090 60 42 0 +1091 60 42 1 +1092 61 43 0 +1093 61 43 1 +1094 61 42 0 +1095 61 42 1 +1096 63 42 1 +1097 63 42 0 +1098 63 43 1 +1099 63 43 0 +1100 62 42 1 +1101 62 42 0 +1102 62 43 1 +1103 62 43 0 +1152 59 45 0 +1153 59 45 1 +1154 59 44 0 +1155 59 44 1 +1156 58 45 0 +1157 58 45 1 +1158 58 44 0 +1159 58 44 1 +1160 56 44 1 +1161 56 44 0 +1162 56 45 1 +1163 56 45 0 +1164 57 44 1 +1165 57 44 0 +1166 57 45 1 +1167 57 45 0 +1184 51 44 0 +1185 51 44 1 +1186 51 45 0 +1187 51 45 1 +1188 50 44 0 +1189 50 44 1 +1190 50 45 0 +1191 50 45 1 +1192 48 45 1 +1193 48 45 0 +1194 48 44 1 +1195 48 44 0 +1196 49 45 1 +1197 49 45 0 +1198 49 44 1 +1199 49 44 0 +1200 52 44 0 +1201 52 44 1 +1202 52 45 0 +1203 52 45 1 +1204 53 44 0 +1205 53 44 1 +1206 53 45 0 +1207 53 45 1 +1208 55 45 1 +1209 55 45 0 +1210 55 44 1 +1211 55 44 0 +1212 54 45 1 +1213 54 45 0 +1214 54 44 1 +1215 54 44 0 +1216 60 45 0 +1217 60 45 1 +1218 60 44 0 +1219 60 44 1 +1220 61 45 0 +1221 61 45 1 +1222 61 44 0 +1223 61 44 1 +1224 63 44 1 +1225 63 44 0 +1226 63 45 1 +1227 63 45 0 +1228 62 44 1 +1229 62 44 0 +1230 62 45 1 +1231 62 45 0 +1280 59 47 0 +1281 59 47 1 +1282 59 46 0 +1283 59 46 1 +1284 58 47 0 +1285 58 47 1 +1286 58 46 0 +1287 58 46 1 +1288 56 46 1 +1289 56 46 0 +1290 56 47 1 +1291 56 47 0 +1292 57 46 1 +1293 57 46 0 +1294 57 47 1 +1295 57 47 0 +1312 51 46 0 +1313 51 46 1 +1314 51 47 0 +1315 51 47 1 +1316 50 46 0 +1317 50 46 1 +1318 50 47 0 +1319 50 47 1 +1320 48 47 1 +1321 48 47 0 +1322 48 46 1 +1323 48 46 0 +1324 49 47 1 +1325 49 47 0 +1326 49 46 1 +1327 49 46 0 +1328 52 46 0 +1329 52 46 1 +1330 52 47 0 +1331 52 47 1 +1332 53 46 0 +1333 53 46 1 +1334 53 47 0 +1335 53 47 1 +1336 55 47 1 +1337 55 47 0 +1338 55 46 1 +1339 55 46 0 +1340 54 47 1 +1341 54 47 0 +1342 54 46 1 +1343 54 46 0 +1344 60 47 0 +1345 60 47 1 +1346 60 46 0 +1347 60 46 1 +1348 61 47 0 +1349 61 47 1 +1350 61 46 0 +1351 61 46 1 +1352 63 46 1 +1353 63 46 0 +1354 63 47 1 +1355 63 47 0 +1356 62 46 1 +1357 62 46 0 +1358 62 47 1 +1359 62 47 0 +1408 59 49 0 +1409 59 49 1 +1410 59 48 0 +1411 59 48 1 +1412 58 49 0 +1413 58 49 1 +1414 58 48 0 +1415 58 48 1 +1416 56 48 1 +1417 56 48 0 +1418 56 49 1 +1419 56 49 0 +1420 57 48 1 +1421 57 48 0 +1422 57 49 1 +1423 57 49 0 +1440 51 48 0 +1441 51 48 1 +1442 51 49 0 +1443 51 49 1 +1444 50 48 0 +1445 50 48 1 +1446 50 49 0 +1447 50 49 1 +1448 48 49 1 +1449 48 49 0 +1450 48 48 1 +1451 48 48 0 +1452 49 49 1 +1453 49 49 0 +1454 49 48 1 +1455 49 48 0 +1456 52 48 0 +1457 52 48 1 +1458 52 49 0 +1459 52 49 1 +1460 53 48 0 +1461 53 48 1 +1462 53 49 0 +1463 53 49 1 +1464 55 49 1 +1465 55 49 0 +1466 55 48 1 +1467 55 48 0 +1468 54 49 1 +1469 54 49 0 +1470 54 48 1 +1471 54 48 0 +1472 60 49 0 +1473 60 49 1 +1474 60 48 0 +1475 60 48 1 +1476 61 49 0 +1477 61 49 1 +1478 61 48 0 +1479 61 48 1 +1480 63 48 1 +1481 63 48 0 +1482 63 49 1 +1483 63 49 0 +1484 62 48 1 +1485 62 48 0 +1486 62 49 1 +1487 62 49 0 +1536 59 51 0 +1537 59 51 1 +1538 59 50 0 +1539 59 50 1 +1540 58 51 0 +1541 58 51 1 +1542 58 50 0 +1543 58 50 1 +1544 56 50 1 +1545 56 50 0 +1546 56 51 1 +1547 56 51 0 +1548 57 50 1 +1549 57 50 0 +1550 57 51 1 +1551 57 51 0 +1568 51 50 0 +1569 51 50 1 +1570 51 51 0 +1571 51 51 1 +1572 50 50 0 +1573 50 50 1 +1574 50 51 0 +1575 50 51 1 +1576 48 51 1 +1577 48 51 0 +1578 48 50 1 +1579 48 50 0 +1580 49 51 1 +1581 49 51 0 +1582 49 50 1 +1583 49 50 0 +1584 52 50 0 +1585 52 50 1 +1586 52 51 0 +1587 52 51 1 +1588 53 50 0 +1589 53 50 1 +1590 53 51 0 +1591 53 51 1 +1592 55 51 1 +1593 55 51 0 +1594 55 50 1 +1595 55 50 0 +1596 54 51 1 +1597 54 51 0 +1598 54 50 1 +1599 54 50 0 +1600 60 51 0 +1601 60 51 1 +1602 60 50 0 +1603 60 50 1 +1604 61 51 0 +1605 61 51 1 +1606 61 50 0 +1607 61 50 1 +1608 63 50 1 +1609 63 50 0 +1610 63 51 1 +1611 63 51 0 +1612 62 50 1 +1613 62 50 0 +1614 62 51 1 +1615 62 51 0 +1664 59 53 0 +1665 59 53 1 +1666 59 52 0 +1667 59 52 1 +1668 58 53 0 +1669 58 53 1 +1670 58 52 0 +1671 58 52 1 +1672 56 52 1 +1673 56 52 0 +1674 56 53 1 +1675 56 53 0 +1676 57 52 1 +1677 57 52 0 +1678 57 53 1 +1679 57 53 0 +1696 51 52 0 +1697 51 52 1 +1698 51 53 0 +1699 51 53 1 +1700 50 52 0 +1701 50 52 1 +1702 50 53 0 +1703 50 53 1 +1704 48 53 1 +1705 48 53 0 +1706 48 52 1 +1707 48 52 0 +1708 49 53 1 +1709 49 53 0 +1710 49 52 1 +1711 49 52 0 +1712 52 52 0 +1713 52 52 1 +1714 52 53 0 +1715 52 53 1 +1716 53 52 0 +1717 53 52 1 +1718 53 53 0 +1719 53 53 1 +1720 55 53 1 +1721 55 53 0 +1722 55 52 1 +1723 55 52 0 +1724 54 53 1 +1725 54 53 0 +1726 54 52 1 +1727 54 52 0 +1728 60 53 0 +1729 60 53 1 +1730 60 52 0 +1731 60 52 1 +1732 61 53 0 +1733 61 53 1 +1734 61 52 0 +1735 61 52 1 +1736 63 52 1 +1737 63 52 0 +1738 63 53 1 +1739 63 53 0 +1740 62 52 1 +1741 62 52 0 +1742 62 53 1 +1743 62 53 0 +1792 59 55 0 +1793 59 55 1 +1794 59 54 0 +1795 59 54 1 +1796 58 55 0 +1797 58 55 1 +1798 58 54 0 +1799 58 54 1 +1800 56 54 1 +1801 56 54 0 +1802 56 55 1 +1803 56 55 0 +1804 57 54 1 +1805 57 54 0 +1806 57 55 1 +1807 57 55 0 +1824 51 54 0 +1825 51 54 1 +1826 51 55 0 +1827 51 55 1 +1828 50 54 0 +1829 50 54 1 +1830 50 55 0 +1831 50 55 1 +1832 48 55 1 +1833 48 55 0 +1834 48 54 1 +1835 48 54 0 +1836 49 55 1 +1837 49 55 0 +1838 49 54 1 +1839 49 54 0 +1840 52 54 0 +1841 52 54 1 +1842 52 55 0 +1843 52 55 1 +1844 53 54 0 +1845 53 54 1 +1846 53 55 0 +1847 53 55 1 +1848 55 55 1 +1849 55 55 0 +1850 55 54 1 +1851 55 54 0 +1852 54 55 1 +1853 54 55 0 +1854 54 54 1 +1855 54 54 0 +1856 60 55 0 +1857 60 55 1 +1858 60 54 0 +1859 60 54 1 +1860 61 55 0 +1861 61 55 1 +1862 61 54 0 +1863 61 54 1 +1864 63 54 1 +1865 63 54 0 +1866 63 55 1 +1867 63 55 0 +1868 62 54 1 +1869 62 54 0 +1870 62 55 1 +1871 62 55 0 +2176 59 27 0 +2177 59 27 1 +2178 59 26 0 +2179 59 26 1 +2180 58 27 0 +2181 58 27 1 +2182 58 26 0 +2183 58 26 1 +2184 56 26 1 +2185 56 26 0 +2186 56 27 1 +2187 56 27 0 +2188 57 26 1 +2189 57 26 0 +2190 57 27 1 +2191 57 27 0 +2208 51 26 0 +2209 51 26 1 +2210 51 27 0 +2211 51 27 1 +2212 50 26 0 +2213 50 26 1 +2214 50 27 0 +2215 50 27 1 +2216 48 27 1 +2217 48 27 0 +2218 48 26 1 +2219 48 26 0 +2220 49 27 1 +2221 49 27 0 +2222 49 26 1 +2223 49 26 0 +2224 52 26 0 +2225 52 26 1 +2226 52 27 0 +2227 52 27 1 +2228 53 26 0 +2229 53 26 1 +2230 53 27 0 +2231 53 27 1 +2232 55 27 1 +2233 55 27 0 +2234 55 26 1 +2235 55 26 0 +2236 54 27 1 +2237 54 27 0 +2238 54 26 1 +2239 54 26 0 +2240 60 27 0 +2241 60 27 1 +2242 60 26 0 +2243 60 26 1 +2244 61 27 0 +2245 61 27 1 +2246 61 26 0 +2247 61 26 1 +2248 63 26 1 +2249 63 26 0 +2250 63 27 1 +2251 63 27 0 +2252 62 26 1 +2253 62 26 0 +2254 62 27 1 +2255 62 27 0 +2304 59 25 0 +2305 59 25 1 +2306 59 24 0 +2307 59 24 1 +2308 58 25 0 +2309 58 25 1 +2310 58 24 0 +2311 58 24 1 +2312 56 24 1 +2313 56 24 0 +2314 56 25 1 +2315 56 25 0 +2316 57 24 1 +2317 57 24 0 +2318 57 25 1 +2319 57 25 0 +2336 51 24 0 +2337 51 24 1 +2338 51 25 0 +2339 51 25 1 +2340 50 24 0 +2341 50 24 1 +2342 50 25 0 +2343 50 25 1 +2344 48 25 1 +2345 48 25 0 +2346 48 24 1 +2347 48 24 0 +2348 49 25 1 +2349 49 25 0 +2350 49 24 1 +2351 49 24 0 +2352 52 24 0 +2353 52 24 1 +2354 52 25 0 +2355 52 25 1 +2356 53 24 0 +2357 53 24 1 +2358 53 25 0 +2359 53 25 1 +2360 55 25 1 +2361 55 25 0 +2362 55 24 1 +2363 55 24 0 +2364 54 25 1 +2365 54 25 0 +2366 54 24 1 +2367 54 24 0 +2368 60 25 0 +2369 60 25 1 +2370 60 24 0 +2371 60 24 1 +2372 61 25 0 +2373 61 25 1 +2374 61 24 0 +2375 61 24 1 +2376 63 24 1 +2377 63 24 0 +2378 63 25 1 +2379 63 25 0 +2380 62 24 1 +2381 62 24 0 +2382 62 25 1 +2383 62 25 0 +2432 59 23 0 +2433 59 23 1 +2434 59 22 0 +2435 59 22 1 +2436 58 23 0 +2437 58 23 1 +2438 58 22 0 +2439 58 22 1 +2440 56 22 1 +2441 56 22 0 +2442 56 23 1 +2443 56 23 0 +2444 57 22 1 +2445 57 22 0 +2446 57 23 1 +2447 57 23 0 +2464 51 22 0 +2465 51 22 1 +2466 51 23 0 +2467 51 23 1 +2468 50 22 0 +2469 50 22 1 +2470 50 23 0 +2471 50 23 1 +2472 48 23 1 +2473 48 23 0 +2474 48 22 1 +2475 48 22 0 +2476 49 23 1 +2477 49 23 0 +2478 49 22 1 +2479 49 22 0 +2480 52 22 0 +2481 52 22 1 +2482 52 23 0 +2483 52 23 1 +2484 53 22 0 +2485 53 22 1 +2486 53 23 0 +2487 53 23 1 +2488 55 23 1 +2489 55 23 0 +2490 55 22 1 +2491 55 22 0 +2492 54 23 1 +2493 54 23 0 +2494 54 22 1 +2495 54 22 0 +2496 60 23 0 +2497 60 23 1 +2498 60 22 0 +2499 60 22 1 +2500 61 23 0 +2501 61 23 1 +2502 61 22 0 +2503 61 22 1 +2504 63 22 1 +2505 63 22 0 +2506 63 23 1 +2507 63 23 0 +2508 62 22 1 +2509 62 22 0 +2510 62 23 1 +2511 62 23 0 +2560 59 21 0 +2561 59 21 1 +2562 59 20 0 +2563 59 20 1 +2564 58 21 0 +2565 58 21 1 +2566 58 20 0 +2567 58 20 1 +2568 56 20 1 +2569 56 20 0 +2570 56 21 1 +2571 56 21 0 +2572 57 20 1 +2573 57 20 0 +2574 57 21 1 +2575 57 21 0 +2592 51 20 0 +2593 51 20 1 +2594 51 21 0 +2595 51 21 1 +2596 50 20 0 +2597 50 20 1 +2598 50 21 0 +2599 50 21 1 +2600 48 21 1 +2601 48 21 0 +2602 48 20 1 +2603 48 20 0 +2604 49 21 1 +2605 49 21 0 +2606 49 20 1 +2607 49 20 0 +2608 52 20 0 +2609 52 20 1 +2610 52 21 0 +2611 52 21 1 +2612 53 20 0 +2613 53 20 1 +2614 53 21 0 +2615 53 21 1 +2616 55 21 1 +2617 55 21 0 +2618 55 20 1 +2619 55 20 0 +2620 54 21 1 +2621 54 21 0 +2622 54 20 1 +2623 54 20 0 +2624 60 21 0 +2625 60 21 1 +2626 60 20 0 +2627 60 20 1 +2628 61 21 0 +2629 61 21 1 +2630 61 20 0 +2631 61 20 1 +2632 63 20 1 +2633 63 20 0 +2634 63 21 1 +2635 63 21 0 +2636 62 20 1 +2637 62 20 0 +2638 62 21 1 +2639 62 21 0 +2688 59 19 0 +2689 59 19 1 +2690 59 18 0 +2691 59 18 1 +2692 58 19 0 +2693 58 19 1 +2694 58 18 0 +2695 58 18 1 +2696 56 18 1 +2697 56 18 0 +2698 56 19 1 +2699 56 19 0 +2700 57 18 1 +2701 57 18 0 +2702 57 19 1 +2703 57 19 0 +2720 51 18 0 +2721 51 18 1 +2722 51 19 0 +2723 51 19 1 +2724 50 18 0 +2725 50 18 1 +2726 50 19 0 +2727 50 19 1 +2728 48 19 1 +2729 48 19 0 +2730 48 18 1 +2731 48 18 0 +2732 49 19 1 +2733 49 19 0 +2734 49 18 1 +2735 49 18 0 +2736 52 18 0 +2737 52 18 1 +2738 52 19 0 +2739 52 19 1 +2740 53 18 0 +2741 53 18 1 +2742 53 19 0 +2743 53 19 1 +2744 55 19 1 +2745 55 19 0 +2746 55 18 1 +2747 55 18 0 +2748 54 19 1 +2749 54 19 0 +2750 54 18 1 +2751 54 18 0 +2752 60 19 0 +2753 60 19 1 +2754 60 18 0 +2755 60 18 1 +2756 61 19 0 +2757 61 19 1 +2758 61 18 0 +2759 61 18 1 +2760 63 18 1 +2761 63 18 0 +2762 63 19 1 +2763 63 19 0 +2764 62 18 1 +2765 62 18 0 +2766 62 19 1 +2767 62 19 0 +2816 59 17 0 +2817 59 17 1 +2818 59 16 0 +2819 59 16 1 +2820 58 17 0 +2821 58 17 1 +2822 58 16 0 +2823 58 16 1 +2824 56 16 1 +2825 56 16 0 +2826 56 17 1 +2827 56 17 0 +2828 57 16 1 +2829 57 16 0 +2830 57 17 1 +2831 57 17 0 +2848 51 16 0 +2849 51 16 1 +2850 51 17 0 +2851 51 17 1 +2852 50 16 0 +2853 50 16 1 +2854 50 17 0 +2855 50 17 1 +2856 48 17 1 +2857 48 17 0 +2858 48 16 1 +2859 48 16 0 +2860 49 17 1 +2861 49 17 0 +2862 49 16 1 +2863 49 16 0 +2864 52 16 0 +2865 52 16 1 +2866 52 17 0 +2867 52 17 1 +2868 53 16 0 +2869 53 16 1 +2870 53 17 0 +2871 53 17 1 +2872 55 17 1 +2873 55 17 0 +2874 55 16 1 +2875 55 16 0 +2876 54 17 1 +2877 54 17 0 +2878 54 16 1 +2879 54 16 0 +2880 60 17 0 +2881 60 17 1 +2882 60 16 0 +2883 60 16 1 +2884 61 17 0 +2885 61 17 1 +2886 61 16 0 +2887 61 16 1 +2888 63 16 1 +2889 63 16 0 +2890 63 17 1 +2891 63 17 0 +2892 62 16 1 +2893 62 16 0 +2894 62 17 1 +2895 62 17 0 +2944 59 15 0 +2945 59 15 1 +2946 59 14 0 +2947 59 14 1 +2948 58 15 0 +2949 58 15 1 +2950 58 14 0 +2951 58 14 1 +2952 56 14 1 +2953 56 14 0 +2954 56 15 1 +2955 56 15 0 +2956 57 14 1 +2957 57 14 0 +2958 57 15 1 +2959 57 15 0 +2976 51 14 0 +2977 51 14 1 +2978 51 15 0 +2979 51 15 1 +2980 50 14 0 +2981 50 14 1 +2982 50 15 0 +2983 50 15 1 +2984 48 15 1 +2985 48 15 0 +2986 48 14 1 +2987 48 14 0 +2988 49 15 1 +2989 49 15 0 +2990 49 14 1 +2991 49 14 0 +2992 52 14 0 +2993 52 14 1 +2994 52 15 0 +2995 52 15 1 +2996 53 14 0 +2997 53 14 1 +2998 53 15 0 +2999 53 15 1 +3000 55 15 1 +3001 55 15 0 +3002 55 14 1 +3003 55 14 0 +3004 54 15 1 +3005 54 15 0 +3006 54 14 1 +3007 54 14 0 +3008 60 15 0 +3009 60 15 1 +3010 60 14 0 +3011 60 14 1 +3012 61 15 0 +3013 61 15 1 +3014 61 14 0 +3015 61 14 1 +3016 63 14 1 +3017 63 14 0 +3018 63 15 1 +3019 63 15 0 +3020 62 14 1 +3021 62 14 0 +3022 62 15 1 +3023 62 15 0 +3072 59 13 0 +3073 59 13 1 +3074 59 12 0 +3075 59 12 1 +3076 58 13 0 +3077 58 13 1 +3078 58 12 0 +3079 58 12 1 +3080 56 12 1 +3081 56 12 0 +3082 56 13 1 +3083 56 13 0 +3084 57 12 1 +3085 57 12 0 +3086 57 13 1 +3087 57 13 0 +3104 51 12 0 +3105 51 12 1 +3106 51 13 0 +3107 51 13 1 +3108 50 12 0 +3109 50 12 1 +3110 50 13 0 +3111 50 13 1 +3112 48 13 1 +3113 48 13 0 +3114 48 12 1 +3115 48 12 0 +3116 49 13 1 +3117 49 13 0 +3118 49 12 1 +3119 49 12 0 +3120 52 12 0 +3121 52 12 1 +3122 52 13 0 +3123 52 13 1 +3124 53 12 0 +3125 53 12 1 +3126 53 13 0 +3127 53 13 1 +3128 55 13 1 +3129 55 13 0 +3130 55 12 1 +3131 55 12 0 +3132 54 13 1 +3133 54 13 0 +3134 54 12 1 +3135 54 12 0 +3136 60 13 0 +3137 60 13 1 +3138 60 12 0 +3139 60 12 1 +3140 61 13 0 +3141 61 13 1 +3142 61 12 0 +3143 61 12 1 +3144 63 12 1 +3145 63 12 0 +3146 63 13 1 +3147 63 13 0 +3148 62 12 1 +3149 62 12 0 +3150 62 13 1 +3151 62 13 0 +3200 59 11 0 +3201 59 11 1 +3202 59 10 0 +3203 59 10 1 +3204 58 11 0 +3205 58 11 1 +3206 58 10 0 +3207 58 10 1 +3208 56 10 1 +3209 56 10 0 +3210 56 11 1 +3211 56 11 0 +3212 57 10 1 +3213 57 10 0 +3214 57 11 1 +3215 57 11 0 +3232 51 10 0 +3233 51 10 1 +3234 51 11 0 +3235 51 11 1 +3236 50 10 0 +3237 50 10 1 +3238 50 11 0 +3239 50 11 1 +3240 48 11 1 +3241 48 11 0 +3242 48 10 1 +3243 48 10 0 +3244 49 11 1 +3245 49 11 0 +3246 49 10 1 +3247 49 10 0 +3248 52 10 0 +3249 52 10 1 +3250 52 11 0 +3251 52 11 1 +3252 53 10 0 +3253 53 10 1 +3254 53 11 0 +3255 53 11 1 +3256 55 11 1 +3257 55 11 0 +3258 55 10 1 +3259 55 10 0 +3260 54 11 1 +3261 54 11 0 +3262 54 10 1 +3263 54 10 0 +3264 60 11 0 +3265 60 11 1 +3266 60 10 0 +3267 60 10 1 +3268 61 11 0 +3269 61 11 1 +3270 61 10 0 +3271 61 10 1 +3272 63 10 1 +3273 63 10 0 +3274 63 11 1 +3275 63 11 0 +3276 62 10 1 +3277 62 10 0 +3278 62 11 1 +3279 62 11 0 +3328 59 9 0 +3329 59 9 1 +3330 59 8 0 +3331 59 8 1 +3332 58 9 0 +3333 58 9 1 +3334 58 8 0 +3335 58 8 1 +3336 56 8 1 +3337 56 8 0 +3338 56 9 1 +3339 56 9 0 +3340 57 8 1 +3341 57 8 0 +3342 57 9 1 +3343 57 9 0 +3360 51 8 0 +3361 51 8 1 +3362 51 9 0 +3363 51 9 1 +3364 50 8 0 +3365 50 8 1 +3366 50 9 0 +3367 50 9 1 +3368 48 9 1 +3369 48 9 0 +3370 48 8 1 +3371 48 8 0 +3372 49 9 1 +3373 49 9 0 +3374 49 8 1 +3375 49 8 0 +3376 52 8 0 +3377 52 8 1 +3378 52 9 0 +3379 52 9 1 +3380 53 8 0 +3381 53 8 1 +3382 53 9 0 +3383 53 9 1 +3384 55 9 1 +3385 55 9 0 +3386 55 8 1 +3387 55 8 0 +3388 54 9 1 +3389 54 9 0 +3390 54 8 1 +3391 54 8 0 +3392 60 9 0 +3393 60 9 1 +3394 60 8 0 +3395 60 8 1 +3396 61 9 0 +3397 61 9 1 +3398 61 8 0 +3399 61 8 1 +3400 63 8 1 +3401 63 8 0 +3402 63 9 1 +3403 63 9 0 +3404 62 8 1 +3405 62 8 0 +3406 62 9 1 +3407 62 9 0 +3456 59 7 0 +3457 59 7 1 +3458 59 6 0 +3459 59 6 1 +3460 58 7 0 +3461 58 7 1 +3462 58 6 0 +3463 58 6 1 +3464 56 6 1 +3465 56 6 0 +3466 56 7 1 +3467 56 7 0 +3468 57 6 1 +3469 57 6 0 +3470 57 7 1 +3471 57 7 0 +3488 51 6 0 +3489 51 6 1 +3490 51 7 0 +3491 51 7 1 +3492 50 6 0 +3493 50 6 1 +3494 50 7 0 +3495 50 7 1 +3496 48 7 1 +3497 48 7 0 +3498 48 6 1 +3499 48 6 0 +3500 49 7 1 +3501 49 7 0 +3502 49 6 1 +3503 49 6 0 +3504 52 6 0 +3505 52 6 1 +3506 52 7 0 +3507 52 7 1 +3508 53 6 0 +3509 53 6 1 +3510 53 7 0 +3511 53 7 1 +3512 55 7 1 +3513 55 7 0 +3514 55 6 1 +3515 55 6 0 +3516 54 7 1 +3517 54 7 0 +3518 54 6 1 +3519 54 6 0 +3520 60 7 0 +3521 60 7 1 +3522 60 6 0 +3523 60 6 1 +3524 61 7 0 +3525 61 7 1 +3526 61 6 0 +3527 61 6 1 +3528 63 6 1 +3529 63 6 0 +3530 63 7 1 +3531 63 7 0 +3532 62 6 1 +3533 62 6 0 +3534 62 7 1 +3535 62 7 0 +3584 59 5 0 +3585 59 5 1 +3586 59 4 0 +3587 59 4 1 +3588 58 5 0 +3589 58 5 1 +3590 58 4 0 +3591 58 4 1 +3592 56 4 1 +3593 56 4 0 +3594 56 5 1 +3595 56 5 0 +3596 57 4 1 +3597 57 4 0 +3598 57 5 1 +3599 57 5 0 +3616 51 4 0 +3617 51 4 1 +3618 51 5 0 +3619 51 5 1 +3620 50 4 0 +3621 50 4 1 +3622 50 5 0 +3623 50 5 1 +3624 48 5 1 +3625 48 5 0 +3626 48 4 1 +3627 48 4 0 +3628 49 5 1 +3629 49 5 0 +3630 49 4 1 +3631 49 4 0 +3632 52 4 0 +3633 52 4 1 +3634 52 5 0 +3635 52 5 1 +3636 53 4 0 +3637 53 4 1 +3638 53 5 0 +3639 53 5 1 +3640 55 5 1 +3641 55 5 0 +3642 55 4 1 +3643 55 4 0 +3644 54 5 1 +3645 54 5 0 +3646 54 4 1 +3647 54 4 0 +3648 60 5 0 +3649 60 5 1 +3650 60 4 0 +3651 60 4 1 +3652 61 5 0 +3653 61 5 1 +3654 61 4 0 +3655 61 4 1 +3656 63 4 1 +3657 63 4 0 +3658 63 5 1 +3659 63 5 0 +3660 62 4 1 +3661 62 4 0 +3662 62 5 1 +3663 62 5 0 +3712 59 3 0 +3713 59 3 1 +3714 59 2 0 +3715 59 2 1 +3716 58 3 0 +3717 58 3 1 +3718 58 2 0 +3719 58 2 1 +3720 56 2 1 +3721 56 2 0 +3722 56 3 1 +3723 56 3 0 +3724 57 2 1 +3725 57 2 0 +3726 57 3 1 +3727 57 3 0 +3744 51 2 0 +3745 51 2 1 +3746 51 3 0 +3747 51 3 1 +3748 50 2 0 +3749 50 2 1 +3750 50 3 0 +3751 50 3 1 +3752 48 3 1 +3753 48 3 0 +3754 48 2 1 +3755 48 2 0 +3756 49 3 1 +3757 49 3 0 +3758 49 2 1 +3759 49 2 0 +3760 52 2 0 +3761 52 2 1 +3762 52 3 0 +3763 52 3 1 +3764 53 2 0 +3765 53 2 1 +3766 53 3 0 +3767 53 3 1 +3768 55 3 1 +3769 55 3 0 +3770 55 2 1 +3771 55 2 0 +3772 54 3 1 +3773 54 3 0 +3774 54 2 1 +3775 54 2 0 +3776 60 3 0 +3777 60 3 1 +3778 60 2 0 +3779 60 2 1 +3780 61 3 0 +3781 61 3 1 +3782 61 2 0 +3783 61 2 1 +3784 63 2 1 +3785 63 2 0 +3786 63 3 1 +3787 63 3 0 +3788 62 2 1 +3789 62 2 0 +3790 62 3 1 +3791 62 3 0 +3840 59 1 0 +3841 59 1 1 +3842 59 0 0 +3843 59 0 1 +3844 58 1 0 +3845 58 1 1 +3846 58 0 0 +3847 58 0 1 +3848 56 0 1 +3849 56 0 0 +3850 56 1 1 +3851 56 1 0 +3852 57 0 1 +3853 57 0 0 +3854 57 1 1 +3855 57 1 0 +3872 51 0 0 +3873 51 0 1 +3874 51 1 0 +3875 51 1 1 +3876 50 0 0 +3877 50 0 1 +3878 50 1 0 +3879 50 1 1 +3880 48 1 1 +3881 48 1 0 +3882 48 0 1 +3883 48 0 0 +3884 49 1 1 +3885 49 1 0 +3886 49 0 1 +3887 49 0 0 +3888 52 0 0 +3889 52 0 1 +3890 52 1 0 +3891 52 1 1 +3892 53 0 0 +3893 53 0 1 +3894 53 1 0 +3895 53 1 1 +3896 55 1 1 +3897 55 1 0 +3898 55 0 1 +3899 55 0 0 +3900 54 1 1 +3901 54 1 0 +3902 54 0 1 +3903 54 0 0 +3904 60 1 0 +3905 60 1 1 +3906 60 0 0 +3907 60 0 1 +3908 61 1 0 +3909 61 1 1 +3910 61 0 0 +3911 61 0 1 +3912 63 0 1 +3913 63 0 0 +3914 63 1 1 +3915 63 1 0 +3916 62 0 1 +3917 62 0 0 +3918 62 1 1 +3919 62 1 0 diff --git a/Detectors/PHOS/base/files/Mod1RCU0.data b/Detectors/PHOS/base/files/Mod1RCU0.data new file mode 100644 index 0000000000000..4739df6e3e61e --- /dev/null +++ b/Detectors/PHOS/base/files/Mod1RCU0.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 0 0 2 + 1 0 1 2 + 2 0 2 2 + 3 0 3 2 + 4 0 4 2 + 5 0 5 2 + 6 0 6 2 + 7 0 7 2 + 8 0 8 2 + 9 0 9 2 + 10 0 10 2 + 11 0 11 2 + 12 0 12 2 + 13 0 13 2 + 14 0 14 2 + 15 0 15 2 + 16 0 16 2 + 17 0 17 2 + 18 0 18 2 + 19 0 19 2 + 20 0 20 2 + 21 0 21 2 + 22 0 22 2 + 23 0 23 2 + 24 0 24 2 + 25 0 25 2 + 26 0 26 2 + 27 0 27 2 + 28 0 28 2 + 29 0 29 2 + 30 0 30 2 + 31 0 31 2 + 32 0 32 2 + 33 0 33 2 + 34 0 34 2 + 35 0 35 2 + 36 0 36 2 + 37 0 37 2 + 38 0 38 2 + 39 0 39 2 + 40 0 40 2 + 41 0 41 2 + 42 0 42 2 + 43 0 43 2 + 44 0 44 2 + 45 0 45 2 + 46 0 46 2 + 47 0 47 2 + 48 0 48 2 + 49 0 49 2 + 50 0 50 2 + 51 0 51 2 + 52 0 52 2 + 53 0 53 2 + 54 0 54 2 + 55 0 55 2 + 56 0 56 2 + 57 0 57 2 + 58 0 58 2 + 59 0 59 2 + 60 0 60 2 + 61 0 61 2 + 62 0 62 2 + 63 0 63 2 + 64 0 64 2 + 65 0 65 2 + 66 0 66 2 + 67 0 67 2 + 68 0 68 2 + 69 0 69 2 + 70 0 70 2 + 71 0 71 2 + 72 0 72 2 + 73 0 73 2 + 74 0 74 2 + 75 0 75 2 + 76 0 76 2 + 77 0 77 2 + 78 0 78 2 + 79 0 79 2 + 80 0 80 2 + 81 0 81 2 + 82 0 82 2 + 83 0 83 2 + 84 0 84 2 + 85 0 85 2 + 86 0 86 2 + 87 0 87 2 + 88 0 88 2 + 89 0 89 2 + 90 0 90 2 + 91 0 91 2 + 92 0 92 2 + 93 0 93 2 + 94 0 94 2 + 95 0 95 2 + 96 0 96 2 + 97 0 97 2 + 98 0 98 2 + 99 0 99 2 + 100 0 100 2 + 101 0 101 2 + 102 0 102 2 + 103 0 103 2 + 104 0 104 2 + 105 0 105 2 + 106 0 106 2 + 107 0 107 2 + 108 0 108 2 + 109 0 109 2 + 110 0 110 2 + 111 0 111 2 + 112 0 112 2 + 113 0 113 2 + 114 0 114 2 + 115 0 115 2 + 116 0 116 2 + 117 0 117 2 + 118 0 118 2 + 119 0 119 2 + 120 0 120 2 + 121 0 121 2 + 122 0 122 2 + 123 0 123 2 + 124 0 124 2 + 125 0 125 2 + 126 0 126 2 + 127 0 127 2 +2048 0 2048 2 +2049 0 2049 2 +2050 0 2050 2 +2051 0 2051 2 +2052 0 2052 2 +2053 0 2053 2 +2054 0 2054 2 +2055 0 2055 2 +2056 0 2056 2 +2057 0 2057 2 +2058 0 2058 2 +2059 0 2059 2 +2060 0 2060 2 +2061 0 2061 2 +2062 0 2062 2 +2063 0 2063 2 +2064 0 2064 2 +2065 0 2065 2 +2066 0 2066 2 +2067 0 2067 2 +2068 0 2068 2 +2069 0 2069 2 +2070 0 2070 2 +2071 0 2071 2 +2072 0 2072 2 +2073 0 2073 2 +2074 0 2074 2 +2075 0 2075 2 +2076 0 2076 2 +2077 0 2077 2 +2078 0 2078 2 +2079 0 2079 2 +2080 0 2080 2 +2081 0 2081 2 +2082 0 2082 2 +2083 0 2083 2 +2084 0 2084 2 +2085 0 2085 2 +2086 0 2086 2 +2087 0 2087 2 +2088 0 2088 2 +2089 0 2089 2 +2090 0 2090 2 +2091 0 2091 2 +2092 0 2092 2 +2093 0 2093 2 +2094 0 2094 2 +2095 0 2095 2 +2096 0 2096 2 +2097 0 2097 2 +2098 0 2098 2 +2099 0 2099 2 +2100 0 2100 2 +2101 0 2101 2 +2102 0 2102 2 +2103 0 2103 2 +2104 0 2104 2 +2105 0 2105 2 +2106 0 2106 2 +2107 0 2107 2 +2108 0 2108 2 +2109 0 2109 2 +2110 0 2110 2 +2111 0 2111 2 +2112 0 2112 2 +2113 0 2113 2 +2114 0 2114 2 +2115 0 2115 2 +2116 0 2116 2 +2117 0 2117 2 +2118 0 2118 2 +2119 0 2119 2 +2120 0 2120 2 +2121 0 2121 2 +2122 0 2122 2 +2123 0 2123 2 +2124 0 2124 2 +2125 0 2125 2 +2126 0 2126 2 +2127 0 2127 2 +2128 0 2128 2 +2129 0 2129 2 +2130 0 2130 2 +2131 0 2131 2 +2132 0 2132 2 +2133 0 2133 2 +2134 0 2134 2 +2135 0 2135 2 +2136 0 2136 2 +2137 0 2137 2 +2138 0 2138 2 +2139 0 2139 2 +2140 0 2140 2 +2141 0 2141 2 +2142 0 2142 2 +2143 0 2143 2 +2144 0 2144 2 +2145 0 2145 2 +2146 0 2146 2 +2147 0 2147 2 +2148 0 2148 2 +2149 0 2149 2 +2150 0 2150 2 +2151 0 2151 2 +2152 0 2152 2 +2153 0 2153 2 +2154 0 2154 2 +2155 0 2155 2 +2156 0 2156 2 +2157 0 2157 2 +2158 0 2158 2 +2159 0 2159 2 +2160 0 2160 2 +2161 0 2161 2 +2162 0 2162 2 +2163 0 2163 2 +2164 0 2164 2 +2165 0 2165 2 +2166 0 2166 2 +2167 0 2167 2 +2168 0 2168 2 +2169 0 2169 2 +2170 0 2170 2 +2171 0 2171 2 +2172 0 2172 2 +2173 0 2173 2 +2174 0 2174 2 +2175 0 2175 2 + 128 11 29 0 + 129 11 29 1 + 130 11 28 0 + 131 11 28 1 + 132 10 29 0 + 133 10 29 1 + 134 10 28 0 + 135 10 28 1 + 136 8 28 1 + 137 8 28 0 + 138 8 29 1 + 139 8 29 0 + 140 9 28 1 + 141 9 28 0 + 142 9 29 1 + 143 9 29 0 + 160 3 28 0 + 161 3 28 1 + 162 3 29 0 + 163 3 29 1 + 164 2 28 0 + 165 2 28 1 + 166 2 29 0 + 167 2 29 1 + 168 0 29 1 + 169 0 29 0 + 170 0 28 1 + 171 0 28 0 + 172 1 29 1 + 173 1 29 0 + 174 1 28 1 + 175 1 28 0 + 176 4 28 0 + 177 4 28 1 + 178 4 29 0 + 179 4 29 1 + 180 5 28 0 + 181 5 28 1 + 182 5 29 0 + 183 5 29 1 + 184 7 29 1 + 185 7 29 0 + 186 7 28 1 + 187 7 28 0 + 188 6 29 1 + 189 6 29 0 + 190 6 28 1 + 191 6 28 0 + 192 12 29 0 + 193 12 29 1 + 194 12 28 0 + 195 12 28 1 + 196 13 29 0 + 197 13 29 1 + 198 13 28 0 + 199 13 28 1 + 200 15 28 1 + 201 15 28 0 + 202 15 29 1 + 203 15 29 0 + 204 14 28 1 + 205 14 28 0 + 206 14 29 1 + 207 14 29 0 + 256 11 31 0 + 257 11 31 1 + 258 11 30 0 + 259 11 30 1 + 260 10 31 0 + 261 10 31 1 + 262 10 30 0 + 263 10 30 1 + 264 8 30 1 + 265 8 30 0 + 266 8 31 1 + 267 8 31 0 + 268 9 30 1 + 269 9 30 0 + 270 9 31 1 + 271 9 31 0 + 288 3 30 0 + 289 3 30 1 + 290 3 31 0 + 291 3 31 1 + 292 2 30 0 + 293 2 30 1 + 294 2 31 0 + 295 2 31 1 + 296 0 31 1 + 297 0 31 0 + 298 0 30 1 + 299 0 30 0 + 300 1 31 1 + 301 1 31 0 + 302 1 30 1 + 303 1 30 0 + 304 4 30 0 + 305 4 30 1 + 306 4 31 0 + 307 4 31 1 + 308 5 30 0 + 309 5 30 1 + 310 5 31 0 + 311 5 31 1 + 312 7 31 1 + 313 7 31 0 + 314 7 30 1 + 315 7 30 0 + 316 6 31 1 + 317 6 31 0 + 318 6 30 1 + 319 6 30 0 + 320 12 31 0 + 321 12 31 1 + 322 12 30 0 + 323 12 30 1 + 324 13 31 0 + 325 13 31 1 + 326 13 30 0 + 327 13 30 1 + 328 15 30 1 + 329 15 30 0 + 330 15 31 1 + 331 15 31 0 + 332 14 30 1 + 333 14 30 0 + 334 14 31 1 + 335 14 31 0 + 384 11 33 0 + 385 11 33 1 + 386 11 32 0 + 387 11 32 1 + 388 10 33 0 + 389 10 33 1 + 390 10 32 0 + 391 10 32 1 + 392 8 32 1 + 393 8 32 0 + 394 8 33 1 + 395 8 33 0 + 396 9 32 1 + 397 9 32 0 + 398 9 33 1 + 399 9 33 0 + 416 3 32 0 + 417 3 32 1 + 418 3 33 0 + 419 3 33 1 + 420 2 32 0 + 421 2 32 1 + 422 2 33 0 + 423 2 33 1 + 424 0 33 1 + 425 0 33 0 + 426 0 32 1 + 427 0 32 0 + 428 1 33 1 + 429 1 33 0 + 430 1 32 1 + 431 1 32 0 + 432 4 32 0 + 433 4 32 1 + 434 4 33 0 + 435 4 33 1 + 436 5 32 0 + 437 5 32 1 + 438 5 33 0 + 439 5 33 1 + 440 7 33 1 + 441 7 33 0 + 442 7 32 1 + 443 7 32 0 + 444 6 33 1 + 445 6 33 0 + 446 6 32 1 + 447 6 32 0 + 448 12 33 0 + 449 12 33 1 + 450 12 32 0 + 451 12 32 1 + 452 13 33 0 + 453 13 33 1 + 454 13 32 0 + 455 13 32 1 + 456 15 32 1 + 457 15 32 0 + 458 15 33 1 + 459 15 33 0 + 460 14 32 1 + 461 14 32 0 + 462 14 33 1 + 463 14 33 0 + 512 11 35 0 + 513 11 35 1 + 514 11 34 0 + 515 11 34 1 + 516 10 35 0 + 517 10 35 1 + 518 10 34 0 + 519 10 34 1 + 520 8 34 1 + 521 8 34 0 + 522 8 35 1 + 523 8 35 0 + 524 9 34 1 + 525 9 34 0 + 526 9 35 1 + 527 9 35 0 + 544 3 34 0 + 545 3 34 1 + 546 3 35 0 + 547 3 35 1 + 548 2 34 0 + 549 2 34 1 + 550 2 35 0 + 551 2 35 1 + 552 0 35 1 + 553 0 35 0 + 554 0 34 1 + 555 0 34 0 + 556 1 35 1 + 557 1 35 0 + 558 1 34 1 + 559 1 34 0 + 560 4 34 0 + 561 4 34 1 + 562 4 35 0 + 563 4 35 1 + 564 5 34 0 + 565 5 34 1 + 566 5 35 0 + 567 5 35 1 + 568 7 35 1 + 569 7 35 0 + 570 7 34 1 + 571 7 34 0 + 572 6 35 1 + 573 6 35 0 + 574 6 34 1 + 575 6 34 0 + 576 12 35 0 + 577 12 35 1 + 578 12 34 0 + 579 12 34 1 + 580 13 35 0 + 581 13 35 1 + 582 13 34 0 + 583 13 34 1 + 584 15 34 1 + 585 15 34 0 + 586 15 35 1 + 587 15 35 0 + 588 14 34 1 + 589 14 34 0 + 590 14 35 1 + 591 14 35 0 + 640 11 37 0 + 641 11 37 1 + 642 11 36 0 + 643 11 36 1 + 644 10 37 0 + 645 10 37 1 + 646 10 36 0 + 647 10 36 1 + 648 8 36 1 + 649 8 36 0 + 650 8 37 1 + 651 8 37 0 + 652 9 36 1 + 653 9 36 0 + 654 9 37 1 + 655 9 37 0 + 672 3 36 0 + 673 3 36 1 + 674 3 37 0 + 675 3 37 1 + 676 2 36 0 + 677 2 36 1 + 678 2 37 0 + 679 2 37 1 + 680 0 37 1 + 681 0 37 0 + 682 0 36 1 + 683 0 36 0 + 684 1 37 1 + 685 1 37 0 + 686 1 36 1 + 687 1 36 0 + 688 4 36 0 + 689 4 36 1 + 690 4 37 0 + 691 4 37 1 + 692 5 36 0 + 693 5 36 1 + 694 5 37 0 + 695 5 37 1 + 696 7 37 1 + 697 7 37 0 + 698 7 36 1 + 699 7 36 0 + 700 6 37 1 + 701 6 37 0 + 702 6 36 1 + 703 6 36 0 + 704 12 37 0 + 705 12 37 1 + 706 12 36 0 + 707 12 36 1 + 708 13 37 0 + 709 13 37 1 + 710 13 36 0 + 711 13 36 1 + 712 15 36 1 + 713 15 36 0 + 714 15 37 1 + 715 15 37 0 + 716 14 36 1 + 717 14 36 0 + 718 14 37 1 + 719 14 37 0 + 768 11 39 0 + 769 11 39 1 + 770 11 38 0 + 771 11 38 1 + 772 10 39 0 + 773 10 39 1 + 774 10 38 0 + 775 10 38 1 + 776 8 38 1 + 777 8 38 0 + 778 8 39 1 + 779 8 39 0 + 780 9 38 1 + 781 9 38 0 + 782 9 39 1 + 783 9 39 0 + 800 3 38 0 + 801 3 38 1 + 802 3 39 0 + 803 3 39 1 + 804 2 38 0 + 805 2 38 1 + 806 2 39 0 + 807 2 39 1 + 808 0 39 1 + 809 0 39 0 + 810 0 38 1 + 811 0 38 0 + 812 1 39 1 + 813 1 39 0 + 814 1 38 1 + 815 1 38 0 + 816 4 38 0 + 817 4 38 1 + 818 4 39 0 + 819 4 39 1 + 820 5 38 0 + 821 5 38 1 + 822 5 39 0 + 823 5 39 1 + 824 7 39 1 + 825 7 39 0 + 826 7 38 1 + 827 7 38 0 + 828 6 39 1 + 829 6 39 0 + 830 6 38 1 + 831 6 38 0 + 832 12 39 0 + 833 12 39 1 + 834 12 38 0 + 835 12 38 1 + 836 13 39 0 + 837 13 39 1 + 838 13 38 0 + 839 13 38 1 + 840 15 38 1 + 841 15 38 0 + 842 15 39 1 + 843 15 39 0 + 844 14 38 1 + 845 14 38 0 + 846 14 39 1 + 847 14 39 0 + 896 11 41 0 + 897 11 41 1 + 898 11 40 0 + 899 11 40 1 + 900 10 41 0 + 901 10 41 1 + 902 10 40 0 + 903 10 40 1 + 904 8 40 1 + 905 8 40 0 + 906 8 41 1 + 907 8 41 0 + 908 9 40 1 + 909 9 40 0 + 910 9 41 1 + 911 9 41 0 + 928 3 40 0 + 929 3 40 1 + 930 3 41 0 + 931 3 41 1 + 932 2 40 0 + 933 2 40 1 + 934 2 41 0 + 935 2 41 1 + 936 0 41 1 + 937 0 41 0 + 938 0 40 1 + 939 0 40 0 + 940 1 41 1 + 941 1 41 0 + 942 1 40 1 + 943 1 40 0 + 944 4 40 0 + 945 4 40 1 + 946 4 41 0 + 947 4 41 1 + 948 5 40 0 + 949 5 40 1 + 950 5 41 0 + 951 5 41 1 + 952 7 41 1 + 953 7 41 0 + 954 7 40 1 + 955 7 40 0 + 956 6 41 1 + 957 6 41 0 + 958 6 40 1 + 959 6 40 0 + 960 12 41 0 + 961 12 41 1 + 962 12 40 0 + 963 12 40 1 + 964 13 41 0 + 965 13 41 1 + 966 13 40 0 + 967 13 40 1 + 968 15 40 1 + 969 15 40 0 + 970 15 41 1 + 971 15 41 0 + 972 14 40 1 + 973 14 40 0 + 974 14 41 1 + 975 14 41 0 +1024 11 43 0 +1025 11 43 1 +1026 11 42 0 +1027 11 42 1 +1028 10 43 0 +1029 10 43 1 +1030 10 42 0 +1031 10 42 1 +1032 8 42 1 +1033 8 42 0 +1034 8 43 1 +1035 8 43 0 +1036 9 42 1 +1037 9 42 0 +1038 9 43 1 +1039 9 43 0 +1056 3 42 0 +1057 3 42 1 +1058 3 43 0 +1059 3 43 1 +1060 2 42 0 +1061 2 42 1 +1062 2 43 0 +1063 2 43 1 +1064 0 43 1 +1065 0 43 0 +1066 0 42 1 +1067 0 42 0 +1068 1 43 1 +1069 1 43 0 +1070 1 42 1 +1071 1 42 0 +1072 4 42 0 +1073 4 42 1 +1074 4 43 0 +1075 4 43 1 +1076 5 42 0 +1077 5 42 1 +1078 5 43 0 +1079 5 43 1 +1080 7 43 1 +1081 7 43 0 +1082 7 42 1 +1083 7 42 0 +1084 6 43 1 +1085 6 43 0 +1086 6 42 1 +1087 6 42 0 +1088 12 43 0 +1089 12 43 1 +1090 12 42 0 +1091 12 42 1 +1092 13 43 0 +1093 13 43 1 +1094 13 42 0 +1095 13 42 1 +1096 15 42 1 +1097 15 42 0 +1098 15 43 1 +1099 15 43 0 +1100 14 42 1 +1101 14 42 0 +1102 14 43 1 +1103 14 43 0 +1152 11 45 0 +1153 11 45 1 +1154 11 44 0 +1155 11 44 1 +1156 10 45 0 +1157 10 45 1 +1158 10 44 0 +1159 10 44 1 +1160 8 44 1 +1161 8 44 0 +1162 8 45 1 +1163 8 45 0 +1164 9 44 1 +1165 9 44 0 +1166 9 45 1 +1167 9 45 0 +1184 3 44 0 +1185 3 44 1 +1186 3 45 0 +1187 3 45 1 +1188 2 44 0 +1189 2 44 1 +1190 2 45 0 +1191 2 45 1 +1192 0 45 1 +1193 0 45 0 +1194 0 44 1 +1195 0 44 0 +1196 1 45 1 +1197 1 45 0 +1198 1 44 1 +1199 1 44 0 +1200 4 44 0 +1201 4 44 1 +1202 4 45 0 +1203 4 45 1 +1204 5 44 0 +1205 5 44 1 +1206 5 45 0 +1207 5 45 1 +1208 7 45 1 +1209 7 45 0 +1210 7 44 1 +1211 7 44 0 +1212 6 45 1 +1213 6 45 0 +1214 6 44 1 +1215 6 44 0 +1216 12 45 0 +1217 12 45 1 +1218 12 44 0 +1219 12 44 1 +1220 13 45 0 +1221 13 45 1 +1222 13 44 0 +1223 13 44 1 +1224 15 44 1 +1225 15 44 0 +1226 15 45 1 +1227 15 45 0 +1228 14 44 1 +1229 14 44 0 +1230 14 45 1 +1231 14 45 0 +1280 11 47 0 +1281 11 47 1 +1282 11 46 0 +1283 11 46 1 +1284 10 47 0 +1285 10 47 1 +1286 10 46 0 +1287 10 46 1 +1288 8 46 1 +1289 8 46 0 +1290 8 47 1 +1291 8 47 0 +1292 9 46 1 +1293 9 46 0 +1294 9 47 1 +1295 9 47 0 +1312 3 46 0 +1313 3 46 1 +1314 3 47 0 +1315 3 47 1 +1316 2 46 0 +1317 2 46 1 +1318 2 47 0 +1319 2 47 1 +1320 0 47 1 +1321 0 47 0 +1322 0 46 1 +1323 0 46 0 +1324 1 47 1 +1325 1 47 0 +1326 1 46 1 +1327 1 46 0 +1328 4 46 0 +1329 4 46 1 +1330 4 47 0 +1331 4 47 1 +1332 5 46 0 +1333 5 46 1 +1334 5 47 0 +1335 5 47 1 +1336 7 47 1 +1337 7 47 0 +1338 7 46 1 +1339 7 46 0 +1340 6 47 1 +1341 6 47 0 +1342 6 46 1 +1343 6 46 0 +1344 12 47 0 +1345 12 47 1 +1346 12 46 0 +1347 12 46 1 +1348 13 47 0 +1349 13 47 1 +1350 13 46 0 +1351 13 46 1 +1352 15 46 1 +1353 15 46 0 +1354 15 47 1 +1355 15 47 0 +1356 14 46 1 +1357 14 46 0 +1358 14 47 1 +1359 14 47 0 +1408 11 49 0 +1409 11 49 1 +1410 11 48 0 +1411 11 48 1 +1412 10 49 0 +1413 10 49 1 +1414 10 48 0 +1415 10 48 1 +1416 8 48 1 +1417 8 48 0 +1418 8 49 1 +1419 8 49 0 +1420 9 48 1 +1421 9 48 0 +1422 9 49 1 +1423 9 49 0 +1440 3 48 0 +1441 3 48 1 +1442 3 49 0 +1443 3 49 1 +1444 2 48 0 +1445 2 48 1 +1446 2 49 0 +1447 2 49 1 +1448 0 49 1 +1449 0 49 0 +1450 0 48 1 +1451 0 48 0 +1452 1 49 1 +1453 1 49 0 +1454 1 48 1 +1455 1 48 0 +1456 4 48 0 +1457 4 48 1 +1458 4 49 0 +1459 4 49 1 +1460 5 48 0 +1461 5 48 1 +1462 5 49 0 +1463 5 49 1 +1464 7 49 1 +1465 7 49 0 +1466 7 48 1 +1467 7 48 0 +1468 6 49 1 +1469 6 49 0 +1470 6 48 1 +1471 6 48 0 +1472 12 49 0 +1473 12 49 1 +1474 12 48 0 +1475 12 48 1 +1476 13 49 0 +1477 13 49 1 +1478 13 48 0 +1479 13 48 1 +1480 15 48 1 +1481 15 48 0 +1482 15 49 1 +1483 15 49 0 +1484 14 48 1 +1485 14 48 0 +1486 14 49 1 +1487 14 49 0 +1536 11 51 0 +1537 11 51 1 +1538 11 50 0 +1539 11 50 1 +1540 10 51 0 +1541 10 51 1 +1542 10 50 0 +1543 10 50 1 +1544 8 50 1 +1545 8 50 0 +1546 8 51 1 +1547 8 51 0 +1548 9 50 1 +1549 9 50 0 +1550 9 51 1 +1551 9 51 0 +1568 3 50 0 +1569 3 50 1 +1570 3 51 0 +1571 3 51 1 +1572 2 50 0 +1573 2 50 1 +1574 2 51 0 +1575 2 51 1 +1576 0 51 1 +1577 0 51 0 +1578 0 50 1 +1579 0 50 0 +1580 1 51 1 +1581 1 51 0 +1582 1 50 1 +1583 1 50 0 +1584 4 50 0 +1585 4 50 1 +1586 4 51 0 +1587 4 51 1 +1588 5 50 0 +1589 5 50 1 +1590 5 51 0 +1591 5 51 1 +1592 7 51 1 +1593 7 51 0 +1594 7 50 1 +1595 7 50 0 +1596 6 51 1 +1597 6 51 0 +1598 6 50 1 +1599 6 50 0 +1600 12 51 0 +1601 12 51 1 +1602 12 50 0 +1603 12 50 1 +1604 13 51 0 +1605 13 51 1 +1606 13 50 0 +1607 13 50 1 +1608 15 50 1 +1609 15 50 0 +1610 15 51 1 +1611 15 51 0 +1612 14 50 1 +1613 14 50 0 +1614 14 51 1 +1615 14 51 0 +1664 11 53 0 +1665 11 53 1 +1666 11 52 0 +1667 11 52 1 +1668 10 53 0 +1669 10 53 1 +1670 10 52 0 +1671 10 52 1 +1672 8 52 1 +1673 8 52 0 +1674 8 53 1 +1675 8 53 0 +1676 9 52 1 +1677 9 52 0 +1678 9 53 1 +1679 9 53 0 +1696 3 52 0 +1697 3 52 1 +1698 3 53 0 +1699 3 53 1 +1700 2 52 0 +1701 2 52 1 +1702 2 53 0 +1703 2 53 1 +1704 0 53 1 +1705 0 53 0 +1706 0 52 1 +1707 0 52 0 +1708 1 53 1 +1709 1 53 0 +1710 1 52 1 +1711 1 52 0 +1712 4 52 0 +1713 4 52 1 +1714 4 53 0 +1715 4 53 1 +1716 5 52 0 +1717 5 52 1 +1718 5 53 0 +1719 5 53 1 +1720 7 53 1 +1721 7 53 0 +1722 7 52 1 +1723 7 52 0 +1724 6 53 1 +1725 6 53 0 +1726 6 52 1 +1727 6 52 0 +1728 12 53 0 +1729 12 53 1 +1730 12 52 0 +1731 12 52 1 +1732 13 53 0 +1733 13 53 1 +1734 13 52 0 +1735 13 52 1 +1736 15 52 1 +1737 15 52 0 +1738 15 53 1 +1739 15 53 0 +1740 14 52 1 +1741 14 52 0 +1742 14 53 1 +1743 14 53 0 +1792 11 55 0 +1793 11 55 1 +1794 11 54 0 +1795 11 54 1 +1796 10 55 0 +1797 10 55 1 +1798 10 54 0 +1799 10 54 1 +1800 8 54 1 +1801 8 54 0 +1802 8 55 1 +1803 8 55 0 +1804 9 54 1 +1805 9 54 0 +1806 9 55 1 +1807 9 55 0 +1824 3 54 0 +1825 3 54 1 +1826 3 55 0 +1827 3 55 1 +1828 2 54 0 +1829 2 54 1 +1830 2 55 0 +1831 2 55 1 +1832 0 55 1 +1833 0 55 0 +1834 0 54 1 +1835 0 54 0 +1836 1 55 1 +1837 1 55 0 +1838 1 54 1 +1839 1 54 0 +1840 4 54 0 +1841 4 54 1 +1842 4 55 0 +1843 4 55 1 +1844 5 54 0 +1845 5 54 1 +1846 5 55 0 +1847 5 55 1 +1848 7 55 1 +1849 7 55 0 +1850 7 54 1 +1851 7 54 0 +1852 6 55 1 +1853 6 55 0 +1854 6 54 1 +1855 6 54 0 +1856 12 55 0 +1857 12 55 1 +1858 12 54 0 +1859 12 54 1 +1860 13 55 0 +1861 13 55 1 +1862 13 54 0 +1863 13 54 1 +1864 15 54 1 +1865 15 54 0 +1866 15 55 1 +1867 15 55 0 +1868 14 54 1 +1869 14 54 0 +1870 14 55 1 +1871 14 55 0 +2176 11 27 0 +2177 11 27 1 +2178 11 26 0 +2179 11 26 1 +2180 10 27 0 +2181 10 27 1 +2182 10 26 0 +2183 10 26 1 +2184 8 26 1 +2185 8 26 0 +2186 8 27 1 +2187 8 27 0 +2188 9 26 1 +2189 9 26 0 +2190 9 27 1 +2191 9 27 0 +2208 3 26 0 +2209 3 26 1 +2210 3 27 0 +2211 3 27 1 +2212 2 26 0 +2213 2 26 1 +2214 2 27 0 +2215 2 27 1 +2216 0 27 1 +2217 0 27 0 +2218 0 26 1 +2219 0 26 0 +2220 1 27 1 +2221 1 27 0 +2222 1 26 1 +2223 1 26 0 +2224 4 26 0 +2225 4 26 1 +2226 4 27 0 +2227 4 27 1 +2228 5 26 0 +2229 5 26 1 +2230 5 27 0 +2231 5 27 1 +2232 7 27 1 +2233 7 27 0 +2234 7 26 1 +2235 7 26 0 +2236 6 27 1 +2237 6 27 0 +2238 6 26 1 +2239 6 26 0 +2240 12 27 0 +2241 12 27 1 +2242 12 26 0 +2243 12 26 1 +2244 13 27 0 +2245 13 27 1 +2246 13 26 0 +2247 13 26 1 +2248 15 26 1 +2249 15 26 0 +2250 15 27 1 +2251 15 27 0 +2252 14 26 1 +2253 14 26 0 +2254 14 27 1 +2255 14 27 0 +2304 11 25 0 +2305 11 25 1 +2306 11 24 0 +2307 11 24 1 +2308 10 25 0 +2309 10 25 1 +2310 10 24 0 +2311 10 24 1 +2312 8 24 1 +2313 8 24 0 +2314 8 25 1 +2315 8 25 0 +2316 9 24 1 +2317 9 24 0 +2318 9 25 1 +2319 9 25 0 +2336 3 24 0 +2337 3 24 1 +2338 3 25 0 +2339 3 25 1 +2340 2 24 0 +2341 2 24 1 +2342 2 25 0 +2343 2 25 1 +2344 0 25 1 +2345 0 25 0 +2346 0 24 1 +2347 0 24 0 +2348 1 25 1 +2349 1 25 0 +2350 1 24 1 +2351 1 24 0 +2352 4 24 0 +2353 4 24 1 +2354 4 25 0 +2355 4 25 1 +2356 5 24 0 +2357 5 24 1 +2358 5 25 0 +2359 5 25 1 +2360 7 25 1 +2361 7 25 0 +2362 7 24 1 +2363 7 24 0 +2364 6 25 1 +2365 6 25 0 +2366 6 24 1 +2367 6 24 0 +2368 12 25 0 +2369 12 25 1 +2370 12 24 0 +2371 12 24 1 +2372 13 25 0 +2373 13 25 1 +2374 13 24 0 +2375 13 24 1 +2376 15 24 1 +2377 15 24 0 +2378 15 25 1 +2379 15 25 0 +2380 14 24 1 +2381 14 24 0 +2382 14 25 1 +2383 14 25 0 +2432 11 23 0 +2433 11 23 1 +2434 11 22 0 +2435 11 22 1 +2436 10 23 0 +2437 10 23 1 +2438 10 22 0 +2439 10 22 1 +2440 8 22 1 +2441 8 22 0 +2442 8 23 1 +2443 8 23 0 +2444 9 22 1 +2445 9 22 0 +2446 9 23 1 +2447 9 23 0 +2464 3 22 0 +2465 3 22 1 +2466 3 23 0 +2467 3 23 1 +2468 2 22 0 +2469 2 22 1 +2470 2 23 0 +2471 2 23 1 +2472 0 23 1 +2473 0 23 0 +2474 0 22 1 +2475 0 22 0 +2476 1 23 1 +2477 1 23 0 +2478 1 22 1 +2479 1 22 0 +2480 4 22 0 +2481 4 22 1 +2482 4 23 0 +2483 4 23 1 +2484 5 22 0 +2485 5 22 1 +2486 5 23 0 +2487 5 23 1 +2488 7 23 1 +2489 7 23 0 +2490 7 22 1 +2491 7 22 0 +2492 6 23 1 +2493 6 23 0 +2494 6 22 1 +2495 6 22 0 +2496 12 23 0 +2497 12 23 1 +2498 12 22 0 +2499 12 22 1 +2500 13 23 0 +2501 13 23 1 +2502 13 22 0 +2503 13 22 1 +2504 15 22 1 +2505 15 22 0 +2506 15 23 1 +2507 15 23 0 +2508 14 22 1 +2509 14 22 0 +2510 14 23 1 +2511 14 23 0 +2560 11 21 0 +2561 11 21 1 +2562 11 20 0 +2563 11 20 1 +2564 10 21 0 +2565 10 21 1 +2566 10 20 0 +2567 10 20 1 +2568 8 20 1 +2569 8 20 0 +2570 8 21 1 +2571 8 21 0 +2572 9 20 1 +2573 9 20 0 +2574 9 21 1 +2575 9 21 0 +2592 3 20 0 +2593 3 20 1 +2594 3 21 0 +2595 3 21 1 +2596 2 20 0 +2597 2 20 1 +2598 2 21 0 +2599 2 21 1 +2600 0 21 1 +2601 0 21 0 +2602 0 20 1 +2603 0 20 0 +2604 1 21 1 +2605 1 21 0 +2606 1 20 1 +2607 1 20 0 +2608 4 20 0 +2609 4 20 1 +2610 4 21 0 +2611 4 21 1 +2612 5 20 0 +2613 5 20 1 +2614 5 21 0 +2615 5 21 1 +2616 7 21 1 +2617 7 21 0 +2618 7 20 1 +2619 7 20 0 +2620 6 21 1 +2621 6 21 0 +2622 6 20 1 +2623 6 20 0 +2624 12 21 0 +2625 12 21 1 +2626 12 20 0 +2627 12 20 1 +2628 13 21 0 +2629 13 21 1 +2630 13 20 0 +2631 13 20 1 +2632 15 20 1 +2633 15 20 0 +2634 15 21 1 +2635 15 21 0 +2636 14 20 1 +2637 14 20 0 +2638 14 21 1 +2639 14 21 0 +2688 11 19 0 +2689 11 19 1 +2690 11 18 0 +2691 11 18 1 +2692 10 19 0 +2693 10 19 1 +2694 10 18 0 +2695 10 18 1 +2696 8 18 1 +2697 8 18 0 +2698 8 19 1 +2699 8 19 0 +2700 9 18 1 +2701 9 18 0 +2702 9 19 1 +2703 9 19 0 +2720 3 18 0 +2721 3 18 1 +2722 3 19 0 +2723 3 19 1 +2724 2 18 0 +2725 2 18 1 +2726 2 19 0 +2727 2 19 1 +2728 0 19 1 +2729 0 19 0 +2730 0 18 1 +2731 0 18 0 +2732 1 19 1 +2733 1 19 0 +2734 1 18 1 +2735 1 18 0 +2736 4 18 0 +2737 4 18 1 +2738 4 19 0 +2739 4 19 1 +2740 5 18 0 +2741 5 18 1 +2742 5 19 0 +2743 5 19 1 +2744 7 19 1 +2745 7 19 0 +2746 7 18 1 +2747 7 18 0 +2748 6 19 1 +2749 6 19 0 +2750 6 18 1 +2751 6 18 0 +2752 12 19 0 +2753 12 19 1 +2754 12 18 0 +2755 12 18 1 +2756 13 19 0 +2757 13 19 1 +2758 13 18 0 +2759 13 18 1 +2760 15 18 1 +2761 15 18 0 +2762 15 19 1 +2763 15 19 0 +2764 14 18 1 +2765 14 18 0 +2766 14 19 1 +2767 14 19 0 +2816 11 17 0 +2817 11 17 1 +2818 11 16 0 +2819 11 16 1 +2820 10 17 0 +2821 10 17 1 +2822 10 16 0 +2823 10 16 1 +2824 8 16 1 +2825 8 16 0 +2826 8 17 1 +2827 8 17 0 +2828 9 16 1 +2829 9 16 0 +2830 9 17 1 +2831 9 17 0 +2848 3 16 0 +2849 3 16 1 +2850 3 17 0 +2851 3 17 1 +2852 2 16 0 +2853 2 16 1 +2854 2 17 0 +2855 2 17 1 +2856 0 17 1 +2857 0 17 0 +2858 0 16 1 +2859 0 16 0 +2860 1 17 1 +2861 1 17 0 +2862 1 16 1 +2863 1 16 0 +2864 4 16 0 +2865 4 16 1 +2866 4 17 0 +2867 4 17 1 +2868 5 16 0 +2869 5 16 1 +2870 5 17 0 +2871 5 17 1 +2872 7 17 1 +2873 7 17 0 +2874 7 16 1 +2875 7 16 0 +2876 6 17 1 +2877 6 17 0 +2878 6 16 1 +2879 6 16 0 +2880 12 17 0 +2881 12 17 1 +2882 12 16 0 +2883 12 16 1 +2884 13 17 0 +2885 13 17 1 +2886 13 16 0 +2887 13 16 1 +2888 15 16 1 +2889 15 16 0 +2890 15 17 1 +2891 15 17 0 +2892 14 16 1 +2893 14 16 0 +2894 14 17 1 +2895 14 17 0 +2944 11 15 0 +2945 11 15 1 +2946 11 14 0 +2947 11 14 1 +2948 10 15 0 +2949 10 15 1 +2950 10 14 0 +2951 10 14 1 +2952 8 14 1 +2953 8 14 0 +2954 8 15 1 +2955 8 15 0 +2956 9 14 1 +2957 9 14 0 +2958 9 15 1 +2959 9 15 0 +2976 3 14 0 +2977 3 14 1 +2978 3 15 0 +2979 3 15 1 +2980 2 14 0 +2981 2 14 1 +2982 2 15 0 +2983 2 15 1 +2984 0 15 1 +2985 0 15 0 +2986 0 14 1 +2987 0 14 0 +2988 1 15 1 +2989 1 15 0 +2990 1 14 1 +2991 1 14 0 +2992 4 14 0 +2993 4 14 1 +2994 4 15 0 +2995 4 15 1 +2996 5 14 0 +2997 5 14 1 +2998 5 15 0 +2999 5 15 1 +3000 7 15 1 +3001 7 15 0 +3002 7 14 1 +3003 7 14 0 +3004 6 15 1 +3005 6 15 0 +3006 6 14 1 +3007 6 14 0 +3008 12 15 0 +3009 12 15 1 +3010 12 14 0 +3011 12 14 1 +3012 13 15 0 +3013 13 15 1 +3014 13 14 0 +3015 13 14 1 +3016 15 14 1 +3017 15 14 0 +3018 15 15 1 +3019 15 15 0 +3020 14 14 1 +3021 14 14 0 +3022 14 15 1 +3023 14 15 0 +3072 11 13 0 +3073 11 13 1 +3074 11 12 0 +3075 11 12 1 +3076 10 13 0 +3077 10 13 1 +3078 10 12 0 +3079 10 12 1 +3080 8 12 1 +3081 8 12 0 +3082 8 13 1 +3083 8 13 0 +3084 9 12 1 +3085 9 12 0 +3086 9 13 1 +3087 9 13 0 +3104 3 12 0 +3105 3 12 1 +3106 3 13 0 +3107 3 13 1 +3108 2 12 0 +3109 2 12 1 +3110 2 13 0 +3111 2 13 1 +3112 0 13 1 +3113 0 13 0 +3114 0 12 1 +3115 0 12 0 +3116 1 13 1 +3117 1 13 0 +3118 1 12 1 +3119 1 12 0 +3120 4 12 0 +3121 4 12 1 +3122 4 13 0 +3123 4 13 1 +3124 5 12 0 +3125 5 12 1 +3126 5 13 0 +3127 5 13 1 +3128 7 13 1 +3129 7 13 0 +3130 7 12 1 +3131 7 12 0 +3132 6 13 1 +3133 6 13 0 +3134 6 12 1 +3135 6 12 0 +3136 12 13 0 +3137 12 13 1 +3138 12 12 0 +3139 12 12 1 +3140 13 13 0 +3141 13 13 1 +3142 13 12 0 +3143 13 12 1 +3144 15 12 1 +3145 15 12 0 +3146 15 13 1 +3147 15 13 0 +3148 14 12 1 +3149 14 12 0 +3150 14 13 1 +3151 14 13 0 +3200 11 11 0 +3201 11 11 1 +3202 11 10 0 +3203 11 10 1 +3204 10 11 0 +3205 10 11 1 +3206 10 10 0 +3207 10 10 1 +3208 8 10 1 +3209 8 10 0 +3210 8 11 1 +3211 8 11 0 +3212 9 10 1 +3213 9 10 0 +3214 9 11 1 +3215 9 11 0 +3232 3 10 0 +3233 3 10 1 +3234 3 11 0 +3235 3 11 1 +3236 2 10 0 +3237 2 10 1 +3238 2 11 0 +3239 2 11 1 +3240 0 11 1 +3241 0 11 0 +3242 0 10 1 +3243 0 10 0 +3244 1 11 1 +3245 1 11 0 +3246 1 10 1 +3247 1 10 0 +3248 4 10 0 +3249 4 10 1 +3250 4 11 0 +3251 4 11 1 +3252 5 10 0 +3253 5 10 1 +3254 5 11 0 +3255 5 11 1 +3256 7 11 1 +3257 7 11 0 +3258 7 10 1 +3259 7 10 0 +3260 6 11 1 +3261 6 11 0 +3262 6 10 1 +3263 6 10 0 +3264 12 11 0 +3265 12 11 1 +3266 12 10 0 +3267 12 10 1 +3268 13 11 0 +3269 13 11 1 +3270 13 10 0 +3271 13 10 1 +3272 15 10 1 +3273 15 10 0 +3274 15 11 1 +3275 15 11 0 +3276 14 10 1 +3277 14 10 0 +3278 14 11 1 +3279 14 11 0 +3328 11 9 0 +3329 11 9 1 +3330 11 8 0 +3331 11 8 1 +3332 10 9 0 +3333 10 9 1 +3334 10 8 0 +3335 10 8 1 +3336 8 8 1 +3337 8 8 0 +3338 8 9 1 +3339 8 9 0 +3340 9 8 1 +3341 9 8 0 +3342 9 9 1 +3343 9 9 0 +3360 3 8 0 +3361 3 8 1 +3362 3 9 0 +3363 3 9 1 +3364 2 8 0 +3365 2 8 1 +3366 2 9 0 +3367 2 9 1 +3368 0 9 1 +3369 0 9 0 +3370 0 8 1 +3371 0 8 0 +3372 1 9 1 +3373 1 9 0 +3374 1 8 1 +3375 1 8 0 +3376 4 8 0 +3377 4 8 1 +3378 4 9 0 +3379 4 9 1 +3380 5 8 0 +3381 5 8 1 +3382 5 9 0 +3383 5 9 1 +3384 7 9 1 +3385 7 9 0 +3386 7 8 1 +3387 7 8 0 +3388 6 9 1 +3389 6 9 0 +3390 6 8 1 +3391 6 8 0 +3392 12 9 0 +3393 12 9 1 +3394 12 8 0 +3395 12 8 1 +3396 13 9 0 +3397 13 9 1 +3398 13 8 0 +3399 13 8 1 +3400 15 8 1 +3401 15 8 0 +3402 15 9 1 +3403 15 9 0 +3404 14 8 1 +3405 14 8 0 +3406 14 9 1 +3407 14 9 0 +3456 11 7 0 +3457 11 7 1 +3458 11 6 0 +3459 11 6 1 +3460 10 7 0 +3461 10 7 1 +3462 10 6 0 +3463 10 6 1 +3464 8 6 1 +3465 8 6 0 +3466 8 7 1 +3467 8 7 0 +3468 9 6 1 +3469 9 6 0 +3470 9 7 1 +3471 9 7 0 +3488 3 6 0 +3489 3 6 1 +3490 3 7 0 +3491 3 7 1 +3492 2 6 0 +3493 2 6 1 +3494 2 7 0 +3495 2 7 1 +3496 0 7 1 +3497 0 7 0 +3498 0 6 1 +3499 0 6 0 +3500 1 7 1 +3501 1 7 0 +3502 1 6 1 +3503 1 6 0 +3504 4 6 0 +3505 4 6 1 +3506 4 7 0 +3507 4 7 1 +3508 5 6 0 +3509 5 6 1 +3510 5 7 0 +3511 5 7 1 +3512 7 7 1 +3513 7 7 0 +3514 7 6 1 +3515 7 6 0 +3516 6 7 1 +3517 6 7 0 +3518 6 6 1 +3519 6 6 0 +3520 12 7 0 +3521 12 7 1 +3522 12 6 0 +3523 12 6 1 +3524 13 7 0 +3525 13 7 1 +3526 13 6 0 +3527 13 6 1 +3528 15 6 1 +3529 15 6 0 +3530 15 7 1 +3531 15 7 0 +3532 14 6 1 +3533 14 6 0 +3534 14 7 1 +3535 14 7 0 +3584 11 5 0 +3585 11 5 1 +3586 11 4 0 +3587 11 4 1 +3588 10 5 0 +3589 10 5 1 +3590 10 4 0 +3591 10 4 1 +3592 8 4 1 +3593 8 4 0 +3594 8 5 1 +3595 8 5 0 +3596 9 4 1 +3597 9 4 0 +3598 9 5 1 +3599 9 5 0 +3616 3 4 0 +3617 3 4 1 +3618 3 5 0 +3619 3 5 1 +3620 2 4 0 +3621 2 4 1 +3622 2 5 0 +3623 2 5 1 +3624 0 5 1 +3625 0 5 0 +3626 0 4 1 +3627 0 4 0 +3628 1 5 1 +3629 1 5 0 +3630 1 4 1 +3631 1 4 0 +3632 4 4 0 +3633 4 4 1 +3634 4 5 0 +3635 4 5 1 +3636 5 4 0 +3637 5 4 1 +3638 5 5 0 +3639 5 5 1 +3640 7 5 1 +3641 7 5 0 +3642 7 4 1 +3643 7 4 0 +3644 6 5 1 +3645 6 5 0 +3646 6 4 1 +3647 6 4 0 +3648 12 5 0 +3649 12 5 1 +3650 12 4 0 +3651 12 4 1 +3652 13 5 0 +3653 13 5 1 +3654 13 4 0 +3655 13 4 1 +3656 15 4 1 +3657 15 4 0 +3658 15 5 1 +3659 15 5 0 +3660 14 4 1 +3661 14 4 0 +3662 14 5 1 +3663 14 5 0 +3712 11 3 0 +3713 11 3 1 +3714 11 2 0 +3715 11 2 1 +3716 10 3 0 +3717 10 3 1 +3718 10 2 0 +3719 10 2 1 +3720 8 2 1 +3721 8 2 0 +3722 8 3 1 +3723 8 3 0 +3724 9 2 1 +3725 9 2 0 +3726 9 3 1 +3727 9 3 0 +3744 3 2 0 +3745 3 2 1 +3746 3 3 0 +3747 3 3 1 +3748 2 2 0 +3749 2 2 1 +3750 2 3 0 +3751 2 3 1 +3752 0 3 1 +3753 0 3 0 +3754 0 2 1 +3755 0 2 0 +3756 1 3 1 +3757 1 3 0 +3758 1 2 1 +3759 1 2 0 +3760 4 2 0 +3761 4 2 1 +3762 4 3 0 +3763 4 3 1 +3764 5 2 0 +3765 5 2 1 +3766 5 3 0 +3767 5 3 1 +3768 7 3 1 +3769 7 3 0 +3770 7 2 1 +3771 7 2 0 +3772 6 3 1 +3773 6 3 0 +3774 6 2 1 +3775 6 2 0 +3776 12 3 0 +3777 12 3 1 +3778 12 2 0 +3779 12 2 1 +3780 13 3 0 +3781 13 3 1 +3782 13 2 0 +3783 13 2 1 +3784 15 2 1 +3785 15 2 0 +3786 15 3 1 +3787 15 3 0 +3788 14 2 1 +3789 14 2 0 +3790 14 3 1 +3791 14 3 0 +3840 11 1 0 +3841 11 1 1 +3842 11 0 0 +3843 11 0 1 +3844 10 1 0 +3845 10 1 1 +3846 10 0 0 +3847 10 0 1 +3848 8 0 1 +3849 8 0 0 +3850 8 1 1 +3851 8 1 0 +3852 9 0 1 +3853 9 0 0 +3854 9 1 1 +3855 9 1 0 +3872 3 0 0 +3873 3 0 1 +3874 3 1 0 +3875 3 1 1 +3876 2 0 0 +3877 2 0 1 +3878 2 1 0 +3879 2 1 1 +3880 0 1 1 +3881 0 1 0 +3882 0 0 1 +3883 0 0 0 +3884 1 1 1 +3885 1 1 0 +3886 1 0 1 +3887 1 0 0 +3888 4 0 0 +3889 4 0 1 +3890 4 1 0 +3891 4 1 1 +3892 5 0 0 +3893 5 0 1 +3894 5 1 0 +3895 5 1 1 +3896 7 1 1 +3897 7 1 0 +3898 7 0 1 +3899 7 0 0 +3900 6 1 1 +3901 6 1 0 +3902 6 0 1 +3903 6 0 0 +3904 12 1 0 +3905 12 1 1 +3906 12 0 0 +3907 12 0 1 +3908 13 1 0 +3909 13 1 1 +3910 13 0 0 +3911 13 0 1 +3912 15 0 1 +3913 15 0 0 +3914 15 1 1 +3915 15 1 0 +3916 14 0 1 +3917 14 0 0 +3918 14 1 1 +3919 14 1 0 diff --git a/Detectors/PHOS/base/files/Mod1RCU1.data b/Detectors/PHOS/base/files/Mod1RCU1.data new file mode 100644 index 0000000000000..db125226496cf --- /dev/null +++ b/Detectors/PHOS/base/files/Mod1RCU1.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 1 0 2 + 1 1 1 2 + 2 1 2 2 + 3 1 3 2 + 4 1 4 2 + 5 1 5 2 + 6 1 6 2 + 7 1 7 2 + 8 1 8 2 + 9 1 9 2 + 10 1 10 2 + 11 1 11 2 + 12 1 12 2 + 13 1 13 2 + 14 1 14 2 + 15 1 15 2 + 16 1 16 2 + 17 1 17 2 + 18 1 18 2 + 19 1 19 2 + 20 1 20 2 + 21 1 21 2 + 22 1 22 2 + 23 1 23 2 + 24 1 24 2 + 25 1 25 2 + 26 1 26 2 + 27 1 27 2 + 28 1 28 2 + 29 1 29 2 + 30 1 30 2 + 31 1 31 2 + 32 1 32 2 + 33 1 33 2 + 34 1 34 2 + 35 1 35 2 + 36 1 36 2 + 37 1 37 2 + 38 1 38 2 + 39 1 39 2 + 40 1 40 2 + 41 1 41 2 + 42 1 42 2 + 43 1 43 2 + 44 1 44 2 + 45 1 45 2 + 46 1 46 2 + 47 1 47 2 + 48 1 48 2 + 49 1 49 2 + 50 1 50 2 + 51 1 51 2 + 52 1 52 2 + 53 1 53 2 + 54 1 54 2 + 55 1 55 2 + 56 1 56 2 + 57 1 57 2 + 58 1 58 2 + 59 1 59 2 + 60 1 60 2 + 61 1 61 2 + 62 1 62 2 + 63 1 63 2 + 64 1 64 2 + 65 1 65 2 + 66 1 66 2 + 67 1 67 2 + 68 1 68 2 + 69 1 69 2 + 70 1 70 2 + 71 1 71 2 + 72 1 72 2 + 73 1 73 2 + 74 1 74 2 + 75 1 75 2 + 76 1 76 2 + 77 1 77 2 + 78 1 78 2 + 79 1 79 2 + 80 1 80 2 + 81 1 81 2 + 82 1 82 2 + 83 1 83 2 + 84 1 84 2 + 85 1 85 2 + 86 1 86 2 + 87 1 87 2 + 88 1 88 2 + 89 1 89 2 + 90 1 90 2 + 91 1 91 2 + 92 1 92 2 + 93 1 93 2 + 94 1 94 2 + 95 1 95 2 + 96 1 96 2 + 97 1 97 2 + 98 1 98 2 + 99 1 99 2 + 100 1 100 2 + 101 1 101 2 + 102 1 102 2 + 103 1 103 2 + 104 1 104 2 + 105 1 105 2 + 106 1 106 2 + 107 1 107 2 + 108 1 108 2 + 109 1 109 2 + 110 1 110 2 + 111 1 111 2 + 112 1 112 2 + 113 1 113 2 + 114 1 114 2 + 115 1 115 2 + 116 1 116 2 + 117 1 117 2 + 118 1 118 2 + 119 1 119 2 + 120 1 120 2 + 121 1 121 2 + 122 1 122 2 + 123 1 123 2 + 124 1 124 2 + 125 1 125 2 + 126 1 126 2 + 127 1 127 2 +2048 1 2048 2 +2049 1 2049 2 +2050 1 2050 2 +2051 1 2051 2 +2052 1 2052 2 +2053 1 2053 2 +2054 1 2054 2 +2055 1 2055 2 +2056 1 2056 2 +2057 1 2057 2 +2058 1 2058 2 +2059 1 2059 2 +2060 1 2060 2 +2061 1 2061 2 +2062 1 2062 2 +2063 1 2063 2 +2064 1 2064 2 +2065 1 2065 2 +2066 1 2066 2 +2067 1 2067 2 +2068 1 2068 2 +2069 1 2069 2 +2070 1 2070 2 +2071 1 2071 2 +2072 1 2072 2 +2073 1 2073 2 +2074 1 2074 2 +2075 1 2075 2 +2076 1 2076 2 +2077 1 2077 2 +2078 1 2078 2 +2079 1 2079 2 +2080 1 2080 2 +2081 1 2081 2 +2082 1 2082 2 +2083 1 2083 2 +2084 1 2084 2 +2085 1 2085 2 +2086 1 2086 2 +2087 1 2087 2 +2088 1 2088 2 +2089 1 2089 2 +2090 1 2090 2 +2091 1 2091 2 +2092 1 2092 2 +2093 1 2093 2 +2094 1 2094 2 +2095 1 2095 2 +2096 1 2096 2 +2097 1 2097 2 +2098 1 2098 2 +2099 1 2099 2 +2100 1 2100 2 +2101 1 2101 2 +2102 1 2102 2 +2103 1 2103 2 +2104 1 2104 2 +2105 1 2105 2 +2106 1 2106 2 +2107 1 2107 2 +2108 1 2108 2 +2109 1 2109 2 +2110 1 2110 2 +2111 1 2111 2 +2112 1 2112 2 +2113 1 2113 2 +2114 1 2114 2 +2115 1 2115 2 +2116 1 2116 2 +2117 1 2117 2 +2118 1 2118 2 +2119 1 2119 2 +2120 1 2120 2 +2121 1 2121 2 +2122 1 2122 2 +2123 1 2123 2 +2124 1 2124 2 +2125 1 2125 2 +2126 1 2126 2 +2127 1 2127 2 +2128 1 2128 2 +2129 1 2129 2 +2130 1 2130 2 +2131 1 2131 2 +2132 1 2132 2 +2133 1 2133 2 +2134 1 2134 2 +2135 1 2135 2 +2136 1 2136 2 +2137 1 2137 2 +2138 1 2138 2 +2139 1 2139 2 +2140 1 2140 2 +2141 1 2141 2 +2142 1 2142 2 +2143 1 2143 2 +2144 1 2144 2 +2145 1 2145 2 +2146 1 2146 2 +2147 1 2147 2 +2148 1 2148 2 +2149 1 2149 2 +2150 1 2150 2 +2151 1 2151 2 +2152 1 2152 2 +2153 1 2153 2 +2154 1 2154 2 +2155 1 2155 2 +2156 1 2156 2 +2157 1 2157 2 +2158 1 2158 2 +2159 1 2159 2 +2160 1 2160 2 +2161 1 2161 2 +2162 1 2162 2 +2163 1 2163 2 +2164 1 2164 2 +2165 1 2165 2 +2166 1 2166 2 +2167 1 2167 2 +2168 1 2168 2 +2169 1 2169 2 +2170 1 2170 2 +2171 1 2171 2 +2172 1 2172 2 +2173 1 2173 2 +2174 1 2174 2 +2175 1 2175 2 + 128 27 29 0 + 129 27 29 1 + 130 27 28 0 + 131 27 28 1 + 132 26 29 0 + 133 26 29 1 + 134 26 28 0 + 135 26 28 1 + 136 24 28 1 + 137 24 28 0 + 138 24 29 1 + 139 24 29 0 + 140 25 28 1 + 141 25 28 0 + 142 25 29 1 + 143 25 29 0 + 160 19 28 0 + 161 19 28 1 + 162 19 29 0 + 163 19 29 1 + 164 18 28 0 + 165 18 28 1 + 166 18 29 0 + 167 18 29 1 + 168 16 29 1 + 169 16 29 0 + 170 16 28 1 + 171 16 28 0 + 172 17 29 1 + 173 17 29 0 + 174 17 28 1 + 175 17 28 0 + 176 20 28 0 + 177 20 28 1 + 178 20 29 0 + 179 20 29 1 + 180 21 28 0 + 181 21 28 1 + 182 21 29 0 + 183 21 29 1 + 184 23 29 1 + 185 23 29 0 + 186 23 28 1 + 187 23 28 0 + 188 22 29 1 + 189 22 29 0 + 190 22 28 1 + 191 22 28 0 + 192 28 29 0 + 193 28 29 1 + 194 28 28 0 + 195 28 28 1 + 196 29 29 0 + 197 29 29 1 + 198 29 28 0 + 199 29 28 1 + 200 31 28 1 + 201 31 28 0 + 202 31 29 1 + 203 31 29 0 + 204 30 28 1 + 205 30 28 0 + 206 30 29 1 + 207 30 29 0 + 256 27 31 0 + 257 27 31 1 + 258 27 30 0 + 259 27 30 1 + 260 26 31 0 + 261 26 31 1 + 262 26 30 0 + 263 26 30 1 + 264 24 30 1 + 265 24 30 0 + 266 24 31 1 + 267 24 31 0 + 268 25 30 1 + 269 25 30 0 + 270 25 31 1 + 271 25 31 0 + 288 19 30 0 + 289 19 30 1 + 290 19 31 0 + 291 19 31 1 + 292 18 30 0 + 293 18 30 1 + 294 18 31 0 + 295 18 31 1 + 296 16 31 1 + 297 16 31 0 + 298 16 30 1 + 299 16 30 0 + 300 17 31 1 + 301 17 31 0 + 302 17 30 1 + 303 17 30 0 + 304 20 30 0 + 305 20 30 1 + 306 20 31 0 + 307 20 31 1 + 308 21 30 0 + 309 21 30 1 + 310 21 31 0 + 311 21 31 1 + 312 23 31 1 + 313 23 31 0 + 314 23 30 1 + 315 23 30 0 + 316 22 31 1 + 317 22 31 0 + 318 22 30 1 + 319 22 30 0 + 320 28 31 0 + 321 28 31 1 + 322 28 30 0 + 323 28 30 1 + 324 29 31 0 + 325 29 31 1 + 326 29 30 0 + 327 29 30 1 + 328 31 30 1 + 329 31 30 0 + 330 31 31 1 + 331 31 31 0 + 332 30 30 1 + 333 30 30 0 + 334 30 31 1 + 335 30 31 0 + 384 27 33 0 + 385 27 33 1 + 386 27 32 0 + 387 27 32 1 + 388 26 33 0 + 389 26 33 1 + 390 26 32 0 + 391 26 32 1 + 392 24 32 1 + 393 24 32 0 + 394 24 33 1 + 395 24 33 0 + 396 25 32 1 + 397 25 32 0 + 398 25 33 1 + 399 25 33 0 + 416 19 32 0 + 417 19 32 1 + 418 19 33 0 + 419 19 33 1 + 420 18 32 0 + 421 18 32 1 + 422 18 33 0 + 423 18 33 1 + 424 16 33 1 + 425 16 33 0 + 426 16 32 1 + 427 16 32 0 + 428 17 33 1 + 429 17 33 0 + 430 17 32 1 + 431 17 32 0 + 432 20 32 0 + 433 20 32 1 + 434 20 33 0 + 435 20 33 1 + 436 21 32 0 + 437 21 32 1 + 438 21 33 0 + 439 21 33 1 + 440 23 33 1 + 441 23 33 0 + 442 23 32 1 + 443 23 32 0 + 444 22 33 1 + 445 22 33 0 + 446 22 32 1 + 447 22 32 0 + 448 28 33 0 + 449 28 33 1 + 450 28 32 0 + 451 28 32 1 + 452 29 33 0 + 453 29 33 1 + 454 29 32 0 + 455 29 32 1 + 456 31 32 1 + 457 31 32 0 + 458 31 33 1 + 459 31 33 0 + 460 30 32 1 + 461 30 32 0 + 462 30 33 1 + 463 30 33 0 + 512 27 35 0 + 513 27 35 1 + 514 27 34 0 + 515 27 34 1 + 516 26 35 0 + 517 26 35 1 + 518 26 34 0 + 519 26 34 1 + 520 24 34 1 + 521 24 34 0 + 522 24 35 1 + 523 24 35 0 + 524 25 34 1 + 525 25 34 0 + 526 25 35 1 + 527 25 35 0 + 544 19 34 0 + 545 19 34 1 + 546 19 35 0 + 547 19 35 1 + 548 18 34 0 + 549 18 34 1 + 550 18 35 0 + 551 18 35 1 + 552 16 35 1 + 553 16 35 0 + 554 16 34 1 + 555 16 34 0 + 556 17 35 1 + 557 17 35 0 + 558 17 34 1 + 559 17 34 0 + 560 20 34 0 + 561 20 34 1 + 562 20 35 0 + 563 20 35 1 + 564 21 34 0 + 565 21 34 1 + 566 21 35 0 + 567 21 35 1 + 568 23 35 1 + 569 23 35 0 + 570 23 34 1 + 571 23 34 0 + 572 22 35 1 + 573 22 35 0 + 574 22 34 1 + 575 22 34 0 + 576 28 35 0 + 577 28 35 1 + 578 28 34 0 + 579 28 34 1 + 580 29 35 0 + 581 29 35 1 + 582 29 34 0 + 583 29 34 1 + 584 31 34 1 + 585 31 34 0 + 586 31 35 1 + 587 31 35 0 + 588 30 34 1 + 589 30 34 0 + 590 30 35 1 + 591 30 35 0 + 640 27 37 0 + 641 27 37 1 + 642 27 36 0 + 643 27 36 1 + 644 26 37 0 + 645 26 37 1 + 646 26 36 0 + 647 26 36 1 + 648 24 36 1 + 649 24 36 0 + 650 24 37 1 + 651 24 37 0 + 652 25 36 1 + 653 25 36 0 + 654 25 37 1 + 655 25 37 0 + 672 19 36 0 + 673 19 36 1 + 674 19 37 0 + 675 19 37 1 + 676 18 36 0 + 677 18 36 1 + 678 18 37 0 + 679 18 37 1 + 680 16 37 1 + 681 16 37 0 + 682 16 36 1 + 683 16 36 0 + 684 17 37 1 + 685 17 37 0 + 686 17 36 1 + 687 17 36 0 + 688 20 36 0 + 689 20 36 1 + 690 20 37 0 + 691 20 37 1 + 692 21 36 0 + 693 21 36 1 + 694 21 37 0 + 695 21 37 1 + 696 23 37 1 + 697 23 37 0 + 698 23 36 1 + 699 23 36 0 + 700 22 37 1 + 701 22 37 0 + 702 22 36 1 + 703 22 36 0 + 704 28 37 0 + 705 28 37 1 + 706 28 36 0 + 707 28 36 1 + 708 29 37 0 + 709 29 37 1 + 710 29 36 0 + 711 29 36 1 + 712 31 36 1 + 713 31 36 0 + 714 31 37 1 + 715 31 37 0 + 716 30 36 1 + 717 30 36 0 + 718 30 37 1 + 719 30 37 0 + 768 27 39 0 + 769 27 39 1 + 770 27 38 0 + 771 27 38 1 + 772 26 39 0 + 773 26 39 1 + 774 26 38 0 + 775 26 38 1 + 776 24 38 1 + 777 24 38 0 + 778 24 39 1 + 779 24 39 0 + 780 25 38 1 + 781 25 38 0 + 782 25 39 1 + 783 25 39 0 + 800 19 38 0 + 801 19 38 1 + 802 19 39 0 + 803 19 39 1 + 804 18 38 0 + 805 18 38 1 + 806 18 39 0 + 807 18 39 1 + 808 16 39 1 + 809 16 39 0 + 810 16 38 1 + 811 16 38 0 + 812 17 39 1 + 813 17 39 0 + 814 17 38 1 + 815 17 38 0 + 816 20 38 0 + 817 20 38 1 + 818 20 39 0 + 819 20 39 1 + 820 21 38 0 + 821 21 38 1 + 822 21 39 0 + 823 21 39 1 + 824 23 39 1 + 825 23 39 0 + 826 23 38 1 + 827 23 38 0 + 828 22 39 1 + 829 22 39 0 + 830 22 38 1 + 831 22 38 0 + 832 28 39 0 + 833 28 39 1 + 834 28 38 0 + 835 28 38 1 + 836 29 39 0 + 837 29 39 1 + 838 29 38 0 + 839 29 38 1 + 840 31 38 1 + 841 31 38 0 + 842 31 39 1 + 843 31 39 0 + 844 30 38 1 + 845 30 38 0 + 846 30 39 1 + 847 30 39 0 + 896 27 41 0 + 897 27 41 1 + 898 27 40 0 + 899 27 40 1 + 900 26 41 0 + 901 26 41 1 + 902 26 40 0 + 903 26 40 1 + 904 24 40 1 + 905 24 40 0 + 906 24 41 1 + 907 24 41 0 + 908 25 40 1 + 909 25 40 0 + 910 25 41 1 + 911 25 41 0 + 928 19 40 0 + 929 19 40 1 + 930 19 41 0 + 931 19 41 1 + 932 18 40 0 + 933 18 40 1 + 934 18 41 0 + 935 18 41 1 + 936 16 41 1 + 937 16 41 0 + 938 16 40 1 + 939 16 40 0 + 940 17 41 1 + 941 17 41 0 + 942 17 40 1 + 943 17 40 0 + 944 20 40 0 + 945 20 40 1 + 946 20 41 0 + 947 20 41 1 + 948 21 40 0 + 949 21 40 1 + 950 21 41 0 + 951 21 41 1 + 952 23 41 1 + 953 23 41 0 + 954 23 40 1 + 955 23 40 0 + 956 22 41 1 + 957 22 41 0 + 958 22 40 1 + 959 22 40 0 + 960 28 41 0 + 961 28 41 1 + 962 28 40 0 + 963 28 40 1 + 964 29 41 0 + 965 29 41 1 + 966 29 40 0 + 967 29 40 1 + 968 31 40 1 + 969 31 40 0 + 970 31 41 1 + 971 31 41 0 + 972 30 40 1 + 973 30 40 0 + 974 30 41 1 + 975 30 41 0 +1024 27 43 0 +1025 27 43 1 +1026 27 42 0 +1027 27 42 1 +1028 26 43 0 +1029 26 43 1 +1030 26 42 0 +1031 26 42 1 +1032 24 42 1 +1033 24 42 0 +1034 24 43 1 +1035 24 43 0 +1036 25 42 1 +1037 25 42 0 +1038 25 43 1 +1039 25 43 0 +1056 19 42 0 +1057 19 42 1 +1058 19 43 0 +1059 19 43 1 +1060 18 42 0 +1061 18 42 1 +1062 18 43 0 +1063 18 43 1 +1064 16 43 1 +1065 16 43 0 +1066 16 42 1 +1067 16 42 0 +1068 17 43 1 +1069 17 43 0 +1070 17 42 1 +1071 17 42 0 +1072 20 42 0 +1073 20 42 1 +1074 20 43 0 +1075 20 43 1 +1076 21 42 0 +1077 21 42 1 +1078 21 43 0 +1079 21 43 1 +1080 23 43 1 +1081 23 43 0 +1082 23 42 1 +1083 23 42 0 +1084 22 43 1 +1085 22 43 0 +1086 22 42 1 +1087 22 42 0 +1088 28 43 0 +1089 28 43 1 +1090 28 42 0 +1091 28 42 1 +1092 29 43 0 +1093 29 43 1 +1094 29 42 0 +1095 29 42 1 +1096 31 42 1 +1097 31 42 0 +1098 31 43 1 +1099 31 43 0 +1100 30 42 1 +1101 30 42 0 +1102 30 43 1 +1103 30 43 0 +1152 27 45 0 +1153 27 45 1 +1154 27 44 0 +1155 27 44 1 +1156 26 45 0 +1157 26 45 1 +1158 26 44 0 +1159 26 44 1 +1160 24 44 1 +1161 24 44 0 +1162 24 45 1 +1163 24 45 0 +1164 25 44 1 +1165 25 44 0 +1166 25 45 1 +1167 25 45 0 +1184 19 44 0 +1185 19 44 1 +1186 19 45 0 +1187 19 45 1 +1188 18 44 0 +1189 18 44 1 +1190 18 45 0 +1191 18 45 1 +1192 16 45 1 +1193 16 45 0 +1194 16 44 1 +1195 16 44 0 +1196 17 45 1 +1197 17 45 0 +1198 17 44 1 +1199 17 44 0 +1200 20 44 0 +1201 20 44 1 +1202 20 45 0 +1203 20 45 1 +1204 21 44 0 +1205 21 44 1 +1206 21 45 0 +1207 21 45 1 +1208 23 45 1 +1209 23 45 0 +1210 23 44 1 +1211 23 44 0 +1212 22 45 1 +1213 22 45 0 +1214 22 44 1 +1215 22 44 0 +1216 28 45 0 +1217 28 45 1 +1218 28 44 0 +1219 28 44 1 +1220 29 45 0 +1221 29 45 1 +1222 29 44 0 +1223 29 44 1 +1224 31 44 1 +1225 31 44 0 +1226 31 45 1 +1227 31 45 0 +1228 30 44 1 +1229 30 44 0 +1230 30 45 1 +1231 30 45 0 +1280 27 47 0 +1281 27 47 1 +1282 27 46 0 +1283 27 46 1 +1284 26 47 0 +1285 26 47 1 +1286 26 46 0 +1287 26 46 1 +1288 24 46 1 +1289 24 46 0 +1290 24 47 1 +1291 24 47 0 +1292 25 46 1 +1293 25 46 0 +1294 25 47 1 +1295 25 47 0 +1312 19 46 0 +1313 19 46 1 +1314 19 47 0 +1315 19 47 1 +1316 18 46 0 +1317 18 46 1 +1318 18 47 0 +1319 18 47 1 +1320 16 47 1 +1321 16 47 0 +1322 16 46 1 +1323 16 46 0 +1324 17 47 1 +1325 17 47 0 +1326 17 46 1 +1327 17 46 0 +1328 20 46 0 +1329 20 46 1 +1330 20 47 0 +1331 20 47 1 +1332 21 46 0 +1333 21 46 1 +1334 21 47 0 +1335 21 47 1 +1336 23 47 1 +1337 23 47 0 +1338 23 46 1 +1339 23 46 0 +1340 22 47 1 +1341 22 47 0 +1342 22 46 1 +1343 22 46 0 +1344 28 47 0 +1345 28 47 1 +1346 28 46 0 +1347 28 46 1 +1348 29 47 0 +1349 29 47 1 +1350 29 46 0 +1351 29 46 1 +1352 31 46 1 +1353 31 46 0 +1354 31 47 1 +1355 31 47 0 +1356 30 46 1 +1357 30 46 0 +1358 30 47 1 +1359 30 47 0 +1408 27 49 0 +1409 27 49 1 +1410 27 48 0 +1411 27 48 1 +1412 26 49 0 +1413 26 49 1 +1414 26 48 0 +1415 26 48 1 +1416 24 48 1 +1417 24 48 0 +1418 24 49 1 +1419 24 49 0 +1420 25 48 1 +1421 25 48 0 +1422 25 49 1 +1423 25 49 0 +1440 19 48 0 +1441 19 48 1 +1442 19 49 0 +1443 19 49 1 +1444 18 48 0 +1445 18 48 1 +1446 18 49 0 +1447 18 49 1 +1448 16 49 1 +1449 16 49 0 +1450 16 48 1 +1451 16 48 0 +1452 17 49 1 +1453 17 49 0 +1454 17 48 1 +1455 17 48 0 +1456 20 48 0 +1457 20 48 1 +1458 20 49 0 +1459 20 49 1 +1460 21 48 0 +1461 21 48 1 +1462 21 49 0 +1463 21 49 1 +1464 23 49 1 +1465 23 49 0 +1466 23 48 1 +1467 23 48 0 +1468 22 49 1 +1469 22 49 0 +1470 22 48 1 +1471 22 48 0 +1472 28 49 0 +1473 28 49 1 +1474 28 48 0 +1475 28 48 1 +1476 29 49 0 +1477 29 49 1 +1478 29 48 0 +1479 29 48 1 +1480 31 48 1 +1481 31 48 0 +1482 31 49 1 +1483 31 49 0 +1484 30 48 1 +1485 30 48 0 +1486 30 49 1 +1487 30 49 0 +1536 27 51 0 +1537 27 51 1 +1538 27 50 0 +1539 27 50 1 +1540 26 51 0 +1541 26 51 1 +1542 26 50 0 +1543 26 50 1 +1544 24 50 1 +1545 24 50 0 +1546 24 51 1 +1547 24 51 0 +1548 25 50 1 +1549 25 50 0 +1550 25 51 1 +1551 25 51 0 +1568 19 50 0 +1569 19 50 1 +1570 19 51 0 +1571 19 51 1 +1572 18 50 0 +1573 18 50 1 +1574 18 51 0 +1575 18 51 1 +1576 16 51 1 +1577 16 51 0 +1578 16 50 1 +1579 16 50 0 +1580 17 51 1 +1581 17 51 0 +1582 17 50 1 +1583 17 50 0 +1584 20 50 0 +1585 20 50 1 +1586 20 51 0 +1587 20 51 1 +1588 21 50 0 +1589 21 50 1 +1590 21 51 0 +1591 21 51 1 +1592 23 51 1 +1593 23 51 0 +1594 23 50 1 +1595 23 50 0 +1596 22 51 1 +1597 22 51 0 +1598 22 50 1 +1599 22 50 0 +1600 28 51 0 +1601 28 51 1 +1602 28 50 0 +1603 28 50 1 +1604 29 51 0 +1605 29 51 1 +1606 29 50 0 +1607 29 50 1 +1608 31 50 1 +1609 31 50 0 +1610 31 51 1 +1611 31 51 0 +1612 30 50 1 +1613 30 50 0 +1614 30 51 1 +1615 30 51 0 +1664 27 53 0 +1665 27 53 1 +1666 27 52 0 +1667 27 52 1 +1668 26 53 0 +1669 26 53 1 +1670 26 52 0 +1671 26 52 1 +1672 24 52 1 +1673 24 52 0 +1674 24 53 1 +1675 24 53 0 +1676 25 52 1 +1677 25 52 0 +1678 25 53 1 +1679 25 53 0 +1696 19 52 0 +1697 19 52 1 +1698 19 53 0 +1699 19 53 1 +1700 18 52 0 +1701 18 52 1 +1702 18 53 0 +1703 18 53 1 +1704 16 53 1 +1705 16 53 0 +1706 16 52 1 +1707 16 52 0 +1708 17 53 1 +1709 17 53 0 +1710 17 52 1 +1711 17 52 0 +1712 20 52 0 +1713 20 52 1 +1714 20 53 0 +1715 20 53 1 +1716 21 52 0 +1717 21 52 1 +1718 21 53 0 +1719 21 53 1 +1720 23 53 1 +1721 23 53 0 +1722 23 52 1 +1723 23 52 0 +1724 22 53 1 +1725 22 53 0 +1726 22 52 1 +1727 22 52 0 +1728 28 53 0 +1729 28 53 1 +1730 28 52 0 +1731 28 52 1 +1732 29 53 0 +1733 29 53 1 +1734 29 52 0 +1735 29 52 1 +1736 31 52 1 +1737 31 52 0 +1738 31 53 1 +1739 31 53 0 +1740 30 52 1 +1741 30 52 0 +1742 30 53 1 +1743 30 53 0 +1792 27 55 0 +1793 27 55 1 +1794 27 54 0 +1795 27 54 1 +1796 26 55 0 +1797 26 55 1 +1798 26 54 0 +1799 26 54 1 +1800 24 54 1 +1801 24 54 0 +1802 24 55 1 +1803 24 55 0 +1804 25 54 1 +1805 25 54 0 +1806 25 55 1 +1807 25 55 0 +1824 19 54 0 +1825 19 54 1 +1826 19 55 0 +1827 19 55 1 +1828 18 54 0 +1829 18 54 1 +1830 18 55 0 +1831 18 55 1 +1832 16 55 1 +1833 16 55 0 +1834 16 54 1 +1835 16 54 0 +1836 17 55 1 +1837 17 55 0 +1838 17 54 1 +1839 17 54 0 +1840 20 54 0 +1841 20 54 1 +1842 20 55 0 +1843 20 55 1 +1844 21 54 0 +1845 21 54 1 +1846 21 55 0 +1847 21 55 1 +1848 23 55 1 +1849 23 55 0 +1850 23 54 1 +1851 23 54 0 +1852 22 55 1 +1853 22 55 0 +1854 22 54 1 +1855 22 54 0 +1856 28 55 0 +1857 28 55 1 +1858 28 54 0 +1859 28 54 1 +1860 29 55 0 +1861 29 55 1 +1862 29 54 0 +1863 29 54 1 +1864 31 54 1 +1865 31 54 0 +1866 31 55 1 +1867 31 55 0 +1868 30 54 1 +1869 30 54 0 +1870 30 55 1 +1871 30 55 0 +2176 27 27 0 +2177 27 27 1 +2178 27 26 0 +2179 27 26 1 +2180 26 27 0 +2181 26 27 1 +2182 26 26 0 +2183 26 26 1 +2184 24 26 1 +2185 24 26 0 +2186 24 27 1 +2187 24 27 0 +2188 25 26 1 +2189 25 26 0 +2190 25 27 1 +2191 25 27 0 +2208 19 26 0 +2209 19 26 1 +2210 19 27 0 +2211 19 27 1 +2212 18 26 0 +2213 18 26 1 +2214 18 27 0 +2215 18 27 1 +2216 16 27 1 +2217 16 27 0 +2218 16 26 1 +2219 16 26 0 +2220 17 27 1 +2221 17 27 0 +2222 17 26 1 +2223 17 26 0 +2224 20 26 0 +2225 20 26 1 +2226 20 27 0 +2227 20 27 1 +2228 21 26 0 +2229 21 26 1 +2230 21 27 0 +2231 21 27 1 +2232 23 27 1 +2233 23 27 0 +2234 23 26 1 +2235 23 26 0 +2236 22 27 1 +2237 22 27 0 +2238 22 26 1 +2239 22 26 0 +2240 28 27 0 +2241 28 27 1 +2242 28 26 0 +2243 28 26 1 +2244 29 27 0 +2245 29 27 1 +2246 29 26 0 +2247 29 26 1 +2248 31 26 1 +2249 31 26 0 +2250 31 27 1 +2251 31 27 0 +2252 30 26 1 +2253 30 26 0 +2254 30 27 1 +2255 30 27 0 +2304 27 25 0 +2305 27 25 1 +2306 27 24 0 +2307 27 24 1 +2308 26 25 0 +2309 26 25 1 +2310 26 24 0 +2311 26 24 1 +2312 24 24 1 +2313 24 24 0 +2314 24 25 1 +2315 24 25 0 +2316 25 24 1 +2317 25 24 0 +2318 25 25 1 +2319 25 25 0 +2336 19 24 0 +2337 19 24 1 +2338 19 25 0 +2339 19 25 1 +2340 18 24 0 +2341 18 24 1 +2342 18 25 0 +2343 18 25 1 +2344 16 25 1 +2345 16 25 0 +2346 16 24 1 +2347 16 24 0 +2348 17 25 1 +2349 17 25 0 +2350 17 24 1 +2351 17 24 0 +2352 20 24 0 +2353 20 24 1 +2354 20 25 0 +2355 20 25 1 +2356 21 24 0 +2357 21 24 1 +2358 21 25 0 +2359 21 25 1 +2360 23 25 1 +2361 23 25 0 +2362 23 24 1 +2363 23 24 0 +2364 22 25 1 +2365 22 25 0 +2366 22 24 1 +2367 22 24 0 +2368 28 25 0 +2369 28 25 1 +2370 28 24 0 +2371 28 24 1 +2372 29 25 0 +2373 29 25 1 +2374 29 24 0 +2375 29 24 1 +2376 31 24 1 +2377 31 24 0 +2378 31 25 1 +2379 31 25 0 +2380 30 24 1 +2381 30 24 0 +2382 30 25 1 +2383 30 25 0 +2432 27 23 0 +2433 27 23 1 +2434 27 22 0 +2435 27 22 1 +2436 26 23 0 +2437 26 23 1 +2438 26 22 0 +2439 26 22 1 +2440 24 22 1 +2441 24 22 0 +2442 24 23 1 +2443 24 23 0 +2444 25 22 1 +2445 25 22 0 +2446 25 23 1 +2447 25 23 0 +2464 19 22 0 +2465 19 22 1 +2466 19 23 0 +2467 19 23 1 +2468 18 22 0 +2469 18 22 1 +2470 18 23 0 +2471 18 23 1 +2472 16 23 1 +2473 16 23 0 +2474 16 22 1 +2475 16 22 0 +2476 17 23 1 +2477 17 23 0 +2478 17 22 1 +2479 17 22 0 +2480 20 22 0 +2481 20 22 1 +2482 20 23 0 +2483 20 23 1 +2484 21 22 0 +2485 21 22 1 +2486 21 23 0 +2487 21 23 1 +2488 23 23 1 +2489 23 23 0 +2490 23 22 1 +2491 23 22 0 +2492 22 23 1 +2493 22 23 0 +2494 22 22 1 +2495 22 22 0 +2496 28 23 0 +2497 28 23 1 +2498 28 22 0 +2499 28 22 1 +2500 29 23 0 +2501 29 23 1 +2502 29 22 0 +2503 29 22 1 +2504 31 22 1 +2505 31 22 0 +2506 31 23 1 +2507 31 23 0 +2508 30 22 1 +2509 30 22 0 +2510 30 23 1 +2511 30 23 0 +2560 27 21 0 +2561 27 21 1 +2562 27 20 0 +2563 27 20 1 +2564 26 21 0 +2565 26 21 1 +2566 26 20 0 +2567 26 20 1 +2568 24 20 1 +2569 24 20 0 +2570 24 21 1 +2571 24 21 0 +2572 25 20 1 +2573 25 20 0 +2574 25 21 1 +2575 25 21 0 +2592 19 20 0 +2593 19 20 1 +2594 19 21 0 +2595 19 21 1 +2596 18 20 0 +2597 18 20 1 +2598 18 21 0 +2599 18 21 1 +2600 16 21 1 +2601 16 21 0 +2602 16 20 1 +2603 16 20 0 +2604 17 21 1 +2605 17 21 0 +2606 17 20 1 +2607 17 20 0 +2608 20 20 0 +2609 20 20 1 +2610 20 21 0 +2611 20 21 1 +2612 21 20 0 +2613 21 20 1 +2614 21 21 0 +2615 21 21 1 +2616 23 21 1 +2617 23 21 0 +2618 23 20 1 +2619 23 20 0 +2620 22 21 1 +2621 22 21 0 +2622 22 20 1 +2623 22 20 0 +2624 28 21 0 +2625 28 21 1 +2626 28 20 0 +2627 28 20 1 +2628 29 21 0 +2629 29 21 1 +2630 29 20 0 +2631 29 20 1 +2632 31 20 1 +2633 31 20 0 +2634 31 21 1 +2635 31 21 0 +2636 30 20 1 +2637 30 20 0 +2638 30 21 1 +2639 30 21 0 +2688 27 19 0 +2689 27 19 1 +2690 27 18 0 +2691 27 18 1 +2692 26 19 0 +2693 26 19 1 +2694 26 18 0 +2695 26 18 1 +2696 24 18 1 +2697 24 18 0 +2698 24 19 1 +2699 24 19 0 +2700 25 18 1 +2701 25 18 0 +2702 25 19 1 +2703 25 19 0 +2720 19 18 0 +2721 19 18 1 +2722 19 19 0 +2723 19 19 1 +2724 18 18 0 +2725 18 18 1 +2726 18 19 0 +2727 18 19 1 +2728 16 19 1 +2729 16 19 0 +2730 16 18 1 +2731 16 18 0 +2732 17 19 1 +2733 17 19 0 +2734 17 18 1 +2735 17 18 0 +2736 20 18 0 +2737 20 18 1 +2738 20 19 0 +2739 20 19 1 +2740 21 18 0 +2741 21 18 1 +2742 21 19 0 +2743 21 19 1 +2744 23 19 1 +2745 23 19 0 +2746 23 18 1 +2747 23 18 0 +2748 22 19 1 +2749 22 19 0 +2750 22 18 1 +2751 22 18 0 +2752 28 19 0 +2753 28 19 1 +2754 28 18 0 +2755 28 18 1 +2756 29 19 0 +2757 29 19 1 +2758 29 18 0 +2759 29 18 1 +2760 31 18 1 +2761 31 18 0 +2762 31 19 1 +2763 31 19 0 +2764 30 18 1 +2765 30 18 0 +2766 30 19 1 +2767 30 19 0 +2816 27 17 0 +2817 27 17 1 +2818 27 16 0 +2819 27 16 1 +2820 26 17 0 +2821 26 17 1 +2822 26 16 0 +2823 26 16 1 +2824 24 16 1 +2825 24 16 0 +2826 24 17 1 +2827 24 17 0 +2828 25 16 1 +2829 25 16 0 +2830 25 17 1 +2831 25 17 0 +2848 19 16 0 +2849 19 16 1 +2850 19 17 0 +2851 19 17 1 +2852 18 16 0 +2853 18 16 1 +2854 18 17 0 +2855 18 17 1 +2856 16 17 1 +2857 16 17 0 +2858 16 16 1 +2859 16 16 0 +2860 17 17 1 +2861 17 17 0 +2862 17 16 1 +2863 17 16 0 +2864 20 16 0 +2865 20 16 1 +2866 20 17 0 +2867 20 17 1 +2868 21 16 0 +2869 21 16 1 +2870 21 17 0 +2871 21 17 1 +2872 23 17 1 +2873 23 17 0 +2874 23 16 1 +2875 23 16 0 +2876 22 17 1 +2877 22 17 0 +2878 22 16 1 +2879 22 16 0 +2880 28 17 0 +2881 28 17 1 +2882 28 16 0 +2883 28 16 1 +2884 29 17 0 +2885 29 17 1 +2886 29 16 0 +2887 29 16 1 +2888 31 16 1 +2889 31 16 0 +2890 31 17 1 +2891 31 17 0 +2892 30 16 1 +2893 30 16 0 +2894 30 17 1 +2895 30 17 0 +2944 27 15 0 +2945 27 15 1 +2946 27 14 0 +2947 27 14 1 +2948 26 15 0 +2949 26 15 1 +2950 26 14 0 +2951 26 14 1 +2952 24 14 1 +2953 24 14 0 +2954 24 15 1 +2955 24 15 0 +2956 25 14 1 +2957 25 14 0 +2958 25 15 1 +2959 25 15 0 +2976 19 14 0 +2977 19 14 1 +2978 19 15 0 +2979 19 15 1 +2980 18 14 0 +2981 18 14 1 +2982 18 15 0 +2983 18 15 1 +2984 16 15 1 +2985 16 15 0 +2986 16 14 1 +2987 16 14 0 +2988 17 15 1 +2989 17 15 0 +2990 17 14 1 +2991 17 14 0 +2992 20 14 0 +2993 20 14 1 +2994 20 15 0 +2995 20 15 1 +2996 21 14 0 +2997 21 14 1 +2998 21 15 0 +2999 21 15 1 +3000 23 15 1 +3001 23 15 0 +3002 23 14 1 +3003 23 14 0 +3004 22 15 1 +3005 22 15 0 +3006 22 14 1 +3007 22 14 0 +3008 28 15 0 +3009 28 15 1 +3010 28 14 0 +3011 28 14 1 +3012 29 15 0 +3013 29 15 1 +3014 29 14 0 +3015 29 14 1 +3016 31 14 1 +3017 31 14 0 +3018 31 15 1 +3019 31 15 0 +3020 30 14 1 +3021 30 14 0 +3022 30 15 1 +3023 30 15 0 +3072 27 13 0 +3073 27 13 1 +3074 27 12 0 +3075 27 12 1 +3076 26 13 0 +3077 26 13 1 +3078 26 12 0 +3079 26 12 1 +3080 24 12 1 +3081 24 12 0 +3082 24 13 1 +3083 24 13 0 +3084 25 12 1 +3085 25 12 0 +3086 25 13 1 +3087 25 13 0 +3104 19 12 0 +3105 19 12 1 +3106 19 13 0 +3107 19 13 1 +3108 18 12 0 +3109 18 12 1 +3110 18 13 0 +3111 18 13 1 +3112 16 13 1 +3113 16 13 0 +3114 16 12 1 +3115 16 12 0 +3116 17 13 1 +3117 17 13 0 +3118 17 12 1 +3119 17 12 0 +3120 20 12 0 +3121 20 12 1 +3122 20 13 0 +3123 20 13 1 +3124 21 12 0 +3125 21 12 1 +3126 21 13 0 +3127 21 13 1 +3128 23 13 1 +3129 23 13 0 +3130 23 12 1 +3131 23 12 0 +3132 22 13 1 +3133 22 13 0 +3134 22 12 1 +3135 22 12 0 +3136 28 13 0 +3137 28 13 1 +3138 28 12 0 +3139 28 12 1 +3140 29 13 0 +3141 29 13 1 +3142 29 12 0 +3143 29 12 1 +3144 31 12 1 +3145 31 12 0 +3146 31 13 1 +3147 31 13 0 +3148 30 12 1 +3149 30 12 0 +3150 30 13 1 +3151 30 13 0 +3200 27 11 0 +3201 27 11 1 +3202 27 10 0 +3203 27 10 1 +3204 26 11 0 +3205 26 11 1 +3206 26 10 0 +3207 26 10 1 +3208 24 10 1 +3209 24 10 0 +3210 24 11 1 +3211 24 11 0 +3212 25 10 1 +3213 25 10 0 +3214 25 11 1 +3215 25 11 0 +3232 19 10 0 +3233 19 10 1 +3234 19 11 0 +3235 19 11 1 +3236 18 10 0 +3237 18 10 1 +3238 18 11 0 +3239 18 11 1 +3240 16 11 1 +3241 16 11 0 +3242 16 10 1 +3243 16 10 0 +3244 17 11 1 +3245 17 11 0 +3246 17 10 1 +3247 17 10 0 +3248 20 10 0 +3249 20 10 1 +3250 20 11 0 +3251 20 11 1 +3252 21 10 0 +3253 21 10 1 +3254 21 11 0 +3255 21 11 1 +3256 23 11 1 +3257 23 11 0 +3258 23 10 1 +3259 23 10 0 +3260 22 11 1 +3261 22 11 0 +3262 22 10 1 +3263 22 10 0 +3264 28 11 0 +3265 28 11 1 +3266 28 10 0 +3267 28 10 1 +3268 29 11 0 +3269 29 11 1 +3270 29 10 0 +3271 29 10 1 +3272 31 10 1 +3273 31 10 0 +3274 31 11 1 +3275 31 11 0 +3276 30 10 1 +3277 30 10 0 +3278 30 11 1 +3279 30 11 0 +3328 27 9 0 +3329 27 9 1 +3330 27 8 0 +3331 27 8 1 +3332 26 9 0 +3333 26 9 1 +3334 26 8 0 +3335 26 8 1 +3336 24 8 1 +3337 24 8 0 +3338 24 9 1 +3339 24 9 0 +3340 25 8 1 +3341 25 8 0 +3342 25 9 1 +3343 25 9 0 +3360 19 8 0 +3361 19 8 1 +3362 19 9 0 +3363 19 9 1 +3364 18 8 0 +3365 18 8 1 +3366 18 9 0 +3367 18 9 1 +3368 16 9 1 +3369 16 9 0 +3370 16 8 1 +3371 16 8 0 +3372 17 9 1 +3373 17 9 0 +3374 17 8 1 +3375 17 8 0 +3376 20 8 0 +3377 20 8 1 +3378 20 9 0 +3379 20 9 1 +3380 21 8 0 +3381 21 8 1 +3382 21 9 0 +3383 21 9 1 +3384 23 9 1 +3385 23 9 0 +3386 23 8 1 +3387 23 8 0 +3388 22 9 1 +3389 22 9 0 +3390 22 8 1 +3391 22 8 0 +3392 28 9 0 +3393 28 9 1 +3394 28 8 0 +3395 28 8 1 +3396 29 9 0 +3397 29 9 1 +3398 29 8 0 +3399 29 8 1 +3400 31 8 1 +3401 31 8 0 +3402 31 9 1 +3403 31 9 0 +3404 30 8 1 +3405 30 8 0 +3406 30 9 1 +3407 30 9 0 +3456 27 7 0 +3457 27 7 1 +3458 27 6 0 +3459 27 6 1 +3460 26 7 0 +3461 26 7 1 +3462 26 6 0 +3463 26 6 1 +3464 24 6 1 +3465 24 6 0 +3466 24 7 1 +3467 24 7 0 +3468 25 6 1 +3469 25 6 0 +3470 25 7 1 +3471 25 7 0 +3488 19 6 0 +3489 19 6 1 +3490 19 7 0 +3491 19 7 1 +3492 18 6 0 +3493 18 6 1 +3494 18 7 0 +3495 18 7 1 +3496 16 7 1 +3497 16 7 0 +3498 16 6 1 +3499 16 6 0 +3500 17 7 1 +3501 17 7 0 +3502 17 6 1 +3503 17 6 0 +3504 20 6 0 +3505 20 6 1 +3506 20 7 0 +3507 20 7 1 +3508 21 6 0 +3509 21 6 1 +3510 21 7 0 +3511 21 7 1 +3512 23 7 1 +3513 23 7 0 +3514 23 6 1 +3515 23 6 0 +3516 22 7 1 +3517 22 7 0 +3518 22 6 1 +3519 22 6 0 +3520 28 7 0 +3521 28 7 1 +3522 28 6 0 +3523 28 6 1 +3524 29 7 0 +3525 29 7 1 +3526 29 6 0 +3527 29 6 1 +3528 31 6 1 +3529 31 6 0 +3530 31 7 1 +3531 31 7 0 +3532 30 6 1 +3533 30 6 0 +3534 30 7 1 +3535 30 7 0 +3584 27 5 0 +3585 27 5 1 +3586 27 4 0 +3587 27 4 1 +3588 26 5 0 +3589 26 5 1 +3590 26 4 0 +3591 26 4 1 +3592 24 4 1 +3593 24 4 0 +3594 24 5 1 +3595 24 5 0 +3596 25 4 1 +3597 25 4 0 +3598 25 5 1 +3599 25 5 0 +3616 19 4 0 +3617 19 4 1 +3618 19 5 0 +3619 19 5 1 +3620 18 4 0 +3621 18 4 1 +3622 18 5 0 +3623 18 5 1 +3624 16 5 1 +3625 16 5 0 +3626 16 4 1 +3627 16 4 0 +3628 17 5 1 +3629 17 5 0 +3630 17 4 1 +3631 17 4 0 +3632 20 4 0 +3633 20 4 1 +3634 20 5 0 +3635 20 5 1 +3636 21 4 0 +3637 21 4 1 +3638 21 5 0 +3639 21 5 1 +3640 23 5 1 +3641 23 5 0 +3642 23 4 1 +3643 23 4 0 +3644 22 5 1 +3645 22 5 0 +3646 22 4 1 +3647 22 4 0 +3648 28 5 0 +3649 28 5 1 +3650 28 4 0 +3651 28 4 1 +3652 29 5 0 +3653 29 5 1 +3654 29 4 0 +3655 29 4 1 +3656 31 4 1 +3657 31 4 0 +3658 31 5 1 +3659 31 5 0 +3660 30 4 1 +3661 30 4 0 +3662 30 5 1 +3663 30 5 0 +3712 27 3 0 +3713 27 3 1 +3714 27 2 0 +3715 27 2 1 +3716 26 3 0 +3717 26 3 1 +3718 26 2 0 +3719 26 2 1 +3720 24 2 1 +3721 24 2 0 +3722 24 3 1 +3723 24 3 0 +3724 25 2 1 +3725 25 2 0 +3726 25 3 1 +3727 25 3 0 +3744 19 2 0 +3745 19 2 1 +3746 19 3 0 +3747 19 3 1 +3748 18 2 0 +3749 18 2 1 +3750 18 3 0 +3751 18 3 1 +3752 16 3 1 +3753 16 3 0 +3754 16 2 1 +3755 16 2 0 +3756 17 3 1 +3757 17 3 0 +3758 17 2 1 +3759 17 2 0 +3760 20 2 0 +3761 20 2 1 +3762 20 3 0 +3763 20 3 1 +3764 21 2 0 +3765 21 2 1 +3766 21 3 0 +3767 21 3 1 +3768 23 3 1 +3769 23 3 0 +3770 23 2 1 +3771 23 2 0 +3772 22 3 1 +3773 22 3 0 +3774 22 2 1 +3775 22 2 0 +3776 28 3 0 +3777 28 3 1 +3778 28 2 0 +3779 28 2 1 +3780 29 3 0 +3781 29 3 1 +3782 29 2 0 +3783 29 2 1 +3784 31 2 1 +3785 31 2 0 +3786 31 3 1 +3787 31 3 0 +3788 30 2 1 +3789 30 2 0 +3790 30 3 1 +3791 30 3 0 +3840 27 1 0 +3841 27 1 1 +3842 27 0 0 +3843 27 0 1 +3844 26 1 0 +3845 26 1 1 +3846 26 0 0 +3847 26 0 1 +3848 24 0 1 +3849 24 0 0 +3850 24 1 1 +3851 24 1 0 +3852 25 0 1 +3853 25 0 0 +3854 25 1 1 +3855 25 1 0 +3872 19 0 0 +3873 19 0 1 +3874 19 1 0 +3875 19 1 1 +3876 18 0 0 +3877 18 0 1 +3878 18 1 0 +3879 18 1 1 +3880 16 1 1 +3881 16 1 0 +3882 16 0 1 +3883 16 0 0 +3884 17 1 1 +3885 17 1 0 +3886 17 0 1 +3887 17 0 0 +3888 20 0 0 +3889 20 0 1 +3890 20 1 0 +3891 20 1 1 +3892 21 0 0 +3893 21 0 1 +3894 21 1 0 +3895 21 1 1 +3896 23 1 1 +3897 23 1 0 +3898 23 0 1 +3899 23 0 0 +3900 22 1 1 +3901 22 1 0 +3902 22 0 1 +3903 22 0 0 +3904 28 1 0 +3905 28 1 1 +3906 28 0 0 +3907 28 0 1 +3908 29 1 0 +3909 29 1 1 +3910 29 0 0 +3911 29 0 1 +3912 31 0 1 +3913 31 0 0 +3914 31 1 1 +3915 31 1 0 +3916 30 0 1 +3917 30 0 0 +3918 30 1 1 +3919 30 1 0 diff --git a/Detectors/PHOS/base/files/Mod1RCU2.data b/Detectors/PHOS/base/files/Mod1RCU2.data new file mode 100644 index 0000000000000..21de94d7ace53 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod1RCU2.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 2 0 2 + 1 2 1 2 + 2 2 2 2 + 3 2 3 2 + 4 2 4 2 + 5 2 5 2 + 6 2 6 2 + 7 2 7 2 + 8 2 8 2 + 9 2 9 2 + 10 2 10 2 + 11 2 11 2 + 12 2 12 2 + 13 2 13 2 + 14 2 14 2 + 15 2 15 2 + 16 2 16 2 + 17 2 17 2 + 18 2 18 2 + 19 2 19 2 + 20 2 20 2 + 21 2 21 2 + 22 2 22 2 + 23 2 23 2 + 24 2 24 2 + 25 2 25 2 + 26 2 26 2 + 27 2 27 2 + 28 2 28 2 + 29 2 29 2 + 30 2 30 2 + 31 2 31 2 + 32 2 32 2 + 33 2 33 2 + 34 2 34 2 + 35 2 35 2 + 36 2 36 2 + 37 2 37 2 + 38 2 38 2 + 39 2 39 2 + 40 2 40 2 + 41 2 41 2 + 42 2 42 2 + 43 2 43 2 + 44 2 44 2 + 45 2 45 2 + 46 2 46 2 + 47 2 47 2 + 48 2 48 2 + 49 2 49 2 + 50 2 50 2 + 51 2 51 2 + 52 2 52 2 + 53 2 53 2 + 54 2 54 2 + 55 2 55 2 + 56 2 56 2 + 57 2 57 2 + 58 2 58 2 + 59 2 59 2 + 60 2 60 2 + 61 2 61 2 + 62 2 62 2 + 63 2 63 2 + 64 2 64 2 + 65 2 65 2 + 66 2 66 2 + 67 2 67 2 + 68 2 68 2 + 69 2 69 2 + 70 2 70 2 + 71 2 71 2 + 72 2 72 2 + 73 2 73 2 + 74 2 74 2 + 75 2 75 2 + 76 2 76 2 + 77 2 77 2 + 78 2 78 2 + 79 2 79 2 + 80 2 80 2 + 81 2 81 2 + 82 2 82 2 + 83 2 83 2 + 84 2 84 2 + 85 2 85 2 + 86 2 86 2 + 87 2 87 2 + 88 2 88 2 + 89 2 89 2 + 90 2 90 2 + 91 2 91 2 + 92 2 92 2 + 93 2 93 2 + 94 2 94 2 + 95 2 95 2 + 96 2 96 2 + 97 2 97 2 + 98 2 98 2 + 99 2 99 2 + 100 2 100 2 + 101 2 101 2 + 102 2 102 2 + 103 2 103 2 + 104 2 104 2 + 105 2 105 2 + 106 2 106 2 + 107 2 107 2 + 108 2 108 2 + 109 2 109 2 + 110 2 110 2 + 111 2 111 2 + 112 2 112 2 + 113 2 113 2 + 114 2 114 2 + 115 2 115 2 + 116 2 116 2 + 117 2 117 2 + 118 2 118 2 + 119 2 119 2 + 120 2 120 2 + 121 2 121 2 + 122 2 122 2 + 123 2 123 2 + 124 2 124 2 + 125 2 125 2 + 126 2 126 2 + 127 2 127 2 +2048 2 2048 2 +2049 2 2049 2 +2050 2 2050 2 +2051 2 2051 2 +2052 2 2052 2 +2053 2 2053 2 +2054 2 2054 2 +2055 2 2055 2 +2056 2 2056 2 +2057 2 2057 2 +2058 2 2058 2 +2059 2 2059 2 +2060 2 2060 2 +2061 2 2061 2 +2062 2 2062 2 +2063 2 2063 2 +2064 2 2064 2 +2065 2 2065 2 +2066 2 2066 2 +2067 2 2067 2 +2068 2 2068 2 +2069 2 2069 2 +2070 2 2070 2 +2071 2 2071 2 +2072 2 2072 2 +2073 2 2073 2 +2074 2 2074 2 +2075 2 2075 2 +2076 2 2076 2 +2077 2 2077 2 +2078 2 2078 2 +2079 2 2079 2 +2080 2 2080 2 +2081 2 2081 2 +2082 2 2082 2 +2083 2 2083 2 +2084 2 2084 2 +2085 2 2085 2 +2086 2 2086 2 +2087 2 2087 2 +2088 2 2088 2 +2089 2 2089 2 +2090 2 2090 2 +2091 2 2091 2 +2092 2 2092 2 +2093 2 2093 2 +2094 2 2094 2 +2095 2 2095 2 +2096 2 2096 2 +2097 2 2097 2 +2098 2 2098 2 +2099 2 2099 2 +2100 2 2100 2 +2101 2 2101 2 +2102 2 2102 2 +2103 2 2103 2 +2104 2 2104 2 +2105 2 2105 2 +2106 2 2106 2 +2107 2 2107 2 +2108 2 2108 2 +2109 2 2109 2 +2110 2 2110 2 +2111 2 2111 2 +2112 2 2112 2 +2113 2 2113 2 +2114 2 2114 2 +2115 2 2115 2 +2116 2 2116 2 +2117 2 2117 2 +2118 2 2118 2 +2119 2 2119 2 +2120 2 2120 2 +2121 2 2121 2 +2122 2 2122 2 +2123 2 2123 2 +2124 2 2124 2 +2125 2 2125 2 +2126 2 2126 2 +2127 2 2127 2 +2128 2 2128 2 +2129 2 2129 2 +2130 2 2130 2 +2131 2 2131 2 +2132 2 2132 2 +2133 2 2133 2 +2134 2 2134 2 +2135 2 2135 2 +2136 2 2136 2 +2137 2 2137 2 +2138 2 2138 2 +2139 2 2139 2 +2140 2 2140 2 +2141 2 2141 2 +2142 2 2142 2 +2143 2 2143 2 +2144 2 2144 2 +2145 2 2145 2 +2146 2 2146 2 +2147 2 2147 2 +2148 2 2148 2 +2149 2 2149 2 +2150 2 2150 2 +2151 2 2151 2 +2152 2 2152 2 +2153 2 2153 2 +2154 2 2154 2 +2155 2 2155 2 +2156 2 2156 2 +2157 2 2157 2 +2158 2 2158 2 +2159 2 2159 2 +2160 2 2160 2 +2161 2 2161 2 +2162 2 2162 2 +2163 2 2163 2 +2164 2 2164 2 +2165 2 2165 2 +2166 2 2166 2 +2167 2 2167 2 +2168 2 2168 2 +2169 2 2169 2 +2170 2 2170 2 +2171 2 2171 2 +2172 2 2172 2 +2173 2 2173 2 +2174 2 2174 2 +2175 2 2175 2 + 128 43 29 0 + 129 43 29 1 + 130 43 28 0 + 131 43 28 1 + 132 42 29 0 + 133 42 29 1 + 134 42 28 0 + 135 42 28 1 + 136 40 28 1 + 137 40 28 0 + 138 40 29 1 + 139 40 29 0 + 140 41 28 1 + 141 41 28 0 + 142 41 29 1 + 143 41 29 0 + 160 35 28 0 + 161 35 28 1 + 162 35 29 0 + 163 35 29 1 + 164 34 28 0 + 165 34 28 1 + 166 34 29 0 + 167 34 29 1 + 168 32 29 1 + 169 32 29 0 + 170 32 28 1 + 171 32 28 0 + 172 33 29 1 + 173 33 29 0 + 174 33 28 1 + 175 33 28 0 + 176 36 28 0 + 177 36 28 1 + 178 36 29 0 + 179 36 29 1 + 180 37 28 0 + 181 37 28 1 + 182 37 29 0 + 183 37 29 1 + 184 39 29 1 + 185 39 29 0 + 186 39 28 1 + 187 39 28 0 + 188 38 29 1 + 189 38 29 0 + 190 38 28 1 + 191 38 28 0 + 192 44 29 0 + 193 44 29 1 + 194 44 28 0 + 195 44 28 1 + 196 45 29 0 + 197 45 29 1 + 198 45 28 0 + 199 45 28 1 + 200 47 28 1 + 201 47 28 0 + 202 47 29 1 + 203 47 29 0 + 204 46 28 1 + 205 46 28 0 + 206 46 29 1 + 207 46 29 0 + 256 43 31 0 + 257 43 31 1 + 258 43 30 0 + 259 43 30 1 + 260 42 31 0 + 261 42 31 1 + 262 42 30 0 + 263 42 30 1 + 264 40 30 1 + 265 40 30 0 + 266 40 31 1 + 267 40 31 0 + 268 41 30 1 + 269 41 30 0 + 270 41 31 1 + 271 41 31 0 + 288 35 30 0 + 289 35 30 1 + 290 35 31 0 + 291 35 31 1 + 292 34 30 0 + 293 34 30 1 + 294 34 31 0 + 295 34 31 1 + 296 32 31 1 + 297 32 31 0 + 298 32 30 1 + 299 32 30 0 + 300 33 31 1 + 301 33 31 0 + 302 33 30 1 + 303 33 30 0 + 304 36 30 0 + 305 36 30 1 + 306 36 31 0 + 307 36 31 1 + 308 37 30 0 + 309 37 30 1 + 310 37 31 0 + 311 37 31 1 + 312 39 31 1 + 313 39 31 0 + 314 39 30 1 + 315 39 30 0 + 316 38 31 1 + 317 38 31 0 + 318 38 30 1 + 319 38 30 0 + 320 44 31 0 + 321 44 31 1 + 322 44 30 0 + 323 44 30 1 + 324 45 31 0 + 325 45 31 1 + 326 45 30 0 + 327 45 30 1 + 328 47 30 1 + 329 47 30 0 + 330 47 31 1 + 331 47 31 0 + 332 46 30 1 + 333 46 30 0 + 334 46 31 1 + 335 46 31 0 + 384 43 33 0 + 385 43 33 1 + 386 43 32 0 + 387 43 32 1 + 388 42 33 0 + 389 42 33 1 + 390 42 32 0 + 391 42 32 1 + 392 40 32 1 + 393 40 32 0 + 394 40 33 1 + 395 40 33 0 + 396 41 32 1 + 397 41 32 0 + 398 41 33 1 + 399 41 33 0 + 416 35 32 0 + 417 35 32 1 + 418 35 33 0 + 419 35 33 1 + 420 34 32 0 + 421 34 32 1 + 422 34 33 0 + 423 34 33 1 + 424 32 33 1 + 425 32 33 0 + 426 32 32 1 + 427 32 32 0 + 428 33 33 1 + 429 33 33 0 + 430 33 32 1 + 431 33 32 0 + 432 36 32 0 + 433 36 32 1 + 434 36 33 0 + 435 36 33 1 + 436 37 32 0 + 437 37 32 1 + 438 37 33 0 + 439 37 33 1 + 440 39 33 1 + 441 39 33 0 + 442 39 32 1 + 443 39 32 0 + 444 38 33 1 + 445 38 33 0 + 446 38 32 1 + 447 38 32 0 + 448 44 33 0 + 449 44 33 1 + 450 44 32 0 + 451 44 32 1 + 452 45 33 0 + 453 45 33 1 + 454 45 32 0 + 455 45 32 1 + 456 47 32 1 + 457 47 32 0 + 458 47 33 1 + 459 47 33 0 + 460 46 32 1 + 461 46 32 0 + 462 46 33 1 + 463 46 33 0 + 512 43 35 0 + 513 43 35 1 + 514 43 34 0 + 515 43 34 1 + 516 42 35 0 + 517 42 35 1 + 518 42 34 0 + 519 42 34 1 + 520 40 34 1 + 521 40 34 0 + 522 40 35 1 + 523 40 35 0 + 524 41 34 1 + 525 41 34 0 + 526 41 35 1 + 527 41 35 0 + 544 35 34 0 + 545 35 34 1 + 546 35 35 0 + 547 35 35 1 + 548 34 34 0 + 549 34 34 1 + 550 34 35 0 + 551 34 35 1 + 552 32 35 1 + 553 32 35 0 + 554 32 34 1 + 555 32 34 0 + 556 33 35 1 + 557 33 35 0 + 558 33 34 1 + 559 33 34 0 + 560 36 34 0 + 561 36 34 1 + 562 36 35 0 + 563 36 35 1 + 564 37 34 0 + 565 37 34 1 + 566 37 35 0 + 567 37 35 1 + 568 39 35 1 + 569 39 35 0 + 570 39 34 1 + 571 39 34 0 + 572 38 35 1 + 573 38 35 0 + 574 38 34 1 + 575 38 34 0 + 576 44 35 0 + 577 44 35 1 + 578 44 34 0 + 579 44 34 1 + 580 45 35 0 + 581 45 35 1 + 582 45 34 0 + 583 45 34 1 + 584 47 34 1 + 585 47 34 0 + 586 47 35 1 + 587 47 35 0 + 588 46 34 1 + 589 46 34 0 + 590 46 35 1 + 591 46 35 0 + 640 43 37 0 + 641 43 37 1 + 642 43 36 0 + 643 43 36 1 + 644 42 37 0 + 645 42 37 1 + 646 42 36 0 + 647 42 36 1 + 648 40 36 1 + 649 40 36 0 + 650 40 37 1 + 651 40 37 0 + 652 41 36 1 + 653 41 36 0 + 654 41 37 1 + 655 41 37 0 + 672 35 36 0 + 673 35 36 1 + 674 35 37 0 + 675 35 37 1 + 676 34 36 0 + 677 34 36 1 + 678 34 37 0 + 679 34 37 1 + 680 32 37 1 + 681 32 37 0 + 682 32 36 1 + 683 32 36 0 + 684 33 37 1 + 685 33 37 0 + 686 33 36 1 + 687 33 36 0 + 688 36 36 0 + 689 36 36 1 + 690 36 37 0 + 691 36 37 1 + 692 37 36 0 + 693 37 36 1 + 694 37 37 0 + 695 37 37 1 + 696 39 37 1 + 697 39 37 0 + 698 39 36 1 + 699 39 36 0 + 700 38 37 1 + 701 38 37 0 + 702 38 36 1 + 703 38 36 0 + 704 44 37 0 + 705 44 37 1 + 706 44 36 0 + 707 44 36 1 + 708 45 37 0 + 709 45 37 1 + 710 45 36 0 + 711 45 36 1 + 712 47 36 1 + 713 47 36 0 + 714 47 37 1 + 715 47 37 0 + 716 46 36 1 + 717 46 36 0 + 718 46 37 1 + 719 46 37 0 + 768 43 39 0 + 769 43 39 1 + 770 43 38 0 + 771 43 38 1 + 772 42 39 0 + 773 42 39 1 + 774 42 38 0 + 775 42 38 1 + 776 40 38 1 + 777 40 38 0 + 778 40 39 1 + 779 40 39 0 + 780 41 38 1 + 781 41 38 0 + 782 41 39 1 + 783 41 39 0 + 800 35 38 0 + 801 35 38 1 + 802 35 39 0 + 803 35 39 1 + 804 34 38 0 + 805 34 38 1 + 806 34 39 0 + 807 34 39 1 + 808 32 39 1 + 809 32 39 0 + 810 32 38 1 + 811 32 38 0 + 812 33 39 1 + 813 33 39 0 + 814 33 38 1 + 815 33 38 0 + 816 36 38 0 + 817 36 38 1 + 818 36 39 0 + 819 36 39 1 + 820 37 38 0 + 821 37 38 1 + 822 37 39 0 + 823 37 39 1 + 824 39 39 1 + 825 39 39 0 + 826 39 38 1 + 827 39 38 0 + 828 38 39 1 + 829 38 39 0 + 830 38 38 1 + 831 38 38 0 + 832 44 39 0 + 833 44 39 1 + 834 44 38 0 + 835 44 38 1 + 836 45 39 0 + 837 45 39 1 + 838 45 38 0 + 839 45 38 1 + 840 47 38 1 + 841 47 38 0 + 842 47 39 1 + 843 47 39 0 + 844 46 38 1 + 845 46 38 0 + 846 46 39 1 + 847 46 39 0 + 896 43 41 0 + 897 43 41 1 + 898 43 40 0 + 899 43 40 1 + 900 42 41 0 + 901 42 41 1 + 902 42 40 0 + 903 42 40 1 + 904 40 40 1 + 905 40 40 0 + 906 40 41 1 + 907 40 41 0 + 908 41 40 1 + 909 41 40 0 + 910 41 41 1 + 911 41 41 0 + 928 35 40 0 + 929 35 40 1 + 930 35 41 0 + 931 35 41 1 + 932 34 40 0 + 933 34 40 1 + 934 34 41 0 + 935 34 41 1 + 936 32 41 1 + 937 32 41 0 + 938 32 40 1 + 939 32 40 0 + 940 33 41 1 + 941 33 41 0 + 942 33 40 1 + 943 33 40 0 + 944 36 40 0 + 945 36 40 1 + 946 36 41 0 + 947 36 41 1 + 948 37 40 0 + 949 37 40 1 + 950 37 41 0 + 951 37 41 1 + 952 39 41 1 + 953 39 41 0 + 954 39 40 1 + 955 39 40 0 + 956 38 41 1 + 957 38 41 0 + 958 38 40 1 + 959 38 40 0 + 960 44 41 0 + 961 44 41 1 + 962 44 40 0 + 963 44 40 1 + 964 45 41 0 + 965 45 41 1 + 966 45 40 0 + 967 45 40 1 + 968 47 40 1 + 969 47 40 0 + 970 47 41 1 + 971 47 41 0 + 972 46 40 1 + 973 46 40 0 + 974 46 41 1 + 975 46 41 0 +1024 43 43 0 +1025 43 43 1 +1026 43 42 0 +1027 43 42 1 +1028 42 43 0 +1029 42 43 1 +1030 42 42 0 +1031 42 42 1 +1032 40 42 1 +1033 40 42 0 +1034 40 43 1 +1035 40 43 0 +1036 41 42 1 +1037 41 42 0 +1038 41 43 1 +1039 41 43 0 +1056 35 42 0 +1057 35 42 1 +1058 35 43 0 +1059 35 43 1 +1060 34 42 0 +1061 34 42 1 +1062 34 43 0 +1063 34 43 1 +1064 32 43 1 +1065 32 43 0 +1066 32 42 1 +1067 32 42 0 +1068 33 43 1 +1069 33 43 0 +1070 33 42 1 +1071 33 42 0 +1072 36 42 0 +1073 36 42 1 +1074 36 43 0 +1075 36 43 1 +1076 37 42 0 +1077 37 42 1 +1078 37 43 0 +1079 37 43 1 +1080 39 43 1 +1081 39 43 0 +1082 39 42 1 +1083 39 42 0 +1084 38 43 1 +1085 38 43 0 +1086 38 42 1 +1087 38 42 0 +1088 44 43 0 +1089 44 43 1 +1090 44 42 0 +1091 44 42 1 +1092 45 43 0 +1093 45 43 1 +1094 45 42 0 +1095 45 42 1 +1096 47 42 1 +1097 47 42 0 +1098 47 43 1 +1099 47 43 0 +1100 46 42 1 +1101 46 42 0 +1102 46 43 1 +1103 46 43 0 +1152 43 45 0 +1153 43 45 1 +1154 43 44 0 +1155 43 44 1 +1156 42 45 0 +1157 42 45 1 +1158 42 44 0 +1159 42 44 1 +1160 40 44 1 +1161 40 44 0 +1162 40 45 1 +1163 40 45 0 +1164 41 44 1 +1165 41 44 0 +1166 41 45 1 +1167 41 45 0 +1184 35 44 0 +1185 35 44 1 +1186 35 45 0 +1187 35 45 1 +1188 34 44 0 +1189 34 44 1 +1190 34 45 0 +1191 34 45 1 +1192 32 45 1 +1193 32 45 0 +1194 32 44 1 +1195 32 44 0 +1196 33 45 1 +1197 33 45 0 +1198 33 44 1 +1199 33 44 0 +1200 36 44 0 +1201 36 44 1 +1202 36 45 0 +1203 36 45 1 +1204 37 44 0 +1205 37 44 1 +1206 37 45 0 +1207 37 45 1 +1208 39 45 1 +1209 39 45 0 +1210 39 44 1 +1211 39 44 0 +1212 38 45 1 +1213 38 45 0 +1214 38 44 1 +1215 38 44 0 +1216 44 45 0 +1217 44 45 1 +1218 44 44 0 +1219 44 44 1 +1220 45 45 0 +1221 45 45 1 +1222 45 44 0 +1223 45 44 1 +1224 47 44 1 +1225 47 44 0 +1226 47 45 1 +1227 47 45 0 +1228 46 44 1 +1229 46 44 0 +1230 46 45 1 +1231 46 45 0 +1280 43 47 0 +1281 43 47 1 +1282 43 46 0 +1283 43 46 1 +1284 42 47 0 +1285 42 47 1 +1286 42 46 0 +1287 42 46 1 +1288 40 46 1 +1289 40 46 0 +1290 40 47 1 +1291 40 47 0 +1292 41 46 1 +1293 41 46 0 +1294 41 47 1 +1295 41 47 0 +1312 35 46 0 +1313 35 46 1 +1314 35 47 0 +1315 35 47 1 +1316 34 46 0 +1317 34 46 1 +1318 34 47 0 +1319 34 47 1 +1320 32 47 1 +1321 32 47 0 +1322 32 46 1 +1323 32 46 0 +1324 33 47 1 +1325 33 47 0 +1326 33 46 1 +1327 33 46 0 +1328 36 46 0 +1329 36 46 1 +1330 36 47 0 +1331 36 47 1 +1332 37 46 0 +1333 37 46 1 +1334 37 47 0 +1335 37 47 1 +1336 39 47 1 +1337 39 47 0 +1338 39 46 1 +1339 39 46 0 +1340 38 47 1 +1341 38 47 0 +1342 38 46 1 +1343 38 46 0 +1344 44 47 0 +1345 44 47 1 +1346 44 46 0 +1347 44 46 1 +1348 45 47 0 +1349 45 47 1 +1350 45 46 0 +1351 45 46 1 +1352 47 46 1 +1353 47 46 0 +1354 47 47 1 +1355 47 47 0 +1356 46 46 1 +1357 46 46 0 +1358 46 47 1 +1359 46 47 0 +1408 43 49 0 +1409 43 49 1 +1410 43 48 0 +1411 43 48 1 +1412 42 49 0 +1413 42 49 1 +1414 42 48 0 +1415 42 48 1 +1416 40 48 1 +1417 40 48 0 +1418 40 49 1 +1419 40 49 0 +1420 41 48 1 +1421 41 48 0 +1422 41 49 1 +1423 41 49 0 +1440 35 48 0 +1441 35 48 1 +1442 35 49 0 +1443 35 49 1 +1444 34 48 0 +1445 34 48 1 +1446 34 49 0 +1447 34 49 1 +1448 32 49 1 +1449 32 49 0 +1450 32 48 1 +1451 32 48 0 +1452 33 49 1 +1453 33 49 0 +1454 33 48 1 +1455 33 48 0 +1456 36 48 0 +1457 36 48 1 +1458 36 49 0 +1459 36 49 1 +1460 37 48 0 +1461 37 48 1 +1462 37 49 0 +1463 37 49 1 +1464 39 49 1 +1465 39 49 0 +1466 39 48 1 +1467 39 48 0 +1468 38 49 1 +1469 38 49 0 +1470 38 48 1 +1471 38 48 0 +1472 44 49 0 +1473 44 49 1 +1474 44 48 0 +1475 44 48 1 +1476 45 49 0 +1477 45 49 1 +1478 45 48 0 +1479 45 48 1 +1480 47 48 1 +1481 47 48 0 +1482 47 49 1 +1483 47 49 0 +1484 46 48 1 +1485 46 48 0 +1486 46 49 1 +1487 46 49 0 +1536 43 51 0 +1537 43 51 1 +1538 43 50 0 +1539 43 50 1 +1540 42 51 0 +1541 42 51 1 +1542 42 50 0 +1543 42 50 1 +1544 40 50 1 +1545 40 50 0 +1546 40 51 1 +1547 40 51 0 +1548 41 50 1 +1549 41 50 0 +1550 41 51 1 +1551 41 51 0 +1568 35 50 0 +1569 35 50 1 +1570 35 51 0 +1571 35 51 1 +1572 34 50 0 +1573 34 50 1 +1574 34 51 0 +1575 34 51 1 +1576 32 51 1 +1577 32 51 0 +1578 32 50 1 +1579 32 50 0 +1580 33 51 1 +1581 33 51 0 +1582 33 50 1 +1583 33 50 0 +1584 36 50 0 +1585 36 50 1 +1586 36 51 0 +1587 36 51 1 +1588 37 50 0 +1589 37 50 1 +1590 37 51 0 +1591 37 51 1 +1592 39 51 1 +1593 39 51 0 +1594 39 50 1 +1595 39 50 0 +1596 38 51 1 +1597 38 51 0 +1598 38 50 1 +1599 38 50 0 +1600 44 51 0 +1601 44 51 1 +1602 44 50 0 +1603 44 50 1 +1604 45 51 0 +1605 45 51 1 +1606 45 50 0 +1607 45 50 1 +1608 47 50 1 +1609 47 50 0 +1610 47 51 1 +1611 47 51 0 +1612 46 50 1 +1613 46 50 0 +1614 46 51 1 +1615 46 51 0 +1664 43 53 0 +1665 43 53 1 +1666 43 52 0 +1667 43 52 1 +1668 42 53 0 +1669 42 53 1 +1670 42 52 0 +1671 42 52 1 +1672 40 52 1 +1673 40 52 0 +1674 40 53 1 +1675 40 53 0 +1676 41 52 1 +1677 41 52 0 +1678 41 53 1 +1679 41 53 0 +1696 35 52 0 +1697 35 52 1 +1698 35 53 0 +1699 35 53 1 +1700 34 52 0 +1701 34 52 1 +1702 34 53 0 +1703 34 53 1 +1704 32 53 1 +1705 32 53 0 +1706 32 52 1 +1707 32 52 0 +1708 33 53 1 +1709 33 53 0 +1710 33 52 1 +1711 33 52 0 +1712 36 52 0 +1713 36 52 1 +1714 36 53 0 +1715 36 53 1 +1716 37 52 0 +1717 37 52 1 +1718 37 53 0 +1719 37 53 1 +1720 39 53 1 +1721 39 53 0 +1722 39 52 1 +1723 39 52 0 +1724 38 53 1 +1725 38 53 0 +1726 38 52 1 +1727 38 52 0 +1728 44 53 0 +1729 44 53 1 +1730 44 52 0 +1731 44 52 1 +1732 45 53 0 +1733 45 53 1 +1734 45 52 0 +1735 45 52 1 +1736 47 52 1 +1737 47 52 0 +1738 47 53 1 +1739 47 53 0 +1740 46 52 1 +1741 46 52 0 +1742 46 53 1 +1743 46 53 0 +1792 43 55 0 +1793 43 55 1 +1794 43 54 0 +1795 43 54 1 +1796 42 55 0 +1797 42 55 1 +1798 42 54 0 +1799 42 54 1 +1800 40 54 1 +1801 40 54 0 +1802 40 55 1 +1803 40 55 0 +1804 41 54 1 +1805 41 54 0 +1806 41 55 1 +1807 41 55 0 +1824 35 54 0 +1825 35 54 1 +1826 35 55 0 +1827 35 55 1 +1828 34 54 0 +1829 34 54 1 +1830 34 55 0 +1831 34 55 1 +1832 32 55 1 +1833 32 55 0 +1834 32 54 1 +1835 32 54 0 +1836 33 55 1 +1837 33 55 0 +1838 33 54 1 +1839 33 54 0 +1840 36 54 0 +1841 36 54 1 +1842 36 55 0 +1843 36 55 1 +1844 37 54 0 +1845 37 54 1 +1846 37 55 0 +1847 37 55 1 +1848 39 55 1 +1849 39 55 0 +1850 39 54 1 +1851 39 54 0 +1852 38 55 1 +1853 38 55 0 +1854 38 54 1 +1855 38 54 0 +1856 44 55 0 +1857 44 55 1 +1858 44 54 0 +1859 44 54 1 +1860 45 55 0 +1861 45 55 1 +1862 45 54 0 +1863 45 54 1 +1864 47 54 1 +1865 47 54 0 +1866 47 55 1 +1867 47 55 0 +1868 46 54 1 +1869 46 54 0 +1870 46 55 1 +1871 46 55 0 +2176 43 27 0 +2177 43 27 1 +2178 43 26 0 +2179 43 26 1 +2180 42 27 0 +2181 42 27 1 +2182 42 26 0 +2183 42 26 1 +2184 40 26 1 +2185 40 26 0 +2186 40 27 1 +2187 40 27 0 +2188 41 26 1 +2189 41 26 0 +2190 41 27 1 +2191 41 27 0 +2208 35 26 0 +2209 35 26 1 +2210 35 27 0 +2211 35 27 1 +2212 34 26 0 +2213 34 26 1 +2214 34 27 0 +2215 34 27 1 +2216 32 27 1 +2217 32 27 0 +2218 32 26 1 +2219 32 26 0 +2220 33 27 1 +2221 33 27 0 +2222 33 26 1 +2223 33 26 0 +2224 36 26 0 +2225 36 26 1 +2226 36 27 0 +2227 36 27 1 +2228 37 26 0 +2229 37 26 1 +2230 37 27 0 +2231 37 27 1 +2232 39 27 1 +2233 39 27 0 +2234 39 26 1 +2235 39 26 0 +2236 38 27 1 +2237 38 27 0 +2238 38 26 1 +2239 38 26 0 +2240 44 27 0 +2241 44 27 1 +2242 44 26 0 +2243 44 26 1 +2244 45 27 0 +2245 45 27 1 +2246 45 26 0 +2247 45 26 1 +2248 47 26 1 +2249 47 26 0 +2250 47 27 1 +2251 47 27 0 +2252 46 26 1 +2253 46 26 0 +2254 46 27 1 +2255 46 27 0 +2304 43 25 0 +2305 43 25 1 +2306 43 24 0 +2307 43 24 1 +2308 42 25 0 +2309 42 25 1 +2310 42 24 0 +2311 42 24 1 +2312 40 24 1 +2313 40 24 0 +2314 40 25 1 +2315 40 25 0 +2316 41 24 1 +2317 41 24 0 +2318 41 25 1 +2319 41 25 0 +2336 35 24 0 +2337 35 24 1 +2338 35 25 0 +2339 35 25 1 +2340 34 24 0 +2341 34 24 1 +2342 34 25 0 +2343 34 25 1 +2344 32 25 1 +2345 32 25 0 +2346 32 24 1 +2347 32 24 0 +2348 33 25 1 +2349 33 25 0 +2350 33 24 1 +2351 33 24 0 +2352 36 24 0 +2353 36 24 1 +2354 36 25 0 +2355 36 25 1 +2356 37 24 0 +2357 37 24 1 +2358 37 25 0 +2359 37 25 1 +2360 39 25 1 +2361 39 25 0 +2362 39 24 1 +2363 39 24 0 +2364 38 25 1 +2365 38 25 0 +2366 38 24 1 +2367 38 24 0 +2368 44 25 0 +2369 44 25 1 +2370 44 24 0 +2371 44 24 1 +2372 45 25 0 +2373 45 25 1 +2374 45 24 0 +2375 45 24 1 +2376 47 24 1 +2377 47 24 0 +2378 47 25 1 +2379 47 25 0 +2380 46 24 1 +2381 46 24 0 +2382 46 25 1 +2383 46 25 0 +2432 43 23 0 +2433 43 23 1 +2434 43 22 0 +2435 43 22 1 +2436 42 23 0 +2437 42 23 1 +2438 42 22 0 +2439 42 22 1 +2440 40 22 1 +2441 40 22 0 +2442 40 23 1 +2443 40 23 0 +2444 41 22 1 +2445 41 22 0 +2446 41 23 1 +2447 41 23 0 +2464 35 22 0 +2465 35 22 1 +2466 35 23 0 +2467 35 23 1 +2468 34 22 0 +2469 34 22 1 +2470 34 23 0 +2471 34 23 1 +2472 32 23 1 +2473 32 23 0 +2474 32 22 1 +2475 32 22 0 +2476 33 23 1 +2477 33 23 0 +2478 33 22 1 +2479 33 22 0 +2480 36 22 0 +2481 36 22 1 +2482 36 23 0 +2483 36 23 1 +2484 37 22 0 +2485 37 22 1 +2486 37 23 0 +2487 37 23 1 +2488 39 23 1 +2489 39 23 0 +2490 39 22 1 +2491 39 22 0 +2492 38 23 1 +2493 38 23 0 +2494 38 22 1 +2495 38 22 0 +2496 44 23 0 +2497 44 23 1 +2498 44 22 0 +2499 44 22 1 +2500 45 23 0 +2501 45 23 1 +2502 45 22 0 +2503 45 22 1 +2504 47 22 1 +2505 47 22 0 +2506 47 23 1 +2507 47 23 0 +2508 46 22 1 +2509 46 22 0 +2510 46 23 1 +2511 46 23 0 +2560 43 21 0 +2561 43 21 1 +2562 43 20 0 +2563 43 20 1 +2564 42 21 0 +2565 42 21 1 +2566 42 20 0 +2567 42 20 1 +2568 40 20 1 +2569 40 20 0 +2570 40 21 1 +2571 40 21 0 +2572 41 20 1 +2573 41 20 0 +2574 41 21 1 +2575 41 21 0 +2592 35 20 0 +2593 35 20 1 +2594 35 21 0 +2595 35 21 1 +2596 34 20 0 +2597 34 20 1 +2598 34 21 0 +2599 34 21 1 +2600 32 21 1 +2601 32 21 0 +2602 32 20 1 +2603 32 20 0 +2604 33 21 1 +2605 33 21 0 +2606 33 20 1 +2607 33 20 0 +2608 36 20 0 +2609 36 20 1 +2610 36 21 0 +2611 36 21 1 +2612 37 20 0 +2613 37 20 1 +2614 37 21 0 +2615 37 21 1 +2616 39 21 1 +2617 39 21 0 +2618 39 20 1 +2619 39 20 0 +2620 38 21 1 +2621 38 21 0 +2622 38 20 1 +2623 38 20 0 +2624 44 21 0 +2625 44 21 1 +2626 44 20 0 +2627 44 20 1 +2628 45 21 0 +2629 45 21 1 +2630 45 20 0 +2631 45 20 1 +2632 47 20 1 +2633 47 20 0 +2634 47 21 1 +2635 47 21 0 +2636 46 20 1 +2637 46 20 0 +2638 46 21 1 +2639 46 21 0 +2688 43 19 0 +2689 43 19 1 +2690 43 18 0 +2691 43 18 1 +2692 42 19 0 +2693 42 19 1 +2694 42 18 0 +2695 42 18 1 +2696 40 18 1 +2697 40 18 0 +2698 40 19 1 +2699 40 19 0 +2700 41 18 1 +2701 41 18 0 +2702 41 19 1 +2703 41 19 0 +2720 35 18 0 +2721 35 18 1 +2722 35 19 0 +2723 35 19 1 +2724 34 18 0 +2725 34 18 1 +2726 34 19 0 +2727 34 19 1 +2728 32 19 1 +2729 32 19 0 +2730 32 18 1 +2731 32 18 0 +2732 33 19 1 +2733 33 19 0 +2734 33 18 1 +2735 33 18 0 +2736 36 18 0 +2737 36 18 1 +2738 36 19 0 +2739 36 19 1 +2740 37 18 0 +2741 37 18 1 +2742 37 19 0 +2743 37 19 1 +2744 39 19 1 +2745 39 19 0 +2746 39 18 1 +2747 39 18 0 +2748 38 19 1 +2749 38 19 0 +2750 38 18 1 +2751 38 18 0 +2752 44 19 0 +2753 44 19 1 +2754 44 18 0 +2755 44 18 1 +2756 45 19 0 +2757 45 19 1 +2758 45 18 0 +2759 45 18 1 +2760 47 18 1 +2761 47 18 0 +2762 47 19 1 +2763 47 19 0 +2764 46 18 1 +2765 46 18 0 +2766 46 19 1 +2767 46 19 0 +2816 43 17 0 +2817 43 17 1 +2818 43 16 0 +2819 43 16 1 +2820 42 17 0 +2821 42 17 1 +2822 42 16 0 +2823 42 16 1 +2824 40 16 1 +2825 40 16 0 +2826 40 17 1 +2827 40 17 0 +2828 41 16 1 +2829 41 16 0 +2830 41 17 1 +2831 41 17 0 +2848 35 16 0 +2849 35 16 1 +2850 35 17 0 +2851 35 17 1 +2852 34 16 0 +2853 34 16 1 +2854 34 17 0 +2855 34 17 1 +2856 32 17 1 +2857 32 17 0 +2858 32 16 1 +2859 32 16 0 +2860 33 17 1 +2861 33 17 0 +2862 33 16 1 +2863 33 16 0 +2864 36 16 0 +2865 36 16 1 +2866 36 17 0 +2867 36 17 1 +2868 37 16 0 +2869 37 16 1 +2870 37 17 0 +2871 37 17 1 +2872 39 17 1 +2873 39 17 0 +2874 39 16 1 +2875 39 16 0 +2876 38 17 1 +2877 38 17 0 +2878 38 16 1 +2879 38 16 0 +2880 44 17 0 +2881 44 17 1 +2882 44 16 0 +2883 44 16 1 +2884 45 17 0 +2885 45 17 1 +2886 45 16 0 +2887 45 16 1 +2888 47 16 1 +2889 47 16 0 +2890 47 17 1 +2891 47 17 0 +2892 46 16 1 +2893 46 16 0 +2894 46 17 1 +2895 46 17 0 +2944 43 15 0 +2945 43 15 1 +2946 43 14 0 +2947 43 14 1 +2948 42 15 0 +2949 42 15 1 +2950 42 14 0 +2951 42 14 1 +2952 40 14 1 +2953 40 14 0 +2954 40 15 1 +2955 40 15 0 +2956 41 14 1 +2957 41 14 0 +2958 41 15 1 +2959 41 15 0 +2976 35 14 0 +2977 35 14 1 +2978 35 15 0 +2979 35 15 1 +2980 34 14 0 +2981 34 14 1 +2982 34 15 0 +2983 34 15 1 +2984 32 15 1 +2985 32 15 0 +2986 32 14 1 +2987 32 14 0 +2988 33 15 1 +2989 33 15 0 +2990 33 14 1 +2991 33 14 0 +2992 36 14 0 +2993 36 14 1 +2994 36 15 0 +2995 36 15 1 +2996 37 14 0 +2997 37 14 1 +2998 37 15 0 +2999 37 15 1 +3000 39 15 1 +3001 39 15 0 +3002 39 14 1 +3003 39 14 0 +3004 38 15 1 +3005 38 15 0 +3006 38 14 1 +3007 38 14 0 +3008 44 15 0 +3009 44 15 1 +3010 44 14 0 +3011 44 14 1 +3012 45 15 0 +3013 45 15 1 +3014 45 14 0 +3015 45 14 1 +3016 47 14 1 +3017 47 14 0 +3018 47 15 1 +3019 47 15 0 +3020 46 14 1 +3021 46 14 0 +3022 46 15 1 +3023 46 15 0 +3072 43 13 0 +3073 43 13 1 +3074 43 12 0 +3075 43 12 1 +3076 42 13 0 +3077 42 13 1 +3078 42 12 0 +3079 42 12 1 +3080 40 12 1 +3081 40 12 0 +3082 40 13 1 +3083 40 13 0 +3084 41 12 1 +3085 41 12 0 +3086 41 13 1 +3087 41 13 0 +3104 35 12 0 +3105 35 12 1 +3106 35 13 0 +3107 35 13 1 +3108 34 12 0 +3109 34 12 1 +3110 34 13 0 +3111 34 13 1 +3112 32 13 1 +3113 32 13 0 +3114 32 12 1 +3115 32 12 0 +3116 33 13 1 +3117 33 13 0 +3118 33 12 1 +3119 33 12 0 +3120 36 12 0 +3121 36 12 1 +3122 36 13 0 +3123 36 13 1 +3124 37 12 0 +3125 37 12 1 +3126 37 13 0 +3127 37 13 1 +3128 39 13 1 +3129 39 13 0 +3130 39 12 1 +3131 39 12 0 +3132 38 13 1 +3133 38 13 0 +3134 38 12 1 +3135 38 12 0 +3136 44 13 0 +3137 44 13 1 +3138 44 12 0 +3139 44 12 1 +3140 45 13 0 +3141 45 13 1 +3142 45 12 0 +3143 45 12 1 +3144 47 12 1 +3145 47 12 0 +3146 47 13 1 +3147 47 13 0 +3148 46 12 1 +3149 46 12 0 +3150 46 13 1 +3151 46 13 0 +3200 43 11 0 +3201 43 11 1 +3202 43 10 0 +3203 43 10 1 +3204 42 11 0 +3205 42 11 1 +3206 42 10 0 +3207 42 10 1 +3208 40 10 1 +3209 40 10 0 +3210 40 11 1 +3211 40 11 0 +3212 41 10 1 +3213 41 10 0 +3214 41 11 1 +3215 41 11 0 +3232 35 10 0 +3233 35 10 1 +3234 35 11 0 +3235 35 11 1 +3236 34 10 0 +3237 34 10 1 +3238 34 11 0 +3239 34 11 1 +3240 32 11 1 +3241 32 11 0 +3242 32 10 1 +3243 32 10 0 +3244 33 11 1 +3245 33 11 0 +3246 33 10 1 +3247 33 10 0 +3248 36 10 0 +3249 36 10 1 +3250 36 11 0 +3251 36 11 1 +3252 37 10 0 +3253 37 10 1 +3254 37 11 0 +3255 37 11 1 +3256 39 11 1 +3257 39 11 0 +3258 39 10 1 +3259 39 10 0 +3260 38 11 1 +3261 38 11 0 +3262 38 10 1 +3263 38 10 0 +3264 44 11 0 +3265 44 11 1 +3266 44 10 0 +3267 44 10 1 +3268 45 11 0 +3269 45 11 1 +3270 45 10 0 +3271 45 10 1 +3272 47 10 1 +3273 47 10 0 +3274 47 11 1 +3275 47 11 0 +3276 46 10 1 +3277 46 10 0 +3278 46 11 1 +3279 46 11 0 +3328 43 9 0 +3329 43 9 1 +3330 43 8 0 +3331 43 8 1 +3332 42 9 0 +3333 42 9 1 +3334 42 8 0 +3335 42 8 1 +3336 40 8 1 +3337 40 8 0 +3338 40 9 1 +3339 40 9 0 +3340 41 8 1 +3341 41 8 0 +3342 41 9 1 +3343 41 9 0 +3360 35 8 0 +3361 35 8 1 +3362 35 9 0 +3363 35 9 1 +3364 34 8 0 +3365 34 8 1 +3366 34 9 0 +3367 34 9 1 +3368 32 9 1 +3369 32 9 0 +3370 32 8 1 +3371 32 8 0 +3372 33 9 1 +3373 33 9 0 +3374 33 8 1 +3375 33 8 0 +3376 36 8 0 +3377 36 8 1 +3378 36 9 0 +3379 36 9 1 +3380 37 8 0 +3381 37 8 1 +3382 37 9 0 +3383 37 9 1 +3384 39 9 1 +3385 39 9 0 +3386 39 8 1 +3387 39 8 0 +3388 38 9 1 +3389 38 9 0 +3390 38 8 1 +3391 38 8 0 +3392 44 9 0 +3393 44 9 1 +3394 44 8 0 +3395 44 8 1 +3396 45 9 0 +3397 45 9 1 +3398 45 8 0 +3399 45 8 1 +3400 47 8 1 +3401 47 8 0 +3402 47 9 1 +3403 47 9 0 +3404 46 8 1 +3405 46 8 0 +3406 46 9 1 +3407 46 9 0 +3456 43 7 0 +3457 43 7 1 +3458 43 6 0 +3459 43 6 1 +3460 42 7 0 +3461 42 7 1 +3462 42 6 0 +3463 42 6 1 +3464 40 6 1 +3465 40 6 0 +3466 40 7 1 +3467 40 7 0 +3468 41 6 1 +3469 41 6 0 +3470 41 7 1 +3471 41 7 0 +3488 35 6 0 +3489 35 6 1 +3490 35 7 0 +3491 35 7 1 +3492 34 6 0 +3493 34 6 1 +3494 34 7 0 +3495 34 7 1 +3496 32 7 1 +3497 32 7 0 +3498 32 6 1 +3499 32 6 0 +3500 33 7 1 +3501 33 7 0 +3502 33 6 1 +3503 33 6 0 +3504 36 6 0 +3505 36 6 1 +3506 36 7 0 +3507 36 7 1 +3508 37 6 0 +3509 37 6 1 +3510 37 7 0 +3511 37 7 1 +3512 39 7 1 +3513 39 7 0 +3514 39 6 1 +3515 39 6 0 +3516 38 7 1 +3517 38 7 0 +3518 38 6 1 +3519 38 6 0 +3520 44 7 0 +3521 44 7 1 +3522 44 6 0 +3523 44 6 1 +3524 45 7 0 +3525 45 7 1 +3526 45 6 0 +3527 45 6 1 +3528 47 6 1 +3529 47 6 0 +3530 47 7 1 +3531 47 7 0 +3532 46 6 1 +3533 46 6 0 +3534 46 7 1 +3535 46 7 0 +3584 43 5 0 +3585 43 5 1 +3586 43 4 0 +3587 43 4 1 +3588 42 5 0 +3589 42 5 1 +3590 42 4 0 +3591 42 4 1 +3592 40 4 1 +3593 40 4 0 +3594 40 5 1 +3595 40 5 0 +3596 41 4 1 +3597 41 4 0 +3598 41 5 1 +3599 41 5 0 +3616 35 4 0 +3617 35 4 1 +3618 35 5 0 +3619 35 5 1 +3620 34 4 0 +3621 34 4 1 +3622 34 5 0 +3623 34 5 1 +3624 32 5 1 +3625 32 5 0 +3626 32 4 1 +3627 32 4 0 +3628 33 5 1 +3629 33 5 0 +3630 33 4 1 +3631 33 4 0 +3632 36 4 0 +3633 36 4 1 +3634 36 5 0 +3635 36 5 1 +3636 37 4 0 +3637 37 4 1 +3638 37 5 0 +3639 37 5 1 +3640 39 5 1 +3641 39 5 0 +3642 39 4 1 +3643 39 4 0 +3644 38 5 1 +3645 38 5 0 +3646 38 4 1 +3647 38 4 0 +3648 44 5 0 +3649 44 5 1 +3650 44 4 0 +3651 44 4 1 +3652 45 5 0 +3653 45 5 1 +3654 45 4 0 +3655 45 4 1 +3656 47 4 1 +3657 47 4 0 +3658 47 5 1 +3659 47 5 0 +3660 46 4 1 +3661 46 4 0 +3662 46 5 1 +3663 46 5 0 +3712 43 3 0 +3713 43 3 1 +3714 43 2 0 +3715 43 2 1 +3716 42 3 0 +3717 42 3 1 +3718 42 2 0 +3719 42 2 1 +3720 40 2 1 +3721 40 2 0 +3722 40 3 1 +3723 40 3 0 +3724 41 2 1 +3725 41 2 0 +3726 41 3 1 +3727 41 3 0 +3744 35 2 0 +3745 35 2 1 +3746 35 3 0 +3747 35 3 1 +3748 34 2 0 +3749 34 2 1 +3750 34 3 0 +3751 34 3 1 +3752 32 3 1 +3753 32 3 0 +3754 32 2 1 +3755 32 2 0 +3756 33 3 1 +3757 33 3 0 +3758 33 2 1 +3759 33 2 0 +3760 36 2 0 +3761 36 2 1 +3762 36 3 0 +3763 36 3 1 +3764 37 2 0 +3765 37 2 1 +3766 37 3 0 +3767 37 3 1 +3768 39 3 1 +3769 39 3 0 +3770 39 2 1 +3771 39 2 0 +3772 38 3 1 +3773 38 3 0 +3774 38 2 1 +3775 38 2 0 +3776 44 3 0 +3777 44 3 1 +3778 44 2 0 +3779 44 2 1 +3780 45 3 0 +3781 45 3 1 +3782 45 2 0 +3783 45 2 1 +3784 47 2 1 +3785 47 2 0 +3786 47 3 1 +3787 47 3 0 +3788 46 2 1 +3789 46 2 0 +3790 46 3 1 +3791 46 3 0 +3840 43 1 0 +3841 43 1 1 +3842 43 0 0 +3843 43 0 1 +3844 42 1 0 +3845 42 1 1 +3846 42 0 0 +3847 42 0 1 +3848 40 0 1 +3849 40 0 0 +3850 40 1 1 +3851 40 1 0 +3852 41 0 1 +3853 41 0 0 +3854 41 1 1 +3855 41 1 0 +3872 35 0 0 +3873 35 0 1 +3874 35 1 0 +3875 35 1 1 +3876 34 0 0 +3877 34 0 1 +3878 34 1 0 +3879 34 1 1 +3880 32 1 1 +3881 32 1 0 +3882 32 0 1 +3883 32 0 0 +3884 33 1 1 +3885 33 1 0 +3886 33 0 1 +3887 33 0 0 +3888 36 0 0 +3889 36 0 1 +3890 36 1 0 +3891 36 1 1 +3892 37 0 0 +3893 37 0 1 +3894 37 1 0 +3895 37 1 1 +3896 39 1 1 +3897 39 1 0 +3898 39 0 1 +3899 39 0 0 +3900 38 1 1 +3901 38 1 0 +3902 38 0 1 +3903 38 0 0 +3904 44 1 0 +3905 44 1 1 +3906 44 0 0 +3907 44 0 1 +3908 45 1 0 +3909 45 1 1 +3910 45 0 0 +3911 45 0 1 +3912 47 0 1 +3913 47 0 0 +3914 47 1 1 +3915 47 1 0 +3916 46 0 1 +3917 46 0 0 +3918 46 1 1 +3919 46 1 0 diff --git a/Detectors/PHOS/base/files/Mod1RCU3.data b/Detectors/PHOS/base/files/Mod1RCU3.data new file mode 100644 index 0000000000000..43bd76fc42791 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod1RCU3.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 3 0 2 + 1 3 1 2 + 2 3 2 2 + 3 3 3 2 + 4 3 4 2 + 5 3 5 2 + 6 3 6 2 + 7 3 7 2 + 8 3 8 2 + 9 3 9 2 + 10 3 10 2 + 11 3 11 2 + 12 3 12 2 + 13 3 13 2 + 14 3 14 2 + 15 3 15 2 + 16 3 16 2 + 17 3 17 2 + 18 3 18 2 + 19 3 19 2 + 20 3 20 2 + 21 3 21 2 + 22 3 22 2 + 23 3 23 2 + 24 3 24 2 + 25 3 25 2 + 26 3 26 2 + 27 3 27 2 + 28 3 28 2 + 29 3 29 2 + 30 3 30 2 + 31 3 31 2 + 32 3 32 2 + 33 3 33 2 + 34 3 34 2 + 35 3 35 2 + 36 3 36 2 + 37 3 37 2 + 38 3 38 2 + 39 3 39 2 + 40 3 40 2 + 41 3 41 2 + 42 3 42 2 + 43 3 43 2 + 44 3 44 2 + 45 3 45 2 + 46 3 46 2 + 47 3 47 2 + 48 3 48 2 + 49 3 49 2 + 50 3 50 2 + 51 3 51 2 + 52 3 52 2 + 53 3 53 2 + 54 3 54 2 + 55 3 55 2 + 56 3 56 2 + 57 3 57 2 + 58 3 58 2 + 59 3 59 2 + 60 3 60 2 + 61 3 61 2 + 62 3 62 2 + 63 3 63 2 + 64 3 64 2 + 65 3 65 2 + 66 3 66 2 + 67 3 67 2 + 68 3 68 2 + 69 3 69 2 + 70 3 70 2 + 71 3 71 2 + 72 3 72 2 + 73 3 73 2 + 74 3 74 2 + 75 3 75 2 + 76 3 76 2 + 77 3 77 2 + 78 3 78 2 + 79 3 79 2 + 80 3 80 2 + 81 3 81 2 + 82 3 82 2 + 83 3 83 2 + 84 3 84 2 + 85 3 85 2 + 86 3 86 2 + 87 3 87 2 + 88 3 88 2 + 89 3 89 2 + 90 3 90 2 + 91 3 91 2 + 92 3 92 2 + 93 3 93 2 + 94 3 94 2 + 95 3 95 2 + 96 3 96 2 + 97 3 97 2 + 98 3 98 2 + 99 3 99 2 + 100 3 100 2 + 101 3 101 2 + 102 3 102 2 + 103 3 103 2 + 104 3 104 2 + 105 3 105 2 + 106 3 106 2 + 107 3 107 2 + 108 3 108 2 + 109 3 109 2 + 110 3 110 2 + 111 3 111 2 + 112 3 112 2 + 113 3 113 2 + 114 3 114 2 + 115 3 115 2 + 116 3 116 2 + 117 3 117 2 + 118 3 118 2 + 119 3 119 2 + 120 3 120 2 + 121 3 121 2 + 122 3 122 2 + 123 3 123 2 + 124 3 124 2 + 125 3 125 2 + 126 3 126 2 + 127 3 127 2 +2048 3 2048 2 +2049 3 2049 2 +2050 3 2050 2 +2051 3 2051 2 +2052 3 2052 2 +2053 3 2053 2 +2054 3 2054 2 +2055 3 2055 2 +2056 3 2056 2 +2057 3 2057 2 +2058 3 2058 2 +2059 3 2059 2 +2060 3 2060 2 +2061 3 2061 2 +2062 3 2062 2 +2063 3 2063 2 +2064 3 2064 2 +2065 3 2065 2 +2066 3 2066 2 +2067 3 2067 2 +2068 3 2068 2 +2069 3 2069 2 +2070 3 2070 2 +2071 3 2071 2 +2072 3 2072 2 +2073 3 2073 2 +2074 3 2074 2 +2075 3 2075 2 +2076 3 2076 2 +2077 3 2077 2 +2078 3 2078 2 +2079 3 2079 2 +2080 3 2080 2 +2081 3 2081 2 +2082 3 2082 2 +2083 3 2083 2 +2084 3 2084 2 +2085 3 2085 2 +2086 3 2086 2 +2087 3 2087 2 +2088 3 2088 2 +2089 3 2089 2 +2090 3 2090 2 +2091 3 2091 2 +2092 3 2092 2 +2093 3 2093 2 +2094 3 2094 2 +2095 3 2095 2 +2096 3 2096 2 +2097 3 2097 2 +2098 3 2098 2 +2099 3 2099 2 +2100 3 2100 2 +2101 3 2101 2 +2102 3 2102 2 +2103 3 2103 2 +2104 3 2104 2 +2105 3 2105 2 +2106 3 2106 2 +2107 3 2107 2 +2108 3 2108 2 +2109 3 2109 2 +2110 3 2110 2 +2111 3 2111 2 +2112 3 2112 2 +2113 3 2113 2 +2114 3 2114 2 +2115 3 2115 2 +2116 3 2116 2 +2117 3 2117 2 +2118 3 2118 2 +2119 3 2119 2 +2120 3 2120 2 +2121 3 2121 2 +2122 3 2122 2 +2123 3 2123 2 +2124 3 2124 2 +2125 3 2125 2 +2126 3 2126 2 +2127 3 2127 2 +2128 3 2128 2 +2129 3 2129 2 +2130 3 2130 2 +2131 3 2131 2 +2132 3 2132 2 +2133 3 2133 2 +2134 3 2134 2 +2135 3 2135 2 +2136 3 2136 2 +2137 3 2137 2 +2138 3 2138 2 +2139 3 2139 2 +2140 3 2140 2 +2141 3 2141 2 +2142 3 2142 2 +2143 3 2143 2 +2144 3 2144 2 +2145 3 2145 2 +2146 3 2146 2 +2147 3 2147 2 +2148 3 2148 2 +2149 3 2149 2 +2150 3 2150 2 +2151 3 2151 2 +2152 3 2152 2 +2153 3 2153 2 +2154 3 2154 2 +2155 3 2155 2 +2156 3 2156 2 +2157 3 2157 2 +2158 3 2158 2 +2159 3 2159 2 +2160 3 2160 2 +2161 3 2161 2 +2162 3 2162 2 +2163 3 2163 2 +2164 3 2164 2 +2165 3 2165 2 +2166 3 2166 2 +2167 3 2167 2 +2168 3 2168 2 +2169 3 2169 2 +2170 3 2170 2 +2171 3 2171 2 +2172 3 2172 2 +2173 3 2173 2 +2174 3 2174 2 +2175 3 2175 2 + 128 59 29 0 + 129 59 29 1 + 130 59 28 0 + 131 59 28 1 + 132 58 29 0 + 133 58 29 1 + 134 58 28 0 + 135 58 28 1 + 136 56 28 1 + 137 56 28 0 + 138 56 29 1 + 139 56 29 0 + 140 57 28 1 + 141 57 28 0 + 142 57 29 1 + 143 57 29 0 + 160 51 28 0 + 161 51 28 1 + 162 51 29 0 + 163 51 29 1 + 164 50 28 0 + 165 50 28 1 + 166 50 29 0 + 167 50 29 1 + 168 48 29 1 + 169 48 29 0 + 170 48 28 1 + 171 48 28 0 + 172 49 29 1 + 173 49 29 0 + 174 49 28 1 + 175 49 28 0 + 176 52 28 0 + 177 52 28 1 + 178 52 29 0 + 179 52 29 1 + 180 53 28 0 + 181 53 28 1 + 182 53 29 0 + 183 53 29 1 + 184 55 29 1 + 185 55 29 0 + 186 55 28 1 + 187 55 28 0 + 188 54 29 1 + 189 54 29 0 + 190 54 28 1 + 191 54 28 0 + 192 60 29 0 + 193 60 29 1 + 194 60 28 0 + 195 60 28 1 + 196 61 29 0 + 197 61 29 1 + 198 61 28 0 + 199 61 28 1 + 200 63 28 1 + 201 63 28 0 + 202 63 29 1 + 203 63 29 0 + 204 62 28 1 + 205 62 28 0 + 206 62 29 1 + 207 62 29 0 + 256 59 31 0 + 257 59 31 1 + 258 59 30 0 + 259 59 30 1 + 260 58 31 0 + 261 58 31 1 + 262 58 30 0 + 263 58 30 1 + 264 56 30 1 + 265 56 30 0 + 266 56 31 1 + 267 56 31 0 + 268 57 30 1 + 269 57 30 0 + 270 57 31 1 + 271 57 31 0 + 288 51 30 0 + 289 51 30 1 + 290 51 31 0 + 291 51 31 1 + 292 50 30 0 + 293 50 30 1 + 294 50 31 0 + 295 50 31 1 + 296 48 31 1 + 297 48 31 0 + 298 48 30 1 + 299 48 30 0 + 300 49 31 1 + 301 49 31 0 + 302 49 30 1 + 303 49 30 0 + 304 52 30 0 + 305 52 30 1 + 306 52 31 0 + 307 52 31 1 + 308 53 30 0 + 309 53 30 1 + 310 53 31 0 + 311 53 31 1 + 312 55 31 1 + 313 55 31 0 + 314 55 30 1 + 315 55 30 0 + 316 54 31 1 + 317 54 31 0 + 318 54 30 1 + 319 54 30 0 + 320 60 31 0 + 321 60 31 1 + 322 60 30 0 + 323 60 30 1 + 324 61 31 0 + 325 61 31 1 + 326 61 30 0 + 327 61 30 1 + 328 63 30 1 + 329 63 30 0 + 330 63 31 1 + 331 63 31 0 + 332 62 30 1 + 333 62 30 0 + 334 62 31 1 + 335 62 31 0 + 384 59 33 0 + 385 59 33 1 + 386 59 32 0 + 387 59 32 1 + 388 58 33 0 + 389 58 33 1 + 390 58 32 0 + 391 58 32 1 + 392 56 32 1 + 393 56 32 0 + 394 56 33 1 + 395 56 33 0 + 396 57 32 1 + 397 57 32 0 + 398 57 33 1 + 399 57 33 0 + 416 51 32 0 + 417 51 32 1 + 418 51 33 0 + 419 51 33 1 + 420 50 32 0 + 421 50 32 1 + 422 50 33 0 + 423 50 33 1 + 424 48 33 1 + 425 48 33 0 + 426 48 32 1 + 427 48 32 0 + 428 49 33 1 + 429 49 33 0 + 430 49 32 1 + 431 49 32 0 + 432 52 32 0 + 433 52 32 1 + 434 52 33 0 + 435 52 33 1 + 436 53 32 0 + 437 53 32 1 + 438 53 33 0 + 439 53 33 1 + 440 55 33 1 + 441 55 33 0 + 442 55 32 1 + 443 55 32 0 + 444 54 33 1 + 445 54 33 0 + 446 54 32 1 + 447 54 32 0 + 448 60 33 0 + 449 60 33 1 + 450 60 32 0 + 451 60 32 1 + 452 61 33 0 + 453 61 33 1 + 454 61 32 0 + 455 61 32 1 + 456 63 32 1 + 457 63 32 0 + 458 63 33 1 + 459 63 33 0 + 460 62 32 1 + 461 62 32 0 + 462 62 33 1 + 463 62 33 0 + 512 59 35 0 + 513 59 35 1 + 514 59 34 0 + 515 59 34 1 + 516 58 35 0 + 517 58 35 1 + 518 58 34 0 + 519 58 34 1 + 520 56 34 1 + 521 56 34 0 + 522 56 35 1 + 523 56 35 0 + 524 57 34 1 + 525 57 34 0 + 526 57 35 1 + 527 57 35 0 + 544 51 34 0 + 545 51 34 1 + 546 51 35 0 + 547 51 35 1 + 548 50 34 0 + 549 50 34 1 + 550 50 35 0 + 551 50 35 1 + 552 48 35 1 + 553 48 35 0 + 554 48 34 1 + 555 48 34 0 + 556 49 35 1 + 557 49 35 0 + 558 49 34 1 + 559 49 34 0 + 560 52 34 0 + 561 52 34 1 + 562 52 35 0 + 563 52 35 1 + 564 53 34 0 + 565 53 34 1 + 566 53 35 0 + 567 53 35 1 + 568 55 35 1 + 569 55 35 0 + 570 55 34 1 + 571 55 34 0 + 572 54 35 1 + 573 54 35 0 + 574 54 34 1 + 575 54 34 0 + 576 60 35 0 + 577 60 35 1 + 578 60 34 0 + 579 60 34 1 + 580 61 35 0 + 581 61 35 1 + 582 61 34 0 + 583 61 34 1 + 584 63 34 1 + 585 63 34 0 + 586 63 35 1 + 587 63 35 0 + 588 62 34 1 + 589 62 34 0 + 590 62 35 1 + 591 62 35 0 + 640 59 37 0 + 641 59 37 1 + 642 59 36 0 + 643 59 36 1 + 644 58 37 0 + 645 58 37 1 + 646 58 36 0 + 647 58 36 1 + 648 56 36 1 + 649 56 36 0 + 650 56 37 1 + 651 56 37 0 + 652 57 36 1 + 653 57 36 0 + 654 57 37 1 + 655 57 37 0 + 672 51 36 0 + 673 51 36 1 + 674 51 37 0 + 675 51 37 1 + 676 50 36 0 + 677 50 36 1 + 678 50 37 0 + 679 50 37 1 + 680 48 37 1 + 681 48 37 0 + 682 48 36 1 + 683 48 36 0 + 684 49 37 1 + 685 49 37 0 + 686 49 36 1 + 687 49 36 0 + 688 52 36 0 + 689 52 36 1 + 690 52 37 0 + 691 52 37 1 + 692 53 36 0 + 693 53 36 1 + 694 53 37 0 + 695 53 37 1 + 696 55 37 1 + 697 55 37 0 + 698 55 36 1 + 699 55 36 0 + 700 54 37 1 + 701 54 37 0 + 702 54 36 1 + 703 54 36 0 + 704 60 37 0 + 705 60 37 1 + 706 60 36 0 + 707 60 36 1 + 708 61 37 0 + 709 61 37 1 + 710 61 36 0 + 711 61 36 1 + 712 63 36 1 + 713 63 36 0 + 714 63 37 1 + 715 63 37 0 + 716 62 36 1 + 717 62 36 0 + 718 62 37 1 + 719 62 37 0 + 768 59 39 0 + 769 59 39 1 + 770 59 38 0 + 771 59 38 1 + 772 58 39 0 + 773 58 39 1 + 774 58 38 0 + 775 58 38 1 + 776 56 38 1 + 777 56 38 0 + 778 56 39 1 + 779 56 39 0 + 780 57 38 1 + 781 57 38 0 + 782 57 39 1 + 783 57 39 0 + 800 51 38 0 + 801 51 38 1 + 802 51 39 0 + 803 51 39 1 + 804 50 38 0 + 805 50 38 1 + 806 50 39 0 + 807 50 39 1 + 808 48 39 1 + 809 48 39 0 + 810 48 38 1 + 811 48 38 0 + 812 49 39 1 + 813 49 39 0 + 814 49 38 1 + 815 49 38 0 + 816 52 38 0 + 817 52 38 1 + 818 52 39 0 + 819 52 39 1 + 820 53 38 0 + 821 53 38 1 + 822 53 39 0 + 823 53 39 1 + 824 55 39 1 + 825 55 39 0 + 826 55 38 1 + 827 55 38 0 + 828 54 39 1 + 829 54 39 0 + 830 54 38 1 + 831 54 38 0 + 832 60 39 0 + 833 60 39 1 + 834 60 38 0 + 835 60 38 1 + 836 61 39 0 + 837 61 39 1 + 838 61 38 0 + 839 61 38 1 + 840 63 38 1 + 841 63 38 0 + 842 63 39 1 + 843 63 39 0 + 844 62 38 1 + 845 62 38 0 + 846 62 39 1 + 847 62 39 0 + 896 59 41 0 + 897 59 41 1 + 898 59 40 0 + 899 59 40 1 + 900 58 41 0 + 901 58 41 1 + 902 58 40 0 + 903 58 40 1 + 904 56 40 1 + 905 56 40 0 + 906 56 41 1 + 907 56 41 0 + 908 57 40 1 + 909 57 40 0 + 910 57 41 1 + 911 57 41 0 + 928 51 40 0 + 929 51 40 1 + 930 51 41 0 + 931 51 41 1 + 932 50 40 0 + 933 50 40 1 + 934 50 41 0 + 935 50 41 1 + 936 48 41 1 + 937 48 41 0 + 938 48 40 1 + 939 48 40 0 + 940 49 41 1 + 941 49 41 0 + 942 49 40 1 + 943 49 40 0 + 944 52 40 0 + 945 52 40 1 + 946 52 41 0 + 947 52 41 1 + 948 53 40 0 + 949 53 40 1 + 950 53 41 0 + 951 53 41 1 + 952 55 41 1 + 953 55 41 0 + 954 55 40 1 + 955 55 40 0 + 956 54 41 1 + 957 54 41 0 + 958 54 40 1 + 959 54 40 0 + 960 60 41 0 + 961 60 41 1 + 962 60 40 0 + 963 60 40 1 + 964 61 41 0 + 965 61 41 1 + 966 61 40 0 + 967 61 40 1 + 968 63 40 1 + 969 63 40 0 + 970 63 41 1 + 971 63 41 0 + 972 62 40 1 + 973 62 40 0 + 974 62 41 1 + 975 62 41 0 +1024 59 43 0 +1025 59 43 1 +1026 59 42 0 +1027 59 42 1 +1028 58 43 0 +1029 58 43 1 +1030 58 42 0 +1031 58 42 1 +1032 56 42 1 +1033 56 42 0 +1034 56 43 1 +1035 56 43 0 +1036 57 42 1 +1037 57 42 0 +1038 57 43 1 +1039 57 43 0 +1056 51 42 0 +1057 51 42 1 +1058 51 43 0 +1059 51 43 1 +1060 50 42 0 +1061 50 42 1 +1062 50 43 0 +1063 50 43 1 +1064 48 43 1 +1065 48 43 0 +1066 48 42 1 +1067 48 42 0 +1068 49 43 1 +1069 49 43 0 +1070 49 42 1 +1071 49 42 0 +1072 52 42 0 +1073 52 42 1 +1074 52 43 0 +1075 52 43 1 +1076 53 42 0 +1077 53 42 1 +1078 53 43 0 +1079 53 43 1 +1080 55 43 1 +1081 55 43 0 +1082 55 42 1 +1083 55 42 0 +1084 54 43 1 +1085 54 43 0 +1086 54 42 1 +1087 54 42 0 +1088 60 43 0 +1089 60 43 1 +1090 60 42 0 +1091 60 42 1 +1092 61 43 0 +1093 61 43 1 +1094 61 42 0 +1095 61 42 1 +1096 63 42 1 +1097 63 42 0 +1098 63 43 1 +1099 63 43 0 +1100 62 42 1 +1101 62 42 0 +1102 62 43 1 +1103 62 43 0 +1152 59 45 0 +1153 59 45 1 +1154 59 44 0 +1155 59 44 1 +1156 58 45 0 +1157 58 45 1 +1158 58 44 0 +1159 58 44 1 +1160 56 44 1 +1161 56 44 0 +1162 56 45 1 +1163 56 45 0 +1164 57 44 1 +1165 57 44 0 +1166 57 45 1 +1167 57 45 0 +1184 51 44 0 +1185 51 44 1 +1186 51 45 0 +1187 51 45 1 +1188 50 44 0 +1189 50 44 1 +1190 50 45 0 +1191 50 45 1 +1192 48 45 1 +1193 48 45 0 +1194 48 44 1 +1195 48 44 0 +1196 49 45 1 +1197 49 45 0 +1198 49 44 1 +1199 49 44 0 +1200 52 44 0 +1201 52 44 1 +1202 52 45 0 +1203 52 45 1 +1204 53 44 0 +1205 53 44 1 +1206 53 45 0 +1207 53 45 1 +1208 55 45 1 +1209 55 45 0 +1210 55 44 1 +1211 55 44 0 +1212 54 45 1 +1213 54 45 0 +1214 54 44 1 +1215 54 44 0 +1216 60 45 0 +1217 60 45 1 +1218 60 44 0 +1219 60 44 1 +1220 61 45 0 +1221 61 45 1 +1222 61 44 0 +1223 61 44 1 +1224 63 44 1 +1225 63 44 0 +1226 63 45 1 +1227 63 45 0 +1228 62 44 1 +1229 62 44 0 +1230 62 45 1 +1231 62 45 0 +1280 59 47 0 +1281 59 47 1 +1282 59 46 0 +1283 59 46 1 +1284 58 47 0 +1285 58 47 1 +1286 58 46 0 +1287 58 46 1 +1288 56 46 1 +1289 56 46 0 +1290 56 47 1 +1291 56 47 0 +1292 57 46 1 +1293 57 46 0 +1294 57 47 1 +1295 57 47 0 +1312 51 46 0 +1313 51 46 1 +1314 51 47 0 +1315 51 47 1 +1316 50 46 0 +1317 50 46 1 +1318 50 47 0 +1319 50 47 1 +1320 48 47 1 +1321 48 47 0 +1322 48 46 1 +1323 48 46 0 +1324 49 47 1 +1325 49 47 0 +1326 49 46 1 +1327 49 46 0 +1328 52 46 0 +1329 52 46 1 +1330 52 47 0 +1331 52 47 1 +1332 53 46 0 +1333 53 46 1 +1334 53 47 0 +1335 53 47 1 +1336 55 47 1 +1337 55 47 0 +1338 55 46 1 +1339 55 46 0 +1340 54 47 1 +1341 54 47 0 +1342 54 46 1 +1343 54 46 0 +1344 60 47 0 +1345 60 47 1 +1346 60 46 0 +1347 60 46 1 +1348 61 47 0 +1349 61 47 1 +1350 61 46 0 +1351 61 46 1 +1352 63 46 1 +1353 63 46 0 +1354 63 47 1 +1355 63 47 0 +1356 62 46 1 +1357 62 46 0 +1358 62 47 1 +1359 62 47 0 +1408 59 49 0 +1409 59 49 1 +1410 59 48 0 +1411 59 48 1 +1412 58 49 0 +1413 58 49 1 +1414 58 48 0 +1415 58 48 1 +1416 56 48 1 +1417 56 48 0 +1418 56 49 1 +1419 56 49 0 +1420 57 48 1 +1421 57 48 0 +1422 57 49 1 +1423 57 49 0 +1440 51 48 0 +1441 51 48 1 +1442 51 49 0 +1443 51 49 1 +1444 50 48 0 +1445 50 48 1 +1446 50 49 0 +1447 50 49 1 +1448 48 49 1 +1449 48 49 0 +1450 48 48 1 +1451 48 48 0 +1452 49 49 1 +1453 49 49 0 +1454 49 48 1 +1455 49 48 0 +1456 52 48 0 +1457 52 48 1 +1458 52 49 0 +1459 52 49 1 +1460 53 48 0 +1461 53 48 1 +1462 53 49 0 +1463 53 49 1 +1464 55 49 1 +1465 55 49 0 +1466 55 48 1 +1467 55 48 0 +1468 54 49 1 +1469 54 49 0 +1470 54 48 1 +1471 54 48 0 +1472 60 49 0 +1473 60 49 1 +1474 60 48 0 +1475 60 48 1 +1476 61 49 0 +1477 61 49 1 +1478 61 48 0 +1479 61 48 1 +1480 63 48 1 +1481 63 48 0 +1482 63 49 1 +1483 63 49 0 +1484 62 48 1 +1485 62 48 0 +1486 62 49 1 +1487 62 49 0 +1536 59 51 0 +1537 59 51 1 +1538 59 50 0 +1539 59 50 1 +1540 58 51 0 +1541 58 51 1 +1542 58 50 0 +1543 58 50 1 +1544 56 50 1 +1545 56 50 0 +1546 56 51 1 +1547 56 51 0 +1548 57 50 1 +1549 57 50 0 +1550 57 51 1 +1551 57 51 0 +1568 51 50 0 +1569 51 50 1 +1570 51 51 0 +1571 51 51 1 +1572 50 50 0 +1573 50 50 1 +1574 50 51 0 +1575 50 51 1 +1576 48 51 1 +1577 48 51 0 +1578 48 50 1 +1579 48 50 0 +1580 49 51 1 +1581 49 51 0 +1582 49 50 1 +1583 49 50 0 +1584 52 50 0 +1585 52 50 1 +1586 52 51 0 +1587 52 51 1 +1588 53 50 0 +1589 53 50 1 +1590 53 51 0 +1591 53 51 1 +1592 55 51 1 +1593 55 51 0 +1594 55 50 1 +1595 55 50 0 +1596 54 51 1 +1597 54 51 0 +1598 54 50 1 +1599 54 50 0 +1600 60 51 0 +1601 60 51 1 +1602 60 50 0 +1603 60 50 1 +1604 61 51 0 +1605 61 51 1 +1606 61 50 0 +1607 61 50 1 +1608 63 50 1 +1609 63 50 0 +1610 63 51 1 +1611 63 51 0 +1612 62 50 1 +1613 62 50 0 +1614 62 51 1 +1615 62 51 0 +1664 59 53 0 +1665 59 53 1 +1666 59 52 0 +1667 59 52 1 +1668 58 53 0 +1669 58 53 1 +1670 58 52 0 +1671 58 52 1 +1672 56 52 1 +1673 56 52 0 +1674 56 53 1 +1675 56 53 0 +1676 57 52 1 +1677 57 52 0 +1678 57 53 1 +1679 57 53 0 +1696 51 52 0 +1697 51 52 1 +1698 51 53 0 +1699 51 53 1 +1700 50 52 0 +1701 50 52 1 +1702 50 53 0 +1703 50 53 1 +1704 48 53 1 +1705 48 53 0 +1706 48 52 1 +1707 48 52 0 +1708 49 53 1 +1709 49 53 0 +1710 49 52 1 +1711 49 52 0 +1712 52 52 0 +1713 52 52 1 +1714 52 53 0 +1715 52 53 1 +1716 53 52 0 +1717 53 52 1 +1718 53 53 0 +1719 53 53 1 +1720 55 53 1 +1721 55 53 0 +1722 55 52 1 +1723 55 52 0 +1724 54 53 1 +1725 54 53 0 +1726 54 52 1 +1727 54 52 0 +1728 60 53 0 +1729 60 53 1 +1730 60 52 0 +1731 60 52 1 +1732 61 53 0 +1733 61 53 1 +1734 61 52 0 +1735 61 52 1 +1736 63 52 1 +1737 63 52 0 +1738 63 53 1 +1739 63 53 0 +1740 62 52 1 +1741 62 52 0 +1742 62 53 1 +1743 62 53 0 +1792 59 55 0 +1793 59 55 1 +1794 59 54 0 +1795 59 54 1 +1796 58 55 0 +1797 58 55 1 +1798 58 54 0 +1799 58 54 1 +1800 56 54 1 +1801 56 54 0 +1802 56 55 1 +1803 56 55 0 +1804 57 54 1 +1805 57 54 0 +1806 57 55 1 +1807 57 55 0 +1824 51 54 0 +1825 51 54 1 +1826 51 55 0 +1827 51 55 1 +1828 50 54 0 +1829 50 54 1 +1830 50 55 0 +1831 50 55 1 +1832 48 55 1 +1833 48 55 0 +1834 48 54 1 +1835 48 54 0 +1836 49 55 1 +1837 49 55 0 +1838 49 54 1 +1839 49 54 0 +1840 52 54 0 +1841 52 54 1 +1842 52 55 0 +1843 52 55 1 +1844 53 54 0 +1845 53 54 1 +1846 53 55 0 +1847 53 55 1 +1848 55 55 1 +1849 55 55 0 +1850 55 54 1 +1851 55 54 0 +1852 54 55 1 +1853 54 55 0 +1854 54 54 1 +1855 54 54 0 +1856 60 55 0 +1857 60 55 1 +1858 60 54 0 +1859 60 54 1 +1860 61 55 0 +1861 61 55 1 +1862 61 54 0 +1863 61 54 1 +1864 63 54 1 +1865 63 54 0 +1866 63 55 1 +1867 63 55 0 +1868 62 54 1 +1869 62 54 0 +1870 62 55 1 +1871 62 55 0 +2176 59 27 0 +2177 59 27 1 +2178 59 26 0 +2179 59 26 1 +2180 58 27 0 +2181 58 27 1 +2182 58 26 0 +2183 58 26 1 +2184 56 26 1 +2185 56 26 0 +2186 56 27 1 +2187 56 27 0 +2188 57 26 1 +2189 57 26 0 +2190 57 27 1 +2191 57 27 0 +2208 51 26 0 +2209 51 26 1 +2210 51 27 0 +2211 51 27 1 +2212 50 26 0 +2213 50 26 1 +2214 50 27 0 +2215 50 27 1 +2216 48 27 1 +2217 48 27 0 +2218 48 26 1 +2219 48 26 0 +2220 49 27 1 +2221 49 27 0 +2222 49 26 1 +2223 49 26 0 +2224 52 26 0 +2225 52 26 1 +2226 52 27 0 +2227 52 27 1 +2228 53 26 0 +2229 53 26 1 +2230 53 27 0 +2231 53 27 1 +2232 55 27 1 +2233 55 27 0 +2234 55 26 1 +2235 55 26 0 +2236 54 27 1 +2237 54 27 0 +2238 54 26 1 +2239 54 26 0 +2240 60 27 0 +2241 60 27 1 +2242 60 26 0 +2243 60 26 1 +2244 61 27 0 +2245 61 27 1 +2246 61 26 0 +2247 61 26 1 +2248 63 26 1 +2249 63 26 0 +2250 63 27 1 +2251 63 27 0 +2252 62 26 1 +2253 62 26 0 +2254 62 27 1 +2255 62 27 0 +2304 59 25 0 +2305 59 25 1 +2306 59 24 0 +2307 59 24 1 +2308 58 25 0 +2309 58 25 1 +2310 58 24 0 +2311 58 24 1 +2312 56 24 1 +2313 56 24 0 +2314 56 25 1 +2315 56 25 0 +2316 57 24 1 +2317 57 24 0 +2318 57 25 1 +2319 57 25 0 +2336 51 24 0 +2337 51 24 1 +2338 51 25 0 +2339 51 25 1 +2340 50 24 0 +2341 50 24 1 +2342 50 25 0 +2343 50 25 1 +2344 48 25 1 +2345 48 25 0 +2346 48 24 1 +2347 48 24 0 +2348 49 25 1 +2349 49 25 0 +2350 49 24 1 +2351 49 24 0 +2352 52 24 0 +2353 52 24 1 +2354 52 25 0 +2355 52 25 1 +2356 53 24 0 +2357 53 24 1 +2358 53 25 0 +2359 53 25 1 +2360 55 25 1 +2361 55 25 0 +2362 55 24 1 +2363 55 24 0 +2364 54 25 1 +2365 54 25 0 +2366 54 24 1 +2367 54 24 0 +2368 60 25 0 +2369 60 25 1 +2370 60 24 0 +2371 60 24 1 +2372 61 25 0 +2373 61 25 1 +2374 61 24 0 +2375 61 24 1 +2376 63 24 1 +2377 63 24 0 +2378 63 25 1 +2379 63 25 0 +2380 62 24 1 +2381 62 24 0 +2382 62 25 1 +2383 62 25 0 +2432 59 23 0 +2433 59 23 1 +2434 59 22 0 +2435 59 22 1 +2436 58 23 0 +2437 58 23 1 +2438 58 22 0 +2439 58 22 1 +2440 56 22 1 +2441 56 22 0 +2442 56 23 1 +2443 56 23 0 +2444 57 22 1 +2445 57 22 0 +2446 57 23 1 +2447 57 23 0 +2464 51 22 0 +2465 51 22 1 +2466 51 23 0 +2467 51 23 1 +2468 50 22 0 +2469 50 22 1 +2470 50 23 0 +2471 50 23 1 +2472 48 23 1 +2473 48 23 0 +2474 48 22 1 +2475 48 22 0 +2476 49 23 1 +2477 49 23 0 +2478 49 22 1 +2479 49 22 0 +2480 52 22 0 +2481 52 22 1 +2482 52 23 0 +2483 52 23 1 +2484 53 22 0 +2485 53 22 1 +2486 53 23 0 +2487 53 23 1 +2488 55 23 1 +2489 55 23 0 +2490 55 22 1 +2491 55 22 0 +2492 54 23 1 +2493 54 23 0 +2494 54 22 1 +2495 54 22 0 +2496 60 23 0 +2497 60 23 1 +2498 60 22 0 +2499 60 22 1 +2500 61 23 0 +2501 61 23 1 +2502 61 22 0 +2503 61 22 1 +2504 63 22 1 +2505 63 22 0 +2506 63 23 1 +2507 63 23 0 +2508 62 22 1 +2509 62 22 0 +2510 62 23 1 +2511 62 23 0 +2560 59 21 0 +2561 59 21 1 +2562 59 20 0 +2563 59 20 1 +2564 58 21 0 +2565 58 21 1 +2566 58 20 0 +2567 58 20 1 +2568 56 20 1 +2569 56 20 0 +2570 56 21 1 +2571 56 21 0 +2572 57 20 1 +2573 57 20 0 +2574 57 21 1 +2575 57 21 0 +2592 51 20 0 +2593 51 20 1 +2594 51 21 0 +2595 51 21 1 +2596 50 20 0 +2597 50 20 1 +2598 50 21 0 +2599 50 21 1 +2600 48 21 1 +2601 48 21 0 +2602 48 20 1 +2603 48 20 0 +2604 49 21 1 +2605 49 21 0 +2606 49 20 1 +2607 49 20 0 +2608 52 20 0 +2609 52 20 1 +2610 52 21 0 +2611 52 21 1 +2612 53 20 0 +2613 53 20 1 +2614 53 21 0 +2615 53 21 1 +2616 55 21 1 +2617 55 21 0 +2618 55 20 1 +2619 55 20 0 +2620 54 21 1 +2621 54 21 0 +2622 54 20 1 +2623 54 20 0 +2624 60 21 0 +2625 60 21 1 +2626 60 20 0 +2627 60 20 1 +2628 61 21 0 +2629 61 21 1 +2630 61 20 0 +2631 61 20 1 +2632 63 20 1 +2633 63 20 0 +2634 63 21 1 +2635 63 21 0 +2636 62 20 1 +2637 62 20 0 +2638 62 21 1 +2639 62 21 0 +2688 59 19 0 +2689 59 19 1 +2690 59 18 0 +2691 59 18 1 +2692 58 19 0 +2693 58 19 1 +2694 58 18 0 +2695 58 18 1 +2696 56 18 1 +2697 56 18 0 +2698 56 19 1 +2699 56 19 0 +2700 57 18 1 +2701 57 18 0 +2702 57 19 1 +2703 57 19 0 +2720 51 18 0 +2721 51 18 1 +2722 51 19 0 +2723 51 19 1 +2724 50 18 0 +2725 50 18 1 +2726 50 19 0 +2727 50 19 1 +2728 48 19 1 +2729 48 19 0 +2730 48 18 1 +2731 48 18 0 +2732 49 19 1 +2733 49 19 0 +2734 49 18 1 +2735 49 18 0 +2736 52 18 0 +2737 52 18 1 +2738 52 19 0 +2739 52 19 1 +2740 53 18 0 +2741 53 18 1 +2742 53 19 0 +2743 53 19 1 +2744 55 19 1 +2745 55 19 0 +2746 55 18 1 +2747 55 18 0 +2748 54 19 1 +2749 54 19 0 +2750 54 18 1 +2751 54 18 0 +2752 60 19 0 +2753 60 19 1 +2754 60 18 0 +2755 60 18 1 +2756 61 19 0 +2757 61 19 1 +2758 61 18 0 +2759 61 18 1 +2760 63 18 1 +2761 63 18 0 +2762 63 19 1 +2763 63 19 0 +2764 62 18 1 +2765 62 18 0 +2766 62 19 1 +2767 62 19 0 +2816 59 17 0 +2817 59 17 1 +2818 59 16 0 +2819 59 16 1 +2820 58 17 0 +2821 58 17 1 +2822 58 16 0 +2823 58 16 1 +2824 56 16 1 +2825 56 16 0 +2826 56 17 1 +2827 56 17 0 +2828 57 16 1 +2829 57 16 0 +2830 57 17 1 +2831 57 17 0 +2848 51 16 0 +2849 51 16 1 +2850 51 17 0 +2851 51 17 1 +2852 50 16 0 +2853 50 16 1 +2854 50 17 0 +2855 50 17 1 +2856 48 17 1 +2857 48 17 0 +2858 48 16 1 +2859 48 16 0 +2860 49 17 1 +2861 49 17 0 +2862 49 16 1 +2863 49 16 0 +2864 52 16 0 +2865 52 16 1 +2866 52 17 0 +2867 52 17 1 +2868 53 16 0 +2869 53 16 1 +2870 53 17 0 +2871 53 17 1 +2872 55 17 1 +2873 55 17 0 +2874 55 16 1 +2875 55 16 0 +2876 54 17 1 +2877 54 17 0 +2878 54 16 1 +2879 54 16 0 +2880 60 17 0 +2881 60 17 1 +2882 60 16 0 +2883 60 16 1 +2884 61 17 0 +2885 61 17 1 +2886 61 16 0 +2887 61 16 1 +2888 63 16 1 +2889 63 16 0 +2890 63 17 1 +2891 63 17 0 +2892 62 16 1 +2893 62 16 0 +2894 62 17 1 +2895 62 17 0 +2944 59 15 0 +2945 59 15 1 +2946 59 14 0 +2947 59 14 1 +2948 58 15 0 +2949 58 15 1 +2950 58 14 0 +2951 58 14 1 +2952 56 14 1 +2953 56 14 0 +2954 56 15 1 +2955 56 15 0 +2956 57 14 1 +2957 57 14 0 +2958 57 15 1 +2959 57 15 0 +2976 51 14 0 +2977 51 14 1 +2978 51 15 0 +2979 51 15 1 +2980 50 14 0 +2981 50 14 1 +2982 50 15 0 +2983 50 15 1 +2984 48 15 1 +2985 48 15 0 +2986 48 14 1 +2987 48 14 0 +2988 49 15 1 +2989 49 15 0 +2990 49 14 1 +2991 49 14 0 +2992 52 14 0 +2993 52 14 1 +2994 52 15 0 +2995 52 15 1 +2996 53 14 0 +2997 53 14 1 +2998 53 15 0 +2999 53 15 1 +3000 55 15 1 +3001 55 15 0 +3002 55 14 1 +3003 55 14 0 +3004 54 15 1 +3005 54 15 0 +3006 54 14 1 +3007 54 14 0 +3008 60 15 0 +3009 60 15 1 +3010 60 14 0 +3011 60 14 1 +3012 61 15 0 +3013 61 15 1 +3014 61 14 0 +3015 61 14 1 +3016 63 14 1 +3017 63 14 0 +3018 63 15 1 +3019 63 15 0 +3020 62 14 1 +3021 62 14 0 +3022 62 15 1 +3023 62 15 0 +3072 59 13 0 +3073 59 13 1 +3074 59 12 0 +3075 59 12 1 +3076 58 13 0 +3077 58 13 1 +3078 58 12 0 +3079 58 12 1 +3080 56 12 1 +3081 56 12 0 +3082 56 13 1 +3083 56 13 0 +3084 57 12 1 +3085 57 12 0 +3086 57 13 1 +3087 57 13 0 +3104 51 12 0 +3105 51 12 1 +3106 51 13 0 +3107 51 13 1 +3108 50 12 0 +3109 50 12 1 +3110 50 13 0 +3111 50 13 1 +3112 48 13 1 +3113 48 13 0 +3114 48 12 1 +3115 48 12 0 +3116 49 13 1 +3117 49 13 0 +3118 49 12 1 +3119 49 12 0 +3120 52 12 0 +3121 52 12 1 +3122 52 13 0 +3123 52 13 1 +3124 53 12 0 +3125 53 12 1 +3126 53 13 0 +3127 53 13 1 +3128 55 13 1 +3129 55 13 0 +3130 55 12 1 +3131 55 12 0 +3132 54 13 1 +3133 54 13 0 +3134 54 12 1 +3135 54 12 0 +3136 60 13 0 +3137 60 13 1 +3138 60 12 0 +3139 60 12 1 +3140 61 13 0 +3141 61 13 1 +3142 61 12 0 +3143 61 12 1 +3144 63 12 1 +3145 63 12 0 +3146 63 13 1 +3147 63 13 0 +3148 62 12 1 +3149 62 12 0 +3150 62 13 1 +3151 62 13 0 +3200 59 11 0 +3201 59 11 1 +3202 59 10 0 +3203 59 10 1 +3204 58 11 0 +3205 58 11 1 +3206 58 10 0 +3207 58 10 1 +3208 56 10 1 +3209 56 10 0 +3210 56 11 1 +3211 56 11 0 +3212 57 10 1 +3213 57 10 0 +3214 57 11 1 +3215 57 11 0 +3232 51 10 0 +3233 51 10 1 +3234 51 11 0 +3235 51 11 1 +3236 50 10 0 +3237 50 10 1 +3238 50 11 0 +3239 50 11 1 +3240 48 11 1 +3241 48 11 0 +3242 48 10 1 +3243 48 10 0 +3244 49 11 1 +3245 49 11 0 +3246 49 10 1 +3247 49 10 0 +3248 52 10 0 +3249 52 10 1 +3250 52 11 0 +3251 52 11 1 +3252 53 10 0 +3253 53 10 1 +3254 53 11 0 +3255 53 11 1 +3256 55 11 1 +3257 55 11 0 +3258 55 10 1 +3259 55 10 0 +3260 54 11 1 +3261 54 11 0 +3262 54 10 1 +3263 54 10 0 +3264 60 11 0 +3265 60 11 1 +3266 60 10 0 +3267 60 10 1 +3268 61 11 0 +3269 61 11 1 +3270 61 10 0 +3271 61 10 1 +3272 63 10 1 +3273 63 10 0 +3274 63 11 1 +3275 63 11 0 +3276 62 10 1 +3277 62 10 0 +3278 62 11 1 +3279 62 11 0 +3328 59 9 0 +3329 59 9 1 +3330 59 8 0 +3331 59 8 1 +3332 58 9 0 +3333 58 9 1 +3334 58 8 0 +3335 58 8 1 +3336 56 8 1 +3337 56 8 0 +3338 56 9 1 +3339 56 9 0 +3340 57 8 1 +3341 57 8 0 +3342 57 9 1 +3343 57 9 0 +3360 51 8 0 +3361 51 8 1 +3362 51 9 0 +3363 51 9 1 +3364 50 8 0 +3365 50 8 1 +3366 50 9 0 +3367 50 9 1 +3368 48 9 1 +3369 48 9 0 +3370 48 8 1 +3371 48 8 0 +3372 49 9 1 +3373 49 9 0 +3374 49 8 1 +3375 49 8 0 +3376 52 8 0 +3377 52 8 1 +3378 52 9 0 +3379 52 9 1 +3380 53 8 0 +3381 53 8 1 +3382 53 9 0 +3383 53 9 1 +3384 55 9 1 +3385 55 9 0 +3386 55 8 1 +3387 55 8 0 +3388 54 9 1 +3389 54 9 0 +3390 54 8 1 +3391 54 8 0 +3392 60 9 0 +3393 60 9 1 +3394 60 8 0 +3395 60 8 1 +3396 61 9 0 +3397 61 9 1 +3398 61 8 0 +3399 61 8 1 +3400 63 8 1 +3401 63 8 0 +3402 63 9 1 +3403 63 9 0 +3404 62 8 1 +3405 62 8 0 +3406 62 9 1 +3407 62 9 0 +3456 59 7 0 +3457 59 7 1 +3458 59 6 0 +3459 59 6 1 +3460 58 7 0 +3461 58 7 1 +3462 58 6 0 +3463 58 6 1 +3464 56 6 1 +3465 56 6 0 +3466 56 7 1 +3467 56 7 0 +3468 57 6 1 +3469 57 6 0 +3470 57 7 1 +3471 57 7 0 +3488 51 6 0 +3489 51 6 1 +3490 51 7 0 +3491 51 7 1 +3492 50 6 0 +3493 50 6 1 +3494 50 7 0 +3495 50 7 1 +3496 48 7 1 +3497 48 7 0 +3498 48 6 1 +3499 48 6 0 +3500 49 7 1 +3501 49 7 0 +3502 49 6 1 +3503 49 6 0 +3504 52 6 0 +3505 52 6 1 +3506 52 7 0 +3507 52 7 1 +3508 53 6 0 +3509 53 6 1 +3510 53 7 0 +3511 53 7 1 +3512 55 7 1 +3513 55 7 0 +3514 55 6 1 +3515 55 6 0 +3516 54 7 1 +3517 54 7 0 +3518 54 6 1 +3519 54 6 0 +3520 60 7 0 +3521 60 7 1 +3522 60 6 0 +3523 60 6 1 +3524 61 7 0 +3525 61 7 1 +3526 61 6 0 +3527 61 6 1 +3528 63 6 1 +3529 63 6 0 +3530 63 7 1 +3531 63 7 0 +3532 62 6 1 +3533 62 6 0 +3534 62 7 1 +3535 62 7 0 +3584 59 5 0 +3585 59 5 1 +3586 59 4 0 +3587 59 4 1 +3588 58 5 0 +3589 58 5 1 +3590 58 4 0 +3591 58 4 1 +3592 56 4 1 +3593 56 4 0 +3594 56 5 1 +3595 56 5 0 +3596 57 4 1 +3597 57 4 0 +3598 57 5 1 +3599 57 5 0 +3616 51 4 0 +3617 51 4 1 +3618 51 5 0 +3619 51 5 1 +3620 50 4 0 +3621 50 4 1 +3622 50 5 0 +3623 50 5 1 +3624 48 5 1 +3625 48 5 0 +3626 48 4 1 +3627 48 4 0 +3628 49 5 1 +3629 49 5 0 +3630 49 4 1 +3631 49 4 0 +3632 52 4 0 +3633 52 4 1 +3634 52 5 0 +3635 52 5 1 +3636 53 4 0 +3637 53 4 1 +3638 53 5 0 +3639 53 5 1 +3640 55 5 1 +3641 55 5 0 +3642 55 4 1 +3643 55 4 0 +3644 54 5 1 +3645 54 5 0 +3646 54 4 1 +3647 54 4 0 +3648 60 5 0 +3649 60 5 1 +3650 60 4 0 +3651 60 4 1 +3652 61 5 0 +3653 61 5 1 +3654 61 4 0 +3655 61 4 1 +3656 63 4 1 +3657 63 4 0 +3658 63 5 1 +3659 63 5 0 +3660 62 4 1 +3661 62 4 0 +3662 62 5 1 +3663 62 5 0 +3712 59 3 0 +3713 59 3 1 +3714 59 2 0 +3715 59 2 1 +3716 58 3 0 +3717 58 3 1 +3718 58 2 0 +3719 58 2 1 +3720 56 2 1 +3721 56 2 0 +3722 56 3 1 +3723 56 3 0 +3724 57 2 1 +3725 57 2 0 +3726 57 3 1 +3727 57 3 0 +3744 51 2 0 +3745 51 2 1 +3746 51 3 0 +3747 51 3 1 +3748 50 2 0 +3749 50 2 1 +3750 50 3 0 +3751 50 3 1 +3752 48 3 1 +3753 48 3 0 +3754 48 2 1 +3755 48 2 0 +3756 49 3 1 +3757 49 3 0 +3758 49 2 1 +3759 49 2 0 +3760 52 2 0 +3761 52 2 1 +3762 52 3 0 +3763 52 3 1 +3764 53 2 0 +3765 53 2 1 +3766 53 3 0 +3767 53 3 1 +3768 55 3 1 +3769 55 3 0 +3770 55 2 1 +3771 55 2 0 +3772 54 3 1 +3773 54 3 0 +3774 54 2 1 +3775 54 2 0 +3776 60 3 0 +3777 60 3 1 +3778 60 2 0 +3779 60 2 1 +3780 61 3 0 +3781 61 3 1 +3782 61 2 0 +3783 61 2 1 +3784 63 2 1 +3785 63 2 0 +3786 63 3 1 +3787 63 3 0 +3788 62 2 1 +3789 62 2 0 +3790 62 3 1 +3791 62 3 0 +3840 59 1 0 +3841 59 1 1 +3842 59 0 0 +3843 59 0 1 +3844 58 1 0 +3845 58 1 1 +3846 58 0 0 +3847 58 0 1 +3848 56 0 1 +3849 56 0 0 +3850 56 1 1 +3851 56 1 0 +3852 57 0 1 +3853 57 0 0 +3854 57 1 1 +3855 57 1 0 +3872 51 0 0 +3873 51 0 1 +3874 51 1 0 +3875 51 1 1 +3876 50 0 0 +3877 50 0 1 +3878 50 1 0 +3879 50 1 1 +3880 48 1 1 +3881 48 1 0 +3882 48 0 1 +3883 48 0 0 +3884 49 1 1 +3885 49 1 0 +3886 49 0 1 +3887 49 0 0 +3888 52 0 0 +3889 52 0 1 +3890 52 1 0 +3891 52 1 1 +3892 53 0 0 +3893 53 0 1 +3894 53 1 0 +3895 53 1 1 +3896 55 1 1 +3897 55 1 0 +3898 55 0 1 +3899 55 0 0 +3900 54 1 1 +3901 54 1 0 +3902 54 0 1 +3903 54 0 0 +3904 60 1 0 +3905 60 1 1 +3906 60 0 0 +3907 60 0 1 +3908 61 1 0 +3909 61 1 1 +3910 61 0 0 +3911 61 0 1 +3912 63 0 1 +3913 63 0 0 +3914 63 1 1 +3915 63 1 0 +3916 62 0 1 +3917 62 0 0 +3918 62 1 1 +3919 62 1 0 diff --git a/Detectors/PHOS/base/files/Mod2RCU0.data b/Detectors/PHOS/base/files/Mod2RCU0.data new file mode 100644 index 0000000000000..4739df6e3e61e --- /dev/null +++ b/Detectors/PHOS/base/files/Mod2RCU0.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 0 0 2 + 1 0 1 2 + 2 0 2 2 + 3 0 3 2 + 4 0 4 2 + 5 0 5 2 + 6 0 6 2 + 7 0 7 2 + 8 0 8 2 + 9 0 9 2 + 10 0 10 2 + 11 0 11 2 + 12 0 12 2 + 13 0 13 2 + 14 0 14 2 + 15 0 15 2 + 16 0 16 2 + 17 0 17 2 + 18 0 18 2 + 19 0 19 2 + 20 0 20 2 + 21 0 21 2 + 22 0 22 2 + 23 0 23 2 + 24 0 24 2 + 25 0 25 2 + 26 0 26 2 + 27 0 27 2 + 28 0 28 2 + 29 0 29 2 + 30 0 30 2 + 31 0 31 2 + 32 0 32 2 + 33 0 33 2 + 34 0 34 2 + 35 0 35 2 + 36 0 36 2 + 37 0 37 2 + 38 0 38 2 + 39 0 39 2 + 40 0 40 2 + 41 0 41 2 + 42 0 42 2 + 43 0 43 2 + 44 0 44 2 + 45 0 45 2 + 46 0 46 2 + 47 0 47 2 + 48 0 48 2 + 49 0 49 2 + 50 0 50 2 + 51 0 51 2 + 52 0 52 2 + 53 0 53 2 + 54 0 54 2 + 55 0 55 2 + 56 0 56 2 + 57 0 57 2 + 58 0 58 2 + 59 0 59 2 + 60 0 60 2 + 61 0 61 2 + 62 0 62 2 + 63 0 63 2 + 64 0 64 2 + 65 0 65 2 + 66 0 66 2 + 67 0 67 2 + 68 0 68 2 + 69 0 69 2 + 70 0 70 2 + 71 0 71 2 + 72 0 72 2 + 73 0 73 2 + 74 0 74 2 + 75 0 75 2 + 76 0 76 2 + 77 0 77 2 + 78 0 78 2 + 79 0 79 2 + 80 0 80 2 + 81 0 81 2 + 82 0 82 2 + 83 0 83 2 + 84 0 84 2 + 85 0 85 2 + 86 0 86 2 + 87 0 87 2 + 88 0 88 2 + 89 0 89 2 + 90 0 90 2 + 91 0 91 2 + 92 0 92 2 + 93 0 93 2 + 94 0 94 2 + 95 0 95 2 + 96 0 96 2 + 97 0 97 2 + 98 0 98 2 + 99 0 99 2 + 100 0 100 2 + 101 0 101 2 + 102 0 102 2 + 103 0 103 2 + 104 0 104 2 + 105 0 105 2 + 106 0 106 2 + 107 0 107 2 + 108 0 108 2 + 109 0 109 2 + 110 0 110 2 + 111 0 111 2 + 112 0 112 2 + 113 0 113 2 + 114 0 114 2 + 115 0 115 2 + 116 0 116 2 + 117 0 117 2 + 118 0 118 2 + 119 0 119 2 + 120 0 120 2 + 121 0 121 2 + 122 0 122 2 + 123 0 123 2 + 124 0 124 2 + 125 0 125 2 + 126 0 126 2 + 127 0 127 2 +2048 0 2048 2 +2049 0 2049 2 +2050 0 2050 2 +2051 0 2051 2 +2052 0 2052 2 +2053 0 2053 2 +2054 0 2054 2 +2055 0 2055 2 +2056 0 2056 2 +2057 0 2057 2 +2058 0 2058 2 +2059 0 2059 2 +2060 0 2060 2 +2061 0 2061 2 +2062 0 2062 2 +2063 0 2063 2 +2064 0 2064 2 +2065 0 2065 2 +2066 0 2066 2 +2067 0 2067 2 +2068 0 2068 2 +2069 0 2069 2 +2070 0 2070 2 +2071 0 2071 2 +2072 0 2072 2 +2073 0 2073 2 +2074 0 2074 2 +2075 0 2075 2 +2076 0 2076 2 +2077 0 2077 2 +2078 0 2078 2 +2079 0 2079 2 +2080 0 2080 2 +2081 0 2081 2 +2082 0 2082 2 +2083 0 2083 2 +2084 0 2084 2 +2085 0 2085 2 +2086 0 2086 2 +2087 0 2087 2 +2088 0 2088 2 +2089 0 2089 2 +2090 0 2090 2 +2091 0 2091 2 +2092 0 2092 2 +2093 0 2093 2 +2094 0 2094 2 +2095 0 2095 2 +2096 0 2096 2 +2097 0 2097 2 +2098 0 2098 2 +2099 0 2099 2 +2100 0 2100 2 +2101 0 2101 2 +2102 0 2102 2 +2103 0 2103 2 +2104 0 2104 2 +2105 0 2105 2 +2106 0 2106 2 +2107 0 2107 2 +2108 0 2108 2 +2109 0 2109 2 +2110 0 2110 2 +2111 0 2111 2 +2112 0 2112 2 +2113 0 2113 2 +2114 0 2114 2 +2115 0 2115 2 +2116 0 2116 2 +2117 0 2117 2 +2118 0 2118 2 +2119 0 2119 2 +2120 0 2120 2 +2121 0 2121 2 +2122 0 2122 2 +2123 0 2123 2 +2124 0 2124 2 +2125 0 2125 2 +2126 0 2126 2 +2127 0 2127 2 +2128 0 2128 2 +2129 0 2129 2 +2130 0 2130 2 +2131 0 2131 2 +2132 0 2132 2 +2133 0 2133 2 +2134 0 2134 2 +2135 0 2135 2 +2136 0 2136 2 +2137 0 2137 2 +2138 0 2138 2 +2139 0 2139 2 +2140 0 2140 2 +2141 0 2141 2 +2142 0 2142 2 +2143 0 2143 2 +2144 0 2144 2 +2145 0 2145 2 +2146 0 2146 2 +2147 0 2147 2 +2148 0 2148 2 +2149 0 2149 2 +2150 0 2150 2 +2151 0 2151 2 +2152 0 2152 2 +2153 0 2153 2 +2154 0 2154 2 +2155 0 2155 2 +2156 0 2156 2 +2157 0 2157 2 +2158 0 2158 2 +2159 0 2159 2 +2160 0 2160 2 +2161 0 2161 2 +2162 0 2162 2 +2163 0 2163 2 +2164 0 2164 2 +2165 0 2165 2 +2166 0 2166 2 +2167 0 2167 2 +2168 0 2168 2 +2169 0 2169 2 +2170 0 2170 2 +2171 0 2171 2 +2172 0 2172 2 +2173 0 2173 2 +2174 0 2174 2 +2175 0 2175 2 + 128 11 29 0 + 129 11 29 1 + 130 11 28 0 + 131 11 28 1 + 132 10 29 0 + 133 10 29 1 + 134 10 28 0 + 135 10 28 1 + 136 8 28 1 + 137 8 28 0 + 138 8 29 1 + 139 8 29 0 + 140 9 28 1 + 141 9 28 0 + 142 9 29 1 + 143 9 29 0 + 160 3 28 0 + 161 3 28 1 + 162 3 29 0 + 163 3 29 1 + 164 2 28 0 + 165 2 28 1 + 166 2 29 0 + 167 2 29 1 + 168 0 29 1 + 169 0 29 0 + 170 0 28 1 + 171 0 28 0 + 172 1 29 1 + 173 1 29 0 + 174 1 28 1 + 175 1 28 0 + 176 4 28 0 + 177 4 28 1 + 178 4 29 0 + 179 4 29 1 + 180 5 28 0 + 181 5 28 1 + 182 5 29 0 + 183 5 29 1 + 184 7 29 1 + 185 7 29 0 + 186 7 28 1 + 187 7 28 0 + 188 6 29 1 + 189 6 29 0 + 190 6 28 1 + 191 6 28 0 + 192 12 29 0 + 193 12 29 1 + 194 12 28 0 + 195 12 28 1 + 196 13 29 0 + 197 13 29 1 + 198 13 28 0 + 199 13 28 1 + 200 15 28 1 + 201 15 28 0 + 202 15 29 1 + 203 15 29 0 + 204 14 28 1 + 205 14 28 0 + 206 14 29 1 + 207 14 29 0 + 256 11 31 0 + 257 11 31 1 + 258 11 30 0 + 259 11 30 1 + 260 10 31 0 + 261 10 31 1 + 262 10 30 0 + 263 10 30 1 + 264 8 30 1 + 265 8 30 0 + 266 8 31 1 + 267 8 31 0 + 268 9 30 1 + 269 9 30 0 + 270 9 31 1 + 271 9 31 0 + 288 3 30 0 + 289 3 30 1 + 290 3 31 0 + 291 3 31 1 + 292 2 30 0 + 293 2 30 1 + 294 2 31 0 + 295 2 31 1 + 296 0 31 1 + 297 0 31 0 + 298 0 30 1 + 299 0 30 0 + 300 1 31 1 + 301 1 31 0 + 302 1 30 1 + 303 1 30 0 + 304 4 30 0 + 305 4 30 1 + 306 4 31 0 + 307 4 31 1 + 308 5 30 0 + 309 5 30 1 + 310 5 31 0 + 311 5 31 1 + 312 7 31 1 + 313 7 31 0 + 314 7 30 1 + 315 7 30 0 + 316 6 31 1 + 317 6 31 0 + 318 6 30 1 + 319 6 30 0 + 320 12 31 0 + 321 12 31 1 + 322 12 30 0 + 323 12 30 1 + 324 13 31 0 + 325 13 31 1 + 326 13 30 0 + 327 13 30 1 + 328 15 30 1 + 329 15 30 0 + 330 15 31 1 + 331 15 31 0 + 332 14 30 1 + 333 14 30 0 + 334 14 31 1 + 335 14 31 0 + 384 11 33 0 + 385 11 33 1 + 386 11 32 0 + 387 11 32 1 + 388 10 33 0 + 389 10 33 1 + 390 10 32 0 + 391 10 32 1 + 392 8 32 1 + 393 8 32 0 + 394 8 33 1 + 395 8 33 0 + 396 9 32 1 + 397 9 32 0 + 398 9 33 1 + 399 9 33 0 + 416 3 32 0 + 417 3 32 1 + 418 3 33 0 + 419 3 33 1 + 420 2 32 0 + 421 2 32 1 + 422 2 33 0 + 423 2 33 1 + 424 0 33 1 + 425 0 33 0 + 426 0 32 1 + 427 0 32 0 + 428 1 33 1 + 429 1 33 0 + 430 1 32 1 + 431 1 32 0 + 432 4 32 0 + 433 4 32 1 + 434 4 33 0 + 435 4 33 1 + 436 5 32 0 + 437 5 32 1 + 438 5 33 0 + 439 5 33 1 + 440 7 33 1 + 441 7 33 0 + 442 7 32 1 + 443 7 32 0 + 444 6 33 1 + 445 6 33 0 + 446 6 32 1 + 447 6 32 0 + 448 12 33 0 + 449 12 33 1 + 450 12 32 0 + 451 12 32 1 + 452 13 33 0 + 453 13 33 1 + 454 13 32 0 + 455 13 32 1 + 456 15 32 1 + 457 15 32 0 + 458 15 33 1 + 459 15 33 0 + 460 14 32 1 + 461 14 32 0 + 462 14 33 1 + 463 14 33 0 + 512 11 35 0 + 513 11 35 1 + 514 11 34 0 + 515 11 34 1 + 516 10 35 0 + 517 10 35 1 + 518 10 34 0 + 519 10 34 1 + 520 8 34 1 + 521 8 34 0 + 522 8 35 1 + 523 8 35 0 + 524 9 34 1 + 525 9 34 0 + 526 9 35 1 + 527 9 35 0 + 544 3 34 0 + 545 3 34 1 + 546 3 35 0 + 547 3 35 1 + 548 2 34 0 + 549 2 34 1 + 550 2 35 0 + 551 2 35 1 + 552 0 35 1 + 553 0 35 0 + 554 0 34 1 + 555 0 34 0 + 556 1 35 1 + 557 1 35 0 + 558 1 34 1 + 559 1 34 0 + 560 4 34 0 + 561 4 34 1 + 562 4 35 0 + 563 4 35 1 + 564 5 34 0 + 565 5 34 1 + 566 5 35 0 + 567 5 35 1 + 568 7 35 1 + 569 7 35 0 + 570 7 34 1 + 571 7 34 0 + 572 6 35 1 + 573 6 35 0 + 574 6 34 1 + 575 6 34 0 + 576 12 35 0 + 577 12 35 1 + 578 12 34 0 + 579 12 34 1 + 580 13 35 0 + 581 13 35 1 + 582 13 34 0 + 583 13 34 1 + 584 15 34 1 + 585 15 34 0 + 586 15 35 1 + 587 15 35 0 + 588 14 34 1 + 589 14 34 0 + 590 14 35 1 + 591 14 35 0 + 640 11 37 0 + 641 11 37 1 + 642 11 36 0 + 643 11 36 1 + 644 10 37 0 + 645 10 37 1 + 646 10 36 0 + 647 10 36 1 + 648 8 36 1 + 649 8 36 0 + 650 8 37 1 + 651 8 37 0 + 652 9 36 1 + 653 9 36 0 + 654 9 37 1 + 655 9 37 0 + 672 3 36 0 + 673 3 36 1 + 674 3 37 0 + 675 3 37 1 + 676 2 36 0 + 677 2 36 1 + 678 2 37 0 + 679 2 37 1 + 680 0 37 1 + 681 0 37 0 + 682 0 36 1 + 683 0 36 0 + 684 1 37 1 + 685 1 37 0 + 686 1 36 1 + 687 1 36 0 + 688 4 36 0 + 689 4 36 1 + 690 4 37 0 + 691 4 37 1 + 692 5 36 0 + 693 5 36 1 + 694 5 37 0 + 695 5 37 1 + 696 7 37 1 + 697 7 37 0 + 698 7 36 1 + 699 7 36 0 + 700 6 37 1 + 701 6 37 0 + 702 6 36 1 + 703 6 36 0 + 704 12 37 0 + 705 12 37 1 + 706 12 36 0 + 707 12 36 1 + 708 13 37 0 + 709 13 37 1 + 710 13 36 0 + 711 13 36 1 + 712 15 36 1 + 713 15 36 0 + 714 15 37 1 + 715 15 37 0 + 716 14 36 1 + 717 14 36 0 + 718 14 37 1 + 719 14 37 0 + 768 11 39 0 + 769 11 39 1 + 770 11 38 0 + 771 11 38 1 + 772 10 39 0 + 773 10 39 1 + 774 10 38 0 + 775 10 38 1 + 776 8 38 1 + 777 8 38 0 + 778 8 39 1 + 779 8 39 0 + 780 9 38 1 + 781 9 38 0 + 782 9 39 1 + 783 9 39 0 + 800 3 38 0 + 801 3 38 1 + 802 3 39 0 + 803 3 39 1 + 804 2 38 0 + 805 2 38 1 + 806 2 39 0 + 807 2 39 1 + 808 0 39 1 + 809 0 39 0 + 810 0 38 1 + 811 0 38 0 + 812 1 39 1 + 813 1 39 0 + 814 1 38 1 + 815 1 38 0 + 816 4 38 0 + 817 4 38 1 + 818 4 39 0 + 819 4 39 1 + 820 5 38 0 + 821 5 38 1 + 822 5 39 0 + 823 5 39 1 + 824 7 39 1 + 825 7 39 0 + 826 7 38 1 + 827 7 38 0 + 828 6 39 1 + 829 6 39 0 + 830 6 38 1 + 831 6 38 0 + 832 12 39 0 + 833 12 39 1 + 834 12 38 0 + 835 12 38 1 + 836 13 39 0 + 837 13 39 1 + 838 13 38 0 + 839 13 38 1 + 840 15 38 1 + 841 15 38 0 + 842 15 39 1 + 843 15 39 0 + 844 14 38 1 + 845 14 38 0 + 846 14 39 1 + 847 14 39 0 + 896 11 41 0 + 897 11 41 1 + 898 11 40 0 + 899 11 40 1 + 900 10 41 0 + 901 10 41 1 + 902 10 40 0 + 903 10 40 1 + 904 8 40 1 + 905 8 40 0 + 906 8 41 1 + 907 8 41 0 + 908 9 40 1 + 909 9 40 0 + 910 9 41 1 + 911 9 41 0 + 928 3 40 0 + 929 3 40 1 + 930 3 41 0 + 931 3 41 1 + 932 2 40 0 + 933 2 40 1 + 934 2 41 0 + 935 2 41 1 + 936 0 41 1 + 937 0 41 0 + 938 0 40 1 + 939 0 40 0 + 940 1 41 1 + 941 1 41 0 + 942 1 40 1 + 943 1 40 0 + 944 4 40 0 + 945 4 40 1 + 946 4 41 0 + 947 4 41 1 + 948 5 40 0 + 949 5 40 1 + 950 5 41 0 + 951 5 41 1 + 952 7 41 1 + 953 7 41 0 + 954 7 40 1 + 955 7 40 0 + 956 6 41 1 + 957 6 41 0 + 958 6 40 1 + 959 6 40 0 + 960 12 41 0 + 961 12 41 1 + 962 12 40 0 + 963 12 40 1 + 964 13 41 0 + 965 13 41 1 + 966 13 40 0 + 967 13 40 1 + 968 15 40 1 + 969 15 40 0 + 970 15 41 1 + 971 15 41 0 + 972 14 40 1 + 973 14 40 0 + 974 14 41 1 + 975 14 41 0 +1024 11 43 0 +1025 11 43 1 +1026 11 42 0 +1027 11 42 1 +1028 10 43 0 +1029 10 43 1 +1030 10 42 0 +1031 10 42 1 +1032 8 42 1 +1033 8 42 0 +1034 8 43 1 +1035 8 43 0 +1036 9 42 1 +1037 9 42 0 +1038 9 43 1 +1039 9 43 0 +1056 3 42 0 +1057 3 42 1 +1058 3 43 0 +1059 3 43 1 +1060 2 42 0 +1061 2 42 1 +1062 2 43 0 +1063 2 43 1 +1064 0 43 1 +1065 0 43 0 +1066 0 42 1 +1067 0 42 0 +1068 1 43 1 +1069 1 43 0 +1070 1 42 1 +1071 1 42 0 +1072 4 42 0 +1073 4 42 1 +1074 4 43 0 +1075 4 43 1 +1076 5 42 0 +1077 5 42 1 +1078 5 43 0 +1079 5 43 1 +1080 7 43 1 +1081 7 43 0 +1082 7 42 1 +1083 7 42 0 +1084 6 43 1 +1085 6 43 0 +1086 6 42 1 +1087 6 42 0 +1088 12 43 0 +1089 12 43 1 +1090 12 42 0 +1091 12 42 1 +1092 13 43 0 +1093 13 43 1 +1094 13 42 0 +1095 13 42 1 +1096 15 42 1 +1097 15 42 0 +1098 15 43 1 +1099 15 43 0 +1100 14 42 1 +1101 14 42 0 +1102 14 43 1 +1103 14 43 0 +1152 11 45 0 +1153 11 45 1 +1154 11 44 0 +1155 11 44 1 +1156 10 45 0 +1157 10 45 1 +1158 10 44 0 +1159 10 44 1 +1160 8 44 1 +1161 8 44 0 +1162 8 45 1 +1163 8 45 0 +1164 9 44 1 +1165 9 44 0 +1166 9 45 1 +1167 9 45 0 +1184 3 44 0 +1185 3 44 1 +1186 3 45 0 +1187 3 45 1 +1188 2 44 0 +1189 2 44 1 +1190 2 45 0 +1191 2 45 1 +1192 0 45 1 +1193 0 45 0 +1194 0 44 1 +1195 0 44 0 +1196 1 45 1 +1197 1 45 0 +1198 1 44 1 +1199 1 44 0 +1200 4 44 0 +1201 4 44 1 +1202 4 45 0 +1203 4 45 1 +1204 5 44 0 +1205 5 44 1 +1206 5 45 0 +1207 5 45 1 +1208 7 45 1 +1209 7 45 0 +1210 7 44 1 +1211 7 44 0 +1212 6 45 1 +1213 6 45 0 +1214 6 44 1 +1215 6 44 0 +1216 12 45 0 +1217 12 45 1 +1218 12 44 0 +1219 12 44 1 +1220 13 45 0 +1221 13 45 1 +1222 13 44 0 +1223 13 44 1 +1224 15 44 1 +1225 15 44 0 +1226 15 45 1 +1227 15 45 0 +1228 14 44 1 +1229 14 44 0 +1230 14 45 1 +1231 14 45 0 +1280 11 47 0 +1281 11 47 1 +1282 11 46 0 +1283 11 46 1 +1284 10 47 0 +1285 10 47 1 +1286 10 46 0 +1287 10 46 1 +1288 8 46 1 +1289 8 46 0 +1290 8 47 1 +1291 8 47 0 +1292 9 46 1 +1293 9 46 0 +1294 9 47 1 +1295 9 47 0 +1312 3 46 0 +1313 3 46 1 +1314 3 47 0 +1315 3 47 1 +1316 2 46 0 +1317 2 46 1 +1318 2 47 0 +1319 2 47 1 +1320 0 47 1 +1321 0 47 0 +1322 0 46 1 +1323 0 46 0 +1324 1 47 1 +1325 1 47 0 +1326 1 46 1 +1327 1 46 0 +1328 4 46 0 +1329 4 46 1 +1330 4 47 0 +1331 4 47 1 +1332 5 46 0 +1333 5 46 1 +1334 5 47 0 +1335 5 47 1 +1336 7 47 1 +1337 7 47 0 +1338 7 46 1 +1339 7 46 0 +1340 6 47 1 +1341 6 47 0 +1342 6 46 1 +1343 6 46 0 +1344 12 47 0 +1345 12 47 1 +1346 12 46 0 +1347 12 46 1 +1348 13 47 0 +1349 13 47 1 +1350 13 46 0 +1351 13 46 1 +1352 15 46 1 +1353 15 46 0 +1354 15 47 1 +1355 15 47 0 +1356 14 46 1 +1357 14 46 0 +1358 14 47 1 +1359 14 47 0 +1408 11 49 0 +1409 11 49 1 +1410 11 48 0 +1411 11 48 1 +1412 10 49 0 +1413 10 49 1 +1414 10 48 0 +1415 10 48 1 +1416 8 48 1 +1417 8 48 0 +1418 8 49 1 +1419 8 49 0 +1420 9 48 1 +1421 9 48 0 +1422 9 49 1 +1423 9 49 0 +1440 3 48 0 +1441 3 48 1 +1442 3 49 0 +1443 3 49 1 +1444 2 48 0 +1445 2 48 1 +1446 2 49 0 +1447 2 49 1 +1448 0 49 1 +1449 0 49 0 +1450 0 48 1 +1451 0 48 0 +1452 1 49 1 +1453 1 49 0 +1454 1 48 1 +1455 1 48 0 +1456 4 48 0 +1457 4 48 1 +1458 4 49 0 +1459 4 49 1 +1460 5 48 0 +1461 5 48 1 +1462 5 49 0 +1463 5 49 1 +1464 7 49 1 +1465 7 49 0 +1466 7 48 1 +1467 7 48 0 +1468 6 49 1 +1469 6 49 0 +1470 6 48 1 +1471 6 48 0 +1472 12 49 0 +1473 12 49 1 +1474 12 48 0 +1475 12 48 1 +1476 13 49 0 +1477 13 49 1 +1478 13 48 0 +1479 13 48 1 +1480 15 48 1 +1481 15 48 0 +1482 15 49 1 +1483 15 49 0 +1484 14 48 1 +1485 14 48 0 +1486 14 49 1 +1487 14 49 0 +1536 11 51 0 +1537 11 51 1 +1538 11 50 0 +1539 11 50 1 +1540 10 51 0 +1541 10 51 1 +1542 10 50 0 +1543 10 50 1 +1544 8 50 1 +1545 8 50 0 +1546 8 51 1 +1547 8 51 0 +1548 9 50 1 +1549 9 50 0 +1550 9 51 1 +1551 9 51 0 +1568 3 50 0 +1569 3 50 1 +1570 3 51 0 +1571 3 51 1 +1572 2 50 0 +1573 2 50 1 +1574 2 51 0 +1575 2 51 1 +1576 0 51 1 +1577 0 51 0 +1578 0 50 1 +1579 0 50 0 +1580 1 51 1 +1581 1 51 0 +1582 1 50 1 +1583 1 50 0 +1584 4 50 0 +1585 4 50 1 +1586 4 51 0 +1587 4 51 1 +1588 5 50 0 +1589 5 50 1 +1590 5 51 0 +1591 5 51 1 +1592 7 51 1 +1593 7 51 0 +1594 7 50 1 +1595 7 50 0 +1596 6 51 1 +1597 6 51 0 +1598 6 50 1 +1599 6 50 0 +1600 12 51 0 +1601 12 51 1 +1602 12 50 0 +1603 12 50 1 +1604 13 51 0 +1605 13 51 1 +1606 13 50 0 +1607 13 50 1 +1608 15 50 1 +1609 15 50 0 +1610 15 51 1 +1611 15 51 0 +1612 14 50 1 +1613 14 50 0 +1614 14 51 1 +1615 14 51 0 +1664 11 53 0 +1665 11 53 1 +1666 11 52 0 +1667 11 52 1 +1668 10 53 0 +1669 10 53 1 +1670 10 52 0 +1671 10 52 1 +1672 8 52 1 +1673 8 52 0 +1674 8 53 1 +1675 8 53 0 +1676 9 52 1 +1677 9 52 0 +1678 9 53 1 +1679 9 53 0 +1696 3 52 0 +1697 3 52 1 +1698 3 53 0 +1699 3 53 1 +1700 2 52 0 +1701 2 52 1 +1702 2 53 0 +1703 2 53 1 +1704 0 53 1 +1705 0 53 0 +1706 0 52 1 +1707 0 52 0 +1708 1 53 1 +1709 1 53 0 +1710 1 52 1 +1711 1 52 0 +1712 4 52 0 +1713 4 52 1 +1714 4 53 0 +1715 4 53 1 +1716 5 52 0 +1717 5 52 1 +1718 5 53 0 +1719 5 53 1 +1720 7 53 1 +1721 7 53 0 +1722 7 52 1 +1723 7 52 0 +1724 6 53 1 +1725 6 53 0 +1726 6 52 1 +1727 6 52 0 +1728 12 53 0 +1729 12 53 1 +1730 12 52 0 +1731 12 52 1 +1732 13 53 0 +1733 13 53 1 +1734 13 52 0 +1735 13 52 1 +1736 15 52 1 +1737 15 52 0 +1738 15 53 1 +1739 15 53 0 +1740 14 52 1 +1741 14 52 0 +1742 14 53 1 +1743 14 53 0 +1792 11 55 0 +1793 11 55 1 +1794 11 54 0 +1795 11 54 1 +1796 10 55 0 +1797 10 55 1 +1798 10 54 0 +1799 10 54 1 +1800 8 54 1 +1801 8 54 0 +1802 8 55 1 +1803 8 55 0 +1804 9 54 1 +1805 9 54 0 +1806 9 55 1 +1807 9 55 0 +1824 3 54 0 +1825 3 54 1 +1826 3 55 0 +1827 3 55 1 +1828 2 54 0 +1829 2 54 1 +1830 2 55 0 +1831 2 55 1 +1832 0 55 1 +1833 0 55 0 +1834 0 54 1 +1835 0 54 0 +1836 1 55 1 +1837 1 55 0 +1838 1 54 1 +1839 1 54 0 +1840 4 54 0 +1841 4 54 1 +1842 4 55 0 +1843 4 55 1 +1844 5 54 0 +1845 5 54 1 +1846 5 55 0 +1847 5 55 1 +1848 7 55 1 +1849 7 55 0 +1850 7 54 1 +1851 7 54 0 +1852 6 55 1 +1853 6 55 0 +1854 6 54 1 +1855 6 54 0 +1856 12 55 0 +1857 12 55 1 +1858 12 54 0 +1859 12 54 1 +1860 13 55 0 +1861 13 55 1 +1862 13 54 0 +1863 13 54 1 +1864 15 54 1 +1865 15 54 0 +1866 15 55 1 +1867 15 55 0 +1868 14 54 1 +1869 14 54 0 +1870 14 55 1 +1871 14 55 0 +2176 11 27 0 +2177 11 27 1 +2178 11 26 0 +2179 11 26 1 +2180 10 27 0 +2181 10 27 1 +2182 10 26 0 +2183 10 26 1 +2184 8 26 1 +2185 8 26 0 +2186 8 27 1 +2187 8 27 0 +2188 9 26 1 +2189 9 26 0 +2190 9 27 1 +2191 9 27 0 +2208 3 26 0 +2209 3 26 1 +2210 3 27 0 +2211 3 27 1 +2212 2 26 0 +2213 2 26 1 +2214 2 27 0 +2215 2 27 1 +2216 0 27 1 +2217 0 27 0 +2218 0 26 1 +2219 0 26 0 +2220 1 27 1 +2221 1 27 0 +2222 1 26 1 +2223 1 26 0 +2224 4 26 0 +2225 4 26 1 +2226 4 27 0 +2227 4 27 1 +2228 5 26 0 +2229 5 26 1 +2230 5 27 0 +2231 5 27 1 +2232 7 27 1 +2233 7 27 0 +2234 7 26 1 +2235 7 26 0 +2236 6 27 1 +2237 6 27 0 +2238 6 26 1 +2239 6 26 0 +2240 12 27 0 +2241 12 27 1 +2242 12 26 0 +2243 12 26 1 +2244 13 27 0 +2245 13 27 1 +2246 13 26 0 +2247 13 26 1 +2248 15 26 1 +2249 15 26 0 +2250 15 27 1 +2251 15 27 0 +2252 14 26 1 +2253 14 26 0 +2254 14 27 1 +2255 14 27 0 +2304 11 25 0 +2305 11 25 1 +2306 11 24 0 +2307 11 24 1 +2308 10 25 0 +2309 10 25 1 +2310 10 24 0 +2311 10 24 1 +2312 8 24 1 +2313 8 24 0 +2314 8 25 1 +2315 8 25 0 +2316 9 24 1 +2317 9 24 0 +2318 9 25 1 +2319 9 25 0 +2336 3 24 0 +2337 3 24 1 +2338 3 25 0 +2339 3 25 1 +2340 2 24 0 +2341 2 24 1 +2342 2 25 0 +2343 2 25 1 +2344 0 25 1 +2345 0 25 0 +2346 0 24 1 +2347 0 24 0 +2348 1 25 1 +2349 1 25 0 +2350 1 24 1 +2351 1 24 0 +2352 4 24 0 +2353 4 24 1 +2354 4 25 0 +2355 4 25 1 +2356 5 24 0 +2357 5 24 1 +2358 5 25 0 +2359 5 25 1 +2360 7 25 1 +2361 7 25 0 +2362 7 24 1 +2363 7 24 0 +2364 6 25 1 +2365 6 25 0 +2366 6 24 1 +2367 6 24 0 +2368 12 25 0 +2369 12 25 1 +2370 12 24 0 +2371 12 24 1 +2372 13 25 0 +2373 13 25 1 +2374 13 24 0 +2375 13 24 1 +2376 15 24 1 +2377 15 24 0 +2378 15 25 1 +2379 15 25 0 +2380 14 24 1 +2381 14 24 0 +2382 14 25 1 +2383 14 25 0 +2432 11 23 0 +2433 11 23 1 +2434 11 22 0 +2435 11 22 1 +2436 10 23 0 +2437 10 23 1 +2438 10 22 0 +2439 10 22 1 +2440 8 22 1 +2441 8 22 0 +2442 8 23 1 +2443 8 23 0 +2444 9 22 1 +2445 9 22 0 +2446 9 23 1 +2447 9 23 0 +2464 3 22 0 +2465 3 22 1 +2466 3 23 0 +2467 3 23 1 +2468 2 22 0 +2469 2 22 1 +2470 2 23 0 +2471 2 23 1 +2472 0 23 1 +2473 0 23 0 +2474 0 22 1 +2475 0 22 0 +2476 1 23 1 +2477 1 23 0 +2478 1 22 1 +2479 1 22 0 +2480 4 22 0 +2481 4 22 1 +2482 4 23 0 +2483 4 23 1 +2484 5 22 0 +2485 5 22 1 +2486 5 23 0 +2487 5 23 1 +2488 7 23 1 +2489 7 23 0 +2490 7 22 1 +2491 7 22 0 +2492 6 23 1 +2493 6 23 0 +2494 6 22 1 +2495 6 22 0 +2496 12 23 0 +2497 12 23 1 +2498 12 22 0 +2499 12 22 1 +2500 13 23 0 +2501 13 23 1 +2502 13 22 0 +2503 13 22 1 +2504 15 22 1 +2505 15 22 0 +2506 15 23 1 +2507 15 23 0 +2508 14 22 1 +2509 14 22 0 +2510 14 23 1 +2511 14 23 0 +2560 11 21 0 +2561 11 21 1 +2562 11 20 0 +2563 11 20 1 +2564 10 21 0 +2565 10 21 1 +2566 10 20 0 +2567 10 20 1 +2568 8 20 1 +2569 8 20 0 +2570 8 21 1 +2571 8 21 0 +2572 9 20 1 +2573 9 20 0 +2574 9 21 1 +2575 9 21 0 +2592 3 20 0 +2593 3 20 1 +2594 3 21 0 +2595 3 21 1 +2596 2 20 0 +2597 2 20 1 +2598 2 21 0 +2599 2 21 1 +2600 0 21 1 +2601 0 21 0 +2602 0 20 1 +2603 0 20 0 +2604 1 21 1 +2605 1 21 0 +2606 1 20 1 +2607 1 20 0 +2608 4 20 0 +2609 4 20 1 +2610 4 21 0 +2611 4 21 1 +2612 5 20 0 +2613 5 20 1 +2614 5 21 0 +2615 5 21 1 +2616 7 21 1 +2617 7 21 0 +2618 7 20 1 +2619 7 20 0 +2620 6 21 1 +2621 6 21 0 +2622 6 20 1 +2623 6 20 0 +2624 12 21 0 +2625 12 21 1 +2626 12 20 0 +2627 12 20 1 +2628 13 21 0 +2629 13 21 1 +2630 13 20 0 +2631 13 20 1 +2632 15 20 1 +2633 15 20 0 +2634 15 21 1 +2635 15 21 0 +2636 14 20 1 +2637 14 20 0 +2638 14 21 1 +2639 14 21 0 +2688 11 19 0 +2689 11 19 1 +2690 11 18 0 +2691 11 18 1 +2692 10 19 0 +2693 10 19 1 +2694 10 18 0 +2695 10 18 1 +2696 8 18 1 +2697 8 18 0 +2698 8 19 1 +2699 8 19 0 +2700 9 18 1 +2701 9 18 0 +2702 9 19 1 +2703 9 19 0 +2720 3 18 0 +2721 3 18 1 +2722 3 19 0 +2723 3 19 1 +2724 2 18 0 +2725 2 18 1 +2726 2 19 0 +2727 2 19 1 +2728 0 19 1 +2729 0 19 0 +2730 0 18 1 +2731 0 18 0 +2732 1 19 1 +2733 1 19 0 +2734 1 18 1 +2735 1 18 0 +2736 4 18 0 +2737 4 18 1 +2738 4 19 0 +2739 4 19 1 +2740 5 18 0 +2741 5 18 1 +2742 5 19 0 +2743 5 19 1 +2744 7 19 1 +2745 7 19 0 +2746 7 18 1 +2747 7 18 0 +2748 6 19 1 +2749 6 19 0 +2750 6 18 1 +2751 6 18 0 +2752 12 19 0 +2753 12 19 1 +2754 12 18 0 +2755 12 18 1 +2756 13 19 0 +2757 13 19 1 +2758 13 18 0 +2759 13 18 1 +2760 15 18 1 +2761 15 18 0 +2762 15 19 1 +2763 15 19 0 +2764 14 18 1 +2765 14 18 0 +2766 14 19 1 +2767 14 19 0 +2816 11 17 0 +2817 11 17 1 +2818 11 16 0 +2819 11 16 1 +2820 10 17 0 +2821 10 17 1 +2822 10 16 0 +2823 10 16 1 +2824 8 16 1 +2825 8 16 0 +2826 8 17 1 +2827 8 17 0 +2828 9 16 1 +2829 9 16 0 +2830 9 17 1 +2831 9 17 0 +2848 3 16 0 +2849 3 16 1 +2850 3 17 0 +2851 3 17 1 +2852 2 16 0 +2853 2 16 1 +2854 2 17 0 +2855 2 17 1 +2856 0 17 1 +2857 0 17 0 +2858 0 16 1 +2859 0 16 0 +2860 1 17 1 +2861 1 17 0 +2862 1 16 1 +2863 1 16 0 +2864 4 16 0 +2865 4 16 1 +2866 4 17 0 +2867 4 17 1 +2868 5 16 0 +2869 5 16 1 +2870 5 17 0 +2871 5 17 1 +2872 7 17 1 +2873 7 17 0 +2874 7 16 1 +2875 7 16 0 +2876 6 17 1 +2877 6 17 0 +2878 6 16 1 +2879 6 16 0 +2880 12 17 0 +2881 12 17 1 +2882 12 16 0 +2883 12 16 1 +2884 13 17 0 +2885 13 17 1 +2886 13 16 0 +2887 13 16 1 +2888 15 16 1 +2889 15 16 0 +2890 15 17 1 +2891 15 17 0 +2892 14 16 1 +2893 14 16 0 +2894 14 17 1 +2895 14 17 0 +2944 11 15 0 +2945 11 15 1 +2946 11 14 0 +2947 11 14 1 +2948 10 15 0 +2949 10 15 1 +2950 10 14 0 +2951 10 14 1 +2952 8 14 1 +2953 8 14 0 +2954 8 15 1 +2955 8 15 0 +2956 9 14 1 +2957 9 14 0 +2958 9 15 1 +2959 9 15 0 +2976 3 14 0 +2977 3 14 1 +2978 3 15 0 +2979 3 15 1 +2980 2 14 0 +2981 2 14 1 +2982 2 15 0 +2983 2 15 1 +2984 0 15 1 +2985 0 15 0 +2986 0 14 1 +2987 0 14 0 +2988 1 15 1 +2989 1 15 0 +2990 1 14 1 +2991 1 14 0 +2992 4 14 0 +2993 4 14 1 +2994 4 15 0 +2995 4 15 1 +2996 5 14 0 +2997 5 14 1 +2998 5 15 0 +2999 5 15 1 +3000 7 15 1 +3001 7 15 0 +3002 7 14 1 +3003 7 14 0 +3004 6 15 1 +3005 6 15 0 +3006 6 14 1 +3007 6 14 0 +3008 12 15 0 +3009 12 15 1 +3010 12 14 0 +3011 12 14 1 +3012 13 15 0 +3013 13 15 1 +3014 13 14 0 +3015 13 14 1 +3016 15 14 1 +3017 15 14 0 +3018 15 15 1 +3019 15 15 0 +3020 14 14 1 +3021 14 14 0 +3022 14 15 1 +3023 14 15 0 +3072 11 13 0 +3073 11 13 1 +3074 11 12 0 +3075 11 12 1 +3076 10 13 0 +3077 10 13 1 +3078 10 12 0 +3079 10 12 1 +3080 8 12 1 +3081 8 12 0 +3082 8 13 1 +3083 8 13 0 +3084 9 12 1 +3085 9 12 0 +3086 9 13 1 +3087 9 13 0 +3104 3 12 0 +3105 3 12 1 +3106 3 13 0 +3107 3 13 1 +3108 2 12 0 +3109 2 12 1 +3110 2 13 0 +3111 2 13 1 +3112 0 13 1 +3113 0 13 0 +3114 0 12 1 +3115 0 12 0 +3116 1 13 1 +3117 1 13 0 +3118 1 12 1 +3119 1 12 0 +3120 4 12 0 +3121 4 12 1 +3122 4 13 0 +3123 4 13 1 +3124 5 12 0 +3125 5 12 1 +3126 5 13 0 +3127 5 13 1 +3128 7 13 1 +3129 7 13 0 +3130 7 12 1 +3131 7 12 0 +3132 6 13 1 +3133 6 13 0 +3134 6 12 1 +3135 6 12 0 +3136 12 13 0 +3137 12 13 1 +3138 12 12 0 +3139 12 12 1 +3140 13 13 0 +3141 13 13 1 +3142 13 12 0 +3143 13 12 1 +3144 15 12 1 +3145 15 12 0 +3146 15 13 1 +3147 15 13 0 +3148 14 12 1 +3149 14 12 0 +3150 14 13 1 +3151 14 13 0 +3200 11 11 0 +3201 11 11 1 +3202 11 10 0 +3203 11 10 1 +3204 10 11 0 +3205 10 11 1 +3206 10 10 0 +3207 10 10 1 +3208 8 10 1 +3209 8 10 0 +3210 8 11 1 +3211 8 11 0 +3212 9 10 1 +3213 9 10 0 +3214 9 11 1 +3215 9 11 0 +3232 3 10 0 +3233 3 10 1 +3234 3 11 0 +3235 3 11 1 +3236 2 10 0 +3237 2 10 1 +3238 2 11 0 +3239 2 11 1 +3240 0 11 1 +3241 0 11 0 +3242 0 10 1 +3243 0 10 0 +3244 1 11 1 +3245 1 11 0 +3246 1 10 1 +3247 1 10 0 +3248 4 10 0 +3249 4 10 1 +3250 4 11 0 +3251 4 11 1 +3252 5 10 0 +3253 5 10 1 +3254 5 11 0 +3255 5 11 1 +3256 7 11 1 +3257 7 11 0 +3258 7 10 1 +3259 7 10 0 +3260 6 11 1 +3261 6 11 0 +3262 6 10 1 +3263 6 10 0 +3264 12 11 0 +3265 12 11 1 +3266 12 10 0 +3267 12 10 1 +3268 13 11 0 +3269 13 11 1 +3270 13 10 0 +3271 13 10 1 +3272 15 10 1 +3273 15 10 0 +3274 15 11 1 +3275 15 11 0 +3276 14 10 1 +3277 14 10 0 +3278 14 11 1 +3279 14 11 0 +3328 11 9 0 +3329 11 9 1 +3330 11 8 0 +3331 11 8 1 +3332 10 9 0 +3333 10 9 1 +3334 10 8 0 +3335 10 8 1 +3336 8 8 1 +3337 8 8 0 +3338 8 9 1 +3339 8 9 0 +3340 9 8 1 +3341 9 8 0 +3342 9 9 1 +3343 9 9 0 +3360 3 8 0 +3361 3 8 1 +3362 3 9 0 +3363 3 9 1 +3364 2 8 0 +3365 2 8 1 +3366 2 9 0 +3367 2 9 1 +3368 0 9 1 +3369 0 9 0 +3370 0 8 1 +3371 0 8 0 +3372 1 9 1 +3373 1 9 0 +3374 1 8 1 +3375 1 8 0 +3376 4 8 0 +3377 4 8 1 +3378 4 9 0 +3379 4 9 1 +3380 5 8 0 +3381 5 8 1 +3382 5 9 0 +3383 5 9 1 +3384 7 9 1 +3385 7 9 0 +3386 7 8 1 +3387 7 8 0 +3388 6 9 1 +3389 6 9 0 +3390 6 8 1 +3391 6 8 0 +3392 12 9 0 +3393 12 9 1 +3394 12 8 0 +3395 12 8 1 +3396 13 9 0 +3397 13 9 1 +3398 13 8 0 +3399 13 8 1 +3400 15 8 1 +3401 15 8 0 +3402 15 9 1 +3403 15 9 0 +3404 14 8 1 +3405 14 8 0 +3406 14 9 1 +3407 14 9 0 +3456 11 7 0 +3457 11 7 1 +3458 11 6 0 +3459 11 6 1 +3460 10 7 0 +3461 10 7 1 +3462 10 6 0 +3463 10 6 1 +3464 8 6 1 +3465 8 6 0 +3466 8 7 1 +3467 8 7 0 +3468 9 6 1 +3469 9 6 0 +3470 9 7 1 +3471 9 7 0 +3488 3 6 0 +3489 3 6 1 +3490 3 7 0 +3491 3 7 1 +3492 2 6 0 +3493 2 6 1 +3494 2 7 0 +3495 2 7 1 +3496 0 7 1 +3497 0 7 0 +3498 0 6 1 +3499 0 6 0 +3500 1 7 1 +3501 1 7 0 +3502 1 6 1 +3503 1 6 0 +3504 4 6 0 +3505 4 6 1 +3506 4 7 0 +3507 4 7 1 +3508 5 6 0 +3509 5 6 1 +3510 5 7 0 +3511 5 7 1 +3512 7 7 1 +3513 7 7 0 +3514 7 6 1 +3515 7 6 0 +3516 6 7 1 +3517 6 7 0 +3518 6 6 1 +3519 6 6 0 +3520 12 7 0 +3521 12 7 1 +3522 12 6 0 +3523 12 6 1 +3524 13 7 0 +3525 13 7 1 +3526 13 6 0 +3527 13 6 1 +3528 15 6 1 +3529 15 6 0 +3530 15 7 1 +3531 15 7 0 +3532 14 6 1 +3533 14 6 0 +3534 14 7 1 +3535 14 7 0 +3584 11 5 0 +3585 11 5 1 +3586 11 4 0 +3587 11 4 1 +3588 10 5 0 +3589 10 5 1 +3590 10 4 0 +3591 10 4 1 +3592 8 4 1 +3593 8 4 0 +3594 8 5 1 +3595 8 5 0 +3596 9 4 1 +3597 9 4 0 +3598 9 5 1 +3599 9 5 0 +3616 3 4 0 +3617 3 4 1 +3618 3 5 0 +3619 3 5 1 +3620 2 4 0 +3621 2 4 1 +3622 2 5 0 +3623 2 5 1 +3624 0 5 1 +3625 0 5 0 +3626 0 4 1 +3627 0 4 0 +3628 1 5 1 +3629 1 5 0 +3630 1 4 1 +3631 1 4 0 +3632 4 4 0 +3633 4 4 1 +3634 4 5 0 +3635 4 5 1 +3636 5 4 0 +3637 5 4 1 +3638 5 5 0 +3639 5 5 1 +3640 7 5 1 +3641 7 5 0 +3642 7 4 1 +3643 7 4 0 +3644 6 5 1 +3645 6 5 0 +3646 6 4 1 +3647 6 4 0 +3648 12 5 0 +3649 12 5 1 +3650 12 4 0 +3651 12 4 1 +3652 13 5 0 +3653 13 5 1 +3654 13 4 0 +3655 13 4 1 +3656 15 4 1 +3657 15 4 0 +3658 15 5 1 +3659 15 5 0 +3660 14 4 1 +3661 14 4 0 +3662 14 5 1 +3663 14 5 0 +3712 11 3 0 +3713 11 3 1 +3714 11 2 0 +3715 11 2 1 +3716 10 3 0 +3717 10 3 1 +3718 10 2 0 +3719 10 2 1 +3720 8 2 1 +3721 8 2 0 +3722 8 3 1 +3723 8 3 0 +3724 9 2 1 +3725 9 2 0 +3726 9 3 1 +3727 9 3 0 +3744 3 2 0 +3745 3 2 1 +3746 3 3 0 +3747 3 3 1 +3748 2 2 0 +3749 2 2 1 +3750 2 3 0 +3751 2 3 1 +3752 0 3 1 +3753 0 3 0 +3754 0 2 1 +3755 0 2 0 +3756 1 3 1 +3757 1 3 0 +3758 1 2 1 +3759 1 2 0 +3760 4 2 0 +3761 4 2 1 +3762 4 3 0 +3763 4 3 1 +3764 5 2 0 +3765 5 2 1 +3766 5 3 0 +3767 5 3 1 +3768 7 3 1 +3769 7 3 0 +3770 7 2 1 +3771 7 2 0 +3772 6 3 1 +3773 6 3 0 +3774 6 2 1 +3775 6 2 0 +3776 12 3 0 +3777 12 3 1 +3778 12 2 0 +3779 12 2 1 +3780 13 3 0 +3781 13 3 1 +3782 13 2 0 +3783 13 2 1 +3784 15 2 1 +3785 15 2 0 +3786 15 3 1 +3787 15 3 0 +3788 14 2 1 +3789 14 2 0 +3790 14 3 1 +3791 14 3 0 +3840 11 1 0 +3841 11 1 1 +3842 11 0 0 +3843 11 0 1 +3844 10 1 0 +3845 10 1 1 +3846 10 0 0 +3847 10 0 1 +3848 8 0 1 +3849 8 0 0 +3850 8 1 1 +3851 8 1 0 +3852 9 0 1 +3853 9 0 0 +3854 9 1 1 +3855 9 1 0 +3872 3 0 0 +3873 3 0 1 +3874 3 1 0 +3875 3 1 1 +3876 2 0 0 +3877 2 0 1 +3878 2 1 0 +3879 2 1 1 +3880 0 1 1 +3881 0 1 0 +3882 0 0 1 +3883 0 0 0 +3884 1 1 1 +3885 1 1 0 +3886 1 0 1 +3887 1 0 0 +3888 4 0 0 +3889 4 0 1 +3890 4 1 0 +3891 4 1 1 +3892 5 0 0 +3893 5 0 1 +3894 5 1 0 +3895 5 1 1 +3896 7 1 1 +3897 7 1 0 +3898 7 0 1 +3899 7 0 0 +3900 6 1 1 +3901 6 1 0 +3902 6 0 1 +3903 6 0 0 +3904 12 1 0 +3905 12 1 1 +3906 12 0 0 +3907 12 0 1 +3908 13 1 0 +3909 13 1 1 +3910 13 0 0 +3911 13 0 1 +3912 15 0 1 +3913 15 0 0 +3914 15 1 1 +3915 15 1 0 +3916 14 0 1 +3917 14 0 0 +3918 14 1 1 +3919 14 1 0 diff --git a/Detectors/PHOS/base/files/Mod2RCU1.data b/Detectors/PHOS/base/files/Mod2RCU1.data new file mode 100644 index 0000000000000..db125226496cf --- /dev/null +++ b/Detectors/PHOS/base/files/Mod2RCU1.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 1 0 2 + 1 1 1 2 + 2 1 2 2 + 3 1 3 2 + 4 1 4 2 + 5 1 5 2 + 6 1 6 2 + 7 1 7 2 + 8 1 8 2 + 9 1 9 2 + 10 1 10 2 + 11 1 11 2 + 12 1 12 2 + 13 1 13 2 + 14 1 14 2 + 15 1 15 2 + 16 1 16 2 + 17 1 17 2 + 18 1 18 2 + 19 1 19 2 + 20 1 20 2 + 21 1 21 2 + 22 1 22 2 + 23 1 23 2 + 24 1 24 2 + 25 1 25 2 + 26 1 26 2 + 27 1 27 2 + 28 1 28 2 + 29 1 29 2 + 30 1 30 2 + 31 1 31 2 + 32 1 32 2 + 33 1 33 2 + 34 1 34 2 + 35 1 35 2 + 36 1 36 2 + 37 1 37 2 + 38 1 38 2 + 39 1 39 2 + 40 1 40 2 + 41 1 41 2 + 42 1 42 2 + 43 1 43 2 + 44 1 44 2 + 45 1 45 2 + 46 1 46 2 + 47 1 47 2 + 48 1 48 2 + 49 1 49 2 + 50 1 50 2 + 51 1 51 2 + 52 1 52 2 + 53 1 53 2 + 54 1 54 2 + 55 1 55 2 + 56 1 56 2 + 57 1 57 2 + 58 1 58 2 + 59 1 59 2 + 60 1 60 2 + 61 1 61 2 + 62 1 62 2 + 63 1 63 2 + 64 1 64 2 + 65 1 65 2 + 66 1 66 2 + 67 1 67 2 + 68 1 68 2 + 69 1 69 2 + 70 1 70 2 + 71 1 71 2 + 72 1 72 2 + 73 1 73 2 + 74 1 74 2 + 75 1 75 2 + 76 1 76 2 + 77 1 77 2 + 78 1 78 2 + 79 1 79 2 + 80 1 80 2 + 81 1 81 2 + 82 1 82 2 + 83 1 83 2 + 84 1 84 2 + 85 1 85 2 + 86 1 86 2 + 87 1 87 2 + 88 1 88 2 + 89 1 89 2 + 90 1 90 2 + 91 1 91 2 + 92 1 92 2 + 93 1 93 2 + 94 1 94 2 + 95 1 95 2 + 96 1 96 2 + 97 1 97 2 + 98 1 98 2 + 99 1 99 2 + 100 1 100 2 + 101 1 101 2 + 102 1 102 2 + 103 1 103 2 + 104 1 104 2 + 105 1 105 2 + 106 1 106 2 + 107 1 107 2 + 108 1 108 2 + 109 1 109 2 + 110 1 110 2 + 111 1 111 2 + 112 1 112 2 + 113 1 113 2 + 114 1 114 2 + 115 1 115 2 + 116 1 116 2 + 117 1 117 2 + 118 1 118 2 + 119 1 119 2 + 120 1 120 2 + 121 1 121 2 + 122 1 122 2 + 123 1 123 2 + 124 1 124 2 + 125 1 125 2 + 126 1 126 2 + 127 1 127 2 +2048 1 2048 2 +2049 1 2049 2 +2050 1 2050 2 +2051 1 2051 2 +2052 1 2052 2 +2053 1 2053 2 +2054 1 2054 2 +2055 1 2055 2 +2056 1 2056 2 +2057 1 2057 2 +2058 1 2058 2 +2059 1 2059 2 +2060 1 2060 2 +2061 1 2061 2 +2062 1 2062 2 +2063 1 2063 2 +2064 1 2064 2 +2065 1 2065 2 +2066 1 2066 2 +2067 1 2067 2 +2068 1 2068 2 +2069 1 2069 2 +2070 1 2070 2 +2071 1 2071 2 +2072 1 2072 2 +2073 1 2073 2 +2074 1 2074 2 +2075 1 2075 2 +2076 1 2076 2 +2077 1 2077 2 +2078 1 2078 2 +2079 1 2079 2 +2080 1 2080 2 +2081 1 2081 2 +2082 1 2082 2 +2083 1 2083 2 +2084 1 2084 2 +2085 1 2085 2 +2086 1 2086 2 +2087 1 2087 2 +2088 1 2088 2 +2089 1 2089 2 +2090 1 2090 2 +2091 1 2091 2 +2092 1 2092 2 +2093 1 2093 2 +2094 1 2094 2 +2095 1 2095 2 +2096 1 2096 2 +2097 1 2097 2 +2098 1 2098 2 +2099 1 2099 2 +2100 1 2100 2 +2101 1 2101 2 +2102 1 2102 2 +2103 1 2103 2 +2104 1 2104 2 +2105 1 2105 2 +2106 1 2106 2 +2107 1 2107 2 +2108 1 2108 2 +2109 1 2109 2 +2110 1 2110 2 +2111 1 2111 2 +2112 1 2112 2 +2113 1 2113 2 +2114 1 2114 2 +2115 1 2115 2 +2116 1 2116 2 +2117 1 2117 2 +2118 1 2118 2 +2119 1 2119 2 +2120 1 2120 2 +2121 1 2121 2 +2122 1 2122 2 +2123 1 2123 2 +2124 1 2124 2 +2125 1 2125 2 +2126 1 2126 2 +2127 1 2127 2 +2128 1 2128 2 +2129 1 2129 2 +2130 1 2130 2 +2131 1 2131 2 +2132 1 2132 2 +2133 1 2133 2 +2134 1 2134 2 +2135 1 2135 2 +2136 1 2136 2 +2137 1 2137 2 +2138 1 2138 2 +2139 1 2139 2 +2140 1 2140 2 +2141 1 2141 2 +2142 1 2142 2 +2143 1 2143 2 +2144 1 2144 2 +2145 1 2145 2 +2146 1 2146 2 +2147 1 2147 2 +2148 1 2148 2 +2149 1 2149 2 +2150 1 2150 2 +2151 1 2151 2 +2152 1 2152 2 +2153 1 2153 2 +2154 1 2154 2 +2155 1 2155 2 +2156 1 2156 2 +2157 1 2157 2 +2158 1 2158 2 +2159 1 2159 2 +2160 1 2160 2 +2161 1 2161 2 +2162 1 2162 2 +2163 1 2163 2 +2164 1 2164 2 +2165 1 2165 2 +2166 1 2166 2 +2167 1 2167 2 +2168 1 2168 2 +2169 1 2169 2 +2170 1 2170 2 +2171 1 2171 2 +2172 1 2172 2 +2173 1 2173 2 +2174 1 2174 2 +2175 1 2175 2 + 128 27 29 0 + 129 27 29 1 + 130 27 28 0 + 131 27 28 1 + 132 26 29 0 + 133 26 29 1 + 134 26 28 0 + 135 26 28 1 + 136 24 28 1 + 137 24 28 0 + 138 24 29 1 + 139 24 29 0 + 140 25 28 1 + 141 25 28 0 + 142 25 29 1 + 143 25 29 0 + 160 19 28 0 + 161 19 28 1 + 162 19 29 0 + 163 19 29 1 + 164 18 28 0 + 165 18 28 1 + 166 18 29 0 + 167 18 29 1 + 168 16 29 1 + 169 16 29 0 + 170 16 28 1 + 171 16 28 0 + 172 17 29 1 + 173 17 29 0 + 174 17 28 1 + 175 17 28 0 + 176 20 28 0 + 177 20 28 1 + 178 20 29 0 + 179 20 29 1 + 180 21 28 0 + 181 21 28 1 + 182 21 29 0 + 183 21 29 1 + 184 23 29 1 + 185 23 29 0 + 186 23 28 1 + 187 23 28 0 + 188 22 29 1 + 189 22 29 0 + 190 22 28 1 + 191 22 28 0 + 192 28 29 0 + 193 28 29 1 + 194 28 28 0 + 195 28 28 1 + 196 29 29 0 + 197 29 29 1 + 198 29 28 0 + 199 29 28 1 + 200 31 28 1 + 201 31 28 0 + 202 31 29 1 + 203 31 29 0 + 204 30 28 1 + 205 30 28 0 + 206 30 29 1 + 207 30 29 0 + 256 27 31 0 + 257 27 31 1 + 258 27 30 0 + 259 27 30 1 + 260 26 31 0 + 261 26 31 1 + 262 26 30 0 + 263 26 30 1 + 264 24 30 1 + 265 24 30 0 + 266 24 31 1 + 267 24 31 0 + 268 25 30 1 + 269 25 30 0 + 270 25 31 1 + 271 25 31 0 + 288 19 30 0 + 289 19 30 1 + 290 19 31 0 + 291 19 31 1 + 292 18 30 0 + 293 18 30 1 + 294 18 31 0 + 295 18 31 1 + 296 16 31 1 + 297 16 31 0 + 298 16 30 1 + 299 16 30 0 + 300 17 31 1 + 301 17 31 0 + 302 17 30 1 + 303 17 30 0 + 304 20 30 0 + 305 20 30 1 + 306 20 31 0 + 307 20 31 1 + 308 21 30 0 + 309 21 30 1 + 310 21 31 0 + 311 21 31 1 + 312 23 31 1 + 313 23 31 0 + 314 23 30 1 + 315 23 30 0 + 316 22 31 1 + 317 22 31 0 + 318 22 30 1 + 319 22 30 0 + 320 28 31 0 + 321 28 31 1 + 322 28 30 0 + 323 28 30 1 + 324 29 31 0 + 325 29 31 1 + 326 29 30 0 + 327 29 30 1 + 328 31 30 1 + 329 31 30 0 + 330 31 31 1 + 331 31 31 0 + 332 30 30 1 + 333 30 30 0 + 334 30 31 1 + 335 30 31 0 + 384 27 33 0 + 385 27 33 1 + 386 27 32 0 + 387 27 32 1 + 388 26 33 0 + 389 26 33 1 + 390 26 32 0 + 391 26 32 1 + 392 24 32 1 + 393 24 32 0 + 394 24 33 1 + 395 24 33 0 + 396 25 32 1 + 397 25 32 0 + 398 25 33 1 + 399 25 33 0 + 416 19 32 0 + 417 19 32 1 + 418 19 33 0 + 419 19 33 1 + 420 18 32 0 + 421 18 32 1 + 422 18 33 0 + 423 18 33 1 + 424 16 33 1 + 425 16 33 0 + 426 16 32 1 + 427 16 32 0 + 428 17 33 1 + 429 17 33 0 + 430 17 32 1 + 431 17 32 0 + 432 20 32 0 + 433 20 32 1 + 434 20 33 0 + 435 20 33 1 + 436 21 32 0 + 437 21 32 1 + 438 21 33 0 + 439 21 33 1 + 440 23 33 1 + 441 23 33 0 + 442 23 32 1 + 443 23 32 0 + 444 22 33 1 + 445 22 33 0 + 446 22 32 1 + 447 22 32 0 + 448 28 33 0 + 449 28 33 1 + 450 28 32 0 + 451 28 32 1 + 452 29 33 0 + 453 29 33 1 + 454 29 32 0 + 455 29 32 1 + 456 31 32 1 + 457 31 32 0 + 458 31 33 1 + 459 31 33 0 + 460 30 32 1 + 461 30 32 0 + 462 30 33 1 + 463 30 33 0 + 512 27 35 0 + 513 27 35 1 + 514 27 34 0 + 515 27 34 1 + 516 26 35 0 + 517 26 35 1 + 518 26 34 0 + 519 26 34 1 + 520 24 34 1 + 521 24 34 0 + 522 24 35 1 + 523 24 35 0 + 524 25 34 1 + 525 25 34 0 + 526 25 35 1 + 527 25 35 0 + 544 19 34 0 + 545 19 34 1 + 546 19 35 0 + 547 19 35 1 + 548 18 34 0 + 549 18 34 1 + 550 18 35 0 + 551 18 35 1 + 552 16 35 1 + 553 16 35 0 + 554 16 34 1 + 555 16 34 0 + 556 17 35 1 + 557 17 35 0 + 558 17 34 1 + 559 17 34 0 + 560 20 34 0 + 561 20 34 1 + 562 20 35 0 + 563 20 35 1 + 564 21 34 0 + 565 21 34 1 + 566 21 35 0 + 567 21 35 1 + 568 23 35 1 + 569 23 35 0 + 570 23 34 1 + 571 23 34 0 + 572 22 35 1 + 573 22 35 0 + 574 22 34 1 + 575 22 34 0 + 576 28 35 0 + 577 28 35 1 + 578 28 34 0 + 579 28 34 1 + 580 29 35 0 + 581 29 35 1 + 582 29 34 0 + 583 29 34 1 + 584 31 34 1 + 585 31 34 0 + 586 31 35 1 + 587 31 35 0 + 588 30 34 1 + 589 30 34 0 + 590 30 35 1 + 591 30 35 0 + 640 27 37 0 + 641 27 37 1 + 642 27 36 0 + 643 27 36 1 + 644 26 37 0 + 645 26 37 1 + 646 26 36 0 + 647 26 36 1 + 648 24 36 1 + 649 24 36 0 + 650 24 37 1 + 651 24 37 0 + 652 25 36 1 + 653 25 36 0 + 654 25 37 1 + 655 25 37 0 + 672 19 36 0 + 673 19 36 1 + 674 19 37 0 + 675 19 37 1 + 676 18 36 0 + 677 18 36 1 + 678 18 37 0 + 679 18 37 1 + 680 16 37 1 + 681 16 37 0 + 682 16 36 1 + 683 16 36 0 + 684 17 37 1 + 685 17 37 0 + 686 17 36 1 + 687 17 36 0 + 688 20 36 0 + 689 20 36 1 + 690 20 37 0 + 691 20 37 1 + 692 21 36 0 + 693 21 36 1 + 694 21 37 0 + 695 21 37 1 + 696 23 37 1 + 697 23 37 0 + 698 23 36 1 + 699 23 36 0 + 700 22 37 1 + 701 22 37 0 + 702 22 36 1 + 703 22 36 0 + 704 28 37 0 + 705 28 37 1 + 706 28 36 0 + 707 28 36 1 + 708 29 37 0 + 709 29 37 1 + 710 29 36 0 + 711 29 36 1 + 712 31 36 1 + 713 31 36 0 + 714 31 37 1 + 715 31 37 0 + 716 30 36 1 + 717 30 36 0 + 718 30 37 1 + 719 30 37 0 + 768 27 39 0 + 769 27 39 1 + 770 27 38 0 + 771 27 38 1 + 772 26 39 0 + 773 26 39 1 + 774 26 38 0 + 775 26 38 1 + 776 24 38 1 + 777 24 38 0 + 778 24 39 1 + 779 24 39 0 + 780 25 38 1 + 781 25 38 0 + 782 25 39 1 + 783 25 39 0 + 800 19 38 0 + 801 19 38 1 + 802 19 39 0 + 803 19 39 1 + 804 18 38 0 + 805 18 38 1 + 806 18 39 0 + 807 18 39 1 + 808 16 39 1 + 809 16 39 0 + 810 16 38 1 + 811 16 38 0 + 812 17 39 1 + 813 17 39 0 + 814 17 38 1 + 815 17 38 0 + 816 20 38 0 + 817 20 38 1 + 818 20 39 0 + 819 20 39 1 + 820 21 38 0 + 821 21 38 1 + 822 21 39 0 + 823 21 39 1 + 824 23 39 1 + 825 23 39 0 + 826 23 38 1 + 827 23 38 0 + 828 22 39 1 + 829 22 39 0 + 830 22 38 1 + 831 22 38 0 + 832 28 39 0 + 833 28 39 1 + 834 28 38 0 + 835 28 38 1 + 836 29 39 0 + 837 29 39 1 + 838 29 38 0 + 839 29 38 1 + 840 31 38 1 + 841 31 38 0 + 842 31 39 1 + 843 31 39 0 + 844 30 38 1 + 845 30 38 0 + 846 30 39 1 + 847 30 39 0 + 896 27 41 0 + 897 27 41 1 + 898 27 40 0 + 899 27 40 1 + 900 26 41 0 + 901 26 41 1 + 902 26 40 0 + 903 26 40 1 + 904 24 40 1 + 905 24 40 0 + 906 24 41 1 + 907 24 41 0 + 908 25 40 1 + 909 25 40 0 + 910 25 41 1 + 911 25 41 0 + 928 19 40 0 + 929 19 40 1 + 930 19 41 0 + 931 19 41 1 + 932 18 40 0 + 933 18 40 1 + 934 18 41 0 + 935 18 41 1 + 936 16 41 1 + 937 16 41 0 + 938 16 40 1 + 939 16 40 0 + 940 17 41 1 + 941 17 41 0 + 942 17 40 1 + 943 17 40 0 + 944 20 40 0 + 945 20 40 1 + 946 20 41 0 + 947 20 41 1 + 948 21 40 0 + 949 21 40 1 + 950 21 41 0 + 951 21 41 1 + 952 23 41 1 + 953 23 41 0 + 954 23 40 1 + 955 23 40 0 + 956 22 41 1 + 957 22 41 0 + 958 22 40 1 + 959 22 40 0 + 960 28 41 0 + 961 28 41 1 + 962 28 40 0 + 963 28 40 1 + 964 29 41 0 + 965 29 41 1 + 966 29 40 0 + 967 29 40 1 + 968 31 40 1 + 969 31 40 0 + 970 31 41 1 + 971 31 41 0 + 972 30 40 1 + 973 30 40 0 + 974 30 41 1 + 975 30 41 0 +1024 27 43 0 +1025 27 43 1 +1026 27 42 0 +1027 27 42 1 +1028 26 43 0 +1029 26 43 1 +1030 26 42 0 +1031 26 42 1 +1032 24 42 1 +1033 24 42 0 +1034 24 43 1 +1035 24 43 0 +1036 25 42 1 +1037 25 42 0 +1038 25 43 1 +1039 25 43 0 +1056 19 42 0 +1057 19 42 1 +1058 19 43 0 +1059 19 43 1 +1060 18 42 0 +1061 18 42 1 +1062 18 43 0 +1063 18 43 1 +1064 16 43 1 +1065 16 43 0 +1066 16 42 1 +1067 16 42 0 +1068 17 43 1 +1069 17 43 0 +1070 17 42 1 +1071 17 42 0 +1072 20 42 0 +1073 20 42 1 +1074 20 43 0 +1075 20 43 1 +1076 21 42 0 +1077 21 42 1 +1078 21 43 0 +1079 21 43 1 +1080 23 43 1 +1081 23 43 0 +1082 23 42 1 +1083 23 42 0 +1084 22 43 1 +1085 22 43 0 +1086 22 42 1 +1087 22 42 0 +1088 28 43 0 +1089 28 43 1 +1090 28 42 0 +1091 28 42 1 +1092 29 43 0 +1093 29 43 1 +1094 29 42 0 +1095 29 42 1 +1096 31 42 1 +1097 31 42 0 +1098 31 43 1 +1099 31 43 0 +1100 30 42 1 +1101 30 42 0 +1102 30 43 1 +1103 30 43 0 +1152 27 45 0 +1153 27 45 1 +1154 27 44 0 +1155 27 44 1 +1156 26 45 0 +1157 26 45 1 +1158 26 44 0 +1159 26 44 1 +1160 24 44 1 +1161 24 44 0 +1162 24 45 1 +1163 24 45 0 +1164 25 44 1 +1165 25 44 0 +1166 25 45 1 +1167 25 45 0 +1184 19 44 0 +1185 19 44 1 +1186 19 45 0 +1187 19 45 1 +1188 18 44 0 +1189 18 44 1 +1190 18 45 0 +1191 18 45 1 +1192 16 45 1 +1193 16 45 0 +1194 16 44 1 +1195 16 44 0 +1196 17 45 1 +1197 17 45 0 +1198 17 44 1 +1199 17 44 0 +1200 20 44 0 +1201 20 44 1 +1202 20 45 0 +1203 20 45 1 +1204 21 44 0 +1205 21 44 1 +1206 21 45 0 +1207 21 45 1 +1208 23 45 1 +1209 23 45 0 +1210 23 44 1 +1211 23 44 0 +1212 22 45 1 +1213 22 45 0 +1214 22 44 1 +1215 22 44 0 +1216 28 45 0 +1217 28 45 1 +1218 28 44 0 +1219 28 44 1 +1220 29 45 0 +1221 29 45 1 +1222 29 44 0 +1223 29 44 1 +1224 31 44 1 +1225 31 44 0 +1226 31 45 1 +1227 31 45 0 +1228 30 44 1 +1229 30 44 0 +1230 30 45 1 +1231 30 45 0 +1280 27 47 0 +1281 27 47 1 +1282 27 46 0 +1283 27 46 1 +1284 26 47 0 +1285 26 47 1 +1286 26 46 0 +1287 26 46 1 +1288 24 46 1 +1289 24 46 0 +1290 24 47 1 +1291 24 47 0 +1292 25 46 1 +1293 25 46 0 +1294 25 47 1 +1295 25 47 0 +1312 19 46 0 +1313 19 46 1 +1314 19 47 0 +1315 19 47 1 +1316 18 46 0 +1317 18 46 1 +1318 18 47 0 +1319 18 47 1 +1320 16 47 1 +1321 16 47 0 +1322 16 46 1 +1323 16 46 0 +1324 17 47 1 +1325 17 47 0 +1326 17 46 1 +1327 17 46 0 +1328 20 46 0 +1329 20 46 1 +1330 20 47 0 +1331 20 47 1 +1332 21 46 0 +1333 21 46 1 +1334 21 47 0 +1335 21 47 1 +1336 23 47 1 +1337 23 47 0 +1338 23 46 1 +1339 23 46 0 +1340 22 47 1 +1341 22 47 0 +1342 22 46 1 +1343 22 46 0 +1344 28 47 0 +1345 28 47 1 +1346 28 46 0 +1347 28 46 1 +1348 29 47 0 +1349 29 47 1 +1350 29 46 0 +1351 29 46 1 +1352 31 46 1 +1353 31 46 0 +1354 31 47 1 +1355 31 47 0 +1356 30 46 1 +1357 30 46 0 +1358 30 47 1 +1359 30 47 0 +1408 27 49 0 +1409 27 49 1 +1410 27 48 0 +1411 27 48 1 +1412 26 49 0 +1413 26 49 1 +1414 26 48 0 +1415 26 48 1 +1416 24 48 1 +1417 24 48 0 +1418 24 49 1 +1419 24 49 0 +1420 25 48 1 +1421 25 48 0 +1422 25 49 1 +1423 25 49 0 +1440 19 48 0 +1441 19 48 1 +1442 19 49 0 +1443 19 49 1 +1444 18 48 0 +1445 18 48 1 +1446 18 49 0 +1447 18 49 1 +1448 16 49 1 +1449 16 49 0 +1450 16 48 1 +1451 16 48 0 +1452 17 49 1 +1453 17 49 0 +1454 17 48 1 +1455 17 48 0 +1456 20 48 0 +1457 20 48 1 +1458 20 49 0 +1459 20 49 1 +1460 21 48 0 +1461 21 48 1 +1462 21 49 0 +1463 21 49 1 +1464 23 49 1 +1465 23 49 0 +1466 23 48 1 +1467 23 48 0 +1468 22 49 1 +1469 22 49 0 +1470 22 48 1 +1471 22 48 0 +1472 28 49 0 +1473 28 49 1 +1474 28 48 0 +1475 28 48 1 +1476 29 49 0 +1477 29 49 1 +1478 29 48 0 +1479 29 48 1 +1480 31 48 1 +1481 31 48 0 +1482 31 49 1 +1483 31 49 0 +1484 30 48 1 +1485 30 48 0 +1486 30 49 1 +1487 30 49 0 +1536 27 51 0 +1537 27 51 1 +1538 27 50 0 +1539 27 50 1 +1540 26 51 0 +1541 26 51 1 +1542 26 50 0 +1543 26 50 1 +1544 24 50 1 +1545 24 50 0 +1546 24 51 1 +1547 24 51 0 +1548 25 50 1 +1549 25 50 0 +1550 25 51 1 +1551 25 51 0 +1568 19 50 0 +1569 19 50 1 +1570 19 51 0 +1571 19 51 1 +1572 18 50 0 +1573 18 50 1 +1574 18 51 0 +1575 18 51 1 +1576 16 51 1 +1577 16 51 0 +1578 16 50 1 +1579 16 50 0 +1580 17 51 1 +1581 17 51 0 +1582 17 50 1 +1583 17 50 0 +1584 20 50 0 +1585 20 50 1 +1586 20 51 0 +1587 20 51 1 +1588 21 50 0 +1589 21 50 1 +1590 21 51 0 +1591 21 51 1 +1592 23 51 1 +1593 23 51 0 +1594 23 50 1 +1595 23 50 0 +1596 22 51 1 +1597 22 51 0 +1598 22 50 1 +1599 22 50 0 +1600 28 51 0 +1601 28 51 1 +1602 28 50 0 +1603 28 50 1 +1604 29 51 0 +1605 29 51 1 +1606 29 50 0 +1607 29 50 1 +1608 31 50 1 +1609 31 50 0 +1610 31 51 1 +1611 31 51 0 +1612 30 50 1 +1613 30 50 0 +1614 30 51 1 +1615 30 51 0 +1664 27 53 0 +1665 27 53 1 +1666 27 52 0 +1667 27 52 1 +1668 26 53 0 +1669 26 53 1 +1670 26 52 0 +1671 26 52 1 +1672 24 52 1 +1673 24 52 0 +1674 24 53 1 +1675 24 53 0 +1676 25 52 1 +1677 25 52 0 +1678 25 53 1 +1679 25 53 0 +1696 19 52 0 +1697 19 52 1 +1698 19 53 0 +1699 19 53 1 +1700 18 52 0 +1701 18 52 1 +1702 18 53 0 +1703 18 53 1 +1704 16 53 1 +1705 16 53 0 +1706 16 52 1 +1707 16 52 0 +1708 17 53 1 +1709 17 53 0 +1710 17 52 1 +1711 17 52 0 +1712 20 52 0 +1713 20 52 1 +1714 20 53 0 +1715 20 53 1 +1716 21 52 0 +1717 21 52 1 +1718 21 53 0 +1719 21 53 1 +1720 23 53 1 +1721 23 53 0 +1722 23 52 1 +1723 23 52 0 +1724 22 53 1 +1725 22 53 0 +1726 22 52 1 +1727 22 52 0 +1728 28 53 0 +1729 28 53 1 +1730 28 52 0 +1731 28 52 1 +1732 29 53 0 +1733 29 53 1 +1734 29 52 0 +1735 29 52 1 +1736 31 52 1 +1737 31 52 0 +1738 31 53 1 +1739 31 53 0 +1740 30 52 1 +1741 30 52 0 +1742 30 53 1 +1743 30 53 0 +1792 27 55 0 +1793 27 55 1 +1794 27 54 0 +1795 27 54 1 +1796 26 55 0 +1797 26 55 1 +1798 26 54 0 +1799 26 54 1 +1800 24 54 1 +1801 24 54 0 +1802 24 55 1 +1803 24 55 0 +1804 25 54 1 +1805 25 54 0 +1806 25 55 1 +1807 25 55 0 +1824 19 54 0 +1825 19 54 1 +1826 19 55 0 +1827 19 55 1 +1828 18 54 0 +1829 18 54 1 +1830 18 55 0 +1831 18 55 1 +1832 16 55 1 +1833 16 55 0 +1834 16 54 1 +1835 16 54 0 +1836 17 55 1 +1837 17 55 0 +1838 17 54 1 +1839 17 54 0 +1840 20 54 0 +1841 20 54 1 +1842 20 55 0 +1843 20 55 1 +1844 21 54 0 +1845 21 54 1 +1846 21 55 0 +1847 21 55 1 +1848 23 55 1 +1849 23 55 0 +1850 23 54 1 +1851 23 54 0 +1852 22 55 1 +1853 22 55 0 +1854 22 54 1 +1855 22 54 0 +1856 28 55 0 +1857 28 55 1 +1858 28 54 0 +1859 28 54 1 +1860 29 55 0 +1861 29 55 1 +1862 29 54 0 +1863 29 54 1 +1864 31 54 1 +1865 31 54 0 +1866 31 55 1 +1867 31 55 0 +1868 30 54 1 +1869 30 54 0 +1870 30 55 1 +1871 30 55 0 +2176 27 27 0 +2177 27 27 1 +2178 27 26 0 +2179 27 26 1 +2180 26 27 0 +2181 26 27 1 +2182 26 26 0 +2183 26 26 1 +2184 24 26 1 +2185 24 26 0 +2186 24 27 1 +2187 24 27 0 +2188 25 26 1 +2189 25 26 0 +2190 25 27 1 +2191 25 27 0 +2208 19 26 0 +2209 19 26 1 +2210 19 27 0 +2211 19 27 1 +2212 18 26 0 +2213 18 26 1 +2214 18 27 0 +2215 18 27 1 +2216 16 27 1 +2217 16 27 0 +2218 16 26 1 +2219 16 26 0 +2220 17 27 1 +2221 17 27 0 +2222 17 26 1 +2223 17 26 0 +2224 20 26 0 +2225 20 26 1 +2226 20 27 0 +2227 20 27 1 +2228 21 26 0 +2229 21 26 1 +2230 21 27 0 +2231 21 27 1 +2232 23 27 1 +2233 23 27 0 +2234 23 26 1 +2235 23 26 0 +2236 22 27 1 +2237 22 27 0 +2238 22 26 1 +2239 22 26 0 +2240 28 27 0 +2241 28 27 1 +2242 28 26 0 +2243 28 26 1 +2244 29 27 0 +2245 29 27 1 +2246 29 26 0 +2247 29 26 1 +2248 31 26 1 +2249 31 26 0 +2250 31 27 1 +2251 31 27 0 +2252 30 26 1 +2253 30 26 0 +2254 30 27 1 +2255 30 27 0 +2304 27 25 0 +2305 27 25 1 +2306 27 24 0 +2307 27 24 1 +2308 26 25 0 +2309 26 25 1 +2310 26 24 0 +2311 26 24 1 +2312 24 24 1 +2313 24 24 0 +2314 24 25 1 +2315 24 25 0 +2316 25 24 1 +2317 25 24 0 +2318 25 25 1 +2319 25 25 0 +2336 19 24 0 +2337 19 24 1 +2338 19 25 0 +2339 19 25 1 +2340 18 24 0 +2341 18 24 1 +2342 18 25 0 +2343 18 25 1 +2344 16 25 1 +2345 16 25 0 +2346 16 24 1 +2347 16 24 0 +2348 17 25 1 +2349 17 25 0 +2350 17 24 1 +2351 17 24 0 +2352 20 24 0 +2353 20 24 1 +2354 20 25 0 +2355 20 25 1 +2356 21 24 0 +2357 21 24 1 +2358 21 25 0 +2359 21 25 1 +2360 23 25 1 +2361 23 25 0 +2362 23 24 1 +2363 23 24 0 +2364 22 25 1 +2365 22 25 0 +2366 22 24 1 +2367 22 24 0 +2368 28 25 0 +2369 28 25 1 +2370 28 24 0 +2371 28 24 1 +2372 29 25 0 +2373 29 25 1 +2374 29 24 0 +2375 29 24 1 +2376 31 24 1 +2377 31 24 0 +2378 31 25 1 +2379 31 25 0 +2380 30 24 1 +2381 30 24 0 +2382 30 25 1 +2383 30 25 0 +2432 27 23 0 +2433 27 23 1 +2434 27 22 0 +2435 27 22 1 +2436 26 23 0 +2437 26 23 1 +2438 26 22 0 +2439 26 22 1 +2440 24 22 1 +2441 24 22 0 +2442 24 23 1 +2443 24 23 0 +2444 25 22 1 +2445 25 22 0 +2446 25 23 1 +2447 25 23 0 +2464 19 22 0 +2465 19 22 1 +2466 19 23 0 +2467 19 23 1 +2468 18 22 0 +2469 18 22 1 +2470 18 23 0 +2471 18 23 1 +2472 16 23 1 +2473 16 23 0 +2474 16 22 1 +2475 16 22 0 +2476 17 23 1 +2477 17 23 0 +2478 17 22 1 +2479 17 22 0 +2480 20 22 0 +2481 20 22 1 +2482 20 23 0 +2483 20 23 1 +2484 21 22 0 +2485 21 22 1 +2486 21 23 0 +2487 21 23 1 +2488 23 23 1 +2489 23 23 0 +2490 23 22 1 +2491 23 22 0 +2492 22 23 1 +2493 22 23 0 +2494 22 22 1 +2495 22 22 0 +2496 28 23 0 +2497 28 23 1 +2498 28 22 0 +2499 28 22 1 +2500 29 23 0 +2501 29 23 1 +2502 29 22 0 +2503 29 22 1 +2504 31 22 1 +2505 31 22 0 +2506 31 23 1 +2507 31 23 0 +2508 30 22 1 +2509 30 22 0 +2510 30 23 1 +2511 30 23 0 +2560 27 21 0 +2561 27 21 1 +2562 27 20 0 +2563 27 20 1 +2564 26 21 0 +2565 26 21 1 +2566 26 20 0 +2567 26 20 1 +2568 24 20 1 +2569 24 20 0 +2570 24 21 1 +2571 24 21 0 +2572 25 20 1 +2573 25 20 0 +2574 25 21 1 +2575 25 21 0 +2592 19 20 0 +2593 19 20 1 +2594 19 21 0 +2595 19 21 1 +2596 18 20 0 +2597 18 20 1 +2598 18 21 0 +2599 18 21 1 +2600 16 21 1 +2601 16 21 0 +2602 16 20 1 +2603 16 20 0 +2604 17 21 1 +2605 17 21 0 +2606 17 20 1 +2607 17 20 0 +2608 20 20 0 +2609 20 20 1 +2610 20 21 0 +2611 20 21 1 +2612 21 20 0 +2613 21 20 1 +2614 21 21 0 +2615 21 21 1 +2616 23 21 1 +2617 23 21 0 +2618 23 20 1 +2619 23 20 0 +2620 22 21 1 +2621 22 21 0 +2622 22 20 1 +2623 22 20 0 +2624 28 21 0 +2625 28 21 1 +2626 28 20 0 +2627 28 20 1 +2628 29 21 0 +2629 29 21 1 +2630 29 20 0 +2631 29 20 1 +2632 31 20 1 +2633 31 20 0 +2634 31 21 1 +2635 31 21 0 +2636 30 20 1 +2637 30 20 0 +2638 30 21 1 +2639 30 21 0 +2688 27 19 0 +2689 27 19 1 +2690 27 18 0 +2691 27 18 1 +2692 26 19 0 +2693 26 19 1 +2694 26 18 0 +2695 26 18 1 +2696 24 18 1 +2697 24 18 0 +2698 24 19 1 +2699 24 19 0 +2700 25 18 1 +2701 25 18 0 +2702 25 19 1 +2703 25 19 0 +2720 19 18 0 +2721 19 18 1 +2722 19 19 0 +2723 19 19 1 +2724 18 18 0 +2725 18 18 1 +2726 18 19 0 +2727 18 19 1 +2728 16 19 1 +2729 16 19 0 +2730 16 18 1 +2731 16 18 0 +2732 17 19 1 +2733 17 19 0 +2734 17 18 1 +2735 17 18 0 +2736 20 18 0 +2737 20 18 1 +2738 20 19 0 +2739 20 19 1 +2740 21 18 0 +2741 21 18 1 +2742 21 19 0 +2743 21 19 1 +2744 23 19 1 +2745 23 19 0 +2746 23 18 1 +2747 23 18 0 +2748 22 19 1 +2749 22 19 0 +2750 22 18 1 +2751 22 18 0 +2752 28 19 0 +2753 28 19 1 +2754 28 18 0 +2755 28 18 1 +2756 29 19 0 +2757 29 19 1 +2758 29 18 0 +2759 29 18 1 +2760 31 18 1 +2761 31 18 0 +2762 31 19 1 +2763 31 19 0 +2764 30 18 1 +2765 30 18 0 +2766 30 19 1 +2767 30 19 0 +2816 27 17 0 +2817 27 17 1 +2818 27 16 0 +2819 27 16 1 +2820 26 17 0 +2821 26 17 1 +2822 26 16 0 +2823 26 16 1 +2824 24 16 1 +2825 24 16 0 +2826 24 17 1 +2827 24 17 0 +2828 25 16 1 +2829 25 16 0 +2830 25 17 1 +2831 25 17 0 +2848 19 16 0 +2849 19 16 1 +2850 19 17 0 +2851 19 17 1 +2852 18 16 0 +2853 18 16 1 +2854 18 17 0 +2855 18 17 1 +2856 16 17 1 +2857 16 17 0 +2858 16 16 1 +2859 16 16 0 +2860 17 17 1 +2861 17 17 0 +2862 17 16 1 +2863 17 16 0 +2864 20 16 0 +2865 20 16 1 +2866 20 17 0 +2867 20 17 1 +2868 21 16 0 +2869 21 16 1 +2870 21 17 0 +2871 21 17 1 +2872 23 17 1 +2873 23 17 0 +2874 23 16 1 +2875 23 16 0 +2876 22 17 1 +2877 22 17 0 +2878 22 16 1 +2879 22 16 0 +2880 28 17 0 +2881 28 17 1 +2882 28 16 0 +2883 28 16 1 +2884 29 17 0 +2885 29 17 1 +2886 29 16 0 +2887 29 16 1 +2888 31 16 1 +2889 31 16 0 +2890 31 17 1 +2891 31 17 0 +2892 30 16 1 +2893 30 16 0 +2894 30 17 1 +2895 30 17 0 +2944 27 15 0 +2945 27 15 1 +2946 27 14 0 +2947 27 14 1 +2948 26 15 0 +2949 26 15 1 +2950 26 14 0 +2951 26 14 1 +2952 24 14 1 +2953 24 14 0 +2954 24 15 1 +2955 24 15 0 +2956 25 14 1 +2957 25 14 0 +2958 25 15 1 +2959 25 15 0 +2976 19 14 0 +2977 19 14 1 +2978 19 15 0 +2979 19 15 1 +2980 18 14 0 +2981 18 14 1 +2982 18 15 0 +2983 18 15 1 +2984 16 15 1 +2985 16 15 0 +2986 16 14 1 +2987 16 14 0 +2988 17 15 1 +2989 17 15 0 +2990 17 14 1 +2991 17 14 0 +2992 20 14 0 +2993 20 14 1 +2994 20 15 0 +2995 20 15 1 +2996 21 14 0 +2997 21 14 1 +2998 21 15 0 +2999 21 15 1 +3000 23 15 1 +3001 23 15 0 +3002 23 14 1 +3003 23 14 0 +3004 22 15 1 +3005 22 15 0 +3006 22 14 1 +3007 22 14 0 +3008 28 15 0 +3009 28 15 1 +3010 28 14 0 +3011 28 14 1 +3012 29 15 0 +3013 29 15 1 +3014 29 14 0 +3015 29 14 1 +3016 31 14 1 +3017 31 14 0 +3018 31 15 1 +3019 31 15 0 +3020 30 14 1 +3021 30 14 0 +3022 30 15 1 +3023 30 15 0 +3072 27 13 0 +3073 27 13 1 +3074 27 12 0 +3075 27 12 1 +3076 26 13 0 +3077 26 13 1 +3078 26 12 0 +3079 26 12 1 +3080 24 12 1 +3081 24 12 0 +3082 24 13 1 +3083 24 13 0 +3084 25 12 1 +3085 25 12 0 +3086 25 13 1 +3087 25 13 0 +3104 19 12 0 +3105 19 12 1 +3106 19 13 0 +3107 19 13 1 +3108 18 12 0 +3109 18 12 1 +3110 18 13 0 +3111 18 13 1 +3112 16 13 1 +3113 16 13 0 +3114 16 12 1 +3115 16 12 0 +3116 17 13 1 +3117 17 13 0 +3118 17 12 1 +3119 17 12 0 +3120 20 12 0 +3121 20 12 1 +3122 20 13 0 +3123 20 13 1 +3124 21 12 0 +3125 21 12 1 +3126 21 13 0 +3127 21 13 1 +3128 23 13 1 +3129 23 13 0 +3130 23 12 1 +3131 23 12 0 +3132 22 13 1 +3133 22 13 0 +3134 22 12 1 +3135 22 12 0 +3136 28 13 0 +3137 28 13 1 +3138 28 12 0 +3139 28 12 1 +3140 29 13 0 +3141 29 13 1 +3142 29 12 0 +3143 29 12 1 +3144 31 12 1 +3145 31 12 0 +3146 31 13 1 +3147 31 13 0 +3148 30 12 1 +3149 30 12 0 +3150 30 13 1 +3151 30 13 0 +3200 27 11 0 +3201 27 11 1 +3202 27 10 0 +3203 27 10 1 +3204 26 11 0 +3205 26 11 1 +3206 26 10 0 +3207 26 10 1 +3208 24 10 1 +3209 24 10 0 +3210 24 11 1 +3211 24 11 0 +3212 25 10 1 +3213 25 10 0 +3214 25 11 1 +3215 25 11 0 +3232 19 10 0 +3233 19 10 1 +3234 19 11 0 +3235 19 11 1 +3236 18 10 0 +3237 18 10 1 +3238 18 11 0 +3239 18 11 1 +3240 16 11 1 +3241 16 11 0 +3242 16 10 1 +3243 16 10 0 +3244 17 11 1 +3245 17 11 0 +3246 17 10 1 +3247 17 10 0 +3248 20 10 0 +3249 20 10 1 +3250 20 11 0 +3251 20 11 1 +3252 21 10 0 +3253 21 10 1 +3254 21 11 0 +3255 21 11 1 +3256 23 11 1 +3257 23 11 0 +3258 23 10 1 +3259 23 10 0 +3260 22 11 1 +3261 22 11 0 +3262 22 10 1 +3263 22 10 0 +3264 28 11 0 +3265 28 11 1 +3266 28 10 0 +3267 28 10 1 +3268 29 11 0 +3269 29 11 1 +3270 29 10 0 +3271 29 10 1 +3272 31 10 1 +3273 31 10 0 +3274 31 11 1 +3275 31 11 0 +3276 30 10 1 +3277 30 10 0 +3278 30 11 1 +3279 30 11 0 +3328 27 9 0 +3329 27 9 1 +3330 27 8 0 +3331 27 8 1 +3332 26 9 0 +3333 26 9 1 +3334 26 8 0 +3335 26 8 1 +3336 24 8 1 +3337 24 8 0 +3338 24 9 1 +3339 24 9 0 +3340 25 8 1 +3341 25 8 0 +3342 25 9 1 +3343 25 9 0 +3360 19 8 0 +3361 19 8 1 +3362 19 9 0 +3363 19 9 1 +3364 18 8 0 +3365 18 8 1 +3366 18 9 0 +3367 18 9 1 +3368 16 9 1 +3369 16 9 0 +3370 16 8 1 +3371 16 8 0 +3372 17 9 1 +3373 17 9 0 +3374 17 8 1 +3375 17 8 0 +3376 20 8 0 +3377 20 8 1 +3378 20 9 0 +3379 20 9 1 +3380 21 8 0 +3381 21 8 1 +3382 21 9 0 +3383 21 9 1 +3384 23 9 1 +3385 23 9 0 +3386 23 8 1 +3387 23 8 0 +3388 22 9 1 +3389 22 9 0 +3390 22 8 1 +3391 22 8 0 +3392 28 9 0 +3393 28 9 1 +3394 28 8 0 +3395 28 8 1 +3396 29 9 0 +3397 29 9 1 +3398 29 8 0 +3399 29 8 1 +3400 31 8 1 +3401 31 8 0 +3402 31 9 1 +3403 31 9 0 +3404 30 8 1 +3405 30 8 0 +3406 30 9 1 +3407 30 9 0 +3456 27 7 0 +3457 27 7 1 +3458 27 6 0 +3459 27 6 1 +3460 26 7 0 +3461 26 7 1 +3462 26 6 0 +3463 26 6 1 +3464 24 6 1 +3465 24 6 0 +3466 24 7 1 +3467 24 7 0 +3468 25 6 1 +3469 25 6 0 +3470 25 7 1 +3471 25 7 0 +3488 19 6 0 +3489 19 6 1 +3490 19 7 0 +3491 19 7 1 +3492 18 6 0 +3493 18 6 1 +3494 18 7 0 +3495 18 7 1 +3496 16 7 1 +3497 16 7 0 +3498 16 6 1 +3499 16 6 0 +3500 17 7 1 +3501 17 7 0 +3502 17 6 1 +3503 17 6 0 +3504 20 6 0 +3505 20 6 1 +3506 20 7 0 +3507 20 7 1 +3508 21 6 0 +3509 21 6 1 +3510 21 7 0 +3511 21 7 1 +3512 23 7 1 +3513 23 7 0 +3514 23 6 1 +3515 23 6 0 +3516 22 7 1 +3517 22 7 0 +3518 22 6 1 +3519 22 6 0 +3520 28 7 0 +3521 28 7 1 +3522 28 6 0 +3523 28 6 1 +3524 29 7 0 +3525 29 7 1 +3526 29 6 0 +3527 29 6 1 +3528 31 6 1 +3529 31 6 0 +3530 31 7 1 +3531 31 7 0 +3532 30 6 1 +3533 30 6 0 +3534 30 7 1 +3535 30 7 0 +3584 27 5 0 +3585 27 5 1 +3586 27 4 0 +3587 27 4 1 +3588 26 5 0 +3589 26 5 1 +3590 26 4 0 +3591 26 4 1 +3592 24 4 1 +3593 24 4 0 +3594 24 5 1 +3595 24 5 0 +3596 25 4 1 +3597 25 4 0 +3598 25 5 1 +3599 25 5 0 +3616 19 4 0 +3617 19 4 1 +3618 19 5 0 +3619 19 5 1 +3620 18 4 0 +3621 18 4 1 +3622 18 5 0 +3623 18 5 1 +3624 16 5 1 +3625 16 5 0 +3626 16 4 1 +3627 16 4 0 +3628 17 5 1 +3629 17 5 0 +3630 17 4 1 +3631 17 4 0 +3632 20 4 0 +3633 20 4 1 +3634 20 5 0 +3635 20 5 1 +3636 21 4 0 +3637 21 4 1 +3638 21 5 0 +3639 21 5 1 +3640 23 5 1 +3641 23 5 0 +3642 23 4 1 +3643 23 4 0 +3644 22 5 1 +3645 22 5 0 +3646 22 4 1 +3647 22 4 0 +3648 28 5 0 +3649 28 5 1 +3650 28 4 0 +3651 28 4 1 +3652 29 5 0 +3653 29 5 1 +3654 29 4 0 +3655 29 4 1 +3656 31 4 1 +3657 31 4 0 +3658 31 5 1 +3659 31 5 0 +3660 30 4 1 +3661 30 4 0 +3662 30 5 1 +3663 30 5 0 +3712 27 3 0 +3713 27 3 1 +3714 27 2 0 +3715 27 2 1 +3716 26 3 0 +3717 26 3 1 +3718 26 2 0 +3719 26 2 1 +3720 24 2 1 +3721 24 2 0 +3722 24 3 1 +3723 24 3 0 +3724 25 2 1 +3725 25 2 0 +3726 25 3 1 +3727 25 3 0 +3744 19 2 0 +3745 19 2 1 +3746 19 3 0 +3747 19 3 1 +3748 18 2 0 +3749 18 2 1 +3750 18 3 0 +3751 18 3 1 +3752 16 3 1 +3753 16 3 0 +3754 16 2 1 +3755 16 2 0 +3756 17 3 1 +3757 17 3 0 +3758 17 2 1 +3759 17 2 0 +3760 20 2 0 +3761 20 2 1 +3762 20 3 0 +3763 20 3 1 +3764 21 2 0 +3765 21 2 1 +3766 21 3 0 +3767 21 3 1 +3768 23 3 1 +3769 23 3 0 +3770 23 2 1 +3771 23 2 0 +3772 22 3 1 +3773 22 3 0 +3774 22 2 1 +3775 22 2 0 +3776 28 3 0 +3777 28 3 1 +3778 28 2 0 +3779 28 2 1 +3780 29 3 0 +3781 29 3 1 +3782 29 2 0 +3783 29 2 1 +3784 31 2 1 +3785 31 2 0 +3786 31 3 1 +3787 31 3 0 +3788 30 2 1 +3789 30 2 0 +3790 30 3 1 +3791 30 3 0 +3840 27 1 0 +3841 27 1 1 +3842 27 0 0 +3843 27 0 1 +3844 26 1 0 +3845 26 1 1 +3846 26 0 0 +3847 26 0 1 +3848 24 0 1 +3849 24 0 0 +3850 24 1 1 +3851 24 1 0 +3852 25 0 1 +3853 25 0 0 +3854 25 1 1 +3855 25 1 0 +3872 19 0 0 +3873 19 0 1 +3874 19 1 0 +3875 19 1 1 +3876 18 0 0 +3877 18 0 1 +3878 18 1 0 +3879 18 1 1 +3880 16 1 1 +3881 16 1 0 +3882 16 0 1 +3883 16 0 0 +3884 17 1 1 +3885 17 1 0 +3886 17 0 1 +3887 17 0 0 +3888 20 0 0 +3889 20 0 1 +3890 20 1 0 +3891 20 1 1 +3892 21 0 0 +3893 21 0 1 +3894 21 1 0 +3895 21 1 1 +3896 23 1 1 +3897 23 1 0 +3898 23 0 1 +3899 23 0 0 +3900 22 1 1 +3901 22 1 0 +3902 22 0 1 +3903 22 0 0 +3904 28 1 0 +3905 28 1 1 +3906 28 0 0 +3907 28 0 1 +3908 29 1 0 +3909 29 1 1 +3910 29 0 0 +3911 29 0 1 +3912 31 0 1 +3913 31 0 0 +3914 31 1 1 +3915 31 1 0 +3916 30 0 1 +3917 30 0 0 +3918 30 1 1 +3919 30 1 0 diff --git a/Detectors/PHOS/base/files/Mod2RCU2.data b/Detectors/PHOS/base/files/Mod2RCU2.data new file mode 100644 index 0000000000000..21de94d7ace53 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod2RCU2.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 2 0 2 + 1 2 1 2 + 2 2 2 2 + 3 2 3 2 + 4 2 4 2 + 5 2 5 2 + 6 2 6 2 + 7 2 7 2 + 8 2 8 2 + 9 2 9 2 + 10 2 10 2 + 11 2 11 2 + 12 2 12 2 + 13 2 13 2 + 14 2 14 2 + 15 2 15 2 + 16 2 16 2 + 17 2 17 2 + 18 2 18 2 + 19 2 19 2 + 20 2 20 2 + 21 2 21 2 + 22 2 22 2 + 23 2 23 2 + 24 2 24 2 + 25 2 25 2 + 26 2 26 2 + 27 2 27 2 + 28 2 28 2 + 29 2 29 2 + 30 2 30 2 + 31 2 31 2 + 32 2 32 2 + 33 2 33 2 + 34 2 34 2 + 35 2 35 2 + 36 2 36 2 + 37 2 37 2 + 38 2 38 2 + 39 2 39 2 + 40 2 40 2 + 41 2 41 2 + 42 2 42 2 + 43 2 43 2 + 44 2 44 2 + 45 2 45 2 + 46 2 46 2 + 47 2 47 2 + 48 2 48 2 + 49 2 49 2 + 50 2 50 2 + 51 2 51 2 + 52 2 52 2 + 53 2 53 2 + 54 2 54 2 + 55 2 55 2 + 56 2 56 2 + 57 2 57 2 + 58 2 58 2 + 59 2 59 2 + 60 2 60 2 + 61 2 61 2 + 62 2 62 2 + 63 2 63 2 + 64 2 64 2 + 65 2 65 2 + 66 2 66 2 + 67 2 67 2 + 68 2 68 2 + 69 2 69 2 + 70 2 70 2 + 71 2 71 2 + 72 2 72 2 + 73 2 73 2 + 74 2 74 2 + 75 2 75 2 + 76 2 76 2 + 77 2 77 2 + 78 2 78 2 + 79 2 79 2 + 80 2 80 2 + 81 2 81 2 + 82 2 82 2 + 83 2 83 2 + 84 2 84 2 + 85 2 85 2 + 86 2 86 2 + 87 2 87 2 + 88 2 88 2 + 89 2 89 2 + 90 2 90 2 + 91 2 91 2 + 92 2 92 2 + 93 2 93 2 + 94 2 94 2 + 95 2 95 2 + 96 2 96 2 + 97 2 97 2 + 98 2 98 2 + 99 2 99 2 + 100 2 100 2 + 101 2 101 2 + 102 2 102 2 + 103 2 103 2 + 104 2 104 2 + 105 2 105 2 + 106 2 106 2 + 107 2 107 2 + 108 2 108 2 + 109 2 109 2 + 110 2 110 2 + 111 2 111 2 + 112 2 112 2 + 113 2 113 2 + 114 2 114 2 + 115 2 115 2 + 116 2 116 2 + 117 2 117 2 + 118 2 118 2 + 119 2 119 2 + 120 2 120 2 + 121 2 121 2 + 122 2 122 2 + 123 2 123 2 + 124 2 124 2 + 125 2 125 2 + 126 2 126 2 + 127 2 127 2 +2048 2 2048 2 +2049 2 2049 2 +2050 2 2050 2 +2051 2 2051 2 +2052 2 2052 2 +2053 2 2053 2 +2054 2 2054 2 +2055 2 2055 2 +2056 2 2056 2 +2057 2 2057 2 +2058 2 2058 2 +2059 2 2059 2 +2060 2 2060 2 +2061 2 2061 2 +2062 2 2062 2 +2063 2 2063 2 +2064 2 2064 2 +2065 2 2065 2 +2066 2 2066 2 +2067 2 2067 2 +2068 2 2068 2 +2069 2 2069 2 +2070 2 2070 2 +2071 2 2071 2 +2072 2 2072 2 +2073 2 2073 2 +2074 2 2074 2 +2075 2 2075 2 +2076 2 2076 2 +2077 2 2077 2 +2078 2 2078 2 +2079 2 2079 2 +2080 2 2080 2 +2081 2 2081 2 +2082 2 2082 2 +2083 2 2083 2 +2084 2 2084 2 +2085 2 2085 2 +2086 2 2086 2 +2087 2 2087 2 +2088 2 2088 2 +2089 2 2089 2 +2090 2 2090 2 +2091 2 2091 2 +2092 2 2092 2 +2093 2 2093 2 +2094 2 2094 2 +2095 2 2095 2 +2096 2 2096 2 +2097 2 2097 2 +2098 2 2098 2 +2099 2 2099 2 +2100 2 2100 2 +2101 2 2101 2 +2102 2 2102 2 +2103 2 2103 2 +2104 2 2104 2 +2105 2 2105 2 +2106 2 2106 2 +2107 2 2107 2 +2108 2 2108 2 +2109 2 2109 2 +2110 2 2110 2 +2111 2 2111 2 +2112 2 2112 2 +2113 2 2113 2 +2114 2 2114 2 +2115 2 2115 2 +2116 2 2116 2 +2117 2 2117 2 +2118 2 2118 2 +2119 2 2119 2 +2120 2 2120 2 +2121 2 2121 2 +2122 2 2122 2 +2123 2 2123 2 +2124 2 2124 2 +2125 2 2125 2 +2126 2 2126 2 +2127 2 2127 2 +2128 2 2128 2 +2129 2 2129 2 +2130 2 2130 2 +2131 2 2131 2 +2132 2 2132 2 +2133 2 2133 2 +2134 2 2134 2 +2135 2 2135 2 +2136 2 2136 2 +2137 2 2137 2 +2138 2 2138 2 +2139 2 2139 2 +2140 2 2140 2 +2141 2 2141 2 +2142 2 2142 2 +2143 2 2143 2 +2144 2 2144 2 +2145 2 2145 2 +2146 2 2146 2 +2147 2 2147 2 +2148 2 2148 2 +2149 2 2149 2 +2150 2 2150 2 +2151 2 2151 2 +2152 2 2152 2 +2153 2 2153 2 +2154 2 2154 2 +2155 2 2155 2 +2156 2 2156 2 +2157 2 2157 2 +2158 2 2158 2 +2159 2 2159 2 +2160 2 2160 2 +2161 2 2161 2 +2162 2 2162 2 +2163 2 2163 2 +2164 2 2164 2 +2165 2 2165 2 +2166 2 2166 2 +2167 2 2167 2 +2168 2 2168 2 +2169 2 2169 2 +2170 2 2170 2 +2171 2 2171 2 +2172 2 2172 2 +2173 2 2173 2 +2174 2 2174 2 +2175 2 2175 2 + 128 43 29 0 + 129 43 29 1 + 130 43 28 0 + 131 43 28 1 + 132 42 29 0 + 133 42 29 1 + 134 42 28 0 + 135 42 28 1 + 136 40 28 1 + 137 40 28 0 + 138 40 29 1 + 139 40 29 0 + 140 41 28 1 + 141 41 28 0 + 142 41 29 1 + 143 41 29 0 + 160 35 28 0 + 161 35 28 1 + 162 35 29 0 + 163 35 29 1 + 164 34 28 0 + 165 34 28 1 + 166 34 29 0 + 167 34 29 1 + 168 32 29 1 + 169 32 29 0 + 170 32 28 1 + 171 32 28 0 + 172 33 29 1 + 173 33 29 0 + 174 33 28 1 + 175 33 28 0 + 176 36 28 0 + 177 36 28 1 + 178 36 29 0 + 179 36 29 1 + 180 37 28 0 + 181 37 28 1 + 182 37 29 0 + 183 37 29 1 + 184 39 29 1 + 185 39 29 0 + 186 39 28 1 + 187 39 28 0 + 188 38 29 1 + 189 38 29 0 + 190 38 28 1 + 191 38 28 0 + 192 44 29 0 + 193 44 29 1 + 194 44 28 0 + 195 44 28 1 + 196 45 29 0 + 197 45 29 1 + 198 45 28 0 + 199 45 28 1 + 200 47 28 1 + 201 47 28 0 + 202 47 29 1 + 203 47 29 0 + 204 46 28 1 + 205 46 28 0 + 206 46 29 1 + 207 46 29 0 + 256 43 31 0 + 257 43 31 1 + 258 43 30 0 + 259 43 30 1 + 260 42 31 0 + 261 42 31 1 + 262 42 30 0 + 263 42 30 1 + 264 40 30 1 + 265 40 30 0 + 266 40 31 1 + 267 40 31 0 + 268 41 30 1 + 269 41 30 0 + 270 41 31 1 + 271 41 31 0 + 288 35 30 0 + 289 35 30 1 + 290 35 31 0 + 291 35 31 1 + 292 34 30 0 + 293 34 30 1 + 294 34 31 0 + 295 34 31 1 + 296 32 31 1 + 297 32 31 0 + 298 32 30 1 + 299 32 30 0 + 300 33 31 1 + 301 33 31 0 + 302 33 30 1 + 303 33 30 0 + 304 36 30 0 + 305 36 30 1 + 306 36 31 0 + 307 36 31 1 + 308 37 30 0 + 309 37 30 1 + 310 37 31 0 + 311 37 31 1 + 312 39 31 1 + 313 39 31 0 + 314 39 30 1 + 315 39 30 0 + 316 38 31 1 + 317 38 31 0 + 318 38 30 1 + 319 38 30 0 + 320 44 31 0 + 321 44 31 1 + 322 44 30 0 + 323 44 30 1 + 324 45 31 0 + 325 45 31 1 + 326 45 30 0 + 327 45 30 1 + 328 47 30 1 + 329 47 30 0 + 330 47 31 1 + 331 47 31 0 + 332 46 30 1 + 333 46 30 0 + 334 46 31 1 + 335 46 31 0 + 384 43 33 0 + 385 43 33 1 + 386 43 32 0 + 387 43 32 1 + 388 42 33 0 + 389 42 33 1 + 390 42 32 0 + 391 42 32 1 + 392 40 32 1 + 393 40 32 0 + 394 40 33 1 + 395 40 33 0 + 396 41 32 1 + 397 41 32 0 + 398 41 33 1 + 399 41 33 0 + 416 35 32 0 + 417 35 32 1 + 418 35 33 0 + 419 35 33 1 + 420 34 32 0 + 421 34 32 1 + 422 34 33 0 + 423 34 33 1 + 424 32 33 1 + 425 32 33 0 + 426 32 32 1 + 427 32 32 0 + 428 33 33 1 + 429 33 33 0 + 430 33 32 1 + 431 33 32 0 + 432 36 32 0 + 433 36 32 1 + 434 36 33 0 + 435 36 33 1 + 436 37 32 0 + 437 37 32 1 + 438 37 33 0 + 439 37 33 1 + 440 39 33 1 + 441 39 33 0 + 442 39 32 1 + 443 39 32 0 + 444 38 33 1 + 445 38 33 0 + 446 38 32 1 + 447 38 32 0 + 448 44 33 0 + 449 44 33 1 + 450 44 32 0 + 451 44 32 1 + 452 45 33 0 + 453 45 33 1 + 454 45 32 0 + 455 45 32 1 + 456 47 32 1 + 457 47 32 0 + 458 47 33 1 + 459 47 33 0 + 460 46 32 1 + 461 46 32 0 + 462 46 33 1 + 463 46 33 0 + 512 43 35 0 + 513 43 35 1 + 514 43 34 0 + 515 43 34 1 + 516 42 35 0 + 517 42 35 1 + 518 42 34 0 + 519 42 34 1 + 520 40 34 1 + 521 40 34 0 + 522 40 35 1 + 523 40 35 0 + 524 41 34 1 + 525 41 34 0 + 526 41 35 1 + 527 41 35 0 + 544 35 34 0 + 545 35 34 1 + 546 35 35 0 + 547 35 35 1 + 548 34 34 0 + 549 34 34 1 + 550 34 35 0 + 551 34 35 1 + 552 32 35 1 + 553 32 35 0 + 554 32 34 1 + 555 32 34 0 + 556 33 35 1 + 557 33 35 0 + 558 33 34 1 + 559 33 34 0 + 560 36 34 0 + 561 36 34 1 + 562 36 35 0 + 563 36 35 1 + 564 37 34 0 + 565 37 34 1 + 566 37 35 0 + 567 37 35 1 + 568 39 35 1 + 569 39 35 0 + 570 39 34 1 + 571 39 34 0 + 572 38 35 1 + 573 38 35 0 + 574 38 34 1 + 575 38 34 0 + 576 44 35 0 + 577 44 35 1 + 578 44 34 0 + 579 44 34 1 + 580 45 35 0 + 581 45 35 1 + 582 45 34 0 + 583 45 34 1 + 584 47 34 1 + 585 47 34 0 + 586 47 35 1 + 587 47 35 0 + 588 46 34 1 + 589 46 34 0 + 590 46 35 1 + 591 46 35 0 + 640 43 37 0 + 641 43 37 1 + 642 43 36 0 + 643 43 36 1 + 644 42 37 0 + 645 42 37 1 + 646 42 36 0 + 647 42 36 1 + 648 40 36 1 + 649 40 36 0 + 650 40 37 1 + 651 40 37 0 + 652 41 36 1 + 653 41 36 0 + 654 41 37 1 + 655 41 37 0 + 672 35 36 0 + 673 35 36 1 + 674 35 37 0 + 675 35 37 1 + 676 34 36 0 + 677 34 36 1 + 678 34 37 0 + 679 34 37 1 + 680 32 37 1 + 681 32 37 0 + 682 32 36 1 + 683 32 36 0 + 684 33 37 1 + 685 33 37 0 + 686 33 36 1 + 687 33 36 0 + 688 36 36 0 + 689 36 36 1 + 690 36 37 0 + 691 36 37 1 + 692 37 36 0 + 693 37 36 1 + 694 37 37 0 + 695 37 37 1 + 696 39 37 1 + 697 39 37 0 + 698 39 36 1 + 699 39 36 0 + 700 38 37 1 + 701 38 37 0 + 702 38 36 1 + 703 38 36 0 + 704 44 37 0 + 705 44 37 1 + 706 44 36 0 + 707 44 36 1 + 708 45 37 0 + 709 45 37 1 + 710 45 36 0 + 711 45 36 1 + 712 47 36 1 + 713 47 36 0 + 714 47 37 1 + 715 47 37 0 + 716 46 36 1 + 717 46 36 0 + 718 46 37 1 + 719 46 37 0 + 768 43 39 0 + 769 43 39 1 + 770 43 38 0 + 771 43 38 1 + 772 42 39 0 + 773 42 39 1 + 774 42 38 0 + 775 42 38 1 + 776 40 38 1 + 777 40 38 0 + 778 40 39 1 + 779 40 39 0 + 780 41 38 1 + 781 41 38 0 + 782 41 39 1 + 783 41 39 0 + 800 35 38 0 + 801 35 38 1 + 802 35 39 0 + 803 35 39 1 + 804 34 38 0 + 805 34 38 1 + 806 34 39 0 + 807 34 39 1 + 808 32 39 1 + 809 32 39 0 + 810 32 38 1 + 811 32 38 0 + 812 33 39 1 + 813 33 39 0 + 814 33 38 1 + 815 33 38 0 + 816 36 38 0 + 817 36 38 1 + 818 36 39 0 + 819 36 39 1 + 820 37 38 0 + 821 37 38 1 + 822 37 39 0 + 823 37 39 1 + 824 39 39 1 + 825 39 39 0 + 826 39 38 1 + 827 39 38 0 + 828 38 39 1 + 829 38 39 0 + 830 38 38 1 + 831 38 38 0 + 832 44 39 0 + 833 44 39 1 + 834 44 38 0 + 835 44 38 1 + 836 45 39 0 + 837 45 39 1 + 838 45 38 0 + 839 45 38 1 + 840 47 38 1 + 841 47 38 0 + 842 47 39 1 + 843 47 39 0 + 844 46 38 1 + 845 46 38 0 + 846 46 39 1 + 847 46 39 0 + 896 43 41 0 + 897 43 41 1 + 898 43 40 0 + 899 43 40 1 + 900 42 41 0 + 901 42 41 1 + 902 42 40 0 + 903 42 40 1 + 904 40 40 1 + 905 40 40 0 + 906 40 41 1 + 907 40 41 0 + 908 41 40 1 + 909 41 40 0 + 910 41 41 1 + 911 41 41 0 + 928 35 40 0 + 929 35 40 1 + 930 35 41 0 + 931 35 41 1 + 932 34 40 0 + 933 34 40 1 + 934 34 41 0 + 935 34 41 1 + 936 32 41 1 + 937 32 41 0 + 938 32 40 1 + 939 32 40 0 + 940 33 41 1 + 941 33 41 0 + 942 33 40 1 + 943 33 40 0 + 944 36 40 0 + 945 36 40 1 + 946 36 41 0 + 947 36 41 1 + 948 37 40 0 + 949 37 40 1 + 950 37 41 0 + 951 37 41 1 + 952 39 41 1 + 953 39 41 0 + 954 39 40 1 + 955 39 40 0 + 956 38 41 1 + 957 38 41 0 + 958 38 40 1 + 959 38 40 0 + 960 44 41 0 + 961 44 41 1 + 962 44 40 0 + 963 44 40 1 + 964 45 41 0 + 965 45 41 1 + 966 45 40 0 + 967 45 40 1 + 968 47 40 1 + 969 47 40 0 + 970 47 41 1 + 971 47 41 0 + 972 46 40 1 + 973 46 40 0 + 974 46 41 1 + 975 46 41 0 +1024 43 43 0 +1025 43 43 1 +1026 43 42 0 +1027 43 42 1 +1028 42 43 0 +1029 42 43 1 +1030 42 42 0 +1031 42 42 1 +1032 40 42 1 +1033 40 42 0 +1034 40 43 1 +1035 40 43 0 +1036 41 42 1 +1037 41 42 0 +1038 41 43 1 +1039 41 43 0 +1056 35 42 0 +1057 35 42 1 +1058 35 43 0 +1059 35 43 1 +1060 34 42 0 +1061 34 42 1 +1062 34 43 0 +1063 34 43 1 +1064 32 43 1 +1065 32 43 0 +1066 32 42 1 +1067 32 42 0 +1068 33 43 1 +1069 33 43 0 +1070 33 42 1 +1071 33 42 0 +1072 36 42 0 +1073 36 42 1 +1074 36 43 0 +1075 36 43 1 +1076 37 42 0 +1077 37 42 1 +1078 37 43 0 +1079 37 43 1 +1080 39 43 1 +1081 39 43 0 +1082 39 42 1 +1083 39 42 0 +1084 38 43 1 +1085 38 43 0 +1086 38 42 1 +1087 38 42 0 +1088 44 43 0 +1089 44 43 1 +1090 44 42 0 +1091 44 42 1 +1092 45 43 0 +1093 45 43 1 +1094 45 42 0 +1095 45 42 1 +1096 47 42 1 +1097 47 42 0 +1098 47 43 1 +1099 47 43 0 +1100 46 42 1 +1101 46 42 0 +1102 46 43 1 +1103 46 43 0 +1152 43 45 0 +1153 43 45 1 +1154 43 44 0 +1155 43 44 1 +1156 42 45 0 +1157 42 45 1 +1158 42 44 0 +1159 42 44 1 +1160 40 44 1 +1161 40 44 0 +1162 40 45 1 +1163 40 45 0 +1164 41 44 1 +1165 41 44 0 +1166 41 45 1 +1167 41 45 0 +1184 35 44 0 +1185 35 44 1 +1186 35 45 0 +1187 35 45 1 +1188 34 44 0 +1189 34 44 1 +1190 34 45 0 +1191 34 45 1 +1192 32 45 1 +1193 32 45 0 +1194 32 44 1 +1195 32 44 0 +1196 33 45 1 +1197 33 45 0 +1198 33 44 1 +1199 33 44 0 +1200 36 44 0 +1201 36 44 1 +1202 36 45 0 +1203 36 45 1 +1204 37 44 0 +1205 37 44 1 +1206 37 45 0 +1207 37 45 1 +1208 39 45 1 +1209 39 45 0 +1210 39 44 1 +1211 39 44 0 +1212 38 45 1 +1213 38 45 0 +1214 38 44 1 +1215 38 44 0 +1216 44 45 0 +1217 44 45 1 +1218 44 44 0 +1219 44 44 1 +1220 45 45 0 +1221 45 45 1 +1222 45 44 0 +1223 45 44 1 +1224 47 44 1 +1225 47 44 0 +1226 47 45 1 +1227 47 45 0 +1228 46 44 1 +1229 46 44 0 +1230 46 45 1 +1231 46 45 0 +1280 43 47 0 +1281 43 47 1 +1282 43 46 0 +1283 43 46 1 +1284 42 47 0 +1285 42 47 1 +1286 42 46 0 +1287 42 46 1 +1288 40 46 1 +1289 40 46 0 +1290 40 47 1 +1291 40 47 0 +1292 41 46 1 +1293 41 46 0 +1294 41 47 1 +1295 41 47 0 +1312 35 46 0 +1313 35 46 1 +1314 35 47 0 +1315 35 47 1 +1316 34 46 0 +1317 34 46 1 +1318 34 47 0 +1319 34 47 1 +1320 32 47 1 +1321 32 47 0 +1322 32 46 1 +1323 32 46 0 +1324 33 47 1 +1325 33 47 0 +1326 33 46 1 +1327 33 46 0 +1328 36 46 0 +1329 36 46 1 +1330 36 47 0 +1331 36 47 1 +1332 37 46 0 +1333 37 46 1 +1334 37 47 0 +1335 37 47 1 +1336 39 47 1 +1337 39 47 0 +1338 39 46 1 +1339 39 46 0 +1340 38 47 1 +1341 38 47 0 +1342 38 46 1 +1343 38 46 0 +1344 44 47 0 +1345 44 47 1 +1346 44 46 0 +1347 44 46 1 +1348 45 47 0 +1349 45 47 1 +1350 45 46 0 +1351 45 46 1 +1352 47 46 1 +1353 47 46 0 +1354 47 47 1 +1355 47 47 0 +1356 46 46 1 +1357 46 46 0 +1358 46 47 1 +1359 46 47 0 +1408 43 49 0 +1409 43 49 1 +1410 43 48 0 +1411 43 48 1 +1412 42 49 0 +1413 42 49 1 +1414 42 48 0 +1415 42 48 1 +1416 40 48 1 +1417 40 48 0 +1418 40 49 1 +1419 40 49 0 +1420 41 48 1 +1421 41 48 0 +1422 41 49 1 +1423 41 49 0 +1440 35 48 0 +1441 35 48 1 +1442 35 49 0 +1443 35 49 1 +1444 34 48 0 +1445 34 48 1 +1446 34 49 0 +1447 34 49 1 +1448 32 49 1 +1449 32 49 0 +1450 32 48 1 +1451 32 48 0 +1452 33 49 1 +1453 33 49 0 +1454 33 48 1 +1455 33 48 0 +1456 36 48 0 +1457 36 48 1 +1458 36 49 0 +1459 36 49 1 +1460 37 48 0 +1461 37 48 1 +1462 37 49 0 +1463 37 49 1 +1464 39 49 1 +1465 39 49 0 +1466 39 48 1 +1467 39 48 0 +1468 38 49 1 +1469 38 49 0 +1470 38 48 1 +1471 38 48 0 +1472 44 49 0 +1473 44 49 1 +1474 44 48 0 +1475 44 48 1 +1476 45 49 0 +1477 45 49 1 +1478 45 48 0 +1479 45 48 1 +1480 47 48 1 +1481 47 48 0 +1482 47 49 1 +1483 47 49 0 +1484 46 48 1 +1485 46 48 0 +1486 46 49 1 +1487 46 49 0 +1536 43 51 0 +1537 43 51 1 +1538 43 50 0 +1539 43 50 1 +1540 42 51 0 +1541 42 51 1 +1542 42 50 0 +1543 42 50 1 +1544 40 50 1 +1545 40 50 0 +1546 40 51 1 +1547 40 51 0 +1548 41 50 1 +1549 41 50 0 +1550 41 51 1 +1551 41 51 0 +1568 35 50 0 +1569 35 50 1 +1570 35 51 0 +1571 35 51 1 +1572 34 50 0 +1573 34 50 1 +1574 34 51 0 +1575 34 51 1 +1576 32 51 1 +1577 32 51 0 +1578 32 50 1 +1579 32 50 0 +1580 33 51 1 +1581 33 51 0 +1582 33 50 1 +1583 33 50 0 +1584 36 50 0 +1585 36 50 1 +1586 36 51 0 +1587 36 51 1 +1588 37 50 0 +1589 37 50 1 +1590 37 51 0 +1591 37 51 1 +1592 39 51 1 +1593 39 51 0 +1594 39 50 1 +1595 39 50 0 +1596 38 51 1 +1597 38 51 0 +1598 38 50 1 +1599 38 50 0 +1600 44 51 0 +1601 44 51 1 +1602 44 50 0 +1603 44 50 1 +1604 45 51 0 +1605 45 51 1 +1606 45 50 0 +1607 45 50 1 +1608 47 50 1 +1609 47 50 0 +1610 47 51 1 +1611 47 51 0 +1612 46 50 1 +1613 46 50 0 +1614 46 51 1 +1615 46 51 0 +1664 43 53 0 +1665 43 53 1 +1666 43 52 0 +1667 43 52 1 +1668 42 53 0 +1669 42 53 1 +1670 42 52 0 +1671 42 52 1 +1672 40 52 1 +1673 40 52 0 +1674 40 53 1 +1675 40 53 0 +1676 41 52 1 +1677 41 52 0 +1678 41 53 1 +1679 41 53 0 +1696 35 52 0 +1697 35 52 1 +1698 35 53 0 +1699 35 53 1 +1700 34 52 0 +1701 34 52 1 +1702 34 53 0 +1703 34 53 1 +1704 32 53 1 +1705 32 53 0 +1706 32 52 1 +1707 32 52 0 +1708 33 53 1 +1709 33 53 0 +1710 33 52 1 +1711 33 52 0 +1712 36 52 0 +1713 36 52 1 +1714 36 53 0 +1715 36 53 1 +1716 37 52 0 +1717 37 52 1 +1718 37 53 0 +1719 37 53 1 +1720 39 53 1 +1721 39 53 0 +1722 39 52 1 +1723 39 52 0 +1724 38 53 1 +1725 38 53 0 +1726 38 52 1 +1727 38 52 0 +1728 44 53 0 +1729 44 53 1 +1730 44 52 0 +1731 44 52 1 +1732 45 53 0 +1733 45 53 1 +1734 45 52 0 +1735 45 52 1 +1736 47 52 1 +1737 47 52 0 +1738 47 53 1 +1739 47 53 0 +1740 46 52 1 +1741 46 52 0 +1742 46 53 1 +1743 46 53 0 +1792 43 55 0 +1793 43 55 1 +1794 43 54 0 +1795 43 54 1 +1796 42 55 0 +1797 42 55 1 +1798 42 54 0 +1799 42 54 1 +1800 40 54 1 +1801 40 54 0 +1802 40 55 1 +1803 40 55 0 +1804 41 54 1 +1805 41 54 0 +1806 41 55 1 +1807 41 55 0 +1824 35 54 0 +1825 35 54 1 +1826 35 55 0 +1827 35 55 1 +1828 34 54 0 +1829 34 54 1 +1830 34 55 0 +1831 34 55 1 +1832 32 55 1 +1833 32 55 0 +1834 32 54 1 +1835 32 54 0 +1836 33 55 1 +1837 33 55 0 +1838 33 54 1 +1839 33 54 0 +1840 36 54 0 +1841 36 54 1 +1842 36 55 0 +1843 36 55 1 +1844 37 54 0 +1845 37 54 1 +1846 37 55 0 +1847 37 55 1 +1848 39 55 1 +1849 39 55 0 +1850 39 54 1 +1851 39 54 0 +1852 38 55 1 +1853 38 55 0 +1854 38 54 1 +1855 38 54 0 +1856 44 55 0 +1857 44 55 1 +1858 44 54 0 +1859 44 54 1 +1860 45 55 0 +1861 45 55 1 +1862 45 54 0 +1863 45 54 1 +1864 47 54 1 +1865 47 54 0 +1866 47 55 1 +1867 47 55 0 +1868 46 54 1 +1869 46 54 0 +1870 46 55 1 +1871 46 55 0 +2176 43 27 0 +2177 43 27 1 +2178 43 26 0 +2179 43 26 1 +2180 42 27 0 +2181 42 27 1 +2182 42 26 0 +2183 42 26 1 +2184 40 26 1 +2185 40 26 0 +2186 40 27 1 +2187 40 27 0 +2188 41 26 1 +2189 41 26 0 +2190 41 27 1 +2191 41 27 0 +2208 35 26 0 +2209 35 26 1 +2210 35 27 0 +2211 35 27 1 +2212 34 26 0 +2213 34 26 1 +2214 34 27 0 +2215 34 27 1 +2216 32 27 1 +2217 32 27 0 +2218 32 26 1 +2219 32 26 0 +2220 33 27 1 +2221 33 27 0 +2222 33 26 1 +2223 33 26 0 +2224 36 26 0 +2225 36 26 1 +2226 36 27 0 +2227 36 27 1 +2228 37 26 0 +2229 37 26 1 +2230 37 27 0 +2231 37 27 1 +2232 39 27 1 +2233 39 27 0 +2234 39 26 1 +2235 39 26 0 +2236 38 27 1 +2237 38 27 0 +2238 38 26 1 +2239 38 26 0 +2240 44 27 0 +2241 44 27 1 +2242 44 26 0 +2243 44 26 1 +2244 45 27 0 +2245 45 27 1 +2246 45 26 0 +2247 45 26 1 +2248 47 26 1 +2249 47 26 0 +2250 47 27 1 +2251 47 27 0 +2252 46 26 1 +2253 46 26 0 +2254 46 27 1 +2255 46 27 0 +2304 43 25 0 +2305 43 25 1 +2306 43 24 0 +2307 43 24 1 +2308 42 25 0 +2309 42 25 1 +2310 42 24 0 +2311 42 24 1 +2312 40 24 1 +2313 40 24 0 +2314 40 25 1 +2315 40 25 0 +2316 41 24 1 +2317 41 24 0 +2318 41 25 1 +2319 41 25 0 +2336 35 24 0 +2337 35 24 1 +2338 35 25 0 +2339 35 25 1 +2340 34 24 0 +2341 34 24 1 +2342 34 25 0 +2343 34 25 1 +2344 32 25 1 +2345 32 25 0 +2346 32 24 1 +2347 32 24 0 +2348 33 25 1 +2349 33 25 0 +2350 33 24 1 +2351 33 24 0 +2352 36 24 0 +2353 36 24 1 +2354 36 25 0 +2355 36 25 1 +2356 37 24 0 +2357 37 24 1 +2358 37 25 0 +2359 37 25 1 +2360 39 25 1 +2361 39 25 0 +2362 39 24 1 +2363 39 24 0 +2364 38 25 1 +2365 38 25 0 +2366 38 24 1 +2367 38 24 0 +2368 44 25 0 +2369 44 25 1 +2370 44 24 0 +2371 44 24 1 +2372 45 25 0 +2373 45 25 1 +2374 45 24 0 +2375 45 24 1 +2376 47 24 1 +2377 47 24 0 +2378 47 25 1 +2379 47 25 0 +2380 46 24 1 +2381 46 24 0 +2382 46 25 1 +2383 46 25 0 +2432 43 23 0 +2433 43 23 1 +2434 43 22 0 +2435 43 22 1 +2436 42 23 0 +2437 42 23 1 +2438 42 22 0 +2439 42 22 1 +2440 40 22 1 +2441 40 22 0 +2442 40 23 1 +2443 40 23 0 +2444 41 22 1 +2445 41 22 0 +2446 41 23 1 +2447 41 23 0 +2464 35 22 0 +2465 35 22 1 +2466 35 23 0 +2467 35 23 1 +2468 34 22 0 +2469 34 22 1 +2470 34 23 0 +2471 34 23 1 +2472 32 23 1 +2473 32 23 0 +2474 32 22 1 +2475 32 22 0 +2476 33 23 1 +2477 33 23 0 +2478 33 22 1 +2479 33 22 0 +2480 36 22 0 +2481 36 22 1 +2482 36 23 0 +2483 36 23 1 +2484 37 22 0 +2485 37 22 1 +2486 37 23 0 +2487 37 23 1 +2488 39 23 1 +2489 39 23 0 +2490 39 22 1 +2491 39 22 0 +2492 38 23 1 +2493 38 23 0 +2494 38 22 1 +2495 38 22 0 +2496 44 23 0 +2497 44 23 1 +2498 44 22 0 +2499 44 22 1 +2500 45 23 0 +2501 45 23 1 +2502 45 22 0 +2503 45 22 1 +2504 47 22 1 +2505 47 22 0 +2506 47 23 1 +2507 47 23 0 +2508 46 22 1 +2509 46 22 0 +2510 46 23 1 +2511 46 23 0 +2560 43 21 0 +2561 43 21 1 +2562 43 20 0 +2563 43 20 1 +2564 42 21 0 +2565 42 21 1 +2566 42 20 0 +2567 42 20 1 +2568 40 20 1 +2569 40 20 0 +2570 40 21 1 +2571 40 21 0 +2572 41 20 1 +2573 41 20 0 +2574 41 21 1 +2575 41 21 0 +2592 35 20 0 +2593 35 20 1 +2594 35 21 0 +2595 35 21 1 +2596 34 20 0 +2597 34 20 1 +2598 34 21 0 +2599 34 21 1 +2600 32 21 1 +2601 32 21 0 +2602 32 20 1 +2603 32 20 0 +2604 33 21 1 +2605 33 21 0 +2606 33 20 1 +2607 33 20 0 +2608 36 20 0 +2609 36 20 1 +2610 36 21 0 +2611 36 21 1 +2612 37 20 0 +2613 37 20 1 +2614 37 21 0 +2615 37 21 1 +2616 39 21 1 +2617 39 21 0 +2618 39 20 1 +2619 39 20 0 +2620 38 21 1 +2621 38 21 0 +2622 38 20 1 +2623 38 20 0 +2624 44 21 0 +2625 44 21 1 +2626 44 20 0 +2627 44 20 1 +2628 45 21 0 +2629 45 21 1 +2630 45 20 0 +2631 45 20 1 +2632 47 20 1 +2633 47 20 0 +2634 47 21 1 +2635 47 21 0 +2636 46 20 1 +2637 46 20 0 +2638 46 21 1 +2639 46 21 0 +2688 43 19 0 +2689 43 19 1 +2690 43 18 0 +2691 43 18 1 +2692 42 19 0 +2693 42 19 1 +2694 42 18 0 +2695 42 18 1 +2696 40 18 1 +2697 40 18 0 +2698 40 19 1 +2699 40 19 0 +2700 41 18 1 +2701 41 18 0 +2702 41 19 1 +2703 41 19 0 +2720 35 18 0 +2721 35 18 1 +2722 35 19 0 +2723 35 19 1 +2724 34 18 0 +2725 34 18 1 +2726 34 19 0 +2727 34 19 1 +2728 32 19 1 +2729 32 19 0 +2730 32 18 1 +2731 32 18 0 +2732 33 19 1 +2733 33 19 0 +2734 33 18 1 +2735 33 18 0 +2736 36 18 0 +2737 36 18 1 +2738 36 19 0 +2739 36 19 1 +2740 37 18 0 +2741 37 18 1 +2742 37 19 0 +2743 37 19 1 +2744 39 19 1 +2745 39 19 0 +2746 39 18 1 +2747 39 18 0 +2748 38 19 1 +2749 38 19 0 +2750 38 18 1 +2751 38 18 0 +2752 44 19 0 +2753 44 19 1 +2754 44 18 0 +2755 44 18 1 +2756 45 19 0 +2757 45 19 1 +2758 45 18 0 +2759 45 18 1 +2760 47 18 1 +2761 47 18 0 +2762 47 19 1 +2763 47 19 0 +2764 46 18 1 +2765 46 18 0 +2766 46 19 1 +2767 46 19 0 +2816 43 17 0 +2817 43 17 1 +2818 43 16 0 +2819 43 16 1 +2820 42 17 0 +2821 42 17 1 +2822 42 16 0 +2823 42 16 1 +2824 40 16 1 +2825 40 16 0 +2826 40 17 1 +2827 40 17 0 +2828 41 16 1 +2829 41 16 0 +2830 41 17 1 +2831 41 17 0 +2848 35 16 0 +2849 35 16 1 +2850 35 17 0 +2851 35 17 1 +2852 34 16 0 +2853 34 16 1 +2854 34 17 0 +2855 34 17 1 +2856 32 17 1 +2857 32 17 0 +2858 32 16 1 +2859 32 16 0 +2860 33 17 1 +2861 33 17 0 +2862 33 16 1 +2863 33 16 0 +2864 36 16 0 +2865 36 16 1 +2866 36 17 0 +2867 36 17 1 +2868 37 16 0 +2869 37 16 1 +2870 37 17 0 +2871 37 17 1 +2872 39 17 1 +2873 39 17 0 +2874 39 16 1 +2875 39 16 0 +2876 38 17 1 +2877 38 17 0 +2878 38 16 1 +2879 38 16 0 +2880 44 17 0 +2881 44 17 1 +2882 44 16 0 +2883 44 16 1 +2884 45 17 0 +2885 45 17 1 +2886 45 16 0 +2887 45 16 1 +2888 47 16 1 +2889 47 16 0 +2890 47 17 1 +2891 47 17 0 +2892 46 16 1 +2893 46 16 0 +2894 46 17 1 +2895 46 17 0 +2944 43 15 0 +2945 43 15 1 +2946 43 14 0 +2947 43 14 1 +2948 42 15 0 +2949 42 15 1 +2950 42 14 0 +2951 42 14 1 +2952 40 14 1 +2953 40 14 0 +2954 40 15 1 +2955 40 15 0 +2956 41 14 1 +2957 41 14 0 +2958 41 15 1 +2959 41 15 0 +2976 35 14 0 +2977 35 14 1 +2978 35 15 0 +2979 35 15 1 +2980 34 14 0 +2981 34 14 1 +2982 34 15 0 +2983 34 15 1 +2984 32 15 1 +2985 32 15 0 +2986 32 14 1 +2987 32 14 0 +2988 33 15 1 +2989 33 15 0 +2990 33 14 1 +2991 33 14 0 +2992 36 14 0 +2993 36 14 1 +2994 36 15 0 +2995 36 15 1 +2996 37 14 0 +2997 37 14 1 +2998 37 15 0 +2999 37 15 1 +3000 39 15 1 +3001 39 15 0 +3002 39 14 1 +3003 39 14 0 +3004 38 15 1 +3005 38 15 0 +3006 38 14 1 +3007 38 14 0 +3008 44 15 0 +3009 44 15 1 +3010 44 14 0 +3011 44 14 1 +3012 45 15 0 +3013 45 15 1 +3014 45 14 0 +3015 45 14 1 +3016 47 14 1 +3017 47 14 0 +3018 47 15 1 +3019 47 15 0 +3020 46 14 1 +3021 46 14 0 +3022 46 15 1 +3023 46 15 0 +3072 43 13 0 +3073 43 13 1 +3074 43 12 0 +3075 43 12 1 +3076 42 13 0 +3077 42 13 1 +3078 42 12 0 +3079 42 12 1 +3080 40 12 1 +3081 40 12 0 +3082 40 13 1 +3083 40 13 0 +3084 41 12 1 +3085 41 12 0 +3086 41 13 1 +3087 41 13 0 +3104 35 12 0 +3105 35 12 1 +3106 35 13 0 +3107 35 13 1 +3108 34 12 0 +3109 34 12 1 +3110 34 13 0 +3111 34 13 1 +3112 32 13 1 +3113 32 13 0 +3114 32 12 1 +3115 32 12 0 +3116 33 13 1 +3117 33 13 0 +3118 33 12 1 +3119 33 12 0 +3120 36 12 0 +3121 36 12 1 +3122 36 13 0 +3123 36 13 1 +3124 37 12 0 +3125 37 12 1 +3126 37 13 0 +3127 37 13 1 +3128 39 13 1 +3129 39 13 0 +3130 39 12 1 +3131 39 12 0 +3132 38 13 1 +3133 38 13 0 +3134 38 12 1 +3135 38 12 0 +3136 44 13 0 +3137 44 13 1 +3138 44 12 0 +3139 44 12 1 +3140 45 13 0 +3141 45 13 1 +3142 45 12 0 +3143 45 12 1 +3144 47 12 1 +3145 47 12 0 +3146 47 13 1 +3147 47 13 0 +3148 46 12 1 +3149 46 12 0 +3150 46 13 1 +3151 46 13 0 +3200 43 11 0 +3201 43 11 1 +3202 43 10 0 +3203 43 10 1 +3204 42 11 0 +3205 42 11 1 +3206 42 10 0 +3207 42 10 1 +3208 40 10 1 +3209 40 10 0 +3210 40 11 1 +3211 40 11 0 +3212 41 10 1 +3213 41 10 0 +3214 41 11 1 +3215 41 11 0 +3232 35 10 0 +3233 35 10 1 +3234 35 11 0 +3235 35 11 1 +3236 34 10 0 +3237 34 10 1 +3238 34 11 0 +3239 34 11 1 +3240 32 11 1 +3241 32 11 0 +3242 32 10 1 +3243 32 10 0 +3244 33 11 1 +3245 33 11 0 +3246 33 10 1 +3247 33 10 0 +3248 36 10 0 +3249 36 10 1 +3250 36 11 0 +3251 36 11 1 +3252 37 10 0 +3253 37 10 1 +3254 37 11 0 +3255 37 11 1 +3256 39 11 1 +3257 39 11 0 +3258 39 10 1 +3259 39 10 0 +3260 38 11 1 +3261 38 11 0 +3262 38 10 1 +3263 38 10 0 +3264 44 11 0 +3265 44 11 1 +3266 44 10 0 +3267 44 10 1 +3268 45 11 0 +3269 45 11 1 +3270 45 10 0 +3271 45 10 1 +3272 47 10 1 +3273 47 10 0 +3274 47 11 1 +3275 47 11 0 +3276 46 10 1 +3277 46 10 0 +3278 46 11 1 +3279 46 11 0 +3328 43 9 0 +3329 43 9 1 +3330 43 8 0 +3331 43 8 1 +3332 42 9 0 +3333 42 9 1 +3334 42 8 0 +3335 42 8 1 +3336 40 8 1 +3337 40 8 0 +3338 40 9 1 +3339 40 9 0 +3340 41 8 1 +3341 41 8 0 +3342 41 9 1 +3343 41 9 0 +3360 35 8 0 +3361 35 8 1 +3362 35 9 0 +3363 35 9 1 +3364 34 8 0 +3365 34 8 1 +3366 34 9 0 +3367 34 9 1 +3368 32 9 1 +3369 32 9 0 +3370 32 8 1 +3371 32 8 0 +3372 33 9 1 +3373 33 9 0 +3374 33 8 1 +3375 33 8 0 +3376 36 8 0 +3377 36 8 1 +3378 36 9 0 +3379 36 9 1 +3380 37 8 0 +3381 37 8 1 +3382 37 9 0 +3383 37 9 1 +3384 39 9 1 +3385 39 9 0 +3386 39 8 1 +3387 39 8 0 +3388 38 9 1 +3389 38 9 0 +3390 38 8 1 +3391 38 8 0 +3392 44 9 0 +3393 44 9 1 +3394 44 8 0 +3395 44 8 1 +3396 45 9 0 +3397 45 9 1 +3398 45 8 0 +3399 45 8 1 +3400 47 8 1 +3401 47 8 0 +3402 47 9 1 +3403 47 9 0 +3404 46 8 1 +3405 46 8 0 +3406 46 9 1 +3407 46 9 0 +3456 43 7 0 +3457 43 7 1 +3458 43 6 0 +3459 43 6 1 +3460 42 7 0 +3461 42 7 1 +3462 42 6 0 +3463 42 6 1 +3464 40 6 1 +3465 40 6 0 +3466 40 7 1 +3467 40 7 0 +3468 41 6 1 +3469 41 6 0 +3470 41 7 1 +3471 41 7 0 +3488 35 6 0 +3489 35 6 1 +3490 35 7 0 +3491 35 7 1 +3492 34 6 0 +3493 34 6 1 +3494 34 7 0 +3495 34 7 1 +3496 32 7 1 +3497 32 7 0 +3498 32 6 1 +3499 32 6 0 +3500 33 7 1 +3501 33 7 0 +3502 33 6 1 +3503 33 6 0 +3504 36 6 0 +3505 36 6 1 +3506 36 7 0 +3507 36 7 1 +3508 37 6 0 +3509 37 6 1 +3510 37 7 0 +3511 37 7 1 +3512 39 7 1 +3513 39 7 0 +3514 39 6 1 +3515 39 6 0 +3516 38 7 1 +3517 38 7 0 +3518 38 6 1 +3519 38 6 0 +3520 44 7 0 +3521 44 7 1 +3522 44 6 0 +3523 44 6 1 +3524 45 7 0 +3525 45 7 1 +3526 45 6 0 +3527 45 6 1 +3528 47 6 1 +3529 47 6 0 +3530 47 7 1 +3531 47 7 0 +3532 46 6 1 +3533 46 6 0 +3534 46 7 1 +3535 46 7 0 +3584 43 5 0 +3585 43 5 1 +3586 43 4 0 +3587 43 4 1 +3588 42 5 0 +3589 42 5 1 +3590 42 4 0 +3591 42 4 1 +3592 40 4 1 +3593 40 4 0 +3594 40 5 1 +3595 40 5 0 +3596 41 4 1 +3597 41 4 0 +3598 41 5 1 +3599 41 5 0 +3616 35 4 0 +3617 35 4 1 +3618 35 5 0 +3619 35 5 1 +3620 34 4 0 +3621 34 4 1 +3622 34 5 0 +3623 34 5 1 +3624 32 5 1 +3625 32 5 0 +3626 32 4 1 +3627 32 4 0 +3628 33 5 1 +3629 33 5 0 +3630 33 4 1 +3631 33 4 0 +3632 36 4 0 +3633 36 4 1 +3634 36 5 0 +3635 36 5 1 +3636 37 4 0 +3637 37 4 1 +3638 37 5 0 +3639 37 5 1 +3640 39 5 1 +3641 39 5 0 +3642 39 4 1 +3643 39 4 0 +3644 38 5 1 +3645 38 5 0 +3646 38 4 1 +3647 38 4 0 +3648 44 5 0 +3649 44 5 1 +3650 44 4 0 +3651 44 4 1 +3652 45 5 0 +3653 45 5 1 +3654 45 4 0 +3655 45 4 1 +3656 47 4 1 +3657 47 4 0 +3658 47 5 1 +3659 47 5 0 +3660 46 4 1 +3661 46 4 0 +3662 46 5 1 +3663 46 5 0 +3712 43 3 0 +3713 43 3 1 +3714 43 2 0 +3715 43 2 1 +3716 42 3 0 +3717 42 3 1 +3718 42 2 0 +3719 42 2 1 +3720 40 2 1 +3721 40 2 0 +3722 40 3 1 +3723 40 3 0 +3724 41 2 1 +3725 41 2 0 +3726 41 3 1 +3727 41 3 0 +3744 35 2 0 +3745 35 2 1 +3746 35 3 0 +3747 35 3 1 +3748 34 2 0 +3749 34 2 1 +3750 34 3 0 +3751 34 3 1 +3752 32 3 1 +3753 32 3 0 +3754 32 2 1 +3755 32 2 0 +3756 33 3 1 +3757 33 3 0 +3758 33 2 1 +3759 33 2 0 +3760 36 2 0 +3761 36 2 1 +3762 36 3 0 +3763 36 3 1 +3764 37 2 0 +3765 37 2 1 +3766 37 3 0 +3767 37 3 1 +3768 39 3 1 +3769 39 3 0 +3770 39 2 1 +3771 39 2 0 +3772 38 3 1 +3773 38 3 0 +3774 38 2 1 +3775 38 2 0 +3776 44 3 0 +3777 44 3 1 +3778 44 2 0 +3779 44 2 1 +3780 45 3 0 +3781 45 3 1 +3782 45 2 0 +3783 45 2 1 +3784 47 2 1 +3785 47 2 0 +3786 47 3 1 +3787 47 3 0 +3788 46 2 1 +3789 46 2 0 +3790 46 3 1 +3791 46 3 0 +3840 43 1 0 +3841 43 1 1 +3842 43 0 0 +3843 43 0 1 +3844 42 1 0 +3845 42 1 1 +3846 42 0 0 +3847 42 0 1 +3848 40 0 1 +3849 40 0 0 +3850 40 1 1 +3851 40 1 0 +3852 41 0 1 +3853 41 0 0 +3854 41 1 1 +3855 41 1 0 +3872 35 0 0 +3873 35 0 1 +3874 35 1 0 +3875 35 1 1 +3876 34 0 0 +3877 34 0 1 +3878 34 1 0 +3879 34 1 1 +3880 32 1 1 +3881 32 1 0 +3882 32 0 1 +3883 32 0 0 +3884 33 1 1 +3885 33 1 0 +3886 33 0 1 +3887 33 0 0 +3888 36 0 0 +3889 36 0 1 +3890 36 1 0 +3891 36 1 1 +3892 37 0 0 +3893 37 0 1 +3894 37 1 0 +3895 37 1 1 +3896 39 1 1 +3897 39 1 0 +3898 39 0 1 +3899 39 0 0 +3900 38 1 1 +3901 38 1 0 +3902 38 0 1 +3903 38 0 0 +3904 44 1 0 +3905 44 1 1 +3906 44 0 0 +3907 44 0 1 +3908 45 1 0 +3909 45 1 1 +3910 45 0 0 +3911 45 0 1 +3912 47 0 1 +3913 47 0 0 +3914 47 1 1 +3915 47 1 0 +3916 46 0 1 +3917 46 0 0 +3918 46 1 1 +3919 46 1 0 diff --git a/Detectors/PHOS/base/files/Mod2RCU3.data b/Detectors/PHOS/base/files/Mod2RCU3.data new file mode 100644 index 0000000000000..43bd76fc42791 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod2RCU3.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 3 0 2 + 1 3 1 2 + 2 3 2 2 + 3 3 3 2 + 4 3 4 2 + 5 3 5 2 + 6 3 6 2 + 7 3 7 2 + 8 3 8 2 + 9 3 9 2 + 10 3 10 2 + 11 3 11 2 + 12 3 12 2 + 13 3 13 2 + 14 3 14 2 + 15 3 15 2 + 16 3 16 2 + 17 3 17 2 + 18 3 18 2 + 19 3 19 2 + 20 3 20 2 + 21 3 21 2 + 22 3 22 2 + 23 3 23 2 + 24 3 24 2 + 25 3 25 2 + 26 3 26 2 + 27 3 27 2 + 28 3 28 2 + 29 3 29 2 + 30 3 30 2 + 31 3 31 2 + 32 3 32 2 + 33 3 33 2 + 34 3 34 2 + 35 3 35 2 + 36 3 36 2 + 37 3 37 2 + 38 3 38 2 + 39 3 39 2 + 40 3 40 2 + 41 3 41 2 + 42 3 42 2 + 43 3 43 2 + 44 3 44 2 + 45 3 45 2 + 46 3 46 2 + 47 3 47 2 + 48 3 48 2 + 49 3 49 2 + 50 3 50 2 + 51 3 51 2 + 52 3 52 2 + 53 3 53 2 + 54 3 54 2 + 55 3 55 2 + 56 3 56 2 + 57 3 57 2 + 58 3 58 2 + 59 3 59 2 + 60 3 60 2 + 61 3 61 2 + 62 3 62 2 + 63 3 63 2 + 64 3 64 2 + 65 3 65 2 + 66 3 66 2 + 67 3 67 2 + 68 3 68 2 + 69 3 69 2 + 70 3 70 2 + 71 3 71 2 + 72 3 72 2 + 73 3 73 2 + 74 3 74 2 + 75 3 75 2 + 76 3 76 2 + 77 3 77 2 + 78 3 78 2 + 79 3 79 2 + 80 3 80 2 + 81 3 81 2 + 82 3 82 2 + 83 3 83 2 + 84 3 84 2 + 85 3 85 2 + 86 3 86 2 + 87 3 87 2 + 88 3 88 2 + 89 3 89 2 + 90 3 90 2 + 91 3 91 2 + 92 3 92 2 + 93 3 93 2 + 94 3 94 2 + 95 3 95 2 + 96 3 96 2 + 97 3 97 2 + 98 3 98 2 + 99 3 99 2 + 100 3 100 2 + 101 3 101 2 + 102 3 102 2 + 103 3 103 2 + 104 3 104 2 + 105 3 105 2 + 106 3 106 2 + 107 3 107 2 + 108 3 108 2 + 109 3 109 2 + 110 3 110 2 + 111 3 111 2 + 112 3 112 2 + 113 3 113 2 + 114 3 114 2 + 115 3 115 2 + 116 3 116 2 + 117 3 117 2 + 118 3 118 2 + 119 3 119 2 + 120 3 120 2 + 121 3 121 2 + 122 3 122 2 + 123 3 123 2 + 124 3 124 2 + 125 3 125 2 + 126 3 126 2 + 127 3 127 2 +2048 3 2048 2 +2049 3 2049 2 +2050 3 2050 2 +2051 3 2051 2 +2052 3 2052 2 +2053 3 2053 2 +2054 3 2054 2 +2055 3 2055 2 +2056 3 2056 2 +2057 3 2057 2 +2058 3 2058 2 +2059 3 2059 2 +2060 3 2060 2 +2061 3 2061 2 +2062 3 2062 2 +2063 3 2063 2 +2064 3 2064 2 +2065 3 2065 2 +2066 3 2066 2 +2067 3 2067 2 +2068 3 2068 2 +2069 3 2069 2 +2070 3 2070 2 +2071 3 2071 2 +2072 3 2072 2 +2073 3 2073 2 +2074 3 2074 2 +2075 3 2075 2 +2076 3 2076 2 +2077 3 2077 2 +2078 3 2078 2 +2079 3 2079 2 +2080 3 2080 2 +2081 3 2081 2 +2082 3 2082 2 +2083 3 2083 2 +2084 3 2084 2 +2085 3 2085 2 +2086 3 2086 2 +2087 3 2087 2 +2088 3 2088 2 +2089 3 2089 2 +2090 3 2090 2 +2091 3 2091 2 +2092 3 2092 2 +2093 3 2093 2 +2094 3 2094 2 +2095 3 2095 2 +2096 3 2096 2 +2097 3 2097 2 +2098 3 2098 2 +2099 3 2099 2 +2100 3 2100 2 +2101 3 2101 2 +2102 3 2102 2 +2103 3 2103 2 +2104 3 2104 2 +2105 3 2105 2 +2106 3 2106 2 +2107 3 2107 2 +2108 3 2108 2 +2109 3 2109 2 +2110 3 2110 2 +2111 3 2111 2 +2112 3 2112 2 +2113 3 2113 2 +2114 3 2114 2 +2115 3 2115 2 +2116 3 2116 2 +2117 3 2117 2 +2118 3 2118 2 +2119 3 2119 2 +2120 3 2120 2 +2121 3 2121 2 +2122 3 2122 2 +2123 3 2123 2 +2124 3 2124 2 +2125 3 2125 2 +2126 3 2126 2 +2127 3 2127 2 +2128 3 2128 2 +2129 3 2129 2 +2130 3 2130 2 +2131 3 2131 2 +2132 3 2132 2 +2133 3 2133 2 +2134 3 2134 2 +2135 3 2135 2 +2136 3 2136 2 +2137 3 2137 2 +2138 3 2138 2 +2139 3 2139 2 +2140 3 2140 2 +2141 3 2141 2 +2142 3 2142 2 +2143 3 2143 2 +2144 3 2144 2 +2145 3 2145 2 +2146 3 2146 2 +2147 3 2147 2 +2148 3 2148 2 +2149 3 2149 2 +2150 3 2150 2 +2151 3 2151 2 +2152 3 2152 2 +2153 3 2153 2 +2154 3 2154 2 +2155 3 2155 2 +2156 3 2156 2 +2157 3 2157 2 +2158 3 2158 2 +2159 3 2159 2 +2160 3 2160 2 +2161 3 2161 2 +2162 3 2162 2 +2163 3 2163 2 +2164 3 2164 2 +2165 3 2165 2 +2166 3 2166 2 +2167 3 2167 2 +2168 3 2168 2 +2169 3 2169 2 +2170 3 2170 2 +2171 3 2171 2 +2172 3 2172 2 +2173 3 2173 2 +2174 3 2174 2 +2175 3 2175 2 + 128 59 29 0 + 129 59 29 1 + 130 59 28 0 + 131 59 28 1 + 132 58 29 0 + 133 58 29 1 + 134 58 28 0 + 135 58 28 1 + 136 56 28 1 + 137 56 28 0 + 138 56 29 1 + 139 56 29 0 + 140 57 28 1 + 141 57 28 0 + 142 57 29 1 + 143 57 29 0 + 160 51 28 0 + 161 51 28 1 + 162 51 29 0 + 163 51 29 1 + 164 50 28 0 + 165 50 28 1 + 166 50 29 0 + 167 50 29 1 + 168 48 29 1 + 169 48 29 0 + 170 48 28 1 + 171 48 28 0 + 172 49 29 1 + 173 49 29 0 + 174 49 28 1 + 175 49 28 0 + 176 52 28 0 + 177 52 28 1 + 178 52 29 0 + 179 52 29 1 + 180 53 28 0 + 181 53 28 1 + 182 53 29 0 + 183 53 29 1 + 184 55 29 1 + 185 55 29 0 + 186 55 28 1 + 187 55 28 0 + 188 54 29 1 + 189 54 29 0 + 190 54 28 1 + 191 54 28 0 + 192 60 29 0 + 193 60 29 1 + 194 60 28 0 + 195 60 28 1 + 196 61 29 0 + 197 61 29 1 + 198 61 28 0 + 199 61 28 1 + 200 63 28 1 + 201 63 28 0 + 202 63 29 1 + 203 63 29 0 + 204 62 28 1 + 205 62 28 0 + 206 62 29 1 + 207 62 29 0 + 256 59 31 0 + 257 59 31 1 + 258 59 30 0 + 259 59 30 1 + 260 58 31 0 + 261 58 31 1 + 262 58 30 0 + 263 58 30 1 + 264 56 30 1 + 265 56 30 0 + 266 56 31 1 + 267 56 31 0 + 268 57 30 1 + 269 57 30 0 + 270 57 31 1 + 271 57 31 0 + 288 51 30 0 + 289 51 30 1 + 290 51 31 0 + 291 51 31 1 + 292 50 30 0 + 293 50 30 1 + 294 50 31 0 + 295 50 31 1 + 296 48 31 1 + 297 48 31 0 + 298 48 30 1 + 299 48 30 0 + 300 49 31 1 + 301 49 31 0 + 302 49 30 1 + 303 49 30 0 + 304 52 30 0 + 305 52 30 1 + 306 52 31 0 + 307 52 31 1 + 308 53 30 0 + 309 53 30 1 + 310 53 31 0 + 311 53 31 1 + 312 55 31 1 + 313 55 31 0 + 314 55 30 1 + 315 55 30 0 + 316 54 31 1 + 317 54 31 0 + 318 54 30 1 + 319 54 30 0 + 320 60 31 0 + 321 60 31 1 + 322 60 30 0 + 323 60 30 1 + 324 61 31 0 + 325 61 31 1 + 326 61 30 0 + 327 61 30 1 + 328 63 30 1 + 329 63 30 0 + 330 63 31 1 + 331 63 31 0 + 332 62 30 1 + 333 62 30 0 + 334 62 31 1 + 335 62 31 0 + 384 59 33 0 + 385 59 33 1 + 386 59 32 0 + 387 59 32 1 + 388 58 33 0 + 389 58 33 1 + 390 58 32 0 + 391 58 32 1 + 392 56 32 1 + 393 56 32 0 + 394 56 33 1 + 395 56 33 0 + 396 57 32 1 + 397 57 32 0 + 398 57 33 1 + 399 57 33 0 + 416 51 32 0 + 417 51 32 1 + 418 51 33 0 + 419 51 33 1 + 420 50 32 0 + 421 50 32 1 + 422 50 33 0 + 423 50 33 1 + 424 48 33 1 + 425 48 33 0 + 426 48 32 1 + 427 48 32 0 + 428 49 33 1 + 429 49 33 0 + 430 49 32 1 + 431 49 32 0 + 432 52 32 0 + 433 52 32 1 + 434 52 33 0 + 435 52 33 1 + 436 53 32 0 + 437 53 32 1 + 438 53 33 0 + 439 53 33 1 + 440 55 33 1 + 441 55 33 0 + 442 55 32 1 + 443 55 32 0 + 444 54 33 1 + 445 54 33 0 + 446 54 32 1 + 447 54 32 0 + 448 60 33 0 + 449 60 33 1 + 450 60 32 0 + 451 60 32 1 + 452 61 33 0 + 453 61 33 1 + 454 61 32 0 + 455 61 32 1 + 456 63 32 1 + 457 63 32 0 + 458 63 33 1 + 459 63 33 0 + 460 62 32 1 + 461 62 32 0 + 462 62 33 1 + 463 62 33 0 + 512 59 35 0 + 513 59 35 1 + 514 59 34 0 + 515 59 34 1 + 516 58 35 0 + 517 58 35 1 + 518 58 34 0 + 519 58 34 1 + 520 56 34 1 + 521 56 34 0 + 522 56 35 1 + 523 56 35 0 + 524 57 34 1 + 525 57 34 0 + 526 57 35 1 + 527 57 35 0 + 544 51 34 0 + 545 51 34 1 + 546 51 35 0 + 547 51 35 1 + 548 50 34 0 + 549 50 34 1 + 550 50 35 0 + 551 50 35 1 + 552 48 35 1 + 553 48 35 0 + 554 48 34 1 + 555 48 34 0 + 556 49 35 1 + 557 49 35 0 + 558 49 34 1 + 559 49 34 0 + 560 52 34 0 + 561 52 34 1 + 562 52 35 0 + 563 52 35 1 + 564 53 34 0 + 565 53 34 1 + 566 53 35 0 + 567 53 35 1 + 568 55 35 1 + 569 55 35 0 + 570 55 34 1 + 571 55 34 0 + 572 54 35 1 + 573 54 35 0 + 574 54 34 1 + 575 54 34 0 + 576 60 35 0 + 577 60 35 1 + 578 60 34 0 + 579 60 34 1 + 580 61 35 0 + 581 61 35 1 + 582 61 34 0 + 583 61 34 1 + 584 63 34 1 + 585 63 34 0 + 586 63 35 1 + 587 63 35 0 + 588 62 34 1 + 589 62 34 0 + 590 62 35 1 + 591 62 35 0 + 640 59 37 0 + 641 59 37 1 + 642 59 36 0 + 643 59 36 1 + 644 58 37 0 + 645 58 37 1 + 646 58 36 0 + 647 58 36 1 + 648 56 36 1 + 649 56 36 0 + 650 56 37 1 + 651 56 37 0 + 652 57 36 1 + 653 57 36 0 + 654 57 37 1 + 655 57 37 0 + 672 51 36 0 + 673 51 36 1 + 674 51 37 0 + 675 51 37 1 + 676 50 36 0 + 677 50 36 1 + 678 50 37 0 + 679 50 37 1 + 680 48 37 1 + 681 48 37 0 + 682 48 36 1 + 683 48 36 0 + 684 49 37 1 + 685 49 37 0 + 686 49 36 1 + 687 49 36 0 + 688 52 36 0 + 689 52 36 1 + 690 52 37 0 + 691 52 37 1 + 692 53 36 0 + 693 53 36 1 + 694 53 37 0 + 695 53 37 1 + 696 55 37 1 + 697 55 37 0 + 698 55 36 1 + 699 55 36 0 + 700 54 37 1 + 701 54 37 0 + 702 54 36 1 + 703 54 36 0 + 704 60 37 0 + 705 60 37 1 + 706 60 36 0 + 707 60 36 1 + 708 61 37 0 + 709 61 37 1 + 710 61 36 0 + 711 61 36 1 + 712 63 36 1 + 713 63 36 0 + 714 63 37 1 + 715 63 37 0 + 716 62 36 1 + 717 62 36 0 + 718 62 37 1 + 719 62 37 0 + 768 59 39 0 + 769 59 39 1 + 770 59 38 0 + 771 59 38 1 + 772 58 39 0 + 773 58 39 1 + 774 58 38 0 + 775 58 38 1 + 776 56 38 1 + 777 56 38 0 + 778 56 39 1 + 779 56 39 0 + 780 57 38 1 + 781 57 38 0 + 782 57 39 1 + 783 57 39 0 + 800 51 38 0 + 801 51 38 1 + 802 51 39 0 + 803 51 39 1 + 804 50 38 0 + 805 50 38 1 + 806 50 39 0 + 807 50 39 1 + 808 48 39 1 + 809 48 39 0 + 810 48 38 1 + 811 48 38 0 + 812 49 39 1 + 813 49 39 0 + 814 49 38 1 + 815 49 38 0 + 816 52 38 0 + 817 52 38 1 + 818 52 39 0 + 819 52 39 1 + 820 53 38 0 + 821 53 38 1 + 822 53 39 0 + 823 53 39 1 + 824 55 39 1 + 825 55 39 0 + 826 55 38 1 + 827 55 38 0 + 828 54 39 1 + 829 54 39 0 + 830 54 38 1 + 831 54 38 0 + 832 60 39 0 + 833 60 39 1 + 834 60 38 0 + 835 60 38 1 + 836 61 39 0 + 837 61 39 1 + 838 61 38 0 + 839 61 38 1 + 840 63 38 1 + 841 63 38 0 + 842 63 39 1 + 843 63 39 0 + 844 62 38 1 + 845 62 38 0 + 846 62 39 1 + 847 62 39 0 + 896 59 41 0 + 897 59 41 1 + 898 59 40 0 + 899 59 40 1 + 900 58 41 0 + 901 58 41 1 + 902 58 40 0 + 903 58 40 1 + 904 56 40 1 + 905 56 40 0 + 906 56 41 1 + 907 56 41 0 + 908 57 40 1 + 909 57 40 0 + 910 57 41 1 + 911 57 41 0 + 928 51 40 0 + 929 51 40 1 + 930 51 41 0 + 931 51 41 1 + 932 50 40 0 + 933 50 40 1 + 934 50 41 0 + 935 50 41 1 + 936 48 41 1 + 937 48 41 0 + 938 48 40 1 + 939 48 40 0 + 940 49 41 1 + 941 49 41 0 + 942 49 40 1 + 943 49 40 0 + 944 52 40 0 + 945 52 40 1 + 946 52 41 0 + 947 52 41 1 + 948 53 40 0 + 949 53 40 1 + 950 53 41 0 + 951 53 41 1 + 952 55 41 1 + 953 55 41 0 + 954 55 40 1 + 955 55 40 0 + 956 54 41 1 + 957 54 41 0 + 958 54 40 1 + 959 54 40 0 + 960 60 41 0 + 961 60 41 1 + 962 60 40 0 + 963 60 40 1 + 964 61 41 0 + 965 61 41 1 + 966 61 40 0 + 967 61 40 1 + 968 63 40 1 + 969 63 40 0 + 970 63 41 1 + 971 63 41 0 + 972 62 40 1 + 973 62 40 0 + 974 62 41 1 + 975 62 41 0 +1024 59 43 0 +1025 59 43 1 +1026 59 42 0 +1027 59 42 1 +1028 58 43 0 +1029 58 43 1 +1030 58 42 0 +1031 58 42 1 +1032 56 42 1 +1033 56 42 0 +1034 56 43 1 +1035 56 43 0 +1036 57 42 1 +1037 57 42 0 +1038 57 43 1 +1039 57 43 0 +1056 51 42 0 +1057 51 42 1 +1058 51 43 0 +1059 51 43 1 +1060 50 42 0 +1061 50 42 1 +1062 50 43 0 +1063 50 43 1 +1064 48 43 1 +1065 48 43 0 +1066 48 42 1 +1067 48 42 0 +1068 49 43 1 +1069 49 43 0 +1070 49 42 1 +1071 49 42 0 +1072 52 42 0 +1073 52 42 1 +1074 52 43 0 +1075 52 43 1 +1076 53 42 0 +1077 53 42 1 +1078 53 43 0 +1079 53 43 1 +1080 55 43 1 +1081 55 43 0 +1082 55 42 1 +1083 55 42 0 +1084 54 43 1 +1085 54 43 0 +1086 54 42 1 +1087 54 42 0 +1088 60 43 0 +1089 60 43 1 +1090 60 42 0 +1091 60 42 1 +1092 61 43 0 +1093 61 43 1 +1094 61 42 0 +1095 61 42 1 +1096 63 42 1 +1097 63 42 0 +1098 63 43 1 +1099 63 43 0 +1100 62 42 1 +1101 62 42 0 +1102 62 43 1 +1103 62 43 0 +1152 59 45 0 +1153 59 45 1 +1154 59 44 0 +1155 59 44 1 +1156 58 45 0 +1157 58 45 1 +1158 58 44 0 +1159 58 44 1 +1160 56 44 1 +1161 56 44 0 +1162 56 45 1 +1163 56 45 0 +1164 57 44 1 +1165 57 44 0 +1166 57 45 1 +1167 57 45 0 +1184 51 44 0 +1185 51 44 1 +1186 51 45 0 +1187 51 45 1 +1188 50 44 0 +1189 50 44 1 +1190 50 45 0 +1191 50 45 1 +1192 48 45 1 +1193 48 45 0 +1194 48 44 1 +1195 48 44 0 +1196 49 45 1 +1197 49 45 0 +1198 49 44 1 +1199 49 44 0 +1200 52 44 0 +1201 52 44 1 +1202 52 45 0 +1203 52 45 1 +1204 53 44 0 +1205 53 44 1 +1206 53 45 0 +1207 53 45 1 +1208 55 45 1 +1209 55 45 0 +1210 55 44 1 +1211 55 44 0 +1212 54 45 1 +1213 54 45 0 +1214 54 44 1 +1215 54 44 0 +1216 60 45 0 +1217 60 45 1 +1218 60 44 0 +1219 60 44 1 +1220 61 45 0 +1221 61 45 1 +1222 61 44 0 +1223 61 44 1 +1224 63 44 1 +1225 63 44 0 +1226 63 45 1 +1227 63 45 0 +1228 62 44 1 +1229 62 44 0 +1230 62 45 1 +1231 62 45 0 +1280 59 47 0 +1281 59 47 1 +1282 59 46 0 +1283 59 46 1 +1284 58 47 0 +1285 58 47 1 +1286 58 46 0 +1287 58 46 1 +1288 56 46 1 +1289 56 46 0 +1290 56 47 1 +1291 56 47 0 +1292 57 46 1 +1293 57 46 0 +1294 57 47 1 +1295 57 47 0 +1312 51 46 0 +1313 51 46 1 +1314 51 47 0 +1315 51 47 1 +1316 50 46 0 +1317 50 46 1 +1318 50 47 0 +1319 50 47 1 +1320 48 47 1 +1321 48 47 0 +1322 48 46 1 +1323 48 46 0 +1324 49 47 1 +1325 49 47 0 +1326 49 46 1 +1327 49 46 0 +1328 52 46 0 +1329 52 46 1 +1330 52 47 0 +1331 52 47 1 +1332 53 46 0 +1333 53 46 1 +1334 53 47 0 +1335 53 47 1 +1336 55 47 1 +1337 55 47 0 +1338 55 46 1 +1339 55 46 0 +1340 54 47 1 +1341 54 47 0 +1342 54 46 1 +1343 54 46 0 +1344 60 47 0 +1345 60 47 1 +1346 60 46 0 +1347 60 46 1 +1348 61 47 0 +1349 61 47 1 +1350 61 46 0 +1351 61 46 1 +1352 63 46 1 +1353 63 46 0 +1354 63 47 1 +1355 63 47 0 +1356 62 46 1 +1357 62 46 0 +1358 62 47 1 +1359 62 47 0 +1408 59 49 0 +1409 59 49 1 +1410 59 48 0 +1411 59 48 1 +1412 58 49 0 +1413 58 49 1 +1414 58 48 0 +1415 58 48 1 +1416 56 48 1 +1417 56 48 0 +1418 56 49 1 +1419 56 49 0 +1420 57 48 1 +1421 57 48 0 +1422 57 49 1 +1423 57 49 0 +1440 51 48 0 +1441 51 48 1 +1442 51 49 0 +1443 51 49 1 +1444 50 48 0 +1445 50 48 1 +1446 50 49 0 +1447 50 49 1 +1448 48 49 1 +1449 48 49 0 +1450 48 48 1 +1451 48 48 0 +1452 49 49 1 +1453 49 49 0 +1454 49 48 1 +1455 49 48 0 +1456 52 48 0 +1457 52 48 1 +1458 52 49 0 +1459 52 49 1 +1460 53 48 0 +1461 53 48 1 +1462 53 49 0 +1463 53 49 1 +1464 55 49 1 +1465 55 49 0 +1466 55 48 1 +1467 55 48 0 +1468 54 49 1 +1469 54 49 0 +1470 54 48 1 +1471 54 48 0 +1472 60 49 0 +1473 60 49 1 +1474 60 48 0 +1475 60 48 1 +1476 61 49 0 +1477 61 49 1 +1478 61 48 0 +1479 61 48 1 +1480 63 48 1 +1481 63 48 0 +1482 63 49 1 +1483 63 49 0 +1484 62 48 1 +1485 62 48 0 +1486 62 49 1 +1487 62 49 0 +1536 59 51 0 +1537 59 51 1 +1538 59 50 0 +1539 59 50 1 +1540 58 51 0 +1541 58 51 1 +1542 58 50 0 +1543 58 50 1 +1544 56 50 1 +1545 56 50 0 +1546 56 51 1 +1547 56 51 0 +1548 57 50 1 +1549 57 50 0 +1550 57 51 1 +1551 57 51 0 +1568 51 50 0 +1569 51 50 1 +1570 51 51 0 +1571 51 51 1 +1572 50 50 0 +1573 50 50 1 +1574 50 51 0 +1575 50 51 1 +1576 48 51 1 +1577 48 51 0 +1578 48 50 1 +1579 48 50 0 +1580 49 51 1 +1581 49 51 0 +1582 49 50 1 +1583 49 50 0 +1584 52 50 0 +1585 52 50 1 +1586 52 51 0 +1587 52 51 1 +1588 53 50 0 +1589 53 50 1 +1590 53 51 0 +1591 53 51 1 +1592 55 51 1 +1593 55 51 0 +1594 55 50 1 +1595 55 50 0 +1596 54 51 1 +1597 54 51 0 +1598 54 50 1 +1599 54 50 0 +1600 60 51 0 +1601 60 51 1 +1602 60 50 0 +1603 60 50 1 +1604 61 51 0 +1605 61 51 1 +1606 61 50 0 +1607 61 50 1 +1608 63 50 1 +1609 63 50 0 +1610 63 51 1 +1611 63 51 0 +1612 62 50 1 +1613 62 50 0 +1614 62 51 1 +1615 62 51 0 +1664 59 53 0 +1665 59 53 1 +1666 59 52 0 +1667 59 52 1 +1668 58 53 0 +1669 58 53 1 +1670 58 52 0 +1671 58 52 1 +1672 56 52 1 +1673 56 52 0 +1674 56 53 1 +1675 56 53 0 +1676 57 52 1 +1677 57 52 0 +1678 57 53 1 +1679 57 53 0 +1696 51 52 0 +1697 51 52 1 +1698 51 53 0 +1699 51 53 1 +1700 50 52 0 +1701 50 52 1 +1702 50 53 0 +1703 50 53 1 +1704 48 53 1 +1705 48 53 0 +1706 48 52 1 +1707 48 52 0 +1708 49 53 1 +1709 49 53 0 +1710 49 52 1 +1711 49 52 0 +1712 52 52 0 +1713 52 52 1 +1714 52 53 0 +1715 52 53 1 +1716 53 52 0 +1717 53 52 1 +1718 53 53 0 +1719 53 53 1 +1720 55 53 1 +1721 55 53 0 +1722 55 52 1 +1723 55 52 0 +1724 54 53 1 +1725 54 53 0 +1726 54 52 1 +1727 54 52 0 +1728 60 53 0 +1729 60 53 1 +1730 60 52 0 +1731 60 52 1 +1732 61 53 0 +1733 61 53 1 +1734 61 52 0 +1735 61 52 1 +1736 63 52 1 +1737 63 52 0 +1738 63 53 1 +1739 63 53 0 +1740 62 52 1 +1741 62 52 0 +1742 62 53 1 +1743 62 53 0 +1792 59 55 0 +1793 59 55 1 +1794 59 54 0 +1795 59 54 1 +1796 58 55 0 +1797 58 55 1 +1798 58 54 0 +1799 58 54 1 +1800 56 54 1 +1801 56 54 0 +1802 56 55 1 +1803 56 55 0 +1804 57 54 1 +1805 57 54 0 +1806 57 55 1 +1807 57 55 0 +1824 51 54 0 +1825 51 54 1 +1826 51 55 0 +1827 51 55 1 +1828 50 54 0 +1829 50 54 1 +1830 50 55 0 +1831 50 55 1 +1832 48 55 1 +1833 48 55 0 +1834 48 54 1 +1835 48 54 0 +1836 49 55 1 +1837 49 55 0 +1838 49 54 1 +1839 49 54 0 +1840 52 54 0 +1841 52 54 1 +1842 52 55 0 +1843 52 55 1 +1844 53 54 0 +1845 53 54 1 +1846 53 55 0 +1847 53 55 1 +1848 55 55 1 +1849 55 55 0 +1850 55 54 1 +1851 55 54 0 +1852 54 55 1 +1853 54 55 0 +1854 54 54 1 +1855 54 54 0 +1856 60 55 0 +1857 60 55 1 +1858 60 54 0 +1859 60 54 1 +1860 61 55 0 +1861 61 55 1 +1862 61 54 0 +1863 61 54 1 +1864 63 54 1 +1865 63 54 0 +1866 63 55 1 +1867 63 55 0 +1868 62 54 1 +1869 62 54 0 +1870 62 55 1 +1871 62 55 0 +2176 59 27 0 +2177 59 27 1 +2178 59 26 0 +2179 59 26 1 +2180 58 27 0 +2181 58 27 1 +2182 58 26 0 +2183 58 26 1 +2184 56 26 1 +2185 56 26 0 +2186 56 27 1 +2187 56 27 0 +2188 57 26 1 +2189 57 26 0 +2190 57 27 1 +2191 57 27 0 +2208 51 26 0 +2209 51 26 1 +2210 51 27 0 +2211 51 27 1 +2212 50 26 0 +2213 50 26 1 +2214 50 27 0 +2215 50 27 1 +2216 48 27 1 +2217 48 27 0 +2218 48 26 1 +2219 48 26 0 +2220 49 27 1 +2221 49 27 0 +2222 49 26 1 +2223 49 26 0 +2224 52 26 0 +2225 52 26 1 +2226 52 27 0 +2227 52 27 1 +2228 53 26 0 +2229 53 26 1 +2230 53 27 0 +2231 53 27 1 +2232 55 27 1 +2233 55 27 0 +2234 55 26 1 +2235 55 26 0 +2236 54 27 1 +2237 54 27 0 +2238 54 26 1 +2239 54 26 0 +2240 60 27 0 +2241 60 27 1 +2242 60 26 0 +2243 60 26 1 +2244 61 27 0 +2245 61 27 1 +2246 61 26 0 +2247 61 26 1 +2248 63 26 1 +2249 63 26 0 +2250 63 27 1 +2251 63 27 0 +2252 62 26 1 +2253 62 26 0 +2254 62 27 1 +2255 62 27 0 +2304 59 25 0 +2305 59 25 1 +2306 59 24 0 +2307 59 24 1 +2308 58 25 0 +2309 58 25 1 +2310 58 24 0 +2311 58 24 1 +2312 56 24 1 +2313 56 24 0 +2314 56 25 1 +2315 56 25 0 +2316 57 24 1 +2317 57 24 0 +2318 57 25 1 +2319 57 25 0 +2336 51 24 0 +2337 51 24 1 +2338 51 25 0 +2339 51 25 1 +2340 50 24 0 +2341 50 24 1 +2342 50 25 0 +2343 50 25 1 +2344 48 25 1 +2345 48 25 0 +2346 48 24 1 +2347 48 24 0 +2348 49 25 1 +2349 49 25 0 +2350 49 24 1 +2351 49 24 0 +2352 52 24 0 +2353 52 24 1 +2354 52 25 0 +2355 52 25 1 +2356 53 24 0 +2357 53 24 1 +2358 53 25 0 +2359 53 25 1 +2360 55 25 1 +2361 55 25 0 +2362 55 24 1 +2363 55 24 0 +2364 54 25 1 +2365 54 25 0 +2366 54 24 1 +2367 54 24 0 +2368 60 25 0 +2369 60 25 1 +2370 60 24 0 +2371 60 24 1 +2372 61 25 0 +2373 61 25 1 +2374 61 24 0 +2375 61 24 1 +2376 63 24 1 +2377 63 24 0 +2378 63 25 1 +2379 63 25 0 +2380 62 24 1 +2381 62 24 0 +2382 62 25 1 +2383 62 25 0 +2432 59 23 0 +2433 59 23 1 +2434 59 22 0 +2435 59 22 1 +2436 58 23 0 +2437 58 23 1 +2438 58 22 0 +2439 58 22 1 +2440 56 22 1 +2441 56 22 0 +2442 56 23 1 +2443 56 23 0 +2444 57 22 1 +2445 57 22 0 +2446 57 23 1 +2447 57 23 0 +2464 51 22 0 +2465 51 22 1 +2466 51 23 0 +2467 51 23 1 +2468 50 22 0 +2469 50 22 1 +2470 50 23 0 +2471 50 23 1 +2472 48 23 1 +2473 48 23 0 +2474 48 22 1 +2475 48 22 0 +2476 49 23 1 +2477 49 23 0 +2478 49 22 1 +2479 49 22 0 +2480 52 22 0 +2481 52 22 1 +2482 52 23 0 +2483 52 23 1 +2484 53 22 0 +2485 53 22 1 +2486 53 23 0 +2487 53 23 1 +2488 55 23 1 +2489 55 23 0 +2490 55 22 1 +2491 55 22 0 +2492 54 23 1 +2493 54 23 0 +2494 54 22 1 +2495 54 22 0 +2496 60 23 0 +2497 60 23 1 +2498 60 22 0 +2499 60 22 1 +2500 61 23 0 +2501 61 23 1 +2502 61 22 0 +2503 61 22 1 +2504 63 22 1 +2505 63 22 0 +2506 63 23 1 +2507 63 23 0 +2508 62 22 1 +2509 62 22 0 +2510 62 23 1 +2511 62 23 0 +2560 59 21 0 +2561 59 21 1 +2562 59 20 0 +2563 59 20 1 +2564 58 21 0 +2565 58 21 1 +2566 58 20 0 +2567 58 20 1 +2568 56 20 1 +2569 56 20 0 +2570 56 21 1 +2571 56 21 0 +2572 57 20 1 +2573 57 20 0 +2574 57 21 1 +2575 57 21 0 +2592 51 20 0 +2593 51 20 1 +2594 51 21 0 +2595 51 21 1 +2596 50 20 0 +2597 50 20 1 +2598 50 21 0 +2599 50 21 1 +2600 48 21 1 +2601 48 21 0 +2602 48 20 1 +2603 48 20 0 +2604 49 21 1 +2605 49 21 0 +2606 49 20 1 +2607 49 20 0 +2608 52 20 0 +2609 52 20 1 +2610 52 21 0 +2611 52 21 1 +2612 53 20 0 +2613 53 20 1 +2614 53 21 0 +2615 53 21 1 +2616 55 21 1 +2617 55 21 0 +2618 55 20 1 +2619 55 20 0 +2620 54 21 1 +2621 54 21 0 +2622 54 20 1 +2623 54 20 0 +2624 60 21 0 +2625 60 21 1 +2626 60 20 0 +2627 60 20 1 +2628 61 21 0 +2629 61 21 1 +2630 61 20 0 +2631 61 20 1 +2632 63 20 1 +2633 63 20 0 +2634 63 21 1 +2635 63 21 0 +2636 62 20 1 +2637 62 20 0 +2638 62 21 1 +2639 62 21 0 +2688 59 19 0 +2689 59 19 1 +2690 59 18 0 +2691 59 18 1 +2692 58 19 0 +2693 58 19 1 +2694 58 18 0 +2695 58 18 1 +2696 56 18 1 +2697 56 18 0 +2698 56 19 1 +2699 56 19 0 +2700 57 18 1 +2701 57 18 0 +2702 57 19 1 +2703 57 19 0 +2720 51 18 0 +2721 51 18 1 +2722 51 19 0 +2723 51 19 1 +2724 50 18 0 +2725 50 18 1 +2726 50 19 0 +2727 50 19 1 +2728 48 19 1 +2729 48 19 0 +2730 48 18 1 +2731 48 18 0 +2732 49 19 1 +2733 49 19 0 +2734 49 18 1 +2735 49 18 0 +2736 52 18 0 +2737 52 18 1 +2738 52 19 0 +2739 52 19 1 +2740 53 18 0 +2741 53 18 1 +2742 53 19 0 +2743 53 19 1 +2744 55 19 1 +2745 55 19 0 +2746 55 18 1 +2747 55 18 0 +2748 54 19 1 +2749 54 19 0 +2750 54 18 1 +2751 54 18 0 +2752 60 19 0 +2753 60 19 1 +2754 60 18 0 +2755 60 18 1 +2756 61 19 0 +2757 61 19 1 +2758 61 18 0 +2759 61 18 1 +2760 63 18 1 +2761 63 18 0 +2762 63 19 1 +2763 63 19 0 +2764 62 18 1 +2765 62 18 0 +2766 62 19 1 +2767 62 19 0 +2816 59 17 0 +2817 59 17 1 +2818 59 16 0 +2819 59 16 1 +2820 58 17 0 +2821 58 17 1 +2822 58 16 0 +2823 58 16 1 +2824 56 16 1 +2825 56 16 0 +2826 56 17 1 +2827 56 17 0 +2828 57 16 1 +2829 57 16 0 +2830 57 17 1 +2831 57 17 0 +2848 51 16 0 +2849 51 16 1 +2850 51 17 0 +2851 51 17 1 +2852 50 16 0 +2853 50 16 1 +2854 50 17 0 +2855 50 17 1 +2856 48 17 1 +2857 48 17 0 +2858 48 16 1 +2859 48 16 0 +2860 49 17 1 +2861 49 17 0 +2862 49 16 1 +2863 49 16 0 +2864 52 16 0 +2865 52 16 1 +2866 52 17 0 +2867 52 17 1 +2868 53 16 0 +2869 53 16 1 +2870 53 17 0 +2871 53 17 1 +2872 55 17 1 +2873 55 17 0 +2874 55 16 1 +2875 55 16 0 +2876 54 17 1 +2877 54 17 0 +2878 54 16 1 +2879 54 16 0 +2880 60 17 0 +2881 60 17 1 +2882 60 16 0 +2883 60 16 1 +2884 61 17 0 +2885 61 17 1 +2886 61 16 0 +2887 61 16 1 +2888 63 16 1 +2889 63 16 0 +2890 63 17 1 +2891 63 17 0 +2892 62 16 1 +2893 62 16 0 +2894 62 17 1 +2895 62 17 0 +2944 59 15 0 +2945 59 15 1 +2946 59 14 0 +2947 59 14 1 +2948 58 15 0 +2949 58 15 1 +2950 58 14 0 +2951 58 14 1 +2952 56 14 1 +2953 56 14 0 +2954 56 15 1 +2955 56 15 0 +2956 57 14 1 +2957 57 14 0 +2958 57 15 1 +2959 57 15 0 +2976 51 14 0 +2977 51 14 1 +2978 51 15 0 +2979 51 15 1 +2980 50 14 0 +2981 50 14 1 +2982 50 15 0 +2983 50 15 1 +2984 48 15 1 +2985 48 15 0 +2986 48 14 1 +2987 48 14 0 +2988 49 15 1 +2989 49 15 0 +2990 49 14 1 +2991 49 14 0 +2992 52 14 0 +2993 52 14 1 +2994 52 15 0 +2995 52 15 1 +2996 53 14 0 +2997 53 14 1 +2998 53 15 0 +2999 53 15 1 +3000 55 15 1 +3001 55 15 0 +3002 55 14 1 +3003 55 14 0 +3004 54 15 1 +3005 54 15 0 +3006 54 14 1 +3007 54 14 0 +3008 60 15 0 +3009 60 15 1 +3010 60 14 0 +3011 60 14 1 +3012 61 15 0 +3013 61 15 1 +3014 61 14 0 +3015 61 14 1 +3016 63 14 1 +3017 63 14 0 +3018 63 15 1 +3019 63 15 0 +3020 62 14 1 +3021 62 14 0 +3022 62 15 1 +3023 62 15 0 +3072 59 13 0 +3073 59 13 1 +3074 59 12 0 +3075 59 12 1 +3076 58 13 0 +3077 58 13 1 +3078 58 12 0 +3079 58 12 1 +3080 56 12 1 +3081 56 12 0 +3082 56 13 1 +3083 56 13 0 +3084 57 12 1 +3085 57 12 0 +3086 57 13 1 +3087 57 13 0 +3104 51 12 0 +3105 51 12 1 +3106 51 13 0 +3107 51 13 1 +3108 50 12 0 +3109 50 12 1 +3110 50 13 0 +3111 50 13 1 +3112 48 13 1 +3113 48 13 0 +3114 48 12 1 +3115 48 12 0 +3116 49 13 1 +3117 49 13 0 +3118 49 12 1 +3119 49 12 0 +3120 52 12 0 +3121 52 12 1 +3122 52 13 0 +3123 52 13 1 +3124 53 12 0 +3125 53 12 1 +3126 53 13 0 +3127 53 13 1 +3128 55 13 1 +3129 55 13 0 +3130 55 12 1 +3131 55 12 0 +3132 54 13 1 +3133 54 13 0 +3134 54 12 1 +3135 54 12 0 +3136 60 13 0 +3137 60 13 1 +3138 60 12 0 +3139 60 12 1 +3140 61 13 0 +3141 61 13 1 +3142 61 12 0 +3143 61 12 1 +3144 63 12 1 +3145 63 12 0 +3146 63 13 1 +3147 63 13 0 +3148 62 12 1 +3149 62 12 0 +3150 62 13 1 +3151 62 13 0 +3200 59 11 0 +3201 59 11 1 +3202 59 10 0 +3203 59 10 1 +3204 58 11 0 +3205 58 11 1 +3206 58 10 0 +3207 58 10 1 +3208 56 10 1 +3209 56 10 0 +3210 56 11 1 +3211 56 11 0 +3212 57 10 1 +3213 57 10 0 +3214 57 11 1 +3215 57 11 0 +3232 51 10 0 +3233 51 10 1 +3234 51 11 0 +3235 51 11 1 +3236 50 10 0 +3237 50 10 1 +3238 50 11 0 +3239 50 11 1 +3240 48 11 1 +3241 48 11 0 +3242 48 10 1 +3243 48 10 0 +3244 49 11 1 +3245 49 11 0 +3246 49 10 1 +3247 49 10 0 +3248 52 10 0 +3249 52 10 1 +3250 52 11 0 +3251 52 11 1 +3252 53 10 0 +3253 53 10 1 +3254 53 11 0 +3255 53 11 1 +3256 55 11 1 +3257 55 11 0 +3258 55 10 1 +3259 55 10 0 +3260 54 11 1 +3261 54 11 0 +3262 54 10 1 +3263 54 10 0 +3264 60 11 0 +3265 60 11 1 +3266 60 10 0 +3267 60 10 1 +3268 61 11 0 +3269 61 11 1 +3270 61 10 0 +3271 61 10 1 +3272 63 10 1 +3273 63 10 0 +3274 63 11 1 +3275 63 11 0 +3276 62 10 1 +3277 62 10 0 +3278 62 11 1 +3279 62 11 0 +3328 59 9 0 +3329 59 9 1 +3330 59 8 0 +3331 59 8 1 +3332 58 9 0 +3333 58 9 1 +3334 58 8 0 +3335 58 8 1 +3336 56 8 1 +3337 56 8 0 +3338 56 9 1 +3339 56 9 0 +3340 57 8 1 +3341 57 8 0 +3342 57 9 1 +3343 57 9 0 +3360 51 8 0 +3361 51 8 1 +3362 51 9 0 +3363 51 9 1 +3364 50 8 0 +3365 50 8 1 +3366 50 9 0 +3367 50 9 1 +3368 48 9 1 +3369 48 9 0 +3370 48 8 1 +3371 48 8 0 +3372 49 9 1 +3373 49 9 0 +3374 49 8 1 +3375 49 8 0 +3376 52 8 0 +3377 52 8 1 +3378 52 9 0 +3379 52 9 1 +3380 53 8 0 +3381 53 8 1 +3382 53 9 0 +3383 53 9 1 +3384 55 9 1 +3385 55 9 0 +3386 55 8 1 +3387 55 8 0 +3388 54 9 1 +3389 54 9 0 +3390 54 8 1 +3391 54 8 0 +3392 60 9 0 +3393 60 9 1 +3394 60 8 0 +3395 60 8 1 +3396 61 9 0 +3397 61 9 1 +3398 61 8 0 +3399 61 8 1 +3400 63 8 1 +3401 63 8 0 +3402 63 9 1 +3403 63 9 0 +3404 62 8 1 +3405 62 8 0 +3406 62 9 1 +3407 62 9 0 +3456 59 7 0 +3457 59 7 1 +3458 59 6 0 +3459 59 6 1 +3460 58 7 0 +3461 58 7 1 +3462 58 6 0 +3463 58 6 1 +3464 56 6 1 +3465 56 6 0 +3466 56 7 1 +3467 56 7 0 +3468 57 6 1 +3469 57 6 0 +3470 57 7 1 +3471 57 7 0 +3488 51 6 0 +3489 51 6 1 +3490 51 7 0 +3491 51 7 1 +3492 50 6 0 +3493 50 6 1 +3494 50 7 0 +3495 50 7 1 +3496 48 7 1 +3497 48 7 0 +3498 48 6 1 +3499 48 6 0 +3500 49 7 1 +3501 49 7 0 +3502 49 6 1 +3503 49 6 0 +3504 52 6 0 +3505 52 6 1 +3506 52 7 0 +3507 52 7 1 +3508 53 6 0 +3509 53 6 1 +3510 53 7 0 +3511 53 7 1 +3512 55 7 1 +3513 55 7 0 +3514 55 6 1 +3515 55 6 0 +3516 54 7 1 +3517 54 7 0 +3518 54 6 1 +3519 54 6 0 +3520 60 7 0 +3521 60 7 1 +3522 60 6 0 +3523 60 6 1 +3524 61 7 0 +3525 61 7 1 +3526 61 6 0 +3527 61 6 1 +3528 63 6 1 +3529 63 6 0 +3530 63 7 1 +3531 63 7 0 +3532 62 6 1 +3533 62 6 0 +3534 62 7 1 +3535 62 7 0 +3584 59 5 0 +3585 59 5 1 +3586 59 4 0 +3587 59 4 1 +3588 58 5 0 +3589 58 5 1 +3590 58 4 0 +3591 58 4 1 +3592 56 4 1 +3593 56 4 0 +3594 56 5 1 +3595 56 5 0 +3596 57 4 1 +3597 57 4 0 +3598 57 5 1 +3599 57 5 0 +3616 51 4 0 +3617 51 4 1 +3618 51 5 0 +3619 51 5 1 +3620 50 4 0 +3621 50 4 1 +3622 50 5 0 +3623 50 5 1 +3624 48 5 1 +3625 48 5 0 +3626 48 4 1 +3627 48 4 0 +3628 49 5 1 +3629 49 5 0 +3630 49 4 1 +3631 49 4 0 +3632 52 4 0 +3633 52 4 1 +3634 52 5 0 +3635 52 5 1 +3636 53 4 0 +3637 53 4 1 +3638 53 5 0 +3639 53 5 1 +3640 55 5 1 +3641 55 5 0 +3642 55 4 1 +3643 55 4 0 +3644 54 5 1 +3645 54 5 0 +3646 54 4 1 +3647 54 4 0 +3648 60 5 0 +3649 60 5 1 +3650 60 4 0 +3651 60 4 1 +3652 61 5 0 +3653 61 5 1 +3654 61 4 0 +3655 61 4 1 +3656 63 4 1 +3657 63 4 0 +3658 63 5 1 +3659 63 5 0 +3660 62 4 1 +3661 62 4 0 +3662 62 5 1 +3663 62 5 0 +3712 59 3 0 +3713 59 3 1 +3714 59 2 0 +3715 59 2 1 +3716 58 3 0 +3717 58 3 1 +3718 58 2 0 +3719 58 2 1 +3720 56 2 1 +3721 56 2 0 +3722 56 3 1 +3723 56 3 0 +3724 57 2 1 +3725 57 2 0 +3726 57 3 1 +3727 57 3 0 +3744 51 2 0 +3745 51 2 1 +3746 51 3 0 +3747 51 3 1 +3748 50 2 0 +3749 50 2 1 +3750 50 3 0 +3751 50 3 1 +3752 48 3 1 +3753 48 3 0 +3754 48 2 1 +3755 48 2 0 +3756 49 3 1 +3757 49 3 0 +3758 49 2 1 +3759 49 2 0 +3760 52 2 0 +3761 52 2 1 +3762 52 3 0 +3763 52 3 1 +3764 53 2 0 +3765 53 2 1 +3766 53 3 0 +3767 53 3 1 +3768 55 3 1 +3769 55 3 0 +3770 55 2 1 +3771 55 2 0 +3772 54 3 1 +3773 54 3 0 +3774 54 2 1 +3775 54 2 0 +3776 60 3 0 +3777 60 3 1 +3778 60 2 0 +3779 60 2 1 +3780 61 3 0 +3781 61 3 1 +3782 61 2 0 +3783 61 2 1 +3784 63 2 1 +3785 63 2 0 +3786 63 3 1 +3787 63 3 0 +3788 62 2 1 +3789 62 2 0 +3790 62 3 1 +3791 62 3 0 +3840 59 1 0 +3841 59 1 1 +3842 59 0 0 +3843 59 0 1 +3844 58 1 0 +3845 58 1 1 +3846 58 0 0 +3847 58 0 1 +3848 56 0 1 +3849 56 0 0 +3850 56 1 1 +3851 56 1 0 +3852 57 0 1 +3853 57 0 0 +3854 57 1 1 +3855 57 1 0 +3872 51 0 0 +3873 51 0 1 +3874 51 1 0 +3875 51 1 1 +3876 50 0 0 +3877 50 0 1 +3878 50 1 0 +3879 50 1 1 +3880 48 1 1 +3881 48 1 0 +3882 48 0 1 +3883 48 0 0 +3884 49 1 1 +3885 49 1 0 +3886 49 0 1 +3887 49 0 0 +3888 52 0 0 +3889 52 0 1 +3890 52 1 0 +3891 52 1 1 +3892 53 0 0 +3893 53 0 1 +3894 53 1 0 +3895 53 1 1 +3896 55 1 1 +3897 55 1 0 +3898 55 0 1 +3899 55 0 0 +3900 54 1 1 +3901 54 1 0 +3902 54 0 1 +3903 54 0 0 +3904 60 1 0 +3905 60 1 1 +3906 60 0 0 +3907 60 0 1 +3908 61 1 0 +3909 61 1 1 +3910 61 0 0 +3911 61 0 1 +3912 63 0 1 +3913 63 0 0 +3914 63 1 1 +3915 63 1 0 +3916 62 0 1 +3917 62 0 0 +3918 62 1 1 +3919 62 1 0 diff --git a/Detectors/PHOS/base/files/Mod3RCU0.data b/Detectors/PHOS/base/files/Mod3RCU0.data new file mode 100644 index 0000000000000..4739df6e3e61e --- /dev/null +++ b/Detectors/PHOS/base/files/Mod3RCU0.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 0 0 2 + 1 0 1 2 + 2 0 2 2 + 3 0 3 2 + 4 0 4 2 + 5 0 5 2 + 6 0 6 2 + 7 0 7 2 + 8 0 8 2 + 9 0 9 2 + 10 0 10 2 + 11 0 11 2 + 12 0 12 2 + 13 0 13 2 + 14 0 14 2 + 15 0 15 2 + 16 0 16 2 + 17 0 17 2 + 18 0 18 2 + 19 0 19 2 + 20 0 20 2 + 21 0 21 2 + 22 0 22 2 + 23 0 23 2 + 24 0 24 2 + 25 0 25 2 + 26 0 26 2 + 27 0 27 2 + 28 0 28 2 + 29 0 29 2 + 30 0 30 2 + 31 0 31 2 + 32 0 32 2 + 33 0 33 2 + 34 0 34 2 + 35 0 35 2 + 36 0 36 2 + 37 0 37 2 + 38 0 38 2 + 39 0 39 2 + 40 0 40 2 + 41 0 41 2 + 42 0 42 2 + 43 0 43 2 + 44 0 44 2 + 45 0 45 2 + 46 0 46 2 + 47 0 47 2 + 48 0 48 2 + 49 0 49 2 + 50 0 50 2 + 51 0 51 2 + 52 0 52 2 + 53 0 53 2 + 54 0 54 2 + 55 0 55 2 + 56 0 56 2 + 57 0 57 2 + 58 0 58 2 + 59 0 59 2 + 60 0 60 2 + 61 0 61 2 + 62 0 62 2 + 63 0 63 2 + 64 0 64 2 + 65 0 65 2 + 66 0 66 2 + 67 0 67 2 + 68 0 68 2 + 69 0 69 2 + 70 0 70 2 + 71 0 71 2 + 72 0 72 2 + 73 0 73 2 + 74 0 74 2 + 75 0 75 2 + 76 0 76 2 + 77 0 77 2 + 78 0 78 2 + 79 0 79 2 + 80 0 80 2 + 81 0 81 2 + 82 0 82 2 + 83 0 83 2 + 84 0 84 2 + 85 0 85 2 + 86 0 86 2 + 87 0 87 2 + 88 0 88 2 + 89 0 89 2 + 90 0 90 2 + 91 0 91 2 + 92 0 92 2 + 93 0 93 2 + 94 0 94 2 + 95 0 95 2 + 96 0 96 2 + 97 0 97 2 + 98 0 98 2 + 99 0 99 2 + 100 0 100 2 + 101 0 101 2 + 102 0 102 2 + 103 0 103 2 + 104 0 104 2 + 105 0 105 2 + 106 0 106 2 + 107 0 107 2 + 108 0 108 2 + 109 0 109 2 + 110 0 110 2 + 111 0 111 2 + 112 0 112 2 + 113 0 113 2 + 114 0 114 2 + 115 0 115 2 + 116 0 116 2 + 117 0 117 2 + 118 0 118 2 + 119 0 119 2 + 120 0 120 2 + 121 0 121 2 + 122 0 122 2 + 123 0 123 2 + 124 0 124 2 + 125 0 125 2 + 126 0 126 2 + 127 0 127 2 +2048 0 2048 2 +2049 0 2049 2 +2050 0 2050 2 +2051 0 2051 2 +2052 0 2052 2 +2053 0 2053 2 +2054 0 2054 2 +2055 0 2055 2 +2056 0 2056 2 +2057 0 2057 2 +2058 0 2058 2 +2059 0 2059 2 +2060 0 2060 2 +2061 0 2061 2 +2062 0 2062 2 +2063 0 2063 2 +2064 0 2064 2 +2065 0 2065 2 +2066 0 2066 2 +2067 0 2067 2 +2068 0 2068 2 +2069 0 2069 2 +2070 0 2070 2 +2071 0 2071 2 +2072 0 2072 2 +2073 0 2073 2 +2074 0 2074 2 +2075 0 2075 2 +2076 0 2076 2 +2077 0 2077 2 +2078 0 2078 2 +2079 0 2079 2 +2080 0 2080 2 +2081 0 2081 2 +2082 0 2082 2 +2083 0 2083 2 +2084 0 2084 2 +2085 0 2085 2 +2086 0 2086 2 +2087 0 2087 2 +2088 0 2088 2 +2089 0 2089 2 +2090 0 2090 2 +2091 0 2091 2 +2092 0 2092 2 +2093 0 2093 2 +2094 0 2094 2 +2095 0 2095 2 +2096 0 2096 2 +2097 0 2097 2 +2098 0 2098 2 +2099 0 2099 2 +2100 0 2100 2 +2101 0 2101 2 +2102 0 2102 2 +2103 0 2103 2 +2104 0 2104 2 +2105 0 2105 2 +2106 0 2106 2 +2107 0 2107 2 +2108 0 2108 2 +2109 0 2109 2 +2110 0 2110 2 +2111 0 2111 2 +2112 0 2112 2 +2113 0 2113 2 +2114 0 2114 2 +2115 0 2115 2 +2116 0 2116 2 +2117 0 2117 2 +2118 0 2118 2 +2119 0 2119 2 +2120 0 2120 2 +2121 0 2121 2 +2122 0 2122 2 +2123 0 2123 2 +2124 0 2124 2 +2125 0 2125 2 +2126 0 2126 2 +2127 0 2127 2 +2128 0 2128 2 +2129 0 2129 2 +2130 0 2130 2 +2131 0 2131 2 +2132 0 2132 2 +2133 0 2133 2 +2134 0 2134 2 +2135 0 2135 2 +2136 0 2136 2 +2137 0 2137 2 +2138 0 2138 2 +2139 0 2139 2 +2140 0 2140 2 +2141 0 2141 2 +2142 0 2142 2 +2143 0 2143 2 +2144 0 2144 2 +2145 0 2145 2 +2146 0 2146 2 +2147 0 2147 2 +2148 0 2148 2 +2149 0 2149 2 +2150 0 2150 2 +2151 0 2151 2 +2152 0 2152 2 +2153 0 2153 2 +2154 0 2154 2 +2155 0 2155 2 +2156 0 2156 2 +2157 0 2157 2 +2158 0 2158 2 +2159 0 2159 2 +2160 0 2160 2 +2161 0 2161 2 +2162 0 2162 2 +2163 0 2163 2 +2164 0 2164 2 +2165 0 2165 2 +2166 0 2166 2 +2167 0 2167 2 +2168 0 2168 2 +2169 0 2169 2 +2170 0 2170 2 +2171 0 2171 2 +2172 0 2172 2 +2173 0 2173 2 +2174 0 2174 2 +2175 0 2175 2 + 128 11 29 0 + 129 11 29 1 + 130 11 28 0 + 131 11 28 1 + 132 10 29 0 + 133 10 29 1 + 134 10 28 0 + 135 10 28 1 + 136 8 28 1 + 137 8 28 0 + 138 8 29 1 + 139 8 29 0 + 140 9 28 1 + 141 9 28 0 + 142 9 29 1 + 143 9 29 0 + 160 3 28 0 + 161 3 28 1 + 162 3 29 0 + 163 3 29 1 + 164 2 28 0 + 165 2 28 1 + 166 2 29 0 + 167 2 29 1 + 168 0 29 1 + 169 0 29 0 + 170 0 28 1 + 171 0 28 0 + 172 1 29 1 + 173 1 29 0 + 174 1 28 1 + 175 1 28 0 + 176 4 28 0 + 177 4 28 1 + 178 4 29 0 + 179 4 29 1 + 180 5 28 0 + 181 5 28 1 + 182 5 29 0 + 183 5 29 1 + 184 7 29 1 + 185 7 29 0 + 186 7 28 1 + 187 7 28 0 + 188 6 29 1 + 189 6 29 0 + 190 6 28 1 + 191 6 28 0 + 192 12 29 0 + 193 12 29 1 + 194 12 28 0 + 195 12 28 1 + 196 13 29 0 + 197 13 29 1 + 198 13 28 0 + 199 13 28 1 + 200 15 28 1 + 201 15 28 0 + 202 15 29 1 + 203 15 29 0 + 204 14 28 1 + 205 14 28 0 + 206 14 29 1 + 207 14 29 0 + 256 11 31 0 + 257 11 31 1 + 258 11 30 0 + 259 11 30 1 + 260 10 31 0 + 261 10 31 1 + 262 10 30 0 + 263 10 30 1 + 264 8 30 1 + 265 8 30 0 + 266 8 31 1 + 267 8 31 0 + 268 9 30 1 + 269 9 30 0 + 270 9 31 1 + 271 9 31 0 + 288 3 30 0 + 289 3 30 1 + 290 3 31 0 + 291 3 31 1 + 292 2 30 0 + 293 2 30 1 + 294 2 31 0 + 295 2 31 1 + 296 0 31 1 + 297 0 31 0 + 298 0 30 1 + 299 0 30 0 + 300 1 31 1 + 301 1 31 0 + 302 1 30 1 + 303 1 30 0 + 304 4 30 0 + 305 4 30 1 + 306 4 31 0 + 307 4 31 1 + 308 5 30 0 + 309 5 30 1 + 310 5 31 0 + 311 5 31 1 + 312 7 31 1 + 313 7 31 0 + 314 7 30 1 + 315 7 30 0 + 316 6 31 1 + 317 6 31 0 + 318 6 30 1 + 319 6 30 0 + 320 12 31 0 + 321 12 31 1 + 322 12 30 0 + 323 12 30 1 + 324 13 31 0 + 325 13 31 1 + 326 13 30 0 + 327 13 30 1 + 328 15 30 1 + 329 15 30 0 + 330 15 31 1 + 331 15 31 0 + 332 14 30 1 + 333 14 30 0 + 334 14 31 1 + 335 14 31 0 + 384 11 33 0 + 385 11 33 1 + 386 11 32 0 + 387 11 32 1 + 388 10 33 0 + 389 10 33 1 + 390 10 32 0 + 391 10 32 1 + 392 8 32 1 + 393 8 32 0 + 394 8 33 1 + 395 8 33 0 + 396 9 32 1 + 397 9 32 0 + 398 9 33 1 + 399 9 33 0 + 416 3 32 0 + 417 3 32 1 + 418 3 33 0 + 419 3 33 1 + 420 2 32 0 + 421 2 32 1 + 422 2 33 0 + 423 2 33 1 + 424 0 33 1 + 425 0 33 0 + 426 0 32 1 + 427 0 32 0 + 428 1 33 1 + 429 1 33 0 + 430 1 32 1 + 431 1 32 0 + 432 4 32 0 + 433 4 32 1 + 434 4 33 0 + 435 4 33 1 + 436 5 32 0 + 437 5 32 1 + 438 5 33 0 + 439 5 33 1 + 440 7 33 1 + 441 7 33 0 + 442 7 32 1 + 443 7 32 0 + 444 6 33 1 + 445 6 33 0 + 446 6 32 1 + 447 6 32 0 + 448 12 33 0 + 449 12 33 1 + 450 12 32 0 + 451 12 32 1 + 452 13 33 0 + 453 13 33 1 + 454 13 32 0 + 455 13 32 1 + 456 15 32 1 + 457 15 32 0 + 458 15 33 1 + 459 15 33 0 + 460 14 32 1 + 461 14 32 0 + 462 14 33 1 + 463 14 33 0 + 512 11 35 0 + 513 11 35 1 + 514 11 34 0 + 515 11 34 1 + 516 10 35 0 + 517 10 35 1 + 518 10 34 0 + 519 10 34 1 + 520 8 34 1 + 521 8 34 0 + 522 8 35 1 + 523 8 35 0 + 524 9 34 1 + 525 9 34 0 + 526 9 35 1 + 527 9 35 0 + 544 3 34 0 + 545 3 34 1 + 546 3 35 0 + 547 3 35 1 + 548 2 34 0 + 549 2 34 1 + 550 2 35 0 + 551 2 35 1 + 552 0 35 1 + 553 0 35 0 + 554 0 34 1 + 555 0 34 0 + 556 1 35 1 + 557 1 35 0 + 558 1 34 1 + 559 1 34 0 + 560 4 34 0 + 561 4 34 1 + 562 4 35 0 + 563 4 35 1 + 564 5 34 0 + 565 5 34 1 + 566 5 35 0 + 567 5 35 1 + 568 7 35 1 + 569 7 35 0 + 570 7 34 1 + 571 7 34 0 + 572 6 35 1 + 573 6 35 0 + 574 6 34 1 + 575 6 34 0 + 576 12 35 0 + 577 12 35 1 + 578 12 34 0 + 579 12 34 1 + 580 13 35 0 + 581 13 35 1 + 582 13 34 0 + 583 13 34 1 + 584 15 34 1 + 585 15 34 0 + 586 15 35 1 + 587 15 35 0 + 588 14 34 1 + 589 14 34 0 + 590 14 35 1 + 591 14 35 0 + 640 11 37 0 + 641 11 37 1 + 642 11 36 0 + 643 11 36 1 + 644 10 37 0 + 645 10 37 1 + 646 10 36 0 + 647 10 36 1 + 648 8 36 1 + 649 8 36 0 + 650 8 37 1 + 651 8 37 0 + 652 9 36 1 + 653 9 36 0 + 654 9 37 1 + 655 9 37 0 + 672 3 36 0 + 673 3 36 1 + 674 3 37 0 + 675 3 37 1 + 676 2 36 0 + 677 2 36 1 + 678 2 37 0 + 679 2 37 1 + 680 0 37 1 + 681 0 37 0 + 682 0 36 1 + 683 0 36 0 + 684 1 37 1 + 685 1 37 0 + 686 1 36 1 + 687 1 36 0 + 688 4 36 0 + 689 4 36 1 + 690 4 37 0 + 691 4 37 1 + 692 5 36 0 + 693 5 36 1 + 694 5 37 0 + 695 5 37 1 + 696 7 37 1 + 697 7 37 0 + 698 7 36 1 + 699 7 36 0 + 700 6 37 1 + 701 6 37 0 + 702 6 36 1 + 703 6 36 0 + 704 12 37 0 + 705 12 37 1 + 706 12 36 0 + 707 12 36 1 + 708 13 37 0 + 709 13 37 1 + 710 13 36 0 + 711 13 36 1 + 712 15 36 1 + 713 15 36 0 + 714 15 37 1 + 715 15 37 0 + 716 14 36 1 + 717 14 36 0 + 718 14 37 1 + 719 14 37 0 + 768 11 39 0 + 769 11 39 1 + 770 11 38 0 + 771 11 38 1 + 772 10 39 0 + 773 10 39 1 + 774 10 38 0 + 775 10 38 1 + 776 8 38 1 + 777 8 38 0 + 778 8 39 1 + 779 8 39 0 + 780 9 38 1 + 781 9 38 0 + 782 9 39 1 + 783 9 39 0 + 800 3 38 0 + 801 3 38 1 + 802 3 39 0 + 803 3 39 1 + 804 2 38 0 + 805 2 38 1 + 806 2 39 0 + 807 2 39 1 + 808 0 39 1 + 809 0 39 0 + 810 0 38 1 + 811 0 38 0 + 812 1 39 1 + 813 1 39 0 + 814 1 38 1 + 815 1 38 0 + 816 4 38 0 + 817 4 38 1 + 818 4 39 0 + 819 4 39 1 + 820 5 38 0 + 821 5 38 1 + 822 5 39 0 + 823 5 39 1 + 824 7 39 1 + 825 7 39 0 + 826 7 38 1 + 827 7 38 0 + 828 6 39 1 + 829 6 39 0 + 830 6 38 1 + 831 6 38 0 + 832 12 39 0 + 833 12 39 1 + 834 12 38 0 + 835 12 38 1 + 836 13 39 0 + 837 13 39 1 + 838 13 38 0 + 839 13 38 1 + 840 15 38 1 + 841 15 38 0 + 842 15 39 1 + 843 15 39 0 + 844 14 38 1 + 845 14 38 0 + 846 14 39 1 + 847 14 39 0 + 896 11 41 0 + 897 11 41 1 + 898 11 40 0 + 899 11 40 1 + 900 10 41 0 + 901 10 41 1 + 902 10 40 0 + 903 10 40 1 + 904 8 40 1 + 905 8 40 0 + 906 8 41 1 + 907 8 41 0 + 908 9 40 1 + 909 9 40 0 + 910 9 41 1 + 911 9 41 0 + 928 3 40 0 + 929 3 40 1 + 930 3 41 0 + 931 3 41 1 + 932 2 40 0 + 933 2 40 1 + 934 2 41 0 + 935 2 41 1 + 936 0 41 1 + 937 0 41 0 + 938 0 40 1 + 939 0 40 0 + 940 1 41 1 + 941 1 41 0 + 942 1 40 1 + 943 1 40 0 + 944 4 40 0 + 945 4 40 1 + 946 4 41 0 + 947 4 41 1 + 948 5 40 0 + 949 5 40 1 + 950 5 41 0 + 951 5 41 1 + 952 7 41 1 + 953 7 41 0 + 954 7 40 1 + 955 7 40 0 + 956 6 41 1 + 957 6 41 0 + 958 6 40 1 + 959 6 40 0 + 960 12 41 0 + 961 12 41 1 + 962 12 40 0 + 963 12 40 1 + 964 13 41 0 + 965 13 41 1 + 966 13 40 0 + 967 13 40 1 + 968 15 40 1 + 969 15 40 0 + 970 15 41 1 + 971 15 41 0 + 972 14 40 1 + 973 14 40 0 + 974 14 41 1 + 975 14 41 0 +1024 11 43 0 +1025 11 43 1 +1026 11 42 0 +1027 11 42 1 +1028 10 43 0 +1029 10 43 1 +1030 10 42 0 +1031 10 42 1 +1032 8 42 1 +1033 8 42 0 +1034 8 43 1 +1035 8 43 0 +1036 9 42 1 +1037 9 42 0 +1038 9 43 1 +1039 9 43 0 +1056 3 42 0 +1057 3 42 1 +1058 3 43 0 +1059 3 43 1 +1060 2 42 0 +1061 2 42 1 +1062 2 43 0 +1063 2 43 1 +1064 0 43 1 +1065 0 43 0 +1066 0 42 1 +1067 0 42 0 +1068 1 43 1 +1069 1 43 0 +1070 1 42 1 +1071 1 42 0 +1072 4 42 0 +1073 4 42 1 +1074 4 43 0 +1075 4 43 1 +1076 5 42 0 +1077 5 42 1 +1078 5 43 0 +1079 5 43 1 +1080 7 43 1 +1081 7 43 0 +1082 7 42 1 +1083 7 42 0 +1084 6 43 1 +1085 6 43 0 +1086 6 42 1 +1087 6 42 0 +1088 12 43 0 +1089 12 43 1 +1090 12 42 0 +1091 12 42 1 +1092 13 43 0 +1093 13 43 1 +1094 13 42 0 +1095 13 42 1 +1096 15 42 1 +1097 15 42 0 +1098 15 43 1 +1099 15 43 0 +1100 14 42 1 +1101 14 42 0 +1102 14 43 1 +1103 14 43 0 +1152 11 45 0 +1153 11 45 1 +1154 11 44 0 +1155 11 44 1 +1156 10 45 0 +1157 10 45 1 +1158 10 44 0 +1159 10 44 1 +1160 8 44 1 +1161 8 44 0 +1162 8 45 1 +1163 8 45 0 +1164 9 44 1 +1165 9 44 0 +1166 9 45 1 +1167 9 45 0 +1184 3 44 0 +1185 3 44 1 +1186 3 45 0 +1187 3 45 1 +1188 2 44 0 +1189 2 44 1 +1190 2 45 0 +1191 2 45 1 +1192 0 45 1 +1193 0 45 0 +1194 0 44 1 +1195 0 44 0 +1196 1 45 1 +1197 1 45 0 +1198 1 44 1 +1199 1 44 0 +1200 4 44 0 +1201 4 44 1 +1202 4 45 0 +1203 4 45 1 +1204 5 44 0 +1205 5 44 1 +1206 5 45 0 +1207 5 45 1 +1208 7 45 1 +1209 7 45 0 +1210 7 44 1 +1211 7 44 0 +1212 6 45 1 +1213 6 45 0 +1214 6 44 1 +1215 6 44 0 +1216 12 45 0 +1217 12 45 1 +1218 12 44 0 +1219 12 44 1 +1220 13 45 0 +1221 13 45 1 +1222 13 44 0 +1223 13 44 1 +1224 15 44 1 +1225 15 44 0 +1226 15 45 1 +1227 15 45 0 +1228 14 44 1 +1229 14 44 0 +1230 14 45 1 +1231 14 45 0 +1280 11 47 0 +1281 11 47 1 +1282 11 46 0 +1283 11 46 1 +1284 10 47 0 +1285 10 47 1 +1286 10 46 0 +1287 10 46 1 +1288 8 46 1 +1289 8 46 0 +1290 8 47 1 +1291 8 47 0 +1292 9 46 1 +1293 9 46 0 +1294 9 47 1 +1295 9 47 0 +1312 3 46 0 +1313 3 46 1 +1314 3 47 0 +1315 3 47 1 +1316 2 46 0 +1317 2 46 1 +1318 2 47 0 +1319 2 47 1 +1320 0 47 1 +1321 0 47 0 +1322 0 46 1 +1323 0 46 0 +1324 1 47 1 +1325 1 47 0 +1326 1 46 1 +1327 1 46 0 +1328 4 46 0 +1329 4 46 1 +1330 4 47 0 +1331 4 47 1 +1332 5 46 0 +1333 5 46 1 +1334 5 47 0 +1335 5 47 1 +1336 7 47 1 +1337 7 47 0 +1338 7 46 1 +1339 7 46 0 +1340 6 47 1 +1341 6 47 0 +1342 6 46 1 +1343 6 46 0 +1344 12 47 0 +1345 12 47 1 +1346 12 46 0 +1347 12 46 1 +1348 13 47 0 +1349 13 47 1 +1350 13 46 0 +1351 13 46 1 +1352 15 46 1 +1353 15 46 0 +1354 15 47 1 +1355 15 47 0 +1356 14 46 1 +1357 14 46 0 +1358 14 47 1 +1359 14 47 0 +1408 11 49 0 +1409 11 49 1 +1410 11 48 0 +1411 11 48 1 +1412 10 49 0 +1413 10 49 1 +1414 10 48 0 +1415 10 48 1 +1416 8 48 1 +1417 8 48 0 +1418 8 49 1 +1419 8 49 0 +1420 9 48 1 +1421 9 48 0 +1422 9 49 1 +1423 9 49 0 +1440 3 48 0 +1441 3 48 1 +1442 3 49 0 +1443 3 49 1 +1444 2 48 0 +1445 2 48 1 +1446 2 49 0 +1447 2 49 1 +1448 0 49 1 +1449 0 49 0 +1450 0 48 1 +1451 0 48 0 +1452 1 49 1 +1453 1 49 0 +1454 1 48 1 +1455 1 48 0 +1456 4 48 0 +1457 4 48 1 +1458 4 49 0 +1459 4 49 1 +1460 5 48 0 +1461 5 48 1 +1462 5 49 0 +1463 5 49 1 +1464 7 49 1 +1465 7 49 0 +1466 7 48 1 +1467 7 48 0 +1468 6 49 1 +1469 6 49 0 +1470 6 48 1 +1471 6 48 0 +1472 12 49 0 +1473 12 49 1 +1474 12 48 0 +1475 12 48 1 +1476 13 49 0 +1477 13 49 1 +1478 13 48 0 +1479 13 48 1 +1480 15 48 1 +1481 15 48 0 +1482 15 49 1 +1483 15 49 0 +1484 14 48 1 +1485 14 48 0 +1486 14 49 1 +1487 14 49 0 +1536 11 51 0 +1537 11 51 1 +1538 11 50 0 +1539 11 50 1 +1540 10 51 0 +1541 10 51 1 +1542 10 50 0 +1543 10 50 1 +1544 8 50 1 +1545 8 50 0 +1546 8 51 1 +1547 8 51 0 +1548 9 50 1 +1549 9 50 0 +1550 9 51 1 +1551 9 51 0 +1568 3 50 0 +1569 3 50 1 +1570 3 51 0 +1571 3 51 1 +1572 2 50 0 +1573 2 50 1 +1574 2 51 0 +1575 2 51 1 +1576 0 51 1 +1577 0 51 0 +1578 0 50 1 +1579 0 50 0 +1580 1 51 1 +1581 1 51 0 +1582 1 50 1 +1583 1 50 0 +1584 4 50 0 +1585 4 50 1 +1586 4 51 0 +1587 4 51 1 +1588 5 50 0 +1589 5 50 1 +1590 5 51 0 +1591 5 51 1 +1592 7 51 1 +1593 7 51 0 +1594 7 50 1 +1595 7 50 0 +1596 6 51 1 +1597 6 51 0 +1598 6 50 1 +1599 6 50 0 +1600 12 51 0 +1601 12 51 1 +1602 12 50 0 +1603 12 50 1 +1604 13 51 0 +1605 13 51 1 +1606 13 50 0 +1607 13 50 1 +1608 15 50 1 +1609 15 50 0 +1610 15 51 1 +1611 15 51 0 +1612 14 50 1 +1613 14 50 0 +1614 14 51 1 +1615 14 51 0 +1664 11 53 0 +1665 11 53 1 +1666 11 52 0 +1667 11 52 1 +1668 10 53 0 +1669 10 53 1 +1670 10 52 0 +1671 10 52 1 +1672 8 52 1 +1673 8 52 0 +1674 8 53 1 +1675 8 53 0 +1676 9 52 1 +1677 9 52 0 +1678 9 53 1 +1679 9 53 0 +1696 3 52 0 +1697 3 52 1 +1698 3 53 0 +1699 3 53 1 +1700 2 52 0 +1701 2 52 1 +1702 2 53 0 +1703 2 53 1 +1704 0 53 1 +1705 0 53 0 +1706 0 52 1 +1707 0 52 0 +1708 1 53 1 +1709 1 53 0 +1710 1 52 1 +1711 1 52 0 +1712 4 52 0 +1713 4 52 1 +1714 4 53 0 +1715 4 53 1 +1716 5 52 0 +1717 5 52 1 +1718 5 53 0 +1719 5 53 1 +1720 7 53 1 +1721 7 53 0 +1722 7 52 1 +1723 7 52 0 +1724 6 53 1 +1725 6 53 0 +1726 6 52 1 +1727 6 52 0 +1728 12 53 0 +1729 12 53 1 +1730 12 52 0 +1731 12 52 1 +1732 13 53 0 +1733 13 53 1 +1734 13 52 0 +1735 13 52 1 +1736 15 52 1 +1737 15 52 0 +1738 15 53 1 +1739 15 53 0 +1740 14 52 1 +1741 14 52 0 +1742 14 53 1 +1743 14 53 0 +1792 11 55 0 +1793 11 55 1 +1794 11 54 0 +1795 11 54 1 +1796 10 55 0 +1797 10 55 1 +1798 10 54 0 +1799 10 54 1 +1800 8 54 1 +1801 8 54 0 +1802 8 55 1 +1803 8 55 0 +1804 9 54 1 +1805 9 54 0 +1806 9 55 1 +1807 9 55 0 +1824 3 54 0 +1825 3 54 1 +1826 3 55 0 +1827 3 55 1 +1828 2 54 0 +1829 2 54 1 +1830 2 55 0 +1831 2 55 1 +1832 0 55 1 +1833 0 55 0 +1834 0 54 1 +1835 0 54 0 +1836 1 55 1 +1837 1 55 0 +1838 1 54 1 +1839 1 54 0 +1840 4 54 0 +1841 4 54 1 +1842 4 55 0 +1843 4 55 1 +1844 5 54 0 +1845 5 54 1 +1846 5 55 0 +1847 5 55 1 +1848 7 55 1 +1849 7 55 0 +1850 7 54 1 +1851 7 54 0 +1852 6 55 1 +1853 6 55 0 +1854 6 54 1 +1855 6 54 0 +1856 12 55 0 +1857 12 55 1 +1858 12 54 0 +1859 12 54 1 +1860 13 55 0 +1861 13 55 1 +1862 13 54 0 +1863 13 54 1 +1864 15 54 1 +1865 15 54 0 +1866 15 55 1 +1867 15 55 0 +1868 14 54 1 +1869 14 54 0 +1870 14 55 1 +1871 14 55 0 +2176 11 27 0 +2177 11 27 1 +2178 11 26 0 +2179 11 26 1 +2180 10 27 0 +2181 10 27 1 +2182 10 26 0 +2183 10 26 1 +2184 8 26 1 +2185 8 26 0 +2186 8 27 1 +2187 8 27 0 +2188 9 26 1 +2189 9 26 0 +2190 9 27 1 +2191 9 27 0 +2208 3 26 0 +2209 3 26 1 +2210 3 27 0 +2211 3 27 1 +2212 2 26 0 +2213 2 26 1 +2214 2 27 0 +2215 2 27 1 +2216 0 27 1 +2217 0 27 0 +2218 0 26 1 +2219 0 26 0 +2220 1 27 1 +2221 1 27 0 +2222 1 26 1 +2223 1 26 0 +2224 4 26 0 +2225 4 26 1 +2226 4 27 0 +2227 4 27 1 +2228 5 26 0 +2229 5 26 1 +2230 5 27 0 +2231 5 27 1 +2232 7 27 1 +2233 7 27 0 +2234 7 26 1 +2235 7 26 0 +2236 6 27 1 +2237 6 27 0 +2238 6 26 1 +2239 6 26 0 +2240 12 27 0 +2241 12 27 1 +2242 12 26 0 +2243 12 26 1 +2244 13 27 0 +2245 13 27 1 +2246 13 26 0 +2247 13 26 1 +2248 15 26 1 +2249 15 26 0 +2250 15 27 1 +2251 15 27 0 +2252 14 26 1 +2253 14 26 0 +2254 14 27 1 +2255 14 27 0 +2304 11 25 0 +2305 11 25 1 +2306 11 24 0 +2307 11 24 1 +2308 10 25 0 +2309 10 25 1 +2310 10 24 0 +2311 10 24 1 +2312 8 24 1 +2313 8 24 0 +2314 8 25 1 +2315 8 25 0 +2316 9 24 1 +2317 9 24 0 +2318 9 25 1 +2319 9 25 0 +2336 3 24 0 +2337 3 24 1 +2338 3 25 0 +2339 3 25 1 +2340 2 24 0 +2341 2 24 1 +2342 2 25 0 +2343 2 25 1 +2344 0 25 1 +2345 0 25 0 +2346 0 24 1 +2347 0 24 0 +2348 1 25 1 +2349 1 25 0 +2350 1 24 1 +2351 1 24 0 +2352 4 24 0 +2353 4 24 1 +2354 4 25 0 +2355 4 25 1 +2356 5 24 0 +2357 5 24 1 +2358 5 25 0 +2359 5 25 1 +2360 7 25 1 +2361 7 25 0 +2362 7 24 1 +2363 7 24 0 +2364 6 25 1 +2365 6 25 0 +2366 6 24 1 +2367 6 24 0 +2368 12 25 0 +2369 12 25 1 +2370 12 24 0 +2371 12 24 1 +2372 13 25 0 +2373 13 25 1 +2374 13 24 0 +2375 13 24 1 +2376 15 24 1 +2377 15 24 0 +2378 15 25 1 +2379 15 25 0 +2380 14 24 1 +2381 14 24 0 +2382 14 25 1 +2383 14 25 0 +2432 11 23 0 +2433 11 23 1 +2434 11 22 0 +2435 11 22 1 +2436 10 23 0 +2437 10 23 1 +2438 10 22 0 +2439 10 22 1 +2440 8 22 1 +2441 8 22 0 +2442 8 23 1 +2443 8 23 0 +2444 9 22 1 +2445 9 22 0 +2446 9 23 1 +2447 9 23 0 +2464 3 22 0 +2465 3 22 1 +2466 3 23 0 +2467 3 23 1 +2468 2 22 0 +2469 2 22 1 +2470 2 23 0 +2471 2 23 1 +2472 0 23 1 +2473 0 23 0 +2474 0 22 1 +2475 0 22 0 +2476 1 23 1 +2477 1 23 0 +2478 1 22 1 +2479 1 22 0 +2480 4 22 0 +2481 4 22 1 +2482 4 23 0 +2483 4 23 1 +2484 5 22 0 +2485 5 22 1 +2486 5 23 0 +2487 5 23 1 +2488 7 23 1 +2489 7 23 0 +2490 7 22 1 +2491 7 22 0 +2492 6 23 1 +2493 6 23 0 +2494 6 22 1 +2495 6 22 0 +2496 12 23 0 +2497 12 23 1 +2498 12 22 0 +2499 12 22 1 +2500 13 23 0 +2501 13 23 1 +2502 13 22 0 +2503 13 22 1 +2504 15 22 1 +2505 15 22 0 +2506 15 23 1 +2507 15 23 0 +2508 14 22 1 +2509 14 22 0 +2510 14 23 1 +2511 14 23 0 +2560 11 21 0 +2561 11 21 1 +2562 11 20 0 +2563 11 20 1 +2564 10 21 0 +2565 10 21 1 +2566 10 20 0 +2567 10 20 1 +2568 8 20 1 +2569 8 20 0 +2570 8 21 1 +2571 8 21 0 +2572 9 20 1 +2573 9 20 0 +2574 9 21 1 +2575 9 21 0 +2592 3 20 0 +2593 3 20 1 +2594 3 21 0 +2595 3 21 1 +2596 2 20 0 +2597 2 20 1 +2598 2 21 0 +2599 2 21 1 +2600 0 21 1 +2601 0 21 0 +2602 0 20 1 +2603 0 20 0 +2604 1 21 1 +2605 1 21 0 +2606 1 20 1 +2607 1 20 0 +2608 4 20 0 +2609 4 20 1 +2610 4 21 0 +2611 4 21 1 +2612 5 20 0 +2613 5 20 1 +2614 5 21 0 +2615 5 21 1 +2616 7 21 1 +2617 7 21 0 +2618 7 20 1 +2619 7 20 0 +2620 6 21 1 +2621 6 21 0 +2622 6 20 1 +2623 6 20 0 +2624 12 21 0 +2625 12 21 1 +2626 12 20 0 +2627 12 20 1 +2628 13 21 0 +2629 13 21 1 +2630 13 20 0 +2631 13 20 1 +2632 15 20 1 +2633 15 20 0 +2634 15 21 1 +2635 15 21 0 +2636 14 20 1 +2637 14 20 0 +2638 14 21 1 +2639 14 21 0 +2688 11 19 0 +2689 11 19 1 +2690 11 18 0 +2691 11 18 1 +2692 10 19 0 +2693 10 19 1 +2694 10 18 0 +2695 10 18 1 +2696 8 18 1 +2697 8 18 0 +2698 8 19 1 +2699 8 19 0 +2700 9 18 1 +2701 9 18 0 +2702 9 19 1 +2703 9 19 0 +2720 3 18 0 +2721 3 18 1 +2722 3 19 0 +2723 3 19 1 +2724 2 18 0 +2725 2 18 1 +2726 2 19 0 +2727 2 19 1 +2728 0 19 1 +2729 0 19 0 +2730 0 18 1 +2731 0 18 0 +2732 1 19 1 +2733 1 19 0 +2734 1 18 1 +2735 1 18 0 +2736 4 18 0 +2737 4 18 1 +2738 4 19 0 +2739 4 19 1 +2740 5 18 0 +2741 5 18 1 +2742 5 19 0 +2743 5 19 1 +2744 7 19 1 +2745 7 19 0 +2746 7 18 1 +2747 7 18 0 +2748 6 19 1 +2749 6 19 0 +2750 6 18 1 +2751 6 18 0 +2752 12 19 0 +2753 12 19 1 +2754 12 18 0 +2755 12 18 1 +2756 13 19 0 +2757 13 19 1 +2758 13 18 0 +2759 13 18 1 +2760 15 18 1 +2761 15 18 0 +2762 15 19 1 +2763 15 19 0 +2764 14 18 1 +2765 14 18 0 +2766 14 19 1 +2767 14 19 0 +2816 11 17 0 +2817 11 17 1 +2818 11 16 0 +2819 11 16 1 +2820 10 17 0 +2821 10 17 1 +2822 10 16 0 +2823 10 16 1 +2824 8 16 1 +2825 8 16 0 +2826 8 17 1 +2827 8 17 0 +2828 9 16 1 +2829 9 16 0 +2830 9 17 1 +2831 9 17 0 +2848 3 16 0 +2849 3 16 1 +2850 3 17 0 +2851 3 17 1 +2852 2 16 0 +2853 2 16 1 +2854 2 17 0 +2855 2 17 1 +2856 0 17 1 +2857 0 17 0 +2858 0 16 1 +2859 0 16 0 +2860 1 17 1 +2861 1 17 0 +2862 1 16 1 +2863 1 16 0 +2864 4 16 0 +2865 4 16 1 +2866 4 17 0 +2867 4 17 1 +2868 5 16 0 +2869 5 16 1 +2870 5 17 0 +2871 5 17 1 +2872 7 17 1 +2873 7 17 0 +2874 7 16 1 +2875 7 16 0 +2876 6 17 1 +2877 6 17 0 +2878 6 16 1 +2879 6 16 0 +2880 12 17 0 +2881 12 17 1 +2882 12 16 0 +2883 12 16 1 +2884 13 17 0 +2885 13 17 1 +2886 13 16 0 +2887 13 16 1 +2888 15 16 1 +2889 15 16 0 +2890 15 17 1 +2891 15 17 0 +2892 14 16 1 +2893 14 16 0 +2894 14 17 1 +2895 14 17 0 +2944 11 15 0 +2945 11 15 1 +2946 11 14 0 +2947 11 14 1 +2948 10 15 0 +2949 10 15 1 +2950 10 14 0 +2951 10 14 1 +2952 8 14 1 +2953 8 14 0 +2954 8 15 1 +2955 8 15 0 +2956 9 14 1 +2957 9 14 0 +2958 9 15 1 +2959 9 15 0 +2976 3 14 0 +2977 3 14 1 +2978 3 15 0 +2979 3 15 1 +2980 2 14 0 +2981 2 14 1 +2982 2 15 0 +2983 2 15 1 +2984 0 15 1 +2985 0 15 0 +2986 0 14 1 +2987 0 14 0 +2988 1 15 1 +2989 1 15 0 +2990 1 14 1 +2991 1 14 0 +2992 4 14 0 +2993 4 14 1 +2994 4 15 0 +2995 4 15 1 +2996 5 14 0 +2997 5 14 1 +2998 5 15 0 +2999 5 15 1 +3000 7 15 1 +3001 7 15 0 +3002 7 14 1 +3003 7 14 0 +3004 6 15 1 +3005 6 15 0 +3006 6 14 1 +3007 6 14 0 +3008 12 15 0 +3009 12 15 1 +3010 12 14 0 +3011 12 14 1 +3012 13 15 0 +3013 13 15 1 +3014 13 14 0 +3015 13 14 1 +3016 15 14 1 +3017 15 14 0 +3018 15 15 1 +3019 15 15 0 +3020 14 14 1 +3021 14 14 0 +3022 14 15 1 +3023 14 15 0 +3072 11 13 0 +3073 11 13 1 +3074 11 12 0 +3075 11 12 1 +3076 10 13 0 +3077 10 13 1 +3078 10 12 0 +3079 10 12 1 +3080 8 12 1 +3081 8 12 0 +3082 8 13 1 +3083 8 13 0 +3084 9 12 1 +3085 9 12 0 +3086 9 13 1 +3087 9 13 0 +3104 3 12 0 +3105 3 12 1 +3106 3 13 0 +3107 3 13 1 +3108 2 12 0 +3109 2 12 1 +3110 2 13 0 +3111 2 13 1 +3112 0 13 1 +3113 0 13 0 +3114 0 12 1 +3115 0 12 0 +3116 1 13 1 +3117 1 13 0 +3118 1 12 1 +3119 1 12 0 +3120 4 12 0 +3121 4 12 1 +3122 4 13 0 +3123 4 13 1 +3124 5 12 0 +3125 5 12 1 +3126 5 13 0 +3127 5 13 1 +3128 7 13 1 +3129 7 13 0 +3130 7 12 1 +3131 7 12 0 +3132 6 13 1 +3133 6 13 0 +3134 6 12 1 +3135 6 12 0 +3136 12 13 0 +3137 12 13 1 +3138 12 12 0 +3139 12 12 1 +3140 13 13 0 +3141 13 13 1 +3142 13 12 0 +3143 13 12 1 +3144 15 12 1 +3145 15 12 0 +3146 15 13 1 +3147 15 13 0 +3148 14 12 1 +3149 14 12 0 +3150 14 13 1 +3151 14 13 0 +3200 11 11 0 +3201 11 11 1 +3202 11 10 0 +3203 11 10 1 +3204 10 11 0 +3205 10 11 1 +3206 10 10 0 +3207 10 10 1 +3208 8 10 1 +3209 8 10 0 +3210 8 11 1 +3211 8 11 0 +3212 9 10 1 +3213 9 10 0 +3214 9 11 1 +3215 9 11 0 +3232 3 10 0 +3233 3 10 1 +3234 3 11 0 +3235 3 11 1 +3236 2 10 0 +3237 2 10 1 +3238 2 11 0 +3239 2 11 1 +3240 0 11 1 +3241 0 11 0 +3242 0 10 1 +3243 0 10 0 +3244 1 11 1 +3245 1 11 0 +3246 1 10 1 +3247 1 10 0 +3248 4 10 0 +3249 4 10 1 +3250 4 11 0 +3251 4 11 1 +3252 5 10 0 +3253 5 10 1 +3254 5 11 0 +3255 5 11 1 +3256 7 11 1 +3257 7 11 0 +3258 7 10 1 +3259 7 10 0 +3260 6 11 1 +3261 6 11 0 +3262 6 10 1 +3263 6 10 0 +3264 12 11 0 +3265 12 11 1 +3266 12 10 0 +3267 12 10 1 +3268 13 11 0 +3269 13 11 1 +3270 13 10 0 +3271 13 10 1 +3272 15 10 1 +3273 15 10 0 +3274 15 11 1 +3275 15 11 0 +3276 14 10 1 +3277 14 10 0 +3278 14 11 1 +3279 14 11 0 +3328 11 9 0 +3329 11 9 1 +3330 11 8 0 +3331 11 8 1 +3332 10 9 0 +3333 10 9 1 +3334 10 8 0 +3335 10 8 1 +3336 8 8 1 +3337 8 8 0 +3338 8 9 1 +3339 8 9 0 +3340 9 8 1 +3341 9 8 0 +3342 9 9 1 +3343 9 9 0 +3360 3 8 0 +3361 3 8 1 +3362 3 9 0 +3363 3 9 1 +3364 2 8 0 +3365 2 8 1 +3366 2 9 0 +3367 2 9 1 +3368 0 9 1 +3369 0 9 0 +3370 0 8 1 +3371 0 8 0 +3372 1 9 1 +3373 1 9 0 +3374 1 8 1 +3375 1 8 0 +3376 4 8 0 +3377 4 8 1 +3378 4 9 0 +3379 4 9 1 +3380 5 8 0 +3381 5 8 1 +3382 5 9 0 +3383 5 9 1 +3384 7 9 1 +3385 7 9 0 +3386 7 8 1 +3387 7 8 0 +3388 6 9 1 +3389 6 9 0 +3390 6 8 1 +3391 6 8 0 +3392 12 9 0 +3393 12 9 1 +3394 12 8 0 +3395 12 8 1 +3396 13 9 0 +3397 13 9 1 +3398 13 8 0 +3399 13 8 1 +3400 15 8 1 +3401 15 8 0 +3402 15 9 1 +3403 15 9 0 +3404 14 8 1 +3405 14 8 0 +3406 14 9 1 +3407 14 9 0 +3456 11 7 0 +3457 11 7 1 +3458 11 6 0 +3459 11 6 1 +3460 10 7 0 +3461 10 7 1 +3462 10 6 0 +3463 10 6 1 +3464 8 6 1 +3465 8 6 0 +3466 8 7 1 +3467 8 7 0 +3468 9 6 1 +3469 9 6 0 +3470 9 7 1 +3471 9 7 0 +3488 3 6 0 +3489 3 6 1 +3490 3 7 0 +3491 3 7 1 +3492 2 6 0 +3493 2 6 1 +3494 2 7 0 +3495 2 7 1 +3496 0 7 1 +3497 0 7 0 +3498 0 6 1 +3499 0 6 0 +3500 1 7 1 +3501 1 7 0 +3502 1 6 1 +3503 1 6 0 +3504 4 6 0 +3505 4 6 1 +3506 4 7 0 +3507 4 7 1 +3508 5 6 0 +3509 5 6 1 +3510 5 7 0 +3511 5 7 1 +3512 7 7 1 +3513 7 7 0 +3514 7 6 1 +3515 7 6 0 +3516 6 7 1 +3517 6 7 0 +3518 6 6 1 +3519 6 6 0 +3520 12 7 0 +3521 12 7 1 +3522 12 6 0 +3523 12 6 1 +3524 13 7 0 +3525 13 7 1 +3526 13 6 0 +3527 13 6 1 +3528 15 6 1 +3529 15 6 0 +3530 15 7 1 +3531 15 7 0 +3532 14 6 1 +3533 14 6 0 +3534 14 7 1 +3535 14 7 0 +3584 11 5 0 +3585 11 5 1 +3586 11 4 0 +3587 11 4 1 +3588 10 5 0 +3589 10 5 1 +3590 10 4 0 +3591 10 4 1 +3592 8 4 1 +3593 8 4 0 +3594 8 5 1 +3595 8 5 0 +3596 9 4 1 +3597 9 4 0 +3598 9 5 1 +3599 9 5 0 +3616 3 4 0 +3617 3 4 1 +3618 3 5 0 +3619 3 5 1 +3620 2 4 0 +3621 2 4 1 +3622 2 5 0 +3623 2 5 1 +3624 0 5 1 +3625 0 5 0 +3626 0 4 1 +3627 0 4 0 +3628 1 5 1 +3629 1 5 0 +3630 1 4 1 +3631 1 4 0 +3632 4 4 0 +3633 4 4 1 +3634 4 5 0 +3635 4 5 1 +3636 5 4 0 +3637 5 4 1 +3638 5 5 0 +3639 5 5 1 +3640 7 5 1 +3641 7 5 0 +3642 7 4 1 +3643 7 4 0 +3644 6 5 1 +3645 6 5 0 +3646 6 4 1 +3647 6 4 0 +3648 12 5 0 +3649 12 5 1 +3650 12 4 0 +3651 12 4 1 +3652 13 5 0 +3653 13 5 1 +3654 13 4 0 +3655 13 4 1 +3656 15 4 1 +3657 15 4 0 +3658 15 5 1 +3659 15 5 0 +3660 14 4 1 +3661 14 4 0 +3662 14 5 1 +3663 14 5 0 +3712 11 3 0 +3713 11 3 1 +3714 11 2 0 +3715 11 2 1 +3716 10 3 0 +3717 10 3 1 +3718 10 2 0 +3719 10 2 1 +3720 8 2 1 +3721 8 2 0 +3722 8 3 1 +3723 8 3 0 +3724 9 2 1 +3725 9 2 0 +3726 9 3 1 +3727 9 3 0 +3744 3 2 0 +3745 3 2 1 +3746 3 3 0 +3747 3 3 1 +3748 2 2 0 +3749 2 2 1 +3750 2 3 0 +3751 2 3 1 +3752 0 3 1 +3753 0 3 0 +3754 0 2 1 +3755 0 2 0 +3756 1 3 1 +3757 1 3 0 +3758 1 2 1 +3759 1 2 0 +3760 4 2 0 +3761 4 2 1 +3762 4 3 0 +3763 4 3 1 +3764 5 2 0 +3765 5 2 1 +3766 5 3 0 +3767 5 3 1 +3768 7 3 1 +3769 7 3 0 +3770 7 2 1 +3771 7 2 0 +3772 6 3 1 +3773 6 3 0 +3774 6 2 1 +3775 6 2 0 +3776 12 3 0 +3777 12 3 1 +3778 12 2 0 +3779 12 2 1 +3780 13 3 0 +3781 13 3 1 +3782 13 2 0 +3783 13 2 1 +3784 15 2 1 +3785 15 2 0 +3786 15 3 1 +3787 15 3 0 +3788 14 2 1 +3789 14 2 0 +3790 14 3 1 +3791 14 3 0 +3840 11 1 0 +3841 11 1 1 +3842 11 0 0 +3843 11 0 1 +3844 10 1 0 +3845 10 1 1 +3846 10 0 0 +3847 10 0 1 +3848 8 0 1 +3849 8 0 0 +3850 8 1 1 +3851 8 1 0 +3852 9 0 1 +3853 9 0 0 +3854 9 1 1 +3855 9 1 0 +3872 3 0 0 +3873 3 0 1 +3874 3 1 0 +3875 3 1 1 +3876 2 0 0 +3877 2 0 1 +3878 2 1 0 +3879 2 1 1 +3880 0 1 1 +3881 0 1 0 +3882 0 0 1 +3883 0 0 0 +3884 1 1 1 +3885 1 1 0 +3886 1 0 1 +3887 1 0 0 +3888 4 0 0 +3889 4 0 1 +3890 4 1 0 +3891 4 1 1 +3892 5 0 0 +3893 5 0 1 +3894 5 1 0 +3895 5 1 1 +3896 7 1 1 +3897 7 1 0 +3898 7 0 1 +3899 7 0 0 +3900 6 1 1 +3901 6 1 0 +3902 6 0 1 +3903 6 0 0 +3904 12 1 0 +3905 12 1 1 +3906 12 0 0 +3907 12 0 1 +3908 13 1 0 +3909 13 1 1 +3910 13 0 0 +3911 13 0 1 +3912 15 0 1 +3913 15 0 0 +3914 15 1 1 +3915 15 1 0 +3916 14 0 1 +3917 14 0 0 +3918 14 1 1 +3919 14 1 0 diff --git a/Detectors/PHOS/base/files/Mod3RCU1.data b/Detectors/PHOS/base/files/Mod3RCU1.data new file mode 100644 index 0000000000000..db125226496cf --- /dev/null +++ b/Detectors/PHOS/base/files/Mod3RCU1.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 1 0 2 + 1 1 1 2 + 2 1 2 2 + 3 1 3 2 + 4 1 4 2 + 5 1 5 2 + 6 1 6 2 + 7 1 7 2 + 8 1 8 2 + 9 1 9 2 + 10 1 10 2 + 11 1 11 2 + 12 1 12 2 + 13 1 13 2 + 14 1 14 2 + 15 1 15 2 + 16 1 16 2 + 17 1 17 2 + 18 1 18 2 + 19 1 19 2 + 20 1 20 2 + 21 1 21 2 + 22 1 22 2 + 23 1 23 2 + 24 1 24 2 + 25 1 25 2 + 26 1 26 2 + 27 1 27 2 + 28 1 28 2 + 29 1 29 2 + 30 1 30 2 + 31 1 31 2 + 32 1 32 2 + 33 1 33 2 + 34 1 34 2 + 35 1 35 2 + 36 1 36 2 + 37 1 37 2 + 38 1 38 2 + 39 1 39 2 + 40 1 40 2 + 41 1 41 2 + 42 1 42 2 + 43 1 43 2 + 44 1 44 2 + 45 1 45 2 + 46 1 46 2 + 47 1 47 2 + 48 1 48 2 + 49 1 49 2 + 50 1 50 2 + 51 1 51 2 + 52 1 52 2 + 53 1 53 2 + 54 1 54 2 + 55 1 55 2 + 56 1 56 2 + 57 1 57 2 + 58 1 58 2 + 59 1 59 2 + 60 1 60 2 + 61 1 61 2 + 62 1 62 2 + 63 1 63 2 + 64 1 64 2 + 65 1 65 2 + 66 1 66 2 + 67 1 67 2 + 68 1 68 2 + 69 1 69 2 + 70 1 70 2 + 71 1 71 2 + 72 1 72 2 + 73 1 73 2 + 74 1 74 2 + 75 1 75 2 + 76 1 76 2 + 77 1 77 2 + 78 1 78 2 + 79 1 79 2 + 80 1 80 2 + 81 1 81 2 + 82 1 82 2 + 83 1 83 2 + 84 1 84 2 + 85 1 85 2 + 86 1 86 2 + 87 1 87 2 + 88 1 88 2 + 89 1 89 2 + 90 1 90 2 + 91 1 91 2 + 92 1 92 2 + 93 1 93 2 + 94 1 94 2 + 95 1 95 2 + 96 1 96 2 + 97 1 97 2 + 98 1 98 2 + 99 1 99 2 + 100 1 100 2 + 101 1 101 2 + 102 1 102 2 + 103 1 103 2 + 104 1 104 2 + 105 1 105 2 + 106 1 106 2 + 107 1 107 2 + 108 1 108 2 + 109 1 109 2 + 110 1 110 2 + 111 1 111 2 + 112 1 112 2 + 113 1 113 2 + 114 1 114 2 + 115 1 115 2 + 116 1 116 2 + 117 1 117 2 + 118 1 118 2 + 119 1 119 2 + 120 1 120 2 + 121 1 121 2 + 122 1 122 2 + 123 1 123 2 + 124 1 124 2 + 125 1 125 2 + 126 1 126 2 + 127 1 127 2 +2048 1 2048 2 +2049 1 2049 2 +2050 1 2050 2 +2051 1 2051 2 +2052 1 2052 2 +2053 1 2053 2 +2054 1 2054 2 +2055 1 2055 2 +2056 1 2056 2 +2057 1 2057 2 +2058 1 2058 2 +2059 1 2059 2 +2060 1 2060 2 +2061 1 2061 2 +2062 1 2062 2 +2063 1 2063 2 +2064 1 2064 2 +2065 1 2065 2 +2066 1 2066 2 +2067 1 2067 2 +2068 1 2068 2 +2069 1 2069 2 +2070 1 2070 2 +2071 1 2071 2 +2072 1 2072 2 +2073 1 2073 2 +2074 1 2074 2 +2075 1 2075 2 +2076 1 2076 2 +2077 1 2077 2 +2078 1 2078 2 +2079 1 2079 2 +2080 1 2080 2 +2081 1 2081 2 +2082 1 2082 2 +2083 1 2083 2 +2084 1 2084 2 +2085 1 2085 2 +2086 1 2086 2 +2087 1 2087 2 +2088 1 2088 2 +2089 1 2089 2 +2090 1 2090 2 +2091 1 2091 2 +2092 1 2092 2 +2093 1 2093 2 +2094 1 2094 2 +2095 1 2095 2 +2096 1 2096 2 +2097 1 2097 2 +2098 1 2098 2 +2099 1 2099 2 +2100 1 2100 2 +2101 1 2101 2 +2102 1 2102 2 +2103 1 2103 2 +2104 1 2104 2 +2105 1 2105 2 +2106 1 2106 2 +2107 1 2107 2 +2108 1 2108 2 +2109 1 2109 2 +2110 1 2110 2 +2111 1 2111 2 +2112 1 2112 2 +2113 1 2113 2 +2114 1 2114 2 +2115 1 2115 2 +2116 1 2116 2 +2117 1 2117 2 +2118 1 2118 2 +2119 1 2119 2 +2120 1 2120 2 +2121 1 2121 2 +2122 1 2122 2 +2123 1 2123 2 +2124 1 2124 2 +2125 1 2125 2 +2126 1 2126 2 +2127 1 2127 2 +2128 1 2128 2 +2129 1 2129 2 +2130 1 2130 2 +2131 1 2131 2 +2132 1 2132 2 +2133 1 2133 2 +2134 1 2134 2 +2135 1 2135 2 +2136 1 2136 2 +2137 1 2137 2 +2138 1 2138 2 +2139 1 2139 2 +2140 1 2140 2 +2141 1 2141 2 +2142 1 2142 2 +2143 1 2143 2 +2144 1 2144 2 +2145 1 2145 2 +2146 1 2146 2 +2147 1 2147 2 +2148 1 2148 2 +2149 1 2149 2 +2150 1 2150 2 +2151 1 2151 2 +2152 1 2152 2 +2153 1 2153 2 +2154 1 2154 2 +2155 1 2155 2 +2156 1 2156 2 +2157 1 2157 2 +2158 1 2158 2 +2159 1 2159 2 +2160 1 2160 2 +2161 1 2161 2 +2162 1 2162 2 +2163 1 2163 2 +2164 1 2164 2 +2165 1 2165 2 +2166 1 2166 2 +2167 1 2167 2 +2168 1 2168 2 +2169 1 2169 2 +2170 1 2170 2 +2171 1 2171 2 +2172 1 2172 2 +2173 1 2173 2 +2174 1 2174 2 +2175 1 2175 2 + 128 27 29 0 + 129 27 29 1 + 130 27 28 0 + 131 27 28 1 + 132 26 29 0 + 133 26 29 1 + 134 26 28 0 + 135 26 28 1 + 136 24 28 1 + 137 24 28 0 + 138 24 29 1 + 139 24 29 0 + 140 25 28 1 + 141 25 28 0 + 142 25 29 1 + 143 25 29 0 + 160 19 28 0 + 161 19 28 1 + 162 19 29 0 + 163 19 29 1 + 164 18 28 0 + 165 18 28 1 + 166 18 29 0 + 167 18 29 1 + 168 16 29 1 + 169 16 29 0 + 170 16 28 1 + 171 16 28 0 + 172 17 29 1 + 173 17 29 0 + 174 17 28 1 + 175 17 28 0 + 176 20 28 0 + 177 20 28 1 + 178 20 29 0 + 179 20 29 1 + 180 21 28 0 + 181 21 28 1 + 182 21 29 0 + 183 21 29 1 + 184 23 29 1 + 185 23 29 0 + 186 23 28 1 + 187 23 28 0 + 188 22 29 1 + 189 22 29 0 + 190 22 28 1 + 191 22 28 0 + 192 28 29 0 + 193 28 29 1 + 194 28 28 0 + 195 28 28 1 + 196 29 29 0 + 197 29 29 1 + 198 29 28 0 + 199 29 28 1 + 200 31 28 1 + 201 31 28 0 + 202 31 29 1 + 203 31 29 0 + 204 30 28 1 + 205 30 28 0 + 206 30 29 1 + 207 30 29 0 + 256 27 31 0 + 257 27 31 1 + 258 27 30 0 + 259 27 30 1 + 260 26 31 0 + 261 26 31 1 + 262 26 30 0 + 263 26 30 1 + 264 24 30 1 + 265 24 30 0 + 266 24 31 1 + 267 24 31 0 + 268 25 30 1 + 269 25 30 0 + 270 25 31 1 + 271 25 31 0 + 288 19 30 0 + 289 19 30 1 + 290 19 31 0 + 291 19 31 1 + 292 18 30 0 + 293 18 30 1 + 294 18 31 0 + 295 18 31 1 + 296 16 31 1 + 297 16 31 0 + 298 16 30 1 + 299 16 30 0 + 300 17 31 1 + 301 17 31 0 + 302 17 30 1 + 303 17 30 0 + 304 20 30 0 + 305 20 30 1 + 306 20 31 0 + 307 20 31 1 + 308 21 30 0 + 309 21 30 1 + 310 21 31 0 + 311 21 31 1 + 312 23 31 1 + 313 23 31 0 + 314 23 30 1 + 315 23 30 0 + 316 22 31 1 + 317 22 31 0 + 318 22 30 1 + 319 22 30 0 + 320 28 31 0 + 321 28 31 1 + 322 28 30 0 + 323 28 30 1 + 324 29 31 0 + 325 29 31 1 + 326 29 30 0 + 327 29 30 1 + 328 31 30 1 + 329 31 30 0 + 330 31 31 1 + 331 31 31 0 + 332 30 30 1 + 333 30 30 0 + 334 30 31 1 + 335 30 31 0 + 384 27 33 0 + 385 27 33 1 + 386 27 32 0 + 387 27 32 1 + 388 26 33 0 + 389 26 33 1 + 390 26 32 0 + 391 26 32 1 + 392 24 32 1 + 393 24 32 0 + 394 24 33 1 + 395 24 33 0 + 396 25 32 1 + 397 25 32 0 + 398 25 33 1 + 399 25 33 0 + 416 19 32 0 + 417 19 32 1 + 418 19 33 0 + 419 19 33 1 + 420 18 32 0 + 421 18 32 1 + 422 18 33 0 + 423 18 33 1 + 424 16 33 1 + 425 16 33 0 + 426 16 32 1 + 427 16 32 0 + 428 17 33 1 + 429 17 33 0 + 430 17 32 1 + 431 17 32 0 + 432 20 32 0 + 433 20 32 1 + 434 20 33 0 + 435 20 33 1 + 436 21 32 0 + 437 21 32 1 + 438 21 33 0 + 439 21 33 1 + 440 23 33 1 + 441 23 33 0 + 442 23 32 1 + 443 23 32 0 + 444 22 33 1 + 445 22 33 0 + 446 22 32 1 + 447 22 32 0 + 448 28 33 0 + 449 28 33 1 + 450 28 32 0 + 451 28 32 1 + 452 29 33 0 + 453 29 33 1 + 454 29 32 0 + 455 29 32 1 + 456 31 32 1 + 457 31 32 0 + 458 31 33 1 + 459 31 33 0 + 460 30 32 1 + 461 30 32 0 + 462 30 33 1 + 463 30 33 0 + 512 27 35 0 + 513 27 35 1 + 514 27 34 0 + 515 27 34 1 + 516 26 35 0 + 517 26 35 1 + 518 26 34 0 + 519 26 34 1 + 520 24 34 1 + 521 24 34 0 + 522 24 35 1 + 523 24 35 0 + 524 25 34 1 + 525 25 34 0 + 526 25 35 1 + 527 25 35 0 + 544 19 34 0 + 545 19 34 1 + 546 19 35 0 + 547 19 35 1 + 548 18 34 0 + 549 18 34 1 + 550 18 35 0 + 551 18 35 1 + 552 16 35 1 + 553 16 35 0 + 554 16 34 1 + 555 16 34 0 + 556 17 35 1 + 557 17 35 0 + 558 17 34 1 + 559 17 34 0 + 560 20 34 0 + 561 20 34 1 + 562 20 35 0 + 563 20 35 1 + 564 21 34 0 + 565 21 34 1 + 566 21 35 0 + 567 21 35 1 + 568 23 35 1 + 569 23 35 0 + 570 23 34 1 + 571 23 34 0 + 572 22 35 1 + 573 22 35 0 + 574 22 34 1 + 575 22 34 0 + 576 28 35 0 + 577 28 35 1 + 578 28 34 0 + 579 28 34 1 + 580 29 35 0 + 581 29 35 1 + 582 29 34 0 + 583 29 34 1 + 584 31 34 1 + 585 31 34 0 + 586 31 35 1 + 587 31 35 0 + 588 30 34 1 + 589 30 34 0 + 590 30 35 1 + 591 30 35 0 + 640 27 37 0 + 641 27 37 1 + 642 27 36 0 + 643 27 36 1 + 644 26 37 0 + 645 26 37 1 + 646 26 36 0 + 647 26 36 1 + 648 24 36 1 + 649 24 36 0 + 650 24 37 1 + 651 24 37 0 + 652 25 36 1 + 653 25 36 0 + 654 25 37 1 + 655 25 37 0 + 672 19 36 0 + 673 19 36 1 + 674 19 37 0 + 675 19 37 1 + 676 18 36 0 + 677 18 36 1 + 678 18 37 0 + 679 18 37 1 + 680 16 37 1 + 681 16 37 0 + 682 16 36 1 + 683 16 36 0 + 684 17 37 1 + 685 17 37 0 + 686 17 36 1 + 687 17 36 0 + 688 20 36 0 + 689 20 36 1 + 690 20 37 0 + 691 20 37 1 + 692 21 36 0 + 693 21 36 1 + 694 21 37 0 + 695 21 37 1 + 696 23 37 1 + 697 23 37 0 + 698 23 36 1 + 699 23 36 0 + 700 22 37 1 + 701 22 37 0 + 702 22 36 1 + 703 22 36 0 + 704 28 37 0 + 705 28 37 1 + 706 28 36 0 + 707 28 36 1 + 708 29 37 0 + 709 29 37 1 + 710 29 36 0 + 711 29 36 1 + 712 31 36 1 + 713 31 36 0 + 714 31 37 1 + 715 31 37 0 + 716 30 36 1 + 717 30 36 0 + 718 30 37 1 + 719 30 37 0 + 768 27 39 0 + 769 27 39 1 + 770 27 38 0 + 771 27 38 1 + 772 26 39 0 + 773 26 39 1 + 774 26 38 0 + 775 26 38 1 + 776 24 38 1 + 777 24 38 0 + 778 24 39 1 + 779 24 39 0 + 780 25 38 1 + 781 25 38 0 + 782 25 39 1 + 783 25 39 0 + 800 19 38 0 + 801 19 38 1 + 802 19 39 0 + 803 19 39 1 + 804 18 38 0 + 805 18 38 1 + 806 18 39 0 + 807 18 39 1 + 808 16 39 1 + 809 16 39 0 + 810 16 38 1 + 811 16 38 0 + 812 17 39 1 + 813 17 39 0 + 814 17 38 1 + 815 17 38 0 + 816 20 38 0 + 817 20 38 1 + 818 20 39 0 + 819 20 39 1 + 820 21 38 0 + 821 21 38 1 + 822 21 39 0 + 823 21 39 1 + 824 23 39 1 + 825 23 39 0 + 826 23 38 1 + 827 23 38 0 + 828 22 39 1 + 829 22 39 0 + 830 22 38 1 + 831 22 38 0 + 832 28 39 0 + 833 28 39 1 + 834 28 38 0 + 835 28 38 1 + 836 29 39 0 + 837 29 39 1 + 838 29 38 0 + 839 29 38 1 + 840 31 38 1 + 841 31 38 0 + 842 31 39 1 + 843 31 39 0 + 844 30 38 1 + 845 30 38 0 + 846 30 39 1 + 847 30 39 0 + 896 27 41 0 + 897 27 41 1 + 898 27 40 0 + 899 27 40 1 + 900 26 41 0 + 901 26 41 1 + 902 26 40 0 + 903 26 40 1 + 904 24 40 1 + 905 24 40 0 + 906 24 41 1 + 907 24 41 0 + 908 25 40 1 + 909 25 40 0 + 910 25 41 1 + 911 25 41 0 + 928 19 40 0 + 929 19 40 1 + 930 19 41 0 + 931 19 41 1 + 932 18 40 0 + 933 18 40 1 + 934 18 41 0 + 935 18 41 1 + 936 16 41 1 + 937 16 41 0 + 938 16 40 1 + 939 16 40 0 + 940 17 41 1 + 941 17 41 0 + 942 17 40 1 + 943 17 40 0 + 944 20 40 0 + 945 20 40 1 + 946 20 41 0 + 947 20 41 1 + 948 21 40 0 + 949 21 40 1 + 950 21 41 0 + 951 21 41 1 + 952 23 41 1 + 953 23 41 0 + 954 23 40 1 + 955 23 40 0 + 956 22 41 1 + 957 22 41 0 + 958 22 40 1 + 959 22 40 0 + 960 28 41 0 + 961 28 41 1 + 962 28 40 0 + 963 28 40 1 + 964 29 41 0 + 965 29 41 1 + 966 29 40 0 + 967 29 40 1 + 968 31 40 1 + 969 31 40 0 + 970 31 41 1 + 971 31 41 0 + 972 30 40 1 + 973 30 40 0 + 974 30 41 1 + 975 30 41 0 +1024 27 43 0 +1025 27 43 1 +1026 27 42 0 +1027 27 42 1 +1028 26 43 0 +1029 26 43 1 +1030 26 42 0 +1031 26 42 1 +1032 24 42 1 +1033 24 42 0 +1034 24 43 1 +1035 24 43 0 +1036 25 42 1 +1037 25 42 0 +1038 25 43 1 +1039 25 43 0 +1056 19 42 0 +1057 19 42 1 +1058 19 43 0 +1059 19 43 1 +1060 18 42 0 +1061 18 42 1 +1062 18 43 0 +1063 18 43 1 +1064 16 43 1 +1065 16 43 0 +1066 16 42 1 +1067 16 42 0 +1068 17 43 1 +1069 17 43 0 +1070 17 42 1 +1071 17 42 0 +1072 20 42 0 +1073 20 42 1 +1074 20 43 0 +1075 20 43 1 +1076 21 42 0 +1077 21 42 1 +1078 21 43 0 +1079 21 43 1 +1080 23 43 1 +1081 23 43 0 +1082 23 42 1 +1083 23 42 0 +1084 22 43 1 +1085 22 43 0 +1086 22 42 1 +1087 22 42 0 +1088 28 43 0 +1089 28 43 1 +1090 28 42 0 +1091 28 42 1 +1092 29 43 0 +1093 29 43 1 +1094 29 42 0 +1095 29 42 1 +1096 31 42 1 +1097 31 42 0 +1098 31 43 1 +1099 31 43 0 +1100 30 42 1 +1101 30 42 0 +1102 30 43 1 +1103 30 43 0 +1152 27 45 0 +1153 27 45 1 +1154 27 44 0 +1155 27 44 1 +1156 26 45 0 +1157 26 45 1 +1158 26 44 0 +1159 26 44 1 +1160 24 44 1 +1161 24 44 0 +1162 24 45 1 +1163 24 45 0 +1164 25 44 1 +1165 25 44 0 +1166 25 45 1 +1167 25 45 0 +1184 19 44 0 +1185 19 44 1 +1186 19 45 0 +1187 19 45 1 +1188 18 44 0 +1189 18 44 1 +1190 18 45 0 +1191 18 45 1 +1192 16 45 1 +1193 16 45 0 +1194 16 44 1 +1195 16 44 0 +1196 17 45 1 +1197 17 45 0 +1198 17 44 1 +1199 17 44 0 +1200 20 44 0 +1201 20 44 1 +1202 20 45 0 +1203 20 45 1 +1204 21 44 0 +1205 21 44 1 +1206 21 45 0 +1207 21 45 1 +1208 23 45 1 +1209 23 45 0 +1210 23 44 1 +1211 23 44 0 +1212 22 45 1 +1213 22 45 0 +1214 22 44 1 +1215 22 44 0 +1216 28 45 0 +1217 28 45 1 +1218 28 44 0 +1219 28 44 1 +1220 29 45 0 +1221 29 45 1 +1222 29 44 0 +1223 29 44 1 +1224 31 44 1 +1225 31 44 0 +1226 31 45 1 +1227 31 45 0 +1228 30 44 1 +1229 30 44 0 +1230 30 45 1 +1231 30 45 0 +1280 27 47 0 +1281 27 47 1 +1282 27 46 0 +1283 27 46 1 +1284 26 47 0 +1285 26 47 1 +1286 26 46 0 +1287 26 46 1 +1288 24 46 1 +1289 24 46 0 +1290 24 47 1 +1291 24 47 0 +1292 25 46 1 +1293 25 46 0 +1294 25 47 1 +1295 25 47 0 +1312 19 46 0 +1313 19 46 1 +1314 19 47 0 +1315 19 47 1 +1316 18 46 0 +1317 18 46 1 +1318 18 47 0 +1319 18 47 1 +1320 16 47 1 +1321 16 47 0 +1322 16 46 1 +1323 16 46 0 +1324 17 47 1 +1325 17 47 0 +1326 17 46 1 +1327 17 46 0 +1328 20 46 0 +1329 20 46 1 +1330 20 47 0 +1331 20 47 1 +1332 21 46 0 +1333 21 46 1 +1334 21 47 0 +1335 21 47 1 +1336 23 47 1 +1337 23 47 0 +1338 23 46 1 +1339 23 46 0 +1340 22 47 1 +1341 22 47 0 +1342 22 46 1 +1343 22 46 0 +1344 28 47 0 +1345 28 47 1 +1346 28 46 0 +1347 28 46 1 +1348 29 47 0 +1349 29 47 1 +1350 29 46 0 +1351 29 46 1 +1352 31 46 1 +1353 31 46 0 +1354 31 47 1 +1355 31 47 0 +1356 30 46 1 +1357 30 46 0 +1358 30 47 1 +1359 30 47 0 +1408 27 49 0 +1409 27 49 1 +1410 27 48 0 +1411 27 48 1 +1412 26 49 0 +1413 26 49 1 +1414 26 48 0 +1415 26 48 1 +1416 24 48 1 +1417 24 48 0 +1418 24 49 1 +1419 24 49 0 +1420 25 48 1 +1421 25 48 0 +1422 25 49 1 +1423 25 49 0 +1440 19 48 0 +1441 19 48 1 +1442 19 49 0 +1443 19 49 1 +1444 18 48 0 +1445 18 48 1 +1446 18 49 0 +1447 18 49 1 +1448 16 49 1 +1449 16 49 0 +1450 16 48 1 +1451 16 48 0 +1452 17 49 1 +1453 17 49 0 +1454 17 48 1 +1455 17 48 0 +1456 20 48 0 +1457 20 48 1 +1458 20 49 0 +1459 20 49 1 +1460 21 48 0 +1461 21 48 1 +1462 21 49 0 +1463 21 49 1 +1464 23 49 1 +1465 23 49 0 +1466 23 48 1 +1467 23 48 0 +1468 22 49 1 +1469 22 49 0 +1470 22 48 1 +1471 22 48 0 +1472 28 49 0 +1473 28 49 1 +1474 28 48 0 +1475 28 48 1 +1476 29 49 0 +1477 29 49 1 +1478 29 48 0 +1479 29 48 1 +1480 31 48 1 +1481 31 48 0 +1482 31 49 1 +1483 31 49 0 +1484 30 48 1 +1485 30 48 0 +1486 30 49 1 +1487 30 49 0 +1536 27 51 0 +1537 27 51 1 +1538 27 50 0 +1539 27 50 1 +1540 26 51 0 +1541 26 51 1 +1542 26 50 0 +1543 26 50 1 +1544 24 50 1 +1545 24 50 0 +1546 24 51 1 +1547 24 51 0 +1548 25 50 1 +1549 25 50 0 +1550 25 51 1 +1551 25 51 0 +1568 19 50 0 +1569 19 50 1 +1570 19 51 0 +1571 19 51 1 +1572 18 50 0 +1573 18 50 1 +1574 18 51 0 +1575 18 51 1 +1576 16 51 1 +1577 16 51 0 +1578 16 50 1 +1579 16 50 0 +1580 17 51 1 +1581 17 51 0 +1582 17 50 1 +1583 17 50 0 +1584 20 50 0 +1585 20 50 1 +1586 20 51 0 +1587 20 51 1 +1588 21 50 0 +1589 21 50 1 +1590 21 51 0 +1591 21 51 1 +1592 23 51 1 +1593 23 51 0 +1594 23 50 1 +1595 23 50 0 +1596 22 51 1 +1597 22 51 0 +1598 22 50 1 +1599 22 50 0 +1600 28 51 0 +1601 28 51 1 +1602 28 50 0 +1603 28 50 1 +1604 29 51 0 +1605 29 51 1 +1606 29 50 0 +1607 29 50 1 +1608 31 50 1 +1609 31 50 0 +1610 31 51 1 +1611 31 51 0 +1612 30 50 1 +1613 30 50 0 +1614 30 51 1 +1615 30 51 0 +1664 27 53 0 +1665 27 53 1 +1666 27 52 0 +1667 27 52 1 +1668 26 53 0 +1669 26 53 1 +1670 26 52 0 +1671 26 52 1 +1672 24 52 1 +1673 24 52 0 +1674 24 53 1 +1675 24 53 0 +1676 25 52 1 +1677 25 52 0 +1678 25 53 1 +1679 25 53 0 +1696 19 52 0 +1697 19 52 1 +1698 19 53 0 +1699 19 53 1 +1700 18 52 0 +1701 18 52 1 +1702 18 53 0 +1703 18 53 1 +1704 16 53 1 +1705 16 53 0 +1706 16 52 1 +1707 16 52 0 +1708 17 53 1 +1709 17 53 0 +1710 17 52 1 +1711 17 52 0 +1712 20 52 0 +1713 20 52 1 +1714 20 53 0 +1715 20 53 1 +1716 21 52 0 +1717 21 52 1 +1718 21 53 0 +1719 21 53 1 +1720 23 53 1 +1721 23 53 0 +1722 23 52 1 +1723 23 52 0 +1724 22 53 1 +1725 22 53 0 +1726 22 52 1 +1727 22 52 0 +1728 28 53 0 +1729 28 53 1 +1730 28 52 0 +1731 28 52 1 +1732 29 53 0 +1733 29 53 1 +1734 29 52 0 +1735 29 52 1 +1736 31 52 1 +1737 31 52 0 +1738 31 53 1 +1739 31 53 0 +1740 30 52 1 +1741 30 52 0 +1742 30 53 1 +1743 30 53 0 +1792 27 55 0 +1793 27 55 1 +1794 27 54 0 +1795 27 54 1 +1796 26 55 0 +1797 26 55 1 +1798 26 54 0 +1799 26 54 1 +1800 24 54 1 +1801 24 54 0 +1802 24 55 1 +1803 24 55 0 +1804 25 54 1 +1805 25 54 0 +1806 25 55 1 +1807 25 55 0 +1824 19 54 0 +1825 19 54 1 +1826 19 55 0 +1827 19 55 1 +1828 18 54 0 +1829 18 54 1 +1830 18 55 0 +1831 18 55 1 +1832 16 55 1 +1833 16 55 0 +1834 16 54 1 +1835 16 54 0 +1836 17 55 1 +1837 17 55 0 +1838 17 54 1 +1839 17 54 0 +1840 20 54 0 +1841 20 54 1 +1842 20 55 0 +1843 20 55 1 +1844 21 54 0 +1845 21 54 1 +1846 21 55 0 +1847 21 55 1 +1848 23 55 1 +1849 23 55 0 +1850 23 54 1 +1851 23 54 0 +1852 22 55 1 +1853 22 55 0 +1854 22 54 1 +1855 22 54 0 +1856 28 55 0 +1857 28 55 1 +1858 28 54 0 +1859 28 54 1 +1860 29 55 0 +1861 29 55 1 +1862 29 54 0 +1863 29 54 1 +1864 31 54 1 +1865 31 54 0 +1866 31 55 1 +1867 31 55 0 +1868 30 54 1 +1869 30 54 0 +1870 30 55 1 +1871 30 55 0 +2176 27 27 0 +2177 27 27 1 +2178 27 26 0 +2179 27 26 1 +2180 26 27 0 +2181 26 27 1 +2182 26 26 0 +2183 26 26 1 +2184 24 26 1 +2185 24 26 0 +2186 24 27 1 +2187 24 27 0 +2188 25 26 1 +2189 25 26 0 +2190 25 27 1 +2191 25 27 0 +2208 19 26 0 +2209 19 26 1 +2210 19 27 0 +2211 19 27 1 +2212 18 26 0 +2213 18 26 1 +2214 18 27 0 +2215 18 27 1 +2216 16 27 1 +2217 16 27 0 +2218 16 26 1 +2219 16 26 0 +2220 17 27 1 +2221 17 27 0 +2222 17 26 1 +2223 17 26 0 +2224 20 26 0 +2225 20 26 1 +2226 20 27 0 +2227 20 27 1 +2228 21 26 0 +2229 21 26 1 +2230 21 27 0 +2231 21 27 1 +2232 23 27 1 +2233 23 27 0 +2234 23 26 1 +2235 23 26 0 +2236 22 27 1 +2237 22 27 0 +2238 22 26 1 +2239 22 26 0 +2240 28 27 0 +2241 28 27 1 +2242 28 26 0 +2243 28 26 1 +2244 29 27 0 +2245 29 27 1 +2246 29 26 0 +2247 29 26 1 +2248 31 26 1 +2249 31 26 0 +2250 31 27 1 +2251 31 27 0 +2252 30 26 1 +2253 30 26 0 +2254 30 27 1 +2255 30 27 0 +2304 27 25 0 +2305 27 25 1 +2306 27 24 0 +2307 27 24 1 +2308 26 25 0 +2309 26 25 1 +2310 26 24 0 +2311 26 24 1 +2312 24 24 1 +2313 24 24 0 +2314 24 25 1 +2315 24 25 0 +2316 25 24 1 +2317 25 24 0 +2318 25 25 1 +2319 25 25 0 +2336 19 24 0 +2337 19 24 1 +2338 19 25 0 +2339 19 25 1 +2340 18 24 0 +2341 18 24 1 +2342 18 25 0 +2343 18 25 1 +2344 16 25 1 +2345 16 25 0 +2346 16 24 1 +2347 16 24 0 +2348 17 25 1 +2349 17 25 0 +2350 17 24 1 +2351 17 24 0 +2352 20 24 0 +2353 20 24 1 +2354 20 25 0 +2355 20 25 1 +2356 21 24 0 +2357 21 24 1 +2358 21 25 0 +2359 21 25 1 +2360 23 25 1 +2361 23 25 0 +2362 23 24 1 +2363 23 24 0 +2364 22 25 1 +2365 22 25 0 +2366 22 24 1 +2367 22 24 0 +2368 28 25 0 +2369 28 25 1 +2370 28 24 0 +2371 28 24 1 +2372 29 25 0 +2373 29 25 1 +2374 29 24 0 +2375 29 24 1 +2376 31 24 1 +2377 31 24 0 +2378 31 25 1 +2379 31 25 0 +2380 30 24 1 +2381 30 24 0 +2382 30 25 1 +2383 30 25 0 +2432 27 23 0 +2433 27 23 1 +2434 27 22 0 +2435 27 22 1 +2436 26 23 0 +2437 26 23 1 +2438 26 22 0 +2439 26 22 1 +2440 24 22 1 +2441 24 22 0 +2442 24 23 1 +2443 24 23 0 +2444 25 22 1 +2445 25 22 0 +2446 25 23 1 +2447 25 23 0 +2464 19 22 0 +2465 19 22 1 +2466 19 23 0 +2467 19 23 1 +2468 18 22 0 +2469 18 22 1 +2470 18 23 0 +2471 18 23 1 +2472 16 23 1 +2473 16 23 0 +2474 16 22 1 +2475 16 22 0 +2476 17 23 1 +2477 17 23 0 +2478 17 22 1 +2479 17 22 0 +2480 20 22 0 +2481 20 22 1 +2482 20 23 0 +2483 20 23 1 +2484 21 22 0 +2485 21 22 1 +2486 21 23 0 +2487 21 23 1 +2488 23 23 1 +2489 23 23 0 +2490 23 22 1 +2491 23 22 0 +2492 22 23 1 +2493 22 23 0 +2494 22 22 1 +2495 22 22 0 +2496 28 23 0 +2497 28 23 1 +2498 28 22 0 +2499 28 22 1 +2500 29 23 0 +2501 29 23 1 +2502 29 22 0 +2503 29 22 1 +2504 31 22 1 +2505 31 22 0 +2506 31 23 1 +2507 31 23 0 +2508 30 22 1 +2509 30 22 0 +2510 30 23 1 +2511 30 23 0 +2560 27 21 0 +2561 27 21 1 +2562 27 20 0 +2563 27 20 1 +2564 26 21 0 +2565 26 21 1 +2566 26 20 0 +2567 26 20 1 +2568 24 20 1 +2569 24 20 0 +2570 24 21 1 +2571 24 21 0 +2572 25 20 1 +2573 25 20 0 +2574 25 21 1 +2575 25 21 0 +2592 19 20 0 +2593 19 20 1 +2594 19 21 0 +2595 19 21 1 +2596 18 20 0 +2597 18 20 1 +2598 18 21 0 +2599 18 21 1 +2600 16 21 1 +2601 16 21 0 +2602 16 20 1 +2603 16 20 0 +2604 17 21 1 +2605 17 21 0 +2606 17 20 1 +2607 17 20 0 +2608 20 20 0 +2609 20 20 1 +2610 20 21 0 +2611 20 21 1 +2612 21 20 0 +2613 21 20 1 +2614 21 21 0 +2615 21 21 1 +2616 23 21 1 +2617 23 21 0 +2618 23 20 1 +2619 23 20 0 +2620 22 21 1 +2621 22 21 0 +2622 22 20 1 +2623 22 20 0 +2624 28 21 0 +2625 28 21 1 +2626 28 20 0 +2627 28 20 1 +2628 29 21 0 +2629 29 21 1 +2630 29 20 0 +2631 29 20 1 +2632 31 20 1 +2633 31 20 0 +2634 31 21 1 +2635 31 21 0 +2636 30 20 1 +2637 30 20 0 +2638 30 21 1 +2639 30 21 0 +2688 27 19 0 +2689 27 19 1 +2690 27 18 0 +2691 27 18 1 +2692 26 19 0 +2693 26 19 1 +2694 26 18 0 +2695 26 18 1 +2696 24 18 1 +2697 24 18 0 +2698 24 19 1 +2699 24 19 0 +2700 25 18 1 +2701 25 18 0 +2702 25 19 1 +2703 25 19 0 +2720 19 18 0 +2721 19 18 1 +2722 19 19 0 +2723 19 19 1 +2724 18 18 0 +2725 18 18 1 +2726 18 19 0 +2727 18 19 1 +2728 16 19 1 +2729 16 19 0 +2730 16 18 1 +2731 16 18 0 +2732 17 19 1 +2733 17 19 0 +2734 17 18 1 +2735 17 18 0 +2736 20 18 0 +2737 20 18 1 +2738 20 19 0 +2739 20 19 1 +2740 21 18 0 +2741 21 18 1 +2742 21 19 0 +2743 21 19 1 +2744 23 19 1 +2745 23 19 0 +2746 23 18 1 +2747 23 18 0 +2748 22 19 1 +2749 22 19 0 +2750 22 18 1 +2751 22 18 0 +2752 28 19 0 +2753 28 19 1 +2754 28 18 0 +2755 28 18 1 +2756 29 19 0 +2757 29 19 1 +2758 29 18 0 +2759 29 18 1 +2760 31 18 1 +2761 31 18 0 +2762 31 19 1 +2763 31 19 0 +2764 30 18 1 +2765 30 18 0 +2766 30 19 1 +2767 30 19 0 +2816 27 17 0 +2817 27 17 1 +2818 27 16 0 +2819 27 16 1 +2820 26 17 0 +2821 26 17 1 +2822 26 16 0 +2823 26 16 1 +2824 24 16 1 +2825 24 16 0 +2826 24 17 1 +2827 24 17 0 +2828 25 16 1 +2829 25 16 0 +2830 25 17 1 +2831 25 17 0 +2848 19 16 0 +2849 19 16 1 +2850 19 17 0 +2851 19 17 1 +2852 18 16 0 +2853 18 16 1 +2854 18 17 0 +2855 18 17 1 +2856 16 17 1 +2857 16 17 0 +2858 16 16 1 +2859 16 16 0 +2860 17 17 1 +2861 17 17 0 +2862 17 16 1 +2863 17 16 0 +2864 20 16 0 +2865 20 16 1 +2866 20 17 0 +2867 20 17 1 +2868 21 16 0 +2869 21 16 1 +2870 21 17 0 +2871 21 17 1 +2872 23 17 1 +2873 23 17 0 +2874 23 16 1 +2875 23 16 0 +2876 22 17 1 +2877 22 17 0 +2878 22 16 1 +2879 22 16 0 +2880 28 17 0 +2881 28 17 1 +2882 28 16 0 +2883 28 16 1 +2884 29 17 0 +2885 29 17 1 +2886 29 16 0 +2887 29 16 1 +2888 31 16 1 +2889 31 16 0 +2890 31 17 1 +2891 31 17 0 +2892 30 16 1 +2893 30 16 0 +2894 30 17 1 +2895 30 17 0 +2944 27 15 0 +2945 27 15 1 +2946 27 14 0 +2947 27 14 1 +2948 26 15 0 +2949 26 15 1 +2950 26 14 0 +2951 26 14 1 +2952 24 14 1 +2953 24 14 0 +2954 24 15 1 +2955 24 15 0 +2956 25 14 1 +2957 25 14 0 +2958 25 15 1 +2959 25 15 0 +2976 19 14 0 +2977 19 14 1 +2978 19 15 0 +2979 19 15 1 +2980 18 14 0 +2981 18 14 1 +2982 18 15 0 +2983 18 15 1 +2984 16 15 1 +2985 16 15 0 +2986 16 14 1 +2987 16 14 0 +2988 17 15 1 +2989 17 15 0 +2990 17 14 1 +2991 17 14 0 +2992 20 14 0 +2993 20 14 1 +2994 20 15 0 +2995 20 15 1 +2996 21 14 0 +2997 21 14 1 +2998 21 15 0 +2999 21 15 1 +3000 23 15 1 +3001 23 15 0 +3002 23 14 1 +3003 23 14 0 +3004 22 15 1 +3005 22 15 0 +3006 22 14 1 +3007 22 14 0 +3008 28 15 0 +3009 28 15 1 +3010 28 14 0 +3011 28 14 1 +3012 29 15 0 +3013 29 15 1 +3014 29 14 0 +3015 29 14 1 +3016 31 14 1 +3017 31 14 0 +3018 31 15 1 +3019 31 15 0 +3020 30 14 1 +3021 30 14 0 +3022 30 15 1 +3023 30 15 0 +3072 27 13 0 +3073 27 13 1 +3074 27 12 0 +3075 27 12 1 +3076 26 13 0 +3077 26 13 1 +3078 26 12 0 +3079 26 12 1 +3080 24 12 1 +3081 24 12 0 +3082 24 13 1 +3083 24 13 0 +3084 25 12 1 +3085 25 12 0 +3086 25 13 1 +3087 25 13 0 +3104 19 12 0 +3105 19 12 1 +3106 19 13 0 +3107 19 13 1 +3108 18 12 0 +3109 18 12 1 +3110 18 13 0 +3111 18 13 1 +3112 16 13 1 +3113 16 13 0 +3114 16 12 1 +3115 16 12 0 +3116 17 13 1 +3117 17 13 0 +3118 17 12 1 +3119 17 12 0 +3120 20 12 0 +3121 20 12 1 +3122 20 13 0 +3123 20 13 1 +3124 21 12 0 +3125 21 12 1 +3126 21 13 0 +3127 21 13 1 +3128 23 13 1 +3129 23 13 0 +3130 23 12 1 +3131 23 12 0 +3132 22 13 1 +3133 22 13 0 +3134 22 12 1 +3135 22 12 0 +3136 28 13 0 +3137 28 13 1 +3138 28 12 0 +3139 28 12 1 +3140 29 13 0 +3141 29 13 1 +3142 29 12 0 +3143 29 12 1 +3144 31 12 1 +3145 31 12 0 +3146 31 13 1 +3147 31 13 0 +3148 30 12 1 +3149 30 12 0 +3150 30 13 1 +3151 30 13 0 +3200 27 11 0 +3201 27 11 1 +3202 27 10 0 +3203 27 10 1 +3204 26 11 0 +3205 26 11 1 +3206 26 10 0 +3207 26 10 1 +3208 24 10 1 +3209 24 10 0 +3210 24 11 1 +3211 24 11 0 +3212 25 10 1 +3213 25 10 0 +3214 25 11 1 +3215 25 11 0 +3232 19 10 0 +3233 19 10 1 +3234 19 11 0 +3235 19 11 1 +3236 18 10 0 +3237 18 10 1 +3238 18 11 0 +3239 18 11 1 +3240 16 11 1 +3241 16 11 0 +3242 16 10 1 +3243 16 10 0 +3244 17 11 1 +3245 17 11 0 +3246 17 10 1 +3247 17 10 0 +3248 20 10 0 +3249 20 10 1 +3250 20 11 0 +3251 20 11 1 +3252 21 10 0 +3253 21 10 1 +3254 21 11 0 +3255 21 11 1 +3256 23 11 1 +3257 23 11 0 +3258 23 10 1 +3259 23 10 0 +3260 22 11 1 +3261 22 11 0 +3262 22 10 1 +3263 22 10 0 +3264 28 11 0 +3265 28 11 1 +3266 28 10 0 +3267 28 10 1 +3268 29 11 0 +3269 29 11 1 +3270 29 10 0 +3271 29 10 1 +3272 31 10 1 +3273 31 10 0 +3274 31 11 1 +3275 31 11 0 +3276 30 10 1 +3277 30 10 0 +3278 30 11 1 +3279 30 11 0 +3328 27 9 0 +3329 27 9 1 +3330 27 8 0 +3331 27 8 1 +3332 26 9 0 +3333 26 9 1 +3334 26 8 0 +3335 26 8 1 +3336 24 8 1 +3337 24 8 0 +3338 24 9 1 +3339 24 9 0 +3340 25 8 1 +3341 25 8 0 +3342 25 9 1 +3343 25 9 0 +3360 19 8 0 +3361 19 8 1 +3362 19 9 0 +3363 19 9 1 +3364 18 8 0 +3365 18 8 1 +3366 18 9 0 +3367 18 9 1 +3368 16 9 1 +3369 16 9 0 +3370 16 8 1 +3371 16 8 0 +3372 17 9 1 +3373 17 9 0 +3374 17 8 1 +3375 17 8 0 +3376 20 8 0 +3377 20 8 1 +3378 20 9 0 +3379 20 9 1 +3380 21 8 0 +3381 21 8 1 +3382 21 9 0 +3383 21 9 1 +3384 23 9 1 +3385 23 9 0 +3386 23 8 1 +3387 23 8 0 +3388 22 9 1 +3389 22 9 0 +3390 22 8 1 +3391 22 8 0 +3392 28 9 0 +3393 28 9 1 +3394 28 8 0 +3395 28 8 1 +3396 29 9 0 +3397 29 9 1 +3398 29 8 0 +3399 29 8 1 +3400 31 8 1 +3401 31 8 0 +3402 31 9 1 +3403 31 9 0 +3404 30 8 1 +3405 30 8 0 +3406 30 9 1 +3407 30 9 0 +3456 27 7 0 +3457 27 7 1 +3458 27 6 0 +3459 27 6 1 +3460 26 7 0 +3461 26 7 1 +3462 26 6 0 +3463 26 6 1 +3464 24 6 1 +3465 24 6 0 +3466 24 7 1 +3467 24 7 0 +3468 25 6 1 +3469 25 6 0 +3470 25 7 1 +3471 25 7 0 +3488 19 6 0 +3489 19 6 1 +3490 19 7 0 +3491 19 7 1 +3492 18 6 0 +3493 18 6 1 +3494 18 7 0 +3495 18 7 1 +3496 16 7 1 +3497 16 7 0 +3498 16 6 1 +3499 16 6 0 +3500 17 7 1 +3501 17 7 0 +3502 17 6 1 +3503 17 6 0 +3504 20 6 0 +3505 20 6 1 +3506 20 7 0 +3507 20 7 1 +3508 21 6 0 +3509 21 6 1 +3510 21 7 0 +3511 21 7 1 +3512 23 7 1 +3513 23 7 0 +3514 23 6 1 +3515 23 6 0 +3516 22 7 1 +3517 22 7 0 +3518 22 6 1 +3519 22 6 0 +3520 28 7 0 +3521 28 7 1 +3522 28 6 0 +3523 28 6 1 +3524 29 7 0 +3525 29 7 1 +3526 29 6 0 +3527 29 6 1 +3528 31 6 1 +3529 31 6 0 +3530 31 7 1 +3531 31 7 0 +3532 30 6 1 +3533 30 6 0 +3534 30 7 1 +3535 30 7 0 +3584 27 5 0 +3585 27 5 1 +3586 27 4 0 +3587 27 4 1 +3588 26 5 0 +3589 26 5 1 +3590 26 4 0 +3591 26 4 1 +3592 24 4 1 +3593 24 4 0 +3594 24 5 1 +3595 24 5 0 +3596 25 4 1 +3597 25 4 0 +3598 25 5 1 +3599 25 5 0 +3616 19 4 0 +3617 19 4 1 +3618 19 5 0 +3619 19 5 1 +3620 18 4 0 +3621 18 4 1 +3622 18 5 0 +3623 18 5 1 +3624 16 5 1 +3625 16 5 0 +3626 16 4 1 +3627 16 4 0 +3628 17 5 1 +3629 17 5 0 +3630 17 4 1 +3631 17 4 0 +3632 20 4 0 +3633 20 4 1 +3634 20 5 0 +3635 20 5 1 +3636 21 4 0 +3637 21 4 1 +3638 21 5 0 +3639 21 5 1 +3640 23 5 1 +3641 23 5 0 +3642 23 4 1 +3643 23 4 0 +3644 22 5 1 +3645 22 5 0 +3646 22 4 1 +3647 22 4 0 +3648 28 5 0 +3649 28 5 1 +3650 28 4 0 +3651 28 4 1 +3652 29 5 0 +3653 29 5 1 +3654 29 4 0 +3655 29 4 1 +3656 31 4 1 +3657 31 4 0 +3658 31 5 1 +3659 31 5 0 +3660 30 4 1 +3661 30 4 0 +3662 30 5 1 +3663 30 5 0 +3712 27 3 0 +3713 27 3 1 +3714 27 2 0 +3715 27 2 1 +3716 26 3 0 +3717 26 3 1 +3718 26 2 0 +3719 26 2 1 +3720 24 2 1 +3721 24 2 0 +3722 24 3 1 +3723 24 3 0 +3724 25 2 1 +3725 25 2 0 +3726 25 3 1 +3727 25 3 0 +3744 19 2 0 +3745 19 2 1 +3746 19 3 0 +3747 19 3 1 +3748 18 2 0 +3749 18 2 1 +3750 18 3 0 +3751 18 3 1 +3752 16 3 1 +3753 16 3 0 +3754 16 2 1 +3755 16 2 0 +3756 17 3 1 +3757 17 3 0 +3758 17 2 1 +3759 17 2 0 +3760 20 2 0 +3761 20 2 1 +3762 20 3 0 +3763 20 3 1 +3764 21 2 0 +3765 21 2 1 +3766 21 3 0 +3767 21 3 1 +3768 23 3 1 +3769 23 3 0 +3770 23 2 1 +3771 23 2 0 +3772 22 3 1 +3773 22 3 0 +3774 22 2 1 +3775 22 2 0 +3776 28 3 0 +3777 28 3 1 +3778 28 2 0 +3779 28 2 1 +3780 29 3 0 +3781 29 3 1 +3782 29 2 0 +3783 29 2 1 +3784 31 2 1 +3785 31 2 0 +3786 31 3 1 +3787 31 3 0 +3788 30 2 1 +3789 30 2 0 +3790 30 3 1 +3791 30 3 0 +3840 27 1 0 +3841 27 1 1 +3842 27 0 0 +3843 27 0 1 +3844 26 1 0 +3845 26 1 1 +3846 26 0 0 +3847 26 0 1 +3848 24 0 1 +3849 24 0 0 +3850 24 1 1 +3851 24 1 0 +3852 25 0 1 +3853 25 0 0 +3854 25 1 1 +3855 25 1 0 +3872 19 0 0 +3873 19 0 1 +3874 19 1 0 +3875 19 1 1 +3876 18 0 0 +3877 18 0 1 +3878 18 1 0 +3879 18 1 1 +3880 16 1 1 +3881 16 1 0 +3882 16 0 1 +3883 16 0 0 +3884 17 1 1 +3885 17 1 0 +3886 17 0 1 +3887 17 0 0 +3888 20 0 0 +3889 20 0 1 +3890 20 1 0 +3891 20 1 1 +3892 21 0 0 +3893 21 0 1 +3894 21 1 0 +3895 21 1 1 +3896 23 1 1 +3897 23 1 0 +3898 23 0 1 +3899 23 0 0 +3900 22 1 1 +3901 22 1 0 +3902 22 0 1 +3903 22 0 0 +3904 28 1 0 +3905 28 1 1 +3906 28 0 0 +3907 28 0 1 +3908 29 1 0 +3909 29 1 1 +3910 29 0 0 +3911 29 0 1 +3912 31 0 1 +3913 31 0 0 +3914 31 1 1 +3915 31 1 0 +3916 30 0 1 +3917 30 0 0 +3918 30 1 1 +3919 30 1 0 diff --git a/Detectors/PHOS/base/files/Mod3RCU2.data b/Detectors/PHOS/base/files/Mod3RCU2.data new file mode 100644 index 0000000000000..21de94d7ace53 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod3RCU2.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 2 0 2 + 1 2 1 2 + 2 2 2 2 + 3 2 3 2 + 4 2 4 2 + 5 2 5 2 + 6 2 6 2 + 7 2 7 2 + 8 2 8 2 + 9 2 9 2 + 10 2 10 2 + 11 2 11 2 + 12 2 12 2 + 13 2 13 2 + 14 2 14 2 + 15 2 15 2 + 16 2 16 2 + 17 2 17 2 + 18 2 18 2 + 19 2 19 2 + 20 2 20 2 + 21 2 21 2 + 22 2 22 2 + 23 2 23 2 + 24 2 24 2 + 25 2 25 2 + 26 2 26 2 + 27 2 27 2 + 28 2 28 2 + 29 2 29 2 + 30 2 30 2 + 31 2 31 2 + 32 2 32 2 + 33 2 33 2 + 34 2 34 2 + 35 2 35 2 + 36 2 36 2 + 37 2 37 2 + 38 2 38 2 + 39 2 39 2 + 40 2 40 2 + 41 2 41 2 + 42 2 42 2 + 43 2 43 2 + 44 2 44 2 + 45 2 45 2 + 46 2 46 2 + 47 2 47 2 + 48 2 48 2 + 49 2 49 2 + 50 2 50 2 + 51 2 51 2 + 52 2 52 2 + 53 2 53 2 + 54 2 54 2 + 55 2 55 2 + 56 2 56 2 + 57 2 57 2 + 58 2 58 2 + 59 2 59 2 + 60 2 60 2 + 61 2 61 2 + 62 2 62 2 + 63 2 63 2 + 64 2 64 2 + 65 2 65 2 + 66 2 66 2 + 67 2 67 2 + 68 2 68 2 + 69 2 69 2 + 70 2 70 2 + 71 2 71 2 + 72 2 72 2 + 73 2 73 2 + 74 2 74 2 + 75 2 75 2 + 76 2 76 2 + 77 2 77 2 + 78 2 78 2 + 79 2 79 2 + 80 2 80 2 + 81 2 81 2 + 82 2 82 2 + 83 2 83 2 + 84 2 84 2 + 85 2 85 2 + 86 2 86 2 + 87 2 87 2 + 88 2 88 2 + 89 2 89 2 + 90 2 90 2 + 91 2 91 2 + 92 2 92 2 + 93 2 93 2 + 94 2 94 2 + 95 2 95 2 + 96 2 96 2 + 97 2 97 2 + 98 2 98 2 + 99 2 99 2 + 100 2 100 2 + 101 2 101 2 + 102 2 102 2 + 103 2 103 2 + 104 2 104 2 + 105 2 105 2 + 106 2 106 2 + 107 2 107 2 + 108 2 108 2 + 109 2 109 2 + 110 2 110 2 + 111 2 111 2 + 112 2 112 2 + 113 2 113 2 + 114 2 114 2 + 115 2 115 2 + 116 2 116 2 + 117 2 117 2 + 118 2 118 2 + 119 2 119 2 + 120 2 120 2 + 121 2 121 2 + 122 2 122 2 + 123 2 123 2 + 124 2 124 2 + 125 2 125 2 + 126 2 126 2 + 127 2 127 2 +2048 2 2048 2 +2049 2 2049 2 +2050 2 2050 2 +2051 2 2051 2 +2052 2 2052 2 +2053 2 2053 2 +2054 2 2054 2 +2055 2 2055 2 +2056 2 2056 2 +2057 2 2057 2 +2058 2 2058 2 +2059 2 2059 2 +2060 2 2060 2 +2061 2 2061 2 +2062 2 2062 2 +2063 2 2063 2 +2064 2 2064 2 +2065 2 2065 2 +2066 2 2066 2 +2067 2 2067 2 +2068 2 2068 2 +2069 2 2069 2 +2070 2 2070 2 +2071 2 2071 2 +2072 2 2072 2 +2073 2 2073 2 +2074 2 2074 2 +2075 2 2075 2 +2076 2 2076 2 +2077 2 2077 2 +2078 2 2078 2 +2079 2 2079 2 +2080 2 2080 2 +2081 2 2081 2 +2082 2 2082 2 +2083 2 2083 2 +2084 2 2084 2 +2085 2 2085 2 +2086 2 2086 2 +2087 2 2087 2 +2088 2 2088 2 +2089 2 2089 2 +2090 2 2090 2 +2091 2 2091 2 +2092 2 2092 2 +2093 2 2093 2 +2094 2 2094 2 +2095 2 2095 2 +2096 2 2096 2 +2097 2 2097 2 +2098 2 2098 2 +2099 2 2099 2 +2100 2 2100 2 +2101 2 2101 2 +2102 2 2102 2 +2103 2 2103 2 +2104 2 2104 2 +2105 2 2105 2 +2106 2 2106 2 +2107 2 2107 2 +2108 2 2108 2 +2109 2 2109 2 +2110 2 2110 2 +2111 2 2111 2 +2112 2 2112 2 +2113 2 2113 2 +2114 2 2114 2 +2115 2 2115 2 +2116 2 2116 2 +2117 2 2117 2 +2118 2 2118 2 +2119 2 2119 2 +2120 2 2120 2 +2121 2 2121 2 +2122 2 2122 2 +2123 2 2123 2 +2124 2 2124 2 +2125 2 2125 2 +2126 2 2126 2 +2127 2 2127 2 +2128 2 2128 2 +2129 2 2129 2 +2130 2 2130 2 +2131 2 2131 2 +2132 2 2132 2 +2133 2 2133 2 +2134 2 2134 2 +2135 2 2135 2 +2136 2 2136 2 +2137 2 2137 2 +2138 2 2138 2 +2139 2 2139 2 +2140 2 2140 2 +2141 2 2141 2 +2142 2 2142 2 +2143 2 2143 2 +2144 2 2144 2 +2145 2 2145 2 +2146 2 2146 2 +2147 2 2147 2 +2148 2 2148 2 +2149 2 2149 2 +2150 2 2150 2 +2151 2 2151 2 +2152 2 2152 2 +2153 2 2153 2 +2154 2 2154 2 +2155 2 2155 2 +2156 2 2156 2 +2157 2 2157 2 +2158 2 2158 2 +2159 2 2159 2 +2160 2 2160 2 +2161 2 2161 2 +2162 2 2162 2 +2163 2 2163 2 +2164 2 2164 2 +2165 2 2165 2 +2166 2 2166 2 +2167 2 2167 2 +2168 2 2168 2 +2169 2 2169 2 +2170 2 2170 2 +2171 2 2171 2 +2172 2 2172 2 +2173 2 2173 2 +2174 2 2174 2 +2175 2 2175 2 + 128 43 29 0 + 129 43 29 1 + 130 43 28 0 + 131 43 28 1 + 132 42 29 0 + 133 42 29 1 + 134 42 28 0 + 135 42 28 1 + 136 40 28 1 + 137 40 28 0 + 138 40 29 1 + 139 40 29 0 + 140 41 28 1 + 141 41 28 0 + 142 41 29 1 + 143 41 29 0 + 160 35 28 0 + 161 35 28 1 + 162 35 29 0 + 163 35 29 1 + 164 34 28 0 + 165 34 28 1 + 166 34 29 0 + 167 34 29 1 + 168 32 29 1 + 169 32 29 0 + 170 32 28 1 + 171 32 28 0 + 172 33 29 1 + 173 33 29 0 + 174 33 28 1 + 175 33 28 0 + 176 36 28 0 + 177 36 28 1 + 178 36 29 0 + 179 36 29 1 + 180 37 28 0 + 181 37 28 1 + 182 37 29 0 + 183 37 29 1 + 184 39 29 1 + 185 39 29 0 + 186 39 28 1 + 187 39 28 0 + 188 38 29 1 + 189 38 29 0 + 190 38 28 1 + 191 38 28 0 + 192 44 29 0 + 193 44 29 1 + 194 44 28 0 + 195 44 28 1 + 196 45 29 0 + 197 45 29 1 + 198 45 28 0 + 199 45 28 1 + 200 47 28 1 + 201 47 28 0 + 202 47 29 1 + 203 47 29 0 + 204 46 28 1 + 205 46 28 0 + 206 46 29 1 + 207 46 29 0 + 256 43 31 0 + 257 43 31 1 + 258 43 30 0 + 259 43 30 1 + 260 42 31 0 + 261 42 31 1 + 262 42 30 0 + 263 42 30 1 + 264 40 30 1 + 265 40 30 0 + 266 40 31 1 + 267 40 31 0 + 268 41 30 1 + 269 41 30 0 + 270 41 31 1 + 271 41 31 0 + 288 35 30 0 + 289 35 30 1 + 290 35 31 0 + 291 35 31 1 + 292 34 30 0 + 293 34 30 1 + 294 34 31 0 + 295 34 31 1 + 296 32 31 1 + 297 32 31 0 + 298 32 30 1 + 299 32 30 0 + 300 33 31 1 + 301 33 31 0 + 302 33 30 1 + 303 33 30 0 + 304 36 30 0 + 305 36 30 1 + 306 36 31 0 + 307 36 31 1 + 308 37 30 0 + 309 37 30 1 + 310 37 31 0 + 311 37 31 1 + 312 39 31 1 + 313 39 31 0 + 314 39 30 1 + 315 39 30 0 + 316 38 31 1 + 317 38 31 0 + 318 38 30 1 + 319 38 30 0 + 320 44 31 0 + 321 44 31 1 + 322 44 30 0 + 323 44 30 1 + 324 45 31 0 + 325 45 31 1 + 326 45 30 0 + 327 45 30 1 + 328 47 30 1 + 329 47 30 0 + 330 47 31 1 + 331 47 31 0 + 332 46 30 1 + 333 46 30 0 + 334 46 31 1 + 335 46 31 0 + 384 43 33 0 + 385 43 33 1 + 386 43 32 0 + 387 43 32 1 + 388 42 33 0 + 389 42 33 1 + 390 42 32 0 + 391 42 32 1 + 392 40 32 1 + 393 40 32 0 + 394 40 33 1 + 395 40 33 0 + 396 41 32 1 + 397 41 32 0 + 398 41 33 1 + 399 41 33 0 + 416 35 32 0 + 417 35 32 1 + 418 35 33 0 + 419 35 33 1 + 420 34 32 0 + 421 34 32 1 + 422 34 33 0 + 423 34 33 1 + 424 32 33 1 + 425 32 33 0 + 426 32 32 1 + 427 32 32 0 + 428 33 33 1 + 429 33 33 0 + 430 33 32 1 + 431 33 32 0 + 432 36 32 0 + 433 36 32 1 + 434 36 33 0 + 435 36 33 1 + 436 37 32 0 + 437 37 32 1 + 438 37 33 0 + 439 37 33 1 + 440 39 33 1 + 441 39 33 0 + 442 39 32 1 + 443 39 32 0 + 444 38 33 1 + 445 38 33 0 + 446 38 32 1 + 447 38 32 0 + 448 44 33 0 + 449 44 33 1 + 450 44 32 0 + 451 44 32 1 + 452 45 33 0 + 453 45 33 1 + 454 45 32 0 + 455 45 32 1 + 456 47 32 1 + 457 47 32 0 + 458 47 33 1 + 459 47 33 0 + 460 46 32 1 + 461 46 32 0 + 462 46 33 1 + 463 46 33 0 + 512 43 35 0 + 513 43 35 1 + 514 43 34 0 + 515 43 34 1 + 516 42 35 0 + 517 42 35 1 + 518 42 34 0 + 519 42 34 1 + 520 40 34 1 + 521 40 34 0 + 522 40 35 1 + 523 40 35 0 + 524 41 34 1 + 525 41 34 0 + 526 41 35 1 + 527 41 35 0 + 544 35 34 0 + 545 35 34 1 + 546 35 35 0 + 547 35 35 1 + 548 34 34 0 + 549 34 34 1 + 550 34 35 0 + 551 34 35 1 + 552 32 35 1 + 553 32 35 0 + 554 32 34 1 + 555 32 34 0 + 556 33 35 1 + 557 33 35 0 + 558 33 34 1 + 559 33 34 0 + 560 36 34 0 + 561 36 34 1 + 562 36 35 0 + 563 36 35 1 + 564 37 34 0 + 565 37 34 1 + 566 37 35 0 + 567 37 35 1 + 568 39 35 1 + 569 39 35 0 + 570 39 34 1 + 571 39 34 0 + 572 38 35 1 + 573 38 35 0 + 574 38 34 1 + 575 38 34 0 + 576 44 35 0 + 577 44 35 1 + 578 44 34 0 + 579 44 34 1 + 580 45 35 0 + 581 45 35 1 + 582 45 34 0 + 583 45 34 1 + 584 47 34 1 + 585 47 34 0 + 586 47 35 1 + 587 47 35 0 + 588 46 34 1 + 589 46 34 0 + 590 46 35 1 + 591 46 35 0 + 640 43 37 0 + 641 43 37 1 + 642 43 36 0 + 643 43 36 1 + 644 42 37 0 + 645 42 37 1 + 646 42 36 0 + 647 42 36 1 + 648 40 36 1 + 649 40 36 0 + 650 40 37 1 + 651 40 37 0 + 652 41 36 1 + 653 41 36 0 + 654 41 37 1 + 655 41 37 0 + 672 35 36 0 + 673 35 36 1 + 674 35 37 0 + 675 35 37 1 + 676 34 36 0 + 677 34 36 1 + 678 34 37 0 + 679 34 37 1 + 680 32 37 1 + 681 32 37 0 + 682 32 36 1 + 683 32 36 0 + 684 33 37 1 + 685 33 37 0 + 686 33 36 1 + 687 33 36 0 + 688 36 36 0 + 689 36 36 1 + 690 36 37 0 + 691 36 37 1 + 692 37 36 0 + 693 37 36 1 + 694 37 37 0 + 695 37 37 1 + 696 39 37 1 + 697 39 37 0 + 698 39 36 1 + 699 39 36 0 + 700 38 37 1 + 701 38 37 0 + 702 38 36 1 + 703 38 36 0 + 704 44 37 0 + 705 44 37 1 + 706 44 36 0 + 707 44 36 1 + 708 45 37 0 + 709 45 37 1 + 710 45 36 0 + 711 45 36 1 + 712 47 36 1 + 713 47 36 0 + 714 47 37 1 + 715 47 37 0 + 716 46 36 1 + 717 46 36 0 + 718 46 37 1 + 719 46 37 0 + 768 43 39 0 + 769 43 39 1 + 770 43 38 0 + 771 43 38 1 + 772 42 39 0 + 773 42 39 1 + 774 42 38 0 + 775 42 38 1 + 776 40 38 1 + 777 40 38 0 + 778 40 39 1 + 779 40 39 0 + 780 41 38 1 + 781 41 38 0 + 782 41 39 1 + 783 41 39 0 + 800 35 38 0 + 801 35 38 1 + 802 35 39 0 + 803 35 39 1 + 804 34 38 0 + 805 34 38 1 + 806 34 39 0 + 807 34 39 1 + 808 32 39 1 + 809 32 39 0 + 810 32 38 1 + 811 32 38 0 + 812 33 39 1 + 813 33 39 0 + 814 33 38 1 + 815 33 38 0 + 816 36 38 0 + 817 36 38 1 + 818 36 39 0 + 819 36 39 1 + 820 37 38 0 + 821 37 38 1 + 822 37 39 0 + 823 37 39 1 + 824 39 39 1 + 825 39 39 0 + 826 39 38 1 + 827 39 38 0 + 828 38 39 1 + 829 38 39 0 + 830 38 38 1 + 831 38 38 0 + 832 44 39 0 + 833 44 39 1 + 834 44 38 0 + 835 44 38 1 + 836 45 39 0 + 837 45 39 1 + 838 45 38 0 + 839 45 38 1 + 840 47 38 1 + 841 47 38 0 + 842 47 39 1 + 843 47 39 0 + 844 46 38 1 + 845 46 38 0 + 846 46 39 1 + 847 46 39 0 + 896 43 41 0 + 897 43 41 1 + 898 43 40 0 + 899 43 40 1 + 900 42 41 0 + 901 42 41 1 + 902 42 40 0 + 903 42 40 1 + 904 40 40 1 + 905 40 40 0 + 906 40 41 1 + 907 40 41 0 + 908 41 40 1 + 909 41 40 0 + 910 41 41 1 + 911 41 41 0 + 928 35 40 0 + 929 35 40 1 + 930 35 41 0 + 931 35 41 1 + 932 34 40 0 + 933 34 40 1 + 934 34 41 0 + 935 34 41 1 + 936 32 41 1 + 937 32 41 0 + 938 32 40 1 + 939 32 40 0 + 940 33 41 1 + 941 33 41 0 + 942 33 40 1 + 943 33 40 0 + 944 36 40 0 + 945 36 40 1 + 946 36 41 0 + 947 36 41 1 + 948 37 40 0 + 949 37 40 1 + 950 37 41 0 + 951 37 41 1 + 952 39 41 1 + 953 39 41 0 + 954 39 40 1 + 955 39 40 0 + 956 38 41 1 + 957 38 41 0 + 958 38 40 1 + 959 38 40 0 + 960 44 41 0 + 961 44 41 1 + 962 44 40 0 + 963 44 40 1 + 964 45 41 0 + 965 45 41 1 + 966 45 40 0 + 967 45 40 1 + 968 47 40 1 + 969 47 40 0 + 970 47 41 1 + 971 47 41 0 + 972 46 40 1 + 973 46 40 0 + 974 46 41 1 + 975 46 41 0 +1024 43 43 0 +1025 43 43 1 +1026 43 42 0 +1027 43 42 1 +1028 42 43 0 +1029 42 43 1 +1030 42 42 0 +1031 42 42 1 +1032 40 42 1 +1033 40 42 0 +1034 40 43 1 +1035 40 43 0 +1036 41 42 1 +1037 41 42 0 +1038 41 43 1 +1039 41 43 0 +1056 35 42 0 +1057 35 42 1 +1058 35 43 0 +1059 35 43 1 +1060 34 42 0 +1061 34 42 1 +1062 34 43 0 +1063 34 43 1 +1064 32 43 1 +1065 32 43 0 +1066 32 42 1 +1067 32 42 0 +1068 33 43 1 +1069 33 43 0 +1070 33 42 1 +1071 33 42 0 +1072 36 42 0 +1073 36 42 1 +1074 36 43 0 +1075 36 43 1 +1076 37 42 0 +1077 37 42 1 +1078 37 43 0 +1079 37 43 1 +1080 39 43 1 +1081 39 43 0 +1082 39 42 1 +1083 39 42 0 +1084 38 43 1 +1085 38 43 0 +1086 38 42 1 +1087 38 42 0 +1088 44 43 0 +1089 44 43 1 +1090 44 42 0 +1091 44 42 1 +1092 45 43 0 +1093 45 43 1 +1094 45 42 0 +1095 45 42 1 +1096 47 42 1 +1097 47 42 0 +1098 47 43 1 +1099 47 43 0 +1100 46 42 1 +1101 46 42 0 +1102 46 43 1 +1103 46 43 0 +1152 43 45 0 +1153 43 45 1 +1154 43 44 0 +1155 43 44 1 +1156 42 45 0 +1157 42 45 1 +1158 42 44 0 +1159 42 44 1 +1160 40 44 1 +1161 40 44 0 +1162 40 45 1 +1163 40 45 0 +1164 41 44 1 +1165 41 44 0 +1166 41 45 1 +1167 41 45 0 +1184 35 44 0 +1185 35 44 1 +1186 35 45 0 +1187 35 45 1 +1188 34 44 0 +1189 34 44 1 +1190 34 45 0 +1191 34 45 1 +1192 32 45 1 +1193 32 45 0 +1194 32 44 1 +1195 32 44 0 +1196 33 45 1 +1197 33 45 0 +1198 33 44 1 +1199 33 44 0 +1200 36 44 0 +1201 36 44 1 +1202 36 45 0 +1203 36 45 1 +1204 37 44 0 +1205 37 44 1 +1206 37 45 0 +1207 37 45 1 +1208 39 45 1 +1209 39 45 0 +1210 39 44 1 +1211 39 44 0 +1212 38 45 1 +1213 38 45 0 +1214 38 44 1 +1215 38 44 0 +1216 44 45 0 +1217 44 45 1 +1218 44 44 0 +1219 44 44 1 +1220 45 45 0 +1221 45 45 1 +1222 45 44 0 +1223 45 44 1 +1224 47 44 1 +1225 47 44 0 +1226 47 45 1 +1227 47 45 0 +1228 46 44 1 +1229 46 44 0 +1230 46 45 1 +1231 46 45 0 +1280 43 47 0 +1281 43 47 1 +1282 43 46 0 +1283 43 46 1 +1284 42 47 0 +1285 42 47 1 +1286 42 46 0 +1287 42 46 1 +1288 40 46 1 +1289 40 46 0 +1290 40 47 1 +1291 40 47 0 +1292 41 46 1 +1293 41 46 0 +1294 41 47 1 +1295 41 47 0 +1312 35 46 0 +1313 35 46 1 +1314 35 47 0 +1315 35 47 1 +1316 34 46 0 +1317 34 46 1 +1318 34 47 0 +1319 34 47 1 +1320 32 47 1 +1321 32 47 0 +1322 32 46 1 +1323 32 46 0 +1324 33 47 1 +1325 33 47 0 +1326 33 46 1 +1327 33 46 0 +1328 36 46 0 +1329 36 46 1 +1330 36 47 0 +1331 36 47 1 +1332 37 46 0 +1333 37 46 1 +1334 37 47 0 +1335 37 47 1 +1336 39 47 1 +1337 39 47 0 +1338 39 46 1 +1339 39 46 0 +1340 38 47 1 +1341 38 47 0 +1342 38 46 1 +1343 38 46 0 +1344 44 47 0 +1345 44 47 1 +1346 44 46 0 +1347 44 46 1 +1348 45 47 0 +1349 45 47 1 +1350 45 46 0 +1351 45 46 1 +1352 47 46 1 +1353 47 46 0 +1354 47 47 1 +1355 47 47 0 +1356 46 46 1 +1357 46 46 0 +1358 46 47 1 +1359 46 47 0 +1408 43 49 0 +1409 43 49 1 +1410 43 48 0 +1411 43 48 1 +1412 42 49 0 +1413 42 49 1 +1414 42 48 0 +1415 42 48 1 +1416 40 48 1 +1417 40 48 0 +1418 40 49 1 +1419 40 49 0 +1420 41 48 1 +1421 41 48 0 +1422 41 49 1 +1423 41 49 0 +1440 35 48 0 +1441 35 48 1 +1442 35 49 0 +1443 35 49 1 +1444 34 48 0 +1445 34 48 1 +1446 34 49 0 +1447 34 49 1 +1448 32 49 1 +1449 32 49 0 +1450 32 48 1 +1451 32 48 0 +1452 33 49 1 +1453 33 49 0 +1454 33 48 1 +1455 33 48 0 +1456 36 48 0 +1457 36 48 1 +1458 36 49 0 +1459 36 49 1 +1460 37 48 0 +1461 37 48 1 +1462 37 49 0 +1463 37 49 1 +1464 39 49 1 +1465 39 49 0 +1466 39 48 1 +1467 39 48 0 +1468 38 49 1 +1469 38 49 0 +1470 38 48 1 +1471 38 48 0 +1472 44 49 0 +1473 44 49 1 +1474 44 48 0 +1475 44 48 1 +1476 45 49 0 +1477 45 49 1 +1478 45 48 0 +1479 45 48 1 +1480 47 48 1 +1481 47 48 0 +1482 47 49 1 +1483 47 49 0 +1484 46 48 1 +1485 46 48 0 +1486 46 49 1 +1487 46 49 0 +1536 43 51 0 +1537 43 51 1 +1538 43 50 0 +1539 43 50 1 +1540 42 51 0 +1541 42 51 1 +1542 42 50 0 +1543 42 50 1 +1544 40 50 1 +1545 40 50 0 +1546 40 51 1 +1547 40 51 0 +1548 41 50 1 +1549 41 50 0 +1550 41 51 1 +1551 41 51 0 +1568 35 50 0 +1569 35 50 1 +1570 35 51 0 +1571 35 51 1 +1572 34 50 0 +1573 34 50 1 +1574 34 51 0 +1575 34 51 1 +1576 32 51 1 +1577 32 51 0 +1578 32 50 1 +1579 32 50 0 +1580 33 51 1 +1581 33 51 0 +1582 33 50 1 +1583 33 50 0 +1584 36 50 0 +1585 36 50 1 +1586 36 51 0 +1587 36 51 1 +1588 37 50 0 +1589 37 50 1 +1590 37 51 0 +1591 37 51 1 +1592 39 51 1 +1593 39 51 0 +1594 39 50 1 +1595 39 50 0 +1596 38 51 1 +1597 38 51 0 +1598 38 50 1 +1599 38 50 0 +1600 44 51 0 +1601 44 51 1 +1602 44 50 0 +1603 44 50 1 +1604 45 51 0 +1605 45 51 1 +1606 45 50 0 +1607 45 50 1 +1608 47 50 1 +1609 47 50 0 +1610 47 51 1 +1611 47 51 0 +1612 46 50 1 +1613 46 50 0 +1614 46 51 1 +1615 46 51 0 +1664 43 53 0 +1665 43 53 1 +1666 43 52 0 +1667 43 52 1 +1668 42 53 0 +1669 42 53 1 +1670 42 52 0 +1671 42 52 1 +1672 40 52 1 +1673 40 52 0 +1674 40 53 1 +1675 40 53 0 +1676 41 52 1 +1677 41 52 0 +1678 41 53 1 +1679 41 53 0 +1696 35 52 0 +1697 35 52 1 +1698 35 53 0 +1699 35 53 1 +1700 34 52 0 +1701 34 52 1 +1702 34 53 0 +1703 34 53 1 +1704 32 53 1 +1705 32 53 0 +1706 32 52 1 +1707 32 52 0 +1708 33 53 1 +1709 33 53 0 +1710 33 52 1 +1711 33 52 0 +1712 36 52 0 +1713 36 52 1 +1714 36 53 0 +1715 36 53 1 +1716 37 52 0 +1717 37 52 1 +1718 37 53 0 +1719 37 53 1 +1720 39 53 1 +1721 39 53 0 +1722 39 52 1 +1723 39 52 0 +1724 38 53 1 +1725 38 53 0 +1726 38 52 1 +1727 38 52 0 +1728 44 53 0 +1729 44 53 1 +1730 44 52 0 +1731 44 52 1 +1732 45 53 0 +1733 45 53 1 +1734 45 52 0 +1735 45 52 1 +1736 47 52 1 +1737 47 52 0 +1738 47 53 1 +1739 47 53 0 +1740 46 52 1 +1741 46 52 0 +1742 46 53 1 +1743 46 53 0 +1792 43 55 0 +1793 43 55 1 +1794 43 54 0 +1795 43 54 1 +1796 42 55 0 +1797 42 55 1 +1798 42 54 0 +1799 42 54 1 +1800 40 54 1 +1801 40 54 0 +1802 40 55 1 +1803 40 55 0 +1804 41 54 1 +1805 41 54 0 +1806 41 55 1 +1807 41 55 0 +1824 35 54 0 +1825 35 54 1 +1826 35 55 0 +1827 35 55 1 +1828 34 54 0 +1829 34 54 1 +1830 34 55 0 +1831 34 55 1 +1832 32 55 1 +1833 32 55 0 +1834 32 54 1 +1835 32 54 0 +1836 33 55 1 +1837 33 55 0 +1838 33 54 1 +1839 33 54 0 +1840 36 54 0 +1841 36 54 1 +1842 36 55 0 +1843 36 55 1 +1844 37 54 0 +1845 37 54 1 +1846 37 55 0 +1847 37 55 1 +1848 39 55 1 +1849 39 55 0 +1850 39 54 1 +1851 39 54 0 +1852 38 55 1 +1853 38 55 0 +1854 38 54 1 +1855 38 54 0 +1856 44 55 0 +1857 44 55 1 +1858 44 54 0 +1859 44 54 1 +1860 45 55 0 +1861 45 55 1 +1862 45 54 0 +1863 45 54 1 +1864 47 54 1 +1865 47 54 0 +1866 47 55 1 +1867 47 55 0 +1868 46 54 1 +1869 46 54 0 +1870 46 55 1 +1871 46 55 0 +2176 43 27 0 +2177 43 27 1 +2178 43 26 0 +2179 43 26 1 +2180 42 27 0 +2181 42 27 1 +2182 42 26 0 +2183 42 26 1 +2184 40 26 1 +2185 40 26 0 +2186 40 27 1 +2187 40 27 0 +2188 41 26 1 +2189 41 26 0 +2190 41 27 1 +2191 41 27 0 +2208 35 26 0 +2209 35 26 1 +2210 35 27 0 +2211 35 27 1 +2212 34 26 0 +2213 34 26 1 +2214 34 27 0 +2215 34 27 1 +2216 32 27 1 +2217 32 27 0 +2218 32 26 1 +2219 32 26 0 +2220 33 27 1 +2221 33 27 0 +2222 33 26 1 +2223 33 26 0 +2224 36 26 0 +2225 36 26 1 +2226 36 27 0 +2227 36 27 1 +2228 37 26 0 +2229 37 26 1 +2230 37 27 0 +2231 37 27 1 +2232 39 27 1 +2233 39 27 0 +2234 39 26 1 +2235 39 26 0 +2236 38 27 1 +2237 38 27 0 +2238 38 26 1 +2239 38 26 0 +2240 44 27 0 +2241 44 27 1 +2242 44 26 0 +2243 44 26 1 +2244 45 27 0 +2245 45 27 1 +2246 45 26 0 +2247 45 26 1 +2248 47 26 1 +2249 47 26 0 +2250 47 27 1 +2251 47 27 0 +2252 46 26 1 +2253 46 26 0 +2254 46 27 1 +2255 46 27 0 +2304 43 25 0 +2305 43 25 1 +2306 43 24 0 +2307 43 24 1 +2308 42 25 0 +2309 42 25 1 +2310 42 24 0 +2311 42 24 1 +2312 40 24 1 +2313 40 24 0 +2314 40 25 1 +2315 40 25 0 +2316 41 24 1 +2317 41 24 0 +2318 41 25 1 +2319 41 25 0 +2336 35 24 0 +2337 35 24 1 +2338 35 25 0 +2339 35 25 1 +2340 34 24 0 +2341 34 24 1 +2342 34 25 0 +2343 34 25 1 +2344 32 25 1 +2345 32 25 0 +2346 32 24 1 +2347 32 24 0 +2348 33 25 1 +2349 33 25 0 +2350 33 24 1 +2351 33 24 0 +2352 36 24 0 +2353 36 24 1 +2354 36 25 0 +2355 36 25 1 +2356 37 24 0 +2357 37 24 1 +2358 37 25 0 +2359 37 25 1 +2360 39 25 1 +2361 39 25 0 +2362 39 24 1 +2363 39 24 0 +2364 38 25 1 +2365 38 25 0 +2366 38 24 1 +2367 38 24 0 +2368 44 25 0 +2369 44 25 1 +2370 44 24 0 +2371 44 24 1 +2372 45 25 0 +2373 45 25 1 +2374 45 24 0 +2375 45 24 1 +2376 47 24 1 +2377 47 24 0 +2378 47 25 1 +2379 47 25 0 +2380 46 24 1 +2381 46 24 0 +2382 46 25 1 +2383 46 25 0 +2432 43 23 0 +2433 43 23 1 +2434 43 22 0 +2435 43 22 1 +2436 42 23 0 +2437 42 23 1 +2438 42 22 0 +2439 42 22 1 +2440 40 22 1 +2441 40 22 0 +2442 40 23 1 +2443 40 23 0 +2444 41 22 1 +2445 41 22 0 +2446 41 23 1 +2447 41 23 0 +2464 35 22 0 +2465 35 22 1 +2466 35 23 0 +2467 35 23 1 +2468 34 22 0 +2469 34 22 1 +2470 34 23 0 +2471 34 23 1 +2472 32 23 1 +2473 32 23 0 +2474 32 22 1 +2475 32 22 0 +2476 33 23 1 +2477 33 23 0 +2478 33 22 1 +2479 33 22 0 +2480 36 22 0 +2481 36 22 1 +2482 36 23 0 +2483 36 23 1 +2484 37 22 0 +2485 37 22 1 +2486 37 23 0 +2487 37 23 1 +2488 39 23 1 +2489 39 23 0 +2490 39 22 1 +2491 39 22 0 +2492 38 23 1 +2493 38 23 0 +2494 38 22 1 +2495 38 22 0 +2496 44 23 0 +2497 44 23 1 +2498 44 22 0 +2499 44 22 1 +2500 45 23 0 +2501 45 23 1 +2502 45 22 0 +2503 45 22 1 +2504 47 22 1 +2505 47 22 0 +2506 47 23 1 +2507 47 23 0 +2508 46 22 1 +2509 46 22 0 +2510 46 23 1 +2511 46 23 0 +2560 43 21 0 +2561 43 21 1 +2562 43 20 0 +2563 43 20 1 +2564 42 21 0 +2565 42 21 1 +2566 42 20 0 +2567 42 20 1 +2568 40 20 1 +2569 40 20 0 +2570 40 21 1 +2571 40 21 0 +2572 41 20 1 +2573 41 20 0 +2574 41 21 1 +2575 41 21 0 +2592 35 20 0 +2593 35 20 1 +2594 35 21 0 +2595 35 21 1 +2596 34 20 0 +2597 34 20 1 +2598 34 21 0 +2599 34 21 1 +2600 32 21 1 +2601 32 21 0 +2602 32 20 1 +2603 32 20 0 +2604 33 21 1 +2605 33 21 0 +2606 33 20 1 +2607 33 20 0 +2608 36 20 0 +2609 36 20 1 +2610 36 21 0 +2611 36 21 1 +2612 37 20 0 +2613 37 20 1 +2614 37 21 0 +2615 37 21 1 +2616 39 21 1 +2617 39 21 0 +2618 39 20 1 +2619 39 20 0 +2620 38 21 1 +2621 38 21 0 +2622 38 20 1 +2623 38 20 0 +2624 44 21 0 +2625 44 21 1 +2626 44 20 0 +2627 44 20 1 +2628 45 21 0 +2629 45 21 1 +2630 45 20 0 +2631 45 20 1 +2632 47 20 1 +2633 47 20 0 +2634 47 21 1 +2635 47 21 0 +2636 46 20 1 +2637 46 20 0 +2638 46 21 1 +2639 46 21 0 +2688 43 19 0 +2689 43 19 1 +2690 43 18 0 +2691 43 18 1 +2692 42 19 0 +2693 42 19 1 +2694 42 18 0 +2695 42 18 1 +2696 40 18 1 +2697 40 18 0 +2698 40 19 1 +2699 40 19 0 +2700 41 18 1 +2701 41 18 0 +2702 41 19 1 +2703 41 19 0 +2720 35 18 0 +2721 35 18 1 +2722 35 19 0 +2723 35 19 1 +2724 34 18 0 +2725 34 18 1 +2726 34 19 0 +2727 34 19 1 +2728 32 19 1 +2729 32 19 0 +2730 32 18 1 +2731 32 18 0 +2732 33 19 1 +2733 33 19 0 +2734 33 18 1 +2735 33 18 0 +2736 36 18 0 +2737 36 18 1 +2738 36 19 0 +2739 36 19 1 +2740 37 18 0 +2741 37 18 1 +2742 37 19 0 +2743 37 19 1 +2744 39 19 1 +2745 39 19 0 +2746 39 18 1 +2747 39 18 0 +2748 38 19 1 +2749 38 19 0 +2750 38 18 1 +2751 38 18 0 +2752 44 19 0 +2753 44 19 1 +2754 44 18 0 +2755 44 18 1 +2756 45 19 0 +2757 45 19 1 +2758 45 18 0 +2759 45 18 1 +2760 47 18 1 +2761 47 18 0 +2762 47 19 1 +2763 47 19 0 +2764 46 18 1 +2765 46 18 0 +2766 46 19 1 +2767 46 19 0 +2816 43 17 0 +2817 43 17 1 +2818 43 16 0 +2819 43 16 1 +2820 42 17 0 +2821 42 17 1 +2822 42 16 0 +2823 42 16 1 +2824 40 16 1 +2825 40 16 0 +2826 40 17 1 +2827 40 17 0 +2828 41 16 1 +2829 41 16 0 +2830 41 17 1 +2831 41 17 0 +2848 35 16 0 +2849 35 16 1 +2850 35 17 0 +2851 35 17 1 +2852 34 16 0 +2853 34 16 1 +2854 34 17 0 +2855 34 17 1 +2856 32 17 1 +2857 32 17 0 +2858 32 16 1 +2859 32 16 0 +2860 33 17 1 +2861 33 17 0 +2862 33 16 1 +2863 33 16 0 +2864 36 16 0 +2865 36 16 1 +2866 36 17 0 +2867 36 17 1 +2868 37 16 0 +2869 37 16 1 +2870 37 17 0 +2871 37 17 1 +2872 39 17 1 +2873 39 17 0 +2874 39 16 1 +2875 39 16 0 +2876 38 17 1 +2877 38 17 0 +2878 38 16 1 +2879 38 16 0 +2880 44 17 0 +2881 44 17 1 +2882 44 16 0 +2883 44 16 1 +2884 45 17 0 +2885 45 17 1 +2886 45 16 0 +2887 45 16 1 +2888 47 16 1 +2889 47 16 0 +2890 47 17 1 +2891 47 17 0 +2892 46 16 1 +2893 46 16 0 +2894 46 17 1 +2895 46 17 0 +2944 43 15 0 +2945 43 15 1 +2946 43 14 0 +2947 43 14 1 +2948 42 15 0 +2949 42 15 1 +2950 42 14 0 +2951 42 14 1 +2952 40 14 1 +2953 40 14 0 +2954 40 15 1 +2955 40 15 0 +2956 41 14 1 +2957 41 14 0 +2958 41 15 1 +2959 41 15 0 +2976 35 14 0 +2977 35 14 1 +2978 35 15 0 +2979 35 15 1 +2980 34 14 0 +2981 34 14 1 +2982 34 15 0 +2983 34 15 1 +2984 32 15 1 +2985 32 15 0 +2986 32 14 1 +2987 32 14 0 +2988 33 15 1 +2989 33 15 0 +2990 33 14 1 +2991 33 14 0 +2992 36 14 0 +2993 36 14 1 +2994 36 15 0 +2995 36 15 1 +2996 37 14 0 +2997 37 14 1 +2998 37 15 0 +2999 37 15 1 +3000 39 15 1 +3001 39 15 0 +3002 39 14 1 +3003 39 14 0 +3004 38 15 1 +3005 38 15 0 +3006 38 14 1 +3007 38 14 0 +3008 44 15 0 +3009 44 15 1 +3010 44 14 0 +3011 44 14 1 +3012 45 15 0 +3013 45 15 1 +3014 45 14 0 +3015 45 14 1 +3016 47 14 1 +3017 47 14 0 +3018 47 15 1 +3019 47 15 0 +3020 46 14 1 +3021 46 14 0 +3022 46 15 1 +3023 46 15 0 +3072 43 13 0 +3073 43 13 1 +3074 43 12 0 +3075 43 12 1 +3076 42 13 0 +3077 42 13 1 +3078 42 12 0 +3079 42 12 1 +3080 40 12 1 +3081 40 12 0 +3082 40 13 1 +3083 40 13 0 +3084 41 12 1 +3085 41 12 0 +3086 41 13 1 +3087 41 13 0 +3104 35 12 0 +3105 35 12 1 +3106 35 13 0 +3107 35 13 1 +3108 34 12 0 +3109 34 12 1 +3110 34 13 0 +3111 34 13 1 +3112 32 13 1 +3113 32 13 0 +3114 32 12 1 +3115 32 12 0 +3116 33 13 1 +3117 33 13 0 +3118 33 12 1 +3119 33 12 0 +3120 36 12 0 +3121 36 12 1 +3122 36 13 0 +3123 36 13 1 +3124 37 12 0 +3125 37 12 1 +3126 37 13 0 +3127 37 13 1 +3128 39 13 1 +3129 39 13 0 +3130 39 12 1 +3131 39 12 0 +3132 38 13 1 +3133 38 13 0 +3134 38 12 1 +3135 38 12 0 +3136 44 13 0 +3137 44 13 1 +3138 44 12 0 +3139 44 12 1 +3140 45 13 0 +3141 45 13 1 +3142 45 12 0 +3143 45 12 1 +3144 47 12 1 +3145 47 12 0 +3146 47 13 1 +3147 47 13 0 +3148 46 12 1 +3149 46 12 0 +3150 46 13 1 +3151 46 13 0 +3200 43 11 0 +3201 43 11 1 +3202 43 10 0 +3203 43 10 1 +3204 42 11 0 +3205 42 11 1 +3206 42 10 0 +3207 42 10 1 +3208 40 10 1 +3209 40 10 0 +3210 40 11 1 +3211 40 11 0 +3212 41 10 1 +3213 41 10 0 +3214 41 11 1 +3215 41 11 0 +3232 35 10 0 +3233 35 10 1 +3234 35 11 0 +3235 35 11 1 +3236 34 10 0 +3237 34 10 1 +3238 34 11 0 +3239 34 11 1 +3240 32 11 1 +3241 32 11 0 +3242 32 10 1 +3243 32 10 0 +3244 33 11 1 +3245 33 11 0 +3246 33 10 1 +3247 33 10 0 +3248 36 10 0 +3249 36 10 1 +3250 36 11 0 +3251 36 11 1 +3252 37 10 0 +3253 37 10 1 +3254 37 11 0 +3255 37 11 1 +3256 39 11 1 +3257 39 11 0 +3258 39 10 1 +3259 39 10 0 +3260 38 11 1 +3261 38 11 0 +3262 38 10 1 +3263 38 10 0 +3264 44 11 0 +3265 44 11 1 +3266 44 10 0 +3267 44 10 1 +3268 45 11 0 +3269 45 11 1 +3270 45 10 0 +3271 45 10 1 +3272 47 10 1 +3273 47 10 0 +3274 47 11 1 +3275 47 11 0 +3276 46 10 1 +3277 46 10 0 +3278 46 11 1 +3279 46 11 0 +3328 43 9 0 +3329 43 9 1 +3330 43 8 0 +3331 43 8 1 +3332 42 9 0 +3333 42 9 1 +3334 42 8 0 +3335 42 8 1 +3336 40 8 1 +3337 40 8 0 +3338 40 9 1 +3339 40 9 0 +3340 41 8 1 +3341 41 8 0 +3342 41 9 1 +3343 41 9 0 +3360 35 8 0 +3361 35 8 1 +3362 35 9 0 +3363 35 9 1 +3364 34 8 0 +3365 34 8 1 +3366 34 9 0 +3367 34 9 1 +3368 32 9 1 +3369 32 9 0 +3370 32 8 1 +3371 32 8 0 +3372 33 9 1 +3373 33 9 0 +3374 33 8 1 +3375 33 8 0 +3376 36 8 0 +3377 36 8 1 +3378 36 9 0 +3379 36 9 1 +3380 37 8 0 +3381 37 8 1 +3382 37 9 0 +3383 37 9 1 +3384 39 9 1 +3385 39 9 0 +3386 39 8 1 +3387 39 8 0 +3388 38 9 1 +3389 38 9 0 +3390 38 8 1 +3391 38 8 0 +3392 44 9 0 +3393 44 9 1 +3394 44 8 0 +3395 44 8 1 +3396 45 9 0 +3397 45 9 1 +3398 45 8 0 +3399 45 8 1 +3400 47 8 1 +3401 47 8 0 +3402 47 9 1 +3403 47 9 0 +3404 46 8 1 +3405 46 8 0 +3406 46 9 1 +3407 46 9 0 +3456 43 7 0 +3457 43 7 1 +3458 43 6 0 +3459 43 6 1 +3460 42 7 0 +3461 42 7 1 +3462 42 6 0 +3463 42 6 1 +3464 40 6 1 +3465 40 6 0 +3466 40 7 1 +3467 40 7 0 +3468 41 6 1 +3469 41 6 0 +3470 41 7 1 +3471 41 7 0 +3488 35 6 0 +3489 35 6 1 +3490 35 7 0 +3491 35 7 1 +3492 34 6 0 +3493 34 6 1 +3494 34 7 0 +3495 34 7 1 +3496 32 7 1 +3497 32 7 0 +3498 32 6 1 +3499 32 6 0 +3500 33 7 1 +3501 33 7 0 +3502 33 6 1 +3503 33 6 0 +3504 36 6 0 +3505 36 6 1 +3506 36 7 0 +3507 36 7 1 +3508 37 6 0 +3509 37 6 1 +3510 37 7 0 +3511 37 7 1 +3512 39 7 1 +3513 39 7 0 +3514 39 6 1 +3515 39 6 0 +3516 38 7 1 +3517 38 7 0 +3518 38 6 1 +3519 38 6 0 +3520 44 7 0 +3521 44 7 1 +3522 44 6 0 +3523 44 6 1 +3524 45 7 0 +3525 45 7 1 +3526 45 6 0 +3527 45 6 1 +3528 47 6 1 +3529 47 6 0 +3530 47 7 1 +3531 47 7 0 +3532 46 6 1 +3533 46 6 0 +3534 46 7 1 +3535 46 7 0 +3584 43 5 0 +3585 43 5 1 +3586 43 4 0 +3587 43 4 1 +3588 42 5 0 +3589 42 5 1 +3590 42 4 0 +3591 42 4 1 +3592 40 4 1 +3593 40 4 0 +3594 40 5 1 +3595 40 5 0 +3596 41 4 1 +3597 41 4 0 +3598 41 5 1 +3599 41 5 0 +3616 35 4 0 +3617 35 4 1 +3618 35 5 0 +3619 35 5 1 +3620 34 4 0 +3621 34 4 1 +3622 34 5 0 +3623 34 5 1 +3624 32 5 1 +3625 32 5 0 +3626 32 4 1 +3627 32 4 0 +3628 33 5 1 +3629 33 5 0 +3630 33 4 1 +3631 33 4 0 +3632 36 4 0 +3633 36 4 1 +3634 36 5 0 +3635 36 5 1 +3636 37 4 0 +3637 37 4 1 +3638 37 5 0 +3639 37 5 1 +3640 39 5 1 +3641 39 5 0 +3642 39 4 1 +3643 39 4 0 +3644 38 5 1 +3645 38 5 0 +3646 38 4 1 +3647 38 4 0 +3648 44 5 0 +3649 44 5 1 +3650 44 4 0 +3651 44 4 1 +3652 45 5 0 +3653 45 5 1 +3654 45 4 0 +3655 45 4 1 +3656 47 4 1 +3657 47 4 0 +3658 47 5 1 +3659 47 5 0 +3660 46 4 1 +3661 46 4 0 +3662 46 5 1 +3663 46 5 0 +3712 43 3 0 +3713 43 3 1 +3714 43 2 0 +3715 43 2 1 +3716 42 3 0 +3717 42 3 1 +3718 42 2 0 +3719 42 2 1 +3720 40 2 1 +3721 40 2 0 +3722 40 3 1 +3723 40 3 0 +3724 41 2 1 +3725 41 2 0 +3726 41 3 1 +3727 41 3 0 +3744 35 2 0 +3745 35 2 1 +3746 35 3 0 +3747 35 3 1 +3748 34 2 0 +3749 34 2 1 +3750 34 3 0 +3751 34 3 1 +3752 32 3 1 +3753 32 3 0 +3754 32 2 1 +3755 32 2 0 +3756 33 3 1 +3757 33 3 0 +3758 33 2 1 +3759 33 2 0 +3760 36 2 0 +3761 36 2 1 +3762 36 3 0 +3763 36 3 1 +3764 37 2 0 +3765 37 2 1 +3766 37 3 0 +3767 37 3 1 +3768 39 3 1 +3769 39 3 0 +3770 39 2 1 +3771 39 2 0 +3772 38 3 1 +3773 38 3 0 +3774 38 2 1 +3775 38 2 0 +3776 44 3 0 +3777 44 3 1 +3778 44 2 0 +3779 44 2 1 +3780 45 3 0 +3781 45 3 1 +3782 45 2 0 +3783 45 2 1 +3784 47 2 1 +3785 47 2 0 +3786 47 3 1 +3787 47 3 0 +3788 46 2 1 +3789 46 2 0 +3790 46 3 1 +3791 46 3 0 +3840 43 1 0 +3841 43 1 1 +3842 43 0 0 +3843 43 0 1 +3844 42 1 0 +3845 42 1 1 +3846 42 0 0 +3847 42 0 1 +3848 40 0 1 +3849 40 0 0 +3850 40 1 1 +3851 40 1 0 +3852 41 0 1 +3853 41 0 0 +3854 41 1 1 +3855 41 1 0 +3872 35 0 0 +3873 35 0 1 +3874 35 1 0 +3875 35 1 1 +3876 34 0 0 +3877 34 0 1 +3878 34 1 0 +3879 34 1 1 +3880 32 1 1 +3881 32 1 0 +3882 32 0 1 +3883 32 0 0 +3884 33 1 1 +3885 33 1 0 +3886 33 0 1 +3887 33 0 0 +3888 36 0 0 +3889 36 0 1 +3890 36 1 0 +3891 36 1 1 +3892 37 0 0 +3893 37 0 1 +3894 37 1 0 +3895 37 1 1 +3896 39 1 1 +3897 39 1 0 +3898 39 0 1 +3899 39 0 0 +3900 38 1 1 +3901 38 1 0 +3902 38 0 1 +3903 38 0 0 +3904 44 1 0 +3905 44 1 1 +3906 44 0 0 +3907 44 0 1 +3908 45 1 0 +3909 45 1 1 +3910 45 0 0 +3911 45 0 1 +3912 47 0 1 +3913 47 0 0 +3914 47 1 1 +3915 47 1 0 +3916 46 0 1 +3917 46 0 0 +3918 46 1 1 +3919 46 1 0 diff --git a/Detectors/PHOS/base/files/Mod3RCU3.data b/Detectors/PHOS/base/files/Mod3RCU3.data new file mode 100644 index 0000000000000..43bd76fc42791 --- /dev/null +++ b/Detectors/PHOS/base/files/Mod3RCU3.data @@ -0,0 +1,2050 @@ +2048 +3919 + 0 3 0 2 + 1 3 1 2 + 2 3 2 2 + 3 3 3 2 + 4 3 4 2 + 5 3 5 2 + 6 3 6 2 + 7 3 7 2 + 8 3 8 2 + 9 3 9 2 + 10 3 10 2 + 11 3 11 2 + 12 3 12 2 + 13 3 13 2 + 14 3 14 2 + 15 3 15 2 + 16 3 16 2 + 17 3 17 2 + 18 3 18 2 + 19 3 19 2 + 20 3 20 2 + 21 3 21 2 + 22 3 22 2 + 23 3 23 2 + 24 3 24 2 + 25 3 25 2 + 26 3 26 2 + 27 3 27 2 + 28 3 28 2 + 29 3 29 2 + 30 3 30 2 + 31 3 31 2 + 32 3 32 2 + 33 3 33 2 + 34 3 34 2 + 35 3 35 2 + 36 3 36 2 + 37 3 37 2 + 38 3 38 2 + 39 3 39 2 + 40 3 40 2 + 41 3 41 2 + 42 3 42 2 + 43 3 43 2 + 44 3 44 2 + 45 3 45 2 + 46 3 46 2 + 47 3 47 2 + 48 3 48 2 + 49 3 49 2 + 50 3 50 2 + 51 3 51 2 + 52 3 52 2 + 53 3 53 2 + 54 3 54 2 + 55 3 55 2 + 56 3 56 2 + 57 3 57 2 + 58 3 58 2 + 59 3 59 2 + 60 3 60 2 + 61 3 61 2 + 62 3 62 2 + 63 3 63 2 + 64 3 64 2 + 65 3 65 2 + 66 3 66 2 + 67 3 67 2 + 68 3 68 2 + 69 3 69 2 + 70 3 70 2 + 71 3 71 2 + 72 3 72 2 + 73 3 73 2 + 74 3 74 2 + 75 3 75 2 + 76 3 76 2 + 77 3 77 2 + 78 3 78 2 + 79 3 79 2 + 80 3 80 2 + 81 3 81 2 + 82 3 82 2 + 83 3 83 2 + 84 3 84 2 + 85 3 85 2 + 86 3 86 2 + 87 3 87 2 + 88 3 88 2 + 89 3 89 2 + 90 3 90 2 + 91 3 91 2 + 92 3 92 2 + 93 3 93 2 + 94 3 94 2 + 95 3 95 2 + 96 3 96 2 + 97 3 97 2 + 98 3 98 2 + 99 3 99 2 + 100 3 100 2 + 101 3 101 2 + 102 3 102 2 + 103 3 103 2 + 104 3 104 2 + 105 3 105 2 + 106 3 106 2 + 107 3 107 2 + 108 3 108 2 + 109 3 109 2 + 110 3 110 2 + 111 3 111 2 + 112 3 112 2 + 113 3 113 2 + 114 3 114 2 + 115 3 115 2 + 116 3 116 2 + 117 3 117 2 + 118 3 118 2 + 119 3 119 2 + 120 3 120 2 + 121 3 121 2 + 122 3 122 2 + 123 3 123 2 + 124 3 124 2 + 125 3 125 2 + 126 3 126 2 + 127 3 127 2 +2048 3 2048 2 +2049 3 2049 2 +2050 3 2050 2 +2051 3 2051 2 +2052 3 2052 2 +2053 3 2053 2 +2054 3 2054 2 +2055 3 2055 2 +2056 3 2056 2 +2057 3 2057 2 +2058 3 2058 2 +2059 3 2059 2 +2060 3 2060 2 +2061 3 2061 2 +2062 3 2062 2 +2063 3 2063 2 +2064 3 2064 2 +2065 3 2065 2 +2066 3 2066 2 +2067 3 2067 2 +2068 3 2068 2 +2069 3 2069 2 +2070 3 2070 2 +2071 3 2071 2 +2072 3 2072 2 +2073 3 2073 2 +2074 3 2074 2 +2075 3 2075 2 +2076 3 2076 2 +2077 3 2077 2 +2078 3 2078 2 +2079 3 2079 2 +2080 3 2080 2 +2081 3 2081 2 +2082 3 2082 2 +2083 3 2083 2 +2084 3 2084 2 +2085 3 2085 2 +2086 3 2086 2 +2087 3 2087 2 +2088 3 2088 2 +2089 3 2089 2 +2090 3 2090 2 +2091 3 2091 2 +2092 3 2092 2 +2093 3 2093 2 +2094 3 2094 2 +2095 3 2095 2 +2096 3 2096 2 +2097 3 2097 2 +2098 3 2098 2 +2099 3 2099 2 +2100 3 2100 2 +2101 3 2101 2 +2102 3 2102 2 +2103 3 2103 2 +2104 3 2104 2 +2105 3 2105 2 +2106 3 2106 2 +2107 3 2107 2 +2108 3 2108 2 +2109 3 2109 2 +2110 3 2110 2 +2111 3 2111 2 +2112 3 2112 2 +2113 3 2113 2 +2114 3 2114 2 +2115 3 2115 2 +2116 3 2116 2 +2117 3 2117 2 +2118 3 2118 2 +2119 3 2119 2 +2120 3 2120 2 +2121 3 2121 2 +2122 3 2122 2 +2123 3 2123 2 +2124 3 2124 2 +2125 3 2125 2 +2126 3 2126 2 +2127 3 2127 2 +2128 3 2128 2 +2129 3 2129 2 +2130 3 2130 2 +2131 3 2131 2 +2132 3 2132 2 +2133 3 2133 2 +2134 3 2134 2 +2135 3 2135 2 +2136 3 2136 2 +2137 3 2137 2 +2138 3 2138 2 +2139 3 2139 2 +2140 3 2140 2 +2141 3 2141 2 +2142 3 2142 2 +2143 3 2143 2 +2144 3 2144 2 +2145 3 2145 2 +2146 3 2146 2 +2147 3 2147 2 +2148 3 2148 2 +2149 3 2149 2 +2150 3 2150 2 +2151 3 2151 2 +2152 3 2152 2 +2153 3 2153 2 +2154 3 2154 2 +2155 3 2155 2 +2156 3 2156 2 +2157 3 2157 2 +2158 3 2158 2 +2159 3 2159 2 +2160 3 2160 2 +2161 3 2161 2 +2162 3 2162 2 +2163 3 2163 2 +2164 3 2164 2 +2165 3 2165 2 +2166 3 2166 2 +2167 3 2167 2 +2168 3 2168 2 +2169 3 2169 2 +2170 3 2170 2 +2171 3 2171 2 +2172 3 2172 2 +2173 3 2173 2 +2174 3 2174 2 +2175 3 2175 2 + 128 59 29 0 + 129 59 29 1 + 130 59 28 0 + 131 59 28 1 + 132 58 29 0 + 133 58 29 1 + 134 58 28 0 + 135 58 28 1 + 136 56 28 1 + 137 56 28 0 + 138 56 29 1 + 139 56 29 0 + 140 57 28 1 + 141 57 28 0 + 142 57 29 1 + 143 57 29 0 + 160 51 28 0 + 161 51 28 1 + 162 51 29 0 + 163 51 29 1 + 164 50 28 0 + 165 50 28 1 + 166 50 29 0 + 167 50 29 1 + 168 48 29 1 + 169 48 29 0 + 170 48 28 1 + 171 48 28 0 + 172 49 29 1 + 173 49 29 0 + 174 49 28 1 + 175 49 28 0 + 176 52 28 0 + 177 52 28 1 + 178 52 29 0 + 179 52 29 1 + 180 53 28 0 + 181 53 28 1 + 182 53 29 0 + 183 53 29 1 + 184 55 29 1 + 185 55 29 0 + 186 55 28 1 + 187 55 28 0 + 188 54 29 1 + 189 54 29 0 + 190 54 28 1 + 191 54 28 0 + 192 60 29 0 + 193 60 29 1 + 194 60 28 0 + 195 60 28 1 + 196 61 29 0 + 197 61 29 1 + 198 61 28 0 + 199 61 28 1 + 200 63 28 1 + 201 63 28 0 + 202 63 29 1 + 203 63 29 0 + 204 62 28 1 + 205 62 28 0 + 206 62 29 1 + 207 62 29 0 + 256 59 31 0 + 257 59 31 1 + 258 59 30 0 + 259 59 30 1 + 260 58 31 0 + 261 58 31 1 + 262 58 30 0 + 263 58 30 1 + 264 56 30 1 + 265 56 30 0 + 266 56 31 1 + 267 56 31 0 + 268 57 30 1 + 269 57 30 0 + 270 57 31 1 + 271 57 31 0 + 288 51 30 0 + 289 51 30 1 + 290 51 31 0 + 291 51 31 1 + 292 50 30 0 + 293 50 30 1 + 294 50 31 0 + 295 50 31 1 + 296 48 31 1 + 297 48 31 0 + 298 48 30 1 + 299 48 30 0 + 300 49 31 1 + 301 49 31 0 + 302 49 30 1 + 303 49 30 0 + 304 52 30 0 + 305 52 30 1 + 306 52 31 0 + 307 52 31 1 + 308 53 30 0 + 309 53 30 1 + 310 53 31 0 + 311 53 31 1 + 312 55 31 1 + 313 55 31 0 + 314 55 30 1 + 315 55 30 0 + 316 54 31 1 + 317 54 31 0 + 318 54 30 1 + 319 54 30 0 + 320 60 31 0 + 321 60 31 1 + 322 60 30 0 + 323 60 30 1 + 324 61 31 0 + 325 61 31 1 + 326 61 30 0 + 327 61 30 1 + 328 63 30 1 + 329 63 30 0 + 330 63 31 1 + 331 63 31 0 + 332 62 30 1 + 333 62 30 0 + 334 62 31 1 + 335 62 31 0 + 384 59 33 0 + 385 59 33 1 + 386 59 32 0 + 387 59 32 1 + 388 58 33 0 + 389 58 33 1 + 390 58 32 0 + 391 58 32 1 + 392 56 32 1 + 393 56 32 0 + 394 56 33 1 + 395 56 33 0 + 396 57 32 1 + 397 57 32 0 + 398 57 33 1 + 399 57 33 0 + 416 51 32 0 + 417 51 32 1 + 418 51 33 0 + 419 51 33 1 + 420 50 32 0 + 421 50 32 1 + 422 50 33 0 + 423 50 33 1 + 424 48 33 1 + 425 48 33 0 + 426 48 32 1 + 427 48 32 0 + 428 49 33 1 + 429 49 33 0 + 430 49 32 1 + 431 49 32 0 + 432 52 32 0 + 433 52 32 1 + 434 52 33 0 + 435 52 33 1 + 436 53 32 0 + 437 53 32 1 + 438 53 33 0 + 439 53 33 1 + 440 55 33 1 + 441 55 33 0 + 442 55 32 1 + 443 55 32 0 + 444 54 33 1 + 445 54 33 0 + 446 54 32 1 + 447 54 32 0 + 448 60 33 0 + 449 60 33 1 + 450 60 32 0 + 451 60 32 1 + 452 61 33 0 + 453 61 33 1 + 454 61 32 0 + 455 61 32 1 + 456 63 32 1 + 457 63 32 0 + 458 63 33 1 + 459 63 33 0 + 460 62 32 1 + 461 62 32 0 + 462 62 33 1 + 463 62 33 0 + 512 59 35 0 + 513 59 35 1 + 514 59 34 0 + 515 59 34 1 + 516 58 35 0 + 517 58 35 1 + 518 58 34 0 + 519 58 34 1 + 520 56 34 1 + 521 56 34 0 + 522 56 35 1 + 523 56 35 0 + 524 57 34 1 + 525 57 34 0 + 526 57 35 1 + 527 57 35 0 + 544 51 34 0 + 545 51 34 1 + 546 51 35 0 + 547 51 35 1 + 548 50 34 0 + 549 50 34 1 + 550 50 35 0 + 551 50 35 1 + 552 48 35 1 + 553 48 35 0 + 554 48 34 1 + 555 48 34 0 + 556 49 35 1 + 557 49 35 0 + 558 49 34 1 + 559 49 34 0 + 560 52 34 0 + 561 52 34 1 + 562 52 35 0 + 563 52 35 1 + 564 53 34 0 + 565 53 34 1 + 566 53 35 0 + 567 53 35 1 + 568 55 35 1 + 569 55 35 0 + 570 55 34 1 + 571 55 34 0 + 572 54 35 1 + 573 54 35 0 + 574 54 34 1 + 575 54 34 0 + 576 60 35 0 + 577 60 35 1 + 578 60 34 0 + 579 60 34 1 + 580 61 35 0 + 581 61 35 1 + 582 61 34 0 + 583 61 34 1 + 584 63 34 1 + 585 63 34 0 + 586 63 35 1 + 587 63 35 0 + 588 62 34 1 + 589 62 34 0 + 590 62 35 1 + 591 62 35 0 + 640 59 37 0 + 641 59 37 1 + 642 59 36 0 + 643 59 36 1 + 644 58 37 0 + 645 58 37 1 + 646 58 36 0 + 647 58 36 1 + 648 56 36 1 + 649 56 36 0 + 650 56 37 1 + 651 56 37 0 + 652 57 36 1 + 653 57 36 0 + 654 57 37 1 + 655 57 37 0 + 672 51 36 0 + 673 51 36 1 + 674 51 37 0 + 675 51 37 1 + 676 50 36 0 + 677 50 36 1 + 678 50 37 0 + 679 50 37 1 + 680 48 37 1 + 681 48 37 0 + 682 48 36 1 + 683 48 36 0 + 684 49 37 1 + 685 49 37 0 + 686 49 36 1 + 687 49 36 0 + 688 52 36 0 + 689 52 36 1 + 690 52 37 0 + 691 52 37 1 + 692 53 36 0 + 693 53 36 1 + 694 53 37 0 + 695 53 37 1 + 696 55 37 1 + 697 55 37 0 + 698 55 36 1 + 699 55 36 0 + 700 54 37 1 + 701 54 37 0 + 702 54 36 1 + 703 54 36 0 + 704 60 37 0 + 705 60 37 1 + 706 60 36 0 + 707 60 36 1 + 708 61 37 0 + 709 61 37 1 + 710 61 36 0 + 711 61 36 1 + 712 63 36 1 + 713 63 36 0 + 714 63 37 1 + 715 63 37 0 + 716 62 36 1 + 717 62 36 0 + 718 62 37 1 + 719 62 37 0 + 768 59 39 0 + 769 59 39 1 + 770 59 38 0 + 771 59 38 1 + 772 58 39 0 + 773 58 39 1 + 774 58 38 0 + 775 58 38 1 + 776 56 38 1 + 777 56 38 0 + 778 56 39 1 + 779 56 39 0 + 780 57 38 1 + 781 57 38 0 + 782 57 39 1 + 783 57 39 0 + 800 51 38 0 + 801 51 38 1 + 802 51 39 0 + 803 51 39 1 + 804 50 38 0 + 805 50 38 1 + 806 50 39 0 + 807 50 39 1 + 808 48 39 1 + 809 48 39 0 + 810 48 38 1 + 811 48 38 0 + 812 49 39 1 + 813 49 39 0 + 814 49 38 1 + 815 49 38 0 + 816 52 38 0 + 817 52 38 1 + 818 52 39 0 + 819 52 39 1 + 820 53 38 0 + 821 53 38 1 + 822 53 39 0 + 823 53 39 1 + 824 55 39 1 + 825 55 39 0 + 826 55 38 1 + 827 55 38 0 + 828 54 39 1 + 829 54 39 0 + 830 54 38 1 + 831 54 38 0 + 832 60 39 0 + 833 60 39 1 + 834 60 38 0 + 835 60 38 1 + 836 61 39 0 + 837 61 39 1 + 838 61 38 0 + 839 61 38 1 + 840 63 38 1 + 841 63 38 0 + 842 63 39 1 + 843 63 39 0 + 844 62 38 1 + 845 62 38 0 + 846 62 39 1 + 847 62 39 0 + 896 59 41 0 + 897 59 41 1 + 898 59 40 0 + 899 59 40 1 + 900 58 41 0 + 901 58 41 1 + 902 58 40 0 + 903 58 40 1 + 904 56 40 1 + 905 56 40 0 + 906 56 41 1 + 907 56 41 0 + 908 57 40 1 + 909 57 40 0 + 910 57 41 1 + 911 57 41 0 + 928 51 40 0 + 929 51 40 1 + 930 51 41 0 + 931 51 41 1 + 932 50 40 0 + 933 50 40 1 + 934 50 41 0 + 935 50 41 1 + 936 48 41 1 + 937 48 41 0 + 938 48 40 1 + 939 48 40 0 + 940 49 41 1 + 941 49 41 0 + 942 49 40 1 + 943 49 40 0 + 944 52 40 0 + 945 52 40 1 + 946 52 41 0 + 947 52 41 1 + 948 53 40 0 + 949 53 40 1 + 950 53 41 0 + 951 53 41 1 + 952 55 41 1 + 953 55 41 0 + 954 55 40 1 + 955 55 40 0 + 956 54 41 1 + 957 54 41 0 + 958 54 40 1 + 959 54 40 0 + 960 60 41 0 + 961 60 41 1 + 962 60 40 0 + 963 60 40 1 + 964 61 41 0 + 965 61 41 1 + 966 61 40 0 + 967 61 40 1 + 968 63 40 1 + 969 63 40 0 + 970 63 41 1 + 971 63 41 0 + 972 62 40 1 + 973 62 40 0 + 974 62 41 1 + 975 62 41 0 +1024 59 43 0 +1025 59 43 1 +1026 59 42 0 +1027 59 42 1 +1028 58 43 0 +1029 58 43 1 +1030 58 42 0 +1031 58 42 1 +1032 56 42 1 +1033 56 42 0 +1034 56 43 1 +1035 56 43 0 +1036 57 42 1 +1037 57 42 0 +1038 57 43 1 +1039 57 43 0 +1056 51 42 0 +1057 51 42 1 +1058 51 43 0 +1059 51 43 1 +1060 50 42 0 +1061 50 42 1 +1062 50 43 0 +1063 50 43 1 +1064 48 43 1 +1065 48 43 0 +1066 48 42 1 +1067 48 42 0 +1068 49 43 1 +1069 49 43 0 +1070 49 42 1 +1071 49 42 0 +1072 52 42 0 +1073 52 42 1 +1074 52 43 0 +1075 52 43 1 +1076 53 42 0 +1077 53 42 1 +1078 53 43 0 +1079 53 43 1 +1080 55 43 1 +1081 55 43 0 +1082 55 42 1 +1083 55 42 0 +1084 54 43 1 +1085 54 43 0 +1086 54 42 1 +1087 54 42 0 +1088 60 43 0 +1089 60 43 1 +1090 60 42 0 +1091 60 42 1 +1092 61 43 0 +1093 61 43 1 +1094 61 42 0 +1095 61 42 1 +1096 63 42 1 +1097 63 42 0 +1098 63 43 1 +1099 63 43 0 +1100 62 42 1 +1101 62 42 0 +1102 62 43 1 +1103 62 43 0 +1152 59 45 0 +1153 59 45 1 +1154 59 44 0 +1155 59 44 1 +1156 58 45 0 +1157 58 45 1 +1158 58 44 0 +1159 58 44 1 +1160 56 44 1 +1161 56 44 0 +1162 56 45 1 +1163 56 45 0 +1164 57 44 1 +1165 57 44 0 +1166 57 45 1 +1167 57 45 0 +1184 51 44 0 +1185 51 44 1 +1186 51 45 0 +1187 51 45 1 +1188 50 44 0 +1189 50 44 1 +1190 50 45 0 +1191 50 45 1 +1192 48 45 1 +1193 48 45 0 +1194 48 44 1 +1195 48 44 0 +1196 49 45 1 +1197 49 45 0 +1198 49 44 1 +1199 49 44 0 +1200 52 44 0 +1201 52 44 1 +1202 52 45 0 +1203 52 45 1 +1204 53 44 0 +1205 53 44 1 +1206 53 45 0 +1207 53 45 1 +1208 55 45 1 +1209 55 45 0 +1210 55 44 1 +1211 55 44 0 +1212 54 45 1 +1213 54 45 0 +1214 54 44 1 +1215 54 44 0 +1216 60 45 0 +1217 60 45 1 +1218 60 44 0 +1219 60 44 1 +1220 61 45 0 +1221 61 45 1 +1222 61 44 0 +1223 61 44 1 +1224 63 44 1 +1225 63 44 0 +1226 63 45 1 +1227 63 45 0 +1228 62 44 1 +1229 62 44 0 +1230 62 45 1 +1231 62 45 0 +1280 59 47 0 +1281 59 47 1 +1282 59 46 0 +1283 59 46 1 +1284 58 47 0 +1285 58 47 1 +1286 58 46 0 +1287 58 46 1 +1288 56 46 1 +1289 56 46 0 +1290 56 47 1 +1291 56 47 0 +1292 57 46 1 +1293 57 46 0 +1294 57 47 1 +1295 57 47 0 +1312 51 46 0 +1313 51 46 1 +1314 51 47 0 +1315 51 47 1 +1316 50 46 0 +1317 50 46 1 +1318 50 47 0 +1319 50 47 1 +1320 48 47 1 +1321 48 47 0 +1322 48 46 1 +1323 48 46 0 +1324 49 47 1 +1325 49 47 0 +1326 49 46 1 +1327 49 46 0 +1328 52 46 0 +1329 52 46 1 +1330 52 47 0 +1331 52 47 1 +1332 53 46 0 +1333 53 46 1 +1334 53 47 0 +1335 53 47 1 +1336 55 47 1 +1337 55 47 0 +1338 55 46 1 +1339 55 46 0 +1340 54 47 1 +1341 54 47 0 +1342 54 46 1 +1343 54 46 0 +1344 60 47 0 +1345 60 47 1 +1346 60 46 0 +1347 60 46 1 +1348 61 47 0 +1349 61 47 1 +1350 61 46 0 +1351 61 46 1 +1352 63 46 1 +1353 63 46 0 +1354 63 47 1 +1355 63 47 0 +1356 62 46 1 +1357 62 46 0 +1358 62 47 1 +1359 62 47 0 +1408 59 49 0 +1409 59 49 1 +1410 59 48 0 +1411 59 48 1 +1412 58 49 0 +1413 58 49 1 +1414 58 48 0 +1415 58 48 1 +1416 56 48 1 +1417 56 48 0 +1418 56 49 1 +1419 56 49 0 +1420 57 48 1 +1421 57 48 0 +1422 57 49 1 +1423 57 49 0 +1440 51 48 0 +1441 51 48 1 +1442 51 49 0 +1443 51 49 1 +1444 50 48 0 +1445 50 48 1 +1446 50 49 0 +1447 50 49 1 +1448 48 49 1 +1449 48 49 0 +1450 48 48 1 +1451 48 48 0 +1452 49 49 1 +1453 49 49 0 +1454 49 48 1 +1455 49 48 0 +1456 52 48 0 +1457 52 48 1 +1458 52 49 0 +1459 52 49 1 +1460 53 48 0 +1461 53 48 1 +1462 53 49 0 +1463 53 49 1 +1464 55 49 1 +1465 55 49 0 +1466 55 48 1 +1467 55 48 0 +1468 54 49 1 +1469 54 49 0 +1470 54 48 1 +1471 54 48 0 +1472 60 49 0 +1473 60 49 1 +1474 60 48 0 +1475 60 48 1 +1476 61 49 0 +1477 61 49 1 +1478 61 48 0 +1479 61 48 1 +1480 63 48 1 +1481 63 48 0 +1482 63 49 1 +1483 63 49 0 +1484 62 48 1 +1485 62 48 0 +1486 62 49 1 +1487 62 49 0 +1536 59 51 0 +1537 59 51 1 +1538 59 50 0 +1539 59 50 1 +1540 58 51 0 +1541 58 51 1 +1542 58 50 0 +1543 58 50 1 +1544 56 50 1 +1545 56 50 0 +1546 56 51 1 +1547 56 51 0 +1548 57 50 1 +1549 57 50 0 +1550 57 51 1 +1551 57 51 0 +1568 51 50 0 +1569 51 50 1 +1570 51 51 0 +1571 51 51 1 +1572 50 50 0 +1573 50 50 1 +1574 50 51 0 +1575 50 51 1 +1576 48 51 1 +1577 48 51 0 +1578 48 50 1 +1579 48 50 0 +1580 49 51 1 +1581 49 51 0 +1582 49 50 1 +1583 49 50 0 +1584 52 50 0 +1585 52 50 1 +1586 52 51 0 +1587 52 51 1 +1588 53 50 0 +1589 53 50 1 +1590 53 51 0 +1591 53 51 1 +1592 55 51 1 +1593 55 51 0 +1594 55 50 1 +1595 55 50 0 +1596 54 51 1 +1597 54 51 0 +1598 54 50 1 +1599 54 50 0 +1600 60 51 0 +1601 60 51 1 +1602 60 50 0 +1603 60 50 1 +1604 61 51 0 +1605 61 51 1 +1606 61 50 0 +1607 61 50 1 +1608 63 50 1 +1609 63 50 0 +1610 63 51 1 +1611 63 51 0 +1612 62 50 1 +1613 62 50 0 +1614 62 51 1 +1615 62 51 0 +1664 59 53 0 +1665 59 53 1 +1666 59 52 0 +1667 59 52 1 +1668 58 53 0 +1669 58 53 1 +1670 58 52 0 +1671 58 52 1 +1672 56 52 1 +1673 56 52 0 +1674 56 53 1 +1675 56 53 0 +1676 57 52 1 +1677 57 52 0 +1678 57 53 1 +1679 57 53 0 +1696 51 52 0 +1697 51 52 1 +1698 51 53 0 +1699 51 53 1 +1700 50 52 0 +1701 50 52 1 +1702 50 53 0 +1703 50 53 1 +1704 48 53 1 +1705 48 53 0 +1706 48 52 1 +1707 48 52 0 +1708 49 53 1 +1709 49 53 0 +1710 49 52 1 +1711 49 52 0 +1712 52 52 0 +1713 52 52 1 +1714 52 53 0 +1715 52 53 1 +1716 53 52 0 +1717 53 52 1 +1718 53 53 0 +1719 53 53 1 +1720 55 53 1 +1721 55 53 0 +1722 55 52 1 +1723 55 52 0 +1724 54 53 1 +1725 54 53 0 +1726 54 52 1 +1727 54 52 0 +1728 60 53 0 +1729 60 53 1 +1730 60 52 0 +1731 60 52 1 +1732 61 53 0 +1733 61 53 1 +1734 61 52 0 +1735 61 52 1 +1736 63 52 1 +1737 63 52 0 +1738 63 53 1 +1739 63 53 0 +1740 62 52 1 +1741 62 52 0 +1742 62 53 1 +1743 62 53 0 +1792 59 55 0 +1793 59 55 1 +1794 59 54 0 +1795 59 54 1 +1796 58 55 0 +1797 58 55 1 +1798 58 54 0 +1799 58 54 1 +1800 56 54 1 +1801 56 54 0 +1802 56 55 1 +1803 56 55 0 +1804 57 54 1 +1805 57 54 0 +1806 57 55 1 +1807 57 55 0 +1824 51 54 0 +1825 51 54 1 +1826 51 55 0 +1827 51 55 1 +1828 50 54 0 +1829 50 54 1 +1830 50 55 0 +1831 50 55 1 +1832 48 55 1 +1833 48 55 0 +1834 48 54 1 +1835 48 54 0 +1836 49 55 1 +1837 49 55 0 +1838 49 54 1 +1839 49 54 0 +1840 52 54 0 +1841 52 54 1 +1842 52 55 0 +1843 52 55 1 +1844 53 54 0 +1845 53 54 1 +1846 53 55 0 +1847 53 55 1 +1848 55 55 1 +1849 55 55 0 +1850 55 54 1 +1851 55 54 0 +1852 54 55 1 +1853 54 55 0 +1854 54 54 1 +1855 54 54 0 +1856 60 55 0 +1857 60 55 1 +1858 60 54 0 +1859 60 54 1 +1860 61 55 0 +1861 61 55 1 +1862 61 54 0 +1863 61 54 1 +1864 63 54 1 +1865 63 54 0 +1866 63 55 1 +1867 63 55 0 +1868 62 54 1 +1869 62 54 0 +1870 62 55 1 +1871 62 55 0 +2176 59 27 0 +2177 59 27 1 +2178 59 26 0 +2179 59 26 1 +2180 58 27 0 +2181 58 27 1 +2182 58 26 0 +2183 58 26 1 +2184 56 26 1 +2185 56 26 0 +2186 56 27 1 +2187 56 27 0 +2188 57 26 1 +2189 57 26 0 +2190 57 27 1 +2191 57 27 0 +2208 51 26 0 +2209 51 26 1 +2210 51 27 0 +2211 51 27 1 +2212 50 26 0 +2213 50 26 1 +2214 50 27 0 +2215 50 27 1 +2216 48 27 1 +2217 48 27 0 +2218 48 26 1 +2219 48 26 0 +2220 49 27 1 +2221 49 27 0 +2222 49 26 1 +2223 49 26 0 +2224 52 26 0 +2225 52 26 1 +2226 52 27 0 +2227 52 27 1 +2228 53 26 0 +2229 53 26 1 +2230 53 27 0 +2231 53 27 1 +2232 55 27 1 +2233 55 27 0 +2234 55 26 1 +2235 55 26 0 +2236 54 27 1 +2237 54 27 0 +2238 54 26 1 +2239 54 26 0 +2240 60 27 0 +2241 60 27 1 +2242 60 26 0 +2243 60 26 1 +2244 61 27 0 +2245 61 27 1 +2246 61 26 0 +2247 61 26 1 +2248 63 26 1 +2249 63 26 0 +2250 63 27 1 +2251 63 27 0 +2252 62 26 1 +2253 62 26 0 +2254 62 27 1 +2255 62 27 0 +2304 59 25 0 +2305 59 25 1 +2306 59 24 0 +2307 59 24 1 +2308 58 25 0 +2309 58 25 1 +2310 58 24 0 +2311 58 24 1 +2312 56 24 1 +2313 56 24 0 +2314 56 25 1 +2315 56 25 0 +2316 57 24 1 +2317 57 24 0 +2318 57 25 1 +2319 57 25 0 +2336 51 24 0 +2337 51 24 1 +2338 51 25 0 +2339 51 25 1 +2340 50 24 0 +2341 50 24 1 +2342 50 25 0 +2343 50 25 1 +2344 48 25 1 +2345 48 25 0 +2346 48 24 1 +2347 48 24 0 +2348 49 25 1 +2349 49 25 0 +2350 49 24 1 +2351 49 24 0 +2352 52 24 0 +2353 52 24 1 +2354 52 25 0 +2355 52 25 1 +2356 53 24 0 +2357 53 24 1 +2358 53 25 0 +2359 53 25 1 +2360 55 25 1 +2361 55 25 0 +2362 55 24 1 +2363 55 24 0 +2364 54 25 1 +2365 54 25 0 +2366 54 24 1 +2367 54 24 0 +2368 60 25 0 +2369 60 25 1 +2370 60 24 0 +2371 60 24 1 +2372 61 25 0 +2373 61 25 1 +2374 61 24 0 +2375 61 24 1 +2376 63 24 1 +2377 63 24 0 +2378 63 25 1 +2379 63 25 0 +2380 62 24 1 +2381 62 24 0 +2382 62 25 1 +2383 62 25 0 +2432 59 23 0 +2433 59 23 1 +2434 59 22 0 +2435 59 22 1 +2436 58 23 0 +2437 58 23 1 +2438 58 22 0 +2439 58 22 1 +2440 56 22 1 +2441 56 22 0 +2442 56 23 1 +2443 56 23 0 +2444 57 22 1 +2445 57 22 0 +2446 57 23 1 +2447 57 23 0 +2464 51 22 0 +2465 51 22 1 +2466 51 23 0 +2467 51 23 1 +2468 50 22 0 +2469 50 22 1 +2470 50 23 0 +2471 50 23 1 +2472 48 23 1 +2473 48 23 0 +2474 48 22 1 +2475 48 22 0 +2476 49 23 1 +2477 49 23 0 +2478 49 22 1 +2479 49 22 0 +2480 52 22 0 +2481 52 22 1 +2482 52 23 0 +2483 52 23 1 +2484 53 22 0 +2485 53 22 1 +2486 53 23 0 +2487 53 23 1 +2488 55 23 1 +2489 55 23 0 +2490 55 22 1 +2491 55 22 0 +2492 54 23 1 +2493 54 23 0 +2494 54 22 1 +2495 54 22 0 +2496 60 23 0 +2497 60 23 1 +2498 60 22 0 +2499 60 22 1 +2500 61 23 0 +2501 61 23 1 +2502 61 22 0 +2503 61 22 1 +2504 63 22 1 +2505 63 22 0 +2506 63 23 1 +2507 63 23 0 +2508 62 22 1 +2509 62 22 0 +2510 62 23 1 +2511 62 23 0 +2560 59 21 0 +2561 59 21 1 +2562 59 20 0 +2563 59 20 1 +2564 58 21 0 +2565 58 21 1 +2566 58 20 0 +2567 58 20 1 +2568 56 20 1 +2569 56 20 0 +2570 56 21 1 +2571 56 21 0 +2572 57 20 1 +2573 57 20 0 +2574 57 21 1 +2575 57 21 0 +2592 51 20 0 +2593 51 20 1 +2594 51 21 0 +2595 51 21 1 +2596 50 20 0 +2597 50 20 1 +2598 50 21 0 +2599 50 21 1 +2600 48 21 1 +2601 48 21 0 +2602 48 20 1 +2603 48 20 0 +2604 49 21 1 +2605 49 21 0 +2606 49 20 1 +2607 49 20 0 +2608 52 20 0 +2609 52 20 1 +2610 52 21 0 +2611 52 21 1 +2612 53 20 0 +2613 53 20 1 +2614 53 21 0 +2615 53 21 1 +2616 55 21 1 +2617 55 21 0 +2618 55 20 1 +2619 55 20 0 +2620 54 21 1 +2621 54 21 0 +2622 54 20 1 +2623 54 20 0 +2624 60 21 0 +2625 60 21 1 +2626 60 20 0 +2627 60 20 1 +2628 61 21 0 +2629 61 21 1 +2630 61 20 0 +2631 61 20 1 +2632 63 20 1 +2633 63 20 0 +2634 63 21 1 +2635 63 21 0 +2636 62 20 1 +2637 62 20 0 +2638 62 21 1 +2639 62 21 0 +2688 59 19 0 +2689 59 19 1 +2690 59 18 0 +2691 59 18 1 +2692 58 19 0 +2693 58 19 1 +2694 58 18 0 +2695 58 18 1 +2696 56 18 1 +2697 56 18 0 +2698 56 19 1 +2699 56 19 0 +2700 57 18 1 +2701 57 18 0 +2702 57 19 1 +2703 57 19 0 +2720 51 18 0 +2721 51 18 1 +2722 51 19 0 +2723 51 19 1 +2724 50 18 0 +2725 50 18 1 +2726 50 19 0 +2727 50 19 1 +2728 48 19 1 +2729 48 19 0 +2730 48 18 1 +2731 48 18 0 +2732 49 19 1 +2733 49 19 0 +2734 49 18 1 +2735 49 18 0 +2736 52 18 0 +2737 52 18 1 +2738 52 19 0 +2739 52 19 1 +2740 53 18 0 +2741 53 18 1 +2742 53 19 0 +2743 53 19 1 +2744 55 19 1 +2745 55 19 0 +2746 55 18 1 +2747 55 18 0 +2748 54 19 1 +2749 54 19 0 +2750 54 18 1 +2751 54 18 0 +2752 60 19 0 +2753 60 19 1 +2754 60 18 0 +2755 60 18 1 +2756 61 19 0 +2757 61 19 1 +2758 61 18 0 +2759 61 18 1 +2760 63 18 1 +2761 63 18 0 +2762 63 19 1 +2763 63 19 0 +2764 62 18 1 +2765 62 18 0 +2766 62 19 1 +2767 62 19 0 +2816 59 17 0 +2817 59 17 1 +2818 59 16 0 +2819 59 16 1 +2820 58 17 0 +2821 58 17 1 +2822 58 16 0 +2823 58 16 1 +2824 56 16 1 +2825 56 16 0 +2826 56 17 1 +2827 56 17 0 +2828 57 16 1 +2829 57 16 0 +2830 57 17 1 +2831 57 17 0 +2848 51 16 0 +2849 51 16 1 +2850 51 17 0 +2851 51 17 1 +2852 50 16 0 +2853 50 16 1 +2854 50 17 0 +2855 50 17 1 +2856 48 17 1 +2857 48 17 0 +2858 48 16 1 +2859 48 16 0 +2860 49 17 1 +2861 49 17 0 +2862 49 16 1 +2863 49 16 0 +2864 52 16 0 +2865 52 16 1 +2866 52 17 0 +2867 52 17 1 +2868 53 16 0 +2869 53 16 1 +2870 53 17 0 +2871 53 17 1 +2872 55 17 1 +2873 55 17 0 +2874 55 16 1 +2875 55 16 0 +2876 54 17 1 +2877 54 17 0 +2878 54 16 1 +2879 54 16 0 +2880 60 17 0 +2881 60 17 1 +2882 60 16 0 +2883 60 16 1 +2884 61 17 0 +2885 61 17 1 +2886 61 16 0 +2887 61 16 1 +2888 63 16 1 +2889 63 16 0 +2890 63 17 1 +2891 63 17 0 +2892 62 16 1 +2893 62 16 0 +2894 62 17 1 +2895 62 17 0 +2944 59 15 0 +2945 59 15 1 +2946 59 14 0 +2947 59 14 1 +2948 58 15 0 +2949 58 15 1 +2950 58 14 0 +2951 58 14 1 +2952 56 14 1 +2953 56 14 0 +2954 56 15 1 +2955 56 15 0 +2956 57 14 1 +2957 57 14 0 +2958 57 15 1 +2959 57 15 0 +2976 51 14 0 +2977 51 14 1 +2978 51 15 0 +2979 51 15 1 +2980 50 14 0 +2981 50 14 1 +2982 50 15 0 +2983 50 15 1 +2984 48 15 1 +2985 48 15 0 +2986 48 14 1 +2987 48 14 0 +2988 49 15 1 +2989 49 15 0 +2990 49 14 1 +2991 49 14 0 +2992 52 14 0 +2993 52 14 1 +2994 52 15 0 +2995 52 15 1 +2996 53 14 0 +2997 53 14 1 +2998 53 15 0 +2999 53 15 1 +3000 55 15 1 +3001 55 15 0 +3002 55 14 1 +3003 55 14 0 +3004 54 15 1 +3005 54 15 0 +3006 54 14 1 +3007 54 14 0 +3008 60 15 0 +3009 60 15 1 +3010 60 14 0 +3011 60 14 1 +3012 61 15 0 +3013 61 15 1 +3014 61 14 0 +3015 61 14 1 +3016 63 14 1 +3017 63 14 0 +3018 63 15 1 +3019 63 15 0 +3020 62 14 1 +3021 62 14 0 +3022 62 15 1 +3023 62 15 0 +3072 59 13 0 +3073 59 13 1 +3074 59 12 0 +3075 59 12 1 +3076 58 13 0 +3077 58 13 1 +3078 58 12 0 +3079 58 12 1 +3080 56 12 1 +3081 56 12 0 +3082 56 13 1 +3083 56 13 0 +3084 57 12 1 +3085 57 12 0 +3086 57 13 1 +3087 57 13 0 +3104 51 12 0 +3105 51 12 1 +3106 51 13 0 +3107 51 13 1 +3108 50 12 0 +3109 50 12 1 +3110 50 13 0 +3111 50 13 1 +3112 48 13 1 +3113 48 13 0 +3114 48 12 1 +3115 48 12 0 +3116 49 13 1 +3117 49 13 0 +3118 49 12 1 +3119 49 12 0 +3120 52 12 0 +3121 52 12 1 +3122 52 13 0 +3123 52 13 1 +3124 53 12 0 +3125 53 12 1 +3126 53 13 0 +3127 53 13 1 +3128 55 13 1 +3129 55 13 0 +3130 55 12 1 +3131 55 12 0 +3132 54 13 1 +3133 54 13 0 +3134 54 12 1 +3135 54 12 0 +3136 60 13 0 +3137 60 13 1 +3138 60 12 0 +3139 60 12 1 +3140 61 13 0 +3141 61 13 1 +3142 61 12 0 +3143 61 12 1 +3144 63 12 1 +3145 63 12 0 +3146 63 13 1 +3147 63 13 0 +3148 62 12 1 +3149 62 12 0 +3150 62 13 1 +3151 62 13 0 +3200 59 11 0 +3201 59 11 1 +3202 59 10 0 +3203 59 10 1 +3204 58 11 0 +3205 58 11 1 +3206 58 10 0 +3207 58 10 1 +3208 56 10 1 +3209 56 10 0 +3210 56 11 1 +3211 56 11 0 +3212 57 10 1 +3213 57 10 0 +3214 57 11 1 +3215 57 11 0 +3232 51 10 0 +3233 51 10 1 +3234 51 11 0 +3235 51 11 1 +3236 50 10 0 +3237 50 10 1 +3238 50 11 0 +3239 50 11 1 +3240 48 11 1 +3241 48 11 0 +3242 48 10 1 +3243 48 10 0 +3244 49 11 1 +3245 49 11 0 +3246 49 10 1 +3247 49 10 0 +3248 52 10 0 +3249 52 10 1 +3250 52 11 0 +3251 52 11 1 +3252 53 10 0 +3253 53 10 1 +3254 53 11 0 +3255 53 11 1 +3256 55 11 1 +3257 55 11 0 +3258 55 10 1 +3259 55 10 0 +3260 54 11 1 +3261 54 11 0 +3262 54 10 1 +3263 54 10 0 +3264 60 11 0 +3265 60 11 1 +3266 60 10 0 +3267 60 10 1 +3268 61 11 0 +3269 61 11 1 +3270 61 10 0 +3271 61 10 1 +3272 63 10 1 +3273 63 10 0 +3274 63 11 1 +3275 63 11 0 +3276 62 10 1 +3277 62 10 0 +3278 62 11 1 +3279 62 11 0 +3328 59 9 0 +3329 59 9 1 +3330 59 8 0 +3331 59 8 1 +3332 58 9 0 +3333 58 9 1 +3334 58 8 0 +3335 58 8 1 +3336 56 8 1 +3337 56 8 0 +3338 56 9 1 +3339 56 9 0 +3340 57 8 1 +3341 57 8 0 +3342 57 9 1 +3343 57 9 0 +3360 51 8 0 +3361 51 8 1 +3362 51 9 0 +3363 51 9 1 +3364 50 8 0 +3365 50 8 1 +3366 50 9 0 +3367 50 9 1 +3368 48 9 1 +3369 48 9 0 +3370 48 8 1 +3371 48 8 0 +3372 49 9 1 +3373 49 9 0 +3374 49 8 1 +3375 49 8 0 +3376 52 8 0 +3377 52 8 1 +3378 52 9 0 +3379 52 9 1 +3380 53 8 0 +3381 53 8 1 +3382 53 9 0 +3383 53 9 1 +3384 55 9 1 +3385 55 9 0 +3386 55 8 1 +3387 55 8 0 +3388 54 9 1 +3389 54 9 0 +3390 54 8 1 +3391 54 8 0 +3392 60 9 0 +3393 60 9 1 +3394 60 8 0 +3395 60 8 1 +3396 61 9 0 +3397 61 9 1 +3398 61 8 0 +3399 61 8 1 +3400 63 8 1 +3401 63 8 0 +3402 63 9 1 +3403 63 9 0 +3404 62 8 1 +3405 62 8 0 +3406 62 9 1 +3407 62 9 0 +3456 59 7 0 +3457 59 7 1 +3458 59 6 0 +3459 59 6 1 +3460 58 7 0 +3461 58 7 1 +3462 58 6 0 +3463 58 6 1 +3464 56 6 1 +3465 56 6 0 +3466 56 7 1 +3467 56 7 0 +3468 57 6 1 +3469 57 6 0 +3470 57 7 1 +3471 57 7 0 +3488 51 6 0 +3489 51 6 1 +3490 51 7 0 +3491 51 7 1 +3492 50 6 0 +3493 50 6 1 +3494 50 7 0 +3495 50 7 1 +3496 48 7 1 +3497 48 7 0 +3498 48 6 1 +3499 48 6 0 +3500 49 7 1 +3501 49 7 0 +3502 49 6 1 +3503 49 6 0 +3504 52 6 0 +3505 52 6 1 +3506 52 7 0 +3507 52 7 1 +3508 53 6 0 +3509 53 6 1 +3510 53 7 0 +3511 53 7 1 +3512 55 7 1 +3513 55 7 0 +3514 55 6 1 +3515 55 6 0 +3516 54 7 1 +3517 54 7 0 +3518 54 6 1 +3519 54 6 0 +3520 60 7 0 +3521 60 7 1 +3522 60 6 0 +3523 60 6 1 +3524 61 7 0 +3525 61 7 1 +3526 61 6 0 +3527 61 6 1 +3528 63 6 1 +3529 63 6 0 +3530 63 7 1 +3531 63 7 0 +3532 62 6 1 +3533 62 6 0 +3534 62 7 1 +3535 62 7 0 +3584 59 5 0 +3585 59 5 1 +3586 59 4 0 +3587 59 4 1 +3588 58 5 0 +3589 58 5 1 +3590 58 4 0 +3591 58 4 1 +3592 56 4 1 +3593 56 4 0 +3594 56 5 1 +3595 56 5 0 +3596 57 4 1 +3597 57 4 0 +3598 57 5 1 +3599 57 5 0 +3616 51 4 0 +3617 51 4 1 +3618 51 5 0 +3619 51 5 1 +3620 50 4 0 +3621 50 4 1 +3622 50 5 0 +3623 50 5 1 +3624 48 5 1 +3625 48 5 0 +3626 48 4 1 +3627 48 4 0 +3628 49 5 1 +3629 49 5 0 +3630 49 4 1 +3631 49 4 0 +3632 52 4 0 +3633 52 4 1 +3634 52 5 0 +3635 52 5 1 +3636 53 4 0 +3637 53 4 1 +3638 53 5 0 +3639 53 5 1 +3640 55 5 1 +3641 55 5 0 +3642 55 4 1 +3643 55 4 0 +3644 54 5 1 +3645 54 5 0 +3646 54 4 1 +3647 54 4 0 +3648 60 5 0 +3649 60 5 1 +3650 60 4 0 +3651 60 4 1 +3652 61 5 0 +3653 61 5 1 +3654 61 4 0 +3655 61 4 1 +3656 63 4 1 +3657 63 4 0 +3658 63 5 1 +3659 63 5 0 +3660 62 4 1 +3661 62 4 0 +3662 62 5 1 +3663 62 5 0 +3712 59 3 0 +3713 59 3 1 +3714 59 2 0 +3715 59 2 1 +3716 58 3 0 +3717 58 3 1 +3718 58 2 0 +3719 58 2 1 +3720 56 2 1 +3721 56 2 0 +3722 56 3 1 +3723 56 3 0 +3724 57 2 1 +3725 57 2 0 +3726 57 3 1 +3727 57 3 0 +3744 51 2 0 +3745 51 2 1 +3746 51 3 0 +3747 51 3 1 +3748 50 2 0 +3749 50 2 1 +3750 50 3 0 +3751 50 3 1 +3752 48 3 1 +3753 48 3 0 +3754 48 2 1 +3755 48 2 0 +3756 49 3 1 +3757 49 3 0 +3758 49 2 1 +3759 49 2 0 +3760 52 2 0 +3761 52 2 1 +3762 52 3 0 +3763 52 3 1 +3764 53 2 0 +3765 53 2 1 +3766 53 3 0 +3767 53 3 1 +3768 55 3 1 +3769 55 3 0 +3770 55 2 1 +3771 55 2 0 +3772 54 3 1 +3773 54 3 0 +3774 54 2 1 +3775 54 2 0 +3776 60 3 0 +3777 60 3 1 +3778 60 2 0 +3779 60 2 1 +3780 61 3 0 +3781 61 3 1 +3782 61 2 0 +3783 61 2 1 +3784 63 2 1 +3785 63 2 0 +3786 63 3 1 +3787 63 3 0 +3788 62 2 1 +3789 62 2 0 +3790 62 3 1 +3791 62 3 0 +3840 59 1 0 +3841 59 1 1 +3842 59 0 0 +3843 59 0 1 +3844 58 1 0 +3845 58 1 1 +3846 58 0 0 +3847 58 0 1 +3848 56 0 1 +3849 56 0 0 +3850 56 1 1 +3851 56 1 0 +3852 57 0 1 +3853 57 0 0 +3854 57 1 1 +3855 57 1 0 +3872 51 0 0 +3873 51 0 1 +3874 51 1 0 +3875 51 1 1 +3876 50 0 0 +3877 50 0 1 +3878 50 1 0 +3879 50 1 1 +3880 48 1 1 +3881 48 1 0 +3882 48 0 1 +3883 48 0 0 +3884 49 1 1 +3885 49 1 0 +3886 49 0 1 +3887 49 0 0 +3888 52 0 0 +3889 52 0 1 +3890 52 1 0 +3891 52 1 1 +3892 53 0 0 +3893 53 0 1 +3894 53 1 0 +3895 53 1 1 +3896 55 1 1 +3897 55 1 0 +3898 55 0 1 +3899 55 0 0 +3900 54 1 1 +3901 54 1 0 +3902 54 0 1 +3903 54 0 0 +3904 60 1 0 +3905 60 1 1 +3906 60 0 0 +3907 60 0 1 +3908 61 1 0 +3909 61 1 1 +3910 61 0 0 +3911 61 0 1 +3912 63 0 1 +3913 63 0 0 +3914 63 1 1 +3915 63 1 0 +3916 62 0 1 +3917 62 0 0 +3918 62 1 1 +3919 62 1 0 diff --git a/Detectors/PHOS/base/files/alignment.root b/Detectors/PHOS/base/files/alignment.root new file mode 100644 index 0000000000000..d4248de4167ce Binary files /dev/null and b/Detectors/PHOS/base/files/alignment.root differ diff --git a/Detectors/PHOS/base/include/PHOSBase/Geometry.h b/Detectors/PHOS/base/include/PHOSBase/Geometry.h index 8a48225c28dc0..04d3491c4dfd0 100644 --- a/Detectors/PHOS/base/include/PHOSBase/Geometry.h +++ b/Detectors/PHOS/base/include/PHOSBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,10 +13,14 @@ #define ALICEO2_PHOS_GEOMETRY_H_ #include <string> +#include <array> #include <Rtypes.h> #include <RStringView.h> +#include <TGeoMatrix.h> +#include <TVector3.h> #include <TMath.h> +#include <array> namespace o2 { @@ -100,8 +105,24 @@ class Geometry static bool absToRelNumbering(short absId, char* relid); static char absIdToModule(short absId); static void absIdToRelPosInModule(short absId, float& x, float& z); + static void relPosToRelId(short module, float x, float z, char* relId); static bool relToAbsNumbering(const char* RelId, short& AbsId); - // converts the absolute PHOS numbering to a relative + + //Converters for TRU digits + static bool truAbsToRelNumbering(short truId, char* relid); + static short truRelToAbsNumbering(const char* relId); + static bool truRelId2RelId(const char* truRelId, char* relId); + static short relPosToTruId(char mod, float x, float z, short& ddl); + + //local position to absId + static void relPosToAbsId(char module, float x, float z, short& absId); + + // convert local position in module to global position in ALICE + void local2Global(char module, float x, float z, TVector3& globaPos) const; + + // calculate impact position on PHOS + bool impactOnPHOS(const TVector3& vtx, const TVector3& p, + short& module, float& z, float& x) const; static int getTotalNCells() { return 56 * 64 * 4; } // TODO: evaluate from real geometry static bool isCellExists(short absId) @@ -111,8 +132,13 @@ class Geometry const std::string& GetName() const { return mGeoName; } + const TGeoHMatrix* getAlignmentMatrix(int mod) const { return &(mPHOS[mod]); } + private: - static Geometry* sGeom; // Pointer to the unique instance of the singleton + static constexpr float CELLSTEP = 2.25; + + static Geometry* sGeom; // Pointer to the unique instance of the singleton + std::array<TGeoHMatrix, 5> mPHOS; //Rotation/shift matrices std::string mGeoName; ///< Geometry name string diff --git a/Detectors/PHOS/base/include/PHOSBase/Hit.h b/Detectors/PHOS/base/include/PHOSBase/Hit.h index f987158686a1f..84f10f15a431c 100644 --- a/Detectors/PHOS/base/include/PHOSBase/Hit.h +++ b/Detectors/PHOS/base/include/PHOSBase/Hit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/base/include/PHOSBase/Mapping.h b/Detectors/PHOS/base/include/PHOSBase/Mapping.h new file mode 100644 index 0000000000000..7921eda82a149 --- /dev/null +++ b/Detectors/PHOS/base/include/PHOSBase/Mapping.h @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class Mapping +/// \brief Checks validity of hardware address (HW) and transform it to digit AbsId index +/// +/// \author Dmitri Peresunko +/// \since Jan.2020 +/// + +#ifndef PHOSMAPPING_H_ +#define PHOSMAPPING_H_ + +#include <string_view> +#include <vector> +#include <utility> +#include "Rtypes.h" + +namespace o2 +{ + +namespace phos +{ + +class Mapping +{ + public: + enum ErrorStatus { kOK, + kWrongDDL, + kWrongHWAddress, + kWrongAbsId, + kWrongCaloFlag, + kNotInitialized }; + static constexpr short NCHANNELS = 14336; ///< Number of channels starting from 1 + static constexpr short NHWPERDDL = 2048; ///< Number of HW addressed per DDL + static constexpr short NMaxHWAddress = 3929; ///< Maximal HW address (size of array) + static constexpr short NDDL = 14; ///< Total number of DDLs + static constexpr short NTRUBranchReadoutChannels = 112; ///< Number of TRU readout channels per branch + static constexpr short NTRUReadoutChannels = 3136; ///< Total number of TRU readout channels + static constexpr short TRUFinalProductionChannel = 123; // The last channel of production bits, contains markesr to choose between 2x2 and 4x4 algorithm + + enum CaloFlag { kLowGain, + kHighGain, + kTRU }; + + ~Mapping() = default; + + //Getters for unique instance of Mapping + static Mapping* Instance(); + static Mapping* Instance(std::basic_string_view<char> path); + + /// \brief convert hardware address to absId and caloFlag + ErrorStatus hwToAbsId(short ddl, short hw, short& absId, CaloFlag& caloFlag) const; + /// \brief convert absId and caloflag to hardware address and ddl + ErrorStatus absIdTohw(short absId, short caloFlag, short& ddl, short& hwAddr) const; + + /// \brief convert ddl number to crorc and link number (TODO!!!) + static void ddlToCrorcLink(short iddl, short& crorc, short& link) + { + crorc = iddl / 8; + link = iddl % 8; + } + + ErrorStatus setMapping(); + + //Select TRU readout channels or TRU flag channels + static bool isTRUReadoutchannel(short hwAddress) { return (hwAddress < 112) || (hwAddress > 2048 && hwAddress < 2048 + 112); } + + protected: + Mapping() = default; + Mapping(std::basic_string_view<char> path); + + /// \brief Construct vector for conversion only if necessary + ErrorStatus constructAbsToHWMatrix(); + + private: + static Mapping* sMapping; ///< Pointer to the unique instance of the singleton + std::string mPath = ""; ///< path to mapping files + bool mInitialized = false; ///< If conversion tables created + bool mInvInitialized = false; ///< If inverse conversion tables created + short mAbsId[NDDL][NMaxHWAddress] = {0}; ///< Conversion table (ddl,branch,fec,chip,channel) to absId + CaloFlag mCaloFlag[NDDL][NMaxHWAddress] = {kTRU}; ///< Conversion table (ddl,branch,fec,chip,channel) to absId + short mAbsToHW[NCHANNELS][3][2] = {0}; ///< Conversion table (AbsId,caloFlag) to pair (ddl, hw address) + + ClassDefNV(Mapping, 1); +}; // End of Mapping + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/base/include/PHOSBase/PHOSSimParams.h b/Detectors/PHOS/base/include/PHOSBase/PHOSSimParams.h index ceb1c49ed22eb..c53a4360071a2 100644 --- a/Detectors/PHOS/base/include/PHOSBase/PHOSSimParams.h +++ b/Detectors/PHOS/base/include/PHOSBase/PHOSSimParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,11 +32,15 @@ struct PHOSSimParams : public o2::conf::ConfigurableParamHelper<PHOSSimParams> { float mAPDFactor = (13.418 / mLightYieldMean / 100.) * 300.; // factor relating light yield and APD response //Parameters used in electronic noise calculation and thresholds (Digitizer) + float mReadoutTime = 5.; ///< Read-out time in ns for default simulaionts + float mDeadTime = 20.; ///< PHOS dead time (includes Read-out time i.e. mDeadTime>=mReadoutTime) + float mReadoutTimePU = 2000.; ///< Read-out time in ns if pileup simulation on in DigitizerSpec + float mDeadTimePU = 30000.; ///< PHOS dead time if pileup simulation on in DigitizerSpec bool mApplyTimeResolution = false; ///< Apply time resolution in digitization bool mApplyNonLinearity = false; ///< Apply energy non-linearity in digitization bool mApplyDigitization = false; ///< Apply energy digitization in digitization float mAPDNoise = 0.005; ///< RMS of APD noise - float mDigitThreshold = 2.5; ///< minimal energy to keep digit in ADC counts + float mDigitThreshold = 2.; ///< minimal energy to keep digit in ADC counts float mADCwidth = 0.005; ///< width of ADC channel in GeV float mTOFa = 0.5e-9; ///< constant term of TOF resolution float mTOFb = 1.e-9; ///< stohastic term of TOF resolution @@ -43,25 +48,48 @@ struct PHOSSimParams : public o2::conf::ConfigurableParamHelper<PHOSSimParams> { float mCellNonLineaityB = 0.109; ///< Energy scale of cel non-linearity float mCellNonLineaityC = 1.; ///< Overall calibration - float mZSthreshold = 2.5; ///< Zero Suppression threshold + short mZSthreshold = 1; ///< Zero Suppression threshold float mTimeResolutionA = 2.; ///< Time resolution parameter A (in ns) float mTimeResolutionB = 2.; ///< Time resolution parameter B (in ns/GeV) float mTimeResThreshold = 0.5; ///< threshold for time resolution calculation (in GeV) float mMinNoiseTime = -200.; ///< minimum time in noise channels (in ns) float mMaxNoiseTime = 2000.; ///< minimum time in noise channels (in ns) + float mTrig2x2MinThreshold = 800.; ///< threshold to simulate 2x2 trigger turn-on curve (in ADC counts~0.005 GeV/count!) + float mTrig4x4MinThreshold = 900.; ///< threshold to simulate 4x4 trigger turn-on curve (in ADC counts!) + + //Parameters used in Raw simulation + float mSampleDecayTime = 0.091; ///< Time parameter in Gamma2 function (1/tau, 100.e-9/2.1e-6) + + // //Parameters used in raw data reconstruction + short mSpikeThreshold = 100; ///< Single spike >100 ADC channels + short mBaseLine = 0; ///< + short mPreSamples = 2; ///< number of pre-samples readout before sample (if no pedestal subtrauction) + short mMCOverflow = 970; ///< Overflow level for MC simulations: 1023-(pedestal~50) + float mTimeTick = 100.; ///< ns to PHOS digitization step conversion + float mSampleTimeFitAccuracy = 1.e-3; //Abs accuracy of time fit of saturated samples (in 100ns tick units) + float mSampleAmpFitAccuracy = 1.e-2; //Relative accuracy of amp. fit + short mNIterations = 5; ///< maximal number of iterations in oveflow sample fit + + // bool mSubtractPedestal = false ; ///< subtract pedestals + // bool mCreateSampleQualityOutput = false ; ///< Create stream of sample quality + // bool mApplyBadMap = false ; ///< Apply bad map in sample fitting + // short mChiMinCut = 0 ; ///< Minimal cut on sample quality + // short mChiMaxCut = 1000; ///< Maximal cut on sample quality + // std::string mFitterVersion = "default"; ///< version of raw fitter to be used + //Parameters used in clusterization - float mLogWeight = 4.5; ///< Cutoff used in log. weight calculation - float mDigitMinEnergy = 0.010; ///< Minimal energy of digits to be used in cluster (GeV) - float mClusteringThreshold = 0.050; ///< Minimal energy of digit to start clustering (GeV) - float mLocalMaximumCut = 0.015; ///< Minimal height of local maximum over neighbours - bool mUnfoldClusters = false; ///< To perform cluster unfolding - float mUnfogingEAccuracy = 1.e-3; ///< Accuracy of energy calculation in unfoding prosedure (GeV) - float mUnfogingXZAccuracy = 1.e-1; ///< Accuracy of position calculation in unfolding procedure (cm) - int mNMaxIterations = 10; ///< Maximal number of iterations in unfolding procedure - int mNLMMax = 30; ///< Maximal number of local maxima in unfolding - float mCoreR = 3.5; ///< Radius to caluclate core energy - float mSortingDelta = 1.; ///< used in sorting clusters + float mLogWeight = 4.5; ///< Cutoff used in log. weight calculation + float mDigitMinEnergy = 0.010; ///< Minimal energy of digits to be used in cluster (GeV) + float mClusteringThreshold = 0.050; ///< Minimal energy of digit to start clustering (GeV) + float mLocalMaximumCut = 0.015; ///< Minimal height of local maximum over neighbours + bool mUnfoldClusters = true; ///< To perform cluster unfolding + float mUnfogingEAccuracy = 1.e-2; ///< Accuracy of energy calculation in unfoding prosedure (GeV) + float mUnfogingXZAccuracy = 1.e-1; ///< Accuracy of position calculation in unfolding procedure (cm) + float mUnfogingChi2Accuracy = 1.e-2; ///< critical chi2/NDF + int mNMaxIterations = 10; ///< Maximal number of iterations in unfolding procedure + float mCoreR = 3.5; ///< Radius to caluclate core energy + float mSortingDelta = 1.; ///< used in sorting clusters O2ParamDef(PHOSSimParams, "PHOSSimParams"); }; diff --git a/Detectors/PHOS/base/include/PHOSBase/RCUTrailer.h b/Detectors/PHOS/base/include/PHOSBase/RCUTrailer.h new file mode 100644 index 0000000000000..3f3ffece96623 --- /dev/null +++ b/Detectors/PHOS/base/include/PHOSBase/RCUTrailer.h @@ -0,0 +1,209 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_RCUTRAILER_H +#define ALICEO2_PHOS_RCUTRAILER_H + +#include <exception> +#include <iosfwd> +#include <string> +#include <cstdint> +#include <gsl/span> +#include "Rtypes.h" + +namespace o2 +{ + +namespace phos +{ + +union ChannelHeader { + uint32_t mDataWord; + struct { + uint32_t mHardwareAddress : 16; ///< Bits 0 - 15: Hardware address + uint32_t mPayloadSize : 10; ///< Bits 16 - 25: Payload size + uint32_t mZero1 : 3; ///< Bits 26 - 28: zeroed + uint32_t mBadChannel : 1; ///< Bit 29: Bad channel status + uint32_t mMark : 1; ///< Bits 30 - 30: Mark header + }; +}; + +union CaloBunchWord { + uint32_t mDataWord; + struct { + uint32_t mWord2 : 10; ///< Bits 0 - 9 : Word 2 + uint32_t mWord1 : 10; ///< Bits 10 - 19 : Word 1 + uint32_t mWord0 : 10; ///< Bits 20 - 29 : Word 0 + uint32_t mZero : 2; ///< Bits 30 - 31 : zeroed + }; +}; + +/// \class RCUTrailer +/// \brief Information stored in the RCU trailer +/// \ingroup PHOSbase +/// +/// The RCU trailer can be found at the end of +/// the payload and contains general information +/// sent by the SRU. +class RCUTrailer +{ + public: + /// \class Error + /// \brief Error handling of the + class Error : public std::exception + { + public: + /// \enum ErrorType_t + /// \brief Error codes for different error types + enum class ErrorType_t { + DECODING_INVALID, ///< Invalid words during decoding + SIZE_INVALID, ///< Invalid trailer size + SAMPLINGFREQ_INVALID, ///< Invalid sampling frequency + L1PHASE_INVALID ///< Invalid L1 phase + }; + + /// \brief Constructor + /// \param errtype Code of the error type + /// \param message corresponding error message + /// + /// Initializing the error with error code and message. + /// To be called when the exception is raised. + Error(ErrorType_t errtype, const char* message) : mErrorType(errtype), mErrorMessage(message) {} + + /// \brief Destructor + ~Error() noexcept override = default; + + /// \brief Access to the error message + /// \return Error message related to the exception type + const char* what() const noexcept override { return mErrorMessage.data(); } + + /// \brief Access to error code + /// \return Error code of the exception type + ErrorType_t getErrorType() const noexcept { return mErrorType; } + + private: + ErrorType_t mErrorType; ///< Type of the error + std::string mErrorMessage; ///< Error Message + }; + + /// \brief Constructor + RCUTrailer() = default; + + RCUTrailer(const gsl::span<const uint32_t> payloadwords); + + /// \brief destructor + ~RCUTrailer() = default; + + /// \brief Reset the RCU trailer + /// + /// Setting all values to 0 + void reset(); + + /// \brief Prints the contents of the RCU trailer data + /// \param stream stream the trailer has to be put on + void printStream(std::ostream& stream) const; + + /// \brief Decode RCU trailer from the 32-bit words in the raw buffer + /// \param buffer Raw buffer from which to read the trailer + /// + /// Read the RCU trailer according to the RCU formware version + /// specified in CDH. + void constructFromRawPayload(const gsl::span<const uint32_t> payloadwords); + + unsigned int getFECErrorsA() const { return mFECERRA; } + unsigned int getFECErrorsB() const { return mFECERRB; } + unsigned short getErrorsG2() const { return mERRREG2; } + unsigned int getErrorsG3() const { return mERRREG3; } + unsigned short getActiveFECsA() const { return mActiveFECsA; } + unsigned short getActiveFECsB() const { return mActiveFECsB; } + unsigned int getAltroCFGReg1() const { return mAltroCFG1; } + unsigned int getAltroCFGReg2() const { return mAltroCFG2; } + int getRCUID() const { return mRCUId; } + unsigned int getTrailerSize() const { return mTrailerSize; } + unsigned int getPayloadSize() const { return mPayloadSize; } + unsigned char getFirmwareVersion() const { return mFirmwareVersion; } + + unsigned short getNumberOfChannelAddressMismatch() const { return (mERRREG3 & 0xFFF); } + unsigned short getNumberOfChannelLengthMismatch() const { return ((mERRREG3 >> 12) & 0x1FFF); } + unsigned char getBaselineCorrection() const { return mAltroCFG1 & 0xF; } + bool getPolarity() const { return (mAltroCFG1 >> 4) & 0x1; } + unsigned char getNumberOfPresamples() const { return (mAltroCFG1 >> 5) & 0x3; } + unsigned char getNumberOfPostsamples() const { return (mAltroCFG1 >> 7) & 0xF; } + bool hasSecondBaselineCorr() const { return (mAltroCFG1 >> 11) & 0x1; } + unsigned char getGlitchFilter() const { return (mAltroCFG1 >> 12) & 0x3; } + unsigned char getNumberOfNonZeroSuppressedPostsamples() const { return (mAltroCFG1 >> 14) & 0x7; } + unsigned char getNumberOfNonZeroSuppressedPresamples() const { return (mAltroCFG1 >> 17) & 0x3; } + bool hasZeroSuppression() const { return (mAltroCFG1 >> 19) & 0x1; } + bool getNumberOfAltroBuffers() const { return (mAltroCFG2 >> 24) & 0x1; } + unsigned char getNumberOfPretriggerSamples() const { return (mAltroCFG2 >> 20) & 0xF; } + unsigned short getNumberOfSamplesPerChannel() const { return (mAltroCFG2 >> 10) & 0x3FF; } + bool isSparseReadout() const { return (mAltroCFG2 >> 9) & 0x1; } + + /// \brief Access to the sampling time + /// \return Sampling time in seconds. + /// \throw Error if the RCU trailer was not properly initializied + double getTimeSample() const; + + /// \brief set time sample + /// \param timesample Time sample (in ns) + void setTimeSample(double timesample); + + /// \brief Access to the L1 phase + /// \return L1 phase w.r.t to the LHC clock + double getL1Phase() const; + + /// \brief Set the L1 phase + /// \param l1phase L1 phase (in ns) + void setL1Phase(double l1phase); + + void setFECErrorsA(unsigned int value) { mFECERRA = value; } + void setFECErrorsB(unsigned int value) { mFECERRB = value; } + void setErrorsG2(unsigned short value) { mERRREG2 = value; } + void setErrorsG3(unsigned int value) { mERRREG3 = value; } + void setActiveFECsA(unsigned short value) { mActiveFECsA = value; } + void setActiveFECsB(unsigned short value) { mActiveFECsB = value; } + void setAltroCFGReg1(unsigned int value) { mAltroCFG1 = value; } + void setAltroCFGReg2(unsigned int value) { mAltroCFG2 = value; } + void setFirmwareVersion(unsigned char version) { mFirmwareVersion = version; } + void setPayloadSize(unsigned int size) { mPayloadSize = size; } + + /// \brief checlks whether the RCU trailer is initialzied + /// \return True if the trailer is initialized, false otherwise + bool isInitialized() const { return mIsInitialized; } + + std::vector<uint32_t> encode() const; + + static RCUTrailer constructFromPayloadWords(const gsl::span<const uint32_t> payloadwords); + + private: + int mRCUId = -1; ///< current RCU identifier + unsigned char mFirmwareVersion = 0; ///< RCU firmware version + unsigned int mTrailerSize = 0; ///< Size of the trailer (in number of 32 bit words) + unsigned int mPayloadSize = 0; ///< Size of the payload (in nunber of 32 bit words) + unsigned int mFECERRA = 0; ///< contains errors related to ALTROBUS transactions + unsigned int mFECERRB = 0; ///< contains errors related to ALTROBUS transactions + unsigned short mERRREG2 = 0; ///< contains errors related to ALTROBUS transactions or trailer of ALTRO channel block + unsigned int mERRREG3 = 0; ///< contains number of altro channels skipped due to an address mismatch + unsigned short mActiveFECsA = 0; ///< bit pattern of active FECs in branch A + unsigned short mActiveFECsB = 0; ///< bit pattern of active FECs in branch B + unsigned int mAltroCFG1 = 0; ///< ALTROCFG1 register + unsigned int mAltroCFG2 = 0; ///< ALTROCFG2 and ALTROIF register + bool mIsInitialized = false; ///< Flag whether RCU trailer is initialized for the given raw event + + ClassDefNV(RCUTrailer, 1); +}; + +std::ostream& operator<<(std::ostream& stream, const RCUTrailer& trailer); + +} // namespace phos + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/PHOS/base/src/Geometry.cxx b/Detectors/PHOS/base/src/Geometry.cxx index fd625a50e1e5c..f82cf32a8ecf8 100644 --- a/Detectors/PHOS/base/src/Geometry.cxx +++ b/Detectors/PHOS/base/src/Geometry.cxx @@ -1,37 +1,52 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "PHOSBase/Geometry.h" +#include "FairLogger.h" +#include "TSystem.h" +#include "TFile.h" using namespace o2::phos; ClassImp(Geometry); +// module numbering: +// start from module 0 (non-existing), 1 (half-module), 2 (bottom),... 4(highest) +// absId: +// start from 1 till 4*64*56. Numbering in each module starts at bottom left and first go in z direction: +// 56 112 3584 +// ... ... ... +// 1 57 ...3529 +// relid[3]: (module number[1...4], iphi[1...64], iz[1...56]) +// +// Then TRU channels go from 1 to 112 per branch, 2 branches per ddl +// absId = getTotalNCells() + TRUabsId ; +// relId for TRU +// relid: [DDL id=0..13] [x in 2x2 system: 1..8] [z in 2x2 system 1..28] TODO: verify with real TRU data!!! + // these initialisations are needed for a singleton Geometry* Geometry::sGeom = nullptr; -Geometry::Geometry(const std::string_view name) : mGeoName(name) {} - -// static Geometry* Geometry::GetInstance(const std::string_view name) -// { -// if(sGeom){ -// if(sGeom->GetName()==name){ -// return sGeom; -// } -// else{ -// delete sGeom ; -// } -// } -// sGeom = new Geometry(name) ; -// return sGeom; -// } +Geometry::Geometry(const std::string_view name) : mGeoName(name) +{ + std::string p = gSystem->Getenv("O2_ROOT"); + p += "/share/Detectors/PHOS/files/alignment.root"; + TFile fin(p.data()); + + //try reading rotation mathices + for (int m = 1; m < 5; m++) { + mPHOS[m] = *static_cast<TGeoHMatrix*>(fin.Get(Form("Module%d", m))); + } + fin.Close(); +} short Geometry::relToAbsId(char moduleNumber, int strip, int cell) { @@ -57,16 +72,48 @@ bool Geometry::absToRelNumbering(short absId, char* relid) // relid[2] = Column number inside a PHOS module (Phi coordinate) const short nZ = 56; // nStripZ * nCellsZInStrip const short nPhi = 64; // nStripZ * nCellsZInStrip - - short phosmodulenumber = (absId - 1) / (nZ * nPhi); + absId--; + short phosmodulenumber = absId / (nZ * nPhi); relid[0] = phosmodulenumber + 1; absId -= phosmodulenumber * nPhi * nZ; - relid[1] = 1 + (absId - 1) / nZ; - relid[2] = absId - (relid[1] - 1) * nZ; + relid[1] = 1 + absId / nZ; + relid[2] = absId - (relid[1] - 1) * nZ + 1; return true; } +bool Geometry::truAbsToRelNumbering(short truId, char* relid) +{ + //convert trigger cell Id to + truId--; + relid[0] = truId / 224; //2*112 channels // DDL id + truId = truId % 224; + relid[1] = 1 + truId % 8; // x index in TRU internal 2x2 coordinate system + relid[2] = 1 + truId / 8; // z index in TRU internal 2x2 coordinate system + return true; +} +short Geometry::truRelToAbsNumbering(const char* relId) +{ + return relId[0] * 224 + // the offset of PHOS modules + relId[1] - 1 + // the offset along phi + (relId[2] - 1) * 8; // the offset along z +} +bool Geometry::truRelId2RelId(const char* truRelId, char* relId) +{ + relId[0] = 1 + (truRelId[0] + 2) / 4; + relId[1] = ((truRelId[0] + 2) % 4) * 16 + truRelId[1] * 2 - 1; + relId[2] = truRelId[2] * 2 - 1; + return true; +} +short Geometry::relPosToTruId(char mod, float x, float z, short& ddl) +{ + //tranform local cluster coordinates to truId + char relid[3] = {mod, static_cast<char>(ceil(x / CELLSTEP + 32.5)), static_cast<char>(ceil(z / CELLSTEP + 28.5))}; + ddl = (mod - 1) * 4 + relid[1] / 16 - 2; + char truid[3] = {static_cast<char>(ddl), static_cast<char>(1 + ((relid[1] - 1) % 16) / 2), static_cast<char>(1 + (relid[2] - 1) / 2)}; + return truRelToAbsNumbering(truid); +} + char Geometry::absIdToModule(short absId) { const short nZ = 56; @@ -117,13 +164,11 @@ int Geometry::areNeighbours(short absId1, short absId2) void Geometry::absIdToRelPosInModule(short absId, float& x, float& z) { - const float cellStep = 2.25; - char relid[3]; absToRelNumbering(absId, relid); - x = (relid[1] - 28 - 0.5) * cellStep; - z = (relid[2] - 32 - 0.5) * cellStep; + x = (relid[1] - 32 - 0.5) * CELLSTEP; + z = (relid[2] - 28 - 0.5) * CELLSTEP; } bool Geometry::relToAbsNumbering(const char* relId, short& absId) { @@ -137,3 +182,65 @@ bool Geometry::relToAbsNumbering(const char* relId, short& absId) return true; } +//local position to absId +void Geometry::relPosToAbsId(char module, float x, float z, short& absId) +{ + char relid[3] = {module, static_cast<char>(ceil(x / CELLSTEP + 32.5)), static_cast<char>(ceil(z / CELLSTEP + 28.5))}; + relToAbsNumbering(relid, absId); +} +void Geometry::relPosToRelId(short module, float x, float z, char* relId) +{ + relId[0] = module; + relId[1] = static_cast<char>(ceil(x / CELLSTEP + 32.5)); + relId[2] = static_cast<char>(ceil(z / CELLSTEP + 28.5)); +} + +// convert local position in module to global position in ALICE +void Geometry::local2Global(char module, float x, float z, TVector3& globaPos) const +{ + // constexpr float shiftY=-10.76; Run2 + constexpr float shiftY = -1.26; //Depth-optimized + Double_t posL[3] = {x, z, shiftY}; + Double_t posG[3]; + mPHOS[module].LocalToMaster(posL, posG); + globaPos.SetXYZ(posG[0], posG[1], posG[2]); +} + +bool Geometry::impactOnPHOS(const TVector3& vtx, const TVector3& p, + short& module, float& z, float& x) const +{ + // calculates the impact coordinates on PHOS of a neutral particle + // emitted in the vertex vtx with 3-momentum p + constexpr float shiftY = -1.26; //Depth-optimized + constexpr float moduleXhalfSize = 72.16; // 18.04 / 2 * 8 + constexpr float moduleZhalfSize = 64.14; // 4.51 / 2 * 28 + + for (short mod = 1; mod < 5; mod++) { + //create vector from (0,0,0) to center of crystal surface of imod module + double tmp[3] = {0., 0., shiftY}; + double posG[3] = {0., 0., 0.}; + mPHOS[mod].LocalToMaster(tmp, posG); + TVector3 n(posG[0], posG[1], posG[2]); + double direction = n.Dot(p); + if (direction <= 0.) { + continue; //momentum directed FROM module + } + double fr = (n.Mag2() - n.Dot(vtx)) / direction; + //Calculate direction in module plane + n -= vtx + fr * p; + n *= -1.; + if (TMath::Abs(n.Z()) < moduleZhalfSize && n.Pt() < moduleXhalfSize) { + module = mod; + z = n.Z(); + x = TMath::Sign(n.Pt(), n.X()); + //no need to return to local system since we calcilated distance from module center + //and tilts can not be significant. + return true; + } + } + //Not in acceptance + x = 0; + z = 0; + module = 0; + return false; +} diff --git a/Detectors/PHOS/base/src/Hit.cxx b/Detectors/PHOS/base/src/Hit.cxx index 9c767ab3db959..04cf613293c51 100644 --- a/Detectors/PHOS/base/src/Hit.cxx +++ b/Detectors/PHOS/base/src/Hit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/base/src/Mapping.cxx b/Detectors/PHOS/base/src/Mapping.cxx new file mode 100644 index 0000000000000..4fe7f7b9648d1 --- /dev/null +++ b/Detectors/PHOS/base/src/Mapping.cxx @@ -0,0 +1,217 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Mapping.cxx +/// \author Dmitri Peresunko + +#include <fstream> +#include "TSystem.h" +#include "FairLogger.h" +#include "PHOSBase/Mapping.h" +#include "PHOSBase/Geometry.h" + +using namespace o2::phos; +Mapping* Mapping::sMapping = nullptr; +//_______________________________________________________ +Mapping::Mapping(std::basic_string_view<char> path) : mPath(path), + mInitialized(false) +{ +} +//_______________________________________________________ +Mapping* Mapping::Instance() +{ + if (sMapping) { + return sMapping; + } else { + sMapping = new Mapping(); + sMapping->setMapping(); + return sMapping; + } +} +//_______________________________________________________ +Mapping* Mapping::Instance(std::basic_string_view<char> path) +{ + if (sMapping) { + if (sMapping->mPath == path) { + return sMapping; + } else { + delete sMapping; + } + } + sMapping = new Mapping(path); + sMapping->setMapping(); + return sMapping; +} +//_______________________________________________________ +Mapping::ErrorStatus Mapping::hwToAbsId(short ddl, short hwAddr, short& absId, CaloFlag& caloFlag) const +{ + + if (!mInitialized) { + LOG(ERROR) << "Mapping not initialized"; + return kNotInitialized; + } + + if (ddl < 0 || ddl > 14) { + return kWrongDDL; + } + if ((hwAddr >= 112 && hwAddr < 128) || (hwAddr >= 2159 && hwAddr < 2176)) { //TRU flags + caloFlag = kTRU; + absId = -1; + return kOK; + } + if (hwAddr < 0 || hwAddr >= NMaxHWAddress) { + return kWrongHWAddress; + } + + //transform + absId = mAbsId[ddl][hwAddr]; + caloFlag = mCaloFlag[ddl][hwAddr]; + + if (absId > NCHANNELS || absId <= 1792) { + absId = 0; + return kWrongHWAddress; + } + return kOK; +} +//_______________________________________________________ +Mapping::ErrorStatus Mapping::absIdTohw(short absId, short caloFlag, short& ddl, short& hwAddr) const +{ + + if (caloFlag < 0 || caloFlag > 2) { + ddl = 0; + hwAddr = 0; + return kWrongCaloFlag; + } + if (caloFlag < 2) { + if (absId <= 1792 || absId > NCHANNELS) { + ddl = 0; + hwAddr = 0; + return kWrongAbsId; + } + } else { + if (absId < 0 || absId > NTRUReadoutChannels) { + ddl = 0; + hwAddr = 0; + return kWrongAbsId; + } + } + + if (!mInitialized) { + LOG(ERROR) << "Mapping not initialized"; + return kNotInitialized; + } + + ddl = mAbsToHW[absId - 1][caloFlag][0]; + hwAddr = mAbsToHW[absId - 1][caloFlag][1]; + return kOK; +} +//_______________________________________________________ +Mapping::ErrorStatus Mapping::setMapping() +{ + //Read mapping from data files a-la Run2 + + std::string p; + if (mPath.empty()) { //use default path + p = gSystem->Getenv("O2_ROOT"); + p += "/share/Detectors/PHOS/files"; + } else { + p = mPath.data(); + } + + for (short m = 0; m < 4; m++) { //modules + for (short i = 0; i < 4; i++) { //RCU + if (m == 0 && (i < 2)) { + continue; //half of module: only RCU 2,3 + } + + short numberOfChannels = 0; + short maxHWAddress = 0; + std::string fname = fmt::format("{:s}/Mod{:d}RCU{:d}.data", p, m, i); + std::ifstream fIn(fname); + if (!fIn.is_open()) { + LOG(FATAL) << "Missing mapping file " << p << "/Mod" << m << "RCU" << i << ".data"; + return kNotInitialized; + } + if (!(fIn >> numberOfChannels)) { + LOG(FATAL) << "Syntax of mapping file " << p << "/Mod" << m << "RCU" << i << ".data is wrong: no numberOfChannels"; + return kNotInitialized; + } + if (numberOfChannels != NHWPERDDL) { + LOG(FATAL) << "Unexpected number of channels: " << numberOfChannels << " expecting " << NHWPERDDL << " file " << p << "/Mod" << m << "RCU" << i << ".data is wrong: no numberOfChannels"; + return kNotInitialized; + } + if (!(fIn >> maxHWAddress)) { + LOG(FATAL) << "Syntax of mapping file " << p << "/Mod" << m << "RCU" << i << ".data is wrong: no maxHWAddress"; + return kNotInitialized; + } + if (maxHWAddress > NMaxHWAddress) { + LOG(FATAL) << "Maximal HW address in file " << maxHWAddress << "larger than array size " << NMaxHWAddress << "for /Mod" << m << "RCU" << i << ".data is wrong: no maxHWAddress"; + return kNotInitialized; + } + for (short ich = 0; ich < numberOfChannels; ich++) { // 1792 = 2*896 channels connected to each RCU + int hwAddress; + if (!(fIn >> hwAddress)) { + LOG(FATAL) << "Syntax of mapping file " << p << "/Mod" << m << "RCU" << i << ".data is wrong: no HWadd for ch " << ich; + return kNotInitialized; + } + if (hwAddress > maxHWAddress) { + LOG(FATAL) << "Hardware (ALTRO) adress (" << hwAddress << ") outside the range (0 -> " << maxHWAddress << ") !"; + return kNotInitialized; + } + int row, col, caloFlag; + if (!(fIn >> row >> col >> caloFlag)) { + LOG(FATAL) << "Syntax of mapping file " << p << "/Mod" << m << "RCU" << i << ".data is wrong: no (raw col caloFlag)"; + return kNotInitialized; + } + + if (caloFlag < 0 || caloFlag > 2) { + LOG(FATAL) << "Wrong CaloFlag value found (" << caloFlag << "). Should be 0, 1, 2 !"; + return kNotInitialized; + } + + //convert ddl, col,raw caloFlag to AbsId + // Converts the absolute numbering into the following array + // relid[0] = PHOS Module number + // relid[1] = Row number inside a PHOS module (Phi coordinate) + // relid[2] = Column number inside a PHOS module (Z coordinate) + short ddl = 4 * m + i - 2; + if (ddl < 0 || ddl >= NDDL) { + LOG(FATAL) << "Wrong ddl address found (" << ddl << "). Module= " << m << " RCU =" << i; + return kNotInitialized; + } + + short absId; + if (caloFlag < 2) { //readout channels + char relid[3] = {static_cast<char>(m + 1), static_cast<char>(row + 1), static_cast<char>(col + 1)}; + Geometry::relToAbsNumbering(relid, absId); + } else { //TRU channels + if (isTRUReadoutchannel(hwAddress)) { + if (hwAddress < 2048) { //branch 28<=z<56 + absId = ddl * 2 * NTRUBranchReadoutChannels + hwAddress; + } else { //branch 0<=z<28 + absId = (ddl * 2 + 1) * NTRUBranchReadoutChannels + hwAddress - 2048; + } + } else { //TRU flag channels, no absId + continue; + } + } + + mAbsId[ddl][hwAddress] = absId; + mCaloFlag[ddl][hwAddress] = (CaloFlag)caloFlag; + mAbsToHW[absId - 1][caloFlag][0] = ddl; + mAbsToHW[absId - 1][caloFlag][1] = hwAddress; + } + fIn.close(); + } //RCU + } // module + mInitialized = true; + return kOK; +} diff --git a/Detectors/PHOS/base/src/PHOSBaseLinkDef.h b/Detectors/PHOS/base/src/PHOSBaseLinkDef.h index 3bd0b052130d1..742ae82379a74 100644 --- a/Detectors/PHOS/base/src/PHOSBaseLinkDef.h +++ b/Detectors/PHOS/base/src/PHOSBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/base/src/PHOSSimParams.cxx b/Detectors/PHOS/base/src/PHOSSimParams.cxx index 4b2817a9d12ed..edf4c8fdca869 100644 --- a/Detectors/PHOS/base/src/PHOSSimParams.cxx +++ b/Detectors/PHOS/base/src/PHOSSimParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/base/src/RCUTrailer.cxx b/Detectors/PHOS/base/src/RCUTrailer.cxx new file mode 100644 index 0000000000000..818930a46b832 --- /dev/null +++ b/Detectors/PHOS/base/src/RCUTrailer.cxx @@ -0,0 +1,247 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <cfloat> +#include <cmath> +#include <iostream> +#include <fmt/format.h> +#include "FairLogger.h" +#include "CommonConstants/LHCConstants.h" +#include "PHOSBase/RCUTrailer.h" + +using namespace o2::phos; + +RCUTrailer::RCUTrailer(const gsl::span<const uint32_t> payloadwords) +{ + constructFromRawPayload(payloadwords); +} + +void RCUTrailer::reset() +{ + mRCUId = -1; + mFirmwareVersion = 0; + mTrailerSize = 0; + mPayloadSize = 0; + mFECERRA = 0; + mFECERRB = 0; + mERRREG2 = 0; + mERRREG3 = 0; + mActiveFECsA = 0; + mActiveFECsB = 0; + mAltroCFG1 = 0; + mAltroCFG2 = 0; + mIsInitialized = false; +} + +void RCUTrailer::constructFromRawPayload(const gsl::span<const uint32_t> payloadwords) +{ + reset(); + int index = payloadwords.size(); + auto word = payloadwords[--index]; + if ((word >> 30) != 3) { + throw Error(Error::ErrorType_t::DECODING_INVALID, "Last RCU trailer word not found!"); + } + mFirmwareVersion = (word >> 16) & 0xFF; + + mRCUId = (int)((word >> 7) & 0x1FF); + int trailerSize = (word & 0x7F); + + if (trailerSize < 2) { + throw Error(Error::ErrorType_t::SIZE_INVALID, fmt::format("Invalid trailer size found (%d bytes) !", trailerSize * 4).data()); + } + mTrailerSize = trailerSize; + + trailerSize -= 2; // Cut first and last trailer words as they are handled separately + for (; trailerSize > 0; trailerSize--) { + word = payloadwords[--index]; + if ((word >> 30) != 2) { + LOG(ERROR) << "Missing RCU trailer identifier pattern!"; + continue; + } + int parCode = (word >> 26) & 0xF; + int parData = word & 0x3FFFFFF; + switch (parCode) { + case 1: + // ERR_REG1 + mFECERRA = ((parData >> 13) & 0x1FFF) << 7; + mFECERRB = ((parData & 0x1FFF)) << 7; + break; + case 2: + // ERR_REG2 + mERRREG2 = parData & 0x1FF; + break; + case 3: + // ERR_REG3 + mERRREG3 = parData & 0x1FFFFFF; + break; + case 4: + // FEC_RO_A + mActiveFECsA = parData & 0xFFFF; + break; + case 5: + // FEC_RO_B + mActiveFECsB = parData & 0xFFFF; + break; + case 6: + // RDO_CFG1 + mAltroCFG1 = parData & 0xFFFFF; + break; + case 7: + // RDO_CFG2 + mAltroCFG2 = parData & 0x1FFFFFF; + break; + default: + LOG(ERROR) << "Undefined parameter code " << parCode << ", ignore it !"; + break; + } + } + mPayloadSize = payloadwords[--index] & 0x3FFFFFF; + mIsInitialized = true; +} + +double RCUTrailer::getTimeSample() const +{ + unsigned char fq = (mAltroCFG2 >> 5) & 0xF; + double tSample; + switch (fq) { + case 0: + // 20 MHz + tSample = 2.0; + break; + case 1: + // 10 Mhz + tSample = 4.0; + break; + case 2: + // 5 MHz + tSample = 8.; + break; + default: + throw Error(Error::ErrorType_t::SAMPLINGFREQ_INVALID, fmt::format("Invalid sampling frequency value %d !", int(fq)).data()); + } + + return tSample * o2::constants::lhc::LHCBunchSpacingNS * 1.e-9; +} + +void RCUTrailer::setTimeSample(double timesample) +{ + int fq = 0; + if (std::abs(timesample - 50) < DBL_EPSILON) { + fq = 0; + } else if (std::abs(timesample - 100) < DBL_EPSILON) { + fq = 1; + } else if (std::abs(timesample - 200) < DBL_EPSILON) { + fq = 2; + } else { + throw Error(Error::ErrorType_t::SAMPLINGFREQ_INVALID, fmt::format("invalid time sample: %f", timesample).data()); + } + mAltroCFG2 = (mAltroCFG2 & 0x1F) | fq << 5; +} + +double RCUTrailer::getL1Phase() const +{ + double tSample = getTimeSample(), + phase = ((double)(mAltroCFG2 & 0x1F)) * o2::constants::lhc::LHCBunchSpacingNS * 1.e-9; + if (phase >= tSample) { + throw Error(Error::ErrorType_t::L1PHASE_INVALID, fmt::format("Invalid L1 trigger phase (%e s (phase) >= %e s (sampling time)) !", phase, tSample).data()); + } + return phase; +} + +void RCUTrailer::setL1Phase(double l1phase) +{ + int phase = l1phase / 25.; + mAltroCFG2 = (mAltroCFG2 & 0x1E0) | phase; +} + +std::vector<uint32_t> RCUTrailer::encode() const +{ + std::vector<uint32_t> encoded; + encoded.emplace_back(mPayloadSize | 2 << 30); + encoded.emplace_back(mAltroCFG2 | 7 << 26 | 2 << 30); + encoded.emplace_back(mAltroCFG1 | 6 << 26 | 2 << 30); + encoded.emplace_back(mActiveFECsB | 5 << 26 | 2 << 30); + encoded.emplace_back(mActiveFECsA | 4 << 26 | 2 << 30); + encoded.emplace_back(mERRREG3 | 3 << 26 | 2 << 30); + encoded.emplace_back(mERRREG2 | 2 << 26 | 2 << 30); + encoded.emplace_back(mFECERRB >> 7 | (mFECERRA >> 7) << 13 | 1 << 26 | 2 << 30); + + uint32_t lasttrailerword = 3 << 30 | mFirmwareVersion << 16 | mRCUId << 7 | (encoded.size() + 1); + encoded.emplace_back(lasttrailerword); + + return encoded; +} + +void RCUTrailer::printStream(std::ostream& stream) const +{ + std::vector<std::string> errors; + double timesample = -1., l1phase = -1.; + try { + timesample = getTimeSample(); + } catch (Error& e) { + errors.push_back(e.what()); + } + try { + l1phase = getL1Phase(); + } catch (Error& e) { + errors.push_back(e.what()); + } + + stream << "RCU trailer (Format version 2):\n" + << "==================================================\n" + << "RCU ID: " << mRCUId << "\n" + << "Firmware version: " << int(mFirmwareVersion) << "\n" + << "Trailer size: " << mTrailerSize << "\n" + << "Payload size: " << mPayloadSize << "\n" + << "FECERRA: 0x" << std::hex << mFECERRA << "\n" + << "FECERRB: 0x" << std::hex << mFECERRB << "\n" + << "ERRREG2: 0x" << std::hex << mERRREG2 << "\n" + << "#channels skipped due to address mismatch: " << std::dec << getNumberOfChannelAddressMismatch() << "\n" + << "#channels skipped due to bad block length: " << std::dec << getNumberOfChannelLengthMismatch() << "\n" + << "Active FECs (branch A): 0x" << std::hex << mActiveFECsA << "\n" + << "Active FECs (branch B): 0x" << std::hex << mActiveFECsB << "\n" + << "Baseline corr: 0x" << std::hex << int(getBaselineCorrection()) << "\n" + << "Number of presamples: " << std::dec << int(getNumberOfPresamples()) << "\n" + << "Number of postsamples: " << std::dec << int(getNumberOfPostsamples()) << "\n" + << "Second baseline corr: " << (hasSecondBaselineCorr() ? "yes" : "no") << "\n" + << "GlitchFilter: " << std::dec << int(getGlitchFilter()) << "\n" + << "Number of non-ZS postsamples: " << std::dec << int(getNumberOfNonZeroSuppressedPostsamples()) << "\n" + << "Number of non-ZS presamples: " << std::dec << int(getNumberOfNonZeroSuppressedPresamples()) << "\n" + << "Number of ALTRO buffers: " << std::dec << getNumberOfAltroBuffers() << "\n" + << "Number of pretrigger samples: " << std::dec << int(getNumberOfPretriggerSamples()) << "\n" + << "Number of samples per channel: " << std::dec << getNumberOfSamplesPerChannel() << "\n" + << "Sparse readout: " << (isSparseReadout() ? "yes" : "no") << "\n" + << "AltroCFG1: 0x" << std::hex << mAltroCFG1 << "\n" + << "AltroCFG2: 0x" << std::hex << mAltroCFG2 << "\n" + << "Sampling time: " << std::scientific << timesample << " s\n" + << "L1 Phase: " << std::scientific << l1phase << " s\n" + << std::dec << std::fixed; + if (errors.size()) { + stream << "Errors: \n" + << "-------------------------------------------------\n"; + for (const auto& e : errors) { + stream << e << "\n"; + } + } + stream << "==================================================\n"; +} + +RCUTrailer RCUTrailer::constructFromPayloadWords(const gsl::span<const uint32_t> payloadwords) +{ + RCUTrailer result; + result.constructFromRawPayload(payloadwords); + return result; +} + +std::ostream& o2::phos::operator<<(std::ostream& stream, const o2::phos::RCUTrailer& trailer) +{ + trailer.printStream(stream); + return stream; +} diff --git a/Detectors/PHOS/calib/CMakeLists.txt b/Detectors/PHOS/calib/CMakeLists.txt index 0067579a4de92..bb65608093e82 100644 --- a/Detectors/PHOS/calib/CMakeLists.txt +++ b/Detectors/PHOS/calib/CMakeLists.txt @@ -1,33 +1,52 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library(PHOSCalib - SOURCES src/BadChannelMap.cxx - src/CalibParams.cxx - src/CalibDB.cxx - PUBLIC_LINK_LIBRARIES O2::CCDB O2::PHOSBase) +o2_add_library(PHOSCalibWorkflow + SOURCES src/PHOSPedestalCalibDevice.cxx + src/PHOSHGLGRatioCalibDevice.cxx + src/PHOSEnergyCalibrator.cxx + src/PHOSEnergyCalibDevice.cxx + src/TurnOnHistos.cxx + src/PHOSTurnonCalibDevice.cxx + src/PHOSTurnonCalibrator.cxx + src/PHOSRunbyrunCalibrator.cxx + src/PHOSRunbyrunCalibDevice.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsPHOS + O2::DetectorsRaw + O2::PHOSReconstruction + O2::DetectorsCalibration) +o2_add_header_only_library(PHOSCalib) -o2_target_root_dictionary(PHOSCalib - HEADERS include/PHOSCalib/BadChannelMap.h - include/PHOSCalib/CalibParams.h - include/PHOSCalib/CalibDB.h - LINKDEF src/PHOSCalibLinkDef.h) +o2_target_root_dictionary(PHOSCalibWorkflow + HEADERS include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h + include/PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h + include/PHOSCalibWorkflow/PHOSTurnonCalibrator.h + include/PHOSCalibWorkflow/RingBuffer.h + include/PHOSCalibWorkflow/ETCalibHistos.h + include/PHOSCalibWorkflow/PHOSEnergyCalibrator.h + include/PHOSCalibWorkflow/PHOSEnergyCalibDevice.h + include/PHOSCalibWorkflow/TurnOnHistos.h + include/PHOSCalibWorkflow/PHOSTurnonCalibrator.h + include/PHOSCalibWorkflow/PHOSTurnonCalibDevice.h + include/PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h + include/PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h + LINKDEF src/PHOSCalibWorkflowLinkDef.h) -if(BUILD_TESTING) - o2_add_test_root_macro(macros/PostBadMapCCDB.C - PUBLIC_LINK_LIBRARIES O2::CCDB O2::PHOSBase O2::PHOSCalib - LABELS PHOS COMPILE_ONLY) +o2_add_executable(calib-workflow + COMPONENT_NAME phos + SOURCES src/phos-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsPHOS + O2::PHOSCalibWorkflow + O2::DetectorsCalibration) - o2_add_test_root_macro( macros/PostCalibCCDB.C - PUBLIC_LINK_LIBRARIES O2::CCDB O2::PHOSBase O2::PHOSCalib - LABELS PHOS COMPILE_ONLY) - -endif() diff --git a/Detectors/PHOS/calib/README.md b/Detectors/PHOS/calib/README.md new file mode 100644 index 0000000000000..54d058213dcd3 --- /dev/null +++ b/Detectors/PHOS/calib/README.md @@ -0,0 +1,68 @@ +<!-- doxy +\page refDetectorsPHOScalibration PHOS Calibration +/doxy --> + +# PHOS calibration objects (see DataDormats/Detectors/PHOS/) + +The following objects are used for PHOS calibration +## Pedestals +Calculated during dedicate runs with and used for FEE configuration in later physics runs + +## CalibParams +Include channel-by channel gain parameters, High Gain/Low Gain ratio and time offsets for High Gain and Low Gain channels separately. + +## TriggerMap +Object contains trigger bad map and 14 parameterizations of L0 turn-on curves (one for each DDL) + +## Runbyrun +Time-dependent energy scale corrections, one number per module (plus uncertainty of the fitting procedure) + +## BadChannelsMap +Bad channels map used in reconstruction and simulation. Caclulated by combining inputs from pedestal, noisy, LED and physics runs and DCS configuration + +# Calibration procedures + +## Pedestal calculation +Dedicated pedestal runs (trigger rate ~10 Hz) and length ~100 s to collect ~1000 events. Analyzed with class PHOSPedestalCalibDevice which uses as input vector of o2::phos::Cell, produced with raw to cell converted with option --pedestal. In this conficuration Cell::Energy contains mean and Cell::Time contains RMS of pedestal. +``` cpp +o2-raw-file-reader-workflow --input-conf PHSraw.cfg | +o2-phos-reco-workflow --input-type raw --output-type cells --disable-root-output --pedestal on | +o2-phos-calib-workflow --pedestals +``` + +# High Gain/Low Gain ratio calculation +Dedicated LED runs (trigger rate ~1000 Hz) and length ~100 s to collect 10^5 events. Analyzed with class PHOSHGLGRatioCalibDevice which uses output of standard reconstruction but wich switched off merging of HG and LG channels: +``` cpp +o2-raw-file-reader-workflow --input-conf PHSraw.cfg | +o2-phos-reco-workflow --input-type raw --output-type cells --disable-root-output --keepHGLG on | +o2-phos-calib-workflow --hglgratio +``` +## Turn-on curve and trigger bad map calculation +Run over physics run, selecting events not marked as PHOS L0 trigger. Performed with classes PHOSTurnonCalibDevice and PHOSTurnonCalibrator. Stores transient object to CCDB if sufficient statistics not collected yet or calculates TriggerMap objects and stores it at CCDB. Uses list of Cells and FullClusters as input. Running on MC digits +``` cpp +o2-phos-reco-workflow --input-type digits --output-type cells --disable-root-output | +o2-phos-reco-workflow --input-type cells --output-type clusters --fullclu-output --disable-root-output --disable-root-input | +o2-phos-calib-workflow --turnon +``` + +## Run-by-run correction +Calculated pi0 peak position in each module in current run (or equivavlt period). Use list of FullClusters as input and produce 8 numbers: peak position and fit uncertainties for each module. Run as +``` cpp +o2-phos-reco-workflow --input-type digits --output-type cells --disable-root-output | +o2-phos-reco-workflow --input-type cells --output-type clusters --fullclu-output --disable-root-output --disable-root-input | +o2-phos-calib-workflow --runbyrun +``` + +## Energy and time calibration +Relative energy scale per channel and time offsets for High Gain and Low Gain channels is calculated with iterative procedure. At the first step physics (better PHOS triggered) data are scanned and list of digits contributed to PHOS clusters are stored in local root files on EPN. digits are packed as std::vector<uint32_t> and simutaneously a list of inv. mass and time histograms are filled. Then new calibration coefficients are calculated from collected histograms and list of clusters re-scanned with new calibration. Few (~5) iterations is necessary to reach final accuracy. First scan is ran as +``` cpp +o2-phos-reco-workflow --input-type digits --output-type cells --disable-root-output | +o2-phos-reco-workflow --input-type cells --output-type clusters --fullclu-output --disable-root-output --disable-root-input | +o2-phos-calib-workflow --not-use-ccdb --energy +``` + +## Bad map calculation + + +<!-- doxy +/doxy --> diff --git a/Detectors/PHOS/calib/include/PHOSCalib/BadChannelMap.h b/Detectors/PHOS/calib/include/PHOSCalib/BadChannelMap.h index da4050098e930..7019e2686d598 100644 --- a/Detectors/PHOS/calib/include/PHOSCalib/BadChannelMap.h +++ b/Detectors/PHOS/calib/include/PHOSCalib/BadChannelMap.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,6 @@ #include <iosfwd> #include <bitset> #include <Rtypes.h> -#include <CCDB/TObjectWrapper.h> // Needed to trigger dictionary build class TH2; @@ -85,28 +85,19 @@ class BadChannelMap /// \brief Add bad cell to the container /// \param channelID Absolute ID of the bad channel /// \param mask type of the bad channel - /// - /// Adding new bad channel to the container. In case a cell - /// with the same ID is already present in the container, - /// the mask status is updated. Otherwise it is added. - /// - /// Only bad or warm cells are added to the container. In case - /// the mask type is GOOD_CELL, the entry is removed from the - /// container if present before, otherwise the cell is ignored. - void addBadChannel(short channelID) { mBadCells.set(channelID); } //set bit to true + void addBadChannel(short channelID) { mBadCells.set(channelID - OFFSET); } //set bit to true /// \brief Mark channel as good /// \param channelID Absolute ID of the channel - /// /// Setting channel as good. - void setChannelGood(short channelID) { mBadCells.set(channelID, false); } + void setChannelGood(short channelID) { mBadCells.set(channelID - OFFSET, false); } /// \brief Get the status of a certain cell /// \param channelID channel for which to obtain the channel status /// \return true if good channel /// /// Provide the mask status of a cell. - bool isChannelGood(short channelID) const { return !mBadCells.test(channelID); } + bool isChannelGood(short channelID) const { return !mBadCells.test(channelID - OFFSET); } /// \brief Convert map into 2D histogram representation /// \param mod Module number @@ -132,6 +123,7 @@ class BadChannelMap private: static constexpr short NCHANNELS = 14337; ///< Number of channels starting from 1 (4*64*56+1 + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*0.5+1 std::bitset<NCHANNELS> mBadCells; ///< Container for bad cells, 1 means bad sell ClassDefNV(BadChannelMap, 1); diff --git a/Detectors/PHOS/calib/include/PHOSCalib/CalibDB.h b/Detectors/PHOS/calib/include/PHOSCalib/CalibDB.h deleted file mode 100644 index cd1c2e5c6e834..0000000000000 --- a/Detectors/PHOS/calib/include/PHOSCalib/CalibDB.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include <exception> -#include <map> -#include <string> -#include "Rtypes.h" -#include "RStringView.h" -#include "CCDB/CcdbApi.h" - -namespace o2 -{ - -namespace phos -{ - -class BadChannelMap; -class CalibParams; - -/// \class CalibDB -/// \brief Interface to calibration data from CCDB for PHOS -/// \author Dmitri Peresunko, adopted from EMCAL (Markus Fasel) -/// \since Aug 1, 2019 -/// -/// Interface handling simple access to CCDB content for -/// PHOS objects. The interface allows storing and -/// reading of the common PHOS calibration objects -/// - Bad Channel Map -/// - Gain, HG/LG ratio, Time calibration -/// - Run-by-run gaincorrections -/// Users only need to specify the CCDB server, the timestamp and -/// (optionally) additional meta data. Handling of the CCDB path -/// and type conversions is done internally - users deal directly -/// with the low level containers. -/// -/// Attention: The read process of the CCDB objects might fail, -/// either because the query of the CCDB was not successfull -/// (wrong server / path / timestamp) or the object type is different -/// and internal conversion failed. In both cases dedicated exceptions -/// are thrown: -/// - ObjectNotFoundException in case of failure of the query -/// - TypeMismatchException in case object type doesn't match the expected type -/// Users must handle the exceptions. -class CalibDB -{ - public: - /// \class ObjectNotFoundException - /// \brief Handling errors due to objects not found in the CCDB - /// - /// Objects cannot be found due to - /// - Not existing on server - /// - Incorrect path - /// - Wrong timestamp - /// - Meta data not set - class ObjectNotFoundException final : public std::exception - { - public: - /// \brief Constructor with query parameters - /// \param server URL of the CCDB server - /// \param path CCDB path - /// \param metadata Meta data used in the query - /// \param timestamp Timestamp used in the query - ObjectNotFoundException(const std::string_view server, const std::string_view path, const std::map<std::string, std::string>& metadata, ULong_t timestamp) : std::exception(), - mServ(server), - mPath(path), - mMetaDat(metadata), - mTimestamp(timestamp) - { - mMessage = "Not possible to access entry \"" + mPath + "\" on " + mServ + " for timestamp " + std::to_string(mTimestamp); - } - - /// \brief destructor - ~ObjectNotFoundException() noexcept final = default; - - /// \brief Creating error message with relevant query paramters - /// \return error message - const char* what() const noexcept final - { - return mMessage.data(); - } - - /// \brief Accessor to meta data - /// \return meta data - const std::map<std::string, std::string> getMetaData() const { return mMetaDat; } - - /// \Accessor to URL of the CCDB server - /// \return URL of the CCDB server - const std::string& getServer() const { return mServ; } - - /// \Accessor to the CCDB path in the query - /// return CCDB path in the query - const std::string& getPath() const { return mPath; } - - /// \brief Accessor to timestamp used in the query - /// \return Timestamp used in query - ULong_t getTimestamp() const { return mTimestamp; } - - private: - const std::string mServ; ///< URL of the CCDB server - const std::string mPath; ///< Query path - std::string mMessage; ///< Resulting error message - const std::map<std::string, std::string> mMetaDat; ///< <Meta data - ULong_t mTimestamp; ///< Timestamp - }; - - /// \class TypeMismatchException - /// \brief Class handling errors of wrong type of a query result - /// - /// The exepction is thrown in case the query for an object under - /// a certain path and with a certain timestamp was valid, the object - /// however has a different type than the expected one (something was - /// screwed up when writing to the CCDB) - class TypeMismatchException final : public std::exception - { - public: - /// \brief Constructor - /// \param obtained Type of the object obtained in the query - /// \param expected Expected type of the object - TypeMismatchException(const std::string_view obtained, const std::string_view expected) : std::exception(), - mTypeObtained(obtained), - mTypeExpected(expected), - mMessage() - { - mMessage = "Incorrect type, expected " + mTypeExpected + ", obtained " + mTypeObtained; - } - - /// \brief Destructor - ~TypeMismatchException() noexcept final = default; - - /// \brief Creating error message - /// \return Error message with expected and obtained type - const char* what() const noexcept final - { - return mMessage.data(); - } - - /// \brief Accessor to expected type - /// \return Name of the expected type - const std::string& getExpectedType() const { return mTypeExpected; } - - /// \brief Accessor to the type of the object obtained from the CCDB - /// \return Name of the obtained type of the object - const std::string& getObtainedType() const { return mTypeObtained; } - - private: - const std::string mTypeObtained; ///< Type of the object obtained from the CCDB - const std::string mTypeExpected; ///< Expected type of the object - std::string mMessage; ///< Resulting error message - }; - - /// \brief Default constructor - CalibDB() = default; - - /// \brief Constructor initializing also the server - /// \param server Name of the CCDB server to be used in queries - CalibDB(const std::string_view server); - - /// \brief Destructor - ~CalibDB() = default; - - /// \brief Store bad channel map in the CCDB - /// \brief bcm Bad channel map to be stored - /// \brief metadata Additional metadata that can be used in the query - /// \timestart Start of the time range of the validity of the object - /// \timeend End of the time range of the validity of the object - void storeBadChannelMap(BadChannelMap* bcm, const std::map<std::string, std::string>& metadata, ULong_t timestart, ULong_t timeend); - - /// \brief Find bad channel map in the CCDB for given timestamp - /// \param timestamp Timestamp used in query - /// \param metadata Additional metadata to be used in the query - /// \throw ObjectNotFoundException if object is not found for the given timestamp - /// \throw TypeMismatchException if object is present but type is different (CCDB corrupted) - BadChannelMap* readBadChannelMap(ULong_t timestamp, const std::map<std::string, std::string>& metadata); - - /// \brief Store calibration parameters in the CCDB - /// \brief prmtrs calibration parameters to be stored - /// \brief metadata Additional metadata that can be used in the query - /// \timestart Start of the time range of the validity of the object - /// \timeend End of the time range of the validity of the object - void storeCalibParams(CalibParams* prmtrs, const std::map<std::string, std::string>& metadata, ULong_t timestart, ULong_t timeend); - - /// \brief Find calibration parameters in the CCDB for given timestamp - /// \param timestamp Timestamp used in query - /// \param metadata Additional metadata to be used in the query - /// \throw ObjectNotFoundException if object is not found for the given timestamp - /// \throw TypeMismatchException if object is present but type is different (CCDB corrupted) - CalibParams* readCalibParams(ULong_t timestamp, const std::map<std::string, std::string>& metadata); - - /// \brief Set new CCDB server URL - /// \param server Name of the CCDB server to be used in queries - /// - /// Setting new CCDB server. Will require a re-init of the - /// the CCDB handler the next time a store or read of any object - /// is done. - void setServer(const std::string_view server) - { - mCCDBServer = server; - mInit = false; - } - - private: - /// \brief Initialize CCDB server (when new object is created or the server URL changes) - void init(); - - ccdb::CcdbApi mCCDBManager; ///< Handler for queries of the CCDB content - std::string mCCDBServer = "ccdb-test.cern.ch"; ///< Name of the CCDB server - Bool_t mInit = false; ///< Init status (needed for lazy evaluation of the CcdbApi init) - - ClassDefNV(CalibDB, 1); -}; -} // namespace phos - -} // namespace o2 diff --git a/Detectors/PHOS/calib/include/PHOSCalib/CalibParams.h b/Detectors/PHOS/calib/include/PHOSCalib/CalibParams.h deleted file mode 100644 index 302b6797d0283..0000000000000 --- a/Detectors/PHOS/calib/include/PHOSCalib/CalibParams.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \class CalibParams -/// \brief CCDB container for the full set of PHOS calibration coefficients -/// \author Dmitri Peresunko, RRC Kurchatov institute -/// \since Aug. 1, 2019 -/// -/// - -#ifndef PHOS_CALIBPARAMS_H -#define PHOS_CALIBPARAMS_H - -#include <array> -#include "TObject.h" - -class TH2; - -namespace o2 -{ - -namespace phos -{ - -class CalibParams -{ - public: - /// \brief Constructor - CalibParams() = default; - - /// \brief Constructor for tests - CalibParams(int test); - - /// \brief Destructor - ~CalibParams() = default; - - /// \brief Get High Gain energy calibration coefficients - /// \param cellID Absolute ID of cell - /// \return high gain energy calibration coefficient of the cell - float getGain(short cellID) const { return mGainCalib.at(cellID); } - - /// \brief Set High Gain energy calibration coefficient - /// \param cellID Absolute ID of cell - /// \param c is the calibration coefficient - void setGain(short cellID, float c) { mGainCalib[cellID] = c; } - - /// \brief Set High Gain energy calibration coefficients for one module in the form of 2D histogram - /// \param 2D(64,56) histogram with calibration coefficients - /// \param module number - /// \return Is successful - bool setGain(TH2* h, char module); - - /// \brief Get High Gain to Low Gain ratio calibration coefficients - /// \param cellID Absolute ID of cell - /// \return High Gain to Low Gain ratio of the cell - float getHGLGRatio(short cellID) const { return mHGLGRatio.at(cellID); } - - /// \brief Set High Gain to Low Gain ratio - /// \param cellID Absolute ID of cell - /// \param r is the calibration coefficient - void setHGLGRatio(short cellID, float r) { mHGLGRatio[cellID] = r; } - - /// \brief Set High Gain to Low Gain ratio for one module in the form of 2D histogram - /// \param 2D(64,56) histogram with High Gain to Low Gain ratio - /// \param module number - /// \return Is successful - bool setHGLGRatio(TH2* h, char module); - - /// \brief Get High Gain time calibration coefficients - /// \param cellID Absolute ID of cell - /// \return high gain time calibration coefficient of the cell - float getHGTimeCalib(short cellID) const { return mHGTimeCalib.at(cellID); } - - /// \brief Set High Gain time calibration coefficient - /// \param cellID Absolute ID of cell - /// \param t is the calibration coefficient - void setHGTimeCalib(short cellID, float t) { mHGTimeCalib[cellID] = t; } - - /// \brief Set High Gain time calibration coefficients for one module in the form of 2D histogram - /// \param 2D(64,56) histogram with calibration coefficients - /// \param module number - /// \return Is successful - bool setHGTimeCalib(TH2* h, char module); - - /// \brief Get Low Gain time calibration coefficient - /// \param cellID Absolute ID of cell - /// \return low gain time calibration coefficient of the cell - float getLGTimeCalib(short cellID) const { return mLGTimeCalib.at(cellID); } - - /// \brief Set time calibration coefficient - /// \param cellID Absolute ID of cell - /// \param t is the calibration coefficient - void setLGTimeCalib(short cellID, float t) { mLGTimeCalib[cellID] = t; } - - /// \brief Set Low Gain time calibration coefficients for one module in the form of 2D histogram - /// \param 2D(64,56) histogram with calibration coefficients - /// \param module number - /// \return Is successful - bool setLGTimeCalib(TH2* h, char module); - - private: - static constexpr short NCHANNELS = 14337; ///< Number of channels starting from 1 - std::array<float, NCHANNELS> mGainCalib; ///< Container for the gain calibration coefficients - std::array<float, NCHANNELS> mHGLGRatio; ///< Container for the High Gain to Low Gain ratios - std::array<float, NCHANNELS> mHGTimeCalib; ///< Container for the High Gain time calibration coefficients - std::array<float, NCHANNELS> mLGTimeCalib; ///< Container for the Low Gain time calibration coefficients - - ClassDefNV(CalibParams, 1); -}; - -} // namespace phos - -} // namespace o2 -#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/ETCalibHistos.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/ETCalibHistos.h new file mode 100644 index 0000000000000..c4714cc58d0d1 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/ETCalibHistos.h @@ -0,0 +1,171 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class ETCalibHistos +/// \brief container to store calibration info for time and energy calibration +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Apr. 1, 2021 +/// +/// + +#ifndef PHOS_ETCALIBHISTOS_H +#define PHOS_ETCALIBHISTOS_H + +#include <array> +#include <cstring> +#include "TObject.h" + +namespace o2 +{ + +namespace phos +{ + +class ETCalibHistos +{ + public: + //Histogram kinds to be filled + enum hnames { kReInvMassPerCell, + kMiInvMassPerCell, + kReInvMassNonlin, + kMiInvMassNonlin, + kTimeHGPerCell, + kTimeLGPerCell, + kTimeHGSlewing, + kTimeLGSlewing }; + static constexpr int nChannels = 14336 - 1793; //4 full modules -1/2 + static constexpr int offset = 1793; //1/2 full module + //mgg histos + static constexpr int nMass = 150.; + static constexpr float massMax = 0.3; + static constexpr float dm = massMax / nMass; + //time histograms + static constexpr int nTime = 200; + static constexpr float timeMin = -100.e-9; + static constexpr float timeMax = 100.e-9; + static constexpr float dt = (timeMax - timeMin) / nTime; + + //pt + static constexpr int npt = 200; + static constexpr float ptMax = 20; + static constexpr float dpt = ptMax / npt; + + /// \brief Constructor + ETCalibHistos() = default; + + ETCalibHistos& operator=(const ETCalibHistos& other) = default; + + /// \brief Destructor + ~ETCalibHistos() = default; + + /// \brief Merge statistics in two containers + /// \param other Another container to be added to current + void merge(ETCalibHistos& other) + { + for (int i = nChannels; --i;) { + for (int j = nMass; --j;) { + mReInvMassPerCell[i][j] += other.mReInvMassPerCell[i][j]; + mMiInvMassPerCell[i][j] += other.mMiInvMassPerCell[i][j]; + } + for (int j = nTime; --j;) { + mTimeHGPerCell[i][j] += other.mTimeHGPerCell[i][j]; + mTimeLGPerCell[i][j] += other.mTimeLGPerCell[i][j]; + } + } + for (int i = npt; --i;) { + for (int j = nMass; --j;) { + mReInvMassNonlin[i][j] += other.mReInvMassNonlin[i][j]; + mMiInvMassNonlin[i][j] += other.mMiInvMassNonlin[i][j]; + } + for (int j = nTime; --j;) { + mTimeHGSlewing[i][j] += other.mTimeHGSlewing[i][j]; + mTimeLGSlewing[i][j] += other.mTimeLGSlewing[i][j]; + } + } + } + + void fill(int kind, float x, float y) + { + if (kind == kReInvMassNonlin || kind == kMiInvMassNonlin) { + int i = int(x / dm); + int j = int(y / dpt); + if (i < nMass && j < npt) { + if (kind == kReInvMassNonlin) { + mReInvMassNonlin[i][j]++; + } else { + mMiInvMassNonlin[i][j]++; + } + } + } + if (kind == kTimeHGSlewing || kind == kTimeLGSlewing) { + int i = int((x - timeMin) / dt); + int j = int(y / dpt); + if (i >= 0 && i < nTime && j < npt) { + if (kind == kTimeHGSlewing) { + mTimeHGSlewing[i][j]++; + } else { + mTimeHGSlewing[i][j]++; + } + } + } + } + void fill(int kind, int x, float y) + { + if (kind == kReInvMassPerCell || kind == kMiInvMassPerCell) { + int j = int(y / dm); + if (j < nMass) { + if (kind == kReInvMassPerCell) { + mReInvMassPerCell[x - offset][j]++; + } else { + mMiInvMassPerCell[x - offset][j]++; + } + } + } + if (kind == kTimeHGPerCell || kind == kTimeLGPerCell) { + int j = int((y - timeMin) / dt); + if (j >= 0 && j < nTime) { + if (kind == kTimeHGPerCell) { + mTimeHGPerCell[x - offset][j]++; + } else { + mTimeLGPerCell[x - offset][j]++; + } + } + } + } + void reset() + { + memset(&mReInvMassPerCell, 0, sizeof(mReInvMassPerCell)); + memset(&mMiInvMassPerCell, 0, sizeof(mMiInvMassPerCell)); + memset(&mReInvMassNonlin, 0, sizeof(mReInvMassNonlin)); + memset(&mMiInvMassNonlin, 0, sizeof(mMiInvMassNonlin)); + memset(&mTimeHGPerCell, 0, sizeof(mTimeHGPerCell)); + memset(&mTimeLGPerCell, 0, sizeof(mTimeLGPerCell)); + memset(&mTimeHGSlewing, 0, sizeof(mTimeHGSlewing)); + memset(&mTimeLGSlewing, 0, sizeof(mTimeLGSlewing)); + } + + public: + std::array<std::array<float, nMass>, nChannels> mReInvMassPerCell; ///< inv mass per cell + std::array<std::array<float, nMass>, nChannels> mMiInvMassPerCell; ///< inv mass per cell + std::array<std::array<float, npt>, nMass> mReInvMassNonlin; ///< inv mass vs pT + std::array<std::array<float, npt>, nMass> mMiInvMassNonlin; ///< inv mass vs pT + std::array<std::array<float, nTime>, nChannels> mTimeHGPerCell; ///< time per cell + std::array<std::array<float, nTime>, nChannels> mTimeLGPerCell; ///< time per cell + std::array<std::array<float, npt>, nTime> mTimeHGSlewing; ///< time vs pT + std::array<std::array<float, npt>, nTime> mTimeLGSlewing; ///< time vs pT + + ClassDefNV(ETCalibHistos, 1); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibDevice.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibDevice.h new file mode 100644 index 0000000000000..397555ab0efc0 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibDevice.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSENERGY_CALIBDEV_H +#define O2_CALIBRATION_PHOSENERGY_CALIBDEV_H + +/// @file PHOSEnergyCalibDevice.h +/// @brief Device to collect histos and digits for PHOS energy and time calibration. + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ProcessingContext.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/BadChannelsMap.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "PHOSCalibWorkflow/PHOSEnergyCalibrator.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSEnergyCalibDevice : public o2::framework::Task +{ + public: + explicit PHOSEnergyCalibDevice(bool useCCDB, std::string path, std::string digitspath) : mUseCCDB(useCCDB), mCCDBPath(path), mdigitsfilename(digitspath) {} + + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + private: + static constexpr short kMaxCluInEvent = 64; /// maximal number of clusters per event to separate digits from them (6 bits in digit map) + bool mUseCCDB = false; + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; ///< CCDB server path + std::string mdigitsfilename = "./CalibDigits.root"; + long mRunStartTime = 0; /// start time of the run (sec) + float mPtMin = 1.5; /// minimal energy to fill inv. mass histo + float mEminHGTime = 1.5; + float mEminLGTime = 5.; + std::unique_ptr<PHOSEnergyCalibrator> mCalibrator; /// Agregator of calibration TimeFrameSlots + std::unique_ptr<BadChannelsMap> mBadMap; /// Latest bad channels map + std::unique_ptr<CalibParams> mCalibParams; /// Latest bad channels map + ClassDefNV(PHOSEnergyCalibDevice, 1); +}; + +o2::framework::DataProcessorSpec getPHOSEnergyCalibDeviceSpec(bool useCCDB, std::string path, std::string digitspath); +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibrator.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibrator.h new file mode 100644 index 0000000000000..3fb685e7668b5 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSEnergyCalibrator.h @@ -0,0 +1,159 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSENERGY_CALIBRATOR_H +#define O2_CALIBRATION_PHOSENERGY_CALIBRATOR_H + +/// @file PHOSEnergyCalibtor.h +/// @brief Device to collect energy and time PHOS energy and time calibration. + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/Cluster.h" +#include "PHOSCalibWorkflow/RingBuffer.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "DataFormatsPHOS/BadChannelsMap.h" +#include "PHOSBase/Geometry.h" +#include "PHOSCalibWorkflow/ETCalibHistos.h" + +#include <TLorentzVector.h> +#include <TVector3.h> +#include <TFile.h> +#include <array> + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +// structure used to store digit info for re-calibration +union CalibDigit { + uint32_t mDataWord; + struct { + uint32_t mAddress : 14; ///< Bits 0 - 13: Hardware address + uint32_t mAdcAmp : 10; ///< Bits 14 - 23: ADC counts + uint32_t mHgLg : 1; ///< Bit 24: LG/HG + uint32_t mCluster : 7; ///< Bits 25-32: index of cluster in event + }; +}; +// Event header for energy calibraton. Allow accessing external info with vertex position and collision time +union EventHeader { + uint32_t mDataWord; + struct { + uint32_t mMarker : 14; ///< Bits 0 - 13: non-existing address to separate events 16383 + uint32_t mBC : 18; ///< Bits 14-32: event BC (16bit in InterationRecord. Orbit (32bit) will be stored in next word) + }; +}; + +class PHOSEnergySlot +{ + + public: + static constexpr short kMaxCluInEvent = 128; /// maximal number of clusters per event to separate digits from them (7 bits in digit map) + + PHOSEnergySlot(); + PHOSEnergySlot(const PHOSEnergySlot& other); + + ~PHOSEnergySlot() = default; + + void print() const; + void fill(const gsl::span<const Cluster>& clusters, const gsl::span<const CluElement>& cluelements, const gsl::span<const TriggerRecord>& cluTR); + void fill(const gsl::span<const Cluster>& /*c*/){}; //not used + void merge(const PHOSEnergySlot* /*prev*/) {} //not used + void clear(); + + ETCalibHistos& getCollectedHistos() { return mHistos; } + std::vector<uint32_t>& getCollectedDigits() { return mDigits; } + + void setRunStartTime(long tf) { mRunStartTime = tf; } + void setCalibration(CalibParams& c) { mCalibParams.reset(new CalibParams(c)); } + void setBadMap(BadChannelsMap& map) { mBadMap.reset(new BadChannelsMap(map)); } + void setCuts(float ptMin, float eminHGTime, float eminLGTime) + { + mPtMin = ptMin; + mEminHGTime = eminHGTime; + mEminLGTime = eminLGTime; + } + + private: + void fillTimeMassHisto(const Cluster& clu, const gsl::span<const CluElement>& cluelements); + bool checkCluster(const Cluster& clu); + + long mRunStartTime = 0; /// start time of the run (sec) + std::unique_ptr<RingBuffer> mBuffer; /// Buffer for current and previous events + std::unique_ptr<CalibParams> mCalibParams; /// Final calibration object + std::unique_ptr<BadChannelsMap> mBadMap; /// Final calibration object + Geometry* mGeom; /// Pointer to PHOS singleton geometry + TVector3 mVertex; + ETCalibHistos mHistos; /// final histograms + uint32_t mEvBC = 0; + uint32_t mEvOrbit = 0; + uint32_t mEvent = 0; + float mPtMin = 1.5; /// minimal energy to fill inv. mass histo + float mEminHGTime = 1.5; + float mEminLGTime = 5.; + std::vector<uint32_t> mDigits; /// list of calibration digits to fill + + ClassDefNV(PHOSEnergySlot, 1); +}; + +class PHOSEnergyCalibrator final : public o2::calibration::TimeSlotCalibration<o2::phos::Cluster, o2::phos::PHOSEnergySlot> +{ + using Slot = o2::calibration::TimeSlot<o2::phos::PHOSEnergySlot>; + + public: + PHOSEnergyCalibrator(); + + bool hasEnoughData(const Slot& slot) const final { return true; } //no need to merge Slots + void initOutput() final {} + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) final; + bool process(uint64_t tf, const gsl::span<const Cluster>& clusters, const gsl::span<const CluElement>& cluelements, const gsl::span<const TriggerRecord>& cluTR); + + void endOfStream(); + + void setOutDigitsFile(std::string& name) { mdigitsfilename = name; }; + void setCalibration(CalibParams& c) { mCalibParams.reset(new CalibParams(c)); } + void setBadMap(BadChannelsMap& map) { mBadMap.reset(new BadChannelsMap(map)); } + void setCuts(float ptMin, float eminHGTime, float eminLGTime) + { + mPtMin = ptMin; + mEminHGTime = eminHGTime; + mEminLGTime = eminLGTime; + } + + private: + bool calculateCalibrations(); + + private: + std::string mdigitsfilename = "CalibDigits.root"; + long mRunStartTime = 0; /// start time of the run (sec) + int mChank = 0; /// Number of digits chanks (==TF) wrote to file + float mPtMin = 1.5; /// minimal energy to fill inv. mass histo + float mEminHGTime = 1.5; + float mEminLGTime = 5.; + std::unique_ptr<CalibParams> mCalibParams; /// Current calibration object + std::unique_ptr<BadChannelsMap> mBadMap; /// Current BadMap + ETCalibHistos mHistos; /// final histograms + std::vector<uint32_t> mDigits; /// list of calibration digits to fill + std::unique_ptr<TFile> mFout; /// file to write calib digits + + ClassDefOverride(PHOSEnergyCalibrator, 1); +}; + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h new file mode 100644 index 0000000000000..562c1840d37ad --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSHGLGRATIO_CALIBRATOR_H +#define O2_CALIBRATION_PHOSHGLGRATIO_CALIBRATOR_H + +/// @file HGLGRatioCalibSpec.h +/// @brief Device to calculate PHOS HG/LG ratio + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "PHOSBase/Mapping.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "TH2.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSHGLGRatioCalibDevice : public o2::framework::Task +{ + + union PairAmp { + uint32_t mDataWord; + struct { + uint32_t mHGAmp : 16; ///< Bits 0 - 15: HG amplitude in channel + uint32_t mLGAmp : 16; ///< Bits 16 - 25: LG amplitude in channel + }; + }; + + public: + explicit PHOSHGLGRatioCalibDevice(bool useCCDB, bool forceUpdate, std::string path) : mUseCCDB(useCCDB), mForceUpdate(forceUpdate), mCCDBPath(path) {} + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + void sendOutput(DataAllocator& output); + void fillRatios(); + void calculateRatios(); + void checkRatios(); + + // void evaluateMeans + + private: + bool mUseCCDB = false; + bool mForceUpdate = false; /// Update CCDB even if difference to current is large + bool mUpdateCCDB = true; /// set is close to current and can update it + static constexpr short kMinorChange = 10; /// ignore if number of channels changed smaller than... + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; ///< CCDB server path + std::unique_ptr<CalibParams> mCalibParams; //! Final calibration object + short mMinLG = 20; /// minimal LG ampl used in ratio + short minimalStatistics = 100; /// minimal statistics per channel + std::map<short, PairAmp> mMapPairs; //! HG/LG pair + std::unique_ptr<TH2F> mhRatio; //! Histogram with ratios + std::array<float, o2::phos::Mapping::NCHANNELS> mRatioDiff; //! Ratio variation wrt previous map +}; + +DataProcessorSpec getHGLGRatioCalibSpec(bool useCCDB, bool forceUpdate, std::string path); + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h new file mode 100644 index 0000000000000..93dd2ec152da5 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSPEDESTALS_CALIBRATOR_H +#define O2_CALIBRATION_PHOSPEDESTALS_CALIBRATOR_H + +/// @file PedestalCalibSpec.h +/// @brief Device to calculate PHOS pedestals + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "PHOSBase/Mapping.h" +#include "DataFormatsPHOS/Pedestals.h" +#include "TH2.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSPedestalCalibDevice : public o2::framework::Task +{ + + public: + explicit PHOSPedestalCalibDevice(bool useCCDB, bool forceUpdate, std::string path) : mUseCCDB(useCCDB), mForceUpdate(forceUpdate), mCCDBPath(path) {} + + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + void sendOutput(DataAllocator& output); + // void evaluateMeans + void calculatePedestals(); + void checkPedestals(); + + private: + bool mUseCCDB = false; + bool mForceUpdate = false; /// Update CCDB even if difference to current is large + bool mUpdateCCDB = true; /// set is close to current and can update it + static constexpr short kMinorChange = 10; /// ignore if number of channels changed smaller than... + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; /// CCDB path to retrieve current CCDB objects for comparison + std::unique_ptr<Pedestals> mPedestals; //! Final calibration object + std::unique_ptr<Pedestals> mOldPed; //! Pedestals currently stored in CCDB for comparisoin + std::unique_ptr<TH2F> mMeanHG; //! Mean values in High Gain channels + std::unique_ptr<TH2F> mMeanLG; //! RMS of values in High Gain channels + std::unique_ptr<TH2F> mRMSHG; //! Mean values in Low Gain channels + std::unique_ptr<TH2F> mRMSLG; //! RMS of values in Low Gain channels + std::array<short, 2 * o2::phos::Mapping::NCHANNELS + 1> mPedDiff; //! Pedestal variation wrt previous map +}; + +o2::framework::DataProcessorSpec getPedestalCalibSpec(bool useCCDB, bool forceUpdate, std::string path); +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h new file mode 100644 index 0000000000000..f862f7ece4eb0 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSRUNBYRUN_CALIBDEV_H +#define O2_CALIBRATION_PHOSRUNBYRUN_CALIBDEV_H + +/// @file PHOSRunbyrunCalibDevice.h +/// @brief Device to calculate PHOS energy run by run corrections + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ProcessingContext.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/BadChannelsMap.h" +#include "PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSRunbyrunCalibDevice +{ + public: + PHOSRunbyrunCalibDevice() = default; + + void init(o2::framework::InitContext& ic); + + void run(o2::framework::ProcessingContext& pc); + + void endOfStream(o2::framework::EndOfStreamContext& ec); + + protected: + bool checkFitResult(); + + private: + bool mUseCCDB = false; + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; /// CCDB path to retrieve current CCDB objects for comparison + std::array<float, 8> mRunByRun; /// Final calibration object + std::unique_ptr<PHOSRunbyrunCalibrator> mCalibrator; /// Agregator of calibration TimeFrameSlots +}; + +o2::framework::DataProcessorSpec getPHOSRunbyrunCalibDeviceSpec(bool useCCDB, std::string path); +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h new file mode 100644 index 0000000000000..e6094308c1512 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h @@ -0,0 +1,111 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSRUNBYRUN_CALIBRATOR_H +#define O2_CALIBRATION_PHOSRUNBYRUN_CALIBRATOR_H + +/// @file PHOSRunbyrunCalibDevice.h +/// @brief Device to calculate PHOS energy run by run corrections + +#include "Framework/Task.h" +#include "Framework/ProcessingContext.h" +#include "DataFormatsPHOS/BadChannelsMap.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include <boost/histogram.hpp> +#include "TH1.h" +#include "PHOSCalibWorkflow/RingBuffer.h" +#include "DataFormatsPHOS/Cluster.h" +#include "PHOSBase/Geometry.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSRunbyrunSlot +{ + public: + using boostHisto = boost::histogram::histogram<std::tuple<boost::histogram::axis::regular<double, boost::use_default, boost::use_default, boost::use_default>>, boost::histogram::unlimited_storage<std::allocator<char>>>; + + PHOSRunbyrunSlot(bool useCCDB, std::string path); + PHOSRunbyrunSlot(const PHOSRunbyrunSlot& other); + + ~PHOSRunbyrunSlot() = default; + + void print() const; + void fill(const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& trs); + void fill(const gsl::span<const Cluster>& /*clusters*/){}; //not used + void merge(const PHOSRunbyrunSlot* prev); + void clear(); + + boostHisto& getCollectedHistos(int m) { return mReMi[m]; } + + void setRunStartTime(long tf) { mRunStartTime = tf; } + + private: + bool checkCluster(const Cluster& clu); + + private: + bool mUseCCDB = false; + long mRunStartTime = 0; /// start time of the run (sec) + float mPtCut = 1.5; /// ptmin of a pair cut (GeV/c) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; /// CCDB path to retrieve current CCDB objects for comparison + std::array<boostHisto, 8> mReMi; /// Real and Mixed inv mass distributions per module + std::unique_ptr<RingBuffer> mBuffer; /// Buffer for current and previous events + std::unique_ptr<BadChannelsMap> mBadMap; /// Latest bad channels map + + ClassDefNV(PHOSRunbyrunSlot, 1); +}; + +//========================================================================================== +class PHOSRunbyrunCalibrator final : public o2::calibration::TimeSlotCalibration<o2::phos::Cluster, o2::phos::PHOSRunbyrunSlot> +{ + using Slot = o2::calibration::TimeSlot<o2::phos::PHOSRunbyrunSlot>; + + public: + PHOSRunbyrunCalibrator(); + ~PHOSRunbyrunCalibrator() final; + + bool hasEnoughData(const Slot& slot) const final; + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) final; + bool process(uint64_t tf, const gsl::span<const Cluster>& clu, const gsl::span<const TriggerRecord>& trs); + + std::array<float, 8> getCalibration() { return mRunByRun; } + void endOfStream(); + + //Functions used in histo fittings + double CBRatio(double* x, double* p); + double CBSignal(double* x, double* p); + double bg(double* x, double* p); + + private: + void scanClusters(o2::framework::ProcessingContext& pc); + bool checkCluster(const Cluster& clu); + + private: + bool mUseCCDB = false; + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; /// CCDB path to retrieve current CCDB objects for comparison + std::array<float, 8> mRunByRun; /// Final calibration object + std::array<TH1F*, 8> mReMi; /// Real and Mixed inv mass distributions per module + + ClassDefOverride(PHOSRunbyrunCalibrator, 1); +}; + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibDevice.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibDevice.h new file mode 100644 index 0000000000000..a8c9b58f56aaf --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibDevice.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSTURNON_CALIBDEV_H +#define O2_CALIBRATION_PHOSTURNON_CALIBDEV_H + +/// @file PHOSTurnonCalibDevice.h +/// @brief Device to calculate PHOS turn-on curves and trigger map + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/TriggerMap.h" +#include "PHOSCalibWorkflow/PHOSTurnonCalibrator.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSTurnonCalibDevice : public o2::framework::Task +{ + public: + explicit PHOSTurnonCalibDevice(bool useCCDB, std::string path) : mUseCCDB(useCCDB), mCCDBPath(path) {} + + void init(o2::framework::InitContext& ic) final; + + void run(o2::framework::ProcessingContext& pc) final; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + protected: + bool checkFitResult() { return true; } //TODO!! implement true check + + private: + bool mUseCCDB = false; + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; ///< CCDB server path + long mRunStartTime = 0; /// start time of the run (sec) + std::unique_ptr<TriggerMap> mTriggerMap; /// Final calibration object + std::unique_ptr<PHOSTurnonCalibrator> mCalibrator; /// Agregator of calibration TimeFrameSlots +}; + +o2::framework::DataProcessorSpec getPHOSTurnonCalibDeviceSpec(bool useCCDB, std::string path); +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibrator.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibrator.h new file mode 100644 index 0000000000000..e1656c2a19af8 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/PHOSTurnonCalibrator.h @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOSTURNON_CALIBRATOR_H +#define O2_CALIBRATION_PHOSTURNON_CALIBRATOR_H + +/// @file PHOSTurnonCalibrator.h +/// @brief Device to calculate PHOS turn-on curve and bad map + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/TriggerMap.h" +#include "PHOSCalibWorkflow/TurnOnHistos.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +class PHOSTurnonSlot +{ + public: + static constexpr short NCHANNELS = 3136; ///< Number of trigger channels + + PHOSTurnonSlot(bool useCCDB, std::string path); + PHOSTurnonSlot(const PHOSTurnonSlot& other); + + ~PHOSTurnonSlot() = default; + + void print() const; + void fill(const gsl::span<const Cell>& cells, const gsl::span<const TriggerRecord>& trs, + const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& cluTR); + void fill(const gsl::span<const Cluster>& /*cells*/){}; //not used + void merge(const PHOSTurnonSlot* /*prev*/) {} //not used + void clear(); + + TurnOnHistos& getCollectedHistos() { return *mTurnOnHistos; } + + void setRunStartTime(long tf) { mRunStartTime = tf; } + + private: + void scanClusters(const gsl::span<const Cell>& cells, const TriggerRecord& celltr, + const gsl::span<const Cluster>& clusters, const TriggerRecord& clutr); + + private: + bool mUseCCDB = false; + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; ///< CCDB server path + std::bitset<NCHANNELS> mFiredTiles; //! Container for bad trigger cells, 1 means bad sell + std::bitset<NCHANNELS> mNoisyTiles; //! Container for bad trigger cells, 1 means bad sell + std::unique_ptr<TurnOnHistos> mTurnOnHistos; //! Collection of histos to fill + + ClassDefNV(PHOSTurnonSlot, 1); +}; + +//========================================================================================== +class PHOSTurnonCalibrator final : public o2::calibration::TimeSlotCalibration<o2::phos::Cluster, o2::phos::PHOSTurnonSlot> +{ + using Slot = o2::calibration::TimeSlot<o2::phos::PHOSTurnonSlot>; + + public: + PHOSTurnonCalibrator() = default; + + bool hasEnoughData(const Slot& slot) const final { return true; } //no need to merge Slots + void initOutput() final {} + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) final; + bool process(uint64_t tf, const gsl::span<const Cell>& cells, const gsl::span<const TriggerRecord>& trs, + const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& cluTR); + + TriggerMap& getCalibration() { return *mTriggerMap; } + void endOfStream(); + + private: + bool calculateCalibrations(); + + private: + bool mUseCCDB = false; + long mRunStartTime = 0; /// start time of the run (sec) + std::string mCCDBPath{"http://ccdb-test.cern.ch:8080"}; /// CCDB path to retrieve current CCDB objects for comparison + std::unique_ptr<TurnOnHistos> mTurnOnHistos; //! Collection of histos to fill + std::unique_ptr<TriggerMap> mTriggerMap; + + ClassDefOverride(PHOSTurnonCalibrator, 1); +}; + +o2::framework::DataProcessorSpec getPHOSTunronCalibDeviceSpec(bool useCCDB, std::string path); +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/RingBuffer.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/RingBuffer.h new file mode 100644 index 0000000000000..8f075d0de57c7 --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/RingBuffer.h @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_PHOS_RINGBUFFER_H +#define O2_CALIBRATION_PHOS_RINGBUFFER_H + +/// @file RingBuffer.h +/// @brief Device to collect energy and time PHOS energy and time calibration. + +#include <TLorentzVector.h> +#include <TVector3.h> +#include <array> + +namespace o2 +{ +namespace phos +{ + +// For real/mixed distribution calculation +class RingBuffer +{ + public: + RingBuffer() = default; + ~RingBuffer() = default; + + short size() + { + if (mFilled) { + return kBufferSize; + } else { + return mCurrent; + } + } + void addEntry(TLorentzVector& v) + { + mBuffer[mCurrent] = v; + mCurrent++; + if (mCurrent >= kBufferSize) { + mFilled = true; + mCurrent -= kBufferSize; + } + } + const TLorentzVector& getEntry(short index) const + { + //get entry from (mCurrent-1) corresponding to index=size()-1 down to size + if (mFilled) { + index += mCurrent; + } + index = index % kBufferSize; + return mBuffer[index]; + } + //mark that next added entry will be from next event + void startNewEvent() { mStartCurrentEvent = mCurrent; } + + bool isCurrentEvent(short index) const + { + if (mCurrent >= mStartCurrentEvent) { + return (index >= mStartCurrentEvent && index < mCurrent); + } else { + return (index >= mStartCurrentEvent || index < mCurrent); + } + } + + private: + static constexpr short kBufferSize = 100; ///< Total size of the buffer + std::array<TLorentzVector, kBufferSize> mBuffer; ///< buffer + bool mFilled = false; ///< if buffer fully filled + short mCurrent = 0; ///< where next object will be added + short mStartCurrentEvent = 0; ///< start of current event +}; +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/calib/include/PHOSCalibWorkflow/TurnOnHistos.h b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/TurnOnHistos.h new file mode 100644 index 0000000000000..4457da2e100ad --- /dev/null +++ b/Detectors/PHOS/calib/include/PHOSCalibWorkflow/TurnOnHistos.h @@ -0,0 +1,115 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class TurnOnHistos +/// \brief transient CCDB container to collect histos for calculation of trigger maps and turn-on curves +/// \author Dmitri Peresunko, RRC Kurchatov institute +/// \since Apr. 1, 2021 +/// +/// + +#ifndef PHOS_TURNONHISTOS_H +#define PHOS_TURNONHISTOS_H + +#include <bitset> +#include <array> +#include "TObject.h" + +namespace o2 +{ + +namespace phos +{ + +class TurnOnHistos +{ + public: + //class to collect statistics to calculate trigger turn-on curves and trigger bad maps + static constexpr short NCHANNELS = 3136; ///< Number of trigger channels + static constexpr short NDDL = 14; ///< Number of DDLs + static constexpr short Npt = 200; ///< Number of bins in pt distribution + static constexpr float dpt = 0.1; ///< bin width + + /// \brief Constructor + TurnOnHistos() = default; + + TurnOnHistos& operator=(const TurnOnHistos& other) = default; + + /// \brief Destructor + ~TurnOnHistos() = default; + + /// \brief Merge statistics in two containers + /// \param other Another container to be added to current + void merge(TurnOnHistos& other); + + /// \brief Fill spectum of all clusters + /// \param ddl ddl ID + /// \param e cluster energy + void fillTotSp(short ddl, float e) + { + short bin = e / dpt; + if (bin < Npt) { + mTotSp[ddl][bin]++; + } + } + + /// \brief Fill spectum of clusters fired trigger + /// \param ddl ddl ID + /// \param e cluster energy + void fillFiredSp(short ddl, float e) + { + short bin = e / dpt; + if (bin < Npt) { + mTrSp[ddl][bin]++; + } + } + + /// \brief Collects entries in good map + /// \param bitset with channels fired in event + void fillFiredMap(const std::bitset<NCHANNELS>& bs) + { + for (short i = NCHANNELS; --i;) { + if (bs[i]) { + mGoodMap[i]++; + } + } + } + + /// \brief Collects entries in noisy map + /// \param bitset with channels fired in event + void fillNoisyMap(const std::bitset<NCHANNELS>& bs) + { + for (short i = NCHANNELS; --i;) { + if (bs[i]) { + mNoisyMap[i]++; + } + } + } + + //getters now + const std::array<float, Npt>& getTotSpectrum(short ddl) const { return mTotSp[ddl]; } + const std::array<float, Npt>& getTrSpectrum(short ddl) const { return mTrSp[ddl]; } + const std::array<float, NCHANNELS>& getGoodMap() const { return mGoodMap; } + const std::array<float, NCHANNELS>& getNoisyMap() const { return mNoisyMap; } + + private: + std::array<float, NCHANNELS> mGoodMap; ///< Container to collect entries in good map + std::array<float, NCHANNELS> mNoisyMap; ///< Container to collect entries in noisy map + std::array<std::array<float, Npt>, NDDL> mTotSp; ///< Spectrum of all clusters + std::array<std::array<float, Npt>, NDDL> mTrSp; ///< Spectrum of fired trigger cl. + + ClassDefNV(TurnOnHistos, 1); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/calib/macros/PostBadMapCCDB.C b/Detectors/PHOS/calib/macros/PostBadMapCCDB.C deleted file mode 100644 index a307ac7359c62..0000000000000 --- a/Detectors/PHOS/calib/macros/PostBadMapCCDB.C +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include "TRandom.h" -#include "CCDB/CcdbApi.h" -#include "PHOSCalib/BadChannelMap.h" -#include "PHOSBase/Geometry.h" -#endif -void PostBadMapCCDB() -{ - - //Post test bad map for PHOS to test CCDB - - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - - auto o2phosBM = new o2::phos::BadChannelMap(); - - o2::phos::Geometry* geom = o2::phos::Geometry::GetInstance("Run3"); // Needed for tranforming 2D histograms to channel ID - - int nBad = 50; - - for (int i = 0; i < nBad; i++) { - unsigned short channelID = gRandom->Uniform(56 * 64 * 3.5); //Random bad channels in 3.5 PHOS modules - o2phosBM->addBadChannel(channelID); - } - - ccdb.storeAsTFileAny(o2phosBM, "PHOS/BadMap", metadata, 1, 1670700184549); // one year validity time -} \ No newline at end of file diff --git a/Detectors/PHOS/calib/macros/PostCalibCCDB.C b/Detectors/PHOS/calib/macros/PostCalibCCDB.C deleted file mode 100644 index b26b54ba33985..0000000000000 --- a/Detectors/PHOS/calib/macros/PostCalibCCDB.C +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include "TFile.h" -#include "TH2F.h" -#include "CCDB/CcdbApi.h" -#include "PHOSCalib/CalibParams.h" -#include "PHOSBase/Geometry.h" -#include <iostream> -#endif -void PostCalibCCDB() -{ - - //Post test calibration parameters for PHOS to test CCDB - //Input are files which can be produced with macros PlotOCDB.C - - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - - auto o2phosCalib = new o2::phos::CalibParams(); - - o2::phos::Geometry* geom = o2::phos::Geometry::GetInstance("Run3"); // Needed for tranforming 2D histograms to channel ID - - TFile* fHGLGratio = new TFile("Run2_HGLH.root"); - // TFile * fTimeCalib = new TFile("Run2_TimeCalib.root") ; - TFile* fGains = new TFile("Run2_PHOSCalib.root"); - TH2F *hHGLG[5], *hTimeHG[5], *hTimeLG[5], *hGains[5]; - for (Int_t mod = 1; mod < 5; mod++) { - hHGLG[mod] = (TH2F*)fHGLGratio->Get(Form("LGHGm%d", mod)); - - if (!o2phosCalib->setHGLGRatio(hHGLG[mod], mod)) { - std::cout << " Can not set LG/HG ratio for module " << mod << std::endl; - return; - } - - hTimeHG[mod] = (TH2F*)fGains->Get(Form("Tmod%d", mod)); - hTimeLG[mod] = (TH2F*)fGains->Get(Form("Tlmod%d", mod)); - if (!o2phosCalib->setHGTimeCalib(hTimeHG[mod], mod)) { - std::cout << " Can not set HG time for module " << mod << std::endl; - return; - } - if (!o2phosCalib->setLGTimeCalib(hTimeLG[mod], mod)) { - std::cout << " Can not set LG time for module " << mod << std::endl; - return; - } - - hGains[mod] = (TH2F*)fGains->Get(Form("mod%d", mod)); - if (!o2phosCalib->setGain(hGains[mod], mod)) { - std::cout << " Can not set gain for module " << mod << std::endl; - return; - } - } - - ccdb.storeAsTFileAny(o2phosCalib, "PHOS/Calib", metadata, 1, 1670700184549); // one year validity time -} \ No newline at end of file diff --git a/Detectors/PHOS/calib/src/BadChannelMap.cxx b/Detectors/PHOS/calib/src/BadChannelMap.cxx deleted file mode 100644 index 4e920ef009671..0000000000000 --- a/Detectors/PHOS/calib/src/BadChannelMap.cxx +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "PHOSBase/Geometry.h" -#include "PHOSCalib/BadChannelMap.h" - -#include "FairLogger.h" - -#include <TH2.h> - -#include <iostream> - -using namespace o2::phos; - -BadChannelMap::BadChannelMap(int /*dummy*/) -{ - - //Mark few channels as bad for test peurposes - for (short i = 0; i < 56; i++) { - //module 2 - short channelID = 3584 + i * 57; - mBadCells.set(channelID); - channelID = 3640 + i * 55; - mBadCells.set(channelID); - } - - for (short i = 0; i < 16; i++) { - //module 3 - int channelID = 8972 + i * 57; - mBadCells.set(channelID); - channelID = 8092 + i * 57; - mBadCells.set(channelID); - channelID = 8147 + i * 55; - mBadCells.set(channelID); - channelID = 9059 + i * 55; - mBadCells.set(channelID); - } -} - -void BadChannelMap::getHistogramRepresentation(char module, TH2* h) const -{ - if (!h) { - LOG(ERROR) << "provide histogram to be filled"; - } - - const char MAXX = 64, - MAXZ = 56; - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return; - } - - h->Reset(); - auto geo = Geometry::GetInstance(); - if (!geo) { - LOG(ERROR) << "Geometry needs to be initialized"; - return; - } - - char relid[3] = {module, 1, 1}; - short absId; - for (char ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (char iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - if (geo->relToAbsNumbering(relid, absId)) { - if (!isChannelGood(absId)) { - h->SetBinContent(ix, iz, 1); - } - } - } - } -} - -void BadChannelMap::PrintStream(std::ostream& stream) const -{ - // first sort bad channel IDs - stream << "Number of bad cells: " << mBadCells.count() << "\n"; - for (int cellID = 0; cellID < mBadCells.size(); cellID++) { - if (mBadCells.test(cellID)) { - stream << cellID << "\n"; - } - } -} - -std::ostream& o2::phos::operator<<(std::ostream& stream, const BadChannelMap& bcm) -{ - bcm.PrintStream(stream); - return stream; -} diff --git a/Detectors/PHOS/calib/src/CalibDB.cxx b/Detectors/PHOS/calib/src/CalibDB.cxx deleted file mode 100644 index 08aa853a24997..0000000000000 --- a/Detectors/PHOS/calib/src/CalibDB.cxx +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "PHOSCalib/BadChannelMap.h" -#include "PHOSCalib/CalibDB.h" - -using namespace o2::phos; - -CalibDB::CalibDB(const std::string_view server) : CalibDB() -{ - mCCDBServer = server; -} - -void CalibDB::init() -{ - mCCDBManager.init(mCCDBServer); - mInit = true; -} - -void CalibDB::storeBadChannelMap(BadChannelMap* bcm, const std::map<std::string, std::string>& metadata, ULong_t rangestart, ULong_t rangeend) -{ - if (!mInit) { - init(); - } - mCCDBManager.storeAsTFile(new o2::TObjectWrapper<o2::phos::BadChannelMap>(bcm), "BadChannelMap/PHS", metadata, rangestart, rangeend); -} - -BadChannelMap* CalibDB::readBadChannelMap(ULong_t timestamp, const std::map<std::string, std::string>& metadata) -{ - if (!mInit) { - init(); - } - auto result = mCCDBManager.retrieveFromTFile("BadChannelMap/PHS", metadata, timestamp); - if (!result) { - throw ObjectNotFoundException(mCCDBServer, "BadChannelMap/PHS", metadata, timestamp); - } - if (result->IsA() != TObjectWrapper<o2::phos::BadChannelMap>::Class()) { - throw TypeMismatchException("TObjectWrapper<o2::phos::BadChannelMap>", result->IsA()->GetName()); - } - auto wrap = dynamic_cast<TObjectWrapper<o2::phos::BadChannelMap>*>(result); - if (!wrap) { - throw TypeMismatchException("TObjectWrapper<o2::phos::BadChannelMap>", result->IsA()->GetName()); // type checked before - should not enter here - } - return wrap->getObj(); -} -void CalibDB::storeCalibParams(CalibParams* prms, const std::map<std::string, std::string>& metadata, ULong_t rangestart, ULong_t rangeend) -{ - if (!mInit) { - init(); - } - mCCDBManager.storeAsTFile(new o2::TObjectWrapper<o2::phos::CalibParams>(prms), "CalibParams/PHS", metadata, rangestart, rangeend); -} -CalibParams* CalibDB::readCalibParams(ULong_t timestamp, const std::map<std::string, std::string>& metadata) -{ - if (!mInit) { - init(); - } - auto result = mCCDBManager.retrieveFromTFile("CalibParams/PHS", metadata, timestamp); - if (!result) { - throw ObjectNotFoundException(mCCDBServer, "CalibParams/PHS", metadata, timestamp); - } - if (result->IsA() != TObjectWrapper<o2::phos::CalibParams>::Class()) { - throw TypeMismatchException("TObjectWrapper<o2::phos::CalibParams>", result->IsA()->GetName()); - } - auto wrap = dynamic_cast<TObjectWrapper<o2::phos::CalibParams>*>(result); - if (!wrap) { - throw TypeMismatchException("TObjectWrapper<o2::phos::CalibParams>", result->IsA()->GetName()); // type checked before - should not enter here - } - return wrap->getObj(); -} diff --git a/Detectors/PHOS/calib/src/CalibParams.cxx b/Detectors/PHOS/calib/src/CalibParams.cxx deleted file mode 100644 index 7474eaa7154ed..0000000000000 --- a/Detectors/PHOS/calib/src/CalibParams.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "PHOSCalib/CalibParams.h" -#include "PHOSBase/Geometry.h" - -#include "FairLogger.h" - -#include <TH2.h> - -#include <iostream> - -using namespace o2::phos; - -CalibParams::CalibParams(int /*dummy*/) -{ - //produce reasonable objest for test purposes - mGainCalib.fill(0.005); - mHGLGRatio.fill(16.); - mHGTimeCalib.fill(0.); - mLGTimeCalib.fill(0.); -} - -bool CalibParams::setGain(TH2* h, char module) -{ - const char MAXX = 64, - MAXZ = 56; - if (!h) { - LOG(ERROR) << "no input histogam"; - return false; - } - - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return false; - } - - auto geo = Geometry::GetInstance(); - if (!geo) { - LOG(ERROR) << "Geometry needs to be initialized"; - return false; - } - - char relid[3] = {module, 1, 1}; - short absId; - for (char ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (char iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - - if (geo->relToAbsNumbering(relid, absId)) { - mGainCalib[absId] = h->GetBinContent(ix, iz); - } - } - } - return true; -} - -bool CalibParams::setHGLGRatio(TH2* h, char module) -{ - const char MAXX = 64, - MAXZ = 56; - if (!h) { - LOG(ERROR) << "no input histogam"; - return false; - } - - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return false; - } - - auto geo = Geometry::GetInstance(); - if (!geo) { - LOG(ERROR) << "Geometry needs to be initialized"; - return false; - } - - char relid[3] = {module, 1, 1}; - short absId; - for (char ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (char iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - - if (geo->relToAbsNumbering(relid, absId)) { - mHGLGRatio[absId] = h->GetBinContent(ix, iz); - } - } - } - return true; -} - -bool CalibParams::setHGTimeCalib(TH2* h, char module) -{ - const char MAXX = 64, - MAXZ = 56; - if (!h) { - LOG(ERROR) << "no input histogam"; - return false; - } - - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return false; - } - - auto geo = Geometry::GetInstance(); - if (!geo) { - LOG(ERROR) << "Geometry needs to be initialized"; - return false; - } - - char relid[3] = {module, 1, 1}; - short absId; - for (char ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (char iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - - if (geo->relToAbsNumbering(relid, absId)) { - mHGTimeCalib[absId] = h->GetBinContent(ix, iz); - } - } - } - return true; -} - -bool CalibParams::setLGTimeCalib(TH2* h, char module) -{ - const char MAXX = 64, - MAXZ = 56; - if (!h) { - LOG(ERROR) << "no input histogam"; - return false; - } - - if (h->GetNbinsX() != MAXX || h->GetNbinsY() != MAXZ) { - LOG(ERROR) << "Wrong dimentions of input histogram:" << h->GetNbinsX() << "," << h->GetNbinsY() << " instead of " << MAXX << "," << MAXZ; - return false; - } - - auto geo = Geometry::GetInstance(); - if (!geo) { - LOG(ERROR) << "Geometry needs to be initialized"; - return false; - } - - char relid[3] = {module, 1, 1}; - short absId; - for (char ix = 1; ix <= MAXX; ix++) { - relid[1] = ix; - for (char iz = 1; iz <= MAXZ; iz++) { - relid[2] = iz; - - if (geo->relToAbsNumbering(relid, absId)) { - mLGTimeCalib[absId] = h->GetBinContent(ix, iz); - } - } - } - return true; -} diff --git a/Detectors/PHOS/calib/src/PHOSBadMapCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSBadMapCalibDevice.cxx new file mode 100644 index 0000000000000..e611069684b7c --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSBadMapCalibDevice.cxx @@ -0,0 +1,380 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSCalibCollector.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" + +#include "FairLogger.h" +#include <fstream> // std::ifstream + +using namespace o2::phos; + +void PHOSCalibCollector::init(o2::framework::InitContext& ic) +{ + + mEvent = 0; + //Create output histograms + const int nChannels = 14336; //4 full modules + const int nMass = 150.; + float massMax = 0.3; + //First create all histograms then get direct pointers + mHistos.emplace_back("hReInvMassPerCell", "Real inv. mass per cell", nChannels, 0., nChannels, nMass, 0., massMax); + mHistos.emplace_back("hMiInvMassPerCell", "Mixed inv. mass per cell", nChannels, 0., nChannels, nMass, 0., massMax); + + int npt = 45; + float xpt[46] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.2, 1.4, 1.6, 1.8, 2., 2.2, 2.4, 2.6, 2.8, 3., 3.4, 3.8, 4.2, 4.6, 5., + 5.5, 6., 6.5, 7., 7.5, 8., 9., 10., 12., 14., 16., 18., 20., 24., 28., 32., 36., 40., 50., 55., 60.}; + float massbins[nMass + 1]; + for (int i = 0; i <= nMass; i++) { + massbins[i] = i * massMax / nMass; + } + mHistos.emplace_back("hReInvMassNonlin", "Real inv. mass vs Eclu", nMass, massbins, npt, xpt); + mHistos.emplace_back("hMiInvMassNonlin", "Mixed inv. mass vs Eclu", nMass, massbins, npt, xpt); + + const int nTime = 200; + float timeMin = -100.e-9; + float timeMax = 100.e-9; + mHistos.emplace_back("hTimeHGPerCell", "time per cell, high gain", nChannels, 0., nChannels, nTime, timeMin, timeMax); + mHistos.emplace_back("hTimeLGPerCell", "time per cell, low gain", nChannels, 0., nChannels, nTime, timeMin, timeMax); + float timebins[nTime + 1]; + for (int i = 0; i <= nTime; i++) { + timebins[i] = timeMin + i * timeMax / nTime; + } + mHistos.emplace_back("hTimeHGSlewing", "time vs E, high gain", nTime, timebins, npt, xpt); + mHistos.emplace_back("hTimeLGSlewing", "time vs E, low gain", nTime, timebins, npt, xpt); + + if (mMode != 2) { + TFile fcalib(mfilenameCalib.data(), "READ"); + if (fcalib.IsOpen()) { + CalibParams* cp = nullptr; + fcalib.GetObject("PHOSCalibration", cp); + mCalibParams.reset(cp); + } else { + LOG(ERROR) << "can not read calibration <PHOSCalibration> from file " << mfilenameCalib; + } + fcalib.Close(); + } + + //TODO: configure reading bad map from file + // this is special bad map for calibration + mBadMap.reset(new BadChannelsMap()); + + mGeom = Geometry::GetInstance("Run3"); +} + +void PHOSCalibCollector::run(o2::framework::ProcessingContext& pc) +{ + + //select possible options + switch (mMode) { + case 0: // Read new data + scanClusters(pc); + writeOutputs(); + break; + case 1: // Read and re-calibrate stored trees + readDigits(); + writeOutputs(); + break; + case 2: //Calculate calibration from stored histograms + calculateCalibrations(); + compareCalib(); + sendOutput(pc.outputs()); + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + break; + } +} + +void PHOSCalibCollector::scanClusters(o2::framework::ProcessingContext& pc) +{ + + // auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; // is this the timestamp of the current TF? + + auto clusters = pc.inputs().get<gsl::span<o2::phos::Cluster>>("clusters"); + auto cluTR = pc.inputs().get<gsl::span<o2::phos::TriggerRecord>>("cluTR"); + LOG(INFO) << "Processing TF with " << clusters.size() << " clusters and " << cluTR.size() << " TriggerRecords"; + + for (auto& tr : cluTR) { + + //Mark new event + //First goes new event marker + BC (16 bit), next word orbit (32 bit) + EventHeader h = {0}; + h.mMarker = 16383; + h.mBC = tr.getBCData().bc; + mDigits.push_back(h.mDataWord); + mDigits.push_back(tr.getBCData().orbit); + + int iclu = 0; + int firstCluInEvent = tr.getFirstEntry(); + int lastCluInEvent = firstCluInEvent + tr.getNumberOfObjects(); + + mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing + for (int i = firstCluInEvent; i < lastCluInEvent; i++) { + const Cluster& clu = clusters[i]; + + fillTimeMassHisto(clu); + bool isGood = checkCluster(clu); + + auto cluList = clu.getElementList(); + for (auto ce = cluList->begin(); ce != cluList->end(); ce++) { + short absId = ce->absId; + //Fill cells from cluster for next iterations + short adcCounts = ce->energy / mCalibParams->getGain(absId); + // Need to chale LG gain too to fit dynamic range + if (!ce->isHG) { + adcCounts /= mCalibParams->getHGLGRatio(absId); + } + CalibDigit d = {0}; + d.mAddress = absId; + d.mAdcAmp = adcCounts; + d.mHgLg = ce->isHG; + d.mBadChannel = isGood; + d.mCluster = (i - firstCluInEvent) % kMaxCluInEvent; + mDigits.push_back(d.mDataWord); + if (i - firstCluInEvent > kMaxCluInEvent) { + //Normally this is not critical as indexes are used "locally", i.e. are compared to previous/next + LOG(INFO) << "Too many clusters per event:" << i - firstCluInEvent << ", apply more strict selection; clusters with same indexes will appear"; + } + } + } + } +} + +void PHOSCalibCollector::readDigits() +{ + // open files from the list + // for each file read digits, calibrate them and form clusters + // fill inv mass and time (for check) histograms + std::ifstream ifs(mdigitsfilelist, std::ifstream::in); + if (!ifs.is_open()) { + LOG(ERROR) << "can not open file " << mdigitsfilelist; + return; + } + + std::string filename; + while (ifs >> filename) { + TFile f(filename.data(), "READ"); + if (!f.IsOpen()) { + LOG(ERROR) << "can not read file " << filename; + continue; + } + std::vector<uint32_t>* digits; + f.GetObject("Digits", digits); + + std::vector<uint32_t>::const_iterator digIt = digits->cbegin(); + std::vector<uint32_t>::const_iterator digEnd = digits->cend(); + Cluster clu; + bool isNextNewEvent; + mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing + while (nextCluster(digIt, digEnd, clu, isNextNewEvent)) { + + fillTimeMassHisto(clu); + if (isNextNewEvent) { + mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing + } + } + delete digits; + f.Close(); + } +} + +bool PHOSCalibCollector::nextCluster(std::vector<uint32_t>::const_iterator digitIt, std::vector<uint32_t>::const_iterator digitEnd, + Cluster& clu, bool& isNextNewEvent) +{ + //Scan digits belonging to cluster + // return true if cluster read + isNextNewEvent = false; + clu.reset(); + int cluIndex = -1; + while (digitIt != digitEnd) { + CalibDigit d = {*digitIt}; + if (d.mAddress == 16383) { //impossible address, marker of new event + if (clu.getMultiplicity() > 0) { //already read cluster: calculate its parameters; do not go into next event + isNextNewEvent = true; + break; + } + //If just started cluster, read new event. Two first words event header + EventHeader h = {*digitIt}; + mEvBC = h.mBC; //current event BC + digitIt++; + mEvOrbit = *digitIt; //current event orbit + digitIt++; + continue; + } + if (cluIndex == -1) { //start new cluster + cluIndex = d.mCluster; + } else { + if (cluIndex != d.mCluster) { //digit belongs to text cluster: all digits from current read + break; + } + } + short absId = d.mAddress; + float energy = d.mAdcAmp * mCalibParams->getGain(absId); + if (!d.mHgLg) { + energy *= mCalibParams->getHGLGRatio(absId); + } + clu.addDigit(absId, energy, 0., 0, 1.); + digitIt++; + } + if (digitIt == digitEnd && clu.getMultiplicity() == 0) { + return false; + } + //Evaluate clu parameters + clu.purify(); + clu.evalAll(); + return true; +} + +//Write +void PHOSCalibCollector::writeOutputs() +{ + //Write digits only in first scan + if (mMode == 0) { + TFile fout(mdigitsfilename.data(), "recreate"); + fout.WriteObjectAny(&mDigits, "std::vector<uint32_t", "Digits"); + fout.Close(); + } + + // in all cases write inv mass distributions + TFile fHistoOut(mhistosfilename.data(), "recreate"); + for (auto h : mHistos) { + h.Write(); + } + fHistoOut.Close(); +} + +void PHOSCalibCollector::fillTimeMassHisto(const Cluster& clu) +{ + // // Fill time distributions only for cells in cluster + // if (mMode == 0) { + // auto cluList = clu.getElementList(); + // for (auto ce = cluList->begin(); ce != cluList->end(); ce++) { + // short absId = ce->absId; + // if (ce->isHG) { + // if (ce->energy > mEminHGTime) { + // mHistos[kTimeHGPerCell].Fill(absId, ce->time); + // } + // mHistos[kTimeHGSlewing].Fill(ce->time, ce->energy); + // } else { + // if (ce->energy > mEminLGTime) { + // mHistos[kTimeLGPerCell].Fill(absId, ce->time); + // } + // mHistos[kTimeLGSlewing].Fill(ce->time, ce->energy); + // } + // } + // } + + //Real and Mixed inv mass distributions + // prepare TLorentsVector + float posX, posZ; + clu.getLocalPosition(posX, posZ); + TVector3 vec3; + mGeom->local2Global(clu.module(), posX, posZ, vec3); + vec3 -= mVertex; + float e = clu.getEnergy(); + short absId; + mGeom->relPosToAbsId(clu.module(), posX, posZ, absId); + + TLorentzVector v(vec3.X() * e, vec3.Y() * e, vec3.Z() * e, e); + // Fill calibration histograms for all cells, even bad, but partners in inv, mass should be good + bool isGood = checkCluster(clu); + for (short ip = mBuffer->size(); --ip;) { + const TLorentzVector& vp = mBuffer->getEntry(ip); + TLorentzVector sum = v + vp; + if (mBuffer->isCurrentEvent(ip)) { //same (real) event + if (isGood) { + mHistos[kReInvMassNonlin].Fill(e, sum.M()); + } + if (sum.Pt() > mPtMin) { + mHistos[kReInvMassPerCell].Fill(absId, sum.M()); + } + } else { //Mixed + if (isGood) { + mHistos[kMiInvMassNonlin].Fill(e, sum.M()); + } + if (sum.Pt() > mPtMin) { + mHistos[kMiInvMassPerCell].Fill(absId, sum.M()); + } + } + } + + //Add to list ot partners only if cluster is good + if (isGood) { + mBuffer->addEntry(v); + } +} + +bool PHOSCalibCollector::checkCluster(const Cluster& clu) +{ + //First check BadMap + float posX, posZ; + clu.getLocalPosition(posX, posZ); + short absId; + Geometry::relPosToAbsId(clu.module(), posX, posZ, absId); + if (!mBadMap->isChannelGood(absId)) { + return false; + } + + return (clu.getEnergy() > 0.3 && clu.getMultiplicity() > 1); +} + +void PHOSCalibCollector::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + //Write Filledhistograms and estimate mean number of entries + switch (mMode) { + case 0: // Read new data + writeOutputs(); + break; + case 1: // Read and re-calibrate stored trees + writeOutputs(); + break; + case 2: //Calculate calibration from stored histograms + // do nothing, already sent + break; + } +} + +void PHOSCalibCollector::sendOutput(DataAllocator& output) +{ + // If calibration OK, send calibration to CCDB + // and difference to last iteration to QC + //.... +} + +o2::framework::DataProcessorSpec o2::phos::getPHOSCalibCollectorDeviceSpec(int mode) +{ + + std::vector<OutputSpec> outputs; + if (mode == 2) { //fit of inv masses: gain calculation: send to CCDB and QC + outputs.emplace_back(o2::header::gDataOriginPHS, "COLLECTEDINFO", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginPHS, "ENTRIESCH", 0, Lifetime::Timeframe); + } + + std::vector<InputSpec> inputs; + if (mode == 0) { + inputs.emplace_back("clusters", "PHS", "CLUSTERS"); + inputs.emplace_back("cluTR", "PHS", "CLUSTERTRIGRECS"); + } + + return DataProcessorSpec{ + "calib-phoscalib-collector", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<PHOSCalibCollector>(mode)}, + Options{ + {"inputFileList", VariantType::String, "./calibDigits.txt", {"File with list of digit files to be scanned"}}, + {"outputDigitDir", VariantType::String, "./", {"directory to write filtered Digits"}}, + {"outputHistoDir", VariantType::String, "./", {"directory to write inv. mass histograms"}}, + {"forceCCDBUpdate", VariantType::Bool, false, {"force updating CCDB bypassing quality check"}}}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSCalibLinkDef.h b/Detectors/PHOS/calib/src/PHOSCalibLinkDef.h deleted file mode 100644 index cbf026280f14b..0000000000000 --- a/Detectors/PHOS/calib/src/PHOSCalibLinkDef.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::phos::CalibDB+; -#pragma link C++ class o2::phos::BadChannelMap+; -#pragma link C++ class o2::TObjectWrapper<o2::phos::BadChannelMap>+; -#pragma link C++ class o2::phos::CalibParams+; -#pragma link C++ class o2::TObjectWrapper<o2::phos::CalibParams>+; - -#endif diff --git a/Detectors/PHOS/calib/src/PHOSCalibWorkflowLinkDef.h b/Detectors/PHOS/calib/src/PHOSCalibWorkflowLinkDef.h new file mode 100644 index 0000000000000..db66c6bb39c57 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSCalibWorkflowLinkDef.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::phos::PHOSPedestalCalibDevice + ; +#pragma link C++ class o2::phos::PHOSHGLGRatioCalibDevice + ; +#pragma link C++ class o2::phos::ETCalibHistos + ; +#pragma link C++ class o2::phos::PHOSEnergySlot + ; +#pragma link C++ class o2::phos::PHOSEnergyCalibrator + ; +#pragma link C++ class o2::phos::PHOSEnergyCalibDevice + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::phos::PHOSEnergySlot> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::phos::Cluster, o2::phos::PHOSEnergySlot> + ; +#pragma link C++ class o2::phos::TurnOnHistos + ; +#pragma link C++ class o2::phos::PHOSTurnonSlot + ; +#pragma link C++ class o2::phos::PHOSTurnonCalibrator + ; +#pragma link C++ class o2::phos::PHOSTurnonCalibDevice + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::phos::PHOSTurnonSlot> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::phos::Cluster, o2::phos::PHOSTurnonSlot> + ; +#pragma link C++ class o2::phos::PHOSRunbyrunSlot + ; +#pragma link C++ class o2::phos::PHOSRunbyrunCalibrator + ; +#pragma link C++ class o2::phos::PHOSRunbyrunCalibDevice + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::phos::PHOSRunbyrunSlot> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::phos::Cluster, o2::phos::PHOSRunbyrunSlot> + ; + +#endif diff --git a/Detectors/PHOS/calib/src/PHOSEnergyCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSEnergyCalibDevice.cxx new file mode 100644 index 0000000000000..a9608c6086323 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSEnergyCalibDevice.cxx @@ -0,0 +1,110 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSEnergyCalibDevice.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" + +#include "FairLogger.h" +#include <string> + +using namespace o2::phos; + +void PHOSEnergyCalibDevice::init(o2::framework::InitContext& ic) +{ + mCalibrator.reset(new PHOSEnergyCalibrator()); + + //TODO!!! read configuration + // mPtMin,mEminHGTime,mEminLGTime + + //Configure output Digits file + mCalibrator->setOutDigitsFile(mdigitsfilename); + + //read calibration and bad map objects and send them to calibrator + if (!mBadMap) { + if (mUseCCDB) { + LOG(INFO) << "Retrieving BadMap from CCDB"; + o2::ccdb::CcdbApi ccdb; + ccdb.init(mCCDBPath); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> metadata; + mBadMap.reset(ccdb.retrieveFromTFileAny<BadChannelsMap>("PHS/Calib/BadChannels", metadata, mRunStartTime)); + + if (!mBadMap) { //was not read from CCDB, but expected + LOG(FATAL) << "Can not read BadMap from CCDB, you may use --not-use-ccdb option to create default bad map"; + } + //same for calibration + + mCalibParams.reset(ccdb.retrieveFromTFileAny<CalibParams>("PHS/Calib/CalibParams", metadata, mRunStartTime)); + if (!mCalibParams) { //was not read from CCDB, but expected + LOG(FATAL) << "Can not read current CalibParams from ccdb"; + } + } else { + LOG(INFO) << "Do not use CCDB, create default BadMap and calibration"; + mBadMap.reset(new BadChannelsMap(1)); + mCalibParams.reset(new CalibParams(1)); + } + } + mCalibrator->setBadMap(*mBadMap); + mCalibrator->setCalibration(*mCalibParams); + mCalibrator->setCuts(mPtMin, mEminHGTime, mEminLGTime); + + //Create geometry instance (inclusing reading mis-alignement) + //instance will be pick up by Calibrator + Geometry::GetInstance("Run3"); +} + +void PHOSEnergyCalibDevice::run(o2::framework::ProcessingContext& pc) +{ + //TODO! extract vertex information and send to Calibrator + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("clusters").header)->startTime; // is this the timestamp of the current TF? + const gsl::span<const Cluster>& clusters = pc.inputs().get<gsl::span<Cluster>>("clusters"); + const gsl::span<const CluElement>& cluelements = pc.inputs().get<gsl::span<CluElement>>("cluelements"); + const gsl::span<const TriggerRecord>& cluTR = pc.inputs().get<gsl::span<TriggerRecord>>("clusterTriggerRecords"); + + LOG(INFO) << "[PHOSEnergyCalibDevice - run] Received " << clusters.size() << " clusters and " << clusters.size() << " clusters, running calibration"; + + mCalibrator->process(tfcounter, clusters, cluelements, cluTR); +} + +void PHOSEnergyCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + mCalibrator->endOfStream(); +} + +o2::framework::DataProcessorSpec o2::phos::getPHOSEnergyCalibDeviceSpec(bool useCCDB, std::string path, std::string digitspath) +{ + + std::vector<InputSpec> inputs; + inputs.emplace_back("clusters", o2::header::gDataOriginPHS, "CLUSTERS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("cluelements", o2::header::gDataOriginPHS, "CLUELEMENTS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("clusterTriggerRecords", o2::header::gDataOriginPHS, "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe); + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back( + ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "PHOS_EnCalib"}); + outputs.emplace_back( + ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "PHOS_EnCalib"}); + //stream for QC data + //outputs.emplace_back("PHS", "TRIGGERQC", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"PHOSEnergyCalibDevice", + inputs, + outputs, + o2::framework::adaptFromTask<PHOSEnergyCalibDevice>(useCCDB, path, digitspath), + o2::framework::Options{}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSEnergyCalibrator.cxx b/Detectors/PHOS/calib/src/PHOSEnergyCalibrator.cxx new file mode 100644 index 0000000000000..9cc4443171779 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSEnergyCalibrator.cxx @@ -0,0 +1,240 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSEnergyCalibrator.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" + +#include "FairLogger.h" +#include <fstream> // std::ifstream + +using namespace o2::phos; + +PHOSEnergySlot::PHOSEnergySlot() +{ + mHistos.reset(); + mBuffer.reset(new RingBuffer()); + mGeom = Geometry::GetInstance(); +} + +void PHOSEnergySlot::print() const +{ + LOG(INFO) << "Collected " << mDigits.size() << " CalibDigits"; +} + +void PHOSEnergySlot::fill(const gsl::span<const Cluster>& clusters, const gsl::span<const CluElement>& cluelements, const gsl::span<const TriggerRecord>& cluTR) +{ + //Scan current list of clusters + //Fill time, non-linearity and mgg histograms + //Fill list of re-calibraiable digits + for (auto& tr : cluTR) { + + //Mark new event + //First goes new event marker + BC (16 bit), next word orbit (32 bit) + EventHeader h = {0}; + h.mMarker = 16383; + h.mBC = tr.getBCData().bc; + mDigits.push_back(h.mDataWord); + mDigits.push_back(tr.getBCData().orbit); + + int iclu = 0; + int firstCluInEvent = tr.getFirstEntry(); + int lastCluInEvent = firstCluInEvent + tr.getNumberOfObjects(); + + mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing + for (int i = firstCluInEvent; i < lastCluInEvent; i++) { + const Cluster& clu = clusters[i]; + + fillTimeMassHisto(clu, cluelements); + // bool isGood = checkCluster(clu); + + uint32_t firstCE = clu.getFirstCluEl(); + uint32_t lastCE = clu.getLastCluEl(); + for (int idig = firstCE; idig < lastCE; idig++) { + const CluElement& ce = cluelements[idig]; + short absId = ce.absId; + //Fill cells from cluster for next iterations + short adcCounts = ce.energy / mCalibParams->getGain(absId); + // Need to chale LG gain too to fit dynamic range + if (!ce.isHG) { + adcCounts /= mCalibParams->getHGLGRatio(absId); + } + CalibDigit d = {0}; + d.mAddress = absId; + d.mAdcAmp = adcCounts; + d.mHgLg = ce.isHG; + d.mCluster = (i - firstCluInEvent) % kMaxCluInEvent; + mDigits.push_back(d.mDataWord); + if (i - firstCluInEvent > kMaxCluInEvent) { + //Normally this is not critical as indexes are used "locally", i.e. are compared to previous/next + LOG(INFO) << "Too many clusters per event:" << i - firstCluInEvent << ", apply more strict selection; clusters with same indexes will appear"; + } + } + } + } +} +void PHOSEnergySlot::clear() +{ + mHistos.reset(); + mDigits.clear(); +} + +void PHOSEnergySlot::fillTimeMassHisto(const Cluster& clu, const gsl::span<const CluElement>& cluelements) +{ + // Fill time distributions only for cells in cluster + uint32_t firstCE = clu.getFirstCluEl(); + uint32_t lastCE = clu.getLastCluEl(); + + for (int idig = firstCE; idig < lastCE; idig++) { + const CluElement& ce = cluelements[idig]; + short absId = ce.absId; + if (ce.isHG) { + if (ce.energy > mEminHGTime) { + mHistos.fill(ETCalibHistos::kTimeHGPerCell, absId, ce.time); + } + mHistos.fill(ETCalibHistos::kTimeHGSlewing, ce.time, ce.energy); + } else { + if (ce.energy > mEminLGTime) { + mHistos.fill(ETCalibHistos::kTimeLGPerCell, absId, ce.time); + } + mHistos.fill(ETCalibHistos::kTimeLGSlewing, ce.time, ce.energy); + } + } + + //Real and Mixed inv mass distributions + // prepare TLorentsVector + float posX, posZ; + clu.getLocalPosition(posX, posZ); + TVector3 vec3; + mGeom->local2Global(clu.module(), posX, posZ, vec3); + vec3 -= mVertex; + float e = clu.getEnergy(); + short absId; + mGeom->relPosToAbsId(clu.module(), posX, posZ, absId); + + vec3 *= 1. / vec3.Mag(); + TLorentzVector v(vec3.X() * e, vec3.Y() * e, vec3.Z() * e, e); + // Fill calibration histograms for all cells, even bad, but partners in inv, mass should be good + bool isGood = checkCluster(clu); + for (short ip = mBuffer->size(); ip--;) { + const TLorentzVector& vp = mBuffer->getEntry(ip); + TLorentzVector sum = v + vp; + if (mBuffer->isCurrentEvent(ip)) { //same (real) event + if (isGood) { + mHistos.fill(ETCalibHistos::kReInvMassNonlin, e, sum.M()); + } + if (sum.Pt() > mPtMin) { + mHistos.fill(ETCalibHistos::kReInvMassPerCell, absId, sum.M()); + } + } else { //Mixed + if (isGood) { + mHistos.fill(ETCalibHistos::kMiInvMassNonlin, e, sum.M()); + } + if (sum.Pt() > mPtMin) { + mHistos.fill(ETCalibHistos::kMiInvMassPerCell, absId, sum.M()); + } + } + } + + //Add to list ot partners only if cluster is good + if (isGood) { + mBuffer->addEntry(v); + } +} + +bool PHOSEnergySlot::checkCluster(const Cluster& clu) +{ + //First check BadMap + float posX, posZ; + clu.getLocalPosition(posX, posZ); + short absId; + Geometry::relPosToAbsId(clu.module(), posX, posZ, absId); + if (!mBadMap->isChannelGood(absId)) { + return false; + } + + return (clu.getEnergy() > 0.3 && clu.getMultiplicity() > 1); +} + +//================================================== + +using es = o2::phos::PHOSEnergySlot; +using Slot = o2::calibration::TimeSlot<o2::phos::PHOSEnergySlot>; +PHOSEnergyCalibrator::PHOSEnergyCalibrator() +{ + // create final histos + mHistos.reset(); +} +PHOSEnergySlot::PHOSEnergySlot(const PHOSEnergySlot& other) +{ + mRunStartTime = other.mRunStartTime; + mBuffer.reset(new RingBuffer()); + mCalibParams.reset(new CalibParams(*(other.mCalibParams))); + mBadMap.reset(new BadChannelsMap(*(other.mBadMap))); + mEvBC = other.mEvBC; + mEvOrbit = other.mEvOrbit; + mEvent = 0; + mPtMin = other.mPtMin; + mEminHGTime = other.mEminHGTime; + mEminLGTime = other.mEminLGTime; + mDigits.clear(); + mHistos.reset(); +} + +void PHOSEnergyCalibrator::finalizeSlot(Slot& slot) +{ + + // Extract results for the single slot + es* c = slot.getContainer(); + LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + //Add histos + mHistos.merge(c->getCollectedHistos()); + //Add collected Digits + auto tmpD = c->getCollectedDigits(); + //Add to list or write to file directly? + if (!mFout) { //not open yet? + LOG(INFO) << "Writing CalibDigits to file " << mdigitsfilename.data(); + mFout.reset(TFile::Open(mdigitsfilename.data(), "recreate")); + } + int nbites = mFout->WriteObjectAny(&tmpD, "std::vector<uint32_t>", Form("Digits%d", mChank++)); + LOG(INFO) << "Writing " << tmpD.size() << " CalibDigits, wrote " << nbites << "bytes"; + c->clear(); +} + +Slot& PHOSEnergyCalibrator::emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<es>()); + slot.getContainer()->setBadMap(*mBadMap); + slot.getContainer()->setCalibration(*mCalibParams); + slot.getContainer()->setCuts(mPtMin, mEminHGTime, mEminLGTime); + return slot; +} + +bool PHOSEnergyCalibrator::process(uint64_t tf, const gsl::span<const Cluster>& clusters, + const gsl::span<const CluElement>& cluelements, + const gsl::span<const TriggerRecord>& cluTR) +{ + // process current TF + //First receive bad map and calibration if not received yet + + auto& slotTF = getSlotForTF(tf); + slotTF.getContainer()->setRunStartTime(tf); + slotTF.getContainer()->fill(clusters, cluelements, cluTR); + return true; +} + +void PHOSEnergyCalibrator::endOfStream() +{ +} diff --git a/Detectors/PHOS/calib/src/PHOSHGLGRatioCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSHGLGRatioCalibDevice.cxx new file mode 100644 index 0000000000000..ee36a2a44a023 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSHGLGRatioCalibDevice.cxx @@ -0,0 +1,217 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/Cell.h" +#include "PHOSBase/Mapping.h" +#include <TFile.h> +#include <TF1.h> + +using namespace o2::phos; + +void PHOSHGLGRatioCalibDevice::init(o2::framework::InitContext& ic) +{ + + //Create histograms for mean and RMS + short n = o2::phos::Mapping::NCHANNELS - 1792; + mhRatio.reset(new TH2F("HGLGRatio", "HGLGRatio", n, 1792.5, n + 1792.5, 100, 10., 20.)); + mCalibParams.reset(new CalibParams()); +} + +void PHOSHGLGRatioCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + + // scan Cells stream, collect HG/LG pairs + if (mRunStartTime == 0) { + mRunStartTime = o2::header::get<o2::framework::DataProcessingHeader*>(ctx.inputs().get("cellTriggerRecords").header)->startTime; + } + + auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells"); + LOG(DEBUG) << "[PHOSHGLGRatioCalibDevice - run] Received " << cells.size() << " cells, running calibration ..."; + auto cellsTR = ctx.inputs().get<gsl::span<o2::phos::TriggerRecord>>("cellTriggerRecords"); + for (const auto& tr : cellsTR) { + int firstCellInEvent = tr.getFirstEntry(); + int lastCellInEvent = firstCellInEvent + tr.getNumberOfObjects(); + mMapPairs.clear(); + + for (int i = firstCellInEvent; i < lastCellInEvent; i++) { + const Cell c = cells[i]; + + auto search = mMapPairs.find(c.getAbsId()); + if (search != mMapPairs.end()) { //exist + if (c.getHighGain()) { + search->second.mHGAmp = c.getEnergy(); + } + if (c.getLowGain()) { + search->second.mLGAmp = c.getEnergy(); + } + } else { + PairAmp pa = {0}; + if (c.getHighGain()) { + pa.mHGAmp = c.getEnergy(); + } + if (c.getLowGain()) { + pa.mLGAmp = c.getEnergy(); + } + mMapPairs.insert({c.getAbsId(), pa}); + } + } + fillRatios(); + } +} +void PHOSHGLGRatioCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + LOG(INFO) << "[PHOSHGLGRatioCalibDevice - endOfStream]"; + //calculate stuff here + calculateRatios(); + checkRatios(); + sendOutput(ec.outputs()); +} + +void PHOSHGLGRatioCalibDevice::fillRatios() +{ + // scan collected map and fill ratio histogram if both channels are filled + for (auto& it : mMapPairs) { + if (it.second.mHGAmp > 0 && it.second.mLGAmp > mMinLG) { + mhRatio->Fill(it.first, float(it.second.mHGAmp / it.second.mLGAmp)); + } + } + mMapPairs.clear(); //to avoid double counting +} + +void PHOSHGLGRatioCalibDevice::calculateRatios() +{ + // Calculate mean of the ratio + int n = o2::phos::Mapping::NCHANNELS; + if (mhRatio->Integral() > 2 * minimalStatistics * n) { //average per channel + + TF1* fitFunc = new TF1("fitFunc", "gaus", 0., 4000.); + fitFunc->SetParameters(1., 200., 60.); + fitFunc->SetParLimits(1, 10., 2000.); + for (int i = 1; i <= n; i++) { + TH1D* tmp = mhRatio->ProjectionY(Form("channel%d", i), i, i); + fitFunc->SetParameters(tmp->Integral(), tmp->GetMean(), tmp->GetRMS()); + if (tmp->Integral() < minimalStatistics) { + tmp->Delete(); + continue; + } + tmp->Fit(fitFunc, "QL0", "", 0., 20.); + float a = fitFunc->GetParameter(1); + mCalibParams->setHGLGRatio(i, a); //absId starts from 0 + tmp->Delete(); + } + } +} +void PHOSHGLGRatioCalibDevice::checkRatios() +{ + //Compare ratios to current ones stored in CCDB + if (!mUseCCDB) { + mUpdateCCDB = true; + return; + } + LOG(INFO) << "Retrieving current HG/LG ratio from CCDB"; + //Read current padestals for comarison + o2::ccdb::CcdbApi ccdb; + ccdb.init(mCCDBPath); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> metadata; + auto* currentCalibParams = ccdb.retrieveFromTFileAny<CalibParams>("PHS/Calib/CalibParams", metadata, mRunStartTime); + + if (!currentCalibParams) { //was not read from CCDB, but expected + mUpdateCCDB = true; + LOG(ERROR) << "Can not read current CalibParams from ccdb"; + return; + } + + LOG(INFO) << "Got current calibration from CCDB"; + + //Compare to current + int nChanged = 0; + for (short i = o2::phos::Mapping::NCHANNELS; i > 1792; i--) { + short dp = 2; + if (currentCalibParams->getHGLGRatio(i) > 0) { + dp = mCalibParams->getHGLGRatio(i) / currentCalibParams->getHGLGRatio(i); + } + mRatioDiff[i] = dp; + if (abs(dp - 1.) > 0.1) { //not a fluctuation + nChanged++; + } + //Copy other stuff from the current CalibParams to new one + mCalibParams->setGain(i, currentCalibParams->getGain(i)); + mCalibParams->setHGTimeCalib(i, currentCalibParams->getHGTimeCalib(i)); + mCalibParams->setLGTimeCalib(i, currentCalibParams->getLGTimeCalib(i)); + } + LOG(INFO) << nChanged << "channels changed more that 1 ADC channel"; + if (nChanged > kMinorChange) { //serious change, do not update CCDB automatically, use "force" option to overwrite + LOG(ERROR) << "too many channels changed: " << nChanged << " (threshold " << kMinorChange << ")"; + if (!mForceUpdate) { + LOG(ERROR) << "you may use --forceupdate option to force updating ccdb"; + } + mUpdateCCDB = false; + } else { + mUpdateCCDB = true; + } +} + +void PHOSHGLGRatioCalibDevice::sendOutput(DataAllocator& output) +{ + + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + if (mUpdateCCDB || mForceUpdate) { + // prepare all info to be sent to CCDB + auto flName = o2::ccdb::CcdbApi::generateFileName("CalibParams"); + std::map<std::string, std::string> md; + o2::ccdb::CcdbObjectInfo info("PHS/Calib/CalibParams", "CalibParams", flName, md, mRunStartTime, 99999999999999); + info.setMetaData(md); + auto image = o2::ccdb::CcdbApi::createObjectImage(mCalibParams.get(), &info); + + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_HGLGratio", subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "PHOS_HGLGratio", subSpec}, info); + } + //Anyway send change to QC + LOG(INFO) << "[PHOSHGLGRatioCalibDevice - sendOutput] Sending QC "; + output.snapshot(o2::framework::Output{"PHS", "CALIBDIFF", 0, o2::framework::Lifetime::Timeframe}, mRatioDiff); +} + +DataProcessorSpec o2::phos::getHGLGRatioCalibSpec(bool useCCDB, bool forceUpdate, std::string path) +{ + + std::vector<InputSpec> inputs; + inputs.emplace_back("cells", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLS"}, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("cellTriggerRecords", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLTRIGREC"}, o2::framework::Lifetime::Timeframe); + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginPHS, "CALIBDIFF", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "PHOS_HGLGratio"}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "PHOS_HGLGratio"}); + return o2::framework::DataProcessorSpec{"HGLGRatioCalibSpec", + inputs, + outputs, + o2::framework::adaptFromTask<PHOSHGLGRatioCalibDevice>(useCCDB, forceUpdate, path), + o2::framework::Options{}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSPedestalCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSPedestalCalibDevice.cxx new file mode 100644 index 0000000000000..10eaec1fed4fb --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSPedestalCalibDevice.cxx @@ -0,0 +1,191 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSPedestalCalibDevice.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/Cell.h" +#include "PHOSBase/Mapping.h" +#include <TFile.h> + +using namespace o2::phos; + +void PHOSPedestalCalibDevice::init(o2::framework::InitContext& ic) +{ + + //Create histograms for mean and RMS + short n = o2::phos::Mapping::NCHANNELS - 1792; + mMeanHG.reset(new TH2F("MeanHighGain", "MeanHighGain", n, 1792.5, n + 1792.5, 100, 0., 100.)); + mMeanLG.reset(new TH2F("MeanLowGain", "MeanLowGain", n, 1792.5, n + 1792.5, 100, 0., 100.)); + mRMSHG.reset(new TH2F("RMSHighGain", "RMSHighGain", n, 1792.5, n + 1792.5, 100, 0., 10.)); + mRMSLG.reset(new TH2F("RMSLowGain", "RMSLowGain", n, 1792.5, n + 1792.5, 100, 0., 10.)); +} + +void PHOSPedestalCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + // scan Cells stream, collect mean and RMS then calculateaverage and post + if (mRunStartTime == 0) { + mRunStartTime = o2::header::get<o2::framework::DataProcessingHeader*>(ctx.inputs().get("cellTriggerRecords").header)->startTime; + } + + auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells"); + LOG(DEBUG) << "[PHOSPedestalCalibDevice - run] Received " << cells.size() << " cells, running calibration ..."; + auto cellsTR = ctx.inputs().get<gsl::span<o2::phos::TriggerRecord>>("cellTriggerRecords"); + for (const auto& tr : cellsTR) { + int firstCellInEvent = tr.getFirstEntry(); + int lastCellInEvent = firstCellInEvent + tr.getNumberOfObjects(); + for (int i = firstCellInEvent; i < lastCellInEvent; i++) { + const Cell c = cells[i]; + if (c.getHighGain()) { + mMeanHG->Fill(c.getAbsId(), c.getEnergy()); + mRMSHG->Fill(c.getAbsId(), 1.e+7 * c.getTime()); + } else { + mMeanLG->Fill(c.getAbsId(), c.getEnergy()); + mRMSLG->Fill(c.getAbsId(), 1.e+7 * c.getTime()); + } + } + } +} + +void PHOSPedestalCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + LOG(INFO) << "[PHOSPedestalCalibDevice - endOfStream]"; + //calculate stuff here + calculatePedestals(); + checkPedestals(); + sendOutput(ec.outputs()); +} + +void PHOSPedestalCalibDevice::sendOutput(DataAllocator& output) +{ + + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + if (mUpdateCCDB || mForceUpdate) { + // prepare all info to be sent to CCDB + auto flName = o2::ccdb::CcdbApi::generateFileName("Pedestals"); + std::map<std::string, std::string> md; + o2::ccdb::CcdbObjectInfo info("PHS/Calib/Pedestals", "Pedestals", flName, md, mRunStartTime, 99999999999999); + info.setMetaData(md); + auto image = o2::ccdb::CcdbApi::createObjectImage(mPedestals.get(), &info); + + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_Pedestal", subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "PHOS_Pedestal", subSpec}, info); + } + //Anyway send change to QC + LOG(INFO) << "[PHOSPedestalCalibDevice - run] Sending QC "; + output.snapshot(o2::framework::Output{"PHS", "CALIBDIFF", 0, o2::framework::Lifetime::Timeframe}, mPedDiff); +} + +void PHOSPedestalCalibDevice::calculatePedestals() +{ + mPedestals.reset(new Pedestals()); + + //Calculate mean of pedestal distributions + for (unsigned short i = mMeanHG->GetNbinsX(); i > 0; i--) { + TH1D* pr = mMeanHG->ProjectionY(Form("proj%d", i), i, i); + float a = pr->GetMean(); + short cellId = static_cast<short>(mMeanHG->GetXaxis()->GetBinCenter(i)); + mPedestals->setHGPedestal(cellId, std::min(255, int(a))); + pr->Delete(); + pr = mMeanLG->ProjectionY(Form("projLG%d", i), i, i); + a = pr->GetMean(); + mPedestals->setLGPedestal(cellId, std::min(255, int(a))); + pr->Delete(); + pr = mRMSHG->ProjectionY(Form("projRMS%d", i), i, i); + a = pr->GetMean(); + mPedestals->setHGRMS(cellId, a); + pr->Delete(); + pr = mRMSLG->ProjectionY(Form("projRMSLG%d", i), i, i); + a = pr->GetMean(); + mPedestals->setLGRMS(cellId, a); + pr->Delete(); + } +} + +void PHOSPedestalCalibDevice::checkPedestals() +{ + if (!mUseCCDB) { + mUpdateCCDB = true; + return; + } + LOG(INFO) << "Retrieving current Pedestals from CCDB"; + //Read current padestals for comarison + o2::ccdb::CcdbApi ccdb; + ccdb.init(mCCDBPath); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> metadata; + auto* currentPedestals = ccdb.retrieveFromTFileAny<Pedestals>("PHS/Calib/Pedestals", metadata, mRunStartTime); + + if (!currentPedestals) { //was not read from CCDB, but expected + mUpdateCCDB = true; + return; + } + + LOG(INFO) << "Got current Pedestals from CCDB"; + + //Compare to current + int nChanged = 0; + for (short i = o2::phos::Mapping::NCHANNELS; i > 1792; i--) { + short dp = mPedestals->getHGPedestal(i) - currentPedestals->getHGPedestal(i); + mPedDiff[i] = dp; + if (abs(dp) > 1) { //not a fluctuation + nChanged++; + } + dp = mPedestals->getLGPedestal(i) - currentPedestals->getLGPedestal(i); + mPedDiff[i + o2::phos::Mapping::NCHANNELS] = dp; + if (abs(dp) > 1) { //not a fluctuation + nChanged++; + } + } + LOG(INFO) << nChanged << " channels changed more that 1 ADC channel"; + if (nChanged > kMinorChange) { //serious change, do not update CCDB automatically, use "force" option to overwrite + LOG(ERROR) << "too many channels changed: " << nChanged << " (threshold not more than " << kMinorChange << ")"; + if (!mForceUpdate) { + LOG(ERROR) << "you may use --forceupdate option to force updating ccdb"; + } + mUpdateCCDB = false; + } else { + mUpdateCCDB = true; + } +} + +o2::framework::DataProcessorSpec o2::phos::getPedestalCalibSpec(bool useCCDB, bool forceUpdate, std::string path) +{ + + std::vector<InputSpec> inputs; + inputs.emplace_back("cells", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLS"}, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("cellTriggerRecords", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLTRIGREC"}, o2::framework::Lifetime::Timeframe); + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginPHS, "CALIBDIFF", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "PHOS_Pedestal"}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "PHOS_Pedestal"}); + return o2::framework::DataProcessorSpec{"PedestalCalibSpec", + inputs, + outputs, + o2::framework::adaptFromTask<PHOSPedestalCalibDevice>(useCCDB, forceUpdate, path), + o2::framework::Options{}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSRunbyrunCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSRunbyrunCalibDevice.cxx new file mode 100644 index 0000000000000..6d0caba4f2913 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSRunbyrunCalibDevice.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h" +#include "Framework/ConfigParamRegistry.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" + +#include "FairLogger.h" + +using namespace o2::phos; + +void PHOSRunbyrunCalibDevice::init(o2::framework::InitContext& ic) +{ + // int slotL = ic.options().get<int>("tf-per-slot"); + // int delay = ic.options().get<int>("max-delay"); + mCalibrator.reset(new PHOSRunbyrunCalibrator()); + + // mCalibrator->setSlotLength(slotL); + // mCalibrator->setMaxSlotsDelay(delay); + mCalibrator->setUpdateAtTheEndOfRunOnly(); +} +void PHOSRunbyrunCalibDevice::run(o2::framework::ProcessingContext& pc) +{ + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("clusters").header)->startTime; // is this the timestamp of the current TF? + auto clusters = pc.inputs().get<gsl::span<Cluster>>("clusters"); + auto cluTR = pc.inputs().get<gsl::span<TriggerRecord>>("cluTR"); + LOG(INFO) << "Processing TF with " << clusters.size() << " clusters and " << cluTR.size() << " TriggerRecords"; + mCalibrator->process(tfcounter, clusters, cluTR); +} + +void PHOSRunbyrunCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + mCalibrator->endOfStream(); + mRunByRun = mCalibrator->getCalibration(); + if (checkFitResult()) { + LOG(INFO) << "End of stream reached, sending output to CCDB"; + // prepare all info to be sent to CCDB + auto flName = o2::ccdb::CcdbApi::generateFileName("Runbyrun"); + std::map<std::string, std::string> md; + o2::ccdb::CcdbObjectInfo info("PHS/Calib/Runbyrun", "Runbyrun", flName, md, mRunStartTime, INFINITE_TF); + info.setMetaData(md); + auto image = o2::ccdb::CcdbApi::createObjectImage(&mRunByRun, &info); + + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + ec.outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_Runbyrun", subSpec}, *image.get()); + ec.outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "PHOS_Runbyrun", subSpec}, info); + } else { + LOG(ERROR) << "Incorrect fit results: " << mRunByRun[0] << "+-" << mRunByRun[1] << ", " + << mRunByRun[2] << "+-" << mRunByRun[3] << ", " + << mRunByRun[4] << "+-" << mRunByRun[5] << ", " + << mRunByRun[6] << "+-" << mRunByRun[7]; + } + //TODO! Send mRunByRun for QC and trending plots + // + + //Get ready for next run + mCalibrator->initOutput(); // reset the outputs once they are already sent +} +bool PHOSRunbyrunCalibDevice::checkFitResult() +{ + bool res = true; + const float massmin = 0.125; + const float massmax = 0.155; + for (int mod = 0; mod < 4; mod++) { + res &= mRunByRun[2 * mod] < massmax && mRunByRun[2 * mod] > massmin; + } + return res; +} + +o2::framework::DataProcessorSpec o2::phos::getPHOSRunbyrunCalibDeviceSpec(bool useCCDB, std::string path) +{ + + std::vector<OutputSpec> outputs; + outputs.emplace_back("PHS", "RUNBYRUNHISTOS", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_Runbyrun"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "PHOS_Runbyrun"}); + + std::vector<InputSpec> inputs; + inputs.emplace_back("clusters", "PHS", "CLUSTERS"); + inputs.emplace_back("cluTR", "PHS", "CLUSTERTRIGREC"); + + return DataProcessorSpec{ + "calib-phos-runbyrun", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<PHOSRunbyrunCalibDevice>()}, + Options{}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSRunbyrunCalibrator.cxx b/Detectors/PHOS/calib/src/PHOSRunbyrunCalibrator.cxx new file mode 100644 index 0000000000000..a22977a1165a4 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSRunbyrunCalibrator.cxx @@ -0,0 +1,286 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSRunbyrunCalibrator.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "Framework/ControlService.h" +#include "TFile.h" +#include "TF1.h" + +#include "FairLogger.h" + +using namespace o2::phos; + +using Slot = o2::calibration::TimeSlot<o2::phos::PHOSRunbyrunSlot>; + +PHOSRunbyrunSlot::PHOSRunbyrunSlot(bool useCCDB, std::string path) : mUseCCDB(useCCDB), mCCDBPath(path) +{ + const int nMass = 150.; + const float massMax = 0.3; + for (int mod = 0; mod < 4; mod++) { + mReMi[2 * mod] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nMass, 0., massMax, "mgg")); + mReMi[2 * mod + 1] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nMass, 0., massMax, "mgg")); + } + mBuffer.reset(new RingBuffer()); +} +PHOSRunbyrunSlot::PHOSRunbyrunSlot(const PHOSRunbyrunSlot& other) +{ + mUseCCDB = other.mUseCCDB; + mRunStartTime = other.mUseCCDB; + mCCDBPath = other.mCCDBPath; + const int nMass = 150.; + const float massMax = 0.3; + for (int mod = 0; mod < 4; mod++) { + mReMi[2 * mod] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nMass, 0., massMax, "mgg")); + mReMi[2 * mod + 1] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(nMass, 0., massMax, "mgg")); + } + mBuffer.reset(new RingBuffer()); + mBadMap = nullptr; +} + +void PHOSRunbyrunSlot::print() const +{ + // to print number of entries in pi0 region + double s[4]; + for (int mod = 0; mod < 4; mod++) { + s[mod] = boost::histogram::algorithm::sum(mReMi[2 * mod]); + } + LOG(INFO) << "Total number of entries in pi0 region: " << s[0] << "," << s[1] << "," << s[2] << "," << s[3]; +} + +void PHOSRunbyrunSlot::fill(const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& trs) +{ + if (!mBadMap) { + if (mUseCCDB) { + LOG(INFO) << "Retrieving BadMap from CCDB"; + o2::ccdb::CcdbApi ccdb; + ccdb.init(mCCDBPath); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> metadata; + mBadMap.reset(ccdb.retrieveFromTFileAny<BadChannelsMap>("PHS/Calib/BadChannels", metadata, mRunStartTime)); + + if (!mBadMap) { //was not read from CCDB, but expected + LOG(FATAL) << "Can not read BadMap from CCDB, you may use --not-use-ccdb option to create default bad map"; + } + } else { + LOG(INFO) << "Do not use CCDB, create default BadMap"; + mBadMap.reset(new BadChannelsMap()); + } + } + + for (auto& tr : trs) { + + int firstCluInEvent = tr.getFirstEntry(); + int lastCluInEvent = firstCluInEvent + tr.getNumberOfObjects(); + + //TODO!!! Get MFT0 vertex + TVector3 vertex = {0., 0., 0.}; + mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing + for (int i = firstCluInEvent; i < lastCluInEvent; i++) { + const Cluster& clu = clusters[i]; + + if (!checkCluster(clu)) { + continue; + } + // prepare TLorentsVector + float posX, posZ; + clu.getLocalPosition(posX, posZ); + TVector3 vec3; + Geometry::GetInstance("Run3")->local2Global(clu.module(), posX, posZ, vec3); + vec3 -= vertex; + float e = clu.getEnergy(); + vec3 *= 1. / vec3.Mag(); + TLorentzVector v(vec3.X() * e, vec3.Y() * e, vec3.Z() * e, e); + for (short ip = mBuffer->size(); ip--;) { + const TLorentzVector& vp = mBuffer->getEntry(ip); + TLorentzVector sum = v + vp; + if (sum.Pt() > mPtCut) { + if (mBuffer->isCurrentEvent(ip)) { //same (real) event + mReMi[2 * clu.module()](sum.M()); // put all high-pt pairs to bin 4-6 GeV + } else { //Mixed + mReMi[2 * clu.module() + 1](sum.M()); // put all high-pt pairs to bin 4-6 GeV + } + } + } + mBuffer->addEntry(v); + } + } +} +void PHOSRunbyrunSlot::merge(const PHOSRunbyrunSlot* prev) +{ + //Not used +} +bool PHOSRunbyrunSlot::checkCluster(const Cluster& clu) +{ + //First check BadMap + float posX, posZ; + clu.getLocalPosition(posX, posZ); + short absId; + Geometry::relPosToAbsId(clu.module(), posX, posZ, absId); + if (!mBadMap->isChannelGood(absId)) { + return false; + } + return (clu.getEnergy() > 0.3 && clu.getMultiplicity() > 1); +} +void PHOSRunbyrunSlot::clear() +{ + for (int mod = 0; mod < 8; mod++) { + mReMi[mod].reset(); + } +} + +//============================================================== + +PHOSRunbyrunCalibrator::PHOSRunbyrunCalibrator() +{ + const int nMass = 150.; + const float massMax = 0.3; + for (int mod = 0; mod < 4; mod++) { + mReMi[2 * mod] = new TH1F(Form("hReInvMassMod%d", mod), "Real inv. mass per module", nMass, 0., massMax); + mReMi[2 * mod + 1] = new TH1F(Form("hMiInvMassMod%d", mod), "Mixed inv. mass per module", nMass, 0., massMax); + } +} +PHOSRunbyrunCalibrator::~PHOSRunbyrunCalibrator() +{ + for (int mod = 0; mod < 8; mod++) { + if (mReMi[mod]) { + mReMi[mod]->Delete(); + mReMi[mod] = nullptr; + } + } +} + +bool PHOSRunbyrunCalibrator::hasEnoughData(const Slot& slot) const +{ + //otherwize will be merged with next Slot + return true; +} +void PHOSRunbyrunCalibrator::initOutput() +{ +} +void PHOSRunbyrunCalibrator::finalizeSlot(Slot& slot) +{ + + // Extract results for the single slot + PHOSRunbyrunSlot* c = slot.getContainer(); + LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + //Add histos + for (int mod = 0; mod < 8; mod++) { + PHOSRunbyrunSlot::boostHisto& tmp = c->getCollectedHistos(mod); + int indx = 1; + for (auto&& x : boost::histogram::indexed(tmp)) { + mReMi[mod]->SetBinContent(indx, x.get() + mReMi[mod]->GetBinContent(indx)); + indx++; + } + } + c->clear(); +} + +Slot& PHOSRunbyrunCalibrator::emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) +{ + + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<PHOSRunbyrunSlot>(mUseCCDB, mCCDBPath)); + return slot; +} + +bool PHOSRunbyrunCalibrator::process(uint64_t tf, const gsl::span<const Cluster>& clu, const gsl::span<const TriggerRecord>& tr) +{ + // if (!mUpdateAtTheEndOfRunOnly) { + // int maxDelay = mMaxSlotsDelay * mSlotLength; + // // if (tf<mLastClosedTF || (!mSlots.empty() && getSlot(0).getTFStart() > tf + maxDelay)) { // ignore TF + // if (maxDelay != 0 && (tf < mLastClosedTF || (!mSlots.empty() && getLastSlot().getTFStart() > tf + maxDelay))) { // ignore TF + // LOG(INFO) << "Ignoring TF " << tf; + // return false; + // } + + // // check if some slots are done + // checkSlotsToFinalize(tf, maxDelay); + // } + + // process current TF + auto& slotTF = getSlotForTF(tf); + slotTF.getContainer()->setRunStartTime(tf); + slotTF.getContainer()->fill(clu, tr); + + return true; +} +void PHOSRunbyrunCalibrator::endOfStream() +{ + //Merge collected in different slots histograms + TF1 fRatio("ratio", this, &PHOSRunbyrunCalibrator::CBRatio, 0, 1, 6, "PHOSRunbyrunCalibrator", "CBRatio"); + TF1 fBg("background", this, &PHOSRunbyrunCalibrator::bg, 0, 1, 6, "PHOSRunbyrunCalibrator", "bg"); + TF1 fSignal("signal", this, &PHOSRunbyrunCalibrator::CBSignal, 0, 1, 6, "PHOSRunbyrunCalibrator", "CBSignal"); + //fit inv mass distributions + TFile fout("mgg.root", "recreate"); + for (int mod = 0; mod < 4; mod++) { + mReMi[2 * mod]->Sumw2(); + mReMi[2 * mod + 1]->Sumw2(); + TH1D* tmp = (TH1D*)mReMi[2 * mod]->Clone("Ratio"); + tmp->Divide(mReMi[2 * mod + 1]); + fRatio.SetParameters(1., 0.134, 0.005, 0.01, 0., 0.); + tmp->Fit(&fRatio, "q", "", 0.07, 0.22); + fBg.SetParameters(fRatio.GetParameter(3), fRatio.GetParameter(4), fRatio.GetParameter(5)); + mReMi[2 * mod + 1]->Multiply(&fBg); + // mReMi[2*mod]->Add(mReMi[2*mod+1],-1.) ; + fSignal.SetParameters(0.3 * mReMi[2 * mod]->Integral(65, 67, ""), 0.135, 0.005); + mReMi[2 * mod]->Fit(&fSignal, "q", "", 0.07, 0.22); + mRunByRun[2 * mod] = fSignal.GetParameter(1); + mRunByRun[2 * mod + 1] = fSignal.GetParError(1); + tmp->Write(); + mReMi[2 * mod]->Write(); + mReMi[2 * mod + 1]->Write(); + delete tmp; + //Clear before next period? + mReMi[2 * mod]->Reset(); + mReMi[2 * mod + 1]->Reset(); + } + fout.Close(); +} +double PHOSRunbyrunCalibrator::CBRatio(double* x, double* par) +{ + double m = par[1]; + double s = par[2]; + const double n = 4.1983; + const double a = 1.5; + const double A = TMath::Power((n / TMath::Abs(a)), n) * TMath::Exp(-a * a / 2); + const double B = n / TMath::Abs(a) - TMath::Abs(a); + double dx = (x[0] - m) / s; + if (dx > -a) { + return par[0] * exp(-dx * dx / 2.) + + par[3] + par[4] * x[0] + par[5] * x[0] * x[0]; + } else { + return par[0] * A * TMath::Power((B - dx), -n) + + par[3] + par[4] * x[0] + par[5] * x[0] * x[0]; + } +} +double PHOSRunbyrunCalibrator::CBSignal(double* x, double* par) +{ + double m = par[1]; + double s = par[2]; + const double n = 4.1983; + const double a = 1.5; + const double A = TMath::Power((n / TMath::Abs(a)), n) * TMath::Exp(-a * a / 2); + const double B = n / TMath::Abs(a) - TMath::Abs(a); + double dx = (x[0] - m) / s; + if (dx > -a) { + return par[0] * exp(-dx * dx / 2.) + par[3]; + } else { + return par[0] * A * TMath::Power((B - dx), -n) + par[3]; + } +} +double PHOSRunbyrunCalibrator::bg(double* x, double* par) +{ + return par[0] + par[1] * x[0] + par[2] * x[0] * x[0]; +} \ No newline at end of file diff --git a/Detectors/PHOS/calib/src/PHOSTurnonCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSTurnonCalibDevice.cxx new file mode 100644 index 0000000000000..8ee05bebcebbb --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSTurnonCalibDevice.cxx @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSTurnonCalibDevice.h" +#include "PHOSCalibWorkflow/TurnOnHistos.h" +#include "Framework/ConfigParamRegistry.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" + +#include "TF1.h" +#include "TH1.h" +#include "TGraphAsymmErrors.h" + +#include "FairLogger.h" +#include <fstream> // std::ifstream + +using namespace o2::phos; + +void PHOSTurnonCalibDevice::init(o2::framework::InitContext& ic) +{ + // int slotL = ic.options().get<int>("tf-per-slot"); + // int delay = ic.options().get<int>("max-delay"); + mCalibrator.reset(new PHOSTurnonCalibrator()); + + // mCalibrator->setSlotLength(slotL); + // mCalibrator->setMaxSlotsDelay(delay); + mCalibrator->setUpdateAtTheEndOfRunOnly(); +} +void PHOSTurnonCalibDevice::run(o2::framework::ProcessingContext& pc) +{ + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("clusters").header)->startTime; // is this the timestamp of the current TF? + auto cells = pc.inputs().get<gsl::span<Cell>>("cells"); + auto cellTR = pc.inputs().get<gsl::span<TriggerRecord>>("cellTriggerRecords"); + auto clusters = pc.inputs().get<gsl::span<Cluster>>("clusters"); + auto cluTR = pc.inputs().get<gsl::span<TriggerRecord>>("clusterTriggerRecords"); + + LOG(INFO) << "[PHOSTurnonCalibDevice - run] Received " << cells.size() << " cells and " << clusters.size() << " clusters, running calibration"; + + mCalibrator->process(tfcounter, cells, cellTR, clusters, cluTR); +} + +void PHOSTurnonCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + mCalibrator->endOfStream(); + mTriggerMap.reset(new TriggerMap(mCalibrator->getCalibration())); + if (checkFitResult()) { + //Calculate and send final object to CCDB + auto flName = o2::ccdb::CcdbApi::generateFileName("TriggerMap"); + std::map<std::string, std::string> md; + o2::ccdb::CcdbObjectInfo info("PHS/Calib/TriggerMap", "TriggerMap", flName, md, mRunStartTime, 99999999999999); + info.setMetaData(md); + auto image = o2::ccdb::CcdbApi::createObjectImage(mTriggerMap.get(), &info); + + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + ec.outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_Tunron", subSpec}, *image.get()); + ec.outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHOS_Tunron", subSpec}, info); + } else { + LOG(ERROR) << "Incorrect fit results"; + } + // //Send result to QC + // ec.outputs().snapshot(o2::framework::Output{"PHS", "TRIGMAPDIFF", 0, o2::framework::Lifetime::Timeframe}, mTrigMapDiff); + // ec.outputs().snapshot(o2::framework::Output{"PHS", "TURNONDIFF", 0, o2::framework::Lifetime::Timeframe}, mTurnOnDiff); +} + +o2::framework::DataProcessorSpec o2::phos::getPHOSTurnonCalibDeviceSpec(bool useCCDB, std::string path) +{ + + std::vector<InputSpec> inputs; + inputs.emplace_back("cells", o2::header::gDataOriginPHS, "CELLS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("cellTriggerRecords", o2::header::gDataOriginPHS, "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("clusters", o2::header::gDataOriginPHS, "CLUSTERS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("clusterTriggerRecords", o2::header::gDataOriginPHS, "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe); + + using clbUtils = o2::calibration::Utils; + std::vector<OutputSpec> outputs; + outputs.emplace_back( + ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "PHOS_Tunron"}); + outputs.emplace_back( + ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "PHOS_Tunron"}); + //stream for QC data + //outputs.emplace_back("PHS", "TRIGGERQC", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"PHOSTurnonCalibDevice", + inputs, + outputs, + o2::framework::adaptFromTask<PHOSTurnonCalibDevice>(useCCDB, path), + o2::framework::Options{}}; +} diff --git a/Detectors/PHOS/calib/src/PHOSTurnonCalibrator.cxx b/Detectors/PHOS/calib/src/PHOSTurnonCalibrator.cxx new file mode 100644 index 0000000000000..94c6d09206c03 --- /dev/null +++ b/Detectors/PHOS/calib/src/PHOSTurnonCalibrator.cxx @@ -0,0 +1,202 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSTurnonCalibrator.h" +#include "PHOSCalibWorkflow/TurnOnHistos.h" +#include "PHOSBase/Geometry.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ControlService.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +#include "TF1.h" +#include "TH1.h" +#include "TGraphAsymmErrors.h" + +#include "FairLogger.h" +#include <fstream> // std::ifstream + +using namespace o2::phos; + +PHOSTurnonSlot::PHOSTurnonSlot(bool useCCDB, std::string path) : mUseCCDB(useCCDB), mCCDBPath(path) +{ + mFiredTiles.reset(); + mNoisyTiles.reset(); + mTurnOnHistos.reset(new TurnOnHistos()); +} +PHOSTurnonSlot::PHOSTurnonSlot(const PHOSTurnonSlot& other) +{ + mUseCCDB = other.mUseCCDB; + mRunStartTime = other.mUseCCDB; + mCCDBPath = other.mCCDBPath; + mFiredTiles.reset(); + mNoisyTiles.reset(); + mTurnOnHistos.reset(new TurnOnHistos()); +} + +void PHOSTurnonSlot::print() const +{ + for (short ddl = 0; ddl < 14; ddl++) { + const std::array<float, TurnOnHistos::Npt>& all = mTurnOnHistos->getTotSpectrum(ddl); + const std::array<float, TurnOnHistos::Npt>& tr = mTurnOnHistos->getTrSpectrum(ddl); + float sumAll = 0, sumTr = 0.; + for (int i = 0; i < TurnOnHistos::Npt; i++) { + sumAll += all[i]; + sumTr += tr[i]; + } + LOG(INFO) << "DDL " << ddl << " total entries " << sumAll << " trigger clusters " << sumTr; + } +} +void PHOSTurnonSlot::fill(const gsl::span<const Cell>& cells, const gsl::span<const TriggerRecord>& cellTR, + const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& cluTR) +{ + + auto ctr = cellTR.begin(); + auto clutr = cluTR.begin(); + while (ctr != cellTR.end() && clutr != cluTR.end()) { + // + //TODO! select NOT PHOS triggered events + // DataProcessingHeader:: + // + if (ctr->getBCData() != clutr->getBCData()) { + LOG(ERROR) << "Different TrigRecords for cells:" << ctr->getBCData() << " and clusters:" << clutr->getBCData(); + //TODO: Try to recover by increasing smaller TR? + } + scanClusters(cells, *ctr, clusters, *clutr); + ctr++; + clutr++; + } +} +void PHOSTurnonSlot::clear() +{ + mFiredTiles.reset(); + mNoisyTiles.reset(); + mTurnOnHistos.reset(); +} +void PHOSTurnonSlot::scanClusters(const gsl::span<const Cell>& cells, const TriggerRecord& celltr, + const gsl::span<const Cluster>& clusters, const TriggerRecord& clutr) +{ + //First fill map of expected tiles from TRU cells + mNoisyTiles.reset(); + int firstCellInEvent = celltr.getFirstEntry(); + int lastCellInEvent = firstCellInEvent + celltr.getNumberOfObjects(); + for (int i = firstCellInEvent; i < lastCellInEvent; i++) { + const Cell& c = cells[i]; + if (c.getTRU()) { + mNoisyTiles.set(c.getTRUId()); + } + } + + //Copy to have good and noisy map + + mFiredTiles.reset(); + char mod; + float x, z; + short ddl; + int firstCluInEvent = clutr.getFirstEntry(); + int lastCluInEvent = firstCluInEvent + clutr.getNumberOfObjects(); + for (int i = firstCluInEvent; i < lastCluInEvent; i++) { + const Cluster& clu = clusters[i]; + mod = clu.module(); + clu.getLocalPosition(x, z); + short truId = Geometry::relPosToTruId(mod, x, z, ddl); + //TODO!!! if(map.isGood2x2(truId)){ + mTurnOnHistos->fillTotSp(ddl, clu.getEnergy()); + if (clu.firedTrigger() & 1) { //Bit 1: 2x2, bit 2 4x4 //TODO: do we need separate 2x2 and 4x4 spectra? Switch? + mTurnOnHistos->fillFiredSp(ddl, clu.getEnergy()); + //Fill trigger map + mFiredTiles.set(truId); + } + // } + } + //Fill final good and noisy maps + mTurnOnHistos->fillFiredMap(mFiredTiles); + mNoisyTiles ^= mFiredTiles; + mTurnOnHistos->fillNoisyMap(mFiredTiles); +} +//============================================== + +void PHOSTurnonCalibrator::finalizeSlot(Slot& slot) +{ + // Extract results for the single slot + //if not ready yet, prepare containers + if (!mTurnOnHistos) { + mTurnOnHistos.reset(new TurnOnHistos()); + } + PHOSTurnonSlot* c = slot.getContainer(); + LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + //Add histos + for (int mod = 0; mod < 8; mod++) { + mTurnOnHistos->merge(c->getCollectedHistos()); + } + c->clear(); +} +PHOSTurnonCalibrator::Slot& PHOSTurnonCalibrator::emplaceNewSlot(bool front, uint64_t tstart, uint64_t tend) +{ + + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<PHOSTurnonSlot>(mUseCCDB, mCCDBPath)); + return slot; +} + +bool PHOSTurnonCalibrator::process(uint64_t tf, const gsl::span<const Cell>& cells, const gsl::span<const TriggerRecord>& cellTR, + const gsl::span<const Cluster>& clusters, const gsl::span<const TriggerRecord>& cluTR) +{ + // process current TF + auto& slotTF = getSlotForTF(tf); + slotTF.getContainer()->setRunStartTime(tf); + slotTF.getContainer()->fill(cells, cellTR, clusters, cluTR); + + return true; +} + +void PHOSTurnonCalibrator::endOfStream() +{ + //Use stored histos to calculate maps and turn-on curves + //return true of successful + + //extract TOC + if (!mTriggerMap) { + mTriggerMap.reset(new TriggerMap()); + } + TF1* th = new TF1("aTh", "[0]/(TMath::Exp(([1]-x)/[2])+1.)+(1.-[0])/(TMath::Exp(([3]-x)/[2])+1.)", 0., 40.); + std::array<std::array<float, 10>, TurnOnHistos::NDDL> params; + for (int ddl = 0; ddl < TurnOnHistos::NDDL; ddl++) { + TH1F hF("fired", "fired", 200, 0., 20.); + TH1F hA("all", "all", 200, 0., 20.); + const std::array<float, TurnOnHistos::Npt>& vf = mTurnOnHistos->getTrSpectrum(ddl); + const std::array<float, TurnOnHistos::Npt>& va = mTurnOnHistos->getTotSpectrum(ddl); + for (int i = 0; i < 200; i++) { + hF.SetBinContent(i + 1, vf[i]); + hA.SetBinContent(i + 1, va[i]); + } + hF.Sumw2(); + hA.Sumw2(); + + TGraphAsymmErrors* gr = new TGraphAsymmErrors(&hF, &hA); + th->SetParameters(0.9, 3.5, 0.3, 7.5, 0.6); + gr->Fit(th, "Q", "", 2., 20.); + gr->SetName(Form("DDL_%d", ddl)); + gr->SetTitle(Form("DDL %d", ddl)); + //TODO!!! Add TGraph with fit to list of objects to send to QC + double* par = th->GetParameters(); + for (int i = 0; i < 10; i++) { + params[ddl][i] = par[i]; + } + } + std::string_view versionName{"default"}; + mTriggerMap->addTurnOnCurvesParams(versionName, params); + //TODO: calculate bad map + //and fill object + //mTriggerMap->addBad2x2Channel(short cellID) ; +} diff --git a/Detectors/PHOS/calib/src/TurnOnHistos.cxx b/Detectors/PHOS/calib/src/TurnOnHistos.cxx new file mode 100644 index 0000000000000..86d3ba79d5508 --- /dev/null +++ b/Detectors/PHOS/calib/src/TurnOnHistos.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/TurnOnHistos.h" + +using namespace o2::phos; + +void TurnOnHistos::merge(TurnOnHistos& other) +{ + for (int i = NCHANNELS; --i;) { + mGoodMap[i] += other.mGoodMap[i]; + mNoisyMap[i] += other.mNoisyMap[i]; + } + for (int i = NDDL; --i;) { + for (int j = Npt; --j;) { + mTotSp[i][j] += other.mTotSp[i][j]; + mTrSp[i][j] += other.mTrSp[i][j]; + } + } +} diff --git a/Detectors/PHOS/calib/src/phos-calib-workflow.cxx b/Detectors/PHOS/calib/src/phos-calib-workflow.cxx new file mode 100644 index 0000000000000..429456336727e --- /dev/null +++ b/Detectors/PHOS/calib/src/phos-calib-workflow.cxx @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSCalibWorkflow/PHOSPedestalCalibDevice.h" +#include "PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h" +#include "PHOSCalibWorkflow/PHOSEnergyCalibDevice.h" +#include "PHOSCalibWorkflow/PHOSTurnonCalibDevice.h" +#include "PHOSCalibWorkflow/PHOSRunbyrunCalibDevice.h" +#include "Framework/DataProcessorSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// // we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + // which method should be called + workflowOptions.push_back(ConfigParamSpec{"pedestals", o2::framework::VariantType::Bool, false, {"do pedestal calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"hglgratio", o2::framework::VariantType::Bool, false, {"do HG/LG ratio calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"turnon", o2::framework::VariantType::Bool, false, {"scan trigger turn-on curves"}}); + workflowOptions.push_back(ConfigParamSpec{"runbyrun", o2::framework::VariantType::Bool, false, {"do run by run correction calculation"}}); + workflowOptions.push_back(ConfigParamSpec{"energy", o2::framework::VariantType::Bool, false, {"collect tree for E calib"}}); + workflowOptions.push_back(ConfigParamSpec{"badmap", o2::framework::VariantType::Bool, false, {"do bad map calculation"}}); + // + workflowOptions.push_back(ConfigParamSpec{"not-use-ccdb", o2::framework::VariantType::Bool, false, {"enable access to ccdb phos calibration objects"}}); + workflowOptions.push_back(ConfigParamSpec{"forceupdate", o2::framework::VariantType::Bool, false, {"update ccdb even difference to previous object large"}}); + workflowOptions.push_back(ConfigParamSpec{"ccdbpath", o2::framework::VariantType::String, "http://ccdb-test.cern.ch:8080", {"CCDB address to get current objects"}}); + workflowOptions.push_back(ConfigParamSpec{"digitspath", o2::framework::VariantType::String, "./CalibDigits.root", {"path and name of file to store calib. digits"}}); + + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); +} + +// ------------------------------------------------------------------ +// we need to add workflow options before including Framework/runDataProcessing +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + auto doPedestals = configcontext.options().get<bool>("pedestals"); + auto doHgLgRatio = configcontext.options().get<bool>("hglgratio"); + auto doTurnOn = configcontext.options().get<bool>("turnon"); + auto doRunbyrun = configcontext.options().get<bool>("runbyrun"); + auto doEnergy = configcontext.options().get<bool>("energy"); + auto doBadMap = configcontext.options().get<bool>("badmap"); + auto useCCDB = !configcontext.options().get<bool>("not-use-ccdb"); + auto forceUpdate = configcontext.options().get<bool>("forceupdate"); + auto path = configcontext.options().get<std::string>("ccdbpath"); + auto dpath = configcontext.options().get<std::string>("digitspath"); + if (doPedestals && doHgLgRatio) { + LOG(FATAL) << "Can not run pedestal and HG/LG calibration simulteneously"; + } + + LOG(INFO) << "PHOS Calibration workflow: options"; + LOG(INFO) << "useCCDB = " << useCCDB; + if (doPedestals) { + LOG(INFO) << "pedestals "; + specs.emplace_back(o2::phos::getPedestalCalibSpec(useCCDB, forceUpdate, path)); + } else { + if (doHgLgRatio) { + LOG(INFO) << "hglgratio "; + specs.emplace_back(o2::phos::getHGLGRatioCalibSpec(useCCDB, forceUpdate, path)); + } + } + if (doEnergy) { + LOG(INFO) << "Filling tree for energy and time calibration "; + specs.emplace_back(o2::phos::getPHOSEnergyCalibDeviceSpec(useCCDB, path, dpath)); + } + if (doTurnOn) { + LOG(INFO) << "TurnOn curves calculation"; + specs.emplace_back(o2::phos::getPHOSTurnonCalibDeviceSpec(useCCDB, path)); + } + if (doRunbyrun) { + LOG(INFO) << "Run by run correction calculation on "; + specs.emplace_back(o2::phos::getPHOSRunbyrunCalibDeviceSpec(useCCDB, path)); + } + if (doBadMap) { + LOG(INFO) << "bad map calculation "; + short m = 0; + // specs.emplace_back(o2::phos::getBadMapCalibSpec(useCCDB,forceUpdate,path,m)); + } + return specs; +} diff --git a/Detectors/PHOS/reconstruction/CMakeLists.txt b/Detectors/PHOS/reconstruction/CMakeLists.txt index bf49c5acffe09..e24b0e1e91b28 100644 --- a/Detectors/PHOS/reconstruction/CMakeLists.txt +++ b/Detectors/PHOS/reconstruction/CMakeLists.txt @@ -1,21 +1,40 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(PHOSReconstruction SOURCES src/Clusterer.cxx - src/FullCluster.cxx + src/RawReaderMemory.cxx + src/RawBuffer.cxx + src/RawHeaderStream.cxx + src/RawPayload.cxx + src/AltroDecoder.cxx + src/CaloRawFitter.cxx + src/CaloRawFitterGS.cxx + src/CTFCoder.cxx + src/CTFHelper.cxx PUBLIC_LINK_LIBRARIES O2::PHOSBase - O2::PHOSCalib O2::DataFormatsPHOS - AliceO2::InfoLogger) + O2::DetectorsRaw + AliceO2::InfoLogger + O2::rANS + Microsoft.GSL::GSL) o2_target_root_dictionary(PHOSReconstruction - HEADERS include/PHOSReconstruction/Clusterer.h - include/PHOSReconstruction/FullCluster.h) + HEADERS include/PHOSReconstruction/RawReaderMemory.h + include/PHOSReconstruction/RawBuffer.h + include/PHOSReconstruction/RawHeaderStream.h + include/PHOSReconstruction/RawPayload.h + include/PHOSReconstruction/RawReaderError.h + include/PHOSReconstruction/RawDecodingError.h + include/PHOSReconstruction/AltroDecoder.h + include/PHOSReconstruction/CaloRawFitter.h + include/PHOSReconstruction/CaloRawFitterGS.h + include/PHOSReconstruction/Clusterer.h) diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/AltroDecoder.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/AltroDecoder.h new file mode 100644 index 0000000000000..8be2a6333513f --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/AltroDecoder.h @@ -0,0 +1,151 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_ALTRODECODER_H +#define ALICEO2_PHOS_ALTRODECODER_H + +#include <iosfwd> +#include <gsl/span> +#include <string> +#include <bitset> +#include "PHOSBase/RCUTrailer.h" +#include "DataFormatsPHOS/Cell.h" +#include "PHOSBase/Mapping.h" +#include "PHOSReconstruction/RawReaderError.h" +#include "PHOSReconstruction/CaloRawFitter.h" +#include "PHOSReconstruction/RawReaderMemory.h" + +namespace o2 +{ +namespace phos +{ + +/// \class AltroDecoderError +/// \brief Error handling of the ALTRO Decoder +/// \ingroup EMCALreconstruction +class AltroDecoderError : public std::exception +{ + public: + enum ErrorType_t { + kOK, ///< NoError + RCU_TRAILER_ERROR, ///< RCU trailer cannot be decoded or invalid + RCU_VERSION_ERROR, ///< RCU trailer version not matching with the version in the raw header + RCU_TRAILER_SIZE_ERROR, ///< RCU trailer size length + ALTRO_BUNCH_HEADER_ERROR, ///< ALTRO bunch header cannot be decoded or is invalid + ALTRO_BUNCH_LENGTH_ERROR, ///< ALTRO bunch has incorrect length + ALTRO_PAYLOAD_ERROR, ///< ALTRO payload cannot be decoded + ALTRO_MAPPING_ERROR, ///< Incorrect ALTRO channel mapping + CHANNEL_ERROR ///< Channels not initialized + }; + + /// \brief Constructor + /// + /// Defining error code and error message. To be called when the + /// exception is thrown + AltroDecoderError(ErrorType_t errtype, const char* message) : mErrorType(errtype), mErrorMessage(message) {} + + /// \brief Destructor + ~AltroDecoderError() noexcept override = default; + + /// \brief Access to error message cnnected to the error + /// \return Error message + const char* what() const noexcept override { return mErrorMessage.data(); } + + /// \brief Access to the error type connected to the erro + /// \return Error type + const ErrorType_t getErrorType() const noexcept { return mErrorType; } + + private: + ErrorType_t mErrorType; ///< Code of the decoding error type + std::string mErrorMessage; ///< Message connected to the error type +}; + +/// \class AltroDecoder +/// \brief Decoder of the ALTRO data in the raw page +/// \ingroup PHOSreconstruction +/// \author Dmitri Peresunko aftesr Markus Fasel +/// \since Sept, 2020 +/// +/// This is a base class for reading raw data digits in Altro format. +/// The class is able to read the RCU v3 and above formats. +/// The main difference between the format V3 and older ones is in +/// the coding of the 10-bit Altro payload words. In V3 3 10-bit words +/// are coded in one 32-bit word. The bits 30 and 31 are used to identify +/// the payload, altro header and RCU trailer contents. +/// +/// Based on AliAltroRawStreamV3 and AliCaloRawStreamV3 by C. Cheshkov + +class AltroDecoder +{ + public: + /// \brief Constructor + AltroDecoder() = default; + + /// \brief Destructor + ~AltroDecoder() = default; + + /// \brief Decode the ALTRO stream + /// \throw AltroDecoderError if the RCUTrailer or ALTRO payload cannot be decoded + /// + /// Decoding and checking the RCUTtrailer and + /// all channels and bunches in the ALTRO stream. + /// After successfull decoding the Decoder can provide + /// a reference to the RCU trailer and a vector + /// with the decoded chanenels, each containing + /// its bunches. + AltroDecoderError::ErrorType_t decode(RawReaderMemory& rawreader, CaloRawFitter* rawFitter, + std::vector<o2::phos::Cell>& cellContainer, + std::vector<o2::phos::Cell>& truContainer); + + /// \brief Get list of hw errors found in decoding + const std::vector<o2::phos::RawReaderError>& hwerrors() { return mOutputHWErrors; } + + /// \brief Get reference to the RCU trailer object + /// \return reference to the RCU trailers vector + const RCUTrailer& getRCUTrailer() const { return mRCUTrailer; } + + /// \brief Read channels for the current event in the raw buffer + void readChannels(const std::vector<uint32_t>& payloadwords, CaloRawFitter* rawFitter, + std::vector<o2::phos::Cell>& cellContainer, + std::vector<o2::phos::Cell>& truContainer); + void setPedestalRun() + { + mPedestalRun = true; + mCombineGHLG = false; + } + void setCombineHGLG(bool a) { mCombineGHLG = a; } + + private: + static constexpr int kGeneralSRUErr = 15; ///< Non-existing FEE card to store general SRU errors + static constexpr int kGeneralTRUErr = 16; ///< Non-existing FEE card to store general TRU errors + //check and convert HW address to absId and caloFlag + bool hwToAbsAddress(short hwaddress, short& absId, Mapping::CaloFlag& caloFlag); + //read trigger digits + void readTRUDigits(short absId, int payloadSize, std::vector<o2::phos::Cell>& truContainer); + //read trigger summary tables + void readTRUFlags(short hwAddress, int payloadSize); + + bool mCombineGHLG = true; ///< Combine or not HG and LG channels (def: combine, LED runs: not combine) + bool mPedestalRun = false; ///< Analyze pedestal run (calculate pedestal mean and RMS) + short mddl; ///< Current DDL + std::vector<uint16_t> mBunchwords; ///< (transient) bunch of samples for current channel + std::vector<o2::phos::RawReaderError> mOutputHWErrors; ///< Errors occured in reading data + std::vector<short> mOutputFitChi; ///< Raw sample fit quality + std::bitset<Mapping::NTRUReadoutChannels + 2> mTRUFlags; ///< trigger summary table + RCUTrailer mRCUTrailer; ///< RCU trailer + + ClassDefNV(AltroDecoder, 1); +}; + +} // namespace phos + +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..b07b578d3bcee --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h @@ -0,0 +1,156 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of PHOS data + +#ifndef O2_PHOS_CTFCODER_H +#define O2_PHOS_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsPHOS/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "PHOSReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace phos +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::PHS) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Cell>& cellData); + + /// entropy decode data from buffer with CTF + template <typename VTRG, typename VCELL> + void decode(const CTF::base& ec, VTRG& trigVec, VCELL& cellVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Cell>& cellVec); +}; + +/// entropy-encode clusters to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Cell>& cellData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_entriesTrig + MD::EENCODE, // BLC_packedID + MD::EENCODE, // BLC_time + MD::EENCODE, // BLC_energy + MD::EENCODE // BLC_status + }; + + CTFHelper helper(trigData, cellData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODEPHS(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODEPHS(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODEPHS(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + ENCODEPHS(helper.begin_entriesTrig(), helper.end_entriesTrig(), CTF::BLC_entriesTrig, 0); + + ENCODEPHS(helper.begin_packedID(), helper.end_packedID(), CTF::BLC_packedID, 0); + ENCODEPHS(helper.begin_time(), helper.end_time(), CTF::BLC_time, 0); + ENCODEPHS(helper.begin_energy(), helper.end_energy(), CTF::BLC_energy, 0); + ENCODEPHS(helper.begin_status(), helper.end_status(), CTF::BLC_status, 0); + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded clusters to standard compact clusters +template <typename VTRG, typename VCELL> +void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VCELL& cellVec) +{ + const auto& header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcInc, entries, energy, cellTime, packedID; + std::vector<uint32_t> orbitInc; + std::vector<uint8_t> status; + +#define DECODEPHOS(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODEPHOS(bcInc, CTF::BLC_bcIncTrig); + DECODEPHOS(orbitInc, CTF::BLC_orbitIncTrig); + DECODEPHOS(entries, CTF::BLC_entriesTrig); + DECODEPHOS(packedID, CTF::BLC_packedID); + + DECODEPHOS(cellTime, CTF::BLC_time); + DECODEPHOS(energy, CTF::BLC_energy); + DECODEPHOS(status, CTF::BLC_status); + // clang-format on + // + trigVec.clear(); + cellVec.clear(); + trigVec.reserve(header.nTriggers); + status.reserve(header.nCells); + + uint32_t firstEntry = 0, cellCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + + Cell cell; + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + + firstEntry = cellVec.size(); + for (uint16_t ic = 0; ic < entries[itrig]; ic++) { + cell.setPacked(packedID[cellCount], cellTime[cellCount], energy[cellCount], status[cellCount]); + cellVec.emplace_back(cell); + cellCount++; + } + trigVec.emplace_back(ir, firstEntry, entries[itrig]); + } + assert(cellCount == header.nCells); +} + +} // namespace phos +} // namespace o2 + +#endif // O2_PHOS_CTFCODER_H diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFHelper.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..8b35228c78ff4 --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFHelper.h @@ -0,0 +1,195 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for PHOS CTF creation + +#ifndef O2_PHOS_CTF_HELPER_H +#define O2_PHOS_CTF_HELPER_H + +#include "DataFormatsPHOS/CTF.h" +#include <gsl/span> + +namespace o2 +{ +namespace phos +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const TriggerRecord>& trgData, const gsl::span<const Cell>& cellData) + : mTrigData(trgData), mCellData(cellData) {} + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigData.size()), uint32_t(mCellData.size()), 0, 0}; + if (mTrigData.size()) { + h.firstOrbit = mTrigData[0].getBCData().orbit; + h.firstBC = mTrigData[0].getBCData().bc; + } + return h; + } + + size_t getSize() const { return mTrigData.size() * sizeof(TriggerRecord) + mCellData.size() * sizeof(Cell); } + + //>>> =========================== ITERATORS ======================================== + + template <typename I, typename D, typename T> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].getBCData().orbit == mData[mIndex - 1].getBCData().orbit) { + return mData[mIndex].getBCData().bc - mData[mIndex - 1].getBCData().bc; + } else { + return mData[mIndex].getBCData().bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].getBCData().orbit - mData[mIndex - 1].getBCData().orbit : 0; } + }; + + //_______________________________________________ + // Number of cells for trigger + class Iter_entriesTrig : public _Iter<Iter_entriesTrig, TriggerRecord, uint16_t> + { + public: + using _Iter<Iter_entriesTrig, TriggerRecord, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNumberOfObjects(); } + }; + + //_______________________________________________ + class Iter_packedID : public _Iter<Iter_packedID, Cell, uint16_t> + { + public: + using _Iter<Iter_packedID, Cell, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedID(); } + }; + + //_______________________________________________ + class Iter_time : public _Iter<Iter_time, Cell, uint16_t> + { + public: + using _Iter<Iter_time, Cell, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedTime(); } + }; + + //_______________________________________________ + class Iter_energy : public _Iter<Iter_energy, Cell, uint16_t> + { + public: + using _Iter<Iter_energy, Cell, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedEnergy(); } + }; + + //_______________________________________________ + class Iter_status : public _Iter<Iter_status, Cell, uint8_t> + { + public: + using _Iter<Iter_status, Cell, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPackedCellStatus(); } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, true); } + + Iter_entriesTrig begin_entriesTrig() const { return Iter_entriesTrig(mTrigData, false); } + Iter_entriesTrig end_entriesTrig() const { return Iter_entriesTrig(mTrigData, true); } + + Iter_packedID begin_packedID() const { return Iter_packedID(mCellData, false); } + Iter_packedID end_packedID() const { return Iter_packedID(mCellData, true); } + + Iter_time begin_time() const { return Iter_time(mCellData, false); } + Iter_time end_time() const { return Iter_time(mCellData, true); } + + Iter_energy begin_energy() const { return Iter_energy(mCellData, false); } + Iter_energy end_energy() const { return Iter_energy(mCellData, true); } + + Iter_status begin_status() const { return Iter_status(mCellData, false); } + Iter_status end_status() const { return Iter_status(mCellData, true); } + + private: + const gsl::span<const o2::phos::TriggerRecord> mTrigData; + const gsl::span<const o2::phos::Cell> mCellData; +}; + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitter.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitter.h new file mode 100644 index 0000000000000..edbac3f043473 --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitter.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class CaloRawFitter +/// \brief Raw data fitting: extraction amplitude and time +/// +/// Extraction of amplitude and time +/// from CALO raw data using fast k-level approach or +/// least square fit with Gamma2 function +/// +/// \author Dmitri Peresunko +/// \since Jan.2020 +/// + +#ifndef PHOSRAWFITTER_H_ +#define PHOSRAWFITTER_H_ +#include "Rtypes.h" + +namespace o2 +{ + +namespace phos +{ + +class CaloRawFitter +{ + + public: + enum FitStatus { kOK, + kNotEvaluated, + kEmptyBunch, + kOverflow, + kSpike, + kNoTime, + kFitFailed, + kBadPedestal, + kManyBunches }; + + public: + /// \brief Constructor + CaloRawFitter(); + + /// \brief Destructor + virtual ~CaloRawFitter() = default; + + /// \brief Evaluation Amplitude and TOF + /// return status -1: not evaluated/empty bunch; + /// 0: OK; + /// 1: overflow; + /// 4: single spikes + /// 3: too large RMS; + virtual FitStatus evaluate(gsl::span<short unsigned int> signal); + + /// \brief Set HighGain/LowGain channel to performe or not fit of saturated samples + void setLowGain(bool isLow = false) { mLowGain = isLow; } + + /// \brief estimate and subtract pedestals from pre-samples + void setPedSubtract(bool toSubtruct = false) { mPedSubtract = toSubtruct; } + + /// \brief amplitude in last fitted sample + float getAmp() const { return mAmp; } + + /// \brief Chi2/NDF of last performed fit + float getChi2() const { return mChi2; } + + /// \brief time in last fitted sample + float getTime() const { return mTime; } + + /// \brief is last fitted sample has overflow + bool isOverflow() const { return mOverflow; } + + /// \brief Forse perform fitting + /// Make fit for any sample, not only saturated LowGain samples as by default + void forseFitting(bool toRunFit = true) { makeFit = toRunFit; } + + /// \brief Set analysis of pedestal run + /// Analyze pedestal run, i.e. calculate mean and RMS of pedestals instead of Amp and Time + void setPedestal() { mPedestalRun = true; } + + protected: + FitStatus evalKLevel(gsl::span<short unsigned int> signal); + + protected: + bool makeFit = false; ///< run (slow) fit with Gamma2 or use fast evaluation with k-level + bool mLowGain = false; ///< is current bunch from LowGain channel + bool mPedSubtract = false; ///< should one evaluate and subtract pedestals + bool mPedestalRun = false; ///< analyze as pedestal run + bool mOverflow; ///< is last sample saturated + FitStatus mStatus = kNotEvaluated; ///< status of last evaluated sample: -1: not yet evaluated; 0: OK; 1: overflow; 2: too large RMS; 3: single spikes + short mMaxSample = 0; ///< maximal sample + float mAmp; ///< amplitude of last processed sample + float mTime; ///< time of last processed sample + float mChi2; ///< chi2 calculated in last fit + short mSpikeThreshold; + short mBaseLine; + short mPreSamples; + + ClassDef(CaloRawFitter, 1); +}; // End of CaloRawFitter + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitterGS.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitterGS.h new file mode 100644 index 0000000000000..8e7526494a9ff --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitterGS.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \class CaloRawFitterGSGS +/// \brief Raw data fitting based on NIM A621 (2010) 231–237 +/// +/// Extraction of amplitude and time +/// from CALO raw data using analytical calculation of +/// least square fit with Gamma2 function +/// +/// \author Dmitri Peresunko after M.Bogolybski +/// \since April.2021 +/// + +#ifndef PHOSRAWFITTERGS_H +#define PHOSRAWFITTERGS_H +#include "PHOSReconstruction/CaloRawFitter.h" + +namespace o2 +{ + +namespace phos +{ + +class CaloRawFitterGS : public CaloRawFitter +{ + + public: + static constexpr int NMAXSAMPLES = 40; ///< maximal expected number of samples per bunch + /// \brief Constructor + CaloRawFitterGS(); + + /// \brief Destructor + ~CaloRawFitterGS() final = default; + + /// \brief Evaluation Amplitude and TOF + FitStatus evaluate(gsl::span<short unsigned int> signal) final; + + protected: + void init(); + FitStatus evalFit(gsl::span<short unsigned int> signal); + + private: + float mDecTime = 0.058823529; ///< decay time constant + float mTimeAccuracy = 0.; ///< accuracy of iterative fit + float mAmpAccuracy = 0.; ///< accuracy of iterative fit + float ma0[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + float mb0[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + float mb1[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + float mb2[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + float mb3[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + float mb4[NMAXSAMPLES]; ///< arrays to tabulate Gamma2 function and its momenta + + ClassDef(CaloRawFitterGS, 1); +}; // End of CaloRawFitterGS + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h index 05b4183b659c6..de307bb329646 100644 --- a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,12 +16,11 @@ #include "DataFormatsPHOS/Digit.h" #include "DataFormatsPHOS/Cell.h" #include "DataFormatsPHOS/Cluster.h" -#include "PHOSReconstruction/FullCluster.h" -#include "PHOSCalib/CalibParams.h" -#include "PHOSCalib/BadChannelMap.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "DataFormatsPHOS/BadChannelsMap.h" #include "DataFormatsPHOS/MCLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" #include "DataFormatsPHOS/TriggerRecord.h" +#include "SimulationDataFormat/MCTruthContainer.h" namespace o2 { @@ -37,28 +37,28 @@ class Clusterer void initialize(); void process(gsl::span<const Digit> digits, gsl::span<const TriggerRecord> dtr, const o2::dataformats::MCTruthContainer<MCLabel>* dmc, - std::vector<Cluster>* clusters, std::vector<TriggerRecord>* rigRec, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC); + std::vector<Cluster>& clusters, std::vector<CluElement>& cluel, std::vector<TriggerRecord>& rigRec, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC); void processCells(gsl::span<const Cell> digits, gsl::span<const TriggerRecord> dtr, - const o2::dataformats::MCTruthContainer<MCLabel>* dmc, gsl::span<const unsigned int> mcmap, - std::vector<Cluster>* clusters, std::vector<TriggerRecord>* rigRec, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC); + const o2::dataformats::MCTruthContainer<MCLabel>* dmc, + std::vector<Cluster>& clusters, std::vector<CluElement>& cluel, std::vector<TriggerRecord>& rigRec, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC); - void makeClusters(gsl::span<const Digit> digits); - void evalCluProperties(gsl::span<const Digit> digits, std::vector<Cluster>* clusters, - const o2::dataformats::MCTruthContainer<MCLabel>* dmc, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC); + void makeClusters(std::vector<Cluster>& clusters, std::vector<o2::phos::CluElement>& cluel); - float showerShape(float dx, float dz); // Parameterization of EM shower - - void makeUnfoldings(gsl::span<const Digit> digits); // Find and unfold clusters with few local maxima - void unfoldOneCluster(FullCluster& iniClu, char nMax, gsl::span<int> digitId, gsl::span<const Digit> digits); + void setBadMap(std::unique_ptr<BadChannelsMap>& m) { mBadMap = std::move(m); } + void setCalibration(std::unique_ptr<CalibParams>& c) { mCalibParams = std::move(c); } protected: - void convertCellsToDigits(gsl::span<const Cell> cells, int firstCellInEvent, int lastCellInEvent, gsl::span<const unsigned int> mcmap); - //Calibrate energy - inline float calibrate(float amp, short absId) { return amp * mCalibParams->getGain(absId); } + inline float calibrate(float amp, short absId, bool isHighGain) + { + if (isHighGain) { + return amp * mCalibParams->getGain(absId); + } else { + return amp * mCalibParams->getGain(absId) * mCalibParams->getHGLGRatio(absId); + } + } //Calibrate time inline float calibrateT(float time, short absId, bool isHighGain) { @@ -72,15 +72,50 @@ class Clusterer //Test Bad map inline bool isBadChannel(short absId) { return (!mBadMap->isChannelGood(absId)); } + char getNumberOfLocalMax(Cluster& clu, std::vector<CluElement>& cluel); + void evalAll(Cluster& clu, std::vector<CluElement>& cluel) const; + void evalLabels(std::vector<Cluster>& clusters, std::vector<CluElement>& cluel, + const o2::dataformats::MCTruthContainer<MCLabel>* dmc, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC); + + double showerShape(double r2, double& deriv); // Parameterization of EM shower + + void makeUnfolding(Cluster& clu, std::vector<Cluster>& clusters, std::vector<o2::phos::CluElement>& cluel); //unfold cluster with few local maxima + void unfoldOneCluster(Cluster& iniClu, char nMax, std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements); + protected: + static constexpr short NLOCMAX = 30; //Maximal number of local maxima in cluster + bool mProcessMC = false; + int miCellLabel = 0; + bool mFullCluOutput = false; ///< Write output full of reduced (no contributed digits) clusters Geometry* mPHOSGeom = nullptr; ///< PHOS geometry - const CalibParams* mCalibParams = nullptr; //! Calibration coefficients - const BadChannelMap* mBadMap = nullptr; //! Calibration coefficients + std::unique_ptr<CalibParams> mCalibParams; ///! Calibration coefficients + std::unique_ptr<BadChannelsMap> mBadMap; ///! Bad map + + std::vector<CluElement> mCluEl; ///< internal vector of clusters + std::vector<Digit> mTrigger; ///< internal vector of clusters + int mFirstElememtInEvent; ///< Range of digits from one event + int mLastElementInEvent; ///< Range of digits from one event - std::vector<FullCluster> mClusters; ///< internal vector of clusters - int mFirstDigitInEvent; ///< Range of digits from one event - int mLastDigitInEvent; ///< Range of digits from one event - std::vector<Digit> mDigits; ///< vector of trancient digits for cell processing + std::vector<float> mProp; ///< proportion of clusters in the current digit + std::array<float, NLOCMAX> mxMax; ///< current maximum coordinate + std::array<float, NLOCMAX> mzMax; ///< in the unfolding procedure + std::array<float, NLOCMAX> meMax; ///< currecnt amplitude in unfoding + std::array<float, NLOCMAX> mxMaxPrev; ///< coordunates at previous step + std::array<float, NLOCMAX> mzMaxPrev; ///< coordunates at previous step + std::array<float, NLOCMAX> mdx; ///< step on current minimization iteration + std::array<float, NLOCMAX> mdz; ///< step on current minimization iteration + std::array<float, NLOCMAX> mdxprev; ///< step on previoud minimization iteration + std::array<float, NLOCMAX> mdzprev; ///< step on previoud minimization iteration + std::array<double, NLOCMAX> mA; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mxB; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mzB; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mfijx; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mfijz; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mfijr; ///< transient variable for derivative calculation + std::array<double, NLOCMAX> mfij; ///< transient variable for derivative calculation + std::vector<bool> mIsLocalMax; ///< transient array for local max finding + std::array<int, NLOCMAX> mMaxAt; ///< indexes of local maxima }; } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/FullCluster.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/FullCluster.h deleted file mode 100644 index ed22c5e806fac..0000000000000 --- a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/FullCluster.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <gsl/gsl> -#ifndef ALICEO2_PHOS_FULLCLUSTER_H_ -#define ALICEO2_PHOS_FULLCLUSTER_H_ - -#include "DataFormatsPHOS/Digit.h" -#include "DataFormatsPHOS/Cluster.h" -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace phos -{ -class Geometry; -/// \class FullCluster -/// \brief PHOS cluster implementation - -class FullCluster : public Cluster -{ - - using Label = o2::MCCompLabel; - - public: - struct CluElement { - short absId; - float energy; - float time; - float localX; - float localZ; - int label; - float scale; - CluElement(short a, float e, float t, float x, float z, int l, float s) : absId(a), energy(e), time(t), localX(x), localZ(z), label(l), scale(s) {} - }; - - FullCluster() = default; - FullCluster(short digitAbsId, float energy, float time, int label, float scale); - - ~FullCluster() = default; - - /// \brief Method to add digit to a cluster - /// \param digit being added, energy of this digit, may be smaller than full due to everlap - void addDigit(short digitAbsId, float energy, float time, int label, float scale); - - void evalAll(); - - // Get index of a digit with i - short getDigitAbsId(Int_t i) const { return mElementList.at(i).absId; } - - const std::vector<CluElement>* getElementList() const { return &mElementList; } - - //Counts local maxima and returns their positions - char getNumberOfLocalMax(gsl::span<int> maxAt) const; - - void purify(); // Removes digits below threshold - - protected: - void evalCoreEnergy(); // computes energy within radius Rcore - void evalLocalPosition(); // computes the position in the PHOS module - void evalDispersion(); // computes the dispersion of the shower - void evalElipsAxis(); // computes the axis of shower ellipsoide - void evalTime(); - // Binary search implementation - std::vector<Digit>::const_iterator BinarySearch(const std::vector<Digit>* container, Digit& element); - - private: - std::vector<CluElement> mElementList; //! Transient Array of digits - - ClassDefNV(FullCluster, 1); -}; -} // namespace phos -} // namespace o2 - -#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawBuffer.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawBuffer.h new file mode 100644 index 0000000000000..9e06a1fd36887 --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawBuffer.h @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_RAWBUFFER_H +#define ALICEO2_PHOS_RAWBUFFER_H + +#include <array> +#include <cstdint> +#include <iosfwd> +#include <gsl/span> + +namespace o2 +{ +namespace phos +{ + +/// \class RawBuffer +/// \brief Buffer for PHOS raw pages +/// \ingroup PHOSreconstruction +/// \author Dmitri Peresunko after Markus Fasel +/// \since Sept, 2020 +class RawBuffer +{ + public: + RawBuffer() = default; + ~RawBuffer() = default; + + void reset() { mCurrentDataWord = 0; } + + /// \brief Flush the buffer + /// Does not overwrite the word buffer but just resets the counter and iterator + void flush(); + + /// \brief Read page from stream + /// \param in Input file stream + /// \param payloadsize Number of char words in payload + /// Read a whole superpage from the raw stream + /// and convert the bitwise representation directly + /// into 32 bit words + void readFromStream(std::istream& in, uint32_t payloadsize); + + /// \brief Read page from raw memory buffer + /// \param rawmemory Raw memory buffer (as char words) with size of the payload from the raw data header + /// Converts the char word raw memory buffer of a pages into + /// into the 32 bit word buffer + void readFromMemoryBuffer(const gsl::span<const char> rawmemory); + + /// \brief Get the number of data words read for the superpage + /// \return Number of data words in the superpage + int getNDataWords() const { return mNDataWords; } + + /// \brief Get the next data word in the superpage + /// \return next data word in the superpage + /// \throw std::runtime_error if there exists no next data word + uint32_t getNextDataWord(); + + /// \brief Get the data word at a given index + /// \param index index of the word in the buffer + /// \return word at requested index + /// \throw std::runtime_error if the index is out-of-range + uint32_t getWord(int index) const; + + /// \brief Get all data words from the raw buffer + /// \return Span with data words in the buffer (removing trailing null entries) + const gsl::span<const uint32_t> getDataWords() const { return gsl::span<const uint32_t>(mDataWords.data(), mNDataWords); } + + /// \brief Check whether the next data word exists + /// \return True if more data words exist, false otherwise + /// Check is done starting from the current position + /// of the iterator + bool hasNext() const { return mCurrentDataWord < mNDataWords; } + + private: + std::array<uint32_t, 2048> mDataWords; ///< Data words in one superpage + int mNDataWords = 0; ///< Number of data words read from superpage + int mCurrentDataWord = 0; ///< Iterator over words in superpage +}; + +} // namespace phos + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawDecodingError.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawDecodingError.h new file mode 100644 index 0000000000000..27eac69cc59ce --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawDecodingError.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_RAWDECODINGERROR_H +#define ALICEO2_PHOS_RAWDECODINGERROR_H + +#include <exception> + +namespace o2 +{ + +namespace phos +{ + +/// \class RawDecodingError +/// \brief Error handling of the raw reader +/// \ingroup PHOSreconstruction +/// +/// The following error types are defined: +/// - Page not found +/// - Raw header decoding error +/// - Payload decoding error +class RawDecodingError : public std::exception +{ + public: + /// \enum ErrorType_t + /// \brief Codes for different error types + enum class ErrorType_t { + PAGE_NOTFOUND, ///< Page was not found (page index outside range) + HEADER_DECODING, ///< Header cannot be decoded (format incorrect) + PAYLOAD_DECODING, ///< Payload cannot be decoded (format incorrect) + HEADER_INVALID, ///< Header in memory not belonging to requested superpage + PAYLOAD_INVALID, ///< Payload in memory not belonging to requested superpage + }; + + /// \brief Constructor + /// \param errtype Identifier code of the error type + /// + /// Constructing the error with error code. To be called when the + /// exception is thrown. + RawDecodingError(ErrorType_t errtype) : mErrorType(errtype) + { + } + + /// \brief destructor + ~RawDecodingError() noexcept override = default; + + /// \brief Providing error message of the exception + /// \return Error message of the exception + const char* what() const noexcept override + { + switch (mErrorType) { + case ErrorType_t::PAGE_NOTFOUND: + return "Page with requested index not found"; + case ErrorType_t::HEADER_DECODING: + return "RDH of page cannot be decoded"; + case ErrorType_t::PAYLOAD_DECODING: + return "Payload of page cannot be decoded"; + case ErrorType_t::HEADER_INVALID: + return "Access to header not belonging to requested superpage"; + case ErrorType_t::PAYLOAD_INVALID: + return "Access to payload not belonging to requested superpage"; + }; + return "Undefined error"; + } + + /// \brief Get the type identifier of the error handled with this exception + /// \return Error code of the exception + ErrorType_t getErrorType() const { return mErrorType; } + + private: + ErrorType_t mErrorType; ///< Type of the error +}; + +} // namespace phos + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawHeaderStream.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawHeaderStream.h new file mode 100644 index 0000000000000..ecb057e66acbb --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawHeaderStream.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RawHeaderStream.h +/// \brief Input stream operators for raw header 4 and 5 from binary file +/// +/// Helpers to define input stream operator for raw headers v4 and v5 from +/// binary file input stream, used in RawReaderFile + +#ifndef ALICEO2_PHOS_RAWHEADERSTREAM_H +#define ALICEO2_PHOS_RAWHEADERSTREAM_H + +#include <iosfwd> +#include "Headers/RAWDataHeader.h" + +namespace o2 +{ + +namespace phos +{ + +std::istream& operator>>(std::istream& stream, o2::header::RAWDataHeaderV4& header); +std::istream& operator>>(std::istream& stream, o2::header::RAWDataHeaderV5& header); + +std::ostream& operator<<(std::ostream& stream, const o2::header::RAWDataHeaderV4& header); +std::ostream& operator<<(std::ostream& stream, const o2::header::RAWDataHeaderV5& header); + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawPayload.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawPayload.h new file mode 100644 index 0000000000000..d95d092f85141 --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawPayload.h @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_PHOS_RAWPAYLOAD_H +#define ALICEO2_PHOS_RAWPAYLOAD_H + +#include <cstdint> +#include <vector> +#include <gsl/span> +#include "Rtypes.h" + +namespace o2 +{ + +namespace phos +{ + +/// \class RawPayload +/// \brief Class for raw payload excluding raw data headers from one or multiple DMA pages +/// \ingroup PHOSreconstruction +/// \author Markus Fasel <markus.fasel@cern.ch>, Oak Ridge National Laboratory +/// \since Nov 14, 2019 +/// +/// Container of 32-bit words in the current payload which can come from a single DMA page +/// or, in case the payload had to be split into multiple pages due to exceeding of the +/// page size, from multiple DMA pages. A page counter provides the amount of DMA pages +/// contributing to the current payload. +class RawPayload +{ + public: + /// \brief Constructor + RawPayload() = default; + + /// \brief Constructor + /// \param payloadwords Payload words of one or multiple pages + /// \param numpages Number of DMA pages contributing to the payload + RawPayload(const gsl::span<const uint32_t> payloadwords, int numpages); + + /// \brief Destructor + ~RawPayload() = default; + + /// \brief Set the number of pages contributing to the current payload + /// \param numpages Number of DMA pages contributing to the payload + void setNumberOfPages(int numpages) { mNumberOfPages = numpages; } + + /// \brief Append many words to the current payload (usually of a given DMA page) + /// \param payloadwords Payload words to be appened to the current payload + void appendPayloadWords(const gsl::span<const uint32_t> payloadwords); + + /// \brief Append single payload word to the current payload + /// \param payloadword Payload word to be appended to the current payload + void appendPayloadWord(uint32_t payloadword) { mPayloadWords.emplace_back(payloadword); }; + + /// \brief Increase the page counter of the current payload + void increasePageCount() { mNumberOfPages++; } + + /// \brief Get the payload words (as 32 bit words) contributing to the current payload + /// \return Words of the current payload + const std::vector<uint32_t>& getPayloadWords() const { return mPayloadWords; } + + /// \brief Get the number of pages contributing to the payload + /// \return Number of pages + int getNumberOfPages() const { return mNumberOfPages; } + + /// \brief Resetting payload words and page counter + void reset(); + + /// \brief Get the size of the payload + /// \return Size of the payload + int getPayloadSize() const { return mPayloadWords.size(); } + + private: + std::vector<uint32_t> mPayloadWords; ///< Payload words (excluding raw header) + int mNumberOfPages; ///< Number of DMA pages + + ClassDefNV(RawPayload, 1); +}; + +} // namespace phos + +} // namespace o2 +#endif diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderError.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderError.h new file mode 100644 index 0000000000000..e17ee30282472 --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderError.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_RAWREADERERROR_H +#define ALICEO2_PHOS_RAWREADERERROR_H + +namespace o2 +{ + +namespace phos +{ + +/// \class RawReaderError +/// \brief Error occured during reasing raw data +/// \ingroup PHOSReconstruction +/// +/// Error contains DDL number, FEE, chip, channel number if possible and error code + +class RawReaderError +{ + public: + /// \brief Constructor + RawReaderError() = default; + + /// \brief Constructor + RawReaderError(char ddl, char fec, char err) : mDDL(ddl), mFEC(fec), mErr(err) {} + + /// \brief destructor + ~RawReaderError() = default; + + char getDDL() { return mDDL; } + char getFEC() { return mFEC; } + char getError() { return mErr; } + + private: + char mDDL = 0; + char mFEC = 0; + char mErr = 0; + + ClassDefNV(RawReaderError, 1); +}; + +} // namespace phos + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderMemory.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderMemory.h new file mode 100644 index 0000000000000..5cf17db569e9a --- /dev/null +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/RawReaderMemory.h @@ -0,0 +1,121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_PHOS_RAWREADERMEMORY_H +#define ALICEO2_PHOS_RAWREADERMEMORY_H + +#include <gsl/span> +#include <Rtypes.h> + +#include "PHOSBase/RCUTrailer.h" +#include "PHOSReconstruction/RawBuffer.h" +#include "PHOSReconstruction/RawPayload.h" +#include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" + +namespace o2 +{ + +namespace phos +{ + +/// \class RawReaderMemory +/// \brief Reader for raw data produced by the Readout application in in-memory format +/// \ingroup PHOSreconstruction +/// \author Dmitri Peresunko after Markus Fasel +/// \since Sept. 25, 2020 +/// +/// +class RawReaderMemory +{ + public: + /// \brief Constructor + RawReaderMemory(const gsl::span<const char> rawmemory); + + /// \brief Destructor + ~RawReaderMemory() = default; + + /// \brief set new raw memory chunk + /// \param rawmemory New raw memory chunk + void setRawMemory(const gsl::span<const char> rawmemory); + + /// \brief Read next payload from the stream + /// + /// Read the next pages until the stop bit is found. + void next(); + + /// \brief Read the next page from the stream (single DMA page) + /// \param resetPayload If true the raw payload is reset + /// \throw Error if the page cannot be read or header or payload cannot be deocded + /// + /// Function reading a single DMA page from the stream. It is called + /// inside the next() function for reading payload from multiple DMA + /// pages. As the function cannot handle payload from multiple pages + /// it should not be called directly by the user. + void nextPage(bool resetPayload = true); + + /// \brief access to the raw header of the current page + /// \return Raw header of the current page + /// \throw RawDecodingError with HEADER_INVALID if the header was not decoded + const o2::header::RDHAny& getRawHeader() const; + + /// \brief access to the raw buffer (single DMA page) + /// \return Raw buffer of the current page + /// \throw Error with PAYLOAD_INCALID if payload was not decoded + const RawBuffer& getRawBuffer() const; + + /// \brief access to the full raw payload (single or multiple DMA pages) + /// \return Raw Payload of the data until the stop bit is received. + const RawPayload& getPayload() const { return mRawPayload; } + + /// \brief Return size of the payload + /// \return size of the payload + int getPayloadSize() const { return mRawPayload.getPayloadSize(); } + + /// \brief get the size of the file in bytes + /// \return size of the file in byte + int getFileSize() const noexcept { return mRawMemoryBuffer.size(); } + + /// \brief get the number of pages in the file + /// \return number of pages in the file + int getNumberOfPages() const noexcept { return mNumData; } + + /// \brief check if more pages are available in the raw file + /// \return true if there is a next page + bool hasNext() const { return mCurrentPosition < mRawMemoryBuffer.size(); } + + protected: + /// \brief Initialize the raw stream + /// + /// Rewind stream to the first entry + void init(); + + o2::header::RDHAny decodeRawHeader(const void* headerwords); + + private: + gsl::span<const char> mRawMemoryBuffer; ///< Memory block with multiple DMA pages + RawBuffer mRawBuffer; ///< Raw buffer + o2::header::RDHAny mRawHeader; ///< Raw header + RawPayload mRawPayload; ///< Raw payload (can consist of multiple pages) + RCUTrailer mCurrentTrailer; ///< RCU trailer + uint64_t mTrailerPayloadWords = 0; ///< Payload words in common trailer + int mCurrentPosition = 0; ///< Current page in file + int mNumData = 0; ///< Number of pages + bool mRawHeaderInitialized = false; ///< RDH for current page initialized + bool mPayloadInitialized = false; ///< Payload for current page initialized + + ClassDefNV(RawReaderMemory, 1); +}; + +} // namespace phos + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/PHOS/reconstruction/src/AltroDecoder.cxx b/Detectors/PHOS/reconstruction/src/AltroDecoder.cxx new file mode 100644 index 0000000000000..e3d83975b78ef --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/AltroDecoder.cxx @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <cstring> +#include <boost/format.hpp> +#include "InfoLogger/InfoLogger.hxx" +#include "PHOSBase/PHOSSimParams.h" +#include "PHOSReconstruction/AltroDecoder.h" +#include "PHOSReconstruction/RawReaderMemory.h" +#include "PHOSReconstruction/RawDecodingError.h" + +#include "DetectorsRaw/RDHUtils.h" +#include <FairLogger.h> + +using namespace o2::phos; + +AltroDecoderError::ErrorType_t AltroDecoder::decode(RawReaderMemory& rawreader, CaloRawFitter* rawFitter, + std::vector<o2::phos::Cell>& currentCellContainer, std::vector<o2::phos::Cell>& currentTRUContainer) +{ + mOutputHWErrors.clear(); + mOutputFitChi.clear(); + + auto& header = rawreader.getRawHeader(); + mddl = o2::raw::RDHUtils::getFEEID(header); + + const std::vector<uint32_t>& payloadwords = rawreader.getPayload().getPayloadWords(); + + try { + gsl::span<const uint32_t> tmp(payloadwords.data(), payloadwords.size()); + mRCUTrailer.constructFromRawPayload(tmp); + } catch (RCUTrailer::Error& e) { + LOG(ERROR) << "RCU trailer error" << (int)e.getErrorType(); + mOutputHWErrors.emplace_back(mddl, kGeneralSRUErr, static_cast<char>(e.getErrorType())); //assign general SRU header errors to non-existing FEE 15 + return AltroDecoderError::RCU_TRAILER_ERROR; + } + + //TODO checkRCUTrailer(); + try { + readChannels(payloadwords, rawFitter, currentCellContainer, currentTRUContainer); + } catch (AltroDecoderError::ErrorType_t e) { + LOG(ERROR) << "Altro decoding error " << e; + return e; + } + return AltroDecoderError::kOK; +} + +void AltroDecoder::readChannels(const std::vector<uint32_t>& buffer, CaloRawFitter* rawFitter, + std::vector<o2::phos::Cell>& currentCellContainer, std::vector<o2::phos::Cell>& currentTRUContainer) +{ + int currentpos = 0; + + int payloadend = buffer.size() - mRCUTrailer.getTrailerSize(); //mRCUTrailer.getPayloadSize() was not updated in case of merged pages. + while (currentpos < payloadend) { + auto currentword = buffer[currentpos++]; + ChannelHeader header = {currentword}; + if (header.mMark != 1) { + if (currentword != 0) { + LOG(ERROR) << "Channel header mark not found, header word " << currentword; + short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + short branch = header.mHardwareAddress >> 11 & 0x1; + if (fec > 14) { + fec = kGeneralSRUErr; + } + fec += kGeneralTRUErr * branch; + mOutputHWErrors.emplace_back(mddl, fec, 5); //5: channel header error + } + continue; + } + /// decode all words for channel + int numberofwords = (header.mPayloadSize + 2) / 3; + if (numberofwords > payloadend - currentpos) { + LOG(ERROR) << "Channel payload " << numberofwords << " larger than left in total " << payloadend - currentpos; + short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + short branch = header.mHardwareAddress >> 11 & 0x1; + if (fec > 14) { + fec = kGeneralSRUErr; + } + fec += kGeneralTRUErr * branch; + mOutputHWErrors.emplace_back(mddl, fec, 6); //6: channel payload error + continue; + } + mBunchwords.clear(); + int isample = 0; + while (isample < header.mPayloadSize) { + currentword = buffer[currentpos++]; + if ((currentword >> 30) != 0) { + LOG(ERROR) << "Unexpected end of payload in altro channel payload! FEE=" << mddl + << ", Address=0x" << std::hex << header.mHardwareAddress << ", word=0x" << currentword << std::dec; + currentpos--; + short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + short branch = header.mHardwareAddress >> 11 & 0x1; + if (fec > 14) { + fec = kGeneralSRUErr; + } + fec += kGeneralTRUErr * branch; + mOutputHWErrors.emplace_back(mddl, fec, 6); //6: channel payload error + break; + } + mBunchwords.push_back((currentword >> 20) & 0x3FF); + isample++; + if (isample < header.mPayloadSize) { + mBunchwords.push_back((currentword >> 10) & 0x3FF); + isample++; + if (isample < header.mPayloadSize) { + mBunchwords.push_back(currentword & 0x3FF); + isample++; + } else { + break; + } + } else { + break; + } + } + short absId; + Mapping::CaloFlag caloFlag; + if (!hwToAbsAddress(header.mHardwareAddress, absId, caloFlag)) { + // do not decode, skip to hext channel + short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + short branch = header.mHardwareAddress >> 11 & 0x1; + if (fec > 14) { + fec = kGeneralSRUErr; + } + fec += kGeneralTRUErr * branch; + mOutputHWErrors.emplace_back(mddl, fec, 7); //7: wrong hw address + continue; + } + + //Get time and amplitude + if (caloFlag != Mapping::kTRU) { //HighGain or LowGain + // decode bunches + int currentsample = 0; + while (currentsample < header.mPayloadSize) { + int bunchlength = mBunchwords[currentsample] - 2, // remove words for bunchlength and starttime + starttime = mBunchwords[currentsample + 1]; + if (bunchlength < 0) { // corrupted data, + short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + short branch = header.mHardwareAddress >> 11 & 0x1; + fec += kGeneralTRUErr * branch; + mOutputHWErrors.emplace_back(mddl, fec, 6); //6: channel payload error + break; + } + //extract sample properties + CaloRawFitter::FitStatus fitResult = rawFitter->evaluate(gsl::span<uint16_t>(&mBunchwords[currentsample + 2], std::min((unsigned long)bunchlength, mBunchwords.size() - currentsample - 2))); + currentsample += bunchlength + 2; + //set output cell + // if (fitResult == CaloRawFitter::FitStatus::kNoTime) { //Time evaluation error occured: should we add this err to list? + // short fec = header.mHardwareAddress >> 7 & 0xf; //try to extract FEE number from header + // short branch = header.mHardwareAddress >> 11 & 0x1; + // if (fec > 14) { + // fec = kGeneralSRUErr; + // } + // fec += kGeneralTRUErr * branch; + // mOutputHWErrors.emplace_back(mddl, fec, 8); //8: time calculation failed + // } + if (!rawFitter->isOverflow()) { //Overflow is will show wrong chi2 + short chiAddr = absId; + chiAddr |= caloFlag << 14; + mOutputFitChi.emplace_back(chiAddr); + mOutputFitChi.emplace_back(short(rawFitter->getChi2())); + } + + if (fitResult == CaloRawFitter::FitStatus::kOK || fitResult == CaloRawFitter::FitStatus::kNoTime) { + if (!mPedestalRun) { + if (caloFlag == Mapping::kHighGain && !rawFitter->isOverflow()) { + currentCellContainer.emplace_back(absId, rawFitter->getAmp(), + (rawFitter->getTime() + starttime) * o2::phos::PHOSSimParams::Instance().mTimeTick, (ChannelType_t)caloFlag); + } + if (caloFlag == Mapping::kLowGain) { + currentCellContainer.emplace_back(absId, rawFitter->getAmp(), + (rawFitter->getTime() + starttime) * o2::phos::PHOSSimParams::Instance().mTimeTick, (ChannelType_t)caloFlag); + } + } else { //pedestal, to store RMS, scale in by 1.e-7 to fit range + currentCellContainer.emplace_back(absId, rawFitter->getAmp(), 1.e-7 * rawFitter->getTime(), (ChannelType_t)caloFlag); + } + } //Successful fit + } //Bunched of a channel + } //HG or LG channel + else { //TRU channel + // Channels in TRU: + // There are 112 readout channels and 12 channels reserved for production flags: + // Channels 0-111: channel data readout + // Channels 112-123: production flags + if (Mapping::isTRUReadoutchannel(header.mHardwareAddress)) { + Mapping::Instance()->hwToAbsId(mddl, header.mHardwareAddress, absId, caloFlag); + readTRUDigits(absId, header.mPayloadSize, currentTRUContainer); + } else { + readTRUFlags(header.mHardwareAddress, header.mPayloadSize); + } + } //TRU channel + } + + //Scan Flags and trigger cells and left only good + //if trigger cell exists and the trigger flag true -add it + bool is4x4Trigger = mTRUFlags[Mapping::NTRUReadoutChannels]; + for (auto rit = currentTRUContainer.rbegin(); rit != currentTRUContainer.rend(); rit++) { + if (mTRUFlags[rit->getTRUId()]) { //there is corresponding flag + if (is4x4Trigger) { + rit->setType(ChannelType_t::TRU4x4); + } else { + rit->setType(ChannelType_t::TRU2x2); + } + } else { //will be removed later + rit->setEnergy(0); + } + } +} + +bool AltroDecoder::hwToAbsAddress(short hwAddr, short& absId, Mapping::CaloFlag& caloFlag) +{ + //check hardware address and convert to absId and caloFlag + + if (mddl < 0 || mddl > o2::phos::Mapping::NDDL) { + return (char)4; + } + // short chan = hwAddr & 0xf; + short chip = hwAddr >> 4 & 0x7; + short fec = hwAddr >> 7 & 0xf; + short branch = hwAddr >> 11 & 0x1; + + short e2 = 0; + if (fec > 14) { + e2 = 2; + fec = kGeneralSRUErr; + mOutputHWErrors.emplace_back(mddl, fec + branch * kGeneralTRUErr, 2); + } else { + if (fec != 0 && (chip < 0 || chip > 4 || chip == 1)) { //Do not check for TRU (fec=0) + e2 = 3; + mOutputHWErrors.emplace_back(mddl, fec + branch * kGeneralTRUErr, 3); + } + } + + if (e2) { + return false; + } + + //correct hw address, try to convert + Mapping::ErrorStatus s = Mapping::Instance()->hwToAbsId(mddl, hwAddr, absId, caloFlag); + if (s != Mapping::ErrorStatus::kOK) { + mOutputHWErrors.emplace_back(mddl, branch * kGeneralTRUErr + kGeneralSRUErr, 4); //4: error in mapping + return false; + } + return true; +} + +void AltroDecoder::readTRUDigits(short absId, int payloadSize, std::vector<o2::phos::Cell>& truContainer) +{ + int currentsample = 0; + while (currentsample < payloadSize) { + int bunchlength = mBunchwords[currentsample] - 2; // remove words for bunchlength and starttime + if (bunchlength < 0) { //corrupted sample: add error and ignore the reast of bunchwords + mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(1)); // 1: wrong TRU header + return; + } + int timeBin = mBunchwords[currentsample + 1]; + int istart = currentsample + 2; + int iend = std::min((unsigned long)bunchlength, mBunchwords.size() - currentsample - 2); + currentsample += bunchlength + 2; + int smax = 0, tmax = 0; + // Loop over all the time steps in the signal + for (int i = iend - 1; i >= istart; i--) { + if (mBunchwords[i] > smax) { + smax = mBunchwords[i]; + tmax = timeBin; + } + timeBin++; + } + truContainer.emplace_back(absId + 14337 + 1, smax, tmax * 1.e-9, TRU2x2); //add TRU cells + } +} +void AltroDecoder::readTRUFlags(short hwAddress, int payloadSize) +{ + // Production flags: + // Production flags are supplied in channels 112 - 123 + // Each of the channels is 10 bit wide + // The bits inside the channel (indexing starting from the first bit of channel 112) is as follows: + // Bits 0-111: Trigger flags for corresponding channel index + // If using 4x4 algorithm, only 91 first bits are used of these + // Bit 112: Marker for 4x4 algorithm (1 active, 0 not active) + // Bit 113: Marker for 2x2 algorithm (1 active, 0 not active) + // Bit 114: Global L0 OR of all patches in the TRU + + int currentsample = 0; + while (currentsample < payloadSize) { + int bunchlength = mBunchwords[currentsample] - 2; // remove words for bunchlength and starttime + int timeBin = mBunchwords[currentsample + 1]; + if (bunchlength < 0) { //corrupted sample: add error and ignore the reast of bunchwords + mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(1)); // 1: wrong TRU header + return; + } + int istart = currentsample + 2; + int iend = std::min((unsigned long)bunchlength, mBunchwords.size() - currentsample - 2); + currentsample += bunchlength + 2; + + for (int i = iend - 1; i >= istart; i--) { + short a = mBunchwords[i]; + // If bit 112 is 1, we are considering 4x4 algorithm + if (hwAddress == Mapping::TRUFinalProductionChannel) { + mTRUFlags[Mapping::NTRUReadoutChannels] = (a & (1 << 2)); // Check the bit number 112 + } + const int kWordLength = 10; // Length of one data word in TRU raw data + + // Assign the bits in the words to corresponding channels + for (Int_t bitIndex = 0; bitIndex < kWordLength; bitIndex++) { + // Find the correct channel number assuming that + // hwAddress 112 = bits 0-9 corresponding trigger flags in channels 0-9 + // hwAddress 113 = bits 10-19 corresponding trigger flags in channels 10-19 + // and so on + short channel; + if (hwAddress < 128) { + channel = (hwAddress - Mapping::NTRUBranchReadoutChannels) * kWordLength + bitIndex; + } else { + channel = 112 + (hwAddress - 2048 - Mapping::NTRUBranchReadoutChannels) * kWordLength + bitIndex; //branch 0 + } + mTRUFlags[channel] = mTRUFlags[channel] | (a & (1 << bitIndex)); + } // Bits in one word + } // Length of signal + } +} diff --git a/Detectors/PHOS/reconstruction/src/CTFCoder.cxx b/Detectors/PHOS/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..2d89517ba9173 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of PHOS data + +#include "PHOSReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::phos; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Cell>& cellVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, trigVec, cellVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc = 0, entries = 0, cellTime = 0, energy = 0, packedid = 0; + uint32_t orbitInc = 0; + uint8_t status = 0; +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(entries, CTF::BLC_entriesTrig); + MAKECODER(packedid, CTF::BLC_packedID); + MAKECODER(cellTime, CTF::BLC_time); + MAKECODER(energy, CTF::BLC_energy); + MAKECODER(status, CTF::BLC_status); + // clang-format on +} diff --git a/Detectors/PHOS/reconstruction/src/CTFHelper.cxx b/Detectors/PHOS/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..36e1839ceeb52 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for PHOS CTF creation + +#include "PHOSReconstruction/CTFHelper.h" diff --git a/Detectors/PHOS/reconstruction/src/CaloRawFitter.cxx b/Detectors/PHOS/reconstruction/src/CaloRawFitter.cxx new file mode 100644 index 0000000000000..afcdd41906125 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/CaloRawFitter.cxx @@ -0,0 +1,216 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CaloRawFitter.cxx +/// \author Dmitri Peresunko + +#include <gsl/span> + +#include "PHOSReconstruction/CaloRawFitter.h" +#include "PHOSBase/PHOSSimParams.h" + +using namespace o2::phos; + +CaloRawFitter::CaloRawFitter() +{ + + mSpikeThreshold = o2::phos::PHOSSimParams::Instance().mSpikeThreshold; + mBaseLine = o2::phos::PHOSSimParams::Instance().mBaseLine; + mPreSamples = o2::phos::PHOSSimParams::Instance().mPreSamples; +} + +CaloRawFitter::FitStatus CaloRawFitter::evaluate(gsl::span<short unsigned int> signal) +{ + + //Pedestal analysis mode + if (mPedestalRun) { + int nPed = signal.size(); + float mean = 0.; + float rms = 0.; + for (auto a : signal) { + mean += a; + rms += a * a; + } + if (nPed > 0) { + mean /= nPed; + rms = rms / nPed - mean * mean; + if (rms > 0.) { + rms = sqrt(rms); + } + } + mAmp = mean; + mTime = rms; // only in Pedestal mode! + mOverflow = false; + mStatus = kOK; + return kOK; + } + + // Extract amplitude and time using maximum and k-level methods + return evalKLevel(signal); +} + +CaloRawFitter::FitStatus CaloRawFitter::evalKLevel(gsl::span<short unsigned int> signal) //const ushort *signal, int sigStart, int sigLength) +{ + // Calculate signal parameters (energy, time, quality) from array of samples + // Energy is a maximum sample minus pedestal 9 + // Time is the first time bin + // Signal overflows is there are at least 3 samples of the same amplitude above 900 + + int sigLength = signal.size(); + if (sigLength == 0) { + return kEmptyBunch; + } + + float pedMean = 0; + int nPed = 0; + mMaxSample = 0; + int nMax = 0; //number of consequitive maximal samples + bool spike = false; + mOverflow = false; + + int ap = -1, app = -1; //remember previous values to evaluate spikes + for (auto it = signal.rbegin(); it != signal.rend(); ++it) { + uint16_t a = *it; + if (mPedSubtract) { + if (nPed < mPreSamples) { //inverse signal time order + nPed++; + pedMean += a; + } + } + if (a > mMaxSample) { + mMaxSample = a; + nMax = 0; + } + if (a == mMaxSample) { + nMax++; + } + //check if there is a spike + if (app >= 0 && ap >= 0) { + spike |= (2 * ap - (a + app) > 2 * mSpikeThreshold); + } + app = ap; + ap = a; + } + mAmp = (float)mMaxSample; + + if (spike) { + mTime = -2; + mOverflow = false; + return kSpike; + } + + if (mMaxSample > 900 && nMax > 2) { + mOverflow = true; + } + + float pedestal = 0; + if (mPedSubtract) { + if (nPed > 0) { + pedMean /= nPed; + } else { + mAmp = 0.; + mTime = -2; + mOverflow = false; + return kBadPedestal; + } + } else { + pedMean = 0.; + } + + mAmp -= pedMean; + if (mAmp < mBaseLine) { + mAmp = 0; + } + + //Evaluate time + mTime = -2; + const int nLine = 6; //Parameters of fitting + const float eMinTOF = 10.; //Choosed from beam-test and cosmic analyis + const float kAmp = 0.35; //Result slightly depends on them, so no getters + // Avoid too low peak: + if (mAmp < eMinTOF) { + return kOK; //use estimated time + } + + // Find index posK (kLevel is a level of "timestamp" point Tk): + int posK = sigLength - 1; //last point before crossing k-level + float levelK = pedestal + kAmp * mAmp; + while (signal[posK] <= levelK && posK >= 0) { + posK--; + } + posK++; + + if (posK == 0 || posK == sigLength - 1) { + return kNoTime; // + } + + // Find crossing point by solving linear equation (least squares method) + int np = 0; + int iup = posK - 1; + int idn = posK; + double sx = 0., sy = 0., sxx = 0., sxy = 0.; + double x, y; + + while (np < nLine) { + //point above crossing point + if (iup >= 0) { + x = sigLength - iup - 1; + y = signal[iup]; + sx += x; + sy += y; + sxx += (x * x); + sxy += (x * y); + np++; + iup--; + } + //Point below crossing point + if (idn < sigLength) { + if (signal[idn] < pedestal) { + idn = sigLength - 1; //do not scan further + idn++; + continue; + } + x = sigLength - idn - 1; + y = signal[idn]; + sx += x; + sy += y; + sxx += (x * x); + sxy += (x * y); + np++; + idn++; + } + if (idn >= sigLength && iup < 0) { + break; //can not fit futher + } + } + + double det = np * sxx - sx * sx; + if (det == 0) { + return kNoTime; + } + if (np == 0) { + return kEmptyBunch; + } + double c1 = (np * sxy - sx * sy) / det; //slope + double c0 = (sy - c1 * sx) / np; //offset + if (c1 == 0) { + return kNoTime; + } + + // Find where the line cross kLevel: + mTime += (levelK - c0) / c1 - 5.; //5: mean offset between k-Level and start times + + if (mOverflow) { + return kOverflow; + } else { + return kOK; + } +} diff --git a/Detectors/PHOS/reconstruction/src/CaloRawFitterGS.cxx b/Detectors/PHOS/reconstruction/src/CaloRawFitterGS.cxx new file mode 100644 index 0000000000000..7dcf11b703be7 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/CaloRawFitterGS.cxx @@ -0,0 +1,315 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CaloRawFitterGS.cxx +/// \author Dmitri Peresunko + +#include <gsl/span> + +#include "PHOSReconstruction/CaloRawFitterGS.h" +#include "PHOSBase/PHOSSimParams.h" + +using namespace o2::phos; +CaloRawFitterGS::CaloRawFitterGS() : CaloRawFitter() +{ + mDecTime = o2::phos::PHOSSimParams::Instance().mSampleDecayTime; + mTimeAccuracy = o2::phos::PHOSSimParams::Instance().mSampleTimeFitAccuracy; + mAmpAccuracy = o2::phos::PHOSSimParams::Instance().mSampleAmpFitAccuracy; + init(); +} + +void CaloRawFitterGS::init() +{ + //prepare fitting arrays, once per lifetime + double k = o2::phos::PHOSSimParams::Instance().mSampleDecayTime; + ma0[0] = 1.; + mb0[0] = 1.; + mb1[0] = 0.; + mb2[0] = 0.; + mb3[0] = 0.; + mb4[0] = 0.; + for (int i = 1; i < NMAXSAMPLES; i++) { + double xi = k * i; + ma0[i] = exp(-xi); + mb0[i] = mb0[i - 1] + ma0[i]; + mb1[i] = 4 * mb1[i - 1] + ma0[i] * xi; + mb2[i] = 6 * mb2[i - 1] + ma0[i] * xi * xi; + mb3[i] = 4 * mb3[i - 1] + ma0[i] * xi * xi * xi; + mb4[i] = mb4[i - 1] + ma0[i] * xi * xi * xi * xi; + } +} + +CaloRawFitterGS::FitStatus CaloRawFitterGS::evaluate(gsl::span<short unsigned int> signal) +{ + + //Pedestal analysis mode + if (mPedestalRun) { + int nPed = signal.size(); + mAmp = 0.; + mTime = 0.; + for (auto a : signal) { + mAmp += a; + mTime += a * a; + } + if (nPed > 0) { + mAmp /= nPed; + mTime = mTime / nPed - mAmp * mAmp; + if (mTime > 0.) { + mTime = sqrt(mTime); + } + } + mOverflow = false; + mStatus = kOK; + return kOK; + } + + mStatus = kNotEvaluated; + // Extract amplitude and time + mStatus = evalFit(signal); + return mStatus; +} + +CaloRawFitterGS::FitStatus CaloRawFitterGS::evalFit(gsl::span<short unsigned int> signal) +{ + // Calculate signal parameters (energy, time, quality) from array of samples + // Energy is a maximum sample minus pedestal 9 + // Time is the first time bin + // Signal overflows is there are at least 3 samples of the same amplitude above 900 + + int sigLength = signal.size(); + if (sigLength == 0) { + return kEmptyBunch; + } + mAmp = 0.; + mTime = 0.; + mChi2 = 0.; + mOverflow = false; + FitStatus status = kNotEvaluated; + + //if pedestal should be subtracted first evaluate it + float pedMean = 0; + int nPed = 0; + if (mPedSubtract) { + //remember inverse time order + for (auto it = signal.rbegin(); (nPed < mPreSamples) && it != signal.rend(); ++it) { + nPed++; + pedMean += *it; + } + if (nPed > 0) { + pedMean /= nPed; + } + } + + float maxSample = 0.; //maximal sample value + int nMax = 0; //number of consequitive maximal samples + bool spike = false; //did we observe spike? + int ap = -1, app = -1; //remember previous values to evaluate spikes + double At = 0., Bt = 0., Ct = 0., y2 = 0.; + + int nSamples = signal.size(); + if (mPedSubtract) { + nSamples = -mPreSamples; + } + int firstS = nSamples - 1; + for (int i = 0; i < nSamples; i++) { + float a = signal[firstS - i] - pedMean; //remember inverse order of samples + float xi = i * mDecTime; + if (a > maxSample) { + mMaxSample = a; + nMax = 1; + } + if (a == maxSample) { + nMax++; + } + //check if there was a spike in previous step? + if (app >= 0 && ap >= 0) { + spike = (2 * ap - (a + app) > 2 * mSpikeThreshold); + } + if (spike) { + status = kSpike; + //Try to recover: subtract last point contribution and replace by average of "app" and "a" + float atmp = 0.5 * (app + a); + float xiprev = xi - mDecTime; + float ss = (atmp - ap) * ma0[i - 1]; + At += ss; //spike can not appear at 0-th bin + Bt += ss * xiprev; + Ct += ss * xiprev * xiprev; + y2 += (atmp * atmp - ap * ap); + } else { + app = ap; + ap = a; + } + //Check if in saturation + if (maxSample > 900 && nMax > 3) { + mOverflow = true; + } + + //to calculate time + float st = a * ma0[i]; + At += st; + Bt += st * xi; + Ct += st * xi * xi; + y2 += a * a; + //to calculate amplitude + } //Scanned full sample + + //calculate time, amp and chi2 + double polB = At - Bt; + double polC = Ct - 2. * Bt; + if (At == 0.) { + if (polB == 0.) { + mTime = 999.; + status = kFitFailed; + } else { + mTime = -polC / (2. * polB); + } + } else { + double d = polB * polB - At * polC; + if (d >= 0) { + mTime = (-polB - sqrt(d)) / (At * mDecTime); + } else { + mTime = 999.; + status = kFitFailed; + } + } + if (status == kFitFailed && !mOverflow) { //in case of overflow try to recover + mAmp = 0.; + mTime = 999.; + mChi2 = 999.; + return status; + } + + if (!mOverflow) { //normal sample, calculate amp and chi2 and return + double tt = mTime * mDecTime; + double tt2 = tt * tt; + double expT = exp(tt); + double nom = (At * tt2 - 2. * Bt * tt + Ct) * expT; // 1./(k*k) cancel with denom + int i = nSamples - 1; + double denom = (mb4[i] - tt * (mb3[i] - tt * (mb2[i] - tt * (mb1[i] - tt * mb0[i])))) * + expT * expT / (mDecTime * mDecTime); // 1/(k*k) cancel with nom + if (denom != 0) { + mAmp = nom / denom; + mChi2 = (y2 - (2. * (At * tt2 - 2. * tt * Bt + Ct) - mAmp * denom * expT) * mAmp * expT / (mDecTime * mDecTime)) / (i + 1); + } else { + mAmp = 0.; + status = kFitFailed; + } + return status; + } else { // overflow: try iterative procedure but for lowGain only + if (!mLowGain) { + mAmp = 0.; + mTime = 999.; + mChi2 = 999.; + return kOverflow; + } + + //Try to recalculate parameters replacing overflow/spike values by those expected from the sample shape + short nIter = 0; + double timeOld = mTime; + double ampOld = mAmp; + if (status == kFitFailed) { //could not calculate time, amp: set best guess + timeOld = 0; + ampOld = maxSample; + } + + //Iterative process, not more than NITERATIONS + short nMaxIter = o2::phos::PHOSSimParams::Instance().mNIterations; + for (short nIter = 0; nIter < nMaxIter; nIter++) { + ap = -1; + app = -1; //remember previous values to evaluate spikes + + double expT = exp(mDecTime * timeOld); + for (int i = 0; i < nSamples; i++) { + float a = signal[firstS - i] - pedMean; //remember inverse order of samples + float xi = i * mDecTime; + if (a == maxSample) { //overflow, replace with calculated + a = ampOld * ma0[i] * (timeOld - i) * (timeOld - i) * expT; + } + //check if there was a spike in prev step? + if (app >= 0 && ap >= 0) { + if (2 * ap - (a + app) > 2 * mSpikeThreshold) { + //Try to recover: subtract last point contribution and replace by average of "app" and "a" + float atmp = ampOld * ma0[i] * (timeOld - i + 1) * (timeOld - i + 1) * expT; //0.5*(app+a) ; + float xiprev = xi - mDecTime; + float s = (atmp - ap) * ma0[i - 1]; //spike can not appear at 0-th bin + At += s; + Bt += s * xiprev; + Ct += s * xiprev * xiprev; + y2 += (atmp * atmp - ap * ap); + } + } else { + app = ap; + ap = a; + } + + //to calculate time + float ss = a * ma0[i]; + At += ss; + Bt += ss * xi; + Ct += ss * xi * xi; + y2 += a * a; + } + //evaluate new time and amp + + double polB = At - Bt; + double polC = Ct - 2. * Bt; + if (At == 0.) { + if (polB == 0.) { + mTime = 999.; + status = kFitFailed; + } else { + mTime = -polC / (2. * polB); + } + } else { + double d = polB * polB - At * polC; + if (d >= 0) { + mTime = (-polB - sqrt(d)) / (At * mDecTime); + } else { + mTime = 999.; + status = kFitFailed; + } + } + if (status == kFitFailed) { //Can not improve, give up + mAmp = 0; + mTime = 999.; + mChi2 = 999.; + mOverflow = false; + return status; + } + double tt = mTime * mDecTime; + expT = exp(tt); + double nom = (At * tt * tt - 2. * Bt * tt + Ct) * expT; // 1./(k*k) cancel with denom + int i = nSamples - 1; + double denom = ((mb4[i] - tt * (mb3[i] - tt * (mb2[i] - tt * (mb1[i] - tt * mb0[i]))))) * + expT * expT / (mDecTime * mDecTime); // 1/(k*k) cancel with nom + if (denom != 0) { + mAmp = nom / denom; + mChi2 = (y2 - (2. * (At * tt * tt - 2. * tt * Bt + Ct) - mAmp * denom * expT) * mAmp * expT / (mDecTime * mDecTime)) / (i + 1); + } else { + mAmp = 0; + mTime = 999.; + mChi2 = 999.; + mOverflow = false; + return kFitFailed; + } + + //Check modification and quit if ready + if (std::abs(mTime - timeOld) < mTimeAccuracy && std::abs(mAmp - ampOld) < ampOld * mAmpAccuracy) { + break; + } + + timeOld = mTime; + ampOld = mAmp; + } + } + + return status; +} diff --git a/Detectors/PHOS/reconstruction/src/Clusterer.cxx b/Detectors/PHOS/reconstruction/src/Clusterer.cxx index fc1ae809d9c6b..fcc512a8661c2 100644 --- a/Detectors/PHOS/reconstruction/src/Clusterer.cxx +++ b/Detectors/PHOS/reconstruction/src/Clusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,14 +12,13 @@ /// \file Clusterer.cxx /// \brief Implementation of the PHOS cluster finder #include <memory> +#include "TDecompBK.h" #include "PHOSReconstruction/Clusterer.h" // for LOG #include "PHOSBase/Geometry.h" #include "PHOSBase/PHOSSimParams.h" #include "DataFormatsPHOS/Cluster.h" -#include "PHOSReconstruction/FullCluster.h" #include "DataFormatsPHOS/Digit.h" -#include "CCDB/CcdbApi.h" #include "FairLogger.h" // for LOG @@ -32,196 +32,141 @@ void Clusterer::initialize() if (!mPHOSGeom) { mPHOSGeom = Geometry::GetInstance(); } - mFirstDigitInEvent = 0; - mLastDigitInEvent = -1; + mFirstElememtInEvent = 0; + mLastElementInEvent = -1; } //____________________________________________________________________________ void Clusterer::process(gsl::span<const Digit> digits, gsl::span<const TriggerRecord> dtr, const o2::dataformats::MCTruthContainer<MCLabel>* dmc, - std::vector<Cluster>* clusters, std::vector<TriggerRecord>* trigRec, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC) + std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements, std::vector<TriggerRecord>& trigRec, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC) { - clusters->clear(); //final out list of clusters - trigRec->clear(); - cluMC->clear(); + clusters.clear(); //final out list of clusters + cluelements.clear(); + cluelements.reserve(digits.size()); + trigRec.clear(); + cluMC.clear(); + mProcessMC = (dmc != nullptr); for (const auto& tr : dtr) { - mFirstDigitInEvent = tr.getFirstEntry(); - mLastDigitInEvent = mFirstDigitInEvent + tr.getNumberOfObjects(); - int indexStart = clusters->size(); - mClusters.clear(); // internal list of FullClusters - - LOG(DEBUG) << "Starting clusteriztion digits from " << mFirstDigitInEvent << " to " << mLastDigitInEvent; - - if (!mBadMap) { - if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mBadMap = new BadChannelMap(1); // test default map - mCalibParams = new CalibParams(1); //test calibration map - LOG(INFO) << "No reading BadMap/Calibration from ccdb requested, set default"; - } else { - LOG(INFO) << "Getting BadMap object from ccdb"; - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - long bcTime = 1; //TODO!!! Convert BC time to time o2::InteractionRecord bcTime = digitsTR.front().getBCData() ; - mBadMap = ccdb.retrieveFromTFileAny<o2::phos::BadChannelMap>("PHOS/BadMap", metadata, bcTime); - mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, bcTime); - if (!mBadMap) { - LOG(FATAL) << "[PHOSCellConverter - run] can not get Bad Map"; - } - if (!mCalibParams) { - LOG(FATAL) << "[PHOSCellConverter - run] can not get CalibParams"; - } + int indexStart = clusters.size(); //final out list of clusters + + LOG(DEBUG) << "Starting clusteriztion digits from " << mFirstElememtInEvent << " to " << mLastElementInEvent; + //Convert digits to cluelements + int firstDigitInEvent = tr.getFirstEntry(); + int lastDigitInEvent = firstDigitInEvent + tr.getNumberOfObjects(); + mFirstElememtInEvent = cluelements.size(); + mCluEl.clear(); + mTrigger.clear(); + for (int i = firstDigitInEvent; i < lastDigitInEvent; i++) { + const Digit& digitSeed = digits[i]; + short absId = digitSeed.getAbsId(); + if (digitSeed.isTRU()) { + mTrigger.emplace_back(digitSeed); + continue; + } + if (isBadChannel(absId)) { + continue; } + float energy = calibrate(digitSeed.getAmplitude(), absId, digitSeed.isHighGain()); + if (energy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { + continue; + } + float x = 0., z = 0.; + Geometry::absIdToRelPosInModule(digits[i].getAbsId(), x, z); + mCluEl.emplace_back(absId, digitSeed.isHighGain(), energy, calibrateT(digitSeed.getTime(), absId, digitSeed.isHighGain()), + x, z, digitSeed.getLabel(), 1.); } + mLastElementInEvent = mCluEl.size(); // Collect digits to clusters - makeClusters(digits); + makeClusters(clusters, cluelements); - // Unfold overlapped clusters - // Split clusters with several local maxima if necessary - if (o2::phos::PHOSSimParams::Instance().mUnfoldClusters) { - makeUnfoldings(digits); - } - - // Calculate properties of collected clusters (Local position, energy, disp etc.) - evalCluProperties(digits, clusters, dmc, cluMC); - - LOG(DEBUG) << "Found clusters from " << indexStart << " to " << clusters->size(); - - trigRec->emplace_back(tr.getBCData(), indexStart, clusters->size()); + LOG(DEBUG) << "Found clusters from " << indexStart << " to " << clusters.size(); + trigRec.emplace_back(tr.getBCData(), indexStart, clusters.size() - indexStart); + } + if (mProcessMC) { + evalLabels(clusters, cluelements, dmc, cluMC); } } //____________________________________________________________________________ void Clusterer::processCells(gsl::span<const Cell> cells, gsl::span<const TriggerRecord> ctr, - const o2::dataformats::MCTruthContainer<MCLabel>* dmc, gsl::span<const unsigned int> mcmap, - std::vector<Cluster>* clusters, std::vector<TriggerRecord>* trigRec, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC) + const o2::dataformats::MCTruthContainer<MCLabel>* dmc, + std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements, std::vector<TriggerRecord>& trigRec, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC) { // Transform input Cells to digits and run standard recontruction - clusters->clear(); //final out list of clusters - trigRec->clear(); - cluMC->clear(); - + clusters.clear(); //final out list of clusters + trigRec.clear(); + cluelements.reserve(cells.size()); + cluMC.clear(); + mProcessMC = (dmc != nullptr); + miCellLabel = 0; for (const auto& tr : ctr) { int firstCellInEvent = tr.getFirstEntry(); int lastCellInEvent = firstCellInEvent + tr.getNumberOfObjects(); - int indexStart = clusters->size(); - mClusters.clear(); // internal list of FullClusters - - LOG(DEBUG) << "Starting clusteriztion cells from " << mFirstDigitInEvent << " to " << mLastDigitInEvent; - - if (!mBadMap) { - if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mBadMap = new BadChannelMap(1); // test default map - mCalibParams = new CalibParams(1); //test calibration map - LOG(INFO) << "No reading BadMap/Calibration from ccdb requested, set default"; - } else { - LOG(INFO) << "Getting BadMap object from ccdb"; - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - long bcTime = 1; //TODO!!! Convert BC time to time o2::InteractionRecord bcTime = digitsTR.front().getBCData() ; - mBadMap = ccdb.retrieveFromTFileAny<o2::phos::BadChannelMap>("PHOS/BadMap", metadata, bcTime); - mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, bcTime); - if (!mBadMap) { - LOG(FATAL) << "[PHOSCellConverter - run] can not get Bad Map"; - } - if (!mCalibParams) { - LOG(FATAL) << "[PHOSCellConverter - run] can not get CalibParams"; - } + int indexStart = clusters.size(); //final out list of clusters + LOG(DEBUG) << "Starting clusteriztion cells from " << firstCellInEvent << " to " << lastCellInEvent; + //convert cells to cluelements + mFirstElememtInEvent = cluelements.size(); + mCluEl.clear(); + mTrigger.clear(); + for (int i = firstCellInEvent; i < lastCellInEvent; i++) { + const Cell c = cells[i]; + short absId = c.getAbsId(); + if (c.getTRU()) { + mTrigger.emplace_back(c.getTRUId(), c.getEnergy(), c.getTime(), 0); + continue; } + if (isBadChannel(absId)) { + continue; + } + float energy = calibrate(c.getEnergy(), absId, c.getHighGain()); + if (energy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { + continue; + } + float x = 0., z = 0.; + Geometry::absIdToRelPosInModule(absId, x, z); + mCluEl.emplace_back(absId, c.getHighGain(), energy, calibrateT(c.getTime(), absId, c.getHighGain()), + x, z, i, 1.); } + mLastElementInEvent = cluelements.size(); - convertCellsToDigits(cells, firstCellInEvent, lastCellInEvent, mcmap); - - // Collect digits to clusters - makeClusters(mDigits); - - // Unfold overlapped clusters - // Split clusters with several local maxima if necessary - if (o2::phos::PHOSSimParams::Instance().mUnfoldClusters) { - makeUnfoldings(mDigits); - } - - // Calculate properties of collected clusters (Local position, energy, disp etc.) - evalCluProperties(mDigits, clusters, dmc, cluMC); - - LOG(DEBUG) << "Found clusters from " << indexStart << " to " << clusters->size(); + makeClusters(clusters, cluelements); - trigRec->emplace_back(tr.getBCData(), indexStart, clusters->size()); - } -} -//____________________________________________________________________________ -void Clusterer::convertCellsToDigits(gsl::span<const Cell> cells, int firstCellInEvent, int lastCellInEvent, gsl::span<const unsigned int> mcmap) -{ - - mDigits.clear(); - if (mDigits.capacity() < lastCellInEvent - firstCellInEvent) { - mDigits.reserve(lastCellInEvent - firstCellInEvent); - } - int iLab = 0, nLab = mcmap.size(); - while (iLab < nLab) { - if (mcmap[iLab] >= firstCellInEvent) { - break; - } - ++iLab; + LOG(DEBUG) << "Found clusters from " << indexStart << " to " << clusters.size(); + trigRec.emplace_back(tr.getBCData(), indexStart, clusters.size() - indexStart); } - - for (int i = firstCellInEvent; i < lastCellInEvent; i++) { - const Cell c = cells[i]; - //short cell, float amplitude, float time, int label - int label = -1; - if (mcmap[iLab] == i) { - label = iLab; - ++iLab; - if (iLab >= nLab) { - --iLab; - } - } - mDigits.emplace_back(c.getAbsId(), c.getEnergy(), c.getTime(), label); - mDigits.back().setHighGain(c.getHighGain()); + if (mProcessMC) { + evalLabels(clusters, cluelements, dmc, cluMC); } - mFirstDigitInEvent = 0; - mLastDigitInEvent = mDigits.size(); } //____________________________________________________________________________ -void Clusterer::makeClusters(gsl::span<const Digit> digits) +void Clusterer::makeClusters(std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements) { - // A cluster is defined as a list of neighbour digits - - // Mark all digits as unused yet - const int maxNDigits = 12546; // There is no digits more than in PHOS modules ;) - bool digitsUsed[maxNDigits]; - memset(digitsUsed, 0, sizeof(bool) * maxNDigits); - - int iFirst = mFirstDigitInEvent; // first index of digit which potentially can be a part of cluster - - for (int i = iFirst; i < mLastDigitInEvent; i++) { - if (digitsUsed[i - mFirstDigitInEvent]) { + // A cluster is defined as a list of neighbour digits (as defined in Geometry::areNeighbours) + // Cluster contains first and (next-to) last index of the combined list of clusterelements, so + // add elements to final list and mark element in internal list as used (zero energy) + + int iFirst = 0; // first index of digit which potentially can be a part of cluster + int n = mCluEl.size(); + for (int i = iFirst; i < n; i++) { + if (mCluEl[i].energy == 0) { //already used continue; } - const Digit& digitSeed = digits[i]; - float digitSeedEnergy = calibrate(digitSeed.getAmplitude(), digitSeed.getAbsId()); - if (isBadChannel(digitSeed.getAbsId())) { - digitSeedEnergy = 0.; - } - if (digitSeedEnergy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { - continue; - } + CluElement& digitSeed = mCluEl[i]; // is this digit so energetic that start cluster? - FullCluster* clu = nullptr; + Cluster* clu = nullptr; int iDigitInCluster = 0; - if (digitSeedEnergy > o2::phos::PHOSSimParams::Instance().mClusteringThreshold) { + if (digitSeed.energy > o2::phos::PHOSSimParams::Instance().mClusteringThreshold) { // start new cluster - mClusters.emplace_back(digitSeed.getAbsId(), digitSeedEnergy, - calibrateT(digitSeed.getTime(), digitSeed.getAbsId(), digitSeed.isHighGain()), - digitSeed.getLabel(), 1.); - clu = &(mClusters.back()); - - digitsUsed[i - mFirstDigitInEvent] = true; + clusters.emplace_back(); + clu = &(clusters.back()); + clu->setFirstCluEl(cluelements.size()); + cluelements.emplace_back(digitSeed); + digitSeed.energy = 0; iDigitInCluster = 1; } else { continue; @@ -229,23 +174,16 @@ void Clusterer::makeClusters(gsl::span<const Digit> digits) // Now scan remaining digits in list to find neigbours of our seed int index = 0; while (index < iDigitInCluster) { // scan over digits already in cluster - short digitSeedAbsId = clu->getDigitAbsId(index); + short digitSeedAbsId = cluelements.at(clu->getFirstCluEl() + index).absId; index++; - for (Int_t j = iFirst; j < mLastDigitInEvent; j++) { - if (digitsUsed[j - mFirstDigitInEvent]) { + for (int j = iFirst; j < n; j++) { + if (mCluEl[j].energy == 0) { continue; // look through remaining digits } - const Digit* digitN = &(digits[j]); - float digitNEnergy = calibrate(digitN->getAmplitude(), digitN->getAbsId()); - if (isBadChannel(digitN->getAbsId())) { //remove digit - digitNEnergy = 0.; - } - if (digitNEnergy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { - continue; - } + CluElement& digitN = mCluEl[j]; // call (digit,digitN) in THAT oder !!!!! - Int_t ineb = mPHOSGeom->areNeighbours(digitSeedAbsId, digitN->getAbsId()); + Int_t ineb = Geometry::areNeighbours(digitSeedAbsId, digitN.absId); switch (ineb) { case -1: // too early (e.g. previous module), do not look before j at subsequent passes iFirst = j; @@ -253,9 +191,9 @@ void Clusterer::makeClusters(gsl::span<const Digit> digits) case 0: // not a neighbour break; case 1: // are neighbours - clu->addDigit(digitN->getAbsId(), digitNEnergy, calibrateT(digitN->getTime(), digitN->getAbsId(), digitN->isHighGain()), digitN->getLabel(), 1.); + cluelements.emplace_back(digitN); + digitN.energy = 0; iDigitInCluster++; - digitsUsed[j - mFirstDigitInEvent] = true; break; case 2: // too far from each other default: @@ -263,34 +201,48 @@ void Clusterer::makeClusters(gsl::span<const Digit> digits) } // switch } } // loop over cluster - } // energy theshold + clu->setLastCluEl(cluelements.size()); + + // Unfold overlapped clusters + // Split clusters with several local maxima if necessary + if (o2::phos::PHOSSimParams::Instance().mUnfoldClusters) { + makeUnfolding(*clu, clusters, cluelements); + } else { + evalAll(*clu, cluelements); + if (clu->getEnergy() < 1.e-4) { //remove cluster and belonging to it elements + for (int i = clu->getMultiplicity(); i--;) { + cluelements.pop_back(); + } + clusters.pop_back(); + } + } + + } // energy theshold } //__________________________________________________________________________ -void Clusterer::makeUnfoldings(gsl::span<const Digit> digits) +void Clusterer::makeUnfolding(Cluster& clu, std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements) { //Split cluster if several local maxima are found + if (clu.getNExMax() > -1) { //already unfolded + return; + } - std::vector<int> maxAt(o2::phos::PHOSSimParams::Instance().mNLMMax); // NLMMax:Maximal number of local maxima - - int numberOfNotUnfolded = mClusters.size(); - - for (int i = 0; i < numberOfNotUnfolded; i++) { //can not use iterator here as list can expand - FullCluster& clu = mClusters[i]; - if (clu.getNExMax() > -1) { //already unfolded - continue; - } - char nMultipl = clu.getMultiplicity(); - char nMax = clu.getNumberOfLocalMax(maxAt); - if (nMax > 1) { - unfoldOneCluster(clu, nMax, maxAt, digits); - clu.setEnergy(0); // will be skipped later - } else { - clu.setNExMax(nMax); // Only one local maximum + char nMax = getNumberOfLocalMax(clu, cluelements); + if (nMax > 1) { + unfoldOneCluster(clu, nMax, clusters, cluelements); + } else { + clu.setNExMax(nMax); // Only one local maximum + evalAll(clu, cluelements); + if (clu.getEnergy() < 1.e-4) { //remove cluster and belonging to it elements + for (int i = clu.getMultiplicity(); i--;) { + cluelements.pop_back(); + } + clusters.pop_back(); } } } //____________________________________________________________________________ -void Clusterer::unfoldOneCluster(FullCluster& iniClu, char nMax, gsl::span<int> digitId, gsl::span<const Digit> digits) +void Clusterer::unfoldOneCluster(Cluster& iniClu, char nMax, std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements) { // Performs the unfolding of a cluster with nMax overlapping showers // Parameters: iniClu cluster to be unfolded @@ -300,229 +252,416 @@ void Clusterer::unfoldOneCluster(FullCluster& iniClu, char nMax, gsl::span<int> // Take initial cluster and calculate local coordinates of digits // To avoid multiple re-calculation of same parameters - char mult = iniClu.getMultiplicity(); + short mult = iniClu.getMultiplicity(); std::vector<std::vector<float>> eInClusters(mult, std::vector<float>(nMax)); - std::vector<std::vector<float>> fij(mult, std::vector<float>(nMax)); - - const std::vector<FullCluster::CluElement>* cluElist = iniClu.getElementList(); - - // Coordinates of centers of clusters - std::vector<float> xMax(nMax); - std::vector<float> zMax(nMax); - std::vector<float> eMax(nMax); - std::vector<float> deNew(nMax); - - //transient variables - std::vector<float> a(nMax); - std::vector<float> b(nMax); - std::vector<float> c(nMax); - - for (int iclu = 0; iclu < nMax; iclu++) { - xMax[iclu] = (*cluElist)[digitId[iclu]].localX; - zMax[iclu] = (*cluElist)[digitId[iclu]].localZ; - eMax[iclu] = 2. * (*cluElist)[digitId[iclu]].energy; + uint32_t firstCE = iniClu.getFirstCluEl(); + uint32_t lastCE = iniClu.getLastCluEl(); + + mProp.reserve(mult * nMax); + + for (int iclu = nMax; iclu--;) { + CluElement& ce = cluelements[mMaxAt[iclu]]; + mxMax[iclu] = ce.localX; + mzMax[iclu] = ce.localZ; + meMax[iclu] = ce.energy; + mxMaxPrev[iclu] = mxMax[iclu]; + mzMaxPrev[iclu] = mzMax[iclu]; } - std::vector<float> prop(nMax); // proportion of clusters in the current digit + TMatrixDSym B(nMax); + TVectorD C(nMax); + TDecompBK bk(nMax); // Try to decompose cluster to contributions int nIterations = 0; bool insuficientAccuracy = true; + double chi2Previous = 1.e+6; + double step = 0.2; while (insuficientAccuracy && nIterations < o2::phos::PHOSSimParams::Instance().mNMaxIterations) { insuficientAccuracy = false; // will be true if at least one parameter changed too much - a.clear(); - b.clear(); - c.clear(); - //First calculate shower shapes - for (int idig = 0; idig < mult; idig++) { - auto it = (*cluElist)[idig]; - for (int iclu = 0; iclu < nMax; iclu++) { - fij[idig][iclu] = showerShape(it.localX - xMax[iclu], it.localZ - zMax[iclu]); - } + B.Zero(); + C.Zero(); + mProp.clear(); + double chi2 = 0.; + for (int iclu = nMax; iclu--;) { + mA[iclu] = 0; + mxB[iclu] = 0; + mzB[iclu] = 0; } - - //Fit energies - for (int idig = 0; idig < mult; idig++) { - auto it = (*cluElist)[idig]; + //Fill matrix and vector + for (int idig = firstCE; idig < lastCE; idig++) { + CluElement& ce = cluelements[idig]; + double sumA = 0.; + for (int iclu = nMax; iclu--;) { + double lx = ce.localX - mxMax[iclu]; + double lz = ce.localZ - mzMax[iclu]; + double r2 = lx * lx + lz * lz; + double deriv = 0; + double ss = showerShape(r2, deriv); + mfij[iclu] = ss; + mfijr[iclu] = deriv; + mfijx[iclu] = deriv * ce.localX; //derivatives + mfijz[iclu] = deriv * ce.localZ; + sumA += ss * meMax[iclu]; + C(iclu) += ce.energy * ss; + } + double dE = ce.energy - sumA; + chi2 += dE * dE; for (int iclu = 0; iclu < nMax; iclu++) { - a[iclu] += fij[idig][iclu] * fij[idig][iclu]; - b[iclu] += it.energy * fij[idig][iclu]; - for (int kclu = 0; kclu < nMax; kclu++) { - if (iclu == kclu) { - continue; - } - c[iclu] += eMax[kclu] * fij[idig][iclu] * fij[idig][kclu]; + for (int jclu = iclu; jclu < nMax; jclu++) { + B(iclu, jclu) += mfij[iclu] * mfij[jclu]; } + mA[iclu] += mfijr[iclu] * dE; + mxB[iclu] += mfijx[iclu] * dE; + mzB[iclu] += mfijz[iclu] * dE; + mProp[(idig - firstCE) * nMax + iclu] = mfij[iclu] * meMax[iclu] / sumA; } } - //Evaluate new maximal energies - for (int iclu = 0; iclu < nMax; iclu++) { - if (a[iclu] != 0.) { - float eNew = (b[iclu] - c[iclu]) / a[iclu]; - insuficientAccuracy += (std::abs(eMax[iclu] - eNew) > eNew * o2::phos::PHOSSimParams::Instance().mUnfogingEAccuracy); - eMax[iclu] = eNew; + if (nIterations > 0 && chi2 > chi2Previous) { //too big step + step = 0.5 * step; + for (int iclu = nMax; iclu--;) { + mxMax[iclu] = mxMaxPrev[iclu] + step * mdx[iclu]; + mzMax[iclu] = mzMaxPrev[iclu] + step * mdz[iclu]; } - } // otherwise keep old value + nIterations++; + insuficientAccuracy = true; + continue; + } + //Good iteration, move further + step = 0.2; + chi2Previous = chi2; + for (int iclu = nMax; iclu--;) { + mxMaxPrev[iclu] = mxMax[iclu]; + mzMaxPrev[iclu] = mzMax[iclu]; + } - // Loop over all digits of parent cluster and split their energies between daughter clusters - // according to shower shape - // then re-evaluate local position of clusters - for (int idig = 0; idig < mult; idig++) { - float eEstimated = 0; - for (int iclu = 0; iclu < nMax; iclu++) { - prop[iclu] = eMax[iclu] * fij[idig][iclu]; - eEstimated += prop[iclu]; + //calculate next step using derivative + //fill remaning part of B + for (int iclu = 1; iclu < nMax; iclu++) { + for (int jclu = 0; jclu < iclu; jclu++) { + B(iclu, jclu) = B(jclu, iclu); } - if (eEstimated == 0.) { // numerical accuracy - continue; + } + for (int iclu = nMax; iclu--;) { + if (mA[iclu] != 0) { + mdx[iclu] = mxB[iclu] / mA[iclu] - mxMaxPrev[iclu]; + mdz[iclu] = mzB[iclu] / mA[iclu] - mzMaxPrev[iclu]; } - // Split energy of digit according to contributions + } + + for (int iclu = nMax; iclu--;) { + //a-la Fletcher-Rivs algorithm + mdx[iclu] += 0.2 * mdxprev[iclu]; + mdz[iclu] += 0.2 * mdzprev[iclu]; + mdxprev[iclu] = mdx[iclu]; + mdzprev[iclu] = mdz[iclu]; + insuficientAccuracy |= fabs(step * mdx[iclu]) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy; + insuficientAccuracy |= fabs(step * mdz[iclu]) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy; + mxMax[iclu] = mxMaxPrev[iclu] + step * mdx[iclu]; + mzMax[iclu] = mzMaxPrev[iclu] + step * mdz[iclu]; + } + //now exact solution for amplitudes + bk.SetMatrix(B); + if (bk.Solve(C)) { for (int iclu = 0; iclu < nMax; iclu++) { - eInClusters[idig][iclu] = (*cluElist)[idig].energy * prop[iclu] / eEstimated; + double eOld = meMax[iclu]; + meMax[iclu] = C(iclu); + // insuficientAccuracy|=fabs(meMax[iclu]-eOld)> meMax[iclu]*o2::phos::PHOSSimParams::Instance().mUnfogingEAccuracy ; } } + insuficientAccuracy &= (chi2 > o2::phos::PHOSSimParams::Instance().mUnfogingChi2Accuracy * nMax); + nIterations++; + } - // Recalculate parameters of clusters and check relative variation of energy and absolute of position - for (int iclu = 0; iclu < nMax; iclu++) { - float oldX = xMax[iclu]; - float oldZ = zMax[iclu]; - // full energy, need for weight - float eTotNew = 0; - for (int idig = 0; idig < mult; idig++) { - eTotNew += eInClusters[idig][iclu]; + // Iterations finished, put first new cluster into place of mother one, others to the end of list + for (int iclu = nMax; iclu--;) { + //copy cluElements to the final list + int start = cluelements.size(); + int nce = 0; + for (int idig = firstCE; idig < lastCE; idig++) { + float eDigit = eInClusters[idig - firstCE][iclu]; + CluElement& el = cluelements[idig]; + float ei = el.energy * mProp[(idig - firstCE) * nMax + iclu]; + if (ei > o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { + cluelements.emplace_back(el); + cluelements.back().energy = ei; + cluelements.back().fraction = mProp[(idig - firstCE) * nMax + iclu]; + nce++; } - xMax[iclu] = 0; - zMax[iclu] = 0.; - float wtot = 0.; - for (int idig = 0; idig < mult; idig++) { - if (eInClusters[idig][iclu] > 0) { - // In unfolding it is better to use linear weight to reduce contribution of unfolded tails - float w = eInClusters[idig][iclu] / eTotNew; - // float w = std::max(std::log(eInClusters[idig][iclu] / eTotNew) + o2::phos::PHOSSimParams::Instance().mLogWeight, float(0.)); - xMax[iclu] += (*cluElist)[idig].localX * w; - zMax[iclu] += (*cluElist)[idig].localZ * w; - wtot += w; + } + if (iclu == 0) { //replace parent + iniClu.setNExMax(nMax); + iniClu.setFirstCluEl(start); + iniClu.setLastCluEl(start + nce); + evalAll(iniClu, cluelements); + if (iniClu.getEnergy() < 1.e-4) { //remove cluster and belonging to it elements + for (int i = iniClu.getMultiplicity(); i--;) { + cluelements.pop_back(); } + clusters.pop_back(); } - if (wtot > 0.) { - wtot = 1. / wtot; - xMax[iclu] *= wtot; - zMax[iclu] *= wtot; + } else { + clusters.emplace_back(); + Cluster& clu = clusters.back(); + clu.setNExMax(nMax); + clu.setFirstCluEl(start); + clu.setLastCluEl(start + nce); + evalAll(clu, cluelements); + if (clu.getEnergy() < 1.e-4) { //remove cluster and belonging to it elements + for (int i = clu.getMultiplicity(); i--;) { + cluelements.pop_back(); + } + clusters.pop_back(); } - // Compare variation of parameters - insuficientAccuracy += (std::abs(xMax[iclu] - oldX) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy); - insuficientAccuracy += (std::abs(zMax[iclu] - oldZ) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy); } - nIterations++; } - // Iterations finished, add new clusters - for (int iclu = 0; iclu < nMax; iclu++) { - mClusters.emplace_back(); - FullCluster& clu = mClusters.back(); - clu.setNExMax(nMax); - int idig = 0; - for (int idig = 0; idig < mult; idig++) { - float eDigit = eInClusters[idig][iclu]; - idig++; - if (eDigit < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) { +} + +//____________________________________________________________________________ +void Clusterer::evalLabels(std::vector<Cluster>& clusters, std::vector<CluElement>& cluElements, + const o2::dataformats::MCTruthContainer<MCLabel>* dmc, + o2::dataformats::MCTruthContainer<MCLabel>& cluMC) +{ + + int labelIndex = cluMC.getIndexedSize(); + auto clu = clusters.begin(); + + while (clu != clusters.end()) { + //Calculate list of primaries + //loop over entries in digit MCTruthContainer + for (uint32_t id = clu->getFirstCluEl(); id < clu->getLastCluEl(); id++) { + CluElement& ll = cluElements[id]; + int i = ll.label; //index + float sc = ll.fraction; + gsl::span<const MCLabel> spDigList = dmc->getLabels(i); + if (spDigList.size() == 0 || spDigList.begin()->isFake()) { continue; } - clu.addDigit((*cluElist)[idig].absId, eDigit, (*cluElist)[idig].time, (*cluElist)[idig].label, eDigit / (*cluElist)[idig].energy); + gsl::span<MCLabel> spCluList = cluMC.getLabels(labelIndex); //get updated list + auto digL = spDigList.begin(); + while (digL != spDigList.end()) { + if (digL->isFake()) { + digL++; + continue; + } + bool merged = false; + auto cluL = spCluList.begin(); + while (cluL != spCluList.end()) { + if (*digL == *cluL) { + (*cluL).add(*digL, sc); + merged = true; + break; + } + ++cluL; + } + if (!merged) { //just add label + if (sc == 1.) { + cluMC.addElement(labelIndex, (*digL)); + } else { //rare case of unfolded clusters + MCLabel tmpL = (*digL); + tmpL.scale(sc); + cluMC.addElement(labelIndex, tmpL); + } + } + ++digL; + } } + labelIndex++; + ++clu; } } - //____________________________________________________________________________ -void Clusterer::evalCluProperties(gsl::span<const Digit> digits, std::vector<Cluster>* clusters, - const o2::dataformats::MCTruthContainer<MCLabel>* dmc, - o2::dataformats::MCTruthContainer<MCLabel>* cluMC) +double Clusterer::showerShape(double r2, double& deriv) { + // Shape of the shower (see PHOS TDR) + // we neglect dependence on the incident angle. - if (clusters->capacity() - clusters->size() < mClusters.size()) { //avoid expanding vector per element - clusters->reserve(clusters->size() + mClusters.size()); + // const float width = 1. / (2. * 2.32 * 2.32 * 2.32 * 2.32 * 2.32 * 2.32); + // const float width = 1. / (2. * 2.32 * 2.32 * 2.32 * 2.32 ); + // return TMath::Exp(-r2 * r2 * width); + if (r2 == 0.) { + deriv = 0; + return 1.; } + double r4 = r2 * r2; + double r295 = TMath::Power(r2, 2.95 / 2.); + double a = 2.32 + 0.26 * r4; + double b = 31.645570 + 2.0632911 * r295; + double s = TMath::Exp(-r4 * ((a + b) / (a * b))); + deriv = -2. * s * r2 * (2.32 / (a * a) + (0.54161392 * r295 + 31.645570) / (b * b)); + return s; +} - int labelIndex = 0; - if (cluMC) { - labelIndex = cluMC->getIndexedSize(); +//____________________________________________________________________________ +void Clusterer::evalAll(Cluster& clu, std::vector<CluElement>& cluel) const +{ + //position, energy, coreEnergy, dispersion, time, + + // Calculates the center of gravity in the local PHOS-module coordinates + // Note that correction for non-perpendicular incidence will be applied later + // when vertex will be known. + float fullEnergy = 0.; + float time = 0.; + float eMax = 0.; + uint32_t iFirst = clu.getFirstCluEl(), iLast = clu.getLastCluEl(); + clu.setModule(Geometry::absIdToModule(cluel[iFirst].absId)); + float eMin = o2::phos::PHOSSimParams::Instance().mDigitMinEnergy; + for (uint32_t i = iFirst; i < iLast; i++) { + float ei = cluel[i].energy; + if (ei < eMin) { + continue; + } + fullEnergy += ei; + if (ei > eMax) { + time = cluel[i].time; + eMax = ei; + } } - auto clu = mClusters.begin(); - - while (clu != mClusters.end()) { - - if (clu->getEnergy() < 1.e-4) { //Marked earlier for removal - ++clu; + clu.setEnergy(fullEnergy); + if (fullEnergy <= 0) { + return; + } + // Calculate time as time in the digit with maximal energy + clu.setTime(time); + + float localPosX = 0., localPosZ = 0.; + float wtot = 0.; + float invE = 1. / fullEnergy; + for (uint32_t i = iFirst; i < iLast; i++) { + CluElement& ce = cluel[i]; + if (ce.energy < eMin) { continue; } + float w = std::max(float(0.), o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(ce.energy * invE)); + localPosX += ce.localX * w; + localPosZ += ce.localZ * w; + wtot += w; + } + if (wtot > 0) { + wtot = 1. / wtot; + localPosX *= wtot; + localPosZ *= wtot; + } + clu.setLocalPosition(localPosX, localPosZ); + + //Dispersion, core energy + float coreRadius2 = o2::phos::PHOSSimParams::Instance().mCoreR; + coreRadius2 *= coreRadius2; + float coreE = 0.; + float dispersion = 0.; + float dxx = 0., dxz = 0., dzz = 0., lambdaLong = 0., lambdaShort = 0.; + for (uint32_t i = iFirst; i < iLast; i++) { + CluElement& ce = cluel[i]; + float ei = ce.energy; + if (ei < eMin) { + continue; + } + float x = ce.localX - localPosX; + float z = ce.localZ - localPosZ; + float distance = x * x + z * z; + + float w = std::max(float(0.), o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(ei * invE)); + dispersion += w * distance; + dxx += w * x * x; + dzz += w * z * z; + dxz += w * x * z; + if (distance < coreRadius2) { + coreE += ei; + } + } + clu.setCoreEnergy(coreE); + //dispersion + if (wtot > 0) { + wtot = 1. / wtot; + dispersion *= wtot; + + dxx *= wtot; + dzz *= wtot; + dxz *= wtot; + + lambdaLong = 0.5 * (dxx + dzz) + std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz); + if (lambdaLong > 0) { + lambdaLong = std::sqrt(lambdaLong); + } - // may be soft digits remain after unfolding - clu->purify(); - - // LOG(DEBUG) << "Purify done"; - clu->evalAll(); - - if (clu->getEnergy() > 1.e-4) { //Non-empty cluster - clusters->emplace_back(*clu); - - if (cluMC) { //Handle labels - //Calculate list of primaries - //loop over entries in digit MCTruthContainer - const std::vector<FullCluster::CluElement>* vl = clu->getElementList(); - auto ll = vl->begin(); - while (ll != vl->end()) { - int i = (*ll).label; //index - float sc = (*ll).scale; - if (i < 0) { - ++ll; - continue; - } - gsl::span<const MCLabel> spDigList = dmc->getLabels(i); - gsl::span<MCLabel> spCluList = cluMC->getLabels(labelIndex); //get updated list - auto digL = spDigList.begin(); - while (digL != spDigList.end()) { - bool merged = false; - auto cluL = spCluList.begin(); - while (cluL != spCluList.end()) { - if (*digL == *cluL) { - (*cluL).add(*digL, sc); - merged = true; - break; - } - ++cluL; - } - if (!merged) { //just add label - if (sc == 1.) { - cluMC->addElement(labelIndex, (*digL)); - } else { //rare case of unfolded clusters - MCLabel tmpL = (*digL); - tmpL.scale(sc); - cluMC->addElement(labelIndex, tmpL); - } - } - ++digL; - } - ++ll; - } - clusters->back().setLabel(labelIndex); - labelIndex++; - } // Work with MC + lambdaShort = 0.5 * (dxx + dzz) - std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz); + if (lambdaShort > 0) { // To avoid exception if numerical errors lead to negative lambda. + lambdaShort = std::sqrt(lambdaShort); + } else { + lambdaShort = 0.; } + } + if (dispersion >= 0) { + clu.setDispersion(std::sqrt(dispersion)); + } else { + clu.setDispersion(0.); + } + clu.setElipsAxis(lambdaShort, lambdaLong); - ++clu; + //Test trigger + char relId[3]; + Geometry::relPosToRelId(clu.module(), localPosX, localPosZ, relId); + + for (auto& trd : mTrigger) { + char trurelid[3]; + Geometry::truAbsToRelNumbering(trd.getAbsId(), trurelid); + + int dx = relId[1] - trurelid[1]; + int dz = relId[2] - trurelid[2]; + if (dx > -2 && dx < 3 && dz > -2 && dz < 3) { + clu.setFiredTrigger(trd.isHighGain()); + break; + } } } //____________________________________________________________________________ -float Clusterer::showerShape(float x, float z) +char Clusterer::getNumberOfLocalMax(Cluster& clu, std::vector<CluElement>& cluel) { - // Shape of the shower (see PHOS TDR) - // we neglect dependence on the incident angle. + // Calculates the number of local maxima in the cluster using LocalMaxCut as the minimum + // energy difference between maximum and surrounding digits + + float locMaxCut = o2::phos::PHOSSimParams::Instance().mLocalMaximumCut; + float cluSeed = o2::phos::PHOSSimParams::Instance().mClusteringThreshold; + mIsLocalMax.clear(); + mIsLocalMax.reserve(clu.getMultiplicity()); + + uint32_t iFirst = clu.getFirstCluEl(), iLast = clu.getLastCluEl(); + for (uint32_t i = iFirst; i < iLast; i++) { + mIsLocalMax.push_back(cluel[i].energy > cluSeed); + } - const float width = 1. / (2. * 2.32 * 2.32 * 2.32 * 2.32 * 2.32 * 2.32); - float r2 = x * x + z * z; - return TMath::Exp(-r2 * r2 * r2 * width); -/* float r2 = x * x + z * z; - float r4 = r2 * r2; - float r295 = TMath::Power(r2, 2.95 / 2.); - float shape = TMath::Exp(-r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295))); - return shape; -*/} + for (uint32_t i = iFirst; i < iLast - 1; i++) { + for (int j = i + 1; j < iLast; j++) { + + if (Geometry::areNeighbours(cluel[i].absId, cluel[j].absId) == 1) { + if (cluel[i].energy > cluel[j].energy) { + mIsLocalMax[j - iFirst] = false; + // but may be digit too is not local max ? + if (cluel[j].energy > cluel[i].energy - locMaxCut) { + mIsLocalMax[i - iFirst] = false; + } + } else { + mIsLocalMax[i - iFirst] = false; + // but may be digitN is not local max too? + if (cluel[i].energy > cluel[j].energy - locMaxCut) { + mIsLocalMax[j - iFirst] = false; + } + } + } // if areneighbours + } // digit j + } // digit i + + int iDigitN = 0; + for (int i = 0; i < mIsLocalMax.size(); i++) { + if (mIsLocalMax[i]) { + mMaxAt[iDigitN] = i + iFirst; + iDigitN++; + if (iDigitN >= NLOCMAX) { // Note that size of output arrays is limited: + LOG(ERROR) << "Too many local maxima, cluster multiplicity " << mIsLocalMax.size(); + return -2; + } + } + } + + return iDigitN; +} diff --git a/Detectors/PHOS/reconstruction/src/FullCluster.cxx b/Detectors/PHOS/reconstruction/src/FullCluster.cxx deleted file mode 100644 index 38d9fc69d3894..0000000000000 --- a/Detectors/PHOS/reconstruction/src/FullCluster.cxx +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFormatsPHOS/Cluster.h" -#include "PHOSReconstruction/FullCluster.h" -#include "PHOSBase/Geometry.h" -#include "PHOSBase/PHOSSimParams.h" - -#include "FairLogger.h" // for LOG - -using namespace o2::phos; - -ClassImp(FullCluster); - -FullCluster::FullCluster(short digitAbsId, float energy, float time, int label, float scale) - : Cluster() -{ - addDigit(digitAbsId, energy, time, label, scale); -} -//____________________________________________________________________________ -void FullCluster::addDigit(short digitIndex, float energy, float time, int label, float scale) -{ - - // Adds digit to the FullCluster - // and accumulates the total amplitude and the multiplicity, list of primaries - float x = 0., z = 0.; - Geometry* phosGeom = Geometry::GetInstance(); - phosGeom->absIdToRelPosInModule(digitIndex, x, z); - - mElementList.emplace_back(digitIndex, energy, time, x, z, label, scale); - mFullEnergy += energy; //To be updated when calculate cluster properties. - mMulDigit++; -} -//____________________________________________________________________________ -void FullCluster::evalAll() -{ - // Evaluate cluster parameters - evalCoreEnergy(); - evalLocalPosition(); - evalElipsAxis(); - evalDispersion(); - evalTime(); -} -//____________________________________________________________________________ -void FullCluster::purify() -{ - // Removes digits below threshold - - float threshold = o2::phos::PHOSSimParams::Instance().mDigitMinEnergy; - Geometry* phosGeom = Geometry::GetInstance(); - - std::vector<CluElement>::iterator itEl = mElementList.begin(); - while (itEl != mElementList.end()) { - if ((*itEl).energy < threshold) { //very rare case - itEl = mElementList.erase(itEl); - } else { - ++itEl; - } - } - - mMulDigit = mElementList.size(); - - if (mMulDigit == 0) { // too soft cluster - mFullEnergy = 0.; - return; - } - - // Remove non-connected cells - if (mMulDigit > 1) { - mFullEnergy = 0.; // Recalculate total energy - auto it = mElementList.begin(); - while (it != mElementList.end()) { - bool hasNeighbours = false; - for (auto jt = mElementList.begin(); jt != mElementList.end(); ++jt) { - if (it == jt) { - continue; - } - if (phosGeom->areNeighbours((*it).absId, (*jt).absId) == 1) { - hasNeighbours = true; - break; - } - } - if (!hasNeighbours) { //Isolated digits are rare - it = mElementList.erase(it); - --mMulDigit; - } else { - mFullEnergy += (*it).energy; - ++it; - } - } - } else { - mFullEnergy = mElementList[0].energy; - } -} -//____________________________________________________________________________ -void FullCluster::evalCoreEnergy() -{ - // This function calculates energy in the core, - // i.e. within a radius coreRadius (~3cm) around the center. Beyond this radius - // in accordance with shower profile the energy deposition - // should be less than 2% - - if (mLocalPosX < -900.) // local position was not calculated yiet - { - evalLocalPosition(); - } - - float coreRadius = o2::phos::PHOSSimParams::Instance().mCoreR; - for (auto it : mElementList) { - Float_t distance = std::sqrt((it.localX - mLocalPosX) * (it.localX - mLocalPosX) + - (it.localZ - mLocalPosZ) * (it.localZ - mLocalPosX)); - if (distance < coreRadius) { - mCoreEnergy += it.energy; - } - } -} -//____________________________________________________________________________ -void FullCluster::evalLocalPosition() -{ - // Calculates the center of gravity in the local PHOS-module coordinates - // Note that correction for non-perpendicular incidence will be applied later - // when vertex will be known. - - if (mFullEnergy <= 0.) { // zero energy cluster, position undefined - mLocalPosX = -999.; - mLocalPosZ = -999.; - return; - } - - // find module number - Geometry* phosGeom = Geometry::GetInstance(); - mModule = phosGeom->absIdToModule(mElementList[0].absId); - - float wtot = 0.; - mLocalPosX = 0.; - mLocalPosZ = 0.; - float invE = 1. / mFullEnergy; - for (auto it : mElementList) { - float w = std::max(float(0.), o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(it.energy * invE)); - mLocalPosX += it.localX * w; - mLocalPosZ += it.localZ * w; - wtot += w; - } - if (wtot > 0) { - wtot = 1. / wtot; - mLocalPosX *= wtot; - mLocalPosZ *= wtot; - } -} -//____________________________________________________________________________ -void FullCluster::evalDispersion() -{ // computes the dispersion of the shower - - mDispersion = 0.; - if (mFullEnergy <= 0.) { // zero energy cluster, dispersion undefined - return; - } - if (mLocalPosX < -900.) // local position was not calculated yiet - { - evalLocalPosition(); - } - - float wtot = 0.; - float invE = 1. / mFullEnergy; - for (auto it : mElementList) { - float w = std::max(float(0.), o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(it.energy * invE)); - mDispersion += w * ((it.localX - mLocalPosX) * (it.localX - mLocalPosX) + - (it.localZ - mLocalPosZ) * (it.localZ - mLocalPosZ)); - wtot += w; - } - - if (wtot > 0) { - mDispersion /= wtot; - } - - if (mDispersion >= 0) { - mDispersion = std::sqrt(mDispersion); - } else { - mDispersion = 0.; - } -} -//____________________________________________________________________________ -void FullCluster::evalElipsAxis() -{ // computes the axis of shower ellipsoide - // Calculates the axis of the shower ellipsoid - - if (mFullEnergy <= 0.) { // zero energy cluster, dispersion undefined - mLambdaLong = mLambdaShort = 0.; - return; - } - - float wtot = 0., x = 0., z = 0., dxx = 0., dxz = 0., dzz = 0.; - float invE = 1. / mFullEnergy; - for (auto it : mElementList) { - float xi = 0., zi = 0.; - float w = std::max(float(0.), o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(it.energy * invE)); - dxx += w * it.localX * it.localX; - x += w * it.localX; - dzz += w * it.localZ * it.localZ; - z += w * it.localZ; - dxz += w * it.localX * it.localZ; - wtot += w; - } - if (wtot > 0) { - wtot = 1. / wtot; - dxx *= wtot; - x *= wtot; - dxx -= x * x; - dzz *= wtot; - z *= wtot; - dzz -= z * z; - dxz *= wtot; - dxz -= x * z; - - mLambdaLong = 0.5 * (dxx + dzz) + std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz); - if (mLambdaLong > 0) { - mLambdaLong = std::sqrt(mLambdaLong); - } - - mLambdaShort = 0.5 * (dxx + dzz) - std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz); - if (mLambdaShort > 0) { // To avoid exception if numerical errors lead to negative lambda. - mLambdaShort = std::sqrt(mLambdaShort); - } else { - mLambdaShort = 0.; - } - } else { - mLambdaLong = mLambdaShort = 0.; - } -} -//____________________________________________________________________________ -void FullCluster::evalTime() -{ - - // Calculate time as time in the digit with maximal energy - - float eMax = 0.; - for (auto it : mElementList) { - if (it.energy > eMax) { - mTime = it.time; - eMax = it.energy; - } - } -} -//____________________________________________________________________________ -std::vector<Digit>::const_iterator FullCluster::BinarySearch(const std::vector<Digit>* container, Digit& element) -{ - const std::vector<Digit>::const_iterator endIt = container->end(); - - std::vector<Digit>::const_iterator left = container->begin(); - std::vector<Digit>::const_iterator right = endIt; - - if (container->size() == 0 || container->front() > element || container->back() < element) { - return endIt; - } - - while (distance(left, right) > 0) { - const std::vector<Digit>::const_iterator mid = left + distance(left, right) / 2; - - if (element > *mid) { - left = mid + 1; - } else { - right = mid; - } - } - - if (*right == element) { - return right; - } - - return endIt; -} -//____________________________________________________________________________ -char FullCluster::getNumberOfLocalMax(gsl::span<int> maxAt) const -{ - // Calculates the number of local maxima in the cluster using LocalMaxCut as the minimum - // energy difference between maximum and surrounding digits - - float locMaxCut = o2::phos::PHOSSimParams::Instance().mLocalMaximumCut; - - std::unique_ptr<bool[]> isLocalMax = std::make_unique<bool[]>(mMulDigit); - - for (int i = 0; i < mMulDigit; i++) { - if (mElementList[i].energy > o2::phos::PHOSSimParams::Instance().mClusteringThreshold) { - isLocalMax[i] = true; - } else { - isLocalMax[i] = false; - } - } - for (int i = 0; i < mMulDigit; i++) { - - for (int j = i + 1; j < mMulDigit; j++) { - - if (Geometry::GetInstance()->areNeighbours(mElementList[i].absId, mElementList[j].absId) == 1) { - if (mElementList[i].energy > mElementList[j].energy) { - isLocalMax[j] = false; - // but may be digit too is not local max ? - if (mElementList[j].energy > mElementList[i].energy - locMaxCut) { - isLocalMax[i] = false; - } - } else { - isLocalMax[i] = false; - // but may be digitN is not local max too? - if (mElementList[i].energy > mElementList[j].energy - locMaxCut) { - isLocalMax[j] = false; - } - } - } // if areneighbours - } // digit j - } // digit i - - int iDigitN = 0; - for (int i = 0; i < mMulDigit; i++) { - if (isLocalMax[i]) { - maxAt[iDigitN] = i; - iDigitN++; - if (iDigitN >= o2::phos::PHOSSimParams::Instance().mNLMMax) { // Note that size of output arrays is limited: - LOG(ERROR) << "Too many local maxima, cluster multiplicity " << mMulDigit; - return 0; - } - } - } - - return iDigitN; -} diff --git a/Detectors/PHOS/reconstruction/src/PHOSReconstructionLinkDef.h b/Detectors/PHOS/reconstruction/src/PHOSReconstructionLinkDef.h index fdd37317dacee..25a42a3b43132 100644 --- a/Detectors/PHOS/reconstruction/src/PHOSReconstructionLinkDef.h +++ b/Detectors/PHOS/reconstruction/src/PHOSReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,8 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::phos::CaloRawFitter + ; +#pragma link C++ class o2::phos::CaloRawFitterGS + ; #pragma link C++ class o2::phos::Clusterer + ; -#pragma link C++ class o2::phos::FullCluster + ; #endif diff --git a/Detectors/PHOS/reconstruction/src/RawBuffer.cxx b/Detectors/PHOS/reconstruction/src/RawBuffer.cxx new file mode 100644 index 0000000000000..2de79e1a90ab5 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/RawBuffer.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <fstream> +#include <iostream> +#include <cstring> +#include <FairLogger.h> +#include "PHOSReconstruction/RawBuffer.h" + +using namespace o2::phos; + +void RawBuffer::flush() +{ + mCurrentDataWord = 0; + mNDataWords = 0; + memset(mDataWords.data(), 0, sizeof(uint32_t) * mDataWords.size()); +} + +void RawBuffer::readFromStream(std::istream& in, uint32_t payloadsize) +{ + flush(); + uint32_t word(0); + auto address = reinterpret_cast<char*>(&word); + int nbyte = 0; + while (nbyte < payloadsize) { + in.read(address, sizeof(word)); + nbyte += sizeof(word); + if ((word & 0xFFFFFF) == 0x1d3082) { + LOG(ERROR) << "Found stop word" << std::endl; + // Termination word + // should normally not be decoded in case the payload size + // is determined correctly + break; + } + mDataWords[mNDataWords++] = word; + } +} + +void RawBuffer::readFromMemoryBuffer(const gsl::span<const char> rawmemory) +{ + flush(); + auto address = reinterpret_cast<const uint32_t*>(rawmemory.data()); + for (auto iword = 0; iword < rawmemory.size() / sizeof(uint32_t); iword++) { + // Run2 code, probably not needed for run3 + // if ((address[iword] & 0xFFF) == 0x082) { + // Termination word + // should normally not be decoded in case the payload size + // is determined correctly + //std::cout << "Found termination word" << std::endl; + //break; + // } + mDataWords[mNDataWords++] = address[iword]; + } +} + +uint32_t RawBuffer::getWord(int index) const +{ + if (index >= mNDataWords) { + throw std::runtime_error("Index out of range"); + } + return mDataWords[index]; +} + +uint32_t RawBuffer::getNextDataWord() +{ + if (!hasNext()) { + throw std::runtime_error("No more data words in buffer"); + } + return mDataWords[mCurrentDataWord++]; +} diff --git a/Detectors/PHOS/reconstruction/src/RawHeaderStream.cxx b/Detectors/PHOS/reconstruction/src/RawHeaderStream.cxx new file mode 100644 index 0000000000000..57daf7d626fa0 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/RawHeaderStream.cxx @@ -0,0 +1,107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <fstream> +#include <iostream> +#include "PHOSReconstruction/RawHeaderStream.h" + +std::istream& o2::phos::operator>>(std::istream& stream, o2::header::RAWDataHeaderV4& header) +{ + //std::cout << "called, 10 words" << std::endl; + using wordtype = uint64_t; + constexpr int RAWHEADERWORDS = sizeof(header) / sizeof(wordtype); + wordtype message[RAWHEADERWORDS]; + auto address = reinterpret_cast<char*>(message); + for (int i = 0; i < RAWHEADERWORDS; i++) { + stream.read(address + i * sizeof(wordtype) / sizeof(char), sizeof(message[i])); + //std::cout << "Word " << i << ": " << std::hex << message[i] << std::dec << std::endl; + } + header.word0 = message[0]; + header.word1 = message[1]; + header.word2 = message[2]; + header.word3 = message[3]; + header.word4 = message[4]; + header.word5 = message[5]; + header.word6 = message[6]; + header.word7 = message[7]; + return stream; +} + +std::istream& o2::phos::operator>>(std::istream& stream, o2::header::RAWDataHeaderV5& header) +{ + //std::cout << "called, 10 words" << std::endl; + using wordtype = uint64_t; + constexpr int RAWHEADERWORDS = sizeof(header) / sizeof(wordtype); + wordtype message[RAWHEADERWORDS]; + auto address = reinterpret_cast<char*>(message); + for (int i = 0; i < RAWHEADERWORDS; i++) { + stream.read(address + i * sizeof(wordtype) / sizeof(char), sizeof(message[i])); + //std::cout << "Word " << i << ": " << std::hex << message[i] << std::dec << std::endl; + } + header.word0 = message[0]; + header.word1 = message[1]; + header.word2 = message[2]; + header.word3 = message[3]; + header.word4 = message[4]; + header.word5 = message[5]; + header.word6 = message[6]; + header.word7 = message[7]; + return stream; +} + +std::ostream& o2::phos::operator<<(std::ostream& stream, const o2::header::RAWDataHeaderV4& header) +{ + stream << "Raw data header V4:\n" + << " Word0 " << header.word0 << " (0x" << std::hex << header.word0 << std::dec << ")\n" + << " Version: " << header.version << "\n" + << " Header size: " << header.headerSize << "\n" + << " Block length: " << header.blockLength << "\n" + << " FEE ID: " << header.feeId << "\n" + << " Priority: " << header.priority << "\n" + << " Word1 " << header.word1 << " (0x" << std::hex << header.word1 << std::dec << ")\n" + << " Offset to next: " << header.offsetToNext << "\n" + << " Payload size (B):" << header.memorySize << "\n" + << " Packet counter: " << static_cast<int>(header.packetCounter) << "\n" + << " Link ID: " << static_cast<int>(header.linkID) << "\n" + << " Card ID: " << header.cruID << "\n" + << " Endpoint: " << static_cast<int>(header.endPointID) << "\n" + << " Word2 " << header.word2 << " (0x" << std::hex << header.word2 << std::dec << ")\n" + << " Trigger orbit: " << header.triggerOrbit << "\n" + << " Heartbeat orbit: " << header.heartbeatOrbit << "\n" + << " Word3 " << header.word3 << " (0x" << std::hex << header.word3 << std::dec << ")\n" + << " Word4 " << header.word4 << " (0x" << std::hex << header.word4 << std::dec << ")\n" + << " Trigger BC: " << header.triggerBC << "\n" + << " Heartbeat BC: " << header.heartbeatBC << "\n" + << " Trigger Type: " << header.triggerType << "\n" + << " Word5 " << header.word5 << " (0x" << std::hex << header.word5 << std::dec << ")\n" + << " Word6 " << header.word6 << " (0x" << std::hex << header.word6 << std::dec << ")\n" + << " Detector Field: " << header.detectorField << "\n" + << " PAR: " << header.par << "\n" + << " STOP: " << header.stop << "\n" + << " Page count: " << header.pageCnt << "\n" + << " Word7 " << header.word7 << " (0x" << std::hex << header.word7 << std::dec << ")\n" + << "End header\n"; + return stream; +} + +std::ostream& o2::phos::operator<<(std::ostream& stream, const o2::header::RAWDataHeaderV5& header) +{ + stream << "Raw data header V5:\n" + << " Word0 " << header.word0 << " (0x" << std::hex << header.word0 << std::dec << ")\n" + << " Word1 " << header.word1 << " (0x" << std::hex << header.word1 << std::dec << ")\n" + << " Word2 " << header.word2 << " (0x" << std::hex << header.word2 << std::dec << ")\n" + << " Word3 " << header.word3 << " (0x" << std::hex << header.word3 << std::dec << ")\n" + << " Word4 " << header.word4 << " (0x" << std::hex << header.word4 << std::dec << ")\n" + << " Word5 " << header.word5 << " (0x" << std::hex << header.word5 << std::dec << ")\n" + << " Word6 " << header.word6 << " (0x" << std::hex << header.word6 << std::dec << ")\n" + << " Word7 " << header.word7 << " (0x" << std::hex << header.word7 << std::dec << ")\n" + << "End header\n"; + return stream; +} \ No newline at end of file diff --git a/Detectors/PHOS/reconstruction/src/RawPayload.cxx b/Detectors/PHOS/reconstruction/src/RawPayload.cxx new file mode 100644 index 0000000000000..bbd8d4479e69a --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/RawPayload.cxx @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSReconstruction/RawPayload.h" + +using namespace o2::phos; + +RawPayload::RawPayload(gsl::span<const uint32_t> payloadwords, int numpages) : mPayloadWords(payloadwords.size()), + mNumberOfPages(numpages) +{ + for (auto word : payloadwords) { + mPayloadWords.emplace_back(word); + } +} + +void RawPayload::appendPayloadWords(const gsl::span<const uint32_t> payloadwords) +{ + for (auto word : payloadwords) { + mPayloadWords.emplace_back(word); + } +} + +void RawPayload::reset() +{ + mPayloadWords.clear(); + mNumberOfPages = 0; +} diff --git a/Detectors/PHOS/reconstruction/src/RawReaderMemory.cxx b/Detectors/PHOS/reconstruction/src/RawReaderMemory.cxx new file mode 100644 index 0000000000000..0d0e55f352ee2 --- /dev/null +++ b/Detectors/PHOS/reconstruction/src/RawReaderMemory.cxx @@ -0,0 +1,152 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <sstream> +#include <string> +#include "PHOSReconstruction/RawReaderMemory.h" +#include "PHOSReconstruction/RawDecodingError.h" +#include "DetectorsRaw/RDHUtils.h" + +using namespace o2::phos; + +using RDHDecoder = o2::raw::RDHUtils; + +RawReaderMemory::RawReaderMemory(gsl::span<const char> rawmemory) : mRawMemoryBuffer(rawmemory) +{ + init(); +} + +void RawReaderMemory::setRawMemory(const gsl::span<const char> rawmemory) +{ + mRawMemoryBuffer = rawmemory; + init(); +} + +o2::header::RDHAny RawReaderMemory::decodeRawHeader(const void* payloadwords) +{ + auto headerversion = RDHDecoder::getVersion(payloadwords); + if (headerversion == 4) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV4*>(payloadwords)); + } else if (headerversion == 5) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV5*>(payloadwords)); + } else if (headerversion == 6) { + return o2::header::RDHAny(*reinterpret_cast<const o2::header::RAWDataHeaderV6*>(payloadwords)); + } + throw RawDecodingError::ErrorType_t::HEADER_DECODING; +} + +void RawReaderMemory::init() +{ + mCurrentPosition = 0; + mRawHeaderInitialized = false; + mPayloadInitialized = false; + mRawBuffer.flush(); + mNumData = mRawMemoryBuffer.size() / 8192; // assume fixed 8 kB pages +} + +void RawReaderMemory::next() +{ + //Reads pages till RCU trailer found + //Several 8kB pages can be concatenated + //RCU trailer expected at the end of payload + //but not at the end of each page + mRawPayload.reset(); + mCurrentTrailer.reset(); + bool isDataTerminated = false; + do { + try { + nextPage(false); + } catch (RawDecodingError::ErrorType_t e) { + throw e; + } + if (hasNext()) { + auto nextheader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); + // check continuing payload based on the bc/orbit ID + auto currentbc = RDHDecoder::getTriggerBC(mRawHeader), + nextbc = RDHDecoder::getTriggerBC(nextheader); + auto currentorbit = RDHDecoder::getTriggerOrbit(mRawHeader), + nextorbit = RDHDecoder::getTriggerOrbit(nextheader); + if (currentbc != nextbc || currentorbit != nextorbit) { + isDataTerminated = true; + } else { + auto nextpagecounter = RDHDecoder::getPageCounter(nextheader); + if (nextpagecounter == 0) { + isDataTerminated = true; + } else { + isDataTerminated = false; + } + } + } else { + isDataTerminated = true; + } + // Check if the data continues + } while (!isDataTerminated); + try { + mCurrentTrailer.constructFromPayloadWords(mRawBuffer.getDataWords()); + } catch (...) { + throw RawDecodingError::ErrorType_t::HEADER_DECODING; + } +} + +void RawReaderMemory::nextPage(bool doResetPayload) +{ + if (!hasNext()) { + throw RawDecodingError::ErrorType_t::PAGE_NOTFOUND; + } + if (doResetPayload) { + mRawPayload.reset(); + } + mRawHeaderInitialized = false; + mPayloadInitialized = false; + + // Read RDH header + try { + mRawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); + while (RDHDecoder::getOffsetToNext(mRawHeader) == RDHDecoder::getHeaderSize(mRawHeader) && + mCurrentPosition < mRawMemoryBuffer.size()) { + // No Payload - jump to next rawheader + // This will eventually move, depending on whether for events without payload in the SRU we send the RCU trailer + mCurrentPosition += RDHDecoder::getHeaderSize(mRawHeader); + mRawHeader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); + } + mRawHeaderInitialized = true; + } catch (...) { + throw RawDecodingError::ErrorType_t::HEADER_DECODING; + } + if (mCurrentPosition + RDHDecoder::getMemorySize(mRawHeader) > mRawMemoryBuffer.size()) { + // Payload incomplete + throw RawDecodingError::ErrorType_t::PAYLOAD_DECODING; + } + + mRawBuffer.readFromMemoryBuffer(gsl::span<const char>(mRawMemoryBuffer.data() + mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader), + RDHDecoder::getMemorySize(mRawHeader) - RDHDecoder::getHeaderSize(mRawHeader))); + gsl::span<const uint32_t> payloadWithoutTrailer(mRawBuffer.getDataWords().data(), mRawBuffer.getNDataWords()); + mRawPayload.appendPayloadWords(payloadWithoutTrailer); + mRawPayload.increasePageCount(); + + mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); /// Assume fixed 8 kB page size +} + +const o2::header::RDHAny& RawReaderMemory::getRawHeader() const +{ + if (!mRawHeaderInitialized) { + throw RawDecodingError::ErrorType_t::HEADER_INVALID; + } + return mRawHeader; +} + +const RawBuffer& RawReaderMemory::getRawBuffer() const +{ + if (!mPayloadInitialized) { + throw RawDecodingError::ErrorType_t::PAYLOAD_INVALID; + } + return mRawBuffer; +} diff --git a/Detectors/PHOS/simulation/CMakeLists.txt b/Detectors/PHOS/simulation/CMakeLists.txt index a7dc3a7ef4095..feef887df38a8 100644 --- a/Detectors/PHOS/simulation/CMakeLists.txt +++ b/Detectors/PHOS/simulation/CMakeLists.txt @@ -1,25 +1,36 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(PHOSSimulation SOURCES src/Detector.cxx src/GeometryParams.cxx src/Digitizer.cxx + src/RawWriter.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::DataFormatsPHOS O2::PHOSBase - O2::PHOSCalib) + O2::SimConfig + O2::SimulationDataFormat + O2::Headers + O2::DetectorsRaw) o2_target_root_dictionary(PHOSSimulation - HEADERS include/PHOSSimulation/Detector.h - include/PHOSSimulation/GeometryParams.h - include/PHOSSimulation/Digitizer.h) + HEADERS include/PHOSSimulation/Detector.h + include/PHOSSimulation/GeometryParams.h + include/PHOSSimulation/Digitizer.h + include/PHOSSimulation/RawWriter.h) +o2_add_executable(digi2raw + COMPONENT_NAME phos + PUBLIC_LINK_LIBRARIES O2::PHOSSimulation + SOURCES src/RawCreator.cxx) + o2_data_file(COPY data DESTINATION Detectors/PHS/simulation) diff --git a/Detectors/PHOS/simulation/include/PHOSSimulation/Detector.h b/Detectors/PHOS/simulation/include/PHOSSimulation/Detector.h index 34d7dfc138a40..cba3a1a7e9c6a 100644 --- a/Detectors/PHOS/simulation/include/PHOSSimulation/Detector.h +++ b/Detectors/PHOS/simulation/include/PHOSSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h b/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h index 19da5693e8e86..62e14086109dc 100644 --- a/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h +++ b/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,10 +13,11 @@ #define ALICEO2_PHOS_DIGITIZER_H #include "DataFormatsPHOS/Digit.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "DataFormatsPHOS/TriggerMap.h" +#include "DataFormatsPHOS/MCLabel.h" #include "PHOSBase/Geometry.h" -#include "PHOSCalib/CalibParams.h" #include "PHOSBase/Hit.h" -#include "DataFormatsPHOS/MCLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" namespace o2 @@ -34,32 +36,30 @@ class Digitizer : public TObject void finish(); /// Steer conversion of hits to digits - void process(const std::vector<Hit>* hitsBg, const std::vector<Hit>* hitsS, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::phos::MCLabel>& labels); - - void setEventTime(double t); - double getEventTime() const { return mEventTime; } - - void setCurrEvID(int v); - int getCurrEvID() const { return mCurrEvID; } + void processHits(const std::vector<Hit>* mHits, const std::vector<Digit>& digitsBg, + std::vector<Digit>& digitsOut, o2::dataformats::MCTruthContainer<MCLabel>& mLabels, + int source, int entry, double dt); + void processMC(bool mc) { mProcessMC = mc; } protected: float nonLinearity(float e); float uncalibrate(float e, int absId); - float uncalibrateT(float t, int absId, bool isHighGain); + float uncalibrateT(float t, int absId); float timeResolution(float time, float e); float simulateNoiseEnergy(int absId); float simulateNoiseTime(); private: - const Geometry* mGeometry = nullptr; //! PHOS geometry - const CalibParams* mCalibParams = nullptr; //! Calibration coefficients - double mEventTime = 0; ///< global event time - uint mROFrameMin = 0; ///< lowest RO frame of current digits - uint mROFrameMax = 0; ///< highest RO frame of current digits - int mCurrSrcID = 0; ///< current MC source from the manager - int mCurrEvID = 0; ///< current event ID from the manager + static constexpr short NCHANNELS = 12544; ///< Number of channels starting from 56*64*(4-0.5) + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*0.5+1 + bool mProcessMC = true; + bool mTrig2x2 = true; ///< simulate 2x2 PHOS trigger + bool mTrig4x4 = false; ///< simulate 4x4 PHOS trigger + std::unique_ptr<CalibParams> mCalibParams; /// Calibration coefficients + std::unique_ptr<TriggerMap> mTrigUtils; /// trigger bad map and turn-on curves + std::array<Digit, NCHANNELS> mArrayD; - ClassDefOverride(Digitizer, 2); + ClassDefOverride(Digitizer, 4); }; } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/simulation/include/PHOSSimulation/GeometryParams.h b/Detectors/PHOS/simulation/include/PHOSSimulation/GeometryParams.h index b4f95f91ac1ed..c7e819038459c 100644 --- a/Detectors/PHOS/simulation/include/PHOSSimulation/GeometryParams.h +++ b/Detectors/PHOS/simulation/include/PHOSSimulation/GeometryParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -47,7 +48,7 @@ class GeometryParams final : public TNamed int getNZ() const { return mNz; } int getNCristalsInModule() const { return mNPhi * mNz; } int getNModules() const { return mNModules; } - float getPHOSAngle(int index) const { return mPHOSAngle[index - 1]; } + float getPHOSAngle(int index) const { return mPHOSAngle[index]; } float* getPHOSParams() { return mPHOSParams; } // Half-sizes of PHOS trapecoid float* getPHOSATBParams() { return mPHOSATBParams; } // Half-sizes of PHOS trapecoid float getOuterBoxSize(int index) const { return 2. * mPHOSParams[index]; } @@ -143,7 +144,7 @@ class GeometryParams final : public TNamed // General PHOS modules parameters int mNModules; ///< Number of PHOS modules float mAngle; ///< Position angles between modules - float mPHOSAngle[4]; ///< Position angles of modules + float mPHOSAngle[5]; ///< Position angles of modules float mPHOSParams[4]; ///< Half-sizes of PHOS trapecoid float mPHOSATBParams[4]; ///< Half-sizes of (air-filled) inner part of PHOS air tight box float mCrystalShift; ///< Distance from crystal center to front surface diff --git a/Detectors/PHOS/simulation/include/PHOSSimulation/RawWriter.h b/Detectors/PHOS/simulation/include/PHOSSimulation/RawWriter.h new file mode 100644 index 0000000000000..829f040830925 --- /dev/null +++ b/Detectors/PHOS/simulation/include/PHOSSimulation/RawWriter.h @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_PHOS_RAWWRITER_H +#define ALICEO2_PHOS_RAWWRITER_H + +#include <gsl/span> + +#include <array> +#include <fstream> +#include <memory> +#include <string> +#include <map> +#include <vector> + +#include "Rtypes.h" + +#include "DetectorsRaw/RawFileWriter.h" +#include "DataFormatsPHOS/Digit.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "PHOSBase/RCUTrailer.h" + +namespace o2 +{ + +namespace phos +{ + +static constexpr short kNPHOSSAMPLES = 30; ///< Maximal number of samples in altro +static constexpr short kNPRESAMPLES = 2; ///< Number of pre-samples in altro +static constexpr short kOVERFLOW = 970; ///< Overflow level: 1023-pedestal~50 +static constexpr float kPHOSTIMETICK = 100.; ///< PHOS sampling time step in ns (hits/digits keep time in ns) + +struct AltroBunch { + int mStarttime; + std::vector<int> mADCs; +}; + +struct SRUDigitContainer { + int mSRUid; + std::map<short, std::vector<o2::phos::Digit*>> mChannels; +}; + +class RawWriter +{ + public: + enum class FileFor_t { + kFullDet, + kLink + }; + RawWriter() = default; + RawWriter(const char* outputdir) { setOutputLocation(outputdir); } + ~RawWriter() = default; + + o2::raw::RawFileWriter& getWriter() const { return *mRawWriter; } + + void setOutputLocation(const char* outputdir) { mOutputLocation = outputdir; } + void setFileFor(FileFor_t filefor) { mFileFor = filefor; } + + void init(); + void digitsToRaw(gsl::span<o2::phos::Digit> digits, gsl::span<o2::phos::TriggerRecord> triggers); + bool processTrigger(const gsl::span<o2::phos::Digit> digitsbranch, const o2::phos::TriggerRecord& trg); + + int carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const; + + protected: + void createTRUBunches(short truId, const std::vector<o2::phos::Digit*>& channelDigits, std::vector<o2::phos::AltroBunch>& bunchs); + void createRawBunches(short absId, const std::vector<o2::phos::Digit*>& digits, std::vector<o2::phos::AltroBunch>& bunchHG, + std::vector<o2::phos::AltroBunch>& bunchLG, bool& isLGFilled); + + std::vector<uint32_t> encodeBunchData(const std::vector<uint32_t>& data); + void fillGamma2(float amp, float time, short* samples); + // std::tuple<int, int, int> getOnlineID(int towerID); + // std::tuple<int, int> getLinkAssignment(int ddlID); + + std::vector<char> createRCUTrailer(int payloadsize, int feca, int fecb, double timesample, double l1phase); + + private: + FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files + std::string mOutputLocation = "./"; ///< Rawfile name + std::unique_ptr<const CalibParams> mCalibParams; ///< PHOS calibration + gsl::span<o2::phos::Digit> mDigits; ///< Digits input vector - must be in digitized format including the time response + std::vector<SRUDigitContainer> mSRUdata; ///< Internal helper of digits assigned to SRUs + std::vector<SRUDigitContainer> mTRUdata; ///< Internal helper of digits assigned to TRUs + std::unique_ptr<o2::raw::RawFileWriter> mRawWriter; ///< Raw writer + + ClassDefNV(RawWriter, 1); +}; + +} // namespace phos + +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/simulation/src/Detector.cxx b/Detectors/PHOS/simulation/src/Detector.cxx index 8a64841d18cc9..3cee6411e3217 100644 --- a/Detectors/PHOS/simulation/src/Detector.cxx +++ b/Detectors/PHOS/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -176,7 +177,6 @@ Bool_t Detector::ProcessHits(FairVolume* v) Int_t cell; fMC->CurrentVolOffID(2, cell); // 2: number of geom levels between PXTL and cell: get sell in strip number. Int_t detID = Geometry::relToAbsId(moduleNumber, strip, cell); - if (superParent == mCurentSuperParent && detID == mCurrentCellID && mCurrentHit) { // continue with current hit mCurrentHit->addEnergyLoss(lostenergy); @@ -205,7 +205,7 @@ Bool_t Detector::ProcessHits(FairVolume* v) fMC->TrackPosition(posX, posY, posZ); fMC->TrackMomentum(momX, momY, momZ, energy); Double_t estart = fMC->Etot(); - Double_t time = fMC->TrackTime() * 1.e+9; // time in ns?? To be consistent with EMCAL + Double_t time = fMC->TrackTime() * 1.e+9; // time in ns mCurrentHit = addHit(superParent, detID, math_utils::Point3D<float>(posX, posY, posZ), math_utils::Vector3D<float>(momX, momY, momZ), estart, time, lostenergy); @@ -234,6 +234,7 @@ void Detector::ConstructGeometry() LOG(DEBUG) << "Creating PHOS geometry\n"; phos::GeometryParams* geom = phos::GeometryParams::GetInstance("Run2"); + Geometry::GetInstance("Run2"); if (!geom) { LOG(ERROR) << "ConstructGeometry: PHOS Geometry class has not been set up.\n"; @@ -261,6 +262,7 @@ void Detector::ConstructGeometry() // Depending on configuration we should prepare containers for normal PHOS module "PHOS" // and half-module "PHOH" // This is still air tight box around PHOS + fMC->Gsvolu("PHOS", "TRD1", getMediumID(ID_FE), geom->getPHOSParams(), 4); if (mCreateHalfMod) { fMC->Gsvolu("PHOH", "TRD1", getMediumID(ID_FE), geom->getPHOSParams(), 4); @@ -275,21 +277,20 @@ void Detector::ConstructGeometry() Int_t idrotm[5]; Int_t iXYZ, iAngle; char im[5]; - for (Int_t iModule = 0; iModule < 5; iModule++) { - if (!mActiveModule[iModule + 1]) { + for (Int_t iModule = 1; iModule < 5; iModule++) { + if (!mActiveModule[iModule]) { continue; } Float_t angle[3][2] = {0}; geom->getModuleAngle(iModule, angle); Matrix(idrotm[iModule], angle[0][0], angle[0][1], angle[1][0], angle[1][1], angle[2][0], angle[2][1]); - Float_t pos[3] = {0}; geom->getModuleCenter(iModule, pos); - if (iModule == 0) { // special 1/2 module - fMC->Gspos("PHOH", iModule + 1, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); + if (iModule == 1) { // special 1/2 module + fMC->Gspos("PHOH", iModule, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); } else { - fMC->Gspos("PHOS", iModule + 1, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); + fMC->Gspos("PHOS", iModule, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY"); } } @@ -799,9 +800,9 @@ void Detector::ConstructEMCGeometry() fMC->Gspos("PEMH", 1, "PATH", 0., 0., z, 0, "ONLY"); } - fMC->Gspos("PATB", 1, "PHOS", 0., 0., 0, 0, "ONLY"); + fMC->Gspos("PATB", 1, "PHOS", 0., 0., 0., 0, "ONLY"); if (mCreateHalfMod) { // half of PHOS module - fMC->Gspos("PATH", 1, "PHOH", 0., 0., 0, 0, "ONLY"); + fMC->Gspos("PATH", 1, "PHOH", 0., 0., 0., 0, "ONLY"); } } @@ -823,7 +824,7 @@ void Detector::ConstructSupportGeometry() fMC->Gsvolu("PRRD", "BOX ", getMediumID(ID_AIR), par, 3); y0 = -(geom->getRailsDistanceFromIP() - geom->getRailRoadSize(1) / 2.0); - fMC->Gspos("PRRD", 1, "barrel", 0.0, y0 + 30., 0.0, 0, "ONLY"); + fMC->Gspos("PRRD", 1, "barrel", 0.0, y0 + 30. - 6.15, 0.0, 0, "ONLY"); // --- Dummy box containing one rail @@ -926,7 +927,7 @@ void Detector::defineSensitiveVolumes() //----------------------------------------- void Detector::addAlignableVolumes() const { - // + // Create entries for alignable volumes associating the symbolic volume // name with the corresponding volume path. @@ -938,15 +939,16 @@ void Detector::addAlignableVolumes() const o2::detectors::DetID::ID idPHOS = o2::detectors::DetID::PHS; TString physModulePath = "/cave_1/barrel_1/PHOS_"; + TString physModulePath2 = "/cave_1/barrel_1/PHOH_"; TString symbModuleName = "PHOS/Module"; for (Int_t iModule = 1; iModule <= geom->getNModules(); iModule++) { - if (!mActiveModule[iModule - 1]) { + if (!mActiveModule[iModule]) { continue; } - TString volPath(physModulePath); + TString volPath(iModule == 1 ? physModulePath2 : physModulePath); volPath += iModule; TString symName(symbModuleName); @@ -961,7 +963,6 @@ void Detector::addAlignableVolumes() const LOG(DEBUG) << "symName=" << symName << "\n"; LOG(DEBUG) << "--------------------------------------------" << "\n"; - LOG(DEBUG) << "Check for alignable entry: " << symName; if (!gGeoManager->SetAlignableEntry(symName.Data(), volPath.Data(), modUID)) { @@ -972,16 +973,8 @@ void Detector::addAlignableVolumes() const // Create the Tracking to Local transformation matrix for PHOS modules TGeoPNEntry* alignableEntry = gGeoManager->GetAlignableEntryByUID(modUID); LOG(DEBUG) << "Got TGeoPNEntry " << alignableEntry; - if (alignableEntry) { - Float_t angle = geom->getPHOSAngle(iModule); - TGeoHMatrix* globMatrix = alignableEntry->GetGlobalOrig(); - - TGeoHMatrix* matTtoL = new TGeoHMatrix; - matTtoL->RotateZ(270. + angle); - const TGeoHMatrix& globmatrixi = globMatrix->Inverse(); - matTtoL->MultiplyLeft(&globmatrixi); - alignableEntry->SetMatrix(matTtoL); + alignableEntry->SetMatrix(Geometry::GetInstance()->getAlignmentMatrix(iModule)); } } } diff --git a/Detectors/PHOS/simulation/src/Digitizer.cxx b/Detectors/PHOS/simulation/src/Digitizer.cxx index 630e31b2367c5..a401bddbb2668 100644 --- a/Detectors/PHOS/simulation/src/Digitizer.cxx +++ b/Detectors/PHOS/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,20 +28,27 @@ using namespace o2::phos; //_______________________________________________________________________ void Digitizer::init() { - mGeometry = Geometry::GetInstance(); if (!mCalibParams) { if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mCalibParams = new CalibParams(1); // test default calibration + mCalibParams.reset(new CalibParams(1)); // test default calibration LOG(INFO) << "[PHOSDigitizer] No reading calibration from ccdb requested, set default"; } else { - LOG(INFO) << "[PHOSDigitizer] getting calibration object from ccdb"; - o2::ccdb::CcdbApi ccdb; - std::map<std::string, std::string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation - mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, mEventTime); - if (!mCalibParams) { - LOG(FATAL) << "[PHOSDigitizer] can not get calibration object from ccdb"; - } + LOG(ERROR) << "[PHOSDigitizer] can not get calibration object from ccdb yet"; + // o2::ccdb::CcdbApi ccdb; + // std::map<std::string, std::string> metadata; // do we want to store any meta data? + // ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + // mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, mEventTime); + // if (!mCalibParams) { + // LOG(FATAL) << "[PHOSDigitizer] can not get calibration object from ccdb"; + // } + } + } + if (!mTrigUtils) { + if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { + mTrigUtils.reset(new TriggerMap(0)); // test default calibration + LOG(INFO) << "[PHOSDigitizer] No reading trigger map from ccdb requested, set default"; + } else { + LOG(ERROR) << "[PHOSDigitizer] can not get trigger map object from ccdb yet"; } } } @@ -49,161 +57,195 @@ void Digitizer::init() void Digitizer::finish() {} //_______________________________________________________________________ -void Digitizer::process(const std::vector<Hit>* hitsBg, const std::vector<Hit>* hitsS, std::vector<Digit>& digits, o2::dataformats::MCTruthContainer<o2::phos::MCLabel>& labels) +void Digitizer::processHits(const std::vector<Hit>* hits, const std::vector<Digit>& digitsBg, + std::vector<Digit>& digitsOut, o2::dataformats::MCTruthContainer<MCLabel>& labels, + int collId, int source, double dt) { - // Convert list of hits to digits: + // Convert list of hits + possible Bg digits to digits: // Add hits with energy deposition in same cell and same time // Add energy corrections // Apply time smearing - - std::vector<Hit>::const_iterator hitBg = hitsBg->cbegin(); - std::vector<Hit>::const_iterator hitS = hitsS->cbegin(); - std::vector<Hit>::const_iterator hit; //Far above maximal PHOS absId - const short kBigAbsID = 32767; - short hitAbsId = kBigAbsID; - short hitBgAbsId = kBigAbsID; - short hitSAbsId = kBigAbsID; - - if (hitBg != hitsBg->end()) { - hitBgAbsId = hitBg->GetDetectorID(); + // //Despite sorting in Detector::EndEvent(), hits still can be unsorted due to splitting of processing different bunches of primary + for (int i = NCHANNELS; i--;) { + mArrayD[i].reset(); } - if (hitS != hitsS->end()) { - hitSAbsId = hitS->GetDetectorID(); - } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; + + if (digitsBg.size() == 0) { // no digits provided: try simulate noise + for (int i = NCHANNELS; i--;) { + float energy = simulateNoiseEnergy(i + OFFSET); + energy = uncalibrate(energy, i + OFFSET); + if (energy > o2::phos::PHOSSimParams::Instance().mDigitThreshold) { + float time = simulateNoiseTime(); + mArrayD[i].setAmplitude(energy); + mArrayD[i].setTime(time); + mArrayD[i].setAbsId(i + OFFSET); + } + } + } else { //if digits exist, no noise should be added + for (auto& dBg : digitsBg) { //digits are sorted and unique + mArrayD[dBg.getAbsId() - OFFSET] = dBg; } } - Int_t nTotCells = mGeometry->getTotalNCells(); - for (short absId = 1; absId < nTotCells; absId++) { - - // If signal exist in this cell, add noise to it, otherwise just create noise digit - if (absId == hitAbsId) { - int labelIndex = labels.getIndexedSize(); - //Add primary info: create new MCLabels entry - o2::phos::MCLabel label(hit->GetTrackID(), mCurrEvID, mCurrSrcID, true, hit->GetEnergyLoss()); - labels.addElement(labelIndex, label); - - Digit digit((*hit), labelIndex); - - //May be add more hits to this digit? - if (hitBg == hitsBg->end()) { - hitBgAbsId = kBigAbsID; - } else { - hitBgAbsId = hitBg->GetDetectorID(); + //add Hits + for (auto& h : *hits) { + short absId = h.GetDetectorID(); + short i = absId - OFFSET; + float energy = h.GetEnergyLoss(); + if (o2::phos::PHOSSimParams::Instance().mApplyNonLinearity) { + energy = nonLinearity(energy); + } + float time = h.GetTime() + dt * 1.e-9; + if (o2::phos::PHOSSimParams::Instance().mApplyTimeResolution) { + time = uncalibrateT(timeResolution(time, energy), absId); + } + energy = uncalibrate(energy, absId); + if (mArrayD[i].getAmplitude() > 0) { + //update energy and time + if (mArrayD[i].isHighGain()) { + mArrayD[i].addEnergyTime(energy, time); + //if overflow occured? + if (mArrayD[i].getAmplitude() > o2::phos::PHOSSimParams::Instance().mMCOverflow) { //10bit ADC + float hglgratio = mCalibParams->getHGLGRatio(absId); + mArrayD[i].setAmplitude(mArrayD[i].getAmplitude() / hglgratio); + mArrayD[i].setHighGain(false); + } + } else { //digit already in LG + float hglgratio = mCalibParams->getHGLGRatio(absId); + energy /= hglgratio; + mArrayD[i].addEnergyTime(energy, time); } - if (hitS == hitsS->end()) { - hitSAbsId = kBigAbsID; + } else { + mArrayD[i].setHighGain(energy < o2::phos::PHOSSimParams::Instance().mMCOverflow); //10bit ADC + if (mArrayD[i].isHighGain()) { + mArrayD[i].setAmplitude(energy); } else { - hitSAbsId = hitS->GetDetectorID(); + float hglgratio = mCalibParams->getHGLGRatio(absId); + mArrayD[i].setAmplitude(energy / hglgratio); } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; - } else { //no hits left - hitAbsId = kBigAbsID; - continue; + mArrayD[i].setTime(time); + mArrayD[i].setAbsId(absId); + } + //Add MC info + if (mProcessMC) { + int labelIndex = mArrayD[i].getLabel(); + if (labelIndex == -1) { //no digit or noisy + labelIndex = labels.getIndexedSize(); + MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss()); + labels.addElement(labelIndex, label); + mArrayD[i].setLabel(labelIndex); + } else { //check if lable already exist + MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss()); + gsl::span<MCLabel> sp = labels.getLabels(labelIndex); + bool found = false; + for (MCLabel& te : sp) { + if (te == label) { + found = true; + te.add(label, 1.); + break; + } + } + if (!found) { + //Highly inefficient management of Labels: commenting line below reeduces WHOLE digitization time by factor ~30 + labels.addElementRandomAccess(labelIndex, label); + //sort MCLabels according to eDeposited + sp = labels.getLabels(labelIndex); + std::sort(sp.begin(), sp.end(), + [](o2::phos::MCLabel a, o2::phos::MCLabel b) { return a.getEdep() > b.getEdep(); }); } } - - while (absId == hitAbsId) { - Digit digitNext((*hit), labelIndex); //Use same MCTruth entry so far - digit += digitNext; - - //add MCLabel to list (add energy if same primary or add another label) - o2::phos::MCLabel label(hit->GetTrackID(), mCurrEvID, mCurrSrcID, true, hit->GetEnergyLoss()); - labels.addElement(labelIndex, label); - - //next hit? - if (hitBg == hitsBg->end()) { - hitBgAbsId = kBigAbsID; - } else { - hitBgAbsId = hitBg->GetDetectorID(); + } else { + mArrayD[i].setLabel(-1); + } + } + //Calculate trigger tiles 2*2 and 4*4 + bool mL0Fired = false; + const int nDDL = 14; + const int nxTRU = 8; + const int nzTRU = 28; + float sum2x2[nxTRU + 1][nzTRU + 1]; + float time2x2[nxTRU + 1][nzTRU + 1]; + float tt = 0; + for (char iTRU = 0; iTRU < nDDL; iTRU++) { + for (char ix = 1; ix <= nxTRU; ix++) { + for (char iz = 1; iz <= nzTRU; iz++) { + char truRelId[3] = {iTRU, ix, iz}; + short tileId = Geometry::truRelToAbsNumbering(truRelId); + if (!mTrigUtils->isGood2x2(tileId)) { + continue; } - if (hitS == hitsS->end()) { - hitSAbsId = kBigAbsID; - } else { - hitSAbsId = hitS->GetDetectorID(); + char relId[3]; + Geometry::truRelId2RelId(truRelId, relId); + short i1, i2, i3, i4; + Geometry::relToAbsNumbering(relId, i1); + relId[1] = relId[1] + 1; + Geometry::relToAbsNumbering(relId, i2); + relId[2] = relId[2] + 1; + Geometry::relToAbsNumbering(relId, i4); + relId[1] = relId[1] - 1; + Geometry::relToAbsNumbering(relId, i3); + sum2x2[ix][iz] = mArrayD[i1 - OFFSET].getAmplitude() + mArrayD[i2 - OFFSET].getAmplitude() + + mArrayD[i3 - OFFSET].getAmplitude() + mArrayD[i4 - OFFSET].getAmplitude(); + float ampMax = mArrayD[i1 - OFFSET].getAmplitude(); + tt = mArrayD[i1 - OFFSET].getTime(); + if (mArrayD[i2 - OFFSET].getAmplitude() > ampMax) { + ampMax = mArrayD[i2 - OFFSET].getAmplitude(); + tt = mArrayD[i2 - OFFSET].getTime(); } - if (hitBgAbsId < hitSAbsId) { // Bg hit exists and smaller than signal - hitAbsId = hitBgAbsId; - hit = hitBg; - mCurrSrcID = 0; - ++hitBg; - } else { - if (hitSAbsId < kBigAbsID) { //Signal hit exists and smaller than Bg - hitAbsId = hitSAbsId; - hit = hitS; - mCurrSrcID = 1; - ++hitS; - } else { //no hits left - hitAbsId = kBigAbsID; - digitNext.setAbsId(kBigAbsID); - continue; + if (mArrayD[i3 - OFFSET].getAmplitude() > ampMax) { + ampMax = mArrayD[i3 - OFFSET].getAmplitude(); + tt = mArrayD[i3 - OFFSET].getTime(); + } + if (mArrayD[i4 - OFFSET].getAmplitude() > ampMax) { + tt = mArrayD[i4 - OFFSET].getTime(); + } + time2x2[ix][iz] = tt; + if (mTrig2x2) { + if (sum2x2[ix][iz] > PHOSSimParams::Instance().mTrig2x2MinThreshold) { //do not test (slow) probability function with soft tiles + mL0Fired |= mTrigUtils->isFiredMC2x2(sum2x2[ix][iz], iTRU, short(ix), short(iz)); + //add TRU digit. Note that only tiles with E>mTrigMinThreshold added! + digitsOut.emplace_back(tileId, sum2x2[ix][iz], tt, true, -1); } } - - digitNext.fillFromHit(*hit); - } - - //Current digit finished, sort MCLabels according to eDeposited - auto lbls = labels.getLabels(labelIndex); - std::sort(lbls.begin(), lbls.end(), - [](o2::phos::MCLabel a, o2::phos::MCLabel b) { return a.getEdep() > b.getEdep(); }); - - // Add Electroinc noise, apply non-linearity, digitize, de-calibrate, time resolution - float energy = digit.getAmplitude(); - // Simulate electronic noise - energy += simulateNoiseEnergy(absId); - - if (o2::phos::PHOSSimParams::Instance().mApplyNonLinearity) { - energy = nonLinearity(energy); - } - - energy = uncalibrate(energy, absId); - - if (energy < o2::phos::PHOSSimParams::Instance().mZSthreshold) { - continue; - } - digit.setAmplitude(energy); - digit.setHighGain(energy < 1024); //10bit ADC - - if (o2::phos::PHOSSimParams::Instance().mApplyTimeResolution) { - digit.setTimeStamp(uncalibrateT(timeResolution(digit.getTimeStamp(), energy), absId, digit.isHighGain())); } + } - digits.push_back(digit); - } else { // No signal in this cell, - if (!mGeometry->isCellExists(absId)) { - continue; - } - // Simulate noise - float energy = simulateNoiseEnergy(absId); - energy = uncalibrate(energy, absId); - float time = simulateNoiseTime(); - if (energy > o2::phos::PHOSSimParams::Instance().mZSthreshold) { - digits.emplace_back(absId, energy, time, -1); // current AbsId, energy, random time, no primary + if (mTrig4x4) { + for (char ix = 1; ix < nxTRU; ix++) { + for (char iz = 1; iz < nzTRU; iz++) { + char truRelId[3] = {iTRU, ix, iz}; + short tileId = Geometry::truRelToAbsNumbering(truRelId); + if (!mTrigUtils->isGood4x4(tileId)) { + continue; + } + float sum4x4 = sum2x2[ix][iz] + sum2x2[ix][iz + 1] + sum2x2[ix + 1][iz] + sum2x2[ix + 1][iz + 1]; + if (sum4x4 > PHOSSimParams::Instance().mTrig4x4MinThreshold) { //do not test (slow) probability function with soft tiles + mL0Fired |= mTrigUtils->isFiredMC4x4(sum4x4, iTRU, short(ix), short(iz)); + //Add TRU digit short cell, float amplitude, float time, int label + tt = time2x2[ix][iz]; + float ampMax = sum2x2[ix][iz]; + if (sum2x2[ix][iz + 1] > ampMax) { + ampMax = sum2x2[ix][iz + 1]; + tt = sum2x2[ix][iz + 1]; + } + if (sum2x2[ix + 1][iz] > ampMax) { + ampMax = sum2x2[ix + 1][iz]; + tt = sum2x2[ix + 1][iz]; + } + if (sum2x2[ix + 1][iz + 1] > ampMax) { + tt = sum2x2[ix][iz + 1]; + } + digitsOut.emplace_back(tileId, sum4x4, tt, false, -1); + } + } } } } + for (int i = 0; i < NCHANNELS; i++) { + if (mArrayD[i].getAmplitude() > PHOSSimParams::Instance().mZSthreshold) { + digitsOut.push_back(mArrayD[i]); + } + } } //_______________________________________________________________________ @@ -222,23 +264,21 @@ float Digitizer::uncalibrate(const float e, const int absId) if (calib > 0) { return floor(e / calib); } else { - return 0; // TODO apply de-calibration from OCDB + return 0; } } //_______________________________________________________________________ -float Digitizer::uncalibrateT(const float time, const int absId, bool isHighGain) +float Digitizer::uncalibrateT(const float time, const int absId) { // Decalibrate EMC digit, i.e. transform from energy to ADC counts a factor read from CDB - if (isHighGain) { - return time + mCalibParams->getHGTimeCalib(absId); - } else { - return time + mCalibParams->getLGTimeCalib(absId); - } + // note time in seconds + return time + mCalibParams->getHGTimeCalib(absId); } //_______________________________________________________________________ float Digitizer::timeResolution(const float time, const float e) { // apply time resolution + // time measured in seconds float timeResolution = o2::phos::PHOSSimParams::Instance().mTimeResolutionA + o2::phos::PHOSSimParams::Instance().mTimeResolutionB / @@ -253,25 +293,3 @@ float Digitizer::simulateNoiseEnergy(int absId) //_______________________________________________________________________ float Digitizer::simulateNoiseTime() { return gRandom->Uniform(o2::phos::PHOSSimParams::Instance().mMinNoiseTime, o2::phos::PHOSSimParams::Instance().mMaxNoiseTime); } - -//_______________________________________________________________________ -void Digitizer::setEventTime(double t) -{ - // assign event time, it should be in a strictly increasing order - // in ns - - if (t < mEventTime) { - LOG(INFO) << "New event time (" << t << ") is < previous event time (" << mEventTime << ")"; - } - mEventTime = t; -} - -//_______________________________________________________________________ -void Digitizer::setCurrEvID(int v) -{ - // set current MC event ID - if (v > MCCompLabel::maxEventID()) { - LOG(FATAL) << "MC event id " << v << " exceeds max storable in the label " << MCCompLabel::maxEventID(); - } - mCurrEvID = v; -} diff --git a/Detectors/PHOS/simulation/src/GeometryParams.cxx b/Detectors/PHOS/simulation/src/GeometryParams.cxx index bedee16625c91..88eef57c35a9d 100644 --- a/Detectors/PHOS/simulation/src/GeometryParams.cxx +++ b/Detectors/PHOS/simulation/src/GeometryParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -379,11 +380,11 @@ GeometryParams::GeometryParams(const std::string_view name) mAngle = 20; for (Int_t i = 1; i <= mNModules; i++) { Float_t angle = mAngle * (i - 2); - mPHOSAngle[i - 1] = angle; + mPHOSAngle[i] = angle; } Float_t r = mIPtoOuterCoverDistance + mPHOSParams[3]; - for (Int_t iModule = 0; iModule < mNModules; iModule++) { + for (Int_t iModule = 1; iModule <= mNModules; iModule++) { mModuleCenter[iModule][0] = r * TMath::Sin(mPHOSAngle[iModule] / kRADDEG); mModuleCenter[iModule][1] = -r * TMath::Cos(mPHOSAngle[iModule] / kRADDEG); mModuleCenter[iModule][2] = 0.; diff --git a/Detectors/PHOS/simulation/src/PHOSSimulationLinkDef.h b/Detectors/PHOS/simulation/src/PHOSSimulationLinkDef.h index c6017f6b1148b..b8e973aad849e 100644 --- a/Detectors/PHOS/simulation/src/PHOSSimulationLinkDef.h +++ b/Detectors/PHOS/simulation/src/PHOSSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,5 +19,6 @@ #pragma link C++ class o2::phos::GeometryParams + ; #pragma link C++ class o2::base::DetImpl < o2::phos::Detector> + ; #pragma link C++ class o2::phos::Digitizer + ; +#pragma link C++ class o2::phos::RawWriter + ; #endif diff --git a/Detectors/PHOS/simulation/src/RawCreator.cxx b/Detectors/PHOS/simulation/src/RawCreator.cxx new file mode 100644 index 0000000000000..a63f300bcd3cc --- /dev/null +++ b/Detectors/PHOS/simulation/src/RawCreator.cxx @@ -0,0 +1,118 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <memory> +#include <string> +#include <vector> +#include "Framework/Logger.h" +#include <filesystem> +#include <boost/program_options.hpp> + +#include <TFile.h> +#include <TTree.h> +#include <TTreeReader.h> + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/StringUtils.h" +#include "DataFormatsPHOS/Digit.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "PHOSBase/Geometry.h" +#include "PHOSSimulation/RawWriter.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +namespace bpo = boost::program_options; + +int main(int argc, const char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " <cmds/options>\n" + " Tool will encode phos raw data from input file\n" + "Commands / Options"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbose,v", bpo::value<uint32_t>()->default_value(0), "Select verbosity level [0 = no output]"); + add_option("input-file,i", bpo::value<std::string>()->default_value("phosdigits.root"), "Specifies digit input file."); + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,link"); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); + add_option("debug,d", bpo::value<uint32_t>()->default_value(0), "Select debug output level [0 = no debug output]"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help") || argc == 1) { + std::cout << opt_general << std::endl; + exit(0); + } + + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + + auto digitfilename = vm["input-file"].as<std::string>(), + outputdir = vm["output-dir"].as<std::string>(), + filefor = vm["file-for"].as<std::string>(); + + // if needed, create output directory + if (!std::filesystem::exists(outputdir)) { + if (!std::filesystem::create_directories(outputdir)) { + LOG(FATAL) << "could not create output directory " << outputdir; + } else { + LOG(INFO) << "created output directory " << outputdir; + } + } + + std::unique_ptr<TFile> digitfile(TFile::Open(digitfilename.data(), "READ")); + auto treereader = std::make_unique<TTreeReader>(static_cast<TTree*>(digitfile->Get("o2sim"))); + TTreeReaderValue<std::vector<o2::phos::Digit>> digitbranch(*treereader, "PHOSDigit"); + TTreeReaderValue<std::vector<o2::phos::TriggerRecord>> triggerbranch(*treereader, "PHOSDigitTrigRecords"); + + o2::phos::RawWriter::FileFor_t granularity = o2::phos::RawWriter::FileFor_t::kFullDet; + if (filefor == "all") { + granularity = o2::phos::RawWriter::FileFor_t::kFullDet; + } else if (filefor == "link") { + granularity = o2::phos::RawWriter::FileFor_t::kLink; + } + + o2::phos::RawWriter rawwriter; + rawwriter.setOutputLocation(outputdir.data()); + rawwriter.setFileFor(granularity); + rawwriter.init(); + + // Loop over all entries in the tree, where each tree entry corresponds to a time frame + for (auto en : *treereader) { + rawwriter.digitsToRaw(*digitbranch, *triggerbranch); + } + rawwriter.getWriter().writeConfFile("PHS", "RAWDATA", o2::utils::Str::concat_string(outputdir, "/PHSraw.cfg")); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} diff --git a/Detectors/PHOS/simulation/src/RawWriter.cxx b/Detectors/PHOS/simulation/src/RawWriter.cxx new file mode 100644 index 0000000000000..09f67ccfb064a --- /dev/null +++ b/Detectors/PHOS/simulation/src/RawWriter.cxx @@ -0,0 +1,486 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FairLogger.h" +#include <iostream> + +#include <fmt/core.h> +#include <gsl/span> +#include <TSystem.h> +#include "PHOSSimulation/RawWriter.h" +#include "PHOSBase/Mapping.h" +#include "PHOSBase/PHOSSimParams.h" +#include "CCDB/CcdbApi.h" + +using namespace o2::phos; + +void RawWriter::init() +{ + mRawWriter = std::make_unique<o2::raw::RawFileWriter>(o2::header::gDataOriginPHS, false); + mRawWriter->setCarryOverCallBack(this); + mRawWriter->setApplyCarryOverToLastPage(true); + + // initialize mapping + Mapping::Instance(); + + for (auto iddl = 0; iddl < o2::phos::Mapping::NDDL; iddl++) { + // For PHOS set + std::string rawfilename = mOutputLocation; + switch (mFileFor) { + case FileFor_t::kFullDet: + rawfilename += "/phos.raw"; + break; + case FileFor_t::kLink: + rawfilename += fmt::format("/phos_{:d}.raw", iddl); + } + short crorc, link; + Mapping::ddlToCrorcLink(iddl, crorc, link); + mRawWriter->registerLink(iddl, crorc, link, 0, rawfilename.data()); + } + + // initialize containers for SRU and TRU + for (auto isru = 0; isru < o2::phos::Mapping::NDDL; isru++) { + SRUDigitContainer srucont; + srucont.mSRUid = isru; + mSRUdata.push_back(srucont); + + SRUDigitContainer trucont; + trucont.mSRUid = isru; + mTRUdata.push_back(trucont); + } +} + +void RawWriter::digitsToRaw(gsl::span<o2::phos::Digit> digitsbranch, gsl::span<o2::phos::TriggerRecord> triggerbranch) +{ + if (!mCalibParams) { + if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { + mCalibParams = std::make_unique<CalibParams>(1); // test default calibration + LOG(INFO) << "[RawWriter] No reading calibration from ccdb requested, set default"; + } else { + LOG(INFO) << "[RawWriter] getting calibration object from ccdb"; + o2::ccdb::CcdbApi ccdb; + std::map<std::string, std::string> metadata; + ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + auto tr = triggerbranch.begin(); + double eventTime = -1; + // if(tr!=triggerbranch.end()){ + // eventTime = (*tr).getBCData().getTimeNS() ; + // } + // mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, eventTime); + if (!mCalibParams) { + LOG(FATAL) << "[RawWriter] can not get calibration object from ccdb"; + } + } + } + + for (auto trg : triggerbranch) { + processTrigger(digitsbranch, trg); + } +} + +bool RawWriter::processTrigger(const gsl::span<o2::phos::Digit> digitsbranch, const o2::phos::TriggerRecord& trg) +{ + auto srucont = mSRUdata.begin(); + while (srucont != mSRUdata.end()) { + srucont->mChannels.clear(); + srucont++; + } + auto trucont = mTRUdata.begin(); + while (trucont != mTRUdata.end()) { + trucont->mChannels.clear(); + trucont++; + } + for (auto& dig : gsl::span(digitsbranch.data() + trg.getFirstEntry(), trg.getNumberOfObjects())) { + if (dig.isTRU()) { + short absId = dig.getTRUId(); + short ddl, hwAddr; + //get ddl and High Gain hw addresses + if (Mapping::Instance()->absIdTohw(absId, Mapping::kTRU, ddl, hwAddr) != o2::phos::Mapping::kOK) { + LOG(ERROR) << "Wrong truId=" << absId; + } + //Collect possible several digits (signal+pileup) into one map record + auto celldata = mTRUdata[ddl].mChannels.find(absId); + if (celldata == mTRUdata[ddl].mChannels.end()) { + const auto it = mTRUdata[ddl].mChannels.insert(celldata, {absId, std::vector<o2::phos::Digit*>()}); + it->second.push_back(&dig); + } else { + celldata->second.push_back(&dig); + } + } else { + short absId = dig.getAbsId(); + short ddl, hwAddr; + //get ddl and High Gain hw addresses + if (Mapping::Instance()->absIdTohw(absId, Mapping::kHighGain, ddl, hwAddr) != o2::phos::Mapping::kOK) { + LOG(ERROR) << "Wrong AbsId" << absId; + } + + //Collect possible several digits (signal+pileup) into one map record + auto celldata = mSRUdata[ddl].mChannels.find(absId); + if (celldata == mSRUdata[ddl].mChannels.end()) { + const auto it = mSRUdata[ddl].mChannels.insert(celldata, {absId, std::vector<o2::phos::Digit*>()}); + it->second.push_back(&dig); + } else { + celldata->second.push_back(&dig); + } + } + } + // Create and fill DMA pages for each channel + std::vector<uint32_t> rawbunches; + std::vector<char> payload; + std::vector<AltroBunch> rawbunchesTRU, rawbunchesHG, rawbunchesLG; + + for (short ddl = 0; ddl < o2::phos::Mapping::NDDL; ddl++) { + payload.clear(); + //Create trigger + //Trigger mask + short trmask[2 * Mapping::NTRUBranchReadoutChannels] = {0}; //Time bin in which trigger was fired. + for (auto ch = mTRUdata[ddl].mChannels.cbegin(); ch != mTRUdata[ddl].mChannels.cend(); ch++) { + short truId = ch->first; + short hwAddr, iddl; + if ((Mapping::Instance()->absIdTohw(truId, Mapping::kTRU, iddl, hwAddr) != o2::phos::Mapping::kOK) || iddl != ddl) { + LOG(ERROR) << "Wrong truId=" << truId << ", iDDL=" << iddl << "!=" << ddl; + } + rawbunchesTRU.clear(); + createTRUBunches(truId, ch->second, rawbunchesTRU); + rawbunches.clear(); + for (auto& bunch : rawbunchesTRU) { + rawbunches.push_back(bunch.mADCs.size() + 2); + rawbunches.push_back(bunch.mStarttime); + for (auto adc : bunch.mADCs) { + rawbunches.push_back(adc); + } + trmask[truId % (2 * Mapping::NTRUBranchReadoutChannels)] = bunch.mStarttime + 1; //need last tile (inverse time order) + } + if (rawbunches.size() == 0) { + continue; + } + auto encodedbunches = encodeBunchData(rawbunches); + ChannelHeader chanhead = {0}; + chanhead.mHardwareAddress = hwAddr; + chanhead.mPayloadSize = rawbunches.size(); + chanhead.mMark = 1; //mark channel header + char* chanheadwords = reinterpret_cast<char*>(&chanhead.mDataWord); + for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { + payload.emplace_back(chanheadwords[iword]); + } + char* channelwords = reinterpret_cast<char*>(encodedbunches.data()); + for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) { + payload.emplace_back(channelwords[iword]); + } + } + if (mTRUdata[ddl].mChannels.size()) { // if there are TRU digits, fill trigger flags + std::vector<uint32_t> a; + for (short chan = 0; chan < Mapping::NTRUBranchReadoutChannels; chan++) { + if (trmask[chan] > 0) { + while (a.size() < trmask[chan]) { + a.push_back(0); + } + a[trmask[chan] - 1] |= (1 << (chan % 10)); //Fill mask for a given channel + } + if (chan % 10 == 9 || chan + 1 == Mapping::NTRUBranchReadoutChannels) { + auto encodedbunches = encodeBunchData(a); + ChannelHeader chanhead = {0}; + chanhead.mHardwareAddress = 112 + chan / 10; + chanhead.mPayloadSize = a.size(); + chanhead.mMark = 1; //mark channel header + char* chanheadwords = reinterpret_cast<char*>(&chanhead.mDataWord); + for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { + payload.emplace_back(chanheadwords[iword]); + } + char* channelwords = reinterpret_cast<char*>(encodedbunches.data()); + for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) { + payload.emplace_back(channelwords[iword]); + } + a.clear(); + } + } + //second branch + for (short i = 0; i < Mapping::NTRUBranchReadoutChannels; i++) { + short chan = i + Mapping::NTRUBranchReadoutChannels; + if (trmask[chan] > 0) { + while (a.size() < trmask[chan]) { + a.push_back(0); + } + a[trmask[chan] - 1] |= (1 << (i % 10)); //Fill mask for a given channel + } + if (i % 10 == 9 || i + 1 == Mapping::NTRUBranchReadoutChannels) { + auto encodedbunches = encodeBunchData(a); + ChannelHeader chanhead = {0}; + chanhead.mHardwareAddress = 2048 + 112 + i / 10; + chanhead.mPayloadSize = a.size(); + chanhead.mMark = 1; //mark channel header + char* chanheadwords = reinterpret_cast<char*>(&chanhead.mDataWord); + for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { + payload.emplace_back(chanheadwords[iword]); + } + char* channelwords = reinterpret_cast<char*>(encodedbunches.data()); + for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) { + payload.emplace_back(channelwords[iword]); + } + a.clear(); + } + } + } + + for (auto ch = mSRUdata[ddl].mChannels.cbegin(); ch != mSRUdata[ddl].mChannels.cend(); ch++) { + // Find out hardware address of the channel + bool isLGfilled = 0; + createRawBunches(ch->first, ch->second, rawbunchesHG, rawbunchesLG, isLGfilled); + + short hwAddrHG; //High gain always filled + if (Mapping::Instance()->absIdTohw(ch->first, Mapping::kHighGain, ddl, hwAddrHG) != o2::phos::Mapping::kOK) { + LOG(ERROR) << "Wrong AbsId" << ch->first; + } + rawbunches.clear(); + for (auto& bunch : rawbunchesHG) { + rawbunches.push_back(bunch.mADCs.size() + 2); + rawbunches.push_back(bunch.mStarttime); + for (auto adc : bunch.mADCs) { + rawbunches.push_back(adc); + } + } + if (rawbunches.size() == 0) { + continue; + } + auto encodedbunches = encodeBunchData(rawbunches); + ChannelHeader chanhead = {0}; + chanhead.mHardwareAddress = hwAddrHG; + chanhead.mPayloadSize = rawbunches.size(); + chanhead.mMark = 1; //mark channel header + char* chanheadwords = reinterpret_cast<char*>(&chanhead.mDataWord); + for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { + payload.emplace_back(chanheadwords[iword]); + } + + char* channelwords = reinterpret_cast<char*>(encodedbunches.data()); + for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) { + payload.emplace_back(channelwords[iword]); + } + + if (isLGfilled) { //fill both HighGain, and LowGain channels in case of saturation + short hwAddrLG; //High gain always filled + if (Mapping::Instance()->absIdTohw(ch->first, 1, ddl, hwAddrLG) != o2::phos::Mapping::kOK) { + LOG(ERROR) << "Wrong AbsId" << ch->first; + } + + rawbunches.clear(); + for (auto& bunch : rawbunchesLG) { + rawbunches.push_back(bunch.mADCs.size() + 2); + rawbunches.push_back(bunch.mStarttime); + for (auto adc : bunch.mADCs) { + rawbunches.push_back(adc); + } + } + + encodedbunches = encodeBunchData(rawbunches); + ChannelHeader chanheadLG = {0}; + chanheadLG.mHardwareAddress = hwAddrLG; + chanheadLG.mPayloadSize = rawbunches.size(); + chanheadLG.mMark = 1; //mark channel header + + chanheadwords = reinterpret_cast<char*>(&chanheadLG.mDataWord); + for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) { + payload.emplace_back(chanheadwords[iword]); + } + channelwords = reinterpret_cast<char*>(encodedbunches.data()); + for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) { + payload.emplace_back(channelwords[iword]); + } + } + } + + // Create RCU trailer + auto trailerwords = createRCUTrailer(payload.size() / 4, 16, 16, 100., 0.); + for (auto word : trailerwords) { + payload.emplace_back(word); + } + + // register output data + LOG(DEBUG1) << "Adding payload with size " << payload.size() << " (" << payload.size() / 4 << " ALTRO words)"; + + short crorc, link; + Mapping::ddlToCrorcLink(ddl, crorc, link); + mRawWriter->addData(ddl, crorc, link, 0, trg.getBCData(), payload); + } + return true; +} +void RawWriter::createTRUBunches(short truId, const std::vector<o2::phos::Digit*>& channelDigits, + std::vector<o2::phos::AltroBunch>& bunchs) +{ + + AltroBunch currentBunch; + std::vector<short> samples; + float maxAmp = 0; + for (auto dig : channelDigits) { + float ampADC = dig->getAmplitude(); // Digits amplitude already in ADC channels + short time = short(dig->getTime() / 25.); // digit time in nc, convert to bunch crossings (25ns), max readout time 3 mks + if (time > 120) { + time = 120; + } + if (time < 0) { + time = 0; + } + if (maxAmp < ampADC) { + currentBunch.mStarttime = time; + maxAmp = ampADC; + } + while (samples.size() <= time) { + samples.push_back(0); + } + samples[time] = ampADC; + } + + //Note reverse time order + for (int i = samples.size(); i--;) { + currentBunch.mADCs.emplace_back(samples[i]); + } + bunchs.push_back(currentBunch); +} + +void RawWriter::createRawBunches(short absId, const std::vector<o2::phos::Digit*>& channelDigits, std::vector<o2::phos::AltroBunch>& bunchHG, + std::vector<o2::phos::AltroBunch>& bunchLG, bool& isLGFilled) +{ + + isLGFilled = false; + short samples[kNPHOSSAMPLES] = {0}; + float hglgratio = mCalibParams->getHGLGRatio(absId); + for (auto dig : channelDigits) { + //Convert energy and time to ADC counts and time ticks + float ampADC = dig->getAmplitude(); // Digits amplitude already in ADC channels + if (!dig->isHighGain() || ampADC > o2::phos::PHOSSimParams::Instance().mMCOverflow) { //High Gain in saturation, fill also Low Gain + isLGFilled = true; + } + float timeTicks = dig->getTime(); //time in ns + timeTicks /= o2::phos::PHOSSimParams::Instance().mTimeTick; //time in PHOS ticks + //Add to current sample contribution from digit + if (!dig->isHighGain()) { + ampADC *= hglgratio; + } + fillGamma2(ampADC, timeTicks, samples); + } + + //reduce samples below ZS and fill output + short zs = (short)o2::phos::PHOSSimParams::Instance().mZSthreshold; + bunchHG.clear(); + AltroBunch currentBunch; + //Note reverse time order + for (int i = kNPHOSSAMPLES; i--;) { + if (samples[i] > zs) { + currentBunch.mADCs.emplace_back(std::min(o2::phos::PHOSSimParams::Instance().mMCOverflow, samples[i])); + } else { //end of sample? + if (currentBunch.mADCs.size()) { + currentBunch.mStarttime = i + 1; + bunchHG.push_back(currentBunch); + currentBunch.mADCs.clear(); + } + } + } + if (currentBunch.mADCs.size()) { + bunchHG.push_back(currentBunch); + currentBunch.mADCs.clear(); + } + if (isLGFilled) { + bunchLG.clear(); + currentBunch.mADCs.clear(); + for (int i = kNPHOSSAMPLES; i--;) { + if (samples[i] > zs * hglgratio) { + currentBunch.mADCs.emplace_back(std::min(o2::phos::PHOSSimParams::Instance().mMCOverflow, short(samples[i] / hglgratio))); + } else { //end of sample? + if (currentBunch.mADCs.size()) { + currentBunch.mStarttime = i + 1; + bunchLG.push_back(currentBunch); + currentBunch.mADCs.clear(); + } + } + } + if (currentBunch.mADCs.size()) { + bunchLG.push_back(currentBunch); + } + } +} + +void RawWriter::fillGamma2(float amp, float time, short* samples) +{ + //Simulate Gamma2 signal added to current sample in PHOS + float alpha = o2::phos::PHOSSimParams::Instance().mSampleDecayTime; + amp += 0.5; //rounding err + for (int i = 0; i < kNPHOSSAMPLES; i++) { + if (i < time) { + continue; + } + float x = alpha * (i - time); + float y = 0.25 * amp * x * x * std::exp(2. - x); //0.25*exp(-2) normalization to unity + samples[i] += short(y); + } +} + +std::vector<uint32_t> RawWriter::encodeBunchData(const std::vector<uint32_t>& data) +{ + std::vector<uint32_t> encoded; + CaloBunchWord currentword; + currentword.mDataWord = 0; + int wordnumber = 0; + for (auto adc : data) { + switch (wordnumber) { + case 0: + currentword.mWord0 = adc; + break; + case 1: + currentword.mWord1 = adc; + break; + case 2: + currentword.mWord2 = adc; + break; + }; + wordnumber++; + if (wordnumber == 3) { + // start new word; + encoded.push_back(currentword.mDataWord); + currentword.mDataWord = 0; + wordnumber = 0; + } + } + if (wordnumber) { + encoded.push_back(currentword.mDataWord); + } + return encoded; +} + +std::vector<char> RawWriter::createRCUTrailer(int payloadsize, int feca, int fecb, double timesample, double l1phase) +{ + RCUTrailer trailer; + trailer.setActiveFECsA(feca); + trailer.setActiveFECsB(fecb); + trailer.setPayloadSize(payloadsize); + trailer.setL1Phase(l1phase); + trailer.setTimeSample(timesample); + auto trailerwords = trailer.encode(); + std::vector<char> encoded(trailerwords.size() * sizeof(uint32_t)); + memcpy(encoded.data(), trailerwords.data(), trailerwords.size() * sizeof(uint32_t)); + return encoded; +} + +int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data, + const char* ptr, int maxSize, int splitID, + std::vector<char>& trailer, std::vector<char>& header) const +{ + + constexpr int phosTrailerSize = 36; + int offs = ptr - &data[0]; // offset wrt the head of the payload + assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); // make sure ptr and end of the suggested block are within the payload + int leftBefore = data.size() - offs; // payload left before this splitting + int leftAfter = leftBefore - maxSize; // what would be left after the suggested splitting + int actualSize = maxSize; + if (leftAfter && leftAfter <= phosTrailerSize) { // avoid splitting the trailer or writing only it. + actualSize -= (phosTrailerSize - leftAfter) + 4; // (as we work with int, not char in decoding) + } + return actualSize; +} diff --git a/Detectors/PHOS/testsimulation/CMakeLists.txt b/Detectors/PHOS/testsimulation/CMakeLists.txt index b69dbcb572725..bfeca6123b55d 100644 --- a/Detectors/PHOS/testsimulation/CMakeLists.txt +++ b/Detectors/PHOS/testsimulation/CMakeLists.txt @@ -1,12 +1,13 @@ -#Copyright CERN and copyright holders of ALICE O2.This software is distributed -#under the terms of the GNU General Public License v3(GPL Version 3), copied -#verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -#See http: //alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # -#In applying this license CERN does not waive the privileges and immunities -#granted to it by virtue of its status as an Intergovernmental Organization or -#submit itself to any jurisdiction. +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(PutPhosInTop.C PUBLIC_LINK_LIBRARIES O2::DetectorsPassive FairRoot::Base diff --git a/Detectors/PHOS/workflow/CMakeLists.txt b/Detectors/PHOS/workflow/CMakeLists.txt index 788527d945d91..32c8a76f42568 100644 --- a/Detectors/PHOS/workflow/CMakeLists.txt +++ b/Detectors/PHOS/workflow/CMakeLists.txt @@ -1,8 +1,9 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/ for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization @@ -10,14 +11,28 @@ o2_add_library(PHOSWorkflow SOURCES src/RecoWorkflow.cxx - src/PublisherSpec.cxx + src/ReaderSpec.cxx src/CellConverterSpec.cxx + src/RawToCellConverterSpec.cxx src/ClusterizerSpec.cxx src/DigitsPrinterSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsPHOS - O2::DPLUtils O2::PHOSBase O2::PHOSCalib O2::PHOSSimulation O2::PHOSReconstruction O2::Algorithm) + src/RawWriterSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + src/WriterSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsPHOS + O2::DPLUtils + O2::PHOSBase + O2::PHOSSimulation + O2::PHOSReconstruction + O2::Algorithm) o2_add_executable(reco-workflow COMPONENT_NAME phos SOURCES src/phos-reco-workflow.cxx PUBLIC_LINK_LIBRARIES O2::PHOSWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME phos + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::PHOSWorkflow) diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h index b70718f019260..f75dd42375151 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ #include <vector> -#include "PHOSCalib/BadChannelMap.h" +#include "DataFormatsPHOS/BadChannelsMap.h" #include "DataFormatsPHOS/MCLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "DataFormatsPHOS/Cell.h" @@ -75,8 +76,7 @@ class CellConverterSpec : public framework::Task std::vector<Cell> mOutputCells; ///< Container with output cells std::vector<TriggerRecord> mOutputCellTrigRecs; ///< Container with trigger records for output cells o2::dataformats::MCTruthContainer<MCLabel> mOutputTruthCont; ///< output MC labels - std::vector<uint> mOutputTruthMap; ///< output MC labels - o2::phos::BadChannelMap* mBadMap = nullptr; ///< Bad channels map + o2::phos::BadChannelsMap* mBadMap = nullptr; ///< Bad channels map }; /// \brief Creating DataProcessorSpec for the PHOS Cell Converter Spec diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/ClusterizerSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/ClusterizerSpec.h index bd9e08a75049d..0917242ad3d56 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/ClusterizerSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/ClusterizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ class ClusterizerSpec : public framework::Task { public: /// \brief Constructor - ClusterizerSpec(bool propagateMC) : framework::Task(), mPropagateMC(propagateMC) {} + ClusterizerSpec(bool propagateMC, bool scanDigits, bool outputFullClu) : framework::Task(), mPropagateMC(propagateMC), mUseDigits(scanDigits), mFullCluOutput(outputFullClu) {} /// \brief Destructor ~ClusterizerSpec() override = default; @@ -58,8 +59,11 @@ class ClusterizerSpec : public framework::Task private: bool mPropagateMC = false; ///< Switch whether to process MC true labels + bool mUseDigits = false; ///< Make clusters from digits or cells + bool mFullCluOutput = false; ///< Write full of reduced (no contributed digits) clusters o2::phos::Clusterer mClusterizer; ///< Clusterizer object std::vector<o2::phos::Cluster> mOutputClusters; + std::vector<o2::phos::CluElement> mOutputCluElements; std::vector<o2::phos::TriggerRecord> mOutputClusterTrigRecs; o2::dataformats::MCTruthContainer<o2::phos::MCLabel> mOutputTruthCont; }; @@ -67,8 +71,8 @@ class ClusterizerSpec : public framework::Task /// \brief Creating DataProcessorSpec for the PHOS Clusterizer Spec /// /// Refer to ClusterizerSpec::run for input and output specs -framework::DataProcessorSpec getClusterizerSpec(bool propagateMC); -framework::DataProcessorSpec getCellClusterizerSpec(bool propagateMC); +framework::DataProcessorSpec getClusterizerSpec(bool propagateMC, bool fillFullClu); +framework::DataProcessorSpec getCellClusterizerSpec(bool propagateMC, bool fillFullClu); } // namespace reco_workflow diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitsPrinterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitsPrinterSpec.h index e9cfe87347d60..7ea91c1dee595 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitsPrinterSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitsPrinterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..775057806bde7 --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to PHOS digit/channels strean + +#ifndef O2_PHOS_ENTROPYDECODER_SPEC +#define O2_PHOS_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "PHOSReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +namespace o2 +{ +namespace phos +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::phos::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..fef1c8625e50c --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert PHOS data to CTF (EncodedBlocks) + +#ifndef O2_PHOS_ENTROPYENCODER_SPEC +#define O2_PHOS_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include <TStopwatch.h> +#include "PHOSReconstruction/CTFCoder.h" + +namespace o2 +{ +namespace phos +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::phos::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace phos +} // namespace o2 + +#endif diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h deleted file mode 100644 index f79d38432cfeb..0000000000000 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/DataProcessorSpec.h" -#include "Framework/OutputSpec.h" -#include <string> -#include <vector> - -namespace o2 -{ - -namespace phos -{ - -using OutputSpec = framework::OutputSpec; - -struct PublisherConf { - struct BranchOptionConfig { - std::string option; - std::string defval; - std::string help; - }; - - std::string processName; - std::string defaultTreeName; - BranchOptionConfig databranch; - BranchOptionConfig datatrbranch; - BranchOptionConfig mcbranch; - BranchOptionConfig mcmapbranch; - OutputSpec dataoutput; - OutputSpec datatroutput; - OutputSpec mcoutput; - OutputSpec mcmapoutput; -}; - -framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true, bool createMCMap = false); - -} // namespace phos -} // end namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/RawToCellConverterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/RawToCellConverterSpec.h new file mode 100644 index 0000000000000..7ffdcbe195cd3 --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/RawToCellConverterSpec.h @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DataFormatsPHOS/CalibParams.h" +#include "PHOSBase/Mapping.h" +#include "PHOSReconstruction/AltroDecoder.h" +#include "PHOSReconstruction/CaloRawFitter.h" +#include "PHOSReconstruction/RawReaderError.h" + +namespace o2 +{ + +namespace phos +{ + +namespace reco_workflow +{ + +/// \class RawToCellConverterSpec +/// \brief Coverter task for Raw data to PHOS cells +/// \author Dmitri Peresunko NRC KI +/// \since Sept., 2020 +/// +class RawToCellConverterSpec : public framework::Task +{ + public: + /// \brief Constructor + /// \param propagateMC If true the MCTruthContainer is propagated to the output + RawToCellConverterSpec() : framework::Task(){}; + + /// \brief Destructor + ~RawToCellConverterSpec() override = default; + + /// \brief Initializing the RawToCellConverterSpec + /// \param ctx Init context + void init(framework::InitContext& ctx) final; + + /// \brief Run conversion of raw data to cells + /// \param ctx Processing context + /// + /// The following branches are linked: + /// Input RawData: {"ROUT", "RAWDATA", 0, Lifetime::Timeframe} + /// Output cells: {"PHS", "CELLS", 0, Lifetime::Timeframe} + /// Output cells trigger record: {"PHS", "CELLSTR", 0, Lifetime::Timeframe} + /// Output HW errors: {"PHS", "RAWHWERRORS", 0, Lifetime::Timeframe} + void run(framework::ProcessingContext& ctx) final; + + protected: + private: + bool mFillChi2 = false; ///< Fill output with quality of samples + bool mCombineGHLG = true; ///< Combine or not HG and LG channels (def: combine, LED runs: not combine) + bool mPedestalRun = false; ///< Analyze pedestal run (calculate pedestal mean and RMS) + int mLastSize = 0; ///< size of last send list of cells to reserve same in next bunch + std::unique_ptr<CalibParams> mCalibParams; ///!<! PHOS calibration + std::unique_ptr<AltroDecoder> mDecoder; ///!<! Raw decoder + std::unique_ptr<CaloRawFitter> mRawFitter; ///!<! Raw fitter + std::array<std::vector<Cell>, 14> mTmpCells; ///< Temporary cells storage to all 14 DLL + std::array<std::vector<Cell>, 14> mTmpTRU; ///< Temporary tru cells storage to all 14 DLL + std::vector<o2::phos::Cell> mOutputCells; ///< Container with output cells + std::vector<o2::phos::TriggerRecord> mOutputTriggerRecords; ///< Container with output cells + std::vector<o2::phos::RawReaderError> mOutputHWErrors; ///< Errors occured in reading data + std::vector<short> mOutputFitChi; ///< Raw sample fit quality +}; + +/// \brief Creating DataProcessorSpec for the PHOS Cell Converter Spec +/// +/// Refer to RawToCellConverterSpec::run for input and output specs +framework::DataProcessorSpec getRawToCellConverterSpec(int flpId); + +} // namespace reco_workflow + +} // namespace phos + +} // namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/RawWriterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/RawWriterSpec.h new file mode 100644 index 0000000000000..f5e403d274a5a --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/RawWriterSpec.h @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/DataProcessorSpec.h" +#include "PHOSSimulation/RawWriter.h" +#include "Framework/Task.h" + +namespace o2 +{ + +namespace phos +{ + +namespace reco_workflow +{ + +/// \class RawWriterSpec +/// \brief Coverter task for PHOS digits to raw +/// \author Dmitri Peresunko after Markus Fasel +/// \since Nov.20, 2020 +/// +/// Task converting a vector of PHOS digits to raw file +class RawWriterSpec : public framework::Task +{ + public: + /// \brief Constructor + /// \param propagateMC If true the MCTruthContainer is propagated to the output + RawWriterSpec() : framework::Task(){}; + + /// \brief Destructor + ~RawWriterSpec() override = default; + + /// \brief Initializing the RawWriterSpec + /// \param ctx Init context + void init(framework::InitContext& ctx) final; + + /// \brief Run conversion of digits to cells + /// \param ctx Processing context + /// + /// Converting the input vector of o2::phos::Digit to + /// file with raw data + /// + /// The following branches are linked: + /// Input digits: {"PHS", "DIGITS", 0, Lifetime::Timeframe} + /// Input digit trigger records: {"PHS", "DIGITTRS", 0, Lifetime::Timeframe} + void run(framework::ProcessingContext& ctx) final; + + private: + o2::phos::RawWriter* mRawWriter = nullptr; +}; + +/// \brief Creating DataProcessorSpec for the PHOS Cell Converter Spec +/// \param propagateMC If true the MC truth container is propagated to the output +/// +/// Refer to RawWriterSpec::run for input and output specs +framework::DataProcessorSpec getRawWriterSpec(); + +} // namespace reco_workflow + +} // namespace phos + +} // namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h new file mode 100644 index 0000000000000..9dacec2a249ef --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/OutputSpec.h" +#include <string> +#include <vector> + +namespace o2 +{ + +namespace phos +{ + +using OutputSpec = framework::OutputSpec; + +framework::DataProcessorSpec getDigitsReaderSpec(bool propagateMC = true); +framework::DataProcessorSpec getCellReaderSpec(bool propagateMC = true); + +} // namespace phos +} // end namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h index 7235ffa805e98..dbf49d9ab0efc 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,11 +39,13 @@ enum struct OutputType { Digits, }; /// create the workflow for PHOS reconstruction -framework::WorkflowSpec getWorkflow(bool propagateMC = true, - bool enableDigitsPrinter = false, - std::string const& cfgInput = "hits", // - std::string const& cfgOutput = "clusters" // -); +framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC = true, + std::string const& cfgInput = "hits", // + std::string const& cfgOutput = "clusters", // + bool fullCluOut = false, + int flpId = 0); } // namespace reco_workflow } // namespace phos diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h new file mode 100644 index 0000000000000..e86089af75859 --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.h + +#ifndef O2_PHOS_WRITER +#define O2_PHOS_WRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace phos +{ + +/// create a processor spec +/// write PHOS clusters to ROOT file +framework::DataProcessorSpec getCellWriterSpec(bool useMC); + +/// write PHOS clusters to ROOT file +framework::DataProcessorSpec getClusterWriterSpec(bool useMC); + +} // namespace phos +} // namespace o2 + +#endif /* O2_PHOS_WRITER */ \ No newline at end of file diff --git a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx index d3c9ced7ef8c0..a7a438f610cda 100644 --- a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx +++ b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "Framework/ControlService.h" #include "DataFormatsPHOS/MCLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" #include "CommonDataFormat/InteractionRecord.h" #include "PHOSBase/PHOSSimParams.h" #include "CCDB/CcdbApi.h" @@ -24,7 +26,7 @@ using namespace o2::phos::reco_workflow; void CellConverterSpec::init(framework::InitContext& ctx) { - LOG(DEBUG) << "[PHOSCellConverter - init] Initialize converter " << (mPropagateMC ? "with" : "without") << " MC truth container"; + LOG(INFO) << "[PHOSCellConverter - init] Initialize converter " << (mPropagateMC ? "with" : "without") << " MC truth container"; } void CellConverterSpec::run(framework::ProcessingContext& ctx) @@ -38,24 +40,27 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); return; } - LOG(INFO) << "Had Payload"; mOutputCells.clear(); mOutputCellTrigRecs.clear(); auto digits = ctx.inputs().get<std::vector<o2::phos::Digit>>("digits"); auto digitsTR = ctx.inputs().get<std::vector<o2::phos::TriggerRecord>>("digitTriggerRecords"); - auto truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("digitsmctr"); + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::phos::MCLabel>> truthcont(nullptr); if (mPropagateMC) { + truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("digitsmctr"); mOutputTruthCont.clear(); - mOutputTruthMap.clear(); } - LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords"; + if (mPropagateMC) { + LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords" << truthcont->getNElements() << " MC labels"; + } else { + LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords"; + } //Get TimeStamp from TriggerRecord if (!mBadMap) { if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { - mBadMap = new BadChannelMap(1); // test default map + mBadMap = new BadChannelsMap(1); // test default map LOG(INFO) << "[PHOSCellConverter - run] No reading BadMap from ccdb requested, set default"; } else { LOG(INFO) << "[PHOSCellConverter - run] getting BadMap object from ccdb"; @@ -63,7 +68,7 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) std::map<std::string, std::string> metadata; // do we want to store any meta data? ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation long bcTime = -1; //TODO!!! Convert BC time to time o2::InteractionRecord bcTime = digitsTR.front().getBCData() ; - mBadMap = ccdb.retrieveFromTFileAny<o2::phos::BadChannelMap>("PHOS/BadMap", metadata, bcTime); + mBadMap = ccdb.retrieveFromTFileAny<o2::phos::BadChannelsMap>("PHOS/BadMap", metadata, bcTime); if (!mBadMap) { LOG(FATAL) << "[PHOSCellConverter - run] can not get Bad Map"; } @@ -71,53 +76,58 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) } //TODO!!! Should we check if BadMap should be updated/validity range still valid??? mOutputCells.reserve(digits.size()); // most of digits will be copied + int icell = 0; int labelIndex = 0; for (const auto& tr : digitsTR) { int iFirstDigit = tr.getFirstEntry(); int iLastDigit = iFirstDigit + tr.getNumberOfObjects(); int indexStart = mOutputCells.size(); - int icell = 0; for (int i = iFirstDigit; i < iLastDigit; i++) { const auto& dig = digits.at(i); - //apply filter - if (!mBadMap->isChannelGood(dig.getAbsId())) { - continue; - } - - ChannelType_t chantype; - if (dig.isHighGain()) { - chantype = ChannelType_t::HIGH_GAIN; + if (dig.isTRU()) { + ChannelType_t chantype; + if (dig.isHighGain()) { + chantype = ChannelType_t::TRU2x2; + } else { + chantype = ChannelType_t::TRU4x4; + } + mOutputCells.emplace_back(dig.getAbsId(), dig.getAmplitude(), dig.getTime(), chantype); } else { - chantype = ChannelType_t::LOW_GAIN; - } - - // TODO!!! TRU copying... - // if (dig.getTRU()) - // chantype = ChannelType_t::TRU; + //apply filter + if (!mBadMap->isChannelGood(dig.getAbsId())) { + continue; + } - mOutputCells.emplace_back(dig.getAbsId(), dig.getAmplitude(), dig.getTime(), chantype); - icell++; - if (mPropagateMC) { //copy MC info, - int iLab = dig.getLabel(); - if (iLab > -1) { - mOutputTruthCont.addElements(labelIndex, truthcont->getLabels(iLab)); - mOutputTruthMap.emplace_back(icell); //Relate cell index and label index - labelIndex++; + ChannelType_t chantype; + if (dig.isHighGain()) { + chantype = ChannelType_t::HIGH_GAIN; + } else { + chantype = ChannelType_t::LOW_GAIN; + } + mOutputCells.emplace_back(dig.getAbsId(), dig.getAmplitude(), dig.getTime(), chantype); + if (mPropagateMC) { //copy MC info, + int iLab = dig.getLabel(); + if (iLab > -1) { + mOutputTruthCont.addElements(icell, truthcont->getLabels(iLab)); + } else { + MCLabel label(0, 0, 0, true, 0); + label.setNoise(); + mOutputTruthCont.addElement(icell, label); + } + icell++; } } } - mOutputCellTrigRecs.emplace_back(tr.getBCData(), indexStart, mOutputCells.size()); + mOutputCellTrigRecs.emplace_back(tr.getBCData(), indexStart, mOutputCells.size() - indexStart); } - LOG(INFO) << "[PHOSCellConverter - run] Writing " << mOutputCells.size() << " cells and " << mOutputCellTrigRecs.size() << " Trig Records "; + LOG(INFO) << "[PHOSCellConverter - run] Writing " << mOutputCells.size() << " cells, " << mOutputCellTrigRecs.size() << " Trig Records " << mOutputTruthCont.getNElements() << " PHOS labels "; + ; ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLS", 0, o2::framework::Lifetime::Timeframe}, mOutputCells); ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputCellTrigRecs); if (mPropagateMC) { ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthCont); - ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthMap); } - LOG(INFO) << "Finished "; - ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); } o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellConverterSpec(bool propagateMC) @@ -131,7 +141,6 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellConverterSpec(b if (propagateMC) { inputs.emplace_back("digitsmctr", "PHS", "DIGITSMCTR", 0, o2::framework::Lifetime::Timeframe); outputs.emplace_back("PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe); - outputs.emplace_back("PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe); } return o2::framework::DataProcessorSpec{"PHOSCellConverterSpec", inputs, diff --git a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx index 5654e58927bc5..6718f0c4a6901 100644 --- a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,13 +22,39 @@ void ClusterizerSpec::init(framework::InitContext& ctx) { LOG(DEBUG) << "[PHOSClusterizer - init] Initialize clusterizer ..."; - // Initialize clusterizer and link geometry + //get BadMap and calibration CCDB + std::unique_ptr<CalibParams> calibParams; ///! Calibration coefficients + std::unique_ptr<BadChannelsMap> badMap; ///! Bad map + + // if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { + badMap.reset(new BadChannelsMap(1)); // test default map + calibParams.reset(new CalibParams(1)); //test calibration map + LOG(INFO) << "No reading BadMap/Calibration from ccdb requested, set default"; + // } else { + // LOG(INFO) << "Getting BadMap object from ccdb"; + // o2::ccdb::CcdbApi ccdb; + // std::map<std::string, std::string> metadata; // do we want to store any meta data? + // ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + // long bcTime = 1; //TODO!!! Convert BC time to time o2::InteractionRecord bcTime = digitsTR.front().getBCData() ; + // mBadMap = ccdb.retrieveFromTFileAny<o2::phos::BadChannelsMap>("PHOS/BadMap", metadata, bcTime); + // mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, bcTime); + // if (!mBadMap) { + // LOG(FATAL) << "[PHOSCellConverter - run] can not get Bad Map"; + // } + // if (!mCalibParams) { + // LOG(FATAL) << "[PHOSCellConverter - run] can not get CalibParams"; + // } + // } + mClusterizer.initialize(); + mClusterizer.setBadMap(badMap); + mClusterizer.setCalibration(calibParams); } void ClusterizerSpec::run(framework::ProcessingContext& ctx) { - if (ctx.inputs().isValid("digits")) { + + if (mUseDigits) { LOG(DEBUG) << "PHOSClusterizer - run on digits called"; auto dataref = ctx.inputs().get("digits"); @@ -38,47 +65,52 @@ void ClusterizerSpec::run(framework::ProcessingContext& ctx) return; } - // auto digits = ctx.inputs().get<gsl::span<o2::phos::Digit>>("digits"); - // results in [7968:PHOSClusterizerSpec]: [20:51:44][ERROR] Exception caught: Inconsistent serialization method for extracting span + // auto digits = ctx.inputs().get<gsl::span<o2::phos::Digit>>("digits"); auto digits = ctx.inputs().get<std::vector<o2::phos::Digit>>("digits"); auto digitsTR = ctx.inputs().get<std::vector<o2::phos::TriggerRecord>>("digitTriggerRecords"); - - // auto digitsTR = ctx.inputs().get<std::vector<o2::phos::TriggerRecord>>("digitTriggerRecords"); LOG(DEBUG) << "[PHOSClusterizer - run] Received " << digitsTR.size() << " TR, running clusterizer ..."; - auto truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("digitsmctr"); - mClusterizer.process(digits, digitsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + // const o2::dataformats::MCTruthContainer<MCLabel>* truthcont=nullptr; + if (mPropagateMC) { + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::phos::MCLabel>> truthcont(ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("digitsmctr")); + mClusterizer.process(digits, digitsTR, truthcont.get(), mOutputClusters, mOutputCluElements, mOutputClusterTrigRecs, mOutputTruthCont); // Find clusters on digits (pass by ref) + } else { + mClusterizer.process(digits, digitsTR, nullptr, mOutputClusters, mOutputCluElements, mOutputClusterTrigRecs, mOutputTruthCont); // Find clusters on digits (pass by ref) + } } else { LOG(DEBUG) << "PHOSClusterizer - run run on cells called"; - auto dataref = ctx.inputs().get("cells"); - auto const* phosheader = o2::framework::DataRefUtils::getHeader<o2::phos::PHOSBlockHeader*>(dataref); - if (!phosheader->mHasPayload) { - LOG(DEBUG) << "[PHOSClusterizer - run] No more cells" << std::endl; - ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); - return; - } - - auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells"); + auto cells = ctx.inputs().get<std::vector<o2::phos::Cell>>("cells"); + // auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells"); LOG(DEBUG) << "[PHOSClusterizer - run] Received " << cells.size() << " cells, running clusterizer ..."; - auto cellsTR = ctx.inputs().get<gsl::span<o2::phos::TriggerRecord>>("cellTriggerRecords"); - auto truthcont = ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("cellsmctr"); - auto truthmap = ctx.inputs().get<gsl::span<uint>>("cellssmcmap"); - - mClusterizer.processCells(cells, cellsTR, truthcont.get(), truthmap, &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + // auto cellsTR = ctx.inputs().get<gsl::span<o2::phos::TriggerRecord>>("cellTriggerRecords"); + auto cellsTR = ctx.inputs().get<std::vector<o2::phos::TriggerRecord>>("cellTriggerRecords"); + if (mPropagateMC) { + std::unique_ptr<const o2::dataformats::MCTruthContainer<o2::phos::MCLabel>> truthcont(ctx.inputs().get<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>*>("cellsmctr")); + // truthmap = ctx.inputs().get<gsl::span<uint>>("cellssmcmap"); + mClusterizer.processCells(cells, cellsTR, truthcont.get(), mOutputClusters, mOutputCluElements, mOutputClusterTrigRecs, mOutputTruthCont); // Find clusters on digits (pass by ref) + } else { + mClusterizer.processCells(cells, cellsTR, nullptr, mOutputClusters, mOutputCluElements, mOutputClusterTrigRecs, mOutputTruthCont); // Find clusters on digits (pass by ref) + } } - LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; + if (mPropagateMC) { + LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; + } else { + LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters and " << mOutputClusterTrigRecs.size() << " TR"; + } ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusters); - ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusterTrigRecs); + if (mFullCluOutput) { + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUELEMENTS", 0, o2::framework::Lifetime::Timeframe}, mOutputCluElements); + } + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputClusterTrigRecs); if (mPropagateMC) { ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERTRUEMC", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthCont); } - LOG(INFO) << "Finished "; ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); } -o2::framework::DataProcessorSpec o2::phos::reco_workflow::getClusterizerSpec(bool propagateMC) +o2::framework::DataProcessorSpec o2::phos::reco_workflow::getClusterizerSpec(bool propagateMC, bool fullClu) { std::vector<o2::framework::InputSpec> inputs; std::vector<o2::framework::OutputSpec> outputs; @@ -88,7 +120,10 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getClusterizerSpec(boo inputs.emplace_back("digitsmctr", "PHS", "DIGITSMCTR", 0, o2::framework::Lifetime::Timeframe); } outputs.emplace_back("PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe); - outputs.emplace_back("PHS", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe); + if (fullClu) { + outputs.emplace_back("PHS", "CLUELEMENTS", 0, o2::framework::Lifetime::Timeframe); + } + outputs.emplace_back("PHS", "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe); if (propagateMC) { outputs.emplace_back("PHS", "CLUSTERTRUEMC", 0, o2::framework::Lifetime::Timeframe); } @@ -96,10 +131,10 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getClusterizerSpec(boo return o2::framework::DataProcessorSpec{"PHOSClusterizerSpec", inputs, outputs, - o2::framework::adaptFromTask<o2::phos::reco_workflow::ClusterizerSpec>(propagateMC)}; + o2::framework::adaptFromTask<o2::phos::reco_workflow::ClusterizerSpec>(propagateMC, true, fullClu)}; } -o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellClusterizerSpec(bool propagateMC) +o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellClusterizerSpec(bool propagateMC, bool fullClu) { //Cluaterizer with cell input std::vector<o2::framework::InputSpec> inputs; @@ -108,10 +143,12 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellClusterizerSpec inputs.emplace_back("cellTriggerRecords", o2::header::gDataOriginPHS, "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe); if (propagateMC) { inputs.emplace_back("cellsmctr", "PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe); - inputs.emplace_back("cellssmcmap", "PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe); } outputs.emplace_back("PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe); - outputs.emplace_back("PHS", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe); + if (fullClu) { + outputs.emplace_back("PHS", "CLUELEMENTS", 0, o2::framework::Lifetime::Timeframe); + } + outputs.emplace_back("PHS", "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe); if (propagateMC) { outputs.emplace_back("PHS", "CLUSTERTRUEMC", 0, o2::framework::Lifetime::Timeframe); } @@ -119,5 +156,5 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellClusterizerSpec return o2::framework::DataProcessorSpec{"PHOSClusterizerSpec", inputs, outputs, - o2::framework::adaptFromTask<o2::phos::reco_workflow::ClusterizerSpec>(propagateMC)}; + o2::framework::adaptFromTask<o2::phos::reco_workflow::ClusterizerSpec>(propagateMC, false, fullClu)}; } diff --git a/Detectors/PHOS/workflow/src/DigitsPrinterSpec.cxx b/Detectors/PHOS/workflow/src/DigitsPrinterSpec.cxx index fd95b46e415b5..e74730e7b4c96 100644 --- a/Detectors/PHOS/workflow/src/DigitsPrinterSpec.cxx +++ b/Detectors/PHOS/workflow/src/DigitsPrinterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx b/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..78350f74c3b9e --- /dev/null +++ b/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "PHOSWorkflow/EntropyDecoderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& triggers = pc.outputs().make<std::vector<TriggerRecord>>(OutputRef{"triggers"}); + auto& cells = pc.outputs().make<std::vector<Cell>>(OutputRef{"cells"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::phos::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, triggers, cells); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << cells.size() << " PHOS cells in " << triggers.size() << " triggers in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "PHOS Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"triggers"}, "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe}, + OutputSpec{{"cells"}, "PHS", "CELLS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "phos-entropy-decoder", + Inputs{InputSpec{"ctf", "PHS", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace phos +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx b/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..4beede08b054c --- /dev/null +++ b/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "PHOSWorkflow/EntropyEncoderSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto triggers = pc.inputs().get<gsl::span<TriggerRecord>>("triggers"); + auto cells = pc.inputs().get<gsl::span<Cell>>("cells"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"PHS", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, triggers, cells); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for PHOS in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "PHOS Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("triggers", "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe); + inputs.emplace_back("cells", "PHS", "CELLS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "phos-entropy-encoder", + inputs, + Outputs{{"PHS", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace phos +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/PublisherSpec.cxx b/Detectors/PHOS/workflow/src/PublisherSpec.cxx deleted file mode 100644 index 574a447552ab0..0000000000000 --- a/Detectors/PHOS/workflow/src/PublisherSpec.cxx +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFormatsPHOS/PHOSBlockHeader.h" -#include "PHOSWorkflow/PublisherSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Headers/DataHeader.h" -#include "DPLUtils/RootTreeReader.h" -#include "Framework/DataSpecUtils.h" -#include <memory> -#include <utility> - -namespace o2 -{ - -namespace phos -{ - -o2::framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC, bool createMCMap) -{ - struct ProcessAttributes { - std::shared_ptr<o2::framework::RootTreeReader> reader; - std::string datatype; - bool terminateOnEod; - bool finished; - }; - - auto initFunction = [config, propagateMC, createMCMap](o2::framework::InitContext& ic) { - // get the option from the init context - auto filename = ic.options().get<std::string>("infile"); - auto treename = ic.options().get<std::string>("treename"); - auto dtbrName = ic.options().get<std::string>(config.databranch.option.c_str()); // databranch name - auto dttrbrName = ic.options().get<std::string>(config.datatrbranch.option.c_str()); // datatrigrec name - auto mcbrName = ic.options().get<std::string>(config.mcbranch.option.c_str()); // mcbranch name - auto mcmapbrName = ic.options().get<std::string>(config.mcmapbranch.option.c_str()); // mc map branch name - auto nofEvents = ic.options().get<int>("nevents"); - // auto publishingMode = nofEvents == -1 ? o2::framework::RootTreeReader::PublishingMode::Single : o2::framework::RootTreeReader::PublishingMode::Loop; - auto publishingMode = o2::framework::RootTreeReader::PublishingMode::Single; - - auto processAttributes = std::make_shared<ProcessAttributes>(); - { - processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); - processAttributes->finished = false; - processAttributes->datatype = config.databranch.defval; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); - constexpr auto persistency = o2::framework::Lifetime::Timeframe; - o2::header::DataHeader::SubSpecificationType subSpec = 0; - if (propagateMC) { - if (!createMCMap) { - processAttributes->reader = std::make_shared<o2::framework::RootTreeReader>(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str() // name of mc label branch - ); - } else { - processAttributes->reader = std::make_shared<o2::framework::RootTreeReader>(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str(), // name of mc label branch - o2::framework::Output{mcmapo.origin, mcmapo.description, subSpec, persistency}, - mcmapbrName.c_str() // name of mc label branch - ); - } - } else { - processAttributes->reader = std::make_shared<o2::framework::RootTreeReader>(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str() // name of data tr branch - ); - } - } - - auto processFunction = [processAttributes, propagateMC, createMCMap](o2::framework::ProcessingContext& pc) { - if (processAttributes->finished) { - return; - } - - auto publish = [&processAttributes, &pc, propagateMC, createMCMap]() { - o2::phos::PHOSBlockHeader phosheader(true); - if (processAttributes->reader->next()) { - (*processAttributes->reader)(pc, phosheader); - } else { - processAttributes->reader.reset(); - return false; - } - return true; - }; - - bool active(true); - if (!publish()) { - active = false; - // Send dummy header with no payload option - o2::phos::PHOSBlockHeader dummyheader(false); - pc.outputs().snapshot(o2::framework::OutputRef{"output", 0, {dummyheader}}, 0); - pc.outputs().snapshot(o2::framework::OutputRef{"outputTR", 0, {dummyheader}}, 0); - if (propagateMC) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMC", 0, {dummyheader}}, 0); - if (createMCMap) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMCmap", 0, {dummyheader}}, 0); - } - } - } - if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { - pc.services().get<o2::framework::ControlService>().endOfStream(); - pc.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); - } - }; - - return processFunction; - }; - - auto createOutputSpecs = [&config, propagateMC, createMCMap]() { - std::vector<o2::framework::OutputSpec> outputSpecs; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"output"}, dto.origin, dto.description, 0, o2::framework::Lifetime::Timeframe}); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputTR"}, dttro.origin, dttro.description, 0, o2::framework::Lifetime::Timeframe}); - if (propagateMC) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMC"}, mco.origin, mco.description, 0, o2::framework::Lifetime::Timeframe}); - if (createMCMap) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMCmap"}, mcmapo.origin, mcmapo.description, 0, o2::framework::Lifetime::Timeframe}); - } - } - return std::move(outputSpecs); - }; - - auto& dtb = config.databranch; - auto& dttrb = config.datatrbranch; - auto& mcb = config.mcbranch; - auto& mcmapb = config.mcmapbranch; - return o2::framework::DataProcessorSpec{ - config.processName.c_str(), - o2::framework::Inputs{}, // no inputs - {createOutputSpecs()}, - o2::framework::AlgorithmSpec(initFunction), - o2::framework::Options{ - {"infile", o2::framework::VariantType::String, "", {"Name of the input file"}}, - {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, - {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, - {dttrb.option.c_str(), o2::framework::VariantType::String, dttrb.defval.c_str(), {dttrb.help.c_str()}}, - {mcb.option.c_str(), o2::framework::VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, - {mcmapb.option.c_str(), o2::framework::VariantType::String, mcmapb.defval.c_str(), {mcmapb.help.c_str()}}, - {"nevents", o2::framework::VariantType::Int, -1, {"number of events to run"}}, - {"terminate-on-eod", o2::framework::VariantType::Bool, true, {"terminate on end-of-data"}}, - }}; -} - -} // namespace phos - -} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/RawToCellConverterSpec.cxx b/Detectors/PHOS/workflow/src/RawToCellConverterSpec.cxx new file mode 100644 index 0000000000000..77dc8fa4d54b1 --- /dev/null +++ b/Detectors/PHOS/workflow/src/RawToCellConverterSpec.cxx @@ -0,0 +1,286 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include <string> +#include "FairLogger.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsPHOS/PHOSBlockHeader.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Framework/InputRecordWalker.h" +#include "CCDB/CcdbApi.h" +#include "PHOSBase/Mapping.h" +#include "PHOSBase/PHOSSimParams.h" +#include "PHOSReconstruction/CaloRawFitter.h" +#include "PHOSReconstruction/CaloRawFitterGS.h" +#include "PHOSReconstruction/RawDecodingError.h" +#include "PHOSWorkflow/RawToCellConverterSpec.h" + +using namespace o2::phos::reco_workflow; + +void RawToCellConverterSpec::init(framework::InitContext& ctx) +{ + LOG(DEBUG) << "Initialize converter "; + + auto path = ctx.options().get<std::string>("mappingpath"); + Mapping::Instance(path); + + if (!mCalibParams) { + if (o2::phos::PHOSSimParams::Instance().mCCDBPath.compare("localtest") == 0) { + mCalibParams = std::make_unique<CalibParams>(1); // test default calibration + LOG(INFO) << "[RawToCellConverterSpec] No reading calibration from ccdb requested, set default"; + } else { + LOG(INFO) << "[RawToCellConverterSpec] getting calibration object from ccdb"; + o2::ccdb::CcdbApi ccdb; + std::map<std::string, std::string> metadata; + ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + // auto tr = triggerbranch.begin(); + double eventTime = -1; + // if(tr!=triggerbranch.end()){ + // eventTime = (*tr).getBCData().getTimeNS() ; + // } + // mCalibParams = ccdb.retrieveFromTFileAny<o2::phos::CalibParams>("PHOS/Calib", metadata, eventTime); + if (!mCalibParams) { + LOG(FATAL) << "[RawToCellConverterSpec] can not get calibration object from ccdb"; + } + } + } + + auto fitmethod = ctx.options().get<std::string>("fitmethod"); + if (fitmethod == "default") { + LOG(INFO) << "Using default raw fitter"; + mRawFitter = std::unique_ptr<o2::phos::CaloRawFitter>(new o2::phos::CaloRawFitter); + } + if (fitmethod == "semigaus") { + LOG(INFO) << "Using SemiGauss raw fitter"; + mRawFitter = std::unique_ptr<o2::phos::CaloRawFitter>(new o2::phos::CaloRawFitterGS); + } + + mFillChi2 = (ctx.options().get<std::string>("fillchi2").compare("on") == 0); + if (mFillChi2) { + LOG(INFO) << "Fit quality output will be filled"; + } + + mDecoder = std::make_unique<AltroDecoder>(); + + mPedestalRun = (ctx.options().get<std::string>("pedestal").find("on") != std::string::npos); + if (mPedestalRun) { + mRawFitter->setPedestal(); + mDecoder->setPedestalRun(); //sets also keeping both HG and LG channels + LOG(INFO) << "Pedestal run will be processed"; + } + + mCombineGHLG = (ctx.options().get<std::string>("keepHGLG").compare("on") != 0); + if (!mCombineGHLG) { + mDecoder->setCombineHGLG(false); + LOG(INFO) << "Both HighGain and LowGain will be kept"; + } +} + +void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) +{ + // Cache cells from bunch crossings as the component reads timeframes from many links consecutively + std::vector<o2::InteractionRecord> irList; + std::vector<std::array<short, 56>> cellTRURanges; // start/end points for cells in mTmpCells[ddl] arrays + for (int iddl = 14; iddl--;) { + mTmpCells[iddl].clear(); + mTmpTRU[iddl].clear(); + } + mOutputHWErrors.clear(); + if (mFillChi2) { + mOutputFitChi.clear(); + } + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + std::vector<o2::framework::InputSpec> dummy{o2::framework::InputSpec{"dummy", o2::framework::ConcreteDataMatcher{"PHS", o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : framework::InputRecordWalker(ctx.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { // send empty output + mOutputCells.clear(); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLS", 0, o2::framework::Lifetime::Timeframe}, mOutputCells); + mOutputTriggerRecords.clear(); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputTriggerRecords); + mOutputHWErrors.clear(); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe}, mOutputHWErrors); + if (mFillChi2) { + mOutputFitChi.clear(); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLFITQA", 0, o2::framework::Lifetime::Timeframe}, mOutputFitChi); + } + return; //empty TF, nothing to process + } + } + + std::vector<o2::framework::InputSpec> inputFilter{o2::framework::InputSpec{"filter", o2::framework::ConcreteDataTypeMatcher{"PHS", "RAWDATA"}, o2::framework::Lifetime::Timeframe}}; + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs(), inputFilter)) { + + o2::phos::RawReaderMemory rawreader(o2::framework::DataRefUtils::as<const char>(rawData)); + + // loop over all the DMA pages + while (rawreader.hasNext()) { + try { + rawreader.next(); + } catch (RawDecodingError::ErrorType_t e) { + LOG(ERROR) << "Raw decoding error " << (int)e; + //add error list + mOutputHWErrors.emplace_back(14, (int)e, 1); //Put general errors to non-existing DDL14 + //if problem in header, abandon this page + if (e == RawDecodingError::ErrorType_t::PAGE_NOTFOUND || + e == RawDecodingError::ErrorType_t::HEADER_DECODING || + e == RawDecodingError::ErrorType_t::HEADER_INVALID) { + break; + } + //if problem in payload, try to continue + continue; + } + auto& header = rawreader.getRawHeader(); + auto triggerBC = o2::raw::RDHUtils::getTriggerBC(header); + auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(header); + auto ddl = o2::raw::RDHUtils::getFEEID(header); + + if (ddl > o2::phos::Mapping::NDDL || ddl < 0) { //only 14 correct DDLs + LOG(ERROR) << "DDL=" << ddl; + mOutputHWErrors.emplace_back(15, 16, char(ddl)); //Add non-existing DDL as DDL 15 + continue; //skip STU ddl + } + + o2::InteractionRecord currentIR(triggerBC, triggerOrbit); + auto irIter = irList.rbegin(); + auto rangeIter = cellTRURanges.rbegin(); + while (irIter != irList.rend() && *irIter != currentIR) { + irIter++; + rangeIter++; + } + if (irIter != irList.rend()) { //found + (*rangeIter)[2 * ddl] = mTmpCells[ddl].size(); //start of the cell list + (*rangeIter)[28 + 2 * ddl] = mTmpTRU[ddl].size(); //start of the tru list + } else { //create new entry + irList.push_back(currentIR); + cellTRURanges.emplace_back(); + cellTRURanges.back().fill(0); + cellTRURanges.back()[2 * ddl] = mTmpCells[ddl].size(); + cellTRURanges.back()[28 + 2 * ddl] = mTmpTRU[ddl].size(); + rangeIter = cellTRURanges.rbegin(); + } + std::vector<Cell>& currentCellContainer = mTmpCells[ddl]; + std::vector<Cell>& currentTRUContainer = mTmpTRU[ddl]; + + // use the altro decoder to decode the raw data, and extract the RCU trailer + mDecoder->decode(rawreader, mRawFitter.get(), currentCellContainer, currentTRUContainer); + const std::vector<o2::phos::RawReaderError>& errs = mDecoder->hwerrors(); + for (auto a : errs) { + mOutputHWErrors.emplace_back(a); + } + // Sort cells according to cell ID + (*rangeIter)[2 * ddl + 1] = currentCellContainer.size(); + auto itBegin = currentCellContainer.begin() + (*rangeIter)[2 * ddl]; + std::sort(itBegin, currentCellContainer.end(), [](o2::phos::Cell& lhs, o2::phos::Cell& rhs) { return lhs.getAbsId() < rhs.getAbsId(); }); + auto itTrBegin = currentTRUContainer.begin() + (*rangeIter)[28 + 2 * ddl]; + (*rangeIter)[28 + 2 * ddl + 1] = currentTRUContainer.size(); + std::sort(itTrBegin, currentTRUContainer.end(), [](o2::phos::Cell& lhs, o2::phos::Cell& rhs) { return lhs.getAbsId() < rhs.getAbsId(); }); + } //RawReader::hasNext + } + + // Loop over BCs, sort cells with increasing cell ID and write to output containers + mOutputCells.clear(); + if (mLastSize > 0) { + mOutputCells.reserve(mLastSize); + } + mOutputTriggerRecords.clear(); + auto rangeIter = cellTRURanges.begin(); + for (auto irIter = irList.begin(); irIter != irList.end(); ++irIter, ++rangeIter) { + // find all DDLs for current BC + // sort separately then concatenate + int prevCellSize = mOutputCells.size(); + for (int iddl = 0; iddl < 14; iddl++) { + auto cbegin = mTmpCells[iddl].begin() + (*rangeIter)[2 * iddl]; + auto cend = mTmpCells[iddl].begin() + (*rangeIter)[2 * iddl + 1]; + + if (mCombineGHLG && !mPedestalRun) { // combine for normal data, do not combine e.g. for LED run and pedestal + //Combine HG and LG sells + //Should be next to each other after sorting + auto it1 = cbegin; + auto it2 = cbegin; + it2++; + while (it1 != cend) { + if (it2 != cend) { + if ((*it1).getAbsId() == (*it2).getAbsId()) { //HG and LG channels, if both, copy only HG as more precise + if ((*it1).getType() == o2::phos::HIGH_GAIN) { + mOutputCells.push_back(*it1); + } else { + mOutputCells.push_back(*it2); + } + ++it1; //yes increase twice + ++it2; + } else { //no double cells, copy this one + mOutputCells.push_back(*it1); + } + } else { //just copy last one + mOutputCells.push_back(*it1); + } + ++it1; + ++it2; + } + } else { + mOutputCells.insert(mOutputCells.end(), cbegin, cend); + } + } //all readout cells + for (int iddl = 0; iddl < 14; iddl++) { + auto trbegin = mTmpTRU[iddl].begin() + (*rangeIter)[28 + 2 * iddl]; + auto trend = mTmpTRU[iddl].begin() + (*rangeIter)[28 + 2 * iddl + 1]; + //Move trigger cells + for (auto tri = trbegin; tri != trend; tri++) { + if (tri->getEnergy() > 0) { + mOutputCells.emplace_back(tri->getAbsId(), tri->getEnergy(), tri->getTime(), tri->getType()); + } + } + } + + mOutputTriggerRecords.emplace_back(*irIter, prevCellSize, mOutputCells.size() - prevCellSize); + } + + mLastSize = 1.1 * mOutputCells.size(); + + LOG(DEBUG) << "[PHOSRawToCellConverter - run] Writing " << mOutputCells.size() << " cells ..."; + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLS", 0, o2::framework::Lifetime::Timeframe}, mOutputCells); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputTriggerRecords); + ctx.outputs().snapshot(o2::framework::Output{"PHS", "RAWHWERRORS", 0, o2::framework::Lifetime::Timeframe}, mOutputHWErrors); + if (mFillChi2) { + ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLFITQA", 0, o2::framework::Lifetime::Timeframe}, mOutputFitChi); + } +} + +o2::framework::DataProcessorSpec o2::phos::reco_workflow::getRawToCellConverterSpec(int flpId) +{ + std::vector<o2::framework::InputSpec> inputs; + inputs.emplace_back("RAWDATA", o2::framework::ConcreteDataTypeMatcher{"PHS", "RAWDATA"}, o2::framework::Lifetime::Optional); + //receive at least 1 guaranteed input (which will allow to acknowledge the TF) + inputs.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back("PHS", "CELLS", flpId, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("PHS", "CELLTRIGREC", flpId, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("PHS", "RAWHWERRORS", flpId, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("PHS", "CELLFITQA", flpId, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{"PHOSRawToCellConverterSpec", + inputs, // o2::framework::select("A:PHS/RAWDATA"), + outputs, + o2::framework::adaptFromTask<o2::phos::reco_workflow::RawToCellConverterSpec>(), + o2::framework::Options{ + {"fitmethod", o2::framework::VariantType::String, "default", {"Fit method (default or semigaus)"}}, + {"mappingpath", o2::framework::VariantType::String, "", {"Path to mapping files"}}, + {"fillchi2", o2::framework::VariantType::String, "off", {"Fill sample qualities on/off"}}, + {"keepHGLG", o2::framework::VariantType::String, "off", {"keep HighGain and Low Gain signals on/off"}}, + {"pedestal", o2::framework::VariantType::String, "off", {"Analyze as pedestal run on/off"}}}}; +} diff --git a/Detectors/PHOS/workflow/src/RawWriterSpec.cxx b/Detectors/PHOS/workflow/src/RawWriterSpec.cxx new file mode 100644 index 0000000000000..248c2f0ed42de --- /dev/null +++ b/Detectors/PHOS/workflow/src/RawWriterSpec.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "FairLogger.h" + +/// \file PHOS/Workflow/src/RawWriterSpec.cxx +/// \brief Digits to raw converter spec for PHOS +/// \author Dmitri Peresunko <Dmitri.Peresunko at cern.ch> +/// \date 20 Nov 2020 + +#include "PHOSWorkflow/RawWriterSpec.h" +#include "Framework/RootSerializationSupport.h" +#include "DataFormatsPHOS/Digit.h" +#include "Framework/ControlService.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "PHOSSimulation/RawWriter.h" +#include "DataFormatsPHOS/PHOSBlockHeader.h" +#include "Framework/ConfigParamRegistry.h" + +using namespace o2::phos::reco_workflow; + +void RawWriterSpec::init(framework::InitContext& ctx) +{ + + auto rawdir = ctx.options().get<std::string>("rawpath"); + + LOG(INFO) << "[PHOSRawWriter - init] Initialize raw writer "; + if (!mRawWriter) { + mRawWriter = new o2::phos::RawWriter(); + mRawWriter->setOutputLocation(rawdir.data()); + mRawWriter->init(); + } +} + +void RawWriterSpec::run(framework::ProcessingContext& ctx) +{ + LOG(DEBUG) << "[PHOSRawWriter - run] called"; + + auto digits = ctx.inputs().get<std::vector<o2::phos::Digit>>("digits"); + auto digitsTR = ctx.inputs().get<std::vector<o2::phos::TriggerRecord>>("digitTriggerRecords"); + LOG(INFO) << "[PHOSRawWriter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords"; + + mRawWriter->digitsToRaw(digits, digitsTR); + LOG(INFO) << "[PHOSRawWriter - run] Finished "; + + //flash and close output files + mRawWriter->getWriter().close(); + ctx.services().get<o2::framework::ControlService>().readyToQuit(framework::QuitRequest::Me); +} + +o2::framework::DataProcessorSpec o2::phos::reco_workflow::getRawWriterSpec() +{ + std::vector<o2::framework::InputSpec> inputs; + std::vector<o2::framework::OutputSpec> outputs; + inputs.emplace_back("digits", o2::header::gDataOriginPHS, "DIGITS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("digitTriggerRecords", o2::header::gDataOriginPHS, "DIGITTRIGREC", 0, o2::framework::Lifetime::Timeframe); + return o2::framework::DataProcessorSpec{"PHOSRawWriterSpec", + inputs, + outputs, + o2::framework::adaptFromTask<o2::phos::reco_workflow::RawWriterSpec>(), + o2::framework::Options{ + {"rawpath", o2::framework::VariantType::String, "./", {"path to write raw"}}, + }}; +} diff --git a/Detectors/PHOS/workflow/src/ReaderSpec.cxx b/Detectors/PHOS/workflow/src/ReaderSpec.cxx new file mode 100644 index 0000000000000..7607fa34b494b --- /dev/null +++ b/Detectors/PHOS/workflow/src/ReaderSpec.cxx @@ -0,0 +1,242 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsPHOS/PHOSBlockHeader.h" +#include "PHOSWorkflow/ReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/DataSpecUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include <memory> +#include <utility> + +using namespace o2::framework; + +namespace o2 +{ + +namespace phos +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +struct ProcessAttributes { + std::shared_ptr<RootTreeReader> reader; + std::string datatype; + bool terminateOnEod; + bool finished; +}; + +DataProcessorSpec getDigitsReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + auto treename = ic.options().get<std::string>("treename"); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "PHOSDigit"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "DIGITS", subSpec, persistency}, + "PHOSDigit", // name of data branch + Output{"PHS", "DIGITTRIGREC", subSpec, persistency}, + "PHOSDigitTrigRecords", // name of data triggerrecords branch + Output{"PHS", "DIGITSMCTR", subSpec, persistency}, + "PHOSDigitMCTruth"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "DIGITS", subSpec, persistency}, + "PHOSDigit", // name of data branch + Output{"PHS", "DIGITTRIGREC", subSpec, persistency}, + "PHOSDigitTrigRecords"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::phos::PHOSBlockHeader phosheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, phosheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::phos::PHOSBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "PHS", "DIGITS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "PHS", "DIGITTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "PHS", "DIGITSMCTR", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "phos-digit-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "phosdigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +///////////////Cell reader + +DataProcessorSpec getCellReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + auto treename = ic.options().get<std::string>("treename"); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "PHOSCell"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "CELLS", subSpec, persistency}, + "PHOSCell", // name of data branch + Output{"PHS", "CELLTRIGREC", subSpec, persistency}, + "PHOSCellTrigRec", // name of data triggerrecords branch + Output{"PHS", "CELLSMCTR", subSpec, persistency}, + "PHOSCellTrueMC"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared<RootTreeReader>(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "CELLS", subSpec, persistency}, + "PHOSCell", // name of data branch + Output{"PHS", "CELLTRIGREC", subSpec, persistency}, + "PHOSCellTrigRec"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + PHOSBlockHeader phosheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, phosheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + PHOSBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputMCmap", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "PHS", "CELLS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "PHS", "CELLSMCTR", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputMCmap"}, "PHS", "CELLSMCMAP", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "phos-cell-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "phoscells.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +} // namespace phos + +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx index cc925c40d7011..345078191b033 100644 --- a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,9 +25,10 @@ #include "PHOSWorkflow/RecoWorkflow.h" #include "PHOSWorkflow/CellConverterSpec.h" #include "PHOSWorkflow/ClusterizerSpec.h" -#include "PHOSWorkflow/DigitsPrinterSpec.h" -#include "PHOSWorkflow/PublisherSpec.h" -//#include "PHOSWorkflow/RawWriterSpec.h" +#include "PHOSWorkflow/ReaderSpec.h" +#include "PHOSWorkflow/WriterSpec.h" +#include "PHOSWorkflow/RawToCellConverterSpec.h" +#include "PHOSWorkflow/RawWriterSpec.h" #include "Framework/DataSpecUtils.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -43,21 +45,21 @@ namespace reco_workflow { const std::unordered_map<std::string, InputType> InputMap{ - {"hits", InputType::Hits}, + {"raw", InputType::Raw}, {"digits", InputType::Digits}, - {"cells", InputType::Cells}, - {"raw", InputType::Raw}}; + {"cells", InputType::Cells}}; const std::unordered_map<std::string, OutputType> OutputMap{ - {"digits", OutputType::Digits}, {"cells", OutputType::Cells}, - {"raw", OutputType::Raw}, {"clusters", OutputType::Clusters}}; -o2::framework::WorkflowSpec getWorkflow(bool propagateMC, - bool enableDigitsPrinter, +o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC, std::string const& cfgInput, - std::string const& cfgOutput) + std::string const& cfgOutput, + bool fullCluOut, + int ddlId) { InputType inputType; @@ -78,181 +80,58 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, o2::framework::WorkflowSpec specs; - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::phos::reco_workflow::getRawWriterSpec()); - // } + //Raw to .... + if (inputType == InputType::Raw) { + //no explicit raw reader ?? - if (inputType == InputType::Digits) { - specs.emplace_back(o2::phos::getPublisherSpec(PublisherConf{ - "phos-digit-reader", - "o2sim", - {"digitbranch", "PHOSDigit", "Digit branch"}, - {"digittrigger", "PHOSDigitTrigRecords", "TrigRecords branch"}, - {"mcbranch", "PHOSDigitMCTruth", "MC label branch"}, - {"mcmapbranch", "", "Dummy branch"}, - o2::framework::OutputSpec{"PHS", "DIGITS"}, - o2::framework::OutputSpec{"PHS", "DIGITTRIGREC"}, - o2::framework::OutputSpec{"PHS", "DIGITSMCTR"}, - o2::framework::OutputSpec{"PHS", ""}}, // it empty, do not create - propagateMC, false)); - - if (enableDigitsPrinter) { - specs.emplace_back(o2::phos::reco_workflow::getPhosDigitsPrinterSpec()); + if (isEnabled(OutputType::Cells)) { + specs.emplace_back(o2::phos::reco_workflow::getRawToCellConverterSpec(ddlId)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getCellWriterSpec(false)); + } } + if (isEnabled(OutputType::Clusters)) { + specs.emplace_back(o2::phos::reco_workflow::getRawToCellConverterSpec(ddlId)); + specs.emplace_back(o2::phos::reco_workflow::getCellClusterizerSpec(false, fullCluOut)); //no MC propagation + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(false)); + } + } + } + // Digits to .... + if (inputType == InputType::Digits) { + if (!disableRootInp) { + specs.emplace_back(o2::phos::getDigitsReaderSpec(propagateMC)); + } if (isEnabled(OutputType::Cells)) { // add converter for cells specs.emplace_back(o2::phos::reco_workflow::getCellConverterSpec(propagateMC)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getCellWriterSpec(propagateMC)); + } + } else { + if (isEnabled(OutputType::Clusters)) { + specs.emplace_back(o2::phos::reco_workflow::getClusterizerSpec(propagateMC, fullCluOut)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(propagateMC)); + } + } } - - if (isEnabled(OutputType::Clusters)) { - // add clusterizer - specs.emplace_back(o2::phos::reco_workflow::getClusterizerSpec(propagateMC)); - } - - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::phos::reco_workflow::getRawWriterSpec()); - // } } + //Cells to if (inputType == InputType::Cells) { - specs.emplace_back(o2::phos::getPublisherSpec(PublisherConf{ - "phos-cell-reader", - "o2sim", - {"cellbranch", "PHSCell", "Cells branch"}, - {"celltrigger", "PHSCellTR", "TrigRecords branch"}, - {"mcbranch", "PHSCellMCTruth", "MC label branch"}, - {"mcmapbranch", "PHSCellMCMap", "MC label map branch"}, - o2::framework::OutputSpec{"PHS", "CELLS"}, - o2::framework::OutputSpec{"PHS", "CELLTRIGREC"}, - o2::framework::OutputSpec{"PHS", "CELLSMCTR"}, - o2::framework::OutputSpec{"PHS", "CELLSMCMAP"}}, - propagateMC, true)); - + if (!disableRootInp) { + specs.emplace_back(o2::phos::getCellReaderSpec(propagateMC)); + } if (isEnabled(OutputType::Clusters)) { // add clusterizer - specs.emplace_back(o2::phos::reco_workflow::getCellClusterizerSpec(propagateMC)); - } - } - - // check if the process is ready to quit - // this is decided upon the meta information in the PHOS block header, the operation is set - // value kNoPayload in case of no data or no operation - // see also PublisherSpec.cxx - // in this workflow, the EOD is sent after the last real data, and all inputs will receive EOD, - // so it is enough to check on the first occurence - // FIXME: this will be changed once DPL can propagate control events like EOD - auto checkReady = [](o2::framework::DataRef const& ref) { - auto const* phosheader = o2::framework::DataRefUtils::getHeader<o2::phos::PHOSBlockHeader*>(ref); - // sector number -1 indicates end-of-data - if (phosheader != nullptr) { - // indicate normal processing if not ready and skip if ready - if (!phosheader->mHasPayload) { - return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::SkipProcessing, true); + specs.emplace_back(o2::phos::reco_workflow::getCellClusterizerSpec(propagateMC, fullCluOut)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(propagateMC)); } } - return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::DoProcessing, false); - }; - - // auto makeWriterSpec = [propagateMC, checkReady](const char* processName, - // const char* defaultFileName, - // const char* defaultTreeName, - // bool createMCMap, - // auto&& databranch, - // auto&& datatrbranch, - // auto&& mcbranch=nullptr, - // auto&& mcmapbranch=nullptr) { - // // depending on the MC propagation flag, the RootTreeWriter spec is created with two - // // or one branch definition - // if (propagateMC) { - // if(createMCMap){ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch), - // std::move(mcbranch), - // std::move(mcmapbranch))); - // } - // else{ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch), - // std::move(mcbranch))); - // } - // } - // else{ - // return std::move(o2::framework::MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // std::move(databranch), - // std::move(datatrbranch))); - // } - // }; - - // if (isEnabled(OutputType::Raw)) { - // using RawOutputType = std::vector<o2::phos::Raw>; - // specs.push_back(makeWriterSpec("phos-raw-writer", - // inputType == InputType::Digits ? "phos-raw.root" : "phosrawcells.root", - // "o2sim", - // BranchDefinition<DigitOutputType>{o2::framework::InputSpec{"data", "PHS", "RAW", 0}, - // "PHSRaw", - // "raw-branch-name"}, - // BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{o2::framework::InputSpec{"mc", "PHS", "RAWMCTR", 0}, - // "PHSRawMCTruth", - // "rawmc-branch-name"})()); - // } - - if (isEnabled(OutputType::Digits)) { - using DigitOutputType = std::vector<o2::phos::Digit>; - using DTROutputType = std::vector<o2::phos::TriggerRecord>; - - specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("phos-digits-writer", "phosdigits.root", "o2sim", - -1, - o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - BranchDefinition<DigitOutputType>{o2::framework::InputSpec{"data", "PHS", "DIGITS", 0}, - "PHSDigit", - "digit-branch-name"}, - BranchDefinition<DTROutputType>{o2::framework::InputSpec{"data", "PHS", "DIGITTRIGREC", 0}, - "PHSDigTR", - "digittr-branch-name"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{o2::framework::InputSpec{"mc", "PHS", "DIGITSMCTR", 0}, - "PHSDigitMCTruth", - "digitmc-branch-name"})()); - } - - if (isEnabled(OutputType::Cells)) { - using CellOutputType = std::vector<o2::phos::Cell>; - using CTROutputType = std::vector<o2::phos::TriggerRecord>; - specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("phos-cells-writer", "phoscells.root", "o2sim", -1, - o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - BranchDefinition<CellOutputType>{o2::framework::InputSpec{"data", "PHS", "CELLS", 0}, - "PHSCell", - "cell-branch-name"}, - BranchDefinition<CTROutputType>{o2::framework::InputSpec{"data", "PHS", "CELLTRIGREC", 0}, - "PHSCellTR", - "celltr-branch-name"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{o2::framework::InputSpec{"mc", "PHS", "CELLSMCTR", 0}, - "PHSCellMCTruth", - "cellmc-branch-name"}, - BranchDefinition<std::vector<uint>>{o2::framework::InputSpec{"mcmap", "PHS", "CELLSMCMAP", 0}, - "PHSCellMCMAP", - "cellmcmap-branch-name"})()); - } - - if (isEnabled(OutputType::Clusters)) { - specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("phos-clusters-writer", "phosclusters.root", "o2sim", -1, - o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - BranchDefinition<std::vector<o2::phos::Cluster>>{o2::framework::InputSpec{"data", "PHS", "CLUSTERS", 0}, - "PHSCluster", - "cluster-branch-name"}, - BranchDefinition<std::vector<o2::phos::TriggerRecord>>{o2::framework::InputSpec{"datatr", "PHS", "CLUSTERTRIGRECS", 0}, - "PHSClusTR", - "clustertr-branch-name"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{o2::framework::InputSpec{"mc", "PHS", "CLUSTERTRUEMC", 0}, - "PHSClusMC", - "clustermc-branch-name"})()); } return std::move(specs); diff --git a/Detectors/PHOS/workflow/src/WriterSpec.cxx b/Detectors/PHOS/workflow/src/WriterSpec.cxx new file mode 100644 index 0000000000000..a686cf535e2ac --- /dev/null +++ b/Detectors/PHOS/workflow/src/WriterSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.cxx + +#include <vector> + +#include "PHOSWorkflow/WriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/MCLabel.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using ClusType = std::vector<o2::phos::Cluster>; +using CellType = std::vector<o2::phos::Cell>; +using TriggerRecordType = std::vector<o2::phos::TriggerRecord>; +using MCLabelType = o2::dataformats::MCTruthContainer<o2::phos::MCLabel>; +using namespace o2::header; + +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto ClustersSize = std::make_shared<int>(0); + auto ClustersSizeGetter = [ClustersSize](ClusType const& Clusters) { + *ClustersSize = Clusters.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("phos-cluster-writer", + "phosclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS clusters"}, + BranchDefinition<ClusType>{InputSpec{"clus", "PHS", "CLUSTERS", 0}, + "PHOSCluster", ClustersSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"clusRecs", "PHS", "CLUSTERTRIGREC", 0}, + "PHOSClusterTrigRec"}, + BranchDefinition<MCLabelType>{InputSpec{"clusMC", "PHS", "CLUSTERTRUEMC", 0}, + "PHOSClusterTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("phos-cluster-writer", + "phosclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS clusters"}, + BranchDefinition<ClusType>{InputSpec{"clus", "PHS", "CLUSTERS", 0}, + "PHOSCluster", ClustersSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"clusRecs", "PHS", "CLUSTERTRIGREC", 0}, + "PHOSClusterTrigRec"})(); + } +} + +DataProcessorSpec getCellWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto CellSize = std::make_shared<int>(0); + auto CellSizeGetter = [CellSize](CellType const& Cells) { + *CellSize = Cells.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("phos-cell-writer", + "phoscells.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS cells"}, + BranchDefinition<CellType>{InputSpec{"cell", "PHS", "CELLS", 0}, + "PHOSCell", CellSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"PHOSCellTR", "PHS", "CELLTRIGREC", 0}, + "PHOSCellTrigRec"}, + BranchDefinition<MCLabelType>{InputSpec{"PHOSCellMCTruth", "PHS", "CELLSMCTR", 0}, + "PHOSCellTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("phos-cell-writer", + "phoscells.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS cells"}, + BranchDefinition<CellType>{InputSpec{"cell", "PHS", "CELLS", 0}, + "PHOSCell", CellSizeGetter}, + BranchDefinition<TriggerRecordType>{InputSpec{"PHOSCellTR", "PHS", "CELLTRIGREC", 0}, + "PHOSCellTrigRec"})(); + } +} +} // namespace phos +} // namespace o2 \ No newline at end of file diff --git a/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx b/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..c1a5dba036b12 --- /dev/null +++ b/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "PHOSWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::phos::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx index a81b3d1e9ea38..c9e1eda90977c 100644 --- a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx +++ b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include "Framework/ConfigParamSpec.h" #include "PHOSWorkflow/RecoWorkflow.h" #include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include <string> #include <stdexcept> @@ -27,11 +30,17 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { std::vector<o2::framework::ConfigParamSpec> options{ - {"input-type", o2::framework::VariantType::String, "hits", {"hits, digits, raw, clusters"}}, - {"output-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters, cells"}}, - {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, + {"input-type", o2::framework::VariantType::String, "digits", {"hits, digits, raw, clusters"}}, + {"output-type", o2::framework::VariantType::String, "cells", {"digits, raw, clusters, cells"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, - }; + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"fullclu-output", o2::framework::VariantType::Bool, false, {"compact of full (with contr. digits) clusters output"}}, + {"flpId", o2::framework::VariantType::Int, 0, {"FLP identification: 0,1,..."}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -52,9 +61,18 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // - return o2::phos::reco_workflow::getWorkflow(not cfgc.options().get<bool>("disable-mc"), // - cfgc.options().get<bool>("enable-digits-printer"), // - cfgc.options().get<std::string>("input-type"), // - cfgc.options().get<std::string>("output-type") // - ); + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + auto wf = o2::phos::reco_workflow::getWorkflow(cfgc.options().get<bool>("disable-root-input"), + cfgc.options().get<bool>("disable-root-output"), + !cfgc.options().get<bool>("disable-mc"), + cfgc.options().get<std::string>("input-type"), + cfgc.options().get<std::string>("output-type"), + cfgc.options().get<bool>("fullclu-output"), + cfgc.options().get<int>("flpId")); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); + + return std::move(wf); } diff --git a/Detectors/Passive/CMakeLists.txt b/Detectors/Passive/CMakeLists.txt index c53f2c75ad0a2..95bb39118cb20 100644 --- a/Detectors/Passive/CMakeLists.txt +++ b/Detectors/Passive/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsPassive SOURCES src/Absorber.cxx diff --git a/Detectors/Passive/include/DetectorsPassive/Absorber.h b/Detectors/Passive/include/DetectorsPassive/Absorber.h index 5b90be40b6729..81d74fb8d843f 100644 --- a/Detectors/Passive/include/DetectorsPassive/Absorber.h +++ b/Detectors/Passive/include/DetectorsPassive/Absorber.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Cave.h b/Detectors/Passive/include/DetectorsPassive/Cave.h index d060e210952c6..760c9c5b535fd 100644 --- a/Detectors/Passive/include/DetectorsPassive/Cave.h +++ b/Detectors/Passive/include/DetectorsPassive/Cave.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Compensator.h b/Detectors/Passive/include/DetectorsPassive/Compensator.h index 1bf50664e81ba..75b86b3d29c6a 100644 --- a/Detectors/Passive/include/DetectorsPassive/Compensator.h +++ b/Detectors/Passive/include/DetectorsPassive/Compensator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Dipole.h b/Detectors/Passive/include/DetectorsPassive/Dipole.h index e4583c1611e37..8ebc87e47cbbb 100644 --- a/Detectors/Passive/include/DetectorsPassive/Dipole.h +++ b/Detectors/Passive/include/DetectorsPassive/Dipole.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/FrameStructure.h b/Detectors/Passive/include/DetectorsPassive/FrameStructure.h index 60c129893acc1..451d15612cf72 100644 --- a/Detectors/Passive/include/DetectorsPassive/FrameStructure.h +++ b/Detectors/Passive/include/DetectorsPassive/FrameStructure.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Hall.h b/Detectors/Passive/include/DetectorsPassive/Hall.h index 04ab16c282158..2133859b27d22 100644 --- a/Detectors/Passive/include/DetectorsPassive/Hall.h +++ b/Detectors/Passive/include/DetectorsPassive/Hall.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/HallSimParam.h b/Detectors/Passive/include/DetectorsPassive/HallSimParam.h index ffa15d9c673a3..66fa7d96e6e2b 100644 --- a/Detectors/Passive/include/DetectorsPassive/HallSimParam.h +++ b/Detectors/Passive/include/DetectorsPassive/HallSimParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Magnet.h b/Detectors/Passive/include/DetectorsPassive/Magnet.h index 4238198e58e8b..81c9e4cfb835c 100644 --- a/Detectors/Passive/include/DetectorsPassive/Magnet.h +++ b/Detectors/Passive/include/DetectorsPassive/Magnet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/PassiveBase.h b/Detectors/Passive/include/DetectorsPassive/PassiveBase.h index 5a3ebc75e0893..1baf72d085cab 100644 --- a/Detectors/Passive/include/DetectorsPassive/PassiveBase.h +++ b/Detectors/Passive/include/DetectorsPassive/PassiveBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/PassiveContFact.h b/Detectors/Passive/include/DetectorsPassive/PassiveContFact.h index e44033d1ab96c..a68f2b8090dfe 100644 --- a/Detectors/Passive/include/DetectorsPassive/PassiveContFact.h +++ b/Detectors/Passive/include/DetectorsPassive/PassiveContFact.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Pipe.h b/Detectors/Passive/include/DetectorsPassive/Pipe.h index e05a0d80b0d00..1c03ed589a1b0 100644 --- a/Detectors/Passive/include/DetectorsPassive/Pipe.h +++ b/Detectors/Passive/include/DetectorsPassive/Pipe.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/include/DetectorsPassive/Shil.h b/Detectors/Passive/include/DetectorsPassive/Shil.h index 12cf24d85d1ba..38cd3b7ae755a 100644 --- a/Detectors/Passive/include/DetectorsPassive/Shil.h +++ b/Detectors/Passive/include/DetectorsPassive/Shil.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Absorber.cxx b/Detectors/Passive/src/Absorber.cxx index 959fea59a8449..97b091f5965a6 100644 --- a/Detectors/Passive/src/Absorber.cxx +++ b/Detectors/Passive/src/Absorber.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Cave.cxx b/Detectors/Passive/src/Cave.cxx index 80f5a2be02cc7..fa6850ed0565f 100644 --- a/Detectors/Passive/src/Cave.cxx +++ b/Detectors/Passive/src/Cave.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,7 +25,7 @@ #include "DetectorsBase/Detector.h" #include "DetectorsPassive/Cave.h" #include "SimConfig/SimConfig.h" -#include "SimConfig/SimCutParams.h" +#include "SimConfig/SimParams.h" #include <TRandom.h> #include "FairLogger.h" #include "TGeoManager.h" diff --git a/Detectors/Passive/src/Compensator.cxx b/Detectors/Passive/src/Compensator.cxx index deba512284a5d..68e344495aaab 100644 --- a/Detectors/Passive/src/Compensator.cxx +++ b/Detectors/Passive/src/Compensator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Dipole.cxx b/Detectors/Passive/src/Dipole.cxx index 694cf1e1d8844..eb9ee9e640373 100644 --- a/Detectors/Passive/src/Dipole.cxx +++ b/Detectors/Passive/src/Dipole.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/FrameStructure.cxx b/Detectors/Passive/src/FrameStructure.cxx index c9290e061b889..ac9f273275769 100644 --- a/Detectors/Passive/src/FrameStructure.cxx +++ b/Detectors/Passive/src/FrameStructure.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Hall.cxx b/Detectors/Passive/src/Hall.cxx index 316488a8c6a8a..52d6c2c324d56 100644 --- a/Detectors/Passive/src/Hall.cxx +++ b/Detectors/Passive/src/Hall.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/HallSimParam.cxx b/Detectors/Passive/src/HallSimParam.cxx index 5c1679984bc12..c24d8b7491937 100644 --- a/Detectors/Passive/src/HallSimParam.cxx +++ b/Detectors/Passive/src/HallSimParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Magnet.cxx b/Detectors/Passive/src/Magnet.cxx index 13faacbcbb08b..e4cea9d4b00da 100644 --- a/Detectors/Passive/src/Magnet.cxx +++ b/Detectors/Passive/src/Magnet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/PassiveBase.cxx b/Detectors/Passive/src/PassiveBase.cxx index 2952b335d98bd..65e74de98f08f 100644 --- a/Detectors/Passive/src/PassiveBase.cxx +++ b/Detectors/Passive/src/PassiveBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/PassiveContFact.cxx b/Detectors/Passive/src/PassiveContFact.cxx index 2542ad1467a35..1fce6d48536a0 100644 --- a/Detectors/Passive/src/PassiveContFact.cxx +++ b/Detectors/Passive/src/PassiveContFact.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/PassiveLinkDef.h b/Detectors/Passive/src/PassiveLinkDef.h index 9169834b8cb49..4ecb54ec2cb34 100644 --- a/Detectors/Passive/src/PassiveLinkDef.h +++ b/Detectors/Passive/src/PassiveLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Passive/src/Pipe.cxx b/Detectors/Passive/src/Pipe.cxx index 57d4e0678540e..ef169f9f682ab 100644 --- a/Detectors/Passive/src/Pipe.cxx +++ b/Detectors/Passive/src/Pipe.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -107,6 +108,7 @@ void Pipe::ConstructGeometry() const TGeoMedium* kMedRohacell = matmgr.getTGeoMedium("PIPE_ROHACELL"); const TGeoMedium* kMedPolyimide = matmgr.getTGeoMedium("PIPE_POLYIMIDE"); const TGeoMedium* kMedCarbonFiber = matmgr.getTGeoMedium("PIPE_M55J6K"); + const TGeoMedium* kMedTitanium = matmgr.getTGeoMedium("PIPE_TITANIUM"); // Top volume TGeoVolume* top = gGeoManager->GetVolume("cave"); @@ -226,7 +228,6 @@ void Pipe::ConstructGeometry() beamPipeCsideSection->AddNode(voberylliumTubeVacuum, 1, new TGeoTranslation(0., 0., (kBeryliumSectionZmax + kBeryliumSectionZmin) / 2)); - //---------------- Al tube ------------------ TGeoPcon* aluBeforeBellows = new TGeoPcon(0., 360., 9); aluBeforeBellows->DefineSection(0, kZ9, 0., kBellowSectionOuterRadius - kBeryliumSectionThickness + kBellowPlieThickness); @@ -346,144 +347,169 @@ void Pipe::ConstructGeometry() // Dimensions : const Float_t kSupportXdim = 20.67; - const Float_t kBeamPipeRingZdim = 4.0; + const Float_t kBeamPipeRingZdim = 3.6; const Float_t kVespelRmax = 2.3; const Float_t kVespelRmin = 2.22; - const Float_t kBeampipeCarbonCollarRmin = 2.4; + const Float_t kBeampipeCarbonCollarRmin = 2.5; const Float_t kBeampipeCarbonCollarRmax = 2.7; const Float_t kFixationCarbonCollarRmin = 1.5; const Float_t kFixationCarbonCollarRmax = 1.7; const Float_t kFixationCarbonCollarDZ = 2.5; - const Float_t kSkinThickness = 0.1; - const Float_t kSkinXdim = 14.25; - const Float_t kSkinYdim = 1.; + const Float_t kSkinThickness = 0.3; + const Float_t kSkinXdim = 14.2; + const Float_t kSkinYdim = 1.4; const Float_t kSkinZdim = kFixationCarbonCollarDZ; - const Float_t kCarbonEarsXdim = 1.01; - const Float_t kCarbonEarsYdim = 0.2; + const Float_t kCarbonEarsXdim = 2.8; + const Float_t kCarbonEarsYdimIn = 1.1; + const Float_t kCarbonEarsYdimOut = 0.6; const Float_t kCarbonEarsZdim = kFixationCarbonCollarDZ; + const Float_t kScrewDiameter = 0.4; + const Float_t kScrewHeadHeight = 0.2; + const Float_t kScrewHeadDiameter = 0.6; + const Float_t kScrewPositionIn = 3.25; + const Float_t kScrewPositionOut = 21.80; + const Float_t kScrewThreadLength = 1.0; + const Float_t holeSightDiameterOut = 0.60; + const Float_t holeSightDiameterIn = 0.25; // Support Bar TGeoVolumeAssembly* supportBar = new TGeoVolumeAssembly("BPS_SupportBar"); - - TGeoBBox* carbonSkinBPS = new TGeoBBox(kSkinXdim / 2., kSkinYdim / 2., kSkinZdim / 2.); - carbonSkinBPS->SetName("carbonSkinBPS"); - + TGeoBBox* carbonSkinBPS = new TGeoBBox("carbonSkinBPS", kSkinXdim / 2., kSkinYdim / 2., kSkinZdim / 2.); TGeoBBox* foambarBPS = new TGeoBBox("foambarBPS", kSkinXdim / 2. - kSkinThickness, kSkinYdim / 2. - kSkinThickness, kSkinZdim / 2. - kSkinThickness / 2.); - TGeoBBox* carbonEarsBPS = new TGeoBBox(kCarbonEarsXdim / 2., kCarbonEarsYdim / 2., kCarbonEarsZdim / 2.); - carbonEarsBPS->SetName("carbonEarsBPS"); + TGeoBBox* carbonEarsBPSin = new TGeoBBox("carbonEarsBPSin", kCarbonEarsXdim / 2., kCarbonEarsYdimIn / 2., kCarbonEarsZdim / 2.); + TGeoBBox* carbonEarsBPSout = new TGeoBBox("carbonEarsBPSout", kCarbonEarsXdim / 2., kCarbonEarsYdimOut / 2., kCarbonEarsZdim / 2.); + + //===== building the main support bar in carbon ==== + TGeoTranslation* tBP1 = new TGeoTranslation("tBP1", (kSkinXdim + kCarbonEarsXdim) / 2., -(kSkinYdim - kCarbonEarsYdimIn) / 2., 0.); + TGeoTranslation* tBP2 = new TGeoTranslation("tBP2", -(kSkinXdim + kCarbonEarsXdim) / 2., 0., 0.); + tBP1->RegisterYourself(); + tBP2->RegisterYourself(); + + TGeoRotation* rotScrew = new TGeoRotation("rotScrew", 0., 90., 0.); + rotScrew->RegisterYourself(); + + TGeoTube* holeScrew = new TGeoTube("holeScrew", 0., kScrewDiameter / 2., kCarbonEarsYdimIn / 2. + 0.001); + TGeoTube* holeSight = new TGeoTube("holeSight", 0., holeSightDiameterOut / 2., kSkinZdim / 2. + 0.001); + TGeoTranslation* tHoleSight = new TGeoTranslation("tHoleSight", kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax - 6.55, 0., 0.); + tHoleSight->RegisterYourself(); + Double_t kXHoleIn = kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax - kScrewPositionIn; + Double_t kXHoleOut = kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax - kScrewPositionOut; + TGeoCombiTrans* tHoleScrew1 = new TGeoCombiTrans("tHoleScrew1", kXHoleIn, -(kSkinYdim - kCarbonEarsYdimIn) / 2., -0.7, rotScrew); + TGeoCombiTrans* tHoleScrew2 = new TGeoCombiTrans("tHoleScrew2", kXHoleIn, -(kSkinYdim - kCarbonEarsYdimIn) / 2., 0.7, rotScrew); + TGeoCombiTrans* tHoleScrew3 = new TGeoCombiTrans("tHoleScrew3", kXHoleOut, -(kSkinYdim - kCarbonEarsYdimIn) / 2., -0.7, rotScrew); + TGeoCombiTrans* tHoleScrew4 = new TGeoCombiTrans("tHoleScrew4", kXHoleOut, -(kSkinYdim - kCarbonEarsYdimIn) / 2., 0.7, rotScrew); + tHoleScrew1->RegisterYourself(); + tHoleScrew2->RegisterYourself(); + tHoleScrew3->RegisterYourself(); + tHoleScrew4->RegisterYourself(); - TGeoTranslation* transBP1 = new TGeoTranslation("transBP1", (kSkinXdim + kCarbonEarsXdim) / 2., 0., 0.); - transBP1->RegisterYourself(); - TGeoTranslation* transBP2 = new TGeoTranslation("transBP2", -(kSkinXdim + kCarbonEarsXdim) / 2., 0., 0.); - transBP2->RegisterYourself(); TGeoCompositeShape* supportBarCarbon = new TGeoCompositeShape( - "BPS_supportBarCarbon", "(carbonSkinBPS-foambarBPS)+carbonEarsBPS:transBP1+carbonEarsBPS:transBP2"); - + "BPS_supportBarCarbon", "(carbonSkinBPS-foambarBPS)+carbonEarsBPSin:tBP1-holeScrew:tHoleScrew1-holeScrew:tHoleScrew2+carbonEarsBPSout:tBP2-holeSight:tHoleSight-holeScrew:tHoleScrew3-holeScrew:tHoleScrew4"); TGeoVolume* supportBarCarbonVol = new TGeoVolume("BPS_supportBarCarbon", supportBarCarbon, kMedCarbonFiber); - supportBarCarbonVol->SetLineColor(kGray + 3); - - supportBar->AddNode(supportBarCarbonVol, 1, - new TGeoTranslation(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax, 0, 0)); - supportBar->AddNode(supportBarCarbonVol, 2, - new TGeoTranslation(-(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax), 0, 0)); - - TGeoVolume* foamVol = new TGeoVolume("supportBarFoam", foambarBPS, kMedRohacell); - foamVol->SetLineColor(kGray); - supportBar->AddNode(foamVol, 1, - new TGeoTranslation(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax, 0, 0)); - supportBar->AddNode(foamVol, 2, - new TGeoTranslation(-(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax), 0, 0)); + supportBarCarbonVol->SetLineColor(kGray + 2); + supportBar->AddNode(supportBarCarbonVol, 1, new TGeoTranslation(-(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax), 0, 0)); + TGeoRotation* rotBar1 = new TGeoRotation("rotBar1", 0., 180., 180.); + rotBar1->RegisterYourself(); + TGeoCombiTrans* transBar1 = new TGeoCombiTrans("transBar1", kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax, 0, 0, rotBar1); + transBar1->RegisterYourself(); + supportBar->AddNode(supportBarCarbonVol, 2, transBar1); + //================================================== + + //==== Adding the internal foam volumes ============ + TGeoCompositeShape* foamVolume = new TGeoCompositeShape("foamVolume", "foambarBPS-holeSight:tHoleSight"); + TGeoVolume* FoamVolume = new TGeoVolume("supportBarFoam", foamVolume, kMedRohacell); + FoamVolume->SetLineColor(kGreen); + TGeoRotation* rotBar2 = new TGeoRotation("rotBar2", 0., 0., 180.); + rotBar2->RegisterYourself(); + TGeoCombiTrans* transBar2 = new TGeoCombiTrans("transBar2", kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax, 0, 0, rotBar2); + transBar2->RegisterYourself(); + supportBar->AddNode(FoamVolume, 1, transBar1); + supportBar->AddNode(FoamVolume, 2, new TGeoTranslation(-(kSkinXdim / 2. + kCarbonEarsXdim + kBeampipeCarbonCollarRmax), 0, 0)); + //================================================== + + //================= Screws ==================== + TGeoVolumeAssembly* screw = new TGeoVolumeAssembly("screw"); + TGeoTube* headScrew = new TGeoTube("headScrew", 0., kScrewHeadDiameter / 2., kScrewHeadHeight / 2.); + TGeoVolume* HeadScrew = new TGeoVolume("HeadScrew", headScrew, kMedTitanium); + HeadScrew->SetLineColor(kRed); + TGeoTube* threadScrew = new TGeoTube("threadScrew", 0., kScrewDiameter / 2., kCarbonEarsYdimIn / 2.); + TGeoVolume* ThreadScrew = new TGeoVolume("ThreadScrew", threadScrew, kMedTitanium); + ThreadScrew->SetLineColor(kRed); + screw->AddNode(HeadScrew, 1, new TGeoTranslation(0., 0., -(kCarbonEarsYdimIn + kScrewHeadHeight) / 2.)); + screw->AddNode(ThreadScrew, 1); + TGeoCombiTrans* tScrew1 = new TGeoCombiTrans("transScrew1", kScrewPositionIn, (kCarbonEarsYdimIn - kSkinYdim) / 2., -0.7, rotScrew); + TGeoCombiTrans* tScrew2 = new TGeoCombiTrans("transScrew2", kScrewPositionIn, (kCarbonEarsYdimIn - kSkinYdim) / 2., 0.7, rotScrew); + TGeoCombiTrans* tScrew3 = new TGeoCombiTrans("transScrew3", -kScrewPositionIn, (kCarbonEarsYdimIn - kSkinYdim) / 2., -0.7, rotScrew); + TGeoCombiTrans* tScrew4 = new TGeoCombiTrans("transScrew4", -kScrewPositionIn, (kCarbonEarsYdimIn - kSkinYdim) / 2., 0.7, rotScrew); + tScrew1->RegisterYourself(); + tScrew2->RegisterYourself(); + tScrew3->RegisterYourself(); + tScrew4->RegisterYourself(); + supportBar->AddNode(screw, 1, tScrew1); + supportBar->AddNode(screw, 2, tScrew2); + supportBar->AddNode(screw, 3, tScrew3); + supportBar->AddNode(screw, 4, tScrew4); + //============================================== + + // === Optical sights === + TGeoVolumeAssembly* fixationSight = new TGeoVolumeAssembly("fixationSight"); + TGeoTube* screwSight = new TGeoTube("screwSight", holeSightDiameterIn / 2., holeSightDiameterOut / 2., kScrewThreadLength / 2.); + TGeoVolume* ScrewSight = new TGeoVolume("ScrewSight", screwSight, kMedSteel); + ScrewSight->SetLineColor(kBlue); + Double_t supportSightLength = 0.5; + TGeoTube* supportSight = new TGeoTube("supportSight", holeSightDiameterIn / 2., 1.4 / 2., supportSightLength / 2.); + TGeoVolume* SupportSight = new TGeoVolume("SupportSight", supportSight, kMedSteel); + SupportSight->SetLineColor(kBlue); + fixationSight->AddNode(ScrewSight, 1); + fixationSight->AddNode(SupportSight, 1, new TGeoTranslation(0., 0., (kScrewThreadLength + supportSightLength) / 2.)); + SupportSight->SetVisibility(kTRUE); + fixationSight->SetVisibility(kTRUE); + TGeoTranslation* tSight1 = new TGeoTranslation("tSight1", 6.55, 0., (kSkinZdim - kScrewThreadLength) / 2.); + TGeoTranslation* tSight2 = new TGeoTranslation("tSight2", -6.55, 0., (kSkinZdim - kScrewThreadLength) / 2.); + tSight1->RegisterYourself(); + tSight2->RegisterYourself(); + supportBar->AddNode(fixationSight, 1, tSight1); + supportBar->AddNode(fixationSight, 2, tSight2); + // ===================== beamPipeSupport->AddNode(supportBar, 1); - // Fixation to wings - - TGeoVolumeAssembly* fixationToWings = new TGeoVolumeAssembly("BPS_fixationToWings"); - - Float_t delatX = 0.1; - - TGeoTubeSeg* fixationTube = - new TGeoTubeSeg(kFixationCarbonCollarRmin, kFixationCarbonCollarRmax, kFixationCarbonCollarDZ / 2., -90., 90.); - fixationTube->SetName("fixationTube"); - TGeoBBox* fixationToBar = new TGeoBBox(kCarbonEarsXdim / 2. + delatX, kCarbonEarsYdim / 2., kCarbonEarsZdim / 2.); - fixationToBar->SetName("fixationToBar"); - - TGeoTranslation* transBP3 = - new TGeoTranslation("transBP3", kFixationCarbonCollarRmax + kCarbonEarsXdim / 2. - delatX, kCarbonEarsYdim, 0.); - transBP3->RegisterYourself(); - TGeoTranslation* transBP4 = - new TGeoTranslation("transBP4", kFixationCarbonCollarRmax + kCarbonEarsXdim / 2. - delatX, -kCarbonEarsYdim, 0.); - transBP4->RegisterYourself(); - TGeoCompositeShape* fixationToWing = - new TGeoCompositeShape("fixationToWing", "fixationTube+fixationToBar:transBP3+fixationToBar:transBP4"); - - TGeoVolume* fixationToWingVol = new TGeoVolume("fixationToWing", fixationToWing, kMedCarbonFiber); - fixationToWingVol->SetLineColor(kGray + 2); - - fixationToWings->AddNode(fixationToWingVol, 1, new TGeoTranslation(-kSupportXdim, 0, 0)); - fixationToWings->AddNode(fixationToWingVol, 2, - new TGeoCombiTrans(+kSupportXdim, 0, 0, new TGeoRotation("rot", 0., 0., 180.))); - - beamPipeSupport->AddNode(fixationToWings, 1); - - // Fixation to pipe - + //======================= Fixation to pipe ======================== TGeoVolumeAssembly* fixationToPipe = new TGeoVolumeAssembly("fixationToPipe"); - - TGeoTubeSeg* pipeSupportTubeCarbon = - new TGeoTubeSeg(kBeampipeCarbonCollarRmin, kBeampipeCarbonCollarRmax, kFixationCarbonCollarDZ / 2., 0., 180.); + TGeoTube* pipeSupportTubeCarbon = + new TGeoTube(kBeampipeCarbonCollarRmin, kBeampipeCarbonCollarRmax, kFixationCarbonCollarDZ / 2.); pipeSupportTubeCarbon->SetName("pipeSupportTubeCarbon"); - - TGeoBBox* fixationTubeToBar = new TGeoBBox(kCarbonEarsXdim / 2. + delatX, kCarbonEarsYdim / 2., kCarbonEarsZdim / 2.); - fixationTubeToBar->SetName("fixationTubeToBar"); - TGeoBBox* hole = - new TGeoBBox((kBeampipeCarbonCollarRmax - kVespelRmin) / 2., kCarbonEarsYdim / 2., kCarbonEarsZdim / 2. + 1e-3); - hole->SetName("hole"); - - TGeoTranslation* transBP5 = - new TGeoTranslation("transBP5", kBeampipeCarbonCollarRmax + kCarbonEarsXdim / 2. - delatX, kCarbonEarsYdim, 0.); - transBP5->RegisterYourself(); - TGeoTranslation* transBP6 = - new TGeoTranslation("transBP6", -(kBeampipeCarbonCollarRmax + kCarbonEarsXdim / 2. - delatX), kCarbonEarsYdim, 0.); - transBP6->RegisterYourself(); - TGeoTranslation* transBP7 = new TGeoTranslation("transBP7", (kBeampipeCarbonCollarRmax + kVespelRmin) / 2., 0., 0.); - transBP7->RegisterYourself(); - TGeoTranslation* transBP8 = - new TGeoTranslation("transBP8", -((kBeampipeCarbonCollarRmax + kVespelRmin) / 2.), 0., 0.); - transBP8->RegisterYourself(); TGeoCompositeShape* halfFixationToPipe = new TGeoCompositeShape( "halfFixationToPipe", - "(pipeSupportTubeCarbon-hole:transBP7-hole:transBP8)+fixationTubeToBar:transBP5+fixationTubeToBar:transBP6"); - - TGeoVolume* halfFixationToPipeVol = new TGeoVolume("halfFixationToPipe", halfFixationToPipe, kMedCarbonFiber); - halfFixationToPipeVol->SetLineColor(kRed + 2); - - fixationToPipe->AddNode(halfFixationToPipeVol, 1); - fixationToPipe->AddNode(halfFixationToPipeVol, 2, new TGeoCombiTrans(0, 0, 0, new TGeoRotation("rot", 0., 0., 180.))); - + "pipeSupportTubeCarbon"); + TGeoVolume* FixationToPipeVol = new TGeoVolume("FixationToPipe", pipeSupportTubeCarbon, kMedCarbonFiber); + FixationToPipeVol->SetLineColor(kGray + 2); + fixationToPipe->AddNode(FixationToPipeVol, 1); beamPipeSupport->AddNode(fixationToPipe, 1); + //================================================================== - // Beam Pipe Ring - + //================ Beam Pipe Ring ================= TGeoVolumeAssembly* beamPipeRing = new TGeoVolumeAssembly("beamPipeRing"); - TGeoTube* beamPipeRingCarbon = new TGeoTube(kVespelRmax, kBeampipeCarbonCollarRmin, kBeamPipeRingZdim / 2.); TGeoVolume* beamPipeRingCarbonVol = new TGeoVolume("beamPipeRingCarbon", beamPipeRingCarbon, kMedCarbonFiber); - beamPipeRingCarbonVol->SetLineColor(kGreen + 2); + beamPipeRingCarbonVol->SetLineColor(kGray + 2); beamPipeRing->AddNode(beamPipeRingCarbonVol, 1, new TGeoTranslation(0., 0, (kBeamPipeRingZdim - kFixationCarbonCollarDZ) / 2.)); - - TGeoTube* beamPipeRingVespel = new TGeoTube(kVespelRmin, kVespelRmax, kBeamPipeRingZdim / 2.); + TGeoTube* beamPipeRingVespel = new TGeoTube(kVespelRmin, kVespelRmax, (kBeamPipeRingZdim + 0.4) / 2.); TGeoVolume* beamPipeRingVespelVol = new TGeoVolume("beamPipeRingVespel", beamPipeRingVespel, kMedPolyimide); - beamPipeRingVespelVol->SetLineColor(kGreen + 4); + beamPipeRingVespelVol->SetLineColor(kGreen + 2); beamPipeRing->AddNode(beamPipeRingVespelVol, 1, new TGeoTranslation(0., 0, (kBeamPipeRingZdim - kFixationCarbonCollarDZ) / 2.)); - beamPipeSupport->AddNode(beamPipeRing, 1); - beamPipeSupport->SetVisibility(0); + beamPipeSupport->SetVisibility(1); + beamPipeSupport->IsVisible(); + //================================================== + + // Wings + //TGeoVolumeAssembly* Wing = new TGeoVolumeAssembly("Wing"); not yet, be patient... barrel->AddNode(beamPipeSupport, 1, new TGeoTranslation(0., 30, kBeamPipesupportZpos + kFixationCarbonCollarDZ / 2.)); @@ -2579,12 +2605,10 @@ void Pipe::createMaterials() Float_t aAlBe[2] = {26.98, 9.01}; // al=2.702 be=1.8477 Float_t zAlBe[2] = {13.00, 4.00}; Float_t wAlBe[2] = {0.4, 0.6}; - // // Polyamid Float_t aPA[4] = {16., 14., 12., 1.}; Float_t zPA[4] = {8., 7., 6., 1.}; Float_t wPA[4] = {1., 1., 6., 11.}; - // // Polyimide film Float_t aPI[4] = {16., 14., 12., 1.}; Float_t zPI[4] = {8., 7., 6., 1.}; @@ -2593,15 +2617,12 @@ void Pipe::createMaterials() Float_t aRohacell[4] = {16., 14., 12., 1.}; Float_t zRohacell[4] = {8., 7., 6., 1.}; Float_t wRohacell[4] = {2., 1., 9., 13.}; - // // Air - // Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; Float_t zAir[4] = {6., 7., 8., 18.}; Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; Float_t dAir = 1.20479E-3; Float_t dAir1 = 1.20479E-11; - // // Insulation powder // Si O Ti Al Float_t ains[4] = {28.0855, 15.9994, 47.867, 26.982}; @@ -2722,6 +2743,10 @@ void Pipe::createMaterials() // Rohacell matmgr.Mixture("PIPE", 67, "Rohacell$", aRohacell, zRohacell, 0.03, -4, wRohacell); matmgr.Medium("PIPE", 67, "ROHACELL", 67, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + + // Titanium + matmgr.Material("PIPE", 22, "Titanium", 47.867, 22, 4.54, 3.560, 27.80); + matmgr.Medium("PIPE", 22, "TITANIUM", 22, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); } TGeoPcon* Pipe::MakeMotherFromTemplate(const TGeoPcon* shape, Int_t imin, Int_t imax, Float_t r0, Int_t nz) @@ -2820,46 +2845,41 @@ TGeoVolume* Pipe::MakeBellow(const char* ext, Int_t nc, Float_t rMin, Float_t rM auto& matmgr = o2::base::MaterialManager::Instance(); const TGeoMedium* kMedVac = matmgr.getTGeoMedium("PIPE_VACUUM"); const TGeoMedium* kMedSteel = matmgr.getTGeoMedium("PIPE_INOX"); - - char name[64], nameA[64], nameB[64], bools[64]; // // Upper part of the undulation // + std::string name, nameA, nameB; TGeoTorus* shPlieTorusU = new TGeoTorus(rMax - rPlie, rPlie - dPlie, rPlie); - snprintf(nameA, 64, "%sTorusU", ext); - shPlieTorusU->SetName(nameA); + nameA = fmt::format("{:s}TorusU", ext); + shPlieTorusU->SetName(nameA.c_str()); TGeoTube* shPlieTubeU = new TGeoTube(rMax - rPlie, rMax, rPlie); - snprintf(nameB, 64, "%sTubeU", ext); - shPlieTubeU->SetName(nameB); - snprintf(name, 64, "%sUpperPlie", ext); - snprintf(bools, 64, "%s*%s", nameA, nameB); - TGeoCompositeShape* shUpperPlie = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}TubeU", ext); + shPlieTubeU->SetName(nameB.c_str()); + name = fmt::format("{:s}UpperPlie", ext); + TGeoCompositeShape* shUpperPlie = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}*{:s}", nameA, nameB).c_str()); - TGeoVolume* voWiggleU = new TGeoVolume(name, shUpperPlie, kMedSteel); + TGeoVolume* voWiggleU = new TGeoVolume(name.c_str(), shUpperPlie, kMedSteel); // // Lower part of the undulation TGeoTorus* shPlieTorusL = new TGeoTorus(rMin + rPlie, rPlie - dPlie, rPlie); - snprintf(nameA, 64, "%sTorusL", ext); - shPlieTorusL->SetName(nameA); + nameA = fmt::format("{:s}TorusL", ext); + shPlieTorusL->SetName(nameA.c_str()); TGeoTube* shPlieTubeL = new TGeoTube(rMin, rMin + rPlie, rPlie); - snprintf(nameB, 64, "%sTubeL", ext); - shPlieTubeL->SetName(nameB); - snprintf(name, 64, "%sLowerPlie", ext); - snprintf(bools, 64, "%s*%s", nameA, nameB); - TGeoCompositeShape* shLowerPlie = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}TubeL", ext); + shPlieTubeL->SetName(nameB.c_str()); + name = fmt::format("{:s}LowerPlie", ext); + TGeoCompositeShape* shLowerPlie = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}*{:s}", nameA, nameB).c_str()); - TGeoVolume* voWiggleL = new TGeoVolume(name, shLowerPlie, kMedSteel); + TGeoVolume* voWiggleL = new TGeoVolume(name.c_str(), shLowerPlie, kMedSteel); // // Connection between upper and lower part of undulation - snprintf(name, 64, "%sPlieConn1", ext); - TGeoVolume* voWiggleC1 = new TGeoVolume(name, new TGeoTube(rMin + rPlie, rMax - rPlie, dPlie / 2.), kMedSteel); + TGeoVolume* voWiggleC1 = new TGeoVolume(fmt::format("{:s}PlieConn1", ext).c_str(), new TGeoTube(rMin + rPlie, rMax - rPlie, dPlie / 2.), kMedSteel); // // One wiggle Float_t dz = rPlie - dPlie / 2.; Float_t z0 = -dPlie / 2.; - snprintf(name, 64, "%sWiggle", ext); - TGeoVolumeAssembly* asWiggle = new TGeoVolumeAssembly(name); + TGeoVolumeAssembly* asWiggle = new TGeoVolumeAssembly(fmt::format("{:s}Wiggle", ext).c_str()); asWiggle->AddNode(voWiggleC1, 1, new TGeoTranslation(0., 0., z0)); z0 += dz; asWiggle->AddNode(voWiggleU, 1, new TGeoTranslation(0., 0., z0)); @@ -2869,9 +2889,8 @@ TGeoVolume* Pipe::MakeBellow(const char* ext, Int_t nc, Float_t rMin, Float_t rM asWiggle->AddNode(voWiggleL, 1, new TGeoTranslation(0., 0., z0)); asWiggle->GetShape()->ComputeBBox(); // enforce recomputing of BBox // - snprintf(name, 64, "%sBellowUS", ext); Float_t zBellowTot = nc * (static_cast<TGeoBBox*>(asWiggle->GetShape()))->GetDZ(); - TGeoVolume* voBellow = new TGeoVolume(name, new TGeoTube(rMin, rMax, zBellowTot), kMedVac); + TGeoVolume* voBellow = new TGeoVolume(fmt::format("{:s}BellowUS", ext).c_str(), new TGeoTube(rMin, rMax, zBellowTot), kMedVac); // Positioning of the volumes z0 = -dU / 2. + rPlie; voBellow->AddNode(voWiggleL, 2, new TGeoTranslation(0., 0., z0)); @@ -2898,57 +2917,54 @@ TGeoVolume* Pipe::MakeBellowCside(const char* ext, Int_t nc, Float_t rMin, Float Float_t dU = nc * (4. * rPlie - 2. * dPlie); - char name[64], nameA[64], nameB[64], bools[64]; - snprintf(name, 64, "%sBellowUS", ext); + std::string name, nameA, nameB; + name = fmt::format("{:s}BellowUS", ext); // TGeoVolume* voBellow = new TGeoVolume(name, new TGeoTube(rMin, rMax, dU/2.), kMedVac); - TGeoVolumeAssembly* voBellow = new TGeoVolumeAssembly(name); + TGeoVolumeAssembly* voBellow = new TGeoVolumeAssembly(name.c_str()); // // Upper part of the undulation // TGeoTorus* shPlieTorusU = new TGeoTorus(rMax - rPlie, rPlie - dPlie, rPlie); - snprintf(nameA, 64, "%sTorusU", ext); - shPlieTorusU->SetName(nameA); + nameA = fmt::format("{:s}TorusU", ext); + shPlieTorusU->SetName(nameA.c_str()); TGeoTube* shPlieTubeU = new TGeoTube(rMax - rPlie, rMax, rPlie); - snprintf(nameB, 64, "%sTubeU", ext); - shPlieTubeU->SetName(nameB); - snprintf(name, 64, "%sUpperPlie", ext); - snprintf(bools, 64, "%s*%s", nameA, nameB); - TGeoCompositeShape* shUpperPlie = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}TubeU", ext); + shPlieTubeU->SetName(nameB.c_str()); + name = fmt::format("{:s}UpperPlie", ext); + TGeoCompositeShape* shUpperPlie = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}*{:s}", nameA, nameB).c_str()); - TGeoVolume* voWiggleU = new TGeoVolume(name, shUpperPlie, kMedAlu5083); + TGeoVolume* voWiggleU = new TGeoVolume(name.c_str(), shUpperPlie, kMedAlu5083); voWiggleU->SetLineColor(kOrange); // fm // First Lower part of the ondulation TGeoTorus* shPlieTorusL = new TGeoTorus(rMin + rPlie, rPlie - dPlie, rPlie); - snprintf(nameA, 64, "%sTorusL", ext); - shPlieTorusL->SetName(nameA); + nameA = fmt::format("{:s}TorusL", ext); + shPlieTorusL->SetName(nameA.c_str()); TGeoTranslation* t1 = new TGeoTranslation("t1", 0, 0, -rPlie / 2.); t1->RegisterYourself(); TGeoTube* shPlieTubeL = new TGeoTube(rMin, rMin + rPlie, rPlie / 2.); - snprintf(nameB, 64, "%sTubeL", ext); - shPlieTubeL->SetName(nameB); - snprintf(name, 64, "%sLowerPlie", ext); - snprintf(bools, 64, "%s*%s:t1", nameA, nameB); - TGeoCompositeShape* shLowerPlie1 = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}TubeL", ext); + shPlieTubeL->SetName(nameB.c_str()); + name = fmt::format("{:s}LowerPlie", ext); + TGeoCompositeShape* shLowerPlie1 = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}*{:s}:t1", nameA, nameB).c_str()); - TGeoVolume* voWiggleL1 = new TGeoVolume(name, shLowerPlie1, kMedAlu5083); + TGeoVolume* voWiggleL1 = new TGeoVolume(name.c_str(), shLowerPlie1, kMedAlu5083); voWiggleL1->SetLineColor(kOrange); // fm // Second Lower part of the undulation TGeoTranslation* t2 = new TGeoTranslation("t2", 0, 0, rPlie / 2.); t2->RegisterYourself(); - snprintf(bools, 64, "%s*%s:t2", nameA, nameB); - TGeoCompositeShape* shLowerPlie2 = new TGeoCompositeShape(name, bools); + TGeoCompositeShape* shLowerPlie2 = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}*{:s}:t2", nameA, nameB).c_str()); - TGeoVolume* voWiggleL2 = new TGeoVolume(name, shLowerPlie2, kMedAlu5083); + TGeoVolume* voWiggleL2 = new TGeoVolume(name.c_str(), shLowerPlie2, kMedAlu5083); voWiggleL2->SetLineColor(kOrange); // fm // Connection between upper and lower part of undulation - snprintf(name, 64, "%sPlieConn1", ext); - TGeoVolume* voWiggleC1 = new TGeoVolume(name, new TGeoTube(rMin + rPlie, rMax - rPlie, dPlie / 2.), kMedAlu5083); + name = fmt::format("{:s}PlieConn1", ext); + TGeoVolume* voWiggleC1 = new TGeoVolume(name.c_str(), new TGeoTube(rMin + rPlie, rMax - rPlie, dPlie / 2.), kMedAlu5083); voWiggleC1->SetLineColor(kOrange); // fm // @@ -2958,45 +2974,42 @@ TGeoVolume* Pipe::MakeBellowCside(const char* ext, Int_t nc, Float_t rMin, Float //--Upper part of the ondulation TGeoTorus* vacPlieTorusU = new TGeoTorus(rMax - rPlie, 0., rPlie - dPlie); - snprintf(nameA, 64, "%svacTorusU", ext); - vacPlieTorusU->SetName(nameA); + nameA = fmt::format("{:s}vacTorusU", ext); + vacPlieTorusU->SetName(nameA.c_str()); TGeoTube* vacPlieTubeU = new TGeoTube(0., rMax - rPlie, rPlie - dPlie); - snprintf(nameB, 64, "%svacTubeU", ext); - vacPlieTubeU->SetName(nameB); - snprintf(name, 64, "%svacUpperPlie", ext); - snprintf(bools, 64, "%s+%s", nameA, nameB); - TGeoCompositeShape* vacUpperPlie = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}vacTubeU", ext); + vacPlieTubeU->SetName(nameB.c_str()); + name = fmt::format("{:s}vacUpperPlie", ext); + TGeoCompositeShape* vacUpperPlie = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}+{:s}", nameA, nameB).c_str()); - TGeoVolume* voVacWiggleU = new TGeoVolume(name, vacUpperPlie, kMedVac); + TGeoVolume* voVacWiggleU = new TGeoVolume(name.c_str(), vacUpperPlie, kMedVac); voVacWiggleU->SetVisibility(0); // First Lower part of the undulation TGeoTorus* vacPlieTorusL = new TGeoTorus(rMin + rPlie, 0., rPlie); - snprintf(nameA, 64, "%svacTorusL", ext); - vacPlieTorusL->SetName(nameA); + nameA = fmt::format("{:s}vacTorusL", ext); + vacPlieTorusL->SetName(nameA.c_str()); TGeoTube* vacPlieTubeL = new TGeoTube(0., rMin + rPlie, rPlie / 2.); - snprintf(nameB, 64, "%svacTubeL", ext); - vacPlieTubeL->SetName(nameB); - snprintf(name, 64, "%svacLowerPlie", ext); - snprintf(bools, 64, "%s:t1-%s", nameB, nameA); - TGeoCompositeShape* vacLowerPlie1 = new TGeoCompositeShape(name, bools); + nameB = fmt::format("{:s}vacTubeL", ext); + vacPlieTubeL->SetName(nameB.c_str()); + name = fmt::format("{:s}vacLowerPlie", ext); + TGeoCompositeShape* vacLowerPlie1 = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}:t1-{:s}", nameB, nameA).c_str()); - TGeoVolume* voVacWiggleL1 = new TGeoVolume(name, vacLowerPlie1, kMedVac); + TGeoVolume* voVacWiggleL1 = new TGeoVolume(name.c_str(), vacLowerPlie1, kMedVac); voVacWiggleL1->SetVisibility(0); // Second Lower part of the undulation - snprintf(bools, 64, "%s:t2-%s", nameB, nameA); - TGeoCompositeShape* vacLowerPlie2 = new TGeoCompositeShape(name, bools); + TGeoCompositeShape* vacLowerPlie2 = new TGeoCompositeShape(name.c_str(), fmt::format("{:s}:t2-{:s}", nameB, nameA).c_str()); - TGeoVolume* voVacWiggleL2 = new TGeoVolume(name, vacLowerPlie2, kMedVac); + TGeoVolume* voVacWiggleL2 = new TGeoVolume(name.c_str(), vacLowerPlie2, kMedVac); voVacWiggleL2->SetVisibility(0); // One wiggle Float_t dz = rPlie - dPlie / 2.; Float_t z0 = 2. * rPlie; - snprintf(name, 64, "%sWiggle", ext); - TGeoVolumeAssembly* asWiggle = new TGeoVolumeAssembly(name); + name = fmt::format("{:s}Wiggle", ext); + TGeoVolumeAssembly* asWiggle = new TGeoVolumeAssembly(name.c_str()); asWiggle->AddNode(voWiggleL1, 1, new TGeoTranslation(0., 0., z0)); asWiggle->AddNode(voVacWiggleL1, 1, new TGeoTranslation(0., 0., z0)); diff --git a/Detectors/Passive/src/Shil.cxx b/Detectors/Passive/src/Shil.cxx index d8dc7b2401396..c81560b48862a 100644 --- a/Detectors/Passive/src/Shil.cxx +++ b/Detectors/Passive/src/Shil.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/README.md b/Detectors/README.md index 3be3ed677ae60..b52a27acc0f59 100644 --- a/Detectors/README.md +++ b/Detectors/README.md @@ -9,16 +9,20 @@ There is no module description yet. <!-- doxy This module contains the following submodules: -* \subpage refDetectorsRaw +* \subpage refDetectorsAlign * \subpage refDetectorsBase * \subpage refDetectorsBasetest +* \subpage refDetectorsCalibration * \subpage refDetectorsGeometry * \subpage refDetectorsGlobalTracking +* \subpage refDetectorsGlobalTrackingWorkflow +* \subpage refDetectorsRaw * \subpage refDetectorsVertexing -* \subpage refDetectorsCalibration * \subpage refDetectorsCPV * \subpage refDetectorsCTF +* \subpage refDetectorsDCS * \subpage refDetectorsEMCAL +* \subpage refDetectorsDCS * \subpage refDetectorsFIT * \subpage refDetectorsHMPID * \subpage refDetectorsITSMFT @@ -28,5 +32,6 @@ This module contains the following submodules: * \subpage refDetectorsTOF * \subpage refDetectorsTPC * \subpage refDetectorsTRD +* \subpage refDetectorsUpgrades * \subpage refDetectorsZDC /doxy --> diff --git a/Detectors/Raw/CMakeLists.txt b/Detectors/Raw/CMakeLists.txt index cda1bf6fd01a1..4576bb530f7a9 100644 --- a/Detectors/Raw/CMakeLists.txt +++ b/Detectors/Raw/CMakeLists.txt @@ -1,20 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsRaw SOURCES src/RawFileReader.cxx src/RawFileWriter.cxx - src/SimpleRawReader.cxx - src/SimpleSTF.cxx - src/HBFUtils.cxx - src/RDHUtils.cxx + src/HBFUtils.cxx + src/RDHUtils.cxx + src/HBFUtilsInitializer.cxx PUBLIC_LINK_LIBRARIES FairRoot::Base O2::Headers O2::CommonDataFormat @@ -22,10 +22,11 @@ o2_add_library(DetectorsRaw O2::Framework FairMQ::FairMQ) +add_subdirectory(TFReaderDD) + o2_target_root_dictionary(DetectorsRaw HEADERS include/DetectorsRaw/RawFileReader.h include/DetectorsRaw/RawFileWriter.h - include/DetectorsRaw/SimpleRawReader.h include/DetectorsRaw/HBFUtils.h include/DetectorsRaw/RDHUtils.h) @@ -35,12 +36,18 @@ o2_add_executable(file-check PUBLIC_LINK_LIBRARIES O2::DetectorsRaw Boost::program_options) +o2_add_executable(file-split + COMPONENT_NAME raw + SOURCES src/rawfileSplit.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsRaw) + o2_add_executable(file-reader-workflow COMPONENT_NAME raw SOURCES src/rawfile-reader-workflow.cxx src/RawFileReaderWorkflow.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsRaw) + o2_add_test(HBFUtils PUBLIC_LINK_LIBRARIES O2::DetectorsRaw O2::Steer @@ -51,7 +58,7 @@ o2_add_test(HBFUtils o2_add_test(RawReaderWriter PUBLIC_LINK_LIBRARIES O2::DetectorsRaw O2::Steer - O2::DPLUtils + O2::DPLUtils SOURCES test/testRawReaderWriter.cxx COMPONENT_NAME raw LABELS raw) diff --git a/Detectors/Raw/README.md b/Detectors/Raw/README.md index 13b744a92dc78..55520588905dc 100644 --- a/Detectors/Raw/README.md +++ b/Detectors/Raw/README.md @@ -1,5 +1,5 @@ <!-- doxy -\page refDetectorsRaw Raw Data +\page refDetectorsRaw Raw Data /doxy --> # Raw data tools @@ -41,12 +41,14 @@ HBFUtil::fillHBIRvector(std::vector<IR>& dst, const IR& fromIR, const IR& payLoa will fill the provided `dst` vector with the IR's (between `fromIR` and `payLoadIR`) for which the HBFs should be generated and flushed to raw data **before** filling the payload of `payLoadIR`. +Extra data member `HBFUtil.maxNOrbits` (= highest possible orbit by default) is used only in the RawFileWriter as a maximum orbit number (with respect to 1st orbit) for which detector payload is considered. + See `Detectors/Raw/test/testHBFUtils.cxx` for details of usage of this class (also check the jira ticket about the [MC->Raw conversion](https://alice.its.cern.ch/jira/browse/O2-972)). ## RawFileWriter A class to facilitate writing to files the MC data converted to raw data payload. Payload will be formatted according to CRU data -specifications and should be simular to produced by the readout.exe (and can be pumped into the DPL workflows) +specifications and should be simular to produced by the o2-readout-exe (and can be pumped into the DPL workflows) The detector code for MC to raw conversion should instatiate the RawFileWriter object and: @@ -61,7 +63,7 @@ auto& lnkB = writer.registerLink(fee_1, cru_0, link_1, endpoint_0, "outfile_0.ra .. // or o2::header::RawDataHeader rdh; // by default, v4 is used currently. -// also o2::header::RDHAny rdh(4); can be used with the same effect +// also o2::header::RDHAny rdh(4); can be used with the same effect rdh.feeId = feeX; rdh.cruID = cruY; rdh.linkID = linkZ; @@ -80,14 +82,17 @@ If needed, user may set manually the non-mutable (for given link) fields of the The data must be provided as a `gsl::span<char>`` and contain only detector GBT (16 bytes words) payload. The annotation by RDH, formatting to CRU pages and eventual splitting of the large payload to multiple pages will be done by the `RawFileWriter`. ```cpp -writer.addData(cru_0, link_0, endpoint_0, {bc, orbit}, gsl::span( (char*)payload_0, payload_0_size) ); +writer.addData(cru_0, link_0, endpoint_0, {bc, orbit}, gsl::span( (char*)payload_0, payload_0_size), <optional arguments> ); ... o2::InteractionRecord ir{bc, orbit}; -writer.addData(rdh, ir, gsl::span( (char*)payload_f, payload_f_size )); +writer.addData(rdh, ir, gsl::span( (char*)payload_f, payload_f_size ), <optional arguments>); ``` +where <optional arguments> are currently: `bool preformatted = false, uint32_t trigger = 0, uint32_t detField = 0` (see below for the meaning). By default the data will be written using o2::header::RAWDataHeader. User can request particular RDH version via `writer.useRDHVersion(v)`. +Note that the `addData` will have no effect if its `{bc, orbit}` exceeds the `HBFUtils.getFirstIR()` by more than `HBFUtils.maxNOrbits`. + The `RawFileWriter` will take care of writing created CRU data to file in `super-pages` whose size can be set using `writer.setSuperPageSize(size_in_bytes)` (default in 1 MB). @@ -97,7 +102,7 @@ also triggered by `write.close()`. In case detector link payload for given HBF exceeds the maximum CRU page size of 8KB (including the RDH added by the writer; this may happen even if it the payload size is less than 8KB, since it might be added to already partially populated CRU page of the same HBF) it will write on the page only part of the payload and carry over the rest on the extra page(s). -By default the RawFileWriter will simply chunk payload as it considers necessary, but some +By default the RawFileWriter will simply chunk payload as it considers necessary, but some detectors want their CRU pages to be self-consistent: they add to their payload detector-specific trailer and header in the beginning and in the end of the CRU page. In case part of the data is carried over to another page, this extra information need to be repeated (possibly, with some modifications). @@ -115,7 +120,7 @@ It provides to the converter carryOverMethod method the following info: rdh : RDH of the CRU page being written (pointer to o2::header::RDHAny) data : original payload received by the RawFileWriter ptr : pointer on the data in the payload which was not yet added to the link CRU pages -maxSize : maximum size (multiple of 16 bytes) of the bloc starting at ptr which it can +maxSize : maximum size (multiple of 16 bytes) of the bloc starting at ptr which it can accomodate at the current CRU page (i.e. what it would write by default) splitID : number of times this payload was already split, 0 at 1st call trailer : what it wants to add in the end of the CRU page where the data starting from ptr @@ -160,7 +165,17 @@ void newRDHMethod(const RDHAny* rdh, bool prevEmpty, std::vector<char>& toAdd) c ``` It proveds the ``RDH`` of the page for which it is called, information if the previous had some payload and buffer to be filled by the used algorithm. -The behaviour described above can be modified by providing an extra argument in the `addData` method +Some detectors signal the end of the HBF by adding an empty CRU page containing just a header with ``RDH.stop=1`` while others may simply set the ``RDH.stop=1`` in the last CRU page of the HBF (it may appear to be also the 1st and the only page of the HBF and may or may not contain the payload). +This behaviour is steered by ``writer.setAddSeparateHBFStopPage(bool v)`` switch. By default end of the HBF is signaled on separate page. + +RawFileWriter will check for every bc/orbit for which at least 1 link was filled by the detector if all other registered links also got `addData` call. +If not, it will be enforced internally with 0 payload and `trigger` and `detField` RDH fields provided in the 1st addData call of this IR. +This may be pose a problem in case detector needs to insert some header even for 0-size payloads. +In this case it is detector's responsibility to make sure that all links receive their proper `addData` call for every IR. + +Extra arguments: + +* `preformatted` (default: false): The behaviour described above can be modified by providing an extra argument in the `addData` method ```cpp bool preformatted = true; writer.addData(cru_0, link_0, endpoint_0, {bc, orbit}, gsl::span( (char*)payload_0, payload_0_size ), preformatted ); @@ -172,8 +187,9 @@ writer.addData(rdh, ir, gsl::span( (char*)payload_f, payload_f_size ), preformat In this case provided span is interpretted as a fully formatted CRU page payload (i.e. it lacks the RDH which will be added by the writer) of the maximum size `8192-sizeof(RDH) = 8128` bytes. The writer will create a new CRU page with provided payload equipping it with the proper RDH: copying already stored RDH of the current HBF, if the interaction record `ir` belongs to the same HBF or generating new RDH for new HBF otherwise (and filling all missing HBFs in-between). In case the payload size exceeds maximum, an exception will be thrown w/o any attempt to split the page. -Some detectors signal the end of the HBF by adding an empty CRU page containing just a header with ``RDH.stop=1`` while others may simply set the ``RDH.stop=1`` in the last CRU page of the HBF (it may appear to be also the 1st and the only page of the HBF and may or may not contain the payload). -This behaviour is steered by ``writer.setAddSeparateHBFStopPage(bool v)`` switch. By default end of the HBF is signaled on separate page. +* `trigger` (default 0): optionally detector may provide a trigger word for this payload, this word will be OR-ed with the current RDH.triggerType + +* `detField` (default 0): optionally detector may provide a custom 32-bit word which will be assigned to RDH.detectorField. For further details see ``ITSMFT/common/simulation/MC2RawEncoder`` class and the macro `Detectors/ITSMFT/ITS/macros/test/run_digi2rawVarPage_its.C` to steer the MC to raw data conversion. @@ -183,7 +199,7 @@ For further details see ``ITSMFT/common/simulation/MC2RawEncoder`` class and th A class for parsing raw data file(s) with "variable-size" CRU format. For every encountered link the DPL `SubSpecification` is assigned according to the formula used by DataDistribution: ```cpp -SubSpec = (RDH.cruID<<16) | ((RDH.linkID + 1)<<(RDH.endPointID == 1 ? 8 : 0)); +SubSpec = (RDH.cruID<<16) | ((RDH.linkID + 1)<<(RDH.endPointID == 1 ? 8 : 0)); ``` This `SubSpecification` is used to define the DPL InputSpecs (and match the OutputSpecs). @@ -231,22 +247,22 @@ The input configuration must have following format (parsed using `Common-O2::Con # optional, will override defaults set by RawFileReader [defaults] -# optional, initial default is FLP +# optional, initial default is FLP dataOrigin = ITS # optional, initial default is RAWDATA -dataDescription = RAWRDATA +dataDescription = RAWRDATA [input-0] #optional, if missing then default is used dataOrigin = ITS #optional, if missing then default is used -dataDescription = RAWDATA +dataDescription = RAWDATA filePath = path_and_name_of_the_data_file0 # for CRU detectors the "readoutCard" record below is optional # readoutCard = CRU [input-1] -dataOrigin = TPC +dataOrigin = TPC filePath = path_and_name_of_the_data_file1 [input-2] @@ -256,7 +272,7 @@ filePath = path_and_name_of_the_data_file2 dataOrigin = EMC filePath = path_and_name_of_the_data_fileX # for RORC detectors the record below is obligatory -readoutCard = RORC +readoutCard = RORC @@ -265,7 +281,7 @@ readoutCard = RORC ``` -The typical loop to read the data from already initialized reader is: +The typical loop to read the data from already initialized reader is: ```cpp int nlinks = reader.getNLinks(); bool readPerTF = true; // data can be read per TF or per HBF @@ -276,7 +292,7 @@ while(1) { LOG(INFO) << "nothing left to read after " << tfID << " TFs read"; break; } - std::vector<char> dataBuffer; // where to put extracted data + std::vector<char> dataBuffer; // where to put extracted data for (int il = 0; il < reader.getNLinks(); il++) { auto& link = reader.getLink(il); @@ -285,14 +301,14 @@ while(1) { dataBuffer.resize(sz); link.readNextTF(dataTF.data()); // use data ... - } - else { // read data per HBF + } + else { // read data per HBF int nHBF = link.getNHBFinTF(); // number of HBFs in the TF for (int ihb=0;ihb<nHBF;ihb++) { auto sz = link.getNextHBSize(); // size in bytes needed for the next HBF of this link - dataBuffer.resize(sz); - link.readNextHBF(dataTF.data()); - // use data ... + dataBuffer.resize(sz); + link.readNextHBF(dataTF.data()); + // use data ... } } } @@ -304,7 +320,7 @@ Note: every input file may contain data from different CRUs or GBT links, but mi `o2::header::DataOrigin` and `o2::header::DataDescription`) is not allowed. Data from the same detector may be split to multiple files link-wise and/or time-wise. In the latter case the input files must be provided ordered in time (HBF orbit in the RDH). -## Raw data file reader workflow +## Raw data file reader workflow ```cpp o2-raw-file-reader-workflow @@ -315,10 +331,12 @@ o2-raw-file-reader-workflow --delay arg (=0) delay in seconds between consecutive TFs sending --buffer-size arg (=1048576) buffer size for files preprocessing --super-page-size arg (=1048576) super-page size for FMQ parts definition - --part-per-hbf FMQ parts per superpage (default) of HBF + --part-per-sp FMQ parts per superpage instead of per HBF --raw-channel-config arg optional raw FMQ channel for non-DPL output --cache-data cache data at 1st reading, may require excessive memory!!! - --detect-tf0 autodetect HBFUtils start Orbit/BC from 1st TF seen + --detect-tf0 autodetect HBFUtils start Orbit/BC from 1st TF seen (at SOX) + --calculate-tf-start calculate TF start from orbit instead of using TType + --drop-tf arg (=none) Drop each TFid%(1)==(2) of detector, e.g. ITS,2,4;TPC,4[,0];... --configKeyValues arg semicolon separated key=value strings # to suppress various error checks / reporting @@ -331,6 +349,9 @@ o2-raw-file-reader-workflow --nocheck-tf-per-link ignore /Number of TFs is less than expected/ --nocheck-hbf-jump ignore /Wrong HBF orbit increment/ --nocheck-no-spage-for-tf ignore /TF does not start by new superpage/ + --nocheck-no-sox ignore /No SOX found on 1st page/ + --nocheck-tf-start-mismatch ignore /Mismatch between TType-flagged and calculated new TF start/ + ``` The workflow takes an input from the configuration file (as described in `RawFileReader` section), reads the data and sends them as DPL messages @@ -341,7 +362,7 @@ If `--loop` argument is provided, data will be re-played in loop. The delay (in Using `--cache-data` option one can force caching the data to memory during the 1st reading, this avoiding disk I/O for following iterations, but this option should be used with care as it will eventually create a memory copy of all TFs to read. At every invocation of the device `processing` callback a full TimeFrame for every link will be added as a multi-part `FairMQ` message and relayed by the relevant channel. -By default each part will be a single CRU super-page of the link. This behaviour can be changed by providing `part-per-hbf` option, in which case each HBF will be added as a separate HBF. +By default each HBF will start a new part in the multipart message. This behaviour can be changed by providing `part-per-sp` option, in which case there will be one part per superpage (Note that this is incompatible to the DPLRawSequencer). The standard use case of this workflow is to provide the input for other worfklows using the piping, e.g. ```cpp @@ -358,6 +379,8 @@ To inject such a data to DPL one should use a parallel process starting with `o2 [Terminal 2]> o2-raw-file-reader-workflow --session default --loop 1000 --delay 3 --input-conf raw/rawAll.cfg --raw-channel-config "name=raw-reader,type=push,method=bind,address=ipc://@rr-to-dpl,transport=shmem,rateLogging=1" --shm-segment-size 16000000000 ``` +For testing reason one can request dropping of some fraction of the TFs for particular detector. With option `--drop-tf "ITS,3,2;TPC,10"` the reader will not send the output for ITS in TFs with `(TFid%3)==2` and for TPC in TFs with `(TFid%10)==0`. Note that in order to acknowledge the TF, the message `{FLP/DISTSUBTIMEFRAME/0}` will still be sent even if all detector's data was dropped for a given TF. + ## Raw data file checker (standalone executable) ```cpp @@ -369,6 +392,7 @@ Options: -v [ --verbosity ] arg (=0) 1: long report, 2 or 3: print or dump all RDH -s [ --spsize ] arg (=1048576) nominal super-page size in bytes --detect-tf0 autodetect HBFUtils start Orbit/BC from 1st TF seen + --calculate-tf-start calculate TF start from orbit instead of using TType --rorc impose RORC as default detector mode --configKeyValues arg semicolon separated key=value strings --nocheck-packet-increment ignore /Wrong RDH.packetCounter increment/ @@ -380,6 +404,8 @@ Options: --nocheck-tf-per-link ignore /Number of TFs is less than expected/ --nocheck-hbf-jump ignore /Wrong HBF orbit increment/ --nocheck-no-spage-for-tf ignore /TF does not start by new superpage/ + --nocheck-no-sox ignore /No SOX found on 1st page/ + --nocheck-tf-start-mismatch ignore /Mismatch between TType-flagged and calculated new TF start/ (input files are optional if config file was provided) ``` @@ -404,7 +430,7 @@ A warning is printed if this size exceeds the nominal SuperPage size (D=1MB, can For the correct data the output should look like this: ```cpp -o2-raw-filecheck ALPIDE_DATA/rawits_pseudoCalib_RU46_49.bin +o2-raw-filecheck ALPIDE_DATA/rawits_pseudoCalib_RU46_49.bin [INFO] RawDataHeader v4 is assumed [INFO] #0: 182108928 bytes scanned, 69552 RDH read for 12 links from ALPIDE_DATA/rawits_pseudoCalib_RU46_49.bin @@ -424,6 +450,80 @@ L11 | Spec:0x3211267 FEE:0x3201 CRU: 49 Lnk: 2 EP:0 | SPages: 31 Pages: 76 Largest super-page: 1047008 B, largest TF: 4070048 B Real time 0:00:00, CP time 0.120 ``` +## DataDistribution TF reader workflow + +`o2-raw-tf-reader-workflow` allows to inject into the DPL the `(s)TF` data produced by the DataDistribution, avoiding running DD sTFReader in a separate terminal and sending data via proxies. +The relevant command line options are: +``` +--input-data arg +``` +input data (obligatory): comma-separated list of input data files and/or files with list of data files and/or directories containing files + +``` +--max-tf arg (=-1) +``` +max TF ID to process (<= 0 : infinite) + +``` +--loop arg (=0) +``` +loop N times (-1 = infinite) over input files (but max-tf has priority if positive) + +``` +--delay arg (=0) +``` +delay in seconds between consecutive TFs sending (provided TFs can be read fast enough) + +``` +--copy-cmd arg (=XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst) +``` +copy command for remote files + +``` +--tf-file-regex arg (=.+\.tf$) +``` +regex string to identify TF files: optional to filter data files (if the input contains directories, it will be used to avoid picking non-TF files) + +``` +--remote-regex arg (=^/eos/aliceo2/.+) +``` +regex string to identify remote files (they will be copied to `/tmp/<random>/` directory, then removed after processing) + +``` +--max-cached-tf arg (=3) +``` +max TFs to cache in memory: builds TFs asynchrously to sending, may speed up processing but needs more shmem. + +``` +--max-cached-files arg (=3) +``` +max TF files queued (copied for remote source). For local files almost irrelevant, for remote ones asynchronously creates local copy. + +``` +--tf-reader-verbosity arg (=0) +``` +verbosity level (1 or 2: check RDH, print DH/DPH for 1st or all slices, >2 print RDH) + +``` +--raw-channel-config arg +``` +optional raw FMQ channel for non-DPL output, similar to `o2-raw-file-reader-workflow`. + +Since a priory it is not known what kind of data is in the raw TF file provided on the input, by default the reader will define outputs for the raw data of all known detectors (as subspecification-wildcarded `<DET>/RAWDATA`). Additionally, since some detectors might have done processing on the FLP (in which case the DD TF will contain derived data, e.g. cells), the reader will open extra outputs for all kinds of messages for which we know they can be produced on the FLP. Following 3 partially redundant options allow to decrease the number of defined outputs: +``` +--onlyDet arg (=all) +``` +list of detectors to select from available in the data, outputs for others will not be created, their data will be skipped. +``` +--raw-only-det arg (=none) +``` +list of detectors for which non-raw outputs (if any) are discarded. +``` +--non-raw-only-det arg (=none) +``` +list of detectors for which raw outputs are discarded. + +The raw data will be propagated (if present) only if the detector is selected in `--onlyDet` and `NOT` selected in `--non-raw-only-det`. The non-raw data will be propagated (if defined for the given detector and present in the file) only if the detector is selected in `--onlyDet` and `NOT` selected in `--raw-only-det`. ## Miscellaneous macros diff --git a/Detectors/Raw/TFReaderDD/CMakeLists.txt b/Detectors/Raw/TFReaderDD/CMakeLists.txt new file mode 100644 index 0000000000000..5b5beef56c949 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TFReaderDD + SOURCES src/SubTimeFrameFile.cxx + src/SubTimeFrameFileReader.cxx + PUBLIC_LINK_LIBRARIES FairRoot::Base + O2::Headers + O2::Framework + O2::DetectorsRaw + O2::CommonUtils + FairMQ::FairMQ) + +o2_add_executable(tf-reader-workflow + COMPONENT_NAME raw + SOURCES src/TFReaderSpec.cxx + src/tf-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::TFReaderDD) diff --git a/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFile.h b/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFile.h new file mode 100644 index 0000000000000..92a72a8796d40 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFile.h @@ -0,0 +1,354 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Adapthed with minimal changes from Gvozden Nescovic code to read sTFs files created by DataDistribution + +#ifndef _ALICEO2_SUBTIMEFRAME_FILE_RAWDD_H_ +#define _ALICEO2_SUBTIMEFRAME_FILE_RAWDD_H_ + +#include <chrono> +#include <iomanip> +#include <ostream> +#include <sstream> +#include <vector> + +#include <Headers/DataHeader.h> +#include "Framework/Logger.h" + +namespace o2 +{ +namespace rawdd +{ + +struct EquipmentIdentifier { + o2::header::DataDescription mDataDescription; /* 2 x uint64_t */ + o2::header::DataHeader::SubSpecificationType mSubSpecification; /* uint32_t */ + o2::header::DataOrigin mDataOrigin; /* 1 x uint32_t */ + + EquipmentIdentifier() = delete; + + EquipmentIdentifier(const o2::header::DataDescription& pDataDesc, + const o2::header::DataOrigin& pDataOrig, + const o2::header::DataHeader::SubSpecificationType& pSubSpec) noexcept + : mDataDescription(pDataDesc), + mSubSpecification(pSubSpec), + mDataOrigin(pDataOrig) + { + } + + EquipmentIdentifier(const o2::header::DataIdentifier& pDataId, + const o2::header::DataHeader::SubSpecificationType& pSubSpec) noexcept + : EquipmentIdentifier(pDataId.dataDescription, pDataId.dataOrigin, pSubSpec) + { + } + + EquipmentIdentifier(const EquipmentIdentifier& pEid) noexcept + : EquipmentIdentifier(pEid.mDataDescription, pEid.mDataOrigin, pEid.mSubSpecification) + { + } + + EquipmentIdentifier(const o2::header::DataHeader& pDh) noexcept + : EquipmentIdentifier(pDh.dataDescription, pDh.dataOrigin, pDh.subSpecification) + { + } + + operator o2::header::DataIdentifier() const noexcept + { + o2::header::DataIdentifier lRetId; + lRetId.dataDescription = mDataDescription; + lRetId.dataOrigin = mDataOrigin; + return lRetId; + } + + bool operator<(const EquipmentIdentifier& other) const noexcept + { + if (mDataDescription < other.mDataDescription) { + return true; + } + + if (mDataDescription == other.mDataDescription && mDataOrigin < other.mDataOrigin) { + return true; + } + + if (mDataDescription == other.mDataDescription && mDataOrigin == other.mDataOrigin && + mSubSpecification < other.mSubSpecification) { + return true; + } + + return false; + } + + bool operator==(const EquipmentIdentifier& other) const noexcept + { + if (mDataDescription == other.mDataDescription && + mSubSpecification == other.mSubSpecification && + mDataOrigin == other.mDataOrigin) { + return true; + } else { + return false; + } + } + + bool operator!=(const EquipmentIdentifier& other) const noexcept + { + return !(*this == other); + } + + const std::string info() const + { + return fmt::format("{}/{}/{}", + std::string(mDataOrigin.str), + std::string(mDataDescription.str), + mSubSpecification); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileMeta +//////////////////////////////////////////////////////////////////////////////// + +struct SubTimeFrameFileMeta { + static const o2::header::DataDescription sDataDescFileSubTimeFrame; + + static const o2::header::DataHeader getDataHeader() + { + auto lHdr = o2::header::DataHeader( + SubTimeFrameFileMeta::sDataDescFileSubTimeFrame, + o2::header::gDataOriginFLP, + 0, // TODO: subspecification? FLP ID? EPN ID? + sizeof(SubTimeFrameFileMeta)); + + lHdr.payloadSerializationMethod = o2::header::gSerializationMethodNone; + + return lHdr; + } + + static constexpr std::uint64_t getSizeInFile() + { + return sizeof(o2::header::DataHeader) + sizeof(SubTimeFrameFileMeta); + } + + /// + /// Version of STF file format + /// + const std::uint64_t mStfFileVersion = 1; + + /// + /// Size of the Stf in file, including this header. + /// + std::uint64_t mStfSizeInFile; + + /// + /// Time when Stf was written (in ms) + /// + std::uint64_t mWriteTimeMs; + + auto getTimePoint() + { + using namespace std::chrono; + return time_point<system_clock, milliseconds>{milliseconds{mWriteTimeMs}}; + } + + std::string getTimeString() + { + using namespace std::chrono; + std::time_t lTime = system_clock::to_time_t(getTimePoint()); + + std::stringstream lTimeStream; + lTimeStream << std::put_time(std::localtime(&lTime), "%F %T"); + return lTimeStream.str(); + } + + SubTimeFrameFileMeta(const std::uint64_t pStfSize) + : SubTimeFrameFileMeta() + { + mStfSizeInFile = pStfSize; + } + + SubTimeFrameFileMeta() + : mStfSizeInFile{0} + { + using namespace std::chrono; + mWriteTimeMs = time_point_cast<milliseconds>(system_clock::now()).time_since_epoch().count(); + } + + friend std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileMeta& pMeta); +}; + +std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileMeta& pMeta); + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileDataIndex +//////////////////////////////////////////////////////////////////////////////// + +struct SubTimeFrameFileDataIndex { + static const o2::header::DataDescription sDataDescFileStfDataIndex; + + struct DataIndexElem { + /// Equipment Identifier: unrolled to pack better + o2::header::DataDescription mDataDescription; + o2::header::DataOrigin mDataOrigin; + /// Number of data blocks <data_header, data> + std::uint32_t mDataBlockCnt = 0; + /// subspecification (u64) + o2::header::DataHeader::SubSpecificationType mSubSpecification = 0; + /// Offset of data block (corresponding data header) relative to + std::uint64_t mOffset = 0; + /// Total size of data blocks including headers + std::uint64_t mSize = 0; + + DataIndexElem() = delete; + DataIndexElem(const EquipmentIdentifier& pId, + const std::uint32_t pCnt, + const std::uint64_t pOff, + const std::uint64_t pSize) + : mDataDescription(pId.mDataDescription), + mDataOrigin(pId.mDataOrigin), + mDataBlockCnt(pCnt), + mSubSpecification(pId.mSubSpecification), + mOffset(pOff), + mSize(pSize) + { + static_assert(sizeof(DataIndexElem) == 48, + "DataIndexElem changed -> Binary compatibility is lost!"); + } + }; + + SubTimeFrameFileDataIndex() = default; + + void clear() noexcept { mDataIndex.clear(); } + bool empty() const noexcept { return mDataIndex.empty(); } + + void AddStfElement(const EquipmentIdentifier& pEqDataId, + const std::uint32_t pCnt, + const std::uint64_t pOffset, + const std::uint64_t pSize) + { + mDataIndex.emplace_back(pEqDataId, pCnt, pOffset, pSize); + } + + std::uint64_t getSizeInFile() const + { + return sizeof(o2::header::DataHeader) + (sizeof(DataIndexElem) * mDataIndex.size()); + } + + friend std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileDataIndex& pIndex); + + private: + const o2::header::DataHeader getDataHeader() const + { + auto lHdr = o2::header::DataHeader( + sDataDescFileStfDataIndex, + o2::header::gDataOriginAny, + 0, // TODO: subspecification? FLP ID? EPN ID? + mDataIndex.size() * sizeof(DataIndexElem)); + + lHdr.payloadSerializationMethod = o2::header::gSerializationMethodNone; + + return lHdr; + } + + std::vector<DataIndexElem> mDataIndex; +}; + +std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileDataIndex& pIndex); +} // namespace rawdd + +} // namespace o2 + +namespace std +{ +template <> +struct hash<o2::header::DataDescription> { + typedef o2::header::DataDescription argument_type; + typedef std::uint64_t result_type; + + result_type operator()(argument_type const& a) const noexcept + { + + static_assert(sizeof(o2::header::DataDescription::ItgType) == sizeof(uint64_t) && + sizeof(o2::header::DataDescription) == 16, + "DataDescription must be 16B long (uint64_t itg[2])"); + + return std::hash<o2::header::DataDescription::ItgType>{}(a.itg[0]) ^ + std::hash<o2::header::DataDescription::ItgType>{}(a.itg[1]); + } +}; + +template <> +struct hash<o2::header::DataOrigin> { + typedef o2::header::DataOrigin argument_type; + typedef std::uint32_t result_type; + + result_type operator()(argument_type const& a) const noexcept + { + + static_assert(sizeof(o2::header::DataOrigin::ItgType) == sizeof(uint32_t) && + sizeof(o2::header::DataOrigin) == 4, + "DataOrigin must be 4B long (uint32_t itg[1])"); + + return std::hash<o2::header::DataOrigin::ItgType>{}(a.itg[0]); + } +}; + +inline void hash_combine(std::size_t& seed) {} + +template <typename T, typename... Rest> +inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) +{ + std::hash<T> hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + hash_combine(seed, rest...); +} + +template <> +struct hash<o2::header::DataHeader> { + typedef o2::header::DataHeader argument_type; + typedef std::size_t result_type; + + result_type operator()(argument_type const& a) const noexcept + { + result_type h = (size_t(a.tfCounter) << 32) + a.subSpecification; + hash_combine(h, a.dataOrigin, a.dataDescription); + return h; + } +}; + +template <> +struct hash<o2::header::DataIdentifier> { + typedef o2::header::DataIdentifier argument_type; + typedef std::uint64_t result_type; + + result_type operator()(argument_type const& a) const noexcept + { + + return std::hash<o2::header::DataDescription>{}(a.dataDescription) ^ + std::hash<o2::header::DataOrigin>{}(a.dataOrigin); + } +}; + +template <> +struct hash<o2::rawdd::EquipmentIdentifier> { + typedef o2::rawdd::EquipmentIdentifier argument_type; + typedef std::uint64_t result_type; + + result_type operator()(argument_type const& a) const noexcept + { + + return std::hash<o2::header::DataDescription>{}(a.mDataDescription) ^ + (std::hash<o2::header::DataOrigin>{}(a.mDataOrigin) << 1) ^ + a.mSubSpecification; + } +}; + +} //namespace std + +#endif /* _ALICEO2_SUBTIMEFRAME_FILE_RAWDD_H_ */ diff --git a/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFileReader.h b/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFileReader.h new file mode 100644 index 0000000000000..5dd2f08266f58 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/include/TFReaderDD/SubTimeFrameFileReader.h @@ -0,0 +1,143 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Adapthed with minimal changes from Gvozden Nescovic code to read sTFs files created by DataDistribution + +#ifndef ALICEO2_SUBTIMEFRAME_FILE_READER_RAWDD_H_ +#define ALICEO2_SUBTIMEFRAME_FILE_READER_RAWDD_H_ + +#include <Headers/DataHeader.h> +#include "DetectorsCommonDataFormats/DetID.h" +#include <Headers/Stack.h> +#include <fairmq/FairMQParts.h> +#include <fairmq/FairMQDevice.h> +#include <Framework/OutputRoute.h> +#include <boost/filesystem.hpp> +#include <boost/iostreams/device/mapped_file.hpp> +#include <fstream> +#include <vector> +#include <unordered_map> + +namespace o2f = o2::framework; + +namespace o2 +{ + +namespace rawdd +{ + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileReader +//////////////////////////////////////////////////////////////////////////////// +using MessagesPerRoute = std::unordered_map<std::string, std::unique_ptr<FairMQParts>>; + +class SubTimeFrameFileReader +{ + public: + static constexpr o2::header::DataDescription gDataDescSubTimeFrame{"DISTSUBTIMEFRAME"}; + struct STFHeader { // fake header to mimic DD SubTimeFrame::Header sent with DISTSUBTIMEFRAME message + uint64_t id = uint64_t(-1); + uint32_t firstOrbit = uint32_t(-1); + std::uint32_t runNumber = 0; + }; + + SubTimeFrameFileReader() = delete; + SubTimeFrameFileReader(const std::string& pFileName, o2::detectors::DetID::mask_t detMask); + ~SubTimeFrameFileReader(); + + /// Read a single TF from the file + std::unique_ptr<MessagesPerRoute> read(FairMQDevice* device, const std::vector<o2f::OutputRoute>& outputRoutes, const std::string& rawChannel, int verbosity); + + /// Tell the current position of the file + inline std::uint64_t position() const { return mFileMapOffset; } + + /// Set the current position of the file + inline void set_position(std::uint64_t pPos) + { + const std::uint64_t lPos = std::min(pPos, mFileSize); + assert(pPos == lPos); + mFileMapOffset = lPos; + } + + /// Is the stream position at EOF + inline bool eof() const { return mFileMapOffset == mFileSize; } + + /// Tell the size of the file + inline std::uint64_t size() const { return mFileSize; } + + private: + std::string mFileName; + std::unordered_map<o2::header::DataOrigin, bool> mDetOrigMap; + boost::iostreams::mapped_file_source mFileMap; + std::uint64_t mFileMapOffset = 0; + std::uint64_t mFileSize = 0; + + // helper to make sure written chunks are buffered, only allow pointers + template <typename pointer, + typename = std::enable_if_t<std::is_pointer<pointer>::value>> + bool read_advance(pointer pPtr, std::uint64_t pLen) + { + if (!mFileMap.is_open()) { + return false; + } + + assert(mFileMapOffset <= mFileSize); + const std::uint64_t lToRead = std::min(pLen, mFileSize - mFileMapOffset); + + if (lToRead != pLen) { + LOGP(ERROR, "FileReader: request to read beyond the file end. pos={} size={} len={}", + mFileMapOffset, mFileSize, pLen); + LOGP(ERROR, "Closing the file {}. The read data is invalid.", mFileName); + mFileMap.close(); + mFileMapOffset = 0; + mFileSize = 0; + return false; + } + + std::memcpy(reinterpret_cast<char*>(pPtr), mFileMap.data() + mFileMapOffset, lToRead); + mFileMapOffset += lToRead; + return true; + } + + // return the pointer + unsigned char* peek() const + { + return const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(mFileMap.data() + mFileMapOffset)); + } + + inline bool ignore_nbytes(const std::size_t pLen) + { + const std::size_t lToIgnore = std::min(pLen, std::size_t(mFileSize - mFileMapOffset)); + if (pLen != lToIgnore) { + LOGP(ERROR, "FileReader: request to ignore bytes beyond the file end. pos={} size={} len={}", + mFileMapOffset, mFileSize, pLen); + LOGP(ERROR, "Closing the file {}. The read data is invalid.", mFileName); + mFileMap.close(); + mFileMapOffset = 0; + mFileSize = 0; + return false; + } + + mFileMapOffset += lToIgnore; + assert(mFileMapOffset <= mFileSize); + return true; + } + + std::size_t getHeaderStackSize(); + o2::header::Stack getHeaderStack(std::size_t& pOrigsize); + + // flags for upgrading DataHeader versions + static std::uint64_t sStfId; // TODO: add id to files metadata +}; +} // namespace rawdd +} // namespace o2 + +#endif /* ALICEO2_SUBTIMEFRAME_FILE_READER_RAWDD_H_ */ diff --git a/Detectors/Raw/TFReaderDD/src/SubTimeFrameFile.cxx b/Detectors/Raw/TFReaderDD/src/SubTimeFrameFile.cxx new file mode 100644 index 0000000000000..4cf058e450031 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/src/SubTimeFrameFile.cxx @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Adapthed with minimal changes from Gvozden Nescovic code to read sTFs files created by DataDistribution + +#include "TFReaderDD/SubTimeFrameFile.h" + +namespace o2 +{ +namespace rawdd +{ + +using namespace o2::header; + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileMeta +//////////////////////////////////////////////////////////////////////////////// + +const o2::header::DataDescription SubTimeFrameFileMeta::sDataDescFileSubTimeFrame{"FILE_STF_META"}; + +std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileMeta& pMeta) +{ + static_assert(std::is_standard_layout<SubTimeFrameFileMeta>::value, + "SubTimeFrameFileMeta must be a std layout type."); + + // write DataHeader + const o2::header::DataHeader lDataHeader = SubTimeFrameFileMeta::getDataHeader(); + pStream.write(reinterpret_cast<const char*>(&lDataHeader), sizeof(o2::header::DataHeader)); + // write the meta + + return pStream.write(reinterpret_cast<const char*>(&pMeta), sizeof(SubTimeFrameFileMeta)); +} + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileDataIndex +//////////////////////////////////////////////////////////////////////////////// + +const o2::header::DataDescription SubTimeFrameFileDataIndex::sDataDescFileStfDataIndex{"FILE_STF_INDEX"}; + +std::ostream& operator<<(std::ostream& pStream, const SubTimeFrameFileDataIndex& pIndex) +{ + static_assert(std::is_standard_layout<SubTimeFrameFileDataIndex::DataIndexElem>::value, + "SubTimeFrameFileDataIndex::DataIndexElem must be a std layout type."); + + // write DataHeader + const o2::header::DataHeader lDataHeader = pIndex.getDataHeader(); + pStream.write(reinterpret_cast<const char*>(&lDataHeader), sizeof(o2::header::DataHeader)); + + // write the index + return pStream.write(reinterpret_cast<const char*>(pIndex.mDataIndex.data()), + pIndex.mDataIndex.size() * sizeof(SubTimeFrameFileDataIndex::DataIndexElem)); +} +} // namespace rawdd +} // namespace o2 diff --git a/Detectors/Raw/TFReaderDD/src/SubTimeFrameFileReader.cxx b/Detectors/Raw/TFReaderDD/src/SubTimeFrameFileReader.cxx new file mode 100644 index 0000000000000..741a8a573f7c3 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/src/SubTimeFrameFileReader.cxx @@ -0,0 +1,429 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Adapthed with minimal changes from Gvozden Nescovic code to read sTFs files created by DataDistribution + +#include "TFReaderDD/SubTimeFrameFile.h" +#include "TFReaderDD/SubTimeFrameFileReader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Framework/Logger.h" +#include "Framework/OutputRoute.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DataProcessingHeader.h" +#include <fairmq/FairMQDevice.h> + +#if __linux__ +#include <sys/mman.h> +#endif + +// uncomment this to check breakdown of TF building timing +//#define _RUN_TIMING_MEASUREMENT_ + +#ifdef _RUN_TIMING_MEASUREMENT_ +#include "TStopwatch.h" +#endif + +namespace o2 +{ +namespace rawdd +{ +using DetID = o2::detectors::DetID; +using namespace o2::header; +namespace o2f = o2::framework; + +//////////////////////////////////////////////////////////////////////////////// +/// SubTimeFrameFileReader +//////////////////////////////////////////////////////////////////////////////// + +SubTimeFrameFileReader::SubTimeFrameFileReader(const std::string& pFileName, o2::detectors::DetID::mask_t detMask) + : mFileName(pFileName) +{ + mFileMap.open(mFileName); + if (!mFileMap.is_open()) { + LOG(ERROR) << "Failed to open TF file for reading (mmap)."; + return; + } + mFileSize = mFileMap.size(); + mFileMapOffset = 0; + + for (DetID::ID id = DetID::First; id <= DetID::Last; id++) { + mDetOrigMap[DetID::getDataOrigin(id)] = detMask[id]; + } + +#if __linux__ + madvise((void*)mFileMap.data(), mFileMap.size(), MADV_HUGEPAGE | MADV_SEQUENTIAL | MADV_DONTDUMP); +#endif +} + +SubTimeFrameFileReader::~SubTimeFrameFileReader() +{ + if (!mFileMap.is_open()) { +#if __linux__ + madvise((void*)mFileMap.data(), mFileMap.size(), MADV_DONTNEED); +#endif + mFileMap.close(); + } +} + +std::size_t SubTimeFrameFileReader::getHeaderStackSize() // throws ios_base::failure +{ + // Expect valid Stack in the file. + // First Header must be DataHeader. The size is unknown since there are multiple versions. + // Each header in the stack extends BaseHeader + + // Read first the base header then the rest of the extended header. Keep going until the next flag is set. + // reset the file pointer to the original incoming position, so the complete Stack can be read in + + bool readNextHeader = true; + std::size_t lStackSize = 0; + DataHeader lBaseHdr; // Use DataHeader since the BaseHeader has no default contructor. + + const auto lFilePosStart = position(); + + const auto cMaxHeaders = 16; /* make sure we don't loop forever */ + auto lNumHeaders = 0; + while (readNextHeader && (++lNumHeaders <= cMaxHeaders)) { + // read BaseHeader only! + if (!read_advance(&lBaseHdr, sizeof(BaseHeader))) { + return 0; + } + + if (!ignore_nbytes(lBaseHdr.size())) { + return 0; + } + + lStackSize += lBaseHdr.size(); + readNextHeader = (lBaseHdr.next() != nullptr); + } + // reset the file pointer + set_position(lFilePosStart); + + if (lNumHeaders >= cMaxHeaders) { + LOGP(ERROR, "FileReader: Reached max number of headers allowed: {}.", cMaxHeaders); + return 0; + } + + return lStackSize; +} + +Stack SubTimeFrameFileReader::getHeaderStack(std::size_t& pOrigsize) +{ + const auto lStackSize = getHeaderStackSize(); + pOrigsize = lStackSize; + + if (lStackSize < sizeof(BaseHeader)) { + // error in the stream + pOrigsize = 0; + return Stack{}; + } + + std::byte* lStackMem = reinterpret_cast<std::byte*>(peek()); + if (!ignore_nbytes(lStackSize)) { + // error in the stream + pOrigsize = 0; + return Stack{}; + } + + // This must handle different versions of DataHeader + // check if DataHeader needs an upgrade by looking at the version number + const BaseHeader* lBaseOfDH = BaseHeader::get(lStackMem); + if (!lBaseOfDH) { + return Stack{}; + } + + if (lBaseOfDH->headerVersion < DataHeader::sVersion) { + DataHeader lNewDh; + + // Write over the new DataHeader. We need to update some of the BaseHeader values. + assert(sizeof(DataHeader) > lBaseOfDH->size()); // current DataHeader must be larger + std::memcpy(&lNewDh, (void*)lBaseOfDH->data(), lBaseOfDH->size()); + + // make sure to bump the version in the BaseHeader. + // TODO: Is there a better way? + lNewDh.headerSize = sizeof(DataHeader); + lNewDh.headerVersion = DataHeader::sVersion; + + if (lBaseOfDH->headerVersion == 1 || lBaseOfDH->headerVersion == 2) { + /* nothing to do for the upgrade */ + } else { + LOGP(ERROR, "FileReader: DataHeader v{} read from file is not upgraded to the current version {}", + lBaseOfDH->headerVersion, DataHeader::sVersion); + LOGP(ERROR, "Try using a newer version of DataDistribution or file a BUG"); + } + + if (lBaseOfDH->size() == lStackSize) { + return Stack(lNewDh); + } else { + assert(lBaseOfDH->size() < lStackSize); + + return Stack( + lNewDh, + Stack(lStackMem + lBaseOfDH->size())); + } + } + + return Stack(lStackMem); +} + +std::uint64_t SubTimeFrameFileReader::sStfId = 0; // TODO: add id to files metadata + +std::unique_ptr<MessagesPerRoute> SubTimeFrameFileReader::read(FairMQDevice* device, const std::vector<o2f::OutputRoute>& outputRoutes, + const std::string& rawChannel, int verbosity) +{ + std::unique_ptr<MessagesPerRoute> messagesPerRoute = std::make_unique<MessagesPerRoute>(); + auto& msgMap = *messagesPerRoute.get(); + assert(device); + std::unordered_map<o2::header::DataHeader, std::pair<std::string, bool>> channelsMap; + auto findOutputChannel = [&outputRoutes, &rawChannel, &channelsMap](const o2::header::DataHeader* h) -> const std::string& { + if (!rawChannel.empty()) { + return rawChannel; + } + auto& chFromMap = channelsMap[*h]; + if (chFromMap.first.empty() && !chFromMap.second) { // search for channel which is enountered for the 1st time + chFromMap.second = true; // flag that it was already checked + for (auto& oroute : outputRoutes) { + LOG(DEBUG) << "comparing with matcher to route " << oroute.matcher << " TSlice:" << oroute.timeslice; + if (o2f::DataSpecUtils::match(oroute.matcher, h->dataOrigin, h->dataDescription, h->subSpecification) && ((h->tfCounter % oroute.maxTimeslices) == oroute.timeslice)) { + LOG(DEBUG) << "picking the route:" << o2f::DataSpecUtils::describe(oroute.matcher) << " channel " << oroute.channel; + chFromMap.first = oroute.channel; + break; + } + } + } + return chFromMap.first; + }; + + auto addPart = [&msgMap](FairMQMessagePtr hd, FairMQMessagePtr pl, const std::string& fairMQChannel) { + FairMQParts* parts = nullptr; + parts = msgMap[fairMQChannel].get(); // FairMQParts* + if (!parts) { + msgMap[fairMQChannel] = std::make_unique<FairMQParts>(); + parts = msgMap[fairMQChannel].get(); + } + parts->AddPart(std::move(hd)); + parts->AddPart(std::move(pl)); + }; + + // record current position + const auto lTfStartPosition = position(); + + if (lTfStartPosition == size() || !mFileMap.is_open() || eof()) { + return nullptr; + } + auto tfID = sStfId++; + std::size_t lMetaHdrStackSize = 0; + const DataHeader* lStfMetaDataHdr = nullptr; + SubTimeFrameFileMeta lStfFileMeta; + + auto printStack = [tfID](const o2::header::Stack& st) { + auto dph = o2::header::get<o2f::DataProcessingHeader*>(st.data()); + auto dh = o2::header::get<o2::header::DataHeader*>(st.data()); + LOGP(INFO, "TF#{} Header for {}/{}/{} @ timeslice {} run {} | {} of {} size {}, TForbit {} | DPH: {}/{}/{}", tfID, + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->runNumber, + dh->splitPayloadIndex, dh->splitPayloadParts, dh->payloadSize, dh->firstTForbit, + dph ? dph->startTime : 0, dph ? dph->duration : 0, dph ? dph->creation : 0); + }; + + // Read DataHeader + SubTimeFrameFileMeta + auto lMetaHdrStack = getHeaderStack(lMetaHdrStackSize); + if (lMetaHdrStackSize == 0) { + LOG(ERROR) << "Failed to read the TF file header. The file might be corrupted."; + mFileMap.close(); + return nullptr; + } + + lStfMetaDataHdr = o2::header::DataHeader::Get(lMetaHdrStack.first()); + if (!read_advance(&lStfFileMeta, sizeof(SubTimeFrameFileMeta))) { + return nullptr; + } + + // verify we're actually reading the correct data in + if (!(SubTimeFrameFileMeta::getDataHeader().dataDescription == lStfMetaDataHdr->dataDescription)) { + LOGP(WARNING, "Reading bad data: SubTimeFrame META header"); + mFileMap.close(); + return nullptr; + } + + // prepare to read the TF data + const auto lStfSizeInFile = lStfFileMeta.mStfSizeInFile; + if (lStfSizeInFile == (sizeof(DataHeader) + sizeof(SubTimeFrameFileMeta))) { + LOGP(WARNING, "Reading an empty TF from file. Only meta information present"); + mFileMap.close(); + return nullptr; + } + + // check there's enough data in the file + if ((lTfStartPosition + lStfSizeInFile) > this->size()) { + LOGP(WARNING, "Not enough data in file for this TF. Required: {}, available: {}", lStfSizeInFile, (this->size() - lTfStartPosition)); + mFileMap.close(); + return nullptr; + } + + // Index + std::size_t lStfIndexHdrStackSize = 0; + const DataHeader* lStfIndexHdr = nullptr; + + // Read DataHeader + SubTimeFrameFileMeta + auto lStfIndexHdrStack = getHeaderStack(lStfIndexHdrStackSize); + if (lStfIndexHdrStackSize == 0) { + mFileMap.close(); + return nullptr; + } + lStfIndexHdr = o2::header::DataHeader::Get(lStfIndexHdrStack.first()); + if (!lStfIndexHdr) { + LOG(ERROR) << "Failed to read the TF index structure. The file might be corrupted."; + return nullptr; + } + + if (!ignore_nbytes(lStfIndexHdr->payloadSize)) { + return nullptr; + } +#ifdef _RUN_TIMING_MEASUREMENT_ + TStopwatch readSW, findChanSW, msgSW, addPartSW; + findChanSW.Stop(); + msgSW.Stop(); + addPartSW.Stop(); +#endif + // Remaining data size of the TF: + // total size in file - meta (hdr+struct) - index (hdr + payload) + const auto lStfDataSize = lStfSizeInFile - (lMetaHdrStackSize + sizeof(SubTimeFrameFileMeta)) - (lStfIndexHdrStackSize + lStfIndexHdr->payloadSize); + + std::int64_t lLeftToRead = lStfDataSize; + STFHeader stfHeader{tfID, -1u, -1u}; + + // read <hdrStack + data> pairs + while (lLeftToRead > 0) { + + // allocate and read the Headers + std::size_t lDataHeaderStackSize = 0; + Stack lDataHeaderStack = getHeaderStack(lDataHeaderStackSize); + if (lDataHeaderStackSize == 0) { + mFileMap.close(); + return nullptr; + } + const DataHeader* lDataHeader = o2::header::DataHeader::Get(lDataHeaderStack.first()); + if (!lDataHeader) { + LOG(ERROR) << "Failed to read the TF HBF DataHeader structure. The file might be corrupted."; + mFileMap.close(); + return nullptr; + } + + o2::header::Stack headerStack{*lDataHeader, o2f::DataProcessingHeader{tfID, 1}}; + if (stfHeader.runNumber == -1) { + stfHeader.id = lDataHeader->tfCounter; + stfHeader.runNumber = lDataHeader->runNumber; + stfHeader.firstOrbit = lDataHeader->firstTForbit; + } + + const std::uint64_t lDataSize = lDataHeader->payloadSize; + // do we accept these data? + auto detOrigStatus = mDetOrigMap.find(lDataHeader->dataOrigin); + if (detOrigStatus != mDetOrigMap.end() && !detOrigStatus->second) { // this is a detector data and we don't want to read it + if (!ignore_nbytes(lDataSize)) { + return nullptr; + } + lLeftToRead -= (lDataHeaderStackSize + lDataSize); // update the counter + continue; + } +#ifdef _RUN_TIMING_MEASUREMENT_ + findChanSW.Start(false); +#endif + const auto& fmqChannel = findOutputChannel(lDataHeader); +#ifdef _RUN_TIMING_MEASUREMENT_ + findChanSW.Stop(); +#endif + if (fmqChannel.empty()) { // no output channel + if (!ignore_nbytes(lDataSize)) { + return nullptr; + } + lLeftToRead -= (lDataHeaderStackSize + lDataSize); // update the counter + continue; + //mFileMap.close(); + //return nullptr; + } + // read the data + + auto fmqFactory = device->GetChannel(fmqChannel, 0).Transport(); +#ifdef _RUN_TIMING_MEASUREMENT_ + msgSW.Start(false); +#endif + auto lHdrStackMsg = fmqFactory->CreateMessage(headerStack.size(), fair::mq::Alignment{64}); + auto lDataMsg = fmqFactory->CreateMessage(lDataSize, fair::mq::Alignment{64}); +#ifdef _RUN_TIMING_MEASUREMENT_ + msgSW.Stop(); +#endif + memcpy(lHdrStackMsg->GetData(), headerStack.data(), headerStack.size()); + + if (!read_advance(lDataMsg->GetData(), lDataSize)) { + return nullptr; + } + if (verbosity > 0) { + if (verbosity > 1 || lDataHeader->splitPayloadIndex == 0) { + printStack(headerStack); + if (o2::raw::RDHUtils::checkRDH(lDataMsg->GetData()) && verbosity > 2) { + o2::raw::RDHUtils::printRDH(lDataMsg->GetData()); + } + } + } +#ifdef _RUN_TIMING_MEASUREMENT_ + addPartSW.Start(false); +#endif + addPart(std::move(lHdrStackMsg), std::move(lDataMsg), fmqChannel); +#ifdef _RUN_TIMING_MEASUREMENT_ + addPartSW.Stop(); +#endif + // update the counter + lLeftToRead -= (lDataHeaderStackSize + lDataSize); + } + + if (lLeftToRead < 0) { + LOG(ERROR) << "FileRead: Read more data than it is indicated in the META header!"; + return nullptr; + } + + // add TF acknowledge part + o2::header::DataHeader stfDistDataHeader(gDataDescSubTimeFrame, o2::header::gDataOriginFLP, 0, sizeof(STFHeader), 0, 1); + stfDistDataHeader.payloadSerializationMethod = o2::header::gSerializationMethodNone; + stfDistDataHeader.firstTForbit = stfHeader.firstOrbit; + stfDistDataHeader.runNumber = stfHeader.runNumber; + stfDistDataHeader.tfCounter = stfHeader.id; + stfHeader.id = tfID; + const auto fmqChannel = findOutputChannel(&stfDistDataHeader); + if (!fmqChannel.empty()) { // no output channel + auto fmqFactory = device->GetChannel(fmqChannel, 0).Transport(); + o2::header::Stack headerStackSTF{stfDistDataHeader, o2f::DataProcessingHeader{tfID}}; + if (verbosity > 0) { + printStack(headerStackSTF); + } + auto hdMessageSTF = fmqFactory->CreateMessage(headerStackSTF.size(), fair::mq::Alignment{64}); + auto plMessageSTF = fmqFactory->CreateMessage(stfDistDataHeader.payloadSize, fair::mq::Alignment{64}); + memcpy(hdMessageSTF->GetData(), headerStackSTF.data(), headerStackSTF.size()); + memcpy(plMessageSTF->GetData(), &stfHeader, sizeof(STFHeader)); +#ifdef _RUN_TIMING_MEASUREMENT_ + addPartSW.Start(false); +#endif + addPart(std::move(hdMessageSTF), std::move(plMessageSTF), fmqChannel); +#ifdef _RUN_TIMING_MEASUREMENT_ + addPartSW.Stop(); +#endif + } +#ifdef _RUN_TIMING_MEASUREMENT_ + readSW.Stop(); + LOG(INFO) << "TF creation time: CPU: " << readSW.CpuTime() << " Wall: " << readSW.RealTime() << " s"; + LOG(INFO) << "AddPart Timer CPU: " << addPartSW.CpuTime() << " Wall: " << addPartSW.RealTime() << " s"; + LOG(INFO) << "CreMsg Timer CPU: " << msgSW.CpuTime() << " Wall: " << msgSW.RealTime() << " s"; + LOG(INFO) << "FndChan Timer CPU: " << findChanSW.CpuTime() << " Wall: " << findChanSW.RealTime() << " s"; +#endif + return messagesPerRoute; +} + +} // namespace rawdd +} // namespace o2 diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx new file mode 100644 index 0000000000000..b876c938c4e3b --- /dev/null +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx @@ -0,0 +1,283 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigContext.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/ControlService.h" +#include "Framework/OutputRoute.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +#include "DetectorsCommonDataFormats/DetID.h" +#include <TStopwatch.h> +#include <fairmq/FairMQDevice.h> +#include "TFReaderSpec.h" +#include "TFReaderDD/SubTimeFrameFileReader.h" +#include "CommonUtils/FileFetcher.h" +#include "CommonUtils/FIFO.h" +#include <unistd.h> +#include <algorithm> +#include <unordered_map> +#include <cctype> +#include <string> +#include <climits> +#include <regex> +#include <deque> +#include <chrono> + +using namespace o2::rawdd; +using namespace std::chrono_literals; +using DetID = o2::detectors::DetID; +namespace o2f = o2::framework; + +class TFReaderSpec : public o2f::Task +{ + public: + using TFMap = std::unordered_map<std::string, std::unique_ptr<FairMQParts>>; // map of channel / TFparts + + explicit TFReaderSpec(const TFReaderInp& rinp) : mInput(rinp) {} + void init(o2f::InitContext& ic) final; + void run(o2f::ProcessingContext& ctx) final; + void endOfStream(o2f::EndOfStreamContext& ec) final; + + private: + void stopProcessing(o2f::ProcessingContext& ctx); + void TFBuilder(); + + private: + FairMQDevice* mDevice = nullptr; + std::vector<o2f::OutputRoute> mOutputRoutes; + std::unique_ptr<o2::utils::FileFetcher> mFileFetcher; + o2::utils::FIFO<std::unique_ptr<TFMap>> mTFQueue{}; // queued TFs + int mTFCounter = 0; + int mTFBuilderCounter = 0; + bool mRunning = false; + TFReaderInp mInput; // command line inputs + std::thread mTFBuilderThread{}; +}; + +//___________________________________________________________ +void TFReaderSpec::init(o2f::InitContext& ic) +{ + mFileFetcher = std::make_unique<o2::utils::FileFetcher>(mInput.inpdata, mInput.tffileRegex, mInput.remoteRegex, mInput.copyCmd); + mFileFetcher->setMaxFilesInQueue(mInput.maxFileCache); + mFileFetcher->setMaxLoops(mInput.maxLoops); + mFileFetcher->start(); +} + +//___________________________________________________________ +void TFReaderSpec::run(o2f::ProcessingContext& ctx) +{ + if (!mDevice) { + mDevice = ctx.services().get<o2f::RawDeviceService>().device(); + mOutputRoutes = ctx.services().get<o2f::RawDeviceService>().spec().outputs; // copy!!! + // start TFBuilder thread + mRunning = true; + mTFBuilderThread = std::thread(&TFReaderSpec::TFBuilder, this); + } + static auto tLastTF = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + static long deltaSending = 0; // time correction for sending + auto device = ctx.services().get<o2f::RawDeviceService>().device(); + assert(device); + if (device != mDevice) { + throw std::runtime_error(fmt::format("FMQDevice has changed, old={} new={}", fmt::ptr(mDevice), fmt::ptr(device))); + } + + while (1) { + if (mTFCounter >= mInput.maxTFs) { // done + stopProcessing(ctx); + break; + } + if (mTFQueue.size()) { + auto tfPtr = std::move(mTFQueue.front()); + mTFQueue.pop(); + if (!tfPtr) { + LOG(ERROR) << "Builder provided nullptr TF pointer"; + continue; + } + auto tNow = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + auto tDiff = tNow - tLastTF + 2 * deltaSending; + if (mTFCounter && tDiff < mInput.delay_us) { + usleep(mInput.delay_us - tDiff); // respect requested delay before sending + } + size_t nparts = 0; + auto tSend = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + for (auto& msgIt : *tfPtr.get()) { + nparts += msgIt.second->Size() / 2; + device->Send(*msgIt.second.get(), msgIt.first); + } + tNow = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + deltaSending = mTFCounter ? tNow - tLastTF : 0; + LOGP(INFO, "Sent TF {} of {} parts, {:.4f} s elapsed from previous TF.", mTFCounter, nparts, double(deltaSending) * 1e-6); + deltaSending -= mInput.delay_us; + if (!mTFCounter || deltaSending < 0) { + deltaSending = 0; // correction for next delay + } + tLastTF = tNow; + ++mTFCounter; + break; + } + if (!mRunning) { // no more TFs will be provided + stopProcessing(ctx); + break; + } + usleep(5000); // wait 5ms for new TF to be built + } +} + +//____________________________________________________________ +void TFReaderSpec::endOfStream(o2f::EndOfStreamContext& ec) +{ + if (mFileFetcher) { + mFileFetcher->stop(); + mFileFetcher.reset(); + } + if (mTFBuilderThread.joinable()) { + mTFBuilderThread.join(); + } +} + +//___________________________________________________________ +void TFReaderSpec::stopProcessing(o2f::ProcessingContext& ctx) +{ + LOG(INFO) << mTFCounter << " TFs in " << mFileFetcher->getNLoops() << " loops were sent"; + mRunning = false; + mFileFetcher->stop(); + mFileFetcher.reset(); + if (mTFBuilderThread.joinable()) { + mTFBuilderThread.join(); + } + ctx.services().get<o2f::ControlService>().endOfStream(); + ctx.services().get<o2f::ControlService>().readyToQuit(o2f::QuitRequest::Me); +} + +//____________________________________________________________ +void TFReaderSpec::TFBuilder() +{ + // build TFs and add to the queue + std::string tfFileName; + auto sleepTime = std::chrono::microseconds(mInput.delay_us > 10000 ? mInput.delay_us : 10000); + while (mRunning && mDevice) { + if (mTFQueue.size() >= size_t(mInput.maxTFCache)) { + std::this_thread::sleep_for(sleepTime); + continue; + } + tfFileName = mFileFetcher ? mFileFetcher->getNextFileInQueue() : ""; + if (!mRunning || (tfFileName.empty() && !mFileFetcher->isRunning()) || mTFBuilderCounter >= mInput.maxTFs) { + // stopped or no more files in the queue is expected or needed + LOG(INFO) << "TFBuilder stops processing"; + if (mFileFetcher) { + mFileFetcher->stop(); + } + mRunning = false; + break; + } + if (tfFileName.empty()) { + std::this_thread::sleep_for(10ms); // fait for the files cache to be filled + continue; + } + LOG(INFO) << "Processing file " << tfFileName; + SubTimeFrameFileReader reader(tfFileName, mInput.detMask); + size_t locID = 0; + //try + { + while (mRunning && mTFBuilderCounter < mInput.maxTFs) { + if (mTFQueue.size() >= size_t(mInput.maxTFCache)) { + std::this_thread::sleep_for(sleepTime); + continue; + } + auto tf = reader.read(mDevice, mOutputRoutes, mInput.rawChannelConfig, mInput.verbosity); + if (tf) { + mTFBuilderCounter++; + } + if (mRunning && tf) { + mTFQueue.push(std::move(tf)); + locID++; + } else { + break; + } + } + // remove already processed file from the queue, unless they are needed for further looping + if (mFileFetcher) { + mFileFetcher->popFromQueue(mFileFetcher->getNLoops() >= mInput.maxLoops); + } + } /*catch (...) { + LOGP(ERROR, "Error when building {}-th TF from file {}", locID, tfFileName); + mFileFetcher->popFromQueue(mFileFetcher->getNLoops() >= mInput.maxLoops); // remove faile TF file + } */ + } +} + +//_________________________________________________________ +o2f::DataProcessorSpec o2::rawdd::getTFReaderSpec(o2::rawdd::TFReaderInp& rinp) +{ + // check which inputs are present in files to read + o2f::DataProcessorSpec spec; + spec.name = "tf-reader"; + const DetID::mask_t DEFMask = DetID::getMask("ITS,TPC,TRD,TOF,PHS,CPV,EMC,HMP,MFT,MCH,MID,ZDC,FT0,FV0,FDD,CTP"); + rinp.detMask = DetID::getMask(rinp.detList) & DEFMask; + rinp.detMaskRawOnly = DetID::getMask(rinp.detListRawOnly) & DEFMask; + rinp.detMaskNonRawOnly = DetID::getMask(rinp.detListNonRawOnly) & DEFMask; + if (rinp.rawChannelConfig.empty()) { + // we don't know a priori what will be the content of the TF data, so we create all possible outputs + for (DetID::ID id = DetID::First; id <= DetID::Last; id++) { + if (rinp.detMask[id]) { + if (!rinp.detMaskNonRawOnly[id]) { + spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(id), "RAWDATA"}}); + } + // + if (rinp.detMaskRawOnly[id]) { // used asked to not open non-raw channels + continue; + } + // in case detectors were processed on FLP + if (id == DetID::TOF) { + spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(DetID::TOF), "CRAWDATA"}}); + } else if (id == DetID::FT0 || id == DetID::FV0 || id == DetID::FDD) { + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "DIGITSBC", 0}); + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "DIGITSCH", 0}); + } else if (id == DetID::PHS) { + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "CELLS", 0}); + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "CELLTRIGREC", 0}); + } else if (id == DetID::CPV) { + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "DIGITS", 0}); + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "DIGITTRIGREC", 0}); + spec.outputs.emplace_back(o2f::OutputSpec{DetID::getDataOrigin(id), "RAWHWERRORS", 0}); + } else if (id == DetID::EMC) { + spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(id), "CELLS"}}); + spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(id), "CELLSTRGR"}}); + spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(id), "DECODERERR"}}); + } + } + } + + spec.outputs.emplace_back(o2f::OutputSpec{{"stfDist"}, o2::header::gDataOriginFLP, "DISTSUBTIMEFRAME", 0}); + } else { + auto nameStart = rinp.rawChannelConfig.find("name="); + if (nameStart == std::string::npos) { + throw std::runtime_error("raw channel name is not provided"); + } + nameStart += strlen("name="); + auto nameEnd = rinp.rawChannelConfig.find(",", nameStart + 1); + if (nameEnd == std::string::npos) { + nameEnd = rinp.rawChannelConfig.size(); + } + spec.options = {o2f::ConfigParamSpec{"channel-config", o2f::VariantType::String, rinp.rawChannelConfig, {"Out-of-band channel config"}}}; + rinp.rawChannelConfig = rinp.rawChannelConfig.substr(nameStart, nameEnd - nameStart); + } + + spec.algorithm = o2f::adaptFromTask<TFReaderSpec>(rinp); + + return spec; +} diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.h b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.h new file mode 100644 index 0000000000000..1055ab77bb6e6 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TF_READER_SPEC_H +#define O2_TF_READER_SPEC_H + +/// @file TFReaderWorkflow.h + +#include "Framework/WorkflowSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +namespace o2 +{ +namespace rawdd +{ +struct TFReaderInp { + std::string inpdata{}; + std::string detList{}; + std::string detListRawOnly{}; + std::string detListNonRawOnly{}; + std::string rawChannelConfig{}; + std::string copyCmd{}; + std::string tffileRegex{}; + std::string remoteRegex{}; + o2::detectors::DetID::mask_t detMask{}; + o2::detectors::DetID::mask_t detMaskRawOnly{}; + o2::detectors::DetID::mask_t detMaskNonRawOnly{}; + int maxTFCache = 1; + int maxFileCache = 1; + int verbosity = 0; + int64_t delay_us = 0; + int maxLoops = 0; + int maxTFs = -1; +}; + +o2::framework::DataProcessorSpec getTFReaderSpec(o2::rawdd::TFReaderInp& rinp); + +} // namespace rawdd +} // namespace o2 +#endif diff --git a/Detectors/Raw/TFReaderDD/src/tf-reader-workflow.cxx b/Detectors/Raw/TFReaderDD/src/tf-reader-workflow.cxx new file mode 100644 index 0000000000000..45ef99990c079 --- /dev/null +++ b/Detectors/Raw/TFReaderDD/src/tf-reader-workflow.cxx @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include <string> +#include <bitset> +#include "TFReaderSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options; + options.push_back(ConfigParamSpec{"input-data", VariantType::String, "", {"input data (obligatory)"}}); + options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, "all", {"list of dectors"}}); + options.push_back(ConfigParamSpec{"raw-only-det", VariantType::String, "none", {"do not open non-raw channel for these detectors"}}); + options.push_back(ConfigParamSpec{"non-raw-only-det", VariantType::String, "none", {"do not open raw channel for these detectors"}}); + options.push_back(ConfigParamSpec{"max-tf", VariantType::Int, -1, {"max TF ID to process (<= 0 : infinite)"}}); + options.push_back(ConfigParamSpec{"loop", VariantType::Int, 0, {"loop N times (-1 = infinite)"}}); + options.push_back(ConfigParamSpec{"delay", VariantType::Float, 0.f, {"delay in seconds between consecutive TFs sending"}}); + options.push_back(ConfigParamSpec{"copy-cmd", VariantType::String, "XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst", {"copy command for remote files"}}); + options.push_back(ConfigParamSpec{"tf-file-regex", VariantType::String, ".+\\.tf$", {"regex string to identify TF files"}}); + options.push_back(ConfigParamSpec{"remote-regex", VariantType::String, "^/eos/aliceo2/.+", {"regex string to identify remote files"}}); + options.push_back(ConfigParamSpec{"max-cached-tf", VariantType::Int, 3, {"max TFs to cache in memory"}}); + options.push_back(ConfigParamSpec{"max-cached-files", VariantType::Int, 3, {"max TF files queued (copied for remote source)"}}); + options.push_back(ConfigParamSpec{"tf-reader-verbosity", VariantType::Int, 0, {"verbosity level (1 or 2: check RDH, print DH/DPH for 1st or all slices, >2 print RDH)"}}); + options.push_back(ConfigParamSpec{"raw-channel-config", VariantType::String, "", {"optional raw FMQ channel for non-DPL output"}}); + options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}); + // options for error-check suppression + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::rawdd::TFReaderInp rinp; + rinp.inpdata = configcontext.options().get<std::string>("input-data"); + rinp.maxLoops = configcontext.options().get<int>("loop"); + int n = configcontext.options().get<int>("max-tf"); + rinp.maxTFs = n > 0 ? n : 0x7fffffff; + rinp.detList = configcontext.options().get<std::string>("onlyDet"); + rinp.detListRawOnly = configcontext.options().get<std::string>("raw-only-det"); + rinp.detListNonRawOnly = configcontext.options().get<std::string>("non-raw-only-det"); + rinp.rawChannelConfig = configcontext.options().get<std::string>("raw-channel-config"); + rinp.delay_us = uint64_t(1e6 * configcontext.options().get<float>("delay")); // delay in microseconds + rinp.verbosity = configcontext.options().get<int>("tf-reader-verbosity"); + rinp.maxTFCache = std::max(1, configcontext.options().get<int>("max-cached-tf")); + rinp.maxFileCache = std::max(1, configcontext.options().get<int>("max-cached-files")); + rinp.copyCmd = configcontext.options().get<std::string>("copy-cmd"); + rinp.tffileRegex = configcontext.options().get<std::string>("tf-file-regex"); + rinp.remoteRegex = configcontext.options().get<std::string>("remote-regex"); + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + WorkflowSpec specs; + specs.emplace_back(o2::rawdd::getTFReaderSpec(rinp)); + return specs; +} diff --git a/Detectors/Raw/include/DetectorsRaw/HBFUtils.h b/Detectors/Raw/include/DetectorsRaw/HBFUtils.h index 6bfc6c097509d..013c84a80a1b5 100644 --- a/Detectors/Raw/include/DetectorsRaw/HBFUtils.h +++ b/Detectors/Raw/include/DetectorsRaw/HBFUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,14 +28,14 @@ namespace raw { /* In the MC->Raw conversion we have to make sure that - 1) The HB and TF starts are in sync for all detectors regardless on time (bc/orbir) + 1) The HB and TF starts are in sync for all detectors regardless on time (0/orbit) distribution of its signal. 2) All HBF and TF (RAWDataHeaders with corresponding HB and TF trigger flags) are present in the emulated raw data, even if some of them had no data in particular detector. - + The HBFUtils class provides tools for interaction record -> HBF conversion and sampling of IRs for which the HBF RDH should be added to the raw data from the CRU. - + See testHBFUtils.cxx for the outline of generating HBF frames for simulated data. */ @@ -42,8 +43,7 @@ namespace raw struct HBFUtils : public o2::conf::ConfigurableParamHelper<HBFUtils> { using IR = o2::InteractionRecord; - - IR getFirstIR() const { return {bcFirst, orbitFirst}; } + IR getFirstIR() const { return {0, orbitFirst}; } int getNOrbitsPerTF() const { return nHBFPerTF; } @@ -69,6 +69,9 @@ struct HBFUtils : public o2::conf::ConfigurableParamHelper<HBFUtils> { ///< get 1st IR of the TF corresponding to provided interaction record IR getFirstIRofTF(const IR& rec) const { return getIRTF(getTF(rec)); } + ///< get 1st IR of TF corresponding to the 1st sampled orbit (in MC) + IR getFirstSampledTFIR() const { return getFirstIRofTF({0, orbitFirstSampled}); } + ///< get TF and HB (abs) for this IR std::pair<int, int> getTFandHB(const IR& rec) const { @@ -85,8 +88,8 @@ struct HBFUtils : public o2::conf::ConfigurableParamHelper<HBFUtils> { void updateRDH(H& rdh, const IR& rec, bool setHBTF = true) const; /*//------------------------------------------------------------------------------------- - Fill provided vector (cleaned) by interaction records (bc/orbit) for HBFs, considering - BCs between interaction records "fromIR" and "toIR" (inclusive). + Fill provided vector (cleaned) by interaction records (bc/orbit) for HBFs, considering + BCs between interaction records "fromIR" and "toIR" (inclusive). This method provides the IRs for RDHs to add obligatory for the MC->raw conversion, in order to avoid missing HBFs (or even TFs) Typical use case: assume we are converting to RAW data the digits corresponding to triggers @@ -123,9 +126,14 @@ struct HBFUtils : public o2::conf::ConfigurableParamHelper<HBFUtils> { void print() const { printKeyValues(true); } - int nHBFPerTF = 1 + 0xff; // number of orbits per BC - uint16_t bcFirst = 0; ///< BC of 1st TF - uint32_t orbitFirst = 0; ///< orbit of 1st TF + void checkConsistency() const; + + int nHBFPerTF = 256; ///< number of orbits per BC + uint32_t orbitFirst = 0; ///< orbit of 1st TF of the run + + // used for MC + uint32_t orbitFirstSampled = 0; ///< 1st orbit sampled in the MC + uint32_t maxNOrbits = 0xffffffff; ///< max number of orbits to accept, used in digit->raw conversion O2ParamDef(HBFUtils, "HBFUtils"); }; @@ -139,10 +147,10 @@ void HBFUtils::updateRDH(H& rdh, const IR& rec, bool setHBTF) const if (setHBTF) { // need to set the HBF IR and HB / TF trigger flags auto tfhb = getTFandHBinTF(rec); - RDHUtils::setHeartBeatBC(rdh, bcFirst); + RDHUtils::setHeartBeatBC(rdh, 0); RDHUtils::setHeartBeatOrbit(rdh, rec.orbit); - if (rec.bc == bcFirst) { // if we are starting new HB, set the HB trigger flag + if (rec.bc == 0) { // if we are starting new HB, set the HB trigger flag auto trg = RDHUtils::getTriggerType(rdh) | (o2::trigger::ORBIT | o2::trigger::HB); if (tfhb.second == 0) { // if we are starting new TF, set the TF trigger flag trg |= o2::trigger::TF; diff --git a/Detectors/Raw/include/DetectorsRaw/HBFUtilsInitializer.h b/Detectors/Raw/include/DetectorsRaw/HBFUtilsInitializer.h new file mode 100644 index 0000000000000..70cb8ff9f3164 --- /dev/null +++ b/Detectors/Raw/include/DetectorsRaw/HBFUtilsInitializer.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// @brief Aux.class initialize HBFUtils +// @author ruben.shahoyan@cern.ch + +#ifndef _O2_HBFUTILS_INITIALIZER_ +#define _O2_HBFUTILS_INITIALIZER_ + +#include <vector> + +namespace o2 +{ + +namespace framework +{ +class ConfigContext; +class DataProcessorSpec; +class ConfigParamSpec; +using WorkflowSpec = std::vector<DataProcessorSpec>; +} // namespace framework + +namespace raw +{ + +struct HBFUtilsInitializer { + static constexpr char HBFConfOpt[] = "hbfutils-config"; + + HBFUtilsInitializer(const o2::framework::ConfigContext& configcontext, o2::framework::WorkflowSpec& wf); + + static void addConfigOption(std::vector<o2::framework::ConfigParamSpec>& opts); +}; + +} // namespace raw +} // namespace o2 + +#endif diff --git a/Detectors/Raw/include/DetectorsRaw/RDHUtils.h b/Detectors/Raw/include/DetectorsRaw/RDHUtils.h index 181ce7c5aca5c..34ef8ae22d622 100644 --- a/Detectors/Raw/include/DetectorsRaw/RDHUtils.h +++ b/Detectors/Raw/include/DetectorsRaw/RDHUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ #include "GPUCommonRtypes.h" #include "Headers/RAWDataHeader.h" #include "Headers/RDHAny.h" - +#include "GPUCommonTypeTraits.h" #if !defined(GPUCA_GPUCODE) #include "CommonDataFormat/InteractionRecord.h" #endif @@ -35,7 +36,7 @@ using LinkSubSpec_t = uint32_t; struct RDHUtils { // disable is the type is a pointer -#define NOTPTR(T) typename std::enable_if<!std::is_pointer<T>::value>::type* = 0 +#define NOTPTR(T) typename std::enable_if<!std::is_pointer<GPUgeneric() T>::value>::type* = 0 // dereference SRC pointer as DST type reference #define TOREF(DST, SRC) *reinterpret_cast<DST*>(SRC) // dereference SRC pointer as DST type const reference @@ -692,7 +693,8 @@ struct RDHUtils { private: static uint32_t fletcher32(const uint16_t* data, int len); #if defined(GPUCA_GPUCODE_DEVICE) || defined(GPUCA_STANDALONE) - GPUhdi() static void processError(int v, const char* field) + template <typename T> + GPUhdi() static void processError(int v, const T* field) { } #else diff --git a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h index 90b4e769a8656..1f6c5a463c154 100644 --- a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h +++ b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,6 +35,23 @@ namespace raw using IR = o2::InteractionRecord; +struct ReaderInp { + std::string inifile{}; + std::string rawChannelConfig{}; + std::string dropTF{}; + size_t spSize = 1024L * 1024L; + size_t bufferSize = 1024L * 1024L; + int loop = 1; + uint32_t delay_us = 0; + uint32_t errMap = 0xffffffff; + uint32_t minTF = 0; + uint32_t maxTF = 0xffffffff; + bool partPerSP = true; + bool cache = false; + bool autodetectTF0 = false; + bool preferCalcTF = false; +}; + class RawFileReader { using LinkSpec_t = uint64_t; // = (origin<<32) | LinkSubSpec @@ -52,6 +70,8 @@ class RawFileReader ErrWrongNumberOfTF, ErrHBFJump, ErrNoSuperPageForTF, + ErrNoSOX, + ErrMismatchTF, NErrorsDefined }; @@ -61,15 +81,17 @@ class RawFileReader static constexpr std::string_view ErrNames[] = { // long names for error codes - "Wrong RDH.packetCounter increment", // ErrWrongPacketCounterIncrement - "Wrong RDH.pageCnt increment", // ErrWrongPageCounterIncrement - "RDH.stop set of 1st HBF page", // ErrHBFStopOnFirstPage - "New HBF starts w/o closing old one", // ErrHBFNoStop - "Data does not start with TF/HBF", // ErrWrongFirstPage - "Number of HBFs per TF not as expected", // ErrWrongHBFsPerTF - "Number of TFs is less than expected", // ErrWrongNumberOfTF - "Wrong HBF orbit increment", // ErrHBFJump - "TF does not start by new superpage" // ErrNoSuperPageForTF + "Wrong RDH.packetCounter increment", // ErrWrongPacketCounterIncrement + "Wrong RDH.pageCnt increment", // ErrWrongPageCounterIncrement + "RDH.stop set of 1st HBF page", // ErrHBFStopOnFirstPage + "New HBF starts w/o closing old one", // ErrHBFNoStop + "Data does not start with TF/HBF", // ErrWrongFirstPage + "Number of HBFs per TF not as expected", // ErrWrongHBFsPerTF + "Number of TFs is less than expected", // ErrWrongNumberOfTF + "Wrong HBF orbit increment", // ErrHBFJump + "TF does not start by new superpage", // ErrNoSuperPageForTF + "No SOX found on 1st page", // ErrNoSOX + "Mismatch between flagged and calculated new TF start" // ErrMismatchTF }; static constexpr std::string_view ErrNamesShort[] = { // short names for error codes @@ -81,7 +103,9 @@ class RawFileReader "hbf-per-tf", // ErrWrongHBFsPerTF "tf-per-link", // ErrWrongNumberOfTF "hbf-jump", // ErrHBFJump - "no-spage-for-tf" // ErrNoSuperPageForTF + "no-spage-for-tf", // ErrNoSuperPageForTF + "no-sox", // ErrNoSOX + "tf-start-mismatch" // ErrMismatchTF }; static constexpr bool ErrCheckDefaults[] = { true, // ErrWrongPacketCounterIncrement @@ -92,7 +116,9 @@ class RawFileReader true, // ErrWrongHBFsPerTF true, // ErrWrongNumberOfTF true, // ErrHBFJump - false // ErrNoSuperPageForTF + false, // ErrNoSuperPageForTF + true, // ErrNoSOX + true, // ErrMismatchTF }; //================================================================================ @@ -115,12 +141,12 @@ class RawFileReader StartHB = 0x1 << 1, StartSP = 0x1 << 2, EndHB = 0x1 << 3 }; - size_t offset = 0; //! where data of the block starts - uint32_t size = 0; //! block size - uint32_t tfID = 0; //! tf counter (from 0) - IR ir = 0; //! ir starting the block - uint16_t fileID = 0; //! file id where the block is located - uint8_t flags = 0; //! different flags + size_t offset = 0; //! where data of the block starts + uint32_t size = 0; //! block size + uint32_t tfID = 0; //! tf counter (from 0) + IR ir = 0; //! ir starting the block + uint16_t fileID = 0; //! file id where the block is located + uint8_t flags = 0; //! different flags std::unique_ptr<char[]> dataCache; //! optional cache for fast access LinkBlock() = default; LinkBlock(int fid, size_t offs) : offset(offs), fileID(fid) {} @@ -138,7 +164,8 @@ class RawFileReader //===================================================================================== struct LinkData { - RDHAny rdhl; //! RDH with the running info of the last RDH seen + RDHAny rdhl; //! RDH with the running info of the last RDH seen + o2::InteractionRecord irOfSOX{}; LinkSpec_t spec = 0; //! Link subspec augmented by its origin LinkSubSpec_t subspec = 0; //! subspec according to DataDistribution uint32_t nTimeFrames = 0; //! @@ -150,7 +177,6 @@ class RawFileReader o2::header::DataOrigin origin = o2::header::gDataOriginInvalid; //! o2::header::DataDescription description = o2::header::gDataDescriptionInvalid; //! - std::string fairMQChannel{}; //! name of the fairMQ channel for the output int nErrors = 0; //! std::vector<LinkBlock> blocks; //! std::vector<std::pair<int, uint32_t>> tfStartBlock; @@ -242,10 +268,13 @@ class RawFileReader o2::header::DataDescription getDefaultDataSpecification() const { return mDefDataDescription; } ReadoutCardType getDefaultReadoutCardType() const { return mDefCardType; } - void imposeFirstTF(uint32_t orbit, uint16_t bc); + void imposeFirstTF(uint32_t orbit); void setTFAutodetect(FirstTFDetection v) { mFirstTFAutodetect = v; } + void setPreferCalculatedTFStart(bool v) { mPreferCalculatedTFStart = v; } FirstTFDetection getTFAutodetect() const { return mFirstTFAutodetect; } + void setIROfSOX(const o2::InteractionRecord& ir); + static o2::header::DataOrigin getDataOrigin(const std::string& ors); static o2::header::DataDescription getDataDescription(const std::string& ors); static InputsMap parseInput(const std::string& confUri); @@ -260,38 +289,36 @@ class RawFileReader static constexpr o2::header::DataOrigin DEFDataOrigin = o2::header::gDataOriginFLP; static constexpr o2::header::DataDescription DEFDataDescription = o2::header::gDataDescriptionRawData; static constexpr ReadoutCardType DEFCardType = CRU; - o2::header::DataOrigin mDefDataOrigin = DEFDataOrigin; //! o2::header::DataDescription mDefDataDescription = DEFDataDescription; //! ReadoutCardType mDefCardType = CRU; //! - - std::vector<std::string> mFileNames; //! input file names - std::vector<FILE*> mFiles; //! input file handlers - std::vector<std::unique_ptr<char[]>> mFileBuffers; //! buffers for input files - std::vector<OrigDescCard> mDataSpecs; //! data origin and description for every input file + readout card type + std::vector<std::string> mFileNames; //! input file names + std::vector<FILE*> mFiles; //! input file handlers + std::vector<std::unique_ptr<char[]>> mFileBuffers; //! buffers for input files + std::vector<OrigDescCard> mDataSpecs; //! data origin and description for every input file + readout card type bool mInitDone = false; bool mEmpty = true; - std::unordered_map<LinkSpec_t, int> mLinkEntries; //! mapping between RDH specs and link entry in the mLinksData - std::vector<LinkData> mLinksData; //! info on links data in the files - std::vector<int> mOrderedIDs; //! links entries ordered in Specs - uint32_t mMaxTFToRead = 0xffffffff; //! max TFs to process - uint32_t mNTimeFrames = 0; //! total number of time frames - uint32_t mNextTF2Read = 0; //! next TF to read - uint32_t mOrbitMin = 0xffffffff; //! lowest orbit seen by any link - uint32_t mOrbitMax = 0; //! highest orbit seen by any link - size_t mBufferSize = 5 * 1024UL; //! size of the buffer for files reading - int mNominalSPageSize = 0x1 << 20; //! expected super-page size in B - int mCurrentFileID = 0; //! current file being processed - long int mPosInFile = 0; //! current position in the file - bool mMultiLinkFile = false; //! was > than 1 link seen in the file? - bool mCacheData = false; //! cache data to block after 1st scan (may require excessive memory, use with care) - uint32_t mCheckErrors = 0; //! mask for errors to check + std::unordered_map<LinkSpec_t, int> mLinkEntries; //! mapping between RDH specs and link entry in the mLinksData + std::vector<LinkData> mLinksData; //! info on links data in the files + std::vector<int> mOrderedIDs; //! links entries ordered in Specs + uint32_t mMaxTFToRead = 0xffffffff; //! max TFs to process + uint32_t mNTimeFrames = 0; //! total number of time frames + uint32_t mNextTF2Read = 0; //! next TF to read + uint32_t mOrbitMin = 0xffffffff; //! lowest orbit seen by any link + uint32_t mOrbitMax = 0; //! highest orbit seen by any link + size_t mBufferSize = 5 * 1024UL; //! size of the buffer for files reading + int mNominalSPageSize = 0x1 << 20; //! expected super-page size in B + int mCurrentFileID = 0; //! current file being processed + long int mPosInFile = 0; //! current position in the file + bool mMultiLinkFile = false; //! was > than 1 link seen in the file? + bool mCacheData = false; //! cache data to block after 1st scan (may require excessive memory, use with care) + uint32_t mCheckErrors = 0; //! mask for errors to check FirstTFDetection mFirstTFAutodetect = FirstTFDetection::Disabled; //! + bool mPreferCalculatedTFStart = false; //! prefer TFstart calculated via HBFUtils int mVerbosity = 0; //! ClassDefNV(RawFileReader, 1); }; - } // namespace raw } // namespace o2 diff --git a/Detectors/Raw/include/DetectorsRaw/RawFileWriter.h b/Detectors/Raw/include/DetectorsRaw/RawFileWriter.h index 89de7974f4b6f..4617a77696d71 100644 --- a/Detectors/Raw/include/DetectorsRaw/RawFileWriter.h +++ b/Detectors/Raw/include/DetectorsRaw/RawFileWriter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -70,6 +71,7 @@ class RawFileWriter struct PayloadCache { bool preformatted = false; uint32_t trigger = 0; + uint32_t detField = 0; std::vector<char> payload; ClassDefNV(PayloadCache, 1); }; @@ -78,22 +80,22 @@ class RawFileWriter /// Single GBT link helper struct LinkData { static constexpr int MarginToFlush = 10 * sizeof(RDHAny); // flush superpage if free space left <= this margin - RDHAny rdhCopy; // RDH with the running info of the last RDH seen - IR updateIR; // IR at which new HBF needs to be created - int lastRDHoffset = -1; // position of last RDH in the link buffer - bool startOfRun = true; // to signal if this is the 1st HBF of the run or not - uint8_t packetCounter = 0; // running counter - uint16_t pageCnt = 0; // running counter - LinkSubSpec_t subspec = 0; // subspec according to DataDistribution - int counter = 0; //RSREM + RDHAny rdhCopy; // RDH with the running info of the last RDH seen + IR updateIR; // IR at which new HBF needs to be created + int lastRDHoffset = -1; // position of last RDH in the link buffer + bool startOfRun = true; // to signal if this is the 1st HBF of the run or not + uint8_t packetCounter = 0; // running counter + uint16_t pageCnt = 0; // running counter + LinkSubSpec_t subspec = 0; // subspec according to DataDistribution + bool discardData = false; // discard data if true (e.g. desired max IR reached) // size_t nTFWritten = 0; // number of TFs written size_t nRDHWritten = 0; // number of RDHs written size_t nBytesWritten = 0; // number of bytes written // - std::string fileName{}; // file name associated with this link - std::vector<char> buffer; // buffer to accumulate superpage data - RawFileWriter* writer = nullptr; // pointer on the parent writer + std::string fileName{}; // file name associated with this link + std::vector<char> buffer; // buffer to accumulate superpage data + RawFileWriter* writer = nullptr; // pointer on the parent writer PayloadCache cacheBuffer; // used for caching in case of async. data input std::unique_ptr<TTree> cacheTree; // tree to store the cache @@ -106,7 +108,7 @@ class RawFileWriter LinkData& operator=(const LinkData& src); // due to the mutex... void close(const IR& ir); void print() const; - void addData(const IR& ir, const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0); + void addData(const IR& ir, const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0, uint32_t detField = 0); RDHAny* getLastRDH() { return lastRDHoffset < 0 ? nullptr : reinterpret_cast<RDHAny*>(&buffer[lastRDHoffset]); } int getCurrentPageSize() const { return lastRDHoffset < 0 ? -1 : int(buffer.size()) - lastRDHoffset; } // check if we are at the beginning of new page @@ -114,13 +116,14 @@ class RawFileWriter std::string describe() const; protected: + void addDataInternal(const IR& ir, const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0, uint32_t detField = 0, bool checkEmpty = true); void openHBFPage(const RDHAny& rdh, uint32_t trigger = 0); void addHBFPage(bool stop = false); - void closeHBFPage() { addHBFPage(true); } + void closeHBFPage(); void flushSuperPage(bool keepLastPage = false); void fillEmptyHBHs(const IR& ir, bool dataAdded); void addPreformattedCRUPage(const gsl::span<char> data); - void cacheData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger = 0); + void cacheData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger = 0, uint32_t detField = 0); /// expand buffer by positive increment and return old size size_t expandBufferBy(size_t by) @@ -131,20 +134,7 @@ class RawFileWriter } /// append to the end of the buffer and return the point where appended to - size_t pushBack(const char* ptr, size_t sz, bool keepLastOnFlash = true) - { - if (!sz) { - return buffer.size(); - } - nBytesWritten += sz; - // do we have a space one this superpage? - if ((writer->mSuperPageSize - int(buffer.size())) < 0) { // need to flush - flushSuperPage(keepLastOnFlash); - } - auto offs = expandBufferBy(sz); - memmove(&buffer[offs], ptr, sz); - return offs; - } + size_t pushBack(const char* ptr, size_t sz, bool keepLastOnFlash = true); /// add RDH to buffer. In case this requires flushing of the superpage, do not keep the previous page size_t pushBack(const RDHAny& rdh) @@ -152,8 +142,27 @@ class RawFileWriter nRDHWritten++; return pushBack(reinterpret_cast<const char*>(&rdh), sizeof(RDHAny), false); } - }; + //===================================================================================== + // If addData was called with given IR for at least 1 link, then it should be called for all links, even it with empty payload + // This structure will check if detector has dared to do this + struct DetLazinessCheck { + IR ir{}; + bool preformatted = false; + uint32_t trigger = 0; + uint32_t detField = 0; + size_t irSeen = 0; + size_t completeCount = 0; + std::unordered_map<LinkSubSpec_t, bool> linksDone; // links for which addData was called + void acknowledge(LinkSubSpec_t s, const IR& _ir, bool _preformatted, uint32_t _trigger, uint32_t _detField); + void completeLinks(RawFileWriter* wr, const IR& _ir); + void clear() + { + linksDone.clear(); + ir.clear(); + } + }; + //===================================================================================== RawFileWriter(o2::header::DataOrigin origin = o2::header::gDataOriginInvalid, bool cru = true) : mOrigin(origin) @@ -164,6 +173,7 @@ class RawFileWriter } ~RawFileWriter(); void useCaching(); + void doLazinessCheck(bool v) { mDoLazinessCheck = v; } void writeConfFile(std::string_view origin = "FLP", std::string_view description = "RAWDATA", std::string_view cfgname = "raw.cfg", bool fullPath = true) const; void close(); @@ -195,7 +205,7 @@ class RawFileWriter } void addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR& ir, - const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0); + const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0, uint32_t detField = 0); template <typename H> void addData(const H& rdh, const IR& ir, const gsl::span<char> data, bool preformatted = false, uint32_t trigger = 0) @@ -208,7 +218,7 @@ class RawFileWriter void setTriggeredReadout() { mROMode = Triggered; - setDontFillEmptyHBF(true); + setDontFillEmptyHBF(!mCRUDetector); } void setContinuousReadout(bool v) { @@ -240,6 +250,8 @@ class RawFileWriter return it->first; } + OutputFile& getOutputFileForLink(const LinkData& lnk) { return mFName2File[lnk.fileName]; } + int getSuperPageSize() const { return mSuperPageSize; } void setSuperPageSize(int nbytes); @@ -390,13 +402,13 @@ class RawFileWriter int mVerbosity = 0; o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; int mUseRDHVersion = RDHUtils::getVersion<o2::header::RAWDataHeader>(); // by default, use default version - int mSuperPageSize = 1024 * 1024; // super page size - bool mStartTFOnNewSPage = true; // every TF must start on a new SPage - bool mDontFillEmptyHBF = false; // skipp adding empty HBFs (uness it must have TF flag) - bool mAddSeparateHBFStopPage = true; // HBF stop is added on a separate CRU page - bool mUseRDHStop = true; // detector uses STOP in RDH - bool mCRUDetector = true; // Detector readout via CRU ( RORC if false) - bool mApplyCarryOverToLastPage = false; // call CarryOver method also for last chunk and overwrite modified trailer + int mSuperPageSize = 1024 * 1024; // super page size + bool mStartTFOnNewSPage = true; // every TF must start on a new SPage + bool mDontFillEmptyHBF = false; // skipp adding empty HBFs (uness it must have TF flag) + bool mAddSeparateHBFStopPage = true; // HBF stop is added on a separate CRU page + bool mUseRDHStop = true; // detector uses STOP in RDH + bool mCRUDetector = true; // Detector readout via CRU ( RORC if false) + bool mApplyCarryOverToLastPage = false; // call CarryOver method also for last chunk and overwrite modified trailer //>> caching -------------- bool mCachingStage = false; // signal that current data should be cached @@ -409,8 +421,18 @@ class RawFileWriter TStopwatch mTimer; RoMode_t mROMode = NotSet; IR mFirstIRAdded; // 1st IR seen + DetLazinessCheck mDetLazyCheck{}; + bool mDoLazinessCheck = true; + ClassDefNV(RawFileWriter, 1); -}; // namespace raw +}; + +/** Ensure (i.e. create if needed) directory + * @param outDirName : output path to be asserted + * + * Log a FATAL if the directory does not exist and can not be created + */ +void assertOutputDirectory(std::string_view outDirName); } // namespace raw } // namespace o2 diff --git a/Detectors/Raw/include/DetectorsRaw/SimpleRawReader.h b/Detectors/Raw/include/DetectorsRaw/SimpleRawReader.h deleted file mode 100644 index 91904e44da2bd..0000000000000 --- a/Detectors/Raw/include/DetectorsRaw/SimpleRawReader.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SimpleRawReader.h -/// \brief Definition of the simple reader for non-DPL tests -#ifndef ALICEO2_ITSMFT_SIMPLERAWREADER_H_ -#define ALICEO2_ITSMFT_SIMPLERAWREADER_H_ - -#include "DetectorsRaw/RawFileReader.h" - -namespace o2 -{ -namespace framework -{ -class InputRecord; -} -namespace raw -{ -struct SimpleSTF; - -/// Class to read raw data from the file and to create a STF-like structure which can be navigated using e.g. DPLRawParser -/// but which can be used in the standalone code not using exchange over the DPL. -/// Simple reader for non-DPL tests -class SimpleRawReader -{ - - public: - SimpleRawReader(); - SimpleRawReader(const std::string& cfg, bool tfPerMessage = false, int loop = 1); - ~SimpleRawReader(); - void init(); - bool loadNextTF(); - int getNLinks() const { return mReader ? mReader->getNLinks() : 0; } - bool isDone() const { return mDone; } - void setTFPerMessage(bool v = true) { mHBFPerMessage = !v; } - void setConfigFileName(const std::string& fn) { mCFGName = fn; } - void printStat() const; - - SimpleSTF* getSimpleSTF(); - o2::framework::InputRecord* getInputRecord(); - - private: - int mLoop = 0; // once last TF reached, loop while mLoop>=0 - bool mHBFPerMessage = true; // true: send TF as multipart of HBFs, false: single message per TF - bool mDone = false; - std::string mCFGName{}; - std::unique_ptr<o2::raw::RawFileReader> mReader; - size_t mLoopsDone = 0, mSentSize = 0, mSentMessages = 0, mTFIDaccum = 0; // statistics - - std::unique_ptr<SimpleSTF> mSTF; - - ClassDefNV(SimpleRawReader, 1); -}; - -} // namespace itsmft -} // namespace o2 - -#endif diff --git a/Detectors/Raw/include/DetectorsRaw/SimpleSTF.h b/Detectors/Raw/include/DetectorsRaw/SimpleSTF.h deleted file mode 100644 index 8e8ffce695fcd..0000000000000 --- a/Detectors/Raw/include/DetectorsRaw/SimpleSTF.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SimpleSTF.h -/// \brief Mocked STF with InputRecord for standalone tests (improved version of Matthias' structure in the test_DPLRawParser) -#ifndef ALICEO2_ITSMFT_SIMPLESTF_H_ -#define ALICEO2_ITSMFT_SIMPLESTF_H_ - -#include <vector> -#include <memory> -#include <utility> -#include <gsl/span> -#include "Framework/InputRoute.h" -#include "Framework/InputRecord.h" - -namespace o2 -{ -namespace framework -{ -struct InputRoute; -class InputRecord; -} // namespace framework -namespace raw -{ -namespace o2f = o2::framework; - -struct SimpleSTF { - using PartsRef = std::vector<std::pair<int, int>>; - using Messages = std::vector<std::unique_ptr<std::vector<char>>>; - - SimpleSTF(std::vector<o2f::InputRoute>&& sch, PartsRef&& pref, Messages&& msg); - bool empty() const { return partsRef.size() == 0; } - int getNLinks() const { return partsRef.size(); } - int getNParts(int il) const { return il < getNLinks() ? partsRef[il].second : 0; } - const gsl::span<const char> getPart(int il, int part) const { return *messages[partsRef[il].first + (part << 1) + 1].get(); } - - std::vector<o2f::InputRoute> schema; - PartsRef partsRef; // i-th entry is the 1st entry and N parts of multipart for i-th channel in the messages - Messages messages; - o2f::InputRecord record; -}; - -} // namespace raw -} // namespace o2 - -#endif diff --git a/Detectors/Raw/src/DetectorsRawLinkDef.h b/Detectors/Raw/src/DetectorsRawLinkDef.h index e7459d6e89f18..8a420a1aa89af 100644 --- a/Detectors/Raw/src/DetectorsRawLinkDef.h +++ b/Detectors/Raw/src/DetectorsRawLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,6 @@ #pragma link C++ class o2::raw::RawFileWriter + ; #pragma link C++ class o2::raw::RawFileWriter::PayloadCache + ; #pragma link C++ class o2::raw::RawFileWriter::LinkData + ; -#pragma link C++ class o2::raw::SimpleRawReader + ; #pragma link C++ class o2::raw::RDHUtils + ; #pragma link C++ class o2::raw::HBFUtils + ; diff --git a/Detectors/Raw/src/HBFUtils.cxx b/Detectors/Raw/src/HBFUtils.cxx index e9f8978451570..848966b557d6e 100644 --- a/Detectors/Raw/src/HBFUtils.cxx +++ b/Detectors/Raw/src/HBFUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,7 @@ uint32_t HBFUtils::getHBF(const IR& rec) const auto diff = rec.differenceInBC(getFirstIR()); if (diff < 0) { LOG(ERROR) << "IR " << rec.bc << '/' << rec.orbit << " is ahead of the reference IR " - << bcFirst << '/' << orbitFirst; + << "0/" << orbitFirst; throw std::runtime_error("Requested IR is ahead of the reference IR"); } return diff / o2::constants::lhc::LHCMaxBunches; @@ -39,7 +40,7 @@ int HBFUtils::fillHBIRvector(std::vector<IR>& dst, const IR& fromIR, const IR& t // BCs between interaction records "fromIR" and "toIR" (inclusive). dst.clear(); int hb0 = getHBF(fromIR), hb1 = getHBF(toIR); - if (fromIR.bc != bcFirst) { // unless we are just starting the HBF of fromIR, it was already counted + if (fromIR.bc != 0) { // unless we are just starting the HBF of fromIR, it was already counted hb0++; } for (int ihb = hb0; ihb <= hb1; ihb++) { @@ -47,3 +48,13 @@ int HBFUtils::fillHBIRvector(std::vector<IR>& dst, const IR& fromIR, const IR& t } return dst.size(); } + +//_________________________________________________ +void HBFUtils::checkConsistency() const +{ + if (orbitFirstSampled < orbitFirst) { + auto s = fmt::format("1st sampled orbit ({}) < 1st orbit of run ({})", orbitFirstSampled, orbitFirst); + LOG(ERROR) << s; + throw std::runtime_error(s); + } +} \ No newline at end of file diff --git a/Detectors/Raw/src/HBFUtilsInitializer.cxx b/Detectors/Raw/src/HBFUtilsInitializer.cxx new file mode 100644 index 0000000000000..4a8676558d3fd --- /dev/null +++ b/Detectors/Raw/src/HBFUtilsInitializer.cxx @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// @brief Aux.class initialize HBFUtils +// @author ruben.shahoyan@cern.ch + +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DetectorsRaw/HBFUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Framework/ConfigContext.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConfigParamsHelper.h" +#include "Framework/Logger.h" + +using namespace o2::raw; +namespace o2f = o2::framework; + +/// If the workflow has devices w/o inputs, we assume that these are data readers in root-file based workflow. +/// In this case this class will configure these devices DataHeader.firstTForbit generator to provide orbit according to HBFUtil setings +/// In case the configcontext has relevant option, the HBFUtils will be beforehand updated from the file indicated by this option. +/// (only those fields of HBFUtils which were not modified before, e.g. by ConfigurableParam::updateFromString) + +HBFUtilsInitializer::HBFUtilsInitializer(const o2f::ConfigContext& configcontext, o2f::WorkflowSpec& wf) +{ + auto updateHBFUtils = [&configcontext]() { + static bool done = false; + if (!done) { + bool helpasked = configcontext.helpOnCommandLine(); // if help is asked, don't take for granted that the ini file is there, don't produce an error if it is not! + std::string conf = configcontext.options().isSet(HBFConfOpt) ? configcontext.options().get<std::string>(HBFConfOpt) : ""; + if (!conf.empty() && conf != "none" && !(helpasked && !o2::utils::Str::pathExists(conf))) { + o2::conf::ConfigurableParam::updateFromFile(conf, "HBFUtils", true); // update only those values which were not touched yet (provenance == kCODE) + } + const auto& hbfu = o2::raw::HBFUtils::Instance(); + hbfu.checkConsistency(); + done = true; + } + }; + + const auto& hbfu = o2::raw::HBFUtils::Instance(); + for (auto& spec : wf) { + if (spec.inputs.empty()) { + updateHBFUtils(); + o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{"orbit-offset-enumeration", o2f::VariantType::Int64, int64_t(hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit), {"1st injected orbit"}}); + o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{"orbit-multiplier-enumeration", o2f::VariantType::Int64, int64_t(hbfu.nHBFPerTF), {"orbits/TF"}}); + } + } +} + +void HBFUtilsInitializer::addConfigOption(std::vector<o2f::ConfigParamSpec>& opts) +{ + o2f::ConfigParamsHelper::addOptionIfMissing(opts, o2f::ConfigParamSpec{HBFConfOpt, o2f::VariantType::String, std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE), {"configKeyValues file for HBFUtils (or none)"}}); +} diff --git a/Detectors/Raw/src/RDHUtils.cxx b/Detectors/Raw/src/RDHUtils.cxx index c00f793c0b4f1..2eef9f3ea19e2 100644 --- a/Detectors/Raw/src/RDHUtils.cxx +++ b/Detectors/Raw/src/RDHUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Raw/src/RawFileReader.cxx b/Detectors/Raw/src/RawFileReader.cxx index c2d6889771fa2..bb4be40e0abbb 100644 --- a/Detectors/Raw/src/RawFileReader.cxx +++ b/Detectors/Raw/src/RawFileReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -354,24 +355,50 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage ok = false; nErrors++; } - + auto ir = RDHUtils::getTriggerIR(rdh); auto pageCnt = RDHUtils::getPageCounter(rdh); + if (pageCnt == 0) { - if (cruDetector) { - auto triggerType = RDHUtils::getTriggerType(rdh); - newTF = (triggerType & o2::trigger::TF); - newHB = (triggerType & (o2::trigger::ORBIT | o2::trigger::HB)) == (o2::trigger::ORBIT | o2::trigger::HB); + auto triggerType = RDHUtils::getTriggerType(rdh); + if (!nCRUPages) { // 1st page, expect SOX if (triggerType & o2::trigger::SOC) { continuousRO = true; + irOfSOX = ir; } else if (triggerType & o2::trigger::SOT) { continuousRO = false; + irOfSOX = ir; + } else { + if (reader->mCheckErrors & (0x1 << ErrNoSOX)) { + LOG(ERROR) << ErrNames[ErrNoSOX]; + ok = false; + nErrors++; + } + } + if (!irOfSOX.isDummy() && reader->getTFAutodetect() == FirstTFDetection::Pending) { + reader->imposeFirstTF(irOfSOX.orbit); + } + } + auto newTFCalc = blocks.empty() || HBU.getTF(blocks.back().ir) < HBU.getTF(ir); + if (cruDetector) { + newTF = (triggerType & o2::trigger::TF); + newHB = (triggerType & (o2::trigger::ORBIT | o2::trigger::HB)) == (o2::trigger::ORBIT | o2::trigger::HB); + if (newTFCalc != newTF && (reader->mCheckErrors & (0x1 << ErrMismatchTF))) { + LOG(ERROR) << ErrNames[ErrMismatchTF]; + ok = false; + nErrors++; + } + if (reader->mPreferCalculatedTFStart) { + newTF = newTFCalc; + if (newTF) { + newHB = true; + } } } else { newHB = true; // in RORC detectors treat each trigger as a HBF - if (blocks.empty() || HBU.getTF(blocks.back().ir) < HBU.getTF(RDHUtils::getTriggerIR(rdh))) { + if (newTFCalc) { newTF = true; + // continuousRO = false; } - continuousRO = false; } } else if (reader->mCheckErrors & (0x1 << ErrWrongPageCounterIncrement)) { // check increasing pageCnt @@ -456,7 +483,7 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage if (newTF) { if (reader->getTFAutodetect() == FirstTFDetection::Pending) { // impose first TF if (cruDetector) { - reader->imposeFirstTF(hbIR.orbit, hbIR.bc); + reader->imposeFirstTF(hbIR.orbit); bl.tfID = HBU.getTF(hbIR); // update } else { throw std::runtime_error("HBFUtil first orbit/bc autodetection cannot be done with first link from CRORC detector"); @@ -687,7 +714,7 @@ bool RawFileReader::init() } } std::sort(mOrderedIDs.begin(), mOrderedIDs.end(), - [& links = mLinksData](int a, int b) { return links[a].spec < links[b].spec; }); + [&links = mLinksData](int a, int b) { return links[a].spec < links[b].spec; }); size_t maxSP = 0, maxTF = 0; @@ -875,14 +902,13 @@ RawFileReader::InputsMap RawFileReader::parseInput(const std::string& confUri) return entries; } -void RawFileReader::imposeFirstTF(uint32_t orbit, uint16_t bc) +void RawFileReader::imposeFirstTF(uint32_t orbit) { if (mFirstTFAutodetect != FirstTFDetection::Pending) { throw std::runtime_error("reader was not expecting imposing first TF"); } auto& hbu = o2::raw::HBFUtils::Instance(); o2::raw::HBFUtils::setValue("HBFUtils", "orbitFirst", orbit); - o2::raw::HBFUtils::setValue("HBFUtils", "bcFirst", bc); LOG(INFO) << "Imposed data-driven TF start"; mFirstTFAutodetect = FirstTFDetection::Done; hbu.printKeyValues(); diff --git a/Detectors/Raw/src/RawFileReaderWorkflow.cxx b/Detectors/Raw/src/RawFileReaderWorkflow.cxx index 8fc58670ae1a2..f6dc24546cb3b 100644 --- a/Detectors/Raw/src/RawFileReaderWorkflow.cxx +++ b/Detectors/Raw/src/RawFileReaderWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include "DetectorsRaw/RawFileReader.h" #include "DetectorsRaw/RDHUtils.h" #include "DetectorsRaw/HBFUtils.h" - +#include "DetectorsCommonDataFormats/DetID.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" @@ -36,6 +37,7 @@ #include <cctype> #include <string> #include <climits> +#include <regex> using namespace o2::raw; @@ -45,216 +47,286 @@ namespace o2h = o2::header; class RawReaderSpecs : public o2f::Task { public: - explicit RawReaderSpecs(const std::string& config, int loop = 1, uint32_t delay_us = 0, - uint32_t errmap = 0xffffffff, uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, bool autodetectTF0 = false, - size_t spSize = 1024L * 1024L, size_t buffSize = 5 * 1024UL, - const std::string& rawChannelName = "") - : mLoop(loop < 0 ? INT_MAX : (loop < 1 ? 1 : loop)), mDelayUSec(delay_us), mMinTFID(minTF), mMaxTFID(maxTF), mPartPerSP(partPerSP), mReader(std::make_unique<o2::raw::RawFileReader>(config, 0, buffSize)), mRawChannelName(rawChannelName) + static constexpr o2h::DataDescription gDataDescSubTimeFrame{"DISTSUBTIMEFRAME"}; + struct STFHeader { // fake header to mimic DD SubTimeFrame::Header sent with DISTSUBTIMEFRAME message + uint64_t mId = uint64_t(-1); + uint32_t mFirstOrbit = uint32_t(-1); + std::uint32_t mRunNumber = 0; + }; + explicit RawReaderSpecs(const ReaderInp& rinp); + void init(o2f::InitContext& ic) final; + void run(o2f::ProcessingContext& ctx) final; + + uint32_t getMinTFID() const { return mMinTFID; } + uint32_t getMaxTFID() const { return mMaxTFID; } + void setMinMaxTFID(uint32_t mn, uint32_t mx) { - mReader->setCheckErrors(errmap); - mReader->setMaxTFToRead(maxTF); - mReader->setNominalSPageSize(spSize); - mReader->setCacheData(cache); - mReader->setTFAutodetect(autodetectTF0 ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); - LOG(INFO) << "Will preprocess files with buffer size of " << buffSize << " bytes"; - LOG(INFO) << "Number of loops over whole data requested: " << mLoop; - for (int i = NTimers; i--;) { - mTimer[i].Stop(); - mTimer[i].Reset(); - } + mMinTFID = mn; + mMaxTFID = mx >= mn ? mx : mn; } - void init(o2f::InitContext& ic) final - { - assert(mReader); - mTimer[TimerInit].Start(); - mReader->init(); - mTimer[TimerInit].Stop(); - if (mMaxTFID >= mReader->getNTimeFrames()) { - mMaxTFID = mReader->getNTimeFrames() ? mReader->getNTimeFrames() - 1 : 0; - } + private: + void processDropTF(const std::string& drops); + + int mLoop = 0; // once last TF reached, loop while mLoop>=0 + uint32_t mTFCounter = 0; // TFId accumulator (accounts for looping) + uint32_t mDelayUSec = 0; // Delay in microseconds between TFs + uint32_t mMinTFID = 0; // 1st TF to extract + uint32_t mMaxTFID = 0xffffffff; // last TF to extrct + size_t mLoopsDone = 0; + size_t mSentSize = 0; + size_t mSentMessages = 0; + bool mPartPerSP = true; // fill part per superpage + std::string mRawChannelName = ""; // name of optional non-DPL channel + std::unique_ptr<o2::raw::RawFileReader> mReader; // matching engine + std::unordered_map<std::string, std::pair<int, int>> mDropTFMap; // allows to drop certain fraction of TFs + enum TimerIDs { TimerInit, + TimerTotal, + TimerIO, + NTimers }; + static constexpr std::string_view TimerName[] = {"Init", "Total", "IO"}; + TStopwatch mTimer[NTimers]; +}; + +//___________________________________________________________ +RawReaderSpecs::RawReaderSpecs(const ReaderInp& rinp) + : mLoop(rinp.loop < 0 ? INT_MAX : (rinp.loop < 1 ? 1 : rinp.loop)), mDelayUSec(rinp.delay_us), mMinTFID(rinp.minTF), mMaxTFID(rinp.maxTF), mPartPerSP(rinp.partPerSP), mReader(std::make_unique<o2::raw::RawFileReader>(rinp.inifile, 0, rinp.bufferSize)), mRawChannelName(rinp.rawChannelConfig) +{ + mReader->setCheckErrors(rinp.errMap); + mReader->setMaxTFToRead(rinp.maxTF); + mReader->setNominalSPageSize(rinp.spSize); + mReader->setCacheData(rinp.cache); + mReader->setTFAutodetect(rinp.autodetectTF0 ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); + mReader->setPreferCalculatedTFStart(rinp.preferCalcTF); + LOG(INFO) << "Will preprocess files with buffer size of " << rinp.bufferSize << " bytes"; + LOG(INFO) << "Number of loops over whole data requested: " << mLoop; + for (int i = NTimers; i--;) { + mTimer[i].Stop(); + mTimer[i].Reset(); } + processDropTF(rinp.dropTF); +} - void run(o2f::ProcessingContext& ctx) final - { - assert(mReader); - if (mDone) { - return; +//___________________________________________________________ +void RawReaderSpecs::processDropTF(const std::string& dropTF) +{ + static const std::regex delimDet(";"); + if (dropTF.empty() || dropTF == "none") { + return; + } + std::sregex_token_iterator iter(dropTF.begin(), dropTF.end(), delimDet, -1), end; + for (; iter != end; ++iter) { + std::string sdet = iter->str(); + if (sdet.length() < 5 || sdet[3] != ',') { + throw std::runtime_error(fmt::format("Wrong dropTF argument {} in {}", sdet, dropTF)); } - auto tTotStart = mTimer[TimerTotal].CpuTime(), tIOStart = mTimer[TimerIO].CpuTime(); - mTimer[TimerTotal].Start(false); - auto device = ctx.services().get<o2f::RawDeviceService>().device(); - assert(device); - - auto findOutputChannel = [&ctx, this](RawFileReader::LinkData& link, size_t timeslice) { - if (!this->mRawChannelName.empty()) { - link.fairMQChannel = this->mRawChannelName; - return true; - } + std::string detName = sdet.substr(0, 3); + o2::detectors::DetID det(detName.c_str()); // make sure this is a valid detector + std::string sdetArg = sdet.substr(4, sdet.length()); + int modV = 0, rej = 0, posrej = sdetArg.find(','); + if (posrej != std::string::npos) { + modV = std::stoi(sdetArg.substr(0, posrej)); + rej = std::stoi(sdetArg.substr(++posrej, sdetArg.length())); + } else { + modV = std::stoi(sdetArg); + } + if (modV < 1 || rej < 0 || rej >= modV) { + throw std::runtime_error(fmt::format("Wrong dropTF argument {}, 1st number must be > than 2nd", sdet)); + } + mDropTFMap[detName] = {modV, rej}; + LOG(INFO) << " Will drop TF for detector " << detName << " if (TF_ID%" << modV << ")==" << rej; + } +} + +//___________________________________________________________ +void RawReaderSpecs::init(o2f::InitContext& ic) +{ + assert(mReader); + mTimer[TimerInit].Start(); + mReader->init(); + mTimer[TimerInit].Stop(); + if (mMaxTFID >= mReader->getNTimeFrames()) { + mMaxTFID = mReader->getNTimeFrames() ? mReader->getNTimeFrames() - 1 : 0; + } +} + +//___________________________________________________________ +void RawReaderSpecs::run(o2f::ProcessingContext& ctx) +{ + assert(mReader); + auto tTotStart = mTimer[TimerTotal].CpuTime(), tIOStart = mTimer[TimerIO].CpuTime(); + mTimer[TimerTotal].Start(false); + auto device = ctx.services().get<o2f::RawDeviceService>().device(); + assert(device); + + auto findOutputChannel = [&ctx, this](o2h::DataHeader& h) { + if (!this->mRawChannelName.empty()) { + return std::string{this->mRawChannelName}; + } else { auto outputRoutes = ctx.services().get<o2f::RawDeviceService>().spec().outputs; for (auto& oroute : outputRoutes) { LOG(DEBUG) << "comparing with matcher to route " << oroute.matcher << " TSlice:" << oroute.timeslice; - if (o2f::DataSpecUtils::match(oroute.matcher, link.origin, link.description, link.subspec) && ((timeslice % oroute.maxTimeslices) == oroute.timeslice)) { - link.fairMQChannel = oroute.channel; + if (o2f::DataSpecUtils::match(oroute.matcher, h.dataOrigin, h.dataDescription, h.subSpecification) && ((h.tfCounter % oroute.maxTimeslices) == oroute.timeslice)) { LOG(DEBUG) << "picking the route:" << o2f::DataSpecUtils::describe(oroute.matcher) << " channel " << oroute.channel; - return true; + return std::string{oroute.channel}; } } - LOGF(ERROR, "Failed to find output channel for %s/%s/0x%x", link.origin.as<std::string>(), - link.description.as<std::string>(), link.subspec); - return false; - }; - - // clean-up before reading next TF - auto tfID = mReader->getNextTFToRead(); - int nlinks = mReader->getNLinks(); - - std::unordered_map<std::string, std::unique_ptr<FairMQParts>> messagesPerRoute; - - if (tfID > mMaxTFID) { - if (!mReader->isEmpty() && --mLoop) { - mLoopsDone++; - tfID = 0; - LOG(INFO) << "Starting new loop " << mLoopsDone << " from the beginning of data"; - } else { - mTimer[TimerTotal].Stop(); - LOGF(INFO, "Finished: payload of %zu bytes in %zu messages sent for %d TFs", mSentSize, mSentMessages, mTFCounter); - for (int i = 0; i < NTimers; i++) { - LOGF(INFO, "Timing for %15s: Cpu: %.3e Real: %.3e s in %d slots", TimerName[i], mTimer[i].CpuTime(), mTimer[i].RealTime(), mTimer[i].Counter() - 1); - } - ctx.services().get<o2f::ControlService>().endOfStream(); - ctx.services().get<o2f::ControlService>().readyToQuit(o2f::QuitRequest::Me); - mDone = true; - return; - } } - - if (tfID < mMinTFID) { - tfID = mMinTFID; + LOGP(ERROR, "Failed to find output channel for {}/{}/{} @ timeslice {}", h.dataOrigin.str, h.dataDescription.str, h.subSpecification, h.tfCounter); + return std::string{}; + }; + + size_t tfNParts = 0, tfSize = 0; + std::unordered_map<std::string, std::unique_ptr<FairMQParts>> messagesPerRoute; + + auto addPart = [&messagesPerRoute, &tfNParts, &tfSize](FairMQMessagePtr hd, FairMQMessagePtr pl, const std::string& fairMQChannel) { + FairMQParts* parts = nullptr; + parts = messagesPerRoute[fairMQChannel].get(); // FairMQParts* + if (!parts) { + messagesPerRoute[fairMQChannel] = std::make_unique<FairMQParts>(); + parts = messagesPerRoute[fairMQChannel].get(); } - mReader->setNextTFToRead(tfID); - std::vector<RawFileReader::PartStat> partsSP; - const auto& hbfU = HBFUtils::Instance(); - - // read next time frame - size_t tfNParts = 0, tfSize = 0; - LOG(INFO) << "Reading TF#" << mTFCounter << " (" << tfID << " at iteration " << mLoopsDone << ')'; - o2::header::Stack dummyStack{o2h::DataHeader{}, o2::framework::DataProcessingHeader{0}}; // dummy stack to just to get stack size - auto hstackSize = dummyStack.size(); - - for (int il = 0; il < nlinks; il++) { - auto& link = mReader->getLink(il); - if (!link.rewindToTF(tfID)) { - continue; // this link has no data for wanted TF - } - if (!findOutputChannel(link, mTFCounter)) { // no output channel - continue; - } - - o2h::DataHeader hdrTmpl(link.description, link.origin, link.subspec); // template with 0 size - int nParts = mPartPerSP ? link.getNextTFSuperPagesStat(partsSP) : link.getNHBFinTF(); - hdrTmpl.payloadSerializationMethod = o2h::gSerializationMethodNone; - hdrTmpl.splitPayloadParts = nParts; - - while (hdrTmpl.splitPayloadIndex < hdrTmpl.splitPayloadParts) { - - tfSize += hdrTmpl.payloadSize = mPartPerSP ? partsSP[hdrTmpl.splitPayloadIndex].size : link.getNextHBFSize(); - auto fmqFactory = device->GetChannel(link.fairMQChannel, 0).Transport(); - auto hdMessage = fmqFactory->CreateMessage(hstackSize, fair::mq::Alignment{64}); - auto plMessage = fmqFactory->CreateMessage(hdrTmpl.payloadSize, fair::mq::Alignment{64}); - mTimer[TimerIO].Start(false); - auto bread = mPartPerSP ? link.readNextSuperPage(reinterpret_cast<char*>(plMessage->GetData()), &partsSP[hdrTmpl.splitPayloadIndex]) : link.readNextHBF(reinterpret_cast<char*>(plMessage->GetData())); - if (bread != hdrTmpl.payloadSize) { - LOG(ERROR) << "Link " << il << " read " << bread << " bytes instead of " << hdrTmpl.payloadSize - << " expected in TF=" << mTFCounter << " part=" << hdrTmpl.splitPayloadIndex; - } - mTimer[TimerIO].Stop(); - // check if the RDH to send corresponds to expected orbit - if (hdrTmpl.splitPayloadIndex == 0) { - auto ir = o2::raw::RDHUtils::getHeartBeatIR(plMessage->GetData()); - auto tfid = hbfU.getTF(ir); - hdrTmpl.firstTForbit = hbfU.getIRTF(tfid).orbit; // will be picked for the - hdrTmpl.tfCounter = mTFCounter; // following parts - // reinterpret_cast<o2::header::DataHeader*>(hdMessage->GetData())->firstTForbit = hdrTmpl.firstTForbit; // hack to fix already filled headers - // reinterpret_cast<o2::header::DataHeader*>(hdMessage->GetData())->tfCounter = mTFCounter; // at the moment don't use it - } - o2::header::Stack headerStack{hdrTmpl, o2::framework::DataProcessingHeader{mTFCounter}}; - memcpy(hdMessage->GetData(), headerStack.data(), headerStack.size()); - - FairMQParts* parts = nullptr; - parts = messagesPerRoute[link.fairMQChannel].get(); // FairMQParts* - if (!parts) { - messagesPerRoute[link.fairMQChannel] = std::make_unique<FairMQParts>(); - parts = messagesPerRoute[link.fairMQChannel].get(); - } - parts->AddPart(std::move(hdMessage)); - parts->AddPart(std::move(plMessage)); - hdrTmpl.splitPayloadIndex++; // prepare for next - tfNParts++; + tfSize += pl->GetSize(); + tfNParts++; + parts->AddPart(std::move(hd)); + parts->AddPart(std::move(pl)); + }; + + // clean-up before reading next TF + auto tfID = mReader->getNextTFToRead(); + int nlinks = mReader->getNLinks(); + + if (tfID > mMaxTFID) { + if (!mReader->isEmpty() && --mLoop) { + mLoopsDone++; + tfID = 0; + LOG(INFO) << "Starting new loop " << mLoopsDone << " from the beginning of data"; + } else { + mTimer[TimerTotal].Stop(); + LOGF(INFO, "Finished: payload of %zu bytes in %zu messages sent for %d TFs", mSentSize, mSentMessages, mTFCounter); + for (int i = 0; i < NTimers; i++) { + LOGF(INFO, "Timing for %15s: Cpu: %.3e Real: %.3e s in %d slots", TimerName[i], mTimer[i].CpuTime(), mTimer[i].RealTime(), mTimer[i].Counter() - 1); } - LOGF(DEBUG, "Added %d parts for TF#%d(%d in iteration %d) of %s/%s/0x%u", hdrTmpl.splitPayloadParts, mTFCounter, tfID, - mLoopsDone, link.origin.as<std::string>(), link.description.as<std::string>(), link.subspec); + ctx.services().get<o2f::ControlService>().endOfStream(); + ctx.services().get<o2f::ControlService>().readyToQuit(o2f::QuitRequest::Me); + return; } + } - if (mTFCounter) { // delay sending - usleep(mDelayUSec); + if (tfID < mMinTFID) { + tfID = mMinTFID; + } + mReader->setNextTFToRead(tfID); + std::vector<RawFileReader::PartStat> partsSP; + const auto& hbfU = HBFUtils::Instance(); + + // read next time frame + LOG(INFO) << "Reading TF#" << mTFCounter << " (" << tfID << " at iteration " << mLoopsDone << ')'; + o2::header::Stack dummyStack{o2h::DataHeader{}, o2::framework::DataProcessingHeader{0}}; // dummy stack to just to get stack size + auto hstackSize = dummyStack.size(); + + uint32_t firstOrbit = 0; + for (int il = 0; il < nlinks; il++) { + auto& link = mReader->getLink(il); + + if (!mDropTFMap.empty()) { // some TFs should be dropped + auto res = mDropTFMap.find(link.origin.str); + if (res != mDropTFMap.end() && (mTFCounter % res->second.first) == res->second.second) { + LOG(INFO) << "Droppint " << mTFCounter << " for " << link.origin.str << "/" << link.description.str << "/" << link.subspec; + continue; // drop the data + } } - for (auto& msgIt : messagesPerRoute) { - LOG(INFO) << "Sending " << msgIt.second->Size() / 2 << " parts to channel " << msgIt.first; - device->Send(*msgIt.second.get(), msgIt.first); + if (!link.rewindToTF(tfID)) { + continue; // this link has no data for wanted TF } - mTimer[TimerTotal].Stop(); - LOGF(INFO, "Sent payload of %zu bytes in %zu parts in %zu messages for TF %d | Timing (total/IO): %.3e / %.3e", tfSize, tfNParts, - messagesPerRoute.size(), mTFCounter, mTimer[TimerTotal].CpuTime() - tTotStart, mTimer[TimerIO].CpuTime() - tIOStart); + o2h::DataHeader hdrTmpl(link.description, link.origin, link.subspec); // template with 0 size + int nParts = mPartPerSP ? link.getNextTFSuperPagesStat(partsSP) : link.getNHBFinTF(); + hdrTmpl.payloadSerializationMethod = o2h::gSerializationMethodNone; + hdrTmpl.splitPayloadParts = nParts; + hdrTmpl.tfCounter = mTFCounter; + + const auto fmqChannel = findOutputChannel(hdrTmpl); + if (fmqChannel.empty()) { // no output channel + continue; + } - mSentSize += tfSize; - mSentMessages += tfNParts; + auto fmqFactory = device->GetChannel(fmqChannel, 0).Transport(); + while (hdrTmpl.splitPayloadIndex < hdrTmpl.splitPayloadParts) { + hdrTmpl.payloadSize = mPartPerSP ? partsSP[hdrTmpl.splitPayloadIndex].size : link.getNextHBFSize(); + auto hdMessage = fmqFactory->CreateMessage(hstackSize, fair::mq::Alignment{64}); + auto plMessage = fmqFactory->CreateMessage(hdrTmpl.payloadSize, fair::mq::Alignment{64}); + mTimer[TimerIO].Start(false); + auto bread = mPartPerSP ? link.readNextSuperPage(reinterpret_cast<char*>(plMessage->GetData()), &partsSP[hdrTmpl.splitPayloadIndex]) : link.readNextHBF(reinterpret_cast<char*>(plMessage->GetData())); + if (bread != hdrTmpl.payloadSize) { + LOG(ERROR) << "Link " << il << " read " << bread << " bytes instead of " << hdrTmpl.payloadSize + << " expected in TF=" << mTFCounter << " part=" << hdrTmpl.splitPayloadIndex; + } + mTimer[TimerIO].Stop(); + // check if the RDH to send corresponds to expected orbit + if (hdrTmpl.splitPayloadIndex == 0) { + auto ir = o2::raw::RDHUtils::getHeartBeatIR(plMessage->GetData()); + auto tfid = hbfU.getTF(ir); + firstOrbit = hdrTmpl.firstTForbit = hbfU.getIRTF(tfid).orbit; // will be picked for the following parts + } + o2::header::Stack headerStack{hdrTmpl, o2::framework::DataProcessingHeader{mTFCounter}}; + memcpy(hdMessage->GetData(), headerStack.data(), headerStack.size()); + hdrTmpl.splitPayloadIndex++; // prepare for next - mReader->setNextTFToRead(++tfID); - ++mTFCounter; + addPart(std::move(hdMessage), std::move(plMessage), fmqChannel); + } + LOGF(DEBUG, "Added %d parts for TF#%d(%d in iteration %d) of %s/%s/0x%u", hdrTmpl.splitPayloadParts, mTFCounter, tfID, + mLoopsDone, link.origin.as<std::string>(), link.description.as<std::string>(), link.subspec); } - uint32_t getMinTFID() const { return mMinTFID; } - uint32_t getMaxTFID() const { return mMaxTFID; } - void setMinMaxTFID(uint32_t mn, uint32_t mx) + // send sTF acknowledge message { - mMinTFID = mn; - mMaxTFID = mx >= mn ? mx : mn; + STFHeader stfHeader{mTFCounter, firstOrbit, 0}; + o2::header::DataHeader stfDistDataHeader(gDataDescSubTimeFrame, o2::header::gDataOriginFLP, 0, sizeof(STFHeader), 0, 1); + stfDistDataHeader.payloadSerializationMethod = o2h::gSerializationMethodNone; + stfDistDataHeader.firstTForbit = stfHeader.mFirstOrbit; + stfDistDataHeader.tfCounter = mTFCounter; + const auto fmqChannel = findOutputChannel(stfDistDataHeader); + if (!fmqChannel.empty()) { // no output channel + auto fmqFactory = device->GetChannel(fmqChannel, 0).Transport(); + o2::header::Stack headerStackSTF{stfDistDataHeader, o2::framework::DataProcessingHeader{mTFCounter}}; + auto hdMessageSTF = fmqFactory->CreateMessage(hstackSize, fair::mq::Alignment{64}); + auto plMessageSTF = fmqFactory->CreateMessage(stfDistDataHeader.payloadSize, fair::mq::Alignment{64}); + memcpy(hdMessageSTF->GetData(), headerStackSTF.data(), headerStackSTF.size()); + memcpy(plMessageSTF->GetData(), &stfHeader, sizeof(STFHeader)); + addPart(std::move(hdMessageSTF), std::move(plMessageSTF), fmqChannel); + } } - private: - int mLoop = 0; // once last TF reached, loop while mLoop>=0 - uint32_t mTFCounter = 0; // TFId accumulator (accounts for looping) - uint32_t mDelayUSec = 0; // Delay in microseconds between TFs - uint32_t mMinTFID = 0; // 1st TF to extract - uint32_t mMaxTFID = 0xffffffff; // last TF to extrct - size_t mLoopsDone = 0; - size_t mSentSize = 0; - size_t mSentMessages = 0; - bool mPartPerSP = true; // fill part per superpage - bool mDone = false; // processing is over or not - std::string mRawChannelName = ""; // name of optional non-DPL channel - std::unique_ptr<o2::raw::RawFileReader> mReader; // matching engine + if (mTFCounter) { // delay sending + usleep(mDelayUSec); + } + for (auto& msgIt : messagesPerRoute) { + LOG(INFO) << "Sending " << msgIt.second->Size() / 2 << " parts to channel " << msgIt.first; + device->Send(*msgIt.second.get(), msgIt.first); + } + mTimer[TimerTotal].Stop(); - enum TimerIDs { TimerInit, - TimerTotal, - TimerIO, - NTimers }; - static constexpr std::string_view TimerName[] = {"Init", "Total", "IO"}; - TStopwatch mTimer[NTimers]; -}; + LOGF(INFO, "Sent payload of %zu bytes in %zu parts in %zu messages for TF %d | Timing (total/IO): %.3e / %.3e", tfSize, tfNParts, + messagesPerRoute.size(), mTFCounter, mTimer[TimerTotal].CpuTime() - tTotStart, mTimer[TimerIO].CpuTime() - tIOStart); + + mSentSize += tfSize; + mSentMessages += tfNParts; + + mReader->setNextTFToRead(++tfID); + ++mTFCounter; +} -o2f::DataProcessorSpec getReaderSpec(std::string config, int loop, uint32_t delay_us, uint32_t errmap, - uint32_t minTF, uint32_t maxTF, bool partPerSP, bool cache, bool autodetectTF0, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) +//_________________________________________________________ +o2f::DataProcessorSpec getReaderSpec(ReaderInp rinp) { // check which inputs are present in files to read o2f::DataProcessorSpec spec; spec.name = "raw-file-reader"; std::string rawChannelName = ""; - if (rawChannelConfig.empty()) { - if (!config.empty()) { - auto conf = o2::raw::RawFileReader::parseInput(config); + if (rinp.rawChannelConfig.empty()) { + if (!rinp.inifile.empty()) { + auto conf = o2::raw::RawFileReader::parseInput(rinp.inifile); for (const auto& entry : conf) { const auto& ordescard = entry.first; if (!entry.second.empty()) { // origin and decription for files to process @@ -262,30 +334,31 @@ o2f::DataProcessorSpec getReaderSpec(std::string config, int loop, uint32_t dela } } } + // add output for DISTSUBTIMEFRAME + spec.outputs.emplace_back(o2f::OutputSpec{{"stfDist"}, o2::header::gDataOriginFLP, RawReaderSpecs::gDataDescSubTimeFrame, 0}); } else { - auto nameStart = rawChannelConfig.find("name="); + auto nameStart = rinp.rawChannelConfig.find("name="); if (nameStart == std::string::npos) { throw std::runtime_error("raw channel name is not provided"); } nameStart += strlen("name="); - auto nameEnd = rawChannelConfig.find(",", nameStart + 1); + auto nameEnd = rinp.rawChannelConfig.find(",", nameStart + 1); if (nameEnd == std::string::npos) { - nameEnd = rawChannelConfig.size(); + nameEnd = rinp.rawChannelConfig.size(); } - rawChannelName = rawChannelConfig.substr(nameStart, nameEnd - nameStart); - spec.options = {o2f::ConfigParamSpec{"channel-config", o2f::VariantType::String, rawChannelConfig, {"Out-of-band channel config"}}}; - LOG(INFO) << "Will send output to non-DPL channel " << rawChannelConfig; + spec.options = {o2f::ConfigParamSpec{"channel-config", o2f::VariantType::String, rinp.rawChannelConfig, {"Out-of-band channel config"}}}; + rinp.rawChannelConfig = rinp.rawChannelConfig.substr(nameStart, nameEnd - nameStart); + LOG(INFO) << "Will send output to non-DPL channel " << rinp.rawChannelConfig; } - spec.algorithm = o2f::adaptFromTask<RawReaderSpecs>(config, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelName); + spec.algorithm = o2f::adaptFromTask<RawReaderSpecs>(rinp); return spec; } -o2f::WorkflowSpec o2::raw::getRawFileReaderWorkflow(std::string inifile, int loop, uint32_t delay_us, uint32_t errmap, uint32_t minTF, uint32_t maxTF, - bool partPerSP, bool cache, bool autodetectTF0, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) +o2f::WorkflowSpec o2::raw::getRawFileReaderWorkflow(ReaderInp& rinp) { o2f::WorkflowSpec specs; - specs.emplace_back(getReaderSpec(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelConfig)); + specs.emplace_back(getReaderSpec(rinp)); return specs; } diff --git a/Detectors/Raw/src/RawFileReaderWorkflow.h b/Detectors/Raw/src/RawFileReaderWorkflow.h index c209fd088f573..aefee0f3bf3b4 100644 --- a/Detectors/Raw/src/RawFileReaderWorkflow.h +++ b/Detectors/Raw/src/RawFileReaderWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,11 +21,9 @@ namespace o2 { namespace raw { +struct ReaderInp; -framework::WorkflowSpec getRawFileReaderWorkflow(std::string inifile, int loop = 1, uint32_t delay_us = 0, uint32_t errMap = 0xffffffff, - uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, bool autodetectTF0 = false, - size_t spSize = 1024L * 1024L, size_t bufferSize = 1024L * 1024L, - const std::string& rawChannelConfig = ""); +framework::WorkflowSpec getRawFileReaderWorkflow(ReaderInp& rinp); } // namespace raw } // namespace o2 diff --git a/Detectors/Raw/src/RawFileWriter.cxx b/Detectors/Raw/src/RawFileWriter.cxx index b8a60d55ab682..0d84d6a02a72e 100644 --- a/Detectors/Raw/src/RawFileWriter.cxx +++ b/Detectors/Raw/src/RawFileWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #include "DetectorsRaw/HBFUtils.h" #include "CommonConstants/Triggers.h" #include "Framework/Logger.h" +#include <filesystem> using namespace o2::raw; using IR = o2::InteractionRecord; @@ -39,13 +41,21 @@ void RawFileWriter::close() if (mFName2File.empty()) { return; } - if (mCachingStage) { fillFromCache(); } + if (mDoLazinessCheck) { + IR newIR = mDetLazyCheck.ir; + mDetLazyCheck.completeLinks(this, ++newIR); // make sure that all links for previously called IR got their addData call + mDoLazinessCheck = false; + } if (!mFirstIRAdded.isDummy()) { // flushing and completing the last HBF makes sense only if data was added. auto irmax = getIRMax(); + // for CRU detectors link.updateIR and hence the irmax points on the last IR with data + 1 orbit + if (isCRUDetector()) { + irmax.orbit -= 1; + } for (auto& lnk : mSSpec2Link) { lnk.second.close(irmax); lnk.second.print(); @@ -59,6 +69,10 @@ void RawFileWriter::close() flh.second.handler = nullptr; } mFName2File.clear(); + if (mDetLazyCheck.completeCount) { + LOG(WARNING) << "RawFileWriter forced " << mDetLazyCheck.completeCount << " dummy addData calls in " + << mDetLazyCheck.irSeen << " IRs for links which did not receive data"; + } mTimer.Stop(); mTimer.Print(); } @@ -72,7 +86,11 @@ void RawFileWriter::fillFromCache() for (const auto& entry : cache.second) { auto& link = getLinkWithSubSpec(entry.first); link.cacheTree->GetEntry(entry.second); - link.addData(cache.first, link.cacheBuffer.payload, link.cacheBuffer.preformatted, link.cacheBuffer.trigger); + if (mDoLazinessCheck) { + mDetLazyCheck.completeLinks(this, cache.first); // make sure that all links for previously called IR got their addData call + mDetLazyCheck.acknowledge(link.subspec, cache.first, link.cacheBuffer.preformatted, link.cacheBuffer.trigger, link.cacheBuffer.detField); + } + link.addData(cache.first, link.cacheBuffer.payload, link.cacheBuffer.preformatted, link.cacheBuffer.trigger, link.cacheBuffer.detField); } } mCacheFile->cd(); @@ -156,23 +174,38 @@ RawFileWriter::LinkData& RawFileWriter::registerLink(uint16_t fee, uint16_t cru, } //_____________________________________________________________________ -void RawFileWriter::addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger) +void RawFileWriter::addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger, uint32_t detField) { // add payload to relevant links + auto sspec = RDHUtils::getSubSpec(cru, lnk, endpoint, feeid); + auto& link = getLinkWithSubSpec(sspec); + if (mVerbosity > 10) { + LOGP(INFO, "addData for {} on IR BCid:{} Orbit: {}, payload: {}, preformatted: {}, trigger: {}, detField: {}", link.describe(), ir.bc, ir.orbit, data.size(), preformatted, trigger, detField); + } if (isCRUDetector() && (data.size() % RDHUtils::GBTWord)) { LOG(ERROR) << "provided payload size " << data.size() << " is not multiple of GBT word size"; throw std::runtime_error("payload size is not mutiple of GBT word size"); } - auto sspec = RDHUtils::getSubSpec(cru, lnk, endpoint, feeid); - auto& link = getLinkWithSubSpec(sspec); if (ir < mHBFUtils.getFirstIR()) { LOG(WARNING) << "provided " << ir << " precedes first TF " << mHBFUtils.getFirstIR() << " | discarding data for " << link.describe(); return; } + if (link.discardData || ir.orbit - mHBFUtils.orbitFirst >= mHBFUtils.maxNOrbits) { + if (!link.discardData) { + link.discardData = true; + LOG(INFO) << "Orbit " << ir.orbit << ": max. allowed orbit " << mHBFUtils.orbitFirst + mHBFUtils.maxNOrbits - 1 << " exceeded, " << link.describe() << " will discard further data"; + } + return; + } if (ir < mFirstIRAdded) { + mHBFUtils.checkConsistency(); // done only once mFirstIRAdded = ir; } - link.addData(ir, data, preformatted, trigger); + if (mDoLazinessCheck && !mCachingStage) { + mDetLazyCheck.completeLinks(this, ir); // make sure that all links for previously called IR got their addData call + mDetLazyCheck.acknowledge(sspec, ir, preformatted, trigger, detField); + } + link.addData(ir, data, preformatted, trigger, detField); } //_____________________________________________________________________ @@ -223,7 +256,7 @@ void RawFileWriter::writeConfFile(std::string_view origin, std::string_view desc cfgfile << "dataOrigin = " << origin << std::endl; cfgfile << "dataDescription = " << description << std::endl; cfgfile << "readoutCard = " << (isCRUDetector() ? "CRU" : "RORC") << std::endl; - cfgfile << "filePath = " << (fullPath ? o2::base::NameConf::getFullPath(getOutputFileName(i)) : getOutputFileName(i)) << std::endl; + cfgfile << "filePath = " << (fullPath ? o2::utils::Str::getFullPath(getOutputFileName(i)) : getOutputFileName(i)) << std::endl; } cfgfile.close(); } @@ -239,7 +272,7 @@ void RawFileWriter::useCaching() if (mCacheFile) { return; // already done } - auto cachename = o2::utils::concat_string("_rawWriter_cache_", mOrigin.str, ::getpid(), ".root"); + auto cachename = o2::utils::Str::concat_string("_rawWriter_cache_", mOrigin.str, ::getpid(), ".root"); mCacheFile.reset(TFile::Open(cachename.c_str(), "recreate")); LOG(INFO) << "Switched caching ON"; } @@ -247,17 +280,18 @@ void RawFileWriter::useCaching() //=================================================================================== //___________________________________________________________________________________ -void RawFileWriter::LinkData::cacheData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger) +void RawFileWriter::LinkData::cacheData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger, uint32_t detField) { // cache data to temporary tree std::lock_guard<std::mutex> lock(writer->mCacheFileMtx); if (!cacheTree) { writer->mCacheFile->cd(); - cacheTree = std::make_unique<TTree>(o2::utils::concat_string("lnk", std::to_string(subspec)).c_str(), "cache"); + cacheTree = std::make_unique<TTree>(o2::utils::Str::concat_string("lnk", std::to_string(subspec)).c_str(), "cache"); cacheTree->Branch("cache", &cacheBuffer); } cacheBuffer.preformatted = preformatted; cacheBuffer.trigger = trigger; + cacheBuffer.detField = detField; cacheBuffer.payload.resize(data.size()); if (!data.empty()) { memcpy(cacheBuffer.payload.data(), data.data(), data.size()); @@ -268,14 +302,20 @@ void RawFileWriter::LinkData::cacheData(const IR& ir, const gsl::span<char> data } //___________________________________________________________________________________ -void RawFileWriter::LinkData::addData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger) +void RawFileWriter::LinkData::addData(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger, uint32_t detField) { - // add payload corresponding to IR - LOG(DEBUG) << "Adding " << data.size() << " bytes in IR " << ir << " to " << describe(); + // add payload corresponding to IR, locking access to this method std::lock_guard<std::mutex> lock(mtx); + addDataInternal(ir, data, preformatted, trigger, detField); +} +//___________________________________________________________________________________ +void RawFileWriter::LinkData::addDataInternal(const IR& ir, const gsl::span<char> data, bool preformatted, uint32_t trigger, uint32_t detField, bool checkEmpty) +{ + // add payload corresponding to IR + LOG(DEBUG) << "Adding " << data.size() << " bytes in IR " << ir << " to " << describe() << " checkEmpty=" << checkEmpty; if (writer->mCachingStage) { - cacheData(ir, data, preformatted, trigger); + cacheData(ir, data, preformatted, trigger, detField); return; } @@ -287,7 +327,7 @@ void RawFileWriter::LinkData::addData(const IR& ir, const gsl::span<char> data, } int dataSize = data.size(); - if (ir >= updateIR) { // new IR exceeds or equal IR of next HBF to open, insert missed HBFs if needed + if (ir >= updateIR && checkEmpty) { // new IR exceeds or equal IR of next HBF to open, insert missed HBFs if needed fillEmptyHBHs(ir, true); } // we are guaranteed to be under the valid RDH + possibly some data @@ -296,6 +336,10 @@ void RawFileWriter::LinkData::addData(const IR& ir, const gsl::span<char> data, auto& rdh = *getLastRDH(); RDHUtils::setTriggerType(rdh, RDHUtils::getTriggerType(rdh) | trigger); } + if (detField) { + auto& rdh = *getLastRDH(); + RDHUtils::setDetectorField(rdh, detField); + } if (!dataSize) { return; @@ -409,7 +453,7 @@ void RawFileWriter::LinkData::addPreformattedCRUPage(const gsl::span<char> data) throw std::runtime_error("preformatted payload exceeds max size"); } if (int(buffer.size()) - lastRDHoffset > sizeof(RDHAny)) { // we must start from empty page - addHBFPage(); // start new CRU page + addHBFPage(); // start new CRU page } pushBack(&data[0], data.size()); } @@ -425,16 +469,6 @@ void RawFileWriter::LinkData::addHBFPage(bool stop) // finalize last RDH auto& lastRDH = *getLastRDH(); int psize = getCurrentPageSize(); // set the size for the previous header RDH - bool emptyPage = psize == sizeof(RDHAny); - if (stop && emptyPage && writer->emptyHBFFunc) { // we are closing an empty page, does detector want to add something? - std::vector<char> emtyHBFFiller; // working space for optional empty HBF filler - writer->emptyHBFFunc(&lastRDH, emtyHBFFiller); - if (emtyHBFFiller.size()) { - LOG(DEBUG) << "Adding empty HBF filler of size " << emtyHBFFiller.size() << " for " << describe(); - pushBack(emtyHBFFiller.data(), emtyHBFFiller.size()); - psize += emtyHBFFiller.size(); - } - } RDHUtils::setOffsetToNext(lastRDH, psize); RDHUtils::setMemorySize(lastRDH, psize); @@ -461,7 +495,7 @@ void RawFileWriter::LinkData::addHBFPage(bool stop) std::vector<char> userData; int sz = sizeof(RDHAny); if (stop && writer->newRDHFunc) { // detector may want to write something in closing page - writer->newRDHFunc(&rdhCopy, emptyPage, userData); + writer->newRDHFunc(&rdhCopy, psize == sizeof(RDHAny), userData); sz += userData.size(); } RDHUtils::setOffsetToNext(rdhCopy, sz); @@ -484,19 +518,36 @@ void RawFileWriter::LinkData::addHBFPage(bool stop) // } +//___________________________________________________________________________________ +void RawFileWriter::LinkData::closeHBFPage() +{ + // close the HBF page, if it is empty and detector has a special treatment of empty pages + // invoke detector callback method + if (lastRDHoffset < 0) { + return; // no page was open + } + bool emptyPage = getCurrentPageSize() == sizeof(RDHAny); + if (emptyPage && writer->emptyHBFFunc) { // we are closing an empty page, does detector want to add something? + std::vector<char> emtyHBFFiller; // working space for optional empty HBF filler + const auto rdh = getLastRDH(); + writer->emptyHBFFunc(rdh, emtyHBFFiller); + if (!emtyHBFFiller.empty()) { + auto ir = RDHUtils::getTriggerIR(rdh); + LOG(DEBUG) << "Adding empty HBF filler of size " << emtyHBFFiller.size() << " for " << describe(); + addDataInternal(ir, emtyHBFFiller, false, 0, 0, false); // add filler w/o new check for empty HBF + } + } + addHBFPage(true); +} + //___________________________________________________________________________________ void RawFileWriter::LinkData::openHBFPage(const RDHAny& rdhn, uint32_t trigger) { /// create 1st page of the new HBF bool forceNewPage = false; - // for RORC detectors the TF flag is absent, instead the 1st trigger after the start of TF will define the 1st be interpreted as 1st TF - auto newTF_RORC = [this, &rdhn]() -> bool { - auto tfhbPrev = writer->mHBFUtils.getTFandHBinTF(this->updateIR.bc ? this->updateIR - 1 : this->updateIR); // updateIR was advanced by 1 BC wrt IR of the previous update - return this->writer->mHBFUtils.getTFandHBinTF(RDHUtils::getTriggerIR(rdhn)).first > tfhbPrev.first; // new TF_ID exceeds old one - }; - - if ((RDHUtils::getTriggerType(rdhn) & o2::trigger::TF) || (writer->isRORCDetector() && newTF_RORC())) { + if ((RDHUtils::getTriggerType(rdhn) & o2::trigger::TF) || + (writer->isRORCDetector() && writer->mHBFUtils.getTF(updateIR - 1) < writer->mHBFUtils.getTF(RDHUtils::getTriggerIR(rdhn)))) { if (writer->mVerbosity > -10) { LOGF(INFO, "Starting new TF for link FEEId 0x%04x", RDHUtils::getFEEID(rdhn)); } @@ -557,11 +608,7 @@ void RawFileWriter::LinkData::close(const IR& irf) return; // already closed } if (writer->isCRUDetector()) { // finalize last TF - auto irfin = irf; - if (irfin < updateIR) { - irfin = updateIR; - } - int tf = writer->mHBFUtils.getTF(irfin); + int tf = writer->mHBFUtils.getTF(irf); auto finalIR = writer->mHBFUtils.getIRTF(tf + 1) - 1; // last IR of the current TF fillEmptyHBHs(finalIR, false); } @@ -582,10 +629,10 @@ void RawFileWriter::LinkData::fillEmptyHBHs(const IR& ir, bool dataAdded) for (const auto& irdummy : irw) { if (writer->mDontFillEmptyHBF && writer->mHBFUtils.getTFandHBinTF(irdummy).second != 0 && - (!dataAdded || irdummy < ir)) { + (!dataAdded || irdummy.orbit < ir.orbit)) { // even if requested, we skip empty HBF filling only if // 1) we are not at the new TF start - // 2) method was called from addData and the current IR is the one for which it was called (then it is not empty HB/trigger!) + // 2) method was called from addData and the current IR orbit is the one for which it was called (then it is not empty HB/trigger!) continue; } if (writer->mVerbosity > 2) { @@ -601,11 +648,11 @@ void RawFileWriter::LinkData::fillEmptyHBHs(const IR& ir, bool dataAdded) if (writer->mVerbosity > 2) { LOG(INFO) << "Adding HBF " << ir << " for " << describe(); } - closeHBFPage(); // close current HBF: add RDH with stop and update counters - RDHUtils::setTriggerType(rdhCopy, 0); // reset to avoid any detector specific flags in the dummy HBFs + closeHBFPage(); // close current HBF: add RDH with stop and update counters + RDHUtils::setTriggerType(rdhCopy, 0); // reset to avoid any detector specific flags in the dummy HBFs writer->mHBFUtils.updateRDH<RDHAny>(rdhCopy, ir, false); // update HBF orbit/bc and trigger flags - openHBFPage(rdhCopy); // open new HBF - updateIR = ir + 1; // new Trigger in RORC detector will be generated at >= this IR + openHBFPage(rdhCopy); // open new HBF + updateIR = ir + 1; // new Trigger in RORC detector will be generated at >= this IR } } @@ -613,8 +660,7 @@ void RawFileWriter::LinkData::fillEmptyHBHs(const IR& ir, bool dataAdded) std::string RawFileWriter::LinkData::describe() const { std::stringstream ss; - ss << "Link SubSpec=0x" << std::hex << std::setw(8) << std::setfill('0') - << RDHUtils::getSubSpec(rdhCopy) << std::dec + ss << "Link SubSpec=0x" << std::hex << std::setw(8) << std::setfill('0') << subspec << std::dec << '(' << std::setw(3) << int(RDHUtils::getCRUID(rdhCopy)) << ':' << std::setw(2) << int(RDHUtils::getLinkID(rdhCopy)) << ':' << int(RDHUtils::getEndPointID(rdhCopy)) << ") feeID=0x" << std::hex << std::setw(4) << std::setfill('0') << RDHUtils::getFEEID(rdhCopy); return ss.str(); @@ -626,10 +672,79 @@ void RawFileWriter::LinkData::print() const LOGF(INFO, "Summary for %s : NTF: %u NRDH: %u Nbytes: %u", describe(), nTFWritten, nRDHWritten, nBytesWritten); } +//____________________________________________ +size_t RawFileWriter::LinkData::pushBack(const char* ptr, size_t sz, bool keepLastOnFlash) +{ + if (!sz) { + return buffer.size(); + } + nBytesWritten += sz; + // do we have a space one this superpage? + if ((writer->mSuperPageSize - int(buffer.size())) < 0) { // need to flush + flushSuperPage(keepLastOnFlash); + } + auto offs = expandBufferBy(sz); + memmove(&buffer[offs], ptr, sz); + return offs; +} + //================================================ +//____________________________________________ void RawFileWriter::OutputFile::write(const char* data, size_t sz) { std::lock_guard<std::mutex> lock(fileMtx); fwrite(data, 1, sz, handler); // flush to file } + +//____________________________________________ +void RawFileWriter::DetLazinessCheck::acknowledge(LinkSubSpec_t s, const IR& _ir, bool _preformatted, uint32_t _trigger, uint32_t _detField) +{ + if (_ir != ir) { // unseen IR arrived + ir = _ir; + irSeen++; + preformatted = _preformatted; + trigger = _trigger; + detField = _detField; + } + linksDone[s] = true; +} + +//____________________________________________ +void RawFileWriter::DetLazinessCheck::completeLinks(RawFileWriter* wr, const IR& _ir) +{ + if (wr->mSSpec2Link.size() == linksDone.size() || ir == _ir || ir.isDummy()) { // nothing to do + return; + } + for (auto& it : wr->mSSpec2Link) { + auto res = linksDone.find(it.first); + if (res == linksDone.end()) { + if (wr->mVerbosity > 10) { + LOGP(INFO, "Complete {} for IR BCid:{} Orbit: {}", it.second.describe(), ir.bc, ir.orbit); + } + completeCount++; + it.second.addData(ir, gsl::span<char>{}, preformatted, trigger, detField); + } + } + clear(); +} + +void o2::raw::assertOutputDirectory(std::string_view outDirName) +{ + if (!std::filesystem::exists(outDirName)) { +#if defined(__clang__) + // clang `create_directories` implementation is misbehaving and can + // return false even if the directory is actually successfully created + // so we work around that "feature" by not checking the + // return value at all but using a second call to `exists` + std::filesystem::create_directories(outDirName); + if (!std::filesystem::exists(outDirName)) { + LOG(FATAL) << "could not create output directory " << outDirName; + } +#else + if (!std::filesystem::create_directories(outDirName)) { + LOG(FATAL) << "could not create output directory " << outDirName; + } +#endif + } +} diff --git a/Detectors/Raw/src/SimpleRawReader.cxx b/Detectors/Raw/src/SimpleRawReader.cxx deleted file mode 100644 index 4bd2af95c6ff8..0000000000000 --- a/Detectors/Raw/src/SimpleRawReader.cxx +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SimpleRawReader.cxx -/// \brief Simple reader for non-DPL tests -#include "Framework/Logger.h" -#include "DetectorsRaw/SimpleRawReader.h" -#include "DetectorsRaw/SimpleSTF.h" -#include "DetectorsRaw/HBFUtils.h" - -using namespace o2::raw; -using namespace o2::framework; - -/// due to the dictionary genation for the macros which include this class, the constructors and d-tor are defined here. -///_________________________________________________________________ -SimpleRawReader::SimpleRawReader(const std::string& cfg, bool tfPerMessage, int loop) - : mLoop(loop), mHBFPerMessage(!tfPerMessage), mCFGName(cfg) {} - -///_________________________________________________________________ -SimpleRawReader::SimpleRawReader() = default; - -///_________________________________________________________________ -SimpleRawReader::~SimpleRawReader() = default; - -///_________________________________________________________________ -/// Init the reader from the config string, create buffer -void SimpleRawReader::init() -{ - if (mReader) { - return; - } - if (mCFGName.empty()) { - throw std::runtime_error("input is not set"); - } - mReader = std::make_unique<RawFileReader>(mCFGName); // init from configuration file - uint32_t errCheck = 0xffffffff; - errCheck ^= 0x1 << RawFileReader::ErrNoSuperPageForTF; // makes no sense for superpages not interleaved by others - mReader->setCheckErrors(errCheck); - mReader->init(); -} - -///_________________________________________________________________ -/// read data of all links for next TF, return number of links with data -bool SimpleRawReader::loadNextTF() -{ - mSTF.reset(); - - if (!mReader) { - init(); - } - int nLinks = mReader->getNLinks(), nread = 0; - std::vector<InputRoute> inpRoutes; - SimpleSTF::PartsRef partsRef; - SimpleSTF::Messages messages; - - auto tfID = mReader->getNextTFToRead(); - if (tfID >= mReader->getNTimeFrames()) { - if (mReader->getNTimeFrames() && mLoop--) { - tfID = 0; - mReader->setNextTFToRead(tfID); - mLoopsDone++; - for (int il = 0; il < nLinks; il++) { - mReader->getLink(il).nextBlock2Read = 0; // think about more elaborate looping scheme, e.g. incrementing the orbits in RDHs - } - LOG(INFO) << "Starting new loop " << mLoopsDone << " from the beginning of data"; - } else { - printStat(); - mDone = true; - return false; - } - } - auto nHB = HBFUtils::Instance().getNOrbitsPerTF(); - partsRef.reserve(nLinks); - inpRoutes.reserve(nLinks); - messages.reserve(2 * (mHBFPerMessage ? nHB * nLinks : nLinks)); - size_t totSize = 0; - for (int il = 0; il < nLinks; il++) { - auto& link = mReader->getLink(il); - auto tfsz = link.getNextTFSize(); - if (!tfsz) { - continue; - } - InputSpec inps(std::string("inpSpec") + std::to_string(il), link.origin, link.description, link.subspec, Lifetime::Timeframe); - inpRoutes.emplace_back(InputRoute{inps, size_t(il), std::string("src") + std::to_string(il)}); - - o2::header::DataHeader hdrTmpl(link.description, link.origin, link.subspec); // template with 0 size - hdrTmpl.payloadSerializationMethod = o2::header::gSerializationMethodNone; - hdrTmpl.splitPayloadParts = mHBFPerMessage ? nHB : 1; - partsRef.emplace_back(messages.size(), hdrTmpl.splitPayloadParts); // entry and nparts the multipart in the messages - while (hdrTmpl.splitPayloadIndex < hdrTmpl.splitPayloadParts) { - - hdrTmpl.payloadSize = mHBFPerMessage ? link.getNextHBFSize() : tfsz; - o2::header::Stack headerStack{hdrTmpl, o2f::DataProcessingHeader{mTFIDaccum}}; - auto* hdMessage = messages.emplace_back(std::make_unique<std::vector<char>>(headerStack.size()))->data(); // header message - memcpy(hdMessage, headerStack.data(), headerStack.size()); - - auto* plMessage = messages.emplace_back(std::make_unique<std::vector<char>>(hdrTmpl.payloadSize))->data(); // payload message - auto bread = mHBFPerMessage ? link.readNextHBF(plMessage) : link.readNextTF(plMessage); - if (bread != hdrTmpl.payloadSize) { - LOG(ERROR) << "Link " << il << " read " << bread << " bytes instead of " << hdrTmpl.payloadSize - << " expected in TF=" << mTFIDaccum << " part=" << hdrTmpl.splitPayloadIndex; - throw std::runtime_error("error in link data reading"); - } - hdrTmpl.splitPayloadIndex++; // prepare for next - LOG(DEBUG) << "Loaded " << tfsz << " bytes for " << link.describe(); - } - totSize += tfsz; - nread++; - } - LOG(INFO) << "Loaded " << totSize << " bytes for " << nread << " non-empty links out of " << nLinks; - mSTF = std::make_unique<SimpleSTF>(std::move(inpRoutes), std::move(partsRef), std::move(messages)); - - return nread > 0; -} - -///_________________________________________________________________ -/// get current SimpleSTD pointer -SimpleSTF* SimpleRawReader::getSimpleSTF() -{ - return mSTF.get(); -} - -///_________________________________________________________________ -/// get current SimpleSTD InputRecord pointer -o2::framework::InputRecord* SimpleRawReader::getInputRecord() -{ - return mSTF ? &mSTF->record : nullptr; -} - -///_________________________________________________________________ -/// print current statistics -void SimpleRawReader::printStat() const -{ - LOGF(INFO, "Sent payload of %zu bytes in %zu messages sent for %d TFs in %d links", mSentSize, mSentMessages, mTFIDaccum, getNLinks()); -} diff --git a/Detectors/Raw/src/SimpleSTF.cxx b/Detectors/Raw/src/SimpleSTF.cxx deleted file mode 100644 index 9f9c06f4b02f1..0000000000000 --- a/Detectors/Raw/src/SimpleSTF.cxx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SimpleSTF.cxx -/// \brief Mocked STF with InputRecord for standalone tests - -#include "DetectorsRaw/SimpleSTF.h" -#include "Framework/DataRefUtils.h" - -using namespace o2::raw; - -SimpleSTF::SimpleSTF(std::vector<o2f::InputRoute>&& sch, PartsRef&& pref, Messages&& msg) - : schema{std::move(sch)}, partsRef{std::move(pref)}, messages{std::move(msg)}, record{schema, {[this](size_t i, size_t part) { // getter for the DataRef of a part in the input "i" - auto ref = this->partsRef[i].first + (part << 1); // entry of the header for this part, the payload follows - auto header = static_cast<char const*>(this->messages[ref]->data()); - auto payload = static_cast<char const*>(this->messages[ref + 1]->data()); - return o2f::DataRef{nullptr, header, payload}; - }, - [this](size_t i) { // getter for the nparts in the input "i" - return i < partsRef.size() ? partsRef[i].second : 0; - }, - this->partsRef.size()}} -{ -} diff --git a/Detectors/Raw/src/rawfile-reader-workflow.cxx b/Detectors/Raw/src/rawfile-reader-workflow.cxx index 7f1062969e6b8..33800b5085d66 100644 --- a/Detectors/Raw/src/rawfile-reader-workflow.cxx +++ b/Detectors/Raw/src/rawfile-reader-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,10 +31,12 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) options.push_back(ConfigParamSpec{"delay", VariantType::Float, 0.f, {"delay in seconds between consecutive TFs sending"}}); options.push_back(ConfigParamSpec{"buffer-size", VariantType::Int64, 5 * 1024L, {"buffer size for files preprocessing"}}); options.push_back(ConfigParamSpec{"super-page-size", VariantType::Int64, 1024L * 1024L, {"super-page size for FMQ parts definition"}}); - options.push_back(ConfigParamSpec{"part-per-hbf", VariantType::Bool, false, {"FMQ parts per superpage (default) of HBF"}}); + options.push_back(ConfigParamSpec{"part-per-sp", VariantType::Bool, false, {"FMQ parts per superpage instead of per HBF"}}); options.push_back(ConfigParamSpec{"raw-channel-config", VariantType::String, "", {"optional raw FMQ channel for non-DPL output"}}); options.push_back(ConfigParamSpec{"cache-data", VariantType::Bool, false, {"cache data at 1st reading, may require excessive memory!!!"}}); options.push_back(ConfigParamSpec{"detect-tf0", VariantType::Bool, false, {"autodetect HBFUtils start Orbit/BC from 1st TF seen"}}); + options.push_back(ConfigParamSpec{"calculate-tf-start", VariantType::Bool, false, {"calculate TF start instead of using TType"}}); + options.push_back(ConfigParamSpec{"drop-tf", VariantType::String, "none", {"Drop each TFid%(1)==(2) of detector, e.g. ITS,2,4;TPC,4[,0];..."}}); options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}); // options for error-check suppression @@ -50,26 +53,29 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { - auto inifile = configcontext.options().get<std::string>("input-conf"); - auto loop = configcontext.options().get<int>("loop"); - uint32_t maxTF = uint32_t(configcontext.options().get<int64_t>("max-tf")); - uint32_t minTF = uint32_t(configcontext.options().get<int64_t>("min-tf")); - uint64_t buffSize = uint64_t(configcontext.options().get<int64_t>("buffer-size")); - uint64_t spSize = uint64_t(configcontext.options().get<int64_t>("super-page-size")); - bool partPerSP = !configcontext.options().get<bool>("part-per-hbf"); - bool cache = configcontext.options().get<bool>("cache-data"); - bool autodetectTF0 = configcontext.options().get<bool>("detect-tf0"); - std::string rawChannelConfig = configcontext.options().get<std::string>("raw-channel-config"); - uint32_t errmap = 0; + ReaderInp rinp; + rinp.inifile = configcontext.options().get<std::string>("input-conf"); + rinp.loop = configcontext.options().get<int>("loop"); + rinp.maxTF = uint32_t(configcontext.options().get<int64_t>("max-tf")); + rinp.minTF = uint32_t(configcontext.options().get<int64_t>("min-tf")); + rinp.bufferSize = uint64_t(configcontext.options().get<int64_t>("buffer-size")); + rinp.spSize = uint64_t(configcontext.options().get<int64_t>("super-page-size")); + rinp.partPerSP = configcontext.options().get<bool>("part-per-sp"); + rinp.cache = configcontext.options().get<bool>("cache-data"); + rinp.autodetectTF0 = configcontext.options().get<bool>("detect-tf0"); + rinp.preferCalcTF = configcontext.options().get<bool>("calculate-tf-start"); + rinp.rawChannelConfig = configcontext.options().get<std::string>("raw-channel-config"); + rinp.delay_us = uint32_t(1e6 * configcontext.options().get<float>("delay")); // delay in microseconds + rinp.dropTF = configcontext.options().get<std::string>("drop-tf"); + rinp.errMap = 0; for (int i = RawFileReader::NErrorsDefined; i--;) { auto ei = RawFileReader::ErrTypes(i); bool defOpt = RawFileReader::ErrCheckDefaults[i]; if (configcontext.options().get<bool>(RawFileReader::nochk_opt(ei).c_str()) ? !defOpt : defOpt) { // cmdl option inverts default! - errmap |= 0x1 << i; + rinp.errMap |= 0x1 << i; } } o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); - uint32_t delay_us = uint32_t(1e6 * configcontext.options().get<float>("delay")); // delay in microseconds - return std::move(o2::raw::getRawFileReaderWorkflow(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelConfig)); + return std::move(o2::raw::getRawFileReaderWorkflow(rinp)); } diff --git a/Detectors/Raw/src/rawfileCheck.cxx b/Detectors/Raw/src/rawfileCheck.cxx index cb29425cc7250..7b4b42c9b1dae 100644 --- a/Detectors/Raw/src/rawfileCheck.cxx +++ b/Detectors/Raw/src/rawfileCheck.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,7 @@ int main(int argc, char* argv[]) desc_add_option("spsize,s", bpo::value<int>()->default_value(reader.getNominalSPageSize()), "nominal super-page size in bytes"); desc_add_option("buffer-size,b", bpo::value<size_t>()->default_value(reader.getNominalSPageSize()), "buffer size for files preprocessing"); desc_add_option("detect-tf0", "autodetect HBFUtils start Orbit/BC from 1st TF seen"); + desc_add_option("calculate-tf-start", "calculate TF start instead of using TType"); desc_add_option("rorc", "impose RORC as default detector mode"); desc_add_option("configKeyValues", bpo::value(&configKeyValues)->default_value(""), "semicolon separated key=value strings"); for (int i = 0; i < RawFileReader::NErrorsDefined; i++) { @@ -91,6 +93,7 @@ int main(int argc, char* argv[]) reader.setNominalSPageSize(vm["spsize"].as<int>()); reader.setMaxTFToRead(vm["max-tf"].as<uint32_t>()); reader.setBufferSize(vm["buffer-size"].as<size_t>()); + reader.setPreferCalculatedTFStart(vm.count("calculate-tf-start")); reader.setDefaultReadoutCardType(rocard); reader.setTFAutodetect(vm.count("detect-tf0") ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); uint32_t errmap = 0; diff --git a/Detectors/Raw/src/rawfileSplit.cxx b/Detectors/Raw/src/rawfileSplit.cxx new file mode 100644 index 0000000000000..4ba937247719a --- /dev/null +++ b/Detectors/Raw/src/rawfileSplit.cxx @@ -0,0 +1,215 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file rawfileCheck.h +/// @author ruben.shahoyan@cern.ch +/// @brief Checker for raw data conformity with CRU format + +#include "DetectorsRaw/RawFileReader.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/StringUtils.h" +#include "Framework/Logger.h" +#include <TStopwatch.h> +#include <boost/program_options.hpp> +#include <iostream> +#include <string> +#include <vector> +#include <filesystem> + +namespace bpo = boost::program_options; + +using namespace o2::raw; + +int main(int argc, char* argv[]) +{ + RawFileReader reader; + std::vector<std::string> fnames; + std::string config, configKeyValues; + bpo::variables_map vm; + bpo::options_description descOpt("Options"); + auto desc_add_option = descOpt.add_options(); + desc_add_option("help,h", "print this help message."); + desc_add_option("input-conf,c", bpo::value(&config)->default_value(""), "read input from configuration file"); + desc_add_option("max-tf,m", bpo::value<uint32_t>()->default_value(0xffffffff), " ID to read (counts from 0)"); + desc_add_option("verbosity,v", bpo::value<int>()->default_value(reader.getVerbosity()), "1: long report, 2 or 3: print or dump all RDH"); + desc_add_option("spsize,s", bpo::value<int>()->default_value(reader.getNominalSPageSize()), "nominal super-page size in bytes"); + desc_add_option("buffer-size,b", bpo::value<size_t>()->default_value(reader.getNominalSPageSize()), "buffer size for files preprocessing"); + desc_add_option("detect-tf0", "autodetect HBFUtils start Orbit/BC from 1st TF seen"); + desc_add_option("calculate-tf-start", "calculate TF start instead of using TType"); + desc_add_option("rorc", "impose RORC as default detector mode"); + desc_add_option("tfs-per-chunk,n", bpo::value<uint32_t>()->default_value(0xffffffff), " number of output TFs per chunk"); + desc_add_option("output-dir-prefix,o", bpo::value<std::string>()->default_value("./chunk"), "output directory prefix for raw data chunk (chunk ID will be added)"); + desc_add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,cru,link"); + + desc_add_option("configKeyValues", bpo::value(&configKeyValues)->default_value(""), "semicolon separated key=value strings"); + for (int i = 0; i < RawFileReader::NErrorsDefined; i++) { + auto ei = RawFileReader::ErrTypes(i); + desc_add_option(RawFileReader::nochk_opt(ei).c_str(), RawFileReader::nochk_expl(ei).c_str()); + } + + bpo::options_description hiddenOpt("hidden"); + hiddenOpt.add_options()("files", bpo::value(&fnames)->composing(), ""); + + bpo::options_description fullOpt("cmd"); + fullOpt.add(descOpt).add(hiddenOpt); + + bpo::positional_options_description posOpt; + posOpt.add("files", -1); + + auto printHelp = [&](std::ostream& stream) { + stream << "Usage: " << argv[0] << " [options] file0 [... fileN]" << std::endl; + stream << descOpt << std::endl; + stream << " (input files are optional if config file was provided)" << std::endl; + }; + + try { + bpo::store(bpo::command_line_parser(argc, argv) + .options(fullOpt) + .positional(posOpt) + .allow_unregistered() + .run(), + vm); + bpo::notify(vm); + if (argc == 1 || vm.count("help") || (fnames.empty() && config.empty())) { + printHelp(std::cout); + return 0; + } + o2::conf::ConfigurableParam::updateFromString(configKeyValues); + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing command line arguments\n"; + printHelp(std::cerr); + return -1; + } + + RawFileReader::RDH rdh; + LOG(INFO) << "RawDataHeader v" << int(rdh.version) << " is assumed"; + + RawFileReader::ReadoutCardType rocard = vm.count("rorc") ? RawFileReader::ReadoutCardType::RORC : RawFileReader::ReadoutCardType::CRU; + + reader.setVerbosity(vm["verbosity"].as<int>()); + reader.setNominalSPageSize(vm["spsize"].as<int>()); + reader.setMaxTFToRead(vm["max-tf"].as<uint32_t>()); + reader.setBufferSize(vm["buffer-size"].as<size_t>()); + reader.setDefaultReadoutCardType(rocard); + reader.setTFAutodetect(vm.count("detect-tf0") ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); + reader.setPreferCalculatedTFStart(vm.count("calculate-tf-start")); + + std::string_view fileFor = vm["file-for"].as<std::string>(); + + uint32_t errmap = 0; + for (int i = RawFileReader::NErrorsDefined; i--;) { + auto ei = RawFileReader::ErrTypes(i); + if (RawFileReader::ErrCheckDefaults[i]) { + errmap |= 0x1 << i; + } + if (vm.count(RawFileReader::nochk_opt(ei).c_str())) { // toggle + errmap ^= 0x1 << i; + } + LOG(INFO) << ((errmap & (0x1 << i)) ? "apply " : "ignore") << " check for " << RawFileReader::ErrNames[i].data(); + } + + if (!config.empty()) { + auto inp = RawFileReader::parseInput(config); + reader.loadFromInputsMap(inp); + } + + for (int i = 0; i < fnames.size(); i++) { + reader.addFile(fnames[i]); + } + + TStopwatch sw; + sw.Start(); + + reader.setCheckErrors(errmap); + reader.init(); + + sw.Print(); + int maxTFPerChunk = vm["tfs-per-chunk"].as<uint32_t>(); + std::string outDirPrefix = vm["output-dir-prefix"].as<std::string>(), outDir = ""; + int ntf = reader.getNTimeFrames(); + int nlinks = reader.getNLinks(); + std::vector<RawFileReader::PartStat> partsSP; + std::vector<char> buffer; + std::unique_ptr<RawFileWriter> writer; + int chunkID = -1; + + for (int itf = 0; itf < ntf; itf++) { + reader.setNextTFToRead(itf); + bool reinitWriter = false; + if ((itf % maxTFPerChunk) == 0) { + reinitWriter = true; + chunkID++; + } + for (int il = 0; il < nlinks; il++) { + auto& link = reader.getLink(il); + if (!link.rewindToTF(itf)) { + continue; // this link has no data for wanted TF + } + int nParts = link.getNextTFSuperPagesStat(partsSP); + for (int ip = 0; ip < nParts; ip++) { + buffer.resize(partsSP[ip].size); + auto bread = link.readNextSuperPage(buffer.data(), &partsSP[ip]); + if (bread != partsSP[ip].size) { + LOG(ERROR) << "Link " << il << " read " << bread << " bytes instead of " << partsSP[ip].size << " expected in TF=" << itf << " part=" << ip; + } + + if (reinitWriter) { + if (writer) { // generate config for previous chunk + writer->writeConfFile(writer->getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDir, '/', writer->getOrigin().str, "raw.cfg")); + } + outDir = o2::utils::Str::concat_string(outDirPrefix, "_", std::to_string(chunkID)); + // if needed, create output directory + if (!std::filesystem::exists(outDir)) { + if (!std::filesystem::create_directories(outDir)) { + LOG(FATAL) << "could not create output directory " << outDir; + } else { + LOG(INFO) << "created output directory " << outDir; + } + } + writer = std::make_unique<RawFileWriter>(link.origin, link.cruDetector); + writer->useRDHVersion(RDHUtils::getVersion(link.rdhl)); + reinitWriter = false; + } + if (!writer->isLinkRegistered(RDHUtils::getSubSpec(RDHUtils::getCRUID(link.rdhl), RDHUtils::getLinkID(link.rdhl), RDHUtils::getEndPointID(link.rdhl), RDHUtils::getFEEID(link.rdhl)))) { // register the output link + std::string outFileName; + + if (fileFor == "all") { // single file for all links + outFileName = o2::utils::Str::concat_string(outDir, "/", fileFor, ".raw"); + } else if (fileFor == "cru") { + outFileName = o2::utils::Str::concat_string(outDir, "/", fileFor, "_", std::to_string(RDHUtils::getCRUID(link.rdhl)), ".raw"); + } else if (fileFor == "link") { + outFileName = o2::utils::Str::concat_string(outDir, "/", fileFor, + "_", std::to_string(RDHUtils::getLinkID(link.rdhl)), + "_cru", std::to_string(RDHUtils::getCRUID(link.rdhl)), + "_ep", std::to_string(RDHUtils::getEndPointID(link.rdhl)), + "_feeid", std::to_string(RDHUtils::getFEEID(link.rdhl)), ".raw"); + } else { + throw std::runtime_error("invalid option provided for file grouping"); + } + + writer->registerLink(link.rdhl, outFileName); + } + + auto& linkW = writer->getLinkWithSubSpec(link.rdhl); + auto& outF = writer->getOutputFileForLink(linkW); + outF.write(buffer.data(), bread); + } + } + } + if (writer) { // generate config for previous chunk + writer->writeConfFile(writer->getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDir, '/', writer->getOrigin().str, "raw.cfg")); + } + writer.reset(); + + return 0; +} diff --git a/Detectors/Raw/test/testHBFUtils.cxx b/Detectors/Raw/test/testHBFUtils.cxx index cdccf4ab91a9e..07e42dc60b4e3 100644 --- a/Detectors/Raw/test/testHBFUtils.cxx +++ b/Detectors/Raw/test/testHBFUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Raw/test/testRawReaderWriter.cxx b/Detectors/Raw/test/testRawReaderWriter.cxx index d11c7aba41e19..b8704df590978 100644 --- a/Detectors/Raw/test/testRawReaderWriter.cxx +++ b/Detectors/Raw/test/testRawReaderWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,11 +22,11 @@ #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RDHUtils.h" #include "DetectorsRaw/RawFileWriter.h" -#include "DetectorsRaw/SimpleRawReader.h" -#include "DetectorsRaw/SimpleSTF.h" +#include "DetectorsRaw/RawFileReader.h" #include "CommonConstants/Triggers.h" #include "Framework/Logger.h" #include "Framework/InputRecord.h" +#include "Headers/DataHeaderHelpers.h" #include "DPLUtils/DPLRawParser.h" #include "CommonUtils/StringUtils.h" @@ -69,7 +70,7 @@ struct TestRawWriter { // simple class to create detector payload for multiple l int feeIDShift = writer.isCRUDetector() ? 8 : 9; // register links for (int icru = 0; icru < NCRU; icru++) { - std::string outFileName = o2::utils::concat_string("testdata_", writer.isCRUDetector() ? "cru" : "rorc", std::to_string(icru), ".raw"); + std::string outFileName = o2::utils::Str::concat_string("testdata_", writer.isCRUDetector() ? "cru" : "rorc", std::to_string(icru), ".raw"); for (int il = 0; il < NLinkPerCRU; il++) { auto& link = writer.registerLink((icru << feeIDShift) + il, icru, il, 0, outFileName); RDHUtils::setDetectorField(link.rdhCopy, 0xff << icru); // if needed, set extra link info, will be copied to all RDHs @@ -83,6 +84,7 @@ struct TestRawWriter { // simple class to create detector payload for multiple l writer.setCarryOverCallBack(this); // we want that writer to ask the detector code how to split large payloads writer.setApplyCarryOverToLastPage(true); // call CarryOver method also for the last chunk + writer.doLazinessCheck(false); // do not apply auto-completion since the test mixes preformatted links filled per HBF and standard links filled per IR. } //_________________________________________________________________ @@ -314,38 +316,6 @@ BOOST_AUTO_TEST_CASE(RawReaderWriter_CRU) TestRawReader dr{"TST", "test_raw_conf_GBT.cfg"}; // here we set the reader wrapper name just to deduce the input config name, everything else will be deduced from the config dr.init(); dr.run(); // read back and check - - // test SimpleReader - int nLoops = 5; - SimpleRawReader sr(dr.confName, false, nLoops); - int ntf = 0; - while (sr.loadNextTF()) { - ntf++; - auto& record = *sr.getInputRecord(); - BOOST_CHECK(record.size() == NCRU * NLinkPerCRU); - o2::header::DataHeader const* dhPrev = nullptr; - DPLRawParser parser(record); - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - // auto const* rdh = &get_if<RDHAny>(); - auto const* rdh = reinterpret_cast<const RDHAny*>(it.raw()); // RSTODO this is a hack in absence of generic header getter - auto const* dh = it.o2DataHeader(); - BOOST_REQUIRE(rdh != nullptr); - bool newLink = false; - if (dh != dhPrev) { - dhPrev = dh; - newLink = true; - } - if (RDHUtils::getCRUID(*rdh) == NCRU - 1) { - if (newLink) { - dh->print(); - } - RDHUtils::printRDH(rdh); - if (RDHUtils::getMemorySize(*rdh) > sizeof(RDHAny) + RDHUtils::GBTWord) { // special CRU with predefined sizes - BOOST_CHECK(it.size() + sizeof(RDHAny) == SpecSize[RDHUtils::getLinkID(*rdh)]); - } - } - } - } } BOOST_AUTO_TEST_CASE(RawReaderWriter_RORC) @@ -357,31 +327,6 @@ BOOST_AUTO_TEST_CASE(RawReaderWriter_RORC) TestRawReader dr{"TST", "test_raw_conf_DDL.cfg"}; // here we set the reader wrapper name just to deduce the input config name, everything else will be deduced from the config dr.init(); dr.run(); // read back and check - - // test SimpleReader - int nLoops = 5; - SimpleRawReader sr(dr.confName, false, nLoops); - int ntf = 0; - while (sr.loadNextTF()) { - ntf++; - auto& record = *sr.getInputRecord(); - LOG(INFO) << "FAIL? " << record.size() << " " << NCRU * NLinkPerCRU; - - BOOST_CHECK(record.size() == NCRU * NLinkPerCRU); - o2::header::DataHeader const* dhPrev = nullptr; - DPLRawParser parser(record); - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - // auto const* rdh = &get_if<RDHAny>(); - auto const* rdh = reinterpret_cast<const RDHAny*>(it.raw()); // RSTODO this is a hack in absence of generic header getter - auto const* dh = it.o2DataHeader(); - BOOST_REQUIRE(rdh != nullptr); - bool newLink = false; - if (dh != dhPrev) { - dhPrev = dh; - newLink = true; - } - } - } } } // namespace o2 diff --git a/Detectors/TOF/CMakeLists.txt b/Detectors/TOF/CMakeLists.txt index 7ac94855f7b2d..fa27efaa02c6e 100644 --- a/Detectors/TOF/CMakeLists.txt +++ b/Detectors/TOF/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(calibration) @@ -15,5 +16,7 @@ add_subdirectory(reconstruction) add_subdirectory(compression) if(BUILD_TESTING) add_subdirectory(prototyping) + add_subdirectory(calibration/macros) endif() +add_subdirectory(workflowIO) add_subdirectory(workflow) diff --git a/Detectors/TOF/README.md b/Detectors/TOF/README.md new file mode 100644 index 0000000000000..aee082d197019 --- /dev/null +++ b/Detectors/TOF/README.md @@ -0,0 +1,11 @@ +<!-- doxy +\page refDetectorsTOF TOF +/doxy --> + +# TOF + +This is a top page for the TOF detector documentation. + +<!-- doxy +* \subpage refDetectorsTOFtestWorkflow +/doxy --> \ No newline at end of file diff --git a/Detectors/TOF/base/CMakeLists.txt b/Detectors/TOF/base/CMakeLists.txt index 2e063f4851424..8df86bca1370c 100644 --- a/Detectors/TOF/base/CMakeLists.txt +++ b/Detectors/TOF/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFBase SOURCES src/Geo.cxx @@ -15,8 +16,9 @@ o2_add_library(TOFBase src/Mapping.cxx src/Strip.cxx src/WindowFiller.cxx - PUBLIC_LINK_LIBRARIES Boost::serialization FairRoot::Base ms_gsl::ms_gsl - O2::DetectorsBase O2::CommonDataFormat O2::DetectorsRaw) + PUBLIC_LINK_LIBRARIES Boost::serialization FairRoot::Base Microsoft.GSL::GSL + O2::DetectorsBase O2::CommonDataFormat O2::DetectorsRaw + O2::DataFormatsTOF) o2_target_root_dictionary(TOFBase HEADERS include/TOFBase/Geo.h include/TOFBase/Digit.h diff --git a/Detectors/TOF/base/include/TOFBase/Digit.h b/Detectors/TOF/base/include/TOFBase/Digit.h index ae07cb36e175f..d23c138012e81 100644 --- a/Detectors/TOF/base/include/TOFBase/Digit.h +++ b/Detectors/TOF/base/include/TOFBase/Digit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,6 +57,9 @@ class Digit uint64_t getBC() const { return mIR.toLong(); } void setBC(uint64_t bc) { mIR.setFromLong(bc); } + void setIR(const InteractionRecord& ir) { mIR = ir; } + + auto getIR() const { return mIR; } Int_t getLabel() const { return mLabel; } void setLabel(Int_t label) { mLabel = label; } @@ -68,7 +72,7 @@ class Digit Bool_t isUsedInCluster() const { return mIsUsedInCluster; } - void setIsUsedInCluster() { mIsUsedInCluster = kTRUE; } + void setIsUsedInCluster(bool val = true) { mIsUsedInCluster = val; } Int_t getElectronicIndex() const { return mElectronIndex; } void setElectronicIndex(Int_t ind) { mElectronIndex = ind; } @@ -188,13 +192,13 @@ struct ReadoutWindowData { struct DigitHeader { int mCountsCrate[Geo::kNCrate] = {0}; - int mNumberOfCrates[Geo::kNCrate] = {0}; + int mNumberOfCrates[Geo::kNCrate + 1] = {0}; int mCountsRow = 0; void clear() { memset(mCountsCrate, 0, Geo::kNCrate * 4); - memset(mNumberOfCrates, 0, Geo::kNCrate * 4); + memset(mNumberOfCrates, 0, (Geo::kNCrate + 1) * 4); mCountsRow = 0; } DigitHeader() { clear(); } diff --git a/Detectors/TOF/base/include/TOFBase/Geo.h b/Detectors/TOF/base/include/TOFBase/Geo.h index 66dcc3feea9e8..46d186082d6d5 100644 --- a/Detectors/TOF/base/include/TOFBase/Geo.h +++ b/Detectors/TOF/base/include/TOFBase/Geo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,8 +13,10 @@ #define ALICEO2_TOF_GEO_H #include "Rtypes.h" +#include <array> +#include <vector> #include "CommonConstants/LHCConstants.h" -#include "DetectorsRaw/HBFUtils.h" +//#include "DetectorsRaw/HBFUtils.h" namespace o2 { @@ -27,8 +30,38 @@ class Geo public: // static void updateNSinTF() { NS_IN_TF = o2::constants::lhc::LHCOrbitNS * o2::raw::HBFUtils::getNOrbitsPerTF(); } + // FLP <-> CRU <-> LINKS mapping + static Int_t getCRU(int link) + { + return CRUFROMLINK[link]; + } + static Int_t getCRUlink(int link) + { + return CRULINK[link]; + } + static Int_t getCRUendpoint(int link) + { + return CRUENDPOINT[link]; + } + static Int_t getCONETlink(int link) { return (link % 4); } + static Int_t getCRUid(int link) + { + return CRUID[CRUFROMLINK[link]]; + } + static Int_t getCRUid(int iflp, int icru) { return CRUFROMFLP[iflp][icru]; } + static Int_t getFLPid(int link) + { + return FLPFROMCRU[CRUFROMLINK[link]]; + } + static Int_t getFEEid(int link) + { + return FEEID[link]; + } + static Int_t getFLP(int iflp) { return FLP[iflp]; } + // From AliTOFGeometry static void translate(Float_t* xyz, Float_t translationVector[3]); + static void translate(Float_t& x, Float_t& y, Float_t& z, Float_t translationVector[3]); static void rotate(Float_t* xyz, Double_t rotationAngles[6]); static void rotateToSector(Float_t* xyz, Int_t isector); @@ -41,13 +74,14 @@ class Geo static void getVolumeIndices(Int_t index, Int_t* detId); // Get volume index from channel index static void getPos(Int_t* det, Float_t* pos); - static void getVolumePath(const Int_t* ind, Char_t* path); + static std::string getVolumePath(const Int_t* ind); static Int_t getStripNumberPerSM(Int_t iplate, Int_t istrip); + static void getStripAndModule(Int_t iStripPerSM, Int_t& iplate, Int_t& istrip); // Return the module and strip per module corresponding to the strip number per SM static Float_t getAngles(Int_t iplate, Int_t istrip) { return ANGLES[iplate][istrip]; } static Float_t getHeights(Int_t iplate, Int_t istrip) { return HEIGHTS[iplate][istrip]; } static Float_t getDistances(Int_t iplate, Int_t istrip) { return DISTANCES[iplate][istrip]; } - static void getPadDxDyDz(const Float_t* pos, Int_t* det, Float_t* DeltaPos); + static void getPadDxDyDz(const Float_t* pos, Int_t* det, Float_t* DeltaPos, int sector = -1); enum { // DAQ characteristics // cfr. TOF-TDR pag. 105 for Glossary @@ -69,13 +103,16 @@ class Geo static constexpr int BC_IN_ORBIT = o2::constants::lhc::LHCMaxBunches; // N. bunch crossing in 1 orbit static constexpr Int_t NPADX = 48; + static constexpr Float_t NPADX_INV_INT = 1. / NPADX; static constexpr Int_t NPADZ = 2; static constexpr Int_t NPADS = NPADX * NPADZ; + static constexpr Float_t NPADS_INV_INT = 1. / NPADS; static constexpr Int_t NSTRIPA = 15; static constexpr Int_t NSTRIPB = 19; static constexpr Int_t NSTRIPC = 19; static constexpr Int_t NMAXNSTRIP = 20; static constexpr Int_t NSTRIPXSECTOR = NSTRIPA + 2 * NSTRIPB + 2 * NSTRIPC; + static constexpr Float_t NSTRIPXSECTOR_INV_INT = 1. / NSTRIPXSECTOR; static constexpr Int_t NPADSXSECTOR = NSTRIPXSECTOR * NPADS; static constexpr Int_t NSECTORS = 18; @@ -105,6 +142,7 @@ class Geo static constexpr Float_t SIGMAFORTAIL12 = 0.5; // Sig2 for simulation of TDC tails static constexpr Float_t PHISEC = 20; // sector Phi width (deg) + static constexpr Float_t PHISECINV = 1. / PHISEC; // sector Phi width (deg) static constexpr Float_t TDCBIN = o2::constants::lhc::LHCBunchSpacingNS * 1E3 / 1024; ///< TDC bin width [ps] static constexpr Float_t NTDCBIN_PER_PS = 1. / TDCBIN; ///< number of TDC bins in 1 ns @@ -133,6 +171,35 @@ class Geo static constexpr Double_t MATCHINGWINDOW = MATCHINGWINDOW_IN_BC * o2::constants::lhc::LHCBunchSpacingNS; // Matching window in ns static constexpr Double_t WINDOWOVERLAP = MATCHINGWINDOW - READOUTWINDOW; // overlap between two consecutive matchingwindow + static constexpr Int_t CRUFROMLINK[kNCrate] = { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + + static constexpr Int_t FEEID[kNCrate] = { + 327680, 327681, 327682, 327683, 327684, 327685, 327686, 327687, 327688, 327689, 327690, 327691, 327692, 327693, 327694, 327695, 327696, 327697, + 327698, 327699, 327700, 327701, 327702, 327703, 327704, 327705, 327706, 327707, 327708, 327709, 327710, 327711, 327712, 327713, 327714, 327715, + 327716, 327717, 327718, 327719, 327720, 327721, 327722, 327723, 327724, 327725, 327726, 327727, 327728, 327729, 327730, 327731, 327732, 327733, + 327734, 327735, 327736, 327737, 327738, 327739, 327740, 327741, 327742, 327743, 327744, 327745, 327746, 327747, 327748, 327749, 327750, 327751}; + + static constexpr Int_t FLP[2] = {178, 179}; + static constexpr Int_t CRUFROMFLP[2][2] = {{227, 228}, {225, 226}}; + static constexpr Int_t FLPFROMCRU[4] = {179, 179, 178, 178}; + static constexpr Int_t CRUID[4] = {225, 226, 227, 228}; + + static constexpr Int_t CRULINK[kNCrate] = { + 11, 10, 0, 1, 9, 8, 2, 3, 7, 6, 4, 5, 5, 4, 6, 7, 3, 2, + 3, 9, 11, 10, 0, 1, 9, 8, 2, 3, 7, 6, 4, 5, 5, 4, 6, 7, + 11, 10, 0, 1, 9, 8, 2, 3, 7, 6, 4, 5, 5, 4, 6, 7, 3, 2, + 8, 9, 11, 10, 0, 1, 9, 8, 2, 3, 7, 6, 4, 5, 5, 4, 6, 7}; + + static constexpr Int_t CRUENDPOINT[kNCrate] = { + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; + static constexpr Float_t ANGLES[NPLATES][NMAXNSTRIP] = { // Strip Tilt Angles {43.99, 43.20, 42.40, 41.59, 40.77, 39.94, 39.11, 38.25, 37.40, 36.53, 35.65, 34.76, 33.87, 32.96, 32.05, 31.13, 30.19, 29.24, 12.33, 0.00}, @@ -278,9 +345,10 @@ class Geo static Int_t getECHFromCH(int chan) { return CHAN_TO_ELCHAN[chan]; } static Int_t getCHFromECH(int echan) { return ELCHAN_TO_CHAN[echan]; } - private: static void Init(); + static void InitIndices(); + private: static Int_t getSector(const Float_t* pos); static Int_t getPlate(const Float_t* pos); static Int_t getPadZ(const Float_t* pos); @@ -293,6 +361,9 @@ class Geo static Float_t mRotationMatrixSector[NSECTORS + 1][3][3]; // rotation matrixes static Float_t mRotationMatrixPlateStrip[NPLATES][NMAXNSTRIP][3][3]; static Float_t mPadPosition[NSECTORS][NPLATES][NMAXNSTRIP][NPADZ][NPADX][3]; + static Int_t mPlate[NSTRIPXSECTOR]; + static Int_t mStripInPlate[NSTRIPXSECTOR]; + static std::array<std::vector<float>, 5> mDistances; // cable length map static constexpr Float_t CABLEPROPAGATIONDELAY = 0.0513; // Propagation delay [ns/cm] @@ -300,7 +371,7 @@ class Geo static const Int_t CHAN_TO_ELCHAN[NCHANNELS]; static const Int_t ELCHAN_TO_CHAN[N_ELECTRONIC_CHANNELS]; - ClassDefNV(Geo, 1); + ClassDefNV(Geo, 2); }; } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/base/include/TOFBase/Strip.h b/Detectors/TOF/base/include/TOFBase/Strip.h index 7b38c757c9e53..994635b13dc5a 100644 --- a/Detectors/TOF/base/include/TOFBase/Strip.h +++ b/Detectors/TOF/base/include/TOFBase/Strip.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/include/TOFBase/WindowFiller.h b/Detectors/TOF/base/include/TOFBase/WindowFiller.h index 4c2f43764cd9c..6100a94c1461c 100644 --- a/Detectors/TOF/base/include/TOFBase/WindowFiller.h +++ b/Detectors/TOF/base/include/TOFBase/WindowFiller.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "TOFBase/Strip.h" #include "DetectorsRaw/HBFUtils.h" #include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsTOF/Diagnostic.h" namespace o2 { @@ -64,6 +66,8 @@ class WindowFiller void setContinuous(bool value = true) { mContinuous = value; } bool isContinuous() const { return mContinuous; } + void fillDiagnosticFrequency(); + void resizeVectorFutureDigit(int size) { mFutureDigits.resize(size); } void setFirstIR(const o2::InteractionRecord& ir) { mFirstIR = ir; } @@ -75,9 +79,10 @@ class WindowFiller memset(mChannelCounts, 0, o2::tof::Geo::NCHANNELS * sizeof(mChannelCounts[0])); } - std::vector<uint32_t>& getPatterns() { return mPatterns; } + std::vector<uint8_t>& getPatterns() { return mPatterns; } void addPattern(const uint32_t val, int icrate, int orbit, int bc) { mCratePatterns.emplace_back(val, icrate, orbit * 3 + (bc + 100) / Geo::BC_IN_WINDOW); } void addCrateHeaderData(unsigned long orbit, int crate, int32_t bc, uint32_t eventCounter); + Diagnostic getDiagnosticFrequency() { return mDiagnosticFrequency; } protected: // info TOF timewindow @@ -89,7 +94,7 @@ class WindowFiller bool mFutureToBeSorted = false; // only needed from Decoder - int mMaskNoiseRate = -1; + int mMaskNoiseRate = -999999999; int mChannelCounts[o2::tof::Geo::NCHANNELS]; // count of channel hits in the current TF (if MaskNoiseRate enabled) // digit info @@ -111,9 +116,11 @@ class WindowFiller // arrays with digit and MCLabels out of the current readout windows (stored to fill future readout window) std::vector<Digit> mFutureDigits; - std::vector<uint32_t> mPatterns; + std::vector<uint8_t> mPatterns; std::vector<uint64_t> mErrors; + Diagnostic mDiagnosticFrequency; + std::vector<PatternData> mCratePatterns; std::vector<CrateHeaderData> mCrateHeaderData; diff --git a/Detectors/TOF/base/src/CableLength.cxx b/Detectors/TOF/base/src/CableLength.cxx index 9f59fff9ae48c..450a0cbe8495d 100644 --- a/Detectors/TOF/base/src/CableLength.cxx +++ b/Detectors/TOF/base/src/CableLength.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/src/Digit.cxx b/Detectors/TOF/base/src/Digit.cxx index e1de38006e59d..ed58623877e8d 100644 --- a/Detectors/TOF/base/src/Digit.cxx +++ b/Detectors/TOF/base/src/Digit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/src/Geo.cxx b/Detectors/TOF/base/src/Geo.cxx index 79c12f697d934..54709ea93ddd7 100644 --- a/Detectors/TOF/base/src/Geo.cxx +++ b/Detectors/TOF/base/src/Geo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,11 @@ #include "TOFBase/Geo.h" #include "TGeoManager.h" #include "TMath.h" -#include "FairLogger.h" +#include "Framework/Logger.h" #include "DetectorsBase/GeometryManager.h" +#include "CommonUtils/StringUtils.h" +#include <string> +#include "MathUtils/Utils.h" ClassImp(o2::tof::Geo); @@ -28,18 +32,23 @@ Bool_t Geo::mToBeIntit = kTRUE; Float_t Geo::mRotationMatrixSector[NSECTORS + 1][3][3]; Float_t Geo::mRotationMatrixPlateStrip[NPLATES][NMAXNSTRIP][3][3]; Float_t Geo::mPadPosition[NSECTORS][NPLATES][NMAXNSTRIP][NPADZ][NPADX][3]; +Int_t Geo::mPlate[NSTRIPXSECTOR]; +Int_t Geo::mStripInPlate[NSTRIPXSECTOR]; +std::array<std::vector<float>, 5> Geo::mDistances; void Geo::Init() { + if (!mToBeIntit) { + return; + } LOG(INFO) << "tof::Geo: Initialization of TOF rotation parameters"; if (!gGeoManager) { - LOG(WARNING) << " no TGeo! Loading it"; + LOG(INFO) << " no TGeo! Loading it"; o2::base::GeometryManager::loadGeometry(); } int det[5]; - Char_t path[200]; for (Int_t isector = 0; isector < NSECTORS; isector++) { det[0] = isector; for (Int_t iplate = 0; iplate < NPLATES; iplate++) { @@ -56,8 +65,7 @@ void Geo::Init() det[3] = ipadz; for (Int_t ipadx = 0; ipadx < NPADX; ipadx++) { det[4] = ipadx; - getVolumePath(det, path); - gGeoManager->cd(path); + gGeoManager->cd(getVolumePath(det).c_str()); TGeoHMatrix global; global = *gGeoManager->GetCurrentMatrix(); const Double_t* tr = global.GetTranslation(); @@ -138,27 +146,59 @@ void Geo::Init() } } } - + InitIndices(); mToBeIntit = kFALSE; } -void Geo::getVolumePath(const Int_t* ind, Char_t* path) +void Geo::InitIndices() +{ + + // initialization of some indices arrays + + for (Int_t istrip = 0; istrip < NSTRIPXSECTOR; ++istrip) { + if (istrip < NSTRIPC) { + mPlate[istrip] = 0; + mStripInPlate[istrip] = istrip; + } else if (istrip >= NSTRIPC && istrip < NSTRIPC + NSTRIPB) { + mPlate[istrip] = 1; + mStripInPlate[istrip] = istrip - NSTRIPC; + } else if (istrip >= NSTRIPC + NSTRIPB && istrip < NSTRIPC + NSTRIPB + NSTRIPA) { + mPlate[istrip] = 2; + mStripInPlate[istrip] = istrip - NSTRIPC - NSTRIPB; + } else if (istrip >= NSTRIPC + NSTRIPB + NSTRIPA && istrip < NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB) { + mPlate[istrip] = 3; + mStripInPlate[istrip] = istrip - NSTRIPC - NSTRIPB - NSTRIPA; + } else if (istrip >= NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB && istrip < NSTRIPXSECTOR) { + mPlate[istrip] = 4; + mStripInPlate[istrip] = istrip - NSTRIPC - NSTRIPB - NSTRIPA - NSTRIPB; + } + } + + Int_t nstrips = NSTRIPC; + for (int iplate = 0; iplate < 5; ++iplate) { + if (iplate == 1 || iplate == 3) { + nstrips = NSTRIPB; + } else if (iplate == 2) { + nstrips = NSTRIPA; + } + mDistances[iplate].reserve(nstrips); + for (int i = 0; i < nstrips; ++i) { + mDistances[iplate].push_back(DISTANCES[iplate][nstrips - i - 1]); + } + } +} + +std::string Geo::getVolumePath(const Int_t* ind) { //-------------------------------------------------------------------- // This function returns the volume path of a given pad //-------------------------------------------------------------------- Int_t sector = ind[0]; - const Int_t kSize = 100; - - Char_t string1[kSize]; - Char_t string2[kSize]; - Char_t string3[kSize]; - Int_t icopy = -1; icopy = sector; - snprintf(string1, kSize, "/cave_1/barrel_1/B077_1/BSEGMO%i_1/BTOF%i_1", icopy, icopy); + auto string1 = fmt::format("/cave_1/barrel_1/B077_1/BSEGMO{:d}_1/BTOF{:d}_1", icopy, icopy); Bool_t fgHoles = kTRUE; @@ -180,20 +220,19 @@ void Geo::getVolumePath(const Int_t* ind, Char_t* path) icopy = istrip + NSTRIPC + 2 * NSTRIPB + NSTRIPA; } icopy++; - snprintf(string2, kSize, "FTOA_0/FLTA_0/FSTR_%i", icopy); + auto string2 = fmt::format("FTOA_0/FLTA_0/FSTR_{:d}", icopy); if (fgHoles && (sector == 13 || sector == 14 || sector == 15)) { if (iplate < 2) { - snprintf(string2, kSize, "FTOB_0/FLTB_0/FSTR_%i", icopy); + string2 = fmt::format("FTOB_0/FLTB_0/FSTR_{:d}", icopy); } if (iplate > 2) { - snprintf(string2, kSize, "FTOC_0/FLTC_0/FSTR_%i", icopy); + string2 = fmt::format("FTOC_0/FLTC_0/FSTR_{:d}", icopy); } } Int_t padz = ind[3] + 1; Int_t padx = ind[4] + 1; - snprintf(string3, kSize, "FPCB_1/FSEN_1/FSEZ_%i/FPAD_%i", padz, padx); - snprintf(path, 2 * kSize, "%s/%s/%s", string1, string2, string3); + return o2::utils::Str::concat_string(string1, '/', string2, '/', fmt::format("FPCB_1/FSEN_1/FSEZ_{:d}/FPAD_{:d}", padz, padx)); } void Geo::getPos(Int_t* det, Float_t* pos) @@ -228,12 +267,21 @@ void Geo::getDetID(Float_t* pos, Int_t* det) } det[0] = getSector(posLocal); + if (det[0] == -1) { + return; + } fromGlobalToSector(posLocal, det[0]); det[1] = getPlate(posLocal); + if (det[1] == -1) { + return; + } det[2] = fromPlateToStrip(posLocal, det[1]); + if (det[2] == -1) { + return; + } det[3] = getPadZ(posLocal); det[4] = getPadX(posLocal); @@ -244,30 +292,16 @@ void Geo::getVolumeIndices(Int_t index, Int_t* detId) // // Retrieve volume indices from the calibration channel index // - Int_t npadxstrip = NPADX * NPADZ; - - detId[0] = index / npadxstrip / NSTRIPXSECTOR; - - Int_t dummyStripPerModule = - (index - (NSTRIPXSECTOR * npadxstrip * detId[0])) / npadxstrip; - if (dummyStripPerModule < NSTRIPC) { - detId[1] = 0; - detId[2] = dummyStripPerModule; - } else if (dummyStripPerModule >= NSTRIPC && dummyStripPerModule < NSTRIPC + NSTRIPB) { - detId[1] = 1; - detId[2] = dummyStripPerModule - NSTRIPC; - } else if (dummyStripPerModule >= NSTRIPC + NSTRIPB && dummyStripPerModule < NSTRIPC + NSTRIPB + NSTRIPA) { - detId[1] = 2; - detId[2] = dummyStripPerModule - NSTRIPC - NSTRIPB; - } else if (dummyStripPerModule >= NSTRIPC + NSTRIPB + NSTRIPA && dummyStripPerModule < NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB) { - detId[1] = 3; - detId[2] = dummyStripPerModule - NSTRIPC - NSTRIPB - NSTRIPA; - } else if (dummyStripPerModule >= NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB && dummyStripPerModule < NSTRIPXSECTOR) { - detId[1] = 4; - detId[2] = dummyStripPerModule - NSTRIPC - NSTRIPB - NSTRIPA - NSTRIPB; - } - - Int_t padPerStrip = (index - (NSTRIPXSECTOR * npadxstrip * detId[0])) - dummyStripPerModule * npadxstrip; + + if (mToBeIntit) { + InitIndices(); + } + detId[0] = index * NPADS_INV_INT * NSTRIPXSECTOR_INV_INT; + + Int_t dummyStripPerModule = index / NPADS - NSTRIPXSECTOR * detId[0]; + detId[1] = mPlate[dummyStripPerModule]; + detId[2] = mStripInPlate[dummyStripPerModule]; + Int_t padPerStrip = index - (NSTRIPXSECTOR * detId[0] + dummyStripPerModule) * NPADS; detId[3] = padPerStrip / NPADX; // padZ detId[4] = padPerStrip - detId[3] * NPADX; // padX @@ -399,22 +433,56 @@ Int_t Geo::fromPlateToStrip(Float_t* pos, Int_t iplate) Float_t step[3]; // FTOA/B/C = FLTA/B/C reference frame -> FSTR reference frame - for (Int_t istrip = 0; istrip < nstrips; istrip++) { + + // we restrict the search of the strip to a more reasonable range, considering that the + // DISTANCES are never larger than 10 between consecutive strips + auto ilower = std::lower_bound(mDistances[iplate].begin(), mDistances[iplate].end(), -pos[2]); + int stripFound = mDistances[iplate].size() - 1 - std::distance(mDistances[iplate].begin(), ilower); + int firstStripToCheck = stripFound; + int lastStripToCheck = stripFound; + if (stripFound != 0) { + while (std::abs(pos[2] + DISTANCES[iplate][firstStripToCheck - 1]) < 10) { + --firstStripToCheck; + } + } + if (stripFound != nstrips - 1) { + while (std::abs(pos[2] + DISTANCES[iplate][lastStripToCheck + 1]) < 10) { + ++lastStripToCheck; + } + } + + for (Int_t istrip = firstStripToCheck; istrip <= lastStripToCheck; ++istrip) { Float_t posLoc2[3] = {pos[0], pos[1], pos[2]}; step[0] = 0.; step[1] = getHeights(iplate, istrip); step[2] = -getDistances(iplate, istrip); - translate(posLoc2, step); + translate(posLoc2[0], posLoc2[1], posLoc2[2], step); + + if (fabs(posLoc2[1]) > 10) { + continue; + } + if (fabs(posLoc2[2]) > 10) { + continue; + } + + float distanceSquared = posLoc2[1] * posLoc2[1] + posLoc2[2] * posLoc2[2]; + + if (distanceSquared > 45) { + continue; + } + rotateToStrip(posLoc2, iplate, istrip); + if ((TMath::Abs(posLoc2[0]) <= STRIPLENGTH * 0.5) && (TMath::Abs(posLoc2[1]) <= HSTRIPY * 0.5) && (TMath::Abs(posLoc2[2]) <= WCPCBZ * 0.5)) { step[0] = -0.5 * NPADX * XPAD; step[1] = 0.; step[2] = -0.5 * NPADZ * ZPAD; - translate(posLoc2, step); + //translate(posLoc2, step); + translate(posLoc2[0], posLoc2[1], posLoc2[2], step); - for (Int_t jj = 0; jj < 3; jj++) { + for (Int_t jj = 0; jj < 3; ++jj) { pos[jj] = posLoc2[jj]; } @@ -432,25 +500,25 @@ Int_t Geo::getSector(const Float_t* pos) Int_t iSect = -1; - Float_t x = pos[0]; - Float_t y = pos[1]; - Float_t z = pos[2]; + //Float_t x = pos[0]; + //Float_t y = pos[1]; + //Float_t z = pos[2]; - Float_t rho2 = x * x + y * y; + Float_t rho2 = pos[0] * pos[0] + pos[1] * pos[1]; - if (!((z >= -ZLENA * 0.5 && z <= ZLENA * 0.5) && (rho2 >= (RMIN2) && rho2 <= (RMAX2)))) { + if (!((pos[2] >= -ZLENA * 0.5 && pos[2] <= ZLENA * 0.5) && (rho2 >= (RMIN2) && rho2 <= (RMAX2)))) { // AliError("Detector Index could not be determined"); return iSect; } - Float_t phi = TMath::Pi() + TMath::ATan2(-y, -x); + Float_t phi = TMath::Pi() + o2::math_utils::fastATan2(-pos[1], -pos[0]); - iSect = (Int_t)(phi * TMath::RadToDeg() / PHISEC); + iSect = (Int_t)(phi * TMath::RadToDeg() * PHISECINV); return iSect; } -void Geo::getPadDxDyDz(const Float_t* pos, Int_t* det, Float_t* DeltaPos) +void Geo::getPadDxDyDz(const Float_t* pos, Int_t* det, Float_t* DeltaPos, int sector) { // // Returns the x coordinate in the Pad reference frame @@ -463,10 +531,26 @@ void Geo::getPadDxDyDz(const Float_t* pos, Int_t* det, Float_t* DeltaPos) DeltaPos[ii] = pos[ii]; } - det[0] = getSector(DeltaPos); + det[0] = sector; + if (det[0] == -1) { + det[0] = getSector(DeltaPos); + + if (det[0] == -1) { + return; + } + } + fromGlobalToSector(DeltaPos, det[0]); det[1] = getPlate(DeltaPos); + if (det[1] == -1) { + return; + } + det[2] = fromPlateToStrip(DeltaPos, det[1]); + if (det[2] == -1) { + return; + } + det[3] = getPadZ(DeltaPos); det[4] = getPadX(DeltaPos); // translate to the pad center @@ -590,6 +674,23 @@ void Geo::translate(Float_t* xyz, Float_t translationVector[3]) return; } +void Geo::translate(Float_t& x, Float_t& y, Float_t& z, Float_t translationVector[3]) +{ + // + // Return the vector xyz translated by translationVector vector + // + + x -= translationVector[0]; + y -= translationVector[1]; + z -= translationVector[2]; + + /* + for (Int_t ii = 0; ii < 3; ii++) { + xyz[ii] -= translationVector[ii]; + } + */ + return; +} void Geo::antiRotateToSector(Float_t* xyz, Int_t isector) { if (mToBeIntit) { @@ -723,3 +824,32 @@ Int_t Geo::getIndexFromEquipment(Int_t icrate, Int_t islot, Int_t ichain, Int_t { return 0; // to be implemented } + +void Geo::getStripAndModule(Int_t iStripPerSM, Int_t& iplate, Int_t& istrip) +{ + // + // Convert the serial number of the TOF strip number iStripPerSM [0,90] + // in module number iplate [0,4] and strip number istrip [0,14/18]. + // Copied from AliRoot TOF::AliTOFGeometry + // + + if (iStripPerSM < 0 || iStripPerSM >= NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB + NSTRIPC) { + iplate = -1; + istrip = -1; + } else if (iStripPerSM < NSTRIPC) { + iplate = 0; + istrip = iStripPerSM; + } else if (iStripPerSM >= NSTRIPC && iStripPerSM < NSTRIPC + NSTRIPB) { + iplate = 1; + istrip = iStripPerSM - NSTRIPC; + } else if (iStripPerSM >= NSTRIPC + NSTRIPB && iStripPerSM < NSTRIPC + NSTRIPB + NSTRIPA) { + iplate = 2; + istrip = iStripPerSM - NSTRIPC - NSTRIPB; + } else if (iStripPerSM >= NSTRIPC + NSTRIPB + NSTRIPA && iStripPerSM < NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB) { + iplate = 3; + istrip = iStripPerSM - NSTRIPC - NSTRIPB - NSTRIPA; + } else if (iStripPerSM >= NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB && iStripPerSM < NSTRIPC + NSTRIPB + NSTRIPA + NSTRIPB + NSTRIPC) { + iplate = 4; + istrip = iStripPerSM - NSTRIPC - NSTRIPB - NSTRIPA - NSTRIPB; + } +} diff --git a/Detectors/TOF/base/src/Mapping.cxx b/Detectors/TOF/base/src/Mapping.cxx index b20eebd81e8b4..3c9dca3ff90eb 100644 --- a/Detectors/TOF/base/src/Mapping.cxx +++ b/Detectors/TOF/base/src/Mapping.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/src/Strip.cxx b/Detectors/TOF/base/src/Strip.cxx index 82eedd5c561ed..a008776c2690f 100644 --- a/Detectors/TOF/base/src/Strip.cxx +++ b/Detectors/TOF/base/src/Strip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/src/TOFBaseLinkDef.h b/Detectors/TOF/base/src/TOFBaseLinkDef.h index f5cc651c66c47..57c0e232ad8b5 100644 --- a/Detectors/TOF/base/src/TOFBaseLinkDef.h +++ b/Detectors/TOF/base/src/TOFBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/base/src/WindowFiller.cxx b/Detectors/TOF/base/src/WindowFiller.cxx index 492bf51a59914..34709cf8b1704 100644 --- a/Detectors/TOF/base/src/WindowFiller.cxx +++ b/Detectors/TOF/base/src/WindowFiller.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include <algorithm> #include <cassert> #include "FairLogger.h" +#include "DataFormatsTOF/CompressedDataFormat.h" using namespace o2::tof; @@ -106,7 +108,9 @@ void WindowFiller::reset() //______________________________________________________________________ void WindowFiller::fillDigitsInStrip(std::vector<Strip>* strips, int channel, int tdc, int tot, uint64_t nbc, UInt_t istrip, uint32_t triggerorbit, uint16_t triggerbunch) { - (*strips)[istrip].addDigit(channel, tdc, tot, nbc, 0, triggerorbit, triggerbunch); + if (channel > -1) { // check channel validity + (*strips)[istrip].addDigit(channel, tdc, tot, nbc, 0, triggerorbit, triggerbunch); + } } //______________________________________________________________________ void WindowFiller::addCrateHeaderData(unsigned long orbit, int crate, int32_t bc, uint32_t eventCounter) @@ -190,18 +194,51 @@ void WindowFiller::fillOutputContainer(std::vector<Digit>& digits) int npatterns = 0; // check if patterns are in the current row + unsigned int initrow = mFirstIR.orbit * Geo::NWINDOW_IN_ORBIT; for (std::vector<PatternData>::reverse_iterator it = mCratePatterns.rbegin(); it != mCratePatterns.rend(); ++it) { - if (it->row > mReadoutWindowCurrent) { + //printf("pattern row=%ld current=%ld\n",it->row - initrow,mReadoutWindowCurrent); + + if (it->row - initrow > mReadoutWindowCurrent) { break; } - if (it->row < mReadoutWindowCurrent) { // this should not happen + if (it->row - initrow < mReadoutWindowCurrent) { // this should not happen LOG(ERROR) << "One pattern skipped because appears to occur early of the current row " << it->row << " < " << mReadoutWindowCurrent << " ?!"; } else { - mPatterns.push_back(it->pattern); - info.addedDiagnostic(it->icrate); + uint32_t cpatt = it->pattern; + auto dpatt = reinterpret_cast<compressed::Diagnostic_t*>(&cpatt); + uint8_t slot = dpatt->slotID; + uint32_t cbit = 1; + mPatterns.push_back(slot + 28); // add slot + info.addedDiagnostic(it->icrate); npatterns++; + + for (int ibit = 0; ibit < 28; ibit++) { + if (dpatt->faultBits & cbit) { + mPatterns.push_back(ibit); // add bit error + info.addedDiagnostic(it->icrate); + npatterns++; + } + cbit <<= 1; + } + // uint8_t w1 = cpatt & 0xff; + // uint8_t w2 = (cpatt >> 8) & 0xff; + // uint8_t w3 = (cpatt >> 16) & 0xff; + // uint8_t w4 = (cpatt >> 24) & 0xff; + //// cpatt = w1 + (w2 + (w3 + uint(w4)*256)*256)*256; + // mPatterns.push_back(w1); + // info.addedDiagnostic(it->icrate); + // npatterns++; + // mPatterns.push_back(w2); + // info.addedDiagnostic(it->icrate); + // npatterns++; + // mPatterns.push_back(w3); + // info.addedDiagnostic(it->icrate); + // npatterns++; + // mPatterns.push_back(w4); + // info.addedDiagnostic(it->icrate); + // npatterns++; } mCratePatterns.pop_back(); } @@ -265,12 +302,14 @@ void WindowFiller::flushOutputContainer(std::vector<Digit>& digits) checkIfReuseFutureDigitsRO(); } + int nwindowperTF = o2::raw::HBFUtils::Instance().getNOrbitsPerTF() * Geo::NWINDOW_IN_ORBIT; + for (Int_t i = 0; i < MAXWINDOWS; i++) { - fillOutputContainer(digits); // fill last readout windows + if (mReadoutWindowData.size() < nwindowperTF) { + fillOutputContainer(digits); // fill last readout windows + } } - int nwindowperTF = o2::raw::HBFUtils::Instance().getNOrbitsPerTF() * Geo::NWINDOW_IN_ORBIT; - // check that all orbits are complete in terms of number of readout windows while ((mReadoutWindowData.size() % nwindowperTF)) { fillOutputContainer(digits); // fill windows without digits to complete all orbits in the last TF @@ -306,7 +345,7 @@ void WindowFiller::checkIfReuseFutureDigits() int isnext = Int_t(timestamp * Geo::READOUTWINDOW_INV) - (mReadoutWindowCurrent + 1); // to be replaced with uncalibrated time if (isnext < 0) { // we jump too ahead in future, digit will be not stored - LOG(INFO) << "Digit lost because we jump too ahead in future. Current RO window=" << isnext << "\n"; + LOG(DEBUG) << "Digit lost because we jump too ahead in future. Current RO window=" << isnext << "\n"; // remove digit from array in the future int labelremoved = digit->getLabel(); @@ -375,7 +414,7 @@ void WindowFiller::checkIfReuseFutureDigitsRO() // the same but using readout in int isnext = row - mReadoutWindowCurrent; if (isnext < 0) { // we jump too ahead in future, digit will be not stored - LOG(INFO) << "Digit lost because we jump too ahead in future. Current RO window=" << isnext << "\n"; + LOG(DEBUG) << "Digit lost because we jump too ahead in future. Current RO window=" << isnext << "\n"; // remove digit from array in the future int labelremoved = digit->getLabel(); @@ -405,3 +444,50 @@ void WindowFiller::checkIfReuseFutureDigitsRO() // the same but using readout in idigit--; // go back to the next position in the reverse iterator } // close future digit loop } + +void WindowFiller::fillDiagnosticFrequency() +{ + // fill diagnostic frequency + for (int j = 0; j < mReadoutWindowData.size(); j++) { + mDiagnosticFrequency.fillROW(); + for (int ic = 0; ic < 72; ic++) { + int dia = mReadoutWindowData[j].getDiagnosticInCrate(ic); + int slot = 0; + if (mReadoutWindowData[j].isEmptyCrate(ic)) { + mDiagnosticFrequency.fillEmptyCrate(ic); + } + if (dia) { + int fd = mReadoutWindowData[j].firstDia(); + int lastdia = fd + dia; + + ULong64_t key; + for (int dd = fd; dd < lastdia; dd++) { + if (mPatterns[dd] >= 28) { + slot = mPatterns[dd] - 28; + key = (ULong64_t(slot) << 32) + (ULong64_t(ic) << 36); + continue; + } + + key += (1 << mPatterns[dd]); + + if (dd + 1 == lastdia || mPatterns[dd + 1] >= 28) { + mDiagnosticFrequency.fill(key); + } + } + } + } + } + + // fill also noise diagnostic if the counts within the TF is larger than a threashold (default >=11, -> 1 kHZ) + int masknoise = mMaskNoiseRate; + if (masknoise < 0) { + masknoise = -masknoise; + } + + for (int i = 0; i < Geo::NCHANNELS; i++) { + if (mChannelCounts[i] >= masknoise) { + //Fill noisy in diagnostic + mDiagnosticFrequency.fillNoisy(i); + } + } +} diff --git a/Detectors/TOF/base/test/testTOFIndex.cxx b/Detectors/TOF/base/test/testTOFIndex.cxx index beec1680ef462..f311a055955b6 100644 --- a/Detectors/TOF/base/test/testTOFIndex.cxx +++ b/Detectors/TOF/base/test/testTOFIndex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,6 +32,8 @@ BOOST_AUTO_TEST_CASE(testTOFIndex) Bool_t ErrorPx = 0; Bool_t ErrorPz = 0; + o2::tof::Geo::InitIndices(); + for (Int_t i = 0; i < Geo::NSECTORS; i++) { // Loop on all Sectors indextof[0] = i; for (Int_t j = 0; j < Geo::NPLATES; j++) { // Loop on all Plates diff --git a/Detectors/TOF/calibration/CMakeLists.txt b/Detectors/TOF/calibration/CMakeLists.txt index 75c7ce9d792a8..5aa860652a7a2 100644 --- a/Detectors/TOF/calibration/CMakeLists.txt +++ b/Detectors/TOF/calibration/CMakeLists.txt @@ -1,75 +1,123 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFCalibration + TARGETVARNAME targetName SOURCES src/CalibTOFapi.cxx - src/CalibTOF.cxx - src/CollectCalibInfoTOF.cxx + src/CalibTOF.cxx + src/CollectCalibInfoTOF.cxx src/LHCClockCalibrator.cxx - src/TOFChannelCalibrator.cxx - src/TOFCalibCollector.cxx + src/TOFChannelCalibrator.cxx + src/TOFCalibCollector.cxx + src/TOFDCSProcessor.cxx + src/TOFFEElightReader.cxx + src/TOFFEElightConfig.cxx + src/TOFDiagnosticCalibrator.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF O2::TOFBase O2::CCDB - O2::DetectorsCalibration - ROOT::Minuit - ms_gsl::ms_gsl) - - + O2::DetectorsCalibration + O2::DetectorsDCS + ROOT::Minuit + Microsoft.GSL::GSL) + + o2_target_root_dictionary(TOFCalibration HEADERS include/TOFCalibration/CalibTOFapi.h include/TOFCalibration/CalibTOF.h include/TOFCalibration/LHCClockCalibrator.h include/TOFCalibration/TOFChannelCalibrator.h include/TOFCalibration/TOFCalibCollector.h - include/TOFCalibration/CollectCalibInfoTOF.h) + include/TOFCalibration/CollectCalibInfoTOF.h + include/TOFCalibration/TOFDCSProcessor.h + include/TOFCalibration/TOFFEElightReader.h + include/TOFCalibration/TOFFEElightConfig.h + include/TOFCalibration/TOFDiagnosticCalibrator.h) +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() o2_add_executable(data-generator-workflow COMPONENT_NAME calibration SOURCES testWorkflow/data-generator-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::DataFormatsTOF - O2::TOFBase) + O2::DataFormatsTOF + O2::TOFBase) + +o2_add_executable(data-generator-diagnostic-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/data-generator-diagnostic-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsTOF + O2::TOFBase) o2_add_executable(lhc-clockphase-workflow COMPONENT_NAME calibration SOURCES testWorkflow/lhc-clockphase-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration) + O2::TOFCalibration + O2::DetectorsCalibration) o2_add_executable(tof-channel-calib-workflow COMPONENT_NAME calibration SOURCES testWorkflow/tof-channel-calib-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration) + O2::TOFCalibration + O2::DetectorsCalibration) o2_add_executable(tof-calib-workflow COMPONENT_NAME calibration SOURCES testWorkflow/tof-calib-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration) + O2::TOFCalibration + O2::DetectorsCalibration) o2_add_executable(tof-dummy-ccdb-for-calib COMPONENT_NAME calibration SOURCES testWorkflow/tof-dummy-ccdb-for-calib.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration) + O2::TOFCalibration + O2::DetectorsCalibration) o2_add_executable(tof-collect-calib-workflow COMPONENT_NAME calibration SOURCES testWorkflow/tof-collect-calib-workflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework - O2::TOFCalibration - O2::DetectorsCalibration) + O2::TOFCalibration + O2::DetectorsCalibration) + +o2_add_executable(tof-dcs-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/tof-dcs-data-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::TOFCalibration + O2::DetectorsDCS) + +o2_add_executable(tof-dcs-sim-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/tof-dcs-sim-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) + +o2_add_executable(tof-dcs-config-processor-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/tof-dcs-config-processor-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::TOFCalibration + O2::DetectorsCalibration) + +o2_add_executable(tof-diagnostic-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/tof-diagnostic-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::TOFCalibration + O2::DetectorsCalibration) diff --git a/Detectors/TOF/calibration/include/TOFCalibration/CalibTOF.h b/Detectors/TOF/calibration/include/TOFCalibration/CalibTOF.h index 20b3c9383501b..229b79d1ac442 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/CalibTOF.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/CalibTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/include/TOFCalibration/CalibTOFapi.h b/Detectors/TOF/calibration/include/TOFCalibration/CalibTOFapi.h index 564d7590feb0a..c2d3e397ef1cb 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/CalibTOFapi.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/CalibTOFapi.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/include/TOFCalibration/CollectCalibInfoTOF.h b/Detectors/TOF/calibration/include/TOFCalibration/CollectCalibInfoTOF.h index 702961afc0f21..a566bc509f8f7 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/CollectCalibInfoTOF.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/CollectCalibInfoTOF.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h b/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h index 09ef16b5dc1b9..e1803ccd740ea 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFCalibCollector.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFCalibCollector.h index a5a664b8e9208..230e17d771192 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/TOFCalibCollector.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFCalibCollector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "DetectorsCalibration/TimeSlotCalibration.h" #include "DetectorsCalibration/TimeSlot.h" #include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/CalibInfoCluster.h" #include "TOFBase/Geo.h" #include "DataFormatsTOF/CalibInfoTOFshort.h" @@ -45,6 +47,7 @@ class TOFCalibInfoSlot void print() const; void printEntries() const; void fill(const gsl::span<const o2::dataformats::CalibInfoTOF> data); + void fill(const gsl::span<const o2::tof::CalibInfoCluster> data); void merge(const TOFCalibInfoSlot* prev); auto& getEntriesPerChannel() const { return mEntriesSlot; } diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFChannelCalibrator.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFChannelCalibrator.h index 9927e1e549354..56eafad4fc8ce 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/TOFChannelCalibrator.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFChannelCalibrator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "DetectorsCalibration/TimeSlotCalibration.h" #include "DetectorsCalibration/TimeSlot.h" #include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/CalibInfoCluster.h" #include "DataFormatsTOF/CalibLHCphaseTOF.h" #include "TOFBase/Geo.h" #include "CCDB/CcdbObjectInfo.h" @@ -22,6 +24,21 @@ #include <array> #include <boost/histogram.hpp> +#include "TGraphErrors.h" +#include "TF1.h" +#include "MathUtils/fit.h" +#include "TLinearFitter.h" +#include "Fit/Fitter.h" + +#include "DetectorsCalibration/Utils.h" +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include <boost/format.hpp> + +using o2::math_utils::fitGaus; + namespace o2 { namespace tof @@ -35,14 +52,14 @@ class TOFChannelData using boostHisto = boost::histogram::histogram<std::tuple<boost::histogram::axis::regular<double, boost::use_default, boost::use_default, boost::use_default>, boost::histogram::axis::integer<>>, boost::histogram::unlimited_storage<std::allocator<char>>>; public: - static constexpr int NCHANNELSXSECTOR = o2::tof::Geo::NCHANNELS / o2::tof::Geo::NSECTORS; + static constexpr int NCOMBINSTRIP = o2::tof::Geo::NPADX + o2::tof::Geo::NPADS; TOFChannelData() { LOG(INFO) << "Default c-tor, not to be used"; } - TOFChannelData(int nb, float r, CalibTOFapi* cta) : mNBins(nb), mRange(r), mCalibTOFapi(cta) + TOFChannelData(int nb, float r, CalibTOFapi* cta, int nElsPerSector = o2::tof::Geo::NPADSXSECTOR) : mNBins(nb), mRange(r), mCalibTOFapi(cta), mNElsPerSector(nElsPerSector) { if (r <= 0. || nb < 1) { throw std::runtime_error("Wrong initialization of the histogram"); @@ -50,9 +67,9 @@ class TOFChannelData mV2Bin = mNBins / (2 * mRange); for (int isect = 0; isect < 18; isect++) { mHisto[isect] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(mNBins, -mRange, mRange, "t-texp"), - boost::histogram::axis::integer<>(0, o2::tof::Geo::NPADSXSECTOR, "channel index in sector" + std::to_string(isect))); // bin is defined as [low, high[ + boost::histogram::axis::integer<>(0, mNElsPerSector, "channel index in sector" + std::to_string(isect))); // bin is defined as [low, high[ } - mEntries.resize(o2::tof::Geo::NCHANNELS, 0); + mEntries.resize(mNElsPerSector * 18, 0); } ~TOFChannelData() = default; @@ -61,6 +78,7 @@ class TOFChannelData void print(int isect) const; void printEntries() const; void fill(const gsl::span<const o2::dataformats::CalibInfoTOF> data); + void fill(const gsl::span<const o2::tof::CalibInfoCluster> data); void merge(const TOFChannelData* prev); int findBin(float v) const; float integral(int chmin, int chmax, float binmin, float binmax) const; @@ -91,11 +109,13 @@ class TOFChannelData std::vector<int> mEntries; // vector containing number of entries per channel CalibTOFapi* mCalibTOFapi = nullptr; // calibTOFapi to correct the t-text + int mNElsPerSector = o2::tof::Geo::NPADSXSECTOR; ClassDefNV(TOFChannelData, 1); }; -class TOFChannelCalibrator final : public o2::calibration::TimeSlotCalibration<o2::dataformats::CalibInfoTOF, o2::tof::TOFChannelData> +template <class T> +class TOFChannelCalibrator final : public o2::calibration::TimeSlotCalibration<T, o2::tof::TOFChannelData> { using TFType = uint64_t; using Slot = o2::calibration::TimeSlot<o2::tof::TOFChannelData>; @@ -105,16 +125,77 @@ class TOFChannelCalibrator final : public o2::calibration::TimeSlotCalibration<o using CcdbObjectInfoVector = std::vector<CcdbObjectInfo>; using TimeSlewingVector = std::vector<TimeSlewing>; + protected: + std::deque<o2::calibration::TimeSlot<o2::tof::TOFChannelData>>& getSlots() { return o2::calibration::TimeSlotCalibration<T, o2::tof::TOFChannelData>::getSlots(); } + public: - static const int NCHANNELSXSECTOR = o2::tof::Geo::NCHANNELS / o2::tof::Geo::NSECTORS; - TOFChannelCalibrator(int minEnt = 500, int nb = 1000, float r = 24400) : mMinEntries(minEnt), mNBins(nb), mRange(r){}; + static double FuncDeltaOffset(double* x, double* params) + { + int i1 = int(x[0]) % 96; + int i2 = int(x[0]) / 96 ? (i1 + 48) : (i1 + 1); + + if (i1 < 0) { + return 0; + } + if (i2 >= Geo::NPADS) { + return 0; + } + + return (params[i1] - params[i2]); + } + + static constexpr int NCOMBINSTRIP = o2::tof::Geo::NPADX + o2::tof::Geo::NPADS; + static constexpr int NMAXTHREADS = o2::tof::Geo::NSECTORS; // number of max threads that we allow OpenMP to use; + // since at max we parallelize the processing of the sectors, + // the number if sectors is what we use + + TOFChannelCalibrator(int minEnt = 500, int nb = 1000, float r = 24400) : mMinEntries(minEnt), mNBins(nb), mRange(r) + { + setStripFunction(); + for (int i = 0; i < NMAXTHREADS; ++i) { + //mLinFitters[i] = new TLinearFitter(3, "pol2"); + mLinFitters[i].SetDim(3); + mLinFitters[i].SetFormula("pol2"); + } + } ~TOFChannelCalibrator() final = default; - bool hasEnoughData(const Slot& slot) const final; - void initOutput() final; - void finalizeSlot(Slot& slot) final; - Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + bool hasEnoughData(const Slot& slot) const final + { + // Checking if all channels have enough data to do calibration. + // Delegating this to TOFChannelData + const o2::tof::TOFChannelData* c = slot.getContainer(); + LOG(DEBUG) << "Checking statistics"; + return (mTest ? true : c->hasEnoughData(mMinEntries)); + } + + void initOutput() final + { + // Here we initialize the vector of our output objects + mInfoVector.clear(); + mTimeSlewingVector.clear(); + return; + } + + void finalizeSlot(Slot& slot) final + { + // here we simply decide which finalize to call: for the use case with Tracks or cosmics + mCalibWithCosmics ? finalizeSlotWithCosmics(slot) : finalizeSlotWithTracks(slot); + return; + } + + void finalizeSlotWithCosmics(Slot& slot); + void finalizeSlotWithTracks(Slot& slot); + + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final + { + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + int nElements = mCalibWithCosmics ? NCOMBINSTRIP * Geo::NSTRIPXSECTOR : Geo::NPADSXSECTOR; // if we calibrate with cosmics, we pass the number of possible combinations per sector; otherwise, the number of pads per sector + slot.setContainer(std::make_unique<TOFChannelData>(mNBins, mRange, mCalibTOFapi, nElements)); + return slot; + } const TimeSlewingVector& getTimeSlewingVector() const { return mTimeSlewingVector; } const CcdbObjectInfoVector& getTimeSlewingInfoVector() const { return mInfoVector; } @@ -129,6 +210,52 @@ class TOFChannelCalibrator final : public o2::calibration::TimeSlotCalibration<o void setRange(float r) { mRange = r; } float getRange() const { return mRange; } + void setDoCalibWithCosmics(bool doCalibWithCosmics = true) { mCalibWithCosmics = doCalibWithCosmics; } + bool doCalibWithCosmics() const { return mCalibWithCosmics; } + + void setNThreads(int n) { mNThreads = std::min(n, NMAXTHREADS); } + int getNThreads() const { return mNThreads; } + + void setStripFunction() + { + mStripOffsetFunction.clear(); + for (int i = 0; i < 96; i++) { + int irow = i % 48; + int icolumn = i / 48; + if (i > 0) { + mStripOffsetFunction.append(Form("++ (")); + } else { + mStripOffsetFunction.append(Form("(")); + } + bool kadd = false; + if (irow < 47) { + mStripOffsetFunction.append(Form("(x > %d && x < %d)", irow + icolumn * 48, irow + icolumn * 48 + 1)); + kadd = true; + } + if (irow > 0) { + mStripOffsetFunction.append("-"); + mStripOffsetFunction.append(Form("(x > %d && x < %d)", irow + icolumn * 48 - 1, irow + icolumn * 48)); + kadd = true; + } + if (icolumn < 1) { + if (kadd) { + mStripOffsetFunction.append("+"); + } + mStripOffsetFunction.append(Form("(x > %d && x < %d)", irow + 96, irow + 96 + 1)); + } else { + mStripOffsetFunction.append("-"); + mStripOffsetFunction.append(Form("(x > %d && x < %d)", irow + 96, irow + 96 + 1)); + } + mStripOffsetFunction.append(Form(") ")); + } + TLinearFitter localFitter2(1, mStripOffsetFunction.c_str()); // this is a workaround: when we define the TLinearFitter, + // the function is sort of added in some global namespace + // or somthing analogous; when then we use more than 1 thread, + // the threads conflict with each other in this operation, and + // it does not work. So we do the operation of adding the + // function to this global namespece in advance. + } + private: int mMinEntries = 0; // min number of entries to calibrate the TimeSlot int mNBins = 0; // bins of the histogram with the t-text per channel @@ -146,6 +273,14 @@ class TOFChannelCalibrator final : public o2::calibration::TimeSlotCalibration<o // and will go to the CCDB. Note that for the channel offset // we still fill the TimeSlewing object + bool mCalibWithCosmics = false; // flag to indicate whether we are calibrating with cosmics + + int mNThreads = 0; // number of threads from OpenMP + + std::string mStripOffsetFunction; // TLinear functon for fitting channel offset within the strip in cosmic data + + TLinearFitter mLinFitters[NMAXTHREADS]; // fitters for OpenMP for fitGaus + ClassDefOverride(TOFChannelCalibrator, 1); }; diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFDCSProcessor.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFDCSProcessor.h new file mode 100644 index 0000000000000..193dcd71c19f9 --- /dev/null +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFDCSProcessor.h @@ -0,0 +1,168 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTOR_TOFDCSPROCESSOR_H_ +#define DETECTOR_TOFDCSPROCESSOR_H_ + +#include <memory> +#include <Rtypes.h> +#include <unordered_map> +#include <deque> +#include <numeric> +#include "Framework/Logger.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DeliveryType.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" +#include <gsl/gsl> +#include "TOFBase/Geo.h" + +/// @brief Class to process DCS data points + +namespace o2 +{ +namespace tof +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; + +struct TOFDCSinfo { + std::pair<uint64_t, double> firstValue; // first value seen by the TOF DCS processor + std::pair<uint64_t, double> lastValue; // last value seen by the TOF DCS processor + std::pair<uint64_t, double> midValue; // mid value seen by the TOF DCS processor + std::pair<uint64_t, double> maxChange; // maximum variation seen by the TOF DCS processor + TOFDCSinfo() + { + firstValue = std::make_pair(0, -999999999); + lastValue = std::make_pair(0, -999999999); + midValue = std::make_pair(0, -999999999); + maxChange = std::make_pair(0, -999999999); + } + void makeEmpty() + { + firstValue.first = lastValue.first = midValue.first = maxChange.first = 0; + firstValue.second = lastValue.second = midValue.second = maxChange.second = -999999999; + } + void print() const; + + ClassDefNV(TOFDCSinfo, 1); +}; + +struct TOFFEACinfo { + std::array<int32_t, 6> stripInSM = {-1, -1, -1, -1, -1, -1}; + int32_t firstPadX = -1; + int32_t lastPadX = -1; +}; + +class TOFDCSProcessor +{ + + public: + using TFType = uint64_t; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + using DQDoubles = std::deque<double>; + + static constexpr int NFEACS = 8; + static constexpr int NDDLS = Geo::kNDDL * Geo::NSECTORS; + + TOFDCSProcessor() = default; + ~TOFDCSProcessor() = default; + + void init(const std::vector<DPID>& pids); + + //int process(const std::vector<DPCOM>& dps); + int process(const gsl::span<const DPCOM> dps); + int processDP(const DPCOM& dpcom); + uint64_t processFlags(uint64_t flag, const char* pid); + + void updateDPsCCDB(); + void getStripsConnectedToFEAC(int nDDL, int nFEAC, TOFFEACinfo& info) const; + void updateFEACCCDB(); + void updateHVCCDB(); + + const CcdbObjectInfo& getccdbDPsInfo() const { return mccdbDPsInfo; } + CcdbObjectInfo& getccdbDPsInfo() { return mccdbDPsInfo; } + const std::unordered_map<DPID, TOFDCSinfo>& getTOFDPsInfo() const { return mTOFDCS; } + + const CcdbObjectInfo& getccdbLVInfo() const { return mccdbLVInfo; } + CcdbObjectInfo& getccdbLVInfo() { return mccdbLVInfo; } + const std::bitset<Geo::NCHANNELS>& getLVStatus() const { return mFeac; } + bool isLVUpdated() const { return mUpdateFeacStatus; } + + const CcdbObjectInfo& getccdbHVInfo() const { return mccdbHVInfo; } + CcdbObjectInfo& getccdbHVInfo() { return mccdbHVInfo; } + const std::bitset<Geo::NCHANNELS>& getHVStatus() const { return mHV; } + bool isHVUpdated() const { return mUpdateHVStatus; } + + template <typename T> + void prepareCCDBobjectInfo(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, + const std::map<std::string, std::string>& md); + + void setTF(TFType tf) { mTF = tf; } + void useVerboseMode() { mVerbose = true; } + + void clearDPsinfo() + { + mDpsdoublesmap.clear(); + mTOFDCS.clear(); + } + + private: + std::unordered_map<DPID, TOFDCSinfo> mTOFDCS; // this is the object that will go to the CCDB + std::unordered_map<DPID, bool> mPids; // contains all PIDs for the processor, the bool + // will be true if the DP was processed at least once + std::unordered_map<DPID, std::vector<DPVAL>> mDpsdoublesmap; // this is the map that will hold the DPs for the + // double type (voltages and currents) + + std::array<std::array<TOFFEACinfo, NFEACS>, NDDLS> mFeacInfo; // contains the strip/pad info per FEAC + std::array<std::bitset<8>, NDDLS> mPrevFEACstatus; // previous FEAC status + std::bitset<Geo::NCHANNELS> mFeac; // bitset with feac status per channel + bool mUpdateFeacStatus = false; // whether to update the FEAC status in CCDB or not + std::bitset<Geo::NCHANNELS> mHV; // bitset with HV status per channel + std::array<std::array<std::bitset<19>, Geo::NSECTORS>, Geo::NPLATES> mPrevHVstatus; // previous HV status + bool mUpdateHVStatus = false; // whether to update the HV status in CCDB or not + CcdbObjectInfo mccdbDPsInfo; + CcdbObjectInfo mccdbLVInfo; + CcdbObjectInfo mccdbHVInfo; + TFType mStartTF; // TF index for processing of first processed TF, used to store CCDB object + TFType mTF = 0; // TF index for processing, used to store CCDB object + bool mStartTFset = false; + + bool mVerbose = false; + + ClassDefNV(TOFDCSProcessor, 0); +}; + +template <typename T> +void TOFDCSProcessor::prepareCCDBobjectInfo(T& obj, CcdbObjectInfo& info, const std::string& path, TFType tf, + const std::map<std::string, std::string>& md) +{ + + // prepare all info to be sent to CCDB for object obj + auto clName = o2::utils::MemFileHelper::getClassName(obj); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + info.setPath(path); + info.setObjectType(clName); + info.setFileName(flName); + info.setStartValidityTimestamp(tf); + info.setEndValidityTimestamp(99999999999999); + info.setMetaData(md); +} + +} // namespace tof +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFDiagnosticCalibrator.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFDiagnosticCalibrator.h new file mode 100644 index 0000000000000..2a0455bf53f1a --- /dev/null +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFDiagnosticCalibrator.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TOF_DIAGNOSTIC_CALIBRATION_H_ +#define TOF_DIAGNOSTIC_CALIBRATION_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsTOF/Diagnostic.h" +#include "CCDB/CcdbObjectInfo.h" + +namespace o2 +{ +namespace tof +{ + +class TOFDiagnosticCalibrator final : public o2::calibration::TimeSlotCalibration<o2::tof::Diagnostic, o2::tof::Diagnostic> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<o2::tof::Diagnostic>; + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + using CcdbObjectInfoVector = std::vector<CcdbObjectInfo>; + + public: + TOFDiagnosticCalibrator() = default; + ~TOFDiagnosticCalibrator() final = default; + bool hasEnoughData(const Slot& slot) const final { return true; } + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + + const std::vector<Diagnostic>& getDiagnosticVector() const { return mDiagnosticVector; } + const CcdbObjectInfoVector& getDiagnosticInfoVector() const { return mccdbInfoVector; } + CcdbObjectInfoVector& getDiagnosticInfoVector() { return mccdbInfoVector; } + + private: + CcdbObjectInfoVector mccdbInfoVector; + std::vector<Diagnostic> mDiagnosticVector; + + ClassDefOverride(TOFDiagnosticCalibrator, 1); +}; + +} // end namespace tof +} // end namespace o2 + +#endif /* TOF_DIAGNOSTIC_CALIBRATION_H_ */ diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightConfig.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightConfig.h new file mode 100644 index 0000000000000..4706c29570288 --- /dev/null +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightConfig.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTOR_TOFFEELIGHTCONFIG_H_ +#define DETECTOR_TOFFEELIGHTCONFIG_H_ + +#include "Rtypes.h" +#include "TOFBase/Geo.h" +#include <array> + +using namespace o2::tof; + +namespace o2 +{ +namespace tof +{ + +struct TOFFEEchannelConfig { + + enum EStatus_t { + kStatusEnabled = 0x1 + }; + unsigned char mStatus = 0x0; // status + int mMatchingWindow = 0; // matching window [ns] // can this be int32? + int mLatencyWindow = 0; // latency window [ns] // can this be int32? + TOFFEEchannelConfig() = default; + bool isEnabled() const { return mStatus & kStatusEnabled; }; + + ClassDefNV(TOFFEEchannelConfig, 1); +}; + +//_____________________________________________________________________________ + +struct TOFFEEtriggerConfig { + + unsigned int mStatusMap = 0; // status // can it be uint32? + TOFFEEtriggerConfig() = default; + + ClassDefNV(TOFFEEtriggerConfig, 1); +}; + +//_____________________________________________________________________________ + +struct TOFFEElightConfig { + + static constexpr int NCHANNELS = 172800; + static constexpr int NTRIGGERMAPS = Geo::kNCrate; + + int mVersion = 0; // version + int mRunNumber = 0; // run number + int mRunType = 0; // run type + + // std::array<TOFFEEchannelConfig, NCHANNELS> mChannelConfig; + TOFFEEchannelConfig mChannelConfig[Geo::kNCrate][Geo::kNTRM - 2][Geo::kNChain][Geo::kNTdc][Geo::kNCh]; // in O2, the number of TRMs is 12, but in the FEE world it is 10 + TOFFEEtriggerConfig mTriggerConfig[NTRIGGERMAPS]; + TOFFEElightConfig() = default; + const TOFFEEchannelConfig* getChannelConfig(int icrate, int itrm, int ichain, int itdc, int ich) const; + const TOFFEEtriggerConfig* getTriggerConfig(int idx) const { return idx < NTRIGGERMAPS ? &mTriggerConfig[idx] : nullptr; } + + ClassDefNV(TOFFEElightConfig, 1); +}; + +} // namespace tof +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightReader.h b/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightReader.h new file mode 100644 index 0000000000000..3aee85a3b0faf --- /dev/null +++ b/Detectors/TOF/calibration/include/TOFCalibration/TOFFEElightReader.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTOR_TOFFEELIGHTREADER_H_ +#define DETECTOR_TOFFEELIGHTREADER_H_ + +#include "Rtypes.h" +#include "TOFCalibration/TOFFEElightConfig.h" +#include "TOFBase/Geo.h" +#include <gsl/span> +#include <memory> + +/// @brief Class to read the TOFFEElight information + +namespace o2 +{ +namespace tof +{ + +using namespace o2::tof; + +struct TOFFEElightInfo { + + int mVersion = -1; // version + int mRunNumber = -1; // run number + int mRunType = -1; // run type + std::array<bool, Geo::NCHANNELS> mChannelEnabled; + std::array<int, Geo::NCHANNELS> mMatchingWindow; // can it be int32_t? + std::array<int, Geo::NCHANNELS> mLatencyWindow; // can it be int32_t? + std::array<uint64_t, TOFFEElightConfig::NTRIGGERMAPS> mTriggerMask; // trigger mask, can it be uint32_t? + TOFFEElightInfo() + { + mVersion = -1; + mRunNumber = -1; + mRunType = -1; + mChannelEnabled.fill(false); + mMatchingWindow.fill(0); + mLatencyWindow.fill(0); + mTriggerMask.fill(0); + } + + void resetAll() + { + mVersion = -1; + mRunNumber = -1; + mRunType = -1; + mChannelEnabled.fill(false); + mMatchingWindow.fill(0); + mLatencyWindow.fill(0); + mTriggerMask.fill(0); + } + + int getVersion() const { return mVersion; } + int getRunNumber() const { return mRunNumber; } + int getRunType() const { return mRunType; } + bool getChannelEnabled(int idx) const { return idx < Geo::NCHANNELS ? mChannelEnabled[idx] : false; } + int getMatchingWindow(int idx) const { return idx < Geo::NCHANNELS ? mMatchingWindow[idx] : 0; } + int getLatencyWindow(int idx) const { return idx < Geo::NCHANNELS ? mLatencyWindow[idx] : 0; } + uint64_t getTriggerMask(int ddl) const { return ddl < TOFFEElightConfig::NTRIGGERMAPS ? mTriggerMask[ddl] : 0; } + + ClassDefNV(TOFFEElightInfo, 1); +}; + +class TOFFEElightReader +{ + + public: + TOFFEElightReader() = default; // default constructor + ~TOFFEElightReader() = default; // default destructor + + void loadFEElightConfig(const char* fileName); // load FEElight config + void loadFEElightConfig(gsl::span<const char> configBuf); // load FEElight config + int parseFEElightConfig(bool verbose = false); // parse FEElight config + + const TOFFEElightConfig* getTOFFEElightConfig() { return mFEElightConfig; } + TOFFEElightInfo& getTOFFEElightInfo() { return mFEElightInfo; } + + private: + const TOFFEElightConfig* mFEElightConfig = nullptr; // FEElight config + TOFFEElightInfo mFEElightInfo; // what will go to CCDB + std::unique_ptr<char[]> mFileLoadBuff; // temporary buffer to be used when we load the configuration from file + + ClassDefNV(TOFFEElightReader, 1); +}; + +} // namespace tof +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/macros/CMakeLists.txt b/Detectors/TOF/calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..473ad71bbe793 --- /dev/null +++ b/Detectors/TOF/calibration/macros/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro( + makeTOFCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +o2_add_test_root_macro( + readTOFDCSentries.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +install( + FILES makeTOFCCDBEntryForDCS.C + readTOFDCSentries.C + DESTINATION share/macro/) + diff --git a/Detectors/TOF/calibration/macros/makeTOFCCDBEntryForDCS.C b/Detectors/TOF/calibration/macros/makeTOFCCDBEntryForDCS.C new file mode 100644 index 0000000000000..e2a3eb912e033 --- /dev/null +++ b/Detectors/TOF/calibration/macros/makeTOFCCDBEntryForDCS.C @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include <unordered_map> +#include <chrono> + +using DPID = o2::dcs::DataPointIdentifier; + +int makeTOFCCDBEntryForDCS(const std::string url = "http://localhost:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for TOF with the configuration for DCS + std::unordered_map<DPID, std::string> dpid2DataDesc; + std::vector<std::string> aliases = {"tof_hv_vp_[00..89]", "tof_hv_vn_[00..89]", "tof_hv_ip_[00..89]", "tof_hv_in_[00..89]"}; + std::vector<std::string> aliasesInt = {"TOF_FEACSTATUS_[00..71]", "TOF_HVSTATUS_SM[00..01]MOD[0..1]"}; + std::vector<std::string> expaliases = o2::dcs::expandAliases(aliases); + std::vector<std::string> expaliasesInt = o2::dcs::expandAliases(aliasesInt); + + DPID dpidtmp; + for (size_t i = 0; i < expaliases.size(); ++i) { + DPID::FILL(dpidtmp, expaliases[i], o2::dcs::DeliveryType::RAW_DOUBLE); + dpid2DataDesc[dpidtmp] = "TOFDATAPOINTS"; + } + for (size_t i = 0; i < expaliasesInt.size(); ++i) { + DPID::FILL(dpidtmp, expaliasesInt[i], o2::dcs::DeliveryType::RAW_INT); + dpid2DataDesc[dpidtmp] = "TOFDATAPOINTS"; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> md; + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc, "TOF/Config/DCSDPconfig", md, ts); + + return 0; +} diff --git a/Detectors/TOF/calibration/macros/readTOFDCSentries.C b/Detectors/TOF/calibration/macros/readTOFDCSentries.C new file mode 100644 index 0000000000000..4e0a280d4da13 --- /dev/null +++ b/Detectors/TOF/calibration/macros/readTOFDCSentries.C @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// macro to read the TOF DCS information from CCDB +// default ts is very big: Saturday, November 20, 2286 5:46:39 PM + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "TOFCalibration/TOFDCSProcessor.h" + +#include <string> +#include <unordered_map> +#include <chrono> +#include <bitset> +#endif + +void readTOFDCSentries(long ts = 9999999999000, const char* ccdb = "http://localhost:8080") +{ + + o2::ccdb::CcdbApi api; + api.init(ccdb); // or http://ccdb-test.cern.ch:8080 + std::map<std::string, std::string> metadata; + if (ts == 9999999999000) { + ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + std::unordered_map<o2::dcs::DataPointIdentifier, o2::tof::TOFDCSinfo>* m = api.retrieveFromTFileAny<std::unordered_map<o2::dcs::DataPointIdentifier, o2::tof::TOFDCSinfo>>("TOF/Calib/DCSDPs", metadata, ts); + std::cout << "size of map = " << m->size() << std::endl; + + for (auto& i : *m) { + std::cout << "id = " << i.first << std::endl; + i.second.print(); + } + + std::bitset<o2::tof::Geo::NCHANNELS>* feac = api.retrieveFromTFileAny<std::bitset<o2::tof::Geo::NCHANNELS>>("TOF/Calib/LVStatus", metadata, ts); + //std::cout << "LV info (FEAC): " << feac->to_string() << std::endl; + std::cout << "LV info (FEAC): number of channels that are ON = " << feac->count() << std::endl; + for (int ich = 0; ich < o2::tof::Geo::NCHANNELS; ++ich) { + if (feac->test(ich) != 0) { + std::cout << "LV for channel " << ich << " is ON" << std::endl; + } + } + + std::bitset<o2::tof::Geo::NCHANNELS>* hv = api.retrieveFromTFileAny<std::bitset<o2::tof::Geo::NCHANNELS>>("TOF/Calib/HVStatus", metadata, ts); + //std::cout << "HV info : " << hv->to_string() << std::endl; + std::cout << "HV info : number of channels that are ON = " << hv->count() << std::endl; + for (int ich = 0; ich < o2::tof::Geo::NCHANNELS; ++ich) { + if (hv->test(ich) != 0) { + std::cout << "HV for channel " << ich << " is ON" << std::endl; + } + } + + return; +} diff --git a/Detectors/TOF/calibration/src/CalibTOF.cxx b/Detectors/TOF/calibration/src/CalibTOF.cxx index 2a1c5890ab108..21e2dac859fd9 100644 --- a/Detectors/TOF/calibration/src/CalibTOF.cxx +++ b/Detectors/TOF/calibration/src/CalibTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/src/CalibTOFapi.cxx b/Detectors/TOF/calibration/src/CalibTOFapi.cxx index 2e994bc802675..36d02ee1ed555 100644 --- a/Detectors/TOF/calibration/src/CalibTOFapi.cxx +++ b/Detectors/TOF/calibration/src/CalibTOFapi.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ void CalibTOFapi::readLHCphase() // getting the LHCphase calibration auto& mgr = CcdbManager::instance(); - mLHCphase = mgr.getForTimeStamp<LhcPhase>("TOF/LHCphase", mTimeStamp); + mLHCphase = mgr.getForTimeStamp<LhcPhase>("TOF/Calib/LHCphase", mTimeStamp); } //______________________________________________________________________ @@ -43,7 +44,7 @@ void CalibTOFapi::readTimeSlewingParam() // it includes also offset and information on problematic auto& mgr = CcdbManager::instance(); - mSlewParam = mgr.getForTimeStamp<SlewParam>("TOF/ChannelCalib", mTimeStamp); + mSlewParam = mgr.getForTimeStamp<SlewParam>("TOF/Calib/ChannelCalib", mTimeStamp); } //______________________________________________________________________ @@ -56,7 +57,7 @@ void CalibTOFapi::writeLHCphase(LhcPhase* phase, std::map<std::string, std::stri auto& mgr = CcdbManager::instance(); CcdbApi api; api.init(mgr.getURL()); - api.storeAsTFileAny(phase, "TOF/LHCphase", metadataLHCphase, minTimeStamp, maxTimeStamp); + api.storeAsTFileAny(phase, "TOF/Calib/LHCphase", metadataLHCphase, minTimeStamp, maxTimeStamp); } //______________________________________________________________________ @@ -70,9 +71,9 @@ void CalibTOFapi::writeTimeSlewingParam(SlewParam* param, std::map<std::string, CcdbApi api; api.init(mgr.getURL()); if (maxTimeStamp == 0) { - api.storeAsTFileAny(param, "TOF/ChannelCalib", metadataChannelCalib, minTimeStamp); + api.storeAsTFileAny(param, "TOF/Calib/ChannelCalib", metadataChannelCalib, minTimeStamp); } else { - api.storeAsTFileAny(param, "TOF/ChannelCalib", metadataChannelCalib, minTimeStamp, maxTimeStamp); + api.storeAsTFileAny(param, "TOF/Calib/ChannelCalib", metadataChannelCalib, minTimeStamp, maxTimeStamp); } } diff --git a/Detectors/TOF/calibration/src/CollectCalibInfoTOF.cxx b/Detectors/TOF/calibration/src/CollectCalibInfoTOF.cxx index 3c96a22781f82..f7bfbf45147c6 100644 --- a/Detectors/TOF/calibration/src/CollectCalibInfoTOF.cxx +++ b/Detectors/TOF/calibration/src/CollectCalibInfoTOF.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/src/LHCClockCalibrator.cxx b/Detectors/TOF/calibration/src/LHCClockCalibrator.cxx index 5391071dd833b..280db7e05780d 100644 --- a/Detectors/TOF/calibration/src/LHCClockCalibrator.cxx +++ b/Detectors/TOF/calibration/src/LHCClockCalibrator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -96,7 +97,7 @@ void LHCClockCalibrator::finalizeSlot(Slot& slot) l.addLHCphase(slot.getTFStart(), fitValues[1]); auto clName = o2::utils::MemFileHelper::getClassName(l); auto flName = o2::ccdb::CcdbApi::generateFileName(clName); - mInfoVector.emplace_back("TOF/LHCphase", clName, flName, md, slot.getTFStart(), 99999999999999); + mInfoVector.emplace_back("TOF/Calib/LHCphase", clName, flName, md, slot.getTFStart(), 99999999999999); mLHCphaseVector.emplace_back(l); slot.print(); diff --git a/Detectors/TOF/calibration/src/TOFCalibCollector.cxx b/Detectors/TOF/calibration/src/TOFCalibCollector.cxx index eef82b962e436..315bfab133db8 100644 --- a/Detectors/TOF/calibration/src/TOFCalibCollector.cxx +++ b/Detectors/TOF/calibration/src/TOFCalibCollector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,6 +51,51 @@ void TOFCalibInfoSlot::fill(const gsl::span<const o2::dataformats::CalibInfoTOF> } } //_____________________________________________ +void TOFCalibInfoSlot::fill(const gsl::span<const o2::tof::CalibInfoCluster> data) +{ + // fill container + // we do not apply any calibration at this stage, it will be applied when we + // process the data before filling the CCDB in the separate process + + // we first order the data that arrived, to improve speed when filling + int nd = data.size(); + LOG(DEBUG) << "entries in incoming data = " << nd; + std::vector<int> ord(nd); + std::iota(ord.begin(), ord.end(), 0); + std::sort(ord.begin(), ord.end(), [&data](int i, int j) { return data[i].getCH() < data[j].getCH(); }); + int chPrev = 0, offsPrev = 0; + for (int i = 0; i < nd; i++) { + const auto& dti = data[ord[i]]; + auto ch = dti.getCH(); + auto dch = dti.getDCH(); + auto dt = dti.getDT(); + auto tot1 = dti.getTOT1(); + auto tot2 = dti.getTOT2(); + + // we order them so that the channel number of the first cluster is smaller than + // the one of the second cluster + if (dch < 0) { + ch += dch; + dt = -dt; + dch = -dch; + float inv = tot1; + tot1 = tot2; + tot2 = inv; + } + + auto offset = offsPrev; + if (ch > chPrev) { + offset += std::accumulate(mEntriesSlot.begin() + chPrev, mEntriesSlot.begin() + ch, 0); + } + offsPrev = offset; + chPrev = ch; + + // TO be adjusted + //mTOFCollectedCalibInfoSlot.emplace(mTOFCollectedCalibInfoSlot.begin() + offset, data[ord[i]].getTimestamp(), data[ord[i]].getDeltaTimePi(), data[ord[i]].getTot(), data[ord[i]].getFlags()); + //mEntriesSlot[ch]++; + } +} +//_____________________________________________ void TOFCalibInfoSlot::merge(const TOFCalibInfoSlot* prev) { // merge data of 2 slots diff --git a/Detectors/TOF/calibration/src/TOFCalibrationLinkDef.h b/Detectors/TOF/calibration/src/TOFCalibrationLinkDef.h index 9b7043720f9f0..380067e313f8c 100644 --- a/Detectors/TOF/calibration/src/TOFCalibrationLinkDef.h +++ b/Detectors/TOF/calibration/src/TOFCalibrationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,13 +25,31 @@ #pragma link C++ class o2::tof::LHCClockCalibrator + ; #pragma link C++ class o2::tof::TOFChannelData + ; -#pragma link C++ class o2::tof::TOFChannelCalibrator + ; +#pragma link C++ class o2::tof::TOFChannelCalibrator < o2::dataformats::CalibInfoTOF> + ; +#pragma link C++ class o2::tof::TOFChannelCalibrator < o2::tof::CalibInfoCluster> + ; #pragma link C++ class o2::calibration::TimeSlot < o2::tof::TOFChannelData> + ; #pragma link C++ class o2::calibration::TimeSlotCalibration < o2::dataformats::CalibInfoTOF, o2::tof::TOFChannelData> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::tof::CalibInfoCluster, o2::tof::TOFChannelData> + ; #pragma link C++ class o2::tof::TOFCalibInfoSlot + ; #pragma link C++ class o2::tof::TOFCalibCollector + ; #pragma link C++ class o2::calibration::TimeSlot < o2::tof::TOFCalibInfoSlot> + ; #pragma link C++ class o2::calibration::TimeSlotCalibration < o2::dataformats::CalibInfoTOF, o2::tof::TOFCalibInfoSlot> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::tof::CalibInfoCluster, o2::tof::TOFCalibInfoSlot> + ; + +#pragma link C++ class std::bitset < o2::tof::Geo::NCHANNELS> + ; +#pragma link C++ struct std::pair < uint64_t, double> + ; +#pragma link C++ struct o2::tof::TOFDCSinfo + ; +#pragma link C++ class std::unordered_map < o2::dcs::DataPointIdentifier, o2::tof::TOFDCSinfo> + ; + +#pragma link C++ struct TOFFEElightInfo + ; +#pragma link C++ struct TOFFEEchannelConfig + ; +#pragma link C++ struct TOFFEEtriggerConfig + ; +#pragma link C++ struct TOFFEElightConfig + ; +#pragma link C++ struct TOFFEElightReader + ; + +#pragma link C++ class o2::calibration::TimeSlot < o2::tof::Diagnostic> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::tof::Diagnostic, o2::tof::Diagnostic> + ; +#pragma link C++ class o2::tof::TOFDiagnosticCalibrator + ; #endif diff --git a/Detectors/TOF/calibration/src/TOFChannelCalibrator.cxx b/Detectors/TOF/calibration/src/TOFChannelCalibrator.cxx index a2d89aa0ec793..2be3af80e09cb 100644 --- a/Detectors/TOF/calibration/src/TOFChannelCalibrator.cxx +++ b/Detectors/TOF/calibration/src/TOFChannelCalibrator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,17 +11,17 @@ #include "TOFCalibration/TOFChannelCalibrator.h" #include "Framework/Logger.h" -#include "MathUtils/fit.h" -#include "CommonUtils/MemFileHelper.h" -#include "CCDB/CcdbApi.h" -#include "DetectorsCalibration/Utils.h" -#include <boost/histogram.hpp> -#include <boost/histogram/ostream.hpp> -#include <boost/format.hpp> #include <cassert> #include <iostream> #include <sstream> #include <TStopwatch.h> +#include "Fit/Fitter.h" +#include "Fit/BinData.h" +#include "Math/WrappedMultiTF1.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif namespace o2 { @@ -31,7 +32,7 @@ using Slot = o2::calibration::TimeSlot<o2::tof::TOFChannelData>; using TimeSlewing = o2::dataformats::CalibTimeSlewingParamTOF; using clbUtils = o2::calibration::Utils; using boost::histogram::indexed; -using o2::math_utils::fitGaus; +using namespace o2::tof; //using boost::histogram::algorithm; // not sure why it does not work... //_____________________________________________ @@ -40,8 +41,8 @@ void TOFChannelData::fill(const gsl::span<const o2::dataformats::CalibInfoTOF> d // fill container for (int i = data.size(); i--;) { auto ch = data[i].getTOFChIndex(); - int sector = ch / o2::tof::Geo::NPADSXSECTOR; - int chInSect = ch % o2::tof::Geo::NPADSXSECTOR; + int sector = ch / Geo::NPADSXSECTOR; + int chInSect = ch % Geo::NPADSXSECTOR; auto dt = data[i].getDeltaTimePi(); auto tot = data[i].getTot(); @@ -56,15 +57,66 @@ void TOFChannelData::fill(const gsl::span<const o2::dataformats::CalibInfoTOF> d } } +//_____________________________________________ +void TOFChannelData::fill(const gsl::span<const o2::tof::CalibInfoCluster> data) +{ + // fill container + for (int i = data.size(); i--;) { + auto ch = data[i].getCH(); + auto dch = data[i].getDCH(); // this is a char! if you print it, you need to cast it to int + auto dt = data[i].getDT(); + auto tot1 = data[i].getTOT1(); + auto tot2 = data[i].getTOT2(); + + // we order them so that the channel number of the first cluster is smaller than + // the one of the second cluster + if (dch < 0) { + ch += dch; + dt = -dt; + dch = -dch; + float inv = tot1; + tot1 = tot2; + tot2 = inv; + } + + int sector = ch / Geo::NPADSXSECTOR; + int absoluteStrip = ch / Geo::NPADS; + int stripInSect = absoluteStrip % Geo::NSTRIPXSECTOR; + int shift = 0; + if (dch == 1) { + shift = 0; // 2nd channel is on the right + } else if (dch == 48) { + shift = 1; // 2nd channel is at the top + } else { + continue; + } + int chOnStrip = ch % 96; + int comb = 96 * shift + chOnStrip; // index of the current pair of clusters on the strip; there are in total 96 + 48 + + auto corr1 = mCalibTOFapi->getTimeCalibration(ch, tot1); // we take into account LHCphase, offsets and time slewing + auto corr2 = mCalibTOFapi->getTimeCalibration(ch + dch, tot2); // we take into account LHCphase, offsets and time slewing + LOG(DEBUG) << "inserting in channel " << ch << ", " << ch + dch << ": dt = " << dt << ", tot1 = " << tot1 << ", tot2 = " << tot2 << ", corr1 = " << corr1 << ", corr2 = " << corr2 << ", corrected dt = " << dt - corr1 + corr2; + + dt -= corr1 - corr2; + + int combInSect = comb + stripInSect * NCOMBINSTRIP; + + LOG(DEBUG) << "ch = " << ch << ", sector = " << sector << ", absoluteStrip = " << absoluteStrip << ", stripInSect = " << stripInSect << ", shift = " << shift << ", dch = " << (int)dch << ", chOnStrip = " << chOnStrip << ", comb = " << comb; + + mHisto[sector](dt, combInSect); // we pass the difference of the *calibrated* times + mEntries[comb + NCOMBINSTRIP * absoluteStrip] += 1; + } +} + //_____________________________________________ void TOFChannelData::merge(const TOFChannelData* prev) { // merge data of 2 slots - for (int isect = 0; isect < o2::tof::Geo::NSECTORS; isect++) { + for (int isect = 0; isect < Geo::NSECTORS; isect++) { mHisto[isect] += prev->getHisto(isect); } - for (int ich = 0; ich < o2::tof::Geo::NCHANNELS; ich++) { - mEntries[ich] += prev->mEntries[ich]; + for (auto iel = 0; iel < mEntries.size(); iel++) { + mEntries[iel] += prev->mEntries[iel]; } } @@ -73,15 +125,48 @@ bool TOFChannelData::hasEnoughData(int minEntries) const { // true if all channels can be fitted --> have enough statistics - // TODO: think of a better logic: it could be that some channels are off or misbehaving and do not - // have enough entries, even if in principle we collected enough + // We consider that we have enough entries if the mean of the number of entries in the channels + // with at least one entry is greater than the cut at "minEntries" + // Channels/pairs with zero entries are assumed to be off --> we do not consider them + + //printEntries(); + int nValid = 0; + float mean = 0; + int smallestElementIndex = -1; + int smallestEntries = 1e5; + int largestElementIndex = -1; + int largestEntries = 0; + for (auto i = 0; i < mEntries.size(); ++i) { + if (mEntries[i] != 0) { // skipping channels/pairs if they have zero entries (most likely they are simply off) + mean += mEntries[i]; + ++nValid; + if (mEntries[i] < smallestEntries) { + smallestEntries = mEntries[i]; + smallestElementIndex = i; + } + if (mEntries[i] > largestEntries) { + largestEntries = mEntries[i]; + largestElementIndex = i; + } + } + } + if (nValid == 0) { + LOG(INFO) << "hasEnough = false: all channels/pairs are empty"; + return false; + } - // we can simply check if the min of the elements of the mEntries vector is >= minEntries - printEntries(); - auto minElementIndex = std::min_element(mEntries.begin(), mEntries.end()); - LOG(INFO) << "minElement is at position " << std::distance(mEntries.begin(), minElementIndex) << " and is " << *minElementIndex; - bool enough = *minElementIndex < minEntries ? false : true; - LOG(INFO) << "hasEnough = (minEntry=" << minEntries << ") " << (int)enough; + LOG(DEBUG) << "mean = " << mean << ", nvalid = " << nValid; + mean /= nValid; + + LOG(DEBUG) << "minElement is at position " << smallestElementIndex << " and has " << smallestEntries << " entries"; + LOG(DEBUG) << "maxElement is at position " << largestElementIndex << " and has " << largestEntries << " entries"; + float threshold = minEntries + 5 * std::sqrt(minEntries); + bool enough = mean < threshold ? false : true; + if (enough) { + LOG(INFO) << "hasEnough: " << (int)enough << " (" + << nValid << " valid channels found (should be " << mEntries.size() << ") with mean = " + << mean << " with cut at = " << threshold << ") "; + } return enough; } @@ -90,7 +175,7 @@ void TOFChannelData::print() const { LOG(INFO) << "Printing histograms:"; std::ostringstream os; - for (int isect = 0; isect < o2::tof::Geo::NSECTORS; isect++) { + for (int isect = 0; isect < Geo::NSECTORS; isect++) { LOG(INFO) << "Sector: " << isect; os << mHisto[isect]; auto nentriesInSec = boost::histogram::algorithm::sum(mHisto[isect]); @@ -136,7 +221,11 @@ void TOFChannelData::printEntries() const { // to print number of entries per channel for (int i = 0; i < mEntries.size(); ++i) { - LOG(INFO) << "channel " << i << " has " << mEntries[i] << " entries"; + if (mEntries.size() > tof::Geo::NCHANNELS) { + LOG(INFO) << "pair of channels " << i << " has " << mEntries[i] << " entries"; + } else { + LOG(INFO) << "channel " << i << " has " << mEntries[i] << " entries"; + } } } @@ -163,20 +252,20 @@ float TOFChannelData::integral(int chmin, int chmax, float binmin, float binmax) { // calculates the integral in [chmin, chmax] and in [binmin, binmax] - if (binmin < -mRange || binmax > mRange || chmin < 0 || chmax >= o2::tof::Geo::NCHANNELS) { + if (binmin < -mRange || binmax > mRange || chmin < 0 || chmax >= Geo::NSECTORS * mNElsPerSector) { throw std::runtime_error("Check your bins, we cannot calculate the integrals in under/overflows bins"); } if (binmax < binmin || chmax < chmin) { throw std::runtime_error("Check your bin limits!"); } - int sector = chmin / o2::tof::Geo::NPADSXSECTOR; - if (sector != chmax / o2::tof::Geo::NPADSXSECTOR) { + int sector = chmin / mNElsPerSector; + if (sector != chmax / mNElsPerSector) { throw std::runtime_error("We cannot integrate over channels that belong to different sectors"); } - int chinsectormin = chmin % o2::tof::Geo::NPADSXSECTOR; - int chinsectormax = chmax % o2::tof::Geo::NPADSXSECTOR; + int chinsectormin = chmin % mNElsPerSector; + int chinsectormax = chmax % mNElsPerSector; float res2 = 0; //TStopwatch t3; @@ -197,82 +286,6 @@ float TOFChannelData::integral(int chmin, int chmax, float binmin, float binmax) return res2; - /* // what is below is only for alternative methods which all proved to be slower - float res = 0, res1 = 0; - //TStopwatch t1, t2, - int startCount = chinsectormin * mNBins + binxmin; - int endCount = chinsectormax * mNBins + binxmax; // = startCount + (chinsectormax - chinsectormin) * mNBins + (binxmax - binxmin); - LOG(DEBUG) << "startCount = " << startCount << " endCount = " << endCount-1; - //t2.Start(); - int counts = -1; - for (auto&& x : indexed(mHisto[sector])) { - counts++; - if (counts < startCount) continue; - if (x.bin(0).lower() > binmax && chinsectormin == chinsectormax) { // all others also will be > but only if chmin = chmax; in the other cases, we should jump to the next row,which for now we cannot do in boost - // LOG(INFO) << "x.bin(0).lower() > binmax && chinsectormin == chinsectormax: BREAKING"; - break; - } - if (x.index(1) > chinsectormax) { // we passed the needed channel - //LOG(INFO) << "x.index(1) > chinsectormax: BREAKING"; - break; - } - if ( (x.bin(0).upper() > binmin) && (x.bin(0).lower() <= binmax) && (x.index(1) >= chinsectormin)) { // I have to keep the condition "&& (x.bin(0).lower() <= binmax)" because I can break only if chmin == chmax - res1 += x.get(); - //if (x.get() != 0) LOG(INFO) << "ind = " << counts << " will add bin " << x.index(0) - // << " along x (in [" << x.bin(0).lower() << ", " - // << x.bin(0).upper() << "], and bin " << x.index(1) << " along y" << " with content " << x.get() << " --> res1 = " << res1; - } - } - //t2.Stop(); - //LOG(DEBUG) << "Time for integral looping over restricted range (result = " << res1 << "):"; - //t2.Print(); - //t1.Start(); - ind = -1; - for (auto&& x : indexed(mHisto[sector])) { - ind++; - if ((x.bin(0).upper() > binmin && x.bin(0).lower() < binmax) && (x.index(1) >= chinsectormin && x.index(1) <= chinsectormax)) { - res += x.get(); - //if (x.get() != 0) LOG(INFO) << "ind = " << ind << " will add bin " << x.index(0) - // << " along x (in [" << x.bin(0).lower() << ", " - // << x.bin(0).upper() << "], and bin " << x.index(1) << " along y" << " with content " << x.get(); - } - } - //t1.Stop(); - //LOG(DEBUG) << "Time for integral looping (result = " << res << "):"; - //t1.Print(); - LOG(DEBUG) << "Reducing... "; - //TStopwatch t; - //t.Start(); - if (binmin == binmax) binmax += 1.e-1; - float chinsectorminfl = float(chinsectormin); - float chinsectormaxfl = float(chinsectormax); - chinsectormaxfl += 1.e-1; // we need to add a bit because the upper value otherwise is not included - LOG(DEBUG) << "chinsectorminfl = " << chinsectorminfl << ", chinsectormaxfl = " << chinsectormaxfl << ", binmin= " << binmin << ", binmax = " << binmax; - LOG(DEBUG) << "chinsectormin = " << chinsectormin << ", chinsectormax = " << chinsectormax; - auto hch = boost::histogram::algorithm::reduce(mHisto[sector], - boost::histogram::algorithm::shrink(1, chinsectorminfl, chinsectormaxfl), - boost::histogram::algorithm::shrink(0, binmin, binmax)); - //t.Stop(); - //LOG(DEBUG) << "Time for projection with shrink"; - //t.Print(); - //LOG(DEBUG) << "...done."; - - //int sizeBeforeAxis1 = mHisto[sector].axis(1).size(); - //int sizeAfterAxis1 = hch.axis(1).size(); - //int sizeBeforeAxis0 = mHisto[sector].axis(0).size(); - //int sizeAfterAxis0 = hch.axis(0).size(); - //std::cout << "axis size before reduction: axis 0: " << sizeBeforeAxis0 << ", axis 1: " << sizeBeforeAxis1 << std::endl; - //std::cout << "axis size after reduction: axis 0: " << sizeAfterAxis0 << ", axis 1: " << sizeAfterAxis1 << std::endl; - - //t.Start(); - auto indhch = indexed(hch); - const double enthchInd = std::accumulate(indhch.begin(), indhch.end(), 0.0); - //t.Stop(); - //LOG(DEBUG) << "Time for accumulate (result = " << enthchInd << ")"; - //t.Print(); - - return enthchInd; -*/ } //_____________________________________________ @@ -288,20 +301,20 @@ float TOFChannelData::integral(int chmin, int chmax, int binxmin, int binxmax) c { // calculates the integral in [chmin, chmax] and in [binmin, binmax] - if (binxmin < 0 || binxmax > mNBins || chmin < 0 || chmax >= o2::tof::Geo::NCHANNELS) { + if (binxmin < 0 || binxmax > mNBins || chmin < 0 || chmax >= Geo::NSECTORS * mNElsPerSector) { throw std::runtime_error("Check your bins, we cannot calculate the integrals in under/overflows bins"); } if (binxmax < binxmin || chmax < chmin) { throw std::runtime_error("Check your bin limits!"); } - int sector = chmin / o2::tof::Geo::NPADSXSECTOR; - if (sector != chmax / o2::tof::Geo::NPADSXSECTOR) { + int sector = chmin / mNElsPerSector; + if (sector != chmax / mNElsPerSector) { throw std::runtime_error("We cannot integrate over channels that belong to different sectors"); } - int chinsectormin = chmin % o2::tof::Geo::NPADSXSECTOR; - int chinsectormax = chmax % o2::tof::Geo::NPADSXSECTOR; + int chinsectormin = chmin % mNElsPerSector; + int chinsectormax = chmax % mNElsPerSector; float res2 = 0; //TStopwatch t3; @@ -317,76 +330,6 @@ float TOFChannelData::integral(int chmin, int chmax, int binxmin, int binxmax) c //t3.Print(); return res2; - /* // all that is below is alternative methods, all proved to be slower - float res = 0, res1 = 0; - //TStopwatch t1, t2; - int ind = -1; - int startCount = chinsectormin * mNBins + binxmin; - int endCount = chinsectormax * mNBins + binxmax; // = startCount + (chinsectormax - chinsectormin) * mNBins + (binxmax - binxmin); - LOG(DEBUG) << "startCount = " << startCount << " endCount = " << endCount-1; - //t2.Start(); - int counts = -1; - for (auto&& x : indexed(mHisto[sector])) { - counts++; - if (counts < startCount) continue; - if (x.index(0) > binxmax && chinsectormin == chinsectormax) { // all others also will be > but only if chmin = chmax; in the other cases, we should jump to the next row,which for now we cannot do in boost - //LOG(INFO) << "x.index(0) > binxmax && chinsectormin == chinsectormax: BREAKING"; - break; - } - if (x.index(1) > chinsectormax) { // we passed the needed channel - //LOG(INFO) << "x.index(1) > chinsectormax) > chinsectormax: BREAKING"; - break; - } - if ( (x.index(0) >= binxmin) && (x.index(0) <= binxmax) && (x.index(1) >= chinsectormin)) { // I have to keep the condition "&& (x.bin(0).lower() <= binmax)" because I can break only if chmin == chmax - res1 += x.get(); - // if (x.get() != 0) - // LOG(INFO) << "ind = " << counts << " will add bin " << x.index(0) - // << " along x (in [" << x.bin(0).lower() << ", " - // << x.bin(0).upper() << "], and bin " << x.index(1) << " along y" << " with content " << x.get() - // << " --> res1 = " << res1; - } - } - //t2.Stop(); - //LOG(DEBUG) << "Time for integral looping over restricted range (result = " << res1 << "):"; - //t2.Print(); - //t1.Start(); - for (auto&& x : indexed(mHisto[sector])) { - ind++; - if ((x.index(0) >= binxmin && x.index(0) <= binxmax) && (x.index(1) >= chinsectormin && x.index(1) <= chinsectormax)) { - res += x.get(); - //LOG(INFO) << "ind = " << ind << " will add bin " << x.index(0) << " along x and bin " << x.index(1) << " along y"; - } - } - //t1.Stop(); - //LOG(DEBUG) << "Time for integral looping (result = " << res << "):"; - //t1.Print(); - //LOG(DEBUG) << "Reducing... "; - //TStopwatch t; - //t.Start(); - auto hch = boost::histogram::algorithm::reduce(mHisto[sector], - boost::histogram::algorithm::slice(1, chinsectormin, chinsectormax+1), - boost::histogram::algorithm::slice(0, binxmin, binxmax+1)); // we need to add "+1" - //t.Stop(); - //LOG(DEBUG) << "Time for projection with slice"; - //t.Print(); - //LOG(INFO) << "...done."; - - //int sizeBeforeAxis1 = mHisto[sector].axis(1).size(); - //int sizeAfterAxis1 = hch.axis(1).size(); - //int sizeBeforeAxis0 = mHisto[sector].axis(0).size(); - //int sizeAfterAxis0 = hch.axis(0).size(); - //std::cout << "axis size before reduction: axis 0: " << sizeBeforeAxis0 << ", axis 1: " << sizeBeforeAxis1 << std::endl; - //std::cout << "axis size after reduction: axis 0: " << sizeAfterAxis0 << ", axis 1: " << sizeAfterAxis1 << std::endl; - - // first way: using indexed (which excludes under/overflow) - //t.Start(); - auto indhch = indexed(hch); - const double enthchInd = std::accumulate(indhch.begin(), indhch.end(), 0.0); - //t.Stop(); - //LOG(DEBUG) << "Time for accumulate (result = " << enthchInd << ")"; - //t.Print(); - return enthchInd; - */ } //_____________________________________________ @@ -402,145 +345,303 @@ float TOFChannelData::integral(int ch) const { // calculates the integral along one fixed channel and in the full x-range - return integral(ch, ch, 0, mNBins - 1); + return mEntries.at(ch); } -//=================================================================== +//------------------------------------------------------------------- +// TOF Channel Calibrator +//------------------------------------------------------------------- -//_____________________________________________ -void TOFChannelCalibrator::initOutput() +template <typename T> +void TOFChannelCalibrator<T>::finalizeSlotWithCosmics(Slot& slot) { - // Here we initialize the vector of our output objects - mInfoVector.clear(); - mTimeSlewingVector.clear(); - return; -} + // Extract results for the single slot -//_____________________________________________ -bool TOFChannelCalibrator::hasEnoughData(const Slot& slot) const -{ + o2::tof::TOFChannelData* c = slot.getContainer(); + LOG(INFO) << "Finalize slot for calibration with cosmics " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + + // for the CCDB entry + std::map<std::string, std::string> md; + TimeSlewing& ts = mCalibTOFapi->getSlewParamObj(); // we take the current CCDB object, since we want to simply update the offset + + int nbins = c->getNbins(); + float range = c->getRange(); + std::vector<int> entriesPerChannel = c->getEntriesPerChannel(); - // Checking if all channels have enough data to do calibration. - // Delegating this to TOFChannelData +#ifdef WITH_OPENMP + if (mNThreads < 1) { + mNThreads = std::min(omp_get_max_threads(), NMAXTHREADS); + } + LOG(DEBUG) << "Number of threads that will be used = " << mNThreads; +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#else + mNThreads = 1; +#endif + for (int sector = 0; sector < Geo::NSECTORS; sector++) { + TMatrixD mat(3, 3); + int ithread = 0; +#ifdef WITH_OPENMP + ithread = omp_get_thread_num(); +#endif + + LOG(INFO) << "Processing sector " << sector << " with thread " << ithread; + double xp[NCOMBINSTRIP], exp[NCOMBINSTRIP], deltat[NCOMBINSTRIP], edeltat[NCOMBINSTRIP]; + + std::array<double, 3> fitValues; + std::vector<float> histoValues; - const o2::tof::TOFChannelData* c = slot.getContainer(); - LOG(INFO) << "Checking statistics"; - return (mTest ? true : c->hasEnoughData(mMinEntries)); + auto& histo = c->getHisto(sector); + + int offsetPairInSector = sector * Geo::NSTRIPXSECTOR * NCOMBINSTRIP; + int offsetsector = sector * Geo::NSTRIPXSECTOR * Geo::NPADS; + for (int istrip = 0; istrip < Geo::NSTRIPXSECTOR; istrip++) { + LOG(INFO) << "Processing strip " << istrip; + double fracUnderPeak[Geo::NPADS] = {0.}; + bool isChON[96] = {false}; + int offsetstrip = istrip * Geo::NPADS + offsetsector; + int goodpoints = 0; + + TLinearFitter localFitter(1, mStripOffsetFunction.c_str()); + + int offsetPairInStrip = istrip * NCOMBINSTRIP; + + localFitter.StoreData(kFALSE); + localFitter.ClearPoints(); + for (int ipair = 0; ipair < NCOMBINSTRIP; ipair++) { + int chinsector = ipair + offsetPairInStrip; + int ich = chinsector + offsetPairInSector; + auto entriesInPair = entriesPerChannel.at(ich); + if (entriesInPair == 0) { + continue; // skip always since a channel with 0 entries is normal, it will be flagged as problematic + } + if (entriesInPair < mMinEntries) { + LOG(DEBUG) << "pair " << ich << " will not be calibrated since it has only " << entriesInPair << " entries (min = " << mMinEntries << ")"; + continue; + } + fitValues.fill(-99999999); + histoValues.clear(); + + // make the slice of the 2D histogram so that we have the 1D of the current channel + for (unsigned i = 0; i < nbins; ++i) { + const auto& v = histo.at(i, chinsector); + LOG(DEBUG) << "channel = " << ich << ", in sector = " << sector << " (where it is channel = " << chinsector << ") bin = " << i << " value = " << v; + histoValues.push_back(v); + } + + double fitres = entriesInPair - 1; + fitres = fitGaus(nbins, histoValues.data(), -range, range, fitValues, nullptr, 2., true); + if (fitres >= 0) { + LOG(DEBUG) << "Pair " << ich << " :: Fit result " << fitres << " Mean = " << fitValues[1] << " Sigma = " << fitValues[2]; + } else { + LOG(DEBUG) << "Pair " << ich << " :: Fit failed with result = " << fitres; + continue; + } + + if (fitValues[2] < 0) { + fitValues[2] = -fitValues[2]; + } + + float intmin = fitValues[1] - 5 * fitValues[2]; // mean - 5*sigma + float intmax = fitValues[1] + 5 * fitValues[2]; // mean + 5*sigma + + if (intmin < -mRange) { + intmin = -mRange; + } + if (intmax < -mRange) { + intmax = -mRange; + } + if (intmin > mRange) { + intmin = mRange; + } + if (intmax > mRange) { + intmax = mRange; + } + + xp[goodpoints] = ipair + 0.5; // pair index + exp[goodpoints] = 0.0; // error on pair index (dummy since it is on the pair index) + deltat[goodpoints] = fitValues[1]; // delta between offsets from channels in pair (from the fit) - in ps + edeltat[goodpoints] = 20 + fitValues[2] / sqrt(entriesInPair); // TODO: for now put by default to 20 ps since it was seen to be reasonable; but it should come from the fit: who gives us the error from the fit ?????? + localFitter.AddPoint(&(xp[goodpoints]), deltat[goodpoints], edeltat[goodpoints]); + goodpoints++; + int ch1 = ipair % 96; + int ch2 = ipair / 96 ? ch1 + 48 : ch1 + 1; + isChON[ch1] = true; + isChON[ch2] = true; + + float fractionUnderPeak = entriesInPair > 0 ? c->integral(ich, intmin, intmax) / entriesInPair : 0; + // we keep as fractionUnderPeak of the channel the largest one that is found in the 3 possible pairs with that channel (for both channels ch1 and ch2 in the pair) + if (fracUnderPeak[ch1] < fractionUnderPeak) { + fracUnderPeak[ch1] = fractionUnderPeak; + } + if (fracUnderPeak[ch2] < fractionUnderPeak) { + fracUnderPeak[ch2] = fractionUnderPeak; + } + } // end loop pairs + + // fit strip offset + if (goodpoints == 0) { + continue; + } + LOG(DEBUG) << "We found " << goodpoints << " good points for strip " << istrip << " in sector " << sector << " --> we can fit the TGraph"; + + bool isFirst = true; + int nparams = 0; + LOG(DEBUG) << "N parameters before fixing = " << localFitter.GetNumberFreeParameters(); + + // we fix to zero the parameters that have no entry, plus the first one that we find, which we will use as reference for the other offsets + for (int i = 0; i < 96; ++i) { + if (isChON[i]) { + if (isFirst) { + localFitter.FixParameter(i, 0.); + isFirst = false; + } else { + nparams++; + } + } else { + localFitter.FixParameter(i, 0.); + } + } + + LOG(DEBUG) << "Strip = " << istrip << " fitted by thread = " << ithread << ", goodpoints = " << goodpoints << ", number of free parameters = " + << localFitter.GetNumberFreeParameters() << ", NDF = " << goodpoints - localFitter.GetNumberFreeParameters(); + + if (goodpoints <= localFitter.GetNumberFreeParameters()) { + LOG(DEBUG) << "Skipped"; + continue; + } + + LOG(DEBUG) << "N real params = " << nparams << ", fitter has " << localFitter.GetNumberFreeParameters() << " free parameters, " << localFitter.GetNumberTotalParameters() << " total parameters, " << localFitter.GetNpoints() << " points"; + LOG(INFO) << "Sector = " << sector << ", strip = " << istrip << " fitted by thread = " << ithread << ": ready to fit"; + localFitter.Eval(); + + LOG(INFO) << "Sector = " << sector << ", strip = " << istrip << " fitted by thread = " << ithread << " with Chi/NDF " << localFitter.GetChisquare() << "/" << goodpoints - localFitter.GetNumberFreeParameters(); + LOG(DEBUG) << "Strip = " << istrip << " fitted by thread = " << ithread << " with Chi/NDF " << localFitter.GetChisquare() << "/" << goodpoints - localFitter.GetNumberFreeParameters(); + + //update calibrations + for (int ichLocal = 0; ichLocal < Geo::NPADS; ichLocal++) { + int ich = ichLocal + offsetstrip; + ts.updateOffsetInfo(ich, localFitter.GetParameter(ichLocal)); + ts.setFractionUnderPeak(ich / Geo::NPADSXSECTOR, ich % Geo::NPADSXSECTOR, fracUnderPeak[ichLocal]); + ts.setSigmaPeak(ich / Geo::NPADSXSECTOR, ich % Geo::NPADSXSECTOR, abs(std::sqrt(localFitter.GetCovarianceMatrixElement(ichLocal, ichLocal)))); + } + + } // end loop strips + } // end loop sectors + + auto clName = o2::utils::MemFileHelper::getClassName(ts); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + mInfoVector.emplace_back("TOF/Calib/ChannelCalib", clName, flName, md, slot.getTFStart(), 99999999999999); + mTimeSlewingVector.emplace_back(ts); } //_____________________________________________ -void TOFChannelCalibrator::finalizeSlot(Slot& slot) + +template <typename T> +void TOFChannelCalibrator<T>::finalizeSlotWithTracks(Slot& slot) { // Extract results for the single slot o2::tof::TOFChannelData* c = slot.getContainer(); LOG(INFO) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + int nbins = c->getNbins(); + float range = c->getRange(); + std::vector<int> entriesPerChannel = c->getEntriesPerChannel(); // for the CCDB entry std::map<std::string, std::string> md; TimeSlewing& ts = mCalibTOFapi->getSlewParamObj(); // we take the current CCDB object, since we want to simply update the offset - for (int ich = 0; ich < o2::tof::Geo::NCHANNELS; ich++) { - // make the slice of the 2D histogram so that we have the 1D of the current channel - int sector = ich / o2::tof::Geo::NPADSXSECTOR; - int chinsector = ich % o2::tof::Geo::NPADSXSECTOR; - std::vector<float> fitValues; +#ifdef WITH_OPENMP + if (mNThreads < 1) { + mNThreads = std::min(omp_get_max_threads(), NMAXTHREADS); + } + LOG(DEBUG) << "Number of threads that will be used = " << mNThreads; +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#else + mNThreads = 1; +#endif + for (int sector = 0; sector < Geo::NSECTORS; sector++) { + TMatrixD mat(3, 3); + int ithread = 0; +#ifdef WITH_OPENMP + ithread = omp_get_thread_num(); +#endif + LOG(INFO) << "Processing sector " << sector << " with thread " << ithread; + auto& histo = c->getHisto(sector); + + std::array<double, 3> fitValues; std::vector<float> histoValues; - /* //less efficient way - int startCount = chinsector * c->getNbins(); - int counts = -1; - for (auto&& x : indexed(c->getHisto(sector))) { - counts++; - if (counts < startCount) continue; - if (x.index(1) > chinsector) { // we passed the needed channel - //LOG(INFO) << "x.index(1) > chinsectormax) > chinsectormax: BREAKING"; - break; + for (int chinsector = 0; chinsector < Geo::NPADSXSECTOR; chinsector++) { + // make the slice of the 2D histogram so that we have the 1D of the current channel + int ich = chinsector + sector * Geo::NPADSXSECTOR; + auto entriesInChannel = entriesPerChannel.at(ich); + if (entriesInChannel == 0) { + continue; // skip always since a channel with 0 entries is normal, it will be flagged as problematic } - histoValues.push_back(x.get()); - } - */ - std::vector<int> entriesPerChannel = c->getEntriesPerChannel(); - if (entriesPerChannel.at(ich) == 0) { - continue; // skip always since a channel with 0 entries is normal, it will be flagged as problematic - if (mTest) { - LOG(DEBUG) << "Skipping channel " << ich << " because it has zero entries, but it should not be"; // should become error! + + if (entriesInChannel < mMinEntries) { + LOG(DEBUG) << "channel " << ich << " will not be calibrated since it has only " << entriesInChannel << " entries (min = " << mMinEntries << ")"; continue; - } else { - throw std::runtime_error("We found one channel with no entries, we cannot calibrate!"); } - } - // more efficient way - auto histo = c->getHisto(sector); - for (unsigned j = chinsector; j <= chinsector; ++j) { - for (unsigned i = 0; i < c->getNbins(); ++i) { - const auto& v = histo.at(i, j); - LOG(DEBUG) << "channel = " << ich << ", in sector = " << sector << " (where it is channel = " << chinsector << ") bin = " << i << " value = " << v; - histoValues.push_back(v); + LOG(INFO) << "channel " << ich << " will be calibrated since it has " << entriesInChannel << " entries (min = " << mMinEntries << ")"; + fitValues.fill(-99999999); + histoValues.clear(); + // more efficient way + for (unsigned j = chinsector; j <= chinsector; ++j) { + for (unsigned i = 0; i < nbins; ++i) { + const auto& v = histo.at(i, j); + LOG(DEBUG) << "channel = " << ich << ", in sector = " << sector << " (where it is channel = " << chinsector << ") bin = " << i << " value = " << v; + histoValues.push_back(v); + } } - } - double fitres = fitGaus(c->getNbins(), histoValues.data(), -(c->getRange()), c->getRange(), fitValues); + double fitres = fitGaus(nbins, histoValues.data(), -range, range, fitValues, nullptr, 2., true); + LOG(INFO) << "channel = " << ich << " fitted by thread = " << ithread; + if (fitres >= 0) { + LOG(DEBUG) << "Channel " << ich << " :: Fit result " << fitres << " Mean = " << fitValues[1] << " Sigma = " << fitValues[2]; + } else { + // LOG(INFO) << "Channel " << ich << " :: Fit failed with result = " << fitres; + continue; + } - if (fitValues[2] < 0) { - fitValues[2] = -fitValues[2]; - } + if (fitValues[2] < 0) { + fitValues[2] = -fitValues[2]; + } - if (fitres >= 0) { - LOG(DEBUG) << "Channel " << ich << " :: Fit result " << fitres << " Mean = " << fitValues[1] << " Sigma = " << fitValues[2]; - } else { - LOG(INFO) << "Channel " << ich << " :: Fit failed with result = " << fitres; - } - float fractionUnderPeak; - float intmin = fitValues[1] - 5 * fitValues[2]; // mean - 5*sigma - float intmax = fitValues[1] + 5 * fitValues[2]; // mean + 5*sigma + float fractionUnderPeak; + float intmin = fitValues[1] - 5 * fitValues[2]; // mean - 5*sigma + float intmax = fitValues[1] + 5 * fitValues[2]; // mean + 5*sigma - if (intmin < -mRange) { - intmin = -mRange; - } - if (intmax < -mRange) { - intmax = -mRange; - } - if (intmin > mRange) { - intmin = mRange; - } - if (intmax > mRange) { - intmax = mRange; - } + if (intmin < -mRange) { + intmin = -mRange; + } + if (intmax < -mRange) { + intmax = -mRange; + } + if (intmin > mRange) { + intmin = mRange; + } + if (intmax > mRange) { + intmax = mRange; + } - /* - // needed if we calculate the integral using the values - int binmin = c->findBin(intmin); - int binmax = c->findBin(intmax); - - // for now these checks are useless, as we pass the value of the bin - if (binmin < 0) - binmin = 1; // avoid to take the underflow bin (can happen in case the sigma is too large) - if (binmax >= c->getNbins()) - binmax = c->getNbins()-1; // avoid to take the overflow bin (can happen in case the sigma is too large) - float fractionUnderPeak = (c->integral(ch, binmin, binmax) + addduetoperiodicity) / c->integral(ch, 1, c->nbins()); - */ - float channelIntegral = c->integral(ich); - fractionUnderPeak = channelIntegral > 0 ? c->integral(ich, intmin, intmax) / channelIntegral : 0; - // now we need to store the results in the TimeSlewingObject - ts.setFractionUnderPeak(ich / o2::tof::Geo::NPADSXSECTOR, ich % o2::tof::Geo::NPADSXSECTOR, fractionUnderPeak); - ts.setSigmaPeak(ich / o2::tof::Geo::NPADSXSECTOR, ich % o2::tof::Geo::NPADSXSECTOR, abs(fitValues[2])); - ts.updateOffsetInfo(ich, fitValues[1]); - } + fractionUnderPeak = entriesInChannel > 0 ? c->integral(ich, intmin, intmax) / entriesInChannel : 0; + // now we need to store the results in the TimeSlewingObject + ts.setFractionUnderPeak(ich / Geo::NPADSXSECTOR, ich % Geo::NPADSXSECTOR, fractionUnderPeak); + ts.setSigmaPeak(ich / Geo::NPADSXSECTOR, ich % Geo::NPADSXSECTOR, abs(fitValues[2])); + ts.updateOffsetInfo(ich, fitValues[1]); + } // end loop channels in sector + } // end loop over sectors auto clName = o2::utils::MemFileHelper::getClassName(ts); auto flName = o2::ccdb::CcdbApi::generateFileName(clName); - mInfoVector.emplace_back("TOF/ChannelCalib", clName, flName, md, slot.getTFStart(), 99999999999999); + mInfoVector.emplace_back("TOF/Calib/ChannelCalib", clName, flName, md, slot.getTFStart(), 99999999999999); mTimeSlewingVector.emplace_back(ts); } //_____________________________________________ -Slot& TOFChannelCalibrator::emplaceNewSlot(bool front, TFType tstart, TFType tend) -{ - auto& cont = getSlots(); - auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); - slot.setContainer(std::make_unique<TOFChannelData>(mNBins, mRange, mCalibTOFapi)); - return slot; -} +template class TOFChannelCalibrator<o2::dataformats::CalibInfoTOF>; +template class TOFChannelCalibrator<o2::tof::CalibInfoCluster>; } // end namespace tof } // end namespace o2 diff --git a/Detectors/TOF/calibration/src/TOFDCSProcessor.cxx b/Detectors/TOF/calibration/src/TOFDCSProcessor.cxx new file mode 100644 index 0000000000000..66c2eebdd5423 --- /dev/null +++ b/Detectors/TOF/calibration/src/TOFDCSProcessor.cxx @@ -0,0 +1,576 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TOFCalibration/TOFDCSProcessor.h> +#include "Rtypes.h" +#include <deque> +#include <string> +#include <algorithm> +#include <iterator> +#include <cstring> +#include <bitset> + +using namespace o2::tof; +using namespace o2::dcs; + +using DeliveryType = o2::dcs::DeliveryType; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; + +ClassImp(o2::tof::TOFDCSinfo); + +void TOFDCSinfo::print() const +{ + LOG(INFO) << "First Value: timestamp = " << firstValue.first << ", value = " << firstValue.second; + LOG(INFO) << "Last Value: timestamp = " << lastValue.first << ", value = " << lastValue.second; + LOG(INFO) << "Mid Value: timestamp = " << midValue.first << ", value = " << midValue.second; + LOG(INFO) << "Max Change: timestamp = " << maxChange.first << ", value = " << maxChange.second; +} + +//__________________________________________________________________ + +void TOFDCSProcessor::init(const std::vector<DPID>& pids) +{ + // fill the array of the DPIDs that will be used by TOF + // pids should be provided by CCDB + + for (const auto& it : pids) { + mPids[it] = false; + mTOFDCS[it].makeEmpty(); + } + + for (int iddl = 0; iddl < NDDLS; ++iddl) { + for (int ifeac = 0; ifeac < NFEACS; ++ifeac) { + getStripsConnectedToFEAC(iddl, ifeac, mFeacInfo[iddl][ifeac]); + } + } +} + +//__________________________________________________________________ + +int TOFDCSProcessor::process(const gsl::span<const DPCOM> dps) +{ + + // first we check which DPs are missing - if some are, it means that + // the delta map was sent + if (mVerbose) { + LOG(INFO) << "\n\n\nProcessing new TF\n-----------------"; + } + if (!mStartTFset) { + mStartTF = mTF; + mStartTFset = true; + } + + std::unordered_map<DPID, DPVAL> mapin; + for (auto& it : dps) { + mapin[it.id] = it.data; + } + for (auto& it : mPids) { + const auto& el = mapin.find(it.first); + if (el == mapin.end()) { + LOG(DEBUG) << "DP " << it.first << " not found in map"; + } else { + LOG(DEBUG) << "DP " << it.first << " found in map"; + } + } + + mUpdateFeacStatus = false; // by default, we do not foresee a new entry in the CCDB for the FEAC + mUpdateHVStatus = false; // by default, we do not foresee a new entry in the CCDB for the HV + + // now we process all DPs, one by one + for (const auto& it : dps) { + // we process only the DPs defined in the configuration + const auto& el = mPids.find(it.id); + if (el == mPids.end()) { + LOG(INFO) << "DP " << it.id << " not found in TOFDCSProcessor, we will not process it"; + continue; + } + processDP(it); + mPids[it.id] = true; + } + + if (mUpdateFeacStatus) { + updateFEACCCDB(); + } + + if (mUpdateHVStatus) { + updateHVCCDB(); + } + + return 0; +} + +//__________________________________________________________________ + +int TOFDCSProcessor::processDP(const DPCOM& dpcom) +{ + + // processing single DP + + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + auto& val = dpcom.data; + if (mVerbose) { + if (type == RAW_DOUBLE) { + LOG(INFO); + LOG(INFO) << "Processing DP = " << dpcom << ", with value = " << o2::dcs::getValue<double>(dpcom); + } else if (type == RAW_INT) { + LOG(INFO); + LOG(INFO) << "Processing DP = " << dpcom << ", with value = " << o2::dcs::getValue<int32_t>(dpcom); + } + } + auto flags = val.get_flags(); + if (processFlags(flags, dpid.get_alias()) == 0) { + // now I need to access the correct element + if (type == RAW_DOUBLE) { + // for these DPs, we will store the first, last, mid value, plus the value where the maximum variation occurred + auto& dvect = mDpsdoublesmap[dpid]; + LOG(DEBUG) << "mDpsdoublesmap[dpid].size() = " << dvect.size(); + auto etime = val.get_epoch_time(); + if (dvect.size() == 0 || + etime != dvect.back().get_epoch_time()) { // we check + // that we did not get the + // same timestamp as the + // latest one + dvect.push_back(val); + } + } + + if (type == RAW_INT) { + // for these DPs, we need some processing + if (std::strstr(dpid.get_alias(), "FEACSTATUS") != nullptr) { // DP is FEACSTATUS + std::string aliasStr(dpid.get_alias()); + // extracting DDL number (regex is quite slow, using this way) + const auto offs = std::strlen("TOF_FEACSTATUS_"); + std::size_t const nn = aliasStr.find_first_of("0123456789", offs); + std::size_t const mm = aliasStr.find_first_not_of("0123456789", nn); + std::string ddlStr = aliasStr.substr(nn, mm != std::string::npos ? mm - nn : mm); + auto iddl = std::stoi(ddlStr); + std::bitset<8> feacstatus(o2::dcs::getValue<int32_t>(dpcom)); + if (mVerbose) { + LOG(INFO) << "DDL: " << iddl << ": Prev FEAC = " << mPrevFEACstatus[iddl] << ", new = " << feacstatus; + } + if (feacstatus == mPrevFEACstatus[iddl]) { + if (mVerbose) { + LOG(INFO) << "Same FEAC status as before, we do nothing"; + } + return 0; + } + if (mVerbose) { + LOG(INFO) << "Something changed in LV for DDL " << iddl << ", we need to check what"; + } + mUpdateFeacStatus = true; + int plate = -1, strip = -1; + int det[5] = {iddl / 4, -1, -1, -1, -1}; + for (auto ifeac = 0; ifeac < NFEACS; ++ifeac) { // we have one bit per FEAC + auto singlefeacstatus = feacstatus[ifeac]; + for (int istrip = 0; istrip < 6; ++istrip) { + if (mFeacInfo[iddl][ifeac].stripInSM[istrip] == -1) { + continue; + } + for (int ipadz = 0; ipadz < Geo::NPADZ; ++ipadz) { + for (int ipadx = mFeacInfo[iddl][ifeac].firstPadX; ipadx <= mFeacInfo[iddl][ifeac].lastPadX; ++ipadx) { + if (mVerbose) { + LOG(INFO) << "mFeacInfo[" << iddl << "][" << ifeac << "].stripInSM[" << istrip << "] = " << mFeacInfo[iddl][ifeac].stripInSM[istrip]; + } + Geo::getStripAndModule(mFeacInfo[iddl][ifeac].stripInSM[istrip], plate, strip); + det[1] = plate; + det[2] = strip; + det[3] = ipadz; + det[4] = ipadx; + if (mVerbose) { + LOG(INFO) << "det[0] = " << det[0] << ", det[1] = " << det[1] << ", det[2] = " << det[2] << ", det[3] = " << det[3] << ", det[4] = " << det[4]; + } + int channelIdx = Geo::getIndex(det); + if (mFeac[channelIdx] != singlefeacstatus) { + mFeac[channelIdx] = singlefeacstatus; + } + } + } + } + } // end loop on FEACs + if (mVerbose) { + LOG(INFO) << "Updating previous FEAC status for DDL " << iddl; + } + mPrevFEACstatus[iddl] = feacstatus; + } // end processing current DP, when it is of type FEACSTATUS + + if (std::strstr(dpid.get_alias(), "HVSTATUS") != nullptr) { // DP is HVSTATUS + std::string aliasStr(dpid.get_alias()); + // extracting SECTOR and PLATE number (regex is quite slow, using this way) + const auto offs = std::strlen("TOF_HVSTATUS_SM"); + std::size_t const nn = aliasStr.find_first_of("0123456789", offs); + std::size_t const mm = aliasStr.find_first_not_of("0123456789", nn); + std::size_t const oo = aliasStr.find_first_of("0123456789", mm); + std::size_t const pp = aliasStr.find_first_not_of("0123456789", oo); + std::string sectorStr = aliasStr.substr(nn, mm != std::string::npos ? mm - nn : mm); + auto isect = std::stoi(sectorStr); + std::string plateStr = aliasStr.substr(oo, pp != std::string::npos ? pp - oo : pp); + auto iplat = std::stoi(plateStr); + std::bitset<19> hvstatus(o2::dcs::getValue<int32_t>(dpcom)); + if (mVerbose) { + LOG(INFO) << "Sector: " << isect << ", plate = " << iplat << ": Prev HV = " + << mPrevHVstatus[iplat][isect] << ", new = " << hvstatus; + } + if (hvstatus == mPrevHVstatus[iplat][isect]) { + if (mVerbose) { + LOG(INFO) << "Same HV status as before, we do nothing"; + } + return 0; + } + if (mVerbose) { + LOG(INFO) << "Something changed in HV for Sect " << isect << " and plate " + << iplat << ", we need to check what"; + } + mUpdateHVStatus = true; + int det[5] = {isect, iplat, -1, -1, -1}; + auto nStrips = (iplat == 2 ? Geo::NSTRIPA : (iplat == 0 || iplat == 4) ? Geo::NSTRIPC : Geo::NSTRIPB); + for (auto istrip = 0; istrip < nStrips; ++istrip) { + auto singlestripHV = hvstatus[istrip]; + for (int ipadz = 0; ipadz < Geo::NPADZ; ++ipadz) { + for (int ipadx = 0; ipadx < Geo::NPADX; ++ipadx) { + det[2] = istrip; + det[3] = ipadz; + det[4] = ipadx; + int channelIdx = Geo::getIndex(det); + if (mHV[channelIdx] != singlestripHV) { + mHV[channelIdx] = singlestripHV; + } + } + } + } // end loop on strips + if (mVerbose) { + LOG(INFO) << "Updating previous HV status for Sector: " << isect << ", plate = " << iplat; + } + mPrevHVstatus[iplat][isect] = hvstatus; + } //end processing current DP, when it is of type HVSTATUS + } + } + return 0; +} + +//______________________________________________________________________ + +uint64_t TOFDCSProcessor::processFlags(const uint64_t flags, const char* pid) +{ + + // function to process the flag. the return code zero means that all is fine. + // anything else means that there was an issue + + // for now, I don't know how to use the flags, so I do nothing + + if (flags & DataPointValue::KEEP_ALIVE_FLAG) { + LOG(DEBUG) << "KEEP_ALIVE_FLAG active for DP " << pid; + } + if (flags & DataPointValue::END_FLAG) { + LOG(DEBUG) << "END_FLAG active for DP " << pid; + } + if (flags & DataPointValue::FBI_FLAG) { + LOG(DEBUG) << "FBI_FLAG active for DP " << pid; + } + if (flags & DataPointValue::NEW_FLAG) { + LOG(DEBUG) << "NEW_FLAG active for DP " << pid; + } + if (flags & DataPointValue::DIRTY_FLAG) { + LOG(DEBUG) << "DIRTY_FLAG active for DP " << pid; + } + if (flags & DataPointValue::TURN_FLAG) { + LOG(DEBUG) << "TURN_FLAG active for DP " << pid; + } + if (flags & DataPointValue::WRITE_FLAG) { + LOG(DEBUG) << "WRITE_FLAG active for DP " << pid; + } + if (flags & DataPointValue::READ_FLAG) { + LOG(DEBUG) << "READ_FLAG active for DP " << pid; + } + if (flags & DataPointValue::OVERWRITE_FLAG) { + LOG(DEBUG) << "OVERWRITE_FLAG active for DP " << pid; + } + if (flags & DataPointValue::VICTIM_FLAG) { + LOG(DEBUG) << "VICTIM_FLAG active for DP " << pid; + } + if (flags & DataPointValue::DIM_ERROR_FLAG) { + LOG(DEBUG) << "DIM_ERROR_FLAG active for DP " << pid; + } + if (flags & DataPointValue::BAD_DPID_FLAG) { + LOG(DEBUG) << "BAD_DPID_FLAG active for DP " << pid; + } + if (flags & DataPointValue::BAD_FLAGS_FLAG) { + LOG(DEBUG) << "BAD_FLAGS_FLAG active for DP " << pid; + } + if (flags & DataPointValue::BAD_TIMESTAMP_FLAG) { + LOG(DEBUG) << "BAD_TIMESTAMP_FLAG active for DP " << pid; + } + if (flags & DataPointValue::BAD_PAYLOAD_FLAG) { + LOG(DEBUG) << "BAD_PAYLOAD_FLAG active for DP " << pid; + } + if (flags & DataPointValue::BAD_FBI_FLAG) { + LOG(DEBUG) << "BAD_FBI_FLAG active for DP " << pid; + } + + return 0; +} + +//______________________________________________________________________ + +void TOFDCSProcessor::updateDPsCCDB() +{ + + // here we create the object to then be sent to CCDB + LOG(INFO) << "Finalizing"; + union Converter { + uint64_t raw_data; + double double_value; + } converter0, converter1; + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::RAW_DOUBLE) { + auto& tofdcs = mTOFDCS[it.first]; + if (it.second == true) { // we processed the DP at least 1x + auto& dpvect = mDpsdoublesmap[it.first]; + tofdcs.firstValue.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + tofdcs.firstValue.second = converter0.double_value; + tofdcs.lastValue.first = dpvect.back().get_epoch_time(); + converter0.raw_data = dpvect.back().payload_pt1; + tofdcs.lastValue.second = converter0.double_value; + // now I will look for the max change + if (dpvect.size() > 1) { + auto deltatime = dpvect.back().get_epoch_time() - dpvect[0].get_epoch_time(); + if (deltatime < 60000) { + // if we did not cover at least 1 minute, + // max variation is defined as the difference between first and last value + converter0.raw_data = dpvect[0].payload_pt1; + converter1.raw_data = dpvect.back().payload_pt1; + double delta = std::abs(converter0.double_value - converter1.double_value); + tofdcs.maxChange.first = deltatime; // is it ok to do like this, as in Run 2? + tofdcs.maxChange.second = delta; + } else { + for (auto i = 0; i < dpvect.size() - 1; ++i) { + for (auto j = i + 1; j < dpvect.size(); ++j) { + auto deltatime = dpvect[j].get_epoch_time() - dpvect[i].get_epoch_time(); + if (deltatime >= 60000) { // we check every min; epoch_time in ms + converter0.raw_data = dpvect[i].payload_pt1; + converter1.raw_data = dpvect[j].payload_pt1; + double delta = std::abs(converter0.double_value - converter1.double_value); + if (delta > tofdcs.maxChange.second) { + tofdcs.maxChange.first = deltatime; // is it ok to do like this, as in Run 2? + tofdcs.maxChange.second = delta; + } + } + } + } + } + // mid point + auto midIdx = dpvect.size() / 2 - 1; + tofdcs.midValue.first = dpvect[midIdx].get_epoch_time(); + converter0.raw_data = dpvect[midIdx].payload_pt1; + tofdcs.midValue.second = converter0.double_value; + } else { + tofdcs.maxChange.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + tofdcs.maxChange.second = converter0.double_value; + tofdcs.midValue.first = dpvect[0].get_epoch_time(); + converter0.raw_data = dpvect[0].payload_pt1; + tofdcs.midValue.second = converter0.double_value; + } + } + if (mVerbose) { + LOG(INFO) << "PID = " << it.first.get_alias(); + tofdcs.print(); + } + } + } + std::map<std::string, std::string> md; + md["responsible"] = "Chiara Zampolli"; + prepareCCDBobjectInfo(mTOFDCS, mccdbDPsInfo, "TOF/Calib/DCSDPs", mTF, md); + + return; +} + +//______________________________________________________________________ + +void TOFDCSProcessor::updateFEACCCDB() +{ + + // we need to update a CCDB for the FEAC status --> let's prepare the CCDBInfo + + if (mVerbose) { + LOG(INFO) << "At least one FEAC changed status --> we will update CCDB"; + } + std::map<std::string, std::string> md; + md["responsible"] = "Chiara Zampolli"; + prepareCCDBobjectInfo(mFeac, mccdbLVInfo, "TOF/Calib/LVStatus", mTF, md); + return; +} + +//______________________________________________________________________ + +void TOFDCSProcessor::updateHVCCDB() +{ + + // we need to update a CCDB for the HV status --> let's prepare the CCDBInfo + + if (mVerbose) { + LOG(INFO) << "At least one HV changed status --> we will update CCDB"; + } + std::map<std::string, std::string> md; + md["responsible"] = "Chiara Zampolli"; + prepareCCDBobjectInfo(mHV, mccdbHVInfo, "TOF/Calib/HVStatus", mTF, md); + return; +} + +//_______________________________________________________________________ + +void TOFDCSProcessor::getStripsConnectedToFEAC(int nDDL, int nFEAC, TOFFEACinfo& info) const +{ + + // + // Taken from AliRoot/TOF/AliTOFLvHvDataPoints.cxx + // + // FEAC-strip mapping: + // return the strips and first PadX numbers + // connected to the FEAC number nFEAC in the crate number nDDL + // + + switch (nDDL % 4) { + case 0: + info.firstPadX = 0; + info.lastPadX = Geo::NPADX / 2 - 1; + + if (nFEAC <= 2) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC; + } + } else if (nFEAC == 3) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC; + } + } else if (nFEAC == 4) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 1; + } + } else if (nFEAC == 5) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 1; + } + } else if (nFEAC == 6) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 2; + } + } else if (nFEAC == 7) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 2; + } + } + + break; + case 1: + info.firstPadX = Geo::NPADX / 2; + info.lastPadX = Geo::NPADX - 1; + + if (nFEAC <= 2) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC; + } + } else if (nFEAC == 3) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC; + } + } else if (nFEAC == 4) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 1; + } + } else if (nFEAC == 5) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 1; + } + } else if (nFEAC == 6) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 1; + } + } else if (nFEAC == 7) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = ii + 6 * nFEAC - 2; + } + } + + break; + case 2: + info.firstPadX = Geo::NPADX / 2; + info.lastPadX = Geo::NPADX - 1; + + if (nFEAC <= 2) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC); + } + } else if (nFEAC == 3) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC); + } + } else if (nFEAC == 4) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 1); + } + } else if (nFEAC == 5) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 1); + } + } else if (nFEAC == 6) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 2); + } + } else if (nFEAC == 7) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 2); + } + } + + break; + case 3: + info.firstPadX = 0; + info.lastPadX = Geo::NPADX / 2 - 1; + + if (nFEAC <= 2) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC); + } + } else if (nFEAC == 3) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC); + } + } else if (nFEAC == 4) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 1); + } + } else if (nFEAC == 5) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 1); + } + } else if (nFEAC == 6) { + for (int ii = 0; ii < 5; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 1); + } + } else if (nFEAC == 7) { + for (int ii = 0; ii < 6; ++ii) { + info.stripInSM[ii] = 90 - (ii + 6 * nFEAC - 2); + } + } + + break; + } + if (mVerbose) { + for (int ii = 0; ii < 6; ++ii) { + LOG(INFO) << "nDDL = " << nDDL << ", nFEAC = " << nFEAC << ", stripInSM[" << ii << "] = " << info.stripInSM[ii]; + } + } +} diff --git a/Detectors/TOF/calibration/src/TOFDiagnosticCalibrator.cxx b/Detectors/TOF/calibration/src/TOFDiagnosticCalibrator.cxx new file mode 100644 index 0000000000000..7ddf8c201e2c0 --- /dev/null +++ b/Detectors/TOF/calibration/src/TOFDiagnosticCalibrator.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TOFCalibration/TOFDiagnosticCalibrator.h" +#include "Framework/Logger.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" + +namespace o2 +{ +namespace tof +{ + +using Slot = o2::calibration::TimeSlot<o2::tof::Diagnostic>; + +//---------------------------------------------------------- +void TOFDiagnosticCalibrator::initOutput() +{ + mccdbInfoVector.clear(); + mDiagnosticVector.clear(); +} + +//---------------------------------------------------------- +void TOFDiagnosticCalibrator::finalizeSlot(Slot& slot) +{ + + Diagnostic* diag = slot.getContainer(); + LOG(INFO) << "Finalizing slot"; + diag->print(); + std::map<std::string, std::string> md; + auto clName = o2::utils::MemFileHelper::getClassName(*diag); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + mccdbInfoVector.emplace_back("TOF/Calib/Diagnostic", clName, flName, md, slot.getTFStart(), 99999999999999); + mDiagnosticVector.emplace_back(*diag); +} + +//---------------------------------------------------------- +Slot& TOFDiagnosticCalibrator::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<Diagnostic>()); + return slot; +} + +} // end namespace tof +} // end namespace o2 diff --git a/Detectors/TOF/calibration/src/TOFFEElightConfig.cxx b/Detectors/TOF/calibration/src/TOFFEElightConfig.cxx new file mode 100644 index 0000000000000..13c2a92966c82 --- /dev/null +++ b/Detectors/TOF/calibration/src/TOFFEElightConfig.cxx @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TOFCalibration/TOFFEElightConfig.h> + +using namespace o2::tof; + +const TOFFEEchannelConfig* TOFFEElightConfig::getChannelConfig(int icrate, int itrm, int ichain, int itdc, int ichtdc) const +{ + + // return the channel config for the given crate, trm, chain, tdc, tdcchannel + + return icrate >= Geo::kNCrate ? nullptr : itrm >= Geo::kNTRM - 2 ? nullptr + : ichain >= Geo::kNChain ? nullptr + : itdc >= Geo::kNTdc ? nullptr + : ichtdc >= Geo::kNCh ? nullptr + : &mChannelConfig[icrate][itrm][ichain][itdc][ichtdc]; // the TRM index goes from 0 to 9, but in O2 kNTRM = 12, because it corresponds to the VME slots which span in [3, 12] +} diff --git a/Detectors/TOF/calibration/src/TOFFEElightReader.cxx b/Detectors/TOF/calibration/src/TOFFEElightReader.cxx new file mode 100644 index 0000000000000..96f2829ef688e --- /dev/null +++ b/Detectors/TOF/calibration/src/TOFFEElightReader.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TOFCalibration/TOFFEElightReader.h> +#include "Framework/Logger.h" +#include "TSystem.h" +#include <fstream> + +using namespace o2::tof; + +void TOFFEElightReader::loadFEElightConfig(const char* fileName) +{ + // load FEElight config + + char* expandedFileName = gSystem->ExpandPathName(fileName); + std::ifstream is; + is.open(expandedFileName, std::ios::binary); + mFileLoadBuff.reset(new char[sizeof(o2::tof::TOFFEElightConfig)]); + is.read(mFileLoadBuff.get(), sizeof(o2::tof::TOFFEElightConfig)); + is.close(); + mFEElightConfig = reinterpret_cast<const TOFFEElightConfig*>(mFileLoadBuff.get()); +} + +//_______________________________________________________________ +void TOFFEElightReader::loadFEElightConfig(gsl::span<const char> configBuf) +{ + // load FEElight config from buffer + + if (configBuf.size() != sizeof(o2::tof::TOFFEElightConfig)) { + LOG(FATAL) << "Incoming message with TOFFEE configuration does not match expected size: " << configBuf.size() << " received, " << sizeof(*mFEElightConfig) << " expected"; + } + mFEElightConfig = reinterpret_cast<const TOFFEElightConfig*>(configBuf.data()); +} + +//_______________________________________________________________ + +int TOFFEElightReader::parseFEElightConfig(bool verbose) +{ + // parse FEElight config + // loops over all FEE channels, checks whether they are enabled + // and sets channel enabled + + mFEElightInfo.resetAll(); + + int version = mFEElightConfig->mVersion; + int runNumber = mFEElightConfig->mRunNumber; + int runType = mFEElightConfig->mRunType; + + mFEElightInfo.mVersion = version; + mFEElightInfo.mRunNumber = runNumber; + mFEElightInfo.mRunType = runType; + + int nEnabled = 0, index; + const TOFFEEchannelConfig* channelConfig = nullptr; + for (int crateId = 0; crateId < Geo::kNCrate; crateId++) { + for (int trmId = 0; trmId < Geo::kNTRM - 2; trmId++) { // in O2, the number of TRMs is 12, but in the FEE world it is 10 + for (int chainId = 0; chainId < Geo::kNChain; chainId++) { + for (int tdcId = 0; tdcId < Geo::kNTdc; tdcId++) { + for (int channelId = 0; channelId < Geo::kNCh; channelId++) { + channelConfig = mFEElightConfig->getChannelConfig(crateId, trmId, chainId, tdcId, channelId); + if (verbose) { + LOG(INFO) << "Processing electronic channel with indices: crate = " << crateId << ", trm = " << trmId << ", chain = " + << chainId << ", tdc = " << tdcId << ", tdcChannel = " << channelId << " -> " << channelConfig; + } + if (channelConfig) { + if (!channelConfig->isEnabled()) { + continue; + } + // get index DO from crate, trm, chain, tdc, tdcchannel + index = Geo::getCHFromECH(Geo::getECHFromIndexes(crateId, trmId + 3, chainId, tdcId, channelId)); // in O2, the TRM index is shifted by 3 because it corresponds to the VME slot + if (index == -1) { + continue; + } + nEnabled++; + LOG(INFO) << "Enabling channel " << index; + mFEElightInfo.mChannelEnabled[index] = channelConfig->isEnabled(); + mFEElightInfo.mMatchingWindow[index] = channelConfig->mMatchingWindow; + mFEElightInfo.mLatencyWindow[index] = channelConfig->mLatencyWindow; + } + } + } + } + } + } + + const TOFFEEtriggerConfig* triggerConfig = nullptr; + for (Int_t iddl = 0; iddl < TOFFEElightConfig::NTRIGGERMAPS; iddl++) { + triggerConfig = mFEElightConfig->getTriggerConfig(iddl); + if (verbose) { + LOG(INFO) << "Processing trigger config " << iddl << ": " << triggerConfig; + } + if (triggerConfig) { + mFEElightInfo.mTriggerMask[iddl] = triggerConfig->mStatusMap; + } + } + + return nEnabled; +} diff --git a/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h b/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h index 34b56e2ab5d01..e4b034d67f50d 100644 --- a/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,6 +26,8 @@ #include "DataFormatsTOF/CalibInfoTOF.h" #include "TOFBase/Geo.h" #include "CommonConstants/MathConstants.h" +#include "DataFormatsTOF/Diagnostic.h" +#include "DetectorsRaw/HBFUtils.h" namespace o2 { @@ -34,42 +37,71 @@ namespace calibration class TFDispatcher : public o2::framework::Task { public: + TFDispatcher(int slot, int ngen, int nlanes, int latency) : mSlot(slot), mNGen(ngen), mNLanes(nlanes), mLatency(latency) {} + void init(o2::framework::InitContext& ic) final { mMaxTF = ic.options().get<int64_t>("max-timeframes"); + mMinSize = ic.options().get<int64_t>("min-number-of-info"); } void run(o2::framework::ProcessingContext& pc) final { for (auto& input : pc.inputs()) { auto tfid = header::get<o2::framework::DataProcessingHeader*>(input.header)->startTime; - if (tfid >= mMaxTF) { + if (tfid >= mMaxTF - 1) { LOG(INFO) << "Data generator reached TF " << tfid << ", stopping"; pc.services().get<o2::framework::ControlService>().endOfStream(); pc.services().get<o2::framework::ControlService>().readyToQuit(o2::framework::QuitRequest::Me); + if (!acceptTF(tfid)) { + return; + } break; } + if (!acceptTF(tfid)) { + return; + } } - int size = 100 + gRandom->Integer(100); // push dummy output + int size = mMinSize + gRandom->Integer(100); // push dummy output + usleep(mLatency); pc.outputs().snapshot(o2::framework::OutputRef{"output", 0}, size); } + bool acceptTF(int tfid) + { + + // check if the current TF should be processed by this instance of the generator + + int targetSlot = (tfid / mNLanes) % mNGen; + if (targetSlot != mSlot) { + LOG(INFO) << "tfid = " << tfid << ", mNLanes = " << mNLanes << ", mNGen = " << mNGen << ", mSlot = " << mSlot << " target slot = " << targetSlot << ": discarded"; + return false; + } + LOG(INFO) << "tfid = " << tfid << ", mNLanes = " << mNLanes << ", mNGen = " << mNGen << ", mSlot = " << mSlot << " target slot = " << targetSlot << ": accepted"; + return true; + } + private: uint64_t mMaxTF = 1; + int mSlot = 1; + int mNGen = 1; + int mNLanes = 1; + int mLatency = 0; + int mMinSize = 100; }; -class TFProcessor : public o2::framework::Task +class TFProcessorCalibInfoTOF : public o2::framework::Task { public: + TFProcessorCalibInfoTOF(int latency, int latencyRMS) : mMeanLatency(latency), mLatencyRMS(latencyRMS){}; + void init(o2::framework::InitContext& ic) final { mDevCopy = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; gRandom->SetSeed(mDevCopy); - mMeanLatency = std::max(1, ic.options().get<int>("mean-latency")); - mLatencyRMS = std::max(1, ic.options().get<int>("latency-spread")); mTOFChannelCalib = ic.options().get<bool>("do-TOF-channel-calib"); mTOFChannelCalibInTestMode = ic.options().get<bool>("do-TOF-channel-calib-in-test-mode"); - LOG(INFO) << "TFProcessorCopy: " << mDevCopy << " MeanLatency: " << mMeanLatency << " LatencyRMS: " << mLatencyRMS << " DoTOFChannelCalib: " << mTOFChannelCalib + LOG(INFO) << "TFProcessorCalibInfoTOFCopy: " << mDevCopy << " MeanLatency: " << mMeanLatency << " LatencyRMS: " << mLatencyRMS << " DoTOFChannelCalib: " << mTOFChannelCalib << " DoTOFChannelCalibInTestMode: " << mTOFChannelCalibInTestMode; for (int i = 0; i < o2::tof::Geo::NCHANNELS; i++) { @@ -82,7 +114,7 @@ class TFProcessor : public o2::framework::Task auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; // introduceDelay uint32_t delay = std::abs(gRandom->Gaus(mMeanLatency, mLatencyRMS)); - LOG(INFO) << "TFProcessorCopy: " << mDevCopy << " Simulate latency of " << delay << " mcs for TF " << tfcounter; + LOG(INFO) << "TFProcessorCalibInfoTOFCopy: " << mDevCopy << " Simulate latency of " << delay << " mcs for TF " << tfcounter; usleep(delay); // push dummy output @@ -113,35 +145,110 @@ class TFProcessor : public o2::framework::Task double mChannelShifts[o2::tof::Geo::NCHANNELS]; }; +class TFProcessorDiagnostic : public o2::framework::Task +{ + public: + TFProcessorDiagnostic(int latency, int latencyRMS) : mMeanLatency(latency), mLatencyRMS(latencyRMS){}; + + void init(o2::framework::InitContext& ic) final + { + + mDevCopy = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; + gRandom->SetSeed(mDevCopy); + LOG(INFO) << "TFProcessorDiagnosticCopy: " << mDevCopy; + + auto size = ic.options().get<int>("n-diag-words"); // number of diagnostic words that we want to simulate; only these will then be present + mProb.resize(size); + mDiagnosticPattern.resize(size); + + for (int i = 0; i < size; ++i) { + int crateId = gRandom->Integer(72); + int trmId = gRandom->Integer(10); + mProb[i] = 0; + mDiagnosticPattern[i] = (ULong64_t(trmId) << 32) + (ULong64_t(crateId) << 36); + for (int j = 0; j < 28; ++j) { // adding diagnostic patterns for each word; we can have 28 at max, but we don't want all of them (we use a cut on a probability of 30%) + if (gRandom->Rndm() < 0.3) { + mDiagnosticPattern[i] += 1 << j; + mProb[i] = gRandom->Rndm(); // probability for each diagnostic word + } + } + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + // introduceDelay + uint32_t delay = std::abs(gRandom->Gaus(mMeanLatency, mLatencyRMS)); + LOG(INFO) << "TFProcessorDiagnosticCopy: " << mDevCopy << " Simulate latency of " << delay << " mcs for TF " << tfcounter; + usleep(delay); + + // push dummy output + auto& outputDiagnostic = pc.outputs().make<o2::tof::Diagnostic>(o2::framework::OutputRef{"output", 0}); + for (int iOrbit = 0; iOrbit < o2::raw::HBFUtils::Instance().getNOrbitsPerTF(); ++iOrbit) { + for (int iROwindow = 0; iROwindow < o2::tof::Geo::NWINDOW_IN_ORBIT; ++iROwindow) { + outputDiagnostic.fillROW(); + for (int i = 0; i < mDiagnosticPattern.size(); ++i) { + if (gRandom->Rndm() < mProb[i]) { + outputDiagnostic.fill(mDiagnosticPattern[i]); + } + } + } + } + LOG(DEBUG) << "diagnostic for TF " << tfcounter << " --> "; + outputDiagnostic.print(); + } + + private: + int mDevCopy = 0; + std::vector<uint64_t> mDiagnosticPattern; + std::vector<float> mProb; + o2::tof::Diagnostic mDiagnosticFrequency; + uint32_t mMeanLatency = 0; + uint32_t mLatencyRMS = 1; +}; + } // namespace calibration namespace framework { -DataProcessorSpec getTFDispatcherSpec() +DataProcessorSpec getTFDispatcherSpec(int slot, int ngen, int nlanes, int latency) { return DataProcessorSpec{ "calib-tf-dispatcher", Inputs{}, Outputs{{{"output"}, "TOF", "DATASIZE"}}, - AlgorithmSpec{adaptFromTask<o2::calibration::TFDispatcher>()}, - Options{{"max-timeframes", VariantType::Int64, 99999999999ll, {"max TimeFrames to generate"}}}}; + AlgorithmSpec{adaptFromTask<o2::calibration::TFDispatcher>(slot, ngen, nlanes, latency)}, + Options{{"max-timeframes", VariantType::Int64, 99999999999ll, {"max TimeFrames to generate"}}, + {"min-number-of-info", VariantType::Int64, 99999999999ll, {"min number of Info (CalibTOFInfo, or Diagnostic) to generate"}}}}; } -DataProcessorSpec getTFProcessorSpec() +DataProcessorSpec getTFProcessorCalibInfoTOFSpec(int latency, int latencyRMS) { + return DataProcessorSpec{ "calib-tf-data-processor", Inputs{{"input", "TOF", "DATASIZE"}}, Outputs{{{"output"}, "TOF", "CALIBDATA"}}, - AlgorithmSpec{adaptFromTask<o2::calibration::TFProcessor>()}, + AlgorithmSpec{adaptFromTask<o2::calibration::TFProcessorCalibInfoTOF>(latency, latencyRMS)}, Options{ - {"mean-latency", VariantType::Int, 1000, {"mean latency of the generator in microseconds"}}, - {"latency-spread", VariantType::Int, 100, {"latency gaussian RMS of the generator in microseconds"}}, {"do-TOF-channel-calib", VariantType::Bool, false, {"flag to do TOF ChannelCalib"}}, {"do-TOF-channel-calib-in-test-mode", VariantType::Bool, false, {"flag to do TOF ChannelCalib in testMode"}}}}; } +DataProcessorSpec getTFProcessorDiagnosticSpec(int latency, int latencyRMS) +{ + + return DataProcessorSpec{ + "calib-tf-data-processor", + Inputs{{"input", "TOF", "DATASIZE"}}, + Outputs{{{"output"}, "TOF", "DIAGNOSTIC"}}, + AlgorithmSpec{adaptFromTask<o2::calibration::TFProcessorDiagnostic>(latency, latencyRMS)}, + Options{ + {"n-diag-words", VariantType::Int, 20, {"number of diagnostic words to simulate"}}}}; +} + } // namespace framework } // namespace o2 diff --git a/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h b/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h index 9999aad1d81c2..bdda7c029e92a 100644 --- a/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -83,8 +84,8 @@ class LHCClockCalibDevice : public o2::framework::Task auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, i}, *image.get()); // vector<char> - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, i}, w); // root-serialized + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_LHCphase", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_LHCphase", i}, w); // root-serialized } if (payloadVec.size()) { mCalibrator->initOutput(); // reset the outputs once they are already sent @@ -103,8 +104,8 @@ DataProcessorSpec getLHCClockCalibDeviceSpec() using clbUtils = o2::calibration::Utils; std::vector<OutputSpec> outputs; - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_LHCphase"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_LHCphase"}); return DataProcessorSpec{ "calib-lhcclock-calibration", Inputs{{"input", "TOF", "CALIBDATA"}}, diff --git a/Detectors/TOF/calibration/testWorkflow/README.md b/Detectors/TOF/calibration/testWorkflow/README.md new file mode 100644 index 0000000000000..379fa9621400c --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/README.md @@ -0,0 +1,134 @@ +<!-- doxy +\page refDetectorsTOFtestWorkflow testWorkflow +/doxy --> + +# TOF calibration workflows + +## DCS DP processing: + +Local example workflow with local CCDB (running on port 8080) : + +This will read the list of DPs to be associated to TOF from CCDB (remove +`--use-ccdb-to-configure` if you don't want this, but use hardcoded +aliases. You can specify the path of CCDB also with `--ccdb-path`. +You can also specify to run in verbose mode (`--use-verbose-mode`) + +```shell +o2-calibration-tof-dcs-sim-workflow --max-timeframes 3 --delta-fraction 0.5 -b | +o2-calibration-tof-dcs-workflow --use-ccdb-to-configure -b | +o2-calibration-ccdb-populator-workflow --ccdb-path="http://localhost:8080" -b +``` +To populate locally a DCS entry for the configuration, run the: + +`O2/Detectors/TOF/calibration/macros/makeCCDBEntryForDCS.C` + +macro. + +Detailed explanation of the command above: + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/TOF/calibration/testWorkflow/tof-dcs-sim-workflow.cxx --> executable to generate the TOF DCS DPs + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx --> data processor executed by the "tof-dcs-sim-workflow.cxx" above (see 1); it is defined with the list of aliases and the name of the detector; it will take care of generating randomly the data points, and send them wither as a Full Buffer Image (FBI, see code, for the full list of data points), or as a "delta" (containing only the values of the DPs that changed) + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/TOF/calibration/testWorkflow/tof-dcs-data-workflow.cxx --> executable to trigger the DCS processing; + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/TOF/calibration/testWorkflow/TOFDCSDataProcessorSpec.h --> data processor executed by the above "tof-dcs-data-workflow.cxx" (see 3); its input is the block of DCS data subscribed by TOF, the output is the CCDB payload and information. In between, "TOFDCSProcessor.cxx" is used (see 5). + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/TOF/calibration/src/TOFDCSProcessor.cxx --> this is the core of the processing, which is detector dependent; it iw what will run at every new "packet" of data, and it will create the object to be sent to the CCDB; + +1. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/Calibration/workflow/ccdb-populator-workflow.cxx --> executable (service in common to everything that populates the CCDB) that fills the CCDB from the payload and info created in 5. + +When all is tested locally, the central simulation in DCS can be done, and the procedure can be tested centrally with the "dcs-proxy" (not for development, see https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx). + +The definition per detector of the DPs that it has to subscribe to should be stored in CCDB, see e.g. https://github.com/AliceO2Group/AliceO2/blob/dev/Detectors/TOF/calibration/macros/makeTOFCCDBEntryForDCS.C. + +## LHC phase: + +This will process the LHC phase simulated by the Generator workflow + +```shell +LHC phase +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 500 | +o2-calibration-lhc-clockphase-workflow --tf-per-slot 20 | +o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 +``` + +## TOF channel calibration: + +To obtain the TOF channel offsets (at end of processing). Input from simulation, but is should work if attached to reco+calib flow + +* simulating reading from ccdb, and using it, with "-b", in "test" mode --> to use this, we need an appropriate CCDB object in the CCDB + +```shell +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 500 --do-TOF-channel-calib --do-TOF-channel-calib-in-test-mode -b | +o2-testworkflows-tof-dummy-ccdb -b | +o2-calibration-tof-channel-calib-workflow --min-entries 50 --do-TOF-channel-calib-in-test-mode --use-ccdb -b | +o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 -b +``` + +* simulating reading from ccdb, but not using it, with "-b", in "test" mode --> to use this, we need an appropriate CCDB object in the CCDB + +``` +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 500 --do-TOF-channel-calib --do-TOF-channel-calib-in-test-mode -b | +o2-testworkflows-tof-dummy-ccdb -b +| o2-calibration-tof-channel-calib-workflow --min-entries 50 --do-TOF-channel-calib-in-test-mode -b +| o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 -b +``` + +* Using the workflow that has both LHCclockPhase and TOFChannelCalib; for now I can enable only one, or the CCDB populator will not work + +```shell +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 500 --do-TOF-channel-calib --do-TOF-channel-calib-in-test-mode -b | +o2-calibration-tof-dummy-ccdb-for-calib -b | +o2-calibration-tof-calib-workflow --do-channel-offset --min-entries 50 --do-TOF-channel-calib-in-test-mode -b | +o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 -b +``` +* same as above, enabling CCDB + +```shell +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 500 --do-TOF-channel-calib --do-TOF-channel-calib-in-test-mode -b | +o2-calibration-tof-dummy-ccdb-for-calib -b | +o2-calibration-tof-calib-workflow --do-channel-offset --use-ccdb --min-entries 50 --do-TOF-channel-calib-in-test-mode -b | +o2-calibration-ccdb-populator-workflow --ccdb-path localhost:8080 -b +``` + +By default the rate of the TF sampling will match to `mean-latence / lanes`, so that the sampling and generation are balanced and no TF is dropped out at the generation level. +One can provide the option `--pressure <float, D=1.>`, in which case the sampling rate will be increased by this factor, creating a back-pressure on the processing due to its latency. + +There is a possibility to generate data in multiple independent workflows, still avoiding TF-s with the same ID in different workflow. Options `--gen-norm <N, D=1> --gen-slot <I,D=0>` will +enforce skipping all TF-s except those with ``(TFID/lanes)%N == I``. I.e. for example, to emulate the processing with 3 different EPN's with 8 lanes each one can run in 3 terminals: + +```shell +# Term.1: will produce TFs [0:7], [24:31], [48:55] ... +o2-calibration-data-generator-workflow --lanes 8 --max-timeframes 5000 --gen-norm 3 --gen-slot 0 + +# Term.2: will produce TFs [8:15], [32,39], [56:63] ... +o2-calibration-data-generator-workflow --lanes 8 --max-timeframes 5000 --gen-norm 3 --gen-slot 1 + +# Term.3: will produce TFs [16:23], [40:47], [64:71] ... +o2-calibration-data-generator-workflow --lanes 8 --max-timeframes 5000 --gen-norm 3 --gen-slot 2 +``` + +* To run the calibration with cosmics: + +```shell +o2-tof-cluscal-reader-workflow -b | o2-calibration-tof-calib-workflow -b --cosmics --do-channel-offset --min-entries 50 --update-interval 10000 +``` + +## TimeSlewing: + +For Time Slewing. Will save the Time Slewing information in files when a certain condition is reached. A post-processing +should then take care of extracting the CCDB + +* test mode: + +``` shell +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 10 -b | +o2-calibration-tof-collect-calib-workflow --tf-sending-policy --running-in-test-mode -b + +* non-test but simplified (using option "is-max-number-hits-to-fill-tree-absolute"): + +```shell +o2-calibration-data-generator-workflow --lanes 10 --mean-latency 100000 --max-timeframes 10 -b | +o2-calibration-tof-collect-calib-workflow --max-number-hits-to-fill-tree 300 --is-max-number-hits-to-fill-tree-absolute -b +``` diff --git a/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorSpec.h index 9f9df0953a107..22ec312e64137 100644 --- a/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,8 @@ #include "Framework/ControlService.h" #include "Framework/WorkflowSpec.h" +#include <limits> + using namespace o2::framework; namespace o2 @@ -40,10 +43,12 @@ class TOFCalibCollectorDevice : public o2::framework::Task int maxEnt = ic.options().get<int>("max-number-hits-to-fill-tree"); bool isTest = ic.options().get<bool>("running-in-test-mode"); bool absMaxEnt = ic.options().get<bool>("is-max-number-hits-to-fill-tree-absolute"); + int updateInterval = ic.options().get<int64_t>("update-interval"); mCollector = std::make_unique<o2::tof::TOFCalibCollector>(isTFsendingPolicy, maxEnt); mCollector->setIsTest(isTest); mCollector->setIsMaxNumberOfHitsAbsolute(absMaxEnt); - mCollector->setSlotLength(1); + mCollector->setSlotLength(std::numeric_limits<long>::max()); + mCollector->setCheckIntervalInfiniteSlot(updateInterval); mCollector->setMaxSlotsDelay(0); } @@ -101,7 +106,6 @@ DataProcessorSpec getTOFCalibCollectorDeviceSpec() std::vector<OutputSpec> outputs; outputs.emplace_back(o2::header::gDataOriginTOF, "COLLECTEDINFO", 0, Lifetime::Timeframe); - // or should I use the ConcreteDataTypeMatcher? e.g.: outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); outputs.emplace_back(o2::header::gDataOriginTOF, "ENTRIESCH", 0, Lifetime::Timeframe); std::vector<InputSpec> inputs; @@ -116,7 +120,8 @@ DataProcessorSpec getTOFCalibCollectorDeviceSpec() {"max-number-hits-to-fill-tree", VariantType::Int, 500, {"maximum number of entries in one channel to trigger teh filling of the tree"}}, {"is-max-number-hits-to-fill-tree-absolute", VariantType::Bool, false, {"to decide if we want to multiply the max-number-hits-to-fill-tree by the number of channels (when set to true), or not (when set to false) for fast checks"}}, {"tf-sending-policy", VariantType::Bool, false, {"if we are sending output at every TF; otherwise, we use the max-number-hits-to-fill-tree"}}, - {"running-in-test-mode", VariantType::Bool, false, {"to run in test mode for simplification"}}}}; + {"running-in-test-mode", VariantType::Bool, false, {"to run in test mode for simplification"}}, + {"update-interval", VariantType::Int64, 10ll, {"number of TF after which to try to finalize calibration"}}}}; } } // namespace framework diff --git a/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorWriterSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorWriterSpec.h index fc126b0fc1670..fabb41408a0ee 100644 --- a/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorWriterSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/TOFCalibCollectorWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/testWorkflow/TOFChannelCalibratorSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFChannelCalibratorSpec.h index 12847abd5c364..2d583ab8217fc 100644 --- a/Detectors/TOF/calibration/testWorkflow/TOFChannelCalibratorSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/TOFChannelCalibratorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "TOFCalibration/TOFChannelCalibrator.h" #include "DetectorsCalibration/Utils.h" #include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/CalibInfoCluster.h" #include "CommonUtils/MemFileHelper.h" #include "Framework/Task.h" #include "Framework/ConfigParamRegistry.h" @@ -24,6 +26,7 @@ #include "Framework/WorkflowSpec.h" #include "CCDB/CcdbApi.h" #include "CCDB/CcdbObjectInfo.h" +#include <limits> using namespace o2::framework; @@ -32,6 +35,7 @@ namespace o2 namespace calibration { +template <class T> class TOFChannelCalibDevice : public o2::framework::Task { @@ -39,7 +43,7 @@ class TOFChannelCalibDevice : public o2::framework::Task using LHCphase = o2::dataformats::CalibLHCphaseTOF; public: - explicit TOFChannelCalibDevice(bool useCCDB, bool attachChannelOffsetToLHCphase) : mUseCCDB(useCCDB), mAttachToLHCphase(attachChannelOffsetToLHCphase) {} + explicit TOFChannelCalibDevice(bool useCCDB, bool attachChannelOffsetToLHCphase, bool isCosmics) : mUseCCDB(useCCDB), mAttachToLHCphase(attachChannelOffsetToLHCphase), mCosmics(isCosmics) {} void init(o2::framework::InitContext& ic) final { @@ -47,9 +51,30 @@ class TOFChannelCalibDevice : public o2::framework::Task int nb = std::max(500, ic.options().get<int>("nbins")); float range = ic.options().get<float>("range"); int isTest = ic.options().get<bool>("do-TOF-channel-calib-in-test-mode"); - mCalibrator = std::make_unique<o2::tof::TOFChannelCalibrator>(minEnt, nb, range); - mCalibrator->setUpdateAtTheEndOfRunOnly(); + bool updateAtEORonly = ic.options().get<bool>("update-at-end-of-run-only"); + int64_t slotL = ic.options().get<int64_t>("tf-per-slot"); + int64_t delay = ic.options().get<int64_t>("max-delay"); + int updateInterval = ic.options().get<int64_t>("update-interval"); + int deltaUpdateInterval = ic.options().get<int64_t>("delta-update-interval"); + mCalibrator = std::make_unique<o2::tof::TOFChannelCalibrator<T>>(minEnt, nb, range); + + // default behaviour is to have only 1 slot at a time, accepting everything for it till the + // minimum statistics is reached; + // if one defines a different slot length and delay, + // the usual time slot calibration behaviour is used; + // if one defines that the calibration should happen only at the end of the run, + // then the slot length and delay won't matter + mCalibrator->setSlotLength(slotL); + mCalibrator->setCheckIntervalInfiniteSlot(updateInterval); + mCalibrator->setCheckDeltaIntervalInfiniteSlot(deltaUpdateInterval); + mCalibrator->setMaxSlotsDelay(delay); + + if (updateAtEORonly) { // has priority over other settings + mCalibrator->setUpdateAtTheEndOfRunOnly(); + } + mCalibrator->setIsTest(isTest); + mCalibrator->setDoCalibWithCosmics(mCosmics); // calibration objects set to zero mPhase.addLHCphase(0, 0); @@ -90,13 +115,13 @@ class TOFChannelCalibDevice : public o2::framework::Task } if (lhcphaseIndex == -1) { // no new object found, use CCDB - auto lhcPhase = pc.inputs().get<LHCphase*>("tofccdbLHCphase"); + auto lhcPhase = pc.inputs().get<LHCphase*>("tofccdbLHCphase"); lhcPhaseObjTmp = std::move(*lhcPhase); } else { const auto pld = pc.inputs().get<gsl::span<char>>("clbPayload", lhcphaseIndex); // this is actually an image of TMemFile // now i need to make a LHCphase object; Ruben suggested how, I did not try yet - // ... + // ... } } else { @@ -127,9 +152,17 @@ class TOFChannelCalibDevice : public o2::framework::Task mCalibrator->setRange(mCalibrator->getRange() * 10); // we enlarge the range for the calibration in case the last valid object is too old (older than 1 week) } - auto data = pc.inputs().get<gsl::span<o2::dataformats::CalibInfoTOF>>("input"); - LOG(INFO) << "Processing TF " << tfcounter << " with " << data.size() << " tracks"; - mCalibrator->process(tfcounter, data); + if (!mCosmics) { + auto data = pc.inputs().get<gsl::span<T>>("input"); + LOG(INFO) << "Processing TF " << tfcounter << " with " << data.size() << " tracks"; + mCalibrator->process(tfcounter, data); + sendOutput(pc.outputs()); + } else { + auto data = pc.inputs().get<gsl::span<T>>("input"); + LOG(INFO) << "Processing TF " << tfcounter << " with " << data.size() << " tracks"; + mCalibrator->process(tfcounter, data); + sendOutput(pc.outputs()); + } } void endOfStream(o2::framework::EndOfStreamContext& ec) final @@ -140,12 +173,13 @@ class TOFChannelCalibDevice : public o2::framework::Task } private: - std::unique_ptr<o2::tof::TOFChannelCalibrator> mCalibrator; + std::unique_ptr<o2::tof::TOFChannelCalibrator<T>> mCalibrator; o2::tof::CalibTOFapi* mcalibTOFapi = nullptr; LHCphase mPhase; TimeSlewing mTimeSlewing; bool mUseCCDB = false; bool mAttachToLHCphase = false; // whether to use or not previously defined LHCphase + bool mCosmics = false; //________________________________________________________________ void sendOutput(DataAllocator& output) @@ -162,8 +196,9 @@ class TOFChannelCalibDevice : public o2::framework::Task auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload, i}, *image.get()); // vector<char> - output.snapshot(Output{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo, i}, w); // root-serialized + + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_CHANCALIB", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_CHANCALIB", i}, w); // root-serialized } if (payloadVec.size()) { mCalibrator->initOutput(); // reset the outputs once they are already sent @@ -176,17 +211,24 @@ class TOFChannelCalibDevice : public o2::framework::Task namespace framework { -DataProcessorSpec getTOFChannelCalibDeviceSpec(bool useCCDB, bool attachChannelOffsetToLHCphase = false) +template <class T> +DataProcessorSpec getTOFChannelCalibDeviceSpec(bool useCCDB, bool attachChannelOffsetToLHCphase = false, bool isCosmics = false) { - using device = o2::calibration::TOFChannelCalibDevice; + constexpr int64_t INFINITE_TF_int64 = std::numeric_limits<long>::max(); + using device = o2::calibration::TOFChannelCalibDevice<T>; using clbUtils = o2::calibration::Utils; std::vector<OutputSpec> outputs; - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); - outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_CHANCALIB"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_CHANCALIB"}); std::vector<InputSpec> inputs; - inputs.emplace_back("input", "TOF", "CALIBDATA"); + if (!isCosmics) { + inputs.emplace_back("input", "TOF", "CALIBDATA"); + } else { + inputs.emplace_back("input", "TOF", "INFOCALCLUS"); + } + if (useCCDB) { inputs.emplace_back("tofccdbLHCphase", o2::header::gDataOriginTOF, "LHCphase"); inputs.emplace_back("tofccdbChannelCalib", o2::header::gDataOriginTOF, "ChannelCalib"); @@ -198,13 +240,18 @@ DataProcessorSpec getTOFChannelCalibDeviceSpec(bool useCCDB, bool attachChannelO "calib-tofchannel-calibration", inputs, outputs, - AlgorithmSpec{adaptFromTask<device>(useCCDB, attachChannelOffsetToLHCphase)}, + AlgorithmSpec{adaptFromTask<device>(useCCDB, attachChannelOffsetToLHCphase, isCosmics)}, Options{ {"min-entries", VariantType::Int, 500, {"minimum number of entries to fit channel histos"}}, {"nbins", VariantType::Int, 1000, {"number of bins for t-texp"}}, {"range", VariantType::Float, 24000.f, {"range for t-text"}}, {"do-TOF-channel-calib-in-test-mode", VariantType::Bool, false, {"to run in test mode for simplification"}}, - {"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}}}; + {"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}, + {"update-at-end-of-run-only", VariantType::Bool, false, {"to update the CCDB only at the end of the run; has priority over calibrating in time slots"}}, + {"tf-per-slot", VariantType::Int64, INFINITE_TF_int64, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int64, 0ll, {"number of slots in past to consider"}}, + {"update-interval", VariantType::Int64, 10ll, {"number of TF after which to try to finalize calibration"}}, + {"delta-update-interval", VariantType::Int64, 10ll, {"number of TF after which to try to finalize calibration, if previous attempt failed"}}}}; } } // namespace framework diff --git a/Detectors/TOF/calibration/testWorkflow/TOFDCSConfigProcessorSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFDCSConfigProcessorSpec.h new file mode 100644 index 0000000000000..07b1ec2143259 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/TOFDCSConfigProcessorSpec.h @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TOF_DCSCONFIGPROCESSOR_H +#define O2_TOF_DCSCONFIGPROCESSOR_H + +/// @file TOFDCSConfigProcessorSpec.h +/// @brief TOF Processor for DCS Configurations + +#include "TOFCalibration/TOFFEElightReader.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CCDB/CcdbApi.h" + +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +#include <chrono> + +using namespace o2::framework; +using TFType = uint64_t; +using HighResClock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration<double, std::ratio<1, 1>>; + +namespace o2 +{ +namespace tof +{ + +class TOFDCSConfigProcessor : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + mVerbose = ic.options().get<bool>("use-verbose-mode"); + LOG(INFO) << " ************************* Verbose?" << mVerbose; + } + + //--------------------------------------------------------- + + void run(o2::framework::ProcessingContext& pc) final + { + auto configBuff = pc.inputs().get<gsl::span<char>>("inputConfig"); + auto configFileName = pc.inputs().get<std::string>("inputConfigFileName"); + auto timer = std::chrono::duration_cast<std::chrono::milliseconds>(HighResClock::now().time_since_epoch()).count(); + LOG(INFO) << "got input file " << configFileName << " of size " << configBuff.size(); + mTOFFEElightReader.loadFEElightConfig(configBuff); + mTOFFEElightReader.parseFEElightConfig(mVerbose); + //auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().getFirstValid(true).header)->startTime; + sendOutput(pc.outputs(), timer); + } + + //--------------------------------------------------------- + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + } + + private: + void sendOutput(DataAllocator& output, long tf) + { + // sending output to CCDB + + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + + using clbUtils = o2::calibration::Utils; + const auto& payload = mTOFFEElightReader.getTOFFEElightInfo(); + auto clName = o2::utils::MemFileHelper::getClassName(payload); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + std::map<std::string, std::string> md; + md.emplace("created by", "dpl"); + o2::ccdb::CcdbObjectInfo info("TOF/Calib/FEELIGHT", clName, flName, md, tf, INFINITE_TF); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_FEELIGHT", 0}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_FEELIGHT", 0}, info); // root-serialized + } + //________________________________________________________________ + + TOFFEElightReader mTOFFEElightReader; // reader for configuration + bool mVerbose = false; // to enable verbose mode + +}; // end class +} // namespace tof + +namespace framework +{ + +DataProcessorSpec getTOFDCSConfigProcessorSpec() +{ + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_FEELIGHT"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_FEELIGHT"}); + + return DataProcessorSpec{ + "tof-dcs-config-processor", + Inputs{{"inputConfig", o2::header::gDataOriginTOF, "DCS_CONFIG_FILE", Lifetime::Timeframe}, + {"inputConfigFileName", o2::header::gDataOriginTOF, "DCS_CONFIG_NAME", Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<o2::tof::TOFDCSConfigProcessor>()}, + Options{{"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/testWorkflow/TOFDCSDataProcessorSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFDCSDataProcessorSpec.h new file mode 100644 index 0000000000000..d29d9e9c4efe5 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/TOFDCSDataProcessorSpec.h @@ -0,0 +1,209 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TOF_DATAPROCESSOR_H +#define O2_TOF_DATAPROCESSOR_H + +/// @file DCSTOFDataProcessorSpec.h +/// @brief TOF Processor for DCS Data Points + +#include <unistd.h> +#include <TRandom.h> +#include <TStopwatch.h> +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/AliasExpander.h" +#include "TOFCalibration/TOFDCSProcessor.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "Framework/Logger.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using namespace o2::ccdb; +using CcdbManager = o2::ccdb::BasicCCDBManager; +using clbUtils = o2::calibration::Utils; +using HighResClock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration<double, std::ratio<1, 1>>; + +class TOFDCSDataProcessor : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + + std::vector<DPID> vect; + mDPsUpdateInterval = ic.options().get<int64_t>("DPs-update-interval"); + if (mDPsUpdateInterval == 0) { + LOG(ERROR) << "TOF DPs update interval set to zero seconds --> changed to 60"; + mDPsUpdateInterval = 60; + } + bool useCCDBtoConfigure = ic.options().get<bool>("use-ccdb-to-configure"); + if (useCCDBtoConfigure) { + LOG(INFO) << "Configuring via CCDB"; + std::string ccdbpath = ic.options().get<std::string>("ccdb-path"); + auto& mgr = CcdbManager::instance(); + mgr.setURL(ccdbpath); + CcdbApi api; + api.init(mgr.getURL()); + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + std::unordered_map<DPID, std::string>* dpid2DataDesc = mgr.getForTimeStamp<std::unordered_map<DPID, std::string>>("TOF/Config/DCSDPconfig", ts); + for (auto& i : *dpid2DataDesc) { + vect.push_back(i.first); + } + } else { + LOG(INFO) << "Configuring via hardcoded strings"; + std::vector<std::string> aliases = {"tof_hv_vp_[00..89]", "tof_hv_vn_[00..89]", "tof_hv_ip_[00..89]", "tof_hv_in_[00..89]"}; + std::vector<std::string> aliasesInt = {"TOF_FEACSTATUS_[00..71]"}; + std::vector<std::string> expaliases = o2::dcs::expandAliases(aliases); + std::vector<std::string> expaliasesInt = o2::dcs::expandAliases(aliasesInt); + for (const auto& i : expaliases) { + vect.emplace_back(i, o2::dcs::RAW_DOUBLE); + } + for (const auto& i : expaliasesInt) { + vect.emplace_back(i, o2::dcs::RAW_INT); + } + } + + LOG(INFO) << "Listing Data Points for TOF:"; + for (auto& i : vect) { + LOG(INFO) << i; + } + + mProcessor = std::make_unique<o2::tof::TOFDCSProcessor>(); + bool useVerboseMode = ic.options().get<bool>("use-verbose-mode"); + LOG(INFO) << " ************************* Verbose?" << useVerboseMode; + if (useVerboseMode) { + mProcessor->useVerboseMode(); + } + mProcessor->init(vect); + mTimer = HighResClock::now(); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfid = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + auto dps = pc.inputs().get<gsl::span<DPCOM>>("input"); + mProcessor->setTF(tfid); + mProcessor->process(dps); + auto timeNow = HighResClock::now(); + Duration elapsedTime = timeNow - mTimer; // in seconds + if (elapsedTime.count() >= mDPsUpdateInterval) { + sendDPsoutput(pc.outputs()); + mTimer = timeNow; + } + sendLVandHVoutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + sendDPsoutput(ec.outputs()); + sendLVandHVoutput(ec.outputs()); + } + + private: + std::unique_ptr<TOFDCSProcessor> mProcessor; + HighResClock::time_point mTimer; + int64_t mDPsUpdateInterval; + + //________________________________________________________________ + void sendDPsoutput(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + mProcessor->updateDPsCCDB(); + const auto& payload = mProcessor->getTOFDPsInfo(); + auto& info = mProcessor->getccdbDPsInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_DCSDPs", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_DCSDPs", 0}, info); + mProcessor->clearDPsinfo(); + } + + //________________________________________________________________ + void sendLVandHVoutput(DataAllocator& output) + { + // extract CCDB infos and calibration objects for LV and HV, convert it to TMemFile and send them to the output + + if (mProcessor->isLVUpdated()) { + const auto& payload = mProcessor->getLVStatus(); + auto& info = mProcessor->getccdbLVInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_LVStatus", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_LVStatus", 0}, info); + } + if (mProcessor->isHVUpdated()) { + const auto& payload = mProcessor->getHVStatus(); + auto& info = mProcessor->getccdbHVInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(INFO) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_HVStatus", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_HVStatus", 0}, info); + } + } + +}; // end class +} // namespace tof + +namespace framework +{ + +DataProcessorSpec getTOFDCSDataProcessorSpec() +{ + + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_LVStatus"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_LVStatus"}); + + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_HVStatus"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_HVStatus"}); + + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_DCSDPs"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_DCSDPs"}); + + return DataProcessorSpec{ + "tof-dcs-data-processor", + Inputs{{"input", "DCS", "TOFDATAPOINTS"}}, + outputs, + AlgorithmSpec{adaptFromTask<o2::tof::TOFDCSDataProcessor>()}, + Options{{"ccdb-path", VariantType::String, "http://localhost:8080", {"Path to CCDB"}}, + {"use-ccdb-to-configure", VariantType::Bool, false, {"Use CCDB to configure"}}, + {"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, + {"DPs-update-interval", VariantType::Int64, 600ll, {"Interval (in s) after which to update the DPs CCDB entry"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/testWorkflow/TOFDiagnosticCalibratorSpec.h b/Detectors/TOF/calibration/testWorkflow/TOFDiagnosticCalibratorSpec.h new file mode 100644 index 0000000000000..0c8514b4fc945 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/TOFDiagnosticCalibratorSpec.h @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TOF_DIAGNOSTIC_CALIBRATOR_H +#define O2_TOF_DIAGNOSTIC_CALIBRATOR_H + +/// @file TOFDiagnosticCalibratorSpec.h +/// @brief Device to stor in CCDB the diagnostic words from TOF + +#include "TOFCalibration/TOFDiagnosticCalibrator.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace calibration +{ + +class TOFDiagnosticCalibDevice : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + int slotL = ic.options().get<int>("tf-per-slot"); + int delay = ic.options().get<int>("max-delay"); + mCalibrator = std::make_unique<o2::tof::TOFDiagnosticCalibrator>(); + mCalibrator->setSlotLength(slotL); + mCalibrator->setMaxSlotsDelay(delay); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + auto const data = pc.inputs().get<o2::tof::Diagnostic*>("input"); + LOG(INFO) << "Processing TF " << tfcounter; + mCalibrator->process<o2::tof::Diagnostic>(tfcounter, *data); + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOG(INFO) << "Finalizing calibration"; + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<o2::tof::TOFDiagnosticCalibrator> mCalibrator; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + using clbUtils = o2::calibration::Utils; + const auto& payloadVec = mCalibrator->getDiagnosticVector(); + auto& infoVec = mCalibrator->getDiagnosticInfoVector(); // use non-const version as we update it + assert(payloadVec.size() == infoVec.size()); + for (uint32_t i = 0; i < payloadVec.size(); i++) { + auto& w = infoVec[i]; + auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &w); + LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() + << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_Diagnostic", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_Diagnostic", i}, w); // root-serialized + } + if (payloadVec.size()) { + mCalibrator->initOutput(); // reset the outputs once they are already sent + } + } +}; + +} // namespace calibration + +namespace framework +{ + +DataProcessorSpec getTOFDiagnosticCalibDeviceSpec() +{ + using device = o2::calibration::TOFDiagnosticCalibDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TOF_Diagnostic"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TOF_Diagnostic"}); + return DataProcessorSpec{ + "tof-diagnostic-calibration", + Inputs{{"input", "TOF", "DIAGNOSTIC"}}, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"tf-per-slot", VariantType::Int, 5, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int, 3, {"number of slots in past to consider"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/TOF/calibration/testWorkflow/data-generator-diagnostic-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/data-generator-diagnostic-workflow.cxx new file mode 100644 index 0000000000000..b4fd0c6f0bfb3 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/data-generator-diagnostic-workflow.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "DataGeneratorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"lanes", o2::framework::VariantType::Int, 2, {"number of data generator lanes"}}); + workflowOptions.push_back(ConfigParamSpec{"gen-norm", o2::framework::VariantType::Int, 1, {"nominal number of expected generators"}}); + workflowOptions.push_back(ConfigParamSpec{"gen-slot", o2::framework::VariantType::Int, 0, {"generate TFs of slot in [0 : gen-norm) range"}}); + workflowOptions.push_back(ConfigParamSpec{"pressure", o2::framework::VariantType::Float, 1.f, {"generation / processing rate factor"}}); + workflowOptions.push_back(ConfigParamSpec{"mean-latency", o2::framework::VariantType::Int, 1000, {"mean latency of the processor in microseconds"}}); + workflowOptions.push_back(ConfigParamSpec{"latency-spread", o2::framework::VariantType::Int, 100, {"latency gaussian RMS of the processor in microseconds"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + auto nlanes = std::max(1, configcontext.options().get<int>("lanes")); + auto ngen = std::max(1, configcontext.options().get<int>("gen-norm")); + auto slot = std::max(0, configcontext.options().get<int>("gen-slot")); + auto latency = std::max(1, configcontext.options().get<int>("mean-latency")); + auto latencyRMS = std::max(1, configcontext.options().get<int>("latency-spread")); + auto pressure = std::max(0.001f, configcontext.options().get<float>("pressure")); + if (slot >= ngen) { + slot = 0; + ngen = 1; + } + specs.emplace_back(getTFDispatcherSpec(slot, ngen, nlanes, std::max(1, int(float(latency) / nlanes / pressure)))); + specs.emplace_back(timePipeline(getTFProcessorDiagnosticSpec(latency, latencyRMS), nlanes)); + return specs; +} diff --git a/Detectors/TOF/calibration/testWorkflow/data-generator-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/data-generator-workflow.cxx index 1a3dd7b5ec7e3..f8fa38432cbd7 100644 --- a/Detectors/TOF/calibration/testWorkflow/data-generator-workflow.cxx +++ b/Detectors/TOF/calibration/testWorkflow/data-generator-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,11 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters workflowOptions.push_back(ConfigParamSpec{"lanes", o2::framework::VariantType::Int, 2, {"number of data generator lanes"}}); + workflowOptions.push_back(ConfigParamSpec{"gen-norm", o2::framework::VariantType::Int, 1, {"nominal number of expected generators"}}); + workflowOptions.push_back(ConfigParamSpec{"gen-slot", o2::framework::VariantType::Int, 0, {"generate TFs of slot in [0 : gen-norm) range"}}); + workflowOptions.push_back(ConfigParamSpec{"pressure", o2::framework::VariantType::Float, 1.f, {"generation / processing rate factor"}}); + workflowOptions.push_back(ConfigParamSpec{"mean-latency", o2::framework::VariantType::Int, 1000, {"mean latency of the processor in microseconds"}}); + workflowOptions.push_back(ConfigParamSpec{"latency-spread", o2::framework::VariantType::Int, 100, {"latency gaussian RMS of the processor in microseconds"}}); } // ------------------------------------------------------------------ @@ -27,8 +33,17 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; - auto n = configcontext.options().get<int>("lanes"); - specs.emplace_back(getTFDispatcherSpec()); - specs.emplace_back(timePipeline(getTFProcessorSpec(), n > 1 ? n : 1)); + auto nlanes = std::max(1, configcontext.options().get<int>("lanes")); + auto ngen = std::max(1, configcontext.options().get<int>("gen-norm")); + auto slot = std::max(0, configcontext.options().get<int>("gen-slot")); + auto latency = std::max(1, configcontext.options().get<int>("mean-latency")); + auto latencyRMS = std::max(1, configcontext.options().get<int>("latency-spread")); + auto pressure = std::max(0.001f, configcontext.options().get<float>("pressure")); + if (slot >= ngen) { + slot = 0; + ngen = 1; + } + specs.emplace_back(getTFDispatcherSpec(slot, ngen, nlanes, std::max(1, int(float(latency) / nlanes / pressure)))); + specs.emplace_back(timePipeline(getTFProcessorCalibInfoTOFSpec(latency, latencyRMS), nlanes)); return specs; } diff --git a/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx index 46a8e12b3045f..4f3e44a7779e4 100644 --- a/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx +++ b/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/testWorkflow/tof-calib-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-calib-workflow.cxx index 4d14607ff69cd..99a4eee1f0641 100644 --- a/Detectors/TOF/calibration/testWorkflow/tof-calib-workflow.cxx +++ b/Detectors/TOF/calibration/testWorkflow/tof-calib-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,8 @@ #include "TOFChannelCalibratorSpec.h" #include "LHCClockCalibratorSpec.h" #include "Framework/DataProcessorSpec.h" - +#include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/CalibInfoCluster.h" using namespace o2::framework; // we need to add workflow options before including Framework/runDataProcessing @@ -22,6 +24,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) workflowOptions.push_back(ConfigParamSpec{"do-lhc-phase", o2::framework::VariantType::Bool, true, {"do LHC clock phase calibration"}}); workflowOptions.push_back(ConfigParamSpec{"do-channel-offset", o2::framework::VariantType::Bool, false, {"do TOF channel offset calibration"}}); workflowOptions.push_back(ConfigParamSpec{"attach-channel-offset-to-lhcphase", o2::framework::VariantType::Bool, false, {"do TOF channel offset calibration using the LHCphase previously calculated in the same workflow"}}); + workflowOptions.push_back(ConfigParamSpec{"cosmics", o2::framework::VariantType::Bool, false, {"for cosmics data"}}); } // ------------------------------------------------------------------ @@ -35,6 +38,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto doLHCcalib = configcontext.options().get<bool>("do-lhc-phase"); auto doChannelOffsetCalib = configcontext.options().get<bool>("do-channel-offset"); auto attachChannelOffsetToLHCphase = configcontext.options().get<bool>("attach-channel-offset-to-lhcphase"); + auto isCosmics = configcontext.options().get<bool>("cosmics"); + + if (isCosmics) { + LOG(INFO) << "Cosmics set!!!! No LHC phase, Yes channel offset"; + doChannelOffsetCalib = true; + doLHCcalib = false; + } + if (!doLHCcalib && attachChannelOffsetToLHCphase) { LOG(INFO) << "Over-writing attachChannelOffsetToLHCphase because we are not doing the LHCphase calibration"; attachChannelOffsetToLHCphase = false; @@ -49,7 +60,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(getLHCClockCalibDeviceSpec()); } if (doChannelOffsetCalib) { - specs.emplace_back(getTOFChannelCalibDeviceSpec(useCCDB, attachChannelOffsetToLHCphase)); + if (!isCosmics) { + specs.emplace_back(getTOFChannelCalibDeviceSpec<o2::dataformats::CalibInfoTOF>(useCCDB, attachChannelOffsetToLHCphase, isCosmics)); + } else { + specs.emplace_back(getTOFChannelCalibDeviceSpec<o2::tof::CalibInfoCluster>(useCCDB, attachChannelOffsetToLHCphase, isCosmics)); + } } return specs; } diff --git a/Detectors/TOF/calibration/testWorkflow/tof-channel-calib-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-channel-calib-workflow.cxx index 80c4c24770bad..9195f057f49fc 100644 --- a/Detectors/TOF/calibration/testWorkflow/tof-channel-calib-workflow.cxx +++ b/Detectors/TOF/calibration/testWorkflow/tof-channel-calib-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "TOFChannelCalibratorSpec.h" #include "Framework/DataProcessorSpec.h" +#include "DataFormatsTOF/CalibInfoTOF.h" using namespace o2::framework; @@ -28,6 +30,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; auto useCCDB = configcontext.options().get<bool>("use-ccdb"); - specs.emplace_back(getTOFChannelCalibDeviceSpec(useCCDB, false)); + specs.emplace_back(getTOFChannelCalibDeviceSpec<o2::dataformats::CalibInfoTOF>(useCCDB, false, false)); return specs; } diff --git a/Detectors/TOF/calibration/testWorkflow/tof-collect-calib-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-collect-calib-workflow.cxx index f31c9ce7984ae..fec7a06f6519c 100644 --- a/Detectors/TOF/calibration/testWorkflow/tof-collect-calib-workflow.cxx +++ b/Detectors/TOF/calibration/testWorkflow/tof-collect-calib-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/calibration/testWorkflow/tof-dcs-config-processor-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-dcs-config-processor-workflow.cxx new file mode 100644 index 0000000000000..7200cda867d69 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/tof-dcs-config-processor-workflow.cxx @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/TypeTraits.h" +#include "Framework/DataProcessorSpec.h" +#include "TOFDCSConfigProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getTOFDCSConfigProcessorSpec()); + return specs; +} diff --git a/Detectors/TOF/calibration/testWorkflow/tof-dcs-data-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-dcs-data-workflow.cxx new file mode 100644 index 0000000000000..f1ff87c70bfe1 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/tof-dcs-data-workflow.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "Framework/TypeTraits.h" +#include <unordered_map> +namespace o2::framework +{ +template <> +struct has_root_dictionary<std::unordered_map<o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue>, void> : std::true_type { +}; +} // namespace o2::framework +#include "Framework/DataProcessorSpec.h" +#include "TOFDCSDataProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getTOFDCSDataProcessorSpec()); + return specs; +} diff --git a/Detectors/TOF/calibration/testWorkflow/tof-dcs-sim-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..99cede5367218 --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/tof-dcs-sim-workflow.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// // we need to add workflow options before including Framework/runDataProcessing +// void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +// { +// // option allowing to set parameters +// } + +// ------------------------------------------------------------------ + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcontext) +{ + std::vector<o2::dcs::test::HintType> dphints; + // for TOF + // for test, we use less DPs that official ones + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_vp_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_vn_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_ip_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"tof_hv_in_[00..02]", 0, 50.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"TOF_FEACSTATUS_[00..01]", 0, 255}); + dphints.emplace_back(o2::dcs::test::DataPointHint<int32_t>{"TOF_HVSTATUS_SM[00..01]MOD[0..1]", 0, 524287}); + // for TOF, official list + //mTOFDataPointHints.emplace_back(DataPointHint<double>{"tof_hv_vp_[00..89]", 0, 50.}); + //mTOFDataPointHints.emplace_back(DataPointHint<double>{"tof_hv_vn_[00..89]", 0, 50.}); + //mTOFDataPointHints.emplace_back(DataPointHint<double>{"tof_hv_ip_[00..89]", 0, 50.}); + //mTOFDataPointHints.emplace_back(DataPointHint<double>{"tof_hv_in_[00..89]", 0, 50.}); + //mTOFDataPointHints.emplace_back(DataPointHint<int32_t>{"TOF_FEACSTATUS_[00..71]", 0, 255}); + //mTOFDataPointHints.emplace_back(DataPointHint<int32_t>{"TOF_HVSTATUS_SM[00..17]MOD[0..4]", 0, 524287}); + o2::framework::WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "TOF")); + return specs; +} diff --git a/Detectors/TOF/calibration/testWorkflow/tof-diagnostic-workflow.cxx b/Detectors/TOF/calibration/testWorkflow/tof-diagnostic-workflow.cxx new file mode 100644 index 0000000000000..290ad5b0c3d8d --- /dev/null +++ b/Detectors/TOF/calibration/testWorkflow/tof-diagnostic-workflow.cxx @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "TOFDiagnosticCalibratorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getTOFDiagnosticCalibDeviceSpec()); + return specs; +} diff --git a/Detectors/TOF/calibration/testWorkflow/tof-dummy-ccdb-for-calib.cxx b/Detectors/TOF/calibration/testWorkflow/tof-dummy-ccdb-for-calib.cxx index 1ad9eb8662b1e..9bdb59ace622e 100644 --- a/Detectors/TOF/calibration/testWorkflow/tof-dummy-ccdb-for-calib.cxx +++ b/Detectors/TOF/calibration/testWorkflow/tof-dummy-ccdb-for-calib.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/compression/CMakeLists.txt b/Detectors/TOF/compression/CMakeLists.txt index adef2471c81e4..8ea77eb8028ba 100644 --- a/Detectors/TOF/compression/CMakeLists.txt +++ b/Detectors/TOF/compression/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFCompression SOURCES src/Compressor.cxx @@ -19,6 +20,7 @@ o2_add_executable(compressor COMPONENT_NAME tof SOURCES src/tof-compressor.cxx PUBLIC_LINK_LIBRARIES O2::TOFCompression + TARGETVARNAME tofcompressor ) o2_add_executable(compressed-inspector @@ -33,4 +35,8 @@ o2_add_executable(compressed-analysis PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils ) +if(NOT APPLE) + set_property(TARGET ${tofcompressor} PROPERTY LINK_WHAT_YOU_USE ON) + +endif() diff --git a/Detectors/TOF/compression/include/TOFCompression/Compressor.h b/Detectors/TOF/compression/include/TOFCompression/Compressor.h index 7d958bb863d05..9b39b765c223f 100644 --- a/Detectors/TOF/compression/include/TOFCompression/Compressor.h +++ b/Detectors/TOF/compression/include/TOFCompression/Compressor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ namespace o2 namespace tof { -template <typename RDH, bool verbose> +template <typename RDH, bool verbose, bool paranoid> class Compressor { diff --git a/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h b/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h index 0bd9adb6b0e0b..e18cde9d3dc4e 100644 --- a/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h +++ b/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,20 +29,18 @@ namespace o2 namespace tof { -template <typename RDH, bool verbose> +template <typename RDH, bool verbose, bool paranoid> class CompressorTask : public Task { public: - CompressorTask() { mBufferOut = new char[mBufferOutSize]; }; - ~CompressorTask() override { delete[] mBufferOut; }; + CompressorTask() = default; + ~CompressorTask() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; private: - Compressor<RDH, verbose> mCompressor; - - char* mBufferOut = nullptr; - const int mBufferOutSize = 33554432; + Compressor<RDH, verbose, paranoid> mCompressor; + int mOutputBufferSize; }; } // namespace tof diff --git a/Detectors/TOF/compression/src/Compressor.cxx b/Detectors/TOF/compression/src/Compressor.cxx index 1b31d746f36ed..a16a64e46fcdf 100644 --- a/Detectors/TOF/compression/src/Compressor.cxx +++ b/Detectors/TOF/compression/src/Compressor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -96,8 +97,8 @@ namespace o2 namespace tof { -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::processHBF() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::processHBF() { if (verbose && mDecoderVerbose) { @@ -111,6 +112,16 @@ bool Compressor<RDH, verbose>::processHBF() mEncoderRDH = reinterpret_cast<RDH*>(mEncoderPointer); auto rdh = mDecoderRDH; + /** check that we got the first RDH open **/ + if (rdh->stop || rdh->pageCnt != 0) { + std::cout << colorRed + << "[FATAL] this does not look like the first RDH in the HBF" + << colorReset + << std::endl; + o2::raw::RDHUtils::printRDH(*rdh); + return true; + } + /** loop until RDH close **/ while (!rdh->stop) { @@ -122,6 +133,16 @@ bool Compressor<RDH, verbose>::processHBF() o2::raw::RDHUtils::printRDH(*rdh); } + /** do some minimal RDH sanity checks **/ + if (rdh->feeId != mDecoderRDH->feeId || + rdh->orbit != mDecoderRDH->orbit) { + std::cout << colorRed + << "[FATAL] something does not match between this and first RDH" + << colorReset + << std::endl; + return true; + } + auto headerSize = rdh->headerSize; auto memorySize = rdh->memorySize; auto offsetToNext = rdh->offsetToNext; @@ -151,6 +172,16 @@ bool Compressor<RDH, verbose>::processHBF() o2::raw::RDHUtils::printRDH(*rdh); } + /** do some minimal RDH sanity checks **/ + if (rdh->feeId != mDecoderRDH->feeId || + rdh->orbit != mDecoderRDH->orbit) { + std::cout << colorRed + << "[FATAL] something does not match between this and first RDH" + << colorReset + << std::endl; + return true; + } + /** copy RDH open to encoder buffer **/ std::memcpy(mEncoderPointer, mDecoderRDH, mDecoderRDH->headerSize); mEncoderPointer = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(mEncoderPointer) + rdh->headerSize); @@ -167,20 +198,21 @@ bool Compressor<RDH, verbose>::processHBF() } mDecoderSaveBufferDataSize = 0; - /** bring encoder pointer back if fatal error **/ + /** updated encoder RDH open **/ + mEncoderRDH->memorySize = reinterpret_cast<char*>(mEncoderPointer) - reinterpret_cast<char*>(mEncoderRDH); + mEncoderRDH->offsetToNext = mEncoderRDH->memorySize; + + /** bring encoder pointer back if fatal error and flag it **/ if (mDecoderFatal) { mFatalCounter++; mEncoderPointer = mEncoderPointerStart; + mEncoderRDH->detectorField |= 0x00001000; } if (mDecoderError) { mErrorCounter++; } - /** updated encoder RDH open **/ - mEncoderRDH->memorySize = reinterpret_cast<char*>(mEncoderPointer) - reinterpret_cast<char*>(mEncoderRDH); - mEncoderRDH->offsetToNext = mEncoderRDH->memorySize; - /** copy RDH close to encoder buffer **/ /** CAREFUL WITH THE PAGE COUNTER **/ mEncoderRDH = reinterpret_cast<RDH*>(mEncoderPointer); @@ -208,8 +240,8 @@ bool Compressor<RDH, verbose>::processHBF() return true; } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::processDRM() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::processDRM() { if (verbose && mDecoderVerbose) { @@ -238,11 +270,10 @@ bool Compressor<RDH, verbose>::processDRM() auto bytePayload = tofDataHeader->bytePayload; printf(" %08x TOF Data Header (bytePayload=%d) \n", *mDecoderPointer, bytePayload); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** TOF Orbit **/ mDecoderSummary.tofOrbit = mDecoderPointer; @@ -251,11 +282,10 @@ bool Compressor<RDH, verbose>::processDRM() auto orbit = tofOrbit->orbit; printf(" %08x TOF Orbit (orbit=%u) \n", *mDecoderPointer, orbit); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** check DRM Data Header **/ if (!IS_DRM_GLOBAL_HEADER(*mDecoderPointer)) { @@ -272,11 +302,10 @@ bool Compressor<RDH, verbose>::processDRM() auto eventWords = drmDataHeader->eventWords; printf(" %08x DRM Data Header (drmId=%d, eventWords=%d) \n", *mDecoderPointer, drmId, eventWords); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** DRM Header Word 1 **/ mDecoderSummary.drmHeadW1 = mDecoderPointer; @@ -287,11 +316,10 @@ bool Compressor<RDH, verbose>::processDRM() auto drmHSize = drmHeadW1->drmHSize; printf(" %08x DRM Header Word 1 (partSlotMask=0x%03x, clockStatus=%d, drmHSize=%d) \n", *mDecoderPointer, partSlotMask, clockStatus, drmHSize); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** DRM Header Word 2 **/ mDecoderSummary.drmHeadW2 = mDecoderPointer; @@ -302,11 +330,10 @@ bool Compressor<RDH, verbose>::processDRM() auto readoutTimeOut = drmHeadW2->readoutTimeOut; printf(" %08x DRM Header Word 2 (enaSlotMask=0x%03x, faultSlotMask=0x%03x, readoutTimeOut=%d) \n", *mDecoderPointer, enaSlotMask, faultSlotMask, readoutTimeOut); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** DRM Header Word 3 **/ mDecoderSummary.drmHeadW3 = mDecoderPointer; @@ -316,33 +343,30 @@ bool Compressor<RDH, verbose>::processDRM() auto locBunchCnt = drmHeadW3->locBunchCnt; printf(" %08x DRM Header Word 3 (gbtBunchCnt=%d, locBunchCnt=%d) \n", *mDecoderPointer, gbtBunchCnt, locBunchCnt); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** DRM Header Word 4 **/ mDecoderSummary.drmHeadW4 = mDecoderPointer; if (verbose && mDecoderVerbose) { printf(" %08x DRM Header Word 4 \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** DRM Header Word 5 **/ mDecoderSummary.drmHeadW5 = mDecoderPointer; if (verbose && mDecoderVerbose) { printf(" %08x DRM Header Word 5 \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** encode Crate Header **/ *mEncoderPointer = 0x80000000; @@ -393,22 +417,20 @@ bool Compressor<RDH, verbose>::processDRM() auto locEvCnt = drmDataTrailer->locEvCnt; printf(" %08x DRM Data Trailer (locEvCnt=%d) \n", *mDecoderPointer, locEvCnt); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** filler detected **/ if (IS_FILLER(*mDecoderPointer)) { if (verbose && mDecoderVerbose) { printf(" %08x Filler \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } } /** encode Crate Trailer **/ @@ -418,7 +440,9 @@ bool Compressor<RDH, verbose>::processDRM() /** check event **/ checkerCheck(); *mEncoderPointer |= mCheckerSummary.nDiagnosticWords; +#if ENCODE_TDC_ERRORS *mEncoderPointer |= (mCheckerSummary.nTDCErrors << 16); +#endif if (verbose && mEncoderVerbose) { auto CrateTrailer = reinterpret_cast<compressed::CrateTrailer_t*>(mEncoderPointer); @@ -445,6 +469,7 @@ bool Compressor<RDH, verbose>::processDRM() /** encode TDC errors **/ for (int itrm = 0; itrm < 10; ++itrm) { for (int ichain = 0; ichain < 2; ++ichain) { +#if ENCODE_TDC_ERRORS for (int ierror = 0; ierror < mDecoderSummary.trmErrors[itrm][ichain]; ++ierror) { *mEncoderPointer = *mDecoderSummary.trmError[itrm][ichain][ierror]; *mEncoderPointer &= 0xFF07FFFF; @@ -460,6 +485,7 @@ bool Compressor<RDH, verbose>::processDRM() } encoderNext(); } +#endif mDecoderSummary.trmErrors[itrm][ichain] = 0; } } @@ -508,19 +534,18 @@ bool Compressor<RDH, verbose>::processDRM() return false; } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::processLTM() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::processLTM() { /** process LTM **/ if (verbose && mDecoderVerbose) { printf(" %08x LTM Global Header \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** loop over LTM payload **/ while (true) { @@ -529,30 +554,28 @@ bool Compressor<RDH, verbose>::processLTM() if (verbose && mDecoderVerbose) { printf(" %08x LTM Global Trailer \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } break; } if (verbose && mDecoderVerbose) { printf(" %08x LTM data \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } } /** success **/ return false; } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::processTRM() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::processTRM() { /** process TRM **/ @@ -566,11 +589,10 @@ bool Compressor<RDH, verbose>::processTRM() auto emptyBit = trmDataHeader->emptyBit; printf(" %08x TRM Data Header (slotId=%u, eventWords=%d, eventCnt=%d, emptyBit=%01x) \n", *mDecoderPointer, slotId, eventWords, eventCnt, emptyBit); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** loop over TRM payload **/ while (true) { @@ -598,22 +620,20 @@ bool Compressor<RDH, verbose>::processTRM() auto lutErrorBit = trmDataTrailer->lutErrorBit; printf(" %08x TRM Data Trailer (slotId=%u, eventCRC=%d, lutErrorBit=%d) \n", *mDecoderPointer, slotId, eventCRC, lutErrorBit); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** filler detected **/ if (IS_FILLER(*mDecoderPointer)) { if (verbose && mDecoderVerbose) { printf(" %08x Filler \n", *mDecoderPointer); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } } /** encoder Spider **/ @@ -631,12 +651,11 @@ bool Compressor<RDH, verbose>::processTRM() if (verbose && mDecoderVerbose) { printf("%s %08x [ERROR] breaking TRM decode stream %s \n", colorRed, *mDecoderPointer, colorReset); } - /** decode error detected, be paranoid **/ - if (decoderParanoid()) { + decoderNext(); + if (decoderParanoid()) { /** decode error detected, be always paranoid **/ return true; } - decoderNext(); return false; } /** end of loop over TRM payload **/ @@ -645,8 +664,8 @@ bool Compressor<RDH, verbose>::processTRM() return false; } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::processTRMchain(int itrm, int ichain) { /** process TRM chain **/ @@ -660,11 +679,10 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) auto bunchCnt = trmChainHeader->bunchCnt; printf(" %08x TRM Chain-%c Header (slotId=%u, bunchCnt=%d) \n", *mDecoderPointer, ichain == 0 ? 'A' : 'B', slotId, bunchCnt); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } /** loop over TRM Chain payload **/ while (true) { @@ -683,11 +701,10 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) auto dataId = trmDataHit->dataId; printf(" %08x TRM Data Hit (time=%d, chanId=%d, tdcId=%d, dataId=0x%x) \n", *mDecoderPointer, time, chanId, tdcId, dataId); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } continue; } @@ -700,11 +717,10 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) if (verbose && mDecoderVerbose) { printf("%s %08x TDC error %s \n", colorRed, *mDecoderPointer, colorReset); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } continue; } @@ -716,11 +732,10 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) auto eventCnt = trmChainTrailer->eventCnt; printf(" %08x TRM Chain-A Trailer (slotId=%u, eventCnt=%d) \n", *mDecoderPointer, slotId, eventCnt); } -#ifdef DECODER_PARANOID - if (decoderParanoid()) - return true; -#endif decoderNext(); + if (paranoid && decoderParanoid()) { + return true; + } break; } @@ -730,12 +745,11 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) if (verbose && mDecoderVerbose) { printf("%s %08x [ERROR] breaking TRM Chain-%c decode stream %s \n", colorRed, *mDecoderPointer, ichain == 0 ? 'A' : 'B', colorReset); } - /** decode error detected, be paranoid **/ - if (decoderParanoid()) { + decoderNext(); + if (decoderParanoid()) { /** decode error detected, be alway paranoid **/ return true; } - decoderNext(); break; } /** end of loop over TRM chain payload **/ @@ -744,8 +758,8 @@ bool Compressor<RDH, verbose>::processTRMchain(int itrm, int ichain) return false; } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::decoderParanoid() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::decoderParanoid() { /** decoder paranoid **/ @@ -757,8 +771,8 @@ bool Compressor<RDH, verbose>::decoderParanoid() return false; } -template <typename RDH, bool verbose> -void Compressor<RDH, verbose>::encoderSpider(int itrm) +template <typename RDH, bool verbose, bool paranoid> +void Compressor<RDH, verbose, paranoid>::encoderSpider(int itrm) { /** encoder spider **/ @@ -870,8 +884,8 @@ void Compressor<RDH, verbose>::encoderSpider(int itrm) } } -template <typename RDH, bool verbose> -bool Compressor<RDH, verbose>::checkerCheck() +template <typename RDH, bool verbose, bool paranoid> +bool Compressor<RDH, verbose, paranoid>::checkerCheck() { /** checker check **/ @@ -1280,107 +1294,37 @@ bool Compressor<RDH, verbose>::checkerCheck() return false; } -template <typename RDH, bool verbose> -void Compressor<RDH, verbose>::checkerCheckRDH() -{ -} - -template <> -void Compressor<o2::header::RAWDataHeaderV4, true>::checkerCheckRDH() -{ - - uint32_t orbit = *mDecoderSummary.tofOrbit; - uint32_t drmId = GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader); - - /** check orbit **/ - if (mCheckerVerbose) { - printf(" --- Checking DRM/RDH orbit: %08x/%08x \n", orbit, mDecoderRDH->heartbeatOrbit); - } - if (orbit != mDecoderRDH->heartbeatOrbit) { - if (mCheckerVerbose) { - printf(" DRM/RDH orbit mismatch: %08x/%08x \n", orbit, mDecoderRDH->heartbeatOrbit); - } - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_ORBIT_MISMATCH; - } - - /** check FEE id **/ - if (mCheckerVerbose) { - printf(" --- Checking DRM/RDH FEE id: %d/%d \n", drmId, mDecoderRDH->feeId & 0xFF); - } - if (drmId != (mDecoderRDH->feeId & 0xFF)) { - if (mCheckerVerbose) { - printf(" DRM/RDH FEE id mismatch: %d/%d \n", drmId, mDecoderRDH->feeId & 0xFF); - } - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_FEEID_MISMATCH; - } -} - -template <> -void Compressor<o2::header::RAWDataHeaderV4, false>::checkerCheckRDH() -{ - - uint32_t orbit = *mDecoderSummary.tofOrbit; - uint32_t drmId = GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader); - - /** check orbit **/ - if (orbit != mDecoderRDH->heartbeatOrbit) { - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_ORBIT_MISMATCH; - } - - /** check FEE id **/ - if (drmId != (mDecoderRDH->feeId & 0xFF)) { - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_FEEID_MISMATCH; - } -} - -template <> -void Compressor<o2::header::RAWDataHeaderV6, true>::checkerCheckRDH() +template <typename RDH, bool verbose, bool paranoid> +void Compressor<RDH, verbose, paranoid>::checkerCheckRDH() { uint32_t orbit = *mDecoderSummary.tofOrbit; uint32_t drmId = GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader); /** check orbit **/ - if (mCheckerVerbose) { + if (verbose && mCheckerVerbose) { printf(" --- Checking DRM/RDH orbit: %08x/%08x \n", orbit, mDecoderRDH->orbit); } if (orbit != mDecoderRDH->orbit) { - if (mCheckerVerbose) { + if (verbose && mCheckerVerbose) { printf(" DRM/RDH orbit mismatch: %08x/%08x \n", orbit, mDecoderRDH->orbit); } mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_ORBIT_MISMATCH; } /** check FEE id **/ - if (mCheckerVerbose) { + if (verbose && mCheckerVerbose) { printf(" --- Checking DRM/RDH FEE id: %d/%d \n", drmId, mDecoderRDH->feeId & 0xFF); } if (drmId != (mDecoderRDH->feeId & 0xFF)) { - if (mCheckerVerbose) { + if (verbose && mCheckerVerbose) { printf(" DRM/RDH FEE id mismatch: %d/%d \n", drmId, mDecoderRDH->feeId & 0xFF); } mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_FEEID_MISMATCH; } } -template <> -void Compressor<o2::header::RAWDataHeaderV6, false>::checkerCheckRDH() -{ - uint32_t orbit = *mDecoderSummary.tofOrbit; - uint32_t drmId = GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader); - - /** check orbit **/ - if (orbit != mDecoderRDH->orbit) { - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_ORBIT_MISMATCH; - } - - /** check FEE id **/ - if (drmId != (mDecoderRDH->feeId & 0xFF)) { - mCheckerSummary.DiagnosticWord[0] |= diagnostic::DRM_FEEID_MISMATCH; - } -} - -template <typename RDH, bool verbose> -void Compressor<RDH, verbose>::resetCounters() +template <typename RDH, bool verbose, bool paranoid> +void Compressor<RDH, verbose, paranoid>::resetCounters() { mEventCounter = 0; mFatalCounter = 0; @@ -1394,8 +1338,8 @@ void Compressor<RDH, verbose>::resetCounters() } } -template <typename RDH, bool verbose> -void Compressor<RDH, verbose>::checkSummary() +template <typename RDH, bool verbose, bool paranoid> +void Compressor<RDH, verbose, paranoid>::checkSummary() { char chname[2] = {'a', 'b'}; @@ -1464,10 +1408,10 @@ void Compressor<RDH, verbose>::checkSummary() printf("\n"); } -template class Compressor<o2::header::RAWDataHeaderV4, false>; -template class Compressor<o2::header::RAWDataHeaderV4, true>; -template class Compressor<o2::header::RAWDataHeaderV6, false>; -template class Compressor<o2::header::RAWDataHeaderV6, true>; +template class Compressor<o2::header::RAWDataHeaderV6, false, false>; +template class Compressor<o2::header::RAWDataHeaderV6, false, true>; +template class Compressor<o2::header::RAWDataHeaderV6, true, false>; +template class Compressor<o2::header::RAWDataHeaderV6, true, true>; } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/compression/src/CompressorTask.cxx b/Detectors/TOF/compression/src/CompressorTask.cxx index 7e4d5854daec8..8ef0834b36609 100644 --- a/Detectors/TOF/compression/src/CompressorTask.cxx +++ b/Detectors/TOF/compression/src/CompressorTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "Framework/RawDeviceService.h" #include "Framework/DeviceSpec.h" #include "Framework/DataSpecUtils.h" +#include "Framework/InputRecordWalker.h" #include <fairmq/FairMQDevice.h> @@ -29,8 +31,8 @@ namespace o2 namespace tof { -template <typename RDH, bool verbose> -void CompressorTask<RDH, verbose>::init(InitContext& ic) +template <typename RDH, bool verbose, bool paranoid> +void CompressorTask<RDH, verbose, paranoid>::init(InitContext& ic) { LOG(INFO) << "Compressor init"; @@ -38,6 +40,7 @@ void CompressorTask<RDH, verbose>::init(InitContext& ic) auto decoderVerbose = ic.options().get<bool>("tof-compressor-decoder-verbose"); auto encoderVerbose = ic.options().get<bool>("tof-compressor-encoder-verbose"); auto checkerVerbose = ic.options().get<bool>("tof-compressor-checker-verbose"); + mOutputBufferSize = ic.options().get<int>("tof-compressor-output-buffer-size"); mCompressor.setDecoderCONET(decoderCONET); mCompressor.setDecoderVerbose(decoderVerbose); @@ -51,67 +54,105 @@ void CompressorTask<RDH, verbose>::init(InitContext& ic) ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishFunction); } -template <typename RDH, bool verbose> -void CompressorTask<RDH, verbose>::run(ProcessingContext& pc) +template <typename RDH, bool verbose, bool paranoid> +void CompressorTask<RDH, verbose, paranoid>::run(ProcessingContext& pc) { LOG(DEBUG) << "Compressor run"; - /** set encoder output buffer **/ - mCompressor.setEncoderBuffer(mBufferOut); - mCompressor.setEncoderBufferSize(mBufferOutSize); - auto device = pc.services().get<o2::framework::RawDeviceService>().device(); auto outputRoutes = pc.services().get<o2::framework::RawDeviceService>().spec().outputs; auto fairMQChannel = outputRoutes.at(0).channel; + FairMQParts partsOut; + + /** to store data sorted by subspec id **/ + std::map<int, std::vector<o2::framework::DataRef>> subspecPartMap; + std::map<int, int> subspecBufferSize; /** loop over inputs routes **/ - for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { - if (!iit.isValid()) { - continue; + std::vector<InputSpec> sel{InputSpec{"filter", ConcreteDataTypeMatcher{"TOF", "RAWDATA"}}}; + for (const auto& ref : InputRecordWalker(pc.inputs(), sel)) { + // for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { + // if (!iit.isValid()) { + // continue; + // } + + /** loop over input parts **/ + // for (auto const& ref : iit) { + + /** store parts in map **/ + auto headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + auto subspec = headerIn->subSpecification; + subspecPartMap[subspec].push_back(ref); + + /** increase subspec buffer size **/ + if (!subspecBufferSize.count(subspec)) { + subspecBufferSize[subspec] = 0; } + subspecBufferSize[subspec] += headerIn->payloadSize; + // } + } - /** prepare output parts **/ - FairMQParts parts; + /** loop over subspecs **/ + for (auto& subspecPartEntry : subspecPartMap) { - /** loop over input parts **/ - for (auto const& ref : iit) { + auto subspec = subspecPartEntry.first; + auto parts = subspecPartEntry.second; + auto& firstPart = parts.at(0); + + /** use the first part to define output headers **/ + auto headerOut = *DataRefUtils::getHeader<o2::header::DataHeader*>(firstPart); + auto dataProcessingHeaderOut = *DataRefUtils::getHeader<o2::framework::DataProcessingHeader*>(firstPart); + headerOut.dataDescription = "CRAWDATA"; + headerOut.payloadSize = 0; + headerOut.splitPayloadParts = 1; + + /** initialise output message **/ + auto bufferSize = mOutputBufferSize >= 0 ? mOutputBufferSize + subspecBufferSize[subspec] : std::abs(mOutputBufferSize); + auto payloadMessage = device->NewMessage(bufferSize); + auto bufferPointer = (char*)payloadMessage->GetData(); + + /** loop over subspec parts **/ + for (const auto& ref : parts) { + /** input **/ auto headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); auto dataProcessingHeaderIn = DataRefUtils::getHeader<o2::framework::DataProcessingHeader*>(ref); auto payloadIn = ref.payload; auto payloadInSize = headerIn->payloadSize; + + /** prepare compressor **/ mCompressor.setDecoderBuffer(payloadIn); mCompressor.setDecoderBufferSize(payloadInSize); + mCompressor.setEncoderBuffer(bufferPointer); + mCompressor.setEncoderBufferSize(bufferSize); /** run **/ mCompressor.run(); auto payloadOutSize = mCompressor.getEncoderByteCounter(); - auto payloadMessage = device->NewMessage(payloadOutSize); - std::memcpy(payloadMessage->GetData(), mBufferOut, payloadOutSize); - - /** output **/ - auto headerOut = *headerIn; - auto dataProcessingHeaderOut = *dataProcessingHeaderIn; - headerOut.dataDescription = "CRAWDATA"; - headerOut.payloadSize = payloadOutSize; - o2::header::Stack headerStack{headerOut, dataProcessingHeaderOut}; - auto headerMessage = device->NewMessage(headerStack.size()); - std::memcpy(headerMessage->GetData(), headerStack.data(), headerStack.size()); - - /** add parts **/ - parts.AddPart(std::move(headerMessage)); - parts.AddPart(std::move(payloadMessage)); + bufferPointer += payloadOutSize; + bufferSize -= payloadOutSize; + headerOut.payloadSize += payloadOutSize; } - /** send message **/ - device->Send(parts, fairMQChannel); + /** finalise output message **/ + payloadMessage->SetUsedSize(headerOut.payloadSize); + o2::header::Stack headerStack{headerOut, dataProcessingHeaderOut}; + auto headerMessage = device->NewMessage(headerStack.size()); + std::memcpy(headerMessage->GetData(), headerStack.data(), headerStack.size()); + + /** add parts **/ + partsOut.AddPart(std::move(headerMessage)); + partsOut.AddPart(std::move(payloadMessage)); } + + /** send message **/ + device->Send(partsOut, fairMQChannel); } -template class CompressorTask<o2::header::RAWDataHeaderV4, true>; -template class CompressorTask<o2::header::RAWDataHeaderV4, false>; -template class CompressorTask<o2::header::RAWDataHeaderV6, true>; -template class CompressorTask<o2::header::RAWDataHeaderV6, false>; +template class CompressorTask<o2::header::RAWDataHeaderV6, false, false>; +template class CompressorTask<o2::header::RAWDataHeaderV6, false, true>; +template class CompressorTask<o2::header::RAWDataHeaderV6, true, false>; +template class CompressorTask<o2::header::RAWDataHeaderV6, true, true>; } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/compression/src/tof-compressed-analysis.cxx b/Detectors/TOF/compression/src/tof-compressed-analysis.cxx index 4f194448841dc..4d76626ba8a43 100644 --- a/Detectors/TOF/compression/src/tof-compressed-analysis.cxx +++ b/Detectors/TOF/compression/src/tof-compressed-analysis.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,8 @@ using namespace o2::framework; // including Framework/runDataProcessing void customize(std::vector<ConfigParamSpec>& workflowOptions) { + auto inputDesc = ConfigParamSpec{"tof-compressed-analysis-input-desc", VariantType::String, "CRAWDATA", {"Input specs description string"}}; + workflowOptions.push_back(inputDesc); } #include "Framework/runDataProcessing.h" // the main driver @@ -31,9 +34,11 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) /// This function hooks up the the workflow specifications into the DPL driver. WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + auto inputDesc = cfgc.options().get<std::string>("tof-compressed-analysis-input-desc"); + return WorkflowSpec{ DataProcessorSpec{"compressed-analysis", - select("x:TOF/CRAWDATA"), + select(std::string("x:TOF/" + inputDesc).c_str()), Outputs{}, AlgorithmSpec(adaptFromTask<o2::tof::CompressedAnalysisTask>()), Options{ diff --git a/Detectors/TOF/compression/src/tof-compressed-inspector.cxx b/Detectors/TOF/compression/src/tof-compressed-inspector.cxx index 654858b3b264a..9f1d918932fd8 100644 --- a/Detectors/TOF/compression/src/tof-compressed-inspector.cxx +++ b/Detectors/TOF/compression/src/tof-compressed-inspector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,7 +53,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) Outputs{}, algoSpec, Options{ - {"tof-compressed-inspector-filename", VariantType::String, "inspector.root", {"Name of the inspector output file"}}}}); + {"tof-compressed-inspector-filename", VariantType::String, "inspector.root", {"Name of the inspector output file"}}, + {"tof-compressed-inspector-decoder-verbose", VariantType::Bool, false, {"Decode in verbose mode"}}}}); return workflow; } diff --git a/Detectors/TOF/compression/src/tof-compressor.cxx b/Detectors/TOF/compression/src/tof-compressor.cxx index 15ab4be396642..baf3db7536ff1 100644 --- a/Detectors/TOF/compression/src/tof-compressor.cxx +++ b/Detectors/TOF/compression/src/tof-compressor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,8 @@ #include "Framework/ConcreteDataMatcher.h" #include "Framework/Logger.h" #include "DetectorsRaw/RDHUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" using namespace o2::framework; @@ -30,11 +33,16 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) auto outputDesc = ConfigParamSpec{"tof-compressor-output-desc", VariantType::String, "CRAWDATA", {"Output specs description string"}}; auto rdhVersion = ConfigParamSpec{"tof-compressor-rdh-version", VariantType::Int, o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(), {"Raw Data Header version"}}; auto verbose = ConfigParamSpec{"tof-compressor-verbose", VariantType::Bool, false, {"Enable verbose compressor"}}; + auto paranoid = ConfigParamSpec{"tof-compressor-paranoid", VariantType::Bool, false, {"Enable paranoid compressor"}}; + auto ignoreStf = ConfigParamSpec{"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}; workflowOptions.push_back(config); workflowOptions.push_back(outputDesc); workflowOptions.push_back(rdhVersion); workflowOptions.push_back(verbose); + workflowOptions.push_back(paranoid); + workflowOptions.push_back(ignoreStf); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); } #include "Framework/runDataProcessing.h" // the main driver @@ -42,26 +50,29 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) /// This function hooks up the the workflow specifications into the DPL driver. WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); auto config = cfgc.options().get<std::string>("tof-compressor-config"); // auto outputDesc = cfgc.options().get<std::string>("output-desc"); auto rdhVersion = cfgc.options().get<int>("tof-compressor-rdh-version"); auto verbose = cfgc.options().get<bool>("tof-compressor-verbose"); + auto paranoid = cfgc.options().get<bool>("tof-compressor-paranoid"); + auto ignoreStf = cfgc.options().get<bool>("ignore-dist-stf"); std::vector<OutputSpec> outputs; outputs.emplace_back(OutputSpec(ConcreteDataTypeMatcher{"TOF", "CRAWDATA"})); AlgorithmSpec algoSpec; - if (rdhVersion == 4) { - if (verbose) { - algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV4, true>>()}; - } else { - algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV4, false>>()}; + if (rdhVersion == 6) { + if (!verbose && !paranoid) { + algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, false, false>>()}; + } + if (!verbose && paranoid) { + algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, false, true>>()}; } - } else if (rdhVersion == 6) { - if (verbose) { - algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, true>>()}; - } else { - algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, false>>()}; + if (verbose && !paranoid) { + algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, true, false>>()}; + } + if (verbose && paranoid) { + algoSpec = AlgorithmSpec{adaptFromTask<o2::tof::CompressorTask<o2::header::RAWDataHeaderV6, true, true>>()}; } } @@ -73,11 +84,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) This is is done with a configuration string like the following one, where the input matching for each device is provide in comma-separated strings. For instance - + A:TOF/RAWDATA/768;B:TOF/RAWDATA/1024,C:TOF/RAWDATA/1280;D:TOF/RAWDATA/1536 - + will lead to a workflow with 2 devices which will input match - + tof-compressor-0 --> A:TOF/RAWDATA/768;B:TOF/RAWDATA/1024 tof-compressor-1 --> C:TOF/RAWDATA/1280;D:TOF/RAWDATA/1536 **/ @@ -87,12 +98,21 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) int idevice = 0; while (getline(ssconfig, iconfig, ',')) { + std::vector<InputSpec> inputs = select(iconfig.c_str()); + if (!ignoreStf) { + for (auto& val : inputs) { + val.lifetime = Lifetime::Optional; + } + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } workflow.emplace_back(DataProcessorSpec{ std::string("tof-compressor-") + std::to_string(idevice), - select(iconfig.c_str()), + // select(iconfig.c_str()), + inputs, outputs, algoSpec, Options{ + {"tof-compressor-output-buffer-size", VariantType::Int, 0, {"Encoder output buffer size (in bytes). Zero = automatic (careful)."}}, {"tof-compressor-conet-mode", VariantType::Bool, false, {"Decoder CONET flag"}}, {"tof-compressor-decoder-verbose", VariantType::Bool, false, {"Decoder verbose flag"}}, {"tof-compressor-encoder-verbose", VariantType::Bool, false, {"Encoder verbose flag"}}, diff --git a/Detectors/TOF/prototyping/CMakeLists.txt b/Detectors/TOF/prototyping/CMakeLists.txt index 7ed9c7157a7d9..eff28025f5f8c 100644 --- a/Detectors/TOF/prototyping/CMakeLists.txt +++ b/Detectors/TOF/prototyping/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(checkRotation.C PUBLIC_LINK_LIBRARIES O2::TOFBase diff --git a/Detectors/TOF/prototyping/drawTOFgeometry.C b/Detectors/TOF/prototyping/drawTOFgeometry.C index 97ea964efe595..ca13d8b72470f 100644 --- a/Detectors/TOF/prototyping/drawTOFgeometry.C +++ b/Detectors/TOF/prototyping/drawTOFgeometry.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/prototyping/findLabels.C b/Detectors/TOF/prototyping/findLabels.C index 6f1ce86e31ed7..b43fac2a2043a 100644 --- a/Detectors/TOF/prototyping/findLabels.C +++ b/Detectors/TOF/prototyping/findLabels.C @@ -24,9 +24,9 @@ void findLabels(int itrk, int ientry) // getting the TPC tracks TFile* ftracksTPC = new TFile("tpctracks.root"); - TTree* tpcTree = (TTree*)ftracksTPC->Get("events"); + TTree* tpcTree = (TTree*)ftracksTPC->Get("tpcrec"); std::vector<o2::tpc::TrackTPC>* mTPCTracksArrayInp = new std::vector<o2::tpc::TrackTPC>; - tpcTree->SetBranchAddress("Tracks", &mTPCTracksArrayInp); + tpcTree->SetBranchAddress("TPCTracks", &mTPCTracksArrayInp); o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mcTPC = new o2::dataformats::MCTruthContainer<o2::MCCompLabel>(); tpcTree->SetBranchAddress("TPCTracksMCTruth", &mcTPC); diff --git a/Detectors/TOF/prototyping/findTOFclusterFromLabel.C b/Detectors/TOF/prototyping/findTOFclusterFromLabel.C index 533d555a76aa9..6dc6299f3d46b 100644 --- a/Detectors/TOF/prototyping/findTOFclusterFromLabel.C +++ b/Detectors/TOF/prototyping/findTOFclusterFromLabel.C @@ -107,9 +107,9 @@ void findTOFclusterFromLabel(int trackID, int eventID = 0, int sourceID = 0) // getting the TPC tracks TFile* ftracksTPC = new TFile("tpctracks.root"); - TTree* tpcTree = (TTree*)ftracksTPC->Get("events"); + TTree* tpcTree = (TTree*)ftracksTPC->Get("tpcrec"); std::vector<o2::tpc::TrackTPC>* mTPCTracksArrayInp = new std::vector<o2::tpc::TrackTPC>; - tpcTree->SetBranchAddress("Tracks", &mTPCTracksArrayInp); + tpcTree->SetBranchAddress("TPCTracks", &mTPCTracksArrayInp); o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mcTPC = new o2::dataformats::MCTruthContainer<o2::MCCompLabel>(); tpcTree->SetBranchAddress("TPCTracksMCTruth", &mcTPC); tpcTree->GetEntry(eventID); diff --git a/Detectors/TOF/reconstruction/CMakeLists.txt b/Detectors/TOF/reconstruction/CMakeLists.txt index d577164f5202e..0e79336416683 100644 --- a/Detectors/TOF/reconstruction/CMakeLists.txt +++ b/Detectors/TOF/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFReconstruction SOURCES src/DataReader.cxx src/Clusterer.cxx @@ -14,18 +15,22 @@ o2_add_library(TOFReconstruction src/DecoderBase.cxx src/Decoder.cxx src/CTFCoder.cxx + src/EventTimeMaker.cxx + src/CosmicProcessor.cxx PUBLIC_LINK_LIBRARIES O2::TOFBase O2::DataFormatsTOF O2::SimulationDataFormat O2::CommonDataFormat O2::DataFormatsTOF O2::rANS O2::DPLUtils - O2::TOFCalibration O2::DetectorsRaw) + O2::TOFCalibration O2::DetectorsRaw) o2_target_root_dictionary(TOFReconstruction HEADERS include/TOFReconstruction/DataReader.h include/TOFReconstruction/Clusterer.h include/TOFReconstruction/ClustererTask.h include/TOFReconstruction/Encoder.h - include/TOFReconstruction/DecoderBase.h + include/TOFReconstruction/DecoderBase.h include/TOFReconstruction/Decoder.h - include/TOFReconstruction/CTFCoder.h) + include/TOFReconstruction/CTFCoder.h + include/TOFReconstruction/EventTimeMaker.h + include/TOFReconstruction/CosmicProcessor.h) diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h index edea8157d760e..f923a835c9a64 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ class CTFCoder : public o2::ctf::CTFCoderBase /// entropy-encode clusters to buffer with CTF template <typename VEC> - void encode(VEC& buff, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint32_t>& pattVec); + void encode(VEC& buff, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint8_t>& pattVec); /// entropy decode clusters from buffer with CTF template <typename VROF, typename VDIG, typename VPAT> @@ -49,14 +50,14 @@ class CTFCoder : public o2::ctf::CTFCoderBase private: /// compres compact clusters to CompressedInfos - void compress(CompressedInfos& cc, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint32_t>& pattVec); + void compress(CompressedInfos& cc, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint8_t>& pattVec); size_t estimateCompressedSize(const CompressedInfos& cc); /// decompress CompressedInfos to compact clusters template <typename VROF, typename VDIG, typename VPAT> void decompress(const CompressedInfos& cc, VROF& rofRecVec, VDIG& cdigVec, VPAT& pattVec); void appendToTree(TTree& tree, CTF& ec); - void readFromTree(TTree& tree, int entry, std::vector<ReadoutWindowData>& rofRecVec, std::vector<Digit>& cdigVec, std::vector<uint32_t>& pattVec); + void readFromTree(TTree& tree, int entry, std::vector<ReadoutWindowData>& rofRecVec, std::vector<Digit>& cdigVec, std::vector<uint8_t>& pattVec); protected: ClassDefNV(CTFCoder, 1); @@ -65,7 +66,7 @@ class CTFCoder : public o2::ctf::CTFCoderBase ///___________________________________________________________________________________ /// entropy-encode digits to buffer with CTF template <typename VEC> -void CTFCoder::encode(VEC& buff, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint32_t>& pattVec) +void CTFCoder::encode(VEC& buff, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, const gsl::span<const uint8_t>& pattVec) { using MD = o2::ctf::Metadata::OptStore; // what to do which each field: see o2::ctd::Metadata explanation @@ -92,6 +93,7 @@ void CTFCoder::encode(VEC& buff, const gsl::span<const ReadoutWindowData>& rofRe using ECB = CTF::base; ec->setHeader(cc.header); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec @@ -120,6 +122,7 @@ void CTFCoder::decode(const CTF::base& ec, VROF& rofRecVec, VDIG& cdigVec, VPAT& CompressedInfos cc; ec.print(getPrefix()); cc.header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cc.header)); #define DECODETOF(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) // clang-format off DECODETOF(cc.bcIncROF, CTF::BLCbcIncROF); @@ -127,7 +130,7 @@ void CTFCoder::decode(const CTF::base& ec, VROF& rofRecVec, VDIG& cdigVec, VPAT& DECODETOF(cc.ndigROF, CTF::BLCndigROF); DECODETOF(cc.ndiaROF, CTF::BLCndiaROF); DECODETOF(cc.ndiaCrate, CTF::BLCndiaCrate); - + DECODETOF(cc.timeFrameInc, CTF::BLCtimeFrameInc); DECODETOF(cc.timeTDCInc, CTF::BLCtimeTDCInc); DECODETOF(cc.stripID, CTF::BLCstripID); @@ -180,7 +183,7 @@ void CTFCoder::decompress(const CompressedInfos& cc, VROF& rofRecVec, VDIG& cdig int firstDig = digCount; - int BCrow = prevIR.orbit * Geo::BC_IN_ORBIT + prevIR.bc; + int64_t BCrow = prevIR.toLong(); digCopy.resize(cc.ndigROF[irof]); for (uint32_t idig = 0; idig < cc.ndigROF[irof]; idig++) { @@ -192,7 +195,7 @@ void CTFCoder::decompress(const CompressedInfos& cc, VROF& rofRecVec, VDIG& cdig } else { ctdc += cc.timeTDCInc[digCount]; } - LOGF(DEBUG, "BC=%d, TDC=%d, TOT=%d, CH=%d", uint32_t(ctimeframe) * 64 + ctdc / 1024 + BCrow, ctdc % 1024, cc.tot[digCount], uint32_t(cc.stripID[digCount]) * 96 + cc.chanInStrip[digCount]); + LOGF(DEBUG, "BC=%ld, TDC=%d, TOT=%d, CH=%d", uint32_t(ctimeframe) * 64 + ctdc / 1024 + BCrow, ctdc % 1024, cc.tot[digCount], uint32_t(cc.stripID[digCount]) * 96 + cc.chanInStrip[digCount]); digit.setBC(uint32_t(ctimeframe) * 64 + ctdc / 1024 + BCrow); digit.setTDC(ctdc % 1024); diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/Clusterer.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/Clusterer.h index 3049a955c8e26..de67538617429 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/Clusterer.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/Clusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include <utility> #include <vector> #include "DataFormatsTOF/Cluster.h" +#include "DataFormatsTOF/CalibInfoCluster.h" #include "TOFBase/Geo.h" #include "TOFReconstruction/DataReader.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -51,8 +53,17 @@ class Clusterer mCalibApi = calibApi; } - void setFirstOrbit(uint32_t orb); - uint32_t getFirstOrbit() const { return mFirstOrbit; } + void addCalibFromCluster(int ch1, int8_t dch, float dtime, short tot1, short tot2); + + void setFirstOrbit(uint64_t orb); + uint64_t getFirstOrbit() const { return mFirstOrbit; } + + void setCalibFromCluster(bool val = 1) { mCalibFromCluster = val; } + bool isCalibFromCluster() const { return mCalibFromCluster; } + + void setDeltaTforClustering(float val) { mDeltaTforClustering = val; } + float getDeltaTforClustering() const { return mDeltaTforClustering; } + std::vector<o2::tof::CalibInfoCluster>* getInfoFromCluster() { return &mCalibInfosFromCluster; } private: void calibrateStrip(); @@ -68,8 +79,13 @@ class Clusterer void addContributingDigit(Digit* dig); void buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth); CalibApi* mCalibApi = nullptr; //! calib api to handle the TOF calibration - uint32_t mFirstOrbit = 0; //! 1st orbit of the TF + uint64_t mFirstOrbit = 0; //! 1st orbit of the TF uint64_t mBCOffset = 0; //! 1st orbit of the TF converted to BCs + + float mDeltaTforClustering = 5000; //! delta time (in ps) accepted for clustering + bool mCalibFromCluster = false; //! if producing calib from clusters + + std::vector<o2::tof::CalibInfoCluster> mCalibInfosFromCluster; }; } // namespace tof diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/ClustererTask.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/ClustererTask.h index 45b0caffa4a24..b44388e98aebd 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/ClustererTask.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/ClustererTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/CosmicProcessor.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/CosmicProcessor.h new file mode 100644 index 0000000000000..7342447c5ede7 --- /dev/null +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/CosmicProcessor.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CosmicProcessor.h +/// \brief Managing digitsi in a RO window to provide cosmics candidates +#ifndef ALICEO2_TOF_COSMICPROCESSOR_H +#define ALICEO2_TOF_COSMICPROCESSOR_H + +#include <utility> +#include <vector> +#include "TOFBase/Geo.h" +#include "TOFBase/Digit.h" +#include "TOFReconstruction/DataReader.h" +#include "DataFormatsTOF/CosmicInfo.h" + +namespace o2 +{ + +namespace tof +{ +class CosmicProcessor +{ + using Digit = o2::tof::Digit; + using StripData = o2::tof::DataReader::StripData; + + public: + CosmicProcessor() = default; + ~CosmicProcessor() = default; + + CosmicProcessor(const CosmicProcessor&) = delete; + CosmicProcessor& operator=(const CosmicProcessor&) = delete; + + void process(DigitDataReader& r, bool fill = true); + void processTrack(); + void clear(); + std::vector<CosmicInfo>* getCosmicInfo() { return (&mCosmicInfo); } + std::vector<CalibInfoTrackCl>* getCosmicTrack() { return (&mCosmicTrack); } + std::vector<int>* getCosmicTrackSize() { return (&mSizeTrack); } + + private: + std::vector<CosmicInfo> mCosmicInfo; + std::vector<CalibInfoTrackCl> mCosmicTrack; + std::vector<CalibInfoTrackCl> mCosmicTrackTemp; + std::vector<int> mSizeTrack; + int mCounters[Geo::NCHANNELS]; +}; + +} // namespace tof +} // namespace o2 +#endif /* ALICEO2_TOF_COSMICPROCESSOR_H */ diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/DataReader.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/DataReader.h index a9000b29b85b4..6b8de627544d8 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/DataReader.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/DataReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -74,6 +75,8 @@ class DigitDataReader : public DataReader Bool_t getNextStripData(StripData& stripData) override; + const gsl::span<const o2::tof::Digit>* getDigitArray() const { return mDigitArray; } + private: const gsl::span<const o2::tof::Digit>* mDigitArray = nullptr; const Digit* mLastDigit = nullptr; diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/Decoder.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/Decoder.h index 735273db631f4..ba27b7805059c 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/Decoder.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/Decoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,7 +47,7 @@ class Decoder : public WindowFiller bool decode(); void readTRM(int icru, int icrate, uint32_t orbit, uint16_t bunchid); void InsertDigit(int icrate, int itrm, int itdc, int ichain, int channel, uint32_t orbit, uint16_t bunchid, int time_ext, int tdc, int tot); - void FillWindows(); + void fillWindows(); void clear(); bool close(); diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/DecoderBase.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/DecoderBase.h index a4346afb59298..348b864ab1f70 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/DecoderBase.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/DecoderBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/Encoder.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/Encoder.h index 98de71d3adadb..8f33a6a3f90a6 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/Encoder.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/Encoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/EventTimeMaker.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/EventTimeMaker.h new file mode 100644 index 0000000000000..18e14bd5b15c2 --- /dev/null +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/EventTimeMaker.h @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EventTimeMaker.h +/// \brief Definition of the TOF event time maker + +#ifndef ALICEO2_TOF_EVENTTIMEMAKER_H +#define ALICEO2_TOF_EVENTTIMEMAKER_H + +namespace o2 +{ + +namespace tof +{ + +struct eventTimeContainer { + eventTimeContainer(const float& e) : eventTime{e} {}; + float eventTime = 0.f; +}; + +template <typename tTracks> +eventTimeContainer evTimeMaker(const tTracks& tracks) +{ + for (auto track : tracks) { + track.tofSignal(); + } + return eventTimeContainer{0}; +} + +} // namespace tof +} // namespace o2 + +#endif /* ALICEO2_TOF_EVENTTIMEMAKER_H */ \ No newline at end of file diff --git a/Detectors/TOF/reconstruction/src/CTFCoder.cxx b/Detectors/TOF/reconstruction/src/CTFCoder.cxx index 8a72aab4ac933..c883f0dbe5b55 100644 --- a/Detectors/TOF/reconstruction/src/CTFCoder.cxx +++ b/Detectors/TOF/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,7 @@ void CTFCoder::appendToTree(TTree& tree, CTF& ec) ///___________________________________________________________________________________ // extract and decode data from the tree -void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ReadoutWindowData>& rofRecVec, std::vector<Digit>& cdigVec, std::vector<uint32_t>& pattVec) +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ReadoutWindowData>& rofRecVec, std::vector<Digit>& cdigVec, std::vector<uint8_t>& pattVec) { assert(entry >= 0 && entry < tree.GetEntries()); CTF ec; @@ -39,7 +40,7 @@ void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<ReadoutWindowDat void CTFCoder::compress(CompressedInfos& cc, const gsl::span<const ReadoutWindowData>& rofRecVec, const gsl::span<const Digit>& cdigVec, - const gsl::span<const uint32_t>& pattVec) + const gsl::span<const uint8_t>& pattVec) { // store in the header the orbit of 1st ROF cc.clear(); @@ -49,7 +50,7 @@ void CTFCoder::compress(CompressedInfos& cc, const auto& rofRec0 = rofRecVec[0]; int nrof = rofRecVec.size(); - LOGF(INFO, "TOF compress %d ReadoutWindow with %ld digits", nrof, cdigVec.size()); + LOGF(DEBUG, "TOF compress %d ReadoutWindow with %ld digits", nrof, cdigVec.size()); cc.header.nROFs = nrof; cc.header.firstOrbit = rofRec0.getBCData().orbit; @@ -68,7 +69,7 @@ void CTFCoder::compress(CompressedInfos& cc, cc.stripID.resize(cc.header.nDigits); cc.chanInStrip.resize(cc.header.nDigits); cc.tot.resize(cc.header.nDigits); - cc.pattMap.resize(cc.header.nPatternBytes); + cc.pattMap.resize(pattVec.size()); uint16_t prevBC = cc.header.firstBC; uint32_t prevOrbit = cc.header.firstOrbit; @@ -79,7 +80,7 @@ void CTFCoder::compress(CompressedInfos& cc, const auto& rofRec = rofRecVec[irof]; const auto& intRec = rofRec.getBCData(); - int rofInBC = intRec.toLong(); + int64_t rofInBC = intRec.toLong(); // define interaction record if (intRec.orbit == prevOrbit) { cc.orbitIncROF[irof] = 0; @@ -150,7 +151,6 @@ void CTFCoder::compress(CompressedInfos& cc, LOGF(DEBUG, "%d) TF=%d, TDC=%d, STRIP=%d, CH=%d, TOT=%d", idig, cc.timeFrameInc[idig], cc.timeTDCInc[idig], cc.stripID[idig], cc.chanInStrip[idig], cc.tot[idig]); } } - // store explicit patters as they are memcpy(cc.pattMap.data(), pattVec.data(), cc.header.nPatternBytes); // RSTODO: do we need this? } @@ -218,7 +218,7 @@ size_t CTFCoder::estimateCompressedSize(const CompressedInfos& cc) sz += ESTSIZE(cc.tot, CTF::BLCtot); sz += ESTSIZE(cc.pattMap, CTF::BLCpattMap); // clang-format on - - LOG(INFO) << "Estimated output size is " << sz << " bytes"; + sz *= 2. / 3; // if needed, will be autoexpanded + LOG(DEBUG) << "Estimated output size is " << sz << " bytes"; return sz; } diff --git a/Detectors/TOF/reconstruction/src/Clusterer.cxx b/Detectors/TOF/reconstruction/src/Clusterer.cxx index ccaa484954303..19e0884cce425 100644 --- a/Detectors/TOF/reconstruction/src/Clusterer.cxx +++ b/Detectors/TOF/reconstruction/src/Clusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,7 +55,7 @@ void Clusterer::calibrateStrip() double calib = mCalibApi->getTimeCalibration(dig->getChannel(), dig->getTOT() * Geo::TOTBIN_NS); //printf("channel %d) isProblematic = %d, fractionUnderPeak = %f\n",dig->getChannel(),mCalibApi->isProblematic(dig->getChannel()),mCalibApi->getFractionUnderPeak(dig->getChannel())); // toberem dig->setIsProblematic(mCalibApi->isProblematic(dig->getChannel())); - dig->setCalibratedTime(dig->getTDC() * Geo::TDCBIN + dig->getBC() * o2::constants::lhc::LHCBunchSpacingNS * 1E3 - calib); //TODO: to be checked that "-" is correct, and we did not need "+" instead :-) + dig->setCalibratedTime(dig->getTDC() * Geo::TDCBIN + dig->getBC() * o2::constants::lhc::LHCBunchSpacingNS * 1E3 - Geo::LATENCYWINDOW * 1E3 - calib); //TODO: to be checked that "-" is correct, and we did not need "+" instead :-) //printf("calibration correction = %f\n",calib); // toberem } } @@ -100,7 +101,7 @@ void Clusterer::processStrip(std::vector<Cluster>& clusters, MCLabelContainer co // check if the TOF time are close enough to be merged; if not, it means that nothing else will contribute to the cluster (since digits are ordered in time) double timeDigNext = digNext->getCalibratedTime(); // in ps LOG(DEBUG) << "Time difference = " << timeDigNext - timeDig; - if (timeDigNext - timeDig > 500 /*in ps*/) { + if (timeDigNext - timeDig > mDeltaTforClustering /*in ps*/) { // to be change to 500 ps break; } digNext->getPhiAndEtaIndex(iphi2, ieta2); @@ -108,7 +109,7 @@ void Clusterer::processStrip(std::vector<Cluster>& clusters, MCLabelContainer co // check if the fired pad are close in space LOG(DEBUG) << "phi difference = " << iphi - iphi2; LOG(DEBUG) << "eta difference = " << ieta - ieta2; - if ((TMath::Abs(iphi - iphi2) > 1) || (TMath::Abs(ieta - ieta2) > 1)) { + if ((std::abs(iphi - iphi2) > 1) || (std::abs(ieta - ieta2) > 1)) { continue; } @@ -179,6 +180,12 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) //setL0L1Latency(); // to be filled (maybe) //setDeltaBC(); // to be filled (maybe) + c.setDigitInfo(0, mContributingDigit[0]->getChannel(), mContributingDigit[0]->getCalibratedTime(), mContributingDigit[0]->getTOT() * Geo::TOTBIN_NS); + + int ch1 = mContributingDigit[0]->getChannel(); + short tot1 = mContributingDigit[0]->getTOT() < 20000 ? mContributingDigit[0]->getTOT() : 20000; + double dtime = c.getTimeRaw(); + int chan1, chan2; int phi1, phi2; int eta1, eta2; @@ -191,6 +198,9 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) mContributingDigit[idig]->getPhiAndEtaIndex(phi2, eta2); deltaPhi = phi1 - phi2; deltaEta = eta1 - eta2; + + bool isOk = true; + if (deltaPhi == 1) { // the digit is to the LEFT of the cluster; let's check about UP/DOWN/Same Line if (deltaEta == 1) { // the digit is DOWN LEFT wrt the cluster mask = Cluster::kDownLeft; @@ -212,13 +222,25 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) mask = Cluster::kDown; } else if (deltaEta == -1) { // the digit is UP wrt the cluster mask = Cluster::kUp; - } else { // impossible!! + } else { // same channel! LOG(DEBUG) << " Check what is going on, the digit you are trying to merge to the cluster must be in a different channels... "; } - } else { // impossible!!! We checked above... - LOG(DEBUG) << " Check what is going on, the digit you are trying to merge to the cluster is too far from the cluster, you should have not got here... "; + } else { // |delataphi| > 1 + isOk = false; + mContributingDigit[idig]->setIsUsedInCluster(false); + } + + if (isOk) { + c.setDigitInfo(c.getNumOfContributingChannels(), mContributingDigit[idig]->getChannel(), mContributingDigit[idig]->getCalibratedTime(), mContributingDigit[idig]->getTOT() * Geo::TOTBIN_NS); + c.addBitInContributingChannels(mask); + + if (mCalibFromCluster && c.getNumOfContributingChannels() == 2) { // fill info for calibration + int8_t dch = int8_t(mContributingDigit[idig]->getChannel() - ch1); + short tot2 = mContributingDigit[idig]->getTOT() < 20000 ? mContributingDigit[idig]->getTOT() : 20000; + dtime -= mContributingDigit[idig]->getTDC() * Geo::TDCBIN + mContributingDigit[idig]->getBC() * o2::constants::lhc::LHCBunchSpacingNS * 1E3; + addCalibFromCluster(ch1, dch, float(dtime), tot1, tot2); + } } - c.addBitInContributingChannels(mask); } // filling the MC labels of this cluster; the first will be those of the main digit; then the others @@ -226,6 +248,9 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) int lbl = mClsLabels->getIndexedSize(); // this should correspond to the number of digits also; //printf("lbl = %d\n", lbl); for (int i = 0; i < mNumberOfContributingDigits; i++) { + if (!mContributingDigit[i]->isUsedInCluster()) { + continue; + } //printf("contributing digit = %d\n", i); int digitLabel = mContributingDigit[i]->getLabel(); //printf("digitLabel = %d\n", digitLabel); @@ -247,8 +272,8 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) Geo::rotateToSector(pos, c.getSector()); c.setXYZ(pos[2], pos[0], pos[1]); // storing coordinates in sector frame: note that the rotation above puts z in pos[1], the radial coordinate in pos[2], and the tangent coordinate in pos[0] (this is to match the TOF residual system, where we don't use the radial component), so we swap their positions. - c.setR(TMath::Sqrt(pos[0] * pos[0] + pos[1] * pos[1])); // it is the R in the sector frame - c.setPhi(TMath::ATan2(pos[1], pos[0])); + c.setR(std::sqrt(pos[0] * pos[0] + pos[1] * pos[1])); // it is the R in the sector frame + c.setPhi(std::atan2(pos[1], pos[0])); float errY2 = Geo::XPAD * Geo::XPAD * inv12; float errZ2 = Geo::ZPAD * Geo::ZPAD * inv12; @@ -264,8 +289,13 @@ void Clusterer::buildCluster(Cluster& c, MCLabelContainer const* digitMCTruth) } //_____________________________________________________________________ -void Clusterer::setFirstOrbit(uint32_t orb) +void Clusterer::setFirstOrbit(uint64_t orb) { mFirstOrbit = orb; mBCOffset = orb * o2::constants::lhc::LHCMaxBunches; } +//_____________________________________________________________________ +void Clusterer::addCalibFromCluster(int ch1, int8_t dch, float dtime, short tot1, short tot2) +{ + mCalibInfosFromCluster.emplace_back(ch1, dch, dtime, tot1, tot2); +} diff --git a/Detectors/TOF/reconstruction/src/ClustererTask.cxx b/Detectors/TOF/reconstruction/src/ClustererTask.cxx index 2410a47b349d1..c78e3e3dd0b4c 100644 --- a/Detectors/TOF/reconstruction/src/ClustererTask.cxx +++ b/Detectors/TOF/reconstruction/src/ClustererTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/reconstruction/src/CosmicProcessor.cxx b/Detectors/TOF/reconstruction/src/CosmicProcessor.cxx new file mode 100644 index 0000000000000..108727b6f02f2 --- /dev/null +++ b/Detectors/TOF/reconstruction/src/CosmicProcessor.cxx @@ -0,0 +1,160 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Clusterer.cxx +/// \brief Implementation of the TOF cluster finder +#include <algorithm> +#include "FairLogger.h" // for LOG +#include "TOFReconstruction/CosmicProcessor.h" +#include <TStopwatch.h> +#include "DetectorsRaw/HBFUtils.h" + +using namespace o2::tof; + +//__________________________________________________ +void CosmicProcessor::clear() +{ + mCosmicInfo.clear(); + mCosmicInfo.reserve(5200); + mCosmicTrack.clear(); + mCosmicTrack.reserve(1200); + mSizeTrack.clear(); + mSizeTrack.reserve(1200); + + mCosmicTrackTemp.reserve(200); + + memset(mCounters, 0, sizeof(int) * Geo::NCHANNELS); +} +//__________________________________________________ +void CosmicProcessor::processTrack() +{ + if (mCosmicTrack.size() > 1000) { + return; + } + + // fit the track and check if is good + mSizeTrack.push_back(int(mCosmicTrackTemp.size())); + mCosmicTrack.insert(mCosmicTrack.end(), mCosmicTrackTemp.begin(), mCosmicTrackTemp.end()); +} +//__________________________________________________ +void CosmicProcessor::process(DigitDataReader& reader, bool fill) +{ + if (mCosmicInfo.size() > 5000) { + return; + } + + TStopwatch timerProcess; + timerProcess.Start(); + + reader.init(); + const o2::raw::HBFUtils& hbfutils = o2::raw::HBFUtils::Instance(); + + auto array = reader.getDigitArray(); + int ndig = array->size(); + int ndig2 = ndig * fill; + + int npair = 0; + + int bcdist = 200; + float thr = 5000000; // in ps + + int volID1[5], volID2[5]; + float pos1[3], pos2[3], pos2or[3]; + + std::vector<int> mIcandClus; + mIcandClus.reserve(200); + + bool trackFound = false; + + for (int i = 0; i < ndig; i++) { + if (npair >= 150) { + break; + } + auto& dig1 = (*array)[i]; + int ch1 = dig1.getChannel(); + mCounters[ch1]++; + if (mCounters[ch1] > 3) { + continue; + } + auto ir0 = hbfutils.getFirstIRofTF(dig1.getIR()); + + int64_t bc1 = int64_t(dig1.getBC()); + int tdc1 = int(dig1.getTDC()); + float tot1 = dig1.getTOT() * 48.8E-3; + Geo::getVolumeIndices(ch1, volID1); + Geo::getPos(volID1, pos1); + + float tm1 = (dig1.getIR().differenceInBC(ir0) * 1024 + tdc1) * Geo::TDCBIN; // in ps + + mIcandClus.clear(); + if (!trackFound) { + mCosmicTrackTemp.clear(); + mCosmicTrackTemp.emplace_back(ch1, pos1[0], pos1[1], pos1[2], 0.0, tot1); + } + + for (int j = i + 1; j < ndig2; j++) { + auto& dig2 = (*array)[j]; + int64_t bc2 = int64_t(dig2.getBC()) - bc1; + if (labs(bc2) > bcdist) { + continue; + } + + int ch2 = dig2.getChannel(); + if (mCounters[ch2] > 3) { + continue; + } + float tm2 = (dig2.getIR().differenceInBC(ir0) * 1024 + int(dig2.getTDC())) * Geo::TDCBIN; // in ps + + int tdc2 = int(dig2.getTDC()) - tdc1; + float tot2 = dig2.getTOT() * 48.8E-3; + Geo::getVolumeIndices(ch2, volID2); + Geo::getPos(volID2, pos2or); + pos2[0] = pos2or[0] - pos1[0]; + pos2[1] = pos2or[1] - pos1[1]; + pos2[2] = pos2or[2] - pos1[2]; + + float dtime = (bc2 * 1024 + tdc2) * Geo::TDCBIN; // in ps + + float lt2 = pos2[0] * pos2[0] + pos2[1] * pos2[1]; + float l = sqrt(lt2 + pos2[2] * pos2[2]); + + if (!trackFound && lt2 < 40000 && fabs(dtime) < 10000) { + mCosmicTrackTemp.emplace_back(ch2, pos2or[0], pos2or[1], pos2or[2], dtime, tot2); + } + + if (l < 500) { + continue; + } + if (pos2[1] > 0) { + l = -l; + } + + dtime -= l * 33.356409; // corrected for pad distance assuiming muonn downward + + if (fabs(dtime) > thr) { + continue; + } + + npair++; + mCosmicInfo.emplace_back(ch1, ch2, dtime, tot1, tot2, l, tm1, tm2); + } + if (!trackFound && ndig < 1000 && mCosmicTrackTemp.size() > 4) { + trackFound = true; + } + } + + if (trackFound) { + processTrack(); + } + + LOG(DEBUG) << "We had " << ndig << " digits in this event"; + timerProcess.Stop(); +} diff --git a/Detectors/TOF/reconstruction/src/DataReader.cxx b/Detectors/TOF/reconstruction/src/DataReader.cxx index 8057f86fbeebd..cdb9b339ae5c9 100644 --- a/Detectors/TOF/reconstruction/src/DataReader.cxx +++ b/Detectors/TOF/reconstruction/src/DataReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,7 +51,7 @@ Bool_t DigitDataReader::getNextStripData(StripData& stripData) // sorting the digits of the current strip according to the TDC std::sort(stripData.digits.begin(), stripData.digits.end(), - [](const Digit& a, const Digit& b) { return a.getTDC() < b.getTDC(); }); + [](const Digit& a, const Digit& b) { if(a.getBC() != b.getBC()){ return a.getBC() < b.getBC();} return a.getTDC() < b.getTDC(); }); return kTRUE; } diff --git a/Detectors/TOF/reconstruction/src/Decoder.cxx b/Detectors/TOF/reconstruction/src/Decoder.cxx index 46cb81b1ab31f..2954347e25391 100644 --- a/Detectors/TOF/reconstruction/src/Decoder.cxx +++ b/Detectors/TOF/reconstruction/src/Decoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -113,25 +114,32 @@ bool Decoder::close() void Decoder::clear() { reset(); - if (mMaskNoiseRate > 0) { - clearCounts(); - } + clearCounts(); mPatterns.clear(); mCratePatterns.clear(); mCrateHeaderData.clear(); mErrors.clear(); + mDiagnosticFrequency.clear(); } void Decoder::InsertDigit(int icrate, int itrm, int itdc, int ichain, int channel, uint32_t orbit, uint16_t bunchid, int time_ext, int tdc, int tot) { DigitInfo digitInfo; + if (icrate % 2 == 1 && itrm == 3 && itdc / 3 > 0) { // Signal not coming from a TOF pad but -probably- from a TOF OR signal + // add operation on LTM (Trigger) if needed (not used) + return; + } + fromRawHit2Digit(icrate, itrm, itdc, ichain, channel, orbit, bunchid, time_ext + tdc, tot, digitInfo); - if (mMaskNoiseRate > 0) { - mChannelCounts[digitInfo.channel]++; + + if (digitInfo.channel < 0) { // check needed for the moment. To be removed once debugged + return; } + mChannelCounts[digitInfo.channel]++; + mHitDecoded++; uint64_t isnext = digitInfo.bcAbs * Geo::BC_IN_WINDOW_INV; @@ -175,12 +183,25 @@ void Decoder::readTRM(int icru, int icrate, uint32_t orbit, uint16_t bunchid) DigitInfo digitInfo; for (int i = 0; i < nhits; i++) { + if (icrate % 2 == 1 && itrm == 3 && mUnion[icru]->packedHit.tdcID / 3 > 0) { // Signal not coming from a TOF pad but -probably- from a TOF OR signal + // add operation on LTM (Trigger) if needed (not used) + + mUnion[icru]++; + mIntegratedBytes[icru] += 4; + continue; + } + fromRawHit2Digit(icrate, itrm, mUnion[icru]->packedHit.tdcID, mUnion[icru]->packedHit.chain, mUnion[icru]->packedHit.channel, orbit, bunchid, time_ext + mUnion[icru]->packedHit.time, mUnion[icru]->packedHit.tot, digitInfo); - if (mMaskNoiseRate > 0) { - mChannelCounts[digitInfo.channel]++; + + if (digitInfo.channel < 0) { // check needed for the moment. To be removed once debugged + mUnion[icru]++; + mIntegratedBytes[icru] += 4; + continue; } + mChannelCounts[digitInfo.channel]++; + mHitDecoded++; if (mVerbose) { @@ -215,6 +236,11 @@ void Decoder::fromRawHit2Digit(int icrate, int itrm, int itdc, int ichain, int c // tdc = packetHit.time + (frameHeader.frameID << 13) int echannel = Geo::getECHFromIndexes(icrate, itrm, ichain, itdc, channel); dinfo.channel = Geo::getCHFromECH(echannel); + + if (dinfo.channel < 0) { // it should not happen! + LOG(ERROR) << "No valid channel for icrate = " << icrate << ", itrm = " << itrm << ", ichain = " << ichain << ", itdc = " << itdc << ", channel = " << channel; + } + dinfo.tot = tot; dinfo.bcAbs = uint64_t(orbit) * o2::tof::Geo::BC_IN_ORBIT + bunchid + tdc / 1024; dinfo.tdc = tdc % 1024; @@ -323,12 +349,13 @@ bool Decoder::decode() // return a vector of digits in a TOF readout window // since digits are not yet divided in tof readout window we need to do it // flushOutputContainer does the job - FillWindows(); + fillWindows(); + fillDiagnosticFrequency(); return false; } -void Decoder::FillWindows() +void Decoder::fillWindows() { std::vector<Digit> digTemp; flushOutputContainer(digTemp); diff --git a/Detectors/TOF/reconstruction/src/DecoderBase.cxx b/Detectors/TOF/reconstruction/src/DecoderBase.cxx index 8c7fcb4a299fe..00dcbf131139f 100644 --- a/Detectors/TOF/reconstruction/src/DecoderBase.cxx +++ b/Detectors/TOF/reconstruction/src/DecoderBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,6 +59,14 @@ bool DecoderBaseT<RDH>::processHBF() } #endif + if (mDecoderBufferSize <= 0) { + std::cout << colorRed + << " got an empty buffer, do nothing" + << colorReset + << std::endl; + return true; + } + mDecoderRDH = reinterpret_cast<const RDH*>(mDecoderPointer); auto rdh = mDecoderRDH; diff --git a/Detectors/TOF/reconstruction/src/Encoder.cxx b/Detectors/TOF/reconstruction/src/Encoder.cxx index 41f0146bc97b5..d78b3c6d22099 100644 --- a/Detectors/TOF/reconstruction/src/Encoder.cxx +++ b/Detectors/TOF/reconstruction/src/Encoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -63,25 +64,24 @@ bool Encoder::open(const std::string& name, const std::string& path, const std:: // register links o2::header::RAWDataHeader rdh; mFileWriter.useRDHVersion(RDHUtils::getVersion<o2::header::RAWDataHeader>()); - for (int feeid = 0; feeid < 72; feeid++) { - // cru=0 --> FLP 0, endpoint 0 --> 18 links -> fees 0-17 - // cru=1 --> FLP 0, endpoint 1 --> 18 links -> fees 18-35 - // cru=2 --> FLP 1, endpoint 0 --> 18 links -> fees 36-53 - // cru=3 --> FLP 1, endpoint 1 --> 18 links -> fees 54-71 - RDHUtils::setFEEID(rdh, feeid); - RDHUtils::setCRUID(rdh, feeid / NLINKSPERCRU); - RDHUtils::setLinkID(rdh, feeid % NLINKSPERCRU); - RDHUtils::setEndPointID(rdh, RDHUtils::getCRUID(rdh) % 2); + for (int crateid = 0; crateid < 72; crateid++) { + // cru=0 --> FLP 1, ... defined in Geo + // cru=1 --> FLP 1, ... defined in Geo + // cru=2 --> FLP 0, ... defined in Geo + // cru=3 --> FLP 0, ... defined in Geo + RDHUtils::setFEEID(rdh, Geo::getFEEid(crateid)); + RDHUtils::setCRUID(rdh, Geo::getCRUid(crateid)); + RDHUtils::setLinkID(rdh, Geo::getCRUlink(crateid)); + RDHUtils::setEndPointID(rdh, Geo::getCRUendpoint(crateid)); // currently storing each CRU in a separate file std::string outFileLink; - if (mCrateOn[feeid]) { + if (mCrateOn[crateid]) { if (fileFor == "all") { // single file for all links - outFileLink = o2::utils::concat_string(path, "/TOF.raw"); + outFileLink = o2::utils::Str::concat_string(path, "/TOF.raw"); } else if (fileFor == "cru") { - outFileLink = o2::utils::concat_string(path, "/", "TOF_cru", std::to_string(RDHUtils::getCRUID(rdh)), ".raw"); + outFileLink = o2::utils::Str::concat_string(path, "/", "TOF_alio2-cr1-flp", std::to_string(Geo::getFLPid(crateid)), "_cru", std::to_string(Geo::getCRUid(crateid)), "_", std::to_string(Geo::getCRUendpoint(crateid)), ".raw"); } else if (fileFor == "link") { - outFileLink = o2::utils::concat_string(path, "/", "TOF_cru", std::to_string(RDHUtils::getCRUID(rdh)), "_link", - std::to_string(RDHUtils::getLinkID(rdh)), "_ep", std::to_string(RDHUtils::getEndPointID(rdh)), ".raw"); + outFileLink = o2::utils::Str::concat_string(path, "/", "TOF_alio2-cr1-flp", std::to_string(Geo::getFLPid(crateid)), "_cru", std::to_string(Geo::getCRUid(crateid)), "_", std::to_string(Geo::getCRUendpoint(crateid)), "_link", std::to_string(RDHUtils::getLinkID(rdh)), ".raw"); } else { throw std::runtime_error("invalid option provided for file grouping"); } @@ -99,11 +99,10 @@ bool Encoder::open(const std::string& name, const std::string& path, const std:: bool Encoder::flush(int icrate) { int nbyte = getSize(mStart[icrate], mUnion[icrate]); - int cru = icrate / NLINKSPERCRU; if (nbyte) { if (mCrateOn[icrate]) { //printf("flush crate %d -- byte = %d -- orbit = %d, bc = %d\n",icrate, nbyte, mIR.orbit, mIR.bc); - mFileWriter.addData(icrate, cru, icrate % NLINKSPERCRU, cru % 2, mIR, gsl::span(mBuffer[icrate], nbyte)); + mFileWriter.addData(Geo::getFEEid(icrate), Geo::getCRUid(icrate), Geo::getCRUlink(icrate), Geo::getCRUendpoint(icrate), mIR, gsl::span(mBuffer[icrate], nbyte)); } mIntegratedAllBytes += nbyte; } diff --git a/Detectors/TOF/reconstruction/src/EventTimeMaker.cxx b/Detectors/TOF/reconstruction/src/EventTimeMaker.cxx new file mode 100644 index 0000000000000..32123466296c1 --- /dev/null +++ b/Detectors/TOF/reconstruction/src/EventTimeMaker.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EventTimeMaker.cxx +/// \brief Implementation of the TOF event time maker + +#include "TOFReconstruction/EventTimeMaker.h" + +namespace o2 +{ + +namespace tof +{ + +} // namespace tof +} // namespace o2 \ No newline at end of file diff --git a/Detectors/TOF/reconstruction/src/TOFReconstructionLinkDef.h b/Detectors/TOF/reconstruction/src/TOFReconstructionLinkDef.h index a8cd7a6c2c067..d0a7b4b527c1c 100644 --- a/Detectors/TOF/reconstruction/src/TOFReconstructionLinkDef.h +++ b/Detectors/TOF/reconstruction/src/TOFReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,5 +22,6 @@ #pragma link C++ class o2::tof::raw::Encoder + ; #pragma link C++ class o2::tof::compressed::Decoder + ; #pragma link C++ class o2::tof::CTFCoder + ; +#pragma link C++ class o2::tof::CosmicProcessor + ; #endif diff --git a/Detectors/TOF/simulation/CMakeLists.txt b/Detectors/TOF/simulation/CMakeLists.txt index 0b02ad8df9897..6d18790cee362 100644 --- a/Detectors/TOF/simulation/CMakeLists.txt +++ b/Detectors/TOF/simulation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFSimulation SOURCES src/Detector.cxx src/Digitizer.cxx src/DigitizerTask.cxx src/TOFSimParams.cxx diff --git a/Detectors/TOF/simulation/include/TOFSimulation/Detector.h b/Detectors/TOF/simulation/include/TOFSimulation/Detector.h index 04e9c9dd09e12..86f86acc61846 100644 --- a/Detectors/TOF/simulation/include/TOFSimulation/Detector.h +++ b/Detectors/TOF/simulation/include/TOFSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/include/TOFSimulation/Digitizer.h b/Detectors/TOF/simulation/include/TOFSimulation/Digitizer.h index 453475bd775ee..59ab55b7bbf47 100644 --- a/Detectors/TOF/simulation/include/TOFSimulation/Digitizer.h +++ b/Detectors/TOF/simulation/include/TOFSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/include/TOFSimulation/DigitizerTask.h b/Detectors/TOF/simulation/include/TOFSimulation/DigitizerTask.h index e229b964208bf..0e5b40e2905e6 100644 --- a/Detectors/TOF/simulation/include/TOFSimulation/DigitizerTask.h +++ b/Detectors/TOF/simulation/include/TOFSimulation/DigitizerTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/include/TOFSimulation/MCLabel.h b/Detectors/TOF/simulation/include/TOFSimulation/MCLabel.h index ca78700e74c49..99317b02c1a47 100644 --- a/Detectors/TOF/simulation/include/TOFSimulation/MCLabel.h +++ b/Detectors/TOF/simulation/include/TOFSimulation/MCLabel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/include/TOFSimulation/TOFSimParams.h b/Detectors/TOF/simulation/include/TOFSimulation/TOFSimParams.h index 9103b3a341f32..de67cabfce474 100644 --- a/Detectors/TOF/simulation/include/TOFSimulation/TOFSimParams.h +++ b/Detectors/TOF/simulation/include/TOFSimulation/TOFSimParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/src/Detector.cxx b/Detectors/TOF/simulation/src/Detector.cxx index 5001fda818ef6..5300b73461b22 100644 --- a/Detectors/TOF/simulation/src/Detector.cxx +++ b/Detectors/TOF/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/src/Digitizer.cxx b/Detectors/TOF/simulation/src/Digitizer.cxx index d855866604c2f..30f39b31b287c 100644 --- a/Detectors/TOF/simulation/src/Digitizer.cxx +++ b/Detectors/TOF/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -105,7 +106,7 @@ int Digitizer::process(const std::vector<HitType>* hits, std::vector<Digit>* dig for (auto& hit : *hits) { //TODO: put readout window counting/selection - processHit(hit, mEventTime.getTimeOffsetWrtBC()); + processHit(hit, mEventTime.getTimeOffsetWrtBC() + Geo::LATENCYWINDOW); } // end loop over hits if (!mContinuous) { // fill output container per event diff --git a/Detectors/TOF/simulation/src/DigitizerTask.cxx b/Detectors/TOF/simulation/src/DigitizerTask.cxx index 80470b4e6a548..1c53d2257b97b 100644 --- a/Detectors/TOF/simulation/src/DigitizerTask.cxx +++ b/Detectors/TOF/simulation/src/DigitizerTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/src/TOFSimParams.cxx b/Detectors/TOF/simulation/src/TOFSimParams.cxx index b2fd20ceb4e97..ab6cfa671611d 100644 --- a/Detectors/TOF/simulation/src/TOFSimParams.cxx +++ b/Detectors/TOF/simulation/src/TOFSimParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/src/TOFSimulationLinkDef.h b/Detectors/TOF/simulation/src/TOFSimulationLinkDef.h index 9e656b7eb03ff..aa6dc59f59671 100644 --- a/Detectors/TOF/simulation/src/TOFSimulationLinkDef.h +++ b/Detectors/TOF/simulation/src/TOFSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/simulation/src/digi2raw.cxx b/Detectors/TOF/simulation/src/digi2raw.cxx index 3d687bbb814dd..1409fcdfa578b 100644 --- a/Detectors/TOF/simulation/src/digi2raw.cxx +++ b/Detectors/TOF/simulation/src/digi2raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,6 +34,8 @@ int main(int argc, char** argv) add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); add_option("file-for,f", bpo::value<std::string>()->default_value("cru"), "single file per: all,cru,link"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + //add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value("none"), "config file for HBFUtils (or none)"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -52,8 +55,9 @@ int main(int argc, char** argv) exit(2); } - auto cmd = o2::utils::concat_string("o2-tof-reco-workflow -b --output-type raw --tof-raw-outdir ", vm["output-dir"].as<std::string>(), - " --tof-raw-file-for ", vm["file-for"].as<std::string>(), - R"( --configKeyValues ")", vm["configKeyValues"].as<std::string>(), '"'); + auto cmd = o2::utils::Str::concat_string("o2-tof-reco-workflow -b --output-type raw --tof-raw-outdir ", vm["output-dir"].as<std::string>(), + " --file-for ", vm["file-for"].as<std::string>(), + " --hbfutils-config ", vm["hbfutils-config"].as<std::string>(), + R"( --configKeyValues ")", vm["configKeyValues"].as<std::string>(), '"'); return system(cmd.c_str()); } diff --git a/Detectors/TOF/workflow/CMakeLists.txt b/Detectors/TOF/workflow/CMakeLists.txt index 567c372173917..ee77b7cbb2e66 100644 --- a/Detectors/TOF/workflow/CMakeLists.txt +++ b/Detectors/TOF/workflow/CMakeLists.txt @@ -1,26 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TOFWorkflowUtils - SOURCES src/DigitReaderSpec.cxx - src/ClusterReaderSpec.cxx - src/TOFClusterizerSpec.cxx - src/TOFClusterWriterSpec.cxx - src/TOFDigitWriterSpec.cxx - src/TOFRawWriterSpec.cxx + SOURCES src/TOFClusterizerSpec.cxx src/CompressedDecodingTask.cxx src/CompressedInspectorTask.cxx src/CompressedAnalysisTask.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction O2::TOFWorkflowIO) o2_add_executable(entropy-encoder-workflow SOURCES src/entropy-encoder-workflow.cxx @@ -31,3 +27,23 @@ o2_add_executable(digit-writer-workflow SOURCES src/digit-writer-commissioning.cxx COMPONENT_NAME tof PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils) + +o2_add_executable(cluster-writer-workflow + SOURCES src/cluster-writer-commissioning.cxx + COMPONENT_NAME tof + PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils) + +o2_add_executable(cluster-calib-workflow + SOURCES src/cluster-calib.cxx + COMPONENT_NAME tof + PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils) + +o2_add_executable(cluscal-reader-workflow + SOURCES src/cluscal-reader.cxx + COMPONENT_NAME tof + PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils) + +o2_add_executable(file-proxy + SOURCES src/file-proxy.cxx + COMPONENT_NAME tof + PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils) diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/ClusterReaderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/ClusterReaderSpec.h deleted file mode 100644 index 7d9728c00a92b..0000000000000 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/ClusterReaderSpec.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterReaderSpec.h - -#ifndef O2_TOF_CLUSTERREADER -#define O2_TOF_CLUSTERREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "DataFormatsTOF/Cluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -class ClusterReader : public Task -{ - public: - ClusterReader(bool useMC) : mUseMC(useMC) {} - ~ClusterReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - void connectTree(const std::string& filename); - - bool mUseMC = true; - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - std::string mFileName = ""; - - std::vector<Cluster> mClusters, *mClustersPtr = &mClusters; - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; -}; - -/// create a processor spec -/// read simulated TOF digits from a root file -framework::DataProcessorSpec getClusterReaderSpec(bool useMC); - -} // namespace tof -} // namespace o2 - -#endif /* O2_TOF_CLUSTERREADER */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysis.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysis.h index 32d5a28f63ff9..7315e7977d35c 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysis.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysis.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysisTask.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysisTask.h index 367ba19b2aa43..1332ee2effb85 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysisTask.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedAnalysisTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedDecodingTask.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedDecodingTask.h index 35b67d5224b78..e64a1869e9350 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedDecodingTask.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedDecodingTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,15 +37,17 @@ using namespace compressed; class CompressedDecodingTask : public DecoderBase, public Task { public: - CompressedDecodingTask(bool conet = false) + CompressedDecodingTask(bool conet, o2::header::DataDescription dataDesc) { mConetMode = conet; + mDataDesc = dataDesc; setDecoderCONET(conet); } ~CompressedDecodingTask() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; + void decodeTF(ProcessingContext& pc); void endOfStream(EndOfStreamContext& ec) final; void postData(ProcessingContext& pc); @@ -60,19 +63,21 @@ class CompressedDecodingTask : public DecoderBase, public Task o2::tof::compressed::Decoder mDecoder; std::vector<std::vector<o2::tof::Digit>> mDigits; + o2::header::DataDescription mDataDesc; int mNTF = 0; int mNCrateOpenTF = 0; int mNCrateCloseTF = 0; bool mHasToBePosted = false; bool mConetMode = false; uint32_t mInitOrbit = 0; + uint32_t mCurrentOrbit = 0; bool mRowFilter = false; bool mMaskNoise = false; int mNoiseRate = 1000; TStopwatch mTimer; }; -framework::DataProcessorSpec getCompressedDecodingSpec(const std::string& inputDesc, bool conet = false); +framework::DataProcessorSpec getCompressedDecodingSpec(const std::string& inputDesc, bool conet = false, bool askDISTSTF = true); } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedInspectorTask.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedInspectorTask.h index 535bdd61f2d47..993487764033d 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedInspectorTask.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedInspectorTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/DigitReaderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/DigitReaderSpec.h deleted file mode 100644 index e4e3acca37947..0000000000000 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/DigitReaderSpec.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.h - -#ifndef O2_TOF_DIGITREADER -#define O2_TOF_DIGITREADER - -#include "TFile.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "TOFBase/Digit.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -class DigitReader : public Task -{ - public: - DigitReader(bool useMC) : mUseMC(useMC) {} - ~DigitReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - int mState = 0; - int mCurrentEntry = 0; - bool mUseMC = true; - std::unique_ptr<TFile> mFile = nullptr; - std::vector<o2::tof::Digit> mDigits, *mPdigits = &mDigits; - std::vector<o2::tof::ReadoutWindowData> mRow, *mProw = &mRow; - std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabels, *mPlabels = &mLabels; - std::vector<uint32_t> mPatterns, *mPpatterns = &mPatterns; -}; - -/// create a processor spec -/// read simulated TOF digits from a root file -framework::DataProcessorSpec getDigitReaderSpec(bool useMC); - -} // namespace tof -} // namespace o2 - -#endif /* O2_TOF_DIGITREADER */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h index e699549ab2147..b365dc0589936 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h index 2a535abde1eb5..4c915052a2489 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterWriterSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterWriterSpec.h deleted file mode 100644 index 12d8525da6d9a..0000000000000 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterWriterSpec.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TOFClusterWriterSpec.h - -#ifndef STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ -#define STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -/// create a processor spec -/// write ITS tracks a root file -o2::framework::DataProcessorSpec getTOFClusterWriterSpec(bool useMC); - -} // namespace tof -} // namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterizerSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterizerSpec.h index eaa4262c23813..edbb927bd2808 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterizerSpec.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ namespace o2 namespace tof { -o2::framework::DataProcessorSpec getTOFClusterizerSpec(bool useMC, bool useCCDB = 0); +o2::framework::DataProcessorSpec getTOFClusterizerSpec(bool useMC, bool useCCDB = 0, bool doCalib = 0, bool isCosmic = 0); } // end namespace tof } // end namespace o2 diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSpec.h deleted file mode 100644 index d45d2e4c95509..0000000000000 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSpec.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ -#define STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace tof -{ - -o2::framework::DataProcessorSpec getTOFDigitWriterSpec(bool useMC = 1, bool writeErr = 0); - -} // end namespace tof -} // end namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSplitterSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSplitterSpec.h deleted file mode 100644 index 432504430afb0..0000000000000 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSplitterSpec.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TOFDIGIT_SPLITTER_WRITER_H -#define O2_TOFDIGIT_SPLITTER_WRITER_H - -/// @file TOFDigitWriterSplitterSpec.h -/// @brief Device to write to tree the information for TOF time slewing calibration. - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "TOFBase/Digit.h" -#include "Framework/Logger.h" -#include <TTree.h> -#include <gsl/span> - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ -class TOFDigitWriterSplitter : public Task -{ - using OutputType = std::vector<o2::tof::Digit>; - using ReadoutWinType = std::vector<o2::tof::ReadoutWindowData>; - using PatternType = std::vector<uint32_t>; - using ErrorType = std::vector<uint64_t>; - using HeaderType = o2::tof::DigitHeader; - - public: - TOFDigitWriterSplitter(int nTF, bool storeErr = false) : mTFthr(nTF), mStoreErrors(storeErr) {} - - void createAndOpenFileAndTree() - { - TString filename = TString::Format("tofdigits_%d.root", mCount); - LOG(DEBUG) << "opening file " << filename.Data(); - mfileOut.reset(TFile::Open(TString::Format("%s", filename.Data()), "RECREATE")); - mOutputTree = std::make_unique<TTree>("o2sim", "Tree with TOF digits"); - mOutputTree->Branch("TOFHeader", &mPHeader); - mOutputTree->Branch("TOFDigit", &mPDigits); - mOutputTree->Branch("TOFReadoutWindow", &mPROW); - mOutputTree->Branch("TOFPatterns", &mPDia); - if (mStoreErrors) { - mOutputTree->Branch("TOFErrors", &mPErr); - } - - mNTF = 0; - } - - void init(o2::framework::InitContext& ic) final - { - mCount = 0; - createAndOpenFileAndTree(); - } - - void run(o2::framework::ProcessingContext& pc) final - { - auto digits = pc.inputs().get<OutputType>("digits"); - mPDigits = &digits; - auto header = pc.inputs().get<HeaderType>("header"); - mPHeader = &header; - auto row = pc.inputs().get<ReadoutWinType>("rows"); - mPROW = &row; - auto dia = pc.inputs().get<PatternType>("patterns"); - mPDia = &dia; - if (mStoreErrors) { - auto error = pc.inputs().get<ErrorType>("errors"); - mPErr = &error; - - mOutputTree->Fill(); - } else { - mOutputTree->Fill(); - } - mNTF++; - - if (mNTF >= mTFthr) { - sendOutput(); - } - } - - void endOfStream(o2::framework::EndOfStreamContext& ec) final - { - mIsEndOfStream = true; - sendOutput(); - } - - private: - int mCount = 0; // how many times we filled the tree - int mNTF = 0; - int mTFthr = 1; - bool mStoreErrors = false; - bool mIsEndOfStream = false; - OutputType mDigits; - const OutputType* mPDigits = &mDigits; - ReadoutWinType mROW; - const ReadoutWinType* mPROW = &mROW; - PatternType mDia; - const PatternType* mPDia = &mDia; - ErrorType mErr; - const ErrorType* mPErr = &mErr; - HeaderType mHeader; - const HeaderType* mPHeader = &mHeader; - std::unique_ptr<TTree> mOutputTree; ///< tree for the collected calib tof info - std::unique_ptr<TFile> mfileOut = nullptr; // file in which to write the output - - //________________________________________________________________ - void sendOutput() - { - // This is to fill the tree. - // One file with an empty tree will be created at the end, because we have to have a - // tree opened before processing, since we do not know a priori if something else - // will still come. The size of this extra file is ~6.5 kB - - mfileOut->cd(); - mOutputTree->Write(); - mOutputTree.reset(); - mfileOut.reset(); - mCount++; - if (!mIsEndOfStream) { - createAndOpenFileAndTree(); - } - } -}; -} // namespace tof - -namespace framework -{ - -DataProcessorSpec getTOFCalibCollectorWriterSpec(int nTF, bool storeErr = false) -{ - std::vector<InputSpec> inputs; - inputs.emplace_back("header", o2::header::gDataOriginTOF, "DIGITHEADER"); - inputs.emplace_back("digits", o2::header::gDataOriginTOF, "DIGITS"); - inputs.emplace_back("rows", o2::header::gDataOriginTOF, "READOUTWINDOW"); - inputs.emplace_back("patterns", o2::header::gDataOriginTOF, "PATTERNS"); - - if (storeErr) { - inputs.emplace_back("errors", o2::header::gDataOriginTOF, "ERRORS"); - } - - std::vector<OutputSpec> outputs; // empty - - return DataProcessorSpec{ - "tof-digit-splitter-writer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask<o2::tof::TOFDigitWriterSplitter>(nTF, storeErr)}, - Options{}}; -} - -} // namespace framework -} // namespace o2 - -#endif diff --git a/Detectors/TOF/workflow/src/ClusterReaderSpec.cxx b/Detectors/TOF/workflow/src/ClusterReaderSpec.cxx deleted file mode 100644 index f9c422307bab3..0000000000000 --- a/Detectors/TOF/workflow/src/ClusterReaderSpec.cxx +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterReaderSpec.cxx - -#include <vector> - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "TOFWorkflowUtils/ClusterReaderSpec.h" -#include "DataFormatsParameters/GRPObject.h" - -using namespace o2::framework; -using namespace o2::tof; - -namespace o2 -{ -namespace tof -{ - -void ClusterReader::init(InitContext& ic) -{ - LOG(INFO) << "Init Cluster reader!"; - mFileName = ic.options().get<std::string>("tof-cluster-infile"); - connectTree(mFileName); -} - -void ClusterReader::run(ProcessingContext& pc) -{ - auto ent = mTree->GetReadEntry() + 1; - assert(ent < mTree->GetEntries()); // this should not happen - mTree->GetEntry(ent); - LOG(INFO) << "Pushing " << mClustersPtr->size() << " TOF clusters at entry " << ent; - - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe}, mClusters); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe}, mLabels); - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -void ClusterReader::connectTree(const std::string& filename) -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(filename.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get("o2sim")); - assert(mTree); - mTree->SetBranchAddress("TOFCluster", &mClustersPtr); - if (mUseMC) { - mTree->SetBranchAddress("TOFClusterMCTruth", &mLabelsPtr); - } - LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; -} - -DataProcessorSpec getClusterReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back(o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "tof-cluster-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<ClusterReader>(useMC)}, - Options{ - {"tof-cluster-infile", VariantType::String, "tofclusters.root", {"Name of the input file"}}}}; -} - -} // namespace tof -} // namespace o2 diff --git a/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx b/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx index efd9efc9198ef..1d98d16427dd5 100644 --- a/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx +++ b/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/src/CompressedDecodingTask.cxx b/Detectors/TOF/workflow/src/CompressedDecodingTask.cxx index e6bb8ee347c7b..575bbb6e4ced5 100644 --- a/Detectors/TOF/workflow/src/CompressedDecodingTask.cxx +++ b/Detectors/TOF/workflow/src/CompressedDecodingTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,6 +26,8 @@ #include "Framework/WorkflowSpec.h" #include "Framework/Logger.h" #include "DetectorsRaw/RDHUtils.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/DataRefUtils.h" using namespace o2::framework; @@ -45,6 +48,8 @@ void CompressedDecodingTask::init(InitContext& ic) if (mMaskNoise) { mDecoder.maskNoiseRate(mNoiseRate); + } else { + mDecoder.maskNoiseRate(-mNoiseRate); // negative means -> flag but not filter } auto finishFunction = [this]() { @@ -58,7 +63,8 @@ void CompressedDecodingTask::init(InitContext& ic) void CompressedDecodingTask::postData(ProcessingContext& pc) { mHasToBePosted = false; - mDecoder.FillWindows(); + mDecoder.fillWindows(); + mDecoder.fillDiagnosticFrequency(); // send output message std::vector<o2::tof::Digit>* alldigits = mDecoder.getDigitPerTimeFrame(); @@ -99,7 +105,8 @@ void CompressedDecodingTask::postData(ProcessingContext& pc) pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe}, *alldigits); pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe}, *row); - std::vector<uint32_t>& patterns = mDecoder.getPatterns(); + std::vector<uint8_t>& patterns = mDecoder.getPatterns(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe}, patterns); std::vector<uint64_t>& errors = mDecoder.getErrors(); @@ -108,17 +115,9 @@ void CompressedDecodingTask::postData(ProcessingContext& pc) DigitHeader& digitH = mDecoder.getDigitHeader(); pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITHEADER", 0, Lifetime::Timeframe}, digitH); - // RS this is a hack to be removed once we have correct propagation of the firstTForbit by the framework - auto setFirstTFOrbit = [&](const Output& spec, uint32_t orb) { - auto* hd = pc.outputs().findMessageHeader(spec); - if (!hd) { - throw std::runtime_error(o2::utils::concat_string("failed to find output message header for ", spec.origin.str, "/", spec.description.str, "/", std::to_string(spec.subSpec))); - } - hd->firstTForbit = orb; - }; - - setFirstTFOrbit(Output{o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe}, mInitOrbit); - setFirstTFOrbit(Output{o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe}, mInitOrbit); + auto diagnosticFrequency = mDecoder.getDiagnosticFrequency(); + //diagnosticFrequency.print(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIAFREQ", 0, Lifetime::Timeframe}, diagnosticFrequency); mDecoder.clear(); @@ -131,33 +130,18 @@ void CompressedDecodingTask::run(ProcessingContext& pc) { mTimer.Start(false); - if (pc.inputs().getNofParts(0) && !mConetMode) { - //RS set the 1st orbit of the TF from the O2 header, relying on rdhHandler is not good (in fact, the RDH might be eliminated in the derived data) - const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().getByPos(0).header); - mInitOrbit = dh->firstTForbit; + //RS set the 1st orbit of the TF from the O2 header, relying on rdhHandler is not good (in fact, the RDH might be eliminated in the derived data) + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + mInitOrbit = dh->firstTForbit; + if (!mConetMode) { + mDecoder.setFirstIR({0, mInitOrbit}); } - mDecoder.setFirstIR({0, mInitOrbit}); - - /** loop over inputs routes **/ - for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { - if (!iit.isValid()) { - continue; - } - - /** loop over input parts **/ - for (auto const& ref : iit) { - const auto* headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); - auto payloadIn = ref.payload; - auto payloadInSize = headerIn->payloadSize; - - DecoderBase::setDecoderBuffer(payloadIn); - DecoderBase::setDecoderBufferSize(payloadInSize); - DecoderBase::run(); - } - } + decodeTF(pc); - if ((mNCrateOpenTF == 72 || mConetMode) && mNCrateOpenTF == mNCrateCloseTF) { + if (!mConetMode) { + mHasToBePosted = true; + } else if (mNCrateOpenTF == mNCrateCloseTF) { mHasToBePosted = true; } @@ -173,13 +157,54 @@ void CompressedDecodingTask::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } +void CompressedDecodingTask::decodeTF(ProcessingContext& pc) +{ + auto& inputs = pc.inputs(); + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{"TOF", mDataDesc, 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return; + } + } + } + + /** loop over inputs routes **/ + std::vector<InputSpec> sel{InputSpec{"filter", ConcreteDataTypeMatcher{"TOF", "CRAWDATA"}}}; + for (const auto& ref : InputRecordWalker(pc.inputs(), sel)) { + // for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { + // if (!iit.isValid()) { + // continue; + // } + + /** loop over input parts **/ + // for (auto const& ref : iit) { + const auto* headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + auto payloadIn = ref.payload; + auto payloadInSize = headerIn->payloadSize; + + DecoderBase::setDecoderBuffer(payloadIn); + DecoderBase::setDecoderBufferSize(payloadInSize); + DecoderBase::run(); + // } + } +} + void CompressedDecodingTask::headerHandler(const CrateHeader_t* crateHeader, const CrateOrbit_t* crateOrbit) { if (mConetMode) { - LOG(DEBUG) << "Crate found" << crateHeader->drmID; - - mInitOrbit = crateOrbit->orbitID; + if (mNCrateOpenTF == 0) { + mInitOrbit = crateOrbit->orbitID; + mDecoder.setFirstIR({0, mInitOrbit}); + } + LOG(DEBUG) << "Crate found" << crateHeader->drmID; mNCrateOpenTF++; } } @@ -188,22 +213,29 @@ void CompressedDecodingTask::trailerHandler(const CrateHeader_t* crateHeader, co const Error_t* errors) { if (mConetMode) { - LOG(DEBUG) << "Crate closed" << crateHeader->drmID; + LOG(DEBUG) << "Crate closed " << crateHeader->drmID; mNCrateCloseTF++; } - mDecoder.addCrateHeaderData(crateOrbit->orbitID, crateHeader->drmID, crateHeader->bunchID, crateTrailer->eventCounter); + if (mCurrentOrbit > 0) { + mDecoder.addCrateHeaderData(mCurrentOrbit, crateHeader->drmID, crateHeader->bunchID, crateTrailer->eventCounter); + } else { + mDecoder.addCrateHeaderData(crateOrbit->orbitID, crateHeader->drmID, crateHeader->bunchID, crateTrailer->eventCounter); + } // Diagnostics used to fill digit patterns auto numberOfDiagnostics = crateTrailer->numberOfDiagnostics; auto numberOfErrors = crateTrailer->numberOfErrors; for (int i = 0; i < numberOfDiagnostics; i++) { const uint32_t* val = reinterpret_cast<const uint32_t*>(&(diagnostics[i])); - mDecoder.addPattern(*val, crateHeader->drmID, crateOrbit->orbitID, crateHeader->bunchID); + if (mCurrentOrbit > 0) { + mDecoder.addPattern(*val, crateHeader->drmID, mCurrentOrbit, crateHeader->bunchID); // take orbit from crateHeader instead of crateOrbit (it can be wrong, check also for digits!) + } else { + mDecoder.addPattern(*val, crateHeader->drmID, crateOrbit->orbitID, crateHeader->bunchID); + } /* int islot = (*val & 15); - printf("DRM = %d (orbit = %d) slot = %d: \n", crateHeader->drmID, crateOrbit->orbitID, islot); if (islot == 1) { if (o2::tof::diagnostic::DRM_HEADER_MISSING & *val) { printf("DRM_HEADER_MISSING\n"); @@ -323,6 +355,7 @@ void CompressedDecodingTask::trailerHandler(const CrateHeader_t* crateHeader, co printf("------\n"); */ } + for (int i = 0; i < numberOfErrors; i++) { const uint32_t* val = reinterpret_cast<const uint32_t*>(&(errors[i])); mDecoder.addError(*val, crateHeader->drmID); @@ -331,20 +364,19 @@ void CompressedDecodingTask::trailerHandler(const CrateHeader_t* crateHeader, co void CompressedDecodingTask::rdhHandler(const o2::header::RAWDataHeader* rdh) { + const auto& rdhr = *rdh; + // set first orbtìt here (to be check in future), please not remove this!!! + mCurrentOrbit = RDHUtils::getHeartBeatOrbit(rdhr); // rdh close - const auto& rdhr = *rdh; if (RDHUtils::getStop(rdhr) && RDHUtils::getHeartBeatOrbit(rdhr) == o2::raw::HBFUtils::Instance().getNOrbitsPerTF() - 1 + mInitOrbit) { mNCrateCloseTF++; - // printf("New TF close RDH %d\n", int(rdh->feeId)); return; } // rdh open if ((RDHUtils::getPageCounter(rdhr) == 0) && (RDHUtils::getTriggerType(rdhr) & o2::trigger::TF)) { mNCrateOpenTF++; - mInitOrbit = RDHUtils::getHeartBeatOrbit(rdhr); // RSTODO this may be eliminated once the framework will start to propagated the dh.firstTForbit - // printf("New TF open RDH %d\n", int(rdh->feeId)); } }; @@ -353,28 +385,44 @@ void CompressedDecodingTask::frameHandler(const CrateHeader_t* crateHeader, cons { for (int i = 0; i < frameHeader->numberOfHits; ++i) { auto packedHit = packedHits + i; - mDecoder.InsertDigit(crateHeader->drmID, frameHeader->trmID, packedHit->tdcID, packedHit->chain, packedHit->channel, crateOrbit->orbitID, crateHeader->bunchID, frameHeader->frameID << 13, packedHit->time, packedHit->tot); + if (mCurrentOrbit > 0) { + mDecoder.InsertDigit(crateHeader->drmID, frameHeader->trmID, packedHit->tdcID, packedHit->chain, packedHit->channel, mCurrentOrbit, crateHeader->bunchID, frameHeader->frameID << 13, packedHit->time, packedHit->tot); + } else { + mDecoder.InsertDigit(crateHeader->drmID, frameHeader->trmID, packedHit->tdcID, packedHit->chain, packedHit->channel, crateOrbit->orbitID, crateHeader->bunchID, frameHeader->frameID << 13, packedHit->time, packedHit->tot); + } } }; -DataProcessorSpec getCompressedDecodingSpec(const std::string& inputDesc, bool conet) +DataProcessorSpec getCompressedDecodingSpec(const std::string& inputDesc, bool conet, bool askDISTSTF) { + std::vector<InputSpec> inputs; + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + + // inputs.emplace_back(std::string("x:TOF/" + inputDesc).c_str(), 0, Lifetime::Optional); + o2::header::DataDescription dataDesc; + dataDesc.runtimeInit(inputDesc.c_str()); + inputs.emplace_back("x", ConcreteDataTypeMatcher{o2::header::gDataOriginTOF, dataDesc}, Lifetime::Optional); + std::vector<OutputSpec> outputs; outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITHEADER", 0, Lifetime::Timeframe); outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe); outputs.emplace_back(o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe); outputs.emplace_back(o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe); outputs.emplace_back(o2::header::gDataOriginTOF, "ERRORS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "DIAFREQ", 0, Lifetime::Timeframe); return DataProcessorSpec{ "tof-compressed-decoder", - select(std::string("x:TOF/" + inputDesc).c_str()), + inputs, + // select(std::string("x:TOF/" + inputDesc).c_str()), outputs, - AlgorithmSpec{adaptFromTask<CompressedDecodingTask>(conet)}, + AlgorithmSpec{adaptFromTask<CompressedDecodingTask>(conet, dataDesc)}, Options{ {"row-filter", VariantType::Bool, false, {"Filter empty row"}}, {"mask-noise", VariantType::Bool, false, {"Flag to mask noisy digits"}}, - {"noise-counts", VariantType::Int, 1000, {"Counts in a single (TF) payload"}}}}; + {"noise-counts", VariantType::Int, 11, {"Counts in a single (TF) payload"}}}}; } } // namespace tof diff --git a/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx b/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx index 5c8629363cf3c..3a2c53b4722aa 100644 --- a/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx +++ b/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,6 +37,9 @@ void CompressedInspectorTask<RDH>::init(InitContext& ic) { LOG(INFO) << "CompressedInspector init"; auto filename = ic.options().get<std::string>("tof-compressed-inspector-filename"); + auto verbose = ic.options().get<bool>("tof-compressed-inspector-decoder-verbose"); + + DecoderBaseT<RDH>::setDecoderVerbose(verbose); /** open file **/ if (mFile && mFile->IsOpen()) { @@ -62,6 +66,8 @@ void CompressedInspectorTask<RDH>::init(InitContext& ic) mHistos1D["errorBit"] = new TH1F("hErrorBit", ";TDC error bit", 15, 0., 15.); mHistos2D["error"] = new TH2F("hError", ";slot;TDC", 24, 1., 13., 15, 0., 15.); mHistos2D["test"] = new TH2F("hTest", ";slot;TDC", 24, 1., 13., 15, 0., 15.); + mHistos2D["crateBC"] = new TH2F("hCrateBC", ";crate;BC", 72, 0., 72., 4096, 0., 4096.); + mHistos2D["crateOrbit"] = new TH2F("hCrateOrbit", ";crate;orbit", 72, 0., 72., 4096, 0., 4096.); auto finishFunction = [this]() { LOG(INFO) << "CompressedInspector finish"; @@ -110,6 +116,9 @@ void CompressedInspectorTask<RDH>::run(ProcessingContext& pc) template <typename RDH> void CompressedInspectorTask<RDH>::headerHandler(const CrateHeader_t* crateHeader, const CrateOrbit_t* crateOrbit) { + mHistos2D["crateBC"]->Fill(crateHeader->drmID, crateHeader->bunchID); + mHistos2D["crateOrbit"]->Fill(crateHeader->drmID, crateOrbit->orbitID % 4096); + for (int ibit = 0; ibit < 11; ++ibit) { if (crateHeader->slotPartMask & (1 << ibit)) { mHistos2D["slotPartMask"]->Fill(crateHeader->drmID, ibit + 2); diff --git a/Detectors/TOF/workflow/src/DigitReaderSpec.cxx b/Detectors/TOF/workflow/src/DigitReaderSpec.cxx deleted file mode 100644 index 66081b514dff6..0000000000000 --- a/Detectors/TOF/workflow/src/DigitReaderSpec.cxx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.cxx - -#include <vector> - -#include "TTree.h" - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/Logger.h" -#include "TOFWorkflowUtils/DigitReaderSpec.h" -#include "DataFormatsParameters/GRPObject.h" - -using namespace o2::framework; -using namespace o2::tof; - -namespace o2 -{ -namespace tof -{ - -void DigitReader::init(InitContext& ic) -{ - LOG(INFO) << "Init Digit reader!"; - auto filename = ic.options().get<std::string>("tof-digit-infile"); - mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); - if (!mFile->IsOpen()) { - LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; - mState = 0; - return; - } - mState = 1; -} - -void DigitReader::run(ProcessingContext& pc) -{ - if (mState != 1) { - return; - } - - std::unique_ptr<TTree> treeDig((TTree*)mFile->Get("o2sim")); - - if (treeDig) { - treeDig->SetBranchAddress("TOFDigit", &mPdigits); - treeDig->SetBranchAddress("TOFReadoutWindow", &mProw); - treeDig->SetBranchAddress("TOFPatterns", &mPpatterns); - - if (mUseMC) { - treeDig->SetBranchAddress("TOFDigitMCTruth", &mPlabels); - } - - treeDig->GetEntry(mCurrentEntry); - - // add digits loaded in the output snapshot - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe}, mDigits); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe}, mRow); - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe}, mPatterns); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITSMCTR", 0, Lifetime::Timeframe}, mLabels); - } - - static o2::parameters::GRPObject::ROMode roMode = o2::parameters::GRPObject::CONTINUOUS; - - LOG(INFO) << "TOF: Sending ROMode= " << roMode << " to GRPUpdater"; - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "ROMode", 0, Lifetime::Timeframe}, roMode); - } else { - LOG(ERROR) << "Cannot read the TOF digits !"; - return; - } - - mCurrentEntry++; - - if (mCurrentEntry >= treeDig->GetEntries()) { - mState = 2; - //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - pc.services().get<ControlService>().endOfStream(); - } -} - -DataProcessorSpec getDigitReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITSMCTR", 0, Lifetime::Timeframe); - } - outputs.emplace_back(o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTOF, "ROMode", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "tof-digit-reader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, - Options{ - {"tof-digit-infile", VariantType::String, "tofdigits.root", {"Name of the input file"}}}}; -} - -} // namespace tof -} // namespace o2 diff --git a/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx index ca1fa309a8831..0d290299dbf23 100644 --- a/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ EntropyDecoderSpec::EntropyDecoderSpec() void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("tof-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -47,7 +48,7 @@ void EntropyDecoderSpec::run(ProcessingContext& pc) auto& digitheader = pc.outputs().make<DigitHeader>(OutputRef{"digitheader"}); auto& digits = pc.outputs().make<std::vector<Digit>>(OutputRef{"digits"}); auto& row = pc.outputs().make<std::vector<ReadoutWindowData>>(OutputRef{"row"}); - auto& patterns = pc.outputs().make<std::vector<uint32_t>>(OutputRef{"patterns"}); + auto& patterns = pc.outputs().make<std::vector<uint8_t>>(OutputRef{"patterns"}); // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object const auto ctfImage = o2::tof::CTF::getImage(buff.data()); @@ -76,7 +77,7 @@ DataProcessorSpec getEntropyDecoderSpec() Inputs{InputSpec{"ctf", o2::header::gDataOriginTOF, "CTFDATA", 0, Lifetime::Timeframe}}, outputs, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"tof-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace tof diff --git a/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx index 7af45cc28c8b2..6ba5b7da392ad 100644 --- a/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,7 +33,7 @@ EntropyEncoderSpec::EntropyEncoderSpec() void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("tof-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -43,7 +44,7 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) auto cput = mTimer.CpuTime(); mTimer.Start(false); auto compDigits = pc.inputs().get<gsl::span<Digit>>("compDigits"); - auto pspan = pc.inputs().get<gsl::span<uint32_t>>("patterns"); + auto pspan = pc.inputs().get<gsl::span<uint8_t>>("patterns"); auto rofs = pc.inputs().get<gsl::span<ReadoutWindowData>>("ROframes"); auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{o2::header::gDataOriginTOF, "CTFDATA", 0, Lifetime::Timeframe}); @@ -54,7 +55,6 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) // eeb->print(); mTimer.Stop(); LOG(INFO) << "Created encoded data of size " << eeb->size() << " for TOF in " << mTimer.CpuTime() - cput << " s"; - // pc.services().get<ControlService>().endOfStream(); } void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) @@ -75,7 +75,7 @@ DataProcessorSpec getEntropyEncoderSpec() inputs, Outputs{{o2::header::gDataOriginTOF, "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, - Options{{"tof-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; } } // namespace tof diff --git a/Detectors/TOF/workflow/src/TOFClusterizerSpec.cxx b/Detectors/TOF/workflow/src/TOFClusterizerSpec.cxx index 550e56690aacc..60e9f906eb8fe 100644 --- a/Detectors/TOF/workflow/src/TOFClusterizerSpec.cxx +++ b/Detectors/TOF/workflow/src/TOFClusterizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,14 +17,19 @@ #include "Framework/Task.h" #include "Headers/DataHeader.h" #include "TOFReconstruction/Clusterer.h" +#include "TOFReconstruction/CosmicProcessor.h" #include "TOFReconstruction/DataReader.h" #include "DataFormatsTOF/Cluster.h" +#include "DataFormatsTOF/CosmicInfo.h" +#include "DataFormatsTOF/CalibInfoCluster.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "DataFormatsTOF/CalibLHCphaseTOF.h" #include "DataFormatsTOF/CalibTimeSlewingParamTOF.h" #include "TOFCalibration/CalibTOFapi.h" #include "TStopwatch.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataRefUtils.h" #include <memory> // for make_shared, make_unique, unique_ptr #include <vector> @@ -45,14 +51,25 @@ class TOFDPLClustererTask { bool mUseMC = true; bool mUseCCDB = false; + bool mIsCalib = false; + bool mIsCosmic = false; + int mTimeWin = 5000; public: - explicit TOFDPLClustererTask(bool useMC, bool useCCDB) : mUseMC(useMC), mUseCCDB(useCCDB) {} + explicit TOFDPLClustererTask(bool useMC, bool useCCDB, bool doCalib, bool isCosmic) : mUseMC(useMC), mUseCCDB(useCCDB), mIsCalib(doCalib), mIsCosmic(isCosmic) {} void init(framework::InitContext& ic) { // nothing special to be set up mTimer.Stop(); mTimer.Reset(); + + mTimeWin = ic.options().get<int>("cluster-time-window"); + LOG(INFO) << "Is calibration from cluster on? " << mIsCalib; + LOG(INFO) << "DeltaTime for clusterization = " << mTimeWin << " ps"; + LOG(INFO) << "Is cosmics? " << mIsCosmic; + + mClusterer.setCalibFromCluster(mIsCalib); + mClusterer.setDeltaTforClustering(mTimeWin); } void run(framework::ProcessingContext& pc) @@ -60,18 +77,10 @@ class TOFDPLClustererTask mTimer.Start(false); // get digit data auto digits = pc.inputs().get<gsl::span<o2::tof::Digit>>("tofdigits"); - auto row = pc.inputs().get<std::vector<o2::tof::ReadoutWindowData>*>("readoutwin"); + auto row = pc.inputs().get<gsl::span<o2::tof::ReadoutWindowData>>("readoutwin"); - auto header = o2::header::get<o2::header::DataHeader*>(pc.inputs().get("tofdigits").header); - mClusterer.setFirstOrbit(header->firstTForbit); - - //RSTODO: below is a hack, to remove once the framework will start propagating the header.firstTForbit - //Here I extract the orbit/BC from the abs.BC, since the triggerer orbit/bunch are not set. Then why they are needed? - if (digits.size()) { - auto bcabs = digits[0].getBC(); - auto ir0 = o2::raw::HBFUtils::Instance().getFirstIRofTF({uint16_t(bcabs % Geo::BC_IN_ORBIT), uint32_t(bcabs / Geo::BC_IN_ORBIT)}); - mClusterer.setFirstOrbit(ir0.orbit); - } + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + mClusterer.setFirstOrbit(dh->firstTForbit); auto labelvector = std::make_shared<std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>>(); if (mUseMC) { @@ -82,7 +91,7 @@ class TOFDPLClustererTask } o2::dataformats::CalibLHCphaseTOF lhcPhaseObj; - o2::dataformats::CalibTimeSlewingParamTOF channelCalibObj; + auto channelCalibObj = std::make_unique<o2::dataformats::CalibTimeSlewingParamTOF>(); if (mUseCCDB) { // read calibration objects from ccdb // check LHC phase @@ -94,39 +103,50 @@ class TOFDPLClustererTask // make a copy in global scope lhcPhaseObj = lhcPhaseObjTmp; - channelCalibObj = channelCalibObjTmp; + *channelCalibObj = channelCalibObjTmp; } else { // calibration objects set to zero lhcPhaseObj.addLHCphase(0, 0); lhcPhaseObj.addLHCphase(2000000000, 0); for (int ich = 0; ich < o2::dataformats::CalibTimeSlewingParamTOF::NCHANNELS; ich++) { - channelCalibObj.addTimeSlewingInfo(ich, 0, 0); + channelCalibObj->addTimeSlewingInfo(ich, 0, 0); int sector = ich / o2::dataformats::CalibTimeSlewingParamTOF::NCHANNELXSECTOR; int channelInSector = ich % o2::dataformats::CalibTimeSlewingParamTOF::NCHANNELXSECTOR; - channelCalibObj.setFractionUnderPeak(sector, channelInSector, 1); + channelCalibObj->setFractionUnderPeak(sector, channelInSector, 1); } } - o2::tof::CalibTOFapi calibapi(long(0), &lhcPhaseObj, &channelCalibObj); + o2::tof::CalibTOFapi calibapi(long(0), &lhcPhaseObj, channelCalibObj.get()); mClusterer.setCalibApi(&calibapi); // call actual clustering routine mClustersArray.clear(); + if (mIsCalib) { + mClusterer.getInfoFromCluster()->clear(); + } - for (int i = 0; i < row->size(); i++) { - //printf("# TOF readout window for clusterization = %d/%lu (N digits = %d)\n", i, row->size(), row->at(i).size()); - auto digitsRO = row->at(i).getBunchChannelData(digits); + if (mIsCosmic) { + mCosmicProcessor.clear(); + } + for (int i = 0; i < row.size(); i++) { + //printf("# TOF readout window for clusterization = %d/%lu (N digits = %d)\n", i, row.size(), row[i].size()); + auto digitsRO = row[i].getBunchChannelData(digits); mReader.setDigitArray(&digitsRO); + + if (mIsCosmic) { + mCosmicProcessor.process(mReader, i != 0); + } + if (mUseMC) { mClusterer.process(mReader, mClustersArray, &(labelvector->at(i))); } else { mClusterer.process(mReader, mClustersArray, nullptr); } } - LOG(INFO) << "TOF CLUSTERER : TRANSFORMED " << digits.size() - << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; + LOG(DEBUG) << "TOF CLUSTERER : TRANSFORMED " << digits.size() + << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; // send clusters pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe}, mClustersArray); @@ -135,6 +155,20 @@ class TOFDPLClustererTask pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe}, mClsLabels); } + if (mIsCalib) { + std::vector<CalibInfoCluster>* clusterCalInfo = mClusterer.getInfoFromCluster(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOCALCLUS", 0, Lifetime::Timeframe}, *clusterCalInfo); + } + + if (mIsCosmic) { + std::vector<CosmicInfo>* cosmicInfo = mCosmicProcessor.getCosmicInfo(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOCOSMICS", 0, Lifetime::Timeframe}, *cosmicInfo); + std::vector<CalibInfoTrackCl>* cosmicTrack = mCosmicProcessor.getCosmicTrack(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOTRACKCOS", 0, Lifetime::Timeframe}, *cosmicTrack); + std::vector<int>* cosmicTrackSize = mCosmicProcessor.getCosmicTrackSize(); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOTRACKSIZE", 0, Lifetime::Timeframe}, *cosmicTrackSize); + } + mTimer.Stop(); } @@ -147,13 +181,15 @@ class TOFDPLClustererTask private: DigitDataReader mReader; ///< Digit reader Clusterer mClusterer; ///< Cluster finder + CosmicProcessor mCosmicProcessor; ///< Cosmics finder TStopwatch mTimer; std::vector<Cluster> mClustersArray; ///< Array of clusters MCLabelContainer mClsLabels; + std::vector<CalibInfoCluster> mClusterCalInfo; ///< Array of clusters }; -o2::framework::DataProcessorSpec getTOFClusterizerSpec(bool useMC, bool useCCDB) +o2::framework::DataProcessorSpec getTOFClusterizerSpec(bool useMC, bool useCCDB, bool doCalib, bool isCosmic) { std::vector<InputSpec> inputs; inputs.emplace_back("tofdigits", o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe); @@ -172,12 +208,21 @@ o2::framework::DataProcessorSpec getTOFClusterizerSpec(bool useMC, bool useCCDB) outputs.emplace_back(o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); } + if (doCalib) { + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOCALCLUS", 0, Lifetime::Timeframe); + } + if (isCosmic) { + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOCOSMICS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOTRACKCOS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOTRACKSIZE", 0, Lifetime::Timeframe); + } + return DataProcessorSpec{ "TOFClusterer", inputs, outputs, - AlgorithmSpec{adaptFromTask<TOFDPLClustererTask>(useMC, useCCDB)}, - Options{/* for the moment no options */}}; + AlgorithmSpec{adaptFromTask<TOFDPLClustererTask>(useMC, useCCDB, doCalib, isCosmic)}, + Options{{"cluster-time-window", VariantType::Int, 5000, {"time window for clusterization in ps"}}}}; } } // end namespace tof diff --git a/Detectors/TOF/workflow/src/cluscal-reader.cxx b/Detectors/TOF/workflow/src/cluscal-reader.cxx new file mode 100644 index 0000000000000..f6ce01759c3b3 --- /dev/null +++ b/Detectors/TOF/workflow/src/cluscal-reader.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TOFWorkflowIO/CalibClusReaderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"cosmics", o2::framework::VariantType::Bool, false, {"If it has cosmics infos"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + auto isCosmics = cfgc.options().get<bool>("cosmics"); + wf.emplace_back(o2::tof::getCalibClusReaderSpec(isCosmics)); + return wf; +} diff --git a/Detectors/TOF/workflow/src/cluster-calib.cxx b/Detectors/TOF/workflow/src/cluster-calib.cxx new file mode 100644 index 0000000000000..a53554c06c119 --- /dev/null +++ b/Detectors/TOF/workflow/src/cluster-calib.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TOFWorkflowIO/TOFCalClusInfoWriterSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + options.push_back(ConfigParamSpec{"cosmics", o2::framework::VariantType::Bool, false, {"add cal info from cosmics"}}); + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + auto isCosmics = cfgc.options().get<bool>("cosmics"); + wf.emplace_back(o2::tof::getTOFCalClusInfoWriterSpec(isCosmics)); + return wf; +} diff --git a/Detectors/TOF/workflow/src/cluster-writer-commissioning.cxx b/Detectors/TOF/workflow/src/cluster-writer-commissioning.cxx new file mode 100644 index 0000000000000..6a2c4f6210787 --- /dev/null +++ b/Detectors/TOF/workflow/src/cluster-writer-commissioning.cxx @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TOFWorkflowIO/TOFClusterWriterSplitterSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"ntf", o2::framework::VariantType::Int, 1, {"number of timeframe written for output file"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + auto ntf = cfgc.options().get<int>("ntf"); + wf.emplace_back(o2::framework::getTOFClusterWriterSplitterSpec(ntf)); + + return wf; +} diff --git a/Detectors/TOF/workflow/src/digit-writer-commissioning.cxx b/Detectors/TOF/workflow/src/digit-writer-commissioning.cxx index a42cd1fef3046..5e70f51dcc22b 100644 --- a/Detectors/TOF/workflow/src/digit-writer-commissioning.cxx +++ b/Detectors/TOF/workflow/src/digit-writer-commissioning.cxx @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "TOFWorkflowUtils/TOFDigitWriterSplitterSpec.h" +#include "TOFWorkflowIO/TOFDigitWriterSplitterSpec.h" #include "CommonUtils/ConfigurableParam.h" #include "Framework/ConfigParamSpec.h" @@ -34,6 +35,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // Update the (declared) parameters if changed from the command line auto ntf = cfgc.options().get<int>("ntf"); auto write_err = cfgc.options().get<bool>("write-decoding-errors"); - wf.emplace_back(o2::framework::getTOFCalibCollectorWriterSpec(ntf, write_err)); + wf.emplace_back(o2::framework::getTOFDigitWriterSplitterSpec(ntf, write_err)); return wf; } diff --git a/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx b/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx index aaa303de91e00..d679fc665a82a 100644 --- a/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflow/src/file-proxy.cxx b/Detectors/TOF/workflow/src/file-proxy.cxx new file mode 100644 index 0000000000000..ada51fc281d09 --- /dev/null +++ b/Detectors/TOF/workflow/src/file-proxy.cxx @@ -0,0 +1,257 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file file-proxy.cxx +/// @author Roberto Preghenella +/// @since 2020-03-08 +/// @brief TOF compressed data analysis task + +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/CallbackService.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include <fairmq/FairMQDevice.h> + +#include "Headers/RAWDataHeader.h" +#include "DataFormatsTOF/RawDataFormat.h" + +#include <iostream> + +using namespace o2::framework; + +class FileProxyTask : public Task +{ + public: + FileProxyTask() = default; + ~FileProxyTask() override = default; + + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + long readFLP() + { + if (mRDHversion == 4) { + return readFLPv4(); + } + if (mRDHversion == 6) { + return readFLPv6(); + } + return 0; + }; + long readFLPv4(); + long readFLPv6(); + long readCONET(); + + bool mStatus = false; + bool mCONET = false; + int mRDHversion = 4; + bool mDumpData = false; + std::ifstream mFile; + char mBuffer[4194304]; +}; + +void FileProxyTask::init(InitContext& ic) +{ + auto infilename = ic.options().get<std::string>("atc-file-proxy-input-filename"); + auto startfrom = ic.options().get<int>("atc-file-proxy-start-from"); + mCONET = ic.options().get<bool>("atc-file-proxy-conet-mode"); + mDumpData = ic.options().get<bool>("atc-file-proxy-dump-data"); + mRDHversion = ic.options().get<int>("atc-file-proxy-rdh-version"); + + /** open input file **/ + std::cout << " --- Opening input file: " << infilename << std::endl; + mFile.open(infilename, std::fstream::in | std::fstream::binary); + if (!mFile.is_open()) { + std::cout << " --- File is not open " << std::endl; + mStatus = true; + } + std::cout << " --- Start reading from byte offset: " << startfrom << std::endl; + mFile.seekg(startfrom, std::ios::beg); + + if (mCONET) { + std::cout << " --- CONET mode " << std::endl; + } +}; + +long FileProxyTask::readFLPv4() +{ + /** read input file **/ + char* pointer = mBuffer; + if (!mFile.read(pointer, 64)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + long payload = 64; + auto rdh = reinterpret_cast<o2::header::RAWDataHeaderV4*>(pointer); + while (!rdh->stop) { + if (!mFile.read(pointer + rdh->headerSize, rdh->offsetToNext - rdh->headerSize)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + payload += (rdh->offsetToNext - rdh->headerSize); + pointer += rdh->offsetToNext; + if (!mFile.read(pointer, 64)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + payload += 64; + rdh = reinterpret_cast<o2::header::RAWDataHeaderV4*>(pointer); + } + + return payload; +} + +long FileProxyTask::readFLPv6() +{ + /** read input file **/ + char* pointer = mBuffer; + if (!mFile.read(pointer, 64)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + long payload = 64; + auto rdh = reinterpret_cast<o2::header::RAWDataHeaderV6*>(pointer); + while (!rdh->stop) { + if (!mFile.read(pointer + rdh->headerSize, rdh->offsetToNext - rdh->headerSize)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + payload += (rdh->offsetToNext - rdh->headerSize); + pointer += rdh->offsetToNext; + if (!mFile.read(pointer, 64)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + payload += 64; + rdh = reinterpret_cast<o2::header::RAWDataHeaderV6*>(pointer); + } + + return payload; +} + +long FileProxyTask::readCONET() +{ + + uint32_t word; + auto current = mFile.tellg(); + + /** read size of tof buffer **/ + if (!mFile.read((char*)&word, 4)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + auto bytePayload = word * 4; + std::cout << " --- tofBuffer: " << word << " (" << bytePayload << " bytes) at " << current << std::endl; + + /** read payload **/ + if (!mFile.read(mBuffer, bytePayload)) { + std::cout << " --- Cannot read input file: " << strerror(errno) << std::endl; + mStatus = true; + return 0; + } + return bytePayload; +} + +void FileProxyTask::run(ProcessingContext& pc) +{ + + /** check status **/ + if (mStatus) { + mFile.close(); + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + return; + } + + /** read data **/ + int payload = 0; + if (mCONET) { + payload = readCONET(); + } else { + payload = readFLP(); + } + if (payload == 0) { + mStatus = true; + return; + } + + if (mDumpData) { + std::cout << " --- dump data: " << payload << " bytes" << std::endl; + uint32_t* word = reinterpret_cast<uint32_t*>(mBuffer); + for (int i = 0; i < payload / 4; ++i) { + printf(" 0x%08x \n", *word); + word++; + } + std::cout << " --- end of dump data " << std::endl; + } + + /** output **/ + auto device = pc.services().get<o2::framework::RawDeviceService>().device(); + auto outputRoutes = pc.services().get<o2::framework::RawDeviceService>().spec().outputs; + auto fairMQChannel = outputRoutes.at(0).channel; + auto payloadMessage = device->NewMessage(payload); + std::memcpy(payloadMessage->GetData(), mBuffer, payload); + o2::header::DataHeader header("RAWDATA", "TOF", 0); + header.payloadSize = payload; + o2::framework::DataProcessingHeader dataProcessingHeader{0}; + o2::header::Stack headerStack{header, dataProcessingHeader}; + auto headerMessage = device->NewMessage(headerStack.size()); + std::memcpy(headerMessage->GetData(), headerStack.data(), headerStack.size()); + + /** send **/ + FairMQParts parts; + parts.AddPart(std::move(headerMessage)); + parts.AddPart(std::move(payloadMessage)); + device->Send(parts, fairMQChannel); + + /** check end of file **/ + if (mFile.eof()) { + std::cout << " --- End of file " << std::endl; + mStatus = true; + } +}; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ +} + +#include "Framework/runDataProcessing.h" // the main driver + +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + DataProcessorSpec{"file-proxy", + Inputs{}, + Outputs{OutputSpec(ConcreteDataTypeMatcher{"TOF", "RAWDATA"})}, + AlgorithmSpec(adaptFromTask<FileProxyTask>()), + Options{ + {"atc-file-proxy-input-filename", VariantType::String, "", {"Input file name"}}, + {"atc-file-proxy-start-from", VariantType::Int, 0, {"Start reading from byte"}}, + {"atc-file-proxy-dump-data", VariantType::Bool, false, {"Dump data"}}, + {"atc-file-proxy-rdh-version", VariantType::Int, 4, {"RDH version"}}, + {"atc-file-proxy-conet-mode", VariantType::Bool, false, {"CONET mode"}}}}}; +} diff --git a/Detectors/TOF/workflowIO/CMakeLists.txt b/Detectors/TOF/workflowIO/CMakeLists.txt new file mode 100644 index 0000000000000..39cd64fcfe3fa --- /dev/null +++ b/Detectors/TOF/workflowIO/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TOFWorkflowIO + SOURCES src/DigitReaderSpec.cxx + src/ClusterReaderSpec.cxx + src/TOFClusterWriterSpec.cxx + src/TOFDigitWriterSpec.cxx + src/TOFRawWriterSpec.cxx + src/TOFCalClusInfoWriterSpec.cxx + src/CalibClusReaderSpec.cxx + src/TOFMatchedWriterSpec.cxx + src/TOFCalibWriterSpec.cxx + src/TOFMatchedReaderSpec.cxx + src/CalibInfoReaderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction) + diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibClusReaderSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibClusReaderSpec.h new file mode 100644 index 0000000000000..66e847847160a --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibClusReaderSpec.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CalibClusReaderSpec.h + +#ifndef O2_TOF_CALIBCLUSREADER +#define O2_TOF_CALIBCLUSREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTOF/CosmicInfo.h" +#include "DataFormatsTOF/CalibInfoCluster.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +class CalibClusReader : public Task +{ + public: + CalibClusReader(bool isCosmics) : mIsCosmics(isCosmics) {} + ~CalibClusReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + std::unique_ptr<TFile> mFile = nullptr; + std::unique_ptr<TTree> mTree = nullptr; + int mState = 0; + int mCurrentEntry = 0; + bool mIsCosmics = false; + std::vector<CalibInfoCluster> mClusInfos, *mPclusInfos = &mClusInfos; + std::vector<CosmicInfo> mCosmicInfo, *mPcosmicInfo = &mCosmicInfo; + std::vector<o2::tof::CalibInfoTrackCl> mCosmicTrack, *mPcosmicTrack = &mCosmicTrack; + std::vector<int> mCosmicTrackSize, *mPcosmicTrackSize = &mCosmicTrackSize; +}; + +/// create a processor spec +/// read cluster calib infos from a root file +DataProcessorSpec getCalibClusReaderSpec(bool isCosmics); + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_CALIBCLUSREADER */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibInfoReaderSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibInfoReaderSpec.h new file mode 100644 index 0000000000000..c8331beb7e424 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/CalibInfoReaderSpec.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CalibInfoReaderSpec.h + +#ifndef O2_TOF_CALIBINFOREADER +#define O2_TOF_CALIBINFOREADER + +#include "TFile.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTOF/CalibInfoTOF.h" +#include <string> + +class TTree; + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +class CalibInfoReader : public Task +{ + public: + CalibInfoReader(int instance, int ninstances, const char* filename, bool toftpc = false) : mInstance(instance), mNinstances(ninstances), mFileName(filename), mTOFTPC(toftpc) {} + ~CalibInfoReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + int mState = 0; + int mInstance; + int mNinstances; + std::string mFileName{}; + FILE* mFile = nullptr; + TTree* mTree = nullptr; + bool mTOFTPC = false; + int mCurrentEntry = 0; + int mGlobalEntry = 0; + std::vector<o2::dataformats::CalibInfoTOF> mVect, *mPvect = &mVect; +}; + +/// create a processor spec +/// read simulated TOF digits from a root file +framework::DataProcessorSpec getCalibInfoReaderSpec(int instance, int ninstances, const char* filename, bool toftpc = false); + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_CALIBINFOREADER */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/ClusterReaderSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/ClusterReaderSpec.h new file mode 100644 index 0000000000000..b75bee035b8c5 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/ClusterReaderSpec.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.h + +#ifndef O2_TOF_CLUSTERREADER +#define O2_TOF_CLUSTERREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTOF/Cluster.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +class ClusterReader : public Task +{ + public: + ClusterReader(bool useMC) : mUseMC(useMC) {} + ~ClusterReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + + bool mUseMC = true; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + + std::vector<Cluster> mClusters, *mClustersPtr = &mClusters; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; +}; + +/// create a processor spec +/// read simulated TOF digits from a root file +framework::DataProcessorSpec getClusterReaderSpec(bool useMC); + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_CLUSTERREADER */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/DigitReaderSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/DigitReaderSpec.h new file mode 100644 index 0000000000000..9f97f25019e1f --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/DigitReaderSpec.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h + +#ifndef O2_TOF_DIGITREADER +#define O2_TOF_DIGITREADER + +#include "TFile.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "TOFBase/Digit.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +class DigitReader : public Task +{ + public: + DigitReader(bool useMC) : mUseMC(useMC) {} + ~DigitReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + int mState = 0; + int mCurrentEntry = 0; + bool mUseMC = true; + std::unique_ptr<TFile> mFile = nullptr; + std::vector<o2::tof::Digit> mDigits, *mPdigits = &mDigits; + std::vector<o2::tof::ReadoutWindowData> mRow, *mProw = &mRow; + std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabels, *mPlabels = &mLabels; + std::vector<uint8_t> mPatterns, *mPpatterns = &mPatterns; +}; + +/// create a processor spec +/// read simulated TOF digits from a root file +framework::DataProcessorSpec getDigitReaderSpec(bool useMC); + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_DIGITREADER */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalClusInfoWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalClusInfoWriterSpec.h new file mode 100644 index 0000000000000..2836ff5207e9e --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalClusInfoWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFCalClusInfoWriterSpec.h + +#ifndef STEER_DIGITIZERWORKFLOW_TOFCALCLUSINFOWRITER_H_ +#define STEER_DIGITIZERWORKFLOW_TOFCALCLUSINFOWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +/// create a processor spec +/// write ITS tracks a root file +o2::framework::DataProcessorSpec getTOFCalClusInfoWriterSpec(bool isCosmics = 0); + +} // namespace tof +} // namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_TOFCALCLUSINFOWRITER_H_ */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalibWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalibWriterSpec.h new file mode 100644 index 0000000000000..756cfb71c90ed --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFCalibWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFCalibWriterSpec.h + +#ifndef TOFWORKFLOW_TOFCALIBWRITER_H_ +#define TOFWORKFLOW_TOFCALIBWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +/// create a processor spec +/// write TOF calbi info in a root file +o2::framework::DataProcessorSpec getTOFCalibWriterSpec(const char* outdef = "o2calib_tof.root", bool toftpc = false); + +} // namespace tof +} // namespace o2 + +#endif /* TOFWORKFLOW_TOFCALIBWRITER_H_ */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSpec.h new file mode 100644 index 0000000000000..13b23c136013f --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFClusterWriterSpec.h + +#ifndef STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ +#define STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +/// create a processor spec +/// write ITS tracks a root file +o2::framework::DataProcessorSpec getTOFClusterWriterSpec(bool useMC); + +} // namespace tof +} // namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_TOFCLUSTERWRITER_H_ */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSplitterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSplitterSpec.h new file mode 100644 index 0000000000000..be1b9db82c9ec --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFClusterWriterSplitterSpec.h @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TOFCLUSTER_SPLITTER_WRITER_H +#define O2_TOFCLUSTER_SPLITTER_WRITER_H + +/// @file TOFClusterWriterSplitterSpec.h +/// @brief Device to write to tree the information for TOF time slewing calibration. + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTOF/Cluster.h" +#include "Framework/Logger.h" +#include <TTree.h> +#include <TFile.h> +#include <gsl/span> + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ +class TOFClusterWriterSplitter : public Task +{ + using OutputType = std::vector<o2::tof::Cluster>; + + std::string mBaseName; + + public: + TOFClusterWriterSplitter(int nTF) : mTFthr(nTF) {} + + void createAndOpenFileAndTree() + { + TString filename = TString::Format("%s_%06d.root", mBaseName.c_str(), mCount); + LOG(DEBUG) << "opening file " << filename.Data(); + mfileOut.reset(TFile::Open(TString::Format("%s", filename.Data()), "RECREATE")); + mOutputTree = std::make_unique<TTree>("o2sim", "Tree with TOF clusters"); + mOutputTree->Branch("TOFCluster", &mPClusters); + + mNTF = 0; + } + + void init(o2::framework::InitContext& ic) final + { + mBaseName = ic.options().get<std::string>("output-base-name"); + + mCount = 0; + createAndOpenFileAndTree(); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto clusters = pc.inputs().get<OutputType>("clusters"); + mPClusters = &clusters; + mOutputTree->Fill(); + + mNTF++; + + if (mNTF >= mTFthr) { + sendOutput(); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + mIsEndOfStream = true; + sendOutput(); + } + + private: + int mCount = 0; // how many times we filled the tree + int mNTF = 0; + int mTFthr = 1; + bool mIsEndOfStream = false; + OutputType mClusters; + const OutputType* mPClusters = &mClusters; + + std::unique_ptr<TTree> mOutputTree; ///< tree for the collected calib tof info + std::unique_ptr<TFile> mfileOut = nullptr; // file in which to write the output + + //________________________________________________________________ + void sendOutput() + { + // This is to fill the tree. + // One file with an empty tree will be created at the end, because we have to have a + // tree opened before processing, since we do not know a priori if something else + // will still come. The size of this extra file is ~6.5 kB + + mfileOut->cd(); + mOutputTree->Write(); + mOutputTree.reset(); + mfileOut.reset(); + mCount++; + if (!mIsEndOfStream) { + createAndOpenFileAndTree(); + } + } +}; +} // namespace tof + +namespace framework +{ + +DataProcessorSpec getTOFClusterWriterSplitterSpec(int nTF) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("clusters", o2::header::gDataOriginTOF, "CLUSTERS"); + + std::vector<OutputSpec> outputs; // empty + + return DataProcessorSpec{ + "tof-cluster-splitter-writer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<o2::tof::TOFClusterWriterSplitter>(nTF)}, + Options{{"output-base-name", VariantType::String, "tofclusters", {"Name of the input file (root extension will be added)"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSpec.h new file mode 100644 index 0000000000000..d9fcdf399ab68 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ +#define STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tof +{ + +o2::framework::DataProcessorSpec getTOFDigitWriterSpec(bool useMC = 1, bool writeErr = 0); + +} // end namespace tof +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_TOFDIGITWRITER_H_ */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSplitterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSplitterSpec.h new file mode 100644 index 0000000000000..e01b994330068 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFDigitWriterSplitterSpec.h @@ -0,0 +1,179 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TOFDIGIT_SPLITTER_WRITER_H +#define O2_TOFDIGIT_SPLITTER_WRITER_H + +/// @file TOFDigitWriterSplitterSpec.h +/// @brief Device to write to tree the information for TOF time slewing calibration. + +#include "Framework/ControlService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "TOFBase/Digit.h" +#include "Framework/Logger.h" +#include <TTree.h> +#include <TFile.h> +#include <gsl/span> + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ +class TOFDigitWriterSplitter : public Task +{ + using OutputType = std::vector<o2::tof::Digit>; + using ReadoutWinType = std::vector<o2::tof::ReadoutWindowData>; + using PatternType = std::vector<uint8_t>; + using ErrorType = std::vector<uint64_t>; + using HeaderType = o2::tof::DigitHeader; + + std::string mBaseName; + + public: + TOFDigitWriterSplitter(int nTF, bool storeErr = false) : mTFthr(nTF), mStoreErrors(storeErr) {} + + void createAndOpenFileAndTree(int ithread = 0) + { + TString filename = TString::Format("%s_%02d_%06d.root", mBaseName.c_str(), ithread, mCount); + LOG(DEBUG) << "opening file " << filename.Data(); + mfileOut.reset(TFile::Open(TString::Format("%s", filename.Data()), "RECREATE")); + mOutputTree = std::make_unique<TTree>("o2sim", "Tree with TOF digits"); + mOutputTree->Branch("TOFHeader", &mPHeader); + mOutputTree->Branch("TOFDigit", &mPDigits); + mOutputTree->Branch("TOFReadoutWindow", &mPROW); + mOutputTree->Branch("TOFPatterns", &mPDia); + if (mStoreErrors) { + mOutputTree->Branch("TOFErrors", &mPErr); + } + + mNTF = 0; + } + + void init(o2::framework::InitContext& ic) final + { + mBaseName = ic.options().get<std::string>("output-base-name"); + + mCount = 0; + + auto instance = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; + + createAndOpenFileAndTree(instance); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto instance = pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; + //pc.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices; + + auto digits = pc.inputs().get<OutputType>("digits"); + mPDigits = &digits; + auto header = pc.inputs().get<HeaderType>("header"); + mPHeader = &header; + auto row = pc.inputs().get<ReadoutWinType>("rows"); + mPROW = &row; + auto dia = pc.inputs().get<PatternType>("patterns"); + mPDia = &dia; + if (mStoreErrors) { + auto error = pc.inputs().get<ErrorType>("errors"); + mPErr = &error; + + mOutputTree->Fill(); + } else { + mOutputTree->Fill(); + } + mNTF++; + + if (mNTF >= mTFthr) { + sendOutput(instance); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + mIsEndOfStream = true; + auto instance = ec.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; + + sendOutput(instance); + } + + private: + int mCount = 0; // how many times we filled the tree + int mNTF = 0; + int mTFthr = 1; + bool mStoreErrors = false; + bool mIsEndOfStream = false; + OutputType mDigits; + const OutputType* mPDigits = &mDigits; + ReadoutWinType mROW; + const ReadoutWinType* mPROW = &mROW; + PatternType mDia; + const PatternType* mPDia = &mDia; + ErrorType mErr; + const ErrorType* mPErr = &mErr; + HeaderType mHeader; + const HeaderType* mPHeader = &mHeader; + std::unique_ptr<TTree> mOutputTree; ///< tree for the collected calib tof info + std::unique_ptr<TFile> mfileOut = nullptr; // file in which to write the output + + //________________________________________________________________ + void sendOutput(int instance) + { + // This is to fill the tree. + // One file with an empty tree will be created at the end, because we have to have a + // tree opened before processing, since we do not know a priori if something else + // will still come. The size of this extra file is ~6.5 kB + + mfileOut->cd(); + mOutputTree->Write(); + mOutputTree.reset(); + mfileOut.reset(); + mCount++; + if (!mIsEndOfStream) { + createAndOpenFileAndTree(instance); + } + } +}; +} // namespace tof + +namespace framework +{ + +DataProcessorSpec getTOFDigitWriterSplitterSpec(int nTF, bool storeErr = false) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("header", o2::header::gDataOriginTOF, "DIGITHEADER"); + inputs.emplace_back("digits", o2::header::gDataOriginTOF, "DIGITS"); + inputs.emplace_back("rows", o2::header::gDataOriginTOF, "READOUTWINDOW"); + inputs.emplace_back("patterns", o2::header::gDataOriginTOF, "PATTERNS"); + + if (storeErr) { + inputs.emplace_back("errors", o2::header::gDataOriginTOF, "ERRORS"); + } + + std::vector<OutputSpec> outputs; // empty + + return DataProcessorSpec{ + "tof-digit-splitter-writer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<o2::tof::TOFDigitWriterSplitter>(nTF, storeErr)}, + Options{{"output-base-name", VariantType::String, "tofdigits", {"Name of the input file (root extension will be added)"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedReaderSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedReaderSpec.h new file mode 100644 index 0000000000000..45ae9e7bd6c89 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedReaderSpec.h @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatchedReaderSpec.h + +#ifndef O2_TOF_MATCHINFOREADER +#define O2_TOF_MATCHINFOREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ +namespace tof +{ + +class TOFMatchedReader : public o2::framework::Task +{ + public: + TOFMatchedReader(bool useMC, bool tpcmatch, bool readTracks, bool subSpecStrict = false) : mUseMC(useMC), mTPCMatch(tpcmatch), mReadTracks(readTracks), mSubSpecStrict(subSpecStrict) {} + ~TOFMatchedReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + + bool mUseMC = false; + bool mTPCMatch = false; + bool mReadTracks = false; + bool mSubSpecStrict = false; + + std::string mInFileName{"o2match_tof.root"}; + std::string mInTreeName{"matchTOF"}; + std::unique_ptr<TFile> mFile = nullptr; + std::unique_ptr<TTree> mTree = nullptr; + std::vector<o2::dataformats::MatchInfoTOF> mMatches, *mMatchesPtr = &mMatches; + std::vector<o2::dataformats::TrackTPCTOF> mTracks, *mTracksPtr = &mTracks; + std::vector<o2::MCCompLabel> mLabelTOF, *mLabelTOFPtr = &mLabelTOF; +}; + +/// create a processor spec +/// read matched TOF clusters from a ROOT file +framework::DataProcessorSpec getTOFMatchedReaderSpec(bool useMC, bool tpcmatch = false, bool readTracks = false, bool subSpecStrict = false); + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_MATCHINFOREADER */ diff --git a/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedWriterSpec.h new file mode 100644 index 0000000000000..78368ce663fd4 --- /dev/null +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFMatchedWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatchedWriterSpec.h + +#ifndef TOFWORKFLOW_TOFMATCHEDWRITER_H_ +#define TOFWORKFLOW_TOFMATCHEDWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +/// create a processor spec +/// write TOF matching info in a root file +o2::framework::DataProcessorSpec getTOFMatchedWriterSpec(bool useMC, const char* outdef = "o2match_tof.root", bool writeTracks = false, int mode = 0, bool strict = false); + +} // namespace tof +} // namespace o2 + +#endif /* TOFWORKFLOW_TOFMATCHEDWRITER_H_ */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFRawWriterSpec.h b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFRawWriterSpec.h similarity index 75% rename from Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFRawWriterSpec.h rename to Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFRawWriterSpec.h index d58c3a49db6fc..e558284435334 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFRawWriterSpec.h +++ b/Detectors/TOF/workflowIO/include/TOFWorkflowIO/TOFRawWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TOF/workflowIO/src/CalibClusReaderSpec.cxx b/Detectors/TOF/workflowIO/src/CalibClusReaderSpec.cxx new file mode 100644 index 0000000000000..af29ce9e18f15 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/CalibClusReaderSpec.cxx @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CalibClusReaderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TOFWorkflowIO/CalibClusReaderSpec.h" +#include "Framework/Logger.h" + +using namespace o2::framework; +using namespace o2::tof; + +namespace o2 +{ +namespace tof +{ + +void CalibClusReader::init(InitContext& ic) +{ + LOG(INFO) << "Init Cluster reader!"; + auto filename = ic.options().get<std::string>("tof-calclus-infile"); + connectTree(filename); +} + +void CalibClusReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(DEBUG) << "Pushing " << mPclusInfos->size() << " TOF clusters calib info at entry " << ent; + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOCALCLUS", 0, Lifetime::Timeframe}, mClusInfos); + + if (mIsCosmics) { + LOG(DEBUG) << "Pushing " << mPcosmicInfo->size() << " TOF cosmics info at entry " << ent; + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOCOSMICS", 0, Lifetime::Timeframe}, mCosmicInfo); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOTRACKCOS", 0, Lifetime::Timeframe}, mCosmicTrack); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "INFOTRACKSIZE", 0, Lifetime::Timeframe}, mCosmicTrackSize); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void CalibClusReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("o2sim")); + assert(mTree); + mTree->SetBranchAddress("TOFClusterCalInfo", &mPclusInfos); + if (mIsCosmics) { + mTree->SetBranchAddress("TOFCosmics", &mPcosmicInfo); + mTree->SetBranchAddress("TOFTracks", &mPcosmicTrack); + mTree->SetBranchAddress("TOFTracksSize", &mPcosmicTrackSize); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getCalibClusReaderSpec(bool isCosmics) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOCALCLUS", 0, Lifetime::Timeframe); + if (isCosmics) { + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOCOSMICS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOTRACKCOS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "INFOTRACKSIZE", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "tof-calclus-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<CalibClusReader>(isCosmics)}, + Options{ + {"tof-calclus-infile", VariantType::String, "tofclusCalInfo.root", {"Name of the input file"}}}}; +} + +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/CalibInfoReaderSpec.cxx b/Detectors/TOF/workflowIO/src/CalibInfoReaderSpec.cxx new file mode 100644 index 0000000000000..d79bf23c3f629 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/CalibInfoReaderSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include <vector> +#include <unistd.h> + +#include "TChain.h" +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "TOFWorkflowIO/CalibInfoReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::tof; + +namespace o2 +{ +namespace tof +{ + +constexpr o2::header::DataDescription ddCalib{"CALIBDATA"}, ddCalib_tpc{"CALIBDATA_TPC"}; + +void CalibInfoReader::init(InitContext& ic) +{ + LOG(INFO) << "Init CalibInfo reader!"; + auto fname = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), mFileName); + mFile = fopen(fname.c_str(), "r"); + if (!mFile) { + LOG(ERROR) << "Cannot open the " << fname << " file !"; + mState = 0; + return; + } + mState = 1; +} + +void CalibInfoReader::run(ProcessingContext& pc) +{ + if (mState != 1) { + return; + } + + char filename[100]; + + if ((mTree && mCurrentEntry < mTree->GetEntries()) || fscanf(mFile, "%s", filename) == 1) { + if (!mTree || mCurrentEntry >= mTree->GetEntries()) { + TFile* fin = TFile::Open(filename); + mTree = (TTree*)fin->Get("calibTOF"); + mCurrentEntry = 0; + mTree->SetBranchAddress("TOFCalibInfo", &mPvect); + } + if ((mGlobalEntry % mNinstances) == mInstance) { + mTree->GetEvent(mCurrentEntry); + LOG(INFO) << "Send " << mVect.size() << " calib infos"; + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, mTOFTPC ? ddCalib_tpc : ddCalib, 0, Lifetime::Timeframe}, mVect); + usleep(10000); + } + mGlobalEntry++; + mCurrentEntry++; + } else { + mState = 2; + pc.services().get<ControlService>().endOfStream(); + } + return; +} + +DataProcessorSpec getCalibInfoReaderSpec(int instance, int ninstances, const char* filename, bool toftpc) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTOF, toftpc ? ddCalib_tpc : ddCalib, 0, Lifetime::Timeframe); + + std::string nameSpec = "tof-calibinfo-reader"; + if (toftpc) { + nameSpec += "-tpc"; + } + if (ninstances > 1) { + nameSpec += fmt::format("-{:d}", instance); + } + + return DataProcessorSpec{ + nameSpec, + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<CalibInfoReader>(instance, ninstances, filename)}, + Options{{"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/ClusterReaderSpec.cxx b/Detectors/TOF/workflowIO/src/ClusterReaderSpec.cxx new file mode 100644 index 0000000000000..3fd59bc940109 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/ClusterReaderSpec.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TOFWorkflowIO/ClusterReaderSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::tof; + +namespace o2 +{ +namespace tof +{ + +void ClusterReader::init(InitContext& ic) +{ + LOG(INFO) << "Init Cluster reader!"; + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("tof-cluster-infile")); + connectTree(mFileName); +} + +void ClusterReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mClustersPtr->size() << " TOF clusters at entry " << ent; + + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe}, mClusters); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe}, mLabels); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void ClusterReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("o2sim")); + assert(mTree); + mTree->SetBranchAddress("TOFCluster", &mClustersPtr); + if (mUseMC) { + mTree->SetBranchAddress("TOFClusterMCTruth", &mLabelsPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getClusterReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "tof-cluster-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<ClusterReader>(useMC)}, + Options{ + {"tof-cluster-infile", VariantType::String, "tofclusters.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/DigitReaderSpec.cxx b/Detectors/TOF/workflowIO/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..fae339c797495 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/DigitReaderSpec.cxx @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include <vector> + +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "TOFWorkflowIO/DigitReaderSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::tof; + +namespace o2 +{ +namespace tof +{ + +void DigitReader::init(InitContext& ic) +{ + LOG(INFO) << "Init Digit reader!"; + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("tof-digit-infile")); + mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); + if (!mFile->IsOpen()) { + LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; + mState = 0; + return; + } + mState = 1; +} + +void DigitReader::run(ProcessingContext& pc) +{ + if (mState != 1) { + return; + } + + std::unique_ptr<TTree> treeDig((TTree*)mFile->Get("o2sim")); + + if (treeDig) { + treeDig->SetBranchAddress("TOFDigit", &mPdigits); + treeDig->SetBranchAddress("TOFReadoutWindow", &mProw); + treeDig->SetBranchAddress("TOFPatterns", &mPpatterns); + + if (mUseMC) { + treeDig->SetBranchAddress("TOFDigitMCTruth", &mPlabels); + } + + treeDig->GetEntry(mCurrentEntry); + + // add digits loaded in the output snapshot + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe}, mDigits); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe}, mRow); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe}, mPatterns); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "DIGITSMCTR", 0, Lifetime::Timeframe}, mLabels); + } + + static o2::parameters::GRPObject::ROMode roMode = o2::parameters::GRPObject::CONTINUOUS; + + LOG(DEBUG) << "TOF: Sending ROMode= " << roMode << " to GRPUpdater"; + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "ROMode", 0, Lifetime::Timeframe}, roMode); + } else { + LOG(ERROR) << "Cannot read the TOF digits !"; + return; + } + + mCurrentEntry++; + + if (mCurrentEntry >= treeDig->GetEntries()) { + mState = 2; + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + pc.services().get<ControlService>().endOfStream(); + } +} + +DataProcessorSpec getDigitReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, "DIGITSMCTR", 0, Lifetime::Timeframe); + } + outputs.emplace_back(o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTOF, "ROMode", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tof-digit-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, + Options{ + {"tof-digit-infile", VariantType::String, "tofdigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/TOFCalClusInfoWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFCalClusInfoWriterSpec.cxx new file mode 100644 index 0000000000000..08b88d1354e25 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/TOFCalClusInfoWriterSpec.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFCalClusInfoWriterSpec.cxx + +#include "TOFWorkflowIO/TOFCalClusInfoWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsTOF/CalibInfoCluster.h" +#include "DataFormatsTOF/CosmicInfo.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using OutputType = std::vector<o2::tof::CalibInfoCluster>; +using OutputCosmicType = std::vector<o2::tof::CosmicInfo>; +using OutputTrackType = std::vector<o2::tof::CalibInfoTrackCl>; +using OutputTrackSizeType = std::vector<int>; +using namespace o2::header; + +DataProcessorSpec getTOFCalClusInfoWriterSpec(bool isCosmics) +{ + // Spectators for logging + auto logger = [](OutputType const& indata) { + LOG(DEBUG) << "RECEIVED CLUS CAL INFO SIZE " << indata.size(); + }; + auto loggerCosmics = [](OutputCosmicType const& indata) { + LOG(DEBUG) << "RECEIVED COSMICS INFO SIZE " << indata.size(); + }; + auto loggerTracks = [](OutputTrackType const& indata) { + LOG(DEBUG) << "RECEIVED COSMICS TRACK CLUSTERS INFO SIZE " << indata.size(); + }; + auto loggerTracksSize = [](OutputTrackSizeType const& indata) { + LOG(DEBUG) << "RECEIVED COSMICS TRACK INFO SIZE " << indata.size(); + }; + + return MakeRootTreeWriterSpec("TOFCalClusInfoWriter", + "tofclusCalInfo.root", + "o2sim", + BranchDefinition<OutputType>{InputSpec{"clusters", gDataOriginTOF, "INFOCALCLUS", 0}, + "TOFClusterCalInfo", + "tofclusters-branch-name", + 1, + logger}, + BranchDefinition<OutputCosmicType>{InputSpec{"cosmics", gDataOriginTOF, "INFOCOSMICS", 0}, + "TOFCosmics", + "tofcosmics-branch-name", + (isCosmics ? 1 : 0), + loggerCosmics}, + BranchDefinition<OutputTrackType>{InputSpec{"tracks", gDataOriginTOF, "INFOTRACKCOS", 0}, + "TOFTracks", + "toftracks-branch-name", + (isCosmics ? 1 : 0), + loggerTracks}, + BranchDefinition<OutputTrackSizeType>{InputSpec{"tracksize", gDataOriginTOF, "INFOTRACKSIZE", 0}, + "TOFTracksSize", + "toftrackssize-branch-name", + (isCosmics ? 1 : 0), + loggerTracksSize})(); +} +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/TOFCalibWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFCalibWriterSpec.cxx new file mode 100644 index 0000000000000..b89f15d3cbad5 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/TOFCalibWriterSpec.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFCalibWriterSpec.cxx + +#include "TOFWorkflowIO/TOFCalibWriterSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Headers/DataHeader.h" +#include <SimulationDataFormat/MCCompLabel.h> +#include <SimulationDataFormat/MCTruthContainer.h> +#include "TTree.h" +#include "TBranch.h" +#include "TFile.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/Cluster.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using CalibInfosType = std::vector<o2::dataformats::CalibInfoTOF>; +DataProcessorSpec getTOFCalibWriterSpec(const char* outdef, bool toftpc) +{ + // A spectator for logging + auto logger = [](CalibInfosType const& indata) { + LOG(INFO) << "RECEIVED MATCHED SIZE " << indata.size(); + }; + o2::header::DataDescription ddCalib{"CALIBDATA"}; + return MakeRootTreeWriterSpec("TOFCalibWriter", + outdef, + "calibTOF", + BranchDefinition<CalibInfosType>{InputSpec{"input", o2::header::gDataOriginTOF, ddCalib, 0}, + "TOFCalibInfo", + "calibinfo-branch-name", + 1, + logger})(); +} + +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflow/src/TOFClusterWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFClusterWriterSpec.cxx similarity index 79% rename from Detectors/TOF/workflow/src/TOFClusterWriterSpec.cxx rename to Detectors/TOF/workflowIO/src/TOFClusterWriterSpec.cxx index 9141c68c7ee59..ec0ae777dc5da 100644 --- a/Detectors/TOF/workflow/src/TOFClusterWriterSpec.cxx +++ b/Detectors/TOF/workflowIO/src/TOFClusterWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ /// @file TODClusterWriterSpec.cxx -#include "TOFWorkflowUtils/TOFClusterWriterSpec.h" +#include "TOFWorkflowIO/TOFClusterWriterSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -32,10 +33,10 @@ DataProcessorSpec getTOFClusterWriterSpec(bool useMC) { // Spectators for logging auto logger = [](OutputType const& indata) { - LOG(INFO) << "RECEIVED CLUSTERS SIZE " << indata.size(); + LOG(DEBUG) << "RECEIVED CLUSTERS SIZE " << indata.size(); }; auto loggerMCLabels = [](LabelsType const& labeldata) { - LOG(INFO) << "TOF GOT " << labeldata.getNElements() << " LABELS "; + LOG(DEBUG) << "TOF GOT " << labeldata.getNElements() << " LABELS "; }; return MakeRootTreeWriterSpec("TOFClusterWriter", "tofclusters.root", diff --git a/Detectors/TOF/workflow/src/TOFDigitWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFDigitWriterSpec.cxx similarity index 92% rename from Detectors/TOF/workflow/src/TOFDigitWriterSpec.cxx rename to Detectors/TOF/workflowIO/src/TOFDigitWriterSpec.cxx index 24a81ffaa1793..a11f7535e3225 100644 --- a/Detectors/TOF/workflow/src/TOFDigitWriterSpec.cxx +++ b/Detectors/TOF/workflowIO/src/TOFDigitWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ /// @brief Processor spec for a ROOT file writer for TOF digits -#include "TOFWorkflowUtils/TOFDigitWriterSpec.h" +#include "TOFWorkflowIO/TOFDigitWriterSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -26,7 +27,7 @@ template <typename T> using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; using OutputType = std::vector<o2::tof::Digit>; using ReadoutWinType = std::vector<o2::tof::ReadoutWindowData>; -using PatternType = std::vector<uint32_t>; +using PatternType = std::vector<uint8_t>; using ErrorType = std::vector<uint64_t>; using LabelsType = std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>; using HeaderType = o2::tof::DigitHeader; diff --git a/Detectors/TOF/workflowIO/src/TOFMatchedReaderSpec.cxx b/Detectors/TOF/workflowIO/src/TOFMatchedReaderSpec.cxx new file mode 100644 index 0000000000000..3ac1d3bccd8c6 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/TOFMatchedReaderSpec.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatchedReaderSpec.cxx + +#include <vector> + +#include "TTree.h" +#include "TFile.h" + +#include "TOFWorkflowIO/TOFMatchedReaderSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Headers/DataHeader.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/MatchingType.h" +#include "CommonUtils/StringUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ +o2::header::DataDescription ddMatchInfo{"MTC_ITSTPC"}, ddMatchInfo_tpc{"MTC_TPC"}, + ddMCMatchTOF{"MCMATCHTOF"}, ddMCMatchTOF_tpc{"MCMATCHTOF_TPC"}; + +void TOFMatchedReader::init(InitContext& ic) +{ + // get the option from the init context + LOG(INFO) << "Init TOF matching info reader!"; + mInFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("tof-matched-infile")); + mInTreeName = ic.options().get<std::string>("treename"); + connectTree(mInFileName); +} + +void TOFMatchedReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mInTreeName.c_str())); + assert(mTree); + mTree->SetBranchAddress("TOFMatchInfo", &mMatchesPtr); + if (mReadTracks) { + if (!mTree->GetBranch("TPCTOFTracks")) { + throw std::runtime_error("TPC-TOF tracks are requested but not found in the tree"); + } + mTree->SetBranchAddress("TPCTOFTracks", &mTracksPtr); + } + if (mUseMC) { + mTree->SetBranchAddress("MatchTOFMCTruth", &mLabelTOFPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +void TOFMatchedReader::run(ProcessingContext& pc) +{ + auto currEntry = mTree->GetReadEntry() + 1; + assert(currEntry < mTree->GetEntries()); // this should not happen + mTree->GetEntry(currEntry); + LOG(INFO) << "Pushing " << mMatches.size() << " TOF matchings at entry " << currEntry; + + uint32_t tpcMatchSS = o2::globaltracking::getSubSpec(mSubSpecStrict && mTPCMatch ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, mTPCMatch ? ddMatchInfo_tpc : ddMatchInfo, tpcMatchSS, Lifetime::Timeframe}, mMatches); + if (mReadTracks && mTPCMatch) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "TOFTRACKS_TPC", tpcMatchSS, Lifetime::Timeframe}, mTracks); + } + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, mTPCMatch ? ddMCMatchTOF_tpc : ddMCMatchTOF, tpcMatchSS, Lifetime::Timeframe}, mLabelTOF); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +DataProcessorSpec getTOFMatchedReaderSpec(bool useMC, bool tpcmatch, bool readTracks, bool subSpecStrict) +{ + std::vector<OutputSpec> outputs; + uint32_t tpcMatchSS = o2::globaltracking::getSubSpec(subSpecStrict && tpcmatch ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + outputs.emplace_back(o2::header::gDataOriginTOF, tpcmatch ? ddMatchInfo_tpc : ddMatchInfo, tpcMatchSS, Lifetime::Timeframe); + if (tpcmatch && readTracks) { + outputs.emplace_back(o2::header::gDataOriginTOF, "TOFTRACKS_TPC", tpcMatchSS, Lifetime::Timeframe); + } + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTOF, tpcmatch ? ddMCMatchTOF_tpc : ddMCMatchTOF, tpcMatchSS, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + o2::utils::Str::concat_string("TOFMatchedReader_", tpcmatch ? "tpc" : "glo"), + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TOFMatchedReader>(useMC, tpcmatch, readTracks, subSpecStrict)}, + Options{ + {"tof-matched-infile", VariantType::String, tpcmatch ? "o2match_tof_tpc.root" : "o2match_tof_itstpc.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "matchTOF", {"Name of top-level TTree"}}, + }}; +} +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflowIO/src/TOFMatchedWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFMatchedWriterSpec.cxx new file mode 100644 index 0000000000000..ecfd81779ac30 --- /dev/null +++ b/Detectors/TOF/workflowIO/src/TOFMatchedWriterSpec.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TOFMatchedWriterSpec.cxx + +#include "TOFWorkflowIO/TOFMatchedWriterSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Headers/DataHeader.h" +#include <SimulationDataFormat/MCCompLabel.h> +#include <SimulationDataFormat/MCTruthContainer.h> +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/MatchingType.h" +#include "ReconstructionDataFormats/TrackTPCTOF.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsTOF/CalibInfoTOF.h" +#include "DataFormatsTOF/Cluster.h" +#include "CommonUtils/StringUtils.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using MatchInfo = std::vector<o2::dataformats::MatchInfoTOF>; +using TrackInfo = std::vector<o2::dataformats::TrackTPCTOF>; +using LabelsType = std::vector<o2::MCCompLabel>; +using namespace o2::header; + +DataProcessorSpec getTOFMatchedWriterSpec(bool useMC, const char* outdef, bool writeTracks, int mode, bool strict) +{ + // spectators for logging + auto loggerMatched = [](MatchInfo const& indata) { + LOG(INFO) << "RECEIVED MATCHED SIZE " << indata.size(); + }; + auto loggerTofLabels = [](LabelsType const& labeltof) { + LOG(INFO) << "TOF LABELS GOT " << labeltof.size() << " LABELS "; + }; + // o2::header::DataDescription ddMatchInfo{"MTC_ITSTPC"}, ddMatchInfo_tpc{"MTC_TPC"}, + // ddMCMatchTOF{"MCMTC_ITSTPC"}, ddMCMatchTOF_tpc{"MCMTC_TPC"}; + + o2::header::DataDescription ddMatchInfo[4] = {{"MTC_TPC"}, {"MTC_ITSTPC"}, {"MTC_TPCTRD"}, {"MTC_ITSTPCTRD"}}; + o2::header::DataDescription ddMCMatchTOF[4] = {{"MCMTC_TPC"}, {"MCMTC_ITSTPC"}, {"MCMTC_TPCTRD"}, {"MCMTC_ITSTPCTRD"}}; + + uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + + const char* match_name[4] = {"TOFMatchedWriter_TPC", "TOFMatchedWriter_ITSTPC", "TOFMatchedWriter_TPCTRD", "TOFMatchedWriter_ITSTPCTRD"}; + const char* match_name_strict[4] = {"TOFMatchedWriter_TPC_str", "TOFMatchedWriter_ITSTPC_str", "TOFMatchedWriter_TPCTRD_str", "TOFMatchedWriter_ITSTPCTRD_str"}; + + const char* taskName = match_name[mode]; + if (strict) { + taskName = match_name_strict[mode]; + } + + return MakeRootTreeWriterSpec(taskName, + outdef, + "matchTOF", + BranchDefinition<MatchInfo>{InputSpec{"tofmatching", gDataOriginTOF, ddMatchInfo[mode], ss}, + "TOFMatchInfo", + "TOFMatchInfo-branch-name", + 1, + loggerMatched}, + BranchDefinition<TrackInfo>{InputSpec{"tpctofTracks", gDataOriginTOF, "TOFTRACKS_TPC", ss}, + "TPCTOFTracks", + "TPCTOFTracks-branch-name", + writeTracks}, + BranchDefinition<LabelsType>{InputSpec{"matchtoflabels", gDataOriginTOF, ddMCMatchTOF[mode], ss}, + "MatchTOFMCTruth", + "MatchTOFMCTruth-branch-name", + (useMC ? 1 : 0), // one branch if mc labels enabled + loggerTofLabels})(); +} +} // namespace tof +} // namespace o2 diff --git a/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx b/Detectors/TOF/workflowIO/src/TOFRawWriterSpec.cxx similarity index 82% rename from Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx rename to Detectors/TOF/workflowIO/src/TOFRawWriterSpec.cxx index 832e18b4995f2..5e7e6f90df6d5 100644 --- a/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx +++ b/Detectors/TOF/workflowIO/src/TOFRawWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,14 +11,14 @@ /// @file TODRawWriterSpec.cxx -#include "TOFWorkflowUtils/TOFRawWriterSpec.h" +#include "TOFWorkflowIO/TOFRawWriterSpec.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/Logger.h" #include "DetectorsRaw/HBFUtils.h" #include "TOFBase/Geo.h" #include "CommonUtils/StringUtils.h" -#include "TSystem.h" +#include <filesystem> #include <fstream> #include <iostream> #include <iomanip> @@ -34,11 +35,12 @@ void RawWriter::init(InitContext& ic) // get the option from the init context mOutFileName = ic.options().get<std::string>("tof-raw-outfile"); mOutDirName = ic.options().get<std::string>("tof-raw-outdir"); - mFileFor = ic.options().get<std::string>("tof-raw-file-for"); + mFileFor = ic.options().get<std::string>("file-for"); LOG(INFO) << "Raw output file: " << mOutFileName.c_str(); - if (gSystem->AccessPathName(mOutDirName.c_str())) { - if (gSystem->mkdir(mOutDirName.c_str(), kTRUE)) { + // if needed, create output directory + if (!std::filesystem::exists(mOutDirName)) { + if (!std::filesystem::create_directories(mOutDirName)) { LOG(FATAL) << "could not create output directory " << mOutDirName; } else { LOG(INFO) << "created output directory " << mOutDirName; @@ -99,7 +101,7 @@ void RawWriter::run(ProcessingContext& pc) } // create configuration file for rawreader - encoder.getWriter().writeConfFile("TOF", "RAWDATA", o2::utils::concat_string(mOutDirName, '/', "TOFraw.cfg")); + encoder.getWriter().writeConfFile("TOF", "RAWDATA", o2::utils::Str::concat_string(mOutDirName, '/', "TOFraw.cfg")); encoder.close(); } @@ -117,7 +119,7 @@ DataProcessorSpec getTOFRawWriterSpec() Options{ {"tof-raw-outfile", VariantType::String, "tof.raw", {"Name of the output file"}}, {"tof-raw-outdir", VariantType::String, ".", {"Name of the output dir"}}, - {"tof-raw-file-for", VariantType::String, "cru", {"Single file per: all,cru,link"}}}}; + {"file-for", VariantType::String, "cru", {"Single file per: all,cru,link"}}}}; } } // namespace tof } // namespace o2 diff --git a/Detectors/TPC/CMakeLists.txt b/Detectors/TPC/CMakeLists.txt index ccc16941d64b3..bdbca321a978b 100644 --- a/Detectors/TPC/CMakeLists.txt +++ b/Detectors/TPC/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(reconstruction) @@ -15,3 +16,4 @@ add_subdirectory(simulation) add_subdirectory(monitor) add_subdirectory(workflow) add_subdirectory(qc) +add_subdirectory(spacecharge) diff --git a/Detectors/TPC/README.md b/Detectors/TPC/README.md index bbef804c01a3b..4f315a79416ff 100644 --- a/Detectors/TPC/README.md +++ b/Detectors/TPC/README.md @@ -8,4 +8,5 @@ This is a top page for the TPC detector documentation. <!-- doxy * \subpage refTPCworkflow +* \subpage refTPCsimulation /doxy --> diff --git a/Detectors/TPC/base/CMakeLists.txt b/Detectors/TPC/base/CMakeLists.txt index 14a22d5517194..281c7fb0cd88c 100644 --- a/Detectors/TPC/base/CMakeLists.txt +++ b/Detectors/TPC/base/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TPCBase SOURCES src/CalArray.cxx diff --git a/Detectors/TPC/base/include/TPCBase/CDBInterface.h b/Detectors/TPC/base/include/TPCBase/CDBInterface.h index 476ca0b78a025..aaa972894ea53 100644 --- a/Detectors/TPC/base/include/TPCBase/CDBInterface.h +++ b/Detectors/TPC/base/include/TPCBase/CDBInterface.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,6 +40,7 @@ enum class CDBType { CalPedestal, ///< Pedestal calibration CalNoise, ///< Noise calibration CalPulser, ///< Pulser calibration + CalCE, ///< Laser CE calibration CalPadGainFull, ///< Full pad gain calibration CalPadGainResidual, ///< ResidualpPad gain calibration (e.g. from tracks) /// @@ -59,6 +61,7 @@ const std::unordered_map<CDBType, std::string> CDBTypeMap{ {CDBType::CalPedestal, "TPC/Calib/Pedestal"}, {CDBType::CalNoise, "TPC/Calib/Noise"}, {CDBType::CalPulser, "TPC/Calib/Pulser"}, + {CDBType::CalCE, "TPC/Calib/CE"}, {CDBType::CalPadGainFull, "TPC/Calib/PadGainFull"}, {CDBType::CalPadGainResidual, "TPC/Calib/PadGainResidual"}, // @@ -147,6 +150,17 @@ class CDBInterface /// \return GEM parameters const ParameterGEM& getParameterGEM(); + /// Return a CalPad object form the CCDB + /// Deprecated + const CalPad& getCalPad(const std::string_view path); + + /// Return any templated object + /// + /// The function returns the object stored at the given path, timestamp and metaData in the CCDB + /// \return object + template <typename T> + T& getSpecificObjectFromCDB(const std::string_view path, long timestamp = -1, const std::map<std::string, std::string>& metaData = std::map<std::string, std::string>()); + /// Set noise and pedestal object from file /// /// This assumes that the objects are stored under the name @@ -229,6 +243,25 @@ inline T& CDBInterface::getObjectFromCDB(std::string_view path) return *object; } +/// Get a CalPad object stored in templated formats from the CCDB. +/// @tparam T +/// @param path +/// @param timestamp +/// @param metaData +/// @return The object from the CCDB, ownership is transferred to the caller. +/// @todo Consider removing in favour of calling directly the manager::get method. +template <typename T> +inline T& CDBInterface::getSpecificObjectFromCDB(std::string_view path, long timestamp, const std::map<std::string, std::string>& metaData) +{ + static auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + auto* object = cdb.getSpecific<T>(path.data(), timestamp, metaData); + return *object; +} + +template CalPad& CDBInterface::getSpecificObjectFromCDB(const std::string_view path, long timestamp, const std::map<std::string, std::string>& metaData); +template std::vector<CalPad>& CDBInterface::getSpecificObjectFromCDB(const std::string_view path, long timestamp, const std::map<std::string, std::string>& metaData); +template std::unordered_map<std::string, o2::tpc::CalPad>& CDBInterface::getSpecificObjectFromCDB(const std::string_view path, long timestamp, const std::map<std::string, std::string>& metaData); + /// \class CDBStorage /// Simple interface to store TPC CCDB types. Also provide interface functions to upload data from /// a file. @@ -260,7 +293,7 @@ class CDBStorage void setJIRA(std::string_view jira) { - mMetaData["Intervention"] = jira; + mMetaData["JIRA"] = jira; } void setComment(std::string_view comment) @@ -287,7 +320,7 @@ class CDBStorage void uploadNoiseAndPedestal(std::string_view fileName, long first = -1, long last = -1); void uploadGainMap(std::string_view fileName, bool isFull = true, long first = -1, long last = -1); - void uploadPulserData(std::string_view fileName, long first = -1, long last = -1); + void uploadPulserOrCEData(CDBType type, std::string_view fileName, long first = -1, long last = -1); private: bool checkMetaData(MetaData_t metaData) const; diff --git a/Detectors/TPC/base/include/TPCBase/CRU.h b/Detectors/TPC/base/include/TPCBase/CRU.h index 55e6224512a68..d9e6f2b7f0368 100644 --- a/Detectors/TPC/base/include/TPCBase/CRU.h +++ b/Detectors/TPC/base/include/TPCBase/CRU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/CalArray.h b/Detectors/TPC/base/include/TPCBase/CalArray.h index 6cab619159606..70779a11b6067 100644 --- a/Detectors/TPC/base/include/TPCBase/CalArray.h +++ b/Detectors/TPC/base/include/TPCBase/CalArray.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,6 @@ #ifndef ALICEO2_TPC_CALARRAY_H_ #define ALICEO2_TPC_CALARRAY_H_ -#include <Vc/Vc> #include <memory> #include <vector> #include <string> @@ -21,7 +21,7 @@ #include "TPCBase/Mapper.h" #ifndef GPUCA_ALIGPUCODE -#include "FairLogger.h" +#include "Framework/Logger.h" #include <boost/format.hpp> #endif @@ -253,7 +253,7 @@ inline const CalArray<T>& CalArray<T>::operator/=(const CalArray<T>& other) mData[i] /= other.getValue(i); } else { mData[i] = 0; - LOG(ERROR) << "Division by 0 detected! Value was set to 0."; + LOG(DEBUG) << "Division by 0 detected! Value was set to 0."; } } return *this; diff --git a/Detectors/TPC/base/include/TPCBase/CalDet.h b/Detectors/TPC/base/include/TPCBase/CalDet.h index f00794beb08a7..2be4f14c73ed6 100644 --- a/Detectors/TPC/base/include/TPCBase/CalDet.h +++ b/Detectors/TPC/base/include/TPCBase/CalDet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -64,11 +65,14 @@ class CalDet /// /// const T getValue(const int sec, const int globalPadInSector) const; + void setValue(const int sec, const int globalPadInSector, const T& value); + void setValue(const int sec, const int rowInSector, const int padInRow, const T& value); /// \todo return value of T& not possible if a default value should be returned, e.g. T{}: /// warning: returning reference to temporary const T getValue(const ROC roc, const size_t row, const size_t pad) const; const T getValue(const CRU cru, const size_t row, const size_t pad) const; + const T getValue(const Sector sec, const int rowInSector, const int padInRow) const; void setName(const std::string_view name) { mName = name.data(); } const std::string& getName() const { return mName; } @@ -140,7 +144,8 @@ inline const T CalDet<T>::getValue(const ROC roc, const size_t row, const size_t break; } case PadSubset::Region: { - return T{}; + const auto globalRow = roc.isOROC() ? mappedRow + mapper.getNumberOfRowsROC(ROC(0)) : mappedRow; + return mData[Mapper::REGION[globalRow] + roc.getSector() * Mapper::NREGIONS].getValue(Mapper::OFFSETCRUGLOBAL[globalRow] + mappedPad); break; } } @@ -182,6 +187,48 @@ inline const T CalDet<T>::getValue(const CRU cru, const size_t row, const size_t return T{}; } +template <class T> +inline void CalDet<T>::setValue(const int sec, const int globalPadInSector, const T& value) +{ + assert(mPadSubset == PadSubset::ROC); + int roc = sec; + int padInROC = globalPadInSector; + const int padsInIROC = Mapper::getPadsInIROC(); + if (globalPadInSector >= padsInIROC) { + roc += Mapper::getNumberOfIROCs(); + padInROC -= padsInIROC; + } + mData[roc].setValue(padInROC, value); +} + +template <class T> +inline void CalDet<T>::setValue(const int sec, const int rowInSector, const int padInRow, const T& value) +{ + assert(mPadSubset == PadSubset::ROC); + int roc = sec; + int rowInROC = rowInSector; + const int rowsInIROC = 63; + if (rowInSector >= rowsInIROC) { + roc += Mapper::getNumberOfIROCs(); + rowInROC -= rowsInIROC; + } + mData[roc].setValue(rowInROC, padInRow, value); +} + +template <class T> +inline const T CalDet<T>::getValue(const Sector sec, const int rowInSector, const int padInRow) const +{ + assert(mPadSubset == PadSubset::ROC); + int roc = sec; + int rowInROC = rowInSector; + const int rowsInIROC = 63; + if (rowInSector >= rowsInIROC) { + roc += Mapper::getNumberOfIROCs(); + rowInROC -= rowsInIROC; + } + return mData[roc].getValue(rowInROC, padInRow); +} + #ifndef GPUCA_ALIGPUCODE // hide from GPU standalone compilation //______________________________________________________________________________ diff --git a/Detectors/TPC/base/include/TPCBase/ContainerFactory.h b/Detectors/TPC/base/include/TPCBase/ContainerFactory.h index 11f98ac18a595..fc03683117af2 100644 --- a/Detectors/TPC/base/include/TPCBase/ContainerFactory.h +++ b/Detectors/TPC/base/include/TPCBase/ContainerFactory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/DigitPos.h b/Detectors/TPC/base/include/TPCBase/DigitPos.h index 318f954e04a81..0d8adcc646fd6 100644 --- a/Detectors/TPC/base/include/TPCBase/DigitPos.h +++ b/Detectors/TPC/base/include/TPCBase/DigitPos.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/FECInfo.h b/Detectors/TPC/base/include/TPCBase/FECInfo.h index 72af837b31ca1..250ab514660dc 100644 --- a/Detectors/TPC/base/include/TPCBase/FECInfo.h +++ b/Detectors/TPC/base/include/TPCBase/FECInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/Mapper.h b/Detectors/TPC/base/include/TPCBase/Mapper.h index c8f5cd7ca8729..67ebed1ede81c 100644 --- a/Detectors/TPC/base/include/TPCBase/Mapper.h +++ b/Detectors/TPC/base/include/TPCBase/Mapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -57,6 +58,19 @@ class Mapper return mMapPadOffsetPerRow[globalPadPosition.getRow()] + globalPadPosition.getPad(); } + /// \return returns the global pad number for given local pad row and pad + /// \param lrow ungrouped local row in a region + /// \param pad ungrouped pad in row + GlobalPadNumber static getGlobalPadNumber(const unsigned int lrow, const unsigned int pad, const unsigned int region) { return GLOBALPADOFFSET[region] + OFFSETCRULOCAL[region][lrow] + pad; } + + /// \param row global pad row + /// \param pad pad in row + /// \return returns local pad number in region + static unsigned int getLocalPadNumber(const unsigned int row, const unsigned int pad) { return OFFSETCRUGLOBAL[row] + pad; } + + /// \param row global pad row + static unsigned int getLocalRowFromGlobalRow(const unsigned int row) { return row - ROWOFFSET[REGION[row]]; } + /// return the cru number from sector and global pad number /// \param sec sector /// \param globalPad global pad number in sector @@ -412,8 +426,10 @@ class Mapper return getPadsInOROC(); } + const std::vector<float>& getTraceLengthsIROC() const { return mTraceLengthsIROC; } + const std::vector<float>& getTraceLengthsOROC() const { return mTraceLengthsOROC; } + // bool loadFECInfo(); - // bool loadTraceLengh(); // bool loadPositions(); // c++11 feature don't work with root dictionary :( @@ -486,6 +502,70 @@ class Mapper float(double(pos.X()) * sn + double(pos.Y() * cs))); } + static constexpr unsigned int NSECTORS{36}; ///< total number of sectors in the TPC + static constexpr unsigned int NREGIONS{10}; ///< total number of regions in one sector + static constexpr unsigned int PADROWS{152}; ///< total number of pad rows + static constexpr unsigned int PADSPERREGION[NREGIONS]{1200, 1200, 1440, 1440, 1440, 1440, 1600, 1600, 1600, 1600}; ///< number of pads per CRU + static constexpr unsigned int GLOBALPADOFFSET[NREGIONS]{0, 1200, 2400, 3840, 5280, 6720, 8160, 9760, 11360, 12960}; ///< offset of number of pads for region + static constexpr unsigned int ROWSPERREGION[NREGIONS]{17, 15, 16, 15, 18, 16, 16, 14, 13, 12}; ///< number of pad rows for region + static constexpr unsigned int ROWOFFSET[NREGIONS]{0, 17, 32, 48, 63, 81, 97, 113, 127, 140}; ///< offset to calculate local row from global row + static constexpr float REGIONAREA[NREGIONS]{374.4f, 378.f, 453.6f, 470.88f, 864.f, 864.f, 1167.36f, 1128.96f, 1449.6f, 1456.8f}; ///< volume of each region in cm^2 + static constexpr float PADAREA[NREGIONS]{1 / 0.312f, 1 / 0.315f, 1 / 0.315f, 1 / 0.327f, 1 / 0.6f, 1 / 0.6f, 1 / 0.7296f, 1 / 0.7056f, 1 / 0.906f, 1 / 0.9105f}; ///< inverse size of the pad area padwidth*padLength + static constexpr unsigned REGION[PADROWS] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; ///< region for global pad row + const inline static std::vector<unsigned int> ADDITIONALPADSPERROW[NREGIONS]{ + {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5}, // region 0 + {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}, // region 1 + {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4}, // region 2 + {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}, // region 3 + {0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4}, // region 4 + {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4}, // region 5 + {0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6}, // region 6 + {0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}, // region 7 + {0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5}, // region 8 + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5} // region 9 + }; ///< additional pads per row compared to first row + const inline static std::vector<unsigned int> OFFSETCRULOCAL[NREGIONS]{ + {0, 66, 132, 198, 266, 334, 402, 472, 542, 612, 684, 756, 828, 902, 976, 1050, 1124}, // region 0 + {0, 76, 152, 228, 306, 384, 462, 542, 622, 702, 784, 866, 948, 1032, 1116}, // region 1 + {0, 86, 172, 258, 346, 434, 522, 612, 702, 792, 882, 974, 1066, 1158, 1252, 1346}, // region 2 + {0, 92, 184, 276, 370, 464, 558, 654, 750, 846, 944, 1042, 1140, 1240, 1340}, // region 3 + {0, 76, 152, 228, 304, 382, 460, 538, 618, 698, 778, 858, 940, 1022, 1104, 1188, 1272, 1356}, // region 4 + {0, 86, 172, 258, 346, 434, 522, 612, 702, 792, 882, 974, 1066, 1158, 1252, 1346}, // region 5 + {0, 94, 190, 286, 382, 480, 578, 676, 776, 876, 978, 1080, 1182, 1286, 1390, 1494}, // region 6 + {0, 110, 220, 332, 444, 556, 670, 784, 898, 1014, 1130, 1246, 1364, 1482}, // region 7 + {0, 118, 236, 356, 476, 598, 720, 844, 968, 1092, 1218, 1344, 1472}, // region 8 + {0, 128, 258, 388, 520, 652, 784, 918, 1052, 1188, 1324, 1462} // region 9 + }; ///< row offset in cru for given local pad row + const inline static std::vector<unsigned int> PADSPERROW[NREGIONS]{ + {66, 66, 66, 68, 68, 68, 70, 70, 70, 72, 72, 72, 74, 74, 74, 74, 76}, // region 0 + {76, 76, 76, 78, 78, 78, 80, 80, 80, 82, 82, 82, 84, 84, 84}, // region 1 + {86, 86, 86, 88, 88, 88, 90, 90, 90, 90, 92, 92, 92, 94, 94, 94}, // region 2 + {92, 92, 92, 94, 94, 94, 96, 96, 96, 98, 98, 98, 100, 100, 100}, // region 3 + {76, 76, 76, 76, 78, 78, 78, 80, 80, 80, 80, 82, 82, 82, 84, 84, 84, 84}, // region 4 + {86, 86, 86, 88, 88, 88, 90, 90, 90, 90, 92, 92, 92, 94, 94, 94}, // region 5 + {94, 96, 96, 96, 98, 98, 98, 100, 100, 102, 102, 102, 104, 104, 104, 106}, // region 6 + {110, 110, 112, 112, 112, 114, 114, 114, 116, 116, 116, 118, 118, 118}, // region 7 + {118, 118, 120, 120, 122, 122, 124, 124, 124, 126, 126, 128, 128}, // region 8 + {128, 130, 130, 132, 132, 132, 134, 134, 136, 136, 138, 138} // region 9 + }; ///< number of pads per row in region + static constexpr unsigned int OFFSETCRUGLOBAL[PADROWS]{ + 0, 66, 132, 198, 266, 334, 402, 472, 542, 612, 684, 756, 828, 902, 976, 1050, 1124, // region 0 + 0, 76, 152, 228, 306, 384, 462, 542, 622, 702, 784, 866, 948, 1032, 1116, // region 1 + 0, 86, 172, 258, 346, 434, 522, 612, 702, 792, 882, 974, 1066, 1158, 1252, 1346, // region 2 + 0, 92, 184, 276, 370, 464, 558, 654, 750, 846, 944, 1042, 1140, 1240, 1340, // region 3 + 0, 76, 152, 228, 304, 382, 460, 538, 618, 698, 778, 858, 940, 1022, 1104, 1188, 1272, 1356, // region 4 + 0, 86, 172, 258, 346, 434, 522, 612, 702, 792, 882, 974, 1066, 1158, 1252, 1346, // region 5 + 0, 94, 190, 286, 382, 480, 578, 676, 776, 876, 978, 1080, 1182, 1286, 1390, 1494, // region 6 + 0, 110, 220, 332, 444, 556, 670, 784, 898, 1014, 1130, 1246, 1364, 1482, // region 7 + 0, 118, 236, 356, 476, 598, 720, 844, 968, 1092, 1218, 1344, 1472, // region 8 + 0, 128, 258, 388, 520, 652, 784, 918, 1052, 1188, 1324, 1462 // region 9 + }; ///< row offset in cru for given global pad row + private: Mapper(const std::string& mappingDir); // use old c++03 due to root @@ -493,6 +573,11 @@ class Mapper void operator=(const Mapper&) {} void load(const std::string& mappingDir); + + /// load trace lengths + void loadTraceLengths(std::string_view mappingDir = ""); + void setTraceLengths(std::string_view inputFile, std::vector<float>& length); + void initPadRegionsAndPartitions(); bool readMappingFile(std::string file); @@ -505,6 +590,9 @@ class Mapper static constexpr unsigned short mNumberOfPadRowsIROC{63}; ///< number of pad rows in IROC static constexpr unsigned short mNumberOfPadRowsOROC{89}; ///< number of pad rows in IROC + std::vector<float> mTraceLengthsIROC; ///< trace lengths IROC + std::vector<float> mTraceLengthsOROC; ///< trace lengths OROC + // ===| lookup tables |======================================================= // static constexpr std::array<double, SECTORSPERSIDE> SinsPerSector; ///< Sinus values of sectors // static constexpr std::array<double, SECTORSPERSIDE> CosinsPerSector; ///< Cosinus values of sectors diff --git a/Detectors/TPC/base/include/TPCBase/ModelGEM.h b/Detectors/TPC/base/include/TPCBase/ModelGEM.h index 4bb2aec2413d5..f832acbfc0a70 100644 --- a/Detectors/TPC/base/include/TPCBase/ModelGEM.h +++ b/Detectors/TPC/base/include/TPCBase/ModelGEM.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/PadInfo.h b/Detectors/TPC/base/include/TPCBase/PadInfo.h index f89893caade69..f87601fd7a50b 100644 --- a/Detectors/TPC/base/include/TPCBase/PadInfo.h +++ b/Detectors/TPC/base/include/TPCBase/PadInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/PadPos.h b/Detectors/TPC/base/include/TPCBase/PadPos.h index b9046bf77ba60..53c5df2f83d11 100644 --- a/Detectors/TPC/base/include/TPCBase/PadPos.h +++ b/Detectors/TPC/base/include/TPCBase/PadPos.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/PadROCPos.h b/Detectors/TPC/base/include/TPCBase/PadROCPos.h index cb76a725591db..62a6a119253db 100644 --- a/Detectors/TPC/base/include/TPCBase/PadROCPos.h +++ b/Detectors/TPC/base/include/TPCBase/PadROCPos.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/PadRegionInfo.h b/Detectors/TPC/base/include/TPCBase/PadRegionInfo.h index cd28447293916..acb25f03ac9bf 100644 --- a/Detectors/TPC/base/include/TPCBase/PadRegionInfo.h +++ b/Detectors/TPC/base/include/TPCBase/PadRegionInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -93,8 +94,12 @@ class PadRegionInfo /// Return the row offset in the sector /// \return row offset in the sector unsigned char getGlobalRowOffset() const { return mGlobalRowOffset; } - // const unsigned char getRowOffset() const { return mRowOffset; } - // const float getXhelper() const { return mXhelper; } + + /// Local row offset for geometry calculations + unsigned char getRowOffset() const { return mRowOffset; } + + /// Helper variable for geometry calculations + float getXhelper() const { return mXhelper; } /// Return the number of pads for the row in `padPos` (row in the sector) /// \param padPos pad position in the sector diff --git a/Detectors/TPC/base/include/TPCBase/PadSecPos.h b/Detectors/TPC/base/include/TPCBase/PadSecPos.h index d23fc43d12365..7808a81f31f37 100644 --- a/Detectors/TPC/base/include/TPCBase/PadSecPos.h +++ b/Detectors/TPC/base/include/TPCBase/PadSecPos.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/Painter.h b/Detectors/TPC/base/include/TPCBase/Painter.h index bab3d989180ee..f378a70c3072a 100644 --- a/Detectors/TPC/base/include/TPCBase/Painter.h +++ b/Detectors/TPC/base/include/TPCBase/Painter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,10 +18,14 @@ /// #include <vector> +#include <string> +#include <string_view> #include "DataFormatsTPC/Defs.h" class TH1; class TH2; +class TH3F; +class TH2Poly; class TCanvas; namespace o2 @@ -44,12 +49,38 @@ class CalArray; namespace painter { + +/// pad corner coordinates +struct PadCoordinates { + std::array<double, 4> xVals; + std::array<double, 4> yVals; + + void rotate(float angDeg) + { + const auto ang = 0.017453292519943295 * angDeg; + const auto cs = std::cos(ang); + const auto sn = std::sin(ang); + for (size_t i = 0; i < xVals.size(); ++i) { + const auto x = xVals[i] * cs - yVals[i] * sn; + const auto y = xVals[i] * sn + yVals[i] * cs; + xVals[i] = x; + yVals[i] = y; + } + } +}; + +/// create a vector of pad corner coordinate for one full sector +std::vector<PadCoordinates> getPadCoordinatesSector(); + +/// ROC title from ROC number +std::string getROCTitle(const int rocNumber); + //using T=float; /// Drawing of a CalDet object /// \param CalDet object to draw /// \return TCanvas containing CalDet content template <class T> -TCanvas* draw(const CalDet<T>& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0); +TCanvas* draw(const CalDet<T>& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, TCanvas* outputCanvas = nullptr); /// Drawing of a CalDet object /// \param CalArray object to draw @@ -84,6 +115,19 @@ TH2* getHistogram2D(const CalDet<T>& calDet, Side side); template <class T> TH2* getHistogram2D(const CalArray<T>& calArray); +/// make a sector-wise histogram with correct pad corners +TH2Poly* makeSectorHist(const std::string_view name = "hSector", const std::string_view title = "Sector;local #it{x} (cm);local #it{y} (cm)"); + +/// make a side-wise histogram with correct pad corners +TH2Poly* makeSideHist(Side side); + +/// fill existing TH2Poly histogram for CalDet object +/// \param h2D histogram to fill +/// \param CalDet object with data +/// \param side side which to get the histogram for +template <class T> +void fillPoly2D(TH2Poly& h2D, const CalDet<T>& calDet, Side side); + /// Create summary canvases for a CalDet object /// /// 1 Canvas with 2D and 1D distributions for each side @@ -93,9 +137,10 @@ TH2* getHistogram2D(const CalArray<T>& calArray); /// \param nbins1D number of bins used for the 1D projections /// \param xMin1D minimum value for 1D distribution (xMin = 0 and xMax = 0 for auto scaling) /// \param xMax1D maximum value for 1D distribution (xMin = 0 and xMax = 0 for auto scaling) +/// \param outputCanvases if outputCanvases are given, use them instead of creating new ones, 3 are required /// \return TCanvas containing CalDet content template <class T> -std::vector<TCanvas*> makeSummaryCanvases(const CalDet<T>& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, bool onlyFilled = true); +std::vector<TCanvas*> makeSummaryCanvases(const CalDet<T>& calDet, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, bool onlyFilled = true, std::vector<TCanvas*>* outputCanvases = nullptr); /// Create summary canvases for a CalDet object /// @@ -111,6 +156,30 @@ std::vector<TCanvas*> makeSummaryCanvases(const CalDet<T>& calDet, int nbins1D = /// \return TCanvas containing CalDet content std::vector<TCanvas*> makeSummaryCanvases(const std::string_view fileName, const std::string_view calPadNames, int nbins1D = 300, float xMin1D = 0, float xMax1D = 0, bool onlyFilled = true); +/// draw sector boundaris, side name and sector numbers +void drawSectorsXY(Side side, int sectorLineColor = 920, int sectorTextColor = 1); + +/// draw information of the sector: pad number in row +/// \param padTextColor text color of pad number +/// \param lineScalePS setting the width of the lines of the pads which are drawn +void drawSectorLocalPadNumberPoly(short padTextColor = kBlack, float lineScalePS = 1); + +/// draw information of the sector: pad row in region, global pad row, lines for separating the regions +/// \param regionLineColor color of the line which is drawn at the start of a sector +/// \param rowTextColor color of the text which is drawn +void drawSectorInformationPoly(short regionLineColor = kRed, short rowTextColor = kRed); + +/// convert std::vector<CalDet> objects (pad granularity) to a 3D-histogram with rxphixz binning. Each CalDet will be filled in a unique slice in the histogram +/// \param calDet input objects which will be converted to a 3D histogram +/// \param norm whether to normalize the histogram (weighted mean) or to just integrate the values of the CalDet +/// \param nRBins number of bins in r direction of the output histogram +/// \param rMin min r value of the output histogram +/// \param rMax max r value of the output histogram +/// \param nPhiBins number of bins in phi direction of the output histogram +/// \param zMax z range of the output histogram (-zMax to zMax) +template <typename DataT> +TH3F convertCalDetToTH3(const std::vector<CalDet<DataT>>& calDet, const bool norm = true, const int nRBins = 150, const float rMin = 83.5, const float rMax = 254.5, const int nPhiBins = 720, const float zMax = 1); + } // namespace painter } // namespace tpc diff --git a/Detectors/TPC/base/include/TPCBase/ParameterDetector.h b/Detectors/TPC/base/include/TPCBase/ParameterDetector.h index 5b0cee663be96..d9c521eed04a9 100644 --- a/Detectors/TPC/base/include/TPCBase/ParameterDetector.h +++ b/Detectors/TPC/base/include/TPCBase/ParameterDetector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/ParameterElectronics.h b/Detectors/TPC/base/include/TPCBase/ParameterElectronics.h index 3946084f72784..dc98da103e4f3 100644 --- a/Detectors/TPC/base/include/TPCBase/ParameterElectronics.h +++ b/Detectors/TPC/base/include/TPCBase/ParameterElectronics.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/ParameterGEM.h b/Detectors/TPC/base/include/TPCBase/ParameterGEM.h index 1cba7a8a029f5..291058c0bc61e 100644 --- a/Detectors/TPC/base/include/TPCBase/ParameterGEM.h +++ b/Detectors/TPC/base/include/TPCBase/ParameterGEM.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -53,9 +54,9 @@ struct ParameterGEM : public o2::conf::ConfigurableParamHelper<ParameterGEM> { float AbsoluteGain[4] = {14.f, 8.f, 53.f, 240.f}; ///< Absolute gain float CollectionEfficiency[4] = {1.f, 0.2f, 0.25f, 1.f}; ///< Collection efficiency float ExtractionEfficiency[4] = {0.65f, 0.55f, 0.12f, 0.6f}; ///< Extraction efficiency - float TotalGainStack = 1644.f; ///< Total gain of the stack for the EffectiveMode - float KappaStack = 1.2295f; ///< Variable steering the energy resolution of the full stack for the EffectiveMode - float EfficiencyStack = 0.473805f; ///< Variable steering the single electron efficiency of the full stack for the EffectiveMode + float TotalGainStack = 2000.f; ///< Total gain of the stack for the EffectiveMode + float KappaStack = 1.205f; ///< Variable steering the energy resolution of the full stack for the EffectiveMode + float EfficiencyStack = 0.528f; ///< Variable steering the single electron efficiency of the full stack for the EffectiveMode AmplificationMode AmplMode = AmplificationMode::EffectiveMode; ///< Amplification mode [FullMode / EffectiveMode] O2ParamDef(ParameterGEM, "TPCGEMParam"); diff --git a/Detectors/TPC/base/include/TPCBase/ParameterGas.h b/Detectors/TPC/base/include/TPCBase/ParameterGas.h index 94244d3cae872..8e47391e39096 100644 --- a/Detectors/TPC/base/include/TPCBase/ParameterGas.h +++ b/Detectors/TPC/base/include/TPCBase/ParameterGas.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/PartitionInfo.h b/Detectors/TPC/base/include/TPCBase/PartitionInfo.h index 1da24d2bf633f..be7f6058710c2 100644 --- a/Detectors/TPC/base/include/TPCBase/PartitionInfo.h +++ b/Detectors/TPC/base/include/TPCBase/PartitionInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/RDHUtils.h b/Detectors/TPC/base/include/TPCBase/RDHUtils.h index e5f66e6b2be7d..f3fbc3539729f 100644 --- a/Detectors/TPC/base/include/TPCBase/RDHUtils.h +++ b/Detectors/TPC/base/include/TPCBase/RDHUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,9 @@ namespace rdh_utils using o2::raw::RDHUtils; using FEEIDType = uint16_t; -static constexpr FEEIDType UserLogicLinkID = 15; +static constexpr FEEIDType UserLogicLinkID = 15; ///< virtual link ID for ZS data +static constexpr FEEIDType IDCLinkID = 20; ///< Identifier for digital currents +static constexpr FEEIDType IACLinkID = 25; ///< Identifier for analog currents /// compose feeid from cru, endpoint and link static constexpr FEEIDType getFEEID(const FEEIDType cru, const FEEIDType endpoint, const FEEIDType link) { return FEEIDType((cru << 7) | ((endpoint & 1) << 6) | (link & 0x3F)); } diff --git a/Detectors/TPC/base/include/TPCBase/ROC.h b/Detectors/TPC/base/include/TPCBase/ROC.h index 3445b6feabfee..3ed0cf388eb72 100644 --- a/Detectors/TPC/base/include/TPCBase/ROC.h +++ b/Detectors/TPC/base/include/TPCBase/ROC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/Sector.h b/Detectors/TPC/base/include/TPCBase/Sector.h index 4a4fde29ff4ae..cd6da7917c3c1 100644 --- a/Detectors/TPC/base/include/TPCBase/Sector.h +++ b/Detectors/TPC/base/include/TPCBase/Sector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/include/TPCBase/Utils.h b/Detectors/TPC/base/include/TPCBase/Utils.h index d2bc09914f25f..38add5f908c4a 100644 --- a/Detectors/TPC/base/include/TPCBase/Utils.h +++ b/Detectors/TPC/base/include/TPCBase/Utils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,7 +59,7 @@ std::vector<CalPad*> readCalPads(const std::string_view fileName, const std::str /// \param outputFileName name of the output file /// \param inputFileNames input file names. Perforams file system 'ls' in case the string includes '.root'. Otherwise it assumes a text input file with line by line file names. /// \param calPadNames comma separated list of names of the CalPad objects as stored in the file. -void mergeCalPads(std::string_view outputFileName, std::string_view inputFileNames, std::string_view calPadNames); +void mergeCalPads(std::string_view outputFileName, std::string_view inputFileNames, std::string_view calPadNames, bool average = false); /// Build a chain interpreting a command line argument /// diff --git a/Detectors/TPC/base/include/TPCBase/ZeroSuppress.h b/Detectors/TPC/base/include/TPCBase/ZeroSuppress.h index b29dce34c52c6..814021fd6ea8c 100644 --- a/Detectors/TPC/base/include/TPCBase/ZeroSuppress.h +++ b/Detectors/TPC/base/include/TPCBase/ZeroSuppress.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/CDBInterface.cxx b/Detectors/TPC/base/src/CDBInterface.cxx index b6fb55d2083ad..0405e8a909afc 100644 --- a/Detectors/TPC/base/src/CDBInterface.cxx +++ b/Detectors/TPC/base/src/CDBInterface.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -159,6 +160,12 @@ const ParameterGEM& CDBInterface::getParameterGEM() return getObjectFromCDB<ParameterGEM>(CDBTypeMap.at(CDBType::ParGEM)); } +//______________________________________________________________________________ +const CalPad& CDBInterface::getCalPad(const std::string_view path) +{ + return getSpecificObjectFromCDB<CalPad>(path); +} + //______________________________________________________________________________ void CDBInterface::loadNoiseAndPedestalFromFile() { @@ -358,7 +365,7 @@ void CDBStorage::uploadGainMap(std::string_view fileName, bool isFull, long firs } //______________________________________________________________________________ -void CDBStorage::uploadPulserData(std::string_view fileName, long first, long last) +void CDBStorage::uploadPulserOrCEData(CDBType type, std::string_view fileName, long first, long last) { std::unique_ptr<TFile> f(TFile::Open(fileName.data())); CalDet<float>*t0 = nullptr, *width = nullptr, *qtot = nullptr; @@ -375,7 +382,7 @@ void CDBStorage::uploadPulserData(std::string_view fileName, long first, long la pulserCalib["Width"] = *width; pulserCalib["Qtot"] = *qtot; - storeObject(&pulserCalib, CDBType::CalPulser, first, last); + storeObject(&pulserCalib, type, first, last); } //______________________________________________________________________________ diff --git a/Detectors/TPC/base/src/CRU.cxx b/Detectors/TPC/base/src/CRU.cxx index 891962adcbfa3..bbf9a60e88dc2 100644 --- a/Detectors/TPC/base/src/CRU.cxx +++ b/Detectors/TPC/base/src/CRU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/CalArray.cxx b/Detectors/TPC/base/src/CalArray.cxx index de37abbaaee7f..59cf2d3a1d930 100644 --- a/Detectors/TPC/base/src/CalArray.cxx +++ b/Detectors/TPC/base/src/CalArray.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/CalDet.cxx b/Detectors/TPC/base/src/CalDet.cxx index 0fdf0a6afca37..e4ceef112f940 100644 --- a/Detectors/TPC/base/src/CalDet.cxx +++ b/Detectors/TPC/base/src/CalDet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/ContainerFactory.cxx b/Detectors/TPC/base/src/ContainerFactory.cxx index 97349ec7f2eb4..47555bd72be51 100644 --- a/Detectors/TPC/base/src/ContainerFactory.cxx +++ b/Detectors/TPC/base/src/ContainerFactory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/DigitPos.cxx b/Detectors/TPC/base/src/DigitPos.cxx index 2bab8b5e40ba1..e0c6bc134deb1 100644 --- a/Detectors/TPC/base/src/DigitPos.cxx +++ b/Detectors/TPC/base/src/DigitPos.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/FECInfo.cxx b/Detectors/TPC/base/src/FECInfo.cxx index 3b95d069216ab..6e58931163f22 100644 --- a/Detectors/TPC/base/src/FECInfo.cxx +++ b/Detectors/TPC/base/src/FECInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/Mapper.cxx b/Detectors/TPC/base/src/Mapper.cxx index 3acc10d73edd2..c5947b1fbdd19 100644 --- a/Detectors/TPC/base/src/Mapper.cxx +++ b/Detectors/TPC/base/src/Mapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -81,7 +82,9 @@ Mapper::Mapper(const std::string& mappingDir) mMapPartitionInfo() { load(mappingDir); + loadTraceLengths(mappingDir); } + bool Mapper::readMappingFile(std::string file) { // ===| Mapping file layout |================================================= @@ -239,5 +242,66 @@ void Mapper::initPadRegionsAndPartitions() } } +//______________________________________________________________________________ +void Mapper::loadTraceLengths(std::string_view mappingDir) +{ + std::string inputDir = mappingDir.data(); + if (!inputDir.size()) { + const char* aliceO2env = std::getenv("O2_ROOT"); + if (aliceO2env) { + inputDir = aliceO2env; + } + inputDir += "/share/Detectors/TPC/files"; + } + + mTraceLengthsIROC.reserve(Mapper::getPadsInIROC()); + mTraceLengthsOROC.reserve(Mapper::getPadsInOROC()); + setTraceLengths(inputDir + "/LENGTH-IROC.txt", mTraceLengthsIROC); + setTraceLengths(inputDir + "/LENGTH-OROC1.txt", mTraceLengthsOROC); + setTraceLengths(inputDir + "/LENGTH-OROC2.txt", mTraceLengthsOROC); + setTraceLengths(inputDir + "/LENGTH-OROC3.txt", mTraceLengthsOROC); + + assert(mTraceLengthsIROC.size() == Mapper::getPadsInIROC()); + assert(mTraceLengthsOROC.size() == Mapper::getPadsInOROC()); +} + +//______________________________________________________________________________ +void Mapper::setTraceLengths(std::string_view inputFile, std::vector<float>& length) +{ + + std::ifstream infile(inputFile.data(), std::ifstream::in); + if (!infile.is_open()) { + std::cout << "could not open file " << inputFile.data() << "\n"; + exit(1); + } + + // e.g. IROC file + // Col 0 -> INDEX (0 - 5279) + // Col 1 -> PADROW (0 - 62) + // Col 2 -> PAD (0 - (Np-1)) + // Col 3 -> Connector (1 - 132) + // Col 4 -> Pin (1 - 40) + // Col 5 -> Trace length (mm) + // Col 6 -> Number of vias + + unsigned int index{}; + unsigned int padrow{}; + unsigned int pad{}; + unsigned int connector{}; + unsigned int pin{}; + float traceLength{}; + unsigned int numberOfVias{}; + + std::string line; + while (std::getline(infile, line)) { + std::stringstream streamLine(line); + streamLine >> index >> padrow >> pad >> connector >> pin >> traceLength >> numberOfVias; + + traceLength /= 10.f; + + length.emplace_back(traceLength); + } +} + } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/base/src/ModelGEM.cxx b/Detectors/TPC/base/src/ModelGEM.cxx index 0b1b2778bd76b..eb75b432b9fc3 100644 --- a/Detectors/TPC/base/src/ModelGEM.cxx +++ b/Detectors/TPC/base/src/ModelGEM.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PadInfo.cxx b/Detectors/TPC/base/src/PadInfo.cxx index 8c801745f0efd..22f3ab527a201 100644 --- a/Detectors/TPC/base/src/PadInfo.cxx +++ b/Detectors/TPC/base/src/PadInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PadPos.cxx b/Detectors/TPC/base/src/PadPos.cxx index 165aa94d126b3..e57055579785b 100644 --- a/Detectors/TPC/base/src/PadPos.cxx +++ b/Detectors/TPC/base/src/PadPos.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PadROCPos.cxx b/Detectors/TPC/base/src/PadROCPos.cxx index e5f3e25a274fe..12f4a6c2f0b21 100644 --- a/Detectors/TPC/base/src/PadROCPos.cxx +++ b/Detectors/TPC/base/src/PadROCPos.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PadRegionInfo.cxx b/Detectors/TPC/base/src/PadRegionInfo.cxx index 6a3117ad53730..78657507f3a83 100644 --- a/Detectors/TPC/base/src/PadRegionInfo.cxx +++ b/Detectors/TPC/base/src/PadRegionInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PadSecPos.cxx b/Detectors/TPC/base/src/PadSecPos.cxx index 0673a83a8822d..938a3a7fffb11 100644 --- a/Detectors/TPC/base/src/PadSecPos.cxx +++ b/Detectors/TPC/base/src/PadSecPos.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/Painter.cxx b/Detectors/TPC/base/src/Painter.cxx index f818bad0e7add..8401faa143709 100644 --- a/Detectors/TPC/base/src/Painter.cxx +++ b/Detectors/TPC/base/src/Painter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,13 +12,19 @@ #include <string> #include <algorithm> #include <fmt/format.h> +#include <cmath> -#include "TString.h" #include "TAxis.h" #include "TH1.h" #include "TH2.h" +#include "TH3.h" +#include "TH2Poly.h" #include "TCanvas.h" +#include "TLine.h" +#include "TLatex.h" +#include "TStyle.h" +#include "DataFormatsTPC/Defs.h" #include "TPCBase/ROC.h" #include "TPCBase/Sector.h" #include "TPCBase/Mapper.h" @@ -26,10 +33,59 @@ #include "TPCBase/Painter.h" #include "TPCBase/Utils.h" +// for conversion CalDet to TH3 +#include <deque> +#include <boost/geometry.hpp> +#include <boost/geometry/geometries/point_xy.hpp> +#include <boost/geometry/geometries/polygon.hpp> +#include "MathUtils/Utils.h" + using namespace o2::tpc; +std::vector<painter::PadCoordinates> painter::getPadCoordinatesSector() +{ + std::vector<painter::PadCoordinates> padCoords; + + const auto& regInf = Mapper::instance().getMapPadRegionInfo(); + + for (const auto& padReg : regInf) { + const auto npr = padReg.getNumberOfPadRows(); + const auto ro = padReg.getRowOffset(); + const auto xm = padReg.getXhelper(); + const auto ph = padReg.getPadHeight(); + const auto pw = padReg.getPadWidth(); + const auto yro = padReg.getRadiusFirstRow(); + const auto ks = ph / pw * std::tan(1.74532925199432948e-01); + + for (int irow = 0; irow < npr; ++irow) { + const auto npads = std::floor(ks * (irow + ro) + xm); + for (int ipad = -npads; ipad < npads; ++ipad) { + const auto xPadBottomRight = yro + ph * irow; + const auto xPadTopRight = yro + ph * (irow + 1); + const auto ri = xPadBottomRight; + const auto yPadBottomRight = pw * ipad * xPadBottomRight / (ri + ph / 2); + const auto yPadTopRight = pw * ipad * xPadTopRight / (ri + ph / 2); + const auto yPadBottomLeft = pw * (ipad + 1) * xPadBottomRight / (ri + ph / 2); + const auto yPadTopLeft = pw * (ipad + 1) * xPadTopRight / (ri + ph / 2); + auto& padCoord = padCoords.emplace_back(); + padCoord.xVals = {xPadBottomRight, xPadTopRight, xPadTopRight, xPadBottomRight}; + padCoord.yVals = {yPadBottomRight, yPadTopRight, yPadTopLeft, yPadBottomLeft}; + } + } + } + + return padCoords; +} + +std::string painter::getROCTitle(const int rocNumber) +{ + const std::string_view type = (rocNumber < 36) ? "IROC" : "OROC"; + const std::string_view side = ((rocNumber % 36) < 18) ? "A" : "C"; + return fmt::format("{} {}{:02}", type, side, rocNumber % 18); +} + template <class T> -TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float xMax1D) +TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float xMax1D, TCanvas* outputCanvas) { using DetType = CalDet<T>; using CalType = CalArray<T>; @@ -37,9 +93,10 @@ TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float static const Mapper& mapper = Mapper::instance(); // ===| name and title |====================================================== - const auto title = calDet.getName().c_str(); + std::string title = calDet.getName(); std::string name = calDet.getName(); std::replace(name.begin(), name.end(), ' ', '_'); + std::replace(title.begin(), title.end(), '_', ' '); // ===| define histograms |=================================================== // TODO: auto scaling of ranges based on mean and variance? @@ -49,16 +106,16 @@ TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float const int bufferSize = TH1::GetDefaultBufferSize(); TH1::SetDefaultBufferSize(Sector::MAXSECTOR * mapper.getPadsInSector()); - auto hAside1D = new TH1F(Form("h_Aside_1D_%s", name.c_str()), Form("%s (A-Side)", title), + auto hAside1D = new TH1F(fmt::format("h_Aside_1D_{}", name).data(), fmt::format("{} (A-Side)", title).data(), nbins1D, xMin1D, xMax1D); //TODO: modify ranges - auto hCside1D = new TH1F(Form("h_Cside_1D_%s", name.c_str()), Form("%s (C-Side)", title), + auto hCside1D = new TH1F(fmt::format("h_Cside_1D_{}", name).data(), fmt::format("{} (C-Side)", title).data(), nbins1D, xMin1D, xMax1D); //TODO: modify ranges - auto hAside2D = new TH2F(Form("h_Aside_2D_%s", name.c_str()), Form("%s (A-Side);x (cm);y (cm)", title), + auto hAside2D = new TH2F(fmt::format("h_Aside_2D_{}", name).data(), fmt::format("{} (A-Side);x (cm);y (cm)", title).data(), 300, -300, 300, 300, -300, 300); - auto hCside2D = new TH2F(Form("h_Cside_2D_%s", name.c_str()), Form("%s (C-Side);x (cm);y (cm)", title), + auto hCside2D = new TH2F(fmt::format("h_Cside_2D_{}", name).data(), fmt::format("{} (C-Side);x (cm);y (cm)", title).data(), 300, -300, 300, 300, -300, 300); for (ROC roc; !roc.looped(); ++roc) { @@ -93,14 +150,22 @@ TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float } // ===| Draw histograms |===================================================== - auto c = new TCanvas(Form("c_%s", name.c_str()), title, 1000, 1000); + auto c = outputCanvas; + if (!c) { + c = new TCanvas(fmt::format("c_{}", name).data(), title.data(), 1000, 1000); + } + c->Clear(); c->Divide(2, 2); c->cd(1); hAside2D->Draw("colz"); + hAside2D->SetStats(0); + drawSectorsXY(Side::A); c->cd(2); hCside2D->Draw("colz"); + hCside2D->SetStats(0); + drawSectorsXY(Side::C); c->cd(3); hAside1D->Draw(); @@ -111,6 +176,12 @@ TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float // reset the buffer size TH1::SetDefaultBufferSize(bufferSize); + // associate histograms to canvas + hAside1D->SetBit(TObject::kCanDelete); + hCside1D->SetBit(TObject::kCanDelete); + hAside2D->SetBit(TObject::kCanDelete); + hCside2D->SetBit(TObject::kCanDelete); + return c; } @@ -118,14 +189,16 @@ TCanvas* painter::draw(const CalDet<T>& calDet, int nbins1D, float xMin1D, float template <class T> TCanvas* painter::draw(const CalArray<T>& calArray) { - const auto title = calArray.getName().c_str(); - std::string name = calArray.getName(); - std::replace(name.begin(), name.end(), ' ', '_'); - auto c = new TCanvas(Form("c_%s", name.c_str()), title); - auto hist = getHistogram2D(calArray); + std::string name = hist->GetName(); + name[0] = 'c'; + auto c = new TCanvas(fmt::format("c_{}", name).data(), hist->GetTitle()); + hist->Draw("colz"); + // associate histograms to canvas + hist->SetBit(TObject::kCanDelete); + return c; } @@ -181,13 +254,14 @@ void painter::fillHistogram2D(TH2& h2D, const CalArray<T>& calArray) template <class T> TH2* painter::getHistogram2D(const CalDet<T>& calDet, Side side) { - const auto title = calDet.getName().c_str(); + std::string title = calDet.getName(); std::string name = calDet.getName(); std::replace(name.begin(), name.end(), ' ', '_'); + std::replace(title.begin(), title.end(), '_', ' '); const char side_name = (side == Side::A) ? 'A' : 'C'; - auto h2D = new TH2F(Form("h_%cside_2D_%s", side_name, name.c_str()), - Form("%s (%c-Side);x (cm);y (cm)", title, side_name), + auto h2D = new TH2F(fmt::format("h_{}side_2D_{}", side_name, name).data(), + fmt::format("{} ({}-Side);x (cm);y (cm)", title, side_name).data(), 300, -300, 300, 300, -300, 300); fillHistogram2D(*h2D, calDet, side); @@ -209,11 +283,17 @@ TH2* painter::getHistogram2D(const CalArray<T>& calArray) const int npads = mapper.getNumberOfPadsInRow(padSubset, position, nrows - 1) + 6; // ===| create histogram |==================================================== - const auto title = calArray.getName().c_str(); + std::string title = calArray.getName(); std::string name = calArray.getName(); + std::replace(title.begin(), title.end(), '_', ' '); std::replace(name.begin(), name.end(), ' ', '_'); - auto hist = new TH2F(Form("h_%s", name.c_str()), - Form("%s;pad row;pad", title), + + if (padSubset == PadSubset::ROC) { + title += fmt::format(" ({})", getROCTitle(position)); + } + + auto hist = new TH2F(fmt::format("h_{}", name).data(), + fmt::format("{};pad row;pad", title).data(), nrows, 0., nrows, npads, -npads / 2, npads / 2); @@ -235,7 +315,7 @@ std::enable_if_t<std::is_unsigned<T>::value, bool> hasData(const CalArray<T>& ca } template <class T> -std::vector<TCanvas*> painter::makeSummaryCanvases(const CalDet<T>& calDet, int nbins1D, float xMin1D, float xMax1D, bool onlyFilled) +std::vector<TCanvas*> painter::makeSummaryCanvases(const CalDet<T>& calDet, int nbins1D, float xMin1D, float xMax1D, bool onlyFilled, std::vector<TCanvas*>* outputCanvases) { std::vector<TCanvas*> vecCanvases; @@ -258,17 +338,36 @@ std::vector<TCanvas*> painter::makeSummaryCanvases(const CalDet<T>& calDet, int } // ===| set up canvases |=== + TCanvas* cSides = nullptr; + TCanvas* cROCs1D = nullptr; + TCanvas* cROCs2D = nullptr; const std::string_view calName = calDet.getName(); - auto cSides = draw(calDet, nbins1D, xMin1D, xMax1D); - auto cROCs1D = new TCanvas(fmt::format("c_ROCs_{}_1D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); - auto cROCs2D = new TCanvas(fmt::format("c_ROCs_{}_2D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); - vecCanvases.emplace_back(cSides); - vecCanvases.emplace_back(cROCs1D); - vecCanvases.emplace_back(cROCs2D); + if (outputCanvases) { + if (outputCanvases->size() < 3) { + LOGP(error, "At least 3 canvases are needed to fill the output, only {} given", outputCanvases->size()); + return vecCanvases; + } + + cSides = outputCanvases->at(0); + cROCs1D = outputCanvases->at(1); + cROCs2D = outputCanvases->at(2); + cSides->Clear(); + cROCs1D->Clear(); + cROCs2D->Clear(); + } else { + + cROCs1D = new TCanvas(fmt::format("c_ROCs_{}_1D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); + cROCs2D = new TCanvas(fmt::format("c_ROCs_{}_2D", calName).data(), fmt::format("{} values for each ROC", calName).data(), 1400, 1000); + } + cSides = draw(calDet, nbins1D, xMin1D, xMax1D, cSides); cROCs1D->DivideSquare(nROCs); cROCs2D->DivideSquare(nROCs); + vecCanvases.emplace_back(cSides); + vecCanvases.emplace_back(cROCs1D); + vecCanvases.emplace_back(cROCs2D); + // ===| produce plots for each ROC |=== size_t pad = 1; for (size_t iroc = 0; iroc < calDet.getData().size(); ++iroc) { @@ -279,7 +378,7 @@ std::vector<TCanvas*> painter::makeSummaryCanvases(const CalDet<T>& calDet, int } // ===| 1D histogram |=== - auto h1D = new TH1F(fmt::format("h_{}_{:02d}", calName, iroc).data(), fmt::format("{} distribution ROC {:02d};ADC value", calName, iroc).data(), nbins1D, xMin1D, xMax1D); + auto h1D = new TH1F(fmt::format("h_{}_{:02d}", calName, iroc).data(), fmt::format("{} distribution ROC {:02d} ({});ADC value", calName, iroc, getROCTitle(iroc)).data(), nbins1D, xMin1D, xMax1D); for (const auto& val : roc.getData()) { h1D->Fill(val); } @@ -300,12 +399,16 @@ std::vector<TCanvas*> painter::makeSummaryCanvases(const CalDet<T>& calDet, int h2D->Draw("colz"); ++pad; + + // associate histograms to canvas + h1D->SetBit(TObject::kCanDelete); + h2D->SetBit(TObject::kCanDelete); } return vecCanvases; } -//============================================================================== +//______________________________________________________________________________ std::vector<TCanvas*> painter::makeSummaryCanvases(const std::string_view fileName, const std::string_view calPadNames, int nbins1D, float xMin1D, float xMax1D, bool onlyFilled) { using namespace o2::tpc; @@ -324,37 +427,385 @@ std::vector<TCanvas*> painter::makeSummaryCanvases(const std::string_view fileNa return vecCanvases; } +//______________________________________________________________________________ +TH2Poly* painter::makeSectorHist(const std::string_view name, const std::string_view title) +{ + auto poly = new TH2Poly(name.data(), title.data(), 83.65, 247.7, -43.7, 43.7); + + auto coords = painter::getPadCoordinatesSector(); + for (const auto& coord : coords) { + poly->AddBin(coord.xVals.size(), coord.xVals.data(), coord.yVals.data()); + } + + return poly; +} + +//______________________________________________________________________________ +TH2Poly* painter::makeSideHist(Side side) +{ + const auto s = (side == Side::A) ? "A" : "C"; + auto poly = new TH2Poly(fmt::format("hSide_{}", s).data(), fmt::format("{}-Side;#it{{x}} (cm);#it{{y}} (cm)", s).data(), -270., 270., -270., 270.); + + auto coords = painter::getPadCoordinatesSector(); + for (int isec = 0; isec < 18; ++isec) { + const float angDeg = 10.f + isec * 20; + for (auto coord : coords) { + coord.rotate(angDeg); + poly->AddBin(coord.xVals.size(), coord.xVals.data(), coord.yVals.data()); + } + } + + return poly; +} + +//______________________________________________________________________________ +template <class T> +void painter::fillPoly2D(TH2Poly& h2D, const CalDet<T>& calDet, Side side) +{ + static const Mapper& mapper = Mapper::instance(); + + int bin = 1; + for (const auto& calROC : calDet.getData()) { + ROC roc(calROC.getPadSubsetNumber()); + if (roc.side() != side) { + continue; + } + + const int nrows = mapper.getNumberOfRowsROC(roc); + for (int irow = 0; irow < nrows; ++irow) { + const int padMax = mapper.getNumberOfPadsInRowROC(roc, irow) - 1; + for (int ipad = 0; ipad <= padMax; ++ipad) { + const auto pos = mapper.getPadCentre(PadROCPos(calROC.getPadSubsetNumber(), irow, ipad)); + const auto val = calDet.getValue(roc, irow, ipad); + h2D.Fill(pos.X(), pos.Y(), val); + } + } + } +} + +//______________________________________________________________________________ +void painter::drawSectorsXY(Side side, int sectorLineColor, int sectorTextColor) +{ + TLine l; + l.SetLineColor(sectorLineColor); + + TLine l2; + l2.SetLineColor(sectorLineColor); + l2.SetLineStyle(kDotted); + + TLatex latSide; + latSide.SetTextColor(sectorTextColor); + latSide.SetTextAlign(22); + latSide.SetTextSize(0.08); + latSide.DrawLatex(0, 0, (side == Side::C) ? "C" : "A"); + + TLatex lat; + lat.SetTextAlign(22); + lat.SetTextSize(0.03); + lat.SetTextColor(sectorLineColor); + + constexpr float phiWidth = float(SECPHIWIDTH); + const float rFactor = std::cos(phiWidth / 2.); + const float rLow = 83.65 / rFactor; + const float rIROCup = 133.3 / rFactor; + const float rOROClow = 133.5 / rFactor; + const float rOROC12 = 169.75 / rFactor; + const float rOROC23 = 207.85 / rFactor; + const float rOut = 247.7 / rFactor; + const float rText = rLow * rFactor * 3. / 4.; + + for (Int_t isector = 0; isector < 18; ++isector) { + const float sinR = std::sin(phiWidth * isector); + const float cosR = std::cos(phiWidth * isector); + + const float sinL = std::sin(phiWidth * ((isector + 1) % 18)); + const float cosL = std::cos(phiWidth * ((isector + 1) % 18)); + + const float sinText = std::sin(phiWidth * (isector + 0.5)); + const float cosText = std::cos(phiWidth * (isector + 0.5)); + + const float xR1 = rLow * cosR; + const float yR1 = rLow * sinR; + const float xR2 = rOut * cosR; + const float yR2 = rOut * sinR; + + const float xL1 = rLow * cosL; + const float yL1 = rLow * sinL; + const float xL2 = rOut * cosL; + const float yL2 = rOut * sinL; + + const float xOROCmup1 = rOROClow * cosR; + const float yOROCmup1 = rOROClow * sinR; + const float xOROCmup2 = rOROClow * cosL; + const float yOROCmup2 = rOROClow * sinL; + + const float xIROCmup1 = rIROCup * cosR; + const float yIROCmup1 = rIROCup * sinR; + const float xIROCmup2 = rIROCup * cosL; + const float yIROCmup2 = rIROCup * sinL; + + const float xO121 = rOROC12 * cosR; + const float yO121 = rOROC12 * sinR; + const float xO122 = rOROC12 * cosL; + const float yO122 = rOROC12 * sinL; + + const float xO231 = rOROC23 * cosR; + const float yO231 = rOROC23 * sinR; + const float xO232 = rOROC23 * cosL; + const float yO232 = rOROC23 * sinL; + + const float xText = rText * cosText; + const float yText = rText * sinText; + + // left side line + l.DrawLine(xR1, yR1, xR2, yR2); + + // IROC inner line + l.DrawLine(xR1, yR1, xL1, yL1); + + // IROC end line + l.DrawLine(xIROCmup1, yIROCmup1, xIROCmup2, yIROCmup2); + + // OROC start line + l.DrawLine(xOROCmup1, yOROCmup1, xOROCmup2, yOROCmup2); + + // OROC1 - OROC2 line + l.DrawLine(xO121, yO121, xO122, yO122); + + // OROC2 - OROC3 line + l.DrawLine(xO231, yO231, xO232, yO232); + + // IROC inner line + l.DrawLine(xR2, yR2, xL2, yL2); + + // sector numbers + lat.DrawLatex(xText, yText, fmt::format("{}", isector).data()); + } +} + +void painter::drawSectorLocalPadNumberPoly(short padTextColor, float lineScalePS) +{ + static const Mapper& mapper = Mapper::instance(); + const auto coords = getPadCoordinatesSector(); + TLatex lat; + lat.SetTextAlign(12); + lat.SetTextSize(0.002f); + lat.SetTextColor(padTextColor); + gStyle->SetLineScalePS(lineScalePS); + + for (unsigned int iregion = 0; iregion < Mapper::NREGIONS; ++iregion) { + const auto padInf = mapper.getPadRegionInfo(iregion); + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[iregion]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[iregion][irow]; ++ipad) { + const GlobalPadNumber padNum = o2::tpc::Mapper::getGlobalPadNumber(irow, ipad, iregion); + const auto coordinate = coords[padNum]; + const float yPos = (coordinate.yVals[0] + coordinate.yVals[2]) / 2; + const float xPos = (coordinate.xVals[0] + coordinate.xVals[2]) / 2; + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + } +} + +void painter::drawSectorInformationPoly(short regionLineColor, short rowTextColor) +{ + static const Mapper& mapper = Mapper::instance(); + + TLatex lat; + lat.SetTextColor(rowTextColor); + lat.SetTextSize(0.02f); + lat.SetTextAlign(12); + + TLine line; + line.SetLineColor(regionLineColor); + + std::vector<float> radii(Mapper::NREGIONS + 1); + radii.back() = 247; + for (unsigned int ireg = 0; ireg < Mapper::NREGIONS; ++ireg) { + const auto reg = mapper.getPadRegionInfo(ireg); + const float rad = reg.getRadiusFirstRow(); + radii[ireg] = rad; + line.DrawLine(rad, -43, rad, 43); + } + + // draw top region information + for (unsigned int ireg = 0; ireg < Mapper::NREGIONS; ++ireg) { + lat.DrawLatex((radii[ireg] + radii[ireg + 1]) / 2, 45, Form("%i", ireg)); + } + + lat.SetTextSize(0.002f); + lat.SetTextAlign(13); + // draw local and global rows + const std::array<float, Mapper::NREGIONS> posRow{16.2f, 18.2f, 20.2f, 22.3f, 26.f, 29.f, 33.f, 35.f, 39.f, 42.5f}; + int globalRow = 0; + for (unsigned int ireg = 0; ireg < Mapper::NREGIONS; ++ireg) { + const auto reg = mapper.getPadRegionInfo(ireg); + const float nRows = reg.getNumberOfPadRows(); + for (int i = 0; i < nRows; ++i) { + const float padHeight = reg.getPadHeight(); + const float radiusFirstRow = reg.getRadiusFirstRow(); + const float xPos = radiusFirstRow + (i + 0.5f) * padHeight; + const float yPos = posRow[ireg]; + // row in region + lat.DrawLatex(xPos, yPos, Form("%i", i)); + lat.DrawLatex(xPos, -yPos, Form("%i", i)); + // row in sector + const float offs = 0.5f; + lat.DrawLatex(xPos, yPos + offs, Form("%i", globalRow)); + lat.DrawLatex(xPos, -yPos - offs, Form("%i", globalRow++)); + } + } +} + +template <typename DataT> +TH3F painter::convertCalDetToTH3(const std::vector<CalDet<DataT>>& calDet, const bool norm, const int nRBins, const float rMin, const float rMax, const int nPhiBins, const float zMax) +{ + const int nZBins = calDet.size(); + TH3F histConvSum("hisCalDet", "hisCalDet", nPhiBins, 0, o2::constants::math::TwoPI, nRBins, rMin, rMax, 2 * nZBins, -zMax, zMax); // final converted histogram + TH3F histConvWeight("histConvWeight", "histConvWeight", nPhiBins, 0, o2::constants::math::TwoPI, nRBins, rMin, rMax, 2 * nZBins, -zMax, zMax); + + typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<float>> polygon; + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); // coordinates of the pads in one sector + + // create polygons per pad of the input histogram + std::vector<polygon> geoBin; + const int nGeoBins = nPhiBins * nRBins; + geoBin.reserve(nGeoBins); + for (int iphi = 1; iphi <= nPhiBins; ++iphi) { + const double phiLow = histConvSum.GetXaxis()->GetBinLowEdge(iphi); + const double phiUp = histConvSum.GetXaxis()->GetBinUpEdge(iphi); + for (int ir = 1; ir <= nRBins; ++ir) { + const double rLow = histConvSum.GetYaxis()->GetBinLowEdge(ir); + const double rUp = histConvSum.GetYaxis()->GetBinUpEdge(ir); + const double xPos1 = rLow * std::cos(phiLow); + const double yPos1 = rLow * std::sin(phiLow); + const double xPos2 = rLow * std::cos(phiUp); + const double yPos2 = rLow * std::sin(phiUp); + const double xPos4 = rUp * std::cos(phiLow); + const double yPos4 = rUp * std::sin(phiLow); + const double xPos3 = rUp * std::cos(phiUp); + const double yPos3 = rUp * std::sin(phiUp); + // round the values due to problems in intersection in boost with polygons close to each other + boost::geometry::read_wkt(Form("POLYGON((%.4f %.4f, %.4f %.4f, %.4f %.4f, %.4f %.4f, %.4f %.4f))", xPos1, yPos1, xPos2, yPos2, xPos3, yPos3, xPos4, yPos4, xPos1, yPos1), geoBin.emplace_back()); + boost::geometry::correct(geoBin.back()); + } + } + + for (unsigned int sector = 0; sector < Mapper::NSECTORS / 2; ++sector) { + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + const unsigned int rowsRegion = o2::tpc::Mapper::ROWSPERREGION[region]; + for (unsigned int iRow = 0; iRow < rowsRegion; ++iRow) { + const unsigned int padsInRow = o2::tpc::Mapper::PADSPERROW[region][iRow] - 1; + for (unsigned int iPad = 0; iPad <= padsInRow; ++iPad) { + const GlobalPadNumber padNum = Mapper::getGlobalPadNumber(iRow, iPad, region); + + const float angDeg = 10.f + sector * 20; + auto coordinate = coords[padNum]; + coordinate.rotate(angDeg); + + const std::array<double, 2> radiusPadCoord{ + std::sqrt(coordinate.xVals[0] * coordinate.xVals[0] + coordinate.yVals[0] * coordinate.yVals[0]), + std::sqrt(coordinate.xVals[2] * coordinate.xVals[2] + coordinate.yVals[2] * coordinate.yVals[2]), + }; + + std::array<float, 4> phiPadCoord{ + static_cast<float>(std::atan2(coordinate.yVals[0], coordinate.xVals[0])), + static_cast<float>(std::atan2(coordinate.yVals[1], coordinate.xVals[1])), + static_cast<float>(std::atan2(coordinate.yVals[2], coordinate.xVals[2])), + static_cast<float>(std::atan2(coordinate.yVals[3], coordinate.xVals[3]))}; + + for (auto& phi : phiPadCoord) { + o2::math_utils::bringTo02PiGen(phi); + } + + // bins of the histogram of the edges of the pad + const int binRBottomStart = std::clamp(histConvSum.GetYaxis()->FindBin(radiusPadCoord[0]) - 1, 1, nRBins); + const int binRTopEnd = std::clamp(histConvSum.GetYaxis()->FindBin(radiusPadCoord[1]) + 1, 1, nRBins); + int binPhiStart = std::min(histConvSum.GetXaxis()->FindBin(phiPadCoord[0]), histConvSum.GetXaxis()->FindBin(phiPadCoord[1])); + std::clamp(binPhiStart - 1, 1, nPhiBins); + int binPhiEnd = std::max(histConvSum.GetXaxis()->FindBin(phiPadCoord[2]), histConvSum.GetXaxis()->FindBin(phiPadCoord[3])); + std::clamp(binPhiEnd + 1, 1, nPhiBins); + + // define boost geoemtry object + polygon geoPad; + boost::geometry::read_wkt(Form("POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))", coordinate.xVals[0], coordinate.yVals[0], coordinate.xVals[1], coordinate.yVals[1], coordinate.xVals[2], coordinate.yVals[2], coordinate.xVals[3], coordinate.yVals[3], coordinate.xVals[0], coordinate.yVals[0]), geoPad); + boost::geometry::correct(geoPad); + + for (int binR = binRBottomStart; binR <= binRTopEnd; ++binR) { + for (int binPhi = binPhiStart; binPhi <= binPhiEnd; ++binPhi) { + const int ind = (binPhi - 1) * nRBins + binR - 1; + + std::deque<polygon> output; + boost::geometry::intersection(geoPad, geoBin[ind], output); + if (output.empty()) { + continue; + } + const double area = boost::geometry::area(output.front()); + const double fac = area * Mapper::PADAREA[region]; + + for (int iSide = 0; iSide < 2; ++iSide) { + const Side side = iSide == 0 ? Side::C : Side::A; + const unsigned int iCRU = side == Side::A ? (sector * Mapper::NREGIONS + region) : ((sector + Mapper::NSECTORS / 2) * Mapper::NREGIONS + region); + const CRU cru(iCRU); + + for (int iz = 0; iz < nZBins; ++iz) { + const auto val = calDet[iz].getValue(cru, iRow, (side == Side::A) ? iPad : padsInRow - iPad); + const int zBin = side == Side::A ? (nZBins + iz + 1) : (nZBins - iz); + const auto globBin = histConvSum.GetBin(binPhi, binR, zBin); + histConvSum.AddBinContent(globBin, val * fac); + if (norm) { + histConvWeight.AddBinContent(globBin, fac); + } + } + } + } + } + } + } + } + } + + if (norm) { + histConvSum.Divide(&histConvWeight); + } + + return histConvSum; +} + // ===| explicit instantiations |=============================================== // this is required to force the compiler to create instances with the types // we usually would like to deal with -template TCanvas* painter::draw<float>(const CalDet<float>& calDet, int, float, float); -template std::vector<TCanvas*> painter::makeSummaryCanvases<float>(const CalDet<float>& calDet, int, float, float, bool); +template TCanvas* painter::draw<float>(const CalDet<float>& calDet, int, float, float, TCanvas*); +template std::vector<TCanvas*> painter::makeSummaryCanvases<float>(const CalDet<float>& calDet, int, float, float, bool, std::vector<TCanvas*>*); template TCanvas* painter::draw<float>(const CalArray<float>& calArray); template void painter::fillHistogram2D<float>(TH2& h2D, const CalDet<float>& calDet, Side side); +template void painter::fillPoly2D<float>(TH2Poly& h2D, const CalDet<float>& calDet, Side side); template void painter::fillHistogram2D<float>(TH2& h2D, const CalArray<float>& calArray); template TH2* painter::getHistogram2D<float>(const CalDet<float>& calDet, Side side); template TH2* painter::getHistogram2D<float>(const CalArray<float>& calArray); -template TCanvas* painter::draw<double>(const CalDet<double>& calDet, int, float, float); -template std::vector<TCanvas*> painter::makeSummaryCanvases<double>(const CalDet<double>& calDet, int, float, float, bool); +template TCanvas* painter::draw<double>(const CalDet<double>& calDet, int, float, float, TCanvas*); +template std::vector<TCanvas*> painter::makeSummaryCanvases<double>(const CalDet<double>& calDet, int, float, float, bool, std::vector<TCanvas*>*); template TCanvas* painter::draw<double>(const CalArray<double>& calArray); template TH2* painter::getHistogram2D<double>(const CalDet<double>& calDet, Side side); template TH2* painter::getHistogram2D<double>(const CalArray<double>& calArray); -template TCanvas* painter::draw<int>(const CalDet<int>& calDet, int, float, float); -template std::vector<TCanvas*> painter::makeSummaryCanvases<int>(const CalDet<int>& calDet, int, float, float, bool); +template TCanvas* painter::draw<int>(const CalDet<int>& calDet, int, float, float, TCanvas*); +template std::vector<TCanvas*> painter::makeSummaryCanvases<int>(const CalDet<int>& calDet, int, float, float, bool, std::vector<TCanvas*>*); template TCanvas* painter::draw<int>(const CalArray<int>& calArray); template TH2* painter::getHistogram2D<int>(const CalDet<int>& calDet, Side side); template TH2* painter::getHistogram2D<int>(const CalArray<int>& calArray); -template TCanvas* painter::draw<short>(const CalDet<short>& calDet, int, float, float); -template std::vector<TCanvas*> painter::makeSummaryCanvases<short>(const CalDet<short>& calDet, int, float, float, bool); +template TCanvas* painter::draw<short>(const CalDet<short>& calDet, int, float, float, TCanvas*); +template std::vector<TCanvas*> painter::makeSummaryCanvases<short>(const CalDet<short>& calDet, int, float, float, bool, std::vector<TCanvas*>*); template TCanvas* painter::draw<short>(const CalArray<short>& calArray); template TH2* painter::getHistogram2D<short>(const CalDet<short>& calDet, Side side); template TH2* painter::getHistogram2D<short>(const CalArray<short>& calArray); -template TCanvas* painter::draw<bool>(const CalDet<bool>& calDet, int, float, float); -template std::vector<TCanvas*> painter::makeSummaryCanvases<bool>(const CalDet<bool>& calDet, int, float, float, bool); +template TCanvas* painter::draw<bool>(const CalDet<bool>& calDet, int, float, float, TCanvas*); +template std::vector<TCanvas*> painter::makeSummaryCanvases<bool>(const CalDet<bool>& calDet, int, float, float, bool, std::vector<TCanvas*>*); template TCanvas* painter::draw<bool>(const CalArray<bool>& calArray); template TH2* painter::getHistogram2D<bool>(const CalDet<bool>& calDet, Side side); template TH2* painter::getHistogram2D<bool>(const CalArray<bool>& calArray); + +template TH3F painter::convertCalDetToTH3<float>(const std::vector<CalDet<float>>&, const bool, const int, const float, const float, const int, const float); diff --git a/Detectors/TPC/base/src/ParameterDetector.cxx b/Detectors/TPC/base/src/ParameterDetector.cxx index a69d9f55f6387..171156d7f6eba 100644 --- a/Detectors/TPC/base/src/ParameterDetector.cxx +++ b/Detectors/TPC/base/src/ParameterDetector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/ParameterElectronics.cxx b/Detectors/TPC/base/src/ParameterElectronics.cxx index 01662a3ae632e..aee59708d0bc8 100644 --- a/Detectors/TPC/base/src/ParameterElectronics.cxx +++ b/Detectors/TPC/base/src/ParameterElectronics.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/ParameterGEM.cxx b/Detectors/TPC/base/src/ParameterGEM.cxx index 1f4bbe760a755..fcdd3a844f0ff 100644 --- a/Detectors/TPC/base/src/ParameterGEM.cxx +++ b/Detectors/TPC/base/src/ParameterGEM.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/ParameterGas.cxx b/Detectors/TPC/base/src/ParameterGas.cxx index a816b68cc2fe8..37d7b6da05730 100644 --- a/Detectors/TPC/base/src/ParameterGas.cxx +++ b/Detectors/TPC/base/src/ParameterGas.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/PartitionInfo.cxx b/Detectors/TPC/base/src/PartitionInfo.cxx index fead21f05c668..961433a21a389 100644 --- a/Detectors/TPC/base/src/PartitionInfo.cxx +++ b/Detectors/TPC/base/src/PartitionInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/ROC.cxx b/Detectors/TPC/base/src/ROC.cxx index 07d57eddc1e2d..2edc35c043218 100644 --- a/Detectors/TPC/base/src/ROC.cxx +++ b/Detectors/TPC/base/src/ROC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/Sector.cxx b/Detectors/TPC/base/src/Sector.cxx index 07d57eddc1e2d..2edc35c043218 100644 --- a/Detectors/TPC/base/src/Sector.cxx +++ b/Detectors/TPC/base/src/Sector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/src/TPCBaseLinkDef.h b/Detectors/TPC/base/src/TPCBaseLinkDef.h index 024e19c34961a..a68bac674fd3a 100644 --- a/Detectors/TPC/base/src/TPCBaseLinkDef.h +++ b/Detectors/TPC/base/src/TPCBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,8 +28,10 @@ #pragma link C++ class o2::tpc::CalDet < short> + ; #pragma link C++ class o2::tpc::CalDet < bool> + ; #pragma link C++ class std::vector < o2::tpc::CalDet < float>> + ; +#pragma link C++ class std::vector < o2::tpc::CalDet < float>*> + ; #pragma link C++ class std::unordered_map < std::string, o2::tpc::CalDet < float>> + ; #pragma link C++ class o2::tpc::CDBInterface; +#pragma link C++ class o2::tpc::CDBStorage; #pragma link C++ class o2::tpc::ContainerFactory; #pragma link C++ class o2::tpc::CRU; #pragma link C++ class o2::tpc::DigitPos; diff --git a/Detectors/TPC/base/src/Utils.cxx b/Detectors/TPC/base/src/Utils.cxx index 6469639e34171..acbe84ed42aff 100644 --- a/Detectors/TPC/base/src/Utils.cxx +++ b/Detectors/TPC/base/src/Utils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -172,7 +173,7 @@ std::vector<CalPad*> utils::readCalPads(const std::string_view fileName, const s } //______________________________________________________________________________ -void utils::mergeCalPads(std::string_view outputFileName, std::string_view inputFileNames, std::string_view calPadNames) +void utils::mergeCalPads(std::string_view outputFileName, std::string_view inputFileNames, std::string_view calPadNames, bool average) { using namespace o2::tpc; @@ -208,6 +209,15 @@ void utils::mergeCalPads(std::string_view outputFileName, std::string_view input } } + if (average) { + const auto n = arrFiles->GetEntriesFast(); + if (n > 0) { + for (auto calPad : mergedCalPads) { + *calPad /= n; + } + } + } + std::unique_ptr<TFile> outFile(TFile::Open(outputFileName.data(), "recreate")); for (auto calPad : mergedCalPads) { outFile->WriteObject(calPad, calPad->getName().data()); diff --git a/Detectors/TPC/base/src/ZeroSuppress.cxx b/Detectors/TPC/base/src/ZeroSuppress.cxx index 70cb7ca21b6c2..948d4b254cb8c 100644 --- a/Detectors/TPC/base/src/ZeroSuppress.cxx +++ b/Detectors/TPC/base/src/ZeroSuppress.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testRDHUtils.cxx b/Detectors/TPC/base/test/testRDHUtils.cxx index fc33bf5318438..9c5bab1866c5b 100644 --- a/Detectors/TPC/base/test/testRDHUtils.cxx +++ b/Detectors/TPC/base/test/testRDHUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testTPCBase.cxx b/Detectors/TPC/base/test/testTPCBase.cxx index 37b0bca8129b1..46de2af2f680e 100644 --- a/Detectors/TPC/base/test/testTPCBase.cxx +++ b/Detectors/TPC/base/test/testTPCBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testTPCCDBInterface.cxx b/Detectors/TPC/base/test/testTPCCDBInterface.cxx index 026b3c40a15d8..3074c5e90a00c 100644 --- a/Detectors/TPC/base/test/testTPCCDBInterface.cxx +++ b/Detectors/TPC/base/test/testTPCCDBInterface.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testTPCCalDet.cxx b/Detectors/TPC/base/test/testTPCCalDet.cxx index f5d3d60269d2f..ffba10844c482 100644 --- a/Detectors/TPC/base/test/testTPCCalDet.cxx +++ b/Detectors/TPC/base/test/testTPCCalDet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testTPCMapper.cxx b/Detectors/TPC/base/test/testTPCMapper.cxx index 54682abb179ee..64711968d27fe 100644 --- a/Detectors/TPC/base/test/testTPCMapper.cxx +++ b/Detectors/TPC/base/test/testTPCMapper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/base/test/testTPCParameters.cxx b/Detectors/TPC/base/test/testTPCParameters.cxx index 643e9d148ac6d..b15123e745d1d 100644 --- a/Detectors/TPC/base/test/testTPCParameters.cxx +++ b/Detectors/TPC/base/test/testTPCParameters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -228,9 +229,9 @@ BOOST_AUTO_TEST_CASE(ParameterGEM_test1) BOOST_CHECK_CLOSE(ParameterGEM::Instance().AbsoluteGain[1], 8.f, 1e-3); BOOST_CHECK_CLOSE(ParameterGEM::Instance().AbsoluteGain[2], 53.f, 1e-3); BOOST_CHECK_CLOSE(ParameterGEM::Instance().AbsoluteGain[3], 240.f, 1e-3); - BOOST_CHECK_CLOSE(ParameterGEM::Instance().TotalGainStack, 1644.f, 1e-3); - BOOST_CHECK_CLOSE(ParameterGEM::Instance().KappaStack, 1.2295f, 1e-3); - BOOST_CHECK_CLOSE(ParameterGEM::Instance().EfficiencyStack, 0.473805f, 1e-3); + BOOST_CHECK_CLOSE(ParameterGEM::Instance().TotalGainStack, 2000.f, 1e-3); + BOOST_CHECK_CLOSE(ParameterGEM::Instance().KappaStack, 1.205f, 1e-3); + BOOST_CHECK_CLOSE(ParameterGEM::Instance().EfficiencyStack, 0.528f, 1e-3); BOOST_CHECK(ParameterGEM::Instance().AmplMode == AmplificationMode::EffectiveMode); BOOST_CHECK(o2::conf::ConfigurableParam::getValueAs<int>("TPCGEMParam.Geometry[0]") == 0); @@ -255,9 +256,9 @@ BOOST_AUTO_TEST_CASE(ParameterGEM_test1) BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.AbsoluteGain[1]"), 8.f, 1e-3); BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.AbsoluteGain[2]"), 53.f, 1e-3); BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.AbsoluteGain[3]"), 240.f, 1e-3); - BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.TotalGainStack"), 1644.f, 1e-3); - BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.KappaStack"), 1.2295f, 1e-3); - BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.EfficiencyStack"), 0.473805f, 1e-3); + BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.TotalGainStack"), 2000.f, 1e-3); + BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.KappaStack"), 1.205f, 1e-3); + BOOST_CHECK_CLOSE(o2::conf::ConfigurableParam::getValueAs<float>("TPCGEMParam.EfficiencyStack"), 0.528f, 1e-3); // For fixed values BOOST_CHECK_CLOSE(ParameterGEM::Instance().CollectionEfficiency[0], 1.f, 1e-3); diff --git a/Detectors/TPC/calibration/CMakeLists.txt b/Detectors/TPC/calibration/CMakeLists.txt index 6ecb2524b54cc..4fc42fd2f218a 100644 --- a/Detectors/TPC/calibration/CMakeLists.txt +++ b/Detectors/TPC/calibration/CMakeLists.txt @@ -1,16 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(SpacePoints) o2_add_library(TPCCalibration + TARGETVARNAME targetName SOURCES src/CalibRawBase.cxx src/CalibPedestal.cxx src/CalibPulser.cxx @@ -20,9 +22,24 @@ o2_add_library(TPCCalibration src/DigitDump.cxx src/DigitDumpParam.cxx src/CalibPadGainTracks.cxx + src/CalibLaserTracks.cxx + src/LaserTracksCalibrator.cxx + src/IDCAverageGroup.cxx + src/IDCGroup.cxx + src/IDCGroupHelperRegion.cxx + src/IDCGroupingParameter.cxx + src/IDCFactorization.cxx + src/IDCFourierTransformBase.cxx + src/IDCFourierTransform.cxx + src/RobustAverage.cxx + src/IDCCCDBHelper.cxx + src/dEdxHistos.cxx + src/CalibdEdx.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase O2::TPCReconstruction ROOT::Minuit - ms_gsl::ms_gsl) + Microsoft.GSL::GSL + O2::DetectorsCalibration + O2::CCDB) o2_target_root_dictionary(TPCCalibration HEADERS include/TPCCalibration/CalibRawBase.h @@ -34,12 +51,27 @@ o2_target_root_dictionary(TPCCalibration include/TPCCalibration/DigitDump.h include/TPCCalibration/DigitDumpParam.h include/TPCCalibration/CalibPadGainTracks.h - include/TPCCalibration/FastHisto.h) + include/TPCCalibration/FastHisto.h + include/TPCCalibration/CalibLaserTracks.h + include/TPCCalibration/LaserTracksCalibrator.h + include/TPCCalibration/IDCAverageGroup.h + include/TPCCalibration/IDCGroup.h + include/TPCCalibration/IDCGroupHelperRegion.h + include/TPCCalibration/IDCGroupHelperSector.h + include/TPCCalibration/IDCFactorization.h + include/TPCCalibration/IDCGroupingParameter.h + include/TPCCalibration/IDCContainer.h + include/TPCCalibration/RobustAverage.h + include/TPCCalibration/IDCFourierTransformBase.h + include/TPCCalibration/IDCFourierTransform.h + include/TPCCalibration/IDCCCDBHelper.h + include/TPCCalibration/dEdxHistos.h + include/TPCCalibration/CalibdEdx.h) -o2_add_executable(calib-pedestal +o2_add_executable(dcs-sim-workflow COMPONENT_NAME tpc - SOURCES run/calib-pedestal.cxx - PUBLIC_LINK_LIBRARIES O2::TPCCalibration O2::Framework O2::DPLUtils) + SOURCES testWorkflow/tpc-dcs-sim-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::DCStestWorkflow) o2_add_test_root_macro(macro/comparePedestalsAndNoise.C PUBLIC_LINK_LIBRARIES O2::TPCBase @@ -72,3 +104,21 @@ o2_add_test_root_macro(macro/extractGainMap.C o2_add_test_root_macro(macro/preparePedestalFiles.C PUBLIC_LINK_LIBRARIES O2::TPCCalibration LABELS tpc) +o2_add_test_root_macro(macro/makeTPCCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS + LABELS tpc) + +o2_add_test(IDCFourierTransform + COMPONENT_NAME calibration + PUBLIC_LINK_LIBRARIES O2::TPCCalibration + SOURCES test/testO2TPCIDCFourierTransform.cxx + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + LABELS tpc + CONFIGURATIONS RelWithDebInfo Release MinRelSize) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() + +target_link_libraries(${targetName} PRIVATE FFTW3::fftw3f) diff --git a/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt b/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt index 5e6ddbeafe346..cb3ffa6ad15f7 100644 --- a/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt +++ b/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(SpacePoints SOURCES src/SpacePointsCalibParam.cxx @@ -14,14 +15,16 @@ o2_add_library(SpacePoints src/TrackInterpolation.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase + O2::TRDBase O2::TPCReconstruction O2::TPCFastTransformation O2::DataFormatsITS O2::DataFormatsITSMFT - O2::DataFormatsTOF) + O2::DataFormatsTRD + O2::DataFormatsTOF + O2::DataFormatsGlobalTracking) o2_target_root_dictionary(SpacePoints - HEADERS include/SpacePoints/SpacePointsCalibParam.h - include/SpacePoints/TrackResiduals.h + HEADERS include/SpacePoints/TrackResiduals.h include/SpacePoints/TrackInterpolation.h LINKDEF src/SpacePointCalibLinkDef.h) diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibParam.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibParam.h index 4f1eeb9be16bb..14200028759f4 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibParam.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -55,6 +56,7 @@ static constexpr int NPadRows = o2::tpc::constants::MAXGLOBALPADROW; static constexpr int NROCTypes = 4; static constexpr int NRowsPerROC[NROCTypes] = {63, 34, 30, 25}; static constexpr int NRowsAccumulated[NROCTypes] = {63, 97, 127, 152}; +static constexpr float ZLimit[2] = {2.49725e2f, 2.49698e2f}; ///< max z-positions for A/C side static constexpr float RowDX[NROCTypes] = {.75f, 1.f, 1.2f, 1.5f}; static constexpr float MinX = 84.85f; static constexpr float MaxX = 246.4f; diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h index 0ff93475cb93e..16405e5eb88b6 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,19 +23,27 @@ #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsITSMFT/Cluster.h" #include "DataFormatsITS/TrackITS.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/Constants.h" #include "DataFormatsTOF/Cluster.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" #include "SpacePoints/SpacePointsCalibParam.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DetectorsBase/Propagator.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "TRDBase/RecoParam.h" +#include "TRDBase/Geometry.h" class TTree; namespace o2 { + namespace tpc { @@ -60,7 +69,7 @@ struct TPCClusterResiduals { /// Structure filled for each track with track quality information and a vector with TPCClusterResiduals struct TrackData { - int trkId{}; ///< track ID for debugging + o2::dataformats::GlobalTrackID gid{}; ///< global track ID for seeding track float eta{}; ///< track dip angle float phi{}; ///< track azimuthal angle float qPt{}; ///< track q/pT @@ -69,10 +78,9 @@ struct TrackData { unsigned short nClsTPC{}; ///< number of attached TPC clusters unsigned short nClsITS{}; ///< number of attached ITS clusters unsigned short nTrkltsTRD{}; ///< number of attached TRD tracklets - // TODO: Add an additional structure with event information and reference to the tracks for given event? - int nTracksInEvent{}; ///< total number of tracks in given event / timeframe ? Used for multiplicity estimate + unsigned short clAvailTOF{}; ///< whether or not track seed has a matched TOF cluster o2::dataformats::RangeReference<> clIdx{}; ///< index of first cluster residual and total number of cluster residuals of this track - ClassDefNV(TrackData, 1); + ClassDefNV(TrackData, 2); }; /// \class TrackInterpolation @@ -116,27 +124,15 @@ class TrackInterpolation void init(); /// Main processing function - void process(); + void process(const o2::globaltracking::RecoContainer& inp, const std::vector<o2::dataformats::GlobalTrackID>& gids, const std::vector<o2::globaltracking::RecoContainer::GlobalIDSet>& gidTables, std::vector<o2::track::TrackParCov>& seeds, const std::vector<float>& trkTimes); /// Extrapolate ITS-only track through TPC and store residuals to TPC clusters along the way - /// \param trkITS ITS only track to be extrapolated - /// \param trkTPC TPC track matched to trkITS used for TPC cluster access - /// \param trkTime time assigned to TPC track (needed for cluster coordinate transformation) - /// \param trkIdTPC TPC track ID - /// \return flag if track could successfully be extrapolated to all TPC clusters - bool extrapolateTrackITS(const o2::its::TrackITS& trkITS, const TrackTPC& trkTPC, float trkTime, int trkIdTPC); - - /// Interpolate ITS-TPC-TOF tracks in the TPC and store residuals to TPC clusters - /// \param matchTOF - /// \return flag if track could be processed successfully - bool interpolateTrackITSTOF(const o2::dataformats::MatchInfoTOF& matchTOF); - - /// Check if given ITS-TPC track fullfills quality criteria - /// \param matchITSTPC ITS-TPC track to be checked - /// \param hasOuterPoint Flag if track has an attached cluster in TRD or TOF - /// \return Flag if quality criteria are met - bool trackPassesQualityCuts(const o2::dataformats::TrackTPCITS& matchITSTPC, bool hasOuterPoint = true) const; + /// \param seed index + void extrapolateTrack(int iSeed); + /// Interpolate ITS-TRD-TOF track inside TPC and store residuals to TPC clusters along the way + /// \param seed index + void interpolateTrack(int iSeed); /// Reset cache and output vectors void reset(); @@ -149,25 +145,6 @@ class TrackInterpolation void setMaxStep(float step) { mMaxStep = step; } /// Sets the flag if material correction should be applied when extrapolating the tracks void setMatCorr(MatCorrType matCorr) { mMatCorr = matCorr; } - /// Sets whether ITS tracks without match in TRD or TOF should be processed as well - void setDoITSOnlyTracks(bool flag) { mDoITSOnlyTracks = flag; } - - // --------------------------------- input --------------------------------------------- - - /// Sets input ITS tracks received via DPL - void setITSTracksInp(const gsl::span<const o2::its::TrackITS> inp) { mITSTracksArray = inp; } - /// Sets input ITS-TPC matched tracks received via DPL - void setITSTPCTrackMatchesInp(const gsl::span<const o2::dataformats::TrackTPCITS> inp) { mITSTPCTracksArray = inp; } - /// Sets input TPC tracks received via DPL - void setTPCTracksInp(const gsl::span<const o2::tpc::TrackTPC> inp) { mTPCTracksArray = inp; } - /// Sets input TPC track cluster indices received via DPL - void setTPCTrackClusIdxInp(const gsl::span<const o2::tpc::TPCClRefElem> inp) { mTPCTracksClusIdx = inp; } - /// Sets input TPC clusters received via DPL - void setTPCClustersInp(const o2::tpc::ClusterNativeAccess* inp) { mTPCClusterIdxStruct = inp; } - /// Sets input TOF matching records received via DPL - void setTOFMatchesInp(const gsl::span<const o2::dataformats::MatchInfoTOF> inp) { mTOFMatchesArray = inp; } - /// Sets input TOF clusters received via DPL - void setTOFClustersInp(const gsl::span<const o2::tof::Cluster> inp) { mTOFClustersArray = inp; } // --------------------------------- output --------------------------------------------- std::vector<TPCClusterResiduals>& getClusterResiduals() { return mClRes; } @@ -180,16 +157,16 @@ class TrackInterpolation float mMaxSnp{.85f}; ///< max snp when propagating ITS tracks float mMaxStep{2.f}; ///< maximum step for propagation MatCorrType mMatCorr{MatCorrType::USEMatCorrNONE}; ///< if material correction should be done - bool mDoITSOnlyTracks{false}; ///< if ITS only tracks should be processed or not + o2::trd::RecoParam mRecoParam; ///< parameters required for TRD refit + o2::trd::Geometry* mGeoTRD; ///< TRD geometry instance (needed for tilted pad correction) // input - gsl::span<const o2::dataformats::TrackTPCITS> mITSTPCTracksArray; ///< input ITS-TPC matched tracks from span - gsl::span<const TrackTPC> mTPCTracksArray; ///< input TPC tracks from span - gsl::span<const TPCClRefElem> mTPCTracksClusIdx; ///< input TPC tracks cluster indicies from span - gsl::span<const o2::its::TrackITS> mITSTracksArray; ///< input ITS tracks from span - gsl::span<const o2::dataformats::MatchInfoTOF> mTOFMatchesArray; ///< input ITS-TPC-TOF matching information from span - gsl::span<const o2::tof::Cluster> mTOFClustersArray; ///< input TOF clusters from span - + const o2::globaltracking::RecoContainer* mRecoCont = nullptr; ///< input reco container + const std::vector<o2::dataformats::GlobalTrackID>* mGIDs = nullptr; ///< GIDs of input tracks + const std::vector<o2::globaltracking::RecoContainer::GlobalIDSet>* mGIDtables = nullptr; ///< GIDs of contributors from single detectors for each seed + const std::vector<float>* mTrackTimes = nullptr; ///< time estimates for all input tracks in micro seconds + std::vector<o2::track::TrackParCov>* mSeeds = nullptr; ///< seeding track parameters (ITS tracks) + gsl::span<const TPCClRefElem> mTPCTracksClusIdx; ///< input TPC cluster indices from span const ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices // output @@ -198,10 +175,13 @@ class TrackInterpolation // cache std::array<CacheStruct, constants::MAXGLOBALPADROW> mCache{{}}; ///< caching positions, covariances and angles for track extrapolations and interpolation + std::vector<o2::dataformats::GlobalTrackID> mGIDsSuccess; ///< keep track of the GIDs which could be processed successfully // helpers std::unique_ptr<TPCFastTransform> mFastTransform{}; ///< TPC cluster transformation bool mInitDone{false}; ///< initialization done flag + + ClassDefNV(TrackInterpolation, 1); }; } // namespace tpc diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h index 5be72b9045e5e..45127d38cc3da 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #ifndef ALICEO2_TPC_TRACKRESIDUALS_H_ #define ALICEO2_TPC_TRACKRESIDUALS_H_ -#define TPC_RUN2 +//#define TPC_RUN2 #include <memory> #include <vector> @@ -77,6 +78,7 @@ class TrackResiduals /// Structure which gets filled with the results for each voxel struct VoxRes { + VoxRes() = default; std::array<float, ResDim> D{}; ///< values of extracted distortions std::array<float, ResDim> E{}; ///< their errors std::array<float, ResDim> DS{}; ///< smoothed residual @@ -92,9 +94,10 @@ class TrackResiduals /// Structure for local residuals (y/z position, dip angle, voxel identifier) struct LocalResid { - short dy; ///< residual in y, ranges from -param::sMaxResid to +param::sMaxResid - short dz; ///< residual in z, ranges from -param::sMaxResid to +param::sMaxResid - short tgSlp; ///< track dip angle, ranges from -param::sMaxAngle to +param::sMaxAngle + LocalResid() = default; + short dy{0}; ///< residual in y, ranges from -param::sMaxResid to +param::sMaxResid + short dz{0}; ///< residual in z, ranges from -param::sMaxResid to +param::sMaxResid + short tgSlp{0}; ///< track dip angle, ranges from -param::sMaxAngle to +param::sMaxAngle std::array<unsigned char, VoxDim> bvox{}; ///< voxel identifier: VoxZ, VoxF, VoxX }; @@ -116,6 +119,7 @@ class TrackResiduals }; struct DebugOutliers { + DebugOutliers() = default; int idx{-1}; std::array<float, param::NPadRows> x{}; std::array<float, param::NPadRows> xFlagged{}; @@ -153,6 +157,14 @@ class TrackResiduals // -------------------------------------- steering functions -------------------------------------------------- + /// Load input from file + void loadInputFromFile(); + + /// Set input directly + /// \param trkData Vector with seeding track information (contains range ref to related TPC cluster residuals) + /// \param clResiduals Vector of all TPC cluster residuals + void setInputData(std::vector<TrackData>& trkData, std::vector<TPCClusterResiduals>& clResiduals); + /// Build local residual trees from Run 2 legacy data in the same way as in AliRoot void buildLocalResidualTreesFromRun2Data(); @@ -169,7 +181,8 @@ class TrackResiduals void writeLocalResidualTreesToFile(); /// Loads residual data from track interpolation and fills voxel data structures local residuals - void convertToLocalResiduals(); + /// \param loadFromFile Flag if the input should be read from a file. If not, setInputData() must be called before + void convertToLocalResiduals(bool loadFromFile = false); /// Steers the processing of the residuals for all sectors. void processResiduals(); @@ -519,7 +532,7 @@ class TrackResiduals static constexpr int sMaxSmtDim{7}; ///< max matrix size for smoothing (pol2) // input data - std::unique_ptr<TFile> mFileIn{}; ///< input file with residuals data + std::unique_ptr<TFile> mFileIn; ///< input file with residuals data TTree* mTreeInTracks{nullptr}; ///< tree with input track information std::vector<TrackData> mTrackData{}; ///< vector with input track information std::vector<TrackData>* mTrackDataPtr{&mTrackData}; ///< pointer to mTrackData @@ -527,8 +540,8 @@ class TrackResiduals std::vector<TPCClusterResiduals> mClRes{}; ///< vector with TPC cluster residuals std::vector<TPCClusterResiduals>* mClResPtr{&mClRes}; ///< pointer to mClRes // output data - std::unique_ptr<TFile> mFileOut{}; ///< output debug file - std::unique_ptr<TTree> mTreeOut{}; ///< tree holding debug output + std::unique_ptr<TFile> mFileOut; ///< output debug file + std::unique_ptr<TTree> mTreeOut; ///< tree holding debug output // status flags bool mIsInitialized{}; ///< initialize only once bool mPrintMem{}; ///< turn on to print memory usage at certain points @@ -594,7 +607,7 @@ class TrackResiduals std::string mPathToResidualFiles{"~/tmp/"}; ///< path to folder with Run 2 cluster residual data std::string mResidualDataFileName{"ResidualTrees.root"}; ///< filename of Run 2 cluster residual data std::string mResidualDataTreeName{"delta"}; ///< name of tree with cluster residuals - DeltaStruct mDeltaStruct; ///< helper structure to access the data stored in the residual tree + DeltaStruct mDeltaStruct{}; ///< helper structure to access the data stored in the residual tree std::unique_ptr<TChain> mRun2DeltaTree{}; ///< tree with Run 2 cluster residuals bool mFilterOutliers = true; ///< flag, if outliers from the cluster residual trees should be rejected int mNMALong{15}; ///< number of points to be used for moving average (long range) @@ -602,23 +615,25 @@ class TrackResiduals float mMaxRejFrac{.15f}; ///< if the fraction of rejected clusters of a track is higher, the full track is invalidated float mMaxRMSLong{.8f}; ///< maximum variance of the cluster residuals wrt moving avarage for a track to be considered // buffer arrays as in AliTPCDcalibRes - std::array<float, param::NPadRows> mArrX; ///< calculated cluster x position (pad row x) - std::array<float, param::NPadRows> mArrR; ///< cluster radius - std::array<float, param::NPadRows> mArrYTr; ///< reference track y (sector coordinates) - std::array<float, param::NPadRows> mArrZTr; ///< reference track z (sector coordinates) - std::array<float, param::NPadRows> mArrYCl; ///< cluster y (sector coordinates) - std::array<float, param::NPadRows> mArrZCl; ///< cluster z - std::array<float, param::NPadRows> mArrDZ; ///< cluster z residual - std::array<float, param::NPadRows> mArrDY; ///< cluster y residual - std::array<float, param::NPadRows> mArrPhi; ///< cluster phi angle (cluster residuals in Run 2 are stored in cluster frame instead of sector frame) - std::array<float, param::NPadRows> mArrTgSlp; ///< track inclination angle at pad row (azimuthal plane) - std::array<int, param::NPadRows> mArrSecId; ///< cluster sector ID + std::array<float, param::NPadRows> mArrX{}; ///< calculated cluster x position (pad row x) + std::array<float, param::NPadRows> mArrR{}; ///< cluster radius + std::array<float, param::NPadRows> mArrYTr{}; ///< reference track y (sector coordinates) + std::array<float, param::NPadRows> mArrZTr{}; ///< reference track z (sector coordinates) + std::array<float, param::NPadRows> mArrYCl{}; ///< cluster y (sector coordinates) + std::array<float, param::NPadRows> mArrZCl{}; ///< cluster z + std::array<float, param::NPadRows> mArrDZ{}; ///< cluster z residual + std::array<float, param::NPadRows> mArrDY{}; ///< cluster y residual + std::array<float, param::NPadRows> mArrPhi{}; ///< cluster phi angle (cluster residuals in Run 2 are stored in cluster frame instead of sector frame) + std::array<float, param::NPadRows> mArrTgSlp{}; ///< track inclination angle at pad row (azimuthal plane) + std::array<int, param::NPadRows> mArrSecId{}; ///< cluster sector ID float mQpt{0.f}; ///< fitted track q/pt float mTgl{0.f}; ///< fitted track dip angle int mNCl{0}; ///< number of clusters in the track // debugging std::vector<DebugOutliers> mOutVector{}; ///< this vector can be filled with data to stream it to a ROOT tree std::vector<DebugOutliers>* mOutVectorPtr{&mOutVector}; ///< pointer to set the branch address of the debug ROOT tree to + + ClassDefNV(TrackResiduals, 1); }; //_____________________________________________________ diff --git a/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h b/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h index 2ed783553e4ef..cb5fd51e6940a 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h +++ b/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/SpacePoints/src/SpacePointsCalibParam.cxx b/Detectors/TPC/calibration/SpacePoints/src/SpacePointsCalibParam.cxx index af61a01a92a42..a2d8606af065f 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/SpacePointsCalibParam.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/SpacePointsCalibParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx index c5073c92a5de6..125bc9ac759a7 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,18 +19,24 @@ #include "TPCBase/ParameterElectronics.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/Defs.h" +#include "DataFormatsTRD/Constants.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "TRDBase/PadPlane.h" +#include "TMath.h" #include <fairlogger/Logger.h> #include <set> using namespace o2::tpc; +using GTrackID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; void TrackInterpolation::init() { // perform initialization LOG(INFO) << "Start initializing TrackInterpolation"; if (mInitDone) { - LOG(error) << "Initialization already performed."; + LOG(ERROR) << "Initialization already performed."; return; } @@ -39,136 +46,70 @@ void TrackInterpolation::init() std::unique_ptr<TPCFastTransform> fastTransform = (TPCFastTransformHelperO2::instance()->create(0)); mFastTransform = std::move(fastTransform); + mRecoParam.setBfield(o2::base::Propagator::Instance()->getNominalBz()); + mGeoTRD = o2::trd::Geometry::instance(); + mInitDone = true; LOG(INFO) << "Done initializing TrackInterpolation"; } -void TrackInterpolation::process() +void TrackInterpolation::process(const o2::globaltracking::RecoContainer& inp, const std::vector<GTrackID>& gids, const std::vector<o2::globaltracking::RecoContainer::GlobalIDSet>& gidTables, std::vector<o2::track::TrackParCov>& seeds, const std::vector<float>& trkTimes) { // main processing function - if (!mInitDone) { - LOG(error) << "Initialization not yet done. Aborting..."; - return; - } - reset(); - #ifdef TPC_RUN2 // processing will not work if the run 2 geometry is defined in the parameter class SpacePointsCalibParam.h LOG(FATAL) << "Run 2 parameters compiled for the TPC geometry. Creating residual trees from Run 3 data will not work. Aborting..."; return; #endif - std::set<unsigned int> tracksDone; // to store indices of ITS-TPC matched tracks that have been processed - - LOG(INFO) << "Processing " << mTOFMatchesArray.size() << " ITS-TPC-TOF matched tracks out of " - << mITSTPCTracksArray.size() << " ITS-TPC matched tracks"; - - // TODO reserve only a fraction of the needed space for all tracks? How many tracks pass on average the quality cuts with how many TPC clusters? - mTrackData.reserve(mTOFMatchesArray.size()); - mClRes.reserve(mTOFMatchesArray.size() * param::NPadRows); + if (!mInitDone) { + LOG(error) << "Initialization not yet done. Aborting..."; + return; + } - int nTracksTPC = mTPCTracksArray.size(); + // reset output vectors + reset(); - for (const auto& trkTOF : mTOFMatchesArray) { - // process ITS-TPC-TOF matched tracks - if (!trackPassesQualityCuts(mITSTPCTracksArray[trkTOF.getTrackIndex()])) { - LOG(DEBUG) << "Abandoning track due to bad quality"; - continue; - } - mTrackData.emplace_back(); - if (!interpolateTrackITSTOF(trkTOF)) { - LOG(DEBUG) << "Failed to interpolate ITS-TOF track"; - mTrackData.pop_back(); - continue; - } - mTrackData.back().nTracksInEvent = nTracksTPC; - tracksDone.insert(trkTOF.getTrackIndex()); - } + // set the input containers + mRecoCont = &inp; + mGIDs = &gids; + mGIDtables = &gidTables; + mSeeds = &seeds; + mTrackTimes = &trkTimes; + mTPCTracksClusIdx = mRecoCont->getTPCTracksClusterRefs(); + mTPCClusterIdxStruct = &mRecoCont->getTPCClusters(); - LOG(INFO) << "Could process " << tracksDone.size() << " ITS-TPC-TOF matched tracks successfully"; + int nSeeds = mSeeds->size(); + mTrackData.reserve(nSeeds); + mClRes.reserve(nSeeds * param::NPadRows); - if (mDoITSOnlyTracks) { - size_t nTracksDoneITS = 0; - size_t nTracksSkipped = 0; - for (std::size_t iTrk = 0; iTrk < mITSTPCTracksArray.size(); ++iTrk) { - // process ITS-TPC matched tracks that were not matched to TOF - if (tracksDone.find(iTrk) != tracksDone.end()) { - // track also has a matching cluster in TOF and has already been processed - ++nTracksSkipped; - continue; - } - const auto& trk = mITSTPCTracksArray[iTrk]; - if (!trackPassesQualityCuts(trk, false)) { - continue; - } - mTrackData.emplace_back(); - const auto& trkTPC = mTPCTracksArray[trk.getRefTPC()]; - const auto& trkITS = mITSTracksArray[trk.getRefITS()]; - if (!extrapolateTrackITS(trkITS, trkTPC, trk.getTimeMUS().getTimeStamp(), trk.getRefTPC())) { - mTrackData.pop_back(); - continue; - } - mTrackData.back().nTracksInEvent = nTracksTPC; - ++nTracksDoneITS; + for (int iSeed = 0; iSeed < nSeeds; ++iSeed) { + if (gids[iSeed].includesDet(DetID::TRD) || gids[iSeed].includesDet(DetID::TOF)) { + interpolateTrack(iSeed); + } else { + extrapolateTrack(iSeed); } - LOG(INFO) << "Could process " << nTracksDoneITS << " ITS-TPC matched tracks successfully"; - LOG(INFO) << "Skipped " << nTracksSkipped << " tracks, as they were successfully propagated to TOF"; } -} -bool TrackInterpolation::trackPassesQualityCuts(const o2::dataformats::TrackTPCITS& matchITSTPC, bool hasOuterPoint) const -{ - // apply track quality cuts (assume different settings for track with and without points in TRD or TOF) - const auto& trkTPC = mTPCTracksArray[matchITSTPC.getRefTPC()]; - const auto& trkITS = mITSTracksArray[matchITSTPC.getRefITS()]; - if (hasOuterPoint) { - // track has a match in TRD or TOF - if (trkTPC.getNClusterReferences() < param::MinTPCNCls || - trkITS.getNumberOfClusters() < param::MinITSNCls) { - LOG(DEBUG) << "TPC clusters (" << trkTPC.getNClusterReferences() << "), ITS clusters(" << trkITS.getNumberOfClusters() << ")"; - return false; - } - if (trkTPC.getChi2() / trkTPC.getNClusterReferences() > param::MaxTPCChi2 || - trkITS.getChi2() / trkITS.getNumberOfClusters() > param::MaxITSChi2) { - LOG(DEBUG) << "TPC reduced chi2 (" << trkTPC.getChi2() / trkTPC.getNClusterReferences() << "), ITS reduced chi2 (" << trkITS.getChi2() / trkITS.getNumberOfClusters() << ")"; - return false; - } - } else { - // ITS-TPC only track - if (trkTPC.getNClusterReferences() < param::MinTPCNClsNoOuterPoint || - trkITS.getNumberOfClusters() < param::MinITSNClsNoOuterPoint) { - return false; - } - if (trkTPC.getChi2() / trkTPC.getNClusterReferences() > param::MaxTPCChi2 || - trkITS.getChi2() / trkITS.getNumberOfClusters() > param::MaxITSChi2) { - return false; - } - } - return true; + LOG(INFO) << "Could process " << mTrackData.size() << " tracks successfully"; } -bool TrackInterpolation::interpolateTrackITSTOF(const o2::dataformats::MatchInfoTOF& matchTOF) +void TrackInterpolation::interpolateTrack(int iSeed) { - // get TPC cluster residuals to ITS-TOF only tracks - size_t trkIdx = mTrackData.size() - 1; + TrackData trackData; auto propagator = o2::base::Propagator::Instance(); - const auto& matchITSTPC = mITSTPCTracksArray[matchTOF.getTrackIndex()]; - const auto& clTOF = mTOFClustersArray[matchTOF.getTOFClIndex()]; - //const int clTOFSec = (TMath::ATan2(-clTOF.getY(), -clTOF.getX()) + o2::constants::math::PI) * o2::constants::math::Rad2Deg * 0.05; // taken from TOF cluster class as there is no const getter for the sector - const int clTOFSec = clTOF.getCount(); - const float clTOFAlpha = o2::math_utils::sector2Angle(clTOFSec); - const auto& trkTPC = mTPCTracksArray[matchITSTPC.getRefTPC()]; - const auto& trkITS = mITSTracksArray[matchITSTPC.getRefITS()]; - auto trkWork = trkITS.getParamOut(); - // reset the cache array (sufficient to set ) + const auto& gidTable = (*mGIDtables)[iSeed]; + const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]); + const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]); + auto& trkWork = (*mSeeds)[iSeed]; + // reset the cache array (sufficient to set cluster available to zero) for (auto& elem : mCache) { elem.clAvailable = 0; } - mTrackData[trkIdx].clIdx.setFirstEntry(mClRes.size()); // reference the first cluster residual belonging to this track - //printf("=== New Track with pt = %.3f, nClsTPC = %i ===\n", trkWork.getQ2Pt(), trkTPC.getNClusterReferences()); + trackData.clIdx.setFirstEntry(mClRes.size()); // reference the first cluster residual belonging to this track + float clusterTimeBinOffset = (*mTrackTimes)[iSeed] / mTPCTimeBinMUS; // store the TPC cluster positions in the cache - float clusterTimeBinOffset = matchITSTPC.getTimeMUS().getTimeStamp() / mTPCTimeBinMUS; for (int iCl = trkTPC.getNClusterReferences(); iCl--;) { uint8_t sector, row; uint32_t clusterIndexInRow; @@ -183,18 +124,18 @@ bool TrackInterpolation::interpolateTrackITSTOF(const o2::dataformats::MatchInfo mCache[row].clAngle = o2::math_utils::sector2Angle(sector); } - // first extrapolate through TPC and store track position at each pad row + // extrapolate seed through TPC and store track position at each pad row for (int iRow = 0; iRow < param::NPadRows; ++iRow) { if (!mCache[iRow].clAvailable) { continue; } if (!trkWork.rotate(mCache[iRow].clAngle)) { LOG(DEBUG) << "Failed to rotate track during first extrapolation"; - return false; + return; } - if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], o2::constants::physics::MassPionCharged, mMaxSnp, mMaxStep, mMatCorr)) { + if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mMaxSnp, mMaxStep, mMatCorr)) { LOG(DEBUG) << "Failed on first extrapolation"; - return false; + return; } mCache[iRow].y[ExtOut] = trkWork.getY(); mCache[iRow].z[ExtOut] = trkWork.getZ(); @@ -206,25 +147,70 @@ bool TrackInterpolation::interpolateTrackITSTOF(const o2::dataformats::MatchInfo //printf("Track alpha at row %i: %.2f, Y(%.2f), Z(%.2f)\n", iRow, trkWork.getAlpha(), trkWork.getY(), trkWork.getZ()); } - // now continue to TOF and update track with TOF cluster - if (!trkWork.rotate(clTOFAlpha)) { - LOG(DEBUG) << "Failed to rotate into TOF cluster sector frame"; - return false; - } - //float ca, sa; - //o2::math_utils::sincos(clTOFAlpha, sa, ca); - //float clTOFX = clTOF.getX() * ca + clTOF.getY() * sa; // cluster x in sector coordinate frame - //std::array<float, 2> clTOFYZ{ -clTOF.getX() * sa + clTOF.getY() * ca, clTOF.getZ() }; // cluster y and z in sector coordinate frame - float clTOFX = clTOF.getX(); - std::array<float, 2> clTOFYZ{clTOF.getY(), clTOF.getZ()}; - std::array<float, 3> clTOFCov{mSigYZ2TOF, 0.f, mSigYZ2TOF}; // assume no correlation between y and z and equal cluster error sigma^2 = (3cm)^2 / 12 - if (!propagator->PropagateToXBxByBz(trkWork, clTOFX, o2::constants::physics::MassPionCharged, mMaxSnp, mMaxStep, mMatCorr)) { - LOG(DEBUG) << "Failed final propagation to TOF radius"; - return false; + // start from outermost cluster with outer refit and back propagation + if (gidTable[GTrackID::TOF].isIndexSet()) { + LOG(DEBUG) << "TOF point available"; + const auto& clTOF = mRecoCont->getTOFClusters()[gidTable[GTrackID::TOF]]; + const int clTOFSec = clTOF.getCount(); + const float clTOFAlpha = o2::math_utils::sector2Angle(clTOFSec); + if (!trkWork.rotate(clTOFAlpha)) { + LOG(DEBUG) << "Failed to rotate into TOF cluster sector frame"; + return; + } + float clTOFX = clTOF.getX(); + std::array<float, 2> clTOFYZ{clTOF.getY(), clTOF.getZ()}; + std::array<float, 3> clTOFCov{mSigYZ2TOF, 0.f, mSigYZ2TOF}; // assume no correlation between y and z and equal cluster error sigma^2 = (3cm)^2 / 12 + if (!propagator->PropagateToXBxByBz(trkWork, clTOFX, mMaxSnp, mMaxStep, mMatCorr)) { + LOG(DEBUG) << "Failed final propagation to TOF radius"; + return; + } + // TODO: check if reset of covariance matrix is needed here (or, in case TOF point is not available at outermost TRD layer) + if (!trkWork.update(clTOFYZ, clTOFCov)) { + LOG(DEBUG) << "Failed to update extrapolated ITS track with TOF cluster"; + //LOGF(INFO, "trkWork.y=%f, cl.y=%f, trkWork.z=%f, cl.z=%f", trkWork.getY(), clTOFYZ[0], trkWork.getZ(), clTOFYZ[1]); + return; + } } - if (!trkWork.update(clTOFYZ, clTOFCov)) { - LOG(DEBUG) << "Failed to update extrapolated ITS track with TOF cluster"; - return false; + if (gidTable[GTrackID::TRD].isIndexSet()) { + LOG(DEBUG) << "TRD available"; + const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::TRD]); + for (int iLayer = o2::trd::constants::NLAYER - 1; iLayer >= 0; --iLayer) { + int trkltIdx = trkTRD.getTrackletIndex(iLayer); + if (trkltIdx < 0) { + // no TRD tracklet in this layer + continue; + } + const auto& trdSP = mRecoCont->getTRDCalibratedTracklets()[trkltIdx]; + const auto& trdTrklt = mRecoCont->getTRDTracklets()[trkltIdx]; + auto trkltDet = trdTrklt.getDetector(); + auto trkltSec = trkltDet / (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK); + if (trkltSec != o2::math_utils::angle2Sector(trkWork.getAlpha())) { + if (!trkWork.rotate(o2::math_utils::sector2Angle(trkltSec))) { + LOG(DEBUG) << "Track could not be rotated in TRD tracklet coordinate system in layer " << iLayer; + return; + } + } + if (!propagator->PropagateToXBxByBz(trkWork, trdSP.getX(), mMaxSnp, mMaxStep, mMatCorr)) { + LOG(DEBUG) << "Failed propagation to TRD layer " << iLayer; + return; + } + + const auto* pad = mGeoTRD->getPadPlane(trkltDet); + float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees + float tiltCorrUp = tilt * (trdSP.getZ() - trkWork.getZ()); + float zPosCorrUp = trdSP.getZ() + mRecoParam.getZCorrCoeffNRC() * trkWork.getTgl(); // maybe Z can be corrected on avarage already by the tracklet transformer? + float padLength = pad->getRowSize(trdTrklt.getPadRow()); + if (!((trkWork.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(trdSP.getZ() - trkWork.getZ()) < padLength))) { + tiltCorrUp = 0.f; + } + std::array<float, 2> trkltTRDYZ{trdSP.getY() - tiltCorrUp, zPosCorrUp}; + std::array<float, 3> trkltTRDCov; + mRecoParam.recalcTrkltCov(tilt, trkWork.getSnp(), pad->getRowSize(trdTrklt.getPadRow()), trkltTRDCov); + if (!trkWork.update(trkltTRDYZ, trkltTRDCov)) { + LOG(DEBUG) << "Failed to update track at TRD layer " << iLayer; + return; + } + } } // go back through the TPC and store updated track positions @@ -234,12 +220,12 @@ bool TrackInterpolation::interpolateTrackITSTOF(const o2::dataformats::MatchInfo } if (!trkWork.rotate(mCache[iRow].clAngle)) { LOG(DEBUG) << "Failed to rotate track during back propagation"; - return false; + return; } - if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], o2::constants::physics::MassPionCharged, mMaxSnp, mMaxStep, mMatCorr)) { + if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mMaxSnp, mMaxStep, mMatCorr)) { LOG(DEBUG) << "Failed on back propagation"; //printf("trkX(%.2f), clX(%.2f), clY(%.2f), clZ(%.2f), alphaTOF(%.2f)\n", trkWork.getX(), param::RowX[iRow], clTOFYZ[0], clTOFYZ[1], clTOFAlpha); - return false; + return; } mCache[iRow].y[ExtIn] = trkWork.getY(); mCache[iRow].z[ExtIn] = trkWork.getZ(); @@ -282,27 +268,32 @@ bool TrackInterpolation::interpolateTrackITSTOF(const o2::dataformats::MatchInfo deltaRow = 1; } - mTrackData[trkIdx].trkId = matchITSTPC.getRefTPC(); - mTrackData[trkIdx].eta = trkTPC.getEta(); - mTrackData[trkIdx].phi = trkTPC.getSnp(); - mTrackData[trkIdx].qPt = trkTPC.getQ2Pt(); - mTrackData[trkIdx].chi2TPC = trkTPC.getChi2(); - mTrackData[trkIdx].chi2ITS = trkITS.getChi2(); - mTrackData[trkIdx].nClsTPC = trkTPC.getNClusterReferences(); - mTrackData[trkIdx].nClsITS = trkITS.getNumberOfClusters(); - mTrackData[trkIdx].clIdx.setEntries(nMeasurements); + trackData.gid = (*mGIDs)[iSeed]; + trackData.eta = trkTPC.getEta(); + trackData.phi = trkTPC.getSnp(); + trackData.qPt = trkTPC.getQ2Pt(); + trackData.chi2TPC = trkTPC.getChi2(); + trackData.chi2ITS = trkITS.getChi2(); + trackData.nClsTPC = trkTPC.getNClusterReferences(); + trackData.nClsITS = trkITS.getNumberOfClusters(); + trackData.nTrkltsTRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::TRD]).getNtracklets() : 0; + trackData.clAvailTOF = gidTable[GTrackID::TOF].isIndexSet() ? 1 : 0; + trackData.clIdx.setEntries(nMeasurements); - LOG(DEBUG) << "Track interpolation successfull"; - return true; + mTrackData.push_back(std::move(trackData)); + mGIDsSuccess.push_back((*mGIDs)[iSeed]); } -bool TrackInterpolation::extrapolateTrackITS(const o2::its::TrackITS& trkITS, const TrackTPC& trkTPC, float trkTime, int trkIdTPC) +void TrackInterpolation::extrapolateTrack(int iSeed) { // extrapolate ITS-only track through TPC and store residuals to TPC clusters in the output vectors - size_t trkIdx = mTrackData.size() - 1; - mTrackData[trkIdx].clIdx.setFirstEntry(mClRes.size()); - auto trk = trkITS.getParamOut(); - float clusterTimeBinOffset = trkTime / mTPCTimeBinMUS; + const auto& gidTable = (*mGIDtables)[iSeed]; + TrackData trackData; + trackData.clIdx.setFirstEntry(mClRes.size()); + const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]); + const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]); + auto& trkWork = (*mSeeds)[iSeed]; + float clusterTimeBinOffset = (*mTrackTimes)[iSeed] / mTPCTimeBinMUS; auto propagator = o2::base::Propagator::Instance(); unsigned short rowPrev = 0; unsigned short nMeasurements = 0; @@ -312,41 +303,43 @@ bool TrackInterpolation::extrapolateTrackITS(const o2::its::TrackITS& trkITS, co const auto& cl = trkTPC.getCluster(mTPCTracksClusIdx, iCl, *mTPCClusterIdxStruct, sector, row); float x = 0, y = 0, z = 0; mFastTransform->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, clusterTimeBinOffset); - if (!trk.rotate(o2::math_utils::sector2Angle(sector))) { - return false; + if (!trkWork.rotate(o2::math_utils::sector2Angle(sector))) { + return; } - if (!propagator->PropagateToXBxByBz(trk, x, o2::constants::physics::MassPionCharged, mMaxSnp, mMaxStep, mMatCorr)) { - return false; + if (!propagator->PropagateToXBxByBz(trkWork, x, mMaxSnp, mMaxStep, mMatCorr)) { + return; } TPCClusterResiduals res; - res.setDY(y - trk.getY()); - res.setDY(z - trk.getZ()); - res.setY(trk.getY()); - res.setZ(trk.getZ()); - res.setPhi(trk.getSnp()); - res.setTgl(trk.getTgl()); - res.sec = o2::math_utils::angle2Sector(trk.getAlpha()); + res.setDY(y - trkWork.getY()); + res.setDY(z - trkWork.getZ()); + res.setY(trkWork.getY()); + res.setZ(trkWork.getZ()); + res.setPhi(trkWork.getSnp()); + res.setTgl(trkWork.getTgl()); + res.sec = o2::math_utils::angle2Sector(trkWork.getAlpha()); res.dRow = row - rowPrev; res.row = row; rowPrev = row; mClRes.push_back(std::move(res)); ++nMeasurements; } - mTrackData[trkIdx].trkId = trkIdTPC; - mTrackData[trkIdx].eta = trkTPC.getEta(); - mTrackData[trkIdx].phi = trkTPC.getSnp(); - mTrackData[trkIdx].qPt = trkTPC.getQ2Pt(); - mTrackData[trkIdx].chi2TPC = trkTPC.getChi2(); - mTrackData[trkIdx].chi2ITS = trkITS.getChi2(); - mTrackData[trkIdx].nClsTPC = trkTPC.getNClusterReferences(); - mTrackData[trkIdx].nClsITS = trkITS.getNumberOfClusters(); - mTrackData[trkIdx].clIdx.setEntries(nMeasurements); + trackData.gid = (*mGIDs)[iSeed]; + trackData.eta = trkTPC.getEta(); + trackData.phi = trkTPC.getSnp(); + trackData.qPt = trkTPC.getQ2Pt(); + trackData.chi2TPC = trkTPC.getChi2(); + trackData.chi2ITS = trkITS.getChi2(); + trackData.nClsTPC = trkTPC.getNClusterReferences(); + trackData.nClsITS = trkITS.getNumberOfClusters(); + trackData.clIdx.setEntries(nMeasurements); - return true; + mTrackData.push_back(std::move(trackData)); + mGIDsSuccess.push_back((*mGIDs)[iSeed]); } void TrackInterpolation::reset() { mTrackData.clear(); mClRes.clear(); + mGIDsSuccess.clear(); } diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackResiduals.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackResiduals.cxx index 76d23c027831d..c3c1c8b31df1d 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackResiduals.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackResiduals.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,6 +59,11 @@ using namespace o2::tpc; //______________________________________________________________________________ void TrackResiduals::init() { +#ifdef TPC_RUN2 + // Run 2 geometry should only be defined for tests with Run 2 data, i.e. not in production so we send an error message here + LOG(ERROR) << "Run 2 parameters compiled for the TPC geometry. Will lead to errors in case of processing residuals from O2."; +#endif + // initialize binning initBinning(); @@ -153,7 +159,7 @@ void TrackResiduals::initBinning() mDY2X[ix] = 1.f / mDY2XI[ix]; } if (mUniformBins[VoxF]) { - O2INFO("Y/X-binning is uniform with %i bins from -MaxY2X to +MaxY2X", mNY2XBins); + O2INFO("Y/X-binning is uniform with %i bins from -MaxY2X to +MaxY2X (values depend on X-bin)", mNY2XBins); for (int ip = 0; ip < mNY2XBins; ++ip) { mY2XBinsDH.push_back(1.f / mNY2XBins); mY2XBinsDI.push_back(.5f / mY2XBinsDH[ip]); @@ -166,7 +172,7 @@ void TrackResiduals::initBinning() mDZ2XI = mNZ2XBins / sMaxZ2X; mDZ2X = 1.0f / mDZ2XI; // for uniform case only if (mUniformBins[VoxZ]) { - O2INFO("Z/X-binning is uniform with %i bins from 0 to sMaxZ2X", mNY2XBins); + O2INFO("Z/X-binning is uniform with %i bins from 0 to %f", mNY2XBins, sMaxZ2X); for (int iz = 0; iz < mNZ2XBins; ++iz) { mZ2XBinsDH.push_back(.5f * mDZ2X); mZ2XBinsDI.push_back(mDZ2XI); @@ -176,6 +182,7 @@ void TrackResiduals::initBinning() } // mNVoxPerSector = mNY2XBins * mNZ2XBins * mNXBins; + O2INFO("Each TPC sector is divided into %i voxels", mNVoxPerSector); } //______________________________________________________________________________ @@ -252,7 +259,7 @@ int TrackResiduals::getRowID(float x) const } else if (x >= param::RowX[param::NRowsAccumulated[param::NROCTypes - 2]] - .5f * param::RowDX[param::NROCTypes - 1]) { // we are in the OROC3 ix = (x - (param::RowX[param::NRowsAccumulated[param::NROCTypes - 2]] - .5f * param::RowDX[param::NROCTypes - 1])) / param::RowDX[param::NROCTypes - 1] + param::NRowsAccumulated[param::NROCTypes - 2]; - if (ix >= param::nPadRows) { + if (ix >= param::NPadRows) { // x is larger than the outer radius of the last OROC pad row ix = -1; } @@ -713,15 +720,8 @@ void TrackResiduals::writeLocalResidualTreesToFile() } } -void TrackResiduals::convertToLocalResiduals() +void TrackResiduals::loadInputFromFile() { - // When using data generated with o2 without distortions the residuals can easily be converted - // without the need of outlier filtering (is this really true?). - // Probably a lot of the functionality from buildLocalResidualTreesFromRun2Data() have to be - // added here as well. - if (!mIsInitialized) { - init(); - } // open input file and access track data mFileIn = std::make_unique<TFile>(mInputFileNameResiduals.data(), "open"); if (!mFileIn) { @@ -743,24 +743,46 @@ void TrackResiduals::convertToLocalResiduals() } mTreeInClRes->SetBranchAddress("residuals", &mClResPtr); mTreeInClRes->GetEntry(0); +} + +void TrackResiduals::setInputData(std::vector<TrackData>& trkData, std::vector<TPCClusterResiduals>& clResiduals) +{ + mTrackDataPtr = &trkData; + mClResPtr = &clResiduals; +} + +void TrackResiduals::convertToLocalResiduals(bool loadFromFile) +{ + // When using data generated with o2 without distortions the residuals can easily be converted + // without the need of outlier filtering (is this really true?). + // Probably a lot of the functionality from buildLocalResidualTreesFromRun2Data() have to be + // added here as well. + if (!mIsInitialized) { + init(); + } + + if (loadFromFile) { + LOG(INFO) << "Loading TPC cluster residuals (unfiltered) from file."; + loadInputFromFile(); + } prepareLocalResidualTrees(); // loop over tracks - for (const auto& trk : mTrackData) { + for (const auto& trk : *mTrackDataPtr) { int iRow = 0; for (int iCl = 0; iCl < trk.clIdx.getEntries(); ++iCl) { int clIdx = trk.clIdx.getFirstEntry() + iCl; - int sec = mClRes[clIdx].z < 0 ? mClRes[clIdx].sec : mClRes[clIdx].sec + SECTORSPERSIDE; // sector numbering 0..35 a.k.a. A0..C17 + int sec = (*mClResPtr)[clIdx].z < 0 ? (*mClResPtr)[clIdx].sec : (*mClResPtr)[clIdx].sec + SECTORSPERSIDE; // sector numbering 0..35 a.k.a. A0..C17 std::array<unsigned char, VoxDim> bvox; - iRow += mClRes[clIdx].dRow; + iRow += (*mClResPtr)[clIdx].dRow; float xPos = param::RowX[iRow]; - if (!findVoxelBin(sec, xPos, mClRes[clIdx].y * param::MaxY / 0x7fff, mClRes[clIdx].z * param::MaxZ / 0x7fff, bvox)) { + if (!findVoxelBin(sec, xPos, (*mClResPtr)[clIdx].y * param::MaxY / 0x7fff, (*mClResPtr)[clIdx].z * param::MaxZ / 0x7fff, bvox)) { continue; } - mLocalResid.dy = mClRes[clIdx].dy; - mLocalResid.dz = mClRes[clIdx].dz; - mLocalResid.tgSlp = mClRes[clIdx].phi; + mLocalResid.dy = (*mClResPtr)[clIdx].dy; + mLocalResid.dz = (*mClResPtr)[clIdx].dz; + mLocalResid.tgSlp = (*mClResPtr)[clIdx].phi; mLocalResid.bvox = bvox; mTmpTree[sec]->Fill(); // TODO calculate mean position of clusters in each voxel (can be updated each time a new measurement is found inside voxel) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h new file mode 100644 index 0000000000000..53ea2f31d4661 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h @@ -0,0 +1,218 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibLaserTracks.h +/// \brief calibration using laser tracks +/// +/// This class associated tpc tracks with ideal laser track positions from the data base +/// The difference in z-Position, separately on the A- and C-Side, is then used to +/// calculate a drift velocity correction factor as well as the trigger offset. +/// A vector of mathced laser track IDs can be used to monitor the laser system alignment. +/// +/// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#ifndef TPC_CalibLaserTracks_H_ +#define TPC_CalibLaserTracks_H_ + +#include <gsl/span> + +#include "CommonConstants/MathConstants.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/LaserTrack.h" + +namespace o2::tpc +{ + +using o2::track::TrackPar; +using o2::track::TrackParCov; + +struct TimePair { + float x1{0.f}; + float x2{0.f}; + uint64_t time{0}; +}; + +struct LtrCalibData { + size_t processedTFs{}; ///< number of processed TFs with laser track candidates + uint64_t firstTime{}; ///< first time stamp of processed TFs + uint64_t lastTime{}; ///< last time stamp of processed TFs + float dvCorrectionA{}; ///< drift velocity correction factor A-Side + float dvCorrectionC{}; ///< drift velocity correction factor C-Side + float dvOffsetA{}; ///< drift velocity trigger offset A-Side + float dvOffsetC{}; ///< drift velocity trigger offset C-Side + uint16_t nTracksA{}; ///< number of tracks used for A-Side fit + uint16_t nTracksC{}; ///< number of tracks used for C-Side fit + std::vector<uint16_t> matchedLtrIDs; ///< list of matched laser track IDs + + float getDriftVCorrection() const { return 0.5f * (dvCorrectionA + dvCorrectionC); } + + void reset() + { + processedTFs = 0; + firstTime = 0; + lastTime = 0; + dvCorrectionA = 0; + dvCorrectionC = 0; + dvOffsetA = 0; + dvOffsetC = 0; + nTracksA = 0; + nTracksC = 0; + + matchedLtrIDs.clear(); + } + + ClassDefNV(LtrCalibData, 1); +}; + +class CalibLaserTracks +{ + public: + static constexpr size_t MinTrackPerSidePerTF = 50; + + CalibLaserTracks() + { + mLaserTracks.loadTracksFromFile(); + updateParameters(); + } + + CalibLaserTracks(const CalibLaserTracks& other) : mTriggerPos{other.mTriggerPos}, + mBz{other.mBz}, + mDriftV{other.mDriftV}, + mZbinWidth{other.mZbinWidth}, + mTFstart{other.mTFstart}, + mTFend{other.mTFend}, + mCalibDataTF{other.mCalibDataTF}, + mCalibData{other.mCalibData}, + mZmatchPairsTFA{other.mZmatchPairsTFA}, + mZmatchPairsTFC{other.mZmatchPairsTFC}, + mZmatchPairsA{other.mZmatchPairsA}, + mZmatchPairsC{other.mZmatchPairsC}, + mWriteDebugTree{other.mWriteDebugTree}, + mFinalized{other.mFinalized} + { + } + + ~CalibLaserTracks() = default; + + /// process all tracks of one TF + void fill(const gsl::span<const TrackTPC> tracks); + + /// process all tracks of one TF + void fill(std::vector<TrackTPC> const& tracks); + + /// process single track + void processTrack(const TrackTPC& track); + + /// try to associate track with ideal laser track + /// \return laser track ID; -1 in case of no match + int findLaserTrackID(TrackPar track, int side = -1); + + /// calculate phi of nearest laser rod + static float getPhiNearbyLaserRod(const TrackPar& param, int side); + + /// check if param is closer to a laser rod than 1/4 of a sector width + static bool hasNearbyLaserRod(const TrackPar& param, int side); + + /// trigger position for track z position correction + void setTriggerPos(int triggerPos) { mTriggerPos = triggerPos; } + + /// merge data with other calibration object + void merge(const CalibLaserTracks* other); + + /// End processing of this TF + void endTF(); + + /// Finalize full processing + void finalize(); + + /// print information + void print() const; + + /// check amount of data (to be improved) + /// at least numTFs with laser track candidate and MinTrackPerSidePerTF tracks per side per TF + bool hasEnoughData(size_t numTFs = 1) const { return mCalibData.processedTFs >= numTFs && mZmatchPairsA.size() > MinTrackPerSidePerTF * numTFs && mZmatchPairsC.size() > MinTrackPerSidePerTF * numTFs; } + + /// number of associated laser tracks on both sides for all processed TFs + size_t getMatchedPairs() const { return getMatchedPairsA() + getMatchedPairsC(); } + + /// number of associated laser tracks for all processed TFs on the A-Side + size_t getMatchedPairsA() const { return mZmatchPairsA.size(); } + + /// number of associated laser tracks for all processed TFs on the C-Side + size_t getMatchedPairsC() const { return mZmatchPairsC.size(); } + + /// number of associated laser tracks presently processed TFs on the A-Side + size_t getMatchedPairsTFA() const { return mZmatchPairsTFA.size(); } + + /// number of associated laser tracks presently processed TFs on the C-Side + size_t getMatchedPairsTFC() const { return mZmatchPairsTFC.size(); } + + /// time frame time of presently processed time frame + /// should be called before calling processTrack(s) + void setTFtimes(uint64_t tfStart, uint64_t tfEnd = 0) + { + mTFstart = tfStart; + mTFend = tfEnd; + } + + uint64_t getTFstart() const { return mTFstart; } + uint64_t getTFend() const { return mTFend; } + + void setWriteDebugTree(bool write) { mWriteDebugTree = write; } + bool getWriteDebugTree() const { return mWriteDebugTree; } + + /// extract DV correction and T0 offset + TimePair fit(const std::vector<TimePair>& trackMatches) const; + + /// sort TimePoint vectors + void sort(std::vector<TimePair>& trackMatches); + + /// drift velocity fit information for presently processed time frame + const LtrCalibData& getCalibDataTF() { return mCalibDataTF; } + + /// drift velocity fit information for full data set + const LtrCalibData& getCalibData() { return mCalibData; } + + /// name of the debug output tree + void setDebugOutputName(std::string_view name) { mDebugOutputName = name; } + + private: + int mTriggerPos{0}; ///< trigger position, if < 0 it treats it as the CE position + float mBz{0.5}; ///< Bz field in Tesla + float mDriftV{0}; ///< drift velocity used during reconstruction + float mZbinWidth{0}; ///< width of a bin in us + uint64_t mTFstart{0}; ///< start time of processed time frames + uint64_t mTFend{0}; ///< end time of processed time frames + LtrCalibData mCalibDataTF{}; ///< calibration data for single TF (debugging) + LtrCalibData mCalibData{}; ///< final calibration data + std::vector<TimePair> mZmatchPairsTFA; ///< ideal vs. mesured z positions in present time frame A-Side (debugging) + std::vector<TimePair> mZmatchPairsTFC; ///< ideal vs. mesured z positions in present time frame C-Side (debugging) + std::vector<TimePair> mZmatchPairsA; ///< ideal vs. mesured z positions assumulated over all time frames A-Side + std::vector<TimePair> mZmatchPairsC; ///< ideal vs. mesured z positions assumulated over all time frames C-Side + bool mWriteDebugTree{false}; ///< create debug output tree + bool mFinalized{false}; ///< if the finalize method was already called + std::string mDebugOutputName{"CalibLaserTracks_debug.root"}; ///< name of the debug output tree + + LaserTrackContainer mLaserTracks; //!< laser track data base + std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugStream; //!< debug output streamer + + /// update reconstruction parameters + void updateParameters(); + + /// perform fits on the matched z-position pairs to extract the drift velocity correction factor and trigger offset + void fillCalibData(LtrCalibData& calibData, const std::vector<TimePair>& pairsA, const std::vector<TimePair>& pairsC); + + ClassDefNV(CalibLaserTracks, 1); +}; + +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h index c88f6b1251fe1..617c9658d9234 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h index f285f93a8e494..bba3e2215e7aa 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -105,6 +106,9 @@ class CalibPedestal : public CalibRawBase /// \return noise calibration object const CalPad& getNoise() const { return mNoise; } + /// return all pad clibrations as vector + const std::vector<const o2::tpc::CalDet<float>*> getCalDets() const { return std::vector<const o2::tpc::CalDet<float>*>{&mPedestal, &mNoise}; } + /// Get the statistics type StatisticsType getStatisticsType() const { return mStatisticsType; } diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h index 1788e5053cc6c..d49241568b79e 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,11 +27,11 @@ namespace tpc { struct CalibPedestalParam : public o2::conf::ConfigurableParamHelper<CalibPedestalParam> { - int FirstTimeBin{0}; ///< first time bin used in analysis - int LastTimeBin{500}; ///< first time bin used in analysis - int ADCMin{0}; ///< minimum adc value - int ADCMax{120}; ///< maximum adc value - StatisticsType StatType{StatisticsType::GausFit}; ///< statistics type to be used for pedestal and noise evaluation + int FirstTimeBin{0}; ///< first time bin used in analysis + int LastTimeBin{500}; ///< first time bin used in analysis + int ADCMin{0}; ///< minimum adc value + int ADCMax{120}; ///< maximum adc value + StatisticsType StatType{StatisticsType::GausFitFast}; ///< statistics type to be used for pedestal and noise evaluation O2ParamDef(CalibPedestalParam, "TPCCalibPedestal"); }; diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPulser.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPulser.h index 4928604b3b490..3adfdb5b96972 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPulser.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPulser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPulserParam.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPulserParam.h index 8aac9fedd51a4..5127a58d969ca 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPulserParam.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPulserParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h index 0639335c88bd1..ba97cbf4b8ee4 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -126,9 +127,17 @@ class CalibRawBase /// number of processed events size_t getNumberOfProcessedEvents() const { return mNevents; } + /// set present event number + void setPresentEventNumber(size_t eventNr) { mPresentEventNumber = eventNr; } + /// get present event number size_t getPresentEventNumber() const { return mPresentEventNumber; } + bool isPresentEventValie() const { return mPresentEventNumber != std::numeric_limits<size_t>::max(); } + + /// return number of events + int getNumberOfEvents() const; + /// check if present event is complete bool isPresentEventComplete() const { return mRawReaderCRUManager.isEventComplete(mPresentEventNumber); } @@ -147,6 +156,9 @@ class CalibRawBase /// get skipping of incomplete events bool getSkipIncompleteEvents() const { return mSkipIncomplete; } + /// set external digits + void setDigits(std::array<std::vector<Digit>, Sector::MAXSECTOR>* digits) { mExternalDigits = digits; } + protected: const Mapper& mMapper; //!< TPC mapper int mDebugLevel; //!< debug level @@ -163,13 +175,17 @@ class CalibRawBase std::vector<std::unique_ptr<RawReader>> mRawReaders; //!< raw reader pointer rawreader::RawReaderCRUManager mRawReaderCRUManager{}; //!< cru type raw readers - std::unique_ptr<TChain> mDigitTree{}; //!< Chain of digit inputs - //TChain* mDigitTree{}; + std::unique_ptr<TChain> mDigitTree{}; //!< Chain of digit inputs + std::array<std::vector<Digit>, Sector::MAXSECTOR>* mExternalDigits{nullptr}; //!< TPC digits virtual void resetEvent() = 0; virtual void endEvent() = 0; virtual void endReader(){}; + /// call filling function using digits + template <typename T> + bool fillFromDigits(std::array<T, Sector::MAXSECTOR>& digits); + /// Process one event with mTimeBinsPerCall length using GBTFrameContainers ProcessStatus processEventGBT(); @@ -181,11 +197,31 @@ class CalibRawBase /// Process one event using the tree of digits as input ProcessStatus processEventDigitTree(int eventNumber = -1); + + /// Process external digits + ProcessStatus processExternalDigits(); }; //---------------------------------------------------------------- // Inline Functions //---------------------------------------------------------------- +inline int CalibRawBase::getNumberOfEvents() const +{ + if (mGBTFrameContainers.size()) { + return 0; // to be checked + } else if (mRawReaders.size()) { + return 0; // to be checked + } else if (mRawReaderCRUManager.getNumberOfReaders()) { + return mRawReaderCRUManager.getNumberOfEvents(); + } else if (mDigitTree) { + return mDigitTree->GetEntries(); + } else if (mExternalDigits) { + return 1; + } else { + return 0; + } +} + inline CalibRawBase::ProcessStatus CalibRawBase::processEvent(int eventNumber) { if (mGBTFrameContainers.size()) { @@ -196,6 +232,8 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEvent(int eventNumber) return processEventRawReaderCRU(eventNumber); } else if (mDigitTree) { return processEventDigitTree(eventNumber); + } else if (mExternalDigits) { + return processExternalDigits(); } else { return ProcessStatus::NoReaders; } @@ -404,7 +442,6 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventRawReaderCRU(int ev ProcessStatus status = ProcessStatus::Ok; mProcessedTimeBins = 0; - size_t processedReaders = 0; bool hasData = false; const int64_t numberOfEvents = mRawReaderCRUManager.getNumberOfEvents(); @@ -433,11 +470,9 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventRawReaderCRU(int ev // set status, don't overwrite decision if (!hasData) { return ProcessStatus::NoMoreData; - } else if (processedReaders < mRawReaderCRUManager.getNumberOfReaders()) { - status = ProcessStatus::Truncated; } else if (!isPresentEventComplete()) { status = ProcessStatus::IncompleteEvent; - } else if (mPresentEventNumber == size_t(lastEvent)) { + } else if (mPresentEventNumber >= size_t(lastEvent)) { status = ProcessStatus::LastEvent; } @@ -445,7 +480,7 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventRawReaderCRU(int ev ++mNevents; } else { status = ProcessStatus::IncompleteEvent; - if (mPresentEventNumber == size_t(lastEvent)) { + if (mPresentEventNumber >= size_t(lastEvent)) { status = ProcessStatus::LastEvent; } } @@ -466,12 +501,9 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventDigitTree(int event } resetEvent(); - const int nRowIROC = mMapper.getNumberOfRowsROC(0); - ProcessStatus status = ProcessStatus::Ok; mProcessedTimeBins = 0; - bool hasData = false; const int64_t numberOfEvents = mDigitTree->GetEntries(); const int64_t lastEvent = numberOfEvents - 1; @@ -491,63 +523,21 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventDigitTree(int event mPresentEventNumber = numberOfEvents - 1; } } - LOG(INFO) << "Processing event number " << eventNumber << " (" << mNevents << ")"; + LOG(INFO) << "Processing event number " << mPresentEventNumber << " (" << mNevents << ")"; // set up branches - static bool initialized = false; static std::array<std::vector<Digit>*, Sector::MAXSECTOR> digits{}; - if (!initialized) { + if (!mDigitTree->GetBranch("TPCDigit_0")->GetAddress()) { for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { mDigitTree->SetBranchAddress(Form("TPCDigit_%d", iSec), &digits[iSec]); } - initialized = true; } // loop over digits for selected event mDigitTree->GetEntry(mPresentEventNumber); - for (const auto vecSector : digits) { - for (const auto& digit : *vecSector) { - // cluster information - const CRU cru(digit.getCRU()); - const int roc = cru.roc(); - const int row = digit.getRow(); // row is global in sector - const int pad = digit.getPad(); - const size_t timeBin = digit.getTimeStamp(); - // - mProcessedTimeBins = std::max(mProcessedTimeBins, timeBin); - // TODO: OROC case needs subtraction of number of pad rows in IROC - const PadRegionInfo& regionInfo = mMapper.getPadRegionInfo(cru.region()); - const PartitionInfo& partInfo = mMapper.getPartitionInfo(cru.partition()); + const bool hasData = fillFromDigits(digits); - if (row == 255 || pad == 255) { - continue; - } - - int rowOffset = 0; - switch (mPadSubset) { - case PadSubset::ROC: { - rowOffset -= (cru.rocType() == RocType::OROC) * nRowIROC; - break; - } - case PadSubset::Region: { - break; - } - case PadSubset::Partition: { - rowOffset -= partInfo.getGlobalRowOffset(); - break; - } - } - - // modify row depending on the calibration type used - const float signal = digit.getChargeFloat(); - //const FECInfo& fecInfo = mMapper.getFECInfo(PadROCPos(roc, row, pad)); - //printf("Call update: %d, %d (%d), %d, %d, %.3f -- cru: %03d, reg: %02d -- FEC: %02d, Chip: %02d, Chn: %02d\n", roc, row, rowOffset, pad, timeBin, signal, cru.number(), cru.region(), fecInfo.getIndex(), fecInfo.getSampaChip(), fecInfo.getSampaChannel()); - updateCRU(cru, row, pad, timeBin, signal); - updateROC(roc, row + rowOffset, pad, timeBin, signal); - hasData = true; - } - } LOG(INFO) << "Found time bins: " << mProcessedTimeBins << "\n"; // set status, don't overwrite decision if (!hasData) { @@ -567,6 +557,30 @@ inline CalibRawBase::ProcessStatus CalibRawBase::processEventDigitTree(int event return status; } +//______________________________________________________________________________ +inline CalibRawBase::ProcessStatus CalibRawBase::processExternalDigits() +{ + + if (!mExternalDigits) { + return ProcessStatus::NoReaders; + } + resetEvent(); + + const bool hasData = fillFromDigits(*mExternalDigits); + + LOG(INFO) << "Found time bins: " << mProcessedTimeBins << "\n"; + // set status, don't overwrite decision + if (!hasData) { + return ProcessStatus::NoMoreData; + } + + endEvent(); + endReader(); + ++mNevents; + + return ProcessStatus::Ok; +} + //______________________________________________________________________________ inline Int_t CalibRawBase::update(const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) { @@ -614,6 +628,66 @@ inline Int_t CalibRawBase::update(const PadROCPos& padROCPos, const CRU& cru, co return timeBin; } +//______________________________________________________________________________ +template <typename T> +bool CalibRawBase::fillFromDigits(std::array<T, Sector::MAXSECTOR>& digits) +{ + using digitVec_t = typename std::conditional<std::is_pointer_v<T>, T, typename std::add_pointer<T>::type>::type; + bool hasData = false; + const int nRowIROC = mMapper.getNumberOfRowsROC(0); + for (auto& vecSector : digits) { + digitVec_t vecDigits; + if constexpr (std::is_pointer_v<T>) { + vecDigits = vecSector; + } else { + vecDigits = &vecSector; + } + for (const auto& digit : *vecDigits) { + + // cluster information + const CRU cru(digit.getCRU()); + const int roc = cru.roc(); + const int row = digit.getRow(); // row is global in sector + const int pad = digit.getPad(); + const size_t timeBin = digit.getTimeStamp(); + // + mProcessedTimeBins = std::max(mProcessedTimeBins, timeBin); + + // TODO: OROC case needs subtraction of number of pad rows in IROC + const PadRegionInfo& regionInfo = mMapper.getPadRegionInfo(cru.region()); + const PartitionInfo& partInfo = mMapper.getPartitionInfo(cru.partition()); + + if (row == 255 || pad == 255) { + continue; + } + + int rowOffset = 0; + switch (mPadSubset) { + case PadSubset::ROC: { + rowOffset -= (cru.rocType() == RocType::OROC) * nRowIROC; + break; + } + case PadSubset::Region: { + break; + } + case PadSubset::Partition: { + rowOffset -= partInfo.getGlobalRowOffset(); + break; + } + } + + // modify row depending on the calibration type used + const float signal = digit.getChargeFloat(); + //const FECInfo& fecInfo = mMapper.getFECInfo(PadROCPos(roc, row, pad)); + //printf("Call update: %d, %d (%d), %d, %d, %.3f -- cru: %03d, reg: %02d -- FEC: %02d, Chip: %02d, Chn: %02d\n", roc, row, rowOffset, pad, timeBin, signal, cru.number(), cru.region(), fecInfo.getIndex(), fecInfo.getSampaChip(), fecInfo.getSampaChannel()); + updateCRU(cru, row, pad, timeBin, signal); + updateROC(roc, row + rowOffset, pad, timeBin, signal); + hasData = true; + } + } + return hasData; +} + } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h index 6bb611bf40ebb..3c13e1cb12f12 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include <vector> #include <string> +#include <unordered_map> #include <boost/variant.hpp> @@ -75,12 +77,16 @@ class CalibTreeDump /// Dump the registered calibration data to file void dumpToFile(const std::string filename = "CalibTree.root"); + /// Add complementary information + void addInfo(const std::string_view name, float value) { mAddInfo[name.data()] = value; } + private: - std::vector<DataTypes*> mCalDetObjects{}; ///< array of CalDet objects - std::vector<DataTypes*> mCalArrayObjects{}; ///< array of CalArray objects - bool mAddFEEInfo{false}; ///< add front end electronics mappings - std::vector<float> mTraceLengthIROC; ///< trace lengths IROC - std::vector<float> mTraceLengthOROC; ///< trace lengths OROC + std::unordered_map<std::string, float> mAddInfo{}; ///< additional common information to be added to the output tree + std::vector<DataTypes*> mCalDetObjects{}; ///< array of CalDet objects + std::vector<DataTypes*> mCalArrayObjects{}; ///< array of CalArray objects + bool mAddFEEInfo{false}; ///< add front end electronics mappings + std::vector<float> mTraceLengthIROC; ///< trace lengths IROC + std::vector<float> mTraceLengthOROC; ///< trace lengths OROC /// add default mapping like local, global x/y positions void addDefaultMapping(TTree* tree); @@ -95,12 +101,6 @@ class CalibTreeDump /// set default aliases void setDefaultAliases(TTree* tree); - /// read trace lengths - void readTraceLengths(std::string_view mappingDir = ""); - - /// load trace lengths into vector - void setTraceLengths(std::string_view inputFile, std::vector<float>& length); - /// forwarding visitor class, required to loop over the variant types template <class Result, class Func> struct forwarding_visitor : boost::static_visitor<Result> { diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h new file mode 100644 index 0000000000000..402e921a9e9ee --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibdEdx.h +/// \brief This file provides the time dependent dE/dx calibrator, based on the MIP position. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#ifndef ALICEO2_TPC_CALIBDEDX_H_ +#define ALICEO2_TPC_CALIBDEDX_H_ + +#include <array> +#include <cstdint> +#include <string_view> + +// o2 includes +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/TrackCuts.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "TPCCalibration/dEdxHistos.h" +#include "TPCCalibration/FastHisto.h" +#include "CommonUtils/TreeStreamRedirector.h" + +namespace o2::tpc +{ + +/// Container used to store the dE/dx calibration output +struct CalibMIP { + double ASide; + double CSide; +}; + +/// dE/dx calibrator class +class CalibdEdx final : public o2::calibration::TimeSlotCalibration<o2::tpc::TrackTPC, o2::tpc::dEdxHistos> +{ + using TFType = o2::calibration::TFType; + using Slot = o2::calibration::TimeSlot<dEdxHistos>; + using CcdbObjectInfoVector = std::vector<o2::ccdb::CcdbObjectInfo>; + using MIPVector = std::vector<CalibMIP>; + + public: + /// Contructor that enables track cuts + CalibdEdx(int nBins = 200, int minEntries = 100, float minP = 0.4, float maxP = 0.6, int minClusters = 60) + : mNBins{nBins}, mMinEntries{minEntries}, mCuts{minP, maxP, static_cast<float>(minClusters)} + { + } + + /// Destructor + ~CalibdEdx() final = default; + + /// \return if there are enough data to compute the calibration + bool hasEnoughData(const Slot& slot) const final + { + return slot.getContainer()->getASideEntries() >= mMinEntries && slot.getContainer()->getCSideEntries() >= mMinEntries; + } + + /// Empty the output vectors + void initOutput() final; + + /// Process time slot data and compute its calibration + void finalizeSlot(Slot& slot) final; + + /// Creates new time slot + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + + void setApplyCuts(bool apply) { mApplyCuts = apply; } + bool getApplyCuts() { return mApplyCuts; } + void setCuts(const TrackCuts& cuts) { mCuts = cuts; } + + /// \return the computed calibrations + const MIPVector& getMIPVector() const { return mMIPVector; } + + /// \return CCDB output informations + const CcdbObjectInfoVector& getInfoVector() const { return mInfoVector; } + + /// Non const version + /// \return CCDB output informations + CcdbObjectInfoVector& getInfoVector() { return mInfoVector; } + + /// Enable debug output to file of the time slots calibrations outputs and dE/dx histograms + void enableDebugOutput(std::string_view fileName); + + /// Disable debug output to file. Also writes and closes stored time slots. + void disableDebugOutput(); + + /// \return if debug output is enabled + bool hasDebugOutput() const { return static_cast<bool>(mDebugOutputStreamer); } + + /// Write debug output to file + void finalizeDebugOutput() const; + + private: + int mNBins{}; ///< Number of bins in each time slot histogram + int mMinEntries{}; ///< Minimum amount of tracks in each time slot, to get enough statics + bool mApplyCuts{true}; ///< Flag to enable tracks cuts + TrackCuts mCuts; ///< Cut object + + CcdbObjectInfoVector mInfoVector; ///< vector of CCDB Infos, each element is filled with the CCDB description of the accompanying MIP positions + MIPVector mMIPVector; ///< vector of MIP positions, each element is filled in "process" when we finalize one slot (multiple can be finalized during the same "process", which is why we have a vector. Each element is to be considered the output of the device, and will go to the CCDB + + std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugOutputStreamer; ///< Debug output streamer + + ClassDefOverride(CalibdEdx, 1); +}; + +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h b/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h index 284e0f50c9119..4cf7f39e274c7 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include <string> #include <vector> #include <array> +#include <algorithm> #include <memory> #include "Rtypes.h" @@ -92,7 +94,7 @@ class DigitDump : public CalibRawBase void setNoiseThreshold(float noiseThreshold) { mNoiseThreshold = noiseThreshold; } /// set the adc range - void setADCRange(int minADC, int maxADC) + void setADCRange(float minADC, float maxADC) { mADCMin = minADC; mADCMax = maxADC; @@ -114,6 +116,8 @@ class DigitDump : public CalibRawBase for (auto& digits : mDigits) { digits.clear(); } + + std::fill(mTimeBinOccupancy.begin(), mTimeBinOccupancy.end(), 0); } /// set in memory only mode @@ -125,6 +129,10 @@ class DigitDump : public CalibRawBase /// return digits for specific sector std::vector<Digit>& getDigits(int sector) { return mDigits[sector]; } + /// return digit array + const auto& getDigits() const { return mDigits; } + auto& getDigits() { return mDigits; } + /// directly add a digit void addDigit(const CRU& cru, const float signal, const int rowInSector, const int padInRow, const int timeBin) { @@ -137,6 +145,12 @@ class DigitDump : public CalibRawBase /// End event function void endEvent() final; + /// check duplicates and remove the if removeDuplicates is true + void checkDuplicates(bool removeDuplicates = false); + + /// remove digits close to the CE + void removeCEdigits(uint32_t removeNtimeBinsBefore = 10, uint32_t removeNtimeBinsAfter = 100, std::array<std::vector<Digit>, Sector::MAXSECTOR>* removedDigits = nullptr); + private: std::unique_ptr<CalPad> mPedestal{}; ///< CalDet object with pedestal information std::unique_ptr<CalPad> mNoise{}; ///< CalDet object with noise @@ -150,10 +164,12 @@ class DigitDump : public CalibRawBase std::vector<std::array<int, 3>> mPadMask; ///< coordinates of pads to skip + std::vector<size_t> mTimeBinOccupancy; ///< count digits above threshold to be able to remove the CE signal + int mFirstTimeBin{0}; ///< first time bin used in analysis int mLastTimeBin{1000}; ///< first time bin used in analysis - int mADCMin{-100}; ///< minimum adc value - int mADCMax{1024}; ///< maximum adc value + float mADCMin{-100}; ///< minimum adc value + float mADCMax{1024}; ///< maximum adc value float mNoiseThreshold{-1}; ///< zero suppression threshold in noise sigma bool mInMemoryOnly{false}; ///< if processing is only done in memory, no file writing bool mInitialized{false}; ///< if init was called diff --git a/Detectors/TPC/calibration/include/TPCCalibration/DigitDumpParam.h b/Detectors/TPC/calibration/include/TPCCalibration/DigitDumpParam.h index 4054504480e3d..efd0bfa994624 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/DigitDumpParam.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/DigitDumpParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,8 +25,8 @@ namespace tpc { struct DigitDumpParam : public o2::conf::ConfigurableParamHelper<DigitDumpParam> { - int FirstTimeBin{0}; ///< first time bin used in analysis - int LastTimeBin{1000}; ///< first time bin used in analysis + int FirstTimeBin{-1}; ///< first time bin used in analysis + int LastTimeBin{-1}; ///< first time bin used in analysis int ADCMin{-100}; ///< minimum adc value int ADCMax{1024}; ///< maximum adc value float NoiseThreshold{-1}; ///< zero suppression threshold in noise sigma diff --git a/Detectors/TPC/calibration/include/TPCCalibration/FastHisto.h b/Detectors/TPC/calibration/include/TPCCalibration/FastHisto.h index 7318eda963ee5..ecdafca553663 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/FastHisto.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/FastHisto.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include "Framework/Logger.h" #include <sstream> #include <vector> +#include <iomanip> namespace o2 { diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCAverageGroup.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCAverageGroup.h new file mode 100644 index 0000000000000..32b2c66156c2c --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCAverageGroup.h @@ -0,0 +1,180 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCAverageGroup.h +/// \brief class for averaging and grouping of IDCs +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_IDCAVERAGEGROUP_H_ +#define ALICEO2_IDCAVERAGEGROUP_H_ + +#include <vector> +#include "TPCCalibration/IDCGroup.h" +#include "Rtypes.h" +#include "TPCBase/Sector.h" +#include "TPCCalibration/RobustAverage.h" + +namespace o2::utils +{ +class TreeStreamRedirector; +} + +namespace o2::tpc +{ + +/// class for averaging and grouping IDCs +/// usage: +/// 1. Define grouping parameters +/// const int region = 3; +/// IDCAverageGroup idcaverage(6, 4, 3, 2, region); +/// 2. set the ungrouped IDCs for one CRU +/// const int nIntegrationIntervals = 3; +/// std::vector<float> idcsungrouped(nIntegrationIntervals*Mapper::PADSPERREGION[region], 11.11); // vector containing IDCs for one region +/// idcaverage.setIDCs(idcsungrouped) +/// 3. perform the averaging and grouping +/// idcaverage.processIDCs(); +/// 4. draw IDCs +/// idcaverage.drawUngroupedIDCs(0) +/// idcaverage.drawGroupedIDCs(0) + +class IDCAverageGroup +{ + public: + /// constructor + /// \param groupPads number of pads in pad direction which will be grouped + /// \param groupRows number of pads in row direction which will be grouped + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction + /// \param region region of the TPC + /// \param sigma maximum accepted standard deviation for filtering outliers: sigma*stdev + IDCAverageGroup(const unsigned char groupPads = 4, const unsigned char groupRows = 4, const unsigned char groupLastRowsThreshold = 2, const unsigned char groupLastPadsThreshold = 2, const unsigned int region = 0, const Sector sector = Sector{0}, const float sigma = 3); + + /// set the IDCs which will be averaged and grouped + /// \param idcs vector containing the IDCs + void setIDCs(const std::vector<float>& idcs); + + /// set the IDCs which will be averaged and grouped using move operator + /// \param IDCs vector containing the IDCs + void setIDCs(std::vector<float>&& idcs); + + /// \return returns number of integration intervalls stored in this object + unsigned int getNIntegrationIntervals() const; + + /// grouping and averaging of IDCs + void processIDCs(); + + /// \return returns grouped IDC object + const auto& getIDCGroup() const { return mIDCsGrouped; } + + /// \return returns grouped IDC object + auto getIDCGroupData() && { return std::move(mIDCsGrouped).getData(); } + + /// dump object to disc + /// \param outFileName name of the output file + /// \param outName name of the object in the output file + void dumpToFile(const char* outFileName = "IDCAverageGroup.root", const char* outName = "IDCAverageGroup") const; + + /// load ungrouped and grouped IDCs from File + bool setFromFile(const char* fileName = "IDCAverageGroup.root", const char* name = "IDCAverageGroup"); + + /// draw ungrouped IDCs + /// \param integrationInterval integration interval for which the IDCs will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawUngroupedIDCs(const unsigned int integrationInterval = 0, const std::string filename = "IDCsUngrouped.pdf") const; + + /// draw grouped IDCs + /// \param integrationInterval integration interval for which the IDCs will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawGroupedIDCs(const unsigned int integrationInterval = 0, const std::string filename = "IDCsGrouped.pdf") const { mIDCsGrouped.draw(integrationInterval, filename); } + + /// \return returns the stored ungrouped IDC value for local ungrouped pad row and ungrouped pad + /// \param ulrow ungrouped local row in region + /// \param upad ungrouped pad in pad direction + /// \param integrationInterval integration interval for which the IDCs will be returned + float getUngroupedIDCValLocal(const unsigned int ulrow, const unsigned int upad, const unsigned int integrationInterval) const { return mIDCsUngrouped[getUngroupedIndex(ulrow, upad, integrationInterval)]; } + + /// \return returns the stored ungrouped IDC value for global ungrouped pad row and ungrouped pad + /// \param ugrow ungrouped global row + /// \param upad ungrouped pad in pad direction + /// \param integrationInterval integration interval for which the IDCs will be returned + float getUngroupedIDCValGlobal(const unsigned int ugrow, const unsigned int upad, const unsigned int integrationInterval) const { return mIDCsUngrouped[getUngroupedIndexGlobal(ugrow, upad, integrationInterval)]; } + + /// \return returns the stored ungrouped IDC value for local pad number + /// \param localPadNumber local pad number for region + /// \param integrationInterval integration interval for which the IDCs will be returned + float getUngroupedIDCVal(const unsigned int localPadNumber, const unsigned int integrationInterval) const; + + /// \return returns the stored grouped IDC value for local ungrouped pad row and ungrouped pad + /// \param ulrow local row in region of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float getGroupedIDCValLocal(unsigned int ulrow, unsigned int upad, unsigned int integrationInterval) const { return mIDCsGrouped.getValUngrouped(ulrow, upad, integrationInterval); } + + /// \return returns the stored grouped IDC value for local ungrouped pad row and ungrouped pad + /// \param ugrow global ungrouped row + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float getGroupedIDCValGlobal(unsigned int ugrow, unsigned int upad, unsigned int integrationInterval) const { return mIDCsGrouped.getValUngroupedGlobal(ugrow, upad, integrationInterval); } + + /// get the number of threads used for some of the calculations + static int getNThreads() { return sNThreads; } + + /// \return returns sector of which the IDCs are averaged and grouped + Sector getSector() const { return mSector; } + + /// \return returns ungrouped IDCs + const auto& getIDCsUngrouped() const { return mIDCsUngrouped; } + + /// \return returns region + unsigned int getRegion() const { return mIDCsGrouped.getRegion(); } + + /// \return returns sigma used for filtering + float getSigma() const { return mSigma; } + + /// set the number of threads used for some of the calculations + static void setNThreads(const int nThreads) { sNThreads = nThreads; } + + /// for debugging: creating debug tree + /// \param nameFile name of the output file + void createDebugTree(const char* nameFile) const; + + /// for debugging: creating debug tree for integrated IDCs for all objects which are in the same file + /// \param nameFile name of the output file + /// \param filename name of the input file containing all objects + static void createDebugTreeForAllCRUs(const char* nameFile, const char* filename); + + private: + inline static int sNThreads{1}; ///< number of threads which are used during the calculations + std::vector<float> mIDCsUngrouped{}; ///< integrated ungrouped IDC values per pad + IDCGroup mIDCsGrouped{}; ///< grouped and averaged IDC values + const Sector mSector{}; ///< sector of averaged and grouped IDCs (used for debugging) + const float mSigma{}; ///< sigma cut for outlier filtering + std::vector<RobustAverage> mRobustAverage; ///<! object for averaging (each thread will get his one object) + + /// \return returns index to data from ungrouped pad and row + /// \param ulrow ungrouped local row in region + /// \param upad ungrouped pad in pad direction + unsigned int getUngroupedIndex(const unsigned int ulrow, const unsigned int upad, const unsigned int integrationInterval) const; + + /// \return returns index to data from ungrouped pad and row + /// \param ugrow ungrouped global row + /// \param upad ungrouped pad in pad direction + unsigned int getUngroupedIndexGlobal(const unsigned int ugrow, const unsigned int upad, const unsigned int integrationInterval) const; + + /// called from createDebugTreeForAllCRUs() + static void createDebugTree(const IDCAverageGroup& idcavg, o2::utils::TreeStreamRedirector& pcstream); + + ClassDefNV(IDCAverageGroup, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h new file mode 100644 index 0000000000000..5a717e0c53dd3 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCCCDBHelper.h +/// \brief helper class for accessing IDC0 and IDCDelta from CCDB +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_IDCCCDBHELPER_H_ +#define ALICEO2_TPC_IDCCCDBHELPER_H_ + +#include "TPCCalibration/IDCContainer.h" +#include "TPCCalibration/IDCGroupHelperSector.h" +#include "CCDB/BasicCCDBManager.h" +#include "Rtypes.h" + +namespace o2::tpc +{ + +/// Usage +/// o2::tpc::IDCCCDBHelper<short> helper; +/// helper.setTimeStamp(0); +/// helper.loadAll(); +/// helper.drawIDCZeroSide(o2::tpc::Side::A); +/// const unsigned int sector 10; +/// const unsigned int integrationInterval =3; +/// helper.drawIDCDeltaSector(sector, 3); +/// TODO add drawing of 1D-distributions + +/// \tparam DataT the data type for the IDCDelta which are stored in the CCDB (short, char, float) +template <typename DataT = short> +class IDCCCDBHelper +{ + public: + /// constructor + /// \param uri path to CCDB + IDCCCDBHelper(const char* uri = "http://ccdb-test.cern.ch:8080") { mCCDBManager.setURL(uri); } + + /// update timestamp (time frame) + void setTimeStamp(const long long timestamp) { mCCDBManager.setTimestamp(timestamp); } + + /// load IDC-Delta, 0D-IDCs, grouping parameter needed for access + void loadAll(); + + /// load/update IDCDelta + void loadIDCDelta() { mIDCDelta = mCCDBManager.get<o2::tpc::IDCDelta<DataT>>("TPC/Calib/IDC/IDCDELTA"); } + + /// load/update 0D-IDCs + void loadIDCZero() { mIDCZero = mCCDBManager.get<o2::tpc::IDCZero>("TPC/Calib/IDC/IDC0"); } + + /// load/update grouping parameter + void loadGroupingParameter() { mHelperSector = std::make_unique<IDCGroupHelperSector>(IDCGroupHelperSector{*mCCDBManager.get<o2::tpc::ParameterIDCGroupCCDB>("TPC/Calib/IDC/GROUPINGPAR")}); } + + /// \return returns the stored IDC0 value for local ungrouped pad row and ungrouped pad + /// \param sector sector + /// \param region region + /// \param urow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + float getIDCZeroVal(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad) const { return mIDCZero->getValueIDCZero(Sector(sector).side(), mHelperSector->getIndexUngrouped(sector, region, urow, upad, 0)); } + + /// \return returns the stored DeltaIDC value for local ungrouped pad row and ungrouped pad + /// \param sector sector + /// \param region region + /// \param urow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param chunk chunk of the Delta IDC (can be obtained with getLocalIntegrationInterval()) + /// \param localintegrationInterval local integration interval for chunk (can be obtained with getLocalIntegrationInterval()) + float getIDCDeltaVal(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad, unsigned int localintegrationInterval) const { return mIDCDelta->getValue(Sector(sector).side(), mHelperSector->getIndexUngrouped(sector, region, urow, upad, localintegrationInterval)); } + + /// draw IDC zero I_0(r,\phi) = <I(r,\phi,t)>_t + /// \param side side which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCZeroSide(const o2::tpc::Side side, const std::string filename = "IDCZeroSide.pdf") const { drawSide(IDCType::IDCZero, side, 0, filename); } + + /// draw IDCDelta for one side for one integration interval + /// \param side side which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCDeltaSide(const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename = "IDCDeltaSide.pdf") const { drawSide(IDCType::IDCDelta, side, integrationInterval, filename); } + + /// draw IDC zero I_0(r,\phi) = <I(r,\phi,t)>_t + /// \param sector sector which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCZeroSector(const unsigned int sector, const std::string filename = "IDCZeroSector.pdf") const { drawSector(IDCType::IDCZero, sector, 0, filename); } + + /// draw IDCDelta for one sector for one integration interval + /// \param sector sector which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCDeltaSector(const unsigned int sector, const unsigned int integrationInterval, const std::string filename = "IDCDeltaSector.pdf") const { drawSector(IDCType::IDCDelta, sector, integrationInterval, filename); } + + private: + IDCZero* mIDCZero = nullptr; ///< 0D-IDCs: ///< I_0(r,\phi) = <I(r,\phi,t)>_t + IDCDelta<DataT>* mIDCDelta = nullptr; ///< compressed or uncompressed Delta IDC: \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + std::unique_ptr<IDCGroupHelperSector> mHelperSector{}; ///< helper for accessing IDC0 and IDC-Delta + o2::ccdb::BasicCCDBManager mCCDBManager = o2::ccdb::BasicCCDBManager::instance(); ///< CCDB manager for loading objects + + /// draw IDCs for one side for one integration interval + /// \param Side side which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawSide(const IDCType type, const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename) const; + + /// draw IDCs for one sector for one integration interval + /// \param sector sector which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawSector(const IDCType type, const unsigned int sector, const unsigned int integrationInterval, const std::string filename) const; + + /// return returns title for z axis for given IDCType + std::string getZAxisTitle(const o2::tpc::IDCType type) const; + + ClassDefNV(IDCCCDBHelper, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCContainer.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCContainer.h new file mode 100644 index 0000000000000..a4ce414f91f5a --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCContainer.h @@ -0,0 +1,370 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCContainer.h +/// \brief This file provides the structs for storing the factorized IDC values and fourier coefficients to be stored in the CCDB +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 30, 2021 + +#ifndef ALICEO2_TPC_IDCCONTAINER_H_ +#define ALICEO2_TPC_IDCCONTAINER_H_ + +#include <array> +#include <vector> +#include <limits> +#include "DataFormatsTPC/Defs.h" +#include "TPCCalibration/IDCGroupingParameter.h" + +namespace o2 +{ +namespace tpc +{ + +/// IDC types +enum class IDCType { IDC = 0, ///< integrated and grouped IDCs + IDCZero = 1, ///< IDC0: I_0(r,\phi) = <I(r,\phi,t)>_t + IDCOne = 2, ///< IDC1: I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + IDCDelta = 3 ///< IDCDelta: \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) +}; + +/// struct containing the IDC delta values +template <typename DataT> +struct IDCDeltaContainer { + std::array<std::vector<DataT>, o2::tpc::SIDES> mIDCDeltaCont{}; ///< \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) +}; + +/// storage for the factor used to compress IDCDelta. +/// This factor is separated from the IDCDelta struct to able to store those values independently in the CCDB +struct IDCDeltaCompressionFactors { + std::array<float, o2::tpc::SIDES> mFactors{1.f, 1.f}; ///< compression factors for each TPC side +}; + +/// struct to access and set Delta IDCs +template <typename DataT> +struct IDCDelta { + + /// set idcDelta for given index + /// \param idcDelta Delta IDC value which will be set + /// \param side side of the TPC + /// \param index index in the storage + void setValue(const float idcDelta, const o2::tpc::Side side, const unsigned int index) { mIDCDelta.mIDCDeltaCont[side][index] = compressValue(idcDelta, side); } + + /// set idcDelta ath the end of storage + /// \param idcDelta Delta IDC value which will be set + /// \param side side of the TPC + void emplace_back(const float idcDelta, const o2::tpc::Side side) { mIDCDelta.mIDCDeltaCont[side].emplace_back(compressValue(idcDelta, side)); } + + /// \return returns converted IDC value from float to new data type specified by template parameter of the object + /// \param idcDelta Delta IDC value which will be set + /// \param side side of the TPC + DataT compressValue(const float idcDelta, const o2::tpc::Side side) const + { + const static auto& paramIDCGroup = ParameterIDCCompression::Instance(); + return (std::abs(idcDelta) >= paramIDCGroup.MaxIDCDeltaValue) ? static_cast<DataT>(std::copysign(paramIDCGroup.MaxIDCDeltaValue * mCompressionFactor.mFactors[side] + 0.5f, idcDelta)) : static_cast<DataT>(idcDelta * mCompressionFactor.mFactors[side] + std::copysign(0.5f, idcDelta)); + } + + /// \return returns stored Delta IDC value + /// \param side side of the TPC + /// \param index index in the storage (see: getIndexUngrouped int IDCGroupHelperSector) + float getValue(const o2::tpc::Side side, const unsigned int index) const { return (static_cast<float>(mIDCDelta.mIDCDeltaCont[side][index]) / mCompressionFactor.mFactors[side]); } + + /// set compression factor + /// \param side side of the TPC + /// \param factor factor which will be used for the compression + void setCompressionFactor(const o2::tpc::Side side, const float factor) { mCompressionFactor.mFactors[side] = factor; } + + /// \return returns vector of Delta IDCs for given side + /// \param side side of the TPC + const auto& getIDCDelta(const o2::tpc::Side side) const { return mIDCDelta.mIDCDeltaCont[side]; } + + /// \return returns vector of Delta IDCs for given side + /// \param side side of the TPC + auto& getIDCDelta(const o2::tpc::Side side) { return mIDCDelta.mIDCDeltaCont[side]; } + + /// set IDCDelta value + /// \param side side of the TPC + /// \param index index in the storage (see: getIndexUngrouped int IDCGroupHelperSector) + /// \param val value of IDCDelta which will be stored + void setIDCDelta(const o2::tpc::Side side, const unsigned int index, const DataT val) { mIDCDelta.mIDCDeltaCont[side][index] = val; } + + /// \return returns compression factors to uncompress Delta IDC + const auto& getCompressionFactors() const { return mCompressionFactor; } + + /// \return returns compression factors to uncompress Delta IDC + /// \param side side of the TPC + auto getCompressionFactor(const o2::tpc::Side side) const { return mCompressionFactor.mFactors[side]; } + + IDCDeltaContainer<DataT> mIDCDelta{}; ///< storage for Delta IDCs + IDCDeltaCompressionFactors mCompressionFactor{}; ///< compression factor for Delta IDCs + ClassDefNV(IDCDelta, 1) +}; + +// template specialization for float as no compression factor is needed in this case +template <> +struct IDCDelta<float> { + /// set idcDelta for given index + /// \param idcDelta Delta IDC value which will be set + /// \param side side of the TPC + /// \param index index in the storage + void setValue(const float idcDelta, const o2::tpc::Side side, const unsigned int index) { mIDCDelta.mIDCDeltaCont[side][index] = idcDelta; } + + /// \return returns stored Delta IDC value + /// \param side side of the TPC + /// \param index index in the storage + float getValue(const o2::tpc::Side side, const unsigned int index) const { return mIDCDelta.mIDCDeltaCont[side][index]; } + + /// \return returns vector of Delta IDCs for given side + /// \param side side of the TPC + const auto& getIDCDelta(const o2::tpc::Side side) const { return mIDCDelta.mIDCDeltaCont[side]; } + + /// \return returns vector of Delta IDCs for given side + /// \param side side of the TPC + auto& getIDCDelta(const o2::tpc::Side side) { return mIDCDelta.mIDCDeltaCont[side]; } + + /// set IDCDelta value + /// \param side side of the TPC + /// \param index index in the storage (see: getIndexUngrouped int IDCGroupHelperSector) + /// \param val value of IDCDelta which will be stored + void setIDCDelta(const o2::tpc::Side side, const unsigned int index, const float val) { mIDCDelta.mIDCDeltaCont[side][index] = val; } + + IDCDeltaContainer<float> mIDCDelta{}; ///< storage for uncompressed Delta IDCs + ClassDefNV(IDCDelta, 1) +}; + +/// helper class to compress Delta IDC values +/// \tparam template parameter specifying the output format of the compressed IDCDelta +template <typename DataT> +class IDCDeltaCompressionHelper +{ + public: + IDCDeltaCompressionHelper() = default; + + /// static method to get the compressed Delta IDCs from uncompressed Delta IDCs + /// \return returns compressed Delta IDC values + /// \param idcDeltaUncompressed uncompressed Delta IDC values + static IDCDelta<DataT> getCompressedIDCs(const IDCDelta<float>& idcDeltaUncompressed) + { + IDCDelta<DataT> idcCompressed{}; + compress(idcDeltaUncompressed, idcCompressed, o2::tpc::Side::A); + compress(idcDeltaUncompressed, idcCompressed, o2::tpc::Side::C); + return std::move(idcCompressed); + } + + private: + static void compress(const IDCDelta<float>& idcDeltaUncompressed, IDCDelta<DataT>& idcCompressed, const o2::tpc::Side side) + { + idcCompressed.getIDCDelta(side).reserve(idcDeltaUncompressed.getIDCDelta(side).size()); + const float factor = getCompressionFactor(idcDeltaUncompressed, side); + idcCompressed.setCompressionFactor(side, factor); + for (auto& idc : idcDeltaUncompressed.getIDCDelta(side)) { + idcCompressed.emplace_back(idc, side); + } + } + + /// \return returns the factor which is used during the compression + static float getCompressionFactor(const IDCDelta<float>& idcDeltaUncompressed, const o2::tpc::Side side) + { + const float maxAbsIDC = getMaxValue(idcDeltaUncompressed.getIDCDelta(side)); + const auto& paramIDCGroup = ParameterIDCCompression::Instance(); + const float maxIDC = paramIDCGroup.MaxIDCDeltaValue; + return (maxAbsIDC > maxIDC || maxAbsIDC == 0) ? (std::numeric_limits<DataT>::max() / maxIDC) : (std::numeric_limits<DataT>::max() / maxAbsIDC); + } + + /// \returns returns maximum abs value in vector + static float getMaxValue(const std::vector<float>& idcs) + { + return std::abs(*std::max_element(idcs.begin(), idcs.end(), [](const float a, const float b) -> bool { return (std::abs(a) < std::abs(b)); })); + }; +}; + +///<struct containing the IDC1 values +struct IDCZero { + + /// set IDC zero for given index + /// \param idcZero Delta IDC value which will be set + /// \param side side of the TPC + /// \param index index in the storage + void setValueIDCZero(const float idcZero, const o2::tpc::Side side, const unsigned int index) { mIDCZero[side][index] = idcZero; } + + /// increase IDC zero for given index + /// \param idcZero Delta IDC value which will be set + /// \param side side of the TPC + /// \param index index in the storage + void fillValueIDCZero(const float idcZero, const o2::tpc::Side side, const unsigned int index) { mIDCZero[side][index] += idcZero; } + + /// \return returns stored IDC zero value + /// \param side side of the TPC + /// \param index index in the storage + float getValueIDCZero(const o2::tpc::Side side, const unsigned int index) const { return mIDCZero[side][index]; } + + /// set all values back to 0 + /// \param side side of the TPC + void reset(const o2::tpc::Side side) { std::fill(mIDCZero[side].begin(), mIDCZero[side].end(), 0.f); } + + /// resize vector + /// \param side side of the TPC + void resize(const o2::tpc::Side side, const unsigned int size) { mIDCZero[side].resize(size); } + + std::array<std::vector<float>, o2::tpc::SIDES> mIDCZero{}; ///< I_0(r,\phi) = <I(r,\phi,t)>_t + ClassDefNV(IDCZero, 1) +}; + +///<struct containing the IDC0 +struct IDCOne { + /// set IDC one for given index + /// \param idcOne Delta IDC value which will be set + /// \param side side of the TPC + /// \param index index in the storage + void setValueIDCOne(const float idcOne, const o2::tpc::Side side, const unsigned int index) { mIDCOne[side][index] = idcOne; } + + /// \return returns stored IDC one value + /// \param side side of the TPC + /// \param index index in the storage + float getValueIDCOne(const o2::tpc::Side side, const unsigned int index) const { return mIDCOne[side][index]; } + + /// set all values back to 0 + /// \param side side of the TPC + void reset(const o2::tpc::Side side) { std::fill(mIDCOne[side].begin(), mIDCOne[side].end(), 0.f); } + + /// resize vector + /// \param side side of the TPC + void resize(const o2::tpc::Side side, const unsigned int size) { mIDCOne[side].resize(size); } + + std::array<std::vector<float>, o2::tpc::SIDES> mIDCOne{}; ///< I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + ClassDefNV(IDCOne, 1) +}; + +/// struct containing 1D-IDCs +struct OneDIDC { + + /// default constructor + OneDIDC() = default; + + /// constructor for initializing member with default value (this is used in the IDCFourierTransform class to perform calculation of the fourier coefficients for the first aggregation interval) + /// \param nIDC number of IDCs which will be initialized + OneDIDC(const unsigned int nIDC) : mOneDIDC{std::vector<float>(nIDC), std::vector<float>(nIDC)} {}; + + /// \return returns total number of 1D-IDCs for given side + /// \param side side of the TPC + unsigned int getNIDCs(const o2::tpc::Side side) const { return mOneDIDC[side].size(); } + + std::array<std::vector<float>, o2::tpc::SIDES> mOneDIDC{}; ///< 1D-IDCs = <I(r,\phi,t)>_{r,\phi} + ClassDefNV(OneDIDC, 1) +}; + +/// Helper class for aggregation of 1D-IDCs from different CRUs +class OneDIDCAggregator +{ + public: + /// constructor + /// nTimeFrames number of time frames which will be aggregated + OneDIDCAggregator(const unsigned int nTimeFrames = 1) : mOneDIDCAgg(nTimeFrames), mWeight(nTimeFrames){}; + + /// aggregate 1D-IDCs + /// \param side side of the tpcCRUHeader + /// \param idc vector containing the 1D-IDCs + /// \param timeframe of the input 1D-IDC + /// \param region region of the TPC + void aggregate1DIDCs(const o2::tpc::Side side, const std::vector<float>& idc, const unsigned int timeframe, const unsigned int region) + { + if (mOneDIDCAgg[timeframe].mOneDIDC[side].empty()) { + mOneDIDCAgg[timeframe].mOneDIDC[side] = idc; + mWeight[timeframe][side] = Mapper::REGIONAREA[region]; + } else { + std::transform(mOneDIDCAgg[timeframe].mOneDIDC[side].begin(), mOneDIDCAgg[timeframe].mOneDIDC[side].end(), idc.begin(), mOneDIDCAgg[timeframe].mOneDIDC[side].begin(), std::plus<>()); + mWeight[timeframe][side] += Mapper::REGIONAREA[region]; + } + } + + /// \return returns struct containing aggregated 1D IDCs normalized to number of channels weighted with the relative length of each region + OneDIDC getAggregated1DIDCs() + { + OneDIDC oneDIDCTmp; + for (int iside = 0; iside < o2::tpc::SIDES; ++iside) { + const o2::tpc::Side side = iside == 0 ? o2::tpc::Side::A : o2::tpc::Side::C; + for (unsigned int i = 0; i < mOneDIDCAgg.size(); ++i) { + std::transform(mOneDIDCAgg[i].mOneDIDC[side].begin(), mOneDIDCAgg[i].mOneDIDC[side].end(), mOneDIDCAgg[i].mOneDIDC[side].begin(), [norm = mWeight[i][side]](auto& val) { return val / norm; }); + oneDIDCTmp.mOneDIDC[side].insert(oneDIDCTmp.mOneDIDC[side].end(), mOneDIDCAgg[i].mOneDIDC[side].begin(), mOneDIDCAgg[i].mOneDIDC[side].end()); + mOneDIDCAgg[i].mOneDIDC[side].clear(); + } + } + return oneDIDCTmp; + } + + const auto& get() const { return mOneDIDCAgg; } + const auto& getWeight() const { return mWeight; } + + /// \returns vector containing the number of integration intervals for each stored TF + std::vector<unsigned int> getIntegrationIntervalsPerTF(const o2::tpc::Side side = o2::tpc::Side::A) const + { + std::vector<unsigned int> integrationIntervalsPerTF; + integrationIntervalsPerTF.reserve(mOneDIDCAgg.size()); + for (const auto& tf : mOneDIDCAgg) { + integrationIntervalsPerTF.emplace_back(tf.getNIDCs(side)); + } + return integrationIntervalsPerTF; + } + + private: + std::vector<OneDIDC> mOneDIDCAgg{}; ///< 1D-IDCs = <I(r,\phi,t)>_{r,\phi} + std::vector<std::array<float, o2::tpc::SIDES>> mWeight{}; ///< integrated pad area of received data used for normalization +}; + +/// struct containing the fourier coefficients calculated from IDC0 for n timeframes +struct FourierCoeff { + /// constructor + /// \param nTimeFrames number of time frames + /// \param nCoeff number of real/imag fourier coefficients which will be stored + FourierCoeff(const unsigned int nTimeFrames, const unsigned int nCoeff) + : mFourierCoefficients{{std::vector<float>(nTimeFrames * nCoeff), std::vector<float>(nTimeFrames * nCoeff)}}, mCoeffPerTF{nCoeff} {}; + + /// default constructor for ROOT I/O + FourierCoeff() = default; + + /// \return returns total number of stored coefficients for given side and real/complex type + /// \param side side + unsigned long getNCoefficients(const o2::tpc::Side side) const { return mFourierCoefficients[side].size(); } + + /// \return returns number of stored coefficients for TF + unsigned int getNCoefficientsPerTF() const { return mCoeffPerTF; } + + /// \return returns all stored coefficients for given side and real/complex type + /// \param side side + const auto& getFourierCoefficients(const o2::tpc::Side side) const { return mFourierCoefficients[side]; } + + /// \return returns index to fourier coefficient + /// \param interval index of interval + /// \param coefficient index of coefficient + unsigned int getIndex(const unsigned int interval, const unsigned int coefficient) const { return interval * mCoeffPerTF + coefficient; } + + /// \return returns the stored value + /// \param side side of the TPC + /// \param index index of the data + float operator()(const o2::tpc::Side side, unsigned int index) const { return mFourierCoefficients[side][index]; } + + /// \return returns the stored value + /// \param side side of the TPC + /// \param index index of the data + float& operator()(const o2::tpc::Side side, unsigned int index) { return mFourierCoefficients[side][index]; } + + void reset(const o2::tpc::Side side) { std::fill(mFourierCoefficients[side].begin(), mFourierCoefficients[side].end(), 0.f); }; + + std::array<std::vector<float>, o2::tpc::SIDES> mFourierCoefficients{}; ///< fourier coefficients. side -> coefficient real and complex parameters are stored alternating + const unsigned int mCoeffPerTF{}; ///< number of real+imag coefficients per TF + + ClassDefNV(FourierCoeff, 1) +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h new file mode 100644 index 0000000000000..33169152ce877 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h @@ -0,0 +1,267 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCFactorization.h +/// \brief class for aggregating IDCs for the full TPC (all sectors) and factorization of aggregated IDCs +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 30, 2021 + +#ifndef ALICEO2_IDCFACTORIZATION_H_ +#define ALICEO2_IDCFACTORIZATION_H_ + +#include <vector> +#include "Rtypes.h" +#include "TPCBase/Mapper.h" +#include "TPCCalibration/IDCContainer.h" +#include "TPCCalibration/IDCGroupHelperSector.h" +#include "DataFormatsTPC/Defs.h" + +#if (defined(WITH_OPENMP) || defined(_OPENMP)) && !defined(__CLING__) +#include <omp.h> +#endif + +namespace o2::tpc +{ + +/// IDC Delta IDC Compression types +enum class IDCDeltaCompression { NO = 0, ///< no compression using floats + MEDIUM = 1, ///< medium compression using short (data compression ratio 2 when stored in CCDB) + HIGH = 2 ///< high compression using char (data compression ratio ~5.5 when stored in CCDB) +}; + +class IDCFactorization : public IDCGroupHelperSector +{ + public: + /// constructor + /// \param groupPads number of pads in pad direction which will be grouped for all regions + /// \param groupRows number of pads in row direction which will be grouped for all regions + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction for all regions + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction for all regions + /// \param timeFrames number of time frames which will be stored + /// \param timeframesDeltaIDC number of time frames stored for each DeltaIDC object + IDCFactorization(const std::array<unsigned char, Mapper::NREGIONS>& groupPads, const std::array<unsigned char, Mapper::NREGIONS>& groupRows, const std::array<unsigned char, Mapper::NREGIONS>& groupLastRowsThreshold, const std::array<unsigned char, Mapper::NREGIONS>& groupLastPadsThreshold, const unsigned int timeFrames, const unsigned int timeframesDeltaIDC); + + /// default constructor for ROOT I/O + IDCFactorization() = default; + + /// calculate I_0(r,\phi) = <I(r,\phi,t)>_t + /// calculate I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + /// calculate \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + void factorizeIDCs(); + + /// \return returns the stored grouped and integrated IDC + /// \param sector sector + /// \param region region + /// \param grow row in the region of the grouped IDCs + /// \param gpad pad number of the grouped IDCs + /// \param integrationInterval integration interval + float getIDCValGrouped(const unsigned int sector, const unsigned int region, const unsigned int grow, unsigned int gpad, unsigned int integrationInterval) const { return mIDCs[sector * Mapper::NREGIONS + region][integrationInterval][mOffsRow[region][grow] + gpad]; } + + /// \return returns the stored value for local ungrouped pad row and ungrouped pad + /// \param sector sector + /// \param region region + /// \param urow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float getIDCValUngrouped(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad, unsigned int integrationInterval) const; + + /// \return returns the stored IDC0 value for local ungrouped pad row and ungrouped pad + /// \param sector sector + /// \param region region + /// \param urow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + float getIDCZeroVal(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad) const { return mIDCZero.getValueIDCZero(Sector(sector).side(), getIndexUngrouped(sector, region, urow, upad, 0)); } + + /// \return returns the stored DeltaIDC value for local ungrouped pad row and ungrouped pad + /// \param sector sector + /// \param region region + /// \param urow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param chunk chunk of the Delta IDC (can be obtained with getLocalIntegrationInterval()) + /// \param localintegrationInterval local integration interval for chunk (can be obtained with getLocalIntegrationInterval()) + float getIDCDeltaVal(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad, unsigned int chunk, unsigned int localintegrationInterval) const { return mIDCDelta[chunk].getValue(Sector(sector).side(), getIndexUngrouped(sector, region, urow, upad, localintegrationInterval)); } + + /// \return returns index of integration interval in the chunk from global integration interval + /// \param region TPC region + /// \param integrationInterval integration interval + /// \param chunk which will be set in the function + /// \param localintegrationInterval local integration interval for chunk which will be set in the function + void getLocalIntegrationInterval(const unsigned int region, const unsigned int integrationInterval, unsigned int& chunk, unsigned int& localintegrationInterval) const; + + /// \return returns number of timeframes for which the IDCs are stored + unsigned int getNTimeframes() const { return mTimeFrames; } + + /// \return returns the number of stored integration intervals for given Delta IDC chunk + /// \param chunk chunk of Delta IDC + unsigned long getNIntegrationIntervals(const unsigned int chunk) const; + + /// \return returns the total number of stored integration intervals + unsigned long getNIntegrationIntervals() const; + + /// \return returns stored IDC0 I_0(r,\phi) = <I(r,\phi,t)>_t + /// \param side TPC side + const std::vector<float>& getIDCZero(const o2::tpc::Side side) const { return mIDCZero.mIDCZero[side]; } + + /// \return returns stored IDC1 I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + /// \param side TPC side + const std::vector<float>& getIDCOne(const o2::tpc::Side side) const { return mIDCOne.mIDCOne[side]; } + + /// \return returns stored IDCDelta \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + /// \param side TPC side + /// \param chunk chunk of Delta IDC + const std::vector<float>& getIDCDeltaUncompressed(const o2::tpc::Side side, const unsigned int chunk) const { return mIDCDelta[chunk].getIDCDelta(side); } + + /// \return returns stored IDCDelta \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + /// \param chunk chunk of Delta IDC + const auto& getIDCDeltaUncompressed(const unsigned int chunk) const { return mIDCDelta[chunk]; } + + /// \return creates and returns medium compressed IDCDelta \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + /// \param chunk chunk of Delta IDC + auto getIDCDeltaMediumCompressed(const unsigned int chunk) const { return IDCDeltaCompressionHelper<short>::getCompressedIDCs(mIDCDelta[chunk]); } + + /// \return creates and returns high compressed IDCDelta \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + /// \param chunk chunk of Delta IDC + auto getIDCDeltaHighCompressed(const unsigned int chunk) const { return IDCDeltaCompressionHelper<char>::getCompressedIDCs(mIDCDelta[chunk]); } + + /// \return returns number of chunks for Delta IDCs + unsigned int getNChunks() const { return mIDCDelta.size(); } + + /// \return returns struct containing IDC0 + const auto& getIDCZero() const { return mIDCZero; } + + /// \return returns struct containing IDC1 + const auto& getIDCOne() const& { return mIDCOne; } + + /// \return returns struct containing IDC1 using move semantics + auto getIDCOne() && { return std::move(mIDCOne); } + + /// \return returns grouped IDCs + const auto& getIDCs() const { return mIDCs; } + + // get number of TFs in which the DeltaIDCs are split/stored + unsigned int getTimeFramesDeltaIDC() const { return mTimeFramesDeltaIDC; } + + /// \return returns the number of threads used for some of the calculations + static int getNThreads() { return sNThreads; } + + /// set the IDC data + /// \param idcs vector containing the IDCs + /// \param cru CRU + /// \param timeframe time frame of the IDCs + void setIDCs(std::vector<float>&& idcs, const unsigned int cru, const unsigned int timeframe) { mIDCs[cru][timeframe] = std::move(idcs); } + + /// set the number of threads used for some of the calculations + /// \param nThreads number of threads + static void setNThreads(const int nThreads) { sNThreads = nThreads; } + + /// \param maxIDCDeltaValue maximum IDC delta value for compressed IDC delta + static void setMaxCompressedIDCDelta(const float maxIDCDeltaValue) { o2::conf::ConfigurableParam::setValue<float>("TPCIDCCompressionParam", "MaxIDCDeltaValue", maxIDCDeltaValue); } + + /// draw IDCs for one sector for one integration interval + /// \param sector sector which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCsSector(const unsigned int sector, const unsigned int integrationInterval, const std::string filename = "IDCsSector.pdf") const { drawSector(IDCType::IDC, sector, integrationInterval, filename); } + + /// draw IDC zero I_0(r,\phi) = <I(r,\phi,t)>_t + /// \param sector sector which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCZeroSector(const unsigned int sector, const std::string filename = "IDCZeroSector.pdf") const { drawSector(IDCType::IDCZero, sector, 0, filename); } + + /// draw IDCDelta for one sector for one integration interval + /// \param sector sector which will be drawn + /// \param integrationInterval which will be drawn + /// \param compression compression of Delta IDCs. (setMaxCompressedIDCDelta() should be called first in case of non standard compression parameter) + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCDeltaSector(const unsigned int sector, const unsigned int integrationInterval, const IDCDeltaCompression compression, const std::string filename = "IDCDeltaSector.pdf") const { drawSector(IDCType::IDCDelta, sector, integrationInterval, filename, compression); } + + /// draw IDCs for one side for one integration interval + /// \param side side which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCsSide(const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename = "IDCsSide.pdf") const { drawSide(IDCType::IDC, side, integrationInterval, filename); } + + /// draw IDC zero I_0(r,\phi) = <I(r,\phi,t)>_t + /// \param side side which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCZeroSide(const o2::tpc::Side side, const std::string filename = "IDCZeroSide.pdf") const { drawSide(IDCType::IDCZero, side, 0, filename); } + + /// draw IDCDelta for one side for one integration interval + /// \param side side which will be drawn + /// \param integrationInterval which will be drawn + /// \param compression compression of Delta IDCs. (setMaxCompressedIDCDelta() should be called first in case of non standard compression parameter) + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCDeltaSide(const o2::tpc::Side side, const unsigned int integrationInterval, const IDCDeltaCompression compression, const std::string filename = "IDCDeltaSide.pdf") const { drawSide(IDCType::IDCDelta, side, integrationInterval, filename, compression); } + + /// dump object to disc + /// \param outFileName name of the output file + /// \param outName name of the object in the output file + void dumpToFile(const char* outFileName = "IDCFactorized.root", const char* outName = "IDCFactorized") const; + + /// \param integrationIntervals number of integration intervals which will be dumped to the tree (-1: all integration intervalls) + /// \param outFileName name of the output file + void dumpToTree(int integrationIntervals = -1, const char* outFileName = "IDCTree.root") const; + + /// \returns vector containing the number of integration intervals for each stored TF + std::vector<unsigned int> getIntegrationIntervalsPerTF(const unsigned int region = 0) const; + + /// resetting aggregated IDCs + void reset(); + + private: + const unsigned int mTimeFrames{}; ///< number of timeframes which are stored + const unsigned int mTimeFramesDeltaIDC{}; ///< number of timeframes of which Delta IDCs are stored + std::array<std::vector<std::vector<float>>, CRU::MaxCRU> mIDCs{}; ///< grouped and integrated IDCs for the whole TPC. CRU -> time frame -> IDCs + IDCZero mIDCZero{}; ///< I_0(r,\phi) = <I(r,\phi,t)>_t + IDCOne mIDCOne{}; ///< I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + std::vector<IDCDelta<float>> mIDCDelta{}; ///< uncompressed: chunk -> Delta IDC: \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + inline static int sNThreads{1}; ///< number of threads which are used during the calculations + + /// calculate I_0(r,\phi) = <I(r,\phi,t)>_t + void calcIDCZero(); + + /// calculate I_1(t) = <I(r,\phi,t) / I_0(r,\phi)>_{r,\phi} + void calcIDCOne(); + + /// calculate \Delta I(r,\phi,t) = I(r,\phi,t) / ( I_0(r,\phi) * I_1(t) ) + void calcIDCDelta(); + + /// draw IDCs for one sector for one integration interval + /// \param sector sector which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawSector(const IDCType type, const unsigned int sector, const unsigned int integrationInterval, const std::string filename, const IDCDeltaCompression compression = IDCDeltaCompression::NO) const; + + /// draw IDCs for one side for one integration interval + /// \param Side side which will be drawn + /// \param integrationInterval which will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawSide(const IDCType type, const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename, const IDCDeltaCompression compression = IDCDeltaCompression::NO) const; + + /// get z axis title for given IDC type and compression type + std::string getZAxisTitle(const IDCType type, const IDCDeltaCompression compression) const; + + /// get time frame and index of integrationInterval in the TF + void getTF(const unsigned int region, unsigned int integrationInterval, unsigned int& timeFrame, unsigned int& interval) const; + + /// \returns chunk from timeframe + unsigned int getChunk(const unsigned int timeframe) const; + + /// \return returns number of TFs for given chunk + unsigned int getNTFsPerChunk(const unsigned int chunk) const; + + ClassDefNV(IDCFactorization, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransform.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransform.h new file mode 100644 index 0000000000000..ddfc843e72a77 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransform.h @@ -0,0 +1,156 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCFourierTransform.h +/// \brief class for calculating the fourier coefficients from 1D-IDCs +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date May 11, 2021 + +#ifndef ALICEO2_IDCFOURIERTRANSFORM_H_ +#define ALICEO2_IDCFOURIERTRANSFORM_H_ + +#include <vector> +#include "Rtypes.h" +#include "DataFormatsTPC/Defs.h" +#include "TPCCalibration/IDCContainer.h" +#include "TPCCalibration/IDCFourierTransformBase.h" + +using fftwf_plan = struct fftwf_plan_s*; +using fftwf_complex = float[2]; + +namespace o2::tpc +{ + +/// class for fourier transform of 1D-IDCs +/// For example usage see testO2TPCIDCFourierTransform.cxx + +/// \tparam Type type which can either be IDCFourierTransformBaseEPN for synchronous reconstruction or IDCFourierTransformBaseAggregator for aggregator +template <class Type> // do not use enum class as type to avoid problems with ROOT dictionary generation! +class IDCFourierTransform : public IDCFourierTransformBase<Type> +{ + public: + /// constructor for AGGREGATOR type + /// \param rangeIDC number of IDCs for each interval which will be used to calculate the fourier coefficients + /// \param timeFrames number of time frames which will be stored + /// \param nFourierCoefficientsStore number of courier coefficients (real+imag) which will be stored (the maximum can be 'rangeIDC + 2', should be an even number when using naive FT). If less than maximum is setn the inverse fourier transform will not work. + template <bool IsEnabled = true, typename std::enable_if<(IsEnabled && (std::is_same<Type, IDCFourierTransformBaseAggregator>::value)), int>::type = 0> + IDCFourierTransform(const unsigned int rangeIDC = 200, const unsigned int timeFrames = 2000, const unsigned int nFourierCoefficientsStore = 200 + 2) : IDCFourierTransformAggregator(rangeIDC, timeFrames), mFourierCoefficients{timeFrames, nFourierCoefficientsStore}, mVal1DIDCs(sNThreads), mCoefficients(sNThreads) + { + initFFTW3Members(); + }; + + /// constructor for EPN type + /// \param rangeIDC number of IDCs for each interval which will be used to calculate the fourier coefficients + /// \param nFourierCoefficientsStore number of courier coefficients (real+imag) which will be stored (the maximum can be 'rangeIDC + 2', should be an even number when using naive FT). If less than maximum is setn the inverse fourier transform will not work. + template <bool IsEnabled = true, typename std::enable_if<(IsEnabled && (std::is_same<Type, IDCFourierTransformBaseEPN>::value)), int>::type = 0> + IDCFourierTransform(const unsigned int rangeIDC = 200, const unsigned int nFourierCoefficientsStore = 200 + 2) : IDCFourierTransformEPN(rangeIDC), mFourierCoefficients{1, nFourierCoefficientsStore}, mVal1DIDCs(sNThreads), mCoefficients(sNThreads) + { + initFFTW3Members(); + }; + + // Destructor + ~IDCFourierTransform(); + + /// set fast fourier transform using FFTW3 + /// \param fft use FFTW3 or not (naive approach) + static void setFFT(const bool fft) { sFftw = fft; } + + /// This function has to be called before the constructor is called + /// \param nThreads set the number of threads used for calculation of the fourier coefficients + template <bool IsEnabled = true, typename std::enable_if<(IsEnabled && (std::is_same<Type, IDCFourierTransformBaseAggregator>::value)), int>::type = 0> + static void setNThreads(const int nThreads) + { + sNThreads = nThreads; + } + + /// calculate fourier coefficients + void calcFourierCoefficients() { sFftw ? calcFourierCoefficientsFFTW3() : calcFourierCoefficientsNaive(); } + + /// get IDC0 values from the inverse fourier transform. Can be used for debugging. std::vector<std::vector<float>>: first vector interval second vector IDC0 values + /// \param side TPC side + std::vector<std::vector<float>> inverseFourierTransform(const o2::tpc::Side side) const { return sFftw ? inverseFourierTransformFFTW3(side) : inverseFourierTransformNaive(side); } + + /// \return returns number of IDCs for each interval which will be used to calculate the fourier coefficients + unsigned int getrangeIDC() const { return this->mRangeIDC; } + + /// \return returns struct holding all fourier coefficients + const auto& getFourierCoefficients() const { return mFourierCoefficients; } + + /// get type of used fourier transform + static bool getFFT() { return sFftw; } + + /// get the number of threads used for calculation of the fourier coefficients + static int getNThreads() { return sNThreads; } + + /// dump object to disc + /// \param outFileName name of the output file + /// \param outName name of the object in the output file + void dumpToFile(const char* outFileName = "Fourier.root", const char* outName = "FourierCoefficients") const; + + /// create debug tree + /// \param outFileName name of the output tree + void dumpToTree(const char* outFileName = "FourierTree.root") const; + + /// printing information about the algorithms which are used by FFTW for debugging e.g. seeing if SIMD instructions will be used + void printFFTWPlan() const; + + private: + FourierCoeff mFourierCoefficients; ///< fourier coefficients. side -> interval -> coefficient + inline static int sFftw{1}; ///< using fftw or naive approach for calculation of fourier coefficients + inline static int sNThreads{1}; ///< number of threads which are used during the calculation of the fourier coefficients + fftwf_plan mFFTWPlan{nullptr}; ///<! FFTW plan which is used during the ft + std::vector<float*> mVal1DIDCs; ///<! buffer for the 1D-IDC values for SIMD usage (each thread will get his one obejct) + std::vector<fftwf_complex*> mCoefficients; ///<! buffer for coefficients (each thread will get his one obejct) + + /// calculate fourier coefficients + void calcFourierCoefficientsNaive(); + + /// calculate fourier coefficients + /// \param side TPC side + void calcFourierCoefficientsNaive(const o2::tpc::Side side); + + /// calculate fourier coefficients + void calcFourierCoefficientsFFTW3(); + + /// calculate fourier coefficients using FFTW3 package + /// get IDC0 values from the inverse fourier transform. Can be used for debugging. std::vector<std::vector<float>>: first vector interval second vector IDC0 values + /// \param side TPC side + void calcFourierCoefficientsFFTW3(const o2::tpc::Side side); + + /// get IDC0 values from the inverse fourier transform. Can be used for debugging. std::vector<std::vector<float>>: first vector interval second vector IDC0 values + /// \param side TPC side + std::vector<std::vector<float>> inverseFourierTransformNaive(const o2::tpc::Side side) const; + + /// get IDC0 values from the inverse fourier transform using FFTW3. Can be used for debugging. std::vector<std::vector<float>>: first vector interval second vector IDC0 values + /// \param side TPC side + std::vector<std::vector<float>> inverseFourierTransformFFTW3(const o2::tpc::Side side) const; + + /// divide coefficients by number of IDCs used + void normalizeCoefficients(const o2::tpc::Side side) + { + std::transform(mFourierCoefficients.mFourierCoefficients[side].begin(), mFourierCoefficients.mFourierCoefficients[side].end(), mFourierCoefficients.mFourierCoefficients[side].begin(), [norm = this->mRangeIDC](auto& val) { return val / norm; }); + }; + + /// \return returns maximum numbers of stored real/imag fourier coeffiecients + unsigned int getNMaxCoefficients() const { return this->mRangeIDC / 2 + 1; } + + /// initalizing fftw members + void initFFTW3Members(); + + /// performing of ft using FFTW + void fftwLoop(const std::vector<float>& idcOneExpanded, const std::vector<unsigned int>& offsetIndex, const unsigned int interval, const o2::tpc::Side side, const unsigned int thread); + + ClassDefNV(IDCFourierTransform, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransformBase.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransformBase.h new file mode 100644 index 0000000000000..e7ac3d6df1b6e --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCFourierTransformBase.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCFourierTransform.h +/// \brief base class for holding members and functions for separating between EPN and Agregator +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Jun 10, 2021 + +#ifndef ALICEO2_IDCFOURIERTRANSFORMBASE_H_ +#define ALICEO2_IDCFOURIERTRANSFORMBASE_H_ + +#include <vector> +#include "Rtypes.h" +#include "DataFormatsTPC/Defs.h" +#include "TPCCalibration/IDCContainer.h" + +namespace o2::tpc +{ + +template <class Type> +class IDCFourierTransformBase; + +// do not use enum class as type to avoid problems with ROOT dictionary generation! +class IDCFourierTransformBaseEPN; /// dummy class for templating IDCFourierTransformBase class +class IDCFourierTransformBaseAggregator; /// dummy class for templating IDCFourierTransformBase class +using IDCFourierTransformEPN = o2::tpc::IDCFourierTransformBase<o2::tpc::IDCFourierTransformBaseEPN>; +using IDCFourierTransformAggregator = o2::tpc::IDCFourierTransformBase<o2::tpc::IDCFourierTransformBaseAggregator>; + +template <> +class IDCFourierTransformBase<IDCFourierTransformBaseEPN> +{ + public: + /// constructor + /// \param rangeIDC number of IDCs for each interval which will be used to calculate the fourier coefficients + IDCFourierTransformBase(const unsigned int rangeIDC) : mRangeIDC{rangeIDC} {}; + + /// set input 1D-IDCs which are used to calculate fourier coefficients + /// \param oneDIDCs 1D-IDCs + void setIDCs(OneDIDC&& oneDIDCs) { mOneDIDC = std::move(oneDIDCs); } + + /// set input 1D-IDCs which are used to calculate fourier coefficients + /// \param oneDIDCs 1D-IDCs + void setIDCs(const OneDIDC& oneDIDCs) { mOneDIDC = oneDIDCs; } + + /// \return returns number of time frames (only 1!) for which the coefficients are obtained + static constexpr unsigned int getNIntervals() { return 1; } + + /// \return returns indices used for accessing correct IDCs for given TF + std::vector<unsigned int> getLastIntervals(const o2::tpc::Side side) const { return std::vector<unsigned int>{mOneDIDC.getNIDCs(side) - mRangeIDC}; } + + /// copy over IDCs from buffer to current IDCOne vector for easier access + /// \return returns expanded 1D-IDC vector + /// \param side TPC side + std::vector<float> getExpandedIDCOne(const o2::tpc::Side side) const { return mOneDIDC.mOneDIDC[side]; } + + /// \return returns struct of stored 1D-IDC + const OneDIDC& getOneDIDC() const { return mOneDIDC; } + + /// \return returns number of 1D-IDCs + /// \param side TPC side + unsigned long getNIDCs(const o2::tpc::Side side) const { return mOneDIDC.mOneDIDC[side].size(); } + + protected: + const unsigned int mRangeIDC{}; ///< number of IDCs used for the calculation of fourier coefficients + OneDIDC mOneDIDC{}; ///< all 1D-IDCs which are used to calculate the fourier coefficients. + ClassDefNV(IDCFourierTransformBase, 1) +}; + +template <> +class IDCFourierTransformBase<IDCFourierTransformBaseAggregator> +{ + public: + /// \param rangeIDC number of IDCs for each interval which will be used to calculate the fourier coefficients + /// \param timeFrames number of time frames which will be stored + IDCFourierTransformBase(const unsigned int rangeIDC, const unsigned int timeFrames) : mRangeIDC{rangeIDC}, mTimeFrames{timeFrames} {}; + + /// set input 1D-IDCs which are used to calculate fourier coefficients + /// \param oneDIDCs 1D-IDCs + /// \param integrationIntervalsPerTF vector containg for each TF the number of IDCs + void setIDCs(OneDIDC&& oneDIDCs, std::vector<unsigned int>&& integrationIntervalsPerTF); + + /// set input 1D-IDCs which are used to calculate fourier coefficients + /// \param oneDIDCs 1D-IDCs + /// \param integrationIntervalsPerTF vector containg for each TF the number of IDCs + void setIDCs(const OneDIDC& oneDIDCs, const std::vector<unsigned int>& integrationIntervalsPerTF); + + /// \return returns number of 1D-IDCs + /// \param side TPC side + unsigned long getNIDCs(const o2::tpc::Side side) const { return mOneDIDC[!mBufferIndex].mOneDIDC[side].size(); } + + /// \return returns number of time frames for which the coefficients are obtained + unsigned int getNIntervals() const { return mTimeFrames; } + + /// \return returns struct of stored 1D-IDC + const OneDIDC& getOneDIDC() const { return mOneDIDC[!mBufferIndex]; } + + /// \return returns indices used for accessing correct IDCs for given TF + std::vector<unsigned int> getLastIntervals(o2::tpc::Side) const; + + /// copy over IDCs from buffer to current IDCOne vector for easier access + /// \return returns expanded 1D-IDC vector + /// \param side TPC side + std::vector<float> getExpandedIDCOne(const o2::tpc::Side side) const; + + /// allocate memory for variable holding getrangeIDC() IDCs + /// \param side TPC side + float* allocMemFFTW(const o2::tpc::Side side) const; + + protected: + const unsigned int mRangeIDC{}; ///< number of IDCs used for the calculation of fourier coefficients + const unsigned int mTimeFrames{}; ///< number of timeframes which for which teh fourier coefficients are stored + std::array<OneDIDC, 2> mOneDIDC{OneDIDC(mRangeIDC), OneDIDC(mRangeIDC)}; ///< all 1D-IDCs which are used to calculate the fourier coefficients. A buffer for the last aggregation interval is used to calculate the fourier coefficients for the first TFs + std::array<std::vector<unsigned int>, 2> mIntegrationIntervalsPerTF{}; ///< number of integration intervals per TF used to set the correct range of IDCs. A buffer is needed for the last aggregation interval. + bool mBufferIndex{true}; ///< index for the buffer + + /// returns whether the buffer has to be used + bool useLastBuffer() const { return (mRangeIDC > mIntegrationIntervalsPerTF[!mBufferIndex][0]); } + + ClassDefNV(IDCFourierTransformBase, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCGroup.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroup.h new file mode 100644 index 0000000000000..758b5c3535219 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroup.h @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCGroup.h +/// \brief class for storing grouped IDCs +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_IDCGROUP_H_ +#define ALICEO2_TPC_IDCGROUP_H_ + +#include <vector> +#include "Rtypes.h" +#include "TPCCalibration/IDCGroupHelperRegion.h" + +namespace o2::tpc +{ + +/// Class to hold grouped IDC values for one CRU for one TF + +class IDCGroup : public IDCGroupHelperRegion +{ + public: + /// constructor + /// \param groupPads number of pads in pad direction which will be grouped + /// \param groupRows number of pads in row direction which will be grouped + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction + /// \param region region of the TPC + IDCGroup(const unsigned char groupPads = 4, const unsigned char groupRows = 4, const unsigned char groupLastRowsThreshold = 2, const unsigned char groupLastPadsThreshold = 2, const unsigned int region = 0) + : IDCGroupHelperRegion{groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold, region}, mIDCsGrouped(getNIDCsPerIntegrationInterval()){}; + + /// extend the size of the grouped and averaged IDC values corresponding to the number of integration intervals. This has to be called befor filling values! + /// without using this function the object can hold only one integration interval + /// \param nIntegrationIntervals number of ontegration intervals for which teh IDCs are stored + void resize(const unsigned int nIntegrationIntervals) { mIDCsGrouped.resize(getNIDCsPerIntegrationInterval() * nIntegrationIntervals); } + + /// \return returns the stored value + /// \param glrow local row of the grouped IDCs + /// \param pad pad number of the grouped IDCs + /// \param integrationInterval integration interval + float operator()(unsigned int glrow, unsigned int pad, unsigned int integrationInterval) const { return mIDCsGrouped[getIndex(glrow, pad, integrationInterval)]; } + + /// \return returns the stored value + /// \param glrow local row of the grouped IDCs + /// \param pad pad number of the grouped IDCs + /// \param integrationInterval integration interval + float& operator()(unsigned int glrow, unsigned int pad, unsigned int integrationInterval) { return mIDCsGrouped[getIndex(glrow, pad, integrationInterval)]; } + + /// \return returns the stored value for local ungrouped pad row and ungrouped pad + /// \param ulrow local row in region of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float& setValUngrouped(unsigned int ulrow, unsigned int upad, unsigned int integrationInterval) { return mIDCsGrouped[getIndexUngrouped(ulrow, upad, integrationInterval)]; } + + /// \return returns the stored value for local ungrouped pad row and ungrouped pad + /// \param ulrow local row in region of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float getValUngrouped(unsigned int ulrow, unsigned int upad, unsigned int integrationInterval) const { return mIDCsGrouped[getIndexUngrouped(ulrow, upad, integrationInterval)]; } + + /// \return returns the stored value for local ungrouped pad row and ungrouped pad + /// \param ugrow global row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + float getValUngroupedGlobal(unsigned int ugrow, unsigned int upad, unsigned int integrationInterval) const; + + /// \return returns grouped and averaged IDC values + const auto& getData() const& { return mIDCsGrouped; } + + /// \return returns grouped and averaged IDC values using move semantics + auto getData() && { return std::move(mIDCsGrouped); } + + /// \return returns number of stored integration intervals + unsigned int getNIntegrationIntervals() const { return mIDCsGrouped.size() / getNIDCsPerIntegrationInterval(); } + + /// dump the IDCs to a tree + /// \param outname name of the output file + void dumpToTree(const char* outname = "IDCGroup.root") const; + + /// dump object to disc + /// \param outFileName name of the output file + /// \param outName name of the object in the output file + void dumpToFile(const char* outFileName = "IDCGroup.root", const char* outName = "IDCGroup") const; + + /// draw grouped IDCs + /// \param integrationInterval integration interval for which the IDCs will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void draw(const unsigned int integrationInterval = 0, const std::string filename = "IDCsGrouped.pdf") const; + + /// calculate and return 1D-IDCs for this CRU + std::vector<float> get1DIDCs() const; + + private: + std::vector<float> mIDCsGrouped{}; ///< grouped and averaged IDC values for n integration intervals for one CRU + + ClassDefNV(IDCGroup, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperRegion.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperRegion.h new file mode 100644 index 0000000000000..be0d1a3a08504 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperRegion.h @@ -0,0 +1,149 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCGroupHelperRegion.h +/// \brief helper class for grouping of pads and rows for one region +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_IDCGROUPHELPERREGION_H_ +#define ALICEO2_TPC_IDCGROUPHELPERREGION_H_ + +#include <vector> +#include "Rtypes.h" + +namespace o2::tpc +{ + +/// Helper class for accessing grouped pads for one region + +class IDCGroupHelperRegion +{ + public: + /// constructor + /// \param groupPads number of pads in pad direction which will be grouped + /// \param groupRows number of pads in row direction which will be grouped + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction + /// \param region region of the TPC + IDCGroupHelperRegion(const unsigned char groupPads = 4, const unsigned char groupRows = 4, const unsigned char groupLastRowsThreshold = 2, const unsigned char groupLastPadsThreshold = 2, const unsigned int region = 0) + : mGroupPads{groupPads}, mGroupRows{groupRows}, mGroupLastRowsThreshold{groupLastRowsThreshold}, mGroupLastPadsThreshold{groupLastPadsThreshold}, mRegion{region} + { + initIDCGroupHelperRegion(); + } + + /// \return returns number of grouped rows + unsigned int getNRows() const { return mRows; } + + /// \return returns number of grouped pads + /// \param row grouped local row + unsigned int getPadsPerRow(const unsigned int glrow) const { return mPadsPerRow[glrow]; } + + /// \return returns number of grouped pads for all rows + const std::vector<unsigned int>& getPadsPerRow() const { return mPadsPerRow; } + + /// \return returns offsets for rows to calculate data index + const std::vector<unsigned int>& getRowOffset() const { return mOffsRow; } + + /// \return returns the number of pads in pad direction which are grouped + unsigned int getGroupPads() const { return mGroupPads; } + + /// \return returns the number of pads in row direction which are grouped + unsigned int getGroupRows() const { return mGroupRows; } + + /// \return returns threshold for grouping the last group in row direction + unsigned int getGroupLastRowsThreshold() const { return mGroupLastRowsThreshold; } + + /// \return returns threshold for grouping the last group in pad direction + unsigned int getGroupLastPadsThreshold() const { return mGroupLastPadsThreshold; } + + /// \return returns the region for which the IDCs are stored + unsigned int getRegion() const { return mRegion; } + + /// \returns returns number of IDCS per integration interval + unsigned int getNIDCsPerIntegrationInterval() const { return mNIDCsPerCRU; } + + /// \return returns the row of the group from the local ungrouped row in a region + /// \param ulrow local ungrouped row in a region + /// \param groupRows grouping parameter for number of pads in row direction which are grouped + /// \param groupedrows number of grouped rows + static unsigned int getGroupedRow(const unsigned int ulrow, const unsigned int groupRows, const unsigned int groupedrows); + + /// \return returns the row of the group from the local ungrouped row in a region + /// \param ulrow local ungrouped row in a region + unsigned int getGroupedRow(const unsigned int ulrow) const { return getGroupedRow(ulrow, mGroupRows, mRows); } + + /// \return returns the grouped pad index from ungrouped pad and row + /// \param upad ungrouped pad + /// \param ulrow local ungrouped row in a region + /// \param region region + /// \param groupPads grouping parameter for number of pads in pad direction which are grouped + /// \param groupRows grouping parameter for number of pads in row direction which are grouped + /// \param groupedrows number of grouped rows + /// \param padsPerRow vector containing the number of pads per row + static unsigned int getGroupedPad(const unsigned int upad, const unsigned int ulrow, const unsigned int region, const unsigned int groupPads, const unsigned int groupRows, const unsigned int groupedrows, const std::vector<unsigned int>& padsPerRow); + + /// \return returns the grouped pad index from ungrouped pad and row + /// \param pad ungrouped pad + /// \param lrow local ungrouped row in a region + unsigned int getGroupedPad(const unsigned int pad, const unsigned int ulrow) const { return getGroupedPad(pad, ulrow, mRegion, mGroupPads, mGroupRows, mRows, mPadsPerRow); }; + + /// \return returns index to the data + /// \param row local row of the grouped IDCs + /// \param pad pad of the grouped IDCs + /// \param integrationInterval integration interval + unsigned int getIndex(const unsigned int glrow, const unsigned int pad, unsigned int integrationInterval) const { return mNIDCsPerCRU * integrationInterval + mOffsRow[glrow] + pad; } + + /// \return returns index to the data + /// \param urow local ungrouped row + /// \param upad ungrouped pad + /// \param integrationInterval integration interval + unsigned int getIndexUngrouped(const unsigned int ulrow, const unsigned int upad, unsigned int integrationInterval) const { return getIndex(getGroupedRow(ulrow), getGroupedPad(upad, ulrow), integrationInterval); } + + /// \return returns the global pad number for given local pad row and pad + /// \param ulrow local ungrouped row in a region + /// \param pad ungrouped pad in row + unsigned int getGlobalPadNumber(const unsigned int ulrow, const unsigned int pad) const; + + /// \return returns last ungrouped row + unsigned int getLastRow() const; + + /// \return returns last ungrouped pad for given global row + /// \param row local ungrouped row + unsigned int getLastPad(const unsigned int ulrow) const; + + /// dump object to disc + /// \param outFileName name of the output file + /// \param outName name of the object in the output file + void dumpToFile(const char* outFileName = "IDCGroupHelperRegion.root", const char* outName = "IDCGroupHelperRegion") const; + + protected: + const unsigned char mGroupPads{}; ///< grouping parameter in pad direction (how many pads in pad direction are grouped) + const unsigned char mGroupRows{}; ///< grouping parameter in pad direction (how many pads in pad direction are grouped) + const unsigned char mGroupLastRowsThreshold{}; ///< if the last group (region edges) consists in row direction less then mGroupLastRowsThreshold pads then it will be grouped into the previous group + const unsigned char mGroupLastPadsThreshold{}; ///< if the last group (sector edges) consists in pad direction less then mGroupLastPadsThreshold pads then it will be grouped into the previous group + const unsigned int mRegion{}; ///< region of input IDCs + unsigned int mNIDCsPerCRU{}; ///< total number of IDCs per CRU per integration interval + unsigned int mRows{}; ///< number of grouped rows + std::vector<unsigned int> mPadsPerRow{}; ///< number of grouped pads per grouped row + std::vector<unsigned int> mOffsRow{}; ///< offset to calculate the index in the data from grouped row and grouped pad + + /// set number of grouped rows + void setRows(const unsigned int nRows); + + /// initialize members + void initIDCGroupHelperRegion(); + + ClassDefNV(IDCGroupHelperRegion, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperSector.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperSector.h new file mode 100644 index 0000000000000..89662d8184b6d --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupHelperSector.h @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCGroupHelperSector.h +/// \brief helper class for grouping of pads and rows for one sector +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_IDCGROUPHELPERSECTOR_H_ +#define ALICEO2_TPC_IDCGROUPHELPERSECTOR_H_ + +#include <vector> +#include <numeric> +#include "Rtypes.h" +#include "TPCBase/Mapper.h" +#include "TPCCalibration/IDCGroupHelperRegion.h" +#include "TPCCalibration/IDCGroupingParameter.h" + +namespace o2::tpc +{ + +/// Helper class for accessing grouped pads for one sector + +class IDCGroupHelperSector +{ + public: + /// constructor + /// \param groupPads number of pads in pad direction which will be grouped + /// \param groupRows number of pads in row direction which will be grouped + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction + IDCGroupHelperSector(const std::array<unsigned char, Mapper::NREGIONS>& groupPads, const std::array<unsigned char, Mapper::NREGIONS>& groupRows, const std::array<unsigned char, Mapper::NREGIONS>& groupLastRowsThreshold, const std::array<unsigned char, Mapper::NREGIONS>& groupLastPadsThreshold) + : mGroupingPar{groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold} { initIDCGroupHelperSector(); }; + + /// constructor + /// \param groupingParameter struct holding the grouping parameter + IDCGroupHelperSector(const ParameterIDCGroupCCDB& groupingParameter) : mGroupingPar{groupingParameter} { initIDCGroupHelperSector(); }; + + /// default constructor for ROOT I/O + IDCGroupHelperSector() = default; + + /// \return returns index to the data + /// \param glrow grouped local row + /// \param pad pad of the grouped IDCs + unsigned int getIndexGrouped(const unsigned int sector, const unsigned int region, const unsigned int glrow, const unsigned int pad, unsigned int integrationInterval) const { return mNIDCsPerSector * (integrationInterval * SECTORSPERSIDE + sector) + mRegionOffs[region] + mOffsRow[region][glrow] + pad; } + + /// \return returns the index to the grouped data with ungrouped inputs + /// \param sector sector + /// \param region TPC region + /// \param ulrow row of the ungrouped IDCs + /// \param upad pad number of the ungrouped IDCs + /// \param integrationInterval integration interval + unsigned int getIndexUngrouped(const unsigned int sector, const unsigned int region, unsigned int ulrow, unsigned int upad, unsigned int integrationInterval) const { return getIndexGrouped(sector % o2::tpc::SECTORSPERSIDE, region, getGroupedRow(region, ulrow), getGroupedPad(region, ulrow, upad), integrationInterval); } + + /// \return returns grouped pad for ungrouped row and pad + /// \param region region + /// \param ulrow local ungrouped row in a region + /// \param upad ungrouped pad + unsigned int getGroupedPad(const unsigned int region, unsigned int ulrow, unsigned int upad) const { return IDCGroupHelperRegion::getGroupedPad(upad, ulrow, region, mGroupingPar.GroupPads[region], mGroupingPar.GroupRows[region], mRows[region], mPadsPerRow[region]); } + + /// \return returns the row of the group from the local ungrouped row in a region + /// \param region region + /// \param ulrow local ungrouped row in a region + unsigned int getGroupedRow(const unsigned int region, unsigned int ulrow) const { return IDCGroupHelperRegion::getGroupedRow(ulrow, mGroupingPar.GroupRows[region], mRows[region]); } + + /// \returns grouping parameter + const auto& getGroupingParameter() const { return mGroupingPar; } + + /// \return returns number if IDCs for given region + unsigned int getNIDCs(const unsigned int region) { return mNIDCsPerCRU[region]; } + + protected: + ParameterIDCGroupCCDB mGroupingPar{}; ///< struct containg the grouping parameter + std::array<unsigned int, Mapper::NREGIONS> mNIDCsPerCRU{}; ///< total number of IDCs per region per integration interval + unsigned int mNIDCsPerSector{}; ///< number of grouped IDCs per sector + std::array<unsigned int, Mapper::NREGIONS> mRows{}; ///< number of grouped rows per region + std::array<unsigned int, Mapper::NREGIONS> mRegionOffs{}; ///< offset for the region per region + std::array<std::vector<unsigned int>, Mapper::NREGIONS> mPadsPerRow{}; ///< number of pads per row per region + std::array<std::vector<unsigned int>, Mapper::NREGIONS> mOffsRow{}; ///< offset to calculate the index in the data from row and pad per region + + void initIDCGroupHelperSector() + { + for (unsigned int reg = 0; reg < Mapper::NREGIONS; ++reg) { + const IDCGroupHelperRegion groupTmp(mGroupingPar.GroupPads[reg], mGroupingPar.GroupRows[reg], mGroupingPar.GroupLastRowsThreshold[reg], mGroupingPar.GroupLastPadsThreshold[reg], reg); + mNIDCsPerCRU[reg] = groupTmp.getNIDCsPerIntegrationInterval(); + mRows[reg] = groupTmp.getNRows(); + mPadsPerRow[reg] = groupTmp.getPadsPerRow(); + mOffsRow[reg] = groupTmp.getRowOffset(); + if (reg > 0) { + const unsigned int lastInd = reg - 1; + mRegionOffs[reg] = mRegionOffs[lastInd] + mNIDCsPerCRU[lastInd]; + } + } + mNIDCsPerSector = static_cast<unsigned int>(std::accumulate(mNIDCsPerCRU.begin(), mNIDCsPerCRU.end(), decltype(mNIDCsPerCRU)::value_type(0))); + } + + ClassDefNV(IDCGroupHelperSector, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupingParameter.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupingParameter.h new file mode 100644 index 0000000000000..1d429e9b7192f --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCGroupingParameter.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCGroupingParameter.h +/// \brief Definition of the parameter for the grouping of the IDCs +/// \author Matthias Kleiner, mkleiner@ikf.uni-frankfurt.de + +#ifndef ALICEO2_TPC_IDCGROUPINGPARAMETER_H_ +#define ALICEO2_TPC_IDCGROUPINGPARAMETER_H_ + +#include <array> +#include "CommonUtils/ConfigurableParamHelper.h" +#include "TPCBase/Mapper.h" + +namespace o2 +{ +namespace tpc +{ + +/// averaging methods which is used for averaging IDCs from grouped pads +enum class AveragingMethod : char { + FAST = 0, ///< no outlier filtering performed. Only averaging + SLOW = 1 ///< Outlier filtering performed. Filtering + averaging +}; + +/// struct for setting the parameters for the grouping of IDCs +struct ParameterIDCGroup : public o2::conf::ConfigurableParamHelper<ParameterIDCGroup> { + unsigned char GroupPads[Mapper::NREGIONS]{7, 7, 7, 7, 6, 6, 6, 6, 5, 5}; ///< grouping parameter in pad direction (how many pads are grouped) + unsigned char GroupRows[Mapper::NREGIONS]{5, 5, 5, 5, 4, 4, 4, 4, 3, 3}; ///< group parameter in row direction (how many rows are grouped) + unsigned char GroupLastRowsThreshold[Mapper::NREGIONS]{3, 3, 3, 3, 2, 2, 2, 2, 2, 2}; ///< if the last group (region edges) consists in row direction less then mGroupLastRowsThreshold pads then it will be grouped into the previous group + unsigned char GroupLastPadsThreshold[Mapper::NREGIONS]{3, 3, 3, 3, 2, 2, 2, 2, 1, 1}; ///< if the last group (sector edges) consists in pad direction less then mGroupLastPadsThreshold pads then it will be grouped into the previous group + AveragingMethod Method = AveragingMethod::SLOW; ///< method which is used for averaging + + O2ParamDef(ParameterIDCGroup, "TPCIDCGroupParam"); +}; + +/// struct for storing the parameters for the grouping of IDCs to CCDB +struct ParameterIDCGroupCCDB { + + /// contructor + /// \param groupPads number of pads in pad direction which are grouped + /// \param groupRows number of pads in row direction which are grouped + /// \param groupLastRowsThreshold minimum number of pads in row direction for the last group in row direction + /// \param groupLastPadsThreshold minimum number of pads in pad direction for the last group in pad direction + ParameterIDCGroupCCDB(const std::array<unsigned char, Mapper::NREGIONS>& groupPads, const std::array<unsigned char, Mapper::NREGIONS>& groupRows, const std::array<unsigned char, Mapper::NREGIONS>& groupLastRowsThreshold, const std::array<unsigned char, Mapper::NREGIONS>& groupLastPadsThreshold) + : GroupPads{groupPads}, GroupRows{groupRows}, GroupLastRowsThreshold{groupLastRowsThreshold}, GroupLastPadsThreshold{groupLastPadsThreshold} {}; + + ParameterIDCGroupCCDB() = default; + + /// \return returns number of pads in pad direction which are grouped + /// \parameter region TPC region + unsigned char getGroupPads(const unsigned int region) const { return GroupPads[region]; } + + /// \return returns number of pads in row direction which are grouped + /// \parameter region TPC region + unsigned char getGroupRows(const unsigned int region) const { return GroupRows[region]; } + + /// \return returns minimum number of pads in row direction for the last group in row direction + /// \parameter region TPC region + unsigned char getGroupLastRowsThreshold(const unsigned int region) const { return GroupLastRowsThreshold[region]; } + + /// \return returns minimum number of pads in pad direction for the last group in pad direction + /// \parameter region TPC region + unsigned char getGroupLastPadsThreshold(const unsigned int region) const { return GroupLastPadsThreshold[region]; } + + /// \return returns number of pads in pad direction which are grouped for all regions + const std::array<unsigned char, Mapper::NREGIONS>& getGroupPads() const { return GroupPads; } + + /// \return returns number of pads in row direction which are grouped for all regions + const std::array<unsigned char, Mapper::NREGIONS>& getGroupRows() const { return GroupRows; } + + /// \return returns minimum number of pads in row direction for the last group in row direction for all regions + const std::array<unsigned char, Mapper::NREGIONS>& getGroupLastRowsThreshold() const { return GroupLastRowsThreshold; } + + /// \return returns minimum number of pads in pad direction for the last group in pad direction for all regions + const std::array<unsigned char, Mapper::NREGIONS>& getGroupLastPadsThreshold() const { return GroupLastPadsThreshold; } + + std::array<unsigned char, Mapper::NREGIONS> GroupPads{}; ///< grouping parameter in pad direction (how many pads in pad direction are grouped) + std::array<unsigned char, Mapper::NREGIONS> GroupRows{}; ///< grouping parameter in pad direction (how many pads in pad direction are grouped) + std::array<unsigned char, Mapper::NREGIONS> GroupLastRowsThreshold{}; ///< if the last group (region edges) consists in row direction less then mGroupLastRowsThreshold pads then it will be grouped into the previous group + std::array<unsigned char, Mapper::NREGIONS> GroupLastPadsThreshold{}; ///< if the last group (sector edges) consists in pad direction less then mGroupLastPadsThreshold pads then it will be grouped into the previous group +}; + +struct ParameterIDCCompression : public o2::conf::ConfigurableParamHelper<ParameterIDCCompression> { + float MaxIDCDeltaValue = 0.3f; ///< maximum Delta IDC + O2ParamDef(ParameterIDCCompression, "TPCIDCCompressionParam"); +}; + +} // namespace tpc +} // namespace o2 + +#endif // ALICEO2_TPC_ParameterGEM_H_ diff --git a/Detectors/TPC/calibration/include/TPCCalibration/LaserTracksCalibrator.h b/Detectors/TPC/calibration/include/TPCCalibration/LaserTracksCalibrator.h new file mode 100644 index 0000000000000..8ada7e0027bb9 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/LaserTracksCalibrator.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file LaserTracksCalibrator.h +/// \brief time slot calibration using laser tracks +/// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#ifndef TPC_LaserTracksCalibrator_H_ +#define TPC_LaserTracksCalibrator_H_ + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" + +#include "TPCCalibration/CalibLaserTracks.h" + +namespace o2::tpc +{ + +class LaserTracksCalibrator : public o2::calibration::TimeSlotCalibration<TrackTPC, CalibLaserTracks> +{ + using TFType = uint64_t; + using Slot = o2::calibration::TimeSlot<o2::tpc::CalibLaserTracks>; + + public: + LaserTracksCalibrator() = default; + LaserTracksCalibrator(size_t minTFs) : mMinTFs(minTFs) {} + ~LaserTracksCalibrator() final = default; + + bool hasEnoughData(const Slot& slot) const final { return slot.getContainer()->hasEnoughData(mMinTFs); } + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) final; + + const auto& getCalibPerSlot() { return mCalibPerSlot; } + bool hasCalibrationData() const { return mCalibPerSlot.size() > 0; } + + void setWriteDebug(bool debug = true) { mWriteDebug = debug; } + bool getWriteDebug() const { return mWriteDebug; } + + void setMinTFs(size_t minTFs) { mMinTFs = minTFs; } + size_t getMinTFs() const { return mMinTFs; } + + private: + size_t mMinTFs = 100; ///< laser tracks of these amount of time frames + std::vector<LtrCalibData> mCalibPerSlot; ///< drift velocity per slot + bool mWriteDebug = false; ///< if to save debug trees + + ClassDefOverride(LaserTracksCalibrator, 1); +}; +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h b/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h new file mode 100644 index 0000000000000..a124d998805c0 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RobustAverage.h +/// \brief class for performing robust averaging and outlier filtering +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_ROBUSTAVERAGE_H_ +#define ALICEO2_ROBUSTAVERAGE_H_ + +#include <vector> + +namespace o2::tpc +{ + +/// class to perform filtering of outliers and robust averaging of a set of values. +/// This class is more or less a dummy for now... TODO add more sophisticated methods +/// +/// Usage using existing data: +/// 1. std::vector<float> values{1., 2., 2.3}; +/// 2. o2::tpc::RobustAverage rob(std::move(values)); +/// 3. float average = rob.getFilteredAverage(3); +/// +/// Usage using copy of data: +/// 1. o2::tpc::RobustAverage rob(3); +/// 2. rob.addValue(1.); +/// rob.addValue(2.); +/// rob.addValue(2.3); +/// 3. float average = rob.getFilteredAverage(3); +/// + +class RobustAverage +{ + public: + /// constructor + /// \param maxValues maximum number of values which will be averaged. Copy of values will be done. + RobustAverage(const unsigned int maxValues) { mValues.reserve(maxValues); } + + /// default constructor + RobustAverage() = default; + + /// constructor + /// \param values values which will be averaged and filtered. Move operator is used here! + RobustAverage(std::vector<float>&& values) : mValues{std::move(values)} {}; + + /// reserve memory for member + /// \param maxValues maximum number of values which will be averaged. Copy of values will be done. + void reserve(const unsigned int maxValues) { mValues.reserve(maxValues); } + + /// clear the stored values + void clear() { mValues.clear(); } + + /// \param value value which will be added to the list of stored values for averaging + void addValue(const float value) { mValues.emplace_back(value); } + + /// returns the filtered average value + /// \param sigma maximum accepted standard deviation: sigma*stdev + float getFilteredAverage(const float sigma = 3); + + /// \return returns mean of stored values + float getMean() const { return getMean(mValues.begin(), mValues.end()); } + + /// values which will be averaged and filtered + void print() const; + + private: + std::vector<float> mValues{}; ///< values which will be averaged and filtered + std::vector<float> mTmpValues{}; ///< tmp vector used for calculation of std dev + + float getMean(std::vector<float>::const_iterator begin, std::vector<float>::const_iterator end) const; + + /// performing outlier filtering of the stored values + float getStdDev(const float mean); + + /// performing outlier filtering of the stored values by defining range of included values in terms of standard deviation + /// \param mean mean of the stored values + /// \param stdev standard deviation of the values + /// \param sigma maximum accepted standard deviation: sigma*stdev + float getFilteredMean(const float mean, const float stdev, const float sigma); +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/calibration/include/TPCCalibration/dEdxHistos.h b/Detectors/TPC/calibration/include/TPCCalibration/dEdxHistos.h new file mode 100644 index 0000000000000..e54946f56b385 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/dEdxHistos.h @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file dEdxHistos.h +/// \brief This file provides the container used for time based dE/dx calibration. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#ifndef ALICEO2_TPC_DEDXHISTOS_H_ +#define ALICEO2_TPC_DEDXHISTOS_H_ + +#include <array> +#include <gsl/span> +#include <string_view> + +// o2 includes +#include "TPCCalibration/FastHisto.h" +#include "DataFormatsTPC/TrackCuts.h" + +namespace o2::tpc +{ + +// forward declaration +class TrackTPC; + +/// Class that creates dE/dx histograms from a sequence of tracks objects +class dEdxHistos +{ + using Hist = FastHisto<float>; + + public: + /// Default constructor + dEdxHistos() = default; + + /// Constructor that enable tracks cuts + dEdxHistos(unsigned int nBins, const TrackCuts& cuts); + + /// Constructor that enable tracks cuts, and creates a TrackCuts internally + dEdxHistos(unsigned int nBins, float minP = 0.4, float maxP = 0.6, int minClusters = 60) + : dEdxHistos(nBins, {minP, maxP, static_cast<float>(minClusters)}) {} + + /// Fill histograms using tracks data + void fill(const gsl::span<const TrackTPC> tracks); + + /// Add counts from other container + void merge(const dEdxHistos* other); + + /// Print the number of entries in each histogram + void print() const; + + void setApplyCuts(bool apply) { mApplyCuts = apply; } + bool getApplyCuts() { return mApplyCuts; } + void setCuts(const TrackCuts& cuts) { mCuts = cuts; } + + /// \return number of entries in the A side histogram + double getASideEntries() const { return mEntries[0]; } + + /// \return number of entries in the C side histogram + double getCSideEntries() const { return mEntries[1]; } + + /// Get the underlying histograms + const std::array<Hist, 2>& getHists() const { return mHist; } + + /// Save the histograms to a file + void dumpToFile(std::string_view fileName) const; + + private: + bool mApplyCuts{true}; ///< Whether or not to apply tracks cuts + TrackCuts mCuts; ///< Cut class + + std::array<float, 2> mEntries{0, 0}; ///< Number of entries in each histogram + std::array<Hist, 2> mHist; ///< MIP position histograms, for TPC's A and C sides + + ClassDefNV(dEdxHistos, 1); +}; + +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C b/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C index dcb6a398a47ac..5f998453d9515 100644 --- a/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C +++ b/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C b/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C index 974e62940bf6d..2947c37c9ef20 100644 --- a/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C +++ b/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C @@ -1,14 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #if !defined(__CLING__) || defined(__ROOTCLING__) +#include <string> +#include <string_view> +#include <fmt/format.h> + #include "TROOT.h" #include "TMath.h" #include "TH2.h" @@ -16,6 +21,7 @@ #include "TPCBase/CalDet.h" #include "TPCBase/Painter.h" #include "TPCBase/Utils.h" +#include "TPCBase/CDBInterface.h" #include "TPad.h" #include "TCanvas.h" #include "TH1F.h" @@ -38,15 +44,36 @@ TObjArray* drawNoiseAndPedestal(std::string_view pedestalFile, int mode = 0, std arrCanvases->SetName("NoiseAndPedestals"); using namespace o2::tpc; - TFile f(pedestalFile.data()); - gROOT->cd(); // ===| load noise and pedestal from file |=== CalDet<float> dummy; - CalDet<float>* calPedestal = nullptr; - CalDet<float>* calNoise = nullptr; - f.GetObject("Pedestals", calPedestal); - f.GetObject("Noise", calNoise); + const CalDet<float>* calPedestal = nullptr; + const CalDet<float>* calNoise = nullptr; + + if (pedestalFile.find("cdb") != std::string::npos) { + auto& cdb = CDBInterface::instance(); + if (pedestalFile.find("cdb-test") == 0) { + cdb.setURL("http://ccdb-test.cern.ch:8080"); + } else if (pedestalFile.find("cdb-prod") == 0) { + cdb.setURL(""); + } + const auto timePos = pedestalFile.find("@"); + if (timePos != std::string_view::npos) { + std::cout << "set time stamp " << std::stol(pedestalFile.substr(timePos + 1).data()) << "\n"; + cdb.setTimeStamp(std::stol(pedestalFile.substr(timePos + 1).data())); + } + calPedestal = &cdb.getPedestals(); + calNoise = &cdb.getNoise(); + } else { + TFile f(pedestalFile.data()); + gROOT->cd(); + f.GetObject("Pedestals", calPedestal); + f.GetObject("Noise", calNoise); + if (!calNoise) { + calNoise = new CalDet<float>("Noise"); + fmt::print("Noise object not found in file {}, creating a dummy object\n", pedestalFile); + } + } // mode 1 handling if (mode == 1) { diff --git a/Detectors/TPC/calibration/macro/drawPulser.C b/Detectors/TPC/calibration/macro/drawPulser.C index f4f1d28a87964..97d14cfd95a58 100644 --- a/Detectors/TPC/calibration/macro/drawPulser.C +++ b/Detectors/TPC/calibration/macro/drawPulser.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -81,27 +82,27 @@ TObjArray* drawPulser(TString pulserFile, int mode = 0, std::string_view outDir // mode 1 handling if (mode == 1) { - float tMin = 238.f; - float tMax = 240.f; - float wMin = 0.38f; - float wMax = 0.57f; + float tMin = 124.f; + float tMax = 125.f; + float wMin = 0.25f; + float wMax = 0.55; float qMin = 20.f; float qMax = 280.f; if (normalizeQtot) { - qMin = 100.f; - qMax = 350.f; + qMin = 150.f; + qMax = 450.f; } if (type == 1) { - tMin = 425.f; - tMax = 485.f; + tMin = 490.f; + tMax = 510.f; wMin = 0.6; wMax = 0.8; qMin = 5.f; qMax = 500.f; } - auto arrT0 = painter::makeSummaryCanvases(*calT0, 100, tMin, tMax); + auto arrT0 = painter::makeSummaryCanvases(*calT0, 300, tMin, tMax); auto arrWidth = painter::makeSummaryCanvases(*calWidth, 100, wMin, wMax); auto arrQtot = painter::makeSummaryCanvases(*calQtot, 100, qMin, qMax); @@ -142,13 +143,13 @@ TObjArray* drawPulser(TString pulserFile, int mode = 0, std::string_view outDir const float minT0 = medianT0 - rangeT0; const float maxT0 = medianT0 + rangeT0; - const float rangeWidth = 0.1; + const float rangeWidth = 0.5; const float minWidth = medianWidth - rangeWidth; const float maxWidth = medianWidth + rangeWidth; - const float rangeQtot = 150; - const float minQtot = medianQtot - 50; - const float maxQtot = medianQtot + rangeQtot; + //const float rangeQtot = 150; + const float minQtot = medianQtot / 2.; + const float maxQtot = medianQtot * 2.; // ===| histograms for calT0, calWidth and calQtot |=== auto hT0 = new TH1F(Form("hT0%02d", iroc), Form("T0 distribution ROC %02d;time bins (0.2 #mus)", iroc), 100, minT0, maxT0); diff --git a/Detectors/TPC/calibration/macro/dumpDigits.C b/Detectors/TPC/calibration/macro/dumpDigits.C index c8c051e8c2fa2..813489e6ca752 100644 --- a/Detectors/TPC/calibration/macro/dumpDigits.C +++ b/Detectors/TPC/calibration/macro/dumpDigits.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #endif void dumpDigits(std::vector<std::string_view> fileInfos, TString outputFileName = "", int nevents = 100, - int adcMin = -100, int adcMax = 1100, + float adcMin = -100, float adcMax = 1100, int firstTimeBin = 0, int lastTimeBin = 1000, float noiseThreshold = -1, TString pedestalAndNoiseFile = "", @@ -30,6 +31,8 @@ void dumpDigits(std::vector<std::string_view> fileInfos, TString outputFileName dig.setADCRange(adcMin, adcMax); dig.setTimeBinRange(firstTimeBin, lastTimeBin); dig.setNoiseThreshold(noiseThreshold); + dig.setSkipIncompleteEvents(false); + dig.checkDuplicates(true); CalibRawBase::ProcessStatus status = CalibRawBase::ProcessStatus::Ok; for (const auto& fileInfo : fileInfos) { diff --git a/Detectors/TPC/calibration/macro/extractGainMap.C b/Detectors/TPC/calibration/macro/extractGainMap.C index 35ea78192e8df..fe326154c2ea6 100644 --- a/Detectors/TPC/calibration/macro/extractGainMap.C +++ b/Detectors/TPC/calibration/macro/extractGainMap.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/macro/makeTPCCCDBEntryForDCS.C b/Detectors/TPC/calibration/macro/makeTPCCCDBEntryForDCS.C new file mode 100644 index 0000000000000..cf6c7d9f7196c --- /dev/null +++ b/Detectors/TPC/calibration/macro/makeTPCCCDBEntryForDCS.C @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include <unordered_map> +#include <chrono> + +using DPID = o2::dcs::DataPointIdentifier; + +int makeTPCCCDBEntryForDCS(const std::string url = "http://localhost:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for TOF with the configuration for DCS + std::unordered_map<DPID, std::string> dpid2DataDesc; + std::vector<std::string> aliases; + int maxSectors = 17; + aliases.emplace_back("TPC_GC_ARGON"); + aliases.emplace_back("TPC_GC_CO2"); + aliases.emplace_back("TPC_GC_N2"); + aliases.emplace_back("TPC_GC_NEON"); + aliases.emplace_back("TPC_GC_O2"); + aliases.emplace_back("TPC_GC_WATER"); + aliases.emplace_back("TPC_An_L1Sr141_H2O"); + aliases.emplace_back("TPC_An_L1Sr141_O2"); + aliases.emplace_back("TPC_PT_351_TEMPERATURE"); + aliases.emplace_back("TPC_PT_376_TEMPERATURE"); + aliases.emplace_back("TPC_PT_415_TEMPERATURE"); + aliases.emplace_back("TPC_PT_447_TEMPERATURE"); + aliases.emplace_back("TPC_PT_477_TEMPERATURE"); + aliases.emplace_back("TPC_PT_488_TEMPERATURE"); + aliases.emplace_back("TPC_PT_537_TEMPERATURE"); + aliases.emplace_back("TPC_PT_575_TEMPERATURE"); + aliases.emplace_back("TPC_PT_589_TEMPERATURE"); + aliases.emplace_back("TPC_PT_629_TEMPERATURE"); + aliases.emplace_back("TPC_PT_664_TEMPERATURE"); + aliases.emplace_back("TPC_PT_695_TEMPERATURE"); + aliases.emplace_back("TPC_PT_735_TEMPERATURE"); + aliases.emplace_back("TPC_PT_757_TEMPERATURE"); + aliases.emplace_back("TPC_PT_797_TEMPERATURE"); + aliases.emplace_back("TPC_PT_831_TEMPERATURE"); + aliases.emplace_back("TPC_PT_851_TEMPERATURE"); + aliases.emplace_back("TPC_PT_895_TEMPERATURE"); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]B_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]B_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]T_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]T_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]B_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]B_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]T_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]T_U", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]B_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]B_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]T_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]T_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]B_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]B_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]T_I", maxSectors)); + aliases.emplace_back(fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]T_I", maxSectors)); + + std::vector<std::string> expaliases = o2::dcs::expandAliases(aliases); + + DPID dpidtmp; + for (size_t i = 0; i < expaliases.size(); ++i) { + DPID::FILL(dpidtmp, expaliases[i], o2::dcs::DeliveryType::RAW_DOUBLE); + dpid2DataDesc[dpidtmp] = "TPCDATAPOINTS"; + LOG(INFO) << expaliases[i]; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map<std::string, std::string> md; + long ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc, "TPC/Config/DCSDPconfig", md, ts); + + return 0; +} diff --git a/Detectors/TPC/calibration/macro/mergeNoiseAndPedestal.C b/Detectors/TPC/calibration/macro/mergeNoiseAndPedestal.C index 9384c48ab91b3..3e48b8ddced9c 100644 --- a/Detectors/TPC/calibration/macro/mergeNoiseAndPedestal.C +++ b/Detectors/TPC/calibration/macro/mergeNoiseAndPedestal.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/macro/preparePedestalFiles.C b/Detectors/TPC/calibration/macro/preparePedestalFiles.C index 91d2e8a13e962..b3f1b09a2c483 100644 --- a/Detectors/TPC/calibration/macro/preparePedestalFiles.C +++ b/Detectors/TPC/calibration/macro/preparePedestalFiles.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include "TSystem.h" #include "TString.h" +#include "TPCBase/CDBInterface.h" #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/Utils.h" @@ -73,25 +75,43 @@ constexpr float fixedSizeToFloat(uint32_t value) return float(value) * FloatConversion; } -void preparePedestalFiles(const std::string_view pedestalFileName, const TString outputDir = "./", float sigmaNoise = 3, float minADC = 2, float pedestalOffset = 0, bool onlyFilled = false) +void preparePedestalFiles(const std::string_view pedestalFile, const TString outputDir = "./", float sigmaNoise = 3, float minADC = 2, float pedestalOffset = 0, bool onlyFilled = false, bool maskBad = true, float noisyChannelThreshold = 1.5, float sigmaNoiseNoisyChannels = 4, float badChannelThreshold = 6) { static constexpr float FloatConversion = 1.f / float(1 << 2); using namespace o2::tpc; const auto& mapper = Mapper::instance(); - TFile f(pedestalFileName.data()); - gROOT->cd(); - // ===| load noise and pedestal from file |=== CalDet<float> output("Pedestals"); - CalDet<float>* calPedestal = nullptr; - CalDet<float>* calNoise = nullptr; - f.GetObject("Pedestals", calPedestal); - f.GetObject("Noise", calNoise); + const CalDet<float>* calPedestal = nullptr; + const CalDet<float>* calNoise = nullptr; + + if (pedestalFile.find("cdb") != std::string::npos) { + auto& cdb = CDBInterface::instance(); + if (pedestalFile.find("cdb-test") == 0) { + cdb.setURL("http://ccdb-test.cern.ch:8080"); + } else if (pedestalFile.find("cdb-prod") == 0) { + cdb.setURL("http://alice-ccdb.cern.ch"); + } + const auto timePos = pedestalFile.find("@"); + if (timePos != std::string_view::npos) { + std::cout << "set time stamp " << std::stol(pedestalFile.substr(timePos + 1).data()) << "\n"; + cdb.setTimeStamp(std::stol(pedestalFile.substr(timePos + 1).data())); + } + calPedestal = &cdb.getPedestals(); + calNoise = &cdb.getNoise(); + } else { + TFile f(pedestalFile.data()); + gROOT->cd(); + f.GetObject("Pedestals", calPedestal); + f.GetObject("Noise", calNoise); + } DataMap pedestalValues; DataMap thresholdlValues; + DataMap pedestalValuesPhysics; + DataMap thresholdlValuesPhysics; // ===| prepare values |=== for (size_t iroc = 0; iroc < calPedestal->getData().size(); ++iroc) { @@ -101,7 +121,8 @@ void preparePedestalFiles(const std::string_view pedestalFileName, const TString const auto& rocNoise = calNoise->getCalArray(iroc); auto& rocOut = output.getCalArray(iroc); - const int padOffset = (iroc > 35) ? mapper.getPadsInIROC() : 0; + const int padOffset = roc.isOROC() ? mapper.getPadsInIROC() : 0; + const auto& traceLengths = roc.isIROC() ? mapper.getTraceLengthsIROC() : mapper.getTraceLengthsOROC(); // skip empty if (!(std::abs(rocPedestal.getSum() + rocNoise.getSum()) > 0)) { @@ -126,6 +147,8 @@ void preparePedestalFiles(const std::string_view pedestalFileName, const TString const int dataWrapperID = fecInPartition >= fecOffset; const int globalLinkID = (fecInPartition % fecOffset) + dataWrapperID * 12; + const auto traceLength = traceLengths[ipad]; + float pedestal = rocPedestal.getValue(ipad); if ((pedestal > 0) && (pedestalOffset > pedestal)) { printf("ROC: %2zu, pad: %3zu -- pedestal offset %.2f larger than the pedestal value %.2f. Pedestal and noise will be set to 0\n", iroc, ipad, pedestalOffset, pedestal); @@ -134,21 +157,44 @@ void preparePedestalFiles(const std::string_view pedestalFileName, const TString } float noise = std::abs(rocNoise.getValue(ipad)); // it seems with the new fitting procedure, the noise can also be negative, since in gaus sigma is quadratic - if ((pedestal < 0) || (pedestal > 1023) || (noise < 0) || (noise > 1023)) { - printf("Bad pedestal or noise value in ROC %2zu, CRU %3d, fec in CRU: %2d, SAMPA: %d, channel: %2d, pedestal: %.4f, noise %.4f, setting both to 0\n", iroc, cruID, fecInPartition, sampa, sampaChannel, pedestal, noise); - pedestal = 0; - noise = 0; + float noiseCorr = noise - (0.847601 + 0.031514 * traceLength); + if ((pedestal <= 0) || (pedestal > 1023) || (noise <= 0) || (noise > 1023)) { + printf("Bad pedestal or noise value in ROC %2zu, CRU %3d, fec in CRU: %2d, SAMPA: %d, channel: %2d, pedestal: %.4f, noise %.4f", iroc, cruID, fecInPartition, sampa, sampaChannel, pedestal, noise); + if (maskBad) { + pedestal = 1023; + noise = 1023; + printf(", they will be masked using pedestal value %.0f and noise %.0f\n", pedestal, noise); + } else { + printf(", setting both to 0\n"); + pedestal = 0; + noise = 0; + } + } + float threshold = (noise > 0) ? std::max(sigmaNoise * noise, minADC) : 0; + threshold = std::min(threshold, 1023.f); + float thresholdHighNoise = (noiseCorr > noisyChannelThreshold) ? std::max(sigmaNoiseNoisyChannels * noise, minADC) : threshold; + + float pedestalHighNoise = pedestal; + if (noiseCorr > badChannelThreshold) { + pedestalHighNoise = 1023; + thresholdHighNoise = 1023; } - const float threshold = (noise > 0) ? std::max(sigmaNoise * noise, minADC) : 0; const int hwChannel = getHWChannel(sampa, sampaChannel, region % 2); // for debugging //printf("%4d %4d %4d %4d %4d: %u\n", cru.number(), globalLinkID, hwChannel, fecInfo.getSampaChip(), fecInfo.getSampaChannel(), getADCValue(pedestal)); + // default thresholds const auto adcPedestal = floatToFixedSize(pedestal); const auto adcThreshold = floatToFixedSize(threshold); pedestalValues[LinkInfo(cruID, globalLinkID)][hwChannel] = adcPedestal; thresholdlValues[LinkInfo(cruID, globalLinkID)][hwChannel] = adcThreshold; + + // higher thresholds for physics data taking + const auto adcPedestalPhysics = floatToFixedSize(pedestalHighNoise); + const auto adcThresholdPhysics = floatToFixedSize(thresholdHighNoise); + pedestalValuesPhysics[LinkInfo(cruID, globalLinkID)][hwChannel] = adcPedestalPhysics; + thresholdlValuesPhysics[LinkInfo(cruID, globalLinkID)][hwChannel] = adcThresholdPhysics; // for debugging //if(!(std::abs(pedestal - fixedSizeToFloat(adcPedestal)) <= 0.5 * 0.25)) { //printf("%4d %4d %4d %4d %4d: %u %.2f %.4f %.4f\n", cru.number(), globalLinkID, hwChannel, sampa, sampaChannel, adcPedestal, fixedSizeToFloat(adcPedestal), pedestal, pedestal - fixedSizeToFloat(adcPedestal)); @@ -158,6 +204,9 @@ void preparePedestalFiles(const std::string_view pedestalFileName, const TString writeValues((outputDir + "/pedestal_values.txt").Data(), pedestalValues, onlyFilled); writeValues((outputDir + "/threshold_values.txt").Data(), thresholdlValues, onlyFilled); + + writeValues((outputDir + "/pedestal_values.physics.txt").Data(), pedestalValuesPhysics, onlyFilled); + writeValues((outputDir + "/threshold_values.physics.txt").Data(), thresholdlValuesPhysics, onlyFilled); } /// return the hardware channel number as mapped in the CRU @@ -251,7 +300,10 @@ o2::tpc::CalDet<float> getCalPad(const std::string_view fileName, const std::str int sampaOnFEC{0}; int channelOnSAMPA{0}; std::string values; - CalDet<float> calPad(gSystem->BaseName(fileName.data())); + if (!calPadName.size()) { + calPadName = gSystem->BaseName(fileName.data()); + } + CalDet<float> calPad(calPadName); std::string line; std::ifstream infile(fileName.data(), std::ifstream::in); @@ -282,9 +334,6 @@ o2::tpc::CalDet<float> getCalPad(const std::string_view fileName, const std::str if (outputFile.size()) { TFile f(outputFile.data(), "recreate"); - if (!calPadName.size()) { - calPadName = calPad.getName(); - } f.WriteObject(&calPad, calPadName.data()); } return calPad; diff --git a/Detectors/TPC/calibration/macro/preparePedestalFiles.sh b/Detectors/TPC/calibration/macro/preparePedestalFiles.sh index 64e086b803e35..4353ac5341094 100755 --- a/Detectors/TPC/calibration/macro/preparePedestalFiles.sh +++ b/Detectors/TPC/calibration/macro/preparePedestalFiles.sh @@ -8,12 +8,16 @@ required arguments -i, --inputFile= : input file name optional arguments: --o, --outputDir= : set output directory for (default: ./) --m, --minADC= : minimal ADC value accepted for threshold (default: 2) --s, --sigmaNoise= : number of sigmas for the threshold (default: 3) --p, --pedestalOffset= : pedestal offset value --f, --onlyFilled : only write links which have data --h, --help : show this help message" +-o, --outputDir= : set output directory for (default: ./) +-m, --minADC= : minimal ADC value accepted for threshold (default: 2) +-s, --sigmaNoise= : number of sigmas for the threshold (default: 3) +-p, --pedestalOffset= : pedestal offset value +-f, --onlyFilled : only write links which have data +-k, --noMaskZero : don't set pedetal value of missing pads to 512 +-h, --help : show this help message +-n, --noisyThreshold : threshold for noisy channel treatment (default: $noisyThreshold) +-y, --sigmaNoiseNoisy : sigmaNoise for noisy channels (default: $sigmaNoiseNoisy) +-b, --badChannelThreshold : noise threshold to mask channels (default: $badChannelThreshold)" echo "$usage" } @@ -34,9 +38,13 @@ minADC=2 sigmaNoise=3 pedestalOffset=0 onlyFilled=0 +maskZero=1 +noisyThreshold=1.5 +sigmaNoiseNoisy=4 +badChannelThreshold=6 # ===| parse command line options |============================================= -OPTIONS=$(getopt -l "inputFile:,outputDir:,minADC:,sigmaNoise:,pedestalOffset:,onlyFilled,help" -o "i:o:t:m:s:p:fh" -n "preparePedestalFiles.sh" -- "$@") +OPTIONS=$(getopt -l "inputFile:,outputDir:,minADC:,sigmaNoise:,pedestalOffset:,onlyFilled,noMaskZero,help" -o "i:o:t:m:s:p:fkh" -n "preparePedestalFiles.sh" -- "$@") if [ $? != 0 ] ; then usageAndExit @@ -53,6 +61,10 @@ while true; do -s|--sigmaNoise) sigmaNoise=$2; shift 2;; -p|--pedestalOffset) pedestalOffset=$2; shift 2;; -f|--onlyFilled) onlyFilled=1; shift;; + -k|--noMaskZero) maskZero=0; shift;; + -n|--noisyThreshold) noisyThreshold=$2; shift 2;; + -y|--sigmaNoiseNoisy) sigmaNoiseNoisy=$2; shift 2;; + -b|--badChannelThreshold) badChannelThreshold=$2; shift 2;; -h|--help) usageAndExit;; *) echo "Internal error!" ; exit 1 ;; esac @@ -64,6 +76,6 @@ if [[ -z "$inputFile" ]]; then fi # ===| command building and execution |========================================= -cmd="root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/preparePedestalFiles.C+g'(\"$inputFile\",\"$outputDir\", $sigmaNoise, $minADC, $pedestalOffset, $onlyFilled)'" +cmd="root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/preparePedestalFiles.C+g'(\"$inputFile\",\"$outputDir\", $sigmaNoise, $minADC, $pedestalOffset, $onlyFilled, $maskZero, $noisyThreshold, $sigmaNoiseNoisy, $badChannelThreshold)'" echo "running: $cmd" eval $cmd diff --git a/Detectors/TPC/calibration/macro/runPedestal.C b/Detectors/TPC/calibration/macro/runPedestal.C index 80261d0936d0f..7578e9ff666ac 100644 --- a/Detectors/TPC/calibration/macro/runPedestal.C +++ b/Detectors/TPC/calibration/macro/runPedestal.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,13 +20,14 @@ #include "TPCCalibration/CalibRawBase.h" #endif -void runPedestal(std::vector<std::string_view> fileInfos, TString outputFileName = "", Int_t nevents = 100, Int_t adcMin = 0, Int_t adcMax = 1100, Int_t firstTimeBin = 0, Int_t lastTimeBin = 450, Int_t statisticsType = 0, uint32_t verbosity = 0, uint32_t debugLevel = 0, Int_t firstEvent = 0, Bool_t debugOutput = false) +void runPedestal(std::vector<std::string_view> fileInfos, TString outputFileName = "", Int_t nevents = 100, Int_t adcMin = 0, Int_t adcMax = 1100, Int_t firstTimeBin = 0, Int_t lastTimeBin = 450, Int_t statisticsType = 0, uint32_t verbosity = 0, uint32_t debugLevel = 0, Int_t firstEvent = 0, Bool_t debugOutput = false, Bool_t skipIncomplete = false) { using namespace o2::tpc; CalibPedestal ped; //(PadSubset::Region); ped.setADCRange(adcMin, adcMax); ped.setStatisticsType(StatisticsType(statisticsType)); ped.setTimeBinRange(firstTimeBin, lastTimeBin); + ped.setSkipIncompleteEvents(skipIncomplete); //ped.processEvent(); //ped.resetData(); @@ -35,14 +37,13 @@ void runPedestal(std::vector<std::string_view> fileInfos, TString outputFileName for (const auto& fileInfo : fileInfos) { ped.setupContainers(fileInfo.data(), verbosity, debugLevel); - for (Int_t i = firstEvent; i < firstEvent + nevents; ++i) { + const int neventsFile = ped.getNumberOfEvents(); + printf("number of events in files: %d\n", neventsFile); + int lastEvent = std::min(neventsFile, firstEvent + nevents); + + for (Int_t i = firstEvent; i < lastEvent; ++i) { status = ped.processEvent(i); std::cout << "Processing event " << i << " with status " << int(status) << '\n'; - if (status == CalibRawBase::ProcessStatus::IncompleteEvent) { - continue; - } else if (status != CalibRawBase::ProcessStatus::Ok) { - break; - } } } ped.analyse(); @@ -61,7 +62,6 @@ void runPedestal(std::vector<std::string_view> fileInfos, TString outputFileName debugFile.Append("/"); debugFile.Append("pedestals_debug.root"); TFile f(debugFile, "recreate"); - TObjArray arr(72); for (int i = 0; i < 72; ++i) { const auto& rocPedestal = calibPedestal.getCalArray(i); @@ -70,9 +70,8 @@ void runPedestal(std::vector<std::string_view> fileInfos, TString outputFileName } auto ch = ped.createControlHistogram(ROC(i)); - arr.Add(static_cast<TObject*>(ch)); + ch->Write(); } - arr.Write("histos", TObject::kSingleKey); f.Write(); } std::cout << "To display the pedestals run: root.exe $calibMacroDir/drawNoiseAndPedestal.C'(\"" << outputFileName << "\")'\n"; diff --git a/Detectors/TPC/calibration/macro/runPedestal.sh b/Detectors/TPC/calibration/macro/runPedestal.sh index bb246245d4ade..c73309181052d 100755 --- a/Detectors/TPC/calibration/macro/runPedestal.sh +++ b/Detectors/TPC/calibration/macro/runPedestal.sh @@ -40,16 +40,17 @@ outputFile=pedestals.root nevents=1000 firstTimeBin=0 lastTimeBin=450 -statisticsType=0 +statisticsType=1 verbosity=0 debugLevel=0 writeDebug=0 +skipIncomplete=0 adcMin=0 adcMax=1100 # ===| parse command line options |============================================= -OPTIONS=$(getopt -l "fileInfo:,outputFile:,firstTimeBin:,lastTimeBin:,nevents:,adcMin:,adcMax:,statType:,verbosity:,debugLevel:,writeDebug,help" -o "i:o:t:f:l:n:m:x:s:v:d:wh" -n "runPedestal.sh" -- "$@") +OPTIONS=$(getopt -l "fileInfo:,outputFile:,firstTimeBin:,lastTimeBin:,nevents:,skipIncomplete,adcMin:,adcMax:,statType:,verbosity:,debugLevel:,writeDebug,help" -o "i:o:t:f:l:n:km:x:s:v:d:wh" -n "runPedestal.sh" -- "$@") if [ $? != 0 ] ; then usageAndExit @@ -65,6 +66,7 @@ while true; do -f|--firstTimeBin) firstTimeBin=$2; shift 2;; -l|--lastTimeBin) lastTimeBin=$2; shift 2;; -n|--nevents) nevents=$2; shift 2;; + -k|--skipIncomplete) skipIncomplete=1; shift;; -m|--adcMin) adcMin=$2; shift 2;; -x|--adcMax) adcMax=$2; shift 2;; -s|--statType) statisticsType=$2; shift 2;; @@ -96,6 +98,6 @@ fileInfo=$(echo $fileInfo | sed "s|^|{\"|;s|,|:$lastTimeBin\",\"|g;s|$|\"}|") cmd="" #cmd="valgrind --tool=callgrind --dump-instr=yes --dump-instr=yes" #cmd="perf record -g -o perf.log" -cmd="$cmd root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/runPedestal.C'($fileInfo,\"$outputFile\", $nevents, $adcMin, $adcMax, $firstTimeBin, $lastTimeBin, $statisticsType, $verbosity, $debugLevel, 0, $writeDebug)'" +cmd="$cmd root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/runPedestal.C'($fileInfo,\"$outputFile\", $nevents, $adcMin, $adcMax, $firstTimeBin, $lastTimeBin, $statisticsType, $verbosity, $debugLevel, 0, $writeDebug, $skipIncomplete)'" echo "running: $cmd" eval $cmd diff --git a/Detectors/TPC/calibration/macro/runPulser.C b/Detectors/TPC/calibration/macro/runPulser.C index d1b8b4898a701..53030c90bad7a 100644 --- a/Detectors/TPC/calibration/macro/runPulser.C +++ b/Detectors/TPC/calibration/macro/runPulser.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,8 +30,11 @@ void runPulser(std::vector<std::string_view> fileInfos, TString outputFileName = calib.setADCRange(adcMin, adcMax); calib.setTimeBinRange(firstTimeBin, lastTimeBin); calib.setDebugLevel(); - calib.setQtotBinning(140, 22, 302); - if (type == 1) { + //calib.setQtotBinning(140, 22, 302); + calib.setQtotBinning(500, 10, 1010); + if (type == 0) { + calib.setWidthBinning(100, 0.1, 2.1); + } else if (type == 1) { calib.setQtotBinning(150, 2, 302); calib.setMinQtot(8); calib.setMinQmax(6); @@ -66,9 +70,7 @@ void runPulser(std::vector<std::string_view> fileInfos, TString outputFileName = for (Int_t i = 0; i < nevents; ++i) { status = calib.processEvent(i); std::cout << "Processing event " << i << " with status " << int(status) << '\n'; - if (status == CalibRawBase::ProcessStatus::IncompleteEvent) { - continue; - } else if (status != CalibRawBase::ProcessStatus::Ok) { + if (status == CalibRawBase::ProcessStatus::LastEvent) { break; } } diff --git a/Detectors/TPC/calibration/run/calib-pedestal.cxx b/Detectors/TPC/calibration/run/calib-pedestal.cxx deleted file mode 100644 index 0bd23979cb80c..0000000000000 --- a/Detectors/TPC/calibration/run/calib-pedestal.cxx +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <fmt/format.h> -#include "Framework/WorkflowSpec.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/DataSpecUtils.h" -#include "Framework/ControlService.h" -#include "Framework/Logger.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/CompletionPolicy.h" -#include "Framework/CompletionPolicyHelpers.h" -#include "DPLUtils/RawParser.h" -#include "Headers/DataHeader.h" -#include "CommonUtils/ConfigurableParam.h" -#include "TPCCalibration/CalibPedestal.h" -#include "TPCReconstruction/RawReaderCRU.h" -#include <vector> -#include <string> -#include "DetectorsRaw/RDHUtils.h" - -using namespace o2::framework; -using RDHUtils = o2::raw::RDHUtils; - -// customize the completion policy -void customize(std::vector<o2::framework::CompletionPolicy>& policies) -{ - using o2::framework::CompletionPolicy; - policies.push_back(CompletionPolicyHelpers::defineByName("calib-pedestal", CompletionPolicy::CompletionOp::Consume)); -} - -// we need to add workflow options before including Framework/runDataProcessing -void customize(std::vector<ConfigParamSpec>& workflowOptions) -{ - std::vector<ConfigParamSpec> options{ - {"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}}, - {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, - {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; - - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -using RDH = o2::header::RAWDataHeader; - -void printHeader() -{ - LOGP(debug, "{:>5} {:>4} {:>4} {:>4} {:>3} {:>4} {:>10} {:>5} {:>1} {:>10}", "PkC", "pCnt", "fId", "Mem", "CRU", "GLID", "HBOrbit", "HB BC", "s", "Trg"); -} - -void printRDH(const RDH& rdh) -{ - const int globalLinkID = int(RDHUtils::getLinkID(rdh)) + (((rdh.word1 >> 32) >> 28) * 12); - - LOGP(debug, "{:>5} {:>4} {:>4} {:>4} {:>3} {:>4} {:>10} {:>5} {:>1} {:#010X}", (uint64_t)RDHUtils::getPacketCounter(rdh), (uint64_t)RDHUtils::getPageCounter(rdh), - (uint64_t)RDHUtils::getFEEID(rdh), (uint64_t)RDHUtils::getMemorySize(rdh), (uint64_t)RDHUtils::getCRUID(rdh), (uint64_t)globalLinkID, - (uint64_t)RDHUtils::getHeartBeatOrbit(rdh), (uint64_t)RDHUtils::getHeartBeatBC(rdh), (uint64_t)RDHUtils::getStop(rdh), (uint64_t)RDHUtils::getTriggerType(rdh)); -} - -WorkflowSpec defineDataProcessing(ConfigContext const& config) -{ - using namespace o2::tpc; - - // set up configuration - o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); - o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); - o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); - - struct ProcessAttributes { - CalibPedestal calibPedestal; - rawreader::RawReaderCRUManager rawReader; - uint32_t lastOrbit{0}; - uint64_t lastTFID{0}; - uint32_t maxEvents{100}; - bool quit{false}; - bool dumped{false}; - }; - - auto initFunction = [](InitContext& ic) { - auto processAttributes = std::make_shared<ProcessAttributes>(); - // set up calibration - // TODO: - // it is a bit ugly to use the RawReaderCRUManager for this is. - // At some point the raw reader code should be cleaned up and modularized - { - auto& pedestal = processAttributes->calibPedestal; - pedestal.init(); // initialize configuration via configKeyValues - processAttributes->rawReader.createReader(""); - processAttributes->rawReader.setADCDataCallback([&pedestal](const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) -> Int_t { - Int_t timeBins = pedestal.update(padROCPos, cru, data); - pedestal.setNumberOfProcessedTimeBins(std::max(pedestal.getNumberOfProcessedTimeBins(), size_t(timeBins))); - return timeBins; - }); - processAttributes->maxEvents = static_cast<uint32_t>(ic.options().get<int>("max-events")); - } - - auto processingFct = [processAttributes](ProcessingContext& pc) { - // in case the maximum number of events was reached don't do further processing - if (processAttributes->quit) { - return; - } - - if (pc.inputs().isValid("TFID")) { - auto tfid = pc.inputs().get<uint64_t>("TFID"); - LOGP(info, "TFid: {}", tfid); - processAttributes->lastTFID = tfid; - } - - for (auto& input : pc.inputs()) { - const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(input); - - // ---| only process RAWDATA, there might be a nicer way to do this |--- - if (dh == nullptr || dh->dataDescription != o2::header::gDataDescriptionRawData) { - continue; - } - - // ---| extract hardware information to do the processing |--- - const auto subSpecification = dh->subSpecification; - const auto cruID = subSpecification >> 16; - const auto linkID = ((subSpecification + (subSpecification >> 8)) & 0xFF) - 1; - const auto dataWrapperID = ((subSpecification >> 8) & 0xFF) > 0; - const auto globalLinkID = linkID + dataWrapperID * 12; - - // ---| update hardware information in the reader |--- - auto& reader = processAttributes->rawReader.getReaders()[0]; - reader->forceCRU(cruID); - reader->setLink(globalLinkID); - - LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin.as<std::string>(), dh->dataDescription.as<std::string>(), dh->subSpecification); - LOGP(debug, "Payload size: {}", dh->payloadSize); - LOGP(debug, "CRU: {}; linkID: {}; dataWrapperID: {}; globalLinkID: {}", cruID, linkID, dataWrapperID, globalLinkID); - - printHeader(); - - // TODO: exception handling needed? - try { - o2::framework::RawParser parser(input.payload, dh->payloadSize); - - // TODO: it would be better to have external event handling and then moving the event processing functionality to CalibRawBase and RawReader to not repeat it in other places - rawreader::ADCRawData rawData; - rawreader::GBTFrame gFrame; - - auto& calibPedestal = processAttributes->calibPedestal; - - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - auto* rdhPtr = it.get_if<o2::header::RAWDataHeader>(); - if (!rdhPtr) { - break; - } - const auto& rdh = *rdhPtr; - printRDH(rdh); - // ===| event handling |=== - // - // really ugly, better treatment required extension in DPL - // events are are detected by close by orbit numbers - // might be possible to change this using the TFID information - // - const auto hbOrbit = RDHUtils::getHeartBeatOrbit(rdhPtr); - const auto lastOrbit = processAttributes->lastOrbit; - - if ((lastOrbit > 0) && (hbOrbit > (lastOrbit + 3))) { - calibPedestal.incrementNEvents(); - LOGP(info, "Number of processed events: {} ({})", calibPedestal.getNumberOfProcessedEvents(), processAttributes->maxEvents); - if (calibPedestal.getNumberOfProcessedEvents() >= processAttributes->maxEvents) { - LOGP(info, "Maximm number of events reached ({}), no more processing will be done", processAttributes->maxEvents); - processAttributes->quit = true; - break; - } - } - - processAttributes->lastOrbit = hbOrbit; - const auto size = it.size(); - auto data = it.data(); - //LOGP(info, "Data size: {}", size); - - int iFrame = 0; - for (int i = 0; i < size; i += 16) { - gFrame.setFrameNumber(iFrame); - gFrame.setPacketNumber(iFrame / 508); - gFrame.readFromMemory(gsl::span<const o2::byte>(data + i, 16)); - - // extract the half words from the 4 32-bit words - gFrame.getFrameHalfWords(); - - // debug output - //if (CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { - //std::cout << gFrame; - //} - - gFrame.getAdcValues(rawData); - gFrame.updateSyncCheck(false); - - ++iFrame; - } - } - - reader->runADCDataCallback(rawData); - } catch (const std::runtime_error& e) { - LOGP(error, "can not create raw parser form input data"); - o2::header::hexDump("payload", input.payload, dh->payloadSize, 64); - LOG(ERROR) << e.what(); - } - } - - // TODO: For the moment simply dump calibration output to file, to check if everything is working as expected - if (processAttributes->quit && !processAttributes->dumped) { - LOGP(info, "Dumping output"); - processAttributes->calibPedestal.analyse(); - processAttributes->calibPedestal.dumpToFile("pedestals.root"); - processAttributes->dumped = true; - //pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::All); - } - }; - - return processingFct; - }; - - WorkflowSpec workflow; - workflow.emplace_back(DataProcessorSpec{ - "calib-pedestal", - select(config.options().get<std::string>("input-spec").c_str()), - Outputs{}, - AlgorithmSpec{initFunction}, - Options{{"max-events", VariantType::Int, 100, {"maximum number of events to process"}}}}); - - return workflow; -} diff --git a/Detectors/TPC/calibration/src/CalibLaserTracks.cxx b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx new file mode 100644 index 0000000000000..8f5ef3665a626 --- /dev/null +++ b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx @@ -0,0 +1,399 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibLaserTracks.cxx +/// \brief calibration using laser tracks +/// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#include "MathUtils/Utils.h" +#include "TPCBase/ParameterGas.h" +#include "TPCBase/ParameterElectronics.h" +#include "TPCCalibration/CalibLaserTracks.h" +#include "TLinearFitter.h" + +using namespace o2::tpc; +void CalibLaserTracks::fill(std::vector<TrackTPC> const& tracks) +{ + fill(gsl::span(tracks.data(), tracks.size())); +} + +//______________________________________________________________________________ +void CalibLaserTracks::fill(const gsl::span<const TrackTPC> tracks) +{ + // ===| clean up TF data |=== + mZmatchPairsTFA.clear(); + mZmatchPairsTFC.clear(); + mCalibDataTF.reset(); + + if (!tracks.size()) { + return; + } + + // ===| associate tracks with ideal laser track positions |=== + for (const auto& track : tracks) { + processTrack(track); + } + + // ===| set TF start and end times |=== + if (mCalibData.firstTime == 0 && mCalibData.lastTime == 0) { + mCalibData.firstTime = mTFstart; + } + + auto tfEnd = mTFend; + if (tfEnd == 0) { + tfEnd = mTFstart; + } + mCalibData.lastTime = tfEnd; + + mCalibDataTF.firstTime = mTFstart; + mCalibDataTF.lastTime = tfEnd; + + // ===| TF counters |=== + ++mCalibData.processedTFs; + ++mCalibDataTF.processedTFs; + + // ===| finalize TF processing |=== + endTF(); +} + +//______________________________________________________________________________ +void CalibLaserTracks::processTrack(const TrackTPC& track) +{ + if (track.hasBothSidesClusters()) { + return; + } + + // use outer parameters which are closest to the laser mirrors + auto parOutAtLtr = track.getOuterParam(); + + // track should have been alreay propagated close to the laser mirrors + if (parOutAtLtr.getX() < 220) { + return; + } + + // recalculate z position based on trigger or CE position if needed + float zTrack = parOutAtLtr.getZ(); + + // TODO: calculation has to be improved + if (mTriggerPos < 0) { + // use CE for time 0 + const float zOffset = (track.getTime0() + mTriggerPos) * mZbinWidth * mDriftV + 250; + //printf("time0: %.2f, trigger pos: %d, zTrack: %.2f, zOffset: %.2f\n", track.getTime0(), mTriggerPos, zTrack, zOffset); + zTrack += zOffset; + parOutAtLtr.setZ(zTrack); + } else if (mTriggerPos > 0) { + } + + if (std::abs(zTrack) > 300) { + return; + } + + // try association with ideal laser track and rotate parameters + const int side = track.hasCSideClusters(); + const int laserTrackID = findLaserTrackID(parOutAtLtr, side); + + if (laserTrackID < 0 || laserTrackID >= LaserTrack::NumberOfTracks) { + return; + } + + auto ltr = mLaserTracks.getTrack(laserTrackID); + parOutAtLtr.rotateParam(ltr.getAlpha()); + parOutAtLtr.propagateParamTo(ltr.getX(), mBz); + + if (ltr.getSide() == 0) { + mZmatchPairsA.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart}); + mZmatchPairsTFA.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart}); + } else { + mZmatchPairsC.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart}); + mZmatchPairsTFC.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart}); + } + + mCalibData.matchedLtrIDs.emplace_back(laserTrackID); + mCalibDataTF.matchedLtrIDs.emplace_back(laserTrackID); + + // ===| debug output |======================================================== + if (mWriteDebugTree) { + if (!mDebugStream) { + mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugOutputName.data(), "recreate"); + } + + auto writeTrack = track; + *mDebugStream << "ltrMatch" + << "tfStart=" << mTFstart + << "tfEnd=" << mTFend + << "ltr=" << ltr // matched ideal laser track + << "trOutLtr=" << parOutAtLtr // track rotated and propagated to ideal track position + << "TPCTracks=" << writeTrack // original TPC track + << "\n"; + } +} + +//______________________________________________________________________________ +int CalibLaserTracks::findLaserTrackID(TrackPar outerParam, int side) +{ + // ===| rotate outer param to closes laser rod |=== + const auto phisec = getPhiNearbyLaserRod(outerParam, side); + if (!outerParam.rotateParam(phisec)) { + return -1; + } + + if (side < 0) { + side = outerParam.getZ() < 0; + } + + // ===| laser rod |=== + const int rod = std::nearbyint((phisec - LaserTrack::FirstRodPhi[side]) / LaserTrack::RodDistancePhi); + + // ===| laser bundle |=== + float mindist = 1000; + + const auto outerParamZ = std::abs(outerParam.getZ()); + + int bundle = -1; + for (size_t i = 0; i < LaserTrack::CoarseBundleZPos.size(); ++i) { + const float dist = std::abs(outerParamZ - LaserTrack::CoarseBundleZPos[i]); + if (dist < mindist) { + mindist = dist; + bundle = i; + } + } + + if (bundle < 0) { + return -1; + } + + // ===| laser beam |=== + const auto outerParamsInBundle = mLaserTracks.getTracksInBundle(side, rod, bundle); + mindist = 1000; + + int beam = -1; + for (int i = 0; i < outerParamsInBundle.size(); ++i) { + const auto louterParam = outerParamsInBundle[i]; + if (i == 0) { + outerParam.propagateParamTo(louterParam.getX(), mBz); + } + const float dist = std::abs(outerParam.getSnp() - louterParam.getSnp()); + if (dist < mindist) { + mindist = dist; + beam = i; + } + } + + if (mindist > 0.01) { + return -1; + } + + // ===| track ID from side, rod, bundle and beam |=== + const int trackID = LaserTrack::NumberOfTracks / 2 * side + + LaserTrack::BundlesPerRod * LaserTrack::TracksPerBundle * rod + + LaserTrack::TracksPerBundle * bundle + + beam; + + return trackID; +} + +//______________________________________________________________________________ +float CalibLaserTracks::getPhiNearbyLaserRod(const TrackPar& param, int side) +{ + const auto xyzGlo = param.getXYZGlo(); + auto phi = std::atan2(xyzGlo.Y(), xyzGlo.X()) - LaserTrack::FirstRodPhi[side % 2]; + o2::math_utils::bringTo02PiGen(phi); + phi = std::nearbyint(phi / LaserTrack::RodDistancePhi) * LaserTrack::RodDistancePhi + LaserTrack::FirstRodPhi[side % 2]; + o2::math_utils::bringTo02PiGen(phi); + return phi; +} + +//______________________________________________________________________________ +bool CalibLaserTracks::hasNearbyLaserRod(const TrackPar& param, int side) +{ + const auto xyzGlo = param.getXYZGlo(); + const auto phiTrack = std::atan2(xyzGlo.Y(), xyzGlo.X()); + auto phi = phiTrack - LaserTrack::FirstRodPhi[side % 2]; + o2::math_utils::bringTo02PiGen(phi); + phi = std::nearbyint(phi / LaserTrack::RodDistancePhi) * LaserTrack::RodDistancePhi + LaserTrack::FirstRodPhi[side % 2]; + o2::math_utils::bringTo02PiGen(phi); + return std::abs(phi - phiTrack) < LaserTrack::SectorSpanRad / 4.; +} + +//______________________________________________________________________________ +void CalibLaserTracks::updateParameters() +{ + const auto& gasParam = ParameterGas::Instance(); + const auto& electronicsParam = ParameterElectronics::Instance(); + mDriftV = gasParam.DriftV; + mZbinWidth = electronicsParam.ZbinWidth; +} + +//______________________________________________________________________________ +void CalibLaserTracks::merge(const CalibLaserTracks* other) +{ + if (!other) { + return; + } + mCalibData.processedTFs += other->mCalibData.processedTFs; + + const auto sizeAthis = mZmatchPairsA.size(); + const auto sizeCthis = mZmatchPairsC.size(); + const auto sizeAother = other->mZmatchPairsA.size(); + const auto sizeCother = other->mZmatchPairsC.size(); + + mZmatchPairsA.insert(mZmatchPairsA.end(), other->mZmatchPairsA.begin(), other->mZmatchPairsA.end()); + mZmatchPairsC.insert(mZmatchPairsC.end(), other->mZmatchPairsC.begin(), other->mZmatchPairsC.end()); + + auto& ltrIDs = mCalibData.matchedLtrIDs; + auto& ltrIDsOther = other->mCalibData.matchedLtrIDs; + ltrIDs.insert(ltrIDs.end(), ltrIDsOther.begin(), ltrIDsOther.end()); + + mCalibData.firstTime = std::min(mCalibData.firstTime, other->mCalibData.firstTime); + mCalibData.lastTime = std::max(mCalibData.lastTime, other->mCalibData.lastTime); + + sort(mZmatchPairsA); + sort(mZmatchPairsC); + + LOGP(info, "Merged CalibLaserTracks with mached pairs {} / {} + {} / {} = {} / {} (this +_other A- / C-Side)", sizeAthis, sizeCthis, sizeAother, sizeCother, mZmatchPairsA.size(), mZmatchPairsC.size()); +} + +//______________________________________________________________________________ +void CalibLaserTracks::endTF() +{ + LOGP(info, "Ending time frame {} - {} with {} / {} matched laser tracks (total: {} / {}) on the A / C-Side", mTFstart, mTFend, mZmatchPairsTFA.size(), mZmatchPairsTFC.size(), mZmatchPairsA.size(), mZmatchPairsC.size()); + fillCalibData(mCalibDataTF, mZmatchPairsTFA, mZmatchPairsTFC); + + if (mDebugStream) { + (*mDebugStream) << "tfData" + << "tfStart=" << mTFstart + << "tfEnf=" << mTFend + << "zPairsA=" << mZmatchPairsTFA + << "zPairsC=" << mZmatchPairsTFC + << "calibData=" << mCalibDataTF + << "\n"; + } +} + +//______________________________________________________________________________ +void CalibLaserTracks::finalize() +{ + mFinalized = true; + sort(mZmatchPairsA); + sort(mZmatchPairsC); + + fillCalibData(mCalibData, mZmatchPairsA, mZmatchPairsC); + + //auto& ltrIDs = mCalibData.matchedLtrIDs; + //std::sort(ltrIDs.begin(), ltrIDs.end()); + //ltrIDs.erase(std::unique(ltrIDs.begin(), ltrIDs.end()), ltrIDs.end()); + + if (mDebugStream) { + (*mDebugStream) << "finalData" + << "zPairsA=" << mZmatchPairsA + << "zPairsC=" << mZmatchPairsC + << "calibData=" << mCalibData + << "\n"; + + mDebugStream->Close(); + } +} + +//______________________________________________________________________________ +void CalibLaserTracks::fillCalibData(LtrCalibData& calibData, const std::vector<TimePair>& pairsA, const std::vector<TimePair>& pairsC) +{ + auto dvA = fit(pairsA); + auto dvC = fit(pairsC); + + calibData.dvOffsetA = dvA.x1; + calibData.dvCorrectionA = dvA.x2; + calibData.nTracksA = uint16_t(pairsA.size()); + + calibData.dvOffsetC = dvC.x1; + calibData.dvCorrectionC = dvC.x2; + calibData.nTracksC = uint16_t(pairsC.size()); +} + +//______________________________________________________________________________ +TimePair CalibLaserTracks::fit(const std::vector<TimePair>& trackMatches) const +{ + if (!trackMatches.size()) { + return TimePair(); + } + + static TLinearFitter fit(2, "pol1"); + fit.StoreData(false); + fit.ClearPoints(); + + uint64_t meanTime = 0; + for (const auto& point : trackMatches) { + double x = point.x1; + double y = point.x2; + fit.AddPoint(&x, y); + + meanTime += point.time; + } + + meanTime /= uint64_t(trackMatches.size()); + + const float robustFraction = 0.9; + const int minPoints = 6; + + if (trackMatches.size() < size_t(minPoints / robustFraction)) { + return TimePair({0, 0, meanTime}); + } + + //fit.EvalRobust(robustFraction); + fit.Eval(); + + TimePair retVal; + retVal.x1 = float(fit.GetParameter(0)); + retVal.x2 = float(fit.GetParameter(1)); + retVal.time = meanTime; + + return retVal; +} + +//______________________________________________________________________________ +void CalibLaserTracks::sort(std::vector<TimePair>& trackMatches) +{ + std::sort(trackMatches.begin(), trackMatches.end(), [](const auto& first, const auto& second) { return first.time < second.time; }); +} + +//______________________________________________________________________________ +void CalibLaserTracks::print() const +{ + if (mFinalized) { + LOGP(info, + "Processed {} TFs from {} - {}; found tracks: {} / {}; T0 offsets: {} / {}; dv correction factors: {} / {} for A- / C-Side", + mCalibData.processedTFs, + mCalibData.firstTime, + mCalibData.lastTime, + mCalibData.nTracksA, + mCalibData.nTracksC, + mCalibData.dvOffsetA, + mCalibData.dvOffsetC, + mCalibData.dvCorrectionA, + mCalibData.dvCorrectionC); + } else { + LOGP(info, + "Processed {} TFs from {} - {}; **Not finalized**", + mCalibData.processedTFs, + mCalibData.firstTime, + mCalibData.lastTime); + + LOGP(info, + "Last processed TF from {} - {}; found tracks: {} / {}; T0 offsets: {} / {}; dv correction factors: {} / {} for A- / C-Side", + mCalibDataTF.firstTime, + mCalibDataTF.lastTime, + mCalibDataTF.nTracksA, + mCalibDataTF.nTracksC, + mCalibDataTF.dvOffsetA, + mCalibDataTF.dvOffsetC, + mCalibDataTF.dvCorrectionA, + mCalibDataTF.dvCorrectionC); + } +} diff --git a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx index 2b688b63df6ad..3687d1bbda885 100644 --- a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx +++ b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/CalibPedestal.cxx b/Detectors/TPC/calibration/src/CalibPedestal.cxx index df8f5496d0b64..03c27ad5569d4 100644 --- a/Detectors/TPC/calibration/src/CalibPedestal.cxx +++ b/Detectors/TPC/calibration/src/CalibPedestal.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/CalibPedestalParam.cxx b/Detectors/TPC/calibration/src/CalibPedestalParam.cxx index 6fd2f3e8c915e..ad05d41f45467 100644 --- a/Detectors/TPC/calibration/src/CalibPedestalParam.cxx +++ b/Detectors/TPC/calibration/src/CalibPedestalParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/CalibPulser.cxx b/Detectors/TPC/calibration/src/CalibPulser.cxx index d3e2bbb618067..3bd3db8183b88 100644 --- a/Detectors/TPC/calibration/src/CalibPulser.cxx +++ b/Detectors/TPC/calibration/src/CalibPulser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/CalibPulserParam.cxx b/Detectors/TPC/calibration/src/CalibPulserParam.cxx index f2be19cc95851..62ff1d0081658 100644 --- a/Detectors/TPC/calibration/src/CalibPulserParam.cxx +++ b/Detectors/TPC/calibration/src/CalibPulserParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/CalibRawBase.cxx b/Detectors/TPC/calibration/src/CalibRawBase.cxx index a414cbf1f4934..b430572320636 100644 --- a/Detectors/TPC/calibration/src/CalibRawBase.cxx +++ b/Detectors/TPC/calibration/src/CalibRawBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "TSystem.h" #include "TObjString.h" #include "TObjArray.h" +#include "TPCBase/RDHUtils.h" #include "TPCCalibration/CalibRawBase.h" @@ -74,6 +76,14 @@ void CalibRawBase::setupContainers(TString fileInfo, uint32_t verbosity, uint32_ mProcessedTimeBins = std::max(mProcessedTimeBins, size_t(timeBins)); return timeBins; }); + mRawReaderCRUManager.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + updateROC(cruID.roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + const PadRegionInfo& regionInfo = mMapper.getPadRegionInfo(cruID.region()); + updateCRU(cruID, rowInSector - regionInfo.getGlobalRowOffset(), padInRow, timeBin, adcValue); + return true; + }); + for (auto file : *arr) { // fix the number of time bins auto& reader = mRawReaderCRUManager.createReader(file->GetName(), timeBins); @@ -87,6 +97,7 @@ void CalibRawBase::setupContainers(TString fileInfo, uint32_t verbosity, uint32_ printf("Forcing CRU %03d\n", cru); } } + mRawReaderCRUManager.init(); } else if (rorcType == "digits") { TString files = gSystem->GetFromPipe(TString::Format("ls %s", arrDataInfo->At(0)->GetName())); //const int timeBins = static_cast<TObjString*>(arrDataInfo->At(1))->String().Atoi(); diff --git a/Detectors/TPC/calibration/src/CalibTreeDump.cxx b/Detectors/TPC/calibration/src/CalibTreeDump.cxx index 0f92e2c502518..f3bec410325ee 100644 --- a/Detectors/TPC/calibration/src/CalibTreeDump.cxx +++ b/Detectors/TPC/calibration/src/CalibTreeDump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -146,7 +147,8 @@ void CalibTreeDump::addFEEMapping(TTree* tree) // ===| mapper |============================================================== const auto& mapper = Mapper::instance(); - readTraceLengths(); + mTraceLengthIROC = mapper.getTraceLengthsIROC(); + mTraceLengthOROC = mapper.getTraceLengthsOROC(); // ===| default mapping objects |============================================= // FEC @@ -219,20 +221,27 @@ void CalibTreeDump::addCalDetObjects(TTree* tree) std::string meanName = fmt::format("{}_mean", name); std::string stdDevName = fmt::format("{}_stdDev", name); std::string medianName = fmt::format("{}_median", name); + std::string median1Name = fmt::format("{}_median1", name); + std::string median2Name = fmt::format("{}_median2", name); + std::string median3Name = fmt::format("{}_median3", name); // ===| branch variables |=== std::vector<float>* data = nullptr; float mean{}; float stdDev{}; - float median{}; + float median[4]{}; // ===| branch definitions |=== TBranch* brMean = tree->Branch(meanName.data(), &mean); TBranch* brStdDev = tree->Branch(stdDevName.data(), &stdDev); - TBranch* brMedian = tree->Branch(medianName.data(), &median); + TBranch* brMedian = tree->Branch(medianName.data(), &median[0]); + TBranch* brMedian1 = tree->Branch(median1Name.data(), &median[1]); + TBranch* brMedian2 = tree->Branch(median2Name.data(), &median[2]); + TBranch* brMedian3 = tree->Branch(median3Name.data(), &median[3]); TBranch* brData = tree->Branch(name.data(), &data); // ===| loop over ROCs and fill |=== + int roc = 0; for (auto& calArray : calDet.getData()) { // ---| set data |--- data = &calArray.getData(); @@ -240,82 +249,32 @@ void CalibTreeDump::addCalDetObjects(TTree* tree) // ---| statistics |--- mean = TMath::Mean(data->begin(), data->end()); stdDev = TMath::StdDev(data->begin(), data->end()); - median = TMath::Median(data->size(), data->data()); + median[0] = median[1] = median[2] = median[3] = TMath::Median(data->size(), data->data()); + if (roc > 35) { + median[1] = TMath::Median(Mapper::getPadsInOROC1(), data->data()); + median[2] = TMath::Median(Mapper::getPadsInOROC2(), data->data() + Mapper::getPadsInOROC1()); + median[3] = TMath::Median(Mapper::getPadsInOROC3(), data->data() + Mapper::getPadsInOROC1() + Mapper::getPadsInOROC2()); + } // ---| filling |--- brData->Fill(); brMean->Fill(); brStdDev->Fill(); brMedian->Fill(); + brMedian1->Fill(); + brMedian2->Fill(); + brMedian3->Fill(); + ++roc; } } } -//______________________________________________________________________________ -void CalibTreeDump::readTraceLengths(std::string_view mappingDir) -{ - std::string inputDir = mappingDir.data(); - if (!inputDir.size()) { - const char* aliceO2env = std::getenv("O2_ROOT"); - if (aliceO2env) { - inputDir = aliceO2env; - } - inputDir += "/share/Detectors/TPC/files"; - } - - mTraceLengthIROC.reserve(Mapper::getPadsInIROC()); - mTraceLengthOROC.reserve(Mapper::getPadsInOROC()); - setTraceLengths(inputDir + "/LENGTH-IROC.txt", mTraceLengthIROC); - setTraceLengths(inputDir + "/LENGTH-OROC1.txt", mTraceLengthOROC); - setTraceLengths(inputDir + "/LENGTH-OROC2.txt", mTraceLengthOROC); - setTraceLengths(inputDir + "/LENGTH-OROC3.txt", mTraceLengthOROC); - - assert(mTraceLengthIROC.size() == Mapper::getPadsInIROC()); - assert(mTraceLengthOROC.size() == Mapper::getPadsInOROC()); -} - -//______________________________________________________________________________ -void CalibTreeDump::setTraceLengths(std::string_view inputFile, std::vector<float>& length) -{ - - std::ifstream infile(inputFile.data(), std::ifstream::in); - if (!infile.is_open()) { - std::cout << "could not open file " << inputFile.data() << "\n"; - exit(1); - } - - // e.g. IROC file - // Col 0 -> INDEX (0 - 5279) - // Col 1 -> PADROW (0 - 62) - // Col 2 -> PAD (0 - (Np-1)) - // Col 3 -> Connector (1 - 132) - // Col 4 -> Pin (1 - 40) - // Col 5 -> Trace length (mm) - // Col 6 -> Number of vias - - unsigned int index{}; - unsigned int padrow{}; - unsigned int pad{}; - unsigned int connector{}; - unsigned int pin{}; - float traceLength{}; - unsigned int numberOfVias{}; - - std::string line; - while (std::getline(infile, line)) { - std::stringstream streamLine(line); - streamLine >> index >> padrow >> pad >> connector >> pin >> traceLength >> numberOfVias; - - traceLength /= 10.f; - - length.emplace_back(traceLength); - } -} - //______________________________________________________________________________ void CalibTreeDump::setDefaultAliases(TTree* tree) { tree->SetAlias("sector", "roc%36"); + tree->SetAlias("padsPerRow", "2*(pad-cpad)"); + tree->SetAlias("isEdgePad", "(pad==0) || (pad==padsPerRow-1)"); tree->SetAlias("rowInSector", "row + (roc>35)*63"); tree->SetAlias("padWidth", "0.4 + (roc > 35) * 0.2"); tree->SetAlias("padHeight", "0.75 + (rowInSector > 62) * 0.25 + (rowInSector > 96) * 0.2 + (rowInSector > 126) * 0.3"); diff --git a/Detectors/TPC/calibration/src/CalibdEdx.cxx b/Detectors/TPC/calibration/src/CalibdEdx.cxx new file mode 100644 index 0000000000000..4ce590271319a --- /dev/null +++ b/Detectors/TPC/calibration/src/CalibdEdx.cxx @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/CalibdEdx.h" + +#include <array> +#include <cstddef> +#include <memory> +#include <string_view> + +//o2 includes +#include "CommonUtils/MemFileHelper.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/Logger.h" +#include "TPCCalibration/dEdxHistos.h" + +using namespace o2::tpc; + +void CalibdEdx::initOutput() +{ + // Here we initialize the vector of our output objects + mInfoVector.clear(); + mMIPVector.clear(); + return; +} + +void CalibdEdx::finalizeSlot(Slot& slot) +{ + LOG(INFO) << "Finalizing slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + + const dEdxHistos* container = slot.getContainer(); + const auto statsASide = container->getHists()[0].getStatisticsData(); + const auto statsCSide = container->getHists()[1].getStatisticsData(); + + slot.print(); + LOG(INFO) << "A side, truncated mean statistics: Mean = " << statsASide.mCOG << ", StdDev = " << statsCSide.mStdDev << ", Entries = " << statsASide.mSum; + LOG(INFO) << "C side, truncated mean statistics: Mean = " << statsCSide.mCOG << ", StdDev = " << statsCSide.mStdDev << ", Entries = " << statsCSide.mSum; + + CalibMIP mips{statsASide.mCOG, statsCSide.mCOG}; + + const auto className = o2::utils::MemFileHelper::getClassName(mips); + const auto fileName = o2::ccdb::CcdbApi::generateFileName(className); + const std::map<std::string, std::string> metaData; + + // TODO: the timestamp is now given with the TF index, but it will have + // to become an absolute time. + TFType timeFrame = slot.getTFStart(); + mInfoVector.emplace_back("TPC/Calib/MIPS", className, fileName, metaData, timeFrame, 99999999999999); + mMIPVector.push_back(mips); + + if (mDebugOutputStreamer) { + LOG(INFO) << "Dumping time slot data to file"; + + *mDebugOutputStreamer << "mipPosition" + << "timeFrame=" << timeFrame // Initial time frame of time slot + << "calibMIP=" << mips // Computed MIP positions + << "dEdxHistos=" << slot.getContainer() // dE/dx histograms + << "\n"; + } +} + +CalibdEdx::Slot& CalibdEdx::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + + auto container = std::make_unique<dEdxHistos>(mNBins, mCuts); + container->setApplyCuts(mApplyCuts); + + slot.setContainer(std::move(container)); + return slot; +} + +void CalibdEdx::enableDebugOutput(std::string_view fileName) +{ + mDebugOutputStreamer = std::make_unique<o2::utils::TreeStreamRedirector>(fileName.data(), "recreate"); +} + +void CalibdEdx::disableDebugOutput() +{ + // This will call the TreeStream destructor and write any stored data. + mDebugOutputStreamer.reset(); +} + +void CalibdEdx::finalizeDebugOutput() const +{ + if (mDebugOutputStreamer) { + LOG(INFO) << "Closing dump file"; + mDebugOutputStreamer->Close(); + } +} diff --git a/Detectors/TPC/calibration/src/DigitDump.cxx b/Detectors/TPC/calibration/src/DigitDump.cxx index dfbfbe38f3d5e..7142b9d1b1aef 100644 --- a/Detectors/TPC/calibration/src/DigitDump.cxx +++ b/Detectors/TPC/calibration/src/DigitDump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include "TTree.h" #include "TString.h" -#include <fairlogger/Logger.h> +#include "Framework/Logger.h" #include "TPCBase/Mapper.h" #include "TPCBase/ROC.h" @@ -36,8 +37,14 @@ void DigitDump::init() { const auto& param = DigitDumpParam::Instance(); - mFirstTimeBin = param.FirstTimeBin; - mLastTimeBin = param.LastTimeBin; + if (param.FirstTimeBin >= 0) { + mFirstTimeBin = param.FirstTimeBin; + LOGP(info, "Setting FirstTimeBin = {} from TPCDigitDump.FirstTimeBin", mFirstTimeBin); + } + if (param.LastTimeBin >= 0) { + mLastTimeBin = param.LastTimeBin; + LOGP(info, "Setting LastTimeBin = {} from TPCDigitDump.LastTimeBin", mLastTimeBin); + } mADCMin = param.ADCMin; mADCMax = param.ADCMax; mNoiseThreshold = param.NoiseThreshold; @@ -91,6 +98,9 @@ Int_t DigitDump::updateCRU(const CRU& cru, const Int_t row, const Int_t pad, // fill digits addDigit(cru, signalCorr, globalRow, pad, timeBin); + // fill time bin occupancy + ++mTimeBinOccupancy[timeBin - mFirstTimeBin]; + return 0; } @@ -103,8 +113,12 @@ void DigitDump::sortDigits() if (a.getTimeStamp() < b.getTimeStamp()) { return true; } - if ((a.getTimeStamp() == b.getTimeStamp()) && (a.getRow() < b.getRow())) { - return true; + if (a.getTimeStamp() == b.getTimeStamp()) { + if (a.getRow() < b.getRow()) { + return true; + } else if (a.getRow() == b.getRow()) { + return a.getPad() < b.getPad(); + } } return false; }); @@ -163,5 +177,117 @@ void DigitDump::initInputOutput() if (!mInMemoryOnly) { setupOutputTree(); } + mTimeBinOccupancy.resize(mLastTimeBin - mFirstTimeBin + 1); mInitialized = true; } + +//______________________________________________________________________________ +void DigitDump::checkDuplicates(bool removeDuplicates) +{ + sortDigits(); + + auto isEqual = [](const Digit& a, const Digit& b) { + if ((a.getTimeStamp() == b.getTimeStamp()) && (a.getRow() == b.getRow()) && (a.getPad() == b.getPad())) { + LOGP(debug, "digit found twice at sector {:2}, cru {:3}, row {:3}, pad {:3}, time {:6}, ADC {:.2} (other: {:.2})", b.getCRU() / 10, b.getCRU(), b.getRow(), b.getPad(), b.getTimeStamp(), b.getChargeFloat(), a.getChargeFloat()); + return true; + } + return false; + }; + + for (size_t iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { + auto& digits = mDigits[iSec]; + if (!digits.size()) { + continue; + } + + size_t nDuplicates = 0; + if (removeDuplicates) { + const auto last = std::unique(digits.begin(), digits.end(), isEqual); + nDuplicates = std::distance(last, digits.end()); + digits.erase(last, digits.end()); + } else { + auto first = digits.begin(); + const auto last = digits.end(); + while (++first != last) { + nDuplicates += isEqual(*(first - 1), *first); + } + } + if (nDuplicates) { + LOGP(warning, "{} {} duplicate digits in sector {}", removeDuplicates ? "removed" : "found", nDuplicates, iSec); + } + } +} + +//______________________________________________________________________________ +void DigitDump::removeCEdigits(uint32_t removeNtimeBinsBefore, uint32_t removeNtimeBinsAfter, std::array<std::vector<Digit>, Sector::MAXSECTOR>* removedDigits) +{ + if (!mInitialized || !mTimeBinOccupancy.size()) { + LOGP(info, "Cannot calculate CE psition, mInitialized = {}, mTimeBinOccupancy.size() = {}", mInitialized, mTimeBinOccupancy.size()); + return; + } + // ===| check if proper CE signal was found |=== + const auto sectorsWithDigits = std::count_if(mDigits.begin(), mDigits.end(), [](const auto& v) { return v.size(); }); + const auto maxElem = std::max_element(mTimeBinOccupancy.begin(), mTimeBinOccupancy.end()); + const auto maxVal = *maxElem; + + if (!sectorsWithDigits || maxVal < 10) { + LOGP(info, "No sectors with digits: {} or too few pads with max number of digits: {} < 10, CE detection stopped", sectorsWithDigits, maxVal); + return; + } + + // at least 20% of all pad should have fired in sectors wich have digits + const size_t threshold = Mapper::getPadsInSector() * sectorsWithDigits / 5; + if (maxVal < threshold) { + LOGP(warning, "No CE signal found. Number of fired pads is too small {} < {} (with {} sectors having digits)", maxVal, threshold, sectorsWithDigits); + return; + } + + // identify the first time bin to remove + const auto posMaxElem = std::distance(mTimeBinOccupancy.begin(), maxElem); + const auto cePos = posMaxElem + mFirstTimeBin; + + if (cePos < posMaxElem) { + LOGP(warning, "Number of time bins to be removed {} is bigger than the CE peak position {}", removeNtimeBinsBefore, posMaxElem); + return; + } + + const auto firstTimeBin = cePos - removeNtimeBinsBefore; + const auto lastTimeBin = cePos + removeNtimeBinsAfter; + LOGP(info, "CE position found at time bin {}, removing the range {} - {}", cePos, firstTimeBin, lastTimeBin); + + for (size_t iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { + auto& digits = mDigits[iSec]; + if (!digits.size()) { + continue; + } + + //LOGP(info, "processing sector iSec"); + const auto itFirstTB = std::lower_bound(digits.begin(), digits.end(), + firstTimeBin, + [](const auto& digit, const auto val) { + return digit.getTimeStamp() < val; + }); + + //LOGP(info, "first time bin to remove is {} at position {} / {}", *itFirstTB, std::distance(digits.begin(), itFirstTB), digits.size()); + if (itFirstTB == digits.end()) { + continue; + } + + const auto itLastTB = std::upper_bound(digits.begin(), digits.end(), + lastTimeBin, + [](const auto val, const auto& digit) { + return val < digit.getTimeStamp(); + }); + + //LOGP(info, "last time bin to remove is {} at position {} / {}", *(itLastTB - 1), std::distance(digits.begin(), itLastTB), digits.size()); + if (removedDigits) { + //LOGP(info, "copy removed digits"); + auto& cpDigits = (*removedDigits)[iSec]; + cpDigits.clear(); + std::copy(itFirstTB, itLastTB, std::back_inserter(cpDigits)); + } + + //LOGP(info, "erasing {} digits", std::distance(itFirstTB, itLastTB)); + digits.erase(itFirstTB, itLastTB); + } +} diff --git a/Detectors/TPC/calibration/src/DigitDumpParam.cxx b/Detectors/TPC/calibration/src/DigitDumpParam.cxx index b9cc21ab4eb25..d80a95b74b8b3 100644 --- a/Detectors/TPC/calibration/src/DigitDumpParam.cxx +++ b/Detectors/TPC/calibration/src/DigitDumpParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/calibration/src/IDCAverageGroup.cxx b/Detectors/TPC/calibration/src/IDCAverageGroup.cxx new file mode 100644 index 0000000000000..98c35308e4b03 --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCAverageGroup.cxx @@ -0,0 +1,282 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCAverageGroup.h" +#include "TPCCalibration/IDCGroup.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TPCCalibration/IDCGroupingParameter.h" +#include "TPCBase/Mapper.h" + +#include "TFile.h" +#include "TKey.h" +#include "TPCBase/Painter.h" +#include "TH2Poly.h" +#include "TCanvas.h" +#include "TLatex.h" +#include "TKey.h" +#include "Framework/Logger.h" + +#if (defined(WITH_OPENMP) || defined(_OPENMP)) && !defined(__CLING__) +#include <omp.h> +#else +static inline int omp_get_thread_num() { return 0; } +#endif + +o2::tpc::IDCAverageGroup::IDCAverageGroup(const unsigned char groupPads, const unsigned char groupRows, const unsigned char groupLastRowsThreshold, const unsigned char groupLastPadsThreshold, const unsigned int region, const Sector sector, const float sigma) + : mIDCsGrouped{groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold, region}, mSector{sector}, mSigma{sigma}, mRobustAverage(sNThreads) +{ + unsigned int maxValues = 0; + for (unsigned int i = 0; i < Mapper::NREGIONS; ++i) { + const unsigned int maxGroup = (mIDCsGrouped.getGroupRows() + mIDCsGrouped.getGroupLastRowsThreshold()) * (mIDCsGrouped.getGroupPads() + mIDCsGrouped.getGroupLastPadsThreshold() + Mapper::ADDITIONALPADSPERROW[i].back()); + if (maxGroup > maxValues) { + maxValues = maxGroup; + } + } + + for (auto& rob : mRobustAverage) { + rob.reserve(maxValues); + } +} + +void o2::tpc::IDCAverageGroup::processIDCs() +{ + const static auto& paramIDCGroup = ParameterIDCGroup::Instance(); + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int integrationInterval = 0; integrationInterval < getNIntegrationIntervals(); ++integrationInterval) { + const unsigned int threadNum = omp_get_thread_num(); + const unsigned int lastRow = mIDCsGrouped.getLastRow(); + unsigned int rowGrouped = 0; + for (unsigned int iRow = 0; iRow <= lastRow; iRow += mIDCsGrouped.getGroupRows()) { + // the sectors is divide in to two parts around ylocal=0 to get the same simmetric grouping around ylocal=0 + for (int iYLocalSide = 0; iYLocalSide < 2; ++iYLocalSide) { + const unsigned int region = mIDCsGrouped.getRegion(); + const unsigned int nPads = Mapper::PADSPERROW[region][iRow] / 2; + const unsigned int endPads = mIDCsGrouped.getLastPad(iRow) + nPads; + + const unsigned int halfPadsInRow = mIDCsGrouped.getPadsPerRow(rowGrouped) / 2; + unsigned int padGrouped = iYLocalSide ? halfPadsInRow : halfPadsInRow - 1; + for (unsigned int ipad = nPads; ipad <= endPads; ipad += mIDCsGrouped.getGroupPads()) { + const unsigned int endRows = (iRow == lastRow) ? (Mapper::ROWSPERREGION[region] - iRow) : mIDCsGrouped.getGroupRows(); + mRobustAverage[threadNum].clear(); + for (unsigned int iRowMerge = 0; iRowMerge < endRows; ++iRowMerge) { + const unsigned int iRowTmp = iRow + iRowMerge; + const auto offs = Mapper::ADDITIONALPADSPERROW[region][iRowTmp] - Mapper::ADDITIONALPADSPERROW[region][iRow]; + const auto padStart = (ipad == 0) ? 0 : offs; + const unsigned int endPadsTmp = (ipad == endPads) ? (Mapper::PADSPERROW[region][iRowTmp] - ipad) : mIDCsGrouped.getGroupPads() + offs; + for (unsigned int ipadMerge = padStart; ipadMerge < endPadsTmp; ++ipadMerge) { + const unsigned int iPadTmp = ipad + ipadMerge; + const unsigned int iPadSide = iYLocalSide ? iPadTmp : Mapper::PADSPERROW[region][iRowTmp] - iPadTmp - 1; + const unsigned int indexIDC = integrationInterval * Mapper::PADSPERREGION[region] + Mapper::OFFSETCRULOCAL[region][iRowTmp] + iPadSide; + mRobustAverage[threadNum].addValue(mIDCsUngrouped[indexIDC] * Mapper::PADAREA[region]); + } + } + + switch (paramIDCGroup.Method) { + case o2::tpc::AveragingMethod::SLOW: + default: + mIDCsGrouped(rowGrouped, padGrouped, integrationInterval) = mRobustAverage[threadNum].getFilteredAverage(mSigma); + break; + case o2::tpc::AveragingMethod::FAST: + mIDCsGrouped(rowGrouped, padGrouped, integrationInterval) = mRobustAverage[threadNum].getMean(); + break; + } + + iYLocalSide ? ++padGrouped : --padGrouped; + } + } + ++rowGrouped; + } + } +} + +void o2::tpc::IDCAverageGroup::dumpToFile(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "RECREATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} + +bool o2::tpc::IDCAverageGroup::setFromFile(const char* fileName, const char* name) +{ + TFile inpf(fileName, "READ"); + IDCAverageGroup* idcAverageGroupTmp{nullptr}; + idcAverageGroupTmp = reinterpret_cast<IDCAverageGroup*>(inpf.GetObjectChecked(name, IDCAverageGroup::Class())); + + if (!idcAverageGroupTmp) { + LOGP(ERROR, "Failed to load {} from {}", name, inpf.GetName()); + return false; + } + setIDCs(idcAverageGroupTmp->getIDCsUngrouped()); + + delete idcAverageGroupTmp; + return true; +} + +void o2::tpc::IDCAverageGroup::drawUngroupedIDCs(const unsigned int integrationInterval, const std::string filename) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSectorHist("hSector", "Sector;local #it{x} (cm);local #it{y} (cm); #it{IDC}"); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetYaxis()->SetTickSize(0.002f); + poly->GetYaxis()->SetTitleOffset(0.7f); + poly->GetZaxis()->SetTitleOffset(1.3f); + poly->SetStats(0); + + TCanvas* can = new TCanvas("can", "can", 2000, 1400); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.06f); + can->SetTopMargin(0.04f); + + TLatex lat; + lat.SetTextFont(63); + lat.SetTextSize(2); + + poly->Draw("colz"); + const unsigned int region = mIDCsGrouped.getRegion(); + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const auto coordinate = coords[padNum]; + const float yPos = -0.5 * (coordinate.yVals[0] + coordinate.yVals[2]); // local coordinate system is mirrored + const float xPos = 0.5 * (coordinate.xVals[0] + coordinate.xVals[2]); + const unsigned int indexIDC = integrationInterval * Mapper::PADSPERREGION[region] + Mapper::OFFSETCRULOCAL[region][irow] + ipad; + const float idc = mIDCsUngrouped[indexIDC] * Mapper::PADAREA[region]; + poly->Fill(xPos, yPos, idc); + lat.SetTextAlign(12); + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +/// for debugging: creating debug tree for integrated IDCs +/// \param nameFile name of the output file +void o2::tpc::IDCAverageGroup::createDebugTree(const char* nameFile) const +{ + o2::utils::TreeStreamRedirector pcstream(nameFile, "RECREATE"); + pcstream.GetFile()->cd(); + createDebugTree(*this, pcstream); + pcstream.Close(); +} + +void o2::tpc::IDCAverageGroup::createDebugTreeForAllCRUs(const char* nameFile, const char* filename) +{ + o2::utils::TreeStreamRedirector pcstream(nameFile, "RECREATE"); + pcstream.GetFile()->cd(); + TFile fInp(filename, "READ"); + + for (TObject* keyAsObj : *fInp.GetListOfKeys()) { + const auto key = dynamic_cast<TKey*>(keyAsObj); + LOGP(info, "Key name: {} Type: {}", key->GetName(), key->GetClassName()); + + if (std::strcmp(o2::tpc::IDCAverageGroup::Class()->GetName(), key->GetClassName()) != 0) { + LOGP(info, "skipping object. wrong class."); + continue; + } + + IDCAverageGroup* idcavg = (IDCAverageGroup*)fInp.Get(key->GetName()); + createDebugTree(*idcavg, pcstream); + delete idcavg; + } + pcstream.Close(); +} + +void o2::tpc::IDCAverageGroup::createDebugTree(const IDCAverageGroup& idcavg, o2::utils::TreeStreamRedirector& pcstream) +{ + const Mapper& mapper = Mapper::instance(); + unsigned int sector = idcavg.getSector(); + unsigned int cru = sector * Mapper::NREGIONS + idcavg.getRegion(); + const o2::tpc::CRU cruTmp(cru); + unsigned int region = cruTmp.region(); + + for (unsigned int integrationInterval = 0; integrationInterval < idcavg.getNIntegrationIntervals(); ++integrationInterval) { + const unsigned long padsPerCRU = Mapper::PADSPERREGION[region]; + std::vector<unsigned int> vRow(padsPerCRU); + std::vector<unsigned int> vPad(padsPerCRU); + std::vector<float> vXPos(padsPerCRU); + std::vector<float> vYPos(padsPerCRU); + std::vector<float> vGlobalXPos(padsPerCRU); + std::vector<float> vGlobalYPos(padsPerCRU); + std::vector<float> idcsPerIntegrationInterval(padsPerCRU); // idcs for one time bin + std::vector<float> groupedidcsPerIntegrationInterval(padsPerCRU); // idcs for one time bin + std::vector<float> invPadArea(padsPerCRU); + + for (unsigned int iPad = 0; iPad < padsPerCRU; ++iPad) { + const GlobalPadNumber globalNum = Mapper::GLOBALPADOFFSET[region] + iPad; + const auto& padPosLocal = mapper.padPos(globalNum); + vRow[iPad] = padPosLocal.getRow(); + vPad[iPad] = padPosLocal.getPad(); + vXPos[iPad] = mapper.getPadCentre(padPosLocal).X(); + vYPos[iPad] = mapper.getPadCentre(padPosLocal).Y(); + invPadArea[iPad] = Mapper::PADAREA[region]; + const GlobalPosition2D globalPos = mapper.LocalToGlobal(LocalPosition2D(vXPos[iPad], vYPos[iPad]), cruTmp.sector()); + vGlobalXPos[iPad] = globalPos.X(); + vGlobalYPos[iPad] = globalPos.Y(); + idcsPerIntegrationInterval[iPad] = idcavg.getUngroupedIDCVal(iPad, integrationInterval); + groupedidcsPerIntegrationInterval[iPad] = idcavg.getGroupedIDCValGlobal(vRow[iPad], vPad[iPad], integrationInterval); + } + + pcstream << "tree" + << "cru=" << cru + << "sector=" << sector + << "region=" << region + << "integrationInterval=" << integrationInterval + << "IDCUngrouped.=" << idcsPerIntegrationInterval + << "IDCGrouped.=" << groupedidcsPerIntegrationInterval + << "invPadArea.=" << invPadArea + << "pad.=" << vPad + << "row.=" << vRow + << "lx.=" << vXPos + << "ly.=" << vYPos + << "gx.=" << vGlobalXPos + << "gy.=" << vGlobalYPos + << "\n"; + } +} + +void o2::tpc::IDCAverageGroup::setIDCs(const std::vector<float>& idcs) +{ + mIDCsUngrouped = idcs; + mIDCsGrouped.resize(getNIntegrationIntervals()); +} + +void o2::tpc::IDCAverageGroup::setIDCs(std::vector<float>&& idcs) +{ + mIDCsUngrouped = std::move(idcs); + mIDCsGrouped.resize(getNIntegrationIntervals()); +} + +unsigned int o2::tpc::IDCAverageGroup::getNIntegrationIntervals() const +{ + return mIDCsUngrouped.size() / Mapper::PADSPERREGION[mIDCsGrouped.getRegion()]; +} + +float o2::tpc::IDCAverageGroup::getUngroupedIDCVal(const unsigned int localPadNumber, const unsigned int integrationInterval) const +{ + return mIDCsUngrouped[localPadNumber + integrationInterval * Mapper::PADSPERREGION[mIDCsGrouped.getRegion()]]; +} + +unsigned int o2::tpc::IDCAverageGroup::getUngroupedIndex(const unsigned int ulrow, const unsigned int upad, const unsigned int integrationInterval) const +{ + return integrationInterval * Mapper::PADSPERREGION[mIDCsGrouped.getRegion()] + Mapper::OFFSETCRULOCAL[mIDCsGrouped.getRegion()][ulrow] + upad; +} + +unsigned int o2::tpc::IDCAverageGroup::getUngroupedIndexGlobal(const unsigned int ugrow, const unsigned int upad, const unsigned int integrationInterval) const +{ + return integrationInterval * Mapper::PADSPERREGION[mIDCsGrouped.getRegion()] + Mapper::OFFSETCRUGLOBAL[ugrow] + upad; +} diff --git a/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx b/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx new file mode 100644 index 0000000000000..27c74826bfcde --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCCCDBHelper.h" +#include "TPCBase/Mapper.h" +#include "TPCBase/Painter.h" +#include "TH2Poly.h" +#include "TCanvas.h" +#include "TLatex.h" + +template <typename DataT> +std::string o2::tpc::IDCCCDBHelper<DataT>::getZAxisTitle(const o2::tpc::IDCType type) const +{ + switch (type) { + case IDCType::IDCZero: + default: + return "#it{IDC_{0}}"; + break; + case IDCType::IDCDelta: + return "#Delta#it{IDC}"; + break; + case IDCType::IDCOne: + case IDCType::IDC: + return "Wrong Type"; + break; + } +} + +template <typename DataT> +void o2::tpc::IDCCCDBHelper<DataT>::drawSide(const o2::tpc::IDCType type, const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSideHist(side); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetXaxis()->SetTitleOffset(1.2f); + poly->GetYaxis()->SetTitleOffset(1.3f); + poly->GetZaxis()->SetTitleOffset(1.2f); + poly->GetZaxis()->SetTitle(getZAxisTitle(type).data()); + poly->GetZaxis()->SetMaxDigits(3); // force exponential axis + poly->SetStats(0); + + TCanvas* can = new TCanvas("can", "can", 650, 600); + can->SetTopMargin(0.04f); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.1f); + poly->Draw("colz"); + + unsigned int sectorStart = (side == Side::A) ? 0 : o2::tpc::SECTORSPERSIDE; + unsigned int sectorEnd = (side == Side::A) ? o2::tpc::SECTORSPERSIDE : Mapper::NSECTORS; + for (unsigned int sector = sectorStart; sector < sectorEnd; ++sector) { + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const float angDeg = 10.f + sector * 20; + auto coordinate = coords[padNum]; + coordinate.rotate(angDeg); + const float yPos = 0.25f * static_cast<float>(coordinate.yVals[0] + coordinate.yVals[1] + coordinate.yVals[2] + coordinate.yVals[3]); + const float xPos = 0.25f * static_cast<float>(coordinate.xVals[0] + coordinate.xVals[1] + coordinate.xVals[2] + coordinate.xVals[3]); + const auto padTmp = (side == Side::A) ? ipad : (Mapper::PADSPERROW[region][irow] - ipad); // C-Side is mirrored + switch (type) { + case IDCType::IDCZero: + default: + poly->Fill(xPos, yPos, getIDCZeroVal(sector, region, irow, padTmp)); + break; + case IDCType::IDCDelta: + poly->Fill(xPos, yPos, getIDCDeltaVal(sector, region, irow, padTmp, integrationInterval)); + break; + case IDCType::IDC: + break; + case IDCType::IDCOne: + break; + } + } + } + } + } + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +template <typename DataT> +void o2::tpc::IDCCCDBHelper<DataT>::drawSector(const IDCType type, const unsigned int sector, const unsigned int integrationInterval, const std::string filename) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSectorHist("hSector", "Sector;local #it{x} (cm);local #it{y} (cm); #it{IDC}"); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetYaxis()->SetTickSize(0.002f); + poly->GetYaxis()->SetTitleOffset(0.7f); + poly->GetZaxis()->SetTitleOffset(1.3f); + poly->SetStats(0); + poly->GetZaxis()->SetTitle(getZAxisTitle(type).data()); + + TCanvas* can = new TCanvas("can", "can", 2000, 1400); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.06f); + can->SetTopMargin(0.04f); + + TLatex lat; + lat.SetTextFont(63); + lat.SetTextSize(2); + poly->Draw("colz"); + + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const auto coordinate = coords[padNum]; + const float yPos = -0.5f * static_cast<float>(coordinate.yVals[0] + coordinate.yVals[2]); // local coordinate system is mirrored + const float xPos = 0.5f * static_cast<float>(coordinate.xVals[0] + coordinate.xVals[2]); + switch (type) { + case IDCType::IDCZero: + default: + poly->Fill(xPos, yPos, getIDCZeroVal(sector, region, irow, ipad)); + break; + case IDCType::IDCDelta: + poly->Fill(xPos, yPos, getIDCDeltaVal(sector, region, irow, ipad, integrationInterval)); + break; + case IDCType::IDC: + break; + case IDCType::IDCOne: + break; + } + // draw global pad number + lat.SetTextAlign(12); + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + } + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +/// load IDC-Delta, 0D-IDCs, grouping parameter +template <typename DataT> +void o2::tpc::IDCCCDBHelper<DataT>::loadAll() +{ + loadIDCDelta(); + loadIDCZero(); + loadGroupingParameter(); +} + +template class o2::tpc::IDCCCDBHelper<float>; +template class o2::tpc::IDCCCDBHelper<short>; +template class o2::tpc::IDCCCDBHelper<char>; diff --git a/Detectors/TPC/calibration/src/IDCFactorization.cxx b/Detectors/TPC/calibration/src/IDCFactorization.cxx new file mode 100644 index 0000000000000..69138b1d2bff1 --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCFactorization.cxx @@ -0,0 +1,509 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCFactorization.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "Framework/Logger.h" +#include "TPCBase/Painter.h" +#include "TH2Poly.h" +#include "TFile.h" +#include "TCanvas.h" +#include "TLatex.h" +#include <functional> + +o2::tpc::IDCFactorization::IDCFactorization(const std::array<unsigned char, Mapper::NREGIONS>& groupPads, const std::array<unsigned char, Mapper::NREGIONS>& groupRows, const std::array<unsigned char, Mapper::NREGIONS>& groupLastRowsThreshold, const std::array<unsigned char, Mapper::NREGIONS>& groupLastPadsThreshold, const unsigned int timeFrames, const unsigned int timeframesDeltaIDC) + : IDCGroupHelperSector{groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold}, mTimeFrames{timeFrames}, mTimeFramesDeltaIDC{timeframesDeltaIDC}, mIDCDelta{timeFrames / timeframesDeltaIDC + (timeFrames % timeframesDeltaIDC != 0)} +{ + for (auto& idc : mIDCs) { + idc.resize(mTimeFrames); + } +} + +void o2::tpc::IDCFactorization::drawSector(const IDCType type, const unsigned int sector, const unsigned int integrationInterval, const std::string filename, const IDCDeltaCompression compression) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSectorHist("hSector", "Sector;local #it{x} (cm);local #it{y} (cm); #it{IDC}"); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetYaxis()->SetTickSize(0.002f); + poly->GetYaxis()->SetTitleOffset(0.7f); + poly->GetZaxis()->SetTitleOffset(1.3f); + poly->SetStats(0); + poly->GetZaxis()->SetTitle(getZAxisTitle(type, compression).data()); + + TCanvas* can = new TCanvas("can", "can", 2000, 1400); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.06f); + can->SetTopMargin(0.04f); + + TLatex lat; + lat.SetTextFont(63); + lat.SetTextSize(2); + poly->Draw("colz"); + + unsigned int chunk = 0; + unsigned int localintegrationInterval = 0; + getLocalIntegrationInterval(0, integrationInterval, chunk, localintegrationInterval); + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const auto coordinate = coords[padNum]; + const float yPos = -0.5f * static_cast<float>(coordinate.yVals[0] + coordinate.yVals[2]); // local coordinate system is mirrored + const float xPos = 0.5f * static_cast<float>(coordinate.xVals[0] + coordinate.xVals[2]); + + switch (type) { + case IDCType::IDC: + default: + poly->Fill(xPos, yPos, getIDCValUngrouped(sector, region, irow, ipad, integrationInterval)); + break; + case IDCType::IDCZero: + poly->Fill(xPos, yPos, getIDCZeroVal(sector, region, irow, ipad)); + break; + case IDCType::IDCDelta: + switch (compression) { + case IDCDeltaCompression::NO: + default: { + poly->Fill(xPos, yPos, getIDCDeltaVal(sector, region, irow, ipad, chunk, localintegrationInterval)); + break; + } + case IDCDeltaCompression::MEDIUM: { + const static auto idcDeltaMedium = getIDCDeltaMediumCompressed(chunk); // make object static to avoid multiple creations of the object in the loop + const float val = idcDeltaMedium.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, ipad, localintegrationInterval)); + poly->Fill(xPos, yPos, val); + break; + } + case IDCDeltaCompression::HIGH: { + const static auto idcDeltaHigh = getIDCDeltaHighCompressed(chunk); // make object static to avoid multiple creations of the object in the loop + const float val = idcDeltaHigh.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, ipad, localintegrationInterval)); + poly->Fill(xPos, yPos, val); + break; + } + } + case IDCType::IDCOne: + break; + } + // draw global pad number + lat.SetTextAlign(12); + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + } + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +void o2::tpc::IDCFactorization::drawSide(const IDCType type, const o2::tpc::Side side, const unsigned int integrationInterval, const std::string filename, const IDCDeltaCompression compression) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSideHist(side); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetXaxis()->SetTitleOffset(1.2f); + poly->GetYaxis()->SetTitleOffset(1.3f); + poly->GetZaxis()->SetTitleOffset(1.2f); + poly->GetZaxis()->SetTitle(getZAxisTitle(type, compression).data()); + poly->GetZaxis()->SetMaxDigits(3); // force exponential axis + poly->SetStats(0); + + TCanvas* can = new TCanvas("can", "can", 650, 600); + can->SetTopMargin(0.04f); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.1f); + poly->Draw("colz"); + + unsigned int chunk = 0; + unsigned int localintegrationInterval = 0; + getLocalIntegrationInterval(0, integrationInterval, chunk, localintegrationInterval); + unsigned int sectorStart = (side == Side::A) ? 0 : o2::tpc::SECTORSPERSIDE; + unsigned int sectorEnd = (side == Side::A) ? o2::tpc::SECTORSPERSIDE : Mapper::NSECTORS; + for (unsigned int sector = sectorStart; sector < sectorEnd; ++sector) { + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const float angDeg = 10.f + sector * 20; + auto coordinate = coords[padNum]; + coordinate.rotate(angDeg); + const float yPos = 0.25f * static_cast<float>(coordinate.yVals[0] + coordinate.yVals[1] + coordinate.yVals[2] + coordinate.yVals[3]); + const float xPos = 0.25f * static_cast<float>(coordinate.xVals[0] + coordinate.xVals[1] + coordinate.xVals[2] + coordinate.xVals[3]); + const auto padTmp = (side == Side::A) ? ipad : (Mapper::PADSPERROW[region][irow] - ipad); // C-Side is mirrored + switch (type) { + case IDCType::IDC: + default: + poly->Fill(xPos, yPos, getIDCValUngrouped(sector, region, irow, padTmp, integrationInterval)); + break; + case IDCType::IDCZero: + poly->Fill(xPos, yPos, getIDCZeroVal(sector, region, irow, padTmp)); + break; + case IDCType::IDCDelta: + switch (compression) { + case IDCDeltaCompression::NO: + default: { + poly->Fill(xPos, yPos, getIDCDeltaVal(sector, region, irow, padTmp, chunk, localintegrationInterval)); + break; + } + case IDCDeltaCompression::MEDIUM: { + const static auto idcDeltaMedium = getIDCDeltaMediumCompressed(chunk); // make object static to avoid multiple creations of the object in the loop + const float val = idcDeltaMedium.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, padTmp, localintegrationInterval)); + poly->Fill(xPos, yPos, val); + break; + } + case IDCDeltaCompression::HIGH: { + const static auto idcDeltaHigh = getIDCDeltaHighCompressed(chunk); // make object static to avoid multiple creations of the object in the loop + const float val = idcDeltaHigh.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, padTmp, localintegrationInterval)); + poly->Fill(xPos, yPos, val); + break; + } + } + case IDCType::IDCOne: + break; + } + } + } + } + } + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +std::string o2::tpc::IDCFactorization::getZAxisTitle(const IDCType type, const IDCDeltaCompression compression) const +{ + switch (type) { + case IDCType::IDC: + default: + return "#it{IDC}"; + break; + case IDCType::IDCZero: + return "#it{IDC_{0}}"; + break; + case IDCType::IDCDelta: + switch (compression) { + case IDCDeltaCompression::NO: + default: + return "#Delta#it{IDC}"; + break; + case IDCDeltaCompression::MEDIUM: + return "#Delta#it{IDC}_{medium compressed}"; + break; + case IDCDeltaCompression::HIGH: + return "#Delta#it{IDC}_{high compressed}"; + break; + } + case IDCType::IDCOne: + return "#Delta#it{IDC}_{1}"; + break; + } +} + +void o2::tpc::IDCFactorization::dumpToFile(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "RECREATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} + +void o2::tpc::IDCFactorization::dumpToTree(int integrationIntervals, const char* outFileName) const +{ + const Mapper& mapper = Mapper::instance(); + o2::utils::TreeStreamRedirector pcstream(outFileName, "RECREATE"); + pcstream.GetFile()->cd(); + + if (integrationIntervals <= 0) { + integrationIntervals = static_cast<int>(getNIntegrationIntervals()); + } + + std::vector<float> idcOneA = mIDCOne.mIDCOne[0]; + std::vector<float> idcOneC = mIDCOne.mIDCOne[1]; + for (unsigned int integrationInterval = 0; integrationInterval < integrationIntervals; ++integrationInterval) { + const unsigned int nIDCsSector = Mapper::getPadsInSector() * Mapper::NSECTORS; + std::vector<int> vRow(nIDCsSector); + std::vector<int> vPad(nIDCsSector); + std::vector<float> vXPos(nIDCsSector); + std::vector<float> vYPos(nIDCsSector); + std::vector<float> vGlobalXPos(nIDCsSector); + std::vector<float> vGlobalYPos(nIDCsSector); + std::vector<float> idcs(nIDCsSector); + std::vector<float> idcsZero(nIDCsSector); + std::vector<float> idcsDelta(nIDCsSector); + std::vector<float> idcsDeltaMedium(nIDCsSector); + std::vector<float> idcsDeltaHigh(nIDCsSector); + std::vector<unsigned int> sectorv(nIDCsSector); + + unsigned int chunk = 0; + unsigned int localintegrationInterval = 0; + getLocalIntegrationInterval(0, integrationInterval, chunk, localintegrationInterval); + const auto idcDeltaMedium = getIDCDeltaMediumCompressed(chunk); + const auto idcDeltaHigh = getIDCDeltaHighCompressed(chunk); + + unsigned int index = 0; + for (unsigned int sector = 0; sector < Mapper::NSECTORS; ++sector) { + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const auto padTmp = (sector < SECTORSPERSIDE) ? ipad : (Mapper::PADSPERROW[region][irow] - ipad); // C-Side is mirrored + const auto& padPosLocal = mapper.padPos(padNum); + vRow[index] = padPosLocal.getRow(); + vPad[index] = padPosLocal.getPad(); + vXPos[index] = mapper.getPadCentre(padPosLocal).X(); + vYPos[index] = mapper.getPadCentre(padPosLocal).Y(); + const GlobalPosition2D globalPos = mapper.LocalToGlobal(LocalPosition2D(vXPos[index], vYPos[index]), Sector(sector)); + vGlobalXPos[index] = globalPos.X(); + vGlobalYPos[index] = globalPos.Y(); + idcs[index] = getIDCValUngrouped(sector, region, irow, padTmp, integrationInterval); + idcsZero[index] = getIDCZeroVal(sector, region, irow, padTmp); + idcsDelta[index] = getIDCDeltaVal(sector, region, irow, padTmp, chunk, localintegrationInterval); + idcsDeltaMedium[index] = idcDeltaMedium.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, padTmp, localintegrationInterval)); + idcsDeltaHigh[index] = idcDeltaHigh.getValue(Sector(sector).side(), getIndexUngrouped(sector, region, irow, padTmp, localintegrationInterval)); + sectorv[index++] = sector; + } + } + } + } + float idcOneATmp = idcOneA[integrationInterval]; + float idcOneCTmp = idcOneC[integrationInterval]; + unsigned int timeFrame = 0; + unsigned int interval = 0; + getTF(0, integrationInterval, timeFrame, interval); + + pcstream << "tree" + << "integrationInterval=" << integrationInterval + << "localintervalinTF=" << interval + << "indexinchunk=" << localintegrationInterval + << "chunk=" << chunk + << "timeframe=" << timeFrame + << "IDC.=" << idcs + << "IDC0.=" << idcsZero + << "IDC1A=" << idcOneATmp + << "IDC1C=" << idcOneCTmp + << "IDCDeltaNoComp.=" << idcsDelta + << "IDCDeltaMediumComp.=" << idcsDeltaMedium + << "IDCDeltaHighComp.=" << idcsDeltaHigh + << "pad.=" << vPad + << "row.=" << vRow + << "lx.=" << vXPos + << "ly.=" << vYPos + << "gx.=" << vGlobalXPos + << "gy.=" << vGlobalYPos + << "sector.=" << sectorv + << "\n"; + } + pcstream.Close(); +} + +void o2::tpc::IDCFactorization::calcIDCZero() +{ + const unsigned int nIDCsSide = mNIDCsPerSector * o2::tpc::SECTORSPERSIDE; + mIDCZero.reset(Side::A); + mIDCZero.reset(Side::C); + mIDCZero.resize(Side::A, nIDCsSide); + mIDCZero.resize(Side::C, nIDCsSide); + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int cru = 0; cru < mIDCs.size(); ++cru) { + const o2::tpc::CRU cruTmp(cru); + const unsigned int region = cruTmp.region(); + const auto factorIndexGlob = mRegionOffs[region] + mNIDCsPerSector * cruTmp.sector(); + for (unsigned int timeframe = 0; timeframe < mTimeFrames; ++timeframe) { + for (unsigned int idcs = 0; idcs < mIDCs[cru][timeframe].size(); ++idcs) { + const unsigned int indexGlob = (idcs % mNIDCsPerCRU[region]) + factorIndexGlob; + mIDCZero.fillValueIDCZero(mIDCs[cru][timeframe][idcs], cruTmp.side(), indexGlob % nIDCsSide); + } + } + } + std::transform(mIDCZero.mIDCZero[Side::A].begin(), mIDCZero.mIDCZero[Side::A].end(), mIDCZero.mIDCZero[Side::A].begin(), [norm = getNIntegrationIntervals()](auto& val) { return val / norm; }); + std::transform(mIDCZero.mIDCZero[Side::C].begin(), mIDCZero.mIDCZero[Side::C].end(), mIDCZero.mIDCZero[Side::C].begin(), [norm = getNIntegrationIntervals()](auto& val) { return val / norm; }); +} + +void o2::tpc::IDCFactorization::calcIDCOne() +{ + const unsigned int nIDCsSide = mNIDCsPerSector * SECTORSPERSIDE; + const unsigned int integrationIntervals = getNIntegrationIntervals(); + mIDCOne.reset(Side::A); + mIDCOne.reset(Side::C); + mIDCOne.resize(Side::A, integrationIntervals); + mIDCOne.resize(Side::C, integrationIntervals); + const unsigned int crusPerSide = Mapper::NREGIONS * SECTORSPERSIDE; + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int cru = 0; cru < mIDCs.size(); ++cru) { + const o2::tpc::CRU cruTmp(cru); + const unsigned int region = cruTmp.region(); + const auto factorIDCOne = crusPerSide * mNIDCsPerCRU[region]; + const auto side = cruTmp.side(); + const auto factorIndexGlob = mRegionOffs[region] + mNIDCsPerSector * cruTmp.sector(); + unsigned int integrationIntervallast = 0; + for (unsigned int timeframe = 0; timeframe < mTimeFrames; ++timeframe) { + for (unsigned int idcs = 0; idcs < mIDCs[cru][timeframe].size(); ++idcs) { + const unsigned int integrationInterval = idcs / mNIDCsPerCRU[region] + integrationIntervallast; + const unsigned int indexGlob = (idcs % mNIDCsPerCRU[region]) + factorIndexGlob; + mIDCOne.mIDCOne[side][integrationInterval] += mIDCs[cru][timeframe][idcs] / (factorIDCOne * mIDCZero.mIDCZero[side][indexGlob % nIDCsSide]); + } + integrationIntervallast += mIDCs[cru][timeframe].size() / mNIDCsPerCRU[region]; + } + } +} + +void o2::tpc::IDCFactorization::calcIDCDelta() +{ + const unsigned int nIDCsSide = mNIDCsPerSector * SECTORSPERSIDE; + for (unsigned int i = 0; i < getNChunks(); ++i) { + const auto idcsSide = nIDCsSide * getNIntegrationIntervals(i); + mIDCDelta[i].getIDCDelta(Side::A).resize(idcsSide); + mIDCDelta[i].getIDCDelta(Side::C).resize(idcsSide); + } + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int cru = 0; cru < mIDCs.size(); ++cru) { + const o2::tpc::CRU cruTmp(cru); + const unsigned int region = cruTmp.region(); + const auto side = cruTmp.side(); + const auto factorIndexGlob = mRegionOffs[region] + mNIDCsPerSector * cruTmp.sector(); + unsigned int integrationIntervallast = 0; + unsigned int integrationIntervallastLocal = 0; + unsigned int lastChunk = 0; + + for (unsigned int timeframe = 0; timeframe < mTimeFrames; ++timeframe) { + const unsigned int chunk = getChunk(timeframe); + if (lastChunk != chunk) { + integrationIntervallastLocal = 0; + } + + for (unsigned int idcs = 0; idcs < mIDCs[cru][timeframe].size(); ++idcs) { + const unsigned int intervallocal = idcs / mNIDCsPerCRU[region]; + const unsigned int integrationIntervalGlobal = intervallocal + integrationIntervallast; + const unsigned int integrationIntervalLocal = intervallocal + integrationIntervallastLocal; + const unsigned int indexGlob = (idcs % mNIDCsPerCRU[region]) + factorIndexGlob; + const unsigned int indexGlobMod = indexGlob % nIDCsSide; + const auto idcZero = mIDCZero.mIDCZero[side][indexGlobMod]; + const auto idcOne = mIDCOne.mIDCOne[side][integrationIntervalGlobal]; + const auto mult = idcZero * idcOne; + const auto val = (mult > 0) ? mIDCs[cru][timeframe][idcs] / mult : 0; + mIDCDelta[chunk].setIDCDelta(side, indexGlobMod + integrationIntervalLocal * nIDCsSide, val - 1.f); + } + + const unsigned int intervals = mIDCs[cru][timeframe].size() / mNIDCsPerCRU[region]; + integrationIntervallast += intervals; + integrationIntervallastLocal += intervals; + lastChunk = chunk; + } + } +} + +float o2::tpc::IDCFactorization::getIDCValUngrouped(const unsigned int sector, const unsigned int region, unsigned int urow, unsigned int upad, unsigned int integrationInterval) const +{ + unsigned int timeFrame = 0; + unsigned int interval = 0; + getTF(region, integrationInterval, timeFrame, interval); + if (mIDCs[sector * Mapper::NREGIONS + region][timeFrame].empty()) { + return 0.f; + } + return mIDCs[sector * Mapper::NREGIONS + region][timeFrame][interval * mNIDCsPerCRU[region] + mOffsRow[region][getGroupedRow(region, urow)] + getGroupedPad(region, urow, upad)]; +} + +void o2::tpc::IDCFactorization::getTF(const unsigned int region, unsigned int integrationInterval, unsigned int& timeFrame, unsigned int& interval) const +{ + unsigned int nintervals = 0; + unsigned int intervalTmp = 0; + for (unsigned int tf = 0; tf < mTimeFrames; ++tf) { + nintervals += mIDCs[region][tf].size() / mNIDCsPerCRU[region]; + if (integrationInterval < nintervals) { + timeFrame = tf; + interval = integrationInterval - intervalTmp; + return; + } + intervalTmp = nintervals; + } +} + +void o2::tpc::IDCFactorization::factorizeIDCs() +{ + LOGP(info, "Using {} threads for factorization of IDCs", sNThreads); + calcIDCZero(); + calcIDCOne(); + calcIDCDelta(); +} + +unsigned long o2::tpc::IDCFactorization::getNIntegrationIntervals(const unsigned int chunk) const +{ + std::size_t sum = 0; + const auto firstTF = chunk * getNTFsPerChunk(0); + for (unsigned int i = firstTF; i < firstTF + getNTFsPerChunk(chunk); ++i) { + sum += mIDCs[0][i].size(); + } + return sum / mNIDCsPerCRU[0]; +} + +unsigned long o2::tpc::IDCFactorization::getNIntegrationIntervals() const +{ + std::size_t sum = 0; + for (auto&& idcsTF : mIDCs[0]) { + sum += idcsTF.size(); + } + return sum / mNIDCsPerCRU[0]; +} + +void o2::tpc::IDCFactorization::getLocalIntegrationInterval(const unsigned int region, const unsigned int integrationInterval, unsigned int& chunk, unsigned int& localintegrationInterval) const +{ + unsigned int nintervals = 0; + unsigned int nitervalsChunk = 0; + unsigned int globalTF = 0; + for (unsigned int ichunk = 0; ichunk < getNChunks(); ++ichunk) { + const auto nTFsPerChunk = getNTFsPerChunk(ichunk); + for (unsigned int tf = 0; tf < nTFsPerChunk; ++tf) { + nintervals += mIDCs[region][globalTF].size() / mNIDCsPerCRU[region]; + if (integrationInterval < nintervals) { + chunk = getChunk(globalTF); + localintegrationInterval = integrationInterval - nitervalsChunk; + return; + } + ++globalTF; + } + nitervalsChunk = nintervals; + } +} + +unsigned int o2::tpc::IDCFactorization::getChunk(const unsigned int timeframe) const +{ + return timeframe / mTimeFramesDeltaIDC; +} + +unsigned int o2::tpc::IDCFactorization::getNTFsPerChunk(const unsigned int chunk) const +{ + const unsigned int remain = mTimeFrames % mTimeFramesDeltaIDC; + return ((chunk == getNChunks() - 1) && remain) ? remain : mTimeFramesDeltaIDC; +} + +std::vector<unsigned int> o2::tpc::IDCFactorization::getIntegrationIntervalsPerTF(const unsigned int region) const +{ + std::vector<unsigned int> integrationIntervalsPerTF; + integrationIntervalsPerTF.reserve(mTimeFrames); + for (unsigned int tf = 0; tf < mTimeFrames; ++tf) { + integrationIntervalsPerTF.emplace_back(mIDCs[region][tf].size() / mNIDCsPerCRU[region]); + } + return integrationIntervalsPerTF; +} + +void o2::tpc::IDCFactorization::reset() +{ + for (auto& tf : mIDCs) { + for (auto& idcs : tf) { + idcs.clear(); + } + } +} diff --git a/Detectors/TPC/calibration/src/IDCFourierTransform.cxx b/Detectors/TPC/calibration/src/IDCFourierTransform.cxx new file mode 100644 index 0000000000000..43c654fe34358 --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCFourierTransform.cxx @@ -0,0 +1,270 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCFourierTransform.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/Logger.h" +#include "TFile.h" +#include <fftw3.h> + +#if (defined(WITH_OPENMP) || defined(_OPENMP)) && !defined(__CLING__) +#include <omp.h> +#else +static inline int omp_get_thread_num() { return 0; } +#endif + +template <class Type> +o2::tpc::IDCFourierTransform<Type>::~IDCFourierTransform() +{ + for (int thread = 0; thread < sNThreads; ++thread) { + fftwf_free(mVal1DIDCs[thread]); + fftwf_free(mCoefficients[thread]); + } + fftwf_destroy_plan(mFFTWPlan); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::initFFTW3Members() +{ + for (int thread = 0; thread < sNThreads; ++thread) { + mVal1DIDCs[thread] = fftwf_alloc_real(this->mRangeIDC); + mCoefficients[thread] = fftwf_alloc_complex(getNMaxCoefficients()); + } + mFFTWPlan = fftwf_plan_dft_r2c_1d(this->mRangeIDC, mVal1DIDCs.front(), mCoefficients.front(), FFTW_ESTIMATE); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::calcFourierCoefficientsNaive() +{ + LOGP(info, "calculating fourier coefficients for current TF using naive approach using {} threads", sNThreads); + calcFourierCoefficientsNaive(o2::tpc::Side::A); + calcFourierCoefficientsNaive(o2::tpc::Side::C); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::calcFourierCoefficientsFFTW3() +{ + LOGP(info, "calculating fourier coefficients for current TF using fftw3 using {} threads", sNThreads); + calcFourierCoefficientsFFTW3(o2::tpc::Side::A); + calcFourierCoefficientsFFTW3(o2::tpc::Side::C); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::calcFourierCoefficientsNaive(const o2::tpc::Side side) +{ + // check if IDCs are present for current side + if (this->getNIDCs(side) == 0) { + LOGP(warning, "no 1D-IDCs found!"); + mFourierCoefficients.reset(side); + return; + } + + const std::vector<unsigned int> offsetIndex = this->getLastIntervals(side); + + // see: https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Definitiona + const bool add = mFourierCoefficients.getNCoefficientsPerTF() % 2; + const unsigned int lastCoeff = mFourierCoefficients.getNCoefficientsPerTF() / 2; + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int interval = 0; interval < this->getNIntervals(); ++interval) { + const std::vector<float>& idcOneExpanded{this->getExpandedIDCOne(side)}; // 1D-IDC values which will be used for the FFT + for (unsigned int coeff = 0; coeff < lastCoeff; ++coeff) { + const unsigned int indexDataReal = mFourierCoefficients.getIndex(interval, 2 * coeff); // index for storing real fourier coefficient + const unsigned int indexDataImag = indexDataReal + 1; // index for storing complex fourier coefficient + const float term0 = o2::constants::math::TwoPI * coeff / this->mRangeIDC; + for (unsigned int index = 0; index < this->mRangeIDC; ++index) { + const float term = term0 * index; + const float idc0 = idcOneExpanded[index + offsetIndex[interval]]; + mFourierCoefficients(side, indexDataReal) += idc0 * std::cos(term); + mFourierCoefficients(side, indexDataImag) -= idc0 * std::sin(term); + } + } + if (add) { + const unsigned int indexDataReal = mFourierCoefficients.getIndex(interval, 2 * lastCoeff); // index for storing real fourier coefficient + const float term0 = o2::constants::math::TwoPI * lastCoeff / this->mRangeIDC; + for (unsigned int index = 0; index < this->mRangeIDC; ++index) { + const float term = term0 * index; + const float idc0 = idcOneExpanded[index + offsetIndex[interval]]; + mFourierCoefficients(side, indexDataReal) += idc0 * std::cos(term); + } + } + } + // normalize coefficient to number of used points + normalizeCoefficients(side); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::calcFourierCoefficientsFFTW3(const o2::tpc::Side side) +{ + // for FFTW and OMP see: https://stackoverflow.com/questions/15012054/fftw-plan-creation-using-openmp + // check if IDCs are present for current side + if (this->getNIDCs(side) == 0) { + LOGP(warning, "no 1D-IDCs found!"); + mFourierCoefficients.reset(side); + return; + } + + const std::vector<unsigned int> offsetIndex = this->getLastIntervals(side); + const std::vector<float>& idcOneExpanded{this->getExpandedIDCOne(side)}; // 1D-IDC values which will be used for the FFT + + if constexpr (std::is_same_v<Type, IDCFourierTransformBaseAggregator>) { +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int interval = 0; interval < this->getNIntervals(); ++interval) { + fftwLoop(idcOneExpanded, offsetIndex, interval, side, omp_get_thread_num()); + } + } else { + fftwLoop(idcOneExpanded, offsetIndex, 0, side, 0); + } + + normalizeCoefficients(side); +} + +template <class Type> +inline void o2::tpc::IDCFourierTransform<Type>::fftwLoop(const std::vector<float>& idcOneExpanded, const std::vector<unsigned int>& offsetIndex, const unsigned int interval, const o2::tpc::Side side, const unsigned int thread) +{ + std::memcpy(mVal1DIDCs[thread], &idcOneExpanded[offsetIndex[interval]], this->mRangeIDC * sizeof(float)); // copy IDCs to avoid seg fault when using SIMD instructions + fftwf_execute_dft_r2c(mFFTWPlan, mVal1DIDCs[thread], mCoefficients[thread]); // perform ft + std::memcpy(&(*(mFourierCoefficients.mFourierCoefficients[side].begin() + mFourierCoefficients.getIndex(interval, 0))), mCoefficients[thread], mFourierCoefficients.getNCoefficientsPerTF() * sizeof(float)); // store coefficients +} + +template <class Type> +std::vector<std::vector<float>> o2::tpc::IDCFourierTransform<Type>::inverseFourierTransformNaive(const o2::tpc::Side side) const +{ + if (this->mRangeIDC % 2) { + LOGP(info, "number of specified fourier coefficients is {}, but should be an even number! FFTW3 method is used instead!", mFourierCoefficients.getNCoefficientsPerTF()); + return inverseFourierTransformFFTW3(side); + } + + // vector containing for each intervall the inverse fourier IDCs + std::vector<std::vector<float>> inverse(this->getNIntervals()); + const float factor = o2::constants::math::TwoPI / this->mRangeIDC; + + // loop over all the intervals. For each interval the coefficients are calculated + for (unsigned int interval = 0; interval < this->getNIntervals(); ++interval) { + inverse[interval].resize(this->mRangeIDC); + for (unsigned int index = 0; index < this->mRangeIDC; ++index) { + const float term0 = factor * index; + unsigned int coeffTmp = 0; + int fac = 1; // if input data is real (and it is) the coefficients are mirrored https://dsp.stackexchange.com/questions/4825/why-is-the-fft-mirrored + for (unsigned int coeff = 0; coeff < this->mRangeIDC; ++coeff) { + const unsigned int indexDataReal = mFourierCoefficients.getIndex(interval, 2 * coeffTmp); // index for storing real fourier coefficient + const unsigned int indexDataImag = indexDataReal + 1; // index for storing complex fourier coefficient + const float term = term0 * coeff; + inverse[interval][index] += mFourierCoefficients(side, indexDataReal) * std::cos(term) - fac * mFourierCoefficients(side, indexDataImag) * std::sin(term); + if (coeff < getNMaxCoefficients() - 1) { + ++coeffTmp; + } else { + --coeffTmp; + fac = -1; + }; + } + } + } + return inverse; +} + +template <class Type> +std::vector<std::vector<float>> o2::tpc::IDCFourierTransform<Type>::inverseFourierTransformFFTW3(const o2::tpc::Side side) const +{ + // vector containing for each intervall the inverse fourier IDCs + std::vector<std::vector<float>> inverse(this->getNIntervals()); + + // loop over all the intervals. For each interval the coefficients are calculated + // this loop and execution of FFTW is not optimized as it is used only for debugging + for (unsigned int interval = 0; interval < this->getNIntervals(); ++interval) { + inverse[interval].resize(this->mRangeIDC); + std::vector<std::array<float, 2>> val1DIDCs; + val1DIDCs.reserve(this->mRangeIDC); + for (unsigned int index = 0; index < getNMaxCoefficients(); ++index) { + const unsigned int indexDataReal = mFourierCoefficients.getIndex(interval, 2 * index); // index for storing real fourier coefficient + const unsigned int indexDataImag = indexDataReal + 1; // index for storing complex fourier coefficient + val1DIDCs.emplace_back(std::array<float, 2>{mFourierCoefficients(side, indexDataReal), mFourierCoefficients(side, indexDataImag)}); + } + const fftwf_plan fftwPlan = fftwf_plan_dft_c2r_1d(this->mRangeIDC, reinterpret_cast<fftwf_complex*>(val1DIDCs.data()), inverse[interval].data(), FFTW_ESTIMATE); + fftwf_execute(fftwPlan); + fftwf_destroy_plan(fftwPlan); + } + return inverse; +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::dumpToFile(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "RECREATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::dumpToTree(const char* outFileName) const +{ + o2::utils::TreeStreamRedirector pcstream(outFileName, "RECREATE"); + pcstream.GetFile()->cd(); + for (unsigned int iSide = 0; iSide < o2::tpc::SIDES; ++iSide) { + const o2::tpc::Side side = iSide == 0 ? Side::A : Side::C; + const std::vector<unsigned int> offsetIndex = this->getLastIntervals(side); + const auto idcOneExpanded = this->getExpandedIDCOne(side); + const auto inverseFourier = inverseFourierTransformNaive(side); + const auto inverseFourierFFTW3 = inverseFourierTransformFFTW3(side); + + for (unsigned int interval = 0; interval < this->getNIntervals(); ++interval) { + std::vector<float> oneDIDCInverse = inverseFourier[interval]; + std::vector<float> oneDIDCInverseFFTW3 = inverseFourierFFTW3[interval]; + + // get 1D-IDC values used for calculation of the fourier coefficients + std::vector<float> oneDIDC; + oneDIDC.reserve(this->mRangeIDC); + for (unsigned int index = 0; index < this->mRangeIDC; ++index) { + oneDIDC.emplace_back(idcOneExpanded[index + offsetIndex[interval]]); + } + + for (unsigned int coeff = 0; coeff < mFourierCoefficients.getNCoefficientsPerTF(); ++coeff) { + float coefficient = mFourierCoefficients(side, mFourierCoefficients.getIndex(interval, coeff)); + + pcstream << "tree" + << "side=" << iSide + << "interval=" << interval + << "icoefficient=" << coeff // index of ith coefficient + << "coefficient=" << coefficient // value for ith coefficient + << "1DIDC.=" << oneDIDC + << "1DIDCiDFT.=" << oneDIDCInverse + << "1DIDCiDFTFFTW3.=" << oneDIDCInverseFFTW3 + << "\n"; + } + } + } +} + +template <class Type> +void o2::tpc::IDCFourierTransform<Type>::printFFTWPlan() const +{ + float* val1DIDCs = fftwf_alloc_real(this->mRangeIDC); + fftwf_complex* coefficients = fftwf_alloc_complex(getNMaxCoefficients()); + fftwf_plan fftwPlan = fftwf_plan_dft_r2c_1d(this->mRangeIDC, val1DIDCs, coefficients, FFTW_ESTIMATE); + char* splan = fftwf_sprint_plan(fftwPlan); + + LOGP(info, "========= printing FFTW plan ========= \n {}", splan); + double add = 0; + double mul = 0; + double fusedMultAdd = 0; + fftwf_flops(fftwPlan, &add, &mul, &fusedMultAdd); + LOGP(info, "additions: {} multiplications: {} fused multiply-add: {} sum: {}", add, mul, fusedMultAdd, add + mul + fusedMultAdd); + + // free memory + free(splan); + fftwf_free(coefficients); + fftwf_free(val1DIDCs); + fftwf_destroy_plan(fftwPlan); +} + +template class o2::tpc::IDCFourierTransform<o2::tpc::IDCFourierTransformBaseEPN>; +template class o2::tpc::IDCFourierTransform<o2::tpc::IDCFourierTransformBaseAggregator>; diff --git a/Detectors/TPC/calibration/src/IDCFourierTransformBase.cxx b/Detectors/TPC/calibration/src/IDCFourierTransformBase.cxx new file mode 100644 index 0000000000000..d6078fe162194 --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCFourierTransformBase.cxx @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCFourierTransformBase.h" +#include <fftw3.h> + +void o2::tpc::IDCFourierTransformAggregator::setIDCs(OneDIDC&& oneDIDCs, std::vector<unsigned int>&& integrationIntervalsPerTF) +{ + mOneDIDC[mBufferIndex] = std::move(oneDIDCs); + mIntegrationIntervalsPerTF[mBufferIndex] = std::move(integrationIntervalsPerTF); + mBufferIndex = !mBufferIndex; +} + +void o2::tpc::IDCFourierTransformAggregator::setIDCs(const OneDIDC& oneDIDCs, const std::vector<unsigned int>& integrationIntervalsPerTF) +{ + mOneDIDC[mBufferIndex] = oneDIDCs; + mIntegrationIntervalsPerTF[mBufferIndex] = integrationIntervalsPerTF; + mBufferIndex = !mBufferIndex; +} + +std::vector<unsigned int> o2::tpc::IDCFourierTransformAggregator::getLastIntervals(o2::tpc::Side) const +{ + std::vector<unsigned int> endIndex; + endIndex.reserve(mTimeFrames); + endIndex.emplace_back(0); + for (unsigned int interval = 1; interval < mTimeFrames; ++interval) { + endIndex.emplace_back(endIndex[interval - 1] + mIntegrationIntervalsPerTF[!mBufferIndex][interval]); + } + return endIndex; +} + +std::vector<float> o2::tpc::IDCFourierTransformAggregator::getExpandedIDCOne(const o2::tpc::Side side) const +{ + std::vector<float> val1DIDCs = mOneDIDC[!mBufferIndex].mOneDIDC[side]; // just copy the elements + if (useLastBuffer()) { + val1DIDCs.insert(val1DIDCs.begin(), mOneDIDC[mBufferIndex].mOneDIDC[side].end() - mRangeIDC + mIntegrationIntervalsPerTF[!mBufferIndex][0], mOneDIDC[mBufferIndex].mOneDIDC[side].end()); + } + return val1DIDCs; +} + +float* o2::tpc::IDCFourierTransformAggregator::allocMemFFTW(const o2::tpc::Side side) const +{ + const unsigned int nElementsLastBuffer = useLastBuffer() ? mRangeIDC - mIntegrationIntervalsPerTF[!mBufferIndex][0] : 0; + const unsigned int nElementsAll = mOneDIDC[!mBufferIndex].getNIDCs(side) + nElementsLastBuffer; + return fftwf_alloc_real(nElementsAll); +} diff --git a/Detectors/TPC/calibration/src/IDCGroup.cxx b/Detectors/TPC/calibration/src/IDCGroup.cxx new file mode 100644 index 0000000000000..a0996babe833c --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCGroup.cxx @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCGroup.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TPCBase/Painter.h" +#include "TPCBase/Mapper.h" +#include "TH2Poly.h" +#include "TFile.h" +#include "TCanvas.h" +#include "TLatex.h" +#include <numeric> + +void o2::tpc::IDCGroup::dumpToTree(const char* outname) const +{ + o2::utils::TreeStreamRedirector pcstream(outname, "RECREATE"); + pcstream.GetFile()->cd(); + for (unsigned int integrationInterval = 0; integrationInterval < getNIntegrationIntervals(); ++integrationInterval) { + for (unsigned int irow = 0; irow < mRows; ++irow) { + for (unsigned int ipad = 0; ipad < mPadsPerRow[irow]; ++ipad) { + float idc = (*this)(irow, ipad, integrationInterval); + pcstream << "idcs" + << "row=" << irow + << "pad=" << ipad + << "IDC=" << idc + << "\n"; + } + } + } + pcstream.Close(); +} + +void o2::tpc::IDCGroup::draw(const unsigned int integrationInterval, const std::string filename) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSectorHist("hSector", "Sector;local #it{x} (cm);local #it{y} (cm); #it{IDC}"); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetYaxis()->SetTickSize(0.002f); + poly->GetYaxis()->SetTitleOffset(0.7f); + poly->GetZaxis()->SetTitleOffset(1.3f); + poly->SetStats(0); + + TCanvas* can = new TCanvas("can", "can", 2000, 1400); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.06f); + can->SetTopMargin(0.04f); + + TLatex lat; + lat.SetTextFont(63); + lat.SetTextSize(2); + + poly->Draw("colz"); + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[mRegion]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[mRegion][irow]; ++ipad) { + const auto padNum = getGlobalPadNumber(irow, ipad); + const auto coordinate = coords[padNum]; + const float yPos = -0.5f * (coordinate.yVals[0] + coordinate.yVals[2]); // local coordinate system is mirrored + const float xPos = 0.5f * (coordinate.xVals[0] + coordinate.xVals[2]); + poly->Fill(xPos, yPos, (*this)(getGroupedRow(irow), getGroupedPad(ipad, irow), integrationInterval)); + lat.SetTextAlign(12); + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} + +void o2::tpc::IDCGroup::dumpToFile(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "UPDATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} + +float o2::tpc::IDCGroup::getValUngroupedGlobal(unsigned int ugrow, unsigned int upad, unsigned int integrationInterval) const +{ + return mIDCsGrouped[getIndexUngrouped(Mapper::getLocalRowFromGlobalRow(ugrow), upad, integrationInterval)]; +} + +std::vector<float> o2::tpc::IDCGroup::get1DIDCs() const +{ + // integrate IDCs for each interval + std::vector<float> idc; + const unsigned int nIntervals = getNIntegrationIntervals(); + idc.reserve(nIntervals); + for (unsigned int i = 0; i < nIntervals; ++i) { + // set integration range for one integration interval + const auto start = mIDCsGrouped.begin() + i * getNIDCsPerIntegrationInterval(); + const auto end = start + getNIDCsPerIntegrationInterval(); + idc.emplace_back(std::accumulate(start, end, decltype(mIDCsGrouped)::value_type(0))); + } + // normalize 1D-IDCs to absolute space charge + const float norm = Mapper::REGIONAREA[mRegion] / getNIDCsPerIntegrationInterval(); + std::transform(idc.begin(), idc.end(), idc.begin(), [norm](auto& val) { return val * norm; }); + + return idc; +} diff --git a/Detectors/TPC/calibration/src/IDCGroupHelperRegion.cxx b/Detectors/TPC/calibration/src/IDCGroupHelperRegion.cxx new file mode 100644 index 0000000000000..c2f5d411c446d --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCGroupHelperRegion.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCGroupHelperRegion.h" +#include "TPCBase/Mapper.h" +#include "TFile.h" +#include <numeric> + +unsigned int o2::tpc::IDCGroupHelperRegion::getGlobalPadNumber(const unsigned int ulrow, const unsigned int pad) const +{ + return Mapper::getGlobalPadNumber(ulrow, pad, mRegion); +} + +unsigned int o2::tpc::IDCGroupHelperRegion::getGroupedRow(const unsigned int ulrow, const unsigned int groupRows, const unsigned int groupedrows) +{ + const unsigned int row = ulrow / groupRows; + return (row >= groupedrows) ? (groupedrows - 1) : row; +} + +unsigned int o2::tpc::IDCGroupHelperRegion::getGroupedPad(const unsigned int upad, const unsigned int ulrow, const unsigned int region, const unsigned int groupPads, const unsigned int groupRows, const unsigned int groupedrows, const std::vector<unsigned int>& padsPerRow) +{ + const int relPadHalf = static_cast<int>(std::floor((upad - 0.5f * Mapper::PADSPERROW[region][ulrow]) / groupPads)); + const unsigned int nGroupedPads = padsPerRow[getGroupedRow(ulrow, groupRows, groupedrows)]; + const unsigned int nGroupedPadsHalf = (nGroupedPads / 2); + if (std::abs(relPadHalf) >= nGroupedPadsHalf) { + return std::signbit(relPadHalf) ? 0 : nGroupedPads - 1; + } + return static_cast<unsigned int>(static_cast<int>(nGroupedPadsHalf) + relPadHalf); +} + +void o2::tpc::IDCGroupHelperRegion::setRows(const unsigned int nRows) +{ + mRows = nRows; + mPadsPerRow.resize(mRows); + mOffsRow.resize(mRows); +} + +unsigned int o2::tpc::IDCGroupHelperRegion::getLastRow() const +{ + const unsigned int nTotRows = Mapper::ROWSPERREGION[mRegion]; + const unsigned int rowsRemainder = nTotRows % mGroupRows; + unsigned int lastRow = nTotRows - rowsRemainder; + if (rowsRemainder <= mGroupLastRowsThreshold) { + lastRow -= mGroupRows; + } + return lastRow; +} + +unsigned int o2::tpc::IDCGroupHelperRegion::getLastPad(const unsigned int ulrow) const +{ + const unsigned int nPads = Mapper::PADSPERROW[mRegion][ulrow] / 2; + const unsigned int padsRemainder = nPads % mGroupPads; + int unsigned lastPad = (padsRemainder == 0) ? nPads - mGroupPads : nPads - padsRemainder; + if (padsRemainder && padsRemainder <= mGroupLastPadsThreshold) { + lastPad -= mGroupPads; + } + return lastPad; +} + +void o2::tpc::IDCGroupHelperRegion::initIDCGroupHelperRegion() +{ + const unsigned int nRows = getLastRow() / mGroupRows + 1; + setRows(nRows); + for (unsigned int irow = 0; irow < nRows; ++irow) { + const unsigned int row = irow * mGroupRows; + mPadsPerRow[irow] = 2 * (getLastPad(row) / mGroupPads + 1); + } + + mNIDCsPerCRU = std::accumulate(mPadsPerRow.begin(), mPadsPerRow.end(), decltype(mPadsPerRow)::value_type(0)); + for (unsigned int i = 1; i < mRows; ++i) { + const unsigned int lastInd = i - 1; + mOffsRow[i] = mOffsRow[lastInd] + mPadsPerRow[lastInd]; + } +} + +void o2::tpc::IDCGroupHelperRegion::dumpToFile(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "UPDATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} diff --git a/Detectors/TPC/calibration/src/IDCGroupingParameter.cxx b/Detectors/TPC/calibration/src/IDCGroupingParameter.cxx new file mode 100644 index 0000000000000..c2ecf9cf21a2e --- /dev/null +++ b/Detectors/TPC/calibration/src/IDCGroupingParameter.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/IDCGroupingParameter.h" + +using namespace o2::tpc; +O2ParamImpl(o2::tpc::ParameterIDCGroup); +O2ParamImpl(o2::tpc::ParameterIDCCompression); diff --git a/Detectors/TPC/calibration/src/LaserTracksCalibrator.cxx b/Detectors/TPC/calibration/src/LaserTracksCalibrator.cxx new file mode 100644 index 0000000000000..e3b6a18c7e764 --- /dev/null +++ b/Detectors/TPC/calibration/src/LaserTracksCalibrator.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <fmt/format.h> + +#include "TPCCalibration/LaserTracksCalibrator.h" + +using namespace o2::tpc; + +void LaserTracksCalibrator::initOutput() +{ + mCalibPerSlot.clear(); +} + +//______________________________________________________________________________ +void LaserTracksCalibrator::finalizeSlot(Slot& slot) +{ + auto& calibLaser = *slot.getContainer(); + calibLaser.finalize(); + calibLaser.print(); + + mCalibPerSlot.emplace_back(calibLaser.getCalibData()); +} + +//______________________________________________________________________________ +LaserTracksCalibrator::Slot& LaserTracksCalibrator::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique<CalibLaserTracks>()); + auto& calibLaser = *slot.getContainer(); + //calibLaser.setTFtimes(tstart, tend); + + if (mWriteDebug) { + calibLaser.setWriteDebugTree(mWriteDebug); + calibLaser.setDebugOutputName(fmt::format("CalibLaserTracks_debug_{}_{}.root", tstart, tend)); + } + + return slot; +} diff --git a/Detectors/TPC/calibration/src/RobustAverage.cxx b/Detectors/TPC/calibration/src/RobustAverage.cxx new file mode 100644 index 0000000000000..343ddd3c373fd --- /dev/null +++ b/Detectors/TPC/calibration/src/RobustAverage.cxx @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/RobustAverage.h" +#include "Framework/Logger.h" +#include <numeric> + +float o2::tpc::RobustAverage::getFilteredAverage(const float sigma) +{ + if (mValues.empty()) { + return 0; + } + + const float mean = getMean(); + const float stdev = getStdDev(mean); + return getFilteredMean(mean, stdev, sigma); +} + +float o2::tpc::RobustAverage::getStdDev(const float mean) +{ + const auto size = mValues.size(); + mTmpValues.resize(size); + std::transform(mValues.begin(), mValues.end(), mTmpValues.begin(), [mean](const float val) { return val - mean; }); + const float sqsum = std::inner_product(mTmpValues.begin(), mTmpValues.end(), mTmpValues.begin(), decltype(mTmpValues)::value_type(0)); + const float stdev = std::sqrt(sqsum / size); + return stdev; +} + +float o2::tpc::RobustAverage::getFilteredMean(const float mean, const float stdev, const float sigma) +{ + std::sort(mValues.begin(), mValues.end()); + const float sigmastddev = sigma * stdev; + const float minVal = mean - sigmastddev; + const float maxVal = mean + sigmastddev; + const auto upper = std::upper_bound(mValues.begin(), mValues.end(), maxVal); + const auto lower = std::lower_bound(mValues.begin(), mValues.end(), minVal); + return getMean(lower, upper); +} + +void o2::tpc::RobustAverage::print() const +{ + LOGP(info, "PRINTING STORED VALUES"); + for (auto val : mValues) { + LOGP(info, "{}", val); + } +} + +float o2::tpc::RobustAverage::getMean(std::vector<float>::const_iterator begin, std::vector<float>::const_iterator end) const +{ + return std::accumulate(begin, end, decltype(mValues)::value_type(0)) / std::distance(begin, end); +} diff --git a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h index df237af65bfd0..e919073de5391 100644 --- a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h +++ b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,10 +17,10 @@ #pragma link C++ class o2::tpc::CalibRawBase; #pragma link C++ class o2::tpc::CalibPedestal; -#pragma link C++ class o2::tpc::CalibPedestalParam +; +#pragma link C++ class o2::tpc::CalibPedestalParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::tpc::CalibPedestalParam> + ; #pragma link C++ class o2::tpc::CalibPulser; -#pragma link C++ class o2::tpc::CalibPulserParam +; +#pragma link C++ class o2::tpc::CalibPulserParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::tpc::CalibPulserParam> + ; #pragma link C++ class o2::tpc::CalibTreeDump; #pragma link C++ class o2::tpc::DigitDump; @@ -28,5 +29,49 @@ #pragma link C++ class o2::tpc::CalibPadGainTracks; #pragma link C++ class o2::tpc::FastHisto<float> +; #pragma link C++ class o2::tpc::FastHisto<unsigned int> +; +#pragma link C++ class o2::tpc::CalibLaserTracks +; +#pragma link C++ class o2::tpc::LaserTracksCalibrator +; +#pragma link C++ class o2::calibration::TimeSlot<o2::tpc::CalibLaserTracks> +; +#pragma link C++ class o2::calibration::TimeSlotCalibration<o2::tpc::TrackTPC, o2::tpc::CalibLaserTracks> +; +#pragma link C++ class o2::tpc::TimePair +; +#pragma link C++ class o2::tpc::LtrCalibData +; +#pragma link C++ class std::vector<o2::tpc::TimePair> +; +#pragma link C++ class std::vector<o2::tpc::LtrCalibData> +; +#pragma link C++ class o2::tpc::IDCGroup +; +#pragma link C++ class o2::tpc::IDCGroupHelperRegion +; +#pragma link C++ class o2::tpc::IDCGroupHelperSector +; +#pragma link C++ struct o2::tpc::ParameterIDCGroup; +#pragma link C++ struct o2::tpc::ParameterIDCCompression; +#pragma link C++ class o2::tpc::IDCAverageGroup +; +#pragma link C++ class o2::tpc::IDCFactorization +; +#pragma link C++ struct o2::tpc::IDCDelta<float> +; +#pragma link C++ struct o2::tpc::IDCDelta<short> +; +#pragma link C++ struct o2::tpc::IDCDelta<char> +; +#pragma link C++ struct o2::tpc::IDCDeltaCompressionFactors +; +#pragma link C++ struct o2::tpc::IDCDeltaContainer<float> +; +#pragma link C++ struct o2::tpc::IDCDeltaContainer<short> +; +#pragma link C++ struct o2::tpc::IDCDeltaContainer<char> +; +#pragma link C++ class o2::tpc::IDCDeltaCompressionHelper<short> +; +#pragma link C++ class o2::tpc::IDCDeltaCompressionHelper<char> +; +#pragma link C++ struct o2::tpc::IDCZero +; +#pragma link C++ struct o2::tpc::IDCOne +; +#pragma link C++ struct o2::tpc::OneDIDC +; +#pragma link C++ class o2::tpc::OneDIDCAggregator +; +#pragma link C++ struct o2::tpc::FourierCoeff +; +#pragma link C++ struct o2::tpc::ParameterIDCGroupCCDB +; +#pragma link C++ class o2::tpc::RobustAverage +; +#pragma link C++ class o2::tpc::IDCFourierTransformBase<o2::tpc::IDCFourierTransformBaseEPN> +; +#pragma link C++ class o2::tpc::IDCFourierTransformBase<o2::tpc::IDCFourierTransformBaseAggregator> +; +#pragma link C++ class o2::tpc::IDCFourierTransform<o2::tpc::IDCFourierTransformBaseEPN> +; +#pragma link C++ class o2::tpc::IDCFourierTransform<o2::tpc::IDCFourierTransformBaseAggregator> +; +#pragma link C++ class o2::tpc::IDCCCDBHelper<float> +; +#pragma link C++ class o2::tpc::IDCCCDBHelper<short> +; +#pragma link C++ class o2::tpc::IDCCCDBHelper<char> +; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::tpc::TrackTPC, o2::tpc::dEdxHistos> + ; +#pragma link C++ class o2::tpc::CalibdEdx + ; +#pragma link C++ class o2::tpc::dEdxHistos + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::tpc::dEdxHistos> + ; +#pragma link C++ class o2::tpc::CalibMIP + ; +#pragma link C++ enum o2::tpc::AveragingMethod; #endif diff --git a/Detectors/TPC/calibration/src/dEdxHistos.cxx b/Detectors/TPC/calibration/src/dEdxHistos.cxx new file mode 100644 index 0000000000000..e2c523fe1f83d --- /dev/null +++ b/Detectors/TPC/calibration/src/dEdxHistos.cxx @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCCalibration/dEdxHistos.h" + +#include <array> +#include <cstddef> +#include <string_view> +#include <utility> + +//o2 includes +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/TrackCuts.h" +#include "Framework/Logger.h" +#include "TPCCalibration/FastHisto.h" + +//root includes +#include "TFile.h" + +using namespace o2::tpc; + +dEdxHistos::dEdxHistos(unsigned int nBins, const TrackCuts& cuts) + : mCuts{cuts}, mHist{{{nBins, 0, static_cast<float>(nBins)}, {nBins, 0, static_cast<float>(nBins)}}} +{ +} + +void dEdxHistos::fill(const gsl::span<const TrackTPC> tracks) +{ + for (const auto& track : tracks) { + + // applying cut + if (!mApplyCuts || mCuts.goodTrack(track)) { + // filling histogram + if (track.hasASideClustersOnly()) { + mEntries[0]++; + mHist[0].fill(track.getdEdx().dEdxTotTPC); + } else if (track.hasCSideClustersOnly()) { + mEntries[1]++; + mHist[1].fill(track.getdEdx().dEdxTotTPC); + } + } + } +} + +void dEdxHistos::merge(const dEdxHistos* other) +{ + for (size_t i = 0; i < mHist.size(); i++) { + const auto binCount = mHist[i].getNBins(); + for (size_t bin = 0; bin < binCount; bin++) { + float bin_content = other->getHists()[i].getBinContent(bin); + mHist[i].fillBin(bin, bin_content); + } + } +} + +void dEdxHistos::print() const +{ + LOG(INFO) << "Total number of entries: " << mEntries[0] << " in A side, " << mEntries[1] << " in C side"; +} + +void dEdxHistos::dumpToFile(std::string_view fileName) const +{ + TFile file(fileName.data(), "recreate"); + file.WriteObject(&mHist[0], "dEdxTotTPC A side"); + file.WriteObject(&mHist[1], "dEdxTotTPC C side"); + + file.Close(); +} diff --git a/Detectors/TPC/calibration/test/testO2TPCIDCFourierTransform.cxx b/Detectors/TPC/calibration/test/testO2TPCIDCFourierTransform.cxx new file mode 100644 index 0000000000000..31a0545c72e5c --- /dev/null +++ b/Detectors/TPC/calibration/test/testO2TPCIDCFourierTransform.cxx @@ -0,0 +1,137 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file testO2TPCIDCFourierTransform.cxx +/// \brief this task tests the calculation of fourier coefficients by comparing input values with FT->IFT values +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#define BOOST_TEST_MODULE Test TPC O2TPCIDCFourierTransform class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "TPCCalibration/IDCFourierTransform.h" +#include "TRandom.h" +#include <numeric> + +namespace o2::tpc +{ + +static constexpr float ABSTOLERANCE = 0.01f; // absolute tolerance is taken at small values near 0 +static constexpr float TOLERANCE = 0.4f; // difference between original 1D-IDC and 1D-IDC from fourier transform -> inverse fourier transform + +o2::tpc::OneDIDC get1DIDCs(const std::vector<unsigned int>& integrationIntervals) +{ + const unsigned int nIDCs = std::accumulate(integrationIntervals.begin(), integrationIntervals.end(), static_cast<unsigned int>(0)); + o2::tpc::OneDIDC idcsOut; + for (unsigned int iside = 0; iside < 2; ++iside) { + std::vector<float> idcs(nIDCs); + for (auto& val : idcs) { + val = gRandom->Gaus(0, 0.2); + } + idcsOut.mOneDIDC[iside] = std::move(idcs); + } + return idcsOut; +} + +std::vector<unsigned int> getIntegrationIntervalsPerTF(const unsigned int integrationIntervals, const unsigned int tfs) +{ + std::vector<unsigned int> intervals; + intervals.reserve(tfs); + for (unsigned int i = 0; i < tfs; ++i) { + const unsigned int additionalInterval = (i % 3) ? 1 : 0; // in each integration inerval are either 10 or 11 values when having 128 orbits per TF and 12 orbits integration length + intervals.emplace_back(integrationIntervals + additionalInterval); + } + return intervals; +} + +// testing FT of aggregator +BOOST_AUTO_TEST_CASE(IDCFourierTransformAggregator_test) +{ + const unsigned int integrationIntervals = 10; // number of integration intervals for first TF + const unsigned int tfs = 200; // number of aggregated TFs + const unsigned int rangeIDC = 200; // number of IDCs used to calculate the fourier coefficients + const unsigned int nFourierCoeff = rangeIDC + 2; // number of fourier coefficients which will be calculated/stored needs to be the maximum value to be able to perform IFT + using FtType = IDCFourierTransform<IDCFourierTransformBaseAggregator>; + gRandom->SetSeed(0); + + for (int iType = 0; iType < 2; ++iType) { + const bool fft = iType == 0 ? false : true; + FtType::setFFT(fft); + FtType::setNThreads(2); + + FtType idcFourierTransform{rangeIDC, tfs, nFourierCoeff}; + const auto intervalsPerTF = getIntegrationIntervalsPerTF(integrationIntervals, tfs); + idcFourierTransform.setIDCs(get1DIDCs(intervalsPerTF), intervalsPerTF); + idcFourierTransform.setIDCs(get1DIDCs(intervalsPerTF), intervalsPerTF); + idcFourierTransform.calcFourierCoefficients(); + + for (unsigned int iSide = 0; iSide < o2::tpc::SIDES; ++iSide) { + const o2::tpc::Side side = iSide == 0 ? Side::A : Side::C; + const std::vector<unsigned int> offsetIndex = idcFourierTransform.getLastIntervals(side); + const auto idcOneExpanded = idcFourierTransform.getExpandedIDCOne(side); + const auto inverseFourier = idcFourierTransform.inverseFourierTransform(side); + for (unsigned int interval = 0; interval < idcFourierTransform.getNIntervals(); ++interval) { + for (unsigned int index = 0; index < rangeIDC; ++index) { + const float origIDCOne = idcOneExpanded[index + offsetIndex[interval]]; + const float iFTIDCOne = inverseFourier[interval][index]; + if (std::fabs(origIDCOne) < ABSTOLERANCE) { + BOOST_CHECK_SMALL(iFTIDCOne - origIDCOne, ABSTOLERANCE); + } else { + BOOST_CHECK_CLOSE(iFTIDCOne, origIDCOne, TOLERANCE); + } + } + } + } + } +} + +// testing FT of EPN +BOOST_AUTO_TEST_CASE(IDCFourierTransformEPN_test) +{ + const int nIter = 100; // number of iterations + const unsigned int integrationIntervals = 10; // number of integration intervals for first TF + const unsigned int rangeIDC = 200; // number of IDCs used to calculate the fourier coefficients + const unsigned int tfs = rangeIDC / integrationIntervals; // number of aggregated TFs (minimum number of 1D-IDCs obtained by get1DIDCs must be>rangeIDC) + const unsigned int nFourierCoeff = rangeIDC + 2; // number of fourier coefficients which will be calculated/stored needs to be the maximum value to be able to perform IFT + using FtType = o2::tpc::IDCFourierTransform<o2::tpc::IDCFourierTransformBaseEPN>; + gRandom->SetSeed(0); + + for (int iter = 0; iter < nIter; ++iter) { + for (int iType = 0; iType < 2; ++iType) { + const bool fft = iType == 0 ? false : true; + FtType::setFFT(fft); + FtType idcFourierTransform{rangeIDC, nFourierCoeff}; + const auto intervalsPerTF = getIntegrationIntervalsPerTF(integrationIntervals, tfs); + idcFourierTransform.setIDCs(get1DIDCs(intervalsPerTF)); + idcFourierTransform.calcFourierCoefficients(); + for (unsigned int iSide = 0; iSide < o2::tpc::SIDES; ++iSide) { + const o2::tpc::Side side = iSide == 0 ? Side::A : Side::C; + const std::vector<unsigned int> offsetIndex = idcFourierTransform.getLastIntervals(side); + const auto idcOneExpanded = idcFourierTransform.getExpandedIDCOne(side); + const auto inverseFourier = idcFourierTransform.inverseFourierTransform(side); + for (unsigned int interval = 0; interval < idcFourierTransform.getNIntervals(); ++interval) { + for (unsigned int index = 0; index < rangeIDC; ++index) { + const float origIDCOne = idcOneExpanded[index + offsetIndex[interval]]; + const float iFTIDCOne = inverseFourier[interval][index]; + if (std::fabs(origIDCOne) < ABSTOLERANCE) { + BOOST_CHECK_SMALL(iFTIDCOne - origIDCOne, ABSTOLERANCE); + } else { + BOOST_CHECK_CLOSE(iFTIDCOne, origIDCOne, TOLERANCE); + } + } + } + } + } + } +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/calibration/testWorkflow/tpc-dcs-sim-workflow.cxx b/Detectors/TPC/calibration/testWorkflow/tpc-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..8a84ceb365368 --- /dev/null +++ b/Detectors/TPC/calibration/testWorkflow/tpc-dcs-sim-workflow.cxx @@ -0,0 +1,119 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// // we need to add workflow options before including Framework/runDataProcessing +// void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +// { +// // option allowing to set parameters +// } + +// ------------------------------------------------------------------ + +#include <fmt/format.h> + +#include "Framework/ConfigParamSpec.h" + +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"max-sectors", VariantType::Int, 0, {"max sector number to use for HV sensors, 0-17"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + const auto maxSectors = std::min(config.options().get<int>("max-sectors"), 17); + + std::vector<o2::dcs::test::HintType> dphints; + // ===| Gas sensors and gas chromatograph values |============================ + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_ARGON", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_CO2", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_N2", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_NEON", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_O2", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_GC_WATER", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_An_L1Sr141_H2O", 0, 1000.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_An_L1Sr141_O2", 0, 1000.}); + + // ==| Temperature sensors |================================================== + // only the ones inside the TPC + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_351_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_376_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_415_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_447_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_477_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_488_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_537_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_575_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_589_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_629_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_664_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_695_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_735_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_757_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_797_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_831_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_851_TEMPERATURE", 20., 30.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{"TPC_PT_895_TEMPERATURE", 20., 30.}); + + // ===| HV supplies |========================================================= + // + // ---| A-Side voltages |----------------------------------------------------- + // + // ---| bottom electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]B_U", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]B_U", maxSectors), 0, 800.}); + + // ---| top electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]T_U", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]T_U", maxSectors), 0, 800.}); + + // ---| C-Side voltages |----------------------------------------------------- + // ---| bottom electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]B_U", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]B_U", maxSectors), 0, 800.}); + + // ---| top electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]T_U", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]T_U", maxSectors), 0, 800.}); + + // ---| A-Side currents |----------------------------------------------------- + // + // ---| bottom electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]B_I", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]B_I", maxSectors), 0, 800.}); + + // ---| top electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_I_G[1..4]T_I", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_A[00..{:02}]_O[1..3]_G[1..4]T_I", maxSectors), 0, 800.}); + + // ---| C-Side currents |----------------------------------------------------- + // ---| bottom electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]B_I", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]B_I", maxSectors), 0, 800.}); + + // ---| top electrodes |--- + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_I_G[1..4]T_I", maxSectors), 0, 800.}); + dphints.emplace_back(o2::dcs::test::DataPointHint<double>{fmt::format("TPC_HV_C[00..{:02}]_O[1..3]_G[1..4]T_I", maxSectors), 0, 800.}); + + WorkflowSpec specs; + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "TPC")); + return specs; +} diff --git a/Detectors/TPC/monitor/CMakeLists.txt b/Detectors/TPC/monitor/CMakeLists.txt index a124280fa27c3..548ea8485d419 100644 --- a/Detectors/TPC/monitor/CMakeLists.txt +++ b/Detectors/TPC/monitor/CMakeLists.txt @@ -1,19 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TPCMonitor SOURCES src/SimpleEventDisplay.cxx - PUBLIC_LINK_LIBRARIES O2::TPCBase O2::TPCCalibration) + src/SimpleEventDisplayGUI.cxx + PUBLIC_LINK_LIBRARIES ROOT::Gui O2::TPCBase O2::TPCCalibration) o2_target_root_dictionary(TPCMonitor - HEADERS include/TPCMonitor/SimpleEventDisplay.h) + HEADERS include/TPCMonitor/SimpleEventDisplay.h + include/TPCMonitor/SimpleEventDisplayGUI.h) o2_add_executable(monitor COMPONENT_NAME tpc @@ -26,7 +29,3 @@ o2_add_test_root_macro(macro/RunCompareMode3.C o2_add_test_root_macro(macro/RunFindAdcError.C PUBLIC_LINK_LIBRARIES O2::TPCReconstruction LABELS tpc) -o2_add_test_root_macro(macro/RunSimpleEventDisplay.C - PUBLIC_LINK_LIBRARIES O2::TPCMonitor - LABELS tpc - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) diff --git a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h index 54a66f69c0d45..17c03c1db849c 100644 --- a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h +++ b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -61,7 +62,7 @@ class SimpleEventDisplay : public CalibRawBase void setLastSelSector(Int_t lastSelSector) { mLastSelSector = lastSelSector; } void setPedstals(CalPad* pedestals) { mPedestals = pedestals; } - // TH1D* makePadSignals(Int_t roc, Int_t channel); + TH1D* makePadSignals(Int_t roc, Int_t row, Int_t pad); /// set time bin range diff --git a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h new file mode 100644 index 0000000000000..180fc8a9d1741 --- /dev/null +++ b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SimpleEventDisplayGUI.h +/// \brief GUI for raw data event display +/// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#ifndef TPC_SimpleEventDisplayGUI_H_ +#define TPC_SimpleEventDisplayGUI_H_ + +#include <memory> + +#include "TString.h" + +#include "TPCMonitor/SimpleEventDisplay.h" + +class TH2F; +class TH1F; +class TH1; +class TGTextEntry; +class TGTextButton; +class TGCheckButton; + +namespace o2::tpc +{ + +class SimpleEventDisplayGUI +{ + public: + enum RunMode { + Offline = 0, ///< run offline from file + Online = 1, ///< run online from decoded digits + }; + + void toggleFFT(); + void monitorGui(); + void exitRoot(); + void update(TString clist); + void resetHists(int type); + void drawPadSignal(int event, int x, int y, TObject* o); + void fillMaxHists(int type = 0); + void selectSector(int sector); + int FindROCFromXY(const float x, const float y, const int side); + void selectSectorExec(int event, int x, int y, TObject* o); + void initGUI(); + void next(int eventNumber = -1); + void callEventNumber(); + + void runSimpleEventDisplay(std::string_view fileInfo, std::string_view pedestalFile = "", int firstTimeBin = 0, int lastTimeBin = 500, int nTimeBinsPerCall = 500, uint32_t verbosity = 0, uint32_t debugLevel = 0, int selectedSector = 0, bool showSides = 1); + + SimpleEventDisplay& getEventDisplay() { return mEvDisp; } + + void setMode(RunMode mode) { mRunMode = mode; } + + // ===| for online processing |=== + void startGUI(int maxTimeBins = 114048); + bool isStopRequested() const { return mStop; } + bool isProcessingEvent() const { return mProcessingEvent; } + bool isNextEventRequested() const { return mNextEvent; } + bool isWaitingForDigitUpdate() const { return mUpdatingDigits; } + void resetNextEventReqested() { mNextEvent = false; } + void resetUpdatingDigits() { mUpdatingDigits = false; } + void setDataAvailable(bool available) { mDataAvailable = available; } + + private: + SimpleEventDisplay mEvDisp; + + int mOldHooverdSector = -1; + int mSelectedSector = 0; + int mMaxEvents = 100000000; + bool mShowSides = true; + + // ===| for onine processing |=== + bool mNextEvent = false; + bool mProcessingEvent = false; + bool mUpdatingDigits = false; + bool mStop = false; + bool mDataAvailable = false; + RunMode mRunMode; + + TH2F* mHMaxA = nullptr; + TH2F* mHMaxC = nullptr; + TH2F* mHMaxIROC = nullptr; + TH2F* mHMaxOROC = nullptr; + TH1* mHFFTO = nullptr; + TH1* mHFFTI = nullptr; + + TGCheckButton* mCheckFFT = nullptr; + TGTextEntry* mEventNumber = nullptr; + + TH1* getBinInfoXY(int& binx, int& biny, float& bincx, float& bincy); + + ClassDefNV(SimpleEventDisplayGUI, 0); +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/monitor/macro/RunCompareMode3.C b/Detectors/TPC/monitor/macro/RunCompareMode3.C index ff7ae2bc2ab2a..62b221deb06f2 100644 --- a/Detectors/TPC/monitor/macro/RunCompareMode3.C +++ b/Detectors/TPC/monitor/macro/RunCompareMode3.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/monitor/macro/RunFindAdcError.C b/Detectors/TPC/monitor/macro/RunFindAdcError.C index 09c3deb05593e..ad44d72f2ab9c 100644 --- a/Detectors/TPC/monitor/macro/RunFindAdcError.C +++ b/Detectors/TPC/monitor/macro/RunFindAdcError.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/monitor/macro/RunSimpleEventDisplay.C b/Detectors/TPC/monitor/macro/RunSimpleEventDisplay.C deleted file mode 100644 index 7d203bae30596..0000000000000 --- a/Detectors/TPC/monitor/macro/RunSimpleEventDisplay.C +++ /dev/null @@ -1,680 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include "TObjString.h" -#include "TH1F.h" -#include "TH2F.h" -#include "TObjArray.h" -#include "TPaveText.h" -#include "TF1.h" -#include "TStopwatch.h" -#include "TGFrame.h" -#include "TGTextEntry.h" -#include "TGLabel.h" -#include "TFile.h" -#include "TLegend.h" -#include "TSystem.h" -#include "TGButton.h" -#include "TCanvas.h" -#include "TObjArray.h" -#include "TROOT.h" -#include "TH2F.h" -#include "TPRegexp.h" -#include "TMath.h" -#include "TApplication.h" -#include "TPCMonitor/SimpleEventDisplay.h" -#include "TPCBase/Mapper.h" -#include "TPCBase/CalDet.h" -#include "TPCBase/CalArray.h" -#include "FairLogger.h" -#include <iostream> -#include <fstream> -#include <memory> -#endif -using namespace std; -using namespace o2::tpc; -/* -.L RunSimpleEventDisplay.C+ -RunSimpleEventDisplay("GBTx0_Run005:0:0;GBTx1_Run005:1:0") -*/ - -SimpleEventDisplay mEvDisp; -const Mapper& mMapper = Mapper::instance(); - -TObjArray mArrCanvases; -Int_t mOldHooverdSector = -1; -Int_t mSelectedSector = 0; -Int_t mMaxEvents = 100000000; -TH2F* mHMaxA = nullptr; -TH2F* mHMaxC = nullptr; -TH2F* mHMaxIROC = nullptr; -TH2F* mHMaxOROC = nullptr; -TH2F* mHPbVsCkvEle = nullptr; //Pb-glass vs. cherenkov -TH2F* mHPbVsCkvPio = nullptr; //Pb-glass vs. cherenkov -TH1F* mPulseEleMax = nullptr; -TH1F* mPulseEleTot = nullptr; -TH1F* fdEdxEleMax = nullptr; -TH1F* fdEdxEleTot = nullptr; -TH1F* mPulsePioMax = nullptr; -TH1F* mPulsePioTot = nullptr; -TH1F* fdEdxPioMax = nullptr; -TH1F* fdEdxPioTot = nullptr; -TH1F* mHDriftTime = nullptr; -TH1F* mHNcls = nullptr; -TH1* mHFFTO = nullptr; -TH1* mHFFTI = nullptr; -TGCheckButton* mCheckFFT = nullptr; -TGTextEntry* mEventNumber = nullptr; -Bool_t mShowSides = 0; - -Double_t mElePosMax = 0.; -Double_t mElePosTot = 0.; -Double_t mPioPosMax = 0.; -Double_t mPioPosTot = 0.; -Double_t mEleResMax = 0.; -Double_t mEleResTot = 0.; -Double_t mPioResMax = 0.; -Double_t mPioResTot = 0.; - -Int_t mBigEventSize = 8000; - -TObjArray mArrHistCamac(100); //array with histograms for camac data - -void ToggleFFT(); - -//__________________________________________________________________________ -void MonitorGui() -{ - Float_t xsize = 145; - Float_t ysize = 25; - Float_t yoffset = 10; - Float_t ysize_dist = 2; - Float_t mainx = 170; - Float_t mainy = 170; - int ycount = 0; - - TGMainFrame* mFrameMain = new TGMainFrame(gClient->GetRoot(), 200, 200, kMainFrame | kVerticalFrame); - mFrameMain->SetLayoutBroken(kTRUE); - - TGCompositeFrame* mContRight = new TGCompositeFrame(mFrameMain, 155, mainy, kVerticalFrame | kFixedWidth | kFitHeight); - mFrameMain->AddFrame(mContRight, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY | kLHintsExpandX, 3, 5, 3, 3)); - - //--------------------------- - TGTextButton* mFrameNextEvent = new TGTextButton(mContRight, "&Next Event"); - mContRight->AddFrame(mFrameNextEvent, new TGLayoutHints(kLHintsExpandX)); - - mFrameNextEvent->SetCommand("Next(-1)"); - mFrameNextEvent->SetTextColor(200); - mFrameNextEvent->SetToolTipText("Go to next event"); - //mFrameNextEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (UInt_t)ysize); - mFrameNextEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (UInt_t)ysize); - ++ycount; - - //--------------------------- - TGTextButton* mFramePreviousEvent = new TGTextButton(mContRight, "&Previous Event"); - mContRight->AddFrame(mFramePreviousEvent, new TGLayoutHints(kLHintsExpandX)); - - mFramePreviousEvent->SetCommand("Next(-2)"); - mFramePreviousEvent->SetTextColor(200); - mFramePreviousEvent->SetToolTipText("Go to previous event"); - mFramePreviousEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (UInt_t)ysize); - ++ycount; - - //--------------------------- - - //TGCompositeFrame* mContGoToEvent = new TGCompositeFrame(mContRight, 155, ysize, kHorizontalFrame | kFitWidth | kFixedHeight); - //mContRight->AddFrame(mContGoToEvent, new TGLayoutHints(kLHintsExpandX)); - //mContGoToEvent->Move(10, yoffset + ycount * (ysize_dist + ysize)); - - TGTextButton* mGoToEvent = new TGTextButton(mContRight, "&Go to event"); - //mContGoToEvent->AddFrame(mGoToEvent, new TGLayoutHints(kLHintsExpandX)); - mContRight->AddFrame(mGoToEvent, new TGLayoutHints(kLHintsNormal)); - - mGoToEvent->SetTextColor(200); - mGoToEvent->SetToolTipText("Go to event"); - mGoToEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), 0.65 * xsize, (UInt_t)ysize); - mGoToEvent->SetCommand("CallEventNumber()"); - - // - auto* ftbuf = new TGTextBuffer(10); - ftbuf->AddText(0, "0"); - mEventNumber = new TGTextEntry(mContRight, ftbuf); - mContRight->AddFrame(mEventNumber, new TGLayoutHints(kFitHeight)); - mEventNumber->MoveResize(0.7 * xsize, yoffset + ycount * (ysize_dist + ysize), 0.3 * xsize, (UInt_t)ysize); - mEventNumber->SetAlignment(kTextRight); - ++ycount; - - //--------------------------- - //TGTextButton* mFrameRewindEvent = new TGTextButton(mContRight, "Rewind Events" ); - //mContRight->AddFrame(mFrameRewindEvent, new TGLayoutHints(kLHintsExpandX)); - - //mFrameRewindEvent->SetCommand( "RewindEvents()"); - //mFrameRewindEvent->SetTextColor(200); - //mFrameRewindEvent->SetToolTipText("Rewind Events to loop again"); - //mFrameRewindEvent->MoveResize(10, 10+ysize*3, xsize, (UInt_t)ysize); - - mCheckFFT = new TGCheckButton(mContRight, "Show FFT"); - mContRight->AddFrame(mCheckFFT, new TGLayoutHints(kLHintsExpandX)); - - mCheckFFT->SetCommand("ToggleFFT()"); - mCheckFFT->SetTextColor(200); - mCheckFFT->SetToolTipText("Switch on FFT calculation"); - mCheckFFT->MoveResize(10, 10 + ysize * 4, xsize, (UInt_t)ysize); - mCheckFFT->SetDown(1); - ToggleFFT(); - - //--------------------------- - TGTextButton* mFrameExit = new TGTextButton(mContRight, "Exit ROOT"); - mContRight->AddFrame(mFrameExit, new TGLayoutHints(kLHintsExpandX)); - - mFrameExit->SetCommand("ExitRoot()"); - mFrameExit->SetTextColor(200); - mFrameExit->SetToolTipText("Exit the ROOT process"); - mFrameExit->MoveResize(10, 10 + ysize * 5, xsize, (UInt_t)ysize); - - //--------------------------- - mFrameMain->MapSubwindows(); - mFrameMain->MapWindow(); - mFrameMain->SetWindowName("OM"); - mFrameMain->MoveResize(50, 50, (UInt_t)mainx, (UInt_t)mainy); - mFrameMain->Move(4 * 400 + 10, 10); -} - -//__________________________________________________________________________ -void ToggleFFT() -{ - if (mCheckFFT->IsDown()) { - if (gROOT->GetListOfCanvases()->FindObject("SigIFFT")) { - return; - } - //FFT canvas - const Int_t w = 400; - const Int_t h = 400; - new TCanvas("SigIFFT", "SigIFFT", 3 * w, 0 * h, w, h); - new TCanvas("SigOFFT", "SigOFFT", 3 * w, 1 * h, w, h); - } else { - delete gROOT->GetListOfCanvases()->FindObject("SigIFFT"); - delete gROOT->GetListOfCanvases()->FindObject("SigOFFT"); - delete mHFFTI; - delete mHFFTO; - mHFFTI = mHFFTO = nullptr; - } -} - -//__________________________________________________________________________ -void ExitRoot() -{ - gApplication->Terminate(); -} - -//__________________________________________________________________________ -void RewindEvents() -{ - mEvDisp.rewindEvents(); - //if (mRawReader) mRawReader->rewindEvents(); - //printf("RewindEvents: not implemented\n"); -} - -//__________________________________________________________________________ -void Update(TString clist) -{ - TObjArray* arr = clist.Tokenize(";"); - TIter next(arr); - TObject* o; - while ((o = next())) { - TCanvas* c = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(o->GetName()); - if (c) { - c->Modified(); - c->Update(); - } - } -} - -//__________________________________________________________________________ -void ResetHists(Int_t type) -{ - if (!type) { - if (mHMaxA) - mHMaxA->Reset(); - if (mHMaxC) - mHMaxC->Reset(); - } - if (mHMaxIROC) - mHMaxIROC->Reset(); - if (mHMaxOROC) - mHMaxOROC->Reset(); -} - -//__________________________________________________________________________ -TH1* GetBinInfoXY(Int_t& binx, Int_t& biny, Float_t& bincx, Float_t& bincy) -{ - TObject* select = gPad->GetSelected(); - if (!select) - return nullptr; - if (!select->InheritsFrom("TH2")) { - gPad->SetUniqueID(0); - return nullptr; - } - TH1* h = (TH1*)select; - gPad->GetCanvas()->FeedbackMode(kTRUE); - - int px = gPad->GetEventX(); - int py = gPad->GetEventY(); - Float_t xx = gPad->AbsPixeltoX(px); - Float_t x = gPad->PadtoX(xx); - binx = h->GetXaxis()->FindBin(x); - Float_t yy = gPad->AbsPixeltoY(py); - Float_t y = gPad->PadtoX(yy); - biny = h->GetYaxis()->FindBin(y); - bincx = h->GetXaxis()->GetBinCenter(binx); - bincy = h->GetYaxis()->GetBinCenter(biny); - //printf("binx, biny: %d %d\n",binx,biny); - - return h; -} - -//__________________________________________________________________________ -void DrawPadSignal(TString type) -{ - // - // type: name of canvas - // - - // check if an event was alreay loaded - if (!mEvDisp.getNumberOfProcessedEvents()) { - return; - } - - //return if mouse is pressed to allow looking at one pad - Int_t event = gPad->GetEvent(); - if (event != 51) { - return; - } - - Int_t binx, biny; - Float_t bincx, bincy; - TH1* h = GetBinInfoXY(binx, biny, bincx, bincy); - if (!h) { - return; - } - - const Int_t row = Int_t(TMath::Floor(bincx)); - const Int_t cpad = Int_t(TMath::Floor(bincy)); - //find pad and channel - const Int_t roc = h->GetUniqueID(); - if (roc < 0 || roc >= (Int_t)ROC::MaxROC) { - return; - } - - if (row < 0 || row >= (Int_t)mMapper.getNumberOfRowsROC(roc)) { - return; - } - - const int nPads = mMapper.getNumberOfPadsInRowROC(roc, row); - const int pad = cpad + nPads / 2; - //printf("row %d, cpad %d, pad %d, nPads %d\n", row, cpad, pad, nPads); - if (pad < 0 || pad >= (Int_t)nPads) { - return; - } - // Int_t chn = tpcROC->GetRowIndexes(roc)[row]+pad; - //draw requested pad signal - - TH1*& hFFT = (roc < 36) ? mHFFTI : mHFFTO; - - TCanvas* c = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(type); - TCanvas* cFFT = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(Form("%sFFT", type.Data())); - if (c) { - c->Clear(); - c->cd(); - //mRawReader->Reset(); - TH1D* h2 = mEvDisp.makePadSignals(roc, row, pad); - if (h2) { - //h2->GetXaxis()->SetRangeUser(0, mEvDisp.getNumberOfProcessedTimeBins() + 5); - h2->Draw(); - h2->SetStats(0); - - if (cFFT) { - const bool init = (hFFT == nullptr); - const double maxTime = h2->GetNbinsX() * 200.e-6; - hFFT = h2->FFT(hFFT, "MAG M"); - hFFT->SetStats(0); - const auto nbinsx = hFFT->GetNbinsX(); - auto xax = hFFT->GetXaxis(); - xax->SetRange(2, nbinsx / 2); - if (init) { - xax->Set(nbinsx, xax->GetXmin() / maxTime, xax->GetXmax() / maxTime); - hFFT->SetNameTitle(Form("hFFT_%sROC", (roc < 36) ? "I" : "O"), "FFT magnitude;frequency (kHz);amplitude"); - } - hFFT->Scale(2. / (nbinsx - 1)); - cFFT->cd(); - hFFT->Draw(); - } - } - Update(Form("%s;%sFFT", type.Data(), type.Data())); - } - // printf("bin=%03d.%03d(%03d)[%05d], name=%s, ROC=%02d content=%.1f, ev: %d\n",row,pad,cpad,chn,h->GetName(), roc, h->GetBinContent(binx,biny), event); -} - -//__________________________________________________________________________ -void FillMaxHists(Int_t type = 0) -{ - // - // type: 0 fill side and sector, 1: fill sector only - // - Float_t kEpsilon = 0.000000000001; - CalPad* pad = mEvDisp.getCalPadMax(); - TH2F* hSide = nullptr; - TH2F* hROC = nullptr; - ResetHists(type); - const int runNumber = TString(gSystem->Getenv("RUN_NUMBER")).Atoi(); - //const int eventNumber = mEvDisp.getNumberOfProcessedEvents() - 1; - const int eventNumber = mEvDisp.getPresentEventNumber(); - const bool eventComplete = mEvDisp.isPresentEventComplete(); - for (Int_t iROC = 0; iROC < 72; iROC++) { - // TODO: remove again at some point - //if (iROC % 36 != 0) { - //continue; - //} - hROC = mHMaxOROC; - hSide = mHMaxC; - if (iROC < 36) - hROC = mHMaxIROC; - if (iROC % 36 < 18) - hSide = mHMaxA; - if (iROC % 36 == mSelectedSector % 36) { - TString title = Form("Max Values %cROC %c%02d (%02d) Event %s%d%s", (iROC < 36) ? 'I' : 'O', (iROC % 36 < 18) ? 'A' : 'C', iROC % 18, iROC, eventComplete ? "" : "(", eventNumber, eventComplete ? "" : ")"); - //TString title = Form("Max Values Run %d Event %d", runNumber, eventNumber); - if (hROC) { - hROC->SetTitle(title.Data()); - } - } - auto& calRoc = pad->getCalArray(iROC); - const int nRows = mMapper.getNumberOfRowsROC(iROC); - for (Int_t irow = 0; irow < nRows; irow++) { - const int nPads = mMapper.getNumberOfPadsInRowROC(iROC, irow); - for (Int_t ipad = 0; ipad < nPads; ipad++) { - Float_t value = calRoc.getValue(irow, ipad); - //printf("iROC: %02d, sel: %02d, row %02d, pad: %02d, value: %.5f\n", iROC, mSelectedSector, irow, ipad, value); - if (TMath::Abs(value) > kEpsilon) { - if (!type && hSide) { - const GlobalPosition2D global2D = mMapper.getPadCentre(PadSecPos(Sector(iROC % 36), PadPos(irow + (iROC >= 36) * mMapper.getNumberOfRowsROC(0), ipad))); - Int_t binx = 1 + TMath::Nint((global2D.X() + 250.) * hSide->GetNbinsX() / 500.); - Int_t biny = 1 + TMath::Nint((global2D.Y() + 250.) * hSide->GetNbinsY() / 500.); - hSide->SetBinContent(binx, biny, value); - } - const int nPads = mMapper.getNumberOfPadsInRowROC(iROC, irow); - const Int_t cpad = ipad - nPads / 2; - if ((iROC % 36 == mSelectedSector % 36) && hROC) { - //printf(" ->>> Fill: iROC: %02d, sel: %02d, row %02d, pad: %02d, value: %.5f\n", iROC, mSelectedSector, irow, ipad, value); - hROC->Fill(irow, cpad, value); - } - } - if ((iROC % 36 == mSelectedSector % 36) && hROC) { - hROC->SetUniqueID(iROC); - } - } - } - } - if (!type) { - Update("MaxValsA;MaxValsC"); - } - - Update("MaxValsI;MaxValsO"); -} - -//__________________________________________________________________________ -void FillMaxHistsSide() -{ -} - -//__________________________________________________________________________ -void FillMaxHistsSector() -{ -} - -//__________________________________________________________________________ -void SelectSector(Int_t sector) -{ - mSelectedSector = sector % 36; - mEvDisp.setSelectedSector(mSelectedSector); - FillMaxHists(1); -} - -//__________________________________________________________________________ -Int_t FindROCFromXY(const Float_t x, const Float_t y, const Int_t side) -{ - // - // - // - - Float_t r = TMath::Sqrt(x * x + y * y); - static const float innerWall = mMapper.getPadCentre(PadPos(0, 0)).X() - 5.; - static const float outerWall = mMapper.getPadCentre(PadPos(151, 0)).X() + 5.; - static const float outerIROC = mMapper.getPadCentre(PadPos(62, 0)).X(); - static const float innerOROC = mMapper.getPadCentre(PadPos(63, 0)).X(); - static const float betweenROC = (outerIROC + innerOROC) / 2.; - //check radial boundary - if (r < innerWall || r > outerWall) - return -1; - //check for IROC or OROC - Int_t type = 0; - if (r > betweenROC) - type = 1; - Int_t alpha = TMath::Nint(TMath::ATan2(y, x) / TMath::Pi() * 180); - // printf("%6.3f %6.3f %03d\n",x, y, alpha); - if (alpha < 0) - alpha += 360; - Int_t roc = alpha / 20 + side * 18 + type * 36; - return roc; -} - -//__________________________________________________________________________ -void SelectSectorExec() -{ - - Int_t binx, biny; - Float_t bincx, bincy; - TH1* h = GetBinInfoXY(binx, biny, bincx, bincy); - if (!h) - return; - Int_t side = h->GetUniqueID(); - Int_t roc = FindROCFromXY(bincx, bincy, side); - if (roc < 0) - return; - Int_t sector = roc % 36; - h->SetTitle(Form("Max Values %c%02d", (sector < 18) ? 'A' : 'C', sector % 18)); - if (sector != mOldHooverdSector) { - gPad->Modified(); - gPad->Update(); - mOldHooverdSector = sector; - } - int event = gPad->GetEvent(); - if (event != 11) { - return; - } - // printf("SelectSector: %d.%02d.%d = %02d\n",side,sector,roc<36,roc); - SelectSector(sector); -} - -//__________________________________________________________________________ -void InitGUI() -{ - Int_t w = 400; - Int_t h = 400; - TCanvas* c = nullptr; - - if (mShowSides) { - //histograms and canvases for max values A-Side - c = new TCanvas("MaxValsA", "MaxValsA", 0 * w, 0 * h, w, h); - c->AddExec("findSec", "SelectSectorExec()"); - mHMaxA = new TH2F("hMaxValsA", "Max Values Side A;x [cm];y [cm]", 330, -250, 250, 330, -250, 250); - mHMaxA->SetStats(kFALSE); - mHMaxA->SetUniqueID(0); //A-Side - mHMaxA->Draw("colz"); - //histograms and canvases for max values C-Side - c = new TCanvas("MaxValsC", "MaxValsC", 0 * w, 1 * h, w, h); - c->AddExec("findSec", "SelectSectorExec()"); - mHMaxC = new TH2F("hMaxValsC", "Max Values Side C;x [cm];y [cm]", 330, -250, 250, 330, -250, 250); - mHMaxC->SetStats(kFALSE); - mHMaxC->SetUniqueID(1); //C-Side - mHMaxC->Draw("colz"); - } - - //histograms and canvases for max values IROC - c = new TCanvas("MaxValsI", "MaxValsI", 1 * w, 0 * h, w, h); - c->AddExec("padSig", "DrawPadSignal(\"SigI\")"); - mHMaxIROC = new TH2F("hMaxValsIROC", "Max Values IROC;row;pad", 63, 0, 63, 108, -54, 54); - mHMaxIROC->SetDirectory(nullptr); - mHMaxIROC->SetStats(kFALSE); - mHMaxIROC->Draw("colz"); - - //histograms and canvases for max values OROC - c = new TCanvas("MaxValsO", "MaxValsO", 1 * w, 1 * h, w, h); - c->AddExec("padSig", "DrawPadSignal(\"SigO\")"); - mHMaxOROC = new TH2F("hMaxValsOROC", "Max Values OROC;row;pad", 89, 0, 89, 140, -70, 70); - mHMaxOROC->SetDirectory(nullptr); - mHMaxOROC->SetStats(kFALSE); - mHMaxOROC->Draw("colz"); - - //canvases for pad signals - new TCanvas("SigI", "SigI", 2 * w, 0 * h, w, h); - new TCanvas("SigO", "SigO", 2 * w, 1 * h, w, h); -} - -//__________________________________________________________________________ -void Next(int eventNumber = -1) -{ - printf("Calling event number %d\n", eventNumber); - //Int_t ev=mRawReader->NextEvent(); - //if (!ev) return; - using Status = CalibRawBase::ProcessStatus; - Status status = mEvDisp.processEvent(eventNumber); - //const Int_t timeBins = mEvDisp.getTimeBinsPerCall(); - const Int_t timeBins = mEvDisp.getNumberOfProcessedTimeBins(); - - const int presentEventNumber = mEvDisp.getPresentEventNumber(); - mEventNumber->SetText(Form("%d", presentEventNumber)); - - switch (status) { - case Status::Ok: { - std::cout << "Read in full event with " << timeBins << " time bins\n"; - break; - } - case Status::Truncated: { - std::cout << "Event is truncated and contains less than " << timeBins << " time bins\n"; - break; - } - case Status::NoMoreData: { - std::cout << "No more data to be read\n"; - return; - break; - } - case Status::NoReaders: { - std::cout << "No raw readers configured\n"; - return; - break; - } - default: - // Do nothing for non-listed values of Status enum - break; - } - //Bool_t res=mEvDisp.processEvent(); - //printf("Next: %d, %d (%d - %d), %d\n",res, ((AliRawReaderGEMDate*)mRawReader)->mEventInFile,((AliRawReaderGEMDate*)mRawReader)->GetCamacData(0),mRawReader->GetEventFromTag(), mRawReader->GetDataSize()); - //printf("Next Event: %d\n",mRawReader->GetEventFromTag()); - printf("Next Event\n"); - FillMaxHists(); -} - -//__________________________________________________________________________ -void CallEventNumber() -{ - const int event = TString(mEventNumber->GetText()).Atoi(); - Next(event); -} - -//__________________________________________________________________________ -void RunSimpleEventDisplay(TString fileInfo, TString pedestalFile = "", Int_t firstTimeBin = 0, Int_t lastTimeBin = 500, Int_t nTimeBinsPerCall = 500, uint32_t verbosity = 0, uint32_t debugLevel = 0, int selectedSector = 0, bool showSides = 0) -{ - FairLogger* logger = FairLogger::GetLogger(); - logger->SetLogVerbosityLevel("LOW"); - logger->SetLogScreenLevel("DEBUG"); - if (!pedestalFile.IsNull()) { - TFile f(pedestalFile); - if (f.IsOpen()) { - CalDet<float>* pedestal = nullptr; - f.GetObject("Pedestals", pedestal); - mEvDisp.setPedstals(pedestal); - } - } - - mSelectedSector = selectedSector; - mShowSides = showSides; - - mEvDisp.setupContainers(fileInfo, verbosity, debugLevel); - mEvDisp.setSkipIncompleteEvents(false); // in case of the online monitor do not skip incomplete events - mEvDisp.setSelectedSector(mSelectedSector); - mEvDisp.setLastSelSector(mSelectedSector); - mEvDisp.setTimeBinsPerCall(nTimeBinsPerCall); - mEvDisp.setTimeBinRange(firstTimeBin, lastTimeBin); - - InitGUI(); - // while (mRawReader->NextEvent() && mRawReader->GetEventFromTag()==0) Next(); - MonitorGui(); - //SelectSector(selectedSector); - // select first event - Next(0); -} - -//__________________________________________________________________________ -void GetBinMinMax(const TH1* hist, const Float_t frac, Int_t& bin1, Int_t& bin2) -{ - - const Int_t binMax = hist->GetMaximumBin(); - const Double_t contMax = hist->GetBinContent(binMax); - bin1 = binMax; - bin2 = binMax; - while ((bin1--) > binMax / 3.) - if (hist->GetBinContent(bin1) < frac * contMax) - break; - while ((bin2++) < binMax * 3.) - if (hist->GetBinContent(bin2) < frac * contMax) - break; -} - -//__________________________________________________________________________ -void FitGaus(TH1* histEle, TH1* histPio, TPaveText* text, Double_t& posEle, Double_t& resEle, Double_t& posPio, Double_t& resPio) -{ - // - // fit gaus to histograms and add text to the pave - // - TF1* mEle = new TF1("gEle", "gaus", histEle->GetXaxis()->GetXmin(), histEle->GetXaxis()->GetXmax()); - TF1* mPio = new TF1("gPio", "gaus", histPio->GetXaxis()->GetXmin(), histPio->GetXaxis()->GetXmax()); - mEle->SetLineColor(histEle->GetLineColor()); - mPio->SetLineColor(histPio->GetLineColor()); - mEle->SetLineWidth(2); - mPio->SetLineWidth(2); - const Float_t frac = 0.1; - Int_t bin1 = 0, bin2 = 0; - - GetBinMinMax(histEle, frac, bin1, bin2); - histEle->Fit(mEle, "", "Q0", histEle->GetXaxis()->GetBinLowEdge(bin1), histEle->GetXaxis()->GetBinUpEdge(bin2)); - - GetBinMinMax(histPio, frac, bin1, bin2); - histPio->Fit(mPio, "", "Q0", histPio->GetXaxis()->GetBinLowEdge(bin1), histPio->GetXaxis()->GetBinUpEdge(bin2)); - - posEle = mEle->GetParameter(1); - resEle = mEle->GetParameter(2); - posPio = mPio->GetParameter(1); - resPio = mPio->GetParameter(2); - text->AddText(Form("e: %.2f #pm %.2f (%.2f%%)", posEle, resEle, resEle / posEle * 100)); - text->AddText(Form("#pi: %.2f #pm %.2f (%.2f%%)", posPio, resPio, resPio / posPio * 100)); - text->AddText(Form("Separation: %.2f#sigma", TMath::Abs(posEle - posPio) / ((resEle + resPio) / 2.))); -} diff --git a/Detectors/TPC/monitor/macro/startMonitor b/Detectors/TPC/monitor/macro/startMonitor index a9adecda17365..c951141a7b24c 100755 --- a/Detectors/TPC/monitor/macro/startMonitor +++ b/Detectors/TPC/monitor/macro/startMonitor @@ -1,91 +1,6 @@ #!/bin/bash -usage() { - echo "Usage:" - echo "runPedestal <required arguments> [optional arguments]" - echo - echo - echo "required arguments" - echo " -i, --fileInfo= : wildcard of input files in single quotes." - echo " Can obtain the number of time bins separated by a ':'" - echo " e.g. 'cru*.raw:1000' for 1000 time bins" - echo " the time bin option after the ':' overwrites the --timeBins option" - echo - echo "optional arguments:" - echo " -p, --pedestalFile= : pedestal file" - echo " -f, --fistTimeBin= : first time bin for pulser search" - echo " -l, --lastTimeBin= : last time bin for pulser search" - echo " -t, --timeBins= : number of time bins to process (default: $timeBins)" - echo " -v, --verbosity= : set verbosity level" - echo " -d, --debugLevel= : set debug level" - echo " -s, --sector= : select specific sector (default 0)" - echo " -o, --overview : show readout side overview" - echo " -h, --help : show this help message" -} - -usageAndExit() { - usage - if [[ "$0" =~ startMonitor ]]; then - exit 0 - else - return 0 - fi -} - -# ===| default variable values |================================================ -fileInfo= -pedestalFile= -firstTimeBin=0 -lastTimeBin=512 -timeBins=512 -verbosity=0 -debugLevel=0 -selectedSector=0 -showOverview=0 -tool="" - -# ===| parse command line options |============================================= -OPTIONS=$(getopt -l "fileInfo:,pedestalFile:,firstTimeBin:,lastTimeBin:,timeBins:,verbosity:,debugLevel:,sector:,overview,valgrind,callgrind,help" -o "i:p:f:l:t:v:d:s:oh" -n "startMonitor" -- "$@") - -if [ $? != 0 ] ; then - usageAndExit -fi - -eval set -- "$OPTIONS" - -while true; do - case "$1" in - --) shift; break;; - -i|--fileInfo) fileInfo=$2; shift 2;; - -p|--pedestalFile) pedestalFile=$2; shift 2;; - -f|--firstTimeBin) firstTimeBin=$2; shift 2;; - -l|--lastTimeBin) lastTimeBin=$2; shift 2;; - -t|--timeBins) timeBins=$2; shift 2;; - -v|--verbosity) verbosity=$2; shift 2;; - -d|--debugLevel) debugLevel=$2; shift 2;; - -s|--sector) selectedSector=$2; shift 2;; - -o|--overview) showOverview=1; shift;; - --valgrind) tool="valgrind --log-file=valgrind.log"; shift;; - --callgrind) tool="valgrind --tool=callgrind"; shift;; - -h|--help) usageAndExit;; - *) echo "Internal error!" ; exit 1 ;; - esac -done - -# ===| check for required arguments |=========================================== -if [[ -z "$fileInfo" ]]; then - usageAndExit -fi - -# ===| check time bin info |==================================================== -if [[ $fileInfo =~ : ]]; then - timeBins=${fileInfo#*:} - timeBins=${timeBins%%:*} -else - fileInfo=${fileInfo}:${timeBins} -fi - # ===| command building and execution |========================================= -cmd="$tool root.exe -l $O2_SRC/Detectors/TPC/reconstruction/macro/addInclude.C $O2_SRC/Detectors/TPC/monitor/macro/RunSimpleEventDisplay.C+g'(\"$fileInfo\", \"$pedestalFile\", $firstTimeBin, $lastTimeBin, $timeBins, $verbosity, $debugLevel, $selectedSector, $showOverview)'" +cmd="o2-tpc-monitor $@" echo "running: $cmd" eval $cmd diff --git a/Detectors/TPC/monitor/run/runMonitor.cxx b/Detectors/TPC/monitor/run/runMonitor.cxx index 7e92a8bae2a6f..76c538ccfe1f4 100644 --- a/Detectors/TPC/monitor/run/runMonitor.cxx +++ b/Detectors/TPC/monitor/run/runMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,16 +17,39 @@ #include <boost/program_options.hpp> #include <iostream> -namespace bpo = boost::program_options; +#include "TApplication.h" + +#include "TPCMonitor/SimpleEventDisplayGUI.h" + +namespace po = boost::program_options; int main(int argc, char* argv[]) { // Arguments parsing - bpo::variables_map vm; - bpo::options_description desc("Allowed options"); - desc.add_options()("help,h", "Produce help message.")("file,f", "input file(s)"); - bpo::store(parse_command_line(argc, argv, desc), vm); - bpo::notify(vm); + std::string file; + std::string pedestalFile; + int lastTimeBin{512}; + int firstTimeBin{0}; + int verbosity{0}; + int debugLevel{0}; + int sector{0}; + bool overview{true}; + + po::variables_map vm; + po::options_description desc("Allowed options"); + desc.add_options() // + ("fileInfo,i", po::value<std::string>(&file)->required(), "input file(s)") // + ("pedestalFile,p", po::value<std::string>(&pedestalFile), "pedestal file") // + ("firstTimeBin,f", po::value<int>(&firstTimeBin)->default_value(0), "first time bin to process") // + ("lastTimeBin,l", po::value<int>(&lastTimeBin)->default_value(512), "last time bin to process") // + ("verbosity,v", po::value<int>(&verbosity)->default_value(0), "verbosity level") // + ("debugLevel,d", po::value<int>(&debugLevel)->default_value(0), "debug level") // + ("sector,s", po::value<int>(§or)->default_value(0), "sector to be shown on startup") // + ("overview,o", po::value<bool>(&overview)->default_value(true), "show sides overview") // + ("help,h", "Produce help message.") // + ; // + + po::store(parse_command_line(argc, argv, desc), vm); // help if (vm.count("help")) { @@ -33,8 +57,7 @@ int main(int argc, char* argv[]) return EXIT_SUCCESS; } - // Actual "work" - const std::string file = vm["file"].as<std::string>(); + po::notify(vm); std::cout << "####" << '\n'; std::cout << "#### Starting TPC simple online monitor" << '\n'; @@ -43,5 +66,12 @@ int main(int argc, char* argv[]) std::cout << '\n' << '\n'; + TApplication rootApp("TPC Event Monitor", &argc, argv); + + o2::tpc::SimpleEventDisplayGUI g; + g.runSimpleEventDisplay(file + ":" + std::to_string(lastTimeBin), pedestalFile, firstTimeBin, lastTimeBin, lastTimeBin, verbosity, debugLevel, sector, overview); + + rootApp.Run(true); + return EXIT_SUCCESS; } diff --git a/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx b/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx index bd85cb9bb057c..315d490579ff9 100644 --- a/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx +++ b/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,10 +47,6 @@ SimpleEventDisplay::SimpleEventDisplay() mLastTimeBin(512), mTPCmapper(Mapper::instance()) { - // - // - // - initHistograms(); } @@ -62,16 +59,8 @@ void SimpleEventDisplay::initHistograms() const int nPadsOROC = mTPCmapper.getPadsInOROC(); const int numberOfTimeBins = mLastTimeBin - mFirstTimeBin; - //Int_t binsIROC[3] = { 36, nPadsIROC, numberOfTimeBins }; - //Double_t xminIROC[3] = { 0., 0, Double_t(mFirstTimeBin) }; - //Double_t xmaxIROC[3] = { 36., Double_t(nPadsIROC), Double_t(mLastTimeBin) }; - //Int_t binsOROC[3] = { 36, nPadsOROC, 1000 }; - //Double_t xminOROC[3] = { 0., 0., Double_t(mFirstTimeBin) }; - //Double_t xmaxOROC[3] = { 36., Double_t(nPadsOROC), Double_t(mLastTimeBin) }; - mHSigIROC = new TH2D("PadSigIROC", "Pad Signals IROC", numberOfTimeBins, mFirstTimeBin, mLastTimeBin, nPadsIROC, 0, nPadsIROC); mHSigOROC = new TH2D("PadSigOROC", "Pad Signals OROC", numberOfTimeBins, mFirstTimeBin, mLastTimeBin, nPadsOROC, 0, nPadsOROC); - //printf("Selected ini: %d %p\n",0, mPadMax.GetCalROC(0)); } //_____________________________________________________________________ @@ -116,7 +105,6 @@ Int_t SimpleEventDisplay::updateROC(const Int_t roc, } const int iChannel = mTPCmapper.getPadNumberInROC(PadROCPos(roc, row, pad)); - //Int_t iChannel = mTPCmapper.globalPadNumber(PadPos(row, pad)) - (roc >= mTPCmapper.getNumberOfIROCs()) * mTPCmapper.getPadsInIROC(); //init first pad and roc in this event if (mCurrentChannel == -1) { @@ -128,7 +116,6 @@ Int_t SimpleEventDisplay::updateROC(const Int_t roc, //process last pad if we change to a new one if (iChannel != mCurrentChannel) { - //ProcessPad(); mLastSector = mCurrentROC; mCurrentChannel = iChannel; mCurrentROC = roc; @@ -136,7 +123,7 @@ Int_t SimpleEventDisplay::updateROC(const Int_t roc, mCurrentPad = pad; mMaxPadSignal = 0; } - // if (signal>0) printf("%02d:%03d:%03d:%05d: %.3f\n",mCurrentROC,mCurrentRow,mCurrentPad,mCurrentChannel,signal); + //fill signals for current pad if (mCurrentROC % 36 == mSelectedSector % 36) { const Int_t nbins = mLastTimeBin - mFirstTimeBin; @@ -150,31 +137,19 @@ Int_t SimpleEventDisplay::updateROC(const Int_t roc, } CalROC& calROC = mPadMax.getCalArray(mCurrentROC); - //auto val = calROC.getValue(mCurrentRow, mCurrentPad); auto val = calROC.getValue(row, pad); if (corrSignal > val) { - //printf("sec: %2d, row: %2d, pad: %3d, val: %.2f, sig: (%.2f) %.2f\n", mCurrentROC, mCurrentRow, mCurrentPad, val, corrSignal, signal); - //calROC.setValue(mCurrentRow,mCurrentPad,signal); calROC.setValue(row, pad, corrSignal); mMaxPadSignal = corrSignal; mMaxTimeBin = timeBin; } - //printf("update done\n"); return 0; } //_____________________________________________________________________ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) { - // TODO: check - //if (roc<0||roc>=(Int_t)mROC->GetNSectors()) return nullptr; - //if (row<0||row>=(Int_t)mROC->GetNRows(roc)) return nullptr; - //if (pad<0||pad>=(Int_t)mROC->GetNPads(roc,row)) return nullptr; - // TODO: possible bug for OROC - //const Int_t channel = - //mTPCmapper.globalPadNumber(PadPos(row, pad)) - (roc >= mTPCmapper.getNumberOfIROCs()) * mTPCmapper.getPadsInIROC(); - const int padOffset = (roc > 35) * Mapper::getPadsInIROC(); const int channel = mTPCmapper.getPadNumberInROC(PadROCPos(roc, row, pad)); @@ -189,7 +164,7 @@ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) const int globalLinkID = (fecInPartition % fecOffset) + dataWrapperID * 12; mSelectedSector = roc; - // mLastSelSector=roc; + //attention change for if event has changed if (mSelectedSector % 36 != mLastSelSector % 36) { mSectorLoop = kTRUE; @@ -227,14 +202,7 @@ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) title += (roc / 18 % 2 == 0) ? "A" : "C"; title += Form("%02d (%02d) row: %02d, pad: %03d, globalpad: %05d (in roc)}}}{#scale[.5]{FEC: %02d (%02d), Chip: %02d, Chn: %02d, CRU: %d, Link: %02d (%s%d)}}", roc % 18, roc, row, pad, channel, fecInfo.getIndex(), fecInPartition, fecInfo.getSampaChip(), fecInfo.getSampaChannel(), cruNumber % CRU::CRUperSector, globalLinkID, dataWrapperID ? "B" : "A", globalLinkID % 12); - //title+=Form("row: %02d, pad: %03d, cpad: %03d, globalpad: %05d}}}{#scale[.5]{br: %d, FEC: %02d, Chip: %02d, Chn: %02d = HW: %d}}", - //row,pad,pad-mROC->GetNPads(roc,row)/2,channel, - //mTPCmapper.GetBranch(roc,row,pad), - //mTPCmapper.GetFEChw(roc,row,pad), - //mTPCmapper.GetChip(roc,row,pad), - //mTPCmapper.GetChannel(roc,row,pad), - //mTPCmapper.GetHWAddress(roc,row,pad) - //); + h->SetTitle(title.Data()); Int_t entries = 0; for (Int_t i = 0; i < nbins; i++) { @@ -250,9 +218,6 @@ void SimpleEventDisplay::resetEvent() // // // - //for (auto reader : mGBTFrameContainers) { - //reader->reProcessAllFrames(); - //} if (!mSectorLoop) { mPadMax.multiply(0.); } diff --git a/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx new file mode 100644 index 0000000000000..50955148f7801 --- /dev/null +++ b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx @@ -0,0 +1,648 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <fmt/format.h> +#include <iostream> +#include <fstream> +#include <memory> +#include <unistd.h> + +#include "TGFrame.h" +#include "TGTextEntry.h" +#include "TGLabel.h" +#include "TGButton.h" +#include "TQObject.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TFile.h" +#include "TSystem.h" +#include "TCanvas.h" +#include "TObjArray.h" +#include "TROOT.h" +#include "TMath.h" +#include "TApplication.h" + +#include "FairLogger.h" + +#include "TPCBase/Mapper.h" +#include "TPCBase/CalDet.h" +#include "TPCBase/CalArray.h" +#include "TPCBase/Painter.h" + +#include "TPCMonitor/SimpleEventDisplayGUI.h" + +using namespace o2::tpc; + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::monitorGui() +{ + float xsize = 145; + float ysize = 25; + float yoffset = 10; + float ysize_dist = 2; + float mainx = 170; + float mainy = 170; + int ycount = 0; + + TGMainFrame* mFrameMain = new TGMainFrame(gClient->GetRoot(), 200, 200, kMainFrame | kVerticalFrame); + mFrameMain->SetLayoutBroken(kTRUE); + mFrameMain->SetCleanup(kDeepCleanup); + + TGCompositeFrame* mContRight = new TGCompositeFrame(mFrameMain, 155, mainy, kVerticalFrame | kFixedWidth | kFitHeight); + mFrameMain->AddFrame(mContRight, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY | kLHintsExpandX, 3, 5, 3, 3)); + + //--------------------------- + TGTextButton* mFrameNextEvent = new TGTextButton(mContRight, "&Next Event"); + mContRight->AddFrame(mFrameNextEvent, new TGLayoutHints(kLHintsExpandX)); + + mFrameNextEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "next(=-1)"); + mFrameNextEvent->SetTextColor(200); + mFrameNextEvent->SetToolTipText("Go to next event"); + mFrameNextEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (unsigned int)ysize); + ++ycount; + + //--------------------------- + TGTextButton* mFramePreviousEvent = new TGTextButton(mContRight, "&Previous Event"); + mContRight->AddFrame(mFramePreviousEvent, new TGLayoutHints(kLHintsExpandX)); + if (mRunMode == RunMode::Online) { + mFramePreviousEvent->SetState(kButtonDisabled); + } + + mFramePreviousEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "next(=-2)"); + mFramePreviousEvent->SetTextColor(200); + mFramePreviousEvent->SetToolTipText("Go to previous event"); + mFramePreviousEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (unsigned int)ysize); + ++ycount; + + //--------------------------- + + TGTextButton* mGoToEvent = new TGTextButton(mContRight, "&Go to event"); + mContRight->AddFrame(mGoToEvent, new TGLayoutHints(kLHintsNormal)); + + mGoToEvent->SetTextColor(200); + mGoToEvent->SetToolTipText("Go to event"); + mGoToEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), 0.65 * xsize, (unsigned int)ysize); + mGoToEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "callEventNumber()"); + + // + auto* ftbuf = new TGTextBuffer(10); + ftbuf->AddText(0, "0"); + mEventNumber = new TGTextEntry(mContRight, ftbuf); + mContRight->AddFrame(mEventNumber, new TGLayoutHints(kFitHeight)); + mEventNumber->MoveResize(0.7 * xsize, yoffset + ycount * (ysize_dist + ysize), 0.3 * xsize, (unsigned int)ysize); + mEventNumber->SetAlignment(kTextRight); + ++ycount; + + mCheckFFT = new TGCheckButton(mContRight, "Show FFT"); + mContRight->AddFrame(mCheckFFT, new TGLayoutHints(kLHintsExpandX)); + + mCheckFFT->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "toggleFFT()"); + mCheckFFT->SetTextColor(200); + mCheckFFT->SetToolTipText("Switch on FFT calculation"); + mCheckFFT->MoveResize(10, 10 + ysize * 4, xsize, (unsigned int)ysize); + mCheckFFT->SetDown(0); + toggleFFT(); + + //--------------------------- + TGTextButton* mFrameExit = new TGTextButton(mContRight, "Exit ROOT"); + mContRight->AddFrame(mFrameExit, new TGLayoutHints(kLHintsExpandX)); + + mFrameExit->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "exitRoot()"); + mFrameExit->SetTextColor(200); + mFrameExit->SetToolTipText("Exit the ROOT process"); + mFrameExit->MoveResize(10, 10 + ysize * 5, xsize, (unsigned int)ysize); + + //--------------------------- + mFrameMain->MapSubwindows(); + mFrameMain->MapWindow(); + mFrameMain->SetWindowName("OM"); + mFrameMain->MoveResize(50, 50, (unsigned int)mainx, (unsigned int)mainy); + mFrameMain->Move(4 * 400 + 10, 10); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::toggleFFT() +{ + if (mCheckFFT->IsDown()) { + if (gROOT->GetListOfCanvases()->FindObject("SigIFFT")) { + return; + } + //FFT canvas + const int w = 400; + const int h = 400; + const int hOff = 60; + const int vOff = 2; + new TCanvas("SigIFFT", "SigIFFT", -3 * (w + vOff), 0 * h, w, h); + new TCanvas("SigOFFT", "SigOFFT", -3 * (w + vOff), 1 * h + hOff, w, h); + } else { + delete gROOT->GetListOfCanvases()->FindObject("SigIFFT"); + delete gROOT->GetListOfCanvases()->FindObject("SigOFFT"); + delete mHFFTI; + delete mHFFTO; + mHFFTI = mHFFTO = nullptr; + } +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::exitRoot() +{ + mStop = true; + gApplication->Terminate(); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::update(TString clist) +{ + std::unique_ptr<TObjArray> arr(clist.Tokenize(";")); + for (auto o : *arr) { + auto c = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(o->GetName()); + if (c) { + c->Modified(); + c->Update(); + } + } +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::resetHists(int type) +{ + if (!type) { + if (mHMaxA) { + mHMaxA->Reset(); + } + if (mHMaxC) { + mHMaxC->Reset(); + } + } + if (mHMaxIROC) { + mHMaxIROC->Reset(); + } + if (mHMaxOROC) { + mHMaxOROC->Reset(); + } +} + +//__________________________________________________________________________ +TH1* SimpleEventDisplayGUI::getBinInfoXY(int& binx, int& biny, float& bincx, float& bincy) +{ + auto pad = (TPad*)gTQSender; + TObject* select = pad->GetSelected(); + + if (!select) { + return nullptr; + } + + if (!select->InheritsFrom("TH2")) { + pad->SetUniqueID(0); + return nullptr; + } + + TH1* h = (TH1*)select; + pad->GetCanvas()->FeedbackMode(kTRUE); + + const int px = pad->GetEventX(); + const int py = pad->GetEventY(); + const float xx = pad->AbsPixeltoX(px); + const float x = pad->PadtoX(xx); + const float yy = pad->AbsPixeltoY(py); + const float y = pad->PadtoX(yy); + + binx = h->GetXaxis()->FindBin(x); + biny = h->GetYaxis()->FindBin(y); + bincx = h->GetXaxis()->GetBinCenter(binx); + bincy = h->GetYaxis()->GetBinCenter(biny); + + return h; +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::drawPadSignal(int event, int x, int y, TObject* o) +{ + // + // type: name of canvas + // + + if (!o) { + return; + } + + TString type; + if (std::string_view(o->GetName()) == "hMaxValsIROC") { + type = "SigI"; + } else if (std::string_view(o->GetName()) == "hMaxValsOROC") { + type = "SigO"; + } else { + return; + } + // check if an event was alreay loaded + if (!mEvDisp.getNumberOfProcessedEvents()) { + return; + } + + //return if mouse is pressed to allow looking at one pad + if (event != 51) { + return; + } + + int binx, biny; + float bincx, bincy; + TH1* h = getBinInfoXY(binx, biny, bincx, bincy); + if (!h) { + return; + } + + const int row = int(TMath::Floor(bincx)); + const int cpad = int(TMath::Floor(bincy)); + //find pad and channel + const int roc = h->GetUniqueID(); + if (roc < 0 || roc >= (int)ROC::MaxROC) { + return; + } + + const auto& mapper = Mapper::instance(); + if (row < 0 || row >= (int)mapper.getNumberOfRowsROC(roc)) { + return; + } + + const int nPads = mapper.getNumberOfPadsInRowROC(roc, row); + const int pad = cpad + nPads / 2; + if (pad < 0 || pad >= (int)nPads) { + return; + } + + //draw requested pad signal + + TH1*& hFFT = (roc < 36) ? mHFFTI : mHFFTO; + + TCanvas* c = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(type); + TCanvas* cFFT = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(Form("%sFFT", type.Data())); + if (c) { + c->Clear(); + c->cd(); + TH1D* h2 = mEvDisp.makePadSignals(roc, row, pad); + if (h2) { + h2->Draw(); + h2->SetStats(0); + + if (cFFT) { + const bool init = (hFFT == nullptr); + const double maxTime = h2->GetNbinsX() * 200.e-6; + hFFT = h2->FFT(hFFT, "MAG M"); + if (hFFT) { + hFFT->SetStats(0); + const auto nbinsx = hFFT->GetNbinsX(); + auto xax = hFFT->GetXaxis(); + xax->SetRange(2, nbinsx / 2); + if (init) { + xax->Set(nbinsx, xax->GetXmin() / maxTime, xax->GetXmax() / maxTime); + hFFT->SetNameTitle(Form("hFFT_%sROC", (roc < 36) ? "I" : "O"), "FFT magnitude;frequency (kHz);amplitude"); + } + hFFT->Scale(2. / (nbinsx - 1)); + cFFT->cd(); + hFFT->Draw(); + } + } + } + update(Form("%s;%sFFT", type.Data(), type.Data())); + } + // printf("bin=%03d.%03d(%03d)[%05d], name=%s, ROC=%02d content=%.1f, ev: %d\n",row,pad,cpad,chn,h->GetName(), roc, h->GetBinContent(binx,biny), event); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::fillMaxHists(int type) +{ + // + // type: 0 fill side and sector, 1: fill sector only + // + const auto& mapper = Mapper::instance(); + + float kEpsilon = 0.000000000001; + CalPad* pad = mEvDisp.getCalPadMax(); + TH2F* hSide = nullptr; + TH2F* hROC = nullptr; + resetHists(type); + const int runNumber = TString(gSystem->Getenv("RUN_NUMBER")).Atoi(); + //const int eventNumber = mEvDisp.getNumberOfProcessedEvents() - 1; + const int eventNumber = mEvDisp.getPresentEventNumber(); + const bool eventComplete = mEvDisp.isPresentEventComplete(); + + for (int iROC = 0; iROC < 72; iROC++) { + hROC = mHMaxOROC; + hSide = mHMaxC; + if (iROC < 36) { + hROC = mHMaxIROC; + } + if ((iROC % 36) < 18) { + hSide = mHMaxA; + } + if ((iROC % 36) == (mSelectedSector % 36)) { + TString title = Form("Max Values %cROC %c%02d (%02d) TF %s%d%s", (iROC < 36) ? 'I' : 'O', (iROC % 36 < 18) ? 'A' : 'C', iROC % 18, iROC, eventComplete ? "" : "(", eventNumber, eventComplete ? "" : ")"); + //TString title = Form("Max Values Run %d Event %d", runNumber, eventNumber); + if (hROC) { + hROC->SetTitle(title.Data()); + } + } + auto& calRoc = pad->getCalArray(iROC); + const int nRows = mapper.getNumberOfRowsROC(iROC); + for (int irow = 0; irow < nRows; irow++) { + const int nPads = mapper.getNumberOfPadsInRowROC(iROC, irow); + for (int ipad = 0; ipad < nPads; ipad++) { + float value = calRoc.getValue(irow, ipad); + //printf("iROC: %02d, sel: %02d, row %02d, pad: %02d, value: %.5f\n", iROC, mSelectedSector, irow, ipad, value); + if (TMath::Abs(value) > kEpsilon) { + if (!type && hSide) { + const GlobalPosition2D global2D = mapper.getPadCentre(PadSecPos(Sector(iROC % 36), PadPos(irow + (iROC >= 36) * mapper.getNumberOfRowsROC(0), ipad))); + int binx = 1 + TMath::Nint((global2D.X() + 250.) * hSide->GetNbinsX() / 500.); + int biny = 1 + TMath::Nint((global2D.Y() + 250.) * hSide->GetNbinsY() / 500.); + hSide->SetBinContent(binx, biny, value); + } + const int nPads = mapper.getNumberOfPadsInRowROC(iROC, irow); + const int cpad = ipad - nPads / 2; + if ((iROC % 36 == mSelectedSector % 36) && hROC) { + //printf(" ->>> Fill: iROC: %02d, sel: %02d, row %02d, pad: %02d, value: %.5f\n", iROC, mSelectedSector, irow, ipad, value); + hROC->Fill(irow, cpad, value); + } + } + if ((iROC % 36 == mSelectedSector % 36) && hROC) { + hROC->SetUniqueID(iROC); + } + } + } + } + if (!type) { + update("MaxValsA;MaxValsC"); + } + + update("MaxValsI;MaxValsO"); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::selectSector(int sector) +{ + mSelectedSector = sector % 36; + mEvDisp.setSelectedSector(mSelectedSector); + fillMaxHists(1); +} + +//__________________________________________________________________________ +int SimpleEventDisplayGUI::FindROCFromXY(const float x, const float y, const int side) +{ + // + // + // + + const auto& mapper = Mapper::instance(); + float r = TMath::Sqrt(x * x + y * y); + static const float innerWall = mapper.getPadCentre(PadPos(0, 0)).X() - 5.; + static const float outerWall = mapper.getPadCentre(PadPos(151, 0)).X() + 5.; + static const float outerIROC = mapper.getPadCentre(PadPos(62, 0)).X(); + static const float innerOROC = mapper.getPadCentre(PadPos(63, 0)).X(); + static const float betweenROC = (outerIROC + innerOROC) / 2.; + + //check radial boundary + if (r < innerWall || r > outerWall) { + return -1; + } + + //check for IROC or OROC + int type = 0; + + if (r > betweenROC) { + type = 1; + } + + int alpha = TMath::Nint(TMath::ATan2(y, x) / TMath::Pi() * 180); + // printf("%6.3f %6.3f %03d\n",x, y, alpha); + if (alpha < 0) { + alpha += 360; + } + const int roc = alpha / 20 + side * 18 + type * 36; + return roc; +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::selectSectorExec(int event, int x, int y, TObject* o) +{ + + int binx, biny; + float bincx, bincy; + TH1* h = getBinInfoXY(binx, biny, bincx, bincy); + + if (!h) { + return; + } + + const int side = h->GetUniqueID(); + const int roc = FindROCFromXY(bincx, bincy, side); + + if (roc < 0) { + return; + } + + const int sector = roc % 36; + + h->SetTitle(Form("Max Values %c%02d", (sector < 18) ? 'A' : 'C', sector % 18)); + + if (sector != mOldHooverdSector) { + auto pad = (TPad*)gTQSender; + pad->Modified(); + pad->Update(); + mOldHooverdSector = sector; + } + + if (event != 11) { + return; + } + //printf("selectSector: %d.%02d.%d = %02d\n", side, sector, roc < 36, roc); + selectSector(sector); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::initGUI() +{ + const int w = 400; + const int h = 400; + const int hOff = 60; + const int vOff = 2; + TCanvas* c = nullptr; + + if (mShowSides) { + //histograms and canvases for max values A-Side + c = new TCanvas("MaxValsA", "MaxValsA", 0 * w - 1, 0 * h, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "selectSectorExec(int,int,int,TObject*)"); + + mHMaxA = new TH2F("hMaxValsA", "Max Values Side A;x (cm);y (cm)", 330, -250, 250, 330, -250, 250); + mHMaxA->SetStats(kFALSE); + mHMaxA->SetUniqueID(0); //A-Side + mHMaxA->Draw("colz"); + painter::drawSectorsXY(Side::A); + + //histograms and canvases for max values C-Side + c = new TCanvas("MaxValsC", "MaxValsC", 0 * w - 1, 1 * h + hOff, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "selectSectorExec(int,int,int,TObject*)"); + mHMaxC = new TH2F("hMaxValsC", "Max Values Side C;x (cm);y (cm)", 330, -250, 250, 330, -250, 250); + mHMaxC->SetStats(kFALSE); + mHMaxC->SetUniqueID(1); //C-Side + mHMaxC->Draw("colz"); + painter::drawSectorsXY(Side::C); + } + + //histograms and canvases for max values IROC + c = new TCanvas("MaxValsI", "MaxValsI", -1 * (w + vOff), 0 * h, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "drawPadSignal(int,int,int,TObject*)"); + mHMaxIROC = new TH2F("hMaxValsIROC", "Max Values IROC;row;pad", 63, 0, 63, 108, -54, 54); + mHMaxIROC->SetDirectory(nullptr); + mHMaxIROC->SetStats(kFALSE); + mHMaxIROC->Draw("colz"); + + //histograms and canvases for max values OROC + c = new TCanvas("MaxValsO", "MaxValsO", -1 * (w + vOff), 1 * h + hOff, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "drawPadSignal(int,int,int,TObject*)"); + mHMaxOROC = new TH2F("hMaxValsOROC", "Max Values OROC;row;pad", 89, 0, 89, 140, -70, 70); + mHMaxOROC->SetDirectory(nullptr); + mHMaxOROC->SetStats(kFALSE); + mHMaxOROC->Draw("colz"); + + //canvases for pad signals + new TCanvas("SigI", "SigI", -2 * (w + vOff), 0 * h, w, h); + new TCanvas("SigO", "SigO", -2 * (w + vOff), 1 * h + hOff, w, h); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::next(int eventNumber) +{ + if (mRunMode == RunMode::Online) { + + if (!mDataAvailable) { + return; + } + + mUpdatingDigits = true; + usleep(1000); + mNextEvent = true; + + while (mUpdatingDigits) { + usleep(1000); + } + mProcessingEvent = true; + } + + using Status = CalibRawBase::ProcessStatus; + Status status = mEvDisp.processEvent(eventNumber); + + const int timeBins = mEvDisp.getNumberOfProcessedTimeBins(); + + const int presentEventNumber = mEvDisp.getPresentEventNumber(); + mEventNumber->SetText(Form("%d", presentEventNumber)); + + switch (status) { + case Status::Ok: { + std::cout << "Read in full event with " << timeBins << " time bins\n"; + break; + } + case Status::Truncated: { + std::cout << "Event is truncated and contains less than " << timeBins << " time bins\n"; + break; + } + case Status::NoMoreData: { + std::cout << "No more data to be read\n"; + //return; + break; + } + case Status::NoReaders: { + std::cout << "No raw readers configured\n"; + return; + break; + } + default: + // Do nothing for non-listed values of Status enum + break; + } + //bool res=mEvDisp.processEvent(); + //printf("Next: %d, %d (%d - %d), %d\n",res, ((AliRawReaderGEMDate*)mRawReader)->mEventInFile,((AliRawReaderGEMDate*)mRawReader)->GetCamacData(0),mRawReader->GetEventFromTag(), mRawReader->GetDataSize()); + //printf("Next Event: %d\n",mRawReader->GetEventFromTag()); + + fillMaxHists(); + + if (mRunMode == RunMode::Online) { + mProcessingEvent = false; + } +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::callEventNumber() +{ + const int event = TString(mEventNumber->GetText()).Atoi(); + next(event); +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::runSimpleEventDisplay(std::string_view fileInfo, std::string_view pedestalFile, int firstTimeBin, int lastTimeBin, int nTimeBinsPerCall, uint32_t verbosity, uint32_t debugLevel, int selectedSector, bool showSides) +{ + FairLogger* logger = FairLogger::GetLogger(); + logger->SetLogVerbosityLevel("LOW"); + logger->SetLogScreenLevel("DEBUG"); + if (pedestalFile.size()) { + TFile f(pedestalFile.data()); + if (f.IsOpen()) { + CalDet<float>* pedestal = nullptr; + f.GetObject("Pedestals", pedestal); + mEvDisp.setPedstals(pedestal); + } + } + + mSelectedSector = selectedSector; + mShowSides = showSides; + + mEvDisp.setupContainers(fileInfo.data(), verbosity, debugLevel); + mEvDisp.setSkipIncompleteEvents(false); // in case of the online monitor do not skip incomplete events + mEvDisp.setSelectedSector(mSelectedSector); + mEvDisp.setLastSelSector(mSelectedSector); + mEvDisp.setTimeBinsPerCall(nTimeBinsPerCall); + mEvDisp.setTimeBinRange(firstTimeBin, lastTimeBin); + + initGUI(); + monitorGui(); + + next(0); +} + +//_____________________________________________________________________________ +void SimpleEventDisplayGUI::startGUI(int maxTimeBins) +{ + mRunMode = RunMode::Online; + + TApplication evDisp("TPC raw data monitor", nullptr, nullptr); + + mEvDisp.setSkipIncompleteEvents(false); // in case of the online monitor do not skip incomplete events + mEvDisp.setSelectedSector(mSelectedSector); + mEvDisp.setLastSelSector(mSelectedSector); + mEvDisp.setTimeBinsPerCall(maxTimeBins); + mEvDisp.setTimeBinRange(0, maxTimeBins); + + initGUI(); + monitorGui(); + + evDisp.Run(true); +} diff --git a/Detectors/TPC/monitor/src/TPCMonitorLinkDef.h b/Detectors/TPC/monitor/src/TPCMonitorLinkDef.h index 638972c7e784b..a7507723c37ed 100644 --- a/Detectors/TPC/monitor/src/TPCMonitorLinkDef.h +++ b/Detectors/TPC/monitor/src/TPCMonitorLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::tpc::SimpleEventDisplay; +#pragma link C++ class o2::tpc::SimpleEventDisplay + ; +#pragma link C++ class o2::tpc::SimpleEventDisplayGUI + ; #endif diff --git a/Detectors/TPC/qc/CMakeLists.txt b/Detectors/TPC/qc/CMakeLists.txt index 2f60bf0bcfe8b..dea3180b0e16f 100644 --- a/Detectors/TPC/qc/CMakeLists.txt +++ b/Detectors/TPC/qc/CMakeLists.txt @@ -1,27 +1,29 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TPCQC SOURCES src/PID.cxx + src/Tracking.cxx src/Helpers.cxx - src/TrackCuts.cxx src/Clusters.cxx src/Tracks.cxx PUBLIC_LINK_LIBRARIES O2::TPCBase - O2::DataFormatsTPC) + O2::DataFormatsTPC + O2::GPUO2Interface) o2_target_root_dictionary(TPCQC HEADERS include/TPCQC/PID.h + include/TPCQC/Tracking.h include/TPCQC/Helpers.h - include/TPCQC/TrackCuts.h include/TPCQC/Clusters.h include/TPCQC/Tracks.h include/TPCQC/CalPadWrapper.h) @@ -32,12 +34,6 @@ o2_add_test(PID SOURCES test/test_PID.cxx LABELS tpc) -o2_add_test(TrackCuts - COMPONENT_NAME tpc - PUBLIC_LINK_LIBRARIES O2::TPCQC - SOURCES test/test_TrackCuts.cxx - LABELS tpc) - o2_add_test(Clusters COMPONENT_NAME tpc PUBLIC_LINK_LIBRARIES O2::TPCQC @@ -55,16 +51,16 @@ o2_add_test_root_macro(macro/runPID.C PUBLIC_LINK_LIBRARIES O2::TPCQC O2::DataFormatsTPC O2::TPCBase - LABELS tpc) + LABELS tpc COMPILE_ONLY) o2_add_test_root_macro(macro/runClusters.C PUBLIC_LINK_LIBRARIES O2::TPCQC O2::DataFormatsTPC O2::TPCBase - LABELS tpc) + LABELS tpc COMPILE_ONLY) o2_add_test_root_macro(macro/runTracks.C PUBLIC_LINK_LIBRARIES O2::TPCQC O2::DataFormatsTPC O2::TPCBase - LABELS tpc) + LABELS tpc COMPILE_ONLY) diff --git a/Detectors/TPC/qc/include/TPCQC/CalPadWrapper.h b/Detectors/TPC/qc/include/TPCQC/CalPadWrapper.h index 77afbc8909b4b..9fa814e2737b4 100644 --- a/Detectors/TPC/qc/include/TPCQC/CalPadWrapper.h +++ b/Detectors/TPC/qc/include/TPCQC/CalPadWrapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/qc/include/TPCQC/Clusters.h b/Detectors/TPC/qc/include/TPCQC/Clusters.h index 9d4668f490887..911a8c0cd81bb 100644 --- a/Detectors/TPC/qc/include/TPCQC/Clusters.h +++ b/Detectors/TPC/qc/include/TPCQC/Clusters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,9 +42,18 @@ class Clusters public: Clusters() = default; - bool processCluster(const o2::tpc::ClusterNative& cluster, const o2::tpc::Sector sector, const int row); + template <class T> + bool processCluster(const T& cluster, const o2::tpc::Sector sector, const int row); - void analyse(); + void fillADCValue(int cru, int rowInSector, int padInRow, int timeBin, float adcValue); + + void normalize(); + + inline void analyse() { Clusters::normalize(); } + + void denormalize(); + + void reset(); void dumpToFile(std::string filename); @@ -68,6 +78,7 @@ class Clusters CalPad mSigmaTime{"Sigma_Time"}; CalPad mSigmaPad{"Sigma_Pad"}; CalPad mTimeBin{"Time_Bin"}; + bool mIsNormalized{false}; ClassDefNV(Clusters, 1) }; @@ -75,4 +86,4 @@ class Clusters } // namespace tpc } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/TPC/qc/include/TPCQC/Helpers.h b/Detectors/TPC/qc/include/TPCQC/Helpers.h index 454b8b3431afd..509911b816ec4 100644 --- a/Detectors/TPC/qc/include/TPCQC/Helpers.h +++ b/Detectors/TPC/qc/include/TPCQC/Helpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #define AliceO2_TPC_HELPERS_H #include <vector> +#include "TPCBase/CalDet.h" class TH1F; class TH2F; @@ -48,6 +50,13 @@ void setStyleHistogram2D(TH2& histo); /// Set nice style for vector of 2D histograms void setStyleHistogram2D(std::vector<TH2F>& histos); +/// Check if at least one pad in refPedestal and pedestal differs by 3*refNoise to see if new ZS calibration data should be uploaded to the FECs. +/// @param refPedestal +/// @param refNoise +/// @param pedestal +/// @return true if refPedestal - pedestal > 3*refNoise on at least one pad +bool newZSCalib(const o2::tpc::CalDet<float>& refPedestal, const o2::tpc::CalDet<float>& refNoise, const o2::tpc::CalDet<float>& pedestal); + } // namespace helpers } // namespace qc } // namespace tpc diff --git a/Detectors/TPC/qc/include/TPCQC/PID.h b/Detectors/TPC/qc/include/TPCQC/PID.h index 0aff27e1ec9a3..e6be781ff9986 100644 --- a/Detectors/TPC/qc/include/TPCQC/PID.h +++ b/Detectors/TPC/qc/include/TPCQC/PID.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/qc/include/TPCQC/Tracking.h b/Detectors/TPC/qc/include/TPCQC/Tracking.h new file mode 100644 index 0000000000000..27070d72b5971 --- /dev/null +++ b/Detectors/TPC/qc/include/TPCQC/Tracking.h @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// @file Tracking.h +/// @author David Rohr +/// + +#ifndef AliceO2_TPC_QC_TRACKING_H +#define AliceO2_TPC_QC_TRACKING_H + +#include <vector> +#include <memory> + +class TH1F; +class TH2F; +class TH1D; + +//o2 includes +#include "DataFormatsTPC/Defs.h" + +namespace o2 +{ +class MCCompLabel; +namespace gpu +{ +class GPUO2InterfaceQA; +struct GPUO2InterfaceConfiguration; +} // namespace gpu +namespace tpc +{ +class TrackTPC; +struct ClusterNativeAccess; + +namespace qc +{ +// Class for tracking QA (efficiency / resolution) +// Some settings can be steered via --configKeyValues: (See GPUSettingsList.h for actual definitions). Relevant QA parameters are: +// "GPU_QA.strict=[bool]" Strict QA mode: Only consider resolution of tracks where the fit ended within 5 cm of the reference, and remove outliers. (Default: true) +// "GPU_QA.qpt=[float]" Set cut for Q/Pt. (Default: 10.0) +// "GPU_QA.recThreshold=[float]" Compute the efficiency including impure tracks with fake contamination. (Default 0.9) +// "GPU_QA.maxResX=[float]" Maxmimum X (~radius) for reconstructed track position to take into accound for resolution QA in cm (Default: no limit) +// "GPU_QA.nativeFitResolutions=[bool]" Create resolution histograms in the native fit units (sin(phi), tan(lambda), Q/Pt) (Default: false) +// "GPU_QA.filterCharge=[int]" Filter for positive (+1) or negative (-1) charge (Default: no filter) +// "GPU_QA.filterPID=[int]" Filter for Particle Type (0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton) (Default: no filter) + +class Tracking +{ + public: + /// default constructor + Tracking(); + ~Tracking(); + + enum outputModes { + outputMergeable, // output mergeaable histogrems, which can be merged and then postprocessed + outputPostprocessed, // directly postprocess the histograms before merging + outputLayout // arrange postprocessed histograms in predefined layouts + }; + + // Initiaalize + // postprocessOnly = false: initialize to run the full QA via processTracks function. + // postprocessOnly = true : cannot process tracks but only postprocess mergeeablee histogrems in postprocess function, output type must be outputPostprocessed or outputLayout. + void initialize(outputModes outputMode, bool postprocessOnly = false); + + void processTracks(const std::vector<o2::tpc::TrackTPC>* tracks, const std::vector<o2::MCCompLabel>* tracksMC, const o2::tpc::ClusterNativeAccess* clNative, TObjArray* out = nullptr); + int postprocess(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out); // Inputs are modified, thus must not be const + + /// Reset all histograms + void resetHistograms(); + + /// get histograms + void getHists(const std::vector<TH1F>*& h1, const std::vector<TH2F>*& h2, const std::vector<TH1D>*& h3) const; + + private: + std::unique_ptr<o2::gpu::GPUO2InterfaceConfiguration> mQAConfig; //! + std::unique_ptr<o2::gpu::GPUO2InterfaceQA> mQA; //! + outputModes mOutputMode; + + ClassDefNV(Tracking, 1) +}; +} // namespace qc +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/qc/include/TPCQC/Tracks.h b/Detectors/TPC/qc/include/TPCQC/Tracks.h index 94c1bf3043be6..3552e4f335f85 100644 --- a/Detectors/TPC/qc/include/TPCQC/Tracks.h +++ b/Detectors/TPC/qc/include/TPCQC/Tracks.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,6 +60,9 @@ class Tracks /// Reset all histograms void resetHistograms(); + /// Function to be called at each endOfCycle + void processEndOfCycle(); + /// Dump results to a file void dumpToFile(std::string_view filename); @@ -70,11 +74,16 @@ class Tracks std::vector<TH2F>& getHistograms2D() { return mHist2D; } const std::vector<TH2F>& getHistograms2D() const { return mHist2D; } + /// get ratios of 1D histograms + std::vector<TH1F>& getHistogramRatios1D() { return mHistRatio1D; } + const std::vector<TH1F>& getHistogramRatios1D() const { return mHistRatio1D; } + private: - std::vector<TH1F> mHist1D{}; ///< Initialize vector of 1D histograms - std::vector<TH2F> mHist2D{}; ///< Initialize vector of 2D histograms + std::vector<TH1F> mHist1D{}; ///< Initialize vector of 1D histograms + std::vector<TH2F> mHist2D{}; ///< Initialize vector of 2D histograms + std::vector<TH1F> mHistRatio1D{}; ///< Initialize vector of ratios of 1D histograms - ClassDefNV(Tracks, 1) + ClassDefNV(Tracks, 2) }; } // namespace qc } // namespace tpc diff --git a/Detectors/TPC/qc/macro/runClusters.C b/Detectors/TPC/qc/macro/runClusters.C index bed9cbb409d15..ea1d1b54f429e 100644 --- a/Detectors/TPC/qc/macro/runClusters.C +++ b/Detectors/TPC/qc/macro/runClusters.C @@ -1,14 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #if !defined(__CLING__) || defined(__ROOTCLING__) +#define MS_GSL_V3 #include "TFile.h" #include "TTree.h" #include "DataFormatsTPC/ClusterNative.h" @@ -55,6 +57,6 @@ void runClusters(std::string_view outputFile = "ClusterQC.root", std::string_vie } } } - clusters.analyse(); + clusters.normalize(); clusters.dumpToFile(outputFile.data()); } diff --git a/Detectors/TPC/qc/macro/runPID.C b/Detectors/TPC/qc/macro/runPID.C index 26266b00e3669..f88c27d1f4c42 100644 --- a/Detectors/TPC/qc/macro/runPID.C +++ b/Detectors/TPC/qc/macro/runPID.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,10 +17,10 @@ #include "TH1.h" #include "TH2.h" #include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/TrackCuts.h" #include "DataFormatsTPC/ClusterNative.h" #include "TPCQC/PID.h" #include "TPCQC/Helpers.h" -#include "TPCQC/TrackCuts.h" #endif using namespace o2::tpc; @@ -90,4 +91,4 @@ void runPID(std::string outputFileName = "PID", std::string_view inputFileName = pid.dumpToFile(histFile); pid.resetHistograms(); -} \ No newline at end of file +} diff --git a/Detectors/TPC/qc/macro/runTracks.C b/Detectors/TPC/qc/macro/runTracks.C index d4c55c638f7b5..f55747ddd1267 100644 --- a/Detectors/TPC/qc/macro/runTracks.C +++ b/Detectors/TPC/qc/macro/runTracks.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,7 +25,6 @@ #include "DataFormatsTPC/ClusterNative.h" #include "TPCQC/Tracks.h" #include "TPCQC/Helpers.h" -//#include "TPCQC/TrackCuts.h" #endif using namespace o2::tpc; @@ -56,7 +56,7 @@ void runTracks(std::string outputFileName = "tpcQcTracks", std::string_view inpu tree->GetEntry(i); size_t nTracks = (maxTracks > 0) ? std::min(tpcTracks->size(), maxTracks) : tpcTracks->size(); // ---| track loop |--- - for (int k = 0; k < nTracks; k++) { + for (size_t k = 0; k < nTracks; k++) { auto track = (*tpcTracks)[k]; tracksQC.processTrack(track); } diff --git a/Detectors/TPC/qc/src/Clusters.cxx b/Detectors/TPC/qc/src/Clusters.cxx index 54ad4882e7572..e8fc47be9dbff 100644 --- a/Detectors/TPC/qc/src/Clusters.cxx +++ b/Detectors/TPC/qc/src/Clusters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,26 +18,34 @@ #include "TPCQC/Clusters.h" #include "TPCBase/Painter.h" #include "TPCBase/ROC.h" +#include "TPCBase/CRU.h" #include "TPCBase/Mapper.h" #include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/KrCluster.h" ClassImp(o2::tpc::qc::Clusters); using namespace o2::tpc::qc; //______________________________________________________________________________ -bool Clusters::processCluster(const o2::tpc::ClusterNative& cluster, const o2::tpc::Sector sector, const int row) +template <class T> +bool Clusters::processCluster(const T& cluster, const o2::tpc::Sector sector, const int row) { + if (mIsNormalized) { + denormalize(); + LOGP(warning, "calling denormalize() before filling"); + } + const int nROC = row < 63 ? int(sector) : int(sector) + 36; const int rocRow = row < 63 ? row : row - 63; const float pad = cluster.getPad(); - const uint16_t qMax = cluster.qMax; - const uint16_t qTot = cluster.qTot; - const float sigmaPad = cluster.getSigmaPad(); - const float sigmaTime = cluster.getSigmaTime(); - const float timeBin = cluster.getTime(); + const auto qMax = cluster.getQmax(); + const auto qTot = cluster.getQtot(); + const auto sigmaPad = cluster.getSigmaPad(); + const auto sigmaTime = cluster.getSigmaTime(); + const auto timeBin = cluster.getTime(); float count = mNClusters.getCalArray(nROC).getValue(rocRow, pad); mNClusters.getCalArray(nROC).setValue(rocRow, pad, count + 1); @@ -60,13 +69,66 @@ bool Clusters::processCluster(const o2::tpc::ClusterNative& cluster, const o2::t } //______________________________________________________________________________ -void Clusters::analyse() +void Clusters::fillADCValue(int cru, int rowInSector, int padInRow, int timeBin, float adcValue) { + if (mIsNormalized) { + denormalize(); + LOGP(warning, "calling denormalize() before filling"); + } + + const CRU cruID(cru); + float val; + val = mNClusters.getValue(cruID.sector(), rowInSector, padInRow); + mNClusters.setValue(cruID.sector(), rowInSector, padInRow, val + 1); + + val = mQMax.getValue(cruID.sector(), rowInSector, padInRow); + mQMax.setValue(cruID.sector(), rowInSector, padInRow, val + adcValue); + + val = mTimeBin.getValue(cruID.sector(), rowInSector, padInRow); + mTimeBin.setValue(cruID.sector(), rowInSector, padInRow, val + timeBin); +} + +//______________________________________________________________________________ +void Clusters::normalize() +{ + if (mIsNormalized) { + return; + } + mQMax /= mNClusters; mQTot /= mNClusters; mSigmaTime /= mNClusters; mSigmaPad /= mNClusters; mTimeBin /= mNClusters; + + mIsNormalized = true; +} + +//______________________________________________________________________________ +void Clusters::denormalize() +{ + if (!mIsNormalized) { + return; + } + + mQMax *= mNClusters; + mQTot *= mNClusters; + mSigmaTime *= mNClusters; + mSigmaPad *= mNClusters; + mTimeBin *= mNClusters; + + mIsNormalized = false; +} + +//______________________________________________________________________________ +void Clusters::reset() +{ + mNClusters *= 0; + mQMax *= 0; + mQTot *= 0; + mSigmaTime *= 0; + mSigmaPad *= 0; + mTimeBin *= 0; } //______________________________________________________________________________ @@ -96,3 +158,7 @@ void Clusters::dumpToFile(std::string filename) g->WriteObject(&mTimeBin, mTimeBin.getName().data()); g->Close(); } + +// ===| explicit instantiations |=============================================== +template bool Clusters::processCluster<o2::tpc::ClusterNative>(const o2::tpc::ClusterNative&, const o2::tpc::Sector, const int); +template bool Clusters::processCluster<o2::tpc::KrCluster>(const o2::tpc::KrCluster&, const o2::tpc::Sector, const int); diff --git a/Detectors/TPC/qc/src/Helpers.cxx b/Detectors/TPC/qc/src/Helpers.cxx index f80cffd9aba3d..df2c68e4a54e5 100644 --- a/Detectors/TPC/qc/src/Helpers.cxx +++ b/Detectors/TPC/qc/src/Helpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,8 @@ //o2 includes #include "TPCQC/Helpers.h" +#include "TPCBase/Mapper.h" +#include "TPCBase/ROC.h" using namespace o2::tpc::qc; @@ -69,3 +72,26 @@ void helpers::setStyleHistogram2D(std::vector<TH2F>& histos) helpers::setStyleHistogram2D(hist); } } + +//______________________________________________________________________________ +bool helpers::newZSCalib(const o2::tpc::CalDet<float>& refPedestal, const o2::tpc::CalDet<float>& refNoise, const o2::tpc::CalDet<float>& pedestal) +{ + static const o2::tpc::Mapper& mapper = o2::tpc::Mapper::instance(); + + o2::tpc::CalDet<float> diffCalDet = refPedestal - pedestal; + + for (o2::tpc::ROC roc; !roc.looped(); ++roc) { + const int nrows = mapper.getNumberOfRowsROC(roc); + for (int irow = 0; irow < nrows; ++irow) { + const int npads = mapper.getNumberOfPadsInRowROC(roc, irow); + for (int ipad = 0; ipad < npads; ++ipad) { + const auto val = diffCalDet.getValue(roc, irow, ipad); + if (std::abs(val) > 3 * refNoise.getValue(roc, irow, ipad)) { + return true; + } + } + } + } + + return false; +} \ No newline at end of file diff --git a/Detectors/TPC/qc/src/PID.cxx b/Detectors/TPC/qc/src/PID.cxx index c5ef72a00a7fa..ef27761296319 100644 --- a/Detectors/TPC/qc/src/PID.cxx +++ b/Detectors/TPC/qc/src/PID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "TStyle.h" #include "TFile.h" #include "TCanvas.h" +#include "TMathBase.h" //o2 includes #include "DataFormatsTPC/dEdxInfo.h" @@ -30,12 +32,14 @@ using namespace o2::tpc::qc; //______________________________________________________________________________ void PID::initializeHistograms() { - mHist1D.emplace_back("hNClusters", "; # of clusters; counts", 160, 0, 1600); //| mHist1D[0] - mHist1D.emplace_back("hdEdxTot", "; dEdxTot (a.u.); counts", 200, 0, 200); //| mHist1D[1] - mHist1D.emplace_back("hdEdxMax", "; dEdxMax (a.u.); counts", 200, 0, 200); //| mHist1D[2] - mHist1D.emplace_back("hPhi", "; #phi (rad); counts", 180, 0., 2 * M_PI); //| mHist1D[3] - mHist1D.emplace_back("hTgl", "; tan#lambda; counts", 60, -2, 2); //| mHist1D[4] - mHist1D.emplace_back("hSnp", "; sin p; counts", 60, -2, 2); //| mHist1D[5] + mHist1D.emplace_back("hNClusters", "; # of clusters; counts", 160, 0, 160); //| mHist1D[0] + mHist1D.emplace_back("hdEdxTot", "; dEdxTot (a.u.); counts", 200, 0, 200); //| mHist1D[1] + mHist1D.emplace_back("hdEdxMax", "; dEdxMax (a.u.); counts", 200, 0, 200); //| mHist1D[2] + mHist1D.emplace_back("hPhi", "; #phi (rad); counts", 180, 0., 2 * M_PI); //| mHist1D[3] + mHist1D.emplace_back("hTgl", "; tan#lambda; counts", 60, -2, 2); //| mHist1D[4] + mHist1D.emplace_back("hSnp", "; sin p; counts", 60, -2, 2); //| mHist1D[5] + mHist1D.emplace_back("hdEdxMips", "dEdx (a.u.) of MIPs; dEdx of MIPs (a.u.); counts", 25, 35, 60); //| mHist1D[6] + mHist1D.emplace_back("hdEdxEles", "dEdx (a.u.) of electrons; dEdx (a.u.); counts", 30, 70, 100); //| mHist1D[7] mHist2D.emplace_back("hdEdxVsPhi", "dEdx (a.u.) vs #phi (rad); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 300, 0, 300); //| mHist2D[0] mHist2D.emplace_back("hdEdxVsTgl", "dEdx (a.u.) vs tan#lambda; tan#lambda; dEdx (a.u.)", 60, -2, 2, 300, 0, 300); //| mHist2D[1] @@ -45,8 +49,11 @@ void PID::initializeHistograms() if (logPtBinning.size() > 0) { mHist2D.emplace_back("hdEdxVsp", "dEdx (a.u.) vs p (G#it{e}V/#it{c}); p (G#it{e}V/#it{c}); dEdx (a.u.)", logPtBinning.size() - 1, logPtBinning.data(), 300, 0, 300); //| mHist2D[3] } - //mHist2D.emplace_back("hdedxVsphiMIPA","; #phi (rad); dedx (a.u.)", 180,0.,2*M_PI,25,35,60); //| mHist2D[4] - //mHist2D.emplace_back("hdedxVsphiMIPC","; #phi (rad); dedx (a.u.)", 180,0.,2*M_PI,25,35,60); //| mHist2D[5] + + mHist2D.emplace_back("hdEdxVsPhiMipsAside", "dEdx (a.u.) vs #phi (rad) of MIPs (A side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60); //| mHist2D[4] + mHist2D.emplace_back("hdEdxVsPhiMipsCside", "dEdx (a.u.) vs #phi (rad) of MIPs (C side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60); //| mHist2D[5] + mHist2D.emplace_back("hdEdxVsPhiElesAside", "dEdx (a.u.) vs #phi (rad) of electrons (A side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 30, 70, 100); //| mHist2D[6] + mHist2D.emplace_back("hdEdxVsPhiElesCside", "dEdx (a.u.) vs #phi (rad) of electrons (C side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 30, 70, 100); //| mHist2D[7] } //______________________________________________________________________________ @@ -71,6 +78,9 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track) const auto tgl = track.getTgl(); const auto snp = track.getSnp(); const auto nclusters = track.getNClusterReferences(); + const auto eta = track.getEta(); + + double absEta = TMath::Abs(eta); // ===| histogram filling |=== mHist1D[0].Fill(nclusters); @@ -85,6 +95,26 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track) mHist2D[2].Fill(nclusters, dEdxTot); mHist2D[3].Fill(p, dEdxTot); + // ===| cuts and histogram filling for MIPs |=== + if (p > 0.4 && p < 0.55 && absEta < 1. && nclusters > 80 && dEdxTot > 35 && dEdxTot < 60) { + mHist1D[6].Fill(dEdxTot); + if (eta > 0.) { + mHist2D[4].Fill(phi, dEdxTot); + } else { + mHist2D[5].Fill(phi, dEdxTot); + } + } + + // ===| cuts and histogram filling for electrons |=== + if (p > 0.32 && p < 0.38 && absEta < 1. && nclusters > 80 && dEdxTot > 70 && dEdxTot < 100) { + mHist1D[7].Fill(dEdxTot); + if (eta > 0.) { + mHist2D[6].Fill(phi, dEdxTot); + } else { + mHist2D[7].Fill(phi, dEdxTot); + } + } + return true; } diff --git a/Detectors/TPC/qc/src/TPCQCLinkDef.h b/Detectors/TPC/qc/src/TPCQCLinkDef.h index 99cce76f3c5c5..650470f621908 100644 --- a/Detectors/TPC/qc/src/TPCQCLinkDef.h +++ b/Detectors/TPC/qc/src/TPCQCLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,12 +16,13 @@ #pragma link off all functions; #pragma link C++ class o2::tpc::qc::PID+; -#pragma link C++ class o2::tpc::qc::TrackCuts+; +#pragma link C++ class o2::tpc::qc::Tracking + ; #pragma link C++ class o2::tpc::qc::Clusters+; #pragma link C++ class o2::tpc::qc::Tracks+; #pragma link C++ class o2::tpc::qc::CalPadWrapper+; #pragma link C++ function o2::tpc::qc::helpers::makeLogBinning+; #pragma link C++ function o2::tpc::qc::helpers::setStyleHistogram1D+; #pragma link C++ function o2::tpc::qc::helpers::setStyleHistogram2D+; +#pragma link C++ function o2::tpc::qc::helpers::newZSCalib+; #endif diff --git a/Detectors/TPC/qc/src/TrackCuts.cxx b/Detectors/TPC/qc/src/TrackCuts.cxx deleted file mode 100644 index 07cc2cbdba894..0000000000000 --- a/Detectors/TPC/qc/src/TrackCuts.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "FairLogger.h" - -#include "TPCQC/TrackCuts.h" -#include "DataFormatsTPC/TrackTPC.h" - -ClassImp(o2::tpc::qc::TrackCuts); - -using namespace o2::tpc::qc; - -TrackCuts::TrackCuts(float PMin, float PMax, float NClusMin) : mPMin(PMin), - mPMax(PMax), - mNClusMin(NClusMin) -{ -} - -//______________________________________________________________________________ -bool TrackCuts::goodTrack(o2::tpc::TrackTPC const& track) -{ - const auto p = track.getP(); - const auto nclusters = track.getNClusterReferences(); - - if (p > mPMax) { - return false; - } - if (p < mPMin) { - return false; - } - if (nclusters < mNClusMin) { - return false; - } - return true; -} \ No newline at end of file diff --git a/Detectors/TPC/qc/src/Tracking.cxx b/Detectors/TPC/qc/src/Tracking.cxx new file mode 100644 index 0000000000000..3685ba4abb07f --- /dev/null +++ b/Detectors/TPC/qc/src/Tracking.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Tracking.cxx +/// \author David Rohr + +#define _USE_MATH_DEFINES + +#include <cmath> + +//root includes +#include "TStyle.h" +#include "TFile.h" +#include "TCanvas.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TH1D.h" + +//o2 includes +#include "DataFormatsTPC/TrackTPC.h" +#include "TPCQC/Tracking.h" +#include "GPUO2InterfaceQA.h" +#include "GPUO2InterfaceConfiguration.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" + +ClassImp(o2::tpc::qc::Tracking); + +using namespace o2::tpc::qc; +using namespace o2::gpu; + +Tracking::Tracking() = default; +Tracking::~Tracking() = default; + +static constexpr int QAMODE = 7; // Efficiency (1) | Res (2) | Pull (3), others are not supported from external input! + +//______________________________________________________________________________ +void Tracking::initialize(outputModes outputMode, bool postprocessOnly) +{ + mOutputMode = outputMode; + mQAConfig = std::make_unique<GPUO2InterfaceConfiguration>(); + const auto grp = o2::parameters::GRPObject::loadFrom(); + if (grp) { + mQAConfig->configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + mQAConfig->configGRP.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; + } else { + throw std::runtime_error("Failed to initialize run parameters from GRP"); + } + mQAConfig->ReadConfigurableParam(); + mQAConfig->configQA.shipToQCAsCanvas = mOutputMode == outputLayout; + mQA = std::make_unique<GPUO2InterfaceQA>(mQAConfig.get()); + if (!postprocessOnly) { + mQA->initializeForProcessing(QAMODE); + } +} + +//______________________________________________________________________________ +void Tracking::resetHistograms() +{ + mQA->resetHists(); +} + +//______________________________________________________________________________ +void Tracking::processTracks(const std::vector<o2::tpc::TrackTPC>* tracks, const std::vector<o2::MCCompLabel>* tracksMC, const o2::tpc::ClusterNativeAccess* clNative, TObjArray* out) +{ + mQA->runQA(tracks, tracksMC, clNative); + if (mOutputMode == outputPostprocessed || mOutputMode == outputLayout) { + mQA->postprocess(*out); + } +} + +int Tracking::postprocess(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out) +{ + return mQA->postprocessExternal(in1, in2, in3, out, QAMODE); +} + +void Tracking::getHists(const std::vector<TH1F>*& h1, const std::vector<TH2F>*& h2, const std::vector<TH1D>*& h3) const +{ + mQA->getHists(h1, h2, h3); +} diff --git a/Detectors/TPC/qc/src/Tracks.cxx b/Detectors/TPC/qc/src/Tracks.cxx index 6b24975cd88a3..825eb9b7d183a 100644 --- a/Detectors/TPC/qc/src/Tracks.cxx +++ b/Detectors/TPC/qc/src/Tracks.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ // o2 includes #include "DataFormatsTPC/TrackTPC.h" #include "TPCQC/Tracks.h" +#include "TPCQC/Helpers.h" ClassImp(o2::tpc::qc::Tracks); @@ -27,21 +29,36 @@ using namespace o2::tpc::qc; //______________________________________________________________________________ void Tracks::initializeHistograms() { - mHist1D.emplace_back("hNClustersBeforeCuts", "Number of clusters before cuts;# TPC clusters", 160, -0.5, 159.5); - mHist1D.emplace_back("hNClustersAfterCuts", "Number of clusters after cuts;# TPC clusters", 160, -0.5, 159.5); - mHist1D.emplace_back("hEta", "Pseudorapidity;eta", 400, -2., 2.); - mHist1D.emplace_back("hPhiAside", "Azimuthal angle, A side;phi", 360, 0., 2 * M_PI); - mHist1D.emplace_back("hPhiCside", "Azimuthal angle, C side;phi", 360, 0., 2 * M_PI); - mHist1D.emplace_back("hPt", "Transverse momentum;p_T", 200, 0., 10.); - mHist1D.emplace_back("hSign", "Sign of electric charge;charge sign", 3, -1.5, 1.5); - - mHist2D.emplace_back("h2DNClustersEta", "Number of clusters vs. eta;eta;# TPC clusters", 400, -2., 2., 160, -0.5, 159.5); - mHist2D.emplace_back("h2DNClustersPhiAside", "Number of clusters vs. phi, A side ;phi;# TPC clusters", 360, 0., 2 * M_PI, 160, -0.5, 159.5); - mHist2D.emplace_back("h2DNClustersPhiCside", "Number of clusters vs. phi, C side ;phi;# TPC clusters", 360, 0., 2 * M_PI, 160, -0.5, 159.5); - mHist2D.emplace_back("h2DNClustersPt", "Number of clusters vs. p_T;p_T;# TPC clusters", 200, 0., 10., 160, -0.5, 159.5); - mHist2D.emplace_back("h2DEtaPhi", "Tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); - mHist2D.emplace_back("h2DEtaPhiNeg", "Negative tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); - mHist2D.emplace_back("h2DEtaPhiPos", "Positive tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); + const auto logPtBinning = helpers::makeLogBinning(30, 0.1, 20); + + mHist1D.emplace_back("hNClustersBeforeCuts", "Number of clusters before cuts;# TPC clusters", 160, -0.5, 159.5); //| mHist1D[0] + mHist1D.emplace_back("hNClustersAfterCuts", "Number of clusters after cuts;# TPC clusters", 160, -0.5, 159.5); //| mHist1D[1] + mHist1D.emplace_back("hEta", "Pseudorapidity;eta", 400, -2., 2.); //| mHist1D[2] + mHist1D.emplace_back("hPhiAside", "Azimuthal angle, A side;phi", 360, 0., 2 * M_PI); //| mHist1D[3] + mHist1D.emplace_back("hPhiCside", "Azimuthal angle, C side;phi", 360, 0., 2 * M_PI); //| mHist1D[4] + mHist1D.emplace_back("hPt", "Transverse momentum;p_T", logPtBinning.size() - 1, logPtBinning.data()); //| mHist1D[5] + mHist1D.emplace_back("hSign", "Sign of electric charge;charge sign", 3, -1.5, 1.5); //| mHist1D[6] + mHist1D.emplace_back("hEtaNeg", "Pseudorapidity, neg. tracks;eta", 400, -2., 2.); //| mHist1D[7] + mHist1D.emplace_back("hEtaPos", "Pseudorapidity, pos. tracks;eta", 400, -2., 2.); //| mHist1D[8] + mHist1D.emplace_back("hPhiAsideNeg", "Azimuthal angle, A side, neg. tracks;phi", 360, 0., 2 * M_PI); //| mHist1D[9] + mHist1D.emplace_back("hPhiAsidePos", "Azimuthal angle, A side, pos. tracks;phi", 360, 0., 2 * M_PI); //| mHist1D[10] + mHist1D.emplace_back("hPhiCsideNeg", "Azimuthal angle, C side, neg. tracks;phi", 360, 0., 2 * M_PI); //| mHist1D[11] + mHist1D.emplace_back("hPhiCsidePos", "Azimuthal angle, C side, pos. tracks;phi", 360, 0., 2 * M_PI); //| mHist1D[12] + mHist1D.emplace_back("hPtNeg", "Transverse momentum, neg. tracks;p_T", logPtBinning.size() - 1, logPtBinning.data()); //| mHist1D[13] + mHist1D.emplace_back("hPtPos", "Transverse momentum, pos. tracks;p_T", logPtBinning.size() - 1, logPtBinning.data()); //| mHist1D[14] + + mHist2D.emplace_back("h2DNClustersEta", "Number of clusters vs. eta;eta;# TPC clusters", 400, -2., 2., 160, -0.5, 159.5); //| mHist2D[0] + mHist2D.emplace_back("h2DNClustersPhiAside", "Number of clusters vs. phi, A side ;phi;# TPC clusters", 360, 0., 2 * M_PI, 160, -0.5, 159.5); //| mHist2D[1] + mHist2D.emplace_back("h2DNClustersPhiCside", "Number of clusters vs. phi, C side ;phi;# TPC clusters", 360, 0., 2 * M_PI, 160, -0.5, 159.5); //| mHist2D[2] + mHist2D.emplace_back("h2DNClustersPt", "Number of clusters vs. p_T;p_T;# TPC clusters", logPtBinning.size() - 1, logPtBinning.data(), 160, -0.5, 159.5); //| mHist2D[3] + mHist2D.emplace_back("h2DEtaPhi", "Tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); //| mHist2D[4] + mHist2D.emplace_back("h2DEtaPhiNeg", "Negative tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); //| mHist2D[5] + mHist2D.emplace_back("h2DEtaPhiPos", "Positive tracks in eta vs. phi;phi;eta", 360, 0., 2 * M_PI, 400, -2., 2.); //| mHist2D[6] + + mHistRatio1D.emplace_back("hEtaRatio", "Pseudorapidity, ratio neg./pos. ;eta", 400, -2., 2.); //| mHistRatio1D[0] + mHistRatio1D.emplace_back("hPhiAsideRatio", "Azimuthal angle, A side, ratio neg./pos. ;phi", 360, 0., 2 * M_PI); //| mHistRatio1D[1] + mHistRatio1D.emplace_back("hPhiCsideRatio", "Azimuthal angle, C side, ratio neg./pos. ;phi", 360, 0., 2 * M_PI); //| mHistRatio1D[2] + mHistRatio1D.emplace_back("hPtRatio", "Transverse momentum, ratio neg./pos. ;p_T", logPtBinning.size() - 1, logPtBinning.data()); //| mHistRatio1D[3] } //______________________________________________________________________________ @@ -87,6 +104,24 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) mHist1D[5].Fill(pt); mHist1D[6].Fill(sign); + if (sign < 0.) { + mHist1D[7].Fill(eta); + mHist1D[13].Fill(pt); + if (eta > 0.) { + mHist1D[9].Fill(phi); + } else { + mHist1D[11].Fill(phi); + } + } else { + mHist1D[8].Fill(eta); + mHist1D[14].Fill(pt); + if (eta > 0.) { + mHist1D[10].Fill(phi); + } else { + mHist1D[12].Fill(phi); + } + } + // ===| 2D histogram filling |=== mHist2D[0].Fill(eta, nCls); @@ -108,6 +143,16 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) return true; } +//______________________________________________________________________________ +void Tracks::processEndOfCycle() +{ + // ===| Dividing of 1D histograms -> Ratios |=== + mHistRatio1D[0].Divide(&mHist1D[7], &mHist1D[8]); + mHistRatio1D[1].Divide(&mHist1D[9], &mHist1D[10]); + mHistRatio1D[2].Divide(&mHist1D[11], &mHist1D[12]); + mHistRatio1D[3].Divide(&mHist1D[13], &mHist1D[14]); +} + //______________________________________________________________________________ void Tracks::dumpToFile(std::string_view filename) { diff --git a/Detectors/TPC/qc/test/test_Clusters.cxx b/Detectors/TPC/qc/test/test_Clusters.cxx index 429c6ce8f72d0..25a7c8b6d7f63 100644 --- a/Detectors/TPC/qc/test/test_Clusters.cxx +++ b/Detectors/TPC/qc/test/test_Clusters.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/qc/test/test_PID.cxx b/Detectors/TPC/qc/test/test_PID.cxx index f0a830af868ca..0393e466a2458 100644 --- a/Detectors/TPC/qc/test/test_PID.cxx +++ b/Detectors/TPC/qc/test/test_PID.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/qc/test/test_TrackCuts.cxx b/Detectors/TPC/qc/test/test_TrackCuts.cxx deleted file mode 100644 index a86ad7fe56754..0000000000000 --- a/Detectors/TPC/qc/test/test_TrackCuts.cxx +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test TPC QC -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include <boost/test/unit_test.hpp> -#include "TPCQC/TrackCuts.h" - -BOOST_AUTO_TEST_CASE(ReadWriteROOTFile) -{ - o2::tpc::qc::TrackCuts trackcuts; -} diff --git a/Detectors/TPC/qc/test/test_Tracks.cxx b/Detectors/TPC/qc/test/test_Tracks.cxx index 23278497fb32e..fef57df15c62e 100644 --- a/Detectors/TPC/qc/test/test_Tracks.cxx +++ b/Detectors/TPC/qc/test/test_Tracks.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/CMakeLists.txt b/Detectors/TPC/reconstruction/CMakeLists.txt index e7456f146032a..5d010bf3ad6ba 100644 --- a/Detectors/TPC/reconstruction/CMakeLists.txt +++ b/Detectors/TPC/reconstruction/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TPCReconstruction TARGETVARNAME targetName @@ -18,17 +19,22 @@ o2_add_library(TPCReconstruction src/HwClusterer.cxx src/HwClustererParam.cxx src/KrBoxClusterFinder.cxx + src/KrBoxClusterFinderParam.cxx src/RawReader.cxx src/RawReaderCRU.cxx src/RawReaderEventSync.cxx src/SyncPatternMonitor.cxx - src/GPUCATracking.cxx + src/TPCTrackingDigitsPreCheck.cxx src/HardwareClusterDecoder.cxx src/DigitalCurrentClusterIntegrator.cxx src/TPCFastTransformHelperO2.cxx src/CTFCoder.cxx - PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimulationDataFormat - O2::TPCBase O2::GPUTracking + src/RawProcessingHelpers.cxx + PUBLIC_LINK_LIBRARIES FairRoot::Base + O2::SimulationDataFormat + O2::TPCBase + O2::GPUO2Interface + O2::TPCFastTransformation O2::DetectorsRaw) o2_target_root_dictionary( @@ -42,16 +48,17 @@ o2_target_root_dictionary( include/TPCReconstruction/HwClusterer.h include/TPCReconstruction/HwClustererParam.h include/TPCReconstruction/KrBoxClusterFinder.h - include/TPCReconstruction/KrCluster.h + include/TPCReconstruction/KrBoxClusterFinderParam.h include/TPCReconstruction/RawReader.h include/TPCReconstruction/RawReaderCRU.h include/TPCReconstruction/RawReaderEventSync.h include/TPCReconstruction/SyncPatternMonitor.h - include/TPCReconstruction/GPUCATracking.h + include/TPCReconstruction/TPCTrackingDigitsPreCheck.h include/TPCReconstruction/HardwareClusterDecoder.h include/TPCReconstruction/DigitalCurrentClusterIntegrator.h include/TPCReconstruction/TPCFastTransformHelperO2.h - include/TPCReconstruction/CTFCoder.h) + include/TPCReconstruction/CTFCoder.h + include/TPCReconstruction/RawProcessingHelpers.h) o2_add_executable(read-gbtframes COMPONENT_NAME tpc @@ -102,7 +109,8 @@ o2_add_test(FastTransform LABELS tpc PUBLIC_LINK_LIBRARIES O2::TPCReconstruction SOURCES test/testTPCFastTransform.cxx - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) # CONFIGURATIONS RelWithDebInfo) + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + CONFIGURATIONS RelWithDebInfo Release MinRelSize) # FIXME: should be moved to TPCCalibration as it requires O2::TPCCalibration # which is built after TPCReconstruction @@ -113,7 +121,7 @@ o2_add_test_root_macro(macro/readClusters.C PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::SimulationDataFormat O2::TPCBase - LABELS tpc) + LABELS tpc COMPILE_ONLY) o2_add_test_root_macro(macro/testRawRead.C PUBLIC_LINK_LIBRARIES O2::TPCReconstruction LABELS tpc) @@ -123,7 +131,7 @@ o2_add_test_root_macro(macro/createTPCSpaceChargeCorrection.C PUBLIC_LINK_LIBRARIES O2::TPCReconstruction O2::CommonConstants O2::CommonUtils - O2::TPCSpaceChargeBase + O2::TPCSpaceCharge LABELS tpc) o2_add_test_root_macro(macro/findKrBoxCluster.C diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/AdcClockMonitor.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/AdcClockMonitor.h index 3fd010dd7e724..caf13e1c4e5bc 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/AdcClockMonitor.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/AdcClockMonitor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h index 6e2bca379cfcd..2bed0af0d7c55 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include <iterator> #include <string> #include <cassert> +#include <tuple> #include <type_traits> #include <typeinfo> #include <vector> @@ -27,6 +29,7 @@ #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/CTFCoderBase.h" #include "rANS/rans.h" +#include "rANS/utils.h" class TTree; @@ -35,11 +38,71 @@ namespace o2 namespace tpc { +namespace detail +{ + +template <int A, int B> +struct combinedType { + using type = std::conditional_t<(A + B > 16), uint32_t, std::conditional_t<(A + B > 8), uint16_t, uint8_t>>; +}; + +template <int A, int B> +using combinedType_t = typename combinedType<A, B>::type; + +template <typename value_T, size_t shift> +class ShiftFunctor +{ + public: + template <typename iterA_T, typename iterB_T> + inline value_T operator()(iterA_T iterA, iterB_T iterB) const + { + return *iterB + (static_cast<value_T>(*iterA) << shift); + }; + + template <typename iterA_T, typename iterB_T> + inline void operator()(iterA_T iterA, iterB_T iterB, value_T value) const + { + *iterA = value >> shift; + *iterB = value & ((0x1 << shift) - 0x1); + }; +}; + +template <typename iterA_T, typename iterB_T, typename F> +auto makeInputIterators(iterA_T iterA, iterB_T iterB, size_t nElements, F functor) +{ + using namespace o2::rans::utils; + + auto advanceIter = [](auto iter, size_t nElements) { + auto tmp = iter; + std::advance(tmp, nElements); + return tmp; + }; + + return std::make_tuple(CombinedInputIterator{iterA, iterB, functor}, + CombinedInputIterator{advanceIter(iterA, nElements), advanceIter(iterB, nElements), functor}); +}; + +template <int bits_A, int bits_B> +struct MergedColumnsDecoder { + + using combined_t = combinedType_t<bits_A, bits_B>; + + template <typename iterA_T, typename iterB_T, typename F> + static void decode(iterA_T iterA, iterB_T iterB, CTF::Slots slot, F decodingFunctor) + { + ShiftFunctor<combined_t, bits_B> f{}; + auto iter = rans::utils::CombinedOutputIteratorFactory<combined_t>::makeIter(iterA, iterB, f); + + decodingFunctor(iter, slot); + } +}; + +} // namespace detail + class CTFCoder : public o2::ctf::CTFCoderBase { public: CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::TPC) {} - ~CTFCoder() = default; /// entropy-encode compressed clusters to flat buffer template <typename VEC> @@ -79,55 +142,32 @@ class CTFCoder : public o2::ctf::CTFCoderBase private: void checkDataDictionaryConsistency(const CTFHeader& h); - template <int NU, int NL> - static constexpr auto MVAR() - { - typename std::conditional<(NU + NL > 16), uint32_t, typename std::conditional<(NU + NL > 8), uint16_t, uint8_t>::type>::type tp = 0; - return tp; - } - template <int NU, int NL> - static constexpr auto MPTR() - { - typename std::conditional<(NU + NL > 16), uint32_t, typename std::conditional<(NU + NL > 8), uint16_t, uint8_t>::type>::type* tp = nullptr; - return tp; - } -#define MTYPE(A, B) decltype(CTFCoder::MVAR<A, B>()) - template <int NU, int NL, typename CU, typename CL> - static void splitColumns(const std::vector<MTYPE(NU, NL)>& vm, CU*& vu, CL*& vl); + static void splitColumns(const std::vector<detail::combinedType_t<NU, NL>>& vm, CU*& vu, CL*& vl); - template <int NU, int NL, typename CU, typename CL> - static auto mergeColumns(const CU* vu, const CL* vl, size_t nelem); + template <typename source_T> + void buildCoder(ctf::CTFCoderBase::OpType coderType, const CTF::container_t& ctf, CTF::Slots slot); bool mCombineColumns = false; // combine correlated columns ClassDefNV(CTFCoder, 1); }; -/// split words of input vector to columns assigned to provided pointers (memory must be allocated in advance) -template <int NU, int NL, typename CU, typename CL> -void CTFCoder::splitColumns(const std::vector<MTYPE(NU, NL)>& vm, CU*& vu, CL*& vl) +template <typename source_T> +void CTFCoder::buildCoder(ctf::CTFCoderBase::OpType coderType, const CTF::container_t& ctf, CTF::Slots slot) { - static_assert(NU <= sizeof(CU) * 8 && NL <= sizeof(CL) * 8, "output columns bit count is wrong"); - size_t n = vm.size(); - for (size_t i = 0; i < n; i++) { - vu[i] = static_cast<CU>(vm[i] >> NL); - vl[i] = static_cast<CL>(vm[i] & ((0x1 << NL) - 1)); - } -} + auto buildFrequencyTable = [](const CTF::container_t& ctf, CTF::Slots slot) -> rans::FrequencyTable { + rans::FrequencyTable frequencyTable; + auto block = ctf.getBlock(slot); + auto metaData = ctf.getMetadata(slot); + frequencyTable.addFrequencies(block.getDict(), block.getDict() + block.getNDict(), metaData.min, metaData.max); + return frequencyTable; + }; + auto getSymbolTablePrecision = [](const CTF::container_t& ctf, CTF::Slots slot) -> int { + return ctf.getMetadata(slot).probabilityBits; + }; -/// merge elements of 2 columns pointed by vu and vl to a single vector with wider field -template <int NU, int NL, typename CU, typename CL> -auto CTFCoder::mergeColumns(const CU* vu, const CL* vl, size_t nelem) -{ - // merge 2 columns to 1 - static_assert(NU <= sizeof(NU) * 8 && NL <= sizeof(NL) * 8, "input columns bit count is wrong"); - std::vector<MTYPE(NU, NL)> outv; - outv.reserve(nelem); - for (size_t i = 0; i < nelem; i++) { - outv.push_back((static_cast<MTYPE(NU, NL)>(vu[i]) << NL) | static_cast<MTYPE(NU, NL)>(vl[i])); - } - return std::move(outv); + this->createCoder<source_T>(coderType, buildFrequencyTable(ctf, slot), getSymbolTablePrecision(ctf, slot), static_cast<int>(slot)); } /// entropy-encode clusters to buffer with CTF @@ -135,6 +175,7 @@ template <typename VEC> void CTFCoder::encode(VEC& buff, const CompressedClusters& ccl) { using MD = o2::ctf::Metadata::OptStore; + using namespace detail; // what to do which each field: see o2::ctf::Metadata explanation constexpr MD optField[CTF::getNBlocks()] = { MD::EENCODE, //qTotA @@ -171,76 +212,80 @@ void CTFCoder::encode(VEC& buff, const CompressedClusters& ccl) if (mCombineColumns) { flags |= CTFHeader::CombinedColumns; } - ec->setHeader(CTFHeader{reinterpret_cast<const CompressedClustersCounters&>(ccl), flags}); + ec->setHeader(CTFHeader{0, 1, 0, // dummy timestamp, version 1.0 + ccl, flags}); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); ec->getANSHeader().majorVersion = 0; ec->getANSHeader().minorVersion = 1; - // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec -#define ENCODETPC(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); - // clang-format off + + auto encodeTPC = [&buff, &optField, &coders = mCoders](auto begin, auto end, CTF::Slots slot, size_t probabilityBits) { + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec + const auto slotVal = static_cast<int>(slot); + CTF::get(buff.data())->encode(begin, end, slotVal, probabilityBits, optField[slotVal], &buff, coders[slotVal].get()); + }; if (mCombineColumns) { - auto mrg = mergeColumns<CTF::NBitsQTot, CTF::NBitsQMax>(ccl.qTotA, ccl.qMaxA, ccl.nAttachedClusters); - ENCODETPC(&mrg[0], (&mrg[0]) + ccl.nAttachedClusters, CTF::BLCqTotA, 0); - } - else { - ENCODETPC(ccl.qTotA, ccl.qTotA + ccl.nAttachedClusters, CTF::BLCqTotA, 0); + const auto [begin, end] = makeInputIterators(ccl.qTotA, ccl.qMaxA, ccl.nAttachedClusters, + ShiftFunctor<combinedType_t<CTF::NBitsQTot, CTF::NBitsQMax>, CTF::NBitsQMax>{}); + encodeTPC(begin, end, CTF::BLCqTotA, 0); + } else { + encodeTPC(ccl.qTotA, ccl.qTotA + ccl.nAttachedClusters, CTF::BLCqTotA, 0); } - ENCODETPC(ccl.qMaxA, ccl.qMaxA + (mCombineColumns ? 0 : ccl.nAttachedClusters), CTF::BLCqMaxA, 0); - - ENCODETPC(ccl.flagsA, ccl.flagsA + ccl.nAttachedClusters, CTF::BLCflagsA, 0); - + encodeTPC(ccl.qMaxA, ccl.qMaxA + (mCombineColumns ? 0 : ccl.nAttachedClusters), CTF::BLCqMaxA, 0); + + encodeTPC(ccl.flagsA, ccl.flagsA + ccl.nAttachedClusters, CTF::BLCflagsA, 0); + if (mCombineColumns) { - auto mrg = mergeColumns<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>(ccl.rowDiffA, ccl.sliceLegDiffA, ccl.nAttachedClustersReduced); - ENCODETPC(&mrg[0], (&mrg[0]) + ccl.nAttachedClustersReduced, CTF::BLCrowDiffA, 0); - } - else { - ENCODETPC(ccl.rowDiffA, ccl.rowDiffA + ccl.nAttachedClustersReduced, CTF::BLCrowDiffA, 0); + const auto [begin, end] = makeInputIterators(ccl.rowDiffA, ccl.sliceLegDiffA, ccl.nAttachedClustersReduced, + ShiftFunctor<combinedType_t<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>, CTF::NBitsSliceLegDiff>{}); + encodeTPC(begin, end, CTF::BLCrowDiffA, 0); + } else { + encodeTPC(ccl.rowDiffA, ccl.rowDiffA + ccl.nAttachedClustersReduced, CTF::BLCrowDiffA, 0); } - ENCODETPC(ccl.sliceLegDiffA, ccl.sliceLegDiffA + (mCombineColumns ? 0 : ccl.nAttachedClustersReduced), CTF::BLCsliceLegDiffA, 0); + encodeTPC(ccl.sliceLegDiffA, ccl.sliceLegDiffA + (mCombineColumns ? 0 : ccl.nAttachedClustersReduced), CTF::BLCsliceLegDiffA, 0); - ENCODETPC(ccl.padResA, ccl.padResA + ccl.nAttachedClustersReduced, CTF::BLCpadResA, 0); - ENCODETPC(ccl.timeResA, ccl.timeResA + ccl.nAttachedClustersReduced, CTF::BLCtimeResA, 0); + encodeTPC(ccl.padResA, ccl.padResA + ccl.nAttachedClustersReduced, CTF::BLCpadResA, 0); + encodeTPC(ccl.timeResA, ccl.timeResA + ccl.nAttachedClustersReduced, CTF::BLCtimeResA, 0); if (mCombineColumns) { - auto mrg = mergeColumns<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>(ccl.sigmaPadA, ccl.sigmaTimeA, ccl.nAttachedClusters); - ENCODETPC(&mrg[0], &mrg[0] + ccl.nAttachedClusters, CTF::BLCsigmaPadA, 0); + const auto [begin, end] = makeInputIterators(ccl.sigmaPadA, ccl.sigmaTimeA, ccl.nAttachedClusters, + ShiftFunctor<combinedType_t<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>, CTF::NBitsSigmaTime>{}); + encodeTPC(begin, end, CTF::BLCsigmaPadA, 0); + } else { + encodeTPC(ccl.sigmaPadA, ccl.sigmaPadA + ccl.nAttachedClusters, CTF::BLCsigmaPadA, 0); } - else { - ENCODETPC(ccl.sigmaPadA, ccl.sigmaPadA + ccl.nAttachedClusters, CTF::BLCsigmaPadA, 0); - } - ENCODETPC(ccl.sigmaTimeA, ccl.sigmaTimeA + (mCombineColumns ? 0 : ccl.nAttachedClusters), CTF::BLCsigmaTimeA, 0); + encodeTPC(ccl.sigmaTimeA, ccl.sigmaTimeA + (mCombineColumns ? 0 : ccl.nAttachedClusters), CTF::BLCsigmaTimeA, 0); - ENCODETPC(ccl.qPtA, ccl.qPtA + ccl.nTracks, CTF::BLCqPtA, 0); - ENCODETPC(ccl.rowA, ccl.rowA + ccl.nTracks, CTF::BLCrowA, 0); - ENCODETPC(ccl.sliceA, ccl.sliceA + ccl.nTracks, CTF::BLCsliceA, 0); - ENCODETPC(ccl.timeA, ccl.timeA + ccl.nTracks, CTF::BLCtimeA, 0); - ENCODETPC(ccl.padA, ccl.padA + ccl.nTracks, CTF::BLCpadA, 0); + encodeTPC(ccl.qPtA, ccl.qPtA + ccl.nTracks, CTF::BLCqPtA, 0); + encodeTPC(ccl.rowA, ccl.rowA + ccl.nTracks, CTF::BLCrowA, 0); + encodeTPC(ccl.sliceA, ccl.sliceA + ccl.nTracks, CTF::BLCsliceA, 0); + encodeTPC(ccl.timeA, ccl.timeA + ccl.nTracks, CTF::BLCtimeA, 0); + encodeTPC(ccl.padA, ccl.padA + ccl.nTracks, CTF::BLCpadA, 0); if (mCombineColumns) { - auto mrg = mergeColumns<CTF::NBitsQTot, CTF::NBitsQMax>(ccl.qTotU,ccl.qMaxU,ccl.nUnattachedClusters); - ENCODETPC(&mrg[0], &mrg[0] + ccl.nUnattachedClusters, CTF::BLCqTotU, 0); - } - else { - ENCODETPC(ccl.qTotU, ccl.qTotU + ccl.nUnattachedClusters, CTF::BLCqTotU, 0); + const auto [begin, end] = makeInputIterators(ccl.qTotU, ccl.qMaxU, ccl.nUnattachedClusters, + ShiftFunctor<combinedType_t<CTF::NBitsQTot, CTF::NBitsQMax>, CTF::NBitsQMax>{}); + encodeTPC(begin, end, CTF::BLCqTotU, 0); + } else { + encodeTPC(ccl.qTotU, ccl.qTotU + ccl.nUnattachedClusters, CTF::BLCqTotU, 0); } - ENCODETPC(ccl.qMaxU, ccl.qMaxU + (mCombineColumns ? 0 : ccl.nUnattachedClusters), CTF::BLCqMaxU, 0); + encodeTPC(ccl.qMaxU, ccl.qMaxU + (mCombineColumns ? 0 : ccl.nUnattachedClusters), CTF::BLCqMaxU, 0); - ENCODETPC(ccl.flagsU, ccl.flagsU + ccl.nUnattachedClusters, CTF::BLCflagsU, 0); - ENCODETPC(ccl.padDiffU, ccl.padDiffU + ccl.nUnattachedClusters, CTF::BLCpadDiffU, 0); - ENCODETPC(ccl.timeDiffU, ccl.timeDiffU + ccl.nUnattachedClusters, CTF::BLCtimeDiffU, 0); + encodeTPC(ccl.flagsU, ccl.flagsU + ccl.nUnattachedClusters, CTF::BLCflagsU, 0); + encodeTPC(ccl.padDiffU, ccl.padDiffU + ccl.nUnattachedClusters, CTF::BLCpadDiffU, 0); + encodeTPC(ccl.timeDiffU, ccl.timeDiffU + ccl.nUnattachedClusters, CTF::BLCtimeDiffU, 0); if (mCombineColumns) { - auto mrg = mergeColumns<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>(ccl.sigmaPadU, ccl.sigmaTimeU, ccl.nUnattachedClusters); - ENCODETPC(&mrg[0], &mrg[0] + ccl.nUnattachedClusters, CTF::BLCsigmaPadU, 0); + const auto [begin, end] = makeInputIterators(ccl.sigmaPadU, ccl.sigmaTimeU, ccl.nUnattachedClusters, + ShiftFunctor<combinedType_t<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>, CTF::NBitsSigmaTime>{}); + encodeTPC(begin, end, CTF::BLCsigmaPadU, 0); + } else { + encodeTPC(ccl.sigmaPadU, ccl.sigmaPadU + ccl.nUnattachedClusters, CTF::BLCsigmaPadU, 0); } - else { - ENCODETPC(ccl.sigmaPadU, ccl.sigmaPadU + ccl.nUnattachedClusters, CTF::BLCsigmaPadU, 0); - } - ENCODETPC(ccl.sigmaTimeU, ccl.sigmaTimeU + (mCombineColumns ? 0 : ccl.nUnattachedClusters), CTF::BLCsigmaTimeU, 0); + encodeTPC(ccl.sigmaTimeU, ccl.sigmaTimeU + (mCombineColumns ? 0 : ccl.nUnattachedClusters), CTF::BLCsigmaTimeU, 0); - ENCODETPC(ccl.nTrackClusters, ccl.nTrackClusters + ccl.nTracks, CTF::BLCnTrackClusters, 0); - ENCODETPC(ccl.nSliceRowClusters, ccl.nSliceRowClusters + ccl.nSliceRows, CTF::BLCnSliceRowClusters, 0); - // clang-format on + encodeTPC(ccl.nTrackClusters, ccl.nTrackClusters + ccl.nTracks, CTF::BLCnTrackClusters, 0); + encodeTPC(ccl.nSliceRowClusters, ccl.nSliceRowClusters + ccl.nSliceRows, CTF::BLCnSliceRowClusters, 0); CTF::get(buff.data())->print(getPrefix()); } @@ -248,11 +293,13 @@ void CTFCoder::encode(VEC& buff, const CompressedClusters& ccl) template <typename VEC> void CTFCoder::decode(const CTF::base& ec, VEC& buffVec) { + using namespace detail; CompressedClusters cc; CompressedClustersCounters& ccCount = cc; auto& header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); checkDataDictionaryConsistency(header); - ccCount = reinterpret_cast<const CompressedClustersCounters&>(header); + ccCount = static_cast<const CompressedClustersCounters&>(header); CompressedClustersFlat* ccFlat = nullptr; size_t sizeCFlatBody = alignSize(ccFlat); size_t sz = sizeCFlatBody + estimateSize(cc); // total size of the buffVec accounting for the alignment @@ -266,78 +313,64 @@ void CTFCoder::decode(const CTF::base& ec, VEC& buffVec) ec.print(getPrefix()); // decode encoded data directly to destination buff -#define DECODETPC(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) - // clang-format off + auto decodeTPC = [&ec, &coders = mCoders](auto begin, CTF::Slots slot) { + const auto slotVal = static_cast<int>(slot); + ec.decode(begin, slotVal, coders[slotVal].get()); + }; + if (mCombineColumns) { - std::vector<MTYPE(CTF::NBitsQTot, CTF::NBitsQMax)> mrg; - DECODETPC(mrg, CTF::BLCqTotA); - splitColumns<CTF::NBitsQTot, CTF::NBitsQMax>(mrg, cc.qTotA, cc.qMaxA); - } - else { - DECODETPC(cc.qTotA, CTF::BLCqTotA); - DECODETPC(cc.qMaxA, CTF::BLCqMaxA); + detail::MergedColumnsDecoder<CTF::NBitsQTot, CTF::NBitsQMax>::decode(cc.qTotA, cc.qMaxA, CTF::BLCqTotA, decodeTPC); + } else { + decodeTPC(cc.qTotA, CTF::BLCqTotA); + decodeTPC(cc.qMaxA, CTF::BLCqMaxA); } - - DECODETPC(cc.flagsA, CTF::BLCflagsA); - + + decodeTPC(cc.flagsA, CTF::BLCflagsA); + if (mCombineColumns) { - std::vector<MTYPE(CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff)> mrg; - DECODETPC(mrg, CTF::BLCrowDiffA); - splitColumns<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>(mrg, cc.rowDiffA, cc.sliceLegDiffA); + detail::MergedColumnsDecoder<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>::decode(cc.rowDiffA, cc.sliceLegDiffA, CTF::BLCrowDiffA, decodeTPC); + } else { + decodeTPC(cc.rowDiffA, CTF::BLCrowDiffA); + decodeTPC(cc.sliceLegDiffA, CTF::BLCsliceLegDiffA); } - else { - DECODETPC(cc.rowDiffA, CTF::BLCrowDiffA); - DECODETPC(cc.sliceLegDiffA, CTF::BLCsliceLegDiffA); - } - - DECODETPC(cc.padResA, CTF::BLCpadResA); - DECODETPC(cc.timeResA, CTF::BLCtimeResA); + + decodeTPC(cc.padResA, CTF::BLCpadResA); + decodeTPC(cc.timeResA, CTF::BLCtimeResA); if (mCombineColumns) { - std::vector<MTYPE(CTF::NBitsSigmaPad, CTF::NBitsSigmaTime)> mrg; - DECODETPC(mrg, CTF::BLCsigmaPadA); - splitColumns<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>(mrg, cc.sigmaPadA, cc.sigmaTimeA); + detail::MergedColumnsDecoder<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>::decode(cc.sigmaPadA, cc.sigmaTimeA, CTF::BLCsigmaPadA, decodeTPC); + } else { + decodeTPC(cc.sigmaPadA, CTF::BLCsigmaPadA); + decodeTPC(cc.sigmaTimeA, CTF::BLCsigmaTimeA); } - else { - DECODETPC(cc.sigmaPadA, CTF::BLCsigmaPadA); - DECODETPC(cc.sigmaTimeA, CTF::BLCsigmaTimeA); - } - - DECODETPC(cc.qPtA, CTF::BLCqPtA); - DECODETPC(cc.rowA, CTF::BLCrowA); - DECODETPC(cc.sliceA, CTF::BLCsliceA); - DECODETPC(cc.timeA, CTF::BLCtimeA); - DECODETPC(cc.padA, CTF::BLCpadA); + + decodeTPC(cc.qPtA, CTF::BLCqPtA); + decodeTPC(cc.rowA, CTF::BLCrowA); + decodeTPC(cc.sliceA, CTF::BLCsliceA); + decodeTPC(cc.timeA, CTF::BLCtimeA); + decodeTPC(cc.padA, CTF::BLCpadA); if (mCombineColumns) { - std::vector<MTYPE(CTF::NBitsQTot, CTF::NBitsQMax)> mrg; - DECODETPC(mrg, CTF::BLCqTotU); - splitColumns<CTF::NBitsQTot, CTF::NBitsQMax>(mrg, cc.qTotU, cc.qMaxU); - } - else { - DECODETPC(cc.qTotU, CTF::BLCqTotU); - DECODETPC(cc.qMaxU, CTF::BLCqMaxU); + detail::MergedColumnsDecoder<CTF::NBitsQTot, CTF::NBitsQMax>::decode(cc.qTotU, cc.qMaxU, CTF::BLCqTotU, decodeTPC); + } else { + decodeTPC(cc.qTotU, CTF::BLCqTotU); + decodeTPC(cc.qMaxU, CTF::BLCqMaxU); } - DECODETPC(cc.flagsU, CTF::BLCflagsU); - DECODETPC(cc.padDiffU, CTF::BLCpadDiffU); - DECODETPC(cc.timeDiffU, CTF::BLCtimeDiffU); + decodeTPC(cc.flagsU, CTF::BLCflagsU); + decodeTPC(cc.padDiffU, CTF::BLCpadDiffU); + decodeTPC(cc.timeDiffU, CTF::BLCtimeDiffU); if (mCombineColumns) { - std::vector<MTYPE(CTF::NBitsSigmaPad, CTF::NBitsSigmaTime)> mrg; - DECODETPC(mrg, CTF::BLCsigmaPadU); - splitColumns<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>(mrg, cc.sigmaPadU, cc.sigmaTimeU); - } - else { - DECODETPC(cc.sigmaPadU, CTF::BLCsigmaPadU); - DECODETPC(cc.sigmaTimeU, CTF::BLCsigmaTimeU); + detail::MergedColumnsDecoder<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>::decode(cc.sigmaPadU, cc.sigmaTimeU, CTF::BLCsigmaPadU, decodeTPC); + } else { + decodeTPC(cc.sigmaPadU, CTF::BLCsigmaPadU); + decodeTPC(cc.sigmaTimeU, CTF::BLCsigmaTimeU); } - - DECODETPC(cc.nTrackClusters, CTF::BLCnTrackClusters); - DECODETPC(cc.nSliceRowClusters, CTF::BLCnSliceRowClusters); - // clang-format on + + decodeTPC(cc.nTrackClusters, CTF::BLCnTrackClusters); + decodeTPC(cc.nSliceRowClusters, CTF::BLCnSliceRowClusters); } -#undef MTYPE } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h index 84d3acc55e2c2..d86a845b0fe4c 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/Clusterer.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/Clusterer.h index 34405c1de783f..02c7094c25a2d 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/Clusterer.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/Clusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h index 071ded988bdf7..00bddef53dfb1 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/DigitalCurrentClusterIntegrator.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/DigitalCurrentClusterIntegrator.h index e30ea4e2ff186..c437f0d162526 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/DigitalCurrentClusterIntegrator.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/DigitalCurrentClusterIntegrator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ class DigitalCurrentClusterIntegrator } void integrateCluster(int sector, int row, float pad, unsigned int charge) { - int ipad = ipad + 0.5; + int ipad = pad + 0.5; if (ipad < 0) { ipad = 0; } diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrame.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrame.h index 289faa3b44272..68b0104f3dd62 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrame.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrame.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrameContainer.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrameContainer.h index c5f6a7afa26e8..c30ab8a14e371 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrameContainer.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/GBTFrameContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h deleted file mode 100644 index 7ff7d2d0e8729..0000000000000 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUCATracking.h -/// \brief Wrapper class for TPC CA Tracker algorithm -/// \author David Rohr -#ifndef ALICEO2_TPC_TPCCATRACKING_H_ -#define ALICEO2_TPC_TPCCATRACKING_H_ -#include <memory> -#include <vector> -#include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/TrackTPC.h" - -namespace o2 -{ -namespace gpu -{ -struct GPUO2InterfaceConfiguration; -struct GPUO2InterfaceIOPtrs; -struct GPUInterfaceOutputs; -class GPUTPCO2Interface; -} // namespace gpu -} // namespace o2 - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template <class T> -class MCTruthContainer; -} -} // namespace o2 - -namespace o2 -{ -namespace tpc -{ - -class GPUCATracking -{ - public: - GPUCATracking(); - ~GPUCATracking(); - GPUCATracking(const GPUCATracking&) = delete; // Disable copy - GPUCATracking& operator=(const GPUCATracking&) = delete; // Disable assignment - - int initialize(const o2::gpu::GPUO2InterfaceConfiguration& config); - void deinitialize(); - - //Input: cluster structure, possibly including MC labels, pointers to std::vectors for tracks and track MC labels. outputTracksMCTruth may be nullptr to indicate missing cluster MC labels. Otherwise, cluster MC labels are assumed to be present. - int runTracking(o2::gpu::GPUO2InterfaceIOPtrs* data, o2::gpu::GPUInterfaceOutputs* outputs = nullptr); - - float getPseudoVDrift(); //Return artificial VDrift used to convert time to Z - void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const; - - int registerMemoryForGPU(const void* ptr, size_t size); - int unregisterMemoryForGPU(const void* ptr); - - private: - std::unique_ptr<o2::gpu::GPUTPCO2Interface> mTrackingCAO2Interface; //Pointer to Interface class in HLT O2 CA Tracking library. - //The tracking code itself is not included in the O2 package, but contained in the CA library. - //The GPUCATracking class interfaces this library via this pointer to GPUTPCO2Interface class. - - static constexpr float sTrackMCMaxFake = 0.1; -}; - -} // namespace tpc -} // namespace o2 -#endif diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/HalfSAMPAData.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/HalfSAMPAData.h index c5c2b98a42325..bfd3ae3417c72 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/HalfSAMPAData.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/HalfSAMPAData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h index 84d1b2b5ed643..cf53f6295aac5 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClusterer.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClusterer.h index 3d9fe3c9a2c76..11e6b442cae7e 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClusterer.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClusterer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClustererParam.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClustererParam.h index 5a48f31ee4a1b..2f426aa5a2b68 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClustererParam.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/HwClustererParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinder.h index 6f8e18b135ecd..e85d4cd3f2c32 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,35 +47,47 @@ /// At least mMinNumberOfNeighbours neighbours (= direct neighbours) has a signal. /// /// Implementation: -/// The RAW data is "expanded" for each sector and stored in a big signal -/// mMapOfAllDigits = 3d vector of all digits +/// Old ansatz: Store every digit in a big 3D map +/// Problem: Memory consumption too large if timebins > 10k +/// New solution: Use rolling map aka "The set of timeslices" /// -/// To make sure that one never has to check if one is inside the sector or not -/// the arrays are larger than a sector. For the size in row-direction, a constant is used. -/// For time and pad direction, a number is set (here is room for improvements). +/// 1 2 3 4 5 6 7 /// -/// When data from a new sector is encountered, the method +/// 1 o o o x o o o +/// 2 o o o x o o o +/// ............. +/// n-1 o o o x o o o +/// n o o o x o o o /// -/// How to use: -/// Load tpcdigits.root -/// Loop over all events +/// x-axis: timeslices +/// y-axis: global pad number +/// In this example, the fourth timeslice is the interesting one. Here, local maxima and clusters are found. After this slice has been processed, the first slice will be dropped and another slice will be added at the last position (seventh position). +/// Afterwards, the algorithm looks for clusters in the middle time slice. +/// +/// How to use (see macro: findKrBoxCluster.C): +/// Create KrBoxClusterFinder object +/// Load gainmap (if available) +/// Make adjustments to clusterfinder (e.g. set min number of neighbours) /// Loop over all sectors -/// Use KrBoxClusterFinder(sector) to create 3D map -/// Use localMaxima() to find..well the local maxima -/// localMaxima() yields a vector of a tuple with three int -/// Loop over this vector and give the tuple to buildCluster() +/// Use "loopOverSector" function for this /// Write to tree or something similar #ifndef ALICEO2_TPC_KrBoxClusterFinder_H_ #define ALICEO2_TPC_KrBoxClusterFinder_H_ #include "DataFormatsTPC/Digit.h" -#include "TPCReconstruction/KrCluster.h" +#include "DataFormatsTPC/KrCluster.h" +#include "TPCReconstruction/KrBoxClusterFinderParam.h" + #include "TPCBase/Mapper.h" +#include "TPCBase/CalDet.h" + #include <tuple> #include <vector> #include <array> +#include <deque> +#include <gsl/span> namespace o2 { @@ -91,55 +104,192 @@ namespace tpc class KrBoxClusterFinder { + private: + /// Maximum Map Dimensions + /// Here is room for improvements + static constexpr size_t MaxPads = 138; ///< Size of the map in pad-direction + static constexpr size_t MaxRows = 152; ///< Size of the map in row-direction + size_t mMaxTimes = 114048; ///< Size of the map in time-direction + public: /// Constructor: - explicit KrBoxClusterFinder(std::vector<o2::tpc::Digit>& eventSector); ///< Creates a 3D Map + /// The constructor allocates a three dimensional array (Pad,Row,Time) which is + /// later filled with the recorded charges for each digit + explicit KrBoxClusterFinder() = default; + + explicit KrBoxClusterFinder(int sector) : mSector(sector){}; + + /// If a gain map exists, the map can be loaded with this function + /// The function expects a CalDet file with a gain map (gain entry for each pad). + void loadGainMapFromFile(const std::string_view calDetFileName, const std::string_view gainMapName = "GainMap"); /// After the map is created, we look for local maxima with this function: - std::vector<std::tuple<int, int, int>> findLocalMaxima(); + std::vector<std::tuple<int, int, int>> findLocalMaxima(bool directFilling = true, const int timeOffset = 0); /// After finding the local maxima, we can now build clusters around it. /// It works according to the explanation at the beginning of the header file. - KrCluster buildCluster(int clusterCenterPad, int clusterCenterRow, int clusterCenterTime); + KrCluster buildCluster(int clusterCenterPad, int clusterCenterRow, int clusterCenterTime, bool directFilling = false, const int timeOffset = 0); + + /// reset cluster vector + void resetClusters() { mClusters.clear(); } + + std::vector<KrCluster>& getClusters() { return mClusters; } + const std::vector<KrCluster>& getClusters() const { return mClusters; } + + /// set sector of this instance + void setSector(int sector) { mSector = sector; } + + /// ger sector of this instance + int getSector() const { return mSector; } + + /// initialize the parameters from KrBoxClusterFinderParam + void init(); + + /// Set Function for minimum number of direct neighbours required + void setMinNumberOfNeighbours(int minNumberOfNeighbours) { mMinNumberOfNeighbours = minNumberOfNeighbours; } + + /// Set Function for minimal charge required for maxCharge of a cluster + void setMinQTreshold(int minQThreshold) { mQThresholdMax = minQThreshold; } + + /// Set Function for minimal charge required for maxCharge of a cluster + void setMaxTimes(int maxTimes) { mMaxTimes = maxTimes; } + + /// Set Function for maximal cluster sizes in different ROCs + void setMaxClusterSize(int maxClusterSizeRowIROC, int maxClusterSizeRowOROC1, int maxClusterSizeRowOROC2, int maxClusterSizeRowOROC3, + int maxClusterSizePadIROC, int maxClusterSizePadOROC1, int maxClusterSizePadOROC2, int maxClusterSizePadOROC3, + int maxClusterSizeTime) + { + mMaxClusterSizeRowIROC = maxClusterSizeRowIROC; + mMaxClusterSizeRowOROC1 = maxClusterSizeRowOROC1; + mMaxClusterSizeRowOROC2 = maxClusterSizeRowOROC2; + mMaxClusterSizeRowOROC3 = maxClusterSizeRowOROC3; + + mMaxClusterSizePadIROC = maxClusterSizePadIROC; + mMaxClusterSizePadOROC1 = maxClusterSizePadOROC1; + mMaxClusterSizePadOROC2 = maxClusterSizePadOROC2; + mMaxClusterSizePadOROC3 = maxClusterSizePadOROC3; + + mMaxClusterSizeTime = maxClusterSizeTime; + } + + void loopOverSector(const gsl::span<const Digit> eventSector, const int sector); + + void loopOverSector(const std::vector<Digit>& eventSector, const int sector) + { + loopOverSector(gsl::span(eventSector.data(), eventSector.size()), sector); + } private: // These variables can be varied + // They were choses such that the box in each readout chamber is approx. the same size + // NOTE: They will be overwritten by the values in KrBoxClusterFinderParam in case the init() function is called int mMaxClusterSizeTime = 3; ///< The "radius" of a cluster in time direction - int mMaxClusterSizePad = 3; ///< radius in pad direction - int mMaxClusterSizeRow = 2; ///< radius in row direction + int mMaxClusterSizeRow; ///< The "radius" of a cluster in row direction + int mMaxClusterSizePad; ///< The "radius" of a cluster in pad direction + + int mMaxClusterSizeRowIROC = 3; ///< The "radius" of a cluster in row direction in IROC + int mMaxClusterSizeRowOROC1 = 2; ///< The "radius" of a cluster in row direction in OROC1 + int mMaxClusterSizeRowOROC2 = 2; ///< The "radius" of a cluster in row direction in OROC2 + int mMaxClusterSizeRowOROC3 = 1; ///< The "radius" of a cluster in row direction in OROC3 - // Todo: Differentiate between different ROCS: - // int mMaxClusterSizeRowIROC = 3; // radius in row direction - // int mMaxClusterSizeRowOROC1 = 2; // radius in row direction - // int mMaxClusterSizeRowOROC2 = 2; // radius in row direction - // int mMaxClusterSizeRowOROC3 = 1; // radius in row direction + int mMaxClusterSizePadIROC = 5; ///< The "radius" of a cluster in pad direction in IROC + int mMaxClusterSizePadOROC1 = 3; ///< The "radius" of a cluster in pad direction in OROC1 + int mMaxClusterSizePadOROC2 = 3; ///< The "radius" of a cluster in pad direction in OROC2 + int mMaxClusterSizePadOROC3 = 3; ///< The "radius" of a cluster in pad direction in OROC3 - float mQThresholdMax = 10.0; ///< the Maximum charge in a cluster must exceed this value or it is discarded + float mQThresholdMax = 30.0; ///< the Maximum charge in a cluster must exceed this value or it is discarded float mQThreshold = 1.0; ///< every charge which is added to a cluster must exceed this value or it is discarded - int mMinNumberOfNeighbours = 1; ///< amount of direct neighbours required for a cluster maximum + int mMinNumberOfNeighbours = 2; ///< amount of direct neighbours required for a cluster maximum - /// Maximum Map Dimensions - /// Here is room for improvements - static constexpr size_t MaxPads = 138; ///< Size of the map in pad-direction - static constexpr size_t MaxRows = 152; ///< Size of the map in row-direction - static constexpr size_t MaxTimes = 550; ///< Size of the map in time-direction + float mCutMinSigmaTime{0}; ///< Min sigma time to accept cluster + float mCutMaxSigmaTime{1000}; ///< Min sigma time to accept cluster + float mCutMinSigmaPad{0}; ///< Min sigma pad to accept cluster + float mCutMaxSigmaPad{1000}; ///< Min sigma pad to accept cluster + float mCutMinSigmaRow{0}; ///< Min sigma row to accept cluster + float mCutMaxSigmaRow{1000}; ///< Min sigma row to accept cluster + float mCutMaxQtot{1e10}; ///< Max Qtot to accept cluster + float mCutQtot0{1e10}; ///< Max Qtot at zero size for Qtot vs. size correlation cut + float mCutQtotSizeSlope{0}; ///< Max Qtot over size slope for Qtot vs. size correlation cut + unsigned char mCutMaxSize{255}; ///< Max cluster size in number of digits + bool mApplyCuts{false}; ///< if to apply cluster cuts above + + int mSector = -1; ///< sector being processed in this instance + std::unique_ptr<CalPad> mGainMap; ///< Gain map object + + /// Values to define ROC boundaries + static constexpr size_t MaxRowsIROC = 63; ///< Amount of rows in IROC + static constexpr size_t MaxRowsOROC1 = 34; ///< Amount of rows in OROC1 + static constexpr size_t MaxRowsOROC2 = 30; ///< Amount of rows in OROC2 + static constexpr size_t MaxRowsOROC3 = 25; ///< Amount of rows in OROC3 + + /// Vector of cluster objects + /// Used for returning results + std::vector<o2::tpc::KrCluster> mClusters; /// Need an instance of Mapper to know position of pads const Mapper& mMapperInstance = o2::tpc::Mapper::instance(); KrCluster mTempCluster; ///< Used to save the cluster data - /// Here the map is defined where all digits are temporarily stored - std::array<std::array<std::array<float, MaxPads>, MaxRows>, MaxTimes> mMapOfAllDigits{}; + using TimeSliceSector = std::array<std::array<float, MaxPads>, MaxRows>; + + /// A temporary timeslice that gets filled and can be added to the set of timeslices + // TimeSliceSector mTempTimeSlice; + + /// Used to keep track of the digit that has to be processed + size_t mFirstDigit = 0; + + /// The set of timeslices. + /// It consists of 2*mMaxClusterSizeTime + 1 timeslices. + /// You can imagine it like this: + /// \verbatim + /// + /// 1 2 3 4 5 6 7 + /// + /// 1 o o o x o o o + /// 2 o o o x o o o + /// ............. + /// n-1 o o o x o o o + /// n o o o x o o o + /// + /// \endverbatim + /// + /// x-axis: Timeslice number + /// y-axis: Pad number + /// Time slice four is the interesting one. In there, local maxima are found and clusters are built from it. After it is processed, timeslice number 1 will be dropped and another timeslice will be put at the end of the set. + std::deque<TimeSliceSector> mSetOfTimeSlices{}; + + /// pre-store if complete time bins and rows within time bins have charges above mQThresholdMax + struct ThresholdInfo { + bool digitAboveThreshold{}; + std::array<bool, MaxRows> rowAboveThreshold{}; + }; + + std::deque<ThresholdInfo> mThresholdInfo{}; + + void createInitialMap(const gsl::span<const Digit> eventSector); + void popFirstTimeSliceFromMap() + { + mSetOfTimeSlices.pop_front(); + mThresholdInfo.pop_front(); + } + void fillADCValueInLastSlice(int cru, int rowInSector, int padInRow, float adcValue); + void addTimeSlice(const gsl::span<const Digit> eventSector, const int timeSlice); + + /// For each ROC, the maximum cluster size has to be chosen + void setMaxClusterSize(int row); /// To update the temporary cluster, i.e. all digits are added here void updateTempCluster(float tempCharge, int tempPad, int tempRow, int tempTime); /// After all digits are assigned to the cluster, the mean and sigmas are calculated here - void updateTempClusterFinal(); + void updateTempClusterFinal(const int timeOffset = 0); /// Returns sign of val (in a crazy way) int signnum(int val) { return (0 < val) - (val < 0); } + /// Cluster acceptance cuts + bool acceptCluster(const KrCluster& cl); + ClassDefNV(KrBoxClusterFinder, 0); }; diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinderParam.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinderParam.h new file mode 100644 index 0000000000000..141da383d5873 --- /dev/null +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinderParam.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrBoxClusterFinderParam.h +/// \brief Parameter class for the Kr box cluster finder +/// +/// \author Philip Hauer, hauer@hiskp.uni-bonn.de + +#ifndef ALICEO2_TPC_KrBoxClusterFinderParam_H_ +#define ALICEO2_TPC_KrBoxClusterFinderParam_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +#include "DataFormatsTPC/Defs.h" + +namespace o2 +{ +namespace tpc +{ + +struct KrBoxClusterFinderParam : public o2::conf::ConfigurableParamHelper<KrBoxClusterFinderParam> { + int MaxClusterSizeTime{3}; ///< "radius" of a cluster in time direction + + int MaxClusterSizeRowIROC{3}; ///< "radius" of a cluster in row direction in IROC + int MaxClusterSizeRowOROC1{2}; ///< "radius" of a cluster in row direction in OROC1 + int MaxClusterSizeRowOROC2{2}; ///< "radius" of a cluster in row direction in OROC2 + int MaxClusterSizeRowOROC3{1}; ///< "radius" of a cluster in row direction in OROC3 + + int MaxClusterSizePadIROC{5}; ///< "radius" of a cluster in pad direction in IROC + int MaxClusterSizePadOROC1{3}; ///< "radius" of a cluster in pad direction in OROC1 + int MaxClusterSizePadOROC2{3}; ///< "radius" of a cluster in pad direction in OROC2 + int MaxClusterSizePadOROC3{3}; ///< "radius" of a cluster in pad direction in OROC3 + + float QThresholdMax{30.0}; ///< the Maximum charge in a cluster must exceed this value or it is discarded + float QThreshold{1.0}; ///< every charge which is added to a cluster must exceed this value or it is discarded + int MinNumberOfNeighbours{2}; ///< amount of direct neighbours required for a cluster maximum + + float CutMinSigmaTime{0}; ///< Min sigma time to accept cluster + float CutMaxSigmaTime{1000}; ///< Min sigma time to accept cluster + float CutMinSigmaPad{0}; ///< Min sigma pad to accept cluster + float CutMaxSigmaPad{1000}; ///< Min sigma pad to accept cluster + float CutMinSigmaRow{0}; ///< Min sigma row to accept cluster + float CutMaxSigmaRow{1000}; ///< Min sigma row to accept cluster + float CutMaxQtot{1e10}; ///< Max Qtot to accept cluster + float CutQtot0{1e10}; ///< Max Qtot at zero size for Qtot vs. size correlation cut + float CutQtotSizeSlope{0}; ///< Max Qtot over size slope for Qtot vs. size correlation cut + unsigned char CutMaxSize{255}; ///< Max cluster size in number of digits + bool ApplyCuts{false}; ///< if to apply cluster cuts above + + O2ParamDef(KrBoxClusterFinderParam, "TPCKrBoxClusterFinder"); +}; +} // namespace tpc +} // namespace o2 + +#endif // ALICEO2_TPC_KrBoxClusterFinderParam_H_ diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/KrCluster.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/KrCluster.h deleted file mode 100644 index 77f66e934bc8a..0000000000000 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/KrCluster.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file KrCluster.h -/// \brief Struct for Krypton and X-ray clusters -/// \author Philip Hauer <hauer@hiskp.uni-bonn.de> - -#ifndef ALICEO2_TPC_KrCluster_H_ -#define ALICEO2_TPC_KrCluster_H_ - -namespace o2 -{ -namespace tpc -{ - -struct KrCluster { - public: - float totCharge = 0; ///< Total charge of the cluster (ADC counts) - float maxCharge = 0; ///< Maximum charge of the cluster (ADC counts) - int size = 0; ///< Size of the cluster (TPCDigits) - float meanPad = 0; ///< Center of gravity (Pad number) - float meanRow = 0; ///< Center of gravity (Row number) - float meanTime = 0; ///< Center of gravity (Time) - float sigmaPad = 0; ///< RMS of cluster in pad direction - float sigmaRow = 0; ///< RMS of cluster in row direction - float sigmaTime = 0; ///< RMS of cluster in time direction - int sector = 0; ///< Sector number - - /// Used to set all Cluster variables to zero. - void reset() - { - totCharge = 0; - maxCharge = 0; - size = 0; - meanPad = 0; - meanRow = 0; - meanTime = 0; - sigmaPad = 0; - sigmaRow = 0; - sigmaTime = 0; - sector = 0; - } - - ClassDefNV(KrCluster, 1); -}; - -} // namespace tpc -} // namespace o2 - -#endif diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h new file mode 100644 index 0000000000000..edb06eedf1e12 --- /dev/null +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_RawProcessingHelpers_H +#define O2_TPC_RawProcessingHelpers_H + +#include <functional> + +#include "TPCBase/RDHUtils.h" + +namespace o2 +{ +namespace tpc +{ +namespace raw_processing_helpers +{ + +using ADCCallback = std::function<bool(int cru, int rowInSector, int padInRow, int timeBin, float adcValue)>; + +bool processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t orbit, uint32_t referenceOrbit, uint32_t syncOffsetReference, ADCCallback fillADC, bool useTimeBin = false); + +} // namespace raw_processing_helpers +} // namespace tpc +} // namespace o2 +#endif diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReader.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReader.h index b75c4c0fcbb9b..958e25787b159 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReader.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h index ef6ca52e2ae3a..ef0ae33e01904 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,11 +32,13 @@ #include <gsl/span> #include "DetectorsRaw/RDHUtils.h" -#include "MemoryResources/Types.h" #include "TPCBase/CRU.h" #include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" #include "TPCBase/PadPos.h" #include "TPCBase/PadROCPos.h" +#include "TPCBase/RDHUtils.h" +#include "TPCReconstruction/RawProcessingHelpers.h" //#include "git_info.hpp" namespace o2 @@ -46,6 +49,7 @@ namespace rawreader { using RDHUtils = o2::raw::RDHUtils; +using RDH = o2::header::RDHAny; /// debug level bits enum DebugLevel : uint8_t { @@ -75,7 +79,6 @@ enum class RAWDataType : uint8_t { LinkZS = 1, ///< Link based zero suppression }; -using RDH = o2::header::RAWDataHeader; static constexpr int MaxNumberOfLinks = 24; ///< maximum number of links // =========================================================================== @@ -135,6 +138,26 @@ class ADCRawData /// overloading output stream operator to output ADCRawData friend std::ostream& operator<<(std::ostream& output, const ADCRawData& rawData); + /// reset + void reset() + { + mOutputStream = 0; + mNumTimeBins = 0; + for (auto& data : mADCRaw) { + data.clear(); + } + } + + bool hasData() const + { + for (auto& data : mADCRaw) { + if (data.size()) { + return true; + } + } + return false; + } + private: uint32_t mOutputStream{0}; // variable to set the output stream for the << operator uint32_t mNumTimeBins{0}; // variable to set the number of timebins for the << operator @@ -167,6 +190,10 @@ class SyncPosition /// return half word position uint32_t getHalfWordPosition() const { return mHalfWordPos; }; + uint32_t getFrameNumber() const { return mFrameNum; } + + uint32_t getPacketNumber() const { return mPacketNum; } + /// return if sync was found bool synched() const { return mSyncFound; }; @@ -209,7 +236,7 @@ class GBTFrame /// set syncronisation found for stream /// \param stream stream - bool mSyncFound(int stream) { return mSyncPos[stream].synched(); }; + bool syncFound(int stream) { return mSyncPos[stream].synched(); }; /// get the syncronisation array const SyncArray& getSyncArray() const { return mSyncPos; } @@ -232,7 +259,7 @@ class GBTFrame void getAdcValues(ADCRawData& rawData); /// read from memory - void readFromMemory(gsl::span<const o2::byte> data); + void readFromMemory(gsl::span<const std::byte> data); /// read from istream void streamFrom(std::istream& input); @@ -302,8 +329,6 @@ class RawReaderCRUEventSync static constexpr size_t ExpectedNumberOfPacketsPerHBFrame{8}; ///< expected number of packets in one HB frame per link for HB scaling mode static constexpr size_t ExpectedPayloadSize{64000}; ///< expected payload size in case of triggered mode (4000 GBT Frames of 16byte) - using RDH = o2::header::RAWDataHeader; - /// default ctor RawReaderCRUEventSync() { reset(); } @@ -333,7 +358,7 @@ class RawReaderCRUEventSync /// \struct CRUInfo /// \brief summary information of on CRU struct CRUInfo { - CRUInfo() : LinkInformation(24) {} + CRUInfo() : LinkInformation(MaxNumberOfLinks) {} bool isPresent() const { @@ -345,12 +370,22 @@ class RawReaderCRUEventSync return false; } - bool isComplete() const + bool isComplete(RAWDataType rawDataType = RAWDataType::GBT) const { for (const auto& link : LinkInformation) { - if (link.WasSeen && !link.IsPresent && !link.isComplete()) { + if (link.WasSeen && !link.IsPresent) { return false; } + if (rawDataType == RAWDataType::GBT) { + if (!link.isComplete()) { + return false; + } + } + if (rawDataType == RAWDataType::LinkZS) { + if (link.IsPresent && !link.HBEndSeen) { + return false; + } + } } return true; } @@ -382,7 +417,9 @@ class RawReaderCRUEventSync bool operator<(const EventInfo& other) const { return HeartbeatOrbits.back() < other.HeartbeatOrbits[0]; } /// check if heartbeatOrbit contributes to the event - bool hasHearbeatOrbit(uint32_t heartbeatOrbit) { return std::find(HeartbeatOrbits.begin(), HeartbeatOrbits.end(), heartbeatOrbit) != HeartbeatOrbits.end(); } + bool hasHearbeatOrbit(uint32_t heartbeatOrbit) const { return std::find(HeartbeatOrbits.begin(), HeartbeatOrbits.end(), heartbeatOrbit) != HeartbeatOrbits.end(); } + + uint32_t getFirstOrbit() const { return HeartbeatOrbits.size() ? *std::min_element(HeartbeatOrbits.begin(), HeartbeatOrbits.end()) : 0; } std::vector<uint32_t> HeartbeatOrbits{}; ///< vector of heartbeat orbits contributing to the event CRUInfoArray_t CRUInfoArray; ///< Link information for each cru @@ -396,14 +433,17 @@ class RawReaderCRUEventSync LinkInfo& getLinkInfo(const RDH& rdh, DataType dataType) { if (!mLastEvent) { - createEvent(rdh, dataType); + const auto heartbeatOrbit = RDHUtils::getHeartBeatOrbit(rdh); + createEvent(heartbeatOrbit, dataType); } - const auto dataWrapperID = RDHUtils::getEndPointID(rdh); - const auto linkID = RDHUtils::getLinkID(rdh); - const auto globalLinkID = linkID + dataWrapperID * 12; + const auto feeId = RDHUtils::getFEEID(rdh); + const auto endPoint = rdh_utils::getEndPoint(feeId); + const auto link = rdh_utils::getLink(feeId); + const auto globalLink = link + endPoint * 12; + const auto cru = rdh_utils::getCRU(feeId); - return mLastEvent->CRUInfoArray[RDHUtils::getCRUID(rdh)].LinkInformation[globalLinkID]; + return mLastEvent->CRUInfoArray[cru].LinkInformation[globalLink]; } /// get array with all link informaiton for a specific event number and cru @@ -439,13 +479,17 @@ class RawReaderCRUEventSync void sortEvents() { std::sort(mEventInformation.begin(), mEventInformation.end()); } /// create a new event or return the one with the given HB orbit - EventInfo& createEvent(const RDH& rdh, DataType dataType); + EventInfo& createEvent(const uint32_t heartbeatOrbit, DataType dataType); /// analyse events and mark complete events - void analyse(); + void analyse(RAWDataType rawDataType = RAWDataType::GBT); + /// all event information const EventInfoVector& getEventInfoVector() const { return mEventInformation; } + /// information of specific event + const EventInfo& getEventInfo(size_t eventNumber) const { return mEventInformation[eventNumber]; } + /// write data to ostream void streamTo(std::ostream& output) const; @@ -494,6 +538,8 @@ class RawReaderCRU { public: class PacketDescriptor; + using PacketDescriptorMap = std::vector<PacketDescriptor>; + using PacketDescriptorMapArray = std::array<PacketDescriptorMap, MaxNumberOfLinks>; /// constructor /// \param @@ -577,6 +623,9 @@ class RawReaderCRU /// process all data for the selected link reading single 8k packet from file int processDataFile(); + /// process data in case of Link based zero suppression + void processLinkZS(); + /// Collect data to memory and process data void processDataMemory(); @@ -585,7 +634,7 @@ class RawReaderCRU /// Process data from memory for a single link /// The data must be collected before, merged over 8k packets - int processMemory(const std::vector<o2::byte>& data, ADCRawData& rawData); + int processMemory(const std::vector<std::byte>& data, ADCRawData& rawData); /// process links void processLinks(const uint32_t linkMask = 0); @@ -626,12 +675,40 @@ class RawReaderCRU /// set the event sync void setManager(RawReaderCRUManager* manager) { mManager = manager; } + /// get manager + RawReaderCRUManager* getManager() { return mManager; } + /// copy single events to another file void copyEvents(const std::vector<uint32_t>& eventNumbers, std::string outputDirectory, std::ios_base::openmode mode = std::ios_base::openmode(0)); + /// write GBT data into separate files per link + void writeGBTDataPerLink(std::string_view outputDirectory, int maxEvents = -1); + /// run a data filling callback function void runADCDataCallback(const ADCRawData& rawData); + /// set output file prefix + void setOutputFilePrefix(std::string_view prefix) { mOutputFilePrefix = prefix; } + + /// output file prefix + const std::string& getOutputFilePrefix() const { return mOutputFilePrefix; } + + /// get packet descriptor map array + const PacketDescriptorMapArray& getPacketDescriptorMaps() const { return mPacketDescriptorMaps; } + + /// file handling + std::ifstream& getFileHandle() + { + if (!mFileHandle.is_open()) { + mFileHandle.open(mInputFileName, std::ios::binary); + if (!mFileHandle.good()) { + throw std::runtime_error("Unable to open or access file " + mInputFileName); + } + } + + return mFileHandle; + } + //=========================================================================== //===| Nested helper classes |=============================================== // @@ -668,10 +745,15 @@ class RawReaderCRU class PacketDescriptor { public: - PacketDescriptor(size_t headOff, uint32_t cruID, uint32_t linkID, uint32_t dataWrapperID, uint16_t memorySize = 7840, uint16_t packetSize = 8192) : mHeaderOffset(headOff), - mFEEID(cruID + (linkID << 9) + (dataWrapperID << 13)), - mMemorySize(memorySize), - mPacketSize(packetSize) + using FEEIDType = rdh_utils::FEEIDType; + + PacketDescriptor(size_t headOff, uint32_t cru, uint32_t link, uint32_t endPoint, + uint16_t memorySize = 7840, uint16_t packetSize = 8192, + uint32_t heartbeatOrbit = 0) : mHeaderOffset(headOff), + mFEEID(rdh_utils::getFEEID(cru, endPoint, link)), + mMemorySize(memorySize), + mPacketSize(packetSize), + mHeartbeatOrbit(heartbeatOrbit) { } @@ -679,15 +761,18 @@ class RawReaderCRU { return sizeof(RDH); } - uint32_t getHeaderOffset() const { return mHeaderOffset; } - uint32_t getPayloadOffset() const { return mHeaderOffset + getHeaderSize(); } + + uint32_t getHeartBeatOrbit() const { return mHeartbeatOrbit; } + size_t getHeaderOffset() const { return mHeaderOffset; } + size_t getPayloadOffset() const { return mHeaderOffset + getHeaderSize(); } uint32_t getPayloadSize() const { return mMemorySize - getHeaderSize(); } uint32_t getPacketSize() const { return mPacketSize; } - uint16_t getCRUID() const { return mFEEID & 0x01FF; } - uint16_t getLinkID() const { return (mFEEID >> 9) & 0x0F; } - uint16_t getGlobalLinkID() const { return ((mFEEID >> 9) & 0x0F) + getDataWrapperID() * 12; } - uint16_t getDataWrapperID() const { return (mFEEID >> 13) & 0x01; } + FEEIDType getFEEID() const { return mFEEID; } + FEEIDType getCRUID() const { return rdh_utils::getCRU(mFEEID); } + FEEIDType getLinkID() const { return rdh_utils::getLink(mFEEID); } + FEEIDType getGlobalLinkID() const { return getLinkID() + getEndPoint() * 12; } + FEEIDType getEndPoint() const { return rdh_utils::getEndPoint(mFEEID); } /// write data to ostream void streamTo(std::ostream& output) const; @@ -699,10 +784,11 @@ class RawReaderCRU } private: - size_t mHeaderOffset; ///< header offset - uint16_t mMemorySize; ///< payload size - uint16_t mPacketSize; ///< packet size - uint16_t mFEEID; ///< link ID -- BIT 0-8: CRUid -- BIT 9-12: LinkID -- BIT 13: DataWrapperID -- BIT 14,15: unused + size_t mHeaderOffset; ///< header offset + uint32_t mHeartbeatOrbit; ///< heartbeatOrbit + uint16_t mMemorySize; ///< payload size + uint16_t mPacketSize; ///< packet size + FEEIDType mFEEID; ///< FEEid as defined in TPCBase/RDHUtils.h }; // =========================================================================== @@ -710,26 +796,25 @@ class RawReaderCRU // private: - using PacketDescriptorMap = std::vector<PacketDescriptor>; - uint32_t mDebugLevel; ///< debug level - uint32_t mVerbosity; ///< verbosity - uint32_t mNumTimeBins; ///< number of time bins to process - uint32_t mLink; ///< present link being processed - uint32_t mStream; ///< present stream being processed - uint32_t mEventNumber = 0; ///< current event number to process - uint32_t mReaderNumber = 0; ///< raw reader number in manager - CRU mCRU; ///< CRU - size_t mFileSize; ///< size of the input file - bool mDumpTextFiles = false; ///< dump debugging text files - bool mFillADCdataMap = true; ///< fill the ADC data map - bool mForceCRU = false; ///< force CRU: overwrite value from RDH - bool mFileIsScanned = false; ///< if file was already scanned - std::array<uint32_t, MaxNumberOfLinks> mPacketsPerLink; ///< array to keep track of the number of packets per link - std::bitset<MaxNumberOfLinks> mLinkPresent; ///< info if link is present in data; information retrieved from scanning the RDH headers - std::array<PacketDescriptorMap, MaxNumberOfLinks> mPacketDescriptorMaps; ///< array to hold vectors thhe packet descriptors - std::string mInputFileName; ///< input file name - std::string mOutputFilePrefix; ///< input file name - std::array<SyncArray, MaxNumberOfLinks> mSyncPositions{}; ///< sync positions for each link + uint32_t mDebugLevel; ///< debug level + uint32_t mVerbosity; ///< verbosity + uint32_t mNumTimeBins; ///< number of time bins to process + uint32_t mLink; ///< present link being processed + uint32_t mStream; ///< present stream being processed + uint32_t mEventNumber = 0; ///< current event number to process + uint32_t mReaderNumber = 0; ///< raw reader number in manager + CRU mCRU; ///< CRU + size_t mFileSize; ///< size of the input file + bool mDumpTextFiles = false; ///< dump debugging text files + bool mFillADCdataMap = true; ///< fill the ADC data map + bool mForceCRU = false; ///< force CRU: overwrite value from RDH + bool mFileIsScanned = false; ///< if file was already scanned + std::array<uint32_t, MaxNumberOfLinks> mPacketsPerLink; ///< array to keep track of the number of packets per link + std::bitset<MaxNumberOfLinks> mLinkPresent; ///< info if link is present in data; information retrieved from scanning the RDH headers + PacketDescriptorMapArray mPacketDescriptorMaps; ///< array to hold vectors thhe packet descriptors + std::string mInputFileName; ///< input file name + std::string mOutputFilePrefix; ///< input file name + std::array<SyncArray, MaxNumberOfLinks> mSyncPositions{}; ///< sync positions for each link // not so nice but simplest way to store the ADC data std::map<PadPos, std::vector<uint16_t>> mADCdata; ///< decoded ADC data RawReaderCRUManager* mManager{nullptr}; ///< event synchronization information @@ -737,7 +822,7 @@ class RawReaderCRU std::ifstream mFileHandle; ///< file handle for input file /// collect raw GBT data - void collectGBTData(std::vector<o2::byte>& data); + void collectGBTData(std::vector<std::byte>& data); /// fill adc data to output map void fillADCdataMap(const ADCRawData& rawData); @@ -764,10 +849,10 @@ inline void GBTFrame::updateSyncCheck(SyncArray& syncArray) // shift in a 1 if the halfword is 0x15 if (mFrameHalfWords[s][hPos] == 0x15) { mSyncCheckRegister[s] = (mSyncCheckRegister[s] << 1) | 1; - // shift in a 0 if the halfword is 0xA + // shift in a 0 if the halfword is 0xA } else if (mFrameHalfWords[s][hPos] == 0xA) { mSyncCheckRegister[s] = (mSyncCheckRegister[s] << 1); - // otherwise reset the register to 0 + // otherwise reset the register to 0 } else { mSyncCheckRegister[s] = 0; } @@ -792,10 +877,10 @@ inline void GBTFrame::updateSyncCheck(bool verbose) // shift in a 1 if the halfword is 0x15 if (mFrameHalfWords[s][hPos] == 0x15) { mSyncCheckRegister[s] = (mSyncCheckRegister[s] << 1) | 1; - // shift in a 0 if the halfword is 0xA + // shift in a 0 if the halfword is 0xA } else if (mFrameHalfWords[s][hPos] == 0xA) { mSyncCheckRegister[s] = (mSyncCheckRegister[s] << 1); - // otherwise reset the register to 0 + // otherwise reset the register to 0 } else { mSyncCheckRegister[s] = 0; } @@ -854,7 +939,7 @@ inline void GBTFrame::getAdcValues(ADCRawData& rawData) // std::cout << std::endl; } -inline void GBTFrame::readFromMemory(gsl::span<const o2::byte> data) +inline void GBTFrame::readFromMemory(gsl::span<const std::byte> data) { assert(sizeof(mData) == data.size_bytes()); memcpy(mData.data(), data.data(), data.size_bytes()); @@ -873,6 +958,7 @@ class RawReaderCRUManager { public: using ADCDataCallback = std::function<Int_t(const PadROCPos&, const CRU&, const gsl::span<const uint32_t>)>; + using LinkZSCallback = o2::tpc::raw_processing_helpers::ADCCallback; using EndReaderCallback = std::function<void()>; /// constructor @@ -939,6 +1025,9 @@ class RawReaderCRUManager } } + /// get the event sync + const RawReaderCRUEventSync& getEventSync() const { return mEventSync; } + /// get number of all events size_t getNumberOfEvents() const { return mEventSync.getNumberOfEvents(); } @@ -968,9 +1057,21 @@ class RawReaderCRUManager /// copy single events from raw input files to another file static void copyEvents(const std::string_view inputFileNames, const std::vector<uint32_t> eventNumbers, std::string_view outputDirectory, std::ios_base::openmode mode = std::ios_base::openmode(0)); + /// copy single events from raw input files to another file + void writeGBTDataPerLink(std::string_view outputDirectory, int maxEvents = -1); + + /// copy single events from raw input files to another file + static void writeGBTDataPerLink(const std::string_view inputFileNames, std::string_view outputDirectory, int maxEvents = -1); + /// set a callback function void setADCDataCallback(ADCDataCallback function) { mADCDataCallback = function; } + /// set a callback function for decoded LinkZS data + void setLinkZSCallback(LinkZSCallback function) { mLinkZSCallback = function; } + + /// get LinkZSCallback + LinkZSCallback getLinkZSCallback() { return mLinkZSCallback; } + /// process event calling mADCDataCallback to process values void processEvent(uint32_t eventNumber, EndReaderCallback endReader = nullptr); @@ -983,6 +1084,7 @@ class RawReaderCRUManager bool mDetectDataType{true}; ///< try to detect data types bool mIsInitialized{false}; ///< if init was called already ADCDataCallback mADCDataCallback{nullptr}; ///< callback function for filling the ADC data + LinkZSCallback mLinkZSCallback{nullptr}; ///< callback for decoded linkZS data friend class RawReaderCRU; diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderEventSync.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderEventSync.h index 05585dedf8a9a..65e2135d84548 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderEventSync.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderEventSync.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/SyncPatternMonitor.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/SyncPatternMonitor.h index a788d63da9722..061a101e1bd54 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/SyncPatternMonitor.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/SyncPatternMonitor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h index 1ec1a9c8a155c..51f2ea91fe0a6 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCTrackingDigitsPreCheck.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCTrackingDigitsPreCheck.h new file mode 100644 index 0000000000000..7ba4765e6169d --- /dev/null +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/TPCTrackingDigitsPreCheck.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCTrackingDigitsPreCheck.h +/// \brief Wrapper class for TPC CA Tracker algorithm +/// \author David Rohr + +#ifndef ALICEO2_TPC_TRACKING_DIGITSPRECHECK_H +#define ALICEO2_TPC_TRACKING_DIGITSPRECHECK_H + +#include <memory> +namespace o2 +{ +namespace gpu +{ +struct GPUTrackingInOutPointers; +struct GPUO2InterfaceConfiguration; +} // namespace gpu +} // namespace o2 + +namespace o2 +{ +namespace tpc +{ + +class TPCTrackingDigitsPreCheck +{ + struct precheckModifiedDataInternal; // This struct might hold some internal data which the modified members of the data argument might point to + + public: + class precheckModifiedData + { + std::unique_ptr<precheckModifiedDataInternal> data; + + public: + precheckModifiedData(); + precheckModifiedData(std::unique_ptr<precheckModifiedDataInternal>&& v); + ~precheckModifiedData(); + }; + static precheckModifiedData runPrecheck(o2::gpu::GPUTrackingInOutPointers* ptrs, o2::gpu::GPUO2InterfaceConfiguration* config); +}; + +} // namespace tpc +} // namespace o2 +#endif // ALICEO2_TPC_TRACKING_DIGITSPRECHECK_H diff --git a/Detectors/TPC/reconstruction/macro/addInclude.C b/Detectors/TPC/reconstruction/macro/addInclude.C index eda7a2bcc35d7..eedf132892e6a 100644 --- a/Detectors/TPC/reconstruction/macro/addInclude.C +++ b/Detectors/TPC/reconstruction/macro/addInclude.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C index 7c0c46d1e2a65..48d90d933c59e 100644 --- a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C +++ b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ /eos/user/e/ehellbar/SpaceCharge/data/RUN3/InputSCDensityHistograms Run macro: - root -l -b -q $O2_SRC/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C+\(180,65,65,\"InputSCDensityHistograms_8000events.root\",\"inputSCDensity3D_8000_0\",\"tpctransformSCcorrection.root\"\) + root -l -b -q $O2_SRC/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C+\(\"InputSCDensityHistograms_8000events.root\",\"inputSCDensity3D_8000_0\",\"tpctransformSCcorrection.root\"\) Test macro compilation: .L $O2_SRC/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C+ @@ -31,9 +32,8 @@ #include "TFile.h" #include "TH3.h" #include "TLatex.h" -#include "TMatrixD.h" -#include "AliTPCSpaceCharge3DCalc.h" +#include "TPCSpaceCharge/SpaceCharge.h" #include "CommonConstants/MathConstants.h" #include "CommonUtils/TreeStreamRedirector.h" @@ -43,39 +43,37 @@ using namespace o2; using namespace tpc; using namespace gpu; -std::unique_ptr<AliTPCSpaceCharge3DCalc> spaceCharge = nullptr; +/// \param nPhi number of phi bins of original correction lookup table +/// \param nR number of r bins of original correction lookup table, has to be 2^n + 1 +/// \param nZ number of z bins of original correction lookup table, has to be 2^n + 1 +const int nPhi = 180; +const int nR = 129; +const int nZ = 129; +using SC = o2::tpc::SpaceCharge<double>; +std::unique_ptr<SC> spaceCharge; void getSpaceChargeCorrection(const int roc, const double XYZ[3], double dXdYdZ[3]); -void initSpaceCharge(const int nPhi, const int nR, const int nZ, const int interpolationOrder, - const char* histoFileName, const char* histoName); +void initSpaceCharge(const char* histoFileName, const char* histoName); void DumpFlatObjectToFile(const TPCFastTransform* obj, const char* file); std::unique_ptr<TPCFastTransform> ReadFlatObjectFromFile(const char* file); -void debugInterpolation(utils::TreeStreamRedirector& pcstream, - const o2::gpu::TPCFastTransformGeo& geo, - TPCFastTransform* fastTransform); -void debugGridpoints(utils::TreeStreamRedirector& pcstream, - const o2::gpu::TPCFastTransformGeo& geo, - TPCFastTransform* fastTransform); +void debugInterpolation(utils::TreeStreamRedirector& pcstream, const o2::gpu::TPCFastTransformGeo& geo, TPCFastTransform* fastTransform); +void debugGridpoints(utils::TreeStreamRedirector& pcstream, const o2::gpu::TPCFastTransformGeo& geo, TPCFastTransform* fastTransform); -/// Creates TPCFastTransform object for TPC space-charge correction, stores it in a file and provides a deub tree if requested -/// \param nPhi number of phi bins of original correction lookup table -/// \param nR number of r bins of original correction lookup table, has to be 2^n + 1 -/// \param nZ number of z bins of original correction lookup table, has to be 2^n + 1 +/// Creates TPCFastTransform object for TPC space-charge correction, stores it in a file and provides a debug tree if requested /// \param histoFileName path and name to the root file containing input space-charge density histograms /// \param histoName name of the input space-charge density histogram /// \param outputFileName name of the output file to store the TPCFastTransform object in /// \param debug create debug tree comparing original corrections and spline interpolations from TPCFastTransform (1 = on the spline interpolation grid, 2 = on the original lookup table grid) void createTPCSpaceChargeCorrection( - const int nPhi = 180, const int nR = 65, const int nZ = 65, const char* histoFileName = "InputSCDensityHistograms_10000events.root", const char* histoName = "inputSCDensity3D_10000_avg", const char* outputFileName = "tpctransform.root", const int debug = 0) { - const int interpolationOrder = 2.; - initSpaceCharge(nPhi, nR, nZ, interpolationOrder, histoFileName, histoName); + SC::setGrid(nZ, nR, nPhi); + initSpaceCharge(histoFileName, histoName); TPCFastTransformHelperO2::instance()->setSpaceChargeCorrection(getSpaceChargeCorrection); std::unique_ptr<TPCFastTransform> fastTransform(TPCFastTransformHelperO2::instance()->create(0)); @@ -84,7 +82,7 @@ void createTPCSpaceChargeCorrection( if (debug > 0) { const o2::gpu::TPCFastTransformGeo& geo = fastTransform->getGeometry(); - utils::TreeStreamRedirector pcstream(TString::Format("fastTransformUnitTest_debug%d_gridsize%d-%d-%d_order%d.root", debug, nPhi, nR, nZ, interpolationOrder).Data(), "recreate"); + utils::TreeStreamRedirector pcstream(TString::Format("fastTransformUnitTest_debug%d_gridsize%d-%d-%d.root", debug, nPhi, nR, nZ).Data(), "recreate"); switch (debug) { case 1: debugInterpolation(pcstream, geo, fastTransform.get()); @@ -100,54 +98,35 @@ void createTPCSpaceChargeCorrection( } /// Initialize calculation of original correction lookup tables -/// \param nPhi number of phi bins of original correction lookup table -/// \param nR number of r bins of original correction lookup table, has to be 2^n + 1 -/// \param nZ number of z bins of original correction lookup table, has to be 2^n + 1 -/// \param interpolationOrder interpolation method to use for original correction lookup tables (1 = linear interpolation, 2 = polynomial interpolation of 2nd order, >2 = cubic spline interpolation of higher orders) /// \param histoFileName path and name to the root file containing input space-charge density histograms /// \param histoName name of the input space-charge density histogram -void initSpaceCharge(const int nPhi, const int nR, const int nZ, const int interpolationOrder, - const char* histoFileName, const char* histoName) +void initSpaceCharge(const char* histoFileName, const char* histoName) { // get histogram with space-charge density std::unique_ptr<TFile> histoFile = std::unique_ptr<TFile>(TFile::Open(histoFileName)); std::unique_ptr<TH3> scHisto = std::unique_ptr<TH3>((TH3*)histoFile->Get(histoName)); // initialize space-charge object - spaceCharge = std::make_unique<AliTPCSpaceCharge3DCalc>(nR, nZ, nPhi, interpolationOrder, 3, 0); + spaceCharge = std::make_unique<SC>(); // input charge - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixChargeA = std::make_unique<std::unique_ptr<TMatrixD>[]>(nPhi); - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixChargeC = std::make_unique<std::unique_ptr<TMatrixD>[]>(nPhi); - for (int iphi = 0; iphi < nPhi; ++iphi) { - mMatrixChargeA[iphi] = std::make_unique<TMatrixD>(nR, nZ); - mMatrixChargeC[iphi] = std::make_unique<TMatrixD>(nR, nZ); - } - spaceCharge->GetChargeDensity((TMatrixD**)mMatrixChargeA.get(), (TMatrixD**)mMatrixChargeC.get(), (TH3*)scHisto.get(), nR, nZ, nPhi); - spaceCharge->SetInputSpaceChargeA((TMatrixD**)mMatrixChargeA.get()); - spaceCharge->SetInputSpaceChargeC((TMatrixD**)mMatrixChargeC.get()); + spaceCharge->fillChargeDensityFromHisto(*scHisto.get()); // further parameters - spaceCharge->SetOmegaTauT1T2(0.32, 1.f, 1.f); - spaceCharge->SetCorrectionType(0); // 0: use regular spaced LUTs, 1: use irregular LUTs (not recommended at the time as it is slower and results have to be verified) - spaceCharge->SetIntegrationStrategy(0); // 0: use default integration along drift lines, 1: use fast integration (not recommended at the time as results have to be verified) + spaceCharge->setOmegaTauT1T2(0.32, 1.f, 1.f); - // calculate LUTs - spaceCharge->ForceInitSpaceCharge3DPoissonIntegralDz(nR, nZ, nPhi, 300, 1e-8); + // start calculation of lookup tables (takes some time) + spaceCharge->calculateDistortionsCorrections(Side::A); + spaceCharge->calculateDistortionsCorrections(Side::C); } /// Function to get corrections from original lookup tables -/// \param roc readout chamber index (0 - 71) /// \param XYZ array with x, y and z position /// \param dXdYdZ array with correction dx, dy and dz void getSpaceChargeCorrection(const int roc, const double XYZ[3], double dXdYdZ[3]) { - const float xyzf[3] = {static_cast<float>(XYZ[0]), static_cast<float>(XYZ[1]), static_cast<float>(XYZ[2])}; - float dxdydzf[3] = {0.f, 0.f, 0.f}; - spaceCharge->GetCorrection(xyzf, roc, dxdydzf); - dXdYdZ[0] = static_cast<double>(dxdydzf[0]); - dXdYdZ[1] = static_cast<double>(dxdydzf[1]); - dXdYdZ[2] = static_cast<double>(dxdydzf[2]); + Side side = roc < 18 ? Side::A : Side::C; + spaceCharge->getCorrections(XYZ[0], XYZ[1], XYZ[2], side, dXdYdZ[0], dXdYdZ[1], dXdYdZ[2]); } /// Save TPCFastTransform to a file @@ -203,15 +182,12 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, for (int slice = 0; slice < geo.getNumberOfSlices(); slice += 1) { // for (int slice = 21; slice < 22; slice += 1) { std::cout << "debug slice " << slice << " ... " << std::endl; - const o2::gpu::TPCFastTransformGeo::SliceInfo& sliceInfo = geo.getSliceInfo(slice); for (int row = 0; row < geo.getNumberOfRows(); row++) { - int nPads = geo.getRowInfo(row).maxPad + 1; for (int pad = 0; pad < nPads; pad++) { - for (float time = 0; time < 500; time += 10) { // non-corrected point @@ -232,35 +208,32 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, // the original correction double gxyz[3] = {gx, gy, gz}; double gdC[3] = {0, 0, 0}; - getSpaceChargeCorrection(slice, gxyz, gdC); + Side side = slice < geo.getNumberOfSlicesA() ? Side::A : Side::C; + spaceCharge->getCorrections(gxyz[0], gxyz[1], gxyz[2], side, gdC[0], gdC[1], gdC[2]); float ldxC, ldyC, ldzC; - geo.convGlobalToLocal(slice, gdC[0], gdC[1], gdC[2], ldxC, ldyC, - ldzC); + geo.convGlobalToLocal(slice, gdC[0], gdC[1], gdC[2], ldxC, ldyC, ldzC); - float rC = std::sqrt((gx + gdC[0]) * (gx + gdC[0]) + - (gy + gdC[1]) * (gy + gdC[1])); + float rC = std::sqrt((gx + gdC[0]) * (gx + gdC[0]) + (gy + gdC[1]) * (gy + gdC[1])); // calculate distortion for the xyz0 - float ldD[3] = {0.0, 0.0, 0.0}; - float gdD[3] = {0.0, 0.0, 0.0}; + double ldD[3] = {0.0, 0.0, 0.0}; + double gdD[3] = {0.0, 0.0, 0.0}; float gxyzf[3] = {gx, gy, gz}; - float pointCyl[3] = {r, phi, gz}; + float pointCyl[3] = {gz, r, phi}; double efield[3] = {0.0, 0.0, 0.0}; - double charge = spaceCharge->GetChargeCylAC(pointCyl, slice); - double potential = spaceCharge->GetPotentialCylAC(pointCyl, slice); - spaceCharge->GetElectricFieldCyl(pointCyl, slice, efield); - spaceCharge->GetLocalDistortionCyl(pointCyl, slice, ldD); - spaceCharge->GetDistortion(gxyzf, slice, gdD); + double charge = spaceCharge->getDensityCyl(pointCyl[0], pointCyl[1], pointCyl[2], side); + double potential = spaceCharge->getPotentialCyl(pointCyl[0], pointCyl[1], pointCyl[2], side); + spaceCharge->getElectricFieldsCyl(pointCyl[0], pointCyl[1], pointCyl[2], side, efield[0], efield[1], efield[2]); + spaceCharge->getLocalDistortionsCyl(pointCyl[0], pointCyl[1], pointCyl[2], side, ldD[0], ldD[1], ldD[2]); + spaceCharge->getDistortions(gxyzf[0], gxyzf[1], gxyzf[2], side, gdD[0], gdD[1], gdD[2]); double gD[3] = {gx + gdD[0], gy + gdD[1], gz + gdD[2]}; - float rD = std::sqrt(gD[0] * gD[0] + gD[1] * gD[1]); // correction for the distorted point - double gdDC[3] = {0, 0, 0}; - getSpaceChargeCorrection(slice, gD, gdDC); + spaceCharge->getCorrections(gD[0], gD[1], gD[2], side, gdDC[0], gdDC[1], gdDC[2]); pcstream << "fastTransform" // internal coordinates @@ -313,9 +286,9 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, // << "charge=" << charge << "potential=" << potential - << "Er=" << efield[0] - << "Ephi=" << efield[1] - << "Ez=" << efield[2] + << "Ez=" << efield[0] + << "Er=" << efield[1] + << "Ephi=" << efield[2] << "\n"; } } @@ -327,51 +300,33 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, /// \param pcstream output stream /// \param geo TPCFastTransformGeo object /// \param fastTransform TPCFastTransform object -void debugGridpoints(utils::TreeStreamRedirector& pcstream, - const o2::gpu::TPCFastTransformGeo& geo, - TPCFastTransform* fastTransform) +void debugGridpoints(utils::TreeStreamRedirector& pcstream, const o2::gpu::TPCFastTransformGeo& geo, TPCFastTransform* fastTransform) { - int nR = spaceCharge->GetNRRows(); - int nZ = spaceCharge->GetNZColumns(); - int nPhi = spaceCharge->GetNPhiSlices(); - - float deltaR = - (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / - (nR - 1); - float deltaZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZ - 1); - float deltaPhi = o2::constants::math::TwoPI / nPhi; - for (int iside = 0; iside < 2; ++iside) { - + const Side side = iside == 0 ? Side::A : Side::C; for (int iphi = 0; iphi < nPhi; ++iphi) { - float phi = deltaPhi * iphi; - int sector = iside == 0 ? phi / o2::constants::math::TwoPI * 18 - : phi / o2::constants::math::TwoPI * 18 + 18; + float phi = spaceCharge->getPhiVertex(iphi, side); + int sector = iside == 0 ? phi / o2::constants::math::TwoPI * 18 : phi / o2::constants::math::TwoPI * 18 + 18; for (int ir = 0; ir < nR; ++ir) { - float radius = AliTPCPoissonSolver::fgkIFCRadius + deltaR * ir; + float radius = spaceCharge->getRVertex(ir, side); float gx0 = radius * std::cos(phi); float gy0 = radius * std::sin(phi); for (int iz = 0; iz < nZ; ++iz) { - float gz0 = iside == 0 ? deltaZ * iz - : -1 * deltaZ * iz; - + float gz0 = spaceCharge->getZVertex(iz, side); float x0 = 0.f, y0 = 0.f, z0 = 0.f; geo.convGlobalToLocal(sector, gx0, gy0, gz0, x0, y0, z0); if (x0 < geo.getRowInfo(0).x - 0.375) { continue; } - if (x0 >= (geo.getRowInfo(62).x + 0.375) && - x0 < (geo.getRowInfo(63).x - 0.5)) { + if (x0 >= (geo.getRowInfo(62).x + 0.375) && x0 < (geo.getRowInfo(63).x - 0.5)) { continue; } - if (x0 >= (geo.getRowInfo(96).x + 0.5) && - x0 < (geo.getRowInfo(97).x - 0.6)) { + if (x0 >= (geo.getRowInfo(96).x + 0.5) && x0 < (geo.getRowInfo(97).x - 0.6)) { continue; } - if (x0 >= (geo.getRowInfo(126).x + 0.6) && - x0 < (geo.getRowInfo(127).x - 0.75)) { + if (x0 >= (geo.getRowInfo(126).x + 0.6) && x0 < (geo.getRowInfo(127).x - 0.75)) { continue; } if (x0 > (geo.getRowInfo(151).x + 0.75)) { @@ -417,19 +372,18 @@ void debugGridpoints(utils::TreeStreamRedirector& pcstream, double gcorr[3] = {0, 0, 0}; getSpaceChargeCorrection(sector, xyz, gcorr); float lcorr[3]; - geo.convGlobalToLocal(sector, gcorr[0], gcorr[1], gcorr[2], lcorr[0], - lcorr[1], lcorr[2]); + geo.convGlobalToLocal(sector, gcorr[0], gcorr[1], gcorr[2], lcorr[0], lcorr[1], lcorr[2]); float fxyz[3] = {gx0, gy0, gz0}; - float pointCyl[3] = {radius, phi, gz0}; + float pointCyl[3] = {gz0, radius, phi}; double efield[3] = {0.0, 0.0, 0.0}; - float distLocal[3] = {0.0, 0.0, 0.0}; - float dist[3] = {0.0, 0.0, 0.0}; - double charge = spaceCharge->GetChargeCylAC(pointCyl, sector); - double potential = spaceCharge->GetPotentialCylAC(pointCyl, sector); - spaceCharge->GetElectricFieldCyl(pointCyl, sector, efield); - spaceCharge->GetLocalDistortionCyl(pointCyl, sector, distLocal); - spaceCharge->GetDistortion(fxyz, sector, dist); + double distLocal[3] = {0.0, 0.0, 0.0}; + double dist[3] = {0.0, 0.0, 0.0}; + double charge = spaceCharge->getDensityCyl(pointCyl[0], pointCyl[1], pointCyl[2], side); + double potential = spaceCharge->getPotentialCyl(pointCyl[0], pointCyl[1], pointCyl[2], side); + spaceCharge->getElectricFieldsCyl(pointCyl[0], pointCyl[1], pointCyl[2], side, efield[0], efield[1], efield[2]); + spaceCharge->getLocalDistortionsCyl(pointCyl[0], pointCyl[1], pointCyl[2], side, distLocal[0], distLocal[1], distLocal[2]); + spaceCharge->getDistortions(fxyz[0], fxyz[1], fxyz[2], side, dist[0], dist[1], dist[2]); pcstream << "fastTransform" // internal coordinates @@ -472,9 +426,9 @@ void debugGridpoints(utils::TreeStreamRedirector& pcstream, // << "charge=" << charge << "potential=" << potential - << "Er=" << efield[0] - << "Ephi=" << efield[1] - << "Ez=" << efield[2] + << "Ez=" << efield[0] + << "Er=" << efield[1] + << "Ephi=" << efield[2] << "\n"; } } @@ -485,7 +439,7 @@ void debugGridpoints(utils::TreeStreamRedirector& pcstream, /// Make a simple QA plot of the debug stream void makeQAplot() { - TFile f("fastTransformUnitTest_debug1_gridsize180-65-65_order2.root"); + TFile f("fastTransformUnitTest_debug1_gridsize180-129-129.root"); TTree* tree = (TTree*)f.Get("fastTransform"); tree->SetMarkerSize(0.2); tree->SetMarkerStyle(21); diff --git a/Detectors/TPC/reconstruction/macro/findKrBoxCluster.C b/Detectors/TPC/reconstruction/macro/findKrBoxCluster.C index 23bac1ed5c25f..daa215038a509 100644 --- a/Detectors/TPC/reconstruction/macro/findKrBoxCluster.C +++ b/Detectors/TPC/reconstruction/macro/findKrBoxCluster.C @@ -1,92 +1,94 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file findKrBoxCluster.C -/// \brief This macro retrieves clusters from Krypton and X-Ray runs, input tpcdigits.root -/// \author Philip Hauer <philip.hauer@cern.ch> - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include "TCanvas.h" -#include "TFile.h" -#include "TTree.h" - -#include "TPCReconstruction/KrCluster.h" -#include "TPCReconstruction/KrBoxClusterFinder.h" -#include "DataFormatsTPC/Digit.h" - -#include <array> -#include <iostream> -#include <tuple> -#include <vector> -#endif - -void findKrBoxCluster(int lastTimeBin = 1000, int run = -1, int time = -1) -{ - // Read the digits: - TFile* file = new TFile("tpcdigits.root"); - TTree* tree = (TTree*)file->Get("o2sim"); - Long64_t nEntries = tree->GetEntries(); - std::cout << "The Tree has " << nEntries << " Entries." << std::endl; - - // Initialize File for later writing - TFile* fOut = new TFile("BoxClusters.root", "RECREATE"); - TTree* tClusters = new TTree("Clusters", "Clusters"); - - // Create a Branch for each sector: - std::vector<o2::tpc::KrCluster> clusters; - tClusters->Branch("cls", &clusters); - tClusters->Branch("run", &run); - tClusters->Branch("time", &time); - - std::array<std::vector<o2::tpc::Digit>*, 36> digitizedSignal; - for (size_t iSec = 0; iSec < digitizedSignal.size(); ++iSec) { - digitizedSignal[iSec] = nullptr; - tree->SetBranchAddress(Form("TPCDigit_%zu", iSec), &digitizedSignal[iSec]); - } - - // Now everything can get processed - // Loop over all events - for (int iEvent = 0; iEvent < nEntries; ++iEvent) { - std::cout << iEvent + 1 << "/" << nEntries << std::endl; - tree->GetEntry(iEvent); - // Each event consists of sectors (atm only two) - for (int i = 0; i < 36; i++) { - auto sector = digitizedSignal[i]; - if (sector->size() == 0) { - continue; - } - // Create ClusterFinder Object on Heap since creation on stack fails - // Probably due to too much memory consumption - auto clFinder = std::make_unique<o2::tpc::KrBoxClusterFinder>(*sector); - std::vector<std::tuple<int, int, int>> localMaxima = clFinder->findLocalMaxima(); - // Loop over cluster centers - for (const std::tuple<int, int, int>& coords : localMaxima) { - int padMax = std::get<0>(coords); - int rowMax = std::get<1>(coords); - int timeMax = std::get<2>(coords); - - if (timeMax >= lastTimeBin) { - continue; - } - // Build total cluster - o2::tpc::KrCluster tempCluster = clFinder->buildCluster(padMax, rowMax, timeMax); - tempCluster.sector = i; - clusters.emplace_back(tempCluster); - } - } - // Fill Tree - tClusters->Fill(); - clusters.clear(); - } - // Write Tree to file - fOut->Write(); - fOut->Close(); - return; -} +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file findKrBoxCluster.C +/// \brief This macro retrieves clusters from Krypton and X-Ray runs, input tpcdigits.root +/// \author Philip Hauer <philip.hauer@cern.ch> + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "TCanvas.h" +#include "TFile.h" +#include "TTree.h" + +#include "DataFormatsTPC/KrCluster.h" +#include "TPCReconstruction/KrBoxClusterFinder.h" +#include "DataFormatsTPC/Digit.h" + +#include <array> +#include <iostream> +#include <tuple> +#include <vector> +#endif + +void findKrBoxCluster(int lastTimeBin = 1000, int run = -1, int time = -1, std::string_view gainMapFile = "", std::string inputFile = "tpcdigits.root", std::string outputFile = "BoxClusters.root") +{ + // Read the digits: + TFile* file = new TFile(inputFile.c_str()); + TTree* tree = (TTree*)file->Get("o2sim"); + Long64_t nEntries = tree->GetEntries(); + std::cout << "The Tree has " << nEntries << " Entries." << std::endl; + + // Initialize File for later writing + TFile* fOut = new TFile(outputFile.c_str(), "RECREATE"); + TTree* tClusters = new TTree("Clusters", "Clusters"); + + // Create KrBoxClusterFinder object, memory is only allocated once + auto clFinder = std::make_unique<o2::tpc::KrBoxClusterFinder>(); + auto& clusters = clFinder->getClusters(); + // Create a Branch for each sector: + tClusters->Branch("cls", &clusters); + tClusters->Branch("run", &run); + tClusters->Branch("time", &time); + + std::array<std::vector<o2::tpc::Digit>*, 36> digitizedSignal; + for (size_t iSec = 0; iSec < digitizedSignal.size(); ++iSec) { + digitizedSignal[iSec] = nullptr; + tree->SetBranchAddress(Form("TPCDigit_%zu", iSec), &digitizedSignal[iSec]); + } + + if (gainMapFile.size()) { + clFinder->loadGainMapFromFile(gainMapFile); + } + + // clFinder->setMinNumberOfNeighbours(0); + // clFinder->setMinQTreshold(0); + clFinder->setMaxTimes(lastTimeBin); + + // Now everything can get processed + // Loop over all events + for (int iEvent = 0; iEvent < nEntries; ++iEvent) { + std::cout << iEvent + 1 << "/" << nEntries << std::endl; + tree->GetEntry(iEvent); + + for (int i = 0; i < 36; i++) { + auto sector = digitizedSignal[i]; + if (sector->size() == 0) { + continue; + } + std::cout << "Processing sector " << i << "\n"; + + clFinder->loopOverSector(*sector, i); + } + // Fill Tree + tClusters->Fill(); + clusters.clear(); + } + // Write Tree to file + fOut->Write(); + fOut->Close(); + return; +} + +int main() +{ + findKrBoxCluster(); + return 0; +} diff --git a/Detectors/TPC/reconstruction/macro/getTPCTransformationExample.C b/Detectors/TPC/reconstruction/macro/getTPCTransformationExample.C index a33a5f90f83cc..e69c0905f45eb 100644 --- a/Detectors/TPC/reconstruction/macro/getTPCTransformationExample.C +++ b/Detectors/TPC/reconstruction/macro/getTPCTransformationExample.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/macro/readClusters.C b/Detectors/TPC/reconstruction/macro/readClusters.C index b92021aba8dc3..c11c72455cdfc 100644 --- a/Detectors/TPC/reconstruction/macro/readClusters.C +++ b/Detectors/TPC/reconstruction/macro/readClusters.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/macro/testRawRead.C b/Detectors/TPC/reconstruction/macro/testRawRead.C index e7a34167e9a15..a9cec9984bc1a 100644 --- a/Detectors/TPC/reconstruction/macro/testRawRead.C +++ b/Detectors/TPC/reconstruction/macro/testRawRead.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/run/rawReaderCRU.cxx b/Detectors/TPC/reconstruction/run/rawReaderCRU.cxx index 660bda628c31e..03322cd3b4d32 100644 --- a/Detectors/TPC/reconstruction/run/rawReaderCRU.cxx +++ b/Detectors/TPC/reconstruction/run/rawReaderCRU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/run/readGBTFrames.cxx b/Detectors/TPC/reconstruction/run/readGBTFrames.cxx index 96cac97f2adff..39b817e0d7906 100644 --- a/Detectors/TPC/reconstruction/run/readGBTFrames.cxx +++ b/Detectors/TPC/reconstruction/run/readGBTFrames.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/run/readRawData.cxx b/Detectors/TPC/reconstruction/run/readRawData.cxx index 137d5d40486c6..441d651b093fe 100644 --- a/Detectors/TPC/reconstruction/run/readRawData.cxx +++ b/Detectors/TPC/reconstruction/run/readRawData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/AdcClockMonitor.cxx b/Detectors/TPC/reconstruction/src/AdcClockMonitor.cxx index 8b0f3be173da4..183a76a6129a2 100644 --- a/Detectors/TPC/reconstruction/src/AdcClockMonitor.cxx +++ b/Detectors/TPC/reconstruction/src/AdcClockMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/CTFCoder.cxx b/Detectors/TPC/reconstruction/src/CTFCoder.cxx index 07a3ce315c8a7..5b39585c4602f 100644 --- a/Detectors/TPC/reconstruction/src/CTFCoder.cxx +++ b/Detectors/TPC/reconstruction/src/CTFCoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -91,6 +92,8 @@ void CTFCoder::setCompClusAddresses(CompressedClusters& c, void*& buff) ///________________________________ void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) { + using namespace detail; + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); if (!buff.size()) { @@ -99,73 +102,55 @@ void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase:: } throw std::runtime_error("Failed to create CTF dictionaty"); } - const auto* ctf = CTF::get(buff.data()); + const CTF::container_t* ctf = CTF::get(buff.data()); mCombineColumns = ctf->getHeader().flags & CTFHeader::CombinedColumns; LOG(INFO) << "TPC CTF Columns Combining " << (mCombineColumns ? "ON" : "OFF"); - auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { - o2::rans::FrequencyTable ft; - auto bl = ctf->getBlock(slot); - auto md = ctf->getMetadata(slot); - ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); - return std::move(ft); - }; - auto getProbBits = [ctf](CTF::Slots slot) -> int { - return ctf->getMetadata(slot).probabilityBits; - }; - - CompressedClusters cc; // just to get member types -#define MAKECODER(part, slot) createCoder<std::remove_pointer<decltype(part)>::type>(op, getFreq(slot), getProbBits(slot), int(slot)) - // clang-format off + const CompressedClusters cc; // just to get member types if (mCombineColumns) { - MAKECODER( (MPTR<CTF::NBitsQTot, CTF::NBitsQMax>()), CTF::BLCqTotA); // merged qTotA and qMaxA - } - else { - MAKECODER(cc.qTotA, CTF::BLCqTotA); + buildCoder<combinedType_t<CTF::NBitsQTot, CTF::NBitsQMax>>(op, *ctf, CTF::BLCqTotA); + } else { + buildCoder<std::remove_pointer_t<decltype(cc.qTotA)>>(op, *ctf, CTF::BLCqTotA); } - MAKECODER(cc.qMaxA, CTF::BLCqMaxA); - MAKECODER(cc.flagsA, CTF::BLCflagsA); + buildCoder<std::remove_pointer_t<decltype(cc.qMaxA)>>(op, *ctf, CTF::BLCqMaxA); + buildCoder<std::remove_pointer_t<decltype(cc.flagsA)>>(op, *ctf, CTF::BLCflagsA); if (mCombineColumns) { - MAKECODER( (MPTR<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>()), CTF::BLCrowDiffA); // merged rowDiffA and sliceLegDiffA - } - else { - MAKECODER(cc.rowDiffA, CTF::BLCrowDiffA); + buildCoder<combinedType_t<CTF::NBitsRowDiff, CTF::NBitsSliceLegDiff>>(op, *ctf, CTF::BLCrowDiffA); // merged rowDiffA and sliceLegDiffA + + } else { + buildCoder<std::remove_pointer_t<decltype(cc.rowDiffA)>>(op, *ctf, CTF::BLCrowDiffA); } - MAKECODER(cc.sliceLegDiffA, CTF::BLCsliceLegDiffA); - MAKECODER(cc.padResA, CTF::BLCpadResA); - MAKECODER(cc.timeResA, CTF::BLCtimeResA); + buildCoder<std::remove_pointer_t<decltype(cc.sliceLegDiffA)>>(op, *ctf, CTF::BLCsliceLegDiffA); + buildCoder<std::remove_pointer_t<decltype(cc.padResA)>>(op, *ctf, CTF::BLCpadResA); + buildCoder<std::remove_pointer_t<decltype(cc.timeResA)>>(op, *ctf, CTF::BLCtimeResA); if (mCombineColumns) { - MAKECODER( (MPTR<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>()), CTF::BLCsigmaPadA); // merged sigmaPadA and sigmaTimeA - } - else { - MAKECODER(cc.sigmaPadA, CTF::BLCsigmaPadA); + buildCoder<combinedType_t<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>>(op, *ctf, CTF::BLCsigmaPadA); // merged sigmaPadA and sigmaTimeA + } else { + buildCoder<std::remove_pointer_t<decltype(cc.sigmaPadA)>>(op, *ctf, CTF::BLCsigmaPadA); } - MAKECODER(cc.sigmaTimeA, CTF::BLCsigmaTimeA); - MAKECODER(cc.qPtA, CTF::BLCqPtA); - MAKECODER(cc.rowA, CTF::BLCrowA); - MAKECODER(cc.sliceA, CTF::BLCsliceA); - MAKECODER(cc.timeA, CTF::BLCtimeA); - MAKECODER(cc.padA, CTF::BLCpadA); + buildCoder<std::remove_pointer_t<decltype(cc.sigmaTimeA)>>(op, *ctf, CTF::BLCsigmaTimeA); + buildCoder<std::remove_pointer_t<decltype(cc.qPtA)>>(op, *ctf, CTF::BLCqPtA); + buildCoder<std::remove_pointer_t<decltype(cc.rowA)>>(op, *ctf, CTF::BLCrowA); + buildCoder<std::remove_pointer_t<decltype(cc.sliceA)>>(op, *ctf, CTF::BLCsliceA); + buildCoder<std::remove_pointer_t<decltype(cc.timeA)>>(op, *ctf, CTF::BLCtimeA); + buildCoder<std::remove_pointer_t<decltype(cc.padA)>>(op, *ctf, CTF::BLCpadA); if (mCombineColumns) { - MAKECODER( (MPTR<CTF::NBitsQTot, CTF::NBitsQMax>()), CTF::BLCqTotU); // merged qTotU and qMaxU - } - else { - MAKECODER(cc.qTotU, CTF::BLCqTotU); + buildCoder<combinedType_t<CTF::NBitsQTot, CTF::NBitsQMax>>(op, *ctf, CTF::BLCqTotU); // merged qTotU and qMaxU + } else { + buildCoder<std::remove_pointer_t<decltype(cc.qTotU)>>(op, *ctf, CTF::BLCqTotU); } - MAKECODER(cc.qMaxU, CTF::BLCqMaxU); - MAKECODER(cc.flagsU, CTF::BLCflagsU); - MAKECODER(cc.padDiffU, CTF::BLCpadDiffU); - MAKECODER(cc.timeDiffU, CTF::BLCtimeDiffU); + buildCoder<std::remove_pointer_t<decltype(cc.qMaxU)>>(op, *ctf, CTF::BLCqMaxU); + buildCoder<std::remove_pointer_t<decltype(cc.flagsU)>>(op, *ctf, CTF::BLCflagsU); + buildCoder<std::remove_pointer_t<decltype(cc.padDiffU)>>(op, *ctf, CTF::BLCpadDiffU); + buildCoder<std::remove_pointer_t<decltype(cc.timeDiffU)>>(op, *ctf, CTF::BLCtimeDiffU); if (mCombineColumns) { - MAKECODER( (MPTR<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>()), CTF::BLCsigmaPadU); // merged sigmaPadA and sigmaTimeA - } - else { - MAKECODER(cc.sigmaPadU, CTF::BLCsigmaPadU); + buildCoder<combinedType_t<CTF::NBitsSigmaPad, CTF::NBitsSigmaTime>>(op, *ctf, CTF::BLCsigmaPadU); // merged sigmaPadU and sigmaTimeU + } else { + buildCoder<std::remove_pointer_t<decltype(cc.sigmaPadU)>>(op, *ctf, CTF::BLCsigmaPadU); } - MAKECODER(cc.sigmaTimeU, CTF::BLCsigmaTimeU); - MAKECODER(cc.nTrackClusters, CTF::BLCnTrackClusters); - MAKECODER(cc.nSliceRowClusters, CTF::BLCnSliceRowClusters); - // clang-format on + buildCoder<std::remove_pointer_t<decltype(cc.sigmaTimeU)>>(op, *ctf, CTF::BLCsigmaTimeU); + buildCoder<std::remove_pointer_t<decltype(cc.nTrackClusters)>>(op, *ctf, CTF::BLCnTrackClusters); + buildCoder<std::remove_pointer_t<decltype(cc.nSliceRowClusters)>>(op, *ctf, CTF::BLCnSliceRowClusters); } /// make sure loaded dictionaries (if any) are consistent with data @@ -215,7 +200,7 @@ size_t CTFCoder::estimateCompressedSize(const CompressedClusters& ccl) sz += ESTSIZE(CTF::BLCnTrackClusters, ccl.nTrackClusters, ccl.nTracks); sz += ESTSIZE(CTF::BLCnSliceRowClusters, ccl.nSliceRowClusters, ccl.nSliceRows); // clang-format on - + sz *= 2. / 3; // if needed, will be autoexpanded LOG(INFO) << "Estimated output size is " << sz << " bytes"; return sz; } diff --git a/Detectors/TPC/reconstruction/src/ClustererTask.cxx b/Detectors/TPC/reconstruction/src/ClustererTask.cxx index 67bbb1b207dbc..b7c39610941f3 100644 --- a/Detectors/TPC/reconstruction/src/ClustererTask.cxx +++ b/Detectors/TPC/reconstruction/src/ClustererTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/DigitalCurrentClusterIntegrator.cxx b/Detectors/TPC/reconstruction/src/DigitalCurrentClusterIntegrator.cxx index 23e53d0817058..6acefe467e9ba 100644 --- a/Detectors/TPC/reconstruction/src/DigitalCurrentClusterIntegrator.cxx +++ b/Detectors/TPC/reconstruction/src/DigitalCurrentClusterIntegrator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/GBTFrame.cxx b/Detectors/TPC/reconstruction/src/GBTFrame.cxx index 113327cac75be..26a77b02d7cfa 100644 --- a/Detectors/TPC/reconstruction/src/GBTFrame.cxx +++ b/Detectors/TPC/reconstruction/src/GBTFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/GBTFrameContainer.cxx b/Detectors/TPC/reconstruction/src/GBTFrameContainer.cxx index cce8657deeb46..95a0cb57c2162 100644 --- a/Detectors/TPC/reconstruction/src/GBTFrameContainer.cxx +++ b/Detectors/TPC/reconstruction/src/GBTFrameContainer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx b/Detectors/TPC/reconstruction/src/GPUCATracking.cxx deleted file mode 100644 index 8f9a52ab3e55c..0000000000000 --- a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUCATracking.cxx -/// \author David Rohr - -#include "TPCReconstruction/GPUCATracking.h" - -#include "FairLogger.h" -#include "ReconstructionDataFormats/Track.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "TChain.h" -#include "TClonesArray.h" -#include "TPCBase/Mapper.h" -#include "TPCBase/PadRegionInfo.h" -#include "TPCBase/ParameterDetector.h" -#include "TPCBase/ParameterElectronics.h" -#include "TPCBase/ParameterGas.h" -#include "TPCBase/Sector.h" -#include "DataFormatsTPC/Digit.h" -#include "DataFormatsTPC/ClusterNativeHelper.h" -#include "DetectorsRaw/HBFUtils.h" - -#include "GPUO2Interface.h" -#include "GPUO2InterfaceConfiguration.h" -#include "GPUTPCGMMergedTrack.h" -#include "GPUTPCGMMergedTrackHit.h" -#include "GPUTPCGMMergerTypes.h" -#include "GPUHostDataTypes.h" -#include "GPUQAHelper.h" -#include "TPCFastTransform.h" - -#include <atomic> -#include <optional> -#ifdef WITH_OPENMP -#include <omp.h> -#endif - -using namespace o2::gpu; -using namespace o2::tpc; -using namespace o2; -using namespace o2::dataformats; - -GPUCATracking::GPUCATracking() = default; -GPUCATracking::~GPUCATracking() { deinitialize(); } - -int GPUCATracking::initialize(const GPUO2InterfaceConfiguration& config) -{ - mTrackingCAO2Interface.reset(new GPUTPCO2Interface); - int retVal = mTrackingCAO2Interface->Initialize(config); - if (retVal) { - mTrackingCAO2Interface.reset(); - } - return (retVal); -} - -void GPUCATracking::deinitialize() -{ - mTrackingCAO2Interface.reset(); -} - -int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* outputs) -{ - if ((int)(data->tpcZS != nullptr) + (int)(data->o2Digits != nullptr && (data->tpcZS == nullptr || data->o2DigitsMC == nullptr)) + (int)(data->clusters != nullptr) + (int)(data->compressedClusters != nullptr) != 1) { - throw std::runtime_error("Invalid input for gpu tracking"); - } - - constexpr unsigned char flagsReject = GPUTPCGMMergedTrackHit::flagReject | GPUTPCGMMergedTrackHit::flagNotFit; - const unsigned int flagsRequired = mTrackingCAO2Interface->getConfig().configInterface.dropSecondaryLegs ? gputpcgmmergertypes::attachGoodLeg : 0; - - std::vector<TrackTPC>* outputTracks = data->outputTracks; - std::vector<uint32_t>* outClusRefs = data->outputClusRefs; - std::vector<o2::MCCompLabel>* outputTracksMCTruth = data->outputTracksMCTruth; - - if (!outputTracks || !outClusRefs) { - LOG(ERROR) << "Output tracks or clusRefs vectors are not initialized"; - return 0; - } - auto& detParam = ParameterDetector::Instance(); - auto& gasParam = ParameterGas::Instance(); - auto& elParam = ParameterElectronics::Instance(); - float vzbin = (elParam.ZbinWidth * gasParam.DriftV); - Mapper& mapper = Mapper::instance(); - - std::vector<o2::tpc::Digit> gpuDigits[Sector::MAXSECTOR]; - o2::dataformats::MCTruthContainer<o2::MCCompLabel> gpuDigitsMC[Sector::MAXSECTOR]; - ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer gpuDigitsMCConst[Sector::MAXSECTOR]; - - GPUTrackingInOutDigits gpuDigitsMap; - GPUTPCDigitsMCInput gpuDigitsMapMC; - GPUTrackingInOutPointers ptrs; - - ptrs.tpcCompressedClusters = data->compressedClusters; - ptrs.tpcZS = data->tpcZS; - if (data->o2Digits) { - const float zsThreshold = mTrackingCAO2Interface->getConfig().configReconstruction.tpcZSthreshold; - const int maxContTimeBin = mTrackingCAO2Interface->getConfig().configEvent.continuousMaxTimeBin; - for (int i = 0; i < Sector::MAXSECTOR; i++) { - const auto& d = (*(data->o2Digits))[i]; - if (zsThreshold > 0 && data->tpcZS == nullptr) { - gpuDigits[i].reserve(d.size()); - } - for (int j = 0; j < d.size(); j++) { - if (maxContTimeBin && d[j].getTimeStamp() >= maxContTimeBin) { - throw std::runtime_error("Digit time bin exceeds time frame length"); - } - if (zsThreshold > 0 && data->tpcZS == nullptr) { - if (d[j].getChargeFloat() >= zsThreshold) { - if (data->o2DigitsMC) { - for (const auto& element : (*data->o2DigitsMC)[i]->getLabels(j)) { - gpuDigitsMC[i].addElement(gpuDigits[i].size(), element); - } - } - gpuDigits[i].emplace_back(d[j]); - } - } - } - if (zsThreshold > 0 && data->tpcZS == nullptr) { - gpuDigitsMap.tpcDigits[i] = gpuDigits[i].data(); - gpuDigitsMap.nTPCDigits[i] = gpuDigits[i].size(); - if (data->o2DigitsMC) { - gpuDigitsMC[i].flatten_to(gpuDigitsMCConst[i].first); - gpuDigitsMCConst[i].second = gpuDigitsMCConst[i].first; - gpuDigitsMapMC.v[i] = &gpuDigitsMCConst[i].second; - } - } else { - gpuDigitsMap.tpcDigits[i] = (*(data->o2Digits))[i].data(); - gpuDigitsMap.nTPCDigits[i] = (*(data->o2Digits))[i].size(); - if (data->o2DigitsMC) { - gpuDigitsMapMC.v[i] = (*data->o2DigitsMC)[i]; - } - } - } - if (data->o2DigitsMC) { - gpuDigitsMap.tpcDigitsMC = &gpuDigitsMapMC; - } - ptrs.tpcPackedDigits = &gpuDigitsMap; - } - ptrs.clustersNative = data->clusters; - int retVal = mTrackingCAO2Interface->RunTracking(&ptrs, outputs); - if (data->o2Digits || data->tpcZS || data->compressedClusters) { - data->clusters = ptrs.clustersNative; - } - data->compressedClusters = ptrs.tpcCompressedClusters; - const GPUTPCGMMergedTrack* tracks = ptrs.mergedTracks; - int nTracks = ptrs.nMergedTracks; - const GPUTPCGMMergedTrackHit* trackClusters = ptrs.mergedTrackHits; - - if (retVal) { - return retVal; - } - - std::vector<std::pair<int, float>> trackSort(nTracks); - int tmp = 0, tmp2 = 0; - uint32_t clBuff = 0; - for (char cside = 0; cside < 2; cside++) { - for (int i = 0; i < nTracks; i++) { - if (tracks[i].OK() && tracks[i].CSide() == cside) { - trackSort[tmp++] = {i, tracks[i].GetParam().GetTZOffset()}; - auto ncl = tracks[i].NClusters(); - clBuff += ncl + (ncl + 1) / 2; // actual N clusters to store will be less - } - } - std::sort(trackSort.data() + tmp2, trackSort.data() + tmp, - [](const auto& a, const auto& b) { return (a.second > b.second); }); - tmp2 = tmp; - } - nTracks = tmp; - outputTracks->resize(nTracks); - outClusRefs->resize(clBuff); - - std::atomic_int clusterOffsetCounter; - clusterOffsetCounter.store(0); - - constexpr float MinDelta = 0.1; - - auto labelAssigner = (outputTracksMCTruth && data->clusters->clustersMCTruth) ? std::make_optional(GPUTPCTrkLbl(data->clusters->clustersMCTruth, sTrackMCMaxFake)) : std::nullopt; - -#ifdef WITH_OPENMP -#pragma omp parallel for if(!outputTracksMCTruth) num_threads(4) -#endif - for (int iTmp = 0; iTmp < nTracks; iTmp++) { - auto& oTrack = (*outputTracks)[iTmp]; - const int i = trackSort[iTmp].first; - labelAssigner->reset(); - - oTrack = - TrackTPC(tracks[i].GetParam().GetX(), tracks[i].GetAlpha(), - {tracks[i].GetParam().GetY(), tracks[i].GetParam().GetZ(), tracks[i].GetParam().GetSinPhi(), - tracks[i].GetParam().GetDzDs(), tracks[i].GetParam().GetQPt()}, - {tracks[i].GetParam().GetCov(0), tracks[i].GetParam().GetCov(1), tracks[i].GetParam().GetCov(2), - tracks[i].GetParam().GetCov(3), tracks[i].GetParam().GetCov(4), tracks[i].GetParam().GetCov(5), - tracks[i].GetParam().GetCov(6), tracks[i].GetParam().GetCov(7), tracks[i].GetParam().GetCov(8), - tracks[i].GetParam().GetCov(9), tracks[i].GetParam().GetCov(10), tracks[i].GetParam().GetCov(11), - tracks[i].GetParam().GetCov(12), tracks[i].GetParam().GetCov(13), tracks[i].GetParam().GetCov(14)}); - - oTrack.setChi2(tracks[i].GetParam().GetChi2()); - auto& outerPar = tracks[i].OuterParam(); - oTrack.setdEdx(tracks[i].dEdxInfo()); - oTrack.setOuterParam(o2::track::TrackParCov( - outerPar.X, outerPar.alpha, - {outerPar.P[0], outerPar.P[1], outerPar.P[2], outerPar.P[3], outerPar.P[4]}, - {outerPar.C[0], outerPar.C[1], outerPar.C[2], outerPar.C[3], outerPar.C[4], outerPar.C[5], - outerPar.C[6], outerPar.C[7], outerPar.C[8], outerPar.C[9], outerPar.C[10], outerPar.C[11], - outerPar.C[12], outerPar.C[13], outerPar.C[14]})); - int nOutCl = 0; - for (int j = 0; j < tracks[i].NClusters(); j++) { - if ((trackClusters[tracks[i].FirstClusterRef() + j].state & flagsReject) || (ptrs.mergedTrackHitAttachment[trackClusters[tracks[i].FirstClusterRef() + j].num] & flagsRequired) != flagsRequired) { - continue; - } - nOutCl++; - } - clBuff = clusterOffsetCounter.fetch_add(nOutCl + (nOutCl + 1) / 2); - oTrack.setClusterRef(clBuff, nOutCl); // register the references - uint32_t* clIndArr = &(*outClusRefs)[clBuff]; // cluster indices start here - uint8_t* sectorIndexArr = reinterpret_cast<uint8_t*>(clIndArr + nOutCl); - uint8_t* rowIndexArr = sectorIndexArr + nOutCl; - - int nOutCl2 = 0; - float t1, t2; - int sector1, sector2; - for (int j = 0; j < tracks[i].NClusters(); j++) { - if ((trackClusters[tracks[i].FirstClusterRef() + j].state & flagsReject) || (ptrs.mergedTrackHitAttachment[trackClusters[tracks[i].FirstClusterRef() + j].num] & flagsRequired) != flagsRequired) { - continue; - } - int clusterIdGlobal = trackClusters[tracks[i].FirstClusterRef() + j].num; - Sector sector = trackClusters[tracks[i].FirstClusterRef() + j].slice; - int globalRow = trackClusters[tracks[i].FirstClusterRef() + j].row; - int clusterIdInRow = clusterIdGlobal - data->clusters->clusterOffset[sector][globalRow]; - int regionNumber = 0; - while (globalRow > mapper.getGlobalRowOffsetRegion(regionNumber) + mapper.getNumberOfRowsRegion(regionNumber)) { - regionNumber++; - } - clIndArr[nOutCl2] = clusterIdInRow; - sectorIndexArr[nOutCl2] = sector; - rowIndexArr[nOutCl2] = globalRow; - if (nOutCl2 == 0) { - t1 = data->clusters->clustersLinear[clusterIdGlobal].getTime(); - sector1 = sector; - } - nOutCl2++; - if (nOutCl2 == nOutCl) { - t2 = data->clusters->clustersLinear[clusterIdGlobal].getTime(); - sector2 = sector; - } - if (outputTracksMCTruth && data->clusters->clustersMCTruth) { - labelAssigner->addLabel(clusterIdGlobal); - } - } - - bool cce = tracks[i].CCE() && ((sector1 < Sector::MAXSECTOR / 2) ^ (sector2 < Sector::MAXSECTOR / 2)); - float time0 = 0.f, tFwd = 0.f, tBwd = 0.f; - if (mTrackingCAO2Interface->GetParamContinuous()) { - time0 = tracks[i].GetParam().GetTZOffset(); - - if (cce) { - bool lastSide = trackClusters[tracks[i].FirstClusterRef()].slice < Sector::MAXSECTOR / 2; - float delta = 0.f; - for (int iCl = 1; iCl < tracks[i].NClusters(); iCl++) { - if (lastSide ^ (trackClusters[tracks[i].FirstClusterRef() + iCl].slice < Sector::MAXSECTOR / 2)) { - auto& cacl1 = trackClusters[tracks[i].FirstClusterRef() + iCl]; - auto& cacl2 = trackClusters[tracks[i].FirstClusterRef() + iCl - 1]; - auto& cl1 = data->clusters->clustersLinear[cacl1.num]; - auto& cl2 = data->clusters->clustersLinear[cacl2.num]; - delta = fabs(cl1.getTime() - cl2.getTime()) * 0.5f; - if (delta < MinDelta) { - delta = MinDelta; - } - break; - } - } - tFwd = tBwd = delta; - } else { - // estimate max/min time increments which still keep track in the physical limits of the TPC - auto times = std::minmax(t1, t2); - tFwd = times.first - time0; - tBwd = time0 - times.second + mTrackingCAO2Interface->getConfig().configCalib.fastTransform->getMaxDriftTime(t1 > t2 ? sector1 : sector2); - } - } - oTrack.setTime0(time0); - oTrack.setDeltaTBwd(tBwd); - oTrack.setDeltaTFwd(tFwd); - if (cce) { - oTrack.setHasCSideClusters(); - oTrack.setHasASideClusters(); - } else if (tracks[i].CSide()) { - oTrack.setHasCSideClusters(); - } else { - oTrack.setHasASideClusters(); - } - - if (outputTracksMCTruth) { - outputTracksMCTruth->emplace_back(labelAssigner->computeLabel()); - } - } - outClusRefs->resize(clusterOffsetCounter.load()); // remove overhead - - mTrackingCAO2Interface->Clear(false); - - return (retVal); -} - -float GPUCATracking::getPseudoVDrift() -{ - auto& gasParam = ParameterGas::Instance(); - auto& elParam = ParameterElectronics::Instance(); - return (elParam.ZbinWidth * gasParam.DriftV); -} - -void GPUCATracking::GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const -{ - if (mTrackingCAO2Interface == nullptr) { - return; - } - mTrackingCAO2Interface->GetClusterErrors2(row, z, sinPhi, DzDs, clusterState, ErrY2, ErrZ2); -} - -int GPUCATracking::registerMemoryForGPU(const void* ptr, size_t size) -{ - return mTrackingCAO2Interface->registerMemoryForGPU(ptr, size); -} - -int GPUCATracking::unregisterMemoryForGPU(const void* ptr) -{ - return mTrackingCAO2Interface->unregisterMemoryForGPU(ptr); -} diff --git a/Detectors/TPC/reconstruction/src/HalfSAMPAData.cxx b/Detectors/TPC/reconstruction/src/HalfSAMPAData.cxx index facd04332b2d2..8b57f9bfd4569 100644 --- a/Detectors/TPC/reconstruction/src/HalfSAMPAData.cxx +++ b/Detectors/TPC/reconstruction/src/HalfSAMPAData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/HardwareClusterDecoder.cxx b/Detectors/TPC/reconstruction/src/HardwareClusterDecoder.cxx index a11156a2e0d05..85f58c5dd6c8f 100644 --- a/Detectors/TPC/reconstruction/src/HardwareClusterDecoder.cxx +++ b/Detectors/TPC/reconstruction/src/HardwareClusterDecoder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/HwClusterer.cxx b/Detectors/TPC/reconstruction/src/HwClusterer.cxx index f7016bf40ea45..fc804eb1a60db 100644 --- a/Detectors/TPC/reconstruction/src/HwClusterer.cxx +++ b/Detectors/TPC/reconstruction/src/HwClusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/HwClustererParam.cxx b/Detectors/TPC/reconstruction/src/HwClustererParam.cxx index 29190bea020ba..a5553042a276b 100644 --- a/Detectors/TPC/reconstruction/src/HwClustererParam.cxx +++ b/Detectors/TPC/reconstruction/src/HwClustererParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/KrBoxClusterFinder.cxx b/Detectors/TPC/reconstruction/src/KrBoxClusterFinder.cxx index df12de4060693..159557bc6f7c1 100644 --- a/Detectors/TPC/reconstruction/src/KrBoxClusterFinder.cxx +++ b/Detectors/TPC/reconstruction/src/KrBoxClusterFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,58 +14,181 @@ /// \author Philip Hauer <hauer@hiskp.uni-bonn.de> #include "TPCReconstruction/KrBoxClusterFinder.h" +#include "TPCBase/CalDet.h" +#include "TPCBase/Utils.h" + #include "Framework/Logger.h" +#include <TFile.h> +#include <vector> + using namespace o2::tpc; -// Constructor: -// This function creates a three dimensional vector (Pad,Row,Time) which is -// filled with the charges -KrBoxClusterFinder::KrBoxClusterFinder(std::vector<o2::tpc::Digit>& eventSector) +// If a gain map already exists in form of a CalDet file, it can be specified here +void KrBoxClusterFinder::loadGainMapFromFile(const std::string_view calDetFileName, const std::string_view gainMapName) { - if (eventSector.size() == 0) { - // prevents a segementation fault if the envent contains no data - // segementation fault would occure later when trying to dereference the - // max/min pointer (which are nullptr if data is empty) empty events should - // be catched in the main function, hence, this "if" is no longer necessary - LOGP(warning, "Sector size (amount of data points) in current run is 0!"); - LOGP(warning, "mMapOfAllDigits with 0's is generated in order to prevent a segementation fault."); + auto calPads = utils::readCalPads(calDetFileName, gainMapName); + auto gain = calPads[0]; + if (!gain) { + LOGP(error, "No valid gain map object '{}' could be loaded from file '{}'", calDetFileName, gainMapName); return; } + mGainMap.reset(gain); + LOGP(info, "Loaded gain map object '{}' from file '{}'", calDetFileName, gainMapName); +} + +void KrBoxClusterFinder::createInitialMap(const gsl::span<const Digit> eventSector) +{ + mSetOfTimeSlices.clear(); + mThresholdInfo.clear(); + + for (int iTimeSlice = 0; iTimeSlice <= 2 * mMaxClusterSizeTime; ++iTimeSlice) { + addTimeSlice(eventSector, iTimeSlice); + } +} - // Fill digits map - for (const auto& digit : eventSector) { +void KrBoxClusterFinder::fillADCValueInLastSlice(int cru, int rowInSector, int padInRow, float adcValue) +{ + auto& timeSlice = mSetOfTimeSlices.back(); + auto& thresholdInfo = mThresholdInfo.back(); + + // Correct for pad offset: + const int padsInRow = mMapperInstance.getNumberOfPadsInRowSector(rowInSector); + const int corPad = padInRow - (padsInRow / 2) + (MaxPads / 2); + + if (adcValue > mQThresholdMax) { + thresholdInfo.digitAboveThreshold = true; + thresholdInfo.rowAboveThreshold[rowInSector] = true; + } + + // Get correction factor from gain map: + const auto correctionFactorCalDet = mGainMap.get(); + if (!correctionFactorCalDet) { + timeSlice[rowInSector][corPad] = adcValue; + return; + } + + int padNum = mMapperInstance.globalPadNumber(PadPos(rowInSector, padInRow)); + float correctionFactor = correctionFactorCalDet->getValue(mSector, padNum); + + if (correctionFactor == 0) { + LOGP(warning, "Encountered correction factor which is zero."); + LOGP(warning, "Digit will be set to 0!"); + adcValue = 0; + } else { + adcValue /= correctionFactor; + } + + timeSlice[rowInSector][corPad] = adcValue; +} + +void KrBoxClusterFinder::addTimeSlice(const gsl::span<const Digit> eventSector, const int timeSlice) +{ + mSetOfTimeSlices.emplace_back(); + mThresholdInfo.emplace_back(); + + for (; mFirstDigit < eventSector.size(); ++mFirstDigit) { + const auto& digit = eventSector[mFirstDigit]; const int time = digit.getTimeStamp(); - const int row = digit.getRow(); - const int pad = digit.getPad(); + if (time != timeSlice) { + return; + } + + const int cru = digit.getCRU(); + mSector = cru / CRU::CRUperSector; + + const int rowInSector = digit.getRow(); + const int padInRow = digit.getPad(); + const float adcValue = digit.getChargeFloat(); + + fillADCValueInLastSlice(cru, rowInSector, padInRow, adcValue); + } +} - const int pads = mMapperInstance.getNumberOfPadsInRowSector(row); - const int corPad = pad - (pads / 2) + (MaxPads / 2); +void KrBoxClusterFinder::loopOverSector(const gsl::span<const Digit> eventSector, const int sector) +{ + mFirstDigit = 0; + mSector = sector; + + createInitialMap(eventSector); + for (int iTimeSlice = mMaxClusterSizeTime; iTimeSlice < mMaxTimes - mMaxClusterSizeTime; ++iTimeSlice) { + // only search for a local maximum if the central time slice has at least one ADC above the charge threshold + if (mThresholdInfo[mMaxClusterSizeTime].digitAboveThreshold) { + findLocalMaxima(true, iTimeSlice); + } + popFirstTimeSliceFromMap(); + addTimeSlice(eventSector, iTimeSlice + mMaxClusterSizeTime + 1); - mMapOfAllDigits[time][row][corPad] = digit.getChargeFloat(); + // don't spend unnecessary time looping till mMaxTimes if there is no more data + if (mFirstDigit >= eventSector.size()) { + break; + } } } +void KrBoxClusterFinder::init() +{ + const auto& param = KrBoxClusterFinderParam::Instance(); + + mMaxClusterSizeTime = param.MaxClusterSizeTime; + + mMaxClusterSizeRowIROC = param.MaxClusterSizeRowIROC; + mMaxClusterSizeRowOROC1 = param.MaxClusterSizeRowOROC1; + mMaxClusterSizeRowOROC2 = param.MaxClusterSizeRowOROC2; + mMaxClusterSizeRowOROC3 = param.MaxClusterSizeRowOROC3; + + mMaxClusterSizePadIROC = param.MaxClusterSizePadIROC; + mMaxClusterSizePadOROC1 = param.MaxClusterSizePadOROC1; + mMaxClusterSizePadOROC2 = param.MaxClusterSizePadOROC2; + mMaxClusterSizePadOROC3 = param.MaxClusterSizePadOROC3; + + mQThresholdMax = param.QThresholdMax; + mQThreshold = param.QThreshold; + mMinNumberOfNeighbours = param.MinNumberOfNeighbours; + + mCutMinSigmaTime = param.CutMinSigmaTime; + mCutMaxSigmaTime = param.CutMaxSigmaTime; + mCutMinSigmaPad = param.CutMinSigmaPad; + mCutMaxSigmaPad = param.CutMaxSigmaPad; + mCutMinSigmaRow = param.CutMinSigmaRow; + mCutMaxSigmaRow = param.CutMaxSigmaRow; + mCutMaxQtot = param.CutMaxQtot; + mCutQtot0 = param.CutQtot0; + mCutQtotSizeSlope = param.CutQtotSizeSlope; + mCutMaxSize = param.CutMaxSize; + mApplyCuts = param.ApplyCuts; +} + //################################################# // Function to update the temporal cluster -void KrBoxClusterFinder::updateTempClusterFinal() +void KrBoxClusterFinder::updateTempClusterFinal(const int timeOffset) { - const float oneOverQtot = 1. / mTempCluster.totCharge; - mTempCluster.meanPad *= oneOverQtot; - mTempCluster.sigmaPad *= oneOverQtot; - mTempCluster.meanRow *= oneOverQtot; - mTempCluster.sigmaRow *= oneOverQtot; - mTempCluster.meanTime *= oneOverQtot; - mTempCluster.sigmaTime *= oneOverQtot; - mTempCluster.sigmaPad = std::sqrt(std::abs(mTempCluster.sigmaPad - mTempCluster.meanPad * mTempCluster.meanPad)); - mTempCluster.sigmaRow = std::sqrt(std::abs(mTempCluster.sigmaRow - mTempCluster.meanRow * mTempCluster.meanRow)); - mTempCluster.sigmaTime = std::sqrt(std::abs(mTempCluster.sigmaTime - mTempCluster.meanTime * mTempCluster.meanTime)); - - const int pads = mMapperInstance.getNumberOfPadsInRowSector(int(mTempCluster.meanRow)); - - mTempCluster.meanPad = mTempCluster.meanPad + (pads / 2.0) - (MaxPads / 2.0); + if (mTempCluster.totCharge == 0) { + mTempCluster.reset(); + } else { + const float oneOverQtot = 1. / mTempCluster.totCharge; + mTempCluster.meanPad *= oneOverQtot; + mTempCluster.sigmaPad *= oneOverQtot; + mTempCluster.meanRow *= oneOverQtot; + mTempCluster.sigmaRow *= oneOverQtot; + mTempCluster.meanTime *= oneOverQtot; + mTempCluster.sigmaTime *= oneOverQtot; + mTempCluster.sigmaPad = std::sqrt(std::abs(mTempCluster.sigmaPad - mTempCluster.meanPad * mTempCluster.meanPad)); + mTempCluster.sigmaRow = std::sqrt(std::abs(mTempCluster.sigmaRow - mTempCluster.meanRow * mTempCluster.meanRow)); + mTempCluster.sigmaTime = std::sqrt(std::abs(mTempCluster.sigmaTime - mTempCluster.meanTime * mTempCluster.meanTime)); + + const int corPadsMean = mMapperInstance.getNumberOfPadsInRowSector(int(mTempCluster.meanRow)); + const int corPadsMaxCharge = mMapperInstance.getNumberOfPadsInRowSector(int(mTempCluster.maxChargeRow)); + + // Since every padrow is shifted such that neighbouring pads are indeed neighbours, we have to shift once back: + mTempCluster.meanPad = mTempCluster.meanPad + (corPadsMean / 2.0) - (MaxPads / 2.0); + mTempCluster.maxChargePad = mTempCluster.maxChargePad + (corPadsMaxCharge / 2.0) - (MaxPads / 2.0); + mTempCluster.sector = (decltype(mTempCluster.sector))mSector; + + mTempCluster.meanTime += timeOffset; + } } // Function to update the temporal cluster. @@ -75,7 +199,12 @@ void KrBoxClusterFinder::updateTempCluster(float tempCharge, int tempPad, int te return; } - mTempCluster.size += 1; + // Some extrem ugly shaped clusters (mostly noise) might lead to an overflow. + // Hence, we have to define an upper limit here: + if (mTempCluster.size < 255) { + mTempCluster.size += 1; + } + mTempCluster.totCharge += tempCharge; mTempCluster.meanPad += tempPad * tempCharge; @@ -89,83 +218,145 @@ void KrBoxClusterFinder::updateTempCluster(float tempCharge, int tempPad, int te if (tempCharge > mTempCluster.maxCharge) { mTempCluster.maxCharge = tempCharge; + mTempCluster.maxChargePad = tempPad; + mTempCluster.maxChargeRow = tempRow; } } -// This function finds and evaluates all clusters in a 3D mMapOfAllDigits generated by the -// mMapOfAllDigitsCreator function, this function also updates the cluster tree -std::vector<std::tuple<int, int, int>> KrBoxClusterFinder::findLocalMaxima() +// This function finds and evaluates all clusters in a 3D mSetOfTimeSlices generated by the +// mSetOfTimeSlicesCreator function, this function also updates the cluster tree +std::vector<std::tuple<int, int, int>> KrBoxClusterFinder::findLocalMaxima(bool directFilling, const int timeOffset) { std::vector<std::tuple<int, int, int>> localMaximaCoords; - // loop over whole mMapOfAllDigits the find clusers - for (int iTime = 0; iTime < MaxTimes; iTime++) { - for (int iRow = 0; iRow < MaxRows; iRow++) { - for (int iPad = 0; iPad < MaxPads; iPad++) { - mTempCluster.reset(); - const float qMax = mMapOfAllDigits[iTime][iRow][iPad]; + const int iTime = mMaxClusterSizeTime; + const auto& mapRow = mSetOfTimeSlices[iTime]; + const auto& thresholdInfo = mThresholdInfo[iTime]; + + for (int iRow = 0; iRow < MaxRows; iRow++) { // mapRow.size() + // Since pad size is different for each ROC, we take this into account while looking for maxima: + // setMaxClusterSize(iRow); + if (iRow == 0) { + mMaxClusterSizePad = mMaxClusterSizePadIROC; + mMaxClusterSizeRow = mMaxClusterSizeRowIROC; + } else if (iRow == MaxRowsIROC) { + mMaxClusterSizePad = mMaxClusterSizePadOROC1; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC1; + } else if (iRow == MaxRowsIROC + MaxRowsOROC1) { + mMaxClusterSizePad = mMaxClusterSizePadOROC2; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC2; + } else if (iRow == MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2) { + mMaxClusterSizePad = mMaxClusterSizePadOROC3; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC3; + } + // skip rows that don't have charges above the threshold + if (!thresholdInfo.rowAboveThreshold[iRow]) { + continue; + } + + const auto& mapPad = mapRow[iRow]; + const int padsInRow = mMapperInstance.getNumberOfPadsInRowSector(iRow); - // cluster Maximum must at least be larger than Threshold - if (qMax <= mQThresholdMax) { + // Only loop over existing pads: + for (int iPad = MaxPads / 2 - padsInRow / 2; iPad < MaxPads / 2 + padsInRow / 2; iPad++) { // mapPad.size() + + const float qMax = mapPad[iPad]; + + // cluster Maximum must at least be larger than Threshold + if (qMax <= mQThresholdMax) { + continue; + } + + // Acceptance condition: Require at least mMinNumberOfNeighbours neigbours + // with signal in any direction! + int noNeighbours = 0; + if ((iPad + 1 < MaxPads) && (mapPad[iPad + 1] > mQThreshold)) { + if (mapPad[iPad + 1] > qMax) { continue; } + noNeighbours++; + } - // Acceptance condition: Require at least mMinNumberOfNeighbours neigbours - // with signal in any direction! - int noNeighbours = 0; - if ((iPad + 1 < MaxPads) && (mMapOfAllDigits[iTime][iRow][iPad + 1] > mQThreshold)) { - noNeighbours++; - } - if ((iPad - 1 >= 0) && (mMapOfAllDigits[iTime][iRow][iPad - 1] > mQThreshold)) { - noNeighbours++; - } - if ((iTime + 1 < MaxTimes) && (mMapOfAllDigits[iTime + 1][iRow][iPad] > mQThreshold)) { - noNeighbours++; + if ((iPad - 1 >= 0) && (mapPad[iPad - 1] > mQThreshold)) { + if (mapPad[iPad - 1] > qMax) { + continue; } - if ((iTime - 1 >= 0) && (mMapOfAllDigits[iTime - 1][iRow][iPad] > mQThreshold)) { - noNeighbours++; + noNeighbours++; + } + + if ((iRow + 1 < MaxRows) && (mSetOfTimeSlices[iTime][iRow + 1][iPad] > mQThreshold)) { + if (mSetOfTimeSlices[iTime][iRow + 1][iPad] > qMax) { + continue; } - if ((iRow + 1 < MaxRows) && (mMapOfAllDigits[iTime][iRow + 1][iPad] > mQThreshold)) { - noNeighbours++; + noNeighbours++; + } + + if ((iRow - 1 >= 0) && (mSetOfTimeSlices[iTime][iRow - 1][iPad] > mQThreshold)) { + if (mSetOfTimeSlices[iTime][iRow - 1][iPad] > qMax) { + continue; } - if ((iRow - 1 >= 0) && (mMapOfAllDigits[iTime][iRow - 1][iPad] > mQThreshold)) { - noNeighbours++; + noNeighbours++; + } + + if ((iTime + 1 < mMaxTimes) && (mSetOfTimeSlices[iTime + 1][iRow][iPad] > mQThreshold)) { + if (mSetOfTimeSlices[iTime + 1][iRow][iPad] > qMax) { + continue; } - if (noNeighbours < mMinNumberOfNeighbours) { + noNeighbours++; + } + + if ((iTime - 1 >= 0) && (mSetOfTimeSlices[iTime - 1][iRow][iPad] > mQThreshold)) { + if (mSetOfTimeSlices[iTime - 1][iRow][iPad] > qMax) { continue; } + noNeighbours++; + } + if (noNeighbours < mMinNumberOfNeighbours) { + continue; + } + + // Check that this is a local maximum + // Note that the checking is done so that if 2 charges have the same + // qMax then only 1 cluster is generated + // (that is why there is BOTH > and >=) + // -> only the maximum with the smalest indices will be accepted + bool thisIsMax = true; - // Check that this is a local maximum - // Note that the checking is done so that if 2 charges have the same - // qMax then only 1 cluster is generated - // (that is why there is BOTH > and >=) - // -> only the maximum with the smalest indices will be accepted - bool thisIsMax = true; - - for (int i = -mMaxClusterSizePad; (i <= mMaxClusterSizePad) && thisIsMax; - i++) { - for (int k = -mMaxClusterSizeRow; (k <= mMaxClusterSizeRow) && thisIsMax; - k++) { - for (int j = -mMaxClusterSizeTime; - (j <= mMaxClusterSizeTime) && thisIsMax; j++) { - if ((iPad + i < MaxPads) && (iTime + j < MaxTimes) && - (iRow + k < MaxRows) && (iPad + i >= 0) && (iTime + j) >= 0 && - (iRow + k) >= 0 && - mMapOfAllDigits[iTime + j][iRow + k][iPad + i] > qMax) { - thisIsMax = false; - } + for (int j = -mMaxClusterSizeTime; (j <= mMaxClusterSizeTime) && thisIsMax; j++) { + if ((iTime + j >= mMaxTimes) || (iTime + j < 0)) { + continue; + } + for (int k = -mMaxClusterSizeRow; (k <= mMaxClusterSizeRow) && thisIsMax; k++) { + if ((iRow + k >= MaxRows) || (iRow + k < 0)) { + continue; + } + for (int i = -mMaxClusterSizePad; (i <= mMaxClusterSizePad) && thisIsMax; i++) { + if ((iPad + i >= MaxPads) || (iPad + i < 0)) { + continue; + } + if (mSetOfTimeSlices[iTime + j][iRow + k][iPad + i] > qMax) { + thisIsMax = false; } } } + } - if (!thisIsMax) { - continue; + if (!thisIsMax) { + continue; + } else { + if (directFilling) { + + buildCluster(iPad, iRow, iTime, directFilling, timeOffset); } else { localMaximaCoords.emplace_back(std::make_tuple(iPad, iRow, iTime)); } + + // If we have found a local maximum, we can also skip the next few entries: + iPad += mMaxClusterSizePad; } } } + return localMaximaCoords; } @@ -186,50 +377,88 @@ std::vector<std::tuple<int, int, int>> KrBoxClusterFinder::findLocalMaxima() // for loop over whole cluster, to determine if a charge should be added // conditions are extrapolation of the 5x5 cluster case to arbitrary // cluster sizes in 3 dimensions -KrCluster KrBoxClusterFinder::buildCluster(int clusterCenterPad, int clusterCenterRow, int clusterCenterTime) +KrCluster KrBoxClusterFinder::buildCluster(int clusterCenterPad, int clusterCenterRow, int clusterCenterTime, bool directFilling, const int timeOffset) { - mTempCluster = KrCluster(); + mTempCluster.reset(); + setMaxClusterSize(clusterCenterRow); + // Loop over all neighbouring time bins: for (int iTime = -mMaxClusterSizeTime; iTime <= mMaxClusterSizeTime; iTime++) { + // Loop over all neighbouring row bins: + for (int iRow = -mMaxClusterSizeRow; iRow <= mMaxClusterSizeRow; iRow++) { + // First: Check if we look over array boundaries: + if (clusterCenterRow + iRow < 0) { + continue; + } else if (clusterCenterRow + iRow >= MaxRows) { + break; + } + // Second: Check if we might look over ROC boundaries: + else if (clusterCenterRow < MaxRowsIROC) { + if (clusterCenterRow + iRow > MaxRowsIROC) { + break; + } + } else if (clusterCenterRow < MaxRowsIROC + MaxRowsOROC1) { + if (clusterCenterRow + iRow < MaxRowsIROC || clusterCenterRow + iRow >= MaxRowsIROC + MaxRowsOROC1) { + continue; + } + } else if (clusterCenterRow < MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2) { + if (clusterCenterRow + iRow < MaxRowsIROC + MaxRowsOROC1 || clusterCenterRow + iRow >= MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2) { + continue; + } + } else if (clusterCenterRow < MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2 + MaxRowsOROC3) { + if (clusterCenterRow + iRow < MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2) { + continue; + } + } + + // Loop over all neighbouring pad bins: for (int iPad = -mMaxClusterSizePad; iPad <= mMaxClusterSizePad; iPad++) { - // First: Check if we might check outside of map: - if (clusterCenterTime + iTime < 0 || clusterCenterTime + iTime >= MaxTimes || clusterCenterPad + iPad < 0 || clusterCenterPad + iPad >= MaxPads || clusterCenterRow + iRow < 0 || clusterCenterRow + iRow >= MaxRows || mMapOfAllDigits.at(clusterCenterTime + iTime).at(clusterCenterRow + iRow).at(clusterCenterPad + iPad) <= mQThreshold) { + // First: Check again if we might look outside of map: + if (clusterCenterPad + iPad < 0) { + continue; + } else if (clusterCenterPad + iPad >= MaxPads) { + break; + } + + // Second: Check if charge is above threshold + // Might be not necessary since we deal with pedestal subtracted data + if (mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad] <= mQThreshold) { continue; } // If not, there are several cases which were explained (for 2D) in the header of the code. // The first one is for the diagonal. So, the digit we are investigating here is on the diagonal: - else if (std::abs(iTime) == std::abs(iPad) && std::abs(iTime) == std::abs(iRow)) { + if (std::abs(iTime) == std::abs(iPad) && std::abs(iTime) == std::abs(iRow)) { // Now we check, if the next inner digit has a signal above threshold: - if (mMapOfAllDigits[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { + if (mSetOfTimeSlices[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { // If yes, the cluster gets updated with the digit on the diagonal. - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } // Basically, we go through every possible case in the next few if-else conditions: else if (std::abs(iTime) == std::abs(iPad)) { - if (mMapOfAllDigits[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } else if (std::abs(iTime) == std::abs(iRow)) { - if (mMapOfAllDigits[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } else if (std::abs(iPad) == std::abs(iRow)) { - if (mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } else if (std::abs(iTime) > std::abs(iPad) && std::abs(iTime) > std::abs(iRow)) { - if (mMapOfAllDigits[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow][clusterCenterPad + iPad] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime - signnum(iTime)][clusterCenterRow + iRow][clusterCenterPad + iPad] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } else if (std::abs(iTime) < std::abs(iPad) && std::abs(iPad) > std::abs(iRow)) { - if (mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad - signnum(iPad)] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } else if (std::abs(iTime) < std::abs(iRow) && std::abs(iPad) < std::abs(iRow)) { - if (mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad] > mQThreshold) { - updateTempCluster(mMapOfAllDigits[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); + if (mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow - signnum(iRow)][clusterCenterPad + iPad] > mQThreshold) { + updateTempCluster(mSetOfTimeSlices[clusterCenterTime + iTime][clusterCenterRow + iRow][clusterCenterPad + iPad], clusterCenterPad + iPad, clusterCenterRow + iRow, clusterCenterTime + iTime); } } } @@ -237,6 +466,59 @@ KrCluster KrBoxClusterFinder::buildCluster(int clusterCenterPad, int clusterCent } // At the end, out mTempCluster should contain all digits that were assigned to the cluster. // So before returning it, we update it one last time to calculate the correct means and sigmas. - updateTempClusterFinal(); + + updateTempClusterFinal(timeOffset); + + if (directFilling) { + if (!mApplyCuts || acceptCluster(mTempCluster)) { + mClusters.emplace_back(mTempCluster); + } + } + return mTempCluster; } + +// Check if we are in IROC, OROC1, OROC2 or OROC3 and adapt the box size (max cluster size) accordingly. +void KrBoxClusterFinder::setMaxClusterSize(int row) +{ + if (row < MaxRowsIROC) { + mMaxClusterSizePad = mMaxClusterSizePadIROC; + mMaxClusterSizeRow = mMaxClusterSizeRowIROC; + } else if (row < MaxRowsIROC + MaxRowsOROC1) { + mMaxClusterSizePad = mMaxClusterSizePadOROC1; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC1; + } else if (row < MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2) { + mMaxClusterSizePad = mMaxClusterSizePadOROC2; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC2; + } else if (row < MaxRowsIROC + MaxRowsOROC1 + MaxRowsOROC2 + MaxRowsOROC3) { + mMaxClusterSizePad = mMaxClusterSizePadOROC3; + mMaxClusterSizeRow = mMaxClusterSizeRowOROC3; + } +} + +bool KrBoxClusterFinder::acceptCluster(const KrCluster& cl) +{ + // Qtot cut + if (cl.totCharge > mCutMaxQtot) { + return false; + } + + // sigma cuts + if (cl.sigmaPad < mCutMinSigmaPad || cl.sigmaPad > mCutMaxSigmaPad || + cl.sigmaRow < mCutMinSigmaRow || cl.sigmaRow > mCutMaxSigmaRow || + cl.sigmaTime < mCutMinSigmaTime || cl.sigmaRow > mCutMaxSigmaTime) { + return false; + } + + // total charge vs size cut + if (cl.totCharge > mCutQtot0 + mCutQtotSizeSlope * cl.size) { + return false; + } + + // maximal size + if (cl.size > mCutMaxSize) { + return false; + } + + return true; +} diff --git a/Detectors/TPC/reconstruction/src/KrBoxClusterFinderParam.cxx b/Detectors/TPC/reconstruction/src/KrBoxClusterFinderParam.cxx new file mode 100644 index 0000000000000..54178e42cc961 --- /dev/null +++ b/Detectors/TPC/reconstruction/src/KrBoxClusterFinderParam.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrBoxClusterFinderParam.cxx +/// \brief Parameter class for the Kr box cluster finder +/// +/// \author Philip Hauer, hauer@hiskp.uni-bonn.de + +#include "TPCReconstruction/KrBoxClusterFinderParam.h" + +O2ParamImpl(o2::tpc::KrBoxClusterFinderParam); \ No newline at end of file diff --git a/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx new file mode 100644 index 0000000000000..4ba36ed5b100e --- /dev/null +++ b/Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx @@ -0,0 +1,129 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <array> + +#include "CommonConstants/LHCConstants.h" +#include "Framework/Logger.h" +#include "TPCBase/Mapper.h" +#include "DataFormatsTPC/ZeroSuppressionLinkBased.h" +#include "DataFormatsTPC/Constants.h" + +#include "TPCReconstruction/RawProcessingHelpers.h" + +using namespace o2::tpc; + +//______________________________________________________________________________ +bool raw_processing_helpers::processZSdata(const char* data, size_t size, rdh_utils::FEEIDType feeId, uint32_t orbit, uint32_t referenceOrbit, uint32_t syncOffsetReference, ADCCallback fillADC, bool useTimeBin) +{ + const auto& mapper = Mapper::instance(); + + const auto link = rdh_utils::getLink(feeId); + const auto cruID = rdh_utils::getCRU(feeId); + const auto endPoint = rdh_utils::getEndPoint(feeId); + const CRU cru(cruID); + const int fecLinkOffsetCRU = (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2; + const int fecInPartition = link + endPoint * fecLinkOffsetCRU; + + // temporarily store the sync offset until it is available in the ZS header + // WARNING: This only works until the TB counter wrapped afterwards the alignment might change + const int globalLinkID = int(link) + int(endPoint * 12); + const int tpcGlobalLinkID = cruID * 24 + globalLinkID; + static std::array<uint32_t, 360 * 24> syncOffsetLinks; + + const uint32_t maxBunches = (uint32_t)o2::constants::lhc::LHCMaxBunches; + int globalBCOffset = int(orbit - referenceOrbit) * o2::constants::lhc::LHCMaxBunches; + static int triggerBCOffset = 0; + + bool hasData{false}; + + zerosupp_link_based::ContainerZS* zsdata = (zerosupp_link_based::ContainerZS*)data; + const zerosupp_link_based::ContainerZS* const zsdataEnd = (zerosupp_link_based::ContainerZS*)(data + size); + + while (zsdata < zsdataEnd) { + const auto& header = zsdata->cont.header; + + // align to header word if needed + if (!header.hasCorrectMagicWord()) { + zsdata = (zerosupp_link_based::ContainerZS*)((const char*)zsdata + sizeof(zerosupp_link_based::Header)); + if (!header.isFillWord()) { + LOGP(error, "Bad LinkZS magic word (0x{:08x}), for feeId 0x{:05x} (CRU: {:3}, link: {:2}, EP {}) , skipping data block", header.magicWord, feeId, rdh_utils::getCRU(feeId), rdh_utils::getLink(feeId), rdh_utils::getEndPoint(feeId)); + LOGP(error, "Full 128b word is: 0x{:016x}{:016x}", header.word1, header.word0); + } + continue; + } + + // set trigger offset and skip trigger info + if (header.isTriggerInfo()) { + // for the moment only skip the trigger info + const auto triggerInfo = (zerosupp_link_based::TriggerContainer*)zsdata; + const auto triggerOrbit = triggerInfo->triggerInfo.getOrbit(); + const auto triggerBC = triggerInfo->triggerInfo.bunchCrossing; + triggerBCOffset = (int(triggerOrbit) - int(referenceOrbit)) * maxBunches + triggerBC; + LOGP(debug, "orbit: {}, triggerOrbit: {}, triggerBC: {}, triggerBCOffset: {}", orbit, triggerOrbit, triggerBC, triggerBCOffset); + zsdata = (zerosupp_link_based::ContainerZS*)((const char*)zsdata + sizeof(zerosupp_link_based::Header) * (1 + header.numWordsPayload)); + continue; + } + + const auto channelBits = zsdata->getChannelBits(); + const uint32_t expectedWords = std::ceil(channelBits.count() * 0.1f); + const uint32_t numberOfWords = zsdata->getDataWords(); + assert(expectedWords == numberOfWords); + + const uint32_t bunchCrossingHeader = zsdata->getBunchCrossing() + syncOffsetReference; + uint32_t syncOffset = header.syncOffsetBC; + + if (useTimeBin) { + const uint32_t timebinHeader = (header.syncOffsetCRUCycles << 8) | header.syncOffsetBC; + if (syncOffsetLinks[tpcGlobalLinkID] == 0) { + syncOffsetLinks[tpcGlobalLinkID] = (bunchCrossingHeader + maxBunches - (timebinHeader * 8) % maxBunches) % maxBunches % 16; + } + syncOffset = syncOffsetLinks[tpcGlobalLinkID]; + } + + const int bcOffset = (int(globalBCOffset) + int(bunchCrossingHeader) - int(syncOffset)) - triggerBCOffset; + const int timebin = bcOffset / constants::LHCBCPERTIMEBIN; + if (bcOffset < 0) { + LOGP(debug, "skipping time bin with negative BC offset (globalBCoffset (({} - {}) * {} = {}) + bunchCrossingHeader ({}) - syncOffset({}) - triggerBCOffset({})) = {}", orbit, referenceOrbit, o2::constants::lhc::LHCMaxBunches, globalBCOffset, bunchCrossingHeader, syncOffset, triggerBCOffset, bcOffset); + + // go to next time bin + zsdata = zsdata->next(); + continue; + } + + std::size_t processedChannels = 0; + for (std::size_t ichannel = 0; ichannel < channelBits.size(); ++ichannel) { + if (!channelBits[ichannel]) { + continue; + } + + // adc value + const auto adcValue = zsdata->getADCValueFloat(processedChannels); + + // mapping to row, pad sector + int sampaOnFEC{}, channelOnSAMPA{}; + Mapper::getSampaAndChannelOnFEC(cruID, ichannel, sampaOnFEC, channelOnSAMPA); + const auto padSecPos = mapper.padSecPos(cru, fecInPartition, sampaOnFEC, channelOnSAMPA); + const auto& padPos = padSecPos.getPadPos(); + + // add digit using callback + fillADC(int(cruID), int(padPos.getRow()), int(padPos.getPad()), timebin, adcValue); + + ++processedChannels; + hasData = true; + } + + // go to next time bin + zsdata = zsdata->next(); + } + + return hasData; +} diff --git a/Detectors/TPC/reconstruction/src/RawReader.cxx b/Detectors/TPC/reconstruction/src/RawReader.cxx index 5e0aeb6994314..f1943226bfb0d 100644 --- a/Detectors/TPC/reconstruction/src/RawReader.cxx +++ b/Detectors/TPC/reconstruction/src/RawReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx index 91db830c8b619..f512c0283b0d4 100644 --- a/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx +++ b/Detectors/TPC/reconstruction/src/RawReaderCRU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,23 +14,25 @@ /// \author Torsten Alt (Torsten.Alt@cern.ch) #include <fmt/format.h> - +#include <filesystem> #include "TSystem.h" #include "TObjArray.h" +#include "Headers/DataHeader.h" #include "TPCReconstruction/RawReaderCRU.h" #include "TPCBase/Mapper.h" #include "Framework/Logger.h" #include "DetectorsRaw/RDHUtils.h" #define CHECK_BIT(var, pos) ((var) & (1 << (pos))) -using RDH = o2::header::RAWDataHeader; -//using namespace o2::tpc; + using namespace o2::tpc::rawreader; -using RDHUtils = o2::raw::RDHUtils; std::ostream& operator<<(std::ostream& output, const RDH& rdh); -std::istream& operator>>(std::istream& input, RDH& rdh); + +template <typename DataType> +std::istream& operator>>(std::istream& input, DataType& data); + void printHeader(); void printHorizontal(const RDH& rdh); @@ -43,10 +46,8 @@ RawReaderCRUEventSync::LinkInfo& RawReaderCRUEventSync::getLinkInfo(uint32_t hea } */ -RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const RDH& rdh, DataType dataType) +RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const uint32_t heartbeatOrbit, DataType dataType) { - const auto heartbeatOrbit = RDHUtils::getHeartBeatOrbit(rdh); - // TODO: might be that reversing the loop below has the same effect as using mLastEvent if (mLastEvent && mLastEvent->hasHearbeatOrbit(heartbeatOrbit)) { return *mLastEvent; @@ -54,11 +55,13 @@ RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const RDH& for (auto& ev : mEventInformation) { const auto hbMatch = ev.hasHearbeatOrbit(heartbeatOrbit); + const long hbDiff = long(heartbeatOrbit) - long(ev.HeartbeatOrbits.front()); if (hbMatch) { mLastEvent = &ev; return ev; - } else if (ev.HeartbeatOrbits.back() == heartbeatOrbit - 1) { + } else if ((hbDiff >= 0) && (hbDiff < 256)) { ev.HeartbeatOrbits.emplace_back(heartbeatOrbit); + std::sort(ev.HeartbeatOrbits.begin(), ev.HeartbeatOrbits.end()); mLastEvent = &ev; return ev; } @@ -68,7 +71,7 @@ RawReaderCRUEventSync::EventInfo& RawReaderCRUEventSync::createEvent(const RDH& return ev; } -void RawReaderCRUEventSync::analyse() +void RawReaderCRUEventSync::analyse(RAWDataType rawDataType) { //expected number of packets in one HBorbit const size_t numberOfPackets = ExpectedNumberOfPacketsPerHBFrame; @@ -81,6 +84,7 @@ void RawReaderCRUEventSync::analyse() const auto& cruInfo = event.CRUInfoArray[iCRU]; if (!cruInfo.isPresent()) { if (mCRUSeen[iCRU] >= 0) { + LOGP(info, "CRU {} missing in event {}", iCRU, iEvent); event.IsComplete = false; break; } @@ -90,7 +94,8 @@ void RawReaderCRUEventSync::analyse() totalPayloadSize += cruInfo.totalPayloadSize(); } - if (!cruInfo.isComplete()) { + if (!cruInfo.isComplete(rawDataType)) { + LOGP(info, "CRU info is incomplete"); event.IsComplete = false; break; } @@ -149,6 +154,7 @@ void RawReaderCRUEventSync::streamTo(std::ostream& output) const std::cout << orbit << " "; } std::cout << "\n" + << " firstOrbit: " << event.getFirstOrbit() << "\n" << " Is complete: " << isComplete << "\n"; // cru loop @@ -208,19 +214,16 @@ int RawReaderCRU::scanFile() //const uint64_t RDH_HEADERWORD0 = 0x00004003; const uint64_t RDH_HEADERWORD0 = 0x00004000; // + RDHUtils::getVersion<o2::header::RAWDataHeader>(); - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); + LOGP(info, "scanning file {}", mInputFileName); // get length of file in bytes file.seekg(0, file.end); mFileSize = file.tellg(); file.seekg(0, file.beg); + const bool isTFfile = (mInputFileName.rfind(".tf") == mInputFileName.size() - 3); + // the file is supposed to contain N x 8kB packets. So the number of packets // can be determined by the file-size. Ideally, this is not required but the // information is derived directly from the header size and payload size. @@ -229,17 +232,55 @@ int RawReaderCRU::scanFile() // read in the RDH, then jump to the next RDH position RDH rdh; + o2::header::DataHeader dh; uint32_t currentPacket = 0; uint32_t lastHeartbeatOrbit = 0; - while ((currentPacket < numPackets) && !file.eof()) { - const size_t currentPos = file.tellg(); + if (isTFfile) { + // skip the StfBuilder meta data information + file >> dh; + file.seekg(dh.payloadSize, std::ios::cur); + file >> dh; + file.seekg(dh.payloadSize, std::ios::cur); + } + + size_t currentPos = file.tellg(); + size_t dhPayloadSize{}; + size_t dhPayloadSizeSeen{}; + + while ((currentPos < mFileSize) && !file.eof()) { + // ===| in case of TF data file read data header |=== + if (isTFfile && (!dhPayloadSize || (dhPayloadSizeSeen == dhPayloadSize))) { + file >> dh; + dhPayloadSize = dh.payloadSize; + dhPayloadSizeSeen = 0; + currentPos = file.tellg(); + } // ===| read in the RawDataHeader at the current position |================= file >> rdh; const size_t packetSize = RDHUtils::getOffsetToNext(rdh); const size_t offset = packetSize - RDHUtils::getHeaderSize(rdh); + const auto memorySize = RDHUtils::getMemorySize(rdh); + const auto payloadSize = memorySize - RDHUtils::getHeaderSize(rdh); + dhPayloadSizeSeen += packetSize; + + // ===| check for truncated file |========================================== + const size_t curPos = file.tellg(); + if ((curPos + offset) > mFileSize) { + LOGP(error, "File truncated at {}, offset {} would exceed file size of {}", curPos, offset, mFileSize); + break; + } + + // ===| skip IDC data |===================================================== + const auto detField = o2::raw::RDHUtils::getDetectorField(rdh); + if (((detField != 0xdeadbeef) && (detField > 1)) || (payloadSize == 0)) { + file.seekg(offset, file.cur); + ++currentPacket; + currentPos = file.tellg(); + continue; + } // ===| try to detect data type if not already set |======================== // @@ -255,12 +296,13 @@ int RawReaderCRU::scanFile() const uint64_t pageCnt = RDHUtils::getPageCounter(rdh); const uint64_t linkID = RDHUtils::getLinkID(rdh); - if (pageCnt == 0) { - if (linkID == 15) { - mManager->mRawDataType = RAWDataType::LinkZS; - mManager->mDetectDataType = false; - } + //if (pageCnt == 0) { + if ((linkID == 15) || (detField == 0x1)) { + mManager->mRawDataType = RAWDataType::LinkZS; + LOGP(info, "Detected LinkZS data"); + mManager->mDetectDataType = false; } + //} if (pageCnt == 1) { if (triggerType == triggerTypeForTriggeredData) { @@ -276,17 +318,26 @@ int RawReaderCRU::scanFile() } // ===| get relavant data information |===================================== + auto feeId = RDHUtils::getFEEID(rdh); + // treat old RDH where feeId was not set properly + if (feeId == 4844) { + const rdh_utils::FEEIDType cru = RDHUtils::getCRUID(rdh); + const rdh_utils::FEEIDType link = RDHUtils::getLinkID(rdh); + const rdh_utils::FEEIDType endPoint = RDHUtils::getEndPointID(rdh); + feeId = rdh_utils::getFEEID(cru, endPoint, link); + + RDHUtils::setFEEID(rdh, feeId); + } const auto heartbeatOrbit = RDHUtils::getHeartBeatOrbit(rdh); - const auto dataWrapperID = RDHUtils::getEndPointID(rdh); - const auto linkID = RDHUtils::getLinkID(rdh); - const auto globalLinkID = linkID + dataWrapperID * 12; - //const auto blockLength = rdh.blockLength; - const auto memorySize = RDHUtils::getMemorySize(rdh); - const auto payloadSize = memorySize - RDHUtils::getHeaderSize(rdh); + const auto heartbeatOrbitEvent = isTFfile ? dh.firstTForbit : RDHUtils::getHeartBeatOrbit(rdh); + const auto endPoint = rdh_utils::getEndPoint(feeId); + const auto linkID = rdh_utils::getLink(feeId); + const auto globalLinkID = linkID + endPoint * 12; // ===| check if cru should be forced |===================================== if (!mForceCRU) { - mCRU = RDHUtils::getCRUID(rdh); + mCRU = rdh_utils::getCRU(feeId); + //mCRU = RDHUtils::getCRUID(rdh); // work-around for MW2 data } else { //overwrite cru id in rdh for further processing RDHUtils::setCRUID(rdh, mCRU); @@ -296,14 +347,13 @@ int RawReaderCRU::scanFile() RawReaderCRUEventSync::LinkInfo* linkInfo = nullptr; if (mManager) { // in case of triggered mode, we use the first heartbeat orbit as event identifier - if ((lastHeartbeatOrbit == 0) || (heartbeatOrbit != lastHeartbeatOrbit)) { - mManager->mEventSync.createEvent(rdh, mManager->getDataType()); - lastHeartbeatOrbit = heartbeatOrbit; + if ((lastHeartbeatOrbit == 0) || (heartbeatOrbitEvent != lastHeartbeatOrbit)) { + mManager->mEventSync.createEvent(heartbeatOrbitEvent, mManager->getDataType()); + lastHeartbeatOrbit = heartbeatOrbitEvent; } linkInfo = &mManager->mEventSync.getLinkInfo(rdh, mManager->getDataType()); mManager->mEventSync.setCRUSeen(mCRU, mReaderNumber); } - //std::cout << "block length: " << blockLength << '\n'; // ===| set up packet descriptor map for GBT frames |======================= // @@ -313,8 +363,8 @@ int RawReaderCRU::scanFile() // if ((rdh.word0 & 0x0000FFF0) == RDH_HEADERWORD0) { // non 0 stop bit means data with payload - if (RDHUtils::getStop(rdh) == 0) { - mPacketDescriptorMaps[globalLinkID].emplace_back(currentPos, mCRU, linkID, dataWrapperID, memorySize, packetSize); + if (payloadSize) { + mPacketDescriptorMaps[globalLinkID].emplace_back(currentPos, mCRU, linkID, endPoint, memorySize, packetSize, heartbeatOrbit); mLinkPresent[globalLinkID] = true; mPacketsPerLink[globalLinkID]++; if (linkInfo) { @@ -322,33 +372,31 @@ int RawReaderCRU::scanFile() linkInfo->IsPresent = true; linkInfo->PayloadSize += payloadSize; } - } else if (RDHUtils::getStop(rdh) == 1) { + } + if (RDHUtils::getStop(rdh) == 1) { // stop bit 1 means we hit the HB end frame without payload. // This marks the end of an "event" in HB scaling mode. if (linkInfo) { linkInfo->HBEndSeen = true; } - } else { - O2ERROR("Unknown stop code: %lu", (unsigned long)RDHUtils::getStop(rdh)); } - //std::cout << dataWrapperID << "." << linkID << " (" << globalLinkID << ")\n"; } else { - O2ERROR("Found header word %x and required header word %x don't match", rdh.word0, RDH_HEADERWORD0); - }; + O2ERROR("Found header word %x and required header word %x don't match, at %zu, stopping file scan", rdh.word0, RDH_HEADERWORD0, currentPos); + break; + } // debug output - if (CHECK_BIT(mDebugLevel, DebugLevel::RDHDump)) { - //std::cout << "Packet " << std::setw(5) << currentPacket << " - Link " << int(linkID) << "\n"; - //std::cout << rdh; + if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::RDHDump)) { printHorizontal(rdh); if (RDHUtils::getStop(rdh)) { std::cout << "\n"; printHeader(); } - }; - // std::cout << "Position after read : " << std::dec << file.tellg() << std::endl; + } + file.seekg(offset, file.cur); ++currentPacket; + currentPos = file.tellg(); } // close the File @@ -397,13 +445,7 @@ int RawReaderCRU::scanFile() void RawReaderCRU::findSyncPositions() { - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // loop over the MaxNumberOfLinks potential links in the data // only if data from the link is present and selected @@ -443,7 +485,7 @@ void RawReaderCRU::findSyncPositions() // TODO: In future there might be more then one sync in the stream // this should be takein into account if (syncFoundForLink(link)) { - if (CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions)) { + if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions)) { std::cout << "Sync positions for link " << link << '\n'; const auto& syncs = mSyncPositions[link]; for (int i = 0; i < syncs.size(); ++i) { @@ -460,13 +502,7 @@ void RawReaderCRU::findSyncPositions() int RawReaderCRU::processPacket(GBTFrame& gFrame, uint32_t startPos, uint32_t size, ADCRawData& rawData) { // open the data file - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // jump to the start position of the packet file.seekg(startPos, file.beg); @@ -481,12 +517,12 @@ int RawReaderCRU::processPacket(GBTFrame& gFrame, uint32_t startPos, uint32_t si gFrame.getFrameHalfWords(); // debug output - if (CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { + if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { std::cout << gFrame; } gFrame.getAdcValues(rawData); - gFrame.updateSyncCheck(CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions)); + gFrame.updateSyncCheck(mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions)); if (!(rawData.getNumTimebins() % 16) && (rawData.getNumTimebins() >= mNumTimeBins * 16)) { return 1; } @@ -494,10 +530,12 @@ int RawReaderCRU::processPacket(GBTFrame& gFrame, uint32_t startPos, uint32_t si return 0; } -int RawReaderCRU::processMemory(const std::vector<o2::byte>& data, ADCRawData& rawData) +int RawReaderCRU::processMemory(const std::vector<std::byte>& data, ADCRawData& rawData) { GBTFrame gFrame; + const bool dumpSyncPositoins = CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions); + // 16 bytes is the size of a GBT frame for (int iFrame = 0; iFrame < data.size() / 16; ++iFrame) { gFrame.setFrameNumber(iFrame); @@ -508,22 +546,41 @@ int RawReaderCRU::processMemory(const std::vector<o2::byte>& data, ADCRawData& r // reinterpret_cast<const uint32_t*>(data.data() + iFrame * 16), so it could be accessed the // same way as the mData array. // however, this was ~5% slower in execution time. I suspect due to cache misses - gFrame.readFromMemory(gsl::span<const o2::byte>(data.data() + iFrame * 16, 16)); + gFrame.readFromMemory(gsl::span<const std::byte>(data.data() + iFrame * 16, 16)); // extract the half words from the 4 32-bit words gFrame.getFrameHalfWords(); // debug output - if (CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { + if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { std::cout << gFrame; } gFrame.getAdcValues(rawData); - gFrame.updateSyncCheck(CHECK_BIT(mDebugLevel, DebugLevel::SyncPositions)); + gFrame.updateSyncCheck(mVerbosity && dumpSyncPositoins); if (!(rawData.getNumTimebins() % 16) && (rawData.getNumTimebins() >= mNumTimeBins * 16)) { - return 1; + break; } }; + + if (mDumpTextFiles && dumpSyncPositoins) { + const auto fileName = mOutputFilePrefix + "/LinkPositions.txt"; + std::ofstream file(fileName, std::ofstream::app); + auto& syncPositions = gFrame.getSyncArray(); + + for (int s = 0; s < 5; ++s) { + auto& syncPos = syncPositions[s]; + if (syncPos.synched()) { + file << mEventNumber << "\t" + << mCRU.number() << "\t" + << mLink << "\t" + << s << "\t" + << syncPos.getPacketNumber() << "\t" + << syncPos.getFrameNumber() << "\t" + << syncPos.getHalfWordPosition() << "\n"; + } + } + } return 0; } @@ -646,13 +703,13 @@ int RawReaderCRU::processDataFile() std::string fileName; for (int s = 0; s < 5; s++) { if (mStream == 0x0 or ((mStream >> s) & 0x1) == 0x1) { - if (gFrame.mSyncFound(s) == false) { + if (gFrame.syncFound(s) == false) { std::cout << "No sync found" << std::endl; } // debug output rawData.setOutputStream(s); rawData.setNumTimebins(mNumTimeBins); - if (CHECK_BIT(mDebugLevel, DebugLevel::ADCValues)) { + if (mVerbosity && CHECK_BIT(mDebugLevel, DebugLevel::ADCValues)) { std::cout << rawData << std::endl; }; // write the data to file @@ -684,7 +741,8 @@ void RawReaderCRU::processDataMemory() //dataSize = 4000 * 16; //} - std::vector<o2::byte> data(dataSize); + std::vector<std::byte> data; + data.reserve(dataSize); collectGBTData(data); ADCRawData rawData; @@ -694,35 +752,26 @@ void RawReaderCRU::processDataMemory() if (mFillADCdataMap) { fillADCdataMap(rawData); } - if (mManager && mManager->mADCDataCallback) { + if (mManager->mADCDataCallback) { runADCDataCallback(rawData); } } -void RawReaderCRU::collectGBTData(std::vector<o2::byte>& data) +void RawReaderCRU::collectGBTData(std::vector<std::byte>& data) { - const int link = mLink; - - const auto& mapper = Mapper::instance(); - const auto& linkInfoArray = mManager->mEventSync.getLinkInfoArrayForEvent(mEventNumber, mCRU); - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ios::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); size_t presentDataPosition = 0; // loop over the packets for each link and process them //for (const auto& packet : mPacketDescriptorMaps[link]) { - for (auto packetNumber : linkInfoArray[link].PacketPositions) { - const auto& packet = mPacketDescriptorMaps[link][packetNumber]; + for (auto packetNumber : linkInfoArray[mLink].PacketPositions) { + const auto& packet = mPacketDescriptorMaps[mLink][packetNumber]; const auto payloadStart = packet.getPayloadOffset(); - const auto payloadSize = std::min(size_t(packet.getPayloadSize()), data.size() - presentDataPosition); + const auto payloadSize = size_t(packet.getPayloadSize()); + data.insert(data.end(), payloadSize, (std::byte)0); // jump to the start position of the packet file.seekg(payloadStart, std::ios::beg); @@ -730,19 +779,50 @@ void RawReaderCRU::collectGBTData(std::vector<o2::byte>& data) file.read(((char*)data.data()) + presentDataPosition, payloadSize); presentDataPosition += payloadSize; - }; + } +} + +void RawReaderCRU::processLinkZS() +{ + const auto& eventInfo = mManager->mEventSync.getEventInfo(mEventNumber); + const auto& linkInfoArray = eventInfo.CRUInfoArray[mCRU].LinkInformation; + const auto firstOrbitInEvent = eventInfo.getFirstOrbit(); + + auto& file = getFileHandle(); + + char buffer[8192]; + + // loop over the packets for each link and process them + for (const auto packetNumber : linkInfoArray[mLink].PacketPositions) { + const auto& packet = mPacketDescriptorMaps[mLink][packetNumber]; + const size_t payloadOffset = packet.getPayloadOffset(); + const size_t payloadSize = packet.getPayloadSize(); + if ((payloadOffset + payloadSize) > mFileSize) { + LOGP(error, "File truncated at {}, size {} would exceed file size of {}", payloadOffset, payloadSize, mFileSize); + break; + } + file.seekg(payloadOffset, file.beg); + file.read(buffer, payloadSize); + const uint32_t syncOffsetReference = 144; // <<< TODO: fix value as max offset over all links + o2::tpc::raw_processing_helpers::processZSdata(buffer, payloadSize, packet.getFEEID(), packet.getHeartBeatOrbit(), firstOrbitInEvent, syncOffsetReference, mManager->mLinkZSCallback, false); // last parameter should be true for MW2 data + } } void RawReaderCRU::processLinks(const uint32_t linkMask) { + if (!mManager) { + LOGP(error, "cannont run without manager"); + return; + } + try { // read the input data from file, create the packet descriptor map // and the mLinkPresent map. scanFile(); // check if selected event is valid - if (mManager && mEventNumber >= mManager->mEventSync.getNumberOfEvents()) { - O2ERROR("Selected event number %u is larger then the events in the file %lu", mEventNumber, mManager->mEventSync.getNumberOfEvents()); + if (mEventNumber >= mManager->mEventSync.getNumberOfEvents()) { + O2ERROR("Selected event number %u is larger than the events in file %lu", mEventNumber, mManager->mEventSync.getNumberOfEvents()); return; } @@ -751,24 +831,20 @@ void RawReaderCRU::processLinks(const uint32_t linkMask) // for decoding it will be decoded. for (int lnk = 0; lnk < MaxNumberOfLinks; lnk++) { // all links have been selected - if (linkMask == 0 && checkLinkPresent(lnk) == true) { + if (((linkMask == 0) || ((linkMask >> lnk) & 1)) && checkLinkPresent(lnk) == true) { // set the active link variable and process the data if (mDebugLevel) { fmt::print("Processing link {}\n", lnk); } setLink(lnk); - //processDataFile(); - processDataMemory(); - } else if (((linkMask >> lnk) & 0x1) == 0x1 && checkLinkPresent(lnk) == true) { - // set the active link variable and process the data - if (mDebugLevel) { - fmt::print("Processing link {}\n", lnk); + if (mManager->mRawDataType == RAWDataType::GBT) { + //processDataFile(); + processDataMemory(); + } else { + processLinkZS(); } - setLink(lnk); - //processDataFile(); - processDataMemory(); - }; - }; + } + } } catch (const RawReaderCRU::Error& e) { std::cout << e.what() << std::endl; @@ -787,14 +863,39 @@ void RawReaderCRU::processFile(const std::string_view inputFile, uint32_t timeBi // Instantiate the RawReaderCRU RawReaderCRUManager cruManager; cruManager.setDebugLevel(debugLevel); - RawReaderCRU& rawReaderCRU = cruManager.createReader(inputFile, timeBins, 0, stream, debugLevel, verbosity, outputFilePrefix); + //RawReaderCRU& rawReaderCRU = cruManager.createReader(inputFile, timeBins, 0, stream, debugLevel, verbosity, outputFilePrefix); + cruManager.setupReaders(inputFile, timeBins, debugLevel, verbosity, outputFilePrefix); + for (auto& reader : cruManager.getReaders()) { + reader->mDumpTextFiles = true; + reader->mFillADCdataMap = false; + } cruManager.init(); - rawReaderCRU.mDumpTextFiles = true; - rawReaderCRU.mFillADCdataMap = false; - for (int ievent = 0; ievent < rawReaderCRU.getNumberOfEvents(); ++ievent) { + + if (CHECK_BIT(debugLevel, DebugLevel::SyncPositions)) { + std::string outPrefix = outputFilePrefix.length() ? outputFilePrefix.data() : "./"; + const auto fileName = outPrefix + "/LinkPositions.txt"; + std::ofstream file(fileName, std::ofstream::out); + file << "EventNumber/I" + << ":" + << "CRU" + << ":" + << "Link" + << ":" + << "Stream" + << ":" + << "PacketNumber" + << ":" + << "FrameNumber" + << ":" + << "HalfWordPosition" + << "\n"; + file.close(); + } + + for (int ievent = 0; ievent < cruManager.getNumberOfEvents(); ++ievent) { fmt::print("=============| event {: 5d} |===============\n", ievent); - rawReaderCRU.setEventNumber(ievent); - rawReaderCRU.processLinks(linkMask); + + cruManager.processEvent(ievent); } } @@ -812,13 +913,7 @@ void RawReaderCRU::copyEvents(const std::vector<uint32_t>& eventNumbers, std::st std::ofstream outputFile(outputFileName, std::ios_base::binary | mode); // open the input file - std::ifstream& file = mFileHandle; - if (!file.is_open()) { - file.open(mInputFileName, std::ifstream::binary); - if (!file.good()) { - throw std::runtime_error("Unable to open or access file " + mInputFileName); - } - } + auto& file = getFileHandle(); // data buffer. Maximum size is 8k char buffer[8192]; @@ -842,6 +937,44 @@ void RawReaderCRU::copyEvents(const std::vector<uint32_t>& eventNumbers, std::st } } } + +void RawReaderCRU::writeGBTDataPerLink(std::string_view outputDirectory, int maxEvents) +{ + // open the input file + auto& file = getFileHandle(); + + // data buffer. Maximum size is 8k + char buffer[8192]; + + // loop over events + for (int eventNumber = 0; eventNumber < getNumberOfEvents(); ++eventNumber) { + if ((maxEvents > -1) && (eventNumber >= maxEvents)) { + break; + } + + const auto& linkInfoArray = mManager->mEventSync.getLinkInfoArrayForEvent(eventNumber, mCRU); + + for (int iLink = 0; iLink < MaxNumberOfLinks; ++iLink) { + const auto& linkInfo = linkInfoArray[iLink]; + if (!linkInfo.IsPresent) { + continue; + } + printf("Event %4d, Link %2d\n", eventNumber, iLink); + + const int ep = iLink >= 12; + const int link = iLink - (ep)*12; + auto outputFileName = fmt::format("{}/CRU_{:02}_EP_{}_Link_{:02}", outputDirectory.data(), mCRU, ep, link); + std::ofstream outputFile(outputFileName, std::ios_base::binary | std::ios_base::app); + + for (auto packetNumber : linkInfo.PacketPositions) { + const auto& packet = mPacketDescriptorMaps[iLink][packetNumber]; + file.seekg(packet.getPayloadOffset(), file.beg); + file.read(buffer, packet.getPayloadSize()); + outputFile.write(buffer, packet.getPayloadSize()); + } + } + } +} //============================================================================== //===| stream overloads for helper classes |==================================== // @@ -988,11 +1121,12 @@ void printHorizontal(const RDH& rdh) (uint64_t)RDHUtils::getStop(rdh)); } -std::istream& operator>>(std::istream& input, RDH& rdh) +template <typename DataType> +std::istream& operator>>(std::istream& input, DataType& data) { - const int headerSize = sizeof(rdh); - auto charPtr = reinterpret_cast<char*>(&rdh); - input.read(charPtr, headerSize); + const int dataTypeSize = sizeof(data); + auto charPtr = reinterpret_cast<char*>(&data); + input.read(charPtr, dataTypeSize); return input; } @@ -1008,7 +1142,7 @@ void RawReaderCRUManager::init() } mEventSync.sortEvents(); - mEventSync.analyse(); + mEventSync.analyse(mRawDataType); O2INFO("Event information:"); O2INFO(" Number of all events: %lu", getNumberOfEvents()); @@ -1038,6 +1172,7 @@ void RawReaderCRUManager::setupReaders(const std::string_view inputFileNames, reader.setReaderNumber(mRawReadersCRU.size() - 1); reader.setVerbosity(verbosity); reader.setDebugLevel(debugLevel); + reader.setOutputFilePrefix(outputFilePrefix); O2INFO("Adding file: %s\n", file->GetName()); } } @@ -1046,8 +1181,15 @@ void RawReaderCRUManager::copyEvents(const std::vector<uint32_t> eventNumbers, s { // make sure events have been built init(); - for (auto& rawReader : mRawReadersCRU) { - rawReader->copyEvents(eventNumbers, outputDirectory.data(), mode); + const auto& cruSeen = mEventSync.getCRUSeen(); + + for (size_t iCRU = 0; iCRU < cruSeen.size(); ++iCRU) { + const auto readerNumber = cruSeen[iCRU]; + if (readerNumber >= 0) { + auto& reader = mRawReadersCRU[readerNumber]; + reader->forceCRU(iCRU); + reader->copyEvents(eventNumbers, outputDirectory.data(), mode); + } } } @@ -1058,6 +1200,36 @@ void RawReaderCRUManager::copyEvents(const std::string_view inputFileNames, cons manager.copyEvents(eventNumbers, outputDirectory, mode); } +void RawReaderCRUManager::writeGBTDataPerLink(std::string_view outputDirectory, int maxEvents) +{ + init(); + const auto& cruSeen = mEventSync.getCRUSeen(); + + for (size_t iCRU = 0; iCRU < cruSeen.size(); ++iCRU) { + const auto readerNumber = cruSeen[iCRU]; + if (readerNumber >= 0) { + auto& reader = mRawReadersCRU[readerNumber]; + reader->forceCRU(iCRU); + reader->writeGBTDataPerLink(outputDirectory, maxEvents); + } + } +} + +void RawReaderCRUManager::writeGBTDataPerLink(const std::string_view inputFileNames, std::string_view outputDirectory, int maxEvents) +{ + if (!std::filesystem::exists(outputDirectory)) { + if (!std::filesystem::create_directories(outputDirectory)) { + LOG(FATAL) << "could not create output directory " << outputDirectory; + } else { + LOG(INFO) << "created output directory " << outputDirectory; + } + } + + RawReaderCRUManager manager; + manager.setupReaders(inputFileNames); + manager.writeGBTDataPerLink(outputDirectory, maxEvents); +} + void RawReaderCRUManager::processEvent(uint32_t eventNumber, EndReaderCallback endReader) { const auto& cruSeen = mEventSync.getCRUSeen(); diff --git a/Detectors/TPC/reconstruction/src/RawReaderEventSync.cxx b/Detectors/TPC/reconstruction/src/RawReaderEventSync.cxx index c8e383f75ba13..b5805e7206dab 100644 --- a/Detectors/TPC/reconstruction/src/RawReaderEventSync.cxx +++ b/Detectors/TPC/reconstruction/src/RawReaderEventSync.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/SyncPatternMonitor.cxx b/Detectors/TPC/reconstruction/src/SyncPatternMonitor.cxx index 3f03df5d14f2a..357e0bc909991 100644 --- a/Detectors/TPC/reconstruction/src/SyncPatternMonitor.cxx +++ b/Detectors/TPC/reconstruction/src/SyncPatternMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx b/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx index e8b5979231b8d..7a2bcf21d5536 100644 --- a/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx +++ b/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h b/Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h index 4417ee16e038f..51be83630a7d8 100644 --- a/Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h +++ b/Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,17 +26,16 @@ #pragma link C++ class o2::tpc::rawreader::RawReaderCRUManager + ; #pragma link C++ class o2::tpc::RawReaderEventSync + ; #pragma link C++ class o2::tpc::SyncPatternMonitor + ; -#pragma link C++ class o2::tpc::GPUCATracking + ; #pragma link C++ class o2::tpc::HardwareClusterDecoder + ; #pragma link C++ class o2::tpc::KrBoxClusterFinder + ; -#pragma link C++ class o2::tpc::KrCluster + ; -#pragma link C++ class std::vector<o2::tpc::KrCluster> + ; #pragma link C++ class o2::tpc::Clusterer + ; #pragma link C++ class o2::tpc::ClustererTask + ; #pragma link C++ class o2::tpc::HwClusterer + ; #pragma link C++ class o2::tpc::HwClustererParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::tpc::HwClustererParam > +; +#pragma link C++ class o2::tpc::KrBoxClusterFinderParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::tpc::KrBoxClusterFinderParam > +; #pragma link C++ class o2::tpc::TPCFastTransformHelperO2 + ; diff --git a/Detectors/TPC/reconstruction/src/TPCTrackingDigitsPreCheck.cxx b/Detectors/TPC/reconstruction/src/TPCTrackingDigitsPreCheck.cxx new file mode 100644 index 0000000000000..376298417de23 --- /dev/null +++ b/Detectors/TPC/reconstruction/src/TPCTrackingDigitsPreCheck.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCTrackingDigitsPreCheck.cxx +/// \author David Rohr + +#include "TPCReconstruction/TPCTrackingDigitsPreCheck.h" + +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DataFormatsTPC/Digit.h" +#include "DataFormatsTPC/ClusterNative.h" + +#include "GPUO2Interface.h" +#include "GPUO2InterfaceConfiguration.h" +#include "TPCBase/Sector.h" + +#include <atomic> +#include <optional> +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +using namespace o2::gpu; +using namespace o2::tpc; +using namespace o2; +using namespace o2::dataformats; + +TPCTrackingDigitsPreCheck::precheckModifiedData::precheckModifiedData() = default; +TPCTrackingDigitsPreCheck::precheckModifiedData::~precheckModifiedData() = default; +TPCTrackingDigitsPreCheck::precheckModifiedData::precheckModifiedData(std::unique_ptr<precheckModifiedDataInternal>&& v) : data(std::move(v)) {} + +struct TPCTrackingDigitsPreCheck::precheckModifiedDataInternal { + std::vector<o2::tpc::Digit> gpuDigits[Sector::MAXSECTOR]; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> gpuDigitsMC[Sector::MAXSECTOR]; + ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer gpuDigitsMCConst[Sector::MAXSECTOR]; + GPUTrackingInOutDigits tpcDigitsMap; + GPUTPCDigitsMCInput tpcDigitsMapMC; +}; + +TPCTrackingDigitsPreCheck::precheckModifiedData TPCTrackingDigitsPreCheck::runPrecheck(o2::gpu::GPUTrackingInOutPointers* ptrs, o2::gpu::GPUO2InterfaceConfiguration* config) +{ + if (ptrs->tpcPackedDigits) { + std::unique_ptr<precheckModifiedDataInternal> retVal = std::make_unique<precheckModifiedDataInternal>(); + retVal->tpcDigitsMap = *ptrs->tpcPackedDigits; + const float zsThreshold = config->configReconstruction.tpc.zsThreshold; + const int maxContTimeBin = config->configGRP.continuousMaxTimeBin; + bool updateDigits = zsThreshold > 0 && ptrs->tpcZS == nullptr; + const auto& d = ptrs->tpcPackedDigits; + for (int i = 0; i < Sector::MAXSECTOR; i++) { + if (updateDigits) { + retVal->gpuDigits[i].reserve(d->nTPCDigits[i]); + } + for (int j = 0; j < d->nTPCDigits[i]; j++) { + if (maxContTimeBin && d->tpcDigits[i][j].getTimeStamp() >= maxContTimeBin) { + throw std::runtime_error("Digit time bin exceeds time frame length"); + } + if (updateDigits) { + if (d->tpcDigits[i][j].getChargeFloat() >= zsThreshold) { + if (d->tpcDigitsMC) { + for (const auto& element : d->tpcDigitsMC->v[i]->getLabels(j)) { + retVal->gpuDigitsMC[i].addElement(retVal->gpuDigits[i].size(), element); + } + } + retVal->gpuDigits[i].emplace_back(d->tpcDigits[i][j]); + } + } + } + if (updateDigits) { + retVal->tpcDigitsMap.tpcDigits[i] = retVal->gpuDigits[i].data(); + retVal->tpcDigitsMap.nTPCDigits[i] = retVal->gpuDigits[i].size(); + if (ptrs->tpcPackedDigits->tpcDigitsMC) { + retVal->gpuDigitsMC[i].flatten_to(retVal->gpuDigitsMCConst[i].first); + retVal->gpuDigitsMCConst[i].second = retVal->gpuDigitsMCConst[i].first; + retVal->tpcDigitsMapMC.v[i] = &retVal->gpuDigitsMCConst[i].second; + } + } + } + if (updateDigits) { + if (ptrs->tpcPackedDigits->tpcDigitsMC) { + retVal->tpcDigitsMap.tpcDigitsMC = &retVal->tpcDigitsMapMC; + } + ptrs->tpcPackedDigits = &retVal->tpcDigitsMap; + } + return precheckModifiedData(std::move(retVal)); + } + return precheckModifiedData(); +} diff --git a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx index 46a6c19a0bcf0..43e64896ff436 100644 --- a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx +++ b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,13 +22,13 @@ #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/ClusterNativeHelper.h" -#include "TPCReconstruction/GPUCATracking.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "TPCFastTransform.h" #include "TPCdEdxCalibrationSplines.h" +#include "GPUO2Interface.h" #include "GPUO2InterfaceConfiguration.h" -#include "TPCCFCalibration.h" +#include "TPCPadGainCalib.h" using namespace o2::gpu; @@ -45,7 +46,7 @@ namespace tpc /// @brief Test 1 basic class IO tests BOOST_AUTO_TEST_CASE(CATracking_test1) { - GPUCATracking tracker; + GPUO2Interface tracker; float solenoidBz = -5.00668; //B-field float refX = 1000.; //transport tracks to this x after tracking, >500 for disabling @@ -60,13 +61,13 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) config.configProcessing.eventDisplay = nullptr; //Ptr to event display backend, for running standalone OpenGL event display //config.configProcessing.eventDisplay = new GPUDisplayBackendGlfw; - config.configEvent.solenoidBz = solenoidBz; - config.configEvent.continuousMaxTimeBin = continuous ? GPUSettings::TPC_MAX_TF_TIME_BIN : 0; //Number of timebins in timeframe if continuous, 0 otherwise + config.configGRP.solenoidBz = solenoidBz; + config.configGRP.continuousMaxTimeBin = continuous ? GPUSettings::TPC_MAX_TF_TIME_BIN : 0; //Number of timebins in timeframe if continuous, 0 otherwise - config.configReconstruction.NWays = 3; //Should always be 3! - config.configReconstruction.NWaysOuter = true; //Will create outer param for TRD - config.configReconstruction.SearchWindowDZDR = 2.5f; //Should always be 2.5 for looper-finding and/or continuous tracking - config.configReconstruction.TrackReferenceX = refX; + config.configReconstruction.tpc.nWays = 3; //Should always be 3! + config.configReconstruction.tpc.nWaysOuter = true; //Will create outer param for TRD + config.configReconstruction.tpc.searchWindowDZDR = 2.5f; //Should always be 2.5 for looper-finding and/or continuous tracking + config.configReconstruction.tpc.trackReferenceX = refX; config.configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, GPUDataTypes::RecoStep::TPCSliceTracking, GPUDataTypes::RecoStep::TPCMerging, GPUDataTypes::RecoStep::TPCCompression, GPUDataTypes::RecoStep::TPCdEdx); @@ -75,12 +76,12 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) std::unique_ptr<TPCFastTransform> fastTransform(TPCFastTransformHelperO2::instance()->create(0)); config.configCalib.fastTransform = fastTransform.get(); - std::unique_ptr<o2::gpu::TPCdEdxCalibrationSplines> dEdxSplines(new TPCdEdxCalibrationSplines); + std::unique_ptr<o2::gpu::TPCdEdxCalibrationSplines> dEdxSplines = GPUO2Interface::getdEdxCalibrationSplinesDefault(); config.configCalib.dEdxSplines = dEdxSplines.get(); - std::unique_ptr<TPCCFCalibration> tpcCalibration(new TPCCFCalibration{}); - config.configCalib.tpcCalibration = tpcCalibration.get(); + std::unique_ptr<TPCPadGainCalib> gainCalib = GPUO2Interface::getPadGainCalibDefault(); + config.configCalib.tpcPadGain = gainCalib.get(); - tracker.initialize(config); + tracker.Initialize(config); std::vector<ClusterNativeContainer> cont(constants::MAXGLOBALPADROW); for (int i = 0; i < constants::MAXGLOBALPADROW; i++) { @@ -97,16 +98,12 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) std::unique_ptr<ClusterNative[]> clusterBuffer; std::unique_ptr<ClusterNativeAccess> clusters = ClusterNativeHelper::createClusterNativeIndex(clusterBuffer, cont, nullptr, nullptr); - GPUO2InterfaceIOPtrs ptrs; - std::vector<TrackTPC> tracks; - ptrs.clusters = clusters.get(); - ptrs.outputTracks = &tracks; - std::vector<TPCClRefElem> trackClusRefs; - ptrs.outputClusRefs = &trackClusRefs; + GPUTrackingInOutPointers ptrs; + ptrs.clustersNative = clusters.get(); - int retVal = tracker.runTracking(&ptrs); + int retVal = tracker.RunTracking(&ptrs); BOOST_CHECK_EQUAL(retVal, 0); - BOOST_CHECK_EQUAL((int)tracks.size(), 1); + BOOST_CHECK_EQUAL((int)ptrs.nMergedTracks, 1); } } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/reconstruction/test/testTPCAdcClockMonitor.cxx b/Detectors/TPC/reconstruction/test/testTPCAdcClockMonitor.cxx index b2730918e8b48..e21baee28f2a7 100644 --- a/Detectors/TPC/reconstruction/test/testTPCAdcClockMonitor.cxx +++ b/Detectors/TPC/reconstruction/test/testTPCAdcClockMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx b/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx index ae088c52054b5..89d81a42cf543 100644 --- a/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx +++ b/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/test/testTPCHwClusterer.cxx b/Detectors/TPC/reconstruction/test/testTPCHwClusterer.cxx index d6edfe6507f42..407bc203ab08c 100644 --- a/Detectors/TPC/reconstruction/test/testTPCHwClusterer.cxx +++ b/Detectors/TPC/reconstruction/test/testTPCHwClusterer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/reconstruction/test/testTPCSyncPatternMonitor.cxx b/Detectors/TPC/reconstruction/test/testTPCSyncPatternMonitor.cxx index 68ce8581f0f11..b1651d4f5f6e1 100644 --- a/Detectors/TPC/reconstruction/test/testTPCSyncPatternMonitor.cxx +++ b/Detectors/TPC/reconstruction/test/testTPCSyncPatternMonitor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/CMakeLists.txt b/Detectors/TPC/simulation/CMakeLists.txt index 1420c3ce08cce..65831ba4b7036 100644 --- a/Detectors/TPC/simulation/CMakeLists.txt +++ b/Detectors/TPC/simulation/CMakeLists.txt @@ -1,50 +1,42 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TPCSimulation SOURCES src/CommonMode.cxx src/Detector.cxx - src/DigitMCMetaData.cxx src/DigitContainer.cxx src/DigitGlobalPad.cxx src/Digitizer.cxx src/DigitTime.cxx src/ElectronTransport.cxx src/GEMAmplification.cxx - src/PadResponse.cxx src/Point.cxx src/SAMPAProcessing.cxx - src/SpaceCharge.cxx + src/IDCSim.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::SimulationDataFormat - O2::TPCBase O2::TPCSpaceChargeBase + O2::TPCBase O2::TPCSpaceCharge ROOT::Physics) o2_target_root_dictionary(TPCSimulation HEADERS include/TPCSimulation/CommonMode.h include/TPCSimulation/Detector.h - include/TPCSimulation/DigitMCMetaData.h include/TPCSimulation/DigitContainer.h include/TPCSimulation/DigitGlobalPad.h include/TPCSimulation/Digitizer.h include/TPCSimulation/DigitTime.h include/TPCSimulation/ElectronTransport.h include/TPCSimulation/GEMAmplification.h - include/TPCSimulation/PadResponse.h include/TPCSimulation/Point.h include/TPCSimulation/SAMPAProcessing.h - include/TPCSimulation/SpaceCharge.h) - -o2_add_executable(digits-to-rawzs - COMPONENT_NAME tpc - PUBLIC_LINK_LIBRARIES O2::TPCBase O2::SimulationDataFormat O2::GPUTracking O2::DetectorsRaw - SOURCES run/convertDigitsToRawZS.cxx) + include/TPCSimulation/IDCSim.h) o2_data_file(COPY files DESTINATION Detectors/TPC) o2_data_file(COPY data DESTINATION Detectors/TPC/simulation) @@ -57,13 +49,6 @@ if(BUILD_TESTING) O2::SimulationDataFormat LABELS tpc) - o2_add_test_root_macro(macro/createResidualDistortionObject.C - PUBLIC_LINK_LIBRARIES O2::TPCSpaceChargeBase - O2::CommonUtils - O2::CommonConstants - O2::TPCSimulation - LABELS tpc) - o2_add_test_root_macro(macro/laserTrackGenerator.C PUBLIC_LINK_LIBRARIES FairRoot::Base O2::DataFormatsTPC diff --git a/Detectors/TPC/simulation/README.md b/Detectors/TPC/simulation/README.md new file mode 100644 index 0000000000000..8ecdc706b9696 --- /dev/null +++ b/Detectors/TPC/simulation/README.md @@ -0,0 +1,42 @@ +<!-- doxy +\page refTPCsimulation TPC simulation +/doxy --> + +# TPC Digitization + +## Outline + +The TPC digitization handles the transformation from the simulated GEANT hits to the output of the front-end electronics. +The workflow and the validation of the corresponding output is described in detail in the [PhD thesis of Andi Mathis](http://cds.cern.ch/record/2728287). In the following, a concise overview is presented. +For the digitization as conducted by the [TPC digitizer](include/TPCSimulation/Digitizer.h) the following physics processes are considered: + +* The energy loss of each individual GEANT hit is converted into a number of electrons by dividing by the effective ionization potential W_i. Each of these electrons is in the following treated individually. +* The electron is projected onto the readout plane, taking into account diffusion, i.e. smearing its position by a 3D gaussian function ([ElectronTransport](include/TPCSimulation/ElectronTransport.h)). Then, the position is transformed into the local coordinate system of the Readout Chamber (ROC). +* Having arrived at the amplification stage, the electrons undergo amplification in the GEM stack ([GEMAmplification](include/TPCSimulation/GEMAmplification.h)), taking into account fluctuations of the gain. These fluctuations follow a Polya distribution. For performance considerations, two different versions of the amplification are available (one effective single-stage amplification and a successive simulation of the collection, amplification, and extraction processes in the individual GEMs. +* Capacitive coupling of the amplification structure to the readout anode leads to another contribution to the signal, the so-called Common Mode effect. Since the bottom electrode of GEM 4 is unsegmented, capacitive coupling occurs within a full ROC ([CommonMode](include/TPCSimulation/CommonMode.h)) +* The charge signal is then folded with the transfer function of the front-end cards ([SAMPAProcessing](include/TPCSimulation/SAMPAProcessing.h)) and written to the intermediate storage container structure ([DigitContainer](include/TPCSimulation/DigitContainer.h)/[DigitTime](include/TPCSimulation/DigitTime.h)/[DigitGlobalPad](include/TPCSimulation/DigitGlobalPad.h)), which is described below. + +## Workflow + +The digitization is conducted for each TPC sector individually in order to ensure maximal parallelization. The workflow is implemented in the DPL and the `o2-sim-digitizer-workflow`. + +### Input data +The input can be created by running the simulation `o2-sim`, which produces the file `o2sim.root` with the hits stored in separated branches for all sectors. +It should be noted that due to diffusion and the space-charge distortions, charge leakage between sectors can occur. In order to avoid the unnecessary processing of individual hits, several measures are taken + +* for a given sector the hits within an additional safety margin of +/- 10 degree are processed. For this reason, For this reason, the hits are not stored for a given sector, but shifted by 10 degrees. Hence only two branches need to be loaded for the digitization of a given sector. +* Individual hits are only processed when they are within the processed by 3 sigma of the expected width from diffusion + +Hits passing that requirement are further processed by the [TPC digitizer](include/TPCSimulation/Digitizer.h) and undergo the above described physics processes. + +### Intermediate container structure + +In particular in the case of large track densities, the hits from different tracks can contribute to an individual digit (pad, row, time bin). Therefore, an intermediate buffering of the digits is necessary. This is accomplished by an intermediate container structure. +The [DigitContainer](include/TPCSimulation/DigitContainer.h) is a circular buffer of time bins, in order to enable continuous readout of the detector as explained below. +The [DigitTime](include/TPCSimulation/DigitTime.h) is then a flat contained of [DigitGlobalPad](include/TPCSimulation/DigitGlobalPad.h), where the latter correspond to one pad on the pad plane. Accordingly, the buffering of the actual ADC values is conducted using this object. +Similarly, the MC labels are passed throughout the chain, and finally sorted by the number of occurrences, i.e. the track with the largest contribution to the digit is mentioned first etc. + +Correlations among digits from different events can only occur within the integration time of the detector (plus additional 50% contigiency), and therefore the digits are written to disk when the processed event is more than 750 time bins after. This means, that saturation effects are applied to the ADC values stored in the [DigitGlobalPad](include/TPCSimulation/DigitGlobalPad.h) and the relevant information is transformed in a [Digit](../../../DataFormats/Detectors/TPC/include/DataFormatsTPC/Digit.h) which is written to disk. + +### Output data +The digitizer workflow produces the file `tpcdigits.root` by default, data is stored in separated branches for all sectors. \ No newline at end of file diff --git a/Detectors/TPC/simulation/doc/SimulationNote.tex b/Detectors/TPC/simulation/doc/SimulationNote.tex deleted file mode 100644 index 674465ce16baa..0000000000000 --- a/Detectors/TPC/simulation/doc/SimulationNote.tex +++ /dev/null @@ -1,68 +0,0 @@ -\pdfoutput=1 -\RequirePackage{ifpdf} -\documentclass[12pt,DIV=14,parskip=half]{scrartcl} - -\usepackage{graphicx} -\usepackage{abstract} -\usepackage[pdftex]{hyperref} -\hypersetup{ - final, - a4paper=true, - pdfpagelayout=TwoPageRight, - colorlinks=true, - linkcolor=black, - citecolor=black, - filecolor=black, - bookmarks=true, - pdffitwindow=true, - pdfnewwindow=true, - pdfauthor={ALICE TPC collaboration}, - pdfcreator={pdftex}, - pdfproducer={ALICE TPC collaboration}, - pdftitle={Alice TPC Note}, - pdfsubject={Alice TPC Note}, - pdfkeywords={CERN, LHC, ALICE, TPC} } - -\pdfcompresslevel 1 - -\title{High-level description of the Digitization of the ALICE TPC with GEM-based readout} -\author{Andreas Mathis} % (andreas.mathis@ph.tum.de) - -\begin{document} -\maketitle - -The work flow of the digitization for the ALICE TPC with GEM-based readout is summarized in Fig. \ref{fig:workflow}. - -\begin{figure} -\centering -\includegraphics[width=0.6\textwidth]{figures/workflow} -\caption{Summary of work flow and the corresponding physical processes relevant for the digitization in the TPC.} -\label{fig:workflow} -\end{figure} - -The digitization starts in DigitizerTask::Exec, where the digit container from previous events is cleared and Digitizer::Process(TClonesArray *GEANT hits) is called. - -\begin{enumerate} -\item The energy loss of each individual GEANT hit is converted into a number of electrons by dividing by the effective ionization potential $W_i$ . Each of these electrons is in the following treated individually. - -\item The electron is projected onto the readout plane, taking into account diffusion, i.e. smearing its position by a 3D gaussian function (ElectronDrift). Then, the position is transformed into the local coordinate system of the Readout Chamber (ROC). - -\item Having arrived at the amplification stage, the electrons undergo successive amplification in each of the four GEM foils (SingleGEMAmplfication), taking into account fluctuations of the gain. These fluctuations follow a Polya distribution. - -\item Then, the amplified electrons drift towards the segmented readout anode. The spread of the electron cloud during the amplification stage, as well as the $1/r$ dependency of the Coulomb potential leads to an induction of the signal not only on the pad directly underneath the electron cloud, but also on adjacent pads. The function getPadResponse will return a vector with the coordinates of pads which in this way obtain a signal with respect to the central pad and the weight of the corresponding signal. As this effect is currently not considered, the function just returns $(0, 0, 1)$, which indicated that the central pad receives all the charge. -This charge signal is then folded with the transfer function of the front-end cards (Gamma4) and then successively sorted into the DigitContainer. -\end{enumerate} - -The DigitContainer contains a std::vector with pointers to CRU objects, which in turn contain a std::vector with pointers to Pad Row objects etc. The highest level are the ADC objects, which just contain a single float, as sketched in Fig. \ref{fig:container}. -This makes it very easy to deal with signals stemming from e.g. different tracks, which induce a signal on the same pad in the same time bin. In this situation, the time bin containers would contain two pointers with ADC objects corresponding each to the signal of one track. -When the event is fully processed, DigitContainer::fillOutputContainer( TClonesArray *Digits) is called in DigitizerTask::Exec. Successively, all containers are investigated and, at the highest level, the ADC counts in the ADC objects in one single time bin are summed up. The corresponding ADC value is computed in Digitizer::ADCvalue, taking into account the dynamic range and saturation of the front end cards. -A pointer to a Digit object is created, which features all the relevant information (CRU, ADC value, pad row, pad, time bin), and is written in the TClonesArray. With this approach, the Digits are sorted according to the CRU, pad row, etc. as required by the cluster finder. - -\begin{figure} -\centering -\includegraphics[width=0.6\textwidth]{figures/container} -\caption{Overview of the container in which the digits are stored during digitization.} -\label{fig:container} -\end{figure} - -\end{document} \ No newline at end of file diff --git a/Detectors/TPC/simulation/doc/figures/container.pdf b/Detectors/TPC/simulation/doc/figures/container.pdf deleted file mode 100644 index f93386c6aedc6..0000000000000 Binary files a/Detectors/TPC/simulation/doc/figures/container.pdf and /dev/null differ diff --git a/Detectors/TPC/simulation/doc/figures/workflow.png b/Detectors/TPC/simulation/doc/figures/workflow.png deleted file mode 100644 index e1f2880221834..0000000000000 Binary files a/Detectors/TPC/simulation/doc/figures/workflow.png and /dev/null differ diff --git a/Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h b/Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h index 5b57401b0de96..30527741af06f 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file DigitMCMetaData.h -/// \brief Definition of the Meta Data object of the Monte Carlo Digit +/// \file CommonMode.h +/// \brief Definition of the common mode container class /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de #ifndef ALICEO2_TPC_CommonMode_H_ diff --git a/Detectors/TPC/simulation/include/TPCSimulation/Detector.h b/Detectors/TPC/simulation/include/TPCSimulation/Detector.h index ca94e58779bde..85d43328d087a 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/Detector.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/include/TPCSimulation/DigitContainer.h b/Detectors/TPC/simulation/include/TPCSimulation/DigitContainer.h index 218f2598785a4..4695e3763859e 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/DigitContainer.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/DigitContainer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,13 +31,12 @@ namespace tpc { class Digit; -class DigitMCMetaData; /// \class DigitContainer /// This is the base class of the intermediate Digit Containers, in which all incoming electrons from the hits are /// sorted into after amplification /// The structure assures proper sorting of the Digits when later on written out for further processing. -/// This class holds the CRU containers. +/// This class holds the time bin containers. class DigitContainer { diff --git a/Detectors/TPC/simulation/include/TPCSimulation/DigitGlobalPad.h b/Detectors/TPC/simulation/include/TPCSimulation/DigitGlobalPad.h index 1c046279de6c0..e1c5759386813 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/DigitGlobalPad.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/DigitGlobalPad.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,11 +25,8 @@ #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/LabelContainer.h" #include "DataFormatsTPC/Defs.h" -#include "TPCBase/CRU.h" #include "DataFormatsTPC/Digit.h" #include "TPCBase/Mapper.h" -#include "TPCBase/ParameterElectronics.h" -#include "TPCSimulation/DigitMCMetaData.h" #include "TPCSimulation/SAMPAProcessing.h" namespace o2 @@ -39,8 +37,8 @@ namespace tpc /// \class DigitGlobalPad /// This is the lowest class of the intermediate Digit Containers, in which all incoming electrons from the /// hits are sorted into after amplification -/// The structure assures proper sorting of the Digits when later on written out for further processing. -/// This class holds the individual GlobalPad containers and is contained within the Row Container. +/// The structure assures proper sorting of the Digits and proper propagation of the MC labels when later on +/// written out for further processing. class DigitGlobalPad { diff --git a/Detectors/TPC/simulation/include/TPCSimulation/DigitMCMetaData.h b/Detectors/TPC/simulation/include/TPCSimulation/DigitMCMetaData.h deleted file mode 100644 index 5d468ed50ca07..0000000000000 --- a/Detectors/TPC/simulation/include/TPCSimulation/DigitMCMetaData.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file DigitMCMetaData.h -/// \brief Definition of the Meta Data object of the Monte Carlo Digit -/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de - -#ifndef ALICEO2_TPC_DigitMCMetaData_H_ -#define ALICEO2_TPC_DigitMCMetaData_H_ - -#include <Rtypes.h> - -namespace o2 -{ -namespace tpc -{ - -/// \class DigitMCMetaData -/// This is the definition of the Meta Data object of the Monte Carlo Digit -/// It holds auxilliary information relevant for debugging: -/// ADC value, Common Mode, Pedestal and Noise - -class DigitMCMetaData -{ - public: - /// Default constructor - DigitMCMetaData() = default; - - /// Constructor, initializing values for position, charge, time and common mode - /// \param ADC Raw ADC value of the corresponding DigitMC (before saturation) - /// \param commonMode Common mode signal on that ROC in the time bin of the DigitMC - /// \param pedestal Raw pedestal value of the corresponding DigitMC (before saturation) - /// \param noise Raw noise value of the corresponding DigitMC (before saturation) - DigitMCMetaData(float ADC, float commonMode, float pedestal, float noise); - - /// Destructor - ~DigitMCMetaData() = default; - - /// Get the raw ADC value - /// \return Raw ADC value of the corresponding DigitMC (before saturation) - float getRawADC() const { return mADC; } - - /// Get the common mode value - /// \return Common mode signal on that ROC in the time bin of the DigitMC - float getCommonMode() const { return mCommonMode; } - - /// Get the raw pedestal value - /// \return Raw pedestal value of the corresponding DigitMC (before saturation) - float getPedestal() const { return mPedestal; } - - /// Get the raw noise value - /// \return Raw noise value of the corresponding DigitMC (before saturation) - float getNoise() const { return mNoise; } - - private: - float mADC = 0.f; ///< Raw ADC value of the DigitMCMetaData - float mCommonMode = 0.f; ///< Common mode value of the DigitMCMetaData - float mPedestal = 0.f; ///< Pedestal value of the DigitMCMetaData - float mNoise = 0.f; ///< Noise value of the DigitMCMetaData - - ClassDefNV(DigitMCMetaData, 1); -}; - -inline DigitMCMetaData::DigitMCMetaData(float ADC, float commonMode, float pedestal, float noise) - : mADC(ADC), - mCommonMode(commonMode), - mPedestal(pedestal), - mNoise(noise) -{ -} - -} // namespace tpc -} // namespace o2 - -#endif // ALICEO2_TPC_DigitMCMetaData_H_ diff --git a/Detectors/TPC/simulation/include/TPCSimulation/DigitTime.h b/Detectors/TPC/simulation/include/TPCSimulation/DigitTime.h index 3d190c5907646..46edd8add8bee 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/DigitTime.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/DigitTime.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,6 @@ namespace tpc { class Digit; -class DigitMCMetaData; /// \class DigitTime /// This is the second class of the intermediate Digit Containers, in which all incoming electrons from the hits are diff --git a/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h b/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h index c0a565857eedd..aa86fa33804cf 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,8 @@ #define ALICEO2_TPC_Digitizer_H_ #include "TPCSimulation/DigitContainer.h" -#include "TPCSimulation/PadResponse.h" #include "TPCSimulation/Point.h" -#include "TPCSimulation/SpaceCharge.h" +#include "TPCSpaceCharge/SpaceCharge.h" #include "TPCBase/Mapper.h" @@ -43,7 +43,7 @@ class DigitContainer; /// -# Drift and diffusion of the primary electrons while moving in the active volume towards the readout chambers /// (ElectronTransport) /// -# Amplification of the electrons in the stack of four GEM foils (GEMAmplification) -/// -# Induction of the signal on the pad plane, including a spread of the signal due to the pad response (PadResponse) +/// -# Induction of the signal on the pad plane, including a spread of the signal due to the pad response (SignalInduction) /// -# Shaping and further signal processing in the Front-End Cards (SampaProcessing) /// The such created Digits and then sorted in an intermediate Container (DigitContainer) and after processing of the /// full event/drift time summed up @@ -52,6 +52,8 @@ class DigitContainer; class Digitizer { public: + using SC = SpaceCharge<double>; + /// Default constructor Digitizer() = default; @@ -90,18 +92,22 @@ class Digitizer /// Set the start time of the first event /// \param time Time of the first event - void setStartTime(TimeBin time) { mDigitContainer.setStartTime(time); } + void setStartTime(double time); + + /// Set mOutputDigitTimeOffset + void setOutputDigitTimeOffset(double offset) { mOutputDigitTimeOffset = offset; } /// Set the time of the event to be processed /// \param time Time of the event - void setEventTime(float time) { mEventTime = time; } + void setEventTime(double time) { mEventTime = time; } /// Switch for triggered / continuous readout /// \param isContinuous - false for triggered readout, true for continuous readout - static void setContinuousReadout(bool isContinuous) { mIsContinuous = isContinuous; } + void setContinuousReadout(bool isContinuous) { mIsContinuous = isContinuous; } /// Option to retrieve triggered / continuous readout - static bool isContinuousReadout() { return mIsContinuous; } + /// \return true for continuous readout + bool isContinuousReadout() { return mIsContinuous; } /// Enable the use of space-charge distortions and provide space-charge density histogram as input /// \param distortionType select the type of space-charge distortions (constant or realistic) @@ -109,20 +115,24 @@ class Digitizer /// \param nZSlices number of grid points in z, must be (2**N)+1 /// \param nPhiBins number of grid points in phi /// \param nRBins number of grid points in r, must be (2**N)+1 - void setUseSCDistortions(SpaceCharge::SCDistortionType distortionType, const TH3* hisInitialSCDensity, int nRBins, int nPhiBins, int nZSlices); + void setUseSCDistortions(SC::SCDistortionType distortionType, const TH3* hisInitialSCDensity); /// Enable the use of space-charge distortions and provide SpaceCharge object as input /// \param spaceCharge unique pointer to spaceCharge object - void setUseSCDistortions(SpaceCharge* spaceCharge); + void setUseSCDistortions(SC* spaceCharge); + + /// Enable the use of space-charge distortions by providing global distortions and global corrections stored in a ROOT file + /// The storage of the values should be done by the methods provided in the SpaceCharge class + /// \param TFile file containing distortions and corrections + void setUseSCDistortions(TFile& finp); private: - DigitContainer mDigitContainer; ///< Container for the Digits - std::unique_ptr<SpaceCharge> mSpaceCharge; ///< Handler of space-charge distortions - Sector mSector = -1; ///< ID of the currently processed sector - float mEventTime = 0.f; ///< Time of the currently processed event - // FIXME: whats the reason for hving this static? - static bool mIsContinuous; ///< Switch for continuous readout + DigitContainer mDigitContainer; ///< Container for the Digits + std::unique_ptr<SC> mSpaceCharge; ///< Handler of space-charge distortions + Sector mSector = -1; ///< ID of the currently processed sector + double mEventTime = 0.f; ///< Time of the currently processed event + double mOutputDigitTimeOffset = 0; ///< Time of the first IR sampled in the digitizer + bool mIsContinuous; ///< Switch for continuous readout bool mUseSCDistortions = false; ///< Flag to switch on the use of space-charge distortions - ClassDefNV(Digitizer, 1); }; } // namespace tpc diff --git a/Detectors/TPC/simulation/include/TPCSimulation/ElectronTransport.h b/Detectors/TPC/simulation/include/TPCSimulation/ElectronTransport.h index 19da546c95264..16931ca0d6261 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/ElectronTransport.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/ElectronTransport.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,7 +42,7 @@ class ElectronTransport } /// Destructor - ~ElectronTransport(); + ~ElectronTransport() = default; /// Update the OCDB parameters cached in the class. To be called once per event void updateParameters(); diff --git a/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h b/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h index d48af5705832f..f5c40569fee43 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ class GEMAmplification } /// Destructor - ~GEMAmplification(); + ~GEMAmplification() = default; /// Update the OCDB parameters cached in the class. To be called once per event void updateParameters(); diff --git a/Detectors/TPC/simulation/include/TPCSimulation/IDCSim.h b/Detectors/TPC/simulation/include/TPCSimulation/IDCSim.h new file mode 100644 index 0000000000000..7ad150fe69261 --- /dev/null +++ b/Detectors/TPC/simulation/include/TPCSimulation/IDCSim.h @@ -0,0 +1,178 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCSim.h +/// \brief class for integration of IDCs +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 16, 2021 + +#ifndef ALICEO2_TPC_IDCSIM_H_ +#define ALICEO2_TPC_IDCSIM_H_ + +#include <vector> +#include <array> +#include "DataFormatsTPC/Constants.h" +#include "CommonConstants/LHCConstants.h" +#include "TPCBase/Mapper.h" +#include <gsl/span> +#include "Rtypes.h" + +namespace o2::utils +{ +class TreeStreamRedirector; +} + +namespace o2::tpc +{ + +class Digit; + +/// \class IDCSim +/// This class is for the integration of IDCs for one sector. +/// The input has to be provided for one TF. +/// The IDCs are stored per CRU for all integration intervals. + +class IDCSim +{ + public: + /// constructor + /// \param sector sector for which the data is processed + /// \param nOrbits length of integration intervals + IDCSim(const unsigned int sector = 0, const unsigned int nOrbits = 12) : mSector{sector}, mNOrbits{nOrbits} {} + + // integrate IDCs for one TF + /// \param digits digits for one sector for one Time Frame + void integrateDigitsForOneTF(const gsl::span<const o2::tpc::Digit>& digits); + + /// set number of orbits per TF which is used to determine the size of the vectors etc. + /// \param nOrbitsPerTF number of orbits per TF + static void setNOrbitsPerTF(const unsigned int nOrbitsPerTF) { mOrbitsPerTF = nOrbitsPerTF; } + + /// for debugging: dumping IDCs to ROOT file + /// \param filename name of the output file + void dumpIDCs(const char* outFileName, const char* outName = "IDCSim") const; + + /// for debugging: creating debug tree for integrated IDCs + /// \param nameTree name of the output file + void createDebugTree(const char* nameTree) const; + + /// for debugging: creating debug tree for integrated IDCs for all objects which are in the same file + /// \param nameTree name of the output file + /// \param filename name of the input file containing the objects + static void createDebugTreeForAllSectors(const char* nameTree, const char* filename); + + /// \return returns the IDCs for all regions + const auto& get() const { return mIDCs[!mBufferIndex]; } + + /// \return returns the sector for which the IDCs are integrated + unsigned int getSector() const { return mSector; } + + /// \return returns the number of orbits for one TF + static unsigned int getNOrbitsPerTF() { return mOrbitsPerTF; } + + /// \return returns number of orbits used for each integration interval + unsigned int getNOrbitsPerIntegrationInterval() const { return mNOrbits; } + + /// \return returns number of time stamps per integration interval (should be 5346) + unsigned int getNTimeStampsPerIntegrationInterval() const { return mTimeStampsPerIntegrationInterval; } + + /// \return returns the check if an additional interval is used (if the last integration interval can also be empty) + bool additionalInterval() const { return mAddInterval; } + + /// \return returns maximum number of integration intervals used for one TF + unsigned int getNIntegrationIntervalsPerTF() const { return mIntegrationIntervalsPerTF; } + + /// \return number time stamps which remain in one TF and will be buffered to the next TF + unsigned int getNTimeStampsRemainder() const { return mTimeStampsRemainder; } + + /// \return offset from last time bin + int getTimeBinsOff() const { return mTimeBinsOff; } + + /// draw ungrouped IDCs + /// \param integrationInterval integration interval for which the IDCs will be drawn + /// \param filename name of the output file. If empty the canvas is drawn. + void drawIDCs(const unsigned int integrationInterval = 0, const std::string filename = "IDCs.pdf") const; + + /// \return returns maximum number of IDCs per region for all integration intervals + unsigned int getMaxIDCs(const unsigned int region) const { return mMaxIDCs[region]; } + + private: + inline static unsigned int mOrbitsPerTF{256}; ///< length of one TF in units of orbits + const unsigned int mSector{}; ///< sector for which the IDCs are integrated + const unsigned int mNOrbits{12}; ///< integration intervals of IDCs in units of orbits + const unsigned int mTimeStampsPerIntegrationInterval{(o2::constants::lhc::LHCMaxBunches * mNOrbits) / o2::tpc::constants::LHCBCPERTIMEBIN}; ///< number of time stamps for each integration interval (5346) + const bool mAddInterval{(mOrbitsPerTF % mNOrbits) > 0 ? true : false}; ///< if the division has a remainder 256/12=21.333 then add an additional integration interval + const unsigned int mIntegrationIntervalsPerTF{mOrbitsPerTF / mNOrbits + mAddInterval}; ///< number of integration intervals per TF. Add 1: 256/12=21.333 + const unsigned int mTimeStampsRemainder{mTimeStampsPerIntegrationInterval * (mOrbitsPerTF % mNOrbits) / mNOrbits}; ///< number time stamps which remain in one TF and will be buffered to the next TF + int mTimeBinsOff{}; ///< offset from last time bin + bool mBufferIndex{false}; ///< index for the buffer + const std::array<unsigned int, Mapper::NREGIONS> mMaxIDCs{ + Mapper::PADSPERREGION[0] * mIntegrationIntervalsPerTF, // region 0 + Mapper::PADSPERREGION[1] * mIntegrationIntervalsPerTF, // region 1 + Mapper::PADSPERREGION[2] * mIntegrationIntervalsPerTF, // region 2 + Mapper::PADSPERREGION[3] * mIntegrationIntervalsPerTF, // region 3 + Mapper::PADSPERREGION[4] * mIntegrationIntervalsPerTF, // region 4 + Mapper::PADSPERREGION[5] * mIntegrationIntervalsPerTF, // region 5 + Mapper::PADSPERREGION[6] * mIntegrationIntervalsPerTF, // region 6 + Mapper::PADSPERREGION[7] * mIntegrationIntervalsPerTF, // region 7 + Mapper::PADSPERREGION[8] * mIntegrationIntervalsPerTF, // region 8 + Mapper::PADSPERREGION[9] * mIntegrationIntervalsPerTF // region 9 + }; ///< maximum number of IDCs per region + std::array<std::vector<float>, Mapper::NREGIONS> mIDCs[2]{ + {std::vector<float>(mMaxIDCs[0]), // region 0 + std::vector<float>(mMaxIDCs[1]), // region 1 + std::vector<float>(mMaxIDCs[2]), // region 2 + std::vector<float>(mMaxIDCs[3]), // region 3 + std::vector<float>(mMaxIDCs[4]), // region 4 + std::vector<float>(mMaxIDCs[5]), // region 5 + std::vector<float>(mMaxIDCs[6]), // region 6 + std::vector<float>(mMaxIDCs[7]), // region 7 + std::vector<float>(mMaxIDCs[8]), // region 8 + std::vector<float>(mMaxIDCs[9])}, // region 9 + {std::vector<float>(mMaxIDCs[0]), // region 0 + std::vector<float>(mMaxIDCs[1]), // region 1 + std::vector<float>(mMaxIDCs[2]), // region 2 + std::vector<float>(mMaxIDCs[3]), // region 3 + std::vector<float>(mMaxIDCs[4]), // region 4 + std::vector<float>(mMaxIDCs[5]), // region 5 + std::vector<float>(mMaxIDCs[6]), // region 6 + std::vector<float>(mMaxIDCs[7]), // region 7 + std::vector<float>(mMaxIDCs[8]), // region 8 + std::vector<float>(mMaxIDCs[9])} // region 9 + }; ///< IDCs for one sector. The array is needed to buffer the IDCs for the last integration interval + + /// \return returns the last time bin after which the buffer is switched + unsigned int getLastTimeBinForSwitch() const; + + // set offset for the next time frame + void setNewOffset(); + + /// set all IDC values to 0 + void resetIDCs(); + + /// return orbit for given timeStamp + unsigned int getOrbit(const unsigned int timeStamp) const { return static_cast<unsigned int>((timeStamp + mTimeBinsOff) / mTimeStampsPerIntegrationInterval); } + + /// \return returns index in the vector of the mIDCs member + /// \param timeStamp timeStamp for which the index is calculated + /// \param region region in the sector + /// \param row global pad row + /// \param pad pad in row + unsigned int getIndex(const unsigned int timeStamp, const unsigned int region, const unsigned int row, const unsigned int pad) const { return getOrbit(timeStamp) * Mapper::PADSPERREGION[region] + Mapper::getLocalPadNumber(row, pad); } + + static void createDebugTree(const IDCSim& idcsim, o2::utils::TreeStreamRedirector& pcstream); + + ClassDefNV(IDCSim, 1) +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/simulation/include/TPCSimulation/PadResponse.h b/Detectors/TPC/simulation/include/TPCSimulation/PadResponse.h deleted file mode 100644 index 072030391aade..0000000000000 --- a/Detectors/TPC/simulation/include/TPCSimulation/PadResponse.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file PadResponse.h -/// \brief Definition of the Pad Response -/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de - -#ifndef ALICEO2_TPC_PadResponse_H_ -#define ALICEO2_TPC_PadResponse_H_ - -#include "TGraph2D.h" - -#include "TPCBase/Mapper.h" - -namespace o2 -{ -namespace tpc -{ - -/// \class PadResponse -/// This class deals with the induction of the signal on the pad plane. -/// The actual Pad Response Function (PRF) is simulated with Garfield++/COMSOL and dumped to a file. -/// This file is read by this class and dumped to a TGraph2D for each pad size individually (IROC / OROC1-2 / OROC3). -/// The pad response is then computed by evaluating this TGraph2D for a given pad size by evaluating the PRF at the electron position with respect to the pad centre. - -class PadResponse -{ - public: - /// Default constructor - PadResponse(); - - /// Destructor - virtual ~PadResponse() = default; - - /// Import the PRF from a .dat file to a TGraph2D - /// \param file Name of the .dat file - /// \param grPRF TGraph2D to which the PRF will be written - /// \return Boolean if succesful or not - bool importPRF(std::string file, std::unique_ptr<TGraph2D>& grPRF) const; - - /// Compute the impact of the pad response for electrons arriving at the GEM stack - /// \param posEle Position of the electron in real space - /// \param digiPadPos Position of the electron in pad space - /// \return Normalized pad response - float getPadResponse(GlobalPosition3D posEle, DigitPos digiPadPos) const; - - private: - std::unique_ptr<TGraph2D> mIROC; ///< TGraph2D holding the PRF for the IROC (4x7.5 mm2 pads) - std::unique_ptr<TGraph2D> mOROC12; ///< TGraph2D holding the PRF for the OROC1 and OROC2 (6x10 mm2 pads) - std::unique_ptr<TGraph2D> mOROC3; ///< TGraph2D holding the PRF for the OROC3 (6x15 mm2 pads) -}; -} // namespace tpc -} // namespace o2 - -#endif // ALICEO2_TPC_PadResponse_H_ diff --git a/Detectors/TPC/simulation/include/TPCSimulation/Point.h b/Detectors/TPC/simulation/include/TPCSimulation/Point.h index baad3a38fede9..dd477d1d20c33 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/Point.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/Point.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h b/Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h index 1c1bc2c85b0ee..ed1bba3eaaaee 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,7 +46,7 @@ class SAMPAProcessing return sampaProcessing; } /// Destructor - ~SAMPAProcessing(); + ~SAMPAProcessing() = default; /// Update the OCDB parameters cached in the class. To be called once per event void updateParameters(); @@ -209,33 +210,28 @@ inline T SAMPAProcessing::getGamma4(T time, T startTime, T ADC) const inline TimeBin SAMPAProcessing::getTimeBin(float zPos) const { - float timeBin = (mDetParam->TPClength - std::abs(zPos)) / (mGasParam->DriftV * mEleParam->ZbinWidth); - return static_cast<TimeBin>(timeBin); + return static_cast<TimeBin>((mDetParam->TPClength - std::abs(zPos)) / (mGasParam->DriftV * mEleParam->ZbinWidth)); } inline float SAMPAProcessing::getZfromTimeBin(float timeBin, Side s) const { - float zSign = (s == 0) ? 1 : -1; - float zAbs = zSign * (mDetParam->TPClength - (timeBin * mGasParam->DriftV * mEleParam->ZbinWidth)); - return zAbs; + const float zSign = (s == 0) ? 1 : -1; + return zSign * (mDetParam->TPClength - (timeBin * mGasParam->DriftV * mEleParam->ZbinWidth)); } inline TimeBin SAMPAProcessing::getTimeBinFromTime(float time) const { - float timeBin = time / mEleParam->ZbinWidth; - return static_cast<TimeBin>(timeBin); + return static_cast<TimeBin>(time / mEleParam->ZbinWidth); } inline float SAMPAProcessing::getTimeFromBin(TimeBin timeBin) const { - float time = static_cast<float>(timeBin) * mEleParam->ZbinWidth; - return time; + return static_cast<float>(timeBin) * mEleParam->ZbinWidth; } inline float SAMPAProcessing::getTimeBinTime(float time) const { - TimeBin timeBin = getTimeBinFromTime(time); - return getTimeFromBin(timeBin); + return getTimeFromBin(getTimeBinFromTime(time)); } inline float SAMPAProcessing::getNoise(const int sector, const int globalPadInSector) diff --git a/Detectors/TPC/simulation/include/TPCSimulation/SpaceCharge.h b/Detectors/TPC/simulation/include/TPCSimulation/SpaceCharge.h deleted file mode 100644 index 63dbcef7983db..0000000000000 --- a/Detectors/TPC/simulation/include/TPCSimulation/SpaceCharge.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SpaceCharge.h -/// \brief Definition of the handler for the ALICE TPC space-charge distortions calculations -/// \author Ernst Hellbär, Goethe-Universität Frankfurt, ernst.hellbar@cern.ch - -/* - * TODO: - * - modifiy TPCSpaceChargeBase classes - * - create light-weight 2D matrix class as matrix containers - * - std::vector<Matrix> instead of TMatrixD** - * - bring to O2 conventions - * - fix constants (more precise values, export into TPCBase/Constants) - * - granularity in r, rphi, z? - * - accumulate and add next slice - * - event based: propagate charge(ievent-1), add charge(ievent) - * - time based: mTime0, mEffectiveTime - * addIons(eventtime, drifttime, r, phi) - * time in us, 50 kHz = <one event / 20 us> - * if (ev.time+dr.time-mTime0 < mLengthTimebin) => add2NextSlice - * if (mLengthTimebin < ev.time+dr.time-mTime0 < mLengthTimebin+100us) add2NextToNextSlice - * - apply updated distortions to ions in NextToNextSlice when space charge is propagated; need to store exact positions (e.g. std::vector<std::vector<float>>)! - * - ion transport along the E field -> Continuity equation - * - Validate results by comparison to single ion transport - * - what about primary ionization? - * - irregular bin sizes in r and rphi - */ - -#ifndef ALICEO2_TPC_SPACECHARGE_H -#define ALICEO2_TPC_SPACECHARGE_H - -#include "AliTPCSpaceCharge3DCalc.h" -#include "DataFormatsTPC/Defs.h" -#include "MathUtils/RandomRing.h" - -class TH3; - -namespace o2 -{ -namespace tpc -{ - -class SpaceCharge -{ - public: - /// Enumerator for setting the space-charge distortion mode - enum class SCDistortionType : int { - SCDistortionsConstant = 0, // space-charge distortions constant over time - SCDistortionsRealistic = 1 // realistic evolution of space-charge distortions over time - }; - - // Constructors - /// Default constructor using a grid size of (129 z bins, 180 phi bins, 129 r bins) - SpaceCharge(); - /// Constructor with grid size specified by user - /// \param nRBins number of grid points in r, must be (2**N)+1 - /// \param nPhiBins number of grid points in phi - /// \param nZSlices number of grid points in z, must be (2**N)+1 - SpaceCharge(int nRBins, int nPhiBins, int nZSlices); - /// Constructor with grid size and interpolation order specified by user - /// \param nRBins number of grid points in r, must be (2**N)+1 - /// \param nPhiBins number of grid points in phi - /// \param nZSlices number of grid points in z, must be (2**N)+1 - /// \param interpolationOrder order used for interpolation of lookup tables - SpaceCharge(int nRBins, int nPhiBins, int nZSlices, int interpolationOrder); - - // Destructor - ~SpaceCharge() = default; - - /// Calculate lookup tables if initial space-charge density is provided - void init(); - - /// Calculate distortion and correction lookup tables using AliTPCSpaceChargeCalc class - /// \return real time for the calculation of the electron lookup tables - float calculateLookupTables(); - /// Update distortion and correction lookup tables by current space-charge density - /// \param eventTime time of current event - /// \return real time for the re-calculation of the electron lookup tables - float updateLookupTables(float eventTime); - - /// Set omega*tau and T1, T2 tensor terms in Langevin-equation solution - /// \param omegaTau omega*tau - /// \param t1 T1 tensor term - /// \param t2 T2 tensor term - void setOmegaTauT1T2(float omegaTau, float t1, float t2); - /// Set an initial space-charge density - /// \param hisSCDensity 3D space-charge density histogram, expected format (phi,r,z) and units C / cm^3 / epsilon0 - void setInitialSpaceChargeDensity(const TH3* hisSCDensity); - /// Add primary ions to space-charge density - /// \param r global radius - /// \param phi global phi position - /// \param z z position - /// \param nIons number of ions - void fillPrimaryIons(double r, double phi, double z, int nIons); - /// Add charge to space-charge density - /// \param r global radius - /// \param phi global phi position - /// \param z z position - /// \param charge charge in C/cm^3/epsilon0 - void fillPrimaryCharge(double r, double phi, double z, float charge); - /// Add ion backflow to space-charge density - /// \param r global radius - /// \param phi global phi position - /// \param side A or C side - /// \param nIons number of ions - void fillIBFIons(double r, double phi, Side side, int nIons); - /// Add ion backflow to space-charge density - /// \param r global radius - /// \param phi global phi position - /// \param side A or C side - /// \param charge charge in C/cm^3/epsilon0 - void fillIBFCharge(double r, double phi, Side side, float charge); - /// Get ion drift vector along electric field - /// \param r global radius - /// \param phi global phi position - /// \param z z position - /// \param dr return drift in radial direction - /// \param drphi return drift in azimuthal (rphi) direction - /// \param dz return drift in z direction - void getIonDrift(Side side, double r, double phi, double z, double& dr, double& drphi, double& dz) const; - /// Propagate space-charge density along electric field by one time slice - void propagateSpaceCharge(); - /// Convert space-charge density to distribution of ions, propagate them along the electric field and convert back to space-charge density - void propagateIons(); - - /// Correct electron position using correction lookup tables - /// \param point 3D coordinates of the electron - void correctElectron(GlobalPosition3D& point); - /// Distort electron position using distortion lookup tables - /// \param point 3D coordinates of the electron - void distortElectron(GlobalPosition3D& point) const; - - /// Interpolate the space-charge density from lookup tables in mLookUpTableCalculator - /// \param point Position at which to calculate the space-charge density - /// \return space-charge density at given point in C/cm^3/epsilon0 - double getChargeDensity(Side side, const GlobalPosition3D& point) const; - /// Get the space-charge density stored in the - /// \param iphi phi bin - /// \param ir r bin - /// \param iz z bin - /// \return space-charge density in given bin in C/cm^3/epsilon0 - float getChargeDensity(Side side, int ir, int iphi, int iz) const; - - /// Set the space-charge distortions model - /// \param distortionType distortion type (constant or realistic) - void setSCDistortionType(SCDistortionType distortionType) { mSCDistortionType = distortionType; } - /// Get the space-charge distortions model - SCDistortionType getSCDistortionType() const { return mSCDistortionType; } - - /// Return the ion drift time for one z bin - double getDriftTimeZSlice() const { return mDriftTimeVoxel; } - double getNPhi() const { return mNPhi; } - double getNR() const { return mNR; } - double getNZ() const { return mNZ; } - double getVoxelSizePhi() const { return mVoxelSizePhi; } - double getVoxelSizeR() const { return mVoxelSizeR; } - double getVoxelSizeZ() const { return mVoxelSizeZ; } - std::vector<double> getCoordinatesPhi() const { return mCoordPhi; } - std::vector<double> getCoordinatesR() const { return mCoordR; } - std::vector<double> getCoordinatesZ() const { return mCoordZ; } - - void setUseIrregularLUTs(int useIrrLUTs); - void setUseFastDistIntegration(int useFastInt); - - void setDistortionLookupTables(TMatrixD** matrixIntDistDrA, TMatrixD** matrixIntDistDrphiA, TMatrixD** matrixIntDistDzA, TMatrixD** matrixIntDistDrC, TMatrixD** matrixIntDistDrphiC, TMatrixD** matrixIntDistDzC); - - private: - /// Allocate memory for data members - void allocateMemory(); - void setVoxelCoordinates(); - - /// Convert amount of ions into charge density C/cm^3/epsilon0 - /// \param nIons number of ions - /// \return space-charge density (C/cm^3/epsilon0) - float ions2Charge(int rBin, int nIons); - - static constexpr float DvDEoverv0 = 0.0025; //!<! v'(E) / v0 = K / (K*E0) for ions, used in dz calculation - static const float sEzField; //!<! nominal drift field - - static constexpr int MaxNZ = 200; //!<! default number of z slices (1 ms slices) - static constexpr int MaxNPhi = 360; //!<! default number of phi bins - static constexpr float DriftLength = 250.; //!<! drift length of the TPC in (cm) - // ion mobility K = 3.0769231 cm^2/(Vs) in Ne-CO2 90-10 published by A. Deisting - // v_drift = K * E = 3.0769231 cm^2/(Vs) * 400 V/cm = 1230.7692 cm/s - // t_drift = 249.7 cm / v_drift = 203 ms - static constexpr float IonDriftTime = 2.02e5; //!<! drift time of ions for one full drift (us) - - const int mInterpolationOrder; ///< order for interpolation of lookup tables: 2==quadratic, >2==cubic spline - - const int mNZ; ///< number of z slices used in lookup tables - const int mNPhi; ///< number of phi bins used in lookup tables - const int mNR; ///< number of r bins used in lookup tables - const double mVoxelSizeZ; ///< length of one z bin (cm) - const double mDriftTimeVoxel; ///< ion drift time for one z slice (us) - const double mVoxelSizePhi; ///< width of one phi bin (radians) - const double mVoxelSizeR; ///< length of one r bin (cm) - - std::vector<double> mCoordZ; ///< vector with coodinates of the z bins - std::vector<double> mCoordPhi; ///< vector with coodinates of the phi bins - std::vector<double> mCoordR; ///< vector with coodinates of the r bins - - bool mUseInitialSCDensity; ///< Flag for the use of an initial space-charge density at the beginning of the simulation - bool mInitLookUpTables; ///< Flag to indicate if lookup tables have been calculated - float mTimeInit; ///< time of last update of lookup tables - SCDistortionType mSCDistortionType; ///< Type of space-charge distortions - - AliTPCSpaceCharge3DCalc mLookUpTableCalculator; ///< object to calculate and store correction and distortion lookup tables - - /// TODO: What are the coordinates of the bins? They are defined in AliTPCSpaceCharge3DCalc::GetChargeDensity and are different from mCoordZ, mCoordPhi, mCoordR used for local ion drift lookup table! Use consistent convention? Lookup table instead of vector? - std::vector<float> mSpaceChargeDensityA; ///< space-charge density on the A side, stored in C/cm^3/epsilon0, z ordering: z=[0,250], [iphi*mNR*mNZ + ir*mNZ + iz] - std::vector<float> mSpaceChargeDensityC; ///< space-charge density on the C side, stored in C/cm^3/epsilon0, z ordering: z=[0,-250], [iphi*mNR*mNZ + ir*mNZ + iz] - - /// Ion drift vectors after time deltaT = mLengthZSlice / v_driftIon - /// nominal E field only in z direction, distortions in r, phi, z due to space charge - /// d = (dr, drphi, mVoxelSizeZ + dz) - /// TODO: Eliminate the need for these matrices as members, they should be owned by AliTPCLookUpTable3DInterpolatorD. AliTPCLookUpTable3DInterpolatorD needs getters for the matrices and the constructor has to be modified. - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftZA; //!<! matrix to store ion drift in z direction along E field on A side in cm - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftZC; //!<! matrix to store ion drift in z direction along E field on A side in cm - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftRPhiA; //!<! matrix to store ion drift in rphi direction along E field on A side in cm - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftRPhiC; //!<! matrix to store ion drift in rphi direction along E field on A side in cm - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftRA; //!<! matrix to store ion drift in radial direction along E field on A side in cm - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixIonDriftRC; //!<! matrix to store ion drift in radial direction along E field on C side in cm - /// TODO: these lookup tables should be objects? - std::unique_ptr<AliTPCLookUpTable3DInterpolatorD> mLookUpIonDriftA; ///< lookup table for ion drift along E field on A side in cm - std::unique_ptr<AliTPCLookUpTable3DInterpolatorD> mLookUpIonDriftC; ///< lookup table for ion drift along E field on C side in cm - bool mMemoryAllocated; - - math_utils::RandomRing<> mRandomFlat; //!<! Circular random buffer containing flat random values to convert the charge density to a flat ion distribution inside the voxel - - ClassDefNV(SpaceCharge, 1); -}; - -} // namespace tpc -} // namespace o2 - -#endif // ALICEO2_TPC_SPACECHARGE_H diff --git a/Detectors/TPC/simulation/macro/createResidualDistortionObject.C b/Detectors/TPC/simulation/macro/createResidualDistortionObject.C deleted file mode 100644 index 1dcd960a64996..0000000000000 --- a/Detectors/TPC/simulation/macro/createResidualDistortionObject.C +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file createResidualDistortionObject.C -/// \brief This macro creates a SpaceCharge object with residual distortions from a fluctuating and an average space-charge density histogram and stores it in a file. -/// \author Ernst Hellbär, Goethe-Universität Frankfurt, ernst.hellbar@cern.ch - -#include <cmath> - -#include "TFile.h" -#include "TH3.h" -#include "TMatrixD.h" -#include "TString.h" - -#include "AliTPCSpaceCharge3DCalc.h" -#include "CommonConstants/MathConstants.h" -#include "CommonUtils/TreeStreamRedirector.h" -#include "TPCSimulation/SpaceCharge.h" -#include "MathUtils/Cartesian.h" - -using namespace o2::tpc; - -// function declarations -AliTPCSpaceCharge3DCalc* createSpaceCharge(TH3* hisSCDensity, int bSign, int nR, int nPhi, int nZ); -void fillDistortionLookupMatrices(AliTPCSpaceCharge3DCalc* spaceChargeCalc, AliTPCSpaceCharge3DCalc* spaceChargeCalcAvg, TMatrixD** matrixDistDrA, TMatrixD** matrixDistDrphiA, TMatrixD** matrixDistDzA, TMatrixD** matrixDistDrC, TMatrixD** matrixDistDrphiC, TMatrixD** matrixDistDzC); -void makeDebugTreeResiduals(AliTPCSpaceCharge3DCalc* calcFluc, AliTPCSpaceCharge3DCalc* calcAvg, SpaceCharge* spaceChargeRes); - -/// Create a SpaceCharge object with residual distortions from a fluctuating and an average space-charge density histogram and write it to a file. -/// \param bSign sign of the B-field: -1 = negative, 0 = no B-field, 1 = positive -/// \param nR number of bins in r -/// \param nPhi number of bins in phi -/// \param nZ number of bins in z -/// \param pathToHistoFile path to a file with the fluctuating and average histograms -/// \param histoFlucName name of the fluctuating histogram -/// \param histoAvgName name of the average histogram -void createResidualDistortionObject(int bSign, int nR = 129, int nPhi = 144, int nZ = 129, const char* pathToHistoFile = "InputSCDensityHistograms_8000events.root", const char* histoFlucName = "inputSCDensity3D_8000_0", const char* histoAvgName = "inputSCDensity3D_8000_avg", bool debug = false) -{ - /* - Usage: - root -l -b -q createResidualDistortionObject.C+\(-1,129,144,129,\"InputSCDensityHistograms_8000events.root\",\"inputSCDensity3D_8000_0\",\"inputSCDensity3D_8000_avg\",true\) - */ - TFile* fileHistos = TFile::Open(pathToHistoFile); - auto histoFluc = fileHistos->Get<TH3>(histoFlucName); - auto histoAvg = fileHistos->Get<TH3>(histoAvgName); - - TFile* fileOutput = TFile::Open("ResidualDistortions.root", "recreate"); - - // Calculate fluctuating and average distortion and correction lookup tables - AliTPCSpaceCharge3DCalc* scCalcFluc = createSpaceCharge(histoFluc, bSign, nR, nPhi, nZ); - AliTPCSpaceCharge3DCalc* scCalcAvg = createSpaceCharge(histoAvg, bSign, nR, nPhi, nZ); - - // Create matrices and fill them with residual distortions. Create SpaceCharge object, assign residual distortion matrices to it and store it in the output file. - TMatrixD** matrixResDistDrA = new TMatrixD*[nPhi]; - TMatrixD** matrixResDistDrphiA = new TMatrixD*[nPhi]; - TMatrixD** matrixResDistDzA = new TMatrixD*[nPhi]; - TMatrixD** matrixResDistDrC = new TMatrixD*[nPhi]; - TMatrixD** matrixResDistDrphiC = new TMatrixD*[nPhi]; - TMatrixD** matrixResDistDzC = new TMatrixD*[nPhi]; - for (int iphi = 0; iphi < nPhi; ++iphi) { - matrixResDistDrA[iphi] = new TMatrixD(nR, nZ); - matrixResDistDrphiA[iphi] = new TMatrixD(nR, nZ); - matrixResDistDzA[iphi] = new TMatrixD(nR, nZ); - matrixResDistDrC[iphi] = new TMatrixD(nR, nZ); - matrixResDistDrphiC[iphi] = new TMatrixD(nR, nZ); - matrixResDistDzC[iphi] = new TMatrixD(nR, nZ); - } - fillDistortionLookupMatrices(scCalcFluc, scCalcAvg, matrixResDistDrA, matrixResDistDrphiA, matrixResDistDzA, matrixResDistDrC, matrixResDistDrphiC, matrixResDistDzC); - SpaceCharge spaceChargeRes(nR, nPhi, nZ); - spaceChargeRes.setDistortionLookupTables(matrixResDistDrA, matrixResDistDrphiA, matrixResDistDzA, matrixResDistDrC, matrixResDistDrphiC, matrixResDistDzC); - fileOutput->WriteObject(&spaceChargeRes, "spaceChargeRes"); - - if (debug) { - makeDebugTreeResiduals(scCalcFluc, scCalcAvg, &spaceChargeRes); - } -} - -/// Create AliTPCSpaceCharge3DCalc object from a space-charge density histogram -/// \param hisSCDensity input space-charge density histogram -/// \param bSign sign of the B-field: -1 = negative, 0 = no B-field, 1 = positive -/// \param nR number of bins in r -/// \param nPhi number of bins in phi -/// \param nZ number of bins in z -/// \return pointer to AliTPCSpaceCharge3DCalc object -AliTPCSpaceCharge3DCalc* createSpaceCharge(TH3* hisSCDensity, int bSign, int nR, int nPhi, int nZ) -{ - AliTPCSpaceCharge3DCalc* spaceCharge = new AliTPCSpaceCharge3DCalc(nR, nZ, nPhi, 2, 3, 0); - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixChargeA = std::make_unique<std::unique_ptr<TMatrixD>[]>(nPhi); - std::unique_ptr<std::unique_ptr<TMatrixD>[]> mMatrixChargeC = std::make_unique<std::unique_ptr<TMatrixD>[]>(nPhi); - for (int iphi = 0; iphi < nPhi; ++iphi) { - mMatrixChargeA[iphi] = std::make_unique<TMatrixD>(nR, nZ); - mMatrixChargeC[iphi] = std::make_unique<TMatrixD>(nR, nZ); - } - spaceCharge->GetChargeDensity((TMatrixD**)mMatrixChargeA.get(), (TMatrixD**)mMatrixChargeC.get(), hisSCDensity, nR, nZ, nPhi); - spaceCharge->SetInputSpaceChargeA((TMatrixD**)mMatrixChargeA.get()); - spaceCharge->SetInputSpaceChargeC((TMatrixD**)mMatrixChargeC.get()); - float omegaTau = -0.32 * bSign; - spaceCharge->SetOmegaTauT1T2(omegaTau, 1.f, 1.f); - spaceCharge->SetCorrectionType(0); - spaceCharge->SetIntegrationStrategy(0); - spaceCharge->ForceInitSpaceCharge3DPoissonIntegralDz(nR, nZ, nPhi, 300, 1e-8); - return spaceCharge; -} - -/// Store distortions from spaceChargeCalcFluc in the matrices provided. If providing an object with average space-charge distortions spaceChargeCalcAvg, the residual distortions (dist_fluctuation(xyzTrue) + corr_average(xyzDistorted)) will be stored. -/// \param spaceChargeCalcFluc fluctuating distortions object -/// \param spaceChargeCalcAvg average distortions object -/// \param matrixDistDrA matrix to store radial distortions on the A side -/// \param matrixDistDrphiA matrix to store rphi distortions on the A side -/// \param matrixDistDzA matrix to store z distortions on the A side -/// \param matrixDistDrC matrix to store radial distortions on the C side -/// \param matrixDistDrphiC matrix to store rphi distortions on the C side -/// \param matrixDistDzC matrix to store z distortions on the C side -void fillDistortionLookupMatrices(AliTPCSpaceCharge3DCalc* spaceChargeCalcFluc, AliTPCSpaceCharge3DCalc* spaceChargeCalcAvg, TMatrixD** matrixDistDrA, TMatrixD** matrixDistDrphiA, TMatrixD** matrixDistDzA, TMatrixD** matrixDistDrC, TMatrixD** matrixDistDrphiC, TMatrixD** matrixDistDzC) -{ - const int nR = spaceChargeCalcFluc->GetNRRows(); - const int nPhi = spaceChargeCalcFluc->GetNPhiSlices(); - const int nZ = spaceChargeCalcFluc->GetNZColumns(); - const float mVoxelSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nR - 1); - const float mVoxelSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZ - 1); - const float mVoxelSizePhi = o2::constants::math::TwoPI / nPhi; - - for (int iphi = 0; iphi < nPhi; ++iphi) { - float phi = iphi * mVoxelSizePhi; - - for (int ir = 0; ir < nR; ++ir) { - float r = AliTPCPoissonSolver::fgkIFCRadius + ir * mVoxelSizeR; - - for (int iz = 0; iz < nZ; ++iz) { - float absz = iz * mVoxelSizeZ; - - float xCylA[3] = {r, phi, absz}; - float xCylC[3] = {r, phi, -1 * absz}; - int roc = 0; - float distFlucA[3] = {0.f, 0.f, 0.f}; - float distFlucC[3] = {0.f, 0.f, 0.f}; - - // get fluctuating distortions - spaceChargeCalcFluc->GetDistortionCylAC(xCylA, roc, distFlucA); - spaceChargeCalcFluc->GetDistortionCylAC(xCylC, roc + 18, distFlucC); - float distA[3] = {distFlucA[0], distFlucA[1], distFlucA[2]}; - float distC[3] = {distFlucC[0], distFlucC[1], distFlucC[2]}; - - // get average corrections if provided and add them to the fluctuating distortions - if (spaceChargeCalcAvg) { - float xDistCylA[3] = {xCylA[0] + distFlucA[0], xCylA[1] + distFlucA[1] / xCylA[0], xCylA[2] + distFlucA[2]}; - float xDistCylC[3] = {xCylC[0] + distFlucC[0], xCylC[1] + distFlucC[1] / xCylC[0], xCylC[2] + distFlucC[2]}; - float corrAvgA[3] = {0.f, 0.f, 0.f}; - float corrAvgC[3] = {0.f, 0.f, 0.f}; - spaceChargeCalcAvg->GetCorrectionCylAC(xDistCylA, roc, corrAvgA); - spaceChargeCalcAvg->GetCorrectionCylAC(xDistCylC, roc + 18, corrAvgC); - distA[0] += corrAvgA[0]; - distA[1] += (corrAvgA[1] * xCylA[0] / xDistCylA[0]); - distA[2] += corrAvgA[2]; - distC[0] += corrAvgC[0]; - distC[1] += (corrAvgC[1] * xCylC[0] / xDistCylC[0]); - distC[2] += corrAvgC[2]; - } - - // store (residual) distortions in the matrices - (*matrixDistDrA[iphi])(ir, iz) = distA[0]; - (*matrixDistDrphiA[iphi])(ir, iz) = distA[1]; - (*matrixDistDzA[iphi])(ir, iz) = distA[2]; - (*matrixDistDrC[iphi])(ir, iz) = distC[0]; - (*matrixDistDrphiC[iphi])(ir, iz) = distC[1]; - (*matrixDistDzC[iphi])(ir, iz) = -1 * distC[2]; - } - } - } -} - -/// Calculate and stream residual distortions from spaceChargeRes and from calcFluc and calcAvg for comparison. -/// \param calcFluc AliTPCSpaceCharge3DCalc object with fluctuation distortions -/// \param calcAvg AliTPCSpaceCharge3DCalc object with average distortions -/// \param spaceChargeRes SpaceCharge object with residual distortions -void makeDebugTreeResiduals(AliTPCSpaceCharge3DCalc* calcFluc, AliTPCSpaceCharge3DCalc* calcAvg, SpaceCharge* spaceChargeRes) -{ - const int nR = calcFluc->GetNRRows(); - const int nPhi = calcFluc->GetNPhiSlices(); - const int nZ = calcFluc->GetNZColumns(); - const float mVoxelSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nR - 1); - const float mVoxelSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZ - 1); - const float mVoxelSizePhi = o2::constants::math::TwoPI / nPhi; - - o2::utils::TreeStreamRedirector pcstream("debugResidualDistortions.root", "recreate"); - for (int iside = 0; iside < 2; ++iside) { - int roc = iside == 0 ? 0 : 18; - for (int iphi = 0; iphi < nPhi; ++iphi) { - float phi = iphi * mVoxelSizePhi; - for (int ir = 0; ir < nR; ++ir) { - float r = AliTPCPoissonSolver::fgkIFCRadius + ir * mVoxelSizeR; - float x = r * std::cos(phi); - float y = r * std::sin(phi); - for (int iz = 1; iz < nZ; ++iz) { - float z = iside == 0 ? iz * mVoxelSizeZ : -1 * iz * mVoxelSizeZ; - - GlobalPosition3D posDistRes(x, y, z); - spaceChargeRes->distortElectron(posDistRes); - float xyzDistRes[3] = {posDistRes.x(), posDistRes.y(), posDistRes.z()}; - float distRes[3] = {posDistRes.x() - x, posDistRes.y() - y, posDistRes.z() - z}; - - float xyz[3] = {x, y, z}; - float distFluc[3] = {0.f, 0.f, 0.f}; - calcFluc->GetDistortion(xyz, roc, distFluc); - float xyzDist[3] = {xyz[0] + distFluc[0], xyz[1] + distFluc[1], xyz[2] + distFluc[2]}; - float corrAvg[3] = {0.f, 0.f, 0.f}; - calcAvg->GetCorrection(xyzDist, roc, corrAvg); - float xyzDistResTrue[3] = {xyzDist[0] + corrAvg[0], xyzDist[1] + corrAvg[1], xyzDist[2] + corrAvg[2]}; - float distResTrue[3] = {distFluc[0] + corrAvg[0], distFluc[1] + corrAvg[1], distFluc[2] + corrAvg[2]}; - - pcstream << "debug" - << "iside=" << iside - << "iphi=" << iphi - << "ir=" << ir - << "iz=" << iz - // original position - << "phi=" << phi - << "r=" << r - << "x=" << x - << "y=" << y - << "z=" << z - // position of distorted points - << "xRes=" << xyzDistRes[0] - << "yRes=" << xyzDistRes[1] - << "zRes=" << xyzDistRes[2] - // true position of distorted points - << "xResTrue=" << xyzDistResTrue[0] - << "yResTrue=" << xyzDistResTrue[1] - << "zResTrue=" << xyzDistResTrue[2] - // residual distortions - << "distX=" << distRes[0] - << "distY=" << distRes[1] - << "distZ=" << distRes[2] - // true residual distortions - << "distXTrue=" << distResTrue[0] - << "distYTrue=" << distResTrue[1] - << "distZTrue=" << distResTrue[2] - // - << "\n"; - } - } - } - } - pcstream.Close(); -} \ No newline at end of file diff --git a/Detectors/TPC/simulation/macro/laserTrackGenerator.C b/Detectors/TPC/simulation/macro/laserTrackGenerator.C index 8d4cf36837fb3..cec46b51ad539 100644 --- a/Detectors/TPC/simulation/macro/laserTrackGenerator.C +++ b/Detectors/TPC/simulation/macro/laserTrackGenerator.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/macro/readMCtruth.C b/Detectors/TPC/simulation/macro/readMCtruth.C index 062bf2eb7676d..7571187c72fe3 100644 --- a/Detectors/TPC/simulation/macro/readMCtruth.C +++ b/Detectors/TPC/simulation/macro/readMCtruth.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,9 +19,11 @@ #include "TFile.h" #include "TTree.h" #include "DataFormatsTPC/Digit.h" -#include "SimulationDataFormat/MCTruthContainer.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" #include "SimulationDataFormat/MCCompLabel.h" #include <iostream> +#include "Framework/Logger.h" #endif void readMCtruth(std::string filename) @@ -28,25 +31,58 @@ void readMCtruth(std::string filename) TFile* digitFile = TFile::Open(filename.data()); TTree* digitTree = (TTree*)digitFile->Get("o2sim"); - std::vector<o2::tpc::Digit>* digits = nullptr; - digitTree->SetBranchAddress("TPCDigit", &digits); - - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mMCTruthArray; - o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mcTruthArray(&mMCTruthArray); - digitTree->SetBranchAddress("TPCDigitMCTruth", &mcTruthArray); + o2::dataformats::IOMCTruthContainerView* plabels[36] = {0}; + std::vector<o2::tpc::Digit>* digits[36] = {0}; + int nBranches = 0; + bool mcPresent = false, perSector = false; + if (digitTree->GetBranch("TPPCDigit")) { + LOG(INFO) << "Joint digit branch is found"; + nBranches = 1; + digitTree->SetBranchAddress("TPCDigit", &digits[0]); + if (digitTree->GetBranch("TPCDigitMCTruth")) { + mcPresent = true; + digitTree->SetBranchAddress("TPCDigitMCTruth", &plabels[0]); + } + } else { + nBranches = 36; + perSector = true; + for (int i = 0; i < 36; i++) { + std::string digBName = fmt::format("TPCDigit_{:d}", i).c_str(); + if (digitTree->GetBranch(digBName.c_str())) { + digitTree->SetBranchAddress(digBName.c_str(), &digits[i]); + std::string digMCBName = fmt::format("TPCDigitMCTruth_{:d}", i).c_str(); + if (digitTree->GetBranch(digMCBName.c_str())) { + mcPresent = true; + digitTree->SetBranchAddress(digMCBName.c_str(), &plabels[i]); + } + } + } + } + o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel> labels[36]; for (int iEvent = 0; iEvent < digitTree->GetEntriesFast(); ++iEvent) { - int digit = 0; digitTree->GetEntry(iEvent); - for (auto& inputdigit : *digits) { - gsl::span<const o2::MCCompLabel> mcArray = mMCTruthArray.getLabels(digit); - for (int j = 0; j < static_cast<int>(mcArray.size()); ++j) { - std::cout << "Digit " << digit << " from Event " - << mMCTruthArray.getElement(mMCTruthArray.getMCTruthHeader(digit).index + j).getEventID() - << " with Track ID " - << mMCTruthArray.getElement(mMCTruthArray.getMCTruthHeader(digit).index + j).getTrackID() << "\n"; + for (int ib = 0; ib < nBranches; ib++) { + if (plabels[ib]) { + plabels[ib]->copyandflatten(labels[ib]); + delete plabels[ib]; + plabels[ib] = nullptr; + } + } + + for (int ib = 0; ib < nBranches; ib++) { + if (!digits[ib]) { + continue; + } + int nd = digits[ib]->size(); + for (int idig = 0; idig < nd; idig++) { + const auto& digit = (*digits[ib])[idig]; + o2::MCCompLabel lab; + if (mcPresent) { + lab = labels[ib].getLabels(idig)[0]; + } + std::cout << "Digit " << digit << " from " << lab << "\n"; } - ++digit; } } } diff --git a/Detectors/TPC/simulation/run/convertDigitsToRawZS.cxx b/Detectors/TPC/simulation/run/convertDigitsToRawZS.cxx deleted file mode 100644 index fcc06bd746218..0000000000000 --- a/Detectors/TPC/simulation/run/convertDigitsToRawZS.cxx +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file convertDigitsToRawZS.cxx -/// \author Jens Wiechula (Jens.Wiechula@ikf.uni-frankfurt.de) - -#include <boost/program_options.hpp> - -#include <string_view> -#include <memory> -#include <vector> -#include <fmt/format.h> - -#include "TFile.h" -#include "TTree.h" -#include "TROOT.h" -#include "TSystem.h" - -#include "GPUO2Interface.h" -#include "GPUReconstructionConvert.h" -#include "GPUHostDataTypes.h" -#include "GPUParam.h" -#include "GPURawData.h" - -#include "Framework/Logger.h" -#include "DetectorsRaw/RawFileWriter.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "DataFormatsTPC/Digit.h" -#include "TPCBase/Sector.h" -#include "DataFormatsTPC/ZeroSuppression.h" -#include "DataFormatsTPC/Helpers.h" -#include "DetectorsRaw/HBFUtils.h" -#include "DetectorsRaw/RDHUtils.h" -#include "TPCBase/RDHUtils.h" -#include "DataFormatsTPC/Digit.h" -#include "CommonUtils/ConfigurableParam.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsCommonDataFormats/NameConf.h" - -namespace bpo = boost::program_options; - -using namespace o2::tpc; -using namespace o2::gpu; -using namespace o2::dataformats; -using o2::MCCompLabel; - -constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; -constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; -using DigitArray = std::array<gsl::span<const o2::tpc::Digit>, Sector::MAXSECTOR>; - -struct ProcessAttributes { - std::unique_ptr<unsigned long long int[]> zsoutput; - std::vector<unsigned int> sizes; - MCLabelContainer mctruthArray; - std::unique_ptr<o2::gpu::GPUReconstructionConvert> zsEncoder; - std::vector<int> inputIds; - bool zs12bit = true; - float zsThreshold = 2.f; - bool padding = true; - int verbosity = 1; -}; - -void convert(DigitArray& inputDigits, ProcessAttributes* processAttributes, o2::raw::RawFileWriter& writer); -#include "DetectorsRaw/HBFUtils.h" -void convertDigitsToZSfinal(std::string_view digitsFile, std::string_view outputPath, std::string_view fileFor, - bool sectorBySector, uint32_t rdhV, bool stopPage, bool noPadding, bool createParentDir) -{ - - // ===| open file and get tree |============================================== - std::unique_ptr<TFile> o2simDigits(TFile::Open(digitsFile.data())); - if (!o2simDigits || !o2simDigits->IsOpen() || o2simDigits->IsZombie()) { - LOGP(error, "Could not open file {}", digitsFile.data()); - exit(1); - } - auto treeSim = (TTree*)o2simDigits->Get("o2sim"); - if (!treeSim) { - LOGP(error, "Could not read digits tree from file {}", digitsFile.data()); - exit(1); - } - - gROOT->cd(); - - // ===| set up output directory |============================================= - std::string outDir{outputPath}; - if (outDir.empty()) { - outDir = "./"; - } - if (outDir.back() != '/') { - outDir += '/'; - } - - if (gSystem->AccessPathName(outDir.data())) { - if (createParentDir) { - if (gSystem->mkdir(outDir.data(), kTRUE)) { - LOGP(error, "could not create output directory {}", outDir.data()); - exit(1); - } - } else { - LOGP(error, "Requested output directory '{}' does not exists, consider removing '-n'", outDir.data()); - exit(1); - } - } - - // ===| set up raw writer |=================================================== - std::string inputGRP = o2::base::NameConf::getGRPFileName(); - const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); - - o2::raw::RawFileWriter writer{"TPC"}; // to set the RDHv6.sourceID if V6 is used - writer.useRDHVersion(rdhV); - writer.setAddSeparateHBFStopPage(stopPage); - writer.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::TPC)); // must be set explicitly - const unsigned int defaultLink = rdh_utils::UserLogicLinkID; - - for (unsigned int i = 0; i < NSectors; i++) { - for (unsigned int j = 0; j < NEndpoints; j++) { - const unsigned int cruInSector = j / 2; - const unsigned int cruID = i * 10 + cruInSector; - const rdh_utils::FEEIDType feeid = rdh_utils::getFEEID(cruID, j & 1, defaultLink); - std::string outfname; - if (fileFor == "all") { // single file for all links - outfname = fmt::format("{}tpc_all.raw", outDir); - } else if (fileFor == "sector") { - outfname = fmt::format("{}tpc_sector{}.raw", outDir, i); - } else if (fileFor == "link") { - outfname = fmt::format("{}cru{}_{}.raw", outDir, cruID, j & 1); - } else { - throw std::runtime_error("invalid option provided for file grouping"); - } - writer.registerLink(feeid, cruID, defaultLink, j & 1, outfname); - } - } - if (fileFor != "link") { // in case >1 link goes to the file, we must cache to preserve the TFs ordering - writer.useCaching(); - } - - // ===| set up branch addresses |============================================= - std::vector<Digit>* vDigitsPerSectorCollection[Sector::MAXSECTOR] = {nullptr}; // container that keeps Digits per sector - - treeSim->SetBranchStatus("*", 0); - treeSim->SetBranchStatus("TPCDigit_*", 1); - - ProcessAttributes attr; - attr.padding = !noPadding; - - for (int iSecBySec = 0; iSecBySec < Sector::MAXSECTOR; ++iSecBySec) { - treeSim->ResetBranchAddresses(); - for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { - if (sectorBySector) { - iSec = iSecBySec; - } - vDigitsPerSectorCollection[iSec] = nullptr; - treeSim->SetBranchAddress(TString::Format("TPCDigit_%d", iSec), &vDigitsPerSectorCollection[iSec]); - if (sectorBySector) { - break; - } - } - for (Long64_t ievent = 0; ievent < treeSim->GetEntries(); ++ievent) { - DigitArray inputDigits; - if (sectorBySector) { - treeSim->GetBranch(TString::Format("TPCDigit_%d", iSecBySec))->GetEntry(ievent); - } else { - treeSim->GetEntry(ievent); - } - - for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { - if (sectorBySector) { - iSec = iSecBySec; - } - inputDigits[iSec] = *vDigitsPerSectorCollection[iSec]; //???? - if (sectorBySector) { - break; - } - } - convert(inputDigits, &attr, writer); - for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { - delete vDigitsPerSectorCollection[iSec]; - vDigitsPerSectorCollection[iSec] = nullptr; - } - } - if (!sectorBySector) { - break; - } - } - // for further use we write the configuration file for the output - writer.writeConfFile("TPC", "RAWDATA", fmt::format("{}tpcraw.cfg", outDir)); -} - -void convert(DigitArray& inputDigits, ProcessAttributes* processAttributes, o2::raw::RawFileWriter& writer) -{ - auto& zsEncoder = processAttributes->zsEncoder; - const auto zsThreshold = processAttributes->zsThreshold; - const auto zs12bit = processAttributes->zs12bit; - GPUParam _GPUParam; - _GPUParam.SetDefaults(5.00668); - const GPUParam mGPUParam = _GPUParam; - - //o2::InteractionRecord ir = o2::raw::HBFUtils::Instance().getFirstIR(); - o2::InteractionRecord ir(0, 0); // we start with the time registered in ditigs, w/o extra offset - zsEncoder->RunZSEncoder<o2::tpc::Digit>(inputDigits, nullptr, nullptr, &writer, &ir, mGPUParam, zs12bit, false, zsThreshold, processAttributes->padding); -} - -int main(int argc, char** argv) -{ - bpo::variables_map vm; - bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + - " <cmds/options>\n" - " Tool will convert simulation digits to raw zero suppressed data\n" - "Commands / Options"); - bpo::options_description opt_hidden(""); - bpo::options_description opt_all; - bpo::positional_options_description opt_pos; - - try { - auto add_option = opt_general.add_options(); - add_option("help,h", "Print this help message"); - add_option("verbose,v", bpo::value<uint32_t>()->default_value(0), "Select verbosity level [0 = no output]"); - add_option("input-file,i", bpo::value<std::string>()->default_value("tpcdigits.root"), "Specifies input file."); - add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "Specify output directory"); - add_option("no-parent-directories,n", "Do not create parent directories recursively"); - add_option("sector-by-sector,s", bpo::value<bool>()->default_value(false)->implicit_value(true), "Run one TPC sector after another"); - add_option("file-for,f", bpo::value<std::string>()->default_value("sector"), "single file per: link,sector,all"); - add_option("stop-page,p", bpo::value<bool>()->default_value(false)->implicit_value(true), "HBF stop on separate CRU page"); - add_option("no-padding", bpo::value<bool>()->default_value(false)->implicit_value(true), "Don't pad pages to 8kb"); - uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>(); - add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); - add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); - - opt_all.add(opt_general).add(opt_hidden); - bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); - - if (vm.count("help") || argc == 1) { - std::cout << opt_general << std::endl; - exit(0); - } - - bpo::notify(vm); - } catch (bpo::error& e) { - std::cerr << "ERROR: " << e.what() << std::endl - << std::endl; - std::cerr << opt_general << std::endl; - exit(1); - } catch (std::exception& e) { - std::cerr << e.what() << ", application will now exit" << std::endl; - exit(2); - } - o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); - convertDigitsToZSfinal( - vm["input-file"].as<std::string>(), - vm["output-dir"].as<std::string>(), - vm["file-for"].as<std::string>(), - vm["sector-by-sector"].as<bool>(), - vm["rdh-version"].as<uint32_t>(), - vm["stop-page"].as<bool>(), - vm["no-padding"].as<bool>(), - !vm.count("no-parent-directories")); - - return 0; -} diff --git a/Detectors/TPC/simulation/src/CommonMode.cxx b/Detectors/TPC/simulation/src/CommonMode.cxx index 82cc1a678ec9e..5b3756b922e80 100644 --- a/Detectors/TPC/simulation/src/CommonMode.cxx +++ b/Detectors/TPC/simulation/src/CommonMode.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// \file CommonMode.cxx -/// \brief Implementation of the common mode output object +/// \brief Implementation of the common mode container class /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de #include "TPCSimulation/CommonMode.h" diff --git a/Detectors/TPC/simulation/src/Detector.cxx b/Detectors/TPC/simulation/src/Detector.cxx index 41e08eb6d9f77..f602c205261f1 100644 --- a/Detectors/TPC/simulation/src/Detector.cxx +++ b/Detectors/TPC/simulation/src/Detector.cxx @@ -1,13 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "DetectorsBase/MaterialManager.h" #include "TPCSimulation/Detector.h" #include "TPCSimulation/Point.h" #include "TPCBase/ParameterGas.h" @@ -1386,8 +1388,8 @@ void Detector::ConstructTPCGeometry() // guard rings for IFC - outer placed in inner insulator, inner placed in the drift gas (3 different radii) // AL, 1.2 cm wide, 0.015 cm thick, volumes TPC_IGR1 - outer, TPC_IGR2-4 - inner // - auto* igro = new TGeoTube(76.6624, 76.6774, 0.6); - auto* igrio = new TGeoTube(78.845, 78.86, 0.6); //outer part + auto* igro = new TGeoTube(76.6624, 76.6774, 0.6); //inner part, ends at inner radius of the IFC + auto* igrio = new TGeoTube(78.845, 78.86, 0.6); //outer part auto* igrim = new TGeoTube(78.795, 78.81, 0.6); auto* igric = new TGeoTube(78.785, 78.8, 0.6); // @@ -1435,20 +1437,27 @@ void Detector::ConstructTPCGeometry() // auto* cflv = new TGeoVolume("TPC_CDR", cfl, m3); // sandwich - auto* cd1 = new TGeoTubeSeg(60.6224, 61.19, 71.1, 0.2, 119.2); - auto* cd2 = new TGeoTubeSeg(60.6262, 61.1862, 71.1, 0.2, 119.2); - auto* cd3 = new TGeoTubeSeg(60.6462, 61.1662, 71.1, 0.2, 119.2); - auto* cd4 = new TGeoTubeSeg(60.6562, 61.1562, 71.1, 0.2, 119.2); - auto* tepox4 = new TGeoTubeSeg(60.6224, 61.19, 71.1, 359.8, 0.8); + auto* cd1 = new TGeoTubeSeg(60.6224, 61.19, 69.8, 0.05, 119.95); + auto* cd2 = new TGeoTubeSeg(60.6262, 61.1862, 69.8, 0.05, 119.95); + auto* cd3 = new TGeoTubeSeg(60.6462, 61.1662, 69.8, 0.05, 119.95); + auto* cd4 = new TGeoTubeSeg(60.6562, 61.1562, 69.8, 0.05, 119.95); + auto* tepox4 = new TGeoTubeSeg(60.6224, 61.19, 69.8, 359.95, 0.05); //epoxy glue 0.01 deg // TGeoMedium* sm6 = gGeoManager->GetMedium("TPC_Prepreg1"); TGeoMedium* sm8 = gGeoManager->GetMedium("TPC_Epoxyfm"); - auto* cd1v = new TGeoVolume("TPC_CDR1", cd1, sm2); // tedlar - auto* cd2v = new TGeoVolume("TPC_CDR2", cd2, sm6); // prepreg1 - auto* cd3v = new TGeoVolume("TPC_CDR3", cd3, sm8); // epoxy film - auto* cd4v = new TGeoVolume("TPC_CDR4", cd4, sm4); // nomex - auto* tvep4 = new TGeoVolume("TPC_IFEPOX4", tepox4, smep); - + auto* cd1v = new TGeoVolume("TPC_CDR1", cd1, sm2); // tedlar + auto* cd2v = new TGeoVolume("TPC_CDR2", cd2, sm6); // prepreg1 + auto* cd3v = new TGeoVolume("TPC_CDR3", cd3, sm8); // epoxy film + auto* cd4v = new TGeoVolume("TPC_CDR4", cd4, sm4); // nomex + auto* tvep4 = new TGeoVolume("TPC_IFEPOX4", tepox4, smep); // epoxy glue + // + // joints between sections 1 deg prepreg1 placed in nomex at lower and upper radius + 0.1 deg of glue (epoxy) + // + auto* cdjl = new TGeoTubeSeg(60.6562, 60.6762, 69.8, 0., 1.0); //lower, to be rotated when positioned + auto* cdju = new TGeoTubeSeg(61.1362, 61.1562, 69.8, 0., 1.0); //upper, to be rotated when positioned + // + auto* cdjlv = new TGeoVolume("TPC_CDJL", cdjl, sm6); + auto* cdjuv = new TGeoVolume("TPC_CDJU", cdju, sm6); // // seals for central drum 2 copies // @@ -1481,20 +1490,47 @@ void Detector::ConstructTPCGeometry() cd1v->AddNode(cd2v, 1); cd2v->AddNode(cd3v, 1); cd3v->AddNode(cd4v, 1); // sandwich + // + // joints, lower part and upper parts, placed in nomex + // + segrot = new TGeoRotation(); + segrot->RotateZ(0.05); + cd4v->AddNode(cdjlv, 1, segrot); + cd4v->AddNode(cdjuv, 1, segrot); + segrot = new TGeoRotation(); + segrot->RotateZ(118.95); + cd4v->AddNode(cdjlv, 2, segrot); + cd4v->AddNode(cdjuv, 2, segrot); + // + // according to the conversion data, segments have an additionaly rotated by 4.6 deg + // // first segment - cflv->AddNode(cd1v, 1); - cflv->AddNode(tvep4, 1); + segrot = new TGeoRotation(); + segrot->RotateZ(4.6); + cflv->AddNode(cd1v, 1, segrot); + cflv->AddNode(tvep4, 1, segrot); // second segment segrot = new TGeoRotation(); - segrot->RotateZ(120.); + segrot->RotateZ(124.6); cflv->AddNode(cd1v, 2, segrot); cflv->AddNode(tvep4, 2, segrot); // third segment segrot = new TGeoRotation(); - segrot->RotateZ(240.); + segrot->RotateZ(244.6); cflv->AddNode(cd1v, 3, segrot); cflv->AddNode(tvep4, 3, segrot); // + // heating strips + // + auto* hstr = new TGeoTubeSeg(60.6124, 60.6224, 68.5, 0., 1.25); + auto* hstrv = new TGeoVolume("TPC_HSTR", hstr, m1); // air, caved out from cflv, first strip starts at 0 deg + for (Int_t i = 0; i < 144; i++) { + Double_t alpha = 1.25 + i * 2.5; + segrot = new TGeoRotation(); + segrot->RotateZ(alpha); + cflv->AddNode(hstrv, i + 1, segrot); + } + // v1->AddNode(siv, 1, new TGeoTranslation(0., 0., -69.9)); v1->AddNode(siv, 2, new TGeoTranslation(0., 0., 69.9)); v1->AddNode(sev, 1); @@ -3078,6 +3114,18 @@ void Detector::defineSensitiveVolumes() // set volume sentive AddSensitiveVolume(v); } + + // Special sensitive volume parameters in case FLUKA is used as transport engine + auto vmc = TVirtualMC::GetMC(); + if (strcmp(vmc->GetName(), "TFluka") == 0) { + LOG(INFO) << "Setting special FLUKA parameters for TPC Driftgas"; + auto& mgr = o2::base::MaterialManager::Instance(); + Int_t index = mgr.getMediumID("TPC", kDriftGas2); + vmc->Gstpar(index, "PRIMIO_E", 20.77); + vmc->Gstpar(index, "PRIMIO_N", 14.35); + vmc->Gstpar(index, "LOSS", 14); + vmc->Gstpar(index, "STRA", 4); + } } Double_t Detector::Gamma(Double_t k) diff --git a/Detectors/TPC/simulation/src/DigitContainer.cxx b/Detectors/TPC/simulation/src/DigitContainer.cxx index bcb8d9447736e..44e774358fe2e 100644 --- a/Detectors/TPC/simulation/src/DigitContainer.cxx +++ b/Detectors/TPC/simulation/src/DigitContainer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/src/DigitGlobalPad.cxx b/Detectors/TPC/simulation/src/DigitGlobalPad.cxx index 302f7f42ae64e..48201f12e1117 100644 --- a/Detectors/TPC/simulation/src/DigitGlobalPad.cxx +++ b/Detectors/TPC/simulation/src/DigitGlobalPad.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/src/DigitMCMetaData.cxx b/Detectors/TPC/simulation/src/DigitMCMetaData.cxx deleted file mode 100644 index 05004e6038c48..0000000000000 --- a/Detectors/TPC/simulation/src/DigitMCMetaData.cxx +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file DigitMCMetaData.cxx -/// \brief Implementation of the Meta Data object of the Monte Carlo Digit -/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de - -#include "TPCSimulation/DigitMCMetaData.h" - -ClassImp(o2::tpc::DigitMCMetaData); diff --git a/Detectors/TPC/simulation/src/DigitTime.cxx b/Detectors/TPC/simulation/src/DigitTime.cxx index b070708afc63b..9829927178a3f 100644 --- a/Detectors/TPC/simulation/src/DigitTime.cxx +++ b/Detectors/TPC/simulation/src/DigitTime.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/src/Digitizer.cxx b/Detectors/TPC/simulation/src/Digitizer.cxx index 241159f14fe88..bcf79bf61a01c 100644 --- a/Detectors/TPC/simulation/src/Digitizer.cxx +++ b/Detectors/TPC/simulation/src/Digitizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,6 @@ #include "TPCBase/ParameterGas.h" #include "TPCSimulation/ElectronTransport.h" #include "TPCSimulation/GEMAmplification.h" -#include "TPCSimulation/PadResponse.h" #include "TPCSimulation/Point.h" #include "TPCSimulation/SAMPAProcessing.h" #include "TPCBase/CDBInterface.h" @@ -34,8 +34,6 @@ ClassImp(o2::tpc::Digitizer); using namespace o2::tpc; -bool o2::tpc::Digitizer::mIsContinuous = true; - void Digitizer::init() { // Calculate distortion lookup tables if initial space-charge density is provided @@ -65,7 +63,7 @@ void Digitizer::process(const std::vector<o2::tpc::HitGroup>& hits, signalArray.resize(nShapedPoints); /// Reserve space in the digit container for the current event - mDigitContainer.reserve(sampaProcessing.getTimeBinFromTime(mEventTime)); + mDigitContainer.reserve(sampaProcessing.getTimeBinFromTime(mEventTime - mOutputDigitTimeOffset)); /// obtain max drift_time + hitTime which can be processed float maxEleTime = (int(mDigitContainer.size()) - nShapedPoints) * eleParam.ZbinWidth; @@ -105,7 +103,7 @@ void Digitizer::process(const std::vector<o2::tpc::HitGroup>& hits, LOG(WARNING) << "Skipping electron with driftTime " << driftTime << " from hit at time " << hitTime; continue; } - const float absoluteTime = eleTime + mEventTime; /// in us + const float absoluteTime = eleTime + (mEventTime - mOutputDigitTimeOffset); /// in us /// Attachment if (electronTransport.isElectronAttachment(driftTime)) { @@ -161,23 +159,43 @@ void Digitizer::flush(std::vector<o2::tpc::Digit>& digits, bool finalFlush) { static SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance(); - mDigitContainer.fillOutputContainer(digits, labels, commonModeOutput, mSector, sampaProcessing.getTimeBinFromTime(mEventTime), mIsContinuous, finalFlush); + mDigitContainer.fillOutputContainer(digits, labels, commonModeOutput, mSector, sampaProcessing.getTimeBinFromTime(mEventTime - mOutputDigitTimeOffset), mIsContinuous, finalFlush); } -void Digitizer::setUseSCDistortions(SpaceCharge::SCDistortionType distortionType, const TH3* hisInitialSCDensity, int nRBins, int nPhiBins, int nZSlices) +void Digitizer::setUseSCDistortions(SC::SCDistortionType distortionType, const TH3* hisInitialSCDensity) { mUseSCDistortions = true; if (!mSpaceCharge) { - mSpaceCharge = std::make_unique<SpaceCharge>(nRBins, nPhiBins, nZSlices); + mSpaceCharge = std::make_unique<SC>(); } mSpaceCharge->setSCDistortionType(distortionType); if (hisInitialSCDensity) { - mSpaceCharge->setInitialSpaceChargeDensity(hisInitialSCDensity); + mSpaceCharge->fillChargeDensityFromHisto(*hisInitialSCDensity); + mSpaceCharge->setUseInitialSCDensity(true); } } -void Digitizer::setUseSCDistortions(SpaceCharge* spaceCharge) +void Digitizer::setUseSCDistortions(SC* spaceCharge) { mUseSCDistortions = true; mSpaceCharge.reset(spaceCharge); } + +void Digitizer::setUseSCDistortions(TFile& finp) +{ + mUseSCDistortions = true; + if (!mSpaceCharge) { + mSpaceCharge = std::make_unique<SC>(); + } + mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::A); + mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::C); + mSpaceCharge->setGlobalCorrectionsFromFile(finp, Side::A); + mSpaceCharge->setGlobalCorrectionsFromFile(finp, Side::C); +} + +void Digitizer::setStartTime(double time) +{ + static SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance(); + sampaProcessing.updateParameters(); + mDigitContainer.setStartTime(sampaProcessing.getTimeBinFromTime(time - mOutputDigitTimeOffset)); +} diff --git a/Detectors/TPC/simulation/src/ElectronTransport.cxx b/Detectors/TPC/simulation/src/ElectronTransport.cxx index fe4ed7a76f5ca..f63d27eaabf64 100644 --- a/Detectors/TPC/simulation/src/ElectronTransport.cxx +++ b/Detectors/TPC/simulation/src/ElectronTransport.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,8 +26,6 @@ ElectronTransport::ElectronTransport() : mRandomGaus(), mRandomFlat(RandomRing<> updateParameters(); } -ElectronTransport::~ElectronTransport() = default; - void ElectronTransport::updateParameters() { mGasParam = &(ParameterGas::Instance()); diff --git a/Detectors/TPC/simulation/src/GEMAmplification.cxx b/Detectors/TPC/simulation/src/GEMAmplification.cxx index 78da03d0cf495..0f899f797c2ef 100644 --- a/Detectors/TPC/simulation/src/GEMAmplification.cxx +++ b/Detectors/TPC/simulation/src/GEMAmplification.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "TPCBase/CDBInterface.h" #include <fstream> #include "FairLogger.h" +#include <filesystem> using namespace o2::tpc; using namespace o2::math_utils; @@ -37,15 +39,9 @@ GEMAmplification::GEMAmplification() const float kappa = 1 / (sigmaOverMu * sigmaOverMu); boost::format polya("1/(TMath::Gamma(%1%)*%2%) * TMath::Power(x/%3%, %4%) * TMath::Exp(-x/%5%)"); - // to be replaced by std::filesystem::exists once we have C++17 - auto fileexists = [](const char* fileName) -> bool { - std::ifstream infile(fileName); - return infile.good(); - }; - const char* polyaFileName = "tpc_polya.root"; TFile* outfile; - auto cacheexists = fileexists(polyaFileName); + auto cacheexists = std::filesystem::exists(polyaFileName); if (cacheexists) { LOG(INFO) << "TPC: GEM setup from existing cache"; outfile = TFile::Open(polyaFileName); @@ -81,12 +77,13 @@ GEMAmplification::GEMAmplification() const float gainStack = mGEMParam->TotalGainStack; const float kappaStack = mGEMParam->KappaStack; const float effStack = mGEMParam->EfficiencyStack; - const float sStack = gainStack / (kappaStack * (1.f - effStack)); + // Correct for electron losses occurring when changing kappa and the efficiency + const float sStack = gainStack / (kappaStack * effStack); polya % kappaStack % sStack % sStack % (kappaStack - 1) % sStack; std::string name = polya.str(); o2::math_utils::CachingTF1* polyaDistribution = nullptr; if (!cacheexists) { - polyaDistribution = new o2::math_utils::CachingTF1("polya", name.c_str(), 0, 50000); + polyaDistribution = new o2::math_utils::CachingTF1("polya", name.c_str(), 0, 25.f * gainStack); polyaDistribution->SetNpx(50000); } else { polyaDistribution = (o2::math_utils::CachingTF1*)outfile->Get("polyaStack"); @@ -105,8 +102,6 @@ GEMAmplification::GEMAmplification() LOG(INFO) << "TPC: GEM setup (polya) took " << watch.CpuTime(); } -GEMAmplification::~GEMAmplification() = default; - void GEMAmplification::updateParameters() { auto& cdb = CDBInterface::instance(); @@ -134,7 +129,7 @@ int GEMAmplification::getEffectiveStackAmplification(int nElectrons) /// in the stack is handled in an effective manner int nElectronsGEM = 0; for (int i = 0; i < nElectrons; ++i) { - if (mRandomFlat.getNextValue() < mGEMParam->EfficiencyStack) { + if (mRandomFlat.getNextValue() > mGEMParam->EfficiencyStack) { continue; } nElectronsGEM += mGainFullStack.getNextValue(); diff --git a/Detectors/TPC/simulation/src/IDCSim.cxx b/Detectors/TPC/simulation/src/IDCSim.cxx new file mode 100644 index 0000000000000..6dbaded3a513c --- /dev/null +++ b/Detectors/TPC/simulation/src/IDCSim.cxx @@ -0,0 +1,216 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCSimulation/IDCSim.h" +#include "DataFormatsTPC/Digit.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TFile.h" +#include "TPCBase/Mapper.h" +#include <fmt/format.h> +#include "Framework/Logger.h" +#include "TPCBase/Painter.h" +#include "TH2Poly.h" +#include "TCanvas.h" +#include "TLatex.h" +#include "TKey.h" + +void o2::tpc::IDCSim::integrateDigitsForOneTF(const gsl::span<const o2::tpc::Digit>& digits) +{ + resetIDCs(); + + // loop over digits from one sector for ALL Time Frames + const unsigned int switchAfterTB = getLastTimeBinForSwitch(); + + if (mAddInterval) { + // decrease the size of the vector if the last integration intervall is empty + if (switchAfterTB == (mIntegrationIntervalsPerTF - 1) * mTimeStampsPerIntegrationInterval) { + for (unsigned int ireg = 0; ireg < Mapper::NREGIONS; ++ireg) { + mIDCs[mBufferIndex][ireg].resize(mMaxIDCs[ireg] - Mapper::PADSPERREGION[ireg]); + } + } else { + for (auto& idcs : mIDCs[mBufferIndex]) { + idcs.resize(idcs.capacity()); + } + } + } + + for (const auto& digit : digits) { + const o2::tpc::CRU cru(digit.getCRU()); + const unsigned int region = cru.region(); + const int timeStamp = digit.getTimeStamp(); + if (timeStamp < switchAfterTB) { + const unsigned int indexPad = getIndex(timeStamp, region, digit.getRow(), digit.getPad()); + mIDCs[mBufferIndex][region][indexPad] += digit.getChargeFloat(); + } else { + const unsigned int indexPad = getIndex(timeStamp - switchAfterTB, region, digit.getRow(), digit.getPad()); + mIDCs[!mBufferIndex][region][indexPad] += digit.getChargeFloat(); + } + } + + mBufferIndex = !mBufferIndex; // switch buffer index + setNewOffset(); // set offset +} + +unsigned int o2::tpc::IDCSim::getLastTimeBinForSwitch() const +{ + const int totaloffs = mTimeBinsOff + static_cast<int>(mTimeStampsRemainder); + return (totaloffs >= mTimeStampsPerIntegrationInterval) ? mIntegrationIntervalsPerTF * mTimeStampsPerIntegrationInterval - mTimeBinsOff : (mIntegrationIntervalsPerTF - mAddInterval) * mTimeStampsPerIntegrationInterval - mTimeBinsOff; +} + +void o2::tpc::IDCSim::setNewOffset() +{ + const int totaloffs = mTimeBinsOff + static_cast<int>(mTimeStampsRemainder); + mTimeBinsOff = (totaloffs >= mTimeStampsPerIntegrationInterval) ? (totaloffs - static_cast<int>(mTimeStampsPerIntegrationInterval)) : totaloffs; +} + +/// set all IDC values to 0 +void o2::tpc::IDCSim::resetIDCs() +{ + for (auto& idcs : mIDCs[!mBufferIndex]) { + std::fill(idcs.begin(), idcs.end(), 0); + } +} + +void o2::tpc::IDCSim::dumpIDCs(const char* outFileName, const char* outName) const +{ + TFile fOut(outFileName, "RECREATE"); + fOut.WriteObject(this, outName); + fOut.Close(); +} + +void o2::tpc::IDCSim::createDebugTree(const char* nameTree) const +{ + o2::utils::TreeStreamRedirector pcstream(nameTree, "RECREATE"); + pcstream.GetFile()->cd(); + createDebugTree(*this, pcstream); + pcstream.Close(); +} + +void o2::tpc::IDCSim::createDebugTreeForAllSectors(const char* nameTree, const char* filename) +{ + o2::utils::TreeStreamRedirector pcstream(nameTree, "RECREATE"); + pcstream.GetFile()->cd(); + + TFile fInp(filename, "READ"); + for (TObject* keyAsObj : *fInp.GetListOfKeys()) { + const auto key = dynamic_cast<TKey*>(keyAsObj); + LOGP(info, "Key name: {} Type: {}", key->GetName(), key->GetClassName()); + + if (std::strcmp(o2::tpc::IDCSim::Class()->GetName(), key->GetClassName()) != 0) { + LOGP(info, "skipping object. wrong class."); + continue; + } + + IDCSim* idcsim = (IDCSim*)fInp.Get(key->GetName()); + createDebugTree(*idcsim, pcstream); + delete idcsim; + } + pcstream.Close(); +} + +void o2::tpc::IDCSim::createDebugTree(const IDCSim& idcsim, o2::utils::TreeStreamRedirector& pcstream) +{ + const Mapper& mapper = Mapper::instance(); + const unsigned int sector = idcsim.getSector(); + unsigned int cru = sector * Mapper::NREGIONS; + + // loop over data from regions + for (const auto& idcs : idcsim.get()) { + int sectorTmp = sector; + const o2::tpc::CRU cruTmp(cru); + unsigned int region = cruTmp.region(); + const unsigned long padsPerCRU = Mapper::PADSPERREGION[region]; + std::vector<int> vRow(padsPerCRU); + std::vector<int> vPad(padsPerCRU); + std::vector<float> vXPos(padsPerCRU); + std::vector<float> vYPos(padsPerCRU); + std::vector<float> vGlobalXPos(padsPerCRU); + std::vector<float> vGlobalYPos(padsPerCRU); + std::vector<float> idcsPerTimeBin(padsPerCRU); // idcs for one time bin + + for (unsigned int iPad = 0; iPad < padsPerCRU; ++iPad) { + const GlobalPadNumber globalNum = Mapper::GLOBALPADOFFSET[region] + iPad; + const auto& padPosLocal = mapper.padPos(globalNum); + vRow[iPad] = padPosLocal.getRow(); + vPad[iPad] = padPosLocal.getPad(); + vXPos[iPad] = mapper.getPadCentre(padPosLocal).X(); + vYPos[iPad] = mapper.getPadCentre(padPosLocal).Y(); + const GlobalPosition2D globalPos = mapper.LocalToGlobal(LocalPosition2D(vXPos[iPad], vYPos[iPad]), cruTmp.sector()); + vGlobalXPos[iPad] = globalPos.X(); + vGlobalYPos[iPad] = globalPos.Y(); + } + + for (unsigned int integrationInterval = 0; integrationInterval < idcsim.getNIntegrationIntervalsPerTF(); ++integrationInterval) { + for (unsigned int iPad = 0; iPad < padsPerCRU; ++iPad) { + idcsPerTimeBin[iPad] = (idcs)[iPad + integrationInterval * Mapper::PADSPERREGION[region]]; + } + + pcstream << "tree" + << "cru=" << cru + << "sector=" << sectorTmp + << "region=" << region + << "integrationInterval=" << integrationInterval + << "IDC.=" << idcsPerTimeBin + << "pad.=" << vPad + << "row.=" << vRow + << "lx.=" << vXPos + << "ly.=" << vYPos + << "gx.=" << vGlobalXPos + << "gy.=" << vGlobalYPos + << "\n"; + } + ++cru; + } +} + +void o2::tpc::IDCSim::drawIDCs(const unsigned int integrationInterval, const std::string filename) const +{ + const auto coords = o2::tpc::painter::getPadCoordinatesSector(); + TH2Poly* poly = o2::tpc::painter::makeSectorHist("hSector", "Sector;local #it{x} (cm);local #it{y} (cm); #it{IDC}"); + poly->SetContour(255); + poly->SetTitle(nullptr); + poly->GetYaxis()->SetTickSize(0.002f); + poly->GetYaxis()->SetTitleOffset(0.7f); + poly->GetZaxis()->SetTitleOffset(1.3f); + poly->SetStats(0); + + TCanvas* can = new TCanvas("can", "can", 2000, 1400); + can->SetRightMargin(0.14f); + can->SetLeftMargin(0.06f); + can->SetTopMargin(0.04f); + + TLatex lat; + lat.SetTextFont(63); + lat.SetTextSize(2); + + poly->Draw("colz"); + for (unsigned int region = 0; region < Mapper::NREGIONS; ++region) { + for (unsigned int irow = 0; irow < Mapper::ROWSPERREGION[region]; ++irow) { + for (unsigned int ipad = 0; ipad < Mapper::PADSPERROW[region][irow]; ++ipad) { + const auto padNum = Mapper::getGlobalPadNumber(irow, ipad, region); + const auto coordinate = coords[padNum]; + const float yPos = -0.5 * (coordinate.yVals[0] + coordinate.yVals[2]); // local coordinate system is mirrored + const float xPos = 0.5 * (coordinate.xVals[0] + coordinate.xVals[2]); + const unsigned int indexIDC = integrationInterval * Mapper::PADSPERREGION[region] + Mapper::OFFSETCRULOCAL[region][irow] + ipad; + const float idc = mIDCs[!mBufferIndex][region][indexIDC]; + poly->Fill(xPos, yPos, idc); + lat.SetTextAlign(12); + lat.DrawLatex(xPos, yPos, Form("%i", ipad)); + } + } + } + + if (!filename.empty()) { + can->SaveAs(filename.data()); + delete poly; + delete can; + } +} diff --git a/Detectors/TPC/simulation/src/PadResponse.cxx b/Detectors/TPC/simulation/src/PadResponse.cxx deleted file mode 100644 index ebcc2b3fb722a..0000000000000 --- a/Detectors/TPC/simulation/src/PadResponse.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file PadResponse.cxx -/// \brief Implementation of the Pad Response -/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de - -#include "TPCSimulation/PadResponse.h" - -#include "TPCBase/Mapper.h" - -#include <fstream> -#include <iostream> -#include <string> -#include <sstream> -#include <cmath> -#include "FairLogger.h" - -using namespace o2::tpc; - -PadResponse::PadResponse() - : mIROC(), - mOROC12(), - mOROC3() -{ - mIROC = std::make_unique<TGraph2D>(); - mOROC12 = std::make_unique<TGraph2D>(); - mOROC3 = std::make_unique<TGraph2D>(); - - importPRF("PRF_IROC.dat", mIROC); - importPRF("PRF_OROC1-2.dat", mOROC12); - importPRF("PRF_OROC3.dat", mOROC3); -} - -bool PadResponse::importPRF(std::string file, std::unique_ptr<TGraph2D>& grPRF) const -{ - std::string inputDir; - const char* aliceO2env = std::getenv("O2_ROOT"); - if (aliceO2env) { - inputDir = aliceO2env; - } - inputDir += "/share/Detectors/TPC/files/"; - - float x, y, normalizedPadResponse; - int i = 0; - std::ifstream prfFile(inputDir + file, std::ifstream::in); - if (!prfFile) { - LOG(FATAL) << "tpc::PadResponse - Input file '" << inputDir + file << "' does not exist! No PRF loaded!"; - return false; - } - for (std::string line; std::getline(prfFile, line);) { - std::istringstream is(line); - while (is >> x >> y >> normalizedPadResponse) { - grPRF->SetPoint(i++, x, y, normalizedPadResponse); - } - } - return true; -} - -float PadResponse::getPadResponse(GlobalPosition3D posEle, DigitPos digiPadPos) const -{ - /// \todo The procedure to find the global position of the pad centre should be made easier - const Mapper& mapper = Mapper::instance(); - const PadCentre padCentre = mapper.padCentre(mapper.globalPadNumber(digiPadPos.getPadPos())); - const CRU cru(digiPadPos.getCRU()); - const Sector sector(digiPadPos.getPadSecPos().getSector()); - const LocalPosition3D padCentreLocal(padCentre.X(), padCentre.Y(), posEle.Z()); - const GlobalPosition3D padCentrePos = mapper.LocalToGlobal(padCentreLocal, sector); - - ///std::cout << padCentrePos.X() << " " << posEle.X() << " " << padCentrePos.Y() << " " << posEle.Y() << "\n"; - - const int gemStack = int(cru.gemStack()); - const float offsetX = std::abs(posEle.X() - padCentre.X()) * 10.f; /// GlobalPosition3D and DigitPos in cm, PRF in mm - const float offsetY = std::abs(posEle.Y() - padCentre.Y()) * 10.f; /// GlobalPosition3D and DigitPos in cm, PRF in mm - float normalizedPadResponse = 0; - if (gemStack == 0) { - normalizedPadResponse = mIROC->Interpolate(offsetX, offsetY); - } else if (gemStack == 1 || gemStack == 2) { - normalizedPadResponse = mOROC12->Interpolate(offsetX, offsetY); - } else { - normalizedPadResponse = mOROC3->Interpolate(offsetX, offsetY); - } - return normalizedPadResponse; -} diff --git a/Detectors/TPC/simulation/src/Point.cxx b/Detectors/TPC/simulation/src/Point.cxx index a72669370a741..d3d3ee18b00bd 100644 --- a/Detectors/TPC/simulation/src/Point.cxx +++ b/Detectors/TPC/simulation/src/Point.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/src/SAMPAProcessing.cxx b/Detectors/TPC/simulation/src/SAMPAProcessing.cxx index 7de42c442243f..f7d017df02900 100644 --- a/Detectors/TPC/simulation/src/SAMPAProcessing.cxx +++ b/Detectors/TPC/simulation/src/SAMPAProcessing.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,8 +29,6 @@ SAMPAProcessing::SAMPAProcessing() : mRandomNoiseRing() updateParameters(); } -SAMPAProcessing::~SAMPAProcessing() = default; - void SAMPAProcessing::updateParameters() { mGasParam = &(ParameterGas::Instance()); diff --git a/Detectors/TPC/simulation/src/SpaceCharge.cxx b/Detectors/TPC/simulation/src/SpaceCharge.cxx deleted file mode 100644 index 2020d258d2e59..0000000000000 --- a/Detectors/TPC/simulation/src/SpaceCharge.cxx +++ /dev/null @@ -1,653 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file SpaceCharge.cxx -/// \brief Implementation of the interface for the ALICE TPC space-charge distortions calculations -/// \author Ernst Hellbär, Goethe-Universität Frankfurt, ernst.hellbar@cern.ch - -#include "TGeoGlobalMagField.h" -#include "TH3.h" -#include "TMath.h" -#include "TMatrixD.h" -#include "TStopwatch.h" - -#include "FairLogger.h" - -#include "DataFormatsTPC/Constants.h" -#include "DataFormatsTPC/Defs.h" -#include "Field/MagneticField.h" -#include "MathUtils/Utils.h" -#include "TPCBase/ParameterGas.h" -#include "TPCSimulation/SpaceCharge.h" - -using namespace o2::tpc; -using namespace o2::tpc::constants; -using namespace o2::math_utils; - -const float o2::tpc::SpaceCharge::sEzField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; - -SpaceCharge::SpaceCharge() - : mNZ(MaxNZ), - mNPhi(MaxNPhi), - mNR(MAXGLOBALPADROW), - mVoxelSizeZ(AliTPCPoissonSolver::fgkTPCZ0 / (MaxNZ - 1)), - mDriftTimeVoxel(IonDriftTime / (MaxNZ - 1)), - mVoxelSizePhi(TWOPI / MaxNPhi), - mVoxelSizeR((AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (MAXGLOBALPADROW - 1)), - mCoordZ(MaxNZ), - mCoordPhi(MaxNPhi), - mCoordR(MAXGLOBALPADROW), - mInterpolationOrder(2), - mUseInitialSCDensity(false), - mInitLookUpTables(false), - mMemoryAllocated(false), - mTimeInit(-1), - mSCDistortionType(SpaceCharge::SCDistortionType::SCDistortionsRealistic), - mLookUpTableCalculator(MAXGLOBALPADROW, MaxNZ, MaxNPhi, 2, 3, 0), - mSpaceChargeDensityA(MaxNPhi * MAXGLOBALPADROW * MaxNZ), - mSpaceChargeDensityC(MaxNPhi * MAXGLOBALPADROW * MaxNZ), - mRandomFlat(RandomRing<>::RandomType::Flat) -{ - mLookUpTableCalculator.SetCorrectionType(0); - mLookUpTableCalculator.SetIntegrationStrategy(0); - setVoxelCoordinates(); -} - -SpaceCharge::SpaceCharge(int nRBins, int nPhiBins, int nZSlices) - : mNZ(nZSlices), - mNPhi(nPhiBins), - mNR(nRBins), - mVoxelSizeZ(AliTPCPoissonSolver::fgkTPCZ0 / (nZSlices - 1)), - mDriftTimeVoxel(IonDriftTime / (nZSlices - 1)), - mVoxelSizePhi(TWOPI / nPhiBins), - mVoxelSizeR((AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRBins - 1)), - mCoordZ(nZSlices), - mCoordPhi(nPhiBins), - mCoordR(nRBins), - mInterpolationOrder(2), - mUseInitialSCDensity(false), - mInitLookUpTables(false), - mMemoryAllocated(false), - mTimeInit(-1), - mSCDistortionType(SpaceCharge::SCDistortionType::SCDistortionsRealistic), - mLookUpTableCalculator(nRBins, nZSlices, nPhiBins, 2, 3, 0), - mSpaceChargeDensityA(nPhiBins * nRBins * nZSlices), - mSpaceChargeDensityC(nPhiBins * nRBins * nZSlices), - mRandomFlat(RandomRing<>::RandomType::Flat) -{ - mLookUpTableCalculator.SetCorrectionType(0); - mLookUpTableCalculator.SetIntegrationStrategy(0); - setVoxelCoordinates(); -} - -SpaceCharge::SpaceCharge(int nRBins, int nPhiBins, int nZSlices, int interpolationOrder) - : mNZ(nZSlices), - mNPhi(nPhiBins), - mNR(nRBins), - mVoxelSizeZ(AliTPCPoissonSolver::fgkTPCZ0 / (nZSlices - 1)), - mDriftTimeVoxel(IonDriftTime / (nZSlices - 1)), - mVoxelSizePhi(TWOPI / nPhiBins), - mVoxelSizeR((AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRBins - 1)), - mCoordZ(nZSlices), - mCoordPhi(nPhiBins), - mCoordR(nRBins), - mInterpolationOrder(interpolationOrder), - mUseInitialSCDensity(false), - mInitLookUpTables(false), - mMemoryAllocated(false), - mTimeInit(-1), - mSCDistortionType(SpaceCharge::SCDistortionType::SCDistortionsRealistic), - mLookUpTableCalculator(nRBins, nZSlices, nPhiBins, interpolationOrder, 3, 0), - mSpaceChargeDensityA(nPhiBins * nRBins * nZSlices), - mSpaceChargeDensityC(nPhiBins * nRBins * nZSlices), - mRandomFlat(RandomRing<>::RandomType::Flat) -{ - mLookUpTableCalculator.SetCorrectionType(0); - mLookUpTableCalculator.SetIntegrationStrategy(0); - setVoxelCoordinates(); -} - -void SpaceCharge::setVoxelCoordinates() -{ - for (int iz = 0; iz < mNZ; ++iz) { - mCoordZ[iz] = iz * mVoxelSizeZ; - } - for (int iphi = 0; iphi < mNPhi; ++iphi) { - mCoordPhi[iphi] = iphi * mVoxelSizePhi; - } - for (int ir = 0; ir < mNR; ++ir) { - mCoordR[ir] = AliTPCPoissonSolver::fgkIFCRadius + ir * mVoxelSizeR; - } -} - -void SpaceCharge::allocateMemory() -{ - mMatrixIonDriftZA = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - mMatrixIonDriftRPhiA = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - mMatrixIonDriftRA = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - mMatrixIonDriftZC = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - mMatrixIonDriftRPhiC = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - mMatrixIonDriftRC = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - for (int iphi = 0; iphi < mNPhi; ++iphi) { - mMatrixIonDriftZA[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - mMatrixIonDriftRPhiA[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - mMatrixIonDriftRA[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - mMatrixIonDriftZC[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - mMatrixIonDriftRPhiC[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - mMatrixIonDriftRC[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - } - mLookUpIonDriftA = std::make_unique<AliTPCLookUpTable3DInterpolatorD>(mNR, (TMatrixD**)mMatrixIonDriftRA.get(), mCoordR.data(), mNPhi, (TMatrixD**)mMatrixIonDriftRPhiA.get(), mCoordPhi.data(), mNZ, (TMatrixD**)mMatrixIonDriftZA.get(), mCoordZ.data(), mInterpolationOrder); - mLookUpIonDriftC = std::make_unique<AliTPCLookUpTable3DInterpolatorD>(mNR, (TMatrixD**)mMatrixIonDriftRC.get(), mCoordR.data(), mNPhi, (TMatrixD**)mMatrixIonDriftRPhiC.get(), mCoordPhi.data(), mNZ, (TMatrixD**)mMatrixIonDriftZC.get(), mCoordZ.data(), mInterpolationOrder); - mMemoryAllocated = true; -} - -void SpaceCharge::init() -{ - if (!mInitLookUpTables) { - auto o2field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); - const float bzField = o2field->solenoidField(); // magnetic field in kGauss - /// TODO is there a faster way to get the drift velocity - auto& gasParam = ParameterGas::Instance(); - float vDrift = gasParam.DriftV; // drift velocity in cm/us - /// TODO fix hard coded values (ezField, t1, t2): export to Constants.h or get from somewhere? - const float t1 = 1.; - const float t2 = 1.; - /// TODO use this parameterization or fixed value(s) from Magboltz calculations? - const float omegaTau = -10. * bzField * vDrift / std::abs(sEzField); - setOmegaTauT1T2(omegaTau, t1, t2); - if (mUseInitialSCDensity) { - calculateLookupTables(); - } - } -} - -float SpaceCharge::calculateLookupTables() -{ - // Potential, E field and electron distortion and correction lookup tables - TStopwatch timer; - mLookUpTableCalculator.ForceInitSpaceCharge3DPoissonIntegralDz(mNR, mNZ, mNPhi, 300, 1e-8); - float tRealCalc = static_cast<float>(timer.RealTime()); - - // Lookup tables for local ion drift along E field - if (mSCDistortionType == SCDistortionType::SCDistortionsRealistic) { - if (!mMemoryAllocated) { - allocateMemory(); - } - TMatrixD* matrixDriftZ = nullptr; - TMatrixD* matrixDriftRPhi = nullptr; - TMatrixD* matrixDriftR = nullptr; - for (int iside = 0; iside < 2; ++iside) { - const int sign = 1 - iside * 2; - for (int iphi = 0; iphi < mNPhi; ++iphi) { - const float phi = static_cast<float>(mCoordPhi[iphi]); - if (iside == 0) { - matrixDriftZ = mMatrixIonDriftZA[iphi].get(); - matrixDriftRPhi = mMatrixIonDriftRPhiA[iphi].get(); - matrixDriftR = mMatrixIonDriftRA[iphi].get(); - } else { - matrixDriftZ = mMatrixIonDriftZC[iphi].get(); - matrixDriftRPhi = mMatrixIonDriftRPhiC[iphi].get(); - matrixDriftR = mMatrixIonDriftRC[iphi].get(); - } - int roc = iside == 0 ? o2::math_utils::angle2Sector(phi) : o2::math_utils::angle2Sector(phi) + 18; - for (int ir = 0; ir < mNR; ++ir) { - const float radius = static_cast<float>(mCoordR[ir]); - /// TODO: what is the electric field stored in the LUTs at iz=0 and iz=mNZSlices-1 - for (int iz = 0; iz < mNZ; ++iz) { - const float z = static_cast<float>(mCoordZ[iz]); - float x0[3] = {radius, phi, sign * (z + static_cast<float>(mVoxelSizeZ))}; // iphi, ir, iz+1 - float x1[3] = {radius, phi, sign * z}; // iphi, ir, iz - if (iside == 1) { - x0[2] *= -1; - x1[2] *= -1; - } - double eVector0[3] = {0., 0., 0.}; - double eVector1[3] = {0., 0., 0.}; - mLookUpTableCalculator.GetElectricFieldCyl(x0, roc, eVector0); // returns correct sign for Ez - mLookUpTableCalculator.GetElectricFieldCyl(x1, roc, eVector1); // returns correct sign for Ez - - // drift of ions along E field - (*matrixDriftR)(ir, iz) = -1 * sign * mVoxelSizeZ * 0.5 * (eVector0[0] + eVector1[0]) / (sign * sEzField + eVector0[2]); - (*matrixDriftRPhi)(ir, iz) = -1 * sign * mVoxelSizeZ * 0.5 * (eVector0[1] + eVector1[1]) / (sign * sEzField + eVector0[2]); - (*matrixDriftZ)(ir, iz) = -1 * sign * mVoxelSizeZ + DvDEoverv0 * mVoxelSizeZ * 0.5 * (eVector0[2] + eVector1[2]); - } - } - } - if (iside == 0) { - mLookUpIonDriftA->CopyFromMatricesToInterpolator(); - } else { - mLookUpIonDriftC->CopyFromMatricesToInterpolator(); - } - } - - // TODO: Propagate current SC density along E field by one time bin for next update - // propagateSpaceCharge(); - } - - mInitLookUpTables = true; - return tRealCalc; -} - -float SpaceCharge::updateLookupTables(float eventTime) -{ - // TODO: only update after update time interval - // if (mTimeInit < 0.) { - // mTimeInit = eventTime; // set the time of first initialization - // } - // if (std::abs(eventTime - mTimeInit) < mDriftTimeVoxel) { - // return 0.f; // update only after one time bin has passed - // } - // mTimeInit = eventTime; - - std::unique_ptr<std::unique_ptr<TMatrixD>[]> spaceChargeA = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - std::unique_ptr<std::unique_ptr<TMatrixD>[]> spaceChargeC = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - for (int iphi = 0; iphi < mNPhi; ++iphi) { - spaceChargeA[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - spaceChargeC[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - } - for (int iside = 0; iside < 2; ++iside) { - for (int iphi = 0; iphi < mNPhi; ++iphi) { - TMatrixD& chargeDensity = iside == 0 ? *spaceChargeA[iphi] : *spaceChargeC[iphi]; - for (int ir = 0; ir < mNR; ++ir) { - for (int iz = 0; iz < mNZ; ++iz) { - if (iside == 0) { - chargeDensity(ir, iz) = mSpaceChargeDensityA[iphi * mNR * mNZ + ir * mNZ + iz]; - } else { - chargeDensity(ir, iz) = mSpaceChargeDensityC[iphi * mNR * mNZ + ir * mNZ + iz]; - } - } - } - } - } - mLookUpTableCalculator.SetInputSpaceChargeA((TMatrixD**)spaceChargeA.get()); - mLookUpTableCalculator.SetInputSpaceChargeC((TMatrixD**)spaceChargeC.get()); - float tRealCalc = calculateLookupTables(); - return tRealCalc; -} - -void SpaceCharge::setOmegaTauT1T2(float omegaTau, float t1, float t2) -{ - mLookUpTableCalculator.SetOmegaTauT1T2(omegaTau, t1, t2); -} - -void SpaceCharge::setInitialSpaceChargeDensity(const TH3* hisSCDensity) -{ - std::unique_ptr<std::unique_ptr<TMatrixD>[]> spaceChargeA = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - std::unique_ptr<std::unique_ptr<TMatrixD>[]> spaceChargeC = std::make_unique<std::unique_ptr<TMatrixD>[]>(mNPhi); - for (int iphi = 0; iphi < mNPhi; ++iphi) { - spaceChargeA[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - spaceChargeC[iphi] = std::make_unique<TMatrixD>(mNR, mNZ); - } - mLookUpTableCalculator.GetChargeDensity((TMatrixD**)spaceChargeA.get(), (TMatrixD**)spaceChargeC.get(), hisSCDensity, mNR, mNZ, mNPhi); - for (int iside = 0; iside < 2; ++iside) { - for (int iphi = 0; iphi < mNPhi; ++iphi) { - TMatrixD& chargeDensity = iside == 0 ? *spaceChargeA[iphi] : *spaceChargeC[iphi]; - for (int ir = 0; ir < mNR; ++ir) { - for (int iz = 0; iz < mNZ; ++iz) { - if (iside == 0) { - mSpaceChargeDensityA[iphi * mNR * mNZ + ir * mNZ + iz] = chargeDensity(ir, iz); - } else { - mSpaceChargeDensityC[iphi * mNR * mNZ + ir * mNZ + iz] = chargeDensity(ir, iz); - } - } - } - } - } - mLookUpTableCalculator.SetInputSpaceChargeA((TMatrixD**)spaceChargeA.get()); - mLookUpTableCalculator.SetInputSpaceChargeC((TMatrixD**)spaceChargeC.get()); - mUseInitialSCDensity = true; -} - -void SpaceCharge::fillPrimaryIons(double r, double phi, double z, int nIons) -{ - Side side = z > 0 ? Side::A : Side::C; - double dr = 0.; - double drphi = 0.; - double dz = 0.; - getIonDrift(side, r, phi, z, dr, drphi, dz); - double rdist = r + dr; - double phidist = phi + drphi / r; - double zdist = z + dz; - const int zBin = TMath::BinarySearch(mNZ, mCoordZ.data(), std::abs(zdist)); - const int phiBin = TMath::BinarySearch(mNPhi, mCoordPhi.data(), phidist); - const int rBin = TMath::BinarySearch(mNR, mCoordR.data(), rdist); - /// TODO: protection against ions ending up outside the volume - if (z > 0 && zdist > 0) { - mSpaceChargeDensityA[phiBin * mNR * mNZ + rBin * mNZ + zBin] += ions2Charge(rBin, nIons); - } else if (z < 0 && zdist < 0) { - mSpaceChargeDensityC[phiBin * mNR * mNZ + rBin * mNZ + zBin] += ions2Charge(rBin, nIons); - } -} - -void SpaceCharge::fillPrimaryCharge(double r, double phi, double z, float charge) -{ - Side side = z > 0 ? Side::A : Side::C; - double dr = 0.; - double drphi = 0.; - double dz = 0.; - getIonDrift(side, r, phi, z, dr, drphi, dz); - double rdist = r + dr; - double phidist = phi + drphi / r; - double zdist = z + dz; - const int zBin = TMath::BinarySearch(mNZ, mCoordZ.data(), std::abs(zdist)); - const int phiBin = TMath::BinarySearch(mNPhi, mCoordPhi.data(), phidist); - const int rBin = TMath::BinarySearch(mNR, mCoordR.data(), rdist); - /// TODO: protection against ions ending up outside the volume - if (z > 0 && zdist > 0) { - mSpaceChargeDensityA[phiBin * mNR * mNZ + rBin * mNZ + zBin] += charge; - } else if (z < 0 && zdist < 0) { - mSpaceChargeDensityC[phiBin * mNR * mNZ + rBin * mNZ + zBin] += charge; - } -} - -void SpaceCharge::fillIBFIons(double r, double phi, Side side, int nIons) -{ - const int phiBin = TMath::BinarySearch(mNPhi, mCoordPhi.data(), phi); - const int rBin = TMath::BinarySearch(mNR, mCoordR.data(), r); - const int zBin = mNZ - 1; - /// TODO: distribution of amplification ions instead of placing all of them in one point - /// TODO: protection against ions ending up outside the volume - if (side == Side::A) { - mSpaceChargeDensityA[phiBin * mNR * mNZ + rBin * mNZ + zBin] += ions2Charge(rBin, nIons); - } else { - mSpaceChargeDensityC[phiBin * mNR * mNZ + rBin * mNZ + zBin] += ions2Charge(rBin, nIons); - } -} - -void SpaceCharge::fillIBFCharge(double r, double phi, Side side, float charge) -{ - const int phiBin = TMath::BinarySearch(mNPhi, mCoordPhi.data(), phi); - const int rBin = TMath::BinarySearch(mNR, mCoordR.data(), r); - const int zBin = mNZ - 1; - /// TODO: distribution of amplification ions instead of placing all of them in one point - /// TODO: protection against ions ending up outside the volume - if (side == Side::A) { - mSpaceChargeDensityA[phiBin * mNR * mNZ + rBin * mNZ + zBin] += charge; - } else { - mSpaceChargeDensityC[phiBin * mNR * mNZ + rBin * mNZ + zBin] += charge; - } -} - -void SpaceCharge::propagateSpaceCharge() -{ - // - // Continuity equation, assuming that the charge is conserved: - // delta(rho_0) / delta(t) = - div(flux) = - div(rho_0 * u) = - ( rho_0 * div(u) + u * grad(rho_0) ) - // u: velocity vector of space-charge density - // rho_0: space-charge density at time t0 - // - // - // Calculate the change of the space-charge density rho_0 at time t0 after time delta(t) = mVoxelSizeZ / v_driftIon: - // delta(rho_0) = - ( rho_0 * div(u) + u * grad(rho_0) ) * delta(t) - // = - ( rho_0 * div(d) + d * grad(rho_0) ) - // d: drift vector (dr, dphi, mVoxelSizeZ + dz) - // - // div(d) = 1/r del(r*d_r)/del(r) + 1/r del(d_phi)/del(phi) + del(d_z)/del(z) - // = d_r/r + del(d_r)/del(r) + 1/r del(d_phi)/del(phi) + del(d_z)/del(z) - // - // grad(rho_0) = del(rho_0)/del(r) * e_r + 1/r * del(rho_0)/del(phi) * e_phi + del(rho_0)/del(z) * e_z - // e_i: unit vectors in i = {r, phi, z} direction - // - - // Finite difference interpolation coefficients - const float coeffCent40 = 1.f / 12.f; - const float coeffCent41 = -2.f / 3.f; - const float coeffCent42 = -1.f * coeffCent41; - const float coeffCent43 = -1.f * coeffCent40; - const float coeffFwd30 = -11.f / 6.f; - const float coeffFwd31 = 3.f; - const float coeffFwd32 = -1.5; - const float coeffFwd33 = 1.f / 3.f; - const float coeffFwd20 = -1.5; - const float coeffFwd21 = 2.f; - const float coeffFwd22 = -0.5; - - std::vector<float>* scDensity = nullptr; - TMatrixD** matrixDriftZ = nullptr; - TMatrixD** matrixDriftRPhi = nullptr; - TMatrixD** matrixDriftR = nullptr; - for (int iside = 0; iside < 2; ++iside) { - const int signZ = iside == 0 ? 1 : -1; - if (iside == 0) { - scDensity = &mSpaceChargeDensityA; - matrixDriftZ = (TMatrixD**)mMatrixIonDriftZA.get(); - matrixDriftRPhi = (TMatrixD**)mMatrixIonDriftRPhiA.get(); - matrixDriftR = (TMatrixD**)mMatrixIonDriftRA.get(); - } else { - scDensity = &mSpaceChargeDensityC; - matrixDriftZ = (TMatrixD**)mMatrixIonDriftZC.get(); - matrixDriftRPhi = (TMatrixD**)mMatrixIonDriftRPhiC.get(); - matrixDriftR = (TMatrixD**)mMatrixIonDriftRC.get(); - } - /// TODO: is there a better way than to create a copy for the new SC density? - std::vector<float> newSCDensity(mNPhi * mNR * mNZ); - for (int iphi0 = 0; iphi0 < mNPhi; ++iphi0) { - - for (int ir0 = 0; ir0 < mNR; ++ir0) { - const float r0 = static_cast<float>(mCoordR[ir0]); - - for (int iz0 = 0; iz0 < mNZ; ++iz0) { - - // rho_0 * div(d) - float ddrdr = 0.f; - if (ir0 > 1 && ir0 < mNR - 2) { - ddrdr = (coeffCent40 * (*matrixDriftR[iphi0])(ir0 - 2, iz0) + coeffCent41 * (*matrixDriftR[iphi0])(ir0 - 1, iz0) + coeffCent42 * (*matrixDriftR[iphi0])(ir0 + 1, iz0) + coeffCent43 * (*matrixDriftR[iphi0])(ir0 + 2, iz0)) / static_cast<float>(mVoxelSizeR); - } else if (ir0 < 2) { - ddrdr = (coeffFwd30 * (*matrixDriftR[iphi0])(ir0, iz0) + coeffFwd31 * (*matrixDriftR[iphi0])(ir0 + 1, iz0) + coeffFwd32 * (*matrixDriftR[iphi0])(ir0 + 2, iz0) + coeffFwd33 * (*matrixDriftR[iphi0])(ir0 + 3, iz0)) / static_cast<float>(mVoxelSizeR); - } else if (ir0 > (mNR - 3)) { - ddrdr = -1 * (coeffFwd30 * (*matrixDriftR[iphi0])(ir0, iz0) + coeffFwd31 * (*matrixDriftR[iphi0])(ir0 - 1, iz0) + coeffFwd32 * (*matrixDriftR[iphi0])(ir0 - 2, iz0) + coeffFwd33 * (*matrixDriftR[iphi0])(ir0 - 3, iz0)) / static_cast<float>(mVoxelSizeR); - } - - const int iphiCent0 = iphi0 - 2 + (mNPhi) * (iphi0 < 2); - const int iphiCent1 = iphi0 - 1 + (mNPhi) * (iphi0 < 1); - const int iphiCent3 = iphi0 + 1 - (mNPhi) * (iphi0 > (mNPhi - 2)); - const int iphiCent4 = iphi0 + 2 - (mNPhi) * (iphi0 > (mNPhi - 3)); - const float ddphidphi = (coeffCent40 * (*matrixDriftRPhi[iphiCent0])(ir0, iz0) + coeffCent41 * (*matrixDriftRPhi[iphiCent1])(ir0, iz0) + coeffCent42 * (*matrixDriftRPhi[iphiCent3])(ir0, iz0) + coeffCent43 * (*matrixDriftRPhi[iphiCent4])(ir0, iz0)) / static_cast<float>(mVoxelSizePhi); - - float ddzdz = 0.f; - if (iz0 > 1 && iz0 < mNZ - 2) { - ddzdz = signZ * (coeffCent40 * (*matrixDriftZ[iphi0])(ir0, iz0 - 2) + coeffCent41 * (*matrixDriftZ[iphi0])(ir0, iz0 - 1) + coeffCent42 * (*matrixDriftZ[iphi0])(ir0, iz0 + 1) + coeffCent43 * (*matrixDriftZ[iphi0])(ir0, iz0 + 2)) / static_cast<float>(mVoxelSizeR); - } else if (iz0 == 1 || iz0 == (mNZ - 2)) { - ddzdz = signZ * (-0.5 * (*matrixDriftZ[iphi0])(ir0, iz0 - 1) + 0.5 * (*matrixDriftZ[iphi0])(ir0, iz0 + 1)) / static_cast<float>(mVoxelSizeR); - } else if (iz0 == 0) { - ddzdz = signZ * (coeffFwd20 * (*matrixDriftZ[iphi0])(ir0, iz0) + coeffFwd21 * (*matrixDriftZ[iphi0])(ir0, iz0 + 1) + coeffFwd22 * (*matrixDriftZ[iphi0])(ir0, iz0 + 2)) / static_cast<float>(mVoxelSizeR); - } else if (iz0 == (mNZ - 1)) { - ddzdz = -1 * signZ * (coeffFwd20 * (*matrixDriftZ[iphi0])(ir0, iz0) + coeffFwd21 * (*matrixDriftZ[iphi0])(ir0, iz0 - 1) + coeffFwd22 * (*matrixDriftZ[iphi0])(ir0, iz0 - 2)) / static_cast<float>(mVoxelSizeR); - } - - const float qdivd = (*scDensity)[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] * (((*matrixDriftR[iphi0])(ir0, iz0) + ddphidphi) / r0 + ddrdr + ddzdz); - - // - d * grad(rho_0) = - d_drift * grad(rho_0(x)) + d_dist * grad(rho_0(x+d_drift)) = (charge0 - charge1) + d_dist * grad(rho_0(x-d_drift)) - if (iz0 < (mNZ - 1)) { - const float dr = (*matrixDriftR[iphi0])(ir0, iz0); - const float drphi = (*matrixDriftRPhi[iphi0])(ir0, iz0); - const float dz = (*matrixDriftZ[iphi0])(ir0, iz0) + mVoxelSizeZ * signZ; - - const int ir1 = dr < 0 ? ir0 - 1 * (ir0 == (mNR - 1)) : ir0 - 1 + 1 * (ir0 == 0); - const int ir2 = dr < 0 ? ir0 + 1 - 1 * (ir0 == (mNR - 1)) : ir0 + 1 * (ir0 == 0); - const int iphi1 = drphi < 0 ? iphi0 : iphi0 - 1 + (mNPhi) * (iphi0 == 0); - const int iphi2 = drphi < 0 ? iphi0 + 1 - (mNPhi) * (iphi0 == (mNPhi - 1)) : iphi0; - const int iz1 = dz < 0 ? iz0 + 1 - 1 * (iside == 0) * (iz0 == (mNZ - 2)) : iz0 + 2 * (iside == 1) - 1 * (iside == 1) * (iz0 == (mNZ - 2)); - const int iz2 = dz < 0 ? iz0 + 2 - 2 * (iside == 1) - 1 * (iside == 0) * (iz0 == (mNZ - 2)) : iz0 + 1 - 1 * (iside == 1) * (iz0 == (mNZ - 2)); - - const float dqdr = ((*scDensity)[iphi0 * mNR * mNZ + ir2 * mNZ + (iz0 + 1)] - (*scDensity)[iphi0 * mNR * mNZ + ir1 * mNZ + (iz0 + 1)]) / static_cast<float>(mVoxelSizeR); - const float dqdphi = ((*scDensity)[iphi2 * mNR * mNZ + ir0 * mNZ + (iz0 + 1)] - (*scDensity)[iphi1 * mNR * mNZ + ir0 * mNZ + (iz0 + 1)]) / static_cast<float>(mVoxelSizePhi); - const float dqdz = ((*scDensity)[iphi0 * mNR * mNZ + ir0 * mNZ + iz2] - (*scDensity)[iphi0 * mNR * mNZ + ir0 * mNZ + iz1]) / static_cast<float>(mVoxelSizeZ); - - const float dgradq = dr * dqdr + drphi / r0 * dqdphi + dz * dqdz; - - newSCDensity[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] = (*scDensity)[iphi0 * mNR * mNZ + ir0 * mNZ + (iz0 + 1)] - (qdivd + dgradq); - } else { - newSCDensity[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] = -qdivd; - } - - if (newSCDensity[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] < 0.f) { - newSCDensity[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] = 0.f; - } - } - } - } - (*scDensity).swap(newSCDensity); - } -} - -void SpaceCharge::propagateIons() -{ - std::vector<float>* scDensity = nullptr; - AliTPCLookUpTable3DInterpolatorD* lookUpIonDrift = nullptr; - for (int iside = 0; iside < 2; ++iside) { - const int signZ = iside == 0 ? 1 : -1; - if (iside == 0) { - scDensity = &mSpaceChargeDensityA; - lookUpIonDrift = mLookUpIonDriftA.get(); - } else { - scDensity = &mSpaceChargeDensityC; - lookUpIonDrift = mLookUpIonDriftC.get(); - } - std::vector<float> newSCDensity(mNPhi * mNR * mNZ); - - for (int iphi0 = 0; iphi0 < mNPhi; ++iphi0) { - const double phi0 = static_cast<float>(mCoordPhi[iphi0]); - - for (int ir0 = 0; ir0 < mNR; ++ir0) { - const double r0 = static_cast<float>(mCoordR[ir0]); - const double r1 = r0 + mVoxelSizeR; - - for (int iz0 = 0; iz0 < mNZ; ++iz0) { - const double z0 = mCoordZ[iz0] * signZ; - - const float ionDensity = (*scDensity)[iphi0 * mNR * mNZ + ir0 * mNZ + iz0] * AliTPCPoissonSolver::fgke0 / TMath::Qe(); // #ions / cm^3 - const float nIons = std::round(ionDensity * mVoxelSizeZ * 0.5 * mVoxelSizePhi * (r1 * r1 - r0 * r0)); // absolute #ions in the voxel - - for (int iion = 0; iion < nIons; ++iion) { - double phiIon = phi0 + mRandomFlat.getNextValue() * mVoxelSizePhi; - double rIon = r0 + mRandomFlat.getNextValue() * mVoxelSizeR; - double zIon = z0 + mRandomFlat.getNextValue() * mVoxelSizeZ * signZ; - - double drphi = 0.f; - double dr = 0.f; - double dz = 0.f; - lookUpIonDrift->GetValue(rIon, phiIon, std::abs(zIon), dr, drphi, dz); - float phiIonF = static_cast<float>(phiIon + (drphi / rIon)); - o2::math_utils::bringTo02PiGen(phiIonF); - rIon += dr; - zIon += dz; - - // continue if ion is outside the TPC boundaries in r or z - if (rIon > (mCoordR[mNR - 1] + mVoxelSizeR) || rIon < mCoordR[0]) { - continue; - } - if ((zIon * signZ) > (mCoordZ[mNZ - 1] + mVoxelSizeZ) || (zIon * signZ) < mCoordZ[0]) { - continue; - } - - const int iphiDrift = TMath::BinarySearch(mNPhi, mCoordPhi.data(), static_cast<double>(phiIonF)); - const int irDrift = TMath::BinarySearch(mNR, mCoordR.data(), rIon); - const int izDrift = TMath::BinarySearch(mNZ, mCoordZ.data(), std::abs(zIon)); - newSCDensity[iphiDrift * mNR * mNZ + irDrift * mNZ + izDrift] += ions2Charge(irDrift, 1); - } - } - } - } - (*scDensity).swap(newSCDensity); - } -} - -void SpaceCharge::getIonDrift(Side side, double r, double phi, double z, double& dr, double& drphi, double& dz) const -{ - if (!mInitLookUpTables) { - return; - } - if (side == Side::A) { - mLookUpIonDriftA->GetValue(r, phi, z, dr, drphi, dz); - } else if (side == Side::C) { - mLookUpIonDriftC->GetValue(r, phi, -1 * z, dr, drphi, dz); - } else { - LOG(INFO) << "TPC side undefined! Cannot calculate local ion drift correction..."; - } -} - -void SpaceCharge::correctElectron(GlobalPosition3D& point) -{ - if (!mInitLookUpTables) { - return; - } - const float x[3] = {point.X(), point.Y(), point.Z()}; - float dx[3] = {0.f, 0.f, 0.f}; - float phi = point.phi(); - o2::math_utils::bringTo02PiGen(phi); - int roc = o2::math_utils::angle2Sector(phi); - /// FIXME: which side when z==0? - if (x[2] < 0) { - roc += 18; - } - mLookUpTableCalculator.GetCorrection(x, roc, dx); - point.SetXYZ(x[0] + dx[0], x[1] + dx[1], x[2] + dx[2]); -} - -void SpaceCharge::distortElectron(GlobalPosition3D& point) const -{ - if (!mInitLookUpTables) { - return; - } - const float x[3] = {point.X(), point.Y(), point.Z()}; - float dx[3] = {0.f, 0.f, 0.f}; - float phi = point.phi(); - o2::math_utils::bringTo02PiGen(phi); - int roc = o2::math_utils::angle2Sector(phi); - /// FIXME: which side when z==0? - if (x[2] < 0) { - roc += 18; - } - mLookUpTableCalculator.GetDistortion(x, roc, dx); - point.SetXYZ(x[0] + dx[0], x[1] + dx[1], x[2] + dx[2]); -} - -double SpaceCharge::getChargeDensity(Side side, const GlobalPosition3D& point) const -{ - Float_t x[3] = {point.rho(), point.phi(), point.z()}; - o2::math_utils::bringTo02PiGen(x[1]); - const int roc = side == Side::A ? o2::math_utils::angle2Sector(x[1]) : o2::math_utils::angle2Sector(x[1]) + 18; - return mLookUpTableCalculator.GetChargeCylAC(x, roc); -} - -float SpaceCharge::getChargeDensity(Side side, int ir, int iphi, int iz) const -{ - if (side == Side::A) { - return mSpaceChargeDensityA[iphi * mNR * mNZ + ir * mNZ + iz]; - } else if (side == Side::C) { - return mSpaceChargeDensityC[iphi * mNR * mNZ + ir * mNZ + iz]; - } else { - return -1.f; - } -} - -void SpaceCharge::setUseIrregularLUTs(int useIrrLUTs) -{ - mLookUpTableCalculator.SetCorrectionType(useIrrLUTs); -} - -void SpaceCharge::setUseFastDistIntegration(int useFastInt) -{ - mLookUpTableCalculator.SetIntegrationStrategy(useFastInt); -} - -void SpaceCharge::setDistortionLookupTables(TMatrixD** matrixIntDistDrA, TMatrixD** matrixIntDistDrphiA, TMatrixD** matrixIntDistDzA, TMatrixD** matrixIntDistDrC, TMatrixD** matrixIntDistDrphiC, TMatrixD** matrixIntDistDzC) -{ - mLookUpTableCalculator.SetDistortionLookupTables(matrixIntDistDrA, matrixIntDistDrphiA, matrixIntDistDzA, matrixIntDistDrC, matrixIntDistDrphiC, matrixIntDistDzC); - mInitLookUpTables = true; -} - -float SpaceCharge::ions2Charge(int rBin, int nIons) -{ - float rInner = mCoordR[rBin]; - float rOuter = mCoordR[rBin] + mVoxelSizeR; - return nIons * TMath::Qe() / (mVoxelSizeZ * 0.5 * mVoxelSizePhi * (rOuter * rOuter - rInner * rInner)) / AliTPCPoissonSolver::fgke0; -} diff --git a/Detectors/TPC/simulation/src/TPCSimulationLinkDef.h b/Detectors/TPC/simulation/src/TPCSimulationLinkDef.h index 48edbf58b0277..a5f483ddebfef 100644 --- a/Detectors/TPC/simulation/src/TPCSimulationLinkDef.h +++ b/Detectors/TPC/simulation/src/TPCSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,6 @@ #pragma link C++ class o2::tpc::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::tpc::Detector> + ; -#pragma link C++ class o2::tpc::DigitMCMetaData + ; -#pragma link C++ class std::vector < o2::tpc::DigitMCMetaData> + ; #pragma link C++ class o2::tpc::CommonMode + ; #pragma link C++ class std::vector < o2::tpc::CommonMode> + ; #pragma link C++ class o2::tpc::DigitContainer + ; @@ -26,14 +25,12 @@ #pragma link C++ class o2::tpc::DigitTime + ; #pragma link C++ class o2::tpc::ElectronTransport + ; #pragma link C++ class o2::tpc::GEMAmplification + ; -#pragma link C++ class o2::tpc::PadResponse + ; #pragma link C++ class o2::tpc::Point + ; #pragma link C++ class o2::tpc::ElementalHit + ; #pragma link C++ class std::vector < o2::tpc::ElementalHit> + ; #pragma link C++ class o2::tpc::HitGroup + ; #pragma link C++ class o2::tpc::SAMPAProcessing + ; -#pragma link C++ class o2::tpc::SpaceCharge + ; -#pragma link C++ enum o2::tpc::SpaceCharge::SCDistortionType + ; +#pragma link C++ class o2::tpc::IDCSim + ; #pragma link C++ class std::vector < o2::tpc::HitGroup> + ; diff --git a/Detectors/TPC/simulation/test/CMakeLists.txt b/Detectors/TPC/simulation/test/CMakeLists.txt index f3ecb10b4f9aa..cac0c1ef5b839 100644 --- a/Detectors/TPC/simulation/test/CMakeLists.txt +++ b/Detectors/TPC/simulation/test/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(DigitContainer LABELS tpc diff --git a/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx b/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx index ed298b4d9bfba..86a84d950afd6 100644 --- a/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx +++ b/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,6 @@ #include <vector> #include "DataFormatsTPC/Digit.h" #include "TPCSimulation/DigitContainer.h" -#include "TPCSimulation/DigitMCMetaData.h" #include "TPCSimulation/SAMPAProcessing.h" #include "TPCBase/CDBInterface.h" diff --git a/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx b/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx index 69ffede6bd79f..12732a52d7fa7 100644 --- a/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx +++ b/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx b/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx index e67857f5c5af1..63c092deb59c2 100644 --- a/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx +++ b/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -71,7 +72,7 @@ BOOST_AUTO_TEST_CASE(GEMamplification_effective_test) const int nEleIn = 158; /// Number of electrons liberated in Ne-CO2-N2 by an incident Fe-55 photon - for (int i = 0; i < 100000; ++i) { + for (int i = 0; i < 500000; ++i) { hTest.Fill(gemStack.getEffectiveStackAmplification(nEleIn)); } @@ -79,10 +80,10 @@ BOOST_AUTO_TEST_CASE(GEMamplification_effective_test) float energyResolution = gaus.GetParameter(2) / gaus.GetParameter(1) * 100.f; /// Check the resulting gain - /// \todo should be more restrictive - BOOST_CHECK_CLOSE(gaus.GetParameter(1) / static_cast<float>(nEleIn), (gemParam.TotalGainStack), 5.f); + BOOST_CHECK_CLOSE(gaus.GetParameter(1) / static_cast<float>(nEleIn), (gemParam.TotalGainStack), 1.f); /// Check the resulting energy resolution - BOOST_CHECK_CLOSE(energyResolution, 12.4f, 0.5f); + /// we allow for 5% variation which is given by the uncertainty of the experimental determination of the energy resolution (12.1 +/- 0.5) % + BOOST_CHECK_CLOSE(energyResolution, 12.1, 5); } /// \brief Test of the getSingleGEMAmplification function diff --git a/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx b/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx index ef540e21ea8f8..e92a04be4e51b 100644 --- a/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx +++ b/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/simulation/test/testTPCSimulation.cxx b/Detectors/TPC/simulation/test/testTPCSimulation.cxx index 0982ffa7c8c96..93365a2d0668b 100644 --- a/Detectors/TPC/simulation/test/testTPCSimulation.cxx +++ b/Detectors/TPC/simulation/test/testTPCSimulation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,6 @@ #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> #include "TPCSimulation/Point.h" -#include "TPCSimulation/DigitMCMetaData.h" #include "MathUtils/Cartesian.h" template <typename T> @@ -42,15 +42,5 @@ BOOST_AUTO_TEST_CASE(Point_test) BOOST_CHECK_CLOSE(testpoint.GetDetectorID(), 8., 1E-12); } -/// \brief Trivial test of the initialization of a DigitMCMetaData and its getters -/// Precision: 1E-12 % -BOOST_AUTO_TEST_CASE(DigitMCMetaData_test) -{ - DigitMCMetaData testdigit(1.f, 2.f, 3.f, 4.f); - BOOST_CHECK_CLOSE(testdigit.getRawADC(), 1.f, 1E-12); - BOOST_CHECK_CLOSE(testdigit.getCommonMode(), 2.f, 1E-12); - BOOST_CHECK_CLOSE(testdigit.getPedestal(), 3.f, 1E-12); - BOOST_CHECK_CLOSE(testdigit.getNoise(), 4.f, 1E-12); -} } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/spacecharge/CMakeLists.txt b/Detectors/TPC/spacecharge/CMakeLists.txt new file mode 100644 index 0000000000000..448ccf5d470ff --- /dev/null +++ b/Detectors/TPC/spacecharge/CMakeLists.txt @@ -0,0 +1,68 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TPCSpaceCharge + TARGETVARNAME targetName + SOURCES src/SpaceCharge.cxx + src/PoissonSolver.cxx + src/SpaceChargeParameter.cxx + src/TriCubic.cxx + PUBLIC_LINK_LIBRARIES O2::TPCBase + Vc::Vc + ROOT::Core) + +o2_target_root_dictionary(TPCSpaceCharge + HEADERS include/TPCSpaceCharge/PoissonSolver.h + include/TPCSpaceCharge/SpaceCharge.h + include/TPCSpaceCharge/RegularGrid3D.h + include/TPCSpaceCharge/DataContainer3D.h + include/TPCSpaceCharge/PoissonSolverHelpers.h + include/TPCSpaceCharge/SpaceChargeHelpers.h + include/TPCSpaceCharge/TriCubic.h + include/TPCSpaceCharge/Vector.h + include/TPCSpaceCharge/Vector3D.h + include/TPCSpaceCharge/SpaceChargeParameter.h + LINKDEF src/TPCSpacechargeLinkDef.h) + +o2_add_test_root_macro(macro/calculateDistortionsCorrections.C + PUBLIC_LINK_LIBRARIES O2::TPCSpaceCharge + LABELS tpc COMPILE_ONLY) + +o2_add_test_root_macro(macro/createResidualDistortionObject.C + PUBLIC_LINK_LIBRARIES O2::TPCSpaceCharge + O2::CommonUtils + LABELS tpc) + + +install(FILES macro/createSCHistosFromHits.C + DESTINATION share/macro/) + +o2_add_test_root_macro(macro/createSCHistosFromHits.C + PUBLIC_LINK_LIBRARIES O2::TPCSpaceCharge + O2::CommonUtils + O2::TPCBase + O2::TPCSimulation + O2::DataFormatsTPC + O2::MathUtils + LABELS tpc COMPILE_ONLY) + +o2_add_test(PoissonSolver + COMPONENT_NAME spacecharge + PUBLIC_LINK_LIBRARIES O2::TPCSpaceCharge + SOURCES test/testO2TPCPoissonSolver.cxx + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + LABELS tpc + CONFIGURATIONS RelWithDebInfo Release MinRelSize) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h new file mode 100644 index 0000000000000..f9413cb905a59 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h @@ -0,0 +1,220 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataContainer3D.h +/// \brief This class provides a simple method to store values on a large 3-Dim grid with ROOT io functionality +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#ifndef ALICEO2_TPC_DATACONTAINER3D_H_ +#define ALICEO2_TPC_DATACONTAINER3D_H_ + +#include <memory> +#include "TFile.h" +#include "Rtypes.h" +#include "Framework/Logger.h" +#include <iomanip> +#include <vector> + +namespace o2 +{ +namespace tpc +{ + +/// \class DataContainer3D +/// The DataContainer3D class represents a simple method to store values on a large 3-Dim grid with ROOT io functionality. + +/// \tparam DataT the type of data which is used during the calculations +template <typename DataT = double> +struct DataContainer3D { + + ///< constructor + /// \param nZ number of vertices in z direction + /// \param nR number of vertices in r direction + /// \param nPhi number of vertices in phi direction + DataContainer3D(unsigned short nZ, unsigned short nR, unsigned short nPhi) : mZVertices{nZ}, mRVertices{nR}, mPhiVertices{nPhi}, mData(nZ * nR * nPhi){}; + + ///< default constructor for Root I/O + DataContainer3D() = default; + + /// operator to directly access the values + const DataT& operator[](size_t i) const { return mData[i]; } + DataT& operator[](size_t i) { return mData[i]; } + + const auto& getData() const { return mData; } + auto& getData() { return mData; } + + /// \param ix index in x dimension + /// \param iy index in y dimension + /// \param iz index in z dimension + /// \return returns the stored value + const DataT& operator()(size_t ix, size_t iy, size_t iz) const + { + const size_t ind = getDataIndex(ix, iy, iz); + return mData[ind]; + } + + /// \param ix index in x dimension + /// \param iy index in y dimension + /// \param iz index in z dimension + /// \return returns the stored value + DataT& operator()(size_t ix, size_t iy, size_t iz) + { + const size_t ind = getDataIndex(ix, iy, iz); + return mData[ind]; + } + + /// \param ix index in x dimension + /// \param iy index in y dimension + /// \param iz index in z dimension + /// \return returns the index to the data + size_t getDataIndex(const size_t ix, const size_t iy, const size_t iz) const + { + const size_t index = ix + mZVertices * (iy + iz * mRVertices); + return index; + } + + /// \return returns the number of values stored + size_t getNDataPoints() const { return mData.size(); } + + /// \return returns the number of x vertices + unsigned short getNZ() const { return mZVertices; } + + /// \return returns the number of y vertices + unsigned short getNR() const { return mRVertices; } + + /// \return returns the number of z vertices + unsigned short getNPhi() const { return mPhiVertices; } + + /// write this object to a file + /// \param outf object is written to this file + /// \param name object is saved with this name + int writeToFile(TFile& outf, const char* name = "data") const; + + /// set values from file + bool initFromFile(TFile& inpf, const char* name = "data"); + + /// get pointer to object from file + inline static DataContainer3D<DataT>* loadFromFile(TFile& inpf, const char* name = "data"); + + /// print the matrix + void print() const; + + private: + unsigned short mZVertices{}; ///< number of z vertices + unsigned short mRVertices{}; ///< number of r vertices + unsigned short mPhiVertices{}; ///< number of phi vertices + std::vector<DataT> mData{}; ///< storage for the data + + ClassDefNV(DataContainer3D, 1) +}; + +/// +/// ======================================================================================================== +/// Inline implementations of some methods +/// ======================================================================================================== +/// + +template <typename DataT> +int DataContainer3D<DataT>::writeToFile(TFile& outf, const char* name) const +{ + if (outf.IsZombie()) { + LOGP(ERROR, "Failed to write to file: {}", outf.GetName()); + return -1; + } + outf.WriteObjectAny(this, DataContainer3D<DataT>::Class(), name); + return 0; +} + +/// set values from file +template <typename DataT> +bool DataContainer3D<DataT>::initFromFile(TFile& inpf, const char* name) +{ + if (inpf.IsZombie()) { + LOGP(ERROR, "Failed to read from file: {}", inpf.GetName()); + return false; + } + DataContainer3D<DataT>* dataCont{nullptr}; + dataCont = reinterpret_cast<DataContainer3D<DataT>*>(inpf.GetObjectChecked(name, DataContainer3D<DataT>::Class())); + + if (!dataCont) { + LOGP(ERROR, "Failed to load {} from {}", name, inpf.GetName()); + return false; + } + + if (mZVertices != dataCont->getNZ() || mRVertices != dataCont->getNR() || mPhiVertices != dataCont->getNPhi()) { + LOGP(ERROR, "Data from input file has different definition of vertices!"); + LOGP(ERROR, "set vertices before creating the sc object to: SpaceCharge<>::setGrid({}, {}, {})", dataCont->getNZ(), dataCont->getNR(), dataCont->getNPhi()); + delete dataCont; + return false; + } + + mData = dataCont->mData; + delete dataCont; + return true; +} + +template <typename DataT> +DataContainer3D<DataT>* DataContainer3D<DataT>::loadFromFile(TFile& inpf, const char* name) +{ + if (inpf.IsZombie()) { + LOGP(ERROR, "Failed to read from file {}", inpf.GetName()); + return nullptr; + } + DataContainer3D<DataT>* dataCont{nullptr}; + + dataCont = reinterpret_cast<DataContainer3D<DataT>*>(inpf.GetObjectChecked(name, DataContainer3D<DataT>::Class())); + if (!dataCont) { + LOGP(ERROR, "Failed to load {} from {}", name, inpf.GetName()); + return nullptr; + } + return dataCont; +} + +template <typename DataT> +void DataContainer3D<DataT>::print() const +{ + std::stringstream stream; + stream.precision(3); + auto&& w = std::setw(9); + stream << std::endl; + + for (unsigned int iz = 0; iz < mPhiVertices; ++iz) { + stream << "z layer: " << iz << "\n"; + // print top x row + stream << "⎡" << w << (*this)(0, 0, iz); + for (unsigned int ix = 1; ix < mZVertices; ++ix) { + stream << ", " << w << (*this)(ix, 0, iz); + } + stream << " ⎤ \n"; + + for (unsigned int iy = 1; iy < mRVertices - 1; ++iy) { + stream << "⎢" << w << (*this)(0, iy, iz); + for (unsigned int ix = 1; ix < mZVertices; ++ix) { + stream << ", " << w << (*this)(ix, iy, iz); + } + stream << " ⎥ \n"; + } + + stream << "⎣" << w << (*this)(0, mRVertices - 1, iz); + for (unsigned int ix = 1; ix < mZVertices; ++ix) { + stream << ", " << w << (*this)(ix, mRVertices - 1, iz); + } + stream << " ⎦ \n \n"; + } + LOGP(info, "{} \n \n", stream.str()); +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolver.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolver.h new file mode 100644 index 0000000000000..94947ae9fa395 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolver.h @@ -0,0 +1,490 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file PoissonSolver.h +/// \brief This class provides implementation of Poisson equation +/// solver by MultiGrid Method +/// Original version of this class can be found in AliTPCPoissonSolver.h +/// +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#ifndef ALICEO2_TPC_POISSONSOLVER_H_ +#define ALICEO2_TPC_POISSONSOLVER_H_ + +#include "TPCSpaceCharge/DataContainer3D.h" +#include "TPCSpaceCharge/RegularGrid3D.h" +#include "CommonConstants/MathConstants.h" +#include "TPCSpaceCharge/SpaceChargeParameter.h" +#include <vector> + +namespace o2 +{ +namespace tpc +{ + +template <typename DataT> +class Vector3D; + +/// \class PoissonSolver +/// The PoissonSolver class represents methods to solve the poisson equation. +/// Original version with more methods can be found in AliTPCPoissonSolver. +/// Following methods are implemented: poissonSolver3D, poissonSolver3D2D, poissonSolver2D + +/// \tparam DataT the type of data which is used during the calculations +template <typename DataT = double> +class PoissonSolver +{ + public: + using RegularGrid = RegularGrid3D<DataT>; + using DataContainer = DataContainer3D<DataT>; + using Vector = Vector3D<DataT>; + + /// default constructor + PoissonSolver(const RegularGrid& gridProperties) : mGrid3D{gridProperties} {}; + + /// Provides poisson solver in Cylindrical 3D (TPC geometry) + /// + /// Strategy based on parameter settings (mMgParameters)provided + /// * Cascaded multi grid with S.O.R + /// * Geometric MultiGrid + /// * Cycles: V, W, Full + /// * Relaxation: Jacobi, Weighted-Jacobi, Gauss-Seidel + /// * Grid transfer operators: Full, Half + /// * Spectral Methods (TODO) + /// + /// \param matricesV potential in 3D + /// \param matricesCharge charge density in 3D (side effect) + /// \param symmetry symmetry or not + /// + /// \pre Charge density distribution in **matricesCharge** is known and boundary values for **matricesV** are set + /// \post Numerical solution for potential distribution is calculated and stored in each rod at **matricesV** + void poissonSolver3D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry); + + /// Provides poisson solver in 2D + /// + /// Based on the strategy (multi grid) + /// + /// \param matricesV potential in matrix + /// \param matricesCharge charge density in matrix (side effect + void poissonSolver2D(DataContainer& matricesV, const DataContainer& matricesCharge); + + DataT getSpacingZ() const { return mGrid3D.getSpacingZ(); } + DataT getSpacingR() const { return mGrid3D.getSpacingR(); } + DataT getSpacingPhi() const { return mGrid3D.getSpacingPhi(); } + + static void setConvergenceError(const DataT error) { sConvergenceError = error; } + + static DataT getConvergenceError() { return sConvergenceError; } + + /// get the number of threads used for some of the calculations + static int getNThreads() { return sNThreads; } + + /// set the number of threads used for some of the calculations + static void setNThreads(int nThreads) { sNThreads = nThreads; } + + private: + inline static auto& mParamGrid = ParameterSpaceCharge::Instance(); ///< parameters of the grid on which the calculations are performed + const RegularGrid& mGrid3D{}; ///< grid properties + inline static DataT sConvergenceError{1e-6}; ///< Error tolerated + static constexpr DataT INVTWOPI = 1. / o2::constants::math::TwoPI; ///< inverse of 2*pi + inline static int sNThreads{4}; ///< number of threads which are used during some of the calculations (increasing this number has no big impact) + + /// Relative error calculation: comparison with exact solution + /// + /// \param matricesCurrentV current potential (numerical solution) + /// \param prevArrayV content from matricesCurrentV from previous iteration + DataT getConvergenceError(const Vector& matricesCurrentV, Vector& prevArrayV) const; + + /// 3D - Solve Poisson's Equation in 3D by MultiGrid with constant phi slices + /// + /// NOTE: In order for this algorithm to work, the number of Nr and Nz must be a power of 2 plus one. + /// The number of Nr and Z Column can be different. + /// + /// R Row == 2**M + 1 + /// Z Column == 2**N + 1 + /// Phi Slice == Arbitrary but greater than 3 + /// + /// Solving: \f$ \nabla^{2}V(r,\phi,z) = - f(r,\phi,z) \f$ + /// + /// Algorithm for MultiGrid Full Cycle (FMG) + /// - Relax on the coarsest grid + /// - Do from coarsest to finest + /// - Interpolate potential from coarse -> fine + /// - Do V-Cycle to the current coarse level to the coarsest + /// - Stop if converged + /// + /// DeltaPhi in Radians + /// \param matricesV potential in 3D matrix \f$ V(r,\phi,z) \f$ + /// \param matricesCharge charge density in 3D matrix (side effect) \f$ - f(r,\phi,z) \f$ + /// \param symmetry symmetry (TODO for symmetry = 1) + // + /// SYMMETRY = 0 if no phi symmetries, and no phi boundary condition + /// = 1 if we have reflection symmetry at the boundaries (eg. sector symmetry or half sector symmetries). + void poissonMultiGrid3D2D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry); + + /// 3D - Solve Poisson's Equation in 3D in all direction by MultiGrid + /// + /// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. + /// The number of nRRow and Z Column can be different. + /// + /// R Row == 2**M + 1 + /// Z Column == 2**N + 1 + /// Phi Slices == Arbitrary but greater than 3 + /// + /// Solving: \f$ \nabla^{2}V(r,\phi,z) = - f(r,\phi,z) \f$ + /// + /// Algorithm for MultiGrid Full Cycle (FMG) + /// - Relax on the coarsest grid + /// - Do from coarsest to finest + /// - Interpolate potential from coarse -> fine + /// - Do V-Cycle to the current coarse level to the coarsest + /// - Stop if converged + /// + /// \param matricesV potential in 3D matrix + /// \param matricesCharge charge density in 3D matrix (side effect) + /// \param symmetry symmetry or not: symmetry = 0 if no phi symmetries, and no phi boundary condition. + /// symmetry = 1 if we have reflection symmetry at the boundaries (eg. sector symmetry or half sector symmetries). + void poissonMultiGrid3D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry); + + /// Solve Poisson's Equation by MultiGrid Technique in 2D (assuming cylindrical symmetry) + /// + /// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. + /// So nRRow == 2**M + 1 and nZColumn == 2**N + 1. The number of nRRow and nZColumn can be different. + /// + /// \param matricesV potential in matrix + /// \param matricesCharge charge density in matrix (side effect + /// \param iPhi phi vertex + void poissonMultiGrid2D(DataContainer& matricesV, const DataContainer& matricesCharge, const int iPhi = 0); + + /// Restrict2D + /// + /// Grid transfer operator, restrict from fine -> coarse grid + /// provide full-half weighting + /// + /// \[ \frac{1}{16}\left( \begin{array}{ccc} + /// 1 & 2 & 1 \\ + /// 2 & 4 & 2 \\ + /// 1 & 2 & 1 \end{array} \right) \] + /// + /// \param matricesCurrentCharge coarse grid (2h) + /// \param residue fine grid (h) + /// \param tnRRow number of vertices in r direction of TPC + /// \param tnZColumn number of vertices in z direction of TPC + /// \param iphi phi vertex + void restrict2D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int iphi) const; + + /// Restriction in 3D + /// + /// Restriction is a map from fine grid (h) to coarse grid (2h) + /// + /// In case of 3D + /// Full weighting: + /// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] + /// + /// + /// Restriction in all direction r-phi-z + /// restriction in phi only if oldPhi == 2*newPhi + /// \param matricesCurrentCharge coarser grid 2h + /// \param residue fine grid h + /// \param tnRRow number of grid in Nr (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of grid in Nz (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 + /// \param newPhiSlice number of Nphi (in phi-direction) for coarser grid + /// \param oldPhiSlice number of Nphi (in phi-direction) for finer grid + void restrict3D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const; + + /// Restrict Boundary in 3D + /// + /// Pass boundary information to coarse grid + /// + /// \param matricesCurrentCharge coarser grid 2h + /// \param residue fine grid h + /// \param tnRRow number of grid in Nr (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of grid in Nz (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 + /// \param newPhiSlice number of Nphi (in phi-direction) for coarser grid + /// \param oldPhiSlice number of Nphi (in phi-direction) for finer grid + void restrictBoundary3D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const; + + ///Relaxation operation for multiGrid + /// relaxation used 7 stencil in cylindrical coordinate + /// + /// Using the following equations + /// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ + /// + /// \param matricesCurrentV potential in 3D (matrices of matrix) + /// \param matricesCurrentCharge charge in 3D + /// \param tnRRow number of grid in in r-direction for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of grid in in z-direction for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 + /// \param iPhi phi vertex + /// \param symmetry is the cylinder has symmetry + /// \param h2 \f$ h_{r}^{2} \f$ + /// \param tempRatioZ ration between grid size in z-direction and r-direction + /// \param coefficient1 coefficients for \f$ V_{x+1,y,z} \f$ + /// \param coefficient2 coefficients for \f$ V_{x-1,y,z} \f$ + /// \param coefficient3 coefficients for z + /// \param coefficient4 coefficients for f(r,\phi,z) + void relax3D(Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const int iPhi, const int symmetry, const DataT h2, const DataT tempRatioZ, + const std::vector<DataT>& coefficient1, const std::vector<DataT>& coefficient2, const std::vector<DataT>& coefficient3, const std::vector<DataT>& coefficient4) const; + + /// Relax2D + /// + /// Relaxation operation for multiGrid + /// relaxation used 5 stencil in cylindrical coordinate + /// + /// Using the following equations + /// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ + /// + /// \param matricesCurrentV potential in 3D (matrices of matrix) + /// \param matricesCurrentCharge charge in 3D + /// \param tnRRow number of vertices in r direction of TPC + /// \param tnZColumn number of vertices in z direction of TPC + /// \param h2 \f$ h_{r}^{2} \f$ + /// \param tempFourth coefficient for h + /// \param tempRatio ratio between grid size in z-direction and r-direction + /// \param coefficient1 coefficient for \f$ V_{x+1,y,z} \f$ + /// \param coefficient2 coefficient for \f$ V_{x-1,y,z} \f$ + void relax2D(Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const DataT h2, const DataT tempFourth, const DataT tempRatio, + std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2); + + /// Interpolation/Prolongation in 2D + /// + /// Interpolation is a map from coarse grid (h) to fine grid (2h) + /// + /// In case of 2D + /// Full weighting: + /// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] + /// + /// + /// Restriction in all direction r-phi-z + /// \param matricesCurrentV finer grid h + /// \param matricesCurrentVC coarse grid 2h + /// \param tnRRow number of grid in r-direction for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of grid in z-direction for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 + /// \param iphi phi vertex + void interp2D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int iphi) const; + + /// Interpolation/Prolongation in 3D + /// + /// Interpolation is a map from coarse grid (h) to fine grid (2h) + /// + /// In case of 3D + /// Full weighting: + /// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] + /// + /// + /// Restriction in all direction r-phi-z + /// restriction in phi only if oldPhi == 2*newPhi + /// \param matricesCurrentV finer grid h + /// \param matricesCurrentVC coarse grid 2h + /// \param tnRRow number of vertices in r-direction for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of vertices in z-direction for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 + /// \param newPhiSlice number of vertices in phi-direction for coarser grid + /// \param oldPhiSlice number of vertices in phi-direction for finer grid + void interp3D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const; + + /// Prolongation with Addition for 3D + /// + /// Interpolation with addition from coarse level (2h) --> fine level (h) + /// + /// Interpolation in all direction r-phi-z + /// Interpolation in phi only if oldPhi == 2*newPhi + /// \param matricesCurrentV fine grid h + /// \param matricesCurrentVC coarse grid 2h + /// \param tnRRow number of vertices in r-direction for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of vertices in z-direction for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1a + /// \param newPhiSlice number of vertices in phi-direction for coarser grid + /// \param oldPhiSlice number of vertices in phi-direction for finer grid + void addInterp3D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const; + + /// Prolongation with Addition for 2D + /// + /// Interpolation with addition from coarse level (2h) --> fine level (h) + /// + /// Interpolation in all direction r-phi-z + /// \param matricesCurrentV fine grid h + /// \param matricesCurrentVC coarse grid 2h + /// \param tnRRow number of vertices in r-direction for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 + /// \param tnZColumn number of vertices in z-direction for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1a + /// \param tnPhi phi vertices + void addInterp2D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int tnPhi) const; + + /// VCycle 3D2D, V Cycle 3D in multiGrid with constant Nphi + /// fine-->coarsest-->fine, propagating the residue to correct initial guess of V + /// + /// Algorithm: + /// + /// NOTE: In order for this algorithm to work, the number of Nr and Nz must be a power of 2 plus one. + /// The number of Nr and Z Column can be different. + /// + /// R Row == 2**M + 1 + /// Z Column == 2**N + 1 + /// Phi Slice == Arbitrary but greater than 3 + /// + /// DeltaPhi in Radians + /// \param gridFrom finest level of grid + /// \param gridTo coarsest level of grid + /// \param nPre number of smoothing before coarsening + /// \param nPost number of smoothing after coarsening + /// \param ratioZ ratio between square of grid r and grid z (OPTION, recalculate) + /// \param ratioPhi ratio between square of grid r and grid phi (OPTION, recalculate) + /// \param tvArrayV vector of V potential in different grids + /// \param tvCharge vector of charge distribution in different grids + /// \param tvResidue vector of residue calculation in different grids + /// \param coefficient1 coefficient for relaxation (r direction) + /// \param coefficient2 coefficient for relaxation (r direction) + /// \param coefficient3 coefficient for relaxation (ratio r/z) + /// \param coefficient4 coefficient for relaxation (ratio for grid_r) + /// \param inverseCoefficient4 coefficient for relaxation (inverse coefficient4) + void vCycle3D2D(const int symmetry, const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT ratioZ, const DataT ratioPhi, std::vector<Vector>& tvArrayV, + std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, + std::vector<DataT>& coefficient4, std::vector<DataT>& inverseCoefficient4) const; + + /// VCycle 3D, V Cycle in multiGrid, fine-->coarsest-->fine, propagating the residue to correct initial guess of V + /// + /// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. + /// The number of nRRow and Z Column can be different. + /// + /// R Row == 2**M + 1 + /// Z Column == 2**N + 1 + /// Phi Slice == Arbitrary but greater than 3 + /// + /// DeltaPhi in Radians + /// + /// \param symmetry symmetry or not + /// \param gridFrom finest level of grid + /// \param gridTo coarsest level of grid + /// \param nPre number of smoothing before coarsening + /// \param nPost number of smoothing after coarsening + /// \param ratioZ ratio between square of grid r and grid z (OPTION, recalculate) + /// \param tvArrayV vector of V potential in different grids + /// \param tvCharge vector of charge distribution in different grids + /// \param tvResidue vector of residue calculation in different grids + /// \param coefficient1 coefficient for relaxation (r direction) + /// \param coefficient2 coefficient for relaxation (r direction) + /// \param coefficient3 coefficient for relaxation (ratio r/z) + /// \param coefficient4 coefficient for relaxation (ratio for grid_r) + /// \param inverseCoefficient4 coefficient for relaxation (inverse coefficient4) + void vCycle3D(const int symmetry, const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT ratioZ, std::vector<Vector>& tvArrayV, std::vector<Vector>& tvCharge, + std::vector<Vector>& tvResidue, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, + std::vector<DataT>& coefficient4, std::vector<DataT>& inverseCoefficient4) const; + + /// V-Cycle 2D + /// + /// Implementation non-recursive V-cycle for 2D + /// + /// Algorithms: + /// + /// \param gridFrom finest level of grid + /// \param gridTo coarsest level of grid + /// \param nPre number of smoothing before coarsening + /// \param nPost number of smoothing after coarsening + /// \param gridSizeR grid size in r direction (OPTION, recalculate) + /// \param ratio ratio between square of grid r and grid z (OPTION, recalculate) + /// \param tvArrayV vector of V potential in different grids + /// \param tvCharge vector of charge distribution in different grids + /// \param tvResidue vector of residue calculation in different grids + void vCycle2D(const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT gridSizeR, const DataT ratio, std::vector<Vector>& tvArrayV, + std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue); + + /// W-Cycle 2D + /// + /// Implementation non-recursive W-cycle for 2D + /// + ///Algorithms: + /// + /// \param gridFrom finest level of grid + /// \param gridTo coarsest level of grid + /// \param gamma number of iterations at coarsest level + /// \param nPre number of smoothing before coarsening + /// \param nPost number of smoothing after coarsening + /// \param gridSizeR grid size in r direction (OPTION, recalculate) + /// \param ratio ratio between square of grid r and grid z (OPTION, recalculate) + /// \param tvArrayV vector of V potential in different grids + /// \param tvCharge vector of charge distribution in different grids + /// \param tvResidue vector of residue calculation in different grids + void wCycle2D(const int gridFrom, const int gridTo, const int gamma, const int nPre, const int nPost, const DataT gridSizeR, const DataT ratio, + std::vector<Vector>& tvArrayV, std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue); + + /// Residue3D + /// + /// Compute residue from V(.) where V(.) is numerical potential and f(.). + /// residue used 7 stencil in cylindrical coordinate + /// + /// Using the following equations + /// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ + /// + /// \param residue residue in 3D (matrices of matrix) + /// \param matricesCurrentV potential in 3D (matrices of matrix) + /// \param matricesCurrentCharge charge in 3D + /// \param tnRRow number of vertices in the r direction of TPC + /// \param tnZColumn number of vertices in z direction of TPC + /// \param tnPhi number of vertices in phi direction of TPC + /// \param symmetry if the cylinder has symmetry + /// \param ih2 \f$ 1/ h_{r}^{2} \f$ + /// \param tempRatioZ ration between grid size in z-direction and r-direction + /// \param coefficient1 coefficient for \f$ V_{x+1,y,z} \f$ + /// \param coefficient2 coefficient for \f$ V_{x-1,y,z} \f$ + /// \param coefficient3 coefficient for z + /// \param inverseCoefficient4 inverse coefficient for f(r,\phi,z) + void residue3D(Vector& residue, const Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const int tnPhi, const int symmetry, const DataT ih2, const DataT tempRatioZ, + const std::vector<DataT>& coefficient1, const std::vector<DataT>& coefficient2, const std::vector<DataT>& coefficient3, const std::vector<DataT>& inverseCoefficient4) const; + + /// Residue2D + /// + /// Compute residue from V(.) where V(.) is numerical potential and f(.). + /// residue used 5 stencil in cylindrical coordinate + /// + /// Using the following equations + /// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ + /// + /// \param residue potential in 2D + /// \param matricesCurrentV potential in 2D + /// \param matricesCurrentCharge charge in 2D + /// \param nRRow number of nRRow in the r direction of TPC + /// \param nZColumn number of nZColumn in z direction of TPC + /// \param ih2 \f$ h_{r}^{2} \f$ + /// \param iTempFourth coefficient for h + /// \param tempRatio ratio between grid size in z-direction and r-direction + /// \param coefficient1 coefficient for \f$ V_{x+1,y,z} \f$ + /// \param coefficient2 coefficient for \f$ V_{x-1,y,z} \f$ + void residue2D(Vector& residue, const Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const DataT ih2, const DataT inverseTempFourth, + const DataT tempRatio, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2); + + /// Boundary transfer restrict from fine -> coarse grid + /// + /// \param matricesCurrentCharge coarse grid (2h) + /// \param residue fine grid (h) + /// \param tnRRow number of vertices in the r direction of TPC + /// \param tnZColumn number of vertices in z direction of TPC + /// \param tnPhi phi vertices + void restrictBoundary2D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int tnPhi) const; + + // calculate coefficients + void calcCoefficients(unsigned int from, unsigned int to, const DataT h, const DataT tempRatioZ, const DataT tempRatioPhi, std::vector<DataT>& coefficient1, + std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, std::vector<DataT>& coefficient4) const; + + // calculate coefficients for 2D poisson solver + void calcCoefficients2D(unsigned int from, unsigned int to, const DataT h, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2) const; + + /// Helper function to check if the integer is equal to a power of two + /// \param i the number + /// \return 1 if it is a power of two, else 0 + bool isPowerOfTwo(const int i) const + { + return ((i > 0) && !(i & (i - 1))); + }; +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h new file mode 100644 index 0000000000000..30f19fe02a634 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file O2TPCPoissonSolverHelpers.h +/// \brief This file provides all the necessary structs which are used in the poisson solver +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#ifndef ALICEO2_TPC_POISSONSOLVERHELPERS_H_ +#define ALICEO2_TPC_POISSONSOLVERHELPERS_H_ + +#include "CommonConstants/MathConstants.h" + +namespace o2 +{ +namespace tpc +{ + +///< Enumeration of Cycles Type +enum class CycleType { + VCycle = 0, ///< V Cycle + WCycle = 1, ///< W Cycle (TODO) + FCycle = 2 ///< Full Cycle +}; + +///< Fine -> Coarse Grid transfer operator types +enum class GridTransferType { + Half = 0, ///< Half weighting + Full = 1, ///< Full weighting +}; + +///< Smoothing (Relax) operator types +enum class RelaxType { + Jacobi = 0, ///< Jacobi (5 Stencil 2D, 7 Stencil 3D_ + WeightedJacobi = 1, ///< (TODO) + GaussSeidel = 2 ///< Gauss Seidel 2D (2 Color, 5 Stencil), 3D (7 Stencil) +}; + +struct MGParameters { ///< Parameters choice for MultiGrid algorithm + inline static bool isFull3D = true; ///< TRUE: full coarsening, FALSE: semi coarsening + inline static CycleType cycleType = CycleType::FCycle; ///< cycleType follow CycleType + inline static GridTransferType gtType = GridTransferType::Full; ///< gtType grid transfer type follow GridTransferType + inline static RelaxType relaxType = RelaxType::GaussSeidel; ///< relaxType follow RelaxType + inline static int nPre = 2; ///< number of iteration for pre smoothing + inline static int nPost = 2; ///< number of iteration for post smoothing + inline static int nMGCycle = 200; ///< number of multi grid cycle (V type) + inline static int maxLoop = 7; ///< the number of tree-deep of multi grid + inline static int gamma = 1; ///< number of iteration at coarsest level !TODO SET TO REASONABLE VALUE! +}; + +template <typename DataT = double> +struct TPCParameters { + static constexpr DataT TPCZ0{249.525}; ///< nominal G1T position + static constexpr DataT IFCRADIUS{83.5}; ///< Mean Radius of the Inner Field Cage ( 82.43 min, 83.70 max) (cm) + static constexpr DataT OFCRADIUS{254.5}; ///< Mean Radius of the Outer Field Cage (252.55 min, 256.45 max) (cm) + static constexpr DataT ZOFFSET{0.2}; ///< Offset from CE: calculate all distortions closer to CE as if at this point + static constexpr DataT DVDE{0.0024}; ///< [cm/V] drift velocity dependency on the E field (from Magboltz for NeCO2N2 at standard environment) + static constexpr DataT EM{-1.602176487e-19 / 9.10938215e-31}; ///< charge/mass in [C/kg] + static constexpr DataT E0{8.854187817e-12}; ///< vacuum permittivity [A·s/(V·m)] + inline static DataT cathodev{-103070.0}; ///< Cathode Voltage [V] (for 400 V/cm) + inline static DataT vg1t{-3260}; ///< GEM 1 Top voltage. (setting with reduced ET1,2,4 = 3.5kV/cm) +}; + +template <typename DataT = double> +struct GridProperties { + static constexpr DataT RMIN{TPCParameters<DataT>::IFCRADIUS}; ///< min radius + static constexpr DataT ZMIN{0}; ///< min z coordinate + static constexpr DataT PHIMIN{0}; ///< min phi coordinate + static constexpr DataT RMAX{TPCParameters<DataT>::OFCRADIUS}; ///< max radius + static constexpr DataT ZMAX{TPCParameters<DataT>::TPCZ0}; ///< max z coordinate + static constexpr DataT PHIMAX{static_cast<DataT>(o2::constants::math::TwoPI)}; ///< max phi coordinate + + ///< \return returns grid spacing in r direction + static constexpr DataT getGridSpacingR(const unsigned int nR) { return (RMAX - RMIN) / (nR - 1); } + + ///< \return returns grid spacing in z direction + static constexpr DataT getGridSpacingZ(const unsigned int nZ) { return (ZMAX - ZMIN) / (nZ - 1); } + + ///< \return returns grid spacing in phi direction + static constexpr DataT getGridSpacingPhi(const unsigned int nPhi) { return PHIMAX / nPhi; } +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/RegularGrid3D.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/RegularGrid3D.h new file mode 100644 index 0000000000000..213d96b1f2092 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/RegularGrid3D.h @@ -0,0 +1,247 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RegularGrid3D.h +/// \brief Definition of RegularGrid3D class +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_REGULARGRID3D_H_ +#define ALICEO2_TPC_REGULARGRID3D_H_ + +#include "TPCSpaceCharge/Vector.h" +#include "Rtypes.h" // for ClassDefNV +#include "TPCSpaceCharge/SpaceChargeParameter.h" +#include <vector> + +namespace o2 +{ +namespace tpc +{ + +/// \class RegularGrid3D +/// This class implements basic properties of a regular 3D-Grid like the spacing for each dimension and min and max coordinates. + +/// \tparam DataT the type of data which is used during the calculations +template <typename DataT = double> +struct RegularGrid3D { + + public: + RegularGrid3D(const DataT zmin, const DataT rmin, const DataT phimin, const DataT spacingZ, const DataT spacingR, const DataT spacingPhi) : mMin{{zmin, rmin, phimin}}, mMax{{zmin + (mParamGrid.NZVertices - 1) * spacingZ, rmin + (mParamGrid.NRVertices - 1) * spacingR, phimin + (mParamGrid.NPhiVertices - 1) * spacingPhi}}, mSpacing{{spacingZ, spacingR, spacingPhi}}, mInvSpacing{{static_cast<DataT>(1 / spacingZ), static_cast<DataT>(1 / spacingR), static_cast<DataT>(1 / spacingPhi)}} + { + mRVertices.reserve(mParamGrid.NRVertices); + mPhiVertices.reserve(mParamGrid.NPhiVertices); + mZVertices.reserve(mParamGrid.NZVertices); + initLists(); + } + + /// \param deltaX delta x index + /// \return returns the delta index (where the data is stored) for given deltaX + int getDeltaXDataIndex(const int deltaX) const { return deltaX; } + + /// \param deltaY delta y index + /// \return returns the delta index (where the data is stored) for given deltaY + int getDeltaYDataIndex(const int deltaY) const { return mParamGrid.NZVertices * deltaY; } + + /// \param deltaZ delta z index + /// \return returns the delta index (where the data is stored) for given deltaZ + int getDeltaZDataIndex(const int deltaZ) const { return deltaZ * mParamGrid.NRVertices * mParamGrid.NZVertices; } + + // same as above + /// \param delta delta index + /// \param dim dimension of interest + /// \return returns the delta index (where the data is stored) for given delta and dim + int getDeltaDataIndex(const int delta, const int dim) const; + + // check if the specified index for given dimension lies in the grid + /// \param index query index + /// \return returns if the index lies in the grid + bool isIndexInGrid(const int index, const unsigned int dim) const { return index < 0 ? false : (index > (sNdim[dim] - 1) ? false : true); } + + /// \param dim dimension of interest + /// \return returns the number of vertices for given dimension for the grid + size_t getN(unsigned int dim) const { return sNdim[dim]; } + size_t getNZ() const { return sNdim[FZ]; } + size_t getNR() const { return sNdim[FR]; } + size_t getNPhi() const { return sNdim[FPHI]; } + + static constexpr unsigned int getDim() { return FDIM; } /// \return returns number of dimensions of the grid (3) + static constexpr unsigned int getFZ() { return FZ; } /// \return returns the index for dimension x (0) + static constexpr unsigned int getFR() { return FR; } /// \return returns the index for dimension y (1) + static constexpr unsigned int getFPhi() { return FPHI; } /// \return returns the index for dimension z (2) + + const Vector<DataT, 3>& getGridMin() const { return mMin; } /// \return returns the minimum coordinates of the grid in all dimensions + DataT getGridMinZ() const { return mMin[FZ]; } /// \return returns the minimum coordinate of the grid in x dimension + DataT getGridMinR() const { return mMin[FR]; } /// \return returns the minimum coordinate of the grid in y dimension + DataT getGridMinPhi() const { return mMin[FPHI]; } /// \return returns the minimum coordinate of the grid in z dimension + + DataT getGridMaxZ() const { return mMax[FZ]; } + DataT getGridMaxR() const { return mMax[FR]; } + DataT getGridMaxPhi() const { return mMax[FPHI]; } + + /// \return returns the inversed spacing of the grid for all dimensions + const Vector<DataT, 3>& getInvSpacing() const { return mInvSpacing; } + DataT getInvSpacingZ() const { return mInvSpacing[FZ]; } + DataT getInvSpacingR() const { return mInvSpacing[FR]; } + DataT getInvSpacingPhi() const { return mInvSpacing[FPHI]; } + + DataT getSpacingZ() const { return mSpacing[FZ]; } + DataT getSpacingR() const { return mSpacing[FR]; } + DataT getSpacingPhi() const { return mSpacing[FPHI]; } + + // clamp coordinates to the grid (not circular) + /// \param pos query position which will be clamped + /// \return returns clamped coordinate coordinate + DataT clampToGrid(const DataT pos, const unsigned int dim) const; + + // clamp coordinates to the grid (not circular) + /// \param pos relative query position in grid which will be clamped + /// \return returns clamped coordinate coordinate + DataT clampToGridRel(const DataT pos, const unsigned int dim) const; + + // clamp coordinates to the grid circular + /// \param pos query position which will be clamped + /// \return returns clamped coordinate coordinate + DataT clampToGridCircular(DataT pos, const unsigned int dim) const; + + // clamp coordinates to the grid circular + /// \param pos relative query position in grid which will be clamped + /// \return returns clamped coordinate coordinate + DataT clampToGridCircularRel(DataT pos, const unsigned int dim) const; + + /// \param vertexX in x dimension + /// \return returns the x positon for given vertex + DataT getZVertex(const size_t vertexX) const { return mZVertices[vertexX]; } + + /// \param vertexY in y dimension + /// \return returns the y positon for given vertex + DataT getRVertex(const size_t vertexY) const { return mRVertices[vertexY]; } + + /// \param vertexZ in z dimension + /// \return returns the z positon for given vertex + DataT getPhiVertex(const size_t vertexZ) const { return mPhiVertices[vertexZ]; } + + const Vector<DataT, 3>& getMaxIndices() const { return sMaxIndex; } /// get max indices for all dimensions + + DataT getMaxIndexZ() const { return sMaxIndex[0]; } /// get max index in x direction + DataT getMaxIndexR() const { return sMaxIndex[1]; } /// get max index in y direction + DataT getMaxIndexPhi() const { return sMaxIndex[2]; } /// get max index in z direction + + private: + inline static auto& mParamGrid = ParameterSpaceCharge::Instance(); + static constexpr unsigned int FDIM = 3; ///< dimensions of the grid (only 3 supported) + static constexpr unsigned int FZ = 0; ///< index for x coordinate + static constexpr unsigned int FR = 1; ///< index for y coordinate + static constexpr unsigned int FPHI = 2; ///< index for z coordinate + const Vector<DataT, FDIM> mMin{}; ///< min vertices positions of the grid + const Vector<DataT, FDIM> mMax{}; ///< max vertices positions of the grid + const Vector<DataT, FDIM> mSpacing{}; ///< spacing of the grid + const Vector<DataT, FDIM> mInvSpacing{}; ///< inverse spacing of grid + const Vector<DataT, FDIM> sMaxIndex{{static_cast<DataT>(mParamGrid.NZVertices - 1.), static_cast<DataT>(mParamGrid.NRVertices - 1), static_cast<DataT>(mParamGrid.NPhiVertices - 1)}}; ///< max index which is on the grid in all dimensions + const Vector<int, FDIM> sNdim{{static_cast<int>(mParamGrid.NZVertices), static_cast<int>(mParamGrid.NRVertices), static_cast<int>(mParamGrid.NPhiVertices)}}; ///< number of vertices for each dimension + std::vector<DataT> mZVertices{}; ///< positions of vertices in x direction + std::vector<DataT> mRVertices{}; ///< positions of vertices in y direction + std::vector<DataT> mPhiVertices{}; ///< positions of vertices in z direction + + void initLists(); + + ClassDefNV(RegularGrid3D, 1) +}; + +/// +/// ======================================================================================================== +/// Inline implementations of some methods +/// ======================================================================================================== +/// + +template <typename DataT> +DataT RegularGrid3D<DataT>::clampToGrid(const DataT pos, const unsigned int dim) const +{ + if (mMin[dim] < mMax[dim]) { + if (pos < mMin[dim]) { + return mMin[dim]; + } else if (pos > mMax[dim]) { + return mMax[dim]; + } + } else { + if (pos > mMin[dim]) { + return mMin[dim]; + } else if (pos < mMax[dim]) { + return mMax[dim]; + } + } + return pos; +} + +template <typename DataT> +DataT RegularGrid3D<DataT>::clampToGridRel(const DataT pos, const unsigned int dim) const +{ + if (pos < 0) { + return 0; + } else if (pos >= sMaxIndex[dim]) { + return sMaxIndex[dim] - 1; // -1 return second last index. otherwise two additional points have to be extrapolated for tricubic interpolation + } + return pos; +} + +template <typename DataT> +DataT RegularGrid3D<DataT>::clampToGridCircular(DataT pos, const unsigned int dim) const +{ + while (pos < mMin[dim]) { + pos += mMax[dim] - mMin[dim] + mSpacing[dim]; + } + while (pos >= mMax[dim] + mSpacing[dim]) { + pos -= mMax[dim] + mSpacing[dim] - mMin[dim]; + } + return pos; +} + +template <typename DataT> +DataT RegularGrid3D<DataT>::clampToGridCircularRel(DataT pos, const unsigned int dim) const +{ + while (pos < 0) { + pos += sNdim[dim]; + } + while (pos > sNdim[dim]) { + pos -= sNdim[dim]; + } + if (pos == sNdim[dim]) { + pos = 0; + } + return pos; +} + +template <typename DataT> +void RegularGrid3D<DataT>::initLists() +{ + for (size_t i = 0; i < mParamGrid.NZVertices; ++i) { + mZVertices.emplace_back(mMin[FZ] + i * mSpacing[FZ]); + } + for (size_t i = 0; i < mParamGrid.NRVertices; ++i) { + mRVertices.emplace_back(mMin[FR] + i * mSpacing[FR]); + } + for (size_t i = 0; i < mParamGrid.NPhiVertices; ++i) { + mPhiVertices.emplace_back(mMin[FPHI] + i * mSpacing[FPHI]); + } +} + +template <typename DataT> +int RegularGrid3D<DataT>::getDeltaDataIndex(const int delta, const int dim) const +{ + const int offset[FDIM]{1, mParamGrid.NZVertices, mParamGrid.NRVertices * mParamGrid.NZVertices}; + const int deltaIndex = delta * offset[dim]; + return deltaIndex; +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h new file mode 100644 index 0000000000000..cfc8e83a32d43 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h @@ -0,0 +1,1058 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SpaceCharge.h +/// \brief This class contains the algorithms for calculation the distortions and corrections +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#ifndef ALICEO2_TPC_SPACECHARGE_H_ +#define ALICEO2_TPC_SPACECHARGE_H_ + +#include "TPCSpaceCharge/TriCubic.h" +#include "TPCSpaceCharge/SpaceChargeHelpers.h" +#include "TPCSpaceCharge/PoissonSolverHelpers.h" +#include "TPCSpaceCharge/RegularGrid3D.h" +#include "TPCSpaceCharge/DataContainer3D.h" +#include "TPCSpaceCharge/SpaceChargeParameter.h" +#include "DataFormatsTPC/Defs.h" + +class TH3; +class TH3D; +class TH3F; +class TH2F; + +namespace o2 +{ +namespace tpc +{ + +template <class T> +class CalDet; + +/// \class SpaceCharge +/// this class provides the algorithms for calculating the global distortions and corrections from the space charge density. +/// The calculations can be done by a realistic space charge histogram as an input or by an analytical formula. +/// An example of of the usage can be found in 'macro/calculateDistortionsCorrections.C' + +/// \tparam DataT the data type which is used during the calculations +/// \tparam Nz number of vertices in z direction +/// \tparam Nr number of vertices in r direction +/// \tparam Nphi number of vertices in phi direction +template <typename DataT = double> +class SpaceCharge +{ + using RegularGrid = RegularGrid3D<DataT>; + using DataContainer = DataContainer3D<DataT>; + using GridProp = GridProperties<DataT>; + using TriCubic = TriCubicInterpolator<DataT>; + using TH3DataT = std::conditional_t<std::is_same<DataT, double>::value, TH3D, TH3F>; // datatype for TH3 (TH3F for DataT==float and TH3D for DataT==double) + + public: + /// default constructor + /// grid granularity has to set before constructing an object using the static function setGrid(nZVertices, nRVertices, nPhiVertices)! + /// \param omegaTau \omega \tau value + /// \param t1 value for t1 + /// \param t2 value for t2 + SpaceCharge(const DataT omegaTau = 0.32f, const DataT t1 = 1, const DataT t2 = 1) { setOmegaTauT1T2(omegaTau, t1, t2); }; + + /// \param nZVertices number of vertices of the grid in z direction + /// \param nRVertices number of vertices of the grid in z direction + /// \param nPhiVertices number of vertices of the grid in z direction + static void setGrid(const unsigned short nZVertices, const unsigned short nRVertices, const unsigned short nPhiVertices); + + /// Enumerator for setting the space-charge distortion mode + enum class SCDistortionType : int { + SCDistortionsConstant = 0, // space-charge distortions constant over time + SCDistortionsRealistic = 1 // realistic evolution of space-charge distortions over time + }; + + /// numerical integration strategys + enum class IntegrationStrategy { Trapezoidal = 0, ///< trapezoidal integration (https://en.wikipedia.org/wiki/Trapezoidal_rule). straight electron drift line assumed: z0->z1, r0->r0, phi0->phi0 + Simpson = 1, ///< simpon integration. see: https://en.wikipedia.org/wiki/Simpson%27s_rule. straight electron drift line assumed: z0->z1, r0->r0, phi0->phi0 + Root = 2, ///< Root integration. straight electron drift line assumed: z0->z1, r0->r0, phi0->phi0 + SimpsonIterative = 3 ///< simpon integration, but using an iterative method to approximate the drift path. No straight electron drift line assumed: z0->z1, r0->r1, phi0->phi1 + }; + + enum class Type { + Distortions = 0, ///< distortions + Corrections = 1 ///< corrections + }; + + enum class GlobalDistType { + Standard = 0, ///< classical method (start calculation of global distortion at each voxel in the tpc and follow electron drift to readout -slow-) + Fast = 1, ///< interpolation of global corrections (use the global corrections to apply an iterative approach to obtain the global distortions -fast-) + None = 2 ///< dont calculate global distortions + }; + + enum class GlobalDistCorrMethod { + LocalDistCorr, ///< using local dis/corr interpolator for calculation of global distortions/corrections + ElectricalField ///< using electric field for calculation of global distortions/corrections + }; + + /// step 0: set the charge density from TH3 histogram containing the space charge density + /// \param hisSCDensity3D histogram for the space charge density + void fillChargeDensityFromHisto(const TH3& hisSCDensity3D); + + /// step 0: set the space charge density from std::vector<CalDet> containing the space charge density. Each entry in the object corresponds to one z slice + /// \param calSCDensity3D histogram for the space charge density + void fillChargeDensityFromCalDet(const std::vector<CalDet<float>>& calSCDensity3D); + + /// step 0: set the charge (number of ions) from std::vector<CalDet> containing the charge. Each entry in the object corresponds to one z slice. + /// Normalization to the space charge is also done automatically + /// \param calCharge3D histogram for the charge + void fillChargeFromCalDet(const std::vector<CalDet<float>>& calCharge3D); + + /// step 0: set the charge density from TH3 histogram containing the space charge density + /// \param fInp input file containing a histogram for the space charge density + /// \param name the name of the space charge density histogram in the file + void fillChargeDensityFromFile(TFile& fInp, const char* name); + + /// \param side side of the TPC + /// \param calcVectors set to calculate also the local distortion and local correction vectors + void calculateDistortionsCorrections(const o2::tpc::Side side, const bool calcVectors = false); + + /// step 0: this function fills the internal storage for the charge density using an analytical formula + /// \param formulaStruct struct containing a method to evaluate the density + void setChargeDensityFromFormula(const AnalyticalFields<DataT>& formulaStruct); + + /// step 0: this function fills the boundary of the potential using an analytical formula. The boundary is used in the PoissonSolver. + /// \param formulaStruct struct containing a method to evaluate the potential + void setPotentialBoundaryFromFormula(const AnalyticalFields<DataT>& formulaStruct); + + /// step 0: this function fills the potential using an analytical formula + /// \param formulaStruct struct containing a method to evaluate the potential + void setPotentialFromFormula(const AnalyticalFields<DataT>& formulaStruct); + + /// step 1: use the O2TPCPoissonSolver class to numerically calculate the potential with set space charge density and boundary conditions from potential + /// \param side side of the TPC + /// \param maxIteration maximum number of iterations used in the poisson solver + /// \param stoppingConvergence stopping criterion used in the poisson solver + /// \param symmetry use symmetry or not in the poisson solver + void poissonSolver(const Side side, const int maxIteration = 300, const DataT stoppingConvergence = 1e-6, const int symmetry = 0); + + /// step 2: calculate numerically the electric field from the potential + /// \param side side of the TPC + void calcEField(const Side side); + + /// step 2a: set the electric field from an analytical formula + /// \param formulaStruct struct containing a method to evaluate the electric fields + void setEFieldFromFormula(const AnalyticalFields<DataT>& formulaStruct); + + /// step 3: calculate the local distortions and corrections with an electric field + /// \param type calculate local corrections or local distortions: type = o2::tpc::SpaceCharge<>::Type::Distortions or o2::tpc::SpaceCharge<>::Type::Corrections + /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi (analytical formula or by TriCubic interpolator) + template <typename ElectricFields = AnalyticalFields<DataT>> + void calcLocalDistortionsCorrections(const Type type, const ElectricFields& formulaStruct); + + /// step 3b: calculate the local distortion and correction vectors with an electric field + /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi (analytical formula or by TriCubic interpolator) + template <typename ElectricFields = AnalyticalFields<DataT>> + void calcLocalDistortionCorrectionVector(const ElectricFields& formulaStruct); + + /// step 3b: calculate the local distortions and corrections with the local distortion/correction vectors using Runge Kutta 4. + /// calcLocalDistortionCorrectionVector() has to be called before this function + /// \param type calculate local corrections or local distortions: type = o2::tpc::SpaceCharge<>::Type::Distortions or o2::tpc::SpaceCharge<>::Type::Corrections + /// \param side side of the TPC + template <typename ElectricFields = AnalyticalFields<DataT>> + void calcLocalDistortionsCorrectionsRK4(const Type type, const Side side); + + /// step 4: calculate global corrections by using the electric field or the local corrections + /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi or the local corrections + template <typename Fields = AnalyticalFields<DataT>> + void calcGlobalCorrections(const Fields& formulaStruct); + + /// step 5: calculate global distortions by using the electric field or the local distortions (SLOW) + /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi or the local distortions + template <typename Fields = AnalyticalFields<DataT>> + void calcGlobalDistortions(const Fields& formulaStruct); + + void init(); + + /// step 5: calculate global distortions using the global corrections (FAST) + /// \param globCorr interpolator for global corrections + /// \param maxIter maximum iterations per global distortion + /// \param approachZ when the difference between the desired z coordinate and the position of the global correction is deltaZ, approach the desired z coordinate by deltaZ * \p approachZ. + /// \param approachR when the difference between the desired r coordinate and the position of the global correction is deltaR, approach the desired r coordinate by deltaR * \p approachR. + /// \param approachPhi when the difference between the desired phi coordinate and the position of the global correction is deltaPhi, approach the desired phi coordinate by deltaPhi * \p approachPhi. + /// \param diffCorr if the absolute differences from the interpolated values for the global corrections from the last iteration compared to the current iteration is smaller than this value, set converged to true for current global distortion + void calcGlobalDistWithGlobalCorrIterative(const DistCorrInterpolator<DataT>& globCorr, const int maxIter = 100, const DataT approachZ = 0.5, const DataT approachR = 0.5, const DataT approachPhi = 0.5, const DataT diffCorr = 1e-6); + + /// \return returns number of vertices in z direction + unsigned short getNZVertices() { return mParamGrid.NZVertices; } + + /// \return returns number of vertices in r direction + unsigned short getNRVertices() { return mParamGrid.NRVertices; } + + /// \return returns number of vertices in phi direction + unsigned short getNPhiVertices() { return mParamGrid.NPhiVertices; } + + /// get the space charge density for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + DataT getDensityCyl(const DataT z, const DataT r, const DataT phi, const Side side) const; + + /// get the potential for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + DataT getPotentialCyl(const DataT z, const DataT r, const DataT phi, const Side side) const; + + /// get the electric field for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param eZ returns correction in z direction + /// \param eR returns correction in r direction + /// \param ePhi returns correction in phi direction + void getElectricFieldsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& eZ, DataT& eR, DataT& ePhi) const; + + /// get the local correction for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param lcorrZ returns local correction in z direction + /// \param lcorrR returns local correction in r direction + /// \param lcorrRPhi returns local correction in rphi direction + void getLocalCorrectionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lcorrZ, DataT& lcorrR, DataT& lcorrRPhi) const; + + /// get the global correction for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param corrZ returns correction in z direction + /// \param corrR returns correction in r direction + /// \param corrRPhi returns correction in rphi direction + void getCorrectionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& corrZ, DataT& corrR, DataT& corrRPhi) const; + + /// get the global corrections for given coordinate + /// \param x global x coordinate + /// \param y global y coordinate + /// \param z global z coordinate + /// \param corrX returns corrections in x direction + /// \param corrY returns corrections in y direction + /// \param corrZ returns corrections in z direction + void getCorrections(const DataT x, const DataT y, const DataT z, const Side side, DataT& corrX, DataT& corrY, DataT& corrZ) const; + + /// get the local distortions for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param ldistZ returns local distortion in z direction + /// \param ldistR returns local distortion in r direction + /// \param ldistRPhi returns local distortion in rphi direction + void getLocalDistortionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& ldistZ, DataT& ldistR, DataT& ldistRPhi) const; + + /// get the local distortion vector for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param lvecdistZ returns local distortion vector in z direction + /// \param lvecdistR returns local distortion vector in r direction + /// \param lvecdistRPhi returns local distortion vector in rphi direction + void getLocalDistortionVectorCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lvecdistZ, DataT& lvecdistR, DataT& lvecdistRPhi) const; + + /// get the local correction vector for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param ldistZ returns local correction vector in z direction + /// \param ldistR returns local correction vector in r direction + /// \param ldistRPhi returns local correction vector in rphi direction + void getLocalCorrectionVectorCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lveccorrZ, DataT& lveccorrR, DataT& lveccorrRPhi) const; + + /// get the global distortions for given coordinate + /// \param z global z coordinate + /// \param r global r coordinate + /// \param phi global phi coordinate + /// \param distZ returns distortion in z direction + /// \param distR returns distortion in r direction + /// \param distRPhi returns distortion in rphi direction + void getDistortionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& distZ, DataT& distR, DataT& distRPhi) const; + + /// get the global distortions for given coordinate + /// \param x global x coordinate + /// \param y global y coordinate + /// \param z global z coordinate + /// \param distX returns distortion in x direction + /// \param distY returns distortion in y direction + /// \param distZ returns distortion in z direction + void getDistortions(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ) const; + + /// convert x and y coordinates from cartesian to the radius in polar coordinates + static DataT getRadiusFromCartesian(const DataT x, const DataT y) { return std::sqrt(x * x + y * y); } + + /// convert x and y coordinates from cartesian to phi in polar coordinates + static DataT getPhiFromCartesian(const DataT x, const DataT y) { return std::atan2(y, x); } + + /// convert radius and phi coordinates from polar coordinates to x cartesian coordinates + static DataT getXFromPolar(const DataT r, const DataT phi) { return r * std::cos(phi); } + + /// convert radius and phi coordinates from polar coordinates to y cartesian coordinate + static DataT getYFromPolar(const DataT r, const DataT phi) { return r * std::sin(phi); } + + /// Correct electron position using correction lookup tables + /// \param point 3D coordinates of the electron + void correctElectron(GlobalPosition3D& point); + + /// Distort electron position using distortion lookup tables + /// \param point 3D coordinates of the electron + void distortElectron(GlobalPosition3D& point) const; + + /// set the distortions directly from a look up table + /// \param distdZ distortions in z direction + /// \param distdR distortions in r direction + /// \param distdRPhi distortions in rphi direction + /// \param side side of the TPC + void setDistortionLookupTables(const DataContainer& distdZ, const DataContainer& distdR, const DataContainer& distdRPhi, const Side side); + + /// set the density, potential, electric fields, local distortions/corrections, global distortions/corrections from a file. Missing objects in the file are ignored. + /// \file file containing the stored values for the density, potential, electric fields, local distortions/corrections, global distortions/corrections + /// \param side side of the TPC + void setFromFile(TFile& file, const Side side); + + /// Get grid spacing in r direction + DataT getGridSpacingR(const Side side) const { return mGrid3D[side].getSpacingR(); } + + /// Get grid spacing in z direction + DataT getGridSpacingZ(const Side side) const { return mGrid3D[side].getSpacingZ(); } + + /// Get grid spacing in phi direction + DataT getGridSpacingPhi(const Side side) const { return mGrid3D[side].getSpacingPhi(); } + + /// Get constant electric field + static constexpr DataT getEzField(const Side side) { return getSign(side) * (TPCParameters<DataT>::cathodev - TPCParameters<DataT>::vg1t) / TPCParameters<DataT>::TPCZ0; } + + /// Get inner radius of tpc + DataT getRMin(const Side side) const { return mGrid3D[side].getGridMinR(); } + + /// Get min z position which is used during the calaculations + DataT getZMin(const Side side) const { return mGrid3D[side].getGridMinZ(); } + + /// Get min phi + DataT getPhiMin(const Side side) const { return mGrid3D[side].getGridMinPhi(); } + + /// Get max r + DataT getRMax(const Side side) const { return mGrid3D[side].getGridMaxR(); }; + + /// Get max z + DataT getZMax(const Side side) const { return mGrid3D[side].getGridMaxZ(); } + + /// Get max phi + DataT getPhiMax(const Side side) const { return mGrid3D[side].getGridMaxPhi(); } + + // get side of TPC for z coordinate TODO rewrite this + static Side getSide(const DataT z) { return ((z >= 0) ? Side::A : Side::C); } + + /// Get the grid object + const RegularGrid& getGrid3D(const Side side) const { return mGrid3D[side]; } + + /// Get struct containing interpolators for the electrical fields + /// \param side side of the TPC + NumericalFields<DataT> getElectricFieldsInterpolator(const Side side) const; + + /// Get struct containing interpolators for local distortions dR, dZ, dPhi + /// \param side side of the TPC + DistCorrInterpolator<DataT> getLocalDistInterpolator(const Side side) const; + + /// Get struct containing interpolators for local corrections dR, dZ, dPhi + /// \param side side of the TPC + DistCorrInterpolator<DataT> getLocalCorrInterpolator(const Side side) const; + + /// Get struct containing interpolators for global distortions dR, dZ, dPhi + /// \param side side of the TPC + DistCorrInterpolator<DataT> getGlobalDistInterpolator(const Side side) const; + + /// Get struct containing interpolators for global corrections dR, dZ, dPhi + /// \param side side of the TPC + DistCorrInterpolator<DataT> getGlobalCorrInterpolator(const Side side) const; + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion dR for given vertex + DataT getLocalDistR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalDistdR[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion dZ for given vertex + DataT getLocalDistZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalDistdZ[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion dRPhi for given vertex + DataT getLocalDistRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalDistdRPhi[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion vector dR for given vertex + DataT getLocalVecDistR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalVecDistdR[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion vector dZ for given vertex + DataT getLocalVecDistZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalVecDistdZ[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local distortion vector dRPhi for given vertex + DataT getLocalVecDistRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalVecDistdRPhi[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction dR for given vertex + DataT getLocalCorrR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalCorrdR[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction dZ for given vertex + DataT getLocalCorrZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalCorrdZ[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction dRPhi for given vertex + DataT getLocalCorrRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mLocalCorrdRPhi[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction vector dR for given vertex + DataT getLocalVecCorrR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return -mLocalVecDistdR[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction vector dZ for given vertex + DataT getLocalVecCorrZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return -mLocalVecDistdZ[side](iz, ir, iphi); } + + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + /// \return returns local correction vector dRPhi for given vertex + DataT getLocalVecCorrRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return -mLocalVecDistdRPhi[side](iz, ir, iphi); } + + /// Get global distortion dR for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalDistR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalDistdR[side](iz, ir, iphi); } + + /// Get global distortion dZ for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalDistZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalDistdZ[side](iz, ir, iphi); } + + /// Get global distortion dRPhi for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalDistRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalDistdRPhi[side](iz, ir, iphi); } + + /// Get global correction dR for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalCorrR(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalCorrdR[side](iz, ir, iphi); } + + /// Get global correction dZ for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalCorrZ(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalCorrdZ[side](iz, ir, iphi); } + + /// Get global correction dRPhi for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getGlobalCorrRPhi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mGlobalCorrdRPhi[side](iz, ir, iphi); } + + /// Get global electric Field Er for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getEr(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mElectricFieldEr[side](iz, ir, iphi); } + + /// Get global electric Field Ez for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getEz(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mElectricFieldEz[side](iz, ir, iphi); } + + /// Get global electric Field Ephi for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getEphi(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mElectricFieldEphi[side](iz, ir, iphi); } + + /// Get density for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getDensity(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mDensity[side](iz, ir, iphi); } + + /// Get potential for vertex + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \param side side of the TPC + DataT getPotential(const size_t iz, const size_t ir, const size_t iphi, const Side side) const { return mPotential[side](iz, ir, iphi); } + + /// Get the step width which is used for the calculation of the correction/distortions in units of the z-bin + static int getStepWidth() { return 1 / sSteps; } + + /// Get phi vertex position for index in phi direction + /// \param indexPhi index in phi direction + DataT getPhiVertex(const size_t indexPhi, const Side side) const { return mGrid3D[side].getPhiVertex(indexPhi); } + + /// Get r vertex position for index in r direction + /// \param indexR index in r direction + DataT getRVertex(const size_t indexR, const Side side) const { return mGrid3D[side].getRVertex(indexR); } + + /// Get z vertex position for index in z direction + /// \param indexZ index in z direction + DataT getZVertex(const size_t indexZ, const Side side) const { return mGrid3D[side].getZVertex(indexZ); } + + /// \param omegaTau \omega \tau value + /// \param t1 value for t1 see: ??? + /// \param t2 value for t2 see: ??? + void setOmegaTauT1T2(const DataT omegaTau = 0.32f, const DataT t1 = 1, const DataT t2 = 1) + { + const DataT wt0 = t2 * omegaTau; + mC0 = 1 / (1 + wt0 * wt0); + const DataT wt1 = t1 * omegaTau; + mC1 = wt1 / (1 + wt1 * wt1); + }; + + /// \param c0 coefficient C0 (compare Jim Thomas's notes for definitions) + /// \param c1 coefficient C1 (compare Jim Thomas's notes for definitions) + void setC0C1(const DataT c0, const DataT c1) + { + mC0 = c0; + mC1 = c1; + } + + /// set number of steps used for calculation of distortions/corrections per z bin + /// \param nSteps number of steps per z bin + static void setNStep(const int nSteps) { sSteps = nSteps; } + + static int getNStep() { return sSteps; } + + /// get the number of threads used for some of the calculations + static int getNThreads() { return sNThreads; } + + /// set the number of threads used for some of the calculations + static void setNThreads(const int nThreads) + { + sNThreads = nThreads; + TriCubic::setNThreads(nThreads); + } + + /// set which kind of numerical integration is used for calcution of the integrals int Er/Ez dz, int Ephi/Ez dz, int Ez dz + /// \param strategy numerical integration strategy. see enum IntegrationStrategy for the different types + static void setNumericalIntegrationStrategy(const IntegrationStrategy strategy) { sNumericalIntegrationStrategy = strategy; } + static IntegrationStrategy getNumericalIntegrationStrategy() { return sNumericalIntegrationStrategy; } + + static void setGlobalDistType(const GlobalDistType globalDistType) { sGlobalDistType = globalDistType; } + static GlobalDistType getGlobalDistType() { return sGlobalDistType; } + + static void setGlobalDistCorrMethod(const GlobalDistCorrMethod globalDistCorrMethod) { sGlobalDistCorrCalcMethod = globalDistCorrMethod; } + static GlobalDistCorrMethod getGlobalDistCorrMethod() { return sGlobalDistCorrCalcMethod; } + + static void setSimpsonNIteratives(const int nIter) { sSimpsonNIteratives = nIter; } + static int getSimpsonNIteratives() { return sSimpsonNIteratives; } + + /// Set the space-charge distortions model + /// \param distortionType distortion type (constant or realistic) + static void setSCDistortionType(SCDistortionType distortionType) { sSCDistortionType = distortionType; } + /// Get the space-charge distortions model + static SCDistortionType getSCDistortionType() { return sSCDistortionType; } + + void setUseInitialSCDensity(const bool useInitialSCDensity) { mUseInitialSCDensity = useInitialSCDensity; } + + /// write all fields etc to a file + /// \param outf output file + /// \side side of the TPC + void dumpToFile(TFile& outf, const Side side) const; + + /// dump sc density, potential, electric fields, global distortions/corrections to tree + /// \param outFileName name of the output file + /// \side side of the TPC + /// \param nZPoints number of vertices of the output in z + /// \param nRPoints number of vertices of the output in r + /// \param nPhiPoints number of vertices of the output in phi + void dumpToTree(const char* outFileName, const Side side, const int nZPoints = 50, const int nRPoints = 150, const int nPhiPoints = 180) const; + + /// write electric fields to root file + /// \param outf output file where the electrical fields will be written to + /// \side side of the TPC + int dumpElectricFields(TFile& outf, const Side side) const; + + /// set electric field from root file + /// \param inpf input file where the electrical fields are stored + /// \side side of the TPC + void setElectricFieldsFromFile(TFile& inpf, const Side side); + + /// write potential to root file + /// \param outf output file where the potential will be written to + /// \side side of the TPC + int dumpPotential(TFile& outf, const Side side) const { return mPotential[side].writeToFile(outf, Form("potential_side%s", getSideName(side).data())); } + + /// set potential from root file + /// \param inpf input file where the potential is stored + /// \side side of the TPC + void setPotentialFromFile(TFile& inpf, const Side side) { mPotential[side].initFromFile(inpf, Form("potential_side%s", getSideName(side).data())); } + + /// set the potential directly + /// \param potential potential which will be set + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \side side of the TPC + void fillPotential(const DataT potential, const size_t iz, const size_t ir, const size_t iphi, const Side side) { mPotential[side](iz, ir, iphi) = potential; } + + /// write density to root file + /// \param outf output file where the charge density will be written to + /// \side side of the TPC + int dumpDensity(TFile& outf, const Side side) const { return mDensity[side].writeToFile(outf, Form("density_side%s", getSideName(side).data())); } + + /// set density from root file + /// \param inpf input file where the charge density is stored + /// \side side of the TPC + void setDensityFromFile(TFile& inpf, const Side side) + { + mDensity[side].initFromFile(inpf, Form("density_side%s", getSideName(side).data())); + setDensityFilled(side); + } + + /// set the space charge density directly + /// \param density space charege density which will be set + /// \param iz vertex in z dimension + /// \param ir vertex in r dimension + /// \param iphi vertex in phi dimension + /// \side side of the TPC + void fillDensity(const DataT density, const size_t iz, const size_t ir, const size_t iphi, const Side side) { mDensity[side](iz, ir, iphi) = density; } + + /// set the status of the density as filled + /// \side side of the TPC + void setDensityFilled(const Side side) { mIsChargeSet[side] = true; } + + /// write global distortions to root file + /// \param outf output file where the global distortions will be written to + /// \side side of the TPC + int dumpGlobalDistortions(TFile& outf, const Side side) const; + + /// set global distortions from root file + /// \param inpf input file where the global distortions are stored + /// \side side of the TPC + void setGlobalDistortionsFromFile(TFile& inpf, const Side side); + + /// write global corrections to root file + /// \param outf output file where the global corrections will be written to + /// \side side of the TPC + int dumpGlobalCorrections(TFile& outf, const Side side) const; + + /// set global corrections from root file + /// \param inpf input file where the global corrections are stored + /// \side side of the TPC + void setGlobalCorrectionsFromFile(TFile& inpf, const Side side); + + /// write local corrections to root file + /// \param outf output file where the local corrections will be written to + /// \side side of the TPC + int dumpLocalCorrections(TFile& outf, const Side side) const; + + /// set local corrections from root file + /// \param inpf input file where the local corrections are stored + /// \side side of the TPC + void setLocalCorrectionsFromFile(TFile& inpf, const Side side); + + /// write local distortions to root file + /// \param outf output file where the local distortions will be written to + /// \side side of the TPC + int dumpLocalDistortions(TFile& outf, const Side side) const; + + /// write local distortion vector to root file + /// \param outf output file where the local distortions will be written to + /// \side side of the TPC + int dumpLocalDistCorrVectors(TFile& outf, const Side side) const; + + /// set local distortions from root file + /// \param inpf input file where the local distortions are stored + /// \side side of the TPC + void setLocalDistortionsFromFile(TFile& inpf, const Side side); + + /// set local distortion vector from root file + /// \param inpf input file where the local distortions are stored + /// \side side of the TPC + void setLocalDistCorrVectorsFromFile(TFile& inpf, const Side side); + + /// set z coordinate between min z max z + /// \param posZ z position which will be regulated if needed + DataT regulateZ(const DataT posZ, const Side side) const { return mGrid3D[side].clampToGrid(posZ, 0); } + + /// set r coordinate between 'RMIN - 4 * GRIDSPACINGR' and 'RMAX + 2 * GRIDSPACINGR'. the r coordinate is not clamped to RMIN and RMAX to ensure correct interpolation at the borders of the grid. + DataT regulateR(const DataT posR, const Side side) const; + + /// set phi coordinate between min phi max phi + DataT regulatePhi(const DataT posPhi, const Side side) const { return mGrid3D[side].clampToGridCircular(posPhi, 2); } + + /// rebin the input space charge density histogram to desired binning + /// \param hOrig original histogram + /// \param nBinsZNew number of z bins of rebinned histogram + /// \param nBinsRNew number of r bins of rebinned histogram + /// \param nBinsPhiNew number of phi bins of rebinned histogram + static TH3DataT rebinDensityHisto(const TH3& hOrig, const unsigned short nBinsZNew, const unsigned short nBinsRNew, const unsigned short nBinsPhiNew); + + /// function to calculate the drift paths of the electron whose starting position is delivered. Electric fields must be set! + /// \param elePos global position of the start position of the electron + /// \param nSamplingPoints number of output points of the electron drift path + /// \return returns the input electron a vector of 3D-points describing the drift path of the electron + void calculateElectronDriftPath(const std::vector<GlobalPosition3D>& elePos, const int nSamplingPoints, const char* outFile = "electron_tracks.root") const; + + /// \param inpFile input file containing the electron tracks tree, which is the output file of calculateElectronDriftPath() + /// \param hBorder histogram which defines the borders for the drawing and also the axis titles + /// \param type setting dimensions: type=0: radius vs z, type=0: radius vs phi + /// \param gifSpeed speed of the output gif file (fastest is 2, slowest is 99) + /// \param maxsamplingpoints maximum number of frames which will be drawn (higher number increases processing time) + /// \param outName name of the output file + static void makeElectronDriftPathGif(const char* inpFile, TH2F& hBorder, const int type = 0, const int gifSpeed = 2, const int maxsamplingpoints = 100, const char* outName = "electron_drift_path"); + + /// normalize a histogram containing the charge to the space charge density + /// \param histoIonsPhiRZ histogram which will be normalized to the sapce charge density + static void normalizeHistoQVEps0(TH3& histoIonsPhiRZ); + + private: + inline static auto& mParamGrid = ParameterSpaceCharge::Instance(); ///< parameters of the grid on which the calculations are performed + inline static int sNThreads{omp_get_max_threads()}; ///< number of threads which are used during the calculations + + inline static IntegrationStrategy sNumericalIntegrationStrategy{IntegrationStrategy::SimpsonIterative}; ///< numerical integration strategy of integration of the E-Field: 0: trapezoidal, 1: Simpson, 2: Root (only for analytical formula case) + inline static int sSimpsonNIteratives{3}; ///< number of iterations which are performed in the iterative simpson calculation of distortions/corrections + inline static int sSteps{1}; ///< during the calculation of the corrections/distortions it is assumed that the electron drifts on a line from deltaZ = z0 -> z1. The value sets the deltaZ width: 1: deltaZ=zBin/1, 5: deltaZ=zBin/5 + inline static GlobalDistType sGlobalDistType{GlobalDistType::Fast}; ///< setting for global distortions: 0: standard method, 1: interpolation of global corrections + inline static GlobalDistCorrMethod sGlobalDistCorrCalcMethod{GlobalDistCorrMethod::LocalDistCorr}; ///< setting for global distortions/corrections: 0: using electric field, 1: using local dis/corr interpolator + inline static SCDistortionType sSCDistortionType{SCDistortionType::SCDistortionsConstant}; ///< Type of space-charge distortions + + DataT mC0 = 0; ///< coefficient C0 (compare Jim Thomas's notes for definitions) + DataT mC1 = 0; ///< coefficient C1 (compare Jim Thomas's notes for definitions) + + static constexpr int FNSIDES = SIDES; ///< number of sides of the TPC + bool mIsEfieldSet[FNSIDES]{}; ///< flag if E-fields are set + bool mIsLocalCorrSet[FNSIDES]{}; ///< flag if local corrections are set + bool mIsLocalDistSet[FNSIDES]{}; ///< flag if local distortions are set + bool mIsLocalVecDistSet[FNSIDES]{}; ///< flag if local distortions vectors are set + bool mIsGlobalCorrSet[FNSIDES]{}; ///< flag if global corrections are set + bool mIsGlobalDistSet[FNSIDES]{}; ///< flag if global distortions are set + bool mIsChargeSet[FNSIDES]{}; ///< flag if the charge is set + + bool mUseInitialSCDensity{false}; ///< Flag for the use of an initial space-charge density at the beginning of the simulation + bool mInitLookUpTables{false}; ///< Flag to indicate if lookup tables have been calculated + + const RegularGrid mGrid3D[FNSIDES]{ + {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::A) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices)}, + {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices)}}; ///< grid properties + + DataContainer mLocalDistdR[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions dR + DataContainer mLocalDistdZ[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions dZ + DataContainer mLocalDistdRPhi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions dRPhi + + // local distortion vectors. + DataContainer mLocalVecDistdR[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions vector dR + DataContainer mLocalVecDistdZ[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions vector dZ + DataContainer mLocalVecDistdRPhi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local distortions vector dRPhi + + DataContainer mLocalCorrdR[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local corrections dR + DataContainer mLocalCorrdZ[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local corrections dZ + DataContainer mLocalCorrdRPhi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for local corrections dRPhi + + DataContainer mGlobalDistdR[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global distortions dR + DataContainer mGlobalDistdZ[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global distortions dZ + DataContainer mGlobalDistdRPhi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global distortions dRPhi + + DataContainer mGlobalCorrdR[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global corrections dR + DataContainer mGlobalCorrdZ[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global corrections dZ + DataContainer mGlobalCorrdRPhi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for global corrections dRPhi + + DataContainer mDensity[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for space charge density + DataContainer mPotential[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for the potential + + DataContainer mElectricFieldEr[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for the electric field Er + DataContainer mElectricFieldEz[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for the electric field Ez + DataContainer mElectricFieldEphi[FNSIDES]{DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices), DataContainer(mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)}; ///< data storage for the electric field Ephi + + TriCubic mInterpolatorPotential[FNSIDES]{ + {mPotential[Side::A], mGrid3D[Side::A]}, + {mPotential[Side::C], mGrid3D[Side::C]}}; ///< interpolator for the potenial + + TriCubic mInterpolatorDensity[FNSIDES]{ + {mDensity[Side::A], mGrid3D[Side::A]}, + {mDensity[Side::C], mGrid3D[Side::C]}}; ///< interpolator for the charge + + DistCorrInterpolator<DataT> mInterpolatorGlobalCorr[FNSIDES]{ + {mGlobalCorrdR[Side::A], mGlobalCorrdZ[Side::A], mGlobalCorrdRPhi[Side::A], mGrid3D[Side::A], Side::A}, + {mGlobalCorrdR[Side::C], mGlobalCorrdZ[Side::C], mGlobalCorrdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the global corrections + + DistCorrInterpolator<DataT> mInterpolatorLocalCorr[FNSIDES]{ + {mLocalCorrdR[Side::A], mLocalCorrdZ[Side::A], mLocalCorrdRPhi[Side::A], mGrid3D[Side::A], Side::A}, + {mLocalCorrdR[Side::C], mLocalCorrdZ[Side::C], mLocalCorrdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the local corrections + + DistCorrInterpolator<DataT> mInterpolatorGlobalDist[FNSIDES]{ + {mGlobalDistdR[Side::A], mGlobalDistdZ[Side::A], mGlobalDistdRPhi[Side::A], mGrid3D[Side::A], Side::A}, + {mGlobalDistdR[Side::C], mGlobalDistdZ[Side::C], mGlobalDistdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the global distortions + + DistCorrInterpolator<DataT> mInterpolatorLocalDist[FNSIDES]{ + {mLocalDistdR[Side::A], mLocalDistdZ[Side::A], mLocalDistdRPhi[Side::A], mGrid3D[Side::A], Side::A}, + {mLocalDistdR[Side::C], mLocalDistdZ[Side::C], mLocalDistdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the local distortions + + DistCorrInterpolator<DataT> mInterpolatorLocalVecDist[FNSIDES]{ + {mLocalVecDistdR[Side::A], mLocalVecDistdZ[Side::A], mLocalVecDistdRPhi[Side::A], mGrid3D[Side::A], Side::A}, + {mLocalVecDistdR[Side::C], mLocalVecDistdZ[Side::C], mLocalVecDistdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the local distortion vectors + + NumericalFields<DataT> mInterpolatorEField[FNSIDES]{ + {mElectricFieldEr[Side::A], mElectricFieldEz[Side::A], mElectricFieldEphi[Side::A], mGrid3D[Side::A], Side::A}, + {mElectricFieldEr[Side::C], mElectricFieldEz[Side::C], mElectricFieldEphi[Side::C], mGrid3D[Side::C], Side::C}}; ///< interpolator for the electric fields + + static int getSign(const Side side) { return side == Side::C ? -1 : 1; } + + /// get inverse spacing in z direction + DataT getInvSpacingZ(const Side side) const { return mGrid3D[side].getInvSpacingZ(); } + + /// get inverse spacing in r direction + DataT getInvSpacingR(const Side side) const { return mGrid3D[side].getInvSpacingR(); } + + /// get inverse spacing in phi direction + DataT getInvSpacingPhi(const Side side) const { return mGrid3D[side].getInvSpacingPhi(); } + + std::string getSideName(const Side side) const { return side == Side::A ? "A" : "C"; } + + /// calculate distortions or corrections analytical with electric fields + template <typename Fields = AnalyticalFields<DataT>> + void calcDistCorr(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& ddR, DataT& ddPhi, DataT& ddZ, const Fields& formulaStruct, const bool localDistCorr) const; + + /// calculate distortions/corrections using the formulas proposed in https://edms.cern.ch/ui/file/1108138/1/ALICE-INT-2010-016.pdf page 7 + void langevinCylindrical(DataT& ddR, DataT& ddPhi, DataT& ddZ, const DataT radius, const DataT localIntErOverEz, const DataT localIntEPhiOverEz, const DataT localIntDeltaEz) const; + + /// integrate electrical fields using root integration method + template <typename Fields = AnalyticalFields<DataT>> + void integrateEFieldsRoot(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const; + + /// integrate electrical fields using trapezoidal integration method + template <typename Fields = AnalyticalFields<DataT>> + void integrateEFieldsTrapezoidal(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const; + + /// integrate electrical fields using simpson integration method + template <typename Fields = AnalyticalFields<DataT>> + void integrateEFieldsSimpson(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const; + + /// integrate electrical fields using simpson integration method with non straight drift of electrons + template <typename Fields = AnalyticalFields<DataT>> + void integrateEFieldsSimpsonIterative(const DataT p1r, const DataT p2r, const DataT p1phi, const DataT p2phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const; + + /// calculate distortions/corrections using analytical electric fields + void processGlobalDistCorr(const DataT radius, const DataT phi, const DataT z0Tmp, const DataT z1Tmp, DataT& ddR, DataT& ddPhi, DataT& ddZ, const AnalyticalFields<DataT>& formulaStruct) const + { + calcDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct, false); + } + + /// calculate distortions/corrections using electric fields from tricubic interpolator + void processGlobalDistCorr(const DataT radius, const DataT phi, const DataT z0Tmp, const DataT z1Tmp, DataT& ddR, DataT& ddPhi, DataT& ddZ, const NumericalFields<DataT>& formulaStruct) const + { + calcDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct, false); + } + + /// calculate distortions/corrections by interpolation of local distortions/corrections + void processGlobalDistCorr(const DataT radius, const DataT phi, const DataT z0Tmp, [[maybe_unused]] const DataT z1Tmp, DataT& ddR, DataT& ddPhi, DataT& ddZ, const DistCorrInterpolator<DataT>& localDistCorr) const + { + ddR = localDistCorr.evaldR(z0Tmp, radius, phi); + ddZ = localDistCorr.evaldZ(z0Tmp, radius, phi); + ddPhi = localDistCorr.evaldRPhi(z0Tmp, radius, phi) / radius; + } + + /// dump the created electron tracks with calculateElectronDriftPath function to a tree + void dumpElectronTracksToTree(const std::vector<std::vector<GlobalPosition3D>>& electronTracks, const int nSamplingPoints, const char* outFile) const; +}; + +/// +/// ======================================================================================================== +/// Inline implementations of some methods +/// ======================================================================================================== +/// + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::integrateEFieldsTrapezoidal(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const +{ + //========trapezoidal rule see: https://en.wikipedia.org/wiki/Trapezoidal_rule ============== + const DataT fielder0 = formulaStruct.evalEr(p1z, p1r, p1phi); + const DataT fieldez0 = formulaStruct.evalEz(p1z, p1r, p1phi); + const DataT fieldephi0 = formulaStruct.evalEphi(p1z, p1r, p1phi); + + const DataT fielder1 = formulaStruct.evalEr(p2z, p1r, p1phi); + const DataT fieldez1 = formulaStruct.evalEz(p2z, p1r, p1phi); + const DataT fieldephi1 = formulaStruct.evalEphi(p2z, p1r, p1phi); + + const DataT ezField = getEzField(formulaStruct.getSide()); + const DataT eZ0 = (ezField + fieldez0) == 0 ? 0 : 1. / (ezField + fieldez0); + const DataT eZ1 = (ezField + fieldez1) == 0 ? 0 : 1. / (ezField + fieldez1); + + const DataT deltaX = 0.5 * (p2z - p1z); + localIntErOverEz = deltaX * (fielder0 * eZ0 + fielder1 * eZ1); + localIntEPhiOverEz = deltaX * (fieldephi0 * eZ0 + fieldephi1 * eZ1); + localIntDeltaEz = getSign(formulaStruct.getSide()) * deltaX * (fieldez0 + fieldez1); +} + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::integrateEFieldsSimpson(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const +{ + //==========simpsons rule see: https://en.wikipedia.org/wiki/Simpson%27s_rule ============================= + const DataT fielder0 = formulaStruct.evalEr(p1z, p1r, p1phi); + const DataT fieldez0 = formulaStruct.evalEz(p1z, p1r, p1phi); + const DataT fieldephi0 = formulaStruct.evalEphi(p1z, p1r, p1phi); + + const DataT fielder1 = formulaStruct.evalEr(p2z, p1r, p1phi); + const DataT fieldez1 = formulaStruct.evalEz(p2z, p1r, p1phi); + const DataT fieldephi1 = formulaStruct.evalEphi(p2z, p1r, p1phi); + + const DataT deltaX = p2z - p1z; + const DataT ezField = getEzField(formulaStruct.getSide()); + const DataT xk2N = (p2z - static_cast<DataT>(0.5) * deltaX); + const DataT ezField2 = formulaStruct.evalEz(xk2N, p1r, p1phi); + const DataT ezField2Denominator = (ezField + ezField2) == 0 ? 0 : 1. / (ezField + ezField2); + const DataT fieldSum2ErOverEz = formulaStruct.evalEr(xk2N, p1r, p1phi) * ezField2Denominator; + const DataT fieldSum2EphiOverEz = formulaStruct.evalEphi(xk2N, p1r, p1phi) * ezField2Denominator; + + const DataT eZ0 = (ezField + fieldez0) == 0 ? 0 : 1. / (ezField + fieldez0); + const DataT eZ1 = (ezField + fieldez1) == 0 ? 0 : 1. / (ezField + fieldez1); + + const DataT deltaXSimpsonSixth = deltaX / 6.; + localIntErOverEz = deltaXSimpsonSixth * (4. * fieldSum2ErOverEz + fielder0 * eZ0 + fielder1 * eZ1); + localIntEPhiOverEz = deltaXSimpsonSixth * (4. * fieldSum2EphiOverEz + fieldephi0 * eZ0 + fieldephi1 * eZ1); + localIntDeltaEz = getSign(formulaStruct.getSide()) * deltaXSimpsonSixth * (4. * ezField2 + fieldez0 + fieldez1); +} + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::integrateEFieldsSimpsonIterative(const DataT p1r, const DataT p2r, const DataT p1phi, const DataT p2phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const +{ + //==========simpsons rule see: https://en.wikipedia.org/wiki/Simpson%27s_rule ============================= + const Side side = formulaStruct.getSide(); + const DataT ezField = getEzField(side); + const DataT p2phiSave = regulatePhi(p2phi, side); + + const DataT fielder0 = formulaStruct.evalEr(p1z, p1r, p1phi); + const DataT fieldez0 = formulaStruct.evalEz(p1z, p1r, p1phi); + const DataT fieldephi0 = formulaStruct.evalEphi(p1z, p1r, p1phi); + + const DataT fielder1 = formulaStruct.evalEr(p2z, p2r, p2phiSave); + const DataT fieldez1 = formulaStruct.evalEz(p2z, p2r, p2phiSave); + const DataT fieldephi1 = formulaStruct.evalEphi(p2z, p2r, p2phiSave); + + const DataT eZ0Inv = (ezField + fieldez0) == 0 ? 0 : 1. / (ezField + fieldez0); + const DataT eZ1Inv = (ezField + fieldez1) == 0 ? 0 : 1. / (ezField + fieldez1); + + const DataT pHalfZ = 0.5 * (p1z + p2z); // dont needs to be regulated since p1z and p2z are already regulated + const DataT pHalfPhiSave = regulatePhi(0.5 * (p1phi + p2phi), side); // needs to be regulated since p2phi is not regulated + const DataT pHalfR = 0.5 * (p1r + p2r); + + const DataT ezField2 = formulaStruct.evalEz(pHalfZ, pHalfR, pHalfPhiSave); + const DataT eZHalfInv = (ezField + ezField2) == 0 ? 0 : 1. / (ezField + ezField2); + const DataT fieldSum2ErOverEz = formulaStruct.evalEr(pHalfZ, pHalfR, pHalfPhiSave); + const DataT fieldSum2EphiOverEz = formulaStruct.evalEphi(pHalfZ, pHalfR, pHalfPhiSave); + + const DataT deltaXSimpsonSixth = (p2z - p1z) / 6; + localIntErOverEz = deltaXSimpsonSixth * (4 * fieldSum2ErOverEz * eZHalfInv + fielder0 * eZ0Inv + fielder1 * eZ1Inv); + localIntEPhiOverEz = deltaXSimpsonSixth * (4 * fieldSum2EphiOverEz * eZHalfInv + fieldephi0 * eZ0Inv + fieldephi1 * eZ1Inv); + localIntDeltaEz = getSign(side) * deltaXSimpsonSixth * (4 * ezField2 + fieldez0 + fieldez1); +} + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::calcDistCorr(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& ddR, DataT& ddPhi, DataT& ddZ, const Fields& formulaStruct, const bool localDistCorr) const +{ + // see: https://edms.cern.ch/ui/file/1108138/1/ALICE-INT-2010-016.pdf + // needed for calculation of distortions/corrections + DataT localIntErOverEz = 0; // integral_p1z^p2z Er/Ez dz + DataT localIntEPhiOverEz = 0; // integral_p1z^p2z Ephi/Ez dz + DataT localIntDeltaEz = 0; // integral_p1z^p2z Ez dz + + // there are differentnumerical integration strategys implements. for details see each function. + switch (sNumericalIntegrationStrategy) { + case IntegrationStrategy::SimpsonIterative: // iterative simpson integration (should be more precise at least for the analytical E-Field case but takes alot more time than normal simpson integration) + for (int i = 0; i < sSimpsonNIteratives; ++i) { // TODO define a convergence criterion to abort the algorithm earlier for speed up. + const DataT tmpZ = localDistCorr ? (p2z + ddZ) : regulateZ(p2z + ddZ, formulaStruct.getSide()); // dont regulate for local distortions/corrections! (to get same result as using electric field at last/first bin) + integrateEFieldsSimpsonIterative(p1r, p1r + ddR, p1phi, p1phi + ddPhi, p1z, tmpZ, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct); + langevinCylindrical(ddR, ddPhi, ddZ, (p1r + 0.5 * ddR), localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz); // using the mean radius '(p1r + 0.5 * ddR)' for calculation of distortions/corections + } + break; + case IntegrationStrategy::Simpson: // simpson integration + integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct); + langevinCylindrical(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz); + break; + case IntegrationStrategy::Trapezoidal: // trapezoidal integration (fastest) + integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct); + langevinCylindrical(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz); + break; + case IntegrationStrategy::Root: // using integration implemented in ROOT (slow) + integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct); + langevinCylindrical(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz); + break; + default: + integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct); + langevinCylindrical(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz); + } +} + +template <typename DataT> +void SpaceCharge<DataT>::langevinCylindrical(DataT& ddR, DataT& ddPhi, DataT& ddZ, const DataT radius, const DataT localIntErOverEz, const DataT localIntEPhiOverEz, const DataT localIntDeltaEz) const +{ + // calculated distortions/correction with the formula described in https://edms.cern.ch/ui/file/1108138/1/ALICE-INT-2010-016.pdf page 7. + ddR = mC0 * localIntErOverEz + mC1 * localIntEPhiOverEz; + ddPhi = (mC0 * localIntEPhiOverEz - mC1 * localIntErOverEz) / radius; + ddZ = -localIntDeltaEz * TPCParameters<DataT>::DVDE; +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h new file mode 100644 index 0000000000000..96c9087ac8392 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h @@ -0,0 +1,261 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SpaceChargeHelpers.h +/// \brief This file provides all necesseray classes which are used during the calcution of the distortions and corrections +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#ifndef ALICEO2_TPC_SPACECHARGEHELPERS_H_ +#define ALICEO2_TPC_SPACECHARGEHELPERS_H_ + +#include <functional> +#include <cmath> +#include "TPCSpaceCharge/TriCubic.h" +#include "DataFormatsTPC/Defs.h" + +namespace o2 +{ +namespace tpc +{ + +/// +/// this class contains an analytical description of the space charge, potential and the electric fields. +/// The analytical functions can be used to test the poisson solver and the caluclation of distortions/corrections. +/// +template <typename DataT = double> +class AnalyticalFields +{ + public: + AnalyticalFields(const o2::tpc::Side side = o2::tpc::Side::A) : mSide{side} {}; + + o2::tpc::Side getSide() const { return mSide; } + + void setSide(const o2::tpc::Side side) { mSide = side; } + + /// sets the parameters + void setParameters(const DataT parA, const DataT parB, const DataT parC) + { + mParA = parA; + mParB = parB; + mParC = parC; + } + + /// return parameter A + DataT getParA() const { return mParA; } + + /// return parameter B + DataT getParB() const { return mParB; } + + /// return parameter C + DataT getParC() const { return mParC; } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Er for given coordinate + DataT evalEr(DataT z, DataT r, DataT phi) const { return mErFunc(z, r, phi); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Ez for given coordinate + DataT evalEz(DataT z, DataT r, DataT phi) const { return mEzFunc(z, r, phi); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Ephi for given coordinate + DataT evalEphi(DataT z, DataT r, DataT phi) const { return mEphiFunc(z, r, phi); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for the potential for given coordinate + DataT evalPotential(DataT z, DataT r, DataT phi) const { return mPotentialFunc(z, r, phi); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for the space charge density for given coordinate + DataT evalDensity(DataT z, DataT r, DataT phi) const { return mDensityFunc(z, r, phi); } + + /// analytical potential + std::function<DataT(DataT, DataT, DataT)> mPotentialFunc = [& mParA = mParA, &mParB = mParB, &mParC = mParC](const DataT z, const DataT r, const DataT phi) { + const DataT zz = std::abs(z); + return -mParA * (std::pow((-r + 254.5 + 83.5), 4) - 338.0 * std::pow((-r + 254.5 + 83.5), 3) + 21250.75 * std::pow((-r + 254.5 + 83.5), 2)) * std::cos(mParB * phi) * std::cos(mParB * phi) * std::exp(-1 * mParC * (zz - 125) * (zz - 125)); + }; + + /// analytical space charge - NOTE: if the space charge density is calculated analytical there would be a - sign in the formula (-mParA) - however since its an e- the sign is flipped (IS THIS CORRECT??? see for minus sign: AliTPCSpaceCharge3DCalc::SetPotentialBoundaryAndChargeFormula)- + std::function<DataT(DataT, DataT, DataT)> mDensityFunc = [& mParA = mParA, &mParB = mParB, &mParC = mParC](const DataT z, const DataT r, const DataT phi) { + const DataT zz = std::abs(z); + return mParA * ((1 / r * 16 * (-3311250 + 90995.5 * r - 570.375 * r * r + r * r * r)) * std::cos(mParB * phi) * std::cos(mParB * phi) * std::exp(-1 * mParC * (zz - 125) * (zz - 125)) + + (std::pow(-r + 254.5 + 83.5, 4) - 338.0 * std::pow(-r + 254.5 + 83.5, 3) + 21250.75 * std::pow(-r + 254.5 + 83.5, 2)) / (r * r) * std::exp(-1 * mParC * (zz - 125) * (zz - 125)) * -2 * mParB * mParB * std::cos(2 * mParB * phi) + + (std::pow(-r + 254.5 + 83.5, 4) - 338.0 * std::pow(-r + 254.5 + 83.5, 3) + 21250.75 * std::pow(-r + 254.5 + 83.5, 2)) * std::cos(mParB * phi) * std::cos(mParB * phi) * 2 * mParC * std::exp(-1 * mParC * (zz - 125) * (zz - 125)) * (2 * mParC * (zz - 125) * (zz - 125) - 1)); + }; + + /// analytical electric field Er + std::function<DataT(DataT, DataT, DataT)> mErFunc = [& mParA = mParA, &mParB = mParB, &mParC = mParC](const DataT z, const DataT r, const DataT phi) { + const DataT zz = std::abs(z); + return mParA * 4 * (r * r * r - 760.5 * r * r + 181991 * r - 1.3245 * std::pow(10, 7)) * std::cos(mParB * phi) * std::cos(mParB * phi) * std::exp(-1 * mParC * (zz - 125) * (zz - 125)); + }; + + /// analytical electric field Ephi + std::function<DataT(DataT, DataT, DataT)> mEphiFunc = [& mParA = mParA, &mParB = mParB, &mParC = mParC](const DataT z, const DataT r, const DataT phi) { + const DataT zz = std::abs(z); + return mParA * (std::pow(-r + 254.5 + 83.5, 4) - 338.0 * std::pow(-r + 254.5 + 83.5, 3) + 21250.75 * (-r + 254.5 + 83.5) * (-r + 254.5 + 83.5)) / r * std::exp(-1 * mParC * (zz - 125) * (zz - 125)) * -mParB * std::sin(2 * mParB * phi); + }; + + /// analytical electric field Ez + std::function<DataT(DataT, DataT, DataT)> mEzFunc = [& mParA = mParA, &mParB = mParB, &mParC = mParC](const DataT z, const DataT r, const DataT phi) { + const DataT zz = std::abs(z); + return mParA * (std::pow(-r + 254.5 + 83.5, 4) - 338.0 * std::pow(-r + 254.5 + 83.5, 3) + 21250.75 * (-r + 254.5 + 83.5) * (-r + 254.5 + 83.5)) * std::cos(mParB * phi) * std::cos(mParB * phi) * -2 * mParC * (zz - 125) * std::exp(-1 * mParC * (zz - 125) * (zz - 125)); + }; + + static constexpr unsigned int getID() { return ID; } + + private: + static constexpr unsigned int ID = 0; ///< needed to distinguish between the differrent classes + DataT mParA{1e-5}; ///< parameter [0] of functions + DataT mParB{0.5}; ///< parameter [1] of functions + DataT mParC{1e-4}; ///< parameter [2] of functions + o2::tpc::Side mSide{o2::tpc::Side::A}; ///< side of the TPC. Since the absolute value is taken during the calculations the choice of the side is arbitrary. +}; + +/// +/// This class gives tricubic interpolation of the electric fields and can be used to calculate the distortions/corrections. +/// The electric fields have to be calculated by the poisson solver or given by the analytical formula. +/// +template <typename DataT = double> +class NumericalFields +{ + using RegularGrid = o2::tpc::RegularGrid3D<DataT>; + using DataContainer = o2::tpc::DataContainer3D<DataT>; + using TriCubic = o2::tpc::TriCubicInterpolator<DataT>; + + public: + /// constructor + /// \param dataEr container for the data of the electrical field Er + /// \param dataEz container for the data of the electrical field Ez + /// \param dataEphi container for the data of the electrical field Ephi + /// \param gridProperties properties of the grid + /// \param side side of the tpc + NumericalFields(const DataContainer& dataEr, const DataContainer& dataEz, const DataContainer& dataEphi, const RegularGrid& gridProperties, const o2::tpc::Side side) : mDataEr{dataEr}, mDataEz{dataEz}, mDataEphi{dataEphi}, mGridProperties{gridProperties}, mSide{side} {}; + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Er for given coordinate + DataT evalEr(DataT z, DataT r, DataT phi) const { return mInterpolatorEr(z, r, phi, mInterpolType); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Ez for given coordinate + DataT evalEz(DataT z, DataT r, DataT phi) const { return mInterpolatorEz(z, r, phi, mInterpolType); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for electric field Ephi for given coordinate + DataT evalEphi(DataT z, DataT r, DataT phi) const { return mInterpolatorEphi(z, r, phi, mInterpolType); } + + o2::tpc::Side getSide() const { return mSide; } + + static constexpr unsigned int getID() { return ID; } + + /// set which kind of TriCubic interpolation algorithm is used + void setInterpolationType(const typename TriCubic::InterpolationType type) { mInterpolType = type; } + + // \return returns which kind of TriCubic interpolation algorithm is used + typename TriCubic::InterpolationType getInterpolationType() const { return mInterpolType; } + + private: + const DataContainer& mDataEr{}; ///< adress to the data container of the grid + const DataContainer& mDataEz{}; ///< adress to the data container of the grid + const DataContainer& mDataEphi{}; ///< adress to the data container of the grid + const RegularGrid& mGridProperties{}; ///< properties of the regular grid + const o2::tpc::Side mSide{}; ///< side of the TPC + + TriCubic mInterpolatorEr{mDataEr, mGridProperties}; ///< TriCubic interpolator of the electric field Er + TriCubic mInterpolatorEz{mDataEz, mGridProperties}; ///< TriCubic interpolator of the electric field Ez + TriCubic mInterpolatorEphi{mDataEphi, mGridProperties}; ///< TriCubic interpolator of the electric field Ephi + typename TriCubic::InterpolationType mInterpolType = TriCubic::InterpolationType::Sparse; ///< type of TriCubic interpolation + static constexpr unsigned int ID = 1; ///< needed to distinguish between the different classes +}; + +/// +/// This class gives tricubic interpolation of the local distortions or corrections. +/// The the local distortions or corrections can be used to calculate the global distortions/corrections. +/// +template <typename DataT = double> +class DistCorrInterpolator +{ + using RegularGrid = o2::tpc::RegularGrid3D<DataT>; + using DataContainer = o2::tpc::DataContainer3D<DataT>; + using TriCubic = o2::tpc::TriCubicInterpolator<DataT>; + + public: + /// constructor + /// \param dataDistCorrdR container for the data of the distortions dR + /// \param dataDistCorrdZ container for the data of the distortions dZ + /// \param dataDistCorrdRPhi container for the data of the distortions dPhi + /// \param gridProperties properties of the grid + /// \param side side of the tpc + DistCorrInterpolator(const DataContainer& dataDistCorrdR, const DataContainer& dataDistCorrdZ, const DataContainer& dataDistCorrdRPhi, const RegularGrid& gridProperties, const o2::tpc::Side side) : mDataDistCorrdR{dataDistCorrdR}, mDataDistCorrdZ{dataDistCorrdZ}, mDataDistCorrdRPhi{dataDistCorrdRPhi}, mGridProperties{gridProperties}, mSide{side} {}; + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for the local distortion or correction dR for given coordinate + DataT evaldR(const DataT z, const DataT r, const DataT phi) const { return interpolatorDistCorrdR(z, r, phi, mInterpolType); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for the local distortion or correction dZ for given coordinate + DataT evaldZ(const DataT z, const DataT r, const DataT phi) const { return interpolatorDistCorrdZ(z, r, phi, mInterpolType); } + + /// \param r r coordinate + /// \param phi phi coordinate + /// \param z z coordinate + /// \return returns the function value for the local distortion or correction dRPhi for given coordinate + DataT evaldRPhi(const DataT z, const DataT r, const DataT phi) const { return interpolatorDistCorrdRPhi(z, r, phi, mInterpolType); } + + o2::tpc::Side getSide() const { return mSide; } + + static constexpr unsigned int getID() { return ID; } + + /// set which kind of TriCubic interpolation algorithm is used + void setInterpolationType(const typename TriCubic::InterpolationType type) { mInterpolType = type; } + + /// \return returns which kind of TriCubic interpolation algorithm is used + typename TriCubic::InterpolationType getInterpolationType() const { return mInterpolType; } + + private: + const DataContainer& mDataDistCorrdR{}; ///< adress to the data container of the grid + const DataContainer& mDataDistCorrdZ{}; ///< adress to the data container of the grid + const DataContainer& mDataDistCorrdRPhi{}; ///< adress to the data container of the grid + const RegularGrid& mGridProperties{}; ///< properties of the regular grid + const o2::tpc::Side mSide{}; ///< side of the TPC. + + TriCubic interpolatorDistCorrdR{mDataDistCorrdR, mGridProperties}; ///< TriCubic interpolator of distortion or correction dR + TriCubic interpolatorDistCorrdZ{mDataDistCorrdZ, mGridProperties}; ///< TriCubic interpolator of distortion or correction dZ + TriCubic interpolatorDistCorrdRPhi{mDataDistCorrdRPhi, mGridProperties}; ///< TriCubic interpolator of distortion or correction dRPhi + typename TriCubic::InterpolationType mInterpolType = TriCubic::InterpolationType::Sparse; ///< type of TriCubic interpolation + static constexpr unsigned int ID = 2; ///< needed to distinguish between the different classes +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeParameter.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeParameter.h new file mode 100644 index 0000000000000..04b6d552eb0df --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeParameter.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file IDCGroupingParameter.h +/// \brief Definition of the parameter for the grouping of the IDCs +/// \author Matthias Kleiner, mkleiner@ikf.uni-frankfurt.de + +#ifndef ALICEO2_TPC_SPACECHARGEPARAMETER_H_ +#define ALICEO2_TPC_SPACECHARGEPARAMETER_H_ + +#include <array> +#include "CommonUtils/ConfigurableParamHelper.h" +#include "Rtypes.h" // for ClassDefNV + +namespace o2 +{ +namespace tpc +{ + +/// struct for setting the parameters for the grouping of IDCs +struct ParameterSpaceCharge : public o2::conf::ConfigurableParamHelper<ParameterSpaceCharge> { + unsigned short NRVertices = 129; /// NRVertices number of vertices in z direction + unsigned short NZVertices = 129; /// NZVertices number of vertices in r direction + unsigned short NPhiVertices = 180; /// NRPhiVertices number of vertices in phi direction + + O2ParamDef(ParameterSpaceCharge, "TPCSpaceChargeParam"); +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/TriCubic.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/TriCubic.h new file mode 100644 index 0000000000000..c2850ef632d1d --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/TriCubic.h @@ -0,0 +1,356 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TriCubic.h +/// \brief Definition of TriCubic class +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_TRICUBIC_H_ +#define ALICEO2_TPC_TRICUBIC_H_ + +#include "TPCSpaceCharge/Vector.h" +#include "TPCSpaceCharge/RegularGrid3D.h" +#include "TPCSpaceCharge/DataContainer3D.h" + +#if (defined(WITH_OPENMP) || defined(_OPENMP)) && !defined(__CLING__) +#include <omp.h> +#else +static inline int omp_get_thread_num() { return 0; } +static inline int omp_get_max_threads() { return 1; } +#endif + +namespace o2 +{ +namespace tpc +{ + +/// \class TriCubicInterpolator +/// The TriCubic class represents tricubic interpolation on a regular 3-Dim grid. +/// The algorithm which is used is based on the method developed by F. Lekien and J. Marsden and is described +/// in 'Tricubic Interpolation in Three Dimensions (2005)' http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.89.7835 +/// In this method in a first step 64 coefficients are computed by using a predefined 64*64 matrix. +/// These coefficients have to be computed for each cell in the grid, but are only computed when querying a point in a given cell. +/// The calculated coefficient is then stored for only the last cell and will be reused if the next query point lies in the same cell. +/// +/// Additionally the classical one dimensional approach of interpolating values is implemented. This algorithm is faster when interpolating only a few values inside each cube. +/// +/// periodic boundary conditions are used in phi direction. + +/// void test() +/// { +/// // define the grid: +/// // define number of vertices per dimension +/// const int zvertices = 40; +/// const int rvertices = 40; +/// const int phivertices = 40; +/// +/// // define min range +/// float zmin = 0; +/// float rmin = 0; +/// float phimin = 0; +/// +/// // define spacing between grid vertices +/// float zSpacing = 0.25; +/// float rSpacing = 0.25; +/// float phiSpacing = 2 * M_PI / phivertices; +/// +/// // create grid and datacontainer object +/// o2::tpc::RegularGrid3D<float, zvertices, rvertices, phivertices> grid3D(zmin, rmin, phimin, zSpacing, rSpacing, phiSpacing); +/// o2::tpc::DataContainer3D<float> data3D(zvertices, rvertices, phivertices) +/// +/// // fill the DataContainer3D with some values +/// for (int iz = 0; iz < zvertices; ++iz) { +/// for (int ir = 0; ir < rvertices; ++ir) { +/// for (int iphi = 0; iphi < phivertices; ++iphi) { +/// const float izPos = zSpacing * iz + zmin; +/// const float irPos = rSpacing * ir + rmin; +/// const float iphiPos = phiSpacing * iphi + phimin; +/// data3D(iz, ir, iphi) = std::sin(irPos * izPos / 10.) + std::cos(iphiPos); // some arbitrary function is used here +/// } +/// } +/// } +/// +/// // create tricubic interpolator +/// o2::tpc::TriCubicInterpolator<float> interpolator(data3D, grid3D); +/// +/// // query some values +/// for (float iz = grid3D.getGridMinX(); iz < grid3D.getGridMaxX(); iz += zSpacing / 3.) { +/// for (float ir = grid3D.getGridMinY(); ir < grid3D.getGridMaxY(); ir += rSpacing / 3.) { +/// for (float iphi = grid3D.getGridMinZ() - 2 * phiSpacing; iphi < grid3D.getGridMaxZ() + 2 * phiSpacing; iphi += phiSpacing / 3.) { +/// const float zQuery = iz; +/// const float rQuery = ir; +/// const float phiQuery = iphi; +/// +/// const float interpolatedSparse = interpolator(zQuery, rQuery, phiQuery, o2::tpc::TriCubicInterpolator<float, zvertices, rvertices, phivertices>::InterpolationType::Sparse); +/// const float interpolatedDense = interpolator(zQuery, rQuery, phiQuery, o2::tpc::TriCubicInterpolator<float, zvertices, rvertices, phivertices>::InterpolationType::Dense); +/// const float trueValue = std::sin(rQuery * zQuery / 10.) + std::cos(phiQuery); +/// const float interpolatedDerivative = interpolator(zQuery, rQuery, phiQuery, 1, 1, 0); +/// const float trueDerivative = 1 / 10. * std::cos(rQuery * zQuery / 10.) - rQuery / 10. * std::sin(rQuery * zQuery / 10.) * zQuery / 10.; +/// } +/// } +/// } +/// } + +/// \tparam DataT the type of data which is used during the calculations +template <typename DataT = double> +class TriCubicInterpolator +{ + using Grid3D = RegularGrid3D<DataT>; + using DataContainer = DataContainer3D<DataT>; + using VDataT = Vc::Vector<DataT>; + + public: + /// Constructor for a tricubic interpolator + /// \param gridData struct containing access to the values of the grid + /// \param gridProperties properties of the 3D grid + TriCubicInterpolator(const DataContainer& gridData, const Grid3D& gridProperties) : mGridData{gridData}, mGridProperties{gridProperties} {}; + + enum class ExtrapolationType { + Linear = 0, ///< assume linear dependency at the boundaries of the grid + Parabola = 1, ///< assume parabolic dependency at the boundaries of the grid + }; + + enum class InterpolationType { + Sparse = 0, ///< using one dimensional method of interpolation (fast when interpolating only a few values in one cube in the grid) + Dense = 1, ///< using three dimensional method of interpolation (fast when interpolating a lot values in one cube in the grid) + }; + + // interpolate value at given coordinate + /// \param z z coordinate + /// \param r r coordinate + /// \param phi phi coordinate + /// \param type interpolation algorithm + /// \return returns the interpolated value at given coordinate + DataT operator()(const DataT z, const DataT r, const DataT phi, const InterpolationType type = InterpolationType::Sparse) const; + + /// interpolate derivative at given coordinate + /// \param z z coordinate + /// \param r r coordinate + /// \param phi phi coordinate + /// \param derz order of derivative d/dz: derz=1 -> d/dz f(z,r,phi), derz=2 -> d^2/dz^2 f(z,r,phi), derz=3 -> d^3/dz^3 f(z,r,phi) + /// \param derphi order of derivative d/dr: derr=1 -> d/dr f(z,r,phi), derr=2 -> d^2/dr^2 f(z,r,phi), derr=3 -> d^3/dr^3 f(z,r,phi) + /// \param derphi order of derivative d/dphi: derphi=1 -> d/dphi f(z,r,phi), derphi=2 -> d^2/dphi^2 f(z,r,phi), derphi=3 -> d^3/dphi^3 f(z,r,phi) + /// derz=1 and derr=2 -> d/dz * d^2/dr^2 * f(z,r,phi) + /// \return returns the interpolated derivative at given coordinate + DataT operator()(const DataT z, const DataT r, const DataT phi, const size_t derz, const size_t derr, const size_t derphi) const; + + /// set which type of extrapolation is used at the grid boundaries (linear or parabol can be used with periodic phi axis and non periodic z and r axis). + /// \param extrapolationType sets type of extrapolation. See enum ExtrapolationType for different types + void setExtrapolationType(const ExtrapolationType extrapolationType) { mExtrapolationType = extrapolationType; } + + /// \return returns the extrapolation technique for missing boundary values + ExtrapolationType getExtrapolationType() const { return mExtrapolationType; } + + /// get the number of threads used for some of the calculations + static int getNThreads() { return sNThreads; } + + /// set the number of threads used for some of the calculations + static void setNThreads(int nThreads) { sNThreads = nThreads; } + + /// \return returns the number of the thread. Each thread should have an individual thread number + int getThreadNum() const { return sThreadnum; } + + /// \return performs a check if the interpolator can be used with maximum number of threads + bool checkThreadSafety() const { return sNThreads <= omp_get_max_threads(); } + + private: + // matrix containing the 'relationship between the derivatives at the corners of the elements and the coefficients' + inline static Vc::Memory<VDataT, 64> sMat[64]{ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {9, -9, -9, 9, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 6, -6, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 6, -6, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {4, -4, -4, 4, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, + {-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {9, -9, 0, 0, -9, 9, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 0, 0, 6, -6, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0}, + {9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, + {-27, 27, 27, -27, 27, -27, -27, 27, -18, -9, 18, 9, 18, 9, -18, -9, -18, 18, -9, 9, 18, -18, 9, -9, -18, 18, 18, -18, -9, 9, 9, -9, -12, -6, -6, -3, 12, 6, 6, 3, -12, -6, 12, 6, -6, -3, 6, 3, -12, 12, -6, 6, -6, 6, -3, 3, -8, -4, -4, -2, -4, -2, -2, -1}, + {18, -18, -18, 18, -18, 18, 18, -18, 9, 9, -9, -9, -9, -9, 9, 9, 12, -12, 6, -6, -12, 12, -6, 6, 12, -12, -12, 12, 6, -6, -6, 6, 6, 6, 3, 3, -6, -6, -3, -3, 6, 6, -6, -6, 3, 3, -3, -3, 8, -8, 4, -4, 4, -4, 2, -2, 4, 4, 2, 2, 2, 2, 1, 1}, + {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0}, + {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 9, -9, 9, -9, -9, 9, -9, 9, 12, -12, -12, 12, 6, -6, -6, 6, 6, 3, 6, 3, -6, -3, -6, -3, 8, 4, -8, -4, 4, 2, -4, -2, 6, -6, 6, -6, 3, -3, 3, -3, 4, 2, 4, 2, 2, 1, 2, 1}, + {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -6, 6, -6, 6, 6, -6, 6, -6, -8, 8, 8, -8, -4, 4, 4, -4, -3, -3, -3, -3, 3, 3, 3, 3, -4, -4, 4, 4, -2, -2, 2, 2, -4, 4, -4, 4, -2, 2, -2, 2, -2, -2, -2, -2, -1, -1, -1, -1}, + {2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-6, 6, 0, 0, 6, -6, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {4, -4, 0, 0, -4, 4, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, + {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0}, + {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 12, -12, 6, -6, -12, 12, -6, 6, 9, -9, -9, 9, 9, -9, -9, 9, 8, 4, 4, 2, -8, -4, -4, -2, 6, 3, -6, -3, 6, 3, -6, -3, 6, -6, 3, -3, 6, -6, 3, -3, 4, 2, 2, 1, 4, 2, 2, 1}, + {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -8, 8, -4, 4, 8, -8, 4, -4, -6, 6, 6, -6, -6, 6, 6, -6, -4, -4, -2, -2, 4, 4, 2, 2, -3, -3, 3, 3, -3, -3, 3, 3, -4, 4, -2, 2, -4, 4, -2, 2, -2, -2, -1, -1, -2, -2, -1, -1}, + {4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, + {-12, 12, 12, -12, 12, -12, -12, 12, -8, -4, 8, 4, 8, 4, -8, -4, -6, 6, -6, 6, 6, -6, 6, -6, -6, 6, 6, -6, -6, 6, 6, -6, -4, -2, -4, -2, 4, 2, 4, 2, -4, -2, 4, 2, -4, -2, 4, 2, -3, 3, -3, 3, -3, 3, -3, 3, -2, -1, -2, -1, -2, -1, -2, -1}, + {8, -8, -8, 8, -8, 8, 8, -8, 4, 4, -4, -4, -4, -4, 4, 4, 4, -4, 4, -4, -4, 4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 2, 2, 2, 2, -2, -2, -2, -2, 2, 2, -2, -2, 2, 2, -2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 1, 1, 1, 1, 1, 1, 1, 1}}; ///< matrix containing the 'relationship between the derivatives at the corners of the elements and the coefficients' + + inline static Matrix<DataT, 64> sMatrixA{sMat}; ///< this matrix is used for vectorized operations with the 64*64 matrix + static constexpr unsigned int FDim = Grid3D::getDim(); ///< dimensions of the grid + static constexpr unsigned int FZ = Grid3D::getFZ(); ///< index for z coordinate + static constexpr unsigned int FR = Grid3D::getFR(); ///< index for r coordinate + static constexpr unsigned int FPHI = Grid3D::getFPhi(); ///< index for phi coordinate + const DataContainer& mGridData{}; ///< adress to the data container of the grid + const Grid3D& mGridProperties{}; ///< adress to the properties of the grid + inline static thread_local const size_t sThreadnum{static_cast<size_t>(omp_get_thread_num())}; ///< save for each thread the thread number to get fast access to the correct array + inline static int sNThreads{omp_get_max_threads()}; ///< number of threads the tricubic interpolator can be used with + std::unique_ptr<Vector<DataT, 64>[]> mCoefficients = std::make_unique<Vector<DataT, 64>[]>(sNThreads); ///< coefficients needed to interpolate a value + std::unique_ptr<Vector<DataT, FDim>[]> mLastInd = std::make_unique<Vector<DataT, FDim>[]>(sNThreads); ///< stores the index for the cell, where the coefficients are already evaluated (only the coefficients for the last cell are stored) + std::unique_ptr<bool[]> mInitialized = std::make_unique<bool[]>(sNThreads); ///< sets the flag if the coefficients are evaluated at least once + ExtrapolationType mExtrapolationType = ExtrapolationType::Parabola; ///< sets which type of extrapolation for missing points at boundary is used. Linear and Parabola is only supported for perdiodic phi axis and non periodic z and r axis + + // DEFINITION OF enum GridPos + //======================================================== + // r + // | 6------F---7 + // | / | / | + // | K G YR L H + // | / | / | + // | 2---B------3 | + // | | | | | + // | | 4---|---E--5 + // | C XL / D XR / + // | | I YL | J + // | | / | / + // | 0---A------1 + // |------------------------------- z + // / + // / + // / + // phi + //======================================================== + + enum class GridPos { + None = 27, + InnerVolume = 26, + Edge0 = 0, + Edge1 = 1, + Edge2 = 2, + Edge3 = 3, + Edge4 = 4, + Edge5 = 5, + Edge6 = 6, + Edge7 = 7, + LineA = 8, + LineB = 9, + LineC = 10, + LineD = 11, + LineE = 12, + LineF = 13, + LineG = 14, + LineH = 15, + LineI = 16, + LineJ = 17, + LineK = 18, + LineL = 19, + SideXRight = 20, + SideXLeft = 21, + SideYRight = 22, + SideYLeft = 23, + SideZRight = 24, + SideZLeft = 25 + }; + + void setValues(const int iz, const int ir, const int iphi, DataT cVals[64]) const; + + const Vector<DataT, 3> processInp(const Vector<DataT, 3>& coordinates, const bool sparse = false) const; + + // calculate the coefficients needed for the interpolation using the 64*64 matrix. + // this is the 'slow' part of the code and might be optimized + void calcCoefficients(const unsigned int iz, const unsigned int ir, const unsigned int iphi) const; + + DataT interpolateDense(const Vector<DataT, 3>& pos) const; + + // interpolate value at given coordinate - this method doesnt compute and stores the coefficients and is faster when quering only a few values per cube + /// \param z z coordinate + /// \param r r coordinate + /// \param phi phi coordinate + /// \return returns the interpolated value at given coordinate + DataT interpolateSparse(const DataT z, const DataT r, const DataT phi) const; + + DataT evalDerivative(const DataT dz, const DataT dr, const DataT dphi, const size_t derz, const size_t derr, const size_t derphi) const; + + // for periodic boundary conditions + void getDataIndexCircularArray(const int index0, const int dim, int arr[]) const; + + // for non periodic boundary conditions + void getDataIndexNonCircularArray(const int index0, const int dim, int arr[]) const; + + // this helps to get circular and non circular padding indices + int getRegulatedDelta(const int index0, const int delta, const unsigned int dim, const int offs) const + { + return mGridProperties.isIndexInGrid(index0 + delta, dim) ? delta : offs; + } + + void initInterpolator(const unsigned int iz, const unsigned int ir, const unsigned int iphi) const; + + DataT extrapolation(const DataT valk, const DataT valk1, const DataT valk2) const; + + DataT linearExtrapolation(const DataT valk, const DataT valk1) const; + + DataT parabolExtrapolation(const DataT valk, const DataT valk1, const DataT valk2) const; + + GridPos findPos(const int iz, const int ir, const int iphi) const; + + bool isInInnerVolume(const int iz, const int ir, const int iphi, GridPos& posType) const; + + bool findEdge(const int iz, const int ir, const int iphi, GridPos& posType) const; + + bool findLine(const int iz, const int ir, const int iphi, GridPos& posType) const; + + bool findSide(const int iz, const int ir, const int iphi, GridPos& posType) const; + + bool isSideRight(const int ind, const int dim) const; + + bool isSideLeft(const int ind) const; +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector.h new file mode 100644 index 0000000000000..e09e1d80b5392 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector.h @@ -0,0 +1,175 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file matrix.h +/// \brief Definition of Vector and Matrix class +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifndef ALICEO2_TPC_VECTOR_H_ +#define ALICEO2_TPC_VECTOR_H_ + +#include <Vc/vector> +#include <Vc/Memory> + +namespace o2 +{ +namespace tpc +{ +template <typename DataT = float, size_t N = 64> +class Matrix +{ + using VDataT = Vc::Vector<DataT>; + + public: + /// constructor + /// \param dataMatrix pointer to the data + Matrix(const Vc::Memory<VDataT, N>* dataMatrix) : mDataMatrix(dataMatrix) {} + + const Vc::Memory<VDataT, N>& operator[](size_t i) const { return mDataMatrix[i]; } + + private: + const Vc::Memory<VDataT, N>* mDataMatrix{}; +}; + +template <typename DataT = float, size_t N = 64> +class Vector +{ + using VDataT = Vc::Vector<DataT>; + + public: + /// default constructor + Vector() = default; + + /// constructor + /// \param dataVector data which is assigned to the vector + Vector(const Vc::Memory<VDataT, N>& dataVector) : mDataVector(dataVector) {} + + /// operator access + const DataT operator[](size_t i) const { return mDataVector.scalar(i); } + DataT& operator[](size_t i) { return mDataVector.scalar(i); } + + /// sets the vector with index j + void setVector(const size_t j, const VDataT& vector) { mDataVector.vector(j) = vector; } + + /// \return returns the vector with index j + const VDataT getVector(const size_t j) const { return mDataVector.vector(j); } + + /// \return returns the number of Vc::Vector<DataT> stored in the Vector + size_t getvectorsCount() const { return mDataVector.vectorsCount(); } + + /// \return returns the number of entries stored in the Vector + size_t getentriesCount() const { return mDataVector.entriesCount(); } + + private: + // storage for the data + Vc::Memory<VDataT, N> mDataVector{}; +}; + +template <typename DataT, size_t N> +inline Vector<DataT, N> operator*(const Matrix<DataT, N>& a, const Vector<DataT, N>& b) +{ + using V = Vc::Vector<DataT>; + // resulting vector c + Vector<DataT, N> c; + for (size_t i = 0; i < N; ++i) { + V c_ij{}; + for (size_t j = 0; j < a[i].vectorsCount(); ++j) { + c_ij += a[i].vector(j) * b.getVector(j); + } + c[i] = c_ij.sum(); + } + return c; +} + +template <typename DataT, size_t N> +inline Vector<DataT, N> floor(const Vector<DataT, N>& a) +{ + Vector<DataT, N> c; + for (size_t j = 0; j < a.getvectorsCount(); ++j) { + c.setVector(j, Vc::floor(a.getVector(j))); + } + return c; +} + +template <typename DataT, size_t N> +inline Vector<DataT, N> operator-(const Vector<DataT, N>& a, const Vector<DataT, N>& b) +{ + // resulting matrix c + Vector<DataT, N> c; + for (size_t j = 0; j < a.getvectorsCount(); ++j) { + c.setVector(j, a.getVector(j) - b.getVector(j)); + } + return c; +} + +template <typename DataT, size_t N> +inline Vector<DataT, N> operator+(const Vector<DataT, N>& a, const Vector<DataT, N>& b) +{ + // resulting matrix c + Vector<DataT, N> c; + for (size_t j = 0; j < a.getvectorsCount(); ++j) { + c.setVector(j, a.getVector(j) + b.getVector(j)); + } + return c; +} + +template <typename DataT, size_t N> +inline Vector<DataT, N> operator*(const DataT a, const Vector<DataT, N>& b) +{ + // resulting matrix c + Vector<DataT, N> c; + for (size_t j = 0; j < b.getvectorsCount(); ++j) { + c.setVector(j, a * b.getVector(j)); + } + return c; +} + +// compute the sum of one Vector +template <typename DataT, size_t N> +inline DataT sum(const Vector<DataT, N>& a) +{ + // resulting matrix c + Vc::Vector<DataT> b = a.getVector(0); + for (size_t j = 1; j < a.getvectorsCount(); ++j) { + b += a.getVector(j); + } + return b.sum(); +} + +// multiply each row from a vector with the row from a second vector +template <typename DataT, size_t N> +inline Vector<DataT, N> operator*(const Vector<DataT, N>& a, const Vector<DataT, N>& b) +{ + // resulting matrix c + Vector<DataT, N> c{}; + for (size_t j = 0; j < a.getvectorsCount(); ++j) { + c.setVector(j, a.getVector(j) * b.getVector(j)); + } + return c; +} + +// check if all elements are equal +template <typename DataT, size_t N> +inline bool operator==(const Vector<DataT, N>& a, const Vector<DataT, N>& b) +{ + for (size_t j = 0; j < a.getvectorsCount(); ++j) { + if (any_of(a.getVector(j) != b.getVector(j))) { + return false; + } + } + return true; +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector3D.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector3D.h new file mode 100644 index 0000000000000..9338230130932 --- /dev/null +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/Vector3D.h @@ -0,0 +1,110 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Vector3D.h +/// \brief this is a simple 3D-matrix class with the possibility to resize the dimensions +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Oct 23, 2020 + +#ifndef ALICEO2_TPC_VECTOR3D_H_ +#define ALICEO2_TPC_VECTOR3D_H_ + +namespace o2 +{ +namespace tpc +{ + +/// this is a simple vector class which is used in the poisson solver class + +/// \tparam DataT the data type of the mStorage which is used during the calculations +template <typename DataT = double> +class Vector3D +{ + public: + /// Constructor for a tricubic interpolator + /// \param nr number of data points in r directions + /// \param nz number of data points in r directions + /// \param nphi number of data points in r directions + Vector3D(const unsigned int nr, const unsigned int nz, const unsigned int nphi) : mNr{nr}, mNz{nz}, mNphi{nphi}, mStorage{nr * nz * nphi} {}; + + /// default constructor + Vector3D() = default; + + /// operator to set the values + DataT& operator()(const unsigned int iR, const unsigned int iZ, const unsigned int iPhi) + { + return mStorage[getIndex(iR, iZ, iPhi)]; + } + + /// operator to read the values + const DataT& operator()(const unsigned int iR, const unsigned int iZ, const unsigned int iPhi) const + { + return mStorage[getIndex(iR, iZ, iPhi)]; + } + + /// operator to directly access the values + DataT& operator[](const unsigned int index) + { + return mStorage[index]; + } + + const DataT& operator[](const unsigned int index) const + { + return mStorage[index]; + } + + /// \param iR index in r direction + /// \param iZ index in z direction + /// \param iPhi index in phi direction + /// \return returns the index for given indices + int getIndex(const unsigned int iR, const unsigned int iZ, const unsigned int iPhi) const + { + return iR + mNr * (iZ + mNz * iPhi); + } + + /// resize the vector + /// \param nr number of data points in r directions + /// \param nz number of data points in r directions + /// \param nphi number of data points in r directions + void resize(const unsigned int nr, const unsigned int nz, const unsigned int nphi) + { + mNr = nr; + mNz = nz; + mNphi = nphi; + mStorage.resize(nr * nz * nphi); + } + + const auto& data() const { return mStorage; } + auto& data() { return mStorage; } + + unsigned int getNr() const { return mNr; } ///< get number of data points in r direction + unsigned int getNz() const { return mNz; } ///< get number of data points in z direction + unsigned int getNphi() const { return mNphi; } ///< get number of data points in phi direction + unsigned int size() const { return mStorage.size; } ///< get number of data points + + auto begin() const { return mStorage.begin(); } + auto begin() { return mStorage.begin(); } + + auto end() const { return mStorage.end(); } + auto end() { return mStorage.end(); } + + private: + unsigned int mNr{}; ///< number of data points in r direction + unsigned int mNz{}; ///< number of data points in z direction + unsigned int mNphi{}; ///< number of data points in phi direction + std::vector<DataT> mStorage{}; ///< vector containing the data +}; + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/spacecharge/macro/calculateDistortionsCorrections.C b/Detectors/TPC/spacecharge/macro/calculateDistortionsCorrections.C new file mode 100644 index 0000000000000..4337f355fcf67 --- /dev/null +++ b/Detectors/TPC/spacecharge/macro/calculateDistortionsCorrections.C @@ -0,0 +1,382 @@ +// g++ -o spacecharge ~/alice/O2/Detectors/TPC/spacecharge/macro/calculateDistortionsCorrections.C -I ~/alice/sw/osx_x86-64/FairLogger/latest/include -L ~/alice/sw/osx_x86-64/FairLogger/latest/lib -I$O2_ROOT/include -L$O2_ROOT/lib -lO2TPCSpacecharge -lO2CommonUtils -std=c++17 -I$ROOTSYS/include -L$ROOTSYS/lib -lCore -L$VC_ROOT/lib -lVc -I$VC_ROOT/include -Xpreprocessor -fopenmp -I/usr/local/include -L/usr/local/lib -lomp -O3 -ffast-math -lFairLogger -lRIO +#include "TPCSpaceCharge/SpaceCharge.h" +#include <iostream> +#include <chrono> +#include <array> +#include "CommonUtils/TreeStreamRedirector.h" + +template <typename DataT> +void calculateDistortionsAnalytical(const int sides = 0, const int globalEFieldTypeAna = 1, const int globalDistTypeAna = 1, const int eFieldTypeAna = 1, const int usePoissonSolverAna = 1, const int nSteps = 1, const int simpsonIterations = 3, const int nThreads = -1); + +template <typename DataT> +void calculateDistortionsFromHist(const char* path, const char* histoName, const int sides, const int globalEFieldType = 1, const int globalDistType = 1, const int nSteps = 1, const int simpsonIterations = 3, const int nThreads = -1); + +int getSideStart(const int sides); +int getSideEnd(const int sides); + +/// \param sides set which sides will be simulated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +/// \param nZVertices number of vertices of the grid in z direction +/// \param nRVertices number of vertices of the grid in z direction +/// \param nPhiVertices number of vertices of the grid in z direction +/// \param globalEFieldTypeAna setting for global distortions/corrections: 0: using electric field, 1: using local dis/corr interpolator +/// \param globalDistTypeAna setting for global distortions: 0: standard method, 1: interpolation of global corrections +/// \param eFieldTypeAna setting for electrc field: 0: analytical formula, 1: tricubic interpolator +/// \param usePoissonSolverAna setting for use poisson solver or analytical formula for potential: 0: analytical formula, 1: poisson solver +/// \param nSteps number of which are used for calculation of distortions/corrections per z-bin +/// \param simpsonIterations number of iterations used in the simpson intergration +/// \param nThreads number of threads which are used (if the value is -1 all threads should be used) +template <typename DataT> +void calcDistAna(const int sides = 0, const unsigned short nZVertices = 129, const unsigned short nRVertices = 129, const unsigned short nPhiVertices = 180, const int globalEFieldTypeAna = 1, const int globalDistTypeAna = 1, const int eFieldTypeAna = 1, const int usePoissonSolverAna = 1, const int nSteps = 1, const int simpsonIterations = 3, const int nThreads = -1) +{ + o2::tpc::SpaceCharge<DataT>::setGrid(nZVertices, nRVertices, nPhiVertices); + calculateDistortionsAnalytical<DataT>(sides, globalEFieldTypeAna, globalDistTypeAna, eFieldTypeAna, usePoissonSolverAna, nSteps, simpsonIterations, nThreads); +} + +/// \param path path to the root file containing the 3D density histogram +/// \param histoName name of the histogram in the root file +/// \param nZVertices number of vertices of the grid in z direction +/// \param nRVertices number of vertices of the grid in z direction +/// \param nPhiVertices number of vertices of the grid in z direction/// \param sides setting which sides will be processed: 0: A- and C-Side, 1: A-Side, 2: C-Side +/// \param globalEFieldType setting for global distortions/corrections: 0: using electric field, 1: using local dis/corr interpolator +/// \param globalDistType setting for global distortions: 0: standard method, 1: interpolation of global corrections +/// \param nSteps number of which are used for calculation of distortions/corrections per z-bin +/// \param simpsonIterations number of iterations used in the simpson intergration +/// \param nThreads number of threads which are used (if the value is -1 all threads should be used) +void calcDistFromHist(const char* path, const char* histoName, const unsigned short nZVertices = 129, const unsigned short nRVertices = 129, const unsigned short nPhiVertices = 180, const int sides = 0, const int globalEFieldType = 1, const int globalDistType = 1, const int nSteps = 1, const int simpsonIterations = 3, const int nThreads = -1) +{ + o2::tpc::SpaceCharge<double>::setGrid(nZVertices, nRVertices, nPhiVertices); + calculateDistortionsFromHist<double>(path, histoName, sides, globalEFieldType, globalDistType, nSteps, simpsonIterations, nThreads); +} + +/// \param spaceChargeCalc SpaceCharge object in which the calculations are performed +/// \param anaFields struct containing the analytical electric fields potential, space charge +/// \param fileOut output file where the calculated values are stored +/// \param side side of the TPC +/// \param globalEFieldType settings for global distortions/corrections: 0: using electric field for calculation of global distortions/corrections, 1: using local dis/corr interpolator for calculation of global distortions/corrections +/// \param globalDistType settings for global distortions: 0: standard method (start calculation of global distortion at each voxel in the tpc and follow electron drift to readout -slow-), 1: interpolation of global corrections (use the global corrections to apply an iterative approach to obtain the global distortions -fast-) +/// \param eFieldType setting for the electric field: 0: use analytical formula for the eletrical field for all calculations, 1: use the tricubic interpolator for the electric field +/// \param usePoissonSolver use poisson solver to calculate the potential or get the potential from the analytical formula 0: use analytical formula, 1: use poisson solver to calculate the potential (also calculates Efields using the obtained potential) +template <typename DataT> +void calculateDistortionsCorrectionsAnalytical(o2::tpc::SpaceCharge<DataT>& spaceChargeCalc, o2::tpc::AnalyticalFields<DataT> anaFields, const int globalEFieldType, const int eFieldType, const int globalDistType, const int usePoissonSolver) +{ + using timer = std::chrono::high_resolution_clock; + + std::cout << "====== STARTING CALCULATIION OF DISTORTIONS AND CORRECTIONS BY USING A ANALYTICAL FORMULA AS INPUT ======" << std::endl; + std::cout << "bins in z: " << spaceChargeCalc.getNZVertices() << std::endl; + std::cout << "bins in r: " << spaceChargeCalc.getNRVertices() << std::endl; + std::cout << "bins in phi: " << spaceChargeCalc.getNPhiVertices() << std::endl; + + const std::array<std::string, 2> sGlobalType{"Electric fields", "local distortion/correction interpolator"}; + std::cout << "calculation of global distortions and corrections are performed by using: " << sGlobalType[globalEFieldType] << std::endl; + + const std::array<std::string, 2> sGlobalDistType{"Standard method", "interpolation of global corrections"}; + std::cout << "calculation of global distortions performed by following method: " << sGlobalDistType[globalDistType] << std::endl; + + const std::array<std::string, 2> sEfieldType{"analytical formula", "tricubic interpolator"}; + std::cout << "Using the E-fields from: " << sEfieldType[eFieldType] << std::endl; + + const std::array<std::string, 2> sUsePoissonSolver{"analytical formula", "poisson solver"}; + std::cout << "Using the Potential from: " << sUsePoissonSolver[usePoissonSolver] << std::endl; + std::cout << std::endl; + + const o2::tpc::Side side = anaFields.getSide(); + spaceChargeCalc.setChargeDensityFromFormula(anaFields); + + auto startTotal = timer::now(); + + if (usePoissonSolver == 1) { + spaceChargeCalc.setPotentialBoundaryFromFormula(anaFields); + auto start = timer::now(); + spaceChargeCalc.poissonSolver(side); + auto stop = timer::now(); + std::chrono::duration<float> time = stop - start; + std::cout << "poissonSolver: " << time.count() << std::endl; + } else { + spaceChargeCalc.setPotentialFromFormula(anaFields); + } + + if (usePoissonSolver == 1) { + auto start = timer::now(); + spaceChargeCalc.calcEField(side); + auto stop = timer::now(); + std::chrono::duration<float> time = stop - start; + std::cout << "electric field calculation: " << time.count() << std::endl; + } else { + spaceChargeCalc.setEFieldFromFormula(anaFields); + } + + const auto numEFields = spaceChargeCalc.getElectricFieldsInterpolator(side); + auto start = timer::now(); + const auto dist = o2::tpc::SpaceCharge<DataT>::Type::Distortions; + (eFieldType == 1) ? spaceChargeCalc.calcLocalDistortionsCorrections(dist, numEFields) : spaceChargeCalc.calcLocalDistortionsCorrections(dist, anaFields); // local distortion calculation + auto stop = timer::now(); + std::chrono::duration<float> time = stop - start; + std::cout << "local distortions analytical: " << time.count() << std::endl; + + start = timer::now(); + const auto corr = o2::tpc::SpaceCharge<DataT>::Type::Corrections; + (eFieldType == 1) ? spaceChargeCalc.calcLocalDistortionsCorrections(corr, numEFields) : spaceChargeCalc.calcLocalDistortionsCorrections(corr, anaFields); // local correction calculation + stop = timer::now(); + time = stop - start; + std::cout << "local corrections analytical: " << time.count() << std::endl; + + start = timer::now(); + const auto lCorrInterpolator = spaceChargeCalc.getLocalCorrInterpolator(side); + if (globalEFieldType == 1) { + spaceChargeCalc.calcGlobalCorrections(lCorrInterpolator); + } else if (eFieldType == 1) { + spaceChargeCalc.calcGlobalCorrections(numEFields); + } else { + spaceChargeCalc.calcGlobalCorrections(anaFields); + } + + stop = timer::now(); + time = stop - start; + std::cout << "global corrections analytical: " << time.count() << std::endl; + + start = timer::now(); + const auto lDistInterpolator = spaceChargeCalc.getLocalDistInterpolator(side); + if (globalDistType == 0) { + if (globalEFieldType == 1) { + spaceChargeCalc.calcGlobalDistortions(lDistInterpolator); + } else if (eFieldType == 1) { + spaceChargeCalc.calcGlobalDistortions(numEFields); + } else { + spaceChargeCalc.calcGlobalDistortions(anaFields); + } + } else { + const auto globalCorrInterpolator = spaceChargeCalc.getGlobalCorrInterpolator(side); + spaceChargeCalc.calcGlobalDistWithGlobalCorrIterative(globalCorrInterpolator); + } + stop = timer::now(); + time = stop - start; + std::cout << "global distortions analytical: " << time.count() << std::endl; + + auto stopTotal = timer::now(); + time = stopTotal - startTotal; + std::cout << "====== everything is done. Total Time: " << time.count() << std::endl; + std::cout << std::endl; +} + +template <typename DataT> +void writeToTree(o2::tpc::SpaceCharge<DataT>& spaceCharge3D, o2::utils::TreeStreamRedirector& pcstream, const o2::tpc::Side side) +{ + for (size_t iPhi = 0; iPhi < spaceCharge3D.getNPhiVertices(); ++iPhi) { + for (size_t iR = 0; iR < spaceCharge3D.getNRVertices(); ++iR) { + for (size_t iZ = 0; iZ < spaceCharge3D.getNZVertices(); ++iZ) { + auto ldistR = spaceCharge3D.getLocalDistR(iZ, iR, iPhi, side); + auto ldistZ = spaceCharge3D.getLocalDistZ(iZ, iR, iPhi, side); + auto ldistRPhi = spaceCharge3D.getLocalDistRPhi(iZ, iR, iPhi, side); + auto lcorrR = spaceCharge3D.getLocalCorrR(iZ, iR, iPhi, side); + auto lcorrZ = spaceCharge3D.getLocalCorrZ(iZ, iR, iPhi, side); + auto lcorrRPhi = spaceCharge3D.getLocalCorrRPhi(iZ, iR, iPhi, side); + + auto lvecdistR = spaceCharge3D.getLocalVecDistR(iZ, iR, iPhi, side); + auto lvecdistZ = spaceCharge3D.getLocalVecDistZ(iZ, iR, iPhi, side); + auto lvecdistRPhi = spaceCharge3D.getLocalVecDistRPhi(iZ, iR, iPhi, side); + auto lveccorrR = spaceCharge3D.getLocalVecCorrR(iZ, iR, iPhi, side); + auto lveccorrZ = spaceCharge3D.getLocalVecCorrZ(iZ, iR, iPhi, side); + auto lveccorrRPhi = spaceCharge3D.getLocalVecCorrRPhi(iZ, iR, iPhi, side); + + auto distR = spaceCharge3D.getGlobalDistR(iZ, iR, iPhi, side); + auto distZ = spaceCharge3D.getGlobalDistZ(iZ, iR, iPhi, side); + auto distRPhi = spaceCharge3D.getGlobalDistRPhi(iZ, iR, iPhi, side); + auto corrR = spaceCharge3D.getGlobalCorrR(iZ, iR, iPhi, side); + auto corrZ = spaceCharge3D.getGlobalCorrZ(iZ, iR, iPhi, side); + auto corrRPhi = spaceCharge3D.getGlobalCorrRPhi(iZ, iR, iPhi, side); + + // distort then correct + auto radius = spaceCharge3D.getRVertex(iR, side); + auto z = spaceCharge3D.getZVertex(iZ, side); + auto phi = spaceCharge3D.getPhiVertex(iPhi, side); + DataT corrRDistPoint{}; + DataT corrZDistPoint{}; + DataT corrRPhiDistPoint{}; + + const DataT zDistorted = z + distZ; + const DataT radiusDistorted = radius + distR; + const DataT phiDistorted = spaceCharge3D.regulatePhi(phi + distRPhi / radius, side); + spaceCharge3D.getCorrectionsCyl(zDistorted, radiusDistorted, phiDistorted, side, corrZDistPoint, corrRDistPoint, corrRPhiDistPoint); + corrRPhiDistPoint *= radius / radiusDistorted; + + auto eZ = spaceCharge3D.getEz(iZ, iR, iPhi, side); + auto eR = spaceCharge3D.getEr(iZ, iR, iPhi, side); + auto ePhi = spaceCharge3D.getEphi(iZ, iR, iPhi, side); + auto pot = spaceCharge3D.getPotential(iZ, iR, iPhi, side); + auto charge = spaceCharge3D.getDensity(iZ, iR, iPhi, side); + + auto xPos = spaceCharge3D.getXFromPolar(radius, phi); + auto yPos = spaceCharge3D.getYFromPolar(radius, phi); + + int nr = spaceCharge3D.getNRVertices(); + int nz = spaceCharge3D.getNZVertices(); + int nphi = spaceCharge3D.getNPhiVertices(); + int iSide = side; + + pcstream << "distortions" + /// numer of bins + << "nR=" << nr + << "nPhi=" << nphi + << "nZ=" << nz + // bin indices + << "ir=" << iR + << "iz=" << iZ + << "iphi=" << iPhi + // coordinates + << "r=" << radius + << "z=" << z + << "x=" << xPos + << "y=" << yPos + << "phi=" << phi + // local distortions + << "ldistR=" << ldistR + << "ldistZ=" << ldistZ + << "ldistRPhi=" << ldistRPhi + // local corrections + << "lcorrR=" << lcorrR + << "lcorrZ=" << lcorrZ + << "lcorrRPhi=" << lcorrRPhi + // local distortion vector + << "lvecdistR=" << lvecdistR + << "lvecdistZ=" << lvecdistZ + << "lvecdistRPhi=" << lvecdistRPhi + // local correction vector + << "lveccorrR=" << lveccorrR + << "lveccorrZ=" << lveccorrZ + << "lveccorrRPhi=" << lveccorrRPhi + // global distortions + << "distR=" << distR + << "distZ=" << distZ + << "distRPhi=" << distRPhi + // global corrections + << "corrR=" << corrR + << "corrZ=" << corrZ + << "corrRPhi=" << corrRPhi + // correction after distortion applied (test for consistency) + << "corrRDistortedPoint=" << corrRDistPoint + << "corrRPhiDistortedPoint=" << corrRPhiDistPoint + << "corrZDistortedPoint=" << corrZDistPoint + // electric fields etc. + << "Er=" << eR + << "Ez=" << eZ + << "Ephi=" << ePhi + << "potential=" << pot + << "charge=" << charge + << "side=" << iSide + << "\n"; + } + } + } +} + +/// \param globalEFieldTypeAna setting for global distortions/corrections: 0: using electric field, 1: using local dis/corr interpolator +/// \param globalDistTypeAna setting for global distortions: 0: standard method, 1: interpolation of global corrections +/// \param eFieldTypeAna setting for electrc field: 0: analytical formula, 1: tricubic interpolator +/// \param usePoissonSolverAna setting for use poisson solver or analytical formula for potential: 0: analytical formula, 1: poisson solver +/// \param nSteps number of which are used for calculation of distortions/corrections per z-bin +/// \param simpsonIterations number of iterations used in the simpson intergration +template <typename DataT = double> +void calculateDistortionsAnalytical(const int sides, const int globalEFieldTypeAna, const int globalDistTypeAna, const int eFieldTypeAna, const int usePoissonSolverAna, const int nSteps, const int simpsonIterations, const int nThreads) +{ + const auto integrationStrategy = o2::tpc::SpaceCharge<DataT>::IntegrationStrategy::SimpsonIterative; + o2::tpc::SpaceCharge<DataT> spaceCharge3D; + spaceCharge3D.setOmegaTauT1T2(0.32f, 1, 1); + spaceCharge3D.setNStep(nSteps); + spaceCharge3D.setSimpsonNIteratives(simpsonIterations); + spaceCharge3D.setNumericalIntegrationStrategy(integrationStrategy); + if (nThreads != -1) { + spaceCharge3D.setNThreads(nThreads); + } + + // write to root file + o2::utils::TreeStreamRedirector pcstream(TString::Format("distortions_ana_nR%hu_nZ%hu_nPhi%hu_SimpsonsIter%i.root", spaceCharge3D.getNRVertices(), spaceCharge3D.getNZVertices(), spaceCharge3D.getNPhiVertices(), simpsonIterations).Data(), "RECREATE"); + + for (int iside = getSideStart(sides); iside < getSideEnd(sides); ++iside) { + std::cout << "side: " << iside << std::endl; + o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + o2::tpc::AnalyticalFields<DataT> anaFields(side); + calculateDistortionsCorrectionsAnalytical(spaceCharge3D, anaFields, globalEFieldTypeAna, eFieldTypeAna, globalDistTypeAna, usePoissonSolverAna); + pcstream.GetFile()->cd(); + writeToTree(spaceCharge3D, pcstream, side); + spaceCharge3D.dumpToFile(*pcstream.GetFile(), side); + } + + pcstream.GetFile()->cd(); + pcstream.Close(); +} + +/// \param path path to the root file containing the 3D density histogram +/// \param histoName name of the histogram in the root file +/// \param sides setting which sides will be processed: 0: A- and C-Side, 1: A-Side, 2: C-Side +/// \param globalEFieldType setting for global distortions/corrections: 0: using electric field, 1: using local dis/corr interpolator +/// \param globalDistType setting for global distortions: 0: standard method, 1: interpolation of global corrections +/// \param nSteps number of which are used for calculation of distortions/corrections per z-bin +/// \param simpsonIterations number of iterations used in the simpson intergration +template <typename DataT = double> +void calculateDistortionsFromHist(const char* path, const char* histoName, const int sides, const int globalEFieldType, const int globalDistType, const int nSteps, const int simpsonIterations, const int nThreads) +{ + using SC = o2::tpc::SpaceCharge<DataT>; + const auto integrationStrategy = o2::tpc::SpaceCharge<DataT>::IntegrationStrategy::SimpsonIterative; + SC spaceCharge3D; + spaceCharge3D.setOmegaTauT1T2(0.32f, 1, 1); + spaceCharge3D.setNStep(nSteps); + spaceCharge3D.setSimpsonNIteratives(simpsonIterations); + spaceCharge3D.setNumericalIntegrationStrategy(integrationStrategy); + if (nThreads != -1) { + spaceCharge3D.setNThreads(nThreads); + } + + // set density from input file + TFile fileOutSCDensity(path, "READ"); + spaceCharge3D.fillChargeDensityFromFile(fileOutSCDensity, histoName); + fileOutSCDensity.Close(); + + o2::utils::TreeStreamRedirector pcstream(TString::Format("distortions_real_nR%hu_nZ%hu_nPhi%hu_SimpsonsIter%i.root", spaceCharge3D.getNRVertices(), spaceCharge3D.getNZVertices(), spaceCharge3D.getNPhiVertices(), simpsonIterations).Data(), "RECREATE"); + for (int iside = getSideStart(sides); iside < getSideEnd(sides); ++iside) { + std::cout << "side: " << iside << std::endl; + o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + const auto distType = globalDistType == 0 ? SC::GlobalDistType::Standard : SC ::GlobalDistType::Fast; + spaceCharge3D.setGlobalDistType(distType); + const auto eType = globalEFieldType == 1 ? SC::GlobalDistCorrMethod::LocalDistCorr : SC::GlobalDistCorrMethod::ElectricalField; + spaceCharge3D.setGlobalDistCorrMethod(eType); + const bool calcLocalVectors = true; + spaceCharge3D.calculateDistortionsCorrections(side, calcLocalVectors); + // write to root file + pcstream.GetFile()->cd(); + writeToTree(spaceCharge3D, pcstream, side); + } + pcstream.GetFile()->cd(); + pcstream.Close(); + + // write global corrections and distortions to file + TFile fOut("spacecharge.root", "RECREATE"); + if (sides != 2) { + spaceCharge3D.dumpGlobalDistortions(fOut, o2::tpc::Side::A); + spaceCharge3D.dumpGlobalCorrections(fOut, o2::tpc::Side::A); + } + if (sides != 1) { + spaceCharge3D.dumpGlobalDistortions(fOut, o2::tpc::Side::C); + spaceCharge3D.dumpGlobalCorrections(fOut, o2::tpc::Side::C); + } + fOut.Close(); +} + +/// helper function to set the loop over the sides for the tpc +/// \param sides set for which sides the distortions/corrections will be calculated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +int getSideStart(const int sides) +{ + if (sides == 2) { + return 1; + } + return 0; +} + +/// helper function to set the loop over the sides for the tpc +/// \param sides set for which sides the distortions/corrections will be calculated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +int getSideEnd(const int sides) +{ + if (sides == 1) { + return 1; + } + return 2; +} diff --git a/Detectors/TPC/spacecharge/macro/createResidualDistortionObject.C b/Detectors/TPC/spacecharge/macro/createResidualDistortionObject.C new file mode 100644 index 0000000000000..2cb0ed8ecf2ad --- /dev/null +++ b/Detectors/TPC/spacecharge/macro/createResidualDistortionObject.C @@ -0,0 +1,213 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file createResidualDistortionObject.C +/// \brief This macro creates a SpaceCharge object with residual distortions from a fluctuating and an average space-charge density histogram and stores it in a file. +/// \author Ernst Hellbär, Goethe-Universität Frankfurt, ernst.hellbar@cern.ch + +#include <cmath> + +#include "TFile.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TPCSpaceCharge/SpaceCharge.h" +#include "MathUtils/Cartesian.h" + +using namespace o2::tpc; +using DataT = double; +using DataContainer = DataContainer3D<DataT>; + +// function declarations +void createSpaceCharge(o2::tpc::SpaceCharge<DataT>& spaceCharge, const char* path, const char* histoName, const int bSign, const int nThreads = -1); +void fillDistortionLookupMatrices(o2::tpc::SpaceCharge<DataT>& spaceChargeCalcFluc, o2::tpc::SpaceCharge<DataT>* spaceChargeCalcAvg, DataContainer matrixDistDr[2], DataContainer matrixDistDrphi[2], DataContainer matrixDistDz[2]); +void makeDebugTreeResiduals(o2::tpc::SpaceCharge<DataT>& calcFluc, o2::tpc::SpaceCharge<DataT>& calcAvg, o2::tpc::SpaceCharge<DataT>& spaceChargeRes); +/// Create a SpaceCharge object with residual distortions from a fluctuating and an average space-charge density histogram and write it to a file. +/// \param bSign sign of the B-field: -1 = negative, 0 = no B-field, 1 = positive +/// \param pathToHistoFile path to a file with the fluctuating and average histograms +/// \param histoFlucName name of the fluctuating histogram +/// \param histoAvgName name of the average histogram +void createResidualDistortionObject(int bSign, const char* pathToHistoFile = "InputSCDensityHistograms_8000events.root", const char* histoFlucName = "inputSCDensity3D_8000_0", const char* histoAvgName = "inputSCDensity3D_8000_avg", const int nThreads = -1, bool debug = false) +{ + /* + Usage: + root -l -b -q createResidualDistortionObject.C+\(-1,\"InputSCDensityHistograms_8000events.root\",\"inputSCDensity3D_8000_0\",\"inputSCDensity3D_8000_avg\",true\) + */ + + // Calculate fluctuating and average distortion and correction lookup tables + o2::tpc::SpaceCharge<DataT> scCalcFluc; + o2::tpc::SpaceCharge<DataT> scCalcAvg; + createSpaceCharge(scCalcFluc, pathToHistoFile, histoFlucName, bSign, nThreads); + createSpaceCharge(scCalcAvg, pathToHistoFile, histoAvgName, bSign, nThreads); + + // Create matrices and fill them with residual distortions. Create SpaceCharge object, assign residual distortion matrices to it and store it in the output file. + DataContainer matrixResDistDr[2]{DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices()), DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices())}; + DataContainer matrixResDistDrphi[2]{DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices()), DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices())}; + DataContainer matrixResDistDz[2]{DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices()), DataContainer(scCalcAvg.getNZVertices(), scCalcAvg.getNRVertices(), scCalcAvg.getNPhiVertices())}; + + fillDistortionLookupMatrices(scCalcFluc, &scCalcAvg, matrixResDistDr, matrixResDistDrphi, matrixResDistDz); + o2::tpc::SpaceCharge<DataT> spaceChargeRes; + spaceChargeRes.setDistortionLookupTables(matrixResDistDz[0], matrixResDistDr[0], matrixResDistDrphi[0], o2::tpc::Side::A); + spaceChargeRes.setDistortionLookupTables(matrixResDistDz[1], matrixResDistDr[1], matrixResDistDrphi[1], o2::tpc::Side::C); + + TFile fileOutput("ResidualDistortions.root", "recreate"); + spaceChargeRes.dumpGlobalDistortions(fileOutput, o2::tpc::Side::A); + spaceChargeRes.dumpGlobalDistortions(fileOutput, o2::tpc::Side::C); + + if (debug) { + makeDebugTreeResiduals(scCalcFluc, scCalcAvg, spaceChargeRes); + } +} + +/// calculate the distortions and corrections from a space-charge density histogram +/// \param spaceCharge input space-charge density object which will be filled +/// \param path path to a file with the histograms +/// \param histoName name of the histogram +/// \param bSign sign of the B-field: -1 = negative, 0 = no B-field, 1 = positive +/// \param nThreads number of threads which are used +void createSpaceCharge(o2::tpc::SpaceCharge<DataT>& spaceCharge, const char* path, const char* histoName, const int bSign, const int nThreads) +{ + const float omegaTau = -0.32 * bSign; + spaceCharge.setOmegaTauT1T2(omegaTau, 1, 1); + if (nThreads != -1) { + spaceCharge.setNThreads(nThreads); + } + // set density from input file + TFile fileOutSCDensity(path, "READ"); + spaceCharge.fillChargeDensityFromFile(fileOutSCDensity, histoName); + fileOutSCDensity.Close(); + + // calculate the distortions + spaceCharge.calculateDistortionsCorrections(o2::tpc::Side::A); + spaceCharge.calculateDistortionsCorrections(o2::tpc::Side::C); +} + +/// Store distortions from spaceChargeCalcFluc in the matrices provided. If providing an object with average space-charge distortions spaceChargeCalcAvg, the residual distortions (dist_fluctuation(xyzTrue) + corr_average(xyzDistorted)) will be stored. +/// \param spaceChargeCalcFluc fluctuating distortions object +/// \param spaceChargeCalcAvg average distortions object +/// \param matrixDistDr matrix to store radial distortions on the A and C side +/// \param matrixDistDrphi matrix to store rphi distortions on the A and C side +/// \param matrixDistDz matrix to store z distortions on the A and C side +void fillDistortionLookupMatrices(o2::tpc::SpaceCharge<DataT>& spaceChargeCalcFluc, o2::tpc::SpaceCharge<DataT>* spaceChargeCalcAvg, DataContainer matrixDistDr[2], DataContainer matrixDistDrphi[2], DataContainer matrixDistDz[2]) +{ + for (int iside = 0; iside < 2; ++iside) { + o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + for (int iphi = 0; iphi < spaceChargeCalcFluc.getNPhiVertices(); ++iphi) { + const auto phi = spaceChargeCalcFluc.getPhiVertex(iphi, side); + + for (int ir = 0; ir < spaceChargeCalcFluc.getNRVertices(); ++ir) { + const auto r = spaceChargeCalcFluc.getRVertex(ir, side); + + for (int iz = 0; iz < spaceChargeCalcFluc.getNZVertices(); ++iz) { + const auto z = spaceChargeCalcFluc.getZVertex(iz, side); + + // get fluctuating distortions + DataT distFlucdZ = 0; + DataT distFlucdR = 0; + DataT distFlucdRPhi = 0; + spaceChargeCalcFluc.getDistortionsCyl(z, r, phi, side, distFlucdZ, distFlucdR, distFlucdRPhi); + + // get average corrections if provided and add them to the fluctuating distortions + if (spaceChargeCalcAvg) { + const float zDistorted = z + distFlucdZ; + const float rDistorted = r + distFlucdR; + const float phiDistorted = phi + distFlucdRPhi / r; + DataT corrZDistPoint = 0; + DataT corrRDistPoint = 0; + DataT corrRPhiDistPoint = 0; + spaceChargeCalcAvg->getCorrectionsCyl(zDistorted, rDistorted, phiDistorted, side, corrZDistPoint, corrRDistPoint, corrRPhiDistPoint); + distFlucdZ += corrZDistPoint; + distFlucdR += corrRDistPoint; + distFlucdRPhi += corrRPhiDistPoint * r / rDistorted; + } + + // store (residual) distortions in the matrices + matrixDistDr[iside](ir, iz, iphi) = distFlucdR; + matrixDistDrphi[iside](ir, iz, iphi) = distFlucdRPhi; + matrixDistDz[iside](ir, iz, iphi) = distFlucdZ; + } + } + } + } +} + +/// Calculate and stream residual distortions from spaceChargeRes and from calcFluc and calcAvg for comparison. +/// \param calcFluc space charge object with fluctuation distortions +/// \param calcAvg space charge object with average distortions +/// \param spaceChargeRes space charge object with residual distortions +void makeDebugTreeResiduals(o2::tpc::SpaceCharge<DataT>& calcFluc, o2::tpc::SpaceCharge<DataT>& calcAvg, o2::tpc::SpaceCharge<DataT>& spaceChargeRes) +{ + o2::utils::TreeStreamRedirector pcstream("debugResidualDistortions.root", "recreate"); + for (int iside = 0; iside < 2; ++iside) { + o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + for (int iphi = 0; iphi < calcFluc.getNPhiVertices(); ++iphi) { + auto phi = calcFluc.getPhiVertex(iphi, side); + for (int ir = 0; ir < calcFluc.getNRVertices(); ++ir) { + auto r = calcFluc.getRVertex(ir, side); + DataT x = r * std::cos(phi); + DataT y = r * std::sin(phi); + for (int iz = 1; iz < calcFluc.getNZVertices(); ++iz) { + DataT z = calcFluc.getZVertex(iz, side); + + GlobalPosition3D posDistRes(x, y, z); + spaceChargeRes.distortElectron(posDistRes); + DataT xyzDistRes[3] = {posDistRes.x(), posDistRes.y(), posDistRes.z()}; + DataT distRes[3] = {posDistRes.x() - x, posDistRes.y() - y, posDistRes.z() - z}; + + DataT distFlucX = 0; + DataT distFlucY = 0; + DataT distFlucZ = 0; + calcFluc.getDistortions(x, y, z, side, distFlucX, distFlucY, distFlucZ); + + DataT xDistorted = x + distFlucX; + DataT yDistorted = y + distFlucY; + DataT zDistorted = z + distFlucZ; + + DataT corrAvgX = 0; + DataT corrAvgY = 0; + DataT corrAvgZ = 0; + calcAvg.getCorrections(xDistorted, yDistorted, zDistorted, side, corrAvgX, corrAvgY, corrAvgZ); + DataT xyzDistResTrue[3] = {xDistorted + corrAvgX, yDistorted + corrAvgY, zDistorted + corrAvgZ}; + DataT distResTrue[3] = {distFlucX + corrAvgX, distFlucY + corrAvgY, distFlucZ + corrAvgZ}; + + pcstream << "debug" + << "iside=" << iside + << "iphi=" << iphi + << "ir=" << ir + << "iz=" << iz + // original position + << "phi=" << phi + << "r=" << r + << "x=" << x + << "y=" << y + << "z=" << z + // position of distorted points + << "xRes=" << xyzDistRes[0] + << "yRes=" << xyzDistRes[1] + << "zRes=" << xyzDistRes[2] + // true position of distorted points + << "xResTrue=" << xyzDistResTrue[0] + << "yResTrue=" << xyzDistResTrue[1] + << "zResTrue=" << xyzDistResTrue[2] + // residual distortions + << "distX=" << distRes[0] + << "distY=" << distRes[1] + << "distZ=" << distRes[2] + // true residual distortions + << "distXTrue=" << distResTrue[0] + << "distYTrue=" << distResTrue[1] + << "distZTrue=" << distResTrue[2] + // + << "\n"; + } + } + } + } + pcstream.Close(); +} diff --git a/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C b/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C new file mode 100644 index 0000000000000..8983099c11afc --- /dev/null +++ b/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C @@ -0,0 +1,934 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file createSCHistosFromHits +/// \brief This macro implements the creation of space charge density maps from hit files. + +/* + Macro to create random space-charge density distributions from simulated TPC hits and calculated the corresponding integrated digital currents. The density distributions are used to calculated the space-charge distortions. + + Parallization (omp) can only be used if compiled with g++ and not with ROOT! Uncommented for now + Example: +g++ -o createSCHistosFromHits createSCHistosFromHits.C -I ~/alice/sw/osx_x86-64/FairLogger/latest/include -L ~/alice/sw/osx_x86-64/FairLogger/latest/lib -I /Users/matthias/alice/sw/osx_x86-64/FairRoot/latest/include/ -I$ROOTSYS/include -L$ROOTSYS/lib -lRIO -lCore -std=c++17 -I$O2_ROOT/include -L$O2_ROOT/lib -I$O2_ROOT/include/GPU -I /Users/matthias/alice/sw/osx_x86-64/Vc/latest/include/ -lO2TPCBase -lO2TPCSimulation -lO2CommonUtils -lHist -lMathCore -O3 -Xpreprocessor -fopenmp -I/usr/local/include -L/usr/local/lib -lomp -lfairlogger -lboost_system -lboost_filesystem + + Input: + - One o2sim_HitsTPC.root file for first studies + - List of o2sim_HitsTPC.root files + - Number of ion pile-up events to be used + - Ion drift velocity + + Outputs: + - CalDet Objects with 3D-IDCs, std::vector<float> with 1D-IDCs, std::vector<float> with 0D-IDCs (the vector has size 1), + - Granularity? + - Rows, pads at first + - Histograms with space-charge density + - Granularity + - Different for IDCs + - Same as distortions + - Objects of type SpaceCharge<> containing the density, global distortions, global corrections + + Algorithm: + 1) Choose n events randomly from list of o2sim_HitsTPC.root files + - n = number of ion pile-up events + - Assign global indices to single files + + 2) Place r-phi projection of hits randomly in z + - Take into account A, C side + - Electron transport + - Added: diffusion, average space-charge distortions (if provided) + - Could be added: static distortions, electron drift-time + - Ion transport + - Along straight lines + - Could be added: average space-charge distortions, static distortions + - Space charge: + - Apply epsilon + - Convert to charge (C) + - epsilon variations from IBF-map (has to be provided as input) + - IDC: + - Apply effective gain and digitize + - Convert z position to time of IDC measurement + - Gain variations from gain-map (has to be provided as input) + - Grouping of IDCs has not yet be determined + - Same or different for IDC and SC density? + - Integration over 1 ms steps in time + - r, phi: rows, pads + - Average over several rows, pads + + 3) Primary ionization + - Transport of ions + - Along straight lines + - Could be added: average space-charge distortions, static distortions + - 3D hit positions as starting points + - Calculate end points using z position of IBF slice + - Could be added: electron drift-time + + 4) Calculate distortions and corrections + - Corrections to be used for calibration studies + - Active area / volume only? + - Dead regions due to radial distortions + - Do we care about |eta|>0.9 ? + + TODO: + - replace hard coded constants (named constXXX and global constants) by O2 constants + - CalDet objects for IDCs? + - Array of nZ objects, one for each 1 ms + - Variation of ion drift time in IDCs and SC density? + - Make many smaller (~1000 event) CalDets / histos / maps and combine later? DONE + - For the final data for ML, first use only A side values for IDCs, density, corrections + - Later provide data for both sides? Fixed boundary at z = 0 required. + + Usage: + .L $SC/createSCHistosFromHits.C+ + + root -b -l -q $SC/createSCHistosFromHits.C+ +*/ + +#if !defined(__CLING__) || defined(__ROOTCLING__) +// root includes +#include "TFile.h" +#include "TH3F.h" +#include "TMath.h" +#include "TObjArray.h" +#include "TRandom.h" +#include "TString.h" +#include "TSystem.h" +#include "TTree.h" + +// O2 includes +#include "CommonUtils/TreeStreamRedirector.h" +#include "MathUtils/Utils.h" +#include "TPCBase/CalDet.h" +#include "TPCBase/CRU.h" +#include "TPCBase/Mapper.h" +#include "TPCBase/PadPos.h" +#include "TPCBase/ParameterDetector.h" +#include "TPCBase/ParameterGEM.h" +#include "TPCBase/ParameterElectronics.h" +#include "TPCBase/CDBInterface.h" +#include "TPCSimulation/ElectronTransport.h" +#include "TPCSimulation/GEMAmplification.h" +#include "TPCSimulation/SAMPAProcessing.h" +#include "TPCSimulation/Point.h" +#include "TPCSpaceCharge/SpaceCharge.h" +#include "TPCSpaceCharge/PoissonSolverHelpers.h" +#include "DataFormatsTPC/Defs.h" +#include "TPCSpaceCharge/SpaceChargeHelpers.h" + +#include <chrono> +// #include <omp.h> // comment in if using multithreading +#endif + +using namespace o2::tpc; +using CalPad = CalDet<float>; +using CalPadArr = CalArray<float>; + +static constexpr unsigned short NR = 129; // grid in r +static constexpr unsigned short NZ = 129; // grid in z +static constexpr unsigned short NPHI = 180; // grid in phi + +// Gas parameters +// const float mK0 = 2.92f; // in cm^2 / (Vs), reduced ion mobility K0 for Ne-CO2-N2 (90-10-5) with H2O content 130 ppm. Deisting thesis page 88 +// const float mTNull = 273.15f; // in K, zero temperature +// const float mTGas = 294.15f; // in K, TPC gas temperature corresponding to 21 degrees Celsius +// const float mVDriftIon = 1.2577968; // in cm / ms, ion drift velocity = K0 * TGas / TNull * 1 atm / Pmeasured * Ez0 * 1e-3. For Ne-CO2-N2 (90-10-5) with H2O content 130 ppm at Pmeasured = 1 atm. + +// TPC parameters +// const float mEz0 = 400.f; // in V / cm, nominal drift field in z direction +const float mZROC = o2::tpc::TPCParameters<double>::TPCZ0; // absolute - position of G1T +const float mRIFC = o2::tpc::TPCParameters<double>::IFCRADIUS; // inner field cage radius in cm +const float mROFC = o2::tpc::TPCParameters<double>::OFCRADIUS; // outer field cage radius in cm +const float mOmegatau = 0.32f; + +const char* outfnameHists = "spaceChargeDensityHist"; // name of the output file for the histograms +const char* outfnameIDC = "spaceChargeDensityIDC"; // name of the output file for the IDCs +const char* hisSCRandomName = "hisSCRandom"; // name of the histogram of the combined space charge density of IBF and PI +const char* hisSCIBFRandomName = "hisIBF"; // name of the histogram of the space charge density of IBF +const char* hisSCPIRandomName = "hisPI"; // name of the histogram of the space charge density of PI + +CalPad loadMap(std::string mapfile, std::string mapName); + +float get0DIDCs(const std::vector<float>& oneDIDC); +float get1DIDCs(const CalPad& calPad, const o2::tpc::Side side); + +void scale(TH3& hist, const float fac); +const std::string getNameSide(const o2::tpc::Side side, const char* name); +Side getSide(const float z) { return z < 0 ? Side::C : Side::A; } +int getSideStart(const int sides); +int getSideEnd(const int sides); + +/// Create SC density histograms and IDC containers from simulated TPC hits +/// An interaction rate of 50 kHz is assumed. Therefore, the ion drift time determines the number of ion pile-up events. +/// \param ionDriftTime ion drift time in ms. The value determines the number of bins in z/time direction of the histograms and IDCs ( 1 bin / ms / side). +/// \param nEvIon number of ion pile-up events +/// \param debug debug info streaming level +/// \param sides set which sides will be simulated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +/// \param inputfolder folder to the directory where the gain and epsilon map is stored. If an average distortion map is used, the distortion.root file should also be located there +/// \param distortionType sets the type of the electron distortions: 0->no distortions of electrons are applied, 1->average distortion of electrons. Distortions can be created by the makeDistortionsCorrections() function. +/// \nPhiBins number of phi bins the sc density histograms +/// \nRBins number of phi bins the sc density histograms +/// \nZBins number of phi bins the sc density histograms +void createSCHistosFromHits(const int ionDriftTime = 200, const int nEvIon = 1, const int sides = 0, const char* inputfolder = "", const int distortionType = 0, const int nPhiBins = 720, const int nRBins = 257, const int nZBins = 514 /*, const int nThreads = 1*/) +{ + o2::tpc::SpaceCharge<double>::setGrid(NZ, NR, NPHI); + + // load average distortions of electrons + SpaceCharge<double> spacecharge; + if (distortionType == 1) { + const std::string inpFileDistortions = Form("%sdistortions.root", inputfolder); + TFile fInp(inpFileDistortions.data(), "READ"); + for (int iside = getSideStart(sides); iside < getSideEnd(sides); ++iside) { + o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + spacecharge.setGlobalDistortionsFromFile(fInp, side); + } + } + + auto startTotal = std::chrono::high_resolution_clock::now(); + gRandom->SetSeed(0); + std::cout << "Seed is: " << gRandom->GetSeed() << std::endl; + + auto& cdb = CDBInterface::instance(); + cdb.setUseDefaults(); + + const static Mapper& mapper = Mapper::instance(); + + static GEMAmplification& gemAmplification = GEMAmplification::instance(); + gemAmplification.updateParameters(); + + static ElectronTransport& electronTransport = ElectronTransport::instance(); + electronTransport.updateParameters(); + + auto& eleParam = ParameterElectronics::Instance(); + static SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance(); + sampaProcessing.updateParameters(); + + const int nShapedPoints = eleParam.NShapedPoints; + std::vector<float> signalArray; + signalArray.resize(nShapedPoints); + + // load gain map + const std::string gainMapFile = Form("%sGainMap.root", inputfolder); + const std::string gainMapName = "GainMap"; + const CalPad gainMap = loadMap(gainMapFile, gainMapName); + + // load ibf map + const std::string ibfMapFile = Form("%sIBFMap.root", inputfolder); + const std::string ibfMapName = "Gain"; + const CalPad ibfMap = loadMap(ibfMapFile, ibfMapName); + + const std::string hitFileList = Form("%so2sim_HitsTPC.list", inputfolder); + TObjArray* arrHitFiles = (TObjArray*)gSystem->GetFromPipe(TString::Format("cat %s", hitFileList.data()).Data()).Tokenize("\n"); + const int nHitFiles = arrHitFiles->GetEntries(); // number of files with TPC hits + std::cout << "Number of Hit Files: " << nHitFiles << std::endl; + + std::array<TH3F, SIDES> hisSCRandom{TH3F(getNameSide(Side::A, hisSCRandomName).data(), getNameSide(Side::A, hisSCRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, 0, mZROC), + TH3F(getNameSide(Side::C, hisSCRandomName).data(), getNameSide(Side::C, hisSCRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, -mZROC, 0)}; + + std::array<TH3F, SIDES> hisIBF{TH3F(getNameSide(Side::A, hisSCIBFRandomName).data(), getNameSide(Side::A, hisSCIBFRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, 0, mZROC), + TH3F(getNameSide(Side::C, hisSCIBFRandomName).data(), getNameSide(Side::C, hisSCIBFRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, -mZROC, 0)}; + + std::array<TH3F, SIDES> hisPI{TH3F(getNameSide(Side::A, hisSCPIRandomName).data(), getNameSide(Side::A, hisSCPIRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, 0, mZROC), + TH3F(getNameSide(Side::C, hisSCPIRandomName).data(), getNameSide(Side::C, hisSCPIRandomName).data(), nPhiBins, 0, ::TWOPI, nRBins, mRIFC, mROFC, nZBins, -mZROC, 0)}; + + const int nZBinsSide = ionDriftTime; + // vector with CalDet objects for IDCs (1 / ms) + std::vector<CalPad> vecIDC(nZBinsSide); + for (auto& calpadIDC : vecIDC) { + calpadIDC = CalPad("IDC", PadSubset::ROC); + } + + std::vector<CalPad> vecCalCharge(nZBinsSide); + for (auto& calpadIDC : vecCalCharge) { + calpadIDC = CalPad("charge", PadSubset::ROC); + } + + for (int iev = 0; iev < nEvIon; ++iev) { + std::cout << " " << std::endl; + std::cout << "event: " << iev + 1 << " from " << nEvIon << " events" << std::endl; + const int indexHitFile = gRandom->Uniform(0, nHitFiles - 1); + std::cout << "indexHitFile: " << indexHitFile << std::endl; + const std::string hitFileName = arrHitFiles->At(indexHitFile)->GetName(); + std::cout << "hitFileName: " << hitFileName.data() << std::endl; + + std::unique_ptr<TFile> hitFile = std::unique_ptr<TFile>(TFile::Open(hitFileName.data())); + std::unique_ptr<TTree> hitTree = std::unique_ptr<TTree>((TTree*)hitFile->Get("o2sim")); + const int nEvents = hitTree->GetEntries(); // number of simulated events per hit file + + // vector of HitGroups per sector + std::vector<::HitGroup>* arrSectors[::Sector::MAXSECTOR]; + for (int isec = 0; isec < ::Sector::MAXSECTOR; ++isec) { + arrSectors[isec] = nullptr; + std::stringstream sectornamestr; + sectornamestr << "TPCHitsShiftedSector" << isec; + hitTree->SetBranchAddress(sectornamestr.str().c_str(), &arrSectors[isec]); + } + + // 1) Choose n events randomly from list of o2sim_HitsTPC.root files + const int indexEv = gRandom->Uniform(0, nEvents - 1); + std::cout << "index of event which is chosen: " << indexEv << std::endl; + hitTree->GetEntry(indexEv); + + // randomize ion drift length for position of ibf disk and dirft of primary ionization + const float driftLIons = gRandom->Uniform(0., mZROC); + + // rotate event by random phi angle + const float phiRot = gRandom->Uniform(0, ::TWOPI); + + // z position of ions + const float zIonsIBF = mZROC - driftLIons; + const int zbinIDC = static_cast<int>(zIonsIBF / mZROC * ionDriftTime); + + // in case driftLIons = 0 avoid seg fault + if (zbinIDC == nZBinsSide) { + continue; + } + + int startSec = 0; + int endSec = ::Sector::MAXSECTOR; + + // set sector loop depending on the side which was set + if (sides == 1) { // A-side + endSec /= 2; + } else if (sides == 2) { // C-side + startSec = endSec / 2; + } + + // #pragma omp parallel for num_threads(nThreads) // comment in for using multi threading + for (int isec = startSec; isec < endSec; ++isec) { // loop over sectors + auto vecTracks = arrSectors[isec]; + for (auto& hitsTrack : *vecTracks) { + for (size_t ihit = 0; ihit < hitsTrack.getSize(); ++ihit) { + const auto& elHit = hitsTrack.getHit(ihit); + GlobalPosition3D posHit(elHit.GetX(), elHit.GetY(), elHit.GetZ()); + const int nEle = static_cast<int>(elHit.GetEnergyLoss()); + if (nEle <= 0) { + continue; + } + + // phi rotation of hit + const float rHit = posHit.rho(); + float phiHit = posHit.phi() + phiRot; + o2::math_utils::bringTo02PiGen(phiHit); + posHit.SetX(rHit * std::cos(phiHit)); + posHit.SetY(rHit * std::sin(phiHit)); + + // z position of ions + float zIonsPI = std::abs(posHit.Z()) - driftLIons; + float zIonsIBFTmp = zIonsIBF; + if (posHit.Z() < 0) { + zIonsIBFTmp *= -1; + zIonsPI *= -1; + } + + // Primary ionization + if (std::signbit(zIonsPI) == std::signbit(posHit.Z())) { + const Side side = getSide(posHit.Z()); + const auto binPhi = hisSCRandom[side].GetXaxis()->FindBin(phiHit); + const auto binR = hisSCRandom[side].GetYaxis()->FindBin(rHit); + const auto binZ = hisSCRandom[side].GetZaxis()->FindBin(zIonsPI); + const auto globBin = hisSCRandom[side].GetBin(binPhi, binR, binZ); + hisSCRandom[side].AddBinContent(globBin, nEle); + hisPI[side].AddBinContent(globBin, nEle); + } + + // apply distortion of electron if specified + if (distortionType == 1) { + spacecharge.distortElectron(posHit); + } + + // IBF: Place r-phi projection of hits randomly in z + float driftTimeEle = 0.f; + for (int iele = 0; iele < nEle; iele++) { + const GlobalPosition3D posHitDiff = electronTransport.getElectronDrift(posHit, driftTimeEle); + float phiHitDiff = posHitDiff.phi(); + o2::math_utils::bringTo02PiGen(phiHitDiff); + + const DigitPos digiPadPos = mapper.findDigitPosFromGlobalPosition(posHitDiff); + if (!digiPadPos.isValid()) { + continue; + } + + // Attachment + if (electronTransport.isElectronAttachment(driftTimeEle)) { + continue; + } + + const auto padPos = digiPadPos.getPadPos(); + const auto row = static_cast<size_t>(padPos.getRow()); + const auto pad = static_cast<size_t>(padPos.getPad()); + const CRU cru = digiPadPos.getCRU(); + + const int gain = static_cast<int>(gemAmplification.getEffectiveStackAmplification() * gainMap.getValue(cru, row, pad)); + if (gain == 0) { + continue; + } + const int epsilon = static_cast<int>(gain * ibfMap.getValue(cru, row, pad) * 0.01); // IBF value is in % -> convert to absolute value + + const Side sideIBF = getSide(zIonsIBFTmp); + const auto binPhi = hisSCRandom[sideIBF].GetXaxis()->FindBin(phiHitDiff); + const auto binR = hisSCRandom[sideIBF].GetYaxis()->FindBin(posHitDiff.rho()); + const auto binZ = hisSCRandom[sideIBF].GetZaxis()->FindBin(zIonsIBFTmp); + + const auto globBin = hisSCRandom[sideIBF].GetBin(binPhi, binR, binZ); + hisSCRandom[sideIBF].AddBinContent(globBin, epsilon); + hisIBF[sideIBF].AddBinContent(globBin, epsilon); + + // convert electrons to ADC signal + const float adcsignal = sampaProcessing.getADCvalue(static_cast<float>(gain)); + sampaProcessing.getShapedSignal(adcsignal, driftTimeEle, signalArray); + const float signaladc = std::accumulate(signalArray.begin(), signalArray.end(), 0.f); + + // fill pads with adc value + auto padPosGlobal = digiPadPos.getGlobalPadPos(); + auto rowRoc = static_cast<size_t>(padPosGlobal.getRow()); + if (cru.roc().isOROC()) { + rowRoc -= mapper.getNumberOfRowsROC(ROC(0)); + } + + const float charge = vecIDC[zbinIDC].getValue(cru, row, pad) + signaladc; + ((CalPadArr&)(vecIDC[zbinIDC].getCalArray(static_cast<size_t>(cru.roc().getRoc())))).setValue(rowRoc, pad, charge); + + const float chargeEpsilon = vecCalCharge[zbinIDC].getValue(cru, row, pad) + epsilon; + ((CalPadArr&)(vecCalCharge[zbinIDC].getCalArray(static_cast<size_t>(cru.roc().getRoc())))).setValue(rowRoc, pad, chargeEpsilon); + } // electron loop + } // hit loop + } // track loop + } // sector loop + + for (int isec = 0; isec < ::Sector::MAXSECTOR; ++isec) { + delete arrSectors[isec]; + } + } // event loop + + // normalize histograms to Q / cm^3 / epsilon0 + for (int iside = getSideStart(sides); iside < getSideEnd(sides); ++iside) { + o2::tpc::SpaceCharge<float>::normalizeHistoQVEps0(hisSCRandom[iside]); + o2::tpc::SpaceCharge<float>::normalizeHistoQVEps0(hisIBF[iside]); + o2::tpc::SpaceCharge<float>::normalizeHistoQVEps0(hisPI[iside]); + } + + auto stopTotal = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double> elapsedTotal = stopTotal - startTotal; + printf("Total time: %f sec for %d events\n", elapsedTotal.count(), nEvIon); + + TFile fOut(Form("%s.root", outfnameHists), "RECREATE"); + // always store both sides! + for (int iside = 0; iside < 2; ++iside) { + hisSCRandom[iside].Write(); + hisIBF[iside].Write(); + hisPI[iside].Write(); + } + + // write idcs in different files than the histogram to be able to use "hadd" for merging + // make 1D-IDCs and 0D-IDCs + std::vector<float> idc1DASide(nZBinsSide); // 1D-merged idc + std::vector<float> idc1DCSide(nZBinsSide); // 1D-merged idc + + std::vector<float> idc0DASide(1); // 0D-merged idc (A single float value cannot be written to file) TODO find better solution + std::vector<float> idc0DCSide(1); // 0D-merged idc (A single float value cannot be written to file) TODO find better solution + + // calculate 1D IDC + for (unsigned long iSlice = 0; iSlice < vecIDC.size(); ++iSlice) { + const auto vecCalArr = vecIDC[iSlice]; + if (sides == 1) { // A-side + idc1DASide[iSlice] = get1DIDCs(vecCalArr, o2::tpc::Side::A); + } else if (sides == 2) { // C-side + idc1DCSide[iSlice] = get1DIDCs(vecCalArr, o2::tpc::Side::C); + } else { + idc1DASide[iSlice] = get1DIDCs(vecCalArr, o2::tpc::Side::A); + idc1DCSide[iSlice] = get1DIDCs(vecCalArr, o2::tpc::Side::C); + } + } + + if (sides == 1) { // A-side + idc0DASide[0] = get0DIDCs(idc1DASide); + } else if (sides == 2) { // C-side + idc0DCSide[0] = get0DIDCs(idc1DCSide); + } else { + idc0DASide[0] = get0DIDCs(idc1DASide); + idc0DCSide[0] = get0DIDCs(idc1DCSide); + } + + std::cout << "output path is: " << outfnameIDC << std::endl; + TFile fIDC(Form("%s.root", outfnameIDC), "RECREATE"); + fIDC.WriteObject(&vecIDC, "IDC"); + fIDC.WriteObject(&vecCalCharge, "charge"); + fIDC.WriteObject(&idc1DASide, "IDC_1D_A_Side"); + fIDC.WriteObject(&idc1DCSide, "IDC_1D_C_Side"); + fIDC.WriteObject(&idc0DASide, "IDC_0D_A_Side"); + fIDC.WriteObject(&idc0DCSide, "IDC_0D_C_Side"); +} + +/// load gain or ibf map +/// \param mapfile file to the map +/// \param mapName name of the object +CalPad loadMap(std::string mapfile, std::string mapName) +{ + TFile f(mapfile.data(), "READ"); + CalPad* map = nullptr; + f.GetObject(mapName.data(), map); + + if (!map) { + std::cout << mapfile.data() << " NOT FOUND! RETURNING! " << std::endl; + } + + f.Close(); + return *map; +} + +/// create average IDCs from random maps +/// \param files vetor of paths to files containing the IDCs which will be averaged +/// \param outFile output filename +void makeAverageIDCs(const std::vector<std::string>& files, const char* outFile = outfnameIDC) +{ + // vector containing the path of the relevant files which will be averaged + std::cout << "merge IDCs for average map" << std::endl; + + // average idc CalPads + std::vector<CalPad> idc3D; // 3D-average idc + std::vector<float> idc1DASide; // 1D-average idc + std::vector<float> idc1DCSide; // 1D-average idc + + std::vector<float> idc0DASide(1); // 0D-average idc (A single float value cannot be written to file) TODO find better solution + std::vector<float> idc0DCSide(1); // 0D-average idc (A single float value cannot be written to file) TODO find better solution + + // merge the 3D IDC values + const int nMaps = files.size(); + for (int iFile = 0; iFile < nMaps; ++iFile) { + const auto str = files[iFile]; + std::cout << "merging file: " << str.data() << std::endl; + + TFile finp(str.data(), "READ"); + std::vector<CalPad>* idcTmp = nullptr; + finp.GetObject("IDC", idcTmp); + + // number of z-bins + const auto nSlices = idcTmp->size(); + + // init vector for first file + if (iFile == 0) { + idc3D.resize(nSlices); + for (auto& calpadIDC : idc3D) { + calpadIDC = CalPad("IDC", PadSubset::ROC); + } + idc1DASide.resize(nSlices); + idc1DCSide.resize(nSlices); + } + + // merge the idc values + for (unsigned long iSlice = 0; iSlice < nSlices; ++iSlice) { + idc3D[iSlice] += (*idcTmp)[iSlice]; + } + delete idcTmp; + } + + // IDCs have to be normalized to the number of maps + const int nSlices = idc3D.size(); + + // sum up all z-slices for A- and C-side + CalPad idcZSlicesSummedTmp("IDC", PadSubset::ROC); + for (int iSlice = 0; iSlice < nSlices; ++iSlice) { + idc3D[iSlice] /= nMaps; + idcZSlicesSummedTmp += idc3D[iSlice]; + } + // normalize to number of z slices + idcZSlicesSummedTmp /= nSlices; + + // setting each z-slice to average IDC + for (int iSlice = 0; iSlice < nSlices; ++iSlice) { + idc3D[iSlice] = idcZSlicesSummedTmp; + } + + // calculate 1D IDC + for (unsigned long iSlice = 0; iSlice < idc3D.size(); ++iSlice) { + const auto vecCalArr = idc3D[iSlice].getData(); + const int maxrocs = ROC::MaxROC; + for (int iROC = 0; iROC < maxrocs; ++iROC) { + ROC roc(iROC); + const Side side = roc.side(); + if (side == Side::A) { + // 1D IDC for A side + idc1DASide[iSlice] += vecCalArr[iROC].getSum(); + } else { + // 1D IDC for C side + idc1DCSide[iSlice] += vecCalArr[iROC].getSum(); + } + } + } + + // calculate 0D IDC + idc0DASide[0] = std::accumulate(idc1DASide.begin(), idc1DASide.end(), (float)0); + idc0DCSide[0] = std::accumulate(idc1DCSide.begin(), idc1DCSide.end(), (float)0); + + std::cout << "output path is: " << outFile << std::endl; + TFile fMergedIDC(outFile, "RECREATE"); + fMergedIDC.WriteObject(&idc3D, "IDC"); + fMergedIDC.WriteObject(&idc1DASide, "IDC_1D_A_Side"); + fMergedIDC.WriteObject(&idc1DCSide, "IDC_1D_C_Side"); + fMergedIDC.WriteObject(&idc0DASide, "IDC_0D_A_Side"); + fMergedIDC.WriteObject(&idc0DCSide, "IDC_0D_C_Side"); +} + +/// \param histSC input histogram containing the space charge density +/// \param nZ number of z granularity for calculating the distortions +/// \param nR number of r granularity for calculating the distortions +/// \param nPhi number of phi granularity for calculating the distortions +/// \param outFileDistortions path to the file for output distortions (which can be read in from a SpaceCharge object) +/// \param sides set for which sides the distortions/corrections will be calculated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +template <typename DataT = double> +void makeDistortionsCorrections(const TH3& histSC, const int nZ, const int nR, const int nPhi, const char* outFileDistortions = "distortions.root", const int sides = 0) +{ + o2::tpc::SpaceCharge<double>::setGrid(nZ, nR, nPhi); + std::cout << "output file: " << outFileDistortions << std::endl; + + o2::tpc::SpaceCharge<DataT> spacecharge(mOmegatau, 1, 1); + spacecharge.fillChargeDensityFromHisto(histSC); + + // dump distortion object to file if output file is specified + TFile fOut(outFileDistortions, "RECREATE"); + for (int iSide = getSideStart(sides); iSide < getSideEnd(sides); ++iSide) { + const Side side = iSide == 0 ? Side::A : Side::C; + spacecharge.calculateDistortionsCorrections(side, true); + spacecharge.dumpGlobalCorrections(fOut, side); + spacecharge.dumpGlobalDistortions(fOut, side); + spacecharge.dumpLocalCorrections(fOut, side); + spacecharge.dumpLocalDistCorrVectors(fOut, side); + spacecharge.dumpDensity(fOut, side); + spacecharge.dumpPotential(fOut, side); + spacecharge.dumpElectricFields(fOut, side); + } +} + +/// make average distortion map from random maps for histograms for A or C side +/// \param files vector with files which contain the random space charge maps +/// \param histNameNoZDep name of the space charge histogram in the root files which dont have a z dependence +/// \param histNameZDep name of the space charge histogram in the root files which have a z dependence (can also be empty) +/// \param outFileName name of the output file +/// \param outFile output file where the histograms will be written to +void makeAverageDensityMap(const std::vector<std::string> files, TFile& outFile, const char* histNameNoZDep, const char* histNameZDep) +{ + const std::string tmphistNameZDep = histNameZDep; + + // 1. loop over the maps and create the average map (still z dependent) + TH3F averageMapNoZDep; // average sc map which doesnt depend on z (like the IBF) + TH3F averageMapZDep; // average sc map which depends on z (like the PI) + const int nMaps = files.size(); + for (int iFile = 0; iFile < nMaps; ++iFile) { + const auto str = files[iFile]; + std::cout << "using density map: " << str.data() << std::endl; + TFile fInp(str.data(), "READ"); + TH3F* densMapTmpNoZDep = (TH3F*)fInp.Get(histNameNoZDep); + + TH3F* densMapTmpZDep = nullptr; + if (!tmphistNameZDep.empty()) { + densMapTmpZDep = (TH3F*)fInp.Get(histNameZDep); + } + + if (iFile == 0) { + averageMapNoZDep = *densMapTmpNoZDep; + if (densMapTmpZDep) { + averageMapZDep = *densMapTmpZDep; + } + } else { + averageMapNoZDep.Add(densMapTmpNoZDep); + if (densMapTmpZDep) { + averageMapZDep.Add(densMapTmpZDep); + } + } + delete densMapTmpNoZDep; + delete densMapTmpZDep; + } + const float scaleFac = 1.f / nMaps; + scale(averageMapNoZDep, scaleFac); + scale(averageMapZDep, scaleFac); + + // 2.a sum up all z-slices to remove z dependence + const int nBinsPhi = averageMapNoZDep.GetNbinsX(); + const int nBinsR = averageMapNoZDep.GetNbinsY(); + const int nBinsZ = averageMapNoZDep.GetNbinsZ(); + + for (int iPhi = 1; iPhi <= nBinsPhi; ++iPhi) { + for (int iR = 1; iR <= nBinsR; ++iR) { + // either A or C side dependent on the input + const float meanDens = averageMapNoZDep.Integral(iPhi, iPhi, iR, iR, 1, nBinsZ) / nBinsZ; // integral over all z bins for each r and phi bin normalized to number of z slices + for (int iZ = 1; iZ <= nBinsZ; ++iZ) { + averageMapNoZDep.SetBinContent(iPhi, iR, iZ, meanDens); + } + } + } + + outFile.cd(); + averageMapNoZDep.Write(); + if (!tmphistNameZDep.empty()) { + averageMapZDep.Write(); + + // calculate final sc density + averageMapNoZDep.Add(&averageMapZDep); + const auto side = getSide(averageMapNoZDep.GetZaxis()->GetBinCenter(nBinsZ / 2)); + const std::string nameOut = getNameSide(side, hisSCRandomName); + averageMapNoZDep.SetTitle(nameOut.data()); + averageMapNoZDep.SetName(nameOut.data()); + averageMapNoZDep.Write(); + } +} + +/// \param scaleFactorConst constant scaling factor +/// \param scaleFactorLinear linear scaling factor - z dependent +/// \param scaleFactorParabolic parabolic scaling factor - z dependent +float getScaleValueZDep(const float scaleFactorConst, const float scaleFactorLinear, const float scaleFactorParabolic, const float driftLength) +{ + const float scaleVal = 1 + scaleFactorConst + scaleFactorLinear * (driftLength - 0.5f) + scaleFactorParabolic * (driftLength - 0.5f) * (driftLength - 0.5f); // scale factor for data augment (constant, linear(drift), quadratic(drift)) + return scaleVal; +} + +/// use the average space charge density map, scale it and calculat the corrections +/// \param inpFile input density file +/// \param outFile output scaled density file +/// \param sides set for which sides will be processed. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +/// \param scaleFactorConst constant scaling factor +/// \param scaleFactorLinear linear scaling factor - z dependent +/// \param scaleFactorParabolic parabolic scaling factor - z dependent +template <typename DataT = double> +void createScaledMeanMap(const std::string inpFile, const std::string outFile, const int sides, const float scaleFactorConst, const float scaleFactorLinear, const float scaleFactorParabolic, const int nZ, const int nR, const int nPhi) +{ + o2::tpc::SpaceCharge<DataT>::setGrid(nZ, nR, nPhi); + + // load the mean histo + using SC = o2::tpc::SpaceCharge<DataT>; + SC scScaled(mOmegatau, 1, 1); + + TFile fInp(inpFile.data(), "READ"); + if (sides != 2) { + scScaled.setDensityFromFile(fInp, Side::A); + } + if (sides != 1) { + scScaled.setDensityFromFile(fInp, Side::C); + } + + for (int iSide = getSideStart(sides); iSide < getSideEnd(sides); ++iSide) { + const Side side = iSide == 0 ? Side::A : Side::C; + for (size_t iZ = 0; iZ < scScaled.getNZVertices(); ++iZ) { + const float zPos = std::abs(scScaled.getZVertex(iZ, side)); + for (size_t iR = 0; iR < scScaled.getNRVertices(); ++iR) { + for (size_t iPhi = 0; iPhi < scScaled.getNPhiVertices(); ++iPhi) { + const DataT density = scScaled.getDensity(iZ, iR, iPhi, side); + const float driftLength = (mZROC - zPos) / mZROC; // drift relative to full drift + const float scaleVal = getScaleValueZDep(scaleFactorConst, scaleFactorLinear, scaleFactorParabolic, driftLength); + scScaled.fillDensity(density * scaleVal, iZ, iR, iPhi, side); + } + } + } + scScaled.setDensityFilled(side); + } + const bool calcLocalVectors = true; + + if (sides != 2) { + scScaled.calculateDistortionsCorrections(Side::A, calcLocalVectors); + } + if (sides != 1) { + scScaled.calculateDistortionsCorrections(Side::C, calcLocalVectors); + } + + // dump distortion object to file if output file is specified + TFile fOut(outFile.data(), "RECREATE"); + for (int iSide = getSideStart(sides); iSide < getSideEnd(sides); ++iSide) { + const Side side = iSide == 0 ? Side::A : Side::C; + scScaled.dumpGlobalCorrections(fOut, side); + scScaled.dumpGlobalDistortions(fOut, side); + scScaled.dumpLocalCorrections(fOut, side); + scScaled.dumpLocalDistCorrVectors(fOut, side); + scScaled.dumpDensity(fOut, side); + scScaled.dumpPotential(fOut, side); + scScaled.dumpElectricFields(fOut, side); + } +} + +/// scale the IDCs from the average (input) map +/// \param inpIDCs input IDC File +/// \param outFile output file name +/// \param scaleFac multiply sigma by this value. The resulting scaling is "1 + scaleFac * sigmaScale" +/// \param sigmaScale sigma of the scaling +void scaleIDCs(const char* inpIDCs, const char* outFile, const float scaleFactorConst, const float scaleFactorLinear, const float scaleFactorParabolic) +{ + // const float scaleVal = 1 + scaleFac * sigmaScale; + std::cout << "scaling IDC map: " << inpIDCs << std::endl; + + TFile finp(inpIDCs, "READ"); + std::vector<CalPad>* idc3D = nullptr; + finp.GetObject("IDC", idc3D); + + std::vector<float>* idc1DASide = nullptr; + std::vector<float>* idc1DCSide = nullptr; + finp.GetObject("IDC_1D_A_Side", idc1DASide); + finp.GetObject("IDC_1D_C_Side", idc1DCSide); + + // scale the 3d idcs + const int nZBins = idc3D->size(); + const float zHalfBin = 0.5 * mZROC / nZBins; + + for (int iSlice = 0; iSlice < nZBins; ++iSlice) { + const float driftLength = (mZROC - mZROC * iSlice / nZBins - zHalfBin) / mZROC; // index 0 is close to CE. Set z coordinate to middle of z-bin + const float scaleVal = getScaleValueZDep(scaleFactorConst, scaleFactorLinear, scaleFactorParabolic, driftLength); + (*idc3D)[iSlice] *= scaleVal; + } + + // scale the 1d idcs + for (int iSlice = 0; iSlice < nZBins; ++iSlice) { + const float driftLength = (mZROC - mZROC * iSlice / nZBins - zHalfBin) / mZROC; // index 0 is close to CE + const float scaleVal = getScaleValueZDep(scaleFactorConst, scaleFactorLinear, scaleFactorParabolic, driftLength); + (*idc1DASide)[iSlice] *= scaleVal; + (*idc1DCSide)[iSlice] *= scaleVal; + } + + // calculate the 0d idcs + std::vector<float> idc0DASide{get0DIDCs((*idc1DASide))}; + std::vector<float> idc0DCSide{get0DIDCs((*idc1DCSide))}; + + std::cout << "output path is: " << outFile << std::endl; + TFile fMergedIDC(outFile, "RECREATE"); + fMergedIDC.WriteObject(idc3D, "IDC"); + fMergedIDC.WriteObject(idc1DASide, "IDC_1D_A_Side"); + fMergedIDC.WriteObject(idc1DCSide, "IDC_1D_C_Side"); + fMergedIDC.WriteObject(&idc0DASide, "IDC_0D_A_Side"); + fMergedIDC.WriteObject(&idc0DCSide, "IDC_0D_C_Side"); + + delete idc3D; + delete idc1DASide; + delete idc1DCSide; +} + +/// \param calPad create 1D-IDCs from calpad object +/// \side side of the calpad +float get1DIDCs(const CalPad& calPad, const o2::tpc::Side side) +{ + const auto& mapper = Mapper::instance(); + const int nRowsIROC = mapper.getNumberOfRowsROC(ROC(0)); + + // values for weighted mean + float mean = 0; + float ww = 0; + + // create average IDCs from CalPad. weighted with pad size + for (ROC roc; !roc.looped(); ++roc) { + if (roc.side() != side) { + continue; + } + + const int nrows = mapper.getNumberOfRowsROC(roc); + for (int irow = 0; irow < nrows; ++irow) { + // get pad width and length + const int irowGlobal = roc.rocType() == o2::tpc::RocType::IROC ? irow : irow + nRowsIROC; // set global pad row + const int region = o2::tpc::Mapper::REGION[irowGlobal]; + const int npads = mapper.getNumberOfPadsInRowROC(roc, irow); + for (int ipad = 0; ipad < npads; ++ipad) { + const auto idc = calPad.getValue(roc, irow, ipad); + mean += idc * o2::tpc::Mapper::PADAREA[region]; //PADAREA[NREGIONS] = inverse pad area + ++ww; + } + } + } + + mean /= ww; + return mean; +} + +/// \param oneDIDC vector containg the 1D-IDC values for one side +/// \return returns the average of the input vector +float get0DIDCs(const std::vector<float>& oneDIDC) +{ + const float zeroDIDC = std::accumulate(oneDIDC.begin(), oneDIDC.end(), (float)0) / oneDIDC.size(); + return zeroDIDC; +} + +// scale an histogram same as TH3::Scale(), but avoiding an error when a lots of bbins are used and the histogram is written to a file +void scale(TH3& hist, const float fac) +{ + for (int iphi = 1; iphi <= hist.GetNbinsX(); ++iphi) { + for (int ir = 1; ir <= hist.GetNbinsY(); ++ir) { + for (int iz = 1; iz <= hist.GetNbinsZ(); ++iz) { + const auto content = hist.GetBinContent(iphi, ir, iz); + hist.SetBinContent(iphi, ir, iz, content * fac); + } + } + } +} + +const std::string getNameSide(const o2::tpc::Side side, const char* name) +{ + const std::string nameTmp = (side == Side::A) ? Form("%s_A", name) : Form("%s_C", name); + return nameTmp; +} + +/// helper function to set the loop over the sides for the tpc +/// \param sides set for which sides the distortions/corrections will be calculated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +int getSideStart(const int sides) +{ + if (sides == 2) { + return 1; + } + return 0; +} + +/// helper function to set the loop over the sides for the tpc +/// \param sides set for which sides the distortions/corrections will be calculated. sides=0: A- and C-Side, sides=1: A-Side only, sides=2: C-Side only +int getSideEnd(const int sides) +{ + if (sides == 1) { + return 1; + } + return 2; +} + +/// merge two high granularity space charge density histograms which are separated into the A and the C side (size would be larger than 1GB-> writing to file not possible) +/// \param inputFile input file containing the two histograms +/// \param nameA of the histogram for the A-Side +/// \param nameC of the histogram for the C-Side +TH3F mergeHistos(const char* inputFile = ".", const char* nameA = "hisIBF_A", const char* nameC = "hisIBF_C") +{ + TFile fInp(inputFile, "READ"); + TH3F* hSC = (TH3F*)fInp.Get(nameA); + if (hSC == nullptr) { + std::cout << "histogram " << nameA << " not found " << std::endl; + } + const int nPhiBinsTmp = hSC->GetXaxis()->GetNbins(); + const int nRBinsTmp = hSC->GetYaxis()->GetNbins(); + const int nZBins = hSC->GetZaxis()->GetNbins(); + const auto phiLow = hSC->GetXaxis()->GetBinLowEdge(1); + const auto phiUp = hSC->GetXaxis()->GetBinUpEdge(nPhiBinsTmp); + const auto rLow = hSC->GetYaxis()->GetBinLowEdge(1); + const auto rUp = hSC->GetYaxis()->GetBinUpEdge(nRBinsTmp); + const auto zUp = hSC->GetZaxis()->GetBinUpEdge(nZBins); + + // merged histogram + TH3F hisSCMerged("hisMerged", "hisMerged", nPhiBinsTmp, phiLow, phiUp, nRBinsTmp, rLow, rUp, 2 * nZBins, -zUp, zUp); + + std::cout << "merging histograms" << std::endl; + for (int iside = 0; iside < 2; ++iside) { + if (iside == 1) { + delete hSC; + hSC = (TH3F*)fInp.Get(nameC); + if (hSC == nullptr) { + std::cout << "histogram " << nameC << " not found " << std::endl; + } + } + for (int iz = 1; iz <= nZBins; ++iz) { + for (int ir = 1; ir <= nRBinsTmp; ++ir) { + for (int iphi = 1; iphi <= nPhiBinsTmp; ++iphi) { + const int izTmp = iside == 0 ? nZBins + iz : iz; + hisSCMerged.SetBinContent(iphi, ir, izTmp, hSC->GetBinContent(iphi, ir, iz)); + } + } + } + } + + delete hSC; + fInp.Close(); + return hisSCMerged; +} diff --git a/Detectors/TPC/spacecharge/src/PoissonSolver.cxx b/Detectors/TPC/spacecharge/src/PoissonSolver.cxx new file mode 100644 index 0000000000000..b2f1f82d26b23 --- /dev/null +++ b/Detectors/TPC/spacecharge/src/PoissonSolver.cxx @@ -0,0 +1,1498 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file PoissonSolver.cxx +/// \brief This class provides implementation of Poisson Eq +/// solver by MultiGrid Method +/// +/// +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#include "TPCSpaceCharge/PoissonSolver.h" +#include "TPCSpaceCharge/PoissonSolverHelpers.h" +#include "Framework/Logger.h" +#include <numeric> +#include <fmt/core.h> +#include "TPCSpaceCharge/Vector3D.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +using namespace o2::tpc; + +template <typename DataT> +void PoissonSolver<DataT>::poissonSolver3D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry) +{ + if (MGParameters::isFull3D) { + poissonMultiGrid3D(matricesV, matricesCharge, symmetry); + } else { + poissonMultiGrid3D2D(matricesV, matricesCharge, symmetry); + } +} + +template <typename DataT> +void PoissonSolver<DataT>::poissonSolver2D(DataContainer& matricesV, const DataContainer& matricesCharge) +{ + poissonMultiGrid2D(matricesV, matricesCharge); +} + +template <typename DataT> +void PoissonSolver<DataT>::poissonMultiGrid2D(DataContainer& matricesV, const DataContainer& matricesCharge, const int iPhi) +{ + /// Geometry of TPC -- should be use AliTPCParams instead + const DataT gridSpacingR = getSpacingR(); + const DataT gridSpacingZ = getSpacingZ(); + const DataT ratioZ = gridSpacingR * gridSpacingR / (gridSpacingZ * gridSpacingZ); // ratio_{Z} = gridSize_{r} / gridSize_{z} + + int nGridRow = 0; // number grid + int nGridCol = 0; // number grid + + int nnRow = mParamGrid.NRVertices; + while (nnRow >>= 1) { + ++nGridRow; + } + + int nnCol = mParamGrid.NZVertices; + while (nnCol >>= 1) { + ++nGridCol; + } + + //Check that number of mParamGrid.NRVertices and mParamGrid.NZVertices is suitable for multi grid + if (!isPowerOfTwo(mParamGrid.NRVertices - 1)) { + LOGP(ERROR, "PoissonMultiGrid2D: PoissonMultiGrid - Error in the number of mParamGrid.NRVertices. Must be 2**M + 1"); + return; + } + if (!isPowerOfTwo(mParamGrid.NZVertices - 1)) { + LOGP(ERROR, "PoissonMultiGrid2D: PoissonMultiGrid - Error in the number of mParamGrid.NZVertices. Must be 2**N + 1"); + return; + } + + const int nLoop = std::max(nGridRow, nGridCol); // Calculate the number of nLoop for the binary expansion + + LOGP(info, "{}", fmt::format("PoissonMultiGrid2D: nGridRow={}, nGridCol={}, nLoop={}, nMGCycle={}", nGridRow, nGridCol, nLoop, MGParameters::nMGCycle)); + + unsigned int iOne = 1; // index + unsigned int jOne = 1; // index + int tnRRow = mParamGrid.NRVertices; + int tnZColumn = mParamGrid.NZVertices; + + // Vector for storing multi grid array + std::vector<Vector> tvArrayV(nLoop); // potential <--> error + std::vector<Vector> tvChargeFMG(nLoop); // charge is restricted in full multiGrid + std::vector<Vector> tvCharge(nLoop); // charge <--> residue + std::vector<Vector> tvResidue(nLoop); // residue calculation + + // Allocate memory for temporary grid + for (int count = 1; count <= nLoop; ++count) { + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + // if one just address to matrixV + const int index = count - 1; + tvResidue[index].resize(tnRRow, tnZColumn, 1); + tvChargeFMG[index].resize(tnRRow, tnZColumn, 1); + tvArrayV[index].resize(tnRRow, tnZColumn, 1); + tvCharge[index].resize(tnRRow, tnZColumn, 1); + + if (count == 1) { + for (int iphi = iPhi; iphi <= iPhi; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + tvChargeFMG[index](ir, iz, iphi) = matricesCharge(iz, ir, iphi); + tvCharge[index](ir, iz, iphi) = matricesCharge(iz, ir, iphi); + tvArrayV[index](ir, iz, iphi) = matricesV(iz, ir, iphi); + } + } + } + } else { + restrict2D(tvChargeFMG[index], tvChargeFMG[count - 2], tnRRow, tnZColumn, 0); + } + iOne *= 2; + jOne *= 2; + } + + /// full multi grid + if (MGParameters::cycleType == CycleType::FCycle) { + + LOGP(info, "PoissonMultiGrid2D: Do full cycle"); + // FMG + // 1) Relax on the coarsest grid + iOne /= 2; + jOne /= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + const DataT h = gridSpacingR * nLoop; + const DataT h2 = h * h; + const DataT tempRatio = ratioZ * iOne * iOne / (jOne * jOne); + const DataT tempFourth = 1 / (2 + 2 * tempRatio); + + std::vector<DataT> coefficient1(tnRRow); + std::vector<DataT> coefficient2(tnRRow); + calcCoefficients2D(1, tnRRow - 1, h, coefficient1, coefficient2); + + relax2D(tvArrayV[nLoop - 1], tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, coefficient2); + + // Do VCycle from nLoop H to h + for (int count = nLoop - 2; count >= 0; --count) { + iOne /= 2; + jOne /= 2; + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + interp2D(tvArrayV[count], tvArrayV[count + 1], tnRRow, tnZColumn, iPhi); + + // Copy the relax charge to the tvCharge + tvCharge[count] = tvChargeFMG[count]; //copy + + // Do V cycle + for (int mgCycle = 0; mgCycle < MGParameters::nMGCycle; ++mgCycle) { + vCycle2D(count + 1, nLoop, MGParameters::nPre, MGParameters::nPost, gridSpacingR, ratioZ, tvArrayV, tvCharge, tvResidue); + } + } + } else if (MGParameters::cycleType == CycleType::VCycle) { + // 2. VCycle + LOGP(info, "PoissonMultiGrid2D: Do V cycle"); + + int gridFrom = 1; + int gridTo = nLoop; + + // Do MGCycle + for (int mgCycle = 0; mgCycle < MGParameters::nMGCycle; ++mgCycle) { + vCycle2D(gridFrom, gridTo, MGParameters::nPre, MGParameters::nPost, gridSpacingR, ratioZ, tvArrayV, tvCharge, tvResidue); + } + } else if (MGParameters::cycleType == CycleType::WCycle) { + // 3. W Cycle (TODO:) + int gridFrom = 1; + int gridTo = nLoop; + // Do MGCycle + for (Int_t mgCycle = 0; mgCycle < MGParameters::nMGCycle; mgCycle++) { + wCycle2D(gridFrom, gridTo, MGParameters::gamma, MGParameters::nPre, MGParameters::nPost, gridSpacingR, ratioZ, tvArrayV, tvCharge, tvResidue); + } + } + + // fill output + for (int iphi = iPhi; iphi <= iPhi; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + matricesV(iz, ir, iphi) = tvArrayV[0](ir, iz, iphi); + } + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::poissonMultiGrid3D2D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry) +{ + LOGP(info, "{}", fmt::format("PoissonMultiGrid3D2D: in Poisson Solver 3D multiGrid semi coarsening mParamGrid.NRVertices={}, cols={}, mParamGrid.NPhiVertices={}", mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices)); + + // Check that the number of mParamGrid.NRVertices and mParamGrid.NZVertices is suitable for a binary expansion + if (!isPowerOfTwo((mParamGrid.NRVertices - 1))) { + LOGP(ERROR, "PoissonMultiGrid3D2D: Poisson3DMultiGrid - Error in the number of mParamGrid.NRVertices. Must be 2**M + 1"); + return; + } + if (!isPowerOfTwo((mParamGrid.NZVertices - 1))) { + LOGP(ERROR, "PoissonMultiGrid3D2D: Poisson3DMultiGrid - Error in the number of mParamGrid.NZVertices. Must be 2**N + 1"); + return; + } + if (mParamGrid.NPhiVertices <= 3) { + LOGP(ERROR, "PoissonMultiGrid3D2D: Poisson3DMultiGrid - Error in the number of mParamGrid.NPhiVertices. Must be larger than 3"); + return; + } + + const DataT gridSpacingR = getSpacingR(); + const DataT gridSpacingZ = getSpacingZ(); + const DataT gridSpacingPhi = getSpacingPhi(); + const DataT ratioPhi = gridSpacingR * gridSpacingR / (gridSpacingPhi * gridSpacingPhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} + const DataT ratioZ = gridSpacingR * gridSpacingR / (gridSpacingZ * gridSpacingZ); // ratio_{Z} = gridSize_{r} / gridSize_{z} + + // Solve Poisson's equation in cylindrical coordinates by multiGrid technique + // Allow for different size grid spacing in R and Z directions + int nGridRow = 0; // number grid + int nGridCol = 0; // number grid + int nnRow = mParamGrid.NRVertices; + int nnCol = mParamGrid.NZVertices; + + while (nnRow >>= 1) { + ++nGridRow; + } + while (nnCol >>= 1) { + ++nGridCol; + } + + const int maxVal = std::max(nGridRow, nGridCol); // Calculate the number of nLoop for the binary expansion + const size_t nLoop = (maxVal > MGParameters::maxLoop) ? MGParameters::maxLoop : maxVal; + unsigned int iOne = 1; // index i in gridSize r (original) + unsigned int jOne = 1; // index j in gridSize z (original) + + std::vector<Vector> tvArrayV(nLoop); // potential <--> error + std::vector<Vector> tvChargeFMG(nLoop); // charge is restricted in full multiGrid + std::vector<Vector> tvCharge(nLoop); // charge <--> residue + std::vector<Vector> tvPrevArrayV(nLoop); // error calculation + std::vector<Vector> tvResidue(nLoop); // residue calculation + + for (unsigned int count = 1; count <= nLoop; count++) { + const unsigned int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + const unsigned int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + const unsigned int index = count - 1; + tvResidue[index].resize(tnRRow, tnZColumn, mParamGrid.NPhiVertices); + tvPrevArrayV[index].resize(tnRRow, tnZColumn, mParamGrid.NPhiVertices); + + // memory for the finest grid is from parameters + tvChargeFMG[index].resize(tnRRow, tnZColumn, mParamGrid.NPhiVertices); + tvArrayV[index].resize(tnRRow, tnZColumn, mParamGrid.NPhiVertices); + tvCharge[index].resize(tnRRow, tnZColumn, mParamGrid.NPhiVertices); + + if (count == 1) { + for (int iphi = 0; iphi < mParamGrid.NPhiVertices; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + tvChargeFMG[index](ir, iz, iphi) = matricesCharge(iz, ir, iphi); + tvArrayV[index](ir, iz, iphi) = matricesV(iz, ir, iphi); + } + } + } + } else { + restrict3D(tvChargeFMG[index], tvChargeFMG[count - 2], tnRRow, tnZColumn, mParamGrid.NPhiVertices, mParamGrid.NPhiVertices); + restrictBoundary3D(tvArrayV[index], tvArrayV[count - 2], tnRRow, tnZColumn, mParamGrid.NPhiVertices, mParamGrid.NPhiVertices); + } + iOne *= 2; // doubling + jOne *= 2; // doubling + } + + std::vector<DataT> coefficient1(mParamGrid.NRVertices); // coefficient1(mParamGrid.NRVertices) for storing (1 + h_{r}/2r_{i}) from central differences in r direction + std::vector<DataT> coefficient2(mParamGrid.NRVertices); // coefficient2(mParamGrid.NRVertices) for storing (1 + h_{r}/2r_{i}) from central differences in r direction + std::vector<DataT> coefficient3(mParamGrid.NRVertices); // coefficient3(mParamGrid.NRVertices) for storing (1/r_{i}^2) from central differences in phi direction + std::vector<DataT> coefficient4(mParamGrid.NRVertices); // coefficient4(mParamGrid.NRVertices) for storing 1/2 + std::vector<DataT> inverseCoefficient4(mParamGrid.NRVertices); // inverse of coefficient4(mParamGrid.NRVertices) + + // Case full multi grid (FMG) + if (MGParameters::cycleType == CycleType::FCycle) { + // 1) Relax on the coarsest grid + iOne /= 2; + jOne /= 2; + int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + const DataT h = getSpacingR() * iOne; + const DataT h2 = h * h; + const DataT iOne2 = iOne * iOne; + const DataT tempRatioPhi = ratioPhi * iOne2; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 + const DataT tempRatioZ = ratioZ * iOne2 / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + + // relax on the coarsest level + relax3D(tvArrayV[nLoop - 1], tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, mParamGrid.NPhiVertices, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + + // 2) Do multiGrid v-cycle from coarsest to finest + for (int count = nLoop - 2; count >= 0; --count) { + // move to finer grid + iOne /= 2; + jOne /= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + // 2) a) Interpolate potential for h -> 2h (coarse -> fine) + interp3D(tvArrayV[count], tvArrayV[count + 1], tnRRow, tnZColumn, mParamGrid.NPhiVertices, mParamGrid.NPhiVertices); + + // 2) c) Copy the restricted charge to charge for calculation + tvCharge[count] = tvChargeFMG[count]; //copy + + // 2) c) Do V cycle MGParameters::nMGCycle times at most + for (int mgCycle = 0; mgCycle < MGParameters::nMGCycle; ++mgCycle) { + // Copy the potential to temp array for convergence calculation + tvPrevArrayV[count] = tvArrayV[count]; + + // 2) c) i) Call V cycle from grid count+1 (current fine level) to nLoop (coarsest) + vCycle3D2D(symmetry, count + 1, nLoop, MGParameters::nPre, MGParameters::nPost, ratioZ, ratioPhi, tvArrayV, tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, coefficient4, inverseCoefficient4); + + const DataT convergenceError = getConvergenceError(tvArrayV[count], tvPrevArrayV[count]); + + /// if already converge just break move to finer grid + if (convergenceError <= sConvergenceError) { + break; + } + } + } + } + + // fill output + for (int iphi = 0; iphi < mParamGrid.NPhiVertices; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + matricesV(iz, ir, iphi) = tvArrayV[0](ir, iz, iphi); + } + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::poissonMultiGrid3D(DataContainer& matricesV, const DataContainer& matricesCharge, const int symmetry) +{ + const DataT gridSpacingR = getSpacingR(); + const DataT gridSpacingZ = getSpacingZ(); + const DataT ratioZ = gridSpacingR * gridSpacingR / (gridSpacingZ * gridSpacingZ); // ratio_{Z} = gridSize_{r} / gridSize_{z} + + LOGP(info, "{}", fmt::format("PoissonMultiGrid3D: in Poisson Solver 3D multi grid full coarsening mParamGrid.NRVertices={}, cols={}, mParamGrid.NPhiVertices={}", mParamGrid.NRVertices, mParamGrid.NZVertices, mParamGrid.NPhiVertices)); + + // Check that the number of mParamGrid.NRVertices and mParamGrid.NZVertices is suitable for a binary expansion + if (!isPowerOfTwo((mParamGrid.NRVertices - 1))) { + LOGP(ERROR, "PoissonMultiGrid3D: Poisson3DMultiGrid - Error in the number of mParamGrid.NRVertices. Must be 2**M + 1"); + return; + } + if (!isPowerOfTwo((mParamGrid.NZVertices - 1))) { + LOGP(ERROR, "PoissonMultiGrid3D: Poisson3DMultiGrid - Error in the number of mParamGrid.NZVertices. Must be 2**N + 1"); + return; + } + if (mParamGrid.NPhiVertices <= 3) { + LOGP(ERROR, "PoissonMultiGrid3D: Poisson3DMultiGrid - Error in the number of mParamGrid.NPhiVertices. Must be larger than 3"); + return; + } + + // Solve Poisson's equation in cylindrical coordinates by multi grid technique + // Allow for different size grid spacing in R and Z directions + int nGridRow = 0; // number grid + int nGridCol = 0; // number grid + int nGridPhi = 0; + + int nnRow = mParamGrid.NRVertices; + while (nnRow >>= 1) { + ++nGridRow; + } + + int nnCol = mParamGrid.NZVertices; + while (nnCol >>= 1) { + ++nGridCol; + } + + int nnPhi = mParamGrid.NPhiVertices; + while (nnPhi % 2 == 0) { + ++nGridPhi; + nnPhi /= 2; + } + + LOGP(info, "{}", fmt::format("PoissonMultiGrid3D: nGridRow={}, nGridCol={}, nGridPhi={}", nGridRow, nGridCol, nGridPhi)); + const int nLoop = std::max({nGridRow, nGridCol, nGridPhi}); // Calculate the number of nLoop for the binary expansion + + // Vector for storing multi grid array + unsigned int iOne = 1; // index i in gridSize r (original) + unsigned int jOne = 1; // index j in gridSize z (original) + unsigned int kOne = 1; // index k in gridSize phi + int tnRRow = mParamGrid.NRVertices; + int tnZColumn = mParamGrid.NZVertices; + int tPhiSlice = mParamGrid.NPhiVertices; + + // 1) Memory allocation for multi grid + std::vector<Vector> tvArrayV(nLoop); // potential <--> error + std::vector<Vector> tvChargeFMG(nLoop); // charge is restricted in full multiGrid + std::vector<Vector> tvCharge(nLoop); // charge <--> residue + std::vector<Vector> tvPrevArrayV(nLoop); // error calculation + std::vector<Vector> tvResidue(nLoop); // residue calculation + + std::vector<DataT> coefficient1(mParamGrid.NRVertices); // coefficient1(mParamGrid.NRVertices) for storing (1 + h_{r}/2r_{i}) from central differences in r direction + std::vector<DataT> coefficient2(mParamGrid.NRVertices); // coefficient2(mParamGrid.NRVertices) for storing (1 + h_{r}/2r_{i}) from central differences in r direction + std::vector<DataT> coefficient3(mParamGrid.NRVertices); // coefficient3(mParamGrid.NRVertices) for storing (1/r_{i}^2) from central differences in phi direction + std::vector<DataT> coefficient4(mParamGrid.NRVertices); // coefficient4(mParamGrid.NRVertices) for storing 1/2 + std::vector<DataT> inverseCoefficient4(mParamGrid.NRVertices); // inverse of coefficient4(mParamGrid.NRVertices) + + for (int count = 1; count <= nLoop; ++count) { + // tnRRow,tnZColumn in new grid + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + // allocate memory for residue + const int index = count - 1; + tvResidue[index].resize(tnRRow, tnZColumn, tPhiSlice); + tvPrevArrayV[index].resize(tnRRow, tnZColumn, tPhiSlice); + tvChargeFMG[index].resize(tnRRow, tnZColumn, tPhiSlice); + tvArrayV[index].resize(tnRRow, tnZColumn, tPhiSlice); + tvCharge[index].resize(tnRRow, tnZColumn, tPhiSlice); + + // memory for the finest grid is from parameters + if (count == 1) { + for (int iphi = 0; iphi < mParamGrid.NPhiVertices; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + tvChargeFMG[index](ir, iz, iphi) = matricesCharge(iz, ir, iphi); + tvArrayV[index](ir, iz, iphi) = matricesV(iz, ir, iphi); + } + } + } + tvCharge[index] = tvChargeFMG[index]; + } + iOne *= 2; // doubling + jOne *= 2; // doubling + kOne *= 2; + } + + // Case full multi grid (FMG) + if (MGParameters::cycleType == CycleType::FCycle) { + // Restrict the charge to coarser grid + iOne = 2; + jOne = 2; + kOne = 2; + int otPhiSlice = mParamGrid.NPhiVertices; + + // 1) Restrict Charge and Boundary to coarser grid + for (int count = 2; count <= nLoop; ++count) { + // tnRRow,tnZColumn in new grid + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + LOGP(info, "{}", fmt::format("PoissonMultiGrid3D: Restrict3D, tnRRow={}, tnZColumn={}, newPhiSlice={}, oldPhiSlice={}", tnRRow, tnZColumn, tPhiSlice, otPhiSlice)); + restrict3D(tvChargeFMG[count - 1], tvChargeFMG[count - 2], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); + // copy boundary values of V + restrictBoundary3D(tvArrayV[count - 1], tvArrayV[count - 2], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); + otPhiSlice = tPhiSlice; + + iOne *= 2; // doubling + jOne *= 2; // doubling + kOne *= 2; + } + + // Relax on the coarsest grid + // FMG + // 2) Relax on the coarsest grid + // move to the coarsest + 1 + iOne /= 2; + jOne /= 2; + kOne /= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + otPhiSlice = tPhiSlice; + + const DataT h = gridSpacingR * iOne; + const DataT h2 = h * h; + const DataT gridSizePhiInv = tPhiSlice * INVTWOPI; // h_{phi} + const DataT tempRatioPhi = h2 * gridSizePhiInv * gridSizePhiInv; // ratio_{phi} = gridSize_{r} / gridSize_{phi} + const DataT tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + + // 3) Relax on the coarsest grid + relax3D(tvArrayV[nLoop - 1], tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + + // 4) V Cycle from coarsest to finest + for (int count = nLoop - 2; count >= 0; --count) { + // move to finer grid + std::fill(std::begin(coefficient1), std::end(coefficient1), 0); + std::fill(std::begin(coefficient2), std::end(coefficient2), 0); + std::fill(std::begin(coefficient3), std::end(coefficient3), 0); + std::fill(std::begin(coefficient4), std::end(coefficient4), 0); + std::fill(std::begin(inverseCoefficient4), std::end(inverseCoefficient4), 0); + + iOne /= 2; + jOne /= 2; + kOne /= 2; + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + // 4) a) interpolate from 2h --> h grid + interp3D(tvArrayV[count], tvArrayV[count + 1], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); + + // Copy the relax charge to the tvCharge + if (count > 0) { + tvCharge[count] = tvChargeFMG[count]; + } + for (int mgCycle = 0; mgCycle < MGParameters::nMGCycle; ++mgCycle) { + // copy to store previous potential + tvPrevArrayV[count] = tvArrayV[count]; + + vCycle3D(symmetry, count + 1, nLoop, MGParameters::nPre, MGParameters::nPost, ratioZ, tvArrayV, tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, coefficient4, inverseCoefficient4); + + // converge error + const DataT convergenceError = getConvergenceError(tvArrayV[count], tvPrevArrayV[count]); + // if already converge just break move to finer grid + if (convergenceError <= sConvergenceError) { + break; + } + } + // keep old slice information + otPhiSlice = tPhiSlice; + } + } else if (MGParameters::cycleType == CycleType::VCycle) { + // V-cycle + int gridFrom = 1; + int gridTo = nLoop; + + for (int mgCycle = 0; mgCycle < MGParameters::nMGCycle; ++mgCycle) { + // copy to store previous potential + tvPrevArrayV[0] = tvArrayV[0]; + + // Do V Cycle from the coarsest to finest grid + vCycle3D(symmetry, gridFrom, gridTo, MGParameters::nPre, MGParameters::nPost, ratioZ, tvArrayV, tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, coefficient4, inverseCoefficient4); + + // convergence error + const DataT convergenceError = getConvergenceError(tvArrayV[0], tvPrevArrayV[0]); + + // if error already achieved then stop mg iteration + if (convergenceError <= sConvergenceError) { + break; + } + } + } + + // fill output + for (int iphi = 0; iphi < mParamGrid.NPhiVertices; ++iphi) { + for (int ir = 0; ir < mParamGrid.NRVertices; ++ir) { + for (int iz = 0; iz < mParamGrid.NZVertices; ++iz) { + matricesV(iz, ir, iphi) = tvArrayV[0](ir, iz, iphi); + } + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::wCycle2D(const int gridFrom, const int gridTo, const int gamma, const int nPre, const int nPost, const DataT gridSizeR, const DataT ratio, + std::vector<Vector>& tvArrayV, std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue) +{ + unsigned int iOne = 1 << (gridFrom - 1); + unsigned int jOne = 1 << (gridFrom - 1); + + int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + std::vector<DataT> coefficient1(mParamGrid.NRVertices); + std::vector<DataT> coefficient2(mParamGrid.NZVertices); + + // 1) Go to coarsest level + for (int count = gridFrom; count <= gridTo - 2; ++count) { + const int index = count - 1; + const DataT h = gridSizeR * iOne; + const DataT h2 = h * h; + const DataT ih2 = 1 / h2; + const DataT tempRatio = ratio * iOne * iOne / (jOne * jOne); + const DataT tempFourth = 1 / (2 + 2 * tempRatio); + const DataT inverseTempFourth = 1 / tempFourth; + calcCoefficients2D(1, tnRRow - 1, h, coefficient1, coefficient2); + Vector matricesCurrentV = tvArrayV[index]; + Vector matricesCurrentCharge = tvCharge[index]; + Vector residue = tvResidue[index]; + + // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi + for (int jPre = 1; jPre <= nPre; ++jPre) { + relax2D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, coefficient2); + } + + // 2) Residue calculation + residue2D(residue, matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, ih2, inverseTempFourth, tempRatio, coefficient1, coefficient2); + + iOne *= 2; + jOne *= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + matricesCurrentCharge = tvCharge[count]; + matricesCurrentV = tvArrayV[count]; + + //3) Restriction + restrict2D(matricesCurrentCharge, residue, tnRRow, tnZColumn, 0); + } + + // Do V cycle from: gridTo-1 to gridTo gamma times + for (int iGamma = 0; iGamma < gamma; ++iGamma) { + vCycle2D(gridTo - 1, gridTo, nPre, nPost, gridSizeR, ratio, tvArrayV, tvCharge, tvResidue); + } + + // Go to finest grid + for (int count = gridTo - 2; count >= gridFrom; --count) { + iOne /= 2; + jOne /= 2; + + const DataT h = gridSizeR * iOne; + const DataT h2 = h * h; + const DataT tempRatio = ratio * iOne * iOne / (jOne * jOne); + const DataT tempFourth = 1 / (2 + 2 * tempRatio); + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + const Vector matricesCurrentCharge = tvCharge[count - 1]; + Vector matricesCurrentV = tvArrayV[count - 1]; + const Vector matricesCurrentVC = tvArrayV[count]; + + // 6) Interpolation/Prolongation + addInterp2D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, 0); + + calcCoefficients2D(1, tnRRow - 1, h, coefficient1, coefficient2); + + // 7) Post-Smoothing: Gauss-Seidel Relaxation + for (Int_t jPost = 1; jPost <= nPost; ++jPost) { + relax2D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, coefficient2); + } // end post smoothing + } +} + +template <typename DataT> +void PoissonSolver<DataT>::vCycle2D(const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT gridSizeR, const DataT ratio, std::vector<Vector>& tvArrayV, + std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue) +{ + unsigned int iOne = 1 << (gridFrom - 1); + unsigned int jOne = 1 << (gridFrom - 1); + + int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + std::vector<DataT> coefficient1(mParamGrid.NRVertices); + std::vector<DataT> coefficient2(mParamGrid.NZVertices); + + // 1) Go to coarsest level + for (int count = gridFrom; count <= gridTo - 1; ++count) { + const int index = count - 1; + const DataT h = gridSizeR * iOne; + const DataT h2 = h * h; + const DataT ih2 = 1 / h2; + const DataT tempRatio = ratio * iOne * iOne / (jOne * jOne); + const DataT tempFourth = 1 / (2 + 2 * tempRatio); + const DataT inverseTempFourth = 1 / tempFourth; + calcCoefficients2D(1, tnRRow - 1, h, coefficient1, coefficient2); + + for (int jPre = 1; jPre <= nPre; ++jPre) { + relax2D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, coefficient2); + } + + // 2) Residue calculation + residue2D(tvResidue[index], tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, ih2, inverseTempFourth, tempRatio, coefficient1, coefficient2); + + iOne *= 2; + jOne *= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + //3) Restriction + restrict2D(tvCharge[count], tvResidue[index], tnRRow, tnZColumn, 0); + + //4) Zeroing coarser V + std::fill(tvArrayV[count].begin(), tvArrayV[count].end(), 0); // is this necessary??? + } + + // 5) coarsest grid + const DataT h = gridSizeR * iOne; + const DataT h2 = h * h; + const DataT tempRatio = ratio * iOne * iOne / (jOne * jOne); + const DataT tempFourth = 1 / (2 + 2 * tempRatio); + calcCoefficients2D(1, tnRRow - 1, h, coefficient1, coefficient2); + + relax2D(tvArrayV[gridTo - 1], tvCharge[gridTo - 1], tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, coefficient2); + + // Go to finest grid + for (int count = gridTo - 1; count >= gridFrom; count--) { + const int index = count - 1; + iOne /= 2; + jOne /= 2; + + const DataT hTmp = gridSizeR * iOne; + const DataT h2Tmp = hTmp * hTmp; + const DataT tempRatioTmp = ratio * iOne * iOne / (jOne * jOne); + const DataT tempFourthTmp = 1 / (2 + 2 * tempRatioTmp); + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + // 6) Interpolation/Prolongation + addInterp2D(tvArrayV[index], tvArrayV[count], tnRRow, tnZColumn, 0); + + calcCoefficients2D(1, tnRRow - 1, hTmp, coefficient1, coefficient2); + + // 7) Post-Smoothing: Gauss-Seidel Relaxation + for (int jPost = 1; jPost <= nPost; ++jPost) { + relax2D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, h2Tmp, tempFourthTmp, tempRatioTmp, coefficient1, coefficient2); + } // end post smoothing + } +} + +template <typename DataT> +void PoissonSolver<DataT>::vCycle3D2D(const int symmetry, const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT ratioZ, const DataT ratioPhi, + std::vector<Vector>& tvArrayV, std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue, std::vector<DataT>& coefficient1, + std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, std::vector<DataT>& coefficient4, std::vector<DataT>& inverseCoefficient4) const +{ + unsigned int iOne = 1 << (gridFrom - 1); + unsigned int jOne = 1 << (gridFrom - 1); + int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + for (int count = gridFrom; count <= gridTo - 1; ++count) { + const int index = count - 1; + const DataT h = getSpacingR() * iOne; + const DataT h2 = h * h; + const DataT ih2 = 1 / h2; + const int iOne2 = iOne * iOne; + const DataT tempRatioPhi = ratioPhi * iOne2; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 + const DataT tempRatioZ = ratioZ * iOne2 / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + for (unsigned int i = 1; i < tnRRow - 1; ++i) { + inverseCoefficient4[i] = 1 / coefficient4[i]; + } + + //Info("VCycle3D2D","Before Pre-smoothing"); + // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi + for (int jPre = 1; jPre <= nPre; ++jPre) { + relax3D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, mParamGrid.NPhiVertices, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + } // end pre smoothing + + // 2) Residue calculation + residue3D(tvResidue[index], tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, mParamGrid.NPhiVertices, symmetry, ih2, tempRatioZ, coefficient1, coefficient2, coefficient3, inverseCoefficient4); + + iOne *= 2; + jOne *= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + //3) Restriction + restrict3D(tvCharge[count], tvResidue[index], tnRRow, tnZColumn, mParamGrid.NPhiVertices, mParamGrid.NPhiVertices); + + //4) Zeroing coarser V + std::fill(tvArrayV[count].begin(), tvArrayV[count].end(), 0); + } + + // coarsest grid + const DataT hTmp = getSpacingR() * iOne; + const DataT h2Tmp = hTmp * hTmp; + + const int iOne2Tmp = iOne * iOne; + const DataT tempRatioPhiTmp = ratioPhi * iOne2Tmp; + const DataT tempRatioZTmp = ratioZ * iOne2Tmp / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, hTmp, tempRatioZTmp, tempRatioPhiTmp, coefficient1, coefficient2, coefficient3, coefficient4); + + // 3) Relax on the coarsest grid + relax3D(tvArrayV[gridTo - 1], tvCharge[gridTo - 1], tnRRow, tnZColumn, mParamGrid.NPhiVertices, symmetry, h2Tmp, tempRatioZTmp, coefficient1, coefficient2, coefficient3, coefficient4); + + // back to fine + for (int count = gridTo - 1; count >= gridFrom; --count) { + const int index = count - 1; + iOne /= 2; + jOne /= 2; + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + + const DataT h = getSpacingR() * iOne; + const DataT h2 = h * h; + const int iOne2 = iOne * iOne; + const DataT tempRatioPhi = ratioPhi * iOne2; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 + const DataT tempRatioZ = ratioZ * iOne2 / (jOne * jOne); + + // 4) Interpolation/Prolongation + addInterp3D(tvArrayV[index], tvArrayV[count], tnRRow, tnZColumn, mParamGrid.NPhiVertices, mParamGrid.NPhiVertices); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + + // 5) Post-Smoothing: Gauss-Seidel Relaxation + for (int jPost = 1; jPost <= nPost; ++jPost) { + relax3D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, mParamGrid.NPhiVertices, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + } // end post smoothing + } +} + +template <typename DataT> +void PoissonSolver<DataT>::vCycle3D(const int symmetry, const int gridFrom, const int gridTo, const int nPre, const int nPost, const DataT ratioZ, std::vector<Vector>& tvArrayV, + std::vector<Vector>& tvCharge, std::vector<Vector>& tvResidue, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, + std::vector<DataT>& coefficient4, std::vector<DataT>& inverseCoefficient4) const +{ + const DataT gridSpacingR = getSpacingR(); + + unsigned int iOne = 1 << (gridFrom - 1); + unsigned int jOne = 1 << (gridFrom - 1); + unsigned int kOne = 1 << (gridFrom - 1); + + int nnPhi = mParamGrid.NPhiVertices; + while (nnPhi % 2 == 0) { + nnPhi /= 2; + } + + int tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + int tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + int tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + for (int count = gridFrom; count <= gridTo - 1; ++count) { + const int index = count - 1; + const int otPhiSlice = tPhiSlice; + const DataT h = gridSpacingR * iOne; + const DataT h2 = h * h; + const DataT ih2 = 1 / h2; + const DataT tempGridSizePhiInv = tPhiSlice * INVTWOPI; // phi now is multiGrid + const DataT tempRatioPhi = h2 * tempGridSizePhiInv * tempGridSizePhiInv; // ratio_{phi} = gridSize_{r} / gridSize_{phi} + const DataT tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + + for (int i = 1; i < tnRRow - 1; ++i) { + inverseCoefficient4[i] = 1 / coefficient4[i]; + } + + // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi + for (int jPre = 1; jPre <= nPre; ++jPre) { + relax3D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + } // end pre smoothing + + // 2) Residue calculation + residue3D(tvResidue[index], tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, tPhiSlice, symmetry, ih2, tempRatioZ, coefficient1, coefficient2, coefficient3, inverseCoefficient4); + + iOne *= 2; + jOne *= 2; + kOne *= 2; + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + //3) Restriction + restrict3D(tvCharge[count], tvResidue[index], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); + + //4) Zeroing coarser V + std::fill(tvArrayV[count].begin(), tvArrayV[count].end(), 0); + } + + // coarsest grid + const DataT hTmp = gridSpacingR * iOne; + const DataT h2Tmp = hTmp * hTmp; + const DataT tempGridSizePhiInvTmp = tPhiSlice * INVTWOPI; // phi now is multiGrid + const DataT tempRatioPhiTmp = h2Tmp * tempGridSizePhiInvTmp * tempGridSizePhiInvTmp; // ratio_{phi} = gridSize_{r} / gridSize_{phi} + const DataT tempRatioZTmp = ratioZ * iOne * iOne / (jOne * jOne); + + calcCoefficients(1, tnRRow - 1, hTmp, tempRatioZTmp, tempRatioPhiTmp, coefficient1, coefficient2, coefficient3, coefficient4); + + // 3) Relax on the coarsest grid + relax3D(tvArrayV[gridTo - 1], tvCharge[gridTo - 1], tnRRow, tnZColumn, tPhiSlice, symmetry, h2Tmp, tempRatioZTmp, coefficient1, coefficient2, coefficient3, coefficient4); + // back to fine + for (int count = gridTo - 1; count >= gridFrom; --count) { + const int index = count - 1; + const int otPhiSlice = tPhiSlice; + iOne /= 2; + jOne /= 2; + kOne /= 2; + + tnRRow = iOne == 1 ? mParamGrid.NRVertices : mParamGrid.NRVertices / iOne + 1; + tnZColumn = jOne == 1 ? mParamGrid.NZVertices : mParamGrid.NZVertices / jOne + 1; + tPhiSlice = kOne == 1 ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / kOne; + tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; + + const DataT h = gridSpacingR * iOne; + const DataT h2 = h * h; + const DataT tempGridSizePhiInv = tPhiSlice * INVTWOPI; + const DataT tempRatioPhi = h2 * tempGridSizePhiInv * tempGridSizePhiInv; // ratio_{phi} = gridSize_{r} / gridSize_{phi} + const DataT tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); + + // 4) Interpolation/Prolongation + addInterp3D(tvArrayV[index], tvArrayV[count], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); + + calcCoefficients(1, tnRRow - 1, h, tempRatioZ, tempRatioPhi, coefficient1, coefficient2, coefficient3, coefficient4); + + // 5) Post-Smoothing: Gauss-Seidel Relaxation + for (int jPost = 1; jPost <= nPost; ++jPost) { + relax3D(tvArrayV[index], tvCharge[index], tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, coefficient1, coefficient2, coefficient3, coefficient4); + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::residue2D(Vector& residue, const Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const DataT ih2, const DataT inverseTempFourth, + const DataT tempRatio, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2) +{ + const int iPhi = 0; +#pragma omp parallel for num_threads(sNThreads) + for (int i = 1; i < tnRRow - 1; ++i) { + for (int j = 1; j < tnZColumn - 1; ++j) { + residue(i, j, iPhi) = ih2 * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) - inverseTempFourth * matricesCurrentV(i, j, iPhi)) + matricesCurrentCharge(i, j, iPhi); + } // end cols + } // end nRRow + + //Boundary points. + for (int i = 0; i < tnRRow; ++i) { + residue(i, 0, iPhi) = residue(i, tnZColumn - 1, iPhi) = 0.0; + } + + for (int j = 0; j < tnZColumn; ++j) { + residue(0, j, iPhi) = residue(tnRRow - 1, j, iPhi) = 0.0; + } +} + +template <typename DataT> +void PoissonSolver<DataT>::residue3D(Vector& residue, const Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const int tnPhi, const int symmetry, + const DataT ih2, const DataT tempRatioZ, const std::vector<DataT>& coefficient1, const std::vector<DataT>& coefficient2, const std::vector<DataT>& coefficient3, const std::vector<DataT>& inverseCoefficient4) const +{ +#pragma omp parallel for num_threads(sNThreads) // parallising this loop is possible - but using more than 2 cores makes it slower - + for (int m = 0; m < tnPhi; ++m) { + int mp1 = m + 1; + int signPlus = 1; + int mm1 = m - 1; + int signMinus = 1; + + // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) + if (symmetry == 1) { + if (mp1 > tnPhi - 1) { + mp1 = tnPhi - 2; + } + if (mm1 < 0) { + mm1 = 1; + } + } + // Anti-symmetry in phi + else if (symmetry == -1) { + if (mp1 > tnPhi - 1) { + mp1 = tnPhi - 2; + signPlus = -1; + } + if (mm1 < 0) { + mm1 = 1; + signMinus = -1; + } + } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi + if (mp1 > tnPhi - 1) { + mp1 = m + 1 - tnPhi; + } + if (mm1 < 0) { + mm1 = m - 1 + tnPhi; + } + } + + for (int j = 1; j < tnZColumn - 1; ++j) { + for (int i = 1; i < tnRRow - 1; ++i) { + residue(i, j, m) = ih2 * (coefficient2[i] * matricesCurrentV(i - 1, j, m) + tempRatioZ * (matricesCurrentV(i, j - 1, m) + matricesCurrentV(i, j + 1, m)) + coefficient1[i] * matricesCurrentV(i + 1, j, m) + + coefficient3[i] * (signPlus * matricesCurrentV(i, j, mp1) + signMinus * matricesCurrentV(i, j, mm1)) - inverseCoefficient4[i] * matricesCurrentV(i, j, m)) + + matricesCurrentCharge(i, j, m); + } // end cols + } // end mParamGrid.NRVertices + } +} + +template <typename DataT> +void PoissonSolver<DataT>::interp3D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const +{ + // Do restrict 2 D for each slice + if (newPhiSlice == 2 * oldPhiSlice) { + for (int m = 0; m < newPhiSlice; m += 2) { + // assuming no symmetry + int mm = m / 2; + int mmPlus = mm + 1; + int mp1 = m + 1; + + // round + if (mmPlus > oldPhiSlice - 1) { + mmPlus = mm + 1 - oldPhiSlice; + } + if (mp1 > newPhiSlice - 1) { + mp1 = m + 1 - newPhiSlice; + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) = matricesCurrentVC(iHalf, jHalf, mm); + // point on corner lines at phi direction + matricesCurrentV(i, j, mp1) = (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus)) / 2; + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) = (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm)) / 2; + // point on corner lines at phi direction + matricesCurrentV(i, j, mp1) = (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus) + matricesCurrentVC(iHalf, jHalf + 1, mmPlus)) / 4; + } + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) = (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf, mm)) / 2; + // point on line at phi direction + matricesCurrentV(i, j, mp1) = ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus)) + (matricesCurrentVC(iHalf + 1, jHalf, mmPlus) + matricesCurrentVC(iHalf + 1, jHalf, mm))) / 4; + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) = ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm)) + (matricesCurrentVC(iHalf + 1, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf + 1, mm))) / 4; + // point at the center at phi direction + matricesCurrentV(i, j, mp1) = ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus) + matricesCurrentVC(iHalf, jHalf + 1, mmPlus)) + + (matricesCurrentVC(iHalf + 1, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf + 1, mm) + matricesCurrentVC(iHalf + 1, jHalf, mmPlus) + matricesCurrentVC(iHalf + 1, jHalf + 1, mmPlus))) / + 8; + } + } + } + + } else { +#pragma omp parallel for num_threads(sNThreads) // no change + for (int m = 0; m < newPhiSlice; ++m) { + interp2D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, m); + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::interp2D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int iphi) const +{ + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int jHalf = j / 2; + matricesCurrentV(i, j, iphi) = matricesCurrentVC(i / 2, jHalf, iphi); + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, iphi) = (matricesCurrentVC(iHalf, jHalf, iphi) + matricesCurrentVC(iHalf, jHalf + 1, iphi)) / 2; + } + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, iphi) = (matricesCurrentVC(iHalf, jHalf, iphi) + matricesCurrentVC(iHalf + 1, jHalf, iphi)) / 2; + } + } + + // only if full + if (MGParameters::gtType == GridTransferType::Full) { + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, iphi) = (matricesCurrentVC(iHalf, jHalf, iphi) + matricesCurrentVC(iHalf, jHalf + 1, iphi) + matricesCurrentVC(iHalf + 1, jHalf, iphi) + matricesCurrentVC(iHalf + 1, jHalf + 1, iphi)) / 4; + } + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::addInterp3D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const +{ + // Do restrict 2 D for each slice + if (newPhiSlice == 2 * oldPhiSlice) { + for (int m = 0; m < newPhiSlice; m += 2) { + // assuming no symmetry + int mm = m / 2; + int mmPlus = mm + 1; + int mp1 = m + 1; + + // round + if (mmPlus > (oldPhiSlice)-1) { + mmPlus = mm + 1 - (oldPhiSlice); + } + if (mp1 > (newPhiSlice)-1) { + mp1 = m + 1 - (newPhiSlice); + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) += matricesCurrentVC(iHalf, jHalf, mm); + // point on corner lines at phi direction + matricesCurrentV(i, j, mp1) += (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus)) / 2; + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) += (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm)) / 2; + // point on corner lines at phi direction + matricesCurrentV(i, j, mp1) += (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus) + matricesCurrentVC(iHalf, jHalf + 1, mmPlus)) / 4; + } + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) += (matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf, mm)) / 2; + // point on line at phi direction + matricesCurrentV(i, j, mp1) += ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus)) + (matricesCurrentVC(iHalf + 1, jHalf, mmPlus) + matricesCurrentVC(iHalf + 1, jHalf, mm))) / 4; + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, m) += ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm)) + (matricesCurrentVC(iHalf + 1, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf + 1, mm))) / 4; + // point at the center at phi direction + matricesCurrentV(i, j, mp1) += ((matricesCurrentVC(iHalf, jHalf, mm) + matricesCurrentVC(iHalf, jHalf + 1, mm) + matricesCurrentVC(iHalf, jHalf, mmPlus) + matricesCurrentVC(iHalf, jHalf + 1, mmPlus)) + + (matricesCurrentVC(iHalf + 1, jHalf, mm) + matricesCurrentVC(iHalf + 1, jHalf + 1, mm) + matricesCurrentVC(iHalf + 1, jHalf, mmPlus) + matricesCurrentVC(iHalf + 1, jHalf + 1, mmPlus))) / + 8; + } + } + } + + } else { +#pragma omp parallel for num_threads(sNThreads) // no change + for (int m = 0; m < newPhiSlice; m++) { + addInterp2D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, m); + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::addInterp2D(Vector& matricesCurrentV, const Vector& matricesCurrentVC, const int tnRRow, const int tnZColumn, const int tnPhi) const +{ + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + matricesCurrentV(i, j, tnPhi) = matricesCurrentV(i, j, tnPhi) + matricesCurrentVC(i / 2, j / 2, tnPhi); + } + } + + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 2; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, tnPhi) = matricesCurrentV(i, j, tnPhi) + (matricesCurrentVC(iHalf, jHalf, tnPhi) + matricesCurrentVC(iHalf, jHalf + 1, tnPhi)) / 2; + } + } + + for (int j = 2; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, tnPhi) = matricesCurrentV(i, j, tnPhi) + (matricesCurrentVC(iHalf, jHalf, tnPhi) + matricesCurrentVC(iHalf + 1, jHalf, tnPhi)) / 2; + } + } + + // only if full + if (MGParameters::gtType == GridTransferType::Full) { + for (int j = 1; j < tnZColumn - 1; j += 2) { + for (int i = 1; i < tnRRow - 1; i += 2) { + const int iHalf = i / 2; + const int jHalf = j / 2; + matricesCurrentV(i, j, tnPhi) = matricesCurrentV(i, j, tnPhi) + (matricesCurrentVC(iHalf, jHalf, tnPhi) + matricesCurrentVC(iHalf, jHalf + 1, tnPhi) + matricesCurrentVC(iHalf + 1, jHalf, tnPhi) + matricesCurrentVC(iHalf + 1, jHalf + 1, tnPhi)) / 4; + } + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::relax3D(Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const int iPhi, const int symmetry, const DataT h2, + const DataT tempRatioZ, const std::vector<DataT>& coefficient1, const std::vector<DataT>& coefficient2, const std::vector<DataT>& coefficient3, const std::vector<DataT>& coefficient4) const +{ + // Gauss-Seidel (Read Black} + if (MGParameters::relaxType == RelaxType::GaussSeidel) { + // for each slice + for (int iPass = 1; iPass <= 2; ++iPass) { + const int msw = (iPass % 2) ? 1 : 2; + for (int m = 0; m < iPhi; ++m) { + const int jsw = ((msw + m) % 2) ? 1 : 2; + int mp1 = m + 1; + int signPlus = 1; + int mm1 = m - 1; + int signMinus = 1; + // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) + if (symmetry == 1) { + if (mp1 > iPhi - 1) { + mp1 = iPhi - 2; + } + if (mm1 < 0) { + mm1 = 1; + } + } + // Anti-symmetry in phi + else if (symmetry == -1) { + if (mp1 > iPhi - 1) { + mp1 = iPhi - 2; + signPlus = -1; + } + if (mm1 < 0) { + mm1 = 1; + signMinus = -1; + } + } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi + if (mp1 > iPhi - 1) { + mp1 = m + 1 - iPhi; + } + if (mm1 < 0) { + mm1 = m - 1 + iPhi; + } + } + int isw = jsw; + for (int j = 1; j < tnZColumn - 1; ++j, isw = 3 - isw) { + for (int i = isw; i < tnRRow - 1; i += 2) { + (matricesCurrentV)(i, j, m) = (coefficient2[i] * (matricesCurrentV)(i - 1, j, m) + tempRatioZ * ((matricesCurrentV)(i, j - 1, m) + (matricesCurrentV)(i, j + 1, m)) + coefficient1[i] * (matricesCurrentV)(i + 1, j, m) + coefficient3[i] * (signPlus * (matricesCurrentV)(i, j, mp1) + signMinus * (matricesCurrentV)(i, j, mm1)) + (h2 * (matricesCurrentCharge)(i, j, m))) * coefficient4[i]; + } // end cols + } // end mParamGrid.NRVertices + } // end phi + } // end sweep + } else if (MGParameters::relaxType == RelaxType::Jacobi) { + // for each slice + for (int m = 0; m < iPhi; ++m) { + int mp1 = m + 1; + int signPlus = 1; + int mm1 = m - 1; + int signMinus = 1; + + // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) + if (symmetry == 1) { + if (mp1 > iPhi - 1) { + mp1 = iPhi - 2; + } + if (mm1 < 0) { + mm1 = 1; + } + } + // Anti-symmetry in phi + else if (symmetry == -1) { + if (mp1 > iPhi - 1) { + mp1 = iPhi - 2; + signPlus = -1; + } + if (mm1 < 0) { + mm1 = 1; + signMinus = -1; + } + } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi + if (mp1 > iPhi - 1) { + mp1 = m + 1 - iPhi; + } + if (mm1 < 0) { + mm1 = m - 1 + iPhi; + } + } + // Jacobian + for (int j = 1; j < tnZColumn - 1; ++j) { + for (int i = 1; i < tnRRow - 1; ++i) { + (matricesCurrentV)(i, j, m) = (coefficient2[i] * (matricesCurrentV)(i - 1, j, m) + tempRatioZ * ((matricesCurrentV)(i, j - 1, m) + (matricesCurrentV)(i, j + 1, m)) + coefficient1[i] * (matricesCurrentV)(i + 1, j, m) + coefficient3[i] * (signPlus * (matricesCurrentV)(i, j, mp1) + signMinus * (matricesCurrentV)(i, j, mm1)) + (h2 * (matricesCurrentCharge)(i, j, m))) * coefficient4[i]; + } // end cols + } // end mParamGrid.NRVertices + } // end phi + } else { + // Case weighted Jacobi + // TODO + } +} + +template <typename DataT> +void PoissonSolver<DataT>::relax2D(Vector& matricesCurrentV, const Vector& matricesCurrentCharge, const int tnRRow, const int tnZColumn, const DataT h2, const DataT tempFourth, const DataT tempRatio, + std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2) +{ + // Gauss-Seidel + const int iPhi = 0; + if (MGParameters::relaxType == RelaxType::GaussSeidel) { + int jsw = 1; + for (int iPass = 1; iPass <= 2; ++iPass, jsw = 3 - jsw) { + int isw = jsw; + for (int j = 1; j < tnZColumn - 1; ++j, isw = 3 - isw) { + for (int i = isw; i < tnRRow - 1; i += 2) { + matricesCurrentV(i, j, iPhi) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) + (h2 * matricesCurrentCharge(i, j, iPhi))); + } // end cols + } // end mParamGrid.NRVertices + } // end pass red-black + } else if (MGParameters::relaxType == RelaxType::Jacobi) { + for (int j = 1; j < tnZColumn - 1; ++j) { + for (int i = 1; i < tnRRow - 1; ++i) { + matricesCurrentV(i, j, iPhi) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) + (h2 * matricesCurrentCharge(i, j, iPhi))); + } // end cols + } // end mParamGrid.NRVertices + } else if (MGParameters::relaxType == RelaxType::WeightedJacobi) { + // Weighted Jacobi + // TODO + } +} + +template <typename DataT> +void PoissonSolver<DataT>::restrictBoundary3D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const +{ + // in case of full 3d and the mParamGrid.NPhiVertices is also coarsening + if (2 * newPhiSlice == oldPhiSlice) { + for (int m = 0, mm = 0; m < newPhiSlice; ++m, mm += 2) { + // for boundary + for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { + matricesCurrentCharge(0, j, m) = residue(0, jj, mm); + matricesCurrentCharge(tnRRow - 1, j, m) = residue((tnRRow - 1) * 2, jj, mm); + } + + // for boundary + for (int i = 0, ii = 0; i < tnRRow; ++i, ii += 2) { + matricesCurrentCharge(i, 0, m) = residue(ii, 0, mm); + matricesCurrentCharge(i, tnZColumn - 1, m) = residue(ii, (tnZColumn - 1) * 2, mm); + } + } // end phis + } else { + for (int m = 0; m < newPhiSlice; ++m) { + restrictBoundary2D(matricesCurrentCharge, residue, tnRRow, tnZColumn, m); + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::restrictBoundary2D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int tnPhi) const +{ + // for boundary + for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { + matricesCurrentCharge(0, j, tnPhi) = residue(0, jj, tnPhi); + matricesCurrentCharge(tnRRow - 1, j, tnPhi) = residue((tnRRow - 1) * 2, jj, tnPhi); + } + + // for boundary + for (int i = 0, ii = 0; i < tnRRow; ++i, ii += 2) { + matricesCurrentCharge(i, 0, tnPhi) = residue(ii, 0, tnPhi); + matricesCurrentCharge(i, tnZColumn - 1, tnPhi) = residue(ii, (tnZColumn - 1) * 2, tnPhi); + } +} + +template <typename DataT> +void PoissonSolver<DataT>::restrict3D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int newPhiSlice, const int oldPhiSlice) const +{ + if (2 * newPhiSlice == oldPhiSlice) { + int mm = 0; + for (int m = 0; m < newPhiSlice; m++, mm += 2) { + // assuming no symmetry + int mp1 = mm + 1; + int mm1 = mm - 1; + + if (mp1 > (oldPhiSlice)-1) { + mp1 = mm + 1 - (oldPhiSlice); + } + if (mm1 < 0) { + mm1 = mm - 1 + (oldPhiSlice); + } + + for (int i = 1, ii = 2; i < tnRRow - 1; ++i, ii += 2) { + for (int j = 1, jj = 2; j < tnZColumn - 1; ++j, jj += 2) { + + // at the same plane + const int iip1 = ii + 1; + const int iim1 = ii - 1; + const int jjp1 = jj + 1; + const int jjm1 = jj - 1; + const DataT s1 = residue(iip1, jj, mm) + residue(iim1, jj, mm) + residue(ii, jjp1, mm) + residue(ii, jjm1, mm) + residue(ii, jj, mp1) + residue(ii, jj, mm1); + + const DataT s2 = (residue(iip1, jjp1, mm) + residue(iip1, jjm1, mm) + residue(iip1, jj, mp1) + residue(iip1, jj, mm1)) + + (residue(iim1, jjm1, mm) + residue(iim1, jjp1, mm) + residue(iim1, jj, mp1) + residue(iim1, jj, mm1)) + + residue(ii, jjm1, mp1) + residue(ii, jjp1, mm1) + residue(ii, jjm1, mm1) + residue(ii, jjp1, mp1); + + const DataT s3 = (residue(iip1, jjp1, mp1) + residue(iip1, jjm1, mp1) + residue(iip1, jjp1, mm1) + residue(iip1, jjm1, mm1)) + + (residue(iim1, jjm1, mm1) + residue(iim1, jjp1, mm1) + residue(iim1, jjm1, mp1) + residue(iim1, jjp1, mp1)); + + matricesCurrentCharge(i, j, m) = residue(ii, jj, mm) / 8 + s1 / 16 + s2 / 32 + s3 / 64; + } // end cols + } // end mParamGrid.NRVertices + + // for boundary + for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { + matricesCurrentCharge(0, j, m) = residue(0, jj, mm); + matricesCurrentCharge(tnRRow - 1, j, m) = residue((tnRRow - 1) * 2, jj, mm); + } + + // for boundary + for (int i = 0, ii = 0; i < tnRRow; ++i, ii += 2) { + matricesCurrentCharge(i, 0, m) = residue(ii, 0, mm); + matricesCurrentCharge(i, tnZColumn - 1, m) = residue(ii, (tnZColumn - 1) * 2, mm); + } + } // end phis + + } else { + for (int m = 0; m < newPhiSlice; ++m) { + restrict2D(matricesCurrentCharge, residue, tnRRow, tnZColumn, m); + } + } +} + +template <typename DataT> +void PoissonSolver<DataT>::restrict2D(Vector& matricesCurrentCharge, const Vector& residue, const int tnRRow, const int tnZColumn, const int iphi) const +{ + for (int i = 1, ii = 2; i < tnRRow - 1; ++i, ii += 2) { + for (int j = 1, jj = 2; j < tnZColumn - 1; ++j, jj += 2) { + const int iip1 = ii + 1; + const int iim1 = ii - 1; + const int jjp1 = jj + 1; + const int jjm1 = jj - 1; + if (MGParameters::gtType == GridTransferType::Half) { + // half + matricesCurrentCharge(i, j, iphi) = residue(ii, jj, iphi) / 2 + (residue(iip1, jj, iphi) + residue(iim1, jj, iphi) + residue(ii, jjp1, iphi) + residue(ii, jjm1, iphi)) / 8; + } else if (MGParameters::gtType == GridTransferType::Full) { + matricesCurrentCharge(i, j, iphi) = residue(ii, jj, iphi) / 4 + (residue(iip1, jj, iphi) + residue(iim1, jj, iphi) + residue(ii, jjp1, iphi) + residue(ii, jjm1, iphi)) / 8 + + (residue(iip1, jjp1, iphi) + residue(iim1, jjp1, iphi) + residue(iip1, jjm1, iphi) + residue(iim1, jjm1, iphi)) / 16; + } + } // end cols + } // end mParamGrid.NRVertices + // boundary + // for boundary + for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { + matricesCurrentCharge(0, j, iphi) = residue(0, jj, iphi); + matricesCurrentCharge(tnRRow - 1, j, iphi) = residue((tnRRow - 1) * 2, jj, iphi); + } + // for boundary + for (int i = 0, ii = 0; i < tnRRow; ++i, ii += 2) { + matricesCurrentCharge(i, 0, iphi) = residue(ii, 0, iphi); + matricesCurrentCharge(i, tnZColumn - 1, iphi) = residue(ii, (tnZColumn - 1) * 2, iphi); + } +} + +template <typename DataT> +DataT PoissonSolver<DataT>::getConvergenceError(const Vector& matricesCurrentV, Vector& prevArrayV) const +{ + std::vector<DataT> errorArr(prevArrayV.getNphi()); + + // subtract the two matrices + std::transform(prevArrayV.begin(), prevArrayV.end(), matricesCurrentV.begin(), prevArrayV.begin(), std::minus<DataT>()); + +#pragma omp parallel for num_threads(sNThreads) // parallising this loop is possible - but using more than 2 cores makes it slower - + for (unsigned int m = 0; m < prevArrayV.getNphi(); ++m) { + // square each entry in the vector and sum them up + const auto phiStep = prevArrayV.getNr() * prevArrayV.getNz(); // number of points in one phi slice + const auto start = prevArrayV.begin() + m * phiStep; + const auto end = start + phiStep; + errorArr[m] = std::inner_product(start, end, start, DataT(0)); // inner product "Sum (matrix[a]*matrix[a])" + } + // return largest error + return *std::max_element(std::begin(errorArr), std::end(errorArr)); +} + +template <typename DataT> +void PoissonSolver<DataT>::calcCoefficients(unsigned int from, unsigned int to, const DataT h, const DataT tempRatioZ, const DataT tempRatioPhi, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2, std::vector<DataT>& coefficient3, std::vector<DataT>& coefficient4) const +{ + for (unsigned int i = from; i < to; ++i) { + const DataT radiusInv = 1 / (TPCParameters<DataT>::IFCRADIUS + i * h); + const DataT hRadiusTmp = h * radiusInv / 2; + coefficient1[i] = 1 + hRadiusTmp; + coefficient2[i] = 1 - hRadiusTmp; + coefficient3[i] = tempRatioPhi * radiusInv * radiusInv; + coefficient4[i] = 1 / (2 * (1 + tempRatioZ + coefficient3[i])); + } +} + +template <typename DataT> +void PoissonSolver<DataT>::calcCoefficients2D(unsigned int from, unsigned int to, const DataT h, std::vector<DataT>& coefficient1, std::vector<DataT>& coefficient2) const +{ + for (int i = from; i < to; ++i) { + DataT radiusInvHalf = h / (2 * (TPCParameters<DataT>::IFCRADIUS + i * h)); + coefficient1[i] = 1 + radiusInvHalf; + coefficient2[i] = 1 - radiusInvHalf; + } +} + +template class o2::tpc::PoissonSolver<double>; +template class o2::tpc::PoissonSolver<float>; diff --git a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx new file mode 100644 index 0000000000000..94c61e0fe584a --- /dev/null +++ b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx @@ -0,0 +1,1764 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SpaceCharge.cxx +/// \brief Definition of SpaceCharge class +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Aug 21, 2020 + +#include "TPCSpaceCharge/SpaceCharge.h" +#include "fmt/core.h" +#include "Framework/Logger.h" +#include "TPCSpaceCharge/PoissonSolver.h" +#include "Framework/Logger.h" +#include "TGeoGlobalMagField.h" +#include "TPCBase/ParameterGas.h" +#include "Field/MagneticField.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "TPCBase/CalDet.h" +#include "TPCBase/Painter.h" + +#include <numeric> +#include <chrono> +#include "TF1.h" +#include "TH3.h" +#include "TH2F.h" +#include "TGraph.h" +#include "TCanvas.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +templateClassImp(o2::tpc::SpaceCharge); + +using namespace o2::tpc; + +template <typename DataT> +void SpaceCharge<DataT>::setGrid(const unsigned short nZVertices, const unsigned short nRVertices, const unsigned short nPhiVertices) +{ + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NZVertices", nZVertices); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NRVertices", nRVertices); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NPhiVertices", nPhiVertices); +} + +template <typename DataT> +void SpaceCharge<DataT>::calculateDistortionsCorrections(const o2::tpc::Side side, const bool calcVectors) +{ + using timer = std::chrono::high_resolution_clock; + using SC = o2::tpc::SpaceCharge<DataT>; + if (!mIsChargeSet[side]) { + LOGP(ERROR, "the charge is not set!"); + } + + const std::array<std::string, 2> sglobalType{"local distortion/correction interpolator", "Electric fields"}; + const std::array<std::string, 2> sglobalDistType{"Standard method", "interpolation of global corrections"}; + const std::array<std::string, 2> sideName{"A", "C"}; + + LOGP(info, "====== starting calculation of distortions and corrections for Side {} ======", sideName[side]); + LOGP(info, "Using {} threads", getNThreads()); + + if (getGlobalDistCorrMethod() == SC::GlobalDistCorrMethod::LocalDistCorr) { + LOGP(info, "calculation of global distortions and corrections are performed by using: {}", sglobalType[0]); + } else { + LOGP(info, "calculation of global distortions and corrections are performed by using: {}", sglobalType[1]); + } + + if (getGlobalDistType() == SC::GlobalDistType::Fast) { + LOGP(info, "calculation of global distortions performed by following method: {}", sglobalDistType[1]); + } else if (getGlobalDistType() == SC::GlobalDistType::Standard) { + LOGP(info, "calculation of global distortions performed by following method: {}", sglobalDistType[0]); + } else { + LOGP(info, "skipping calculation of global distortions"); + } + + auto startTotal = timer::now(); + + auto start = timer::now(); + poissonSolver(side); + auto stop = timer::now(); + std::chrono::duration<float> time = stop - start; + LOGP(info, "Poisson Solver time: {}", time.count()); + + start = timer::now(); + calcEField(side); + stop = timer::now(); + time = stop - start; + LOGP(info, "electric field calculation time: {}", time.count()); + + const auto numEFields = getElectricFieldsInterpolator(side); + if (getGlobalDistType() == SC::GlobalDistType::Standard) { + start = timer::now(); + const auto dist = o2::tpc::SpaceCharge<DataT>::Type::Distortions; + calcLocalDistortionsCorrections(dist, numEFields); // local distortion calculation + stop = timer::now(); + time = stop - start; + LOGP(info, "local distortions time: {}", time.count()); + } else { + LOGP(info, "skipping local distortions (not needed)"); + } + + start = timer::now(); + const auto corr = o2::tpc::SpaceCharge<DataT>::Type::Corrections; + calcLocalDistortionsCorrections(corr, numEFields); // local correction calculation + stop = timer::now(); + time = stop - start; + LOGP(info, "local corrections time: {}", time.count()); + + if (calcVectors) { + start = timer::now(); + calcLocalDistortionCorrectionVector(numEFields); + stop = timer::now(); + time = stop - start; + LOGP(info, "local correction/distortion vector time: {}", time.count()); + } + + start = timer::now(); + const auto lCorrInterpolator = getLocalCorrInterpolator(side); + (getGlobalDistCorrMethod() == SC::GlobalDistCorrMethod::LocalDistCorr) ? calcGlobalCorrections(lCorrInterpolator) : calcGlobalCorrections(numEFields); + stop = timer::now(); + time = stop - start; + LOGP(info, "global corrections time: {}", time.count()); + start = timer::now(); + if (getGlobalDistType() == SC::GlobalDistType::Fast) { + const auto globalCorrInterpolator = getGlobalCorrInterpolator(side); + calcGlobalDistWithGlobalCorrIterative(globalCorrInterpolator); + } else if (getGlobalDistType() == SC::GlobalDistType::Standard) { + const auto lDistInterpolator = getLocalDistInterpolator(side); + (getGlobalDistCorrMethod() == SC::GlobalDistCorrMethod::LocalDistCorr) ? calcGlobalDistortions(lDistInterpolator) : calcGlobalDistortions(numEFields); + } else { + } + + stop = timer::now(); + time = stop - start; + LOGP(info, "global distortions time: {}", time.count()); + + stop = timer::now(); + time = stop - startTotal; + LOGP(info, "everything is done. Total Time: {}", time.count()); +} + +template <typename DataT> +DataT SpaceCharge<DataT>::regulateR(const DataT posR, const Side side) const +{ + const DataT minR = getRMin(side) - 4 * getGridSpacingR(side); + if (posR < minR) { + return minR; + } + const DataT maxR = getRMax(side) + 2 * getGridSpacingR(side); + if (posR > maxR) { + return maxR; + } + return posR; +} + +template <typename DataT> +void SpaceCharge<DataT>::dumpToFile(TFile& file, const Side side) const +{ + dumpElectricFields(file, side); + dumpPotential(file, side); + dumpDensity(file, side); + dumpGlobalDistortions(file, side); + dumpGlobalCorrections(file, side); + dumpLocalCorrections(file, side); + dumpLocalDistortions(file, side); + dumpLocalDistCorrVectors(file, side); +} + +template <typename DataT> +void SpaceCharge<DataT>::setFromFile(TFile& file, const Side side) +{ + setDensityFromFile(file, side); + setPotentialFromFile(file, side); + setElectricFieldsFromFile(file, side); + setLocalDistortionsFromFile(file, side); + setLocalCorrectionsFromFile(file, side); + setGlobalDistortionsFromFile(file, side); + setGlobalCorrectionsFromFile(file, side); + setLocalDistCorrVectorsFromFile(file, side); +} + +template <typename DataT> +void SpaceCharge<DataT>::setChargeDensityFromFormula(const AnalyticalFields<DataT>& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = getZVertex(iZ, side); + mDensity[side](iZ, iR, iPhi) = formulaStruct.evalDensity(z, radius, phi); + } + } + } + mIsChargeSet[side] = true; +} + +template <typename DataT> +void SpaceCharge<DataT>::setPotentialFromFormula(const AnalyticalFields<DataT>& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = getZVertex(iZ, side); + mPotential[side](iZ, iR, iPhi) = formulaStruct.evalPotential(z, radius, phi); + } + } + } +} + +template <typename DataT> +void SpaceCharge<DataT>::setPotentialBoundaryFromFormula(const AnalyticalFields<DataT>& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = getZVertex(iZ, side); + const size_t iR = 0; + const DataT radius = getRVertex(iR, side); + mPotential[side](iZ, iR, iPhi) = formulaStruct.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = getZVertex(iZ, side); + const size_t iR = mParamGrid.NRVertices - 1; + const DataT radius = getRVertex(iR, side); + mPotential[side](iZ, iR, iPhi) = formulaStruct.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + const size_t iZ = 0; + const DataT z = getZVertex(iZ, side); + mPotential[side](iZ, iR, iPhi) = formulaStruct.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + const size_t iZ = mParamGrid.NZVertices - 1; + const DataT z = getZVertex(iZ, side); + mPotential[side](iZ, iR, iPhi) = formulaStruct.evalPotential(z, radius, phi); + } + } +} + +template <typename DataT> +void SpaceCharge<DataT>::poissonSolver(const Side side, const int maxIteration, const DataT stoppingConvergence, const int symmetry) +{ + PoissonSolver<DataT>::setConvergenceError(stoppingConvergence); + PoissonSolver<DataT> poissonSolver(mGrid3D[0]); + poissonSolver.poissonSolver3D(mPotential[side], mDensity[side], symmetry); +} + +template <typename DataT> +void SpaceCharge<DataT>::setEFieldFromFormula(const AnalyticalFields<DataT>& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT radius = getRVertex(iR, side); + const DataT z = getZVertex(iZ, side); + const DataT phi = getPhiVertex(iPhi, side); + mElectricFieldEr[side](iZ, iR, iPhi) = formulaStruct.evalEr(z, radius, phi); + mElectricFieldEz[side](iZ, iR, iPhi) = formulaStruct.evalEz(z, radius, phi); + mElectricFieldEphi[side](iZ, iR, iPhi) = formulaStruct.evalEphi(z, radius, phi); + } + } + } + mIsEfieldSet[side] = true; +} + +template <typename DataT> +void SpaceCharge<DataT>::calcEField(const Side side) +{ +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const int symmetry = 0; + size_t tmpPlus = iPhi + 1; + int signPlus = 1; + int tmpMinus = static_cast<int>(iPhi - 1); + int signMinus = 1; + if (symmetry == 1 || symmetry == -1) { // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) + if (tmpPlus > mParamGrid.NPhiVertices - 1) { + if (symmetry == -1) { + signPlus = -1; + } + tmpPlus = mParamGrid.NPhiVertices - 2; + } + if (tmpMinus < 0) { + tmpMinus = 1; // SHOULD IT BE =0? + if (symmetry == -1) { + signMinus = -1; + } + } + } else { // No Symmetries in phi, no boundaries, the calculations is continuous across all phi + if (tmpPlus > mParamGrid.NPhiVertices - 1) { + tmpPlus = iPhi + 1 - mParamGrid.NPhiVertices; + } + if (tmpMinus < 0) { + tmpMinus = static_cast<int>(iPhi - 1 + mParamGrid.NPhiVertices); + } + } + + // for non-boundary V + for (size_t iR = 1; iR < mParamGrid.NRVertices - 1; iR++) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 1; iZ < mParamGrid.NZVertices - 1; iZ++) { + mElectricFieldEr[side](iZ, iR, iPhi) = -1 * (mPotential[side](iZ, iR + 1, iPhi) - mPotential[side](iZ, iR - 1, iPhi)) * static_cast<DataT>(0.5) * getInvSpacingR(side); // r direction + mElectricFieldEz[side](iZ, iR, iPhi) = -1 * (mPotential[side](iZ + 1, iR, iPhi) - mPotential[side](iZ - 1, iR, iPhi)) * static_cast<DataT>(0.5) * getInvSpacingZ(side); // z direction + mElectricFieldEphi[side](iZ, iR, iPhi) = -1 * (signPlus * mPotential[side](iZ, iR, tmpPlus) - signMinus * mPotential[side](iZ, iR, tmpMinus)) * static_cast<DataT>(0.5) * getInvSpacingPhi(side) / radius; // phi direction + } + } + + // for boundary-r + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; iZ++) { + mElectricFieldEr[side](iZ, 0, iPhi) = -1 * (-static_cast<DataT>(0.5) * mPotential[side](iZ, 2, iPhi) + 2 * mPotential[side](iZ, 1, iPhi) - static_cast<DataT>(1.5) * mPotential[side](iZ, 0, iPhi)) * getInvSpacingR(side); // forward difference + mElectricFieldEr[side](iZ, mParamGrid.NRVertices - 1, iPhi) = -1 * (static_cast<DataT>(1.5) * mPotential[side](iZ, mParamGrid.NRVertices - 1, iPhi) - 2 * mPotential[side](iZ, mParamGrid.NRVertices - 2, iPhi) + static_cast<DataT>(0.5) * mPotential[side](iZ, mParamGrid.NRVertices - 3, iPhi)) * getInvSpacingR(side); // backward difference + } + + for (size_t iR = 0; iR < mParamGrid.NRVertices; iR += mParamGrid.NRVertices - 1) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 1; iZ < mParamGrid.NZVertices - 1; iZ++) { + mElectricFieldEz[side](iZ, iR, iPhi) = -1 * (mPotential[side](iZ + 1, iR, iPhi) - mPotential[side](iZ - 1, iR, iPhi)) * static_cast<DataT>(0.5) * getInvSpacingZ(side); // z direction + mElectricFieldEphi[side](iZ, iR, iPhi) = -1 * (signPlus * mPotential[side](iZ, iR, tmpPlus) - signMinus * mPotential[side](iZ, iR, tmpMinus)) * static_cast<DataT>(0.5) * getInvSpacingPhi(side) / radius; // phi direction + } + } + + // for boundary-z + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + mElectricFieldEz[side](0, iR, iPhi) = -1 * (-static_cast<DataT>(0.5) * mPotential[side](2, iR, iPhi) + 2 * mPotential[side](1, iR, iPhi) - static_cast<DataT>(1.5) * mPotential[side](0, iR, iPhi)) * getInvSpacingZ(side); + mElectricFieldEz[side](mParamGrid.NZVertices - 1, iR, iPhi) = -1 * (static_cast<DataT>(1.5) * mPotential[side](mParamGrid.NZVertices - 1, iR, iPhi) - 2 * mPotential[side](mParamGrid.NZVertices - 2, iR, iPhi) + static_cast<DataT>(0.5) * mPotential[side](mParamGrid.NZVertices - 3, iR, iPhi)) * getInvSpacingZ(side); + } + + for (size_t iR = 1; iR < mParamGrid.NRVertices - 1; ++iR) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; iZ += mParamGrid.NZVertices - 1) { + mElectricFieldEr[side](iZ, iR, iPhi) = -1 * (mPotential[side](iZ, iR + 1, iPhi) - mPotential[side](iZ, iR - 1, iPhi)) * static_cast<DataT>(0.5) * getInvSpacingR(side); // r direction + mElectricFieldEphi[side](iZ, iR, iPhi) = -1 * (signPlus * mPotential[side](iZ, iR, tmpPlus) - signMinus * mPotential[side](iZ, iR, tmpMinus)) * static_cast<DataT>(0.5) * getInvSpacingPhi(side) / radius; // phi direction + } + } + + // corner points for EPhi + for (size_t iR = 0; iR < mParamGrid.NRVertices; iR += mParamGrid.NRVertices - 1) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; iZ += mParamGrid.NZVertices - 1) { + mElectricFieldEphi[side](iZ, iR, iPhi) = -1 * (signPlus * mPotential[side](iZ, iR, tmpPlus) - signMinus * mPotential[side](iZ, iR, tmpMinus)) * static_cast<DataT>(0.5) * getInvSpacingPhi(side) / radius; // phi direction + } + } + } + mIsEfieldSet[side] = true; +} + +template <typename DataT> +void SpaceCharge<DataT>::calcGlobalDistWithGlobalCorrIterative(const DistCorrInterpolator<DataT>& globCorr, const int maxIter, const DataT approachZ, const DataT approachR, const DataT approachPhi, const DataT diffCorr) +{ + const Side side = globCorr.getSide(); + +#pragma omp parallel for num_threads(sNThreads) + for (unsigned int iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = getZVertex(iZ, side); + + unsigned int nearestiZ = iZ; + unsigned int nearestiR = iR; + unsigned int nearestiPhi = iPhi; + + DataT nearestZ = getZVertex(nearestiZ, side); + DataT nearestR = getRVertex(nearestiR, side); + DataT nearestPhi = getPhiVertex(nearestiPhi, side); + + // + //========================================================================================== + //==== start algorithm: use tricubic upsampling to numerically approach the query point ==== + //========================================================================================== + // + // 1. calculate difference from nearest point to query point with stepwidth factor x + // and approach the new point + // + DataT stepR = (radius - nearestR) * approachR; + DataT stepZ = (z - nearestZ) * approachZ; + DataT stepPhi = (phi - nearestPhi) * approachPhi; + + // needed to check for convergence + DataT lastCorrdR = std::numeric_limits<DataT>::max(); + DataT lastCorrdZ = std::numeric_limits<DataT>::max(); + DataT lastCorrdRPhi = std::numeric_limits<DataT>::max(); + + // interpolated global correction + DataT corrdR = 0; + DataT corrdRPhi = 0; + DataT corrdZ = 0; + + for (int iter = 0; iter < maxIter; ++iter) { + // 2. get new point coordinates + const DataT rCurrPos = getRVertex(nearestiR, side) + stepR; + const DataT zCurrPos = getZVertex(nearestiZ, side) + stepZ; + const DataT phiCurrPos = getPhiVertex(nearestiPhi, side) + stepPhi; + + // interpolate global correction at new point and calculate position of global correction + // corrdR = globCorr.evalSparsedR(zCurrPos, rCurrPos, phiCurrPos); + corrdR = globCorr.evaldR(zCurrPos, rCurrPos, phiCurrPos); + const DataT rNewPos = rCurrPos + corrdR; + + // const DataT corrPhi = globCorr.evalSparsedRPhi(zCurrPos, rCurrPos, phiCurrPos) / rCurrPos; + const DataT corrPhi = globCorr.evaldRPhi(zCurrPos, rCurrPos, phiCurrPos) / rCurrPos; + corrdRPhi = corrPhi * rNewPos; // normalize to new r coordinate + const DataT phiNewPos = phiCurrPos + corrPhi; + + // corrdZ = globCorr.evalSparsedZ(zCurrPos, rCurrPos, phiCurrPos); + corrdZ = globCorr.evaldZ(zCurrPos, rCurrPos, phiCurrPos); + const DataT zNewPos = zCurrPos + corrdZ; + + // approach desired coordinate + stepR += (radius - rNewPos) * approachR; + stepZ += (z - zNewPos) * approachZ; + stepPhi += (phi - phiNewPos) * approachPhi; + + // check for convergence + const DataT diffCorrdR = std::abs(corrdR - lastCorrdR); + const DataT diffCorrdRZ = std::abs(corrdZ - lastCorrdZ); + const DataT diffCorrdRPhi = std::abs(corrdRPhi - lastCorrdRPhi); + + // stop algorithm if converged + if (diffCorrdR < diffCorr && diffCorrdRZ < diffCorr && diffCorrdRPhi < diffCorr) { + break; + } + + lastCorrdR = corrdR; + lastCorrdZ = corrdZ; + lastCorrdRPhi = corrdRPhi; + } + // set global distortions if algorithm converged or iterations exceed max numbers of iterations + mGlobalDistdR[side](iZ, iR, iPhi) = -corrdR; + mGlobalDistdRPhi[side](iZ, iR, iPhi) = -corrdRPhi; + mGlobalDistdZ[side](iZ, iR, iPhi) = -corrdZ; + } + } + } + // set flag that global distortions are set to true + mIsGlobalDistSet[side] = true; +} + +template <typename DataT> +NumericalFields<DataT> SpaceCharge<DataT>::getElectricFieldsInterpolator(const Side side) const +{ + if (!mIsEfieldSet[side]) { + LOGP(warning, "============== E-Fields are not set! ==============\n"); + } + NumericalFields<DataT> numFields(mElectricFieldEr[side], mElectricFieldEz[side], mElectricFieldEphi[side], mGrid3D[side], side); + return numFields; +} + +template <typename DataT> +DistCorrInterpolator<DataT> SpaceCharge<DataT>::getLocalDistInterpolator(const Side side) const +{ + if (!mIsLocalDistSet[side]) { + LOGP(warning, "============== local distortions not set! ==============\n"); + } + DistCorrInterpolator<DataT> numFields(mLocalDistdR[side], mLocalDistdZ[side], mLocalDistdRPhi[side], mGrid3D[side], side); + return numFields; +} + +template <typename DataT> +DistCorrInterpolator<DataT> SpaceCharge<DataT>::getLocalCorrInterpolator(const Side side) const +{ + if (!mIsLocalCorrSet[side]) { + LOGP(warning, "============== local corrections not set! ==============\n"); + } + DistCorrInterpolator<DataT> numFields(mLocalCorrdR[side], mLocalCorrdZ[side], mLocalCorrdRPhi[side], mGrid3D[side], side); + return numFields; +} + +template <typename DataT> +DistCorrInterpolator<DataT> SpaceCharge<DataT>::getGlobalDistInterpolator(const Side side) const +{ + if (!mIsGlobalDistSet[side]) { + LOGP(warning, "============== global distortions not set ==============\n"); + } + DistCorrInterpolator<DataT> numFields(mGlobalDistdR[side], mGlobalDistdZ[side], mGlobalDistdRPhi[side], mGrid3D[side], side); + return numFields; +} + +template <typename DataT> +DistCorrInterpolator<DataT> SpaceCharge<DataT>::getGlobalCorrInterpolator(const Side side) const +{ + if (!mIsGlobalCorrSet[side]) { + LOGP(warning, "============== global corrections not set ==============\n"); + } + DistCorrInterpolator<DataT> numFields(mGlobalCorrdR[side], mGlobalCorrdZ[side], mGlobalCorrdRPhi[side], mGrid3D[side], side); + return numFields; +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpElectricFields(TFile& outf, const Side side) const +{ + if (!mIsEfieldSet[side]) { + LOGP(warning, "============== E-Fields are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int er = mElectricFieldEr[side].writeToFile(outf, fmt::format("fieldEr_side{}", sideName).data()); + const int ez = mElectricFieldEz[side].writeToFile(outf, fmt::format("fieldEz_side{}", sideName).data()); + const int ephi = mElectricFieldEphi[side].writeToFile(outf, fmt::format("fieldEphi_side{}", sideName).data()); + return er + ez + ephi; +} + +template <typename DataT> +void SpaceCharge<DataT>::setElectricFieldsFromFile(TFile& inpf, const Side side) +{ + const std::string sideName = getSideName(side); + mElectricFieldEr[side].initFromFile(inpf, fmt::format("fieldEr_side{}", sideName).data()); + mElectricFieldEz[side].initFromFile(inpf, fmt::format("fieldEz_side{}", sideName).data()); + mElectricFieldEphi[side].initFromFile(inpf, fmt::format("fieldEphi_side{}", sideName).data()); + mIsEfieldSet[side] = true; +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpGlobalDistortions(TFile& outf, const Side side) const +{ + if (!mIsGlobalDistSet[side]) { + LOGP(warning, "============== global distortions are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int er = mGlobalDistdR[side].writeToFile(outf, fmt::format("distR_side{}", sideName).data()); + const int ez = mGlobalDistdZ[side].writeToFile(outf, fmt::format("distZ_side{}", sideName).data()); + const int ephi = mGlobalDistdRPhi[side].writeToFile(outf, fmt::format("distRphi_side{}", sideName).data()); + return er + ez + ephi; +} + +template <typename DataT> +void SpaceCharge<DataT>::setGlobalDistortionsFromFile(TFile& inpf, const Side side) +{ + mIsGlobalDistSet[side] = true; + const std::string sideName = getSideName(side); + mGlobalDistdR[side].initFromFile(inpf, fmt::format("distR_side{}", sideName).data()); + mGlobalDistdZ[side].initFromFile(inpf, fmt::format("distZ_side{}", sideName).data()); + mGlobalDistdRPhi[side].initFromFile(inpf, fmt::format("distRphi_side{}", sideName).data()); +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpGlobalCorrections(TFile& outf, const Side side) const +{ + if (!mIsGlobalCorrSet[side]) { + LOGP(warning, "============== global corrections are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int er = mGlobalCorrdR[side].writeToFile(outf, fmt::format("corrR_side{}", sideName).data()); + const int ez = mGlobalCorrdZ[side].writeToFile(outf, fmt::format("corrZ_side{}", sideName).data()); + const int ephi = mGlobalCorrdRPhi[side].writeToFile(outf, fmt::format("corrRPhi_side{}", sideName).data()); + return er + ez + ephi; +} + +template <typename DataT> +void SpaceCharge<DataT>::setGlobalCorrectionsFromFile(TFile& inpf, const Side side) +{ + mIsGlobalCorrSet[side] = true; + const std::string sideName = getSideName(side); + mGlobalCorrdR[side].initFromFile(inpf, fmt::format("corrR_side{}", sideName).data()); + mGlobalCorrdZ[side].initFromFile(inpf, fmt::format("corrZ_side{}", sideName).data()); + mGlobalCorrdRPhi[side].initFromFile(inpf, fmt::format("corrRPhi_side{}", sideName).data()); +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpLocalCorrections(TFile& outf, const Side side) const +{ + if (!mIsLocalCorrSet[side]) { + LOGP(warning, "============== local corrections are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int lCorrdR = mLocalCorrdR[side].writeToFile(outf, fmt::format("lcorrR_side{}", sideName).data()); + const int lCorrdZ = mLocalCorrdZ[side].writeToFile(outf, fmt::format("lcorrZ_side{}", sideName).data()); + const int lCorrdRPhi = mLocalCorrdRPhi[side].writeToFile(outf, fmt::format("lcorrRPhi_side{}", sideName).data()); + return lCorrdR + lCorrdZ + lCorrdRPhi; +} + +template <typename DataT> +void SpaceCharge<DataT>::setLocalCorrectionsFromFile(TFile& inpf, const Side side) +{ + const std::string sideName = getSideName(side); + const bool lCorrdR = mLocalCorrdR[side].initFromFile(inpf, fmt::format("lcorrR_side{}", sideName).data()); + const bool lCorrdZ = mLocalCorrdZ[side].initFromFile(inpf, fmt::format("lcorrZ_side{}", sideName).data()); + const bool lCorrdRPhi = mLocalCorrdRPhi[side].initFromFile(inpf, fmt::format("lcorrRPhi_side{}", sideName).data()); + if (lCorrdR && lCorrdZ && lCorrdRPhi) { + mIsLocalCorrSet[side] = true; + } else { + mIsLocalCorrSet[side] = false; + } +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpLocalDistortions(TFile& outf, const Side side) const +{ + if (!mIsLocalDistSet[side]) { + LOGP(warning, "============== local distortions are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int lDistdR = mLocalDistdR[side].writeToFile(outf, fmt::format("ldistR_side{}", sideName).data()); + const int lDistdZ = mLocalDistdZ[side].writeToFile(outf, fmt::format("ldistZ_side{}", sideName).data()); + const int lDistdRPhi = mLocalDistdRPhi[side].writeToFile(outf, fmt::format("ldistRPhi_side{}", sideName).data()); + return lDistdR + lDistdZ + lDistdRPhi; +} + +template <typename DataT> +int SpaceCharge<DataT>::dumpLocalDistCorrVectors(TFile& outf, const Side side) const +{ + if (!mIsLocalVecDistSet[side]) { + LOGP(warning, "============== local distortion vectors are not set! returning ==============\n"); + return 0; + } + const std::string sideName = getSideName(side); + const int lVecDistdR = mLocalVecDistdR[side].writeToFile(outf, fmt::format("lvecdistR_side{}", sideName).data()); + const int lVecDistdZ = mLocalVecDistdZ[side].writeToFile(outf, fmt::format("lvecdistZ_side{}", sideName).data()); + const int lVecDistdRPhi = mLocalVecDistdRPhi[side].writeToFile(outf, fmt::format("lvecdistRPhi_side{}", sideName).data()); + return lVecDistdR + lVecDistdZ + lVecDistdRPhi; +} + +template <typename DataT> +void SpaceCharge<DataT>::setLocalDistortionsFromFile(TFile& inpf, const Side side) +{ + const std::string sideName = getSideName(side); + const bool lDistdR = mLocalDistdR[side].initFromFile(inpf, fmt::format("ldistR_side{}", sideName).data()); + const bool lDistdZ = mLocalDistdZ[side].initFromFile(inpf, fmt::format("ldistZ_side{}", sideName).data()); + const bool lDistdRPhi = mLocalDistdRPhi[side].initFromFile(inpf, fmt::format("ldistRPhi_side{}", sideName).data()); + + if (lDistdR && lDistdZ && lDistdRPhi) { + mIsLocalDistSet[side] = true; + } else { + mIsLocalDistSet[side] = false; + } +} + +template <typename DataT> +void SpaceCharge<DataT>::setLocalDistCorrVectorsFromFile(TFile& inpf, const Side side) +{ + const std::string sideName = getSideName(side); + const bool lVecDistdR = mLocalVecDistdR[side].initFromFile(inpf, fmt::format("lvecdistR_side{}", sideName).data()); + const bool lVecDistdZ = mLocalVecDistdZ[side].initFromFile(inpf, fmt::format("lvecdistZ_side{}", sideName).data()); + const bool lVecDistdRPhi = mLocalVecDistdRPhi[side].initFromFile(inpf, fmt::format("lvecdistRPhi_side{}", sideName).data()); + + if (lVecDistdR && lVecDistdZ && lVecDistdRPhi) { + mIsLocalVecDistSet[side] = true; + } else { + mIsLocalVecDistSet[side] = false; + } +} + +template <typename DataT> +void SpaceCharge<DataT>::fillChargeDensityFromFile(TFile& fInp, const char* name) +{ + TH3* hisSCDensity3D = (TH3*)fInp.Get(name); + fillChargeDensityFromHisto(*hisSCDensity3D); + delete hisSCDensity3D; +} + +template <typename DataT> +void SpaceCharge<DataT>::fillChargeDensityFromHisto(const TH3& hisSCDensity3D) +{ + TH3DataT hRebin = rebinDensityHisto(hisSCDensity3D, mParamGrid.NZVertices, mParamGrid.NRVertices, mParamGrid.NPhiVertices); + for (int side = Side::A; side < SIDES; ++side) { + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const size_t zBin = side == Side::A ? mParamGrid.NZVertices + iZ + 1 : mParamGrid.NZVertices - iZ; + mDensity[side](iZ, iR, iPhi) = hRebin.GetBinContent(iPhi + 1, iR + 1, zBin); + } + } + } + mIsChargeSet[side] = true; + } +} + +template <typename DataT> +void SpaceCharge<DataT>::fillChargeDensityFromCalDet(const std::vector<CalDet<float>>& calSCDensity3D) +{ + const auto hConverted = o2::tpc::painter::convertCalDetToTH3(calSCDensity3D, true, mParamGrid.NRVertices, getRMin(Side::A), getRMax(Side::A), mParamGrid.NPhiVertices, getZMax(Side::A)); + fillChargeDensityFromHisto(hConverted); +} + +template <typename DataT> +void SpaceCharge<DataT>::fillChargeFromCalDet(const std::vector<CalDet<float>>& calCharge3D) +{ + auto hConverted = o2::tpc::painter::convertCalDetToTH3(calCharge3D, false, mParamGrid.NRVertices, getRMin(Side::A), getRMax(Side::A), mParamGrid.NPhiVertices, getZMax(Side::A)); + normalizeHistoQVEps0(hConverted); + fillChargeDensityFromHisto(hConverted); +} + +template <typename DataT> +typename SpaceCharge<DataT>::TH3DataT SpaceCharge<DataT>::rebinDensityHisto(const TH3& hOrig, const unsigned short nBinsZNew, const unsigned short nBinsRNew, const unsigned short nBinsPhiNew) +{ + TH3DataT hRebin{}; + const int nBinsZNewTwo = 2 * nBinsZNew; + + const auto phiLow = hOrig.GetXaxis()->GetBinLowEdge(1); + const auto phiUp = hOrig.GetXaxis()->GetBinUpEdge(hOrig.GetNbinsX()); + const auto rLow = hOrig.GetYaxis()->GetBinLowEdge(1); + const auto rUp = hOrig.GetYaxis()->GetBinUpEdge(hOrig.GetNbinsY()); + const auto zLow = hOrig.GetZaxis()->GetBinLowEdge(1); + const auto zUp = hOrig.GetZaxis()->GetBinUpEdge(hOrig.GetNbinsZ()); + hRebin.SetBins(nBinsPhiNew, phiLow, phiUp, nBinsRNew, rLow, rUp, nBinsZNewTwo, zLow, zUp); + + for (int iBinPhi = 1; iBinPhi <= nBinsPhiNew; ++iBinPhi) { + const auto phiLowEdge = hRebin.GetXaxis()->GetBinLowEdge(iBinPhi); + const auto phiUpEdge = hRebin.GetXaxis()->GetBinUpEdge(iBinPhi); + + const int phiLowBinOrig = hOrig.GetXaxis()->FindBin(phiLowEdge); + const int phiUpBinOrig = hOrig.GetXaxis()->FindBin(phiUpEdge); + + // calculate the weights (area of original bin lies in the new bin / binwidthOrig) of the first and last bins + const auto binWidthPhiOrig = hOrig.GetXaxis()->GetBinWidth(phiLowBinOrig); + const auto lowerBinWeightPhi = std::abs(phiLowEdge - hOrig.GetXaxis()->GetBinUpEdge(phiLowBinOrig)) / binWidthPhiOrig; + const auto upperBinWeightPhi = std::abs(phiUpEdge - hOrig.GetXaxis()->GetBinLowEdge(phiUpBinOrig)) / binWidthPhiOrig; + + for (int iBinR = 1; iBinR <= nBinsRNew; ++iBinR) { + const auto rLowEdge = hRebin.GetYaxis()->GetBinLowEdge(iBinR); + const auto rUpEdge = hRebin.GetYaxis()->GetBinUpEdge(iBinR); + + const int rLowBinOrig = hOrig.GetYaxis()->FindBin(rLowEdge); + const int rUpBinOrig = hOrig.GetYaxis()->FindBin(rUpEdge); + + // calculate the weights (area of original bin lies in the new bin / binwidthOrig) of the first and last bins + const auto binWidthROrig = hOrig.GetYaxis()->GetBinWidth(rLowBinOrig); + const auto lowerBinWeightR = std::abs(rLowEdge - hOrig.GetYaxis()->GetBinUpEdge(rLowBinOrig)) / binWidthROrig; + const auto upperBinWeightR = std::abs(rUpEdge - hOrig.GetYaxis()->GetBinLowEdge(rUpBinOrig)) / binWidthROrig; + + for (int iBinZ = 1; iBinZ <= nBinsZNewTwo; ++iBinZ) { + const auto zLowEdge = hRebin.GetZaxis()->GetBinLowEdge(iBinZ); + const auto zUpEdge = hRebin.GetZaxis()->GetBinUpEdge(iBinZ); + const auto zCenter = hRebin.GetZaxis()->GetBinCenter(iBinZ); + + int zLowBinOrig = hOrig.GetZaxis()->FindBin(zLowEdge); + int zUpBinOrig = hOrig.GetZaxis()->FindBin(zUpEdge); + const int currside = getSide(zCenter); // set the side of the current z-bin + // get the side of the lowest and uppest bin from the orig histo + const int sideLowOrig = getSide(hOrig.GetZaxis()->GetBinCenter(zLowBinOrig)); + const int sideUpOrig = getSide(hOrig.GetZaxis()->GetBinCenter(zUpBinOrig)); + + // make bounds/side check of the zLowBinOrig and zUpBinOrig bins. They must be on the same side as the currside!!! + if (currside != sideLowOrig && zLowBinOrig != zUpBinOrig) { + // if the lower bins from the orig histo are not on the same side as the rebinned increase the binnumber until they are on the same side + bool notequal = true; + do { + zLowBinOrig += 1; + if (zLowBinOrig > zUpBinOrig) { + LOGP(WARNING, "SOMETHING WENT WRONG: SETTING BINS TO: {}", zUpBinOrig); + zLowBinOrig = zUpBinOrig; + notequal = false; + } + const int sideTmp = getSide(hOrig.GetZaxis()->GetBinCenter(zLowBinOrig)); + if (sideTmp == currside) { + notequal = false; + } + } while (notequal); + } + + if (currside != sideUpOrig && zLowBinOrig != zUpBinOrig) { + // if the upper bins from the orig histo are not on the same side as the rebinned increase the binnumber until they are on the same side + bool notequal = true; + do { + zUpBinOrig -= 1; + if (zUpBinOrig < zLowBinOrig) { + LOGP(WARNING, "SOMETHING WENT WRONG: SETTING BINS TO: {}", zLowBinOrig); + zUpBinOrig = zLowBinOrig; + notequal = false; + } + const int sideTmp = getSide(hOrig.GetZaxis()->GetBinCenter(zUpBinOrig)); + if (sideTmp == currside) { + notequal = false; + } + } while (notequal); + } + + const auto binWidthZOrig = hOrig.GetZaxis()->GetBinWidth(zLowBinOrig); + const auto lowerBinWeightZ = std::abs(zLowEdge - hOrig.GetZaxis()->GetBinUpEdge(zLowBinOrig)) / binWidthZOrig; + const auto upperBinWeightZ = std::abs(zUpEdge - hOrig.GetZaxis()->GetBinLowEdge(zUpBinOrig)) / binWidthZOrig; + + // get the mean value of the original histogram of the found bin range + DataT sum = 0; + DataT sumW = 0; + for (int iPhi = phiLowBinOrig; iPhi <= phiUpBinOrig; ++iPhi) { + DataT weightPhi = 1; + if (iPhi == phiLowBinOrig) { + weightPhi = lowerBinWeightPhi; + } else if (iPhi == phiUpBinOrig) { + weightPhi = upperBinWeightPhi; + } + + for (int iR = rLowBinOrig; iR <= rUpBinOrig; ++iR) { + DataT weightR = 1; + if (iR == rLowBinOrig) { + weightR = lowerBinWeightR; + } else if (iR == rUpBinOrig) { + weightR = upperBinWeightR; + } + + for (int iZ = zLowBinOrig; iZ <= zUpBinOrig; ++iZ) { + DataT weightZ = 1; + if (iZ == zLowBinOrig) { + weightZ = lowerBinWeightZ; + } else if (iZ == zUpBinOrig) { + weightZ = upperBinWeightZ; + } + const auto val = hOrig.GetBinContent(iPhi, iR, iZ); + // if(val==0){ + // what to do now??? + // } + const auto totalWeight = weightPhi * weightR * weightZ; + sum += val * totalWeight; + sumW += totalWeight; + } + } + } + sum /= sumW; + hRebin.SetBinContent(iBinPhi, iBinR, iBinZ, sum); + } + } + } + return hRebin; +} + +template <typename DataT> +template <typename ElectricFields> +void SpaceCharge<DataT>::calcLocalDistortionsCorrections(const SpaceCharge<DataT>::Type type, const ElectricFields& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + // calculate local distortions/corrections for each vertex in the tpc +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) { + // set z coordinate depending on distortions or correction calculation + const DataT z0 = type == Type::Corrections ? getZVertex(iZ + 1, side) : getZVertex(iZ, side); + const DataT z1 = type == Type::Corrections ? getZVertex(iZ, side) : getZVertex(iZ + 1, side); + + DataT drTmp = 0; // local distortion dR + DataT dPhiTmp = 0; // local distortion dPhi (multiplication with R has to be done at the end) + DataT dzTmp = 0; // local distortion dZ + + const DataT stepSize = (z1 - z0) / sSteps; // the distortions are calculated by leting the elctron drift this distance in z direction + for (int iter = 0; iter < sSteps; ++iter) { + const DataT z0Tmp = (z0 + iter * stepSize + dzTmp); // starting z position + const DataT z1Tmp = (z0Tmp + stepSize); // electron drifts from z0Tmp to z1Tmp + + DataT ddR = 0; // distortion dR for drift from z0Tmp to z1Tmp + DataT ddPhi = 0; // distortion dPhi for drift from z0Tmp to z1Tmp + DataT ddZ = 0; // distortion dZ for drift from z0Tmp to z1Tmp + + const DataT radiusTmp = regulateR(radius + drTmp, side); // current radial position + const DataT phiTmp = regulatePhi(phi + dPhiTmp, side); // current phi position + + // calculate distortions/corrections + calcDistCorr(radiusTmp, phiTmp, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct, true); + + // add temp distortions to local distortions + drTmp += ddR; + dPhiTmp += ddPhi; + dzTmp += ddZ; + } + + // store local distortions/corrections + switch (type) { + case Type::Corrections: + mLocalCorrdR[side](iZ + 1, iR, iPhi) = drTmp; + mLocalCorrdRPhi[side](iZ + 1, iR, iPhi) = dPhiTmp * radius; + mLocalCorrdZ[side](iZ + 1, iR, iPhi) = dzTmp; + break; + + case Type::Distortions: + mLocalDistdR[side](iZ, iR, iPhi) = drTmp; + mLocalDistdRPhi[side](iZ, iR, iPhi) = dPhiTmp * radius; + mLocalDistdZ[side](iZ, iR, iPhi) = dzTmp; + break; + } + } + //extrapolate local distortion/correction to last/first bin using legendre polynoms with x0=0, x1=1, x2=2 and x=-1. This has to be done to ensure correct interpolation in the last,second last/first,second bin! + switch (type) { + case Type::Corrections: + mLocalCorrdR[side](0, iR, iPhi) = 3 * (mLocalCorrdR[side](1, iR, iPhi) - mLocalCorrdR[side](2, iR, iPhi)) + mLocalCorrdR[side](3, iR, iPhi); + mLocalCorrdRPhi[side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[side](1, iR, iPhi) - mLocalCorrdRPhi[side](2, iR, iPhi)) + mLocalCorrdRPhi[side](3, iR, iPhi); + mLocalCorrdZ[side](0, iR, iPhi) = 3 * (mLocalCorrdZ[side](1, iR, iPhi) - mLocalCorrdZ[side](2, iR, iPhi)) + mLocalCorrdZ[side](3, iR, iPhi); + break; + + case Type::Distortions: + mLocalDistdR[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdR[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdR[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdR[side](mParamGrid.NZVertices - 4, iR, iPhi); + mLocalDistdRPhi[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdRPhi[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdRPhi[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdRPhi[side](mParamGrid.NZVertices - 4, iR, iPhi); + mLocalDistdZ[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdZ[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdZ[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdZ[side](mParamGrid.NZVertices - 4, iR, iPhi); + break; + } + } + } + switch (type) { + case Type::Corrections: + mIsLocalCorrSet[side] = true; + break; + case Type::Distortions: + mIsLocalDistSet[side] = true; + break; + } +} + +template <typename DataT> +template <typename ElectricFields> +void SpaceCharge<DataT>::calcLocalDistortionCorrectionVector(const ElectricFields& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + // calculate local distortion/correction vector for each vertex in the tpc +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + for (size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT ezField = getEzField(formulaStruct.getSide()); + const DataT er = mElectricFieldEr[side](iZ, iR, iPhi); + const DataT ez0 = mElectricFieldEz[side](iZ, iR, iPhi); + const DataT ephi = mElectricFieldEphi[side](iZ, iR, iPhi); + const DataT ez = getSign(formulaStruct.getSide()) * 1. / (ezField + ez0); + const DataT erez = er * ez; + const DataT ephiez = ephi * ez; + + const DataT vecdR = mC0 * erez + mC1 * ephiez; + const DataT vecdRPhi = mC0 * ephiez - mC1 * erez; + const DataT vecdZ = -ez0 * TPCParameters<DataT>::DVDE; + + mLocalVecDistdR[side](iZ, iR, iPhi) = vecdR; + mLocalVecDistdRPhi[side](iZ, iR, iPhi) = vecdRPhi; + mLocalVecDistdZ[side](iZ, iR, iPhi) = vecdZ; + } + } + } + mIsLocalVecDistSet[side] = true; +} + +template <typename DataT> +template <typename ElectricFields> +void SpaceCharge<DataT>::calcLocalDistortionsCorrectionsRK4(const SpaceCharge<DataT>::Type type, const Side side) +{ + // see: https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods + // calculate local distortions/corrections for each vertex in the tpc using Runge Kutta 4 method +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) { + // set z coordinate depending on distortions or correction calculation + const size_t iZ0 = type == Type::Corrections ? iZ + 1 : iZ; + const size_t iZ1 = type == Type::Corrections ? iZ : iZ + 1; + + const DataT z0 = getZVertex(iZ0, side); + const DataT z1 = getZVertex(iZ1, side); + + const DataT stepSize = z1 - z0; // h in the RK4 method + const DataT absstepSize = std::abs(stepSize); + + const DataT stepSizeHalf = 0.5 * stepSize; // half z bin for RK4 + const DataT absstepSizeHalf = std::abs(stepSizeHalf); + + // starting position for RK4 + const DataT zk1 = z0; + const DataT rk1 = radius; + const DataT phik1 = phi; + + DataT k1dR = 0; // derivative in r direction + DataT k1dZ = 0; // derivative in z direction + DataT k1dRPhi = 0; // derivative in rphi direction + + // get derivative on current vertex + switch (type) { + case Type::Corrections: + k1dR = getLocalVecCorrR(iZ0, iR, iPhi, side); + k1dZ = getLocalVecCorrZ(iZ0, iR, iPhi, side); + k1dRPhi = getLocalVecCorrRPhi(iZ0, iR, iPhi, side); + break; + + case Type::Distortions: + k1dR = getLocalVecDistR(iZ0, iR, iPhi, side); + k1dZ = getLocalVecDistZ(iZ0, iR, iPhi, side); + k1dRPhi = getLocalVecDistRPhi(iZ0, iR, iPhi, side); + break; + } + + // approximate position after half stepSize + const DataT zk2 = zk1 + stepSizeHalf + absstepSizeHalf * k1dZ; + const DataT rk2 = rk1 + absstepSizeHalf * k1dR; + const DataT k1dPhi = k1dRPhi / rk1; + const DataT phik2 = phik1 + absstepSizeHalf * k1dPhi; + + // get derivative for new position + DataT k2dR = 0; + DataT k2dZ = 0; + DataT k2dRPhi = 0; + type == Type::Corrections ? getLocalCorrectionVectorCyl(zk2, rk2, phik2, side, k2dZ, k2dR, k2dRPhi) : getLocalDistortionVectorCyl(zk2, rk2, phik2, side, k2dZ, k2dR, k2dRPhi); + + // approximate new position + const DataT zk3 = zk1 + stepSizeHalf + absstepSizeHalf * k2dZ; + const DataT rk3 = rk1 + absstepSizeHalf * k2dR; + const DataT k2dPhi = k2dRPhi / rk2; + const DataT phik3 = phik1 + absstepSizeHalf * k2dPhi; + + DataT k3dR = 0; + DataT k3dZ = 0; + DataT k3dRPhi = 0; + type == Type::Corrections ? getLocalCorrectionVectorCyl(zk3, rk3, phik3, side, k3dZ, k3dR, k3dRPhi) : getLocalDistortionVectorCyl(zk3, rk3, phik3, side, k3dZ, k3dR, k3dRPhi); + + const DataT zk4 = zk1 + stepSize + absstepSize * k3dZ; + const DataT rk4 = rk1 + absstepSize * k3dR; + const DataT k3dPhi = k3dRPhi / rk3; + const DataT phik4 = phik1 + absstepSize * k3dPhi; + + DataT k4dR = 0; + DataT k4dZ = 0; + DataT k4dRPhi = 0; + type == Type::Corrections ? getLocalCorrectionVectorCyl(zk4, rk4, phik4, side, k4dZ, k4dR, k4dRPhi) : getLocalDistortionVectorCyl(zk4, rk4, phik4, side, k4dZ, k4dR, k4dRPhi); + const DataT k4dPhi = k4dRPhi / rk4; + + // RK4 formula. See wikipedia: u = h * 1/6 * (k1 + 2*k2 + 2*k3 + k4) + const DataT stepsizeSixth = absstepSize / 6; + const DataT drRK = stepsizeSixth * (k1dR + 2 * k2dR + 2 * k3dR + k4dR); + const DataT dzRK = stepsizeSixth * (k1dZ + 2 * k2dZ + 2 * k3dZ + k4dZ); + const DataT dphiRK = stepsizeSixth * (k1dPhi + 2 * k2dPhi + 2 * k3dPhi + k4dPhi); + + // store local distortions/corrections + switch (type) { + case Type::Corrections: + mLocalCorrdR[side](iZ + 1, iR, iPhi) = drRK; + mLocalCorrdRPhi[side](iZ + 1, iR, iPhi) = dphiRK * radius; + mLocalCorrdZ[side](iZ + 1, iR, iPhi) = dzRK; + break; + + case Type::Distortions: + mLocalDistdR[side](iZ, iR, iPhi) = drRK; + mLocalDistdRPhi[side](iZ, iR, iPhi) = dphiRK * radius; + mLocalDistdZ[side](iZ, iR, iPhi) = dzRK; + break; + } + } + //extrapolate local distortion/correction to last/first bin using legendre polynoms with x0=0, x1=1, x2=2 and x=-1. This has to be done to ensure correct interpolation in the last,second last/first,second bin! + switch (type) { + case Type::Corrections: + mLocalCorrdR[side](0, iR, iPhi) = 3 * (mLocalCorrdR[side](1, iR, iPhi) - mLocalCorrdR[side](2, iR, iPhi)) + mLocalCorrdR[side](3, iR, iPhi); + mLocalCorrdRPhi[side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[side](1, iR, iPhi) - mLocalCorrdRPhi[side](2, iR, iPhi)) + mLocalCorrdRPhi[side](3, iR, iPhi); + mLocalCorrdZ[side](0, iR, iPhi) = 3 * (mLocalCorrdZ[side](1, iR, iPhi) - mLocalCorrdZ[side](2, iR, iPhi)) + mLocalCorrdZ[side](3, iR, iPhi); + break; + + case Type::Distortions: + mLocalDistdR[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdR[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdR[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdR[side](mParamGrid.NZVertices - 4, iR, iPhi); + mLocalDistdRPhi[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdRPhi[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdRPhi[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdRPhi[side](mParamGrid.NZVertices - 4, iR, iPhi); + mLocalDistdZ[side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdZ[side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdZ[side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdZ[side](mParamGrid.NZVertices - 4, iR, iPhi); + break; + } + } + } + switch (type) { + case Type::Corrections: + mIsLocalCorrSet[side] = true; + break; + case Type::Distortions: + mIsLocalDistSet[side] = true; + break; + } +} + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::calcGlobalDistortions(const Fields& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + const DataT stepSize = formulaStruct.getID() == 2 ? getGridSpacingZ(side) : getGridSpacingZ(side) / sSteps; // if one used local distortions then no smaller stepsize is needed. if electric fields are used then smaller stepsize can be used + // loop over tpc volume and let the electron drift from each vertex to the readout of the tpc +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi0 = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT r0 = getRVertex(iR, side); + for (size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) { + const DataT z0 = getZVertex(iZ, side); // the electron starts at z0, r0, phi0 + DataT drDist = 0.0; // global distortion dR + DataT dPhiDist = 0.0; // global distortion dPhi (multiplication with R has to be done at the end) + DataT dzDist = 0.0; // global distortion dZ + int iter = 0; + + for (;;) { + const DataT z0Tmp = z0 + dzDist + iter * stepSize; // starting z position + const DataT z1Tmp = regulateZ(z0Tmp + stepSize, side); // electron drifts from z0Tmp to z1Tmp + const DataT radius = regulateR(r0 + drDist, side); // current radial position of the electron + const DataT phi = regulatePhi(phi0 + dPhiDist, side); // current phi position of the electron + + DataT ddR = 0; // distortion dR for drift from z0Tmp to z1Tmp + DataT ddPhi = 0; // distortion dPhi for drift from z0Tmp to z1Tmp + DataT ddZ = 0; // distortion dZ for drift from z0Tmp to z1Tmp + + // get the distortion from interpolation of local distortions or calculate distortions with the electric field + processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct); + + // if one uses local distortions the interpolated value for the last bin has to be scaled. + // This has to be done because of the interpolated value is defined for a drift length of one z bin, but in the last bin the distance to the readout can be smaller than one z bin. + const bool checkReached = side == Side::A ? z1Tmp >= getZMax(side) : z1Tmp <= getZMax(side); + if (formulaStruct.getID() == 2 && checkReached) { + const DataT fac = std::abs((getZMax(side) - z0Tmp) * getInvSpacingZ(side)); + ddR *= fac; + ddZ *= fac; + ddPhi *= fac; + } + + // add local distortions to global distortions + drDist += ddR; + dPhiDist += ddPhi; + dzDist += ddZ; + + // set loop to exit if the readout is reached and approximate distortion of 'missing' (one never ends exactly on the readout: z1Tmp + ddZ != ZMAX) drift distance. + // approximation is done by the current calculated values of the distortions and scaled linear to the 'missing' distance. + if (checkReached) { + const DataT endPoint = z1Tmp + ddZ; + const DataT deltaZ = getZMax(side) - endPoint; // distance from last point to read out + const DataT diff = endPoint - z0Tmp; + const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0; // approximate the distortions for the 'missing' distance deltaZ + drDist += ddR * fac; + dPhiDist += ddPhi * fac; + dzDist += ddZ * fac; + break; + } + ++iter; + } + // store global distortions + mGlobalDistdR[side](iZ, iR, iPhi) = drDist; + mGlobalDistdRPhi[side](iZ, iR, iPhi) = dPhiDist * r0; + mGlobalDistdZ[side](iZ, iR, iPhi) = dzDist; + } + } + } + // set flag that global distortions are set to true + mIsGlobalDistSet[side] = true; +} + +template <typename DataT> +template <typename Formulas> +void SpaceCharge<DataT>::calcGlobalCorrections(const Formulas& formulaStruct) +{ + const Side side = formulaStruct.getSide(); + const int iSteps = formulaStruct.getID() == 2 ? 1 : sSteps; // if one used local corrections no step width is needed. since it is already used for calculation of the local corrections + const DataT stepSize = -getGridSpacingZ(side) / iSteps; + // loop over tpc volume and let the electron drift from each vertex to the readout of the tpc +#pragma omp parallel for num_threads(sNThreads) + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + const DataT phi0 = getPhiVertex(iPhi, side); + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + + const DataT r0 = getRVertex(iR, side); + DataT drCorr = 0; + DataT dPhiCorr = 0; + DataT dzCorr = 0; + + // start at the readout and follow electron towards central electrode + for (size_t iZ = mParamGrid.NZVertices - 1; iZ >= 1; --iZ) { + const DataT z0 = getZVertex(iZ, side); // the electron starts at z0, r0, phi0 + // flag which is set when the central electrode is reached. if the central electrode is reached the calculation of the global corrections is aborted and the value set is the last calculated value. + bool centralElectrodeReached = false; + for (int iter = 0; iter < iSteps; ++iter) { + if (centralElectrodeReached) { + break; + } + const DataT radius = regulateR(r0 + drCorr, side); // current radial position of the electron + const DataT phi = regulatePhi(phi0 + dPhiCorr, side); // current phi position of the electron + const DataT z0Tmp = z0 + dzCorr + iter * stepSize; // starting z position + const DataT z1Tmp = regulateZ(z0Tmp + stepSize, side); // follow electron from z0Tmp to z1Tmp + DataT ddR = 0; // distortion dR for z0Tmp to z1Tmp + DataT ddPhi = 0; // distortion dPhi for z0Tmp to z1Tmp + DataT ddZ = 0; // distortion dZ for z0Tmp to z1Tmp + + // get the distortion from interpolation of local distortions or calculate distortions with the electric field + processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct); + + // if one uses local corrections the interpolated value for the first bin has to be scaled. + // This has to be done because of the interpolated value is defined for a drift length of one z bin, but in the first bin the distance to the readout can be smaller than one z bin. + centralElectrodeReached = getSign(side) * z1Tmp <= getZMin(side); + if (formulaStruct.getID() == 2 && centralElectrodeReached) { + const DataT fac = (z0Tmp - getZMin(side)) * getInvSpacingZ(side); + ddR *= fac; + ddZ *= fac; + ddPhi *= fac; + } + + // add local corrections to global corrections + drCorr += ddR; + dPhiCorr += ddPhi; + dzCorr += ddZ; + + // set loop to exit if the central electrode is reached and approximate correction of 'missing' (one never ends exactly on the central electrode: z1Tmp + ddZ != ZMIN) distance. + // approximation is done by the current calculated values of the corrections and scaled linear to the 'missing' distance deltaZ. (NOT TESTED) + if (centralElectrodeReached) { + const DataT endPoint = z1Tmp + ddZ; + const DataT deltaZ = endPoint - getZMin(side); + const DataT diff = z0Tmp - endPoint; + const DataT fac = diff != 0 ? deltaZ / diff : 0; // approximate the distortions for the 'missing' distance deltaZ + drCorr += ddR * fac; + dPhiCorr += ddPhi * fac; + dzCorr += ddZ * fac; + break; + } + } + // store global corrections + mGlobalCorrdR[side](iZ - 1, iR, iPhi) = drCorr; + mGlobalCorrdRPhi[side](iZ - 1, iR, iPhi) = dPhiCorr * r0; + mGlobalCorrdZ[side](iZ - 1, iR, iPhi) = dzCorr; + } + } + } + // set flag that global corrections are set to true + mIsGlobalCorrSet[side] = true; +} + +template <typename DataT> +void SpaceCharge<DataT>::correctElectron(GlobalPosition3D& point) +{ + DataT corrX{}; + DataT corrY{}; + DataT corrZ{}; + const Side side = getSide(point.Z()); + + // get the distortions for input coordinate + getCorrections(point.X(), point.Y(), point.Z(), side, corrX, corrY, corrZ); + + // set distorted coordinates + point.SetXYZ(point.X() + corrX, point.Y() + corrY, point.Y() + corrY); +} + +template <typename DataT> +void SpaceCharge<DataT>::distortElectron(GlobalPosition3D& point) const +{ + DataT distX{}; + DataT distY{}; + DataT distZ{}; + const Side side = getSide(point.Z()); + // get the distortions for input coordinate + getDistortions(point.X(), point.Y(), point.Z(), side, distX, distY, distZ); + + // set distorted coordinates + point.SetXYZ(point.X() + distX, point.Y() + distY, point.Z() + distZ); +} + +template <typename DataT> +DataT SpaceCharge<DataT>::getDensityCyl(const DataT z, const DataT r, const DataT phi, const Side side) const +{ + return mInterpolatorDensity[side](z, r, phi); +} + +template <typename DataT> +DataT SpaceCharge<DataT>::getPotentialCyl(const DataT z, const DataT r, const DataT phi, const Side side) const +{ + return mInterpolatorPotential[side](z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getElectricFieldsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& eZ, DataT& eR, DataT& ePhi) const +{ + eZ = mInterpolatorEField[side].evalEz(z, r, phi); + eR = mInterpolatorEField[side].evalEr(z, r, phi); + ePhi = mInterpolatorEField[side].evalEphi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getLocalCorrectionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lcorrZ, DataT& lcorrR, DataT& lcorrRPhi) const +{ + lcorrZ = mInterpolatorLocalCorr[side].evaldZ(z, r, phi); + lcorrR = mInterpolatorLocalCorr[side].evaldR(z, r, phi); + lcorrRPhi = mInterpolatorLocalCorr[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getCorrectionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& corrZ, DataT& corrR, DataT& corrRPhi) const +{ + corrZ = mInterpolatorGlobalCorr[side].evaldZ(z, r, phi); + corrR = mInterpolatorGlobalCorr[side].evaldR(z, r, phi); + corrRPhi = mInterpolatorGlobalCorr[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getCorrections(const DataT x, const DataT y, const DataT z, const Side side, DataT& corrX, DataT& corrY, DataT& corrZ) const +{ + // convert cartesian to polar + const DataT radius = getRadiusFromCartesian(x, y); + const DataT phi = getPhiFromCartesian(x, y); + + DataT corrR{}; + DataT corrRPhi{}; + getCorrectionsCyl(z, radius, phi, side, corrZ, corrR, corrRPhi); + + // Calculate corrected position + const DataT radiusCorr = radius + corrR; + const DataT phiCorr = phi + corrRPhi / radius; + + corrX = getXFromPolar(radiusCorr, phiCorr) - x; // difference between corrected and original x coordinate + corrY = getYFromPolar(radiusCorr, phiCorr) - y; // difference between corrected and original y coordinate +} + +template <typename DataT> +void SpaceCharge<DataT>::getLocalDistortionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& ldistZ, DataT& ldistR, DataT& ldistRPhi) const +{ + ldistZ = mInterpolatorLocalDist[side].evaldZ(z, r, phi); + ldistR = mInterpolatorLocalDist[side].evaldR(z, r, phi); + ldistRPhi = mInterpolatorLocalDist[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getLocalDistortionVectorCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lvecdistZ, DataT& lvecdistR, DataT& lvecdistRPhi) const +{ + lvecdistZ = mInterpolatorLocalVecDist[side].evaldZ(z, r, phi); + lvecdistR = mInterpolatorLocalVecDist[side].evaldR(z, r, phi); + lvecdistRPhi = mInterpolatorLocalVecDist[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getLocalCorrectionVectorCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& lveccorrZ, DataT& lveccorrR, DataT& lveccorrRPhi) const +{ + lveccorrZ = -mInterpolatorLocalVecDist[side].evaldZ(z, r, phi); + lveccorrR = -mInterpolatorLocalVecDist[side].evaldR(z, r, phi); + lveccorrRPhi = -mInterpolatorLocalVecDist[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getDistortionsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& distZ, DataT& distR, DataT& distRPhi) const +{ + distZ = mInterpolatorGlobalDist[side].evaldZ(z, r, phi); + distR = mInterpolatorGlobalDist[side].evaldR(z, r, phi); + distRPhi = mInterpolatorGlobalDist[side].evaldRPhi(z, r, phi); +} + +template <typename DataT> +void SpaceCharge<DataT>::getDistortions(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ) const +{ + // convert cartesian to polar + const DataT radius = getRadiusFromCartesian(x, y); + const DataT phi = getPhiFromCartesian(x, y); + + DataT distR{}; + DataT distRPhi{}; + getDistortionsCyl(z, radius, phi, side, distZ, distR, distRPhi); + + // Calculate distorted position + const DataT radiusDist = radius + distR; + const DataT phiDist = phi + distRPhi / radius; + + distX = getXFromPolar(radiusDist, phiDist) - x; // difference between distorted and original x coordinate + distY = getYFromPolar(radiusDist, phiDist) - y; // difference between distorted and original y coordinate +} + +template <typename DataT> +void SpaceCharge<DataT>::init() +{ + using timer = std::chrono::high_resolution_clock; + if (!mInitLookUpTables) { + auto start = timer::now(); + auto o2field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); + const float bzField = o2field->solenoidField(); // magnetic field in kGauss + /// TODO is there a faster way to get the drift velocity + auto& gasParam = ParameterGas::Instance(); + float vDrift = gasParam.DriftV; // drift velocity in cm/us + /// TODO fix hard coded values (ezField, t1, t2): export to Constants.h or get from somewhere? + const float t1 = 1.; + const float t2 = 1.; + /// TODO use this parameterization or fixed value(s) from Magboltz calculations? + const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(Side::A)); + setOmegaTauT1T2(omegaTau, t1, t2); + if (mUseInitialSCDensity) { + LOG(WARNING) << "mUseInitialSCDensity" << mUseInitialSCDensity; + calculateDistortionsCorrections(Side::A); + calculateDistortionsCorrections(Side::C); + mInitLookUpTables = true; + } + auto stop = timer::now(); + std::chrono::duration<float> time = stop - start; + LOGP(info, "Total Time Distortions and Corrections for A and C Side: {}", time.count()); + } +} + +template <typename DataT> +void SpaceCharge<DataT>::setDistortionLookupTables(const DataContainer& distdZ, const DataContainer& distdR, const DataContainer& distdRPhi, const Side side) +{ + mGlobalDistdR[side] = distdR; + mGlobalDistdZ[side] = distdZ; + mGlobalDistdRPhi[side] = distdRPhi; + mIsGlobalDistSet[side] = true; +} + +template <typename DataT> +template <typename Fields> +void SpaceCharge<DataT>::integrateEFieldsRoot(const DataT p1r, const DataT p1phi, const DataT p1z, const DataT p2z, DataT& localIntErOverEz, DataT& localIntEPhiOverEz, DataT& localIntDeltaEz, const Fields& formulaStruct) const +{ + const DataT ezField = getEzField(formulaStruct.getSide()); + TF1 fErOverEz( + "fErOverEz", [&](double* x, double* p) { (void)p; return static_cast<double>(formulaStruct.evalEr(static_cast<DataT>(x[0]), p1r, p1phi) / (formulaStruct.evalEz(static_cast<DataT>(x[0]), p1r, p1phi) + ezField)); }, p1z, p2z, 1); + localIntErOverEz = static_cast<DataT>(fErOverEz.Integral(p1z, p2z)); + + TF1 fEphiOverEz( + "fEPhiOverEz", [&](double* x, double* p) { (void)p; return static_cast<double>(formulaStruct.evalEphi(static_cast<DataT>(x[0]), p1r, p1phi) / (formulaStruct.evalEz(static_cast<DataT>(x[0]), p1r, p1phi) + ezField)); }, p1z, p2z, 1); + localIntEPhiOverEz = static_cast<DataT>(fEphiOverEz.Integral(p1z, p2z)); + + TF1 fEz( + "fEZOverEz", [&](double* x, double* p) { (void)p; return static_cast<double>(formulaStruct.evalEz(static_cast<DataT>(x[0]), p1r, p1phi) - ezField); }, p1z, p2z, 1); + localIntDeltaEz = getSign(formulaStruct.getSide()) * static_cast<DataT>(fEz.Integral(p1z, p2z)); +} + +template <typename DataT> +void SpaceCharge<DataT>::calculateElectronDriftPath(const std::vector<GlobalPosition3D>& elePos, const int nSamplingPoints, const char* outFile) const +{ + const unsigned int nElectrons = elePos.size(); + std::vector<std::vector<GlobalPosition3D>> electronTracks(nElectrons); + for (unsigned int i = 0; i < nElectrons; ++i) { + electronTracks[i].reserve(nSamplingPoints + 1); + } + + for (unsigned int i = 0; i < nElectrons; ++i) { + const DataT z0 = elePos[i].Z(); + const DataT r0 = elePos[i].Rho(); + const DataT phi0 = elePos[i].Phi(); + const Side side = getSide(z0); + if (!mIsEfieldSet[side]) { + LOGP(warning, "E-Fields are not set! Calculation of drift path is not possible\n"); + continue; + } + const NumericalFields<DataT> numEFields{getElectricFieldsInterpolator(side)}; + const DataT stepSize = getZMax(side) / nSamplingPoints; + + DataT drDist = 0.0; // global distortion dR + DataT dPhiDist = 0.0; // global distortion dPhi (multiplication with R has to be done at the end) + DataT dzDist = 0.0; // global distortion dZ + int iter = 0; + for (;;) { + const DataT z0Tmp = z0 + dzDist + iter * stepSize; // starting z position + const DataT z1Tmp = regulateZ(z0Tmp + stepSize, side); // electron drifts from z0Tmp to z1Tmp + const DataT radius = r0 + drDist; // current radial position of the electron + + // abort calculation of drift path if electron reached inner/outer field cage or central electrode + if (radius <= getRMin(side) || radius >= getRMax(side) || getSide(z0Tmp) != side) { + break; + } + + const DataT phi = regulatePhi(phi0 + dPhiDist, side); // current phi position of the electron + electronTracks[i].emplace_back(GlobalPosition3D(radius * std::cos(phi), radius * std::sin(phi), z0Tmp)); + + DataT ddR = 0; // distortion dR for drift from z0Tmp to z1Tmp + DataT ddPhi = 0; // distortion dPhi for drift from z0Tmp to z1Tmp + DataT ddZ = 0; // distortion dZ for drift from z0Tmp to z1Tmp + + // get the distortion from interpolation of local distortions or calculate distortions with the electric field + processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, numEFields); + + // add local distortions to global distortions + drDist += ddR; + dPhiDist += ddPhi; + dzDist += ddZ; + + // if one uses local distortions the interpolated value for the last bin has to be scaled. + // This has to be done because of the interpolated value is defined for a drift length of one z bin, but in the last bin the distance to the readout can be smaller than one z bin. + const bool checkReached = side == Side::A ? z1Tmp >= getZMax(side) : z1Tmp <= getZMax(side); + + // set loop to exit if the readout is reached and approximate distortion of 'missing' (one never ends exactly on the readout: z1Tmp + ddZ != ZMAX) drift distance. + // approximation is done by the current calculated values of the distortions and scaled linear to the 'missing' distance. + if (checkReached) { + const DataT endPoint = z1Tmp + ddZ; + const DataT deltaZ = getZMax(side) - endPoint; // distance from last point to read out + const DataT diff = endPoint - z0Tmp; + const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0; // approximate the distortions for the 'missing' distance deltaZ + drDist += ddR * fac; + dPhiDist += ddPhi * fac; + dzDist += ddZ * fac; + const DataT z1TmpEnd = regulateZ(z0Tmp + stepSize, side); // electron drifts from z0Tmp to z1Tmp + const DataT radiusEnd = regulateR(r0 + drDist, side); // current radial position of the electron + const DataT phiEnd = regulatePhi(phi0 + dPhiDist, side); // current phi position of the electron + electronTracks[i].emplace_back(GlobalPosition3D(radiusEnd * std::cos(phiEnd), radiusEnd * std::sin(phiEnd), z1TmpEnd)); + break; + } + ++iter; + } + } + dumpElectronTracksToTree(electronTracks, nSamplingPoints, outFile); +} + +template <typename DataT> +void SpaceCharge<DataT>::dumpElectronTracksToTree(const std::vector<std::vector<GlobalPosition3D>>& electronTracks, const int nSamplingPoints, const char* outFile) const +{ + o2::utils::TreeStreamRedirector pcstream(outFile, "RECREATE"); + pcstream.GetFile()->cd(); + + for (int i = 0; i < electronTracks.size(); ++i) { + auto electronPath = electronTracks[i]; + const auto nPoints = electronTracks[i].size(); + std::vector<float> relDriftVel; + relDriftVel.reserve(nPoints); + + for (int iPoint = 0; iPoint < nPoints; ++iPoint) { + const DataT relDriftVelTmp = iPoint == (nPoints - 1) ? 1 : (electronPath[iPoint + 1].Z() - electronPath[iPoint].Z()) / getZMax(getSide(electronPath[iPoint].Z())) * nSamplingPoints; // comparison of drift distance without distortions and with distortions (rel. drift velocity) + relDriftVel.emplace_back(std::abs(relDriftVelTmp)); + } + + pcstream << "drift" + << "electronPath=" << electronPath + << "relDriftVel.=" << relDriftVel // relative drift velocity in z direction + << "\n"; + } + pcstream.Close(); +} + +template <typename DataT> +void SpaceCharge<DataT>::makeElectronDriftPathGif(const char* inpFile, TH2F& hDummy, const int type, const int gifSpeed, const int maxsamplingpoints, const char* outName) +{ + // read in the tree and convert to vector of std::vector<o2::tpc::GlobalPosition3D> + TFile fInp(inpFile, "READ"); + TTree* tree = (TTree*)fInp.Get("drift"); + std::vector<o2::tpc::GlobalPosition3D>* electronPathTree = new std::vector<o2::tpc::GlobalPosition3D>; + tree->SetBranchAddress("electronPath", &electronPathTree); + + std::vector<std::vector<o2::tpc::GlobalPosition3D>> electronPaths; + std::vector<o2::tpc::GlobalPosition3D> elePosTmp; + const int entries = tree->GetEntriesFast(); + for (int i = 0; i < entries; ++i) { + tree->GetEntry(i); + electronPaths.emplace_back(*electronPathTree); + } + delete electronPathTree; + fInp.Close(); + + TCanvas can("canvas", "canvas", 1000, 600); + can.SetTopMargin(0.04f); + can.SetRightMargin(0.04f); + can.SetBottomMargin(0.12f); + can.SetLeftMargin(0.11f); + + const int nElectrons = electronPaths.size(); + std::vector<int> indexStartEle(nElectrons); + std::vector<int> countReadoutReached(nElectrons); + + // define colors of electrons + const std::vector<int> colorsPalette{kViolet + 2, kViolet + 1, kViolet, kViolet - 1, kGreen + 3, kGreen + 2, kGreen + 1, kOrange - 1, kOrange, kOrange + 1, kOrange + 2, kRed - 1, kRed, kRed + 1, kRed + 2, kBlue - 1, kBlue, kBlue + 1, kBlue + 2}; + + // create for each electron an individual graph + unsigned int maxPoints = 0; + std::vector<TGraph> gr(nElectrons); + for (int i = 0; i < nElectrons; ++i) { + gr[i].SetMarkerColor(colorsPalette[i % colorsPalette.size()]); + + if (electronPaths[i].size() > maxPoints) { + maxPoints = electronPaths[i].size(); + } + } + + const DataT pointsPerIteration = maxPoints / static_cast<DataT>(maxsamplingpoints); + std::vector<DataT> zRemainder(nElectrons); + + for (;;) { + for (auto& graph : gr) { + graph.Set(0); + } + + for (int iEle = 0; iEle < nElectrons; ++iEle) { + const int nSamplingPoints = electronPaths[iEle].size(); + const int nPoints = std::round(pointsPerIteration + zRemainder[iEle]); + zRemainder[iEle] = pointsPerIteration - nPoints; + const auto& electronPath = electronPaths[iEle]; + + if (nPoints == 0 && countReadoutReached[iEle] == 0) { + const int indexPoint = indexStartEle[iEle]; + const DataT radius = electronPath[indexPoint].Rho(); + const DataT z = electronPath[indexPoint].Z(); + const DataT phi = electronPath[indexPoint].Phi(); + type == 0 ? gr[iEle].AddPoint(z, radius) : gr[iEle].AddPoint(phi, radius); + } + + for (int iPoint = 0; iPoint < nPoints; ++iPoint) { + const int indexPoint = indexStartEle[iEle]; + if (indexPoint >= nSamplingPoints) { + countReadoutReached[iEle] = 1; + break; + } + + const DataT radius = electronPath[indexPoint].Rho(); + const DataT z = electronPath[indexPoint].Z(); + const DataT phi = electronPath[indexPoint].Phi(); + if (iPoint == nPoints / 2) { + type == 0 ? gr[iEle].AddPoint(z, radius) : gr[iEle].AddPoint(phi, radius); + } + ++indexStartEle[iEle]; + } + } + hDummy.Draw(); + for (auto& graph : gr) { + if (graph.GetN() > 0) { + graph.Draw("P SAME"); + } + } + can.Print(Form("%s.gif+%i", outName, gifSpeed)); + + const int sumReadoutReached = std::accumulate(countReadoutReached.begin(), countReadoutReached.end(), 0); + if (sumReadoutReached == nElectrons) { + break; + } + } + + can.Print(Form("%s.gif++", outName)); +} + +template <typename DataT> +void SpaceCharge<DataT>::dumpToTree(const char* outFileName, const Side side, const int nZPoints, const int nRPoints, const int nPhiPoints) const +{ + const DataT phiSpacing = GridProp::getGridSpacingPhi(nPhiPoints); + const DataT rSpacing = GridProp::getGridSpacingR(nRPoints); + const DataT zSpacing = side == Side::A ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints); + + o2::utils::TreeStreamRedirector pcstream(outFileName, "RECREATE"); + pcstream.GetFile()->cd(); + for (int iPhi = 0; iPhi < nPhiPoints; ++iPhi) { + DataT phiPos = iPhi * phiSpacing; + for (int iR = 0; iR < nRPoints; ++iR) { + DataT rPos = getRMin(side) + iR * rSpacing; + for (int iZ = 0; iZ < nZPoints; ++iZ) { + DataT zPos = getZMin(side) + iZ * zSpacing; + DataT density = getDensityCyl(zPos, rPos, phiPos, side); + DataT potential = getPotentialCyl(zPos, rPos, phiPos, side); + + DataT distZ{}; + DataT distR{}; + DataT distRPhi{}; + getDistortionsCyl(zPos, rPos, phiPos, side, distZ, distR, distRPhi); + + // get average distortions + DataT corrZ{}; + DataT corrR{}; + DataT corrRPhi{}; + getCorrectionsCyl(zPos, rPos, phiPos, side, corrZ, corrR, corrRPhi); + + DataT lcorrZ{}; + DataT lcorrR{}; + DataT lcorrRPhi{}; + getLocalCorrectionsCyl(zPos, rPos, phiPos, side, lcorrZ, lcorrR, lcorrRPhi); + + DataT ldistZ{}; + DataT ldistR{}; + DataT ldistRPhi{}; + getLocalDistortionsCyl(zPos, rPos, phiPos, side, ldistZ, ldistR, ldistRPhi); + + // get average distortions + DataT eZ{}; + DataT eR{}; + DataT ePhi{}; + getElectricFieldsCyl(zPos, rPos, phiPos, side, eZ, eR, ePhi); + + pcstream << "sc" + << "phi=" << phiPos + << "r=" << rPos + << "z=" << zPos + << "scdensity=" << density + << "potential=" << potential + << "eZ=" << eZ + << "eR=" << eR + << "ePhi=" << ePhi + << "distZ=" << distZ + << "distR=" << distR + << "distRPhi=" << distRPhi + << "corrZ=" << corrZ + << "corrR=" << corrR + << "corrRPhi=" << corrRPhi + << "lcorrZ=" << lcorrZ + << "lcorrR=" << lcorrR + << "lcorrRPhi=" << lcorrRPhi + << "ldistZ=" << ldistZ + << "ldistR=" << ldistR + << "ldistRPhi=" << ldistRPhi + << "\n"; + } + } + } + pcstream.Close(); +} + +template <typename DataT> +void SpaceCharge<DataT>::normalizeHistoQVEps0(TH3& histoIonsPhiRZ) +{ + const auto deltaPhi = histoIonsPhiRZ.GetXaxis()->GetBinWidth(1); + const auto deltaZ = histoIonsPhiRZ.GetZaxis()->GetBinWidth(1); + const auto fac = deltaPhi * deltaZ * o2::tpc::TPCParameters<DataT>::E0 / (2 * 100 * TMath::Qe()); // 100 to normalize to cm: vacuum permittivity [A·s/(V·cm)] + for (int ir = 1; ir <= histoIonsPhiRZ.GetNbinsY(); ++ir) { + const auto r0 = histoIonsPhiRZ.GetYaxis()->GetBinLowEdge(ir); + const auto r1 = histoIonsPhiRZ.GetYaxis()->GetBinUpEdge(ir); + const auto norm = fac * (r1 * r1 - r0 * r0); + for (int iphi = 1; iphi <= histoIonsPhiRZ.GetNbinsX(); ++iphi) { + for (int iz = 1; iz <= histoIonsPhiRZ.GetNbinsZ(); ++iz) { + const auto charge = histoIonsPhiRZ.GetBinContent(iphi, ir, iz); + histoIonsPhiRZ.SetBinContent(iphi, ir, iz, charge / norm); + } + } + } +} + +using DataTD = double; +template class o2::tpc::SpaceCharge<DataTD>; + +using NumFieldsD = NumericalFields<DataTD>; +using AnaFieldsD = AnalyticalFields<DataTD>; +using DistCorrInterpD = DistCorrInterpolator<DataTD>; +using O2TPCSpaceCharge3DCalcD = SpaceCharge<DataTD>; + +template void O2TPCSpaceCharge3DCalcD::integrateEFieldsRoot(const DataTD, const DataTD, const DataTD, const DataTD, DataTD&, DataTD&, DataTD&, const NumFieldsD&) const; +template void O2TPCSpaceCharge3DCalcD::integrateEFieldsRoot(const DataTD, const DataTD, const DataTD, const DataTD, DataTD&, DataTD&, DataTD&, const AnaFieldsD&) const; +template void O2TPCSpaceCharge3DCalcD::calcLocalDistortionsCorrections(const O2TPCSpaceCharge3DCalcD::Type, const NumFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcLocalDistortionsCorrections(const O2TPCSpaceCharge3DCalcD::Type, const AnaFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcLocalDistortionCorrectionVector(const NumFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcLocalDistortionCorrectionVector(const AnaFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalCorrections(const NumFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalCorrections(const AnaFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalCorrections(const DistCorrInterpD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalDistortions(const NumFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalDistortions(const AnaFieldsD&); +template void O2TPCSpaceCharge3DCalcD::calcGlobalDistortions(const DistCorrInterpD&); + +using DataTF = float; +template class o2::tpc::SpaceCharge<DataTF>; + +using NumFieldsF = NumericalFields<DataTF>; +using AnaFieldsF = AnalyticalFields<DataTF>; +using DistCorrInterpF = DistCorrInterpolator<DataTF>; +using O2TPCSpaceCharge3DCalcF = SpaceCharge<DataTF>; + +template void O2TPCSpaceCharge3DCalcF::integrateEFieldsRoot(const DataTF, const DataTF, const DataTF, const DataTF, DataTF&, DataTF&, DataTF&, const NumFieldsF&) const; +template void O2TPCSpaceCharge3DCalcF::integrateEFieldsRoot(const DataTF, const DataTF, const DataTF, const DataTF, DataTF&, DataTF&, DataTF&, const AnaFieldsF&) const; +template void O2TPCSpaceCharge3DCalcF::calcLocalDistortionsCorrections(const O2TPCSpaceCharge3DCalcF::Type, const NumFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcLocalDistortionsCorrections(const O2TPCSpaceCharge3DCalcF::Type, const AnaFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcLocalDistortionCorrectionVector(const NumFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcLocalDistortionCorrectionVector(const AnaFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalCorrections(const NumFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalCorrections(const AnaFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalCorrections(const DistCorrInterpF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalDistortions(const NumFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalDistortions(const AnaFieldsF&); +template void O2TPCSpaceCharge3DCalcF::calcGlobalDistortions(const DistCorrInterpF&); diff --git a/Detectors/TPC/spacecharge/src/SpaceChargeParameter.cxx b/Detectors/TPC/spacecharge/src/SpaceChargeParameter.cxx new file mode 100644 index 0000000000000..067bccc2e1536 --- /dev/null +++ b/Detectors/TPC/spacecharge/src/SpaceChargeParameter.cxx @@ -0,0 +1,15 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCSpaceCharge/SpaceChargeParameter.h" + +using namespace o2::tpc; +O2ParamImpl(o2::tpc::ParameterSpaceCharge); diff --git a/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h b/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h new file mode 100644 index 0000000000000..316bc1dd86256 --- /dev/null +++ b/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCSpacechargeLinkDef.h +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ nestedclasses; +#pragma link C++ nestedtypedef; + +#pragma link C++ struct o2::tpc::ParameterSpaceCharge + ; +#pragma link C++ struct o2::tpc::MGParameters + ; +#pragma link C++ struct o2::tpc::TPCParameters < double> + ; +#pragma link C++ class o2::tpc::AnalyticalFields < double> + ; +#pragma link C++ class o2::tpc::RegularGrid3D < double> + ; +#pragma link C++ class o2::tpc::TriCubicInterpolator < double> + ; +#pragma link C++ class o2::tpc::DataContainer3D < double> + ; +#pragma link C++ class o2::tpc::PoissonSolver < double> + ; +#pragma link C++ class o2::tpc::SpaceCharge < double> + ; +#pragma link C++ class o2::tpc::NumericalFields < double> + ; +#pragma link C++ class o2::tpc::DistCorrInterpolator < double> + ; +#pragma link C++ class o2::tpc::GridProperties < double> + ; +#pragma link C++ struct o2::tpc::TPCParameters < float> + ; +#pragma link C++ class o2::tpc::AnalyticalFields < float> + ; +#pragma link C++ class o2::tpc::RegularGrid3D < float> + ; +#pragma link C++ class o2::tpc::TriCubicInterpolator < float> + ; +#pragma link C++ class o2::tpc::DataContainer3D < float> + ; +#pragma link C++ class o2::tpc::PoissonSolver < float> + ; +#pragma link C++ class o2::tpc::SpaceCharge < float> + ; +#pragma link C++ class o2::tpc::NumericalFields < float> + ; +#pragma link C++ class o2::tpc::DistCorrInterpolator < float> + ; +#pragma link C++ class o2::tpc::GridProperties < float> + ; +#endif diff --git a/Detectors/TPC/spacecharge/src/TriCubic.cxx b/Detectors/TPC/spacecharge/src/TriCubic.cxx new file mode 100644 index 0000000000000..f5ddac8aa7a1d --- /dev/null +++ b/Detectors/TPC/spacecharge/src/TriCubic.cxx @@ -0,0 +1,1256 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TriCubic.cxx +/// \brief Definition of TriCubic class +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#include "TPCSpaceCharge/TriCubic.h" + +using namespace o2::tpc; + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::operator()(const DataT z, const DataT r, const DataT phi, const InterpolationType type) const +{ + if (type == InterpolationType::Sparse) { + return interpolateSparse(z, r, phi); + } else { + const Vector<DataT, FDim> coordinates{{z, r, phi}}; // vector holding the coordinates + const auto relPos = processInp(coordinates, false); // vector containing the relative position to + return interpolateDense(relPos); + } +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::operator()(const DataT z, const DataT r, const DataT phi, const size_t derz, const size_t derr, const size_t derphi) const +{ + const Vector<DataT, FDim> coordinates{{z, r, phi}}; // vector holding the coordinates + const auto relPos = processInp(coordinates, false); + return evalDerivative(relPos[0], relPos[1], relPos[2], derz, derr, derphi); +} + +template <typename DataT> +void TriCubicInterpolator<DataT>::initInterpolator(const unsigned int iz, const unsigned int ir, const unsigned int iphi) const +{ + calcCoefficients(iz, ir, iphi); + + // store current cell + mInitialized[sThreadnum] = true; + mLastInd[sThreadnum][FZ] = iz; + mLastInd[sThreadnum][FR] = ir; + mLastInd[sThreadnum][FPHI] = iphi; +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::evalDerivative(const DataT dz, const DataT dr, const DataT dphi, const size_t derz, const size_t derr, const size_t derphi) const +{ + //TODO optimize this + DataT ret{}; + for (size_t i = derz; i < 4; i++) { + for (size_t j = derr; j < 4; j++) { + for (size_t k = derphi; k < 4; k++) { + + const size_t index = i + j * 4 + 16 * k; + DataT cont = mCoefficients[sThreadnum][index] * std::pow(dz, i - derz) * std::pow(dr, j - derr) * std::pow(dphi, k - derphi); + for (size_t w = 0; w < derz; w++) { + cont *= (i - w); + } + for (size_t w = 0; w < derr; w++) { + cont *= (j - w); + } + for (size_t w = 0; w < derphi; w++) { + cont *= (k - w); + } + ret += cont; + } + } + } + const DataT norm = std::pow(mGridProperties.getInvSpacingZ(), derz) * std::pow(mGridProperties.getInvSpacingR(), derr) * std::pow(mGridProperties.getInvSpacingPhi(), derphi); + return (ret * norm); +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::extrapolation(const DataT valk, const DataT valk1, const DataT valk2) const +{ + switch (mExtrapolationType) { + case ExtrapolationType::Linear: + default: + return linearExtrapolation(valk, valk1); + break; + case ExtrapolationType::Parabola: + return parabolExtrapolation(valk, valk1, valk2); + break; + } +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::linearExtrapolation(const DataT valk, const DataT valk1) const +{ + const DataT val = 2 * valk - valk1; + return val; +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::parabolExtrapolation(const DataT valk, const DataT valk1, const DataT valk2) const +{ + const DataT val = 3 * (valk - valk1) + valk2; // legendre polynom with x0=0, x1=1, x2=2 and z=-1 + return val; +} + +template <typename DataT> +void TriCubicInterpolator<DataT>::calcCoefficients(const unsigned int iz, const unsigned int ir, const unsigned int iphi) const +{ + DataT cVals[64]{}; + setValues(iz, ir, iphi, cVals); + + // needed for first derivative + const Vector<DataT, 24> vecDeriv1A{ + {cVals[22], cVals[23], cVals[26], cVals[27], cVals[38], cVals[39], cVals[42], cVals[43], + cVals[25], cVals[26], cVals[29], cVals[30], cVals[41], cVals[42], cVals[45], cVals[46], + cVals[37], cVals[38], cVals[41], cVals[42], cVals[53], cVals[54], cVals[57], cVals[58]}}; + + const Vector<DataT, 24> vecDeriv1B{ + {cVals[20], cVals[21], cVals[24], cVals[25], cVals[36], cVals[37], cVals[40], cVals[41], + cVals[17], cVals[18], cVals[21], cVals[22], cVals[33], cVals[34], cVals[37], cVals[38], + cVals[5], cVals[6], cVals[9], cVals[10], cVals[21], cVals[22], cVals[25], cVals[26]}}; + + // needed for second derivative + const Vector<DataT, 24> vecDeriv2A{ + {cVals[26], cVals[27], cVals[30], cVals[31], cVals[42], cVals[43], cVals[46], cVals[47], + cVals[38], cVals[39], cVals[42], cVals[43], cVals[54], cVals[55], cVals[58], cVals[59], + cVals[41], cVals[42], cVals[45], cVals[46], cVals[57], cVals[58], cVals[61], cVals[62]}}; + + const Vector<DataT, 24> vecDeriv2B{ + {cVals[24], cVals[25], cVals[28], cVals[29], cVals[40], cVals[41], cVals[44], cVals[45], + cVals[36], cVals[37], cVals[40], cVals[41], cVals[52], cVals[53], cVals[56], cVals[57], + cVals[33], cVals[34], cVals[37], cVals[38], cVals[49], cVals[50], cVals[53], cVals[54]}}; + + const Vector<DataT, 24> vecDeriv2C{ + {cVals[18], cVals[19], cVals[22], cVals[23], cVals[34], cVals[35], cVals[38], cVals[39], + cVals[6], cVals[7], cVals[10], cVals[11], cVals[22], cVals[23], cVals[26], cVals[27], + cVals[9], cVals[10], cVals[13], cVals[14], cVals[25], cVals[26], cVals[29], cVals[30]}}; + + const Vector<DataT, 24> vecDeriv2D{ + {cVals[16], cVals[17], cVals[20], cVals[21], cVals[32], cVals[33], cVals[36], cVals[37], + cVals[4], cVals[5], cVals[8], cVals[9], cVals[20], cVals[21], cVals[24], cVals[25], + cVals[1], cVals[2], cVals[5], cVals[6], cVals[17], cVals[18], cVals[21], cVals[22]}}; + + // needed for third derivative + const Vector<DataT, 8> vecDeriv3A{{cVals[42], cVals[43], cVals[46], cVals[47], cVals[58], cVals[59], cVals[62], cVals[63]}}; + const Vector<DataT, 8> vecDeriv3B{{cVals[40], cVals[41], cVals[44], cVals[45], cVals[56], cVals[57], cVals[60], cVals[61]}}; + const Vector<DataT, 8> vecDeriv3C{{cVals[34], cVals[35], cVals[38], cVals[39], cVals[50], cVals[51], cVals[54], cVals[55]}}; + const Vector<DataT, 8> vecDeriv3D{{cVals[32], cVals[33], cVals[36], cVals[37], cVals[48], cVals[49], cVals[52], cVals[53]}}; + const Vector<DataT, 8> vecDeriv3E{{cVals[10], cVals[11], cVals[14], cVals[15], cVals[26], cVals[27], cVals[30], cVals[31]}}; + const Vector<DataT, 8> vecDeriv3F{{cVals[8], cVals[9], cVals[12], cVals[13], cVals[24], cVals[25], cVals[28], cVals[29]}}; + const Vector<DataT, 8> vecDeriv3G{{cVals[2], cVals[3], cVals[6], cVals[7], cVals[18], cVals[19], cVals[22], cVals[23]}}; + const Vector<DataT, 8> vecDeriv3H{{cVals[0], cVals[1], cVals[4], cVals[5], cVals[16], cVals[17], cVals[20], cVals[21]}}; + + // factor for first derivative + const DataT fac1{0.5}; + const Vector<DataT, 24> vfac1{{fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1, fac1}}; + + // factor for second derivative + const DataT fac2{0.25}; + const Vector<DataT, 24> vfac2{{fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2, fac2}}; + + // factor for third derivative + const DataT fac3{0.125}; + const Vector<DataT, 8> vfac3{{fac3, fac3, fac3, fac3, fac3, fac3, fac3, fac3}}; + + // compute the derivatives + const Vector<DataT, 24> vecDeriv1Res{vfac1 * (vecDeriv1A - vecDeriv1B)}; + const Vector<DataT, 24> vecDeriv2Res{vfac2 * (vecDeriv2A - vecDeriv2B - vecDeriv2C + vecDeriv2D)}; + const Vector<DataT, 8> vecDeriv3Res{vfac3 * (vecDeriv3A - vecDeriv3B - vecDeriv3C + vecDeriv3D - vecDeriv3E + vecDeriv3F + vecDeriv3G - vecDeriv3H)}; + + const Vector<DataT, 64> matrixPar{ + {cVals[21], cVals[22], cVals[25], cVals[26], cVals[37], cVals[38], cVals[41], cVals[42], + vecDeriv1Res[0], vecDeriv1Res[1], vecDeriv1Res[2], vecDeriv1Res[3], vecDeriv1Res[4], vecDeriv1Res[5], vecDeriv1Res[6], vecDeriv1Res[7], vecDeriv1Res[8], vecDeriv1Res[9], vecDeriv1Res[10], + vecDeriv1Res[11], vecDeriv1Res[12], vecDeriv1Res[13], vecDeriv1Res[14], vecDeriv1Res[15], vecDeriv1Res[16], vecDeriv1Res[17], vecDeriv1Res[18], vecDeriv1Res[19], vecDeriv1Res[20], vecDeriv1Res[21], + vecDeriv1Res[22], vecDeriv1Res[23], vecDeriv2Res[0], vecDeriv2Res[1], vecDeriv2Res[2], vecDeriv2Res[3], vecDeriv2Res[4], vecDeriv2Res[5], vecDeriv2Res[6], vecDeriv2Res[7], vecDeriv2Res[8], vecDeriv2Res[9], + vecDeriv2Res[10], vecDeriv2Res[11], vecDeriv2Res[12], vecDeriv2Res[13], vecDeriv2Res[14], vecDeriv2Res[15], vecDeriv2Res[16], vecDeriv2Res[17], vecDeriv2Res[18], vecDeriv2Res[19], vecDeriv2Res[20], + vecDeriv2Res[21], vecDeriv2Res[22], vecDeriv2Res[23], vecDeriv3Res[0], vecDeriv3Res[1], vecDeriv3Res[2], vecDeriv3Res[3], vecDeriv3Res[4], vecDeriv3Res[5], vecDeriv3Res[6], vecDeriv3Res[7]}}; + + // calc coeffiecients + mCoefficients[sThreadnum] = sMatrixA * matrixPar; +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::interpolateDense(const Vector<DataT, 3>& pos) const +{ + // the formula for evaluating the interpolation is as follows: + // f(z,r,phi) = \sum_{i,j,k=0}^3 a_{ijk} * z^{i} * r^{j} * phi^{k} + // a_{ijk} is stored in mCoefficients[] and are computed in the function calcCoefficientsX() + + const Vector<DataT, FDim> vals0{{1, 1, 1}}; // z^0, r^0, phi^0 + const Vector<DataT, FDim> vals2{pos * pos}; // z^2, r^2, phi^2 + const Vector<DataT, FDim> vals3{vals2 * pos}; // z^3, r^3, phi^3 + + const DataT valX[4]{vals0[FZ], pos[FZ], vals2[FZ], vals3[FZ]}; + const Vector<DataT, 64> vecValX{ + {valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], + valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], + valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], + valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3], valX[0], valX[1], valX[2], valX[3]}}; + + const DataT valY[4]{vals0[FR], pos[FR], vals2[FR], vals3[FR]}; + const Vector<DataT, 64> vecValY{ + {valY[0], valY[0], valY[0], valY[0], valY[1], valY[1], valY[1], valY[1], valY[2], valY[2], valY[2], valY[2], valY[3], valY[3], valY[3], valY[3], + valY[0], valY[0], valY[0], valY[0], valY[1], valY[1], valY[1], valY[1], valY[2], valY[2], valY[2], valY[2], valY[3], valY[3], valY[3], valY[3], + valY[0], valY[0], valY[0], valY[0], valY[1], valY[1], valY[1], valY[1], valY[2], valY[2], valY[2], valY[2], valY[3], valY[3], valY[3], valY[3], + valY[0], valY[0], valY[0], valY[0], valY[1], valY[1], valY[1], valY[1], valY[2], valY[2], valY[2], valY[2], valY[3], valY[3], valY[3], valY[3]}}; + + const DataT valZ[4]{vals0[FPHI], pos[FPHI], vals2[FPHI], vals3[FPHI]}; + const Vector<DataT, 64> vecValZ{ + {valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], valZ[0], + valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], valZ[1], + valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], valZ[2], + valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3], valZ[3]}}; + + // result = f(z,r,phi) = \sum_{i,j,k=0}^3 a_{ijk} * z^{i} * r^{j} * phi^{k} + const DataT result = sum(mCoefficients[sThreadnum] * vecValX * vecValY * vecValZ); + return result; +} + +template <typename DataT> +DataT TriCubicInterpolator<DataT>::interpolateSparse(const DataT z, const DataT r, const DataT phi) const +{ + const Vector<DataT, FDim> coordinates{{z, r, phi}}; // vector holding the coordinates + const auto posRel = processInp(coordinates, true); + + DataT cVals[64]{}; + setValues(mLastInd[sThreadnum][FZ], mLastInd[sThreadnum][FR], mLastInd[sThreadnum][FPHI], cVals); + + const Vector<DataT, FDim> vals0{posRel}; + const Vector<DataT, FDim> vals1{vals0 * vals0}; + const Vector<DataT, FDim> vals2{vals0 * vals1}; + + const int nPoints = 4; + const Vector<DataT, nPoints> vecValX{{1, vals0[FZ], vals1[FZ], vals2[FZ]}}; + const Vector<DataT, nPoints> vecValY{{1, vals0[FR], vals1[FR], vals2[FR]}}; + const Vector<DataT, nPoints> vecValZ{{1, vals0[FPHI], vals1[FPHI], vals2[FPHI]}}; + + const Vc::Memory<VDataT, nPoints> matrA[nPoints]{ + {0, -0.5, 1, -0.5}, + {1, 0, -2.5, 1.5}, + {0, 0.5, 2., -1.5}, + {0, 0, -0.5, 0.5}}; + + const Matrix<DataT, nPoints> matrixA{matrA}; + const Vector<DataT, nPoints> vecValXMult{matrixA * vecValX}; + const Vector<DataT, nPoints> vecValYMult{matrixA * vecValY}; + const Vector<DataT, nPoints> vecValZMult{matrixA * vecValZ}; + + DataT result{}; + int ind = 0; + for (int slice = 0; slice < nPoints; ++slice) { + const Vector<DataT, nPoints> vecA{vecValZMult[slice] * vecValYMult}; + for (int row = 0; row < nPoints; ++row) { + const Vector<DataT, nPoints> vecD{{cVals[ind], cVals[++ind], cVals[++ind], cVals[++ind]}}; + ++ind; + result += sum(vecA[row] * vecValXMult * vecD); + } + } + return result; +} + +template <typename DataT> +const Vector<DataT, 3> TriCubicInterpolator<DataT>::processInp(const Vector<DataT, 3>& coordinates, const bool sparse) const +{ + Vector<DataT, FDim> posRel{(coordinates - mGridProperties.getGridMin()) * mGridProperties.getInvSpacing()}; // needed for the grid index + posRel[FPHI] = mGridProperties.clampToGridCircularRel(posRel[FPHI], FPHI); + const Vector<DataT, FDim> posRelN{posRel}; + posRel[FZ] = mGridProperties.clampToGridRel(posRel[FZ], FZ); + posRel[FR] = mGridProperties.clampToGridRel(posRel[FR], FR); + + const Vector<DataT, FDim> index{floor(posRel)}; + + if (!sparse && (!mInitialized[sThreadnum] || !(mLastInd[sThreadnum] == index))) { + initInterpolator(index[FZ], index[FR], index[FPHI]); + } else if (sparse) { + mLastInd[sThreadnum][FZ] = index[FZ]; + mLastInd[sThreadnum][FR] = index[FR]; + mLastInd[sThreadnum][FPHI] = index[FPHI]; + mInitialized[sThreadnum] = false; + } + return posRelN - index; +} + +// for perdiodic boundary condition +template <typename DataT> +void TriCubicInterpolator<DataT>::getDataIndexCircularArray(const int index0, const int dim, int arr[]) const +{ + const int delta_min1 = getRegulatedDelta(index0, -1, dim, mGridProperties.getN(dim) - 1); + const int delta_plus1 = getRegulatedDelta(index0, +1, dim, 1 - mGridProperties.getN(dim)); + const int delta_plus2 = getRegulatedDelta(index0, +2, dim, 2 - mGridProperties.getN(dim)); + + arr[0] = mGridProperties.getDeltaDataIndex(delta_min1, dim); + arr[1] = mGridProperties.getDeltaDataIndex(delta_plus1, dim); + arr[2] = mGridProperties.getDeltaDataIndex(delta_plus2, dim); +} + +// for non perdiodic boundary condition +template <typename DataT> +void TriCubicInterpolator<DataT>::getDataIndexNonCircularArray(const int index0, const int dim, int arr[]) const +{ + const int delta_min1 = getRegulatedDelta(index0, -1, dim, 0); + const int delta_plus1 = getRegulatedDelta(index0, +1, dim, 0); + const int delta_plus2 = getRegulatedDelta(index0, +2, dim, delta_plus1); + + arr[0] = mGridProperties.getDeltaDataIndex(delta_min1, dim); + arr[1] = mGridProperties.getDeltaDataIndex(delta_plus1, dim); + arr[2] = mGridProperties.getDeltaDataIndex(delta_plus2, dim); +} + +template <typename DataT> +typename TriCubicInterpolator<DataT>::GridPos TriCubicInterpolator<DataT>::findPos(const int iz, const int ir, const int iphi) const +{ + GridPos pos = GridPos::None; + if (isInInnerVolume(iz, ir, iphi, pos)) { + return pos; + } + + if (findEdge(iz, ir, iphi, pos)) { + return pos; + } + + if (findLine(iz, ir, iphi, pos)) { + return pos; + } + + if (findSide(iz, ir, iphi, pos)) { + return pos; + } + return GridPos::None; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::findEdge(const int iz, const int ir, const int iphi, GridPos& posType) const +{ + const int iR = 2; + if (iz == 0 && ir == 0) { + if (iphi == 0) { + posType = GridPos::Edge0; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::Edge4; + return true; + } + } else if (iz == mGridData.getNZ() - iR && ir == 0) { + if (iphi == 0) { + posType = GridPos::Edge1; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::Edge5; + return true; + } + } else if (iz == 0 && ir == mGridData.getNR() - iR) { + if (iphi == 0) { + posType = GridPos::Edge2; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::Edge6; + return true; + } + } else if (iz == mGridData.getNZ() - iR && ir == mGridData.getNR() - iR) { + if (iphi == 0) { + posType = GridPos::Edge3; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::Edge7; + return true; + } + } + return false; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::findLine(const int iz, const int ir, const int iphi, GridPos& posType) const +{ + const int iR = 2; + //check line + if (ir == 0) { + if (iphi == 0) { + posType = GridPos::LineA; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::LineE; + return true; + } + if (iz == 0) { + posType = GridPos::LineI; + return true; + } else if (iz == mGridData.getNZ() - iR) { + posType = GridPos::LineJ; + return true; + } + } else if (ir == mGridData.getNR() - iR) { + if (iphi == 0) { + posType = GridPos::LineB; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::LineF; + return true; + } + if (iz == 0) { + posType = GridPos::LineK; + return true; + } else if (iz == mGridData.getNZ() - iR) { + posType = GridPos::LineL; + return true; + } + } else if (iz == 0) { + if (iphi == 0) { + posType = GridPos::LineC; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::LineG; + return true; + } + } else if (iz == mGridData.getNZ() - iR) { + if (iphi == 0) { + posType = GridPos::LineD; + return true; + } else if (iphi == mGridData.getNPhi() - iR) { + posType = GridPos::LineH; + return true; + } + } + return false; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::findSide(const int iz, const int ir, const int iphi, GridPos& posType) const +{ + if (isSideRight(iz, FZ)) { + posType = GridPos::SideXRight; + return true; + } else if (isSideLeft(iz)) { + posType = GridPos::SideXLeft; + return true; + } + if (isSideRight(ir, FR)) { + posType = GridPos::SideYRight; + return true; + } else if (isSideLeft(ir)) { + posType = GridPos::SideYLeft; + return true; + } + if (isSideRight(iphi, FPHI)) { + posType = GridPos::SideZRight; + return true; + } else if (isSideLeft(iphi)) { + posType = GridPos::SideZLeft; + return true; + } + return false; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::isInInnerVolume(const int iz, const int ir, const int iphi, GridPos& posType) const +{ + if (iz >= 1 && iz < static_cast<int>(mGridData.getNZ() - 2) && ir >= 1 && ir < static_cast<int>(mGridData.getNR() - 2) && iphi >= 1 && iphi < static_cast<int>(mGridData.getNPhi() - 2)) { + posType = GridPos::InnerVolume; + return true; + } + return false; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::isSideRight(const int ind, const int dim) const +{ + if (ind == static_cast<int>(mGridProperties.getN(dim) - 2)) { + return true; + } + return false; +} + +template <typename DataT> +bool TriCubicInterpolator<DataT>::isSideLeft(const int ind) const +{ + if (ind == 0) { + return true; + } + return false; +} + +template <typename DataT> +void TriCubicInterpolator<DataT>::setValues(const int iz, const int ir, const int iphi, DataT cVals[64]) const +{ + const GridPos location = findPos(iz, ir, iphi); + const int ii_x_y_z = mGridData.getDataIndex(iz, ir, iphi); + cVals[21] = mGridData[ii_x_y_z]; + + int deltaZ[3]{mGridProperties.getDeltaDataIndex(-1, 0), mGridProperties.getDeltaDataIndex(1, 0), mGridProperties.getDeltaDataIndex(2, 0)}; + int deltaR[3]{mGridProperties.getDeltaDataIndex(-1, 1), mGridProperties.getDeltaDataIndex(1, 1), mGridProperties.getDeltaDataIndex(2, 1)}; + int deltaPhi[3]{}; + getDataIndexCircularArray(iphi, FPHI, deltaPhi); + + const int i0 = 0; + const int i1 = 1; + const int i2 = 2; + + switch (location) { + case GridPos::InnerVolume: + case GridPos::SideZRight: + case GridPos::SideZLeft: + default: { + const int ind[4][4][4]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0], ind[0][0][2] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0], ind[0][1][2] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0], ind[0][2][2] - deltaZ[i0]}, + {ind[0][2][0] - deltaR[i0], ind[0][3][0] - deltaZ[i0], ind[0][3][1] - deltaZ[i0], ind[0][3][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0] + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0], ind[1][0][2] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0], ind[1][1][2] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0], ind[1][2][2] - deltaZ[i0]}, + {ind[1][2][0] - deltaR[i0], ind[1][3][0] - deltaZ[i0], ind[1][3][1] - deltaZ[i0], ind[1][3][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0], ind[2][0][2] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0], ind[2][1][2] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0], ind[2][2][2] - deltaZ[i0]}, + {ind[2][2][0] - deltaR[i0], ind[2][3][0] - deltaZ[i0], ind[2][3][1] - deltaZ[i0], ind[2][3][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0], ind[3][0][2] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0], ind[3][1][2] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0], ind[3][2][2] - deltaZ[i0]}, + {ind[3][2][0] - deltaR[i0], ind[3][3][0] - deltaZ[i0], ind[3][3][1] - deltaZ[i0], ind[3][3][2] - deltaZ[i0]}}}; + + cVals[0] = mGridData[ind[0][0][0]]; + cVals[1] = mGridData[ind[0][0][1]]; + cVals[2] = mGridData[ind[0][0][2]]; + cVals[3] = mGridData[ind[0][0][3]]; + cVals[4] = mGridData[ind[0][1][0]]; + cVals[5] = mGridData[ind[0][1][1]]; + cVals[6] = mGridData[ind[0][1][2]]; + cVals[7] = mGridData[ind[0][1][3]]; + cVals[8] = mGridData[ind[0][2][0]]; + cVals[9] = mGridData[ind[0][2][1]]; + cVals[10] = mGridData[ind[0][2][2]]; + cVals[11] = mGridData[ind[0][2][3]]; + cVals[12] = mGridData[ind[0][3][0]]; + cVals[13] = mGridData[ind[0][3][1]]; + cVals[14] = mGridData[ind[0][3][2]]; + cVals[15] = mGridData[ind[0][3][3]]; + cVals[16] = mGridData[ind[1][0][0]]; + cVals[17] = mGridData[ind[1][0][1]]; + cVals[18] = mGridData[ind[1][0][2]]; + cVals[19] = mGridData[ind[1][0][3]]; + cVals[22] = mGridData[ind[1][1][2]]; + cVals[20] = mGridData[ind[1][1][0]]; + cVals[23] = mGridData[ind[1][1][3]]; + cVals[24] = mGridData[ind[1][2][0]]; + cVals[25] = mGridData[ind[1][2][1]]; + cVals[26] = mGridData[ind[1][2][2]]; + cVals[27] = mGridData[ind[1][2][3]]; + cVals[28] = mGridData[ind[1][3][0]]; + cVals[29] = mGridData[ind[1][3][1]]; + cVals[30] = mGridData[ind[1][3][2]]; + cVals[31] = mGridData[ind[1][3][3]]; + cVals[32] = mGridData[ind[2][0][0]]; + cVals[33] = mGridData[ind[2][0][1]]; + cVals[34] = mGridData[ind[2][0][2]]; + cVals[35] = mGridData[ind[2][0][3]]; + cVals[36] = mGridData[ind[2][1][0]]; + cVals[37] = mGridData[ind[2][1][1]]; + cVals[38] = mGridData[ind[2][1][2]]; + cVals[39] = mGridData[ind[2][1][3]]; + cVals[40] = mGridData[ind[2][2][0]]; + cVals[41] = mGridData[ind[2][2][1]]; + cVals[42] = mGridData[ind[2][2][2]]; + cVals[43] = mGridData[ind[2][2][3]]; + cVals[44] = mGridData[ind[2][3][0]]; + cVals[45] = mGridData[ind[2][3][1]]; + cVals[46] = mGridData[ind[2][3][2]]; + cVals[47] = mGridData[ind[2][3][3]]; + cVals[48] = mGridData[ind[3][0][0]]; + cVals[49] = mGridData[ind[3][0][1]]; + cVals[50] = mGridData[ind[3][0][2]]; + cVals[51] = mGridData[ind[3][0][3]]; + cVals[52] = mGridData[ind[3][1][0]]; + cVals[53] = mGridData[ind[3][1][1]]; + cVals[54] = mGridData[ind[3][1][2]]; + cVals[55] = mGridData[ind[3][1][3]]; + cVals[56] = mGridData[ind[3][2][0]]; + cVals[57] = mGridData[ind[3][2][1]]; + cVals[58] = mGridData[ind[3][2][2]]; + cVals[59] = mGridData[ind[3][2][3]]; + cVals[60] = mGridData[ind[3][3][0]]; + cVals[61] = mGridData[ind[3][3][1]]; + cVals[62] = mGridData[ind[3][3][2]]; + cVals[63] = mGridData[ind[3][3][3]]; + } break; + + case GridPos::SideXRight: + case GridPos::LineD: + case GridPos::LineH: { + const int ind[4][4][3]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}, + {ind[0][2][0] - deltaR[i0], ind[0][3][0] - deltaZ[i0], ind[0][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0] + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}, + {ind[1][2][0] - deltaR[i0], ind[1][3][0] - deltaZ[i0], ind[1][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}, + {ind[2][2][0] - deltaR[i0], ind[2][3][0] - deltaZ[i0], ind[2][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}, + {ind[3][2][0] - deltaR[i0], ind[3][3][0] - deltaZ[i0], ind[3][3][1] - deltaZ[i0]}}}; + + cVals[0] = mGridData[ind[0][0][0]]; + cVals[1] = mGridData[ind[0][0][1]]; + cVals[2] = mGridData[ind[0][0][2]]; + cVals[3] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][0][1]], mGridData[ind[0][0][0]]); + cVals[4] = mGridData[ind[0][1][0]]; + cVals[5] = mGridData[ind[0][1][1]]; + cVals[6] = mGridData[ind[0][1][2]]; + cVals[7] = extrapolation(mGridData[ind[0][1][2]], mGridData[ind[0][1][1]], mGridData[ind[0][1][0]]); + cVals[8] = mGridData[ind[0][2][0]]; + cVals[9] = mGridData[ind[0][2][1]]; + cVals[10] = mGridData[ind[0][2][2]]; + cVals[11] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][2][1]], mGridData[ind[0][2][0]]); + cVals[12] = mGridData[ind[0][3][0]]; + cVals[13] = mGridData[ind[0][3][1]]; + cVals[14] = mGridData[ind[0][3][2]]; + cVals[15] = extrapolation(mGridData[ind[0][3][2]], mGridData[ind[0][3][1]], mGridData[ind[0][3][0]]); + cVals[16] = mGridData[ind[1][0][0]]; + cVals[17] = mGridData[ind[1][0][1]]; + cVals[18] = mGridData[ind[1][0][2]]; + cVals[19] = extrapolation(mGridData[ind[1][0][2]], mGridData[ind[1][0][1]], mGridData[ind[1][0][0]]); + cVals[20] = mGridData[ind[1][1][0]]; + cVals[22] = mGridData[ind[1][1][2]]; + cVals[23] = extrapolation(mGridData[ind[1][1][2]], mGridData[ii_x_y_z], mGridData[ind[1][1][0]]); + cVals[24] = mGridData[ind[1][2][0]]; + cVals[25] = mGridData[ind[1][2][1]]; + cVals[26] = mGridData[ind[1][2][2]]; + cVals[27] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][2][1]], mGridData[ind[1][2][0]]); + cVals[28] = mGridData[ind[1][3][0]]; + cVals[29] = mGridData[ind[1][3][1]]; + cVals[30] = mGridData[ind[1][3][2]]; + cVals[31] = extrapolation(mGridData[ind[1][3][2]], mGridData[ind[1][3][1]], mGridData[ind[1][3][0]]); + cVals[32] = mGridData[ind[2][0][0]]; + cVals[33] = mGridData[ind[2][0][1]]; + cVals[34] = mGridData[ind[2][0][2]]; + cVals[35] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][0][1]], mGridData[ind[2][0][0]]); + cVals[36] = mGridData[ind[2][1][0]]; + cVals[37] = mGridData[ind[2][1][1]]; + cVals[38] = mGridData[ind[2][1][2]]; + cVals[39] = extrapolation(mGridData[ind[2][1][2]], mGridData[ind[2][1][1]], mGridData[ind[2][1][0]]); + cVals[40] = mGridData[ind[2][2][0]]; + cVals[41] = mGridData[ind[2][2][1]]; + cVals[42] = mGridData[ind[2][2][2]]; + cVals[43] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][2][1]], mGridData[ind[2][2][0]]); + cVals[44] = mGridData[ind[2][3][0]]; + cVals[45] = mGridData[ind[2][3][1]]; + cVals[46] = mGridData[ind[2][3][2]]; + cVals[47] = extrapolation(mGridData[ind[2][3][2]], mGridData[ind[2][3][1]], mGridData[ind[2][3][0]]); + cVals[48] = mGridData[ind[3][0][0]]; + cVals[49] = mGridData[ind[3][0][1]]; + cVals[50] = mGridData[ind[3][0][2]]; + cVals[52] = mGridData[ind[3][1][0]]; + cVals[51] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][0][1]], mGridData[ind[3][0][0]]); + cVals[53] = mGridData[ind[3][1][1]]; + cVals[54] = mGridData[ind[3][1][2]]; + cVals[55] = extrapolation(mGridData[ind[3][1][2]], mGridData[ind[3][1][1]], mGridData[ind[3][1][0]]); + cVals[56] = mGridData[ind[3][2][0]]; + cVals[57] = mGridData[ind[3][2][1]]; + cVals[58] = mGridData[ind[3][2][2]]; + cVals[59] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][2][1]], mGridData[ind[3][2][0]]); + cVals[60] = mGridData[ind[3][3][0]]; + cVals[61] = mGridData[ind[3][3][1]]; + cVals[62] = mGridData[ind[3][3][2]]; + cVals[63] = extrapolation(mGridData[ind[3][3][2]], mGridData[ind[3][3][1]], mGridData[ind[3][3][0]]); + } break; + + case GridPos::SideYRight: + case GridPos::LineB: + case GridPos::LineF: { + const int ind[4][3][4]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0], ind[0][0][2] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0], ind[0][1][2] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0], ind[0][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0] + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0], ind[1][0][2] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0], ind[1][1][2] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0], ind[1][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0], ind[2][0][2] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0], ind[2][1][2] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0], ind[2][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0], ind[3][0][2] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0], ind[3][1][2] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0], ind[3][2][2] - deltaZ[i0]}}}; + + cVals[0] = mGridData[ind[0][0][0]]; + cVals[1] = mGridData[ind[0][0][1]]; + cVals[2] = mGridData[ind[0][0][2]]; + cVals[3] = mGridData[ind[0][0][3]]; + cVals[4] = mGridData[ind[0][1][0]]; + cVals[5] = mGridData[ind[0][1][1]]; + cVals[6] = mGridData[ind[0][1][2]]; + cVals[7] = mGridData[ind[0][1][3]]; + cVals[8] = mGridData[ind[0][2][0]]; + cVals[9] = mGridData[ind[0][2][1]]; + cVals[10] = mGridData[ind[0][2][2]]; + cVals[11] = mGridData[ind[0][2][3]]; + cVals[12] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][1][0]], mGridData[ind[0][0][0]]); + cVals[13] = extrapolation(mGridData[ind[0][2][1]], mGridData[ind[0][1][1]], mGridData[ind[0][0][1]]); + cVals[14] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][1][2]], mGridData[ind[0][0][2]]); + cVals[15] = extrapolation(mGridData[ind[0][2][3]], mGridData[ind[0][1][3]], mGridData[ind[0][0][3]]); + cVals[16] = mGridData[ind[1][0][0]]; + cVals[17] = mGridData[ind[1][0][1]]; + cVals[18] = mGridData[ind[1][0][2]]; + cVals[19] = mGridData[ind[1][0][3]]; + cVals[20] = mGridData[ind[1][1][0]]; + cVals[22] = mGridData[ind[1][1][2]]; + cVals[23] = mGridData[ind[1][1][3]]; + cVals[24] = mGridData[ind[1][2][0]]; + cVals[25] = mGridData[ind[1][2][1]]; + cVals[26] = mGridData[ind[1][2][2]]; + cVals[27] = mGridData[ind[1][2][3]]; + cVals[28] = extrapolation(mGridData[ind[1][2][0]], mGridData[ind[1][1][0]], mGridData[ind[1][0][0]]); + cVals[29] = extrapolation(mGridData[ind[1][2][1]], mGridData[ii_x_y_z], mGridData[ind[1][0][1]]); + cVals[30] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][1][2]], mGridData[ind[1][0][2]]); + cVals[31] = extrapolation(mGridData[ind[1][2][3]], mGridData[ind[1][1][3]], mGridData[ind[1][0][3]]); + cVals[32] = mGridData[ind[2][0][0]]; + cVals[33] = mGridData[ind[2][0][1]]; + cVals[34] = mGridData[ind[2][0][2]]; + cVals[35] = mGridData[ind[2][0][3]]; + cVals[36] = mGridData[ind[2][1][0]]; + cVals[37] = mGridData[ind[2][1][1]]; + cVals[38] = mGridData[ind[2][1][2]]; + cVals[39] = mGridData[ind[2][1][3]]; + cVals[40] = mGridData[ind[2][2][0]]; + cVals[41] = mGridData[ind[2][2][1]]; + cVals[42] = mGridData[ind[2][2][2]]; + cVals[43] = mGridData[ind[2][2][3]]; + cVals[44] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][1][0]], mGridData[ind[2][0][0]]); + cVals[45] = extrapolation(mGridData[ind[2][2][1]], mGridData[ind[2][1][1]], mGridData[ind[2][0][1]]); + cVals[46] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][1][2]], mGridData[ind[2][0][2]]); + cVals[47] = extrapolation(mGridData[ind[2][2][3]], mGridData[ind[2][1][3]], mGridData[ind[2][0][3]]); + cVals[48] = mGridData[ind[3][0][0]]; + cVals[49] = mGridData[ind[3][0][1]]; + cVals[50] = mGridData[ind[3][0][2]]; + cVals[51] = mGridData[ind[3][0][3]]; + cVals[52] = mGridData[ind[3][1][0]]; + cVals[53] = mGridData[ind[3][1][1]]; + cVals[54] = mGridData[ind[3][1][2]]; + cVals[55] = mGridData[ind[3][1][3]]; + cVals[56] = mGridData[ind[3][2][0]]; + cVals[57] = mGridData[ind[3][2][1]]; + cVals[58] = mGridData[ind[3][2][2]]; + cVals[59] = mGridData[ind[3][2][3]]; + cVals[60] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][1][0]], mGridData[ind[3][0][0]]); + cVals[61] = extrapolation(mGridData[ind[3][2][1]], mGridData[ind[3][1][1]], mGridData[ind[3][0][1]]); + cVals[62] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][1][2]], mGridData[ind[3][0][2]]); + cVals[63] = extrapolation(mGridData[ind[3][2][3]], mGridData[ind[3][1][3]], mGridData[ind[3][0][3]]); + } break; + + case GridPos::SideYLeft: + case GridPos::LineA: + case GridPos::LineE: { + const int ind[4][3][4]{ + {{ii_x_y_z + deltaPhi[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0], ind[0][0][2] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0], ind[0][1][2] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0], ind[0][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0], ind[1][0][2] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0], ind[1][1][2] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0], ind[1][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0], ind[2][0][2] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0], ind[2][1][2] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0], ind[2][2][2] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0], ind[3][0][2] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0], ind[3][1][2] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0], ind[3][2][2] - deltaZ[i0]}}}; + + cVals[0] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][1][0]], mGridData[ind[0][2][0]]); + cVals[1] = extrapolation(mGridData[ind[0][0][1]], mGridData[ind[0][1][1]], mGridData[ind[0][2][1]]); + cVals[2] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][1][2]], mGridData[ind[0][2][2]]); + cVals[3] = extrapolation(mGridData[ind[0][0][3]], mGridData[ind[0][1][3]], mGridData[ind[0][2][3]]); + cVals[4] = mGridData[ind[0][0][0]]; + cVals[5] = mGridData[ind[0][0][1]]; + cVals[6] = mGridData[ind[0][0][2]]; + cVals[7] = mGridData[ind[0][0][3]]; + cVals[8] = mGridData[ind[0][1][0]]; + cVals[9] = mGridData[ind[0][1][1]]; + cVals[10] = mGridData[ind[0][1][2]]; + cVals[11] = mGridData[ind[0][1][3]]; + cVals[12] = mGridData[ind[0][2][0]]; + cVals[13] = mGridData[ind[0][2][1]]; + cVals[14] = mGridData[ind[0][2][2]]; + cVals[15] = mGridData[ind[0][2][3]]; + cVals[16] = extrapolation(mGridData[ind[1][0][0]], mGridData[ind[1][1][0]], mGridData[ind[1][2][0]]); + cVals[17] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][1]], mGridData[ind[1][2][1]]); + cVals[18] = extrapolation(mGridData[ind[1][0][2]], mGridData[ind[1][1][2]], mGridData[ind[1][2][2]]); + cVals[19] = extrapolation(mGridData[ind[1][0][3]], mGridData[ind[1][1][3]], mGridData[ind[1][2][3]]); + cVals[20] = mGridData[ind[1][0][0]]; + cVals[22] = mGridData[ind[1][0][2]]; + cVals[23] = mGridData[ind[1][0][3]]; + cVals[24] = mGridData[ind[1][1][0]]; + cVals[25] = mGridData[ind[1][1][1]]; + cVals[26] = mGridData[ind[1][1][2]]; + cVals[27] = mGridData[ind[1][1][3]]; + cVals[28] = mGridData[ind[1][2][0]]; + cVals[29] = mGridData[ind[1][2][1]]; + cVals[30] = mGridData[ind[1][2][2]]; + cVals[31] = mGridData[ind[1][2][3]]; + cVals[32] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][1][0]], mGridData[ind[2][2][0]]); + cVals[33] = extrapolation(mGridData[ind[2][0][1]], mGridData[ind[2][1][1]], mGridData[ind[2][2][1]]); + cVals[34] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][1][2]], mGridData[ind[2][2][2]]); + cVals[35] = extrapolation(mGridData[ind[2][0][3]], mGridData[ind[2][1][3]], mGridData[ind[2][2][3]]); + cVals[36] = mGridData[ind[2][0][0]]; + cVals[37] = mGridData[ind[2][0][1]]; + cVals[38] = mGridData[ind[2][0][2]]; + cVals[39] = mGridData[ind[2][0][3]]; + cVals[40] = mGridData[ind[2][1][0]]; + cVals[41] = mGridData[ind[2][1][1]]; + cVals[42] = mGridData[ind[2][1][2]]; + cVals[43] = mGridData[ind[2][1][3]]; + cVals[44] = mGridData[ind[2][2][0]]; + cVals[45] = mGridData[ind[2][2][1]]; + cVals[46] = mGridData[ind[2][2][2]]; + cVals[47] = mGridData[ind[2][2][3]]; + cVals[48] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][1][0]], mGridData[ind[3][2][0]]); + cVals[49] = extrapolation(mGridData[ind[3][0][1]], mGridData[ind[3][1][1]], mGridData[ind[3][2][1]]); + cVals[50] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][1][2]], mGridData[ind[3][2][2]]); + cVals[51] = extrapolation(mGridData[ind[3][0][3]], mGridData[ind[3][1][3]], mGridData[ind[3][2][3]]); + cVals[52] = mGridData[ind[3][0][0]]; + cVals[53] = mGridData[ind[3][0][1]]; + cVals[54] = mGridData[ind[3][0][2]]; + cVals[55] = mGridData[ind[3][0][3]]; + cVals[56] = mGridData[ind[3][1][0]]; + cVals[57] = mGridData[ind[3][1][1]]; + cVals[58] = mGridData[ind[3][1][2]]; + cVals[59] = mGridData[ind[3][1][3]]; + cVals[60] = mGridData[ind[3][2][0]]; + cVals[61] = mGridData[ind[3][2][1]]; + cVals[62] = mGridData[ind[3][2][2]]; + cVals[63] = mGridData[ind[3][2][3]]; + } break; + + case GridPos::SideXLeft: + case GridPos::LineC: + case GridPos::LineG: { + const int ind[4][4][3]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}, + {ind[0][2][0] - deltaR[i0], ind[0][3][0] - deltaZ[i0], ind[0][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}, + {ind[1][2][0] - deltaR[i0], ind[1][3][0] - deltaZ[i0], ind[1][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}, + {ind[2][2][0] - deltaR[i0], ind[2][3][0] - deltaZ[i0], ind[2][3][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}, + {ind[3][2][0] - deltaR[i0], ind[3][3][0] - deltaZ[i0], ind[3][3][1] - deltaZ[i0]}}}; + + cVals[0] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][0][1]], mGridData[ind[0][0][2]]); + cVals[1] = mGridData[ind[0][0][0]]; + cVals[2] = mGridData[ind[0][0][1]]; + cVals[3] = mGridData[ind[0][0][2]]; + cVals[4] = extrapolation(mGridData[ind[0][1][0]], mGridData[ind[0][1][1]], mGridData[ind[0][1][2]]); + cVals[5] = mGridData[ind[0][1][0]]; + cVals[6] = mGridData[ind[0][1][1]]; + cVals[7] = mGridData[ind[0][1][2]]; + cVals[8] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][2][1]], mGridData[ind[0][2][2]]); + cVals[9] = mGridData[ind[0][2][0]]; + cVals[10] = mGridData[ind[0][2][1]]; + cVals[11] = mGridData[ind[0][2][2]]; + cVals[12] = extrapolation(mGridData[ind[0][3][0]], mGridData[ind[0][3][1]], mGridData[ind[0][3][2]]); + cVals[13] = mGridData[ind[0][3][0]]; + cVals[14] = mGridData[ind[0][3][1]]; + cVals[15] = mGridData[ind[0][3][2]]; + cVals[16] = extrapolation(mGridData[ind[1][0][0]], mGridData[ind[1][0][1]], mGridData[ind[1][0][2]]); + cVals[17] = mGridData[ind[1][0][0]]; + cVals[18] = mGridData[ind[1][0][1]]; + cVals[19] = mGridData[ind[1][0][2]]; + cVals[20] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][1]], mGridData[ind[1][1][2]]); + cVals[22] = mGridData[ind[1][1][1]]; + cVals[23] = mGridData[ind[1][1][2]]; + cVals[24] = extrapolation(mGridData[ind[1][2][0]], mGridData[ind[1][2][1]], mGridData[ind[1][2][2]]); + cVals[25] = mGridData[ind[1][2][0]]; + cVals[26] = mGridData[ind[1][2][1]]; + cVals[27] = mGridData[ind[1][2][2]]; + cVals[28] = extrapolation(mGridData[ind[1][3][0]], mGridData[ind[1][3][1]], mGridData[ind[1][3][2]]); + cVals[29] = mGridData[ind[1][3][0]]; + cVals[30] = mGridData[ind[1][3][1]]; + cVals[31] = mGridData[ind[1][3][2]]; + cVals[32] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][0][1]], mGridData[ind[2][0][2]]); + cVals[33] = mGridData[ind[2][0][0]]; + cVals[34] = mGridData[ind[2][0][1]]; + cVals[35] = mGridData[ind[2][0][2]]; + cVals[36] = extrapolation(mGridData[ind[2][1][0]], mGridData[ind[2][1][1]], mGridData[ind[2][1][2]]); + cVals[37] = mGridData[ind[2][1][0]]; + cVals[38] = mGridData[ind[2][1][1]]; + cVals[39] = mGridData[ind[2][1][2]]; + cVals[40] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][2][1]], mGridData[ind[2][2][2]]); + cVals[41] = mGridData[ind[2][2][0]]; + cVals[42] = mGridData[ind[2][2][1]]; + cVals[43] = mGridData[ind[2][2][2]]; + cVals[44] = extrapolation(mGridData[ind[2][3][0]], mGridData[ind[2][3][1]], mGridData[ind[2][3][2]]); + cVals[45] = mGridData[ind[2][3][0]]; + cVals[46] = mGridData[ind[2][3][1]]; + cVals[47] = mGridData[ind[2][3][2]]; + cVals[48] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][0][1]], mGridData[ind[3][0][2]]); + cVals[49] = mGridData[ind[3][0][0]]; + cVals[50] = mGridData[ind[3][0][1]]; + cVals[51] = mGridData[ind[3][0][2]]; + cVals[52] = extrapolation(mGridData[ind[3][1][0]], mGridData[ind[3][1][1]], mGridData[ind[3][1][2]]); + cVals[53] = mGridData[ind[3][1][0]]; + cVals[54] = mGridData[ind[3][1][1]]; + cVals[55] = mGridData[ind[3][1][2]]; + cVals[56] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][2][1]], mGridData[ind[3][2][2]]); + cVals[57] = mGridData[ind[3][2][0]]; + cVals[58] = mGridData[ind[3][2][1]]; + cVals[59] = mGridData[ind[3][2][2]]; + cVals[60] = extrapolation(mGridData[ind[3][3][0]], mGridData[ind[3][3][1]], mGridData[ind[3][3][2]]); + cVals[61] = mGridData[ind[3][3][0]]; + cVals[62] = mGridData[ind[3][3][1]]; + cVals[63] = mGridData[ind[3][3][2]]; + } break; + + case GridPos::Edge0: + case GridPos::Edge4: + case GridPos::LineI: { + const int ind[4][3][3]{ + {{ii_x_y_z + deltaPhi[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}}, + {{ii_x_y_z, ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}}}; + + cVals[0] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][1][1]], mGridData[ind[0][2][2]]); + cVals[1] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][1][0]], mGridData[ind[0][2][0]]); + cVals[2] = extrapolation(mGridData[ind[0][0][1]], mGridData[ind[0][1][1]], mGridData[ind[0][2][1]]); + cVals[3] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][1][2]], mGridData[ind[0][2][2]]); + cVals[4] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][0][1]], mGridData[ind[0][0][2]]); + cVals[5] = mGridData[ind[0][0][0]]; + cVals[6] = mGridData[ind[0][0][1]]; + cVals[7] = mGridData[ind[0][0][2]]; + cVals[8] = extrapolation(mGridData[ind[0][1][0]], mGridData[ind[0][1][1]], mGridData[ind[0][1][2]]); + cVals[9] = mGridData[ind[0][1][0]]; + cVals[10] = mGridData[ind[0][1][1]]; + cVals[11] = mGridData[ind[0][1][2]]; + cVals[12] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][2][1]], mGridData[ind[0][2][2]]); + cVals[13] = mGridData[ind[0][2][0]]; + cVals[14] = mGridData[ind[0][2][1]]; + cVals[15] = mGridData[ind[0][2][2]]; + cVals[16] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][1]], mGridData[ind[1][2][2]]); + cVals[17] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][0]], mGridData[ind[1][2][0]]); + cVals[18] = extrapolation(mGridData[ind[1][0][1]], mGridData[ind[1][1][1]], mGridData[ind[1][2][1]]); + cVals[19] = extrapolation(mGridData[ind[1][0][2]], mGridData[ind[1][1][2]], mGridData[ind[1][2][2]]); + cVals[20] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][0][1]], mGridData[ind[1][0][2]]); + cVals[22] = mGridData[ind[1][0][1]]; + cVals[23] = mGridData[ind[1][0][2]]; + cVals[24] = extrapolation(mGridData[ind[1][1][0]], mGridData[ind[1][1][1]], mGridData[ind[1][1][2]]); + cVals[25] = mGridData[ind[1][1][0]]; + cVals[26] = mGridData[ind[1][1][1]]; + cVals[27] = mGridData[ind[1][1][2]]; + cVals[28] = extrapolation(mGridData[ind[1][2][0]], mGridData[ind[1][2][1]], mGridData[ind[1][2][2]]); + cVals[29] = mGridData[ind[1][2][0]]; + cVals[30] = mGridData[ind[1][2][1]]; + cVals[31] = mGridData[ind[1][2][2]]; + cVals[32] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][1][1]], mGridData[ind[2][2][2]]); + cVals[33] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][1][0]], mGridData[ind[2][2][0]]); + cVals[34] = extrapolation(mGridData[ind[2][0][1]], mGridData[ind[2][1][1]], mGridData[ind[2][2][1]]); + cVals[35] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][1][2]], mGridData[ind[2][2][2]]); + cVals[36] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][0][1]], mGridData[ind[2][0][2]]); + cVals[37] = mGridData[ind[2][0][0]]; + cVals[38] = mGridData[ind[2][0][1]]; + cVals[39] = mGridData[ind[2][0][2]]; + cVals[40] = extrapolation(mGridData[ind[2][1][0]], mGridData[ind[2][1][1]], mGridData[ind[2][1][2]]); + cVals[41] = mGridData[ind[2][1][0]]; + cVals[42] = mGridData[ind[2][1][1]]; + cVals[43] = mGridData[ind[2][1][2]]; + cVals[44] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][2][1]], mGridData[ind[2][2][2]]); + cVals[45] = mGridData[ind[2][2][0]]; + cVals[46] = mGridData[ind[2][2][1]]; + cVals[47] = mGridData[ind[2][2][2]]; + cVals[48] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][1][1]], mGridData[ind[3][2][2]]); + cVals[49] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][1][0]], mGridData[ind[3][2][0]]); + cVals[50] = extrapolation(mGridData[ind[3][0][1]], mGridData[ind[3][1][1]], mGridData[ind[3][2][1]]); + cVals[51] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][1][2]], mGridData[ind[3][2][2]]); + cVals[52] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][0][1]], mGridData[ind[3][0][2]]); + cVals[53] = mGridData[ind[3][0][0]]; + cVals[54] = mGridData[ind[3][0][1]]; + cVals[55] = mGridData[ind[3][0][2]]; + cVals[56] = extrapolation(mGridData[ind[3][1][0]], mGridData[ind[3][1][1]], mGridData[ind[3][1][2]]); + cVals[57] = mGridData[ind[3][1][0]]; + cVals[58] = mGridData[ind[3][1][1]]; + cVals[59] = mGridData[ind[3][1][2]]; + cVals[60] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][2][1]], mGridData[ind[3][2][2]]); + cVals[61] = mGridData[ind[3][2][0]]; + cVals[62] = mGridData[ind[3][2][1]]; + cVals[63] = mGridData[ind[3][2][2]]; + } break; + + case GridPos::Edge1: + case GridPos::Edge5: + case GridPos::LineJ: { + const int ind[4][3][3]{ + {{ii_x_y_z + deltaPhi[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}}}; + + cVals[0] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][1][0]], mGridData[ind[0][2][0]]); + cVals[1] = extrapolation(mGridData[ind[0][0][1]], mGridData[ind[0][1][1]], mGridData[ind[0][2][1]]); + cVals[2] = extrapolation(mGridData[ind[0][0][1]], mGridData[ind[0][1][0]], mGridData[ind[0][2][0] + deltaZ[i0]]); + cVals[3] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][1][1]], mGridData[ind[0][2][0]]); + cVals[4] = mGridData[ind[0][0][0]]; + cVals[5] = mGridData[ind[0][0][1]]; + cVals[6] = mGridData[ind[0][0][2]]; + cVals[7] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][0][1]], mGridData[ind[0][0][0]]); + cVals[8] = mGridData[ind[0][1][0]]; + cVals[9] = mGridData[ind[0][1][1]]; + cVals[10] = mGridData[ind[0][1][2]]; + cVals[11] = extrapolation(mGridData[ind[0][1][2]], mGridData[ind[0][1][1]], mGridData[ind[0][1][0]]); + cVals[12] = mGridData[ind[0][2][0]]; + cVals[13] = mGridData[ind[0][2][1]]; + cVals[14] = mGridData[ind[0][2][2]]; + cVals[15] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][2][1]], mGridData[ind[0][2][0]]); + cVals[16] = extrapolation(mGridData[ind[1][0][0]], mGridData[ind[1][1][0]], mGridData[ind[1][2][0]]); + cVals[17] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][1]], mGridData[ind[1][2][1]]); + cVals[18] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][0]], mGridData[ind[1][2][0] + deltaZ[i0]]); + cVals[19] = extrapolation(mGridData[ind[1][0][2]], mGridData[ind[1][1][1]], mGridData[ind[1][2][0]]); + cVals[20] = mGridData[ind[1][0][0]]; + cVals[22] = mGridData[ind[1][0][2]]; + cVals[23] = extrapolation(mGridData[ind[1][0][2]], mGridData[ii_x_y_z], mGridData[ind[1][0][0]]); + cVals[24] = mGridData[ind[1][1][0]]; + cVals[25] = mGridData[ind[1][1][1]]; + cVals[26] = mGridData[ind[1][1][2]]; + cVals[27] = extrapolation(mGridData[ind[1][1][2]], mGridData[ind[1][1][1]], mGridData[ind[1][1][0]]); + cVals[28] = mGridData[ind[1][2][0]]; + cVals[29] = mGridData[ind[1][2][1]]; + cVals[30] = mGridData[ind[1][2][2]]; + cVals[31] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][2][1]], mGridData[ind[1][2][0]]); + cVals[32] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][1][0]], mGridData[ind[2][2][0]]); + cVals[33] = extrapolation(mGridData[ind[2][0][1]], mGridData[ind[2][1][1]], mGridData[ind[2][2][1]]); + cVals[34] = extrapolation(mGridData[ind[2][0][1]], mGridData[ind[2][1][0]], mGridData[ind[2][2][0] + deltaZ[i0]]); + cVals[35] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][1][1]], mGridData[ind[2][2][0]]); + cVals[36] = mGridData[ind[2][0][0]]; + cVals[37] = mGridData[ind[2][0][1]]; + cVals[38] = mGridData[ind[2][0][2]]; + cVals[39] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][0][1]], mGridData[ind[2][0][0]]); + cVals[40] = mGridData[ind[2][1][0]]; + cVals[41] = mGridData[ind[2][1][1]]; + cVals[42] = mGridData[ind[2][1][2]]; + cVals[43] = extrapolation(mGridData[ind[2][1][2]], mGridData[ind[2][1][1]], mGridData[ind[2][1][0]]); + cVals[44] = mGridData[ind[2][2][0]]; + cVals[45] = mGridData[ind[2][2][1]]; + cVals[46] = mGridData[ind[2][2][2]]; + cVals[47] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][2][1]], mGridData[ind[2][2][0]]); + cVals[48] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][1][0]], mGridData[ind[3][2][0]]); + cVals[49] = extrapolation(mGridData[ind[3][0][1]], mGridData[ind[3][1][1]], mGridData[ind[3][2][1]]); + cVals[50] = extrapolation(mGridData[ind[3][0][1]], mGridData[ind[3][1][0]], mGridData[ind[3][2][0] + deltaZ[i0]]); + cVals[51] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][1][1]], mGridData[ind[3][2][0]]); + cVals[52] = mGridData[ind[3][0][0]]; + cVals[53] = mGridData[ind[3][0][1]]; + cVals[54] = mGridData[ind[3][0][2]]; + cVals[55] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][0][1]], mGridData[ind[3][0][0]]); + cVals[56] = mGridData[ind[3][1][0]]; + cVals[57] = mGridData[ind[3][1][1]]; + cVals[58] = mGridData[ind[3][1][2]]; + cVals[59] = extrapolation(mGridData[ind[3][1][2]], mGridData[ind[3][1][1]], mGridData[ind[3][1][0]]); + cVals[60] = mGridData[ind[3][2][0]]; + cVals[61] = mGridData[ind[3][2][1]]; + cVals[62] = mGridData[ind[3][2][2]]; + cVals[63] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][2][1]], mGridData[ind[3][2][0]]); + } break; + + case GridPos::Edge2: + case GridPos::Edge6: + case GridPos::LineK: { + const int ind[4][3][3]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}}}; + + cVals[0] = extrapolation(mGridData[ind[0][0][0]], mGridData[ind[0][0][1]], mGridData[ind[0][0][2]]); + cVals[1] = mGridData[ind[0][0][0]]; + cVals[2] = mGridData[ind[0][0][1]]; + cVals[3] = mGridData[ind[0][0][2]]; + cVals[4] = extrapolation(mGridData[ind[0][1][0]], mGridData[ind[0][1][1]], mGridData[ind[0][1][2]]); + cVals[5] = mGridData[ind[0][1][0]]; + cVals[6] = mGridData[ind[0][1][1]]; + cVals[7] = mGridData[ind[0][1][2]]; + cVals[8] = extrapolation(mGridData[ind[0][1][0]], mGridData[ind[0][0][1]], mGridData[ind[0][0][2] + deltaR[i0]]); + cVals[9] = mGridData[ind[0][2][0]]; + cVals[10] = mGridData[ind[0][2][1]]; + cVals[11] = mGridData[ind[0][2][2]]; + cVals[12] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][1][1]], mGridData[ind[0][0][2]]); + cVals[13] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][1][0]], mGridData[ind[0][0][0]]); + cVals[14] = extrapolation(mGridData[ind[0][2][1]], mGridData[ind[0][1][1]], mGridData[ind[0][0][1]]); + cVals[15] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][1][2]], mGridData[ind[0][0][2]]); + cVals[16] = extrapolation(mGridData[ind[1][0][0]], mGridData[ind[1][0][1]], mGridData[ind[1][0][2]]); + cVals[17] = mGridData[ind[1][0][0]]; + cVals[18] = mGridData[ind[1][0][1]]; + cVals[19] = mGridData[ind[1][0][2]]; + cVals[20] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][1][1]], mGridData[ind[1][1][2]]); + cVals[22] = mGridData[ind[1][1][1]]; + cVals[23] = mGridData[ind[1][1][2]]; + cVals[24] = extrapolation(mGridData[ii_x_y_z], mGridData[ind[1][0][1]], mGridData[ind[1][0][2] + deltaR[i0]]); + cVals[25] = mGridData[ind[1][2][0]]; + cVals[26] = mGridData[ind[1][2][1]]; + cVals[27] = mGridData[ind[1][2][2]]; + cVals[28] = extrapolation(mGridData[ind[1][2][0]], mGridData[ind[1][1][1]], mGridData[ind[1][0][2]]); + cVals[29] = extrapolation(mGridData[ind[1][2][0]], mGridData[ii_x_y_z], mGridData[ind[1][0][0]]); + cVals[30] = extrapolation(mGridData[ind[1][2][1]], mGridData[ind[1][1][1]], mGridData[ind[1][0][1]]); + cVals[32] = extrapolation(mGridData[ind[2][0][0]], mGridData[ind[2][0][1]], mGridData[ind[2][0][2]]); + cVals[31] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][1][2]], mGridData[ind[1][0][2]]); + cVals[33] = mGridData[ind[2][0][0]]; + cVals[34] = mGridData[ind[2][0][1]]; + cVals[35] = mGridData[ind[2][0][2]]; + cVals[36] = extrapolation(mGridData[ind[2][1][0]], mGridData[ind[2][1][1]], mGridData[ind[2][1][2]]); + cVals[37] = mGridData[ind[2][1][0]]; + cVals[38] = mGridData[ind[2][1][1]]; + cVals[39] = mGridData[ind[2][1][2]]; + cVals[40] = extrapolation(mGridData[ind[2][1][0]], mGridData[ind[2][0][1]], mGridData[ind[2][0][2] + deltaR[i0]]); + cVals[41] = mGridData[ind[2][2][0]]; + cVals[42] = mGridData[ind[2][2][1]]; + cVals[43] = mGridData[ind[2][2][2]]; + cVals[44] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][1][1]], mGridData[ind[2][0][2]]); + cVals[45] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][1][0]], mGridData[ind[2][0][0]]); + cVals[46] = extrapolation(mGridData[ind[2][2][1]], mGridData[ind[2][1][1]], mGridData[ind[2][0][1]]); + cVals[47] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][1][2]], mGridData[ind[2][0][2]]); + cVals[48] = extrapolation(mGridData[ind[3][0][0]], mGridData[ind[3][0][1]], mGridData[ind[3][0][2]]); + cVals[49] = mGridData[ind[3][0][0]]; + cVals[50] = mGridData[ind[3][0][1]]; + cVals[51] = mGridData[ind[3][0][2]]; + cVals[52] = extrapolation(mGridData[ind[3][1][0]], mGridData[ind[3][1][1]], mGridData[ind[3][1][2]]); + cVals[53] = mGridData[ind[3][1][0]]; + cVals[54] = mGridData[ind[3][1][1]]; + cVals[55] = mGridData[ind[3][1][2]]; + cVals[56] = extrapolation(mGridData[ind[3][1][0]], mGridData[ind[3][0][1]], mGridData[ind[3][0][2] + deltaR[i0]]); + cVals[57] = mGridData[ind[3][2][0]]; + cVals[58] = mGridData[ind[3][2][1]]; + cVals[59] = mGridData[ind[3][2][2]]; + cVals[60] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][1][1]], mGridData[ind[3][0][2]]); + cVals[61] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][1][0]], mGridData[ind[3][0][0]]); + cVals[62] = extrapolation(mGridData[ind[3][2][1]], mGridData[ind[3][1][1]], mGridData[ind[3][0][1]]); + cVals[63] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][1][2]], mGridData[ind[3][0][2]]); + } break; + + case GridPos::Edge3: + case GridPos::Edge7: + case GridPos::LineL: { + const int ind[4][3][3]{ + {{ii_x_y_z + deltaPhi[i0] + deltaR[i0] + deltaZ[i0], ind[0][0][0] - deltaZ[i0], ind[0][0][1] - deltaZ[i0]}, + {ind[0][0][0] - deltaR[i0], ind[0][1][0] - deltaZ[i0], ind[0][1][1] - deltaZ[i0]}, + {ind[0][1][0] - deltaR[i0], ind[0][2][0] - deltaZ[i0], ind[0][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaR[i0] + deltaZ[i0], ind[1][0][0] - deltaZ[i0], ind[1][0][1] - deltaZ[i0]}, + {ind[1][0][0] - deltaR[i0], ind[1][1][0] - deltaZ[i0], ind[1][1][1] - deltaZ[i0]}, + {ind[1][1][0] - deltaR[i0], ind[1][2][0] - deltaZ[i0], ind[1][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i1] + deltaR[i0] + deltaZ[i0], ind[2][0][0] - deltaZ[i0], ind[2][0][1] - deltaZ[i0]}, + {ind[2][0][0] - deltaR[i0], ind[2][1][0] - deltaZ[i0], ind[2][1][1] - deltaZ[i0]}, + {ind[2][1][0] - deltaR[i0], ind[2][2][0] - deltaZ[i0], ind[2][2][1] - deltaZ[i0]}}, + {{ii_x_y_z + deltaPhi[i2] + deltaR[i0] + deltaZ[i0], ind[3][0][0] - deltaZ[i0], ind[3][0][1] - deltaZ[i0]}, + {ind[3][0][0] - deltaR[i0], ind[3][1][0] - deltaZ[i0], ind[3][1][1] - deltaZ[i0]}, + {ind[3][1][0] - deltaR[i0], ind[3][2][0] - deltaZ[i0], ind[3][2][1] - deltaZ[i0]}}}; + + cVals[0] = mGridData[ind[0][0][0]]; + cVals[1] = mGridData[ind[0][0][1]]; + cVals[2] = mGridData[ind[0][0][2]]; + cVals[3] = extrapolation(mGridData[ind[0][0][2]], mGridData[ind[0][0][1]], mGridData[ind[0][0][0]]); + cVals[4] = mGridData[ind[0][1][0]]; + cVals[5] = mGridData[ind[0][1][1]]; + cVals[6] = mGridData[ind[0][1][2]]; + cVals[7] = extrapolation(mGridData[ind[0][1][2]], mGridData[ind[0][1][1]], mGridData[ind[0][1][0]]); + cVals[8] = mGridData[ind[0][2][0]]; + cVals[9] = mGridData[ind[0][2][1]]; + cVals[10] = mGridData[ind[0][2][2]]; + cVals[11] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][2][1]], mGridData[ind[0][2][0]]); + cVals[12] = extrapolation(mGridData[ind[0][2][0]], mGridData[ind[0][1][0]], mGridData[ind[0][0][0]]); + cVals[13] = extrapolation(mGridData[ind[0][2][1]], mGridData[ind[0][1][1]], mGridData[ind[0][0][1]]); + cVals[14] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][1][2]], mGridData[ind[0][0][2]]); + cVals[15] = extrapolation(mGridData[ind[0][2][2]], mGridData[ind[0][1][1]], mGridData[ind[0][0][0]]); + cVals[16] = mGridData[ind[1][0][0]]; + cVals[17] = mGridData[ind[1][0][1]]; + cVals[18] = mGridData[ind[1][0][2]]; + cVals[19] = extrapolation(mGridData[ind[1][0][2]], mGridData[ind[1][0][1]], mGridData[ind[1][0][0]]); + cVals[20] = mGridData[ind[1][1][0]]; + cVals[22] = mGridData[ind[1][1][2]]; + cVals[23] = extrapolation(mGridData[ind[1][1][2]], mGridData[ii_x_y_z], mGridData[ind[1][1][0]]); + cVals[24] = mGridData[ind[1][2][0]]; + cVals[25] = mGridData[ind[1][2][1]]; + cVals[26] = mGridData[ind[1][2][2]]; + cVals[27] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][2][1]], mGridData[ind[1][2][0]]); + cVals[28] = extrapolation(mGridData[ind[1][2][0]], mGridData[ind[1][1][0]], mGridData[ind[1][0][0]]); + cVals[29] = extrapolation(mGridData[ind[1][2][1]], mGridData[ii_x_y_z], mGridData[ind[1][0][1]]); + cVals[30] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][1][2]], mGridData[ind[1][0][2]]); + cVals[31] = extrapolation(mGridData[ind[1][2][2]], mGridData[ind[1][1][1]], mGridData[ind[1][0][0]]); + cVals[32] = mGridData[ind[2][0][0]]; + cVals[33] = mGridData[ind[2][0][1]]; + cVals[34] = mGridData[ind[2][0][2]]; + cVals[35] = extrapolation(mGridData[ind[2][0][2]], mGridData[ind[2][0][1]], mGridData[ind[2][0][0]]); + cVals[36] = mGridData[ind[2][1][0]]; + cVals[37] = mGridData[ind[2][1][1]]; + cVals[38] = mGridData[ind[2][1][2]]; + cVals[39] = extrapolation(mGridData[ind[2][1][2]], mGridData[ind[2][1][1]], mGridData[ind[2][1][0]]); + cVals[40] = mGridData[ind[2][2][0]]; + cVals[41] = mGridData[ind[2][2][1]]; + cVals[42] = mGridData[ind[2][2][2]]; + cVals[43] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][2][1]], mGridData[ind[2][2][0]]); + cVals[44] = extrapolation(mGridData[ind[2][2][0]], mGridData[ind[2][1][0]], mGridData[ind[2][0][0]]); + cVals[45] = extrapolation(mGridData[ind[2][2][1]], mGridData[ind[2][1][1]], mGridData[ind[2][0][1]]); + cVals[46] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][1][2]], mGridData[ind[2][0][2]]); + cVals[47] = extrapolation(mGridData[ind[2][2][2]], mGridData[ind[2][1][1]], mGridData[ind[2][0][0]]); + cVals[48] = mGridData[ind[3][0][0]]; + cVals[49] = mGridData[ind[3][0][1]]; + cVals[50] = mGridData[ind[3][0][2]]; + cVals[51] = extrapolation(mGridData[ind[3][0][2]], mGridData[ind[3][0][1]], mGridData[ind[3][0][0]]); + cVals[52] = mGridData[ind[3][1][0]]; + cVals[53] = mGridData[ind[3][1][1]]; + cVals[54] = mGridData[ind[3][1][2]]; + cVals[55] = extrapolation(mGridData[ind[3][1][2]], mGridData[ind[3][1][1]], mGridData[ind[3][1][0]]); + cVals[56] = mGridData[ind[3][2][0]]; + cVals[57] = mGridData[ind[3][2][1]]; + cVals[58] = mGridData[ind[3][2][2]]; + cVals[59] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][2][1]], mGridData[ind[3][2][0]]); + cVals[60] = extrapolation(mGridData[ind[3][2][0]], mGridData[ind[3][1][0]], mGridData[ind[3][0][0]]); + cVals[61] = extrapolation(mGridData[ind[3][2][1]], mGridData[ind[3][1][1]], mGridData[ind[3][0][1]]); + cVals[62] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][1][2]], mGridData[ind[3][0][2]]); + cVals[63] = extrapolation(mGridData[ind[3][2][2]], mGridData[ind[3][1][1]], mGridData[ind[3][0][0]]); + } break; + } +} + +template class o2::tpc::TriCubicInterpolator<double>; +template class o2::tpc::TriCubicInterpolator<float>; diff --git a/Detectors/TPC/spacecharge/test/testO2TPCPoissonSolver.cxx b/Detectors/TPC/spacecharge/test/testO2TPCPoissonSolver.cxx new file mode 100644 index 0000000000000..b4a52ddd8b28b --- /dev/null +++ b/Detectors/TPC/spacecharge/test/testO2TPCPoissonSolver.cxx @@ -0,0 +1,255 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file testPoissonSolver.cxx +/// \brief this task tests the poisson solver +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#define BOOST_TEST_MODULE Test TPC O2TPCSpaceCharge3DCalc class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "TPCSpaceCharge/PoissonSolver.h" +#include "TPCSpaceCharge/SpaceChargeHelpers.h" +#include "TPCSpaceCharge/PoissonSolverHelpers.h" + +namespace o2 +{ +namespace tpc +{ + +using DataT = double; // using float actually takes alot longer than double (doesnt converge when using float) +static constexpr DataT TOLERANCE = 3; // relative tolerance for 3D (maximum large error is at phi=90 since there the potential is 0!) +static constexpr DataT TOLERANCE2D = 8.5; // relative tolerance for 2D TODO check why the difference between numerical and analyticial is larger than for 3D! +static constexpr DataT ABSTOLERANCE = 0.01; // absolute tolerance is taken at small values near 0 +static constexpr unsigned short NR = 65; // grid in r +static constexpr unsigned short NZ = 65; // grid in z +static constexpr unsigned short NPHI = 180; // grid in phi +static constexpr unsigned short NR2D = 129; // grid in r +static constexpr unsigned short NZ2D = 129; // grid in z +static constexpr unsigned short NPHI2D = 1; // grid in phi + +/// Get phi vertex position for index in phi direction +/// \param indexPhi index in phi direction +template <typename DataT> +DataT getPhiVertex(const size_t indexPhi, const o2::tpc::RegularGrid3D<DataT>& grid) +{ + return grid.getPhiVertex(indexPhi); +} + +/// Get r vertex position for index in r direction +/// \param indexR index in r direction +template <typename DataT> +DataT getRVertex(const size_t indexR, const o2::tpc::RegularGrid3D<DataT>& grid) +{ + return grid.getRVertex(indexR); +} + +/// Get z vertex position for index in z direction +/// \param indexZ index in z direction +template <typename DataT> +DataT getZVertex(const size_t indexZ, const o2::tpc::RegularGrid3D<DataT>& grid) +{ + return grid.getZVertex(indexZ); +} + +template <typename DataT> +void setChargeDensityFromFormula(const AnalyticalFields<DataT>& formulas, const o2::tpc::RegularGrid3D<DataT>& grid, o2::tpc::DataContainer3D<DataT>& density) +{ + for (size_t iPhi = 0; iPhi < density.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iR = 0; iR < density.getNR(); ++iR) { + const DataT radius = getRVertex<DataT>(iR, grid); + for (size_t iZ = 0; iZ < density.getNZ(); ++iZ) { + const DataT z = getZVertex<DataT>(iZ, grid); + density(iZ, iR, iPhi) = formulas.evalDensity(z, radius, phi); + } + } + } +} + +template <typename DataT> +void setPotentialFromFormula(const AnalyticalFields<DataT>& formulas, const o2::tpc::RegularGrid3D<DataT>& grid, o2::tpc::DataContainer3D<DataT>& potential) +{ + for (size_t iPhi = 0; iPhi < potential.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iR = 0; iR < potential.getNR(); ++iR) { + const DataT radius = getRVertex<DataT>(iR, grid); + for (size_t iZ = 0; iZ < potential.getNZ(); ++iZ) { + const DataT z = getZVertex<DataT>(iZ, grid); + potential(iZ, iR, iPhi) = formulas.evalPotential(z, radius, phi); + } + } + } +} + +template <typename DataT> +void setPotentialBoundaryFromFormula(const AnalyticalFields<DataT>& formulas, const o2::tpc::RegularGrid3D<DataT>& grid, o2::tpc::DataContainer3D<DataT>& potential) +{ + for (size_t iPhi = 0; iPhi < potential.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iZ = 0; iZ < potential.getNZ(); ++iZ) { + const DataT z = getZVertex<DataT>(iZ, grid); + const size_t iR = 0; + const DataT radius = getRVertex<DataT>(iR, grid); + potential(iZ, iR, iPhi) = formulas.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < potential.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iZ = 0; iZ < potential.getNZ(); ++iZ) { + const DataT z = getZVertex<DataT>(iZ, grid); + const size_t iR = potential.getNR() - 1; + const DataT radius = getRVertex<DataT>(iR, grid); + potential(iZ, iR, iPhi) = formulas.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < potential.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iR = 0; iR < potential.getNR(); ++iR) { + const DataT radius = getRVertex<DataT>(iR, grid); + const size_t iZ = 0; + const DataT z = getZVertex<DataT>(iZ, grid); + potential(iZ, iR, iPhi) = formulas.evalPotential(z, radius, phi); + } + } + + for (size_t iPhi = 0; iPhi < potential.getNPhi(); ++iPhi) { + const DataT phi = getPhiVertex<DataT>(iPhi, grid); + for (size_t iR = 0; iR < potential.getNR(); ++iR) { + const DataT radius = getRVertex<DataT>(iR, grid); + const size_t iZ = potential.getNZ() - 1; + const DataT z = getZVertex<DataT>(iZ, grid); + potential(iZ, iR, iPhi) = formulas.evalPotential(z, radius, phi); + } + } +} + +template <typename DataT> +void testAlmostEqualArray(o2::tpc::DataContainer3D<DataT>& analytical, o2::tpc::DataContainer3D<DataT>& numerical) +{ + for (size_t iPhi = 0; iPhi < numerical.getNPhi(); ++iPhi) { + for (size_t iR = 0; iR < numerical.getNR(); ++iR) { + for (size_t iZ = 0; iZ < numerical.getNZ(); ++iZ) { + if (std::fabs(analytical(iZ, iR, iPhi)) < ABSTOLERANCE) { + BOOST_CHECK_SMALL(numerical(iZ, iR, iPhi) - analytical(iZ, iR, iPhi), ABSTOLERANCE); + } else { + BOOST_CHECK_CLOSE(numerical(iZ, iR, iPhi), analytical(iZ, iR, iPhi), TOLERANCE); + } + } + } + } +} + +template <typename DataT> +void testAlmostEqualArray2D(o2::tpc::DataContainer3D<DataT>& analytical, o2::tpc::DataContainer3D<DataT>& numerical) +{ + for (size_t iPhi = 0; iPhi < numerical.getNPhi(); ++iPhi) { + for (size_t iR = 0; iR < numerical.getNR(); ++iR) { + for (size_t iZ = 0; iZ < numerical.getNZ(); ++iZ) { + if (std::fabs(analytical(iZ, iR, iPhi)) < ABSTOLERANCE) { + BOOST_CHECK_SMALL(numerical(iZ, iR, iPhi) - analytical(iZ, iR, iPhi), ABSTOLERANCE); + } else { + BOOST_CHECK_CLOSE(numerical(iZ, iR, iPhi), analytical(iZ, iR, iPhi), TOLERANCE2D); + } + } + } + } +} + +template <typename DataT> +void poissonSolver3D() +{ + using GridProp = GridProperties<DataT>; + const o2::tpc::RegularGrid3D<DataT> grid3D{GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, GridProp::getGridSpacingZ(NZ), GridProp::getGridSpacingR(NR), GridProp::getGridSpacingPhi(NPHI)}; + + using DataContainer = o2::tpc::DataContainer3D<DataT>; + DataContainer potentialNumerical(NZ, NR, NPHI); + DataContainer potentialAnalytical(NZ, NR, NPHI); + DataContainer charge(NZ, NR, NPHI); + + const o2::tpc::AnalyticalFields<DataT> analyticalFields; + // set the boudnary and charge for numerical poisson solver + setChargeDensityFromFormula<DataT>(analyticalFields, grid3D, charge); + setPotentialBoundaryFromFormula<DataT>(analyticalFields, grid3D, potentialNumerical); + + // set analytical potential + setPotentialFromFormula<DataT>(analyticalFields, grid3D, potentialAnalytical); + + //calculate numerical potential + PoissonSolver<DataT> poissonSolver(grid3D); + const int symmetry = 0; + poissonSolver.poissonSolver3D(potentialNumerical, charge, symmetry); + + // compare numerical with analytical solution of the potential + testAlmostEqualArray<DataT>(potentialAnalytical, potentialNumerical); +} + +template <typename DataT> +void poissonSolver2D() +{ + using GridProp = GridProperties<DataT>; + const o2::tpc::RegularGrid3D<DataT> grid3D{GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, GridProp::getGridSpacingZ(NZ2D), GridProp::getGridSpacingR(NR2D), GridProp::getGridSpacingPhi(NPHI2D)}; + + using DataContainer = o2::tpc::DataContainer3D<DataT>; + DataContainer potentialNumerical(NZ2D, NR2D, NPHI2D); + DataContainer potentialAnalytical(NZ2D, NR2D, NPHI2D); + DataContainer charge(NZ2D, NR2D, NPHI2D); + + // set the boudnary and charge for numerical poisson solver + const o2::tpc::AnalyticalFields<DataT> analyticalFields; + setChargeDensityFromFormula<DataT>(analyticalFields, grid3D, charge); + setPotentialBoundaryFromFormula<DataT>(analyticalFields, grid3D, potentialNumerical); + + // set analytical potential + setPotentialFromFormula<DataT>(analyticalFields, grid3D, potentialAnalytical); + + //calculate numerical potential + PoissonSolver<DataT> poissonSolver(grid3D); + poissonSolver.poissonSolver2D(potentialNumerical, charge); + + // compare numerical with analytical solution of the potential + testAlmostEqualArray2D<DataT>(potentialAnalytical, potentialNumerical); +} + +BOOST_AUTO_TEST_CASE(PoissonSolver3D_test) +{ + o2::tpc::MGParameters::isFull3D = true; //3D + + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NZVertices", NZ); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NRVertices", NR); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NPhiVertices", NPHI); + + poissonSolver3D<DataT>(); +} + +BOOST_AUTO_TEST_CASE(PoissonSolver3D2D_test) +{ + o2::tpc::MGParameters::isFull3D = false; // 3D2D + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NZVertices", NZ); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NRVertices", NR); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NPhiVertices", NPHI); + poissonSolver3D<DataT>(); +} + +BOOST_AUTO_TEST_CASE(PoissonSolver2D_test) +{ + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NZVertices", NZ2D); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NRVertices", NR2D); + o2::conf::ConfigurableParam::setValue<unsigned short>("TPCSpaceChargeParam", "NPhiVertices", NPHI2D); + poissonSolver2D<DataT>(); +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 9a7b53474aae2..6ccc0fc4c4c28 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -1,32 +1,58 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -# FIXME: do we really need a library here ? Is the exe not enough ? o2_add_library(TPCWorkflow SOURCES src/RecoWorkflow.cxx - src/PublisherSpec.cxx src/ClustererSpec.cxx src/ClusterDecoderRawSpec.cxx - src/CATrackerSpec.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx - src/TrackReaderSpec.cxx src/RawToDigitsSpec.cxx src/LinkZSToDigitsSpec.cxx - src/TPCSectorCompletionPolicy.cxx src/ZSSpec.cxx + src/CalibProcessingHelper.cxx + src/ClusterSharingMapSpec.cxx + src/CalDetMergerPublisherSpec.cxx + src/KryptonClustererSpec.cxx + src/IDCToVectorSpec.cxx + src/CalibdEdxSpec.cxx + src/MIPTrackFilterSpec.cxx + src/LaserTrackFilterSpec.cxx + src/ApplyCCDBCalibSpec.cxx + src/MonitorWorkflowSpec.cxx + src/ProcessingHelpers.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC O2::DPLUtils O2::TPCReconstruction - O2::TPCCalibration O2::TPCSimulation) + O2::TPCCalibration O2::TPCSimulation + O2::TPCQC O2::DetectorsCalibration + O2::TPCReaderWorkflow + O2::TPCMonitor + PRIVATE_LINK_LIBRARIES O2::GPUTracking # For the Zero Suppression includes + O2::GPUWorkflow + ) + + +o2_add_executable(chunkeddigit-merger + COMPONENT_NAME tpc + TARGETVARNAME mergertargetName + SOURCES src/ChunkedDigitPublisher.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +if(OpenMP_CXX_FOUND) + # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp + target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP) + target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX) +endif() + o2_add_executable(reco-workflow COMPONENT_NAME tpc @@ -38,6 +64,96 @@ o2_add_executable(raw-to-digits-workflow SOURCES src/tpc-raw-to-digits-workflow.cxx PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) +o2_add_executable(calib-pedestal + COMPONENT_NAME tpc + SOURCES src/tpc-calib-pedestal.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(laser-tracks-calibrator + COMPONENT_NAME tpc + SOURCES src/tpc-laser-tracks-calibrator.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(calib-laser-tracks + COMPONENT_NAME tpc + SOURCES src/tpc-calib-laser-tracks.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(laser-track-filter + COMPONENT_NAME tpc + SOURCES src/tpc-laser-track-filter.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(apply-ccdb-calib + COMPONENT_NAME tpc + SOURCES src/tpc-apply-ccdb-calib.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-integrate + COMPONENT_NAME tpc + SOURCES src/tpc-integrate-idc.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-averagegroup + COMPONENT_NAME tpc + SOURCES src/tpc-averagegroup-idc.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-distribute + COMPONENT_NAME tpc + SOURCES src/tpc-distribute-idc.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-ft-aggregator + COMPONENT_NAME tpc + SOURCES src/tpc-fouriertransform-aggregator.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-ft-epn + COMPONENT_NAME tpc + SOURCES src/tpc-fouriertransform-epn.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-factorize + COMPONENT_NAME tpc + SOURCES src/tpc-factorize-idc.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(track-reader + COMPONENT_NAME tpc + SOURCES src/TrackReaderWorkflow.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(file-reader + COMPONENT_NAME tpc + SOURCES src/FileReaderWorkflow.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(krypton-clusterer + COMPONENT_NAME tpc + SOURCES src/tpc-krypton-clusterer.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-to-vector + COMPONENT_NAME tpc + SOURCES src/tpc-idc-to-vector.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(calib-dedx + COMPONENT_NAME tpc + SOURCES src/tpc-calib-dEdx.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(idc-test-ft + COMPONENT_NAME tpc + SOURCES test/test_ft_EPN_Aggregator.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(miptrack-filter + COMPONENT_NAME tpc + SOURCES src/tpc-miptrack-filter.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + o2_add_test(workflow COMPONENT_NAME tpc LABELS tpc workflow @@ -45,8 +161,14 @@ o2_add_test(workflow PUBLIC_LINK_LIBRARIES O2::TPCWorkflow ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) -if(GPUCA_EVENT_DISPLAY OR - (OPENGL_FOUND AND GLFW_FOUND AND TARGET AliceO2::DebugGUI AND OPENGL_GLU_FOUND - AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")) - target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY) -endif() +o2_add_executable(digits-to-rawzs + COMPONENT_NAME tpc + PUBLIC_LINK_LIBRARIES O2::TPCBase O2::SimulationDataFormat O2::GPUO2Interface O2::GPUTracking O2::DetectorsRaw + SOURCES src/convertDigitsToRawZS.cxx) + +o2_add_executable(monitor-workflow + COMPONENT_NAME tpc + SOURCES src/tpc-monitor-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +add_subdirectory(readers) diff --git a/Detectors/TPC/workflow/README.md b/Detectors/TPC/workflow/README.md index a7210e008e46c..e34faa2813edf 100644 --- a/Detectors/TPC/workflow/README.md +++ b/Detectors/TPC/workflow/README.md @@ -18,7 +18,7 @@ The workflow consists of the following DPL processors: * `tpc-digit-reader` -> using tool [o2::framework::RootTreeReader](../../../Framework/Utils/include/Utils/RootTreeReader.h) * `tpc-clusterer` -> interfaces [o2::tpc::HwClusterer](../reconstruction/include/TPCReconstruction/HwClusterer.h) * `tpc-cluster-decoder` -> interfaces [o2::tpc::HardwareClusterDecoder](../reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h) -* `tpc-tracker` -> interfaces [o2::tpc::GPUCATracking](../reconstruction/include/TPCReconstruction/GPUCATracking.h) +* `gpu-reconstruction` -> interfaces [o2::tpc::GPUCATracking](../reconstruction/include/TPCReconstruction/GPUCATracking.h) * `tpc-track-writer` -> implements simple writing to ROOT file Depending on the input and output types the default workflow is extended by the following readers and writers: @@ -146,3 +146,131 @@ bz= magnetic field * implement configuration from the GRP ## Open questions + +## Calibration workflows + +### Pedestal calibration +#### Options +```bash +--direct-file-dump write final calibration to local root file +--max-events maximum number of events to process +--no-write-ccdb don't send the calibration data via DPL (required in case the calibration write is not attached) +--use-old-subspec use old subspec definition (CruId << 16) | ((LinkId + 1) << (CruEndPoint == 1 ? 8 : 0)) +--lanes arg (=1) number of parallel processes +--sectors arg (=0-35) list of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15 +``` + +#### Running with data distribution +In one shell start the data distribution playback, e.g. +```bash +StfBuilder --id builder --data-source-enable --data-source-dir=2020-11-11T14_18_25Z --data-source-rate=100 --dpl-channel-name=dpl-chan --channel-config "name=dpl-chan,type=pair,method=connect,address=ipc:///tmp/stf-builder-dpl-pipe-0,transport=zeromq,rateLogging=1" +``` + +In another shell start the pedestal calibration +```bash +o2-dpl-raw-proxy -b --dataspec "A:TPC/RAWDATA" --channel-config "name=readout-proxy,type=pair,method=bind,address=ipc:///tmp/stf-builder-dpl-pipe-0,transport=zeromq,rateLogging=1" \ +| o2-tpc-calib-pedestal --max-events 5 --direct-file-dump --shm-segment-size $((8<<30)) --no-calib-output --use-old-subspec +``` + +#### Running with raw file playback +Create a raw-reader.cfg e.g. +```bash +i=0; echo -e "[defaults]\ndataOrigin = TPC\ndataDescription = RAWDATA\n" > raw-reader.cfg; echo; for file in *.raw; do echo "[input-$i]"; echo "dataOrigin = TPC"; echo "dataDescription = RAWDATA"; echo "filePath=$file"; echo; i=$((i+1)); done >> raw-reader.cfg +``` + +Then run +```bash +o2-raw-file-reader-workflow --input-conf raw-reader.cfg --nocheck-hbf-per-tf --nocheck-hbf-jump --shm-segment-size $((8<<30)) \ +| o2-tpc-calib-pedestal --max-events 5 --direct-file-dump --shm-segment-size $((8<<30)) --no-calib-output +``` + +#### Send data to CCDB +Remove the `--no-write-ccdb` option and add +```bash +| o2-calibration-ccdb-populator-workflow +``` + +### Laser track calibration +#### Laser track filter +`o2-tpc-laser-track-filter` filters `TPC/TRACKS` looking for laser track candidates. The output is provided as `TPC/LASERTRACKS`. +With the option `--enable-writer`, the filtere tracks can be writte to file (`tpc-laser-tracks.root`). + +#### linear workflow reading from a local track file, direclty running the calibration component +By default `o2-tpc-calib-laser-tracks` assumes non-filtered `TPC/TRACKS` as input. +Using the option `--use-filtered-tracks` the input `TPC/LASERTRACKS` will be used. + +**running without laser track filter** +```bash +o2-tpc-file-reader --input-type tracks --disable-mc --tpc-track-reader '--infile tpctracks.root' \ + | o2-tpc-calib-laser-tracks --write-debug +``` + +**running with laser track filter** +```bash +o2-tpc-file-reader --input-type tracks --disable-mc --tpc-track-reader '--infile tpctracks.root' \ + | o2-tpc-laser-track-filter \ + | o2-tpc-calib-laser-tracks --use-filtered-tracks --write-debug --run +``` + +#### linear workflow reading from a local track file, running with time slot calibration +The time slot calibration assumes as input prefiltered laser track candates (`o2-tpc-laser-track-filter`). +They are published as `TPC/LASERTRACKS`. + +##### Options + --tf-per-slot arg (=5000) number of TFs per calibration time slot + --max-delay arg (=3) number of slots in past to consider + --min-entries arg (=100) minimum number of TFs with at least 50 tracks on each sideto finalize a slot + so 100 means 5000 matched laser tracks on each side. + --write-debug write a debug output tree. + +```bash +o2-tpc-file-reader --input-type tracks --disable-mc --tpc-track-reader '--infile tpctracks.root' \ + | o2-tpc-laser-track-filter \ + | o2-tpc-laser-tracks-calibrator --write-debug --min-entries 100 --tf-per-slot 5000 --run +``` + +#### simple distributed workflow with output and input proxy, running with time slot calibration +**Sending side zeromq** +```bash +o2-tpc-file-reader --input-type tracks --disable-mc --tpc-track-reader '--infile tpctracks.root' \ + | o2-tpc-laser-track-filter \ + | o2-dpl-output-proxy --channel-config "name=downstream,method=connect,address=tcp://localhost:30453,type=push,transport=zeromq" --dataspec lasertracks:TPC/LASERTRACKS -b --run +``` + +**Receeving side zeromq** +```bash +o2-dpl-raw-proxy --dataspec lasertracks:TPC/LASERTRACKS/0 --channel-config "name=readout-proxy,type=pull,method=bind,address=tcp://localhost:30453,rateLogging=1,transport=zeromq" \ + | o2-tpc-laser-tracks-calibrator --write-debug --min-entries 100 --tf-per-slot 5000 --run +``` + +**Sending side shmem** +```bash +ARGS_ALL="--session tpc-laser-tracks -b" +o2-tpc-file-reader $ARGS_ALL --input-type tracks --disable-mc --tpc-track-reader '--infile tpctracks.root' \ + | o2-tpc-laser-track-filter $ARGS_ALL \ + | o2-dpl-output-proxy $ARGS_ALL --channel-config "name=downstream,type=push,method=bind,address=ipc://@tpc-laser-tracks-0,transport=shmem,rateLogging=1" --dataspec lasertracks:TPC/LASERTRACKS \ + | o2-dpl-run $ARGS_ALL --run + +``` + +**Receeving side shmem** +```bash +ARGS_ALL="--session tpc-laser-tracks -b" +o2-dpl-raw-proxy $ARGS_ALL --dataspec lasertracks:TPC/LASERTRACKS/0 --channel-config "name=readout-proxy,type=pull,method=connect,address=ipc://@tpc-laser-tracks-0,transport=shmem,rateLogging=1" \ + | o2-tpc-laser-tracks-calibrator $ARGS_ALL --write-debug --min-entries 100 --tf-per-slot 5000 \ + | o2-dpl-run $ARGS_ALL --run +``` + +## Running the recontruction on GBT raw data +This requires to do zero suppression in the first stage. For this the `DigiDump` class is used, wrapped in an o2 workflow. + +Use either the [DD](#running-with-data-distribution) part or [raw file playback](#running-with-raw-file-playback) from above and add as processor +```bash +| o2-tpc-raw-to-digits-workflow --pedestal-file pedestals.root --configKeyValues "TPCDigitDump.ADCMin=3;TPCDigitDump.NoiseThreshold=3" \ +| o2-tpc-reco-workflow --input-type digitizer --output-type tracks --disable-mc +``` + +To directly dump the digits to file for inspection use for the reco workflow +```bash +| o2-tpc-reco-workflow --input-type digitizer --output-type digits --disable-mc +``` diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ApplyCCDBCalibSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ApplyCCDBCalibSpec.h new file mode 100644 index 0000000000000..d87d176c1232f --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ApplyCCDBCalibSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_ApplyCCDBCalibSpec_H +#define O2_TPC_ApplyCCDBCalibSpec_H + +/// @file ApplyCCDBCalibSpec.h +/// @brief Device to apply calibrations loaded from CCDB + +namespace o2::framework +{ +struct DataProcessorSpec; +} // namespace o2::framework + +namespace o2::tpc +{ +o2::framework::DataProcessorSpec getApplyCCDBCalibSpec(); +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h deleted file mode 100644 index 8f2195dc9eecc..0000000000000 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CATrackerSpec.h -/// @author Matthias Richter -/// @since 2018-04-18 -/// @brief Processor spec for running TPC CA tracking - -#include "Framework/DataProcessorSpec.h" -#include "RecoWorkflow.h" -#include <utility> // std::forward - -namespace o2 -{ -namespace framework -{ -struct CompletionPolicy; -} - -namespace tpc -{ - -namespace ca -{ -// The CA tracker is now a wrapper to not only the actual tracking on GPU but -// also the decoding of the zero-suppressed raw format and the clusterer. -enum struct Operation { - DecompressTPC, // run cluster decompressor - DecompressTPCFromROOT, // the cluster decompressor input is a root object not flat - CAClusterer, // run the CA clusterer - ZSDecoder, // run the ZS raw data decoder - ZSOnTheFly, // use zs on the fly - OutputTracks, // publish tracks - OutputCAClusters, // publish the clusters produced by CA clusterer - OutputCompClusters, // publish CompClusters container - OutputCompClustersFlat, // publish CompClusters container - OutputQA, // Ship QA histograms to QC - ProcessMC, // process MC labels - SendClustersPerSector, // Send clusters and clusters mc labels per sector - Noop, // skip argument on the constructor -}; - -/// Helper struct to pass the individual ca::Operation flags to -/// the processor spec. The struct is initialized by a variable list of -/// constructor arguments. -struct Config { - Config(const Config&) = default; - template <typename... Args> - Config(Args&&... args) - { - init(std::forward<Args>(args)...); - } - - template <typename... Args> - void init(Operation const& op, Args&&... args) - { - switch (op) { - case Operation::DecompressTPC: - decompressTPC = true; - break; - case Operation::DecompressTPCFromROOT: - decompressTPCFromROOT = true; - break; - case Operation::CAClusterer: - caClusterer = true; - break; - case Operation::ZSDecoder: - zsDecoder = true; - break; - case Operation::ZSOnTheFly: - zsOnTheFly = true; - break; - case Operation::OutputTracks: - outputTracks = true; - break; - case Operation::OutputCompClusters: - outputCompClusters = true; - break; - case Operation::OutputCompClustersFlat: - outputCompClustersFlat = true; - break; - case Operation::OutputCAClusters: - outputCAClusters = true; - break; - case Operation::OutputQA: - outputQA = true; - break; - case Operation::ProcessMC: - processMC = true; - break; - case Operation::SendClustersPerSector: - sendClustersPerSector = true; - break; - case Operation::Noop: - break; - default: - throw std::runtime_error("invalid CATracker operation"); - } - if constexpr (sizeof...(args) > 0) { - init(std::forward<Args>(args)...); - } - } - - // Cannot specialize constructor to create proper copy constructor directly --> must overload init - void init(const Config& x) { *this = x; } - - bool decompressTPC = false; - bool decompressTPCFromROOT = false; - bool caClusterer = false; - bool zsDecoder = false; - bool zsOnTheFly = false; - bool outputTracks = false; - bool outputCompClusters = false; - bool outputCompClustersFlat = false; - bool outputCAClusters = false; - bool outputQA = false; - bool processMC = false; - bool sendClustersPerSector = false; -}; - -} // namespace ca - -/// create a processor spec for the CATracker -/// The CA tracker is actually much more than the tracker it has evolved to a -/// general interface processor for TPC GPU algorithms. This includes currently -/// decoding of zero-suppressed raw data, ca clusterer and ca tracking. The input -/// is chosen depending on the mode. -/// -/// The input specs are created depending on the list of tpc sectors, with separate -/// routes per sector. If the processor is also runnig the clusterer and cluster -/// output is enabled, the outputs are created based on the list of TPC sectors. -/// -/// The individual operations of the CA processor can be switched using enum -/// @ca::Operations, a configuration object @a ca::Config is used to pass the -/// configuration to the processor spec. -/// -/// @param specconfig configuration options for the processor spec -/// @param tpcsectors list of sector numbers -framework::DataProcessorSpec getCATrackerSpec(o2::tpc::reco_workflow::CompletionPolicyData* policyData, ca::Config const& specconfig, std::vector<int> const& tpcsectors); - -o2::framework::CompletionPolicy getCATrackerCompletionPolicy(); -} // end namespace tpc -} // end namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h new file mode 100644 index 0000000000000..9d365700582b3 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_CalDetMergerPublisherSpec_H +#define O2_TPC_CalDetMergerPublisherSpec_H + +/// @file CalDetMergerPublisherSpec.h +/// @brief TPC CalDet merger and CCDB publisher +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getCalDetMergerPublisherSpec(uint32_t lanes, bool skipCCDB, bool dumpAfterComplete = false); + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h new file mode 100644 index 0000000000000..6b56d3be2ea2b --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h @@ -0,0 +1,147 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_CalibLaserTracksSpec_H +#define O2_TPC_CalibLaserTracksSpec_H + +/// @file CalibLaserTracksSpec.h +/// @brief Device to run tpc laser track calibration + +#include "TPCCalibration/CalibLaserTracks.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +#include "TPCWorkflow/ProcessingHelpers.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class CalibLaserTracksDevice : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + mCalib.setWriteDebugTree(ic.options().get<bool>("write-debug")); + mMinNumberTFs = ic.options().get<int>("min-tfs"); + mOnlyPublishOnEOS = ic.options().get<bool>("only-publish-on-eos"); + + auto finishFunction = [this]() { + if (!mPublished) { + const auto nTFs = mCalib.getCalibData().processedTFs; + const auto nMatchA = mCalib.getMatchedPairsA(); + const auto nMatchC = mCalib.getMatchedPairsC(); + LOGP(error, "Calibration data was not published, laser track calibration might have enough statistics: {} ({}) matched tracks in {} TFs on the A (C) < {} min TFs * {} min matches per side per TF ", nMatchA, nMatchC, nTFs, mMinNumberTFs, CalibLaserTracks::MinTrackPerSidePerTF); + } + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishFunction); + } + + void run(o2::framework::ProcessingContext& pc) final + { + const auto dph = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header); + const auto startTime = dph->startTime; + const auto endTime = dph->startTime + dph->duration; + mRunNumber = processing_helpers::getRunNumber(pc); + + auto data = pc.inputs().get<gsl::span<TrackTPC>>("input"); + mCalib.setTFtimes(startTime, endTime); + mCalib.fill(data); + + if (!mOnlyPublishOnEOS && mCalib.hasEnoughData(mMinNumberTFs) && !mPublished) { + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "CalibLaserTracksDevice::endOfStream: Finalizing calibration"); + if (!mCalib.hasEnoughData(mMinNumberTFs)) { + const auto nTFs = mCalib.getCalibData().processedTFs; + const auto nMatchA = mCalib.getMatchedPairsA(); + const auto nMatchC = mCalib.getMatchedPairsC(); + LOGP(warning, "laser track calibration does not have enough statistics: {} ({}) matched tracks in {} TFs on the A (C) < {} min TFs * {} min matches per side per TF ", nMatchA, nMatchC, nTFs, mMinNumberTFs, CalibLaserTracks::MinTrackPerSidePerTF); + } + sendOutput(ec.outputs()); + } + + private: + CalibLaserTracks mCalib; ///< laser track calibration component + uint64_t mRunNumber{0}; ///< processed run number + int mMinNumberTFs{100}; ///< minimum number of TFs required for good calibration + bool mPublished{false}; ///< if calibration was already published + bool mOnlyPublishOnEOS{false}; ///< if to only publish the calibration on EOS, not during running + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + mCalib.finalize(); + mCalib.print(); + + std::map<std::string, std::string> md; + + using clbUtils = o2::calibration::Utils; + const auto& ltrCalib = mCalib.getCalibData(); + + o2::ccdb::CcdbObjectInfo w; + auto image = o2::ccdb::CcdbApi::createObjectImage(<rCalib, &w); + + md = w.getMetaData(); + md["runNumber"] = std::to_string(mRunNumber); + + const auto now = std::chrono::system_clock::now(); + const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); + //const auto timeStart = ltrCalib.firstTime; //TODO: use once it is a correct time not TFid + const long timeEnd = 99999999999999; + + w.setPath("TPC/Calib/LaserTracks"); + w.setStartValidityTimestamp(timeStart); + w.setEndValidityTimestamp(timeEnd); + + LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {} ", w.getPath(), w.getFileName(), image->size(), w.getStartValidityTimestamp(), w.getEndValidityTimestamp()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibLtr", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibLtr", 0}, w); + + mPublished = true; + } +}; + +DataProcessorSpec getCalibLaserTracks(const std::string inputSpec) +{ + using device = o2::tpc::CalibLaserTracksDevice; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{"TPC", "LtrCalibData"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibLtr"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibLtr"}); + + return DataProcessorSpec{ + "tpc-calib-laser-tracks", + select(inputSpec.data()), + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"write-debug", VariantType::Bool, false, {"write a debug output tree."}}, + {"min-tfs", VariantType::Int, 100, {"minimum number of TFs with enough laser tracks to finalize the calibration."}}, + {"only-publish-on-eos", VariantType::Bool, false, {"only publish the calibration on eos, not during running"}}, + }}; +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h new file mode 100644 index 0000000000000..e324478fa87bb --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_CalibProcessingHelper_H +#define O2_TPC_CalibProcessingHelper_H + +#include <memory> + +#include "Framework/InputRecord.h" + +using o2::tpc::rawreader::RawReaderCRU; + +namespace o2 +{ +namespace tpc +{ +namespace rawreader +{ +class RawReaderCRU; +} +namespace calib_processing_helper +{ + +uint64_t processRawData(o2::framework::InputRecord& inputs, std::unique_ptr<RawReaderCRU>& reader, bool useOldSubspec = false, const std::vector<int>& sectors = {}, size_t* nerrors = nullptr); +} // namespace calib_processing_helper +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h new file mode 100644 index 0000000000000..290bfbc558f8f --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibdEdxSpec.h +/// \brief Workflow for time based dE/dx calibration. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#ifndef O2_TPC_TPCCALIBDEDXSPEC_H_ +#define O2_TPC_TPCCALIBDEDXSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +/// create a processor spec +o2::framework::DataProcessorSpec getCalibdEdxSpec(); + +} // namespace o2::tpc + +#endif // O2_TPC_TPCCALIBDEDXSPEC_H_ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ClusterDecoderRawSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterDecoderRawSpec.h index dc30bfe4f22b4..f1fb0be5ceae5 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/ClusterDecoderRawSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterDecoderRawSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h new file mode 100644 index 0000000000000..1bade0eec9c4d --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterSharingMapSpec.h +/// @brief Device to produce TPC clusters sharing map +/// \author ruben.shahoyan@cern.ch + +#ifndef O2_TPC_CLUSTERSHARINGMAP_SPEC +#define O2_TPC_CLUSTERSHARINGMAP_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace tpc +{ + +class ClusterSharingMapSpec : public o2::framework::Task +{ + public: + ~ClusterSharingMapSpec() override = default; + void run(framework::ProcessingContext& pc) final; +}; + +o2::framework::DataProcessorSpec getClusterSharingMapSpec() +{ + + std::vector<o2::framework::InputSpec> inputs; + std::vector<o2::framework::OutputSpec> outputs; + inputs.emplace_back("trackTPC", "TPC", "TRACKS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("trackTPCClRefs", "TPC", "CLUSREFS", 0, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("clusTPC", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("TPC", "CLSHAREDMAP", 0, o2::framework::Lifetime::Timeframe); + + return o2::framework::DataProcessorSpec{ + "tpc-clusters-sharing-map-producer", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<ClusterSharingMapSpec>()}, + o2::framework::Options{}}; +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ClustererSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ClustererSpec.h index c56324ff14ab4..7ef24528bb651 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/ClustererSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ClustererSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h index f4f7c2d146ebb..fcd4017e9d8be 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h index 50da4378372ca..3425da02686d0 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/IDCToVectorSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/IDCToVectorSpec.h new file mode 100644 index 0000000000000..635570ae6db38 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/IDCToVectorSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file IDCToVectorSpec.h +/// @author Jens Wiechula +/// @brief Processor to convert IDCs to a vector for each pad in a CRU + +#ifndef TPC_IDCToVectorSpec_H_ +#define TPC_IDCToVectorSpec_H_ + +#include "Framework/DataProcessorSpec.h" +#include <string_view> + +namespace o2::tpc +{ + +/// create a processor spec +/// convert IDC raw values to a vector for each pad in a CRU +o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec, std::vector<uint32_t> const& crus); + +} // end namespace o2::tpc + +#endif //TPC_IDCToVectorSpec_H_ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/KryptonClustererSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/KryptonClustererSpec.h new file mode 100644 index 0000000000000..1bcea33375975 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/KryptonClustererSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawToDigitsSpec.h +/// @author Jens Wiechula +/// @since 2021-02-26 +/// @brief Processor spec for running TPC Krypton cluster finder + +#ifndef TPC_KryptonClustererSpec_H_ +#define TPC_KryptonClustererSpec_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +/// create a processor spec +/// read simulated TPC clusters from file and publish +o2::framework::DataProcessorSpec getKryptonClustererSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif // TPC_RAWTODIGITSSPEC_H_ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/LaserTrackFilterSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTrackFilterSpec.h new file mode 100644 index 0000000000000..63089ef4b0f67 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTrackFilterSpec.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_LaserTrackFilterSpec_H +#define O2_TPC_LaserTrackFilterSpec_H + +/// @file LaserTrackFilterSpec.h +/// @brief Device to filter out laser tracks + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +DataProcessorSpec getLaserTrackFilter(); + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h new file mode 100644 index 0000000000000..6788ba726a85a --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_LaserTracksCalibratorSpec_H +#define O2_TPC_LaserTracksCalibratorSpec_H + +/// @file LaserTracksCalibratorSpec.h +/// @brief Device to run tpc laser track calibration + +#include "TPCCalibration/LaserTracksCalibrator.h" +#include "DetectorsCalibration/Utils.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class LaserTracksCalibratorDevice : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + const int minTFs = ic.options().get<int>("min-tfs"); + const int slotL = ic.options().get<int>("tf-per-slot"); + const int delay = ic.options().get<int>("max-delay"); + const bool debug = ic.options().get<bool>("write-debug"); + + mCalibrator = std::make_unique<LaserTracksCalibrator>(minTFs); + mCalibrator->setSlotLength(slotL); + mCalibrator->setMaxSlotsDelay(delay); + mCalibrator->setWriteDebug(debug); + } + + void run(o2::framework::ProcessingContext& pc) final + { + const auto dph = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("laserTracks").header); + const auto startTime = dph->startTime; + const auto endTime = dph->startTime + dph->duration - 1; + + auto data = pc.inputs().get<gsl::span<TrackTPC>>("laserTracks"); + LOGP(info, "Processing TF with start time {} and {} tracks", startTime, data.size()); + + mCalibrator->getSlotForTF(startTime).getContainer()->setTFtimes(startTime, endTime); + mCalibrator->process(startTime, data); + + if (mCalibrator->hasCalibrationData()) { + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "LaserTracksCalibratorDevice::endOfStream: Finalizing calibration"); + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<LaserTracksCalibrator> mCalibrator; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + using clbUtils = o2::calibration::Utils; + const auto& calibrations = mCalibrator->getCalibPerSlot(); + const long timeEnd = 99999999999999; + for (uint32_t iCalib = 0; iCalib < calibrations.size(); ++iCalib) { + const auto& object = calibrations[iCalib]; + o2::ccdb::CcdbObjectInfo w; + auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &w); + + w.setPath("TPC/Calib/LaserTracks"); + w.setStartValidityTimestamp(object.firstTime); + //w.setEndValidityTimestamp(object.lastTime); + w.setEndValidityTimestamp(timeEnd); + + LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {} ", w.getPath(), w.getFileName(), image->size(), w.getStartValidityTimestamp(), w.getEndValidityTimestamp()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibLtr", iCalib}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibLtr", iCalib}, w); + } + mCalibrator->initOutput(); + } +}; + +DataProcessorSpec getLaserTracksCalibrator() +{ + using device = o2::tpc::LaserTracksCalibratorDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibLtr"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibLtr"}); + return DataProcessorSpec{ + "tpc-laser-tracks-calibrator", + Inputs{{"laserTracks", "TPC", "LASERTRACKS"}}, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"tf-per-slot", VariantType::Int, 5000, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int, 3, {"number of slots in past to consider"}}, + {"min-tfs", VariantType::Int, 100, {"minimum number of TFs with enough laser tracks to finalize a slot"}}, + {"write-debug", VariantType::Bool, false, {"write a debug output tree."}}, + }}; +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/LinkZSToDigitsSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/LinkZSToDigitsSpec.h index b3439d3f21861..1b9e3fefe77ea 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/LinkZSToDigitsSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/LinkZSToDigitsSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/MIPTrackFilterSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/MIPTrackFilterSpec.h new file mode 100644 index 0000000000000..05024baad37b3 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/MIPTrackFilterSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIPTrackFilterSpec.h +/// \brief Workflow to filter MIP tracks and streams them to other devices. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#ifndef O2_TPC_MIPTRACKFILTERSPEC_H_ +#define O2_TPC_MIPTRACKFILTERSPEC_H_ + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +/// create a processor spec +o2::framework::DataProcessorSpec getMIPTrackFilterSpec(); + +} // namespace o2::tpc + +#endif // O2_TPC_MIPTRACKFILTERSPEC_H_ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/MonitorWorkflowSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/MonitorWorkflowSpec.h new file mode 100644 index 0000000000000..4f7fd58260d95 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/MonitorWorkflowSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file MonitorWorkflowSpec.h +/// @author Jens Wiechula +/// @since 2020-01-17 +/// @brief Raw data monitor workflow + +#ifndef TPC_MonitorWorkflowSpec_H_ +#define TPC_MonitorWorkflowSpec_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2::tpc +{ + +/// create a processor spec +/// read simulated TPC clusters from file and publish +o2::framework::DataProcessorSpec getMonitorWorkflowSpec(bool useDigitsAsInput); + +} // namespace o2::tpc + +#endif // TPC_MonitorWorkflowSpec_H_ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ProcessingHelpers.h b/Detectors/TPC/workflow/include/TPCWorkflow/ProcessingHelpers.h new file mode 100644 index 0000000000000..24772ae6b7ee0 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ProcessingHelpers.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +namespace o2::framework +{ +class ProcessingContext; +} + +namespace o2::tpc +{ +namespace processing_helpers +{ + +uint64_t getRunNumber(o2::framework::ProcessingContext& pc); + +} +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/PublisherSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/PublisherSpec.h deleted file mode 100644 index 8a1673977d7f9..0000000000000 --- a/Detectors/TPC/workflow/include/TPCWorkflow/PublisherSpec.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReaderSpec.h -/// @author Matthias Richter -/// @since 2018-12-06 -/// @brief Processor spec for a reader of TPC data from ROOT file - -#include "Framework/DataProcessorSpec.h" -#include "Framework/OutputSpec.h" -#include "Framework/DataSpecUtils.h" -#include "Framework/Output.h" -#include "DPLUtils/RootTreeReader.h" -#include <vector> -#include <string> -#include <functional> - -namespace o2 -{ -namespace tpc -{ - -using OutputSpec = framework::OutputSpec; -using Reader = o2::framework::RootTreeReader; - -struct PublisherConf { - struct BranchOptionConfig { - std::string option; - std::string defval; - std::string help; - }; - - std::string processName; - std::string defaultTreeName; - BranchOptionConfig databranch; - BranchOptionConfig mcbranch; - OutputSpec dataoutput; - OutputSpec mcoutput; - std::vector<int> tpcSectors; - std::vector<int> outputIds; - Reader::SpecialPublishHook* hook = nullptr; -}; - -/// create a processor spec -/// read data from multiple tree branches from ROOT file and publish -template <typename T = void> -framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true) -{ - using Reader = o2::framework::RootTreeReader; - using Output = o2::framework::Output; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - - // a creator callback for the actual reader instance - auto creator = [dto, mco, propagateMC](const char* treename, const char* filename, int nofEvents, Reader::PublishingMode publishingMode, o2::header::DataHeader::SubSpecificationType subSpec, const char* branchname, const char* mcbranchname, Reader::SpecialPublishHook* publishhook = nullptr) { - constexpr auto persistency = o2::framework::Lifetime::Timeframe; - if (propagateMC) { - return std::make_shared<Reader>(treename, - filename, - nofEvents, - publishingMode, - Output{mco.origin, mco.description, subSpec, persistency}, - mcbranchname, - Reader::BranchDefinition<T>{Output{dto.origin, dto.description, subSpec, persistency}, branchname}, - publishhook); - } else { - return std::make_shared<Reader>(treename, - filename, - nofEvents, - publishingMode, - Reader::BranchDefinition<T>{Output{dto.origin, dto.description, subSpec, persistency}, branchname}, - publishhook); - } - }; - - return createPublisherSpec(config, propagateMC, creator); -} - -namespace workflow_reader -{ -using Reader = o2::framework::RootTreeReader; -using Creator = std::function<std::shared_ptr<Reader>(const char*, const char*, int, Reader::PublishingMode, o2::header::DataHeader::SubSpecificationType, const char*, const char*, Reader::SpecialPublishHook*)>; -} // namespace workflow_reader - -framework::DataProcessorSpec createPublisherSpec(PublisherConf const& config, bool propagateMC, workflow_reader::Creator creator); - -} // end namespace tpc -} // end namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RawToDigitsSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/RawToDigitsSpec.h index c0e1703ee632f..4cb76f8baa61a 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RawToDigitsSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RawToDigitsSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,7 @@ namespace tpc /// create a processor spec /// read simulated TPC clusters from file and publish -o2::framework::DataProcessorSpec getRawToDigitsSpec(int channel, const std::string_view inputDef, std::vector<int> const& tpcSectors); +o2::framework::DataProcessorSpec getRawToDigitsSpec(int channel, const std::string inputSpec, std::vector<int> const& tpcSectors); } // end namespace tpc } // end namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h index d4140736b0985..5c23bf3f8e8d3 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,6 +40,7 @@ enum struct InputType { Digitizer, // directly read digits from channel { Clusters, // read native clusters from file CompClusters, // read compressed cluster container CompClustersCTF, // compressed clusters from CTF, as flat format + CompClustersFlat, // compressed clusters in flat format, used as input for the entropy encoder EncodedClusters, // read encoded clusters ZSRaw, }; @@ -61,6 +63,7 @@ enum struct OutputType { Digits, SendClustersPerSector, ZSRaw, QA, + NoSharedClusterMap, }; using CompletionPolicyData = std::vector<framework::InputSpec>; @@ -68,45 +71,15 @@ using CompletionPolicyData = std::vector<framework::InputSpec>; /// create the workflow for TPC reconstruction framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, // std::vector<int> const& tpcSectors, // + unsigned long tpcSectorMask, // std::vector<int> const& laneConfiguration, // bool propagateMC = true, unsigned nLanes = 1, // std::string const& cfgInput = "digitizer", // std::string const& cfgOutput = "tracks", // + bool disableRootInput = false, // int caClusterer = 0, // int zsOnTheFly = 0, - int zs10bit = 0, - float zsThreshold = 2.0f); - -static inline framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, // - std::vector<int> const& tpcSectors, // - bool propagateMC = true, unsigned nLanes = 1, // - std::string const& cfgInput = "digitizer", // - std::string const& cfgOutput = "tracks", // - int caClusterer = 0, // - int zsOnTheFly = 0, - int zs10bit = 0, - float zsThreshold = 2.0f) -{ - // create a default lane configuration with ids [0, nLanes-1] - std::vector<int> laneConfiguration(nLanes); - std::iota(laneConfiguration.begin(), laneConfiguration.end(), 0); - return getWorkflow(policyData, tpcSectors, laneConfiguration, propagateMC, nLanes, cfgInput, cfgOutput, caClusterer, zsOnTheFly, zs10bit, zsThreshold); -} - -static inline framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, // - bool propagateMC = true, unsigned nLanes = 1, // - std::string const& cfgInput = "digitizer", // - std::string const& cfgOutput = "tracks", // - int caClusterer = 0, // - int zsOnTheFly = 0, - int zs10bit = 0, - float zsThreshold = 2.0f) -{ - // create a default lane configuration with ids [0, nLanes-1] - std::vector<int> laneConfiguration(nLanes); - std::iota(laneConfiguration.begin(), laneConfiguration.end(), 0); - return getWorkflow(policyData, {}, laneConfiguration, propagateMC, nLanes, cfgInput, cfgOutput, caClusterer, zsOnTheFly, zs10bit, zsThreshold); -} + bool askDISTSTF = true); } // end namespace reco_workflow } // end namespace tpc diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCAverageGroupIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCAverageGroupIDCSpec.h new file mode 100644 index 0000000000000..e96014039e9fb --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCAverageGroupIDCSpec.h @@ -0,0 +1,212 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCAverageGroupIDCSpec.h +/// \brief TPC merging and averaging of IDCs +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 16, 2021 + +#ifndef O2_TPCAVERAGEGROUPIDCSPEC_H +#define O2_TPCAVERAGEGROUPIDCSPEC_H + +#include <vector> +#include <deque> +#include <algorithm> +#include <fmt/format.h> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Headers/DataHeader.h" +#include "TPCCalibration/IDCAverageGroup.h" +#include "TPCWorkflow/TPCIntegrateIDCSpec.h" +#include "TPCCalibration/IDCGroupingParameter.h" + +#include "TKey.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCAverageGroupIDCDevice : public o2::framework::Task +{ + public: + TPCAverageGroupIDCDevice(const int lane, const std::vector<uint32_t>& crus, const unsigned int rangeIDC, const float sigma, const bool debug = false, const bool loadFromFile = false) + : mLane{lane}, mCRUs{crus}, mRangeIDC{rangeIDC}, mDebug{debug}, mLoadFromFile{loadFromFile}, mOneDIDCs(rangeIDC) + { + auto& paramIDCGroup = ParameterIDCGroup::Instance(); + for (const auto& cru : mCRUs) { + const CRU cruTmp(cru); + const unsigned int reg = cruTmp.region(); + mIDCs.emplace(cru, IDCAverageGroup(paramIDCGroup.GroupPads[reg], paramIDCGroup.GroupRows[reg], paramIDCGroup.GroupLastRowsThreshold[reg], paramIDCGroup.GroupLastPadsThreshold[reg], reg, cruTmp.sector(), sigma)); + mBuffer1DIDCs.emplace(cru, std::deque<std::vector<float>>(std::ceil(static_cast<float>(mRangeIDC) / mMinIDCsPerTF), std::vector<float>(mMinIDCsPerTF, 0))); + } + } + + void init(o2::framework::InitContext& ic) final + { + if (mLoadFromFile) { + const char* fName = "IDCGroup.root"; + TFile fInp(fName, "READ"); + for (TObject* keyAsObj : *fInp.GetListOfKeys()) { + const auto key = dynamic_cast<TKey*>(keyAsObj); + const char* name = key->GetName(); + LOGP(info, "Key name: {} Type: {}", name, key->GetClassName()); + + if (std::strcmp(o2::tpc::IDCAverageGroup::Class()->GetName(), key->GetClassName()) != 0) { + LOGP(info, "skipping object. wrong class."); + continue; + } + IDCAverageGroup* idcavg = (IDCAverageGroup*)fInp.Get(name); + unsigned int cru = idcavg->getSector() * Mapper::NREGIONS + idcavg->getRegion(); + // check cru + if (std::find(mCRUs.begin(), mCRUs.end(), cru) != mCRUs.end()) { + mIDCs[cru].setFromFile(fName, name); + mIDCs[cru].processIDCs(); + } + delete idcavg; + } + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + LOGP(info, "averaging and grouping IDCs for TF {} for CRUs {} to {} using {} threads", getCurrentTF(pc), mCRUs.front(), mCRUs.back(), mIDCs.begin()->second.getNThreads()); + + if (!mLoadFromFile) { + for (int i = 0; i < mCRUs.size(); ++i) { + const DataRef ref = pc.inputs().getByPos(i); + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int cru = tpcCRUHeader->subSpecification >> 7; + mIDCs[cru].setIDCs(pc.inputs().get<std::vector<float>>(ref)); + mIDCs[cru].processIDCs(); + + // send the output for one CRU for one TF + sendOutput(pc.outputs(), cru); + } + } else { + for (int i = 0; i < mCRUs.size(); ++i) { + sendOutput(pc.outputs(), mCRUs[i]); + } + } + + if (mDebug) { + TFile fOut(fmt::format("IDCGroup_{}_tf_{}.root", mLane, getCurrentTF(pc)).data(), "RECREATE"); + for (int i = 0; i < mCRUs.size(); ++i) { + const DataRef ref = pc.inputs().getByPos(i); + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int cru = tpcCRUHeader->subSpecification >> 7; + fOut.WriteObject(&mIDCs[cru], fmt::format("CRU_{}", cru).data()); + } + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + /// return data description for IDC Group + static constexpr header::DataDescription getDataDescriptionIDCGroup() { return header::DataDescription{"IDCGROUP"}; } + + /// return data description for 1D IDCs + static constexpr header::DataDescription getDataDescription1DIDC() { return header::DataDescription{"1DIDC"}; } + + /// return data description for buffered 1D IDCs for EPNs + static constexpr header::DataDescription getDataDescription1DIDCEPN() { return header::DataDescription{"1DIDCEPN"}; } + + /// set minimum IDCs which will be received per TF + /// \param nMinIDCsPerTF minimal number of IDCs per TF + static void setMinIDCsPerTF(const unsigned int nMinIDCsPerTF) { mMinIDCsPerTF = nMinIDCsPerTF; } + + /// \return returns the minimum IDCs which will be received per TF + static unsigned int getMinIDCsPerTF() { return mMinIDCsPerTF; } + + private: + inline static unsigned int mMinIDCsPerTF{10}; ///< minimum number of IDCs per TF (depends only on number of orbits per TF and (fixed) number of orbits per integration interval). 11 for 128 orbits per TF and 21 for 256 orbits per TF + const int mLane{}; ///< lane number of processor + const std::vector<uint32_t> mCRUs{}; ///< CRUs to process in this instance + const unsigned int mRangeIDC{}; ///< number of IDCs used for the calculation of fourier coefficients + const bool mDebug{}; ///< dump IDCs to tree for debugging + const bool mLoadFromFile{}; ///< load ungrouped IDCs from file + std::vector<float> mOneDIDCs{}; ///< 1D-IDCs which will be send to the EPNs + std::unordered_map<unsigned int, IDCAverageGroup> mIDCs{}; ///< object for averaging and grouping of the IDCs + std::unordered_map<unsigned int, std::deque<std::vector<float>>> mBuffer1DIDCs{}; ///< buffer for 1D-IDCs. The buffered 1D-IDCs for n TFs will be send to the EPNs for synchronous reco. Zero initialized to avoid empty first TFs! + + /// \return returns TF of current processed data + uint32_t getCurrentTF(o2::framework::ProcessingContext& pc) const { return o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; } + + void sendOutput(DataAllocator& output, const uint32_t cru) + { + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + + // calculate 1D-IDCs = sum over 2D-IDCs as a function of the integration interval + std::vector<float> vec1DIDCs = mIDCs[cru].getIDCGroup().get1DIDCs(); + output.snapshot(Output{gDataOriginTPC, getDataDescription1DIDC(), subSpec, Lifetime::Timeframe}, vec1DIDCs); + + // TODO use this and fix #include <boost/container/pmr/polymorphic_allocator.hpp> in ROOT CINT + // output.adoptContainer(Output{gDataOriginTPC, getDataDescriptionIDCGroup(), subSpec, Lifetime::Timeframe}, std::move(mIDCs[cru]).getIDCGroupData()); + output.snapshot(Output{gDataOriginTPC, getDataDescriptionIDCGroup(), subSpec, Lifetime::Timeframe}, mIDCs[cru].getIDCGroup().getData()); + + mBuffer1DIDCs[cru].emplace_back(std::move(vec1DIDCs)); + mBuffer1DIDCs[cru].pop_front(); // removing oldest 1D-IDCs + + fill1DIDCs(cru); + output.snapshot(Output{gDataOriginTPC, getDataDescription1DIDCEPN(), subSpec, Lifetime::Timeframe}, mOneDIDCs); + } + + void fill1DIDCs(const uint32_t cru) + { + // fill 1D-IDC vector with mRangeIDC buffered values + unsigned int i = mRangeIDC; + for (auto it = mBuffer1DIDCs[cru].crbegin(); it != mBuffer1DIDCs[cru].crend(); ++it) { + for (auto idc = it->crbegin(); idc != it->crend(); ++idc) { + mOneDIDCs[--i] = *idc; + if (i == 0) { + return; + } + } + } + } +}; + +DataProcessorSpec getTPCAverageGroupIDCSpec(const int ilane, const std::vector<uint32_t>& crus, const unsigned int rangeIDC, const float sigma, const bool debug, const bool loadFromFile) +{ + std::vector<OutputSpec> outputSpecs; + std::vector<InputSpec> inputSpecs; + outputSpecs.reserve(crus.size()); + inputSpecs.reserve(crus.size()); + + for (const auto& cru : crus) { + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + if (!loadFromFile) { + inputSpecs.emplace_back(InputSpec{"idcs", gDataOriginTPC, TPCIntegrateIDCDevice::getDataDescription(TPCIntegrateIDCDevice::IDCFormat::Sim), subSpec, Lifetime::Timeframe}); + } + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescriptionIDCGroup(), subSpec}); + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDC(), subSpec}); + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDCEPN(), subSpec}); + } + + const auto id = fmt::format("tpc-averagegroup-idc-{:02}", ilane); + return DataProcessorSpec{ + id.data(), + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCAverageGroupIDCDevice>(ilane, crus, rangeIDC, sigma, debug, loadFromFile)}, + }; // end DataProcessorSpec +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h new file mode 100644 index 0000000000000..499821a7b98e2 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h @@ -0,0 +1,189 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_TPCCALIBPEDESTALSPEC_H +#define O2_CALIBRATION_TPCCALIBPEDESTALSPEC_H + +/// @file TPCCalibPedestalSpec.h +/// @brief TPC Pedestal calibration processor + +#include <vector> +#include <string> +#include <chrono> +#include <fmt/format.h> + +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" + +#include "CommonUtils/MemFileHelper.h" +#include "Headers/DataHeader.h" + +#include "TPCBase/CDBInterface.h" +#include "TPCCalibration/CalibPedestal.h" +#include "TPCReconstruction/RawReaderCRU.h" +#include "TPCWorkflow/CalibProcessingHelper.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2 +{ +namespace tpc +{ + +class TPCCalibPedestalDevice : public o2::framework::Task +{ + public: + TPCCalibPedestalDevice(uint32_t lane, const std::vector<int>& sectors, uint32_t publishAfterTFs) : mLane{lane}, mSectors(sectors), mPublishAfter(publishAfterTFs) {} + + void init(o2::framework::InitContext& ic) final + { + // set up ADC value filling + // TODO: clean up to not go via RawReaderCRUManager + mCalibPedestal.init(); // initialize configuration via configKeyValues + mRawReader.createReader(""); + + mRawReader.setADCDataCallback([this](const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) -> int { + const int timeBins = mCalibPedestal.update(padROCPos, cru, data); + mCalibPedestal.setNumberOfProcessedTimeBins(std::max(mCalibPedestal.getNumberOfProcessedTimeBins(), size_t(timeBins))); + return timeBins; + }); + + mRawReader.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + mCalibPedestal.updateROC(cruID.roc(), rowInSector - (rowInSector > 62) * 63, padInRow, timeBin, adcValue); + return true; + }); + + mMaxEvents = static_cast<uint32_t>(ic.options().get<int>("max-events")); + mUseOldSubspec = ic.options().get<bool>("use-old-subspec"); + mForceQuit = ic.options().get<bool>("force-quit"); + mDirectFileDump = ic.options().get<bool>("direct-file-dump"); + if (mUseOldSubspec) { + LOGP(info, "Using old subspecification (CruId << 16) | ((LinkId + 1) << (CruEndPoint == 1 ? 8 : 0))"); + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + // in case the maximum number of events was reached don't do further processing + if (mReadyToQuit) { + return; + } + + auto& reader = mRawReader.getReaders()[0]; + calib_processing_helper::processRawData(pc.inputs(), reader, mUseOldSubspec, mSectors); + + mCalibPedestal.incrementNEvents(); + const auto nTFs = mCalibPedestal.getNumberOfProcessedEvents(); + LOGP(info, "Number of processed TFs: {} ({})", nTFs, mMaxEvents); + + if ((mPublishAfter && (nTFs % mPublishAfter) == 0)) { + LOGP(info, "Publishing after {} TFs", nTFs); + mCalibPedestal.analyse(); + dumpCalibData(); + sendOutput(pc.outputs()); + } + + if (mMaxEvents && (nTFs >= mMaxEvents) && !mCalibDumped) { + LOGP(info, "Maximm number of TFs reached ({}), no more processing will be done", mMaxEvents); + mReadyToQuit = true; + mCalibPedestal.analyse(); + dumpCalibData(); + if (mForceQuit) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + } else { + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "endOfStream"); + mCalibPedestal.analyse(); + dumpCalibData(); + sendOutput(ec.outputs()); + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + private: + CalibPedestal mCalibPedestal; + rawreader::RawReaderCRUManager mRawReader; + uint32_t mMaxEvents{0}; ///< maximum number of events to process + uint32_t mPublishAfter{0}; ///< number of events after which to dump the calibration + uint32_t mLane{0}; ///< lane number of processor + std::vector<int> mSectors{}; ///< sectors to process in this instance + bool mReadyToQuit{false}; ///< if processor is ready to quit + bool mCalibDumped{false}; ///< if calibration object already dumped + bool mUseOldSubspec{false}; ///< use the old subspec definition + bool mForceQuit{false}; ///< for quit after processing finished + bool mDirectFileDump{false}; ///< directly dump the calibration data to file + + //____________________________________________________________________________ + void sendOutput(DataAllocator& output) + { + + std::array<const CalDet<float>*, 2> data = {&mCalibPedestal.getPedestal(), &mCalibPedestal.getNoise()}; + std::array<CDBType, 2> dataType = {CDBType::CalPedestal, CDBType::CalNoise}; + + for (size_t i = 0; i < data.size(); ++i) { + auto cal = data[i]; + auto image = o2::utils::MemFileHelper::createFileImage(cal, typeid(*cal), cal->getName(), "data"); + int type = int(dataType[i]); + + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)((mLane << 4) + i)}; + output.snapshot(Output{gDataOriginTPC, "CLBPART", subSpec}, *image.get()); + output.snapshot(Output{gDataOriginTPC, "CLBPARTINFO", subSpec}, type); + } + } + + //____________________________________________________________________________ + void dumpCalibData() + { + if (mDirectFileDump && !mCalibDumped) { + LOGP(info, "Dumping output"); + mCalibPedestal.dumpToFile(fmt::format("pedestals_{:02}.root", mLane)); + mCalibDumped = true; + } + } +}; + +DataProcessorSpec getTPCCalibPedestalSpec(const std::string inputSpec, uint32_t ilane = 0, std::vector<int> sectors = {}, uint32_t publishAfterTFs = 0) +{ + std::vector<o2::framework::OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, "CLBPART"}); + outputs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, "CLBPARTINFO"}); + + const auto id = fmt::format("calib-tpc-pedestal-{:02}", ilane); + return DataProcessorSpec{ + id.data(), + select(inputSpec.data()), + outputs, + AlgorithmSpec{adaptFromTask<TPCCalibPedestalDevice>(ilane, sectors, publishAfterTFs)}, + Options{ + {"max-events", VariantType::Int, 0, {"maximum number of events to process"}}, + {"use-old-subspec", VariantType::Bool, false, {"use old subsecifiation definition"}}, + {"force-quit", VariantType::Bool, false, {"force quit after max-events have been reached"}}, + {"direct-file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, + } // end Options + }; // end DataProcessorSpec +} + +} // namespace tpc +} // namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h new file mode 100644 index 0000000000000..218a42b174ee6 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h @@ -0,0 +1,221 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCDistributeIDCSpec.h +/// \brief TPC aggregation of grouped IDCs and factorization +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 22, 2021 + +#ifndef O2_TPCDISTRIBUTEIDCIDCSPEC_H +#define O2_TPCDISTRIBUTEIDCIDCSPEC_H + +#include <vector> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" +#include "Headers/DataHeader.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCWorkflow/TPCAverageGroupIDCSpec.h" +#include "TPCBase/CRU.h" +#include "MemoryResources/MemoryResources.h" + +#include "TFile.h" +#include "TKey.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCDistributeIDCSpec : public o2::framework::Task +{ + public: + TPCDistributeIDCSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int outlanes, const bool loadFromFile, const unsigned int firstTF) + : mCRUs{crus}, mTimeFrames{timeframes}, mOutLanes{outlanes}, mLoadFromFile{loadFromFile}, mProcessedCRU{{std::vector<unsigned int>(timeframes), std::vector<unsigned int>(timeframes)}}, mTFStart{{firstTF, firstTF + timeframes}}, mTFEnd{{firstTF + timeframes - 1, mTFStart[1] + timeframes - 1}} + { + for (auto& idcbuffer : mIDCs) { + for (auto& idc : idcbuffer) { + idc.resize(mTimeFrames); + } + } + for (auto& idcbuffer : mOneDIDCs) { + for (auto& idc : idcbuffer) { + idc.resize(mTimeFrames); + } + } + }; + + void init(o2::framework::InitContext& ic) final + { + if (mLoadFromFile) { + TFile fInp("IDCGroup.root", "READ"); + for (TObject* keyAsObj : *fInp.GetListOfKeys()) { + const auto key = dynamic_cast<TKey*>(keyAsObj); + LOGP(info, "Key name: {} Type: {}", key->GetName(), key->GetClassName()); + + if (std::strcmp(o2::tpc::IDCAverageGroup::Class()->GetName(), key->GetClassName()) != 0) { + LOGP(info, "skipping object. wrong class."); + continue; + } + IDCAverageGroup* idcavg = (IDCAverageGroup*)fInp.Get(key->GetName()); + unsigned int cru = idcavg->getSector() * Mapper::NREGIONS + idcavg->getRegion(); + const std::vector<float>& idcData = idcavg->getIDCGroup().getData(); + const std::vector<float>& idc1D = idcavg->getIDCGroup().get1DIDCs(); + + for (auto& idcbuffer : mIDCs) { + const auto nIDCS = idcData.size(); + // TODO use memcyp etc here + for (auto& relTF : idcbuffer[cru]) { + relTF.reserve(nIDCS); + for (int i = 0; i < nIDCS; ++i) { + relTF.emplace_back(idcData[i]); + } + } + } + + for (auto& idcbuffer : mOneDIDCs) { + const auto nIDCS = idc1D.size(); + for (auto& relTF : idcbuffer[cru]) { + relTF.reserve(nIDCS); + for (int i = 0; i < nIDCS; ++i) { + relTF.emplace_back(idc1D[i]); + } + } + } + delete idcavg; + } + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + // check which buffer to use for current incoming data + const auto tf = getCurrentTF(pc); + const bool currentBuffer = (tf > mTFEnd[mBuffer]) ? !mBuffer : mBuffer; + const unsigned int currentOutLane = (tf > mTFEnd[mBuffer]) ? (mCurrentOutLane + 1) % mOutLanes : mCurrentOutLane; + const auto relTF = tf - mTFStart[currentBuffer]; + + if (!mLoadFromFile) { + for (auto& ref : InputRecordWalker(pc.inputs(), mFilter)) { + ++mProcessedCRU[currentBuffer][relTF]; + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int cru = tpcCRUHeader->subSpecification >> 7; + const auto descr = tpcCRUHeader->dataDescription; + if (TPCAverageGroupIDCDevice::getDataDescriptionIDCGroup() == descr) { + mIDCs[currentBuffer][cru][relTF] = std::move(pc.inputs().get<pmr::vector<float>>(ref)); + } else { + mOneDIDCs[currentBuffer][cru][relTF] = std::move(pc.inputs().get<pmr::vector<float>>(ref)); + } + } + } + + // check if all CRUs for current TF are already aggregated and send data + if (mProcessedCRU[currentBuffer][relTF] == 2 * mCRUs.size() || mLoadFromFile) { + ++mProcessedTFs[currentBuffer]; + sendOutput(pc, currentOutLane, currentBuffer, relTF); + } + + if (mProcessedTFs[currentBuffer] == mTimeFrames) { + mProcessedTFs[currentBuffer] = 0; // reset processed TFs for next aggregation interval + std::fill(mProcessedCRU[currentBuffer].begin(), mProcessedCRU[currentBuffer].end(), 0); + + // set integration range for next integration interval + mTFStart[mBuffer] = mTFEnd[!mBuffer] + 1; + mTFEnd[mBuffer] = mTFStart[mBuffer] + mTimeFrames - 1; + + // switch buffer + mBuffer = !mBuffer; + + // set output lane + mCurrentOutLane = ++mCurrentOutLane % mOutLanes; + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + /// return data description for aggregated IDCs + static constexpr header::DataDescription getDataDescriptionIDC() { return header::DataDescription{"IDCAGG"}; } + static constexpr header::DataDescription getDataDescription1DIDC() { return header::DataDescription{"1IDCAGG"}; } + + private: + const std::vector<uint32_t> mCRUs{}; ///< CRUs to process in this instance + const unsigned int mTimeFrames{}; ///< number of TFs per aggregation interval + const unsigned int mOutLanes{}; ///< number of output lanes + const bool mLoadFromFile{}; + std::array<int, 2> mProcessedTFs{{0, 0}}; ///< number of processed time frames to keep track of when the writing to CCDB will be done + std::array<std::array<std::vector<pmr::vector<float>>, CRU::MaxCRU>, 2> mIDCs{}; ///< grouped and integrated IDCs for the whole TPC. CRU -> time frame -> IDCs. Buffer used in case one FLP delivers the TF after the last TF for the current aggregation interval faster then the other FLPs the last TF. + std::array<std::array<std::vector<pmr::vector<float>>, CRU::MaxCRU>, 2> mOneDIDCs{}; ///< 1D IDCs for the whole TPC. CRU -> time frame -> IDCs. Buffer used in case one FLP delivers the TF after the last TF for the current aggregation interval faster then the other FLPs the last TF. + std::array<std::vector<unsigned int>, 2> mProcessedCRU{}; ///< counter of received data from CRUs per TF to merge incoming data from FLPs. Buffer used in case one FLP delivers the TF after the last TF for the current aggregation interval faster then the other FLPs the last TF. + std::array<uint32_t, 2> mTFStart{}; ///< storing of first TF used when setting the validity of the objects when writing to CCDB + std::array<uint32_t, 2> mTFEnd{}; ///< storing of last TF used when setting the validity of the objects when writing to CCDB + unsigned int mCurrentOutLane{0}; ///< index for keeping track of the current output lane + bool mBuffer{false}; ///< buffer index + const std::vector<InputSpec> mFilter = {{"idcsgroup", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescriptionIDCGroup()}, Lifetime::Timeframe}, + {"1didc", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDC()}, Lifetime::Timeframe}}; ///< filter for looping over input data + + /// \return returns TF of current processed data + uint32_t getCurrentTF(o2::framework::ProcessingContext& pc) const { return o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; } + + void sendOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const bool currentBuffer, const unsigned int relTF) + { + // send output data for one TF for all CRUs + if (!mLoadFromFile) { + for (unsigned int i = 0; i < mCRUs.size(); ++i) { + pc.outputs().adoptContainer(Output{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescriptionIDC(), header::DataHeader::SubSpecificationType{mCRUs[i] + currentOutLane * CRU::MaxCRU}}, std::move(mIDCs[currentBuffer][mCRUs[i]][relTF])); + pc.outputs().adoptContainer(Output{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescription1DIDC(), header::DataHeader::SubSpecificationType{mCRUs[i]}}, std::move(mOneDIDCs[currentBuffer][mCRUs[i]][relTF])); + } + } else { + for (unsigned int i = 0; i < mCRUs.size(); ++i) { + pc.outputs().snapshot(Output{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescriptionIDC(), header::DataHeader::SubSpecificationType{mCRUs[i] + currentOutLane * CRU::MaxCRU}}, mIDCs[currentBuffer][mCRUs[i]][relTF]); + pc.outputs().snapshot(Output{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescription1DIDC(), header::DataHeader::SubSpecificationType{mCRUs[i]}}, mOneDIDCs[currentBuffer][mCRUs[i]][relTF]); + } + } + } +}; + +DataProcessorSpec getTPCDistributeIDCSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int outlanes, const unsigned int firstTF, const bool loadFromFile) +{ + std::vector<InputSpec> inputSpecs; + if (!loadFromFile) { + inputSpecs.emplace_back(InputSpec{"idcsgroup", ConcreteDataTypeMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescriptionIDCGroup()}, Lifetime::Timeframe}); + inputSpecs.emplace_back(InputSpec{"1didc", ConcreteDataTypeMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDC()}, Lifetime::Timeframe}); + } + + std::vector<OutputSpec> outputSpecs; + outputSpecs.reserve((outlanes + 1) * crus.size()); + for (int lane = 0; lane < outlanes; ++lane) { + for (const auto cru : crus) { + const header::DataHeader::SubSpecificationType subSpec{cru + lane * CRU::MaxCRU}; + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescriptionIDC(), subSpec}); + } + } + + for (const auto cru : crus) { + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescription1DIDC(), header::DataHeader::SubSpecificationType{cru}}); + } + + return DataProcessorSpec{ + "tpc-distribute-idc", + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCDistributeIDCSpec>(crus, timeframes, outlanes, loadFromFile, firstTF)}}; +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h new file mode 100644 index 0000000000000..dd3510876915e --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h @@ -0,0 +1,223 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCFactorizeGroupedIDCSpec.h +/// \brief TPC aggregation of grouped IDCs and factorization +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Jun 25, 2021 + +#ifndef O2_TPCFACTORIZEIDCSPEC_H +#define O2_TPCFACTORIZEIDCSPEC_H + +#include <vector> +#include <fmt/format.h> +#include <limits> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DeviceSpec.h" +#include "Headers/DataHeader.h" +#include "TPCCalibration/IDCFactorization.h" +#include "CCDB/CcdbApi.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCCalibration/IDCGroupingParameter.h" +#include "TPCWorkflow/TPCDistributeIDCSpec.h" +#include "TPCBase/CRU.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCFactorizeIDCSpec : public o2::framework::Task +{ + public: + TPCFactorizeIDCSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int timeframesDeltaIDC, std::array<unsigned char, Mapper::NREGIONS> groupPads, + std::array<unsigned char, Mapper::NREGIONS> groupRows, std::array<unsigned char, Mapper::NREGIONS> groupLastRowsThreshold, + std::array<unsigned char, Mapper::NREGIONS> groupLastPadsThreshold, const IDCDeltaCompression compression, const bool debug = false, const bool senddebug = false) + : mCRUs{crus}, mIDCFactorization{groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold, timeframes, timeframesDeltaIDC}, mCompressionDeltaIDC{compression}, mDebug{debug}, mSendOutDebug{senddebug} {}; + + void init(o2::framework::InitContext& ic) final + { + mLaneId = ic.services().get<const o2::framework::DeviceSpec>().rank; + mDBapi.init(ic.options().get<std::string>("ccdb-uri")); // or http://localhost:8080 for a local installation + mWriteToDB = mDBapi.isHostReachable() ? true : false; + mUpdateGroupingPar = mLaneId == 0 ? !(ic.options().get<bool>("update-not-grouping-parameter")) : false; + + // write struct containing grouping parameters to access grouped IDCs to CCDB + if (mWriteToDB && mUpdateGroupingPar) { + // validity for grouping parameters is from first TF to some really large TF (until it is updated) TODO do somewhere else?! + mDBapi.storeAsTFileAny<o2::tpc::ParameterIDCGroupCCDB>(&mIDCFactorization.getGroupingParameter(), "TPC/Calib/IDC/GROUPINGPAR", mMetadata, getFirstTF(), std::numeric_limits<uint32_t>::max()); + mUpdateGroupingPar = false; // write grouping parameters only once + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + // set the min range of TFs for first TF + if (mProcessedTFs == 0) { + mTFRange[0] = getCurrentTF(pc); + } + + for (int i = 0; i < mCRUs.size(); ++i) { + const DataRef ref = pc.inputs().getByPos(i); + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int cru = tpcCRUHeader->subSpecification - mLaneId * CRU::MaxCRU; + mIDCFactorization.setIDCs(pc.inputs().get<std::vector<float>>(ref), cru, mProcessedTFs); // aggregate IDCs + } + ++mProcessedTFs; + + if (!(mProcessedTFs % ((mIDCFactorization.getNTimeframes() + 5) / 5))) { + LOGP(info, "aggregated TFs: {}", mProcessedTFs); + } + + if (mProcessedTFs == mIDCFactorization.getNTimeframes()) { + mTFRange[1] = getCurrentTF(pc); // set the TF for last aggregated TF + mProcessedTFs = 0; // reset processed TFs for next aggregation interval + mIDCFactorization.factorizeIDCs(); // calculate DeltaIDC, 0D-IDC, 1D-IDC + + if (mDebug) { + LOGP(info, "dumping aggregated and factorized IDCs and FT to file"); + mIDCFactorization.dumpToFile(fmt::format("IDCFactorized_{:02}.root", getCurrentTF(pc)).data()); + } + + // storing to CCDB + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + static constexpr header::DataDescription getDataDescriptionIDC0() { return header::DataDescription{"IDC0"}; } + static constexpr header::DataDescription getDataDescriptionIDC1() { return header::DataDescription{"IDC1"}; } + static constexpr header::DataDescription getDataDescriptionIDCDelta() { return header::DataDescription{"IDCDELTA"}; } + + private: + const std::vector<uint32_t> mCRUs{}; ///< CRUs to process in this instance + int mProcessedTFs{0}; ///< number of processed time frames to keep track of when the writing to CCDB will be done + IDCFactorization mIDCFactorization{}; ///< object aggregating the IDCs and performing the factorization of the IDCs + const IDCDeltaCompression mCompressionDeltaIDC{}; ///< compression type for IDC Delta + const bool mDebug{false}; ///< dump IDCs to tree for debugging + const bool mSendOutDebug{false}; ///< flag if the output will be send (for debugging) + o2::ccdb::CcdbApi mDBapi; ///< API for storing the IDCs in the CCDB + std::map<std::string, std::string> mMetadata; ///< meta data of the stored object in CCDB + bool mWriteToDB{}; ///< flag if writing to CCDB will be done + std::array<uint32_t, 2> mTFRange{}; ///< storing of first and last TF used when setting the validity of the objects when writing to CCDB + bool mUpdateGroupingPar{true}; ///< flag to set if grouping parameters should be updated or not + int mLaneId{0}; ///< the id of the current process within the parallel pipeline + + /// \return returns TF of current processed data + uint32_t getCurrentTF(o2::framework::ProcessingContext& pc) const { return o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; } + + /// \return returns first TF for validity range when storing to CCDB + uint32_t getFirstTF() const { return mTFRange[0]; } + + /// \return returns last TF for validity range when storing to CCDB + uint32_t getLastTF() const { return mTFRange[1]; } + + /// \return returns first TF for validity range when storing to IDCDelta CCDB + unsigned int getFirstTFDeltaIDC(const unsigned int iChunk) const { return getFirstTF() + iChunk * mIDCFactorization.getTimeFramesDeltaIDC(); } + + /// \return returns last TF for validity range when storing to IDCDelta CCDB + unsigned int getLastTFDeltaIDC(const unsigned int iChunk) const { return (iChunk == mIDCFactorization.getNChunks() - 1) ? (mIDCFactorization.getNTimeframes() - 1 + getFirstTF()) : (getFirstTFDeltaIDC(iChunk) + mIDCFactorization.getTimeFramesDeltaIDC() - 1); } + + /// send output to next device for debugging + void sendOutputDebug(DataAllocator& output) + { + output.snapshot(Output{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDC0()}, mIDCFactorization.getIDCZero()); + output.snapshot(Output{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDC1()}, mIDCFactorization.getIDCOne()); + for (unsigned int iChunk = 0; iChunk < mIDCFactorization.getNChunks(); ++iChunk) { + output.snapshot(Output{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDCDelta(), o2::header::DataHeader::SubSpecificationType{iChunk}, Lifetime::Timeframe}, mIDCFactorization.getIDCDeltaUncompressed(iChunk)); + } + } + + void sendOutput(DataAllocator& output) + { + if (mSendOutDebug) { + sendOutputDebug(output); + } + + if (mWriteToDB) { + const long timeStampStart = getFirstTF(); + const long timeStampEnd = getLastTF(); + mDBapi.storeAsTFileAny<o2::tpc::IDCZero>(&mIDCFactorization.getIDCZero(), "TPC/Calib/IDC/IDC0", mMetadata, timeStampStart, timeStampEnd); + mDBapi.storeAsTFileAny<o2::tpc::IDCOne>(&mIDCFactorization.getIDCOne(), "TPC/Calib/IDC/IDC1", mMetadata, timeStampStart, timeStampEnd); + + for (unsigned int iChunk = 0; iChunk < mIDCFactorization.getNChunks(); ++iChunk) { + switch (mCompressionDeltaIDC) { + case IDCDeltaCompression::MEDIUM: + default: { + auto idcDeltaMediumCompressed = mIDCFactorization.getIDCDeltaMediumCompressed(iChunk); + mDBapi.storeAsTFileAny<o2::tpc::IDCDelta<short>>(&idcDeltaMediumCompressed, "TPC/Calib/IDC/IDCDELTA", mMetadata, getFirstTFDeltaIDC(iChunk), getLastTFDeltaIDC(iChunk)); + break; + } + case IDCDeltaCompression::HIGH: { + auto idcDeltaHighCompressed = mIDCFactorization.getIDCDeltaHighCompressed(iChunk); + mDBapi.storeAsTFileAny<o2::tpc::IDCDelta<char>>(&idcDeltaHighCompressed, "TPC/Calib/IDC/IDCDELTA", mMetadata, getFirstTFDeltaIDC(iChunk), getLastTFDeltaIDC(iChunk)); + break; + } + case IDCDeltaCompression::NO: + mDBapi.storeAsTFileAny<o2::tpc::IDCDelta<float>>(&mIDCFactorization.getIDCDeltaUncompressed(iChunk), "TPC/Calib/IDC/IDCDELTA", mMetadata, getFirstTFDeltaIDC(iChunk), getLastTFDeltaIDC(iChunk)); + break; + } + } + } + // reseting aggregated IDCs. This is done for safety, but if all data is received in the next aggregation interval it isnt necessary... remove it? + mIDCFactorization.reset(); + } +}; + +DataProcessorSpec getTPCFactorizeIDCSpec(const int lane, const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int timeframesDeltaIDC, const IDCDeltaCompression compression, const bool debug = false, const bool senddebug = false) +{ + std::vector<OutputSpec> outputSpecs; + if (senddebug) { + outputSpecs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDC0()}); + outputSpecs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDC1()}); + outputSpecs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, TPCFactorizeIDCSpec::getDataDescriptionIDCDelta()}); + } + + std::vector<InputSpec> inputSpecs; //{InputSpec{"idcagg", ConcreteDataTypeMatcher{gDataOriginTPC, TPCDistributeIDCSpec::getDataDescriptionIDC()}, Lifetime::Timeframe}}; + inputSpecs.reserve(crus.size()); + for (const auto& cru : crus) { + inputSpecs.emplace_back(InputSpec{"idcagg", gDataOriginTPC, TPCDistributeIDCSpec::getDataDescriptionIDC(), header::DataHeader::SubSpecificationType{cru + lane * CRU::MaxCRU}, Lifetime::Timeframe}); + } + + const auto& paramIDCGroup = ParameterIDCGroup::Instance(); + std::array<unsigned char, Mapper::NREGIONS> groupPads{}; + std::array<unsigned char, Mapper::NREGIONS> groupRows{}; + std::array<unsigned char, Mapper::NREGIONS> groupLastRowsThreshold{}; + std::array<unsigned char, Mapper::NREGIONS> groupLastPadsThreshold{}; + std::copy(std::begin(paramIDCGroup.GroupPads), std::end(paramIDCGroup.GroupPads), std::begin(groupPads)); + std::copy(std::begin(paramIDCGroup.GroupRows), std::end(paramIDCGroup.GroupRows), std::begin(groupRows)); + std::copy(std::begin(paramIDCGroup.GroupLastRowsThreshold), std::end(paramIDCGroup.GroupLastRowsThreshold), std::begin(groupLastRowsThreshold)); + std::copy(std::begin(paramIDCGroup.GroupLastPadsThreshold), std::end(paramIDCGroup.GroupLastPadsThreshold), std::begin(groupLastPadsThreshold)); + + DataProcessorSpec spec{ + fmt::format("tpc-factorize-idc-{:02}", lane).data(), + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCFactorizeIDCSpec>(crus, timeframes, timeframesDeltaIDC, groupPads, groupRows, groupLastRowsThreshold, groupLastPadsThreshold, compression, debug, senddebug)}, + Options{{"ccdb-uri", VariantType::String, "http://ccdb-test.cern.ch:8080", {"URI for the CCDB access."}}, + {"update-not-grouping-parameter", VariantType::Bool, false, {"Do NOT Update/Writing grouping parameters to CCDB."}}}}; // end DataProcessorSpec + + spec.rank = lane; + return spec; +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformAggregatorSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformAggregatorSpec.h new file mode 100644 index 0000000000000..c7dc7b09b84ea --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformAggregatorSpec.h @@ -0,0 +1,152 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCFourierTransformAggregatorSpec.h +/// \brief TPC aggregation of 1D-IDCs and fourier transform +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Jun 16, 2021 + +#ifndef O2_TPCFOURIERTRANSFORMAGGREGATORSPEC_H +#define O2_TPCFOURIERTRANSFORMAGGREGATORSPEC_H + +#include <vector> +#include <fmt/format.h> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Headers/DataHeader.h" +#include "CCDB/CcdbApi.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCCalibration/IDCFourierTransform.h" +#include "TPCWorkflow/TPCDistributeIDCSpec.h" +#include "TPCBase/CRU.h" +#include "Framework/WorkflowSpec.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCFourierTransformAggregatorSpec : public o2::framework::Task +{ + public: + // Fourier type + using IDCFType = IDCFourierTransform<IDCFourierTransformBaseAggregator>; + + TPCFourierTransformAggregatorSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int nFourierCoefficientsStore, const unsigned int rangeIDC, const bool debug = false, const bool senddebug = false) + : mTimeFrames{timeframes}, mCRUs{crus}, mIDCFourierTransform{rangeIDC, timeframes, nFourierCoefficientsStore}, mOneDIDCAggregator{timeframes}, mDebug{debug}, mSendOutDebug{senddebug} {}; + + void init(o2::framework::InitContext& ic) final + { + mDBapi.init(ic.options().get<std::string>("ccdb-uri")); // or http://localhost:8080 for a local installation + mWriteToDB = mDBapi.isHostReachable() ? true : false; + } + + void run(o2::framework::ProcessingContext& pc) final + { + // set the min range of TFs for first TF + if (mProcessedTFs == 0) { + mTFRange[0] = getCurrentTF(pc); + } + + for (int i = 0; i < mCRUs.size(); ++i) { + const DataRef ref = pc.inputs().getByPos(i); + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const o2::tpc::CRU cruTmp(tpcCRUHeader->subSpecification); + mOneDIDCAggregator.aggregate1DIDCs(cruTmp.side(), pc.inputs().get<std::vector<float>>(ref), mProcessedTFs, cruTmp.region()); + } + ++mProcessedTFs; + + if (!(mProcessedTFs % ((mTimeFrames + 5) / 5))) { + LOGP(info, "aggregated TFs: {}", mProcessedTFs); + } + + if (mProcessedTFs == mTimeFrames) { + mTFRange[1] = getCurrentTF(pc); // set the TF for last aggregated TF + mProcessedTFs = 0; // reset processed TFs for next aggregation interval + + // perform fourier transform of 1D-IDCs + auto intervals = mOneDIDCAggregator.getIntegrationIntervalsPerTF(); + mIDCFourierTransform.setIDCs(std::move(mOneDIDCAggregator).getAggregated1DIDCs(), std::move(intervals)); + mIDCFourierTransform.calcFourierCoefficients(); + + if (mDebug) { + LOGP(info, "dumping FT to file"); + mIDCFourierTransform.dumpToFile(fmt::format("FourierAGG_{:02}.root", getCurrentTF(pc)).data()); + } + + // storing to CCDB + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + static constexpr header::DataDescription getDataDescriptionFourier() { return header::DataDescription{"FOURIER"}; } + + private: + const unsigned int mTimeFrames{}; ///< number of time frames which will be aggregated + const std::vector<uint32_t> mCRUs{}; ///< CRUs to process in this instance + IDCFType mIDCFourierTransform{}; ///< object for performing the fourier transform of 1D-IDCs + OneDIDCAggregator mOneDIDCAggregator{}; ///< helper class for aggregation of 1D-IDCs + const bool mDebug{false}; ///< dump IDCs to tree for debugging + const bool mSendOutDebug{false}; ///< flag if the output will be send (for debugging) + o2::ccdb::CcdbApi mDBapi; ///< API for storing the IDCs in the CCDB + std::map<std::string, std::string> mMetadata; ///< meta data of the stored object in CCDB + bool mWriteToDB{}; ///< flag if writing to CCDB will be done + std::array<uint32_t, 2> mTFRange{}; ///< storing of first and last TF used when setting the validity of the objects when writing to CCDB + int mProcessedTFs{0}; ///< number of processed time frames to keep track of when the writing to CCDB will be done + + /// \return returns TF of current processed data + uint32_t getCurrentTF(o2::framework::ProcessingContext& pc) const { return o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; } + + void sendOutput(DataAllocator& output) + { + if (mSendOutDebug) { + output.snapshot(Output{gDataOriginTPC, TPCFourierTransformAggregatorSpec::getDataDescriptionFourier()}, mIDCFourierTransform.getFourierCoefficients()); + } + + if (mWriteToDB) { + mDBapi.storeAsTFileAny<o2::tpc::FourierCoeff>(&mIDCFourierTransform.getFourierCoefficients(), "TPC/Calib/IDC/FOURIER", mMetadata, mTFRange[0], mTFRange[1]); + } + } +}; + +DataProcessorSpec getTPCFourierTransformAggregatorSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int rangeIDC, const unsigned int nFourierCoefficientsStore, const bool debug = false, const bool senddebug = false) +{ + std::vector<OutputSpec> outputSpecs; + if (senddebug) { + outputSpecs.emplace_back(ConcreteDataTypeMatcher{gDataOriginTPC, TPCFourierTransformAggregatorSpec::getDataDescriptionFourier()}); + } + + std::vector<InputSpec> inputSpecs; + inputSpecs.reserve(crus.size()); + for (const auto cru : crus) { + inputSpecs.emplace_back(InputSpec{"1didc", gDataOriginTPC, TPCDistributeIDCSpec::getDataDescription1DIDC(), header::DataHeader::SubSpecificationType{cru}, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "tpc-aggregator-ft", + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCFourierTransformAggregatorSpec>(crus, timeframes, nFourierCoefficientsStore, rangeIDC, debug, senddebug)}, + Options{{"ccdb-uri", VariantType::String, "http://ccdb-test.cern.ch:8080", {"URI for the CCDB access."}}}}; // end DataProcessorSpec +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformEPNSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformEPNSpec.h new file mode 100644 index 0000000000000..80c00fe21b4f6 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFourierTransformEPNSpec.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCFourierTransformEPNSpec.h +/// \brief fourier transform of 1D-IDCs used during synchronous reconstruction +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Jun 10, 2021 + +#ifndef O2_TPCFOURIERTRANSFORMEPNSPEC_H +#define O2_TPCFOURIERTRANSFORMEPNSPEC_H + +#include <vector> +#include <fmt/format.h> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/InputRecordWalker.h" +#include "Headers/DataHeader.h" +#include "TPCCalibration/IDCFourierTransform.h" +#include "TPCWorkflow/TPCAverageGroupIDCSpec.h" +#include "TPCBase/CRU.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCFourierTransformEPNSpec : public o2::framework::Task +{ + public: + using IDCFType = IDCFourierTransform<IDCFourierTransformBaseEPN>; + + TPCFourierTransformEPNSpec(const std::vector<uint32_t>& crus, const unsigned int nFourierCoefficientsSend, const unsigned int rangeIDC, const bool debug = false) : mCRUs{crus}, mIDCFourierTransform{rangeIDC, nFourierCoefficientsSend}, mOneDIDCAggregator{1}, mDebug{debug} {}; + + void run(o2::framework::ProcessingContext& pc) final + { + for (auto const& ref : InputRecordWalker(pc.inputs(), mFilter)) { + ++mReceivedCRUs; + auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int cru = tpcCRUHeader->subSpecification >> 7; + const o2::tpc::CRU cruTmp(cru); + mOneDIDCAggregator.aggregate1DIDCs(cruTmp.side(), pc.inputs().get<std::vector<float>>(ref), 0, cruTmp.region()); + } + + if (mReceivedCRUs != mCRUs.size()) { + return; + } + + mReceivedCRUs = 0; + + // perform fourier transform of 1D-IDCs + mIDCFourierTransform.setIDCs(std::move(mOneDIDCAggregator).getAggregated1DIDCs()); + mIDCFourierTransform.calcFourierCoefficients(); + + if (mDebug) { + LOGP(info, "dumping FT to file"); + mIDCFourierTransform.dumpToFile(fmt::format("FourierEPN_{:02}.root", o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter).data()); + } + + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + /// \return returns data description for output fourier coefficients + static constexpr header::DataDescription getDataDescription() { return header::DataDescription{"FOURIERCOEFF"}; } + + private: + const std::vector<uint32_t> mCRUs{}; ///< CRUs to process in this instance + IDCFourierTransform<IDCFourierTransformBaseEPN> mIDCFourierTransform{}; ///< object for performing the fourier transform of 1D-IDCs + OneDIDCAggregator mOneDIDCAggregator{}; ///< helper class for aggregation of 1D-IDCs + const bool mDebug{false}; ///< dump IDCs to tree for debugging + int mReceivedCRUs = 0; ///< counter to keep track of the number of received data from CRUs + const std::vector<InputSpec> mFilter = {{"1didcepn", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDCEPN()}, Lifetime::Timeframe}}; ///< filter for looping over input data + + void sendOutput(DataAllocator& output) + { + output.snapshot(Output{gDataOriginTPC, getDataDescription(), header::DataHeader::SubSpecificationType{Side::A}, Lifetime::Timeframe}, mIDCFourierTransform.getFourierCoefficients().getFourierCoefficients(Side::A)); + output.snapshot(Output{gDataOriginTPC, getDataDescription(), header::DataHeader::SubSpecificationType{Side::C}, Lifetime::Timeframe}, mIDCFourierTransform.getFourierCoefficients().getFourierCoefficients(Side::C)); + } +}; + +DataProcessorSpec getTPCFourierTransformEPNSpec(const std::vector<uint32_t>& crus, const unsigned int rangeIDC, const unsigned int nFourierCoefficientsSend, const bool debug = false) +{ + std::vector<InputSpec> inputSpecs{InputSpec{"1didcepn", ConcreteDataTypeMatcher{gDataOriginTPC, TPCAverageGroupIDCDevice::getDataDescription1DIDCEPN()}, Lifetime::Timeframe}}; + std::vector<OutputSpec> outputSpecs{ConcreteDataMatcher{gDataOriginTPC, TPCFourierTransformEPNSpec::getDataDescription(), header::DataHeader::SubSpecificationType{o2::tpc::Side::A}}, + ConcreteDataMatcher{gDataOriginTPC, TPCFourierTransformEPNSpec::getDataDescription(), header::DataHeader::SubSpecificationType{o2::tpc::Side::C}}}; + + return DataProcessorSpec{ + "tpc-epn-ft", + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCFourierTransformEPNSpec>(crus, nFourierCoefficientsSend, rangeIDC, debug)}}; +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCIntegrateIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCIntegrateIDCSpec.h new file mode 100644 index 0000000000000..99d64220a2238 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCIntegrateIDCSpec.h @@ -0,0 +1,140 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCIntegrateIDCSpec.h +/// \brief TPC integration of IDCs processor +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> +/// \date Apr 16, 2021 + +#ifndef O2_TPCINTEGRATEIDCSPEC_H +#define O2_TPCINTEGRATEIDCSPEC_H + +#include <vector> +#include <fmt/format.h> +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Headers/DataHeader.h" +#include "TPCSimulation/IDCSim.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCBase/Mapper.h" + +using namespace o2::framework; +using o2::header::gDataOriginTPC; +using namespace o2::tpc; + +namespace o2::tpc +{ + +class TPCIntegrateIDCDevice : public o2::framework::Task +{ + public: + // enum for the output format of the integrated IDCs + enum class IDCFormat : int { + Sim = 0, // output format of simulation for faster processing + Real = 1 // output format of real CRUs + }; + + TPCIntegrateIDCDevice(const std::vector<unsigned int>& sectors, const int nOrbitsPerIDCIntervall, const IDCFormat outputFormat, const bool debug) : mSectors{sectors}, mIDCFormat{outputFormat}, mDebug{debug} + { + for (const auto& sector : mSectors) { + mIDCs.emplace(sector, IDCSim(sector, nOrbitsPerIDCIntervall)); + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + LOGP(info, "integrating digits for sectors {} to {}", mSectors.front(), mSectors.back()); + + for (int iSec = 0; iSec < mSectors.size(); ++iSec) { + const DataRef ref = pc.inputs().getByPos(iSec); + const int sector = o2::framework::DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref)->sector(); + + // integrate digits for given sector + mIDCs[sector].integrateDigitsForOneTF(pc.inputs().get<gsl::span<o2::tpc::Digit>>(ref)); + + if (mDebug) { + auto const* tpcHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + mIDCs[sector].dumpIDCs(fmt::format("idcs_obj_sec{:02}_tf{:02}.root", sector, tpcHeader->tfCounter).data(), fmt::format("IDCSim_sec{:02}", sector).data()); + } + + // send the output for one sector for one TF + sendOutput(pc.outputs(), sector); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final { ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); } + + /// return the kind of the output for given type. + /// \param idcFormat type of the IDC format + static constexpr header::DataDescription getDataDescription(const IDCFormat idcFormat) { return (idcFormat == IDCFormat::Sim) ? header::DataDescription{"IDCVECTOR"} : header::DataDescription{"IDC"}; } + + private: + const std::vector<unsigned int> mSectors{}; ///< sectors to process in this instance + const IDCFormat mIDCFormat{IDCFormat::Sim}; ///< type of the output format. Sim=simulation, Real=realistic format + const bool mDebug{false}; ///< dump IDCs to tree for debugging + std::unordered_map<unsigned int, IDCSim> mIDCs{}; ///< integrated IDCs for one TF for all specified sectors + + // send output for one sector + void sendOutput(DataAllocator& output, const int sector) + { + uint32_t cru = sector * Mapper::NREGIONS; + for (const auto& idcs : mIDCs[sector].get()) { + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + if (mIDCFormat == IDCFormat::Sim) { + output.snapshot(Output{gDataOriginTPC, getDataDescription(mIDCFormat), subSpec, Lifetime::Timeframe}, idcs); + } else { + // TODO + // convert to format from thorsten here + // send....... + // DUMMY FOR NOW + // const TPCCRUHeader cruheader{cru, mIntegrationIntervalsPerTF}; + output.snapshot(Output{gDataOriginTPC, getDataDescription(mIDCFormat), subSpec, Lifetime::Timeframe}, idcs); + } + ++cru; + } + } +}; + +DataProcessorSpec getTPCIntegrateIDCSpec(const int ilane, const std::vector<unsigned int>& sectors, const int nOrbits = 12, const TPCIntegrateIDCDevice::IDCFormat outputFormat = TPCIntegrateIDCDevice::IDCFormat::Sim, const bool debug = false) +{ + std::vector<InputSpec> inputSpecs; + inputSpecs.reserve(sectors.size()); + + std::vector<OutputSpec> outputSpecs; + outputSpecs.reserve(sectors.size() * Mapper::NREGIONS); + + // define input and output specs + for (const auto& sector : sectors) { + inputSpecs.emplace_back(InputSpec{"digits", gDataOriginTPC, "DIGITS", sector, Lifetime::Timeframe}); + + // output spec + unsigned int cru = sector * Mapper::NREGIONS; + for (int iRegion = 0; iRegion < Mapper::NREGIONS; ++iRegion) { + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCIntegrateIDCDevice::getDataDescription(outputFormat), subSpec}); + ++cru; + } + } + + const auto id = fmt::format("tpc-integrate-idc-{:02}", ilane); + return DataProcessorSpec{ + id.data(), + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCIntegrateIDCDevice>(sectors, nOrbits, outputFormat, debug)}}; // end DataProcessorSpec +} + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h deleted file mode 100644 index f9899344a4213..0000000000000 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TrackReaderSpec.h - -#ifndef O2_TPC_TRACKREADER -#define O2_TPC_TRACKREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "Headers/DataHeader.h" -#include "DataFormatsTPC/TrackTPC.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tpc -{ -///< DPL device to read and send the TPC tracks (+MC) info - -class TrackReader : public Task -{ - public: - TrackReader(bool useMC = true); - ~TrackReader() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - void accumulate(int from, int n); - void connectTree(const std::string& filename); - - std::vector<o2::tpc::TrackTPC>*mTracksInp = nullptr, mTracksOut; - std::vector<o2::tpc::TPCClRefElem>*mCluRefVecInp = nullptr, mCluRefVecOut; - std::vector<o2::MCCompLabel>*mMCTruthInp = nullptr, mMCTruthOut; - - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - - bool mUseMC = true; // use MC truth - - std::string mInputFileName = "tpctracks.root"; - std::string mTrackTreeName = "events"; - std::string mTrackBranchName = "Tracks"; - std::string mClusRefBranchName = "ClusRefs"; - std::string mTrackMCTruthBranchName = "TracksMCTruth"; -}; - -/// create a processor spec -/// read TPC track data from a root file -framework::DataProcessorSpec getTPCTrackReaderSpec(bool useMC = true); - -} // namespace tpc -} // namespace o2 - -#endif /* O2_TPC_TRACKREADER */ diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ZSSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ZSSpec.h index bebb48a6c3fac..f33ef5d96485a 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/ZSSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ZSSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,9 @@ namespace tpc { /// create a processor spec -framework::DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs12bit, float threshold, bool outRaw); +framework::DataProcessorSpec getZSEncoderSpec(std::vector<int> const& tpcSectors, bool outRaw, unsigned long tpcSectorMask); -framework::DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds); +framework::DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& tpcSectors); } // end namespace tpc } // end namespace o2 diff --git a/Detectors/TPC/workflow/readers/CMakeLists.txt b/Detectors/TPC/workflow/readers/CMakeLists.txt new file mode 100644 index 0000000000000..f6129a23989d0 --- /dev/null +++ b/Detectors/TPC/workflow/readers/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TPCReaderWorkflow + SOURCES src/ClusterReaderSpec.cxx + src/PublisherSpec.cxx + src/TrackReaderSpec.cxx + TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsTPC + O2::DPLUtils + O2::TPCBase + ) + +if(OpenMP_CXX_FOUND) + # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp + target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP) + target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/ClusterReaderSpec.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/ClusterReaderSpec.h new file mode 100644 index 0000000000000..53e2fdee48445 --- /dev/null +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/ClusterReaderSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_CLUSTERREADERSPEC_H +#define O2_TPC_CLUSTERREADERSPEC_H +/// @file ClusterReaderSpec.h +/// @author David Rohr + +#include "Framework/WorkflowSpec.h" +#include <vector> + +namespace o2 +{ +namespace tpc +{ +framework::DataProcessorSpec getClusterReaderSpec(bool useMC, const std::vector<int>* tpcSectors = nullptr, const std::vector<int>* laneConfiguration = nullptr); +} // end namespace tpc +} // end namespace o2 +#endif // O2_TPC_CLUSTERREADERSPEC_H diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/PublisherSpec.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/PublisherSpec.h new file mode 100644 index 0000000000000..531bf635a1e5b --- /dev/null +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/PublisherSpec.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h +/// @author Matthias Richter +/// @since 2018-12-06 +/// @brief Processor spec for a reader of TPC data from ROOT file + +#include "Framework/DataProcessorSpec.h" +#include "Framework/OutputSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Output.h" +#include "DPLUtils/RootTreeReader.h" +#include <vector> +#include <string> +#include <functional> + +namespace o2 +{ +namespace tpc +{ + +using OutputSpec = framework::OutputSpec; +using Reader = o2::framework::RootTreeReader; + +struct PublisherConf { + struct BranchOptionConfig { + std::string option; + std::string defval; + std::string help; + }; + + std::string processName; + std::string defaultFileName; + std::string defaultTreeName; + BranchOptionConfig databranch; + BranchOptionConfig mcbranch; + OutputSpec dataoutput; + OutputSpec mcoutput; + std::vector<int> tpcSectors; + std::vector<int> outputIds; + Reader::SpecialPublishHook* hook = nullptr; +}; + +/// create a processor spec +/// read data from multiple tree branches from ROOT file and publish +template <typename T = void> +framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true) +{ + using Reader = o2::framework::RootTreeReader; + using Output = o2::framework::Output; + auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); + auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); + + // a creator callback for the actual reader instance + auto creator = [dto, mco, propagateMC](const char* treename, const char* filename, int nofEvents, Reader::PublishingMode publishingMode, o2::header::DataHeader::SubSpecificationType subSpec, const char* branchname, const char* mcbranchname, Reader::SpecialPublishHook* publishhook = nullptr) { + constexpr auto persistency = o2::framework::Lifetime::Timeframe; + if (propagateMC) { + return std::make_shared<Reader>(treename, + filename, + nofEvents, + publishingMode, + Output{mco.origin, mco.description, subSpec, persistency}, + mcbranchname, + Reader::BranchDefinition<T>{Output{dto.origin, dto.description, subSpec, persistency}, branchname}, + publishhook); + } else { + return std::make_shared<Reader>(treename, + filename, + nofEvents, + publishingMode, + Reader::BranchDefinition<T>{Output{dto.origin, dto.description, subSpec, persistency}, branchname}, + publishhook); + } + }; + + return createPublisherSpec(config, propagateMC, creator); +} + +namespace workflow_reader +{ +using Reader = o2::framework::RootTreeReader; +using Creator = std::function<std::shared_ptr<Reader>(const char*, const char*, int, Reader::PublishingMode, o2::header::DataHeader::SubSpecificationType, const char*, const char*, Reader::SpecialPublishHook*)>; +} // namespace workflow_reader + +framework::DataProcessorSpec createPublisherSpec(PublisherConf const& config, bool propagateMC, workflow_reader::Creator creator); + +} // end namespace tpc +} // end namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h similarity index 84% rename from Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h rename to Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h index 52a38fb2cb2c3..14dfeb3abab30 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,9 +18,12 @@ #include "Framework/CompletionPolicy.h" #include "Framework/InputSpec.h" +#include "Framework/InputSpan.h" #include "Framework/DeviceSpec.h" #include "DataFormatsTPC/TPCSectorHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "TPCBase/Sector.h" +#include <fmt/ostream.h> #include <vector> #include <string> #include <stdexcept> @@ -85,7 +89,8 @@ class TPCSectorCompletionPolicy return std::regex_match(device.name.begin(), device.name.end(), std::regex(expression.c_str())); }; - auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers](framework::CompletionPolicy::InputSet inputs) -> framework::CompletionPolicy::CompletionOp { + auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers, pTpcSectorMask = mTpcSectorMask](framework::InputSpan const& inputs) -> framework::CompletionPolicy::CompletionOp { + unsigned long tpcSectorMask = pTpcSectorMask ? *pTpcSectorMask : 0xFFFFFFFFF; std::bitset<NSectors> validSectors = 0; bool haveMatchedInput = false; uint64_t activeSectors = 0; @@ -114,18 +119,18 @@ class TPCSectorCompletionPolicy inputType = idx; } else if (inputType != idx) { std::stringstream error; - error << "routing error, input messages must all be of the same type previously bound to " - << inputMatchers[inputType] - << dh->dataOrigin.as<std::string>() + "/" - << dh->dataDescription.as<std::string>() + "/" + dh->subSpecification; + error << fmt::format("routing error, input messages must all be of the same type previously bound to {} {}/{}/{}", + inputMatchers[inputType], + dh->dataOrigin, + dh->dataDescription, dh->subSpecification); throw std::runtime_error(error.str()); } auto const* sectorHeader = framework::DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref); if (sectorHeader == nullptr) { throw std::runtime_error("TPC sector header missing on header stack"); } - activeSectors |= sectorHeader->activeSectors; - validSectors |= sectorHeader->sectorBits; + activeSectors |= (sectorHeader->activeSectors & tpcSectorMask); + validSectors |= (sectorHeader->sectorBits & tpcSectorMask); break; } } @@ -139,8 +144,8 @@ class TPCSectorCompletionPolicy if (sectorHeader == nullptr) { throw std::runtime_error("TPC sector header missing on header stack"); } - activeSectors |= sectorHeader->activeSectors; - validSectorsExternal[idx] |= sectorHeader->sectorBits; + activeSectors |= (sectorHeader->activeSectors & tpcSectorMask); + validSectorsExternal[idx] |= (sectorHeader->sectorBits & tpcSectorMask); break; } } @@ -196,16 +201,18 @@ class TPCSectorCompletionPolicy void init(Arg&& arg, Args&&... args) { using Type = std::decay_t<Arg>; - if constexpr (std::is_same<Type, framework::InputSpec>::value) { + if constexpr (std::is_same_v<Type, framework::InputSpec>) { mInputMatchers.emplace_back(std::move(arg)); - } else if constexpr (std::is_same<Type, TPCSectorCompletionPolicy::Config>::value) { + } else if constexpr (std::is_same_v<Type, TPCSectorCompletionPolicy::Config>) { switch (arg) { case Config::RequireAll: mRequireAll = true; break; } - } else if constexpr (std::is_same<Type, std::vector<o2::framework::InputSpec>*>::value) { + } else if constexpr (std::is_same_v<Type, std::vector<o2::framework::InputSpec>*>) { mExternalInputMatchers = arg; + } else if constexpr (std::is_same_v<Type, unsigned long*> || std::is_same_v<Type, const unsigned long*>) { + mTpcSectorMask = arg; } else { static_assert(framework::always_static_assert_v<Type>); } @@ -220,6 +227,7 @@ class TPCSectorCompletionPolicy // - They are controlled externally and the external entity can modify them, e.g. after parsing command line arguments. // - They are all matched independently, it is not sufficient that one of them is present for all sectors const std::vector<framework::InputSpec>* mExternalInputMatchers = nullptr; + const unsigned long* mTpcSectorMask = nullptr; bool mRequireAll = false; }; } // namespace tpc diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TrackReaderSpec.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TrackReaderSpec.h new file mode 100644 index 0000000000000..b073cff8bdb12 --- /dev/null +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TrackReaderSpec.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackReaderSpec.h + +#ifndef O2_TPC_TRACKREADER +#define O2_TPC_TRACKREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ +///< DPL device to read and send the TPC tracks (+MC) info + +class TrackReader : public Task +{ + public: + TrackReader(bool useMC = true); + ~TrackReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void accumulate(int from, int n); + void connectTree(const std::string& filename); + + std::vector<o2::tpc::TrackTPC>*mTracksInp = nullptr, mTracksOut; + std::vector<o2::tpc::TPCClRefElem>*mCluRefVecInp = nullptr, mCluRefVecOut; + std::vector<o2::MCCompLabel>*mMCTruthInp = nullptr, mMCTruthOut; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + + std::string mInputFileName = "tpctracks.root"; + std::string mTrackTreeName = "tpcrec"; + std::string mTrackBranchName = "TPCTracks"; + std::string mClusRefBranchName = "ClusRefs"; + std::string mTrackMCTruthBranchName = "TPCTracksMCTruth"; +}; + +/// create a processor spec +/// read TPC track data from a root file +framework::DataProcessorSpec getTPCTrackReaderSpec(bool useMC = true); + +} // namespace tpc +} // namespace o2 + +#endif /* O2_TPC_TRACKREADER */ diff --git a/Detectors/TPC/workflow/readers/src/ClusterReaderSpec.cxx b/Detectors/TPC/workflow/readers/src/ClusterReaderSpec.cxx new file mode 100644 index 0000000000000..fd52412ea05c4 --- /dev/null +++ b/Detectors/TPC/workflow/readers/src/ClusterReaderSpec.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec1.cxx +/// @author David Rohr + +#include "Framework/WorkflowSpec.h" +#include "DPLUtils/RootTreeReader.h" +#include "TPCReaderWorkflow/PublisherSpec.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "TPCBase/Sector.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +framework::DataProcessorSpec getClusterReaderSpec(bool useMC, const std::vector<int>* tpcSectors, const std::vector<int>* laneConfiguration) +{ + static RootTreeReader::SpecialPublishHook hook{[](std::string_view name, ProcessingContext& context, o2::framework::Output const& output, char* data) -> bool { + if (TString(name.data()).Contains("TPCDigitMCTruth") || TString(name.data()).Contains("TPCClusterHwMCTruth") || TString(name.data()).Contains("TPCClusterNativeMCTruth")) { + auto storedlabels = reinterpret_cast<o2::dataformats::IOMCTruthContainerView const*>(data); + o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel> flatlabels; + storedlabels->copyandflatten(flatlabels); + //LOG(INFO) << "PUBLISHING CONST LABELS " << flatlabels.getNElements(); + context.outputs().snapshot(output, flatlabels); + return true; + } + return false; + }}; + + std::vector<int> defaultSectors; + std::vector<int> defaultLaneConfig; + if (tpcSectors == nullptr) { + defaultSectors.resize(Sector::MAXSECTOR); + std::iota(defaultSectors.begin(), defaultSectors.end(), 0); + tpcSectors = &defaultSectors; + } + if (laneConfiguration == nullptr) { + defaultLaneConfig = *tpcSectors; + laneConfiguration = &defaultLaneConfig; + } + + return std::move(o2::tpc::getPublisherSpec(PublisherConf{ + "tpc-native-cluster-reader", + "tpc-native-clusters.root", + "tpcrec", + {"clusterbranch", "TPCClusterNative", "Branch with TPC native clusters"}, + {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, + OutputSpec{"TPC", "CLUSTERNATIVE"}, + OutputSpec{"TPC", "CLNATIVEMCLBL"}, + *tpcSectors, + *laneConfiguration, + &hook}, + useMC)); +} + +} // end namespace tpc +} // end namespace o2 diff --git a/Detectors/TPC/workflow/readers/src/PublisherSpec.cxx b/Detectors/TPC/workflow/readers/src/PublisherSpec.cxx new file mode 100644 index 0000000000000..6816a0e607894 --- /dev/null +++ b/Detectors/TPC/workflow/readers/src/PublisherSpec.cxx @@ -0,0 +1,251 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file PublisherSpec.cxx +/// @author Matthias Richter +/// @since 2018-12-06 +/// @brief Processor spec for a reader of TPC data from ROOT file + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "TPCReaderWorkflow/PublisherSpec.h" +#include "Headers/DataHeader.h" +#include "TPCBase/Sector.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include <memory> // for make_shared, make_unique, unique_ptr +#include <array> +#include <vector> +#include <utility> // std::move +#include <stdexcept> //std::invalid_argument +#include <TFile.h> +#include <TTree.h> +#include <TBranch.h> + +using namespace o2::framework; +using namespace o2::header; + +namespace o2 +{ +namespace tpc +{ + +/// create a processor spec +/// read data from multiple tree branches from ROOT file and publish +/// data are expected to be stored in separated branches per sector, the default +/// branch name is configurable, sector number is apended as extension '_n' +DataProcessorSpec createPublisherSpec(PublisherConf const& config, bool propagateMC, workflow_reader::Creator creator) +{ + if (config.tpcSectors.size() == 0 || config.outputIds.size() == 0) { + throw std::invalid_argument("need TPC sector and output id configuration"); + } + constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; + enum struct SectorMode { + Sector, // stored in sector branches + Full, // full TPC stored in one branch + }; + struct ProcessAttributes { + std::vector<int> sectors; + std::vector<int> outputIds; + std::vector<o2::header::DataHeader::SubSpecificationType> zeroLengthOutputs; + uint64_t activeSectors = 0; + std::array<std::shared_ptr<RootTreeReader>, NSectors> readers; + bool terminateOnEod = false; + bool finished = false; + SectorMode sectorMode = SectorMode::Sector; + }; + + auto initFunction = [config, propagateMC, creator](InitContext& ic) { + // get the option from the init context + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + auto treename = ic.options().get<std::string>("treename"); + auto clbrName = ic.options().get<std::string>(config.databranch.option.c_str()); + auto mcbrName = ic.options().get<std::string>(config.mcbranch.option.c_str()); + auto nofEvents = ic.options().get<int>("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + // do a runtime check if the branch name without sector number suffix is found in the file + // if found the publisher will publish the single data set at one output route and empty + // messages at all the others + auto checkSectorMode = [&filename, &treename, &clbrName]() -> SectorMode { + std::unique_ptr<TFile> file(TFile::Open(filename.c_str())); + if (file) { + TTree* tree = reinterpret_cast<TTree*>(file->GetObjectChecked(treename.c_str(), "TTree")); + if (tree) { + const auto brlist = tree->GetListOfBranches(); + for (TObject const* entry : *brlist) { + if (clbrName == entry->GetName()) { + return SectorMode::Full; + } + } + } + file->Close(); + } + return SectorMode::Sector; + }; + + auto processAttributes = std::make_shared<ProcessAttributes>(); + { + processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); + processAttributes->sectorMode = checkSectorMode(); + auto& sectors = processAttributes->sectors; + auto& activeSectors = processAttributes->activeSectors; + auto& readers = processAttributes->readers; + auto& outputIds = processAttributes->outputIds; + auto& sectorMode = processAttributes->sectorMode; + + sectors = config.tpcSectors; + outputIds = config.outputIds; + for (auto const& s : sectors) { + // set the mask of active sectors + if (s >= NSectors) { + std::string message = std::string("invalid sector range specified, allowed 0-") + std::to_string(NSectors - 1); + // FIXME should probably be FATAL, but this doesn't seem to be handled in the DPL control flow + // at least the process is not marked dead in the DebugGUI + LOG(ERROR) << message; + throw std::invalid_argument(message); + } + activeSectors |= (uint64_t)0x1 << s; + } + + // set up the tree interface + // TODO: parallelism on sectors needs to be implemented as selector in the reader + // the data is now in parallel branches, as first attempt use an array of readers + auto outputId = outputIds.begin(); + for (auto const& sector : sectors) { + o2::header::DataHeader::SubSpecificationType subSpec = *outputId; + std::string sectorfile = filename; + if (filename.find('%') != std::string::npos) { + vector<char> formattedname(filename.length() + 10, 0); + snprintf(formattedname.data(), formattedname.size() - 1, filename.c_str(), sector); + sectorfile = formattedname.data(); + } + std::string clusterbranchname = clbrName; + std::string mcbranchname = mcbrName; + if (sectorMode == SectorMode::Sector) { + clusterbranchname += "_" + std::to_string(sector); + mcbranchname += "_" + std::to_string(sector); + } + readers[sector] = creator(treename.c_str(), // tree name + sectorfile.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + subSpec, + clusterbranchname.c_str(), // name of data branch + mcbranchname.c_str(), // name of mc label branch + config.hook); + if (sectorMode == SectorMode::Full) { + break; + } + if (++outputId == outputIds.end()) { + outputId = outputIds.begin(); + } + } + if (sectorMode == SectorMode::Full) { + // the slot of the first configured sector is used to publish the full set, all others removed + sectors.resize(1); + // the data will be published at first configured output id, zero-length data on all other output ids + processAttributes->zeroLengthOutputs.assign(++outputId, outputIds.end()); + } + } + + // set up the processing function + // using by-copy capture of the worker instance shared pointer + // the shared pointer makes sure to clean up the instance when the processing + // function gets out of scope + // FIXME: wanted to use it = sectors.begin() in the variable capture but the iterator + // is const and can not be incremented + auto processingFct = [processAttributes, config](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + bool eos = false; + auto const& sectors = processAttributes->sectors; + for (auto const& sector : sectors) { + auto& activeSectors = processAttributes->activeSectors; + auto& readers = processAttributes->readers; + o2::tpc::TPCSectorHeader header{sector}; + if (processAttributes->sectorMode == SectorMode::Full) { + header.sectorBits = activeSectors; + } + header.activeSectors = activeSectors; + auto& r = *(readers[sector].get()); + + // increment the reader and invoke it for the processing context + if (r.next()) { + // there is data, run the reader + r(pc, header); + } else { + // no more data, delete the reader + readers[sector].reset(); + eos = true; + } + } + + if (eos) { + processAttributes->finished = true; + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } else { + // publish empty events + auto dto = DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); + auto mco = DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); + o2::tpc::TPCSectorHeader header{0}; + header.sectorBits = 0; + header.activeSectors = processAttributes->activeSectors; + for (auto const& subSpec : processAttributes->zeroLengthOutputs) { + pc.outputs().make<char>({dto.origin, dto.description, subSpec, Lifetime::Timeframe, {header}}); + if (pc.outputs().isAllowed({mco.origin, mco.description, subSpec})) { + pc.outputs().make<char>({mco.origin, mco.description, subSpec, Lifetime::Timeframe, {header}}); + } + } + } + }; + + // return the actual processing function as a lambda function using variables + // of the init function + return processingFct; + }; + + auto createOutputSpecs = [&config, propagateMC]() { + std::vector<OutputSpec> outputSpecs; + for (size_t n = 0; n < config.outputIds.size(); ++n) { + o2::header::DataHeader::SubSpecificationType subSpec = config.outputIds[n]; + auto dto = DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); + auto mco = DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); + outputSpecs.emplace_back(OutputSpec{{"output"}, dto.origin, dto.description, subSpec, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, mco.origin, mco.description, subSpec, Lifetime::Timeframe}); + } + } + return std::move(outputSpecs); + }; + + auto& dtb = config.databranch; + auto& mcb = config.mcbranch; + return DataProcessorSpec{config.processName.c_str(), + Inputs{}, // no inputs + {createOutputSpecs()}, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, config.defaultFileName.c_str(), {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, + {dtb.option.c_str(), VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, + {mcb.option.c_str(), VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, + {"nevents", VariantType::Int, -1, {"number of events to run"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} +} // end namespace tpc +} // end namespace o2 diff --git a/Detectors/TPC/workflow/readers/src/TrackReaderSpec.cxx b/Detectors/TPC/workflow/readers/src/TrackReaderSpec.cxx new file mode 100644 index 0000000000000..d3c1eb76a5f63 --- /dev/null +++ b/Detectors/TPC/workflow/readers/src/TrackReaderSpec.cxx @@ -0,0 +1,142 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackReaderSpec.cxx + +#include <vector> +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +TrackReader::TrackReader(bool useMC) +{ + mUseMC = useMC; +} + +void TrackReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("infile")); + connectTree(mInputFileName); +} + +void TrackReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + accumulate(ent, 1); // to really accumulate all, use accumulate(ent,mTree->GetEntries()); + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + + pc.outputs().snapshot(Output{"TPC", "TRACKS", 0, Lifetime::Timeframe}, mTracksOut); + pc.outputs().snapshot(Output{"TPC", "CLUSREFS", 0, Lifetime::Timeframe}, mCluRefVecOut); + if (mUseMC) { + pc.outputs().snapshot(Output{"TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe}, mMCTruthOut); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void TrackReader::accumulate(int from, int n) +{ + assert(from + n <= mTree->GetEntries()); + if (n == 1) { + mTree->GetEntry(from); + mTracksOut.swap(*mTracksInp); + mCluRefVecOut.swap(*mCluRefVecInp); + if (mUseMC) { + std::copy(mMCTruthInp->begin(), mMCTruthInp->end(), std::back_inserter(mMCTruthOut)); + } + } else { + for (int iev = 0; iev < n; iev++) { + mTree->GetEntry(from + iev); + // + uint32_t shift = mCluRefVecOut.size(); // during accumulation clusters refs need to be shifted + + auto cl0 = mCluRefVecInp->begin(); + auto cl1 = mCluRefVecInp->end(); + std::copy(cl0, cl1, std::back_inserter(mCluRefVecOut)); + + auto tr0 = mTracksInp->begin(); + auto tr1 = mTracksInp->end(); + // fix cluster references + if (shift) { + for (auto tr = tr0; tr != tr1; tr++) { + tr->shiftFirstClusterRef(shift); + } + } + std::copy(tr0, tr1, std::back_inserter(mTracksOut)); + // MC + if (mUseMC) { + std::copy(mMCTruthInp->begin(), mMCTruthInp->end(), std::back_inserter(mMCTruthOut)); + } + } + } + LOG(INFO) << "TPCTrackReader pushes " << mTracksOut.size() << " tracks from entries " << from << " : " << from + n - 1; +} + +void TrackReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + if (!(mFile && !mFile->IsZombie())) { + throw std::runtime_error("Error opening tree file"); + } + mTree.reset((TTree*)mFile->Get(mTrackTreeName.c_str())); + if (!mTree) { + throw std::runtime_error("Error opening tree"); + } + + mTree->SetBranchAddress(mTrackBranchName.c_str(), &mTracksInp); + mTree->SetBranchAddress(mClusRefBranchName.c_str(), &mCluRefVecInp); + if (mUseMC) { + if (mTree->GetBranch(mTrackMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mTrackMCTruthBranchName.c_str(), &mMCTruthInp); + LOG(INFO) << "Will use MC-truth from " << mTrackMCTruthBranchName; + } else { + LOG(INFO) << "MC-truth is missing"; + mUseMC = false; + } + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getTPCTrackReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("TPC", "TRACKS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("TPC", "CLUSREFS", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "tpc-track-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<TrackReader>(useMC)}, + Options{ + {"infile", VariantType::String, "tpctracks.root", {"Name of the input track file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/ApplyCCDBCalibSpec.cxx b/Detectors/TPC/workflow/src/ApplyCCDBCalibSpec.cxx new file mode 100644 index 0000000000000..17d8ab637db8a --- /dev/null +++ b/Detectors/TPC/workflow/src/ApplyCCDBCalibSpec.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/CCDBParamSpec.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Logger.h" + +#include "TPCBase/ParameterGas.h" +#include "TPCCalibration/CalibLaserTracks.h" +#include "TPCWorkflow/ApplyCCDBCalibSpec.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class ApplyCCDBCalibDevice : public o2::framework::Task +{ + public: + void init(InitContext& ic) final + { + //const int minEnt = ic.options().get<int>("min-tfs"); + mReferenceDriftV = o2::conf::ConfigurableParam::getValueAs<float>("TPCGasParam.DriftV"); + LOGP(info, "Setting reference drift velocity to {}", mReferenceDriftV); + } + + void run(ProcessingContext& pc) final + { + applyLaserVDrift(pc.inputs()); + } + + private: + float mReferenceDriftV{}; ///< reference drift velocity to apply correction to + float mDriftV{}; ///< present drift velocity + std::unique_ptr<const LtrCalibData> mLtrCalibData; ///< presently used laser track calibration + + void applyLaserVDrift(InputRecord& inputs); + void updateVDrift(); +}; + +void ApplyCCDBCalibDevice::applyLaserVDrift(InputRecord& inputs) +{ + auto ltrCalibPtr = inputs.get<LtrCalibData*>("calibLaserTracks"); + if (!mLtrCalibData) { + mLtrCalibData.reset(ltrCalibPtr.release()); + LOGP(info, "Laser track calibration initialized: {} - {}: A - {} C - {}", mLtrCalibData->firstTime, mLtrCalibData->lastTime, mLtrCalibData->dvCorrectionA, mLtrCalibData->dvCorrectionC); + updateVDrift(); + } else { + if (ltrCalibPtr->firstTime != mLtrCalibData->firstTime) { + mLtrCalibData.reset(ltrCalibPtr.release()); + LOGP(info, "Laser track calibration updated: {} - {}: A - {} C - {}, was {} - {}: A - {} C - {}", mLtrCalibData->firstTime, mLtrCalibData->lastTime, mLtrCalibData->dvCorrectionA, mLtrCalibData->dvCorrectionC, ltrCalibPtr->firstTime, ltrCalibPtr->lastTime, ltrCalibPtr->dvCorrectionA, ltrCalibPtr->dvCorrectionC); + updateVDrift(); + } + } +} + +void ApplyCCDBCalibDevice::updateVDrift() +{ + const float oldDriftV = mDriftV; + mDriftV = mReferenceDriftV * mLtrCalibData->getDriftVCorrection(); + LOGP(info, "updating drift velocity correction to {}, was {}, reference is {} (cm / us)", mDriftV, oldDriftV, mReferenceDriftV); + o2::conf::ConfigurableParam::setValue<float>("TPCGasParam", "DriftV", mDriftV); +} + +//______________________________________________________________________________ +DataProcessorSpec getApplyCCDBCalibSpec() +{ + using device = ApplyCCDBCalibDevice; + + std::vector<InputSpec> inputs{ + InputSpec{"calibLaserTracks", "TPC", "CalibLaserTracks", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/LaserTracks")}, + InputSpec{"sometimer", "TST", "BAR", 0, Lifetime::Timer, {startTimeParamSpec(1638548475371)}}, + }; + + return DataProcessorSpec{ + "tpc-apply-ccdb-calib", + inputs, + Outputs{}, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + //{"min-tfs", VariantType::Int, 100, {"minimum number of TFs with enough laser tracks to finalize a slot"}}, + }}; +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/CATrackerSpec.cxx b/Detectors/TPC/workflow/src/CATrackerSpec.cxx deleted file mode 100644 index 2b16a80d6f4ef..0000000000000 --- a/Detectors/TPC/workflow/src/CATrackerSpec.cxx +++ /dev/null @@ -1,831 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CATrackerSpec.cxx -/// @author Matthias Richter -/// @since 2018-04-18 -/// @brief Processor spec for running TPC CA tracking - -#include "TPCWorkflow/CATrackerSpec.h" -#include "Headers/DataHeader.h" -#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs -#include "Framework/DataRefUtils.h" -#include "Framework/DataSpecUtils.h" -#include "Framework/DeviceSpec.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/InputRecordWalker.h" -#include "Framework/SerializationMethods.h" -#include "Framework/Logger.h" -#include "Framework/CallbackService.h" -#include "DataFormatsTPC/TPCSectorHeader.h" -#include "DataFormatsTPC/ClusterGroupAttribute.h" -#include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/ClusterNativeHelper.h" -#include "DataFormatsTPC/CompressedClusters.h" -#include "DataFormatsTPC/Helpers.h" -#include "DataFormatsTPC/ZeroSuppression.h" -#include "TPCReconstruction/GPUCATracking.h" -#include "TPCReconstruction/TPCFastTransformHelperO2.h" -#include "DataFormatsTPC/Digit.h" -#include "TPCFastTransform.h" -#include "TPCdEdxCalibrationSplines.h" -#include "DPLUtils/DPLRawParser.h" -#include "DetectorsBase/MatLayerCylSet.h" -#include "DetectorsRaw/HBFUtils.h" -#include "TPCBase/RDHUtils.h" -#include "GPUO2InterfaceConfiguration.h" -#include "GPUO2InterfaceQA.h" -#include "TPCCFCalibration.h" -#include "GPUDisplayBackend.h" -#ifdef GPUCA_BUILD_EVENT_DISPLAY -#include "GPUDisplayBackendGlfw.h" -#endif -#include "DataFormatsParameters/GRPObject.h" -#include "TPCBase/Sector.h" -#include "TPCBase/Utils.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "Algorithm/Parser.h" -#include <boost/filesystem.hpp> -#include <memory> // for make_shared -#include <vector> -#include <iomanip> -#include <stdexcept> -#include <regex> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include "GPUReconstructionConvert.h" -#include "DetectorsRaw/RDHUtils.h" -#include <TStopwatch.h> -#include <TObjArray.h> -#include <TH1F.h> -#include <TH2F.h> -#include <TH1D.h> - -using namespace o2::framework; -using namespace o2::header; -using namespace o2::gpu; -using namespace o2::base; -using namespace o2::dataformats; -using namespace o2::tpc::reco_workflow; - -namespace o2 -{ -namespace tpc -{ - -DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config const& specconfig, std::vector<int> const& tpcsectors) -{ - if (specconfig.outputCAClusters && !specconfig.caClusterer && !specconfig.decompressTPC) { - throw std::runtime_error("inconsistent configuration: cluster output is only possible if CA clusterer is activated"); - } - - static TStopwatch timer; - - constexpr static size_t NSectors = Sector::MAXSECTOR; - constexpr static size_t NEndpoints = 20; //TODO: get from mapper? - using ClusterGroupParser = o2::algorithm::ForwardParser<ClusterGroupHeader>; - struct ProcessAttributes { - std::unique_ptr<ClusterGroupParser> parser; - std::unique_ptr<GPUCATracking> tracker; - std::unique_ptr<GPUDisplayBackend> displayBackend; - std::unique_ptr<TPCFastTransform> fastTransform; - std::unique_ptr<TPCdEdxCalibrationSplines> dEdxSplines; - std::unique_ptr<TPCCFCalibration> tpcCalibration; - std::unique_ptr<GPUSettingsQA> qaConfig; - std::unique_ptr<GPUO2InterfaceQA> qa; - std::vector<int> clusterOutputIds; - unsigned long outputBufferSize = 0; - unsigned long tpcSectorMask = 0; - int verbosity = 1; - bool readyToQuit = false; - bool allocateOutputOnTheFly = false; - bool suppressOutput = false; - }; - - auto processAttributes = std::make_shared<ProcessAttributes>(); - for (auto s : tpcsectors) { - processAttributes->tpcSectorMask |= (1ul << s); - } - auto initFunction = [processAttributes, specconfig](InitContext& ic) { - GPUO2InterfaceConfiguration config; - GPUSettingsO2 confParam; - { - auto& parser = processAttributes->parser; - auto& tracker = processAttributes->tracker; - parser = std::make_unique<ClusterGroupParser>(); - tracker = std::make_unique<GPUCATracking>(); - - // Create configuration object and fill settings - const auto grp = o2::parameters::GRPObject::loadFrom("o2sim_grp.root"); - if (grp) { - config.configEvent.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; - config.configEvent.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; // Number of timebins in timeframe if continuous, 0 otherwise - LOG(INFO) << "Initializing run paramerers from GRP bz=" << config.configEvent.solenoidBz << " cont=" << grp->isDetContinuousReadOut(o2::detectors::DetID::TPC); - } else { - throw std::runtime_error("Failed to initialize run parameters from GRP"); - } - confParam = config.ReadConfigurableParam(); - processAttributes->allocateOutputOnTheFly = confParam.allocateOutputOnTheFly; - processAttributes->outputBufferSize = confParam.outputBufferSize; - processAttributes->suppressOutput = (confParam.dump == 2); - config.configInterface.dumpEvents = confParam.dump; - config.configInterface.dropSecondaryLegs = confParam.dropSecondaryLegs; - config.configInterface.memoryBufferScaleFactor = confParam.memoryBufferScaleFactor; - if (confParam.display) { -#ifdef GPUCA_BUILD_EVENT_DISPLAY - processAttributes->displayBackend.reset(new GPUDisplayBackendGlfw); - config.configProcessing.eventDisplay = processAttributes->displayBackend.get(); - LOG(INFO) << "Event display enabled"; -#else - throw std::runtime_error("Standalone Event Display not enabled at build time!"); -#endif - } - - if (config.configEvent.continuousMaxTimeBin == -1) { - config.configEvent.continuousMaxTimeBin = (o2::raw::HBFUtils::Instance().getNOrbitsPerTF() * o2::constants::lhc::LHCMaxBunches + 2 * constants::LHCBCPERTIMEBIN - 2) / constants::LHCBCPERTIMEBIN; - } - if (config.configProcessing.deviceNum == -2) { - int myId = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; - int idMax = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices; - config.configProcessing.deviceNum = myId; - LOG(INFO) << "GPU device number selected from pipeline id: " << myId << " / " << idMax; - } - config.configProcessing.runMC = specconfig.processMC; - if (specconfig.outputQA) { - if (!config.configProcessing.runQA) { - config.configQA.shipToQC = true; - } - config.configProcessing.runQA = true; - } - config.configReconstruction.NWaysOuter = true; - config.configInterface.outputToExternalBuffers = true; - - // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) with this instance of GPUCATracking - config.configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, - GPUDataTypes::RecoStep::TPCSliceTracking, - GPUDataTypes::RecoStep::TPCMerging, - GPUDataTypes::RecoStep::TPCCompression); - - config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, !confParam.synchronousProcessing); - if (confParam.synchronousProcessing) { - config.configReconstruction.useMatLUT = false; - } - - // Alternative steps: TRDTracking | ITSTracking - config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); - // Alternative inputs: GPUDataTypes::InOutType::TRDTracklets - config.configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks, GPUDataTypes::InOutType::TPCCompressedClusters); - // Alternative outputs: GPUDataTypes::InOutType::TPCSectorTracks, GPUDataTypes::InOutType::TRDTracks - if (specconfig.caClusterer) { // Override some settings if we have raw data as input - config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw); - config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true); - config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); - } - if (specconfig.decompressTPC) { - config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); - config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters); - config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); - config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); - } - - // Create and forward data objects for TPC transformation, material LUT, ... - if (confParam.transformationFile.size()) { - processAttributes->fastTransform = nullptr; - config.configCalib.fastTransform = TPCFastTransform::loadFromFile(confParam.transformationFile.c_str()); - } else { - processAttributes->fastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0)); - config.configCalib.fastTransform = processAttributes->fastTransform.get(); - } - if (config.configCalib.fastTransform == nullptr) { - throw std::invalid_argument("GPUCATracking: initialization of the TPC transformation failed"); - } - if (confParam.matLUTFile.size()) { - config.configCalib.matLUT = o2::base::MatLayerCylSet::loadFromFile(confParam.matLUTFile.c_str(), "MatBud"); - } - if (confParam.dEdxFile.size()) { - processAttributes->dEdxSplines.reset(new TPCdEdxCalibrationSplines(confParam.dEdxFile.c_str())); - } else { - processAttributes->dEdxSplines.reset(new TPCdEdxCalibrationSplines); - } - - config.configCalib.dEdxSplines = processAttributes->dEdxSplines.get(); - - if (boost::filesystem::exists(confParam.gainCalibFile)) { - LOG(INFO) << "Loading tpc gain correction from file " << confParam.gainCalibFile; - const auto* gainMap = o2::tpc::utils::readCalPads(confParam.gainCalibFile, "GainMap")[0]; - processAttributes->tpcCalibration.reset(new TPCCFCalibration{*gainMap}); - } else { - if (not confParam.gainCalibFile.empty()) { - LOG(WARN) << "Couldn't find tpc gain correction file " << confParam.gainCalibFile << ". Not applying any gain correction."; - } - processAttributes->tpcCalibration.reset(new TPCCFCalibration{}); - } - config.configCalib.tpcCalibration = processAttributes->tpcCalibration.get(); - - // Sample code what needs to be done for the TRD Geometry, when we extend this to TRD tracking. - /*o2::base::GeometryManager::loadGeometry(); - o2::trd::Geometry gm; - gm.createPadPlaneArray(); - gm.createClusterMatrixArray(); - std::unique_ptr<o2::trd::GeometryFlat> gf(gm); - config.trdGeometry = gf.get();*/ - - // Configuration is prepared, initialize the tracker. - if (tracker->initialize(config) != 0) { - throw std::invalid_argument("GPUCATracking initialization failed"); - } - if (specconfig.outputQA) { - processAttributes->qaConfig.reset(new GPUSettingsQA(config.configQA)); - processAttributes->qa = std::make_unique<GPUO2InterfaceQA>(processAttributes->qaConfig.get()); - } - timer.Stop(); - timer.Reset(); - } - - auto& callbacks = ic.services().get<CallbackService>(); - callbacks.set(CallbackService::Id::RegionInfoCallback, [&processAttributes, confParam](FairMQRegionInfo const& info) { - if (info.size) { - int fd = 0; - if (confParam.mutexMemReg) { - fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); - if (fd == -1) { - throw std::runtime_error("Error opening lock file"); - } - if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking file"); - } - } - auto& tracker = processAttributes->tracker; - if (tracker->registerMemoryForGPU(info.ptr, info.size)) { - throw std::runtime_error("Error registering memory for GPU"); - } - if (confParam.mutexMemReg) { - if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking file"); - } - close(fd); - } - } - }); - - // the callback to be set as hook at stop of processing for the framework - auto printTiming = []() { - LOGF(INFO, "TPC CATracker total timing: Cpu: %.3e Real: %.3e s in %d slots", timer.CpuTime(), timer.RealTime(), timer.Counter() - 1); - }; - ic.services().get<CallbackService>().set(CallbackService::Id::Stop, printTiming); - - auto processingFct = [processAttributes, specconfig](ProcessingContext& pc) { - if (processAttributes->readyToQuit) { - return; - } - auto cput = timer.CpuTime(); - timer.Start(false); - auto& parser = processAttributes->parser; - auto& tracker = processAttributes->tracker; - auto& verbosity = processAttributes->verbosity; - // FIXME cleanup almost duplicated code - std::vector<ConstMCLabelContainerView> mcInputs; - std::vector<gsl::span<const char>> inputs; - struct InputRef { - DataRef data; - DataRef labels; - }; - std::map<int, InputRef> inputrefs; - const CompressedClustersFlat* pCompClustersFlat; - size_t compClustersFlatDummyMemory[(sizeof(CompressedClustersFlat) + sizeof(size_t) - 1) / sizeof(size_t)]; - CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast<CompressedClustersFlat&>(compClustersFlatDummyMemory); - CompressedClusters compClustersDummy; - o2::gpu::GPUTrackingInOutZS tpcZS; - std::vector<const void*> tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - std::vector<unsigned int> tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const void** tpcZSmetaPointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const unsigned int* tpcZSmetaSizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - std::array<gsl::span<const o2::tpc::Digit>, NSectors> inputDigits; - std::vector<ConstMCLabelContainerView> inputDigitsMC; - std::array<int, constants::MAXSECTOR> inputDigitsMCIndex; - std::array<const ConstMCLabelContainerView*, constants::MAXSECTOR> inputDigitsMCPtrs; - std::array<unsigned int, NEndpoints * NSectors> tpcZSonTheFlySizes; - gsl::span<const ZeroSuppressedContainer8kb> inputZS; - - // unsigned int totalZSPages = 0; - if (specconfig.processMC) { - std::vector<InputSpec> filter = { - {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}, Lifetime::Timeframe}, - {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "CLNATIVEMCLBL"}, Lifetime::Timeframe}, - }; - unsigned long recvMask = 0; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - auto const* sectorHeader = DataRefUtils::getHeader<TPCSectorHeader*>(ref); - if (sectorHeader == nullptr) { - // FIXME: think about error policy - LOG(ERROR) << "sector header missing on header stack"; - return; - } - const int sector = sectorHeader->sector(); - if (sector < 0) { - continue; - } - if (recvMask & sectorHeader->sectorBits) { - throw std::runtime_error("can only have one MC data set per sector"); - } - recvMask |= sectorHeader->sectorBits; - inputrefs[sector].labels = ref; - if (specconfig.caClusterer) { - inputDigitsMCIndex[sector] = inputDigitsMC.size(); - inputDigitsMC.emplace_back(ConstMCLabelContainerView(pc.inputs().get<gsl::span<char>>(ref))); - } - } - if (recvMask != processAttributes->tpcSectorMask) { - throw std::runtime_error("Incomplete set of MC labels received"); - } - if (specconfig.caClusterer) { - for (unsigned int i = 0; i < NSectors; i++) { - LOG(INFO) << "GOT MC LABELS FOR SECTOR " << i << " -> " << inputDigitsMC[inputDigitsMCIndex[i]].getNElements(); - inputDigitsMCPtrs[i] = &inputDigitsMC[inputDigitsMCIndex[i]]; - } - } - } - - if (!specconfig.decompressTPC && (!specconfig.caClusterer || ((!specconfig.zsOnTheFly || specconfig.processMC) && !specconfig.zsDecoder))) { - std::vector<InputSpec> filter = { - {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe}, - {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe}, - }; - unsigned long recvMask = 0; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - auto const* sectorHeader = DataRefUtils::getHeader<TPCSectorHeader*>(ref); - if (sectorHeader == nullptr) { - throw std::runtime_error("sector header missing on header stack"); - } - const int sector = sectorHeader->sector(); - if (sector < 0) { - continue; - } - if (recvMask & sectorHeader->sectorBits) { - throw std::runtime_error("can only have one cluster data set per sector"); - } - recvMask |= sectorHeader->sectorBits; - inputrefs[sector].data = ref; - if (specconfig.caClusterer && (!specconfig.zsOnTheFly || specconfig.processMC)) { - inputDigits[sector] = pc.inputs().get<gsl::span<o2::tpc::Digit>>(ref); - LOG(INFO) << "GOT DIGITS SPAN FOR SECTOR " << sector << " -> " << inputDigits[sector].size(); - } - } - if (recvMask != processAttributes->tpcSectorMask) { - throw std::runtime_error("Incomplete set of clusters/digits received"); - } - } - - if (specconfig.zsOnTheFly) { - tpcZSonTheFlySizes = {0}; - // tpcZSonTheFlySizes: #zs pages per endpoint: - std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "ZSSIZES"}, Lifetime::Timeframe}}; - bool recv = false, recvsizes = false; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - if (recvsizes) { - throw std::runtime_error("Received multiple ZSSIZES data"); - } - tpcZSonTheFlySizes = pc.inputs().get<std::array<unsigned int, NEndpoints * NSectors>>(ref); - recvsizes = true; - } - // zs pages - std::vector<InputSpec> filter2 = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "TPCZS"}, Lifetime::Timeframe}}; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter2)) { - if (recv) { - throw std::runtime_error("Received multiple TPCZS data"); - } - inputZS = pc.inputs().get<gsl::span<ZeroSuppressedContainer8kb>>(ref); - recv = true; - } - if (!recv || !recvsizes) { - throw std::runtime_error("TPC ZS data not received"); - } - for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZSmetaPointers[i][j].clear(); - tpcZSmetaSizes[i][j].clear(); - } - } - - unsigned int offset = 0; - for (unsigned int i = 0; i < NSectors; i++) { - unsigned int pageSector = 0; - for (unsigned int j = 0; j < NEndpoints; j++) { - pageSector += tpcZSonTheFlySizes[i * NEndpoints + j]; - offset += tpcZSonTheFlySizes[i * NEndpoints + j]; - } - LOG(INFO) << "GOT ZS pages FOR SECTOR " << i << " -> pages: " << pageSector; - } - } - if (specconfig.zsDecoder) { - for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZSmetaPointers[i][j].clear(); - tpcZSmetaSizes[i][j].clear(); - } - } - std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - const o2::header::DataHeader* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); - const gsl::span<const char> raw = pc.inputs().get<gsl::span<char>>(ref); - o2::framework::RawParser parser(raw.data(), raw.size()); - - const unsigned char* ptr = nullptr; - int count = 0; - rdh_utils::FEEIDType lastFEE = -1; - int rawcru = 0; - int rawendpoint = 0; - size_t totalSize = 0; - for (auto it = parser.begin(); it != parser.end(); it++) { - const unsigned char* current = it.raw(); - const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)current; - if (current == nullptr || it.size() == 0 || (current - ptr) % TPCZSHDR::TPC_ZS_PAGE_SIZE || o2::raw::RDHUtils::getFEEID(*rdh) != lastFEE) { - if (count) { - tpcZSmetaPointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr); - tpcZSmetaSizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); - } - count = 0; - lastFEE = o2::raw::RDHUtils::getFEEID(*rdh); - rawcru = o2::raw::RDHUtils::getCRUID(*rdh); - rawendpoint = o2::raw::RDHUtils::getEndPointID(*rdh); - //lastFEE = int(rdh->feeId); - //rawcru = int(rdh->cruID); - //rawendpoint = int(rdh->endPointID); - if (it.size() == 0 && tpcZSmetaPointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].size()) { - ptr = nullptr; - continue; - } - ptr = current; - } else if (ptr == nullptr) { - ptr = current; - } - count++; - } - if (count) { - tpcZSmetaPointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr); - tpcZSmetaSizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); - } - } - int totalCount = 0; - for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZSmetaPointers2[i][j] = tpcZSmetaPointers[i][j].data(); - tpcZSmetaSizes2[i][j] = tpcZSmetaSizes[i][j].data(); - tpcZS.slice[i].zsPtr[j] = tpcZSmetaPointers2[i][j]; - tpcZS.slice[i].nZSPtr[j] = tpcZSmetaSizes2[i][j]; - tpcZS.slice[i].count[j] = tpcZSmetaPointers[i][j].size(); - totalCount += tpcZSmetaPointers[i][j].size(); - } - } - /*DPLRawParser parser(pc.inputs(), filter); - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - // retrieving RDH v4 - auto const* rdh = it.get_if<o2::header::RAWDataHeaderV4>(); - // retrieving the raw pointer of the page - auto const* raw = it.raw(); - // retrieving payload pointer of the page - auto const* payload = it.data(); - // size of payload - size_t payloadSize = it.size(); - // offset of payload in the raw page - size_t offset = it.offset(); - const auto* dh = it.o2DataHeader(); - unsigned long subspec = dh->subSpecification; - printf("Test: rdh %p, raw %p, payload %p, payloadSize %lld, offset %lld, %s %s %lld\n", rdh, raw, payload, (long long int)payloadSize, (long long int)offset, dh->dataOrigin.as<std::string>().c_str(), dh->dataDescription.as<std::string>().c_str(), (long long int)dh->subSpecification); - }*/ - } else if (specconfig.decompressTPC) { - if (specconfig.decompressTPCFromROOT) { - compClustersDummy = *pc.inputs().get<CompressedClustersROOT*>("input"); - compClustersFlatDummy.setForward(&compClustersDummy); - pCompClustersFlat = &compClustersFlatDummy; - } else { - pCompClustersFlat = pc.inputs().get<CompressedClustersFlat*>("input").get(); - } - } else if (!specconfig.zsOnTheFly) { - for (auto const& refentry : inputrefs) { - auto& sector = refentry.first; - auto& ref = refentry.second.data; - if (!specconfig.caClusterer) { - if (ref.payload == nullptr) { - // skip zero-length message - continue; - } - if (refentry.second.labels.header != nullptr && refentry.second.labels.payload != nullptr) { - mcInputs.emplace_back(ConstMCLabelContainerView(pc.inputs().get<gsl::span<char>>(refentry.second.labels))); - } - inputs.emplace_back(gsl::span(ref.payload, DataRefUtils::getPayloadSize(ref))); - } - if (verbosity > 1) { - LOG(INFO) << "received " << *(ref.spec) << ", size " << DataRefUtils::getPayloadSize(ref) << " for sector " << sector; - } - } - if (verbosity) { - LOGF(INFO, "running tracking for sector(s) 0x%09x", processAttributes->tpcSectorMask); - } - } - - std::vector<TrackTPC> tracks; - std::vector<uint32_t> clusRefs; - std::vector<o2::MCCompLabel> tracksMCTruth; - GPUO2InterfaceIOPtrs ptrs; - ClusterNativeAccess clusterIndex; - std::unique_ptr<ClusterNative[]> clusterBuffer; - ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer clustersMCBuffer; - void* ptrEp[NSectors * NEndpoints] = {}; - ptrs.outputTracks = &tracks; - ptrs.outputClusRefs = &clusRefs; - ptrs.outputTracksMCTruth = (specconfig.processMC ? &tracksMCTruth : nullptr); - if (specconfig.caClusterer) { - if (specconfig.zsOnTheFly) { - const unsigned long long int* buffer = reinterpret_cast<const unsigned long long int*>(&inputZS[0]); - o2::gpu::GPUReconstructionConvert::RunZSEncoderCreateMeta(buffer, tpcZSonTheFlySizes.data(), *&ptrEp, &tpcZS); - ptrs.tpcZS = &tpcZS; - if (specconfig.processMC) { - ptrs.o2Digits = &inputDigits; - ptrs.o2DigitsMC = &inputDigitsMCPtrs; - } - } else if (specconfig.zsDecoder) { - ptrs.tpcZS = &tpcZS; - if (specconfig.processMC) { - throw std::runtime_error("Cannot process MC information, none available"); - } - } else { - ptrs.o2Digits = &inputDigits; - if (specconfig.processMC) { - ptrs.o2DigitsMC = &inputDigitsMCPtrs; - } - } - } else if (specconfig.decompressTPC) { - ptrs.compressedClusters = pCompClustersFlat; - } else { - memset(&clusterIndex, 0, sizeof(clusterIndex)); - ClusterNativeHelper::Reader::fillIndex(clusterIndex, clusterBuffer, clustersMCBuffer, inputs, mcInputs, [&processAttributes](auto& index) { return processAttributes->tpcSectorMask & (1ul << index); }); - ptrs.clusters = &clusterIndex; - } - // a byte size resizable vector object, the DataAllocator returns reference to internal object - // initialize optional pointer to the vector object - using O2CharVectorOutputType = std::decay_t<decltype(pc.outputs().make<std::vector<char>>(Output{"", "", 0}))>; - TPCSectorHeader clusterOutputSectorHeader{0}; - if (processAttributes->clusterOutputIds.size() > 0) { - clusterOutputSectorHeader.sectorBits = processAttributes->tpcSectorMask; - // subspecs [0, NSectors - 1] are used to identify sector data, we use NSectors - // to indicate the full TPC - clusterOutputSectorHeader.activeSectors = processAttributes->tpcSectorMask; - } - - GPUInterfaceOutputs outputRegions; - std::optional<std::reference_wrapper<O2CharVectorOutputType>> clusterOutput = std::nullopt, bufferCompressedClusters = std::nullopt, bufferTPCTracks = std::nullopt; - char *clusterOutputChar = nullptr, *bufferCompressedClustersChar = nullptr, *bufferTPCTracksChar = nullptr; - if (specconfig.outputCompClustersFlat) { - if (processAttributes->allocateOutputOnTheFly) { - outputRegions.compressedClusters.allocator = [&bufferCompressedClustersChar, &pc](size_t size) -> void* {bufferCompressedClustersChar = pc.outputs().make<char>(Output{gDataOriginTPC, "COMPCLUSTERSFLAT", 0}, size).data(); return bufferCompressedClustersChar; }; - } else { - bufferCompressedClusters.emplace(pc.outputs().make<std::vector<char>>(Output{gDataOriginTPC, "COMPCLUSTERSFLAT", 0}, processAttributes->outputBufferSize)); - outputRegions.compressedClusters.ptr = bufferCompressedClustersChar = bufferCompressedClusters->get().data(); - outputRegions.compressedClusters.size = bufferCompressedClusters->get().size(); - } - } - if (processAttributes->clusterOutputIds.size() > 0) { - const o2::header::DataDescription outputLabel = specconfig.sendClustersPerSector ? (o2::header::DataDescription) "CLUSTERNATIVETMP" : (o2::header::DataDescription) "CLUSTERNATIVE"; - if (processAttributes->allocateOutputOnTheFly) { - outputRegions.clustersNative.allocator = [&clusterOutputChar, &pc, clusterOutputSectorHeader, outputLabel](size_t size) -> void* {clusterOutputChar = pc.outputs().make<char>({gDataOriginTPC, outputLabel, NSectors, Lifetime::Timeframe, {clusterOutputSectorHeader}}, size + sizeof(ClusterCountIndex)).data(); return clusterOutputChar + sizeof(ClusterCountIndex); }; - } else { - clusterOutput.emplace(pc.outputs().make<std::vector<char>>({gDataOriginTPC, outputLabel, NSectors, Lifetime::Timeframe, {clusterOutputSectorHeader}}, processAttributes->outputBufferSize)); - clusterOutputChar = clusterOutput->get().data(); - outputRegions.clustersNative.ptr = clusterOutputChar + sizeof(ClusterCountIndex); - outputRegions.clustersNative.size = clusterOutput->get().size() - sizeof(ClusterCountIndex); - } - } - if (specconfig.outputTracks) { - if (processAttributes->allocateOutputOnTheFly) { - outputRegions.tpcTracks.allocator = [&bufferTPCTracksChar, &pc](size_t size) -> void* {bufferTPCTracksChar = pc.outputs().make<char>(Output{gDataOriginTPC, "TRACKSGPU", 0}, size).data(); return bufferTPCTracksChar; }; - } else { - bufferTPCTracks.emplace(pc.outputs().make<std::vector<char>>(Output{gDataOriginTPC, "TRACKSGPU", 0}, processAttributes->outputBufferSize)); - outputRegions.tpcTracks.ptr = bufferTPCTracksChar = bufferTPCTracks->get().data(); - outputRegions.tpcTracks.size = bufferTPCTracks->get().size(); - } - } - if (specconfig.processMC) { - outputRegions.clusterLabels.allocator = [&clustersMCBuffer](size_t size) -> void* { return &clustersMCBuffer; }; - } - - int retVal = tracker->runTracking(&ptrs, &outputRegions); - if (processAttributes->suppressOutput) { - return; - } - if (retVal != 0) { - throw std::runtime_error("tracker returned error code " + std::to_string(retVal)); - } - LOG(INFO) << "found " << tracks.size() << " track(s)"; - // tracks are published if the output channel is configured - if (specconfig.outputTracks) { - pc.outputs().snapshot(OutputRef{"outTracks"}, tracks); - pc.outputs().snapshot(OutputRef{"outClusRefs"}, clusRefs); - if (specconfig.processMC) { - LOG(INFO) << "sending " << tracksMCTruth.size() << " track label(s)"; - pc.outputs().snapshot(OutputRef{"mclblout"}, tracksMCTruth); - } - } - - if (ptrs.compressedClusters != nullptr) { - if (specconfig.outputCompClustersFlat) { - if (!processAttributes->allocateOutputOnTheFly) { - bufferCompressedClusters->get().resize(outputRegions.compressedClusters.size); - } - if ((void*)ptrs.compressedClusters != (void*)bufferCompressedClustersChar) { - throw std::runtime_error("compressed cluster output ptrs out of sync"); // sanity check - } - } - if (specconfig.outputCompClusters) { - CompressedClustersROOT compressedClusters = *ptrs.compressedClusters; - pc.outputs().snapshot(Output{gDataOriginTPC, "COMPCLUSTERS", 0}, ROOTSerialized<CompressedClustersROOT const>(compressedClusters)); - } - } else { - LOG(ERROR) << "unable to get compressed cluster info from track"; - } - - // publish clusters produced by CA clusterer sector-wise if the outputs are configured - if (processAttributes->clusterOutputIds.size() > 0 && ptrs.clusters == nullptr) { - throw std::logic_error("No cluster index object provided by GPU processor"); - } - // previously, clusters have been published individually for the enabled sectors - // clusters are now published as one block, subspec is NSectors - if (processAttributes->clusterOutputIds.size() > 0) { - if (!processAttributes->allocateOutputOnTheFly) { - clusterOutput->get().resize(sizeof(ClusterCountIndex) + outputRegions.clustersNative.size); - } - if ((void*)ptrs.clusters->clustersLinear != (void*)(clusterOutputChar + sizeof(ClusterCountIndex))) { - throw std::runtime_error("cluster native output ptrs out of sync"); // sanity check - } - - ClusterNativeAccess const& accessIndex = *ptrs.clusters; - if (specconfig.sendClustersPerSector) { - for (int i = 0; i < NSectors; i++) { - if (processAttributes->tpcSectorMask & (1ul << i)) { - o2::header::DataHeader::SubSpecificationType subspec = i; - clusterOutputSectorHeader.sectorBits = (1ul << i); - char* buffer = pc.outputs().make<char>({gDataOriginTPC, "CLUSTERNATIVE", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear) + sizeof(ClusterCountIndex)).data(); - ClusterCountIndex* outIndex = reinterpret_cast<ClusterCountIndex*>(buffer); - memset(outIndex, 0, sizeof(*outIndex)); - for (int j = 0; j < constants::MAXGLOBALPADROW; j++) { - outIndex->nClusters[i][j] = accessIndex.nClusters[i][j]; - } - memcpy(buffer + sizeof(*outIndex), accessIndex.clusters[i][0], accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear)); - if (specconfig.processMC && accessIndex.clustersMCTruth) { - MCLabelContainer cont; - for (int j = 0; j < accessIndex.nClustersSector[i]; j++) { - const auto& labels = accessIndex.clustersMCTruth->getLabels(accessIndex.clusterOffset[i][0] + j); - for (const auto& label : labels) { - cont.addElement(j, label); - } - } - ConstMCLabelContainer contflat; - cont.flatten_to(contflat); - pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, contflat); - } - } - } - } else { - o2::header::DataHeader::SubSpecificationType subspec = NSectors; - ClusterCountIndex* outIndex = reinterpret_cast<ClusterCountIndex*>(clusterOutputChar); - static_assert(sizeof(ClusterCountIndex) == sizeof(accessIndex.nClusters)); - memcpy(outIndex, &accessIndex.nClusters[0][0], sizeof(ClusterCountIndex)); - if (specconfig.processMC && accessIndex.clustersMCTruth) { - pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, clustersMCBuffer.first); - } - } - } - if (specconfig.outputQA) { - TObjArray out; - std::vector<TH1F> copy1 = *outputRegions.qa.hist1; // Internally, this will also be used as output, so we need a non-const copy - std::vector<TH2F> copy2 = *outputRegions.qa.hist2; - std::vector<TH1D> copy3 = *outputRegions.qa.hist3; - processAttributes->qa->postprocess(copy1, copy2, copy3, out); - pc.outputs().snapshot({gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe}, out); - processAttributes->qa->cleanup(); - } - timer.Stop(); - LOG(INFO) << "TPC CATracker time for this TF " << timer.CpuTime() - cput << " s"; - }; - - return processingFct; - }; - - // FIXME: find out how to handle merge inputs in a simple and intuitive way - // changing the binding name of the input in order to identify inputs by unique labels - // in the processing. Think about how the processing can be made agnostic of input size, - // e.g. by providing a span of inputs under a certain label - auto createInputSpecs = [&tpcsectors, &specconfig, policyData]() { - Inputs inputs; - if (specconfig.decompressTPC) { - inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, specconfig.decompressTPCFromROOT ? header::DataDescription("COMPCLUSTERS") : header::DataDescription("COMPCLUSTERSFLAT")}, Lifetime::Timeframe}); - } else if (specconfig.caClusterer) { - // We accept digits and MC labels also if we run on ZS Raw data, since they are needed for MC label propagation - if ((!specconfig.zsOnTheFly || specconfig.processMC) && !specconfig.zsDecoder) { - inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe}); - policyData->emplace_back(o2::framework::InputSpec{"digits", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITS"}}); - } - } else { - inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe}); - policyData->emplace_back(o2::framework::InputSpec{"clusters", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}}); - } - if (specconfig.processMC) { - if (specconfig.caClusterer) { - if (!specconfig.zsDecoder) { - inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}, Lifetime::Timeframe}); - policyData->emplace_back(o2::framework::InputSpec{"digitsmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITSMCTR"}}); - } - } else { - inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "CLNATIVEMCLBL"}, Lifetime::Timeframe}); - policyData->emplace_back(o2::framework::InputSpec{"clustersmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}}); - } - } - - if (specconfig.zsDecoder) { - // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution - // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA - inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe}); - } - if (specconfig.zsOnTheFly) { - inputs.emplace_back(InputSpec{"zsinput", ConcreteDataTypeMatcher{"TPC", "TPCZS"}, Lifetime::Timeframe}); - inputs.emplace_back(InputSpec{"zsinputsizes", ConcreteDataTypeMatcher{"TPC", "ZSSIZES"}, Lifetime::Timeframe}); - } - return inputs; - }; - - //o2::framework::InputSpec{"cluster", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}}, - // o2::framework::InputSpec{"digits", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITS"}})()); - - auto createOutputSpecs = [&specconfig, &tpcsectors, &processAttributes]() { - std::vector<OutputSpec> outputSpecs{ - OutputSpec{{"outTracks"}, gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe}, - OutputSpec{{"outClusRefs"}, gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe}, - // This is not really used as an output, but merely to allocate a GPU-registered memory where the GPU can write the track output. - // Right now, the tracks are still reformatted, and copied in the above buffers. - // This one will not have any consumer and just be dropped. - // But we need something to provide to the GPU as external buffer to test direct writing of tracks in the shared memory. - OutputSpec{{"outTracksGPUBuffer"}, gDataOriginTPC, "TRACKSGPU", 0, Lifetime::Timeframe}, - }; - if (!specconfig.outputTracks) { - // this case is the less unlikely one, that's why the logic this way - outputSpecs.clear(); - } - if (specconfig.processMC && specconfig.outputTracks) { - OutputLabel label{"mclblout"}; - constexpr o2::header::DataDescription datadesc("TRACKSMCLBL"); - outputSpecs.emplace_back(label, gDataOriginTPC, datadesc, 0, Lifetime::Timeframe); - } - if (specconfig.outputCompClusters) { - outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERS", 0, Lifetime::Timeframe); - } - if (specconfig.outputCompClustersFlat) { - outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe); - } - if (specconfig.outputCAClusters) { - for (auto const& sector : tpcsectors) { - processAttributes->clusterOutputIds.emplace_back(sector); - } - outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", specconfig.sendClustersPerSector ? 0 : NSectors, Lifetime::Timeframe); - if (specconfig.sendClustersPerSector) { - outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVETMP", NSectors, Lifetime::Timeframe); // Dummy buffer the TPC tracker writes the inital linear clusters to - for (const auto sector : tpcsectors) { - outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", sector, Lifetime::Timeframe); - } - } else { - outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", NSectors, Lifetime::Timeframe); - } - if (specconfig.processMC) { - if (specconfig.sendClustersPerSector) { - for (const auto sector : tpcsectors) { - outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", sector, Lifetime::Timeframe); - } - } else { - outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", NSectors, Lifetime::Timeframe); - } - } - } - if (specconfig.outputQA) { - outputSpecs.emplace_back(gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe); - } - return std::move(outputSpecs); - }; - - return DataProcessorSpec{"tpc-tracker", // process id - {createInputSpecs()}, - {createOutputSpecs()}, - AlgorithmSpec(initFunction)}; -} - -} // namespace tpc -} // namespace o2 diff --git a/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx new file mode 100644 index 0000000000000..51f36a0d32f55 --- /dev/null +++ b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx @@ -0,0 +1,198 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CalDetMergerPublisherSpec.cxx +/// @brief TPC CalDet merger and CCDB publisher +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de + +#include <bitset> +#include <unordered_map> +#include <vector> +#include <string> +#include <algorithm> + +#include <fmt/format.h> + +#include "TMemFile.h" +#include "TFile.h" + +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" + +#include "Headers/DataHeader.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "TPCBase/CDBInterface.h" +#include "TPCBase/CalDet.h" +#include "TPCWorkflow/CalDetMergerPublisherSpec.h" + +using namespace o2::framework; +using namespace o2::tpc; +using clbUtils = o2::calibration::Utils; +using o2::header::gDataOriginTPC; + +class CalDetMergerPublisherSpec : public o2::framework::Task +{ + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + + public: + CalDetMergerPublisherSpec(uint32_t lanes, bool skipCCDB, bool dumpAfterComplete = false) : mLanesToExpect(lanes), mSkipCCDB(skipCCDB), mPublishAfterComplete(dumpAfterComplete) {} + + void init(o2::framework::InitContext& ic) final + { + mForceQuit = ic.options().get<bool>("force-quit"); + mDirectFileDump = ic.options().get<bool>("direct-file-dump"); + } + + void run(o2::framework::ProcessingContext& pc) final + { + int nSlots = pc.inputs().getNofParts(0); + assert(pc.inputs().getNofParts(1) == nSlots); + + for (int isl = 0; isl < nSlots; isl++) { + const auto type = pc.inputs().get<int>("clbInfo", isl); + const auto pld = pc.inputs().get<gsl::span<char>>("clbPayload", isl); // this is actually an image of TMemFile + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().get("clbInfo", isl)); + const auto subSpec = dh->subSpecification; + const int lane = subSpec >> 4; + const int calibType = subSpec & 0xf; + + //const auto& path = wrp->getPath(); + TMemFile f("file", (char*)&pld[0], pld.size(), "READ"); + if (!f.IsZombie()) { + auto calDet = f.Get<o2::tpc::CalDet<float>>("data"); + if (calDet) { + if (mMergedCalDets.find(type) == mMergedCalDets.end()) { + mMergedCalDets[type] = *calDet; + } else { + mMergedCalDets[type] += *calDet; + } + } + } + f.Close(); + + LOGP(info, "getting slot {}, subspec {:#8x}, lane {}, type {}", isl, subSpec, lane, calibType); + //if (mReceivedLanes.test(lane)) { + //LOGP(warning, "lane {} received multiple times", lane); + //} + mReceivedLanes.set(lane); + } + + if (mReceivedLanes.count() == mLanesToExpect) { + LOGP(info, "data of all lanes received"); + if (mPublishAfterComplete) { + LOGP(info, "publishing after all data was received"); + dumpCalibData(); + sendOutput(pc.outputs()); + // reset calibration objects + for (auto& [type, object] : mMergedCalDets) { + object *= 0; + } + mCalibDumped = false; + } + mReceivedLanes.reset(); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "endOfStream"); + + if (mReceivedLanes.count() == mLanesToExpect) { + dumpCalibData(); + sendOutput(ec.outputs()); + } else { + LOGP(info, "Received lanes {} does not match expected lanes {}, object already sent", mReceivedLanes.count(), mLanesToExpect); + } + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + + private: + using dataType = o2::tpc::CalDet<float>; + std::bitset<128> mReceivedLanes; ///< counter for received lanes + std::unordered_map<int, dataType> mMergedCalDets; ///< calibration data to merge + uint32_t mLanesToExpect{0}; ///< number of expected lanes sending data + bool mForceQuit{false}; ///< for quit after processing finished + bool mDirectFileDump{false}; ///< directly dump the calibration data to file + bool mPublishAfterComplete{false}; ///< dump calibration directly after data from all lanes received + bool mCalibDumped{false}; ///< if calibration object already dumped + bool mSkipCCDB{false}; ///< skip sending of calibration data + + //____________________________________________________________________________ + void sendOutput(DataAllocator& output) + { + //CDBStorage::MetaData_t md; + + // perhaps should be changed to time of the run + const auto now = std::chrono::system_clock::now(); + const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); + const long timeEnd = 99999999999999; + + for (auto& [type, object] : mMergedCalDets) { + o2::ccdb::CcdbObjectInfo w; + auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &w); + + w.setPath(CDBTypeMap.at(CDBType(type))); + w.setStartValidityTimestamp(timeStart); + w.setEndValidityTimestamp(timeEnd); + + LOG(INFO) << "Sending object " << w.getPath() << "/" << w.getFileName() << " of size " << image->size() + << " bytes, valid for " << w.getStartValidityTimestamp() << " : " << w.getEndValidityTimestamp(); + + o2::header::DataHeader::SubSpecificationType subSpec{(o2::header::DataHeader::SubSpecificationType)type}; + output.snapshot(Output{clbUtils::gDataOriginCDBPayload, "TPC_CALIB", subSpec}, *image.get()); + output.snapshot(Output{clbUtils::gDataOriginCDBWrapper, "TPC_CALIB", subSpec}, w); + } + } + + //____________________________________________________________________________ + void dumpCalibData() + { + if (mDirectFileDump && !mCalibDumped) { + LOGP(info, "Dumping output to file"); + TFile f("merged_CalDet.root", "recreate"); + for (auto& [type, object] : mMergedCalDets) { + f.WriteObject(&object, object.getName().data()); + } + mCalibDumped = true; + } + } +}; + +o2::framework::DataProcessorSpec o2::tpc::getCalDetMergerPublisherSpec(uint32_t lanes, bool skipCCDB, bool dumpAfterComplete) +{ + std::vector<OutputSpec> outputs; + if (!skipCCDB) { + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "TPC_CALIB"}); + outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "TPC_CALIB"}); + } + + std::vector<InputSpec> inputs; + inputs.emplace_back("clbPayload", ConcreteDataTypeMatcher{gDataOriginTPC, "CLBPART"}); + inputs.emplace_back("clbInfo", ConcreteDataTypeMatcher{gDataOriginTPC, "CLBPARTINFO"}); + + const std::string id = "calib-tpc-caldet-merger-publisher"; + + return DataProcessorSpec{ + id.data(), + inputs, + outputs, + AlgorithmSpec{adaptFromTask<CalDetMergerPublisherSpec>(lanes, skipCCDB, dumpAfterComplete)}, + Options{ + {"force-quit", VariantType::Bool, false, {"force quit after max-events have been reached"}}, + {"direct-file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, + } // end Options + }; // end DataProcessorSpec +} diff --git a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx new file mode 100644 index 0000000000000..505b48fe65b32 --- /dev/null +++ b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx @@ -0,0 +1,279 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <algorithm> + +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "DPLUtils/RawParser.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Headers/DataHeaderHelpers.h" +#include "DataFormatsTPC/ZeroSuppressionLinkBased.h" + +#include "TPCBase/RDHUtils.h" +#include "TPCReconstruction/RawReaderCRU.h" +#include "TPCReconstruction/RawProcessingHelpers.h" + +#include "TPCWorkflow/CalibProcessingHelper.h" + +using namespace o2::tpc; +using namespace o2::framework; +using RDHUtils = o2::raw::RDHUtils; + +void processGBT(o2::framework::RawParser<>& parser, std::unique_ptr<RawReaderCRU>& reader, const rdh_utils::FEEIDType feeID); +void processLinkZS(o2::framework::RawParser<>& parser, std::unique_ptr<RawReaderCRU>& reader, uint32_t firstOrbit, uint32_t syncOffsetReference); +uint32_t getBCsyncOffsetReference(InputRecord& inputs, const std::vector<InputSpec>& filter); + +uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inputs, std::unique_ptr<RawReaderCRU>& reader, bool useOldSubspec, const std::vector<int>& sectors, size_t* nerrors) +{ + std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; + size_t errorCount = 0; + // TODO: check if presence of data sampling can be checked in another way + bool sampledData = true; + for ([[maybe_unused]] auto const& ref : InputRecordWalker(inputs, filter)) { + sampledData = false; + break; + } + if (sampledData) { + filter = {{"sampled-rawdata", ConcreteDataTypeMatcher{"DS", "RAWDATA"}, Lifetime::Timeframe}}; + LOGP(info, "Using sampled data"); + } + + uint64_t activeSectors = 0; + bool isLinkZS = false; + bool readFirst = false; + uint32_t firstOrbit = 0; + + // for LinkZS data the maximum sync offset is needed to align the data properly. + // getBCsyncOffsetReference only works, if the full TF is seen. Alternatively, this value could be set + // fixed to e.g. 144 or 152 which is the maximum sync delay expected + // this is less precise and might lead to more time bins which have to be removed at the beginnig + // or end of the TF + // uint32_t syncOffsetReference = getBCsyncOffsetReference(inputs, filter); + uint32_t syncOffsetReference = 144; + + for (auto const& ref : InputRecordWalker(inputs, filter)) { + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + // skip empty HBF + if (dh->payloadSize == 2 * sizeof(o2::header::RAWDataHeader)) { + continue; + } + + firstOrbit = dh->firstTForbit; + + // ---| extract hardware information to do the processing |--- + const auto subSpecification = dh->subSpecification; + rdh_utils::FEEIDType feeID = (rdh_utils::FEEIDType)dh->subSpecification; + + if (useOldSubspec) { + //---| old definition by Gvozden |--- + // TODO: make auto detect from firt RDH? + const auto cruID = (rdh_utils::FEEIDType)(subSpecification >> 16); + const auto linkID = (rdh_utils::FEEIDType)((subSpecification + (subSpecification >> 8)) & 0xFF) - 1; + const auto endPoint = (rdh_utils::FEEIDType)((subSpecification >> 8) & 0xFF) > 0; + feeID = rdh_utils::getFEEID(cruID, endPoint, linkID); + } + + const uint64_t sector = rdh_utils::getCRU(feeID) / 10; + + // sector selection should be better done by directly subscribing to a range of subspecs. But this might not be that simple + if (sectors.size() && (std::find(sectors.begin(), sectors.end(), int(sector)) == sectors.end())) { + continue; + } + + activeSectors |= (0x1 << sector); + + // ===| for debugging only |=== + // remove later + rdh_utils::FEEIDType cruID, linkID, endPoint; + rdh_utils::getMapping(feeID, cruID, endPoint, linkID); + const auto globalLinkID = linkID + endPoint * 12; + LOGP(debug, "Specifier: {}/{}/{} Part {} of {}", dh->dataOrigin, dh->dataDescription, subSpecification, dh->splitPayloadIndex, dh->splitPayloadParts); + LOGP(debug, "Payload size: {}", dh->payloadSize); + LOGP(debug, "CRU: {}; linkID: {}; endPoint: {}; globalLinkID: {}", cruID, linkID, endPoint, globalLinkID); + // ^^^^^^ + + // TODO: exception handling needed? + const gsl::span<const char> raw = inputs.get<gsl::span<char>>(ref); + std::unique_ptr<o2::framework::RawParser<8192>> rawparserPtr; + try { + + o2::framework::RawParser parser(raw.data(), raw.size()); + // detect decoder type by analysing first RDH + if (!readFirst) { + auto it = parser.begin(); + auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV6>(); + if (!rdhPtr) { + throw std::runtime_error("could not get RDH from packet"); + } + const auto link = RDHUtils::getLinkID(*rdhPtr); + const auto detField = RDHUtils::getDetectorField(*rdhPtr); + if ((link == rdh_utils::UserLogicLinkID) || (detField == 1)) { + LOGP(info, "Detected Link-based zero suppression"); + isLinkZS = true; + if (!reader->getManager() || !reader->getManager()->getLinkZSCallback()) { + LOGP(fatal, "LinkZSCallback must be set in RawReaderCRUManager"); + } + } + + //firstOrbit = RDHUtils::getHeartBeatOrbit(*rdhPtr); + LOGP(info, "First orbit in present TF: {}", firstOrbit); + readFirst = true; + } + + if (isLinkZS) { + processLinkZS(parser, reader, firstOrbit, syncOffsetReference); + } else { + processGBT(parser, reader, feeID); + } + + } catch (const std::exception& e) { + LOGP(ERROR, "EXCEPTIION in processRawData: {} -> skipping part:{}/{} of spec:{}/{}/{}, size:{}", e.what(), dh->splitPayloadIndex, dh->splitPayloadParts, + dh->dataOrigin, dh->dataDescription, subSpecification, dh->payloadSize); + errorCount++; + continue; + } + } + if (nerrors) { + *nerrors += errorCount; + } + return activeSectors; +} + +void processGBT(o2::framework::RawParser<>& parser, std::unique_ptr<RawReaderCRU>& reader, const rdh_utils::FEEIDType feeID) +{ + // TODO: currently this will only work for HBa1, since the sync is in the first packet and + // the decoder expects all packets of one link to be processed at once + rdh_utils::FEEIDType cruID, linkID, endPoint; + rdh_utils::getMapping(feeID, cruID, endPoint, linkID); + const auto globalLinkID = linkID + endPoint * 12; + + // ---| update hardware information in the reader |--- + reader->forceCRU(cruID); + reader->setLink(globalLinkID); + + rawreader::ADCRawData rawData; + rawreader::GBTFrame gFrame; + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + + const auto size = it.size(); + auto data = it.data(); + //LOGP(info, "Data size: {}", size); + + int iFrame = 0; + for (int i = 0; i < size; i += 16) { + gFrame.setFrameNumber(iFrame); + gFrame.setPacketNumber(iFrame / 508); + gFrame.readFromMemory(gsl::span<const std::byte>((std::byte*)data + i, 16)); + + // extract the half words from the 4 32-bit words + gFrame.getFrameHalfWords(); + + gFrame.getAdcValues(rawData); + gFrame.updateSyncCheck(false); + + ++iFrame; + } + } + + reader->runADCDataCallback(rawData); +} + +void processLinkZS(o2::framework::RawParser<>& parser, std::unique_ptr<RawReaderCRU>& reader, uint32_t firstOrbit, uint32_t syncOffsetReference) +{ + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV6>(); + if (!rdhPtr) { + throw std::runtime_error("could not get RDH from packet"); + } + // workaround for MW2 data + //const bool useTimeBins = true; + //const auto cru = RDHUtils::getCRUID(*rdhPtr); + //const auto feeID = (RDHUtils::getFEEID(*rdhPtr) & 0x7f) | (cru << 7); + + // skip all data that is not Link-base zero suppression + const auto link = RDHUtils::getLinkID(*rdhPtr); + const auto detField = RDHUtils::getDetectorField(*rdhPtr); + if (!((detField == 1) || ((detField == 0 || detField == 0xdeadbeef) && link == rdh_utils::UserLogicLinkID))) { + continue; + } + + const bool useTimeBins = false; + const auto feeID = RDHUtils::getFEEID(*rdhPtr); + const auto orbit = RDHUtils::getHeartBeatOrbit(*rdhPtr); + const auto data = (const char*)it.data(); + const auto size = it.size(); + raw_processing_helpers::processZSdata(data, size, feeID, orbit, firstOrbit, syncOffsetReference, reader->getManager()->getLinkZSCallback(), useTimeBins); + } +} + +// find the global sync offset reference, using the large sync offset to avoid negative time bins +uint32_t getBCsyncOffsetReference(InputRecord& inputs, const std::vector<InputSpec>& filter) +{ + uint32_t syncOffsetReference = 144; + + for (auto const& ref : InputRecordWalker(inputs, filter)) { + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + // skip empty HBF + if (dh->payloadSize == 2 * sizeof(o2::header::RAWDataHeader)) { + continue; + } + + const gsl::span<const char> raw = inputs.get<gsl::span<char>>(ref); + o2::framework::RawParser parser(raw.data(), raw.size()); + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV6>(); + if (!rdhPtr) { + throw std::runtime_error("could not get RDH from packet"); // RS: this method is not used at the moment + } + + // only process LinkZSdata, only supported for data where this is already set in the UL + const auto link = RDHUtils::getLinkID(*rdhPtr); + const auto detField = RDHUtils::getDetectorField(*rdhPtr); + if (!((detField == 1) || ((detField == 0 || detField == 0xdeadbeef) && link == rdh_utils::UserLogicLinkID))) { + continue; + } + + const auto data = (const char*)it.data(); + const auto size = it.size(); + + zerosupp_link_based::ContainerZS* zsdata = (zerosupp_link_based::ContainerZS*)data; + const zerosupp_link_based::ContainerZS* const zsdataEnd = (zerosupp_link_based::ContainerZS*)(data + size); + + while (zsdata < zsdataEnd) { + const auto& header = zsdata->cont.header; + // align to header word if needed + if (!header.hasCorrectMagicWord()) { + zsdata = (zerosupp_link_based::ContainerZS*)((const char*)zsdata + sizeof(zerosupp_link_based::Header)); + continue; + } + + // skip trigger info + if (header.isTriggerInfo()) { + zsdata = zsdata->next(); + continue; + } + + syncOffsetReference = std::max(header.syncOffsetBC, syncOffsetReference); + + // only read first time bin for each link + break; + } + } + } + + LOGP(info, "syncOffsetReference in this TF: {}", syncOffsetReference); + return syncOffsetReference; +} diff --git a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx new file mode 100644 index 0000000000000..c57c1bb4f2f70 --- /dev/null +++ b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibdEdxSpec.cxx +/// \brief Workflow for time based dE/dx calibration. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#include "TPCWorkflow/CalibdEdxSpec.h" + +#include <vector> +#include <memory> + +// o2 includes +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCCalibration/CalibdEdx.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class CalibdEdxDevice : public Task +{ + public: + void init(framework::InitContext& ic) final + { + const int slotLength = ic.options().get<int>("tf-per-slot"); + const int maxDelay = ic.options().get<int>("max-delay"); + const int minEntries = std::max(50, ic.options().get<int>("min-entries")); + const int nbins = std::max(10, ic.options().get<int>("nbins")); + const bool applyCuts = ic.options().get<bool>("apply-cuts"); + const float minP = ic.options().get<float>("min-momentum"); + const float maxP = ic.options().get<float>("max-momentum"); + const int minClusters = std::max(10, ic.options().get<int>("min-clusters")); + const bool dumpData = ic.options().get<bool>("direct-file-dump"); + + assert(minP < maxP); + + mCalibrator = std::make_unique<tpc::CalibdEdx>(nbins, minEntries, minP, maxP, minClusters); + mCalibrator->setApplyCuts(applyCuts); + + mCalibrator->setSlotLength(slotLength); + mCalibrator->setMaxSlotsDelay(maxDelay); + + if (dumpData) { + mCalibrator->enableDebugOutput("calib_dEdx.root"); + } + } + + void run(ProcessingContext& pc) final + { + const auto tfcounter = o2::header::get<DataProcessingHeader*>(pc.inputs().get("tracks").header)->startTime; + const auto tracks = pc.inputs().get<gsl::span<tpc::TrackTPC>>("tracks"); + + LOG(INFO) << "Processing TF " << tfcounter << " with " << tracks.size() << " tracks"; + + mCalibrator->process(tfcounter, tracks); + sendOutput(pc.outputs()); + + const auto& infoVec = mCalibrator->getInfoVector(); + LOG(INFO) << "Created " << infoVec.size() << " objects for TF " << tfcounter; + } + + void endOfStream(EndOfStreamContext& eos) final + { + LOG(INFO) << "Finalizing calibration"; + constexpr calibration::TFType INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + sendOutput(eos.outputs()); + + if (mCalibrator->hasDebugOutput()) { + mCalibrator->finalizeDebugOutput(); + } + } + + private: + void sendOutput(DataAllocator& output) + { + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + using clbUtils = o2::calibration::Utils; + const auto& payloadVec = mCalibrator->getMIPVector(); + auto& infoVec = mCalibrator->getInfoVector(); // use non-const version as we update it + assert(payloadVec.size() == infoVec.size()); + + // FIXME: not sure about this + for (unsigned int i = 0; i < payloadVec.size(); i++) { + auto& entry = infoVec[i]; + auto image = o2::ccdb::CcdbApi::createObjectImage(&payloadVec[i], &entry); + LOG(INFO) << "Sending object " << entry.getPath() << "/" << entry.getFileName() << " of size " << image->size() + << " bytes, valid for " << entry.getStartValidityTimestamp() << " : " << entry.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_MIPS", i}, *image.get()); // vector<char> + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_MIPS", i}, entry); // root-serialized + } + if (!payloadVec.empty()) { + mCalibrator->initOutput(); // reset the outputs once they are already sent + } + } + + std::unique_ptr<CalibdEdx> mCalibrator; +}; + +DataProcessorSpec getCalibdEdxSpec() +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_MIPS"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_MIPS"}); + + return DataProcessorSpec{ + "tpc-calib-dEdx", + Inputs{ + InputSpec{"tracks", "TPC", "MIPS"}, + }, + outputs, + adaptFromTask<CalibdEdxDevice>(), + Options{ + {"tf-per-slot", VariantType::Int, 100, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int, 3, {"number of slots in past to consider"}}, + {"min-entries", VariantType::Int, 100, {"minimum number of entries to fit single time slot"}}, + {"apply-cuts", VariantType::Bool, false, {"enable tracks filter using cut values passed as options"}}, + {"min-momentum", VariantType::Float, 0.4f, {"minimum momentum cut"}}, + {"max-momentum", VariantType::Float, 0.6f, {"maximum momentum cut"}}, + {"min-clusters", VariantType::Int, 60, {"minimum number of clusters in a track"}}, + {"nbins", VariantType::Int, 200, {"number of bins for stored"}}, + {"direct-file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}}}; +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx b/Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx new file mode 100644 index 0000000000000..5daa1b9bb9d9b --- /dev/null +++ b/Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx @@ -0,0 +1,285 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Sandro Wenzel +/// @since 2021-03-10 +/// @brief Takes TPC digit chunks (such drift times) --> accumulates to digit timeframe format --> publishes + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/DataAllocator.h" +#include "Framework/ControlService.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCSimulation/CommonMode.h" +#include "DetectorsBase/Detector.h" +#include <SimulationDataFormat/MCCompLabel.h> +#include <SimulationDataFormat/MCTruthContainer.h> +#include <SimulationDataFormat/ConstMCTruthContainer.h> +#include <CommonUtils/FileSystemUtils.h> +#include "Algorithm/RangeTokenizer.h" +#include "TPCBase/Sector.h" +#include <TFile.h> +#include <TTree.h> +#include <TBranch.h> +#include <stdexcept> +#include <string> +#include <vector> +#include <utility> +#include <TROOT.h> +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> +#ifdef WITH_OPENMP +#include <omp.h> +#endif +#include <TStopwatch.h> + +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +using namespace o2::framework; +using namespace o2::header; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // for the TPC it is useful to take at most half of the available (logical) cores due to memory requirements + int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + std::string laneshelp("Number of tpc processing lanes. A lane is a pipeline of algorithms."); + workflowOptions.push_back( + ConfigParamSpec{"tpc-lanes", VariantType::Int, defaultlanes, {laneshelp}}); + + std::string sectorshelp("List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"); + std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + workflowOptions.push_back( + ConfigParamSpec{"tpc-sectors", VariantType::String, sectorDefault.c_str(), {sectorshelp}}); + + // option to disable MC truth + workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable mc-truth"}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" +#include "DataFormatsTPC/TPCSectorHeader.h" + +using MCTruthContainer = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; + +namespace o2 +{ +namespace tpc +{ + +template <typename T, typename R> +void copyHelper(T const& origin, R& target) +{ + // Using critical section here as this is writing to shared mem + // and not sure if boost shared mem allocator is thread-safe. + // It was crashing without this. +#pragma omp critical + std::copy(origin.begin(), origin.end(), std::back_inserter(target)); +} +template <> +void copyHelper<MCTruthContainer>(MCTruthContainer const& origin, MCTruthContainer& target) +{ + target.mergeAtBack(origin); +} + +template <typename T> +auto makePublishBuffer(framework::ProcessingContext& pc, int sector, uint64_t activeSectors) +{ + LOG(INFO) << "PUBLISHING SECTOR " << sector; + + o2::tpc::TPCSectorHeader header{sector}; + header.activeSectors = activeSectors; + return &pc.outputs().make<T>(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(sector), Lifetime::Timeframe, + header}); +} + +template <> +auto makePublishBuffer<MCTruthContainer>(framework::ProcessingContext& pc, int sector, uint64_t activeSectors) +{ + return new MCTruthContainer(); +} + +template <typename T> +void publishBuffer(framework::ProcessingContext& pc, int sector, uint64_t activeSectors, T* accum) +{ + // nothing by default +} + +template <> +void publishBuffer<MCTruthContainer>(framework::ProcessingContext& pc, int sector, uint64_t activeSectors, MCTruthContainer* accum) +{ + + LOG(INFO) << "PUBLISHING MC LABELS " << accum->getNElements(); + o2::tpc::TPCSectorHeader header{sector}; + header.activeSectors = activeSectors; + using LabelType = std::decay_t<decltype(pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"", "", 0}))>; + LabelType* sharedlabels; +#pragma omp critical + sharedlabels = &pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>( + Output{"TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(sector), Lifetime::Timeframe, header}); + + accum->flatten_to(*sharedlabels); + delete accum; +} + +template <typename T> +void mergeHelper(const char* brprefix, std::vector<int> const& tpcsectors, uint64_t activeSectors, + TFile& originfile, framework::ProcessingContext& pc) +{ + auto keyslist = originfile.GetListOfKeys(); + for (int i = 0; i < keyslist->GetEntries(); ++i) { + auto key = keyslist->At(i); + int sector = atoi(key->GetName()); + if (std::find(tpcsectors.begin(), tpcsectors.end(), sector) == tpcsectors.end()) { + // do nothing if sector not wanted + continue; + } + + auto oldtree = (TTree*)originfile.Get(key->GetName()); + assert(oldtree); + std::stringstream digitbrname; + digitbrname << brprefix << key->GetName(); + auto br = oldtree->GetBranch(digitbrname.str().c_str()); + if (!br) { + continue; + } + T* chunk = nullptr; + br->SetAddress(&chunk); + + using AccumType = std::decay_t<decltype(makePublishBuffer<T>(pc, sector, activeSectors))>; + AccumType accum; +#pragma omp critical + accum = makePublishBuffer<T>(pc, sector, activeSectors); + + for (auto e = 0; e < br->GetEntries(); ++e) { + br->GetEntry(e); + copyHelper(*chunk, *accum); + delete chunk; + chunk = nullptr; + } + br->ResetAddress(); + br->DropBaskets("all"); + delete oldtree; + + // some data (labels are published slightly differently) + publishBuffer(pc, sector, activeSectors, accum); + } +} + +void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> const& tpcsectors, bool domctruth, framework::ProcessingContext& pc) +{ + uint64_t activeSectors = 0; + for (auto s : tpcsectors) { + activeSectors |= (uint64_t)0x1 << s; + } + + ROOT::EnableThreadSafety(); + // we determine the exact input list of files + auto digitfilelist = o2::utils::listFiles("tpc_driftime_digits_lane.*.root$"); +#ifdef WITH_OPENMP + omp_set_num_threads(std::min(lanes.size(), digitfilelist.size())); + LOG(INFO) << "Running digit publisher with OpenMP enabled"; +#pragma omp parallel for schedule(dynamic) +#endif + for (size_t fi = 0; fi < digitfilelist.size(); ++fi) { + auto& filename = digitfilelist[fi]; + LOG(DEBUG) << "MERGING CHUNKED DIGITS FROM FILE " << filename; + auto originfile = new TFile(filename.c_str(), "OPEN"); + assert(originfile); + + //data definitions + using DigitsType = std::vector<o2::tpc::Digit>; + using LabelType = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; + mergeHelper<DigitsType>("TPCDigit_", tpcsectors, activeSectors, *originfile, pc); + if (domctruth) { + mergeHelper<LabelType>("TPCDigitMCTruth_", tpcsectors, activeSectors, *originfile, pc); + } + originfile->Close(); + delete originfile; + } +} + +class Task +{ + public: + Task(std::vector<int> laneConfig, std::vector<int> tpcsectors, bool mctruth) : mLanes(laneConfig), mTPCSectors(tpcsectors), mDoMCTruth(mctruth) + { + } + + void run(framework::ProcessingContext& pc) + { + LOG(INFO) << "Preparing digits (from digit chunks) for reconstruction"; + + TStopwatch w; + w.Start(); + publishMergedTimeframes(mLanes, mTPCSectors, mDoMCTruth, pc); + + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + + LOG(INFO) << "DIGIT PUBLISHING TOOK " << w.RealTime(); + return; + } + + void init(framework::InitContext& ctx) + { + } + + private: + bool mDoMCTruth = true; + std::vector<int> mLanes; + std::vector<int> mTPCSectors; +}; + +/// create the processor spec +/// describing a processor aggregating digits for various TPC sectors and writing them to file +/// MC truth information is also aggregated and written out +DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector<int> const& tpcsectors, bool mctruth, bool publish = true) +{ + //data definitions + using DigitsOutputType = std::vector<o2::tpc::Digit>; + using CommonModeOutputType = std::vector<o2::tpc::CommonMode>; + + std::vector<OutputSpec> outputs; // define channel by triple of (origin, type id of data to be sent on this channel, subspecification) + if (publish) { + // effectively the input expects one sector per subspecification + for (int s = 0; s < 36; ++s) { + OutputLabel binding{std::to_string(s)}; + outputs.emplace_back(/*binding,*/ "TPC", "DIGITS", static_cast<SubSpecificationType>(s), Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(/*binding,*/ "TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(s), Lifetime::Timeframe); + } + } + } + + return DataProcessorSpec{ + "TPCDigitMerger", {}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<Task>(laneConfiguration, tpcsectors, mctruth)}, Options{}}; +} + +} // end namespace tpc +} // end namespace o2 + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + auto numlanes = configcontext.options().get<int>("tpc-lanes"); + bool mctruth = !configcontext.options().get<bool>("disable-mc"); + auto tpcsectors = o2::RangeTokenizer::tokenize<int>(configcontext.options().get<std::string>("tpc-sectors")); + + std::vector<int> lanes(numlanes); + std::iota(lanes.begin(), lanes.end(), 0); + specs.emplace_back(o2::tpc::getSpec(lanes, tpcsectors, mctruth)); + return specs; +} diff --git a/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx b/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx index 66d9b25966598..015cfdf48f892 100644 --- a/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx +++ b/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx b/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx new file mode 100644 index 0000000000000..6c49fe5539984 --- /dev/null +++ b/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterSharingMapSpec.cxx +/// @brief Device to produce TPC clusters sharing map +/// \author ruben.shahoyan@cern.ch + +#include <gsl/span> +#include <TStopwatch.h> +#include <vector> +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "GPUO2InterfaceRefit.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" + +using namespace o2::framework; +using namespace o2::tpc; + +void ClusterSharingMapSpec::run(ProcessingContext& pc) +{ + TStopwatch timer; + + const auto tracksTPC = pc.inputs().get<gsl::span<o2::tpc::TrackTPC>>("trackTPC"); + const auto tracksTPCClRefs = pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs"); + const auto& clustersTPC = getWorkflowTPCInput(pc); + + auto& bufVec = pc.outputs().make<std::vector<unsigned char>>(Output{o2::header::gDataOriginTPC, "CLSHAREDMAP", 0}, clustersTPC->clusterIndex.nClustersTotal); + o2::gpu::GPUO2InterfaceRefit::fillSharedClustersMap(&clustersTPC->clusterIndex, tracksTPC, tracksTPCClRefs.data(), bufVec.data()); + + timer.Stop(); + LOGF(INFO, "Timing for TPC clusters sharing map creation: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime()); +} diff --git a/Detectors/TPC/workflow/src/ClustererSpec.cxx b/Detectors/TPC/workflow/src/ClustererSpec.cxx index 59b3336a840cf..c35b474b2e53d 100644 --- a/Detectors/TPC/workflow/src/ClustererSpec.cxx +++ b/Detectors/TPC/workflow/src/ClustererSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx index b5d97bb2931ff..ca1a1d021abeb 100644 --- a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,7 @@ namespace tpc void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { - std::string dictPath = ic.options().get<std::string>("tpc-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); } @@ -61,7 +62,7 @@ DataProcessorSpec getEntropyDecoderSpec() Inputs{InputSpec{"ctf", "TPC", "CTFDATA", 0, Lifetime::Timeframe}}, Outputs{OutputSpec{{"output"}, "TPC", "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, - Options{{"tpc-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF decoding dictionary"}}}}; + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; } } // namespace tpc diff --git a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx index e89992a9cf963..5ef7b58dfc858 100644 --- a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,7 +30,7 @@ namespace tpc void EntropyEncoderSpec::init(o2::framework::InitContext& ic) { mCTFCoder.setCombineColumns(!ic.options().get<bool>("no-ctf-columns-combining")); - std::string dictPath = ic.options().get<std::string>("tpc-ctf-dictionary"); + std::string dictPath = ic.options().get<std::string>("ctf-dict"); if (!dictPath.empty() && dictPath != "none") { mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); } @@ -82,7 +83,7 @@ DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile) Inputs{{"input", "TPC", inputType, 0, Lifetime::Timeframe}}, Outputs{{"TPC", "CTFDATA", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>(inputFromFile)}, - Options{{"tpc-ctf-dictionary", VariantType::String, "ctf_dictionary.root", {"File of CTF encoding dictionary"}}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}, {"no-ctf-columns-combining", VariantType::Bool, false, {"Do not combine correlated columns in CTF"}}}}; } diff --git a/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx new file mode 100644 index 0000000000000..b083a5133fae9 --- /dev/null +++ b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FileReaderWorkflow.cxx + +#include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TrackReaderSpec.h" + +#include "Algorithm/RangeTokenizer.h" + +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + using namespace o2::framework; + + std::vector<ConfigParamSpec> options{ + {"input-type", VariantType::String, "clusters", {"clusters, tracks"}}, + {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver + +using namespace o2::framework; + +enum struct Input { Clusters, + Tracks +}; + +const std::unordered_map<std::string, Input> InputMap{ + {"clusters", Input::Clusters}, + {"tracks", Input::Tracks}}; + +/// MC info is processed by default, disabled by using command line option `--disable-mc` +/// +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + + auto inputType = cfgc.options().get<std::string>("input-type"); + bool doMC = not cfgc.options().get<bool>("disable-mc"); + + std::vector<Input> inputTypes; + try { + inputTypes = o2::RangeTokenizer::tokenize<Input>(inputType, [](std::string const& token) { return InputMap.at(token); }); + } catch (std::out_of_range&) { + throw std::invalid_argument(std::string("invalid input type: ") + inputType); + } + auto isEnabled = [&inputTypes](Input type) { + return std::find(inputTypes.begin(), inputTypes.end(), type) != inputTypes.end(); + }; + + if (isEnabled(Input::Clusters)) { + specs.emplace_back(o2::tpc::getClusterReaderSpec(doMC)); + } + + if (isEnabled(Input::Tracks)) { + + specs.push_back(o2::tpc::getTPCTrackReaderSpec(doMC)); + } + + return std::move(specs); +} diff --git a/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx b/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx new file mode 100644 index 0000000000000..dbe7908403d35 --- /dev/null +++ b/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx @@ -0,0 +1,372 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <memory> +#include <vector> +#include <string> +#include <algorithm> +#include <cassert> +#include <cmath> +#include "fmt/format.h" + +#include "TFile.h" +#include "DetectorsRaw/RDHUtils.h" +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/InputRecordWalker.h" +#include "DPLUtils/RawParser.h" +#include "Headers/DataHeader.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "DataFormatsTPC/Constants.h" +#include "CommonConstants/LHCConstants.h" + +#include "DataFormatsTPC/Defs.h" +#include "DataFormatsTPC/IDC.h" +#include "TPCBase/Utils.h" +#include "TPCBase/RDHUtils.h" +#include "TPCBase/Mapper.h" + +using namespace o2::framework; +using o2::constants::lhc::LHCMaxBunches; +using o2::header::gDataOriginTPC; +using o2::tpc::constants::LHCBCPERTIMEBIN; +using RDHUtils = o2::raw::RDHUtils; + +namespace o2::tpc +{ + +class IDCToVectorDevice : public o2::framework::Task +{ + public: + using FEEIDType = rdh_utils::FEEIDType; + IDCToVectorDevice(const std::vector<uint32_t>& crus) : mCRUs(crus) {} + + void init(o2::framework::InitContext& ic) final + { + // set up ADC value filling + if (ic.options().get<bool>("write-debug")) { + mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>("idc_vector_debug.root", "recreate"); + } + const auto pedestalFile = ic.options().get<std::string>("pedestal-file"); + if (pedestalFile.length()) { + LOGP(info, "Setting pedestal file: {}", pedestalFile); + auto calPads = utils::readCalPads(pedestalFile, "Pedestals"); + if (calPads.size() != 1) { + LOGP(error, "Pedestal could not be loaded from file {}", pedestalFile); + } else { + for (auto p : calPads) { + mNoisePedestal.emplace_back(p); + } + } + } + + initIDC(); + } + + void run(o2::framework::ProcessingContext& pc) final + { + std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; // TODO: Change to IDC when changed in DD + const auto& mapper = Mapper::instance(); + + uint32_t heartbeatOrbit = 0; + uint32_t heartbeatBC = 0; + uint32_t tfCounter = 0; + bool first = true; + + CalPad* pedestals = nullptr; + if (mNoisePedestal.size() && mNoisePedestal[0]) { + pedestals = mNoisePedestal[0].get(); + } + + for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + // ---| extract hardware information to do the processing |--- + const auto feeId = (FEEIDType)dh->subSpecification; + const auto link = rdh_utils::getLink(feeId); + const uint32_t cruID = rdh_utils::getCRU(feeId); + const auto endPoint = rdh_utils::getEndPoint(feeId); + tfCounter = dh->tfCounter; + + // only select IDCs + // ToDo: cleanup once IDCs will be propagated not as RAWDATA, but IDC. + if (link != rdh_utils::IDCLinkID) { + continue; + } + LOGP(info, "IDC Processing firstTForbit {:9}, tfCounter {:5}, run {:6}, feeId {:6} ({:3}/{}/{:2})", dh->firstTForbit, dh->tfCounter, dh->runNumber, feeId, cruID, endPoint, link); + + if (std::find(mCRUs.begin(), mCRUs.end(), cruID) == mCRUs.end()) { + LOGP(error, "IDC CRU {:3} not configured in CRUs, skipping", cruID); + continue; + } + + const CRU cru(cruID); + const int sector = cru.sector(); + const auto& partInfo = mapper.getPartitionInfo(cru.partition()); + const int fecLinkOffsetCRU = (partInfo.getNumberOfFECs() + 1) / 2; + const int fecSectorOffset = partInfo.getSectorFECOffset(); + const GlobalPadNumber regionPadOffset = Mapper::GLOBALPADOFFSET[cru.region()]; + const GlobalPadNumber numberPads = Mapper::PADSPERREGION[cru.region()]; + int sampaOnFEC{}, channelOnSAMPA{}; + auto& idcVec = mIDCvectors[cruID]; + auto& infoVec = mIDCInfos[cruID]; + + // ---| data loop |--- + const gsl::span<const char> raw = pc.inputs().get<gsl::span<char>>(ref); + o2::framework::RawParser parser(raw.data(), raw.size()); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + const auto size = it.size(); + assert(size == sizeof(idc::Container)); + auto data = it.data(); + auto& idcs = *((idc::Container*)(data)); + const uint32_t orbit = idcs.header.heartbeatOrbit; + const uint32_t bc = idcs.header.heartbeatBC; + //LOGP(info, "IDC Procssing orbit/BC: {:9}/{:4}", orbit, bc); + + auto infoIt = std::find(infoVec.begin(), infoVec.end(), orbit); + if (!infoVec.size()) { + infoVec.emplace_back(orbit, bc); + infoIt = infoVec.end() - 1; + //} else if (!infoVec.back().matches(orbit, bc)) { + } else if (infoIt == infoVec.end()) { + auto& lastInfo = infoVec.back(); + if ((orbit - lastInfo.heartbeatOrbit) != mNOrbitsIDC) { + LOGP(error, "received packet with invalid jump in idc orbit ({} - {} == {} != {})", orbit, lastInfo.heartbeatOrbit, orbit - lastInfo.heartbeatOrbit, mNOrbitsIDC); + } + infoVec.emplace_back(orbit, bc); + infoIt = infoVec.end() - 1; + } + + // check if end poit was already processed + auto& lastInfo = *infoIt; + if (lastInfo.wasEPseen(endPoint)) { + LOGP(info, "Already received another data packet for CRU {}, ep {}, orbit {}, bc {}", cruID, endPoint, orbit, bc); + continue; + } + + lastInfo.setEPseen(endPoint); + // idc value offset in present time frame + const size_t idcOffset = std::distance(infoVec.begin(), infoIt); + + // TODO: for debugging, remove later + /* + auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV6>(); + const auto feeId2 = (FEEIDType)RDHUtils::getFEEID(*rdhPtr); + const auto link2 = rdh_utils::getLink(feeId2); + const uint32_t cruID2 = rdh_utils::getCRU(feeId2); + const auto endPoint2 = rdh_utils::getEndPoint(feeId2); + const auto detField = RDHUtils::getDetectorField(*rdhPtr); + LOGP(info, "processing IDCs for CRU {}, ep {}, feeId {:6} ({:3}/{}/{:2}), detField: {}, orbit {}, bc {}, idcOffset {}, idcVec size {}, epSeen {:02b}", cruID, endPoint, feeId2, cruID2, endPoint2, link2, detField, orbit, bc, idcOffset, idcVec.size(), lastInfo.epSeen); + */ + + const float norm = 1. / float(mTimeStampsPerIntegrationInterval); + for (uint32_t iLink = 0; iLink < idc::Links; ++iLink) { + if (!idcs.hasLink(iLink)) { + continue; + } + const int fecInSector = iLink + endPoint * fecLinkOffsetCRU + fecSectorOffset; + + for (uint32_t iChannel = 0; iChannel < idc::Channels; ++iChannel) { + auto val = idcs.getChannelValueFloat(iLink, iChannel); + Mapper::getSampaAndChannelOnFEC(cruID, iChannel, sampaOnFEC, channelOnSAMPA); + const GlobalPadNumber padInSector = mapper.globalPadNumber(fecInSector, sampaOnFEC, channelOnSAMPA); + if (pedestals) { + val -= pedestals->getValue(sector, padInSector) * mTimeStampsPerIntegrationInterval; + val *= norm; + } + const GlobalPadNumber padInRegion = padInSector - regionPadOffset; + const GlobalPadNumber vectorPosition = padInRegion + idcOffset * numberPads; + // TODO: for debugging, remove later + //auto rawVal = idcs.getChannelValue(iLink, iChannel); + //auto rawValF = idcs.getChannelValueFloat(iLink, iChannel); + //LOGP(info, "filling channel {}, link {}, fecLinkOffsetCRU {:2}, fecSectorOffset {:3}, fecInSector {:3}, idcVec[{} ({})] = {} ({} / {})", iChannel, iLink, fecLinkOffsetCRU, fecSectorOffset, fecInSector, vectorPosition, padInRegion, val, rawVal, rawValF); + idcVec[vectorPosition] = val; + } + } + } + } + + if (mDebugStream) { + writeDebugOutput(tfCounter); + } + snapshotIDCs(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "endOfStream"); + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + if (mDebugStream) { + mDebugStream->Close(); + } + } + + private: + /// IDC information for each cru + struct IDCInfo { + IDCInfo() = default; + IDCInfo(const IDCInfo&) = default; + IDCInfo(uint32_t orbit, uint16_t bc) : heartbeatOrbit(orbit), heartbeatBC(bc) {} + + uint32_t heartbeatOrbit{0}; + uint16_t heartbeatBC{0}; + uint16_t epSeen{0}; + + bool operator==(const uint32_t orbit) const { return (heartbeatOrbit == orbit); } + bool operator==(const IDCInfo& inf) const { return (inf.heartbeatOrbit == heartbeatOrbit) && (inf.heartbeatBC == heartbeatBC) && (inf.epSeen == epSeen); } + void setEPseen(uint32_t ep) { epSeen |= uint16_t(1 << ep); } + bool wasEPseen(uint32_t ep) const { return epSeen & uint16_t(1 << ep); } + bool matches(uint32_t orbit, int16_t bc) const { return ((heartbeatOrbit == orbit) && (heartbeatBC == bc)); } + bool hasBothEPs() const { return epSeen == 3; } + }; + + const int mNOrbitsIDC{12}; ///< number of orbits over which IDCs are integrated, TODO: take from IDC header + const int mTimeStampsPerIntegrationInterval{(LHCMaxBunches * mNOrbitsIDC) / LHCBCPERTIMEBIN}; ///< number of time stamps for each integration interval (5346) + const uint32_t mMaxIDCPerTF{uint32_t(std::ceil(256.f / mNOrbitsIDC))}; ///< maximum number of IDCs expected per TF, TODO: better way to get max number of orbits + std::vector<uint32_t> mCRUs; ///< CRUs expected for this device + std::unordered_map<uint32_t, std::vector<float>> mIDCvectors; ///< decoded IDCs per cru for each pad in the region over all IDC packets in the TF + std::unordered_map<uint32_t, std::vector<IDCInfo>> mIDCInfos; ///< IDC packet information within the TF + std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugStream; ///< debug output streamer + std::vector<std::unique_ptr<CalPad>> mNoisePedestal{}; ///< noise and pedestal values + + //____________________________________________________________________________ + void snapshotIDCs(DataAllocator& output) + { + LOGP(info, "snapshotIDCs"); + + // check integrety of data between CRUs + size_t orbitsInTF = 0; + std::vector<IDCInfo> const* infVecComp = nullptr; + std::vector<uint64_t> orbitBCInfo; + + for (const auto& [cru, infVec] : mIDCInfos) { + + for (const auto& inf : infVec) { + if (!inf.hasBothEPs()) { + LOGP(fatal, "IDC CRU {:3}: data missing at ({:8}, {:4}) for one or both end points {:02b}", cru, inf.heartbeatOrbit, inf.heartbeatBC, inf.epSeen); + } + } + + if (!infVecComp) { + infVecComp = &infVec; + orbitsInTF = infVec.size(); + std::for_each(infVec.begin(), infVec.end(), [&orbitBCInfo](const auto& inf) { orbitBCInfo.emplace_back((uint64_t(inf.heartbeatOrbit) << 32) + uint64_t(inf.heartbeatBC)); }); + continue; + } + + if (orbitsInTF != infVec.size()) { + LOGP(fatal, "IDC CRU {:3}: unequal number of IDC values {} != {}", cru, orbitsInTF, infVec.size()); + } + + if (!std::equal(infVecComp->begin(), infVecComp->end(), infVec.begin())) { + LOGP(fatal, "IDC CRU {:3}: mismatch in orbits"); + } + } + + // send data + for (auto& [cru, idcVec] : mIDCvectors) { + idcVec.resize(Mapper::PADSPERREGION[CRU(cru).region()] * orbitsInTF); + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + output.snapshot(Output{gDataOriginTPC, "IDCVECTOR", subSpec}, idcVec); + output.snapshot(Output{gDataOriginTPC, "IDCORBITS", subSpec}, orbitBCInfo); + } + + // clear output + initIDC(); + } + + //____________________________________________________________________________ + void initIDC() + { + for (const auto cruID : mCRUs) { + const CRU cru(cruID); + const GlobalPadNumber numberPads = Mapper::PADSPERREGION[cru.region()] * mMaxIDCPerTF; + auto& idcVec = mIDCvectors[cruID]; + idcVec.resize(numberPads); + std::fill(idcVec.begin(), idcVec.end(), -1.f); + + auto& infosCRU = mIDCInfos[cruID]; + infosCRU.clear(); + } + } + + //____________________________________________________________________________ + void writeDebugOutput(uint32_t tfCounter) + { + const auto& mapper = Mapper::instance(); + + mDebugStream->GetFile()->cd(); + auto& stream = (*mDebugStream) << "idcs"; + uint32_t seen = 0; + for (auto cru : mCRUs) { + if (mIDCInfos.find(cru) == mIDCInfos.end()) { + continue; + } + auto& infos = mIDCInfos[cru]; + auto& idcVec = mIDCvectors[cru]; + + for (int i = 0; i < infos.size(); ++i) { + auto& info = infos[i]; + + auto idcFirst = idcVec.begin() + i * Mapper::PADSPERREGION[cru % Mapper::NREGIONS]; + auto idcLast = idcFirst + Mapper::PADSPERREGION[cru % Mapper::NREGIONS]; + std::vector<float> idcs(idcFirst, idcLast); + std::vector<short> cpad(idcs.size()); + std::vector<short> row(idcs.size()); + for (int ipad = 0; ipad < idcs.size(); ++ipad) { + const auto& padPos = mapper.padPos(ipad + Mapper::GLOBALPADOFFSET[cru % Mapper::NREGIONS]); + row[ipad] = (short)padPos.getRow(); + const short pads = (short)mapper.getNumberOfPadsInRowSector(row[ipad]); + cpad[ipad] = (short)padPos.getPad() - pads / 2; + } + float mean = std::accumulate(idcs.begin(), idcs.end(), 0.f) / float(idcs.size()); + + stream << "cru=" << cru + << "epSeen=" << info.epSeen + << "tfCounter=" << tfCounter + << "orbit=" << info.heartbeatOrbit + << "bc=" << info.heartbeatBC + << "idcs=" << idcs + << "cpad=" << cpad + << "row=" << row + << "idc_mean=" << mean + << "\n"; + } + } + } +}; + +o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec, std::vector<uint32_t> const& crus) +{ + using device = o2::tpc::IDCToVectorDevice; + + std::vector<OutputSpec> outputs; + for (const uint32_t cru : crus) { + const header::DataHeader::SubSpecificationType subSpec{cru << 7}; + outputs.emplace_back(gDataOriginTPC, "IDCVECTOR", subSpec, Lifetime::Timeframe); + outputs.emplace_back(gDataOriginTPC, "IDCORBITS", subSpec, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + fmt::format("tpc-idc-to-vector"), + select(inputSpec.data()), + outputs, + AlgorithmSpec{adaptFromTask<device>(crus)}, + Options{ + {"write-debug", VariantType::Bool, false, {"write a debug output tree."}}, + {"pedestal-file", VariantType::String, "", {"file with pedestals and noise for zero suppression"}}, + } // end Options + }; // end DataProcessorSpec +} +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/KryptonClustererSpec.cxx b/Detectors/TPC/workflow/src/KryptonClustererSpec.cxx new file mode 100644 index 0000000000000..d0119f719193c --- /dev/null +++ b/Detectors/TPC/workflow/src/KryptonClustererSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <memory> + +#include "Framework/Task.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Headers/DataHeader.h" + +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/KrCluster.h" +#include "TPCReconstruction/KrBoxClusterFinder.h" +#include "TPCWorkflow/KryptonClustererSpec.h" + +using namespace o2::framework; +using namespace o2::header; +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +namespace o2 +{ +namespace tpc +{ + +class KrBoxClusterFinderDevice : public o2::framework::Task +{ + public: + KrBoxClusterFinderDevice() : mClusterFinder{std::make_unique<KrBoxClusterFinder>()} {} + + void init(o2::framework::InitContext& ic) final + { + mClusterFinder->init(); + } + + void run(o2::framework::ProcessingContext& pc) final + { + for (auto const& inputRef : InputRecordWalker(pc.inputs())) { + auto const* sectorHeader = DataRefUtils::getHeader<TPCSectorHeader*>(inputRef); + if (sectorHeader == nullptr) { + LOGP(error, "sector header missing on header stack for input on ", inputRef.spec->binding); + continue; + } + + const int sector = sectorHeader->sector(); + auto inDigits = pc.inputs().get<gsl::span<o2::tpc::Digit>>(inputRef); + + mClusterFinder->loopOverSector(inDigits, sector); + + snapshotClusters(pc.outputs(), mClusterFinder->getClusters(), sector); + + LOGP(info, "processed sector {} with {} digits and {} reconstructed clusters", sector, inDigits.size(), mClusterFinder->getClusters().size()); + + mClusterFinder->resetClusters(); + } + + ++mProcessedTFs; + LOGP(info, "Number of processed time frames: {}", mProcessedTFs); + } + + private: + std::unique_ptr<KrBoxClusterFinder> mClusterFinder; + uint32_t mProcessedTFs{0}; + + //____________________________________________________________________________ + void snapshotClusters(DataAllocator& output, const std::vector<o2::tpc::KrCluster>& clusters, int sector) + { + o2::tpc::TPCSectorHeader header{sector}; + header.activeSectors = (0x1 << sector); + output.snapshot(Output{gDataOriginTPC, "KRCLUSTERS", static_cast<SubSpecificationType>(sector), Lifetime::Timeframe, header}, clusters); + } +}; + +o2::framework::DataProcessorSpec getKryptonClustererSpec() +{ + using device = o2::tpc::KrBoxClusterFinderDevice; + + std::vector<InputSpec> inputs{ + InputSpec{"digits", gDataOriginTPC, "DIGITS", 0, Lifetime::Timeframe}, + }; + + std::vector<OutputSpec> outputs; + outputs.emplace_back(gDataOriginTPC, "KRCLUSTERS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tpc-krypton-clusterer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{} // end Options + }; // end DataProcessorSpec +} +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/LaserTrackFilterSpec.cxx b/Detectors/TPC/workflow/src/LaserTrackFilterSpec.cxx new file mode 100644 index 0000000000000..2d5ae71ac4c39 --- /dev/null +++ b/Detectors/TPC/workflow/src/LaserTrackFilterSpec.cxx @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file LaserTrackFilterSpec.cxx +/// @brief Device to filter out laser tracks + +#include <algorithm> +#include <iterator> + +#include "DataFormatsTPC/TrackTPC.h" +#include "TPCCalibration/CalibLaserTracks.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class LaserTrackFilterDevice : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + } + + void run(o2::framework::ProcessingContext& pc) final + { + const auto tracks = pc.inputs().get<gsl::span<TrackTPC>>("tracks"); + std::copy_if(tracks.begin(), tracks.end(), std::back_inserter(mLaserTracks), + [this](const auto& track) { return isLaserTrackCandidate(track); }); + + LOGP(info, "Filtered {} laser track candidates out of {} total tpc tracks", mLaserTracks.size(), tracks.size()); + + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + } + + private: + std::vector<TrackTPC> mLaserTracks; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + output.snapshot(Output{"TPC", "LASERTRACKS", 0}, mLaserTracks); + mLaserTracks.clear(); + } + + bool isLaserTrackCandidate(const TrackTPC& track) + { + if (track.getP() < 1) { + return false; + } + + if (track.getNClusters() < 80) { + //return false; + } + + if (track.hasBothSidesClusters()) { + return false; + } + + const auto& parOutLtr = track.getOuterParam(); + if (parOutLtr.getX() < 220) { + return false; + } + + const int side = track.hasCSideClusters(); + if (!CalibLaserTracks::hasNearbyLaserRod(parOutLtr, side)) { + return false; + } + + return true; + } +}; + +DataProcessorSpec getLaserTrackFilter() +{ + using device = o2::tpc::LaserTrackFilterDevice; + + std::vector<OutputSpec> outputs; + outputs.emplace_back("TPC", "LASERTRACKS", 0, o2::framework::Lifetime::Timeframe); + + return DataProcessorSpec{ + "tpc-laser-track-filter", + Inputs{{"tracks", "TPC", "TRACKS", 0}}, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{}}; +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx b/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx index cfb3905b3b3c1..5aec22a921c9a 100644 --- a/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx +++ b/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "Framework/Logger.h" #include "DPLUtils/RawParser.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "DataFormatsTPC/ZeroSuppressionLinkBased.h" #include "DataFormatsTPC/Digit.h" @@ -140,7 +142,7 @@ o2::framework::DataProcessorSpec getLinkZSToDigitsSpec(int channel, const std::s processAttributes->activeSectors |= (0x1 << sector); - LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin.as<std::string>(), dh->dataDescription.as<std::string>(), dh->subSpecification); + LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); LOGP(debug, "Payload size: {}", dh->payloadSize); LOGP(debug, "CRU: {}; linkID: {}; dataWrapperID: {}; globalLinkID: {}", cruID, linkID, dataWrapperID, globalLinkID); diff --git a/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx new file mode 100644 index 0000000000000..a37eac105834c --- /dev/null +++ b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MIPTrackFilterSpec.h +/// \brief Workflow to filter MIP tracks and streams them to other devices. +/// \author Thiago Badaró <thiago.saramela@usp.br> + +#include "TPCWorkflow/MIPTrackFilterSpec.h" + +#include <algorithm> +#include <iterator> +#include <vector> +#include <memory> + +//o2 includes +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/TrackCuts.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ConfigParamRegistry.h" + +using namespace o2::framework; + +namespace o2::tpc +{ + +class MIPTrackFilterDevice : public Task +{ + public: + void init(framework::InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& eos) final; + + private: + void sendOutput(DataAllocator& output); + + TrackCuts mCuts{}; ///< Tracks cuts object + std::vector<TrackTPC> mMIPTracks; ///< Filtered MIP tracks +}; + +void MIPTrackFilterDevice::init(framework::InitContext& ic) +{ + const double minP = ic.options().get<double>("min-momentum"); + const double maxP = ic.options().get<double>("max-momentum"); + assert(minP < maxP); + const int minClusters = std::max(10, ic.options().get<int>("min-clusters")); + + mCuts.setPMin(minP); + mCuts.setPMax(maxP); + mCuts.setNClusMin(minClusters); +} + +void MIPTrackFilterDevice::run(ProcessingContext& pc) +{ + const auto tracks = pc.inputs().get<gsl::span<TrackTPC>>("tracks"); + + std::copy_if(tracks.begin(), tracks.end(), std::back_inserter(mMIPTracks), + [this](const auto& track) { return this->mCuts.goodTrack(track); }); + + LOG(INFO) << mMIPTracks.size() << " MIP tracks in a total of " << tracks.size() << " tracks"; + + pc.outputs().snapshot(Output{"TPC", "MIPS", 0, Lifetime::Timeframe}, mMIPTracks); + mMIPTracks.clear(); +} + +void MIPTrackFilterDevice::endOfStream(EndOfStreamContext& eos) +{ + LOG(INFO) << "Finalizig MIP Tracks filter"; +} + +DataProcessorSpec getMIPTrackFilterSpec() +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("TPC", "MIPS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tpc-miptrack-filter", + Inputs{ + InputSpec{"tracks", "TPC", "TRACKS"}, + }, + outputs, + adaptFromTask<MIPTrackFilterDevice>(), + Options{ + {"min-momentum", VariantType::Double, 0.4, {"minimum momentum cut"}}, + {"max-momentum", VariantType::Double, 0.6, {"maximum momentum cut"}}, + {"min-clusters", VariantType::Int, 60, {"minimum number of clusters in a track"}}}}; +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/MonitorWorkflowSpec.cxx b/Detectors/TPC/workflow/src/MonitorWorkflowSpec.cxx new file mode 100644 index 0000000000000..5d6336ce7fb28 --- /dev/null +++ b/Detectors/TPC/workflow/src/MonitorWorkflowSpec.cxx @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include <thread> +#include <chrono> +#include "fmt/format.h" + +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/InputRecordWalker.h" + +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "Headers/DataHeader.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" + +#include "TPCQC/Clusters.h" +#include "TPCBase/Mapper.h" +#include "TPCMonitor/SimpleEventDisplayGUI.h" +#include "TPCCalibration/DigitDump.h" +#include "TPCReconstruction/RawReaderCRU.h" +#include "TPCWorkflow/CalibProcessingHelper.h" +using namespace o2::framework; +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +namespace o2::tpc +{ + +class TPCMonitorDevice : public o2::framework::Task +{ + public: + TPCMonitorDevice(bool useDigits) : mUseDigits(useDigits) {} + + void init(o2::framework::InitContext& ic) final + { + mBlocking = ic.options().get<bool>("blocking"); + + // set up ADC value filling + mRawReader.createReader(""); + mDigitDump.init(); + mDigitDump.setInMemoryOnly(); + const auto pedestalFile = ic.options().get<std::string>("pedestal-file"); + if (pedestalFile.length()) { + LOGP(info, "Setting pedestal file: {}", pedestalFile); + mDigitDump.setPedestalAndNoiseFile(pedestalFile); + } + + // TODO: Get rid of digit dump and use mDigits? + mRawReader.setADCDataCallback([this](const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) -> int { + const int timeBins = mDigitDump.update(padROCPos, cru, data); + mDigitDump.setNumberOfProcessedTimeBins(std::max(mDigitDump.getNumberOfProcessedTimeBins(), size_t(timeBins))); + return timeBins; + }); + + mRawReader.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + const PadRegionInfo& regionInfo = Mapper::instance().getPadRegionInfo(cruID.region()); + mDigitDump.updateCRU(cruID, rowInSector - regionInfo.getGlobalRowOffset(), padInRow, timeBin, adcValue); + return true; + }); + + if (mUseDigits) { + mEventDisplayGUI.getEventDisplay().setDigits(&mDigits); + } else { + mEventDisplayGUI.getEventDisplay().setDigits(&mDigitDump.getDigits()); + } + + const int maxTimeBins = ic.options().get<int>("max-time-bins"); + mGUIThread = std::make_unique<std::thread>(&SimpleEventDisplayGUI::startGUI, &mEventDisplayGUI, maxTimeBins); + + auto finishFunction = [this]() { + if (mGUIThread) { + mGUIThread->join(); + } + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishFunction); + } + + void run(o2::framework::ProcessingContext& pc) final + { + const auto validInputs = pc.inputs().countValidInputs(); + mEventDisplayGUI.setDataAvailable(validInputs); + + while (mBlocking && validInputs && !mEventDisplayGUI.isNextEventRequested() && !mEventDisplayGUI.isStopRequested()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + LOGP(info, "wait for next event stop {}", mEventDisplayGUI.isStopRequested()); + } + + if (mEventDisplayGUI.isStopRequested()) { + LOGP(info, "call end processing"); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + return; + } + + LOGP(info, "next event requested next {}, processing {}, updating {}", mEventDisplayGUI.isNextEventRequested(), mEventDisplayGUI.isProcessingEvent(), mEventDisplayGUI.isWaitingForDigitUpdate()); + if (!mEventDisplayGUI.isNextEventRequested() && !mEventDisplayGUI.isProcessingEvent()) { + return; + } + mEventDisplayGUI.resetNextEventReqested(); + + const auto tf = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true))->tfCounter; + mEventDisplayGUI.getEventDisplay().setPresentEventNumber(size_t(tf)); + LOGP(info, "processing tF {}", tf); + + if (!mUseDigits) { + mDigitDump.clearDigits(); + auto& reader = mRawReader.getReaders()[0]; + calib_processing_helper::processRawData(pc.inputs(), reader); + + mDigitDump.incrementNEvents(); + } else { + // clear digits + std::for_each(mDigits.begin(), mDigits.end(), [](auto& vec) { vec.clear(); }); + + copyDigits(pc.inputs()); + } + + mEventDisplayGUI.resetUpdatingDigits(); + mEventDisplayGUI.setDataAvailable(false); + } + + private: + SimpleEventDisplayGUI mEventDisplayGUI; ///< Event display + DigitDump mDigitDump; ///< used to covert + std::array<std::vector<Digit>, Sector::MAXSECTOR> mDigits; ///< TPC digits + std::unique_ptr<std::thread> mGUIThread; ///< thread running the GUI + + rawreader::RawReaderCRUManager mRawReader; + bool mUseDigits{false}; + bool mBlocking{false}; + + void copyDigits(InputRecord& inputs) + { + std::vector<InputSpec> filter = { + {"check", ConcreteDataTypeMatcher{"TPC", "DIGITS"}, Lifetime::Timeframe}, + }; + for (auto const& inputRef : InputRecordWalker(inputs)) { + auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(inputRef); + if (sectorHeader == nullptr) { + LOG(ERROR) << "sector header missing on header stack for input on " << inputRef.spec->binding; + continue; + } + const int sector = sectorHeader->sector(); + mDigits[sector] = inputs.get<std::vector<o2::tpc::Digit>>(inputRef); + } + } +}; + +DataProcessorSpec getMonitorWorkflowSpec(bool useDigitsAsInput) +{ + std::string inputSpec = "tpcraw:TPC/RAWDATA"; + if (useDigitsAsInput) { + inputSpec = "tpcdigits:TPC/DIGITS"; + } + + std::vector<OutputSpec> outputs; + + return DataProcessorSpec{ + "tpc-monitor-workflow", + select(inputSpec.data()), + outputs, + AlgorithmSpec{adaptFromTask<TPCMonitorDevice>(useDigitsAsInput)}, + Options{ + {"pedestal-file", VariantType::String, "", {"file with pedestals and noise for zero suppression"}}, + {"max-time-bins", VariantType::Int, 114048, {"maximum number of time bins to show"}}, + {"blocking", VariantType::Bool, false, {"block processing until next event is received"}}, + } // end Options + }; // end DataProcessorSpec +} +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/ProcessingHelpers.cxx b/Detectors/TPC/workflow/src/ProcessingHelpers.cxx new file mode 100644 index 0000000000000..17a5c70e94b0d --- /dev/null +++ b/Detectors/TPC/workflow/src/ProcessingHelpers.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <string> + +#include <FairMQDevice.h> +#include "Headers/DataHeader.h" +#include "Framework/Logger.h" +#include "Framework/ProcessingContext.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DataRefUtils.h" +#include "Framework/InputRecord.h" +#include "Framework/ServiceRegistry.h" + +#include "TPCWorkflow/ProcessingHelpers.h" + +using namespace o2::framework; +using namespace o2::tpc; + +// taken from CTFWriterSpec, TODO: should this be put to some more general location? +uint64_t processing_helpers::getRunNumber(ProcessingContext& pc) +{ + const std::string NAStr = "NA"; + + uint64_t run = 0; + const auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + if (dh->runNumber != 0) { + run = dh->runNumber; + } + // check runNumber with FMQ property, if set, override DH number + { + auto runNStr = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("runNumber", NAStr); + if (runNStr != NAStr) { + size_t nc = 0; + auto runNProp = std::stol(runNStr, &nc); + if (nc != runNStr.size()) { + LOGP(error, "Property runNumber={} is provided but is not a number, ignoring", runNStr); + } else { + run = runNProp; + } + } + } + + return run; +} diff --git a/Detectors/TPC/workflow/src/PublisherSpec.cxx b/Detectors/TPC/workflow/src/PublisherSpec.cxx deleted file mode 100644 index d6c787a37f024..0000000000000 --- a/Detectors/TPC/workflow/src/PublisherSpec.cxx +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file PublisherSpec.cxx -/// @author Matthias Richter -/// @since 2018-12-06 -/// @brief Processor spec for a reader of TPC data from ROOT file - -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "TPCWorkflow/PublisherSpec.h" -#include "Headers/DataHeader.h" -#include "TPCBase/Sector.h" -#include "DataFormatsTPC/TPCSectorHeader.h" -#include <memory> // for make_shared, make_unique, unique_ptr -#include <array> -#include <vector> -#include <utility> // std::move -#include <stdexcept> //std::invalid_argument -#include <TFile.h> -#include <TTree.h> -#include <TBranch.h> - -using namespace o2::framework; -using namespace o2::header; - -namespace o2 -{ -namespace tpc -{ - -/// create a processor spec -/// read data from multiple tree branches from ROOT file and publish -/// data are expected to be stored in separated branches per sector, the default -/// branch name is configurable, sector number is apended as extension '_n' -DataProcessorSpec createPublisherSpec(PublisherConf const& config, bool propagateMC, workflow_reader::Creator creator) -{ - if (config.tpcSectors.size() == 0 || config.outputIds.size() == 0) { - throw std::invalid_argument("need TPC sector and output id configuration"); - } - constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; - enum struct SectorMode { - Sector, // stored in sector branches - Full, // full TPC stored in one branch - }; - struct ProcessAttributes { - std::vector<int> sectors; - std::vector<int> outputIds; - std::vector<o2::header::DataHeader::SubSpecificationType> zeroLengthOutputs; - uint64_t activeSectors = 0; - std::array<std::shared_ptr<RootTreeReader>, NSectors> readers; - bool terminateOnEod = false; - bool finished = false; - SectorMode sectorMode = SectorMode::Sector; - }; - - auto initFunction = [config, propagateMC, creator](InitContext& ic) { - // get the option from the init context - auto filename = ic.options().get<std::string>("infile"); - auto treename = ic.options().get<std::string>("treename"); - auto clbrName = ic.options().get<std::string>(config.databranch.option.c_str()); - auto mcbrName = ic.options().get<std::string>(config.mcbranch.option.c_str()); - auto nofEvents = ic.options().get<int>("nevents"); - auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; - - // do a runtime check if the branch name without sector number suffix is found in the file - // if found the publisher will publish the single data set at one output route and empty - // messages at all the others - auto checkSectorMode = [&filename, &treename, &clbrName]() -> SectorMode { - std::unique_ptr<TFile> file(TFile::Open(filename.c_str())); - if (file) { - TTree* tree = reinterpret_cast<TTree*>(file->GetObjectChecked(treename.c_str(), "TTree")); - if (tree) { - const auto brlist = tree->GetListOfBranches(); - for (TObject const* entry : *brlist) { - if (clbrName == entry->GetName()) { - return SectorMode::Full; - } - } - } - file->Close(); - } - return SectorMode::Sector; - }; - - auto processAttributes = std::make_shared<ProcessAttributes>(); - { - processAttributes->terminateOnEod = ic.options().get<bool>("terminate-on-eod"); - processAttributes->sectorMode = checkSectorMode(); - auto& sectors = processAttributes->sectors; - auto& activeSectors = processAttributes->activeSectors; - auto& readers = processAttributes->readers; - auto& outputIds = processAttributes->outputIds; - auto& sectorMode = processAttributes->sectorMode; - - sectors = config.tpcSectors; - outputIds = config.outputIds; - for (auto const& s : sectors) { - // set the mask of active sectors - if (s >= NSectors) { - std::string message = std::string("invalid sector range specified, allowed 0-") + std::to_string(NSectors - 1); - // FIXME should probably be FATAL, but this doesn't seem to be handled in the DPL control flow - // at least the process is not marked dead in the DebugGUI - LOG(ERROR) << message; - throw std::invalid_argument(message); - } - activeSectors |= (uint64_t)0x1 << s; - } - - // set up the tree interface - // TODO: parallelism on sectors needs to be implemented as selector in the reader - // the data is now in parallel branches, as first attempt use an array of readers - auto outputId = outputIds.begin(); - for (auto const& sector : sectors) { - o2::header::DataHeader::SubSpecificationType subSpec = *outputId; - std::string sectorfile = filename; - if (filename.find('%') != std::string::npos) { - vector<char> formattedname(filename.length() + 10, 0); - snprintf(formattedname.data(), formattedname.size() - 1, filename.c_str(), sector); - sectorfile = formattedname.data(); - } - std::string clusterbranchname = clbrName; - std::string mcbranchname = mcbrName; - if (sectorMode == SectorMode::Sector) { - clusterbranchname += "_" + std::to_string(sector); - mcbranchname += "_" + std::to_string(sector); - } - readers[sector] = creator(treename.c_str(), // tree name - sectorfile.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - subSpec, - clusterbranchname.c_str(), // name of data branch - mcbranchname.c_str(), // name of mc label branch - config.hook); - if (sectorMode == SectorMode::Full) { - break; - } - if (++outputId == outputIds.end()) { - outputId = outputIds.begin(); - } - } - if (sectorMode == SectorMode::Full) { - // the slot of the first configured sector is used to publish the full set, all others removed - sectors.resize(1); - // the data will be published at first configured output id, zero-length data on all other output ids - processAttributes->zeroLengthOutputs.assign(++outputId, outputIds.end()); - } - } - - // set up the processing function - // using by-copy capture of the worker instance shared pointer - // the shared pointer makes sure to clean up the instance when the processing - // function gets out of scope - // FIXME: wanted to use it = sectors.begin() in the variable capture but the iterator - // is const and can not be incremented - auto processingFct = [processAttributes, config](ProcessingContext& pc) { - if (processAttributes->finished) { - return; - } - - bool eos = false; - auto const& sectors = processAttributes->sectors; - for (auto const& sector : sectors) { - auto& activeSectors = processAttributes->activeSectors; - auto& readers = processAttributes->readers; - o2::tpc::TPCSectorHeader header{sector}; - if (processAttributes->sectorMode == SectorMode::Full) { - header.sectorBits = activeSectors; - } - header.activeSectors = activeSectors; - auto& r = *(readers[sector].get()); - - // increment the reader and invoke it for the processing context - if (r.next()) { - // there is data, run the reader - r(pc, header); - } else { - // no more data, delete the reader - readers[sector].reset(); - eos = true; - } - } - - if (eos) { - processAttributes->finished = true; - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } else { - // publish empty events - auto dto = DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto mco = DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - o2::tpc::TPCSectorHeader header{0}; - header.sectorBits = 0; - header.activeSectors = processAttributes->activeSectors; - for (auto const& subSpec : processAttributes->zeroLengthOutputs) { - pc.outputs().make<char>({dto.origin, dto.description, subSpec, Lifetime::Timeframe, {header}}); - if (pc.outputs().isAllowed({mco.origin, mco.description, subSpec})) { - pc.outputs().make<char>({mco.origin, mco.description, subSpec, Lifetime::Timeframe, {header}}); - } - } - } - }; - - // return the actual processing function as a lambda function using variables - // of the init function - return processingFct; - }; - - auto createOutputSpecs = [&config, propagateMC]() { - std::vector<OutputSpec> outputSpecs; - for (size_t n = 0; n < config.outputIds.size(); ++n) { - o2::header::DataHeader::SubSpecificationType subSpec = config.outputIds[n]; - auto dto = DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto mco = DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - outputSpecs.emplace_back(OutputSpec{{"output"}, dto.origin, dto.description, subSpec, Lifetime::Timeframe}); - if (propagateMC) { - outputSpecs.emplace_back(OutputSpec{{"outputMC"}, mco.origin, mco.description, subSpec, Lifetime::Timeframe}); - } - } - return std::move(outputSpecs); - }; - - auto& dtb = config.databranch; - auto& mcb = config.mcbranch; - return DataProcessorSpec{config.processName.c_str(), - Inputs{}, // no inputs - {createOutputSpecs()}, - AlgorithmSpec(initFunction), - Options{ - {"infile", VariantType::String, "", {"Name of the input file"}}, - {"treename", VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, - {dtb.option.c_str(), VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, - {mcb.option.c_str(), VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, - {"nevents", VariantType::Int, -1, {"number of events to run"}}, - {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, - }}; -} -} // end namespace tpc -} // end namespace o2 diff --git a/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx b/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx index 69eae838dd275..aa3a6ac56468b 100644 --- a/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx +++ b/Detectors/TPC/workflow/src/RawToDigitsSpec.cxx @@ -1,30 +1,37 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/WorkflowSpec.h" +#include <vector> +#include <string> +#include "fmt/format.h" + +#include "Framework/Task.h" #include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" #include "Framework/ConfigParamRegistry.h" -#include "Framework/DataRefUtils.h" -#include "Framework/Lifetime.h" -#include "DPLUtils/RawParser.h" -#include "Headers/DataHeader.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/WorkflowSpec.h" + #include "DataFormatsTPC/TPCSectorHeader.h" -#include "DataFormatsTPC/Digit.h" +#include "Headers/DataHeader.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +#include "TPCQC/Clusters.h" +#include "TPCBase/Mapper.h" #include "TPCCalibration/DigitDump.h" #include "TPCReconstruction/RawReaderCRU.h" -#include "TPCWorkflow/RawToDigitsSpec.h" -#include "Framework/Logger.h" -#include <vector> -#include <string> - +#include "TPCWorkflow/CalibProcessingHelper.h" using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; @@ -33,192 +40,181 @@ namespace o2 namespace tpc { -o2::framework::DataProcessorSpec getRawToDigitsSpec(int channel, const std::string_view inputDef, std::vector<int> const& tpcSectors) +class TPCDigitDumpDevice : public o2::framework::Task { + public: + TPCDigitDumpDevice(const std::vector<int>& sectors) : mSectors(sectors) {} + + void init(o2::framework::InitContext& ic) final + { + // parse command line arguments + mMaxEvents = static_cast<uint32_t>(ic.options().get<int>("max-events")); + mUseOldSubspec = ic.options().get<bool>("use-old-subspec"); + const bool createOccupancyMaps = ic.options().get<bool>("create-occupancy-maps"); + mForceQuit = ic.options().get<bool>("force-quit"); + mCheckDuplicates = ic.options().get<bool>("check-for-duplicates"); + mRemoveDuplicates = ic.options().get<bool>("remove-duplicates"); + mRemoveCEdigits = ic.options().get<bool>("remove-ce-digits"); + + if (mUseOldSubspec) { + LOGP(info, "Using old subspecification (CruId << 16) | ((LinkId + 1) << (CruEndPoint == 1 ? 8 : 0))"); + } - struct ProcessAttributes { - DigitDump digitDump; ///< digits creation class - rawreader::RawReaderCRUManager rawReader; ///< GBT frame decoder - uint32_t lastOrbit{0}; ///< last processed orbit number - uint32_t maxEvents{100}; ///< maximum number of events to process - uint64_t activeSectors{0}; ///< bit mask of active sectors - bool quit{false}; ///< if workflow is ready to quit - std::vector<int> tpcSectors{}; ///< tpc sector configuration - }; - - // ===| stateful initialization |============================================= - // - auto initFunction = [channel, tpcSectors](InitContext& ic) { - // ===| create and set up processing attributes |=== - auto processAttributes = std::make_shared<ProcessAttributes>(); - // set up calibration - { - auto& digitDump = processAttributes->digitDump; - digitDump.init(); - digitDump.setInMemoryOnly(); - const auto pedestalFile = ic.options().get<std::string>("pedestal-file"); + // set up ADC value filling + mRawReader.createReader(""); + + const auto inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + if (grp) { + const auto nhbf = (int)grp->getNHBFPerTF(); + const int lastTimeBin = nhbf * 891 / 2; + mDigitDump.setTimeBinRange(0, lastTimeBin); + LOGP(info, "Using GRP NHBF = {} to set last time bin to {}, might be overwritte via --configKeyValues", nhbf, lastTimeBin); + } + + mDigitDump.init(); + mDigitDump.setInMemoryOnly(); + const auto pedestalFile = ic.options().get<std::string>("pedestal-file"); + if (pedestalFile.length()) { LOGP(info, "Setting pedestal file: {}", pedestalFile); - digitDump.setPedestalAndNoiseFile(pedestalFile); - - processAttributes->rawReader.createReader(""); - processAttributes->rawReader.setADCDataCallback([&digitDump](const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) -> Int_t { - Int_t timeBins = digitDump.update(padROCPos, cru, data); - digitDump.setNumberOfProcessedTimeBins(std::max(digitDump.getNumberOfProcessedTimeBins(), size_t(timeBins))); - return timeBins; - }); - processAttributes->maxEvents = static_cast<uint32_t>(ic.options().get<int>("max-events")); - processAttributes->tpcSectors = tpcSectors; + mDigitDump.setPedestalAndNoiseFile(pedestalFile); + } + + // set up cluster qc if requested + if (createOccupancyMaps) { + mClusterQC = std::make_unique<qc::Clusters>(); } - // ===| data processor |==================================================== - // - auto processingFct = [processAttributes, channel](ProcessingContext& pc) { - if (processAttributes->quit) { - return; + mRawReader.setADCDataCallback([this](const PadROCPos& padROCPos, const CRU& cru, const gsl::span<const uint32_t> data) -> int { + const int timeBins = mDigitDump.update(padROCPos, cru, data); + mDigitDump.setNumberOfProcessedTimeBins(std::max(mDigitDump.getNumberOfProcessedTimeBins(), size_t(timeBins))); + return timeBins; + }); + + mRawReader.setLinkZSCallback([this](int cru, int rowInSector, int padInRow, int timeBin, float adcValue) -> bool { + CRU cruID(cru); + const PadRegionInfo& regionInfo = Mapper::instance().getPadRegionInfo(cruID.region()); + mDigitDump.updateCRU(cruID, rowInSector - regionInfo.getGlobalRowOffset(), padInRow, timeBin, adcValue); + if (mClusterQC) { + mClusterQC->fillADCValue(cru, rowInSector, padInRow, timeBin, adcValue); } + return true; + }); + } + + void run(o2::framework::ProcessingContext& pc) final + { + // in case the maximum number of events was reached don't do further processing + if (mReadyToQuit) { + return; + } + + auto& reader = mRawReader.getReaders()[0]; + mActiveSectors = calib_processing_helper::processRawData(pc.inputs(), reader, mUseOldSubspec); + + mDigitDump.incrementNEvents(); + LOGP(info, "Number of processed events: {} ({})", mDigitDump.getNumberOfProcessedEvents(), mMaxEvents); + + snapshotDigits(pc.outputs()); - // ===| digit snapshot |=== - // - // lambda that snapshots digits to be sent out; - // prepares and attaches header with sector information - // - auto snapshotDigits = [&pc, processAttributes, channel](std::vector<o2::tpc::Digit> const& digits, int sector) { - o2::tpc::TPCSectorHeader header{sector}; - header.activeSectors = processAttributes->activeSectors; - // digit for now are transported per sector, not per lane - // pc.outputs().snapshot(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe, header}, - pc.outputs().snapshot(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(sector), Lifetime::Timeframe, header}, - const_cast<std::vector<o2::tpc::Digit>&>(digits)); - }; - - // loop over all inputs - for (auto& input : pc.inputs()) { - const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(input); - - // select only RAW data - if (dh->dataDescription != o2::header::gDataDescriptionRawData) { - continue; - } - - // ===| extract electronics mapping information |=== - const auto subSpecification = dh->subSpecification; - const auto cruID = subSpecification >> 16; - const auto linkID = ((subSpecification + (subSpecification >> 8)) & 0xFF) - 1; - const auto dataWrapperID = ((subSpecification >> 8) & 0xFF) > 0; - const auto globalLinkID = linkID + dataWrapperID * 12; - const auto sector = cruID / 10; - - // update active sectors - processAttributes->activeSectors |= (0x1 << sector); - - // set up mapping information for raw reader - auto& reader = processAttributes->rawReader.getReaders()[0]; - reader->forceCRU(cruID); - reader->setLink(globalLinkID); - - LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin.as<std::string>(), dh->dataDescription.as<std::string>(), dh->subSpecification); - LOGP(debug, "Payload size: {}", dh->payloadSize); - LOGP(debug, "CRU: {}; linkID: {}; dataWrapperID: {}; globalLinkID: {}", cruID, linkID, dataWrapperID, globalLinkID); - - try { - o2::framework::RawParser parser(input.payload, dh->payloadSize); - - rawreader::ADCRawData rawData; - rawreader::GBTFrame gFrame; - - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV4>(); - if (!rdhPtr) { - break; - } - const auto& rdh = *rdhPtr; - //printRDH(rdh); - - // ===| event handling |=== - // - // really ugly, better treatment requires extension in DPL - // events are are detected by close by orbit numbers - // - const auto hbOrbit = rdh.heartbeatOrbit; - const auto lastOrbit = processAttributes->lastOrbit; - - if ((lastOrbit > 0) && (hbOrbit > (lastOrbit + 3))) { - auto& digitDump = processAttributes->digitDump; - digitDump.incrementNEvents(); - LOGP(info, "Number of processed events: {} ({})", digitDump.getNumberOfProcessedEvents(), processAttributes->maxEvents); - digitDump.sortDigits(); - - // publish digits of all configured sectors - for (auto isector : processAttributes->tpcSectors) { - snapshotDigits(digitDump.getDigits(isector), isector); - } - digitDump.clearDigits(); - - processAttributes->activeSectors = 0; - if (digitDump.getNumberOfProcessedEvents() >= processAttributes->maxEvents) { - LOGP(info, "Maximum number of events reached ({}), no more processing will be done", processAttributes->maxEvents); - processAttributes->quit = true; - pc.services().get<ControlService>().endOfStream(); - //pc.services().get<ControlService>().readyToQuit(QuitRequest::All); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - break; - } - } - - processAttributes->lastOrbit = hbOrbit; - const auto size = it.size(); - auto data = it.data(); - LOGP(debug, "Raw data block payload size: {}", size); - - int iFrame = 0; - for (int i = 0; i < size; i += 16) { - gFrame.setFrameNumber(iFrame); - gFrame.setPacketNumber(iFrame / 508); - gFrame.readFromMemory(gsl::span<const o2::byte>(data + i, 16)); - - // extract the half words from the 4 32-bit words - gFrame.getFrameHalfWords(); - - // debug output - //if (CHECK_BIT(mDebugLevel, DebugLevel::GBTFrames)) { - //std::cout << gFrame; - //} - - gFrame.getAdcValues(rawData); - gFrame.updateSyncCheck(false); - - ++iFrame; - } - } - - reader->runADCDataCallback(rawData); - } catch (const std::runtime_error& e) { - LOG(ERROR) << "can not create raw parser form input data"; - o2::header::hexDump("payload", input.payload, dh->payloadSize, 64); - LOG(ERROR) << e.what(); - } + if (mMaxEvents && (mDigitDump.getNumberOfProcessedEvents() >= mMaxEvents)) { + LOGP(info, "Maximm number of events reached ({}), no more processing will be done", mMaxEvents); + mReadyToQuit = true; + if (mForceQuit) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::All); + } else { + //pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); } - }; + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOGP(info, "endOfStream"); + if (mActiveSectors) { + snapshotDigits(ec.outputs()); + } + ec.services().get<ControlService>().readyToQuit(QuitRequest::Me); + + if (mClusterQC) { + dumpClusterQC(); + } + } + + private: + DigitDump mDigitDump; + std::unique_ptr<qc::Clusters> mClusterQC; + rawreader::RawReaderCRUManager mRawReader; + uint32_t mMaxEvents{0}; + bool mReadyToQuit{false}; + bool mCalibDumped{false}; + bool mUseOldSubspec{false}; + bool mForceQuit{false}; + bool mCheckDuplicates{false}; + bool mRemoveDuplicates{false}; + bool mRemoveCEdigits{false}; + uint64_t mActiveSectors{0}; ///< bit mask of active sectors + std::vector<int> mSectors{}; ///< tpc sector configuration + + //____________________________________________________________________________ + void snapshotDigits(DataAllocator& output) + { + if (mCheckDuplicates || mRemoveDuplicates) { + // iplicityly sorts + mDigitDump.checkDuplicates(mRemoveDuplicates); + } else { + mDigitDump.sortDigits(); + } - return processingFct; - }; + if (mRemoveCEdigits) { + mDigitDump.removeCEdigits(); + } - std::stringstream id; - id << "TPCDigitizer" << channel; + for (auto isector : mSectors) { + o2::tpc::TPCSectorHeader header{isector}; + header.activeSectors = mActiveSectors; + // digit for now are transported per sector, not per lane + output.snapshot(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(isector), Lifetime::Timeframe, header}, + mDigitDump.getDigits(isector)); + } + mDigitDump.clearDigits(); + mActiveSectors = 0; + } + + //____________________________________________________________________________ + void dumpClusterQC() + { + mClusterQC->normalize(); + mClusterQC->dumpToFile("ClusterQC.root"); + } +}; + +DataProcessorSpec getRawToDigitsSpec(int channel, const std::string inputSpec, std::vector<int> const& tpcSectors) +{ + using device = o2::tpc::TPCDigitDumpDevice; - std::vector<OutputSpec> outputs; // define channel by triple of (origin, type id of data to be sent on this channel, subspecification) + std::vector<OutputSpec> outputs; for (auto isector : tpcSectors) { outputs.emplace_back("TPC", "DIGITS", static_cast<SubSpecificationType>(isector), Lifetime::Timeframe); } return DataProcessorSpec{ - id.str().c_str(), - select(inputDef.data()), + fmt::format("tpc-raw-to-digits-{}", channel), + select(inputSpec.data()), outputs, - AlgorithmSpec{initFunction}, + AlgorithmSpec{adaptFromTask<device>(tpcSectors)}, Options{ - {"max-events", VariantType::Int, 100, {"maximum number of events to process"}}, - {"pedestal-file", VariantType::String, "", {"file with pedestals and noise for zero suppression"}}}}; + {"max-events", VariantType::Int, 0, {"maximum number of events to process"}}, + {"use-old-subspec", VariantType::Bool, false, {"use old subsecifiation definition"}}, + {"force-quit", VariantType::Bool, false, {"force quit after max-events have been reached"}}, + {"pedestal-file", VariantType::String, "", {"file with pedestals and noise for zero suppression"}}, + {"create-occupancy-maps", VariantType::Bool, false, {"create occupancy maps and store them to local root file for debugging"}}, + {"check-for-duplicates", VariantType::Bool, false, {"check if duplicate digits exist and only report them"}}, + {"remove-duplicates", VariantType::Bool, false, {"check if duplicate digits exist and remove them"}}, + {"remove-ce-digits", VariantType::Bool, false, {"find CE position and remove digits around it"}}, + } // end Options + }; // end DataProcessorSpec } } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index 43116540ffed7..6d1b88ba7fee5 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,10 +19,10 @@ #include "Framework/Logger.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "TPCWorkflow/RecoWorkflow.h" -#include "TPCWorkflow/PublisherSpec.h" +#include "TPCReaderWorkflow/PublisherSpec.h" #include "TPCWorkflow/ClustererSpec.h" #include "TPCWorkflow/ClusterDecoderRawSpec.h" -#include "TPCWorkflow/CATrackerSpec.h" +#include "GPUWorkflow/GPUWorkflowSpec.h" #include "TPCWorkflow/EntropyEncoderSpec.h" #include "TPCWorkflow/ZSSpec.h" #include "Algorithm/RangeTokenizer.h" @@ -37,6 +38,7 @@ #include "SimulationDataFormat/MCCompLabel.h" #include "DataFormatsTPC/Helpers.h" #include "DataFormatsTPC/ZeroSuppression.h" +#include "TPCReaderWorkflow/ClusterReaderSpec.h" #include <string> #include <stdexcept> @@ -72,8 +74,7 @@ const std::unordered_map<std::string, InputType> InputMap{ {"zsraw", InputType::ZSRaw}, {"compressed-clusters", InputType::CompClusters}, {"compressed-clusters-ctf", InputType::CompClustersCTF}, - {"encoded-clusters", InputType::EncodedClusters}, -}; + {"compressed-clusters-flat", InputType::CompClustersFlat}}; const std::unordered_map<std::string, OutputType> OutputMap{ {"digits", OutputType::Digits}, @@ -85,11 +86,12 @@ const std::unordered_map<std::string, OutputType> OutputMap{ {"disable-writer", OutputType::DisableWriter}, {"send-clusters-per-sector", OutputType::SendClustersPerSector}, {"zsraw", OutputType::ZSRaw}, - {"qa", OutputType::QA}}; + {"qa", OutputType::QA}, + {"no-shared-cluster-map", OutputType::NoSharedClusterMap}}; -framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector<int> const& tpcSectors, std::vector<int> const& laneConfiguration, - bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, - int caClusterer, int zsOnTheFly, int zs10bit, float zsThreshold) +framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector<int> const& tpcSectors, unsigned long tpcSectorMask, std::vector<int> const& laneConfiguration, + bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, + int caClusterer, int zsOnTheFly, bool askDISTSTF) { InputType inputType; try { @@ -114,7 +116,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto zsOnTheFly = false; propagateMC = false; } - if (inputType == InputType::ZSRaw) { + if (inputType == InputType::ZSRaw || inputType == InputType::CompClustersFlat) { caClusterer = true; zsOnTheFly = false; propagateMC = false; @@ -152,85 +154,66 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto auto storedlabels = reinterpret_cast<o2::dataformats::IOMCTruthContainerView const*>(data); o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel> flatlabels; storedlabels->copyandflatten(flatlabels); - LOG(INFO) << "PUBLISHING CONST LABELS " << flatlabels.getNElements(); + //LOG(INFO) << "PUBLISHING CONST LABELS " << flatlabels.getNElements(); context.outputs().snapshot(output, flatlabels); return true; } return false; }}; - // The OutputSpec of the PublisherSpec is configured depending on the input - // type. Note that the configuration of the dispatch trigger in the main file - // needs to be done in accordance. This means, if a new input option is added - // also the dispatch trigger needs to be updated. - if (inputType == InputType::Digits) { - using Type = std::vector<o2::tpc::Digit>; - - specs.emplace_back(o2::tpc::getPublisherSpec<Type>(PublisherConf{ - "tpc-digit-reader", - "o2sim", - {"digitbranch", "TPCDigit", "Digit branch"}, - {"mcbranch", "TPCDigitMCTruth", "MC label branch"}, - OutputSpec{"TPC", "DIGITS"}, - OutputSpec{"TPC", "DIGITSMCTR"}, - tpcSectors, - laneConfiguration, - &hook}, - propagateMC)); - } else if (inputType == InputType::ClustersHardware) { - specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ - "tpc-clusterhardware-reader", - "tpcclustershardware", - {"databranch", "TPCClusterHw", "Branch with TPC ClustersHardware"}, - {"mcbranch", "TPCClusterHwMCTruth", "MC label branch"}, - OutputSpec{"TPC", "CLUSTERHW"}, - OutputSpec{"TPC", "CLUSTERHWMCLBL"}, - tpcSectors, - laneConfiguration, - &hook}, - propagateMC)); - } else if (inputType == InputType::Clusters) { - specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ - "tpc-native-cluster-reader", - "tpcrec", - {"clusterbranch", "TPCClusterNative", "Branch with TPC native clusters"}, - {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, - OutputSpec{"TPC", "CLUSTERNATIVE"}, - OutputSpec{"TPC", "CLNATIVEMCLBL"}, - tpcSectors, - laneConfiguration, - &hook}, - propagateMC)); - } else if (inputType == InputType::CompClusters) { - // TODO: need to check if we want to store the MC labels alongside with compressed clusters - // for the moment reading of labels is disabled (last parameter is false) - // TODO: make a different publisher spec for only one output spec, for now using the - // PublisherSpec with only sector 0, '_0' is thus appended to the branch name - specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ - "tpc-compressed-cluster-reader", - "tpcrec", - {"clusterbranch", "TPCCompClusters", "Branch with TPC compressed clusters"}, - {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, - OutputSpec{"TPC", "COMPCLUSTERS"}, - OutputSpec{"TPC", "CLNATIVEMCLBL"}, // This does not work with labels! - std::vector<int>(1, 0), - std::vector<int>(1, 0), - &hook}, - false)); - } else if (inputType == InputType::EncodedClusters) { - // TODO: need to check if we want to store the MC labels alongside with encoded clusters - // for the moment reading of labels is disabled (last parameter is false) - specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ - "tpc-encoded-cluster-reader", - "tpcrec", - {"clusterbranch", "TPCEncodedClusters", "Branch with TPC encoded clusters"}, - {"clustermcbranch", "TPCClusterNativeMCTruth", "MC label branch"}, - OutputSpec{"TPC", "ENCCLUSTERS"}, - OutputSpec{"TPC", "CLNATIVEMCLBL"}, // This does not work with labels! - std::vector<int>(1, 0), - std::vector<int>(1, 0), - &hook}, - false)); + if (!disableRootInput) { + // The OutputSpec of the PublisherSpec is configured depending on the input + // type. Note that the configuration of the dispatch trigger in the main file + // needs to be done in accordance. This means, if a new input option is added + // also the dispatch trigger needs to be updated. + if (inputType == InputType::Digits) { + using Type = std::vector<o2::tpc::Digit>; + + specs.emplace_back(o2::tpc::getPublisherSpec<Type>(PublisherConf{ + "tpc-digit-reader", + "tpcdigits.root", + "o2sim", + {"digitbranch", "TPCDigit", "Digit branch"}, + {"mcbranch", "TPCDigitMCTruth", "MC label branch"}, + OutputSpec{"TPC", "DIGITS"}, + OutputSpec{"TPC", "DIGITSMCTR"}, + tpcSectors, + laneConfiguration, + &hook}, + propagateMC)); + } else if (inputType == InputType::ClustersHardware) { + specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ + "tpc-clusterhardware-reader", + "tpc-clusterhardware.root", + "tpcclustershardware", + {"databranch", "TPCClusterHw", "Branch with TPC ClustersHardware"}, + {"mcbranch", "TPCClusterHwMCTruth", "MC label branch"}, + OutputSpec{"TPC", "CLUSTERHW"}, + OutputSpec{"TPC", "CLUSTERHWMCLBL"}, + tpcSectors, + laneConfiguration, + &hook}, + propagateMC)); + } else if (inputType == InputType::Clusters) { + specs.emplace_back(o2::tpc::getClusterReaderSpec(propagateMC, &tpcSectors, &laneConfiguration)); + } else if (inputType == InputType::CompClusters) { + // TODO: need to check if we want to store the MC labels alongside with compressed clusters + // for the moment reading of labels is disabled (last parameter is false) + // TODO: make a different publisher spec for only one output spec, for now using the + // PublisherSpec with only sector 0, '_0' is thus appended to the branch name + specs.emplace_back(o2::tpc::getPublisherSpec(PublisherConf{ + "tpc-compressed-cluster-reader", + "tpc-compclusters.root", + "tpcrec", + {"clusterbranch", "TPCCompClusters", "Branch with TPC compressed clusters"}, + {"", "", ""}, // No MC labels + OutputSpec{"TPC", "COMPCLUSTERS"}, + OutputSpec{"", ""}, // No MC labels + std::vector<int>(1, 0), + std::vector<int>(1, 0), + &hook}, + false)); + } } // output matrix @@ -238,7 +221,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto // ClusterDecoderRawSpec bool produceCompClusters = isEnabled(OutputType::CompClusters); bool produceTracks = isEnabled(OutputType::Tracks); - bool runTracker = produceTracks || produceCompClusters || (isEnabled(OutputType::Clusters) && caClusterer); + bool runTracker = (produceTracks || produceCompClusters || (isEnabled(OutputType::Clusters) && caClusterer)) && inputType != InputType::CompClustersFlat; bool runHWDecoder = !caClusterer && (runTracker || isEnabled(OutputType::Clusters)); bool runClusterer = !caClusterer && (runHWDecoder || isEnabled(OutputType::ClustersHardware)); bool zsDecoder = inputType == InputType::ZSRaw; @@ -249,7 +232,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto runHWDecoder &= runClusterer || inputType == InputType::ClustersHardware; runTracker &= caClusterer || runHWDecoder || inputType == InputType::Clusters || decompressTPC; - bool outRaw = inputType == InputType::Digits && isEnabled(OutputType::ZSRaw); + bool outRaw = inputType == InputType::Digits && isEnabled(OutputType::ZSRaw) && !isEnabled(OutputType::DisableWriter); //bool runZSDecode = inputType == InputType::ZSRaw; bool zsToDigit = inputType == InputType::ZSRaw && isEnabled(OutputType::Digits); @@ -323,7 +306,8 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto auto fillLabels = [](TBranch& branch, std::vector<char> const& labelbuffer, DataRef const& /*ref*/) { o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel> labels(labelbuffer); o2::dataformats::IOMCTruthContainerView outputcontainer; - auto br = framework::RootTreeWriter::remapBranch(branch, &outputcontainer); + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); outputcontainer.adopt(labelbuffer); br->Fill(); br->ResetAddress(); @@ -418,7 +402,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto } if (zsOnTheFly) { - specs.emplace_back(o2::tpc::getZSEncoderSpec(tpcSectors, zs10bit, zsThreshold, outRaw)); + specs.emplace_back(o2::tpc::getZSEncoderSpec(tpcSectors, outRaw, tpcSectorMask)); } if (zsToDigit) { @@ -431,21 +415,22 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto // // selected by output type 'tracks' if (runTracker) { - specs.emplace_back(o2::tpc::getCATrackerSpec(policyData, ca::Config{ - propagateMC ? ca::Operation::ProcessMC : ca::Operation::Noop, - decompressTPC ? ca::Operation::DecompressTPC : ca::Operation::Noop, - decompressTPC && inputType == InputType::CompClusters ? ca::Operation::DecompressTPCFromROOT : ca::Operation::Noop, - caClusterer ? ca::Operation::CAClusterer : ca::Operation::Noop, - zsDecoder ? ca::Operation::ZSDecoder : ca::Operation::Noop, - zsOnTheFly ? ca::Operation::ZSOnTheFly : ca::Operation::Noop, - produceTracks ? ca::Operation::OutputTracks : ca::Operation::Noop, - produceCompClusters ? ca::Operation::OutputCompClusters : ca::Operation::Noop, - runClusterEncoder ? ca::Operation::OutputCompClustersFlat : ca::Operation::Noop, - isEnabled(OutputType::SendClustersPerSector) ? ca::Operation::SendClustersPerSector : ca::Operation::Noop, - isEnabled(OutputType::QA) ? ca::Operation::OutputQA : ca::Operation::Noop, - isEnabled(OutputType::Clusters) && (caClusterer || decompressTPC) ? ca::Operation::OutputCAClusters : ca::Operation::Noop, - }, - tpcSectors)); + o2::gpu::gpuworkflow::Config cfg; + cfg.decompressTPC = decompressTPC; + cfg.decompressTPCFromROOT = decompressTPC && inputType == InputType::CompClusters; + cfg.caClusterer = caClusterer; + cfg.zsDecoder = zsDecoder; + cfg.zsOnTheFly = zsOnTheFly; + cfg.outputTracks = produceTracks; + cfg.outputCompClusters = produceCompClusters; + cfg.outputCompClustersFlat = runClusterEncoder; + cfg.outputCAClusters = isEnabled(OutputType::Clusters) && (caClusterer || decompressTPC); + cfg.outputQA = isEnabled(OutputType::QA); + cfg.outputSharedClusterMap = (isEnabled(OutputType::Clusters) || inputType == InputType::Clusters) && isEnabled(OutputType::Tracks) && !isEnabled(OutputType::NoSharedClusterMap); + cfg.processMC = propagateMC; + cfg.sendClustersPerSector = isEnabled(OutputType::SendClustersPerSector); + cfg.askDISTSTF = askDISTSTF; + specs.emplace_back(o2::gpu::getGPURecoWorkflowSpec(policyData, cfg, tpcSectors, tpcSectorMask, "tpc-tracker")); } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -454,7 +439,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto // // selected by output type 'encoded-clusters' if (runClusterEncoder) { - specs.emplace_back(o2::tpc::getEntropyEncoderSpec(!runTracker)); + specs.emplace_back(o2::tpc::getEntropyEncoderSpec(!runTracker && inputType != InputType::CompClustersFlat)); } ////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Detectors/TPC/workflow/src/TPCSectorCompletionPolicy.cxx b/Detectors/TPC/workflow/src/TPCSectorCompletionPolicy.cxx deleted file mode 100644 index 6d5b07a4e5e53..0000000000000 --- a/Detectors/TPC/workflow/src/TPCSectorCompletionPolicy.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TPCSectorCompletionPolicy.cxx -/// @author Matthias Richter -/// @since 2020-05-20 -/// @brief DPL completion policy helper for TPC scetor data - -#include "TPCWorkflow/TPCSectorCompletionPolicy.h" -#include "Framework/CompletionPolicy.h" - -namespace o2 -{ -namespace tpc -{ - -} // namespace tpc -} // namespace o2 diff --git a/Detectors/TPC/workflow/src/TrackReaderSpec.cxx b/Detectors/TPC/workflow/src/TrackReaderSpec.cxx deleted file mode 100644 index 7f1c12b54c8ff..0000000000000 --- a/Detectors/TPC/workflow/src/TrackReaderSpec.cxx +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TrackReaderSpec.cxx - -#include <vector> -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "TPCWorkflow/TrackReaderSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace tpc -{ - -TrackReader::TrackReader(bool useMC) -{ - mUseMC = useMC; -} - -void TrackReader::init(InitContext& ic) -{ - mInputFileName = ic.options().get<std::string>("tpc-tracks-infile"); - connectTree(mInputFileName); -} - -void TrackReader::run(ProcessingContext& pc) -{ - auto ent = mTree->GetReadEntry() + 1; - accumulate(ent, 1); // to really accumulate all, use accumulate(ent,mTree->GetEntries()); - assert(ent < mTree->GetEntries()); // this should not happen - mTree->GetEntry(ent); - - pc.outputs().snapshot(Output{"TPC", "TRACKS", 0, Lifetime::Timeframe}, mTracksOut); - pc.outputs().snapshot(Output{"TPC", "CLUSREFS", 0, Lifetime::Timeframe}, mCluRefVecOut); - if (mUseMC) { - pc.outputs().snapshot(Output{"TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe}, mMCTruthOut); - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -void TrackReader::accumulate(int from, int n) -{ - assert(from + n <= mTree->GetEntries()); - if (n == 1) { - mTree->GetEntry(from); - mTracksOut.swap(*mTracksInp); - mCluRefVecOut.swap(*mCluRefVecInp); - if (mUseMC) { - std::copy(mMCTruthInp->begin(), mMCTruthInp->end(), std::back_inserter(mMCTruthOut)); - } - } else { - for (int iev = 0; iev < n; iev++) { - mTree->GetEntry(from + iev); - // - uint32_t shift = mCluRefVecOut.size(); // during accumulation clusters refs need to be shifted - - auto cl0 = mCluRefVecInp->begin(); - auto cl1 = mCluRefVecInp->end(); - std::copy(cl0, cl1, std::back_inserter(mCluRefVecOut)); - - auto tr0 = mTracksInp->begin(); - auto tr1 = mTracksInp->end(); - // fix cluster references - if (shift) { - for (auto tr = tr0; tr != tr1; tr++) { - tr->shiftFirstClusterRef(shift); - } - } - std::copy(tr0, tr1, std::back_inserter(mTracksOut)); - // MC - if (mUseMC) { - std::copy(mMCTruthInp->begin(), mMCTruthInp->end(), std::back_inserter(mMCTruthOut)); - } - } - } - LOG(INFO) << "TPCTrackReader pushes " << mTracksOut.size() << " tracks from entries " << from << " : " << from + n - 1; -} - -void TrackReader::connectTree(const std::string& filename) -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(filename.c_str())); - if (!(mFile && !mFile->IsZombie())) { - throw std::runtime_error("Error opening tree file"); - } - mTree.reset((TTree*)mFile->Get(mTrackTreeName.c_str())); - if (!mTree) { - throw std::runtime_error("Error opening tree"); - } - - mTree->SetBranchAddress(mTrackBranchName.c_str(), &mTracksInp); - mTree->SetBranchAddress(mClusRefBranchName.c_str(), &mCluRefVecInp); - if (mUseMC) { - if (mTree->GetBranch(mTrackMCTruthBranchName.c_str())) { - mTree->SetBranchAddress(mTrackMCTruthBranchName.c_str(), &mMCTruthInp); - LOG(INFO) << "Will use MC-truth from " << mTrackMCTruthBranchName; - } else { - LOG(INFO) << "MC-truth is missing"; - mUseMC = false; - } - } - LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; -} - -DataProcessorSpec getTPCTrackReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputSpec; - outputSpec.emplace_back("TPC", "TRACKS", 0, Lifetime::Timeframe); - outputSpec.emplace_back("TPC", "CLUSREFS", 0, Lifetime::Timeframe); - if (useMC) { - outputSpec.emplace_back("TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "tpc-track-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask<TrackReader>(useMC)}, - Options{ - {"tpc-tracks-infile", VariantType::String, "tpctracks.root", {"Name of the input track file"}}}}; -} - -} // namespace tpc -} // namespace o2 diff --git a/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx new file mode 100644 index 0000000000000..13cf1eaa6b722 --- /dev/null +++ b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackReaderWorkflow.cxx + +#include "Framework/WorkflowSpec.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/PartRef.h" +#include "Framework/ConcreteDataMatcher.h" +#include "TPCWorkflow/RecoWorkflow.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Headers/DataHeaderHelpers.h" + +#include "TPCReaderWorkflow/TrackReaderSpec.h" + +#include <string> +#include <stdexcept> +#include <unordered_map> +#include <regex> + +// we need a global variable to propagate the type the message dispatching of the +// publisher will trigger on. This is dependent on the input type +o2::framework::Output gDispatchTrigger{"", ""}; + +// Global variable used to transport data to the completion policy +o2::tpc::reco_workflow::CompletionPolicyData gPolicyData; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + using namespace o2::framework; + + std::vector<ConfigParamSpec> options{ + {"input-type", VariantType::String, "tracks", {"tracks"}}, + {"dispatching-mode", VariantType::String, "prompt", {"determines when to dispatch: prompt, complete"}}, + {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}}; + + std::swap(workflowOptions, options); +} + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector<o2::framework::DispatchPolicy>& policies) +{ + using DispatchOp = o2::framework::DispatchPolicy::DispatchOp; + // we customize all devices to dispatch data immediately + auto readerMatcher = [](auto const& spec) { + return std::regex_match(spec.name.begin(), spec.name.end(), std::regex(".*-reader")); + }; + auto triggerMatcher = [](auto const& query) { + // a bit of a hack but we want this to be configurable from the command line, + // however DispatchPolicy is inserted before all other setup. Triggering depending + // on the global variable set from the command line option. If scheduled messages + // are not triggered they are sent out at the end of the computation + return gDispatchTrigger.origin == query.origin && gDispatchTrigger.description == query.description; + }; + policies.push_back({"prompt-for-reader", readerMatcher, DispatchOp::WhenReady, triggerMatcher}); +} + +#include "Framework/runDataProcessing.h" // the main driver + +using namespace o2::framework; + +/// MC info is processed by default, disabled by using command line option `--disable-mc` +/// +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + + auto inputType = cfgc.options().get<std::string>("input-type"); + auto dispmode = cfgc.options().get<std::string>("dispatching-mode"); + if (dispmode == "complete") { + // nothing to do we leave the matcher empty which will suppress the dispatch + // trigger and all messages will be sent out together at end of computation + } else if (inputType == "tracks") { + gDispatchTrigger = o2::framework::Output{"TPC", "TRACKS"}; + } + + bool doMC = not cfgc.options().get<bool>("disable-mc"); + + specs.push_back(o2::tpc::getTPCTrackReaderSpec(doMC)); + + return std::move(specs); +} diff --git a/Detectors/TPC/workflow/src/ZSSpec.cxx b/Detectors/TPC/workflow/src/ZSSpec.cxx index 91db1b93f5dbd..1ba76ebac6f67 100644 --- a/Detectors/TPC/workflow/src/ZSSpec.cxx +++ b/Detectors/TPC/workflow/src/ZSSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,10 +17,10 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/InputRecordWalker.h" +#include "Framework/DataRefUtils.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "DataFormatsTPC/ZeroSuppression.h" #include "DataFormatsTPC/Helpers.h" -#include "TPCReconstruction/GPUCATracking.h" #include "DataFormatsTPC/Digit.h" #include "GPUDataTypes.h" #include "GPUHostDataTypes.h" @@ -35,7 +36,6 @@ #include <unistd.h> #include "GPUParam.h" #include "GPUReconstructionConvert.h" -#include "GPURawData.h" #include "DetectorsRaw/RawFileWriter.h" #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RDHUtils.h" @@ -44,6 +44,8 @@ #include "DPLUtils/DPLRawParser.h" #include "DataFormatsParameters/GRPObject.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DetectorsRaw/RDHUtils.h" using namespace o2::framework; using namespace o2::header; @@ -55,31 +57,31 @@ namespace o2 namespace tpc { -DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs10bit, float threshold = 2.f, bool outRaw = false) +DataProcessorSpec getZSEncoderSpec(std::vector<int> const& tpcSectors, bool outRaw = false, unsigned long tpcSectorMask = 0xFFFFFFFFF) { std::string processorName = "tpc-zsEncoder"; constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; - using DigitArray = std::array<gsl::span<const o2::tpc::Digit>, o2::tpc::Sector::MAXSECTOR>; + using DigitArray = std::array<gsl::span<const o2::tpc::Digit>, NSectors>; struct ProcessAttributes { std::unique_ptr<unsigned long long int[]> zsoutput; std::vector<unsigned int> sizes; - std::vector<int> inputIds; + std::vector<int> tpcSectors; bool verify = false; int verbosity = 1; bool finished = false; }; - auto initFunction = [inputIds, zs10bit, threshold, outRaw](InitContext& ic) { + auto initFunction = [tpcSectors, outRaw, tpcSectorMask](InitContext& ic) { auto processAttributes = std::make_shared<ProcessAttributes>(); auto& zsoutput = processAttributes->zsoutput; - processAttributes->inputIds = inputIds; + processAttributes->tpcSectors = tpcSectors; auto& verify = processAttributes->verify; auto& sizes = processAttributes->sizes; auto& verbosity = processAttributes->verbosity; - auto processingFct = [processAttributes, zs10bit, threshold, outRaw]( + auto processingFct = [processAttributes, outRaw, tpcSectorMask]( ProcessingContext& pc) { if (processAttributes->finished) { return; @@ -90,44 +92,17 @@ DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs10bi auto& sizes = processAttributes->sizes; auto& verbosity = processAttributes->verbosity; - std::array<gsl::span<const o2::tpc::Digit>, NSectors> inputDigits; - GPUTrackingInOutDigits inDigitsGPU; - GPUParam _GPUParam; GPUO2InterfaceConfiguration config; - config.configEvent.solenoidBz = 5.00668; + config.configGRP.solenoidBz = 5.00668; config.ReadConfigurableParam(); - _GPUParam.SetDefaults(&config.configEvent, &config.configReconstruction, &config.configProcessing, nullptr); - - int operation = 0; - std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe}}; - for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { - auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref); - if (sectorHeader == nullptr) { - // FIXME: think about error policy - LOG(ERROR) << "sector header missing on header stack"; - return; - } - const int& sector = sectorHeader->sector(); - // the TPCSectorHeader now allows to transport information for more than one sector, - // e.g. for transporting clusters in one single data block. Digits are however grouped - // on sector level - if (sectorHeader->sector() >= TPCSectorHeader::NSectors) { - throw std::runtime_error("Expecting data for single sectors"); - } + _GPUParam.SetDefaults(&config.configGRP, &config.configReconstruction, &config.configProcessing, nullptr); - inputDigits[sector] = pc.inputs().get<gsl::span<o2::tpc::Digit>>(ref); - LOG(INFO) << "GOT SPAN FOR SECTOR " << sector << " -> " - << inputDigits[sector].size(); - } - for (int i = 0; i < NSectors; i++) { - inDigitsGPU.tpcDigits[i] = inputDigits[i].data(); - inDigitsGPU.nTPCDigits[i] = inputDigits[i].size(); - } + const auto& inputs = getWorkflowTPCInput(pc, 0, false, false, tpcSectorMask, true); sizes.resize(NSectors * NEndpoints); - bool zs12bit = !zs10bit; - o2::InteractionRecord ir = o2::raw::HBFUtils::Instance().getFirstIR(); - o2::gpu::GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit, DigitArray>(inputDigits, &zsoutput, sizes.data(), nullptr, &ir, _GPUParam, zs12bit, verify, threshold); + const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(pc.inputs().getFirstValid(true)); + o2::InteractionRecord ir{0, dh->firstTForbit}; + o2::gpu::GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit, DigitArray>(inputs->inputDigits, &zsoutput, sizes.data(), nullptr, &ir, _GPUParam, true, verify, config.configReconstruction.tpc.zsThreshold); ZeroSuppressedContainer8kb* page = reinterpret_cast<ZeroSuppressedContainer8kb*>(zsoutput.get()); unsigned int offset = 0; for (unsigned int i = 0; i < NSectors; i++) { @@ -148,10 +123,11 @@ DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs10bi // ===| set up raw writer |=================================================== std::string inputGRP = o2::base::NameConf::getGRPFileName(); const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); - o2::raw::RawFileWriter writer{"TPC"}; // to set the RDHv6.sourceID if V6 is used + o2::raw::RawFileWriter writer{"TPC"}; // to set the RDHv6.sourceID if V6 is used writer.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::TPC)); // must be set explicitly - uint32_t rdhV = o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>(); + uint32_t rdhV = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); writer.useRDHVersion(rdhV); + writer.doLazinessCheck(false); // LazinessCheck is not thread-safe std::string outDir = "./"; const unsigned int defaultLink = rdh_utils::UserLogicLinkID; enum LinksGrouping { All, @@ -178,26 +154,26 @@ DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs10bi if (useGrouping != LinksGrouping::Link) { writer.useCaching(); } - o2::gpu::GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit>(inputDigits, nullptr, nullptr, &writer, &ir, _GPUParam, zs12bit, false, threshold); + ir = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); + o2::gpu::GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit>(inputs->inputDigits, nullptr, nullptr, &writer, &ir, _GPUParam, true, false, config.configReconstruction.tpc.zsThreshold); writer.writeConfFile("TPC", "RAWDATA", fmt::format("{}tpcraw.cfg", outDir)); } zsoutput.reset(nullptr); sizes = {}; - inputDigits = {}; }; return processingFct; }; - auto createInputSpecs = [inputIds]() { + auto createInputSpecs = [tpcSectors]() { Inputs inputs; // inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe}); inputs.emplace_back(InputSpec{"input", gDataOriginTPC, "DIGITS", 0, Lifetime::Timeframe}); - return std::move(mergeInputs(inputs, inputIds.size(), - [inputIds](InputSpec& input, size_t index) { + return std::move(mergeInputs(inputs, tpcSectors.size(), + [tpcSectors](InputSpec& input, size_t index) { // using unique input names for the moment but want to find // an input-multiplicity-agnostic way of processing - input.binding += std::to_string(inputIds[index]); - DataSpecUtils::updateMatchingSubspec(input, inputIds[index]); + input.binding += std::to_string(tpcSectors[index]); + DataSpecUtils::updateMatchingSubspec(input, tpcSectors[index]); })); return inputs; }; @@ -219,7 +195,7 @@ DataProcessorSpec getZSEncoderSpec(std::vector<int> const& inputIds, bool zs10bi AlgorithmSpec(initFunction)}; } //spec end -DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds) +DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& tpcSectors) { std::string processorName = "tpc-zs-to-Digits"; constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; @@ -230,7 +206,7 @@ DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds) std::unique_ptr<unsigned long long int[]> zsinput; std::vector<unsigned int> sizes; std::unique_ptr<o2::tpc::ZeroSuppress> decoder; - std::vector<int> inputIds; + std::vector<int> tpcSectors; bool verify = false; int verbosity = 1; bool finished = false; @@ -253,9 +229,9 @@ DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds) } }; - auto initFunction = [inputIds](InitContext& ic) { + auto initFunction = [tpcSectors](InitContext& ic) { auto processAttributes = std::make_shared<ProcessAttributes>(); - processAttributes->inputIds = inputIds; + processAttributes->tpcSectors = tpcSectors; auto& outDigits = processAttributes->outDigits; auto& decoder = processAttributes->decoder; decoder = std::make_unique<o2::tpc::ZeroSuppress>(); @@ -277,7 +253,7 @@ DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds) for (unsigned int i = 0; i < NSectors; i++) { outDigits[i].clear(); } - o2::InteractionRecord ir = o2::raw::HBFUtils::Instance().getFirstIR(); + o2::InteractionRecord ir = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); firstOrbit = ir.orbit; std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { @@ -286,34 +262,23 @@ DataProcessorSpec getZStoDigitsSpec(std::vector<int> const& inputIds) o2::framework::RawParser parser(raw.data(), raw.size()); const unsigned char* ptr = nullptr; - int count = 0; int cruID = 0; - rdh_utils::FEEIDType lastFEE = -1; + rdh_utils::FEEIDType FEEID = -1; size_t totalSize = 0; for (auto it = parser.begin(); it != parser.end(); it++) { const unsigned char* current = it.raw(); const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)current; - if (current == nullptr || it.size() == 0 || (current - ptr) % TPCZSHDR::TPC_ZS_PAGE_SIZE || o2::raw::RDHUtils::getFEEID(*rdh) != lastFEE) { - if (count) { - unsigned int sector = cruID / 10; - gsl::span<const ZeroSuppressedContainer8kb> z0in(reinterpret_cast<const ZeroSuppressedContainer8kb*>(ptr), count); - decoder->DecodeZSPages(&z0in, &outDigits[sector], firstOrbit); - } - count = 0; - lastFEE = o2::raw::RDHUtils::getFEEID(*rdh); - cruID = int(o2::raw::RDHUtils::getCRUID(*rdh)); - if (it.size() == 0) { - ptr = nullptr; - continue; - } + if (it.size() == 0) { + ptr = nullptr; + continue; + } else { ptr = current; + FEEID = o2::raw::RDHUtils::getFEEID(*rdh); + cruID = int(o2::raw::RDHUtils::getCRUID(*rdh)); + unsigned int sector = cruID / 10; + gsl::span<const ZeroSuppressedContainer8kb> z0in(reinterpret_cast<const ZeroSuppressedContainer8kb*>(ptr), 1); + decoder->DecodeZSPages(&z0in, &outDigits[sector], firstOrbit); } - count++; - } - if (count) { - unsigned int sector = cruID / 10; - gsl::span<const ZeroSuppressedContainer8kb> z0in(reinterpret_cast<const ZeroSuppressedContainer8kb*>(ptr), count); - decoder->DecodeZSPages(&z0in, &outDigits[sector], firstOrbit); } } for (int i = 0; i < NSectors; i++) { diff --git a/Detectors/TPC/workflow/src/convertDigitsToRawZS.cxx b/Detectors/TPC/workflow/src/convertDigitsToRawZS.cxx new file mode 100644 index 0000000000000..db37ec4104632 --- /dev/null +++ b/Detectors/TPC/workflow/src/convertDigitsToRawZS.cxx @@ -0,0 +1,292 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file convertDigitsToRawZS.cxx +/// \author Jens Wiechula (Jens.Wiechula@ikf.uni-frankfurt.de) + +#include <boost/program_options.hpp> + +#include <string_view> +#include <memory> +#include <vector> +#include <fmt/format.h> +#include <filesystem> +#include "TFile.h" +#include "TTree.h" +#include "TROOT.h" + +#include "GPUO2Interface.h" +#include "GPUReconstructionConvert.h" +#include "GPUHostDataTypes.h" +#include "GPUParam.h" + +#include "Framework/Logger.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCBase/Sector.h" +#include "DataFormatsTPC/ZeroSuppression.h" +#include "DataFormatsTPC/Helpers.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RDHUtils.h" +#include "TPCBase/RDHUtils.h" +#include "DataFormatsTPC/Digit.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/RDHUtils.h" + +namespace bpo = boost::program_options; + +using namespace o2::tpc; +using namespace o2::gpu; +using namespace o2::dataformats; +using o2::MCCompLabel; + +constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; +constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; +using DigitArray = std::array<gsl::span<const o2::tpc::Digit>, Sector::MAXSECTOR>; + +static constexpr const char* CRU_FLPS[360] = { + "alio2-cr1-flp070", "alio2-cr1-flp069", "alio2-cr1-flp070", "alio2-cr1-flp069", "alio2-cr1-flp072", "alio2-cr1-flp071", "alio2-cr1-flp072", "alio2-cr1-flp071", "alio2-cr1-flp072", "alio2-cr1-flp071", "alio2-cr1-flp002", "alio2-cr1-flp001", "alio2-cr1-flp002", "alio2-cr1-flp001", "alio2-cr1-flp004", "alio2-cr1-flp003", "alio2-cr1-flp004", "alio2-cr1-flp003", + "alio2-cr1-flp004", "alio2-cr1-flp003", "alio2-cr1-flp006", "alio2-cr1-flp005", "alio2-cr1-flp006", "alio2-cr1-flp005", "alio2-cr1-flp008", "alio2-cr1-flp007", "alio2-cr1-flp008", "alio2-cr1-flp007", "alio2-cr1-flp008", "alio2-cr1-flp007", "alio2-cr1-flp010", "alio2-cr1-flp009", "alio2-cr1-flp010", "alio2-cr1-flp009", "alio2-cr1-flp012", "alio2-cr1-flp011", + "alio2-cr1-flp012", "alio2-cr1-flp011", "alio2-cr1-flp012", "alio2-cr1-flp011", "alio2-cr1-flp014", "alio2-cr1-flp013", "alio2-cr1-flp014", "alio2-cr1-flp013", "alio2-cr1-flp016", "alio2-cr1-flp015", "alio2-cr1-flp016", "alio2-cr1-flp015", "alio2-cr1-flp016", "alio2-cr1-flp015", "alio2-cr1-flp018", "alio2-cr1-flp017", "alio2-cr1-flp018", "alio2-cr1-flp017", + "alio2-cr1-flp020", "alio2-cr1-flp019", "alio2-cr1-flp020", "alio2-cr1-flp019", "alio2-cr1-flp020", "alio2-cr1-flp019", "alio2-cr1-flp022", "alio2-cr1-flp021", "alio2-cr1-flp022", "alio2-cr1-flp021", "alio2-cr1-flp024", "alio2-cr1-flp023", "alio2-cr1-flp024", "alio2-cr1-flp023", "alio2-cr1-flp024", "alio2-cr1-flp023", "alio2-cr1-flp026", "alio2-cr1-flp025", + "alio2-cr1-flp026", "alio2-cr1-flp025", "alio2-cr1-flp028", "alio2-cr1-flp027", "alio2-cr1-flp028", "alio2-cr1-flp027", "alio2-cr1-flp028", "alio2-cr1-flp027", "alio2-cr1-flp030", "alio2-cr1-flp029", "alio2-cr1-flp030", "alio2-cr1-flp029", "alio2-cr1-flp032", "alio2-cr1-flp031", "alio2-cr1-flp032", "alio2-cr1-flp031", "alio2-cr1-flp032", "alio2-cr1-flp031", + "alio2-cr1-flp034", "alio2-cr1-flp033", "alio2-cr1-flp034", "alio2-cr1-flp033", "alio2-cr1-flp036", "alio2-cr1-flp035", "alio2-cr1-flp036", "alio2-cr1-flp035", "alio2-cr1-flp036", "alio2-cr1-flp035", "alio2-cr1-flp038", "alio2-cr1-flp037", "alio2-cr1-flp038", "alio2-cr1-flp037", "alio2-cr1-flp040", "alio2-cr1-flp039", "alio2-cr1-flp040", "alio2-cr1-flp039", + "alio2-cr1-flp040", "alio2-cr1-flp039", "alio2-cr1-flp042", "alio2-cr1-flp041", "alio2-cr1-flp042", "alio2-cr1-flp041", "alio2-cr1-flp044", "alio2-cr1-flp043", "alio2-cr1-flp044", "alio2-cr1-flp043", "alio2-cr1-flp044", "alio2-cr1-flp043", "alio2-cr1-flp046", "alio2-cr1-flp045", "alio2-cr1-flp046", "alio2-cr1-flp045", "alio2-cr1-flp048", "alio2-cr1-flp047", + "alio2-cr1-flp048", "alio2-cr1-flp047", "alio2-cr1-flp048", "alio2-cr1-flp047", "alio2-cr1-flp050", "alio2-cr1-flp049", "alio2-cr1-flp050", "alio2-cr1-flp049", "alio2-cr1-flp052", "alio2-cr1-flp051", "alio2-cr1-flp052", "alio2-cr1-flp051", "alio2-cr1-flp052", "alio2-cr1-flp051", "alio2-cr1-flp054", "alio2-cr1-flp053", "alio2-cr1-flp054", "alio2-cr1-flp053", + "alio2-cr1-flp056", "alio2-cr1-flp055", "alio2-cr1-flp056", "alio2-cr1-flp055", "alio2-cr1-flp056", "alio2-cr1-flp055", "alio2-cr1-flp058", "alio2-cr1-flp057", "alio2-cr1-flp058", "alio2-cr1-flp057", "alio2-cr1-flp060", "alio2-cr1-flp059", "alio2-cr1-flp060", "alio2-cr1-flp059", "alio2-cr1-flp060", "alio2-cr1-flp059", "alio2-cr1-flp062", "alio2-cr1-flp061", + "alio2-cr1-flp062", "alio2-cr1-flp061", "alio2-cr1-flp064", "alio2-cr1-flp063", "alio2-cr1-flp064", "alio2-cr1-flp063", "alio2-cr1-flp064", "alio2-cr1-flp063", "alio2-cr1-flp066", "alio2-cr1-flp065", "alio2-cr1-flp066", "alio2-cr1-flp065", "alio2-cr1-flp068", "alio2-cr1-flp067", "alio2-cr1-flp068", "alio2-cr1-flp067", "alio2-cr1-flp068", "alio2-cr1-flp067", + "alio2-cr1-flp074", "alio2-cr1-flp073", "alio2-cr1-flp074", "alio2-cr1-flp073", "alio2-cr1-flp076", "alio2-cr1-flp075", "alio2-cr1-flp076", "alio2-cr1-flp075", "alio2-cr1-flp076", "alio2-cr1-flp075", "alio2-cr1-flp078", "alio2-cr1-flp077", "alio2-cr1-flp078", "alio2-cr1-flp077", "alio2-cr1-flp080", "alio2-cr1-flp079", "alio2-cr1-flp080", "alio2-cr1-flp079", + "alio2-cr1-flp080", "alio2-cr1-flp079", "alio2-cr1-flp082", "alio2-cr1-flp081", "alio2-cr1-flp082", "alio2-cr1-flp081", "alio2-cr1-flp084", "alio2-cr1-flp083", "alio2-cr1-flp084", "alio2-cr1-flp083", "alio2-cr1-flp084", "alio2-cr1-flp083", "alio2-cr1-flp086", "alio2-cr1-flp085", "alio2-cr1-flp086", "alio2-cr1-flp085", "alio2-cr1-flp088", "alio2-cr1-flp087", + "alio2-cr1-flp088", "alio2-cr1-flp087", "alio2-cr1-flp088", "alio2-cr1-flp087", "alio2-cr1-flp090", "alio2-cr1-flp089", "alio2-cr1-flp090", "alio2-cr1-flp089", "alio2-cr1-flp092", "alio2-cr1-flp091", "alio2-cr1-flp092", "alio2-cr1-flp091", "alio2-cr1-flp092", "alio2-cr1-flp091", "alio2-cr1-flp094", "alio2-cr1-flp093", "alio2-cr1-flp094", "alio2-cr1-flp093", + "alio2-cr1-flp096", "alio2-cr1-flp095", "alio2-cr1-flp096", "alio2-cr1-flp095", "alio2-cr1-flp096", "alio2-cr1-flp095", "alio2-cr1-flp098", "alio2-cr1-flp097", "alio2-cr1-flp098", "alio2-cr1-flp097", "alio2-cr1-flp100", "alio2-cr1-flp099", "alio2-cr1-flp100", "alio2-cr1-flp099", "alio2-cr1-flp100", "alio2-cr1-flp099", "alio2-cr1-flp102", "alio2-cr1-flp101", + "alio2-cr1-flp102", "alio2-cr1-flp101", "alio2-cr1-flp104", "alio2-cr1-flp103", "alio2-cr1-flp104", "alio2-cr1-flp103", "alio2-cr1-flp104", "alio2-cr1-flp103", "alio2-cr1-flp106", "alio2-cr1-flp105", "alio2-cr1-flp106", "alio2-cr1-flp105", "alio2-cr1-flp108", "alio2-cr1-flp107", "alio2-cr1-flp108", "alio2-cr1-flp107", "alio2-cr1-flp108", "alio2-cr1-flp107", + "alio2-cr1-flp110", "alio2-cr1-flp109", "alio2-cr1-flp110", "alio2-cr1-flp109", "alio2-cr1-flp112", "alio2-cr1-flp111", "alio2-cr1-flp112", "alio2-cr1-flp111", "alio2-cr1-flp112", "alio2-cr1-flp111", "alio2-cr1-flp114", "alio2-cr1-flp113", "alio2-cr1-flp114", "alio2-cr1-flp113", "alio2-cr1-flp116", "alio2-cr1-flp115", "alio2-cr1-flp116", "alio2-cr1-flp115", + "alio2-cr1-flp116", "alio2-cr1-flp115", "alio2-cr1-flp118", "alio2-cr1-flp117", "alio2-cr1-flp118", "alio2-cr1-flp117", "alio2-cr1-flp120", "alio2-cr1-flp119", "alio2-cr1-flp120", "alio2-cr1-flp119", "alio2-cr1-flp120", "alio2-cr1-flp119", "alio2-cr1-flp122", "alio2-cr1-flp121", "alio2-cr1-flp122", "alio2-cr1-flp121", "alio2-cr1-flp124", "alio2-cr1-flp123", + "alio2-cr1-flp124", "alio2-cr1-flp123", "alio2-cr1-flp124", "alio2-cr1-flp123", "alio2-cr1-flp126", "alio2-cr1-flp125", "alio2-cr1-flp126", "alio2-cr1-flp125", "alio2-cr1-flp128", "alio2-cr1-flp127", "alio2-cr1-flp128", "alio2-cr1-flp127", "alio2-cr1-flp128", "alio2-cr1-flp127", "alio2-cr1-flp130", "alio2-cr1-flp129", "alio2-cr1-flp130", "alio2-cr1-flp129", + "alio2-cr1-flp132", "alio2-cr1-flp131", "alio2-cr1-flp132", "alio2-cr1-flp131", "alio2-cr1-flp132", "alio2-cr1-flp131", "alio2-cr1-flp134", "alio2-cr1-flp133", "alio2-cr1-flp134", "alio2-cr1-flp133", "alio2-cr1-flp136", "alio2-cr1-flp135", "alio2-cr1-flp136", "alio2-cr1-flp135", "alio2-cr1-flp136", "alio2-cr1-flp135", "alio2-cr1-flp138", "alio2-cr1-flp137", + "alio2-cr1-flp138", "alio2-cr1-flp137", "alio2-cr1-flp140", "alio2-cr1-flp139", "alio2-cr1-flp140", "alio2-cr1-flp139", "alio2-cr1-flp140", "alio2-cr1-flp139", "alio2-cr1-flp142", "alio2-cr1-flp141", "alio2-cr1-flp142", "alio2-cr1-flp141", "alio2-cr1-flp144", "alio2-cr1-flp143", "alio2-cr1-flp144", "alio2-cr1-flp143", "alio2-cr1-flp144", "alio2-cr1-flp143"}; + +struct ProcessAttributes { + std::unique_ptr<unsigned long long int[]> zsoutput; + std::vector<unsigned int> sizes; + MCLabelContainer mctruthArray; + std::vector<int> inputIds; + bool zs12bit = true; + float zsThreshold = 2.f; + bool padding = true; + int verbosity = 1; +}; + +void convert(DigitArray& inputDigits, ProcessAttributes* processAttributes, o2::raw::RawFileWriter& writer); +#include "DetectorsRaw/HBFUtils.h" +void convertDigitsToZSfinal(std::string_view digitsFile, std::string_view outputPath, std::string_view fileFor, + bool sectorBySector, uint32_t rdhV, bool stopPage, bool padding, bool createParentDir) +{ + + // ===| open file and get tree |============================================== + std::unique_ptr<TFile> o2simDigits(TFile::Open(digitsFile.data())); + if (!o2simDigits || !o2simDigits->IsOpen() || o2simDigits->IsZombie()) { + LOGP(error, "Could not open file {}", digitsFile.data()); + exit(1); + } + auto treeSim = (TTree*)o2simDigits->Get("o2sim"); + if (!treeSim) { + LOGP(error, "Could not read digits tree from file {}", digitsFile.data()); + exit(1); + } + + gROOT->cd(); + + // ===| set up output directory |============================================= + std::string outDir{outputPath}; + if (outDir.empty()) { + outDir = "./"; + } + if (outDir.back() != '/') { + outDir += '/'; + } + + // if needed, create output directory + if (!std::filesystem::exists(outDir)) { + if (createParentDir) { + o2::raw::assertOutputDirectory(outDir); + } else { + LOGP(error, "Requested output directory '{}' does not exists, consider removing '-n'", outDir); + exit(1); + } + } + + // ===| set up raw writer |=================================================== + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + + o2::raw::RawFileWriter writer{"TPC"}; // to set the RDHv6.sourceID if V6 is used + writer.useRDHVersion(rdhV); + writer.setAddSeparateHBFStopPage(stopPage); + writer.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::TPC)); // must be set explicitly + const unsigned int defaultLink = rdh_utils::UserLogicLinkID; + + for (unsigned int i = 0; i < NSectors; i++) { + for (unsigned int j = 0; j < NEndpoints; j++) { + const unsigned int cruInSector = j / 2; + const unsigned int cruID = i * 10 + cruInSector; + const rdh_utils::FEEIDType feeid = rdh_utils::getFEEID(cruID, j & 1, defaultLink); + std::string outfname; + if (fileFor == "all") { // single file for all links + outfname = fmt::format("{}tpc_all.raw", outDir); + } else if (fileFor == "sector") { + outfname = fmt::format("{}tpc_sector{}.raw", outDir, i); + } else if (fileFor == "link" || fileFor == "cru") { + outfname = fmt::format("{}TPC_{}_cru{}_{}.raw", outDir, CRU_FLPS[cruID], cruID, j & 1); + } else { + throw std::runtime_error("invalid option provided for file grouping"); + } + writer.registerLink(feeid, cruID, defaultLink, j & 1, outfname); + } + } + if (fileFor != "link") { // in case >1 link goes to the file, we must cache to preserve the TFs ordering + writer.useCaching(); + } + writer.doLazinessCheck(false); // LazinessCheck is not thread-safe + + // ===| set up branch addresses |============================================= + std::vector<Digit>* vDigitsPerSectorCollection[Sector::MAXSECTOR] = {nullptr}; // container that keeps Digits per sector + + treeSim->SetBranchStatus("*", 0); + treeSim->SetBranchStatus("TPCDigit_*", 1); + + ProcessAttributes attr; + attr.padding = padding; + + for (int iSecBySec = 0; iSecBySec < Sector::MAXSECTOR; ++iSecBySec) { + treeSim->ResetBranchAddresses(); + for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { + if (sectorBySector) { + iSec = iSecBySec; + } + vDigitsPerSectorCollection[iSec] = nullptr; + treeSim->SetBranchAddress(TString::Format("TPCDigit_%d", iSec), &vDigitsPerSectorCollection[iSec]); + if (sectorBySector) { + break; + } + } + for (Long64_t ievent = 0; ievent < treeSim->GetEntries(); ++ievent) { + DigitArray inputDigits; + if (sectorBySector) { + treeSim->GetBranch(TString::Format("TPCDigit_%d", iSecBySec))->GetEntry(ievent); + } else { + treeSim->GetEntry(ievent); + } + + for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { + if (sectorBySector) { + iSec = iSecBySec; + } + inputDigits[iSec] = *vDigitsPerSectorCollection[iSec]; //???? + if (sectorBySector) { + break; + } + } + convert(inputDigits, &attr, writer); + for (int iSec = 0; iSec < Sector::MAXSECTOR; ++iSec) { + delete vDigitsPerSectorCollection[iSec]; + vDigitsPerSectorCollection[iSec] = nullptr; + } + } + if (!sectorBySector) { + break; + } + } + // for further use we write the configuration file for the output + writer.writeConfFile("TPC", "RAWDATA", fmt::format("{}tpcraw.cfg", outDir)); +} + +void convert(DigitArray& inputDigits, ProcessAttributes* processAttributes, o2::raw::RawFileWriter& writer) +{ + const auto zsThreshold = processAttributes->zsThreshold; + const auto zs12bit = processAttributes->zs12bit; + GPUParam _GPUParam; + _GPUParam.SetDefaults(5.00668); + const GPUParam mGPUParam = _GPUParam; + + o2::InteractionRecord ir = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); + ir.bc = 0; // By convention the TF starts at BC = 0 + o2::gpu::GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit>(inputDigits, nullptr, nullptr, &writer, &ir, mGPUParam, zs12bit, false, zsThreshold, processAttributes->padding); +} + +int main(int argc, char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " <cmds/options>\n" + " Tool will convert simulation digits to raw zero suppressed data\n" + "Commands / Options"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbose,v", bpo::value<uint32_t>()->default_value(0), "Select verbosity level [0 = no output]"); + add_option("input-file,i", bpo::value<std::string>()->default_value("tpcdigits.root"), "Specifies input file."); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "Specify output directory"); + add_option("no-parent-directories,n", "Do not create parent directories recursively"); + add_option("sector-by-sector,s", bpo::value<bool>()->default_value(false)->implicit_value(true), "Run one TPC sector after another"); + add_option("file-for,f", bpo::value<std::string>()->default_value("sector"), "single file per: link,sector,cru,all"); + add_option("stop-page,p", bpo::value<bool>()->default_value(false)->implicit_value(true), "HBF stop on separate CRU page"); + add_option("padding", bpo::value<bool>()->default_value(false)->implicit_value(true), "Pad all pages to 8kb"); + uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help") || argc == 1) { + std::cout << opt_general << std::endl; + exit(0); + } + + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + convertDigitsToZSfinal( + vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["file-for"].as<std::string>(), + vm["sector-by-sector"].as<bool>(), + vm["rdh-version"].as<uint32_t>(), + vm["stop-page"].as<bool>(), + vm["padding"].as<bool>(), + !vm.count("no-parent-directories")); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} diff --git a/Detectors/TPC/workflow/src/tpc-apply-ccdb-calib.cxx b/Detectors/TPC/workflow/src/tpc-apply-ccdb-calib.cxx new file mode 100644 index 0000000000000..21b88e08c2927 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-apply-ccdb-calib.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" + +#include "TPCWorkflow/ApplyCCDBCalibSpec.h" + +using namespace o2::framework; + +//// customize the completion policy +//void customize(std::vector<o2::framework::CompletionPolicy>& policies) +//{ +//using o2::framework::CompletionPolicy; +//policies.push_back(CompletionPolicyHelpers::defineByName("tpc-apply-ccdb-calib", CompletionPolicy::CompletionOp::Consume)); +//} + +//// we need to add workflow options before including Framework/runDataProcessing +//void customize(std::vector<ConfigParamSpec>& workflowOptions) +//{ +//std::vector<ConfigParamSpec> options{ +////{"enable-writer", VariantType::Bool, false, {"selection string input specs"}}, +//}; + +//std::swap(workflowOptions, options); +//} +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + using namespace o2::tpc; + + WorkflowSpec workflow; + workflow.emplace_back(getApplyCCDBCalibSpec()); + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-averagegroup-idc.cxx b/Detectors/TPC/workflow/src/tpc-averagegroup-idc.cxx new file mode 100644 index 0000000000000..08ecf4842d966 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-averagegroup-idc.cxx @@ -0,0 +1,162 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <fmt/format.h> +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCAverageGroupIDCSpec.h" +#include "TPCBase/CRU.h" +#include "TPCBase/Mapper.h" +#include "Framework/Variant.h" +#include <boost/lexical_cast.hpp> +#include <boost/tokenizer.hpp> +#include "TPCCalibration/IDCAverageGroup.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-averagegroup.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + const int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector<ConfigParamSpec> options{ + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"debug", VariantType::Bool, false, {"create debug files"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes (crus are split per device)."}}, + {"time-lanes", VariantType::Int, 1, {"Number of parallel processing lanes (timeframes are split per device)."}}, + {"nthreads", VariantType::Int, 1, {"Number of threads which will be used during averaging and grouping."}}, + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"rangeIDC", VariantType::Int, 200, {"Number of 1D-IDCs which will be used for the calculation of the fourier coefficients."}}, + {"minIDCsPerTF", VariantType::Int, 10, {"minimum number of IDCs per TF (needed for sending to 1D-IDCs to EPNs. Depends on number of orbits per TF. 10 for 128 orbits per TF)."}}, + {"sigma", VariantType::Float, 3.f, {"maximum accepted standard deviation for filtering outliers"}}, + {"groupPads", VariantType::String, "7,7,7,7,6,6,6,6,5,5", {"number of pads in a row which will be grouped per region"}}, + {"groupRows", VariantType::String, "5,5,5,5,4,4,4,4,3,3", {"number of pads in row direction which will be grouped per region"}}, + {"groupLastRowsThreshold", VariantType::String, "3,3,3,3,2,2,2,2,2,2", {"set threshold in row direction for merging the last group to the previous group per region"}}, + {"groupLastPadsThreshold", VariantType::String, "3,3,3,3,2,2,2,2,1,1", {"set threshold in pad direction for merging the last group to the previous group per region"}}, + {"load-from-file", VariantType::Bool, false, {"load average and grouped IDCs from IDCGroup.root file."}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g. 'TPCIDCGroupParam.Method=0;')"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto nLanes = std::min(static_cast<unsigned long>(config.options().get<int>("lanes")), nCRUs); + const auto time_lanes = static_cast<unsigned int>(config.options().get<int>("time-lanes")); + const auto crusPerLane = nCRUs / nLanes + ((nCRUs % nLanes) != 0); + const auto debug = config.options().get<bool>("debug"); + const auto nthreads = static_cast<unsigned long>(config.options().get<int>("nthreads")); + IDCAverageGroup::setNThreads(nthreads); + const auto rangeIDC = static_cast<unsigned int>(config.options().get<int>("rangeIDC")); + const auto minIDCsPerTF = static_cast<unsigned int>(config.options().get<int>("minIDCsPerTF")); + const auto sigma = config.options().get<float>("sigma"); + TPCAverageGroupIDCDevice::setMinIDCsPerTF(minIDCsPerTF); + const auto loadFromFile = config.options().get<bool>("load-from-file"); + + const std::string sgroupPads = config.options().get<std::string>("groupPads"); + const std::string sgroupRows = config.options().get<std::string>("groupRows"); + const std::string sgroupLastRowsThreshold = config.options().get<std::string>("groupLastRowsThreshold"); + const std::string sgroupLastPadsThreshold = config.options().get<std::string>("groupLastPadsThreshold"); + + // convert input string to std::vector<unsigned char> + const boost::char_separator<char> sep(","); /// char separator for the tokenizer + const boost::tokenizer<boost::char_separator<char>> tgroupPads(sgroupPads, sep); + const boost::tokenizer<boost::char_separator<char>> tgroupRows(sgroupRows, sep); + const boost::tokenizer<boost::char_separator<char>> tgroupLastRowsThreshold(sgroupLastRowsThreshold, sep); + const boost::tokenizer<boost::char_separator<char>> tgroupLastPadsThreshold(sgroupLastPadsThreshold, sep); + + std::vector<unsigned char> vgroupPads; + std::vector<unsigned char> vgroupRows; + std::vector<unsigned char> vgroupLastRowsThreshold; + std::vector<unsigned char> vgroupLastPadsThreshold; + vgroupPads.reserve(Mapper::NREGIONS); + vgroupRows.reserve(Mapper::NREGIONS); + vgroupLastRowsThreshold.reserve(Mapper::NREGIONS); + vgroupLastPadsThreshold.reserve(Mapper::NREGIONS); + + std::transform(tgroupPads.begin(), tgroupPads.end(), std::back_inserter(vgroupPads), &boost::lexical_cast<int, std::string>); + std::transform(tgroupRows.begin(), tgroupRows.end(), std::back_inserter(vgroupRows), &boost::lexical_cast<int, std::string>); + std::transform(tgroupLastRowsThreshold.begin(), tgroupLastRowsThreshold.end(), std::back_inserter(vgroupLastRowsThreshold), &boost::lexical_cast<int, std::string>); + std::transform(tgroupLastPadsThreshold.begin(), tgroupLastPadsThreshold.end(), std::back_inserter(vgroupLastPadsThreshold), &boost::lexical_cast<int, std::string>); + + if (vgroupPads.size() == 1) { + vgroupPads = std::vector<unsigned char>(Mapper::NREGIONS, vgroupPads.front()); + } else if (vgroupPads.size() != Mapper::NREGIONS) { + LOGP(error, "wrong number of parameters inserted for groupPads (n={}). Number should be 1 or {}", vgroupPads.size(), Mapper::NREGIONS); + } + + if (vgroupRows.size() == 1) { + vgroupRows = std::vector<unsigned char>(Mapper::NREGIONS, vgroupRows.front()); + } else if (vgroupRows.size() != Mapper::NREGIONS) { + LOGP(error, "wrong number of parameters inserted for groupRows (n={}). Number should be 1 or {}", vgroupRows.size(), Mapper::NREGIONS); + } + + if (vgroupLastRowsThreshold.size() == 1) { + vgroupLastRowsThreshold = std::vector<unsigned char>(Mapper::NREGIONS, vgroupLastRowsThreshold.front()); + } else if (vgroupLastRowsThreshold.size() != Mapper::NREGIONS) { + LOGP(error, "wrong number of parameters inserted for groupLastRowsThreshold (n={}). Number should be 1 or {}", vgroupLastRowsThreshold.size(), Mapper::NREGIONS); + } + + if (vgroupLastPadsThreshold.size() == 1) { + vgroupLastPadsThreshold = std::vector<unsigned char>(Mapper::NREGIONS, vgroupLastPadsThreshold.front()); + } else if (vgroupLastPadsThreshold.size() != Mapper::NREGIONS) { + LOGP(error, "wrong number of parameters inserted for groupLastPadsThreshold (n={}). Number should be 1 or {}", vgroupLastPadsThreshold.size(), Mapper::NREGIONS); + } + + for (int i = 0; i < Mapper::NREGIONS; ++i) { + o2::conf::ConfigurableParam::setValue<unsigned char>("TPCIDCGroupParam", fmt::format("GroupPads[{}]", i).data(), vgroupPads[i]); + o2::conf::ConfigurableParam::setValue<unsigned char>("TPCIDCGroupParam", fmt::format("GroupRows[{}]", i).data(), vgroupRows[i]); + o2::conf::ConfigurableParam::setValue<unsigned char>("TPCIDCGroupParam", fmt::format("GroupLastRowsThreshold[{}]", i).data(), vgroupLastRowsThreshold[i]); + o2::conf::ConfigurableParam::setValue<unsigned char>("TPCIDCGroupParam", fmt::format("GroupLastPadsThreshold[{}]", i).data(), vgroupLastPadsThreshold[i]); + } + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::writeINI("o2tpcaveragegroupidc_configuration.ini"); + + WorkflowSpec workflow; + if (nLanes <= 0) { + return workflow; + } + + for (int ilane = 0; ilane < nLanes; ++ilane) { + const auto first = tpcCRUs.begin() + ilane * crusPerLane; + if (first >= tpcCRUs.end()) { + break; + } + const auto last = std::min(tpcCRUs.end(), first + crusPerLane); + const std::vector<uint32_t> rangeCRUs(first, last); + workflow.emplace_back(timePipeline(getTPCAverageGroupIDCSpec(ilane, rangeCRUs, rangeIDC, sigma, debug, loadFromFile), time_lanes)); + } + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx b/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx new file mode 100644 index 0000000000000..d3a7f2cae0d0a --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCWorkflow/CalibdEdxSpec.h" +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + using namespace o2::tpc; + return WorkflowSpec{getCalibdEdxSpec()}; +} diff --git a/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx b/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx new file mode 100644 index 0000000000000..e287b712439d9 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "TPCWorkflow/CalibLaserTracksSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-calib-laser-tracks", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"input-spec", VariantType::String, "input:TPC/TRACKS", {"selection string input specs"}}, + {"use-filtered-tracks", VariantType::Bool, false, {"use prefiltered laser tracks as input"}}, + }; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec specs; + std::string inputSpec = config.options().get<std::string>("input-spec"); + if (config.options().get<bool>("use-filtered-tracks")) { + inputSpec = "input:TPC/LASERTRACKS"; + } + specs.emplace_back(o2::tpc::getCalibLaserTracks(inputSpec)); + return specs; +} diff --git a/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx b/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx new file mode 100644 index 0000000000000..02e61a5c88be7 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <fmt/format.h> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "DPLUtils/RawParser.h" +#include "Headers/DataHeader.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCCalibration/CalibPedestal.h" +#include "TPCReconstruction/RawReaderCRU.h" +#include <vector> +#include <string> +#include "DetectorsRaw/RDHUtils.h" +#include "TPCBase/RDHUtils.h" +#include "TPCWorkflow/TPCCalibPedestalSpec.h" +#include "TPCWorkflow/CalDetMergerPublisherSpec.h" + +using namespace o2::framework; +using RDHUtils = o2::raw::RDHUtils; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("calib-tpc-pedestal.*", CompletionPolicy::CompletionOp::Consume)); + policies.push_back(CompletionPolicyHelpers::defineByName("calib-tpc-caldet-merger-publisher", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector<ConfigParamSpec> options{ + {"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}}, + {"publish-after-tfs", VariantType::Int, 0, {"number of time frames after which to force publishing the objects"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"no-write-ccdb", VariantType::Bool, false, {"skip sending the calibration output to CCDB"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes."}}, + {"sectors", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +using RDH = o2::header::RAWDataHeader; + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); + + const std::string inputSpec = config.options().get<std::string>("input-spec"); + const auto skipCCDB = config.options().get<bool>("no-write-ccdb"); + const auto publishAfterTFs = (uint32_t)config.options().get<int>("publish-after-tfs"); + + const auto tpcsectors = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("sectors")); + const auto nSectors = (uint32_t)tpcsectors.size(); + const auto nLanes = std::min((uint32_t)config.options().get<int>("lanes"), nSectors); + const auto sectorsPerLane = nSectors / nLanes + ((nSectors % nLanes) != 0); + + WorkflowSpec workflow; + + if (nLanes <= 0) { + return workflow; + } + + for (int ilane = 0; ilane < nLanes; ++ilane) { + auto first = tpcsectors.begin() + ilane * sectorsPerLane; + if (first >= tpcsectors.end()) { + break; + } + auto last = std::min(tpcsectors.end(), first + sectorsPerLane); + std::vector<int> range(first, last); + workflow.emplace_back(getTPCCalibPedestalSpec(inputSpec, ilane, range, publishAfterTFs)); + } + + workflow.emplace_back(getCalDetMergerPublisherSpec(nLanes, skipCCDB, publishAfterTFs > 0)); + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-distribute-idc.cxx b/Detectors/TPC/workflow/src/tpc-distribute-idc.cxx new file mode 100644 index 0000000000000..bb68526554080 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-distribute-idc.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCDistributeIDCSpec.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-aggregate.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + + std::vector<ConfigParamSpec> options{ + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"timeframes", VariantType::Int, 2000, {"Number of TFs which will be aggregated per aggregation interval."}}, + {"firstTF", VariantType::Int, 0, {"First time frame index."}}, + {"load-from-file", VariantType::Bool, false, {"load average and grouped IDCs from IDCGroup.root file."}}, + {"output-lanes", VariantType::Int, 2, {"Number of parallel pipelines which will be used in the factorization device."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::writeINI("o2tpcdistributeidc_configuration.ini"); + + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto timeframes = static_cast<unsigned int>(config.options().get<int>("timeframes")); + const auto outlanes = static_cast<unsigned int>(config.options().get<int>("output-lanes")); + const auto firstTF = static_cast<unsigned int>(config.options().get<int>("firstTF")); + const auto loadFromFile = config.options().get<bool>("load-from-file"); + + const auto first = tpcCRUs.begin(); + const auto last = std::min(tpcCRUs.end(), first + nCRUs); + const std::vector<uint32_t> rangeCRUs(first, last); + WorkflowSpec workflow{getTPCDistributeIDCSpec(rangeCRUs, timeframes, outlanes, firstTF, loadFromFile)}; + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-factorize-idc.cxx b/Detectors/TPC/workflow/src/tpc-factorize-idc.cxx new file mode 100644 index 0000000000000..612977b736a52 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-factorize-idc.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCFactorizeIDCSpec.h" +#include "TPCCalibration/IDCFactorization.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-factorize.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + + std::vector<ConfigParamSpec> options{ + {"configFile", VariantType::String, "o2tpcaveragegroupidc_configuration.ini", {"configuration file for configurable parameters"}}, + {"timeframes", VariantType::Int, 2000, {"Number of TFs which will be aggregated per aggregation interval."}}, + {"timeframesDeltaIDC", VariantType::Int, 100, {"Number of TFs used for storing the IDCDelta struct in the CCDB."}}, + {"nthreads-IDC-factorization", VariantType::Int, 1, {"Number of threads which will be used during the factorization of the IDCs."}}, + {"debug", VariantType::Bool, false, {"create debug files"}}, + {"sendOutput", VariantType::Bool, false, {"send IDC0, IDC1, IDCDelta, fourier coefficients (for debugging)"}}, + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"compression", VariantType::Int, 1, {"compression of DeltaIDC: 0 -> No, 1 -> Medium (data compression ratio 2), 2 -> High (data compression ratio ~6)"}}, + {"input-lanes", VariantType::Int, 2, {"Number of parallel pipelines which were set in the TPCDistributeIDCSpec device."}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g. for pp 50kHz: 'TPCIDCCompressionParam.MaxIDCDeltaValue=15;')"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2tpcfactorizeidc_configuration.ini"); + + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto timeframes = static_cast<unsigned int>(config.options().get<int>("timeframes")); + const auto timeframesDeltaIDC = static_cast<unsigned int>(config.options().get<int>("timeframesDeltaIDC")); + const auto debug = config.options().get<bool>("debug"); + const auto sendOutput = config.options().get<bool>("sendOutput"); + const auto nthreadsFactorization = static_cast<unsigned long>(config.options().get<int>("nthreads-IDC-factorization")); + IDCFactorization::setNThreads(nthreadsFactorization); + const auto nLanes = static_cast<unsigned int>(config.options().get<int>("input-lanes")); + + const int compressionTmp = config.options().get<int>("compression"); + IDCDeltaCompression compression; + switch (compressionTmp) { + case static_cast<int>(IDCDeltaCompression::NO): + case static_cast<int>(IDCDeltaCompression::MEDIUM): + case static_cast<int>(IDCDeltaCompression::HIGH): + compression = static_cast<IDCDeltaCompression>(compressionTmp); + break; + default: + LOGP(error, "wrong compression type set. Setting compression to medium compression"); + compression = static_cast<IDCDeltaCompression>(IDCDeltaCompression::MEDIUM); + break; + } + + const auto first = tpcCRUs.begin(); + const auto last = std::min(tpcCRUs.end(), first + nCRUs); + const std::vector<uint32_t> rangeCRUs(first, last); + + WorkflowSpec workflow; + workflow.reserve(nLanes); + for (int ilane = 0; ilane < nLanes; ++ilane) { + workflow.emplace_back(getTPCFactorizeIDCSpec(ilane, rangeCRUs, timeframes, timeframesDeltaIDC, compression, debug, sendOutput)); + } + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-fouriertransform-aggregator.cxx b/Detectors/TPC/workflow/src/tpc-fouriertransform-aggregator.cxx new file mode 100644 index 0000000000000..4cd4ec8e4be50 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-fouriertransform-aggregator.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCFourierTransformAggregatorSpec.h" +#include "TPCCalibration/IDCFactorization.h" +#include "TPCCalibration/IDCFourierTransform.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-aggregator-ft.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + + std::vector<ConfigParamSpec> options{ + {"timeframes", VariantType::Int, 2000, {"Number of TFs which will be aggregated per aggregation interval."}}, + {"rangeIDC", VariantType::Int, 200, {"Number of 1D-IDCs which will be used for the calculation of the fourier coefficients. TODO ALREADY SET IN ABERAGEGROUP"}}, + {"nFourierCoeff", VariantType::Int, 60, {"Number of fourier coefficients (real+imag) which will be stored in the CCDB. The maximum can be 'rangeIDC + 2'."}}, + {"nthreads", VariantType::Int, 1, {"Number of threads which will be used during the calculation of the fourier coefficients."}}, + {"debug", VariantType::Bool, false, {"create debug files"}}, + {"sendOutput", VariantType::Bool, false, {"send IDC0, IDC1, IDCDelta, fourier coefficients (for debugging)"}}, + {"use-naive-fft", VariantType::Bool, false, {"using naive fourier transform (true) or FFTW (false)"}}, + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::writeINI("o2tpcaggregate1didc_configuration.ini"); + + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto timeframes = static_cast<unsigned int>(config.options().get<int>("timeframes")); + const auto debug = config.options().get<bool>("debug"); + const auto sendOutput = config.options().get<bool>("sendOutput"); + const bool fft = config.options().get<bool>("use-naive-fft"); + const auto rangeIDC = static_cast<unsigned int>(config.options().get<int>("rangeIDC")); + const auto nFourierCoeff = std::clamp(static_cast<unsigned int>(config.options().get<int>("nFourierCoeff")), static_cast<unsigned int>(0), rangeIDC + 2); + const auto nthreadsFourier = static_cast<unsigned long>(config.options().get<int>("nthreads")); + TPCFourierTransformAggregatorSpec::IDCFType::setNThreads(nthreadsFourier); + TPCFourierTransformAggregatorSpec::IDCFType::setFFT(!fft); + + const auto first = tpcCRUs.begin(); + const auto last = std::min(tpcCRUs.end(), first + nCRUs); + const std::vector<uint32_t> rangeCRUs(first, last); + WorkflowSpec workflow{getTPCFourierTransformAggregatorSpec(rangeCRUs, timeframes, rangeIDC, nFourierCoeff, debug, sendOutput)}; + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-fouriertransform-epn.cxx b/Detectors/TPC/workflow/src/tpc-fouriertransform-epn.cxx new file mode 100644 index 0000000000000..6fcbeac054ca1 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-fouriertransform-epn.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCFourierTransformEPNSpec.h" +#include "TPCCalibration/IDCFourierTransform.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-epn-ft.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + + std::vector<ConfigParamSpec> options{ + {"configFile", VariantType::String, "o2tpcaveragegroupidc_configuration.ini", {"configuration file for configurable parameters"}}, + {"rangeIDC", VariantType::Int, 200, {"Number of 1D-IDCs which will be used for the calculation of the fourier coefficients."}}, + {"nFourierCoeff", VariantType::Int, 60, {"Number of fourier coefficients (real+imag) which will be stored in the CCDB. The maximum can be 'rangeIDC + 2'."}}, + {"debug", VariantType::Bool, false, {"create debug files"}}, + {"use-naive-fft", VariantType::Bool, false, {"using naive fourier transform (true) or FFTW (false)"}}, + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::writeINI("o2tpcftidcsync_configuration.ini"); + + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto debug = config.options().get<bool>("debug"); + const bool fft = config.options().get<bool>("use-naive-fft"); + const auto rangeIDC = static_cast<unsigned int>(config.options().get<int>("rangeIDC")); + const auto nFourierCoeff = std::clamp(static_cast<unsigned int>(config.options().get<int>("nFourierCoeff")), static_cast<unsigned int>(0), rangeIDC + 2); + TPCFourierTransformEPNSpec::IDCFType::setFFT(!fft); + + WorkflowSpec workflow; + const auto first = tpcCRUs.begin(); + const auto last = std::min(tpcCRUs.end(), first + nCRUs); + const std::vector<uint32_t> rangeCRUs(first, last); + workflow.emplace_back(getTPCFourierTransformEPNSpec(rangeCRUs, rangeIDC, nFourierCoeff, debug)); + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-idc-to-vector.cxx b/Detectors/TPC/workflow/src/tpc-idc-to-vector.cxx new file mode 100644 index 0000000000000..e5d3b736ec6cc --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-idc-to-vector.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include <fmt/format.h> + +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +//#include "Framework/DataProcessorSpec.h" +//#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +//#include "Framework/InputRecordWalker.h" +//#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCBase/CRU.h" +#include "TPCWorkflow/IDCToVectorSpec.h" + +using namespace o2::framework; +using namespace o2::tpc; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-to-vector", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::string sectorDefault = "0-" + std::to_string(CRU::MaxCRU - 1); + int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector<ConfigParamSpec> options{ + {"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"crus", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2tpcidc_configuration.ini"); + + const std::string inputSpec = config.options().get<std::string>("input-spec"); + + const auto crus = o2::RangeTokenizer::tokenize<uint32_t>(config.options().get<std::string>("crus")); + + WorkflowSpec workflow; + + workflow.emplace_back(getIDCToVectorSpec(inputSpec, crus)); + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-integrate-idc.cxx b/Detectors/TPC/workflow/src/tpc-integrate-idc.cxx new file mode 100644 index 0000000000000..828f9c4bbd00f --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-integrate-idc.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCWorkflow/TPCIntegrateIDCSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/HBFUtils.h" +#include "TPCSimulation/IDCSim.h" +#include "TPCBase/Sector.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-idc-integrateidc.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + const int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector<ConfigParamSpec> options{ + {"nOrbits", VariantType::Int, 12, {"number of orbits for which the IDCs are integrated"}}, + {"outputFormat", VariantType::String, "Sim", {"setting the output format type: 'Sim'=IDC simulation format, 'Real'=real output format of CRUs (not implemented yet)"}}, + {"debug", VariantType::Bool, false, {"create debug tree"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes."}}, + {"sectors", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"hbfutils-config", VariantType::String, std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE), {"config file for HBFUtils (or none) to get number of orbits per TF"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + std::string confDig = config.options().get<std::string>("hbfutils-config"); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::writeINI("o2tpcintegrateidc_configuration.ini"); + + const auto& hbfu = o2::raw::HBFUtils::Instance(); + LOGP(info, "Setting {} orbits per TF", hbfu.getNOrbitsPerTF()); + o2::tpc::IDCSim::setNOrbitsPerTF(hbfu.getNOrbitsPerTF()); + + const auto nOrbits = config.options().get<int>("nOrbits"); + const auto outputFormatStr = config.options().get<std::string>("outputFormat"); + const TPCIntegrateIDCDevice::IDCFormat outputFormat = outputFormatStr.compare("Sim") ? TPCIntegrateIDCDevice::IDCFormat::Real : TPCIntegrateIDCDevice::IDCFormat::Sim; + const auto debug = config.options().get<bool>("debug"); + const auto tpcsectors = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("sectors")); + const auto nSectors = tpcsectors.size(); + const auto nLanes = std::min(static_cast<unsigned long>(config.options().get<int>("lanes")), nSectors); + const auto sectorsPerLane = nSectors / nLanes + ((nSectors % nLanes) != 0); + + WorkflowSpec workflow; + if (nLanes <= 0) { + return workflow; + } + + for (int ilane = 0; ilane < nLanes; ++ilane) { + const auto first = tpcsectors.begin() + ilane * sectorsPerLane; + if (first >= tpcsectors.end()) { + break; + } + const auto last = std::min(tpcsectors.end(), first + sectorsPerLane); + const std::vector<unsigned int> rangeSectors(first, last); + workflow.emplace_back(getTPCIntegrateIDCSpec(ilane, rangeSectors, nOrbits, outputFormat, debug)); + } + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-krypton-clusterer.cxx b/Detectors/TPC/workflow/src/tpc-krypton-clusterer.cxx new file mode 100644 index 0000000000000..371403723b846 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-krypton-clusterer.cxx @@ -0,0 +1,178 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> +#include <string> + +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/KrCluster.h" +#include "TPCBase/Sector.h" +#include "TPCWorkflow/KryptonClustererSpec.h" + +using namespace o2::framework; +using namespace o2::tpc; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-krypton-clusterer.*", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector<ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"outputFile", VariantType::String, "./tpcBoxClusters.root", {"output file name for the box cluster root file"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes."}}, + {"sectors", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"disable-writer", VariantType::Bool, false, {"disable the root tree writer"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); + + const std::string outputFile = config.options().get<std::string>("outputFile"); + + const auto tpcSectors = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("sectors")); + const auto nSectors = (int)tpcSectors.size(); + const auto nLanes = std::min(config.options().get<int>("lanes"), nSectors); + const auto disableWriter = config.options().get<bool>("disable-writer"); + + WorkflowSpec workflow; + + if (nLanes <= 0) { + return workflow; + } + + std::vector<int> laneConfiguration = tpcSectors; // Currently just a copy of the tpcSectors, why? + + WorkflowSpec parallelProcessors; + parallelProcessors.emplace_back(getKryptonClustererSpec()); + + parallelProcessors = parallelPipeline( + parallelProcessors, nLanes, + [&laneConfiguration]() { return laneConfiguration.size(); }, + [&laneConfiguration](size_t index) { return laneConfiguration[index]; }); + workflow.insert(workflow.end(), parallelProcessors.begin(), parallelProcessors.end()); + + if (!disableWriter) { + ////////////////////////////////////////////////////////////////////////////////////////////// + // + // generation of processor specs for various types of outputs + // based on generic RootTreeWriter and MakeRootTreeWriterSpec generator + // + // ------------------------------------------------------------------------------------------- + // the callbacks for the RootTreeWriter + // + // The generic writer needs a way to associate incoming data with the individual branches for + // the TPC sectors. The sector number is transmitted as part of the sector header, the callback + // finds the corresponding index in the vector of configured sectors + auto getIndex = [tpcSectors](o2::framework::DataRef const& ref) { + auto const* tpcSectorHeader = o2::framework::DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref); + if (!tpcSectorHeader) { + throw std::runtime_error("TPC sector header missing in header stack"); + } + if (tpcSectorHeader->sector() < 0) { + // special data sets, don't write + return ~(size_t)0; + } + size_t index = 0; + for (auto const& sector : tpcSectors) { + if (sector == tpcSectorHeader->sector()) { + return index; + } + ++index; + } + throw std::runtime_error("sector " + std::to_string(tpcSectorHeader->sector()) + " not configured for writing"); + }; + auto getName = [tpcSectors](std::string base, size_t index) { + return base + "_" + std::to_string(tpcSectors.at(index)); + }; + + auto makeWriterSpec = [tpcSectors, laneConfiguration, getIndex, getName](const char* processName, + const char* defaultFileName, + const char* defaultTreeName, + auto&& databranch, + bool singleBranch = false) { + if (tpcSectors.size() == 0) { + throw std::invalid_argument(std::string("writer process configuration needs list of TPC sectors")); + } + + auto amendInput = [tpcSectors, laneConfiguration](InputSpec& input, size_t index) { + input.binding += std::to_string(laneConfiguration[index]); + DataSpecUtils::updateMatchingSubspec(input, laneConfiguration[index]); + }; + auto amendBranchDef = [laneConfiguration, amendInput, tpcSectors, getIndex, getName, singleBranch](auto&& def, bool enableMC = true) { + if (!singleBranch) { + def.keys = mergeInputs(def.keys, laneConfiguration.size(), amendInput); + // the branch is disabled if set to 0 + def.nofBranches = enableMC ? tpcSectors.size() : 0; + def.getIndex = getIndex; + def.getName = getName; + } else { + // instead of the separate sector branches only one is going to be written + def.nofBranches = enableMC ? 1 : 0; + } + return std::move(def); + }; + + return std::move(MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, + std::move(amendBranchDef(databranch)))()); + }; + + ////////////////////////////////////////////////////////////////////////////////////////////// + // + // a writer process for digits + // + // selected by output type 'difits' + using KrClusterOutputType = std::vector<o2::tpc::KrCluster>; + workflow.push_back(makeWriterSpec("tpc-krcluster-writer", + outputFile.data(), + "Clusters", + BranchDefinition<KrClusterOutputType>{InputSpec{"data", "TPC", "KRCLUSTERS", 0}, + "TPCBoxCluster", + "boxcluster-branch-name"})); + } // if (disableWriter) + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx b/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx new file mode 100644 index 0000000000000..561f972886326 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "TPCWorkflow/LaserTrackFilterSpec.h" +#include "DataFormatsTPC/TrackTPC.h" + +using namespace o2::framework; +using namespace o2::tpc; + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-laser-track-filter", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<ConfigParamSpec> options{ + {"enable-writer", VariantType::Bool, false, {"selection string input specs"}}, + }; + + std::swap(workflowOptions, options); +} +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + using namespace o2::tpc; + + WorkflowSpec workflow; + workflow.emplace_back(getLaserTrackFilter()); + + if (config.options().get<bool>("enable-writer")) { + const char* processName = "tpc-laser-track-writer"; + const char* defaultFileName = "tpc-laser-tracks.root"; + const char* defaultTreeName = "tpcrec"; + + //branch definitions for RootTreeWriter spec + using TrackOutputType = std::vector<o2::tpc::TrackTPC>; + + // a spectator callback which will be invoked by the tree writer with the extracted object + // we are using it for printing a log message + auto logger = BranchDefinition<TrackOutputType>::Spectator([](TrackOutputType const& tracks) { + LOG(INFO) << "writing " << tracks.size() << " track(s)"; + }); + auto tracksdef = BranchDefinition<TrackOutputType>{InputSpec{"inputTracks", "TPC", "LASERTRACKS", 0}, // + "TPCTracks", "track-branch-name", // + 1, // + logger}; // + + workflow.push_back(MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, + std::move(tracksdef))()); + } + + return workflow; +} diff --git a/Detectors/TPC/workflow/src/tpc-laser-tracks-calibrator.cxx b/Detectors/TPC/workflow/src/tpc-laser-tracks-calibrator.cxx new file mode 100644 index 0000000000000..422c4a841d785 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-laser-tracks-calibrator.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" + +#include "TPCWorkflow/LaserTracksCalibratorSpec.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-laser-tracks-calibrator", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(o2::tpc::getLaserTracksCalibrator()); + return specs; +} diff --git a/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx b/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx new file mode 100644 index 0000000000000..0ef0d4cc74867 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCWorkflow/MIPTrackFilterSpec.h" +#include "Framework/runDataProcessing.h" + +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + using namespace o2::tpc; + return WorkflowSpec{getMIPTrackFilterSpec()}; +} diff --git a/Detectors/TPC/workflow/src/tpc-monitor-workflow.cxx b/Detectors/TPC/workflow/src/tpc-monitor-workflow.cxx new file mode 100644 index 0000000000000..898e7bf0dfa9f --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-monitor-workflow.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <vector> + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "TPCWorkflow/MonitorWorkflowSpec.h" + +using namespace o2::framework; + +// customize the completion policy +void customize(std::vector<o2::framework::CompletionPolicy>& policies) +{ + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-monitor-workflow", CompletionPolicy::CompletionOp::Consume)); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + + std::vector<ConfigParamSpec> options{ + {"use-digit-input", VariantType::Bool, false, {"use TPC digits as input, instead of raw data"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + const bool useDigitsAsInput = cfg.options().get<bool>("use-digit-input"); + + WorkflowSpec specs; + + specs.emplace_back(o2::tpc::getMonitorWorkflowSpec(useDigitsAsInput)); + + return specs; +} diff --git a/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx b/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx index b282a0a2269ce..311c4dc135d2b 100644 --- a/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,14 +13,13 @@ #include "Framework/WorkflowSpec.h" #include "Framework/DataProcessorSpec.h" #include "Framework/ControlService.h" -#include "Framework/CompletionPolicy.h" -#include "Framework/CompletionPolicyHelpers.h" #include "Framework/Logger.h" #include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" #include "CommonUtils/ConfigurableParam.h" #include "Algorithm/RangeTokenizer.h" #include "TPCWorkflow/RawToDigitsSpec.h" -#include "TPCWorkflow/LinkZSToDigitsSpec.h" #include "TPCWorkflow/RecoWorkflow.h" #include "TPCBase/Sector.h" #include <vector> @@ -32,24 +32,10 @@ using namespace o2::framework; // customize the completion policy void customize(std::vector<o2::framework::CompletionPolicy>& policies) { - // we customize the completion policy for the writer since it should stream immediately - using CompletionPolicy = o2::framework::CompletionPolicy; - using CompletionPolicyHelpers = o2::framework::CompletionPolicyHelpers; - policies.push_back(CompletionPolicyHelpers::defineByName("tpc-cluster-decoder.*", CompletionPolicy::CompletionOp::Consume)); - policies.push_back(CompletionPolicyHelpers::defineByName("tpc-clusterer.*", CompletionPolicy::CompletionOp::Consume)); - policies.push_back(CompletionPolicyHelpers::defineByName("tpc-tracker.*", CompletionPolicy::CompletionOp::Consume)); + using o2::framework::CompletionPolicy; + policies.push_back(CompletionPolicyHelpers::defineByName("tpc-raw-to-digits-.*", CompletionPolicy::CompletionOp::Consume)); } -enum class DecoderType { - GBT, ///< GBT frame raw decoding - LinkZS ///< Link based zero suppression -}; - -const std::unordered_map<std::string, DecoderType> DecoderTypeMap{ - {"GBT", DecoderType::GBT}, - {"LinkZS", DecoderType::LinkZS}, -}; - // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector<ConfigParamSpec>& workflowOptions) { @@ -60,14 +46,12 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) const std::string sectorshelp("List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"); const std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); const std::string tpcrthelp("Run TPC reco workflow to specified output type, currently supported: 'digits,clusters,tracks'"); - const std::string decoderHelp("Decoder type to use: 'GBT,LinkZS'"); std::vector<ConfigParamSpec> options{ {"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}}, {"tpc-lanes", VariantType::Int, defaultlanes, {laneshelp}}, {"tpc-sectors", VariantType::String, sectorDefault.c_str(), {sectorshelp}}, {"tpc-reco-output", VariantType::String, "", {tpcrthelp}}, - {"decoder-type", VariantType::String, "GBT", {decoderHelp}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; @@ -102,19 +86,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // for the moment no parallel workflow, so just one lane hard coded auto tpcSectors = o2::RangeTokenizer::tokenize<int>(configcontext.options().get<std::string>("tpc-sectors")); - auto lanes = 1; //getNumTPCLanes(tpcSectors, config); - - const auto decoderType = DecoderTypeMap.at(configcontext.options().get<std::string>("decoder-type")); + auto lanes = 1; //getNumTPCLanes(tpcSectors, configcontext); int fanoutsize = 0; for (int l = 0; l < lanes; ++l) { - if (decoderType == DecoderType::GBT) { - specs.emplace_back(o2::tpc::getRawToDigitsSpec(fanoutsize, configcontext.options().get<std::string>("input-spec"), tpcSectors)); - } else if (decoderType == DecoderType::LinkZS) { - specs.emplace_back(o2::tpc::getLinkZSToDigitsSpec(fanoutsize, configcontext.options().get<std::string>("input-spec"), tpcSectors)); - } else { - LOG(FATAL) << "bad decoder type"; - } + specs.emplace_back(o2::tpc::getRawToDigitsSpec(fanoutsize, configcontext.options().get<std::string>("input-spec"), tpcSectors)); fanoutsize++; } @@ -126,8 +102,5 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) recoOuput = tpcRecoOutputType.c_str(); } - auto tpcRecoWorkflow = o2::tpc::reco_workflow::getWorkflow(nullptr, tpcSectors, tpcSectors, false, lanes, "digitizer", recoOuput.data()); - specs.insert(specs.end(), tpcRecoWorkflow.begin(), tpcRecoWorkflow.end()); - return specs; } diff --git a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx index b10b2c08f5293..a490581e2be3f 100644 --- a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,10 +22,11 @@ #include "Framework/PartRef.h" #include "Framework/ConcreteDataMatcher.h" #include "TPCWorkflow/RecoWorkflow.h" -#include "TPCWorkflow/TPCSectorCompletionPolicy.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "Algorithm/RangeTokenizer.h" #include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" #include <string> #include <stdexcept> @@ -37,6 +39,7 @@ o2::framework::Output gDispatchTrigger{"", ""}; // Global variable used to transport data to the completion policy o2::tpc::reco_workflow::CompletionPolicyData gPolicyData; +unsigned long gTpcSectorMask = 0xFFFFFFFFF; // add workflow options, note that customization needs to be declared before // including Framework/runDataProcessing @@ -46,18 +49,20 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) std::vector<ConfigParamSpec> options{ {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, clustershw, clustersnative, compressed-clusters, compressed-clusters-ctf"}}, - {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clustersnative, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector, qa"}}, + {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clustersnative, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector, qa, no-shared-cluster-map"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"no-ca-clusterer", VariantType::Bool, false, {"Use HardwareClusterer instead of clusterer of GPUCATracking"}}, {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, - //{"tpc-sectors", VariantType::String, "0-35", {"TPC sector range, e.g. 5-7,8,9"}}, + {"tpc-sectors", VariantType::String, "0-35", {"TPC sector range, e.g. 5-7,8,9"}}, {"tpc-lanes", VariantType::Int, 1, {"number of parallel lanes up to the tracker"}}, {"dispatching-mode", VariantType::String, "prompt", {"determines when to dispatch: prompt, complete"}}, {"no-tpc-zs-on-the-fly", VariantType::Bool, false, {"Do not use TPC zero suppression on the fly"}}, - {"zs-threshold", VariantType::Float, 2.0f, {"zero suppression threshold"}}, - {"zs-10bit", VariantType::Bool, false, {"use 10 bit ADCs for TPC zero suppression, default = 12 bit ADC"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCHwClusterer.peakChargeThreshold=4;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); } @@ -88,7 +93,7 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies) policies.push_back(CompletionPolicyHelpers::defineByName("tpc-cluster-decoder.*", CompletionPolicy::CompletionOp::Consume)); policies.push_back(CompletionPolicyHelpers::defineByName("tpc-clusterer.*", CompletionPolicy::CompletionOp::Consume)); // the custom completion policy for the tracker - policies.push_back(o2::tpc::TPCSectorCompletionPolicy("tpc-tracker.*", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData)()); + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("tpc-tracker.*", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData, &gTpcSectorMask)()); } #include "Framework/runDataProcessing.h" // the main driver @@ -111,9 +116,7 @@ using namespace o2::framework; /// This function hooks up the the workflow specifications into the DPL driver. WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - //auto tpcSectors = o2::RangeTokenizer::tokenize<int>(cfgc.options().get<std::string>("tpc-sectors")); - std::vector<int> tpcSectors(36); - std::iota(tpcSectors.begin(), tpcSectors.end(), 0); + std::vector<int> tpcSectors = o2::RangeTokenizer::tokenize<int>(cfgc.options().get<std::string>("tpc-sectors")); // the lane configuration defines the subspecification ids to be distributed among the lanes. std::vector<int> laneConfiguration = tpcSectors; // Currently just a copy of the tpcSectors, why? auto nLanes = cfgc.options().get<int>("tpc-lanes"); @@ -140,17 +143,28 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); o2::conf::ConfigurableParam::writeINI("o2tpcrecoworkflow_configuration.ini"); + gTpcSectorMask = 0; + for (auto s : tpcSectors) { + gTpcSectorMask |= (1ul << s); + } + bool doMC = not cfgc.options().get<bool>("disable-mc"); - return o2::tpc::reco_workflow::getWorkflow(&gPolicyData, // - tpcSectors, // sector configuration - laneConfiguration, // lane configuration - doMC, // - nLanes, // - inputType, // - cfgc.options().get<std::string>("output-type"), // - !cfgc.options().get<bool>("no-ca-clusterer"), // - !cfgc.options().get<bool>("no-tpc-zs-on-the-fly"), // - cfgc.options().get<bool>("zs-10bit"), // - cfgc.options().get<float>("zs-threshold") // + auto wf = o2::tpc::reco_workflow::getWorkflow(&gPolicyData, // + tpcSectors, // sector configuration + gTpcSectorMask, // same as bitmask + laneConfiguration, // lane configuration + doMC, // + nLanes, // + inputType, // + cfgc.options().get<std::string>("output-type"), // + cfgc.options().get<bool>("disable-root-input"), // + !cfgc.options().get<bool>("no-ca-clusterer"), // + !cfgc.options().get<bool>("no-tpc-zs-on-the-fly"), // + !cfgc.options().get<bool>("ignore-dist-stf") // ); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); + + return std::move(wf); } diff --git a/Detectors/TPC/workflow/test/test_TPCWorkflow.cxx b/Detectors/TPC/workflow/test/test_TPCWorkflow.cxx index 83c156851f91b..c7b47ebf4e2e6 100644 --- a/Detectors/TPC/workflow/test/test_TPCWorkflow.cxx +++ b/Detectors/TPC/workflow/test/test_TPCWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TPC/workflow/test/test_ft_EPN_Aggregator.cxx b/Detectors/TPC/workflow/test/test_ft_EPN_Aggregator.cxx new file mode 100644 index 0000000000000..35951193d3255 --- /dev/null +++ b/Detectors/TPC/workflow/test/test_ft_EPN_Aggregator.cxx @@ -0,0 +1,268 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file test_ft_EPN_Aggregator.cxx +/// \brief this task tests the the calculation of fourier coefficients on EPN and aggregator +/// +/// \author Matthias Kleiner <mkleiner@ikf.uni-frankfurt.de> + +#include "TPCWorkflow/TPCAverageGroupIDCSpec.h" +#include "TPCWorkflow/TPCIntegrateIDCSpec.h" +#include "TPCWorkflow/TPCFourierTransformEPNSpec.h" +#include "TPCWorkflow/TPCFourierTransformAggregatorSpec.h" +#include "TPCWorkflow/TPCDistributeIDCSpec.h" + +#include <boost/throw_exception.hpp> +#include "Framework/DataRefUtils.h" +#include "Framework/ControlService.h" +#include "Algorithm/RangeTokenizer.h" +#include "TRandom.h" + +#include <unistd.h> + +using namespace o2::framework; + +DataProcessorSpec generateIDCsCRU(int lane, const unsigned int maxTFs, const std::vector<uint32_t>& crus, const bool slowgen); +DataProcessorSpec ftAggregatorIDC(const unsigned int nFourierCoefficients, const unsigned int rangeIDC, const unsigned int maxTFs, const bool debug, const std::vector<uint32_t>& crus); +DataProcessorSpec receiveFourierCoeffEPN(const unsigned int maxTFs, const unsigned int nFourierCoefficients); +DataProcessorSpec compare_EPN_AGG(); +static constexpr o2::header::DataDescription getDataDescriptionCoeffEPN() { return o2::header::DataDescription{"COEFFEPNALL"}; } + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1); + + std::vector<ConfigParamSpec> options{ + {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"timeframes", VariantType::Int, 20, {"Number of TFs which will be produced"}}, + {"ion-drift-time", VariantType::Int, 200, {"Ion drift time in ms. (Number of 1D-IDCs which will be used for the calculation of the fourier coefficients.)"}}, + {"nFourierCoeff", VariantType::Int, 60, {"Number of fourier coefficients per TF (real+imag) which will be compared. The maximum can be 'ion-drift-time + 2'."}}, + {"use-naive-fft", VariantType::Bool, false, {"using naive fourier transform (true) or FFTW (false)"}}, + {"seed", VariantType::Int, 0, {"Seed for the random IDC generator."}}, + {"only-idc-gen", VariantType::Bool, false, {"Start only the IDC generator device"}}, + {"fast-gen", VariantType::Bool, false, {"fast generation of IDCs by setting fixed IDC value"}}, + {"debug", VariantType::Bool, false, {"create debug for FT"}}, + {"idc-gen-lanes", VariantType::Int, 1, {"number of parallel lanes for generation of IDCs"}}, + {"idc-gen-time-lanes", VariantType::Int, 1, {"number of parallel lanes for generation of IDCs"}}, + {"nthreads", VariantType::Int, 1, {"Number of threads."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus")); + const auto nCRUs = tpcCRUs.size(); + const auto first = tpcCRUs.begin(); + const auto last = std::min(tpcCRUs.end(), first + nCRUs); + const std::vector<uint32_t> crus(first, last); + const auto timeframes = static_cast<unsigned int>(config.options().get<int>("timeframes")); + const auto iondrifttime = static_cast<unsigned int>(config.options().get<int>("ion-drift-time")); + const auto nFourierCoefficients = std::clamp(static_cast<unsigned int>(config.options().get<int>("nFourierCoeff")), static_cast<unsigned int>(0), iondrifttime + 2); + const auto nthreads = static_cast<unsigned int>(config.options().get<int>("nthreads")); + const auto seed = static_cast<unsigned int>(config.options().get<int>("seed")); + const auto idcgenlanes = static_cast<unsigned int>(config.options().get<int>("idc-gen-lanes")); + const auto idcgentimelanes = static_cast<unsigned int>(config.options().get<int>("idc-gen-time-lanes")); + + const bool fft = config.options().get<bool>("use-naive-fft"); + const bool onlyIDCGen = config.options().get<bool>("only-idc-gen"); + const bool fastgen = config.options().get<bool>("fast-gen"); + const bool debugFT = config.options().get<bool>("debug"); + const float sigma = 5; + const unsigned int firstTF = 0; + const unsigned int nLanes = 1; + const bool loadFromFile = false; + gRandom->SetSeed(seed); + + WorkflowSpec workflow; + for (int ilane = 0; ilane < idcgenlanes; ++ilane) { + const auto crusPerLane = nCRUs / idcgenlanes + ((nCRUs % idcgenlanes) != 0); + const auto first = tpcCRUs.begin() + ilane * crusPerLane; + if (first >= tpcCRUs.end()) { + break; + } + const auto last = std::min(tpcCRUs.end(), first + crusPerLane); + const std::vector<uint32_t> rangeCRUs(first, last); + workflow.emplace_back(timePipeline(generateIDCsCRU(ilane, timeframes, rangeCRUs, fastgen), idcgentimelanes)); + } + + if (onlyIDCGen == true) { + return workflow; + } + + auto workflowTmp = WorkflowSpec{getTPCAverageGroupIDCSpec(0, crus, iondrifttime, sigma, debugFT, false), getTPCFourierTransformEPNSpec(crus, iondrifttime, nFourierCoefficients, debugFT), getTPCDistributeIDCSpec(crus, timeframes, nLanes, firstTF, loadFromFile), ftAggregatorIDC(nFourierCoefficients, iondrifttime, timeframes, debugFT, crus), receiveFourierCoeffEPN(timeframes, nFourierCoefficients), compare_EPN_AGG()}; + for (auto& spec : workflowTmp) { + workflow.emplace_back(spec); + } + + IDCAverageGroup::setNThreads(nthreads); + TPCFourierTransformEPNSpec::IDCFType::setFFT(!fft); + TPCFourierTransformAggregatorSpec::IDCFType::setNThreads(nthreads); + TPCFourierTransformAggregatorSpec::IDCFType::setFFT(!fft); + return workflow; +} + +DataProcessorSpec generateIDCsCRU(int lane, const unsigned int maxTFs, const std::vector<uint32_t>& crus, const bool fastgen) +{ + // generate random IDCs per CRU + const int nOrbitsPerTF = 128; // number of orbits per TF + const int nOrbitsPerIDC = 12; // integration interval in units of orbits per IDC + const int nIDCs = nOrbitsPerTF / nOrbitsPerIDC; + + std::vector<OutputSpec> outputSpecs; + outputSpecs.reserve(crus.size()); + for (const auto& cru : crus) { + const o2::header::DataHeader::SubSpecificationType subSpec{cru << 7}; + outputSpecs.emplace_back(ConcreteDataMatcher{gDataOriginTPC, TPCIntegrateIDCDevice::getDataDescription(TPCIntegrateIDCDevice::IDCFormat::Sim), subSpec}); + } + + return DataProcessorSpec{ + fmt::format("idc-generator-{:02}", lane).data(), + Inputs{}, + outputSpecs, + AlgorithmSpec{ + [maxTFs, fastgen, nIDCs, cruStart = crus.front(), cruEnde = crus.back()](ProcessingContext& ctx) { + const auto tf = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ctx.inputs().getFirstValid(true))->tfCounter; + + for (uint32_t icru = cruStart; icru <= cruEnde; ++icru) { + const o2::tpc::CRU cruTmp(icru); + const unsigned int nPads = o2::tpc::Mapper::PADSPERREGION[cruTmp.region()]; + const unsigned int additionalInterval = (tf % 3) ? 1 : 0; // in each integration inerval are either 10 or 11 values when having 128 orbits per TF and 12 orbits integration length + const unsigned int nTotIDCs = (nIDCs + additionalInterval) * nPads; + + // generate random IDCs per CRU + if (!fastgen) { + o2::pmr::vector<float> idcs; + idcs.reserve(nTotIDCs); + for (int i = 0; i < nTotIDCs; ++i) { + idcs.emplace_back(gRandom->Gaus(1000, 20)); + } + ctx.outputs().adoptContainer(Output{gDataOriginTPC, TPCIntegrateIDCDevice::getDataDescription(TPCIntegrateIDCDevice::IDCFormat::Sim), o2::header::DataHeader::SubSpecificationType{icru << 7}, Lifetime::Timeframe}, std::move(idcs)); + } else { + o2::pmr::vector<float> idcs(nTotIDCs, 1000.); + ctx.outputs().adoptContainer(Output{gDataOriginTPC, TPCIntegrateIDCDevice::getDataDescription(TPCIntegrateIDCDevice::IDCFormat::Sim), o2::header::DataHeader::SubSpecificationType{icru << 7}, Lifetime::Timeframe}, std::move(idcs)); + } + } + + if (tf >= (maxTFs - 1)) { + ctx.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } + }}}; +} + +DataProcessorSpec ftAggregatorIDC(const unsigned int nFourierCoefficients, const unsigned int rangeIDC, const unsigned int maxTFs, const bool debug, const std::vector<uint32_t>& crus) +{ + std::vector<ConfigParamSpec> options{ + {"ccdb-uri", VariantType::String, "", {"URI for the CCDB access."}}, + {"update-not-grouping-parameter", VariantType::Bool, true, {"Do NOT Update/Writing grouping parameters to CCDB."}}}; + + auto spec = getTPCFourierTransformAggregatorSpec(crus, maxTFs, rangeIDC, nFourierCoefficients, debug, true); + std::swap(spec.options, options); + + return spec; +} + +class TPCReceiveEPNSpec : public o2::framework::Task +{ + /// device for receiving and aggregating fourier coefficients from EPN device + public: + TPCReceiveEPNSpec(const unsigned int nTFs, const unsigned int nFourierCoefficients) : mFourierCoeffEPN(nTFs, o2::tpc::FourierCoeff(1, nFourierCoefficients)), mMaxTF{nTFs - 1} {}; + + void run(o2::framework::ProcessingContext& ctx) final + { + for (int i = 0; i < o2::tpc::SIDES; ++i) { + const DataRef ref = ctx.inputs().getByPos(i); + auto const* tpcFourierCoeffHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + const int side = tpcFourierCoeffHeader->subSpecification; + const auto tf = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref)->tfCounter; + mFourierCoeffEPN[tf].mFourierCoefficients[side] = ctx.inputs().get<std::vector<float>>(ref); + } + + const auto tf = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ctx.inputs().getFirstValid(true))->tfCounter; + if (tf == mMaxTF) { + ctx.outputs().snapshot(Output{gDataOriginTPC, getDataDescriptionCoeffEPN()}, mFourierCoeffEPN); + } + } + + private: + std::vector<o2::tpc::FourierCoeff> mFourierCoeffEPN; ///< one set of fourier coefficients per TF + const unsigned int mMaxTF{}; ///< max TF when aggregator will send data +}; + +class TPCCompareFourierCoeffSpec : public o2::framework::Task +{ + /// device for receiving the fourier coefficients from the EPN and the aggregator and comparing them + public: + void run(o2::framework::ProcessingContext& ctx) final + { + LOGP(info, "==== Comparing Fourier coefficients for EPN and Aggregator... ===="); + const auto fourierCoeffAgg = ctx.inputs().get<FourierCoeff*>(ctx.inputs().get("coeffAgg")); + const std::vector<o2::tpc::FourierCoeff> fourierCoeffEPN = ctx.inputs().get<std::vector<o2::tpc::FourierCoeff>>(ctx.inputs().get("coeffEPN")); + for (int iside = 0; iside < o2::tpc::SIDES; ++iside) { + const o2::tpc::Side side = iside == 0 ? o2::tpc::Side::A : o2::tpc::Side::C; + for (int tf = 0; tf < fourierCoeffEPN.size(); ++tf) { + for (int i = 0; i < fourierCoeffEPN[tf].getNCoefficientsPerTF(); ++i) { + const float epnval = fourierCoeffEPN[tf](side, i); + const float aggval = (*fourierCoeffAgg)(side, fourierCoeffAgg->getIndex(tf, i)); + const bool isEqual = (std::abs(std::min(epnval, aggval)) < 1.f) ? isSameZero(epnval, aggval) : isSame(epnval, aggval); + if (!isEqual) { + ctx.services().get<ControlService>().endOfStream(); + ctx.services().get<ControlService>().readyToQuit(QuitRequest::All); + BOOST_THROW_EXCEPTION(std::runtime_error(fmt::format("EPN value: {} Aggregator value: {} epn-agg: {} epn/agg: {} ", epnval, aggval, epnval - aggval, epnval / aggval).data())); + } + } + } + } + LOGP(info, "==== Test finished successfull! Fourier coefficients for EPN and Aggregator are equal. ===="); + ctx.services().get<ControlService>().endOfStream(); + ctx.services().get<ControlService>().readyToQuit(QuitRequest::All); + } + + private: + const float mTolerance = 1e-4; ///< max accepted tolerance between EPN and Aggregator + + bool isSameZero(const float epnval, const float aggval) const { return (epnval - aggval) * (epnval - aggval) < mTolerance; } + bool isSame(const float epnval, const float aggval) const { return std::abs((epnval - aggval) / std::min(epnval, aggval)) < mTolerance; } +}; + +DataProcessorSpec receiveFourierCoeffEPN(const unsigned int maxTFs, const unsigned int nFourierCoefficients) +{ + // generate IDCs per CRU + std::vector<InputSpec> inputSpecs; + inputSpecs.emplace_back(InputSpec{"coeffAEPN", gDataOriginTPC, TPCFourierTransformEPNSpec::getDataDescription(), o2::header::DataHeader::SubSpecificationType{o2::tpc::Side::A}, Lifetime::Timeframe}); + inputSpecs.emplace_back(InputSpec{"coeffCEPN", gDataOriginTPC, TPCFourierTransformEPNSpec::getDataDescription(), o2::header::DataHeader::SubSpecificationType{o2::tpc::Side::C}, Lifetime::Timeframe}); + std::vector<OutputSpec> outputSpecs{ConcreteDataTypeMatcher{gDataOriginTPC, getDataDescriptionCoeffEPN()}}; + + return DataProcessorSpec{ + "idc-fouriercoeff-epn", + inputSpecs, + outputSpecs, + AlgorithmSpec{adaptFromTask<TPCReceiveEPNSpec>(maxTFs, nFourierCoefficients)}, + }; +} + +DataProcessorSpec compare_EPN_AGG() +{ + // generate IDCs per CRU + std::vector<InputSpec> inputSpecs; + inputSpecs.emplace_back(InputSpec("coeffEPN", ConcreteDataTypeMatcher{gDataOriginTPC, getDataDescriptionCoeffEPN()})); + inputSpecs.emplace_back(InputSpec("coeffAgg", ConcreteDataTypeMatcher{gDataOriginTPC, TPCFourierTransformAggregatorSpec::getDataDescriptionFourier()})); + + return DataProcessorSpec{ + "idc-fouriercoeff-compare", + inputSpecs, + Outputs{}, + AlgorithmSpec{adaptFromTask<TPCCompareFourierCoeffSpec>()}, + }; +} diff --git a/Detectors/TRD/CMakeLists.txt b/Detectors/TRD/CMakeLists.txt index 6f1b27629d9ea..fa3b572150a41 100644 --- a/Detectors/TRD/CMakeLists.txt +++ b/Detectors/TRD/CMakeLists.txt @@ -1,14 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(calibration) add_subdirectory(simulation) +add_subdirectory(reconstruction) add_subdirectory(macros) add_subdirectory(workflow) diff --git a/Detectors/TRD/README.md b/Detectors/TRD/README.md index 5518535375fb3..5c5606384ced4 100644 --- a/Detectors/TRD/README.md +++ b/Detectors/TRD/README.md @@ -2,8 +2,8 @@ \page refDetectorsTRD TRD /doxy --> -# TRD +# TRD <!-- doxy -* \subpage refTRDbase +* \subpage refDetectorsTRDsimulation /doxy --> diff --git a/Detectors/TRD/base/CMakeLists.txt b/Detectors/TRD/base/CMakeLists.txt index d61d638a63fc4..c664415a9db31 100644 --- a/Detectors/TRD/base/CMakeLists.txt +++ b/Detectors/TRD/base/CMakeLists.txt @@ -16,10 +16,10 @@ o2_add_library(TRDBase src/DiffAndTimeStructEstimator.cxx src/SimParam.cxx src/PadResponse.cxx - src/Digit.cxx src/CalDet.cxx src/CalROC.cxx src/FeeParam.cxx + src/RecoParam.cxx src/PadStatus.cxx src/LocalVDrift.cxx src/LocalT0.cxx @@ -29,6 +29,7 @@ o2_add_library(TRDBase src/ChamberNoise.cxx src/CalOnlineGainTables.cxx src/Tracklet.cxx + src/TrackletTransformer.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon O2::GPUUtils O2::DetectorsCommonDataFormats @@ -45,13 +46,13 @@ o2_target_root_dictionary(TRDBase include/TRDBase/Geometry.h include/TRDBase/GeometryFlat.h include/TRDBase/SimParam.h + include/TRDBase/Garfield.h include/TRDBase/CommonParam.h include/TRDBase/PadResponse.h - include/TRDBase/Digit.h - include/TRDBase/MCLabel.h include/TRDBase/CalDet.h include/TRDBase/CalROC.h include/TRDBase/FeeParam.h + include/TRDBase/RecoParam.h include/TRDBase/PadParameters.h include/TRDBase/PadCalibrations.h include/TRDBase/ChamberCalibrations.h @@ -63,7 +64,8 @@ o2_target_root_dictionary(TRDBase include/TRDBase/Calibrations.h include/TRDBase/ChamberNoise.h include/TRDBase/CalOnlineGainTables.h - include/TRDBase/Tracklet.h) + include/TRDBase/Tracklet.h + include/TRDBase/TrackletTransformer.h) o2_add_test(DiffusionCoefficient SOURCES test/testTRDDiffusionCoefficient.cxx @@ -86,3 +88,10 @@ o2_add_test(RawData ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage LABELS trd ) +o2_add_test(Transformations + COMPONENT_NAME trd + PUBLIC_LINK_LIBRARIES O2::TRDBase O2::DataFormatsTRD + SOURCES test/testCoordinateTransforms.cxx + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + LABELS trd + ) diff --git a/Detectors/TRD/base/include/TRDBase/CalDet.h b/Detectors/TRD/base/include/TRDBase/CalDet.h index 9affc767fdcdc..f11423a3aa343 100644 --- a/Detectors/TRD/base/include/TRDBase/CalDet.h +++ b/Detectors/TRD/base/include/TRDBase/CalDet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CalOnlineGainTables.h b/Detectors/TRD/base/include/TRDBase/CalOnlineGainTables.h index 2537830bac80c..6dddbbdd92326 100644 --- a/Detectors/TRD/base/include/TRDBase/CalOnlineGainTables.h +++ b/Detectors/TRD/base/include/TRDBase/CalOnlineGainTables.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CalPad.h b/Detectors/TRD/base/include/TRDBase/CalPad.h index a9708af8d1f49..ecfb062898f9f 100644 --- a/Detectors/TRD/base/include/TRDBase/CalPad.h +++ b/Detectors/TRD/base/include/TRDBase/CalPad.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CalPadStatus.h b/Detectors/TRD/base/include/TRDBase/CalPadStatus.h index 32a61b5285a61..589e4984331b9 100644 --- a/Detectors/TRD/base/include/TRDBase/CalPadStatus.h +++ b/Detectors/TRD/base/include/TRDBase/CalPadStatus.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CalROC.h b/Detectors/TRD/base/include/TRDBase/CalROC.h index 3c50ea1c19aa3..02b2d02e7060b 100644 --- a/Detectors/TRD/base/include/TRDBase/CalROC.h +++ b/Detectors/TRD/base/include/TRDBase/CalROC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CalSingleChamberStatus.h b/Detectors/TRD/base/include/TRDBase/CalSingleChamberStatus.h index d1566ab1b0266..214ae27bfc2dc 100644 --- a/Detectors/TRD/base/include/TRDBase/CalSingleChamberStatus.h +++ b/Detectors/TRD/base/include/TRDBase/CalSingleChamberStatus.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/Calibrations.h b/Detectors/TRD/base/include/TRDBase/Calibrations.h index 3a513b399aa3c..1b9bab2b2480f 100644 --- a/Detectors/TRD/base/include/TRDBase/Calibrations.h +++ b/Detectors/TRD/base/include/TRDBase/Calibrations.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,7 +47,6 @@ #include "TRDBase/PadStatus.h" #include "TRDBase/CalOnlineGainTables.h" -class Geometry; namespace o2 { namespace trd @@ -54,22 +54,13 @@ namespace trd class Calibrations { - enum { - kSimulation = 1, - kReconstruction = 2, - kCalibration = 3 - }; public: Calibrations() = default; ~Calibrations() = default; // - int const getTimeStamp() { return mTimeStamp; } - void setTimeStamp(long timestamp) { mTimeStamp = timestamp; } - void setCCDB(int calibrationobjecttype, long timestamp); - void setCCDBForSimulation(long timestamp) { setCCDB(kSimulation, timestamp); }; - void setCCDBForReconstruction(long timestamp) { setCCDB(kReconstruction, timestamp); }; - void setCCDBForCalibration(long timestamp) { setCCDB(kCalibration, timestamp); }; + int getTimeStamp() const { return mTimeStamp; } + void getCCDBObjects(long timestamp); void setOnlineGainTables(std::string& tablename); // double getVDrift(int roc, int col, int row) const; diff --git a/Detectors/TRD/base/include/TRDBase/ChamberCalibrations.h b/Detectors/TRD/base/include/TRDBase/ChamberCalibrations.h index 9c433deb76c2e..b946f1646220e 100644 --- a/Detectors/TRD/base/include/TRDBase/ChamberCalibrations.h +++ b/Detectors/TRD/base/include/TRDBase/ChamberCalibrations.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/ChamberNoise.h b/Detectors/TRD/base/include/TRDBase/ChamberNoise.h index a6f4df8785fb6..e8c6e16e49c43 100644 --- a/Detectors/TRD/base/include/TRDBase/ChamberNoise.h +++ b/Detectors/TRD/base/include/TRDBase/ChamberNoise.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/ChamberStatus.h b/Detectors/TRD/base/include/TRDBase/ChamberStatus.h index 642a1a56995c4..7c9965612f81c 100644 --- a/Detectors/TRD/base/include/TRDBase/ChamberStatus.h +++ b/Detectors/TRD/base/include/TRDBase/ChamberStatus.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/CommonParam.h b/Detectors/TRD/base/include/TRDBase/CommonParam.h index 5c1f6e079a9ef..a526637327c98 100644 --- a/Detectors/TRD/base/include/TRDBase/CommonParam.h +++ b/Detectors/TRD/base/include/TRDBase/CommonParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,75 +12,67 @@ #ifndef O2_TRD_COMMONPARAM_H #define O2_TRD_COMMONPARAM_H -#include "GPUCommonRtypes.h" +#include <array> +#include "Rtypes.h" // for ClassDef +#include "DataFormatsTRD/Constants.h" +#include "TRDBase/Garfield.h" namespace o2 { namespace trd { -class PadPlane; - class CommonParam { public: enum { kXenon = 0, kArgon = 1 }; - CommonParam(const CommonParam& p); - CommonParam& operator=(const CommonParam& p); - ~CommonParam(); - - static CommonParam* Instance(); - static void Terminate(); + CommonParam(const CommonParam&) = delete; + CommonParam& operator=(const CommonParam&) = delete; + ~CommonParam() = default; - void SetExB(int exbOn = 1) { mExBOn = exbOn; } - void SetSamplingFrequency(float freq) { mSamplingFrequency = freq; } - void SetXenon(); - void SetArgon(); + static CommonParam* instance(); - bool ExBOn() const { return mExBOn; } - bool IsXenon() const { return (mGasMixture == kXenon); } - bool IsArgon() const { return (mGasMixture == kArgon); } - int GetGasMixture() const { return mGasMixture; } - float GetSamplingFrequency() const { return mSamplingFrequency; } - float GetCachedField() const { return mField; } + void setExB(bool flag = true) { mExBOn = flag; } + void setSamplingFrequency(float freq) { mSamplingFrequency = freq; } + void setXenon(); + void setArgon(); - // Cached magnetic field, to be called by the user before using GetDiffCoeff or GetOmegaTau - bool cacheMagField(); - float GetOmegaTau(float vdrift); - bool GetDiffCoeff(float& dl, float& dt, float vdrift); + bool isExBOn() const { return mExBOn; } + bool isXenon() const { return (mGasMixture == kXenon); } + bool isArgon() const { return (mGasMixture == kArgon); } + int getGasMixture() const { return mGasMixture; } + float getSamplingFrequency() const { return mSamplingFrequency; } + float getCachedField() const { return mField; } - double TimeStruct(float vdrift, double xd, double z); + // Cached magnetic field, to be called by the user before using DiffusionAndTimeStructEstimator::GetDiffCoeff + void cacheMagField(); protected: - void SampleTimeStruct(float vdrift); -#ifndef GPUCA_GPUCODE_DEVICE - static CommonParam* fgInstance; // Instance of this class (singleton implementation) - static bool fgTerminated; // Defines if this class has already been terminated -#endif - int mExBOn; // Switch for the ExB effects - double mField; // cached magnetic field - float mDiffusionT; // Transverse drift coefficient - float mDiffusionL; // Longitudinal drift coefficient - float mDiffLastVdrift; // The structures are valid for fLastVdrift (caching) + static CommonParam* mgInstance; ///< Instance of this class (singleton implementation) + bool mExBOn{true}; ///< Switch for the ExB effects + double mField{-0.5}; ///< Cached magnetic field + float mDiffusionT{0.}; ///< Transverse drift coefficient + float mDiffusionL{0.}; ///< Longitudinal drift coefficient + float mDiffLastVdrift{-1.}; ///< The structures are valid for fLastVdrift (caching) - float* mTimeStruct1; //! Time Structure of Drift Cells - float* mTimeStruct2; //! Time Structure of Drift Cells - float mVDlo; // Lower drift velocity, for interpolation - float mVDhi; // Higher drift velocity, for interpolation - float mTimeLastVdrift; // The structures are valid for fLastVdrift (caching) + std::array<float, garfield::TIMEBINSGARFIELD * garfield::ZBINSGARFIELD> mTimeStruct1{}; ///< Time Structure of Drift Cells + std::array<float, garfield::TIMEBINSGARFIELD * garfield::ZBINSGARFIELD> mTimeStruct2{}; ///< Time Structure of Drift Cells + float mVDlo{0.}; ///< Lower drift velocity, for interpolation + float mVDhi{0.}; ///< Higher drift velocity, for interpolation + float mTimeLastVdrift{-1.}; ///< The structures are valid for fLastVdrift (caching) - float mSamplingFrequency; // Sampling Frequency in MHz + float mSamplingFrequency{10.}; ///< Sampling Frequency in MHz - int mGasMixture; // Gas mixture: 0-Xe/C02 1-Ar/CO2. + int mGasMixture{kXenon}; ///< Gas mixture: 0-Xe/C02 1-Ar/CO2. private: - // This is a singleton, constructor is private! - CommonParam(); + /// This is a singleton, constructor is private! + CommonParam() = default; - ClassDef(CommonParam, 1); // The constant parameters common to simulation and reconstruction + ClassDefNV(CommonParam, 1); // The constant parameters common to simulation and reconstruction }; } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/base/include/TRDBase/DiffAndTimeStructEstimator.h b/Detectors/TRD/base/include/TRDBase/DiffAndTimeStructEstimator.h index 33f339ec6e3e1..8499ed4b74599 100644 --- a/Detectors/TRD/base/include/TRDBase/DiffAndTimeStructEstimator.h +++ b/Detectors/TRD/base/include/TRDBase/DiffAndTimeStructEstimator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,15 +13,14 @@ #define O2_TRD_DIFFANDTIMESTRUCTESTIMATOR_H #include <array> +#include "DataFormatsTRD/Constants.h" +#include "TRDBase/Garfield.h" namespace o2 { namespace trd { -// CONTANT TIME STRUCTURE DATA FROM GARFIELD -constexpr int ktimebin = 38; -constexpr int kZbin = 11; /// A class to calculate diffusion and time structure values (GARFIELD model) /// (used in digitization). Class was split off trom CommonParam @@ -31,20 +31,20 @@ class DiffusionAndTimeStructEstimator DiffusionAndTimeStructEstimator() = default; /// determines the diffusion coefficients as a function of drift velocity - bool GetDiffCoeff(float& dl, float& dt, float vdrift); + bool getDiffCoeff(float& dl, float& dt, float vdrift); /// determines drift time as function of drift velocity and coordinates - float TimeStruct(float vdrift, float xd, float z); + float timeStruct(float vdrift, float xd, float z, bool* errFlag = nullptr); private: - void SampleTimeStruct(float vdrift); - - std::array<float, ktimebin * kZbin> mTimeStruct1; //! cached Time Structure of Drift Cells (for last vdrift value) - std::array<float, ktimebin * kZbin> mTimeStruct2; //! cached Time Structure of Drift Cells (for last vdrift value) - float mVDlo; //! Lower drift velocity, for interpolation - float mVDhi; //! Higher drift velocity, for interpolation - float mInvBinWidth; //! caching 1/(mVDhi - mVDlo) - float mTimeLastVdrift = -1.f; //! The structures are valid for this mLastVdrift (caching) + bool sampleTimeStruct(float vdrift); + + std::array<float, garfield::TIMEBINSGARFIELD * garfield::ZBINSGARFIELD> mTimeStruct1; ///< cached Time Structure of Drift Cells (for last vdrift value) + std::array<float, garfield::TIMEBINSGARFIELD * garfield::ZBINSGARFIELD> mTimeStruct2; ///< cached Time Structure of Drift Cells (for last vdrift value) + float mVDlo; ///< Lower drift velocity, for interpolation + float mVDhi; ///< Higher drift velocity, for interpolation + float mInvBinWidth; ///< caching 1/(mVDhi - mVDlo) + float mTimeLastVdrift = -1.f; ///< The structures are valid for this mLastVdrift (caching) // for the diffusion part float mDiffLastVdrift = -1.f; diff --git a/Detectors/TRD/base/include/TRDBase/Digit.h b/Detectors/TRD/base/include/TRDBase/Digit.h deleted file mode 100644 index d76ed2445139b..0000000000000 --- a/Detectors/TRD/base/include/TRDBase/Digit.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_TRD_DIGIT_H_ -#define ALICEO2_TRD_DIGIT_H_ - -#include <cstdint> -#include <vector> -#include <array> -#include <unordered_map> -#include <numeric> -#include "Rtypes.h" // for ClassDef - -#include "CommonDataFormat/TimeStamp.h" -#include "TRDBase/CommonParam.h" -#include "DataFormatsTRD/Constants.h" - -namespace o2 -{ -namespace trd -{ - -using ADC_t = std::uint16_t; -using ArrayADC = std::array<ADC_t, constants::TIMEBINS>; - -using TimeStamp = o2::dataformats::TimeStamp<double>; - -class Digit : public TimeStamp -{ - public: - Digit() = default; - ~Digit() = default; - Digit(const int det, const int row, const int pad, const ArrayADC adc, double t) - : mDetector(det), mRow(row), mPad(pad), mADC(adc), TimeStamp(t) {} - // Copy - Digit(const Digit&) = default; - // Assignment - Digit& operator=(const Digit&) = default; - // Modifiers - void setDetector(int det) { mDetector = det; } - void setRow(int row) { mRow = row; } - void setPad(int pad) { mPad = pad; } - void setADC(ArrayADC const& adc) { mADC = adc; } - // Get methods - int getDetector() const { return mDetector; } - int getRow() const { return mRow; } - int getPad() const { return mPad; } - ArrayADC const& getADC() const { return mADC; } - ADC_t getADCsum() const { return std::accumulate(mADC.begin(), mADC.end(), (ADC_t)0); } - - private: - std::uint16_t mDetector{0}; // TRD detector number, 0-539 - std::uint8_t mRow{0}; // pad row, 0-15 - std::uint8_t mPad{0}; // pad within pad row, 0-143 - ArrayADC mADC{}; // ADC vector (30 time-bins) - ClassDefNV(Digit, 2); -}; - -} // namespace trd -} // namespace o2 - -#endif diff --git a/Detectors/TRD/base/include/TRDBase/FeeParam.h b/Detectors/TRD/base/include/TRDBase/FeeParam.h index 5e16d67b1aa7e..a8f9af75cb456 100644 --- a/Detectors/TRD/base/include/TRDBase/FeeParam.h +++ b/Detectors/TRD/base/include/TRDBase/FeeParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,9 +32,6 @@ #include <array> #include <vector> -class CommonParam; -class PadPlane; -class Geometry; namespace o2 { @@ -44,24 +42,22 @@ class FeeParam { public: - FeeParam(const FeeParam& p); - virtual ~FeeParam(); - FeeParam& operator=(const FeeParam& p); - virtual void Copy(FeeParam& p) const; + ~FeeParam() = default; + FeeParam(const FeeParam&) = delete; + FeeParam& operator=(const FeeParam&) = delete; static FeeParam* instance(); // Singleton - static void terminate(); // Translation from MCM to Pad and vice versa - virtual int getPadRowFromMCM(int irob, int imcm) const; - virtual int getPadColFromADC(int irob, int imcm, int iadc) const; - virtual int getExtendedPadColFromADC(int irob, int imcm, int iadc) const; - virtual int getMCMfromPad(int irow, int icol) const; - virtual int getMCMfromSharedPad(int irow, int icol) const; - virtual int getROBfromPad(int irow, int icol) const; - virtual int getROBfromSharedPad(int irow, int icol) const; - virtual int getRobSide(int irob) const; - virtual int getColSide(int icol) const; + static int getPadRowFromMCM(int irob, int imcm); + static int getPadColFromADC(int irob, int imcm, int iadc); + static int getExtendedPadColFromADC(int irob, int imcm, int iadc); + static int getMCMfromPad(int irow, int icol); + static int getMCMfromSharedPad(int irow, int icol); + static int getROBfromPad(int irow, int icol); + static int getROBfromSharedPad(int irow, int icol); + static int getROBSide(int irob); + static int getColSide(int icol); // SCSN-related static unsigned int aliToExtAli(int rob, int aliid); // Converts the MCM-ROB combination to the extended MCM ALICE ID (used to address MCMs on the SCSN Bus) @@ -70,27 +66,28 @@ class FeeParam static short getRobAB(unsigned short robsel, unsigned short linkpair); // Returns the chamber side (A=0, B=0) of a ROB // wiring - virtual int getORI(int detector, int readoutboard) const; - virtual int getORIinSM(int detector, int readoutboard) const; - // virtual void createORILookUpTable(); - virtual int getORIfromHCID(int hcid) const; - virtual int getHCIDfromORI(int ori, int readoutboard) const; // TODO we need more info than just ori, for now readoutboard is there ... might change + static int getORI(int detector, int readoutboard); + static void unpackORI(int link, int side, int& stack, int& layer, int& halfchamberside); + // void createORILookUpTable(); + static int getORIinSuperModule(int detector, int readoutboard); + static int getLinkIDfromHCID(int hcid); + static int getHCIDfromORI(int ori, int readoutboard); // TODO we need more info than just ori, for now readoutboard is there ... might change // tracklet simulation - bool getTracklet() const { return mgTracklet; } - static void setTracklet(bool trackletSim = true) { mgTracklet = trackletSim; } - bool getRejectMultipleTracklets() const { return mgRejectMultipleTracklets; } - static void setRejectMultipleTracklets(bool rej = true) { mgRejectMultipleTracklets = rej; } - bool getUseMisalignCorr() const { return mgUseMisalignCorr; } - static void setUseMisalignCorr(bool misalign = true) { mgUseMisalignCorr = misalign; } - bool getUseTimeOffset() const { return mgUseTimeOffset; } - static void setUseTimeOffset(bool timeOffset = true) { mgUseTimeOffset = timeOffset; } + bool getTracklet() const { return mTracklet; } + void setTracklet(bool trackletSim = true) { mTracklet = trackletSim; } + bool getRejectMultipleTracklets() const { return mRejectMultipleTracklets; } + void setRejectMultipleTracklets(bool rej = true) { mRejectMultipleTracklets = rej; } + bool getUseMisalignCorr() const { return mUseMisalignCorr; } + void setUseMisalignCorr(bool misalign = true) { mUseMisalignCorr = misalign; } + bool getUseTimeOffset() const { return mUseTimeOffset; } + void setUseTimeOffset(bool timeOffset = true) { mUseTimeOffset = timeOffset; } // Concerning raw data format int getRAWversion() const { return mRAWversion; } void setRAWversion(int rawver); - inline short padMcmLUT(int index) { return mgLUTPadNumbering[index]; } + short padMcmLUT(int index) { return mLUTPadNumbering[index]; } // configuration settings // called with special SCSN commands @@ -138,56 +135,59 @@ class FeeParam protected: static FeeParam* mgInstance; // Singleton instance - static bool mgTerminated; // Defines if this class has already been terminated - CommonParam* mCP = nullptr; // TRD common parameters class + std::array<short, constants::NCOLUMN> mLUTPadNumbering; // Lookup table mapping Pad to MCM - static std::vector<short> mgLUTPadNumbering; // Lookup table mapping Pad to MCM - static bool mgLUTPadNumberingFilled; // Lookup table mapping Pad to MCM - - void createPad2MCMLookUpTable(); + void fillPad2MCMLookUpTable(); // Tracklet processing on/off - static bool mgTracklet; // tracklet processing - static bool mgRejectMultipleTracklets; // only accept best tracklet if found more than once - static bool mgUseMisalignCorr; // add correction for mis-alignment in y - static bool mgUseTimeOffset; // add time offset in calculation of fit sums + bool mTracklet{true}; // tracklet processing + bool mRejectMultipleTracklets{false}; // only accept best tracklet if found more than once + bool mUseMisalignCorr{false}; // add correction for mis-alignment in y + bool mUseTimeOffset{false}; // add time offset in calculation of fit sums // For raw production int mRAWversion{3}; // Raw data production version - static const int mgkMaxRAWversion = 3; // Maximum raw version number supported + const int mkMaxRAWversion = 3; // Maximum raw version number supported // geometry constants - static std::array<float, constants::NCHAMBERPERSEC> mgZrow; // z-position of pad row edge 6x5 - static std::array<float, constants::NLAYER> mgX; // x-position for all layers - static std::array<float, constants::NLAYER> mgInvX; // inverse x-position for all layers (to remove divisions) - static std::array<float, constants::NLAYER> mgTiltingAngle; // tilting angle for every layer - static std::array<float, constants::NLAYER> mgTiltingAngleTan; // tan of tilting angle for every layer (look up table to avoid tan calculations) - static std::array<float, constants::NLAYER> mgWidthPad; // pad width for all layers - static std::array<float, constants::NLAYER> mgInvWidthPad; // inverse pad width for all layers (to remove divisions) - static float mgLengthInnerPadC0; // inner pad length C0 chamber - static float mgLengthOuterPadC0; // outer pad length C0 chamber - static std::array<float, constants::NLAYER> mgLengthInnerPadC1; // inner pad length C1 chambers - static std::array<float, constants::NLAYER> mgLengthOuterPadC1; // outer pad length C1 chambers - static float mgScalePad; // scaling factor for pad width - static float mgDriftLength; // length of the parse gaintbl Krypton_2009-01 drift region - static float mgBinDy; // bin in dy (140 um) - static int mgDyMax; // max dy for a tracklet (hard limit) - static int mgDyMin; // min dy for a tracklet (hard limit) - //std::array<int,30> mgAsideLUT; // A side LUT to map ORI to stack/layer/side - //std::array<int,30> mgCsideLUT; // C side LUT to map ORI to stack/layer/side + std::array<float, constants::NCHAMBERPERSEC> mZrow{// z-position of pad row edge 6x5 + 301, 177, 53, -57, -181, + 301, 177, 53, -57, -181, + 315, 184, 53, -57, -188, + 329, 191, 53, -57, -195, + 343, 198, 53, -57, -202, + 347, 200, 53, -57, -204}; + std::array<float, constants::NLAYER> mX{300.65, 313.25, 325.85, 338.45, 351.05, 363.65}; // x-position for all layers + std::array<float, constants::NLAYER> mInvX; // inverse x-position for all layers (to remove divisions) + std::array<float, constants::NLAYER> mTiltingAngle{-2., 2., -2., 2., -2., 2.}; // tilting angle for every layer + std::array<float, constants::NLAYER> mTiltingAngleTan; // tan of tilting angle for every layer (look up table to avoid tan calculations) + std::array<float, constants::NLAYER> mWidthPad{0.635, 0.665, 0.695, 0.725, 0.755, 0.785}; // pad width for all layers + std::array<float, constants::NLAYER> mInvWidthPad; // inverse pad width for all layers (to remove divisions) + float mLengthInnerPadC0{9.f}; // inner pad length C0 chamber + float mLengthOuterPadC0{8.f}; // outer pad length C0 chamber + std::array<float, constants::NLAYER> mLengthInnerPadC1{7.5, 7.5, 8.0, 8.5, 9.0, 9.0}; // inner pad length C1 chambers + std::array<float, constants::NLAYER> mLengthOuterPadC1{7.5, 7.5, 7.5, 7.5, 7.5, 8.5}; // outer pad length C1 chambers + float mScalePad{256. * 32.}; // scaling factor for pad width + float mDriftLength{3.}; // length of the parse gaintbl Krypton_2009-01 drift region + // WARNING: This values for dY are valid for Run 1+2 format only + float mBinDy{140e-4}; // bin in dy (140 um) + int mDyMax{63}; // max dy for a tracklet (hard limit) + int mDyMin{-64}; // min dy for a tracklet (hard limit) + //std::array<int,30> mAsideLUT; // A side LUT to map ORI to stack/layer/side + //std::array<int,30> mCsideLUT; // C side LUT to map ORI to stack/layer/side // settings - float mMagField; // magnetic field - float mOmegaTau; // omega tau, i.e. tan(Lorentz angle) - float mPtMin; // min. pt for deflection cut - float mInvPtMin; // min. pt for deflection cut (Inverted to remove division) - int mNtimebins; // drift time in units of timebins << 5n - unsigned int mScaleQ0; // scale factor for accumulated charge Q0 - unsigned int mScaleQ1; // scale factor for accumulated charge Q1 - bool mPidTracklengthCorr; // enable tracklet length correction - bool mTiltCorr; // enable tilt correction - bool mPidGainCorr; // enable MCM gain correction factor for PID + float mMagField{0.f}; // magnetic field + float mOmegaTau{0.f}; // omega tau, i.e. tan(Lorentz angle) + float mPtMin{.1f}; // min. pt for deflection cut + float mInvPtMin{1.f / mPtMin}; // min. pt for deflection cut (Inverted to remove division) + int mNtimebins{20 << 5}; // drift time in units of timebins << 5n + unsigned int mScaleQ0{0}; // scale factor for accumulated charge Q0 + unsigned int mScaleQ1{0}; // scale factor for accumulated charge Q1 + bool mPidTracklengthCorr{false}; // enable tracklet length correction + bool mTiltCorr{false}; // enable tilt correction + bool mPidGainCorr{false}; // enable MCM gain correction factor for PID private: FeeParam(); diff --git a/Detectors/TRD/base/include/TRDBase/Garfield.h b/Detectors/TRD/base/include/TRDBase/Garfield.h new file mode 100644 index 0000000000000..fafa794ef11c4 --- /dev/null +++ b/Detectors/TRD/base/include/TRDBase/Garfield.h @@ -0,0 +1,349 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_GARFIELD_H +#define O2_TRD_GARFIELD_H + +namespace o2 +{ +namespace trd +{ +namespace garfield +{ + +constexpr int TIMEBINSGARFIELD = 38; // Number of bins in time direction used for garfield simulation +constexpr int ZBINSGARFIELD = 11; // Number of bins in z direction used for garfield simulation + +// Garfield simulation at UD = -1500V; vd = 1.032cm/microsec, <driftfield> = 525V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time1500{{{{0.09170, 0.09205, 0.09306, 0.09475, 0.09716, 0.10035, 0.10445, 0.10993, 0.11838, 0.13986, 0.37858}}, + {{0.06588, 0.06626, 0.06739, 0.06926, 0.07186, 0.07524, 0.07951, 0.08515, 0.09381, 0.11601, 0.35673}}, + {{0.03946, 0.04003, 0.04171, 0.04435, 0.04780, 0.05193, 0.05680, 0.06306, 0.07290, 0.09873, 0.34748}}, + {{0.01151, 0.01283, 0.01718, 0.02282, 0.02880, 0.03479, 0.04098, 0.04910, 0.06413, 0.10567, 0.36897}}, + {{0.01116, 0.01290, 0.01721, 0.02299, 0.02863, 0.03447, 0.04074, 0.04984, 0.06839, 0.11625, 0.37277}}, + {{0.03919, 0.03974, 0.04131, 0.04380, 0.04703, 0.05102, 0.05602, 0.06309, 0.07651, 0.10938, 0.36838}}, + {{0.06493, 0.06560, 0.06640, 0.06802, 0.07051, 0.07392, 0.07853, 0.08510, 0.09690, 0.12621, 0.38058}}, + {{0.09174, 0.09186, 0.09225, 0.09303, 0.09477, 0.00000, 0.11205, 0.11952, 0.13461, 0.16984, 0.43017}}, + {{0.14356, 0.14494, 0.14959, 0.16002, 0.18328, 0.27981, 0.22785, 0.21240, 0.21948, 0.25965, 0.52392}}, + {{0.23120, 0.23366, 0.24046, 0.25422, 0.28071, 0.36914, 0.32999, 0.31208, 0.31772, 0.35804, 0.62249}}, + {{0.32686, 0.32916, 0.33646, 0.35053, 0.37710, 0.46292, 0.42773, 0.40948, 0.41497, 0.45527, 0.71955}}, + {{0.42353, 0.42583, 0.43317, 0.44727, 0.47380, 0.55884, 0.52479, 0.50650, 0.51194, 0.55225, 0.81658}}, + {{0.52038, 0.52271, 0.53000, 0.54415, 0.57064, 0.65545, 0.62172, 0.60341, 0.60885, 0.64915, 0.91339}}, + {{0.61724, 0.61953, 0.62694, 0.64098, 0.66756, 0.75226, 0.71862, 0.70030, 0.70575, 0.74604, 1.01035}}, + {{0.71460, 0.71678, 0.72376, 0.73786, 0.76447, 0.84913, 0.81551, 0.79720, 0.80264, 0.84292, 1.10723}}, + {{0.81101, 0.81334, 0.82066, 0.83475, 0.86127, 0.94599, 0.91240, 0.89408, 0.89952, 0.93981, 1.20409}}, + {{0.90788, 0.91023, 0.91752, 0.93163, 0.95815, 1.04293, 1.00929, 0.99096, 0.99640, 1.03669, 1.30106}}, + {{1.00477, 1.00707, 1.01449, 1.02852, 1.05504, 1.13976, 1.10617, 1.08784, 1.09329, 1.13358, 1.39796}}, + {{1.10166, 1.10397, 1.11130, 1.12541, 1.15257, 1.23672, 1.20307, 1.18472, 1.19018, 1.23046, 1.49486}}, + {{1.19854, 1.20084, 1.20818, 1.22235, 1.24885, 1.33355, 1.29992, 1.28156, 1.28707, 1.32735, 1.59177}}, + {{1.29544, 1.29780, 1.30507, 1.31917, 1.34575, 1.43073, 1.39681, 1.37851, 1.38396, 1.42377, 1.68854}}, + {{1.39236, 1.39462, 1.40205, 1.41607, 1.44259, 1.52745, 1.49368, 1.47541, 1.48083, 1.52112, 1.78546}}, + {{1.49314, 1.49149, 1.49885, 1.51297, 1.53949, 1.62420, 1.59016, 1.57231, 1.57772, 1.61800, 1.88048}}, + {{1.58610, 1.58839, 1.59572, 1.60983, 1.63635, 1.72109, 1.68651, 1.66921, 1.67463, 1.71489, 1.97918}}, + {{1.68400, 1.68529, 1.69261, 1.70671, 1.73331, 1.81830, 1.78341, 1.76605, 1.77150, 1.81179, 2.07608}}, + {{1.77991, 1.78215, 1.78952, 1.80385, 1.83014, 1.91486, 1.88128, 1.86215, 1.86837, 1.90865, 2.17304}}, + {{1.87674, 1.87904, 1.88647, 1.90052, 1.92712, 2.01173, 1.97812, 1.95905, 1.96527, 2.00710, 2.26979}}, + {{1.97369, 1.97594, 1.98326, 1.99869, 2.02442, 2.10865, 2.07501, 2.05666, 2.06214, 2.10243, 2.36669}}, + {{2.07052, 2.07281, 2.08016, 2.09425, 2.12132, 2.20555, 2.17182, 2.15341, 2.15904, 2.19933, 2.46363}}, + {{2.16742, 2.16971, 2.17707, 2.19114, 2.21766, 2.30240, 2.26877, 2.25015, 2.25573, 2.29586, 2.56060}}, + {{2.26423, 2.26659, 2.27396, 2.28803, 2.31456, 2.40828, 2.36567, 2.34705, 2.35282, 2.39765, 2.65744}}, + {{2.36153, 2.36349, 2.37330, 2.38501, 2.41159, 2.49940, 2.46257, 2.44420, 2.44843, 2.48987, 2.75431}}, + {{2.46558, 2.46035, 2.46822, 2.48181, 2.50849, 2.59630, 2.55947, 2.54112, 2.54513, 2.58677, 2.85094}}, + {{2.56248, 2.55723, 2.56486, 2.57871, 2.60520, 2.68998, 2.65626, 2.63790, 2.64316, 2.68360, 2.94813}}, + {{2.65178, 2.65441, 2.66153, 2.67556, 2.70210, 2.78687, 2.75319, 2.73463, 2.74032, 2.78060, 3.04503}}, + {{2.74868, 2.75131, 2.75870, 2.77245, 2.79385, 2.88700, 2.85009, 2.83177, 2.83723, 2.87750, 3.14193}}, + {{2.84574, 2.84789, 2.85560, 2.86935, 2.89075, 2.98060, 2.94576, 2.92868, 2.93356, 2.97436, 3.23868}}, + {{2.94239, 2.94469, 2.95221, 2.96625, 2.99345, 3.07747, 3.04266, 3.02545, 3.03051, 3.07118, 3.33555}}}}; + +// Garfield simulation at UD = -1600V; vd = 1.158cm/microsec, <driftfield> = 558V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time1600{{{{0.09169, 0.09203, 0.09305, 0.09473, 0.09714, 0.10032, 0.10441, 0.10990, 0.11835, 0.13986, 0.37845}}, + {{0.06589, 0.06626, 0.06738, 0.06924, 0.07184, 0.07521, 0.07947, 0.08512, 0.09379, 0.11603, 0.35648}}, + {{0.03947, 0.04003, 0.04171, 0.04434, 0.04778, 0.05190, 0.05678, 0.06304, 0.07292, 0.09876, 0.34759}}, + {{0.01111, 0.01281, 0.01718, 0.02281, 0.02879, 0.03477, 0.04097, 0.04910, 0.06415, 0.10573, 0.36896}}, + {{0.01120, 0.01311, 0.01721, 0.02279, 0.02862, 0.03446, 0.04074, 0.04981, 0.06825, 0.11595, 0.37255}}, + {{0.03919, 0.03980, 0.04132, 0.04380, 0.04704, 0.05102, 0.05602, 0.06302, 0.07633, 0.10896, 0.36743}}, + {{0.06531, 0.06528, 0.06631, 0.06805, 0.07053, 0.07392, 0.07853, 0.08505, 0.09669, 0.12578, 0.37967}}, + {{0.09157, 0.09171, 0.09216, 0.09301, 0.09475, 0.00000, 0.11152, 0.11879, 0.13352, 0.16802, 0.42750}}, + {{0.13977, 0.14095, 0.14509, 0.15433, 0.17534, 0.26406, 0.21660, 0.20345, 0.21113, 0.25067, 0.51434}}, + {{0.21816, 0.22041, 0.22631, 0.23850, 0.26208, 0.34340, 0.30755, 0.29237, 0.29878, 0.33863, 0.60258}}, + {{0.30344, 0.30547, 0.31241, 0.32444, 0.34809, 0.42696, 0.39464, 0.37919, 0.38546, 0.42530, 0.68926}}, + {{0.38969, 0.39164, 0.39810, 0.41059, 0.43441, 0.51246, 0.48112, 0.46562, 0.47191, 0.51172, 0.77558}}, + {{0.47592, 0.47799, 0.48442, 0.49689, 0.52061, 0.59855, 0.56752, 0.55201, 0.55826, 0.59808, 0.86202}}, + {{0.56226, 0.56428, 0.57074, 0.58324, 0.60696, 0.68483, 0.65388, 0.63837, 0.64461, 0.68445, 0.94830}}, + {{0.64881, 0.65063, 0.65709, 0.66958, 0.69331, 0.77117, 0.74023, 0.72472, 0.73098, 0.77079, 1.03486}}, + {{0.73506, 0.73698, 0.74344, 0.75596, 0.77964, 0.85751, 0.82658, 0.81107, 0.81731, 0.85712, 1.12106}}, + {{0.82132, 0.82333, 0.82979, 0.84228, 0.86608, 0.94386, 0.91293, 0.89742, 0.90367, 0.94335, 1.20737}}, + {{0.90767, 0.90968, 0.91614, 0.92863, 0.95236, 1.03021, 0.99928, 0.98377, 0.99001, 1.02984, 1.29371}}, + {{0.99410, 0.99602, 1.00257, 1.01498, 1.03869, 1.11720, 1.08563, 1.07011, 1.07637, 1.11621, 1.37873}}, + {{1.08036, 1.08240, 1.08884, 1.10138, 1.12504, 1.20301, 1.17198, 1.15647, 1.16272, 1.20255, 1.46651}}, + {{1.16670, 1.16872, 1.17525, 1.18783, 1.21139, 1.28934, 1.25833, 1.24281, 1.24909, 1.28889, 1.55275}}, + {{1.25307, 1.25510, 1.26153, 1.27404, 1.29773, 1.37584, 1.34469, 1.32916, 1.33536, 1.37524, 1.63915}}, + {{1.33942, 1.34146, 1.34788, 1.36040, 1.38410, 1.46438, 1.43105, 1.41537, 1.42176, 1.46158, 1.72538}}, + {{1.42579, 1.42782, 1.43458, 1.44674, 1.47043, 1.55085, 1.51675, 1.50168, 1.50810, 1.54793, 1.81174}}, + {{1.51207, 1.51454, 1.52060, 1.53307, 1.55684, 1.63478, 1.60336, 1.58820, 1.59446, 1.63414, 1.89814}}, + {{1.59856, 1.60047, 1.60693, 1.61942, 1.64317, 1.72257, 1.69008, 1.67454, 1.68080, 1.72063, 1.98433}}, + {{1.68481, 1.68682, 1.69330, 1.70584, 1.72949, 1.80752, 1.77643, 1.76089, 1.76716, 1.80692, 2.07069}}, + {{1.77117, 1.77319, 1.77969, 1.79260, 1.81583, 1.89376, 1.86226, 1.84720, 1.85355, 1.89256, 2.15343}}, + {{1.85748, 1.85967, 1.86605, 1.87848, 1.90222, 1.98010, 1.94913, 1.93271, 1.93981, 1.97968, 2.24355}}, + {{1.94386, 1.94587, 1.95233, 1.96484, 1.98854, 2.06646, 2.03542, 2.01755, 2.02617, 2.06604, 2.32993}}, + {{2.03022, 2.03230, 2.03868, 2.05134, 2.07488, 2.15367, 2.12178, 2.10391, 2.11252, 2.15432, 2.41623}}, + {{2.11656, 2.11857, 2.12505, 2.13772, 2.16147, 2.23919, 2.20817, 2.19265, 2.20744, 2.23872, 2.49996}}, + {{2.20291, 2.20611, 2.21137, 2.22387, 2.24758, 2.32563, 2.29450, 2.27901, 2.28525, 2.32507, 2.58897}}, + {{2.28922, 2.29172, 2.29774, 2.31345, 2.33400, 2.41287, 2.38086, 2.36535, 2.37160, 2.40869, 2.67113}}, + {{2.37572, 2.37764, 2.38410, 2.39803, 2.42046, 2.49817, 2.46721, 2.45171, 2.45794, 2.49505, 2.76061}}, + {{2.46190, 2.46396, 2.47043, 2.48340, 2.50665, 2.58453, 2.55357, 2.53728, 2.54430, 2.58407, 2.84816}}, + {{2.54833, 2.55032, 2.55679, 2.56976, 2.59312, 2.67103, 2.63993, 2.62364, 2.63062, 2.67040, 2.93444}}, + {{2.63456, 2.63660, 2.64304, 2.65555, 2.67938, 2.75739, 2.72629, 2.71064, 2.71688, 2.75671, 3.01886}}}}; + +// Garfield simulation at UD = -1700V; vd = 1.299cm/microsec, <driftfield> = 590V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time1700{{{{0.09167, 0.09201, 0.09302, 0.09471, 0.09712, 0.10029, 0.10438, 0.10986, 0.11832, 0.13986, 0.37824}}, + {{0.06591, 0.06626, 0.06736, 0.06923, 0.07183, 0.07519, 0.07944, 0.08511, 0.09378, 0.11603, 0.35625}}, + {{0.03946, 0.04003, 0.04170, 0.04433, 0.04777, 0.05189, 0.05676, 0.06301, 0.07291, 0.09880, 0.34724}}, + {{0.01110, 0.01281, 0.01718, 0.02280, 0.02879, 0.03476, 0.04096, 0.04910, 0.06417, 0.10582, 0.36861}}, + {{0.01115, 0.01294, 0.01721, 0.02276, 0.02862, 0.03447, 0.04074, 0.04980, 0.06812, 0.11565, 0.37231}}, + {{0.03920, 0.03974, 0.04133, 0.04381, 0.04706, 0.05105, 0.05603, 0.06299, 0.07618, 0.10860, 0.36646}}, + {{0.06498, 0.06529, 0.06634, 0.06808, 0.07055, 0.07395, 0.07852, 0.08500, 0.09650, 0.12532, 0.37850}}, + {{0.09143, 0.09159, 0.09207, 0.09297, 0.09473, 0.00000, 0.11102, 0.11809, 0.13245, 0.16627, 0.42496}}, + {{0.13646, 0.13750, 0.14112, 0.14926, 0.16806, 0.24960, 0.20627, 0.19536, 0.20366, 0.24256, 0.50557}}, + {{0.20678, 0.20848, 0.21384, 0.22450, 0.24552, 0.32018, 0.28740, 0.27477, 0.28196, 0.32128, 0.58475}}, + {{0.28287, 0.28461, 0.29020, 0.30108, 0.32224, 0.39467, 0.36500, 0.35217, 0.35926, 0.39860, 0.66194}}, + {{0.35972, 0.36145, 0.36713, 0.37797, 0.39912, 0.47091, 0.44212, 0.42925, 0.43632, 0.47563, 0.73892}}, + {{0.43667, 0.43841, 0.44413, 0.45494, 0.47607, 0.54780, 0.51912, 0.50627, 0.51334, 0.55254, 0.81595}}, + {{0.51365, 0.51540, 0.52101, 0.53193, 0.55305, 0.62463, 0.59617, 0.58328, 0.59035, 0.62965, 0.89303}}, + {{0.59064, 0.59240, 0.59801, 0.60893, 0.63009, 0.70169, 0.67317, 0.66028, 0.66735, 0.70666, 0.96995}}, + {{0.66765, 0.66939, 0.67501, 0.68592, 0.70724, 0.77863, 0.75016, 0.73728, 0.74435, 0.78366, 1.04696}}, + {{0.74464, 0.74636, 0.75200, 0.76293, 0.78405, 0.85561, 0.82716, 0.81427, 0.82133, 0.86064, 1.12396}}, + {{0.82165, 0.82340, 0.82902, 0.83991, 0.86104, 0.93266, 0.90414, 0.89128, 0.89834, 0.93763, 1.20100}}, + {{0.89863, 0.90042, 0.90659, 0.91705, 0.93805, 1.00960, 0.98115, 0.96825, 0.97533, 1.01462, 1.27801}}, + {{0.97563, 0.97740, 0.98310, 0.99391, 1.01504, 1.08659, 1.05814, 1.04526, 1.05233, 1.09163, 1.35503}}, + {{1.05276, 1.05451, 1.06002, 1.07090, 1.09099, 1.16357, 1.13516, 1.12225, 1.12933, 1.16863, 1.43195}}, + {{1.12977, 1.13138, 1.13700, 1.14792, 1.16797, 1.24061, 1.21212, 1.19926, 1.20626, 1.24554, 1.50900}}, + {{1.20664, 1.20839, 1.21400, 1.22490, 1.24606, 1.31772, 1.28914, 1.27382, 1.28329, 1.32262, 1.58550}}, + {{1.28367, 1.28541, 1.29099, 1.30189, 1.32312, 1.39460, 1.36612, 1.34924, 1.36030, 1.39961, 1.66310}}, + {{1.36064, 1.36249, 1.36799, 1.37896, 1.40004, 1.48030, 1.44314, 1.43032, 1.43731, 1.47659, 1.73442}}, + {{1.43762, 1.43937, 1.44497, 1.45618, 1.47704, 1.54932, 1.52012, 1.50725, 1.51430, 1.55357, 1.81708}}, + {{1.51462, 1.51937, 1.52203, 1.53316, 1.55403, 1.62572, 1.59713, 1.58424, 1.59128, 1.63061, 1.89406}}, + {{1.59162, 1.59338, 1.59947, 1.60989, 1.63103, 1.70270, 1.67411, 1.66124, 1.66799, 1.70759, 1.97103}}, + {{1.66874, 1.67037, 1.67597, 1.68687, 1.70814, 1.77969, 1.75112, 1.73806, 1.74530, 1.78457, 2.04794}}, + {{1.74693, 1.74749, 1.75297, 1.76476, 1.78500, 1.85667, 1.82811, 1.81504, 1.82101, 1.86161, 2.12492}}, + {{1.82260, 1.82437, 1.82995, 1.84174, 1.86202, 1.93372, 1.90509, 1.89202, 1.89930, 1.93859, 2.20189}}, + {{1.89964, 1.90135, 1.90693, 1.91789, 1.93952, 2.01080, 1.98207, 1.96921, 1.97628, 2.01384, 2.27887}}, + {{1.97662, 1.97917, 1.98611, 1.99487, 2.01601, 2.08778, 2.05846, 2.04623, 2.05330, 2.09244, 2.35585}}, + {{2.05359, 2.05615, 2.06309, 2.07187, 2.09867, 2.16459, 2.13610, 2.12322, 2.13029, 2.16942, 2.43199}}, + {{2.13063, 2.13233, 2.13795, 2.14886, 2.17008, 2.24199, 2.21310, 2.20020, 2.20727, 2.24659, 2.50983}}, + {{2.20761, 2.20931, 2.21955, 2.22624, 2.24708, 2.32147, 2.29009, 2.27725, 2.28276, 2.32359, 2.58680}}, + {{2.28459, 2.29108, 2.29202, 2.30286, 2.32007, 2.39559, 2.36683, 2.35422, 2.36119, 2.40058, 2.66081}}, + {{2.36153, 2.36806, 2.36889, 2.37985, 2.40092, 2.47828, 2.44381, 2.43099, 2.43819, 2.47750, 2.73779}}}}; + +// Garfield simulation at UD = -1800V; vd = 1.450cm/microsec, <driftfield> = 623V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time1800{{{{0.09166, 0.09199, 0.09300, 0.09470, 0.09709, 0.10026, 0.10434, 0.10983, 0.11831, 0.13987, 0.37802}}, + {{0.06585, 0.06623, 0.06735, 0.06921, 0.07180, 0.07520, 0.07941, 0.08507, 0.09376, 0.11604, 0.35624}}, + {{0.03945, 0.04004, 0.04169, 0.04432, 0.04776, 0.05187, 0.05674, 0.06300, 0.07290, 0.09884, 0.34704}}, + {{0.01108, 0.01287, 0.01717, 0.02280, 0.02880, 0.03476, 0.04095, 0.04909, 0.06419, 0.10589, 0.36843}}, + {{0.01115, 0.01287, 0.01720, 0.02276, 0.02862, 0.03448, 0.04073, 0.04973, 0.06799, 0.11535, 0.37224}}, + {{0.03918, 0.03975, 0.04134, 0.04382, 0.04707, 0.05105, 0.05603, 0.06296, 0.07605, 0.10822, 0.36560}}, + {{0.06498, 0.06532, 0.06635, 0.06809, 0.07058, 0.07395, 0.07855, 0.08495, 0.09632, 0.12488, 0.37730}}, + {{0.09130, 0.09160, 0.09199, 0.09300, 0.09472, 0.00000, 0.11059, 0.11747, 0.13146, 0.16462, 0.42233}}, + {{0.13364, 0.13449, 0.13767, 0.14481, 0.16147, 0.23635, 0.19706, 0.18812, 0.19704, 0.23520, 0.49749}}, + {{0.19698, 0.19844, 0.20311, 0.21236, 0.23082, 0.29920, 0.26936, 0.25927, 0.26732, 0.30601, 0.56871}}, + {{0.26518, 0.26670, 0.27160, 0.28099, 0.29955, 0.36597, 0.33885, 0.32858, 0.33653, 0.37524, 0.63801}}, + {{0.33441, 0.33553, 0.34040, 0.34987, 0.36841, 0.43428, 0.40797, 0.39763, 0.40556, 0.44425, 0.70698}}, + {{0.40296, 0.40447, 0.40934, 0.41881, 0.43737, 0.50306, 0.47695, 0.46662, 0.47455, 0.51329, 0.77600}}, + {{0.47296, 0.47344, 0.47830, 0.48779, 0.50632, 0.57200, 0.54593, 0.53559, 0.54351, 0.58222, 0.84489}}, + {{0.54089, 0.54264, 0.54727, 0.55673, 0.57529, 0.64094, 0.61490, 0.60457, 0.61249, 0.65118, 0.91394}}, + {{0.60987, 0.61138, 0.61624, 0.62573, 0.64428, 0.70989, 0.68397, 0.67354, 0.68147, 0.72015, 0.98291}}, + {{0.67883, 0.68035, 0.68521, 0.69469, 0.71324, 0.77896, 0.75287, 0.74251, 0.75043, 0.78912, 1.04458}}, + {{0.74780, 0.74932, 0.75421, 0.76367, 0.78221, 0.84785, 0.82185, 0.81148, 0.81941, 0.85811, 1.12085}}, + {{0.81690, 0.81830, 0.82316, 0.83263, 0.85120, 0.91683, 0.89077, 0.88045, 0.88837, 0.92707, 1.18976}}, + {{0.88574, 0.88726, 0.89228, 0.90198, 0.92017, 0.98578, 0.95974, 0.94947, 0.95734, 0.99604, 1.25873}}, + {{0.95493, 0.95624, 0.96110, 0.97058, 0.98913, 1.05481, 1.02873, 1.01839, 1.02631, 1.06503, 1.32772}}, + {{1.02392, 1.02524, 1.03008, 1.03955, 1.05810, 1.12378, 1.09757, 1.08605, 1.09530, 1.13399, 1.39669}}, + {{1.09270, 1.09418, 1.09911, 1.10854, 1.12714, 1.19281, 1.16502, 1.15633, 1.16427, 1.20271, 1.46574}}, + {{1.16168, 1.16323, 1.16801, 1.17772, 1.19604, 1.26190, 1.23399, 1.22531, 1.23323, 1.27194, 1.53475}}, + {{1.23061, 1.23214, 1.23698, 1.24669, 1.26503, 1.33073, 1.30461, 1.29428, 1.30220, 1.34091, 1.60372}}, + {{1.29960, 1.30110, 1.30596, 1.31544, 1.33398, 1.39962, 1.37228, 1.36323, 1.37121, 1.40988, 1.67273}}, + {{1.36851, 1.37007, 1.37512, 1.38441, 1.40297, 1.46865, 1.44256, 1.43222, 1.44017, 1.47878, 1.74155}}, + {{1.43752, 1.43904, 1.44773, 1.45338, 1.47220, 1.53759, 1.51136, 1.50119, 1.50914, 1.54775, 1.81050}}, + {{1.50646, 1.50802, 1.51288, 1.52237, 1.54097, 1.60697, 1.58049, 1.57018, 1.57811, 1.61678, 1.87947}}, + {{1.57545, 1.57720, 1.58185, 1.59134, 1.60996, 1.67787, 1.64929, 1.63914, 1.64707, 1.68570, 1.94851}}, + {{1.64442, 1.64617, 1.65081, 1.66035, 1.67893, 1.74684, 1.71826, 1.70745, 1.71604, 1.75310, 2.01748}}, + {{1.71337, 1.71513, 1.71978, 1.72932, 1.74645, 1.81346, 1.78739, 1.77642, 1.78501, 1.82151, 2.08644}}, + {{1.78238, 1.78410, 1.78876, 1.79824, 1.81678, 1.88332, 1.85639, 1.84262, 1.85397, 1.89270, 2.15533}}, + {{1.85135, 1.85306, 1.85778, 1.86728, 1.88580, 1.95615, 1.92536, 1.91171, 1.92283, 1.96165, 2.22428}}, + {{1.92774, 1.92184, 1.92672, 1.93618, 1.95477, 2.02048, 1.99427, 1.98068, 1.99192, 2.03062, 2.29338}}, + {{1.98929, 1.99081, 1.99567, 2.00515, 2.02373, 2.08987, 2.06332, 2.05249, 2.05939, 2.09928, 2.36227}}, + {{2.05829, 2.05978, 2.06464, 2.07414, 2.09272, 2.15850, 2.12928, 2.12194, 2.12987, 2.16825, 2.43083}}, + {{2.12726, 2.12869, 2.13360, 2.14425, 2.16160, 2.22872, 2.20118, 2.19078, 2.19876, 2.23416, 2.50007}}}}; + +// Garfield simulation at UD = -1900V; vd = 1.610cm/microsec, <driftfield> = 655V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time1900{{{{0.09166, 0.09198, 0.09298, 0.09467, 0.09707, 0.10023, 0.10431, 0.10980, 0.11828, 0.13988, 0.37789}}, + {{0.06584, 0.06622, 0.06735, 0.06920, 0.07179, 0.07514, 0.07938, 0.08505, 0.09374, 0.11606, 0.35599}}, + {{0.03945, 0.04002, 0.04169, 0.04432, 0.04775, 0.05185, 0.05672, 0.06298, 0.07290, 0.09888, 0.34695}}, + {{0.01109, 0.01281, 0.01717, 0.02279, 0.02878, 0.03476, 0.04094, 0.04909, 0.06421, 0.10597, 0.36823}}, + {{0.01115, 0.01287, 0.01720, 0.02294, 0.02862, 0.03448, 0.04074, 0.04973, 0.06783, 0.11506, 0.37206}}, + {{0.03940, 0.03975, 0.04135, 0.04386, 0.04708, 0.05106, 0.05604, 0.06293, 0.07592, 0.10787, 0.36484}}, + {{0.06500, 0.06534, 0.06638, 0.06811, 0.07060, 0.07413, 0.07852, 0.08491, 0.09614, 0.12446, 0.37626}}, + {{0.09119, 0.09140, 0.09194, 0.09293, 0.09471, 0.00000, 0.11013, 0.11685, 0.13050, 0.16302, 0.41991}}, + {{0.13111, 0.13190, 0.13466, 0.14091, 0.15554, 0.22409, 0.18846, 0.18167, 0.19113, 0.22854, 0.48995}}, + {{0.18849, 0.18975, 0.19380, 0.20185, 0.21797, 0.28050, 0.25368, 0.24575, 0.25446, 0.29249, 0.55442}}, + {{0.24995, 0.25125, 0.25563, 0.26366, 0.27986, 0.34065, 0.31605, 0.30815, 0.31680, 0.35482, 0.61697}}, + {{0.31187, 0.31324, 0.31745, 0.32580, 0.34205, 0.40217, 0.37825, 0.37031, 0.37897, 0.41696, 0.67890}}, + {{0.37401, 0.37531, 0.37955, 0.38777, 0.40395, 0.46408, 0.44037, 0.43242, 0.44108, 0.47906, 0.74122}}, + {{0.43610, 0.43741, 0.44161, 0.44986, 0.46604, 0.52614, 0.50248, 0.49452, 0.50316, 0.54116, 0.80326}}, + {{0.49820, 0.49988, 0.50372, 0.51196, 0.52814, 0.58822, 0.56459, 0.55661, 0.56527, 0.60326, 0.86526}}, + {{0.56032, 0.56161, 0.56582, 0.57408, 0.59024, 0.65032, 0.62670, 0.61872, 0.62737, 0.66537, 0.92749}}, + {{0.62240, 0.62371, 0.62792, 0.63624, 0.65236, 0.71241, 0.68881, 0.68081, 0.68947, 0.72750, 0.98941}}, + {{0.68449, 0.68581, 0.69002, 0.69828, 0.71444, 0.77452, 0.75089, 0.74295, 0.75157, 0.78957, 1.05157}}, + {{0.74660, 0.74790, 0.75212, 0.76036, 0.77654, 0.83748, 0.81299, 0.80501, 0.81193, 0.85168, 1.11375}}, + {{0.80870, 0.81017, 0.81423, 0.82246, 0.83867, 0.89908, 0.87509, 0.86660, 0.87577, 0.91376, 1.17586}}, + {{0.87080, 0.87233, 0.87632, 0.88458, 0.90074, 0.96083, 0.93718, 0.92922, 0.93787, 0.97588, 1.23794}}, + {{0.93291, 0.93422, 0.93844, 0.94667, 0.96293, 1.02295, 0.99929, 0.99127, 0.99997, 1.03797, 1.29995}}, + {{0.99500, 0.99645, 1.00308, 1.00877, 1.02497, 1.08504, 1.06140, 1.05343, 1.06203, 1.10006, 1.36216}}, + {{1.05712, 1.05926, 1.06262, 1.07092, 1.08706, 1.14754, 1.12350, 1.11550, 1.12417, 1.16218, 1.42427}}, + {{1.11921, 1.12059, 1.12473, 1.13297, 1.14916, 1.21140, 1.18560, 1.17284, 1.18625, 1.22414, 1.48629}}, + {{1.18140, 1.18262, 1.18690, 1.19508, 1.21125, 1.27139, 1.24164, 1.23495, 1.24838, 1.28634, 1.54852}}, + {{1.24340, 1.24473, 1.24901, 1.25732, 1.27336, 1.33358, 1.30793, 1.30179, 1.31047, 1.34848, 1.61066}}, + {{1.30551, 1.30684, 1.31104, 1.32056, 1.33553, 1.39609, 1.37004, 1.36392, 1.37045, 1.41057, 1.67259}}, + {{1.36755, 1.36892, 1.37315, 1.39148, 1.39755, 1.45820, 1.43215, 1.42602, 1.43467, 1.47268, 1.73477}}, + {{1.42966, 1.43101, 1.43549, 1.45359, 1.45976, 1.52031, 1.49601, 1.48811, 1.49677, 1.53477, 1.79691}}, + {{1.49180, 1.49321, 1.49760, 1.51570, 1.52175, 1.58185, 1.55771, 1.55023, 1.55888, 1.59672, 1.85501}}, + {{1.55391, 1.55527, 1.55943, 1.57782, 1.58391, 1.64395, 1.62008, 1.61233, 1.62085, 1.65883, 1.92091}}, + {{1.61599, 1.61732, 1.62154, 1.63993, 1.64612, 1.70608, 1.68237, 1.67108, 1.68301, 1.72110, 1.97931}}, + {{1.67808, 1.67948, 1.68364, 1.70204, 1.70823, 1.76858, 1.74404, 1.73539, 1.74512, 1.78321, 2.04522}}, + {{1.74019, 1.74152, 1.74573, 1.76415, 1.77015, 1.83040, 1.80615, 1.79366, 1.80723, 1.84509, 2.10742}}, + {{1.80235, 1.80362, 1.80783, 1.82626, 1.83227, 1.89246, 1.86795, 1.85405, 1.86938, 1.90720, 2.16953}}, + {{1.86442, 1.86572, 1.86994, 1.88837, 1.89438, 1.95445, 1.93006, 1.92283, 1.93148, 1.96931, 2.23147}}, + {{1.92700, 1.92783, 1.93197, 1.95049, 1.95649, 2.01668, 1.99217, 1.98486, 1.99352, 2.03143, 2.29358}}}}; + +// Garfield simulation at UD = -2000V; vd = 1.783cm/microsec, <driftfield> = 688V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time2000{{{{0.09176, 0.09196, 0.09296, 0.09465, 0.09704, 0.10020, 0.10427, 0.10977, 0.11825, 0.13988, 0.37774}}, + {{0.06583, 0.06620, 0.06735, 0.06918, 0.07177, 0.07513, 0.07936, 0.08503, 0.09372, 0.11606, 0.35586}}, + {{0.03944, 0.04001, 0.04170, 0.04431, 0.04774, 0.05184, 0.05670, 0.06296, 0.07291, 0.09893, 0.34680}}, + {{0.01108, 0.01281, 0.01719, 0.02279, 0.02879, 0.03474, 0.04093, 0.04908, 0.06422, 0.10605, 0.36800}}, + {{0.01114, 0.01287, 0.01720, 0.02276, 0.02863, 0.03449, 0.04073, 0.04970, 0.06774, 0.11478, 0.37179}}, + {{0.03925, 0.03977, 0.04135, 0.04386, 0.04711, 0.05108, 0.05604, 0.06290, 0.07580, 0.10748, 0.36386}}, + {{0.06501, 0.06536, 0.06640, 0.06814, 0.07062, 0.07398, 0.07852, 0.08487, 0.09598, 0.12405, 0.37519}}, + {{0.09109, 0.09127, 0.09188, 0.09292, 0.09472, 0.00000, 0.10964, 0.11630, 0.12960, 0.16150, 0.41765}}, + {{0.12898, 0.12968, 0.13209, 0.13749, 0.15034, 0.21286, 0.18088, 0.17590, 0.18591, 0.22254, 0.48315}}, + {{0.18122, 0.18227, 0.18574, 0.19263, 0.20674, 0.26376, 0.23960, 0.23375, 0.24316, 0.28047, 0.54179}}, + {{0.23674, 0.23784, 0.24142, 0.24847, 0.26264, 0.31810, 0.29602, 0.29008, 0.29944, 0.33675, 0.59795}}, + {{0.29279, 0.29382, 0.29742, 0.30448, 0.31865, 0.37364, 0.35215, 0.34629, 0.35555, 0.39286, 0.65411}}, + {{0.34875, 0.34987, 0.35346, 0.36054, 0.37472, 0.42956, 0.40825, 0.40229, 0.41167, 0.44894, 0.71033}}, + {{0.40484, 0.40594, 0.40954, 0.41660, 0.43077, 0.48560, 0.46433, 0.45840, 0.46772, 0.50500, 0.76632}}, + {{0.46090, 0.46201, 0.46560, 0.47267, 0.48684, 0.54167, 0.52041, 0.51449, 0.52382, 0.56108, 0.82227}}, + {{0.51698, 0.51809, 0.52173, 0.52874, 0.54291, 0.59776, 0.57646, 0.57052, 0.57986, 0.61717, 0.87836}}, + {{0.57306, 0.57418, 0.57782, 0.58513, 0.59899, 0.65380, 0.63255, 0.62661, 0.63594, 0.67325, 0.93460}}, + {{0.62912, 0.63024, 0.63383, 0.64103, 0.65506, 0.70988, 0.68484, 0.68267, 0.69202, 0.72878, 0.99046}}, + {{0.68521, 0.68633, 0.68990, 0.69699, 0.71115, 0.76595, 0.74468, 0.73872, 0.74814, 0.78538, 1.04674}}, + {{0.74127, 0.74239, 0.74605, 0.75303, 0.77022, 0.82204, 0.80078, 0.79484, 0.80416, 0.84147, 1.10261}}, + {{0.79736, 0.79846, 0.80206, 0.80947, 0.82330, 0.87813, 0.85688, 0.85087, 0.86023, 0.89752, 1.15874}}, + {{0.85342, 0.85454, 0.85815, 0.86519, 0.87936, 0.93417, 0.91293, 0.90428, 0.91631, 0.95360, 1.20760}}, + {{0.90949, 0.91061, 0.91423, 0.92128, 0.93544, 0.99026, 0.96807, 0.96305, 0.97239, 1.00967, 1.27078}}, + {{0.96556, 0.96669, 0.97111, 0.97734, 0.99151, 1.04664, 1.02508, 1.01879, 1.02846, 1.06167, 1.32695}}, + {{1.02167, 1.02279, 1.02656, 1.03341, 1.04759, 1.10242, 1.08115, 1.07003, 1.08453, 1.12184, 1.38304}}, + {{1.07776, 1.07883, 1.08242, 1.08950, 1.10384, 1.16422, 1.13725, 1.13133, 1.14061, 1.17793, 1.43910}}, + {{1.13379, 1.13492, 1.13864, 1.14567, 1.15973, 1.21455, 1.19323, 1.18734, 1.19668, 1.23401, 1.49528}}, + {{1.18988, 1.19098, 1.19457, 1.20164, 1.21582, 1.27064, 1.24937, 1.24044, 1.25275, 1.29004, 1.55137}}, + {{1.24592, 1.24706, 1.25087, 1.25773, 1.27188, 1.32670, 1.30544, 1.29953, 1.30883, 1.34613, 1.60743}}, + {{1.30202, 1.30313, 1.30673, 1.31381, 1.32797, 1.38278, 1.36151, 1.35167, 1.36490, 1.40221, 1.66306}}, + {{1.35809, 1.35921, 1.36282, 1.36986, 1.38403, 1.43888, 1.41760, 1.41174, 1.42083, 1.45830, 1.71915}}, + {{1.41419, 1.41528, 1.41890, 1.42595, 1.44011, 1.49496, 1.47368, 1.46769, 1.47706, 1.51436, 1.77523}}, + {{1.47131, 1.47141, 1.47494, 1.48850, 1.49620, 1.55137, 1.52977, 1.51820, 1.53315, 1.57042, 1.83158}}, + {{1.52635, 1.52750, 1.53103, 1.53814, 1.55228, 1.60736, 1.58503, 1.57986, 1.58920, 1.62649, 1.88767}}, + {{1.58418, 1.58355, 1.58711, 1.59526, 1.60833, 1.66316, 1.63345, 1.63261, 1.64556, 1.68204, 1.94359}}, + {{1.64027, 1.63958, 1.64489, 1.65024, 1.66443, 1.71925, 1.69794, 1.69201, 1.70143, 1.73865, 1.99968}}, + {{1.69450, 1.69566, 1.69940, 1.70697, 1.71841, 1.77819, 1.75396, 1.74814, 1.75743, 1.79083, 2.05427}}, + {{1.75054, 1.75221, 1.75527, 1.76306, 1.77662, 1.83428, 1.81006, 1.81173, 1.81345, 1.85076, 2.10289}}}}; + +// Garfield simulation at UD = -2100V; vd = 1.959cm/microsec, <driftfield> = 720V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time2100{{{{0.09160, 0.09194, 0.09294, 0.09462, 0.09701, 0.10017, 0.10424, 0.10974, 0.11823, 0.13988, 0.37762}}, + {{0.06585, 0.06619, 0.06731, 0.06916, 0.07174, 0.07509, 0.07933, 0.08500, 0.09370, 0.11609, 0.35565}}, + {{0.03960, 0.04001, 0.04171, 0.04430, 0.04774, 0.05182, 0.05668, 0.06294, 0.07291, 0.09896, 0.34676}}, + {{0.01109, 0.01280, 0.01716, 0.02279, 0.02876, 0.03474, 0.04096, 0.04908, 0.06424, 0.10612, 0.36790}}, + {{0.01114, 0.01285, 0.01719, 0.02287, 0.02863, 0.03449, 0.04073, 0.04964, 0.06759, 0.11446, 0.37162}}, + {{0.03922, 0.03977, 0.04146, 0.04386, 0.04711, 0.05109, 0.05605, 0.06287, 0.07575, 0.10713, 0.36298}}, + {{0.06504, 0.06538, 0.06641, 0.06818, 0.07064, 0.07426, 0.07852, 0.08483, 0.09581, 0.12363, 0.37424}}, + {{0.09103, 0.09129, 0.09186, 0.09291, 0.09476, 0.00000, 0.10923, 0.11578, 0.12873, 0.16005, 0.41525}}, + {{0.12723, 0.12777, 0.12988, 0.13458, 0.14579, 0.20264, 0.17421, 0.17078, 0.18132, 0.21708, 0.47699}}, + {{0.17508, 0.17601, 0.17897, 0.18487, 0.19698, 0.24881, 0.22737, 0.22337, 0.23348, 0.27000, 0.53032}}, + {{0.22571, 0.22663, 0.22969, 0.23570, 0.24787, 0.29826, 0.27871, 0.27462, 0.28471, 0.32122, 0.58166}}, + {{0.27664, 0.27759, 0.28067, 0.28669, 0.29891, 0.34898, 0.32982, 0.32570, 0.33576, 0.37229, 0.63268}}, + {{0.32766, 0.32862, 0.33170, 0.33778, 0.34988, 0.39973, 0.38088, 0.37675, 0.38680, 0.42333, 0.68159}}, + {{0.37872, 0.37966, 0.38275, 0.38875, 0.40093, 0.45073, 0.43192, 0.42780, 0.43786, 0.47438, 0.73480}}, + {{0.42974, 0.43070, 0.43378, 0.43982, 0.45196, 0.50177, 0.48297, 0.47884, 0.48889, 0.52544, 0.78581}}, + {{0.48081, 0.48175, 0.48482, 0.49084, 0.50302, 0.55290, 0.53398, 0.52988, 0.53994, 0.57647, 0.83687}}, + {{0.53645, 0.53295, 0.53586, 0.54188, 0.55408, 0.60398, 0.58504, 0.58092, 0.59100, 0.62768, 0.88773}}, + {{0.58345, 0.58409, 0.58690, 0.59292, 0.60510, 0.65562, 0.63609, 0.63197, 0.64203, 0.67856, 0.93907}}, + {{0.63397, 0.63490, 0.63795, 0.64403, 0.65613, 0.70612, 0.68714, 0.68301, 0.69294, 0.72955, 0.99000}}, + {{0.68496, 0.68592, 0.68899, 0.69504, 0.70733, 0.75708, 0.73818, 0.73405, 0.74412, 0.78064, 1.04100}}, + {{0.73600, 0.73696, 0.74003, 0.74624, 0.75828, 0.80805, 0.78904, 0.78512, 0.79517, 0.83152, 1.09205}}, + {{0.78709, 0.78801, 0.79108, 0.79709, 0.80931, 0.85906, 0.84027, 0.83614, 0.84621, 0.88269, 1.14058}}, + {{0.83808, 0.83905, 0.84215, 0.84816, 0.86031, 0.91011, 0.89139, 0.88718, 0.89725, 0.93377, 1.19413}}, + {{0.88916, 0.89010, 0.89320, 0.89920, 0.91136, 0.96117, 0.94235, 0.93822, 0.94828, 0.98480, 1.24538}}, + {{0.94036, 0.94113, 0.94422, 0.95023, 0.96241, 1.01220, 0.99310, 0.98927, 0.99933, 1.03585, 1.29629}}, + {{0.99139, 0.99220, 0.99525, 1.00127, 1.01344, 1.06324, 1.04451, 1.04033, 1.04836, 1.08690, 1.34727}}, + {{1.04261, 1.04325, 1.04628, 1.05232, 1.06448, 1.12090, 1.09546, 1.09136, 1.10142, 1.13795, 1.39831}}, + {{1.09331, 1.09429, 1.09742, 1.10336, 1.11557, 1.16547, 1.14658, 1.13642, 1.15247, 1.18898, 1.44936}}, + {{1.14436, 1.14539, 1.14847, 1.15443, 1.16662, 1.21794, 1.19763, 1.19329, 1.20349, 1.23956, 1.50043}}, + {{1.19533, 1.19651, 1.19943, 1.20548, 1.21666, 1.26753, 1.24862, 1.24434, 1.25455, 1.29106, 1.55142}}, + {{1.24638, 1.24756, 1.25046, 1.25648, 1.26764, 1.31858, 1.29967, 1.29538, 1.30499, 1.34211, 1.60250}}, + {{1.29747, 1.29847, 1.30175, 1.30753, 1.31869, 1.36969, 1.35069, 1.34656, 1.35663, 1.39316, 1.64644}}, + {{1.35537, 1.34952, 1.35255, 1.35869, 1.36973, 1.41387, 1.40173, 1.39761, 1.40768, 1.44396, 1.70238}}, + {{1.39956, 1.40056, 1.40380, 1.40961, 1.42178, 1.46492, 1.45278, 1.45423, 1.45872, 1.49522, 1.75557}}, + {{1.45080, 1.45159, 1.45463, 1.46109, 1.47287, 1.52263, 1.50382, 1.50050, 1.50977, 1.54502, 1.80670}}, + {{1.50165, 1.50264, 1.50570, 1.51214, 1.52233, 1.57370, 1.55484, 1.55155, 1.56080, 1.59731, 1.85778}}, + {{1.55269, 1.55364, 1.55675, 1.56274, 1.57491, 1.62598, 1.60590, 1.60259, 1.61185, 1.64836, 1.90883}}, + {{1.60368, 1.60469, 1.60779, 1.61373, 1.62596, 1.67738, 1.65651, 1.65249, 1.66290, 1.69936, 1.95959}}}}; + +// Garfield simulation at UD = -2200V; vd = 2.134cm/microsec, <driftfield> = 753V/cm +constexpr std::array<std::array<float, ZBINSGARFIELD>, TIMEBINSGARFIELD> Time2200{{{{0.09162, 0.09194, 0.09292, 0.09460, 0.09702, 0.10014, 0.10421, 0.10971, 0.11820, 0.13990, 0.37745}}, + {{0.06581, 0.06618, 0.06730, 0.06915, 0.07173, 0.07507, 0.07931, 0.08497, 0.09368, 0.11609, 0.35560}}, + {{0.03947, 0.04001, 0.04167, 0.04429, 0.04772, 0.05183, 0.05667, 0.06293, 0.07292, 0.09900, 0.34673}}, + {{0.01111, 0.01280, 0.01716, 0.02279, 0.02876, 0.03473, 0.04091, 0.04907, 0.06426, 0.10620, 0.36766}}, + {{0.01113, 0.01285, 0.01719, 0.02276, 0.02863, 0.03452, 0.04076, 0.04960, 0.06745, 0.11419, 0.37139}}, + {{0.03923, 0.03978, 0.04137, 0.04387, 0.04713, 0.05110, 0.05605, 0.06284, 0.07551, 0.10677, 0.36210}}, + {{0.06505, 0.06540, 0.06644, 0.06820, 0.07069, 0.07401, 0.07852, 0.08479, 0.09565, 0.12325, 0.37313}}, + {{0.09107, 0.09127, 0.09181, 0.09291, 0.09474, 0.00000, 0.10883, 0.11528, 0.12789, 0.15865, 0.41313}}, + {{0.12559, 0.12622, 0.12800, 0.13206, 0.14166, 0.19331, 0.16832, 0.16632, 0.17724, 0.21218, 0.47098}}, + {{0.16992, 0.17070, 0.17325, 0.17831, 0.18871, 0.23557, 0.21690, 0.21451, 0.22514, 0.26082, 0.52034}}, + {{0.21640, 0.21722, 0.21987, 0.22500, 0.23540, 0.28097, 0.26399, 0.26154, 0.27214, 0.30784, 0.56734}}, + {{0.26318, 0.26400, 0.26679, 0.27181, 0.28220, 0.32739, 0.31090, 0.30842, 0.31902, 0.35474, 0.61415}}, + {{0.31001, 0.31085, 0.31348, 0.31866, 0.32903, 0.37412, 0.35777, 0.35546, 0.36588, 0.40159, 0.66103}}, + {{0.35687, 0.35769, 0.36033, 0.36556, 0.37588, 0.42094, 0.40523, 0.40214, 0.41273, 0.44841, 0.70785}}, + {{0.40372, 0.40457, 0.40723, 0.41234, 0.42273, 0.46778, 0.45148, 0.44903, 0.45961, 0.49526, 0.75486}}, + {{0.45062, 0.45139, 0.45404, 0.45966, 0.46958, 0.51470, 0.49833, 0.49584, 0.50644, 0.54211, 0.80160}}, + {{0.49742, 0.49825, 0.50088, 0.50605, 0.51644, 0.56148, 0.54518, 0.54270, 0.55330, 0.58897, 0.84854}}, + {{0.54427, 0.54510, 0.54774, 0.55290, 0.56329, 0.60846, 0.59203, 0.58955, 0.60014, 0.63578, 0.89528}}, + {{0.59119, 0.59199, 0.59471, 0.59975, 0.61014, 0.65533, 0.63889, 0.63636, 0.64699, 0.68269, 0.94197}}, + {{0.63866, 0.63880, 0.64145, 0.64664, 0.65701, 0.70639, 0.68574, 0.68325, 0.69385, 0.72949, 0.98900}}, + {{0.68483, 0.68566, 0.68831, 0.69347, 0.70386, 0.74890, 0.73260, 0.73010, 0.74069, 0.77638, 1.03320}}, + {{0.73168, 0.73255, 0.73515, 0.74031, 0.75072, 0.79576, 0.77117, 0.77501, 0.78755, 0.82318, 1.08006}}, + {{0.77854, 0.78310, 0.78200, 0.79525, 0.79756, 0.84281, 0.81803, 0.82393, 0.83441, 0.87008, 1.12692}}, + {{0.82541, 0.82642, 0.82916, 0.83528, 0.84442, 0.89086, 0.87315, 0.87079, 0.88125, 0.91694, 1.17648}}, + {{0.87226, 0.87308, 0.87602, 0.88086, 0.89128, 0.93772, 0.92001, 0.91751, 0.92811, 0.95587, 1.22328}}, + {{0.91921, 0.91994, 0.92256, 0.92772, 0.94713, 0.98566, 0.96690, 0.96436, 0.97495, 1.01064, 1.26882}}, + {{0.96790, 0.96679, 0.96941, 0.97463, 0.99399, 1.03001, 1.01376, 1.01112, 1.02181, 1.05749, 1.31568}}, + {{1.01278, 1.01390, 1.01674, 1.02147, 1.03182, 1.07820, 1.06056, 1.05798, 1.06867, 1.10433, 1.36390}}, + {{1.05964, 1.06076, 1.06331, 1.06833, 1.07870, 1.13297, 1.10742, 1.10520, 1.11543, 1.15120, 1.41069}}, + {{1.10664, 1.10762, 1.10997, 1.11519, 1.12556, 1.17531, 1.15427, 1.14620, 1.16229, 1.19805, 1.45758}}, + {{1.15352, 1.15421, 1.15683, 1.16218, 1.17242, 1.21910, 1.20035, 1.19863, 1.20579, 1.24473, 1.50412}}, + {{1.20019, 1.20115, 1.20369, 1.20892, 1.21928, 1.26913, 1.24721, 1.24549, 1.25605, 1.29159, 1.54920}}, + {{1.24707, 1.24846, 1.25052, 1.25602, 1.26608, 1.31558, 1.29448, 1.29232, 1.30293, 1.33675, 1.59798}}, + {{1.29391, 1.29475, 1.29738, 1.30255, 1.31294, 1.36244, 1.34167, 1.33918, 1.34979, 1.38229, 1.64496}}, + {{1.34078, 1.34304, 1.34424, 1.35565, 1.35980, 1.40930, 1.38853, 1.38229, 1.39664, 1.42863, 1.69162}}, + {{1.38762, 1.38847, 1.39110, 1.39627, 1.40666, 1.45183, 1.43539, 1.43289, 1.44348, 1.47549, 1.73876}}, + {{1.43524, 1.43533, 1.43796, 1.44310, 1.45371, 1.49305, 1.48224, 1.47941, 1.49034, 1.52601, 1.78552}}, + {{1.48122, 1.48219, 1.48482, 1.48991, 1.50030, 1.53991, 1.52898, 1.52653, 1.53653, 1.57282, 1.82386}}}}; + +} // namespace garfield +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_GARFIELD_H diff --git a/Detectors/TRD/base/include/TRDBase/Geometry.h b/Detectors/TRD/base/include/TRDBase/Geometry.h index eb9c6573424cf..7a313a220830f 100644 --- a/Detectors/TRD/base/include/TRDBase/Geometry.h +++ b/Detectors/TRD/base/include/TRDBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/GeometryBase.h b/Detectors/TRD/base/include/TRDBase/GeometryBase.h index 7bb5fec24b65d..c817d21cb7c48 100644 --- a/Detectors/TRD/base/include/TRDBase/GeometryBase.h +++ b/Detectors/TRD/base/include/TRDBase/GeometryBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,6 @@ #define O2_TRD_GEOMETRYBASE_H #include "GPUCommonDef.h" -#include "TRDBase/CommonParam.h" #include "DataFormatsTRD/Constants.h" #include "TRDBase/PadPlane.h" diff --git a/Detectors/TRD/base/include/TRDBase/GeometryFlat.h b/Detectors/TRD/base/include/TRDBase/GeometryFlat.h index 394c4be5595af..73dd11247dd66 100644 --- a/Detectors/TRD/base/include/TRDBase/GeometryFlat.h +++ b/Detectors/TRD/base/include/TRDBase/GeometryFlat.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/LocalGainFactor.h b/Detectors/TRD/base/include/TRDBase/LocalGainFactor.h index 1129445afc9a2..7d737291a1b64 100644 --- a/Detectors/TRD/base/include/TRDBase/LocalGainFactor.h +++ b/Detectors/TRD/base/include/TRDBase/LocalGainFactor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/LocalT0.h b/Detectors/TRD/base/include/TRDBase/LocalT0.h index ff46a1ad35607..68117af19d239 100644 --- a/Detectors/TRD/base/include/TRDBase/LocalT0.h +++ b/Detectors/TRD/base/include/TRDBase/LocalT0.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/LocalVDrift.h b/Detectors/TRD/base/include/TRDBase/LocalVDrift.h index ee3907f17a474..19dcbae89c057 100644 --- a/Detectors/TRD/base/include/TRDBase/LocalVDrift.h +++ b/Detectors/TRD/base/include/TRDBase/LocalVDrift.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/MCLabel.h b/Detectors/TRD/base/include/TRDBase/MCLabel.h deleted file mode 100644 index d0cc90f020a99..0000000000000 --- a/Detectors/TRD/base/include/TRDBase/MCLabel.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// Declaration of a transient MC label class for TRD - -#ifndef ALICEO2_TRD_MCLABEL_H_ -#define ALICEO2_TRD_MCLABEL_H_ - -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace trd -{ -using MCLabel = o2::MCCompLabel; -} // namespace trd -} // namespace o2 - -#endif diff --git a/Detectors/TRD/base/include/TRDBase/PadCalibrations.h b/Detectors/TRD/base/include/TRDBase/PadCalibrations.h index f0523a6e9d53f..75e51364bf6eb 100644 --- a/Detectors/TRD/base/include/TRDBase/PadCalibrations.h +++ b/Detectors/TRD/base/include/TRDBase/PadCalibrations.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/PadNoise.h b/Detectors/TRD/base/include/TRDBase/PadNoise.h index aee57cddb85ad..4ac79ecb5c865 100644 --- a/Detectors/TRD/base/include/TRDBase/PadNoise.h +++ b/Detectors/TRD/base/include/TRDBase/PadNoise.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/PadParameters.h b/Detectors/TRD/base/include/TRDBase/PadParameters.h index a147d21f19c99..abbc9e64667d6 100644 --- a/Detectors/TRD/base/include/TRDBase/PadParameters.h +++ b/Detectors/TRD/base/include/TRDBase/PadParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/PadPlane.h b/Detectors/TRD/base/include/TRDBase/PadPlane.h index 7e72d508c0e03..da17ccb8c7c43 100644 --- a/Detectors/TRD/base/include/TRDBase/PadPlane.h +++ b/Detectors/TRD/base/include/TRDBase/PadPlane.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,6 @@ //Forwards to standard header with protection for GPU compilation #include "GPUCommonRtypes.h" // for ClassDef - #include "GPUCommonDef.h" //////////////////////////////////////////////////////////////////////////// @@ -61,19 +61,44 @@ class PadPlane }; void setLength(double l) { mLength = l; }; void setWidth(double w) { mWidth = w; }; - void setLengthOPad(double l) { mLengthOPad = l; }; - void setWidthOPad(double w) { mWidthOPad = w; }; - void setLengthIPad(double l) { mLengthIPad = l; }; - void setWidthIPad(double w) { mWidthIPad = w; }; + void setLengthOPad(double l) + { + mLengthOPad = l; + mInverseLengthOPad = 1.0 / l; + }; + void setWidthOPad(double w) + { + mWidthOPad = w; + mInverseWidthOPad = 1.0 / w; + }; + void setLengthIPad(double l) + { + mLengthIPad = l; + mInverseLengthIPad = 1.0 / l; + }; + void setWidthIPad(double w) + { + mWidthIPad = w; + mInverseWidthIPad = 1.0 / w; + }; void setPadRowSMOffset(double o) { mPadRowSMOffset = o; }; void setAnodeWireOffset(float o) { mAnodeWireOffset = o; }; void setTiltingAngle(double t); GPUd() int getPadRowNumber(double z) const; GPUd() int getPadRowNumberROC(double z) const; + GPUd() double getPadRow(double z) const; GPUd() int getPadColNumber(double rphi) const; + GPUd() double getPad(double y, double z) const; - GPUd() double getTiltOffset(double rowOffset) const { return mTiltingTan * (rowOffset - 0.5 * mLengthIPad); }; + GPUd() double getTiltOffset(int row, double rowOffset) const + { + if (row == 0 || row == mNrows - 1) { + return mTiltingTan * (rowOffset - 0.5 * mLengthOPad); + } else { + return mTiltingTan * (rowOffset - 0.5 * mLengthIPad); + } + }; GPUd() double getPadRowOffset(int row, double z) const { if ((row < 0) || (row >= mNrows)) { @@ -174,6 +199,12 @@ class PadPlane double mAnodeWireOffset; // Distance of first anode wire from pad edge + double mInverseLengthIPad; // 1 / mLengthIPad + double mInverseLengthOPad; // 1 / mLengthOPad + + double mInverseWidthIPad; // 1 / mWidthIPad + double mInverseWidthOPad; // 1 / mWidthOPad + private: ClassDefNV(PadPlane, 1); // TRD ROC pad plane }; diff --git a/Detectors/TRD/base/include/TRDBase/PadResponse.h b/Detectors/TRD/base/include/TRDBase/PadResponse.h index b655ba847b119..bb97153b32a81 100644 --- a/Detectors/TRD/base/include/TRDBase/PadResponse.h +++ b/Detectors/TRD/base/include/TRDBase/PadResponse.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,8 +29,8 @@ class PadResponse private: void samplePRF(); // Initialized the PRF static constexpr int mPRFbin{500}; // Number of bins for the PRF - static constexpr float mPRFlo{-1.5}; // Lower boundary of the PRF - static constexpr float mPRFhi{1.5}; // Higher boundary of the PRF + const float mPRFlo{-1.5}; // Lower boundary of the PRF + const float mPRFhi{1.5}; // Higher boundary of the PRF float mPRFwid; // Bin width of the sampled PRF int mPRFpad; // Distance to next pad in PRF std::array<float, constants::NLAYER * mPRFbin> mPRFsmp{}; // Sampled pad response diff --git a/Detectors/TRD/base/include/TRDBase/PadStatus.h b/Detectors/TRD/base/include/TRDBase/PadStatus.h index 1a126185a5c21..b87670fd21175 100644 --- a/Detectors/TRD/base/include/TRDBase/PadStatus.h +++ b/Detectors/TRD/base/include/TRDBase/PadStatus.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/RecoParam.h b/Detectors/TRD/base/include/TRDBase/RecoParam.h new file mode 100644 index 0000000000000..1828a0b1724e9 --- /dev/null +++ b/Detectors/TRD/base/include/TRDBase/RecoParam.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoParam.h +/// \brief Error parameterizations and helper functions for TRD reconstruction +/// \author Ole Schmidt + +#ifndef O2_TRD_RECOPARAM_H +#define O2_TRD_RECOPARAM_H + +#include <array> +#include "Rtypes.h" + +namespace o2 +{ +namespace trd +{ + +class RecoParam +{ + public: + RecoParam() = default; + RecoParam(const RecoParam&) = default; + ~RecoParam() = default; + + /// Load parameterization for given magnetic field + void setBfield(float bz); + + /// Recalculate tracklet covariance based on phi angle of related track + void recalcTrkltCov(const float tilt, const float snp, const float rowSize, std::array<float, 3>& cov) const; + + /// Get tracklet r-phi resolution for given phi angle + /// Resolution depends on the track angle sin(phi) = snp and is approximated by the formula + /// sigma_y(snp) = sqrt(a^2 + c^2 * (snp - b^2)^2) + /// more details are given in http://cds.cern.ch/record/2724259 in section 5.3.3 + /// \param phi angle of related track + /// \return sigma_y^2 of tracklet + float getRPhiRes(float snp) const { return (mA2 + mC2 * (snp - mB) * (snp - mB)); } + + /// Get tracklet z correction coefficient for track-eta based corraction + float getZCorrCoeffNRC() const { return mZCorrCoefNRC; } + + private: + // tracklet error parameterization depends on the magnetic field + float mA2{1.f}; ///< parameterization for tracklet position resolution + float mB{0.f}; ///< parameterization for tracklet position resolution + float mC2{0.f}; ///< parameterization for tracklet position resolution + float mZCorrCoefNRC{1.4f}; ///< tracklet z-position depends linearly on track dip angle + + ClassDefNV(RecoParam, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_RECOPARAM_H diff --git a/Detectors/TRD/base/include/TRDBase/SimParam.h b/Detectors/TRD/base/include/TRDBase/SimParam.h index e6de326bc8650..b0c3647ee78f3 100644 --- a/Detectors/TRD/base/include/TRDBase/SimParam.h +++ b/Detectors/TRD/base/include/TRDBase/SimParam.h @@ -1,137 +1,128 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file SimParam.h + #ifndef O2_TRD_SIMPARAM_H #define O2_TRD_SIMPARAM_H -//Forwards to standard header with protection for GPU compilation -#include "GPUCommonRtypes.h" // for ClassDef +#include <array> +#include "Rtypes.h" // for ClassDef namespace o2 { namespace trd { -//////////////////////////////////////////////////////////////////////////// -// // -// Class containing constant simulation parameters // -// // -//////////////////////////////////////////////////////////////////////////// + +/// \brief Constant parameters for the TRD simulation +/// class SimParam { public: enum { - kNPadsInPadResponse = 3 // Number of pads included in the pad response + kNPadsInPadResponse = 3 ///< Number of pads included in the pad response }; - static SimParam* Instance(); - static void Terminate(); - - void SetGasGain(float gasgain) { mGasGain = gasgain; } - void SetNoise(float noise) { mNoise = noise; } - void SetChipGain(float chipgain) { mChipGain = chipgain; } - void SetADCoutRange(float range) { mADCoutRange = range; } - void SetADCinRange(float range) { mADCinRange = range; } - void SetADCbaseline(int basel) { mADCbaseline = basel; } - void SetDiffusion(int diffOn = 1) { mDiffusionOn = diffOn; } - void SetElAttach(int elOn = 1) { mElAttachOn = elOn; } - void SetElAttachProp(float prop) { mElAttachProp = prop; } - void SetTimeResponse(int trfOn = 1) - { - mTRFOn = trfOn; - ReInit(); - } - void SetCrossTalk(int ctOn = 1) - { - mCTOn = ctOn; - ReInit(); - } - void SetPadCoupling(float v) { mPadCoupling = v; } - void SetTimeCoupling(float v) { mTimeCoupling = v; } - void SetTimeStruct(bool tsOn = 1) { mTimeStructOn = tsOn; } - void SetPadResponse(int prfOn = 1) { mPRFOn = prfOn; } - void SetNTimeBins(int ntb) { mNTimeBins = ntb; } - void SetNTBoverwriteOCDB(bool over = true) { mNTBoverwriteOCDB = over; } - float GetGasGain() const { return mGasGain; } - float GetNoise() const { return mNoise; } - float GetChipGain() const { return mChipGain; } - float GetADCoutRange() const { return mADCoutRange; } - float GetADCinRange() const { return mADCinRange; } - int GetADCbaseline() const { return mADCbaseline; } - float GetTRFlo() const { return mTRFlo; } - float GetTRFhi() const { return mTRFhi; } - float GetPadCoupling() const { return mPadCoupling; } - float GetTimeCoupling() const { return mTimeCoupling; } - int GetNTimeBins() const { return mNTimeBins; } - bool GetNTBoverwriteOCDB() const { return mNTBoverwriteOCDB; } - bool DiffusionOn() const { return mDiffusionOn; } - bool ElAttachOn() const { return mElAttachOn; } - float GetElAttachProp() const { return mElAttachProp; } - bool TRFOn() const { return mTRFOn; } - bool CTOn() const { return mCTOn; } - bool TimeStructOn() const { return mTimeStructOn; } - bool PRFOn() const { return mPRFOn; } + /// For a singleton class copying and assigning is not allowed + SimParam(const SimParam&) = delete; + SimParam& operator=(const SimParam&) = delete; + + /// Returns an instance of this class. A SimParam object is created upon the first call of this function + static SimParam* instance(); + + /// After setting a new gas mixture the parameters need to be re-evaluated + void reInit(); + + // Setters + void setGasGain(float gasgain) { mGasGain = gasgain; } + void setNoise(float noise) { mNoise = noise; } + void setChipGain(float chipgain) { mChipGain = chipgain; } + void setADCoutRange(float range) { mADCoutRange = range; } + void setADCinRange(float range) { mADCinRange = range; } + void setADCbaseline(int basel) { mADCbaseline = basel; } + void setDiffusion(bool flag = true) { mDiffusionOn = flag; } + void setElAttach(bool flag = true) { mElAttachOn = flag; } + void setElAttachProp(float prop) { mElAttachProp = prop; } + void setTimeResponse(bool flag = true) { mTRFOn = flag; } + void setCrossTalk(bool flag = true) { mCTOn = flag; } + void setPadCoupling(float v) { mPadCoupling = v; } + void setTimeCoupling(float v) { mTimeCoupling = v; } + void setTimeStruct(bool flag = true) { mTimeStructOn = flag; } + void setPadResponse(bool flag = true) { mPRFOn = flag; } + + // Getters + float getGasGain() const { return mGasGain; } + float getNoise() const { return mNoise; } + float getChipGain() const { return mChipGain; } + float getADCoutRange() const { return mADCoutRange; } + float getADCinRange() const { return mADCinRange; } + int getADCbaseline() const { return mADCbaseline; } + float getTRFlo() const { return mTRFlo; } + float getTRFhi() const { return mTRFhi; } + float getPadCoupling() const { return mPadCoupling; } + float getTimeCoupling() const { return mTimeCoupling; } + bool diffusionOn() const { return mDiffusionOn; } + bool elAttachOn() const { return mElAttachOn; } + float getElAttachProp() const { return mElAttachProp; } + bool trfOn() const { return mTRFOn; } + bool ctOn() const { return mCTOn; } + bool timeStructOn() const { return mTimeStructOn; } + bool prfOn() const { return mPRFOn; } const int getNumberOfPadsInPadResponse() const { return kNPadsInPadResponse; } - inline double TimeResponse(double) const; - inline double CrossTalk(double) const; - void ReInit(); + inline double timeResponse(double) const; + inline double crossTalk(double) const; protected: - static SimParam* fgInstance; // Instance of this class (singleton implementation) - static bool fgTerminated; // Defines if this class has already been terminated and - // therefore does not return instances in GetInstance anymore - - // Digitization parameter - float mGasGain; // Gas gain - float mNoise; // Electronics noise - float mChipGain; // Electronics gain - - float mADCoutRange; // ADC output range (number of channels) - float mADCinRange; // ADC input range (input charge) - int mADCbaseline; // ADC intrinsic baseline in ADC channel - - int mDiffusionOn; // Switch for the diffusion - - int mElAttachOn; // Switch for the electron attachment - float mElAttachProp; // Propability for electron attachment (for 1m) - - int mTRFOn; // Switch for the time response - float* mTRFsmp; //! Integrated time response - int mTRFbin; // Number of bins for the TRF - float mTRFlo; // Lower boundary of the TRF - float mTRFhi; // Higher boundary of the TRF - float mInvTRFwid; // Inverse of the bin width of the integrated TRF - - int mCTOn; // Switch for cross talk - float* mCTsmp; //! Integrated cross talk - - float mPadCoupling; // Pad coupling factor - float mTimeCoupling; // Time coupling factor (image charge of moving ions) - int mTimeStructOn; // Switch for cell time structure - - int mPRFOn; // Switch for the pad response - - int mNTimeBins; // Number of time bins (only used it fNTBoverwriteOCDB = true) - bool mNTBoverwriteOCDB; // Switch to overwrite number of time bins from PCDB + static SimParam* mgInstance; ///< Instance of this class (singleton implementation) + + float mNoise{1250.f}; ///< Electronics noise + float mChipGain{12.4f}; ///< Electronics gain + float mADCoutRange{1023.f}; ///< ADC output range (number of channels for the 10 bit ADC) + float mADCinRange{2000.f}; ///< ADC input range (2V) + int mADCbaseline{10}; ///< ADC intrinsic baseline in ADC channel + bool mDiffusionOn{true}; ///< Switch for the diffusion + bool mElAttachOn{false}; ///< Switch for the electron attachment + float mElAttachProp{0.f}; ///< Propability for electron attachment (for 1m) + bool mTRFOn{true}; ///< Switch for the time response + bool mCTOn{true}; ///< Switch for cross talk + bool mPRFOn{true}; ///< Switch for the pad response + static constexpr int mNBinsMax = 200; ///< Maximum number of bins for integrated time response and cross talk + + // Use 0.46, instead of the theroetical value 0.3, since it reproduces better + // the test beam data, even tough it is not understood why. + float mPadCoupling{.46f}; ///< The pad coupling factor + float mTimeCoupling{.4f}; ///< Time coupling factor (image charge of moving ions); same number as for the TPC + bool mTimeStructOn{true}; ///< Switch for cell time structure + + /// The parameters below depend on the gas mixture and are re-evaluated upon a change + std::array<float, mNBinsMax> mTRFsmp{}; ///< Integrated time response + std::array<float, mNBinsMax> mCTsmp{}; ///< Integrated cross talk + int mTRFbin{200}; ///< Number of bins for the TRF and x-talk + float mTRFlo{-.4f}; ///< Lower boundary of the TRF and x-talk + float mTRFhi{3.58f}; ///< Higher boundary of the TRF and x-talk + float mInvTRFwid{static_cast<float>(mTRFbin) / (mTRFhi - mTRFlo)}; ///< Inverse of the bin width of the integrated TRF and x-talk + float mGasGain{4000.f}; ///< Gas gain private: - // This is a singleton, constructor is private! + /// This is a singleton, constructor is private! SimParam(); - ~SimParam(); + ~SimParam() = default; - void Init(); - void SampleTRF(); + /// Fill the arrays mTRDsmp and mCTsmp for the given gas mixture + void sampleTRF(); ClassDefNV(SimParam, 1); // The TRD simulation parameters }; -inline double SimParam::TimeResponse(double time) const +inline double SimParam::timeResponse(double time) const { // // Applies the preamp shaper time response @@ -148,7 +139,7 @@ inline double SimParam::TimeResponse(double time) const } } -inline double SimParam::CrossTalk(double time) const +inline double SimParam::crossTalk(double time) const { // // Applies the pad-pad capacitive cross talk diff --git a/Detectors/TRD/base/include/TRDBase/Tracklet.h b/Detectors/TRD/base/include/TRDBase/Tracklet.h index 88d6d042ff35f..934a5ba06494a 100644 --- a/Detectors/TRD/base/include/TRDBase/Tracklet.h +++ b/Detectors/TRD/base/include/TRDBase/Tracklet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h b/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h new file mode 100644 index 0000000000000..20ff88e5d7b3a --- /dev/null +++ b/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_TRACKLETTRANSFORMER_H +#define O2_TRD_TRACKLETTRANSFORMER_H + +#include "TRDBase/Geometry.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" + +namespace o2 +{ +namespace trd +{ + +class TrackletTransformer +{ + public: + TrackletTransformer(); + ~TrackletTransformer() = default; + + float getXCathode() { return mXCathode; } + float getXAnode() { return mXAnode; } + float getXDrift() { return mXDrift; } + float getXtb0() { return mXtb0; } + + void setXCathode(float x) { mXCathode = x; } + void setXAnode(float x) { mXAnode = x; } + void setXDrift(float x) { mXDrift = x; } + void setXtb0(float x) { mXtb0 = x; } + + void loadPadPlane(int hcid); + + float calculateY(int hcid, int column, int position); + + float calculateZ(int padrow); + + float calculateDy(int slope, double lorentzAngle, double driftVRatio); + + float calibrateX(double x, double t0Correction); + + std::array<float, 3> transformL2T(int hcid, std::array<double, 3> spacePoint); + + CalibratedTracklet transformTracklet(Tracklet64 tracklet); + + double getTimebin(double x); + + private: + o2::trd::Geometry* mGeo; + const o2::trd::PadPlane* mPadPlane; + + float mXCathode; + float mXAnode; + float mXDrift; + float mXtb0; + + float mt0Correction; + float mLorentzAngle; + float mDriftVRatio; +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/base/macros/ConvertRun2DigitsAndTracklets.C b/Detectors/TRD/base/macros/ConvertRun2DigitsAndTracklets.C index 987e98b1d1674..95f82017fd777 100644 --- a/Detectors/TRD/base/macros/ConvertRun2DigitsAndTracklets.C +++ b/Detectors/TRD/base/macros/ConvertRun2DigitsAndTracklets.C @@ -17,7 +17,7 @@ #include "TH1F.h" #include "AliTRDtrackletMCM.h" //#include "TRDDataFormat/TriggerRecord.h" -#include "TRDBase/Digit.h" +#include "DataFormatsTRD/Digit.h" #include "TRDBase/Tracklet.h" #endif diff --git a/Detectors/TRD/base/macros/OCDB2CCDB.C b/Detectors/TRD/base/macros/OCDB2CCDB.C index ae27dbfafc420..45816ab6614f8 100644 --- a/Detectors/TRD/base/macros/OCDB2CCDB.C +++ b/Detectors/TRD/base/macros/OCDB2CCDB.C @@ -25,7 +25,7 @@ // alienv enter VO_ALICE@O2::latest-O2-o2,VO_ALICE@AliRoot::latest-O2-o2 // according to my configs, modify as required of course. // - +#if !defined(__CINT__) || defined(__MAKECINT__) #include <iostream> #include <fstream> #include <string> @@ -78,11 +78,12 @@ #include "TRDBase/CalOnlineGainTables.h" #include "TRDBase/FeeParam.h" #include "TRDSimulation/TrapConfig.h" +#include "DataFormatsTRD/Constants.h" +#endif using namespace std; using namespace o2::ccdb; using namespace o2::trd; - // global variables // histograms used for extracting the mean and RMS of calibration parameters @@ -212,8 +213,9 @@ void UnpackGainTable(std::string& gainkey, CalOnlineGainTables* gtbl) } } +// choose ccdbPath = "http://ccdb-test.cern.ch:8080" to write to the test CCDB at CERN //__________________________________________________________________________________________ -void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data/2010/OCDB/") +void OCDB2CCDB(TString ccdbPath = "http://localhost:8080", Int_t run = 297595, const Char_t* storageURI = "local:///cvmfs/alice-ocdb.cern.ch/calibration/data/2018/OCDB") { // // Main function to steer the extraction of TRD OCDB information @@ -235,7 +237,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data AliCDBEntry* entry = NULL; Run = run; - std::string TRDCalBase = "TRD_test"; + std::string TRDCalBase = "TRD"; manager->SetRun(Run); @@ -249,7 +251,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data // o2::ccdb::CcdbApi ccdb; map<string, string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + ccdb.init(ccdbPath.Data()); AliTRDCalChamberStatus* chamberStatus = 0; AliTRDCalDet *chamberExB = 0, *chamberVDrift = 0, *chamberGainFactor = 0, *chamberT0 = 0; @@ -264,9 +266,9 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data o2chamberstatus->setRawStatus(i, a); } // store abitrary user object in strongly typed manner - ccdb.storeAsTFileAny(o2chamberstatus, "TRD_test/ChamberStatus", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2chamberstatus, "TRD/Calib/ChamberStatus", metadata, Run, Run + 1); // // read like this (you have to specify the type) - //auto o2chamberstatusback = ccdb.retrieveFromTFileAny<o2::trd::ChamberStatus>("TRD_test/ChamberStatus", metadata); + //auto o2chamberstatusback = ccdb.retrieveFromTFileAny<o2::trd::ChamberStatus>("TRD/Calib/ChamberStatus", metadata); } else cout << "attempt to get object chamber status from ocdb entry. Ergo not writing one to ccdb." << endl; } else @@ -313,7 +315,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data if (chamberGainFactor && chamberExB && chamberT0 && chamberVDrift) { //if all 4 mmebers of calibrations is here then write to ccdb. - ccdb.storeAsTFileAny(o2chambercalibrations, "TRD_test/ChamberCalibrations", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2chambercalibrations, "TRD/Calib/ChamberCalibrations", metadata, Run, Run + 1); } else cout << "something wrong with one of the members of ChamberCalibrations and not writing to ccdb, fix :: " << chamberGainFactor << "&&" << chamberExB << "&&" << chamberT0 << "&&" << chamberVDrift << endl; @@ -333,7 +335,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data } else cout << "calroc is undefiend" << endl; } - ccdb.storeAsTFileAny(o2localvdrift, "TRD_test/LocalVDrift", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2localvdrift, "TRD/Calib/LocalVDrift", metadata, Run, Run + 1); } else cout << "attempt to get object LocalVdrift from ocdb entry. Will not be writing LocalVDritf" << endl; } else @@ -351,7 +353,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data o2localt0->setPadValue(i, j, calroc->GetValue(j)); } } - ccdb.storeAsTFileAny(o2localt0, "TRD_test/LocalT0", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2localt0, "TRD/Calib/LocalT0", metadata, Run, Run + 1); } else cout << "attempt to get object chamber LocalT0 from ocdb entry. Will not be writing LocalT0" << endl; } else @@ -370,7 +372,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data o2padnoise->setPadValue(i, j, calroc->GetValue(j)); } } - ccdb.storeAsTFileAny(o2padnoise, "TRD_test/PadNoise", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2padnoise, "TRD/Calib/PadNoise", metadata, Run, Run + 1); } else cout << "attempt to get object PadNoise from ocdb entry. Will not be writing PadNoise" << endl; } @@ -387,7 +389,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data o2localgainfactor->setPadValue(i, j, calroc->GetValue(j)); } } - ccdb.storeAsTFileAny(o2localgainfactor, "TRD_test/LocalGainFactor", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2localgainfactor, "TRD/Calib/LocalGainFactor", metadata, Run, Run + 1); } else cout << "attempt to get object LocalGainFactor from ocdb entry. Will not be writing LocalGainFactor" << endl; } else @@ -405,7 +407,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data o2padstatus->setStatus(i, j, rocstatus->GetStatus(j)); } } - ccdb.storeAsTFileAny(o2padstatus, "TRD_test/PadStatus", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2padstatus, "TRD/Calib/PadStatus", metadata, Run, Run + 1); } } @@ -416,7 +418,7 @@ void OCDB2CCDB(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data for (int i = 0; i < AliTRDCalDet::kNdet; i++) { o2chambernoise->setNoise(i, chambernoise->GetValue(i)); } - ccdb.storeAsTFileAny(o2chambernoise, "TRD_test/ChamberNoise", metadata, Run, Run + 1); + ccdb.storeAsTFileAny(o2chambernoise, "TRD/Calib/ChamberNoise", metadata, Run, Run + 1); } else cout << "attempt to get object ChamberNoise from ocdb entry. Will not be writing ChamberNoise" << endl; } diff --git a/Detectors/TRD/base/macros/OCDB2CCDBTrapConfig.C b/Detectors/TRD/base/macros/OCDB2CCDBTrapConfig.C index 0121e3d1c4ed2..05791b33b74e5 100644 --- a/Detectors/TRD/base/macros/OCDB2CCDBTrapConfig.C +++ b/Detectors/TRD/base/macros/OCDB2CCDBTrapConfig.C @@ -160,8 +160,9 @@ void ParseTrapConfigs(TrapConfig* trapconfig, AliTRDtrapConfig* run2config) // the same way as it was done in run2 and nothing in the code allows you to change it. }*/ } +// choose ccdbPath = "http://ccdb-test.cern.ch:8080" to write to the test CCDB at CERN //__________________________________________________________________________________________ -void OCDB2CCDBTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data/2018/OCDB/") +void OCDB2CCDBTrapConfig(TString ccdbPath = "http://localhost:8080", Int_t run = 297595, const Char_t* storageURI = "local:///cvmfs/alice-ocdb.cern.ch/calibration/data/2018/OCDB") { // // Main function to steer the extraction of TRD OCDB information @@ -171,7 +172,7 @@ void OCDB2CCDBTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/ TTimeStamp jobStartTime; // if the storage is on alien than we need to do some extra stuff TString storageString(storageURI); - if (storageString.Contains("alien://")) { + if (storageString.Contains("raw://")) { TGrid::Connect("alien://"); } @@ -183,8 +184,6 @@ void OCDB2CCDBTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/ AliCDBEntry* entry = NULL; Run = run; - std::string TRDCalBase = "TRD_test"; - manager->SetRun(Run); time_t startTime = 0; @@ -197,17 +196,17 @@ void OCDB2CCDBTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/ // o2::ccdb::CcdbApi ccdb; map<string, string> metadata; // do we want to store any meta data? - ccdb.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation + ccdb.init(ccdbPath.Data()); /* AliTRDCalTrapConfig has a print command that outputs the list of trapconfigs stored. -AliTRDCalTrapConfig->Print() .... and you get the stuff below via AliInfo, but I can seem to get it right to parse this so +AliTRDCalTrapConfig->Print() .... and you get the stuff below via AliInfo, but I can seem to get it right to parse this so its all going here unfortunately .... */ vector<std::string> run2confignames = { - /* "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5505", + "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5505", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b2p-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5585", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b5p-fs1e24-ht200-qs0e23s23e22-pidlhc11dv3en-pt100_ptrg.r5766", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b0-fs1e24-ht200-qs0e23s23e22-pidlhc11dv3en_ptrg.r5767", @@ -249,7 +248,6 @@ its all going here unfortunately .... "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b5n-fs1e24-ht200-qs0e23s23e22-pidlhc11dv3en-pt100_ptrg.r5765", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b5p-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5570", "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b0-fs1e30-ht200-qs0e29s29e28-nb233-pidlhc11dv4en_ptrg.r5773", - "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549", "cf_pg-fpnp32_zs-s16-deh_tb26_trkl-b5n-fs1e24-ht200-qs0e23s23e22-pidlhc11dv3en-pt100_ptrg.r5771", "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e30-ht200-qs0e29s29e28-nb233-pidlhc11dv4en-pt100_ptrg.r5773", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b0-fs1e24-ht200-qs0e24s24e23-pidlinear_ptrg.r5570", @@ -261,7 +259,7 @@ its all going here unfortunately .... "cf_pg-fpnp32_zs-s16-deh_tb26_trkl-b2n-fs1e24-ht200-qs0e23s23e22-pidlhc11dv3en-pt100_ptrg.r5771", "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b5n-fs1e24-ht200-qs0e23s23e22-pidlhc11dv1-pt100_ptrg.r5762", "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b0-fs1e24-ht200-qs0e24s24e23-pidlinear_ptrg.r5505", - "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b0-fs1e24-ht200-qs0e23s23e22-pidlhc11dv1_ptrg.r5762",*/ + "cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b0-fs1e24-ht200-qs0e23s23e22-pidlhc11dv1_ptrg.r5762", "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549"}; // now we loop over these extracting the trapconfing and dumping it into the ccdb. @@ -270,12 +268,11 @@ its all going here unfortunately .... if ((entry = GetCDBentry("TRD/Calib/TrapConfig", 0))) { if ((run2caltrapconfig = (AliTRDCalTrapConfig*)entry->GetObject())) { for (auto const& run2trapconfigname : run2confignames) { - auto o2trapconfig = new TrapConfig(run2trapconfigname); + auto o2trapconfig = new TrapConfig(); run2trapconfig = run2caltrapconfig->Get(run2trapconfigname.c_str()); ParseTrapConfigs(o2trapconfig, run2trapconfig); - // ccdb.storeAsTFileAny(o2trapconfig, "TRD_test/TrapConfig2020/c", metadata, 1, 1670700184549); //upper time chosen into the future else the server simply adds a year - // cout << "ccdb.storeAsTFileAny(o2trapconfig, Form(\"" << TRDCalBase.c_str() << "/TrapConfig/" << run2trapconfigname.c_str()<< endl; //upper time chosen into the future else the server simply adds a year - //AliTRDcalibDB *calibdb=AliTRDcalibDB::Instance(); + std::string objectPath = "TRD/TrapConfig/" + run2trapconfigname; + ccdb.storeAsTFileAny(o2trapconfig, objectPath, metadata, 1, 1670700184549); //upper time chosen into the future else the server simply adds a year } } } @@ -289,38 +286,38 @@ its all going here unfortunately .... /* THESE ARE THE ONES NOT CURRENTLY INCLUDED. -trd_ddchamberStatus -trd_gaschromatographXe -trd_gasOverpressure +trd_ddchamberStatus +trd_gaschromatographXe +trd_gasOverpressure trd_hvDriftImon -MonitoringData -PIDLQ -trd_envTemp -trd_gasCO2 +MonitoringData +PIDLQ +trd_envTemp +trd_gasCO2 trd_hvDriftUmon -PIDLQ1D -trd_gaschromatographCO2 -trd_gasH2O -trd_hvAnodeImon +PIDLQ1D +trd_gaschromatographCO2 +trd_gasH2O +trd_hvAnodeImon TrkAttach -PIDNN -PHQ PIDThresholds +PIDNN +PHQ PIDThresholds This pulls stuff from DCS I should hopefully not need this stuff for simulation. -DCS +DCS AliTRDSensorArray descends from AliTRDDCSSensorArray -trd_gaschromatographN2 -trd_gasO2 -trd_goofieHv -trd_goofiePressure +trd_gaschromatographN2 +trd_gasO2 +trd_goofieHv +trd_goofiePressure trd_hvAnodeUmon -trd_goofieN2 -trd_goofieTemp -trd_goofieCO2 -trd_goofiePeakArea -trd_goofieVelocity -trd_goofieGain -trd_goofiePeakPos +trd_goofieN2 +trd_goofieTemp +trd_goofieCO2 +trd_goofiePeakArea +trd_goofieVelocity +trd_goofieGain +trd_goofiePeakPos */ return; } diff --git a/Detectors/TRD/base/macros/PrintTrapConfig.C b/Detectors/TRD/base/macros/PrintTrapConfig.C index ec67f89b5fb38..40860038754a4 100644 --- a/Detectors/TRD/base/macros/PrintTrapConfig.C +++ b/Detectors/TRD/base/macros/PrintTrapConfig.C @@ -217,7 +217,7 @@ void PrintTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/alic AliCDBEntry* entry = NULL; Run = run; - std::string TRDCalBase = "TRD_test"; + std::string TRDCalBase = "TRD"; manager->SetRun(Run); @@ -235,7 +235,7 @@ void PrintTrapConfig(Int_t run, const Char_t* storageURI = "alien://folder=/alic /* AliTRDCalTrapConfig has a print command that outputs the list of trapconfigs stored. -AliTRDCalTrapConfig->Print() .... and you get the stuff below via AliInfo, but I can seem to get it right to parse this so +AliTRDCalTrapConfig->Print() .... and you get the stuff below via AliInfo, but I can seem to get it right to parse this so its all going here unfortunately .... */ @@ -309,8 +309,8 @@ its all going here unfortunately .... PrintTrapConfigsAsStored(run2trapconfig); auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); ccdbmgr.setTimestamp(297595); - // auto run3trapconfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD_test/TrapConfig2020/cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549"); - auto run3trapconfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD_test/TrapConfig2020/c"); + auto run3trapconfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD/TrapConfig/cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549"); + //auto run3trapconfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD/Config/TrapConfig2020"); if (run3trapconfig) PrintTrapConfigsAsStored3(run3trapconfig); // ccdb.storeAsTFileAny(o2trapconfig, Form("%s/TrapConfig2020/%s", TRDCalBase.c_str(), run2trapconfigname.c_str()), metadata, 1, 1670700184549); //upper time chosen into the future else the server simply adds a year @@ -329,38 +329,38 @@ its all going here unfortunately .... /* THESE ARE THE ONES NOT CURRENTLY INCLUDED. -trd_ddchamberStatus -trd_gaschromatographXe -trd_gasOverpressure +trd_ddchamberStatus +trd_gaschromatographXe +trd_gasOverpressure trd_hvDriftImon -MonitoringData -PIDLQ -trd_envTemp -trd_gasCO2 +MonitoringData +PIDLQ +trd_envTemp +trd_gasCO2 trd_hvDriftUmon -PIDLQ1D -trd_gaschromatographCO2 -trd_gasH2O -trd_hvAnodeImon +PIDLQ1D +trd_gaschromatographCO2 +trd_gasH2O +trd_hvAnodeImon TrkAttach -PIDNN -PHQ PIDThresholds +PIDNN +PHQ PIDThresholds This pulls stuff from DCS I should hopefully not need this stuff for simulation. -DCS +DCS AliTRDSensorArray descends from AliTRDDCSSensorArray -trd_gaschromatographN2 -trd_gasO2 -trd_goofieHv -trd_goofiePressure +trd_gaschromatographN2 +trd_gasO2 +trd_goofieHv +trd_goofiePressure trd_hvAnodeUmon -trd_goofieN2 -trd_goofieTemp -trd_goofieCO2 -trd_goofiePeakArea -trd_goofieVelocity -trd_goofieGain -trd_goofiePeakPos +trd_goofieN2 +trd_goofieTemp +trd_goofieCO2 +trd_goofiePeakArea +trd_goofieVelocity +trd_goofieGain +trd_goofiePeakPos */ return; } diff --git a/Detectors/TRD/base/macros/Readocdb.C b/Detectors/TRD/base/macros/Readocdb.C index 29d4ef22cd594..660343168aea4 100644 --- a/Detectors/TRD/base/macros/Readocdb.C +++ b/Detectors/TRD/base/macros/Readocdb.C @@ -234,8 +234,6 @@ void Readocdb(Int_t run, const Char_t* storageURI = "alien://folder=/alice/data/ AliCDBEntry* entry = NULL; Run = run; - std::string TRDCalBase = "TRD_test"; - manager->SetRun(Run); time_t startTime = 0; diff --git a/Detectors/TRD/base/src/CalDet.cxx b/Detectors/TRD/base/src/CalDet.cxx index 7fdf6ecd2a6fb..a82233f8853eb 100644 --- a/Detectors/TRD/base/src/CalDet.cxx +++ b/Detectors/TRD/base/src/CalDet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CalOnlineGainTables.cxx b/Detectors/TRD/base/src/CalOnlineGainTables.cxx index 6164137870c2f..988c9e27fa79d 100644 --- a/Detectors/TRD/base/src/CalOnlineGainTables.cxx +++ b/Detectors/TRD/base/src/CalOnlineGainTables.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CalPad.cxx b/Detectors/TRD/base/src/CalPad.cxx index 418e36c51c247..86457092c475c 100644 --- a/Detectors/TRD/base/src/CalPad.cxx +++ b/Detectors/TRD/base/src/CalPad.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CalPadStatus.cxx b/Detectors/TRD/base/src/CalPadStatus.cxx index de82b5155ba33..16d2ac4ce6660 100644 --- a/Detectors/TRD/base/src/CalPadStatus.cxx +++ b/Detectors/TRD/base/src/CalPadStatus.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CalROC.cxx b/Detectors/TRD/base/src/CalROC.cxx index 7c52cba96daa3..74ef75a8e2db2 100644 --- a/Detectors/TRD/base/src/CalROC.cxx +++ b/Detectors/TRD/base/src/CalROC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CalSingleChamberStatus.cxx b/Detectors/TRD/base/src/CalSingleChamberStatus.cxx index f74a3817df95f..f054d49766461 100644 --- a/Detectors/TRD/base/src/CalSingleChamberStatus.cxx +++ b/Detectors/TRD/base/src/CalSingleChamberStatus.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,6 @@ /////////////////////////////////////////////////////////////////////////////// #include "TRDBase/CalSingleChamberStatus.h" -#include <TMath.h> -#include <Rtypes.h> -#include "TRDBase/CommonParam.h" using namespace o2::trd; diff --git a/Detectors/TRD/base/src/Calibrations.cxx b/Detectors/TRD/base/src/Calibrations.cxx index fe251323adfc6..316bf0a288932 100644 --- a/Detectors/TRD/base/src/Calibrations.cxx +++ b/Detectors/TRD/base/src/Calibrations.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,58 +42,45 @@ using namespace o2::trd; // in some FOO detector code (detector initialization) // just give the correct path and you will be served the object -void Calibrations::setCCDB(int calibrationobjecttype, long timestamp) +void Calibrations::getCCDBObjects(long timestamp) { auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); + //ccdbmgr.clearCache(); + //ccdbmgr.setURL("http://localhost:8080"); + mTimeStamp = timestamp; ccdbmgr.setTimestamp(timestamp); // set which time stamp of data we want this is called per timeframe, and removes the need to call it when querying a value. - switch (calibrationobjecttype) { - case 1: //simulation - mChamberCalibrations = ccdbmgr.get<o2::trd::ChamberCalibrations>("TRD_test/ChamberCalibrations"); - if (!mChamberCalibrations) { - LOG(fatal) << "No chamber calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mLocalVDrift = ccdbmgr.get<o2::trd::LocalVDrift>("TRD_test/LocalVDrift"); - if (!mLocalVDrift) { - LOG(fatal) << "No Local V Drift calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mLocalT0 = ccdbmgr.get<o2::trd::LocalT0>("TRD_test/LocalT0"); - if (!mLocalT0) { - LOG(fatal) << "No Local T0 calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mLocalGainFactor = ccdbmgr.get<o2::trd::LocalGainFactor>("TRD_test/LocalGainFactor"); - if (!mLocalT0) { - LOG(fatal) << "No Local T0 calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mPadNoise = ccdbmgr.get<o2::trd::PadNoise>("TRD_test/PadNoise"); - if (!mPadNoise) { - LOG(fatal) << "No Padnoise calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mChamberStatus = ccdbmgr.get<o2::trd::ChamberStatus>("TRD_test/ChamberStatus"); - if (!mChamberStatus) { - LOG(fatal) << "No ChamberStatus calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mPadStatus = ccdbmgr.get<o2::trd::PadStatus>("TRD_test/PadStatus"); - if (!mPadStatus) { - LOG(fatal) << "No Pad Status calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - mChamberNoise = ccdbmgr.get<o2::trd::ChamberNoise>("TRD_test/ChamberNoise"); - if (!mChamberNoise) { - LOG(fatal) << "No ChamberNoise calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; - } - //mCalOnlineGainTables= ccdbmgr.get<o2::trd::CalOnlineGainTables>("TRD_test/OnlineGainTables"); - //std::shared_ptr<TrapConfig> mTrapConfig; - //std::shared_ptr<PRFWidth> mPRDWidth - //std::shared_ptr<CalOnlineGainTables> mCalOnlineGainTables; - break; - case 2: //reconstruction - LOG(fatal) << "Reconstruction calibration not implemented yet "; - break; - case 3: // calibration - LOG(fatal) << "Calibrating calibration not implemented yet "; - break; - default: - LOG(fatal) << "unknown calibration type coming into setCCDB for TRD Calibrations"; + mChamberCalibrations = ccdbmgr.get<o2::trd::ChamberCalibrations>("TRD/Calib/ChamberCalibrations"); + if (!mChamberCalibrations) { + LOG(fatal) << "No chamber calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mLocalVDrift = ccdbmgr.get<o2::trd::LocalVDrift>("TRD/Calib/LocalVDrift"); + if (!mLocalVDrift) { + LOG(fatal) << "No Local V Drift calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mLocalT0 = ccdbmgr.get<o2::trd::LocalT0>("TRD/Calib/LocalT0"); + if (!mLocalT0) { + LOG(fatal) << "No Local T0 calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mLocalGainFactor = ccdbmgr.get<o2::trd::LocalGainFactor>("TRD/Calib/LocalGainFactor"); + if (!mLocalT0) { + LOG(fatal) << "No Local T0 calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mPadNoise = ccdbmgr.get<o2::trd::PadNoise>("TRD/Calib/PadNoise"); + if (!mPadNoise) { + LOG(fatal) << "No Padnoise calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mChamberStatus = ccdbmgr.get<o2::trd::ChamberStatus>("TRD/Calib/ChamberStatus"); + if (!mChamberStatus) { + LOG(fatal) << "No ChamberStatus calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mPadStatus = ccdbmgr.get<o2::trd::PadStatus>("TRD/Calib/PadStatus"); + if (!mPadStatus) { + LOG(fatal) << "No Pad Status calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; + } + mChamberNoise = ccdbmgr.get<o2::trd::ChamberNoise>("TRD/Calib/ChamberNoise"); + if (!mChamberNoise) { + LOG(fatal) << "No ChamberNoise calibrations returned from CCDB for TRD calibrations, or TRD from what ever you are running."; } } @@ -103,7 +91,7 @@ void Calibrations::setOnlineGainTables(std::string& tablename) } auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); - std::string fulltablename = "TRD_test/OnlineGainTables/" + tablename; + std::string fulltablename = "TRD/OnlineGainTables/" + tablename; mCalOnlineGainTables = ccdbmgr.get<o2::trd::CalOnlineGainTables>(fulltablename); } diff --git a/Detectors/TRD/base/src/ChamberNoise.cxx b/Detectors/TRD/base/src/ChamberNoise.cxx index f1e48b53fd5db..9e7e87f4afc44 100644 --- a/Detectors/TRD/base/src/ChamberNoise.cxx +++ b/Detectors/TRD/base/src/ChamberNoise.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/ChamberStatus.cxx b/Detectors/TRD/base/src/ChamberStatus.cxx index 46e0a1a83ced0..6a6679d38c3ff 100644 --- a/Detectors/TRD/base/src/ChamberStatus.cxx +++ b/Detectors/TRD/base/src/ChamberStatus.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/CommonParam.cxx b/Detectors/TRD/base/src/CommonParam.cxx index c8fe591d0536d..5070b3e0ed816 100644 --- a/Detectors/TRD/base/src/CommonParam.cxx +++ b/Detectors/TRD/base/src/CommonParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ // // // Class containing parameters common to simulation and reconstruction // // // -// Request an instance with AliTRDCommonParam::Instance() // +// Request an instance with CommonParam::instance() // // Then request the needed values // // // /////////////////////////////////////////////////////////////////////////////// @@ -28,718 +29,52 @@ #include "Field/MagneticField.h" using namespace o2::trd; +using namespace o2::trd::constants; +using namespace o2::trd::garfield; + ClassImp(CommonParam); -CommonParam* CommonParam::fgInstance = nullptr; -bool CommonParam::fgTerminated = false; +CommonParam* CommonParam::mgInstance = nullptr; //_ singleton implementation __________________________________________________ -CommonParam* CommonParam::Instance() +CommonParam* CommonParam::instance() { // // Singleton implementation // Returns an instance of this class, it is created if neccessary // - if (fgTerminated != false) { - return nullptr; - } - - if (fgInstance == nullptr) { - fgInstance = new CommonParam(); - } - - return fgInstance; -} - -//_____________________________________________________________________________ -void CommonParam::Terminate() -{ - // - // Singleton implementation - // Deletes the instance of this class and sets the terminated flag, - // instances cannot be requested anymore - // This function can be called several times. - // - - fgTerminated = true; - - if (fgInstance != nullptr) { - delete fgInstance; - fgInstance = nullptr; + if (mgInstance == nullptr) { + mgInstance = new CommonParam(); } -} -//_____________________________________________________________________________ -CommonParam::CommonParam() - : mExBOn(true), - mDiffusionT(0.0), - mDiffusionL(0.0), - mDiffLastVdrift(-1.0), - mTimeStruct1(nullptr), - mTimeStruct2(nullptr), - mVDlo(0.0), - mVDhi(0.0), - mTimeLastVdrift(-1.0), - mSamplingFrequency(10.0), - mGasMixture(kXenon), - mField(-0.5) -{ - // - // Default constructor - // + return mgInstance; } -//_____________________________________________________________________________ -CommonParam::~CommonParam() -{ - // - // Destructor - // - if (mTimeStruct1) { - delete[] mTimeStruct1; - mTimeStruct1 = nullptr; - } - if (mTimeStruct2) { - delete[] mTimeStruct2; - mTimeStruct2 = nullptr; - } -} //_____________________________________________________________________________ -bool CommonParam::cacheMagField() +void CommonParam::cacheMagField() { // The magnetic field strength const o2::field::MagneticField* fld = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); if (!fld) { LOG(FATAL) << "Magnetic field is not initialized!"; - return false; + return; } mField = 0.1 * fld->solenoidField(); // kGauss -> Tesla - return true; -} - -//_____________________________________________________________________________ -float CommonParam::GetOmegaTau(float vdrift) -{ - /* - // - // Returns omega*tau (tan(Lorentz-angle)) for a given drift - // velocity <vdrift> for Xe/CO2 (15%). - // The values are according to a GARFIELD simulation. - // - - AliMagF* fld = (AliMagF *) TGeoGlobalMagField::Instance()->GetField(); - if (!fld) { - return 0.0; - } - double bz = 0.1 * fld->SolenoidField(); // kGauss -> Tesla - double fieldAbs = TMath::Abs(bz); - double fieldSgn = (bz > 0.0) ? 1.0 : -1.0; - - const int kNb = 5; - float p0[kNb] = { 0.004810, 0.007412, 0.010252, 0.013409, 0.016888 }; - float p1[kNb] = { 0.054875, 0.081534, 0.107333, 0.131983, 0.155455 }; - float p2[kNb] = { -0.008682, -0.012896, -0.016987, -0.020880, -0.024623 }; - float p3[kNb] = { 0.000155, 0.000238, 0.000330, 0.000428, 0.000541 }; - - // No ExB if field is too small (or zero) - if (fieldAbs < 0.01) { - - return 0.0; - - } - // Calculate ExB from parametrization - else if (IsXenon()) { - - int ib = ((int) (10 * (fieldAbs - 0.15))); - ib = TMath::Max( 0,ib); - ib = TMath::Min(kNb-1,ib); - - float alphaL = p0[ib] - + p1[ib] * vdrift - + p2[ib] * vdrift*vdrift - + p3[ib] * vdrift*vdrift*vdrift; - - return TMath::Tan(fieldSgn * alphaL); - - } - else if (IsArgon()) { - - return 0.0219769; - - } - - return 0.0; - */ - return 0.; // fix compiler warning -} - -//_____________________________________________________________________________ -bool CommonParam::GetDiffCoeff(float& dl, float& dt, float vdrift) -{ - // - // Calculates the diffusion coefficients in longitudinal <dl> and - // transverse <dt> direction for a given drift velocity <vdrift> - // - - // Nothing to do - if (TMath::Abs(mDiffLastVdrift - vdrift) < 0.001) { - dl = mDiffusionL; - dt = mDiffusionT; - return true; - } - mDiffLastVdrift = vdrift; - - if (IsXenon()) { - // - // Vd and B-field dependent diffusion and Lorentz angle - // - - // kNb = kNb = kNb - constexpr int kNb = 5; - - // If looking at compatibility with AliRoot: - // ibL and ibT are calculated the same way so, just define ib = ibL = ibT - int ib = ((int)(10 * (mField - 0.15))); - ib = TMath::Max(0, ib); - ib = TMath::Min(kNb - 1, ib); - - // DiffusionT - constexpr float p0T[kNb] = {0.009550, 0.009599, 0.009674, 0.009757, 0.009850}; - constexpr float p1T[kNb] = {0.006667, 0.006539, 0.006359, 0.006153, 0.005925}; - constexpr float p2T[kNb] = {-0.000853, -0.000798, -0.000721, -0.000635, -0.000541}; - constexpr float p3T[kNb] = {0.000131, 0.000122, 0.000111, 0.000098, 0.000085}; - // DiffusionL - constexpr float p0L[kNb] = {0.007440, 0.007493, 0.007513, 0.007672, 0.007831}; - constexpr float p1L[kNb] = {0.019252, 0.018912, 0.018636, 0.018012, 0.017343}; - constexpr float p2L[kNb] = {-0.005042, -0.004926, -0.004867, -0.004650, -0.004424}; - constexpr float p3L[kNb] = {0.000195, 0.000189, 0.000195, 0.000182, 0.000169}; - - float v2 = vdrift * vdrift; - float v3 = v2 * vdrift; - mDiffusionL = p0L[ib] + p1L[ib] * vdrift + p2L[ib] * v2 + p3L[ib] * v3; - mDiffusionT = p0T[ib] + p1T[ib] * vdrift + p2T[ib] * v2 + p3T[ib] * v3; - - dl = mDiffusionL; - dt = mDiffusionT; - return true; - } else if (IsArgon()) { - // - // Diffusion constants and Lorentz angle only for B = 0.5T - // - mDiffusionL = 0.0182; - mDiffusionT = 0.0159; - dl = mDiffusionL; - dt = mDiffusionT; - return true; - } else { - return false; - } -} - -//_____________________________________________________________________________ -double CommonParam::TimeStruct(float vdrift, double dist, double z) -{ - // - // Applies the time structure of the drift cells (by C.Lippmann). - // The drift time of electrons to the anode wires depends on the - // distance to the wire (z) and on the position in the drift region. - // - // input : - // dist = radial distance from (cathode) pad plane [cm] - // z = distance from anode wire (parallel to cathode planes) [cm] - // - // output : - // tdrift = the drift time of an electron at the given position - // - // We interpolate between the drift time values at the two drift - // velocities fVDlo and fVDhi, being smaller and larger than - // fDriftVelocity. We use the two stored drift time maps fTimeStruct1 - // and fTimeStruct2, calculated for the two mentioned drift velocities. - // - - SampleTimeStruct(vdrift); - - // Indices: - int r1 = (int)(10 * dist); - if (r1 < 0) { - r1 = 0; - } - if (r1 > 37) { - r1 = 37; - } - int r2 = r1 + 1; - if (r2 > 37) { - r2 = 37; - } - const int kz1 = ((int)(100 * z / 2.5)); - const int kz2 = kz1 + 1; - - if ((r1 < 0) || (r1 > 37) || (kz1 < 0) || (kz1 > 10)) { - LOG(INFO) << Form("Indices out of range: dist=%.2f, z=%.2f, r1=%d, kz1=%d", dist, z, r1, kz1); - } - - const float ky111 = mTimeStruct1[r1 + 38 * kz1]; - const float ky221 = ((r2 <= 37) && (kz2 <= 10)) ? mTimeStruct1[r2 + 38 * kz2] : mTimeStruct1[37 + 38 * 10]; - const float ky121 = (kz2 <= 10) ? mTimeStruct1[r1 + 38 * kz2] : mTimeStruct1[r1 + 38 * 10]; - const float ky211 = mTimeStruct1[r2 + 38 * kz1]; - - const float ky112 = mTimeStruct2[r1 + 38 * kz1]; - const float ky222 = ((r2 <= 37) && (kz2 <= 10)) ? mTimeStruct2[r2 + 38 * kz2] : mTimeStruct2[37 + 38 * 10]; - const float ky122 = (kz2 <= 10) ? mTimeStruct2[r1 + 38 * kz2] : mTimeStruct2[r1 + 38 * 10]; - const float ky212 = mTimeStruct2[r2 + 38 * kz1]; - - // Interpolation in dist-directions, lower drift time map - const float ky11 = (ky211 - ky111) * 10 * dist + ky111 - (ky211 - ky111) * r1; - const float ky21 = (ky221 - ky121) * 10 * dist + ky121 - (ky221 - ky121) * r1; - - // Interpolation in dist-direction, larger drift time map - const float ky12 = (ky212 - ky112) * 10 * dist + ky112 - (ky212 - ky112) * r1; - const float ky22 = (ky222 - ky122) * 10 * dist + ky122 - (ky222 - ky122) * r1; - - // Dist now is the drift distance to the anode wires (negative if electrons are - // between anode wire plane and cathode pad plane) - dist -= Geometry::amThick() / 2.0; - - // Interpolation in z-directions, lower drift time map - const float ktdrift1 = - ((TMath::Abs(dist) > 0.005) || (z > 0.005)) ? (ky21 - ky11) * 100 * z / 2.5 + ky11 - (ky21 - ky11) * kz1 : 0.0; - // Interpolation in z-directions, larger drift time map - const float ktdrift2 = - ((TMath::Abs(dist) > 0.005) || (z > 0.005)) ? (ky22 - ky12) * 100 * z / 2.5 + ky12 - (ky22 - ky12) * kz1 : 0.0; - - // Interpolation between the values at fVDlo and fVDhi - float a = (ktdrift2 - ktdrift1) / (mVDhi - mVDlo); - float b = ktdrift2 - a * mVDhi; - float t = a * vdrift + b; - - return t; } -//_____________________________________________________________________________ -void CommonParam::SampleTimeStruct(float vdrift) -{ - // - // Samples the timing structure of a drift cell - // Drift Time data calculated with Garfield (by C.Lippmann) - // - - // Nothing to do - if (TMath::Abs(mTimeLastVdrift - vdrift) < 1.e-3) { - return; - } - mTimeLastVdrift = vdrift; - - // Drift time maps are saved for some drift velocity values (in drift region): - float fVDsmp[8]; - fVDsmp[0] = 1.032; - fVDsmp[1] = 1.158; - fVDsmp[2] = 1.299; - fVDsmp[3] = 1.450; - fVDsmp[4] = 1.610; - fVDsmp[5] = 1.783; - fVDsmp[6] = 1.959; - fVDsmp[7] = 2.134; - - if (vdrift < fVDsmp[0]) { - LOG(INFO) << Form("Drift Velocity too small (%.3f<%.3f)", vdrift, fVDsmp[0]); - vdrift = fVDsmp[0]; - } else if (vdrift > fVDsmp[7]) { - LOG(INFO) << Form("Drift Velocity too large (%.3f>%.3f)", vdrift, fVDsmp[6]); - vdrift = fVDsmp[7]; - } - - const int ktimebin = 38; - const int kZbin = 11; - - // Garfield simulation at UD = -1500V; vd = 1.032cm/microsec, <driftfield> = 525V/cm - float time1500[ktimebin][kZbin] = { - {0.09170, 0.09205, 0.09306, 0.09475, 0.09716, 0.10035, 0.10445, 0.10993, 0.11838, 0.13986, 0.37858}, - {0.06588, 0.06626, 0.06739, 0.06926, 0.07186, 0.07524, 0.07951, 0.08515, 0.09381, 0.11601, 0.35673}, - {0.03946, 0.04003, 0.04171, 0.04435, 0.04780, 0.05193, 0.05680, 0.06306, 0.07290, 0.09873, 0.34748}, - {0.01151, 0.01283, 0.01718, 0.02282, 0.02880, 0.03479, 0.04098, 0.04910, 0.06413, 0.10567, 0.36897}, - {0.01116, 0.01290, 0.01721, 0.02299, 0.02863, 0.03447, 0.04074, 0.04984, 0.06839, 0.11625, 0.37277}, - {0.03919, 0.03974, 0.04131, 0.04380, 0.04703, 0.05102, 0.05602, 0.06309, 0.07651, 0.10938, 0.36838}, - {0.06493, 0.06560, 0.06640, 0.06802, 0.07051, 0.07392, 0.07853, 0.08510, 0.09690, 0.12621, 0.38058}, - {0.09174, 0.09186, 0.09225, 0.09303, 0.09477, 0.00000, 0.11205, 0.11952, 0.13461, 0.16984, 0.43017}, - {0.14356, 0.14494, 0.14959, 0.16002, 0.18328, 0.27981, 0.22785, 0.21240, 0.21948, 0.25965, 0.52392}, - {0.23120, 0.23366, 0.24046, 0.25422, 0.28071, 0.36914, 0.32999, 0.31208, 0.31772, 0.35804, 0.62249}, - {0.32686, 0.32916, 0.33646, 0.35053, 0.37710, 0.46292, 0.42773, 0.40948, 0.41497, 0.45527, 0.71955}, - {0.42353, 0.42583, 0.43317, 0.44727, 0.47380, 0.55884, 0.52479, 0.50650, 0.51194, 0.55225, 0.81658}, - {0.52038, 0.52271, 0.53000, 0.54415, 0.57064, 0.65545, 0.62172, 0.60341, 0.60885, 0.64915, 0.91339}, - {0.61724, 0.61953, 0.62694, 0.64098, 0.66756, 0.75226, 0.71862, 0.70030, 0.70575, 0.74604, 1.01035}, - {0.71460, 0.71678, 0.72376, 0.73786, 0.76447, 0.84913, 0.81551, 0.79720, 0.80264, 0.84292, 1.10723}, - {0.81101, 0.81334, 0.82066, 0.83475, 0.86127, 0.94599, 0.91240, 0.89408, 0.89952, 0.93981, 1.20409}, - {0.90788, 0.91023, 0.91752, 0.93163, 0.95815, 1.04293, 1.00929, 0.99096, 0.99640, 1.03669, 1.30106}, - {1.00477, 1.00707, 1.01449, 1.02852, 1.05504, 1.13976, 1.10617, 1.08784, 1.09329, 1.13358, 1.39796}, - {1.10166, 1.10397, 1.11130, 1.12541, 1.15257, 1.23672, 1.20307, 1.18472, 1.19018, 1.23046, 1.49486}, - {1.19854, 1.20084, 1.20818, 1.22235, 1.24885, 1.33355, 1.29992, 1.28156, 1.28707, 1.32735, 1.59177}, - {1.29544, 1.29780, 1.30507, 1.31917, 1.34575, 1.43073, 1.39681, 1.37851, 1.38396, 1.42377, 1.68854}, - {1.39236, 1.39462, 1.40205, 1.41607, 1.44259, 1.52745, 1.49368, 1.47541, 1.48083, 1.52112, 1.78546}, - {1.49314, 1.49149, 1.49885, 1.51297, 1.53949, 1.62420, 1.59016, 1.57231, 1.57772, 1.61800, 1.88048}, - {1.58610, 1.58839, 1.59572, 1.60983, 1.63635, 1.72109, 1.68651, 1.66921, 1.67463, 1.71489, 1.97918}, - {1.68400, 1.68529, 1.69261, 1.70671, 1.73331, 1.81830, 1.78341, 1.76605, 1.77150, 1.81179, 2.07608}, - {1.77991, 1.78215, 1.78952, 1.80385, 1.83014, 1.91486, 1.88128, 1.86215, 1.86837, 1.90865, 2.17304}, - {1.87674, 1.87904, 1.88647, 1.90052, 1.92712, 2.01173, 1.97812, 1.95905, 1.96527, 2.00710, 2.26979}, - {1.97369, 1.97594, 1.98326, 1.99869, 2.02442, 2.10865, 2.07501, 2.05666, 2.06214, 2.10243, 2.36669}, - {2.07052, 2.07281, 2.08016, 2.09425, 2.12132, 2.20555, 2.17182, 2.15341, 2.15904, 2.19933, 2.46363}, - {2.16742, 2.16971, 2.17707, 2.19114, 2.21766, 2.30240, 2.26877, 2.25015, 2.25573, 2.29586, 2.56060}, - {2.26423, 2.26659, 2.27396, 2.28803, 2.31456, 2.40828, 2.36567, 2.34705, 2.35282, 2.39765, 2.65744}, - {2.36153, 2.36349, 2.37330, 2.38501, 2.41159, 2.49940, 2.46257, 2.44420, 2.44843, 2.48987, 2.75431}, - {2.46558, 2.46035, 2.46822, 2.48181, 2.50849, 2.59630, 2.55947, 2.54112, 2.54513, 2.58677, 2.85094}, - {2.56248, 2.55723, 2.56486, 2.57871, 2.60520, 2.68998, 2.65626, 2.63790, 2.64316, 2.68360, 2.94813}, - {2.65178, 2.65441, 2.66153, 2.67556, 2.70210, 2.78687, 2.75319, 2.73463, 2.74032, 2.78060, 3.04503}, - {2.74868, 2.75131, 2.75870, 2.77245, 2.79385, 2.88700, 2.85009, 2.83177, 2.83723, 2.87750, 3.14193}, - {2.84574, 2.84789, 2.85560, 2.86935, 2.89075, 2.98060, 2.94576, 2.92868, 2.93356, 2.97436, 3.23868}, - {2.94239, 2.94469, 2.95221, 2.96625, 2.99345, 3.07747, 3.04266, 3.02545, 3.03051, 3.07118, 3.33555}}; - - // Garfield simulation at UD = -1600V; vd = 1.158cm/microsec, <driftfield> = 558V/cm - float time1600[ktimebin][kZbin] = { - {0.09169, 0.09203, 0.09305, 0.09473, 0.09714, 0.10032, 0.10441, 0.10990, 0.11835, 0.13986, 0.37845}, - {0.06589, 0.06626, 0.06738, 0.06924, 0.07184, 0.07521, 0.07947, 0.08512, 0.09379, 0.11603, 0.35648}, - {0.03947, 0.04003, 0.04171, 0.04434, 0.04778, 0.05190, 0.05678, 0.06304, 0.07292, 0.09876, 0.34759}, - {0.01111, 0.01281, 0.01718, 0.02281, 0.02879, 0.03477, 0.04097, 0.04910, 0.06415, 0.10573, 0.36896}, - {0.01120, 0.01311, 0.01721, 0.02279, 0.02862, 0.03446, 0.04074, 0.04981, 0.06825, 0.11595, 0.37255}, - {0.03919, 0.03980, 0.04132, 0.04380, 0.04704, 0.05102, 0.05602, 0.06302, 0.07633, 0.10896, 0.36743}, - {0.06531, 0.06528, 0.06631, 0.06805, 0.07053, 0.07392, 0.07853, 0.08505, 0.09669, 0.12578, 0.37967}, - {0.09157, 0.09171, 0.09216, 0.09301, 0.09475, 0.00000, 0.11152, 0.11879, 0.13352, 0.16802, 0.42750}, - {0.13977, 0.14095, 0.14509, 0.15433, 0.17534, 0.26406, 0.21660, 0.20345, 0.21113, 0.25067, 0.51434}, - {0.21816, 0.22041, 0.22631, 0.23850, 0.26208, 0.34340, 0.30755, 0.29237, 0.29878, 0.33863, 0.60258}, - {0.30344, 0.30547, 0.31241, 0.32444, 0.34809, 0.42696, 0.39464, 0.37919, 0.38546, 0.42530, 0.68926}, - {0.38969, 0.39164, 0.39810, 0.41059, 0.43441, 0.51246, 0.48112, 0.46562, 0.47191, 0.51172, 0.77558}, - {0.47592, 0.47799, 0.48442, 0.49689, 0.52061, 0.59855, 0.56752, 0.55201, 0.55826, 0.59808, 0.86202}, - {0.56226, 0.56428, 0.57074, 0.58324, 0.60696, 0.68483, 0.65388, 0.63837, 0.64461, 0.68445, 0.94830}, - {0.64881, 0.65063, 0.65709, 0.66958, 0.69331, 0.77117, 0.74023, 0.72472, 0.73098, 0.77079, 1.03486}, - {0.73506, 0.73698, 0.74344, 0.75596, 0.77964, 0.85751, 0.82658, 0.81107, 0.81731, 0.85712, 1.12106}, - {0.82132, 0.82333, 0.82979, 0.84228, 0.86608, 0.94386, 0.91293, 0.89742, 0.90367, 0.94335, 1.20737}, - {0.90767, 0.90968, 0.91614, 0.92863, 0.95236, 1.03021, 0.99928, 0.98377, 0.99001, 1.02984, 1.29371}, - {0.99410, 0.99602, 1.00257, 1.01498, 1.03869, 1.11720, 1.08563, 1.07011, 1.07637, 1.11621, 1.37873}, - {1.08036, 1.08240, 1.08884, 1.10138, 1.12504, 1.20301, 1.17198, 1.15647, 1.16272, 1.20255, 1.46651}, - {1.16670, 1.16872, 1.17525, 1.18783, 1.21139, 1.28934, 1.25833, 1.24281, 1.24909, 1.28889, 1.55275}, - {1.25307, 1.25510, 1.26153, 1.27404, 1.29773, 1.37584, 1.34469, 1.32916, 1.33536, 1.37524, 1.63915}, - {1.33942, 1.34146, 1.34788, 1.36040, 1.38410, 1.46438, 1.43105, 1.41537, 1.42176, 1.46158, 1.72538}, - {1.42579, 1.42782, 1.43458, 1.44674, 1.47043, 1.55085, 1.51675, 1.50168, 1.50810, 1.54793, 1.81174}, - {1.51207, 1.51454, 1.52060, 1.53307, 1.55684, 1.63478, 1.60336, 1.58820, 1.59446, 1.63414, 1.89814}, - {1.59856, 1.60047, 1.60693, 1.61942, 1.64317, 1.72257, 1.69008, 1.67454, 1.68080, 1.72063, 1.98433}, - {1.68481, 1.68682, 1.69330, 1.70584, 1.72949, 1.80752, 1.77643, 1.76089, 1.76716, 1.80692, 2.07069}, - {1.77117, 1.77319, 1.77969, 1.79260, 1.81583, 1.89376, 1.86226, 1.84720, 1.85355, 1.89256, 2.15343}, - {1.85748, 1.85967, 1.86605, 1.87848, 1.90222, 1.98010, 1.94913, 1.93271, 1.93981, 1.97968, 2.24355}, - {1.94386, 1.94587, 1.95233, 1.96484, 1.98854, 2.06646, 2.03542, 2.01755, 2.02617, 2.06604, 2.32993}, - {2.03022, 2.03230, 2.03868, 2.05134, 2.07488, 2.15367, 2.12178, 2.10391, 2.11252, 2.15432, 2.41623}, - {2.11656, 2.11857, 2.12505, 2.13772, 2.16147, 2.23919, 2.20817, 2.19265, 2.20744, 2.23872, 2.49996}, - {2.20291, 2.20611, 2.21137, 2.22387, 2.24758, 2.32563, 2.29450, 2.27901, 2.28525, 2.32507, 2.58897}, - {2.28922, 2.29172, 2.29774, 2.31345, 2.33400, 2.41287, 2.38086, 2.36535, 2.37160, 2.40869, 2.67113}, - {2.37572, 2.37764, 2.38410, 2.39803, 2.42046, 2.49817, 2.46721, 2.45171, 2.45794, 2.49505, 2.76061}, - {2.46190, 2.46396, 2.47043, 2.48340, 2.50665, 2.58453, 2.55357, 2.53728, 2.54430, 2.58407, 2.84816}, - {2.54833, 2.55032, 2.55679, 2.56976, 2.59312, 2.67103, 2.63993, 2.62364, 2.63062, 2.67040, 2.93444}, - {2.63456, 2.63660, 2.64304, 2.65555, 2.67938, 2.75739, 2.72629, 2.71064, 2.71688, 2.75671, 3.01886}}; - - // Garfield simulation at UD = -1700V; vd = 1.299cm/microsec, <driftfield> = 590V/cm - float time1700[ktimebin][kZbin] = { - {0.09167, 0.09201, 0.09302, 0.09471, 0.09712, 0.10029, 0.10438, 0.10986, 0.11832, 0.13986, 0.37824}, - {0.06591, 0.06626, 0.06736, 0.06923, 0.07183, 0.07519, 0.07944, 0.08511, 0.09378, 0.11603, 0.35625}, - {0.03946, 0.04003, 0.04170, 0.04433, 0.04777, 0.05189, 0.05676, 0.06301, 0.07291, 0.09880, 0.34724}, - {0.01110, 0.01281, 0.01718, 0.02280, 0.02879, 0.03476, 0.04096, 0.04910, 0.06417, 0.10582, 0.36861}, - {0.01115, 0.01294, 0.01721, 0.02276, 0.02862, 0.03447, 0.04074, 0.04980, 0.06812, 0.11565, 0.37231}, - {0.03920, 0.03974, 0.04133, 0.04381, 0.04706, 0.05105, 0.05603, 0.06299, 0.07618, 0.10860, 0.36646}, - {0.06498, 0.06529, 0.06634, 0.06808, 0.07055, 0.07395, 0.07852, 0.08500, 0.09650, 0.12532, 0.37850}, - {0.09143, 0.09159, 0.09207, 0.09297, 0.09473, 0.00000, 0.11102, 0.11809, 0.13245, 0.16627, 0.42496}, - {0.13646, 0.13750, 0.14112, 0.14926, 0.16806, 0.24960, 0.20627, 0.19536, 0.20366, 0.24256, 0.50557}, - {0.20678, 0.20848, 0.21384, 0.22450, 0.24552, 0.32018, 0.28740, 0.27477, 0.28196, 0.32128, 0.58475}, - {0.28287, 0.28461, 0.29020, 0.30108, 0.32224, 0.39467, 0.36500, 0.35217, 0.35926, 0.39860, 0.66194}, - {0.35972, 0.36145, 0.36713, 0.37797, 0.39912, 0.47091, 0.44212, 0.42925, 0.43632, 0.47563, 0.73892}, - {0.43667, 0.43841, 0.44413, 0.45494, 0.47607, 0.54780, 0.51912, 0.50627, 0.51334, 0.55254, 0.81595}, - {0.51365, 0.51540, 0.52101, 0.53193, 0.55305, 0.62463, 0.59617, 0.58328, 0.59035, 0.62965, 0.89303}, - {0.59064, 0.59240, 0.59801, 0.60893, 0.63009, 0.70169, 0.67317, 0.66028, 0.66735, 0.70666, 0.96995}, - {0.66765, 0.66939, 0.67501, 0.68592, 0.70724, 0.77863, 0.75016, 0.73728, 0.74435, 0.78366, 1.04696}, - {0.74464, 0.74636, 0.75200, 0.76293, 0.78405, 0.85561, 0.82716, 0.81427, 0.82133, 0.86064, 1.12396}, - {0.82165, 0.82340, 0.82902, 0.83991, 0.86104, 0.93266, 0.90414, 0.89128, 0.89834, 0.93763, 1.20100}, - {0.89863, 0.90042, 0.90659, 0.91705, 0.93805, 1.00960, 0.98115, 0.96825, 0.97533, 1.01462, 1.27801}, - {0.97563, 0.97740, 0.98310, 0.99391, 1.01504, 1.08659, 1.05814, 1.04526, 1.05233, 1.09163, 1.35503}, - {1.05276, 1.05451, 1.06002, 1.07090, 1.09099, 1.16357, 1.13516, 1.12225, 1.12933, 1.16863, 1.43195}, - {1.12977, 1.13138, 1.13700, 1.14792, 1.16797, 1.24061, 1.21212, 1.19926, 1.20626, 1.24554, 1.50900}, - {1.20664, 1.20839, 1.21400, 1.22490, 1.24606, 1.31772, 1.28914, 1.27382, 1.28329, 1.32262, 1.58550}, - {1.28367, 1.28541, 1.29099, 1.30189, 1.32312, 1.39460, 1.36612, 1.34924, 1.36030, 1.39961, 1.66310}, - {1.36064, 1.36249, 1.36799, 1.37896, 1.40004, 1.48030, 1.44314, 1.43032, 1.43731, 1.47659, 1.73442}, - {1.43762, 1.43937, 1.44497, 1.45618, 1.47704, 1.54932, 1.52012, 1.50725, 1.51430, 1.55357, 1.81708}, - {1.51462, 1.51937, 1.52203, 1.53316, 1.55403, 1.62572, 1.59713, 1.58424, 1.59128, 1.63061, 1.89406}, - {1.59162, 1.59338, 1.59947, 1.60989, 1.63103, 1.70270, 1.67411, 1.66124, 1.66799, 1.70759, 1.97103}, - {1.66874, 1.67037, 1.67597, 1.68687, 1.70814, 1.77969, 1.75112, 1.73806, 1.74530, 1.78457, 2.04794}, - {1.74693, 1.74749, 1.75297, 1.76476, 1.78500, 1.85667, 1.82811, 1.81504, 1.82101, 1.86161, 2.12492}, - {1.82260, 1.82437, 1.82995, 1.84174, 1.86202, 1.93372, 1.90509, 1.89202, 1.89930, 1.93859, 2.20189}, - {1.89964, 1.90135, 1.90693, 1.91789, 1.93952, 2.01080, 1.98207, 1.96921, 1.97628, 2.01384, 2.27887}, - {1.97662, 1.97917, 1.98611, 1.99487, 2.01601, 2.08778, 2.05846, 2.04623, 2.05330, 2.09244, 2.35585}, - {2.05359, 2.05615, 2.06309, 2.07187, 2.09867, 2.16459, 2.13610, 2.12322, 2.13029, 2.16942, 2.43199}, - {2.13063, 2.13233, 2.13795, 2.14886, 2.17008, 2.24199, 2.21310, 2.20020, 2.20727, 2.24659, 2.50983}, - {2.20761, 2.20931, 2.21955, 2.22624, 2.24708, 2.32147, 2.29009, 2.27725, 2.28276, 2.32359, 2.58680}, - {2.28459, 2.29108, 2.29202, 2.30286, 2.32007, 2.39559, 2.36683, 2.35422, 2.36119, 2.40058, 2.66081}, - {2.36153, 2.36806, 2.36889, 2.37985, 2.40092, 2.47828, 2.44381, 2.43099, 2.43819, 2.47750, 2.73779}}; - - // Garfield simulation at UD = -1800V; vd = 1.450cm/microsec, <driftfield> = 623V/cm - float time1800[ktimebin][kZbin] = { - {0.09166, 0.09199, 0.09300, 0.09470, 0.09709, 0.10026, 0.10434, 0.10983, 0.11831, 0.13987, 0.37802}, - {0.06585, 0.06623, 0.06735, 0.06921, 0.07180, 0.07520, 0.07941, 0.08507, 0.09376, 0.11604, 0.35624}, - {0.03945, 0.04004, 0.04169, 0.04432, 0.04776, 0.05187, 0.05674, 0.06300, 0.07290, 0.09884, 0.34704}, - {0.01108, 0.01287, 0.01717, 0.02280, 0.02880, 0.03476, 0.04095, 0.04909, 0.06419, 0.10589, 0.36843}, - {0.01115, 0.01287, 0.01720, 0.02276, 0.02862, 0.03448, 0.04073, 0.04973, 0.06799, 0.11535, 0.37224}, - {0.03918, 0.03975, 0.04134, 0.04382, 0.04707, 0.05105, 0.05603, 0.06296, 0.07605, 0.10822, 0.36560}, - {0.06498, 0.06532, 0.06635, 0.06809, 0.07058, 0.07395, 0.07855, 0.08495, 0.09632, 0.12488, 0.37730}, - {0.09130, 0.09160, 0.09199, 0.09300, 0.09472, 0.00000, 0.11059, 0.11747, 0.13146, 0.16462, 0.42233}, - {0.13364, 0.13449, 0.13767, 0.14481, 0.16147, 0.23635, 0.19706, 0.18812, 0.19704, 0.23520, 0.49749}, - {0.19698, 0.19844, 0.20311, 0.21236, 0.23082, 0.29920, 0.26936, 0.25927, 0.26732, 0.30601, 0.56871}, - {0.26518, 0.26670, 0.27160, 0.28099, 0.29955, 0.36597, 0.33885, 0.32858, 0.33653, 0.37524, 0.63801}, - {0.33441, 0.33553, 0.34040, 0.34987, 0.36841, 0.43428, 0.40797, 0.39763, 0.40556, 0.44425, 0.70698}, - {0.40296, 0.40447, 0.40934, 0.41881, 0.43737, 0.50306, 0.47695, 0.46662, 0.47455, 0.51329, 0.77600}, - {0.47296, 0.47344, 0.47830, 0.48779, 0.50632, 0.57200, 0.54593, 0.53559, 0.54351, 0.58222, 0.84489}, - {0.54089, 0.54264, 0.54727, 0.55673, 0.57529, 0.64094, 0.61490, 0.60457, 0.61249, 0.65118, 0.91394}, - {0.60987, 0.61138, 0.61624, 0.62573, 0.64428, 0.70989, 0.68397, 0.67354, 0.68147, 0.72015, 0.98291}, - {0.67883, 0.68035, 0.68521, 0.69469, 0.71324, 0.77896, 0.75287, 0.74251, 0.75043, 0.78912, 1.04458}, - {0.74780, 0.74932, 0.75421, 0.76367, 0.78221, 0.84785, 0.82185, 0.81148, 0.81941, 0.85811, 1.12085}, - {0.81690, 0.81830, 0.82316, 0.83263, 0.85120, 0.91683, 0.89077, 0.88045, 0.88837, 0.92707, 1.18976}, - {0.88574, 0.88726, 0.89228, 0.90198, 0.92017, 0.98578, 0.95974, 0.94947, 0.95734, 0.99604, 1.25873}, - {0.95493, 0.95624, 0.96110, 0.97058, 0.98913, 1.05481, 1.02873, 1.01839, 1.02631, 1.06503, 1.32772}, - {1.02392, 1.02524, 1.03008, 1.03955, 1.05810, 1.12378, 1.09757, 1.08605, 1.09530, 1.13399, 1.39669}, - {1.09270, 1.09418, 1.09911, 1.10854, 1.12714, 1.19281, 1.16502, 1.15633, 1.16427, 1.20271, 1.46574}, - {1.16168, 1.16323, 1.16801, 1.17772, 1.19604, 1.26190, 1.23399, 1.22531, 1.23323, 1.27194, 1.53475}, - {1.23061, 1.23214, 1.23698, 1.24669, 1.26503, 1.33073, 1.30461, 1.29428, 1.30220, 1.34091, 1.60372}, - {1.29960, 1.30110, 1.30596, 1.31544, 1.33398, 1.39962, 1.37228, 1.36323, 1.37121, 1.40988, 1.67273}, - {1.36851, 1.37007, 1.37512, 1.38441, 1.40297, 1.46865, 1.44256, 1.43222, 1.44017, 1.47878, 1.74155}, - {1.43752, 1.43904, 1.44773, 1.45338, 1.47220, 1.53759, 1.51136, 1.50119, 1.50914, 1.54775, 1.81050}, - {1.50646, 1.50802, 1.51288, 1.52237, 1.54097, 1.60697, 1.58049, 1.57018, 1.57811, 1.61678, 1.87947}, - {1.57545, 1.57720, 1.58185, 1.59134, 1.60996, 1.67787, 1.64929, 1.63914, 1.64707, 1.68570, 1.94851}, - {1.64442, 1.64617, 1.65081, 1.66035, 1.67893, 1.74684, 1.71826, 1.70745, 1.71604, 1.75310, 2.01748}, - {1.71337, 1.71513, 1.71978, 1.72932, 1.74645, 1.81346, 1.78739, 1.77642, 1.78501, 1.82151, 2.08644}, - {1.78238, 1.78410, 1.78876, 1.79824, 1.81678, 1.88332, 1.85639, 1.84262, 1.85397, 1.89270, 2.15533}, - {1.85135, 1.85306, 1.85778, 1.86728, 1.88580, 1.95615, 1.92536, 1.91171, 1.92283, 1.96165, 2.22428}, - {1.92774, 1.92184, 1.92672, 1.93618, 1.95477, 2.02048, 1.99427, 1.98068, 1.99192, 2.03062, 2.29338}, - {1.98929, 1.99081, 1.99567, 2.00515, 2.02373, 2.08987, 2.06332, 2.05249, 2.05939, 2.09928, 2.36227}, - {2.05829, 2.05978, 2.06464, 2.07414, 2.09272, 2.15850, 2.12928, 2.12194, 2.12987, 2.16825, 2.43083}, - {2.12726, 2.12869, 2.13360, 2.14425, 2.16160, 2.22872, 2.20118, 2.19078, 2.19876, 2.23416, 2.50007}}; - - // Garfield simulation at UD = -1900V; vd = 1.610cm/microsec, <driftfield> = 655V/cm - float time1900[ktimebin][kZbin] = { - {0.09166, 0.09198, 0.09298, 0.09467, 0.09707, 0.10023, 0.10431, 0.10980, 0.11828, 0.13988, 0.37789}, - {0.06584, 0.06622, 0.06735, 0.06920, 0.07179, 0.07514, 0.07938, 0.08505, 0.09374, 0.11606, 0.35599}, - {0.03945, 0.04002, 0.04169, 0.04432, 0.04775, 0.05185, 0.05672, 0.06298, 0.07290, 0.09888, 0.34695}, - {0.01109, 0.01281, 0.01717, 0.02279, 0.02878, 0.03476, 0.04094, 0.04909, 0.06421, 0.10597, 0.36823}, - {0.01115, 0.01287, 0.01720, 0.02294, 0.02862, 0.03448, 0.04074, 0.04973, 0.06783, 0.11506, 0.37206}, - {0.03940, 0.03975, 0.04135, 0.04386, 0.04708, 0.05106, 0.05604, 0.06293, 0.07592, 0.10787, 0.36484}, - {0.06500, 0.06534, 0.06638, 0.06811, 0.07060, 0.07413, 0.07852, 0.08491, 0.09614, 0.12446, 0.37626}, - {0.09119, 0.09140, 0.09194, 0.09293, 0.09471, 0.00000, 0.11013, 0.11685, 0.13050, 0.16302, 0.41991}, - {0.13111, 0.13190, 0.13466, 0.14091, 0.15554, 0.22409, 0.18846, 0.18167, 0.19113, 0.22854, 0.48995}, - {0.18849, 0.18975, 0.19380, 0.20185, 0.21797, 0.28050, 0.25368, 0.24575, 0.25446, 0.29249, 0.55442}, - {0.24995, 0.25125, 0.25563, 0.26366, 0.27986, 0.34065, 0.31605, 0.30815, 0.31680, 0.35482, 0.61697}, - {0.31187, 0.31324, 0.31745, 0.32580, 0.34205, 0.40217, 0.37825, 0.37031, 0.37897, 0.41696, 0.67890}, - {0.37401, 0.37531, 0.37955, 0.38777, 0.40395, 0.46408, 0.44037, 0.43242, 0.44108, 0.47906, 0.74122}, - {0.43610, 0.43741, 0.44161, 0.44986, 0.46604, 0.52614, 0.50248, 0.49452, 0.50316, 0.54116, 0.80326}, - {0.49820, 0.49988, 0.50372, 0.51196, 0.52814, 0.58822, 0.56459, 0.55661, 0.56527, 0.60326, 0.86526}, - {0.56032, 0.56161, 0.56582, 0.57408, 0.59024, 0.65032, 0.62670, 0.61872, 0.62737, 0.66537, 0.92749}, - {0.62240, 0.62371, 0.62792, 0.63624, 0.65236, 0.71241, 0.68881, 0.68081, 0.68947, 0.72750, 0.98941}, - {0.68449, 0.68581, 0.69002, 0.69828, 0.71444, 0.77452, 0.75089, 0.74295, 0.75157, 0.78957, 1.05157}, - {0.74660, 0.74790, 0.75212, 0.76036, 0.77654, 0.83748, 0.81299, 0.80501, 0.81193, 0.85168, 1.11375}, - {0.80870, 0.81017, 0.81423, 0.82246, 0.83867, 0.89908, 0.87509, 0.86660, 0.87577, 0.91376, 1.17586}, - {0.87080, 0.87233, 0.87632, 0.88458, 0.90074, 0.96083, 0.93718, 0.92922, 0.93787, 0.97588, 1.23794}, - {0.93291, 0.93422, 0.93844, 0.94667, 0.96293, 1.02295, 0.99929, 0.99127, 0.99997, 1.03797, 1.29995}, - {0.99500, 0.99645, 1.00308, 1.00877, 1.02497, 1.08504, 1.06140, 1.05343, 1.06203, 1.10006, 1.36216}, - {1.05712, 1.05926, 1.06262, 1.07092, 1.08706, 1.14754, 1.12350, 1.11550, 1.12417, 1.16218, 1.42427}, - {1.11921, 1.12059, 1.12473, 1.13297, 1.14916, 1.21140, 1.18560, 1.17284, 1.18625, 1.22414, 1.48629}, - {1.18140, 1.18262, 1.18690, 1.19508, 1.21125, 1.27139, 1.24164, 1.23495, 1.24838, 1.28634, 1.54852}, - {1.24340, 1.24473, 1.24901, 1.25732, 1.27336, 1.33358, 1.30793, 1.30179, 1.31047, 1.34848, 1.61066}, - {1.30551, 1.30684, 1.31104, 1.32056, 1.33553, 1.39609, 1.37004, 1.36392, 1.37045, 1.41057, 1.67259}, - {1.36755, 1.36892, 1.37315, 1.39148, 1.39755, 1.45820, 1.43215, 1.42602, 1.43467, 1.47268, 1.73477}, - {1.42966, 1.43101, 1.43549, 1.45359, 1.45976, 1.52031, 1.49601, 1.48811, 1.49677, 1.53477, 1.79691}, - {1.49180, 1.49321, 1.49760, 1.51570, 1.52175, 1.58185, 1.55771, 1.55023, 1.55888, 1.59672, 1.85501}, - {1.55391, 1.55527, 1.55943, 1.57782, 1.58391, 1.64395, 1.62008, 1.61233, 1.62085, 1.65883, 1.92091}, - {1.61599, 1.61732, 1.62154, 1.63993, 1.64612, 1.70608, 1.68237, 1.67108, 1.68301, 1.72110, 1.97931}, - {1.67808, 1.67948, 1.68364, 1.70204, 1.70823, 1.76858, 1.74404, 1.73539, 1.74512, 1.78321, 2.04522}, - {1.74019, 1.74152, 1.74573, 1.76415, 1.77015, 1.83040, 1.80615, 1.79366, 1.80723, 1.84509, 2.10742}, - {1.80235, 1.80362, 1.80783, 1.82626, 1.83227, 1.89246, 1.86795, 1.85405, 1.86938, 1.90720, 2.16953}, - {1.86442, 1.86572, 1.86994, 1.88837, 1.89438, 1.95445, 1.93006, 1.92283, 1.93148, 1.96931, 2.23147}, - {1.92700, 1.92783, 1.93197, 1.95049, 1.95649, 2.01668, 1.99217, 1.98486, 1.99352, 2.03143, 2.29358}}; - // Garfield simulation at UD = -2000V; vd = 1.783cm/microsec, <driftfield> = 688V/cm - float time2000[ktimebin][kZbin] = { - {0.09176, 0.09196, 0.09296, 0.09465, 0.09704, 0.10020, 0.10427, 0.10977, 0.11825, 0.13988, 0.37774}, - {0.06583, 0.06620, 0.06735, 0.06918, 0.07177, 0.07513, 0.07936, 0.08503, 0.09372, 0.11606, 0.35586}, - {0.03944, 0.04001, 0.04170, 0.04431, 0.04774, 0.05184, 0.05670, 0.06296, 0.07291, 0.09893, 0.34680}, - {0.01108, 0.01281, 0.01719, 0.02279, 0.02879, 0.03474, 0.04093, 0.04908, 0.06422, 0.10605, 0.36800}, - {0.01114, 0.01287, 0.01720, 0.02276, 0.02863, 0.03449, 0.04073, 0.04970, 0.06774, 0.11478, 0.37179}, - {0.03925, 0.03977, 0.04135, 0.04386, 0.04711, 0.05108, 0.05604, 0.06290, 0.07580, 0.10748, 0.36386}, - {0.06501, 0.06536, 0.06640, 0.06814, 0.07062, 0.07398, 0.07852, 0.08487, 0.09598, 0.12405, 0.37519}, - {0.09109, 0.09127, 0.09188, 0.09292, 0.09472, 0.00000, 0.10964, 0.11630, 0.12960, 0.16150, 0.41765}, - {0.12898, 0.12968, 0.13209, 0.13749, 0.15034, 0.21286, 0.18088, 0.17590, 0.18591, 0.22254, 0.48315}, - {0.18122, 0.18227, 0.18574, 0.19263, 0.20674, 0.26376, 0.23960, 0.23375, 0.24316, 0.28047, 0.54179}, - {0.23674, 0.23784, 0.24142, 0.24847, 0.26264, 0.31810, 0.29602, 0.29008, 0.29944, 0.33675, 0.59795}, - {0.29279, 0.29382, 0.29742, 0.30448, 0.31865, 0.37364, 0.35215, 0.34629, 0.35555, 0.39286, 0.65411}, - {0.34875, 0.34987, 0.35346, 0.36054, 0.37472, 0.42956, 0.40825, 0.40229, 0.41167, 0.44894, 0.71033}, - {0.40484, 0.40594, 0.40954, 0.41660, 0.43077, 0.48560, 0.46433, 0.45840, 0.46772, 0.50500, 0.76632}, - {0.46090, 0.46201, 0.46560, 0.47267, 0.48684, 0.54167, 0.52041, 0.51449, 0.52382, 0.56108, 0.82227}, - {0.51698, 0.51809, 0.52173, 0.52874, 0.54291, 0.59776, 0.57646, 0.57052, 0.57986, 0.61717, 0.87836}, - {0.57306, 0.57418, 0.57782, 0.58513, 0.59899, 0.65380, 0.63255, 0.62661, 0.63594, 0.67325, 0.93460}, - {0.62912, 0.63024, 0.63383, 0.64103, 0.65506, 0.70988, 0.68484, 0.68267, 0.69202, 0.72878, 0.99046}, - {0.68521, 0.68633, 0.68990, 0.69699, 0.71115, 0.76595, 0.74468, 0.73872, 0.74814, 0.78538, 1.04674}, - {0.74127, 0.74239, 0.74605, 0.75303, 0.77022, 0.82204, 0.80078, 0.79484, 0.80416, 0.84147, 1.10261}, - {0.79736, 0.79846, 0.80206, 0.80947, 0.82330, 0.87813, 0.85688, 0.85087, 0.86023, 0.89752, 1.15874}, - {0.85342, 0.85454, 0.85815, 0.86519, 0.87936, 0.93417, 0.91293, 0.90428, 0.91631, 0.95360, 1.20760}, - {0.90949, 0.91061, 0.91423, 0.92128, 0.93544, 0.99026, 0.96807, 0.96305, 0.97239, 1.00967, 1.27078}, - {0.96556, 0.96669, 0.97111, 0.97734, 0.99151, 1.04664, 1.02508, 1.01879, 1.02846, 1.06167, 1.32695}, - {1.02167, 1.02279, 1.02656, 1.03341, 1.04759, 1.10242, 1.08115, 1.07003, 1.08453, 1.12184, 1.38304}, - {1.07776, 1.07883, 1.08242, 1.08950, 1.10384, 1.16422, 1.13725, 1.13133, 1.14061, 1.17793, 1.43910}, - {1.13379, 1.13492, 1.13864, 1.14567, 1.15973, 1.21455, 1.19323, 1.18734, 1.19668, 1.23401, 1.49528}, - {1.18988, 1.19098, 1.19457, 1.20164, 1.21582, 1.27064, 1.24937, 1.24044, 1.25275, 1.29004, 1.55137}, - {1.24592, 1.24706, 1.25087, 1.25773, 1.27188, 1.32670, 1.30544, 1.29953, 1.30883, 1.34613, 1.60743}, - {1.30202, 1.30313, 1.30673, 1.31381, 1.32797, 1.38278, 1.36151, 1.35167, 1.36490, 1.40221, 1.66306}, - {1.35809, 1.35921, 1.36282, 1.36986, 1.38403, 1.43888, 1.41760, 1.41174, 1.42083, 1.45830, 1.71915}, - {1.41419, 1.41528, 1.41890, 1.42595, 1.44011, 1.49496, 1.47368, 1.46769, 1.47706, 1.51436, 1.77523}, - {1.47131, 1.47141, 1.47494, 1.48850, 1.49620, 1.55137, 1.52977, 1.51820, 1.53315, 1.57042, 1.83158}, - {1.52635, 1.52750, 1.53103, 1.53814, 1.55228, 1.60736, 1.58503, 1.57986, 1.58920, 1.62649, 1.88767}, - {1.58418, 1.58355, 1.58711, 1.59526, 1.60833, 1.66316, 1.63345, 1.63261, 1.64556, 1.68204, 1.94359}, - {1.64027, 1.63958, 1.64489, 1.65024, 1.66443, 1.71925, 1.69794, 1.69201, 1.70143, 1.73865, 1.99968}, - {1.69450, 1.69566, 1.69940, 1.70697, 1.71841, 1.77819, 1.75396, 1.74814, 1.75743, 1.79083, 2.05427}, - {1.75054, 1.75221, 1.75527, 1.76306, 1.77662, 1.83428, 1.81006, 1.81173, 1.81345, 1.85076, 2.10289}}; - // Garfield simulation at UD = -2100V; vd = 1.959cm/microsec, <driftfield> = 720V/cm - float time2100[ktimebin][kZbin] = { - {0.09160, 0.09194, 0.09294, 0.09462, 0.09701, 0.10017, 0.10424, 0.10974, 0.11823, 0.13988, 0.37762}, - {0.06585, 0.06619, 0.06731, 0.06916, 0.07174, 0.07509, 0.07933, 0.08500, 0.09370, 0.11609, 0.35565}, - {0.03960, 0.04001, 0.04171, 0.04430, 0.04774, 0.05182, 0.05668, 0.06294, 0.07291, 0.09896, 0.34676}, - {0.01109, 0.01280, 0.01716, 0.02279, 0.02876, 0.03474, 0.04096, 0.04908, 0.06424, 0.10612, 0.36790}, - {0.01114, 0.01285, 0.01719, 0.02287, 0.02863, 0.03449, 0.04073, 0.04964, 0.06759, 0.11446, 0.37162}, - {0.03922, 0.03977, 0.04146, 0.04386, 0.04711, 0.05109, 0.05605, 0.06287, 0.07575, 0.10713, 0.36298}, - {0.06504, 0.06538, 0.06641, 0.06818, 0.07064, 0.07426, 0.07852, 0.08483, 0.09581, 0.12363, 0.37424}, - {0.09103, 0.09129, 0.09186, 0.09291, 0.09476, 0.00000, 0.10923, 0.11578, 0.12873, 0.16005, 0.41525}, - {0.12723, 0.12777, 0.12988, 0.13458, 0.14579, 0.20264, 0.17421, 0.17078, 0.18132, 0.21708, 0.47699}, - {0.17508, 0.17601, 0.17897, 0.18487, 0.19698, 0.24881, 0.22737, 0.22337, 0.23348, 0.27000, 0.53032}, - {0.22571, 0.22663, 0.22969, 0.23570, 0.24787, 0.29826, 0.27871, 0.27462, 0.28471, 0.32122, 0.58166}, - {0.27664, 0.27759, 0.28067, 0.28669, 0.29891, 0.34898, 0.32982, 0.32570, 0.33576, 0.37229, 0.63268}, - {0.32766, 0.32862, 0.33170, 0.33778, 0.34988, 0.39973, 0.38088, 0.37675, 0.38680, 0.42333, 0.68159}, - {0.37872, 0.37966, 0.38275, 0.38875, 0.40093, 0.45073, 0.43192, 0.42780, 0.43786, 0.47438, 0.73480}, - {0.42974, 0.43070, 0.43378, 0.43982, 0.45196, 0.50177, 0.48297, 0.47884, 0.48889, 0.52544, 0.78581}, - {0.48081, 0.48175, 0.48482, 0.49084, 0.50302, 0.55290, 0.53398, 0.52988, 0.53994, 0.57647, 0.83687}, - {0.53645, 0.53295, 0.53586, 0.54188, 0.55408, 0.60398, 0.58504, 0.58092, 0.59100, 0.62768, 0.88773}, - {0.58345, 0.58409, 0.58690, 0.59292, 0.60510, 0.65562, 0.63609, 0.63197, 0.64203, 0.67856, 0.93907}, - {0.63397, 0.63490, 0.63795, 0.64403, 0.65613, 0.70612, 0.68714, 0.68301, 0.69294, 0.72955, 0.99000}, - {0.68496, 0.68592, 0.68899, 0.69504, 0.70733, 0.75708, 0.73818, 0.73405, 0.74412, 0.78064, 1.04100}, - {0.73600, 0.73696, 0.74003, 0.74624, 0.75828, 0.80805, 0.78904, 0.78512, 0.79517, 0.83152, 1.09205}, - {0.78709, 0.78801, 0.79108, 0.79709, 0.80931, 0.85906, 0.84027, 0.83614, 0.84621, 0.88269, 1.14058}, - {0.83808, 0.83905, 0.84215, 0.84816, 0.86031, 0.91011, 0.89139, 0.88718, 0.89725, 0.93377, 1.19413}, - {0.88916, 0.89010, 0.89320, 0.89920, 0.91136, 0.96117, 0.94235, 0.93822, 0.94828, 0.98480, 1.24538}, - {0.94036, 0.94113, 0.94422, 0.95023, 0.96241, 1.01220, 0.99310, 0.98927, 0.99933, 1.03585, 1.29629}, - {0.99139, 0.99220, 0.99525, 1.00127, 1.01344, 1.06324, 1.04451, 1.04033, 1.04836, 1.08690, 1.34727}, - {1.04261, 1.04325, 1.04628, 1.05232, 1.06448, 1.12090, 1.09546, 1.09136, 1.10142, 1.13795, 1.39831}, - {1.09331, 1.09429, 1.09742, 1.10336, 1.11557, 1.16547, 1.14658, 1.13642, 1.15247, 1.18898, 1.44936}, - {1.14436, 1.14539, 1.14847, 1.15443, 1.16662, 1.21794, 1.19763, 1.19329, 1.20349, 1.23956, 1.50043}, - {1.19533, 1.19651, 1.19943, 1.20548, 1.21666, 1.26753, 1.24862, 1.24434, 1.25455, 1.29106, 1.55142}, - {1.24638, 1.24756, 1.25046, 1.25648, 1.26764, 1.31858, 1.29967, 1.29538, 1.30499, 1.34211, 1.60250}, - {1.29747, 1.29847, 1.30175, 1.30753, 1.31869, 1.36969, 1.35069, 1.34656, 1.35663, 1.39316, 1.64644}, - {1.35537, 1.34952, 1.35255, 1.35869, 1.36973, 1.41387, 1.40173, 1.39761, 1.40768, 1.44396, 1.70238}, - {1.39956, 1.40056, 1.40380, 1.40961, 1.42178, 1.46492, 1.45278, 1.45423, 1.45872, 1.49522, 1.75557}, - {1.45080, 1.45159, 1.45463, 1.46109, 1.47287, 1.52263, 1.50382, 1.50050, 1.50977, 1.54502, 1.80670}, - {1.50165, 1.50264, 1.50570, 1.51214, 1.52233, 1.57370, 1.55484, 1.55155, 1.56080, 1.59731, 1.85778}, - {1.55269, 1.55364, 1.55675, 1.56274, 1.57491, 1.62598, 1.60590, 1.60259, 1.61185, 1.64836, 1.90883}, - {1.60368, 1.60469, 1.60779, 1.61373, 1.62596, 1.67738, 1.65651, 1.65249, 1.66290, 1.69936, 1.95959}}; - - // Garfield simulation at UD = -2200V; vd = 2.134cm/microsec, <driftfield> = 753V/cm - float time2200[ktimebin][kZbin] = { - {0.09162, 0.09194, 0.09292, 0.09460, 0.09702, 0.10014, 0.10421, 0.10971, 0.11820, 0.13990, 0.37745}, - {0.06581, 0.06618, 0.06730, 0.06915, 0.07173, 0.07507, 0.07931, 0.08497, 0.09368, 0.11609, 0.35560}, - {0.03947, 0.04001, 0.04167, 0.04429, 0.04772, 0.05183, 0.05667, 0.06293, 0.07292, 0.09900, 0.34673}, - {0.01111, 0.01280, 0.01716, 0.02279, 0.02876, 0.03473, 0.04091, 0.04907, 0.06426, 0.10620, 0.36766}, - {0.01113, 0.01285, 0.01719, 0.02276, 0.02863, 0.03452, 0.04076, 0.04960, 0.06745, 0.11419, 0.37139}, - {0.03923, 0.03978, 0.04137, 0.04387, 0.04713, 0.05110, 0.05605, 0.06284, 0.07551, 0.10677, 0.36210}, - {0.06505, 0.06540, 0.06644, 0.06820, 0.07069, 0.07401, 0.07852, 0.08479, 0.09565, 0.12325, 0.37313}, - {0.09107, 0.09127, 0.09181, 0.09291, 0.09474, 0.00000, 0.10883, 0.11528, 0.12789, 0.15865, 0.41313}, - {0.12559, 0.12622, 0.12800, 0.13206, 0.14166, 0.19331, 0.16832, 0.16632, 0.17724, 0.21218, 0.47098}, - {0.16992, 0.17070, 0.17325, 0.17831, 0.18871, 0.23557, 0.21690, 0.21451, 0.22514, 0.26082, 0.52034}, - {0.21640, 0.21722, 0.21987, 0.22500, 0.23540, 0.28097, 0.26399, 0.26154, 0.27214, 0.30784, 0.56734}, - {0.26318, 0.26400, 0.26679, 0.27181, 0.28220, 0.32739, 0.31090, 0.30842, 0.31902, 0.35474, 0.61415}, - {0.31001, 0.31085, 0.31348, 0.31866, 0.32903, 0.37412, 0.35777, 0.35546, 0.36588, 0.40159, 0.66103}, - {0.35687, 0.35769, 0.36033, 0.36556, 0.37588, 0.42094, 0.40523, 0.40214, 0.41273, 0.44841, 0.70785}, - {0.40372, 0.40457, 0.40723, 0.41234, 0.42273, 0.46778, 0.45148, 0.44903, 0.45961, 0.49526, 0.75486}, - {0.45062, 0.45139, 0.45404, 0.45966, 0.46958, 0.51470, 0.49833, 0.49584, 0.50644, 0.54211, 0.80160}, - {0.49742, 0.49825, 0.50088, 0.50605, 0.51644, 0.56148, 0.54518, 0.54270, 0.55330, 0.58897, 0.84854}, - {0.54427, 0.54510, 0.54774, 0.55290, 0.56329, 0.60846, 0.59203, 0.58955, 0.60014, 0.63578, 0.89528}, - {0.59119, 0.59199, 0.59471, 0.59975, 0.61014, 0.65533, 0.63889, 0.63636, 0.64699, 0.68269, 0.94197}, - {0.63866, 0.63880, 0.64145, 0.64664, 0.65701, 0.70639, 0.68574, 0.68325, 0.69385, 0.72949, 0.98900}, - {0.68483, 0.68566, 0.68831, 0.69347, 0.70386, 0.74890, 0.73260, 0.73010, 0.74069, 0.77638, 1.03320}, - {0.73168, 0.73255, 0.73515, 0.74031, 0.75072, 0.79576, 0.77117, 0.77501, 0.78755, 0.82318, 1.08006}, - {0.77854, 0.78310, 0.78200, 0.79525, 0.79756, 0.84281, 0.81803, 0.82393, 0.83441, 0.87008, 1.12692}, - {0.82541, 0.82642, 0.82916, 0.83528, 0.84442, 0.89086, 0.87315, 0.87079, 0.88125, 0.91694, 1.17648}, - {0.87226, 0.87308, 0.87602, 0.88086, 0.89128, 0.93772, 0.92001, 0.91751, 0.92811, 0.95587, 1.22328}, - {0.91921, 0.91994, 0.92256, 0.92772, 0.94713, 0.98566, 0.96690, 0.96436, 0.97495, 1.01064, 1.26882}, - {0.96790, 0.96679, 0.96941, 0.97463, 0.99399, 1.03001, 1.01376, 1.01112, 1.02181, 1.05749, 1.31568}, - {1.01278, 1.01390, 1.01674, 1.02147, 1.03182, 1.07820, 1.06056, 1.05798, 1.06867, 1.10433, 1.36390}, - {1.05964, 1.06076, 1.06331, 1.06833, 1.07870, 1.13297, 1.10742, 1.10520, 1.11543, 1.15120, 1.41069}, - {1.10664, 1.10762, 1.10997, 1.11519, 1.12556, 1.17531, 1.15427, 1.14620, 1.16229, 1.19805, 1.45758}, - {1.15352, 1.15421, 1.15683, 1.16218, 1.17242, 1.21910, 1.20035, 1.19863, 1.20579, 1.24473, 1.50412}, - {1.20019, 1.20115, 1.20369, 1.20892, 1.21928, 1.26913, 1.24721, 1.24549, 1.25605, 1.29159, 1.54920}, - {1.24707, 1.24846, 1.25052, 1.25602, 1.26608, 1.31558, 1.29448, 1.29232, 1.30293, 1.33675, 1.59798}, - {1.29391, 1.29475, 1.29738, 1.30255, 1.31294, 1.36244, 1.34167, 1.33918, 1.34979, 1.38229, 1.64496}, - {1.34078, 1.34304, 1.34424, 1.35565, 1.35980, 1.40930, 1.38853, 1.38229, 1.39664, 1.42863, 1.69162}, - {1.38762, 1.38847, 1.39110, 1.39627, 1.40666, 1.45183, 1.43539, 1.43289, 1.44348, 1.47549, 1.73876}, - {1.43524, 1.43533, 1.43796, 1.44310, 1.45371, 1.49305, 1.48224, 1.47941, 1.49034, 1.52601, 1.78552}, - {1.48122, 1.48219, 1.48482, 1.48991, 1.50030, 1.53991, 1.52898, 1.52653, 1.53653, 1.57282, 1.82386}}; - - if (!mTimeStruct1) { - mTimeStruct1 = new float[ktimebin * kZbin]; - } - if (!mTimeStruct2) { - mTimeStruct2 = new float[ktimebin * kZbin]; - } - memset(mTimeStruct1, 0, ktimebin * kZbin * sizeof(float)); - memset(mTimeStruct2, 0, ktimebin * kZbin * sizeof(float)); - - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - if (vdrift > fVDsmp[6]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time2100[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2200[ctrt][ctrz]; - mVDlo = fVDsmp[6]; - mVDhi = fVDsmp[7]; - } else if (vdrift > fVDsmp[5]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time2000[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2100[ctrt][ctrz]; - mVDlo = fVDsmp[5]; - mVDhi = fVDsmp[6]; - } else if (vdrift > fVDsmp[4]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1900[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2000[ctrt][ctrz]; - mVDlo = fVDsmp[4]; - mVDhi = fVDsmp[5]; - } else if (vdrift > fVDsmp[3]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1800[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1900[ctrt][ctrz]; - mVDlo = fVDsmp[3]; - mVDhi = fVDsmp[4]; - } else if (vdrift > fVDsmp[2]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1700[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1800[ctrt][ctrz]; - mVDlo = fVDsmp[2]; - mVDhi = fVDsmp[3]; - } else if (vdrift > fVDsmp[1]) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1600[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1700[ctrt][ctrz]; - mVDlo = fVDsmp[1]; - mVDhi = fVDsmp[2]; - } else if (vdrift > (fVDsmp[0] - 1.0e-5)) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1500[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1600[ctrt][ctrz]; - mVDlo = fVDsmp[0]; - mVDhi = fVDsmp[1]; - } - } - } -} -void CommonParam::SetXenon() +void CommonParam::setXenon() { mGasMixture = kXenon; - SimParam::Instance()->ReInit(); + SimParam::instance()->reInit(); } -void CommonParam::SetArgon() +void CommonParam::setArgon() { mGasMixture = kArgon; - SimParam::Instance()->ReInit(); + SimParam::instance()->reInit(); } diff --git a/Detectors/TRD/base/src/DiffAndTimeStructEstimator.cxx b/Detectors/TRD/base/src/DiffAndTimeStructEstimator.cxx index 5c9a131050a22..df908467910ba 100644 --- a/Detectors/TRD/base/src/DiffAndTimeStructEstimator.cxx +++ b/Detectors/TRD/base/src/DiffAndTimeStructEstimator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,345 +17,22 @@ namespace o2::trd { -// Garfield simulation at UD = -1500V; vd = 1.032cm/microsec, <driftfield> = 525V/cm -constexpr float time1500[ktimebin][kZbin] = { - {0.09170, 0.09205, 0.09306, 0.09475, 0.09716, 0.10035, 0.10445, 0.10993, 0.11838, 0.13986, 0.37858}, - {0.06588, 0.06626, 0.06739, 0.06926, 0.07186, 0.07524, 0.07951, 0.08515, 0.09381, 0.11601, 0.35673}, - {0.03946, 0.04003, 0.04171, 0.04435, 0.04780, 0.05193, 0.05680, 0.06306, 0.07290, 0.09873, 0.34748}, - {0.01151, 0.01283, 0.01718, 0.02282, 0.02880, 0.03479, 0.04098, 0.04910, 0.06413, 0.10567, 0.36897}, - {0.01116, 0.01290, 0.01721, 0.02299, 0.02863, 0.03447, 0.04074, 0.04984, 0.06839, 0.11625, 0.37277}, - {0.03919, 0.03974, 0.04131, 0.04380, 0.04703, 0.05102, 0.05602, 0.06309, 0.07651, 0.10938, 0.36838}, - {0.06493, 0.06560, 0.06640, 0.06802, 0.07051, 0.07392, 0.07853, 0.08510, 0.09690, 0.12621, 0.38058}, - {0.09174, 0.09186, 0.09225, 0.09303, 0.09477, 0.00000, 0.11205, 0.11952, 0.13461, 0.16984, 0.43017}, - {0.14356, 0.14494, 0.14959, 0.16002, 0.18328, 0.27981, 0.22785, 0.21240, 0.21948, 0.25965, 0.52392}, - {0.23120, 0.23366, 0.24046, 0.25422, 0.28071, 0.36914, 0.32999, 0.31208, 0.31772, 0.35804, 0.62249}, - {0.32686, 0.32916, 0.33646, 0.35053, 0.37710, 0.46292, 0.42773, 0.40948, 0.41497, 0.45527, 0.71955}, - {0.42353, 0.42583, 0.43317, 0.44727, 0.47380, 0.55884, 0.52479, 0.50650, 0.51194, 0.55225, 0.81658}, - {0.52038, 0.52271, 0.53000, 0.54415, 0.57064, 0.65545, 0.62172, 0.60341, 0.60885, 0.64915, 0.91339}, - {0.61724, 0.61953, 0.62694, 0.64098, 0.66756, 0.75226, 0.71862, 0.70030, 0.70575, 0.74604, 1.01035}, - {0.71460, 0.71678, 0.72376, 0.73786, 0.76447, 0.84913, 0.81551, 0.79720, 0.80264, 0.84292, 1.10723}, - {0.81101, 0.81334, 0.82066, 0.83475, 0.86127, 0.94599, 0.91240, 0.89408, 0.89952, 0.93981, 1.20409}, - {0.90788, 0.91023, 0.91752, 0.93163, 0.95815, 1.04293, 1.00929, 0.99096, 0.99640, 1.03669, 1.30106}, - {1.00477, 1.00707, 1.01449, 1.02852, 1.05504, 1.13976, 1.10617, 1.08784, 1.09329, 1.13358, 1.39796}, - {1.10166, 1.10397, 1.11130, 1.12541, 1.15257, 1.23672, 1.20307, 1.18472, 1.19018, 1.23046, 1.49486}, - {1.19854, 1.20084, 1.20818, 1.22235, 1.24885, 1.33355, 1.29992, 1.28156, 1.28707, 1.32735, 1.59177}, - {1.29544, 1.29780, 1.30507, 1.31917, 1.34575, 1.43073, 1.39681, 1.37851, 1.38396, 1.42377, 1.68854}, - {1.39236, 1.39462, 1.40205, 1.41607, 1.44259, 1.52745, 1.49368, 1.47541, 1.48083, 1.52112, 1.78546}, - {1.49314, 1.49149, 1.49885, 1.51297, 1.53949, 1.62420, 1.59016, 1.57231, 1.57772, 1.61800, 1.88048}, - {1.58610, 1.58839, 1.59572, 1.60983, 1.63635, 1.72109, 1.68651, 1.66921, 1.67463, 1.71489, 1.97918}, - {1.68400, 1.68529, 1.69261, 1.70671, 1.73331, 1.81830, 1.78341, 1.76605, 1.77150, 1.81179, 2.07608}, - {1.77991, 1.78215, 1.78952, 1.80385, 1.83014, 1.91486, 1.88128, 1.86215, 1.86837, 1.90865, 2.17304}, - {1.87674, 1.87904, 1.88647, 1.90052, 1.92712, 2.01173, 1.97812, 1.95905, 1.96527, 2.00710, 2.26979}, - {1.97369, 1.97594, 1.98326, 1.99869, 2.02442, 2.10865, 2.07501, 2.05666, 2.06214, 2.10243, 2.36669}, - {2.07052, 2.07281, 2.08016, 2.09425, 2.12132, 2.20555, 2.17182, 2.15341, 2.15904, 2.19933, 2.46363}, - {2.16742, 2.16971, 2.17707, 2.19114, 2.21766, 2.30240, 2.26877, 2.25015, 2.25573, 2.29586, 2.56060}, - {2.26423, 2.26659, 2.27396, 2.28803, 2.31456, 2.40828, 2.36567, 2.34705, 2.35282, 2.39765, 2.65744}, - {2.36153, 2.36349, 2.37330, 2.38501, 2.41159, 2.49940, 2.46257, 2.44420, 2.44843, 2.48987, 2.75431}, - {2.46558, 2.46035, 2.46822, 2.48181, 2.50849, 2.59630, 2.55947, 2.54112, 2.54513, 2.58677, 2.85094}, - {2.56248, 2.55723, 2.56486, 2.57871, 2.60520, 2.68998, 2.65626, 2.63790, 2.64316, 2.68360, 2.94813}, - {2.65178, 2.65441, 2.66153, 2.67556, 2.70210, 2.78687, 2.75319, 2.73463, 2.74032, 2.78060, 3.04503}, - {2.74868, 2.75131, 2.75870, 2.77245, 2.79385, 2.88700, 2.85009, 2.83177, 2.83723, 2.87750, 3.14193}, - {2.84574, 2.84789, 2.85560, 2.86935, 2.89075, 2.98060, 2.94576, 2.92868, 2.93356, 2.97436, 3.23868}, - {2.94239, 2.94469, 2.95221, 2.96625, 2.99345, 3.07747, 3.04266, 3.02545, 3.03051, 3.07118, 3.33555}}; - -// Garfield simulation at UD = -1600V; vd = 1.158cm/microsec, <driftfield> = 558V/cm -constexpr float time1600[ktimebin][kZbin] = { - {0.09169, 0.09203, 0.09305, 0.09473, 0.09714, 0.10032, 0.10441, 0.10990, 0.11835, 0.13986, 0.37845}, - {0.06589, 0.06626, 0.06738, 0.06924, 0.07184, 0.07521, 0.07947, 0.08512, 0.09379, 0.11603, 0.35648}, - {0.03947, 0.04003, 0.04171, 0.04434, 0.04778, 0.05190, 0.05678, 0.06304, 0.07292, 0.09876, 0.34759}, - {0.01111, 0.01281, 0.01718, 0.02281, 0.02879, 0.03477, 0.04097, 0.04910, 0.06415, 0.10573, 0.36896}, - {0.01120, 0.01311, 0.01721, 0.02279, 0.02862, 0.03446, 0.04074, 0.04981, 0.06825, 0.11595, 0.37255}, - {0.03919, 0.03980, 0.04132, 0.04380, 0.04704, 0.05102, 0.05602, 0.06302, 0.07633, 0.10896, 0.36743}, - {0.06531, 0.06528, 0.06631, 0.06805, 0.07053, 0.07392, 0.07853, 0.08505, 0.09669, 0.12578, 0.37967}, - {0.09157, 0.09171, 0.09216, 0.09301, 0.09475, 0.00000, 0.11152, 0.11879, 0.13352, 0.16802, 0.42750}, - {0.13977, 0.14095, 0.14509, 0.15433, 0.17534, 0.26406, 0.21660, 0.20345, 0.21113, 0.25067, 0.51434}, - {0.21816, 0.22041, 0.22631, 0.23850, 0.26208, 0.34340, 0.30755, 0.29237, 0.29878, 0.33863, 0.60258}, - {0.30344, 0.30547, 0.31241, 0.32444, 0.34809, 0.42696, 0.39464, 0.37919, 0.38546, 0.42530, 0.68926}, - {0.38969, 0.39164, 0.39810, 0.41059, 0.43441, 0.51246, 0.48112, 0.46562, 0.47191, 0.51172, 0.77558}, - {0.47592, 0.47799, 0.48442, 0.49689, 0.52061, 0.59855, 0.56752, 0.55201, 0.55826, 0.59808, 0.86202}, - {0.56226, 0.56428, 0.57074, 0.58324, 0.60696, 0.68483, 0.65388, 0.63837, 0.64461, 0.68445, 0.94830}, - {0.64881, 0.65063, 0.65709, 0.66958, 0.69331, 0.77117, 0.74023, 0.72472, 0.73098, 0.77079, 1.03486}, - {0.73506, 0.73698, 0.74344, 0.75596, 0.77964, 0.85751, 0.82658, 0.81107, 0.81731, 0.85712, 1.12106}, - {0.82132, 0.82333, 0.82979, 0.84228, 0.86608, 0.94386, 0.91293, 0.89742, 0.90367, 0.94335, 1.20737}, - {0.90767, 0.90968, 0.91614, 0.92863, 0.95236, 1.03021, 0.99928, 0.98377, 0.99001, 1.02984, 1.29371}, - {0.99410, 0.99602, 1.00257, 1.01498, 1.03869, 1.11720, 1.08563, 1.07011, 1.07637, 1.11621, 1.37873}, - {1.08036, 1.08240, 1.08884, 1.10138, 1.12504, 1.20301, 1.17198, 1.15647, 1.16272, 1.20255, 1.46651}, - {1.16670, 1.16872, 1.17525, 1.18783, 1.21139, 1.28934, 1.25833, 1.24281, 1.24909, 1.28889, 1.55275}, - {1.25307, 1.25510, 1.26153, 1.27404, 1.29773, 1.37584, 1.34469, 1.32916, 1.33536, 1.37524, 1.63915}, - {1.33942, 1.34146, 1.34788, 1.36040, 1.38410, 1.46438, 1.43105, 1.41537, 1.42176, 1.46158, 1.72538}, - {1.42579, 1.42782, 1.43458, 1.44674, 1.47043, 1.55085, 1.51675, 1.50168, 1.50810, 1.54793, 1.81174}, - {1.51207, 1.51454, 1.52060, 1.53307, 1.55684, 1.63478, 1.60336, 1.58820, 1.59446, 1.63414, 1.89814}, - {1.59856, 1.60047, 1.60693, 1.61942, 1.64317, 1.72257, 1.69008, 1.67454, 1.68080, 1.72063, 1.98433}, - {1.68481, 1.68682, 1.69330, 1.70584, 1.72949, 1.80752, 1.77643, 1.76089, 1.76716, 1.80692, 2.07069}, - {1.77117, 1.77319, 1.77969, 1.79260, 1.81583, 1.89376, 1.86226, 1.84720, 1.85355, 1.89256, 2.15343}, - {1.85748, 1.85967, 1.86605, 1.87848, 1.90222, 1.98010, 1.94913, 1.93271, 1.93981, 1.97968, 2.24355}, - {1.94386, 1.94587, 1.95233, 1.96484, 1.98854, 2.06646, 2.03542, 2.01755, 2.02617, 2.06604, 2.32993}, - {2.03022, 2.03230, 2.03868, 2.05134, 2.07488, 2.15367, 2.12178, 2.10391, 2.11252, 2.15432, 2.41623}, - {2.11656, 2.11857, 2.12505, 2.13772, 2.16147, 2.23919, 2.20817, 2.19265, 2.20744, 2.23872, 2.49996}, - {2.20291, 2.20611, 2.21137, 2.22387, 2.24758, 2.32563, 2.29450, 2.27901, 2.28525, 2.32507, 2.58897}, - {2.28922, 2.29172, 2.29774, 2.31345, 2.33400, 2.41287, 2.38086, 2.36535, 2.37160, 2.40869, 2.67113}, - {2.37572, 2.37764, 2.38410, 2.39803, 2.42046, 2.49817, 2.46721, 2.45171, 2.45794, 2.49505, 2.76061}, - {2.46190, 2.46396, 2.47043, 2.48340, 2.50665, 2.58453, 2.55357, 2.53728, 2.54430, 2.58407, 2.84816}, - {2.54833, 2.55032, 2.55679, 2.56976, 2.59312, 2.67103, 2.63993, 2.62364, 2.63062, 2.67040, 2.93444}, - {2.63456, 2.63660, 2.64304, 2.65555, 2.67938, 2.75739, 2.72629, 2.71064, 2.71688, 2.75671, 3.01886}}; - -// Garfield simulation at UD = -1700V; vd = 1.299cm/microsec, <driftfield> = 590V/cm -constexpr float time1700[ktimebin][kZbin] = { - {0.09167, 0.09201, 0.09302, 0.09471, 0.09712, 0.10029, 0.10438, 0.10986, 0.11832, 0.13986, 0.37824}, - {0.06591, 0.06626, 0.06736, 0.06923, 0.07183, 0.07519, 0.07944, 0.08511, 0.09378, 0.11603, 0.35625}, - {0.03946, 0.04003, 0.04170, 0.04433, 0.04777, 0.05189, 0.05676, 0.06301, 0.07291, 0.09880, 0.34724}, - {0.01110, 0.01281, 0.01718, 0.02280, 0.02879, 0.03476, 0.04096, 0.04910, 0.06417, 0.10582, 0.36861}, - {0.01115, 0.01294, 0.01721, 0.02276, 0.02862, 0.03447, 0.04074, 0.04980, 0.06812, 0.11565, 0.37231}, - {0.03920, 0.03974, 0.04133, 0.04381, 0.04706, 0.05105, 0.05603, 0.06299, 0.07618, 0.10860, 0.36646}, - {0.06498, 0.06529, 0.06634, 0.06808, 0.07055, 0.07395, 0.07852, 0.08500, 0.09650, 0.12532, 0.37850}, - {0.09143, 0.09159, 0.09207, 0.09297, 0.09473, 0.00000, 0.11102, 0.11809, 0.13245, 0.16627, 0.42496}, - {0.13646, 0.13750, 0.14112, 0.14926, 0.16806, 0.24960, 0.20627, 0.19536, 0.20366, 0.24256, 0.50557}, - {0.20678, 0.20848, 0.21384, 0.22450, 0.24552, 0.32018, 0.28740, 0.27477, 0.28196, 0.32128, 0.58475}, - {0.28287, 0.28461, 0.29020, 0.30108, 0.32224, 0.39467, 0.36500, 0.35217, 0.35926, 0.39860, 0.66194}, - {0.35972, 0.36145, 0.36713, 0.37797, 0.39912, 0.47091, 0.44212, 0.42925, 0.43632, 0.47563, 0.73892}, - {0.43667, 0.43841, 0.44413, 0.45494, 0.47607, 0.54780, 0.51912, 0.50627, 0.51334, 0.55254, 0.81595}, - {0.51365, 0.51540, 0.52101, 0.53193, 0.55305, 0.62463, 0.59617, 0.58328, 0.59035, 0.62965, 0.89303}, - {0.59064, 0.59240, 0.59801, 0.60893, 0.63009, 0.70169, 0.67317, 0.66028, 0.66735, 0.70666, 0.96995}, - {0.66765, 0.66939, 0.67501, 0.68592, 0.70724, 0.77863, 0.75016, 0.73728, 0.74435, 0.78366, 1.04696}, - {0.74464, 0.74636, 0.75200, 0.76293, 0.78405, 0.85561, 0.82716, 0.81427, 0.82133, 0.86064, 1.12396}, - {0.82165, 0.82340, 0.82902, 0.83991, 0.86104, 0.93266, 0.90414, 0.89128, 0.89834, 0.93763, 1.20100}, - {0.89863, 0.90042, 0.90659, 0.91705, 0.93805, 1.00960, 0.98115, 0.96825, 0.97533, 1.01462, 1.27801}, - {0.97563, 0.97740, 0.98310, 0.99391, 1.01504, 1.08659, 1.05814, 1.04526, 1.05233, 1.09163, 1.35503}, - {1.05276, 1.05451, 1.06002, 1.07090, 1.09099, 1.16357, 1.13516, 1.12225, 1.12933, 1.16863, 1.43195}, - {1.12977, 1.13138, 1.13700, 1.14792, 1.16797, 1.24061, 1.21212, 1.19926, 1.20626, 1.24554, 1.50900}, - {1.20664, 1.20839, 1.21400, 1.22490, 1.24606, 1.31772, 1.28914, 1.27382, 1.28329, 1.32262, 1.58550}, - {1.28367, 1.28541, 1.29099, 1.30189, 1.32312, 1.39460, 1.36612, 1.34924, 1.36030, 1.39961, 1.66310}, - {1.36064, 1.36249, 1.36799, 1.37896, 1.40004, 1.48030, 1.44314, 1.43032, 1.43731, 1.47659, 1.73442}, - {1.43762, 1.43937, 1.44497, 1.45618, 1.47704, 1.54932, 1.52012, 1.50725, 1.51430, 1.55357, 1.81708}, - {1.51462, 1.51937, 1.52203, 1.53316, 1.55403, 1.62572, 1.59713, 1.58424, 1.59128, 1.63061, 1.89406}, - {1.59162, 1.59338, 1.59947, 1.60989, 1.63103, 1.70270, 1.67411, 1.66124, 1.66799, 1.70759, 1.97103}, - {1.66874, 1.67037, 1.67597, 1.68687, 1.70814, 1.77969, 1.75112, 1.73806, 1.74530, 1.78457, 2.04794}, - {1.74693, 1.74749, 1.75297, 1.76476, 1.78500, 1.85667, 1.82811, 1.81504, 1.82101, 1.86161, 2.12492}, - {1.82260, 1.82437, 1.82995, 1.84174, 1.86202, 1.93372, 1.90509, 1.89202, 1.89930, 1.93859, 2.20189}, - {1.89964, 1.90135, 1.90693, 1.91789, 1.93952, 2.01080, 1.98207, 1.96921, 1.97628, 2.01384, 2.27887}, - {1.97662, 1.97917, 1.98611, 1.99487, 2.01601, 2.08778, 2.05846, 2.04623, 2.05330, 2.09244, 2.35585}, - {2.05359, 2.05615, 2.06309, 2.07187, 2.09867, 2.16459, 2.13610, 2.12322, 2.13029, 2.16942, 2.43199}, - {2.13063, 2.13233, 2.13795, 2.14886, 2.17008, 2.24199, 2.21310, 2.20020, 2.20727, 2.24659, 2.50983}, - {2.20761, 2.20931, 2.21955, 2.22624, 2.24708, 2.32147, 2.29009, 2.27725, 2.28276, 2.32359, 2.58680}, - {2.28459, 2.29108, 2.29202, 2.30286, 2.32007, 2.39559, 2.36683, 2.35422, 2.36119, 2.40058, 2.66081}, - {2.36153, 2.36806, 2.36889, 2.37985, 2.40092, 2.47828, 2.44381, 2.43099, 2.43819, 2.47750, 2.73779}}; - -// Garfield simulation at UD = -1800V; vd = 1.450cm/microsec, <driftfield> = 623V/cm -constexpr float time1800[ktimebin][kZbin] = { - {0.09166, 0.09199, 0.09300, 0.09470, 0.09709, 0.10026, 0.10434, 0.10983, 0.11831, 0.13987, 0.37802}, - {0.06585, 0.06623, 0.06735, 0.06921, 0.07180, 0.07520, 0.07941, 0.08507, 0.09376, 0.11604, 0.35624}, - {0.03945, 0.04004, 0.04169, 0.04432, 0.04776, 0.05187, 0.05674, 0.06300, 0.07290, 0.09884, 0.34704}, - {0.01108, 0.01287, 0.01717, 0.02280, 0.02880, 0.03476, 0.04095, 0.04909, 0.06419, 0.10589, 0.36843}, - {0.01115, 0.01287, 0.01720, 0.02276, 0.02862, 0.03448, 0.04073, 0.04973, 0.06799, 0.11535, 0.37224}, - {0.03918, 0.03975, 0.04134, 0.04382, 0.04707, 0.05105, 0.05603, 0.06296, 0.07605, 0.10822, 0.36560}, - {0.06498, 0.06532, 0.06635, 0.06809, 0.07058, 0.07395, 0.07855, 0.08495, 0.09632, 0.12488, 0.37730}, - {0.09130, 0.09160, 0.09199, 0.09300, 0.09472, 0.00000, 0.11059, 0.11747, 0.13146, 0.16462, 0.42233}, - {0.13364, 0.13449, 0.13767, 0.14481, 0.16147, 0.23635, 0.19706, 0.18812, 0.19704, 0.23520, 0.49749}, - {0.19698, 0.19844, 0.20311, 0.21236, 0.23082, 0.29920, 0.26936, 0.25927, 0.26732, 0.30601, 0.56871}, - {0.26518, 0.26670, 0.27160, 0.28099, 0.29955, 0.36597, 0.33885, 0.32858, 0.33653, 0.37524, 0.63801}, - {0.33441, 0.33553, 0.34040, 0.34987, 0.36841, 0.43428, 0.40797, 0.39763, 0.40556, 0.44425, 0.70698}, - {0.40296, 0.40447, 0.40934, 0.41881, 0.43737, 0.50306, 0.47695, 0.46662, 0.47455, 0.51329, 0.77600}, - {0.47296, 0.47344, 0.47830, 0.48779, 0.50632, 0.57200, 0.54593, 0.53559, 0.54351, 0.58222, 0.84489}, - {0.54089, 0.54264, 0.54727, 0.55673, 0.57529, 0.64094, 0.61490, 0.60457, 0.61249, 0.65118, 0.91394}, - {0.60987, 0.61138, 0.61624, 0.62573, 0.64428, 0.70989, 0.68397, 0.67354, 0.68147, 0.72015, 0.98291}, - {0.67883, 0.68035, 0.68521, 0.69469, 0.71324, 0.77896, 0.75287, 0.74251, 0.75043, 0.78912, 1.04458}, - {0.74780, 0.74932, 0.75421, 0.76367, 0.78221, 0.84785, 0.82185, 0.81148, 0.81941, 0.85811, 1.12085}, - {0.81690, 0.81830, 0.82316, 0.83263, 0.85120, 0.91683, 0.89077, 0.88045, 0.88837, 0.92707, 1.18976}, - {0.88574, 0.88726, 0.89228, 0.90198, 0.92017, 0.98578, 0.95974, 0.94947, 0.95734, 0.99604, 1.25873}, - {0.95493, 0.95624, 0.96110, 0.97058, 0.98913, 1.05481, 1.02873, 1.01839, 1.02631, 1.06503, 1.32772}, - {1.02392, 1.02524, 1.03008, 1.03955, 1.05810, 1.12378, 1.09757, 1.08605, 1.09530, 1.13399, 1.39669}, - {1.09270, 1.09418, 1.09911, 1.10854, 1.12714, 1.19281, 1.16502, 1.15633, 1.16427, 1.20271, 1.46574}, - {1.16168, 1.16323, 1.16801, 1.17772, 1.19604, 1.26190, 1.23399, 1.22531, 1.23323, 1.27194, 1.53475}, - {1.23061, 1.23214, 1.23698, 1.24669, 1.26503, 1.33073, 1.30461, 1.29428, 1.30220, 1.34091, 1.60372}, - {1.29960, 1.30110, 1.30596, 1.31544, 1.33398, 1.39962, 1.37228, 1.36323, 1.37121, 1.40988, 1.67273}, - {1.36851, 1.37007, 1.37512, 1.38441, 1.40297, 1.46865, 1.44256, 1.43222, 1.44017, 1.47878, 1.74155}, - {1.43752, 1.43904, 1.44773, 1.45338, 1.47220, 1.53759, 1.51136, 1.50119, 1.50914, 1.54775, 1.81050}, - {1.50646, 1.50802, 1.51288, 1.52237, 1.54097, 1.60697, 1.58049, 1.57018, 1.57811, 1.61678, 1.87947}, - {1.57545, 1.57720, 1.58185, 1.59134, 1.60996, 1.67787, 1.64929, 1.63914, 1.64707, 1.68570, 1.94851}, - {1.64442, 1.64617, 1.65081, 1.66035, 1.67893, 1.74684, 1.71826, 1.70745, 1.71604, 1.75310, 2.01748}, - {1.71337, 1.71513, 1.71978, 1.72932, 1.74645, 1.81346, 1.78739, 1.77642, 1.78501, 1.82151, 2.08644}, - {1.78238, 1.78410, 1.78876, 1.79824, 1.81678, 1.88332, 1.85639, 1.84262, 1.85397, 1.89270, 2.15533}, - {1.85135, 1.85306, 1.85778, 1.86728, 1.88580, 1.95615, 1.92536, 1.91171, 1.92283, 1.96165, 2.22428}, - {1.92774, 1.92184, 1.92672, 1.93618, 1.95477, 2.02048, 1.99427, 1.98068, 1.99192, 2.03062, 2.29338}, - {1.98929, 1.99081, 1.99567, 2.00515, 2.02373, 2.08987, 2.06332, 2.05249, 2.05939, 2.09928, 2.36227}, - {2.05829, 2.05978, 2.06464, 2.07414, 2.09272, 2.15850, 2.12928, 2.12194, 2.12987, 2.16825, 2.43083}, - {2.12726, 2.12869, 2.13360, 2.14425, 2.16160, 2.22872, 2.20118, 2.19078, 2.19876, 2.23416, 2.50007}}; - -// Garfield simulation at UD = -1900V; vd = 1.610cm/microsec, <driftfield> = 655V/cm -constexpr float time1900[ktimebin][kZbin] = { - {0.09166, 0.09198, 0.09298, 0.09467, 0.09707, 0.10023, 0.10431, 0.10980, 0.11828, 0.13988, 0.37789}, - {0.06584, 0.06622, 0.06735, 0.06920, 0.07179, 0.07514, 0.07938, 0.08505, 0.09374, 0.11606, 0.35599}, - {0.03945, 0.04002, 0.04169, 0.04432, 0.04775, 0.05185, 0.05672, 0.06298, 0.07290, 0.09888, 0.34695}, - {0.01109, 0.01281, 0.01717, 0.02279, 0.02878, 0.03476, 0.04094, 0.04909, 0.06421, 0.10597, 0.36823}, - {0.01115, 0.01287, 0.01720, 0.02294, 0.02862, 0.03448, 0.04074, 0.04973, 0.06783, 0.11506, 0.37206}, - {0.03940, 0.03975, 0.04135, 0.04386, 0.04708, 0.05106, 0.05604, 0.06293, 0.07592, 0.10787, 0.36484}, - {0.06500, 0.06534, 0.06638, 0.06811, 0.07060, 0.07413, 0.07852, 0.08491, 0.09614, 0.12446, 0.37626}, - {0.09119, 0.09140, 0.09194, 0.09293, 0.09471, 0.00000, 0.11013, 0.11685, 0.13050, 0.16302, 0.41991}, - {0.13111, 0.13190, 0.13466, 0.14091, 0.15554, 0.22409, 0.18846, 0.18167, 0.19113, 0.22854, 0.48995}, - {0.18849, 0.18975, 0.19380, 0.20185, 0.21797, 0.28050, 0.25368, 0.24575, 0.25446, 0.29249, 0.55442}, - {0.24995, 0.25125, 0.25563, 0.26366, 0.27986, 0.34065, 0.31605, 0.30815, 0.31680, 0.35482, 0.61697}, - {0.31187, 0.31324, 0.31745, 0.32580, 0.34205, 0.40217, 0.37825, 0.37031, 0.37897, 0.41696, 0.67890}, - {0.37401, 0.37531, 0.37955, 0.38777, 0.40395, 0.46408, 0.44037, 0.43242, 0.44108, 0.47906, 0.74122}, - {0.43610, 0.43741, 0.44161, 0.44986, 0.46604, 0.52614, 0.50248, 0.49452, 0.50316, 0.54116, 0.80326}, - {0.49820, 0.49988, 0.50372, 0.51196, 0.52814, 0.58822, 0.56459, 0.55661, 0.56527, 0.60326, 0.86526}, - {0.56032, 0.56161, 0.56582, 0.57408, 0.59024, 0.65032, 0.62670, 0.61872, 0.62737, 0.66537, 0.92749}, - {0.62240, 0.62371, 0.62792, 0.63624, 0.65236, 0.71241, 0.68881, 0.68081, 0.68947, 0.72750, 0.98941}, - {0.68449, 0.68581, 0.69002, 0.69828, 0.71444, 0.77452, 0.75089, 0.74295, 0.75157, 0.78957, 1.05157}, - {0.74660, 0.74790, 0.75212, 0.76036, 0.77654, 0.83748, 0.81299, 0.80501, 0.81193, 0.85168, 1.11375}, - {0.80870, 0.81017, 0.81423, 0.82246, 0.83867, 0.89908, 0.87509, 0.86660, 0.87577, 0.91376, 1.17586}, - {0.87080, 0.87233, 0.87632, 0.88458, 0.90074, 0.96083, 0.93718, 0.92922, 0.93787, 0.97588, 1.23794}, - {0.93291, 0.93422, 0.93844, 0.94667, 0.96293, 1.02295, 0.99929, 0.99127, 0.99997, 1.03797, 1.29995}, - {0.99500, 0.99645, 1.00308, 1.00877, 1.02497, 1.08504, 1.06140, 1.05343, 1.06203, 1.10006, 1.36216}, - {1.05712, 1.05926, 1.06262, 1.07092, 1.08706, 1.14754, 1.12350, 1.11550, 1.12417, 1.16218, 1.42427}, - {1.11921, 1.12059, 1.12473, 1.13297, 1.14916, 1.21140, 1.18560, 1.17284, 1.18625, 1.22414, 1.48629}, - {1.18140, 1.18262, 1.18690, 1.19508, 1.21125, 1.27139, 1.24164, 1.23495, 1.24838, 1.28634, 1.54852}, - {1.24340, 1.24473, 1.24901, 1.25732, 1.27336, 1.33358, 1.30793, 1.30179, 1.31047, 1.34848, 1.61066}, - {1.30551, 1.30684, 1.31104, 1.32056, 1.33553, 1.39609, 1.37004, 1.36392, 1.37045, 1.41057, 1.67259}, - {1.36755, 1.36892, 1.37315, 1.39148, 1.39755, 1.45820, 1.43215, 1.42602, 1.43467, 1.47268, 1.73477}, - {1.42966, 1.43101, 1.43549, 1.45359, 1.45976, 1.52031, 1.49601, 1.48811, 1.49677, 1.53477, 1.79691}, - {1.49180, 1.49321, 1.49760, 1.51570, 1.52175, 1.58185, 1.55771, 1.55023, 1.55888, 1.59672, 1.85501}, - {1.55391, 1.55527, 1.55943, 1.57782, 1.58391, 1.64395, 1.62008, 1.61233, 1.62085, 1.65883, 1.92091}, - {1.61599, 1.61732, 1.62154, 1.63993, 1.64612, 1.70608, 1.68237, 1.67108, 1.68301, 1.72110, 1.97931}, - {1.67808, 1.67948, 1.68364, 1.70204, 1.70823, 1.76858, 1.74404, 1.73539, 1.74512, 1.78321, 2.04522}, - {1.74019, 1.74152, 1.74573, 1.76415, 1.77015, 1.83040, 1.80615, 1.79366, 1.80723, 1.84509, 2.10742}, - {1.80235, 1.80362, 1.80783, 1.82626, 1.83227, 1.89246, 1.86795, 1.85405, 1.86938, 1.90720, 2.16953}, - {1.86442, 1.86572, 1.86994, 1.88837, 1.89438, 1.95445, 1.93006, 1.92283, 1.93148, 1.96931, 2.23147}, - {1.92700, 1.92783, 1.93197, 1.95049, 1.95649, 2.01668, 1.99217, 1.98486, 1.99352, 2.03143, 2.29358}}; - -// Garfield simulation at UD = -2000V; vd = 1.783cm/microsec, <driftfield> = 688V/cm -constexpr float time2000[ktimebin][kZbin] = { - {0.09176, 0.09196, 0.09296, 0.09465, 0.09704, 0.10020, 0.10427, 0.10977, 0.11825, 0.13988, 0.37774}, - {0.06583, 0.06620, 0.06735, 0.06918, 0.07177, 0.07513, 0.07936, 0.08503, 0.09372, 0.11606, 0.35586}, - {0.03944, 0.04001, 0.04170, 0.04431, 0.04774, 0.05184, 0.05670, 0.06296, 0.07291, 0.09893, 0.34680}, - {0.01108, 0.01281, 0.01719, 0.02279, 0.02879, 0.03474, 0.04093, 0.04908, 0.06422, 0.10605, 0.36800}, - {0.01114, 0.01287, 0.01720, 0.02276, 0.02863, 0.03449, 0.04073, 0.04970, 0.06774, 0.11478, 0.37179}, - {0.03925, 0.03977, 0.04135, 0.04386, 0.04711, 0.05108, 0.05604, 0.06290, 0.07580, 0.10748, 0.36386}, - {0.06501, 0.06536, 0.06640, 0.06814, 0.07062, 0.07398, 0.07852, 0.08487, 0.09598, 0.12405, 0.37519}, - {0.09109, 0.09127, 0.09188, 0.09292, 0.09472, 0.00000, 0.10964, 0.11630, 0.12960, 0.16150, 0.41765}, - {0.12898, 0.12968, 0.13209, 0.13749, 0.15034, 0.21286, 0.18088, 0.17590, 0.18591, 0.22254, 0.48315}, - {0.18122, 0.18227, 0.18574, 0.19263, 0.20674, 0.26376, 0.23960, 0.23375, 0.24316, 0.28047, 0.54179}, - {0.23674, 0.23784, 0.24142, 0.24847, 0.26264, 0.31810, 0.29602, 0.29008, 0.29944, 0.33675, 0.59795}, - {0.29279, 0.29382, 0.29742, 0.30448, 0.31865, 0.37364, 0.35215, 0.34629, 0.35555, 0.39286, 0.65411}, - {0.34875, 0.34987, 0.35346, 0.36054, 0.37472, 0.42956, 0.40825, 0.40229, 0.41167, 0.44894, 0.71033}, - {0.40484, 0.40594, 0.40954, 0.41660, 0.43077, 0.48560, 0.46433, 0.45840, 0.46772, 0.50500, 0.76632}, - {0.46090, 0.46201, 0.46560, 0.47267, 0.48684, 0.54167, 0.52041, 0.51449, 0.52382, 0.56108, 0.82227}, - {0.51698, 0.51809, 0.52173, 0.52874, 0.54291, 0.59776, 0.57646, 0.57052, 0.57986, 0.61717, 0.87836}, - {0.57306, 0.57418, 0.57782, 0.58513, 0.59899, 0.65380, 0.63255, 0.62661, 0.63594, 0.67325, 0.93460}, - {0.62912, 0.63024, 0.63383, 0.64103, 0.65506, 0.70988, 0.68484, 0.68267, 0.69202, 0.72878, 0.99046}, - {0.68521, 0.68633, 0.68990, 0.69699, 0.71115, 0.76595, 0.74468, 0.73872, 0.74814, 0.78538, 1.04674}, - {0.74127, 0.74239, 0.74605, 0.75303, 0.77022, 0.82204, 0.80078, 0.79484, 0.80416, 0.84147, 1.10261}, - {0.79736, 0.79846, 0.80206, 0.80947, 0.82330, 0.87813, 0.85688, 0.85087, 0.86023, 0.89752, 1.15874}, - {0.85342, 0.85454, 0.85815, 0.86519, 0.87936, 0.93417, 0.91293, 0.90428, 0.91631, 0.95360, 1.20760}, - {0.90949, 0.91061, 0.91423, 0.92128, 0.93544, 0.99026, 0.96807, 0.96305, 0.97239, 1.00967, 1.27078}, - {0.96556, 0.96669, 0.97111, 0.97734, 0.99151, 1.04664, 1.02508, 1.01879, 1.02846, 1.06167, 1.32695}, - {1.02167, 1.02279, 1.02656, 1.03341, 1.04759, 1.10242, 1.08115, 1.07003, 1.08453, 1.12184, 1.38304}, - {1.07776, 1.07883, 1.08242, 1.08950, 1.10384, 1.16422, 1.13725, 1.13133, 1.14061, 1.17793, 1.43910}, - {1.13379, 1.13492, 1.13864, 1.14567, 1.15973, 1.21455, 1.19323, 1.18734, 1.19668, 1.23401, 1.49528}, - {1.18988, 1.19098, 1.19457, 1.20164, 1.21582, 1.27064, 1.24937, 1.24044, 1.25275, 1.29004, 1.55137}, - {1.24592, 1.24706, 1.25087, 1.25773, 1.27188, 1.32670, 1.30544, 1.29953, 1.30883, 1.34613, 1.60743}, - {1.30202, 1.30313, 1.30673, 1.31381, 1.32797, 1.38278, 1.36151, 1.35167, 1.36490, 1.40221, 1.66306}, - {1.35809, 1.35921, 1.36282, 1.36986, 1.38403, 1.43888, 1.41760, 1.41174, 1.42083, 1.45830, 1.71915}, - {1.41419, 1.41528, 1.41890, 1.42595, 1.44011, 1.49496, 1.47368, 1.46769, 1.47706, 1.51436, 1.77523}, - {1.47131, 1.47141, 1.47494, 1.48850, 1.49620, 1.55137, 1.52977, 1.51820, 1.53315, 1.57042, 1.83158}, - {1.52635, 1.52750, 1.53103, 1.53814, 1.55228, 1.60736, 1.58503, 1.57986, 1.58920, 1.62649, 1.88767}, - {1.58418, 1.58355, 1.58711, 1.59526, 1.60833, 1.66316, 1.63345, 1.63261, 1.64556, 1.68204, 1.94359}, - {1.64027, 1.63958, 1.64489, 1.65024, 1.66443, 1.71925, 1.69794, 1.69201, 1.70143, 1.73865, 1.99968}, - {1.69450, 1.69566, 1.69940, 1.70697, 1.71841, 1.77819, 1.75396, 1.74814, 1.75743, 1.79083, 2.05427}, - {1.75054, 1.75221, 1.75527, 1.76306, 1.77662, 1.83428, 1.81006, 1.81173, 1.81345, 1.85076, 2.10289}}; - -// Garfield simulation at UD = -2100V; vd = 1.959cm/microsec, <driftfield> = 720V/cm -constexpr float time2100[ktimebin][kZbin] = { - {0.09160, 0.09194, 0.09294, 0.09462, 0.09701, 0.10017, 0.10424, 0.10974, 0.11823, 0.13988, 0.37762}, - {0.06585, 0.06619, 0.06731, 0.06916, 0.07174, 0.07509, 0.07933, 0.08500, 0.09370, 0.11609, 0.35565}, - {0.03960, 0.04001, 0.04171, 0.04430, 0.04774, 0.05182, 0.05668, 0.06294, 0.07291, 0.09896, 0.34676}, - {0.01109, 0.01280, 0.01716, 0.02279, 0.02876, 0.03474, 0.04096, 0.04908, 0.06424, 0.10612, 0.36790}, - {0.01114, 0.01285, 0.01719, 0.02287, 0.02863, 0.03449, 0.04073, 0.04964, 0.06759, 0.11446, 0.37162}, - {0.03922, 0.03977, 0.04146, 0.04386, 0.04711, 0.05109, 0.05605, 0.06287, 0.07575, 0.10713, 0.36298}, - {0.06504, 0.06538, 0.06641, 0.06818, 0.07064, 0.07426, 0.07852, 0.08483, 0.09581, 0.12363, 0.37424}, - {0.09103, 0.09129, 0.09186, 0.09291, 0.09476, 0.00000, 0.10923, 0.11578, 0.12873, 0.16005, 0.41525}, - {0.12723, 0.12777, 0.12988, 0.13458, 0.14579, 0.20264, 0.17421, 0.17078, 0.18132, 0.21708, 0.47699}, - {0.17508, 0.17601, 0.17897, 0.18487, 0.19698, 0.24881, 0.22737, 0.22337, 0.23348, 0.27000, 0.53032}, - {0.22571, 0.22663, 0.22969, 0.23570, 0.24787, 0.29826, 0.27871, 0.27462, 0.28471, 0.32122, 0.58166}, - {0.27664, 0.27759, 0.28067, 0.28669, 0.29891, 0.34898, 0.32982, 0.32570, 0.33576, 0.37229, 0.63268}, - {0.32766, 0.32862, 0.33170, 0.33778, 0.34988, 0.39973, 0.38088, 0.37675, 0.38680, 0.42333, 0.68159}, - {0.37872, 0.37966, 0.38275, 0.38875, 0.40093, 0.45073, 0.43192, 0.42780, 0.43786, 0.47438, 0.73480}, - {0.42974, 0.43070, 0.43378, 0.43982, 0.45196, 0.50177, 0.48297, 0.47884, 0.48889, 0.52544, 0.78581}, - {0.48081, 0.48175, 0.48482, 0.49084, 0.50302, 0.55290, 0.53398, 0.52988, 0.53994, 0.57647, 0.83687}, - {0.53645, 0.53295, 0.53586, 0.54188, 0.55408, 0.60398, 0.58504, 0.58092, 0.59100, 0.62768, 0.88773}, - {0.58345, 0.58409, 0.58690, 0.59292, 0.60510, 0.65562, 0.63609, 0.63197, 0.64203, 0.67856, 0.93907}, - {0.63397, 0.63490, 0.63795, 0.64403, 0.65613, 0.70612, 0.68714, 0.68301, 0.69294, 0.72955, 0.99000}, - {0.68496, 0.68592, 0.68899, 0.69504, 0.70733, 0.75708, 0.73818, 0.73405, 0.74412, 0.78064, 1.04100}, - {0.73600, 0.73696, 0.74003, 0.74624, 0.75828, 0.80805, 0.78904, 0.78512, 0.79517, 0.83152, 1.09205}, - {0.78709, 0.78801, 0.79108, 0.79709, 0.80931, 0.85906, 0.84027, 0.83614, 0.84621, 0.88269, 1.14058}, - {0.83808, 0.83905, 0.84215, 0.84816, 0.86031, 0.91011, 0.89139, 0.88718, 0.89725, 0.93377, 1.19413}, - {0.88916, 0.89010, 0.89320, 0.89920, 0.91136, 0.96117, 0.94235, 0.93822, 0.94828, 0.98480, 1.24538}, - {0.94036, 0.94113, 0.94422, 0.95023, 0.96241, 1.01220, 0.99310, 0.98927, 0.99933, 1.03585, 1.29629}, - {0.99139, 0.99220, 0.99525, 1.00127, 1.01344, 1.06324, 1.04451, 1.04033, 1.04836, 1.08690, 1.34727}, - {1.04261, 1.04325, 1.04628, 1.05232, 1.06448, 1.12090, 1.09546, 1.09136, 1.10142, 1.13795, 1.39831}, - {1.09331, 1.09429, 1.09742, 1.10336, 1.11557, 1.16547, 1.14658, 1.13642, 1.15247, 1.18898, 1.44936}, - {1.14436, 1.14539, 1.14847, 1.15443, 1.16662, 1.21794, 1.19763, 1.19329, 1.20349, 1.23956, 1.50043}, - {1.19533, 1.19651, 1.19943, 1.20548, 1.21666, 1.26753, 1.24862, 1.24434, 1.25455, 1.29106, 1.55142}, - {1.24638, 1.24756, 1.25046, 1.25648, 1.26764, 1.31858, 1.29967, 1.29538, 1.30499, 1.34211, 1.60250}, - {1.29747, 1.29847, 1.30175, 1.30753, 1.31869, 1.36969, 1.35069, 1.34656, 1.35663, 1.39316, 1.64644}, - {1.35537, 1.34952, 1.35255, 1.35869, 1.36973, 1.41387, 1.40173, 1.39761, 1.40768, 1.44396, 1.70238}, - {1.39956, 1.40056, 1.40380, 1.40961, 1.42178, 1.46492, 1.45278, 1.45423, 1.45872, 1.49522, 1.75557}, - {1.45080, 1.45159, 1.45463, 1.46109, 1.47287, 1.52263, 1.50382, 1.50050, 1.50977, 1.54502, 1.80670}, - {1.50165, 1.50264, 1.50570, 1.51214, 1.52233, 1.57370, 1.55484, 1.55155, 1.56080, 1.59731, 1.85778}, - {1.55269, 1.55364, 1.55675, 1.56274, 1.57491, 1.62598, 1.60590, 1.60259, 1.61185, 1.64836, 1.90883}, - {1.60368, 1.60469, 1.60779, 1.61373, 1.62596, 1.67738, 1.65651, 1.65249, 1.66290, 1.69936, 1.95959}}; - -// Garfield simulation at UD = -2200V; vd = 2.134cm/microsec, <driftfield> = 753V/cm -constexpr float time2200[ktimebin][kZbin] = { - {0.09162, 0.09194, 0.09292, 0.09460, 0.09702, 0.10014, 0.10421, 0.10971, 0.11820, 0.13990, 0.37745}, - {0.06581, 0.06618, 0.06730, 0.06915, 0.07173, 0.07507, 0.07931, 0.08497, 0.09368, 0.11609, 0.35560}, - {0.03947, 0.04001, 0.04167, 0.04429, 0.04772, 0.05183, 0.05667, 0.06293, 0.07292, 0.09900, 0.34673}, - {0.01111, 0.01280, 0.01716, 0.02279, 0.02876, 0.03473, 0.04091, 0.04907, 0.06426, 0.10620, 0.36766}, - {0.01113, 0.01285, 0.01719, 0.02276, 0.02863, 0.03452, 0.04076, 0.04960, 0.06745, 0.11419, 0.37139}, - {0.03923, 0.03978, 0.04137, 0.04387, 0.04713, 0.05110, 0.05605, 0.06284, 0.07551, 0.10677, 0.36210}, - {0.06505, 0.06540, 0.06644, 0.06820, 0.07069, 0.07401, 0.07852, 0.08479, 0.09565, 0.12325, 0.37313}, - {0.09107, 0.09127, 0.09181, 0.09291, 0.09474, 0.00000, 0.10883, 0.11528, 0.12789, 0.15865, 0.41313}, - {0.12559, 0.12622, 0.12800, 0.13206, 0.14166, 0.19331, 0.16832, 0.16632, 0.17724, 0.21218, 0.47098}, - {0.16992, 0.17070, 0.17325, 0.17831, 0.18871, 0.23557, 0.21690, 0.21451, 0.22514, 0.26082, 0.52034}, - {0.21640, 0.21722, 0.21987, 0.22500, 0.23540, 0.28097, 0.26399, 0.26154, 0.27214, 0.30784, 0.56734}, - {0.26318, 0.26400, 0.26679, 0.27181, 0.28220, 0.32739, 0.31090, 0.30842, 0.31902, 0.35474, 0.61415}, - {0.31001, 0.31085, 0.31348, 0.31866, 0.32903, 0.37412, 0.35777, 0.35546, 0.36588, 0.40159, 0.66103}, - {0.35687, 0.35769, 0.36033, 0.36556, 0.37588, 0.42094, 0.40523, 0.40214, 0.41273, 0.44841, 0.70785}, - {0.40372, 0.40457, 0.40723, 0.41234, 0.42273, 0.46778, 0.45148, 0.44903, 0.45961, 0.49526, 0.75486}, - {0.45062, 0.45139, 0.45404, 0.45966, 0.46958, 0.51470, 0.49833, 0.49584, 0.50644, 0.54211, 0.80160}, - {0.49742, 0.49825, 0.50088, 0.50605, 0.51644, 0.56148, 0.54518, 0.54270, 0.55330, 0.58897, 0.84854}, - {0.54427, 0.54510, 0.54774, 0.55290, 0.56329, 0.60846, 0.59203, 0.58955, 0.60014, 0.63578, 0.89528}, - {0.59119, 0.59199, 0.59471, 0.59975, 0.61014, 0.65533, 0.63889, 0.63636, 0.64699, 0.68269, 0.94197}, - {0.63866, 0.63880, 0.64145, 0.64664, 0.65701, 0.70639, 0.68574, 0.68325, 0.69385, 0.72949, 0.98900}, - {0.68483, 0.68566, 0.68831, 0.69347, 0.70386, 0.74890, 0.73260, 0.73010, 0.74069, 0.77638, 1.03320}, - {0.73168, 0.73255, 0.73515, 0.74031, 0.75072, 0.79576, 0.77117, 0.77501, 0.78755, 0.82318, 1.08006}, - {0.77854, 0.78310, 0.78200, 0.79525, 0.79756, 0.84281, 0.81803, 0.82393, 0.83441, 0.87008, 1.12692}, - {0.82541, 0.82642, 0.82916, 0.83528, 0.84442, 0.89086, 0.87315, 0.87079, 0.88125, 0.91694, 1.17648}, - {0.87226, 0.87308, 0.87602, 0.88086, 0.89128, 0.93772, 0.92001, 0.91751, 0.92811, 0.95587, 1.22328}, - {0.91921, 0.91994, 0.92256, 0.92772, 0.94713, 0.98566, 0.96690, 0.96436, 0.97495, 1.01064, 1.26882}, - {0.96790, 0.96679, 0.96941, 0.97463, 0.99399, 1.03001, 1.01376, 1.01112, 1.02181, 1.05749, 1.31568}, - {1.01278, 1.01390, 1.01674, 1.02147, 1.03182, 1.07820, 1.06056, 1.05798, 1.06867, 1.10433, 1.36390}, - {1.05964, 1.06076, 1.06331, 1.06833, 1.07870, 1.13297, 1.10742, 1.10520, 1.11543, 1.15120, 1.41069}, - {1.10664, 1.10762, 1.10997, 1.11519, 1.12556, 1.17531, 1.15427, 1.14620, 1.16229, 1.19805, 1.45758}, - {1.15352, 1.15421, 1.15683, 1.16218, 1.17242, 1.21910, 1.20035, 1.19863, 1.20579, 1.24473, 1.50412}, - {1.20019, 1.20115, 1.20369, 1.20892, 1.21928, 1.26913, 1.24721, 1.24549, 1.25605, 1.29159, 1.54920}, - {1.24707, 1.24846, 1.25052, 1.25602, 1.26608, 1.31558, 1.29448, 1.29232, 1.30293, 1.33675, 1.59798}, - {1.29391, 1.29475, 1.29738, 1.30255, 1.31294, 1.36244, 1.34167, 1.33918, 1.34979, 1.38229, 1.64496}, - {1.34078, 1.34304, 1.34424, 1.35565, 1.35980, 1.40930, 1.38853, 1.38229, 1.39664, 1.42863, 1.69162}, - {1.38762, 1.38847, 1.39110, 1.39627, 1.40666, 1.45183, 1.43539, 1.43289, 1.44348, 1.47549, 1.73876}, - {1.43524, 1.43533, 1.43796, 1.44310, 1.45371, 1.49305, 1.48224, 1.47941, 1.49034, 1.52601, 1.78552}, - {1.48122, 1.48219, 1.48482, 1.48991, 1.50030, 1.53991, 1.52898, 1.52653, 1.53653, 1.57282, 1.82386}}; +using namespace garfield; +using namespace constants; //_____________________________________________________________________________ -void DiffusionAndTimeStructEstimator::SampleTimeStruct(float vdrift) +bool DiffusionAndTimeStructEstimator::sampleTimeStruct(float vdrift) { // // Samples the timing structure of a drift cell // Drift Time data calculated with Garfield (by C.Lippmann) // + bool retVal = true; + // Nothing to do if (std::abs(mTimeLastVdrift - vdrift) < 1.e-3) { - return; + return retVal; } mTimeLastVdrift = vdrift; @@ -362,81 +40,84 @@ void DiffusionAndTimeStructEstimator::SampleTimeStruct(float vdrift) constexpr float fVDsmp[8] = {1.032, 1.158, 1.299, 1.450, 1.610, 1.783, 1.959, 2.134}; if (vdrift < fVDsmp[0]) { - LOG(WARN) << "TRD: Drift Velocity too small " << vdrift << " < " << fVDsmp[0]; + LOG(DEBUG) << "TRD: Drift Velocity too small " << vdrift << " < " << fVDsmp[0]; vdrift = fVDsmp[0]; + retVal = false; } else if (vdrift > fVDsmp[7]) { - LOG(WARN) << "TRD: Drift Velocity too large " << vdrift << " > " << fVDsmp[6]; + LOG(DEBUG) << "TRD: Drift Velocity too large " << vdrift << " > " << fVDsmp[7]; vdrift = fVDsmp[7]; + retVal = false; } if (vdrift > fVDsmp[6]) { mVDlo = fVDsmp[6]; mVDhi = fVDsmp[7]; - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time2100[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2200[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time2100[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time2200[ctrt][ctrz]; } } } else if (vdrift > fVDsmp[5]) { mVDlo = fVDsmp[5]; mVDhi = fVDsmp[6]; - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time2000[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2100[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time2000[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time2100[ctrt][ctrz]; } } } else if (vdrift > fVDsmp[4]) { - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1900[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time2000[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time1900[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time2000[ctrt][ctrz]; } } mVDlo = fVDsmp[4]; mVDhi = fVDsmp[5]; } else if (vdrift > fVDsmp[3]) { - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1800[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1900[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time1800[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time1900[ctrt][ctrz]; } } mVDlo = fVDsmp[3]; mVDhi = fVDsmp[4]; } else if (vdrift > fVDsmp[2]) { - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1700[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1800[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time1700[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time1800[ctrt][ctrz]; } } mVDlo = fVDsmp[2]; mVDhi = fVDsmp[3]; } else if (vdrift > fVDsmp[1]) { - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1600[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1700[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time1600[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time1700[ctrt][ctrz]; } } mVDlo = fVDsmp[1]; mVDhi = fVDsmp[2]; } else if (vdrift > (fVDsmp[0] - 1.0e-5)) { - for (int ctrt = 0; ctrt < ktimebin; ctrt++) { - for (int ctrz = 0; ctrz < kZbin; ctrz++) { - mTimeStruct1[ctrt + ctrz * ktimebin] = time1500[ctrt][ctrz]; - mTimeStruct2[ctrt + ctrz * ktimebin] = time1600[ctrt][ctrz]; + for (int ctrt = 0; ctrt < TIMEBINSGARFIELD; ctrt++) { + for (int ctrz = 0; ctrz < ZBINSGARFIELD; ctrz++) { + mTimeStruct1[ctrt + ctrz * TIMEBINSGARFIELD] = Time1500[ctrt][ctrz]; + mTimeStruct2[ctrt + ctrz * TIMEBINSGARFIELD] = Time1600[ctrt][ctrz]; } } mVDlo = fVDsmp[0]; mVDhi = fVDsmp[1]; } mInvBinWidth = 1. / (mVDhi - mVDlo); + return retVal; } //_____________________________________________________________________________ -float DiffusionAndTimeStructEstimator::TimeStruct(float vdrift, float dist, float z) +float DiffusionAndTimeStructEstimator::timeStruct(float vdrift, float dist, float z, bool* errFlag) { // // Applies the time structure of the drift cells (by C.Lippmann). @@ -456,7 +137,9 @@ float DiffusionAndTimeStructEstimator::TimeStruct(float vdrift, float dist, floa // and fTimeStruct2, calculated for the two mentioned drift velocities. // - SampleTimeStruct(vdrift); + if (!sampleTimeStruct(vdrift)) { + *errFlag = true; + } // Indices: int r1 = (int)(10 * dist); @@ -516,7 +199,7 @@ float DiffusionAndTimeStructEstimator::TimeStruct(float vdrift, float dist, floa } //_____________________________________________________________________________ -bool DiffusionAndTimeStructEstimator::GetDiffCoeff(float& dl, float& dt, float vdrift) +bool DiffusionAndTimeStructEstimator::getDiffCoeff(float& dl, float& dt, float vdrift) { // // Calculates the diffusion coefficients in longitudinal <dl> and @@ -531,7 +214,7 @@ bool DiffusionAndTimeStructEstimator::GetDiffCoeff(float& dl, float& dt, float v } mDiffLastVdrift = vdrift; - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { // // Vd and B-field dependent diffusion and Lorentz angle // @@ -541,7 +224,7 @@ bool DiffusionAndTimeStructEstimator::GetDiffCoeff(float& dl, float& dt, float v // If looking at compatibility with AliRoot: // ibL and ibT are calculated the same way so, just define ib = ibL = ibT - int ib = ((int)(10 * (CommonParam::Instance()->GetCachedField() - 0.15))); + int ib = ((int)(10 * (CommonParam::instance()->getCachedField() - 0.15))); ib = std::max(0, ib); ib = std::min(kNb - 1, ib); @@ -564,7 +247,7 @@ bool DiffusionAndTimeStructEstimator::GetDiffCoeff(float& dl, float& dt, float v dl = mDiffusionL; dt = mDiffusionT; return true; - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { // // Diffusion constants and Lorentz angle only for B = 0.5T // diff --git a/Detectors/TRD/base/src/Digit.cxx b/Detectors/TRD/base/src/Digit.cxx deleted file mode 100644 index 529f3c6ef8c0f..0000000000000 --- a/Detectors/TRD/base/src/Digit.cxx +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TRDBase/Digit.h" diff --git a/Detectors/TRD/base/src/FeeParam.cxx b/Detectors/TRD/base/src/FeeParam.cxx index 38df171513dbf..6a1e89f47f04c 100644 --- a/Detectors/TRD/base/src/FeeParam.cxx +++ b/Detectors/TRD/base/src/FeeParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,12 +36,15 @@ #include <fairlogger/Logger.h> #include <array> +#include "DataFormatsTRD/HelperMethods.h" #include "DetectorsBase/GeometryManager.h" #include "TRDBase/Geometry.h" #include "TRDBase/PadPlane.h" #include "TRDBase/FeeParam.h" -#include "TRDBase/CommonParam.h" -//#include "DataFormatsTRD/Constants.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif using namespace std; using namespace o2::trd; @@ -49,38 +53,6 @@ using namespace o2::trd::constants; //_____________________________________________________________________________ FeeParam* FeeParam::mgInstance = nullptr; -bool FeeParam::mgTerminated = false; -bool FeeParam::mgTracklet = true; -bool FeeParam::mgRejectMultipleTracklets = false; -bool FeeParam::mgUseMisalignCorr = false; -bool FeeParam::mgUseTimeOffset = false; -bool FeeParam::mgLUTPadNumberingFilled = false; -std::vector<short> FeeParam::mgLUTPadNumbering; - -// definition of geometry constants -std::array<float, NCHAMBERPERSEC> FeeParam::mgZrow = { - 301, 177, 53, -57, -181, - 301, 177, 53, -57, -181, - 315, 184, 53, -57, -188, - 329, 191, 53, -57, -195, - 343, 198, 53, -57, -202, - 347, 200, 53, -57, -204}; -std::array<float, NLAYER> FeeParam::mgX = {300.65, 313.25, 325.85, 338.45, 351.05, 363.65}; -std::array<float, NLAYER> FeeParam::mgTiltingAngle = {-2., 2., -2., 2., -2., 2.}; -int FeeParam::mgDyMax = 63; -int FeeParam::mgDyMin = -64; -float FeeParam::mgBinDy = 140e-4; -std::array<float, NLAYER> FeeParam::mgWidthPad = {0.635, 0.665, 0.695, 0.725, 0.755, 0.785}; -std::array<float, NLAYER> FeeParam::mgLengthInnerPadC1 = {7.5, 7.5, 8.0, 8.5, 9.0, 9.0}; -std::array<float, NLAYER> FeeParam::mgLengthOuterPadC1 = {7.5, 7.5, 7.5, 7.5, 7.5, 8.5}; -std::array<float, NLAYER> FeeParam::mgInvX; -std::array<float, NLAYER> FeeParam::mgTiltingAngleTan; -std::array<float, NLAYER> FeeParam::mgInvWidthPad; - -float FeeParam::mgLengthInnerPadC0 = 9.0; -float FeeParam::mgLengthOuterPadC0 = 8.0; -float FeeParam::mgScalePad = 256. * 32.; -float FeeParam::mgDriftLength = 3.; //_____________________________________________________________________________ FeeParam* FeeParam::instance() @@ -88,124 +60,49 @@ FeeParam* FeeParam::instance() // // Instance constructor // - if (mgTerminated != false) { - return nullptr; - } +#ifdef WITH_OPENMP +#pragma omp critical +#endif + { // start omp critical block + if (mgInstance == nullptr) { + mgInstance = new FeeParam(); + } - if (mgInstance == nullptr) { - mgInstance = new FeeParam(); - } - // this is moved here to remove recursive calls induced by the line 2 above this one. - if (!mgLUTPadNumberingFilled) { - mgInstance->createPad2MCMLookUpTable(); - } - return mgInstance; + return mgInstance; + } // end omp critical block } -//_____________________________________________________________________________ -void FeeParam::terminate() -{ - // - // Terminate the class and release memory - // - - mgTerminated = true; - - if (mgInstance != nullptr) { - delete mgInstance; - mgInstance = nullptr; - } -} //_____________________________________________________________________________ -FeeParam::FeeParam() : mMagField(0.), - mOmegaTau(0.), - mPtMin(0.1), - mNtimebins(20 << 5), - mScaleQ0(0), - mScaleQ1(0), - mPidTracklengthCorr(false), - mTiltCorr(false), - mPidGainCorr(false) +FeeParam::FeeParam() { // // Default constructor // - mCP = CommonParam::Instance(); - - // These variables are used internally in the class to elliminate divisions. - // putting them at the top was messy. - int j = 0; - std::for_each(mgInvX.begin(), mgInvX.end(), [&j](float& x) { x = 1. / mgX[j]; }); - j = 0; - std::for_each(mgInvWidthPad.begin(), mgInvWidthPad.end(), [&j](float& x) { x = 1. / mgWidthPad[j]; }); - j = 0; - std::for_each(mgTiltingAngleTan.begin(), mgTiltingAngleTan.end(), [&j](float& x) { x = std::tan(mgTiltingAngle[j] * M_PI / 180.0); }); - - mInvPtMin = 1 / mPtMin; -} - -//_____________________________________________________________________________ -//FeeParam::FeeParam(TRootIoCtor*) -//{ -// -// IO constructor -// -//} - -//_____________________________________________________________________________ -FeeParam::FeeParam(const FeeParam& p) -{ - // - // FeeParam copy constructor - // - mRAWversion = p.mRAWversion; - mCP = p.mCP; - if (!mgLUTPadNumberingFilled) { - mgInstance->createPad2MCMLookUpTable(); - } -} - -//_____________________________________________________________________________ -FeeParam::~FeeParam() = default; - -//_____________________________________________________________________________ -FeeParam& FeeParam::operator=(const FeeParam& p) -{ - // - // Assignment operator - // - if (this != &p) { - ((FeeParam&)p).Copy(*this); + for (int j = 0; j < constants::NLAYER; ++j) { + mInvX[j] = 1. / mX[j]; + mInvWidthPad[j] = 1. / mWidthPad[j]; + mTiltingAngleTan[j] = std::tan(mTiltingAngle[j] * M_PI / 180.0); } - return *this; + fillPad2MCMLookUpTable(); } -//_____________________________________________________________________________ -void FeeParam::Copy(FeeParam& p) const -{ - // - // Copy function - // - p.mCP = mCP; - p.mRAWversion = mRAWversion; -} //_____________________________________________________________________________ -int FeeParam::getPadRowFromMCM(int irob, int imcm) const +int FeeParam::getPadRowFromMCM(int irob, int imcm) { // // Return on which pad row this mcm sits // - return NMCMROBINROW * (irob / 2) + imcm / NMCMROBINCOL; + return HelperMethods::getPadRowFromMCM(irob, imcm); } //_____________________________________________________________________________ -int FeeParam::getPadColFromADC(int irob, int imcm, int iadc) const +int FeeParam::getPadColFromADC(int irob, int imcm, int iadc) { // // Return which pad is connected to this adc channel. @@ -220,19 +117,11 @@ int FeeParam::getPadColFromADC(int irob, int imcm, int iadc) const // http://wiki.kip.uni-heidelberg.de/ti/TRD/index.php/Image:ROB_MCM_numbering.pdf // - if (iadc < 0 || iadc > NADCMCM) { - return -100; - } - int mcmcol = imcm % NMCMROBINCOL + getRobSide(irob) * NMCMROBINCOL; // MCM column number on ROC [0..7] - int padcol = mcmcol * NCOLMCM + NCOLMCM + 1 - iadc; - if (padcol < 0 || padcol >= NCOLUMN) { - return -1; // this is commented because of reason above OK - } - return padcol; + return HelperMethods::getPadColFromADC(irob, imcm, iadc); } //_____________________________________________________________________________ -int FeeParam::getExtendedPadColFromADC(int irob, int imcm, int iadc) const +int FeeParam::getExtendedPadColFromADC(int irob, int imcm, int iadc) { // // Return which pad coresponds to the extended digit container pad numbering @@ -243,28 +132,25 @@ int FeeParam::getExtendedPadColFromADC(int irob, int imcm, int iadc) const if (iadc < 0 || iadc > NADCMCM) { return -100; } - int mcmcol = imcm % NMCMROBINCOL + getRobSide(irob) * NMCMROBINCOL; // MCM column number on ROC [0..7] + int mcmcol = imcm % NMCMROBINCOL + getROBSide(irob) * NMCMROBINCOL; // MCM column number on ROC [0..7] int padcol = mcmcol * NADCMCM + NCOLMCM + 2 - iadc; return padcol; } //_____________________________________________________________________________ -int FeeParam::getMCMfromPad(int irow, int icol) const +int FeeParam::getMCMfromPad(int irow, int icol) { // // Return on which MCM this pad is directry connected. // Return -1 for error. // - if (irow < 0 || icol < 0 || irow > NROWC1 || icol > NCOLUMN) { - return -1; - } - return (icol % (NCOLUMN / 2)) / NCOLMCM + NMCMROBINCOL * (irow % NMCMROBINROW); + return HelperMethods::getMCMfromPad(irow, icol); } //_____________________________________________________________________________ -int FeeParam::getMCMfromSharedPad(int irow, int icol) const +int FeeParam::getMCMfromSharedPad(int irow, int icol) { // // Return on which MCM this pad is directry connected. @@ -295,16 +181,16 @@ int FeeParam::getMCMfromSharedPad(int irow, int icol) const } //_____________________________________________________________________________ -int FeeParam::getROBfromPad(int irow, int icol) const +int FeeParam::getROBfromPad(int irow, int icol) { // // Return on which rob this pad is // - return (irow / NMCMROBINROW) * 2 + getColSide(icol); + return HelperMethods::getROBfromPad(irow, icol); } //_____________________________________________________________________________ -int FeeParam::getROBfromSharedPad(int irow, int icol) const +int FeeParam::getROBfromSharedPad(int irow, int icol) { // // Return on which rob this pad is for shared pads @@ -318,31 +204,22 @@ int FeeParam::getROBfromSharedPad(int irow, int icol) const } //_____________________________________________________________________________ -int FeeParam::getRobSide(int irob) const +int FeeParam::getROBSide(int irob) { // // Return on which side this rob sits (A side = 0, B side = 1) // - - if (irob < 0 || irob >= NROBC1) { - return -1; - } - - return irob % 2; + return HelperMethods::getROBSide(irob); } //_____________________________________________________________________________ -int FeeParam::getColSide(int icol) const +int FeeParam::getColSide(int icol) { // // Return on which side this column sits (A side = 0, B side = 1) // - if (icol < 0 || icol >= NCOLUMN) { - return -1; - } - - return icol / (NCOLUMN / 2); + return HelperMethods::getColSide(icol); } unsigned int FeeParam::aliToExtAli(int rob, int aliid) @@ -367,7 +244,7 @@ int FeeParam::extAliToAli(unsigned int dest, unsigned short linkpair, unsigned s unsigned int cmA = 0, cmB = 0; // Chipmask for each A and B side // Default chipmask for 4 linkpairs (each bit correponds each alice-mcm) - static const unsigned int gkChipmaskDefLp[4] = {0x1FFFF, 0x1FFFF, 0x3FFFF, 0x1FFFF}; + const unsigned int gkChipmaskDefLp[4] = {0x1FFFF, 0x1FFFF, 0x3FFFF, 0x1FFFF}; rob = dest >> 7; // Extract ROB pattern from dest. mcm = dest & 0x07F; // Extract MCM pattern from dest. @@ -471,7 +348,7 @@ short FeeParam::getRobAB(unsigned short robsel, unsigned short linkpair) return 0; } -/* +/* void FeeParam::createORILookUpTable() { int ori; @@ -482,10 +359,10 @@ void FeeParam::createORILookUpTable() for(int trdlayer=5;trdlayer>=0;trdlayer++) { - ori=trdstack*12 + (5-trdlayer + side*6) +trdlayer/6 + side; - mgAsideLUT[ori]= (trdstack<<8) + (trdlayer<<4) + side; // A side LUT to map ORI to stack/layer/side + ori=trdstack*12 + (5-trdlayer + side*6) +trdlayer/6 + side; + mAsideLUT[ori]= (trdstack<<8) + (trdlayer<<4) + side; // A side LUT to map ORI to stack/layer/side if(ori==29) break; - + } if(ori==29) break; } @@ -501,7 +378,7 @@ void FeeParam::createORILookUpTable() ori = (4-trdstack)*12 + (5-trdlayer + side*5) +trdlayer/6 + side; int newside; if(ori >=24) newside=1; else newside=side; // a hack as I am not typing this all out. - mgCsideLUT[ori]= (trdstack<<8) + (trdlayer<<4) + newside; // A side LUT to map ORI to stack/layer/side + mCsideLUT[ori]= (trdstack<<8) + (trdlayer<<4) + newside; // A side LUT to map ORI to stack/layer/side if(ori==29) break; } if(ori==29) break; @@ -511,53 +388,45 @@ void FeeParam::createORILookUpTable() } */ -int FeeParam::getORI(int detector, int readoutboard) const +void FeeParam::unpackORI(int link, int side, int& stack, int& layer, int& halfchamberside) { - int supermodule = detector / 30; - LOG(debug3) << "getORI : " << detector << " :: " << readoutboard << getORIinSM(detector, readoutboard) + 60 * detector; - return getORIinSM(detector, readoutboard) + 2 * detector; // 2 ORI per detector -} - -int FeeParam::getORIinSM(int detector, int readoutboard) const -{ - int ori = -1; - int chamberside = 0; - int trdstack = Geometry::getStack(detector); - int trdlayer = Geometry::getLayer(detector); - int side = getRobSide(readoutboard); - //see TDP for explanation of mapping TODO should probably come from CCDB for the instances where the mapping of ori fibers is misconfigured (accidental fibre swaps). - if (trdstack < 2 || (trdstack == 2 && side == 0)) // A Side - { - ori = trdstack * 12 + (5 - trdlayer + side * 5) + trdlayer / 6 + side; // <- that is correct for A side at least for now, probably not for very long LUT as that will come form CCDB ni anycase. + // given the link 0-29 and the side A/C 0/1 return the stack layer and halfchamber side + if (side == 0) { + stack = link / 12; + layer = 5 - link % 6; + halfchamberside = (link / 6) % 2; } else { - if (trdstack > 2 || (trdstack == 2 && side == 1)) // CSide - { - int newside = side; - if (trdstack == 2) { - newside = 0; // the last part of C side CRU is a special case. - } - ori = (4 - trdstack) * 12 + (5 - trdlayer + newside * 5) + trdlayer / 6 + newside; - } else { - LOG(warn) << " something wrong with calculation of ORI for detector " << detector << " and readoutboard" << readoutboard; + //c side + stack = 4 - link / 12; + layer = 5 - link % 6; + halfchamberside = (link / 6) % 2; + if (link > 23) { + halfchamberside = 1; } } - // now offset for supermodule (+60*supermodule); +} - return ori; +int FeeParam::getORI(int detector, int readoutboard) +{ + int supermodule = detector / NCHAMBERPERSEC; + /// LOG(info) << "getORI : " << detector << " :: " << readoutboard << " -- " << getORIinSM(detector, readoutboard) << " " << getORIinSM(detector, readoutboard) + NCHAMBERPERSEC * 2 * detector; + return getORIinSuperModule(detector, readoutboard) + NCHAMBER * 2 * detector; // 60 ORI per supermodule } -int FeeParam::getORIfromHCID(int hcid) const +int FeeParam::getORIinSuperModule(int detector, int readoutboard) { - int detector = hcid / 2; - int side = hcid % 2; // 0 for side 0, 1 for side 1; - int ori = -1; - int chamberside = 0; - int trdstack = Geometry::getStack(detector); - int trdlayer = Geometry::getLayer(detector); - return getORIinSM(detector, side); // it takes readoutboard but only cares if its odd or even hence side here. - return 1; + return HelperMethods::getORIinSuperModule(detector, readoutboard); } -int FeeParam::getHCIDfromORI(int ori, int readoutboard) const + +int FeeParam::getLinkIDfromHCID(int hcid) +{ + return HelperMethods::getLinkIDfromHCID(hcid); + //return a number in range [0:29] for the link related to this hcid with in its respective CRU + //lower 15 is endpoint 0 and upper 15 is endpoint 1 + //a side has 30, c side has 30 to give 60 links for a supermodule +} + +int FeeParam::getHCIDfromORI(int ori, int readoutboard) { // ori = 60*SM+offset[0-29 A, 30-59 C] // from the offset, we can derive the stack/layer/side combination giving the decector. @@ -592,10 +461,10 @@ void FeeParam::setRAWversion(int rawver) { // // Set raw data version (major number only) - // Maximum available number is preset in mgkMaxRAWversion + // Maximum available number is preset in mkMaxRAWversion // - if (rawver >= 0 && rawver <= mgkMaxRAWversion) { + if (rawver >= 0 && rawver <= mkMaxRAWversion) { mRAWversion = rawver; } else { LOG(error) << "Raw version is out of range: " << rawver; @@ -606,24 +475,18 @@ void FeeParam::setRAWversion(int rawver) * This was originally moved here from arrayADC, signalADC etc. We now longer use those classes * so removing this for now as its crashing. */ -void FeeParam::createPad2MCMLookUpTable() +void FeeParam::fillPad2MCMLookUpTable() { // // Initializes the Look Up Table to relate // pad numbering and mcm channel numbering // - if (!mgLUTPadNumberingFilled) { - - LOG(debug) << " resizing lookup array to : " << NCOLUMN << " elements previously : " << mgLUTPadNumbering.size(); - mgLUTPadNumbering.resize(NCOLUMN); - memset(&mgLUTPadNumbering[0], 0, sizeof(mgLUTPadNumbering[0]) * NCOLUMN); - for (int mcm = 0; mcm < 8; mcm++) { - int lowerlimit = 0 + mcm * 18; - int upperlimit = 18 + mcm * 18; - int shiftposition = 1 + 3 * mcm; - for (int index = lowerlimit; index < upperlimit; index++) { - mgLUTPadNumbering[index] = index + shiftposition; - } + for (int mcm = 0; mcm < NMCMROBINCOL * 2; mcm++) { + int lowerlimit = mcm * NCOLMCM; + int upperlimit = NCOLMCM + mcm * NCOLMCM; + int shiftposition = 1 + 3 * mcm; + for (int index = lowerlimit; index < upperlimit; index++) { + mLUTPadNumbering[index] = index + shiftposition; } } } @@ -635,17 +498,17 @@ int FeeParam::getDyCorrection(int det, int rob, int mcm) const int layer = det % NLAYER; - float dyTilt = (mgDriftLength * std::tan(mgTiltingAngle[layer] * M_PI / 180.) * - getLocalZ(det, rob, mcm) * mgInvX[layer]); + float dyTilt = (mDriftLength * std::tan(mTiltingAngle[layer] * M_PI / 180.) * + getLocalZ(det, rob, mcm) * mInvX[layer]); // calculate Lorentz correction - float dyCorr = -mOmegaTau * mgDriftLength; + float dyCorr = -mOmegaTau * mDriftLength; if (mTiltCorr) { dyCorr += dyTilt; // add tilt correction } - return (int)TMath::Nint(dyCorr * mgScalePad * mgInvWidthPad[layer]); + return (int)TMath::Nint(dyCorr * mScalePad * mInvWidthPad[layer]); } void FeeParam::getDyRange(int det, int rob, int mcm, int ch, @@ -653,8 +516,8 @@ void FeeParam::getDyRange(int det, int rob, int mcm, int ch, { // calculate the deflection range in which tracklets are accepted - dyMinInt = mgDyMin; - dyMaxInt = mgDyMax; + dyMinInt = mDyMin; + dyMaxInt = mDyMax; // deflection cut is considered for |B| > 0.1 T only if (std::abs(mMagField) < 0.1) { @@ -670,26 +533,26 @@ void FeeParam::getDyRange(int det, int rob, int mcm, int ch, if (maxDeflTemp < std::cos(phi)) { float maxDeflAngle = std::asin(maxDeflTemp); - float dyMin = (mgDriftLength * + float dyMin = (mDriftLength * std::tan(phi - maxDeflAngle)); - dyMinInt = int(dyMin / mgBinDy); + dyMinInt = int(dyMin / mBinDy); // clipping to allowed range - if (dyMinInt < mgDyMin) { - dyMinInt = mgDyMin; - } else if (dyMinInt > mgDyMax) { - dyMinInt = mgDyMax; + if (dyMinInt < mDyMin) { + dyMinInt = mDyMin; + } else if (dyMinInt > mDyMax) { + dyMinInt = mDyMax; } - float dyMax = (mgDriftLength * + float dyMax = (mDriftLength * std::tan(phi + maxDeflAngle)); - dyMaxInt = int(dyMax / mgBinDy); + dyMaxInt = int(dyMax / mBinDy); // clipping to allowed range - if (dyMaxInt > mgDyMax) { - dyMaxInt = mgDyMax; - } else if (dyMaxInt < mgDyMin) { - dyMaxInt = mgDyMin; + if (dyMaxInt > mDyMax) { + dyMaxInt = mDyMax; + } else if (dyMaxInt < mDyMin) { + dyMaxInt = mDyMin; } } else if (maxDeflTemp < 0.) { // this must not happen @@ -701,8 +564,8 @@ void FeeParam::getDyRange(int det, int rob, int mcm, int ch, if ((dyMaxInt - dyMinInt) <= 0) { LOG(debug) << "strange dy range: [" << dyMinInt << "," << dyMaxInt << "], using max range now"; - dyMaxInt = mgDyMax; - dyMinInt = mgDyMin; + dyMaxInt = mDyMax; + dyMinInt = mDyMin; } } @@ -713,7 +576,7 @@ float FeeParam::getElongation(int det, int rob, int mcm, int ch) const int layer = det % NLAYER; - float elongation = std::abs(getDist(det, rob, mcm, ch) * mgInvX[layer]); + float elongation = std::abs(getDist(det, rob, mcm, ch) * mInvX[layer]); // sanity check if (elongation < 0.001) { @@ -753,7 +616,7 @@ float FeeParam::getX(int det, int /* rob */, int /* mcm */) const // return the distance to the beam axis in x-direction int layer = det % NLAYER; - return mgX[layer]; + return mX[layer]; } float FeeParam::getLocalY(int det, int rob, int mcm, int ch) const @@ -763,7 +626,7 @@ float FeeParam::getLocalY(int det, int rob, int mcm, int ch) const int layer = det % NLAYER; // calculate the pad position as in the TRAP float ypos = (-4 + 1 + (rob & 0x1) * 4 + (mcm & 0x3)) * 18 - ch - 0.5; // y position in bins of pad widths - return ypos * mgWidthPad[layer]; + return ypos * mWidthPad[layer]; } float FeeParam::getLocalZ(int det, int rob, int mcm) const @@ -776,19 +639,19 @@ float FeeParam::getLocalZ(int det, int rob, int mcm) const if (stack == 2) { if (row == 0) { - return (mgZrow[layer * NLAYER + stack] - 0.5 * mgLengthOuterPadC0); + return (mZrow[layer * NLAYER + stack] - 0.5 * mLengthOuterPadC0); } else if (row == 11) { - return (mgZrow[layer * NLAYER + stack] - 1.5 * mgLengthOuterPadC0 - (row - 1) * mgLengthInnerPadC0); + return (mZrow[layer * NLAYER + stack] - 1.5 * mLengthOuterPadC0 - (row - 1) * mLengthInnerPadC0); } else { - return (mgZrow[layer * NLAYER + stack] - mgLengthOuterPadC0 - (row - 0.5) * mgLengthInnerPadC0); + return (mZrow[layer * NLAYER + stack] - mLengthOuterPadC0 - (row - 0.5) * mLengthInnerPadC0); } } else { if (row == 0) { - return (mgZrow[layer * NLAYER + stack] - 0.5 * mgLengthOuterPadC1[layer]); + return (mZrow[layer * NLAYER + stack] - 0.5 * mLengthOuterPadC1[layer]); } else if (row == 15) { - return (mgZrow[layer * NLAYER + stack] - 1.5 * mgLengthOuterPadC1[layer] - (row - 1) * mgLengthInnerPadC1[layer]); + return (mZrow[layer * NLAYER + stack] - 1.5 * mLengthOuterPadC1[layer] - (row - 1) * mLengthInnerPadC1[layer]); } else { - return (mgZrow[layer * NLAYER + stack] - mgLengthOuterPadC1[layer] - (row - 0.5) * mgLengthInnerPadC1[layer]); + return (mZrow[layer * NLAYER + stack] - mLengthOuterPadC1[layer] - (row - 0.5) * mLengthInnerPadC1[layer]); } } } diff --git a/Detectors/TRD/base/src/Geometry.cxx b/Detectors/TRD/base/src/Geometry.cxx index 361644709bf73..c9f72d203cef7 100644 --- a/Detectors/TRD/base/src/Geometry.cxx +++ b/Detectors/TRD/base/src/Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/GeometryBase.cxx b/Detectors/TRD/base/src/GeometryBase.cxx index 167c9f73899c5..081f818821ff7 100644 --- a/Detectors/TRD/base/src/GeometryBase.cxx +++ b/Detectors/TRD/base/src/GeometryBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/GeometryFlat.cxx b/Detectors/TRD/base/src/GeometryFlat.cxx index 34ca9ee05db9f..b9867e57a0751 100644 --- a/Detectors/TRD/base/src/GeometryFlat.cxx +++ b/Detectors/TRD/base/src/GeometryFlat.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/LocalGainFactor.cxx b/Detectors/TRD/base/src/LocalGainFactor.cxx index 9d187784891f6..1b43c41d48e66 100644 --- a/Detectors/TRD/base/src/LocalGainFactor.cxx +++ b/Detectors/TRD/base/src/LocalGainFactor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/LocalT0.cxx b/Detectors/TRD/base/src/LocalT0.cxx index 04071027523f9..d9f55022ced45 100644 --- a/Detectors/TRD/base/src/LocalT0.cxx +++ b/Detectors/TRD/base/src/LocalT0.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/LocalVDrift.cxx b/Detectors/TRD/base/src/LocalVDrift.cxx index 6f4d9029a9414..f1bd370565f96 100644 --- a/Detectors/TRD/base/src/LocalVDrift.cxx +++ b/Detectors/TRD/base/src/LocalVDrift.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/PadNoise.cxx b/Detectors/TRD/base/src/PadNoise.cxx index ca91e7cb4107f..3913daa0ae859 100644 --- a/Detectors/TRD/base/src/PadNoise.cxx +++ b/Detectors/TRD/base/src/PadNoise.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/PadPlane.cxx b/Detectors/TRD/base/src/PadPlane.cxx index bc8a65c485869..3f63562a64e3d 100644 --- a/Detectors/TRD/base/src/PadPlane.cxx +++ b/Detectors/TRD/base/src/PadPlane.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,8 +25,10 @@ #include "TRDBase/PadPlane.h" #include <TMath.h> #include <FairLogger.h> +#include "DataFormatsTRD/Constants.h" using namespace o2::trd; +using namespace o2::trd::constants; //_____________________________________________________________________________ void PadPlane::setTiltingAngle(double t) @@ -35,7 +38,7 @@ void PadPlane::setTiltingAngle(double t) // mTiltingAngle = t; - mTiltingTan = TMath::Tan(TMath::Pi() / 180.0 * mTiltingAngle); + mTiltingTan = TMath::Tan(TMath::DegToRad() * mTiltingAngle); } //_____________________________________________________________________________ @@ -158,3 +161,57 @@ void PadPlane::setNrows(int n) } mNrows = n; }; + +double PadPlane::getPadRow(double z) const +{ + double lengthCorr = mLengthIPad * mInverseLengthOPad; + + // calculate position based on inner pad length + double padrow = -z * mInverseLengthIPad + mNrows * 0.5; + + // correct row for outer pad rows + if (padrow <= 1.0) { + padrow = 1.0 - (1.0 - padrow) * lengthCorr; + } + + if (padrow >= double(mNrows - 1)) { + padrow = double(mNrows - 1) + (padrow - double(mNrows - 1)) * lengthCorr; + } + + // sanity check: is the padrow coordinate reasonable? + assert(!(padrow < 0.0 || padrow > double(mNrows))); + + return padrow; +} + +double PadPlane::getPad(double y, double z) const +{ + int padrow = getPadRow(z); + double padrowOffset = getPadRowOffsetROC(padrow, z); + double tiltOffsetY = getTiltOffset(padrow, padrowOffset); + + double pad = y * mInverseWidthIPad + mNcols * 0.5; + + double lengthCorr = mWidthIPad * mInverseWidthOPad; + // correct row for outer pad rows + if (pad <= 1.0) { + pad = 1.0 - (1.0 - pad) * lengthCorr; + } + + if (pad >= double(mNcols - 1)) { + pad = double(mNcols - 1) + (pad - double(mNcols - 1)) * lengthCorr; + } + + double tiltOffsetPad; + if (pad <= 1.0 || pad >= double(mNcols - 1)) { + tiltOffsetPad = tiltOffsetY * mInverseWidthOPad; + pad += tiltOffsetPad; + } else { + tiltOffsetPad = tiltOffsetY * mInverseWidthIPad; + pad += tiltOffsetPad; + } + + assert(!(pad < 0.0 || pad > double(mNcols))); + + return pad; +} diff --git a/Detectors/TRD/base/src/PadResponse.cxx b/Detectors/TRD/base/src/PadResponse.cxx index c011add451b66..458a16b2e0fe7 100644 --- a/Detectors/TRD/base/src/PadResponse.cxx +++ b/Detectors/TRD/base/src/PadResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/PadStatus.cxx b/Detectors/TRD/base/src/PadStatus.cxx index 2f5e3d1ad6f75..d3a38fbe6433c 100644 --- a/Detectors/TRD/base/src/PadStatus.cxx +++ b/Detectors/TRD/base/src/PadStatus.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/RecoParam.cxx b/Detectors/TRD/base/src/RecoParam.cxx new file mode 100644 index 0000000000000..2bca5d0327f5f --- /dev/null +++ b/Detectors/TRD/base/src/RecoParam.cxx @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file RecoParam.cxx +/// \brief Error parameterizations and helper functions for TRD reconstruction +/// \author Ole Schmidt + +#include "TRDBase/RecoParam.h" +#include <fairlogger/Logger.h> +#include <cmath> + +using namespace o2::trd; + +// error parameterizations taken from http://cds.cern.ch/record/2724259 Appendix A +void RecoParam::setBfield(float bz) +{ + if (std::fabs(std::fabs(bz) - 2) < 0.1) { + if (bz > 0) { + // magnetic field +0.2 T + mA2 = 1.6e-3f; + mB = -1.43e-2f; + mC2 = 4.55e-2f; + } else { + // magnetic field -0.2 T + mA2 = 1.6e-3f; + mB = 1.43e-2f; + mC2 = 4.55e-2f; + } + } else if (std::fabs(std::fabs(bz) - 5) < 0.1) { + if (bz > 0) { + // magnetic field +0.5 T + mA2 = 1.6e-3f; + mB = 0.125f; + mC2 = 0.0961f; + } else { + // magnetic field -0.5 T + mA2 = 1.6e-3f; + mB = -0.14f; + mC2 = 0.1156f; + } + } else { + LOG(WARNING) << "No error parameterization available for Bz= " << bz << ". Keeping default value (sigma_y = const. = 1cm)"; + } +} + +void RecoParam::recalcTrkltCov(const float tilt, const float snp, const float rowSize, std::array<float, 3>& cov) const +{ + float t2 = tilt * tilt; // tan^2 (tilt) + float c2 = 1.f / (1.f + t2); // cos^2 (tilt) + float sy2 = getRPhiRes(snp); + float sz2 = rowSize * rowSize / 12.f; + cov[0] = c2 * (sy2 + t2 * sz2); + cov[1] = c2 * tilt * (sz2 - sy2); + cov[2] = c2 * (t2 * sy2 + sz2); +} diff --git a/Detectors/TRD/base/src/SimParam.cxx b/Detectors/TRD/base/src/SimParam.cxx index 83223d8af1b23..97fb36ed3365c 100644 --- a/Detectors/TRD/base/src/SimParam.cxx +++ b/Detectors/TRD/base/src/SimParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,160 +19,48 @@ //////////////////////////////////////////////////////////////////////////// #include "TRDBase/SimParam.h" -#include <TMath.h> #include "TRDBase/CommonParam.h" #include <FairLogger.h> using namespace o2::trd; ClassImp(SimParam); -SimParam* SimParam::fgInstance = nullptr; -bool SimParam::fgTerminated = false; +SimParam* SimParam::mgInstance = nullptr; //_ singleton implementation __________________________________________________ -SimParam* SimParam::Instance() +SimParam* SimParam::instance() { // // Singleton implementation // Returns an instance of this class, it is created if neccessary // - if (fgTerminated != false) { - return nullptr; + if (mgInstance == nullptr) { + mgInstance = new SimParam(); } - if (fgInstance == nullptr) { - fgInstance = new SimParam(); - } - - return fgInstance; -} - -//_ singleton implementation __________________________________________________ -void SimParam::Terminate() -{ - // - // Singleton implementation - // Deletes the instance of this class and sets the terminated flag, - // instances cannot be requested anymore - // This function can be called several times. - // - - fgTerminated = true; - - if (fgInstance != nullptr) { - delete fgInstance; - fgInstance = nullptr; - } + return mgInstance; } //_____________________________________________________________________________ SimParam::SimParam() - : mGasGain(0.0), - mNoise(0.0), - mChipGain(0.0), - mADCoutRange(0.0), - mADCinRange(0.0), - mADCbaseline(0), - mDiffusionOn(false), - mElAttachOn(false), - mElAttachProp(0.0), - mTRFOn(false), - mTRFsmp(nullptr), - mTRFbin(0), - mTRFlo(0.0), - mTRFhi(0.0), - mInvTRFwid(0.0), - mCTOn(false), - mCTsmp(nullptr), - mPadCoupling(0.0), - mTimeCoupling(0.0), - mTimeStructOn(false), - mPRFOn(false), - mNTimeBins(0), - mNTBoverwriteOCDB(false) { // // Default constructor // - - Init(); + sampleTRF(); } -//_____________________________________________________________________________ -void SimParam::Init() -{ - // - // Default initializiation - // - - // The default parameter for the digitization - mGasGain = 4000.0; - mChipGain = 12.4; - mNoise = 1250.0; - mADCoutRange = 1023.0; // 10-bit ADC - mADCinRange = 2000.0; // 2V input range - mADCbaseline = 10; - - // Diffusion on - mDiffusionOn = true; - - // Propability for electron attachment - mElAttachOn = false; - mElAttachProp = 0.0; - - // The time response function - mTRFOn = true; - - // The cross talk - mCTOn = true; - - // The pad coupling factor - // Use 0.46, instead of the theroetical value 0.3, since it reproduces better - // the test beam data, even tough it is not understood why. - mPadCoupling = 0.46; - // The time coupling factor (same number as for the TPC) - mTimeCoupling = 0.4; - - // Use drift time maps - mTimeStructOn = true; - - // The pad response function - mPRFOn = true; - - // The number of time bins - mNTimeBins = 22; - mNTBoverwriteOCDB = false; - - ReInit(); -} - -//_____________________________________________________________________________ -SimParam::~SimParam() -{ - // - // Destructor - // - if (mTRFsmp) { - delete[] mTRFsmp; - mTRFsmp = nullptr; - } - - if (mCTsmp) { - delete[] mCTsmp; - mCTsmp = nullptr; - } -} //_____________________________________________________________________________ -void SimParam::ReInit() +void SimParam::reInit() { // - // Reinitializes the parameter class after a change + // Reinitializes the parameter class after a change of the gas mixture // - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { // The range and the binwidth for the sampled TRF mTRFbin = 200; // Start 0.2 mus before the signal @@ -180,7 +69,7 @@ void SimParam::ReInit() mTRFhi = 3.58; // Standard gas gain mGasGain = 4000.0; - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { // The range and the binwidth for the sampled TRF mTRFbin = 50; // Start 0.2 mus before the signal @@ -195,11 +84,11 @@ void SimParam::ReInit() mInvTRFwid = ((float)mTRFbin) / (mTRFhi - mTRFlo); // Inverse of the bin width of the integrated TRF // Create the sampled TRF - SampleTRF(); + sampleTRF(); } //_____________________________________________________________________________ -void SimParam::SampleTRF() +void SimParam::sampleTRF() { // // Samples the new time response function. @@ -228,9 +117,7 @@ void SimParam::SampleTRF() 0.0138, 0.0135, 0.0133, 0.0131, 0.0128, 0.0126, 0.0124, 0.0121, 0.0119, 0.0120, 0.0115, 0.0113, 0.0111, 0.0109, 0.0107, 0.0105, 0.0103, 0.0101, 0.0100, 0.0098, 0.0096, 0.0094, 0.0092, 0.0091, 0.0089, 0.0088, 0.0086, 0.0084, 0.0083, 0.0081, 0.0080, 0.0078}; - signal[0] = 0.0; - signal[1] = 0.0; - signal[2] = 0.0; + // With undershoot, positive peak corresponds to ~3% of the main signal: for (ipasa = 3; ipasa < kNpasa; ipasa++) { xtalk[ipasa] = 0.2 * (signal[ipasa - 2] - signal[ipasa - 3]); @@ -263,31 +150,12 @@ void SimParam::SampleTRF() xtalkAr[1] = 0.0; xtalkAr[2] = 0.0; - if (mTRFsmp) { - delete[] mTRFsmp; - } - mTRFsmp = new float[mTRFbin]; - - if (mCTsmp) { - delete[] mCTsmp; - } - mCTsmp = new float[mTRFbin]; - - if (CommonParam::Instance()->IsXenon()) { - if (mTRFbin != kNpasa) { - LOG(ERROR) << "Array mismatch (xenon)\n\n"; - } - } else if (CommonParam::Instance()->IsArgon()) { - if (mTRFbin != kNpasaAr) { - LOG(ERROR) << "Array mismatch (argon)\n\n"; - } - } for (int iBin = 0; iBin < mTRFbin; iBin++) { - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { mTRFsmp[iBin] = signal[iBin]; mCTsmp[iBin] = xtalk[iBin]; - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { mTRFsmp[iBin] = signalAr[iBin]; mCTsmp[iBin] = xtalkAr[iBin]; } diff --git a/Detectors/TRD/base/src/TRDBaseLinkDef.h b/Detectors/TRD/base/src/TRDBaseLinkDef.h index 7b9247326057c..065290df7ecb3 100644 --- a/Detectors/TRD/base/src/TRDBaseLinkDef.h +++ b/Detectors/TRD/base/src/TRDBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,8 @@ #pragma link C++ class o2::trd::GeometryBase + ; #pragma link C++ class o2::trd::CommonParam + ; #pragma link C++ class o2::trd::SimParam + ; -#pragma link C++ class o2::trd::Digit + ; -#pragma link C++ class std::vector < o2::trd::Digit> + ; #pragma link C++ class o2::trd::FeeParam + ; +#pragma link C++ class o2::trd::RecoParam + ; #pragma link C++ class o2::trd::CalDet + ; #pragma link C++ class o2::trd::CalROC + ; #pragma link C++ class o2::trd::PadResponse + ; @@ -45,10 +45,5 @@ #pragma link C++ class o2::trd::Tracklet + ; #pragma link C++ class std::vector < o2::trd::Tracklet > +; -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" - -// this is just needed to please the DPL ROOTTreeWriter facility -#pragma link C++ class o2::dataformats::ConstMCTruthContainer < o2::trd::MCLabel> + ; #endif diff --git a/Detectors/TRD/base/src/Tracklet.cxx b/Detectors/TRD/base/src/Tracklet.cxx index 723cdffcae627..a7933f49cc1d0 100644 --- a/Detectors/TRD/base/src/Tracklet.cxx +++ b/Detectors/TRD/base/src/Tracklet.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/base/src/TrackletTransformer.cxx b/Detectors/TRD/base/src/TrackletTransformer.cxx new file mode 100644 index 0000000000000..26f2cf02c5685 --- /dev/null +++ b/Detectors/TRD/base/src/TrackletTransformer.cxx @@ -0,0 +1,168 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsBase/GeometryManager.h" +#include "TRDBase/TrackletTransformer.h" +#include "TMath.h" + +using namespace o2::trd; +using namespace o2::trd::constants; + +TrackletTransformer::TrackletTransformer() +{ + o2::base::GeometryManager::loadGeometry(); + mGeo = Geometry::instance(); + mGeo->createPadPlaneArray(); + mGeo->createClusterMatrixArray(); + + // 3 cm + mXCathode = mGeo->cdrHght(); + // 3.35 + mXAnode = mGeo->cdrHght() + mGeo->camHght() / 2; + // 5mm below cathode plane to reduce error propogation from tracklet fit and driftV + mXDrift = mGeo->cdrHght() - 0.5; + mXtb0 = -100; + + // dummy values for testing. This will change in the future when values are pulled from CCDB + mt0Correction = -0.279; + mLorentzAngle = 0.14; + mDriftVRatio = 1.1; +} + +void TrackletTransformer::loadPadPlane(int hcid) +{ + int detector = hcid / 2; + int stack = mGeo->getStack(detector); + int layer = mGeo->getLayer(detector); + mPadPlane = mGeo->getPadPlane(layer, stack); +} + +float TrackletTransformer::calculateY(int hcid, int column, int position) +{ + double padWidth = mPadPlane->getWidthIPad(); + int side = hcid % 2; + + // the position calculated in TRAPsim is a signed integer + int positionUnsigned = 0; + if (position & (1 << (NBITSTRKLPOS - 1))) { + positionUnsigned = -((~(position - 1)) & ((1 << NBITSTRKLPOS) - 1)); + } else { + positionUnsigned = position & ((1 << NBITSTRKLPOS) - 1); + } + positionUnsigned += 1 << (NBITSTRKLPOS - 1); // shift such that positionUnsigned = 1 << (NBITSTRKLPOS - 1) corresponds to the MCM center + + // slightly modified TDP eq 16.1 (appended -1 to the end to account for MCM shared pads) + double pad = float(positionUnsigned - (1 << (NBITSTRKLPOS - 1))) * GRANULARITYTRKLPOS + NCOLMCM * (4 * side + column) + 10. - 1.; + float y = padWidth * (pad - 72); + + return y; +} + +float TrackletTransformer::calculateZ(int padrow) +{ + double rowPos = mPadPlane->getRowPos(padrow); + double rowSize = mPadPlane->getRowSize(padrow); + double middleRowPos = mPadPlane->getRowPos(mPadPlane->getNrows() / 2); + + return rowPos - rowSize / 2. - middleRowPos; +} + +float TrackletTransformer::calculateDy(int slope, double lorentzAngle, double driftVRatio) +{ + double padWidth = mPadPlane->getWidthIPad(); + + // temporary dummy value in cm/microsecond + float vDrift = 1.5464f; + + int slopeSigned = 0; + if (slope & (1 << (NBITSTRKLSLOPE - 1))) { + slopeSigned = -((~(slope - 1)) & ((1 << NBITSTRKLSLOPE) - 1)); + } else { + slopeSigned = slope & ((1 << NBITSTRKLSLOPE) - 1); + } + + // dy = slope * nTimeBins * padWidth * GRANULARITYTRKLSLOPE; + // nTimeBins should be number of timebins in drift region. 1 timebin is 100 nanosecond + double rawDy = slopeSigned * ((mXCathode / vDrift) * 10.) * padWidth * GRANULARITYTRKLSLOPE; + + // NOTE: check what drift height is used in calibration code to ensure consistency + // NOTE: check sign convention of Lorentz angle + // NOTE: confirm the direction in which vDrift is measured/determined. Is it in x or in direction of drift? + double lorentzCorrection = TMath::Tan(lorentzAngle) * mXAnode; + + // assuming angle in Bailhache, fig. 4.17 would be positive in our calibration code + double calibratedDy = rawDy - lorentzCorrection; + + return rawDy; +} + +float TrackletTransformer::calibrateX(double x, double t0Correction) +{ + return x += t0Correction; +} + +std::array<float, 3> TrackletTransformer::transformL2T(int hcid, std::array<double, 3> point) +{ + int detector = hcid / 2; + auto transformationMatrix = mGeo->getMatrixT2L(detector); + + ROOT::Math::Impl::Transform3D<double>::Point localPoint(point[0], point[1], point[2]); + auto gobalPoint = transformationMatrix ^ localPoint; + + return {(float)gobalPoint.x(), (float)gobalPoint.y(), (float)gobalPoint.z()}; +} + +CalibratedTracklet TrackletTransformer::transformTracklet(Tracklet64 tracklet) +{ + uint64_t hcid = tracklet.getHCID(); + uint64_t padrow = tracklet.getPadRow(); + uint64_t column = tracklet.getColumn(); + uint64_t position = tracklet.getPosition(); + uint64_t slope = tracklet.getSlope(); + + // calculate raw local chamber space point + loadPadPlane(hcid); + float x = getXDrift(); + float y = calculateY(hcid, column, position); + float z = calculateZ(padrow); + + float dy = calculateDy(slope, mLorentzAngle, mDriftVRatio); + float calibratedX = calibrateX(x, mt0Correction); + // NOTE: Correction to y position based on x calibration NOT YET implemented. Need t0. + + std::array<float, 3> sectorSpacePoint = transformL2T(hcid, std::array<double, 3>{calibratedX, y, z}); + + LOG(debug) << "x: " << sectorSpacePoint[0] << " | " + << "y: " << sectorSpacePoint[1] << " | " + << "z: " << sectorSpacePoint[2]; + + return CalibratedTracklet(sectorSpacePoint[0], sectorSpacePoint[1], sectorSpacePoint[2], dy); +} + +double TrackletTransformer::getTimebin(double x) +{ + // calculate timebin from x position within chamber + // calibration parameters need to be extracted from CCDB in the future + double vDrift = 1.5625; // in cm/us + double t0 = 4.0; // time (in timebins) of start of drift region + + double timebin; + // x = 0 at anode plane and points toward pad plane. + if (x < -mGeo->camHght() / 2) { + // drift region + timebin = t0 - (x + mGeo->camHght() / 2) / (vDrift * 0.1); + } else { + // anode region: very rough guess + timebin = t0 - 1.0 + fabs(x); + } + + return timebin; +} diff --git a/Detectors/TRD/base/test/testCoordinateTransforms.cxx b/Detectors/TRD/base/test/testCoordinateTransforms.cxx new file mode 100644 index 0000000000000..1e71a86b39560 --- /dev/null +++ b/Detectors/TRD/base/test/testCoordinateTransforms.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file testCoordinateTransformscxx +/// \brief Test local to row-column (float) coordinate transformations in PadPlane class +/// \author Jason Barrella - jbarrell@cern.ch, Sean Murray - murrays@cern.ch + +#define BOOST_TEST_MODULE Test CoordinateTransforms +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <iostream> +#include <numeric> + +#include "DataFormatsTRD/Constants.h" +#include "TRDBase/TrackletTransformer.h" + +#include "TRDBase/PadPlane.h" +#include "DetectorsBase/GeometryManager.h" +#include "TRDBase/Geometry.h" + +namespace o2 +{ +namespace trd +{ + +using namespace o2::trd::constants; +using namespace std; + +void testRCPoint(double calculatedPoint, double predictedPoint) +{ + float e = 0.000001; + BOOST_CHECK(fabs(predictedPoint - calculatedPoint) <= e); +} + +BOOST_AUTO_TEST_CASE(LocaltoRCTest) +{ + auto mGeo = o2::trd::Geometry::instance(); + mGeo->createPadPlaneArray(); + mGeo->createClusterMatrixArray(); + + int hcid = 776; + // This C1 chamber has 16 pad rows with I pad length = 90mm and O pad length = 75mm + int detector = hcid / 2; + int stack = mGeo->getStack(detector); + int layer = mGeo->getLayer(detector); + + auto padPlane = mGeo->getPadPlane(layer, stack); + double lengthIPad = padPlane->getLengthIPad(); + double lengthOPad = padPlane->getLengthOPad(); + + double padIWidth = padPlane->getWidthIPad(); + double padOWidth = padPlane->getWidthOPad(); + + double tiltingAngle = padPlane->getTiltingAngle(); + + // Test padrows + auto p1 = padPlane->getPadRow(0); + // Center of the chamber. This should return the lower edge of padrow 8. + // Since we are using float values, the lower edge of padrow 8 correspond with float value 8.0. + testRCPoint(p1, 8.); + + auto p2 = padPlane->getPadRow(lengthIPad / 2.); + // With an I pad length of 9 cm, 9. / 2. should put us half way into the preceeding pad (pad 7) since padrow number + // decreses in positive z direction. + testRCPoint(p2, 7.5); + + auto p3 = padPlane->getPadRow(-lengthIPad / 2.); + // Same as above but in the other direction. + testRCPoint(p3, 8.5); + + auto p4 = padPlane->getPadRow(lengthIPad * 4.2); + // Arbitrary distance in z. + testRCPoint(p4, 8 - 4.2); + + auto p5 = padPlane->getPadRow(lengthIPad * 7 + lengthOPad); + // Lower border case. Take center and add 7 pads * 9 cm + 1 pad * 7.5 cm. + testRCPoint(p5, 0); + + auto p6 = padPlane->getPadRow(-lengthIPad * 7 - lengthOPad); + // Upper border case. Take center and subtract 7 pads * 9 cm - 1 pad * 7.5 cm. + testRCPoint(p6, 16); + + // Test pads with pad tilting + double p13 = padPlane->getPad(0, 0.01); + // Center of chamber plus epsilon (in z). Note the discontinuity in pad vs. z at z=0. This puts us at a point on the lower + // (in z direction) end of padrow 7. Since we have a pad tilt of -2 deg (pads tilted clockwise for particle coming + // from interaction vertex). After a lot thought and doodles on Miro (https://miro.com/app/board/o9J_lKgybMc=/) we + // find that we expect a small negative offset which would place us in the upper half of pad 71. + // To calculate that offset, we multiply the tangent of the tilting angle by the distance that our point is away + // from the center of its local padrow. Some unit conversions are also neccessary... + testRCPoint(p13, 72 + TMath::Tan(TMath::DegToRad() * tiltingAngle) * (0.5 * lengthIPad - 0.01) / padIWidth); + + double p14 = padPlane->getPad(0, -lengthIPad / 2.); + // Move from center of chamber to to center of padrow 8 = 8.5. + // This should now place us as edge of pad 72 = 72.0 since no offset is applied from pad tilt. + testRCPoint(p14, 72); + + double p15 = padPlane->getPad(0, lengthIPad / 2.); + // Should be the same in the other direction at padrow = 7.5 + testRCPoint(p15, 72); + + double p16 = padPlane->getPad(padIWidth * 42, lengthIPad / 2.); + // Adding an arbitrary number of pads should just increase position by same number + testRCPoint(p16, 72 + 42); + + double p17 = padPlane->getPad(padIWidth * 42, -lengthIPad * 4 - 2.3); + // Moving to arbitrary point in both y and z. In y, we are 42 pads from the center which would be 72 + 42 = 114 + // if we were in the center of the padrow and no pad tilting is considered. However, we are not in the center of + // a padrow, but rather 2.3 cm into padrow 8 + 4 = 12. This puts us below the center which is at 4.5 cm + // into the padrow and therefore, we expect a small postiive offset since the pad tilting angle is -2 deg. + testRCPoint(p17, 72 + 42 + TMath::Tan(TMath::DegToRad() * tiltingAngle) * (2.3 - 0.5 * lengthIPad) / padIWidth); + + double p18 = padPlane->getPad(padIWidth * 71 + padOWidth, lengthIPad / 2.); + // Border case right on the upper edge of the padrow in y direction and at the center of the padrow in z + testRCPoint(p18, 144); + + double p19 = padPlane->getPad(-padIWidth * 71 - padOWidth, lengthIPad / 2.); + // Border case right on the lower edge of the padrow in y direction and at the center of the padrow in z + testRCPoint(p19, 0); + + double p20 = padPlane->getPad(0, lengthIPad * 7 + 1.5); + // Ensure that shorter length of outer padrows is considered correctly + testRCPoint(p20, 72 + TMath::Tan(TMath::DegToRad() * tiltingAngle) * (0.5 * lengthOPad - 1.5) / padIWidth); +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/base/test/testRawData.cxx b/Detectors/TRD/base/test/testRawData.cxx index f9b88a690be6c..e3384d0a42255 100644 --- a/Detectors/TRD/base/test/testRawData.cxx +++ b/Detectors/TRD/base/test/testRawData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -82,8 +83,8 @@ BOOST_AUTO_TEST_CASE(TRDRawDataHeaderInternals) mcmrawdataheader.word = 0x01fe; BOOST_CHECK_EQUAL(mcmrawdataheader.pid0, 0xff); // 8 bits //check tracklet - tracklet.word = 0xffc00000; - BOOST_CHECK_EQUAL((uint32_t)tracklet.pos, 0x3ff); + tracklet.word = 0xffe00000; + BOOST_CHECK_EQUAL((uint32_t)tracklet.pos, 0x7ff); } } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/base/test/testTRDDiffusionCoefficient.cxx b/Detectors/TRD/base/test/testTRDDiffusionCoefficient.cxx index 55355fc7ef386..2657e189717b2 100644 --- a/Detectors/TRD/base/test/testTRDDiffusionCoefficient.cxx +++ b/Detectors/TRD/base/test/testTRDDiffusionCoefficient.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,56 +35,17 @@ BOOST_AUTO_TEST_CASE(TRDDiffusionCoefficient_test1) TGeoGlobalMagField::Instance()->SetField(fld); TGeoGlobalMagField::Instance()->Lock(); - auto commonParam = CommonParam::Instance(); + auto commonParam = CommonParam::instance(); + DiffusionAndTimeStructEstimator estimator; float dl = 0; float dt = 0; float vd = 1.48; - commonParam->GetDiffCoeff(dl, dt, vd); + estimator.getDiffCoeff(dl, dt, vd); // check whether the values match the expected AliRoot known output BOOST_CHECK_CLOSE(dl, 0.0255211, 0.1); BOOST_CHECK_CLOSE(dt, 0.0179734, 0.1); } -/// \brief Test time structure -BOOST_AUTO_TEST_CASE(TRDTimeStructure_test) -{ - auto commonParam = CommonParam::Instance(); - DiffusionAndTimeStructEstimator estimator; - BOOST_CHECK_CLOSE(estimator.TimeStruct(1.48, 1., 0.1), commonParam->TimeStruct(1.48, 1., 0.1), 0.001); - BOOST_CHECK_CLOSE(estimator.TimeStruct(1.1, 1., 0.1), commonParam->TimeStruct(1.1, 1., 0.1), 0.001); - BOOST_CHECK_CLOSE(estimator.TimeStruct(2, 1., 0.1), commonParam->TimeStruct(2, 1., 0.1), 0.001); - BOOST_CHECK_CLOSE(estimator.TimeStruct(4, 1., 0.1), commonParam->TimeStruct(4, 1., 0.1), 0.001); -} - -/// \brief compare diffusion coeff -BOOST_AUTO_TEST_CASE(TRDDiffusion_test) -{ - auto commonParam = CommonParam::Instance(); - DiffusionAndTimeStructEstimator estimator; - float dl1 = 0.; - float dl2 = 0.; - float dt1 = 0.; - float dt2 = 0.; - estimator.GetDiffCoeff(dl1, dt1, 1.48); - commonParam->GetDiffCoeff(dl2, dt2, 1.48); - BOOST_CHECK_CLOSE(dl1, dl2, 0.001); - BOOST_CHECK_CLOSE(dt1, dt2, 0.001); - - estimator.GetDiffCoeff(dl1, dt1, 1.1); - commonParam->GetDiffCoeff(dl2, dt2, 1.1); - BOOST_CHECK_CLOSE(dl1, dl2, 0.001); - BOOST_CHECK_CLOSE(dt1, dt2, 0.001); - - estimator.GetDiffCoeff(dl1, dt1, 2); - commonParam->GetDiffCoeff(dl2, dt2, 2); - BOOST_CHECK_CLOSE(dl1, dl2, 0.001); - BOOST_CHECK_CLOSE(dt1, dt2, 0.001); - - estimator.GetDiffCoeff(dl1, dt1, 4); - commonParam->GetDiffCoeff(dl2, dt2, 4); - BOOST_CHECK_CLOSE(dl1, dl2, 0.001); - BOOST_CHECK_CLOSE(dt1, dt2, 0.001); -} } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/base/test/testTRDGeometry.cxx b/Detectors/TRD/base/test/testTRDGeometry.cxx index 976f20b9a2699..d37da2efa5148 100644 --- a/Detectors/TRD/base/test/testTRDGeometry.cxx +++ b/Detectors/TRD/base/test/testTRDGeometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/calibration/CMakeLists.txt b/Detectors/TRD/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..22908f84e6552 --- /dev/null +++ b/Detectors/TRD/calibration/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TRDCalibration + SOURCES src/TrackBasedCalib.cxx + src/CalibratorVdExB.cxx + src/KrClusterFinder.cxx + PUBLIC_LINK_LIBRARIES O2::TRDBase + O2::DataFormatsTRD + O2::DataFormatsGlobalTracking + O2::DetectorsBase + O2::DetectorsCalibration + O2::MathUtils + O2::GPUTracking) + + o2_target_root_dictionary(TRDCalibration + HEADERS include/TRDCalibration/TrackBasedCalib.h + include/TRDCalibration/CalibratorVdExB.h + include/TRDCalibration/KrClusterFinder.h) diff --git a/Detectors/TRD/calibration/README.md b/Detectors/TRD/calibration/README.md new file mode 100644 index 0000000000000..71ea8267b8076 --- /dev/null +++ b/Detectors/TRD/calibration/README.md @@ -0,0 +1,18 @@ +<!-- doxy +\page refTRDcalibration TRD calibration +/doxy --> + +# TRD calibration in O2 + +## vDrift and ExB calibration + +The drift velocity and ExB angle are calibrated using input from the global tracking, namely ITS-TPC-TRD and TPC-TRD tracks. The latter is currently disabled, but can be enabled to have more statistics easily. From the global tracks we obtain the association of TRD tracklets to tracks. In the calibration procedure a refit is performed to get TRD only tracks and the angular deviations between those TRD tracks and the associated tracklets are stored in histograms (see class TrackBasedCalib). This is done on the EPNs during the reconstruction. The histograms are send to aggregator nodes which calculate for each TRD chamber the drift velocity and ExB angle based on those histograms (see class CalibratorVdExB). + +To run the calibration one can start the following workflow: + o2-trd-global-tracking -b --disable-root-output | o2-calibration-trd-vdrift-exb -b --calib-vdexb-calibration '--tf-per-slot 5 --min-entries 50000 --max-delay 90000' +You can get information on the meaning of the parameters by running `o2-calibration-trd-vdrift-exb -b --help full` + +If you want to run the calibration from a local file with residuals, trdangreshistos.root, you can run: + o2-calibration-trd-vdrift-exb -b --enable-root-input --calib-vdexb-calibration '--tf-per-slot 1 --min-entries 50000' + +## DCS data points diff --git a/Detectors/TRD/calibration/include/TRDCalibration/CalibratorVdExB.h b/Detectors/TRD/calibration/include/TRDCalibration/CalibratorVdExB.h new file mode 100644 index 0000000000000..8e01fa6bb5d7c --- /dev/null +++ b/Detectors/TRD/calibration/include/TRDCalibration/CalibratorVdExB.h @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibratorVdExB.h +/// \brief TimeSlot-based calibration of vDrift and ExB +/// \author Ole Schmidt + +#ifndef O2_TRD_CALIBRATORVDEXB_H +#define O2_TRD_CALIBRATORVDEXB_H + +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/AngularResidHistos.h" + +#include "Rtypes.h" +#include "TProfile.h" + +#include <array> +#include <cstdlib> + +namespace o2 +{ +namespace trd +{ + +struct FitFunctor { + double operator()(const double* par) const; + double calculateDeltaAlphaSim(double vdFit, double laFit, double impactAng) const; + std::array<std::unique_ptr<TProfile>, constants::MAXCHAMBER> profiles; ///< profile histograms for each TRD chamber + double vdPreCorr; // TODO: these values should eventually be taken from CCDB + double laPreCorr; // TODO: these values should eventually be taken from CCDB + int currDet; ///< the current TRD chamber number + float lowerBoundAngleFit; + float upperBoundAngleFit; +}; + +class CalibratorVdExB final : public o2::calibration::TimeSlotCalibration<o2::trd::AngularResidHistos, o2::trd::AngularResidHistos> +{ + using Slot = o2::calibration::TimeSlot<o2::trd::AngularResidHistos>; + + public: + enum ParamIndex : int { + LA, + VD + }; + CalibratorVdExB(size_t nMin = 40'000) : mMinEntries(nMin) {} + ~CalibratorVdExB() final = default; + + bool hasEnoughData(const Slot& slot) const final { return slot.getContainer()->getNEntries() >= mMinEntries; } + void initOutput() final; + void finalizeSlot(Slot& slot) final; + Slot& emplaceNewSlot(bool front, uint64_t tStart, uint64_t tEnd) final; + + void initProcessing(); + + private: + bool mInitDone{false}; ///< flag to avoid creating the TProfiles multiple times + size_t mMinEntries; ///< minimum total number of angular deviations (on average ~3 entries per bin for each TRD chamber) + FitFunctor mFitFunctor; ///< used for minimization procedure + ClassDefOverride(CalibratorVdExB, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_CALIBRATORVDEXB_H diff --git a/Detectors/TRD/calibration/include/TRDCalibration/KrClusterFinder.h b/Detectors/TRD/calibration/include/TRDCalibration/KrClusterFinder.h new file mode 100644 index 0000000000000..2872e5f9f508c --- /dev/null +++ b/Detectors/TRD/calibration/include/TRDCalibration/KrClusterFinder.h @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrClusterFinder.h +/// \brief The TRD Krypton cluster finder from digits +/// \author Ole Schmidt + +#ifndef O2_TRD_KRCLUSTERFINDER_H +#define O2_TRD_KRCLUSTERFINDER_H + +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/KrCluster.h" +#include "DataFormatsTRD/KrClusterTriggerRecord.h" + +#include "Rtypes.h" +#include "TF1.h" +#include "Fit/Fitter.h" +#include "Fit/FitResult.h" + +#include <memory> +#include <gsl/span> + +namespace o2 +{ + +namespace trd +{ + +class KrClusterFinder +{ + + public: + KrClusterFinder() = default; + KrClusterFinder(const KrClusterFinder&) = delete; + ~KrClusterFinder() = default; + + struct LandauChi2Functor { + double operator()(const double* par) const; + std::vector<float> x; ///< the number of the time bin + std::vector<float> y; ///< ADC sum per time bin + int xLowerBound; + int xUpperBound; + }; + + /// Initialization + void init(); + + // Reset output containers + void reset(); + + /// Provide digits and trigger records as input + void setInput(const gsl::span<const Digit>& digitsIn, const gsl::span<const TriggerRecord>& trigRecIn); + + /// Find clusters in the digit ADC data. + /// We start with finding the maximum ADC value in a chamber. We store the ADC value, the time bin within the corresponding digit + /// and the pad row and pad column of that digit. Afterwards we cluster around that maximum, discarding digits more than 1 pad row + /// or more than 2 pad columns away. In time bin direction there are no limits for other ADC values to contribute to the cluster. + /// Each ADC value is added maximum to a single cluster: ADCs connected to one cluster are flagged as used and disregarded + /// in the following iterations for the given detector. Also ADC below a threshold (mMinAdcClContrib) are ignored. + /// The cluster size is defined in three dimensions (row, column, time bin), for each dimension from the lowermost constituent ADC + /// to the uppermost constituent ADC. + /// Different ADC sums are calculated from the constituent ADCs. + /// Afterwards the main Krypton peak is identified (maxAdcA and maxTbA) and also we try to find the second Kr peak (maxAdcB, maxTbB). + /// Quality checks indicate the validity of those two maxima (shape, ordering, ADC size) + /// A Landau fit to the ADC vs time bins values for a cluster provide the ADC sums for the two Kr peaks. + /// The clusters don't necessarily need to fullfill all quality criteria (e.g. the Landau fit may fail). But these clusters are + /// stored anyway, as they can be filtered out later at the analysis stage. + void findClusters(); + + /// Calculate some statistics for the given cluster constituent ADC values + double getRms(const std::vector<uint64_t>& adcIndices, int itTrunc, double nRmsTrunc, int minAdc, double& rmsTime, uint32_t& sumAdc) const; + + /// Output + const std::vector<KrCluster>& getKrClusters() const { return mKrClusters; } + const std::vector<KrClusterTriggerRecord>& getKrTrigRecs() const { return mTrigRecs; } + + private: + // input + gsl::span<const Digit> mDigits; ///< the TRD digits + gsl::span<const TriggerRecord> mTriggerRecords; ///< the TRD trigger records + // output + std::vector<KrCluster> mKrClusters{}; ///< the Kr clusters + std::vector<KrClusterTriggerRecord> mTrigRecs{}; ///< number of Kr clusters and interaction record of first trigger per time frame + // helpers + LandauChi2Functor mLandauChi2Functor; ///< stores the binned ADC data and provides a chi2 estimate + std::shared_ptr<ROOT::Fit::FitResult> mFitResult{new ROOT::Fit::FitResult()}; ///< pointer to the results of the Landau fit + ROOT::Fit::Fitter mFitter{mFitResult}; ///< an instance of the ROOT fitter + std::array<double, 3> mInitialFitParams{1., 1., 1.}; ///< initial fit parameters for the Landau fit + std::unique_ptr<TF1> mFuncLandauFit; ///< helper function to approximate the binned ADC data with a Landau distribution + // settings + const int mBaselineAdc{10}; ///< ADC baseline for each pad (can maybe be moved into Constants.h) + const int mMinAdcForMax{70}; ///< minimum ADC value that can be considered for a maximum + const int mMinAdcClContrib{40}; ///< minimum ADC value that can contribute to a cluster + const int mMinAdcForSecondMax{50}; ///< threshold for a second maximum inside a cluster + const int mMinAdcClEoverT{60}; ///< energy threshold for ADC value + + ClassDefNV(KrClusterFinder, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_KRCLUSTERFINDER_H diff --git a/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h b/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h new file mode 100644 index 0000000000000..b9b2fa327fdd6 --- /dev/null +++ b/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackBasedCalib.h +/// \brief Provides information required for TRD calibration which is based on the global tracking +/// \author Ole Schmidt + +#ifndef O2_TRD_TRACKBASEDCALIB_H +#define O2_TRD_TRACKBASEDCALIB_H + +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsTRD/AngularResidHistos.h" +#include "DetectorsBase/Propagator.h" +#include "TRDBase/RecoParam.h" + +#include "Rtypes.h" + +#include <gsl/span> + +namespace o2 +{ + +namespace globaltracking +{ +class RecoContainer; +} + +namespace trd +{ + +class TrackBasedCalib +{ + using MatCorrType = o2::base::Propagator::MatCorrType; + + public: + TrackBasedCalib() = default; + TrackBasedCalib(const TrackBasedCalib&) = delete; + ~TrackBasedCalib() = default; + + /// Load geometry and apply magnetic field setting + void init(); + + /// Main processing function for creating angular residual histograms for vDrift and ExB calibration + void calculateAngResHistos(const o2::globaltracking::RecoContainer& input); + + /// Main processing function for gathering information needed for gain calibration + /// i.e. TRD tracklet ADC vs TPC track dEdx for given momentum slice + void calculateGainCalibObjs(const o2::globaltracking::RecoContainer& input); + + /// Extrapolate track parameters to given layer and if requested perform update with tracklet + bool propagateAndUpdate(TrackTRD& trk, int iLayer, bool doUpdate) const; + + const AngularResidHistos& getAngResHistos() const { return mAngResHistos; } + + private: + float mMaxSnp{o2::base::Propagator::MAX_SIN_PHI}; ///< max snp when propagating tracks + float mMaxStep{o2::base::Propagator::MAX_STEP}; ///< maximum step for propagation + MatCorrType mMatCorr{MatCorrType::USEMatCorrNONE}; ///< if material correction should be done + RecoParam mRecoParam; ///< parameters required for TRD reconstruction + AngularResidHistos mAngResHistos; ///< aggregated data for the track based calibration + // input arrays which should not be modified since they are provided externally + gsl::span<const TrackTRD> mTracksIn; ///< TRD tracks reconstructed from TPC or ITS-TPC seeds + gsl::span<const Tracklet64> mTrackletsRaw; ///< array of raw tracklets needed for TRD refit + gsl::span<const CalibratedTracklet> mTrackletsCalib; ///< array of calibrated tracklets needed for TRD refit + + ClassDefNV(TrackBasedCalib, 1); +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_TRACKBASEDCALIB_H diff --git a/Detectors/TRD/calibration/src/CalibratorVdExB.cxx b/Detectors/TRD/calibration/src/CalibratorVdExB.cxx new file mode 100644 index 0000000000000..ea65c56509939 --- /dev/null +++ b/Detectors/TRD/calibration/src/CalibratorVdExB.cxx @@ -0,0 +1,178 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CalibratorVdExB.cxx +/// \brief TimeSlot-based calibration of vDrift and ExB +/// \author Ole Schmidt + +#include "TRDCalibration/CalibratorVdExB.h" +#include "DataFormatsTRD/CalVdriftExB.h" +#include "Fit/Fitter.h" +#include "TStopwatch.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include <string> +#include <map> +#include <memory> + +using namespace o2::trd::constants; + +namespace o2::trd +{ + +double FitFunctor::calculateDeltaAlphaSim(double vdFit, double laFit, double impactAng) const +{ + + double trdAnodePlane = .0335; // distance of the TRD anode plane from the drift cathodes in [m] + + auto xDir = TMath::Cos(impactAng); + auto yDir = TMath::Sin(impactAng); + double slope = (TMath::Abs(xDir) < 1e-7) ? 1e7 : yDir / xDir; + auto laTan = TMath::Tan(laFit); + double lorentzSlope = (TMath::Abs(laTan) < 1e-7) ? 1e7 : 1. / laTan; + + // hit point of incoming track with anode plane + double xAnodeHit = trdAnodePlane / slope; + double yAnodeHit = trdAnodePlane; + + // hit point at anode plane of Lorentz angle shifted cluster from the entrance -> independent of true drift velocity + double xLorentzAnodeHit = trdAnodePlane / lorentzSlope; + double yLorentzAnodeHit = trdAnodePlane; + + // cluster location within drift cell of cluster from entrance after drift velocity ratio is applied + double xLorentzDriftHit = xLorentzAnodeHit; + double yLorentzDriftHit = trdAnodePlane - trdAnodePlane * (vdPreCorr / vdFit); + + // reconstructed hit of first cluster at chamber entrance after pre Lorentz angle correction + double xLorentzDriftHitPreCorr = xLorentzAnodeHit - (trdAnodePlane - yLorentzDriftHit) * TMath::Tan(laPreCorr); + double yLorentzDriftHitPreCorr = trdAnodePlane - trdAnodePlane * (vdPreCorr / vdFit); + + double impactAngleSim = TMath::ATan2(yAnodeHit, xAnodeHit); + + double deltaXLorentzDriftHit = xAnodeHit - xLorentzDriftHitPreCorr; + double deltaYLorentzDriftHit = yAnodeHit - yLorentzDriftHitPreCorr; + double impactAngleRec = TMath::ATan2(deltaYLorentzDriftHit, deltaXLorentzDriftHit); + + double deltaAngle = (impactAngleRec - impactAngleSim); // * TMath::RadToDeg()); + + return deltaAngle; +} + +double FitFunctor::operator()(const double* par) const +{ + double sum = 0; // this value is minimized + for (int iBin = 1; iBin <= profiles[currDet]->GetNbinsX(); ++iBin) { + auto impactAngle = (profiles[currDet]->GetBinCenter(iBin) + 90) * TMath::DegToRad(); + auto deltaAlpha = profiles[currDet]->GetBinContent(iBin) * TMath::DegToRad(); + if (TMath::Abs(deltaAlpha) < 1e-7) { + continue; + } + if (impactAngle < lowerBoundAngleFit || impactAngle > upperBoundAngleFit) { + continue; + } + auto deltaAlphaSim = calculateDeltaAlphaSim(par[CalibratorVdExB::ParamIndex::VD], par[CalibratorVdExB::ParamIndex::LA], impactAngle); + sum += TMath::Power(deltaAlphaSim - deltaAlpha, 2); + } + return sum; +} + +using Slot = o2::calibration::TimeSlot<AngularResidHistos>; + +void CalibratorVdExB::initOutput() +{ + // prepare output objects which will go to CCDB + // nothing to be done +} + +void CalibratorVdExB::initProcessing() +{ + if (mInitDone) { + return; + } + mFitFunctor.lowerBoundAngleFit = 80 * TMath::DegToRad(); + mFitFunctor.upperBoundAngleFit = 100 * TMath::DegToRad(); + mFitFunctor.vdPreCorr = 1.546; // TODO: will be taken from CCDB in the future + mFitFunctor.laPreCorr = -0.16133; // TODO: will be taken from CCDB in the future + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { + mFitFunctor.profiles[iDet] = std::make_unique<TProfile>(Form("profAngleDiff_%i", iDet), Form("profAngleDiff_%i", iDet), NBINSANGLEDIFF, -MAXIMPACTANGLE, MAXIMPACTANGLE); + } + mInitDone = true; +} + +void CalibratorVdExB::finalizeSlot(Slot& slot) +{ + // do actual calibration for the data provided in the given slot + TStopwatch timer; + timer.Start(); + std::array<float, MAXCHAMBER> laFitResults{}; + std::array<float, MAXCHAMBER> vdFitResults{}; + auto residHists = slot.getContainer(); + initProcessing(); + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { + mFitFunctor.profiles[iDet]->Reset(); + mFitFunctor.currDet = iDet; + for (int iBin = 0; iBin < NBINSANGLEDIFF; ++iBin) { + // fill profiles + auto angleDiffSum = residHists->getHistogramEntry(iDet * NBINSANGLEDIFF + iBin); + auto nEntries = residHists->getBinCount(iDet * NBINSANGLEDIFF + iBin); + if (nEntries > 0) { + mFitFunctor.profiles[iDet]->Fill(2 * iBin - MAXIMPACTANGLE, angleDiffSum / nEntries, nEntries); + } + } + ROOT::Fit::Fitter fitter; + double paramsStart[2]; + paramsStart[ParamIndex::LA] = -7.5 * TMath::DegToRad(); + paramsStart[ParamIndex::VD] = 1.; + fitter.SetFCN<FitFunctor>(2, mFitFunctor, paramsStart); + fitter.Config().ParSettings(ParamIndex::LA).SetLimits(-0.7, 0.7); + fitter.Config().ParSettings(ParamIndex::LA).SetStepSize(.01); + fitter.Config().ParSettings(ParamIndex::VD).SetLimits(0., 3.); + fitter.Config().ParSettings(ParamIndex::VD).SetStepSize(.01); + ROOT::Math::MinimizerOptions opt; + opt.SetMinimizerType("Minuit2"); + opt.SetMinimizerAlgorithm("Migrad"); + opt.SetPrintLevel(0); + opt.SetMaxFunctionCalls(1'000); + opt.SetTolerance(.001); + fitter.Config().SetMinimizerOptions(opt); + fitter.FitFCN(); + auto fitResult = fitter.Result(); + laFitResults[iDet] = fitResult.Parameter(ParamIndex::LA); + vdFitResults[iDet] = fitResult.Parameter(ParamIndex::VD); + LOGF(DEBUG, "Fit result for chamber %i: vd=%f, la=%f", iDet, vdFitResults[iDet], laFitResults[iDet] * TMath::RadToDeg()); + } + timer.Stop(); + LOGF(INFO, "Done fitting angular residual histograms. CPU time: %f, real time: %f", timer.CpuTime(), timer.RealTime()); + + // write results to CCDB + o2::ccdb::CcdbApi ccdb; + ccdb.init("http://ccdb-test.cern.ch:8080"); + std::map<std::string, std::string> metadata; // TODO: do we want to store any meta data? + CalVdriftExB calObject; + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { + // OS: what about chambers for which we had no data in this slot? should we use the initial parameters or something else? + // maybe it is better not to overwrite an older result if we don't have anything better? + calObject.setVdrift(iDet, vdFitResults[iDet]); + calObject.setExB(iDet, laFitResults[iDet]); + } + auto timeStamp = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb.storeAsTFileAny(&calObject, "TRD/Calib/CalVdriftExB", metadata, timeStamp); +} + +Slot& CalibratorVdExB::emplaceNewSlot(bool front, uint64_t tStart, uint64_t tEnd) +{ + auto& container = getSlots(); + auto& slot = front ? container.emplace_front(tStart, tEnd) : container.emplace_back(tStart, tEnd); + slot.setContainer(std::make_unique<AngularResidHistos>()); + return slot; +} + +} // namespace o2::trd diff --git a/Detectors/TRD/calibration/src/KrClusterFinder.cxx b/Detectors/TRD/calibration/src/KrClusterFinder.cxx new file mode 100644 index 0000000000000..4bd1aad6b7819 --- /dev/null +++ b/Detectors/TRD/calibration/src/KrClusterFinder.cxx @@ -0,0 +1,411 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrClusterFinder.cxx +/// \brief The TRD Krypton cluster finder from digits +/// \author Alexander Schmah, Ole Schmidt + +#include "TRDCalibration/KrClusterFinder.h" +#include "Math/IntegratorOptions.h" +#include <fairlogger/Logger.h> + +#include <limits> + +using namespace o2::trd; +using namespace o2::trd::constants; + +double KrClusterFinder::LandauChi2Functor::operator()(const double* par) const +{ + // provides chi2 estimate comparing y[] to par[0] * TMath::Landau(x[], par[1], par[2]) + // par[0] : amplitude + // par[1] : location parameter (approximately most probable value) + // par[2] : sigma + double retVal = 0; + for (unsigned int i = xLowerBound; i <= xUpperBound; ++i) { + if (fabs(y[i]) < 1e-3f) { + // exclude bins with zero errors like in TH1::Fit + // the standard bin error is the square root of its content + continue; + } + retVal += TMath::Power(y[i] - par[0] * TMath::Landau(x[i], par[1], par[2]), 2) / y[i]; + } + return retVal; +} + +double KrClusterFinder::getRms(const std::vector<uint64_t>& adcIndices, int itTrunc, double nRmsTrunc, int minAdc, double& rmsTime, uint32_t& sumAdc) const +{ + double rmsAdc = 1e7; + double meanAdc = -10.; + rmsTime = 1e7; + double meanTime = -10.f; + + for (int it = 0; it < itTrunc; ++it) { + // iterations for truncated mean + sumAdc = 0; + uint32_t sumAdc2 = 0; + uint32_t sumTime = 0; + uint32_t sumTime2 = 0; + uint32_t sumWeights = 0; + for (const auto& adcIdx : adcIndices) { + int iTb = adcIdx % TIMEBINS; + int iDigit = adcIdx / TIMEBINS; + int adc = mDigits[iDigit].getADC()[iTb] - mBaselineAdc; + if (adc < minAdc) { + continue; + } + if (fabs(adc - meanAdc) < nRmsTrunc * rmsAdc) { + sumAdc += adc; + sumAdc2 += adc * adc; + sumWeights += 1; + sumTime += iTb; + sumTime2 += iTb * iTb; + } + } + if (sumWeights > 0) { + auto sumWeightsInv = 1. / sumWeights; + meanAdc = sumAdc * sumWeightsInv; + rmsAdc = TMath::Sqrt(sumWeightsInv * (sumAdc2 - 2. * meanAdc * sumAdc + sumWeights * meanAdc * meanAdc)); + meanTime = sumTime * sumWeightsInv; + rmsTime = TMath::Sqrt(sumWeightsInv * (sumTime2 - 2. * meanTime * sumTime + sumWeights * meanTime * meanTime)); + } + } + return rmsAdc; +} + +void KrClusterFinder::init() +{ + mFitter.SetFCN<LandauChi2Functor>(3, mLandauChi2Functor, mInitialFitParams.data()); + mFitter.Config().ParSettings(0).SetLimits(0., 1.e5); + mFitter.Config().ParSettings(1).SetLimits(0., 30.); + mFitter.Config().ParSettings(2).SetLimits(1.e-3, 20.); + mFuncLandauFit = std::make_unique<TF1>( + "fLandauFit", [&](double* x, double* par) { return par[0] * TMath::Landau(x[0], par[1], par[2]); }, 0., static_cast<double>(TIMEBINS), 3); +} + +void KrClusterFinder::reset() +{ + mKrClusters.clear(); + mTrigRecs.clear(); +} + +void KrClusterFinder::setInput(const gsl::span<const Digit>& digitsIn, const gsl::span<const TriggerRecord>& trigRecIn) +{ + mDigits = digitsIn; + mTriggerRecords = trigRecIn; +} + +void KrClusterFinder::findClusters() +{ + int nClsTotal = 0; + int nClsDropped = 0; + int nClsInvalidFit = 0; + /* + The input digits and trigger records are provided on a per time frame basis. + The cluster finding is performed for each trigger. In order to not copy the + input data we sort the digits for each trigger by their detector ID and keep + the sorted indices in the digitIdxArray. + */ + std::vector<uint64_t> digitIdxArray(mDigits.size()); + std::iota(digitIdxArray.begin(), digitIdxArray.end(), 0); + for (const auto& trig : mTriggerRecords) { + // sort the digits of given trigger record by detector ID + const auto& digits = mDigits; // this reference is only needed to be able to pass it to the lambda for sorting + std::stable_sort(std::begin(digitIdxArray) + trig.getFirstDigit(), std::begin(digitIdxArray) + trig.getNumberOfDigits() + trig.getFirstDigit(), + [&digits](uint64_t i, uint64_t j) { return digits[i].getDetector() < digits[j].getDetector(); }); + + /* + Count number of digits per detector: + For each detector we need to know the number of digits. + We fill the array idxFirstDigitInDet with the total number of digits + up to given detector. So we start at 0 for detector 0 and end up with + the total number of digits in entry 540. Thus the number of digits in + detector iDet can be calculated with: + idxFirstDigitInDet[iDet+1] - idxFirstDigitInDet[iDet] + Note, that for a global index one needs to add trig.getFirstDigit() + */ + int currDet = 0; + int nextDet = 0; + int digitCounter = 0; + std::array<unsigned int, MAXCHAMBER + 1> idxFirstDigitInDet{}; + auto idxHelperPtr = &(idxFirstDigitInDet.data()[1]); + idxHelperPtr[-1] = 0; + for (int iDigit = trig.getFirstDigit(); iDigit < trig.getFirstDigit() + trig.getNumberOfDigits(); ++iDigit) { + if (mDigits[digitIdxArray[iDigit]].getDetector() > currDet) { + nextDet = mDigits[digitIdxArray[iDigit]].getDetector(); + for (int iDet = currDet; iDet < nextDet; ++iDet) { + idxHelperPtr[iDet] = digitCounter; + } + currDet = nextDet; + } + ++digitCounter; + } + for (int iDet = currDet; iDet <= MAXCHAMBER; ++iDet) { + idxHelperPtr[iDet] = digitCounter; + } + + // the cluster search is done on a per detector basis + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { + unsigned int nDigitsInDet = idxFirstDigitInDet[iDet + 1] - idxFirstDigitInDet[iDet]; + std::vector<bool> isAdcUsed(nDigitsInDet * TIMEBINS); // keep track of the ADC values which have already been checked or added to a cluster + std::vector<bool> isDigitUsed(nDigitsInDet); // keep track of the digits which have already been processed + bool continueClusterSearch = true; + // the following loop searches for one cluster at a time in iDet + while (continueClusterSearch) { + + // start by finding the max ADC value in all digits of iDet + uint16_t adcMax = 0; + int tbMax = 0; + int rowMax = 0; + int colMax = 0; + unsigned int iDigitMax = 0; + for (int iDigit = 0; iDigit < nDigitsInDet; ++iDigit) { + if (isDigitUsed[iDigit]) { + // if a maximum has been found for this digit then all ADCs above threshold are already flagged as used + continue; + } + uint64_t digitIdx = trig.getFirstDigit() + idxFirstDigitInDet[iDet] + iDigit; // global index for array of all digits (mDigits) + int tbMaxADC = -1; + auto maxAdcInDigit = mDigits[digitIdx].getADCmax(tbMaxADC); + if (maxAdcInDigit > adcMax) { + // potentially found a maximum + tbMax = tbMaxADC; + rowMax = mDigits[digitIdx].getPadRow(); + colMax = mDigits[digitIdx].getPadCol(); + iDigitMax = iDigit; + adcMax = maxAdcInDigit; + } + } + if (adcMax < mMinAdcForMax) { + // the maximum ADC value is below the threshold, go to next chamber + break; + } + + // cluster around max ADC value + int lowerTb = TIMEBINS; + int upperTb = 0; + int lowerCol = NCOLUMN; + int upperCol = 0; + int lowerRow = NROWC1; + int upperRow = 0; + int nUsedADCsInCl = 0; + std::vector<uint64_t> constituentAdcIndices; + for (unsigned int iDigit = 0; iDigit < nDigitsInDet; ++iDigit) { + uint64_t digitIdx = trig.getFirstDigit() + idxFirstDigitInDet[iDet] + iDigit; // global index for array of all digits (mDigits) + int row = mDigits[digitIdx].getPadRow(); + if (std::abs(row - rowMax) > 1) { + continue; + } + int col = mDigits[digitIdx].getPadCol(); + if (std::abs(col - colMax) > 2) { + continue; + } + bool addedAdc = false; + for (int iTb = 0; iTb < TIMEBINS; ++iTb) { + if (isAdcUsed[iDigit * TIMEBINS + iTb]) { + continue; + } + // flag this ADC value as used, regardless of whether or not it is added to the cluster + // (if it is below the threshold it won't be used for another cluster anyway) + isAdcUsed[iDigit * TIMEBINS + iTb] = true; + if (mDigits[digitIdx].getADC()[iTb] > mMinAdcClContrib) { + addedAdc = true; + if (iTb < lowerTb) { + lowerTb = iTb; + } + if (iTb > upperTb) { + upperTb = iTb; + } + ++nUsedADCsInCl; + } + constituentAdcIndices.push_back(digitIdx * TIMEBINS + iTb); // also add ADC values below threshold here + } + if (addedAdc) { + isDigitUsed[iDigit] = true; + if (row < lowerRow) { + lowerRow = row; + } + if (row > upperRow) { + upperRow = row; + } + if (col < lowerCol) { + lowerCol = col; + } + if (col > upperCol) { + upperCol = col; + } + } + } + + // determine cluster size + int clSizeTime = upperTb - lowerTb; + int clSizeRow = upperRow - lowerRow; + int clSizeCol = upperCol - lowerCol; + + if (nUsedADCsInCl > 0) { + // after this cluster is processed, continue looking for another one in iDet + continueClusterSearch = true; + } + + // sum up ADC values (total sum, sum per time bin, total sum for ADCs above energy threshold) + std::array<int, TIMEBINS> sumPerTb{}; + int sumOfAllTimeBins = 0; + int sumOfAllTimeBinsAboveThreshold = 0; + for (const auto idx : constituentAdcIndices) { + auto iTb = idx % TIMEBINS; + auto iDigit = idx / TIMEBINS; + sumOfAllTimeBins += mDigits[iDigit].getADC()[iTb] - mBaselineAdc; + sumPerTb[iTb] += mDigits[iDigit].getADC()[iTb] - mBaselineAdc; + if (mDigits[iDigit].getADC()[iTb] > mMinAdcClEoverT) { + sumOfAllTimeBinsAboveThreshold += mDigits[iDigit].getADC()[iTb] - mBaselineAdc; + } + } + + uint32_t sumOfAdcTrunc; + double rmsTimeTrunc; + auto rmsAdcClusterTrunc = getRms(constituentAdcIndices, 2, 3., static_cast<uint32_t>(mMinAdcClEoverT * .95), rmsTimeTrunc, sumOfAdcTrunc); + + // ADC value and time bin of first maximum + int maxAdcA = -1; + int maxTbA = -1; + mLandauChi2Functor.x.clear(); + mLandauChi2Functor.y.clear(); + for (int iTb = 0; iTb < TIMEBINS; ++iTb) { + mLandauChi2Functor.x.push_back((float)iTb); + mLandauChi2Functor.y.push_back(sumPerTb[iTb]); + if (sumPerTb[iTb] < mMinAdcForMax) { + continue; + } + if (sumPerTb[iTb] > maxAdcA) { + maxAdcA = sumPerTb[iTb]; + maxTbA = iTb; + } + } + mLandauChi2Functor.xLowerBound = maxAdcA - 1; + mLandauChi2Functor.xUpperBound = maxAdcA + 2; + + // ADC value and time bin of second maximum (if there is one) + int maxAdcB = -1; + int maxTbB = -1; + for (int iTb = 2; iTb < TIMEBINS - 2; ++iTb) { // we need to check the neighbouring two bins, so ignore the outermost two bins in the search for a second maximum + if (std::abs(maxTbA - iTb) < 3 || sumPerTb[iTb] < mMinAdcForSecondMax) { + // we are too close to the first maximum (or the ADC value is not too small) + continue; + } + if (sumPerTb[iTb] > maxAdcB) { + // check neighbours + if (sumPerTb[iTb - 1] < sumPerTb[iTb] && + sumPerTb[iTb - 2] < sumPerTb[iTb] && + sumPerTb[iTb + 1] < sumPerTb[iTb] && + sumPerTb[iTb + 2] < sumPerTb[iTb]) { + maxAdcB = sumPerTb[iTb]; + maxTbB = iTb; + } + } + } + + // quality checks for maxima + bool isBadA = false; + bool isBadB = false; + if (maxAdcA < 0 || maxTbA <= 1 || maxTbA >= (TIMEBINS - 2)) { + isBadA = true; + } + if (maxAdcB < 0) { + // second maximum must be inside the time acceptance by construction + isBadB = true; + } + if (!isBadA) { + // we have a good first maximum, let's check its shape + if ((sumPerTb[maxTbA - 1] / static_cast<double>(maxAdcA)) < 0.1 || (sumPerTb[maxTbA + 1] / static_cast<double>(maxAdcA)) < 0.25) { + isBadA = true; + } + } + if (!isBadB) { + // we have a good second maximum, let's check its shape + if ((sumPerTb[maxTbB - 1] / static_cast<double>(maxAdcB)) < 0.1 || (sumPerTb[maxTbB + 1] / static_cast<double>(maxAdcB)) < 0.25) { + isBadB = true; + } + } + if (!isBadA && !isBadB) { + // we have two maxima, check order and size + if (maxTbA > maxTbB || maxAdcA <= maxAdcB) { + isBadA = true; + isBadB = true; + } + } + + if (clSizeCol > 0 && clSizeTime > 3 && clSizeTime < TIMEBINS) { + mFitter.Config().ParSettings(0).SetValue(maxAdcA); + mFitter.Config().ParSettings(1).SetValue(maxTbA); + mFitter.Config().ParSettings(2).SetValue(.5); + bool fitOK = mFitter.FitFCN(); + if (!fitOK) { + ++nClsInvalidFit; + } + mFuncLandauFit->SetParameters(mFitResult->GetParams()[0], mFitResult->GetParams()[1], mFitResult->GetParams()[2]); + double integralLandauFit = fitOK ? mFuncLandauFit->Integral(0., static_cast<double>(TIMEBINS), 1.e-9) : 0.; + + double rmsTime; + uint32_t rmsSumAdc; + auto rmsAdc = getRms(constituentAdcIndices, 1, 2.5, mMinAdcClContrib, rmsTime, rmsSumAdc); + + double sumAdcA = 0.; + double sumAdcB = 0.; + if (!isBadA && !isBadB) { + // use the Landau fit to the first peak to extrapolate the energy of larger time bins (close time bins are evaluated from the array directly) + // for the second peak the Landau fit is used to subtract the energy from the first peak + for (int iTb = 0; iTb < TIMEBINS; ++iTb) { + if (iTb < (maxTbB - 2)) { + sumAdcA += mLandauChi2Functor.y[iTb]; + } else { + sumAdcA += mFuncLandauFit->Eval(mLandauChi2Functor.x[iTb]); + sumAdcB += mLandauChi2Functor.y[iTb] - mFuncLandauFit->Eval(mLandauChi2Functor.x[iTb]); + } + } + } + // create Kr cluster + if (sumOfAllTimeBins <= std::numeric_limits<uint16_t>::max() && + sumOfAllTimeBinsAboveThreshold <= std::numeric_limits<uint16_t>::max() && + integralLandauFit <= std::numeric_limits<uint16_t>::max() && + sumAdcA <= std::numeric_limits<uint16_t>::max() && + sumAdcB <= std::numeric_limits<uint16_t>::max() && + rmsAdc <= std::numeric_limits<uint16_t>::max() && + rmsTime <= std::numeric_limits<uint8_t>::max() && + nUsedADCsInCl <= std::numeric_limits<uint8_t>::max() && + sumOfAdcTrunc <= std::numeric_limits<uint16_t>::max()) { + if (maxTbA < 0) { + maxTbA = tbMax; + } + if (maxTbB < 0) { + maxTbB = 2 * TIMEBINS + 5; // larger than any maximum time bin we can have + } + KrCluster cluster; + cluster.setGlobalPadID(iDet, rowMax, colMax); + cluster.setAdcData(sumOfAllTimeBins, (int)rmsAdc, (int)sumAdcA, (int)sumAdcB, sumOfAllTimeBinsAboveThreshold, (int)integralLandauFit, sumOfAdcTrunc); + cluster.setTimeData(maxTbA, maxTbB, (int)rmsTime); + cluster.setClusterSizeData(clSizeRow, clSizeCol, clSizeTime, nUsedADCsInCl); + mKrClusters.push_back(cluster); + ++nClsTotal; + } else { + //mFitResult->Print(std::cout); + ++nClsDropped; + LOG(DEBUG) << "Kr cluster cannot be added because values are out of range"; + LOGF(DEBUG, "sumOfAllTimeBins(%i), sumAdcA(%f), sumAdcB(%f), clSizeRow(%i), clSizeCol(%i), clSizeTime(%i), maxTbA(%i), maxTbB(%i)", sumOfAllTimeBins, sumAdcA, sumAdcB, clSizeRow, clSizeCol, clSizeTime, maxTbA, maxTbB); + LOGF(DEBUG, "rmsAdc(%f), rmsTime(%f), nUsedADCsInCl(%i), sumOfAllTimeBinsAboveThreshold(%i), integralLandauFit(%f), sumOfAdcTrunc(%u)", rmsAdc, rmsTime, nUsedADCsInCl, sumOfAllTimeBinsAboveThreshold, integralLandauFit, sumOfAdcTrunc); + } + } + } // end cluster search + } // end detector loop + } // end trigger loop + + // we don't need the exact BC time, just use first interaction record within this TF + mTrigRecs.emplace_back(mTriggerRecords[0].getBCData(), nClsTotal); + LOGF(INFO, "Number of Kr clusters with a) invalid fit (%i) b) out-of-range values which were dropped (%i)", nClsInvalidFit, nClsDropped); +} diff --git a/Detectors/TRD/calibration/src/TRDCalibrationLinkDef.h b/Detectors/TRD/calibration/src/TRDCalibrationLinkDef.h new file mode 100644 index 0000000000000..d704d37332fda --- /dev/null +++ b/Detectors/TRD/calibration/src/TRDCalibrationLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::trd::CalibratorVdExB + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::trd::AngularResidHistos> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::trd::AngularResidHistos, o2::trd::AngularResidHistos> + ; +#pragma link C++ class o2::trd::TrackBasedCalib + ; +#pragma link C++ class o2::trd::KrClusterFinder + ; + +#endif diff --git a/Detectors/TRD/calibration/src/TrackBasedCalib.cxx b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx new file mode 100644 index 0000000000000..cc02c633f6697 --- /dev/null +++ b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx @@ -0,0 +1,176 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackBasedCalib.cxx +/// \brief Provides information required for TRD calibration which is based on the global tracking +/// \author Ole Schmidt + +#include "TRDCalibration/TrackBasedCalib.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsBase/GeometryManager.h" +#include "TRDBase/Geometry.h" +#include "TRDBase/PadPlane.h" +#include <fairlogger/Logger.h> + +using namespace o2::trd; +using namespace o2::trd::constants; + +void TrackBasedCalib::init() +{ + mRecoParam.setBfield(o2::base::Propagator::Instance()->getNominalBz()); +} + +void TrackBasedCalib::calculateGainCalibObjs(const o2::globaltracking::RecoContainer& input) +{ + mTracksIn = input.getITSTPCTRDTracks<TrackTRD>(); // alternatively use input.getTPCTRDTracks<TrackTRD>() to use TPC-TRD matches + mTrackletsRaw = input.getTRDTracklets(); + /* + This method could gather the information required for the gain calibration. + The global tracks contain dEdx information from the TPC and the TRD tracklets + contain ADC data stored in different charge windows. + The calibration object for the gain calibration needs to be defined + The tracks probably don't need to be copied, since the track parameters + don't need ot be transported. + */ +} + +void TrackBasedCalib::calculateAngResHistos(const o2::globaltracking::RecoContainer& input) +{ + + mTracksIn = input.getITSTPCTRDTracks<TrackTRD>(); + mTrackletsRaw = input.getTRDTracklets(); + mTrackletsCalib = input.getTRDCalibratedTracklets(); + + if (mTrackletsRaw.size() != mTrackletsCalib.size()) { + LOG(ERROR) << "TRD raw tracklet container size differs from calibrated tracklet container size"; + return; + } + + int nTracksSuccess = 0; + int nAngularResidualsCollected = 0; + for (const auto& trkIn : mTracksIn) { + if (trkIn.getNtracklets() < 3) { + // with less than 3 tracklets the TRD-only refit not meaningful + continue; + } + auto trkWork = trkIn; // input is const, so we need to create a copy + bool trackFailed = false; + + trkWork.setChi2(0.f); + trkWork.resetCovariance(20); + + // first inward propagation (TRD track fit) + int currLayer = NLAYER; + for (int iLayer = NLAYER - 1; iLayer >= 0; --iLayer) { + if (trkWork.getTrackletIndex(iLayer) == -1) { + continue; + } + if (propagateAndUpdate(trkWork, iLayer, true)) { + trackFailed = true; + break; + } + currLayer = iLayer; + } + if (trackFailed) { + continue; + } + + // outward propagation (smoothing) + for (int iLayer = currLayer + 1; iLayer < NLAYER; ++iLayer) { + if (trkWork.getTrackletIndex(iLayer) == -1) { + continue; + } + if (propagateAndUpdate(trkWork, iLayer, true)) { + trackFailed = true; + break; + } + currLayer = iLayer; + } + if (trackFailed) { + continue; + } + + // second inward propagation (collect angular differences between tracklets + TRD track) + for (int iLayer = currLayer; iLayer >= 0; --iLayer) { + if (trkWork.getTrackletIndex(iLayer) == -1) { + continue; + } + if (propagateAndUpdate(trkWork, iLayer, false)) { + trackFailed = true; + break; + } + + float trkAngle = o2::math_utils::asin(trkWork.getSnp()) * TMath::RadToDeg(); + float trkltAngle = o2::math_utils::atan(mTrackletsCalib[trkWork.getTrackletIndex(iLayer)].getDy() / Geometry::cdrHght()) * TMath::RadToDeg(); + float angleDeviation = trkltAngle - trkAngle; + if (mAngResHistos.addEntry(angleDeviation, trkAngle, mTrackletsRaw[trkWork.getTrackletIndex(iLayer)].getDetector())) { + // track impact angle out of histogram range + continue; + } + ++nAngularResidualsCollected; + } + + // here we can count the number of successfully processed tracks + ++nTracksSuccess; + } // end of track loop + LOGF(INFO, "Successfully processed %i tracks and collected %i angular residuals", nTracksSuccess, nAngularResidualsCollected); + //mAngResHistos.print(); +} + +bool TrackBasedCalib::propagateAndUpdate(TrackTRD& trk, int iLayer, bool doUpdate) const +{ + // Propagates the track to TRD layer iLayer and updates the track + // parameters (if requested) + // returns 0 in case of success + + auto propagator = o2::base::Propagator::Instance(); + + int trkltId = trk.getTrackletIndex(iLayer); + int trkltDet = mTrackletsRaw[trkltId].getDetector(); + int trkltSec = trkltDet / (NLAYER * NSTACK); + + if (trkltSec != o2::math_utils::angle2Sector(trk.getAlpha())) { + if (!trk.rotate(o2::math_utils::sector2Angle(trkltSec))) { + LOGF(DEBUG, "Track could not be rotated in tracklet coordinate system"); + return 1; + } + } + + if (!propagator->PropagateToXBxByBz(trk, mTrackletsCalib[trkltId].getX(), mMaxSnp, mMaxStep, mMatCorr)) { + LOGF(DEBUG, "Track propagation failed in layer %i (pt=%f, xTrk=%f, xToGo=%f)", iLayer, trk.getPt(), trk.getX(), mTrackletsCalib[trkltId].getX()); + return 1; + } + + if (!doUpdate) { + // nothing more to be done + return 0; + } + + const PadPlane* pad = Geometry::instance()->getPadPlane(trkltDet); + float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees + float tiltCorrUp = tilt * (mTrackletsCalib[trkltId].getZ() - trk.getZ()); + float zPosCorrUp = mTrackletsCalib[trkltId].getZ() + mRecoParam.getZCorrCoeffNRC() * trk.getTgl(); + float padLength = pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()); + if (!((trk.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trk.getZ()) < padLength))) { + tiltCorrUp = 0.f; + } + + std::array<float, 2> trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp, zPosCorrUp}; + std::array<float, 3> trkltCovUp; + mRecoParam.recalcTrkltCov(tilt, trk.getSnp(), pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()), trkltCovUp); + + if (!trk.update(trkltPosUp, trkltCovUp)) { + LOGF(INFO, "Failed to update track with space point in layer %i", iLayer); + return 1; + } + return 0; +} diff --git a/Detectors/TRD/macros/CMakeLists.txt b/Detectors/TRD/macros/CMakeLists.txt index 405687d0f308f..1f91996037189 100644 --- a/Detectors/TRD/macros/CMakeLists.txt +++ b/Detectors/TRD/macros/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(CheckCCDBvalues.C PUBLIC_LINK_LIBRARIES O2::TRDBase diff --git a/Detectors/TRD/macros/CheckCCDBvalues.C b/Detectors/TRD/macros/CheckCCDBvalues.C index 9a9c292ea32e1..71cecfb8ca50f 100644 --- a/Detectors/TRD/macros/CheckCCDBvalues.C +++ b/Detectors/TRD/macros/CheckCCDBvalues.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,7 +43,7 @@ void CheckCCDBvalues(const long runNumber = 297595) TH1F* histPadGainFactor = new TH1F("histPadGainFactor", ";Pad Gain Factor;Counts", 100, 0, 2); o2::trd::Calibrations calib; - calib.setCCDBForSimulation(runNumber); + calib.getCCDBObjects(runNumber); for (det = 0; det < 540; ++det) { exb = calib.getExB(det); histExB->Fill(exb); diff --git a/Detectors/TRD/macros/CheckDigits.C b/Detectors/TRD/macros/CheckDigits.C index f887fe44d6d3f..7b6899e8bf79a 100644 --- a/Detectors/TRD/macros/CheckDigits.C +++ b/Detectors/TRD/macros/CheckDigits.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,9 +22,8 @@ #include <TLegend.h> #include "FairLogger.h" -#include "TRDBase/Digit.h" #include "TRDBase/SimParam.h" -#include "TRDBase/CommonParam.h" +#include "DataFormatsTRD/Digit.h" #include "DataFormatsTRD/Constants.h" #endif @@ -67,17 +67,16 @@ void CheckDigits(std::string digifile = "trddigits.root", for (int iev = 0; iev < nev; ++iev) { digitTree->GetEvent(iev); for (const auto& digit : *digitCont) { - // loop over det, pad, row? auto adcs = digit.getADC(); - int det = digit.getDetector(); - int row = digit.getRow(); - int pad = digit.getPad(); + int det = digit.getDetector(); // chamber + int row = digit.getPadRow(); // pad row + int col = digit.getPadCol(); // pad column hDet->Fill(det); hRow->Fill(row); - hPad->Fill(pad); + hPad->Fill(col); for (int tb = 0; tb < o2::trd::constants::TIMEBINS; ++tb) { ADC_t adc = adcs[tb]; - if (adc == (ADC_t)SimParam::Instance()->GetADCoutRange()) { + if (adc == (ADC_t)SimParam::instance()->getADCoutRange()) { // LOG(INFO) << "Out of range ADC " << adc; continue; } diff --git a/Detectors/TRD/macros/CheckHits.C b/Detectors/TRD/macros/CheckHits.C index 5f06c5456d92c..ff0de30b77b16 100644 --- a/Detectors/TRD/macros/CheckHits.C +++ b/Detectors/TRD/macros/CheckHits.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,10 @@ #include <TCanvas.h> #include "FairLogger.h" -#include "TRDSimulation/Detector.h" +#include "DataFormatsTRD/Hit.h" #include "TRDBase/Geometry.h" #include "TRDBase/Calibrations.h" +#include "TRDSimulation/Detector.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DetectorsCommonDataFormats/DetID.h" #endif @@ -35,11 +37,11 @@ void CheckHits(const int detector = 50, // 354, 14, 242, 50 std::string paramfile = "o2sim_par.root") { // o2::trd::Calibrations calib; - // calib.setCCDBForSimulation(297595); + // calib.getCCDBObjects(297595); TFile* fin = TFile::Open(hitfile.data()); TTree* hitTree = (TTree*)fin->Get("o2sim"); - std::vector<o2::trd::HitType>* hits = nullptr; + std::vector<o2::trd::Hit>* hits = nullptr; hitTree->SetBranchAddress("TRDHit", &hits); int nev = hitTree->GetEntries(); diff --git a/Detectors/TRD/macros/convertRun2ToRun3Digits.C b/Detectors/TRD/macros/convertRun2ToRun3Digits.C index f67bc7a45bfd7..9a67c49f1202b 100644 --- a/Detectors/TRD/macros/convertRun2ToRun3Digits.C +++ b/Detectors/TRD/macros/convertRun2ToRun3Digits.C @@ -1,209 +1,297 @@ #if !defined(__CINT__) || defined(__MAKECINT__) -#include <TClonesArray.h> +// ROOT +#include "TClonesArray.h" +#include "TH1F.h" +#include "TCanvas.h" +#include "TFile.h" + +// AliRoot #include <AliRunLoader.h> #include <AliLoader.h> #include <AliDataLoader.h> #include <AliTreeLoader.h> #include <AliTRDarrayADC.h> - -#include <iostream> - -#include "TH1F.h" -#include "TRDBase/Digit.h" -#include "TRDBase/Tracklet.h" - #include <AliRawReaderRoot.h> #include <AliRawReaderDateOnline.h> #include <AliTRDrawStream.h> #include <AliRawReader.h> +#include <AliTRDdigitsManager.h> +#include <AliTRDCommonParam.h> +#include <AliTRDSignalIndex.h> +#include <AliTRDfeeParam.h> + +// O2 +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" + +// other +#include <iostream> + #endif -using namespace o2; -using namespace trd; -using namespace std; +/*-------------------------------------------------------------------------- -// qa.root -// 18000283989033.808.root -// TRD.Digits.root -void convertRun2ToRun3Digits(TString qaOutPath = "", - TString rawDataInPath = "", - TString run2DigitsInPath = "", - TString run3DigitsOutPath = "trddigits.root", - int nRawEvents = 1000) -{ - vector<o2::trd::Digit> run3Digits; - vector<o2::trd::TriggerRecord> triggerRecords; +!! Set paths to input data in the convertRun2ToRun3Digits() function below !! - TH1F* hAdc = new TH1F("hADC", "ADC spectrum", 1024, -0.5, 1023.5); - TH1F* hTBsum = new TH1F("hTBsum", "TBsum", 3000, -0.5, 2999.5); +----------------------------------------------------------------------------*/ - // convert raw data if path set - if (rawDataInPath != "") { - cout << "Converting RAW data..." << endl; - AliRawReader* reader; - if (rawDataInPath.Contains(".root")) { - cout << "[I] Reading with ROOT" << endl; - AliRawReaderRoot* readerDate = new AliRawReaderRoot(rawDataInPath); - readerDate->SelectEquipment(0, 1024, 1024); - readerDate->Select("TRD"); - //readerDate->SelectEvents(7); - reader = (AliRawReader*)readerDate; - - } else if (rawDataInPath.Contains(":")) { - cout << "[I] Reading DATE monitoring events" << endl; - AliRawReaderDateOnline* readerRoot = new AliRawReaderDateOnline(rawDataInPath); - readerRoot->SelectEquipment(0, 1024, 1041); - readerRoot->Select("TRD"); - //readerRoot->SelectEvents(7); - reader = (AliRawReader*)readerRoot; - } +using namespace std; +using namespace o2::trd; +using namespace o2::trd::constants; - AliTRDdigitsManager* digitMan = new AliTRDdigitsManager; - digitMan->CreateArrays(); +vector<Digit> run3Digits; +vector<TriggerRecord> triggerRecords; +o2::dataformats::MCTruthContainer<o2::MCCompLabel> mcLabels; + +TH1F* hAdc = new TH1F("hADC", "ADC spectrum", 1024, -0.5, 1023.5); +TH1F* hTBsum = new TH1F("hTBsum", "TBsum", 3000, -0.5, 2999.5); + +void writeDigits(TString filename) +{ + if (run3Digits.size() != 0) { + TFile* digitsFile = new TFile(filename, "RECREATE"); + TTree* digitTree = new TTree("o2sim", "run2 digits"); + std::vector<Digit>* run3pdigits = &run3Digits; + digitTree->Branch("TRDDigit", &run3pdigits); + digitTree->Branch("TriggerRecord", &triggerRecords); + digitTree->Branch("TRDMCLabels", &mcLabels); + digitTree->Fill(); + cout << run3Digits.size() << " run3 digits written to: " << filename << endl; + digitTree->Write(); + delete digitTree; + delete digitsFile; + } +} - AliTRDrawStream* rawStream = new AliTRDrawStream(reader); +void convertRaw(TString rawDataInPath) +{ + cout << "Converting raw data..." << endl; + run3Digits.reserve(4000 * 8000); + triggerRecords.reserve(1000 * 8000); + AliRawReader* reader; + if (rawDataInPath.Contains(".root")) { + cout << "[I] Reading with ROOT" << endl; + AliRawReaderRoot* readerDate = new AliRawReaderRoot(rawDataInPath); + readerDate->SelectEquipment(0, 1024, 1024); + readerDate->Select("TRD"); + //readerDate->SelectEvents(7); + reader = (AliRawReader*)readerDate; + + } else if (rawDataInPath.Contains(":")) { + cout << "[I] Reading DATE monitoring events" << endl; + AliRawReaderDateOnline* readerRoot = new AliRawReaderDateOnline(rawDataInPath); + readerRoot->SelectEquipment(0, 1024, 1041); + readerRoot->Select("TRD"); + //readerRoot->SelectEvents(7); + reader = (AliRawReader*)readerRoot; + } - TClonesArray trkl("AliTRDtrackletMCM"); - rawStream->SetTrackletArray(&trkl); + AliTRDdigitsManager* digitMan = new AliTRDdigitsManager; + digitMan->CreateArrays(); - int ievent = 0; - while (reader->NextEvent()) { - ievent++; - int eventtime = ievent * 12; + AliTRDrawStream* rawStream = new AliTRDrawStream(reader); - if (ievent >= nRawEvents) - break; + TClonesArray trkl("AliTRDtrackletMCM"); + rawStream->SetTrackletArray(&trkl); - //digitMan->ResetArrays(); + int ievent = 0; + TString filename; + uint64_t triggerRecordsStart = 0; + int recordSize = 0; + while (reader->NextEvent()) { + int eventtime = ievent * 12; + if (ievent % 100 == 0 && ievent != 0) { + filename = "trddigits." + to_string(ievent / 100) + ".root"; + } - if (ievent % 10 == 0) { - cout << "Event " << ievent << endl; - } + //digitMan->ResetArrays(); - // hntrkl->Fill(trkl.GetEntries()); - while (rawStream->NextChamber(digitMan) >= 0) { - //hptphase->Fill(digMan->GetDigitsParam()->GetPretriggerPhase()); - } + if (ievent % 10 == 0) { + cout << "Event " << ievent << endl; + } - for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { - AliTRDSignalIndex* idx = digitMan->GetIndexes(det); + // hntrkl->Fill(trkl.GetEntries()); + while (rawStream->NextChamber(digitMan) >= 0) { + //hptphase->Fill(digMan->GetDigitsParam()->GetPretriggerPhase()); + } - if (!idx) - continue; - if (!idx->HasEntry()) - continue; + for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { + AliTRDSignalIndex* idx = digitMan->GetIndexes(det); - int row, col; - while (idx->NextRCIndex(row, col)) { - int tbsum = 0; - ArrayADC adctimes; - for (int timebin = 0; timebin < digitMan->GetDigits(det)->GetNtime(); timebin++) { - int adc = digitMan->GetDigits(det)->GetData(row, col, timebin); - hAdc->Fill(adc); - tbsum += adc; + if (!idx) + continue; + if (!idx->HasEntry()) + continue; - adctimes[timebin] = adc; - } + int row, col; + while (idx->NextRCIndex(row, col)) { + int tbsum = 0; + ArrayADC adctimes; + for (int timebin = 0; timebin < digitMan->GetDigits(det)->GetNtime(); timebin++) { + int adc = digitMan->GetDigits(det)->GetData(row, col, timebin); + hAdc->Fill(adc); + tbsum += adc; - if (tbsum > 0) { - run3Digits.push_back(o2::trd::Digit(det, row, col, adctimes, eventtime)); - } + adctimes[timebin] = adc; + } - hTBsum->Fill(tbsum); + if (tbsum > 0) { + run3Digits.emplace_back(det, row, col, adctimes); } + + hTBsum->Fill(tbsum); } - trkl.Clear(); + digitMan->ClearIndexes(det); } - - delete rawStream; - if (reader) - delete reader; + trkl.Clear(); + recordSize = run3Digits.size() - triggerRecordsStart; + triggerRecords.emplace_back(ievent, triggerRecordsStart, recordSize, 0, 0); + triggerRecordsStart = run3Digits.size(); + ievent++; } - // convert run2 digits if path set - if (run2DigitsInPath != "") { - cout << "Converting Run2 digits..." << endl; + delete rawStream; + if (reader) + delete reader; +} - TFile run2DigitsFile(run2DigitsInPath); - AliTRDdigitsManager* digitMan = new AliTRDdigitsManager; - digitMan->CreateArrays(); +void convertSim(TString run2DigitsInPath) +{ + cout << "Converting run2 digits..." << endl; + run3Digits.reserve(4000 * 8000); + triggerRecords.reserve(1000 * 8000); - TIter next(run2DigitsFile.GetListOfKeys()); + TFile run2DigitsFile(run2DigitsInPath); + AliTRDdigitsManager* digitMan = new AliTRDdigitsManager; + digitMan->CreateArrays(); - uint64_t triggerRecordsStart = 0; - int recordSize = 0; - int ievent = 0; - while (TObject* obj = next()) { - cout << "Processing " << obj->GetName() << endl; + TIter next(run2DigitsFile.GetListOfKeys()); - // eventTime needs to be some increasing integer - string eventNumber(obj->GetName(), 5, 3); - int eventTime = stoi(eventNumber) * 12; + uint64_t triggerRecordsStart = 0; + int recordSize = 0; + int ievent = 0; + while (TObject* obj = next()) { + cout << "Processing " << obj->GetName() << endl; - TTree* tr = (TTree*)run2DigitsFile.Get(Form("%s/TreeD", obj->GetName())); + // eventTime needs to be some increasing integer + string eventNumber(obj->GetName(), 5, 3); + int eventTime = stoi(eventNumber) * 12; - for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { - digitMan->ClearArrays(det); - digitMan->ClearIndexes(det); - } + TTree* tr = (TTree*)run2DigitsFile.Get(Form("%s/TreeD", obj->GetName())); - digitMan->ReadDigits(tr); + for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { + digitMan->ClearArrays(det); + digitMan->ClearIndexes(det); + } - for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { - if (!digitMan->GetDigits(det)) - continue; + digitMan->ReadDigits(tr); - int sector = det / 30; - int stack = (det - sector * 30) / 6; + for (int det = 0; det < AliTRDCommonParam::kNdet; det++) { + if (!digitMan->GetDigits(det)) + continue; - digitMan->GetDigits(det)->Expand(); + if (digitMan->GetDigits(det)->GetNtime() > 30) { + cout << "----!!! --- number of times is greater than 30" << endl; + } - int nrows = AliTRDfeeParam::GetNrowC1(); - if (stack == 2) { - nrows = AliTRDfeeParam::GetNrowC0(); - } + int sector = det / 30; + int stack = (det - sector * 30) / 6; - // cout << "det: " << det << " | " << "sector: " << sector << " | " << "stack: " << stack << " | " << "rows: " << nrows << endl; + digitMan->GetDigits(det)->Expand(); - for (int row = 0; row < nrows; row++) { - for (int col = 0; col < AliTRDfeeParam::GetNcol(); col++) { - int tbsum = 0; - ArrayADC adctimes; + int nrows = AliTRDfeeParam::GetNrowC1(); + if (stack == 2) { + nrows = AliTRDfeeParam::GetNrowC0(); + } - for (int timebin = 0; timebin < digitMan->GetDigits(det)->GetNtime(); timebin++) { + // cout << "det: " << det << " | " << "sector: " << sector << " | " << "stack: " << stack << " | " << "rows: " << nrows << endl; - if (digitMan->GetDigits(det)->GetNtime() > 30) { - cout << "----!!! --- number of times is greater than 30" << endl; - } + for (int row = 0; row < nrows; row++) { + for (int col = 0; col < NCOLUMN; col++) { + int side = (col < NCOLUMN / 2) ? 0 : 1; + int rob = 2 * (row / NMCMROBINROW) + side; + int mcm = side == 0 ? (row * NMCMROBINROW + col / NCOLMCM) % NMCMROB : (row * NMCMROBINROW + (col - NCOLUMN / 2) / NCOLMCM) % NMCMROB; + int channel = 19 - (col % NCOLMCM); + int tbsum = 0; + ArrayADC adctimes; + bool isSharedRight = false, isSharedLeft = false; + if (col % NCOLMCM == 0 || col % NCOLMCM == 1) { + isSharedRight = true; + } else if (col % NCOLMCM == 17) { + isSharedLeft = true; + } - int adc = digitMan->GetDigitAmp(row, col, timebin, det); - adctimes[timebin] = adc; + for (int timebin = 0; timebin < digitMan->GetDigits(det)->GetNtime(); timebin++) { + int adc = digitMan->GetDigitAmp(row, col, timebin, det); - // this value seems to indicate no digit -> skip - if (adc == -7169) - continue; + // this value seems to indicate no digit -> skip + if (adc == -7169) + continue; - hAdc->Fill(adc); - tbsum += adc; - } + adctimes[timebin] = adc; - if (tbsum > 0) { - run3Digits.push_back(o2::trd::Digit(det, row, col, adctimes, eventTime)); - } + hAdc->Fill(adc); + tbsum += adc; + } - if (tbsum > 0) { - hTBsum->Fill(tbsum); + if (tbsum > 0) { + run3Digits.push_back(Digit(det, rob, mcm, channel, adctimes)); + if (isSharedRight && col > 17) { + if (mcm % NMCMROBINCOL == 0) { + // switch to the ROB on the right + run3Digits.emplace_back(det, rob - 1, mcm + 3, channel - NCOLMCM, adctimes); + } else { + // we stay on the same ROB + run3Digits.emplace_back(det, rob, mcm - 1, channel - NCOLMCM, adctimes); + } + + } else if (isSharedLeft && col < 126) { + if (mcm % NMCMROBINCOL == 3) { + // switch to ROB on the left + run3Digits.emplace_back(det, rob + 1, mcm - 3, channel + NCOLMCM, adctimes); + } else { + // we stay on the same ROB + run3Digits.emplace_back(det, rob, mcm + 1, channel + NCOLMCM, adctimes); + } } } + + if (tbsum > 0) { + hTBsum->Fill(tbsum); + } } - recordSize = run3Digits.size() - triggerRecordsStart; - triggerRecords.emplace_back(ievent, triggerRecordsStart, recordSize); - triggerRecordsStart = run3Digits.size(); - ievent++; } } + recordSize = run3Digits.size() - triggerRecordsStart; + triggerRecords.emplace_back(ievent, triggerRecordsStart, recordSize, 0, 0); + triggerRecordsStart = run3Digits.size(); + ievent++; } +} + +// qa.root +// 18000283989033.808.root +// TRD.Digits.root +void convertRun2ToRun3Digits(TString qaOutPath = "", + TString rawDataInPath = "", + TString run2DigitsInPath = "", + TString outputPath = "trddigits.root") +{ + // convert raw data if path set + if (rawDataInPath != "") { + convertRaw(rawDataInPath); + } + + // convert run2 digits if path set + if (run2DigitsInPath != "") { + convertSim(run2DigitsInPath); + } + + writeDigits(outputPath); // show and write QA if (qaOutPath != "") { @@ -224,18 +312,4 @@ void convertRun2ToRun3Digits(TString qaOutPath = "", cout << "QA output written to: " << qaOutPath << endl; } - - // write run3 digits - if (run3Digits.size() != 0) { - TFile* digitsFile = new TFile(run3DigitsOutPath, "RECREATE"); - TTree* digitTree = new TTree("o2sim", "run2 digits"); - std::vector<o2::trd::Digit>* run3pdigits = &run3Digits; - digitTree->Branch("TRDDigit", &run3pdigits); - digitTree->Branch("TriggerRecord", &triggerRecords); - digitTree->Fill(); - cout << run3Digits.size() << " run3 digits written to: " << run3DigitsOutPath << endl; - digitTree->Write(); - delete digitTree; - delete digitsFile; - } } diff --git a/Detectors/TRD/reconstruction/CMakeLists.txt b/Detectors/TRD/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..7e39dfb87f0b9 --- /dev/null +++ b/Detectors/TRD/reconstruction/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + + +o2_add_library(TRDReconstruction + SOURCES src/CTFCoder.cxx + src/CTFHelper.cxx + src/DigitsParser.cxx + src/TrackletsParser.cxx + src/CruRawReader.cxx + src/CompressedRawReader.cxx + src/DataReaderTask.cxx + src/CruCompressorTask.cxx + src/EventRecord.cxx + PUBLIC_LINK_LIBRARIES O2::TRDBase + O2::DataFormatsTRD + O2::DataFormatsTPC + O2::TRDWorkflowIO + O2::ReconstructionDataFormats + O2::DetectorsRaw + O2::rANS + Microsoft.GSL::GSL) + + +o2_add_executable(compressor + COMPONENT_NAME trd + SOURCES src/CruCompressor.cxx + PUBLIC_LINK_LIBRARIES O2::TRDReconstruction + ) + +o2_add_executable(datareader + COMPONENT_NAME trd + SOURCES src/DataReader.cxx + PUBLIC_LINK_LIBRARIES O2::TRDReconstruction + ) diff --git a/Detectors/TRD/reconstruction/README.md b/Detectors/TRD/reconstruction/README.md new file mode 100644 index 0000000000000..be51afaa76891 --- /dev/null +++ b/Detectors/TRD/reconstruction/README.md @@ -0,0 +1,57 @@ +<!-- doxy +\page refDetectorsTRDreconstruction +/doxy --> + +# TRD Reconstruction + +Reconstruction is made up of different parts. There are things that run on the flp, run on the epn and in various forms as well. + +- Parts to reconstruction : + - flp : + - o2-trd-compressor + This takes in the data from the CRU, optionally compresses it or sends it raw out to the epn via workflows. + - epn : + - o2-trd-rawreader + Take the piped in raw data and unpacks it to a vector tracklets/digits/triggerrecords. + +- Generate raw data from montecarlo: +``` +o2-sim -n 200 -g pythia8 --skipModules ZDC +o2-sim-digitizer-workflow -b +o2-trd-trap2raw -d trddigits.root -t trdtracklets.root -l halfcru -o ./ -x -r 6 -e +``` +- Parse raw data : + + You will need the datadistribution installed as well which has an O2 dependency. + +``` +aliBuild build DataDistribution --defaults o2 +``` +Now we are ready to play. +- Where to find some raw data. + - Generate some as above, one can keep looping through a set of data if the traversal of your data is too quick for your purposes. + - Pulling taken data from EOS (14 December 2020(testpattern) and January 2021(test pattern)). [link instructions of eos access] + +- MC to raw + - pipe the simulated raw data through the rawreader and onto where ever you want to use it. +``` +o2-raw-file-reader-workflow --input-conf TRDraw.cfg | o2-trd-datareader --trd-datareader-disablebyteswapdata +``` + +- Bits and pieces required. + - Data input (StfBuilder) + - Data processing (a pipeline of pre compressor, compressor, and post compressor) + - Data output (StfSender) + +``` +StfBuilder --id stfb --session default --transport shmem --detector TRD --detector-rdh 6 --dpl-channel-name dpl-chan --channel-config "name=dpl-chan,type=push,method=bind,address=ipc:///tmp/stfb-to-dpl,transport=shmem,rateLogging=1" --data-source-enable --data-source-dir /path/to/data --data-source-rate=44 +``` + +``` +o2-dpl-raw-proxy --session default -b --dataspec "A:TRD/RAWDATA" --channel-config "name=readout-proxy,type=pull,method=connect,address=ipc:///tmp/stfb-to-dpl,transport=shmem,rateLogging=1" | o2-trd-crucompressor --session default -b | o2-dpl-output-proxy --session default -b --dataspec "downstream:TRD/RAWDATA" --channel-config "name=downstream,type=push,method=bind,address=ipc:///tmp/dpl-to-stfs,rateLogging=1,transport=shmem" +``` + +``` +StfSender --id stfs --session default --transport shmem --stand-alone --input-channel-name=from-dpl --channel-config "name=from-dpl,type=pull,method=connect,address=ipc:///tmp/dpl-to-stfs,rateLogging=1,transport=shmem" + ``` + diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..f019dac086615 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h @@ -0,0 +1,196 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of TRD data + +#ifndef O2_TRD_CTFCODER_H +#define O2_TRD_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsTRD/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "TRDReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace trd +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::TRD) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Tracklet64>& trkData, const gsl::span<const Digit>& digData); + + /// entropy decode data from buffer with CTF + template <typename VTRG, typename VTRK, typename VDIG> + void decode(const CTF::base& ec, VTRG& trigVec, VTRK& trkVec, VDIG& digVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Tracklet64>& trkVec, std::vector<Digit>& digVec); +}; + +/// entropy-encode digits and tracklets to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const TriggerRecord>& trigData, const gsl::span<const Tracklet64>& trkData, const gsl::span<const Digit>& digData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // BLC_bcIncTrig + MD::EENCODE, // BLC_orbitIncTrig + MD::EENCODE, // BLC_entriesTrk + MD::EENCODE, // BLC_entriesDig + MD::EENCODE, // BLC_HCIDTrk + MD::EENCODE, // BLC_padrowTrk + MD::EENCODE, // BLC_colTrk + MD::EENCODE, // BLC_posTrk + MD::EENCODE, // BLC_slopeTrk + MD::EENCODE, // BLC_pidTrk + MD::EENCODE, // BLC_CIDDig + MD::EENCODE, // BLC_ROBDig + MD::EENCODE, // BLC_MCMDig + MD::EENCODE, // BLC_chanDig + MD::EENCODE, // BLC_ADCDig + }; + + CTFHelper helper(trigData, trkData, digData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODETRD(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODETRD(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODETRD(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + ENCODETRD(helper.begin_entriesTrk(), helper.end_entriesTrk(), CTF::BLC_entriesTrk, 0); + ENCODETRD(helper.begin_entriesDig(), helper.end_entriesDig(), CTF::BLC_entriesDig, 0); + + ENCODETRD(helper.begin_HCIDTrk(), helper.end_HCIDTrk(), CTF::BLC_HCIDTrk, 0); + ENCODETRD(helper.begin_padrowTrk(), helper.end_padrowTrk(), CTF::BLC_padrowTrk, 0); + ENCODETRD(helper.begin_colTrk(), helper.end_colTrk(), CTF::BLC_colTrk, 0); + ENCODETRD(helper.begin_posTrk(), helper.end_posTrk(), CTF::BLC_posTrk, 0); + ENCODETRD(helper.begin_slopeTrk(), helper.end_slopeTrk(), CTF::BLC_slopeTrk, 0); + ENCODETRD(helper.begin_pidTrk(), helper.end_pidTrk(), CTF::BLC_pidTrk, 0); + + ENCODETRD(helper.begin_CIDDig(), helper.end_CIDDig(), CTF::BLC_CIDDig, 0); + ENCODETRD(helper.begin_ROBDig(), helper.end_ROBDig(), CTF::BLC_ROBDig, 0); + ENCODETRD(helper.begin_MCMDig(), helper.end_MCMDig(), CTF::BLC_MCMDig, 0); + ENCODETRD(helper.begin_chanDig(), helper.end_chanDig(), CTF::BLC_chanDig, 0); + ENCODETRD(helper.begin_ADCDig(), helper.end_ADCDig(), CTF::BLC_ADCDig, 0); + + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded data to tracklets and digits +template <typename VTRG, typename VTRK, typename VDIG> +void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VTRK& trkVec, VDIG& digVec) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcInc, HCIDTrk, posTrk, CIDDig, ADCDig; + std::vector<uint32_t> orbitInc, entriesTrk, entriesDig, pidTrk; + std::vector<uint8_t> padrowTrk, colTrk, slopeTrk, ROBDig, MCMDig, chanDig; + +#define DECODETRD(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODETRD(bcInc, CTF::BLC_bcIncTrig); + DECODETRD(orbitInc, CTF::BLC_orbitIncTrig); + DECODETRD(entriesTrk, CTF::BLC_entriesTrk); + DECODETRD(entriesDig, CTF::BLC_entriesDig); + + DECODETRD(HCIDTrk, CTF::BLC_HCIDTrk); + DECODETRD(padrowTrk, CTF::BLC_padrowTrk); + DECODETRD(colTrk, CTF::BLC_colTrk); + DECODETRD(posTrk, CTF::BLC_posTrk); + DECODETRD(slopeTrk, CTF::BLC_slopeTrk); + DECODETRD(pidTrk, CTF::BLC_pidTrk); + + DECODETRD(CIDDig, CTF::BLC_CIDDig); + DECODETRD(ROBDig, CTF::BLC_ROBDig); + DECODETRD(MCMDig, CTF::BLC_MCMDig); + DECODETRD(chanDig, CTF::BLC_chanDig); + DECODETRD(ADCDig, CTF::BLC_ADCDig); + // clang-format on + // + trigVec.clear(); + trkVec.clear(); + digVec.clear(); + trigVec.reserve(header.nTriggers); + trkVec.reserve(header.nTracklets); + digVec.reserve(header.nDigits); + + uint32_t trkCount = 0, digCount = 0, adcCount = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitInc[itrig]) { // non-0 increment => new orbit + ir.bc = bcInc[itrig]; // bcInc has absolute meaning + ir.orbit += orbitInc[itrig]; + } else { + ir.bc += bcInc[itrig]; + } + + uint32_t firstEntryTrk = trkVec.size(); + uint16_t hcid = 0; + for (uint32_t it = 0; it < entriesTrk[itrig]; it++) { + hcid += HCIDTrk[trkCount]; // 1st tracklet of trigger was encoded with abs HCID, then increments + trkVec.emplace_back(header.format, hcid, padrowTrk[trkCount], colTrk[trkCount], posTrk[trkCount], slopeTrk[trkCount], pidTrk[trkCount]); + trkCount++; + } + + uint32_t firstEntryDig = digVec.size(); + int16_t cid = 0; + for (uint32_t id = 0; id < entriesDig[itrig]; id++) { + cid += CIDDig[digCount]; // 1st digit of trigger was encoded with abs CID, then increments + auto& dig = digVec.emplace_back(cid, ROBDig[digCount], MCMDig[digCount], chanDig[digCount]); + dig.setADC({&ADCDig[adcCount], constants::TIMEBINS}); + digCount++; + adcCount += constants::TIMEBINS; + } + + trigVec.emplace_back(ir, firstEntryDig, entriesDig[itrig], firstEntryTrk, entriesTrk[itrig]); + } + assert(digCount == header.nDigits && trkCount == header.nTracklets && adcCount == (int)ADCDig.size()); +} + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_CTFCODER_H diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFHelper.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..745b54de672fb --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFHelper.h @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for TRD CTF creation + +#ifndef O2_TRD_CTF_HELPER_H +#define O2_TRD_CTF_HELPER_H + +#include "DataFormatsTRD/CTF.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/Digit.h" +#include <gsl/span> +#include <bitset> + +namespace o2 +{ +namespace trd +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const TriggerRecord>& trgRec, + const gsl::span<const Tracklet64>& trkData, const gsl::span<const Digit>& digData) + : mTrigRec(trgRec), mTrkData(trkData), mDigData(digData), mTrkStart(trkData.size()), mDigStart(digData.size()) + { + // flag start of new trigger for tracklets and digits + for (const auto& trg : mTrigRec) { + if (trg.getNumberOfTracklets()) { + mTrkStart[trg.getFirstTracklet()] = true; + } + if (trg.getNumberOfDigits()) { + mDigStart[trg.getFirstDigit()] = true; + } + } + } + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigRec.size()), uint32_t(mTrkData.size()), uint32_t(mDigData.size()), 0, 0, 0}; + if (mTrigRec.size()) { + h.firstOrbit = mTrigRec[0].getBCData().orbit; + h.firstBC = mTrigRec[0].getBCData().bc; + } + if (mTrkData.size()) { + h.format = (uint16_t)mTrkData[0].getFormat(); + } + return h; + } + + size_t getSize() const { return mTrigRec.size() * sizeof(TriggerRecord) + mTrkData.size() * sizeof(Tracklet64) + mDigData.size() * sizeof(Digit); } + + //>>> =========================== ITERATORS ======================================== + template <typename I, typename D, typename T, int M = 1> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, TriggerRecord, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].getBCData().orbit == mData[mIndex - 1].getBCData().orbit) { + return mData[mIndex].getBCData().bc - mData[mIndex - 1].getBCData().bc; + } else { + return mData[mIndex].getBCData().bc; + } + } + return 0; + } + }; + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, TriggerRecord, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].getBCData().orbit - mData[mIndex - 1].getBCData().orbit : 0; } + }; + + //_______________________________________________ + // Number of tracklets for trigger + class Iter_entriesTrk : public _Iter<Iter_entriesTrk, TriggerRecord, uint32_t> + { + public: + using _Iter<Iter_entriesTrk, TriggerRecord, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNumberOfTracklets(); } + }; + + //_______________________________________________ + // Number of digits for trigger + class Iter_entriesDig : public _Iter<Iter_entriesDig, TriggerRecord, uint32_t> + { + public: + using _Iter<Iter_entriesDig, TriggerRecord, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getNumberOfDigits(); } + }; + + //_______________________________________________ + class Iter_HCIDTrk : public _Iter<Iter_HCIDTrk, Tracklet64, uint16_t> + { + private: + const std::vector<bool>* mTrigStart{nullptr}; + + public: + using _Iter<Iter_HCIDTrk, Tracklet64, uint16_t>::_Iter; + Iter_HCIDTrk(const std::vector<bool>* ts, const gsl::span<const Tracklet64>& data, bool end) : mTrigStart(ts), _Iter(data, end) {} + Iter_HCIDTrk() = default; + + // assume sorting in HCID: for the 1st tracklet of the trigger return the abs HCID, for the following ones: difference to previous HCID + value_type operator*() const + { + return (*mTrigStart)[mIndex] ? mData[mIndex].getHCID() : mData[mIndex].getHCID() - mData[mIndex - 1].getHCID(); + } + }; + + //_______________________________________________ + class Iter_padrowTrk : public _Iter<Iter_padrowTrk, Tracklet64, uint8_t> + { + public: + using _Iter<Iter_padrowTrk, Tracklet64, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPadRow(); } + }; + + //_______________________________________________ + class Iter_colTrk : public _Iter<Iter_colTrk, Tracklet64, uint8_t> + { + public: + using _Iter<Iter_colTrk, Tracklet64, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getColumn(); } + }; + + //_______________________________________________ + class Iter_posTrk : public _Iter<Iter_posTrk, Tracklet64, uint16_t> + { + public: + using _Iter<Iter_posTrk, Tracklet64, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPosition(); } + }; + + //_______________________________________________ + class Iter_slopeTrk : public _Iter<Iter_slopeTrk, Tracklet64, uint8_t> + { + public: + using _Iter<Iter_slopeTrk, Tracklet64, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getSlope(); } + }; + + //_______________________________________________ + class Iter_pidTrk : public _Iter<Iter_pidTrk, Tracklet64, uint32_t> + { + public: + using _Iter<Iter_pidTrk, Tracklet64, uint32_t>::_Iter; + value_type operator*() const { return mData[mIndex].getPID(); } + }; + + //_______________________________________________ + class Iter_CIDDig : public _Iter<Iter_CIDDig, Digit, uint16_t> + { + private: + const std::vector<bool>* mTrigStart{nullptr}; + + public: + using _Iter<Iter_CIDDig, Digit, uint16_t>::_Iter; + Iter_CIDDig(const std::vector<bool>* ts, const gsl::span<const Digit>& data, bool end) : mTrigStart(ts), _Iter(data, end) {} + Iter_CIDDig() = default; + + // assume sorting in CID: for the 1st digit of the trigger return the abs CID, for the following ones: difference to previous CID + value_type operator*() const + { + return (*mTrigStart)[mIndex] ? mData[mIndex].getDetector() : mData[mIndex].getDetector() - mData[mIndex - 1].getDetector(); + } + }; + + //_______________________________________________ + class Iter_ROBDig : public _Iter<Iter_ROBDig, Digit, uint8_t> + { + public: + using _Iter<Iter_ROBDig, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getROB(); } + }; + + //_______________________________________________ + class Iter_MCMDig : public _Iter<Iter_MCMDig, Digit, uint8_t> + { + public: + using _Iter<Iter_MCMDig, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getMCM(); } + }; + + //_______________________________________________ + class Iter_chanDig : public _Iter<Iter_chanDig, Digit, uint8_t> + { + public: + using _Iter<Iter_chanDig, Digit, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].getChannel(); } + }; + + //_______________________________________________ + class Iter_ADCDig : public _Iter<Iter_ADCDig, Digit, uint16_t, constants::TIMEBINS> + { + public: + using _Iter<Iter_ADCDig, Digit, uint16_t, constants::TIMEBINS>::_Iter; + value_type operator*() const { return mData[mIndex / constants::TIMEBINS].getADC()[mIndex % constants::TIMEBINS]; } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mTrigRec, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mTrigRec, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigRec, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigRec, true); } + + Iter_entriesTrk begin_entriesTrk() const { return Iter_entriesTrk(mTrigRec, false); } + Iter_entriesTrk end_entriesTrk() const { return Iter_entriesTrk(mTrigRec, true); } + + Iter_entriesDig begin_entriesDig() const { return Iter_entriesDig(mTrigRec, false); } + Iter_entriesDig end_entriesDig() const { return Iter_entriesDig(mTrigRec, true); } + + Iter_HCIDTrk begin_HCIDTrk() const { return Iter_HCIDTrk(&mTrkStart, mTrkData, false); } + Iter_HCIDTrk end_HCIDTrk() const { return Iter_HCIDTrk(&mTrkStart, mTrkData, true); } + + Iter_padrowTrk begin_padrowTrk() const { return Iter_padrowTrk(mTrkData, false); } + Iter_padrowTrk end_padrowTrk() const { return Iter_padrowTrk(mTrkData, true); } + + Iter_colTrk begin_colTrk() const { return Iter_colTrk(mTrkData, false); } + Iter_colTrk end_colTrk() const { return Iter_colTrk(mTrkData, true); } + + Iter_posTrk begin_posTrk() const { return Iter_posTrk(mTrkData, false); } + Iter_posTrk end_posTrk() const { return Iter_posTrk(mTrkData, true); } + + Iter_slopeTrk begin_slopeTrk() const { return Iter_slopeTrk(mTrkData, false); } + Iter_slopeTrk end_slopeTrk() const { return Iter_slopeTrk(mTrkData, true); } + + Iter_pidTrk begin_pidTrk() const { return Iter_pidTrk(mTrkData, false); } + Iter_pidTrk end_pidTrk() const { return Iter_pidTrk(mTrkData, true); } + + Iter_CIDDig begin_CIDDig() const { return Iter_CIDDig(&mDigStart, mDigData, false); } + Iter_CIDDig end_CIDDig() const { return Iter_CIDDig(&mDigStart, mDigData, true); } + + Iter_ROBDig begin_ROBDig() const { return Iter_ROBDig(mDigData, false); } + Iter_ROBDig end_ROBDig() const { return Iter_ROBDig(mDigData, true); } + + Iter_MCMDig begin_MCMDig() const { return Iter_MCMDig(mDigData, false); } + Iter_MCMDig end_MCMDig() const { return Iter_MCMDig(mDigData, true); } + + Iter_chanDig begin_chanDig() const { return Iter_chanDig(mDigData, false); } + Iter_chanDig end_chanDig() const { return Iter_chanDig(mDigData, true); } + + Iter_ADCDig begin_ADCDig() const { return Iter_ADCDig(mDigData, false); } + Iter_ADCDig end_ADCDig() const { return Iter_ADCDig(mDigData, true); } + + private: + const gsl::span<const o2::trd::TriggerRecord> mTrigRec; + const gsl::span<const o2::trd::Tracklet64> mTrkData; + const gsl::span<const o2::trd::Digit> mDigData; + std::vector<bool> mTrkStart; + std::vector<bool> mDigStart; +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CompressedRawReader.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CompressedRawReader.h new file mode 100644 index 0000000000000..ddf9a6a35f178 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CompressedRawReader.h @@ -0,0 +1,156 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CompressedRawReader.h +/// @author Sean Murray +/// @brief compressed raw reader, this is the part that parses the raw data +// after it is compressed on the flp in the compressor, effectively a decompressor. +// Data format is simply an event based vector of tracklet64, and the event header is +// a custom 64 bit "tracklet" with even info and an offset to the next header (blocksize) + +#ifndef O2_TRD_COMPRESSEDRAWREADER +#define O2_TRD_COMPRESSEDRAWREADER + +#include <fstream> +#include <string> +#include <cstdint> +#include <array> +#include <bitset> +#include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DataFormatsTRD/CompressedDigit.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/RawDataStats.h" + +namespace o2 +{ +namespace trd +{ + +class CompressedRawReader +{ + + static constexpr bool debugparsing = true; + enum CRUSate { CompressedStateHeader, + CompressedStateTracklets, + CompressedStatePadding }; + + public: + CompressedRawReader() = default; + ~CompressedRawReader() = default; + + inline bool run() + { + rewind(); + uint32_t dowhilecount = 0; + do { + int datareadfromhbf = processHBFs(); + } while (mDataReadIn < mDataBufferSize); + + return false; + }; + + void checkSummary(); + void resetCounters(); + + void setDataBuffer(const char* val) { mDataBuffer = val; }; + void setDataBufferSize(long val) { mDataBufferSize = val; }; + + inline uint32_t getDecoderByteCounter() const { return reinterpret_cast<const char*>(mDataPointer) - mDataBuffer; }; + + void setVerbose(bool v) { mVerbose = v; }; + void setDataVerbose(bool v) { mDataVerbose = v; }; + void setHeaderVerbose(bool v) { mHeaderVerbose = v; }; + void configure(std::bitset<16> options) + { + mByteSwap = options[TRDByteSwapBit]; + mVerbose = options[TRDVerboseBit]; + mHeaderVerbose = options[TRDHeaderVerboseBit]; + mDataVerbose = options[TRDDataVerboseBit]; + } + std::vector<Tracklet64>& getTracklets() { return mEventTracklets; }; + std::vector<Digit>& getDigits() { return mEventDigits; }; + std::vector<CompressedDigit>& getCompressedDigits() { return mCompressedEventDigits; }; + std::vector<o2::trd::TriggerRecord> getIR() { return mEventTriggers; } + + protected: + uint32_t processHBFs(); + bool buildCRUPayLoad(); + bool processBlock(); + + /** decoder private functions and data members **/ + + inline void rewind() + { + LOG(debug) << "!!!rewinding"; + mDataPointer = reinterpret_cast<const uint32_t*>(mDataBuffer); + }; + + int mJumpRDH = 0; + + std::ifstream mDecoderFile; + const char* mDataBuffer = nullptr; + long mDataBufferSize; + uint64_t mDataReadIn = 0; + const uint32_t* mDataPointer = nullptr; + const uint32_t* mDataPointerMax = nullptr; + const uint32_t* mDataEndPointer = nullptr; + const uint32_t* mDataPointerNext = nullptr; + uint8_t mDataNextWord = 1; + uint8_t mDataNextWordStep = 2; + const o2::header::RDHAny* mDataRDH; + // no need to waste time doing the copy std::array<uint32_t,8> mCurrentCRUWord; // data for a cru comes in words of 256 bits. + uint32_t mCurrentLinkDataPosition; // count of data read for current link in units of 256 bits + uint32_t mCompressedState; // the state of what we are expecting to read currently from the data stream, *not* what we have just read. + bool mError = false; + bool mFatal = false; + uint16_t mCurrentLink; // current link within the halfcru we are parsing 0-14 + uint16_t mCRUEndpoint; // the upper or lower half of the currently parsed cru 0-14 or 15-29 + uint16_t mCRUID; + uint16_t mHCID; + uint16_t mFEEID; // current Fee ID working on + //pointers to the data as we read them in, again no point in copying. + /** checker private functions and data members **/ + + bool checkerCheck(); + void checkerCheckRDH(); + bool mVerbose{false}; + bool mHeaderVerbose{false}; + bool mDataVerbose{false}; + bool mByteSwap{true}; + int mState; // basic state machine for where we are in the parsing. + // we parse rdh to rdh but data is cru to cru. + uint32_t mEventCounter; + uint32_t mFatalCounter; + uint32_t mErrorCounter; + + std::vector<Tracklet64> mEventTracklets; // when this runs properly it will only 6 for the flp its runnung on. + std::vector<o2::trd::TriggerRecord> mEventTriggers; + std::vector<Digit> mEventDigits; + std::vector<CompressedDigit> mCompressedEventDigits; + o2::InteractionRecord mIR; + struct TRDDataCounters_t { + std::array<uint32_t, 1080> LinkWordCounts; //units of 256bits "cru word" + std::array<uint32_t, 1080> LinkPadWordCounts; // units of 32 bits the data word size. + std::array<uint32_t, 1080> LinkFreq; //units of 256bits "cru word" + } TRDStatCounters; + + /** summary data **/ +}; + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/ConfigEventParser.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/ConfigEventParser.h new file mode 100644 index 0000000000000..f37a6a012e90a --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/ConfigEventParser.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ConfigEventReader.h +/// @author Sean Murray +/// @brief TRD cru output data to tracklet task + +#ifndef O2_TRD_CONFIGEVENTREADER +#define O2_TRD_CONFIGEVENTREADER + +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "TRDReconstruction/CruRawReader.h" +#include "TRDReconstruction/CompressedRawReader.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/CompressedDigit.h" +#include <fstream> + +namespace o2::trd +{ + +// class to Parse a single link of digits data. +// calling class splits data by link and this gets called per link. + +class ConfigEventParser +{ + + public: + ConfigEventParser() = default; + ~ConfigEventParser() = default; + bool getVerbose() { return mVerbose; } + void setVerbose(bool value, bool header, bool data) + { + mVerbose = value; + mHeaderVerbose = header; + mDataVerbose = data; + } + + private: + int mState; + int mDataWordsParsed; // count of data wordsin data that have been parsed in current call to parse. + int mBufferLocation; + bool mDataVerbose{false}; + bool mHeaderVerbose{false}; + bool mVerbose{false}; +}; + +} // namespace o2::trd + +#endif // O2_TRD_CONFIGEVENTREADER diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruCompressorTask.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruCompressorTask.h new file mode 100644 index 0000000000000..0aa0c0b7932d6 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruCompressorTask.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CruCompressorTask.h +/// @author Sean Murray +/// @brief TRD cru output data to tracklet task + +#ifndef O2_TRD_CRU2TRACKLETTASK +#define O2_TRD_CRU2TRACKLETTASK + +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "TRDReconstruction/CruRawReader.h" +#include <fstream> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +class CruCompressorTask : public Task +{ + public: + CruCompressorTask() = default; + ~CruCompressorTask() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + uint64_t buildEventOutput(); + + private: + CruRawReader mReader; // this will do the parsing. + std::array<uint64_t, o2::trd::constants::HBFBUFFERMAX> mOutBuffer; + bool mVerbose{false}; + bool mDataVerbose{false}; + bool mHeaderVerbose{false}; +}; + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_CRU2TRACKLETTASK diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h new file mode 100644 index 0000000000000..3b8a9799c21af --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h @@ -0,0 +1,285 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Cru raw data reader, this is the part that parses the raw data +// it runs on the flp(pre compression) or on the epn(pre tracklet64 array generation) +// it hands off blocks of cru pay load to the parsers. + +#ifndef O2_TRD_CRURAWREADER +#define O2_TRD_CRURAWREADER + +#include <fstream> +#include <iostream> +#include <string> +#include <cstdint> +#include <array> +#include <vector> +#include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/RawDataStats.h" +#include "TRDReconstruction/DigitsParser.h" +#include "TRDReconstruction/TrackletsParser.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/Digit.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "TRDReconstruction/EventRecord.h" + +#include "TH2F.h" + +namespace o2::trd +{ +class Tracklet64; +class TriggerRecord; +class Digit; + +class CruRawReader +{ + + static constexpr bool debugparsing = true; + enum CRUSate { CRUStateHalfCRUHeader = 0, + CRUStateHalfCRU }; + enum Dataformats { TrackletsDataFormat = 0, + DigitsDataFormat, + TestPatternDataFormat, + ConfigEventDataFormat }; + + public: + CruRawReader() = default; + ~CruRawReader() = default; + + bool run(); + + void checkSummary(); + void resetCounters(); + void configure(int tracklethcheader, int halfchamberwords, int halfchambermajor, std::bitset<16> options) + { + mByteSwap = options[TRDByteSwapBit]; + mVerbose = options[TRDVerboseBit]; + mHeaderVerbose = options[TRDHeaderVerboseBit]; + mDataVerbose = options[TRDDataVerboseBit]; + mFixDigitEndCorruption = options[TRDFixDigitCorruptionBit]; + mTrackletHCHeaderState = tracklethcheader; + mHalfChamberWords = halfchamberwords; + mHalfChamberMajor = halfchambermajor; + mRootOutput = options[TRDEnableRootOutputBit]; + mEnableTimeInfo = options[TRDEnableTimeInfoBit]; + mEnableStats = options[TRDEnableStatsBit]; + mOptions = options; + } + void setBlob(bool returnblob) { mReturnBlob = returnblob; }; //set class to produce blobs and not vectors. (compress vs pass through)` + void setDataBuffer(const char* val) + { + mDataBuffer = val; + }; + void setDataBufferSize(long val) + { + if (mVerbose) { + LOG(info) << " Setting buffer size to : " << val; + } + mDataBufferSize = val; + }; + void setVerbose(bool verbose) { mVerbose = verbose; } + void setDataVerbose(bool verbose) { mDataVerbose = verbose; } + void setHeaderVerbose(bool verbose) { mHeaderVerbose = verbose; } + inline uint32_t getDecoderByteCounter() const { return reinterpret_cast<const char*>(mDataPointer) - mDataBuffer; }; + bool buildBlobOutput(char* outputbuffer); // should probably go into a writer object. + // benchmarks + double mIntegratedBytes = 0.; + double mIntegratedTime = 0.; + + std::vector<Tracklet64>& getTracklets(InteractionRecord& ir) { return mEventRecords.getTracklets(ir); }; + std::vector<Digit>& getDigits(InteractionRecord& ir) { return mEventRecords.getDigits(ir); }; + // std::vector<o2::trd::TriggerRecord> getIR() { return mEventTriggers; } + void getParsedObjects(std::vector<Tracklet64>& tracklets, std::vector<Digit>& cdigits, std::vector<TriggerRecord>& triggers); + void getParsedObjectsandClear(std::vector<Tracklet64>& tracklets, std::vector<Digit>& digits, std::vector<TriggerRecord>& triggers); + void buildDPLOutputs(o2::framework::ProcessingContext& outputs, bool displaytracklets = false); + int getDigitsFound() { return mTotalDigitsFound; } + int getTrackletsFound() { return mTotalTrackletsFound; } + int sumTrackletsFound() { return mEventRecords.sumTracklets(); } + int sumDigitsFound() { return mEventRecords.sumDigits(); } + int getWordsRead() { return mTotalDigitWordsRead; } + int getWordsRejected() { return mTotalDigitWordsRejected; } + + std::shared_ptr<EventStorage*> getEventStorage() { return std::make_shared<EventStorage*>(&mEventRecords); } + void clearall() + { + mEventRecords.clear(); + clear(); + } + void clear() + { + mTrackletsParser.clear(); + mDigitsParser.clear(); + } + void OutputHalfCruRawData(); + // void setStats(o2::trd::TRDDataCountersPerTimeFrame* trdstats){mTimeFrameStats=trdstats;} + //void setHistos(std::array<TH2F*, 10> hist, std::array<TH2F*, constants::MAXPARSEERRORHISTOGRAMS> parsingerrors2d) + void setHistos(TList* hist, TList* parsingerrors2d) + { + mLinkErrors = hist; + mParsingErrors2d = parsingerrors2d; + }; + + void setTimeHistos(TH1F* timeframetime, TH1F* trackletparsingtime, TH1F* digitparsingtime, + TH1F* crutime, TH1F* packagingtime, TH1F* versions, TH1F* versionsmajor, + TH1F* parsingerrors) + { + mTimeFrameTime = timeframetime; + mTrackletTiming = trackletparsingtime; + mDigitTiming = digitparsingtime; + mCruTime = crutime; + mEventRecords.setHisto(packagingtime); + mDataVersions = versions; + mDataVersionsMajor = versionsmajor; + mParsingErrors = parsingerrors; + mTrackletsParser.setErrorHistos(parsingerrors, mParsingErrors2d); + }; + + protected: + bool processHBFs(int datasizealreadyread = 0, bool verbose = false); + bool processHBFsa(int datasizealreadyread = 0, bool verbose = false); + bool buildCRUPayLoad(); + int processHalfCRU(int cruhbfstartoffset); + bool processCRULink(); + int parseDigitHCHeader(); + int checkDigitHCHeader(); + int checkTrackletHCHeader(); + bool skipRDH(); + + inline void rewind() + { + if (mVerbose) { + LOG(info) << "rewinding crurawreader incoming data buffer"; + } + mDataPointer = reinterpret_cast<const uint32_t*>(mDataBuffer); + }; + + int mJumpRDH = 0; + bool mVerbose{false}; + bool mHeaderVerbose{false}; + bool mDataVerbose{false}; + bool mByteSwap{false}; + bool mFixDigitEndCorruption{false}; + int mTrackletHCHeaderState{0}; + int mHalfChamberWords{0}; + int mHalfChamberMajor{0}; + bool mRootOutput{0}; + bool mEnableTimeInfo{0}; + bool mEnableStats{0}; + std::bitset<16> mOptions; + const char* mDataBuffer = nullptr; + static const uint32_t mMaxHBFBufferSize = o2::trd::constants::HBFBUFFERMAX; + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX> mHBFPayload; //this holds the O2 payload held with in the HBFs to pass to parsing. + uint32_t mHalfCRUPayLoadRead{0}; // the words current read in for the currnt cru payload. + uint32_t mO2PayLoadRead{0}; // the words current read in for the currnt cru payload. + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator mStartParse, mEndParse; // limits of parsing, start and end points for parsing. + std::array<uint16_t, constants::TIMEBINS> mADCValues{}; + int mCurrentHalfCRULinkHeaderPoisition = 0; + // no need to waste time doing the copy std::array<uint32_t,8> mCurrentCRUWord; // data for a cru comes in words of 256 bits. + uint32_t mCurrentLinkDataPosition256; // count of data read for current link in units of 256 bits + uint32_t mCurrentLinkDataPosition; // count of data read for current link in units of 256 bits + uint32_t mCurrentHalfCRUDataPosition256; //count of data read for this half cru. + uint32_t mTotalHalfCRUDataLength; + uint32_t mTotalHalfCRUDataLength256; + + uint32_t mTotalTrackletsFound{0}; + uint32_t mTotalDigitsFound{0}; + + long mDataBufferSize; + uint64_t mDataReadIn = 0; + const uint32_t* mDataPointer = nullptr; // pointer to the current position in the rdh + const uint32_t* mDataPointerMax = nullptr; + const uint32_t* mDataEndPointer = nullptr; + const uint32_t* mDataPointerNext = nullptr; + uint8_t mDataNextWord = 1; + uint8_t mDataNextWordStep = 2; + + const o2::header::RDHAny* mDataRDH; + HalfCRUHeader mCurrentHalfCRUHeader; // are we waiting for new header or currently parsing the payload of on + DigitHCHeader mDigitHCHeader; // Digit HalfChamber header we are currently on. + DigitHCHeader1 mDigitHCHeader1; // this and the next 2 are option are and variable in order, hence + DigitHCHeader2 mDigitHCHeader2; // the individual seperation instead of an array. + DigitHCHeader3 mDigitHCHeader3; + TrackletHCHeader mTrackletHCHeader; // Tracklet HalfChamber header we are currently on. + uint16_t mCurrentLink; // current link within the halfcru we are parsing 0-14 + uint16_t mCRUEndpoint; // the upper or lower half of the currently parsed cru 0-14 or 15-29 + uint16_t mCRUID; + uint16_t mHCID; + TRDFeeID mFEEID; // current Fee ID working on + // the store of the 3 ways we can determine this information, link,rdh,halfchamber + std::array<int, 3> mDetector; + std::array<int, 3> mSector; + std::array<int, 3> mStack; + std::array<int, 3> mLayer; + std::array<int, 3> mSide; + std::array<int, 3> mEndPoint; + std::array<int, 3> mHalfChamberSide; + int mWhichData; // index used into the above arrays once decided on which source is "correct" + o2::InteractionRecord mIR; + std::array<uint32_t, 15> mCurrentHalfCRULinkLengths; + std::array<uint32_t, 15> mCurrentHalfCRULinkErrorFlags; + uint32_t mCRUState; // the state of what we are expecting to read currently from the data stream, *not* what we have just read. + bool mError = false; + bool mFatal = false; + uint32_t mSaveBufferDataSize = 0; + uint32_t mSaveBufferDataLeft = 0; + uint32_t mcruFeeID = 0; + uint32_t mDatareadfromhbf; + uint32_t mTotalHBFPayLoad = 0; // total data payload of the heart beat frame in question. + uint32_t mHBFoffset32 = 0; // total data payload of the heart beat frame in question. + uint64_t mDigitWordsRead = 0; + uint64_t mDigitWordsRejected = 0; + uint64_t mTotalDigitWordsRead = 0; + uint64_t mTotalDigitWordsRejected = 0; + uint64_t mTrackletWordsRead = 0; + uint64_t mTrackletWordsRejected = 0; + uint64_t mTotalTrackletWordsRejected = 0; + uint64_t mTotalTrackletWordsRead = 0; + //pointers to the data as we read them in, again no point in copying. + HalfCRUHeader* mhalfcruheader; + + bool checkerCheck(); + void checkerCheckRDH(); + int mState; // basic state machine for where we are in the parsing. + // we parse rdh to rdh but data is cru to cru. + //the relevant parsers. Not elegant but we need both so pointers to base classes and sending them in with templates or some other such mechanism seems impossible, or its just late and I cant think. + //TODO think of a more elegant way of incorporating the parsers. + TrackletsParser mTrackletsParser; + DigitsParser mDigitsParser; + //used to surround the outgoing data with a coherent rdh coming from the incoming stream. + o2::header::RDHAny* mOpenRDH; + o2::header::RDHAny* mCloseRDH; + + uint32_t mEventCounter; + uint32_t mFatalCounter; + uint32_t mErrorCounter; + + EventStorage mEventRecords; // store data range indexes into the above vectors. + EventRecord* mCurrentEvent; // the current event we are looking at, info extracted from cru half chamber header. + + bool mReturnBlob{0}; // whether to return blobs or vectors; + o2::trd::TRDDataCountersRunning mStatCountersRunning; + TList* mLinkErrors; + //std::array<TH2F*, constants::MAXLINKERRORHISTOGRAMS> mLinkErrors; + TH2F *hist7, *hist8; // a hack ! + TH1F *mTimeFrameTime, *mTrackletTiming, *mDigitTiming, *mCruTime; // a hack ! + TH1F *mDataVersions, *mDataVersionsMajor; // a hack ! + TH1F* mParsingErrors; // a hack ! + TList* mParsingErrors2d; + //std::array<TH2F*, constants::MAXPARSEERRORHISTOGRAMS> mParsingErrors2d; +}; + +} // namespace o2::trd +// namespace o2 + +#endif diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/DataReaderTask.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/DataReaderTask.h new file mode 100644 index 0000000000000..7ed8af21c994e --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/DataReaderTask.h @@ -0,0 +1,110 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DataReaderTask.h +/// @author Sean Murray +/// @brief TRD epn task to read incoming data + +#ifndef O2_TRD_DATAREADERTASK +#define O2_TRD_DATAREADERTASK + +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "TRDReconstruction/CruRawReader.h" +#include "TRDReconstruction/CompressedRawReader.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/RawDataStats.h" +#include <fstream> + +#include "TGraph2D.h" +#include "TH3F.h" +#include <TH2F.h> + +using namespace o2::framework; + +namespace o2::trd +{ + +class DataReaderTask : public Task +{ + public: + DataReaderTask(int tracklethcheader, int halfchamberwords, int halfchambermajor, std::string histofilename, std::bitset<16> option) : mCompressedData(option[TRDCompressedDataBit]), mByteSwap(option[TRDByteSwapBit]), mFixDigitEndCorruption(option[TRDFixDigitCorruptionBit]), mTrackletHCHeaderState(tracklethcheader), mHalfChamberWords(halfchamberwords), mHalfChamberMajor(halfchambermajor), mHistogramsFilename(histofilename), mVerbose(option[TRDVerboseBit]), mHeaderVerbose(option[TRDHeaderVerboseBit]), mDataVerbose(option[TRDDataVerboseBit]), mEnableTimeInfo(option[TRDEnableTimeInfoBit]), mEnableStats(option[TRDEnableStatsBit]), mRootOutput(option[TRDEnableRootOutputBit]), mIgnoreTrackletHCHeader(option[TRDIgnoreTrackletHCHeaderBit]), mIgnoreDigitHCHeader(option[TRDIgnoreDigitHCHeaderBit]), mOptions(option) {} + ~DataReaderTask() override = default; + void init(InitContext& ic) final; + void sendData(ProcessingContext& pc, bool blankframe = false); + void run(ProcessingContext& pc) final; + bool isTimeFrameEmpty(ProcessingContext& pc); + void endOfStream(o2::framework::EndOfStreamContext& ec) override; + + void setParsingErrorLabels(); + void buildHistograms(); + + private: + CruRawReader mReader; // this will do the parsing, of raw data passed directly through the flp(no compression) + CompressedRawReader mCompressedReader; //this will handle the incoming compressed data from the flp + // in both cases we pull the data from the vectors build message and pass on. + // they will internally produce a vector of digits and a vector tracklets and associated indexing. + // TODO templatise this and 2 versions of datareadertask, instantiated with the relevant parser. + + bool mVerbose{false}; // verbos output general debuggign and info output. + bool mDataVerbose{false}; // verbose output of data unpacking + bool mHeaderVerbose{false}; // verbose output of headers + bool mCompressedData{false}; // are we dealing with the compressed data from the flp (send via option) + bool mByteSwap{true}; // whether we are to byteswap the incoming data, mc is not byteswapped, raw data is (too be changed in cru at some point) + // o2::header::DataDescription mDataDesc; // Data description of the incoming data + bool mEnableTimeInfo{false}; // enable the timing of timeframe,cru,digit,tracklet processing. + bool mEnableStats{false}; // enable the taking of stats in the rawdatastats class + bool mRootOutput{false}; // enable the writing of histos.root, a poor mans qc, mostly for debugging. + bool mIgnoreDigitHCHeader{false}; // ignore this header for the purposes of data cross checking use the rdh/cru as authoritative + bool mIgnoreTrackletHCHeader{false}; // ignore this header for data validity checks, this and the above are use to parse corrupted data. + std::bitset<16> mOptions; // stores the incoming of the above bools, useful to be able to send this on instead of the individual ones above + // the above bools make the code more readable hence still here. + + uint64_t mWordsRead = 0; + uint64_t mWordsRejected = 0; + int mTrackletHCHeaderState{0}; // what to do about tracklethcheader, 0 never there, 2 always there, 1 there iff tracklet data, i.e. only there if next word is *not* endmarker 10001000. + int mHalfChamberWords{0}; // if the halfchamber header is effectively blanked major.minor = 0.0 and halfchamberwords=0 then this value is used as the number of additional words to try recover the data + int mHalfChamberMajor{0}; // if the halfchamber header is effectively blanked major.minor = 0.0 and halfchamberwords=0 then this value is used as the major version to try recover the data + std::string mHistogramsFilename; // filename to use for histograms. + std::string mDataDesc; + o2::header::DataDescription mUserDataDescription = o2::header::gDataDescriptionInvalid; // alternative user-provided description to pick + bool mFixDigitEndCorruption{false}; // fix the parsing of corrupt end of digit data. bounce over it. + o2::trd::TRDDataCountersPerTimeFrame mTimeFrameStats; // TODO for compressed data this is going to come in for each subtimeframe + // and we need to collate them. + + TH2F* LinkError; + TH2F* LinkError1; + TH2F* LinkError2; + TH2F* LinkError3; + TH2F* LinkError4; + TH2F* LinkError5; + TH2F* LinkError6; + TH2F* LinkError7; + //std::array<TH2F*, constants::MAXLINKERRORHISTOGRAMS> mLinkErrors; + //std::array<TH2F*, constants::MAXPARSEERRORHISTOGRAMS> mParseErrors; + TList* mLinkErrors; + TList* mParseErrors; + TH1F* mTimeFrameTime; + TH1F* mTrackletParsingTime; + TH1F* mDigitParsingTime; + TH1F* mCruTime; + TH1F* mPackagingTime; + TH1F* mDataVersions; + TH1F* mDataVersionsMajor; + TH1F* mParsingErrors; + TFile* mRootFile; +}; + +} // namespace o2::trd + +#endif // O2_TRD_DATAREADERTASK diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/DigitsParser.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/DigitsParser.h new file mode 100644 index 0000000000000..4e92a9b6067b6 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/DigitsParser.h @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EpnRawReaderTask.h +/// @author Sean Murray +/// @brief TRD cru output data to tracklet task + +#ifndef O2_TRD_DIGITSPARSER +#define O2_TRD_DIGITSPARSER + +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" + +#include <fstream> +#include <bitset> +#include "TH1F.h" +#include "TH2F.h" +#include "TList.h" + +//using namespace o2::framework; + +namespace o2::trd +{ +class Digit; +class EventRecord; +// class to Parse a single link of digits data. +// calling class splits data by link and this gets called per link. + +class DigitsParser +{ + + public: + DigitsParser() = default; + ~DigitsParser() = default; + void setData(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data) { mData = data; } + int Parse(bool verbose = false); // presupposes you have set everything up already. + int Parse(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data, std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator start, + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator end, int detector, int stack, int layer, int side, DigitHCHeader& hcheader, + TRDFeeID& feeid, unsigned int linkindex, EventRecord* eventrecord, std::bitset<16> options, bool cleardigits = false); + + enum DigitParserState { StateDigitHCHeader, // always the start of a half chamber. + StateDigitMCMHeader, + StateDigitMCMData, + StatePadding, + StateDigitEndMarker }; + + inline void swapByteOrder(unsigned int& word); + + int getDigitsFound() { return mDigitsFound; } + bool getVerbose() { return mVerbose; } + void setVerbose(bool value, bool header, bool data) + { + mVerbose = value; + mHeaderVerbose = header; + mDataVerbose = data; + } + void setByteSwap(bool byteswap) { mByteOrderFix = byteswap; } + std::vector<Digit>& getDigits() { return mDigits; } + void clearDigits() { mDigits.clear(); } + void clear() { mDigits.clear(); } + uint64_t getDumpedDataCount() { return mWordsDumped; } + uint64_t getDataWordsParsed() { return mDataWordsParsed; } + void tryFindMCMHeaderAndDisplay(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator mStartParse); + //void tryFindMCMHeaderAndDisplay(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator mStartParse); + void OutputIncomingData(); + void setParsingHisto(TH1F* parsingerrors, TList* parsingerrors2d) + { + mParsingErrors = parsingerrors; + mParsingErrors2d = parsingerrors2d; + } + void increment2dHist(int hist) + { + ((TH2F*)mParsingErrors2d->At(hist))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack * constants::NLAYER + mLayer); + } + + private: + int mState; + int mDataWordsParsed; // count of data wordsin data that have been parsed in current call to parse. + int mDigitsFound; // digits found in the data block, mostly used for debugging. + int mBufferLocation; + int mPaddingWordsCounter; + bool mSanityCheck{true}; + bool mDumpUnknownData{false}; // if the various sanity checks fail, bail out and dump the rest of the data, keeps stats. + bool mByteOrderFix{false}; // simulated data is not byteswapped, real is, so deal with it accodringly. + bool mReturnVector{true}; // whether we are returing a vector or the raw data buffer. + // yes this is terrible design but it works, + int mReturnVectorPos; + + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* mData = nullptr; // compressed data return space. + std::vector<Digit> mDigits; // outgoing parsed digits + // subtle point, mDigits is not cleared between parsings,only between events. + // this means that successive calls to Parse simply appends the new digits onto the vector. + // at the end of the event the calling object must pull/copy the vector and clear or clear on next parse. + // + uint64_t mWordsDumped{0}; // words rejected for various reasons. + DigitHCHeader mDigitHCHeader; + DigitMCMHeader* mDigitMCMHeader; + DigitMCMADCMask* mDigitMCMADCMask; + uint32_t mADCMask; + DigitMCMData* mDigitMCMData; + EventRecord* mEventRecord; + bool mVerbose{false}; + bool mHeaderVerbose{false}; + bool mDataVerbose{false}; + bool mvVerbose{false}; + std::bitset<16> mOptions; + bool mIgnoreDigitHCHeader{false}; // whether to ignore the contents of the half chamber header and take the rdh/cru header as authoritative + + uint16_t mDetector; + uint16_t mMCM; + uint16_t mROB; + uint16_t mCurrentADCChannel; + uint16_t mDigitWordCount; + uint16_t mStack; + uint16_t mLayer; + uint16_t mSector; + uint16_t mSide; + + uint16_t mEventCounter; + TRDFeeID mFEEID; + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator mStartParse, mEndParse; // limits of parsing, effectively the link limits to parse on. + std::array<uint16_t, constants::TIMEBINS> mADCValues{}; + std::array<uint16_t, constants::MAXMCMCOUNT> mMCMstats; // bit pattern for errors current event for a given mcm; + TH1F* mParsingErrors; + TList* mParsingErrors2d; +}; + +} // namespace o2::trd + +#endif // O2_TRD_DIGITSPARSER diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/EventRecord.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/EventRecord.h new file mode 100644 index 0000000000000..ab797076d3b26 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/EventRecord.h @@ -0,0 +1,127 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_EVENTRECORD_H +#define ALICEO2_TRD_EVENTRECORD_H + +#include <iosfwd> +#include "Rtypes.h" +#include "TH2F.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" +#include "FairLogger.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/RawDataStats.h" +#include "DataFormatsTRD/Digit.h" + +namespace o2::framework +{ +class ProcessingContext; +} + +namespace o2::trd +{ +class TriggerRecord; + +/// \class EventRecord +/// \brief Stores a TRD event +/// adapted from TriggerRecord + +class EventRecord +{ + using BCData = o2::InteractionRecord; + + public: + EventRecord() = default; + EventRecord(BCData& bunchcrossing) : mBCData(bunchcrossing) + { + mTracklets.reserve(30); + mDigits.reserve(20); + } + ~EventRecord() = default; + + void setBCData(const BCData& data) { mBCData = data; } + + const BCData& getBCData() const { return mBCData; } + BCData& getBCData() { return mBCData; } + + //Digit information + std::vector<Digit>& getDigits(); + void addDigits(Digit& digit); + void addDigits(std::vector<Digit>::iterator& start, std::vector<Digit>::iterator& end); + + //tracklet information + std::vector<Tracklet64>& getTracklets(); + void addTracklet(Tracklet64& tracklet); + void addTracklets(std::vector<Tracklet64>::iterator& start, std::vector<Tracklet64>::iterator& end); + void addTracklets(std::vector<Tracklet64>& tracklets); + void popTracklets(int popcount); + //void printStream(std::ostream& stream) const; + void sortByHCID(); + + bool operator==(const EventRecord& o) const + { + return mBCData == o.mBCData; //&& mDigits == o.mDigits && mTracklets == o.mTracklets ; + } + void clear() + { + mDigits.clear(); + mTracklets.clear(); + } + + private: + BCData mBCData; /// orbit and Bunch crossing data of the physics trigger + std::vector<Digit> mDigits{}; /// digit data, for this event + std::vector<Tracklet64> mTracklets{}; /// tracklet data, for this event + o2::trd::TRDDataCountersPerEvent mEventStats; +}; + +class EventStorage +{ + //store a timeframes events for later collating sending on as a message + public: + EventStorage() = default; + ~EventStorage() = default; + //storage of eventrecords + //a vector of eventrecords and the associated funationality to go with it. + void clear() { mEventRecords.clear(); } + void addDigits(InteractionRecord& ir, Digit& digit); + void addDigits(InteractionRecord& ir, std::vector<Digit>::iterator start, std::vector<Digit>::iterator end); + void addTracklet(InteractionRecord& ir, Tracklet64& tracklet); + void addTracklets(InteractionRecord& ir, std::vector<Tracklet64>& tracklets); + void addTracklets(InteractionRecord& ir, std::vector<Tracklet64>::iterator& start, std::vector<Tracklet64>::iterator& end); + void unpackData(std::vector<TriggerRecord>& triggers, std::vector<Tracklet64>& tracklets, std::vector<Digit>& digits); + void sendData(o2::framework::ProcessingContext& pc, bool displaytracklets = false); + EventRecord& getEventRecord(InteractionRecord& ir); + //this could replace by keeing a running total on addition TODO + void sumTrackletsDigitsTriggers(uint64_t& tracklets, uint64_t& digits, uint64_t& triggers); + int sumTracklets(); + int sumDigits(); + std::vector<Tracklet64>& getTracklets(InteractionRecord& ir); + std::vector<Digit>& getDigits(InteractionRecord& ir); + void printIR(); + void setHisto(TH1F* packagetime) { mPackagingTime = packagetime; } + //TODO what would be nice is to write this out as a root tree event by event instead of using the sendData method where its all packaged together to then be unpackaged again. + TRDDataCountersPerTimeFrame mTFStats; + + private: + std::vector<EventRecord> mEventRecords; + //these 2 are hacks to be able to send bak a blank vector if interaction record is not found. + std::vector<Tracklet64> mDummyTracklets; + std::vector<Digit> mDummyDigits; + TH1F* mPackagingTime{nullptr}; +}; + +std::ostream& operator<<(std::ostream& stream, const EventRecord& trg); + +} // namespace o2::trd + +#endif diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/TrackletsParser.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/TrackletsParser.h new file mode 100644 index 0000000000000..cc2a356b813f7 --- /dev/null +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/TrackletsParser.h @@ -0,0 +1,128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackletsParser.h +/// @author Sean Murray +/// @brief TRD parse tracklet o2 payoload and build tracklets. + +#ifndef O2_TRD_TRACKLETPARSER +#define O2_TRD_TRACKLETPARSER + +#include <fstream> +#include <vector> +#include <bitset> + +#include "TH1F.h" +#include "TH2F.h" +#include "TList.h" + +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" + +namespace o2::trd +{ +class EventRecord; + +class TrackletsParser +{ + public: + TrackletsParser() = default; + ~TrackletsParser() = default; + void setData(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data) { mData = data; } + int Parse(); // presupposes you have set everything up already. + int Parse(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data, std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator start, std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator end, TRDFeeID feeid, int robside, + int detector, int stack, int layer, EventRecord* eventrecords, std::bitset<16> option, bool cleardigits = false, + int usetracklethcheader = 0); + void setVerbose(bool verbose, bool header = false, bool data = false) + { + mVerbose = verbose; + mHeaderVerbose = header; + mDataVerbose = data; + } + void setByteSwap(bool swap) { mByteOrderFix = swap; } + int getDataWordsRead() { return mWordsRead; } + int getDataWordsDumped() { return mWordsDumped; } + int getTrackletsFound() { return mTrackletsFound; } + void setIgnoreTrackletHCHeader(bool ignore) { mIgnoreTrackletHCHeader = ignore; } + bool getIgnoreTrackletHCHeader() { return mIgnoreTrackletHCHeader; } + enum TrackletParserState { StateTrackletHCHeader, // always the start of a half chamber. + StateTrackletMCMHeader, + StateTrackletMCMData, + StatePadding, + StateTrackletEndMarker, + StateFinished }; + std::vector<Tracklet64>& getTracklets() { return mTracklets; } + inline void swapByteOrder(unsigned int& ui); + bool getTrackletParsingState() { return mTrackletParsingBad; } + void clear() + { + mTracklets.clear(); + } + void OutputIncomingData(); + void setErrorHistos(TH1F* parsingerrors, TList* parsingerrors2d) + { + mParsingErrors = parsingerrors; + mParsingErrors2d = parsingerrors2d; + } + void increment2dHist(int hist) + { + ((TH2F*)mParsingErrors2d->At(hist))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack * constants::NLAYER + mLayer); + } + + private: + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* mData; + std::vector<Tracklet64> mTracklets; + // pointers to keep track of the currently parsing headers and data. + TrackletHCHeader* mTrackletHCHeader; + TrackletMCMHeader* mTrackletMCMHeader; + TrackletMCMData* mTrackletMCMData; + + int mState; // state that the parser is currently in. + int mWordsRead{0}; // number of words read from buffer + uint64_t mWordsDumped{0}; // number of words ignored from buffer + int mTrackletsFound; // tracklets found in the data block, mostly used for debugging. + int mPaddingWordsCounter; // count of padding words encoutnered + Tracklet64 mCurrentTrack; // the current track we are looking at, used to accumulate the possibly 3 tracks from the parsing 4 incoming data words + bool mVerbose{false}; // user verbose output, put debug statement in output from commandline. + bool mHeaderVerbose{false}; + bool mDataVerbose{false}; + int mTrackletHCHeaderState{0}; //what to with the tracklet half chamber header 0,1,2 + bool mIgnoreTrackletHCHeader{false}; // Is the data with out the tracklet HC Header? defaults to having it in. + bool mByteOrderFix{false}; // simulated data is not byteswapped, real is, so deal with it accodringly. + std::bitset<16> mOptions; + bool mTrackletParsingBad{false}; // store weather we should dump the rest of the link buffer after working through this tracklet buffer. + uint16_t mEventCounter; + std::chrono::duration<double> mTrackletparsetime; // store the time it takes to parse + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator mStartParse, mEndParse; // limits of parsing, effectively the link limits to parse on. + //uint32_t mCurrentLinkDataPosition256; // count of data read for current link in units of 256 bits + EventRecord* mEventRecord; + + uint16_t mCurrentLink; // current link within the halfcru we are parsing 0-14 + uint16_t mCRUEndpoint; // the upper or lower half of the currently parsed cru 0-14 or 15-29 + uint16_t mCRUID; + uint16_t mHCID; + uint16_t mDetector; + uint16_t mRobSide; + uint16_t mStack; + uint16_t mLayer; + TRDFeeID mFEEID; // current Fee ID working on + uint16_t mMCM; + uint16_t mROB; + // std::array<uint32_t, 16> mAverageNumTrackletsPerTrap; TODO come back to this stat. + TH1F* mParsingErrors; + TList* mParsingErrors2d; +}; + +} // namespace o2::trd + +#endif // O2_TRD_TRACKLETPARSER diff --git a/Detectors/TRD/reconstruction/src/CTFCoder.cxx b/Detectors/TRD/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..99f8d0109ff78 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of TRD data + +#include "TRDReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::trd; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<TriggerRecord>& trigVec, std::vector<Tracklet64>& trkVec, std::vector<Digit>& digVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, trigVec, trkVec, digVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcInc, HCIDTrk, posTrk, CIDDig, ADCDig; + uint32_t orbitInc, entriesTrk, entriesDig, pidTrk; + uint8_t padrowTrk, colTrk, slopeTrk, ROBDig, MCMDig, chanDig; + +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcInc, CTF::BLC_bcIncTrig); + MAKECODER(orbitInc, CTF::BLC_orbitIncTrig); + MAKECODER(entriesTrk, CTF::BLC_entriesTrk); + MAKECODER(entriesDig, CTF::BLC_entriesDig); + + MAKECODER(HCIDTrk, CTF::BLC_HCIDTrk); + MAKECODER(padrowTrk, CTF::BLC_padrowTrk); + MAKECODER(colTrk, CTF::BLC_colTrk); + MAKECODER(posTrk, CTF::BLC_posTrk); + MAKECODER(slopeTrk, CTF::BLC_slopeTrk); + MAKECODER(pidTrk, CTF::BLC_pidTrk); + + MAKECODER(CIDDig, CTF::BLC_CIDDig); + MAKECODER(ROBDig, CTF::BLC_ROBDig); + MAKECODER(MCMDig, CTF::BLC_MCMDig); + MAKECODER(chanDig, CTF::BLC_chanDig); + MAKECODER(ADCDig, CTF::BLC_ADCDig); + // clang-format on +} diff --git a/Detectors/TRD/reconstruction/src/CTFHelper.cxx b/Detectors/TRD/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..e5055694834ab --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for TRD CTF creation + +#include "TRDReconstruction/CTFHelper.h" diff --git a/Detectors/TRD/reconstruction/src/CompressedRawReader.cxx b/Detectors/TRD/reconstruction/src/CompressedRawReader.cxx new file mode 100644 index 0000000000000..23b3fdb21817d --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CompressedRawReader.cxx @@ -0,0 +1,216 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CompressedRawReader.h +/// @brief TRD raw data translator + +#include "TRDReconstruction/CompressedRawReader.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CompressedHeader.h" +#include "DataFormatsTRD/CompressedDigit.h" +#include "DataFormatsTRD/Constants.h" +#include "DetectorsRaw/RDHUtils.h" +//#include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" + +#include <cstring> +#include <string> +#include <vector> +#include <array> +#include <iostream> +#include <numeric> + +namespace o2::trd +{ + +uint32_t CompressedRawReader::processHBFs() +{ + + LOG(debug) << "PROCESS HBF starting at " << (void*)mDataPointer; + + mDataRDH = reinterpret_cast<const o2::header::RDHAny*>(mDataPointer); + //mEncoderRDH = reinterpret_cast<o2::header::RDHAny*>(mEncoderPointer); + auto rdh = mDataRDH; + /* loop until RDH stop header */ + while (!o2::raw::RDHUtils::getStop(rdh)) { // carry on till the end of the event. + auto headerSize = o2::raw::RDHUtils::getHeaderSize(rdh); + auto memorySize = o2::raw::RDHUtils::getMemorySize(rdh); + auto offsetToNext = o2::raw::RDHUtils::getOffsetToNext(rdh); + auto dataPayload = memorySize - headerSize; + mFEEID = o2::raw::RDHUtils::getFEEID(rdh); //TODO change this and just carry around the curreht RDH + mCRUEndpoint = o2::raw::RDHUtils::getEndPointID(rdh); // the upper or lower half of the currently parsed cru 0-14 or 15-29 + mCRUID = o2::raw::RDHUtils::getCRUID(rdh); + int packetCount = o2::raw::RDHUtils::getPacketCounter(rdh); + if (mHeaderVerbose) { + LOG(info) << "--- RDH open/continue detected"; + LOG(info) << "FEEID : " << mFEEID << " Packet: " << packetCount << " sizes : header" << headerSize << " memorysize:" << memorySize << " offsettonext:" << offsetToNext << " datapayload:" << dataPayload; + o2::raw::RDHUtils::printRDH(rdh); + } + /* copy CRU payload to save buffer */ + // std::memcpy(mSaveBuffer + mSaveBufferDataSize, (char*)(rdh) + headerSize, drmPayload); + // mSaveBufferDataSize += drmPayload; + // + // we will "simply" parse on the fly with a basic state machine. + mDataPointer = (uint32_t*)((char*)rdh + headerSize); + mDataEndPointer = (const uint32_t*)((char*)rdh + offsetToNext); + mIR = o2::raw::RDHUtils::getTriggerIR(rdh); + while ((void*)mDataPointer < (void*)mDataEndPointer) { // loop to handle the case where a halfcru ends/begins mid rdh data block + mEventCounter++; + if (processBlock()) { // at this point the entire payload is in mSaveBuffer, TODO parse this incrementally, less mem foot print. + LOG(warn) << "processBlock return flase"; + if (mVerbose) { + LOG(info) << "processBlock return flase"; + } + break; // end of CRU + } + //buildCRUPayLoad(); // the rest of the hbf for the subsequent cruhalfchamber payload. + // TODO is this even possible if hbfs upto the stop is for one event and each cru header is for 1 event? + } + /* move to next RDH */ + rdh = (o2::header::RDHAny*)((char*)(rdh) + offsetToNext); + if (mVerbose) { + LOG(info) << " rdh is now at 0x" << (void*)rdh << " offset to next : " << offsetToNext; + } + } + + if (o2::raw::RDHUtils::getStop(rdh)) { + if (mDataPointer != (const uint32_t*)((char*)rdh + o2::raw::RDHUtils::getOffsetToNext(rdh))) { + LOG(warn) << " at end of parsing loop and mDataPointer is on next rdh"; + } + mDataPointer = (const uint32_t*)((char*)rdh + o2::raw::RDHUtils::getOffsetToNext(rdh)); + // make sure mDataPointer is in the correct place. + } else { + mDataPointer = (const uint32_t*)((char*)rdh); + } + if (mVerbose) { + LOGF(debug, " at exiting processHBF after advancing to next rdh mDataPointer is %p ?= %p", (void*)mDataPointer, (void*)mDataEndPointer); + } + o2::raw::RDHUtils::printRDH(rdh); + + if (mVerbose) { + LOG(info) << "--- RDH close detected"; + LOG(info) << "--- END PROCESS HBF"; + } + /* move to next RDH */ + // mDataPointer = (uint32_t*)((char*)(rdh) + o2::raw::RDHUtils::getOffsetToNext(rdh)); + + /* otherwise return */ + + return mDataEndPointer - mDataPointer; +} + +bool CompressedRawReader::processBlock() +{ + /* process a FeeID/halfcru, 15 links */ + // LOG(debug) << "--- PROCESS BLOCK FeeID:" << mFEEID; + mCurrentLinkDataPosition = 0; + + if (mVerbose) { + LOG(info) << "--- END PROCESS HalfCRU with state: " << mState; + } + //this is essentially the inverse function of CruCompressorTask::buildOutput + //tracklet headers. + CompressedRawHeader header; + memcpy((char*)&header, &mDataBuffer, sizeof(CompressedRawHeader)); + mDataPointer += sizeof(CompressedRawHeader); //bytes + mDataReadIn += sizeof(CompressedRawHeader); + //tracklets + int numberoftracklets = header.size; + o2::InteractionRecord ir(header.bc, header.orbit); + Tracklet64* trackletptr = (Tracklet64*)mDataPointer; //payload is supposed to be a block of tracklet64 objects. + std::copy(trackletptr, trackletptr + numberoftracklets, std::back_inserter(mEventTracklets)); + mDataPointer += numberoftracklets * sizeof(Tracklet64); //bytes + mDataReadIn += numberoftracklets * sizeof(Tracklet64); + + //digits headers. + CompressedRawTrackletDigitSeperator tracklettrailer; + memcpy((char*)&tracklettrailer, &mDataBuffer, sizeof(CompressedRawTrackletDigitSeperator)); + mDataBuffer += sizeof(CompressedRawTrackletDigitSeperator); + mDataReadIn += sizeof(CompressedRawTrackletDigitSeperator); + + //digits + int numberofdigits = tracklettrailer.digitcount; + if (mHeaderVerbose || mVerbose) { //sanity check + bool badheader = false; + //check compressedrawtrackletdigitseperator for the pre and postfix 0xe's + if ((tracklettrailer.pad1 & 0xffffff) == 0xeeeeee) { + badheader = true; + } + if ((tracklettrailer.pad2 & 0xffffff) == 0xeeeeee) { + badheader = true; + } + if (badheader) { + LOG(info) << "Bad compressed raw header seperator digitsize :" << tracklettrailer.digitcount << " padding1 : " << std::hex << tracklettrailer.pad1 << " padding2:" << std::hex << tracklettrailer.pad2; + } + if (tracklettrailer.digitcount > 1000) { // TODO probably a better value, but this isfine for now, its for a single half cru count of digits + LOG(info) << "Digit count seems unusually high : " << tracklettrailer.digitcount; + } + } + + CompressedDigit* digitptr = (CompressedDigit*)mDataPointer; + std::copy(digitptr, digitptr + numberofdigits, std::back_inserter(mCompressedEventDigits)); + mDataPointer += numberofdigits + sizeof(CompressedDigit); + mDataReadIn += numberofdigits + sizeof(CompressedDigit); + //convert compresed digits to proper digits TODO put this in a copy operator of Compressed Digit class. + for (int digitcounter = 0; digitcounter < numberofdigits; ++digitcounter) { + ArrayADC timebins; + //TODO This already pre supposes o2::trd::constants::TIMEBINS is 30 from other places, figure something out. + for (int adc = 0; adc < o2::trd::constants::TIMEBINS; adc++) { + timebins[adc] = mCompressedEventDigits[digitcounter][adc]; + } + mEventDigits.emplace_back(mCompressedEventDigits[digitcounter].getDetector(), mCompressedEventDigits[digitcounter].getROB(), + mCompressedEventDigits[digitcounter].getMCM(), mCompressedEventDigits[digitcounter].getChannel(), timebins); + } + // now we *should* have a CompressedRawDigitEndMarker or more commonly known as a lot of 0xe + if ((uint32_t)*mDataPointer != 0xeeeeeeee) { + LOG(warn) << std::hex << *mDataPointer << " We should be seeing CompressedRawDigitEndMarker which is the same as a o2::trd::constants::CRUPADDING32"; + } + mDataPointer += 4; + mDataReadIn += 4; + if (mDataReadIn % 8 != 0) { + // we have an extra padding word to make it to a full 64bit data buffer. + if ((uint32_t)*mDataPointer != 0xeeeeeeee) { + LOG(warn) << std::hex << *mDataPointer << " We should be seeing CompressedRawDigitEndMarker which is the same as a o2::trd::constants::CRUPADDING32"; + } + mDataPointer += 4; + mDataReadIn += 4; + } + auto lasttrigger = mEventTriggers.size() - 1; + int lastdigit = mEventTriggers[lasttrigger].getFirstDigit() + mEventTriggers[lasttrigger].getNumberOfDigits(); + int lasttracklet = mEventTriggers[lasttrigger].getFirstTracklet() + mEventTriggers[lasttrigger].getNumberOfTracklets(); + mEventTriggers.emplace_back(mIR, lastdigit, numberofdigits, lasttracklet, numberoftracklets); + + // either 1 or more depending on padding requirements. + if (mVerbose) { + LOG(info) << "Tracklets in block : " << numberoftracklets << " vector has size:" << mEventTracklets.size(); + LOG(info) << "Digits in block : " << numberofdigits << " vector has size:" << mEventDigits.size(); + } + return true; +} + +void CompressedRawReader::resetCounters() +{ + mEventCounter = 0; + mFatalCounter = 0; + mErrorCounter = 0; +} + +void CompressedRawReader::checkSummary() +{ + char chname[2] = {'a', 'b'}; + + LOG(info) << "--- SUMMARY COUNTERS: " << mEventCounter << " events " + << " | " << mFatalCounter << " decode fatals " + << " | " << mErrorCounter << " decode errors "; +} + +} // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/src/CruCompressor.cxx b/Detectors/TRD/reconstruction/src/CruCompressor.cxx new file mode 100644 index 0000000000000..85fd3baceb8f4 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CruCompressor.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file crucompressor.cxx +/// @author Sean Murray +/// @brief Basic DPL workflow for TRD CRU output(raw) to tracklet/digit data. +/// There may or may not be some compression in this at some point. + +#include "TRDReconstruction/CruCompressorTask.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/Logger.h" +#include "DetectorsRaw/RDHUtils.h" + +using namespace o2::framework; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + auto config = ConfigParamSpec{"trd-crucompressor-config", VariantType::String, "A:TRD/RAWDATA", {"TRD raw data config"}}; + auto outputDesc = ConfigParamSpec{"trd-crucompressor-output-desc", VariantType::String, "TRDTLT", {"Output specs description string"}}; + auto verbosity = ConfigParamSpec{"trd-crucompressor-verbose", VariantType::Bool, false, {"Enable verbose compressor"}}; + auto verboseheaders = ConfigParamSpec{"trd-crucompressor-hedaerverbose", VariantType::Bool, false, {"Enable header verbose compressor"}}; + auto verbosedata = ConfigParamSpec{"trd-crucompressor-dataverbose", VariantType::Bool, false, {"Enable data verbose compressor"}}; + + auto digithcheader = ConfigParamSpec{"trd-crucompressor-digitheader", VariantType::Bool, true, {"using digit half chamber headers"}}; + auto tracklethcheader = ConfigParamSpec{"trd-crucompressor-tracklethcheader", VariantType::Bool, true, {"using tracklet half chamber headers"}}; + auto trackletformat = ConfigParamSpec{"trd-crucompressor-trackletformat", VariantType::Int, 0, {"0: no pid scale factor, 1: pid scale factor"}}; + auto digitformat = ConfigParamSpec{"trd-crucompressor-digitformat", VariantType::Int, 1, {"0: zero supressed digits, 1: non zero suppressed digits "}}; + + workflowOptions.push_back(config); + workflowOptions.push_back(outputDesc); + workflowOptions.push_back(verbosity); + workflowOptions.push_back(verboseheaders); + workflowOptions.push_back(verbosedata); + workflowOptions.push_back(digithcheader); + workflowOptions.push_back(tracklethcheader); + workflowOptions.push_back(trackletformat); + workflowOptions.push_back(digitformat); +} + +#include "Framework/runDataProcessing.h" // the main driver + +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + auto config = cfgc.options().get<std::string>("trd-crucompressor-config"); + auto verbosity = cfgc.options().get<bool>("trd-crucompressor-verbose"); + std::vector<OutputSpec> outputs; + outputs.emplace_back(OutputSpec(ConcreteDataTypeMatcher{"TRD", "CDATA"})); + + AlgorithmSpec algoSpec; + algoSpec = AlgorithmSpec{adaptFromTask<o2::trd::CruCompressorTask>()}; + + WorkflowSpec workflow; + + /* + * This is originaly replicated from TOF + We define at run time the number of devices to be attached + to the workflow and the input matching string of the device. + This is is done with a configuration string like the following + one, where the input matching for each device is provide in + comma-separated strings. For instance + A:TRD/RAWDATA/785;B:TRF/RAWDATA/2560,C:TRD/RAWDATA/1280;D:TRD/RAWDATA/1536 + + will lead to a workflow with 2 devices which will input match + + trd-crucompressor-0 --> A:TRD/RAWDATA/768;B:TRD/RAWDATA/1024 + trd-crucompressor-1 --> C:TRD/RAWDATA/1280;D:TRD/RAWDATA/1536 + The number after the RAWDATA is the FeeID in decimal + */ + + std::stringstream ssconfig(config); + std::string iconfig; + int idevice = 0; + LOG(info) << " config string is : " << config; + LOG(info) << "for now ignoring the multiple processors, something going wrong"; + while (getline(ssconfig, iconfig, ',')) { // for now we will keep the possibilty to have a device per half cru/feeid i.e. 6 per flp + // this is probably never going to be used but would to nice to know hence here. + workflow.emplace_back(DataProcessorSpec{ + std::string("trd-crucompressor-") + std::to_string(idevice), + select(iconfig.c_str()), + outputs, + algoSpec, + Options{ + {"trd-crucompressor-verbose", VariantType::Bool, false, {"verbose flag"}}}}); + idevice++; + } + + return workflow; +} diff --git a/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx b/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx new file mode 100644 index 0000000000000..76467cb076df8 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx @@ -0,0 +1,186 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CruCompressorTask.cxx +/// @author Sean Murray +/// @brief TRD cru output to tracklet task + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Headers/RDHAny.h" + +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/CompressedHeader.h" + +#include "TRDReconstruction/CruCompressorTask.h" +#include "TRDReconstruction/CruRawReader.h" + +#include <fairmq/FairMQDevice.h> +#include <iostream> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +void CruCompressorTask::init(InitContext& ic) +{ + LOG(INFO) << "FLP Compressore Task init"; + + auto finishFunction = [this]() { + mReader.checkSummary(); + }; + + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishFunction); +} + +uint64_t CruCompressorTask::buildEventOutput() +{ + //mReader holds the vectors of tracklets and digits. + // tracklets are 64 bit + // digits are DigitMCMHeader and DigitMCMData + + uint64_t currentpos = 0; + uint64_t trailer = 0xeeeeeeeeeeeeeeeeLL; + //first we write a start rdh block + CompressedRawHeader* trackletheader = (CompressedRawHeader*)&mOutBuffer[0]; + trackletheader->format = 1; + trackletheader->eventtime = 99; + currentpos = 1; + //write the + std::vector<o2::trd::TriggerRecord> ir; + std::vector<o2::trd::Tracklet64> tracklets; + std::vector<o2::trd::Digit> digits; + mReader.getParsedObjects(tracklets, digits, ir); + trackletheader->bc = ir[0].getBCData().bc; + trackletheader->orbit = ir[0].getBCData().orbit; + trackletheader->padding = 0xeeee; + trackletheader->size = mReader.sumTrackletsFound() * 8; // to get to bytes. TODO compare to getTrackletsFound + for (auto tracklet : mReader.getTracklets(ir[0].getBCData())) { + //convert tracklet to 64 bit and add to blob + mOutBuffer[currentpos++] = tracklet.getTrackletWord(); + } + CompressedRawTrackletDigitSeperator* tracklettrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; + tracklettrailer->word = trailer; + currentpos++; + CompressedRawHeader* digitheader = (CompressedRawHeader*)&mOutBuffer[currentpos]; + currentpos++; + digitheader->format = 2; + digitheader->eventtime = 99; + + for (auto digit : mReader.getDigits(ir[0].getBCData())) { + uint64_t* word; + word = &mOutBuffer[currentpos]; + DigitMCMHeader mcmheader; + mcmheader.eventcount = 1; + mcmheader.mcm = digit.getMCM(); + mcmheader.rob = digit.getROB(); + mcmheader.yearflag = 1; + mcmheader.eventcount = 1; + mcmheader.res = 0xc; // formst is reservedto be 1100 binary + //unpack the digit. + mcmheader.word = (*word) >> 32; + currentpos++; + } + CompressedRawTrackletDigitSeperator* digittrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; + digittrailer->word = trailer; + currentpos++; + //as far as I can tell this is almost always going to be blank. + CompressedRawHeader* configheader = (CompressedRawHeader*)&mOutBuffer[currentpos]; + currentpos++; + configheader->size = 2; + configheader->format = 3; + configheader->eventtime = 99; + CompressedRawTrackletDigitSeperator* configtrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; + configtrailer->word = trailer; + //finally we write a stop rdh block + + return currentpos; +} + +void CruCompressorTask::run(ProcessingContext& pc) +{ + LOG(info) << "TRD Compression Task run method"; + + auto device = pc.services().get<o2::framework::RawDeviceService>().device(); + auto outputRoutes = pc.services().get<o2::framework::RawDeviceService>().spec().outputs; + auto fairMQChannel = outputRoutes.at(0).channel; + int inputcount = 0; + /* loop over inputs routes */ + for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { + if (!iit.isValid()) { + continue; + } + //LOG(info) << "iit.mInputs " << iit.mInputs. + /* prepare output parts */ + FairMQParts parts; + + /* loop over input parts */ + for (auto const& ref : iit) { + + auto headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + auto dataProcessingHeaderIn = DataRefUtils::getHeader<o2::framework::DataProcessingHeader*>(ref); + auto payloadIn = ref.payload; + auto payloadInSize = headerIn->payloadSize; + std::cout << "payload In is : " << std::hex << payloadIn << std::endl; + std::cout << "payload In is : " << std::dec << payloadIn << std::endl; + std::cout << "payload In size is : " << std::dec << payloadInSize << std::endl; + mReader.setDataBuffer(payloadIn); + mReader.setDataBufferSize(payloadInSize); + mReader.setVerbose(mVerbose); + mReader.setDataVerbose(mDataVerbose); + mReader.setHeaderVerbose(mHeaderVerbose); + /* run */ + mReader.run(); + + auto payloadOutSize = buildEventOutput(); + + auto payloadOutSizeBytes = payloadOutSize * 8; // payloadoutsize in bytes. + LOG(info) << "outgoing message has a data size of : " << payloadOutSize; + if (payloadOutSizeBytes > 32 * 1024) { + LOG(warn) << " buffer size for data is >32kB so will span rdh"; + } + int numberofpiecestocutinto = payloadOutSizeBytes / (32 * 1024); + int segmentsize = 32 * 1024 - 0x40; // 0x40 is the size of the rdh header in bytes. + //the above will drop the decimal due to int. + numberofpiecestocutinto++; + for (int datasegment = 0; datasegment < numberofpiecestocutinto; ++datasegment) { + auto payloadMessage = device->NewMessage(payloadOutSize); + std::memcpy(payloadMessage->GetData(), (char*)mOutBuffer.data() + datasegment * segmentsize, payloadOutSize); + /* output */ + auto headerOut = *headerIn; + auto dataProcessingHeaderOut = *dataProcessingHeaderIn; + headerOut.dataDescription = "CDATA"; + headerOut.payloadSize = payloadOutSizeBytes; + // what to do about the packet count? + //headerOut.packetCounter; + o2::header::Stack headerStack{headerOut, dataProcessingHeaderOut}; + auto headerMessage = device->NewMessage(headerStack.size()); + std::memcpy(headerMessage->GetData(), headerStack.data(), headerStack.size()); + + /* add parts */ + parts.AddPart(std::move(headerMessage)); + parts.AddPart(std::move(payloadMessage)); + } + } + + /* send message */ + device->Send(parts, fairMQChannel); + } +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/reconstruction/src/CruRawReader.cxx b/Detectors/TRD/reconstruction/src/CruRawReader.cxx new file mode 100644 index 0000000000000..8c62bff964a27 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/CruRawReader.cxx @@ -0,0 +1,717 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CruRawReader.h +/// @brief TRD raw data translator + +#include "DetectorsRaw/RDHUtils.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Headers/RDHAny.h" +#include "TRDReconstruction/CruRawReader.h" +#include "TRDBase/FeeParam.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "TRDReconstruction/DigitsParser.h" +#include "TRDReconstruction/TrackletsParser.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/HelperMethods.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Output.h" +#include "Framework/InputRecordWalker.h" + +#include <cstring> +#include <string> +#include <vector> +#include <array> +#include <iostream> +#include <numeric> +#include <iostream> + +namespace o2::trd +{ + +bool CruRawReader::skipRDH() +{ + // check rdh for being empty or only padding words. + if (o2::raw::RDHUtils::getMemorySize(mOpenRDH) == o2::raw::RDHUtils::getHeaderSize(mOpenRDH)) { + //empty rdh so we want to avoid parsing it for cru data. + LOG(info) << " skipping rdh (empty) with packetcounter of: " << std::hex << o2::raw::RDHUtils::getPacketCounter(mOpenRDH); + return true; + } else { + + if (mHBFPayload[0] == o2::trd::constants::CRUPADDING32 && mHBFPayload[0] == o2::trd::constants::CRUPADDING32) { + //event only contains paddings words. + LOG(info) << " skipping rdh (padding) with packetcounter of: " << std::hex << o2::raw::RDHUtils::getPacketCounter(mOpenRDH); + // mDataPointer+= o2::raw::RDHUtils::getOffsetToNext()/4; + auto rdh = reinterpret_cast<const o2::header::RDHAny*>(mDataPointer); + mDataPointer += o2::raw::RDHUtils::getOffsetToNext(rdh) / 4; + //mDataPointer=reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>(rdh) + o2::raw::RDHUtils::getOffsetToNext(rdh)); + return true; + return true; + } else { + return false; + } + } +} + +void CruRawReader::OutputHalfCruRawData() +{ + LOG(info) << "Full 1/2 CRU dump begin ************************** FEEID:0x" << std::hex << mFEEID.word; + for (int z = 0; z < 15; ++z) { + LOG(info) << "link " << z << " length : " << mCurrentHalfCRULinkLengths[z] << " (256bit rows)"; + } + int linkcount = 0; + uint64_t linkzsum = 0; + int bufferoffset = 0; + uint64_t totalhalfcrulength = std::accumulate(mCurrentHalfCRULinkLengths.begin(), + mCurrentHalfCRULinkLengths.end(), + decltype(mCurrentHalfCRULinkLengths)::value_type(0)); + totalhalfcrulength *= 8; //convert from 256 bits to 32 bits. + LOGP(info, "CRH bufferoffset:{0:06d} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ", bufferoffset, HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 1]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 2]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 3]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 4]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 5]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 6]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 7])); + bufferoffset += 8; + LOGP(info, "CRH bufferoffset:{0:06d} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ", bufferoffset, HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 1]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 2]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 3]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 4]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 5]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 6]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 7])); + int outputoffset = 2; + bufferoffset += 8; + int olengthoffset0 = 0; + while (olengthoffset0 < totalhalfcrulength) { + bufferoffset = olengthoffset0 + 16; + if (mCurrentHalfCRULinkLengths[linkcount] == 0) { + //output nothing, but state link empty + LOG(info) << "empty link link:" << linkcount; + linkcount++; + } else { + LOGP(info, "0x{0:06x} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ", olengthoffset0, HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 1]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 2]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 3]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 4]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 5]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 6]), HelperMethods::swapByteOrderreturn(mHBFPayload[bufferoffset + 7])); + olengthoffset0 += 8; // advance a whole cru word of 256 bits or 8 32 bit words + bufferoffset += 8; // advance a whole cru word of 256 bits or 8 32 bit words + if (olengthoffset0 == mCurrentHalfCRULinkLengths[linkcount] * 8 + linkzsum * 8) { + LOG(info) << "end of link :" << linkcount; + linkzsum += mCurrentHalfCRULinkLengths[linkcount]; + linkcount++; + } + } + } + LOG(info) << "CRU Next 16 words just for info"; + for (int bufferoffset = totalhalfcrulength; bufferoffset < totalhalfcrulength + 16; bufferoffset += 8) { + LOGP(info, "0x{0:06x} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ", bufferoffset, mHBFPayload[bufferoffset], mHBFPayload[bufferoffset + 1], mHBFPayload[bufferoffset + 2], mHBFPayload[bufferoffset + 3], mHBFPayload[bufferoffset + 4], mHBFPayload[bufferoffset + 5], mHBFPayload[bufferoffset + 6], mHBFPayload[bufferoffset + 7]); + } + LOG(info) << "Full 1/2 CRU dump end ***************"; +} + +bool CruRawReader::processHBFs(int datasizealreadyread, bool verbose) +{ + if (mVerbose) { + LOG(info) << "PROCESS HBF starting at " << std::hex << (void*)mDataPointer; + } + mDataRDH = reinterpret_cast<const o2::header::RDHAny*>(mDataPointer); + mOpenRDH = reinterpret_cast<o2::header::RDHAny*>((char*)mDataPointer); + auto rdh = mDataRDH; + auto preceedingrdh = rdh; + uint64_t totaldataread = 0; + mState = CRUStateHalfCRUHeader; + uint32_t currentsaveddatacount = 0; + mTotalHBFPayLoad = 0; + int loopcount = 0; + // loop until RDH stop header + while (!o2::raw::RDHUtils::getStop(rdh)) { // carry on till the end of the event. + //o2::raw::RDHUtils::printRDH(rdh); + if (mVerbose) { + LOG(info) << "--- RDH open/continue detected loopcount :" << loopcount; + LOG(info) << " rdh first word 0x" << std::hex << (uint32_t)*mDataPointer; + for (int i = 0; i < 64; ++i) { + LOG(info) << std::hex << " 0x" << *(mDataPointer + i); + } + LOG(info) << "---------------------- parsing that rdh"; + } + preceedingrdh = rdh; + auto headerSize = o2::raw::RDHUtils::getHeaderSize(rdh); + auto memorySize = o2::raw::RDHUtils::getMemorySize(rdh); + auto offsetToNext = o2::raw::RDHUtils::getOffsetToNext(rdh); + auto rdhpayload = memorySize - headerSize; + mFEEID.word = o2::raw::RDHUtils::getFEEID(rdh); //TODO change this and just carry around the curreht RDH + mCRUEndpoint = o2::raw::RDHUtils::getEndPointID(rdh); // the upper or lower half of the currently parsed cru 0-14 or 15-29 + mCRUID = o2::raw::RDHUtils::getCRUID(rdh); + mIR = o2::raw::RDHUtils::getTriggerIR(rdh); + auto packetCount = o2::raw::RDHUtils::getPacketCounter(rdh); + mDataEndPointer = (const uint32_t*)((char*)rdh + offsetToNext); + // copy the contents of the current rdh into the buffer to be parsed + std::memcpy((char*)&mHBFPayload[0] + currentsaveddatacount, reinterpret_cast<const char*>(rdh) + headerSize, rdhpayload); + mTotalHBFPayLoad += rdhpayload; + currentsaveddatacount += rdhpayload; + totaldataread += offsetToNext; + // move to next rdh + rdh = reinterpret_cast<const o2::header::RDHAny*>(reinterpret_cast<const char*>(rdh) + offsetToNext); + if ((char*)(rdh) < (char*)&mHBFPayload[0] + mDataBufferSize) { + //if (reinterpret_cast<const o2::header::RDHAny*>(rdh) < (char*)&mHBFPayload[0] + mDataBufferSize) { + // we can still copy into this buffer. + } else { + LOG(warn) << "next rdh exceeds the bounds of the cru payload buffer"; + if (mVerbose) { + LOG(info) << "rdh position is out of bounds of the buffer"; + o2::raw::RDHUtils::printRDH(rdh); + } + return false; //-1; + } + } + //increment the data pointer by the size of the stop rdh. + mDataPointer = reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>(rdh) + o2::raw::RDHUtils::getOffsetToNext(rdh)); + // at this point the entire HBF data payload is sitting in mHBFPayload and the total data count is mTotalHBFPayLoad + int counthalfcru = 0; + mHBFoffset32 = 0; + + while ((mHBFoffset32 < ((mTotalHBFPayLoad) / 4))) { // the blank event of eeeeee at the end + if (mHeaderVerbose) { + LOG(info) << "Looping over cruheaders in HBF, loop count " << counthalfcru << " current offset is" << mHBFoffset32 << " total payload is " << mTotalHBFPayLoad / 4 << " raw :" << mTotalHBFPayLoad; + } + int halfcruprocess = processHalfCRU(mHBFoffset32); + if (mVerbose) { + switch (halfcruprocess) { + case -1: + LOG(info) << "ignored rdh event "; + break; + case 0: + LOG(fatal) << "figure out what now"; + break; + case 1: + LOG(info) << "all good parsing half cru"; + break; + default: + return true; + } + } + //take care of the case where there is an "empty" rdh containing all 0xeeeeeeee as payload. + if (mTotalHBFPayLoad / 4 - mHBFoffset32 == 8 && mHBFPayload[mHBFoffset32 + 7] == o2::trd::constants::CRUPADDING32) { + mHBFoffset32 += 8; + } + counthalfcru++; + if (counthalfcru == 1) { + break; + } + } // loop of halfcru's while there is still data in the heart beat frame. + if (totaldataread > 0) { + mDatareadfromhbf = totaldataread; + } + return true; //totaldataread; +} + +int CruRawReader::checkTrackletHCHeader() +{ + // index 0 is rdh data, index 1 is ori calculated data + auto currentsector = mTrackletHCHeader.supermodule; + auto currentlayer = mTrackletHCHeader.layer; + auto currentstack = mTrackletHCHeader.stack; + auto currentside = mTrackletHCHeader.side; + if (!mOptions[TRDIgnoreTrackletHCHeaderBit]) { // we take half chamber header as authoritive + return 0; + } + return 0; // for now always ignore, something is wrong with it, yet to be determined, tdp and header dont match. FIXME! +} + +int CruRawReader::checkDigitHCHeader() +{ + // index 0 is rdh data, index 1 is ori calculated data + auto currentsector = mDigitHCHeader.supermodule; + auto currentlayer = mDigitHCHeader.layer; + auto currentstack = mDigitHCHeader.stack; + auto currentside = mDigitHCHeader.side; + //check rdh info vs half chamber header + if (!mOptions[TRDIgnoreDigitHCHeaderBit]) { // we take half chamber header as authoritive + // can use digithcheader for cross checking the sector/stack/layer + if (currentstack != mStack[0] || currentstack != mStack[1]) { + //stack mismatch + //count these + //mEventRecord.ErrorStats[TRDParsingDigitStackMismatch]++; + if (mRootOutput) { + mParsingErrors->Fill(TRDParsingDigitStackMismatch); + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitStackMismatch))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + if (currentlayer != mLayer[0] || currentlayer != mLayer[1]) { + //layer mismatch + //count these + //mEventRecord.ErrorStats[TRDParsingDigitLayerMisMatch]++; + if (mRootOutput) { + mParsingErrors->Fill(TRDParsingDigitLayerMismatch); + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitLayerMismatch))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + if (currentsector != mSector[0] || currentsector != mSector[1]) { + //sector mismatch, mDetector comes in from a construction via the feeid and ori. + //count these + //mEventRecord.ErrorStats[TRDParsingDigitSectorMisMatch]++; + if (mRootOutput) { + mParsingErrors->Fill(TRDParsingDigitSectorMismatch); + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitSectorMismatch))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + mSector[2] = currentsector; //from hc header treating it as authoritative + mDetector[2] = mSector[2] * 2 + mDigitHCHeader.side; + mLayer[2] = currentlayer; + mSector[2] = currentsector; + return 2; + } else { // ignore the halfcahmber headers contents so use the rdh + //take mDetector, layer and stack from the rdh/cru, we have those already assigned on entry to here + return 0; // the index in mSector/mStack etc. + } +} + +int CruRawReader::parseDigitHCHeader() +{ + //mHBFoffset is the current offset into the current buffer, + // + uint32_t dhcheader = mHBFPayload[mHBFoffset32++]; + std::array<uint32_t, 4> headers{0}; + if (mByteSwap) { + // byte swap if needed. + o2::trd::HelperMethods::swapByteOrder(dhcheader); + } + mDigitHCHeader.word = dhcheader; + if (mDigitHCHeader.major == 0 && mDigitHCHeader.minor == 0 && mDigitHCHeader.numberHCW == 0) { + //hack this data into something resembling usable. + mDigitHCHeader.major = mHalfChamberMajor; + mDigitHCHeader.minor = 42; // to keep me entertained + mDigitHCHeader.numberHCW = mHalfChamberWords; + if (mHalfChamberWords == 0 || mHalfChamberMajor == 0) { + //LOG(warn) << "we have a messed up halfchamber header and you have only set the halfchamber command line option to zero, hex dump of data and revisit what it should be."; + // already in histograms + } + } + + int additionalHeaderWords = mDigitHCHeader.numberHCW; + if (additionalHeaderWords >= 3) { + //LOG(error) << "Error parsing DigitHCHeader, too many additional words count=" << additionalHeaderWords; + if (mRootOutput) { + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitHeaderCountGT3))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + //TODO graph this and stats it + printDigitHCHeader(mDigitHCHeader, &headers[0]); + return -1; + } + for (int headerwordcount = 0; headerwordcount < additionalHeaderWords; ++headerwordcount) { + headers[headerwordcount] = mHBFPayload[mHBFoffset32++]; + if (mByteSwap) { + // byte swap if needed. + o2::trd::HelperMethods::swapByteOrder(headers[headerwordcount]); + } + switch (getDigitHCHeaderWordType(headers[headerwordcount])) { + case 1: // header header1; + mDigitHCHeader1.word = headers[headerwordcount]; + if (mDigitHCHeader1.res != 0x1) { + //LOG(error) << "Digit HC Header 1 reserved : " << std::hex << mDigitHCHeader1.res << " raw: 0x" << mDigitHCHeader1.word; + if (mRootOutput) { + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitHeaderWrong1))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + break; + case 2: // header header2; + mDigitHCHeader2.word = headers[headerwordcount]; + if (mDigitHCHeader2.res != 0b110001) { + // LOG(error) << "Digit HC Header 2 reserved : " << std::hex << mDigitHCHeader2.res << " raw: 0x" << mDigitHCHeader2.word; + if (mRootOutput) { + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitHeaderWrong2))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + break; + case 3: // header header3; + mDigitHCHeader3.word = headers[headerwordcount]; + if (mDigitHCHeader3.res != 0b110101) { + // LOG(error) << "Digit HC Header 3 reserved : " << std::hex << mDigitHCHeader3.res << " raw: 0x" << mDigitHCHeader3.word; + if (mRootOutput) { + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitHeaderWrong3))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + break; + default: + //LOG(error) << "Error parsing DigitHCHeader at word:" << headerwordcount << " looking at 0x:" << std::hex << mHBFPayload[mHBFoffset32 - 1]; + if (mRootOutput) { + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitHeaderWrong4))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + } + if (mHeaderVerbose) { + printDigitHCHeader(mDigitHCHeader, &headers[0]); + } + return 1; +} + +int CruRawReader::processHalfCRU(int cruhbfstartoffset) +{ + //It will clean this code up *alot* + // process a halfcru + uint32_t currentlinkindex = 0; + uint32_t currentlinkoffset = 0; + uint32_t currentlinksize = 0; + uint32_t currentlinksize32 = 0; + uint32_t linksizeAccum32 = 0; + uint32_t sumtrackletwords = 0; + uint32_t sumdigitwords = 0; + uint32_t sumlinklengths = 0; + mDigitWordsRead = 0; + mDigitWordsRejected = 0; + mTrackletWordsRead = 0; + mTrackletWordsRejected = 0; + uint32_t cruwordsread = 9; + //reject halfcru if it starts with padding words. + //this should only hit that instance where the cru payload is a "blank event" of o2::trd::constants::CRUPADDING32 + if (mHBFPayload[cruhbfstartoffset] == o2::trd::constants::CRUPADDING32 && mHBFPayload[cruhbfstartoffset + 1] == o2::trd::constants::CRUPADDING32) { + if (mVerbose) { + LOG(info) << "blank rdh payload"; + } + return -1; + } + if (mTotalHBFPayLoad == 0) { + //empty payload + return -1; + } + auto crustart = std::chrono::high_resolution_clock::now(); + // well then read the halfcruheader. + memcpy((char*)&mCurrentHalfCRUHeader, (void*)(&mHBFPayload[cruhbfstartoffset]), sizeof(mCurrentHalfCRUHeader)); //TODO remove the copy just use pointer dereferencing, doubt it will improve the speed much though. + + o2::trd::getlinkdatasizes(mCurrentHalfCRUHeader, mCurrentHalfCRULinkLengths); + o2::trd::getlinkerrorflags(mCurrentHalfCRUHeader, mCurrentHalfCRULinkErrorFlags); + mTotalHalfCRUDataLength256 = std::accumulate(mCurrentHalfCRULinkLengths.begin(), + mCurrentHalfCRULinkLengths.end(), + decltype(mCurrentHalfCRULinkLengths)::value_type(0)); + mTotalHalfCRUDataLength = mTotalHalfCRUDataLength256 * 32; //convert to bytes. + int mTotalHalfCRUDataLength32 = mTotalHalfCRUDataLength256 * 8; //convert to bytes. + //check for cru errors : + // if (mHeaderVerbose) { + int linkerrorcounter = 0; + for (auto& linkerror : mCurrentHalfCRULinkErrorFlags) { + if (linkerror != 0) { + if (mHeaderVerbose) { + LOG(info) << "E link error FEEID:" << mFEEID.word << " CRUID:" << mCRUID << " Endpoint:" << mCRUEndpoint + << " on linkcount:" << linkerrorcounter++ << " errorval:0x" << std::hex << linkerror; + } + } + } + + std::array<uint32_t, 1024>::iterator currentlinkstart = mHBFPayload.begin() + cruhbfstartoffset; + if (mHeaderVerbose) { + OutputHalfCruRawData(); + } + std::array<uint32_t, 1024>::iterator linkstart, linkend; + int dataoffsetstart32 = sizeof(mCurrentHalfCRUHeader) / 4 + cruhbfstartoffset; // in uint32 + //CHECK 1 does rdh endpoint match cru header end point. + if (mCRUEndpoint != mCurrentHalfCRUHeader.EndPoint) { + LOG(warn) << " Endpoint mismatch : CRU Half chamber header endpoint = " << mCurrentHalfCRUHeader.EndPoint << " rdh end point = " << mCRUEndpoint; + //disaster dump the rest of this hbf + return 42; + if (mVerbose) { + LOG(info) << "******* LINK # " << currentlinkindex; + } + } + + // verify cru header vs rdh header + //FEEID has supermodule/layer/stack/side in it. + //CRU has + mHBFoffset32 += sizeof(mCurrentHalfCRUHeader) / 4; + + //get eventrecord for event we are looking at + mIR.bc = mCurrentHalfCRUHeader.BunchCrossing; // correct mIR to have the physics trigger bunchcrossing *NOT* the heartbeat trigger bunch crossing. + InteractionRecord trdir(mIR); + mCurrentEvent = &mEventRecords.getEventRecord(trdir); + + linkstart = mHBFPayload.begin() + dataoffsetstart32; + linkend = mHBFPayload.begin() + dataoffsetstart32; + //loop over links + for (currentlinkindex = 0; currentlinkindex < constants::NLINKSPERHALFCRU; currentlinkindex++) { + auto linktimerstart = std::chrono::high_resolution_clock::now(); // measure total processing time + mSector[0] = mFEEID.supermodule; + mEndPoint[0] = mFEEID.endpoint; + mSide[0] = mFEEID.side; // side of detector A/C + int hbfoffsetatstartoflink = mHBFoffset32; + //stack layer and side map to ori + int oriindex = currentlinkindex + constants::NLINKSPERHALFCRU * mEndPoint[0]; // endpoint denotes the pci side, upper or lower for the pair of 15 fibres. + FeeParam::unpackORI(oriindex, mSide[0], mStack[1], mLayer[1], mHalfChamberSide[1]); + //sadly not al the data is redundant, probably a good thing, so stack and layer and halfchamber side is derived from the ori. + mLayer[0] = mLayer[1]; + mStack[0] = mStack[1]; + mHalfChamberSide[0] = mHalfChamberSide[1]; + mSector[1] = oriindex / 30; + mSide[1] = mSide[0]; + mDetector[0] = mStack[0] * constants::NLAYER + mLayer[0] + mSector[0] * constants::NLAYER * constants::NSTACK; + mDetector[1] = mStack[1] * constants::NLAYER + mLayer[1] + mSector[1] * constants::NLAYER * constants::NSTACK; + int supermodule_half = mSector[0] * 2 + mHalfChamberSide[0]; // will just go with the rdh one here its only for the hack graphing purposes. + float stack_layer; + stack_layer = mStack[0] * constants::NLAYER + mLayer[0]; // similarly this is also only for graphing so just use the rdh ones for now. + if (mRootOutput) { + if (mCurrentHalfCRULinkErrorFlags[currentlinkindex] == 0) { + ((TH2F*)mLinkErrors->At(0))->Fill(supermodule_half, stack_layer); + } + if (mCurrentHalfCRULinkErrorFlags[currentlinkindex] == 1) { + ((TH2F*)mLinkErrors->At(1))->Fill(supermodule_half, stack_layer); + } + if (mCurrentHalfCRULinkErrorFlags[currentlinkindex] == 2) { + ((TH2F*)mLinkErrors->At(2))->Fill(supermodule_half, stack_layer); + } + if (mCurrentHalfCRULinkErrorFlags[currentlinkindex] > 0) { + ((TH2F*)mLinkErrors->At(3))->Fill(supermodule_half, stack_layer); + } + if (mCurrentHalfCRULinkLengths[currentlinkindex] > 0) { + ((TH2F*)mLinkErrors->At(4))->Fill(supermodule_half, stack_layer); + } + if (mCurrentHalfCRULinkLengths[currentlinkindex] == 0) { + ((TH2F*)mLinkErrors->At(5))->Fill(supermodule_half, stack_layer); + } + } + //mStatCountersPerEvent.mLinkErrorFlag[currentdetector] = mCurrentHalfCRULinkErrorFlags[currentlinkindex]; + + currentlinksize = mCurrentHalfCRULinkLengths[currentlinkindex]; + currentlinksize32 = currentlinksize * 8; //x8 to go from 256 bits to 32 bit; + linkstart = mHBFPayload.begin() + dataoffsetstart32 + linksizeAccum32; + linkend = linkstart + currentlinksize32; + if (currentlinksize == 0) { + mEventRecords.mTFStats.mLinkNoData[oriindex]++; + } + uint64_t linkzsum = 0; + int dioffset = dataoffsetstart32 + linksizeAccum32; + if (dioffset % 8 != 0) { + LOG(error) << " we are not 256 bit aligned ... this should never happen"; + } + if (mHBFoffset32 != std::distance(mHBFPayload.begin(), linkstart)) { + mHBFoffset32 = std::distance(mHBFPayload.begin(), linkstart); + } + if (mHeaderVerbose) { + LOG(info) << "Cru link :" << currentlinkindex << " raw dump before processing begin linkstart:" << std::hex << linkstart << " to " << linkend << " mHBFoffset32=" << std::dec << mHBFoffset32 << " and distance from start is : " << std::distance(mHBFPayload.begin(), linkstart); + for (int dumpoffset = dataoffsetstart32 + linksizeAccum32; dumpoffset < dataoffsetstart32 + linksizeAccum32 + currentlinksize32; dumpoffset += 8) { + LOGP(info, "0x{0:06x} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ", dumpoffset, HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 1]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 2]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 3]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 4]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 5]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 6]), HelperMethods::swapByteOrderreturn(mHBFPayload[dumpoffset + 7])); + } + } + linksizeAccum32 += currentlinksize32; + if (mDataVerbose) { + LOG(info) << "******* LINK # " << currentlinkindex << " and starting at " << mHBFoffset32 << " unpackORI(" << oriindex << "," << mSide[1] << "," << mStack[1] << "," << mLayer[1] << "," << mHalfChamberSide[1] << ") and an FEEID:" << std::hex << mFEEID.word << " det:" << std::dec << mDetector[1]; + LOG(info) << "******* LINK # " << currentlinkindex << " an FEEID:" << std::hex << mFEEID.word << " det:" << std::dec << mDetector[1] << " Error Flags : " << mCurrentHalfCRULinkErrorFlags[currentlinkindex]; + } + if (linkstart != linkend) { // if link is not empty + bool cleardigits = false; //linkstart and linkend already have the multiple cruheaderoffsets built in + auto trackletparsingstart = std::chrono::high_resolution_clock::now(); + if (mHeaderVerbose) { + LOG(info) << "*** Tracklet Parser : starting at " << std::hex << linkstart << " at hbfoffset: " << std::dec << mHBFoffset32 << " linkhbf start pos:" << hbfoffsetatstartoflink; + } + // for now we are using 0 i.e. from rdh FIXME figure out which is authoritative between rdh and ori tracklethcheader if we have it enabled. + mTrackletWordsRead = mTrackletsParser.Parse(&mHBFPayload, linkstart, linkend, mFEEID, mHalfChamberSide[0], mDetector[0], mStack[0], mLayer[0], mCurrentEvent, mOptions, cleardigits, mTrackletHCHeaderState); // this will read up to the tracklet end marker. + mTrackletWordsRejected = mTrackletsParser.getDataWordsDumped(); + std::chrono::duration<double, std::micro> trackletparsingtime = std::chrono::high_resolution_clock::now() - trackletparsingstart; + if (mRootOutput) { + mTrackletTiming->Fill((int)std::chrono::duration_cast<std::chrono::microseconds>(trackletparsingtime).count()); + } + if (mHeaderVerbose) { + LOG(info) << "trackletwordsread:" << mTrackletWordsRead << " trackletwordsrejected:" << mTrackletWordsRejected << " mem copy with offset of : " << cruhbfstartoffset << " parsing with linkstart: " << linkstart << " ending at : " << linkend; + } + linkstart += mTrackletWordsRead + mTrackletWordsRejected; + //now we have a tracklethcheader and a digithcheader. + + mHBFoffset32 += mTrackletWordsRead + mTrackletWordsRejected; + mTotalTrackletsFound += mTrackletsParser.getTrackletsFound(); + mTotalTrackletWordsRejected += mTrackletWordsRejected; + mTotalTrackletWordsRead += mTrackletWordsRead; + + if (mTrackletsParser.getTrackletParsingState()) { + mHBFoffset32 += std::distance(linkstart, linkend); + linkstart = linkend; // bail out as tracklet parsing bombed out. We are essentially lost. + } + if (mHeaderVerbose) { + LOG(info) << "*** Tracklet Parser : trackletwordsread:" << mTrackletWordsRead << " ending " << std::hex << linkstart << " at hbfoffset: " << std::dec << mHBFoffset32; + } + + // check if we are now at the end of the data due to bugs, i.e. if trackletparsing read padding words. + if (linkstart != linkend) { + // linkstart advanced all the way to the end due to trackletparser parsing crupadding words (known bug or feature ) + auto hfboffsetbeforehcparse = mHBFoffset32; + //now read the digit half chamber header + auto hcparse = parseDigitHCHeader(); + mWhichData = checkDigitHCHeader(); + //move over the DigitHCHeader mHBFoffset32 has already been moved in the reading. + if (mHBFoffset32 - hfboffsetbeforehcparse != 1 + mDigitHCHeader.numberHCW) { + LOG(error) << "Seems data offset is out of sync with number of HC Headers words " << mHBFoffset32 << "-" << hfboffsetbeforehcparse << "!=" << 1 << "+" << mDigitHCHeader.numberHCW; + } + if (hcparse == -1) { + LOG(warn) << "Parsing Digit HCHeader returned a -1"; + } else { + linkstart += 1 + mDigitHCHeader.numberHCW; + } + + if (mDigitHCHeader.major == 0x47) { + // config event so ignore for now and bail out of parsing. + LOG(warn) << " HCHeader major version is 0x47 bailing out of parsing this as its a config event"; + //advance data pointers to the end; + linkstart = linkend; + //mHBFoffset32 = std::distance(mHBFPayload.begin(),linkend);//dataoffsetstart32 + currentlinksize; // go to the end of the link + mHBFoffset32 = std::distance(mHBFPayload.begin(), linkend); //currentlinksize-mTrackletWordsRead-sizeof(digitHCHeader)/4; // advance to the end of the link + mTotalDigitWordsRejected += std::distance(linkstart + mTrackletWordsRead + sizeof(DigitHCHeader) / 4, linkend); + } else { + if (((mDigitHCHeader.major & 0x27) == mDigitHCHeader.major) || ((mDigitHCHeader.major & 0x37) == mDigitHCHeader.major) || ((mDigitHCHeader.major & 0x17) == mDigitHCHeader.major)) { + // ZS DisableTracklets + mDigitWordsRead = 0; + auto digitsparsingstart = std::chrono::high_resolution_clock::now(); + //linkstart and linkend already have the multiple cruheaderoffsets built in + mDigitWordsRead = mDigitsParser.Parse(&mHBFPayload, linkstart, linkend, mDetector[mWhichData], mStack[mWhichData], mLayer[mWhichData], mSide[mWhichData], mDigitHCHeader, mFEEID, currentlinkindex, mCurrentEvent, mOptions, cleardigits); + std::chrono::duration<double, std::micro> digitsparsingtime = std::chrono::high_resolution_clock::now() - trackletparsingstart; + if (mRootOutput) { + mDigitTiming->Fill((int)std::chrono::duration_cast<std::chrono::microseconds>(digitsparsingtime).count()); + } + mDigitWordsRejected = mDigitsParser.getDumpedDataCount(); + if (mHeaderVerbose) { + if (mDigitsParser.getDumpedDataCount() != 0) { + LOG(info) << "FEEID: " << mFEEID.word << " LINK #" << oriindex << " bad datacount:" << mDigitsParser.getDataWordsParsed() << "::" << mDigitsParser.getDumpedDataCount(); + } else { + LOG(info) << "FEEID: " << mFEEID.word << " LINK #" << oriindex << " good datacount:" << mDigitsParser.getDataWordsParsed() << "::" << mDigitsParser.getDumpedDataCount(); + } + } + if (mDigitWordsRead + mDigitWordsRejected != std::distance(linkstart, linkend)) { + //we have the data corruption problem of a pile of stuff at the end of a link, jump over it. + if (mFixDigitEndCorruption) { + mDigitWordsRead = std::distance(linkstart, linkend); + } else { + if (mRootOutput) { + mParsingErrors->Fill(TRDParsingDigitStackMismatch); + ((TH2F*)mParsingErrors2d->At(TRDParsingDigitDataStillOnLink))->Fill(mFEEID.supermodule * 2 + mFEEID.side, mStack[0] * constants::NLAYER + mLayer[0]); + } + } + } + mTotalDigitsFound += mDigitsParser.getDigitsFound(); + if (mVerbose) { + LOG(info) << "mDigitWordsRead : " << mDigitWordsRead << " mem copy with offset of : " << cruhbfstartoffset << " parsing digits with linkstart: " << linkstart << " ending at : " << linkend << " linkhbf start pos:" << hbfoffsetatstartoflink; + } + mHBFoffset32 += mDigitWordsRead + mDigitWordsRejected; // all 3 in 32bit units + mTotalDigitWordsRead += mDigitWordsRead; + mTotalDigitWordsRejected += mDigitWordsRejected; + } else { + LOG(warn) << "Digit format not configured ! major.minor in : 0x" << std::hex << mDigitHCHeader.major << ".0x" << mDigitHCHeader.minor; + linkstart = linkend; + mHBFoffset32 = std::distance(mHBFPayload.begin(), linkend); //currentlinksize-mTrackletWordsRead-sizeof(digitHCHeader)/4; // advance to the end of the link + mTotalDigitWordsRejected += std::distance(linkstart + mTrackletWordsRead + sizeof(DigitHCHeader) / 4, linkend); + } + } + } else { + if (mRootOutput) { + mDataVersions->Fill(0); + mDataVersionsMajor->Fill(0); + } + } + sumlinklengths += mCurrentHalfCRULinkLengths[currentlinkindex]; + sumtrackletwords += mTrackletWordsRead; + sumdigitwords += mDigitWordsRead; + + if (mDigitWordsRejected > 0) { + if (mRootOutput) { + ((TH2F*)mLinkErrors->At(6))->Fill(supermodule_half, stack_layer); + } + } else if (mRootOutput) { + ((TH2F*)mLinkErrors->At(7))->Fill(supermodule_half, stack_layer); + } + } else { + if (mVerbose) { + LOG(info) << "link start and end are the same, link appears to be empty for link currentlinkdex"; + } + } + } //for loop over link index. + // we have read in all the digits and tracklets for this event. + //digits and tracklets are sitting inside the parsing classes. + //extract the vectors and copy them to tracklets and digits here, building the indexing(triggerrecords) + //as this is for a single cru half chamber header all the tracklets and digits are for the same trigger defined by the bc and orbit in the rdh which we hold in mIR + + int lasttrigger = 0, lastdigit = 0, lasttracklet = 0; + std::chrono::duration<double, std::micro> cruparsingtime = std::chrono::high_resolution_clock::now() - crustart; + if (mRootOutput) { + mCruTime->Fill((int)std::chrono::duration_cast<std::chrono::microseconds>(cruparsingtime).count()); + } + + //if we get here all is ok. + return 1; +} + +bool CruRawReader::buildCRUPayLoad() +{ + // copy data for the current half cru, and when we eventually get to the end of the payload return 1 + // to say we are done. + int cruid = 0; + int additionalBytes = -1; + int crudatasize = -1; + LOG(info) << "--- Build CRU Payload, added " << additionalBytes << " bytes to CRU " + << cruid << " with new size " << crudatasize; + return true; +} + +bool CruRawReader::processCRULink() +{ + /* process a CRU Link 15 per half cru */ + // checkFeeID(); // check the link we are working with corresponds with the FeeID we have in the current rdh. + // uint32_t slotId = GET_TRMDATAHEADER_SLOTID(*mDataPointer); + return false; +} + +void CruRawReader::resetCounters() +{ + //mStatCountersPerEvent.mLinkErrorFlag.fill(0); + mEventCounter = 0; + mFatalCounter = 0; + mErrorCounter = 0; +} + +void CruRawReader::checkSummary() +{ + char chname[2] = {'a', 'b'}; + + LOG(info) << "--- SUMMARY COUNTERS: " << mEventCounter << " events " + << " | " << mFatalCounter << " decode fatals " + << " | " << mErrorCounter << " decode errors "; +} + +bool CruRawReader::run() +{ + uint32_t dowhilecount = 0; + uint64_t totaldataread = 0; + rewind(); + mTotalDigitWordsRead = 0; + mTotalDigitWordsRejected = 0; + mTotalTrackletWordsRead = 0; + mTotalTrackletWordsRejected = 0; + uint32_t* bufferptr; + bufferptr = (uint32_t*)mDataBuffer; + do { + if (mDataVerbose) { + LOG(info) << " mDataBuffer :" << (void*)mDataBuffer << " and offset to start on is :" << totaldataread; + } + mDatareadfromhbf = 0; + processHBFs(totaldataread, mVerbose); + totaldataread += mDatareadfromhbf; + } while (((char*)mDataPointer - mDataBuffer) < mDataBufferSize); + + return false; +}; + +void CruRawReader::getParsedObjects(std::vector<Tracklet64>& tracklets, std::vector<Digit>& digits, std::vector<TriggerRecord>& triggers) +{ + int digitcountsum = 0; + int trackletcountsum = 0; + mEventRecords.unpackData(triggers, tracklets, digits); +} + +void CruRawReader::getParsedObjectsandClear(std::vector<Tracklet64>& tracklets, std::vector<Digit>& digits, std::vector<TriggerRecord>& triggers) +{ + getParsedObjects(tracklets, digits, triggers); + clearall(); +} + +//write the output data directly to the given DataAllocator from the datareader task. +void CruRawReader::buildDPLOutputs(o2::framework::ProcessingContext& pc, bool displaytracklets) +{ + mEventRecords.sendData(pc, displaytracklets); + clearall(); // having now written the messages clear for next. +} + +} // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/src/DataReader.cxx b/Detectors/TRD/reconstruction/src/DataReader.cxx new file mode 100644 index 0000000000000..f683fd261dd54 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/DataReader.cxx @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file datareader.cxx +/// @author Sean Murray +/// @brief Basic DPL workflow for TRD CRU output(raw) or compressed format to tracklet data. +/// There may or may not be some compression in this at some point. + +#include "TRDReconstruction/DataReaderTask.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConcreteDataMatcher.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/Logger.h" +#include "DetectorsRaw/RDHUtils.h" +#include "TRDWorkflowIO/TRDTrackletWriterSpec.h" +#include "TRDWorkflowIO/TRDDigitWriterSpec.h" +#include "DataFormatsTRD/RawDataStats.h" + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + + std::vector<o2::framework::ConfigParamSpec> options{ + {"trd-datareader-output-desc", VariantType::String, "TRDTLT", {"Output specs description string"}}, + {"trd-datareader-verbose", VariantType::Bool, false, {"Enable verbose epn data reading"}}, + {"trd-datareader-headerverbose", VariantType::Bool, false, {"Enable verbose header info"}}, + {"trd-datareader-dataverbose", VariantType::Bool, false, {"Enable verbose data info"}}, + {"trd-datareader-compresseddata", VariantType::Bool, false, {"The incoming data is compressed or not"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"trd-datareader-fixdigitcorruptdata", VariantType::Bool, false, {"Fix the erroneous data at the end of digits"}}, + {"enable-timing", VariantType::Bool, false, {"enable the timing of tracklet, digit, timeframe, cru processing"}}, + {"enable-stats", VariantType::Bool, false, {"enable the reader stats"}}, + {"enable-root-output", VariantType::Bool, false, {"Write the data to file"}}, + {"ignore-tracklethcheader", VariantType::Bool, false, {"Ignore the tracklethalf chamber header for cross referencing"}}, + {"halfchamberwords", VariantType::Int, 0, {"Fix half chamber for when it is version is 0.0 integer value of additional header words, ignored if version is not 0.0"}}, + {"halfchambermajor", VariantType::Int, 0, {"Fix half chamber for when it is version is 0.0 integer value of major version, ignored if version is not 0.0"}}, + {"ignore-digithcheader", VariantType::Bool, false, {"Ignore the digithalf chamber header for cross referencing, take rdh/cru as authorative."}}, + {"tracklethcheader", VariantType::Int, 0, {"Status of TrackletHalfChamberHeader 0 off always, 1 iff tracklet data, 2 on always"}}, + {"histogramsfile", VariantType::String, "histos.root", {"Name of the histogram file, so one can run multiple per node"}}, + {"trd-datareader-enablebyteswapdata", VariantType::Bool, false, {"byteswap the incoming data, raw data needs it and simulation does not."}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver + +using namespace o2::framework; +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + // auto config = cfgc.options().get<std::string>("trd-datareader-config"); + + //auto outputspec = cfgc.options().get<std::string>("trd-datareader-outputspec"); + auto verbose = cfgc.options().get<bool>("trd-datareader-verbose"); + auto byteswap = cfgc.options().get<bool>("trd-datareader-enablebyteswapdata"); + auto compresseddata = cfgc.options().get<bool>("trd-datareader-compresseddata"); + auto headerverbose = cfgc.options().get<bool>("trd-datareader-headerverbose"); + auto dataverbose = cfgc.options().get<bool>("trd-datareader-dataverbose"); + auto askSTFDist = !cfgc.options().get<bool>("ignore-dist-stf"); + auto fixdigitcorruption = cfgc.options().get<bool>("trd-datareader-fixdigitcorruptdata"); + auto tracklethcheader = cfgc.options().get<int>("tracklethcheader"); + auto enabletimeinfo = cfgc.options().get<bool>("enable-timing"); + auto enablestats = cfgc.options().get<bool>("enable-stats"); + auto halfchamberwords = cfgc.options().get<int>("halfchamberwords"); + auto halfchambermajor = cfgc.options().get<int>("halfchambermajor"); + + std::vector<OutputSpec> outputs; + outputs.emplace_back("TRD", "TRACKLETS", 0, Lifetime::Timeframe); + outputs.emplace_back("TRD", "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back("TRD", "TRKTRGRD", 0, Lifetime::Timeframe); + //outputs.emplace_back("TRD", "FLPSTAT", 0, Lifetime::Timeframe); + // + std::bitset<16> binaryoptions; + binaryoptions[o2::trd::TRDVerboseBit] = cfgc.options().get<bool>("trd-datareader-verbose"); + binaryoptions[o2::trd::TRDHeaderVerboseBit] = cfgc.options().get<bool>("trd-datareader-headerverbose"); + binaryoptions[o2::trd::TRDDataVerboseBit] = cfgc.options().get<bool>("trd-datareader-dataverbose"); + binaryoptions[o2::trd::TRDCompressedDataBit] = cfgc.options().get<bool>("trd-datareader-compresseddata"); + binaryoptions[o2::trd::TRDFixDigitCorruptionBit] = cfgc.options().get<bool>("trd-datareader-fixdigitcorruptdata"); + binaryoptions[o2::trd::TRDEnableTimeInfoBit] = cfgc.options().get<bool>("enable-timing"); + binaryoptions[o2::trd::TRDEnableStatsBit] = cfgc.options().get<bool>("enable-stats"); + binaryoptions[o2::trd::TRDIgnoreDigitHCHeaderBit] = cfgc.options().get<bool>("ignore-digithcheader"); + binaryoptions[o2::trd::TRDIgnoreTrackletHCHeaderBit] = cfgc.options().get<bool>("ignore-tracklethcheader"); + binaryoptions[o2::trd::TRDEnableRootOutputBit] = cfgc.options().get<bool>("enable-root-output"); + binaryoptions[o2::trd::TRDByteSwapBit] = cfgc.options().get<bool>("trd-datareader-enablebyteswapdata"); + + AlgorithmSpec algoSpec; + algoSpec = AlgorithmSpec{adaptFromTask<o2::trd::DataReaderTask>(tracklethcheader, halfchamberwords, halfchambermajor, cfgc.options().get<std::string>("histogramsfile"), binaryoptions)}; + + WorkflowSpec workflow; + + std::string iconfig; + std::string inputDescription; + int idevice = 0; + auto orig = o2::header::gDataOriginTRD; + auto inputs = o2::framework::select(std::string("x:TRD/RAWDATA").c_str()); + for (auto& inp : inputs) { + // take care of case where our data is not in the time frame + inp.lifetime = Lifetime::Optional; + } + if (askSTFDist) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + workflow.emplace_back(DataProcessorSpec{ + std::string("trd-datareader"), // left as a string cast incase we append stuff to the string + inputs, //select(std::string("x:TRD/" + inputspec).c_str()), + outputs, + algoSpec, + Options{}}); + + if (cfgc.options().get<bool>("enable-root-output")) { + workflow.emplace_back(o2::trd::getTRDDigitWriterSpec(false, false)); + workflow.emplace_back(o2::trd::getTRDTrackletWriterSpec(false)); + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, workflow); + + return workflow; +} diff --git a/Detectors/TRD/reconstruction/src/DataReaderTask.cxx b/Detectors/TRD/reconstruction/src/DataReaderTask.cxx new file mode 100644 index 0000000000000..517c9937837e0 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/DataReaderTask.cxx @@ -0,0 +1,331 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DataReaderTask.cxx +/// @author Sean Murray +/// @brief TRD cru output to tracklet task + +#include "TRDReconstruction/DataReaderTask.h" +#include "TRDReconstruction/CruRawReader.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/InputRecordWalker.h" + +#include "DataFormatsTRD/Constants.h" + +#include <fairmq/FairMQDevice.h> +#include <TH3F.h> +#include "TH2F.h" +#include "TFile.h" + +//using namespace o2::framework; + +namespace o2::trd +{ + +void DataReaderTask::setParsingErrorLabels() +{ + //TODO this is not working, come back at some point fix, not essential. + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingNoError, "TRDParsingNoError"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingUnrecognisedVersion, "TRDParsingUnrecognisedVersion"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingBadDigt, "TRDParsingBadDigt"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingBadTracklet, "TRDParsingBadTracklet"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitEndMarkerWrongState, "TRDParsingDigitEndMarkerWrongState"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitMCMHeaderSanityCheckFailure, "TRDParsingDigitMCMHeaderSanityCheckFailure"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitROBDecreasing, "TRDParsingDigitROBDecreasing"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitMCMNotIncreasing, "TRDParsingDigitMCMNotIncreasing"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitADCMaskMismatch, "TRDParsingDigitADCMaskMismatch"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitADCMaskAdvanceToEnd, "TRDParsingDigitADCMaskAdvanceToEnd"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitMCMHeaderBypassButStateMCMHeader, "TRDParsingDigitMCMHeaderBypassButStateMCMHeader"); + mParsingErrors->GetXaxis()->SetBinLabel(TRDParsingDigitEndMarkerStateButReadingMCMADCData, "TRDParsingDigitEndMarkerStateButReadingMCMADCData"); + /* TRDParsingDigitADCChannel21, + TRDParsingDigitADCChannelGT22, + TRDParsingDigitGT10ADCs, + TRDParsingDigitSanityCheck, + TRDParsingDigitExcessTimeBins, + TRDParsingDigitParsingExitInWrongState, + TRDParsingDigitStackMisMatch, + TRDParsingDigitLayerMisMatch, + TRDParsingDigitSectorMisMatch, + TRDParsingTrackletCRUPaddingWhileParsingTracklets, + TRDParsingTrackletBit11NotSetInTrackletHCHeader, + TRDParsingTrackletHCHeaderSanityCheckFailure, + TRDParsingTrackletMCMHeaderSanityCheckFailure, + TRDParsingTrackletMCMHeaderButParsingMCMData, + TRDParsingTrackletStateMCMHeaderButParsingMCMData, + TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader, + TRDParsingTrackletInvalidTrackletCount, + TRDParsingTrackletPadRowIncreaseError, + TRDParsingTrackletColIncreaseError, + TRDParsingTrackletNoTrackletEndMarker, + TRDParsingTrackletExitingNoTrackletEndMarker + */ +} + +void DataReaderTask::buildHistograms() +{ + if (mRootOutput) { + mParseErrors = new TList(); + mLinkErrors = new TList(); + mRootFile = new TFile(mHistogramsFilename.c_str(), "recreate"); // make this changeable from command line + std::array<std::string, 10> linkerrortitles = {"Count of Link had no errors during tf", + "Count of # times Linkerrors 0x1 seen per tf", + "Count of # time Linkerrors 0x2 seen per tf", + "Count of any Linkerror seen during tf", + "Link was seen with no data (empty) in a tf", + "Link was seen with data during a tf", + "Links seen with corrupted data during tf", + "Links seen with out corrupted data during tf", "", ""}; + //lets hack this for some graphs + mTimeFrameTime = new TH1F("timeframetime", "Time taken per time frame", 10000, 0, 10000); + mTrackletParsingTime = new TH1F("tracklettime", "Time taken per tracklet block", 1000, 0, 1000); + mDigitParsingTime = new TH1F("digittime", "Time taken per digit block", 1000, 0, 1000); + mCruTime = new TH1F("crutime", "Time taken per cru link", 1000, 0, 1000); + mPackagingTime = new TH1F("packagingtime", "Time to package the eventrecord and copy the output", 1000, 0, 1000); + mDataVersions = new TH1F("dataversions", "Data versions major.minor seen in data", 65000, 0, 65000); + mDataVersionsMajor = new TH1F("dataversionsmajor", "Data versions major", 256, 0, 256); + mParsingErrors = new TH1F("parseerrors", "Parsing Errors seen in data", 256, 0, 256); + int count = 0; + for (int count = 0; count < constants::MAXPARSEERRORHISTOGRAMS; ++count) { + std::string label = fmt::format("parsingerrors_{0}", count); + std::string title = fmt::format("linkerrors_{0}", count); + TH2F* h = new TH2F(label.c_str(), title.c_str(), 36, 0, 36, 30, 0, 30); + mParseErrors->Add(h); + } + count = 0; + for (int count = 0; count < constants::MAXLINKERRORHISTOGRAMS; ++count) { + std::string label = fmt::format("linkerrors_{0}", count); + std::string title = linkerrortitles[count]; + TH2F* h = new TH2F(label.c_str(), title.c_str(), 36, 0, 36, 30, 0, 30); + mLinkErrors->Add(h); + } + mTimeFrameTime->GetXaxis()->SetTitle("Time taken in ms"); + mCruTime->GetXaxis()->SetTitle("Time taken in ms"); + mTrackletParsingTime->GetXaxis()->SetTitle("Time taken in #mus"); + mDigitParsingTime->GetXaxis()->SetTitle("Time taken in #mus"); + mPackagingTime->GetXaxis()->SetTitle("Time taken in #mus"); + mTimeFrameTime->GetYaxis()->SetTitle("Counts"); + mTrackletParsingTime->GetYaxis()->SetTitle("Counts"); + mDigitParsingTime->GetYaxis()->SetTitle("Counts"); + mCruTime->GetYaxis()->SetTitle("Counts"); + mPackagingTime->GetYaxis()->SetTitle("Counts"); + mDataVersions->GetYaxis()->SetTitle("Counts"); + mDataVersions->GetYaxis()->SetTitle("Counts"); + mDataVersionsMajor->GetYaxis()->SetTitle("Counts"); + mDataVersionsMajor->GetXaxis()->SetTitle("Version major"); + mParsingErrors->GetYaxis()->SetTitle("Erorr Types"); + mParsingErrors->GetXaxis()->SetTitle("Erorr Types"); + for (int count = 0; count < constants::MAXPARSEERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mParseErrors->At(count); + h->GetXaxis()->SetTitle("Sector*2 + side"); + h->GetXaxis()->CenterTitle(kTRUE); + h->GetYaxis()->SetTitle("Stack_Layer"); + h->GetYaxis()->CenterTitle(kTRUE); + } + for (int count = 0; count < constants::MAXLINKERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mLinkErrors->At(count); + h->GetXaxis()->SetTitle("Sector*2 + side"); + h->GetXaxis()->CenterTitle(kTRUE); + h->GetYaxis()->SetTitle("Stack_Layer"); + h->GetYaxis()->CenterTitle(kTRUE); + for (int s = 0; s < o2::trd::constants::NSTACK; ++s) { + for (int l = 0; l < o2::trd::constants::NLAYER; ++l) { + std::string label = fmt::format("{0}_{1}", s, l); + int pos = s * o2::trd::constants::NLAYER + l + 1; + h->GetYaxis()->SetBinLabel(pos, label.c_str()); + } + } + } + mReader.setHistos(mLinkErrors, mParseErrors); + //mReader.setParsingHistos(); + mReader.setTimeHistos(mTimeFrameTime, mTrackletParsingTime, + mDigitParsingTime, mCruTime, mPackagingTime, + mDataVersions, mDataVersionsMajor, mParsingErrors); + } +} +void DataReaderTask::init(InitContext& ic) +{ + LOG(INFO) << "o2::trd::DataReadTask init"; + + auto finishFunction = [this]() { + mReader.checkSummary(); + }; + buildHistograms(); // if requested create all the histograms + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishFunction); + mDataDesc = "RAWDATA"; +} + +void DataReaderTask::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + if (mRootOutput) { + mTimeFrameTime->Draw(); + mTrackletParsingTime->Draw(); + mDigitParsingTime->Draw(); + mCruTime->Draw(); + mPackagingTime->Draw(); + mDataVersions->Draw(); + mDataVersionsMajor->Draw(); + mParsingErrors->Draw(); + for (int count = 0; count < constants::MAXPARSEERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mParseErrors->At(count); + h->Draw(); + } + for (int count = 0; count < constants::MAXLINKERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mLinkErrors->At(count); + h->Draw(); + } + for (int count = 0; count < constants::MAXPARSEERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mParseErrors->At(count); + h->Write(); + } + for (int count = 0; count < constants::MAXLINKERRORHISTOGRAMS; ++count) { + TH2F* h = (TH2F*)mLinkErrors->At(count); + h->Write(); + } + mTimeFrameTime->Write(); + mTrackletParsingTime->Write(); + mDigitParsingTime->Write(); + mCruTime->Write(); + mPackagingTime->Write(); + mDataVersions->Write(); + mDataVersionsMajor->Write(); + mParsingErrors->Write(); + + mRootFile->Close(); + } +} + +void DataReaderTask::sendData(ProcessingContext& pc, bool blankframe) +{ + if (!blankframe) { + mReader.buildDPLOutputs(pc, mDataVerbose); + } else { + //ensure the objects we are sending back are indeed blank. + //TODO maybe put this in buildDPLOutputs so sending all done in 1 place, not now though. + std::vector<Tracklet64> tracklets; + std::vector<Digit> digits; + std::vector<o2::trd::TriggerRecord> triggers; + LOG(info) << "Sending data onwards with " << digits.size() << " Digits and " << tracklets.size() << " Tracklets and " << triggers.size() << " Triggers and blankframe:" << blankframe; + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "DIGITS", 0, Lifetime::Timeframe}, digits); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe}, tracklets); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe}, triggers); + } +} + +bool DataReaderTask::isTimeFrameEmpty(ProcessingContext& pc) +{ + constexpr auto origin = header::gDataOriginTRD; + o2::framework::InputSpec dummy{"dummy", framework::ConcreteDataMatcher{origin, header::gDataDescriptionRawData, 0xDEADBEEF}}; + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload. + // frame detected we have no data and send this instead + // send empty output so as to not block workflow + for (const auto& ref : o2::framework::InputRecordWalker(pc.inputs(), {dummy})) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(INFO, "Found blank input input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : ", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + return true; + } + } + return false; +} + +void DataReaderTask::run(ProcessingContext& pc) +{ + //NB this is run per time frame on the epn. + LOG(info) << "TRD Translator Task run"; + auto dataReadStart = std::chrono::high_resolution_clock::now(); + + if (isTimeFrameEmpty(pc)) { + sendData(pc, true); //send the empty tf data. + return; + } + uint64_t total1 = 0, total2 = 0; + /* set encoder output buffer */ + char bufferOut[o2::trd::constants::HBFBUFFERMAX]; + int loopcounter = 0; + uint64_t tfcounter = 0; + uint64_t inputcounter = 0; + auto device = pc.services().get<o2::framework::RawDeviceService>().device(); + auto outputRoutes = pc.services().get<o2::framework::RawDeviceService>().spec().outputs; + auto fairMQChannel = outputRoutes.at(0).channel; + /* loop over inputs routes */ + for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { + if (!iit.isValid()) { + continue; + } + /* loop over input parts */ + int inputpartscount = 0; + int emptyframe = 0; + tfcounter++; + for (auto const& ref : iit) { + auto inputprocessingstart = std::chrono::high_resolution_clock::now(); // measure total processing time + if (mVerbose) { + const auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + LOGP(info, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : ", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + } + const auto* headerIn = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + auto payloadIn = ref.payload; + auto payloadInSize = headerIn->payloadSize; + // const auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (std::string(headerIn->dataDescription.str) != std::string("DISTSUBTIMEFRAMEFLP")) { + if (!mCompressedData) { //we have raw data coming in from flp + if (mVerbose) { + LOG(info) << " parsing non compressed data in the data reader task with a payload of " << payloadInSize << " payload size"; + } + // LOG(info) << "start of data is at ref.payload=0x"<< std::hex << " headerIn->payloadSize:0x" << headerIn->payloadSize <<" headerIn->headerSize:0x" <<headerIn->headerSize; + total1 += headerIn->payloadSize; + total2 += headerIn->headerSize; + // LOG(info) << "start of data is at ref.payload=0x"<< std::hex << " total1:0x" << total1 <<" total2:0x" <<total2; + mReader.setDataBuffer(payloadIn); + mReader.setDataBufferSize(payloadInSize); + mReader.configure(mTrackletHCHeaderState, mHalfChamberWords, mHalfChamberMajor, mOptions); + //mReader.setStats(&mTimeFrameStats); + mReader.run(); + mWordsRead += mReader.getWordsRead(); + mWordsRejected += mReader.getWordsRejected(); + if (mVerbose) { + LOG(info) << "relevant vectors to read : " << mReader.sumTrackletsFound() << " tracklets and " << mReader.sumDigitsFound() << " compressed digits"; + } + } else { // we have compressed data coming in from flp. + mCompressedReader.setDataBuffer(payloadIn); + mCompressedReader.setDataBufferSize(payloadInSize); + mCompressedReader.configure(mOptions); + mCompressedReader.run(); + } + } // ignore the input of DISTSUBTIMEFRAMEFLP + } + + std::chrono::duration<double, std::milli> dataReadTime = std::chrono::high_resolution_clock::now() - dataReadStart; + LOG(info) << "Processing time for Data reading " << std::chrono::duration_cast<std::chrono::milliseconds>(dataReadTime).count() << "ms"; + if (mRootOutput) { + mTimeFrameTime->Fill((int)std::chrono::duration_cast<std::chrono::milliseconds>(dataReadTime).count()); + } + LOG(info) << "[" << tfcounter << "] D:" << mReader.getDigitsFound() << " T:" << mReader.getTrackletsFound(); + /* output */ + sendData(pc, false); + } + if (!mCompressedData) { + LOG(info) << "Digits found : " << mReader.getDigitsFound(); + LOG(info) << "Tracklets found : " << mReader.getTrackletsFound(); + LOG(info) << "DataRead in :" << mWordsRead * 4 << " bytes"; + LOG(info) << "DataRejected in :" << mWordsRejected * 4 << " bytes"; + LOG(info) << "DataRetention :bad/good" << (double)mWordsRejected / (double)mWordsRead << ""; + LOG(info) << "Total % good data bad/(good+bad)" << (double)mWordsRejected / ((double)mWordsRead + (double)mWordsRejected) * 100.0 << " %"; + } +} + +} // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/src/DigitsParser.cxx b/Detectors/TRD/reconstruction/src/DigitsParser.cxx new file mode 100644 index 0000000000000..16de560ab7299 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/DigitsParser.cxx @@ -0,0 +1,473 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitsParser.h +/// @brief TRD raw data parser for digits + +#include "TRDReconstruction/DigitsParser.h" +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/RawDataStats.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/CompressedDigit.h" +#include "DataFormatsTRD/Digit.h" +#include "TRDReconstruction/EventRecord.h" +#include "fairlogger/Logger.h" + +//TODO come back and figure which of below headers I actually need. +#include <cstring> //memcpy +#include <string> +#include <vector> +#include <array> +#include <iterator> +#include <bitset> +#include <iomanip> +#include <iostream> + +namespace o2::trd +{ + +inline void DigitsParser::swapByteOrder(unsigned int& word) +{ + word = (word >> 24) | + ((word << 8) & 0x00FF0000) | + ((word >> 8) & 0x0000FF00) | + (word << 24); +} +int DigitsParser::Parse(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data, std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator start, + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator end, int detector, int stack, int layer, int side, DigitHCHeader& hcheader, + TRDFeeID& feeid, unsigned int linkindex, EventRecord* eventrecord, std::bitset<16> options, bool cleardigits) +{ + setData(data); + mStartParse = start; + mEndParse = end; + mDetector = detector; + mStack = stack; + mLayer = layer; + mSide = side; + mDigitHCHeader = hcheader; + mFEEID = feeid; + setVerbose(options[TRDVerboseBit], options[TRDHeaderVerboseBit], options[TRDDataVerboseBit]); + if (cleardigits) { + clearDigits(); + } + setByteSwap(options[TRDByteSwapBit]); + mReturnVectorPos = 0; + mEventRecord = eventrecord; + return Parse(); +}; + +void DigitsParser::OutputIncomingData() +{ + + LOG(info) << "Data buffer to parse for Digits begin " << mStartParse << ":" << mEndParse; + int wordcount = 0; + std::stringstream outputstring; + auto word = mStartParse; + outputstring << "digit 0x" << std::hex << std::setfill('0') << std::setw(6) << 0 << " :: "; + while (word <= mEndParse) { // loop over the entire data buffer (a complete link of tracklets and digits) + + if (wordcount != 0 && (wordcount % 8 == 0 || word == mEndParse)) { + LOG(info) << outputstring.str(); + outputstring.str(""); + outputstring << "digit 0x" << std::hex << std::setfill('0') << std::setw(6) << wordcount << " :: "; + } + if (wordcount == 0) { + outputstring << " 0x" << std::hex << std::setfill('0') << std::setw(8) << HelperMethods::swapByteOrderreturn(*word); + } else { + outputstring << " 0x" << std::hex << std::setfill('0') << std::setw(8) << HelperMethods::swapByteOrderreturn(*word); + } + word++; + wordcount++; + } + LOG(info) << "Data buffer to parse for Digits end"; +} + +int DigitsParser::Parse(bool verbose) +{ + + auto timedigitparsestart = std::chrono::high_resolution_clock::now(); // measure total processing time + //we are handed the buffer payload of an rdh and need to parse its contents. + //producing a vector of digits. + mVerbose = verbose; + + mState = StateDigitMCMHeader; + mDataWordsParsed = 0; // count of data wordsin data that have been parsed in current call to parse. + mWordsDumped = 0; + mDigitsFound = 0; // tracklets found in the data block, mostly used for debugging. + mBufferLocation = 0; + mPaddingWordsCounter = 0; + int bitsinmask = 0; + int overchannelcount = 0; + int lastmcmread = 0; + int lastrobread = 0; + int lasteventcounterread = 0; + if (mHeaderVerbose) { + OutputIncomingData(); + } + int mcmdatacount = 0; + int digittimebinoffset = 0; + //mData holds a buffer containing digits parse placing the read digits where they need to be + // due to the nature of the incoming data, there will *never* straggling digits or for that matter trap outputs spanning a boundary. + // data starts with a DigitHCHeader, so pull that off first to simplify looping + + for (auto word = mStartParse; word < mEndParse; ++word) { // loop over the entire data buffer (a complete link of digits) + auto looptime = std::chrono::high_resolution_clock::now() - timedigitparsestart; + //loop over all the words + //check for digit end marker + if (mByteOrderFix) { + // byte swap if needed. + swapByteOrder(*word); + } + auto nextword = std::next(word, 1); + if ((*word) == 0x0 && (*nextword == 0x0)) { // no need to byte swap nextword + // end of digits marker. + if (mHeaderVerbose) { + LOG(info) << "*** DigitEndMarker :0x" << std::hex << *word << "::0x" << *nextword << " at offset " << std::distance(mStartParse, word); + } + //state *should* be StateDigitMCMData check that it is + if (mState == StateDigitMCMData || mState == StateDigitEndMarker || mState == StateDigitHCHeader || mState == StateDigitMCMHeader) { + } else { + //LOG(warn) << "Digit end marker found but state is not StateDigitMCMData(" << StateDigitMCMData << ") or StateDigit but rather " << mState; + // mEventRecord.ErrorStats[TRDParsingDigitEndMarkerWrongState]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitEndMarkerWrongState); + increment2dHist(TRDParsingDigitEndMarkerWrongState); + } + } + //only thing that can remain is the padding. + //now read padding words till end. + //no need to byteswap its uniform. + mBufferLocation += 2; // 2 words forward. + mDataWordsParsed += 2; + mState = StateDigitEndMarker; + std::advance(word, 1); // advance over the second word of the endmarker + if (word < mEndParse) { + mWordsDumped += std::distance(word, mEndParse) - 1; + } + word = mEndParse; + } else { + if ((*word & 0xf) == 0xc && (mState == StateDigitMCMHeader || mState == StateDigitMCMData)) { //marker for DigitMCMHeader. + //read the header + mcmdatacount = 0; + mCurrentADCChannel = 0; + mDigitMCMHeader = (DigitMCMHeader*)(word); + if (mHeaderVerbose) { + printDigitMCMHeader(*mDigitMCMHeader); + } + //checkDigitMCMHeader(mDigitMCMHeader,lastmcmreader,lastrobread,lastevencounterread): + if (!digitMCMHeaderSanityCheck(mDigitMCMHeader)) { + //LOG(warn) << "***DigitMCMHeader Sanity Check Failure 0x" << std::hex << *word << " at offset " << std::distance(mStartParse, word); + // mEventRecord.ErrorStats[TRDParsingDigitMCMHeaderSanityCheckFailure]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitMCMHeaderSanityCheckFailure); + increment2dHist(TRDParsingDigitMCMHeaderSanityCheckFailure); + } + // if (mDumpUnknownData) { + // we dump the remainig data pending better options. + // we can try a 16 bit bitshift... + mWordsDumped = std::distance(word, mEndParse) - 1; + //LOG(error) << " dumping the rest of this digitparsing buffer of " << mWordsDumped; + word = mEndParse; + continue; + } + // now check mcm/rob are read in correct order + if (mDigitMCMHeader->rob > lastrobread) { + lastmcmread = 0; + } else { + if (mDigitMCMHeader->rob < lastrobread) { + //LOG(warn) << "**DigitMCMHeader ROB number is not increasing was:" << lastrobread << " now:" << mDigitMCMHeader->rob << " 0x" << std::hex << *word << " at offset " << std::distance(mStartParse, word); + // mEventRecord.ErrorStats[TRDParsingDigitROBDecreasing]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitROBDecreasing); + increment2dHist(TRDParsingDigitROBDecreasing); + } + // we dump the remainig data pending better options. + // we can try a 16 bit bitshift... + mWordsDumped += std::distance(word, mEndParse) - 1; + word = mEndParse; + } + //the case of rob not changing we ignore, error condition handled by mcm # increasing. + } + if (mDigitMCMHeader->mcm < lastmcmread && mDigitMCMHeader->rob == lastrobread) { + //LOG(warn) << "**DigitMCMHeader MCM number is not increasing 0x" << std::hex << *word << " at offset " << std::distance(mStartParse, word); + // mEventRecord.ErrorStats[TRDParsingDigitMCMNotIncreasing]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitMCMNotIncreasing); + increment2dHist(TRDParsingDigitMCMNotIncreasing); + } + printDigitMCMHeader(*mDigitMCMHeader); + } + lastmcmread = mDigitMCMHeader->mcm; + lastrobread = mDigitMCMHeader->rob; + lasteventcounterread = mDigitMCMHeader->eventcount; + if (mDigitHCHeader.major & 0x20) { + //zero suppressed + //so we have an adcmask next + std::advance(word, 1); + if (mByteOrderFix) { + // byte swap if needed. + swapByteOrder(*word); + } + mDigitMCMADCMask = (DigitMCMADCMask*)(word); + mADCMask = mDigitMCMADCMask->adcmask; + if (mHeaderVerbose) { + LOG(info) << "**DigitADCMask is " << std::hex << mDigitMCMADCMask->adcmask << " raw form : 0x" << std::hex << mDigitMCMADCMask->word << " at offset " << std::distance(mStartParse, word); + } + if (word == mEndParse) { + //LOG(warn) << "we have a problem we have advanced from MCMHeader to the adcmask but are now at the end of the loop"; + // mEventRecord.ErrorStats[TRDParsingDigitADCMaskAdvanceToEnd]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitADCMaskAdvanceToEnd); + increment2dHist(TRDParsingDigitADCMaskAdvanceToEnd); + } + } + std::bitset<21> adcmask(mADCMask); + bitsinmask = adcmask.count(); + //check ADCMask: + if (!digitMCMADCMaskSanityCheck(*mDigitMCMADCMask, bitsinmask)) { + //LOG(info) << "**DigitADCMask SANITY CHECK FAILURE " << std::hex << mDigitMCMADCMask->adcmask << " raw form : 0x" << std::hex << mDigitMCMADCMask->word << " at offset " << std::distance(mStartParse, word); + // mEventRecord.ErrorStats[TRDParsingDigitADCMaskMismatch]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitADCMaskMismatch); + increment2dHist(TRDParsingDigitADCMaskMismatch); + } + mWordsDumped += std::distance(word, mEndParse) - 1; + // tryFindMCMHeaderAndDisplay(word); + word = mEndParse; + } + overchannelcount = 0; + //output all the adc data for the described adc mask, i.e 10 32 bit words per bit in mask. + } + mBufferLocation++; + //new header so digit word count becomes zero + mDigitWordCount = 0; + mState = StateDigitMCMData; + mMCM = mDigitMCMHeader->mcm; + mROB = mDigitMCMHeader->rob; + //TOOD does it match the feeid which ncodes this information as well. + // + mEventCounter = mDigitMCMHeader->eventcount; + mDataWordsParsed++; // header + if (mDigitHCHeader.major & 0x20) { + //zero suppressed digits + mDataWordsParsed++; // adc mask + } + mCurrentADCChannel = 0; + mADCValues.fill(0); + digittimebinoffset = 0; + if (!mReturnVector) { + //returning the raw "compressed" data stream. + //build the digit header and add to outgoing buffer; + uint32_t* header = &(*mData)[mReturnVectorPos]; + //build header. + } + // we dont care about the year flag, we are >2007 already. + } else { + if (mState == StateDigitMCMHeader) { //safety check for some weird data occurances + unsigned int lastbit = (*word) & 0xf; + if (mHeaderVerbose) { + LOG(info) << " we bypassed the mcmheader block but the state is MCMHeader ... 0x" << std::hex << *word << " " << lastbit << " should == 0xc"; + } + //mEventRecord.ErrorStats[TRDParsingDigitMCMHeaderBypassButStateMCMHeader]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitMCMHeaderBypassButStateMCMHeader); + increment2dHist(TRDParsingDigitMCMHeaderBypassButStateMCMHeader); + } + //dump data + mBufferLocation++; + mWordsDumped++; + // carry on parsing we might find an mcm header again + } else if (*word == o2::trd::constants::CRUPADDING32) { + if (mHeaderVerbose) { + LOG(info) << "***CRUPADDING32 word : 0x" << std::hex << *word << " state is:" << mState; + } + //another pointer with padding. + mBufferLocation++; + mPaddingWordsCounter++; + mState = StatePadding; + // mDataWordsParsed++; + mDataWordsParsed += std::distance(word, mEndParse); + //dump the rest of the received buffer its the rdh with e's + word = mEndParse; + mcmdatacount = 0; + // this is supposed to carry on till the end of the buffer, hence the term padding. + //TRDStatCounters.LinkPadWordCounts[mHCID]++; // keep track off all the padding words. + } else { // all we are left with is digitmcmdata words. + if (mState == StateDigitEndMarker) { + + if (mHeaderVerbose) { + LOG(info) << "***DigitEndMarker State : " << std::hex << *word << " at offset " << std::distance(mStartParse, word); + //we are at the end + // do nothing. + } + //mEventRecord.ErrorStats[TRDParsingDigitEndMarkerStateButReadingMCMADCData]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitEndMarkerStateButReadingMCMADCData); + increment2dHist(TRDParsingDigitEndMarkerStateButReadingMCMADCData); + } + mDataWordsParsed += std::distance(word, mEndParse) - 1; + word = mEndParse; + } else { + //for the case of on flp build a vector of tracklets, then pack them into a data stream with a header. + //for dpl build a vector and connect it with a triggerrecord. + if (mHeaderVerbose) { + LOG(info) << "***DigitMCMWord : " << std::hex << *word << " channel:" << std::dec << mCurrentADCChannel << " wordcount:" << mDigitWordCount << " at offset " << std::hex << std::distance(mStartParse, word); + } + if (mDigitWordCount == 0 || mDigitWordCount == constants::TIMEBINS / 3) { + //new adc expected so set channel accord to bitpattern or sequential depending on zero suppressed or not. + if (mDigitHCHeader.major & 0x20) { // zero suppressed + //zero suppressed, so channel must be extracted from next available bit in adcmask + mCurrentADCChannel = nextmcmadc(mADCMask, mCurrentADCChannel); + if (mCurrentADCChannel == 21) { + // LOG(warn) << "ADCMask is zero but we seem to have a digit"; + //mEventRecord.ErrorStats[TRDParsingDigitADCChannel21]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitADCChannel21); + increment2dHist(TRDParsingDigitADCChannel21); + } + } + if (mCurrentADCChannel > 22) { + LOG(error) << "invalid bitpattern (read a zero) for this mcm 0x" << std::hex << mADCMask << " at offset " << std::distance(mStartParse, word); + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitADCChannelGT22); + increment2dHist(TRDParsingDigitADCChannelGT22); + } + //mEventRecord.ErrorStats[TRDParsingDigitADCChannelGT22]++; + mCurrentADCChannel = 100 * bitsinmask + overchannelcount++; + if (mHeaderVerbose) { + LOG(info) << "EEE " << mDetector << ":" << mROB << ":" << mMCM << ":" << mCurrentADCChannel + << " supermodule:stack:layer:side : " << mDigitHCHeader.supermodule << ":" << mDigitHCHeader.stack << ":" << mDigitHCHeader.layer << ":" << mDigitHCHeader.side; + } + } + if (mADCMask == 0) { + //no more adc for zero suppression. + //now we should either have another MCMHeader, or End marker + if (*word != 0 && *(std::next(word)) != 0) { // end marker is a sequence of 32 bit 2 zeros. + mState = StateDigitMCMHeader; + } else { + mState = StateDigitEndMarker; + } + } + } else { // non zero suppressed to simply increment to the next expected channel + mCurrentADCChannel++; + } + } + if (mDigitWordCount > constants::TIMEBINS / 3) { + // LOG(error) << "***DigitMCMData with more than 10 adc's! currently on 0x" << std::hex << *word << " at offset " << std::distance(mStartParse, word); + //mEventRecord.ErrorStats[TRDParsingDigitGT10ADCs]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitGT10ADCs); + increment2dHist(TRDParsingDigitGT10ADCs); + } + } + mDigitMCMData = (DigitMCMData*)word; + mBufferLocation++; + mDataWordsParsed++; + mcmdatacount++; + // digit sanity check + if (!digitMCMWordSanityCheck(mDigitMCMData, mCurrentADCChannel)) { + //mEventRecord.ErrorStats[TRDParsingDigitSanityCheck]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitSanityCheck); + increment2dHist(TRDParsingDigitSanityCheck); + } + mWordsDumped++; + mDataWordsParsed--; // we incremented it above the if loop so now transfer the count to dumped instead of parsed; + } else { + mState = StateDigitMCMData; + mDigitWordCount++; + mADCValues[digittimebinoffset++] = mDigitMCMData->z; + mADCValues[digittimebinoffset++] = mDigitMCMData->y; + mADCValues[digittimebinoffset++] = mDigitMCMData->x; + + if (digittimebinoffset > constants::TIMEBINS) { + //LOG(error) << "too many timebins to insert into mADCValues digittimebinoffset:" << digittimebinoffset; + //mEventRecord.ErrorStats[TRDParsingDigitExcessTimeBins]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitExcessTimeBins); + increment2dHist(TRDParsingDigitExcessTimeBins); + } + //bale out TODO + mWordsDumped += std::distance(word, mEndParse) - 1; + //LOG(error) << " dumping the rest of this digitparsing buffer of " << mWordsDumped; + word = mEndParse; + } + if (mVerbose || mDataVerbose) { + LOG(info) << "digit word count is : " << mDigitWordCount << " digittimebinoffset = " << digittimebinoffset; + } + if (mDigitWordCount == constants::TIMEBINS / 3) { + //write out adc value to vector + //zero digittimebinoffset + mEventRecord->getDigits().emplace_back(mDetector, mROB, mMCM, mCurrentADCChannel, mADCValues); // outgoing parsed digits + if (mDataVerbose) { + LOG(info) << "DDD " << mDetector << ":" << mROB << ":" << mMCM << ":" << mCurrentADCChannel + << " supermodule:stack:layer:side : " << mDigitHCHeader.supermodule << ":" << mDigitHCHeader.stack << ":" << mDigitHCHeader.layer << ":" << mDigitHCHeader.side; + } + mDigitsFound++; + digittimebinoffset = 0; + mDigitWordCount = 0; // end of the digit. + if (mDigitHCHeader.major & 0x3) { + mCurrentADCChannel++; // we count channels as all 21 channels are present, no way to check this. + } + } // mDigitWordCount == timebins/3 + } + } //else digitendmarker if statement + } // else of if crupadding word + } // else of if digitMCMheader + } // else of if digitendmarker + //accounting + // mCurrentLinkDataPosition256++; + // mCurrentHalfCRUDataPosition256++; + // mTotalHalfCRUDataLength++; + //end of data so + } // for loop over word + if (!(mState == StateDigitMCMHeader || mState == StatePadding || mState == StateDigitEndMarker)) { + // LOG(warn) << "Exiting parsing but the state is wrong ... mState= " << mState; + //mEventRecord.ErrorStats[TRDParsingDigitParsingExitInWrongState]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingDigitParsingExitInWrongState); + increment2dHist(TRDParsingDigitParsingExitInWrongState); + } + } + if (std::distance(mStartParse, mEndParse) != mDataWordsParsed && mHeaderVerbose) { + if (mHeaderVerbose) { + LOG(info) << " we rejected " << mWordsDumped << " word and parse " << mDataWordsParsed << " % loss rate of " << (double)mWordsDumped / (double)mDataWordsParsed * 100.0; + } + } + return mDataWordsParsed; +} + +void DigitsParser::tryFindMCMHeaderAndDisplay(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator word) +{ + // given something has gone wrong, assume its a 16 bit shift and see if we can find a valid mcmheader, + // note the mcm and rob and output to log + // merely for debugging to see if we can find a pattern in where the 16 bit shifts/losses occur. + // maybe more recoverly logic later. + uint32_t current = *word; + uint32_t next = *(std::next(word, 1)); + uint32_t previous = *(std::prev(word, 1)); + DigitMCMHeader firstguess; // 16 bits somewhere before the mcmheader got dropped, manifesting as directly before. + DigitMCMHeader secondguess; + DigitMCMHeader thirdguess; + //first last 16 bits of previous and first 16 bits of current + uint32_t a = previous & 0xffff << 16; + uint32_t b = current & 0xffff; + firstguess.word = a + b; + if (digitMCMHeaderSanityCheck(&firstguess)) { + //sanity check passed to prossibly correct. + //LOG(warn) << "***DigitMCMHeader GUESS ??? to follow"; + printDigitMCMHeader(firstguess); + } else { + // LOG(warn) << "***DigitMCMHeader GUESS failed " << std::hex << firstguess.word << " words were 0x" << previous << " 0x" << current << " 0x" << next; + } +} + +} // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/src/EventRecord.cxx b/Detectors/TRD/reconstruction/src/EventRecord.cxx new file mode 100644 index 0000000000000..851a840625cc2 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/EventRecord.cxx @@ -0,0 +1,304 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Event Record // +// Store the tracklets and digits for a single trigger +// used temporarily for raw data + +#include <string> + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/Digit.h" +#include "TRDReconstruction/EventRecord.h" +#include "DataFormatsTRD/Constants.h" + +#include "Framework/Output.h" +#include "Framework/ProcessingContext.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/InputRecordWalker.h" + +#include "DataFormatsTRD/Constants.h" + +#include <cassert> +#include <array> +#include <string> +#include <bitset> +#include <vector> +#include <gsl/span> +#include <typeinfo> + +namespace o2::trd +{ + +//Digit information +std::vector<Digit>& EventRecord::getDigits() { return mDigits; } +void EventRecord::addDigits(Digit& digit) { mDigits.push_back(digit); } +void EventRecord::addDigits(std::vector<Digit>::iterator& start, std::vector<Digit>::iterator& end) { mDigits.insert(std::end(mDigits), start, end); } + +//tracklet information +std::vector<Tracklet64>& EventRecord::getTracklets() { return mTracklets; } +void EventRecord::addTracklet(Tracklet64& tracklet) { mTracklets.push_back(tracklet); } +void EventRecord::addTracklets(std::vector<Tracklet64>::iterator& start, std::vector<Tracklet64>::iterator& end) +{ + mTracklets.insert(std::end(mTracklets), start, end); +} + +void EventRecord::addTracklets(std::vector<Tracklet64>& tracklets) +{ + for (auto tracklet : tracklets) { + mTracklets.push_back(tracklet); + } +} + +void EventRecord::sortByHCID() +{ + // sort the tracklets by HCID + std::stable_sort(std::begin(mTracklets), std::end(mTracklets), [this](const Tracklet64& trackleta, const Tracklet64& trackletb) { return trackleta.getHCID() < trackletb.getHCID(); }); +} +// now for event storage +void EventStorage::addDigits(InteractionRecord& ir, Digit& digit) +{ + bool added = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + //TODO replace this with a hash/map not a vector + mEventRecords[count].addDigits(digit); + added = true; + } + } + if (!added) { + // unseen ir so add it + mEventRecords.push_back(ir); + mEventRecords.back().addDigits(digit); + } +} +void EventStorage::addDigits(InteractionRecord& ir, std::vector<Digit>::iterator start, std::vector<Digit>::iterator end) +{ + bool added = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + //TODO replace this with a hash/map not a vector + mEventRecords[count].addDigits(start, end); + added = true; + } + } + if (!added) { + // unseen ir so add it + mEventRecords.push_back(ir); + mEventRecords.back().addDigits(start, end); + } +} +void EventStorage::addTracklet(InteractionRecord& ir, Tracklet64& tracklet) +{ + bool added = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + //TODO replace this with a hash/map not a vector + mEventRecords[count].addTracklet(tracklet); + added = true; + } + } + if (!added) { + // unseen ir so add it + mEventRecords.push_back(ir); + mEventRecords.back().addTracklet(tracklet); + } +} + +void EventStorage::addTracklets(InteractionRecord& ir, std::vector<Tracklet64>& tracklets) +{ + bool added = false; + int count = 0; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + //TODO replace this with a hash/map not a vector + mEventRecords[count].addTracklets(tracklets); //mTracklets.insert(mTracklets.back(),start,end); + added = true; + } + } + if (!added) { + // unseen ir so add it + mEventRecords.push_back(ir); + mEventRecords.back().addTracklets(tracklets); + } +} +void EventStorage::addTracklets(InteractionRecord& ir, std::vector<Tracklet64>::iterator& start, std::vector<Tracklet64>::iterator& end) +{ + bool added = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + //TODO replace this with a hash/map not a vector + mEventRecords[count].addTracklets(start, end); //mTracklets.insert(mTracklets.back(),start,end); + added = true; + } + } + if (!added) { + // unseen ir so add it + mEventRecords.push_back(ir); + mEventRecords.back().addTracklets(start, end); + // LOG(info) << "x unknown ir adding " << std::distance(start,end)<< " tracklets"; + } +} +void EventStorage::unpackData(std::vector<TriggerRecord>& triggers, std::vector<Tracklet64>& tracklets, std::vector<Digit>& digits) +{ + int digitcount = 0; + int trackletcount = 0; + for (auto& event : mEventRecords) { + tracklets.insert(std::end(tracklets), std::begin(event.getTracklets()), std::end(event.getTracklets())); + digits.insert(std::end(digits), std::begin(event.getDigits()), std::end(event.getDigits())); + triggers.emplace_back(event.getBCData(), digitcount, event.getDigits().size(), trackletcount, event.getTracklets().size()); + digitcount += event.getDigits().size(); + trackletcount += event.getTracklets().size(); + } +} + +void EventStorage::sendData(o2::framework::ProcessingContext& pc, bool displaytracklets) +{ + //at this point we know the total number of tracklets and digits and triggers. + auto dataReadStart = std::chrono::high_resolution_clock::now(); + uint64_t trackletcount = 0; + uint64_t digitcount = 0; + uint64_t triggercount = 0; + sumTrackletsDigitsTriggers(trackletcount, digitcount, triggercount); + std::vector<Tracklet64> tracklets; + tracklets.reserve(trackletcount); + std::vector<Digit> digits; + digits.reserve(digitcount); + std::vector<TriggerRecord> triggers; + triggers.reserve(triggercount); + for (auto& event : mEventRecords) { + //sort tracklets + event.sortByHCID(); + //TODO do this sort in parallel over the events + tracklets.insert(std::end(tracklets), std::begin(event.getTracklets()), std::end(event.getTracklets())); + digits.insert(std::end(digits), std::begin(event.getDigits()), std::end(event.getDigits())); + triggers.emplace_back(event.getBCData(), digitcount, event.getDigits().size(), trackletcount, event.getTracklets().size()); + digitcount += event.getDigits().size(); + trackletcount += event.getTracklets().size(); + } + if (displaytracklets) { // this is purely for trivial debugging purposes + for (auto& event : mEventRecords) { + LOG(info) << "***** Event : " << event.getBCData() << " digit count : " << event.getDigits().size() << " tracklet count : " << event.getTracklets().size(); + auto& trackletv = event.getTracklets(); + for (auto& tracklt : trackletv) { + LOG(info) << " " << std::distance(trackletv.begin(), trackletv.end()) << " " << tracklt; + } + LOG(info) << "*****"; + } + } + LOG(info) << "Sending data onwards with " << digits.size() << " Digits and " << tracklets.size() << " Tracklets and " << triggers.size() << " Triggers"; + //TODO change to adopt instead of having this additional copy. + // + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTRD, "DIGITS", 0, o2::framework::Lifetime::Timeframe}, digits); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTRD, "TRACKLETS", 0, o2::framework::Lifetime::Timeframe}, tracklets); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTRD, "TRKTRGRD", 0, o2::framework::Lifetime::Timeframe}, triggers); + std::chrono::duration<double, std::micro> dataReadTime = std::chrono::high_resolution_clock::now() - dataReadStart; + LOG(info) << "Preparing for sending and sending data took " << std::chrono::duration_cast<std::chrono::milliseconds>(dataReadTime).count() << "ms"; + if (mPackagingTime != nullptr) { + mPackagingTime->Fill((int)std::chrono::duration_cast<std::chrono::microseconds>(dataReadTime).count()); + } +} + +int EventStorage::sumTracklets() +{ + int sum = 0; + for (auto event : mEventRecords) { + sum += event.getTracklets().size(); + } + return sum; +} +int EventStorage::sumDigits() +{ + int sum = 0; + for (auto event : mEventRecords) { + sum += event.getDigits().size(); + } + return sum; +} +void EventStorage::sumTrackletsDigitsTriggers(uint64_t& tracklets, uint64_t& digits, uint64_t& triggers) +{ + int digitsum = 0; + int trackletsum = 0; + int triggersum = 0; + for (auto event : mEventRecords) { + digitsum += event.getDigits().size(); + trackletsum += event.getTracklets().size(); + triggersum++; + } +} + +std::vector<Tracklet64>& EventStorage::getTracklets(InteractionRecord& ir) +{ + bool found = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + found = true; + return mEventRecords[count].getTracklets(); + } + } + LOG(warn) << "attempted to get tracklets from IR: " << ir << " total tracklets of:" << sumTracklets(); + printIR(); + return mDummyTracklets; +} + +std::vector<Digit>& EventStorage::getDigits(InteractionRecord& ir) +{ + bool found = false; + for (int count = 0; count < mEventRecords.size(); ++count) { + if (ir == mEventRecords[count].getBCData()) { + found = true; + return mEventRecords[count].getDigits(); + } + } + LOG(warn) << "attempted to get digits from IR: " << ir << " total digits of:" << sumDigits(); + printIR(); + return mDummyDigits; +} + +void EventStorage::printIR() +{ + for (int count = 0; count < mEventRecords.size(); ++count) { + LOG(info) << "[" << count << "]" << mEventRecords[count].getBCData() << " "; + } +} + +EventRecord& EventStorage::getEventRecord(InteractionRecord& ir) +{ + //now find the event record in question + for (auto& event : mEventRecords) { + if (event == ir) { + return event; + } + } + //oops its new, so add it + mEventRecords.push_back(EventRecord(ir)); + return mEventRecords.back(); +} + +void EventRecord::popTracklets(int popcount) +{ + if (popcount > 3 || popcount < 0) { + LOG(error) << " been asked to pop more than 3 tracklets:" << popcount; + } else { + while (popcount > 0) { + mTracklets.pop_back(); + popcount--; + } + } +} + +} // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/src/TRDReconstructionLinkDef.h b/Detectors/TRD/reconstruction/src/TRDReconstructionLinkDef.h new file mode 100644 index 0000000000000..c85dd2d378ccb --- /dev/null +++ b/Detectors/TRD/reconstruction/src/TRDReconstructionLinkDef.h @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#endif diff --git a/Detectors/TRD/reconstruction/src/TrackletsParser.cxx b/Detectors/TRD/reconstruction/src/TrackletsParser.cxx new file mode 100644 index 0000000000000..29ca9928bd9f4 --- /dev/null +++ b/Detectors/TRD/reconstruction/src/TrackletsParser.cxx @@ -0,0 +1,385 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TrackletParser.h +/// @brief TRD raw data parser for Tracklet data format + +#include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/RawDataStats.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/HelperMethods.h" + +#include "TRDReconstruction/TrackletsParser.h" +#include "TRDReconstruction/EventRecord.h" +#include "fairlogger/Logger.h" + +//TODO come back and figure which of below headers I actually need. +#include <cstring> +#include <string> +#include <vector> +#include <array> +#include <iomanip> +#include <iostream> +#include "TH1F.h" + +namespace o2::trd +{ + +inline void TrackletsParser::swapByteOrder(unsigned int& ui) +{ + ui = (ui >> 24) | + ((ui << 8) & 0x00FF0000) | + ((ui >> 8) & 0x0000FF00) | + (ui << 24); +} + +int TrackletsParser::Parse(std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>* data, + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator start, + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator end, + TRDFeeID feeid, int robside, int detector, int stack, int layer, + EventRecord* eventrecord, std::bitset<16> options, bool cleardigits, int usetracklethcheader) +{ + mStartParse = start; + mEndParse = end; + mDetector = detector; + mFEEID = feeid; + mRobSide = robside; + mStack = stack; + mLayer = layer; + mOptions = options; + setData(data); + setVerbose(options[TRDVerboseBit], options[TRDHeaderVerboseBit], options[TRDDataVerboseBit]); + setByteSwap(options[TRDByteSwapBit]); + mWordsRead = 0; + mWordsDumped = 0; + mTrackletsFound = 0; + mPaddingWordsCounter = 0; + mTrackletHCHeaderState = usetracklethcheader; //what to with the tracklet half chamber header 0,1,2 + mIgnoreTrackletHCHeader = options[TRDIgnoreTrackletHCHeaderBit]; + mEventRecord = eventrecord; + // mTracklets.clear(); + return Parse(); +} + +void TrackletsParser::OutputIncomingData() +{ + LOG(info) << "Data to parse for Tracklets from " << std::hex << mStartParse << " to " << mEndParse; + int wordcount = 0; + std::stringstream outputstring; + auto word = mStartParse; + outputstring << "tracklet 0x" << std::hex << std::setfill('0') << std::setw(6) << 0 << " :: "; + while (word <= mEndParse) { // loop over the entire data buffer (a complete link of tracklets and digits) + + if (wordcount != 0 && (wordcount % 8 == 0 || word == mEndParse)) { + LOG(info) << outputstring.str(); + outputstring.str(""); + outputstring << "tracklet 0x" << std::hex << std::setfill('0') << std::setw(6) << wordcount << " :: "; + } + if (wordcount == 0) { + outputstring << " 0x" << std::hex << std::setfill('0') << std::setw(8) << HelperMethods::swapByteOrderreturn(*word); + } else { + outputstring << " 0x" << std::hex << std::setfill('0') << std::setw(8) << HelperMethods::swapByteOrderreturn(*word); + } + word++; + wordcount++; + } + LOG(info) << "Data buffer to parse for Tracklets end"; + /*for (auto word = mStartParse; word != mEndParse; word+=8) { // loop over the entire data buffer (a complete link of tracklets and digits) + LOGP(info,"0x{0:08x} :: {1:08x} {2:08x} {3:08x} {4:08x} {5:08x} {6:08x} {7:08x} {8:08x} ",std::distance(mStartParse,word), + HelperMethods::swapByteOrderreturn(*word), HelperMethods::swapByteOrderreturn(*std::next(word,1)), + HelperMethods::swapByteOrderreturn(*std::next(word,2)), HelperMethods::swapByteOrderreturn(*std::next(word,3)), + HelperMethods::swapByteOrderreturn(*std::next(word,4)), HelperMethods::swapByteOrderreturn(*std::next(word,5)), + HelperMethods::swapByteOrderreturn(*std::next(word,6)), HelperMethods::swapByteOrderreturn(*std::next(word,7))); + } + LOG(info) << "Data to parse for Tracklets end";*/ +} + +int TrackletsParser::Parse() +{ + auto parsetimestart = std::chrono::high_resolution_clock::now(); // measure total processing time + //we are handed the buffer payload of an rdh and need to parse its contents. + //producing a vector of digits. + + mTrackletParsingBad = false; + if (mHeaderVerbose) { + OutputIncomingData(); + } + //mData holds a buffer containing tracklets parse placing tracklets in the output vector. + //mData holds 2048 digits. + mCurrentLink = 0; + mWordsRead = 0; + mTrackletsFound = 0; + if (mTrackletHCHeaderState == 0) { //TODO move this to the reader as done for the digithcheader + // tracklet hc header is never present + mState = StateTrackletMCMHeader; + } else { + if (mTrackletHCHeaderState == 1) { + auto nextword = std::next(mStartParse); + if (*nextword != constants::TRACKLETENDMARKER) { + //we have tracklet data so no TracletHCHeader + mState = StateTrackletHCHeader; + } else { + //we have no tracklet data so no TracletHCHeader + mState = StateTrackletMCMHeader; + } + } else { + if (mTrackletHCHeaderState != 2) { + LOG(warn) << "unknwon TrackletHCHeaderState of " << mIgnoreTrackletHCHeader; + } + // tracklet hc header is always present + mState = StateTrackletHCHeader; // we start with a trackletMCMHeader + } + } + + int currentLinkStart = 0; + int mcmtrackletcount = 0; + int trackletloopcount = 0; + int headertrackletcount = 0; + bool ignoreDataTillTrackletEndMarker = false; // used for when we need to dump the rest of the tracklet data. + for (auto word = mStartParse; word < mEndParse; ++word) { // loop over the entire data buffer (a complete link of tracklets and digits) + + if (mState == StateFinished) { + mTrackletparsetime += std::chrono::high_resolution_clock::now() - parsetimestart; + return mWordsRead; + } + //loop over all the words ... + //check for tracklet end marker 0x1000 0x1000 + int index = std::distance(mStartParse, word); + int indexend = std::distance(word, mEndParse); + std::array<uint32_t, o2::trd::constants::HBFBUFFERMAX>::iterator nextword = word; + std::advance(nextword, 1); + uint32_t nextwordcopy = *nextword; + + if (mByteOrderFix) { + swapByteOrder(*word); + swapByteOrder(nextwordcopy); + } + + if (*word == 0x10001000 && nextwordcopy == 0x10001000) { + if (!StateTrackletEndMarker && !StateTrackletHCHeader) { + LOG(warn) << "State should be trackletend marker current ?= end marker ?? " << mState << " ?=" << StateTrackletEndMarker; + } + + mWordsRead += 2; + + if (mHeaderVerbose) { + LOG(info) << "***TrackletEndMarker : 0x" << std::hex << *word << " and 0x" << nextwordcopy << " at offset " << std::distance(mStartParse, word); + } + + mState = StateFinished; + mTrackletparsetime += std::chrono::high_resolution_clock::now() - parsetimestart; + return mWordsRead; + } + if (*word == o2::trd::constants::CRUPADDING32) { + //padding word first as it clashes with the hcheader. + mState = StatePadding; + //LOG(warn) << "CRU Padding word while parsing tracklets. Corrupt data dumping the rest of this link"; + //mEventRecord.ErrorStats[TRDParsingTrackletCRUPaddingWhileParsingTracklets]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletCRUPaddingWhileParsingTracklets); + increment2dHist(TRDParsingTrackletCRUPaddingWhileParsingTracklets); + } + //TOOD replace warning with stats increment + mWordsDumped = std::distance(word, mEndParse); + ignoreDataTillTrackletEndMarker = true; + //mWordsRead++; + word = mEndParse; + //TODO remove tracklets already added erroneously + continue; // bail out + //dumping data + + } else { + if (ignoreDataTillTrackletEndMarker) { + mWordsDumped++; + //LOG(info) << "ignoring till end marker ..... word read:0x"<<std::hex << *word << " at offset 0x"<< std::distance(mStartParse,word); + //TODO increment counter instead of above log message + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletBit11NotSetInTrackletHCHeader); + increment2dHist(TRDParsingTrackletBit11NotSetInTrackletHCHeader); + } + continue; //go back to the start of loop, walk the data till the above code of the tracklet end marker is hit, padding is hit or we get to the end of the data. + //TODO might be good to check for end of digit marker as well? + } + //now for Tracklet hc header + if ((((*word) & (0x1 << 11)) != 0) && !mIgnoreTrackletHCHeader && mState == StateTrackletHCHeader) { //TrackletHCHeader has bit 11 set to 1 always. Check for state because raw data can have bit 11 set! + if (mState != StateTrackletHCHeader) { + // LOG(warn) << "Something wrong with TrackletHCHeader bit 11 is set but state is not " << StateTrackletMCMHeader << " its :" << mState; + //TODO count remove warning + //mEventRecord.ErrorStats[TRDParsingTrackletBit11NotSetInTrackletHCHeader]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletBit11NotSetInTrackletHCHeader); + increment2dHist(TRDParsingTrackletBit11NotSetInTrackletHCHeader); + } + } + //read the header + if (mHeaderVerbose) { + LOG(info) << "*** TrackletHCHeader : 0x" << std::hex << *word << " at offset :0x" << std::distance(mStartParse, word); + } + //we actually have a header word. + mTrackletHCHeader = (TrackletHCHeader*)&word; + //sanity check of trackletheader ?? + if (!trackletHCHeaderSanityCheck(*mTrackletHCHeader)) { + // LOG(warn) << "Sanity check Failure HCHeader : " << std::hex << *word << " at offset :0x" << std::distance(mStartParse, word); + //TODO count remove warning + //mEventRecord.ErrorStats[TRDParsingTrackletHCHeaderSanityCheckFailure]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletHCHeaderSanityCheckFailure); + increment2dHist(TRDParsingTrackletHCHeaderSanityCheckFailure); + } + } + mWordsRead++; + mState = StateTrackletMCMHeader; // now we should read a MCMHeader next time through loop + } else { //not TrackletHCHeader + if (((*word) & 0x80000001) == 0x80000001 && mState == StateTrackletMCMHeader) { //TrackletMCMHeader has the bits on either end always 1 + //mcmheader + mTrackletMCMHeader = (TrackletMCMHeader*)&(*word); + if (mHeaderVerbose) { + LOG(info) << "***TrackletMCMHeader : 0x" << std::hex << *word << " at offset: 0x" << std::distance(mStartParse, word); + TrackletMCMHeader a; + a.word = *word; + printTrackletMCMHeader(a); + } + if (!trackletMCMHeaderSanityCheck(*mTrackletMCMHeader)) { + // LOG(warn) << "***TrackletMCMHeader SanityCheckFailure: 0x" << std::hex << *word << " at offset: 0x" << std::distance(mStartParse, word); + //mEventRecord.ErrorStats[TRDParsingTrackletMCMHeaderSanityCheckFailure]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletMCMHeaderSanityCheckFailure); + increment2dHist(TRDParsingTrackletMCMHeaderSanityCheckFailure); + } + } + headertrackletcount = getNumberofTracklets(*mTrackletMCMHeader); + if (headertrackletcount > 0) { + mState = StateTrackletMCMData; // afrter reading a header we should then have data for next round through the loop + } else { + mState = StateTrackletMCMHeader; + } + + mcmtrackletcount = 0; + mWordsRead++; + } else { + if (mState == StateTrackletMCMHeader || (mState == StateTrackletHCHeader && !mOptions[mIgnoreTrackletHCHeader])) { + // if we are here something is wrong, dump the data. The else of line 227 should imply we are in StateTrackletMCMData; + ignoreDataTillTrackletEndMarker = true; + //mEventRecord.ErrorStats[ + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletStateMCMHeaderButParsingMCMData); + increment2dHist(TRDParsingTrackletStateMCMHeaderButParsingMCMData); + } + //mWordsRead++; + mWordsDumped = std::distance(word, mEndParse); + ignoreDataTillTrackletEndMarker = true; + word = mEndParse; + continue; + } + mState = StateTrackletMCMData; + //tracklet data; + mTrackletMCMData = (TrackletMCMData*)&(*word); + mWordsRead++; + if (mHeaderVerbose) { + LOG(info) << "*** TrackletMCMData : 0x" << std::hex << *word << " at offset :0x" << std::distance(mStartParse, word); + printTrackletMCMData(*mTrackletMCMData); + } + // do we have more tracklets than the header allows? + if (headertrackletcount < mcmtrackletcount) { + ignoreDataTillTrackletEndMarker = true; + //dump the rest of the data ... undo any tracklets already written? + //cant dump till mEndParse and digits are after the tracklets + //we can assume the mcmtrackletcountth (n from the end) last tracklets in the vector are to be removed. + //mEventRecord.ErrorStats[TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader); + increment2dHist(TRDParsingTrackletTrackletCountGTThatDeclaredInMCMHeader); + } + mEventRecord->popTracklets(mcmtrackletcount); // our format is always 4 + //TODO count remove warning + } + // take the header and this data word and build the underlying 64bit tracklet. + int q0, q1, q2; + int qa, qb; + switch (mcmtrackletcount) { + case 0: + qa = mTrackletMCMHeader->pid0; + break; + case 1: + qa = mTrackletMCMHeader->pid1; + break; + case 2: + qa = mTrackletMCMHeader->pid2; + break; + default: + LOG(warn) << "mcmtrackletcount is not in [0:2] count=" << mcmtrackletcount << " headertrackletcount=" << headertrackletcount << " something very wrong parsing the TrackletMCMData fields with data of : 0x" << std::hex << mTrackletMCMData->word; + //mEventRecord.ErrorStats[TRDParsingTrackletInvalidTrackletCount]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletInvalidTrackletCount); + increment2dHist(TRDParsingTrackletInvalidTrackletCount); + } + //this should have been caught above by the headertrackletcount to mcmtrackletcount + ignoreDataTillTrackletEndMarker = true; + break; + } + if (!ignoreDataTillTrackletEndMarker) { + q0 = getQFromRaw(mTrackletMCMHeader, mTrackletMCMData, 0, mcmtrackletcount); + q1 = getQFromRaw(mTrackletMCMHeader, mTrackletMCMData, 1, mcmtrackletcount); + q2 = getQFromRaw(mTrackletMCMHeader, mTrackletMCMData, 2, mcmtrackletcount); + int padrow = mTrackletMCMHeader->padrow; + int col = mTrackletMCMHeader->col; + int pos = mTrackletMCMData->pos; + int slope = mTrackletMCMData->slope; + int hcid = mDetector * 2 + mRobSide; + if (mDataVerbose) { + if (mTrackletHCHeaderState) { + LOG(info) << "Tracklet HCID : " << hcid << " mDetector:" << mDetector << " robside:" << mRobSide << " " << mTrackletMCMHeader->padrow << ":" << mTrackletMCMHeader->col << " ---- " << mTrackletHCHeader->supermodule << ":" << mTrackletHCHeader->stack << ":" << mTrackletHCHeader->layer << ":" << mTrackletHCHeader->side << " rawhcheader : 0x" << std::hex << std::hex << mTrackletHCHeader->word; + } else { + LOG(info) << "Tracklet HCID : " << hcid << " mDetector:" << mDetector << " robside:" << mRobSide << " " << mTrackletMCMHeader->padrow << ":" << mTrackletMCMHeader->col; + } + } + //TODO cross reference hcid to somewhere for a check. mDetector is assigned at the time of parser init. + //mEventRecord.TrackletCounts[mcm][mcmtrackletcount]++; + mEventRecord->getTracklets().emplace_back(4, hcid, padrow, col, pos, slope, q0, q1, q2); // our format is always 4 + if (mDataVerbose) { + LOG(info) << "Tracklet added:" << 4 << "-" << hcid << "-" << padrow << "-" << col << "-" << pos << "-" << slope << "-" << q0 << ":" << q1 << ":" << q2; + Tracklet64 a(4, hcid, padrow, col, pos, slope, q0, q1, q2); + LOG(info) << "Tracklet added:" << a; + LOG(info) << "Tracklet64 output ended"; + } + mTrackletsFound++; + mcmtrackletcount++; + if (mcmtrackletcount == headertrackletcount) { // headertrackletcount and mcmtrackletcount are not zero based counting + // at the end of the tracklet output of this mcm + // next to come can either be an mcmheaderword or a trackletendmarker. + // check next word if its a trackletendmarker + auto nextdataword = std::next(word, 1); + // the check is unambigous between trackletendmarker and mcmheader + if ((*nextdataword) == constants::TRACKLETENDMARKER) { + mState = StateTrackletEndMarker; + } else { + mState = StateTrackletMCMHeader; + } + } + } + } + } + } // else + trackletloopcount++; + } //end of for loop + //sanity check + //LOG(warn) << " end of Trackelt parsing but we are exiting with out a tracklet end marker with " << mWordsRead << " 32bit words read"; + //mEventRecord.ErrorStats[TRDParsingTrackletExitingNoTrackletEndMarker]++; + if (mOptions[TRDEnableRootOutputBit]) { + mParsingErrors->Fill(TRDParsingTrackletExitingNoTrackletEndMarker); + increment2dHist(TRDParsingTrackletExitingNoTrackletEndMarker); + } + mTrackletparsetime += std::chrono::high_resolution_clock::now() - parsetimestart; + mTrackletParsingBad = true; + return mWordsRead; +} + +} // namespace o2::trd diff --git a/Detectors/TRD/simulation/CMakeLists.txt b/Detectors/TRD/simulation/CMakeLists.txt index 0292114818995..74fc0d27f2425 100644 --- a/Detectors/TRD/simulation/CMakeLists.txt +++ b/Detectors/TRD/simulation/CMakeLists.txt @@ -1,15 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - - -#add_compile_options(-O0 -g -fPIC) +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(TRDSimulation TARGETVARNAME targetName @@ -17,21 +15,23 @@ o2_add_library(TRDSimulation src/TRsim.cxx src/Digitizer.cxx src/TRDSimParams.cxx - src/TrapConfig.cxx - src/TrapConfigHandler.cxx + src/TrapConfig.cxx + src/TrapConfigHandler.cxx src/TrapSimulator.cxx src/Trap2CRU.cxx + src/PileupTool.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::SimulationDataFormat O2::TRDBase O2::DataFormatsTRD O2::DetectorsRaw) o2_target_root_dictionary(TRDSimulation HEADERS include/TRDSimulation/Detector.h include/TRDSimulation/TRsim.h include/TRDSimulation/Digitizer.h - include/TRDSimulation/TRDSimParams.h + include/TRDSimulation/TRDSimParams.h include/TRDSimulation/TrapConfig.h include/TRDSimulation/TrapConfigHandler.h include/TRDSimulation/Trap2CRU.h - include/TRDSimulation/TrapSimulator.h) + include/TRDSimulation/TrapSimulator.h + include/TRDSimulation/PileupTool.h) if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) @@ -47,5 +47,12 @@ o2_add_executable(trap2raw O2::DetectorsRaw O2::DetectorsCommonDataFormats O2::CommonUtils - O2::DataFormatsTRD + O2::DataFormatsTRD Boost::program_options) + +o2_add_test(PileupTool + SOURCES test/testPileupTool.cxx + COMPONENT_NAME trd + PUBLIC_LINK_LIBRARIES O2::TRDSimulation + ENVIRONMENT VMCWORKDIR=${CMAKE_BINARY_DIR}/stage + LABELS trd) diff --git a/Detectors/TRD/simulation/README.md b/Detectors/TRD/simulation/README.md new file mode 100644 index 0000000000000..8bbf21cb563c2 --- /dev/null +++ b/Detectors/TRD/simulation/README.md @@ -0,0 +1,83 @@ +<!-- doxy +\page refDetectorsTRDsimulation simulation +/doxy --> + +# TRD simulation cheat-sheet +## Using configurable params to pass additional options to the generator for generating specific events +- Generate events with an electron particle gun in |eta| < 0.84: +``` +o2-sim -m PIPE MAG TRD -n 1000 -g boxgen --configKeyValues 'BoxGun.pdg=11;BoxGun.eta[0]=-0.84;BoxGun.eta[1]=0.84' +``` +- Generate events with an electron particle gun with 0.5 < p < 2.5 GeV and |eta| < 0.84: +``` +o2-sim -m PIPE MAG TRD -n 1000 -g boxgen --configKeyValues 'BoxGun.pdg=11;BoxGun.eta[0]=-0.84;BoxGun.eta[1]=0.84;BoxGun.prange[0]=0.5;BoxGun.prange[1]=2.5' +``` +- Generate events with a pion particle gun in |eta| < 0.84: +``` +o2-sim -m PIPE MAG TRD -n 1000 -g boxgen --configKeyValues 'BoxGun.pdg=211;BoxGun.eta[0]=-0.84;BoxGun.eta[1]=0.84' +``` +- Generate events with a pion particle gun with p = 2 GeV and |eta| < 0.84: +``` +o2-sim -m PIPE MAG TRD -n 1000 -g boxgen --configKeyValues 'BoxGun.pdg=211;BoxGun.eta[0]=-0.84;BoxGun.eta[1]=0.84;BoxGun.prange[0]=2;BoxGun.prange[1]=2' +``` +## Using TRD specific configurable params +``` +--configKeyValues 'TRDSimParams.doTR=false;TRDSimParams.maxMCStepSize=0.1' +``` + +# Generate Raw data from MonteCarlo: + +``` +o2-trd-trap2raw +``` +This will convert the tracklets and digits in the current directory to a series of files containing the raw data as it would appear coming out of the cru. +There are multiple options : +- -d [ --input-file-digits ] default of trddigits.root + input Trapsim digits file, empty string to have no digits. +- -t [ --input-file-tracklets ] default of trdtracklets.root + input Trapsim tracklets file +- -l [ --fileper ] how to distrbute the data into raw files. + - all : 1 raw file + - halfcru : 1 file per cru end point, so 2 files per cru. + - cru : one file per cru + - sm: one file per supermodule +- -o [ --output-dir ] output directory for raw data defaults to local directory +- -x [ --trackletHCHeader ] include tracklet half chamber header (for run3, and not in run2) +- -e [ --no-empty-hbf ] do not create empty HBF pages (except for HBF starting TF) +- -r [ --rdh-version ] rdh version in use default of 6 +- --configKeyValues arg comma-separated configKeyValues + +default would then be the following : +``` +o2-trd-trap2raw -d trddigits.root -t trdtracklets.root -l halfcru -o ./ -x -r 6 -e +``` + +# Some technical details: +## Pileup implementation +There are two general cases: +**Case 1:** The first signal triggers the readout at `t=A`. The signal is read out for 30 time bins (3 microseconds). A second signal can arrive at `t=C`. The second signal will contribute to the tail of the first signal with `(B-C)*samplingRate` bins from its head. +``` +A B +********** + ********** + C D +``` +**Case 2:** A trigger happened in the past at `t<A`, but `A` is within the deadtime of the TRD so the detector can't trigger again and the signal isn't readout. Still, the signal can contribute to a future signal. When a new signal arrives at `t=C` that can trigger, the signal will be readout for 30 time bins and will have `(B-C)*samplingRate` bins from the tail of the previous signal onto it's head. +``` +A B +********** + ********** + C D +``` +We keep a deque of signals that is flushed when the detector gets a new trigger. All signals are stored in the deque and are pop from the front only when they are too old. A signal can contribute to two events, one in the past and one in the future. See for example **Case 3**: +``` +A B +********** + ********** + C D + ********** + E F +``` +In this example, we consider a trigger at `t=A`. The second signal contributes with `(B-C)*samplingRate` bins from its head onto the tail of the first signal. A third signal arrives at `t=E`, with `E>A+BUSY_TIME`, which can trigger the detector and be readout. The third signal will have `(D-E)*samplingRate` from the tail of the second signal onto its head. So, the requirement for a signal to be too old, and be dropped, is: +- new trigger arrives, and +- the time difference between the first time bin of the previous signal and the new trigger is greater than `READOUT_TIME`. diff --git a/Detectors/TRD/simulation/include/TRDSimulation/Detector.h b/Detectors/TRD/simulation/include/TRDSimulation/Detector.h index a943d6758155b..0341e0a96fce6 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/Detector.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,44 +17,9 @@ #include "SimulationDataFormat/BaseHits.h" #include "CommonUtils/ShmAllocator.h" -class FairVolume; - -namespace o2 -{ -namespace trd -{ -class HitType : public o2::BasicXYZQHit<float> -{ - public: - using BasicXYZQHit<float>::BasicXYZQHit; - HitType(float x, float y, float z, float lCol, float lRow, float lTime, float tof, int charge, int trackId, int detId, bool drift) - : mInDrift(drift), locC(lCol), locR(lRow), locT(lTime), BasicXYZQHit(x, y, z, tof, charge, trackId, detId){}; - bool isFromDriftRegion() const { return mInDrift; } - void setLocalC(float lCol) { locC = lCol; } - void setLocalR(float lRow) { locR = lRow; } - void setLocalT(float lTime) { locT = lTime; } - float getLocalC() const { return locC; } - float getLocalR() const { return locR; } - float getLocalT() const { return locT; } - - private: - bool mInDrift{false}; - float locC{-99}; // col direction in amplification or drift volume - float locR{-99}; // row direction in amplification or drift volume - float locT{-99}; // time direction in amplification or drift volume -}; -} // namespace trd -} // namespace o2 +#include "DataFormatsTRD/Hit.h" -#ifdef USESHM -namespace std -{ -template <> -class allocator<o2::trd::HitType> : public o2::utils::ShmAllocator<o2::trd::HitType> -{ -}; -} // namespace std -#endif +class FairVolume; namespace o2 { @@ -71,7 +37,7 @@ class Detector : public o2::base::DetImpl<Detector> void InitializeO2Detector() override; bool ProcessHits(FairVolume* v = nullptr) override; void Register() override; - std::vector<HitType>* getHits(int iColl) const + std::vector<Hit>* getHits(int iColl) const { if (iColl == 0) { return mHits; @@ -90,6 +56,8 @@ class Detector : public o2::base::DetImpl<Detector> /// copy constructor (used in MT) Detector(const Detector& rhs); + void InitializeParams(); + // defines/sets-up the sensitive volumes void defineSensitiveVolumes(); @@ -100,12 +68,14 @@ class Detector : public o2::base::DetImpl<Detector> // Create TR hits void createTRhit(int); - std::vector<HitType>* mHits = nullptr; ///!< Collection of TRD hits + std::vector<Hit>* mHits = nullptr; ///!< Collection of TRD hits float mFoilDensity; float mGasNobleFraction; float mGasDensity; + float mMaxMCStepDef; + bool mTRon; // Switch for TR simulation TRsim* mTR; // Access to TR simulation diff --git a/Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h b/Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h index 03b0203e438e7..8250165b393c4 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,10 +15,13 @@ #include "TRDSimulation/Detector.h" #include "TRDBase/Calibrations.h" -#include "TRDBase/Digit.h" -#include "TRDBase/MCLabel.h" #include "TRDBase/CommonParam.h" +#include "TRDBase/PadResponse.h" #include "TRDBase/DiffAndTimeStructEstimator.h" +#include "TRDSimulation/PileupTool.h" + +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/SignalArray.h" #include "DataFormatsTRD/Constants.h" #include "MathUtils/RandomRing.h" @@ -27,6 +31,7 @@ #include <deque> #include <unordered_map> #include <vector> +#include <string> namespace o2 { @@ -35,20 +40,10 @@ namespace trd class Geometry; class SimParam; -class PadPlane; -class TRDArraySignal; -class PadResponse; - -struct SignalArray { - double firstTBtime; // first TB time - std::array<float, constants::TIMEBINS> signals{}; // signals - std::unordered_map<int, int> trackIds; // tracks Ids associated to the signal - std::vector<MCLabel> labels; // labels associated to the signal - bool isDigit = false; // flag a signal converted to a digit -}; using DigitContainer = std::vector<Digit>; using SignalContainer = std::unordered_map<int, SignalArray>; +using MCLabel = o2::MCCompLabel; class Digitizer { @@ -57,28 +52,29 @@ class Digitizer ~Digitizer() = default; void init(); // setup everything - void process(std::vector<HitType> const&, DigitContainer&, o2::dataformats::MCTruthContainer<MCLabel>&); + void process(std::vector<Hit> const&); void flush(DigitContainer&, o2::dataformats::MCTruthContainer<MCLabel>&); + void dumpLabels(const SignalContainer&, o2::dataformats::MCTruthContainer<MCLabel>&); void pileup(); void setEventTime(double timeNS) { mTime = timeNS; } + void setTriggerTime(double t) { mCurrentTriggerTime = t; } void setEventID(int entryID) { mEventID = entryID; } void setSrcID(int sourceID) { mSrcID = sourceID; } void setCalibrations(Calibrations* calibrations) { mCalib = calibrations; } + void setCreateSharedDigits(bool flag) { mCreateSharedDigits = flag; } int getEventTime() const { return mTime; } int getEventID() const { return mEventID; } int getSrcID() const { return mSrcID; } - - // Trigger parameters - static constexpr double READOUT_TIME = 3000; // the time the readout takes, as 30 TB = 3 micro-s. - static constexpr double DEAD_TIME = 200; // trigger deadtime, 2 micro-s - static constexpr double BUSY_TIME = READOUT_TIME + DEAD_TIME; // the time for which no new trigger can be received in nanoseconds + bool getCreateSharedDigits() const { return mCreateSharedDigits; } + std::string dumpFlaggedChambers() const; private: Geometry* mGeo = nullptr; // access to Geometry - PadResponse* mPRF = nullptr; // access to PadResponse + PadResponse mPRF{}; // access to PadResponse SimParam* mSimParam = nullptr; // access to SimParam instance CommonParam* mCommonParam = nullptr; // access to CommonParam instance Calibrations* mCalib = nullptr; // access to Calibrations in CCDB + PileupTool pileupTool; // number of digitizer threads int mNumThreads = 1; @@ -89,18 +85,10 @@ class Digitizer std::vector<math_utils::RandomRing<>> mLogRandomRings; // pre-generated exp distributed random number std::vector<DiffusionAndTimeStructEstimator> mDriftEstimators; - double mTime = 0.; // time in nanoseconds - double mLastTime = -1; // negative, by default to flag the first event - double mCurrentTriggerTime = -1; // negative, by default to flag the first event - int mEventID = 0; - int mSrcID = 0; - - enum EventType { - kFirstEvent, - kPileupEvent, - kTriggerFired, - kEmbeddingEvent - }; + double mTime = 0.; // time in nanoseconds of the hits currently being processed + double mCurrentTriggerTime = 0.; // time in nanoseconds of the current trigger + int mEventID = 0; // event id + int mSrcID = 0; // source id // Digitization parameters static constexpr float AmWidth = Geometry::amThick(); // Width of the amplification region @@ -113,23 +101,25 @@ class Digitizer int mTimeBinTRFend = 0; // time bin TRF ends int mMaxTimeBins = 30; // Maximum number of time bins for processing signals, usually set at 30 tb = 3 microseconds int mMaxTimeBinsTRAP = 30; // Maximum number of time bins for processing adcs; should be read from the CCDB or the TRAP config + bool mCreateSharedDigits = true; // flag if copies should be created of digits from pads which are shared between MCMs // Digitization containers - std::vector<HitType> mHitContainer; // the container of hits in a given detector + std::vector<Hit> mHitContainer; // the container of hits in a given detector std::vector<MCLabel> mMergedLabels; // temporary label container std::array<SignalContainer, constants::MAXCHAMBER> mSignalsMapCollection; // container for caching signals over a timeframe std::deque<std::array<SignalContainer, constants::MAXCHAMBER>> mPileupSignals; // container for piled up signals + std::array<bool, constants::MAXCHAMBER> mFlagVdriftOutOfRange{}; // flag chambers in which the drift velocity is out of range for which a parameterization exists - void getHitContainerPerDetector(const std::vector<HitType>&, std::array<std::vector<HitType>, constants::MAXCHAMBER>&); + void getHitContainerPerDetector(const std::vector<Hit>&, std::array<std::vector<Hit>, constants::MAXCHAMBER>&); void setSimulationParameters(); // Digitization chain methods int triggerEventProcessing(DigitContainer&, o2::dataformats::MCTruthContainer<MCLabel>&); SignalContainer addSignalsFromPileup(); void clearContainers(); - bool convertHits(const int, const std::vector<HitType>&, SignalContainer&, int thread = 0); // True if hit-to-signal conversion is successful - bool convertSignalsToADC(SignalContainer&, DigitContainer&, int thread = 0); // True if signal-to-ADC conversion is successful - void addLabel(const o2::trd::HitType& hit, std::vector<o2::trd::MCLabel>&, std::unordered_map<int, int>&); + bool convertHits(const int, const std::vector<Hit>&, SignalContainer&, int thread = 0); // True if hit-to-signal conversion is successful + bool convertSignalsToADC(SignalContainer&, DigitContainer&, int thread = 0); // True if signal-to-ADC conversion is successful + void addLabel(const int&, std::vector<MCLabel>&, std::unordered_set<int>&); // add a MC label, check if trackId is already registered bool diffusion(float, float, float, float, float, float, double&, double&, double&, int thread = 0); // True if diffusion is applied successfully // Helpers for signal handling diff --git a/Detectors/TRD/simulation/include/TRDSimulation/PileupTool.h b/Detectors/TRD/simulation/include/TRDSimulation/PileupTool.h new file mode 100644 index 0000000000000..5ad5b5620e152 --- /dev/null +++ b/Detectors/TRD/simulation/include/TRDSimulation/PileupTool.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRD_PILEUPTOOL_H_ +#define ALICEO2_TRD_PILEUPTOOL_H_ + +#include "DataFormatsTRD/SignalArray.h" // for SignalArray +#include "DataFormatsTRD/Constants.h" + +#include <array> +#include <deque> +#include <unordered_map> + +namespace o2 +{ +namespace trd +{ + +using SignalContainer = std::unordered_map<int, SignalArray>; + +struct PileupTool { + SignalContainer addSignals(std::deque<std::array<SignalContainer, constants::MAXCHAMBER>>&, const double&); +}; + +} // namespace trd +} // namespace o2 +#endif diff --git a/Detectors/TRD/simulation/include/TRDSimulation/TRDSimParams.h b/Detectors/TRD/simulation/include/TRDSimulation/TRDSimParams.h index 420ef04d026b0..9be3e46f69956 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/TRDSimParams.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/TRDSimParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,10 +23,13 @@ namespace trd { // Global parameters for TRD simulation / digitization +/* + See https://github.com/AliceO2Group/AliceO2/blob/dev/Common/SimConfig/doc/ConfigurableParam.md +*/ struct TRDSimParams : public o2::conf::ConfigurableParamHelper<TRDSimParams> { - - int digithreads = 4; // number of digitizer threads - + int digithreads = 4; // number of digitizer threads + float maxMCStepSize = 0.1; // maximum size of MC steps + bool doTR = true; // switch for transition radiation O2ParamDef(TRDSimParams, "TRDSimParams"); }; diff --git a/Detectors/TRD/simulation/include/TRDSimulation/TRsim.h b/Detectors/TRD/simulation/include/TRDSimulation/TRsim.h index f182e1d4f05a9..9c7eb8b61f24d 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/TRsim.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/TRsim.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h b/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h index c1e672262b1bd..f3e0e0dc09494 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "DataFormatsTRD/LinkRecord.h" #include "DataFormatsTRD/RawData.h" #include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/Digit.h" //#include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RawFileWriter.h" @@ -33,63 +35,90 @@ namespace trd class Trap2CRU { - static constexpr int NumberOfCRU = 36; - static constexpr int NumberOfHalfCRU = 72; - static constexpr int NumberOfFLP = 12; - static constexpr int CRUperFLP = 3; - static constexpr int WordSizeInBytes = 256; // word size in bits, everything is done in 256 bit blocks. - static constexpr int WordSize = 8; // 8 standard 32bit words. - static constexpr int NLinksPerHalfCRU = 15; // number of fibers per each half cru - static constexpr int TRDLinkID = 15; // hard coded link id. TODO give reason? - static constexpr uint32_t PaddWord = 0xeeee; // pad word to fill 256bit blocks or entire block for no data case. - static constexpr bool DebugDataWriting = false; //dump put very first vector of data to see if the thing going into the rawwriter is correct. - //TODO come back and change the mapping of 1077 channels to a lut addnd probably configurable. - // public: Trap2CRU() = default; - Trap2CRU(const std::string& outputDir, const std::string& inputFilename); - void readTrapData(const std::string& otuputDir, const std::string& inputFilename, int superPageSizeInB); - void convertTrapData(o2::trd::TriggerRecord const& TrigRecord); + Trap2CRU(const std::string& outputDir, const std::string& inputDigitsFilename, const std::string& inputTrackletsFilename); + //Trap2CRU(const std::string& outputDir, const std::string& inputFilename, const std::string& inputDigitsFilename, const std::string& inputTrackletsFilename); + void readTrapData(); + void convertTrapData(o2::trd::TriggerRecord const& trigrecord, const int& triggercount); // default for now will be file per half cru as per the files Guido did for us. - // TODO come back and give users a choice. - // void setFilePerLink(){mfileGranularity = mgkFilesPerLink;}; - // bool getFilePerLink(){return (mfileGranularity==mgkFilesPerLink);}; - // void setFilePerHalfCRU(){mfileGranularity = mgkFilesPerHalfCRU;}; - // bool getFilePerHalfCRU(){return (mfileGranularity==mgkFilesPerHalfCRU);}; // + void setFilePer(std::string fileper) { mFilePer = fileper; }; + std::string getFilePer() { return mFilePer; }; + void setOutputDir(std::string outdir) { mOutputDir = outdir; }; + std::string getOutputDir() { return mOutputDir; }; + void setDigitRate(int digitrate) { mDigitRate = digitrate; }; + int getDigitRate() { return mDigitRate; }; int getVerbosity() { return mVerbosity; } void setVerbosity(int verbosity) { mVerbosity = verbosity; } - void buildCRUPayLoad(); - int sortByORI(); + void sortDataToLinks(); o2::raw::RawFileWriter& getWriter() { return mWriter; } - uint32_t buildCRUHeader(HalfCRUHeader& header, uint32_t bc, uint32_t halfcru, int startlinkrecord); - void linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_t& padding); + uint32_t buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru); // build the half cru header holding the lengths of all links amongst other things. + void linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_t& padding); // pad the link data stream to align with 256 bit words. + void openInputFiles(); + void setTrackletHCHeader(int tracklethcheader) { mUseTrackletHCHeader = tracklethcheader; } + bool isTrackletOnLink(int link, int trackletpos); // is the current tracklet on the the current link + bool isDigitOnLink(int link, int digitpos); // is the current digit on the current link + int buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggercount); + int buildTrackletRawData(const int trackletindex, const int linkid); // from the current position in the tracklet vector, build the outgoing data for the current mcm the tracklet is on. + int writeDigitEndMarker(); // write the digit end marker 0x0 0x0 + int writeTrackletEndMarker(); // write the tracklet end maker 0x10001000 0x10001000 + int writeDigitHCHeader(const int eventcount, uint32_t linkid); // write the Digit HalfChamberHeader into the stream, after the tracklet endmarker and before the digits. + int writeTrackletHCHeader(const int eventcount, uint32_t linkid); // write the Tracklet HalfChamberHeader into the stream, at the beginning of data iff there is tracklet data. + + bool digitindexcompare(const o2::trd::Digit& A, const o2::trd::Digit& B); + //boohhl digitindexcompare(const unsigned int A, const unsigned int B); + o2::trd::Digit& getDigitAt(const int i) { return mDigits[mDigitsIndex[i]]; }; + + void mergetriggerDigitRanges(); private: int mfileGranularity; /// per link or per half cru for each file - uint32_t mLinkID; - uint16_t mCruID; - uint64_t mFeeID; - uint32_t mEndPointID; - std::string mInputFilename; - std::string mOutputFilename; - int mVerbosity = 0; - HalfCRUHeader mHalfCRUHeader; - TrackletMCMHeader mTrackletMCMHeader; - TrackletMCMData mTrackletMCMData; - + uint32_t mLinkID; // always 15 for TRD + uint16_t mCruID; // built into the FeeID + uint64_t mFeeID; // front end id defining the cru sm:8 bits, blank 3 bits, side:1,blank 3 bits, end point:1 + uint32_t mEndPointID; // end point on the cru in question, there are 2 pci end points per cru + std::string mFilePer; // how to split up the raw data files, sm:per supermodule, halfcru: per half cru, cru: per cru, all: singular file. + // std::string mInputFileName; + std::string mOutputFileName; + int mVerbosity{0}; + std::string mOutputDir; + uint32_t mSuperPageSizeInB; + int mDigitRate = 1000; + int mEventDigitCount = 0; + //HalfCRUHeader mHalfCRUHeader; + //TrackletMCMHeader mTrackletMCMHeader; + // TrackletMCMData mTrackletMCMData; + int mUseTrackletHCHeader{0}; std::vector<char> mRawData; // store for building data event for a single half cru uint32_t mRawDataPos = 0; - TFile* mTrapRawFile; - TTree* mTrapRawTree; // incoming data tree + char* mRawDataPtr{nullptr}; // locations to store the incoming data branches - std::vector<o2::trd::LinkRecord> mLinkRecords, *mLinkRecordsPtr = &mLinkRecords; - std::vector<o2::trd::TriggerRecord> mTriggerRecords, *mTriggerRecordsPtr = &mTriggerRecords; - std::vector<uint32_t> mTrapRawData, *mTrapRawDataPtr = &mTrapRawData; + + // incoming digit information + std::string mInputDigitsFileName; + TFile* mDigitsFile; + TTree* mDigitsTree; + std::vector<Digit> mDigits, *mDigitsPtr = &mDigits; + std::vector<uint32_t> mDigitsIndex; + std::vector<o2::trd::TriggerRecord> mDigitTriggerRecords; + std::vector<o2::trd::TriggerRecord>* mDigitTriggerRecordsPtr = &mDigitTriggerRecords; + + //incoming tracklet information + std::string mInputTrackletsFileName; + TFile* mTrackletsFile; + TTree* mTrackletsTree; + std::vector<Tracklet64> mTracklets; + std::vector<Tracklet64>* mTrackletsPtr = &mTracklets; + std::vector<uint32_t> mTrackletsIndex; + std::vector<o2::trd::TriggerRecord> mTrackletTriggerRecords; + std::vector<o2::trd::TriggerRecord>* mTrackletTriggerRecordsPtr = &mTrackletTriggerRecords; + uint64_t mCurrentTracklet{0}; //the tracklet we are currently busy adding + uint64_t mCurrentDigit{0}; //the digit we are currently busy adding const o2::raw::HBFUtils& mSampler = o2::raw::HBFUtils::Instance(); o2::raw::RawFileWriter mWriter{"TRD"}; - ClassDefNV(Trap2CRU, 1); + ClassDefNV(Trap2CRU, 3); }; } // end namespace trd diff --git a/Detectors/TRD/simulation/include/TRDSimulation/TrapConfig.h b/Detectors/TRD/simulation/include/TRDSimulation/TrapConfig.h index 8f527eb3063d3..e867f195fbe69 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/TrapConfig.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/TrapConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/simulation/include/TRDSimulation/TrapConfigHandler.h b/Detectors/TRD/simulation/include/TRDSimulation/TrapConfigHandler.h index bd3738fbc1529..2345957a14eca 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/TrapConfigHandler.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/TrapConfigHandler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,8 +20,6 @@ #include <string> #include "TRDBase/CalOnlineGainTables.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "TRDBase/MCLabel.h" namespace o2 { diff --git a/Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h b/Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h index 76bfd284d3c5f..1829a5d18420b 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,17 +24,13 @@ #include <fstream> #include <gsl/span> -#include "TRDBase/Tracklet.h" #include "TRDBase/FeeParam.h" -#include "TRDBase/Digit.h" -#include "TRDBase/Tracklet.h" #include "TRDSimulation/Digitizer.h" -#include "TRDSimulation/TrapConfigHandler.h" //TODO I think i can dump this. #include "TRDSimulation/TrapConfig.h" -#include "TRDBase/MCLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -//#include "DataFormatsTRD/RawData.h" + +#include "DataFormatsTRD/Digit.h" #include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/RawData.h" #include "DataFormatsTRD/Constants.h" class TH2F; @@ -46,7 +43,7 @@ namespace trd class TrapSimulator { public: - TrapSimulator(); + TrapSimulator() = default; ~TrapSimulator() = default; enum { PRINTRAW = 1, @@ -57,12 +54,13 @@ class TrapSimulator PLOTHITS = 2, PLOTTRACKLETS = 4 }; - void init(TrapConfig* trapconfig, int det, int rob, int mcm); // Initialize MCM by the position parameters + void init(TrapConfig* trapconfig, int det, int rob, int mcm); + + bool checkInitialized() const { return mInitialized; } - void reset(); // clears filter registers and internal data - void clear(); + void reset(); // void setDebugStream(TTreeSRedirector* stream) { mDebugStream = stream; } // TTreeSRedirector* getDebugStream() const { return mDebugStream; } @@ -70,31 +68,16 @@ class TrapSimulator void noiseTest(int nsamples, int mean, int sigma, int inputGain = 1, int inputTail = 2); - bool CalibrateRun2(); int getDataRaw(int iadc, int timebin) const { return (mADCR[iadc * mNTimeBin + timebin]); } // >> 2); } // get unfiltered ADC data int getDataFiltered(int iadc, int timebin) const { return (mADCF[iadc * mNTimeBin + timebin]); } // >> 2); } // get filtered ADC data int getZeroSupressionMap(int iadc) const { return (mZSMap[iadc]); } bool isDataSet() { return mDataIsSet; }; - void unsetData() - { - mDataIsSet = false; - for (auto& fitreg : mFitReg) { - fitreg.ClearReg(); - } - mNHits = 0; - mADCFilled = 0; - for (auto& tmplabel : mADCLabels) { - tmplabel.clear(); // clear MC Labels sent in from the digits coming in. - } - mTrackletLabels.clear(); // clear the stored labels. - mTrackletArray.clear(); - mTrackletArray64.clear(); - }; - // void setData(int iadc, const std::vector<int>& adc); // set ADC data with array - void setData(int iadc, const ArrayADC& adc, std::vector<o2::MCCompLabel>& labels); // set ADC data with array - //void setData(int iadc, const ArrayADC& adc, gsl::span<o2::MCCompLabel,-1>& labels); // set ADC data with array + // set ADC data with array + void setData(int iadc, const ArrayADC& adc, unsigned int digitIdx); + // set ADC data with array + //void setData(int iadc, const ArrayADC& adc, gsl::span<o2::MCCompLabel,-1>& labels); void setBaselines(); // set the baselines as done in setDataByPad which is bypassed due to using setData in line above. void setData(int iadc, int it, int adc); // set ADC data void setDataFromDigitizerAndRun(std::vector<o2::trd::Digit>& data, o2::dataformats::MCTruthContainer<MCLabel>&); // data coming in manually from the the digitizer. @@ -123,8 +106,6 @@ class TrapSimulator // for the ADC/Col mapping, see: http://wiki.kip.uni-heidelberg.de/ti/TRD/index.php/Image:ROB_MCM_numbering.pdf const int getNumberOfTimeBins() const { return mNTimeBin; }; bool storeTracklets(); // Stores tracklets to file -- debug purposes - std::string getTrklBranchName() const { return mTrklBranchName; } - void setTrklBranchName(std::string name) { mTrklBranchName = name; } int packData(std::vector<uint32_t>& rawdata, uint32_t offset); int getRawStream(std::vector<uint32_t>& buf, uint32_t offset, unsigned int iEv = 0) const; // Produce raw data stream - Real data format @@ -160,7 +141,11 @@ class TrapSimulator int getNHits() const { return mHits.size(); } bool getHit(int index, int& channel, int& timebin, int& qtot, int& ypos, float& y) const; - //o2::trd::TrapSimulator::Hit& getHit(int index) const; + + // getters for calculated tracklets + labels + std::vector<Tracklet64>& getTrackletArray64() { return mTrackletArray64; } + std::vector<unsigned short>& getTrackletDigitCount() { return mTrackletDigitCount; } + std::vector<unsigned int>& getTrackletDigitIndices() { return mTrackletDigitIndices; } // data display void print(int choice) const; // print stored data to stdout @@ -207,12 +192,6 @@ class TrapSimulator static constexpr int mQ2Startbin = 3; // Start range of Q2, for now here. TODO pull from a revised TrapConfig? static constexpr int mQ2Endbin = 5; // End range of Q2, also pull from a revised trapconfig at some point. - std::vector<Tracklet>& getTrackletArray() { return mTrackletArray; } - std::vector<Tracklet64>& getTrackletArray64() { return mTrackletArray64; } - void getTracklet64s(std::vector<Tracklet64>& TrackletStore); // place the trapsim 64 bit tracklets nto the incoming vector - o2::dataformats::MCTruthContainer<o2::MCCompLabel>& getTrackletLabels() { return mTrackletLabels; } - - bool checkInitialized() const; // Check whether the class is initialized static const int mgkFormatIndex; // index for format settings in stream //TODO should this change to 3 for the new format ????? I cant remember now, ask someone. static const int mgkAddDigits = 2; // additional digits used for internal representation of ADC data @@ -240,9 +219,10 @@ class TrapSimulator mQtot = 0; mYpos = 0; } - }; //mHits[mgkNHitsMC]; - //std::array<Hit, 50> mHits; + }; + std::array<Hit, mgkNHitsMC> mHits{}; // was 100 in the run2 via fgkNHitsMC; + class FilterReg { public: @@ -271,7 +251,7 @@ class TrapSimulator int mNhits; // number of hits unsigned int mQ0; // charge accumulated in first window unsigned int mQ1; // charge accumulated in second window - unsigned int mQ2; // charge accumulated in some other windows TODO find or write the documentation for window3 + unsigned int mQ2; // charge accumulated in third windows currently timebin 3 to 5 unsigned int mSumX; // sum x int mSumY; // sum y unsigned int mSumX2; // sum x**2 @@ -289,44 +269,97 @@ class TrapSimulator mSumY2 = 0; mSumXY = 0; } + void Print() + { + LOG(info) << "FitReg : "; + LOG(info) << "\t Q 0:1:2 : " << mQ0 << ":" << mQ1 << ":" << mQ2; + LOG(info) << "\t SumX:SumY:SumX2:SumY2:SumXY : " << mSumX << ":" << mSumY << ":" << mSumX2 << ":" << mSumY2 << ":" << mSumXY; + } }; std::array<FitReg, constants::NADCMCM> mFitReg{}; + //class to store the tracklet details that are not stored in tracklet64. + //used for later debugging purposes or in depth analysis of some part of tracklet creation or properties. + class TrackletDetail + { + public: + TrackletDetail() = default; + TrackletDetail(float slope, float position, int q0, int q1, int q2, std::array<int, 3> hits, float error) + { + mSlope = slope; + mPosition = position; + mError = error; + mCharges[0] = q0; + mCharges[1] = q1; + mCharges[2] = q2; + mPidHits = hits; + }; + ~TrackletDetail() = default; + std::array<int, 3> mPidHits; // no. of contributing clusters in each pid window. + std::array<int, 3> mCharges; // Q0,Q1,Q2, charges in each pid window. + float mSlope; // tracklet slope + float mPosition; // tracklet offset + float mError; // tracklet error + int mNClusters; // no. of clusters + std::vector<float> mResiduals; //[mNClusters] cluster to tracklet residuals + std::vector<float> mClsCharges; //[mNClusters] cluster charge + void clear() + { + mPidHits[0] = 0; + mPidHits[1] = 0; + mPidHits[2] = 0; + mCharges[0] = 0; + mCharges[1] = 0; + mCharges[2] = 0; + mSlope = 0; + mPosition = 0; + mError = 0; + mNClusters = 0; + mResiduals.clear(); + mClsCharges.clear(); + } + void setHits(std::array<int, 3> hits) { mPidHits = hits; } + + void setClusters(std::vector<float> res, std::vector<float> charges, int nclusters) + { + mResiduals = res; + mClsCharges = charges; + mNClusters = nclusters; + } + }; protected: void setNTimebins(int ntimebins); // allocate data arrays corr. to the no. of timebins - bool mInitialized; // memory is allocated if initialized - int mDetector; // Chamber ID - int mRobPos; // ROB Position on chamber - int mMcmPos; // MCM Position on chamber - int mRow; // Pad row number (0-11 or 0-15) of the MCM on chamber - int mNTimeBin; // Number of timebins currently allocated + bool mInitialized{false}; // memory is allocated if initialized + int mDetector{-1}; // Chamber ID + int mRobPos{-1}; // ROB Position on chamber + int mMcmPos{-1}; // MCM Position on chamber + int mRow{-1}; // Pad row number (0-11 or 0-15) of the MCM on chamber + int mNTimeBin{-1}; // Number of timebins currently allocated //TODO adcr adcf labels zerosupressionmap can all go into their own class. Refactor when stable. std::vector<int> mADCR; // Array with MCM ADC values (Raw, 12 bit) 2d with dimension mNTimeBin std::vector<int> mADCF; // Array with MCM ADC values (Filtered, 12 bit) 2d with dimension mNTimeBin - std::array<std::vector<o2::MCCompLabel>, constants::NADCMCM> mADCLabels{}; // MC Labels sent in from the digits coming in. + std::array<unsigned int, constants::NADCMCM> mADCDigitIndices{}; // indices of the incoming digits, used to relate the tracklets to labels in TRDTrapSimulatorSpec std::vector<unsigned int> mMCMT; // tracklet word for one mcm/trap-chip - std::vector<Tracklet> mTrackletArray; // Array of TRDtrackletMCM which contains MC information in addition to the tracklet word - std::vector<Tracklet64> mTrackletArray64; // Array of TRDtrackletMCM which contains MC information in addition to the tracklet word - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mTrackletLabels; + std::vector<Tracklet64> mTrackletArray64; // Array of 64 bit tracklets + std::vector<unsigned short> mTrackletDigitCount; // Keep track of the number of digits contributing to the tracklet (for MC labels) + std::vector<unsigned int> mTrackletDigitIndices; // For each tracklet the up to two global indices of the digits which contributed (global digit indices are managed in the TRDDPLTrapSimulatorTask class) + std::vector<TrackletDetail> mTrackletDetails; // store additional tracklet information for eventual debug output. std::vector<int> mZSMap; // Zero suppression map (1 dimensional projection) std::array<int, mgkNCPU> mFitPtr{}; // pointer to the tracklet to be calculated by CPU i - std::string mTrklBranchName; // name of the tracklet branch to write to - // Parameter classes - FeeParam* mFeeParam; // FEE parameters - TrapConfig* mTrapConfig; // TRAP config - TrapConfigHandler mTrapConfigHandler; + FeeParam* mFeeParam{FeeParam::instance()}; // FEE parameters, a singleton + TrapConfig* mTrapConfig{nullptr}; // TRAP config // CalOnlineGainTables mGainTable; static const int NOfAdcPerMcm = constants::NADCMCM; std::array<FilterReg, constants::NADCMCM> mInternalFilterRegisters; int mADCFilled = 0; // stores bitpattern of fillted adc, for know when to fill with pure baseline, for use with setData(int iadc, const ArrayADC& adc); - int mNHits; // Number of detected hits + int mNHits{0}; // Number of detected hits // Sort functions as in TRAP void sort2(unsigned short idx1i, unsigned short idx2i, unsigned short val1i, unsigned short val2i, @@ -354,12 +387,19 @@ class TrapSimulator static int mgAddBaseline; // add baseline to the ADC values static bool mgStoreClusters; // whether to store all clusters in the tracklets + + bool mdebugStream = false; // whether or not to keep all the additional info for eventual dumping to a tree. + bool mDataIsSet = false; - Calibrations* mCalib; + + std::array<TrackletMCMData, 3> mTracklets; + TrackletMCMHeader mMCMHeader; static constexpr bool debugheaders = false; }; std::ostream& operator<<(std::ostream& os, const TrapSimulator& mcm); +std::ostream& operator<<(std::ostream& os, TrapSimulator::FitReg& fitreg); + } //namespace trd } //namespace o2 #endif diff --git a/Detectors/TRD/simulation/src/Detector.cxx b/Detectors/TRD/simulation/src/Detector.cxx index dfed6e56c5c12..1b7b9df816497 100644 --- a/Detectors/TRD/simulation/src/Detector.cxx +++ b/Detectors/TRD/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,9 @@ #include "TRDBase/CommonParam.h" #include "TRDBase/Geometry.h" #include "TRDSimulation/TRsim.h" +#include "TRDSimulation/TRDSimParams.h" #include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/Hit.h" #include "CommonUtils/ShmAllocator.h" #include "SimulationDataFormat/Stack.h" @@ -33,46 +36,19 @@ using namespace o2::trd::constants; Detector::Detector(Bool_t active) : o2::base::DetImpl<Detector>("TRD", active) { - mHits = o2::utils::createSimVector<HitType>(); - if (CommonParam::Instance()->IsXenon()) { - mWion = 23.53; // Ionization energy XeCO2 (85/15) - } else if (CommonParam::Instance()->IsArgon()) { - mWion = 27.21; // Ionization energy ArCO2 (82/18) - } else { - LOG(FATAL) << "Wrong gas mixture"; - } - // Switch on TR simulation as default - mTRon = true; - if (!mTRon) { - LOG(INFO) << "TR simulation off"; - } else { - mTR = new TRsim(); - } + mHits = o2::utils::createSimVector<Hit>(); + InitializeParams(); } Detector::Detector(const Detector& rhs) : o2::base::DetImpl<Detector>(rhs), - mHits(o2::utils::createSimVector<HitType>()), + mHits(o2::utils::createSimVector<Hit>()), mFoilDensity(rhs.mFoilDensity), mGasNobleFraction(rhs.mGasNobleFraction), mGasDensity(rhs.mGasDensity), mGeom(rhs.mGeom) { - if (CommonParam::Instance()->IsXenon()) { - mWion = 23.53; // Ionization energy XeCO2 (85/15) - } else if (CommonParam::Instance()->IsArgon()) { - mWion = 27.21; // Ionization energy ArCO2 (82/18) - } else { - LOG(FATAL) << "Wrong gas mixture"; - // add hard exit here! - } - // Switch on TR simulation as default - mTRon = true; - if (!mTRon) { - LOG(INFO) << "TR simulation off"; - } else { - mTR = new TRsim(); - } + InitializeParams(); } Detector::~Detector() @@ -86,13 +62,32 @@ void Detector::InitializeO2Detector() defineSensitiveVolumes(); } +void Detector::InitializeParams() +{ + if (CommonParam::instance()->isXenon()) { + mWion = 23.53; // Ionization energy XeCO2 (85/15) + } else if (CommonParam::instance()->isArgon()) { + mWion = 27.21; // Ionization energy ArCO2 (82/18) + } else { + LOG(FATAL) << "Wrong gas mixture"; + // add hard exit here! + } + // Switch on TR simulation as default + mTRon = TRDSimParams::Instance().doTR; + if (!mTRon) { + LOG(INFO) << "TR simulation off"; + } + mTR = new TRsim(); + mMaxMCStepDef = TRDSimParams::Instance().maxMCStepSize; +} + bool Detector::ProcessHits(FairVolume* v) { // If not charged track or already stopped or disappeared, just return. if ((!fMC->TrackCharge()) || fMC->IsTrackDisappeared()) { return false; } - fMC->SetMaxStep(0.1); // Should we optimize this value? + fMC->SetMaxStep(mMaxMCStepDef); // Should we optimize this value? // Inside sensitive volume ? bool drRegion = false; @@ -238,9 +233,9 @@ void Detector::createTRhit(int det) // The absorbtion cross sections in the drift gas // Gas-mixture (Xe/CO2) double muNo = 0.0; - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { muNo = mTR->getMuXe(energyMeV); - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { muNo = mTR->getMuAr(energyMeV); } double muCO = mTR->getMuCO(energyMeV); @@ -292,7 +287,7 @@ void Detector::FinishEvent() { // Sort hit vector by detector number before the End of the Event std::sort(mHits->begin(), mHits->end(), - [](const HitType& a, const HitType& b) { + [](const Hit& a, const Hit& b) { return a.GetDetectorID() < b.GetDetectorID(); }); } @@ -365,9 +360,9 @@ void Detector::createMaterials() float fac = 0.82; float dar = 0.00166; // at 20C float dgmAr = fac * dar + (1.0 - fac) * dco; - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { Mixture(53, "XeCO2", aXeCO2, zXeCO2, dgmXe, -3, wXeCO2); - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { LOG(INFO) << "Gas mixture: Ar C02 (80/20)"; Mixture(53, "ArCO2", aArCO2, zArCO2, dgmAr, -3, wArCO2); } else { @@ -498,10 +493,10 @@ void Detector::createMaterials() // Save the density values for the TRD absorbtion float dmy = 1.39; mFoilDensity = dmy; - if (CommonParam::Instance()->IsXenon()) { + if (CommonParam::instance()->isXenon()) { mGasDensity = dgmXe; mGasNobleFraction = fxc; - } else if (CommonParam::Instance()->IsArgon()) { + } else if (CommonParam::instance()->isArgon()) { mGasDensity = dgmAr; mGasNobleFraction = fac; } diff --git a/Detectors/TRD/simulation/src/Digitizer.cxx b/Detectors/TRD/simulation/src/Digitizer.cxx index 3647c95a99bc2..2613d228e0c3a 100644 --- a/Detectors/TRD/simulation/src/Digitizer.cxx +++ b/Detectors/TRD/simulation/src/Digitizer.cxx @@ -1,26 +1,30 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "TRDSimulation/Digitizer.h" + #include <TGeoManager.h> #include <TRandom.h> #include "FairLogger.h" #include "DetectorsBase/GeometryManager.h" +#include "DataFormatsTRD/Hit.h" + #include "TRDBase/Geometry.h" #include "TRDBase/SimParam.h" #include "TRDBase/PadPlane.h" #include "TRDBase/PadResponse.h" - -#include "TRDSimulation/Digitizer.h" #include "TRDSimulation/TRDSimParams.h" + #include <cmath> #ifdef WITH_OPENMP @@ -36,16 +40,9 @@ void Digitizer::init() { mGeo = Geometry::instance(); mGeo->createClusterMatrixArray(); // Requiered for chamberInGeometry() - mPRF = new PadResponse(); // Pad response function initialization - mSimParam = SimParam::Instance(); // Instance for simulation parameters - mCommonParam = CommonParam::Instance(); // Instance for common parameters - if (!mSimParam) { - } - if (!mCommonParam) { - } else { - if (!mCommonParam->cacheMagField()) { - } - } + mSimParam = SimParam::instance(); // Instance for simulation parameters + mCommonParam = CommonParam::instance(); // Instance for common parameters + mCommonParam->cacheMagField(); // obtain the number of threads from configuration #ifdef WITH_OPENMP @@ -76,17 +73,18 @@ void Digitizer::init() void Digitizer::setSimulationParameters() { mNpad = mSimParam->getNumberOfPadsInPadResponse(); // Number of pads included in the pad response - if (mSimParam->TRFOn()) { - mTimeBinTRFend = ((int)(mSimParam->GetTRFhi() * mCommonParam->GetSamplingFrequency())) - 1; + if (mSimParam->trfOn()) { + mTimeBinTRFend = ((int)(mSimParam->getTRFhi() * mCommonParam->getSamplingFrequency())) - 1; } mMaxTimeBins = TIMEBINS; // for signals, usually set at 30 tb = 3 microseconds mMaxTimeBinsTRAP = TIMEBINS; // for adcs; should be read from the CCDB or the TRAP config - mSamplingRate = mCommonParam->GetSamplingFrequency(); - mElAttachProp = mSimParam->GetElAttachProp() / 100; + mSamplingRate = mCommonParam->getSamplingFrequency(); + mElAttachProp = mSimParam->getElAttachProp() / 100; } void Digitizer::flush(DigitContainer& digits, o2::dataformats::MCTruthContainer<MCLabel>& labels) { + size_t idx = labels.getIndexedSize(); if (mPileupSignals.size() > 0) { // Add the signals, all chambers are keept in the same signal container SignalContainer smc = addSignalsFromPileup(); @@ -95,10 +93,7 @@ void Digitizer::flush(DigitContainer& digits, o2::dataformats::MCTruthContainer< if (!status) { LOG(WARN) << "TRD conversion of signals to digits failed"; } - for (const auto& iter : smc) { - if (iter.second.isDigit) - labels.addElements(labels.getIndexedSize(), iter.second.labels); - } + dumpLabels(smc, labels); } } else { // since we don't have any pileup signals just flush the signals for each chamber @@ -108,71 +103,27 @@ void Digitizer::flush(DigitContainer& digits, o2::dataformats::MCTruthContainer< if (!status) { LOG(WARN) << "TRD conversion of signals to digits failed"; } - for (const auto& iter : smc) { - if (iter.second.isDigit) - labels.addElements(labels.getIndexedSize(), iter.second.labels); - } + dumpLabels(smc, labels); } } clearContainers(); } -SignalContainer Digitizer::addSignalsFromPileup() +void Digitizer::dumpLabels(const SignalContainer& smc, o2::dataformats::MCTruthContainer<MCLabel>& labels) { - int count = 0; - SignalContainer addedSignalsMap; - for (const auto& collection : mPileupSignals) { - for (int det = 0; det < MAXCHAMBER; ++det) { - const auto& signalMap = collection[det]; //--> a map with active pads only for this chamber - for (const auto& signal : signalMap) { // loop over active pads only, if there is any - const int& key = signal.first; - const SignalArray& signalArray = signal.second; - // check if the signal is from a previous event - if (signalArray.firstTBtime < mCurrentTriggerTime) { - if ((mCurrentTriggerTime - signalArray.firstTBtime) < BUSY_TIME) { - continue; // ignore the signal if it is too old. - } - // add only what's leftover from this signal - // 0.01 = samplingRate/1000, 1/1000 to go from ns to micro-s, the sampling rate is in 1/micro-s - int idx = (int)((mCurrentTriggerTime - signalArray.firstTBtime) * 0.01); // number of bins to add, from the tail - auto it0 = signalArray.signals.begin() + idx; - auto it1 = addedSignalsMap[key].signals.begin(); - while (it0 < signalArray.signals.end()) { - *it1 += *it0; - it0++; - it1++; - } - } else { - // the signal is from a triggered event - int idx = (int)((signalArray.firstTBtime - mCurrentTriggerTime) * 0.01); // number of bins to add, on the tail of the final signal - auto it0 = signalArray.signals.begin(); - auto it1 = addedSignalsMap[key].signals.begin() + idx; - while (it1 < addedSignalsMap[key].signals.end()) { - *it1 += *it0; - it0++; - it1++; - } - if (it0 < signalArray.signals.end()) { - count++; // add one more element to keep from the tail of the deque - } - } - - // do we need to set this for further processing?, it is ok for setting up the full-signal map - addedSignalsMap[key].firstTBtime = mCurrentTriggerTime; - - // keep the labels - for (const auto& label : signalArray.labels) { - (addedSignalsMap[key].labels).push_back(label); // maybe check if the label already exists? is that even possible? - } - } // loop over active pads in detector - } // loop over detectors - } // loop over pileup container - // remove all used added signals, keep those that can pileup to newer events. - const int numberOfElementsToPop = mPileupSignals.size() - count; - for (int i = 0; i < numberOfElementsToPop; ++i) { - mPileupSignals.pop_front(); + for (const auto& iter : smc) { + if (iter.second.isDigit) { + labels.addElements(labels.getIndexedSize(), iter.second.labels); + if (iter.second.isShared) { + labels.addElements(labels.getIndexedSize(), iter.second.labels); // shared digit is a copy of the previous one, need to add the same labels again + } + } } - return addedSignalsMap; +} + +SignalContainer Digitizer::addSignalsFromPileup() +{ + return pileupTool.addSignals(mPileupSignals, mCurrentTriggerTime); } void Digitizer::pileup() @@ -188,21 +139,19 @@ void Digitizer::clearContainers() } } -void Digitizer::process(std::vector<HitType> const& hits, DigitContainer& digits, - o2::dataformats::MCTruthContainer<MCLabel>& labels) +void Digitizer::process(std::vector<Hit> const& hits) { if (!mCalib) { LOG(FATAL) << "TRD Calibration database not available"; } // Get the a hit container for all the hits in a given detector then call convertHits for a given detector (0 - 539) - std::array<std::vector<HitType>, MAXCHAMBER> hitsPerDetector; + std::array<std::vector<Hit>, MAXCHAMBER> hitsPerDetector; getHitContainerPerDetector(hits, hitsPerDetector); #ifdef WITH_OPENMP - omp_set_num_threads(mNumThreads); // Loop over all TRD detectors (in a parallel fashion) -#pragma omp parallel for schedule(dynamic) +#pragma omp parallel for schedule(dynamic) num_threads(mNumThreads) #endif for (int det = 0; det < MAXCHAMBER; ++det) { #ifdef WITH_OPENMP @@ -232,7 +181,7 @@ void Digitizer::process(std::vector<HitType> const& hits, DigitContainer& digits } } -void Digitizer::getHitContainerPerDetector(const std::vector<HitType>& hits, std::array<std::vector<HitType>, MAXCHAMBER>& hitsPerDetector) +void Digitizer::getHitContainerPerDetector(const std::vector<Hit>& hits, std::array<std::vector<Hit>, MAXCHAMBER>& hitsPerDetector) { // // Fill an array of size MAXCHAMBER (540) @@ -244,7 +193,7 @@ void Digitizer::getHitContainerPerDetector(const std::vector<HitType>& hits, std } } -bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, SignalContainer& signalMapCont, int thread) +bool Digitizer::convertHits(const int det, const std::vector<Hit>& hits, SignalContainer& signalMapCont, int thread) { // // Convert the detector-wise sorted hits to detector signals @@ -296,14 +245,14 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig } double rowOffset = padPlane->getPadRowOffsetROC(rowE, locR); - double offsetTilt = padPlane->getTiltOffset(rowOffset); + double offsetTilt = padPlane->getTiltOffset(rowE, rowOffset); int colE = padPlane->getPadColNumber(locC + offsetTilt); if (colE < 0) { continue; } double absDriftLength = std::fabs(driftLength); // Normalized drift length - if (mCommonParam->ExBOn()) { + if (mCommonParam->isExBOn()) { absDriftLength /= std::sqrt(1 / (1 + calExBDetValue * calExBDetValue)); } @@ -314,7 +263,7 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig const int nElectrons = std::fabs(qTotal); for (int el = 0; el < nElectrons; ++el) { // Electron attachment - if (mSimParam->ElAttachOn()) { + if (mSimParam->elAttachOn()) { if (mFlatRandomRings[thread].getNextValue() < absDriftLength * mElAttachProp) { continue; } @@ -323,14 +272,14 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig double locRd{locR}, locCd{locC}, locTd{locT}; // Apply diffusion smearing - if (mSimParam->DiffusionOn()) { + if (mSimParam->diffusionOn()) { if (!diffusion(driftVelocity, absDriftLength, calExBDetValue, locR, locC, locT, locRd, locCd, locTd, thread)) { continue; } } // Apply E x B effects - if (mCommonParam->ExBOn()) { + if (mCommonParam->isExBOn()) { locCd = locCd + calExBDetValue * driftLength; } // The electron position after diffusion and ExB in pad coordinates. @@ -340,7 +289,7 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig } rowOffset = padPlane->getPadRowOffsetROC(rowE, locRd); // The pad column (rphi-direction) - offsetTilt = padPlane->getTiltOffset(rowOffset); + offsetTilt = padPlane->getTiltOffset(rowE, rowOffset); colE = padPlane->getPadColNumber(locCd + offsetTilt); if (colE < 0) { continue; @@ -352,7 +301,7 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig // time structure of drift cells (non-isochronity, GARFIELD calculation). // Also add absolute time of hits to take pile-up events into account properly double driftTime; - if (mSimParam->TimeStructOn()) { + if (mSimParam->timeStructOn()) { // Get z-position with respect to anode wire double zz = row0 - locRd + padPlane->getAnodeWireOffset(); zz -= ((int)(2 * zz)) * 0.5; @@ -360,23 +309,23 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig zz = 0.5 - zz; } // Use drift time map (GARFIELD) - driftTime = mDriftEstimators[thread].TimeStruct(driftVelocity, 0.5 * AmWidth - 1.0 * locTd, zz) + hit.GetTime(); + driftTime = mDriftEstimators[thread].timeStruct(driftVelocity, 0.5 * AmWidth - 1.0 * locTd, zz, &(mFlagVdriftOutOfRange[det])) + hit.GetTime(); } else { // Use constant drift velocity driftTime = std::fabs(locTd) / driftVelocity + hit.GetTime(); // drift time in microseconds } // Apply the gas gain including fluctuations - const double signal = -(mSimParam->GetGasGain()) * mLogRandomRings[thread].getNextValue(); + const double signal = -(mSimParam->getGasGain()) * mLogRandomRings[thread].getNextValue(); // Apply the pad response - if (mSimParam->PRFOn()) { + if (mSimParam->prfOn()) { // The distance of the electron to the center of the pad in units of pad width double dist = (colOffset - 0.5 * padPlane->getColSize(colE)) / padPlane->getColSize(colE); // ******************************************************************************** // This is a fixed parametrization, i.e. not dependent on calibration values ! // ******************************************************************************** - if (!(mPRF->getPRF(signal, dist, layer, padSignal))) { + if (!(mPRF.getPRF(signal, dist, layer, padSignal))) { continue; } } else { @@ -388,7 +337,7 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig // The time bin (always positive), with t0 distortion double timeBinIdeal = driftTime * mSamplingRate + t0; // Protection - if (std::fabs(timeBinIdeal) > (2 * mMaxTimeBins)) { + if (std::fabs(timeBinIdeal) > (2 * mMaxTimeBins)) { // OS: why 2*mMaxTimeBins? timeBinIdeal = 2 * mMaxTimeBins; } int timeBinTruncated = ((int)timeBinIdeal); @@ -415,21 +364,21 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig auto& currentSignal = currentSignalData.signals; auto& trackIds = currentSignalData.trackIds; auto& labels = currentSignalData.labels; - currentSignalData.firstTBtime = mCurrentTriggerTime; - addLabel(hit, labels, trackIds); // add a label record only if needed + currentSignalData.firstTBtime = mTime; + addLabel(hit.GetTrackID(), labels, trackIds); // add a label record only if needed // add signal with crosstalk for the non-central pads only if (colPos != colE) { for (int tb = firstTimeBin; tb < lastTimeBin; ++tb) { const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset; - const double timeResponse = mSimParam->TRFOn() ? mSimParam->TimeResponse(t) : 1; - const double crossTalk = mSimParam->CTOn() ? mSimParam->CrossTalk(t) : 0; + const double timeResponse = mSimParam->trfOn() ? mSimParam->timeResponse(t) : 1; + const double crossTalk = mSimParam->ctOn() ? mSimParam->crossTalk(t) : 0; currentSignal[tb] += padSignal[pad] * (timeResponse + crossTalk); } // end of loop time bins } else { for (int tb = firstTimeBin; tb < lastTimeBin; ++tb) { const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset; - const double timeResponse = mSimParam->TRFOn() ? mSimParam->TimeResponse(t) : 1; + const double timeResponse = mSimParam->trfOn() ? mSimParam->timeResponse(t) : 1; currentSignal[tb] += padSignal[pad] * timeResponse; } // end of loop time bins } @@ -439,11 +388,11 @@ bool Digitizer::convertHits(const int det, const std::vector<HitType>& hits, Sig return true; } -void Digitizer::addLabel(const o2::trd::HitType& hit, std::vector<o2::trd::MCLabel>& labels, std::unordered_map<int, int>& trackIds) +void Digitizer::addLabel(const int& trackId, std::vector<o2::MCCompLabel>& labels, std::unordered_set<int>& trackIds) { - if (trackIds[hit.GetTrackID()] == 0) { - trackIds[hit.GetTrackID()] = 1; - MCLabel label(hit.GetTrackID(), getEventID(), getSrcID()); + if (trackIds.count(trackId) == 0) { + trackIds.insert(trackId); + MCLabel label(trackId, getEventID(), getSrcID()); labels.push_back(label); } } @@ -462,10 +411,10 @@ bool Digitizer::convertSignalsToADC(SignalContainer& signalMapCont, DigitContain // constexpr double kEl2fC = 1.602e-19 * 1.0e15; // Converts number of electrons to fC - double coupling = mSimParam->GetPadCoupling() * mSimParam->GetTimeCoupling(); // Coupling factor - double convert = kEl2fC * mSimParam->GetChipGain(); // Electronics conversion factor - double adcConvert = mSimParam->GetADCoutRange() / mSimParam->GetADCinRange(); // ADC conversion factor - double baseline = mSimParam->GetADCbaseline() / adcConvert; // The electronics baseline in mV + double coupling = mSimParam->getPadCoupling() * mSimParam->getTimeCoupling(); // Coupling factor + double convert = kEl2fC * mSimParam->getChipGain(); // Electronics conversion factor + double adcConvert = mSimParam->getADCoutRange() / mSimParam->getADCinRange(); // ADC conversion factor + double baseline = mSimParam->getADCbaseline() / adcConvert; // The electronics baseline in mV double baselineEl = baseline / convert; // The electronics baseline in electrons for (auto& signalMapIter : signalMapCont) { @@ -504,14 +453,14 @@ bool Digitizer::convertSignalsToADC(SignalContainer& signalMapCont, DigitContain signalAmp *= coupling; // Pad and time coupling signalAmp *= padgain; // Gain factors // Add the noise, starting from minus ADC baseline in electrons - signalAmp = std::max((double)drawGaus(mGausRandomRings[thread], signalAmp, mSimParam->GetNoise()), -baselineEl); + signalAmp = std::max((double)drawGaus(mGausRandomRings[thread], signalAmp, mSimParam->getNoise()), -baselineEl); signalAmp *= convert; // Convert to mV signalAmp += baseline; // Add ADC baseline in mV // Convert to ADC counts // Set the overflow-bit fADCoutRange if the signal is larger than fADCinRange ADC_t adc = 0; - if (signalAmp >= mSimParam->GetADCinRange()) { - adc = ((ADC_t)mSimParam->GetADCoutRange()); + if (signalAmp >= mSimParam->getADCinRange()) { + adc = ((ADC_t)mSimParam->getADCoutRange()); } else { adc = std::lround(signalAmp * adcConvert); } @@ -519,7 +468,23 @@ bool Digitizer::convertSignalsToADC(SignalContainer& signalMapCont, DigitContain adcs[tb] = adc; } // loop over timebins // Convert the map to digits here, and push them to the container - digits.emplace_back(det, row, col, adcs, getEventTime()); + digits.emplace_back(det, row, col, adcs); + if (mCreateSharedDigits) { + auto digit = digits.back(); + if ((digit.getChannel() == 2) && !((digit.getROB() % 2 != 0) && (digit.getMCM() % NMCMROBINCOL == 3))) { + // shared left, if not leftmost MCM of left ROB of chamber + int robShared = (digit.getMCM() % NMCMROBINCOL == 3) ? digit.getROB() + 1 : digit.getROB(); // for the leftmost MCM on a ROB the shared digit is added to the neighbouring ROB + int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() + 1 : digit.getMCM() - 3; + digits.emplace_back(det, robShared, mcmShared, NADCMCM - 1, adcs); + signalMapIter.second.isShared = true; + } else if ((digit.getChannel() == 18 || digit.getChannel() == 19) && !((digit.getROB() % 2 == 0) && (digit.getMCM() % NMCMROBINCOL == 0))) { + // shared right, if not rightmost MCM of right ROB of chamber + int robShared = (digit.getMCM() % NMCMROBINCOL == 0) ? digit.getROB() - 1 : digit.getROB(); // for the rightmost MCM on a ROB the shared digit is added to the neighbouring ROB + int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() - 1 : digit.getMCM() + 3; + digits.emplace_back(det, robShared, mcmShared, digit.getChannel() - NCOLMCM, adcs); + signalMapIter.second.isShared = true; + } + } } // loop over digits return true; } @@ -534,12 +499,12 @@ bool Digitizer::diffusion(float vdrift, float absdriftlength, float exbvalue, // float diffL = 0.0; float diffT = 0.0; - if (mDriftEstimators[thread].GetDiffCoeff(diffL, diffT, vdrift)) { + if (mDriftEstimators[thread].getDiffCoeff(diffL, diffT, vdrift)) { float driftSqrt = std::sqrt(absdriftlength); float sigmaT = driftSqrt * diffT; float sigmaL = driftSqrt * diffL; lRow = drawGaus(mGausRandomRings[thread], lRow0, sigmaT); - if (mCommonParam->ExBOn()) { + if (mCommonParam->isExBOn()) { const float exbfactor = 1.f / (1.f + exbvalue * exbvalue); lCol = drawGaus(mGausRandomRings[thread], lCol0, sigmaT * exbfactor); lTime = drawGaus(mGausRandomRings[thread], lTime0, sigmaL * exbfactor); @@ -552,3 +517,18 @@ bool Digitizer::diffusion(float vdrift, float absdriftlength, float exbvalue, return false; } } + +std::string Digitizer::dumpFlaggedChambers() const +{ + std::string retVal = ""; + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { + if (mFlagVdriftOutOfRange[iDet]) { + retVal += std::to_string(iDet); + retVal += ", "; + } + } + if (!retVal.empty()) { + retVal.erase(retVal.size() - 2); + } + return retVal; +} diff --git a/Detectors/TRD/simulation/src/PileupTool.cxx b/Detectors/TRD/simulation/src/PileupTool.cxx new file mode 100644 index 0000000000000..63a4f625f3324 --- /dev/null +++ b/Detectors/TRD/simulation/src/PileupTool.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDSimulation/PileupTool.h" + +using namespace o2::trd; +using namespace o2::trd::constants; + +SignalContainer PileupTool::addSignals(std::deque<std::array<SignalContainer, constants::MAXCHAMBER>>& pileupSignals, const double& triggerTime) +{ + SignalContainer addedSignalsMap; + int nSignalsToRemove = 0; + for (const auto& collection : pileupSignals) { + bool pileupSignalBecomesObsolete = false; + for (int det = 0; det < MAXCHAMBER; ++det) { + const auto& signalMap = collection[det]; //--> a map with active pads only for this chamber + for (const auto& signal : signalMap) { // loop over active pads only, if there is any + const int& key = signal.first; + const SignalArray& signalArray = signal.second; + // check if the signal is from a previous event + if (signalArray.firstTBtime < triggerTime) { + pileupSignalBecomesObsolete = true; + if ((triggerTime - signalArray.firstTBtime) > constants::READOUT_TIME) { // OS: READOUT_TIME should actually be drift time (we want to ignore signals which don't contribute signal anymore at triggerTime) + continue; // ignore the signal if it is too old. + } + // add only what's leftover from this signal + // 0.01 = samplingRate/1000, 1/1000 to go from ns to micro-s, the sampling rate is in 1/micro-s + int idx = (int)((triggerTime - signalArray.firstTBtime) * 0.01); // number of bins to skip + auto it0 = signalArray.signals.begin() + idx; + auto it1 = addedSignalsMap[key].signals.begin(); + while (it0 < signalArray.signals.end()) { + *it1 += *it0; + it0++; + it1++; + } + } else { + // the signal is from a subsequent event + int idx = (int)((signalArray.firstTBtime - triggerTime) * 0.01); // time bin offset of the pileup signal wrt trigger time. Number of time bins to be added to the signal is constants::TIMEBINS - idx + auto it0 = signalArray.signals.begin(); + auto it1 = addedSignalsMap[key].signals.begin() + idx; + while (it1 < addedSignalsMap[key].signals.end()) { + *it1 += *it0; + it0++; + it1++; + } + } + // keep the labels + for (const auto& label : signalArray.labels) { + // do we want to keep all labels? what about e.g. a TR signal which does not contribute to the pileup of a previous event since the signal arrives too late, but then we will have its label? + (addedSignalsMap[key].labels).push_back(label); // maybe check if the label already exists? is that even possible? + } + } // loop over active pads in detector + } // loop over detectors + if (pileupSignalBecomesObsolete) { + ++nSignalsToRemove; + } + } // loop over pileup container + // remove all used added signals, keep those that can pileup to newer events. + for (int i = 0; i < nSignalsToRemove; ++i) { + pileupSignals.pop_front(); + } + return addedSignalsMap; +} diff --git a/Detectors/TRD/simulation/src/TRDSimParams.cxx b/Detectors/TRD/simulation/src/TRDSimParams.cxx index 1ce2abcf5be27..8709bd91e3649 100644 --- a/Detectors/TRD/simulation/src/TRDSimParams.cxx +++ b/Detectors/TRD/simulation/src/TRDSimParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/simulation/src/TRDSimulationLinkDef.h b/Detectors/TRD/simulation/src/TRDSimulationLinkDef.h index 851660dbdd90c..858becbdba596 100644 --- a/Detectors/TRD/simulation/src/TRDSimulationLinkDef.h +++ b/Detectors/TRD/simulation/src/TRDSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,6 @@ #pragma link C++ class o2::trd::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::trd::Detector> + ; -#pragma link C++ class o2::trd::HitType + ; #pragma link C++ class o2::trd::TRsim + ; #pragma link C++ class o2::trd::Digitizer + ; #pragma link C++ class o2::trd::TrapConfigHandler + ; @@ -25,6 +25,11 @@ #pragma link C++ class o2::trd::TrapConfig::TrapDmemWord + ; #pragma link C++ class o2::trd::TrapConfig::TrapRegister + ; #pragma link C++ class o2::trd::TrapSimulator + ; +// dictionaries for the internal classes of TrapSimulator are needed for the debug output +#pragma link C++ class o2::trd::TrapSimulator::TrackletDetail + ; +#pragma link C++ class o2::trd::TrapSimulator::FitReg + ; +#pragma link C++ class o2::trd::TrapSimulator::FilterReg + ; +#pragma link C++ class o2::trd::TrapSimulator::Hit + ; #pragma link C++ class o2::trd::Trap2CRU + ; #pragma link C++ class o2::trd::TRDSimParams + ; diff --git a/Detectors/TRD/simulation/src/TRsim.cxx b/Detectors/TRD/simulation/src/TRsim.cxx index 8b2b282e2220c..717078426935b 100644 --- a/Detectors/TRD/simulation/src/TRsim.cxx +++ b/Detectors/TRD/simulation/src/TRsim.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/simulation/src/Trap2CRU.cxx b/Detectors/TRD/simulation/src/Trap2CRU.cxx index ff2f3f6514d02..0c770792f0ab6 100644 --- a/Detectors/TRD/simulation/src/Trap2CRU.cxx +++ b/Detectors/TRD/simulation/src/Trap2CRU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,8 +28,8 @@ #include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RawFileWriter.h" #include "TRDSimulation/Trap2CRU.h" +#include "TRDSimulation/TrapSimulator.h" #include "CommonUtils/StringUtils.h" -#include "TRDBase/CommonParam.h" #include "TFile.h" #include "TTree.h" #include <TStopwatch.h> @@ -40,6 +41,7 @@ #include <bitset> #include <vector> #include <gsl/span> +#include <typeinfo> using namespace o2::raw; @@ -48,86 +50,234 @@ namespace o2 namespace trd { -Trap2CRU::Trap2CRU(const std::string& outputDir, const std::string& inputFilename) +Trap2CRU::Trap2CRU(const std::string& outputDir, const std::string& inputdigitsfilename, const std::string& inputtrackletsfilename) { - readTrapData(outputDir, inputFilename, 1024 * 1024); + mOutputDir = outputDir; + mSuperPageSizeInB = 1024 * 1024; + mInputDigitsFileName = inputdigitsfilename; + mInputTrackletsFileName = inputtrackletsfilename; + mCurrentDigit = 0; + mCurrentTracklet = 0; } -void Trap2CRU::readTrapData(const std::string& outputDir, const std::string& inputFilename, int superPageSizeInB) +void Trap2CRU::openInputFiles() +{ + mDigitsFile = TFile::Open(mInputDigitsFileName.data()); + if (mDigitsFile != nullptr) { + mDigitsTree = (TTree*)mDigitsFile->Get("o2sim"); + mDigitsTree->SetBranchAddress("TRDDigit", &mDigitsPtr); // the branch with the actual digits + mDigitsTree->SetBranchAddress("TriggerRecord", &mDigitTriggerRecordsPtr); // branch with trigger records for digits + // LOG(info) << "Digit tree has " << mDigitsTree->GetEntries() << " entries"; //<< + } else { + LOG(warn) << " cant open file containing digit tree"; + } + mTrackletsFile = TFile::Open(mInputTrackletsFileName.data()); + if (mTrackletsFile != nullptr) { + mTrackletsTree = (TTree*)mTrackletsFile->Get("o2sim"); + mTrackletsTree->SetBranchAddress("Tracklet", &mTrackletsPtr); // the branch with the actual tracklets. + mTrackletsTree->SetBranchAddress("TrackTrg", &mTrackletTriggerRecordsPtr); // branch with trigger records for digits + // LOG(info) << "Tracklet tree has " << mTrackletsTree->GetEntries() << " entries";//<< + } else { + LOG(fatal) << " cant open file containing tracklet tree"; + } +} + +void Trap2CRU::sortDataToLinks() +{ + //sort the digits array TODO refactor this intoa vector index sort and possibly generalise past merely digits. + auto sortstart = std::chrono::high_resolution_clock::now(); + //build indexes + // digits first + mDigitsIndex.resize(mDigits.size()); + std::iota(mDigitsIndex.begin(), mDigitsIndex.end(), 0); + + for (auto& trig : mTrackletTriggerRecords) { + if (trig.getNumberOfTracklets() > 0) { + if (mVerbosity) { + LOG(debug) << " sorting digits from : " << trig.getFirstTracklet() << " till " << trig.getFirstTracklet() + trig.getNumberOfTracklets(); + } + // sort to link order *NOT* hcid order ... + // link is defined by stack,layer,halfchamberside. + // tracklet data we have hcid,padrow,colum. + // hcid/2 = detector, detector implies stack and layer, and hcid odd/even gives side. + std::stable_sort(std::begin(mTracklets) + trig.getFirstTracklet(), std::begin(mTracklets) + trig.getNumberOfTracklets() + trig.getFirstTracklet(), + [this](auto&& t1, auto&& t2) { + int link1 = HelperMethods::getLinkIDfromHCID(t1.getHCID()); + int link2 = HelperMethods::getLinkIDfromHCID(t2.getHCID()); + if (link1 != link2) { + return link1 < link2; + } + if (t1.getPadRow() != t2.getPadRow()) { + return t1.getPadRow() < t2.getPadRow(); + } + return t1.getMCM() < t2.getMCM(); + }); + } + if (trig.getNumberOfDigits() != 0) { + if (mVerbosity) { + LOG(debug) << " sorting digits from : " << trig.getFirstDigit() << " till " << trig.getFirstDigit() + trig.getNumberOfDigits(); + } + std::stable_sort(mDigitsIndex.begin() + trig.getFirstDigit(), mDigitsIndex.begin() + trig.getNumberOfDigits() + trig.getFirstDigit(), + [this](const uint32_t i, const uint32_t j) { + int link1=HelperMethods::getLinkIDfromHCID(mDigits[i].getDetector() * 2 + (mDigits[i].getROB() % 2)); + int link2=HelperMethods::getLinkIDfromHCID(mDigits[j].getDetector() * 2 + (mDigits[j].getROB() % 2)); + if(link1!=link2){return link1<link2;} + if(mDigits[i].getROB() != mDigits[j].getROB()){return (mDigits[i].getROB() < mDigits[j].getROB());} + if(mDigits[i].getMCM() != mDigits[j].getMCM()){return (mDigits[i].getMCM() < mDigits[j].getMCM());} + return (mDigits[i].getChannel() < mDigits[j].getChannel()); }); + } + } + + std::chrono::duration<double> duration = std::chrono::high_resolution_clock::now() - sortstart; + if (mVerbosity) { + LOG(info) << "TRD Digit/Tracklet Sorting took " << duration.count() << " s"; + int triggercount = 0; + for (auto& trig : mTrackletTriggerRecords) { + + LOG(info) << "Trigger: " << triggercount << " with T" << trig.getBCData().asString(); + LOG(info) << "Tracklets from:" << trig.getFirstTracklet() << " with " << trig.getNumberOfTracklets(); + LOG(info) << "Digits from:" << trig.getFirstDigit() << " with " << trig.getNumberOfDigits(); + if (trig.getNumberOfTracklets() > 0) { + int firsttracklet = trig.getFirstTracklet(); + int numtracklets = trig.getNumberOfTracklets(); + for (int trackletcount = firsttracklet; trackletcount < firsttracklet + numtracklets; ++trackletcount) { + LOG(info) << "Tracklet : " << trackletcount << " details : supermodule:" << std::dec << mTracklets[trackletcount].getHCID() << std::hex << " tracklet:" << mTracklets[trackletcount]; + } + } else { + LOG(info) << "No Tracklets for this trigger"; + } + if (trig.getNumberOfDigits() != 0) { + int firstdigit = trig.getFirstDigit(); + int numdigits = trig.getNumberOfDigits(); + for (int digitcount = firstdigit; digitcount < firstdigit + numdigits; ++digitcount) { + LOG(info) << "Digit indexed: " << digitcount << " digit index : " << mDigitsIndex[digitcount] << " details : hcid=" << mDigits[mDigitsIndex[digitcount]].getHCId() + << " calculated hcid=" << (mDigits[mDigitsIndex[digitcount]].getDetector() * 2 + (mDigits[mDigitsIndex[digitcount]].getROB() % 2)) + << " det=" << mDigits[mDigitsIndex[digitcount]].getDetector() + << " mcm=" << mDigits[mDigitsIndex[digitcount]].getMCM() + << " rob=" << mDigits[mDigitsIndex[digitcount]].getROB() + << " channel=" << mDigits[mDigitsIndex[digitcount]].getChannel() + << " col=" << mDigits[mDigitsIndex[digitcount]].getPadRow() + << " pad=" << mDigits[mDigitsIndex[digitcount]].getPadCol() + << " adcsum=" << mDigits[mDigitsIndex[digitcount]].getADCsum() + << " hcid=" << mDigits[mDigitsIndex[digitcount]].getHCId(); + } + + } else { + LOG(error) << "No Digits for this trigger <----- this should NEVER EVER HAPPEN"; + } + triggercount++; + } + LOG(info) << "end of pre sort tracklets then digits"; + } // if verbose +} + +void Trap2CRU::mergetriggerDigitRanges() +{ + // pass through the digit ranges of the incoming tracklet triggers. + // this most handles the old data. + // trapsim should now be sending out the trigger with both information. + bool fixdigitinfo = false; + for (auto trig : mTrackletTriggerRecords) { + if (trig.getNumberOfDigits() != 0) { + fixdigitinfo = true; + } + } + if (fixdigitinfo) { + int counter = 0; + for (auto trig : mTrackletTriggerRecords) { + trig.setDigitRange(mDigitTriggerRecords[counter].getFirstDigit(), mDigitTriggerRecords[counter].getNumberOfDigits()); + } + } +} + +void Trap2CRU::readTrapData() { //set things up, read the file and then deligate to convertTrapdata to do the conversion. // mRawData.reserve(1024 * 1024); //TODO take out the hardcoded 1MB its supposed to come in from the options - LOG(debug) << "Trap2CRU::readTrapData"; - // data comes in index by event (triggerrecord) and link (linke record) both sequentially. - // first 15 links go to cru0a, second 15 links go to cru0b, 3rd 15 links go to cru1a ... first 90 links to flp0 and then repate for 12 flp + if (mVerbosity) { + LOG(info) << "Trap2CRU::readTrapData"; + } + // data comes in index by event (triggerrecord) + // first 15 links go to cru0a, second 15 links go to cru0b, 3rd 15 links go to cru1a ... first 90 links to flp0 and then repeat for 12 flp // then do next event // lets register our links - std::string prefix = outputDir; + std::string prefix = mOutputDir; if (!prefix.empty() && prefix.back() != '/') { prefix += '/'; } - for (int link = 0; link < NumberOfHalfCRU; link++) { + for (int link = 0; link < o2::trd::constants::NHALFCRU; link++) { // FeeID *was* 0xFEED, now is indicates the cru Supermodule, side (A/C) and endpoint. See RawData.cxx for details. int supermodule = link / 4; - int endpoint = link / 2; - int side = link % 2 ? 1 : 0; + int endpoint = link % 2; + int cru = link / 2; + int side = cru % 2; // A or C, 0 or 1 respectively: mFeeID = buildTRDFeeID(supermodule, side, endpoint); + LOG(info) << "FEEID;" << std::hex << mFeeID; mCruID = link / 2; - mEndPointID = link % 2 ? 1 : 0; //TODO figure out a value ... endpoint needs a rebase to PR4106 - mLinkID = TRDLinkID; - std::string trdside = link % 2 ? "c" : "a"; // the side of supermodule readout A or C, odd numbered CRU are A, even numbered CRU are C. - // filenmae structure of trd_cru_[CRU#]_[upper/lower].raw - std::string outputFilelink = o2::utils::concat_string(prefix, "trd_cru_", std::to_string(mCruID), "_", trdside, ".raw"); - mWriter.registerLink(mFeeID, mCruID, mLinkID, mEndPointID, outputFilelink); - } - mTrapRawFile = TFile::Open(inputFilename.data()); - assert(mTrapRawFile != nullptr); - LOG(debug) << "Trap Raw file open " << inputFilename; - mTrapRawTree = (TTree*)mTrapRawFile->Get("o2sim"); - - mTrapRawTree->SetBranchAddress("TrapLinkRecord", &mLinkRecordsPtr); // branch with the link records - mTrapRawTree->SetBranchAddress("RawTriggerRecord", &mTriggerRecordsPtr); // branch with the trigger records - mTrapRawTree->SetBranchAddress("TrapRaw", &mTrapRawDataPtr); // branch with the actual incoming data. - - for (int entry = 0; entry < mTrapRawTree->GetEntries(); entry++) { - mTrapRawTree->GetEntry(entry); - LOG(debug) << "Before Trigger Reord loop Event starts at:" << mTriggerRecords[0].getFirstEntry() << " and has " << mTriggerRecords[0].getNumberOfObjects() << " entries"; - uint32_t linkcount = 0; - for (auto trigger : mTriggerRecords) { - //get the event limits from TriggerRecord; - uint32_t eventstart = trigger.getFirstEntry(); - uint32_t eventend = trigger.getFirstEntry() + trigger.getNumberOfObjects(); - LOG(debug) << "Event starts at:" << eventstart << " and ends at :" << eventend; - convertTrapData(trigger); + mEndPointID = endpoint; + mLinkID = o2::trd::constants::TRDLINKID; + + std::string outFileLink; + std::string outPrefix = "trd"; + std::string outSuffix = ".raw"; + std::string trdside = mEndPointID ? "_h" : "_l"; // the side of cru lower or higher + // filename structure of trd_cru_[CRU#]_[upper/lower].raw + std::string whichrun = mUseTrackletHCHeader ? "run3" : "run2"; + if (mFilePer == "all") { // single file for all links + outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, outSuffix); + } else if (mFilePer == "sm") { + int sm = link / 4; + std::stringstream ss; + ss << std::setw(2) << std::setfill('0') << sm; + std::string supermodule = ss.str(); + outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, "_sm_", supermodule, outSuffix); + } else if (mFilePer == "cru") { + outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, "_cru_", std::to_string(mCruID), outSuffix); + } else if (mFilePer == "halfcru") { + outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, "_cru_", std::to_string(mCruID), trdside, outSuffix); + } else { + throw std::runtime_error("invalid option provided for file grouping"); } + + //std::string outputFilelink = o2::utils::Str::concat_string(prefix, "trd_cru_", std::to_string(mCruID), "_", trdside, "_", whichrun, ".raw"); + LOG(info) << "registering links"; + + mWriter.registerLink(mFeeID, mCruID, mLinkID, mEndPointID, outFileLink); } -} -int Trap2CRU::sortByORI() -{ - // data comes in sorted by padcolum, a row of 8 trap chips. - // this is sadly not how the electronics is actually connected. - // we therefore need to resort the data according to the ORI link. - // TODO consider unpacking an entire event into memory into a per ori vector, then dump it all out. - // this is not for production running so the performance hit of sortin is probably ok ?? TODO ask someone to verify that. - return 1; -} + openInputFiles(); -void Trap2CRU::buildCRUPayLoad() -{ - // go through the data for the event in question, sort via above method, produce the raw stream for each cru. - // i.e. 30 link per cru, 3cru per flp. - // 30x [HalfCRUHeader, TrackletHCHeader0, [MCMHeader TrackletMCMData. .....] TrackletHCHeader1 ..... TrackletHCHeader30 ...] - // - // data must be padded into blocks of 256bit so on average 4 padding 32 bit words. + if (mTrackletsTree->GetEntries() != mDigitsTree->GetEntries()) { + LOG(fatal) << "Entry counts in mTrackletsTree and Digits Tree dont match " << mTrackletsTree->GetEntries() << "!=" << mDigitsTree->GetEntries(); + } + uint32_t totaltracklets = 0; + uint32_t totaldigits = 0; + int triggercount = 42; // triggercount is here so that we can span timeframes. The actual number is of no consequence,but must increase. + for (int entry = 0; entry < mTrackletsTree->GetEntries(); entry++) { + mTrackletsTree->GetEntry(entry); + mDigitsTree->GetEntry(entry); + totaltracklets += mTracklets.size(); + totaldigits += mDigits.size(); + //migrate digit trigger information into the tracklettrigger (historical) + sortDataToLinks(); + // each entry is a timeframe + uint32_t linkcount = 0; + for (auto tracklettrigger : mTrackletTriggerRecords) { + convertTrapData(tracklettrigger, triggercount); // tracklettrigger assumed to be authoritive, TODO check for blanks digits range + triggercount++; + mEventDigitCount++; + } + } + LOG(info) << " Total digits : " << totaldigits; + LOG(info) << " Total tracklets : " << totaltracklets; } void Trap2CRU::linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_t& padding) { - // all data must be 256 bit aligned (8x64bit). + // if zero the whole 256 bit must be padded (empty link) // crudatasize is the size to be stored in the cruheader, i.e. units of 256bits. // linksize is the incoming link size from the linkrecord, @@ -144,54 +294,302 @@ void Trap2CRU::linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_ crudatasize = linksize / 8; // 32 bit word to 256 bit word. padding = 0; } - LOG(debug) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; + if (mVerbosity) { + LOG(info) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; + } } else { //linksize is zero so no data, pad fully. crudatasize = 1; padding = 8; - LOG(debug) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; + if (mVerbosity) { + LOG(info) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; + } + } + if (mVerbosity) { + LOG(debug) << __func__ << " leaving linkSizePadding : CRUDATASIZE : " << crudatasize; } - LOG(debug) << "linkSizePadding : CRUDATASIZE : " << crudatasize; } -uint32_t Trap2CRU::buildCRUHeader(HalfCRUHeader& header, uint32_t bc, uint32_t halfcru, int startlinkrecord) +uint32_t Trap2CRU::buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru) { int bunchcrossing = bc; int stopbits = 0x01; // do we care about this and eventtype in simulations? int eventtype = 0x01; int crurdhversion = 6; - int feeid = 0; //TODO must be in cruheader down the road, inside the reserved somewhere ... - int cruid = 0; //TODO """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - uint32_t crudatasize = 0; //link size in units of 256 bits. - int endpoint = halfcru % 2 ? 1 : 0; //TODO figure out a value ... endpoint needs a rebase to PR4106 + int feeid = 0; + int cruid = 0; + uint32_t crudatasize = 0; //link size in units of 256 bits. + int endpoint = halfcru % 2 ? 1 : 0; uint32_t padding = 0; - //setHalfCRUHeader(halfcruheader, rdhversion, bunchcrossing, stopbits, endpoint, eventtype); //TODO come back and pull this from somewhere. + //lets first clear it out. + clearHalfCRUHeader(header); + //this bunchcrossing is not the same as the bunchcrossing in the rdh, which is the bc coming in the parameter list to this function. See explanation in rawdata.h setHalfCRUHeader(header, crurdhversion, bunchcrossing, stopbits, endpoint, eventtype, feeid, cruid); //TODO come back and pull this from somewhere. - // memset(&tmpLinkInfo[0],0,sizeof(tmpLinkInfo[0])*tmpLinkInfo.size()); - - // halfcruheader from the relevant mLinkRecords. - int linkrecord = startlinkrecord; - int totallinkdatasize = 0; //in units of 256bits - for (int link = 0; link < NLinksPerHalfCRU; link++) { - int linkid = link + halfcru * NLinksPerHalfCRU; // TODO this might have to change to a lut I dont think the mapping is linear. - int errors = 0; - int linksize = 0; // linkSizePadding will convert it to 1 for the no data case. - if (mLinkRecords[linkrecord].getLinkId() == linkid) { - linksize = mLinkRecords[linkrecord].getNumberOfObjects(); - // this can be done differently by keeping a pointer to halfcruheader and setting it after reading it all in and going back per link to set the size. - LOG(debug3) << "setting CRU HEADER for halfcru : " << halfcru << "and link : " << link << " contents" << header << ":" << link << ":" << linksize << ":" << errors; - linkrecord++; // increment locally for walking through linkrecords. + + return 1; +} + +bool Trap2CRU::isTrackletOnLink(const int linkid, const int currenttrackletpos) +{ + //hcid is simply the halfcru*15+linkid + int link = HelperMethods::getLinkIDfromHCID(mTracklets[currenttrackletpos].getHCID()); + if (linkid == link) { + // this tracklet is on this link. + return true; + } + return false; +} + +bool Trap2CRU::isDigitOnLink(const int linkid, const int currentdigitpos) +{ + Digit* digit = &mDigits[mDigitsIndex[currentdigitpos]]; + int link = HelperMethods::getLinkIDfromHCID(digit->getDetector() * 2 + (digit->getROB() % 2)); + if (link == linkid) { + return true; + } + return false; +} + +int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggerrecordcount) +{ + //this is not zero suppressed. + int digitwordswritten = 0; + int digitswritten = 0; + // Digit + DigitMCMHeader header; + DigitMCMData data; + int startdet = mDigits[mDigitsIndex[digitstartindex]].getDetector(); + int startrob = mDigits[mDigitsIndex[digitstartindex]].getROB(); + int startmcm = mDigits[mDigitsIndex[digitstartindex]].getMCM(); + if (startrob != rob && startmcm != mcm) { + LOG(error) << "buildDigitRawData but startmcm and rob are not correct : " << startrob << "!=" << rob << " and mcm: " << startmcm << "!=" << mcm; + } + int digitcounter = 0; + header.res = 0xc; //1100 + header.mcm = startmcm; + header.rob = startrob; + header.yearflag = 1; // >10.2007 + header.eventcount = triggerrecordcount; + memcpy(mRawDataPtr, (char*)&header, sizeof(DigitMCMHeader)); // uint32 -- 4 bytes. + DigitMCMHeader* headerptr = (DigitMCMHeader*)mRawDataPtr; + //LOG(info) << "Digt Header word: 0x" << std::hex << headerptr->word; + mRawDataPtr += 4; + digitwordswritten++; + //we are writing zero suppressed so + DigitMCMADCMask adcmask; + adcmask = buildBlankADCMask(); + memcpy(mRawDataPtr, (char*)&adcmask, sizeof(DigitMCMADCMask)); + DigitMCMADCMask* adcmaskptr = (DigitMCMADCMask*)mRawDataPtr; + mRawDataPtr += 4; + digitwordswritten++; + //LOG(info) << "writing data to digit stream of " << std::hex << header.word; + for (int digitindex = digitstartindex; digitindex < digitendindex; ++digitindex) { + //LOG(info) << "digit index of : " << digitindex; //<< + Digit* d = &mDigits[mDigitsIndex[digitindex]]; + ArrayADC adcdata = d->getADC(); + //write these 2 now as we only have it now. + if (startmcm != d->getMCM()) { + LOG(error) << " we are on the wrong mcm:" << startmcm << "!=" << d->getMCM(); + } + if (startrob != d->getROB()) { + LOG(error) << " we are on the wrong rob:" << startrob << "!=" << d->getROB(); + } + int channel = d->getChannel(); + //set adcmask for the channel we currently have. + adcmaskptr->adcmask |= 1UL << channel; + for (int timebin = 0; timebin < o2::trd::constants::TIMEBINS; timebin += 3) { + data.x = adcdata[timebin]; + data.y = adcdata[timebin + 1]; + data.z = adcdata[timebin + 2]; + data.c = (channel % 2 == 0) ? 0x3 : 0x2; // 3 for even channel 2 for odd channel + memcpy(mRawDataPtr, (char*)&data, sizeof(DigitMCMData)); // uint32 -- 4 bytes. + mRawDataPtr += sizeof(DigitMCMData); + digitwordswritten++; + } + if (mVerbosity) { + LOG(info) << "DDDD " << d->getDetector() << ":" << d->getROB() << ":" << d->getMCM() << ":" << d->getChannel() << ":" << d->getADCsum() << ":" << d->getADC()[0] << ":" << d->getADC()[1] << ":" << d->getADC()[2] << "::" << d->getADC()[27] << ":" << d->getADC()[28] << ":" << d->getADC()[29]; + } + if (d->getMCM() != startmcm) { + LOG(fatal) << "digit getmcm = " << d->getMCM() << " while startmcm=" << startmcm; + } + digitswritten++; + } + if (digitswritten != digitendindex - digitstartindex) { + LOG(error) << " something wrong the number of digitswritten does not correspond to the the loop count"; + } + if (digitwordswritten != (digitswritten * 10 + 2)) { + LOG(error) << "something wrong with writing the digits the following should be equal " << digitwordswritten << "==" << (digitswritten * 10 + 2) << " with digitswritten=" << digitswritten; + LOG(error) << "digit start index distance to digit end index :" << digitendindex - digitstartindex; + } + return digitwordswritten; +} + +int Trap2CRU::buildTrackletRawData(const int trackletindex, const int linkid) +{ + TrackletMCMHeader header; + bool destroytracklets = false; + std::array<TrackletMCMData, 3> trackletdata; + + header.col = mTracklets[trackletindex].getColumn(); + header.padrow = mTracklets[trackletindex].getPadRow(); + header.onea = 1; + header.oneb = 1; + header.pid0 = 0xff; + header.pid1 = 0xff; + header.pid2 = 0xff; + unsigned int trackletcounter = 0; + if (mVerbosity) { + LOG(info) << "After instantiation header is : 0x" << header.word << " " << header; + } + while (linkid == HelperMethods::getLinkIDfromHCID(mTracklets[trackletindex + trackletcounter].getHCID()) && header.col == mTracklets[trackletindex + trackletcounter].getColumn() && header.padrow == mTracklets[trackletindex + trackletcounter].getPadRow()) { + int trackletoffset = trackletindex + trackletcounter; + buildTrackletMCMData(trackletdata[trackletcounter], mTracklets[trackletoffset].getSlope(), + mTracklets[trackletoffset].getPosition(), mTracklets[trackletoffset].getQ0(), + mTracklets[trackletoffset].getQ1(), mTracklets[trackletoffset].getQ2()); + unsigned int headerqpart = ((mTracklets[trackletoffset].getQ2() & 0x2f) << 2) + ((mTracklets[trackletoffset].getQ1() >> 6) & 0x3); + //all 6 bits of Q1 and 2 upper bits of 7bit Q1 + if (mVerbosity) { + if (mTracklets[trackletoffset].getQ2() > 0x2f) { + LOGP(warning, "Tracklet Q2 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ2()); + } + if (mTracklets[trackletoffset].getQ1() > 0x7f) { + LOGP(warning, "Tracklet Q1 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ1()); + } + if (mTracklets[trackletoffset].getQ0() > 0x7f) { + LOGP(warning, "Tracklet Q0 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ0()); + } } - linkSizePadding(linksize, crudatasize, padding); - setHalfCRUHeaderLinkData(header, link, crudatasize, errors); // write one padding block for empty links. - totallinkdatasize += crudatasize; + switch (trackletcounter) { + case 0: + header.pid0 = headerqpart; + break; + case 1: + header.pid1 = headerqpart; + if (header.pid0 == 0xff) { + LOG(warn) << "we are setting pid1 but pid0 is not set, a second tracklet but no first one?"; + } + break; + case 2: + header.pid2 = headerqpart; + if (header.pid1 == 0xff || header.pid0 == 0xff) { + LOG(warn) << "we are setting pid2 but pid0/1 is not set, a second tracklet but no first one?" << header.pid0 << " " << header.pid1; + } + break; + default: + LOG(warn) << ">3 tracklets when building the Tracklet raw data stream for hcid=" << mTracklets[trackletindex + trackletcounter].getHCID() << " col:" << mTracklets[trackletindex + trackletcounter].getColumn() << " padrow:" << mTracklets[trackletindex + trackletcounter].getPadRow(); + destroytracklets = true; + break; + } + trackletcounter++; } - return totallinkdatasize; + //now copy the mcmheader and mcmdata. + if (!destroytracklets) { + setNumberOfTrackletsInHeader(header, trackletcounter); + memcpy((char*)mRawDataPtr, (char*)&header, sizeof(TrackletMCMHeader)); + mRawDataPtr += sizeof(TrackletMCMHeader); + for (int i = 0; i < trackletcounter; ++i) { + memcpy((char*)mRawDataPtr, (char*)&trackletdata[i], sizeof(TrackletMCMData)); + mRawDataPtr += sizeof(TrackletMCMData); + } + if (trackletcounter == 0) { + LOG(error) << "we have zero tracklets to go with a tracklet header ?!!??"; + } + } else { + LOG(warn) << "something wrong with these tracklets, there are too many. You might want to take a closer look. Rejecting for now, and moving on."; + } + return trackletcounter; } -void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& TrigRecord) +int Trap2CRU::writeDigitEndMarker() { + int wordswritten = 0; + uint32_t digitendmarker = 0; + + memcpy(mRawDataPtr, (char*)&digitendmarker, 4); + mRawDataPtr += 4; + wordswritten++; + memcpy(mRawDataPtr, (char*)&digitendmarker, 4); + mRawDataPtr += 4; + wordswritten++; + return wordswritten; +} + +int Trap2CRU::writeTrackletEndMarker() +{ + int wordswritten = 0; + uint32_t trackletendmarker = 0x10001000; + + memcpy(mRawDataPtr, (char*)&trackletendmarker, 4); + mRawDataPtr += 4; + wordswritten++; + memcpy(mRawDataPtr, (char*)&trackletendmarker, 4); + mRawDataPtr += 4; + wordswritten++; + return wordswritten; +} + +int Trap2CRU::writeTrackletHCHeader(const int eventcount, const uint32_t linkid) +{ + int wordswritten = 0; + //from linkid we can get supermodule, stack, layer, side + int detector = linkid / 2; + TrackletHCHeader trackletheader; + trackletheader.supermodule = linkid / 60; + trackletheader.stack = (detector % (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK)) / o2::trd::constants::NLAYER; + trackletheader.layer = (detector % o2::trd::constants::NLAYER); + trackletheader.one = 1; + if (mVerbosity) { + LOG(info) << "Tracklet linkid : " << linkid << ":" + << " " << trackletheader.supermodule << ":" << trackletheader.stack << ":" << trackletheader.layer << ":" << trackletheader.side; + } + trackletheader.side = (linkid % 2) ? 1 : 0; + trackletheader.MCLK = eventcount * 42; // just has to be a constant increasing number per event for our purposes in sim to raw. + trackletheader.format = 12; + if (mUseTrackletHCHeader) { // run 3 we also have a TrackletHalfChamber. + memcpy(mRawDataPtr, (char*)&trackletheader, sizeof(TrackletHCHeader)); + if (mVerbosity) { + LOG(info) << "writing tracklethcheader of 0x" << std::hex << trackletheader.word; + } + mRawDataPtr += 4; + wordswritten++; + } + return wordswritten; +} + +int Trap2CRU::writeDigitHCHeader(const int eventcount, const uint32_t linkid) +{ + // we have 2 HCHeaders defined Tracklet and Digit in Rawdata.h + int wordswritten = 0; + //from linkid we can get supermodule, stack, layer, side + int detector = linkid / 2; + + DigitHCHeader digitheader; + DigitHCHeader1 digitheader1; + digitheader.res = 1; + digitheader.side = (linkid % 2) ? 1 : 0; + digitheader.stack = (detector % (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK)) / o2::trd::constants::NLAYER; + digitheader.layer = (detector % o2::trd::constants::NLAYER); + digitheader.supermodule = linkid / 60; + digitheader.numberHCW = 1; // number of additional words in th header, we are using 2 header words so 1 here. + digitheader.minor = 42; // my (shtm) version, not used + digitheader.major = 0x21; // zero suppressed and 0x1 to comply with what we see in the raw data + digitheader.version = 1; //new version of the header. we only have 1 version + digitheader1.res = 1; + digitheader1.ptrigcount = 1; //TODO put something more real in here? + digitheader1.ptrigphase = 1; //TODO put something more real in here? + digitheader1.bunchcrossing = eventcount; //NB this is not the same as the bunchcrossing the rdh. See RawData.h for explanation + digitheader1.numtimebins = 30; + memcpy(mRawDataPtr, (char*)&digitheader, sizeof(DigitHCHeader)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional. + mRawDataPtr += sizeof(DigitHCHeader); + memcpy(mRawDataPtr, (char*)&digitheader1, sizeof(DigitHCHeader1)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional. + mRawDataPtr += sizeof(DigitHCHeader1); + wordswritten += 2; + return wordswritten; +} + +void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, const int& triggercount) +{ //build a HalfCRUHeader for this event/cru/endpoint //loop over cru's // loop over all half chambers, thankfully they data is sorted. @@ -199,113 +597,228 @@ void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& TrigRecord) // if not blank, else fill in data from link records // dump data to rawwriter //finished for event. this method is only called per event. - int currentlinkrecord = 0; - char* traprawdataptr = (char*)&mTrapRawData[0]; - for (int halfcru = 0; halfcru < NumberOfHalfCRU; halfcru++) { - int supermodule = halfcru / 4; - int endpoint = halfcru / 2; - int side = halfcru % 2 ? 1 : 0; - mFeeID = buildTRDFeeID(supermodule, side, endpoint); - mCruID = halfcru / 2; - mLinkID = TRDLinkID; - mEndPointID = halfcru % 2 ? 1 : 0; + // char* traprawdataptr = (char*)&mTrapRawData[0]; + std::array<int64_t, 21> localParsedDigitsindex; // store the index of the digits of an mcm + int rawwords = 0; + char* rawdataptratstart; + std::vector<char> rawdatavector(1024 * 1024 * 2); // sum of link sizes + padding in units of bytes and some space for the header (512 bytes). + if (mVerbosity) { + LOG(info) << "BUNCH CROSSING : " << triggerrecord.getBCData().bc << " with orbit : " << triggerrecord.getBCData().orbit; + } + //set startdigit and starttracklet relative to the trigger. + // + int starttrackletindex = triggerrecord.getFirstTracklet(); + int endtrackletindex = triggerrecord.getFirstTracklet() + triggerrecord.getNumberOfTracklets(); + int64_t startdigitindex = triggerrecord.getFirstDigit(); + int64_t enddigitindex = triggerrecord.getFirstDigit() + triggerrecord.getNumberOfDigits(); + for (int halfcru = 0; halfcru < o2::trd::constants::NHALFCRU; halfcru++) { + int halfcruwordswritten = 0; + int supermodule = halfcru / 4; // 2 cru per supermodule. 72/4, as of writing + mEndPointID = halfcru % 2; // 2 pci end points per cru, 15 links each + //first cru is A second CRU is C , so an flp will be either ACA or CAC A=0 C=1 + int cru = halfcru / 2; + int side = cru % 2; // first cru is A second is B, 3rd is A etc + mFeeID = buildTRDFeeID(supermodule, side, mEndPointID); + mCruID = halfcru / 2; + mLinkID = o2::trd::constants::TRDLINKID; + mEndPointID = halfcru % 2; // just the upper or lower half of the cru, hence %2 of the the halfcru number. + std::string sside; + (side) ? sside = "C" : sside = "A"; + //15 links per half cru or cru end point. memset(&mRawData[0], 0, sizeof(mRawData[0]) * mRawData.size()); // zero the rawdata storage int numberofdetectors = o2::trd::constants::MAXCHAMBER; HalfCRUHeader halfcruheader; //now write the cruheader at the head of all the data for this halfcru. - LOG(debug) << "cru before building cruheader for halfcru index : " << halfcru << " with contents \n" - << halfcruheader; - uint32_t totalhalfcrudatasize = buildCRUHeader(halfcruheader, TrigRecord.getBCData().bc, halfcru, currentlinkrecord); - - std::vector<char> rawdatavector(totalhalfcrudatasize * 32 + sizeof(halfcruheader)); // sum of link sizes + padding in units of bytes and some space for the header (512 bytes). - char* rawdataptr = rawdatavector.data(); - - //dumpHalfCRUHeader(halfcruheader); - memcpy(rawdataptr, (char*)&halfcruheader, sizeof(halfcruheader)); - std::array<uint64_t, 8> raw{}; - memcpy((char*)&raw[0], rawdataptr, sizeof(halfcruheader)); - for (int i = 0; i < 2; i++) { - int index = 4 * i; - LOG(debug) << "[1/2rawdaptr " << i << " " << std::hex << raw[index + 3] << " " << raw[index + 2] << " " << raw[index + 1] << " " << raw[index + 0]; - } - rawdataptr += sizeof(halfcruheader); - - int linkdatasize = 0; // in 32 bit words - int link = halfcru / 2; - for (int halfcrulink = 0; halfcrulink < NLinksPerHalfCRU; halfcrulink++) { + buildHalfCRUHeader(halfcruheader, triggerrecord.getBCData().bc, halfcru); + halfcruheader.EndPoint = mEndPointID; + mRawDataPtr = rawdatavector.data(); + HalfCRUHeader* halfcruheaderptr = (HalfCRUHeader*)mRawDataPtr; // store the ptr to the halfcruheader for later adding the link lengths and possibly simulated errors. + mRawDataPtr += sizeof(halfcruheader); + halfcruwordswritten += sizeof(halfcruheader) / 4; + int totallinklengths = 0; + rawdataptratstart = mRawDataPtr; // keep track of where we started. + //TODO by pass all if the current digit and tracklet are not on this halfcru. + for (int halfcrulink = 0; halfcrulink < o2::trd::constants::NLINKSPERHALFCRU; halfcrulink++) { //links run from 0 to 14, so linkid offset is halfcru*15; - int linkid = halfcrulink + halfcru * NLinksPerHalfCRU; - LOG(debug) << "Currently checking for data on linkid : " << linkid << " from halfcru=" << halfcru << " and halfcrulink:" << halfcrulink << " ?? " << linkid << "==" << mLinkRecords[currentlinkrecord].getLinkId(); + int linkid = halfcrulink + halfcru * o2::trd::constants::NLINKSPERHALFCRU; + if (mVerbosity) { + LOG(info) << " linkid : " << linkid << " with link " << halfcrulink << " of halfcru " << halfcru << " tracklet is on link for linkid : " << linkid << " and tracklet index of : " << mCurrentTracklet << " with current digit index : " << mCurrentDigit; + } + int linkwordswritten = 0; int errors = 0; // put no errors in for now. int size = 0; // in 32 bit words - int datastart = 0; // in 32 bit words - int dataend = 0; // in 32 bit words uint32_t paddingsize = 0; // in 32 bit words uint32_t crudatasize = 0; // in 256 bit words. - if (mLinkRecords[currentlinkrecord].getLinkId() == linkid) { - //this link has data in the stream. - LOG(debug) << "+++ We have data on linkid = " << linkid << " halfcrulink : " << halfcrulink; - linkdatasize = mLinkRecords[currentlinkrecord].getNumberOfObjects(); - datastart = mLinkRecords[currentlinkrecord].getFirstEntry(); - dataend = datastart + size; - LOG(debug) << "We have data on linkid = " << linkid << " and linksize : " << linkdatasize << " so :" << linkdatasize / 8 << " 256 bit words"; - currentlinkrecord++; - } else { - assert(mLinkRecords[currentlinkrecord].getLinkId() < linkid); - LOG(debug) << "---We do not have data on linkid = " << linkid << " halfcrulink : " << halfcrulink; - //blank data for this link - // put in a 1 256 bit word of data for the link and padd with 0xeeee x 8 - linkdatasize = 0; - paddingsize = 8; + //loop over tracklets for mcm's that match + int tracklets = 0; + int trackletendmarker = 0; + int adccounter = 0; + int rawwordsbefore = 0; + bool isFirstDigit = true; + int trackletcounter = 0; + if (mVerbosity) { + LOG(info) << "tracklet on link : " << linkid << " mcurrentdigit:" << mCurrentTracklet << " endtrackletindex:" << endtrackletindex << " is on link: " << isTrackletOnLink(linkid, mCurrentTracklet) << " and digits current digit:" << mCurrentDigit << " enddigitindex:" << enddigitindex << "is digit on link:" << isDigitOnLink(linkid, mCurrentDigit); } - // now copy data to rawdata, padding as and where needed. - // - linkSizePadding(linkdatasize, crudatasize, paddingsize); //TODO this can come out as we have already called it, but previously we have lost the #padding words, solve to remove. - - LOG(debug) << "WRITING " << crudatasize << " 256 bit data words to output stream"; - LOG(debug) << "setting CRY HEADER for " << halfcruheader << ":" << halfcrulink << ":" << crudatasize << ":" << errors; - // now pad .... - LOG(debug) << " now to pump data into the stream with : " << linkdatasize << " crudatasize:" << crudatasize << " paddingsize: " << paddingsize << " and rem:" << linkdatasize % 8; - char* olddataptr = rawdataptr; // store the old pointer so we can do some sanity checks for how far we advance. - //linkdatasize is the #of 32 bit words coming from the incoming tree. - //paddingsize is the number of padding words to add 0xeeee - uint32_t bytestocopy = linkdatasize * (sizeof(uint32_t)); - LOG(debug) << "copying " << bytestocopy << " bytes of link tracklet data at pos:" << std::hex << static_cast<void*>(rawdataptr); - memcpy(rawdataptr, traprawdataptr, bytestocopy); - //increment pointer - rawdataptr += bytestocopy; - traprawdataptr += bytestocopy; - //now for padding - uint16_t padbytes = paddingsize * sizeof(uint32_t); - LOG(debug) << "writing " << padbytes << " bytes of padding data at pos:" << std::hex << static_cast<void*>(rawdataptr); - memset(rawdataptr, 0xee, padbytes); - //increment pointer. - rawdataptr += padbytes; - if (padbytes + bytestocopy != crudatasize * 32) { - LOG(debug) << "something wrong with data size writing padbytes:" << padbytes << " bytestocopy : " << bytestocopy << " crudatasize:" << crudatasize; + if (isTrackletOnLink(linkid, mCurrentTracklet) || isDigitOnLink(linkid, mCurrentDigit)) { + // we have some data somewhere for this link + //write tracklet half chamber header irrespective of there being tracklet data + if (mUseTrackletHCHeader != 0) { + if (isTrackletOnLink(linkid, mCurrentTracklet) || mUseTrackletHCHeader == 2) { + //write tracklethcheader if there is tracklet data or if we always have tracklethcheader + //first part of the if statement handles the mUseTrackletHCHeader==1 option + int hcheaderwords = writeTrackletHCHeader(triggercount, linkid); + linkwordswritten += hcheaderwords; + rawwords += hcheaderwords; + } + //else do nothing as we dont want/have tracklethcheader + } + while (isTrackletOnLink(linkid, mCurrentTracklet) && mCurrentTracklet < endtrackletindex) { + // still on an mcm on this link + tracklets = buildTrackletRawData(mCurrentTracklet, linkid); //returns # of 32 bits, header plus trackletdata words that would have come from the mcm. + mCurrentTracklet += tracklets; + trackletcounter += tracklets; + linkwordswritten += tracklets + 1; + rawwords += tracklets + 1; //1 to include the header + } + if (mCurrentTracklet >= mTracklets.size()) { + LOG(debug) << " finished with tracklets"; + } + //write tracklet end marker irrespective of their being tracklet data. + trackletendmarker = writeTrackletEndMarker(); + linkwordswritten += trackletendmarker; + rawwords += trackletendmarker; + adccounter = 0; + rawwordsbefore = rawwords; + //always write the digit hc header + int hcheaderwords = writeDigitHCHeader(triggercount, linkid); + linkwordswritten += hcheaderwords; + rawwords += hcheaderwords; + //although if there are trackelts there better be some digits unless the digits are switched off. + if (mCurrentDigit < mDigits.size()) { + while (isDigitOnLink(linkid, mCurrentDigit) && mCurrentDigit < enddigitindex && mEventDigitCount % mDigitRate == 0) { + if (mVerbosity) { + LOG(info) << "at top of digit while loop calc linkid :" << linkid << " : " << mDigits[mDigitsIndex[mCurrentDigit]].getDetector() * 2 + mDigits[mDigitsIndex[mCurrentDigit]].getROB() % 2 << " actual link=" << linkid; + } + //while we are on a single mcm, copy the digits timebins to the array. + int digitcounter = 0; + int currentROB = mDigits[mDigitsIndex[mCurrentDigit]].getROB(); + int currentMCM = mDigits[mDigitsIndex[mCurrentDigit]].getMCM(); + int currentDetector = mDigits[mDigitsIndex[mCurrentDigit]].getDetector(); + int startmCurrentDigit = mCurrentDigit; + while (mDigits[mDigitsIndex[mCurrentDigit]].getMCM() == currentMCM && + mDigits[mDigitsIndex[mCurrentDigit]].getROB() == currentROB && + mDigits[mDigitsIndex[mCurrentDigit]].getDetector() == currentDetector) { + LOG(debug) << " on index of : " << mDigitsIndex[mCurrentDigit] << " wuf channel=" << mDigits[mDigitsIndex[mCurrentDigit]].getChannel(); + mCurrentDigit++; + digitcounter++; + adccounter++; + if (digitcounter > 22) { + LOG(error) << " we are on the 22nd digit of an mcm ?? This is not possible"; + } + } + // mcm digits are full, now write it out. + char* preptr; + preptr = mRawDataPtr; + int digitwordswritten = 0; + digitwordswritten = buildDigitRawData(startmCurrentDigit, mCurrentDigit, currentMCM, currentROB, triggercount); + linkwordswritten += digitwordswritten; + } + } } - LOG(debug3) << std::hex << " rawdataptr:" << static_cast<void*>(rawdataptr) << " traprawdataptr " << static_cast<void*>(traprawdataptr); - //sanity check for now: - if (((char*)rawdataptr - (char*)olddataptr) != crudatasize * 32) { // cru words are 8 uint32 and comparison is in bytes. - LOG(debug) << "according to pointer arithmatic we have added " << rawdataptr - olddataptr << "bytes from " << static_cast<void*>(rawdataptr) << "-" << static_cast<void*>(olddataptr) << " when we should have added " << crudatasize * 8 * 4 << " because crudatasize=" << crudatasize; + if (mVerbosity) { + LOG(info) << "link:" << linkid << " trackletcounter: " << trackletcounter << " currenttracklet: " << mCurrentTracklet << " adccounter :" << adccounter << " current digit : " << mCurrentDigit; } - if (crudatasize != o2::trd::getlinkdatasize(halfcruheader, halfcrulink)) { - // we have written the wrong amount of data .... - LOG(debug) << "crudata is ! = get link data size " << crudatasize << "!=" << o2::trd::getlinkdatasize(halfcruheader, halfcrulink); + int counter = 0; + if (adccounter > 0 || trackletcounter > 0) { + //write the tracklet end marker so long as we have any data (digits or tracklets). + int digitendmarkerwritten = writeDigitEndMarker(); + linkwordswritten += digitendmarkerwritten; + rawwords += digitendmarkerwritten; } - LOG(debug) << "copied " << crudatasize * 32 << "bytes to halfcrurawdata which now has size of " << rawdatavector.size() << " for " << link << ":" << endpoint; - } - LOG(debug) << "writing to " << std::hex << mFeeID << std::dec << " : " << mCruID << " : " << mLinkID << " : " << mEndPointID; - mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, TrigRecord.getBCData(), rawdatavector); - if (DebugDataWriting) { - std::ofstream out2("crutestdumprawdatavector"); - out2.write(rawdatavector.data(), rawdatavector.size()); - out2.flush(); - halfcru = NumberOfHalfCRU; // exit loop after 1 half cru for now. + //pad up to a whole 256 bit word size + if (linkwordswritten != 0) { + crudatasize = linkwordswritten / 8; + linkSizePadding(linkwordswritten, crudatasize, paddingsize); + + // now pad the data if needed .... + char* olddataptr = mRawDataPtr; // store the old pointer so we can do some sanity checks for how far we advance. + //now for padding + uint16_t padbytes = paddingsize * sizeof(uint32_t); + uint32_t padword = 0xeeeeeeee; + for (int i = 0; i < paddingsize; ++i) { + memcpy(mRawDataPtr, (char*)&padword, 4); + mRawDataPtr += 4; + linkwordswritten++; + rawwords++; + } + crudatasize = linkwordswritten / 8; //convert to 256 bit alignment. + if ((linkwordswritten % 8) != 0) { + LOG(error) << "linkwordswritten is not 256 bit aligned " << linkwordswritten << " %8 = " << linkwordswritten % 8 << " and a padding size of : " << paddingsize << " or padbytes of : " << padbytes; + } + //set the halfcruheader for the length of this link. + //but first a sanity check. + if (crudatasize > constants::MAXDATAPERLINK256) { + LOG(error) << " linksize is huge : " << crudatasize; + } + LOG(debug) << " setting halfcrulink " << halfcrulink << " linksize to : " << crudatasize << " with a linkwordswrittern=" << linkwordswritten; + setHalfCRUHeaderLinkData(halfcruheader, halfcrulink, crudatasize, errors); + uint32_t bytescopied; + totallinklengths += crudatasize; + if ((mRawDataPtr - rawdataptratstart) != (totallinklengths * 32)) { + bytescopied = mRawDataPtr - rawdataptratstart; + if (mVerbosity) { + LOG(info) << "something wrong with data size in cruheader writing" + << "linkwordswriten:" + << linkwordswritten << " rawwords:" << rawwords << "bytestocopy : " + << bytescopied << " crudatasize:" << crudatasize << " sum of links up to now : " + << totallinklengths << " mRawDataPtr:0x" << std::hex << (void*)mRawDataPtr + << " start ptr:" << std::hex << (void*)rawdataptratstart; + } + } else { + if (mVerbosity) { + LOG(debug) << "all fine with data size writing padbytes:" << paddingsize + << " linkwordswriten:" << linkwordswritten << " bytestocopy : " << bytescopied + << " crudatasize:" << crudatasize << " mRawDataPtr:0x" << std::hex + << (void*)mRawDataPtr << " start ptr:" << std::hex << (void*)rawdataptratstart; + } + } + //sanity check for now: + if (crudatasize != o2::trd::getlinkdatasize(halfcruheader, halfcrulink)) { + // we have written the wrong amount of data .... + LOG(warn) << "crudata is ! = get link data size " << crudatasize << "!=" << o2::trd::getlinkdatasize(halfcruheader, halfcrulink); + } + } // if we have data on link + else { + setHalfCRUHeaderLinkData(halfcruheader, halfcrulink, 0, 0); + if (mVerbosity) { + LOG(info) << "linkwordswritten is zero : " << linkwordswritten; + } + if (crudatasize != 0) { + LOG(warn) << " we should not be here with a crudatasize of " << crudatasize << " as the linkwordswritten is " << linkwordswritten << " with a halfcrulink of : " << halfcrulink; + LOG(debug) << " ### setting halfcrulink " << halfcrulink << " linksize to : " << crudatasize << " with a linkwordswrittern=" << linkwordswritten; + } + // setHalfCRUHeaderLinkData(halfcruheader, halfcrulink, 0,0); + } + halfcruwordswritten += linkwordswritten; + } // if tracklets.size >0 + //write the cruhalfheader now that we know the lengths. + memcpy((char*)halfcruheaderptr, (char*)&halfcruheader, sizeof(halfcruheader)); + //write halfcru data here. + std::vector<char> feeidpayload(halfcruwordswritten * 4); + memcpy(feeidpayload.data(), &rawdatavector[0], halfcruwordswritten * 4); + assert(halfcruwordswritten % 8 == 0); + mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, triggerrecord.getBCData(), feeidpayload, false, triggercount); + if (mVerbosity) { + LOG(info) << "written file for trigger : " << triggercount << " feeid of 0x" << std::hex << mFeeID << " cruid : " << mCruID << " and linkid: " << mLinkID << " and EndPoint: " << mEndPointID << " orbit :0x" << std::hex << triggerrecord.getBCData().orbit << " bc:0x" << std::hex << triggerrecord.getBCData().bc << " and payload size of : " << halfcruwordswritten << " with a half cru of: "; + printHalfCRUHeader(halfcruheader); + HalfCRUHeader* h; + h = (HalfCRUHeader*)feeidpayload.data(); + HalfCRUHeader h1 = *h; + printHalfCRUHeader(h1); + LOG(info) << "+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+ ====== end of writing"; } } } - } // end namespace trd } // end namespace o2 diff --git a/Detectors/TRD/simulation/src/TrapConfig.cxx b/Detectors/TRD/simulation/src/TrapConfig.cxx index 3090036aa2c41..d02c2bc4b230f 100644 --- a/Detectors/TRD/simulation/src/TrapConfig.cxx +++ b/Detectors/TRD/simulation/src/TrapConfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -1064,7 +1065,7 @@ void TrapConfig::configureOnlineGains() for (int iDet = 0; iDet < nDets; ++iDet) { //const int MaxRows = Geometry::getStack(iDet) == 2 ? NROWC0 : NROWC1; int MaxCols = NCOLUMN; - // CalOnlineGainTableROC gainTbl = mGainTable.getGainTableROC(iDet); + //CalOnlineGainTableROC gainTbl = mGainTable.getGainTableROC(iDet); const int nRobs = Geometry::getStack(iDet) == 2 ? Geometry::ROBmaxC0() : Geometry::ROBmaxC1(); for (int rob = 0; rob < nRobs; ++rob) { diff --git a/Detectors/TRD/simulation/src/TrapConfigHandler.cxx b/Detectors/TRD/simulation/src/TrapConfigHandler.cxx index e0c144dd11ec3..a0c2685d2e670 100644 --- a/Detectors/TRD/simulation/src/TrapConfigHandler.cxx +++ b/Detectors/TRD/simulation/src/TrapConfigHandler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -478,6 +479,7 @@ void TrapConfigHandler::configureDRange(int det) // if pt_min < 0.1 GeV/c the maximal allowed range for the tracklet // deflection (-64..63) is used // + // TODO might need to be updated depending in the FEE configuration for Run 3 if (!mTrapConfig) { LOG(error) << "No TRAPconfig given"; @@ -495,7 +497,7 @@ void TrapConfigHandler::configureDRange(int det) // cout << "maxdefl: " << maxDeflAngle << ", localPhi " << localPhi << endl; // cout << "r " << r << ", m" << m << ", c " << c << ", min angle: " << localPhi-maxDeflAngle << ", max: " << localPhi+maxDeflAngle - // << ", min int: " << dyMinInt << ", max int: " << dyMaxInt << endl; + //<< ", min int: " << dyMinInt << ", max int: " << dyMaxInt << endl; int dest = 1 << 10 | r << 7 | m; int lutAddr = TrapSimulator::mgkDmemAddrDeflCutStart + 2 * c; mFeeParam->getDyRange(det, r, m, c, dyMinInt, dyMaxInt); diff --git a/Detectors/TRD/simulation/src/TrapSimulator.cxx b/Detectors/TRD/simulation/src/TrapSimulator.cxx index 793a2d3a2ef0f..e8ffd3bd57cf9 100644 --- a/Detectors/TRD/simulation/src/TrapSimulator.cxx +++ b/Detectors/TRD/simulation/src/TrapSimulator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,10 +19,8 @@ /////////////////////////////////////////////////////////////////////////////// #include "TRDBase/SimParam.h" -#include "TRDBase/CommonParam.h" #include "TRDBase/Geometry.h" #include "TRDBase/FeeParam.h" -#include "TRDBase/Tracklet.h" #include "TRDBase/CalOnlineGainTables.h" #include "TRDSimulation/TrapConfigHandler.h" #include "TRDSimulation/TrapConfig.h" @@ -29,7 +28,7 @@ #include "fairlogger/Logger.h" //to pull in the digitzer incomnig data. -#include "TRDBase/Digit.h" +#include "DataFormatsTRD/Digit.h" #include "TRDSimulation/Digitizer.h" #include <SimulationDataFormat/MCCompLabel.h> #include <SimulationDataFormat/MCTruthContainer.h> @@ -50,54 +49,32 @@ #include "TRandom3.h" #include <ostream> #include <fstream> +#include <numeric> using namespace o2::trd; using namespace std; using namespace o2::trd::constants; -#define DEBUGTRAP 1 +#define infoTRAP 1 bool TrapSimulator::mgApplyCut = true; int TrapSimulator::mgAddBaseline = 0; -bool TrapSimulator::mgStoreClusters = true; +bool TrapSimulator::mgStoreClusters = false; const int TrapSimulator::mgkFormatIndex = std::ios_base::xalloc(); const std::array<unsigned short, 4> TrapSimulator::mgkFPshifts{11, 14, 17, 21}; -TrapSimulator::TrapSimulator() - : mInitialized(false), mDetector(-1), mRobPos(-1), mMcmPos(-1), mRow(-1), mNTimeBin(-1), mTrklBranchName("mcmtrklbranch"), mFeeParam(nullptr), mTrapConfig(nullptr) -{ - // - // TrapSimulator default constructor - // By default, nothing is initialized. - // It is necessary to issue init before use. - - mFitPtr[0] = 0; - mFitPtr[1] = 0; - mFitPtr[2] = 0; - mFitPtr[3] = 0; - mNHits = 0; - // mCalib.setCCDBForSimulation(297595); -} - void TrapSimulator::init(TrapConfig* trapconfig, int det, int robPos, int mcmPos) { // // Initialize the class with new MCM position information - // memory is allocated in the first initialization // - // - LOG(debug4) << " : trap sim is at : 0x" << hex << trapconfig; - if (!mInitialized) { - mFeeParam = FeeParam::instance(); - mTrapConfig = trapconfig; - } - mDetector = det; mRobPos = robPos; mMcmPos = mcmPos; mRow = mFeeParam->getPadRowFromMCM(mRobPos, mMcmPos); if (!mInitialized) { + mTrapConfig = trapconfig; mNTimeBin = mTrapConfig->getTrapReg(TrapConfig::kC13CPUA, mDetector, mRobPos, mMcmPos); mZSMap.resize(NADCMCM); @@ -128,29 +105,35 @@ void TrapSimulator::reset() } //clear the adc data - memset(&mADCR[0], 0, sizeof(mADCR[0]) * mADCR.size()); - memset(&mADCF[0], 0, sizeof(mADCF[0]) * mADCF.size()); - //clear the labels - mADCLabels[0].clear(); - mADCLabels[1].clear(); - mADCLabels[2].clear(); - - mTrackletLabels.clear(); // as the name implies clear the stored labels - mNHits = 0; + std::fill(mADCR.begin(), mADCR.end(), 0); + std::fill(mADCF.begin(), mADCF.end(), 0); + std::fill(mADCDigitIndices.begin(), mADCDigitIndices.end(), -1); for (auto filterreg : mInternalFilterRegisters) { filterreg.ClearReg(); } + // clear the tracklet detail information. + for (auto trackletdetail : mTrackletDetails) { + trackletdetail.clear(); + } // Default unread, low active bit mask - memset(&mZSMap[0], 0, sizeof(mZSMap[0]) * NADCMCM); - memset(&mMCMT[0], 0, sizeof(mMCMT[0]) * mgkMaxTracklets); - //mDict1.clear(); - //mDict2.clear(); - //mDict3.clear(); + std::fill(mZSMap.begin(), mZSMap.end(), 0); + std::fill(mMCMT.begin(), mMCMT.end(), 0); filterPedestalInit(); - filterGainInit(); + //filterGainInit(); // we do not use the gain filter anyway, so disable it completely filterTailInit(); + + for (auto& fitreg : mFitReg) { + fitreg.ClearReg(); + } + mADCFilled = 0; + + mTrackletArray64.clear(); + mTrackletDigitCount.clear(); + mTrackletDigitIndices.clear(); + + mDataIsSet = false; } // ----- I/O implementation ----- @@ -316,7 +299,7 @@ void TrapSimulator::printFitRegXml(ostream& os) const void TrapSimulator::printTrackletsXml(ostream& os) const { // print tracklets in XML format - + //TODO FIX this to new format const char* const cmdid{R"(" cmdid="0">)"}; os << "<nginject>" << std::endl; os << "<ack roc=\"" << mDetector << cmdid << std::endl; @@ -326,6 +309,7 @@ void TrapSimulator::printTrackletsXml(ostream& os) const os << " <m mcm=\"" << mMcmPos << "\">" << std::endl; int pid, padrow, slope, offset; + //TODO take care of the 0th being the header, and cpu1,2,3 being 1 to 3 tracklets. for (int cpu = 0; cpu < 4; cpu++) { if (mMCMT[cpu] == 0x10001000) { pid = -1; @@ -625,17 +609,6 @@ void TrapSimulator::noiseTest(int nsamples, int mean, int sigma, int inputGain, hft->Draw(); } -bool TrapSimulator::checkInitialized() const -{ - // - // Check whether object is initialized - // - - // if (!mInitialized) - // LOG(debug4) << "TrapSimulator is not initialized but function other than Init() is called."; - - return mInitialized; -} void TrapSimulator::print(int choice) const { @@ -653,7 +626,7 @@ void TrapSimulator::print(int choice) const return; } - LOG(info) << "MCM " << mMcmPos << " on ROB " << mRobPos << " in detector " << mDetector; + LOG(debug) << "MCM " << mMcmPos << " on ROB " << mRobPos << " in detector " << mDetector; //std::string opt = option; if ((choice & PRINTRAW) != 0 || (choice & PRINTFILTERED) != 0) { @@ -661,16 +634,17 @@ void TrapSimulator::print(int choice) const } if ((choice & PRINTDETECTED) != 0) { - LOG(info) << "Found " << mNHits << " hits:"; + LOG(debug) << "Found " << mNHits << " hits:"; for (int iHit = 0; iHit < mNHits; iHit++) { - LOG(info) << "Hit " << std::setw(3) << iHit << " in timebin " << std::setw(2) << mHits[iHit].mTimebin << ", ADC " << std::setw(2) << mHits[iHit].mChannel << " has charge " << std::setw(3) << mHits[iHit].mQtot << " and position " << mHits[iHit].mYpos; + LOG(debug) << "Hit " << std::setw(3) << iHit << " in timebin " << std::setw(2) << mHits[iHit].mTimebin << ", ADC " << std::setw(2) << mHits[iHit].mChannel << " has charge " << std::setw(3) << mHits[iHit].mQtot << " and position " << mHits[iHit].mYpos; } } if ((choice & PRINTFOUND) != 0) { - LOG(info) << "Found Tracklets:"; - for (int iTrkl = 0; iTrkl < mTrackletArray.size(); iTrkl++) { - LOG(info) << "tracklet " << iTrkl << ": 0x" << hex << std::setw(16) << mTrackletArray[iTrkl].getTrackletWord(); + LOG(debug) << "Found Tracklets:"; + for (int iTrkl = 0; iTrkl < mTrackletArray64.size(); iTrkl++) { + LOG(debug) << "tracklet " << iTrkl << ": 0x" << hex << std::setw(32) << mTrackletArray64[iTrkl].getTrackletWord(); + LOG(debug) << mTrackletArray64[iTrkl]; } } } @@ -688,7 +662,7 @@ void TrapSimulator::draw(int choice, int index) return; } TFile* rootfile = new TFile("trdtrackletplots.root", "UPDATE"); - TCanvas* c1 = new TCanvas(Form("canvas_%i_%i:%i:%i_%i", index, mDetector, mRobPos, mMcmPos, (int)mTrackletArray.size())); + TCanvas* c1 = new TCanvas(Form("canvas_%i_%i:%i:%i_%i", index, mDetector, mRobPos, mMcmPos, (int)mTrackletArray64.size())); TH2F* hist = new TH2F(Form("mcmdata_%i", index), Form("Data of MCM %i on ROB %i in detector %i ", mMcmPos, mRobPos, mDetector), NADCMCM, @@ -739,44 +713,39 @@ void TrapSimulator::draw(int choice, int index) if ((choice & PLOTTRACKLETS) != 0) { TLine* trklLines = new TLine[4]; - LOG(info) << "Tracklet start for index : " << index; - if (mTrackletArray.size() > 0) { - LOG(info) << "Tracklet : for " << mTrackletArray[0].getDetector() << "::" << mTrackletArray[0].getROB() << " : " << mTrackletArray[0].getMCM(); + LOG(debug) << "Tracklet start for index : " << index; + if (mTrackletArray64.size() > 0) { + LOG(debug) << "Tracklet : for " << mTrackletArray64[0].getDetector() << "::" << mTrackletArray64[0].getROB() << " : " << mTrackletArray64[0].getMCM(); } else { - LOG(info) << "Tracklet : for trackletarray size of zero "; + LOG(debug) << "Tracklet : for trackletarray size of zero "; } - for (int iTrkl = 0; iTrkl < mTrackletArray.size(); iTrkl++) { - Tracklet trkl = mTrackletArray[iTrkl]; - float padWidth = 0.635 + 0.03 * (mDetector % 6); - float offset = padWidth / 256. * ((((((mRobPos & 0x1) << 2) + (mMcmPos & 0x3)) * 18) << 8) - ((18 * 4 * 2 - 18 * 2 - 3) << 7)); // revert adding offset in FitTracklet - //TODO replace the 18, 4 3 and 7 with constants for readability + for (int iTrkl = 0; iTrkl < mTrackletArray64.size(); iTrkl++) { + Tracklet64 trkl = mTrackletArray64[iTrkl]; + float position = trkl.getPosition(); int ndrift = mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos) >> 5; - float slope = 0; - if (ndrift) { - slope = trkl.getdY() * 140e-4 / ndrift; - } + float slope = trkl.getSlope(); int t0 = mTrapConfig->getTrapReg(TrapConfig::kTPFS, mDetector, mRobPos, mMcmPos); int t1 = mTrapConfig->getTrapReg(TrapConfig::kTPFE, mDetector, mRobPos, mMcmPos); - trklLines[iTrkl].SetX1((offset - (trkl.getY() - slope * t0)) / padWidth); // ??? sign? + trklLines[iTrkl].SetX1(position - slope * t0); trklLines[iTrkl].SetY1(t0); - trklLines[iTrkl].SetX2((offset - (trkl.getY() - slope * t1)) / padWidth); // ??? sign? + trklLines[iTrkl].SetX2(position - slope * t1); trklLines[iTrkl].SetY2(t1); trklLines[iTrkl].SetLineColor(2); trklLines[iTrkl].SetLineWidth(2); - LOG(info) << "Tracklet " << iTrkl << ": y = " << trkl.getY() << ", dy = " << (((float)trkl.getdY()) * 140e-4) << " offset : " << offset << "for a det:rob:mcm combo of : " << mDetector << ":" << mRobPos << ":" << mMcmPos; - LOG(info) << "Tracklet " << iTrkl << ": x1,y1,x2,y2 :: " << trklLines[iTrkl].GetX1() << "," << trklLines[iTrkl].GetY1() << "," << trklLines[iTrkl].GetX2() << "," << trklLines[iTrkl].GetY2(); - LOG(info) << "Tracklet " << iTrkl << ": t0 : " << t0 << ", t1 " << t1 << ", padwidth:" << padWidth << ", slope:" << slope << ", ndrift:" << ndrift << " which comes from : " << mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos) << " shifted 5 to the right "; + LOG(debug) << "Tracklet " << iTrkl << ": y = " << trkl.getPosition() << ", slope = " << (float)trkl.getSlope() << "for a det:rob:mcm combo of : " << mDetector << ":" << mRobPos << ":" << mMcmPos; + LOG(debug) << "Tracklet " << iTrkl << ": x1,y1,x2,y2 :: " << trklLines[iTrkl].GetX1() << "," << trklLines[iTrkl].GetY1() << "," << trklLines[iTrkl].GetX2() << "," << trklLines[iTrkl].GetY2(); + LOG(debug) << "Tracklet " << iTrkl << ": t0 : " << t0 << ", t1 " << t1 << ", slope:" << slope << ", which comes from : " << mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos) << " shifted 5 to the right "; trklLines[iTrkl].Draw(); } - LOG(info) << "Tracklet end ..."; + LOG(debug) << "Tracklet end ..."; } c1->Write(); rootfile->Close(); } -void TrapSimulator::setData(int adc, const ArrayADC& data, std::vector<o2::MCCompLabel>& labels) +void TrapSimulator::setData(int adc, const ArrayADC& data, unsigned int digitIdx) { // // Store ADC data into array of raw data @@ -787,24 +756,19 @@ void TrapSimulator::setData(int adc, const ArrayADC& data, std::vector<o2::MCCom } if (adc < 0 || adc >= NADCMCM) { - // LOG(error) << "Error: ADC " << adc << " is out of range (0 .. " << NADCMCM - 1 << ")"; + LOG(error) << "Error: ADC " << adc << " is out of range (0 .. " << NADCMCM - 1 << ")"; return; } - // LOG(info) << "Set Data : Det:Rob:MCM::"<< getDetector() <<":" <<getRobPos()<<":"<<getMcmPos() << " t:"<< mNTimeBin; + // OS: in Run 2 zero was suppressed!!! for (int it = 0; it < mNTimeBin; it++) { mADCR[adc * mNTimeBin + it] = ((int)(data[it]) << mgkAddDigits) + (mgAddBaseline << mgkAddDigits); mADCF[adc * mNTimeBin + it] = ((int)(data[it]) << mgkAddDigits) + (mgAddBaseline << mgkAddDigits); - // mADCR[adc * mNTimeBin + it] = (unsigned int)(data[it]); - // mADCF[adc * mNTimeBin + it] = (unsigned int)(data[it]); - // LOG(info) << data[it] <<" at "<< adc << "*" << mNTimeBin <<"+"<<it <<"="<< adc*mNTimeBin+it << " with data :"<<mADCR[adc*mNTimeBin+it] << ":" << mADCF[adc*mNTimeBin+it]; } mDataIsSet = true; mADCFilled |= (1 << adc); - //for (auto& tmplabel : labels) mADCLabels[adc].push_back(tmplabel); - LOG(debug) << "setting data labels incoming of : " << labels.size() << " with adc of " << adc; - mADCLabels[adc] = labels; - LOG(debug) << "setting data labels incoming of : " << labels.size() << " with adc of " << adc << " now mADCLabels[adc] size is : " << mADCLabels[adc].size(); + + mADCDigitIndices[adc] = digitIdx; } void TrapSimulator::setData(int adc, int it, int data) @@ -835,12 +799,12 @@ void TrapSimulator::setBaselines() //we now add it by singular ADC, so there are adc channels that never get touched. //this fixes that. - LOG(info) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " for " << mDetector << ":" << mRobPos << ":" << mMcmPos; + LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " for " << mDetector << ":" << mRobPos << ":" << mMcmPos; //loop over all adcs. for (int adc = 0; adc < NADCMCM; adc++) { - LOG(info) << "Setting baselines for adc: " << adc << " of " << mDetector << ":" << mRobPos << ":" << mMcmPos << hex << mADCFilled << " if of : " << (mADCFilled & (1 << adc)); + LOG(debug) << "Setting baselines for adc: " << adc << " of " << mDetector << ":" << mRobPos << ":" << mMcmPos << hex << mADCFilled << " if of : " << (mADCFilled & (1 << adc)); if ((mADCFilled & (1 << adc)) == 0) { // adc is empty by construction of mADCFilled. - LOG(info) << "past if Setting baselines for adc: " << adc << " of " << mDetector << ":" << mRobPos << ":" << mMcmPos; + LOG(debug) << "past if Setting baselines for adc: " << adc << " of " << mDetector << ":" << mRobPos << ":" << mMcmPos; for (int timebin = 0; timebin < mNTimeBin; timebin++) { mADCR[adc * mNTimeBin + timebin] = mTrapConfig->getTrapReg(TrapConfig::kFPNP, mDetector, mRobPos, mMcmPos) + (mgAddBaseline << mgkAddDigits); mADCF[adc * mNTimeBin + timebin] = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos) + (mgAddBaseline << mgkAddDigits); @@ -887,11 +851,6 @@ bool TrapSimulator::getHit(int index, int& channel, int& timebin, int& qtot, int return true; } -//TrapSimualtor::Hit& TrapSimulator::getHit(int index, int& channel, int& timebin, int& qtot, int& ypos, float& y, std::vector<o2::MCCompLabel> &labels) const -//{ -// LOG(fatal) << "for now its not implemented"; -// return nullptr; -//} int TrapSimulator::getCol(int adc) { @@ -924,6 +883,7 @@ int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) uint32_t wordswritten = 0; // count the 32 bit words written; // std::cout << &raw[offset] << std::endl; // std::cout << raw.data() << std::endl;; + // //TODO query? the mCPU have the packed data, rather use them? TrackletMCMHeader mcmhead; int trackletcount = 0; // TrackletMCMHeader mcmhead; @@ -951,10 +911,8 @@ int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) break; // all of Q2 and upper 2 bits of Q1. } tracklets[i].checkbit = 1; - uint32_t tmppid = mTrackletArray64[i].getPID() & 0x3fff; - LOG(debug) << "tracklet i " << i << " has pid of 0x" << std::hex << mTrackletArray64[i].getPID() << " and we are going to put in 0x" << std::hex << tmppid; LOG(debug) << mTrackletArray64[i]; - tracklets[i].pid = mTrackletArray64[i].getPID() & 0x3fff; // the bottom 12 bits of the pid + tracklets[i].pid = mTrackletArray64[i].getQ0() & (mTrackletArray64[i].getQ1() << 8); tracklets[i].slope = mTrackletArray64[i].getSlope(); tracklets[i].pos = mTrackletArray64[i].getPosition(); tracklets[i].checkbit = 0; @@ -983,7 +941,7 @@ int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) //display the headers written if (debugheaders) { - LOG(info) << ">>>>> START DEBUG OUTPUT OF packData trackletcount:-:wordcount" << trackletcount << ":-:" << wordswritten; + LOG(debug) << ">>>>> START info OUTPUT OF packData trackletcount:-:wordcount" << trackletcount << ":-:" << wordswritten; o2::trd::printTrackletMCMHeader(mcmhead); o2::trd::printTrackletMCMData(tracklets[0]); if (trackletcount > 1) { @@ -992,7 +950,7 @@ int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) if (trackletcount > 2) { o2::trd::printTrackletMCMData(tracklets[2]); } - LOG(info) << "<<<<< END DEBUG OUTPUT OF packData"; + LOG(debug) << "<<<<< END info OUTPUT OF packData"; } //must produce between 2 and 4 words ... 1 and 3 tracklets. // assert(wordswritten<5); @@ -1003,6 +961,9 @@ int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) int TrapSimulator::getRawStream(std::vector<uint32_t>& buf, uint32_t offset, unsigned int iEv) const { + // + // This is simply a copy of fix to compile from run2 + // TODO needs to possibly be updated changed thrown away ??? problem for later, worry about tracklets now. // // Produce raw data stream from this MCM and put in buf // Returns number of words filled, or negative value @@ -1031,7 +992,7 @@ int TrapSimulator::getRawStream(std::vector<uint32_t>& buf, uint32_t offset, uns } // Produce ADC mask : nncc cccm mmmm mmmm mmmm mmmm mmmm 1100 - // n : unused , c : ADC count, m : selected ADCs + // n : unused , c : ADC count, m : selected ADCs if (rawVer >= 3 && (mTrapConfig->getTrapReg(TrapConfig::kC15CPUA, mDetector, mRobPos, mMcmPos) & (1 << 13))) { // check for zs flag in TRAP configuration int nActiveADC = 0; // number numberOverFlowWordsWritten activated ADC bits in a word @@ -1143,27 +1104,27 @@ void TrapSimulator::filter() // The first filter takes the data from mADCR and // outputs to mADCF. - //LOG(info) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__; // Non-linearity filter not implemented. filterPedestal(); - filterGain(); + //filterGain(); // we do not use the gain filter anyway, so disable it completely filterTail(); // Crosstalk filter not implemented. - // LOG(info) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + LOG(debug) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__; } void TrapSimulator::filterPedestalInit(int baseline) { // Initializes the pedestal filter assuming that the input has // been constant for a long time (compared to the time constant). - // LOG(info) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; unsigned short fptc = mTrapConfig->getTrapReg(TrapConfig::kFPTC, mDetector, mRobPos, mMcmPos); // 0..3, 0 - fastest, 3 - slowest for (int adc = 0; adc < NADCMCM; adc++) { mInternalFilterRegisters[adc].mPedAcc = (baseline << 2) * (1 << mgkFPshifts[fptc]); } - // LOG(info) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + // LOG(debug) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; } unsigned short TrapSimulator::filterPedestalNextSample(int adc, int timebin, unsigned short value) @@ -1171,7 +1132,7 @@ unsigned short TrapSimulator::filterPedestalNextSample(int adc, int timebin, uns // Returns the output of the pedestal filter given the input value. // The output depends on the internal registers and, thus, the // history of the filter. - /// LOG(info) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__; unsigned short fpnp = mTrapConfig->getTrapReg(TrapConfig::kFPNP, mDetector, mRobPos, mMcmPos); // 0..511 -> 0..127.75, pedestal at the output unsigned short fptc = mTrapConfig->getTrapReg(TrapConfig::kFPTC, mDetector, mRobPos, mMcmPos); // 0..3, 0 - fastest, 3 - slowest @@ -1189,9 +1150,12 @@ unsigned short TrapSimulator::filterPedestalNextSample(int adc, int timebin, uns mInternalFilterRegisters[adc].mPedAcc = (mInternalFilterRegisters[adc].mPedAcc + correction) & 0x7FFFFFFF; // 31 bits } - // LOG(info) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + // LOG(debug) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; if (fpby == 0) { - return value; + LOG(debug) << "LEAVE: (about to)" << __FILE__ << ":" << __func__ << ":" << __LINE__; + if (fpby == 0) { + return value; + } } if (inpAdd <= accumulatorShifted) { @@ -1216,16 +1180,16 @@ void TrapSimulator::filterPedestal() // It has only an effect if previous samples have been fed to // find the pedestal. Currently, the simulation assumes that // the input has been stable for a sufficiently long time. - // LOG(info) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) { for (int iAdc = 0; iAdc < NADCMCM; iAdc++) { int oldadc = mADCF[iAdc * mNTimeBin + iTimeBin]; mADCF[iAdc * mNTimeBin + iTimeBin] = filterPedestalNextSample(iAdc, iTimeBin, mADCR[iAdc * mNTimeBin + iTimeBin]); - // LOG(info) << "mADCF : time : " << iTimeBin << " adc : " << iAdc << " change : " << oldadc << " -> " << mADCF[iAdc * mNTimeBin + iTimeBin]; + // LOG(debug) << "mADCF : time : " << iTimeBin << " adc : " << iAdc << " change : " << oldadc << " -> " << mADCF[iAdc * mNTimeBin + iTimeBin]; } } - // LOG(info) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; + // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ; } void TrapSimulator::filterGainInit() @@ -1247,7 +1211,7 @@ unsigned short TrapSimulator::filterGainNextSample(int adc, unsigned short value // BEGIN_LATEX O_{i}(t) = #gamma_{i} * I_{i}(t) + a_{i} END_LATEX // The output depends on the internal registers and, thus, the // history of the filter. - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value; unsigned short mgby = mTrapConfig->getTrapReg(TrapConfig::kFGBY, mDetector, mRobPos, mMcmPos); // bypass, active low unsigned short mgf = mTrapConfig->getTrapReg(TrapConfig::TrapReg_t(TrapConfig::kFGF0 + adc), mDetector, mRobPos, mMcmPos); // 0x700 + (0 & 0x1ff); @@ -1262,23 +1226,23 @@ unsigned short TrapSimulator::filterGainNextSample(int adc, unsigned short value unsigned int mgfExtended = 0x700 + mgf; // The corr factor which is finally applied has to be extended by 0x700 (hex) or 0.875 (dec) // because fgf=0 correspons to 0.875 and fgf=511 correspons to 1.125 - 2^(-11) // (see TRAP User Manual for details) - //if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value << " Trapconfig values :" << mgby <<":"<<mgf<<":"<<mga<<":"<<mgta<<":"<<mgtb << ":"<< mgfExtended; + //if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value << " Trapconfig values :" << mgby <<":"<<mgf<<":"<<mga<<":"<<mgta<<":"<<mgtb << ":"<< mgfExtended; unsigned int corr; // corrected value - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) << "after declaring corr adc = " << adc << " value = " << value; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "after declaring corr adc = " << adc << " value = " << value; value &= 0xFFF; corr = (value * mgfExtended) >> 11; corr = corr > 0xfff ? 0xfff : corr; - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr; corr = addUintClipping(corr, mga, 12); - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr; // Update threshold counters // not really useful as they are cleared with every new event if (!((mInternalFilterRegisters[adc].mGainCounterA == 0x3FFFFFF) || (mInternalFilterRegisters[adc].mGainCounterB == 0x3FFFFFF))) // stop when full { - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgtb : " << mgtb; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgtb : " << mgtb; if (corr >= mgtb) { mInternalFilterRegisters[adc].mGainCounterB++; } else if (corr >= mgta) { @@ -1286,7 +1250,7 @@ unsigned short TrapSimulator::filterGainNextSample(int adc, unsigned short value } } - // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(info) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgby : " << mgby; + // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgby : " << mgby; // if (mgby == 1) // return corr; // else @@ -1501,7 +1465,7 @@ void TrapSimulator::addHitToFitreg(int adc, unsigned short timebin, unsigned sho // the tracklet calculation. // In addition to the fit sums in the fit register // - + LOG(debug) << __func__ << " adc : " << adc << " timebin: " << timebin << " qtot: " << qtot << " ypos:" << ypos; if (adc > 24) { LOG(error) << " adc channel into addHitToFitReg is out of bounds for mFitReg : " << adc; } @@ -1528,30 +1492,25 @@ void TrapSimulator::addHitToFitreg(int adc, unsigned short timebin, unsigned sho mFitReg[adc].mSumY += ypos; mFitReg[adc].mSumY2 += ypos * ypos; mFitReg[adc].mSumXY += timebin * ypos; - // LOG(debug) << "fitreg[" << adc << "] in timebin " << timebin << ": X=" << mFitReg[adc].mSumX - // << ", X2=" << mFitReg[adc].mSumX2 << ", N=" << mFitReg[adc].mNhits << ", Y=" - // << mFitReg[adc].mSumY << ", Y2=" << mFitReg[adc].mSumY2 << ", XY=" << mFitReg[adc].mSumXY - // << ", Q0=" << mFitReg[adc].mQ0 << ", Q1=" << mFitReg[adc].mQ1; + LOG(debug) << "fitreg[" << adc << "] in timebin " << timebin << ": X=" << mFitReg[adc].mSumX + << ", X2=" << mFitReg[adc].mSumX2 << ", N=" << mFitReg[adc].mNhits << ", Y=" + << mFitReg[adc].mSumY << ", Y2=" << mFitReg[adc].mSumY2 << ", XY=" << mFitReg[adc].mSumXY + << ", Q0=" << mFitReg[adc].mQ0 << ", Q1=" << mFitReg[adc].mQ1; } // register hits (MC info) - // + // in contrast to AliRoot, labels are connected to the digits instead to the individual hits (at least for the tracklet label calculation only the digit labels are taken into account...) if (mNHits < mgkNHitsMC) { mHits[mNHits].mChannel = adc; mHits[mNHits].mQtot = qtot; mHits[mNHits].mYpos = ypos; mHits[mNHits].mTimebin = timebin; - // LOG(info) << "in addhit to fit reg labels coming in are of " << labels.size() << " and labels assigned from [mNHits = "<<mNHits<<"] a size of " << mHits[mNHits].mLabels.size(); - // mHits[mNHits].mLabels = labels; - // LOG(info) << "in addhit to fit reg labels coming in are of " << labels.size() << " and labels assigned from [mNHits = "<<mNHits<<"] a size of " << mHits[mNHits].mLabels.size(); - //TODO link to the labels. mNHits++; - //.emplace_back(adc, timebin, qtot, ypos); // TODO add label indexes into the labels container for all those labels pertaining to this hit. } else { LOG(warn) << "no space left to store the MC information for the hit >100 mNHits : " << mNHits; //print( PRINTRAW| PRINTFILTERED); } - // LOG(info) << "added hit of : "<< adc<<":"<< qtot<<":"<< ypos<<":"<< timebin; // TODO add label indexes into the labels container for all those labels pertaining to this hit. + // LOG(debug) << "added hit of : "<< adc<<":"<< qtot<<":"<< ypos<<":"<< timebin; // TODO add label indexes into the labels container for all those labels pertaining to this hit. } void TrapSimulator::calcFitreg() @@ -1571,7 +1530,6 @@ void TrapSimulator::calcFitreg() std::array<unsigned short, 20> qTotal{}; //[19 + 1]; // the last is dummy std::array<unsigned short, 6> marked{}, qMarked{}; unsigned short worse1, worse2; - int debugstop = 1; if (mgStoreClusters) { timebin1 = 0; @@ -1601,10 +1559,10 @@ void TrapSimulator::calcFitreg() fitreg.ClearReg(); } - // mFitReg.clear(); for (int i = 0; i < mNHits; i++) { - mHits[i].ClearHits(); // do it this way as we dont want to 100 members if we only used 3 .... + mHits[i].ClearHits(); // do it this way as we dont want to zero 150 members if we only used 3 .... } + mNHits = 0; for (timebin = timebin1; timebin < timebin2; timebin++) { // first find the hit candidates and store the total cluster charge in qTotal array @@ -1631,15 +1589,15 @@ void TrapSimulator::calcFitreg() // The accumulated charge is with the pedestal!!! qtotTemp = adcLeft + adcCentral + adcRight; - /* if ((qtotTemp > 130)) { - LOG(info) << "testtree " - << "qtot=" << qtotTemp - << " qleft=" << adcLeft - << " qcent=" << adcCentral - << " qright=" << adcRight - << " for " << mDetector <<":"<<mRobPos<<":"<<mMcmPos << ":adcleft:"<<adcch<<":t"<<timebin; - } - */ + if ((qtotTemp > 130)) { + LOG(debug) << "qtotTemp>130 " + << "qtot=" << qtotTemp + << " qleft=" << adcLeft + << " qcent=" << adcCentral + << " qright=" << adcRight + << " for " << mDetector << ":" << mRobPos << ":" << mMcmPos << ":adcleft:" << adcch << ":t" << timebin; + } + if ((hitQual) && (qtotTemp >= mTrapConfig->getTrapReg(TrapConfig::kTPHT, mDetector, mRobPos, mMcmPos)) && (adcLeft <= adcCentral) && @@ -1652,7 +1610,7 @@ void TrapSimulator::calcFitreg() qTotal[adcch] = 0; //jkl } // if (qTotal[adcch] != 0) - // LOG(info) << "ch " << setw(2) << adcch << " qTotal " << qTotal[adcch]; + // LOG(debug) << "ch " << setw(2) << adcch << " qTotal " << qTotal[adcch]; } fromLeft = -1; @@ -1661,7 +1619,6 @@ void TrapSimulator::calcFitreg() marked[4] = 19; // invalid channel marked[5] = 19; // invalid channel qTotal[19] = 0; - int loopcount = 0; while ((adcch < 16) && (found < 3)) { if (qTotal[adcch] > 0) { fromLeft = adcch; @@ -1718,12 +1675,13 @@ void TrapSimulator::calcFitreg() // Now mask the two channels with the smallest charge if (worse1 < 19) { qTotal[worse1] = 0; - //LOG(debug3) << "Kill ch " << worse1; + //LOG(debug) << "Kill ch " << worse1; } if (worse2 < 19) { qTotal[worse2] = 0; - // LOG(debug3) << "Kill ch " << worse2; + // LOG(debug) << "Kill ch " << worse2; } + // OS: do we need to kill 3 channels instead of 2 if we write out at max 3 tracklets? } for (adcch = 0; adcch < 19; adcch++) { @@ -1736,9 +1694,9 @@ void TrapSimulator::calcFitreg() // subtract the pedestal TPFP, clipping instead of wrapping int regTPFP = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos); //TODO put this together with the others as members of trapsim, which is initiliased by det,rob,mcm. - // LOG(info) << "Hit found, time=" << timebin << ", adcch=" << adcch << "/" << adcch + 1 << "/" - // << adcch + 2 << ", adc values=" << adcLeft << "/" << adcCentral << "/" - // << adcRight << ", regTPFP=" << regTPFP << ", TPHT=" << mTrapConfig->getTrapReg(TrapConfig::kTPHT, mDetector, mRobPos, mMcmPos); + LOG(debug) << "Hit found, time=" << timebin << ", adcch=" << adcch << "/" << adcch + 1 << "/" + << adcch + 2 << ", adc values=" << adcLeft << "/" << adcCentral << "/" + << adcRight << ", regTPFP=" << regTPFP << ", TPHT=" << mTrapConfig->getTrapReg(TrapConfig::kTPHT, mDetector, mRobPos, mMcmPos); if (adcLeft < regTPFP) { adcLeft = 0; } else { @@ -1764,9 +1722,13 @@ void TrapSimulator::calcFitreg() if (ypos < 0) { ypos = -ypos; } + //ypos element of [0:128] // make the correction using the position LUT + LOG(debug) << "ypos raw is " << ypos << " adcrigh-adcleft/adccentral " << adcRight << "-" << adcLeft << "/" << adcCentral << "==" << (adcRight - adcLeft) / adcCentral << " 128 * numerator : " << 128 * (adcRight - adcLeft) / adcCentral; + LOG(debug) << "ypos before lut correction : " << ypos; ypos = ypos + mTrapConfig->getTrapReg((TrapConfig::TrapReg_t)(TrapConfig::kTPL00 + (ypos & 0x7F)), mDetector, mRobPos, mMcmPos); + LOG(debug) << "ypos after lut correction : " << ypos; if (adcLeft > adcRight) { ypos = -ypos; } @@ -1774,32 +1736,33 @@ void TrapSimulator::calcFitreg() */ // add the hit to the fitregister // int a=qTotal[adcch] >> mgkAddDigits; - // LOG(info) << "calling addHitToFitreg with :" << adcch << " :: " << timebin << " :: " << hex << qTotal[adcch] << dec << " :: shifted bits :" << 2 << " :: " << ypos; + // LOG(debug) << "calling addHitToFitreg with :" << adcch << " :: " << timebin << " :: " << hex << qTotal[adcch] << dec << " :: shifted bits :" << 2 << " :: " << ypos; // addHitToFitreg(adcch, timebin, qTotal[adcch] >> 2, ypos); - LOG(debug) << __func__ << "ADDING HIT FOR in adclabels : " << mADCLabels[adcch].size() << " with adcch of " << adcch << " qtot : " << qTotal[adcch] << " timebin :" << timebin; - addHitToFitreg(adcch, timebin, qTotal[adcch] >> mgkAddDigits, ypos); //, mADCLabels[adcch]); - // LOG(debug) << __FILE__ << ":" << __LINE__ << " :: added hit to fit re "; + LOG(debug) << __func__ << "ADDING HIT with adcch of " << adcch << " qtot : " << qTotal[adcch] << " timebin :" << timebin << " and ypos:" << ypos; + addHitToFitreg(adcch, timebin, qTotal[adcch] >> mgkAddDigits, ypos); } } } - /* - for (int iAdc = 0; iAdc < NADCMCM; iAdc++) { - if (mFitReg[iAdc].mNhits != 0) { - LOG(debug) << "fitreg[" << iAdc << "]: nHits = " << mFitReg[iAdc].mNhits << "]: sumX = " << mFitReg[iAdc].mSumX << ", sumY = " << mFitReg[iAdc].mSumY << ", sumX2 = " << mFitReg[iAdc].mSumX2 << ", sumY2 = " << mFitReg[iAdc].mSumY2 << ", sumXY = " << mFitReg[iAdc].mSumXY; - } - }*/ + + LOG(debug) << "***** Fit Registers begin"; + for (int iAdc = 0; iAdc < NADCMCM; iAdc++) { + if (mFitReg[iAdc].mNhits != 0) { + LOG(debug) << "fitreg[" << iAdc << "]: nHits = " << mFitReg[iAdc].mNhits << "]: sumX = " << mFitReg[iAdc].mSumX << ", sumY = " << mFitReg[iAdc].mSumY << ", sumX2 = " << mFitReg[iAdc].mSumX2 << ", sumY2 = " << mFitReg[iAdc].mSumY2 << ", sumXY = " << mFitReg[iAdc].mSumXY; + } + } + LOG(debug) << "***** Fit Registers end"; //print(PRINTRAW); LOG(debug) << "LEAVING : " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " :: " << getDetector() << ":" << getRobPos() << ":" << getMcmPos() << " and mNHits : " << mNHits; } void TrapSimulator::trackletSelection() { - // Select up to 4 tracklet candidates from the fit registers + // Select up to 3 tracklet candidates from the fit registers // and assign them to the CPUs. - // LOG(info) << "ENTERING : " << __FILE__ << ":" << __func__ << ":" << __LINE__<<" :: "<< getDetector()<<":"<< getRobPos()<<":"<< getMcmPos(); + LOG(debug) << "ENTERING : " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " :: " << getDetector() << ":" << getRobPos() << ":" << getMcmPos(); unsigned short adcIdx, i, j, ntracks, tmp; - std::array<unsigned short, 18> trackletCandch{}; // store the adcch[0] and number of hits[1] for all tracklet candidates - std::array<unsigned short, 18> trackletCandhits{}; // store the adcch[0] and number of hits[1] for all tracklet candidates + std::array<unsigned short, 18> trackletCandch{}; // store the adcch for all tracklet candidates + std::array<unsigned short, 18> trackletCandhits{}; // store the number of hits for all tracklet candidates ntracks = 0; for (adcIdx = 0; adcIdx < 18; adcIdx++) { // ADCs @@ -1807,15 +1770,15 @@ void TrapSimulator::trackletSelection() (mFitReg[adcIdx].mNhits + mFitReg[adcIdx + 1].mNhits >= mTrapConfig->getTrapReg(TrapConfig::kTPCT, mDetector, mRobPos, mMcmPos))) { trackletCandch[ntracks] = adcIdx; trackletCandhits[ntracks] = mFitReg[adcIdx].mNhits + mFitReg[adcIdx + 1].mNhits; - // LOG(info) << ntracks << " " << trackletCandch[ntracks] << " " << trackletCandhits[ntracks]; + // LOG(debug) << ntracks << " " << trackletCandch[ntracks] << " " << trackletCandhits[ntracks]; ntracks++; }; } - // LOG(info) << "Number of track candidates:"<< ntracks; - // for (i = 0; i < ntracks; i++) - // LOG(info) << "TRACKS: " << i << " " << trackletCandch[i] << " " << trackletCandhits[i]; - - if (ntracks > 4) { + LOG(debug) << "Number of track candidates:" << ntracks; + for (i = 0; i < ntracks; i++) { + LOG(debug) << "TRACKS: " << i << " " << trackletCandch[i] << " " << trackletCandhits[i]; + } + if (ntracks > 3) { // primitive sorting according to the number of hits for (j = 0; j < (ntracks - 1); j++) { for (i = j + 1; i < ntracks; i++) { @@ -1831,7 +1794,7 @@ void TrapSimulator::trackletSelection() } } } - ntracks = 4; // cut the rest, 4 is the max + ntracks = 3; // cut the rest, 3 is the max } // else is not necessary to sort @@ -1852,12 +1815,12 @@ void TrapSimulator::trackletSelection() for (i = 0; i < ntracks; i++) { // CPUs with tracklets. mFitPtr[i] = trackletCandch[i]; // pointer to the left channel with tracklet for CPU[i] } - for (i = ntracks; i < 4; i++) { // CPUs without tracklets - mFitPtr[i] = 31; // pointer to the left channel with tracklet for CPU[i] = 31 (invalid) + for (i = ntracks; i < 4; i++) { // CPUs without tracklets + mFitPtr[i] = 31; // pointer to the left channel with tracklet for CPU[i] = 31 (invalid) } - // LOG(info) << "-------------------------------------------- found " << ntracks << " tracklet candidates"; + LOG(debug) << __func__ << " found " << ntracks << " tracklet candidates"; // for (i = 0; i < 4; i++) - // LOG(info) << "fitPtr[" << i << "]: " << mFitPtr[i]; + // LOG(debug) << "fitPtr[" << i << "]: " << mFitPtr[i]; // reject multiple tracklets if (FeeParam::instance()->getRejectMultipleTracklets()) { @@ -1891,13 +1854,14 @@ void TrapSimulator::trackletSelection() // for (i = 0; i < 4; i++) // LOG(debug) << "fitPtr[" << i << "]: " << mFitPtr[i]; } + LOG(debug) << "LEAVING : " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " :: " << getDetector() << ":" << getRobPos() << ":" << getMcmPos() << " with ntracks:" << ntracks; } void TrapSimulator::fitTracklet() { // Perform the actual tracklet fit based on the fit sums // which have been filled in the fit registers. - // LOG(debug) << "ENTERING : " << __FILE__ << ":" << __func__ << ":" << __LINE__<<" :: "<< getDetector()<<":"<< getRobPos()<<":"<< getMcmPos() << " and Tracklet array size is : " << mTrackletArray.size(); + LOG(debug) << "ENTERING : " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " :: " << getDetector() << ":" << getRobPos() << ":" << getMcmPos() << " and Tracklet array size is : " << mTrackletArray64.size(); // parameters in fitred.asm (fit program) int rndAdd = 0; int decPlaces = 5; // must be larger than 1 or change the following code @@ -1906,36 +1870,39 @@ void TrapSimulator::fitTracklet() // else if (decPlaces == 1) // rndAdd = 1; int ndriftDp = 5; // decimal places for drift time - long shift = ((long)1 << 32); + long shift = 1L << 32; // calculated in fitred.asm - int padrow = ((mRobPos >> 1) << 2) | (mMcmPos >> 2); - int yoffs = (((((mRobPos & 0x1) << 2) + (mMcmPos & 0x3)) * 18) << 8) - - ((18 * 4 * 2 - 18 * 2 - 1) << 7); + uint64_t padrow = ((mRobPos >> 1) << 2) | (mMcmPos >> 2); + //int yoffs = (((((mRobPos & 0x1) << 2) + (mMcmPos & 0x3)) * 18) << 8) - + // ((18 * 4 * 2 - 18 * 2 - 1) << 7); + int yoffs = (9 << 8); // we need to shift to the MCM center (adc channel 10) + // TODO we dont need the stuff calculated in fitred.asm because we are now all relative to the mcm ?? check this statement + LOG(debug) << "padrow:" << padrow << " yoffs:" << yoffs << " and rndAdd:" << rndAdd; // add corrections for mis-alignment if (FeeParam::instance()->getUseMisalignCorr()) { - LOG(debug3) << "using mis-alignment correction"; + LOG(debug) << "using mis-alignment correction"; yoffs += (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrYcorr, mDetector, mRobPos, mMcmPos); } yoffs = yoffs << decPlaces; // holds position of ADC channel 1 - int layer = mDetector % 6; - unsigned int scaleY = (unsigned int)((0.635 + 0.03 * layer) / (256.0 * 160.0e-4) * shift); - unsigned int scaleD = (unsigned int)((0.635 + 0.03 * layer) / (256.0 * 140.0e-4) * shift); + // we need to scale the offset since we want to store it in units of 1/80 pad and the calculation is done in 1/256 pad width granularity + unsigned int scaleY = (unsigned int)(PADGRANULARITYTRKLPOS / 256. * shift); + // the slope is given in units of 1/1000 pads/timebin + unsigned long scaleD = (unsigned long)(PADGRANULARITYTRKLSLOPE / 256. * shift); + LOG(debug) << "scaleY : " << scaleY << " scaleD=" << scaleD << " shift:" << std::hex << shift << std::dec; int deflCorr = (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCorr, mDetector, mRobPos, mMcmPos); int ndrift = (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos); // local variables for calculation - long mult, temp, denom; //??? + long mult, temp, denom; unsigned int q0, q1, q2 = 23, pid; // charges in the two windows and total charge - float rawpid, rawz, rawy, rawslope, rawoffset; - float rawslope4trackletword, rawoffset4trackletword; unsigned short nHits; // number of hits - int slope, offset; // slope and offset of the tracklet + int slope, position; // slope and position of the tracklet int sumX, sumY, sumXY, sumX2; // fit sums from fit registers - int sumY2; // not used in the current TRAP program, now used for error calculation (simulation only) + int sumY2; // not used in the current TRAP program, used for error calculation (simulation only) float fitError, fitSlope, fitOffset; FitReg *fit0, *fit1; // pointers to relevant fit registers @@ -1951,69 +1918,89 @@ void TrapSimulator::fitTracklet() } else { fit0 = &mFitReg[mFitPtr[cpu]]; fit1 = &mFitReg[mFitPtr[cpu] + 1]; // next channel - + // fit0->Print(); + // fit1->Print(); + LOG(debug) << "mult is : " << mult << " and in hex : 0x" << std::hex << mult << std::dec; mult = 1; mult = mult << (32 + decPlaces); mult = -mult; + LOG(debug) << "after mult is : " << mult << " and in hex : 0x" << std::hex << mult << std::dec; // time offset for fit sums const int t0 = FeeParam::instance()->getUseTimeOffset() ? (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrTimeOffset, mDetector, mRobPos, mMcmPos) : 0; - // LOG(info) << "using time offset t0 = " << t0; + LOG(debug) << "using time offset of t0 = " << t0; // Merging nHits = fit0->mNhits + fit1->mNhits; // number of hits sumX = fit0->mSumX + fit1->mSumX; sumX2 = fit0->mSumX2 + fit1->mSumX2; denom = ((long)nHits) * ((long)sumX2) - ((long)sumX) * ((long)sumX); + // set ADC data with array mult = mult / denom; // exactly like in the TRAP program q0 = fit0->mQ0 + fit1->mQ0; q1 = fit0->mQ1 + fit1->mQ1; + q2 = fit0->mQ2 + fit1->mQ2; sumY = fit0->mSumY + fit1->mSumY + 256 * fit1->mNhits; sumXY = fit0->mSumXY + fit1->mSumXY + 256 * fit1->mSumX; sumY2 = fit0->mSumY2 + fit1->mSumY2 + 512 * fit1->mSumY + 256 * 256 * fit1->mNhits; + LOG(debug) << "sumY2 = " << sumY2 << " "; + ; slope = nHits * sumXY - sumX * sumY; + LOG(debug) << "slope = " << slope; //offset = sumX2*sumY - sumX*sumXY - t0 * sumX*sumY + t0 * nHits*sumXY; - offset = sumX2 * sumY - sumX * sumXY; - offset = offset << 5; - offset += t0 * nHits * sumXY - t0 * sumX * sumY; - offset = offset >> 5; + position = sumX2 * sumY - sumX * sumXY; + position = position << 5; + position += t0 * nHits * sumXY - t0 * sumX * sumY; + position = position >> 5; temp = mult * slope; slope = temp >> 32; // take the upper 32 bits slope = -slope; - temp = mult * offset; - offset = temp >> 32; // take the upper 32 bits + temp = mult * position; + position = temp >> 32; // take the upper 32 bits + + position += yoffs; + + LOG(debug) << "slope = " << slope; - offset = offset + yoffs; - // LOG(info) << "slope = " << slope << ", slope * ndrift = " << slope * ndrift << ", deflCorr: " << deflCorr; - slope = ((slope * ndrift) >> ndriftDp) + deflCorr; - offset = offset - (mFitPtr[cpu] << (8 + decPlaces)); + slope = slope + ((deflCorr / ndrift) << ndriftDp); + LOG(debug) << "position = position - (mFitPtr[cpu] << (8 + decPlaces));"; + position = position - (mFitPtr[cpu] << (8 + decPlaces)); + LOG(debug) << "position = " << position << " - " << mFitPtr[cpu] << " << (8+" << decPlaces << ")"; + LOG(debug) << "slope before scale of " << scaleD << " is = " << slope; temp = slope; temp = temp * scaleD; slope = (temp >> 32); - rawslope4trackletword = temp; - temp = offset; + LOG(debug) << "slope after scale and shift is = " << slope; + LOG(debug) << "slope = " << slope; + LOG(debug) << "position before scale and shift = " << position; + temp = position; temp = temp * scaleY; - offset = (temp >> 32); - rawoffset4trackletword = temp; + position = (temp >> 32); + LOG(debug) << "position after scale and shift is = " << position; // rounding, like in the TRAP slope = (slope + rndAdd) >> decPlaces; - offset = (offset + rndAdd) >> decPlaces; + position = (position + rndAdd) >> decPlaces; + LOG(debug) << "position = " << position; + LOG(debug) << "slope = " << slope; - // LOG(info) << "Det: " << setw(3) << mDetector << ", ROB: " << mRobPos << ", MCM: " << setw(2) << mMcmPos << setw(-1) << ": deflection: " << slope << ", min: " << (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos) << " max : " << (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 1 + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos); + LOG(debug) << "Det: " << setw(3) << mDetector << ", ROB: " << mRobPos << ", MCM: " << setw(2) << mMcmPos << setw(-1) << ": deflection: " << slope << ", min: " << (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos) << " max : " << (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 1 + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos); - // LOG(info) << "Fit sums: x = " << sumX << ", X = " << sumX2 << ", y = " << sumY << ", Y = " << sumY2 << ", Z = " << sumXY << ", q0 = " << q0 << ", q1 = " << q1; + LOG(debug) << "Fit sums: x = " << sumX << ", X = " << sumX2 << ", y = " << sumY << ", Y = " << sumY2 << ", Z = " << sumXY << ", q0 = " << q0 << ", q1 = " << q1; fitSlope = (float)(nHits * sumXY - sumX * sumY) / (nHits * sumX2 - sumX * sumX); fitOffset = (float)(sumX2 * sumY - sumX * sumXY) / (nHits * sumX2 - sumX * sumX); + LOG(debug) << "FIT : a:" << fitSlope << " b:" << fitOffset; + LOG(debug) << "FIT for trackletword : a:" << slope << " b:" << position; + float sx = (float)sumX; float sx2 = (float)sumX2; float sy = (float)sumY; @@ -2029,48 +2016,34 @@ void TrapSimulator::fitTracklet() rejected = true; } - // LOG(info) << "slope : " << slope << " getDmemUnsigned " << mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos); + // LOG(debug) << "slope : " << slope << " getDmemUnsigned " << mTrapConfig->getDmemUnsigned(mgkDmemAddrDeflCutStart + 2 * mFitPtr[cpu], mDetector, mRobPos, mMcmPos); if (rejected && getApplyCut()) { mMCMT[cpu] = 0x10001000; //??? FeeParam::getTrackletEndmarker(); } else { - if (slope > 63 || slope < -64) { // wrapping in TRAP! - LOG(info) << "Overflow in slope: " << slope << ", tracklet discarded!"; + if (slope > 127 || slope < -128) { // wrapping in TRAP! + LOG(debug) << "Overflow in slope: " << slope << ", tracklet discarded!"; mMCMT[cpu] = 0x10001000; continue; } - slope = slope & 0x7F; // 7 bit - - if (offset > 0xfff || offset < -0xfff) { - LOG(warning) << "Overflow in offset"; - } - offset = offset & 0x1FFF; // 13 bit - - pid = getPID(q0, q1); - rawpid = pid; + slope = slope & 0xff; // 8 bit - if (pid > 0xff) { - LOG(warn) << "Overflow in PID"; // was warn + if (position > 0x3ff || position < -0x400) { + LOG(warning) << "Overflow in position with position of " << position << " in hex 0x" << std::hex << position; } - pid = pid & 0xFF; // 8 bit, exactly like in the TRAP program + position = position & 0x7ff; // 11 bits // assemble and store the tracklet word - mMCMT[cpu] = (pid << 24) | (padrow << 20) | (slope << 13) | offset; - // pid Z deflection lenght Y - rawz = padrow; - rawoffset = offset; + TrackletMCMData trackletword; + buildTrackletMCMData(trackletword, slope, position, q0, q1, q2); + mMCMT[cpu] = trackletword.word; + // calculate number of hits and MC label - // std::array<int, 3> mcLabel = {-1, -1, -1}; - int nHits0 = 0; - int nHits1 = 0; - - // const int maxLabels = 30; - // std::array<int, 30> label{}; // up to 30 different labels possible - // std::array<int, 30> count{}; - // int nLabels = 0; - std::vector<o2::MCCompLabel> localTrackletLabels; + std::array<int, 3> nHits{}; + mTrackletDigitCount.push_back(0); + //we have 21 adc so can fit into a 32bit bit pattern. uint32_t adchitbp = 0; for (int iHit = 0; iHit < mNHits; iHit++) { @@ -2082,95 +2055,45 @@ void TrapSimulator::fitTracklet() // counting contributing hits if (mHits[iHit].mTimebin >= mTrapConfig->getTrapReg(TrapConfig::kTPQS0, mDetector, mRobPos, mMcmPos) && mHits[iHit].mTimebin < mTrapConfig->getTrapReg(TrapConfig::kTPQE0, mDetector, mRobPos, mMcmPos)) { - nHits0++; + nHits[0]++; } if (mHits[iHit].mTimebin >= mTrapConfig->getTrapReg(TrapConfig::kTPQS1, mDetector, mRobPos, mMcmPos) && mHits[iHit].mTimebin < mTrapConfig->getTrapReg(TrapConfig::kTPQE1, mDetector, mRobPos, mMcmPos)) { - nHits1++; + nHits[1]++; + } + if (mHits[iHit].mTimebin >= 3 && //TODO this needs to come from trapconfig, its not there yet. + mHits[iHit].mTimebin < 5) { + nHits[2]++; } //TODO nHits2 ???? to correspond to Q2 ??? // LOG(debug) << "setting bit pattern for chanel : " << mHits[iHit].mChannel << " of hit : " << iHit << std::hex << " bitp before : " << adchitbp << std::dec; - adchitbp |= (1 << mHits[iHit].mChannel); + adchitbp |= (1U << mHits[iHit].mChannel); LOG(debug) << "after setting bit pattern for chanel : " << mHits[iHit].mChannel << " of hit : " << iHit << std::hex << " bitp after : " << adchitbp << std::dec; - // TODO label calculation only if there is a digitsmanager to get the labels froAm } bool printoutadcs = false; - //TODO these debug statemetns are left in to debug the labels later. - LOG(debug) << "adc bitpatterh is " << std::hex << adchitbp << std::dec; for (int i = 0; i < 21; i++) { - if (adchitbp & (1 << i)) { - LOG(debug) << "adding labels for adc " << i << "adc bitpatterh is " << std::hex << adchitbp << std::dec << " there are : " << mADCLabels[i].size() << " labels"; - - localTrackletLabels.insert(localTrackletLabels.end(), mADCLabels[i].begin(), mADCLabels[i].end()); // append the hit labels to this tracklets temp labels store. - if (mADCLabels[i].size() == 0) { - LOG(debug) << "BECAUSE THERE ARE NO LABELS LETS SEE WHICH ADC's DO HAVE LABELS"; - for (int j = 0; j < 21; j++) { - LOG(debug) << "ADC : " << j << " has " << mADCLabels[j].size() << " labels"; - } - printoutadcs = true; - } + // FIXME it can happen that there is a hit found in a channel where there is no digit provided as input. Is this expected? + if ((adchitbp & (1U << i)) && (mADCDigitIndices[i] >= 0)) { + mTrackletDigitCount.back() += 1; + mTrackletDigitIndices.push_back(mADCDigitIndices[i]); } } //if(printoutadcs) print(PRINTRAW|PRINTFILTERED); //labels come in via adc, now loop over ADC and see which contribute to the hits. - LOG(debug) << "TrapSim Trackletarray size is : " << mTrackletArray.size() << " :: adding a track at " << mMCMT[cpu] << ":" << mDetector * 2 + mRobPos % 2 << ":" << mRobPos << ":" << mMcmPos << " LABELS size: " << localTrackletLabels.size(); - mTrackletArray.emplace_back(mDetector * 2 + mRobPos % 2, mRobPos, mMcmPos, rawpid, rawslope, rawoffset, rawslope4trackletword, rawoffset4trackletword); - uint32_t format = 0; - uint32_t hcid = mDetector * 2 + mRobPos % 2; - uint32_t padrow = ((mRobPos >> 1) << 2) | (mMcmPos >> 2); - uint32_t col = mFeeParam->getPadColFromADC(mRobPos, mMcmPos, 1); - uint32_t position = rawoffset; - //uint32_t s - mTrackletArray64.emplace_back(format, hcid, padrow, col, position, slope, q2, q1, q0); - int newtrackposition = mTrackletArray.size() - 1; - //mTrackletArray[newtrackposition].setLabel(mcLabel); - mTrackletArray[newtrackposition].setNHits(fit0->mNhits + fit1->mNhits); - mTrackletArray[newtrackposition].setNHits0(nHits0); - mTrackletArray[newtrackposition].setNHits1(nHits1); - mTrackletArray[newtrackposition].setQ0(q0); - mTrackletArray[newtrackposition].setQ1(q1); - mTrackletArray[newtrackposition].setSlope(fitSlope); - mTrackletArray[newtrackposition].setOffset(fitOffset); - mTrackletArray[newtrackposition].setError(TMath::Sqrt(TMath::Abs(fitError) / nHits)); - LOG(debug) << "adding elements to mTrackletLabels of size " << mTrackletLabels.getIndexedSize() << "::" << mTrackletLabels.getNElements() << " labels for additional labels vector of :" << localTrackletLabels.size() << " labels"; - mTrackletLabels.addElements(mTrackletLabels.getIndexedSize(), localTrackletLabels); - LOG(debug) << "elements in mTrackletLabels is size " << mTrackletLabels.getIndexedSize() << "::" << mTrackletLabels.getNElements() << " labels for additional labels vector of :" << localTrackletLabels.size() << " labels"; - // store cluster information (if requested) - if (mgStoreClusters) { - std::vector<float> res(getNumberOfTimeBins()); - std::vector<float> qtot(getNumberOfTimeBins()); - for (int iTimebin = 0; iTimebin < getNumberOfTimeBins(); ++iTimebin) { - res[iTimebin] = 0; - qtot[iTimebin] = 0; - } - - for (int iHit = 0; iHit < mNHits; iHit++) { - int timebin = mHits[iHit].mTimebin; - - // check if hit contributes - if (mHits[iHit].mChannel == mFitPtr[cpu]) { - // for (int i=0;i<mNHits;i++) LOG(info) << "mHits.["<<i << "].mTimebin="<< mHits[i].mTimebin; - res[timebin] = mHits[iHit].mYpos - (fitSlope * timebin + fitOffset); - qtot[timebin] = mHits[iHit].mQtot; - } else if (mHits[iHit].mChannel == mFitPtr[cpu] + 1) { - res[timebin] = mHits[iHit].mYpos + 256 - (fitSlope * timebin + fitOffset); - qtot[timebin] = mHits[iHit].mQtot; - } - } - mTrackletArray[newtrackposition].setClusters(res, qtot, getNumberOfTimeBins()); - } - - //TODO dont leave this commented out ! - if (fitError < 0) { - LOG(warn) << "fit slope: " << fitSlope << ", offset: " << fitOffset << ", error: " << TMath::Sqrt(TMath::Abs(fitError) / nHits); - LOG(info) << "Strange fit error: " << fitError << " from Sx: " << sumX << ", Sy: " << sumY << ", Sxy: " << sumXY << ", Sx2: " << sumX2 << ", Sy2: " << sumY2 << ", nHits: " << nHits; + LOG(debug) << "TrapSim Trackletarray size is : " << mTrackletArray64.size() << " :: adding a track at " << mMCMT[cpu] << ":" << mDetector * 2 + mRobPos % 2 << ":" << mRobPos << ":" << mMcmPos; + uint64_t format = 1; + uint64_t hcid = mDetector * 2 + mRobPos % 2; + uint64_t col = mMcmPos % NMCMROBINCOL; + mTrackletArray64.emplace_back(format, hcid, padrow, col, position, slope, q0, q1, q2); + if (mdebugStream) { + mTrackletDetails.emplace_back(position, slope, q0, q1, q2, nHits, fitError); } + LOG(debug) << "LEAVING : " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " :: " << getDetector() << ":" << getRobPos() << ":" << getMcmPos() << " and Tracklet array size is : " << mTrackletArray64.size(); } } } - // LOG(info) << "LEAVING : " << __FILE__ << ":" << __func__ << ":" << __LINE__<<" :: "<< getDetector()<<":"<< getRobPos()<<":"<< getMcmPos() << " and Tracklet array size is : " << mTrackletArray.size(); } void TrapSimulator::tracklet() @@ -2182,22 +2105,16 @@ void TrapSimulator::tracklet() if (!mInitialized) { return; } - mTrackletArray.clear(); - + LOG(debug) << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"; calcFitreg(); if (mNHits == 0) { return; } trackletSelection(); fitTracklet(); -} - -void TrapSimulator::getTracklet64s(std::vector<Tracklet64>& TrackletStore) -{ - // simply returns the found tracklets for the O2 dpl to then do its thing. - // - TrackletStore.insert(std::end(TrackletStore), std::begin(mTrackletArray64), std::end(mTrackletArray64)); - //std::copy(mTrackletArray.begin(),mTrackletArray.end(),std::back_inserter(TrackletStore)); + //print(15); + LOG(debug) << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"; + LOG(debug) << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"; } // ****************************** @@ -2231,6 +2148,7 @@ void TrapSimulator::getTracklet64s(std::vector<Tracklet64>& TrackletStore) // 16) if >=, clip to TableLength-1 // 17) read from the LUT 8 bits // TODO the new program from Venelin will be different. +// // TODO ask someone, we are taking q0,q1,q2 and sending it back, no pid calculation? int TrapSimulator::getPID(int q0, int q1) { @@ -2242,7 +2160,7 @@ int TrapSimulator::getPID(int q0, int q1) unsigned int nBinsQ0 = mTrapConfig->getDmemUnsigned(mgkDmemAddrLUTnbins, mDetector, mRobPos, mMcmPos); // number of bins in q0 / 4 !! unsigned int pidTotalSize = mTrapConfig->getDmemUnsigned(mgkDmemAddrLUTLength, mDetector, mRobPos, mMcmPos); if (nBinsQ0 == 0 || pidTotalSize == 0) { // make sure we don't run into trouble if the value for Q0 is not configured - return 0; // Q1 not configured is ok for 1D LUT + return 0; // Q1 not configured is ok for 1D LUT } unsigned long corrQ0 = mTrapConfig->getDmemUnsigned(mgkDmemAddrLUTcor0, mDetector, mRobPos, mMcmPos); @@ -2255,7 +2173,7 @@ int TrapSimulator::getPID(int q0, int q1) addrQ0 = (((addrQ0 * q0) >> 16) >> 16); // because addrQ0 = (q0 * corrQ0) >> 32; does not work for unknown reasons if (addrQ0 >= nBinsQ0) { // check for overflow - // LOG(debug3) << "Overflow in q0: " << addrQ0 << "/4 is bigger then " << nBinsQ0; + // LOG(debug) << "Overflow in q0: " << addrQ0 << "/4 is bigger then " << nBinsQ0; addrQ0 = nBinsQ0 - 1; } @@ -2264,7 +2182,7 @@ int TrapSimulator::getPID(int q0, int q1) addr = addrQ0 + nBinsQ0 * addr; // because addr = addrQ0 + nBinsQ0* (((corrQ1*q1)>>32); does not work if (addr >= pidTotalSize) { - // LOG(debug3) << "Overflow in q1. Address " << addr << "/4 is bigger then " << pidTotalSize; + // LOG(debug) << "Overflow in q1. Address " << addr << "/4 is bigger then " << pidTotalSize; addr = pidTotalSize - 1; } @@ -2484,7 +2402,7 @@ bool TrapSimulator::readPackedConfig(TrapConfig* cfg, int hc, unsigned int* data data++; idx++; - LOG(debug3) << "read: 0x" << hex << header; + LOG(debug) << "read: 0x" << hex << header; if (header & 0x01) // single data { @@ -2496,22 +2414,22 @@ bool TrapSimulator::readPackedConfig(TrapConfig* cfg, int hc, unsigned int* data if (header & 0x02) // check if > 16 bits { dataHi = *data; - LOG(debug3) << "read: 0x" << hex << dataHi; + LOG(debug) << "read: 0x" << hex << dataHi; data++; idx++; err += ((dataHi ^ (dat | 1)) & 0xFFFF) != 0; dat = (dataHi & 0xFFFF0000) | dat; } - LOG(debug3) << "addr=0x" << hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << dat; + LOG(debug) << "addr=0x" << hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << dat; if (!cfg->poke(caddr, dat, det, rob, mcm)) { - LOG(debug3) << "(single-write): non-existing address 0x" << std::hex << caddr << " containing 0x" << std::hex << header; + LOG(debug) << "(single-write): non-existing address 0x" << std::hex << caddr << " containing 0x" << std::hex << header; } if (idx > size) { - LOG(debug3) << "(single-write): no more data, missing end marker"; + LOG(debug) << "(single-write): no more data, missing end marker"; return -err; } } else { - LOG(debug3) << "(single-write): address 0x" << setw(4) << std::hex << caddr << " => old endmarker?" << std::dec; + LOG(debug) << "(single-write): address 0x" << setw(4) << std::hex << caddr << " => old endmarker?" << std::dec; return err; } } @@ -2541,22 +2459,22 @@ bool TrapSimulator::readPackedConfig(TrapConfig* cfg, int hc, unsigned int* data bitcnt -= bwidth; if (bitcnt < 0) { header = *data; - LOG(debug3) << "read 0x" << setw(8) << std::hex << header << std::dec; + LOG(debug) << "read 0x" << setw(8) << std::hex << header << std::dec; data++; idx++; err += (header & 1); header = header >> 1; bitcnt = 31 - bwidth; } - LOG(debug3) << "addr=0x" << setw(4) << std::hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << setw(8) << std::hex << (header & msk); + LOG(debug) << "addr=0x" << setw(4) << std::hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << setw(8) << std::hex << (header & msk); if (!cfg->poke(caddr, header & msk, det, rob, mcm)) { - LOG(debug3) << "(single-write): non-existing address 0x" << setw(4) << std::hex << caddr << " containing 0x" << setw(8) << std::hex << header << std::dec; + LOG(debug) << "(single-write): non-existing address 0x" << setw(4) << std::hex << caddr << " containing 0x" << setw(8) << std::hex << header << std::dec; } caddr += step; header = header >> bwidth; if (idx >= size) { - LOG(debug3) << "(block-write): no end marker! " << idx << " words read"; + LOG(debug) << "(block-write): no end marker! " << idx << " words read"; return -err; } } @@ -2565,20 +2483,20 @@ bool TrapSimulator::readPackedConfig(TrapConfig* cfg, int hc, unsigned int* data case 31: { while (nwords > 0) { header = *data; - LOG(debug3) << "read 0x" << setw(8) << std::hex << header; + LOG(debug) << "read 0x" << setw(8) << std::hex << header; data++; idx++; nwords--; err += (header & 1); - LOG(debug3) << "addr=0x" << hex << setw(4) << caddr << " (" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << setw(8) << (header >> 1); + LOG(debug) << "addr=0x" << hex << setw(4) << caddr << " (" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << setw(8) << (header >> 1); if (!cfg->poke(caddr, header >> 1, det, rob, mcm)) { - LOG(debug3) << "(single-write): non-existing address 0x" << setw(4) << std::hex << " containing 0x" << setw(8) << std::hex << header << std::dec; + LOG(debug) << "(single-write): non-existing address 0x" << setw(4) << std::hex << " containing 0x" << setw(8) << std::hex << header << std::dec; } caddr += step; if (idx >= size) { - LOG(debug3) << "no end marker! " << idx << " words read"; + LOG(debug) << "no end marker! " << idx << " words read"; return -err; } } diff --git a/Detectors/TRD/simulation/src/trap2raw.cxx b/Detectors/TRD/simulation/src/trap2raw.cxx index bcba5a7c959dd..a56ec743b5a5a 100644 --- a/Detectors/TRD/simulation/src/trap2raw.cxx +++ b/Detectors/TRD/simulation/src/trap2raw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,9 +15,8 @@ // Take the output of the trapsimulator the [2-4]x32 bit words and // // associated headers and links etc. and produce the output of the cru. // // Hence the incredibly original name. // +// Now also digits. // // -// Some parts bare a striking resemblence to (at least when written) // -// FIT/FTO/simulation/src/digit2raw.cxx // /////////////////////////////////////////////////////////////////////////////// #include "fairlogger/Logger.h" @@ -34,7 +34,7 @@ #include "DataFormatsParameters/GRPObject.h" #include <boost/program_options.hpp> -#include <TSystem.h> +#include <filesystem> #include <TFile.h> #include <TStopwatch.h> #include <string> @@ -49,9 +49,9 @@ namespace bpo = boost::program_options; -void trap2raw(const std::string& inpName, const std::string& outDir, int verbosity, - bool filePerLink, uint32_t rdhV = 4, bool noEmptyHBF = false, - int superPageSizeInB = 1024 * 1024); +void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsName, + const std::string& outDir, int digitrate, bool verbose, std::string filePerLink, + uint32_t rdhV = 6, bool noEmptyHBF = false, int tracklethcheader = 0, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) { @@ -66,14 +66,18 @@ int main(int argc, char** argv) auto add_option = opt_general.add_options(); add_option("help,h", "Print this help message"); add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); - add_option("input-file,i", bpo::value<std::string>()->default_value("trdtrapraw.root"), "input Trapsim raw file"); - add_option("file-per-halfcru,l", bpo::value<bool>()->default_value(false)->implicit_value(true), "create output file per half cru, 2 files per cru 15 links each."); + // add_option("input-file,i", bpo::value<std::string>()->default_value("trdtrapraw.root"), "input Trapsim raw file"); + add_option("input-file-digits,d", bpo::value<std::string>()->default_value("trddigits.root"), "input Trapsim digits file"); + add_option("input-file-tracklets,t", bpo::value<std::string>()->default_value("trdtracklets.root"), "input Trapsim tracklets file"); + add_option("fileper,l", bpo::value<std::string>()->default_value("halfcru"), "all : raw file(false), halfcru : cru end point, cru : one file per cru, sm: one file per supermodule"); add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); - uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); - add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); + add_option("tracklethcheader,x", bpo::value<int>()->default_value(0), "include tracklet half chamber header (for run3). 0 never, 1 if there is tracklet data, 2 always"); add_option("no-empty-hbf,e", bpo::value<bool>()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); - // add_option("data-format,d", bpo::value<uint32_t>()->default_value(1)->implicit_value(true), "format of data, default 1, see documentation."); + add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(6), "rdh version in use default"); add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("digitrate", bpo::value<int>()->default_value(1000), "only include digits at 1 per this number"); + add_option("verbose,w", bpo::value<bool>()->default_value(false), "verbose"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -93,23 +97,29 @@ int main(int argc, char** argv) std::cerr << e.what() << ", application will now exit" << std::endl; exit(2); } - // o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); std::cout << "yay it ran" << std::endl; - trap2raw(vm["input-file"].as<std::string>(), vm["output-dir"].as<std::string>(), vm["verbosity"].as<int>(), - vm["file-per-halfcru"].as<bool>(), vm["rdh-version"].as<uint32_t>(), vm["no-empty-hbf"].as<bool>()); + trap2raw(vm["input-file-digits"].as<std::string>(), vm["input-file-tracklets"].as<std::string>(), vm["output-dir"].as<std::string>(), vm["digitrate"].as<int>(), vm["verbosity"].as<int>(), vm["fileper"].as<std::string>(), vm["rdh-version"].as<uint32_t>(), vm["no-empty-hbf"].as<bool>(), vm["tracklethcheader"].as<int>()); return 0; } -void trap2raw(const std::string& inpName, const std::string& outDir, int verbosity, bool filePerLink, uint32_t rdhV, bool noEmptyHBF, int superPageSizeInB) +void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsName, const std::string& outDir, int digitrate, bool verbose, std::string filePer, uint32_t rdhV, bool noEmptyHBF, int trackletHCHeader, int superPageSizeInB) { - TStopwatch swTot; swTot.Start(); - o2::trd::Trap2CRU mc2raw; - //mc2raw.setFilePerLink(filePerLink); TODO come back to this, lets get it working first. - mc2raw.setVerbosity(verbosity); + LOG(info) << "timer started"; + o2::trd::Trap2CRU mc2raw(outDir, inpDigitsName, inpTrackletsName); //,superPageSizeInB); + LOG(info) << "class instantiated"; + mc2raw.setFilePer(filePer); + mc2raw.setVerbosity(verbose); + mc2raw.setTrackletHCHeader(trackletHCHeader); // run3 or run2 + mc2raw.setDigitRate(digitrate); // run3 or run2 auto& wr = mc2raw.getWriter(); std::string inputGRP = o2::base::NameConf::getGRPFileName(); const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); @@ -119,21 +129,17 @@ void trap2raw(const std::string& inpName, const std::string& outDir, int verbosi wr.useRDHVersion(rdhV); wr.setDontFillEmptyHBF(noEmptyHBF); + o2::raw::assertOutputDirectory(outDir); + std::string outDirName(outDir); if (outDirName.back() != '/') { outDirName += '/'; } - // if needed, create output directory - if (gSystem->AccessPathName(outDirName.c_str())) { - if (gSystem->mkdir(outDirName.c_str(), kTRUE)) { - LOG(FATAL) << "could not create output directory " << outDirName; - } else { - LOG(INFO) << "created output directory " << outDirName; - } - } - mc2raw.readTrapData(outDirName, inpName, superPageSizeInB); - wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); + mc2raw.setTrackletHCHeader(trackletHCHeader); + LOG(info) << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;"; + mc2raw.readTrapData(); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); // swTot.Stop(); swTot.Print(); diff --git a/Detectors/TRD/simulation/test/testPileupTool.cxx b/Detectors/TRD/simulation/test/testPileupTool.cxx new file mode 100644 index 0000000000000..2e6e0f439e715 --- /dev/null +++ b/Detectors/TRD/simulation/test/testPileupTool.cxx @@ -0,0 +1,111 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test TRD Pileup Tool +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/SignalArray.h" // for SignalContainer +#include "TRDSimulation/PileupTool.h" + +#include <algorithm> + +namespace o2 +{ +namespace trd +{ + +BOOST_AUTO_TEST_CASE(TRDPileupTool_test) +{ + PileupTool tool; + + auto fill_ones = [](std::array<float, constants::TIMEBINS>& signals) { + for (int tb = 0; tb < constants::TIMEBINS; ++tb) { + signals[tb] = 1; + } + }; + + double triggerTime; + std::vector<SignalArray> signalArrays(3); + std::array<SignalContainer, constants::MAXCHAMBER> chamberSignals; + std::deque<std::array<SignalContainer, constants::MAXCHAMBER>> pileupSignals; + + // set the signals + signalArrays[0].firstTBtime = 0; + signalArrays[1].firstTBtime = 2000; + signalArrays[2].firstTBtime = 4900; + std::fill(signalArrays[0].signals.begin(), signalArrays[0].signals.end(), 1); + std::fill(signalArrays[1].signals.begin(), signalArrays[1].signals.end(), 1); + std::fill(signalArrays[2].signals.begin(), signalArrays[2].signals.end(), 1); + signalArrays[0].labels = {1}; // dummy label; + signalArrays[1].labels = {1}; // dummy label; + signalArrays[2].labels = {1}; // dummy label; + + triggerTime = 0; + // simulate that chamber 0 recieves three signals at t1,...t2,...t3 + // with t1 triggering, and t2 incoming before t1+30tb, and t3 to far in the future + // all with key = 1111 + chamberSignals[0][1111] = signalArrays[0]; // chamber 0, with key 1, first signal at t1 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[1]; // chamber 0, with key 1, second signal at t2 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[2]; // chamber 0, with key 1, third signal at t3 + pileupSignals.push_back(chamberSignals); // pileup + + std::array<float, constants::TIMEBINS> expected1 = { + 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02}; + + auto result1 = tool.addSignals(pileupSignals, triggerTime); + + pileupSignals.clear(); + triggerTime = 2000; + // simulate that chamber 0 recieves three signals at t1,...t2,...t3 + // with t2 triggering, and t1 from the past, and t3 incoming before t2+30tb + // all with key = 1111 + chamberSignals[0][1111] = signalArrays[0]; // chamber 0, with key 1, first signal at t1 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[1]; // chamber 0, with key 1, second signal at t2 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[2]; // chamber 0, with key 1, third signal at t3 + pileupSignals.push_back(chamberSignals); // pileup + + std::array<float, constants::TIMEBINS> expected2 = { + 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 02}; + + auto result2 = tool.addSignals(pileupSignals, triggerTime); + + pileupSignals.clear(); + triggerTime = 4900; + // simulate that chamber 0 recieves three signals at t1,...t2,...t3 + // with t3 triggering, and t1 and t2 from the past + // note that t1 is too old + // all with key = 1111 + chamberSignals[0][1111] = signalArrays[0]; // chamber 0, with key 1, first signal at t1 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[1]; // chamber 0, with key 1, second signal at t2 + pileupSignals.push_back(chamberSignals); // pileup + chamberSignals[0][1111] = signalArrays[2]; // chamber 0, with key 1, third signal at t3 + pileupSignals.push_back(chamberSignals); // pileup + + std::array<float, constants::TIMEBINS> expected3 = { + 02, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01}; + + auto result3 = tool.addSignals(pileupSignals, triggerTime); + + BOOST_TEST(result1[1111].signals == expected1, boost::test_tools::per_element()); + BOOST_TEST(result2[1111].signals == expected2, boost::test_tools::per_element()); + BOOST_TEST(result3[1111].signals == expected3, boost::test_tools::per_element()); +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/CMakeLists.txt b/Detectors/TRD/workflow/CMakeLists.txt index 63f51b35f743b..8a5be503fa771 100644 --- a/Detectors/TRD/workflow/CMakeLists.txt +++ b/Detectors/TRD/workflow/CMakeLists.txt @@ -1,31 +1,29 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -#add_compile_options(-O0 -pg -fPIC) +add_subdirectory(io) o2_add_library(TRDWorkflow TARGETVARNAME targetName SOURCES src/TRDDigitizerSpec.cxx - src/TRDDigitWriterSpec.cxx - src/TRDDigitReaderSpec.cxx - src/TRDTrackletWriterSpec.cxx - src/TRDTrackletReaderSpec.cxx - src/TRDTrapRawWriterSpec.cxx src/TRDTrapSimulatorSpec.cxx + src/TRDTrackletTransformerSpec.cxx + src/TRDEventDisplayFeedSpec.cxx src/TRDGlobalTrackingSpec.cxx - src/TRDTrackWriterSpec.cxx - src/TRDTrackingWorkflow.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::Steer O2::Algorithm O2::DataFormatsTRD O2::TRDSimulation O2::DetectorsBase O2::SimulationDataFormat O2::TRDBase O2::GPUTracking O2::GlobalTrackingWorkflow) - - #o2_target_root_dictionary(TRDWorkflow - # HEADERS include/TRDWorkflow/TRDTrapSimulatorSpec.h) + src/EntropyDecoderSpec.cxx + src/EntropyEncoderSpec.cxx + src/TrackBasedCalibSpec.cxx + src/KrClustererSpec.cxx + include/TRDWorkflow/VdAndExBCalibSpec.h + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::Steer O2::Algorithm O2::DataFormatsTRD O2::TRDSimulation O2::TRDReconstruction O2::DetectorsBase O2::SimulationDataFormat O2::TRDBase O2::TRDCalibration O2::GPUTracking O2::GlobalTrackingWorkflowHelpers O2::GlobalTrackingWorkflowReaders O2::GPUWorkflowHelper O2::ReconstructionDataFormats O2::ITSWorkflow O2::TPCWorkflow O2::TRDWorkflowIO) o2_add_executable(trap-sim COMPONENT_NAME trd @@ -42,6 +40,30 @@ o2_add_executable(global-tracking SOURCES src/trd-tracking-workflow.cxx PUBLIC_LINK_LIBRARIES O2::TRDWorkflow) +o2_add_executable(tracklet-transformer + COMPONENT_NAME trd + SOURCES src/TRDTrackletTransformerWorkflow.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflow) + +o2_add_executable(event-display-feed + COMPONENT_NAME trd + SOURCES src/TRDEventDisplayFeedWorkflow.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflow) + +o2_add_executable(trd-vdrift-exb + COMPONENT_NAME calibration + SOURCES src/trd-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::TRDCalibration O2::TRDWorkflow O2::DetectorsCalibration) + +o2_add_executable(entropy-encoder-workflow + SOURCES src/entropy-encoder-workflow.cxx + COMPONENT_NAME trd + PUBLIC_LINK_LIBRARIES O2::TRDWorkflow) + +o2_add_executable(kr-clusterer + COMPONENT_NAME trd + SOURCES src/trd-kr-clusterer.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflow) if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) diff --git a/Detectors/TRD/workflow/README.md b/Detectors/TRD/workflow/README.md new file mode 100644 index 0000000000000..b70df8ca717c0 --- /dev/null +++ b/Detectors/TRD/workflow/README.md @@ -0,0 +1,45 @@ +<!-- doxy +\page refTRDworkflow TRD workflow +/doxy --> + +# DPL workflows for the TRD + +## TRD reconstruction workflow +The TRD reconstruction workflow requires TRD tracklets, TRD trigger records and as additional input either TPC tracks, ITS-TPC matches, or both. +Take a look at the Input data section to see how to generate the input from a simulation. + +The reconstruction workflow consists of the following DPL processors: + +* `TRDTrackletReader` +* `tpc-track-reader` +* `itstpc-track-reader` +* `trd-globaltracking[TPC_ITS-TPC]` using [o2::gpu::GPUTRDTracker_t<TrackType,PropagatorType>](../../../../tree/dev/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h) +* `trd-trackbased-calib` using [o2::trd::TrackBasedCalib](../../../../tree/dev/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h) +* `trd-track-writer-tpc` +* `trd-track-writer-tpcits` +* `TRDCalibWriter` + +The different track reader and writer are only added to the workflow if the respective tracking source is configured. The workflow is started with the command: +`o2-trd-global-tracking`. Available options are: +* `--disable-mc` disable MC labels +* `--disable-root-input` the input is provided by another DPL device +* `--disable-root-output` the output is not written to file +* `--track-sources ITS-TPC,TPC` a comma-seperated list of sources to use for the tracking. Default is `ALL` which results in the same workflow as `ITS-TPC,TPC` +* `--strict-matching` if enabled, TPC-TRD tracks which have another hypothesis close to the best one are flagged as ambiguous and not written out. The minimum chi2 gap between best and second best hypothesis can be configured with `GPU_rec_trd.chi2SeparationCut` +* `--filter-trigrec` if enabled, the trigger records for which no ITS information is available are ignored. Per default on in the synchronous reconstruction, since there is no matching to TPC-only tracks in that case. +* `--configKeyValues "GPU_rec_trd.nSigmaTerrITSTPC=4;"` only one example for the different options for the TRD tracker. All are listed in [GPUSettingsList.h](../../../../dev/GPU/GPUTracking/Definitions/GPUSettingsList.h). Search for GPUSettingsRecTRD + + +## Input data +Since the TRD reconstruction requires either ITS-TPC or TPC tracks to run there are some additional steps to be taken next to the simulation and digitization of an example data sample: +These commands will generate a small pp data sample with 10 events: +* `o2-sim -n 10 -g pythia8pp --skipModules ZDC` +* `o2-sim-digitizer-workflow -b` this will create both TRD digits and TRD tracklets +* `o2-tpc-reco-workflow -b --input-type digits --output-type clusters,tracks --configKeyValues "GPU_proc.ompThreads=4;" --shm-segment-size 10000000000 --run` +* `o2-its-reco-workflow -b --trackerCA --tracking-mode async --shm-segment-size 10000000000 --run` +* `o2-tpcits-match-workflow -b --tpc-track-reader tpctracks.root --tpc-native-cluster-reader "--infile tpc-native-clusters.root" --shm-segment-size 10000000000 --run` +* `o2-trd-tracklet-transformer -b --filter-trigrec` if the trigger filter is active here, it must also be active for the TRD tracking. Otherwise an error will be thrown +* `o2-trd-global-tracking -b --filter-trigrec` + +Of course one can also concatenate the workflows. For example:`o2-trd-tracklet-transformer -b --disable-root-output | o2-trd-global-tracking -b`. This will create the calibrated tracklets on-the-fly and not create the `trdcalibratedtracklets.root` file. + diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..dc5857560f4d4 --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to TRD digit/tracklets stream + +#ifndef O2_TRD_ENTROPYDECODER_SPEC +#define O2_TRD_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace trd +{ + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..2a49faf23374e --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert TRD data to CTF (EncodedBlocks) + +#ifndef O2_TRD_ENTROPYENCODER_SPEC +#define O2_TRD_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace trd +{ + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h new file mode 100644 index 0000000000000..a45f384377800 --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_KRCLUSTERERSPEC_H +#define O2_TRD_KRCLUSTERERSPEC_H + +/// \file KrClustererSpec.h +/// \brief Steers the TRD Krypton cluster finder +/// \author Ole Schmidt + +// input TRD digits, TRD trigger records +// output Kr clusters + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ +/// create a processor spec +framework::DataProcessorSpec getKrClustererSpec(bool digitTrigRec); + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_KRCLUSTERERSPEC_H diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitReaderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitReaderSpec.h deleted file mode 100644 index 2837bd004e363..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitReaderSpec.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRDTRAPSIMULATORRAWREADERSPEC_H -#define O2_TRDTRAPSIMULATORRAWREADERSPEC_H - -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/DataRefUtils.h" -#include "Framework/Lifetime.h" -#include "Framework/Task.h" -#include "TRDBase/MCLabel.h" -#include "TFile.h" -#include "TTree.h" - -namespace o2 -{ -namespace trd -{ - -class TRDDigitReaderSpec : public o2::framework::Task -{ - public: - TRDDigitReaderSpec(int channels) : mChannels(channels){}; - ~TRDDigitReaderSpec() override = default; - void init(o2::framework::InitContext& ic) override; - void run(o2::framework::ProcessingContext& pc) override; - - private: - bool mFinished = false; - int mState = 0; - bool mUseRun2 = false; - int mChannels; - std::unique_ptr<TFile> mFile = nullptr; - //std::unique_ptr<TTree> DPLTree; - std::string mInputFileName = ""; - std::string mDigitTreeName = "o2sim"; - std::string mDigitBranchName = "TRDDigit"; - std::string mTriggerRecordBranchName = "TriggerRecord"; - std::string mMCLabelsBranchName = "TRDMCLabels"; -}; - -o2::framework::DataProcessorSpec getTRDDigitReaderSpec(int channels); - -} // end namespace trd -} // end namespace o2 - -#endif // O2_TRDTRAPSIMULATORTRACKLETWRITER_H diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitWriterSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitWriterSpec.h deleted file mode 100644 index 4a9bb3738319a..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitWriterSpec.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ -#define TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ - -namespace o2 -{ -namespace framework -{ -struct DataProcessorSpec; -} // end namespace framework - -namespace trd -{ - -o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth = true); - -} // end namespace trd -} // end namespace o2 - -#endif /* TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ */ diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitizerSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitizerSpec.h index 0db95eb36da7f..34107036f44f5 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitizerSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDEventDisplayFeedSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDEventDisplayFeedSpec.h new file mode 100644 index 0000000000000..74a0acdbdd354 --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDEventDisplayFeedSpec.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <gsl/span> + +#include "TRDBase/Geometry.h" +#include "TRDBase/TrackletTransformer.h" + +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" + +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Digit.h" + +#include "ITStracking/json.h" + +using json = nlohmann::json; + +namespace o2 +{ +namespace trd +{ + +class TRDEventDisplayFeedSpec : public o2::framework::Task +{ + public: + TRDEventDisplayFeedSpec(int nEventsMax) : mNeventsMax(nEventsMax){}; + ~TRDEventDisplayFeedSpec() override = default; + void init(o2::framework::InitContext& ic) override; + void run(o2::framework::ProcessingContext& pc) override; + json getTracksJson(gsl::span<const TrackTRD> tracks, gsl::span<const Tracklet64> tracklets, gsl::span<const TrackTriggerRecord> trackTrigRecs, int iEvent); + json getTrackletsJson(gsl::span<const Tracklet64> tracklets, int iEvent); + void writeDigits(gsl::span<const Digit> digits, int iEvent); + + private: + TrackletTransformer mTransformer; + o2::trd::Geometry* mGeo; + + std::map<std::string, std::string> mTrackletMap; + std::bitset<constants::MAXCHAMBER> mUsedDetectors; + gsl::span<const TriggerRecord> mTrigRecs; + + float mBz; + int mNeventsMax; +}; + +o2::framework::DataProcessorSpec getTRDEventDisplayFeedSpec(int nEventsMax); + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h index 12c21c6ab4792..a4f5d39f9147b 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,20 @@ #include "TRDBase/GeometryFlat.h" #include "GPUO2Interface.h" #include "GPUTRDTracker.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/TrackTriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include <memory> + +#include "GPUO2InterfaceRefit.h" +#include "TPCFastTransform.h" +#include "TRDBase/RecoParam.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" namespace o2 { @@ -28,10 +43,16 @@ namespace trd class TRDGlobalTracking : public o2::framework::Task { public: - TRDGlobalTracking(bool useMC) : mUseMC(useMC) {} + TRDGlobalTracking(bool useMC, std::shared_ptr<o2::globaltracking::DataRequest> dataRequest, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict) : mUseMC(useMC), mDataRequest(dataRequest), mTrkMask(src), mTrigRecFilter(trigRecFilterActive), mStrict(strict) {} ~TRDGlobalTracking() override = default; void init(o2::framework::InitContext& ic) final; + void updateTimeDependentParams(); + void fillMCTruthInfo(const TrackTRD& trk, o2::MCCompLabel lblSeed, std::vector<o2::MCCompLabel>& lblContainerTrd, std::vector<o2::MCCompLabel>& lblContainerMatch, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* trkltLabels) const; + void fillTrackTriggerRecord(const std::vector<TrackTRD>& tracks, std::vector<TrackTriggerRecord>& trigRec, const gsl::span<const o2::trd::TriggerRecord>& trackletTrigRec) const; void run(o2::framework::ProcessingContext& pc) final; + bool refitITSTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globaltracking::RecoContainer* recoCont); + bool refitTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globaltracking::RecoContainer* recoCont); + bool refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards); void endOfStream(o2::framework::EndOfStreamContext& ec) final; private: @@ -40,11 +61,30 @@ class TRDGlobalTracking : public o2::framework::Task o2::gpu::GPUChainTracking* mChainTracking{nullptr}; ///< TRD tracker is run in the tracking chain std::unique_ptr<GeometryFlat> mFlatGeo{nullptr}; ///< flat TRD geometry bool mUseMC{false}; ///< MC flag + bool mTrigRecFilter{false}; ///< if true, TRD trigger records without matching ITS IR are filtered out + bool mStrict{false}; ///< preliminary matching in strict mode + float mTPCTBinMUS{.2f}; ///< width of a TPC time bin in us + float mTPCTBinMUSInv{1.f / mTPCTBinMUS}; ///< inverse width of a TPC time bin in 1/us + float mTPCVdrift{2.58f}; ///< TPC drift velocity (for shifting TPC tracks along Z) + std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest; ///< seeding input (TPC-only, ITS-TPC or both) + o2::dataformats::GlobalTrackID::mask_t mTrkMask; ///< seeding track sources (TPC, ITS-TPC) TStopwatch mTimer; + // temporary members -> should go into processor (GPUTRDTracker or additional refit processor?) + std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction + const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices + std::unique_ptr<o2::gpu::TPCFastTransform> mTPCTransform; ///< TPC cluster transformation + RecoParam mRecoParam; ///< parameters required for TRD reconstruction + gsl::span<const Tracklet64> mTrackletsRaw; ///< array of raw tracklets needed for TRD refit + gsl::span<const CalibratedTracklet> mTrackletsCalib; ///< array of calibrated tracklets needed for TRD refit + gsl::span<const o2::tpc::TrackTPC> mTPCTracksArray; ///< input TPC tracks used for refit + gsl::span<const o2::its::TrackITS> mITSTracksArray; ///< input ITS tracks used for refit + gsl::span<const int> mITSTrackClusIdx; ///< input ITS track cluster indices span + std::vector<o2::BaseCluster<float>> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + o2::itsmft::TopologyDictionary mITSDict; ///< cluster patterns dictionary }; /// create a processor spec -framework::DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC); +framework::DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict = false); } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackWriterSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackWriterSpec.h deleted file mode 100644 index 4bacd79c5a014..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackWriterSpec.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRD_TRACK_WRITER_H -#define O2_TRD_TRACK_WRITER_H - -/// @file TRDTrackWriterSpec.h - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace trd -{ - -/// create a processor spec -framework::DataProcessorSpec getTRDTrackWriterSpec(bool useMC); - -} // namespace trd -} // namespace o2 - -#endif diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackingWorkflow.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackingWorkflow.h deleted file mode 100644 index 1bd9e6e33bd81..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackingWorkflow.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRD_TRACKING_WORKFLOW_H -#define O2_TRD_TRACKING_WORKFLOW_H - -/// @file TRDTrackingWorkflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace trd -{ - -framework::WorkflowSpec getTRDTrackingWorkflow(bool disableRootInp, bool disableRootOut); - -} // namespace trd -} // namespace o2 - -#endif diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletReaderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletReaderSpec.h deleted file mode 100644 index cdc839a2f9e4c..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletReaderSpec.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TRDTrackletReaderSpec.h - -#ifndef O2_TRD_TRACKLETREADER -#define O2_TRD_TRACKLETREADER - -#include "TFile.h" -#include "TTree.h" - -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "DataFormatsTRD/Tracklet64.h" -#include "DataFormatsTRD/TriggerRecord.h" -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace trd -{ - -class TRDTrackletReader : public o2::framework::Task -{ - public: - TRDTrackletReader(bool useMC) : mUseMC(useMC) {} - ~TRDTrackletReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - void connectTree(const std::string& filename); - bool mUseMC{false}; - std::unique_ptr<TFile> mFile; - std::unique_ptr<TTree> mTree; - std::string mInFileName{"trdtracklets.root"}; - std::string mInTreeName{"o2sim"}; - std::vector<o2::trd::Tracklet64> mTracklets, *mTrackletsPtr = &mTracklets; - std::vector<o2::trd::TriggerRecord> mTriggerRecords, *mTriggerRecordsPtr = &mTriggerRecords; - std::vector<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; -}; - -/// create a processor spec -/// read TRD tracklets from a root file -framework::DataProcessorSpec getTRDTrackletReaderSpec(bool useMC); - -} // namespace trd -} // namespace o2 - -#endif /* O2_TRD_TRACKLETREADER */ diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletTransformerSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletTransformerSpec.h new file mode 100644 index 0000000000000..efa2ccc2cb12b --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletTransformerSpec.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" + +#include "TRDBase/TrackletTransformer.h" + +namespace o2 +{ +namespace trd +{ + +class TRDTrackletTransformerSpec : public o2::framework::Task +{ + public: + TRDTrackletTransformerSpec(std::shared_ptr<o2::globaltracking::DataRequest> dataRequest, bool trigRecFilterActive) : mDataRequest(dataRequest), mTrigRecFilterActive(trigRecFilterActive){}; + ~TRDTrackletTransformerSpec() override = default; + void init(o2::framework::InitContext& ic) override; + void run(o2::framework::ProcessingContext& pc) override; + + private: + TrackletTransformer mTransformer; + bool mTrigRecFilterActive; ///< if true, transform only TRD tracklets for which ITS data is available + std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest; +}; + +o2::framework::DataProcessorSpec getTRDTrackletTransformerSpec(bool trigRecFilterActive); + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletWriterSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletWriterSpec.h deleted file mode 100644 index 915623afcf0db..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletWriterSpec.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRDTRAPSIMULATORTRACKLETWRITER_H -#define O2_TRDTRAPSIMULATORTRACKLETWRITER_H - -#include "TRDBase/Digit.h" -#include <SimulationDataFormat/MCTruthContainer.h> -#include "TRDBase/MCLabel.h" -#include "TRDBase/Tracklet.h" -#include <fstream> -#include <iostream> - -namespace o2 -{ -namespace framework -{ -struct DataProcessorSpec; -} -} // namespace o2 - -namespace o2 -{ -namespace trd -{ - -o2::framework::DataProcessorSpec getTRDTrackletWriterSpec(); - -} // end namespace trd -} // end namespace o2 - -#endif // O2_TRDTRAPSIMULATORTRACKLETWRITER_H diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapRawWriterSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapRawWriterSpec.h deleted file mode 100644 index 82189f7affe7f..0000000000000 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapRawWriterSpec.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRDTRAPSIMULATORRAWWRITER_H -#define O2_TRDTRAPSIMULATORRAWWRITER_H - -#include <fstream> -#include <iostream> - -// This is the raw data that is output by the trap trap chip. -// mcmheader word followed by 1 or more traprawtracklet words. -// and a halfchamber header at the beginning of a half chamber. -// halfchamber header + mcmheader uniquely identifies the chip producing the data. - -namespace o2 -{ -namespace framework -{ -struct DataProcessorSpec; -} -} // namespace o2 - -namespace o2 -{ -namespace trd -{ - -o2::framework::DataProcessorSpec getTRDTrapRawWriterSpec(); - -} // end namespace trd -} // end namespace o2 - -#endif // O2_TRDTRAPSIMULATORRAWWRITER_H diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h index f4726390e26b0..6d9bb73c9ca36 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,18 +14,14 @@ #include <vector> #include <array> -#include <iostream> +#include <string> #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" -#include "TRDBase/FeeParam.h" #include "TRDSimulation/TrapSimulator.h" -#include "DataFormatsTRD/TriggerRecord.h" -#include "DataFormatsTRD/LinkRecord.h" -#include "DataFormatsTRD/Tracklet64.h" -#include "DataFormatsTRD/RawData.h" #include "TRDSimulation/TrapConfig.h" -#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/Constants.h" class Calibrations; @@ -37,65 +34,29 @@ class TRDDPLTrapSimulatorTask : public o2::framework::Task { public: - TRDDPLTrapSimulatorTask() = default; + TRDDPLTrapSimulatorTask(bool useMC) : mUseMC(useMC) {} void init(o2::framework::InitContext& ic) override; void run(o2::framework::ProcessingContext& pc) override; - protected: - void fixTriggerRecords(std::vector<o2::trd::TriggerRecord>& trigRecord); // should be temporary. - void setTriggerRecord(std::vector<o2::trd::TriggerRecord>& triggerrecord, uint32_t currentrecord, uint64_t recordsize); - void setTrapSimulatorData(int adc, std::vector<o2::trd::Digit>& digits, int digitposition); - // TODO LABELS, o2::dataformats::MCTruthContainer<o2::MCCompLabel>* labels) private: - std::array<TrapSimulator, 8> mTrapSimulator; //the 8 trap simulators for a given padrow. - FeeParam* mFeeParam = nullptr; - TrapConfig* mTrapConfig = nullptr; - std::unique_ptr<Geometry> mGeo; - // std::unique_ptr<TrapConfigHandler> mTrapConfigHandler; - int mNumThreads = 8; - unsigned long mRunNumber = 297595; //run number to anchor simulation to. - bool mDriveFromConfig{false}; // option to disable using the trapconfig to drive the simulation - int mPrintTrackletOptions = 0; // print the trap chips adc vs timebin to the screen, ascii art - int mDrawTrackletOptions = 0; //draw the tracklets 1 per file - int mShowTrackletStats = 25000; //how frequencly to show the trapsimulator stats - bool mPrintOutTrapConfig{false}; - bool mDebugRejectedTracklets{false}; + TrapConfig* mTrapConfig{nullptr}; + unsigned long mRunNumber{297595}; //run number to anchor simulation to. bool mEnableOnlineGainCorrection{false}; + bool mUseMC{false}; // whether or not to use MC labels bool mEnableTrapConfigDump{false}; - bool mFixTriggerRecords{false}; // shift the trigger record due to its being corrupt on coming in. - bool mDumpTriggerRecords{false}; // display the trigger records. - std::vector<Tracklet64> mTracklets; // store of found tracklets + int mNumThreads{-1}; // number of threads used for parallel processing std::string mTrapConfigName; // the name of the config to be used. - std::string mTrapConfigBaseName = "TRD_test/TrapConfig/"; - std::unique_ptr<CalOnlineGainTables> mGainTable; //this will probably not be used in run3. std::string mOnlineGainTableName; std::unique_ptr<Calibrations> mCalib; // store the calibrations connection to CCDB. Used primarily for the gaintables in line above. - std::vector<o2::trd::LinkRecord> mLinkRecords; - //arrays to keep some stats during processing - std::array<unsigned int, 8> mTrapUsedCounter{0}; - std::array<unsigned int, 8> mTrapUsedFrequency{0}; - - //various timers so we can see how long things take - std::chrono::duration<double> mTrapSimAccumulatedTime{0}; ///< full timer - std::chrono::duration<double> mDigitLoopTime{0}; ///< full timer - std::chrono::duration<double> mTrapLoopTime{0}; ///< full timer - std::chrono::duration<double> moldelse{0}; ///< full timer - std::chrono::duration<double> mTrackletTime{0}; ///< full timer - std::chrono::duration<double> mSortingTime{0}; ///< full timer - - uint64_t mTotalRawWordsWritten = 0; // words written for the raw format of 4x32bits, where 4 can be 2 to 4 depending on # of tracklets in the block. - int32_t mOldHalfChamberLinkId = 0; - bool mNewTrackletHCHeaderHasBeenWritten{false}; - TrackletHCHeader mTrackletHCHeader; // the current half chamber header, that will be written if a first tracklet is found for this halfchamber. - TrapConfig* getTrapConfig(); - void loadTrapConfig(); + void initTrapConfig(); void setOnlineGainTables(); + void processTRAPchips(int& nTracklets, std::vector<Tracklet64>& trackletsAccum, std::array<TrapSimulator, constants::NMCMHCMAX>& trapSimulators, std::vector<short>& digitCounts, std::vector<int>& digitIndices); }; -o2::framework::DataProcessorSpec getTRDTrapSimulatorSpec(); +o2::framework::DataProcessorSpec getTRDTrapSimulatorSpec(bool useMC); } // end namespace trd } // end namespace o2 diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TrackBasedCalibSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TrackBasedCalibSpec.h new file mode 100644 index 0000000000000..90d9688f96aaa --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TrackBasedCalibSpec.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_TRACKBASEDCALIBSPEC_H +#define O2_TRD_TRACKBASEDCALIBSPEC_H + +/// \file TrackBasedCalibSpec.h +/// \brief Steers the creation of calibration input based on tracks +/// \author Ole Schmidt + +// input TRD tracks, TRD tracklets, TRD calibrated tracklets +// output AngularResidHistos object + +#include "Framework/DataProcessorSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ +/// create a processor spec +framework::DataProcessorSpec getTRDTrackBasedCalibSpec(); + +} // namespace trd +} // namespace o2 + +#endif // O2_TRD_TRACKBASEDCALIBSPEC_H diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/VdAndExBCalibSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/VdAndExBCalibSpec.h new file mode 100644 index 0000000000000..f55ef5eac79d2 --- /dev/null +++ b/Detectors/TRD/workflow/include/TRDWorkflow/VdAndExBCalibSpec.h @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_VDANDEXBCALIBSPEC_H +#define O2_TRD_VDANDEXBCALIBSPEC_H + +/// \file VdAndExBCalibSpec.h +/// \brief DPL device for steering the TRD vD and ExB time slot based calibration +/// \author Ole Schmidt + +#include "TRDCalibration/CalibratorVdExB.h" +#include "DetectorsCalibration/Utils.h" +#include "DataFormatsTRD/AngularResidHistos.h" +#include "CommonUtils/MemFileHelper.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/WorkflowSpec.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace calibration +{ + +class VdAndExBCalibDevice : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + int minEnt = std::max(100'000, ic.options().get<int>("min-entries")); + int slotL = ic.options().get<int>("tf-per-slot"); + int delay = ic.options().get<int>("max-delay"); + mCalibrator = std::make_unique<o2::trd::CalibratorVdExB>(minEnt); + mCalibrator->setSlotLength(slotL); + mCalibrator->setMaxSlotsDelay(delay); + } + + void run(o2::framework::ProcessingContext& pc) final + { + auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("input").header)->startTime; + auto data = pc.inputs().get<gsl::span<o2::trd::AngularResidHistos>>("input"); + LOG(INFO) << "Processing TF " << tfcounter << " with " << data.size() << " AngularResidHistos objects"; + mCalibrator->process(tfcounter, data); + sendOutput(pc.outputs()); + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOG(INFO) << "Finalizing calibration"; + constexpr uint64_t INFINITE_TF = 0xffffffffffffffff; + mCalibrator->checkSlotsToFinalize(INFINITE_TF); + sendOutput(ec.outputs()); + } + + private: + std::unique_ptr<o2::trd::CalibratorVdExB> mCalibrator; + + //________________________________________________________________ + void sendOutput(DataAllocator& output) + { + // See LHCClockCalibratorSpec.h + // Before this can be implemented the output CCDB objects need to be defined + // and added to CalibratorVdExB + } +}; + +} // namespace calibration + +namespace framework +{ + +DataProcessorSpec getTRDVdAndExBCalibSpec() +{ + using device = o2::calibration::VdAndExBCalibDevice; + using clbUtils = o2::calibration::Utils; + + std::vector<OutputSpec> outputs; + //outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBPayload}); + //outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCLB, clbUtils::gDataDescriptionCLBInfo}); + return DataProcessorSpec{ + "calib-vdexb-calibration", + Inputs{{"input", "TRD", "ANGRESHISTS"}}, + outputs, + AlgorithmSpec{adaptFromTask<device>()}, + Options{ + {"tf-per-slot", VariantType::Int, 5, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::Int, 90'000, {"number of slots in past to consider"}}, // 15 minutes delay, 10ms TF + {"min-entries", VariantType::Int, 500, {"minimum number of entries to fit single time slot"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif // O2_TRD_VDANDEXBCALIBSPEC_H diff --git a/Detectors/TRD/workflow/io/CMakeLists.txt b/Detectors/TRD/workflow/io/CMakeLists.txt new file mode 100644 index 0000000000000..e11d8a2d8f7ea --- /dev/null +++ b/Detectors/TRD/workflow/io/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TRDWorkflowIO + SOURCES src/TRDDigitReaderSpec.cxx + src/TRDTrackletReaderSpec.cxx + src/TRDCalibReaderSpec.cxx + src/TRDDigitWriterSpec.cxx + src/TRDTrackletWriterSpec.cxx + src/TRDTrapRawWriterSpec.cxx + src/TRDCalibratedTrackletWriterSpec.cxx + src/TRDTrackWriterSpec.cxx + src/TRDTrackReaderSpec.cxx + src/TRDCalibWriterSpec.cxx + src/KrClusterWriterSpec.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsTRD O2::SimulationDataFormat O2::DPLUtils O2::GPUDataTypeHeaders O2::DataFormatsTPC) + + +o2_add_executable(track-reader + COMPONENT_NAME trd + SOURCES src/trd-track-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflowIO) +o2_add_executable(digittracklet-writer + COMPONENT_NAME trd + SOURCES src/trd-digittracklet-writer-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflowIO) diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h new file mode 100644 index 0000000000000..a33886639c813 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_KRWRITERSPEC_H +#define O2_TRD_KRWRITERSPEC_H + +namespace o2 +{ +namespace framework +{ +struct DataProcessorSpec; +} +} // namespace o2 + +namespace o2 +{ +namespace trd +{ + +o2::framework::DataProcessorSpec getKrClusterWriterSpec(); + +} // end namespace trd +} // end namespace o2 + +#endif // O2_TRD_KRWRITERSPEC_H diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h new file mode 100644 index 0000000000000..3f1dde950744d --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDCalibReaderSpec.h + +#ifndef O2_TRD_CALIBREADER +#define O2_TRD_CALIBREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTRD/AngularResidHistos.h" + +namespace o2 +{ +namespace trd +{ + +class TRDCalibReader : public o2::framework::Task +{ + public: + TRDCalibReader() = default; + ~TRDCalibReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + private: + void connectTree(); + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mInFileName{"trdangreshistos.root"}; + std::string mInTreeName{"calibdata"}; + std::vector<o2::trd::AngularResidHistos> mAngResids, *mAngResidPtr = &mAngResids; +}; + +/// create a processor spec +/// read TRD calibration data from a root file +framework::DataProcessorSpec getTRDCalibReaderSpec(); + +} // namespace trd +} // namespace o2 + +#endif /* O2_TRD_CALIBREADER */ diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibWriterSpec.h new file mode 100644 index 0000000000000..f9b2f21831032 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRDCALIBWRITERSPEC_H +#define O2_TRDCALIBWRITERSPEC_H + +namespace o2 +{ +namespace framework +{ +struct DataProcessorSpec; +} +} // namespace o2 + +namespace o2 +{ +namespace trd +{ + +o2::framework::DataProcessorSpec getTRDCalibWriterSpec(); + +} // end namespace trd +} // end namespace o2 + +#endif // O2_TRDCALIBWRITERSPEC_H diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibratedTrackletWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibratedTrackletWriterSpec.h new file mode 100644 index 0000000000000..cba56ff3e6263 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibratedTrackletWriterSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRDCALIBRATEDTRACKLETWRITER_H +#define O2_TRDCALIBRATEDTRACKLETWRITER_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace trd +{ + +framework::DataProcessorSpec getTRDCalibratedTrackletWriterSpec(bool useMC); + +} // end namespace trd +} // end namespace o2 + +#endif diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitReaderSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitReaderSpec.h new file mode 100644 index 0000000000000..9cd99eefa8752 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitReaderSpec.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRDTRAPSIMULATORRAWREADERSPEC_H +#define O2_TRDTRAPSIMULATORRAWREADERSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "TFile.h" +#include "TTree.h" + +#include <memory> +#include <string> + +namespace o2 +{ +namespace trd +{ + +class TRDDigitReaderSpec : public o2::framework::Task +{ + public: + TRDDigitReaderSpec(bool useMC) : mUseMC(useMC) {} + ~TRDDigitReaderSpec() override = default; + void init(o2::framework::InitContext& ic) override; + void run(o2::framework::ProcessingContext& pc) override; + + private: + bool mUseMC = false; + std::unique_ptr<TFile> mFile = nullptr; + std::string mDigitTreeName = "o2sim"; + std::string mDigitBranchName = "TRDDigit"; + std::string mTriggerRecordBranchName = "TriggerRecord"; + std::string mMCLabelsBranchName = "TRDMCLabels"; +}; + +o2::framework::DataProcessorSpec getTRDDigitReaderSpec(bool useMC); + +} // end namespace trd +} // end namespace o2 + +#endif // O2_TRDTRAPSIMULATORTRACKLETWRITER_H diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitWriterSpec.h new file mode 100644 index 0000000000000..52ed6f9a2e6fd --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDDigitWriterSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ +#define TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ + +namespace o2 +{ +namespace framework +{ +struct DataProcessorSpec; +} // end namespace framework + +namespace trd +{ + +o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth = true, bool writeTrigRec = true); + +} // end namespace trd +} // end namespace o2 + +#endif /* TRDWORKFLOW_SRC_TRDDIGITWRITERSPEC_H_ */ diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackReaderSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackReaderSpec.h new file mode 100644 index 0000000000000..d4c54273c4b55 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackReaderSpec.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_TRACK_READER_H +#define O2_TRD_TRACK_READER_H + +/// @file TRDTrackReaderSpec.h + +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/TrackTriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +#include "TFile.h" +#include "TTree.h" + +#include <vector> +#include <string> +#include <memory> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +class TRDTrackReader : public Task +{ + public: + enum Mode : int { + ITSTPCTRD, + TPCTRD + }; + + TRDTrackReader(bool useMC, Mode mode, bool subSpecStrict = false) : mUseMC(useMC), mMode(mode), mSubSpecStrict(subSpecStrict) {} + ~TRDTrackReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + bool mUseMC = false; + bool mSubSpecStrict = false; + Mode mMode; + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + std::string mFileName = ""; + std::vector<o2::trd::TrackTRD> mTracks, *mTracksPtr = &mTracks; + std::vector<o2::trd::TrackTriggerRecord> mTrigRec, *mTrigRecPtr = &mTrigRec; + std::vector<o2::MCCompLabel> mLabelsMatch, *mLabelsMatchPtr = &mLabelsMatch; + std::vector<o2::MCCompLabel> mLabelsTrd, *mLabelsTrdPtr = &mLabelsTrd; +}; + +/// read TPC-TRD matched tracks from a root file +framework::DataProcessorSpec getTRDTPCTrackReaderSpec(bool useMC, bool subSpecStrict = false); + +/// read ITS-TPC-TRD matched tracks from a root file +framework::DataProcessorSpec getTRDGlobalTrackReaderSpec(bool useMC); + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackWriterSpec.h new file mode 100644 index 0000000000000..7e8a6b439fdd4 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRD_TRACK_WRITER_H +#define O2_TRD_TRACK_WRITER_H + +/// @file TRDTrackWriterSpec.h + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace trd +{ + +/// writer for matches to ITS-TPC tracks +framework::DataProcessorSpec getTRDGlobalTrackWriterSpec(bool useMC); + +/// writer for matches with TPC-only tracks +framework::DataProcessorSpec getTRDTPCTrackWriterSpec(bool useMC, bool strictMode = false); + +} // namespace trd +} // namespace o2 + +#endif diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletReaderSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletReaderSpec.h new file mode 100644 index 0000000000000..812a56b93f874 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletReaderSpec.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDTrackletReaderSpec.h + +#ifndef O2_TRD_TRACKLETREADER +#define O2_TRD_TRACKLETREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2 +{ +namespace trd +{ + +class TRDTrackletReader : public o2::framework::Task +{ + public: + TRDTrackletReader(bool useMC, bool useTrkltTransf) : mUseMC(useMC), mUseTrackletTransform(useTrkltTransf) {} + ~TRDTrackletReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + private: + void connectTree(); + void connectTreeCTracklet(); + bool mUseMC{false}; + bool mUseTrackletTransform{false}; + std::unique_ptr<TFile> mFileTrklt; + std::unique_ptr<TTree> mTreeTrklt; + std::unique_ptr<TFile> mFileCTrklt; + std::unique_ptr<TTree> mTreeCTrklt; + std::string mInFileNameTrklt{"trdtracklets.root"}; + std::string mInTreeNameTrklt{"o2sim"}; + std::vector<o2::trd::CalibratedTracklet> mTrackletsCal, *mTrackletsCalPtr = &mTrackletsCal; + std::vector<char> mTrigRecMask, *mTrigRecMaskPtr = &mTrigRecMask; + std::vector<o2::trd::Tracklet64> mTracklets, *mTrackletsPtr = &mTracklets; + std::vector<o2::trd::TriggerRecord> mTriggerRecords, *mTriggerRecordsPtr = &mTriggerRecords; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels, *mLabelsPtr = &mLabels; +}; + +/// create a processor spec +/// read TRD tracklets from a root file +framework::DataProcessorSpec getTRDTrackletReaderSpec(bool useMC, bool useCalibratedTracklets); + +} // namespace trd +} // namespace o2 + +#endif /* O2_TRD_TRACKLETREADER */ diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletWriterSpec.h new file mode 100644 index 0000000000000..78e3473503a4a --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrackletWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRDTRAPSIMULATORTRACKLETWRITER_H +#define O2_TRDTRAPSIMULATORTRACKLETWRITER_H + +namespace o2 +{ +namespace framework +{ +struct DataProcessorSpec; +} +} // namespace o2 + +namespace o2 +{ +namespace trd +{ + +o2::framework::DataProcessorSpec getTRDTrackletWriterSpec(bool useMC); + +} // end namespace trd +} // end namespace o2 + +#endif // O2_TRDTRAPSIMULATORTRACKLETWRITER_H diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrapRawWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrapRawWriterSpec.h new file mode 100644 index 0000000000000..7a9363589f585 --- /dev/null +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDTrapRawWriterSpec.h @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TRDTRAPSIMULATORRAWWRITER_H +#define O2_TRDTRAPSIMULATORRAWWRITER_H + +#include <fstream> +#include <iostream> + +// This is the raw data that is output by the trap trap chip. +// mcmheader word followed by 1 or more traprawtracklet words. +// and a halfchamber header at the beginning of a half chamber. +// halfchamber header + mcmheader uniquely identifies the chip producing the data. + +namespace o2 +{ +namespace framework +{ +struct DataProcessorSpec; +} +} // namespace o2 + +namespace o2 +{ +namespace trd +{ + +o2::framework::DataProcessorSpec getTRDTrapRawWriterSpec(); + +} // end namespace trd +} // end namespace o2 + +#endif // O2_TRDTRAPSIMULATORRAWWRITER_H diff --git a/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx b/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx new file mode 100644 index 0000000000000..92fce34ada4a4 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "TRDWorkflowIO/KrClusterWriterSpec.h" +#include "DataFormatsTRD/KrCluster.h" +#include "DataFormatsTRD/KrClusterTriggerRecord.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getKrClusterWriterSpec() +{ + + return framework::MakeRootTreeWriterSpec("TRDKrClWriter", + "trdkrclusters.root", + "krClusters", + BranchDefinition<std::vector<o2::trd::KrCluster>>{InputSpec{"clusters", "TRD", "KRCLUSTER"}, "KrCluster"}, + BranchDefinition<std::vector<o2::trd::KrClusterTriggerRecord>>{InputSpec{"trigRecs", "TRD", "TRGKRCLS"}, "TriggerRecord"})(); +}; + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx b/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx new file mode 100644 index 0000000000000..450f8b40c6df5 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDCalibReaderSpec.cxx + +#include "TRDWorkflowIO/TRDCalibReaderSpec.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "fairlogger/Logger.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +void TRDCalibReader::init(InitContext& ic) +{ + // get the option from the init context + LOG(INFO) << "Init TRD tracklet reader!"; + mInFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("trd-calib-infile")); + mInTreeName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("treename")); + connectTree(); +} + +void TRDCalibReader::connectTree() +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(mInFileName.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mInTreeName.c_str())); + assert(mTree); + mTree->SetBranchAddress("AngularResids", &mAngResidPtr); + LOG(INFO) << "Loaded tree from " << mInFileName << " with " << mTree->GetEntries() << " entries"; +} + +void TRDCalibReader::run(ProcessingContext& pc) +{ + auto currEntry = mTree->GetReadEntry() + 1; + assert(currEntry < mTree->GetEntries()); // this should not happen + mTree->GetEntry(currEntry); + if (mAngResids.size() > 0) { + LOG(INFO) << "Pushing angular residual histograms filled with " << mAngResids.at(0).getNEntries() << " entries at tree entry " << currEntry; + } else { + LOG(WARNING) << "No TRD calibration data available in the tree"; + } + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "ANGRESHISTS", 0, Lifetime::Timeframe}, mAngResids); + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +DataProcessorSpec getTRDCalibReaderSpec() +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTRD, "ANGRESHISTS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "TRDCalibReader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TRDCalibReader>()}, + Options{ + {"trd-calib-infile", VariantType::String, "trdangreshistos.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "calibdata", {"Name of top-level TTree"}}, + }}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDCalibWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDCalibWriterSpec.cxx new file mode 100644 index 0000000000000..054b55ee66622 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDCalibWriterSpec.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "TRDWorkflowIO/TRDCalibWriterSpec.h" +#include "DataFormatsTRD/AngularResidHistos.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getTRDCalibWriterSpec() +{ + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + return MakeRootTreeWriterSpec("TRDCalibWriter", + "trdangreshistos.root", + "calibdata", + BranchDefinition<std::vector<o2::trd::AngularResidHistos>>{InputSpec{"calibdata", "TRD", "ANGRESHISTS"}, "AngularResids"})(); +}; + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDCalibratedTrackletWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDCalibratedTrackletWriterSpec.cxx new file mode 100644 index 0000000000000..341000929e036 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDCalibratedTrackletWriterSpec.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDWorkflowIO/TRDCalibratedTrackletWriterSpec.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include <SimulationDataFormat/MCTruthContainer.h> +#include <SimulationDataFormat/MCCompLabel.h> + +#include "DPLUtils/MakeRootTreeWriterSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getTRDCalibratedTrackletWriterSpec(bool useMC) +{ + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + + return MakeRootTreeWriterSpec("calibrated-tracklet-writer", + "trdcalibratedtracklets.root", + "ctracklets", + BranchDefinition<std::vector<CalibratedTracklet>>{InputSpec{"ctracklets", "TRD", "CTRACKLETS"}, "CTracklets"}, + BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"trklabels", "TRD", "TRKLABELS"}, "TRKLabels", (useMC ? 1 : 0), "TRKLABELS"}, + BranchDefinition<std::vector<char>>{InputSpec{"trigrecmask", "TRD", "TRIGRECMASK"}, "TrigRecMask"})(); +}; + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDDigitReaderSpec.cxx b/Detectors/TRD/workflow/io/src/TRDDigitReaderSpec.cxx new file mode 100644 index 0000000000000..3213f98320acd --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDDigitReaderSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDWorkflowIO/TRDDigitReaderSpec.h" + + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "CommonUtils/StringUtils.h" +#include "fairlogger/Logger.h" + +#include <SimulationDataFormat/MCCompLabel.h> +#include <SimulationDataFormat/ConstMCTruthContainer.h> +#include <SimulationDataFormat/IOMCTruthContainerView.h> + +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/TriggerRecord.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +void TRDDigitReaderSpec::init(InitContext& ic) +{ + + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("digitsfile")); + + mFile = std::make_unique<TFile>(filename.c_str(), "OLD"); + if (!(mFile && !mFile->IsZombie())) { + throw std::runtime_error("Error opening TRD digits file"); + } +} + +void TRDDigitReaderSpec::run(ProcessingContext& pc) +{ + auto DPLTree = ((TTree*)mFile->Get(mDigitTreeName.c_str())); + if (DPLTree) { + std::vector<o2::trd::Digit>* digits = nullptr; + o2::dataformats::IOMCTruthContainerView* ioLabels = nullptr; + std::vector<o2::trd::TriggerRecord>* triggerRecords = nullptr; + + auto getFromBranch = [DPLTree](const char* name, void** ptr) { + auto br = DPLTree->GetBranch(name); + br->SetAddress(ptr); + br->GetEntry(0); + br->ResetAddress(); + }; + getFromBranch(mDigitBranchName.c_str(), (void**)&digits); + getFromBranch(mTriggerRecordBranchName.c_str(), (void**)&triggerRecords); + if (mUseMC) { + getFromBranch(mMCLabelsBranchName.c_str(), (void**)&ioLabels); + // publish labels in shared memory + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TRD", "LABELS", 0, Lifetime::Timeframe}); + ioLabels->copyandflatten(sharedlabels); + LOG(INFO) << "Labels size (in bytes) = " << sharedlabels.size(); + } + + pc.outputs().snapshot(Output{"TRD", "DIGITS", 0, Lifetime::Timeframe}, *digits); + pc.outputs().snapshot(Output{"TRD", "TRGRDIG", 0, Lifetime::Timeframe}, *triggerRecords); + LOG(INFO) << "Digits size=" << digits->size() << " triggerrecords size=" << triggerRecords->size(); + } else { + LOG(ERROR) << "Error opening TTree"; + } + + mFile->Close(); + + // send endOfData control event and mark the reader as ready to finish + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); +} + +DataProcessorSpec getTRDDigitReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("TRD", "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back("TRD", "TRGRDIG", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("TRD", "LABELS", 0, Lifetime::Timeframe); + } + return DataProcessorSpec{"TRDDIGITREADER", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TRDDigitReaderSpec>(useMC)}, + Options{ + {"digitsfile", VariantType::String, "trddigits.root", {"Input data file containing run3 digitizer going into Trap Simulator"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +}; + +} //end namespace trd +} //end namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDDigitWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDDigitWriterSpec.cxx similarity index 84% rename from Detectors/TRD/workflow/src/TRDDigitWriterSpec.cxx rename to Detectors/TRD/workflow/io/src/TRDDigitWriterSpec.cxx index b71d52b5b916e..62b71333585bf 100644 --- a/Detectors/TRD/workflow/src/TRDDigitWriterSpec.cxx +++ b/Detectors/TRD/workflow/io/src/TRDDigitWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,12 +15,11 @@ #include "Framework/DataProcessorSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" -#include "TRDBase/Digit.h" +#include "DataFormatsTRD/Digit.h" #include "DataFormatsTRD/TriggerRecord.h" #include <SimulationDataFormat/ConstMCTruthContainer.h> #include <SimulationDataFormat/IOMCTruthContainerView.h> -#include "TRDBase/MCLabel.h" -#include "TRDWorkflow/TRDDigitWriterSpec.h" +#include "TRDWorkflowIO/TRDDigitWriterSpec.h" namespace o2 { @@ -29,7 +29,7 @@ namespace trd template <typename T> using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; -o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth) +o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth, bool writeTrigRec) { using InputSpec = framework::InputSpec; using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; @@ -57,7 +57,8 @@ o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth) // make the actual output object by adopting/casting the buffer // into a split format o2::dataformats::IOMCTruthContainerView outputcontainer(labeldata); - auto br = framework::RootTreeWriter::remapBranch(branch, &outputcontainer); + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); br->Fill(); br->ResetAddress(); }; @@ -71,11 +72,10 @@ o2::framework::DataProcessorSpec getTRDDigitWriterSpec(bool mctruth) return MakeRootTreeWriterSpec("TRDDigitWriter", "trddigits.root", "o2sim", - 1, // setting a custom callback for closing the writer MakeRootTreeWriterSpec::CustomClose(finishWriting), BranchDefinition<std::vector<o2::trd::Digit>>{InputSpec{"input", "TRD", "DIGITS"}, "TRDDigit"}, - BranchDefinition<std::vector<o2::trd::TriggerRecord>>{InputSpec{"trinput", "TRD", "TRGRDIG"}, "TriggerRecord"}, + BranchDefinition<std::vector<o2::trd::TriggerRecord>>{InputSpec{"trinput", "TRD", "TRGRDIG"}, "TriggerRecord", (writeTrigRec ? 1 : 0)}, std::move(labelsdef))(); } diff --git a/Detectors/TRD/workflow/io/src/TRDTrackReaderSpec.cxx b/Detectors/TRD/workflow/io/src/TRDTrackReaderSpec.cxx new file mode 100644 index 0000000000000..2e7ceee71bad3 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDTrackReaderSpec.cxx @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDTrackReaderSpec.cxx + +#include "TRDWorkflowIO/TRDTrackReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/SerializationMethods.h" +#include "CommonUtils/StringUtils.h" +#include "ReconstructionDataFormats/MatchingType.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace trd +{ + +void TRDTrackReader::init(InitContext& ic) +{ + + mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("track-infile")); + + connectTree(mFileName); +} + +void TRDTrackReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "Pushing " << mTracks.size() << " tracks and " << mTrigRec.size() << " trigger records at entry " << ent; + if (mUseMC) { + if (mLabelsTrd.size() != mLabelsMatch.size()) { + LOG(ERROR) << "The number of labels for matches and for TRD tracks is different. " << mLabelsTrd.size() << " TRD labels vs. " << mLabelsMatch.size() << " match labels"; + } + LOG(INFO) << "Pushing " << mLabelsTrd.size() << " MC labels at entry " << ent; + } + + if (mMode == Mode::TPCTRD) { + uint32_t ss = o2::globaltracking::getSubSpec(mSubSpecStrict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_TPC", ss, Lifetime::Timeframe}, mTracks); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_TPC", ss, Lifetime::Timeframe}, mTrigRec); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC", ss, Lifetime::Timeframe}, mLabelsMatch); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss, Lifetime::Timeframe}, mLabelsTrd); + } + } else if (mMode == Mode::ITSTPCTRD) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe}, mTracks); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe}, mTrigRec); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0, Lifetime::Timeframe}, mLabelsMatch); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe}, mLabelsTrd); + } + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void TRDTrackReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get("tracksTRD")); + assert(mTree); + mTree->SetBranchAddress("tracks", &mTracksPtr); + mTree->SetBranchAddress("trgrec", &mTrigRecPtr); + if (mUseMC) { + mTree->SetBranchAddress("labels", &mLabelsMatchPtr); + mTree->SetBranchAddress("labelsTRD", &mLabelsTrdPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getTRDTPCTrackReaderSpec(bool useMC, bool subSpecStrict) +{ + std::vector<OutputSpec> outputs; + uint32_t sspec = o2::globaltracking::getSubSpec(subSpecStrict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_TPC", sspec, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_TPC", sspec, Lifetime::Timeframe); + + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC", sspec, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC_TRD", sspec, Lifetime::Timeframe); + } + return DataProcessorSpec{ + "tpctrd-track-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TRDTrackReader>(useMC, TRDTrackReader::Mode::TPCTRD, subSpecStrict)}, + Options{ + {"track-infile", VariantType::String, "trdmatches_tpc.root", {"Name of the input file for TPC-TRD matches"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +DataProcessorSpec getTRDGlobalTrackReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe); + + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "itstpctrd-track-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TRDTrackReader>(useMC, TRDTrackReader::Mode::ITSTPCTRD)}, + Options{ + {"track-infile", VariantType::String, "trdmatches_itstpc.root", {"Name of the input file for ITS-TPC-TRD matches"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDTrackWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDTrackWriterSpec.cxx new file mode 100644 index 0000000000000..5a034267a60ac --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDTrackWriterSpec.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDTrackWriterSpec.cxx + +#include <vector> +#include "DataFormatsTRD/TrackTRD.h" +#include "DataFormatsTRD/TrackTriggerRecord.h" +#include "ReconstructionDataFormats/MatchingType.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "TRDWorkflowIO/TRDTrackWriterSpec.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; +using namespace o2::gpu; + +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace trd +{ +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; + +DataProcessorSpec getTRDGlobalTrackWriterSpec(bool useMC) +{ + using LabelsType = std::vector<o2::MCCompLabel>; + + // A spectator to store the size of the data array for the logger below + auto tracksSize = std::make_shared<int>(); + auto tracksLogger = [tracksSize](std::vector<o2::trd::TrackTRD> const& tracks) { + *tracksSize = tracks.size(); + }; + + return MakeRootTreeWriterSpec("trd-track-writer-tpcits", + "trdmatches_itstpc.root", + "tracksTRD", + BranchDefinition<std::vector<o2::trd::TrackTRD>>{InputSpec{"tracks", o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0}, + "tracks", + "tracks-branch-name", + 1, + tracksLogger}, + BranchDefinition<std::vector<o2::trd::TrackTriggerRecord>>{InputSpec{"trackTrig", o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0}, + "trgrec", + "trgrec-branch-name", + 1}, + BranchDefinition<LabelsType>{InputSpec{"trdlabels", o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0}, + "labelsTRD", + (useMC ? 1 : 0), // one branch if mc labels enabled + "trdlabels-branch-name"}, + BranchDefinition<LabelsType>{InputSpec{"matchtpclabels", o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0}, + "labels", + (useMC ? 1 : 0), // one branch if mc labels enabled + "labels-branch-name"})(); +} + +DataProcessorSpec getTRDTPCTrackWriterSpec(bool useMC, bool strictMode) +{ + using LabelsType = std::vector<o2::MCCompLabel>; + + // A spectator to store the size of the data array for the logger below + auto tracksSize = std::make_shared<int>(); + auto tracksLogger = [tracksSize](std::vector<o2::trd::TrackTRD> const& tracks) { + *tracksSize = tracks.size(); + }; + uint32_t ss = o2::globaltracking::getSubSpec(strictMode ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + return MakeRootTreeWriterSpec("trd-track-writer-tpc", + "trdmatches_tpc.root", + "tracksTRD", + BranchDefinition<std::vector<o2::trd::TrackTRD>>{InputSpec{"tracks", o2::header::gDataOriginTRD, "MATCH_TPC", ss}, + "tracks", + "tracks-branch-name", + 1, + tracksLogger}, + BranchDefinition<std::vector<o2::trd::TrackTriggerRecord>>{InputSpec{"trackTrig", o2::header::gDataOriginTRD, "TRGREC_TPC", ss}, + "trgrec", + "trgrec-branch-name", + 1}, + BranchDefinition<LabelsType>{InputSpec{"trdlabels", o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss}, + "labelsTRD", + (useMC ? 1 : 0), // one branch if mc labels enabled + "trdlabels-branch-name"}, + BranchDefinition<LabelsType>{InputSpec{"matchitstpclabels", o2::header::gDataOriginTRD, "MCLB_TPC", ss}, + "labels", + (useMC ? 1 : 0), // one branch if mc labels enabled + "labels-branch-name"})(); +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDTrackletReaderSpec.cxx b/Detectors/TRD/workflow/io/src/TRDTrackletReaderSpec.cxx new file mode 100644 index 0000000000000..fb086714ebaa4 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDTrackletReaderSpec.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TRDTrackletReaderSpec.cxx + +#include "TRDWorkflowIO/TRDTrackletReaderSpec.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "fairlogger/Logger.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +void TRDTrackletReader::init(InitContext& ic) +{ + // get the option from the init context + LOG(INFO) << "Init TRD tracklet reader!"; + mInFileNameTrklt = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("trd-tracklet-infile")); + mInTreeNameTrklt = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("treename")); + connectTree(); + if (mUseTrackletTransform) { + connectTreeCTracklet(); + } +} + +void TRDTrackletReader::connectTreeCTracklet() +{ + mTreeCTrklt.reset(nullptr); // in case it was already loaded + mFileCTrklt.reset(TFile::Open("trdcalibratedtracklets.root")); + assert(mFileCTrklt && !mFileCTrklt->IsZombie()); + mTreeCTrklt.reset((TTree*)mFileCTrklt->Get("ctracklets")); + assert(mTreeCTrklt); + mTreeCTrklt->SetBranchAddress("CTracklets", &mTrackletsCalPtr); + mTreeCTrklt->SetBranchAddress("TrigRecMask", &mTrigRecMaskPtr); + LOG(INFO) << "Loaded tree from trdcalibratedtracklets.root with " << mTreeCTrklt->GetEntries() << " entries"; +} + +void TRDTrackletReader::connectTree() +{ + mTreeTrklt.reset(nullptr); // in case it was already loaded + mFileTrklt.reset(TFile::Open(mInFileNameTrklt.c_str())); + assert(mFileTrklt && !mFileTrklt->IsZombie()); + mTreeTrklt.reset((TTree*)mFileTrklt->Get(mInTreeNameTrklt.c_str())); + assert(mTreeTrklt); + mTreeTrklt->SetBranchAddress("Tracklet", &mTrackletsPtr); + mTreeTrklt->SetBranchAddress("TrackTrg", &mTriggerRecordsPtr); + if (mUseMC) { + mTreeTrklt->SetBranchAddress("TRKLabels", &mLabelsPtr); + } + LOG(INFO) << "Loaded tree from " << mInFileNameTrklt << " with " << mTreeTrklt->GetEntries() << " entries"; +} + +void TRDTrackletReader::run(ProcessingContext& pc) +{ + auto currEntry = mTreeTrklt->GetReadEntry() + 1; + assert(currEntry < mTreeTrklt->GetEntries()); // this should not happen + mTreeTrklt->GetEntry(currEntry); + LOG(INFO) << "Pushing " << mTriggerRecords.size() << " TRD trigger records at entry " << currEntry; + LOG(INFO) << "Pushing " << mTracklets.size() << " uncalibrated TRD tracklets for these trigger records"; + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe}, mTracklets); + if (mUseTrackletTransform) { + assert(mTreeTrklt->GetEntries() == mTreeCTrklt->GetEntries()); + mTreeCTrklt->GetEntry(currEntry); + LOG(INFO) << "Pushing " << mTrackletsCal.size() << " calibrated TRD tracklets for these trigger records"; + LOG(INFO) << "Pushing " << mTrigRecMask.size() << " flags for the given TRD trigger records"; + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "CTRACKLETS", 0, Lifetime::Timeframe}, mTrackletsCal); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRIGRECMASK", 0, Lifetime::Timeframe}, mTrigRecMask); + } + + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe}, mTriggerRecords); + if (mUseMC) { + LOG(INFO) << "Pushing " << mLabels.getNElements() << " TRD tracklet labels"; + pc.outputs().snapshot(Output{"TRD", "TRKLABELS", 0, Lifetime::Timeframe}, mLabels); + } + + if (mTreeTrklt->GetReadEntry() + 1 >= mTreeTrklt->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +DataProcessorSpec getTRDTrackletReaderSpec(bool useMC, bool useCalibratedTracklets) +{ + std::vector<OutputSpec> outputs; + if (useCalibratedTracklets) { + outputs.emplace_back(o2::header::gDataOriginTRD, "CTRACKLETS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRIGRECMASK", 0, Lifetime::Timeframe); + } + outputs.emplace_back(o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("TRD", "TRKLABELS", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "TRDTrackletReader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<TRDTrackletReader>(useMC, useCalibratedTracklets)}, + Options{ + {"trd-tracklet-infile", VariantType::String, "trdtracklets.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"treename", VariantType::String, "o2sim", {"Name of top-level TTree"}}, + }}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/io/src/TRDTrackletWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDTrackletWriterSpec.cxx new file mode 100644 index 0000000000000..0b42453997db3 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/TRDTrackletWriterSpec.cxx @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "TRDWorkflowIO/TRDTrackletWriterSpec.h" +#include <SimulationDataFormat/MCTruthContainer.h> +#include <SimulationDataFormat/MCCompLabel.h> +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" + +#include <fstream> +#include <iostream> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +template <typename T> +using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; + +o2::framework::DataProcessorSpec getTRDTrackletWriterSpec(bool useMC) +{ + // using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + /* int producejson=1; + if(producejson){ + //write tracklets in json format for Samesh javascript ui + //probably only going to be for deubgging. + //filename format is : E#.sector#.stack#.json E=Eventnumber(nominal) ... will use timestamp + LOG(info) << " now to produce json"; + ofstream output("E15.0.1.json"); + output << " 10 " << endl; + }*/ + //LOG(info) << "before writing out the tracklet size is " << Tracklet->size(); + return MakeRootTreeWriterSpec("TRDTrkltWrt", + "trdtracklets.root", + "o2sim", + BranchDefinition<std::vector<o2::trd::Tracklet64>>{InputSpec{"tracklets", "TRD", "TRACKLETS"}, "Tracklet"}, + BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"trklabels", "TRD", "TRKLABELS"}, "TRKLabels", (useMC ? 1 : 0), "TRKLABELS"}, + BranchDefinition<std::vector<o2::trd::TriggerRecord>>{InputSpec{"tracklettrigs", "TRD", "TRKTRGRD"}, "TrackTrg"})(); +}; + +} // end namespace trd +} // end namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDTrapRawWriterSpec.cxx b/Detectors/TRD/workflow/io/src/TRDTrapRawWriterSpec.cxx similarity index 80% rename from Detectors/TRD/workflow/src/TRDTrapRawWriterSpec.cxx rename to Detectors/TRD/workflow/io/src/TRDTrapRawWriterSpec.cxx index e05161a9bcec9..87c88b5157532 100644 --- a/Detectors/TRD/workflow/src/TRDTrapRawWriterSpec.cxx +++ b/Detectors/TRD/workflow/io/src/TRDTrapRawWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include "Framework/DataProcessorSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" -#include "TRDWorkflow/TRDTrapRawWriterSpec.h" +#include "TRDWorkflowIO/TRDTrapRawWriterSpec.h" #include "DataFormatsTRD/RawData.h" #include "DataFormatsTRD/TriggerRecord.h" #include "DataFormatsTRD/LinkRecord.h" @@ -39,7 +40,6 @@ o2::framework::DataProcessorSpec getTRDTrapRawWriterSpec() return MakeRootTreeWriterSpec("TRDTrkltRawWrt", "trdtrapraw.root", "o2sim", - 1, BranchDefinition<std::vector<uint32_t>>{InputSpec{"trapraw", "TRD", "RAWDATA"}, "TrapRaw"}, BranchDefinition<std::vector<o2::trd::LinkRecord>>{InputSpec{"traplinks", "TRD", "RAWLNKRD"}, "TrapLinkRecord"}, BranchDefinition<std::vector<o2::trd::TriggerRecord>>{InputSpec{"traprawtrigrec", "TRD", "RAWTRGRD"}, "RawTriggerRecord"})(); diff --git a/Detectors/TRD/workflow/io/src/trd-digittracklet-writer-workflow.cxx b/Detectors/TRD/workflow/io/src/trd-digittracklet-writer-workflow.cxx new file mode 100644 index 0000000000000..42f3b9a1dc1ac --- /dev/null +++ b/Detectors/TRD/workflow/io/src/trd-digittracklet-writer-workflow.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "TRDWorkflowIO/TRDDigitReaderSpec.h" +#include "TRDWorkflowIO/TRDTrackletWriterSpec.h" +#include "TRDWorkflowIO/TRDDigitWriterSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ +// this is simply to enable one to write out the tracklet and digits and triggers after reading in the ctf +// to do a comparison pre and post ctf. Use case is probably only unit tests. + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + WorkflowSpec specs; + specs.emplace_back(o2::trd::getTRDTrackletWriterSpec(false)); + specs.emplace_back(o2::trd::getTRDDigitWriterSpec(false, false)); + return specs; +} diff --git a/Detectors/TRD/workflow/io/src/trd-track-reader-workflow.cxx b/Detectors/TRD/workflow/io/src/trd-track-reader-workflow.cxx new file mode 100644 index 0000000000000..07927e18be163 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/trd-track-reader-workflow.cxx @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "TRDWorkflowIO/TRDTrackReaderSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using namespace o2::framework; +using GTrackID = o2::dataformats::GlobalTrackID; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, true, {"disable MC propagation"}}, + {"track-types", VariantType::String, std::string{GTrackID::ALL}, {"comma-separated list of sources to use for tracking"}}, + {"output-strict", o2::framework::VariantType::Bool, false, {"outputs specs should correspond to strict matching mode"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + if (useMC) { + LOG(WARNING) << "TRD track reader cannot read MC labels, useMC = false will be enforced"; + useMC = false; + } + + GTrackID::mask_t allowedSources = GTrackID::getSourcesMask("ITS-TPC-TRD,TPC-TRD"); + GTrackID::mask_t srcTRD = allowedSources & GTrackID::getSourcesMask(configcontext.options().get<std::string>("track-types")); + + WorkflowSpec specs; + if (GTrackID::includesSource(GTrackID::Source::ITSTPCTRD, srcTRD)) { + specs.emplace_back(o2::trd::getTRDGlobalTrackReaderSpec(useMC)); + } + if (GTrackID::includesSource(GTrackID::Source::TPCTRD, srcTRD)) { + specs.emplace_back(o2::trd::getTRDTPCTrackReaderSpec(useMC, configcontext.options().get<bool>("output-strict"))); + } + return std::move(specs); +} diff --git a/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..9fd140f4d3ef6 --- /dev/null +++ b/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TRDWorkflow/EntropyDecoderSpec.h" +#include "TRDReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::trd::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& triggers = pc.outputs().make<std::vector<TriggerRecord>>(OutputRef{"triggers"}); + auto& tracklets = pc.outputs().make<std::vector<Tracklet64>>(OutputRef{"tracklets"}); + auto& digits = pc.outputs().make<std::vector<Digit>>(OutputRef{"digits"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::trd::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, triggers, tracklets, digits); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << tracklets.size() << " TRD tracklets and " << digits.size() << " digits in " << triggers.size() << " triggers in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "TRD Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"triggers"}, "TRD", "TRKTRGRD", 0, Lifetime::Timeframe}, + OutputSpec{{"tracklets"}, "TRD", "TRACKLETS", 0, Lifetime::Timeframe}, + OutputSpec{{"digits"}, "TRD", "DIGITS", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "trd-entropy-decoder", + Inputs{InputSpec{"ctf", "TRD", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..0f0febe19d1f9 --- /dev/null +++ b/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TRDWorkflow/EntropyEncoderSpec.h" +#include "TRDReconstruction/CTFCoder.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include <TStopwatch.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::trd::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto triggers = pc.inputs().get<gsl::span<TriggerRecord>>("triggers"); + auto tracklets = pc.inputs().get<gsl::span<Tracklet64>>("tracklets"); + auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"TRD", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, triggers, tracklets, digits); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for TRD in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "TRD Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("triggers", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); + inputs.emplace_back("tracklets", "TRD", "TRACKLETS", 0, Lifetime::Timeframe); + inputs.emplace_back("digits", "TRD", "DIGITS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "trd-entropy-encoder", + inputs, + Outputs{{"TRD", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/src/KrClustererSpec.cxx b/Detectors/TRD/workflow/src/KrClustererSpec.cxx new file mode 100644 index 0000000000000..96021cc66fa48 --- /dev/null +++ b/Detectors/TRD/workflow/src/KrClustererSpec.cxx @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file KrClustererSpec.cxx +/// \brief DPL device for running the TRD Krypton cluster finder +/// \author Ole Schmidt + +#include "TRDWorkflow/KrClustererSpec.h" +#include "TRDCalibration/KrClusterFinder.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "TStopwatch.h" +#include <fairlogger/Logger.h> + +using namespace o2::framework; + +namespace o2 +{ +namespace trd +{ + +class TRDKrClustererDevice : public Task +{ + public: + TRDKrClustererDevice() = default; + ~TRDKrClustererDevice() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + o2::trd::KrClusterFinder mKrClFinder; +}; + +void TRDKrClustererDevice::init(InitContext& ic) +{ + mKrClFinder.init(); +} + +void TRDKrClustererDevice::run(ProcessingContext& pc) +{ + TStopwatch timer; + + const auto digits = pc.inputs().get<gsl::span<Digit>>("digits"); + const auto triggerRecords = pc.inputs().get<gsl::span<TriggerRecord>>("triggerRecords"); + + mKrClFinder.reset(); + mKrClFinder.setInput(digits, triggerRecords); + timer.Start(); + mKrClFinder.findClusters(); + timer.Stop(); + + LOGF(INFO, "TRD Krypton cluster finder total timing: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime()); + LOGF(INFO, "Found %lu Kr clusters in %lu input trigger records.", mKrClFinder.getKrClusters().size(), triggerRecords.size()); + + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe}, mKrClFinder.getKrClusters()); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe}, mKrClFinder.getKrTrigRecs()); +} + +void TRDKrClustererDevice::endOfStream(EndOfStreamContext& ec) +{ + LOG(INFO) << "Done with the cluster finding (EoS received)"; +} + +DataProcessorSpec getKrClustererSpec(bool digitTrigRec) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("digits", o2::header::gDataOriginTRD, "DIGITS", 0, Lifetime::Timeframe); + if (digitTrigRec) { + inputs.emplace_back("triggerRecords", o2::header::gDataOriginTRD, "TRGRDIG", 0, Lifetime::Timeframe); + } else { + inputs.emplace_back("triggerRecords", o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe); + } + std::vector<OutputSpec> outputs; + outputs.emplace_back(o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "trd-kr-clusterer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<TRDKrClustererDevice>()}, + Options{}}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDDigitReaderSpec.cxx b/Detectors/TRD/workflow/src/TRDDigitReaderSpec.cxx deleted file mode 100644 index 9931ad0269fa2..0000000000000 --- a/Detectors/TRD/workflow/src/TRDDigitReaderSpec.cxx +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TRDWorkflow/TRDDigitReaderSpec.h" - -#include <cstdlib> -// this is somewhat assuming that a DPL workflow will run on one node - -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/DataRefUtils.h" -#include "Framework/Lifetime.h" -#include "DPLUtils/RootTreeReader.h" -#include "Headers/DataHeader.h" -#include "TStopwatch.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext -#include "TChain.h" -#include <SimulationDataFormat/MCCompLabel.h> -#include <SimulationDataFormat/ConstMCTruthContainer.h> -#include <SimulationDataFormat/IOMCTruthContainerView.h> -#include "Framework/Task.h" -#include "DataFormatsParameters/GRPObject.h" -#include "TRDBase/Digit.h" // for the Digit type -#include "TRDSimulation/TrapSimulator.h" -#include "TRDSimulation/Digitizer.h" -#include "TRDSimulation/Detector.h" // for the Hit type - -#include "DetectorsBase/GeometryManager.h" - -#include "DataFormatsTRD/TriggerRecord.h" - -#include <TTree.h> -#include <TFile.h> -#include <TSystem.h> -#include <TRandom1.h> - -#include <sstream> -#include <cmath> -#include <unistd.h> // for getppid -#include <TMessage.h> // object serialization -#include <memory> // std::unique_ptr -#include <cstring> // memcpy -#include <string> // std::string -#include <cassert> -#include <chrono> -#include <thread> -#include <algorithm> - -using namespace o2::framework; -using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; - -namespace o2 -{ -namespace trd -{ - -void TRDDigitReaderSpec::init(InitContext& ic) -{ - LOG(info) << "input filename is : " << ic.options().get<std::string>("digitsfile").c_str(); - - mInputFileName = ic.options().get<std::string>("digitsfile"); - mFile = std::make_unique<TFile>(mInputFileName.c_str(), "OLD"); - if (!mFile->IsOpen()) { - LOG(error) << "Cannot open digits input file : " << mInputFileName; - mState = 0; //prevent from getting into run method. - - } else { - mState = 1; - } -} - -void TRDDigitReaderSpec::run(ProcessingContext& pc) -{ - if (mState != 1) { - LOG(info) << "mState is not 1"; - return; - } - auto DPLTree = ((TTree*)mFile->Get(mDigitTreeName.c_str())); - if (DPLTree) { - std::vector<o2::trd::Digit>* digits = nullptr; - o2::dataformats::IOMCTruthContainerView* ioLabels = nullptr; - std::vector<o2::trd::TriggerRecord>* triggerRecords = nullptr; - - auto getFromBranch = [DPLTree](const char* name, void** ptr) { - auto br = DPLTree->GetBranch(name); - br->SetAddress(ptr); - br->GetEntry(0); - br->ResetAddress(); - }; - getFromBranch(mDigitBranchName.c_str(), (void**)&digits); - getFromBranch(mTriggerRecordBranchName.c_str(), (void**)&triggerRecords); - getFromBranch(mMCLabelsBranchName.c_str(), (void**)&ioLabels); - - // publish labels in shared memory - auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::trd::MCLabel>>(Output{"TRD", "LABELS", 0, Lifetime::Timeframe}); - ioLabels->copyandflatten(sharedlabels); - pc.outputs().snapshot(Output{"TRD", "DIGITS", 0, Lifetime::Timeframe}, *digits); - pc.outputs().snapshot(Output{"TRD", "TRGRDIG", 0, Lifetime::Timeframe}, *triggerRecords); - LOG(info) << "TRDDigitReader digits size=" << digits->size() << " triggerrecords size=" << triggerRecords->size() << " mc labels size (in bytes) = " << sharedlabels.size(); - } - //delete DPLTree; // next line will delete the pointer as well. - mFile->Close(); - - mState = 2; // prevent coming in here again. - // send endOfData control event and mark the reader as ready to finish - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); -} - -DataProcessorSpec getTRDDigitReaderSpec(int channels) -{ - - return DataProcessorSpec{"TRDDIGITREADER", - Inputs{}, - Outputs{ - OutputSpec{"TRD", "DIGITS", 0, Lifetime::Timeframe}, - OutputSpec{"TRD", "TRGRDIG", 0, Lifetime::Timeframe}, - OutputSpec{"TRD", "LABELS", 0, Lifetime::Timeframe}}, - // outputs, - AlgorithmSpec{adaptFromTask<TRDDigitReaderSpec>(channels)}, - Options{ - {"digitsfile", VariantType::String, "trddigits.root", {"Input data file containing run3 digitizer going into Trap Simulator"}}, - {"run2digitsfile", VariantType::String, "run2digits.root", {"Input data file containing run2 digitis going into Trap Simulator"}}}}; -}; - -} //end namespace trd -} //end namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx b/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx index 5d8ca8b7b5257..21bdee4ea7475 100644 --- a/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,18 +17,20 @@ #include "Framework/Lifetime.h" #include "Headers/DataHeader.h" #include "TStopwatch.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" +#include "Steer/HitProcessingManager.h" // for DigitizationContext #include <SimulationDataFormat/MCCompLabel.h> #include <SimulationDataFormat/ConstMCTruthContainer.h> #include "Framework/Task.h" +#include "DetectorsBase/BaseDPLDigitizer.h" #include "DataFormatsParameters/GRPObject.h" -#include "TRDBase/Digit.h" // for the Digit type +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/Hit.h" +#include "DataFormatsTRD/Digit.h" // for the Digit type +#include "TRDBase/Calibrations.h" #include "TRDSimulation/Digitizer.h" #include "TRDSimulation/Detector.h" // for the Hit type -#include "DetectorsBase/BaseDPLDigitizer.h" -#include "TRDBase/Calibrations.h" -#include "DataFormatsTRD/TriggerRecord.h" using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; @@ -59,7 +62,7 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer bool mctruth = pc.outputs().isAllowed({"TRD", "LABELS", 0}); Calibrations simcal; - simcal.setCCDBForSimulation(297595); + simcal.getCCDBObjects(297595); mDigitizer.setCalibrations(&simcal); // read collision context from input @@ -68,16 +71,16 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer auto& irecords = context->getEventRecords(); for (auto& record : irecords) { - LOG(INFO) << "TRD TIME RECEIVED " << record.getTimeNS(); + LOG(DEBUG) << "TRD TIME RECEIVED " << record.getTimeNS(); } auto& eventParts = context->getEventParts(); std::vector<o2::trd::Digit> digitsAccum; // accumulator for digits - o2::dataformats::MCTruthContainer<o2::trd::MCLabel> labelsAccum; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> labelsAccum; std::vector<TriggerRecord> triggers; std::vector<o2::trd::Digit> digits; // digits which get filled - o2::dataformats::MCTruthContainer<o2::trd::MCLabel> labels; // labels which get filled + o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels; // labels which get filled o2::InteractionTimeRecord currentTime; // the current time o2::InteractionTimeRecord triggerTime; // the time at which the TRD start reading out a signal @@ -90,13 +93,15 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer for (int collID = 0; collID < irecords.size(); ++collID) { currentTime = irecords[collID]; // Trigger logic implemented here + bool isNewTrigger = true; // flag newly accepted readout trigger if (firstEvent) { triggerTime = currentTime; firstEvent = false; } else { double dT = currentTime.getTimeNS() - triggerTime.getTimeNS(); - if (dT < o2::trd::Digitizer::BUSY_TIME) { + if (dT < o2::trd::constants::BUSY_TIME) { // BUSY_TIME = READOUT_TIME + DEAD_TIME, if less than that, pile up the signals and update the last time + isNewTrigger = false; mDigitizer.pileup(); } else { // A new signal can be received, and the detector read it out: @@ -116,7 +121,10 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer } } - mDigitizer.setEventTime(triggerTime.getTimeNS()); // do we need this? + mDigitizer.setEventTime(triggerTime.getTimeNS()); + if (isNewTrigger) { + mDigitizer.setTriggerTime(triggerTime.getTimeNS()); + } // for each collision, loop over the constituents event and source IDs // (background signal merging is basically taking place here) @@ -124,9 +132,9 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.setEventID(part.entryID); mDigitizer.setSrcID(part.sourceID); // get the hits for this event and this source and process them - std::vector<o2::trd::HitType> hits; + std::vector<o2::trd::Hit> hits; context->retrieveHits(mSimChains, "TRDHit", part.sourceID, part.entryID, &hits); - mDigitizer.process(hits, digits, labels); + mDigitizer.process(hits); } } @@ -138,15 +146,16 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer if (mctruth) { labelsAccum.mergeAtBack(labels); } + LOGF(INFO, "List of TRD chambers with at least one drift velocity out of range: %s", mDigitizer.dumpFlaggedChambers()); timer.Stop(); - LOG(INFO) << "TRD: Digitization took " << timer.RealTime() << "s"; + LOGF(INFO, "TRD digitization timing: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime()); LOG(INFO) << "TRD: Sending " << digitsAccum.size() << " digits"; pc.outputs().snapshot(Output{"TRD", "DIGITS", 0, Lifetime::Timeframe}, digitsAccum); if (mctruth) { LOG(INFO) << "TRD: Sending " << labelsAccum.getNElements() << " labels"; // we are flattening the labels and write to managed shared memory container for further communication - auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::trd::MCLabel>>(Output{"TRD", "LABELS", 0, Lifetime::Timeframe}); + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TRD", "LABELS", 0, Lifetime::Timeframe}); labelsAccum.flatten_to(sharedlabels); } LOG(INFO) << "TRD: Sending ROMode= " << mROMode << " to GRPUpdater"; diff --git a/Detectors/TRD/workflow/src/TRDEventDisplayFeedSpec.cxx b/Detectors/TRD/workflow/src/TRDEventDisplayFeedSpec.cxx new file mode 100644 index 0000000000000..50d709c6df5e2 --- /dev/null +++ b/Detectors/TRD/workflow/src/TRDEventDisplayFeedSpec.cxx @@ -0,0 +1,283 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TMath.h" + +#include "TRDWorkflow/TRDEventDisplayFeedSpec.h" + +#include "DataFormatsTRD/TrackTriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsParameters/GRPObject.h" + +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; +using namespace o2::globaltracking; + +namespace o2 +{ +namespace trd +{ + +void TRDEventDisplayFeedSpec::init(o2::framework::InitContext& ic) +{ + LOG(info) << "Initializing event display feed..."; +} + +json TRDEventDisplayFeedSpec::getTracksJson(gsl::span<const TrackTRD> tracks, gsl::span<const Tracklet64> tracklets, gsl::span<const TrackTriggerRecord> trackTrigRecs, int iEvent) +{ + json trackArray = json::array(); + + const auto& trigRec = trackTrigRecs[iEvent]; + for (int iTrack = 0; iTrack < trigRec.getNumberOfTracks(); ++iTrack) { + TrackTRD track = tracks[iTrack + trigRec.getFirstTrack()]; + std::string trackId = Form("E%d_T%d", iEvent, iTrack); + + float alpha = track.getAlpha(); + if (alpha < 0) { + alpha += TMath::Pi() * 2; + } + + int sector = TMath::Nint(18.0 * alpha / (2 * TMath::Pi()) - 0.5); + int stack; + for (int iLayer = 0; iLayer < 6; iLayer++) { + int trackletIdx = track.getTrackletIndex(iLayer); + if (trackletIdx != -1) { + int detector = tracklets[trackletIdx].getDetector(); + stack = detector % 30 / 6; + break; + } + } + + // Tangent of the track momentum dip angle + float tanLambda = track.getParam(3); + float lambdaDeg = TMath::ATan(tanLambda) * 180 / TMath::Pi(); + + // Record stacks with tracks for look-up by writeDigits() later + int layerZero = mGeo->getDetector(0, stack, sector); + mUsedDetectors.set(layerZero); + + json trackJson = { + {"id", trackId}, + {"stk", stack}, + {"sec", sector}, + {"typ", "Trd"}, + {"i", {{"pT", track.getPt()}, {"alpha", track.getAlpha()}, {"lambda", lambdaDeg}, {"pid", (int)track.getPID().getID()}}}, + {"path", json::array()}, + {"tlids", json::array()}}; + + bool ok; + for (int x = 1; x <= 470; x += 10) { + auto xyz = track.getXYZGloAt(x, mBz, ok); + json point = {{"x", xyz.X()}, {"y", xyz.Y()}, {"z", xyz.Z()}}; + trackJson["path"].push_back(point); + } + + // Match TRD tracklets to track + for (int iLayer = 0; iLayer < 6; iLayer++) { + // trackletIdx gives absolute index of tracklet across all events + int trackletIdx = track.getTrackletIndex(iLayer); + if (trackletIdx != -1) { + int trackletCount = 0; + // count number of tracklets in all events prior to iEvent + for (int i = 0; i < iEvent; i++) { + trackletCount += mTrigRecs[i].getNumberOfTracklets(); + } + // trackletId needs relative tracklet index within single event + std::string trackletId = Form("E%d_L%d", iEvent, trackletIdx - trackletCount); + // record {trackletId, trackId} pair in order to match tracks to tracklets in printTracklets() + mTrackletMap.insert(std::pair<std::string, std::string>(trackletId, trackId)); + trackJson["tlids"].push_back(trackletId); + } + } + trackArray.push_back(trackJson); + } + return trackArray; +} + +json TRDEventDisplayFeedSpec::getTrackletsJson(gsl::span<const Tracklet64> tracklets, int iEvent) +{ + json trackletArray = json::array(); + + const auto& trigRec = mTrigRecs[iEvent]; + for (int iTracklet = 0; iTracklet < trigRec.getNumberOfTracklets(); ++iTracklet) { + Tracklet64 tracklet = tracklets[iTracklet + trigRec.getFirstTracklet()]; + CalibratedTracklet cTracklet = mTransformer.transformTracklet(tracklet); + + std::string trackletId = Form("E%d_L%d", iEvent, iTracklet); + // Find matched track if it exists + std::string trackId = (mTrackletMap.find(trackletId) != mTrackletMap.end() ? mTrackletMap.at(trackletId) : "null"); + + int detector = tracklet.getDetector(); + int sector = mGeo->getSector(detector); + int stack = mGeo->getStack(detector); + int layer = mGeo->getLayer(detector); + + // Start position of both raw and calibrated tracklet in event display + float localY = cTracklet.getY(); + // Slope of raw tracklet (key dyDxAN in JSON) + float rawDyDx = tracklet.getUncalibratedDy() / mGeo->cdrHght(); + // Slope of calibrated tracklet + float dyDx = cTracklet.getDy() / mGeo->cdrHght(); + + json trackletJson = { + {"id", trackletId}, + {"stk", stack}, + {"sec", sector}, + {"lyr", layer}, + {"row", tracklet.getPadRow()}, + {"trk", trackId}, + {"lY", localY}, + {"dyDx", dyDx}, + {"dyDxAN", rawDyDx}}; + + if (trackId == "null") { + trackletJson["trk"] = nullptr; + } + + trackletArray.push_back(trackletJson); + } + return trackletArray; +} + +void TRDEventDisplayFeedSpec::writeDigits(gsl::span<const Digit> digits, int iEvent) +{ + const auto& trigRec = mTrigRecs[iEvent]; + for (int det = 0; det < constants::MAXCHAMBER; det += 6) { + if (mUsedDetectors[det]) { + int sector = mGeo->getSector(det); + int stack = mGeo->getStack(det); + + json digitsJson = { + {"evid", iEvent}, + {"lyrs", json::array()}}; + + for (int iLayer = 0; iLayer < 6; iLayer++) { + json layerJson = { + {"lyr", iLayer}, + {"pads", json::array()}}; + + for (int iDigit = trigRec.getFirstDigit(); iDigit < trigRec.getFirstDigit() + trigRec.getNumberOfDigits(); ++iDigit) { + Digit digit = digits[iDigit]; + + int detector = digit.getDetector(); + + if (detector == det + iLayer) { + // Digits are in stack with track + int row = digit.getPadRow(); + int col = digit.getPadCol(); + + json padJson = { + {"row", row}, + {"col", col}, + {"tbins", json::array()}}; + + for (auto adc : digit.getADC()) { + padJson["tbins"].push_back(adc); + } + layerJson["pads"].push_back(padJson); + } + } + digitsJson["lyrs"].push_back(layerJson); + } + std::ofstream digitsOut(Form("../alice-trd-event-display/data/o2/E%d.%d.%d.json", iEvent, sector, stack)); + digitsOut << digitsJson.dump(4); + } + } +} // namespace trd + +void TRDEventDisplayFeedSpec::run(o2::framework::ProcessingContext& pc) +{ + LOG(info) << "Running event display feed..."; + + json jsonData = json::array(); + + auto tracks = pc.inputs().get<gsl::span<TrackTRD>>("trdtracks"); + auto tracklets = pc.inputs().get<gsl::span<Tracklet64>>("trdtracklets"); + auto digits = pc.inputs().get<gsl::span<Digit>>("trddigits"); + + mTrigRecs = pc.inputs().get<gsl::span<TriggerRecord>>("trdtriggerrec"); + auto trackTrigRecs = pc.inputs().get<gsl::span<TrackTriggerRecord>>("tracktriggerrec"); + + int nEvents = std::min((int)mTrigRecs.size(), mNeventsMax); + + for (int iEvent = 0; iEvent < nEvents; ++iEvent) { + const auto& trigRec = mTrigRecs[iEvent]; + const auto& trackTrigRec = trackTrigRecs[iEvent]; + + if (trackTrigRec.getNumberOfTracks() == 0) { + continue; + } + + mUsedDetectors.reset(); + + // Get run parameters + o2::base::Propagator::initFieldFromGRP(); + auto prop = o2::base::Propagator::Instance(); + mBz = prop->getNominalBz(); + + auto field = o2::field::MagneticField::createNominalField(mBz); + double beamEnergy = field->getBeamEnergy(); + std::string beamType = field->getBeamTypeText(); + + auto grp = o2::parameters::GRPObject::loadFrom(); + auto triggers = grp->getDetsTrigger(); + auto triggerNames = o2::detectors::DetID::getNames(triggers); + + json eventJson = { + {"id", Form("E%d", iEvent)}, + {"i", {{"be", beamEnergy}, {"bt", beamType}, {"ft", triggerNames}}}, + {"tracks", json::array()}, + {"trklts", json::array()}}; + + eventJson["tracks"] = getTracksJson(tracks, tracklets, trackTrigRecs, iEvent); + + eventJson["trklts"] = getTrackletsJson(tracklets, iEvent); + + writeDigits(digits, iEvent); + + jsonData.push_back(eventJson); + } + std::ofstream jsScriptOut(Form("../alice-trd-event-display/data/o2/script.js")); + // Path to data file for alicetrd.web: lxplus.cern.ch:/eos/project/a/alice-trd/www/eventdisplay/data/o2/script.js + + jsScriptOut << "function getDigitsLoadUrl(eventNo, sector, stack) { return `" + << "data/o2/${eventNo}.${sector}.${stack}.json`; }" + << std::endl + << std::endl + << "function getData() {\n\treturn " + << jsonData.dump(4) << "}"; +} + +o2::framework::DataProcessorSpec getTRDEventDisplayFeedSpec(int nEventsMax) +{ + std::vector<InputSpec> inputs; + std::vector<OutputSpec> outputs; + + inputs.emplace_back("trdtracks", "TRD", "MATCH_ITSTPC", 0, Lifetime::Timeframe); + inputs.emplace_back("trdtracklets", "TRD", "TRACKLETS", 0, Lifetime::Timeframe); + inputs.emplace_back("trddigits", "TRD", "DIGITS", 0, Lifetime::Timeframe); + inputs.emplace_back("trdtriggerrec", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); + inputs.emplace_back("tracktriggerrec", "TRD", "TRGREC_ITSTPC", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "TRDEVENTDISPLAYFEED", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<TRDEventDisplayFeedSpec>(nEventsMax)}, + Options{}}; +} + +} // namespace trd +} //end namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDEventDisplayFeedWorkflow.cxx b/Detectors/TRD/workflow/src/TRDEventDisplayFeedWorkflow.cxx new file mode 100644 index 0000000000000..57b62a28a15ee --- /dev/null +++ b/Detectors/TRD/workflow/src/TRDEventDisplayFeedWorkflow.cxx @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDWorkflowIO/TRDDigitReaderSpec.h" +#include "TRDWorkflowIO/TRDTrackReaderSpec.h" +#include "TRDWorkflow/TRDEventDisplayFeedSpec.h" +#include "TRDWorkflowIO/TRDTrackletReaderSpec.h" + +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"nEventsMax", o2::framework::VariantType::Int, 5, {"Number of events to display"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + WorkflowSpec spec; + + bool useMC = true; + if (!configcontext.options().get<bool>("disable-root-input")) { + spec.emplace_back(o2::trd::getTRDGlobalTrackReaderSpec(useMC)); + spec.emplace_back(o2::trd::getTRDTrackletReaderSpec(useMC, false)); + spec.emplace_back(o2::trd::getTRDDigitReaderSpec(useMC)); + } + + int nEventsMax = configcontext.options().get<int>("nEventsMax"); + spec.emplace_back(o2::trd::getTRDEventDisplayFeedSpec(nEventsMax)); + + return spec; +} diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index 6081c105da61b..f3b720c6661fa 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,16 +12,28 @@ /// @file TRDGlobalTrackingSpec.cxx #include "TRDWorkflow/TRDGlobalTrackingSpec.h" - #include "TRDBase/Geometry.h" - #include "DetectorsCommonDataFormats/NameConf.h" -#include "CommonConstants/LHCConstants.h" #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" #include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" +#include "TPCBase/ParameterElectronics.h" +#include "TPCBase/ParameterGas.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "GPUWorkflowHelper/GPUWorkflowHelper.h" +#include "Framework/ConfigParamRegistry.h" + +#include "DataFormatsTPC/WorkflowHelper.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "CommonConstants/GeomConstants.h" +#include "ITStracking/IOUtils.h" +#include "ITSBase/GeometryTGeo.h" +#include "DataFormatsITSMFT/Cluster.h" +#include "ITSReconstruction/RecoGeomHelper.h" // GPU header #include "GPUReconstruction.h" @@ -33,8 +46,14 @@ #include "GPUTRDInterfaces.h" #include "GPUTRDGeometry.h" +#include <algorithm> + using namespace o2::framework; using namespace o2::gpu; +using namespace o2::globaltracking; +using namespace o2::trd::constants; + +using GTrackID = o2::dataformats::GlobalTrackID; namespace o2 { @@ -43,14 +62,27 @@ namespace trd void TRDGlobalTracking::init(InitContext& ic) { + //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP(o2::base::NameConf::getGRPFileName()); + o2::base::Propagator::initFieldFromGRP(); auto geo = Geometry::instance(); + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); geo->createPadPlaneArray(); geo->createClusterMatrixArray(); mFlatGeo = std::make_unique<GeometryFlat>(*geo); + // this is a hack to provide Mat.LUT from the local file, in general will be provided by the framework from CCDB + std::string matLUTPath = ic.options().get<std::string>("material-lut-path"); + std::string matLUTFile = o2::base::NameConf::getMatLUTFileName(matLUTPath); + if (o2::utils::Str::pathExists(matLUTFile)) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + //-------- init GPU reconstruction --------// GPURecoStepConfiguration cfgRecoStep; cfgRecoStep.steps = GPUDataTypes::RecoStep::NoRecoStep; @@ -63,8 +95,11 @@ void TRDGlobalTracking::init(InitContext& ic) mTracker = new GPUTRDTracker(); mTracker->SetNCandidates(mRec->GetProcessingSettings().trdNCandidates); // must be set before initialization - mTracker->SetProcessPerTimeFrame(); - mTracker->SetNMaxCollisions(mRec->GetProcessingSettings().trdNMaxCollisions); + if (mStrict && mRec->GetProcessingSettings().trdNCandidates == 1) { + LOG(ERROR) << "Strict matching mode requested, but tracks with another close hypothesis will not be rejected. Please set trdNCandidates to at least 3."; + } + mTracker->SetProcessPerTimeFrame(true); + mTracker->SetGenerateSpacePoints(false); // set to true to force space point calculation by the TRD tracker itself mRec->RegisterGPUProcessor(mTracker, false); mChainTracking->SetTRDGeometry(std::move(mFlatGeo)); @@ -72,121 +107,529 @@ void TRDGlobalTracking::init(InitContext& ic) LOG(FATAL) << "GPUReconstruction could not be initialized"; } + std::unique_ptr<o2::gpu::TPCFastTransform> fastTransform = (o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); + mTPCTransform = std::move(fastTransform); + mRecoParam.setBfield(o2::base::Propagator::Instance()->getNominalBz()); + mTracker->PrintSettings(); + LOG(INFO) << "Strict matching mode is " << ((mStrict) ? "ON" : "OFF"); mTimer.Stop(); mTimer.Reset(); } +void TRDGlobalTracking::updateTimeDependentParams() +{ + // strictly speaking, one should do this only in case of the CCDB objects update + // TODO: add CCDB interface + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + auto& gasParam = o2::tpc::ParameterGas::Instance(); + mTPCTBinMUS = elParam.ZbinWidth; + mTPCTBinMUSInv = 1. / mTPCTBinMUS; + mTPCVdrift = gasParam.DriftV; + mTracker->SetTPCVdrift(mTPCVdrift); +} + +void TRDGlobalTracking::fillMCTruthInfo(const TrackTRD& trk, o2::MCCompLabel lblSeed, std::vector<o2::MCCompLabel>& lblContainerTrd, std::vector<o2::MCCompLabel>& lblContainerMatch, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* trkltLabels) const +{ + // Check MC labels of the TRD tracklets attached to the track seed. + // Set TRD track label to the most frequent tracklet label. + // Fake flag is set if either not all TRD tracklets have most frequent label + // or if the seeding label is different from the most frequent TRD label. + // In case multiple tracklet labels occur most often we choose the one which matches the label of the seed, or, + // if that is not the case one of the most frequent labels is chosen arbitrarily + LOG(DEBUG) << "Checking seed with label: " << lblSeed; + std::unordered_map<o2::MCCompLabel, unsigned int> labelCounter; + int nTracklets = 0; + unsigned int maxOccurences = 0; + for (int iLy = 0; iLy < constants::NLAYER; ++iLy) { + auto trkltIndex = trk.getTrackletIndex(iLy); + if (trkltIndex == -1) { + // no tracklet in this layer + continue; + } + const auto& lblsTrklt = trkltLabels->getLabels(trkltIndex); + for (const auto lblTrklt : lblsTrklt) { + int nOcc = ++labelCounter[lblTrklt]; + if (nOcc > maxOccurences) { + maxOccurences = nOcc; + } + } + } + o2::MCCompLabel mostFrequentLabel; + for (const auto& [lbl, count] : labelCounter) { + LOG(DEBUG) << "Label " << lbl << " occured " << count << " times."; + if (count == maxOccurences) { + if (lblSeed == lbl) { + // most frequent label matches seed label + mostFrequentLabel = lbl; + mostFrequentLabel.setFakeFlag(maxOccurences != trk.getNtracklets()); + lblContainerTrd.push_back(mostFrequentLabel); + lblContainerMatch.push_back(lblSeed); // is not fake by definition, since the seed label matches the TRD track label + return; + } else { + // maybe multiple labels occur with the same frequency and the next one might match the seed? + mostFrequentLabel = lbl; + } + } + } + mostFrequentLabel.setFakeFlag(maxOccurences != trk.getNtracklets()); + lblContainerTrd.push_back(mostFrequentLabel); + lblSeed.setFakeFlag(lblSeed != mostFrequentLabel); + lblContainerMatch.push_back(lblSeed); +} + +void TRDGlobalTracking::fillTrackTriggerRecord(const std::vector<TrackTRD>& tracks, std::vector<TrackTriggerRecord>& trigRec, const gsl::span<const o2::trd::TriggerRecord>& trackletTrigRec) const +{ + int currTrigRec = 0; + int nTracksCurr = 0; + int iTrackFirst = 0; + for (const auto& trk : tracks) { + if (trk.getCollisionId() != currTrigRec) { + // new collision ID, create new track trigger record + trigRec.emplace_back(trackletTrigRec[currTrigRec].getBCData(), iTrackFirst, nTracksCurr); + currTrigRec = trk.getCollisionId(); + iTrackFirst += nTracksCurr; + nTracksCurr = 0; + } + ++nTracksCurr; + } + if (nTracksCurr > 0) { + // create track trigger record for remaining track range + trigRec.emplace_back(trackletTrigRec[currTrigRec].getBCData(), iTrackFirst, nTracksCurr); + } +} + void TRDGlobalTracking::run(ProcessingContext& pc) { mTimer.Start(false); - const auto tracksITSTPC = pc.inputs().get<gsl::span<o2::dataformats::TrackTPCITS>>("tpcitstrack"); - const auto trackletsTRD = pc.inputs().get<gsl::span<o2::trd::Tracklet64>>("trdtracklets"); - const auto triggerRecords = pc.inputs().get<gsl::span<o2::trd::TriggerRecord>>("trdtriggerrec"); - - int nTracks = tracksITSTPC.size(); - int nCollisions = triggerRecords.size(); - int nTracklets = trackletsTRD.size(); - LOGF(INFO, "There are %i tracklets in total from %i trigger records", nTracklets, nCollisions); + mChainTracking->ClearIOPointers(); + o2::globaltracking::RecoContainer inputTracks; + inputTracks.collectData(pc, *mDataRequest); + mTPCClusterIdxStruct = &inputTracks.inputsTPCclusters->clusterIndex; + mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCTransform.get(), o2::base::Propagator::Instance()->getNominalBz(), inputTracks.getTPCTracksClusterRefs().data(), inputTracks.clusterShMapTPC.data(), nullptr, o2::base::Propagator::Instance()); + auto tmpInputContainer = getRecoInputContainer(pc, &mChainTracking->mIOPtrs, &inputTracks, mUseMC); + auto tmpContainer = GPUWorkflowHelper::fillIOPtr(mChainTracking->mIOPtrs, inputTracks, mUseMC, nullptr, GTrackID::getSourcesMask("TRD"), mTrkMask, GTrackID::mask_t{GTrackID::MASK_NONE}); + mTrackletsRaw = inputTracks.getTRDTracklets(); + mTrackletsCalib = inputTracks.getTRDCalibratedTracklets(); + mTPCTracksArray = inputTracks.getTPCTracks(); + if (GTrackID::includesDet(GTrackID::DetID::ITS, mTrkMask)) { + // load ITS tracks and clusters needed for the refit + mITSTracksArray = inputTracks.getITSTracks(); + mITSTrackClusIdx = inputTracks.getITSTracksClusterRefs(); + const auto clusITS = inputTracks.getITSClusters(); + if (clusITS.empty()) { + LOG(FATAL) << "No ITS clusters"; + return; + } + const auto patterns = inputTracks.getITSClustersPatterns(); + auto pattIt = patterns.begin(); + mITSClustersArray.reserve(clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + } - std::vector<float> trdTriggerTimes; - std::vector<int> trdTriggerIndices; + LOGF(INFO, "There are %i tracklets in total from %i trigger records", mChainTracking->mIOPtrs.nTRDTracklets, mChainTracking->mIOPtrs.nTRDTriggerRecords); + LOGF(INFO, "As input seeds are available: %i ITS-TPC matched tracks and %i TPC tracks", mChainTracking->mIOPtrs.nTracksTPCITSO2, mChainTracking->mIOPtrs.nOutputTracksTPCO2); - for (int iEv = 0; iEv < nCollisions; ++iEv) { - const auto& trg = triggerRecords.at(iEv); - int nTrackletsCurrent = trg.getNumberOfObjects(); - int iFirstTracklet = trg.getFirstEntry(); - int64_t evTime = trg.getBCData().toLong() * o2::constants::lhc::LHCBunchSpacingNS; // event time in ns - trdTriggerTimes.push_back(evTime / 1000.); - trdTriggerIndices.push_back(iFirstTracklet); - LOGF(DEBUG, "Event %i: Occured at %li us after SOR, contains %i tracklets, index of first tracklet is %i", iEv, evTime / 1000, nTrackletsCurrent, iFirstTracklet); + std::vector<o2::MCCompLabel> matchLabelsITSTPC; + std::vector<o2::MCCompLabel> trdLabelsITSTPC; + std::vector<o2::MCCompLabel> matchLabelsTPC; + std::vector<o2::MCCompLabel> trdLabelsTPC; + gsl::span<const o2::MCCompLabel> tpcTrackLabels; + gsl::span<const o2::MCCompLabel> itstpcTrackLabels; + if (mUseMC) { + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, mTrkMask)) { + itstpcTrackLabels = inputTracks.getTPCITSTracksMCLabels(); + } + if (GTrackID::includesSource(GTrackID::Source::TPC, mTrkMask)) { + tpcTrackLabels = inputTracks.getTPCTracksMCLabels(); + } } mTracker->Reset(); - - mChainTracking->mIOPtrs.nMergedTracks = nTracks; - mChainTracking->mIOPtrs.nTRDTracklets = nTracklets; - mChainTracking->AllocateIOMemory(); + updateTimeDependentParams(); mRec->PrepareEvent(); mRec->SetupGPUProcessor(mTracker, true); - LOG(DEBUG) << "Start loading input into TRD tracker"; - // load everything into the tracker - int nTracksLoaded = 0; - for (int iTrk = 0; iTrk < nTracks; ++iTrk) { - const auto& match = tracksITSTPC[iTrk]; - const auto& trk = match.getParamOut(); - GPUTRDTrack trkLoad; - trkLoad.setX(trk.getX()); - trkLoad.setAlpha(trk.getAlpha()); - for (int i = 0; i < 5; ++i) { - trkLoad.setParam(trk.getParam(i), i); - } - for (int i = 0; i < 15; ++i) { - trkLoad.setCov(trk.getCov()[i], i); - } - trkLoad.setTime(match.getTimeMUS().getTimeStamp()); - if (mTracker->LoadTrack(trkLoad)) { - continue; + // check trigger record filter setting + bool foundFilteredTrigger = false; + for (int iTrig = 0; iTrig < mChainTracking->mIOPtrs.nTRDTriggerRecords; ++iTrig) { + if (mChainTracking->mIOPtrs.trdTrigRecMask[iTrig] == 0) { + foundFilteredTrigger = true; } - ++nTracksLoaded; - LOGF(DEBUG, "Loaded track %i with time %f", nTracksLoaded, trkLoad.getTime()); + } + if (!foundFilteredTrigger && mTrigRecFilter) { + LOG(WARNING) << "Trigger filtering requested, but no TRD trigger is actually masked. Can be that none needed to be masked or that the setting was not active for the tracklet transformer"; + } else if (foundFilteredTrigger && !mTrigRecFilter) { + LOG(ERROR) << "Trigger filtering is not requested, but masked TRD triggers are found. Rerun tracklet transformer without trigger filtering"; } - for (int iTrklt = 0; iTrklt < nTracklets; ++iTrklt) { - auto trklt = trackletsTRD[iTrklt]; - unsigned int trkltWord = 0; // DUMMY - GPUTRDTrackletWord trkltLoad; - trkltLoad.SetId(iTrklt); - trkltLoad.SetHCId(trklt.getHCID()); - trkltLoad.SetTrackletWord(trkltWord); - if (mTracker->LoadTracklet(trkltLoad) > 0) { - LOG(WARNING) << "Could not load tracklet " << iTrklt; + // load input tracks + LOG(DEBUG) << "Start loading input seeds into TRD tracker"; + int nTracksLoadedITSTPC = 0; + int nTracksLoadedTPC = 0; + // load ITS-TPC matched tracks + for (int iTrk = 0; iTrk < mChainTracking->mIOPtrs.nTracksTPCITSO2; ++iTrk) { + const auto& trkITSTPC = mChainTracking->mIOPtrs.tracksTPCITSO2[iTrk]; + GPUTRDTracker::HelperTrackAttributes trkAttribs; + trkAttribs.mTime = trkITSTPC.getTimeMUS().getTimeStamp(); + trkAttribs.mTimeAddMax = trkITSTPC.getTimeMUS().getTimeStampError() * mRec->GetParam().rec.trd.nSigmaTerrITSTPC; + trkAttribs.mTimeSubMax = trkITSTPC.getTimeMUS().getTimeStampError() * mRec->GetParam().rec.trd.nSigmaTerrITSTPC; + GPUTRDTrack trkLoad(trkITSTPC); + auto trackGID = GTrackID(iTrk, GTrackID::ITSTPC); + if (mTracker->LoadTrack(trkLoad, trackGID.getRaw(), true, &trkAttribs)) { + continue; + } + ++nTracksLoadedITSTPC; + LOGF(DEBUG, "Loaded ITS-TPC track %i with time %f", nTracksLoadedITSTPC, trkAttribs.mTime); + } + // load TPC-only tracks + for (int iTrk = 0; iTrk < mChainTracking->mIOPtrs.nOutputTracksTPCO2; ++iTrk) { + if (mChainTracking->mIOPtrs.tpcLinkITS && mChainTracking->mIOPtrs.tpcLinkITS[iTrk] != -1) { + // this TPC tracks has already been matched to ITS and the ITS-TPC track has already been loaded in the tracker + continue; } + const auto& trkTpc = mChainTracking->mIOPtrs.outputTracksTPCO2[iTrk]; + GPUTRDTracker::HelperTrackAttributes trkAttribs; + trkAttribs.mTime = trkTpc.getTime0() * mTPCTBinMUS; + trkAttribs.mTimeAddMax = trkTpc.getDeltaTFwd() * mTPCTBinMUS; + trkAttribs.mTimeSubMax = trkTpc.getDeltaTBwd() * mTPCTBinMUS; + if (trkTpc.hasASideClustersOnly()) { + trkAttribs.mSide = -1; + } else if (trkTpc.hasCSideClustersOnly()) { + trkAttribs.mSide = 1; + } + GPUTRDTrack trkLoad(trkTpc); + auto trackGID = GTrackID(iTrk, GTrackID::TPC); + if (mTracker->LoadTrack(trkLoad, trackGID.getRaw(), true, &trkAttribs)) { + continue; + } + ++nTracksLoadedTPC; + LOGF(DEBUG, "Loaded TPC track %i with time %f", nTracksLoadedTPC, trkAttribs.mTime); } - mTracker->SetTriggerRecordTimes(&(trdTriggerTimes[0])); - mTracker->SetTriggerRecordIndices(&(trdTriggerIndices[0])); - mTracker->SetNCollisions(nCollisions); + LOGF(INFO, "%i tracks are loaded into the TRD tracker. Out of those %i ITS-TPC tracks and %i TPC tracks", nTracksLoadedITSTPC + nTracksLoadedTPC, nTracksLoadedITSTPC, nTracksLoadedTPC); + + // start the tracking //mTracker->DumpTracks(); mTracker->DoTracking(mChainTracking); //mTracker->DumpTracks(); - std::vector<GPUTRDTrack> tracksOut(mTracker->NTracks()); - std::copy(mTracker->Tracks(), mTracker->Tracks() + mTracker->NTracks(), tracksOut.begin()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCHTRD", 0, Lifetime::Timeframe}, tracksOut); + // finished tracking, now collect the output + std::vector<TrackTRD> tracksOutITSTPC; + std::vector<TrackTRD> tracksOutTPC; + std::vector<TrackTriggerRecord> trackTrigRecITSTPC; + std::vector<TrackTriggerRecord> trackTrigRecTPC; + GPUTRDTrack* tracksOutRaw = mTracker->Tracks(); + std::vector<unsigned int> trackIdxArray(mTracker->NTracks()); // track indices sorted by trigger record index + std::iota(trackIdxArray.begin(), trackIdxArray.end(), 0); + std::sort(trackIdxArray.begin(), trackIdxArray.end(), [tracksOutRaw](int lhs, int rhs) { return tracksOutRaw[lhs].getCollisionId() < tracksOutRaw[rhs].getCollisionId(); }); + + int nTrackletsAttached = 0; // only used for debug information + int nTracksFailedTPCTRDRefit = 0; + int nTracksFailedITSTPCTRDRefit = 0; + for (int iTrk = 0; iTrk < mTracker->NTracks(); ++iTrk) { + const auto& trdTrack = mTracker->Tracks()[trackIdxArray[iTrk]]; + if (trdTrack.getCollisionId() < 0) { + // skip tracks without TRD tracklets (the collision ID for the TRD tracks is initialized to -1 and only changed if a tracklet is attached to the track) + continue; + } + if (mStrict && (trdTrack.getIsAmbiguous() || trdTrack.getReducedChi2() > mTracker->Param().rec.trd.chi2StrictCut)) { + // skip tracks which have another hypothesis close to the best one or which do are above strict chi2 threshold + continue; + } + nTrackletsAttached += trdTrack.getNtracklets(); + auto trackGID = trdTrack.getRefGlobalTrackId(); + if (trackGID.includesDet(GTrackID::Source::ITS)) { + // this track is from an ITS-TPC seed + tracksOutITSTPC.push_back(trdTrack); + if (!refitITSTPCTRDTrack(tracksOutITSTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()], &inputTracks)) { + tracksOutITSTPC.pop_back(); + ++nTracksFailedITSTPCTRDRefit; + continue; + } + if (mUseMC) { + fillMCTruthInfo(trdTrack, itstpcTrackLabels[trackGID], trdLabelsITSTPC, matchLabelsITSTPC, inputTracks.getTRDTrackletsMCLabels()); + } + } else { + // this track is from a TPC-only seed + tracksOutTPC.push_back(trdTrack); + if (!refitTPCTRDTrack(tracksOutTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()], &inputTracks)) { + tracksOutTPC.pop_back(); + ++nTracksFailedTPCTRDRefit; + continue; + } + if (mUseMC) { + fillMCTruthInfo(trdTrack, tpcTrackLabels[trackGID], trdLabelsTPC, matchLabelsTPC, inputTracks.getTRDTrackletsMCLabels()); + } + } + } + + fillTrackTriggerRecord(tracksOutITSTPC, trackTrigRecITSTPC, tmpInputContainer->mTriggerRecords); + fillTrackTriggerRecord(tracksOutTPC, trackTrigRecTPC, tmpInputContainer->mTriggerRecords); + + LOGF(INFO, "The TRD tracker found %lu tracks from TPC seeds and %lu tracks from ITS-TPC seeds and attached in total %i tracklets out of %i", + tracksOutTPC.size(), tracksOutITSTPC.size(), nTrackletsAttached, mChainTracking->mIOPtrs.nTRDTracklets); + LOGF(INFO, "Number of tracks failed in the refit: TPC-TRD (%i), ITS-TPC-TRD (%i)", nTracksFailedTPCTRDRefit, nTracksFailedITSTPCTRDRefit); + + uint32_t ss = o2::globaltracking::getSubSpec(mStrict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, mTrkMask)) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe}, tracksOutITSTPC); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe}, trackTrigRecITSTPC); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0, Lifetime::Timeframe}, matchLabelsITSTPC); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe}, trdLabelsITSTPC); + } + } + if (GTrackID::includesSource(GTrackID::Source::TPC, mTrkMask)) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_TPC", ss, Lifetime::Timeframe}, tracksOutTPC); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_TPC", ss, Lifetime::Timeframe}, trackTrigRecTPC); + if (mUseMC) { + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC", ss, Lifetime::Timeframe}, matchLabelsTPC); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss, Lifetime::Timeframe}, trdLabelsTPC); + } + } mTimer.Stop(); } +bool TRDGlobalTracking::refitITSTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globaltracking::RecoContainer* recoCont) +{ + auto propagator = o2::base::Propagator::Instance(); + + // refit ITS-TPC-TRD track outwards to outermost TRD space point (start with ITS outer track parameters) + auto& outerParam = trk.getOuterParam(); + const auto trkITS = mITSTracksArray[recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId())[GTrackID::ITS]]; + outerParam = trkITS.getParamOut(); + float chi2Out = 0; + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId())[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + if (retVal < 0) { + LOG(DEBUG) << "TPC refit outwards failed"; + return false; + } + if (!refitTRDTrack(trk, chi2Out, false)) { + LOG(DEBUG) << "TRD refit outwards failed"; + return false; + } + + // refit ITS-TPC-TRD track inwards to innermost ITS cluster + // here we also calculate the LT integral for matching to TOF + float chi2In = 0.f; + if (!refitTRDTrack(trk, chi2In, true)) { + LOG(DEBUG) << "TRD refit inwards failed"; + return false; + } + auto posStart = trk.getXYZGlo(); + retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId())[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit + if (retVal < 0) { + LOG(DEBUG) << "TPC refit inwards failed"; + return false; + } + auto posEnd = trk.getXYZGlo(); + // account path integrals + float dX = posEnd.x() - posStart.x(), dY = posEnd.y() - posStart.y(), dZ = posEnd.z() - posStart.z(), d2XY = dX * dX + dY * dY; + if (std::abs(o2::base::Propagator::Instance()->getNominalBz()) > 0.01) { // circular arc = 2*R*asin(dXY/2R) + float b[3]; + o2::math_utils::Point3D<float> posAv(0.5 * (posEnd.x() + posStart.x()), 0.5 * (posEnd.y() + posStart.y()), 0.5 * (posEnd.z() + posStart.z())); + propagator->getFieldXYZ(posAv, b); + float curvH = std::abs(0.5f * trk.getCurvature(b[2])), arcXY = 1. / curvH * std::asin(curvH * std::sqrt(d2XY)); + d2XY = arcXY * arcXY; + } + auto lInt = std::sqrt(d2XY + dZ * dZ); + trk.getLTIntegralOut().addStep(lInt, trk.getP2Inv()); + // trk.getLTIntegralOut().addX2X0(lInt * mTPCmeanX0Inv); // do we need to account for the material budget here? probably + int nClRefit = 0; + int nCl = trkITS.getNumberOfClusters(); + auto geom = o2::its::GeometryTGeo::Instance(); + int clEntry = trkITS.getFirstClusterEntry(); + + for (int icl = 0; icl < nCl; icl++) { + const auto& clus = mITSClustersArray[mITSTrackClusIdx[clEntry++]]; + float alpha = geom->getSensorRefAlpha(clus.getSensorID()); + float x = clus.getX(); + if (!trk.rotate(alpha) || + // note: here we also calculate the L,T integral (in the inward direction, but this is irrelevant) + // note: we should eventually use TPC pid in the refit (TODO) + // note: since we are at small R, we can use field BZ component at origin rather than 3D field + !propagator->propagateToX(trk, x, propagator->getNominalBz(), + o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE, &trk.getLTIntegralOut())) { + break; + } + chi2In += trk.getPredictedChi2(clus); + if (!trk.update(clus)) { + break; + } + nClRefit++; + } + if (nClRefit != nCl) { + LOG(DEBUG) << "ITS refit inwards failed"; + return false; + } + // We need to update the LTOF integral by the distance to the "primary vertex" + // We want to leave the track at the the position of its last update, so we do a fast propagation on the TrackPar copy of trfit, + // and since for the LTOF calculation the material effects are irrelevant, we skip material corrections + const o2::dataformats::VertexBase vtxDummy; // at the moment using dummy vertex: TODO use MeanVertex constraint instead + o2::track::TrackPar trkPar(trk); + if (!propagator->propagateToDCA(vtxDummy.getXYZ(), trkPar, propagator->getNominalBz(), + o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, &trk.getLTIntegralOut())) { + LOG(ERROR) << "LTOF integral might be incorrect"; + } + return true; +} + +bool TRDGlobalTracking::refitTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globaltracking::RecoContainer* recoCont) +{ + auto propagator = o2::base::Propagator::Instance(); + + // refit TPC-TRD track outwards toward outermost TRD space point + auto& outerParam = trk.getOuterParam(); + outerParam = trk; + float chi2Out = 0; + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId())[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + if (retVal < 0) { + LOG(DEBUG) << "TPC refit outwards failed"; + return false; + } + if (!refitTRDTrack(trk, chi2Out, false)) { + LOG(DEBUG) << "TRD refit outwards failed"; + return false; + } + + // refit TPC-TRD track inwards toward inner TPC radius + float chi2In = 0.f; + if (!refitTRDTrack(trk, chi2In, true)) { + LOG(DEBUG) << "TRD refit inwards failed"; + return false; + } + auto posStart = trk.getXYZGlo(); + retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId())[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit + if (retVal < 0) { + LOG(DEBUG) << "TPC refit inwards failed"; + return false; + } + auto posEnd = trk.getXYZGlo(); + // account path integrals + float dX = posEnd.x() - posStart.x(), dY = posEnd.y() - posStart.y(), dZ = posEnd.z() - posStart.z(), d2XY = dX * dX + dY * dY; + if (std::abs(o2::base::Propagator::Instance()->getNominalBz()) > 0.01) { // circular arc = 2*R*asin(dXY/2R) + float b[3]; + o2::math_utils::Point3D<float> posAv(0.5 * (posEnd.x() + posStart.x()), 0.5 * (posEnd.y() + posStart.y()), 0.5 * (posEnd.z() + posStart.z())); + propagator->getFieldXYZ(posAv, b); + float curvH = std::abs(0.5f * trk.getCurvature(b[2])), arcXY = 1. / curvH * std::asin(curvH * std::sqrt(d2XY)); + d2XY = arcXY * arcXY; + } + auto lInt = std::sqrt(d2XY + dZ * dZ); + trk.getLTIntegralOut().addStep(lInt, trk.getP2Inv()); + // trk.getLTIntegralOut().addX2X0(lInt * mTPCmeanX0Inv); // do we need to account for the material budget here? probably? + + if (!propagator->PropagateToXBxByBz(trk, o2::constants::geom::XTPCInnerRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE, &trk.getLTIntegralOut())) { + LOG(INFO) << "Final propagation to inner TPC radius failed (not removing the track because of this)"; + } + propagator->estimateLTFast(trk.getLTIntegralOut(), trk); // guess about initial value for the track integral from the origin + return true; +} + +bool TRDGlobalTracking::refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards) +{ + auto propagator = o2::base::Propagator::Instance(); + int lyStart = inwards ? NLAYER - 1 : 0; + int direction = inwards ? -1 : 1; + int lyEnd = inwards ? -1 : NLAYER; + o2::track::TrackParCov* trkParam = inwards ? &trk : &trk.getOuterParam(); + o2::track::TrackLTIntegral* tofL = inwards ? &trk.getLTIntegralOut() : nullptr; + for (int iLy = lyStart; iLy != lyEnd; iLy += direction) { + int trkltId = trk.getTrackletIndex(iLy); + if (trkltId < 0) { + continue; + } + int trkltDet = mTrackletsRaw[trkltId].getDetector(); + int trkltSec = trkltDet / (NLAYER * NSTACK); + if (trkltSec != o2::math_utils::angle2Sector(trkParam->getAlpha())) { + if (!trkParam->rotate(o2::math_utils::sector2Angle(trkltSec))) { + LOGF(DEBUG, "Track at alpha=%.2f could not be rotated in tracklet coordinate system with alpha=%.2f", trkParam->getAlpha(), o2::math_utils::sector2Angle(trkltSec)); + return false; + } + } + if (!propagator->PropagateToXBxByBz(*trkParam, mTrackletsCalib[trkltId].getX(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE, tofL)) { + LOGF(DEBUG, "Track propagation failed in layer %i (pt=%f, xTrk=%f, xToGo=%f)", iLy, trkParam->getPt(), trkParam->getX(), mTrackletsCalib[trkltId].getX()); + return false; + } + const PadPlane* pad = Geometry::instance()->getPadPlane(trkltDet); + float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees + float tiltCorrUp = tilt * (mTrackletsCalib[trkltId].getZ() - trkParam->getZ()); + float zPosCorrUp = mTrackletsCalib[trkltId].getZ() + mRecoParam.getZCorrCoeffNRC() * trkParam->getTgl(); + float padLength = pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()); + if (!((trkParam->getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trkParam->getZ()) < padLength))) { + tiltCorrUp = 0.f; + } + + std::array<float, 2> trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp, zPosCorrUp}; + std::array<float, 3> trkltCovUp; + mRecoParam.recalcTrkltCov(tilt, trkParam->getSnp(), pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()), trkltCovUp); + + chi2 += trkParam->getPredictedChi2(trkltPosUp, trkltCovUp); + if (!trkParam->update(trkltPosUp, trkltCovUp)) { + LOGF(DEBUG, "Failed to update track with space point in layer %i", iLy); + return false; + } + } + return true; +} + void TRDGlobalTracking::endOfStream(EndOfStreamContext& ec) { LOGF(INFO, "TRD global tracking total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC) +DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, GTrackID::mask_t src, bool trigRecFilterActive, bool strict) { - std::vector<InputSpec> inputs; std::vector<OutputSpec> outputs; - inputs.emplace_back("tpcitstrack", "GLO", "TPCITS", 0, Lifetime::Timeframe); - inputs.emplace_back("trdtracklets", o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe); - inputs.emplace_back("trdtriggerrec", o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe); + uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); + std::shared_ptr<DataRequest> dataRequest = std::make_shared<DataRequest>(); + if (strict) { + dataRequest->setMatchingInputStrict(); + } + auto trkSrc = src; + trkSrc |= GTrackID::getSourcesMask("TPC"); + dataRequest->requestClusters(GTrackID::getSourcesMask("TRD"), useMC); + dataRequest->requestTPCClusters(false); // only needed for refit, don't care about labels + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, src)) { + // ITS clusters are only needed if we match to ITS-TPC tracks + dataRequest->requestITSClusters(false); // only needed for refit, don't care about labels + trkSrc |= GTrackID::getSourcesMask("ITS"); + } + dataRequest->requestTracks(trkSrc, useMC); + auto& inputs = dataRequest->inputs; + - if (useMC) { - LOG(FATAL) << "MC usage must be disabled for this workflow, since it is not yet implemented"; - //inputs.emplace_back("itstracklabel", "GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); - //inputs.emplace_back("tpctracklabel", "GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, src)) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe); + } + } + if (GTrackID::includesSource(GTrackID::Source::TPC, src)) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_TPC", ss, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_TPC", ss, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC", ss, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss, Lifetime::Timeframe); + } + if (trigRecFilterActive) { + LOG(ERROR) << "Matching to TPC-only tracks requested, but IR without ITS contribution are filtered out. This does not lead to a crash, but it deteriorates the matching efficiency."; + } } - outputs.emplace_back(o2::header::gDataOriginTRD, "MATCHTRD", 0, Lifetime::Timeframe); + std::string processorName = o2::utils::Str::concat_string("trd-globaltracking", GTrackID::getSourcesNames(src)); + std::replace(processorName.begin(), processorName.end(), ',', '_'); return DataProcessorSpec{ - "trd-globaltracking", + processorName, inputs, outputs, - AlgorithmSpec{adaptFromTask<TRDGlobalTracking>(useMC)}, - Options{}}; + AlgorithmSpec{adaptFromTask<TRDGlobalTracking>(useMC, dataRequest, src, trigRecFilterActive, strict)}, + Options{{"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; } } // namespace trd diff --git a/Detectors/TRD/workflow/src/TRDTrackWriterSpec.cxx b/Detectors/TRD/workflow/src/TRDTrackWriterSpec.cxx deleted file mode 100644 index f42af52207f57..0000000000000 --- a/Detectors/TRD/workflow/src/TRDTrackWriterSpec.cxx +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TRDTrackWriterSpec.cxx - -#include <vector> -#include "GPUO2Interface.h" -#include "GPUTRDDef.h" -#include "GPUTRDTrack.h" - -#include "DPLUtils/MakeRootTreeWriterSpec.h" - -using namespace o2::framework; -using namespace o2::gpu; - -namespace o2 -{ -namespace trd -{ -template <typename T> -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; - -DataProcessorSpec getTRDTrackWriterSpec(bool useMC) -{ - // TODO: not clear if the writer is supposed to write MC labels at some point - // this is just a dummy definition for the template branch definition below - // define the correct type and the input specs - using LabelsType = std::vector<int>; - // force, this will disable the branch for now, can be adjusted in the future - useMC = false; - - // A spectator to store the size of the data array for the logger below - auto tracksSize = std::make_shared<int>(); - auto tracksLogger = [tracksSize](std::vector<GPUTRDTrack> const& tracks) { - *tracksSize = tracks.size(); - }; - - return MakeRootTreeWriterSpec("trd-track-writer", - "trdtracks.root", - "tracksTRD", - BranchDefinition<std::vector<GPUTRDTrack>>{InputSpec{"tracks", o2::header::gDataOriginTRD, "MATCHTRD", 0}, - "tracks", - "tracks-branch-name", - 1, - tracksLogger}, - // NOTE: this branch template is to show how the conditional MC labels can - // be defined, the '0' disables the branch for the moment - BranchDefinition<LabelsType>{InputSpec{"matchtpclabels", "GLO", "SOME_LABELS", 0}, - "labels", - (useMC ? 1 : 0), // one branch if mc labels enabled - "labels-branch-name"})(); -} - -} // namespace trd -} // namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDTrackingWorkflow.cxx b/Detectors/TRD/workflow/src/TRDTrackingWorkflow.cxx deleted file mode 100644 index 4b60307680434..0000000000000 --- a/Detectors/TRD/workflow/src/TRDTrackingWorkflow.cxx +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TRDTrackingWorkflow.cxx - -#include <vector> - -#include "Framework/WorkflowSpec.h" -#include "GlobalTrackingWorkflow/TrackTPCITSReaderSpec.h" -#include "TRDWorkflow/TRDTrackletReaderSpec.h" -#include "TRDWorkflow/TRDGlobalTrackingSpec.h" -#include "TRDWorkflow/TRDTrackWriterSpec.h" - -namespace o2 -{ -namespace trd -{ - -framework::WorkflowSpec getTRDTrackingWorkflow(bool disableRootInp, bool disableRootOut) -{ - framework::WorkflowSpec specs; - bool useMC = false; - if (!disableRootInp) { - specs.emplace_back(o2::globaltracking::getTrackTPCITSReaderSpec(useMC)); - specs.emplace_back(o2::trd::getTRDTrackletReaderSpec(useMC)); - } - - specs.emplace_back(o2::trd::getTRDGlobalTrackingSpec(useMC)); - - if (!disableRootOut) { - specs.emplace_back(o2::trd::getTRDTrackWriterSpec(useMC)); - } - return specs; -} - -} // namespace trd -} // namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDTrackletReaderSpec.cxx b/Detectors/TRD/workflow/src/TRDTrackletReaderSpec.cxx deleted file mode 100644 index 2f29405c61564..0000000000000 --- a/Detectors/TRD/workflow/src/TRDTrackletReaderSpec.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TRDTrackletReaderSpec.cxx - -#include "TRDWorkflow/TRDTrackletReaderSpec.h" - -#include "Headers/DataHeader.h" -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace trd -{ - -void TRDTrackletReader::init(InitContext& ic) -{ - // get the option from the init context - LOG(INFO) << "Init TRD tracklet reader!"; - mInFileName = ic.options().get<std::string>("trd-tracklet-infile"); - mInTreeName = ic.options().get<std::string>("treename"); - connectTree(mInFileName); -} - -void TRDTrackletReader::connectTree(const std::string& filename) -{ - mTree.reset(nullptr); // in case it was already loaded - mFile.reset(TFile::Open(filename.c_str())); - assert(mFile && !mFile->IsZombie()); - mTree.reset((TTree*)mFile->Get(mInTreeName.c_str())); - assert(mTree); - mTree->SetBranchAddress("Tracklet", &mTrackletsPtr); - mTree->SetBranchAddress("TrackTrg", &mTriggerRecordsPtr); - if (mUseMC) { - LOG(FATAL) << "MC information not yet included for TRD tracklets"; - } - LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; -} - -void TRDTrackletReader::run(ProcessingContext& pc) -{ - auto currEntry = mTree->GetReadEntry() + 1; - assert(currEntry < mTree->GetEntries()); // this should not happen - mTree->GetEntry(currEntry); - LOG(INFO) << "Pushing " << mTriggerRecords.size() << " TRD trigger records at entry " << currEntry; - LOG(INFO) << "Pushing " << mTracklets.size() << " TRD tracklets for these trigger records"; - - pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe}, mTracklets); - pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe}, mTriggerRecords); - if (mUseMC) { - LOG(FATAL) << "MC information not yet included for TRD tracklets"; - } - - if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - } -} - -DataProcessorSpec getTRDTrackletReaderSpec(bool useMC) -{ - std::vector<OutputSpec> outputs; - outputs.emplace_back(o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe); - if (useMC) { - LOG(FATAL) << "MC information not yet included for TRD tracklets"; - } - - return DataProcessorSpec{ - "TRDTrackletReader", - Inputs{}, - outputs, - AlgorithmSpec{adaptFromTask<TRDTrackletReader>(useMC)}, - Options{ - {"trd-tracklet-infile", VariantType::String, "trdtracklets.root", {"Name of the input file"}}, - {"treename", VariantType::String, "o2sim", {"Name of top-level TTree"}}, - }}; -} - -} // namespace trd -} // namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDTrackletTransformerSpec.cxx b/Detectors/TRD/workflow/src/TRDTrackletTransformerSpec.cxx new file mode 100644 index 0000000000000..49d979a1d37df --- /dev/null +++ b/Detectors/TRD/workflow/src/TRDTrackletTransformerSpec.cxx @@ -0,0 +1,137 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <gsl/span> + +#include "TRDWorkflow/TRDTrackletTransformerSpec.h" + +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "CommonDataFormat/IRFrame.h" + +using namespace o2::framework; +using namespace o2::globaltracking; + +namespace o2 +{ +namespace trd +{ + +void TRDTrackletTransformerSpec::init(o2::framework::InitContext& ic) +{ + LOG(INFO) << "Initializing tracklet transformer"; +} + +void TRDTrackletTransformerSpec::run(o2::framework::ProcessingContext& pc) +{ + LOG(INFO) << "Running tracklet transformer"; + + o2::globaltracking::RecoContainer inputData; + inputData.collectData(pc, *mDataRequest); + + //auto tracklets = inputData.getTRDTracklets(); + //auto trigRecs = inputData.getTRDTriggerRecords(); + + auto tracklets = pc.inputs().get<gsl::span<Tracklet64>>("trdtracklets"); + auto trigRecs = pc.inputs().get<gsl::span<TriggerRecord>>("trdtriggerrec"); + + std::vector<CalibratedTracklet> calibratedTracklets(tracklets.size()); + + std::vector<char> trigRecBitfield(trigRecs.size()); // flag TRD IR with ITS data (std::vector<bool> platform dependend) + int nTrackletsTransformed = 0; + + if (mTrigRecFilterActive) { + const auto irFrames = inputData.getIRFramesITS(); + int lastMatchedIdx = 0; // ITS IR are sorted in time and do not overlap + for (const auto& irFrame : irFrames) { + for (int j = lastMatchedIdx; j < trigRecs.size(); ++j) { + const auto& trigRec = trigRecs[j]; + if (trigRec.getBCData() >= irFrame.getMin()) { + if (trigRec.getBCData() <= irFrame.getMax()) { + // TRD interaction record inside ITS frame + trigRecBitfield[j] = 1; + lastMatchedIdx = j; + } else { + // too late, also the higher trigger records won't match + break; + } + } + } + LOGF(DEBUG, "ITS IR Frame start: %li, end: %li", irFrame.getMin().toLong(), irFrame.getMax().toLong()); + } + /* + // for debugging: print TRD trigger times which are accepted and which are filtered out + for (int j = 0; j < trigRecs.size(); ++j) { + const auto& trigRec = trigRecs[j]; + if (!trigRecBitfield[j]) { + LOGF(DEBUG, "Could not find ITS info for TRD trigger %i: %li", j, trigRec.getBCData().toLong()); + } else { + LOGF(DEBUG, "Found ITS info for TRD trigger %i: %li", j, trigRec.getBCData().toLong()); + } + } + */ + } else { + // fill bitmask with 1 + std::fill(trigRecBitfield.begin(), trigRecBitfield.end(), 1); + } + + if (mTrigRecFilterActive) { + // skip tracklets from TRD triggers without ITS data + for (int iTrig = 0; iTrig < trigRecs.size(); ++iTrig) { + if (!trigRecBitfield[iTrig]) { + continue; + } else { + const auto& trigRec = trigRecs[iTrig]; + for (int iTrklt = trigRec.getFirstTracklet(); iTrklt < trigRec.getFirstTracklet() + trigRec.getNumberOfTracklets(); ++iTrklt) { + calibratedTracklets[iTrklt] = mTransformer.transformTracklet(tracklets[iTrklt]); + ++nTrackletsTransformed; + } + } + } + } else { + // transform all tracklets + for (int iTrklt = 0; iTrklt < tracklets.size(); ++iTrklt) { + calibratedTracklets[iTrklt] = mTransformer.transformTracklet(tracklets[iTrklt]); + ++nTrackletsTransformed; + } + } + + LOGF(INFO, "Found %lu tracklets. Applied filter for ITS IR frames: %i. Transformed %i tracklets.", tracklets.size(), mTrigRecFilterActive, nTrackletsTransformed); + + pc.outputs().snapshot(Output{"TRD", "CTRACKLETS", 0, Lifetime::Timeframe}, calibratedTracklets); + pc.outputs().snapshot(Output{"TRD", "TRIGRECMASK", 0, Lifetime::Timeframe}, trigRecBitfield); +} + +o2::framework::DataProcessorSpec getTRDTrackletTransformerSpec(bool trigRecFilterActive) +{ + std::shared_ptr<DataRequest> dataRequest = std::make_shared<DataRequest>(); + if (trigRecFilterActive) { + dataRequest->requestIRFramesITS(); + } + auto& inputs = dataRequest->inputs; + inputs.emplace_back("trdtracklets", "TRD", "TRACKLETS", 0, Lifetime::Timeframe); + inputs.emplace_back("trdtriggerrec", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); + + std::vector<OutputSpec> outputs; + outputs.emplace_back("TRD", "CTRACKLETS", 0, Lifetime::Timeframe); + outputs.emplace_back("TRD", "TRIGRECMASK", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "TRDTRACKLETTRANSFORMER", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<TRDTrackletTransformerSpec>(dataRequest, trigRecFilterActive)}, + Options{}}; +} + +} //end namespace trd +} //end namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDTrackletTransformerWorkflow.cxx b/Detectors/TRD/workflow/src/TRDTrackletTransformerWorkflow.cxx new file mode 100644 index 0000000000000..f9faaeb2b8e30 --- /dev/null +++ b/Detectors/TRD/workflow/src/TRDTrackletTransformerWorkflow.cxx @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDWorkflow/TRDTrackletTransformerSpec.h" +#include "TRDWorkflowIO/TRDCalibratedTrackletWriterSpec.h" +#include "TRDWorkflowIO/TRDTrackletReaderSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" + +using namespace o2::framework; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"Disable MC labels"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"filter-trigrec", o2::framework::VariantType::Bool, false, {"ignore interaction records without ITS data"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + auto trigRecFilterActive = configcontext.options().get<bool>("filter-trigrec"); + // MC labels are passed through for the global tracking downstream + // in case ROOT output is requested the tracklet labels are duplicated + bool useMC = !configcontext.options().get<bool>("disable-mc"); + + WorkflowSpec spec; + + if (!configcontext.options().get<bool>("disable-root-input")) { + // cannot use InputHelper here, since we have to create the calibrated tracklets first + spec.emplace_back(o2::trd::getTRDTrackletReaderSpec(useMC, false)); + } + + if (trigRecFilterActive) { + o2::globaltracking::InputHelper::addInputSpecsIRFramesITS(configcontext, spec); + } + + spec.emplace_back(o2::trd::getTRDTrackletTransformerSpec(trigRecFilterActive)); + + if (!configcontext.options().get<bool>("disable-root-output")) { + spec.emplace_back(o2::trd::getTRDCalibratedTrackletWriterSpec(useMC)); + } + + return spec; +} diff --git a/Detectors/TRD/workflow/src/TRDTrackletWriterSpec.cxx b/Detectors/TRD/workflow/src/TRDTrackletWriterSpec.cxx deleted file mode 100644 index ee8d4ff93ef7b..0000000000000 --- a/Detectors/TRD/workflow/src/TRDTrackletWriterSpec.cxx +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_TRDTRAPSIMULATORTRACKLETWRITER_H -#define O2_TRDTRAPSIMULATORTRACKLETWRITER_H - -#include "Framework/DataProcessorSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "Framework/InputSpec.h" -#include "TRDWorkflow/TRDTrackletWriterSpec.h" -#include "TRDBase/Digit.h" -#include <SimulationDataFormat/MCTruthContainer.h> -#include "TRDBase/MCLabel.h" -#include "DataFormatsTRD/TriggerRecord.h" -#include "DataFormatsTRD/Tracklet64.h" - -#include <fstream> -#include <iostream> - -using namespace o2::framework; - -namespace o2 -{ -namespace trd -{ - -template <typename T> -using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; - -o2::framework::DataProcessorSpec getTRDTrackletWriterSpec() -{ - // using InputSpec = framework::InputSpec; - using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - /* int producejson=1; - if(producejson){ - //write tracklets in json format for Samesh javascript ui - //probably only going to be for deubgging. - //filename format is : E#.sector#.stack#.json E=Eventnumber(nominal) ... will use timestamp - LOG(info) << " now to produce json"; - ofstream output("E15.0.1.json"); - output << " 10 " << endl; - }*/ - //LOG(info) << "before writing out the tracklet size is " << Tracklet->size(); - return MakeRootTreeWriterSpec("TRDTrkltWrt", - "trdtracklets.root", - "o2sim", - 1, - BranchDefinition<std::vector<o2::trd::Tracklet64>>{InputSpec{"tracklets", "TRD", "TRACKLETS"}, "Tracklet"}, - //BranchDefinition<o2::dataformats::MCTruthContainer<o2::trd::MCLabel>>{InputSpec{"trklabels", "TRD", "TRKLABELS"}, "TRKLabels"}, - BranchDefinition<std::vector<o2::trd::TriggerRecord>>{InputSpec{"tracklettrigs", "TRD", "TRKTRGRD"}, "TrackTrg"})(); -}; - -} // end namespace trd -} // end namespace o2 - -#endif // O2_TRDTRAPSIMULATORTRACKLETWRITER_H diff --git a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx index 00079d0fce8c9..f163ffa1c1850 100644 --- a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx @@ -1,130 +1,77 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -//#include "Framework/runDataProcessing.h" #include "TRDWorkflow/TRDTrapSimulatorSpec.h" -#include <cstdlib> -#include <thread> // to detect number of hardware threads -#include <string> -#include <sstream> -#include <iostream> -#include <fstream> -#include <cmath> -#include <unistd.h> // for getppid #include <chrono> +#include <optional> #include <gsl/span> -#include <iostream> -#include <fstream> -#include "TChain.h" +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +#include "TFile.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" -#include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" -#include "Framework/Task.h" -#include "Headers/DataHeader.h" -#include "TStopwatch.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext -#include "TChain.h" -#include <SimulationDataFormat/MCCompLabel.h> -#include <SimulationDataFormat/ConstMCTruthContainer.h> #include "fairlogger/Logger.h" #include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "TRDSimulation/TrapSimulator.h" -#include "TRDSimulation/Digitizer.h" -#include "TRDSimulation/Detector.h" -#include "TRDBase/Digit.h" // for the Digit type -#include "TRDBase/FeeParam.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" #include "TRDBase/Calibrations.h" -#include "TRDSimulation/TrapSimulator.h" +#include "TRDSimulation/TRDSimParams.h" +#include "DataFormatsTRD/Digit.h" #include "DataFormatsTRD/TriggerRecord.h" -#include "DataFormatsTRD/LinkRecord.h" -#include "DataFormatsTRD/Tracklet64.h" -#include "DataFormatsTRD/RawData.h" - -//#ifdef WITH_OPENMP -//#include <omp.h> -//#endif ci is failing on this, sort out another time. using namespace o2::framework; -using namespace std::placeholders; // this is for std::bind to build the comparator for the indexed sort of digits. namespace o2 { namespace trd { -TrapConfig* TRDDPLTrapSimulatorTask::getTrapConfig() -{ - // return an existing TRAPconfig or load it from the CCDB - // in case of failure, a default TRAPconfig is created - LOG(debug) << "start of gettrapconfig"; - if (mTrapConfig) { - LOG(debug) << "mTrapConfig is valid : 0x" << std::hex << mTrapConfig << std::dec; - return mTrapConfig; - } else { - LOG(debug) << "mTrapConfig is invalid : 0x" << std::hex << mTrapConfig << std::dec; - - //// bypass pulling in the traditional default trapconfigs from ccdb, will sort out latert - // try to load the requested configuration - loadTrapConfig(); - //calib. - LOG(info) << "using TRAPconfig :\"" << mTrapConfig->getConfigName().c_str() << "\".\"" << mTrapConfig->getConfigVersion().c_str() << "\""; - - // we still have to load the gain tables - // if the gain filter is active - return mTrapConfig; - } // end of else from if mTrapConfig -} +using namespace constants; - -void TRDDPLTrapSimulatorTask::loadTrapConfig() +void TRDDPLTrapSimulatorTask::initTrapConfig() { - // try to load the specified configuration from the CCDB - - LOG(info) << "looking for TRAPconfig " << mTrapConfigName; - auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); + //ccdbmgr.setURL("http://localhost:8080"); ccdbmgr.setTimestamp(mRunNumber); - //default is : mTrapConfigName="dcf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549"; - mTrapConfigName = "c"; - mTrapConfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD_test/TrapConfig2020/" + mTrapConfigName); - if (mTrapConfig == nullptr) { - //failed to find or open or connect or something to get the trapconfig from the ccdb. - //first check the directory listing. - LOG(warn) << " failed to get trapconfig from ccdb with name : " << mTrapConfigName; + mTrapConfig = ccdbmgr.get<o2::trd::TrapConfig>("TRD/TrapConfig/" + mTrapConfigName); + + if (mEnableTrapConfigDump) { + mTrapConfig->DumpTrapConfig2File("run3trapconfig_dump"); + } + + if (mTrapConfig->getConfigName() == "" && mTrapConfig->getConfigVersion() == "") { + //some trap configs dont have config name and version set, in those cases, just show the file name used. + LOG(info) << "using TRAPconfig: " << mTrapConfigName; } else { - //TODO figure out how to get the debug level from logger and only do this for debug option to --severity debug (or what ever the command actualy is) - if (mEnableTrapConfigDump) { - mTrapConfig->DumpTrapConfig2File("run3trapconfig_dump"); - } + LOG(info) << "using TRAPconfig :\"" << mTrapConfig->getConfigName().c_str() << "\".\"" << mTrapConfig->getConfigVersion().c_str() << "\""; } } void TRDDPLTrapSimulatorTask::setOnlineGainTables() { - const int nDets = 540; //Geometry::Ndet(); - const int nMcms = Geometry::MCMmax(); - const int nChs = Geometry::ADCmax(); //check FGBY from trapconfig. //check the input parameter of trd-onlinegaincorrection. //warn if you have chosen a trapconfig with gaincorrections but chosen not to use them. if (mEnableOnlineGainCorrection) { if (mTrapConfig->getTrapReg(TrapConfig::kFGBY) == 0) { LOG(warn) << "you have asked to do online gain calibrations but the selected trap config does not have FGBY enabled, so modifying trapconfig to conform to your command line request. OnlineGains will be 1, i.e. no effect."; - for (int iDet = 0; iDet < nDets; ++iDet) { + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { mTrapConfig->setTrapReg(TrapConfig::kFGBY, 1, iDet); } } @@ -132,21 +79,21 @@ void TRDDPLTrapSimulatorTask::setOnlineGainTables() //TODO add some error checking inhere. // gain factors are per MCM // allocate the registers accordingly - for (int ch = 0; ch < nChs; ++ch) { + for (int ch = 0; ch < NADCMCM; ++ch) { TrapConfig::TrapReg_t regFGAN = (TrapConfig::TrapReg_t)(TrapConfig::kFGA0 + ch); TrapConfig::TrapReg_t regFGFN = (TrapConfig::TrapReg_t)(TrapConfig::kFGF0 + ch); mTrapConfig->setTrapRegAlloc(regFGAN, TrapConfig::kAllocByMCM); mTrapConfig->setTrapRegAlloc(regFGFN, TrapConfig::kAllocByMCM); } - for (int iDet = 0; iDet < nDets; ++iDet) { + for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { const int nRobs = Geometry::getStack(iDet) == 2 ? Geometry::ROBmaxC0() : Geometry::ROBmaxC1(); for (int rob = 0; rob < nRobs; ++rob) { - for (int mcm = 0; mcm < nMcms; ++mcm) { + for (int mcm = 0; mcm < NMCMROB; ++mcm) { // set ADC reference voltage mTrapConfig->setTrapReg(TrapConfig::kADCDAC, mCalib->getOnlineGainAdcdac(iDet, rob, mcm), iDet, rob, mcm); // set constants channel-wise - for (int ch = 0; ch < nChs; ++ch) { + for (int ch = 0; ch < NADCMCM; ++ch) { TrapConfig::TrapReg_t regFGAN = (TrapConfig::TrapReg_t)(TrapConfig::kFGA0 + ch); TrapConfig::TrapReg_t regFGFN = (TrapConfig::TrapReg_t)(TrapConfig::kFGF0 + ch); mTrapConfig->setTrapReg(regFGAN, mCalib->getOnlineGainFGAN(iDet, rob, mcm, ch), iDet, rob, mcm); @@ -160,485 +107,215 @@ void TRDDPLTrapSimulatorTask::setOnlineGainTables() } } +void TRDDPLTrapSimulatorTask::processTRAPchips(int& nTracklets, std::vector<Tracklet64>& trackletsAccum, std::array<TrapSimulator, NMCMHCMAX>& trapSimulators, std::vector<short>& digitCounts, std::vector<int>& digitIndices) +{ + // TRAP processing for current half chamber + for (int iTrap = 0; iTrap < NMCMHCMAX; ++iTrap) { + if (!trapSimulators[iTrap].isDataSet()) { + continue; + } + trapSimulators[iTrap].filter(); + trapSimulators[iTrap].tracklet(); + auto trackletsOut = trapSimulators[iTrap].getTrackletArray64(); + nTracklets += trackletsOut.size(); + trackletsAccum.insert(trackletsAccum.end(), trackletsOut.begin(), trackletsOut.end()); + if (mUseMC) { + auto digitCountOut = trapSimulators[iTrap].getTrackletDigitCount(); + digitCounts.insert(digitCounts.end(), digitCountOut.begin(), digitCountOut.end()); + auto digitIndicesOut = trapSimulators[iTrap].getTrackletDigitIndices(); + digitIndices.insert(digitIndices.end(), digitIndicesOut.begin(), digitIndicesOut.end()); + } + trapSimulators[iTrap].reset(); + } +} + void TRDDPLTrapSimulatorTask::init(o2::framework::InitContext& ic) { - mFeeParam = FeeParam::instance(); - mPrintTrackletOptions = ic.options().get<int>("trd-printtracklets"); - mDrawTrackletOptions = ic.options().get<int>("trd-drawtracklets"); - mShowTrackletStats = ic.options().get<int>("show-trd-trackletstats"); mTrapConfigName = ic.options().get<std::string>("trd-trapconfig"); - mDebugRejectedTracklets = ic.options().get<bool>("trd-debugrejectedtracklets"); mEnableOnlineGainCorrection = ic.options().get<bool>("trd-onlinegaincorrection"); mOnlineGainTableName = ic.options().get<std::string>("trd-onlinegaintable"); mRunNumber = ic.options().get<int>("trd-runnum"); mEnableTrapConfigDump = ic.options().get<bool>("trd-dumptrapconfig"); - mDumpTriggerRecords = ic.options().get<bool>("trd-dumptriggerrecords"); - mFixTriggerRecords = ic.options().get<bool>("trd-fixtriggerrecord"); - //Connect to CCDB for all things needing access to ccdb. + //Connect to CCDB for all things needing access to ccdb, trapconfig and online gains auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); mCalib = std::make_unique<Calibrations>(); - mCalib->setCCDBForSimulation(mRunNumber); - getTrapConfig(); + mCalib->getCCDBObjects(mRunNumber); + initTrapConfig(); setOnlineGainTables(); - LOG(info) << "Trap Simulator Device initialised for config : " << mTrapConfigName; -} - -std::string printDigit(o2::trd::Digit& a) -{ - std::string out; - out = a.getRow() + std::string(".") + a.getPad(); // + std::string(".")+ a.getLabelIndex(); - return out; -} - -bool digitindexcompare(unsigned int A, unsigned int B, const std::vector<o2::trd::Digit>& originalDigits) -{ - // sort into ROC:padrow:padcolum - const o2::trd::Digit *a, *b; - a = &originalDigits[A]; - b = &originalDigits[B]; - // timestamps are equal - if (a->getDetector() < b->getDetector()) { - return 1; - } - if (a->getDetector() > b->getDetector()) { - return 0; - } - if (a->getRow() < b->getRow()) { - return 1; - } - if (a->getRow() > b->getRow()) { - return 0; - } - if (a->getPad() < b->getPad()) { - return 0; - } - if (a->getPad() > b->getPad()) { - return 1; - } - return 0; -} - -void TRDDPLTrapSimulatorTask::setTriggerRecord(std::vector<o2::trd::TriggerRecord>& triggerrecord, uint32_t currentrecord, uint64_t recordsize) -{ - // so increment the tracklet trigger records and fill accordingly for the now completed prior triggerrecord. - uint64_t triggerrecordstart = 0; - if (currentrecord == 0) { // for not the first one we can simply look back to the previous one to get the start. - triggerrecordstart = 0; - triggerrecord[currentrecord].setDataRange(triggerrecordstart, recordsize); +#ifdef WITH_OPENMP + int askedThreads = TRDSimParams::Instance().digithreads; + int maxThreads = omp_get_max_threads(); + if (askedThreads < 0) { + mNumThreads = maxThreads; } else { - triggerrecordstart = triggerrecord[currentrecord - 1].getFirstEntry() + triggerrecord[currentrecord - 1].getNumberOfObjects(); - triggerrecord[currentrecord].setDataRange(triggerrecordstart, recordsize - triggerrecordstart); - } -} - -void TRDDPLTrapSimulatorTask::fixTriggerRecords(std::vector<o2::trd::TriggerRecord>& trigRecord) -{ - // Trigger records are coming with an extra one at the end, and the first one blank and the last 2 having the same bunch crossing information. - // This is temporary. - - // take the nth records DataRange, and insert it into the (n-1)th DataRange - // thereby realigning the bunch crossings and dataranges. - // drop the final entry. - - //sanity check -- this is only true if the first range is 0 to 0 - if (trigRecord[0].getFirstEntry() == 0 && trigRecord[0].getNumberOfObjects() == 0) { - for (int i = 0; i < trigRecord.size() - 1; i++) { - trigRecord[i].setDataRange(trigRecord[i + 1].getFirstEntry(), trigRecord[i + 1].getNumberOfObjects()); - } - //now drop the final triggerrecord. - trigRecord.pop_back(); - } else { - LOG(warn) << "TriggerRecord fix requested, but inital TriggerRecord is not 0,0"; + mNumThreads = std::min(maxThreads, askedThreads); } + LOG(info) << "Trap simulation running with " << mNumThreads << " threads "; +#endif } void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) { + // this method steeres the processing of the TRAP simulation LOG(info) << "TRD Trap Simulator Device running over incoming message"; - //#ifdef WITH_OPENMP - // int maxthreads = omp_get_max_threads(); - // mNumThreads = std::min(maxthreads, 8); - // LOG(INFO) << "TRD: Trapping with " << mNumThreads << " threads "; - //#endif - - // get inputs for the TrapSimulator - // the digits are going to be sorted, we therefore need a copy of the vector rather than an object created - // directly on the input data, the output vector however is created directly inside the message - // memory thus avoiding copy by snapshot - auto inputDigits = pc.inputs().get<gsl::span<o2::trd::Digit>>("digitinput"); - std::vector<o2::trd::Digit> msgDigits(inputDigits.begin(), inputDigits.end()); - // auto digits pc.outputs().make<std::vector<o2::trd::Digit>>(Output{"TRD", "TRKDIGITS", 0, Lifetime::Timeframe}, msgDigits.begin(), msgDigits.end()); - auto digitMCLabels = pc.inputs().get<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>("labelinput"); - - // auto rawDataOut = pc.outputs().make<char>(Output{"TRD", "RAWDATA", 0, Lifetime::Timeframe}, 1000); //TODO number is just a place holder until we start using it. - o2::dataformats::MCTruthContainer<o2::MCCompLabel> trackletMCLabels; - - // the returned object is read-only as it refers directly to the underlying raw input data - // need to make a copy because the object might be changed in fixTriggerRecords - auto inputTriggerRecords = pc.inputs().get<gsl::span<o2::trd::TriggerRecord>>("triggerrecords"); - // trigger records to index the 64bit tracklets.yy - std::vector<o2::trd::TriggerRecord> triggerRecords(inputTriggerRecords.begin(), inputTriggerRecords.end()); - // trigger records to index the "raw" data - - uint64_t currentTriggerRecord = 0; - - for (auto& trig : triggerRecords) { - if (mDumpTriggerRecords) { - LOG(info) << "Trigger Record ; " << trig.getFirstEntry() << " --> " << trig.getNumberOfObjects(); - } else { - LOG(debug) << "Trigger Record ; " << trig.getFirstEntry() << " --> " << trig.getNumberOfObjects(); + // input + auto digits = pc.inputs().get<gsl::span<o2::trd::Digit>>("digitinput"); // block of TRD digits + auto triggerRecords = pc.inputs().get<std::vector<o2::trd::TriggerRecord>>("triggerrecords"); // time and number of digits for each collision + LOG(debug) << "Received " << digits.size() << " digits from " << triggerRecords.size() << " collisions"; + + // load MC information if label processing is enabeld + const o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>* lblDigitsPtr = nullptr; + using lblType = std::decay_t<decltype(pc.inputs().get<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(""))>; + std::optional<lblType> lblDigits; + if (mUseMC) { + lblDigits.emplace(pc.inputs().get<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>("labelinput")); // MC labels associated to the input digits + lblDigitsPtr = &lblDigits.value(); + LOG(debug) << "Labels contain " << lblDigitsPtr->getNElements() << " elements with and indexed size of " << lblDigitsPtr->getIndexedSize(); + if (lblDigitsPtr->getIndexedSize() != digits.size()) { + LOG(warn) << "Digits and Labels coming into TrapSimulator are of differing sizes, labels will be jibberish. " << lblDigitsPtr->getIndexedSize() << "!=" << digits.size(); } } - // fix incoming trigger records if requested. - if (mFixTriggerRecords) { - fixTriggerRecords(triggerRecords); - } - - std::vector<o2::trd::TriggerRecord> trackletTriggerRecords = triggerRecords; // copy over the whole thing but we only really want the bunch crossing info. - std::vector<o2::trd::TriggerRecord> rawTriggerRecords = triggerRecords; // as we have the option of having tracklets and/or raw data, we need both triggerrecords. - // of course we dont *actually* need it we could simply walk through all the raw data header to header. - mLinkRecords.reserve(1077 * triggerRecords.size()); // worse case scenario is all links for all events. TODO get 1077 from somewhere. - - //TODO these must be created directly in the output as done at the top of this run method - std::vector<unsigned int> msgDigitsIndex; - msgDigitsIndex.reserve(msgDigits.size()); - - LOG(debug) << "Read in msgDigits with size of : " << msgDigits.size() << " labels contain : " << digitMCLabels.getNElements() << " with and index size of : " << digitMCLabels.getIndexedSize() << " and triggerrecord count of :" << triggerRecords.size(); - if (digitMCLabels.getIndexedSize() != msgDigits.size()) { - LOG(warn) << "Digits and Labels coming into TrapSimulator are of differing sizes, labels will be jibberish. " << digitMCLabels.getIndexedSize() << "!=" << msgDigits.size(); - } - //set up structures to hold the returning tracklets. - std::vector<Tracklet64> trapTracklets; //vector to store the retrieved tracklets from an trapsim object - std::vector<Tracklet64> trapTrackletsAccum; - std::vector<uint32_t> rawdata; - - trapTracklets.reserve(30); - trapTrackletsAccum.reserve(msgDigits.size() / 3); - msgDigitsIndex.reserve(msgDigits.size()); - // worse case scenario is header and single tracklet word, hence 2, for higher tracklet count the factors reduces relative to tracklet count. Remember 3 digits per tracklet. - rawdata.reserve(msgDigits.size() * 2); - - int count = 0; - //make msgDigitsIndex a simple vector of ascending numbers mapping trivially into the msgDigits vector. - for (int i = 0; i < msgDigits.size(); i++) { - msgDigitsIndex.push_back(i); - } - LOG(debug) << "msgdigitsindex is " << msgDigitsIndex.size(); + // output + std::vector<Tracklet64> tracklets; // calculated tracklets + o2::dataformats::MCTruthContainer<o2::MCCompLabel> lblTracklets; // MC labels for the tracklets, taken from the digits which make up the tracklet (duplicates are removed) - auto sortstart = std::chrono::high_resolution_clock::now(); - //sort the digits array TODO refactor this intoa vector index sort and possibly generalise past merely digits. - for (auto& trig : triggerRecords) { - LOG(debug) << " sorting from index: " << trig.getFirstEntry() << " till " << trig.getNumberOfObjects() + trig.getFirstEntry(); - LOG(debug) << "pre sort"; - for (int i = msgDigitsIndex[trig.getFirstEntry()]; i < trig.getNumberOfObjects() + trig.getFirstEntry(); i++) { - LOG(debug) << "i:" << msgDigitsIndex[i]; - } - std::stable_sort(std::begin(msgDigitsIndex) + trig.getFirstEntry(), std::begin(msgDigitsIndex) + trig.getNumberOfObjects() + trig.getFirstEntry(), - [&msgDigits](auto&& PH1, auto&& PH2) { return digitindexcompare(PH1, PH2, msgDigits); }); - LOG(debug) << "post sort"; - for (int i = msgDigitsIndex[trig.getFirstEntry()]; i < trig.getNumberOfObjects() + trig.getFirstEntry(); i++) { - LOG(debug) << "i:" << i << " = " << msgDigitsIndex[i]; - } - LOG(debug) << "*****************************************************************"; - } + auto timeProcessingStart = std::chrono::high_resolution_clock::now(); // measure total processing time - mSortingTime = std::chrono::high_resolution_clock::now() - sortstart; - LOG(debug) << "TRD Digit Sorting took " << mSortingTime.count(); - // sort from triggerRecords.getFirstEntry() to triggerRecords.getFirstEntry()+triggerRecords.getNumberOfObjects(); - //check the incoming triggerrecords: - int triggerrecordcount = 0; + // sort digits by half chamber ID for each collision and keep track in index vector + auto sortStart = std::chrono::high_resolution_clock::now(); + std::vector<unsigned int> digitIdxArray(digits.size()); // digit indices sorted by half chamber ID for each time frame + std::iota(digitIdxArray.begin(), digitIdxArray.end(), 0); for (auto& trig : triggerRecords) { - LOG(debug) << "Trigger Record ; " << triggerrecordcount << " = " << trig.getFirstEntry() << " --> " << trig.getNumberOfObjects(); - triggerrecordcount++; + std::stable_sort(std::begin(digitIdxArray) + trig.getFirstDigit(), std::begin(digitIdxArray) + trig.getNumberOfDigits() + trig.getFirstDigit(), + [&digits](unsigned int i, unsigned int j) { return digits[i].getHCId() < digits[j].getHCId(); }); } - for (auto& trig : trackletTriggerRecords) { - LOG(debug) << "Trigger Tracklet Record ; " << trig.getFirstEntry() << " --> " << trig.getNumberOfObjects(); - } - //print digits to check the sorting. - LOG(info) << " Digits : "; - //for (auto& digit : msgDigits) { - for (auto& digitindex : msgDigitsIndex) { - Digit digit = msgDigits[digitindex]; - LOG(debug) << "sorted digit time:" << digit.getTimeStamp() << " detector:row:pad:rob:mcm ::" - << digit.getDetector() << ":" << digit.getRow() << ":" << digit.getPad() << ":" - << mFeeParam->getROBfromPad(digit.getRow(), digit.getPad()) << ":" - << mFeeParam->getMCMfromPad(digit.getRow(), digit.getPad()) - << " LinkId:" << LinkRecord::getHalfChamberLinkId(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) << "\t\t SM:stack:layer:side " - << digit.getDetector() / 30 << ":" << Geometry::getStack(digit.getDetector()) - << ":" << Geometry::getLayer(digit.getDetector()) << ":" << FeeParam::instance()->getRobSide(mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) - << " with ORI# : " << mFeeParam->getORI(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) - << " within SM ori#:" << mFeeParam->getORIinSM(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())); - } - //accounting variables for various things. - //TODO make them class members, i dont want to fiddle right now though. - int olddetector = -1; - int oldrow = -1; - int oldpad = -1; - int loopindex = 0; - int counttrackletadditions = 0; - int oldsize = 0; - double trackletrate; - unsigned long oldtrackletcount = 0; - mTotalRawWordsWritten = 0; // words written for the raw format of 4x32bits, where 4 can be 2 to 4 depending on # of tracklets in the block. - mOldHalfChamberLinkId = 0; - mNewTrackletHCHeaderHasBeenWritten = false; - - // now to loop over the incoming digits. - auto digitloopstart = std::chrono::high_resolution_clock::now(); - uint64_t digitcounter = 0; - double b = 0; - LOG(debug4) << "now for digit loop "; - for (auto digititerator = msgDigitsIndex.begin(); digititerator != msgDigitsIndex.end() /* && std::distance(msgDigits.begin(),digititerator)<7*/; ++digititerator) { - //in here we have an entire padrow which corresponds to 8 TRAPs. - //while on a single padrow, populate data structures in the 8 trapsimulator. - //on change of padrow - // fireup trapsim, do its thing with each 18 sequence of pads data that already exists inside the class from previous iterations of the loop - LOG(debug) << "Digit iterator is : " << *digititerator; - Digit* digit = &msgDigits[*digititerator]; - double digittime = digit->getTimeStamp(); - int pad = digit->getPad(); - int row = digit->getRow(); - int detector = digit->getDetector(); - int rob = mFeeParam->getROBfromPad(row, pad); - int mcm = mFeeParam->getMCMfromPad(row, pad); - int trdstack = Geometry::getStack(detector); - int trdlayer = Geometry::getLayer(detector); - int fibreside = FeeParam::instance()->getRobSide(rob); - - LOG(debug) << "calculated rob and mcm at top of loop with detector:row:pad:rob:mcm ::" - << detector << ":" << row << ":" << pad << ":" << rob << ":" << mcm - << " LinkId:" << LinkRecord::getHalfChamberLinkId(detector, rob) << "\t\t SM:stack:layer:side " << detector / 30 << ":" << trdstack << ":" << trdlayer << ":" << fibreside - << " with ORI : " << mFeeParam->getORI(detector, rob) << " and within supermodule ori index:" << mFeeParam->getORIinSM(detector, rob); - LOG(debug) << "digit time : " << digittime; - if (digititerator == msgDigitsIndex.begin()) { // first time in loop - oldrow = row; - olddetector = detector; - } - //Are we on a new half chamber ? - if (mOldHalfChamberLinkId != LinkRecord::getHalfChamberLinkId(detector, rob)) { - // hcid= detector*2 + robpos%2; - // new half chamber so add the header to the raw data stream. - buildTrackletHCHeaderd(mTrackletHCHeader, detector, rob, currentTriggerRecord * 42, 4); - //buildTrackletHCHeader(mTrackletHCHeader,sector,stack,layer,side,currentTriggerRecord*42,4); - mOldHalfChamberLinkId = LinkRecord::getHalfChamberLinkId(detector, rob); - // now we have a problem. We must only write the halfchamberheader if a tracklet is written i.e. if the digits for this half chamber actually produce 1 or more tracklets! - mNewTrackletHCHeaderHasBeenWritten = false; - } - //figure out which trigger record from digits we are on - if (digitcounter >= triggerRecords[currentTriggerRecord].getFirstEntry() + triggerRecords[currentTriggerRecord].getNumberOfObjects()) { - //trigger record changed. - //Now we know the ranges so populate the triggerrecord related to the previously block of data. - setTriggerRecord(trackletTriggerRecords, currentTriggerRecord, trapTrackletsAccum.size()); - setTriggerRecord(rawTriggerRecords, currentTriggerRecord, mTotalRawWordsWritten); - currentTriggerRecord++; - LOG(debug) << "changing trigger records : " << currentTriggerRecord; + auto sortTime = std::chrono::high_resolution_clock::now() - sortStart; + + // prepare data structures for accumulating results per collision + std::vector<int> nTracklets(triggerRecords.size()); + std::vector<std::vector<Tracklet64>> trackletsAccum; + trackletsAccum.resize(triggerRecords.size()); + std::vector<std::vector<short>> digitCountsAccum; // holds the number of digits included in each tracklet (therefore has the same number of elements as trackletsAccum) + // digitIndicesAccum holds the global indices of the digits which comprise the tracklets + // with the help of digitCountsAccum one can loop through this vector and find the corresponding digit indices for each tracklet + std::vector<std::vector<int>> digitIndicesAccum; + digitCountsAccum.resize(triggerRecords.size()); + digitIndicesAccum.resize(triggerRecords.size()); + + auto timeParallelStart = std::chrono::high_resolution_clock::now(); + +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNumThreads) +#endif + for (int iTrig = 0; iTrig < triggerRecords.size(); ++iTrig) { + int currHCId = -1; + std::array<TrapSimulator, NMCMHCMAX> trapSimulators{}; //the up to 64 trap simulators for a single half chamber + for (int iDigit = triggerRecords[iTrig].getFirstDigit(); iDigit < (triggerRecords[iTrig].getFirstDigit() + triggerRecords[iTrig].getNumberOfDigits()); ++iDigit) { + const auto& digit = &digits[digitIdxArray[iDigit]]; + if (currHCId < 0) { + currHCId = digit->getHCId(); + } + if (currHCId != digit->getHCId()) { + // we switch to a new half chamber, process all TRAPs of the previous half chamber which contain data + processTRAPchips(nTracklets[iTrig], trackletsAccum[iTrig], trapSimulators, digitCountsAccum[iTrig], digitIndicesAccum[iTrig]); + currHCId = digit->getHCId(); + } + // fill the digit data into the corresponding TRAP chip + int trapIdx = (digit->getROB() / 2) * NMCMROB + digit->getMCM(); + if (!trapSimulators[trapIdx].isDataSet()) { + trapSimulators[trapIdx].init(mTrapConfig, digit->getDetector(), digit->getROB(), digit->getMCM()); + } + trapSimulators[trapIdx].setData(digit->getChannel(), digit->getADC(), digitIdxArray[iDigit]); } - - if (olddetector != detector || oldrow != row) { - // we have gone over the pad row. //TODO ??? do we need to check for change of time as well? - //all data is inside the 8 relavent trapsimulators - int preivousrob = mFeeParam->getROBfromPad(oldrow, oldpad); // - //fireup Trapsim. - auto traploopstart = std::chrono::high_resolution_clock::now(); - unsigned long numberofusedtraps = 0; - for (int trapcounter = 0; trapcounter < 8; trapcounter++) { - unsigned int isinit = mTrapSimulator[trapcounter].checkInitialized(); - LOG(debug) << "Start of trap : " << trapcounter; - if (mTrapSimulator[trapcounter].isDataSet()) { //firedtraps - LOG(debug3) << "DataSet on : " << trapcounter; - //this one has been filled with data for the now previous pad row. - auto trapsimtimerstart = std::chrono::high_resolution_clock::now(); - mTrapUsedCounter[trapcounter]++; - numberofusedtraps++; - mTrapSimulator[trapcounter].filter(); - mTrapSimulator[trapcounter].tracklet(); - - trapTracklets = mTrapSimulator[trapcounter].getTrackletArray64(); //TODO remove the copy and send the Accumulated array into the Trapsimulator - auto trapLabels = mTrapSimulator[trapcounter].getTrackletLabels(); - if (!mNewTrackletHCHeaderHasBeenWritten && trapTracklets.size() != 0) { // take account of the case where we have data in the trapchip adc but no tracklets - //we have a tracklet for said half chamber, but the halfchamber ID has not been written yet - // .. fix the previous linkrecord to note its end of range. - if (mLinkRecords.size() == 0) { // special case for the first entry into the linkrecords vector. - mLinkRecords.emplace_back(mTrackletHCHeader.word, 0, -1); - // LOG(debug) << " added HCID :[record.size==0] " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); - } else { - mLinkRecords.back().setNumberOfObjects(mTotalRawWordsWritten - mLinkRecords.back().getFirstEntry()); // current number of words written - the start of this index record. - // LOG(debug) << " added HCID : " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); - //..... so write the new one thing - mLinkRecords.emplace_back(mTrackletHCHeader.word, mTotalRawWordsWritten, -1); // set the number of elements to -1 for an error condition + // take care of the TRAPs for the last half chamber + processTRAPchips(nTracklets[iTrig], trackletsAccum[iTrig], trapSimulators, digitCountsAccum[iTrig], digitIndicesAccum[iTrig]); + } // done with parallel processing + auto parallelTime = std::chrono::high_resolution_clock::now() - timeParallelStart; + + // accumulate results and add MC labels + for (int iTrig = 0; iTrig < triggerRecords.size(); ++iTrig) { + if (mUseMC) { + int currDigitIndex = 0; // counter for all digits which are associated to tracklets + int trkltIdxStart = tracklets.size(); + for (int iTrklt = 0; iTrklt < nTracklets[iTrig]; ++iTrklt) { + int tmp = currDigitIndex; + for (int iDigitIndex = tmp; iDigitIndex < tmp + digitCountsAccum[iTrig][iTrklt]; ++iDigitIndex) { + if (iDigitIndex == tmp) { + // for the first digit composing the tracklet we don't need to check for duplicate labels + lblTracklets.addElements(trkltIdxStart + iTrklt, lblDigitsPtr->getLabels(digitIndicesAccum[iTrig][iDigitIndex])); + } else { + // in case more than one digit composes the tracklet we add only the labels + // from the additional digit(s) which are not already contained in the previous + // digit(s) + auto currentLabels = lblTracklets.getLabels(trkltIdxStart + iTrklt); + auto newLabels = lblDigitsPtr->getLabels(digitIndicesAccum[iTrig][iDigitIndex]); + for (const auto& newLabel : newLabels) { + bool alreadyIn = false; + for (const auto& currLabel : currentLabels) { + if (currLabel == newLabel) { + alreadyIn = true; + break; + } + } + if (!alreadyIn) { + lblTracklets.addElement(trkltIdxStart + iTrklt, newLabel); + } } - mNewTrackletHCHeaderHasBeenWritten = true; - LOG(debug) << mTrackletHCHeader; } - LOG(debug) << "getting trackletsteram for trapcounter = " << trapcounter; - auto wordswritten = mTrapSimulator[trapcounter].getTrackletStream(rawdata, mTotalRawWordsWritten); // view of data from current marker and only 5 words long (can only have 4 words at most in the trackletstream for 1 MCM) - mTotalRawWordsWritten += wordswritten; - LOG(debug) << "Tracklets accumulated before addition of new ones :" << trapTrackletsAccum.size() - << " :: about to add " << trapTracklets.size() << " count tracklets, labels coming in index of: " - << trapLabels.getIndexedSize() << " and elements of : " - << trapLabels.getNElements() << " with countrackletadditions : " << counttrackletadditions; - counttrackletadditions++; - trapTrackletsAccum.insert(trapTrackletsAccum.end(), trapTracklets.begin(), trapTracklets.end()); - trackletMCLabels.mergeAtBack(trapLabels); - mTrapSimAccumulatedTime += std::chrono::high_resolution_clock::now() - trapsimtimerstart; - if (mShowTrackletStats > 0) { - if (trapTrackletsAccum.size() - oldsize > mShowTrackletStats) { - LOG(debug) << "TrapSim Accumulated tracklets: " << trapTrackletsAccum.size() << " :: " << trapTracklets.size(); - oldsize = trapTrackletsAccum.size(); - } - } - - // mTrapSimulator[trapcounter].zeroSupressionMapping(); - - if (mDrawTrackletOptions != 0) { - mTrapSimulator[trapcounter].draw(mDrawTrackletOptions, loopindex); - } - if (mDebugRejectedTracklets) { //&& trapTracklets.size()==0) { - mTrapSimulator[trapcounter].draw(7, loopindex); //draw adc when no tracklets are found.A - LOG(debug) << "loop index : " << loopindex; - mTrapSimulator[trapcounter].print(1); - } - if (mPrintTrackletOptions != 0) { - mTrapSimulator[trapcounter].print(mPrintTrackletOptions); - } - - loopindex++; - //set this trap sim object to have not data (effectively) reset. - mTrapSimulator[trapcounter].unsetData(); - } else { - LOG(debug) << "if statement is init failed [" << trapcounter << "] PROCESSING TRAP !"; - } - // LOG(debug) << "Finishe MCM : : " << trapcounter; - } //end of loop over trap chips - - //timing info - mTrapLoopTime += std::chrono::high_resolution_clock::now() - traploopstart; - mTrapUsedFrequency[numberofusedtraps]++; - - LOG(debug) << "Row change ... Tracklets so far: " << trapTrackletsAccum.size(); - if (mShowTrackletStats > 0) { - if (trapTrackletsAccum.size() - oldtrackletcount > mShowTrackletStats) { - oldtrackletcount = trapTrackletsAccum.size(); - unsigned long mcmTrackletsize = trapTrackletsAccum.size(); - mTrackletTime = std::chrono::high_resolution_clock::now() - digitloopstart; - trackletrate = mcmTrackletsize / mTrackletTime.count(); - LOG(info) << "Getting tracklets at the rate of : " << trackletrate << " Tracklets/s ... Accumulated tracklets : " << trapTrackletsAccum.size(); + ++currDigitIndex; } } - } //if oldetector!= detector .... - //we are still on the same detector and row. - //add the digits to the padrow. - //copy pad time data into where they belong in the 8 TrapSimulators for this pad. - int mcmoffset = -1; - int firstrob = mFeeParam->getROBfromPad(row, 5); // 5 is arbitrary, but above the lower shared pads. so will get first rob and mcm - int firstmcm = mFeeParam->getMCMfromPad(row, 5); // 5 for same reason - // LOG(info) <<"calculated first rob and mcm"; - int trapindex = pad / 18; - //check trap is initialised. - if (!mTrapSimulator[trapindex].isDataSet()) { - LOG(debug) << "Initialising trapsimulator for triplet (" << detector << "," << rob << "," - << mcm << ") as its not initialized and we need to send it some adc data."; - mTrapSimulator[trapindex].init(mTrapConfig, detector, rob, mcm); } - int adc = 20 - (pad % 18) - 1; - std::vector<o2::MCCompLabel> tmplabels; - auto digitslabels = digitMCLabels.getLabels(digitcounter); - for (auto& tmplabel : digitslabels) { - tmplabels.push_back(tmplabel); - } - LOG(debug) << "tmplabels for set data : " << tmplabels.size() << " and gslspan digitlabels size of : " << digitslabels.size(); - LOG(debug) << " setting data with pad=" << pad << " ti=" << trapindex + 1; - mTrapSimulator[trapindex].setData(adc, digit->getADC(), tmplabels); + tracklets.insert(tracklets.end(), trackletsAccum[iTrig].begin(), trackletsAccum[iTrig].end()); + triggerRecords[iTrig].setTrackletRange(tracklets.size() - nTracklets[iTrig], nTracklets[iTrig]); + } - // now take care of the case of shared pads (the whole reason for doing this pad row wise). + auto processingTime = std::chrono::high_resolution_clock::now() - timeProcessingStart; - if (pad % 18 == 0 || (pad + 1) % 18 == 0) { //case of pad 18 and 19 must be shared to preceding trap chip adc 1 and 0 respectively. - adc = 20 - (pad % 18) - 1; - if (trapindex != 0) { // avoid the case of the first trap chip - LOG(debug) << " setting data preceding with pad=" << pad << " ti=" << trapindex - 1; - mTrapSimulator[trapindex - 1].setData(adc, digit->getADC(), tmplabels); - } - } - if ((pad - 1) % 18 == 0) { // case of pad 17 must shared to next trap chip as adc 20 - //check trap is initialised. - adc = 20 - (pad % 18) - 1; - if (trapindex + 1 != 8) { // avoid the case of the last trap chip. - LOG(debug) << " setting data proceeding with pad=" << pad << " ti=" << trapindex + 1; - mTrapSimulator[trapindex + 1].setData(adc, digit->getADC(), tmplabels); - } - } - - olddetector = detector; - oldrow = row; - oldpad = pad; - digitcounter++; - } // end of loop over digits. - - // now finalise - auto triggerrecordstart = trackletTriggerRecords[currentTriggerRecord - 1].getFirstEntry() + trackletTriggerRecords[currentTriggerRecord - 1].getNumberOfObjects(); - trackletTriggerRecords[currentTriggerRecord].setDataRange(triggerrecordstart, trapTrackletsAccum.size() - triggerrecordstart); - mLinkRecords.back().setNumberOfObjects(mTotalRawWordsWritten - mLinkRecords.back().getFirstEntry()); // set the final link entry - LOG(info) << "Trap simulator found " << trapTrackletsAccum.size() << " tracklets from " << msgDigits.size() << " Digits and " << trackletMCLabels.getIndexedSize() << " associated MC Label indexes and " << trackletMCLabels.getNElements() << " associated MC Labels"; - if (mShowTrackletStats > 0) { - mDigitLoopTime = std::chrono::high_resolution_clock::now() - digitloopstart; - LOG(info) << "Trap Simulator done "; -#ifdef TRDTIMESORT - LOG(info) << "Sorting took " << mSortingTime.count() << "s"; -#endif - LOG(info) << "Digit loop took : " << mDigitLoopTime.count() << "s"; - LOG(info) << "Trapsim took : " << mTrapSimAccumulatedTime.count() << "s"; - LOG(info) << "Traploop took : " << mTrapLoopTime.count() << "s"; - for (auto trapcount : mTrapUsedFrequency) { - LOG(info) << "# traps fired Traploop are : " << trapcount; - } - for (auto trapcount : mTrapUsedCounter) { - LOG(info) << "each trap position fired : " << trapcount; - } - LOG(info) << "Raw data words written = " << mTotalRawWordsWritten << " with a vector size = " << rawdata.size(); - LOG(info) << "Raw data words written = " << mTotalRawWordsWritten << " with a vector size = " << rawdata.size(); + LOG(info) << "Trap simulator found " << tracklets.size() << " tracklets from " << digits.size() << " Digits."; + if (mUseMC) { + LOG(info) << "In total " << lblTracklets.getNElements() << " MC labels are associated to the " << lblTracklets.getIndexedSize() << " tracklets"; + } + LOG(info) << "Total processing time : " << std::chrono::duration_cast<std::chrono::milliseconds>(processingTime).count() << "ms"; + LOG(info) << "Digit Sorting took: " << std::chrono::duration_cast<std::chrono::milliseconds>(sortTime).count() << "ms"; + LOG(info) << "Processing time for parallel region: " << std::chrono::duration_cast<std::chrono::milliseconds>(parallelTime).count() << "ms"; + + pc.outputs().snapshot(Output{"TRD", "TRACKLETS", 0, Lifetime::Timeframe}, tracklets); + pc.outputs().snapshot(Output{"TRD", "TRKTRGRD", 0, Lifetime::Timeframe}, triggerRecords); + if (mUseMC) { + pc.outputs().snapshot(Output{"TRD", "TRKLABELS", 0, Lifetime::Timeframe}, lblTracklets); } - LOG(debug) << "END OF RUN ............."; - //TODO does anyone care to have the digits to tracklet mapping. Do we then presort the digits inline with the index or send both digits and sorted index. - //TODO is is available for post processing via the debug stream output. - pc.outputs().snapshot(Output{"TRD", "TRACKLETS", 0, Lifetime::Timeframe}, trapTrackletsAccum); - pc.outputs().snapshot(Output{"TRD", "TRKTRGRD", 0, Lifetime::Timeframe}, trackletTriggerRecords); - /*pc.outputs().snapshot(Output{"TRD", "TRKLABELS", 0, Lifetime::Timeframe}, trackletMCLabels); */ - // LOG(info) << "digit MCLabels is of type : " << type_id_with_cvr<decltype(digitMCLabels)>().pretty_name(); - pc.outputs().snapshot(Output{"TRD", "RAWDATA", 0, Lifetime::Timeframe}, rawdata); - pc.outputs().snapshot(Output{"TRD", "RAWTRGRD", 0, Lifetime::Timeframe}, rawTriggerRecords); - pc.outputs().snapshot(Output{"TRD", "RAWLNKRD", 0, Lifetime::Timeframe}, mLinkRecords); - - LOG(debug) << "exiting the trap sim run method "; - pc.services().get<ControlService>().endOfStream(); - pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + + LOG(debug) << "TRD Trap Simulator Device exiting"; } -o2::framework::DataProcessorSpec getTRDTrapSimulatorSpec() +o2::framework::DataProcessorSpec getTRDTrapSimulatorSpec(bool useMC) { - return DataProcessorSpec{"TRAP", Inputs{InputSpec{"digitinput", "TRD", "DIGITS", 0}, InputSpec{"triggerrecords", "TRD", "TRGRDIG", 0}, InputSpec{"labelinput", "TRD", "LABELS", 0}}, - - Outputs{OutputSpec{"TRD", "TRACKLETS", 0, Lifetime::Timeframe}, // this is the 64 tracklet words - OutputSpec{"TRD", "TRKTRGRD", 0, Lifetime::Timeframe}, - /*OutputSpec{"TRD", "TRKDIGITS", 0, Lifetime::Timeframe},*/ - OutputSpec{"TRD", "TRKLABELS", 0, Lifetime::Timeframe}, - /*OutputSpec{"TRD", "TRAPRAWDUMP", 0, Lifetime::Timeframe},*/ - OutputSpec{"TRD", "RAWTRGRD", 0, Lifetime::Timeframe}, // offsets for each event in the rawdata - OutputSpec{"TRD", "RAWLNKRD", 0, Lifetime::Timeframe}, // offsets for each link/halfchamberheader in the rawdata, halfchamberheader sitting in here. - OutputSpec{"TRD", "RAWDATA", 0, Lifetime::Timeframe}}, // this is the mcmheader,traprawtracklet, repeat in varying quantities. - AlgorithmSpec{adaptFromTask<TRDDPLTrapSimulatorTask>()}, + std::vector<InputSpec> inputs; + std::vector<OutputSpec> outputs; + + inputs.emplace_back("digitinput", "TRD", "DIGITS", 0); + inputs.emplace_back("triggerrecords", "TRD", "TRGRDIG", 0); + + outputs.emplace_back("TRD", "TRACKLETS", 0, Lifetime::Timeframe); + outputs.emplace_back("TRD", "TRKTRGRD", 0, Lifetime::Timeframe); + + if (useMC) { + inputs.emplace_back("labelinput", "TRD", "LABELS", 0); + outputs.emplace_back("TRD", "TRKLABELS", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{"TRAP", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<TRDDPLTrapSimulatorTask>(useMC)}, Options{ - {"show-trd-trackletstats", VariantType::Int, 25000, {"Display the accumulated size and capacity at number of track intervals"}}, - {"trd-trapconfig", VariantType::String, "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549", {"Name of the trap config from the CCDB default:cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549"}}, - {"trd-drawtracklets", VariantType::Int, 0, {"Bitpattern of input to TrapSimulator Draw method one histogram per chip not per tracklet, 1=raw,2=hits,4=tracklets, 7 for all"}}, - {"trd-printtracklets", VariantType::Int, 0, {"Bitpattern of input to TrapSimulator print method, "}}, - {"trd-fixtriggerrecord", VariantType::Bool, false, {"Fix trigger record alignment, temporary, hence false by default"}}, + {"trd-trapconfig", VariantType::String, "cf_pg-fpnp32_zs-s16-deh_tb30_trkl-b5n-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5549", {"TRAP config name"}}, {"trd-onlinegaincorrection", VariantType::Bool, false, {"Apply online gain calibrations, mostly for back checking to run2 by setting FGBY to 0"}}, {"trd-onlinegaintable", VariantType::String, "Krypton_2015-02", {"Online gain table to be use, names found in CCDB, obviously trd-onlinegaincorrection must be set as well."}}, - {"trd-debugrejectedtracklets", VariantType::Bool, false, {"Output all MCM where tracklets were not identified"}}, {"trd-dumptrapconfig", VariantType::Bool, false, {"Dump the selected trap configuration at loading time, to text file"}}, - {"trd-dumptriggerrecords", VariantType::Bool, false, {"Dump the trigger record to the default log output"}}, {"trd-runnum", VariantType::Int, 297595, {"Run number to use to anchor simulation to, defaults to 297595"}}}}; }; diff --git a/Detectors/TRD/workflow/src/TRDTrapSimulatorWorkFlow.cxx b/Detectors/TRD/workflow/src/TRDTrapSimulatorWorkFlow.cxx index 7ee787c381be3..af075169fccae 100644 --- a/Detectors/TRD/workflow/src/TRDTrapSimulatorWorkFlow.cxx +++ b/Detectors/TRD/workflow/src/TRDTrapSimulatorWorkFlow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,8 @@ // for TRD #include "TRDWorkflow/TRDTrapSimulatorSpec.h" -#include "TRDWorkflow/TRDTrackletWriterSpec.h" -#include "TRDWorkflow/TRDTrapRawWriterSpec.h" -#include "TRDWorkflow/TRDDigitReaderSpec.h" +#include "TRDWorkflowIO/TRDTrackletWriterSpec.h" +#include "TRDWorkflowIO/TRDDigitReaderSpec.h" #include "DataFormatsParameters/GRPObject.h" @@ -58,11 +58,22 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowoptions) //limit to a stack in a supermodule std::string trapsimstackhelp("Specify the specific stack to work on [0-5] within the supermodule"); workflowoptions.push_back(ConfigParamSpec{"simStack", VariantType::Int, -1, {trapsimstackhelp}}); + + workflowoptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"Disable MC labels"}}); + workflowoptions.push_back(ConfigParamSpec{"disable-root-input", o2::framework::VariantType::Bool, false, {"Disable root-files input readers"}}); + workflowoptions.push_back(ConfigParamSpec{"disable-root-output", o2::framework::VariantType::Bool, false, {"Disable root-files output writers"}}); //limit to a stack in a supermodule // the next one is now done inside the trapsim spec. // std::string trapsimconfighelp("Specify the Trap config to use from CCDB yes those long names like cf_pg-fpnp32_zs-s16-deh_tb24_trkl-b2p-fs1e24-ht200-qs0e24s24e23-pidlinear-pt100_ptrg.r5585"); // workflowoptions.push_back(ConfigParamSpec{"trapconfigname", VariantType::Int, -1, {trapsimconfighelp}}); + // option allowing to set parameters + std::string keyvaluehelp("Semicolon separated key=value strings (e.g.: 'TRDSimParams.digithreads=4;...')"); + workflowoptions.push_back( + ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + workflowoptions.push_back( + ConfigParamSpec{"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}); + // json output // run2 input // trap configuration @@ -79,14 +90,18 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // at the end. This places the processor at the beginning of the // workflow in the upper left corner of the GUI. // - return WorkflowSpec{ - //?? maybe a read spec to define the input in the case of my text run2 data and possible a proper data input reader. - o2::trd::getTRDDigitReaderSpec(1), - //o2::trd::getTRDDigitReaderSpec(1), - // connect the TRD digitization - o2::trd::getTRDTrapSimulatorSpec(), - // connect the TRD digit writer - o2::trd::getTRDTrackletWriterSpec(), - // connect the TRD digit writer - o2::trd::getTRDTrapRawWriterSpec()}; + using namespace o2::conf; + ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + WorkflowSpec specs; + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto disableRootInput = configcontext.options().get<bool>("disable-root-input"); + auto disableRootOutput = configcontext.options().get<bool>("disable-root-output"); + if (!disableRootInput) { + specs.emplace_back(o2::trd::getTRDDigitReaderSpec(useMC)); + } + specs.emplace_back(o2::trd::getTRDTrapSimulatorSpec(useMC)); + if (!disableRootOutput) { + specs.emplace_back(o2::trd::getTRDTrackletWriterSpec(useMC)); + } + return std::move(specs); } diff --git a/Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h b/Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h index e109530d22899..e11449dcf481d 100644 --- a/Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h +++ b/Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/TRD/workflow/src/TrackBasedCalibSpec.cxx b/Detectors/TRD/workflow/src/TrackBasedCalibSpec.cxx new file mode 100644 index 0000000000000..7243c56aaaaa8 --- /dev/null +++ b/Detectors/TRD/workflow/src/TrackBasedCalibSpec.cxx @@ -0,0 +1,98 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackBasedCalibSpec.cxx +/// \brief DPL device for creating/providing track based TRD calibration input +/// \author Ole Schmidt + +#include "TRDWorkflow/TrackBasedCalibSpec.h" +#include "TRDCalibration/TrackBasedCalib.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Headers/DataHeader.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" + +using namespace o2::framework; +using namespace o2::globaltracking; +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace trd +{ + +class TRDTrackBasedCalibDevice : public Task +{ + public: + TRDTrackBasedCalibDevice(std::shared_ptr<DataRequest> dr) : mDataRequest(dr) {} + ~TRDTrackBasedCalibDevice() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + std::shared_ptr<DataRequest> mDataRequest; + o2::trd::TrackBasedCalib mCalibrator; // gather input data for calibration of vD, ExB and gain +}; + +void TRDTrackBasedCalibDevice::init(InitContext& ic) +{ + //-------- init geometry and field --------// + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + mCalibrator.init(); +} + +void TRDTrackBasedCalibDevice::run(ProcessingContext& pc) +{ + + RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + mCalibrator.calculateAngResHistos(recoData); + + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "ANGRESHISTS", 0, Lifetime::Timeframe}, mCalibrator.getAngResHistos()); +} + +void TRDTrackBasedCalibDevice::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "Added in total %i entries to angular residual histograms", + mCalibrator.getAngResHistos().getNEntries()); +} + +DataProcessorSpec getTRDTrackBasedCalibSpec() +{ + std::vector<OutputSpec> outputs; + auto dataRequest = std::make_shared<DataRequest>(); + + GTrackID::mask_t srcTrk = GTrackID::getSourcesMask("ITS-TPC-TRD"); // possibly also use TPC-TRD? + GTrackID::mask_t srcClu = GTrackID::getSourcesMask("TRD"); // we don't need all clusters, only TRD tracklets + dataRequest->requestTracks(srcTrk, false); + dataRequest->requestClusters(srcClu, false); + + outputs.emplace_back(o2::header::gDataOriginTRD, "ANGRESHISTS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "trd-trackbased-calib", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask<TRDTrackBasedCalibDevice>(dataRequest)}, + Options{}}; +} + +} // namespace trd +} // namespace o2 diff --git a/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx b/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..e38cf67f7b872 --- /dev/null +++ b/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TRDWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::trd::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/TRD/workflow/src/trd-calib-workflow.cxx b/Detectors/TRD/workflow/src/trd-calib-workflow.cxx new file mode 100644 index 0000000000000..eba8461f9f590 --- /dev/null +++ b/Detectors/TRD/workflow/src/trd-calib-workflow.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "TRDWorkflowIO/TRDCalibReaderSpec.h" +#include "TRDWorkflow/VdAndExBCalibSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"enable-root-input", o2::framework::VariantType::Bool, false, {"enable root-files input readers"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + auto enableRootInp = configcontext.options().get<bool>("enable-root-input"); + WorkflowSpec specs; + if (enableRootInp) { + specs.emplace_back(o2::trd::getTRDCalibReaderSpec()); + } + specs.emplace_back(getTRDVdAndExBCalibSpec()); + return specs; +} diff --git a/Detectors/TRD/workflow/src/trd-kr-clusterer.cxx b/Detectors/TRD/workflow/src/trd-kr-clusterer.cxx new file mode 100644 index 0000000000000..ee0cd08c1e343 --- /dev/null +++ b/Detectors/TRD/workflow/src/trd-kr-clusterer.cxx @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "TRDWorkflow/KrClustererSpec.h" +#include "TRDWorkflowIO/TRDDigitReaderSpec.h" +#include "TRDWorkflowIO/KrClusterWriterSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the workflow + o2::conf::ConfigurableParam::writeINI("o2trdkrcluster_workflow_configuration.ini"); + + o2::framework::WorkflowSpec specs; + + bool useDigitTrigRec = false; + + // input + if (!configcontext.options().get<bool>("disable-root-input")) { + specs.emplace_back(o2::trd::getTRDDigitReaderSpec(false)); + useDigitTrigRec = true; + } + + // processing devices + specs.emplace_back(o2::trd::getKrClustererSpec(useDigitTrigRec)); + + // output devices + if (!configcontext.options().get<bool>("disable-root-output")) { + specs.emplace_back(o2::trd::getKrClusterWriterSpec()); + } + + return specs; +} diff --git a/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx b/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx index 4a15ec72aee6f..f2dc176865a97 100644 --- a/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx +++ b/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx @@ -1,18 +1,26 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "TRDWorkflow/TRDTrackingWorkflow.h" #include "CommonUtils/ConfigurableParam.h" #include "Framework/CompletionPolicy.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "TRDWorkflowIO/TRDCalibWriterSpec.h" +#include "TRDWorkflowIO/TRDTrackWriterSpec.h" +#include "TRDWorkflow/TrackBasedCalibSpec.h" +#include "TRDWorkflow/TRDGlobalTrackingSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" using namespace o2::framework; +using GTrackID = o2::dataformats::GlobalTrackID; // ------------------------------------------------------------------ @@ -20,12 +28,18 @@ using namespace o2::framework; void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) { // option allowing to set parameters - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); - workflowOptions.push_back(ConfigParamSpec{ - "disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); - std::string keyvaluehelp("Semicolon separated key=value strings ..."); - workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"Disable MC labels"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"track-sources", VariantType::String, std::string{GTrackID::ALL}, {"comma-separated list of sources to use for tracking"}}, + {"filter-trigrec", o2::framework::VariantType::Bool, false, {"ignore interaction records without ITS data"}}, + {"strict-matching", o2::framework::VariantType::Bool, false, {"High purity preliminary matching"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); } // ------------------------------------------------------------------ @@ -34,11 +48,50 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { + GTrackID::mask_t allowedSources = GTrackID::getSourcesMask("ITS-TPC,TPC"); // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2trdtracking-workflow_configuration.ini"); - auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); - auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); - return std::move(o2::trd::getTRDTrackingWorkflow(disableRootInp, disableRootOut)); + auto trigRecFilterActive = configcontext.options().get<bool>("filter-trigrec"); + auto strict = configcontext.options().get<bool>("strict-matching"); + GTrackID::mask_t srcTRD = allowedSources & GTrackID::getSourcesMask(configcontext.options().get<std::string>("track-sources")); + if (strict && (srcTRD & ~GTrackID::getSourcesMask("TPC")).any()) { + LOGP(WARNING, "In strict matching mode only TPC source allowed, {} asked, redefining", GTrackID::getSourcesNames(srcTRD)); + srcTRD = GTrackID::getSourcesMask("TPC"); + } + o2::framework::WorkflowSpec specs; + bool useMC = !configcontext.options().get<bool>("disable-mc"); + + // processing devices + specs.emplace_back(o2::trd::getTRDGlobalTrackingSpec(useMC, srcTRD, trigRecFilterActive, strict)); + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, srcTRD)) { + specs.emplace_back(o2::trd::getTRDTrackBasedCalibSpec()); + } + + // output devices + if (!configcontext.options().get<bool>("disable-root-output")) { + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, srcTRD)) { + specs.emplace_back(o2::trd::getTRDGlobalTrackWriterSpec(useMC)); + specs.emplace_back(o2::trd::getTRDCalibWriterSpec()); + } + if (GTrackID::includesSource(GTrackID::Source::TPC, srcTRD)) { + specs.emplace_back(o2::trd::getTRDTPCTrackWriterSpec(useMC, strict)); + } + } + + // input + auto maskClusters = GTrackID::getSourcesMask("TRD,TPC"); + auto maskTracks = srcTRD | GTrackID::getSourcesMask("TPC"); // we always need the TPC tracks for the refit + if (GTrackID::includesDet(GTrackID::DetID::ITS, srcTRD)) { + maskClusters |= GTrackID::getSourcesMask("ITS"); + maskTracks |= GTrackID::getSourcesMask("ITS"); + } + auto maskMatches = GTrackID::getSourcesMask(GTrackID::NONE); + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, maskClusters, maskMatches, maskTracks, useMC); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return specs; } diff --git a/Detectors/TRD/workflow/test/run_trivial_trapsimulator.sh b/Detectors/TRD/workflow/test/run_trivial_trapsimulator.sh index 870faa1d294dc..693335a88961a 100644 --- a/Detectors/TRD/workflow/test/run_trivial_trapsimulator.sh +++ b/Detectors/TRD/workflow/test/run_trivial_trapsimulator.sh @@ -1,5 +1,5 @@ #! /bin/bash -o2-sim -n 10 -g pythia8 --skipModules ZDC > o2sim.log +o2-sim -n 10 -g pythia8pp --skipModules ZDC > o2sim.log o2-sim-digitizer-workflow -b --onlyDET TRD > o2digitizer.log o2-trd-trap-sim -b >trapsim.log diff --git a/Detectors/Upgrades/ALICE3/AOD/CMakeLists.txt b/Detectors/Upgrades/ALICE3/AOD/CMakeLists.txt new file mode 100644 index 0000000000000..e1c59f6a325be --- /dev/null +++ b/Detectors/Upgrades/ALICE3/AOD/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(UpgradesAODUtils + SOURCES src/Run2LikeAO2D.cxx + PUBLIC_LINK_LIBRARIES ROOT::Core) + +o2_target_root_dictionary(UpgradesAODUtils + HEADERS include/UpgradesAODUtils/Run2LikeAO2D.h) diff --git a/Detectors/Upgrades/ALICE3/AOD/include/UpgradesAODUtils/Run2LikeAO2D.h b/Detectors/Upgrades/ALICE3/AOD/include/UpgradesAODUtils/Run2LikeAO2D.h new file mode 100644 index 0000000000000..73bfbd961fb88 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/AOD/include/UpgradesAODUtils/Run2LikeAO2D.h @@ -0,0 +1,300 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Run2LikeAO2D.h + +//****************************************************************** +// AO2D helper information +// +// This header contains basic info needed to mimick a Run 2-like +// converted AO2D file. Its current use case is the ALICE 3 +// G3/G4 simulation to AO2D conversion. +// +//****************************************************************** +#ifndef RUN2LIKE_AOD_H +#define RUN2LIKE_AOD_H +#include <TString.h> + +namespace o2 +{ +namespace upgrades_utils +{ + +enum TreeIndex { // Index of the output trees + kEvents = 0, //ok + kEventsExtra, //ok + kTracks, //ok + kCalo, //N/A + kCaloTrigger, //N/A + kMuon, //N/A + kZdc, //N/A + kFV0A, //N/A + kFV0C, //N/A + kFT0, //N/A + kFDD, //N/A + kV0s, //may be ok (requires tuning) + kCascades, //may be ok (requires tuning) + kTOF, //N/A... for now + kMcParticle, //MC operation + kMcCollision, //MC operation + kMcTrackLabel, //MC operation + kMcCaloLabel, //N/A + kMcCollisionLabel, //MC operation + kBC, //N/A + kTrees //N/A +}; + +enum MCParticleFlags : uint8_t { + ProducedInTransport = 1 // Bit 0: 0 = from generator; 1 = from transport +}; + +const TString gTreeName[kTrees] = {"O2collision", "DbgEventExtra", "O2track", "O2calo", "O2calotrigger", "O2muon", "O2zdc", "O2fv0a", "O2fv0c", "O2ft0", "O2fdd", "O2v0", "O2cascade", "O2tof", "O2mcparticle", "O2mccollision", "O2mctracklabel", "O2mccalolabel", "O2mccollisionlabel", "O2bc"}; +const TString gTreeTitle[kTrees] = {"Collision tree", "Collision extra", "Barrel tracks", "Calorimeter cells", "Calorimeter triggers", "MUON tracks", "ZDC", "FV0A", "FV0C", "FT0", "FDD", "V0s", "Cascades", "TOF hits", "Kinematics", "MC collisions", "MC track labels", "MC calo labels", "MC collision labels", "BC info"}; + +const Bool_t gSaveTree[kTrees] = {kTRUE, kFALSE, kTRUE, kFALSE, kFALSE, kFALSE, kTRUE, kTRUE, kTRUE, kTRUE, kTRUE, + //V0 and cascade (not done for now) + kFALSE, kFALSE, + //TOF + kFALSE, + //MC information (not done for now) + kTRUE, kTRUE, kTRUE, kFALSE, kTRUE, kTRUE}; + +//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// structs for AO2D convenience +// straight from AO2D converter +struct { + // Event data + Int_t fBCsID = 0u; /// Index to BC table + // Primary vertex position + Float_t fPosX = -999.f; /// Primary vertex x coordinate + Float_t fPosY = -999.f; /// Primary vertex y coordinate + Float_t fPosZ = -999.f; /// Primary vertex z coordinate + // Primary vertex covariance matrix + Float_t fCovXX = 999.f; /// cov[0] + Float_t fCovXY = 0.f; /// cov[1] + Float_t fCovXZ = 0.f; /// cov[2] + Float_t fCovYY = 999.f; /// cov[3] + Float_t fCovYZ = 0.f; /// cov[4] + Float_t fCovZZ = 999.f; /// cov[5] + // Quality parameters + Float_t fChi2 = 999.f; /// Chi2 of the vertex + UInt_t fN = 0u; /// Number of contributors + + // The calculation of event time certainly will be modified in Run3 + // The prototype below can be switched on request + Float_t fCollisionTime = 10; /// Event time (t0) obtained with different methods (best, T0, T0-TOF, ...) + Float_t fCollisionTimeRes = 1e-3; /// Resolution on the event time (t0) obtained with different methods (best, T0, T0-TOF, ...) + UChar_t fCollisionTimeMask = 0u; /// Mask with the method used to compute the event time (0x1=T0-TOF,0x2=T0A,0x3=TOC) for each momentum bins + +} collision; //! structure to keep the primary vertex (avoid name conflicts) + +struct { + // Start indices and numbers of elements for data in the other trees matching this vertex. + // Needed for random access of collision-related data, allowing skipping data discarded by the user + Int_t fStart[kTrees] = {0}; /// Start entry indices for data in the other trees matching this vertex + Int_t fNentries[kTrees] = {0}; /// Numbers of entries for data in the other trees matching this vertex +} eventextra; //! structure for benchmarking information + +struct { + int fRunNumber = -1; /// Run number + ULong64_t fGlobalBC = 0u; /// Unique bunch crossing id. Contains period, orbit and bunch crossing numbers + ULong64_t fTriggerMask = 0u; /// Trigger class mask +} bc; //! structure to keep trigger-related info + +struct { + // Track data + + Int_t fCollisionsID = -1; /// The index of the collision vertex in the TF, to which the track is attached + + uint8_t fTrackType = 0; // Type of track: global, ITS standalone, tracklet, ... + + // In case we need connection to TOF clusters, activate next lines + // Int_t fTOFclsIndex; /// The index of the associated TOF cluster + // Int_t fNTOFcls; /// The number of TOF clusters + + // Coordinate system parameters + Float_t fX = -999.f; /// X coordinate for the point of parametrisation + Float_t fAlpha = -999.f; /// Local <--> global coor.system rotation angle + + // Track parameters + Float_t fY = -999.f; /// fP[0] local Y-coordinate of a track (cm) + Float_t fZ = -999.f; /// fP[1] local Z-coordinate of a track (cm) + Float_t fSnp = -999.f; /// fP[2] local sine of the track momentum azimuthal angle + Float_t fTgl = -999.f; /// fP[3] tangent of the track momentum dip angle + Float_t fSigned1Pt = -999.f; /// fP[4] 1/pt (1/(GeV/c)) + + // "Covariance matrix" + // The diagonal elements represent the errors = Sqrt(C[i,i]) + // The off-diagonal elements are the correlations = C[i,j]/Sqrt(C[i,i])/Sqrt(C[j,j]) + // The off-diagonal elements are multiplied by 128 (7bits) and packed in Char_t + Float_t fSigmaY = -999.f; /// Sqrt(fC[0]) + Float_t fSigmaZ = -999.f; /// Sqrt(fC[2]) + Float_t fSigmaSnp = -999.f; /// Sqrt(fC[5]) + Float_t fSigmaTgl = -999.f; /// Sqrt(fC[9]) + Float_t fSigma1Pt = -999.f; /// Sqrt(fC[14]) + Char_t fRhoZY = 0; /// 128*fC[1]/SigmaZ/SigmaY + Char_t fRhoSnpY = 0; /// 128*fC[3]/SigmaSnp/SigmaY + Char_t fRhoSnpZ = 0; /// 128*fC[4]/SigmaSnp/SigmaZ + Char_t fRhoTglY = 0; /// 128*fC[6]/SigmaTgl/SigmaY + Char_t fRhoTglZ = 0; /// 128*fC[7]/SigmaTgl/SigmaZ + Char_t fRhoTglSnp = 0; /// 128*fC[8]/SigmaTgl/SigmaSnp + Char_t fRho1PtY = 0; /// 128*fC[10]/Sigma1Pt/SigmaY + Char_t fRho1PtZ = 0; /// 128*fC[11]/Sigma1Pt/SigmaZ + Char_t fRho1PtSnp = 0; /// 128*fC[12]/Sigma1Pt/SigmaSnp + Char_t fRho1PtTgl = 0; /// 128*fC[13]/Sigma1Pt/SigmaTgl + + // Additional track parameters + Float_t fTPCinnerP = -999.f; /// Full momentum at the inner wall of TPC for dE/dx PID + + // Track quality parameters + UInt_t fFlags = 0u; /// Reconstruction status flags + + // Clusters and tracklets + UChar_t fITSClusterMap = 0u; /// ITS map of clusters, one bit per a layer + UChar_t fTPCNClsFindable = 0u; /// number of clusters that could be assigned in the TPC + Char_t fTPCNClsFindableMinusFound = 0; /// difference between foundable and found clusters + Char_t fTPCNClsFindableMinusCrossedRows = 0; /// difference between foundable clsuters and crossed rows + UChar_t fTPCNClsShared = 0u; /// Number of shared clusters + UChar_t fTRDPattern = 0u; /// Bit 0-5 if tracklet from TRD layer used for this track + + // Chi2 + Float_t fITSChi2NCl = -999.f; /// chi2/Ncl ITS + Float_t fTPCChi2NCl = -999.f; /// chi2/Ncl TPC + Float_t fTRDChi2 = -999.f; /// chi2 TRD match (?) + Float_t fTOFChi2 = -999.f; /// chi2 TOF match (?) + + // PID + Float_t fTPCSignal = -999.f; /// dE/dX TPC + Float_t fTRDSignal = -999.f; /// dE/dX TRD + Float_t fTOFSignal = -999.f; /// TOFsignal + Float_t fLength = -999.f; /// Int.Lenght @ TOF + Float_t fTOFExpMom = -999.f; /// TOF Expected momentum based on the expected time of pions + + // Track extrapolation to EMCAL surface + Float_t fTrackEtaEMCAL = -999.f; /// Track eta at the EMCAL surface + Float_t fTrackPhiEMCAL = -999.f; /// Track phi at the EMCAL surface +} tracks; //! structure to keep track information + +struct { + // MC collision + Int_t fBCsID = 0u; /// Index to BC table + Short_t fGeneratorsID = 0u; /// Generator ID used for the MC + Float_t fPosX = -999.f; /// Primary vertex x coordinate from MC + Float_t fPosY = -999.f; /// Primary vertex y coordinate from MC + Float_t fPosZ = -999.f; /// Primary vertex z coordinate from MC + Float_t fT = -999.f; /// Time of the collision from MC + Float_t fWeight = -999.f; /// Weight from MC + // Generation details (HepMC3 in the future) + Float_t fImpactParameter = -999.f; /// Impact parameter from MC +} mccollision; //! MC collisions = vertices + +struct { + // Track label to find the corresponding MC particle + UInt_t fLabel = 0; /// Track label + UShort_t fLabelMask = 0; /// Bit mask to indicate detector mismatches (bit ON means mismatch) + /// Bit 0-6: mismatch at ITS layer + /// Bit 7-9: # of TPC mismatches in the ranges 0, 1, 2-3, 4-7, 8-15, 16-31, 32-63, >64 + /// Bit 10: TRD, bit 11: TOF, bit 15: negative label sign +} mctracklabel; //! Track labels + +struct { + // MC particle + + Int_t fMcCollisionsID = -1; /// The index of the MC collision vertex + + // MC information (modified version of TParticle + Int_t fPdgCode = -99999; /// PDG code of the particle + Int_t fStatusCode = -99999; /// generation status code + uint8_t fFlags = 0; /// See enum MCParticleFlags + Int_t fMother0 = 0; /// Indices of the mother particles + Int_t fMother1 = 0; + Int_t fDaughter0 = 0; /// Indices of the daughter particles + Int_t fDaughter1 = 0; + Float_t fWeight = 1; /// particle weight from the generator or ML + + Float_t fPx = -999.f; /// x component of momentum + Float_t fPy = -999.f; /// y component of momentum + Float_t fPz = -999.f; /// z component of momentum + Float_t fE = -999.f; /// Energy (covers the case of resonances, no need for calculated mass) + + Float_t fVx = -999.f; /// x of production vertex + Float_t fVy = -999.f; /// y of production vertex + Float_t fVz = -999.f; /// z of production vertex + Float_t fVt = -999.f; /// t of production vertex + // We do not use the polarisation so far +} mcparticle; //! MC particles from the kinematics tree + +struct { + // MC collision label + UInt_t fLabel = 0; /// Collision label + UShort_t fLabelMask = 0; /// Bit mask to indicate collision mismatches (bit ON means mismatch) + /// bit 15: negative label sign +} mccollisionlabel; //! Collision labels + +struct { + /// FDD (AD) + Int_t fBCsID = 0u; /// Index to BC table + Float_t fAmplitudeA[4] = {0.f}; /// Multiplicity for each A-side channel + Float_t fAmplitudeC[4] = {0.f}; /// Multiplicity for each C-side channel + Float_t fTimeA = 56.7f; /// Average A-side time + Float_t fTimeC = 65.3f; /// Average C-side time + uint8_t fTriggerMask = 0; /// Trigger info +} fdd; + +struct { + /// V0A (32 cells in Run2, 48 cells in Run3) + Int_t fBCsID = 0u; /// Index to BC table + Float_t fAmplitude[48] = {0.f}; /// Multiplicity for each channel + Float_t fTime = 11.f; /// Average A-side time + uint8_t fTriggerMask = 0; /// Trigger info +} fv0a; //! structure to keep V0A information + +struct { + /// V0C (32 cells in Run2) + Int_t fBCsID = 0u; /// Index to BC table + Float_t fAmplitude[32] = {0.f}; /// Multiplicity for each channel + Float_t fTime = 3.6f; /// Average C-side time +} fv0c; //! structure to keep V0C information + +struct { + /// FT0 (12+12 channels in Run2, 96+112 channels in Run3) + Int_t fBCsID = 0u; /// Index to BC table + Float_t fAmplitudeA[96] = {0.f}; /// Multiplicity for each A-side channel + Float_t fAmplitudeC[112] = {0.f}; /// Multiplicity for each C-side channel + Float_t fTimeA = 0.02f; /// Average A-side time + Float_t fTimeC = 0.03f; /// Average C-side time + uint8_t fTriggerMask = 0; /// Trigger info +} ft0; //! structure to keep FT0 information + +struct { + Int_t fBCsID = 0u; /// Index to BC table + Float_t fEnergyZEM1 = 0.f; ///< E in ZEM1 + Float_t fEnergyZEM2 = 0.f; ///< E in ZEM2 + Float_t fEnergyCommonZNA = 0.f; ///< E in common ZNA PMT - high gain chain + Float_t fEnergyCommonZNC = 0.f; ///< E in common ZNC PMT - high gain chain + Float_t fEnergyCommonZPA = 0.f; ///< E in common ZPA PMT - high gain chain + Float_t fEnergyCommonZPC = 0.f; ///< E in common ZPC PMT - high gain chain + Float_t fEnergySectorZNA[4] = {0.f}; ///< E in 4 ZNA sectors - high gain chain + Float_t fEnergySectorZNC[4] = {0.f}; ///< E in 4 ZNC sectors - high gain chain + Float_t fEnergySectorZPA[4] = {0.f}; ///< E in 4 ZPA sectors - high gain chain + Float_t fEnergySectorZPC[4] = {0.f}; ///< E in 4 ZPC sectors - high gain chain + Float_t fTimeZEM1 = 0.f; ///< Corrected time in ZEM1 + Float_t fTimeZEM2 = 0.f; ///< Corrected time in ZEM2 + Float_t fTimeZNA = 0.055f; ///< Corrected time in ZNA + Float_t fTimeZNC = -0.049f; ///< Corrected time in ZNC + Float_t fTimeZPA = 0.f; ///< Corrected time in ZPA + Float_t fTimeZPC = 0.f; ///< Corrected time in ZPC +} zdc; +//! structure to keep ZDC information +} // namespace upgrades_utils +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/AOD/src/Run2LikeAO2D.cxx b/Detectors/Upgrades/ALICE3/AOD/src/Run2LikeAO2D.cxx new file mode 100644 index 0000000000000..c01c3181cf454 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/AOD/src/Run2LikeAO2D.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "UpgradesAODUtils/Run2LikeAO2D.h" + +namespace o2 +{ +namespace upgrades_utils +{ + +void __dummy_instance__() +{ // will eventually become the class implementation + TreeIndex Instance; +} + +} // namespace upgrades_utils +} // namespace o2 \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/AOD/src/UpgradesAODUtilsLinkDef.h b/Detectors/Upgrades/ALICE3/AOD/src/UpgradesAODUtilsLinkDef.h new file mode 100644 index 0000000000000..e5b45bbcd779e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/AOD/src/UpgradesAODUtilsLinkDef.h @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/CMakeLists.txt b/Detectors/Upgrades/ALICE3/CMakeLists.txt new file mode 100644 index 0000000000000..3aa6f4bbf613b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(Passive) +add_subdirectory(TRK) +add_subdirectory(FT3) +add_subdirectory(AOD) diff --git a/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt new file mode 100644 index 0000000000000..2d9ff8a9ac78e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(simulation) +add_subdirectory(base) diff --git a/Detectors/Upgrades/ALICE3/FT3/README.md b/Detectors/Upgrades/ALICE3/FT3/README.md new file mode 100644 index 0000000000000..3e7837d9226c0 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/README.md @@ -0,0 +1,10 @@ +<!-- doxy +\page refDetectorsUpgradesALICE3FT3 EndCaps +/doxy --> + +# PostLS4EndCaps + +This is a top page for the PostLS4EndCaps detector documentation. + +<!-- doxy +/doxy --> diff --git a/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt new file mode 100644 index 0000000000000..3e4925e78bd11 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FT3Base + SOURCES src/GeometryTGeo.cxx + SOURCES src/FT3BaseParam.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase) + +o2_target_root_dictionary(FT3Base + HEADERS include/FT3Base/GeometryTGeo.h + HEADERS include/FT3Base/FT3BaseParam.h) diff --git a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h new file mode 100644 index 0000000000000..b286aa068611c --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/FT3BaseParam.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_FT3_BASEPARAM_H_ +#define ALICEO2_FT3_BASEPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace ft3 +{ + +// ** +// ** Parameters for FT3 base configuration +// ** + +enum FT3Geometry { + Default = 0, + Telescope = 1 +}; + +struct FT3BaseParam : public o2::conf::ConfigurableParamHelper<FT3BaseParam> { + // Geometry Builder parameters + + Int_t geoModel = FT3Geometry::Default; + + // FT3Geometry::Telescope parameters + Int_t nLayers = 10; + Float_t z0 = -16.0; // First layer z position + Float_t zLength = 263.0; // Distance between first and last layers + Float_t etaIn = 4.5; + Float_t etaOut = 1.5; + Float_t Layerx2X0 = 0.01; + + // FT3Geometry::External file + std::string configFile = ""; // Overrides geoModel parameter when provided + + O2ParamDef(FT3BaseParam, "FT3Base"); +}; + +} // end namespace ft3 +} // end namespace o2 + +#endif // ALICEO2_FT3_BASEPARAM_H_ diff --git a/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h new file mode 100644 index 0000000000000..e410c7b27985a --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/include/FT3Base/GeometryTGeo.h @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.h +/// \brief Definition of the GeometryTGeo class +/// \author cvetan.cheshkov@cern.ch - 15/02/2007 +/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 +/// \author rafael.pezzi@cern.ch - adapted to PostLS4EndCaps 25/06/2020 + +#ifndef ALICEO2_FT3_GEOMETRYTGEO_H_ +#define ALICEO2_FT3_GEOMETRYTGEO_H_ + +#include <TGeoMatrix.h> // for TGeoHMatrix +#include <TObject.h> // for TObject +#include <array> +#include <string> +#include <vector> +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "ITSMFTBase/GeometryTGeo.h" +#include "MathUtils/Utils.h" +#include "Rtypes.h" // for Int_t, Double_t, Bool_t, UInt_t, etc + +class TGeoPNEntry; + +namespace o2 +{ +namespace ft3 +{ +/// GeometryTGeo is a simple interface class to TGeoManager. It is used in the simulation +/// in order to query the TGeo FT3 geometry. +/// RS: In order to preserve the static character of the class but make it dynamically access +/// geometry, we need to check in every method if the structures are initialized. To be converted +/// to singleton at later stage. + +class GeometryTGeo : public o2::itsmft::GeometryTGeo +{ + public: + typedef o2::math_utils::Transform3D Mat3D; + using DetMatrixCache::getMatrixL2G; + using DetMatrixCache::getMatrixT2GRot; + using DetMatrixCache::getMatrixT2L; + // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation + // it is cheaper to use T2GRot + using DetMatrixCache::getMatrixT2G; + + static GeometryTGeo* Instance() + { + // get (create if needed) a unique instance of the object + if (!sInstance) { + sInstance = std::unique_ptr<GeometryTGeo>(new GeometryTGeo(true, 0)); + } + return sInstance.get(); + } + + // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) + static void adopt(GeometryTGeo* raw); + + // constructor + // ATTENTION: this class is supposed to behave as a singleton, but to make it root-persistent + // we must define public default constructor. + // NEVER use it, it will throw exception if the class instance was already created + // Use GeometryTGeo::Instance() instead + GeometryTGeo(bool build = kFALSE, int loadTrans = 0 + /*o2::base::utils::bit2Mask(o2::TransformType::T2L, // default transformations to load + o2::TransformType::T2G, + o2::TransformType::L2G)*/ + ); + + /// Default destructor + ~GeometryTGeo() override = default; + + GeometryTGeo(const GeometryTGeo& src) = delete; + GeometryTGeo& operator=(const GeometryTGeo& geom) = delete; + + // implement filling of the matrix cache + using o2::itsmft::GeometryTGeo::fillMatrixCache; + void fillMatrixCache(int mask) override; + + /// Exract FT3 parameters from TGeo + void Build(int loadTrans = 0) override; + + void Print(Option_t* opt = "") const; + static const char* getFT3VolPattern() { return sVolumeName.c_str(); } + static const char* getFT3InnerVolPattern() { return sInnerVolumeName.c_str(); } + static const char* getFT3LayerPattern() { return sLayerName.c_str(); } + static const char* getFT3ChipPattern() { return sChipName.c_str(); } + static const char* getFT3SensorPattern() { return sSensorName.c_str(); } + + static const char* composeSymNameFT3(Int_t d) { return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::FT3).getName(), d); } + static const char* composeSymNameLayer(Int_t d, Int_t lr); + static const char* composeSymNameChip(Int_t d, Int_t lr); + static const char* composeSymNameSensor(Int_t d, Int_t lr); + + protected: + static constexpr int MAXLAYERS = 15; ///< max number of active layers + + Int_t mNumberOfLayers; ///< number of layers + static std::string sInnerVolumeName; ///< Mother inner volume name + static std::string sVolumeName; ///< Mother volume name + static std::string sLayerName; ///< Layer name + static std::string sChipName; ///< Chip name + + static std::string sSensorName; ///< Sensor name + + private: + static std::unique_ptr<o2::ft3::GeometryTGeo> sInstance; ///< singletone instance + + ClassDefOverride(GeometryTGeo, 1); // FT3 geometry based on TGeo +}; +} // namespace ft3 +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h new file mode 100644 index 0000000000000..0a732ea1ec39b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::ft3::GeometryTGeo; +#pragma link C++ class o2::ft3::FT3BaseParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::ft3::FT3BaseParam> + ; + +#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx new file mode 100644 index 0000000000000..a5179299531a2 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/src/FT3BaseParam.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT3Base/FT3BaseParam.h" +O2ParamImpl(o2::ft3::FT3BaseParam); diff --git a/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx new file mode 100644 index 0000000000000..a67ac5a59caff --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/base/src/GeometryTGeo.cxx @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.cxx +/// \brief Implementation of the GeometryTGeo class +/// \author cvetan.cheshkov@cern.ch - 15/02/2007 +/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 +/// \author rafael.pezzi@cern.ch - adapted to ALICE 3 EndCaps 14/02/2021 + +// ATTENTION: In opposite to old AliITSgeomTGeo, all indices start from 0, not from 1!!! + +#include "FT3Base/GeometryTGeo.h" +#include "DetectorsBase/GeometryManager.h" +#include "MathUtils/Cartesian.h" + +#include "FairLogger.h" // for LOG + +#include <TGeoBBox.h> // for TGeoBBox +#include <TGeoManager.h> // for gGeoManager, TGeoManager +#include <TGeoPhysicalNode.h> // for TGeoPNEntry, TGeoPhysicalNode +#include <TGeoShape.h> // for TGeoShape +#include <TMath.h> // for Nint, ATan2, RadToDeg +#include <TString.h> // for TString, Form +#include "TClass.h" // for TClass +#include "TGeoMatrix.h" // for TGeoHMatrix +#include "TGeoNode.h" // for TGeoNode, TGeoNodeMatrix +#include "TGeoVolume.h" // for TGeoVolume +#include "TMathBase.h" // for Max +#include "TObjArray.h" // for TObjArray +#include "TObject.h" // for TObject + +#include <cctype> // for isdigit +#include <cstdio> // for snprintf, NULL, printf +#include <cstring> // for strstr, strlen + +using namespace TMath; +using namespace o2::ft3; +using namespace o2::detectors; + +ClassImp(o2::ft3::GeometryTGeo); + +std::unique_ptr<o2::ft3::GeometryTGeo> GeometryTGeo::sInstance; + +std::string GeometryTGeo::sVolumeName = "FT3V"; ///< Mother volume name +std::string GeometryTGeo::sInnerVolumeName = "FT3Inner"; ///< Mother inner volume name +std::string GeometryTGeo::sLayerName = "FT3Layer"; ///< Layer name +std::string GeometryTGeo::sChipName = "FT3Chip"; ///< Sensor name +std::string GeometryTGeo::sSensorName = "FT3Sensor"; ///< Sensor name + +//__________________________________________________________________________ +GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : o2::itsmft::GeometryTGeo(DetID::FT3) +{ + // default c-tor, if build is true, the structures will be filled and the transform matrices + // will be cached + if (sInstance) { + LOG(FATAL) << "Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists"; + // throw std::runtime_error("Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists"); + } + + if (build) { + Build(loadTrans); + } +} + +//__________________________________________________________________________ +void GeometryTGeo::Build(int loadTrans) +{ + if (isBuilt()) { + LOG(WARNING) << "Already built"; + return; // already initialized + } + + if (!gGeoManager) { + // RSTODO: in future there will be a method to load matrices from the CDB + LOG(FATAL) << "Geometry is not loaded"; + } + + fillMatrixCache(loadTrans); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameLayer(Int_t d, Int_t lr) +{ + return Form("%s/%s%d", composeSymNameFT3(d), getFT3LayerPattern(), lr); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameChip(Int_t d, Int_t lr) +{ + return Form("%s/%s%d", composeSymNameLayer(d, lr), getFT3ChipPattern(), lr); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameSensor(Int_t d, Int_t lr) +{ + return Form("%s/%s%d", composeSymNameChip(d, lr), getFT3SensorPattern(), lr); +} + +//__________________________________________________________________________ +void GeometryTGeo::fillMatrixCache(int mask) +{ + // populate matrix cache for requested transformations + // +} diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt new file mode 100644 index 0000000000000..89f8c23797fac --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(FT3Simulation + SOURCES src/FT3Layer.cxx + src/Detector.cxx + PUBLIC_LINK_LIBRARIES O2::FT3Base + O2::ITSMFTSimulation + ROOT::Physics) + +o2_target_root_dictionary(FT3Simulation + HEADERS include/FT3Simulation/Detector.h + include/FT3Simulation/FT3Layer.h) + +o2_data_file(COPY data DESTINATION Detectors/FT3/simulation) diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/data/simcuts.dat b/Detectors/Upgrades/ALICE3/FT3/simulation/data/simcuts.dat similarity index 100% rename from Detectors/Upgrades/PostLS4/IT4/simulation/data/simcuts.dat rename to Detectors/Upgrades/ALICE3/FT3/simulation/data/simcuts.dat diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h new file mode 100644 index 0000000000000..c0f6c441933f4 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h @@ -0,0 +1,177 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Detector.h +/// \brief Definition of the Detector class + +#ifndef ALICEO2_FT3_DETECTOR_H_ +#define ALICEO2_FT3_DETECTOR_H_ + +#include <vector> // for vector +#include "DetectorsBase/GeometryManager.h" // for getSensID +#include "DetectorsBase/Detector.h" // for Detector +#include "DetectorsCommonDataFormats/DetID.h" // for Detector +#include "ITSMFTSimulation/Hit.h" // for Hit +#include "Rtypes.h" // for Int_t, Double_t, Float_t, Bool_t, etc +#include "TArrayD.h" // for TArrayD +#include "TGeoManager.h" // for gGeoManager, TGeoManager (ptr only) +#include "TLorentzVector.h" // for TLorentzVector +#include "TVector3.h" // for TVector3 +#include "FT3Base/FT3BaseParam.h" + +class FairVolume; +class TGeoVolume; + +class TParticle; + +class TString; + +namespace o2 +{ +namespace ft3 +{ +class GeometryTGeo; +} +} // namespace o2 +namespace o2 +{ +namespace ft3 +{ +class FT3Layer; +} +} // namespace o2 + +namespace o2 +{ +namespace ft3 +{ +class FT3Layer; + +class Detector : public o2::base::DetImpl<Detector> +{ + public: + /// Name : Detector Name + /// Active: kTRUE for active detectors (ProcessHits() will be called) + /// kFALSE for inactive detectors + Detector(Bool_t active); + + /// Default constructor + Detector(); + + /// Default destructor + ~Detector() override; + + /// Initialization of the detector is done here + void InitializeO2Detector() override; + + /// This method is called for each step during simulation (see FairMCApplication::Stepping()) + Bool_t ProcessHits(FairVolume* v = nullptr) override; + + /// Registers the produced collections in FAIRRootManager + void Register() override; + + /// Gets the produced collections + std::vector<o2::itsmft::Hit>* getHits(Int_t iColl) const + { + if (iColl == 0) { + return mHits; + } + return nullptr; + } + + /// Has to be called after each event to reset the containers + void Reset() override; + + /// Base class to create the detector geometry + void ConstructGeometry() override; + + /// This method is an example of how to add your own point of type Hit to the clones array + o2::itsmft::Hit* addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, + unsigned char startStatus, unsigned char endStatus); + + Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID::FT3, id); } + + void EndOfEvent() override; + + void FinishPrimary() override { ; } + virtual void finishRun() { ; } + void BeginPrimary() override { ; } + void PostTrack() override { ; } + void PreTrack() override { ; } + + /// Returns the number of layers + Int_t getNumberOfLayers() const { return mNumberOfLayers; } + + void buildBasicFT3(const FT3BaseParam& param); + void buildFT3V1(); + void buildFT3FromFile(std::string); + + GeometryTGeo* mGeometryTGeo; //! access to geometry details + + void exportLayout(); + + protected: + std::vector<Int_t> mLayerID; + std::vector<std::vector<TString>> mLayerName; + Int_t mNumberOfLayers; + + private: + /// this is transient data about track passing the sensor + struct TrackData { // this is transient + bool mHitStarted; //! hit creation started + unsigned char mTrkStatusStart; //! track status flag + TLorentzVector mPositionStart; //! position at entrance + TLorentzVector mMomentumStart; //! momentum + double mEnergyLoss; //! energy loss + } mTrackData; //! + + /// Container for hit data + std::vector<o2::itsmft::Hit>* mHits; + + /// Create the detector materials + virtual void createMaterials(); + + /// Create the detector geometry + void createGeometry(); + + /// Define the sensitive volumes of the geometry + void defineSensitiveVolumes(); + + Detector(const Detector&); + + Detector& operator=(const Detector&); + + std::vector<std::vector<FT3Layer>> mLayers; + bool mIsPipeActivated = true; //! If Alice 3 pipe is present append inner disks to vacuum volume to avoid overlaps + + template <typename Det> + friend class o2::base::DetImpl; + ClassDefOverride(Detector, 1); +}; + +} // namespace ft3 +} // namespace o2 + +#ifdef USESHM +namespace o2 +{ +namespace base +{ +template <> +struct UseShm<o2::ft3::Detector> { + static constexpr bool value = true; +}; +} // namespace base +} // namespace o2 +#endif + +#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h new file mode 100644 index 0000000000000..ad087ad979728 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Layer.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file FT3Layer.h +/// \brief Definition of the FT3Layer class + +#ifndef ALICEO2_FT3_UPGRADEV3LAYER_H_ +#define ALICEO2_FT3_UPGRADEV3LAYER_H_ + +#include <TGeoManager.h> // for gGeoManager +#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc +#include "FT3Simulation/Detector.h" // for Detector, Detector::Model + +class TGeoVolume; + +namespace o2 +{ +namespace ft3 +{ + +/// This class defines the Geometry for the FT3 Layer TGeo. This is a work class used +/// to study different configurations during the development of the ALICE3 EndCaps +class FT3Layer : public TObject +{ + public: + // Default constructor + FT3Layer() = default; + + // Sample layer constructor + FT3Layer(Int_t layerDirection, Int_t layerNumber, std::string layerName, Float_t z, Float_t rIn, Float_t rOut, Float_t Layerx2X0); + + /// Copy constructor + FT3Layer(const FT3Layer&) = default; + + /// Assignment operator + FT3Layer& operator=(const FT3Layer&) = default; + + /// Default destructor + ~FT3Layer() override; + + /// getters + auto getInnerRadius() const { return mInnerRadius; } + auto getOuterRadius() const { return mOuterRadius; } + auto getZ() const { return mZ; } + auto getx2X0() const { return mx2X0; } + + /// Creates the actual Layer and places inside its mother volume + /// \param motherVolume the TGeoVolume owing the volume structure + virtual void createLayer(TGeoVolume* motherVolume); + + private: + Int_t mLayerNumber = -1; ///< Current layer number + Int_t mDirection; ///< Layer direction 0=Forward 1 = Backward + std::string mLayerName; ///< Current layer name + Double_t mInnerRadius; ///< Inner radius of this layer + Double_t mOuterRadius; ///< Outer radius of this layer + Double_t mZ; ///< Z position of the layer + Double_t mChipThickness; ///< Chip thickness + Double_t mx2X0; ///< Layer material budget x/X0 + + ClassDefOverride(FT3Layer, 0); // ALICE 3 EndCaps geometry +}; +} // namespace ft3 +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx new file mode 100644 index 0000000000000..c80c00a3ca680 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx @@ -0,0 +1,587 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Detector.cxx +/// \brief Implementation of the Detector class + +#include "ITSMFTSimulation/Hit.h" +#include "FT3Base/GeometryTGeo.h" +#include "FT3Simulation/Detector.h" +#include "FT3Simulation/FT3Layer.h" +#include "FT3Base/FT3BaseParam.h" + +#include "SimulationDataFormat/Stack.h" +#include "SimulationDataFormat/TrackReference.h" + +// FairRoot includes +#include "FairDetector.h" // for FairDetector +#include "FairLogger.h" // for LOG, LOG_IF +#include "FairRootManager.h" // for FairRootManager +#include "FairRun.h" // for FairRun +#include "FairRuntimeDb.h" // for FairRuntimeDb +#include "FairVolume.h" // for FairVolume +#include "FairRootManager.h" + +#include "TGeoManager.h" // for TGeoManager, gGeoManager +#include "TGeoTube.h" // for TGeoTube +#include "TGeoPcon.h" // for TGeoPcon +#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly +#include "TString.h" // for TString, operator+ +#include "TVirtualMC.h" // for gMC, TVirtualMC +#include "TVirtualMCStack.h" // for TVirtualMCStack + +#include <cstdio> // for NULL, snprintf + +class FairModule; + +class TGeoMedium; + +class TParticle; + +using namespace o2::ft3; +using o2::itsmft::Hit; + +//_________________________________________________________________________________________________ +Detector::Detector() + : o2::base::DetImpl<Detector>("FT3", kTRUE), + mTrackData(), + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) +{ +} + +//_________________________________________________________________________________________________ +void Detector::buildFT3FromFile(std::string configFileName) +{ + // Geometry description from file. One line per disk + // z_layer r_in r_out Layerx2X0 + // This simple file reader is not failproof. Do not add empty lines! + + /* + # Sample MFT configuration + # z_layer r_in r_out Layerx2X0 + -45.3 2.5 9.26 0.0042 + -46.7 2.5 9.26 0.0042 + -48.6 2.5 9.8 0.0042 + -50.0 2.5 9.8 0.0042 + -52.4 2.5 10.43 0.0042 + -53.8 2.5 10.43 0.0042 + -67.7 3.82 13.01 0.0042 + -69.1 3.82 13.01 0.0042 + -76.1 3.92 14.35 0.0042 + -77.5 3.92 14.35 0.0042 + */ + + mLayerName.clear(); + mLayers.clear(); + mLayerID.clear(); + mLayerName.resize(1); + mLayers.resize(1); + + LOG(INFO) << "Building FT3 Detector: From file"; + LOG(INFO) << " FT3 detector configuration: " << configFileName; + std::ifstream ifs(configFileName.c_str()); + if (!ifs.good()) { + LOG(FATAL) << " Invalid FT3Base.configFile!"; + } + std::string tempstr; + float z_layer, r_in, r_out, Layerx2X0; + char delimiter; + int layerNumber = 0; + while (std::getline(ifs, tempstr)) { + if (tempstr[0] == '#') { + LOG(INFO) << " Comment: " << tempstr; + continue; + } + std::istringstream iss(tempstr); + iss >> z_layer; + iss >> r_in; + iss >> r_out; + iss >> Layerx2X0; + + std::string layerName = GeometryTGeo::getFT3LayerPattern() + std::string("_") + std::to_string(layerNumber); + mLayerName[0].push_back(layerName); + LOG(INFO) << "Adding Layer " << layerName << " at z = " << z_layer << " ; r_in = " << r_in << " ; r_out = " << r_out << " x/X0 = " << Layerx2X0; + auto& thisLayer = mLayers[0].emplace_back(0, layerNumber, layerName, z_layer, r_in, r_out, Layerx2X0); + layerNumber++; + } + + mNumberOfLayers = layerNumber; + LOG(INFO) << " Loaded FT3 Detector with " << mNumberOfLayers << " layers"; +} + +//_________________________________________________________________________________________________ +void Detector::exportLayout() +{ + // Export FT3 Layout description to file. One line per disk + // z_layer r_in r_out Layerx2X0 + + std::string configFileName = "FT3_layout.cfg"; + + LOG(INFO) << "Exporting FT3 Detector layout to " << configFileName; + + std::ofstream fOut(configFileName.c_str(), std::ios::out); + if (!fOut) { + printf("Cannot open file\n"); + return; + } + fOut << "# z_layer r_in r_out Layerx2X0" << std::endl; + for (auto layers_dir : mLayers) { + for (auto layer : layers_dir) { + fOut << layer.getZ() << " " << layer.getInnerRadius() << " " << layer.getOuterRadius() << " " << layer.getx2X0() << std::endl; + } + } +} + +//_________________________________________________________________________________________________ +void Detector::buildBasicFT3(const FT3BaseParam& param) +{ + // Build a basic parametrized FT3 detector with nLayers equally spaced between z_first and z_first+z_length + // Covering pseudo rapidity [etaIn,etaOut]. Silicon thinkness computed to match layer x/X0 + + LOG(INFO) << "Building FT3 Detector: Conical Telescope"; + + auto z_first = param.z0; + auto z_length = param.zLength; + auto etaIn = param.etaIn; + auto etaOut = param.etaOut; + auto Layerx2X0 = param.Layerx2X0; + mNumberOfLayers = param.nLayers; + mLayerName.resize(2); + mLayerName[0].resize(mNumberOfLayers); + mLayerName[1].resize(mNumberOfLayers); + mLayerID.clear(); + mLayers.resize(2); + + for (Int_t direction : {0, 1}) { + for (Int_t layerNumber = 0; layerNumber < mNumberOfLayers; layerNumber++) { + std::string layerName = GeometryTGeo::getFT3LayerPattern() + std::to_string(layerNumber + mNumberOfLayers * direction); + mLayerName[direction][layerNumber] = layerName; + + // Adds evenly spaced layers + Float_t layerZ = z_first + (layerNumber * z_length / (mNumberOfLayers - 1)) * std::copysign(1, z_first); + Float_t rIn = std::abs(layerZ * std::tan(2.f * std::atan(std::exp(-etaIn)))); + Float_t rOut = std::abs(layerZ * std::tan(2.f * std::atan(std::exp(-etaOut)))); + auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, layerZ, rIn, rOut, Layerx2X0); + } + } +} + +//_________________________________________________________________________________________________ +void Detector::buildFT3V1() +{ + //Build FT3 detector according to + //https://indico.cern.ch/event/992488/contributions/4174473/attachments/2168881/3661331/tracker_parameters_werner_jan_11_2021.pdf + + LOG(INFO) << "Building FT3 Detector: V1"; + + mNumberOfLayers = 10; + Float_t sensorThickness = 30.e-4; + Float_t layersx2X0 = 1.e-2; + std::vector<std::array<Float_t, 5>> layersConfig{ + {26., .5, 3., 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} + {30., .5, 3., 0.1f * layersx2X0}, + {34., .5, 3., 0.1f * layersx2X0}, + {77., 3.5, 35., layersx2X0}, + {100., 3.5, 35., layersx2X0}, + {122., 3.5, 35., layersx2X0}, + {150., 3.5, 100., layersx2X0}, + {180., 3.5, 100., layersx2X0}, + {220., 3.5, 100., layersx2X0}, + {279., 3.5, 100., layersx2X0}}; + + mLayerName.resize(2); + mLayerName[0].resize(mNumberOfLayers); + mLayerName[1].resize(mNumberOfLayers); + mLayerID.clear(); + mLayers.resize(2); + + for (auto direction : {0, 1}) { + for (int layerNumber = 0; layerNumber < mNumberOfLayers; layerNumber++) { + std::string directionName = std::to_string(direction); + std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); + mLayerName[direction][layerNumber] = layerName; + auto& z = layersConfig[layerNumber][0]; + + auto& rIn = layersConfig[layerNumber][1]; + auto& rOut = layersConfig[layerNumber][2]; + auto& x0 = layersConfig[layerNumber][3]; + + LOG(INFO) << "Adding Layer " << layerName << " at z = " << z; + // Add layers + auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0); + } + } +} + +//_________________________________________________________________________________________________ +Detector::Detector(Bool_t active) + : o2::base::DetImpl<Detector>("FT3", active), + mTrackData(), + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) +{ + + // FT3 Base configuration parameters + auto& ft3BaseParam = FT3BaseParam::Instance(); + + if (ft3BaseParam.configFile != "") { + LOG(INFO) << "FT3 Geometry configuration file provided. Overriding FT3Base.geoModel configuration."; + buildFT3FromFile(ft3BaseParam.configFile); + + } else { + switch (ft3BaseParam.geoModel) { + case Default: + buildFT3V1(); // FT3V1 + break; + case Telescope: + buildBasicFT3(ft3BaseParam); // BasicFT3 = Parametrized telescopic detector (equidistant layers) + break; + default: + LOG(FATAL) << "Invalid Geometry.\n"; + break; + } + } + exportLayout(); +} + +//_________________________________________________________________________________________________ +Detector::Detector(const Detector& rhs) + : o2::base::DetImpl<Detector>(rhs), + mTrackData(), + + /// Container for data points + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) +{ + mLayerID = rhs.mLayerID; + mLayerName = rhs.mLayerName; + mNumberOfLayers = rhs.mNumberOfLayers; +} + +//_________________________________________________________________________________________________ +Detector::~Detector() +{ + + if (mHits) { + // delete mHits; + o2::utils::freeSimVector(mHits); + } +} + +//_________________________________________________________________________________________________ +Detector& Detector::operator=(const Detector& rhs) +{ + // The standard = operator + // Inputs: + // Detector &h the sourse of this copy + // Outputs: + // none. + // Return: + // A copy of the sourse hit h + + if (this == &rhs) { + return *this; + } + + // base class assignment + base::Detector::operator=(rhs); + + mLayerID = rhs.mLayerID; + mLayerName = rhs.mLayerName; + mNumberOfLayers = rhs.mNumberOfLayers; + mLayers = rhs.mLayers; + mTrackData = rhs.mTrackData; + + /// Container for data points + mHits = nullptr; + + return *this; +} + +//_________________________________________________________________________________________________ +void Detector::InitializeO2Detector() +{ + // Define the list of sensitive volumes + LOG(INFO) << "Initialize FT3 O2Detector"; + + mGeometryTGeo = GeometryTGeo::Instance(); + + defineSensitiveVolumes(); +} + +//_________________________________________________________________________________________________ +Bool_t Detector::ProcessHits(FairVolume* vol) +{ + // This method is called from the MC stepping + if (!(fMC->TrackCharge())) { + return kFALSE; + } + + Int_t lay = 0, volID = vol->getMCid(); + while ((lay <= mLayerID.size()) && (volID != mLayerID[lay])) { + ++lay; + } + + auto stack = (o2::data::Stack*)fMC->GetStack(); + + bool startHit = false, stopHit = false; + unsigned char status = 0; + if (fMC->IsTrackEntering()) { + status |= Hit::kTrackEntering; + } + if (fMC->IsTrackInside()) { + status |= Hit::kTrackInside; + } + if (fMC->IsTrackExiting()) { + status |= Hit::kTrackExiting; + } + if (fMC->IsTrackOut()) { + status |= Hit::kTrackOut; + } + if (fMC->IsTrackStop()) { + status |= Hit::kTrackStopped; + } + if (fMC->IsTrackAlive()) { + status |= Hit::kTrackAlive; + } + + // track is entering or created in the volume + if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { + startHit = true; + } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { + stopHit = true; + } + + // increment energy loss at all steps except entrance + if (!startHit) { + mTrackData.mEnergyLoss += fMC->Edep(); + } + if (!(startHit | stopHit)) { + return kFALSE; // do noting + } + if (startHit) { + mTrackData.mEnergyLoss = 0.; + fMC->TrackMomentum(mTrackData.mMomentumStart); + fMC->TrackPosition(mTrackData.mPositionStart); + mTrackData.mTrkStatusStart = status; + mTrackData.mHitStarted = true; + } + if (stopHit) { + TLorentzVector positionStop; + fMC->TrackPosition(positionStop); + // Retrieve the indices with the volume path + int chipindex = lay; + + Hit* p = addHit(stack->GetCurrentTrackNumber(), chipindex, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), + mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); + // p->SetTotalEnergy(vmc->Etot()); + + // RS: not sure this is needed + // Increment number of Detector det points in TParticle + stack->addHit(GetDetId()); + } + + return kTRUE; +} + +//_________________________________________________________________________________________________ +void Detector::createMaterials() +{ + Int_t ifield = 2; + Float_t fieldm = 10.0; + o2::base::Detector::initFieldTrackingParams(ifield, fieldm); + + Float_t tmaxfdSi = 0.1; // .10000E+01; // Degree + Float_t stemaxSi = 0.0075; // .10000E+01; // cm + Float_t deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 + Float_t epsilSi = 1.0E-4; // .10000E+01; + Float_t stminSi = 0.0; // cm "Default value used" + + Float_t tmaxfdAir = 0.1; // .10000E+01; // Degree + Float_t stemaxAir = .10000E+01; // cm + Float_t deemaxAir = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 + Float_t epsilAir = 1.0E-4; // .10000E+01; + Float_t stminAir = 0.0; // cm "Default value used" + + // AIR + Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; + Float_t zAir[4] = {6., 7., 8., 18.}; + Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; + Float_t dAir = 1.20479E-3; + + o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir); + o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir); + + o2::base::Detector::Material(3, "SI$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03); + o2::base::Detector::Medium(3, "SI$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); +} + +//_________________________________________________________________________________________________ +void Detector::EndOfEvent() { Reset(); } + +//_________________________________________________________________________________________________ +void Detector::Register() +{ + // This will create a branch in the output tree called Hit, setting the last + // parameter to kFALSE means that this collection will not be written to the file, + // it will exist only during the simulation + + if (FairRootManager::Instance()) { + FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); + } +} + +//_________________________________________________________________________________________________ +void Detector::Reset() +{ + if (!o2::utils::ShmManager::Instance().isOperational()) { + mHits->clear(); + } +} + +//_________________________________________________________________________________________________ +void Detector::ConstructGeometry() +{ + // Create detector materials + createMaterials(); + + // Construct the detector geometry + createGeometry(); +} + +//_________________________________________________________________________________________________ +void Detector::createGeometry() +{ + + mGeometryTGeo = GeometryTGeo::Instance(); + + TGeoVolume* volFT3 = new TGeoVolumeAssembly(GeometryTGeo::getFT3VolPattern()); + TGeoVolume* volIFT3 = new TGeoVolumeAssembly(GeometryTGeo::getFT3InnerVolPattern()); + + LOG(INFO) << "GeometryBuilder::buildGeometry volume name = " << GeometryTGeo::getFT3VolPattern(); + + TGeoVolume* vALIC = gGeoManager->GetVolume("barrel"); + if (!vALIC) { + LOG(FATAL) << "Could not find the top volume"; + } + + TGeoVolume* A3IPvac = gGeoManager->GetVolume("OUT_PIPEVACUUM"); + if (!A3IPvac) { + LOG(INFO) << "Running simulation with no beam pipe."; + } + + LOG(DEBUG) << "FT3 createGeometry: " + << Form("gGeoManager name is %s title is %s", gGeoManager->GetName(), gGeoManager->GetTitle()); + + if (mLayers.size() == 2) { // V1 and telescope + if (!A3IPvac) { + for (Int_t direction : {0, 1}) { // Backward layers at mLayers[0]; Forward layers at mLayers[1] + std::string directionString = direction ? "Forward" : "Backward"; + LOG(INFO) << "Creating FT3 " << directionString << " layers:"; + for (Int_t iLayer = 0; iLayer < mLayers[direction].size(); iLayer++) { + mLayers[direction][iLayer].createLayer(volFT3); + } + } + vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); + } else { // If beampipe is enabled append inner disks to beampipe filling volume, this should be temporary. + for (Int_t direction : {0, 1}) { + std::string directionString = direction ? "Forward" : "Backward"; + LOG(INFO) << "Creating FT3 " << directionString << " layers:"; + for (Int_t iLayer = 0; iLayer < mLayers[direction].size(); iLayer++) { + if (iLayer < 3) { + mLayers[direction][iLayer].createLayer(volIFT3); + } else { + mLayers[direction][iLayer].createLayer(volFT3); + } + } + } + A3IPvac->AddNode(volIFT3, 2, new TGeoTranslation(0., 0., 0.)); + vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); + } + + for (auto direction : {0, 1}) { + std::string directionString = direction ? "Forward" : "Backward"; + LOG(INFO) << "Registering FT3 " << directionString << " LayerIDs:"; + for (int iLayer = 0; iLayer < mLayers[direction].size(); iLayer++) { + auto layerID = gMC ? TVirtualMC::GetMC()->VolId(Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), direction, iLayer)) : 0; + mLayerID.push_back(layerID); + LOG(INFO) << " " << directionString << " layer " << iLayer << " LayerID " << layerID; + } + } + } + + if (mLayers.size() == 1) { // All layers registered at mLayers[0], used when building from file + LOG(INFO) << "Creating FT3 layers:"; + if (A3IPvac) { + for (Int_t iLayer = 0; iLayer < mLayers[0].size(); iLayer++) { + if (std::abs(mLayers[0][iLayer].getZ()) < 25) { + mLayers[0][iLayer].createLayer(volIFT3); + } else { + mLayers[0][iLayer].createLayer(volFT3); + } + } + A3IPvac->AddNode(volIFT3, 2, new TGeoTranslation(0., 0., 0.)); + vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); + } else { + for (Int_t iLayer = 0; iLayer < mLayers[0].size(); iLayer++) { + mLayers[0][iLayer].createLayer(volFT3); + } + vALIC->AddNode(volFT3, 2, new TGeoTranslation(0., 30., 0.)); + } + LOG(INFO) << "Registering FT3 LayerIDs:"; + for (int iLayer = 0; iLayer < mLayers[0].size(); iLayer++) { + auto layerID = gMC ? TVirtualMC::GetMC()->VolId(Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), 0, iLayer)) : 0; + mLayerID.push_back(layerID); + LOG(INFO) << " mLayerID[" << iLayer << "] = " << layerID; + } + } +} + +//_________________________________________________________________________________________________ +void Detector::defineSensitiveVolumes() +{ + TGeoManager* geoManager = gGeoManager; + TGeoVolume* v; + + TString volumeName; + LOG(INFO) << "Adding FT3 Sensitive Volumes"; + + // The names of the FT3 sensitive volumes have the format: FT3Sensor_(0,1)_(0...sNumberLayers-1) + if (mLayers.size() == 2) { + for (Int_t direction : {0, 1}) { + for (Int_t iLayer = 0; iLayer < mNumberOfLayers; iLayer++) { + volumeName = o2::ft3::GeometryTGeo::getFT3SensorPattern() + std::to_string(iLayer); + v = geoManager->GetVolume(Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), direction, iLayer)); + LOG(INFO) << "Adding FT3 Sensitive Volume => " << v->GetName(); + AddSensitiveVolume(v); + } + } + } + + if (mLayers.size() == 1) { + for (Int_t iLayer = 0; iLayer < mLayers[0].size(); iLayer++) { + volumeName = o2::ft3::GeometryTGeo::getFT3SensorPattern() + std::to_string(iLayer); + v = geoManager->GetVolume(Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), 0, iLayer)); + LOG(INFO) << "Adding FT3 Sensitive Volume => " << v->GetName(); + AddSensitiveVolume(v); + } + } +} + +//_________________________________________________________________________________________________ +Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, + unsigned char endStatus) +{ + mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); + return &(mHits->back()); +} + +ClassImp(o2::ft3::Detector); diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx new file mode 100644 index 0000000000000..867d62492067b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file FT3Layer.cxx +/// \brief Implementation of the FT3Layer class +/// \author Mario Sitta <sitta@to.infn.it> +/// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) + +#include "FT3Simulation/FT3Layer.h" +#include "FT3Base/GeometryTGeo.h" +#include "FT3Simulation/Detector.h" + +#include "FairLogger.h" // for LOG + +#include <TGeoManager.h> // for TGeoManager, gGeoManager +#include <TGeoMatrix.h> // for TGeoCombiTrans, TGeoRotation, etc +#include <TGeoTube.h> // for TGeoTube, TGeoTubeSeg +#include <TGeoVolume.h> // for TGeoVolume, TGeoVolumeAssembly +#include <TGeoCompositeShape.h> // for TGeoCompositeShape +#include "TMathBase.h" // for Abs +#include <TMath.h> // for Sin, RadToDeg, DegToRad, Cos, Tan, etc + +#include <cstdio> // for snprintf + +class TGeoMedium; + +using namespace TMath; +using namespace o2::ft3; +using namespace o2::itsmft; + +ClassImp(FT3Layer); + +FT3Layer::~FT3Layer() = default; + +FT3Layer::FT3Layer(Int_t layerDirection, Int_t layerNumber, std::string layerName, Float_t z, Float_t rIn, Float_t rOut, Float_t Layerx2X0) +{ + // Creates a simple parametrized EndCap layer covering the given + // pseudorapidity range at the z layer position + mDirection = layerDirection; + mLayerNumber = layerNumber; + mLayerName = layerName; + mZ = layerDirection ? std::abs(z) : -std::abs(z); + mx2X0 = Layerx2X0; + mInnerRadius = rIn; + mOuterRadius = rOut; + auto Si_X0 = 9.5; + mChipThickness = Layerx2X0 * Si_X0; + + LOG(INFO) << "Creating FT3 Layer " << mLayerNumber << " ; direction " << mDirection; + LOG(INFO) << " Using silicon X0 = " << Si_X0 << " to emulate layer radiation length."; + LOG(INFO) << " Layer z = " << mZ << " ; R_in = " << mInnerRadius << " ; R_out = " << mOuterRadius << " ; x2X0 = " << mx2X0 << " ; ChipThickness = " << mChipThickness; +} + +void FT3Layer::createLayer(TGeoVolume* motherVolume) +{ + if (mLayerNumber >= 0) { + // Create tube, set sensitive volume, add to mother volume + + std::string chipName = o2::ft3::GeometryTGeo::getFT3ChipPattern() + std::to_string(mLayerNumber), + sensName = Form("%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), mDirection, mLayerNumber); + TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); + TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); + TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mChipThickness / 2); + + TGeoMedium* medSi = gGeoManager->GetMedium("FT3_SI$"); + TGeoMedium* medAir = gGeoManager->GetMedium("FT3_AIR$"); + + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + + LOG(INFO) << "Inserting " << sensVol->GetName() << " inside " << chipVol->GetName(); + chipVol->AddNode(sensVol, 1, nullptr); + + LOG(INFO) << "Inserting " << chipVol->GetName() << " inside " << layerVol->GetName(); + layerVol->AddNode(chipVol, 1, nullptr); + + // Finally put everything in the mother volume + auto* FwdDiskRotation = new TGeoRotation("FwdDiskRotation", 0, 0, 180); + auto* FwdDiskCombiTrans = new TGeoCombiTrans(0, 0, mZ, FwdDiskRotation); + + LOG(INFO) << "Inserting " << layerVol->GetName() << " inside " << motherVolume->GetName(); + motherVolume->AddNode(layerVol, 1, FwdDiskCombiTrans); + + return; + } +} diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h new file mode 100644 index 0000000000000..3908f9aa71e5e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3SimulationLinkDef.h @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::ft3::FT3Layer + ; +#pragma link C++ class o2::ft3::Detector + ; +#pragma link C++ class o2::base::DetImpl < o2::ft3::Detector> + ; + +#endif diff --git a/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt b/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt new file mode 100644 index 0000000000000..7333d7584a7cc --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(Alice3DetectorsPassive + SOURCES src/Pipe.cxx + src/PassiveBase.cxx + PUBLIC_LINK_LIBRARIES O2::Field O2::DetectorsBase O2::SimConfig) + +o2_target_root_dictionary(Alice3DetectorsPassive + HEADERS include/Alice3DetectorsPassive/Pipe.h + include/Alice3DetectorsPassive/PassiveBase.h + LINKDEF src/PassiveLinkDef.h) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBase.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBase.h new file mode 100644 index 0000000000000..47a915ffe3077 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBase.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICE3_PASSIVE_BASE_H +#define ALICE3_PASSIVE_BASE_H + +#include "FairModule.h" // for FairModule + +namespace o2 +{ +namespace passive +{ + +/// a common base class for passive modules - implementing generic functions +class Alice3PassiveBase : public FairModule +{ + public: + using FairModule::FairModule; + void SetSpecialPhysicsCuts() override; + + ClassDefOverride(Alice3PassiveBase, 1); +}; + +} // namespace passive +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h new file mode 100644 index 0000000000000..80d9d58f95d4a --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICE3_PASSIVE_PIPE_H +#define ALICE3_PASSIVE_PIPE_H + +#include "Rtypes.h" +#include "Alice3DetectorsPassive/PassiveBase.h" + +namespace o2 +{ +namespace passive +{ +class Alice3Pipe : public Alice3PassiveBase +{ + public: + Alice3Pipe(); + ~Alice3Pipe() override; + Alice3Pipe(const char* name, + const char* title = "Alice 3 Pipe", + const bool isTRKActivated = false, + const float rMinInnerPipe = 0.f, + const float innerThickness = 0.f, + const float innerLength = 0.f, + const float rMinOuterPipe = 0.f, + const float outerThickness = 0.f, + const float outerLength = 0.f); + + void ConstructGeometry() override; + + /// Clone this object (used in MT mode only) + FairModule* CloneModule() const override; + + float getInnerRmin() const { return mBeInnerPipeRmin; } + float getInnerRmax() const { return mBeInnerPipeRmin + mBeInnerPipeThick; } + float getInnerWidth() const { return mBeInnerPipeThick; } + float getInnerDz() const { return mInnerIpHLength; } + + float getOuterRmin() const { return mBeOuterPipeRmin; } + float getOuterRmax() const { return mBeOuterPipeRmin + mBeOuterPipeThick; } + float getOuterWidth() const { return mBeOuterPipeThick; } + float getOuterDz() const { return mOuterIpHLength; } + + bool IsTRKActivated() const { return mIsTRKActivated; } + + private: + void createMaterials(); + Alice3Pipe(const Alice3Pipe& orig) = default; + Alice3Pipe& operator=(const Alice3Pipe&); + + float mBeInnerPipeRmin = 0.; // inner diameter of the inner Be section + float mBeInnerPipeThick = 0.; // inner beam pipe section thickness + float mInnerIpHLength = 0.; // half length of the inner beampipe around the IP + + float mBeOuterPipeRmin = 0.; // inner diameter of the outer Be section + float mBeOuterPipeThick = 0.; // outer beam pipe section thickness + float mOuterIpHLength = 0.; // half length of the outer beampipe around the IP + + bool mIsTRKActivated = true; // If TRK is not active don't create TRK layers allocations in the vacuum volume + + ClassDefOverride(Alice3Pipe, 1); +}; +} // namespace passive +} // namespace o2 +#endif diff --git a/Detectors/Upgrades/ALICE3/Passive/src/PassiveBase.cxx b/Detectors/Upgrades/ALICE3/Passive/src/PassiveBase.cxx new file mode 100644 index 0000000000000..d6c0ec2cadb6c --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/src/PassiveBase.cxx @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DetectorsBase/MaterialManager.h" +#include "Alice3DetectorsPassive/PassiveBase.h" + +using namespace o2::passive; + +void Alice3PassiveBase::SetSpecialPhysicsCuts() +{ + // default implementation for physics cuts setting (might still be overriden by detectors) + // we try to read an external text file supposed to be installed + // in a standard directory + // ${O2_ROOT}/share/Detectors/DETECTORNAME/simulation/data/simcuts.dat + LOG(INFO) << "Setting special cuts for passive module " << GetName(); + const char* aliceO2env = std::getenv("O2_ROOT"); + std::string inputFile; + if (aliceO2env) { + inputFile = std::string(aliceO2env); + } + inputFile += "/share/Detectors/Upgrades/Passive/simulation/data/simcuts_" + std::string(GetName()) + ".dat"; + auto& matmgr = o2::base::MaterialManager::Instance(); + matmgr.loadCutsAndProcessesFromFile(GetName(), inputFile.c_str()); +} diff --git a/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h b/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h new file mode 100644 index 0000000000000..bab082778a4c2 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::passive::Alice3PassiveBase + ; +#pragma link C++ class o2::passive::Alice3Pipe + ; + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx new file mode 100644 index 0000000000000..0fb0eafe6ab4d --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx @@ -0,0 +1,212 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Alice3DetectorsPassive/Pipe.h" +#include <DetectorsBase/Detector.h> +#include <DetectorsBase/MaterialManager.h> +#include <TGeoTube.h> +#include <TVirtualMC.h> +#include "TGeoManager.h" // for TGeoManager, gGeoManager +#include "TGeoMaterial.h" // for TGeoMaterial +#include "TGeoMedium.h" // for TGeoMedium +#include "TGeoVolume.h" // for TGeoVolume +#include "TGeoCompositeShape.h" // forTGeoCompositeShape +// force availability of assert +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> + +using namespace o2::passive; + +Alice3Pipe::Alice3Pipe() : Alice3PassiveBase{"Alice3PIPE", ""} {} +Alice3Pipe::Alice3Pipe(const char* name, + const char* title, + bool isTRKActivated, + float rMinInnerPipe, + float innerThickness, + float innerLength, + float rMinOuterPipe, + float outerThickness, + float outerLength) + : Alice3PassiveBase{name, title}, + mIsTRKActivated{isTRKActivated}, + mBeInnerPipeRmin{rMinInnerPipe}, + mBeInnerPipeThick{innerThickness}, + mInnerIpHLength{innerLength}, + mBeOuterPipeRmin{rMinOuterPipe}, + mBeOuterPipeThick{outerThickness}, + mOuterIpHLength{outerLength} +{ +} + +Alice3Pipe::~Alice3Pipe() = default; +Alice3Pipe& Alice3Pipe::operator=(const Alice3Pipe& rhs) +{ + // self assignment + if (this == &rhs) { + return *this; + } + + // base class assignment + Alice3PassiveBase::operator=(rhs); + + return *this; +} + +void Alice3Pipe::ConstructGeometry() +{ + createMaterials(); + // + // Class describing the beam Alice3Pipe geometry + // + float z, zsh, z0; + // + // Rotation Matrices + // + const float kDegRad = TMath::Pi() / 180.; + // Rotation by 180 deg + TGeoRotation* rot180 = new TGeoRotation("rot180", 90., 180., 90., 90., 180., 0.); + TGeoRotation* rotyz = new TGeoRotation("rotyz", 90., 180., 0., 180., 90., 90.); + TGeoRotation* rotxz = new TGeoRotation("rotxz", 0., 0., 90., 90., 90., 180.); + // + + // + // Media + auto& matmgr = o2::base::MaterialManager::Instance(); + + const TGeoMedium* kMedBe = matmgr.getTGeoMedium("ALICE3PIPE_BE"); + const TGeoMedium* kMedVac = matmgr.getTGeoMedium("ALICE3PIPE_VACUUM"); + const TGeoMedium* kMedVacNF = matmgr.getTGeoMedium("ALICE3PIPE_VACUUM_NF"); + const TGeoMedium* kMedVacHC = matmgr.getTGeoMedium("ALICE3PIPE_VACUUM_HC"); + const TGeoMedium* kMedVacNFHC = matmgr.getTGeoMedium("ALICE3PIPE_VACUUM_NFHC"); + + // Top volume + TGeoVolume* top = gGeoManager->GetVolume("cave"); + TGeoVolume* barrel = gGeoManager->GetVolume("barrel"); + if (!barrel) { + LOG(FATAL) << "Could not find the top volume"; + } + + //---------------- Outermost Be pipe around the IP ---------- + // Outer pipe has to be filled with vacuum. There we have also TRK layers, which we don't want to depend on the pipe volume. + // Eventually, we will depend on some information passed from the outside. + // For A3PIP-only simulations, we don't want TRK's shade. + // Strategy used here is to use a composite shape where shapes of TRK layers are subtracted to the vacuum volume + TGeoTube* outerBeTube = new TGeoTube("OUT_PIPEsh", mBeOuterPipeRmin, mBeOuterPipeRmin + mBeOuterPipeThick, mOuterIpHLength); + TGeoVolume* outerBeTubeVolume = new TGeoVolume("OUT_PIPE", outerBeTube, kMedBe); + outerBeTubeVolume->SetLineColor(kBlue); + + TGeoTube* outerBerylliumTubeVacuumBase = new TGeoTube("OUT_PIPEVACUUM_BASEsh", mBeInnerPipeRmin + mBeInnerPipeThick, mBeOuterPipeRmin, mOuterIpHLength); // Vacuum filling for outer pipe + TGeoCompositeShape* outerBerylliumTubeVacuumComposite; // Composite volume to subctract to vacuum + TGeoVolume* outerBerylliumTubeVacuumVolume; // Final volume to be used + + TString compositeFormula{"OUT_PIPEVACUUM_BASEsh"}; // If pipe is alone we won't subctract anything + TString subtractorsFormula; + + if (!mIsTRKActivated) { + std::vector<TGeoTube*> trkLayerShapes; + std::vector<std::array<float, 3>> layersQuotas = {std::array<float, 3>{0.5f, 50.f, 50.e-4}, // TODO: Set layers dynamically. {radius, zLen, thickness} + std::array<float, 3>{1.2f, 50.f, 50.e-4}, + std::array<float, 3>{2.5f, 50.f, 50.e-4}}; + + subtractorsFormula = "TRKLAYER_0sh"; // First volume to be subctracted (at least one has to be provided) + for (auto iLayer{0}; iLayer < layersQuotas.size(); ++iLayer) { // Create TRK layers shapes + auto& layerData = layersQuotas[iLayer]; + trkLayerShapes.emplace_back(new TGeoTube(Form("TRKLAYER_%dsh", iLayer), layerData[0], layerData[0] + layerData[2], layerData[1] / 2)); + if (iLayer > 0) { + subtractorsFormula += Form("+TRKLAYER_%dsh", iLayer); + } + } + LOG(DEBUG) << "Subtractors formula before: " << subtractorsFormula; + subtractorsFormula = Form("-(%s)", subtractorsFormula.Data()); + LOG(DEBUG) << "Subtractors formula after: " << subtractorsFormula; + + outerBerylliumTubeVacuumComposite = new TGeoCompositeShape("OUT_PIPEVACUUMsh", (compositeFormula + subtractorsFormula).Data()); + outerBerylliumTubeVacuumVolume = new TGeoVolume("OUT_PIPEVACUUM", outerBerylliumTubeVacuumComposite, kMedVac); + } else { + outerBerylliumTubeVacuumVolume = new TGeoVolume("OUT_PIPEVACUUM", outerBerylliumTubeVacuumBase, kMedVac); + } + + outerBerylliumTubeVacuumVolume->SetVisibility(1); + outerBerylliumTubeVacuumVolume->SetTransparency(50); + outerBerylliumTubeVacuumVolume->SetLineColor(kGreen); + + // outerBeTubeVolume->AddNode(outerBerylliumTubeVacuumVolume, 1, gGeoIdentity); + barrel->AddNode(outerBerylliumTubeVacuumVolume, 1, new TGeoTranslation(0, 30.f, 0)); + + barrel->AddNode(outerBeTubeVolume, 1, new TGeoTranslation(0, 30.f, 0)); // Add to surrounding geometry + + //---------------- Innermost Be pipe around the IP ---------- + TGeoTube* innerBeTube = + new TGeoTube("INN_PIPEsh", mBeInnerPipeRmin, mBeInnerPipeRmin + mBeInnerPipeThick, mInnerIpHLength); + TGeoVolume* innerBeTubeVolume = new TGeoVolume("INN_PIPE", innerBeTube, kMedBe); + innerBeTubeVolume->SetLineColor(kRed); + + TGeoTube* berylliumTubeVacuum = + new TGeoTube("INN_PIPEVACUUMsh", 0., mBeInnerPipeRmin, mInnerIpHLength); + TGeoVolume* innerBerylliumTubeVacuumVolume = new TGeoVolume("INN_PIPEVACUUM", berylliumTubeVacuum, kMedVac); + innerBerylliumTubeVacuumVolume->SetVisibility(1); + innerBerylliumTubeVacuumVolume->SetLineColor(kGreen); + + barrel->AddNode(innerBeTubeVolume, 1, new TGeoTranslation(0, 30.f, 0)); + barrel->AddNode(innerBerylliumTubeVacuumVolume, 1, new TGeoTranslation(0, 30.f, 0)); +} + +void Alice3Pipe::createMaterials() +{ + // + // Define materials for beam Alice3Pipe + // + Int_t isxfld = 2.; + float sxmgmx = 10.; + o2::base::Detector::initFieldTrackingParams(isxfld, sxmgmx); + + // + // Air + // + float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; + float zAir[4] = {6., 7., 8., 18.}; + float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; + float dAir = 1.20479E-3; + float dAir1 = 1.20479E-11; + + // **************** + // Defines tracking media parameters. + // + float epsil = .1; // Tracking precision, + float stemax = -0.01; // Maximum displacement for multiple scat + float tmaxfd = -20.; // Maximum angle due to field deflection + float deemax = -.3; // Maximum fractional energy loss, DLS + float stmin = -.8; + // *************** + + auto& matmgr = o2::base::MaterialManager::Instance(); + + // Beryllium + matmgr.Material("ALICE3PIPE", 5, "BERILLIUM$", 9.01, 4., 1.848, 35.3, 36.7); + matmgr.Medium("ALICE3PIPE", 5, "BE", 5, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + + // Vacuum + matmgr.Mixture("ALICE3PIPE", 16, "VACUUM$ ", aAir, zAir, dAir1, 4, wAir); + matmgr.Mixture("ALICE3PIPE", 36, "VACUUM$_NF", aAir, zAir, dAir1, 4, wAir); + matmgr.Mixture("ALICE3PIPE", 56, "VACUUM$_HC ", aAir, zAir, dAir1, 4, wAir); + matmgr.Mixture("ALICE3PIPE", 76, "VACUUM$_NFHC", aAir, zAir, dAir1, 4, wAir); + + matmgr.Medium("ALICE3PIPE", 16, "VACUUM", 16, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + matmgr.Medium("ALICE3PIPE", 36, "VACUUM_NF", 36, 0, 0, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + matmgr.Medium("ALICE3PIPE", 56, "VACUUM_HC", 56, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + matmgr.Medium("ALICE3PIPE", 76, "VACUUM_NFHC", 76, 0, 0, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); +} + +// ---------------------------------------------------------------------------- +FairModule* Alice3Pipe::CloneModule() const { return new Alice3Pipe(*this); } +ClassImp(o2::passive::Alice3Pipe); diff --git a/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt new file mode 100644 index 0000000000000..8851edcdd17d5 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(simulation) +add_subdirectory(base) +add_subdirectory(macros) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/README.md b/Detectors/Upgrades/ALICE3/TRK/README.md new file mode 100644 index 0000000000000..bbd4f6cb5266e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/README.md @@ -0,0 +1,22 @@ +<!-- doxy +\page refDetectorsUpgradesALICE3TRK UpgradesTRK +/doxy --> + +# TRK +At the moment the TRK name is a placeholder for silicon barrel detector. + +# Run the full simulation +Provided O2 has been compiled with upgrades enabled, it is possible to simulate TRK geometry using the `o2-sim` executable. + +## Simulation +TRK module is enabled via the `-m TRK` parameter. +New beampipe is currently represented by two cylindrical concentric beryllium pipes that cover by default the interaction point region. +It is generally configurable in the code and can be activated passing `-m A3IP` to the `o2-sim` command. + +Typical command to generate MC data: +```bash +o2-sim -m A3IP TRK [...] +``` + +## Reconstruction +Currently, the reconstruction is driven the `macro/run_trac_alice3.C`, which takes as input the hits generated by simulation. Hits can be smeared upon request (see `kUseSmearing`). diff --git a/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt new file mode 100644 index 0000000000000..9107c0fa9e812 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TRKBase + SOURCES src/MisalignmentParameter.cxx + src/GeometryTGeo.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase) + +o2_target_root_dictionary(TRKBase + HEADERS include/TRKBase/GeometryTGeo.h + include/TRKBase/MisalignmentParameter.h) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h new file mode 100644 index 0000000000000..7db4f2d724bc6 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h @@ -0,0 +1,356 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.h +/// \brief Definition of the GeometryTGeo class +/// \author cvetan.cheshkov@cern.ch - 15/02/2007 +/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 + +#ifndef ALICEO2_TRK_GEOMETRYTGEO_H_ +#define ALICEO2_TRK_GEOMETRYTGEO_H_ + +#include <TGeoMatrix.h> // for TGeoHMatrix +#include <TObject.h> // for TObject +#include <array> +#include <string> +#include <vector> +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "ITSMFTBase/GeometryTGeo.h" +#include "MathUtils/Utils.h" +#include "Rtypes.h" // for Int_t, Double_t, Bool_t, UInt_t, etc + +class TGeoPNEntry; + +namespace o2 +{ +namespace trk +{ +/// GeometryTGeo is a simple interface class to TGeoManager. It is used in the simulation +/// and reconstruction in order to query the TGeo ITS geometry. +/// RS: In order to preserve the static character of the class but make it dynamically access +/// geometry, we need to check in every method if the structures are initialized. To be converted +/// to singleton at later stage. + +class GeometryTGeo : public o2::itsmft::GeometryTGeo +{ + public: + typedef o2::math_utils::Transform3D Mat3D; + using DetMatrixCache::getMatrixL2G; + using DetMatrixCache::getMatrixT2GRot; + using DetMatrixCache::getMatrixT2L; + // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation + // it is cheaper to use T2GRot + using DetMatrixCache::getMatrixT2G; + + static GeometryTGeo* Instance() + { + // get (create if needed) a unique instance of the object + if (!sInstance) { + sInstance = std::unique_ptr<GeometryTGeo>(new GeometryTGeo(true, 0)); + } + return sInstance.get(); + } + + // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) + static void adopt(GeometryTGeo* raw); + + // constructor + // ATTENTION: this class is supposed to behave as a singleton, but to make it root-persistent + // we must define public default constructor. + // NEVER use it, it will throw exception if the class instance was already created + // Use GeometryTGeo::Instance() instead + GeometryTGeo(bool build = kFALSE, int loadTrans = 0 + /*o2::base::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, // default transformations to load + o2::math_utils::TransformType::T2G, + o2::math_utils::TransformType::L2G)*/ + ); + + /// Default destructor + ~GeometryTGeo() override = default; + + GeometryTGeo(const GeometryTGeo& src) = delete; + GeometryTGeo& operator=(const GeometryTGeo& geom) = delete; + + // implement filling of the matrix cache + using o2::itsmft::GeometryTGeo::fillMatrixCache; + void fillMatrixCache(int mask) override; + + // cache parameters of sensors tracking frames + void fillTrackingFramesCache(); + + /// Exract ITS parameters from TGeo + void Build(int loadTrans = 0) override; + + int getNumberOfChipRowsPerModule(int lay) const { return mNumberOfChipRowsPerModule[lay]; } + int getNumberOfChipColsPerModule(int lay) const + { + return mNumberOfChipRowsPerModule[lay] ? mNumberOfChipsPerModule[lay] / mNumberOfChipRowsPerModule[lay] : -1; + } + + int getNumberOfChipsPerModule(int lay) const { return mNumberOfChipsPerModule[lay]; } + int getNumberOfChipsPerHalfStave(int lay) const { return mNumberOfChipsPerHalfStave[lay]; } + int getNumberOfChipsPerStave(int lay) const { return mNumberOfChipsPerStave[lay]; } + int getNumberOfChipsPerLayer(int lay) const { return mNumberOfChipsPerLayer[lay]; } + int getNumberOfModules(int lay) const { return mNumberOfModules[lay]; } + int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } + int getNumberOfStaves(int lay) const { return mNumberOfStaves[lay]; } + int getNumberOfLayers() const { return mNumberOfLayers; } + int getChipIndex(int lay, int detInLay) const { return getFirstChipIndex(lay) + detInLay; } + /// This routine computes the chip index number from the layer, stave, and chip number in stave + /// \param int lay The layer number. Starting from 0. + /// \param int sta The stave number. Starting from 0 + /// \param int chipInStave The chip number in the stave. Starting from 0 + int getChipIndex(int lay, int sta, int detInSta) const; + + /// This routine computes the chip index number from the layer, stave, substave and chip number + /// in substave + /// \param int lay The layer number. Starting from 0. + /// \param int sta The stave number. Starting from 0 + /// \param int substa The substave number. Starting from 0 + /// \param int chipInSStave The chip number in the sub stave. Starting from 0 + int getChipIndex(int lay, int sta, int subSta, int detInSubSta) const; + + /// This routine computes the chip index number from the layer,stave, substave module and + /// chip number in module. + /// \param int lay The layer number. Starting from 0. + /// \param int sta The stave number. Starting from 0 + /// \param int substa The substave number. Starting from 0 + /// \param int module The module number ... + /// \param int chipInSStave The chip number in the module. Starting from 0 + int getChipIndex(int lay, int sta, int subSta, int md, int detInMod) const; + + /// This routine computes the layer, stave, substave, module and chip number + /// given the chip index number + /// \param int index The chip index number, starting from zero. + /// \param int lay The layer number. Starting from 0 + /// \param int sta The stave number. Starting from 0 + /// \param int ssta The halfstave number. Starting from 0 + /// \param int mod The module number. Starting from 0 + /// \param int chip The detector number. Starting from 0 + bool getChipId(int index, int& lay, int& sta, int& ssta, int& mod, int& chip) const; + + /// Get chip layer, from 0 + int getLayer(int index) const; + + /// Get chip stave, from 0 + int getStave(int index) const; + + /// Get chip substave id in stave, from 0 + int getHalfStave(int index) const; + + /// Get chip module id in substave, from 0 + int getModule(int index) const; + + /// Get chip number within layer, from 0 + int getChipIdInLayer(int index) const; + + /// Get chip number within stave, from 0 + int getChipIdInStave(int index) const; + + /// Get chip number within stave, from 0 + int getChipIdInHalfStave(int index) const; + + /// Get chip number within module, from 0 + int getChipIdInModule(int index) const; + + int getLastChipIndex(int lay) const { return mLastChipIndex[lay]; } + int getFirstChipIndex(int lay) const { return (lay == 0) ? 0 : mLastChipIndex[lay - 1] + 1; } + const char* getSymbolicName(int index) const + { + /// return symbolic name of sensor + return o2::base::GeometryManager::getSymbolicName(getDetID(), index); + } + + const char* getSymbolicName(int lay, int sta, int det) const + { + /// return symbolic name of sensor + return getSymbolicName(getChipIndex(lay, sta, det)); + } + + /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager + TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } + TGeoHMatrix* getMatrix(int lay, int sta, int sens) const { return getMatrix(getChipIndex(lay, sta, sens)); } + bool getOriginalMatrix(int index, TGeoHMatrix& m) const + { + /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' + /// The method is slow, so it should be used with great care (for caching only) + return o2::base::GeometryManager::getOriginalMatrix(getDetID(), index, m); + } + + bool getOriginalMatrix(int lay, int sta, int det, TGeoHMatrix& m) const + { + /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' + /// The method is slow, so it should be used with great care (for caching only) + return getOriginalMatrix(getChipIndex(lay, sta, det), m); + } + + const Mat3D& getMatrixT2L(int lay, int sta, int det) const { return getMatrixT2L(getChipIndex(lay, sta, det)); } + const Mat3D& getMatrixSensor(int index) const { return getMatrixL2G(index); } + const Mat3D& getMatrixSensor(int lay, int sta, int det) + { + // get positioning matrix of the sensor, alias to getMatrixL2G + return getMatrixSensor(getChipIndex(lay, sta, det)); + } + + const Rot2D& getMatrixT2GRot(int lay, int sta, int sens) + { + /// get matrix for tracking to global frame transformation + return getMatrixT2GRot(getChipIndex(lay, sta, sens)); + } + + bool isTrackingFrameCached() const { return !mCacheRefX.empty(); } + void getSensorXAlphaRefPlane(int index, float& x, float& alpha) const + { + x = getSensorRefX(index); + alpha = getSensorRefAlpha(index); + } + + float getSensorRefX(int isn) const { return mCacheRefX[isn]; } + float getSensorRefAlpha(int isn) const { return mCacheRefAlpha[isn]; } + // Attention: these are transformations wrt sensitive volume! + void localToGlobal(int index, const double* loc, double* glob); + + void localToGlobal(int lay, int sta, int det, const double* loc, double* glob); + + void globalToLocal(int index, const double* glob, double* loc); + + void globalToLocal(int lay, int sta, int det, const double* glob, double* loc); + + void localToGlobalVector(int index, const double* loc, double* glob); + + void globalToLocalVector(int index, const double* glob, double* loc); + + void Print(Option_t* opt = "") const; + + static const char* getITSVolPattern() { return sVolumeName.c_str(); } + static const char* getITSLayerPattern() { return sLayerName.c_str(); } + static const char* getITSWrapVolPattern() { return sWrapperVolumeName.c_str(); } + static const char* getITSStavePattern() { return sStaveName.c_str(); } + static const char* getITSHalfStavePattern() { return sHalfStaveName.c_str(); } + static const char* getITSModulePattern() { return sModuleName.c_str(); } + static const char* getITSChipPattern() { return sChipName.c_str(); } + static const char* getITSSensorPattern() { return sSensorName.c_str(); } + static void setITSVolPattern(const char* nm) { sVolumeName = nm; } + static void setITSLayerPattern(const char* nm) { sLayerName = nm; } + static void setITSWrapVolPattern(const char* nm) { sWrapperVolumeName = nm; } + static void setITSStavePattern(const char* nm) { sStaveName = nm; } + static void setITSHalfStavePattern(const char* nm) { sHalfStaveName = nm; } + static void setITSModulePattern(const char* nm) { sModuleName = nm; } + static void setITSChipPattern(const char* nm) { sChipName = nm; } + static void setITSSensorPattern(const char* nm) { sSensorName = nm; } + /// sym name of the layer + static const char* composeSymNameTRK() { return o2::detectors::DetID(o2::detectors::DetID::IT3).getName(); } + /// sym name of the layer + static const char* composeSymNameLayer(int lr); + + /// Sym name of the stave at given layer + static const char* composeSymNameStave(int lr, int sta); + + /// Sym name of the stave at given layer + static const char* composeSymNameHalfStave(int lr, int sta, int ssta); + + /// Sym name of the substave at given layer/stave + static const char* composeSymNameModule(int lr, int sta, int ssta, int mod); + + /// Sym name of the chip in the given layer/stave/substave/module + static const char* composeSymNameChip(int lr, int sta, int ssta, int mod, int chip); + + protected: + /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) + /// for a given chip 'index' by quering the TGeoManager + TGeoHMatrix* extractMatrixSensor(int index) const; + + // create matrix for transformation from sensor local frame to global one + TGeoHMatrix& createT2LMatrix(int isn); + + // get sensor tracking frame alpha and + void extractSensorXAlpha(int isn, float& x, float& alp); + + /// This routine computes the layer number a given the chip index + /// \param int index The chip index number, starting from zero. + /// \param int indexInLr The chip index inside a layer, starting from zero. + /// \param int lay The layer number. Starting from 0. + bool getLayer(int index, int& lay, int& index2) const; + + /// Determines the number of chips per module on the (sub)stave in the Geometry + /// Also extract the layout: span of module centers in Z and X + /// \param lay: layer number from 0 + int extractNumberOfChipsPerModule(int lay, int& nrow) const; + + /// Determines the number of layers in the Geometry + /// \param lay: layer number, starting from 0 + int extractNumberOfStaves(int lay) const; + + /// Determines the number of substaves in the stave of the layer + /// \param lay: layer number, starting from 0 + int extractNumberOfHalfStaves(int lay) const; + + /// Determines the number of modules in substave in the stave of the layer + /// \param lay: layer number, starting from 0 + /// For the setup w/o modules defined the module and the stave or the substave is the same thing + /// Legacy method, keep it just in case... + int extractNumberOfModules(int lay) const; + + /// Determines the layer detector type the Geometry and + /// returns the detector type id for the layer + /// \param lay: layer number from 0 + int extractLayerChipType(int lay) const; + + /// Determines the number of layers in the Geometry + int extractNumberOfLayers(); + + /// Extract number following the prefix in the name string + int extractVolumeCopy(const char* name, const char* prefix) const; + + TGeoPNEntry* getPNEntry(int index) const + { + /// Get a pointer to the TGeoPNEntry of a chip identified by 'index' + /// Returns NULL in case of invalid index, missing TGeoManager or invalid symbolic name + return o2::base::GeometryManager::getPNEntry(getDetID(), index); + } + + protected: + static constexpr int MAXLAYERS = 15; ///< max number of active layers + + Int_t mNumberOfLayers; ///< number of layers + std::vector<int> mNumberOfStaves; ///< number of staves/layer(layer) + std::vector<int> mNumberOfHalfStaves; ///< the number of substaves/stave(layer) + std::vector<int> mNumberOfModules; ///< number of modules/substave(layer) + std::vector<int> mNumberOfChipsPerModule; ///< number of chips per module (group of chips on substaves) + std::vector<int> mNumberOfChipRowsPerModule; ///< number of chips rows per module (relevant for OB modules) + std::vector<int> mNumberOfChipsPerHalfStave; ///< number of chips per substave + std::vector<int> mNumberOfChipsPerStave; ///< number of chips per stave + std::vector<int> mNumberOfChipsPerLayer; ///< number of chips per stave + std::vector<int> mLastChipIndex; ///< max ID of the detctor in the layer + std::array<char, MAXLAYERS> mLayerToWrapper; ///< Layer to wrapper correspondence + + std::vector<float> mCacheRefX; ///< sensors tracking plane reference X + std::vector<float> mCacheRefAlpha; ///< sensors tracking plane reference alpha + + static std::string sVolumeName; ///< Mother volume name + static std::string sLayerName; ///< Layer name + static std::string sStaveName; ///< Stave name + static std::string sHalfStaveName; ///< HalfStave name + static std::string sModuleName; ///< Module name + static std::string sChipName; ///< Chip name + static std::string sSensorName; ///< Sensor name + static std::string sWrapperVolumeName; ///< Wrapper volume name + + private: + static std::unique_ptr<o2::trk::GeometryTGeo> sInstance; ///< singletone instance + + ClassDefOverride(GeometryTGeo, 1); // ITS geometry based on TGeo +}; +} // namespace trk +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/MisalignmentParameter.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/MisalignmentParameter.h similarity index 80% rename from Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/MisalignmentParameter.h rename to Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/MisalignmentParameter.h index 3c4ea1a572c24..5b1e2fec2b13c 100644 --- a/Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/MisalignmentParameter.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/MisalignmentParameter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,8 @@ /// \file MisalignmentParameter.h /// \brief Definition of the MisalignmentParameter class -#ifndef ALICEO2_ITS4_MISALIGNMENTPARAMETER_H_ -#define ALICEO2_ITS4_MISALIGNMENTPARAMETER_H_ +#ifndef ALICEO2_TRK_MISALIGNMENTPARAMETER_H_ +#define ALICEO2_TRK_MISALIGNMENTPARAMETER_H_ #include "FairParGenericSet.h" // for FairParGenericSet @@ -24,7 +25,7 @@ class FairParamList; namespace o2 { -namespace its4 +namespace trk { class MisalignmentParameter : public FairParGenericSet { @@ -64,7 +65,7 @@ class MisalignmentParameter : public FairParGenericSet ClassDefOverride(MisalignmentParameter, 1); }; -} // namespace its4 +} // namespace trk } // namespace o2 #endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx new file mode 100644 index 0000000000000..b2e860898422a --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -0,0 +1,744 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GeometryTGeo.cxx +/// \brief Implementation of the GeometryTGeo class +/// \author cvetan.cheshkov@cern.ch - 15/02/2007 +/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 + +// ATTENTION: In opposite to old AliITSgeomTGeo, all indices start from 0, not from 1!!! + +#include "TRKBase/GeometryTGeo.h" +#include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "MathUtils/Cartesian.h" + +#include "FairLogger.h" // for LOG + +#include <TGeoBBox.h> // for TGeoBBox +#include <TGeoManager.h> // for gGeoManager, TGeoManager +#include <TGeoPhysicalNode.h> // for TGeoPNEntry, TGeoPhysicalNode +#include <TGeoShape.h> // for TGeoShape +#include <TMath.h> // for Nint, ATan2, RadToDeg +#include <TString.h> // for TString, Form +#include "TClass.h" // for TClass +#include "TGeoMatrix.h" // for TGeoHMatrix +#include "TGeoNode.h" // for TGeoNode, TGeoNodeMatrix +#include "TGeoVolume.h" // for TGeoVolume +#include "TMathBase.h" // for Max +#include "TObjArray.h" // for TObjArray +#include "TObject.h" // for TObject + +#include <cctype> // for isdigit +#include <cstdio> // for snprintf, NULL, printf +#include <cstring> // for strstr, strlen + +using namespace TMath; +using namespace o2::trk; +using namespace o2::detectors; + +using Segmentation = o2::itsmft::SegmentationAlpide; + +ClassImp(o2::trk::GeometryTGeo); + +std::unique_ptr<o2::trk::GeometryTGeo> GeometryTGeo::sInstance; + +std::string GeometryTGeo::sVolumeName = "ITSV"; ///< Mother volume name +std::string GeometryTGeo::sLayerName = "ITSULayer"; ///< Layer name +std::string GeometryTGeo::sStaveName = "ITSUStave"; ///< Stave name +std::string GeometryTGeo::sHalfStaveName = "ITSUHalfStave"; ///< HalfStave name +std::string GeometryTGeo::sModuleName = "ITSUModule"; ///< Module name +std::string GeometryTGeo::sChipName = "ITSUChip"; ///< Chip name +std::string GeometryTGeo::sSensorName = "ITSUSensor"; ///< Sensor name +std::string GeometryTGeo::sWrapperVolumeName = "ITSUWrapVol"; ///< Wrapper volume name + +//__________________________________________________________________________ +GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : o2::itsmft::GeometryTGeo(DetID::TRK) +{ + // default c-tor, if build is true, the structures will be filled and the transform matrices + // will be cached + if (sInstance) { + LOG(FATAL) << "Invalid use of public constructor: o2::trk::GeometryTGeo instance exists"; + // throw std::runtime_error("Invalid use of public constructor: o2::trk::GeometryTGeo instance exists"); + } + + for (int i = MAXLAYERS; i--;) { + mLayerToWrapper[i] = -1; + } + if (build) { + Build(loadTrans); + } +} + +//__________________________________________________________________________ +void GeometryTGeo::adopt(GeometryTGeo* raw) +{ + // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) + if (sInstance) { + LOG(FATAL) << "No adoption: o2::trk::GeometryTGeo instance exists"; + } + sInstance = std::unique_ptr<o2::trk::GeometryTGeo>(raw); +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIndex(int lay, int sta, int chipInStave) const +{ + return getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInStave; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int chipInSStave) const +{ + int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInSStave; + if (mNumberOfHalfStaves[lay] && substa > 0) { + n += mNumberOfChipsPerHalfStave[lay] * substa; + } + return n; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int md, int chipInMod) const +{ + int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInMod; + if (mNumberOfHalfStaves[lay] && substa > 0) { + n += mNumberOfChipsPerHalfStave[lay] * substa; + } + if (mNumberOfModules[lay] && md > 0) { + n += mNumberOfChipsPerModule[lay] * md; + } + return n; +} + +//__________________________________________________________________________ +bool GeometryTGeo::getLayer(int index, int& lay, int& indexInLr) const +{ + lay = getLayer(index); + indexInLr = index - getFirstChipIndex(lay); + return kTRUE; +} + +//__________________________________________________________________________ +int GeometryTGeo::getLayer(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + return lay; +} + +//__________________________________________________________________________ +int GeometryTGeo::getStave(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index / mNumberOfChipsPerStave[lay]; +} + +//__________________________________________________________________________ +int GeometryTGeo::getHalfStave(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + if (mNumberOfHalfStaves[lay] < 0) { + return -1; + } + index -= getFirstChipIndex(lay); + index %= mNumberOfChipsPerStave[lay]; + return index / mNumberOfChipsPerHalfStave[lay]; +} + +//__________________________________________________________________________ +int GeometryTGeo::getModule(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + if (mNumberOfModules[lay] < 0) { + return 0; + } + index -= getFirstChipIndex(lay); + index %= mNumberOfChipsPerStave[lay]; + if (mNumberOfHalfStaves[lay]) { + index %= mNumberOfChipsPerHalfStave[lay]; + } + return index / mNumberOfChipsPerModule[lay]; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIdInLayer(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIdInStave(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index % mNumberOfChipsPerStave[lay]; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIdInHalfStave(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index % mNumberOfChipsPerHalfStave[lay]; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChipIdInModule(int index) const +{ + int lay = 0; + while (index > mLastChipIndex[lay]) { + lay++; + } + index -= getFirstChipIndex(lay); + return index % mNumberOfChipsPerModule[lay]; +} + +//__________________________________________________________________________ +bool GeometryTGeo::getChipId(int index, int& lay, int& sta, int& hsta, int& mod, int& chip) const +{ + lay = getLayer(index); + index -= getFirstChipIndex(lay); + sta = index / mNumberOfChipsPerStave[lay]; + index %= mNumberOfChipsPerStave[lay]; + hsta = mNumberOfHalfStaves[lay] > 0 ? index / mNumberOfChipsPerHalfStave[lay] : -1; + index %= mNumberOfChipsPerHalfStave[lay]; + mod = mNumberOfModules[lay] > 0 ? index / mNumberOfChipsPerModule[lay] : -1; + chip = index % mNumberOfChipsPerModule[lay]; + + return kTRUE; +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameLayer(int lr) +{ + return Form("%s/%s%d", composeSymNameTRK(), getITSLayerPattern(), lr); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameStave(int lr, int stave) +{ + return Form("%s/%s%d", composeSymNameLayer(lr), getITSStavePattern(), stave); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameHalfStave(int lr, int stave, int substave) +{ + return substave >= 0 ? Form("%s/%s%d", composeSymNameStave(lr, stave), getITSHalfStavePattern(), substave) + : composeSymNameStave(lr, stave); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameModule(int lr, int stave, int substave, int mod) +{ + return mod >= 0 ? Form("%s/%s%d", composeSymNameHalfStave(lr, stave, substave), getITSModulePattern(), mod) + : composeSymNameHalfStave(lr, stave, substave); +} + +//__________________________________________________________________________ +const char* GeometryTGeo::composeSymNameChip(int lr, int sta, int substave, int mod, int chip) +{ + return Form("%s/%s%d", composeSymNameModule(lr, sta, substave, mod), getITSChipPattern(), chip); +} + +//__________________________________________________________________________ +TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const +{ + // extract matrix transforming from the PHYSICAL sensor frame to global one + // Note, the if the effective sensitive layer thickness is smaller than the + // total physical sensor tickness, this matrix is biased and connot be used + // directly for transformation from sensor frame to global one. + // + // Therefore we need to add a shift + + int lay, stav, sstav, mod, chipInMod; + getChipId(index, lay, stav, sstav, mod, chipInMod); + + int wrID = mLayerToWrapper[lay]; + + TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getITSVolPattern()); + + if (wrID >= 0) { + path += Form("%s%d_1/", getITSWrapVolPattern(), wrID); + } + + path += + Form("%s%d_1/%s%d_%d/", GeometryTGeo::getITSLayerPattern(), lay, GeometryTGeo::getITSStavePattern(), lay, stav); + + if (mNumberOfHalfStaves[lay] > 0) { + path += Form("%s%d_%d/", GeometryTGeo::getITSHalfStavePattern(), lay, sstav); + } + if (mNumberOfModules[lay] > 0) { + path += Form("%s%d_%d/", GeometryTGeo::getITSModulePattern(), lay, mod); + } + path += + Form("%s%d_%d/%s%d_1", GeometryTGeo::getITSChipPattern(), lay, chipInMod, GeometryTGeo::getITSSensorPattern(), lay); + + static TGeoHMatrix matTmp; + gGeoManager->PushPath(); + + if (!gGeoManager->cd(path.Data())) { + gGeoManager->PopPath(); + LOG(ERROR) << "Error in cd-ing to " << path.Data(); + return nullptr; + } // end if !gGeoManager + + matTmp = *gGeoManager->GetCurrentMatrix(); // matrix may change after cd + // RSS + // printf("%d/%d/%d %s\n",lay,stav,detInSta,path.Data()); + // mat->Print(); + // Restore the modeler state. + gGeoManager->PopPath(); + + // account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor ticknesses + static TGeoTranslation tra(0., 0.5 * (Segmentation::SensorLayerThickness - Segmentation::SensorLayerThicknessEff), 0.); + + matTmp *= tra; + + return &matTmp; +} + +//__________________________________________________________________________ +void GeometryTGeo::Build(int loadTrans) +{ + if (isBuilt()) { + LOG(WARNING) << "Already built"; + return; // already initialized + } + + if (!gGeoManager) { + // RSTODO: in future there will be a method to load matrices from the CDB + LOG(FATAL) << "Geometry is not loaded"; + } + + mNumberOfLayers = extractNumberOfLayers(); + if (!mNumberOfLayers) { + return; + } + + mNumberOfStaves.resize(mNumberOfLayers); + mNumberOfHalfStaves.resize(mNumberOfLayers); + mNumberOfModules.resize(mNumberOfLayers); + mNumberOfChipsPerModule.resize(mNumberOfLayers); + mNumberOfChipRowsPerModule.resize(mNumberOfLayers); + mNumberOfChipsPerHalfStave.resize(mNumberOfLayers); + mNumberOfChipsPerStave.resize(mNumberOfLayers); + mNumberOfChipsPerLayer.resize(mNumberOfLayers); + mLastChipIndex.resize(mNumberOfLayers); + int numberOfChips = 0; + + for (int i = 0; i < mNumberOfLayers; i++) { + mNumberOfStaves[i] = extractNumberOfStaves(i); + mNumberOfHalfStaves[i] = extractNumberOfHalfStaves(i); + mNumberOfModules[i] = extractNumberOfModules(i); + mNumberOfChipsPerModule[i] = extractNumberOfChipsPerModule(i, mNumberOfChipRowsPerModule[i]); + mNumberOfChipsPerHalfStave[i] = mNumberOfChipsPerModule[i] * Max(1, mNumberOfModules[i]); + mNumberOfChipsPerStave[i] = mNumberOfChipsPerHalfStave[i] * Max(1, mNumberOfHalfStaves[i]); + mNumberOfChipsPerLayer[i] = mNumberOfChipsPerStave[i] * mNumberOfStaves[i]; + numberOfChips += mNumberOfChipsPerLayer[i]; + mLastChipIndex[i] = numberOfChips - 1; + } + setSize(numberOfChips); + fillTrackingFramesCache(); + // + fillMatrixCache(loadTrans); +} + +//__________________________________________________________________________ +void GeometryTGeo::fillMatrixCache(int mask) +{ + // populate matrix cache for requested transformations + // + if (mSize < 1) { + LOG(WARNING) << "The method Build was not called yet"; + Build(mask); + return; + } + + // build matrices + if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) { + // Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation + LOG(INFO) << "Loading ITS L2G matrices from TGeo"; + auto& cacheL2G = getCacheL2G(); + cacheL2G.setSize(mSize); + + for (int i = 0; i < mSize; i++) { + TGeoHMatrix* hm = extractMatrixSensor(i); + cacheL2G.setMatrix(Mat3D(*hm), i); + } + } + + if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)) && !getCacheT2L().isFilled()) { + // matrices for Tracking to Local (Sensor!!! rather than the full chip) frame transformation + LOG(INFO) << "Loading ITS T2L matrices from TGeo"; + auto& cacheT2L = getCacheT2L(); + cacheT2L.setSize(mSize); + for (int i = 0; i < mSize; i++) { + TGeoHMatrix& hm = createT2LMatrix(i); + cacheT2L.setMatrix(Mat3D(hm), i); + } + } + + if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2G)) && !getCacheT2G().isFilled()) { + LOG(WARNING) << "It is faster to use 2D rotation for T2G instead of full Transform3D matrices"; + // matrices for Tracking to Global frame transformation + LOG(INFO) << "Loading ITS T2G matrices from TGeo"; + auto& cacheT2G = getCacheT2G(); + cacheT2G.setSize(mSize); + + for (int i = 0; i < mSize; i++) { + TGeoHMatrix& mat = createT2LMatrix(i); + mat.MultiplyLeft(extractMatrixSensor(i)); + cacheT2G.setMatrix(Mat3D(mat), i); + } + } + + if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)) && !getCacheT2GRot().isFilled()) { + // 2D rotation matrices for Tracking frame to Global rotations + LOG(INFO) << "Loading ITS T2G rotation 2D matrices"; + auto& cacheT2Gr = getCacheT2GRot(); + cacheT2Gr.setSize(mSize); + for (int i = 0; i < mSize; i++) { + cacheT2Gr.setMatrix(Rot2D(getSensorRefAlpha(i)), i); + } + } +} + +//__________________________________________________________________________ +void GeometryTGeo::fillTrackingFramesCache() +{ + // fill for every sensor its tracking frame parameteres + if (!isTrackingFrameCached()) { + // special cache for sensors tracking frame X and alpha params + mCacheRefX.resize(mSize); + mCacheRefAlpha.resize(mSize); + for (int i = 0; i < mSize; i++) { + extractSensorXAlpha(i, mCacheRefX[i], mCacheRefAlpha[i]); + } + } +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfLayers() +{ + // int numberOfLayers = 0; + + // TGeoVolume* itsV = gGeoManager->GetVolume(getITSVolPattern()); + // if (!itsV) { + // LOG(FATAL) << "ITS volume " << getITSVolPattern() << " is not in the geometry"; + // } + + // // Loop on all ITSV nodes, count Layer volumes by checking names + // // Build on the fly layer - wrapper correspondence + // TObjArray* nodes = itsV->GetNodes(); + // int nNodes = nodes->GetEntriesFast(); + + // for (int j = 0; j < nNodes; j++) { + // int lrID = -1; + // TGeoNode* nd = (TGeoNode*)nodes->At(j); + // const char* name = nd->GetName(); + + // if (strstr(name, getITSLayerPattern())) { + // numberOfLayers++; + // if ((lrID = extractVolumeCopy(name, GeometryTGeo::getITSLayerPattern())) < 0) { + // LOG(FATAL) << "Failed to extract layer ID from the " << name; + // exit(1); + // } + + // mLayerToWrapper[lrID] = -1; // not wrapped + // } else if (strstr(name, getITSWrapVolPattern())) { // this is a wrapper volume, may cointain layers + // int wrID = -1; + // if ((wrID = extractVolumeCopy(name, GeometryTGeo::getITSWrapVolPattern())) < 0) { + // LOG(FATAL) << "Failed to extract wrapper ID from the " << name; + // exit(1); + // } + + // TObjArray* nodesW = nd->GetNodes(); + // int nNodesW = nodesW->GetEntriesFast(); + + // for (int jw = 0; jw < nNodesW; jw++) { + // TGeoNode* ndW = (TGeoNode*)nodesW->At(jw); + // if (strstr(ndW->GetName(), getITSLayerPattern())) { + // if ((lrID = extractVolumeCopy(ndW->GetName(), GeometryTGeo::getITSLayerPattern())) < 0) { + // LOG(FATAL) << "Failed to extract layer ID from the " << name; + // exit(1); + // } + // numberOfLayers++; + // mLayerToWrapper[lrID] = wrID; + // } + // } + // } + // } + // return numberOfLayers; + return 10; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfStaves(int lay) const +{ + int numberOfStaves = 0; + char laynam[30]; + snprintf(laynam, 30, "%s%d", getITSLayerPattern(), lay); + TGeoVolume* volLr = gGeoManager->GetVolume(laynam); + if (!volLr) { + LOG(FATAL) << "can't find " << laynam << " volume"; + return -1; + } + + // Loop on all layer nodes, count Stave volumes by checking names + int nNodes = volLr->GetNodes()->GetEntries(); + for (int j = 0; j < nNodes; j++) { + // LOG(INFO) << "L" << lay << " " << j << " of " << nNodes << " " + // << volLr->GetNodes()->At(j)->GetName() << " " + // << getITSStavePattern() << " -> " << numberOfStaves; + if (strstr(volLr->GetNodes()->At(j)->GetName(), getITSStavePattern())) { + numberOfStaves++; + } + } + return numberOfStaves; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfHalfStaves(int lay) const +{ + if (sHalfStaveName.empty()) { + return 0; // for the setup w/o substave defined the stave and the substave is the same thing + } + int nSS = 0; + char stavnam[30]; + snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); + TGeoVolume* volLd = gGeoManager->GetVolume(stavnam); + if (!volLd) { + LOG(FATAL) << "can't find volume " << stavnam; + } + // Loop on all stave nodes, count Chip volumes by checking names + int nNodes = volLd->GetNodes()->GetEntries(); + for (int j = 0; j < nNodes; j++) { + if (strstr(volLd->GetNodes()->At(j)->GetName(), getITSHalfStavePattern())) { + nSS++; + } + } + return nSS; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfModules(int lay) const +{ + if (sModuleName.empty()) { + return 0; + } + + char stavnam[30]; + TGeoVolume* volLd = nullptr; + + if (!sHalfStaveName.empty()) { + snprintf(stavnam, 30, "%s%d", getITSHalfStavePattern(), lay); + volLd = gGeoManager->GetVolume(stavnam); + } + if (!volLd) { // no substaves, check staves + snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); + volLd = gGeoManager->GetVolume(stavnam); + } + if (!volLd) { + return 0; + } + + int nMod = 0; + + // Loop on all substave nodes, count module volumes by checking names + int nNodes = volLd->GetNodes()->GetEntries(); + + for (int j = 0; j < nNodes; j++) { + if (strstr(volLd->GetNodes()->At(j)->GetName(), getITSModulePattern())) { + nMod++; + } + } + return nMod; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfChipsPerModule(int lay, int& nrow) const +{ + int numberOfChips = 0; + char stavnam[30]; + TGeoVolume* volLd = nullptr; + + if (!sModuleName.empty()) { + snprintf(stavnam, 30, "%s%d", getITSModulePattern(), lay); + volLd = gGeoManager->GetVolume(stavnam); + } + if (!volLd) { // no modules on this layer, check substaves + if (!sHalfStaveName.empty()) { + snprintf(stavnam, 30, "%s%d", getITSHalfStavePattern(), lay); + volLd = gGeoManager->GetVolume(stavnam); + } + } + if (!volLd) { // no substaves on this layer, check staves + snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); + volLd = gGeoManager->GetVolume(stavnam); + } + if (!volLd) { + LOG(FATAL) << "can't find volume containing chips on layer " << lay; + } + + // Loop on all stave nodes, count Chip volumes by checking names + int nNodes = volLd->GetNodes()->GetEntries(); + + double xmin = 1e9, xmax = -1e9, zmin = 1e9, zmax = -1e9; + double lab[3], loc[3] = {0, 0, 0}; + double dx = -1, dz = -1; + + for (int j = 0; j < nNodes; j++) { + // AliInfo(Form("L%d %d of %d %s %s -> + // %d",lay,j,nNodes,volLd->GetNodes()->At(j)->GetName(),GetITSChipPattern(),numberOfChips)); + TGeoNodeMatrix* node = (TGeoNodeMatrix*)volLd->GetNodes()->At(j); + if (!strstr(node->GetName(), getITSChipPattern())) { + continue; + } + node->LocalToMaster(loc, lab); + if (lab[0] > xmax) { + xmax = lab[0]; + } + if (lab[0] < xmin) { + xmin = lab[0]; + } + if (lab[2] > zmax) { + zmax = lab[2]; + } + if (lab[2] < zmin) { + zmin = lab[2]; + } + + numberOfChips++; + + if (dx < 0) { + TGeoShape* chShape = node->GetVolume()->GetShape(); + TGeoBBox* bbox = dynamic_cast<TGeoBBox*>(chShape); + if (!bbox) { + LOG(FATAL) << "Chip " << node->GetName() << " volume is of unprocessed shape " << chShape->IsA()->GetName(); + } else { + dx = 2 * bbox->GetDX(); + dz = 2 * bbox->GetDZ(); + } + } + } + + double spanX = xmax - xmin; + double spanZ = zmax - zmin; + nrow = TMath::Nint(spanX / dx + 1); + int ncol = TMath::Nint(spanZ / dz + 1); + if (nrow * ncol != numberOfChips) { + LOG(ERROR) << "Inconsistency between Nchips=" << numberOfChips << " and Nrow*Ncol=" << nrow << "*" << ncol << "->" + << nrow * ncol << "\n" + << "Extracted chip dimensions (x,z): " << dx << " " << dz << " Module Span: " << spanX << " " << spanZ; + } + return numberOfChips; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractLayerChipType(int lay) const +{ + char stavnam[30]; + snprintf(stavnam, 30, "%s%d", getITSLayerPattern(), lay); + TGeoVolume* volLd = gGeoManager->GetVolume(stavnam); + if (!volLd) { + LOG(FATAL) << "can't find volume " << stavnam; + return -1; + } + return volLd->GetUniqueID(); +} + +//__________________________________________________________________________ +void GeometryTGeo::Print(Option_t*) const +{ + printf("NLayers:%d NChips:%d\n", mNumberOfLayers, getNumberOfChips()); + if (!isBuilt()) { + return; + } + + for (int i = 0; i < mNumberOfLayers; i++) { + printf( + "Lr%2d\tNStav:%2d\tNChips:%2d " + "(%dx%-2d)\tNMod:%d\tNSubSt:%d\tNSt:%3d\tChip#:%5d:%-5d\tWrapVol:%d\n", + i, mNumberOfStaves[i], mNumberOfChipsPerModule[i], mNumberOfChipRowsPerModule[i], + mNumberOfChipRowsPerModule[i] ? mNumberOfChipsPerModule[i] / mNumberOfChipRowsPerModule[i] : 0, + mNumberOfModules[i], mNumberOfHalfStaves[i], mNumberOfStaves[i], getFirstChipIndex(i), getLastChipIndex(i), + mLayerToWrapper[i]); + } +} + +//__________________________________________________________________________ +void GeometryTGeo::extractSensorXAlpha(int isn, float& x, float& alp) +{ + // calculate r and phi of the impact of the normal on the sensor + // (i.e. phi of the tracking frame alpha and X of the sensor in this frame) + double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; + const TGeoHMatrix* matL2G = extractMatrixSensor(isn); + + matL2G->LocalToMaster(locA, gloA); + matL2G->LocalToMaster(locB, gloB); + double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1]; + double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy); + double xp = gloB[0] - dx * t, yp = gloB[1] - dy * t; + x = Sqrt(xp * xp + yp * yp); + alp = ATan2(yp, xp); + o2::math_utils::bringTo02Pi(alp); +} + +//__________________________________________________________________________ +TGeoHMatrix& GeometryTGeo::createT2LMatrix(int isn) +{ + // create for sensor isn the TGeo matrix for Tracking to Local frame transformations + static TGeoHMatrix t2l; + float x = 0.f, alp = 0.f; + extractSensorXAlpha(isn, x, alp); + t2l.Clear(); + t2l.RotateZ(alp * RadToDeg()); // rotate in direction of normal to the sensor plane + const TGeoHMatrix* matL2G = extractMatrixSensor(isn); + const TGeoHMatrix& matL2Gi = matL2G->Inverse(); + t2l.MultiplyLeft(&matL2Gi); + return t2l; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractVolumeCopy(const char* name, const char* prefix) const +{ + TString nms = name; + if (!nms.BeginsWith(prefix)) { + return -1; + } + nms.Remove(0, strlen(prefix)); + if (!isdigit(nms.Data()[0])) { + return -1; + } + return nms.Atoi(); +} diff --git a/Detectors/Upgrades/PostLS4/IT4/base/src/MisalignmentParameter.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/MisalignmentParameter.cxx similarity index 80% rename from Detectors/Upgrades/PostLS4/IT4/base/src/MisalignmentParameter.cxx rename to Detectors/Upgrades/ALICE3/TRK/base/src/MisalignmentParameter.cxx index de5e2886c9688..b0ee2b9ca617a 100644 --- a/Detectors/Upgrades/PostLS4/IT4/base/src/MisalignmentParameter.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/MisalignmentParameter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,13 +12,13 @@ /// \file MisalignmentParameter.cxx /// \brief Implementation of the MisalignmentParameter class -#include "ITS4Base/MisalignmentParameter.h" +#include "TRKBase/MisalignmentParameter.h" #include "FairParamList.h" -using namespace o2::its4; +using namespace o2::trk; -ClassImp(o2::its4::MisalignmentParameter); +ClassImp(o2::trk::MisalignmentParameter); MisalignmentParameter::MisalignmentParameter(const char* name, const char* title, const char* context) : FairParGenericSet(name, title, context), diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h new file mode 100644 index 0000000000000..524b6431c58cf --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::trk::GeometryTGeo; +#pragma link C++ class o2::trk::MisalignmentParameter + ; + +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/ALICE3toAO2D.C b/Detectors/Upgrades/ALICE3/TRK/macros/ALICE3toAO2D.C new file mode 100644 index 0000000000000..eaf4840d1da5e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/macros/ALICE3toAO2D.C @@ -0,0 +1,671 @@ +//****************************************************************** +// ALICE 3 hits to AO2D converter tool +// +// This macro imports ALICE 3 tracker hits, runs the ITS tracker +// on them and then saves the tracks and primary vertex in a +// AO2D.root file that is compliant with the O2 framework. +// +// More specifically, it mimics Run 2-converted data so that +// any analysis geared towards that can run on the output of this +// conversion tool. +// +// To be used compiled ('root.exe -q -b ALICE3toAO2D.C+') +// +// Comments, complaints, suggestions? Please write to: +// --- david.dobrigkeit.chinellato@cern.ch +//****************************************************************** + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <string> +#include <TFile.h> +#include <TChain.h> +#include <TTree.h> +#include <TBranch.h> +#include <TH2D.h> +#include <TProfile.h> +#include <TBranch.h> +#include <TRandom3.h> +#include <TGeoGlobalMagField.h> +#include <vector> +#include <TTimeStamp.h> +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITSMFTSimulation/Hit.h" +#include "ITStracking/Configuration.h" +#include "ITStracking/IOUtils.h" +#include "ITStracking/Tracker.h" +#include "ITStracking/TrackerTraitsCPU.h" +#include "ITStracking/TimeFrame.h" +#include "ITStracking/Vertexer.h" +#include "ITStracking/VertexerTraits.h" +#include "DataFormatsITSMFT/Cluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "SimulationDataFormat/MCTrack.h" +#include "MathUtils/Cartesian.h" +#include "ReconstructionDataFormats/TrackParametrization.h" +#include "ReconstructionDataFormats/TrackParametrizationWithError.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Vertex.h" +#include "Framework/DataTypes.h" +#include "UpgradesAODUtils/Run2LikeAO2D.h" +#endif + +using o2::its::MemoryParameters; +using o2::its::TrackingParameters; +using o2::itsmft::Hit; +using std::string; + +using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; + +constexpr bool kUseSmearing{true}; + +namespace o2::upgrades_utils +{ +float getDetLengthFromEta(const float eta, const float radius) +{ + return 10. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta)))); +} + +//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +void ALICE3toAO2D() +{ + std::cout << "\e[1;31m***********************************************\e[0;00m" << std::endl; + std::cout << "\e[1;31m ALICE 3 hits to AO2D converter tool \e[0;00m" << std::endl; + std::cout << "\e[1;31m 12-layer version \e[0;00m" << std::endl; + std::cout << "\e[1;31m***********************************************\e[0;00m" << std::endl; + + std::cout << "*- Starting..." << std::endl; + const string hitsFileName = "o2sim_HitsTRK.root"; + TChain mcTree("o2sim"); + mcTree.AddFile("o2sim_Kine.root"); + mcTree.SetBranchStatus("*", 0); //disable all branches + mcTree.SetBranchStatus("MCTrack*", 1); + mcTree.SetBranchStatus("MCEventHeader.", 1); + + std::vector<o2::MCTrack>* mcArr = nullptr; + mcTree.SetBranchAddress("MCTrack", &mcArr); + + //o2::dataformats::MCEventHeader* mcHead; + //FairMCEventHeader *mcHead; + auto mcHead = new o2::dataformats::MCEventHeader; + mcTree.SetBranchAddress("MCEventHeader.", &mcHead); + + o2::its::Vertexer vertexer(new o2::its::VertexerTraits()); + + TChain itsHits("o2sim"); + + itsHits.AddFile(hitsFileName.data()); + + o2::its::TimeFrame tf; + o2::its::Tracker tracker(new o2::its::TrackerTraitsCPU(&tf)); + tracker.setBz(5.f); + + std::uint32_t roFrame; + std::vector<Hit>* hits = nullptr; + itsHits.SetBranchAddress("TRKHit", &hits); + + std::vector<TrackingParameters> trackParams(4); + + //Tracking parameters for 12 layer setup + trackParams[0].NLayers = 12; + trackParams[0].MinTrackLength = 12; //this is the one with fixed params + std::vector<float> LayerRadii = {0.5f, 1.2f, 2.5f, 3.75f, 7.0f, 12.0f, 20.0f, 30.0f, 45.0f, 60.0f, 80.0f, 100.0f}; + std::vector<float> LayerZ(12); + for (int i{0}; i < 12; ++i) + LayerZ[i] = getDetLengthFromEta(1.44, LayerRadii[i]) + 1.; + + //loosely based on run_trac_alice3.C but with extra stuff for the innermost layers + //FIXME: This may be subject to further tuning and is only a first guess + std::vector<float> TrackletMaxDeltaZ = {0.1f, 0.1f, 0.1f, 0.1f, 0.3f, 0.3f, 0.3f, 0.3f, 0.5f, 0.5f, 0.5f}; + std::vector<float> CellMaxDCA = {0.05f, 0.05f, 0.05f, 0.04f, 0.05f, 0.2f, 0.4f, 0.5f, 0.5f, 0.5f}; + std::vector<float> CellMaxDeltaZ = {0.2f, 0.2f, 0.2f, 0.4f, 0.5f, 0.6f, 3.0f, 3.0f, 3.0f, 3.0f}; + std::vector<float> NeighbourMaxDeltaCurvature = {0.012f, 0.010f, 0.008f, 0.0025f, 0.003f, 0.0035f, 0.004f, 0.004f, 0.005f}; + std::vector<float> NeighbourMaxDeltaN = {0.002f, 0.002f, 0.002f, 0.0090f, 0.002f, 0.005f, 0.005f, 0.005f, 0.005f}; + + trackParams[0].LayerRadii = LayerRadii; + trackParams[0].LayerZ = LayerZ; + trackParams[0].TrackletMaxDeltaPhi = 0.3; + trackParams[0].CellMaxDeltaPhi = 0.15; + trackParams[0].CellMaxDeltaTanLambda = 0.03; + trackParams[0].TrackletMaxDeltaZ = TrackletMaxDeltaZ; + trackParams[0].CellMaxDCA = CellMaxDCA; + trackParams[0].CellMaxDeltaZ = CellMaxDeltaZ; + trackParams[0].NeighbourMaxDeltaCurvature = NeighbourMaxDeltaCurvature; + trackParams[0].NeighbourMaxDeltaN = NeighbourMaxDeltaN; + + std::vector<MemoryParameters> memParams(4); + std::vector<float> CellsMemoryCoefficients = {2.3208e-08f * 300, 2.104e-08f * 300, 1.6432e-08f * 300, 1.2412e-08f * 300, 1.3543e-08f * 300, 1.5e-08f * 300, 1.6e-08f * 300, 1.7e-08f * 300}; + std::vector<float> TrackletsMemoryCoefficients = {0.0016353f * 15000, 0.0013627f * 15000, 0.000984f * 15000, 0.00078135f * 15000, 0.00057934f * 15000, 0.00052217f * 15000, 0.00052217f * 15000, 0.00052217f * 15000, 0.00052217f * 15000}; + memParams[0].CellsMemoryCoefficients = CellsMemoryCoefficients; + memParams[0].TrackletsMemoryCoefficients = TrackletsMemoryCoefficients; + memParams[0].MemoryOffset = 120000; + + float loosening = 3.; + for (int i = 1; i < 4; ++i) { + memParams[i] = memParams[i - 1]; + trackParams[i] = trackParams[i - 1]; + // trackParams[i].MinTrackLength -= 2; + trackParams[i].TrackletMaxDeltaPhi = trackParams[i].TrackletMaxDeltaPhi * 3 > TMath::Pi() ? TMath::Pi() : trackParams[i].TrackletMaxDeltaPhi * 3; + trackParams[i].CellMaxDeltaPhi = trackParams[i].CellMaxDeltaPhi * 3 > TMath::Pi() ? TMath::Pi() : trackParams[i].CellMaxDeltaPhi * 3; + trackParams[i].CellMaxDeltaTanLambda *= loosening; + for (auto& val : trackParams[i].TrackletMaxDeltaZ) + val *= loosening; + for (auto& val : trackParams[i].CellMaxDCA) + val *= loosening; + for (auto& val : trackParams[i].CellMaxDeltaZ) + val *= loosening; + for (auto& val : trackParams[i].NeighbourMaxDeltaCurvature) + val *= loosening; + for (auto& val : trackParams[i].NeighbourMaxDeltaN) + val *= loosening; + } + + tracker.setParameters(memParams, trackParams); + + constexpr int nBins = 100; + constexpr float minPt = 0.01; + constexpr float maxPt = 10; + double newBins[nBins + 1]; + newBins[0] = minPt; + double factor = pow(maxPt / minPt, 1. / nBins); + for (int i = 1; i <= nBins; i++) { + newBins[i] = factor * newBins[i - 1]; + } + + Double_t ptbinlimits[] = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2., 2.2, 2.4, 2.6, 2.8, 3.0, + 3.3, 3.6, 3.9, 4.2, 4.6, 5, 5.4, 5.9, 6.5, 7, 7.5, 8, 8.5, 9.2, 10, 11, 12, 13.5, 15, 17, 20}; + Long_t ptbinnumb = sizeof(ptbinlimits) / sizeof(Double_t) - 1; + + //Debug output + TH1D* hNVertices = new TH1D("hNVertices", "", 10, 0, 10); + TH1D* hNTracks = new TH1D("hNTracks", "", 100, 0, 100); + + TH1D* hPtSpectra = new TH1D("hPtSpectra", "", ptbinnumb, ptbinlimits); + TH1D* hPtSpectraFake = new TH1D("hPtSpectraFake", "", ptbinnumb, ptbinlimits); + + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + std::cout << "*- Setting up output file..." << std::endl; + // Setup output + UInt_t fCompress = 101; + int fBasketSizeEvents = 1000000; // Maximum basket size of the trees for events + int fBasketSizeTracks = 10000000; // Maximum basket size of the trees for tracks + TFile* fOutputFile = TFile::Open("AO2D.root", "RECREATE", "O2 AOD", fCompress); // File to store the trees of time frames + + //setup timestamp for output + TTimeStamp ts0(2020, 11, 1, 0, 0, 0); + TTimeStamp ts1; + UInt_t tfId = ts1.GetSec() - ts0.GetSec(); + + // Create the output directory for the current time frame + TDirectory* fOutputDir = 0x0; ///! Pointer to the output Root subdirectory + fOutputDir = fOutputFile->mkdir(Form("DF_%d", tfId)); + fOutputDir->cd(); + + //Create output trees in file + TTree* fTree[kTrees]; + for (Int_t ii = 0; ii < kTrees; ii++) { + if (gSaveTree[ii]) { + std::cout << "*- Creating tree " << gTreeName[ii] << "..." << std::endl; + fTree[ii] = new TTree(gTreeName[ii], gTreeTitle[ii]); + fTree[ii]->SetAutoFlush(0); + } + } + if (gSaveTree[kEvents]) { + fTree[kEvents]->Branch("fBCsID", &collision.fBCsID, "fBCsID/I"); + fTree[kEvents]->Branch("fPosX", &collision.fPosX, "fPosX/F"); + fTree[kEvents]->Branch("fPosY", &collision.fPosY, "fPosY/F"); + fTree[kEvents]->Branch("fPosZ", &collision.fPosZ, "fPosZ/F"); + fTree[kEvents]->Branch("fCovXX", &collision.fCovXX, "fCovXX/F"); + fTree[kEvents]->Branch("fCovXY", &collision.fCovXY, "fCovXY/F"); + fTree[kEvents]->Branch("fCovXZ", &collision.fCovXZ, "fCovXZ/F"); + fTree[kEvents]->Branch("fCovYY", &collision.fCovYY, "fCovYY/F"); + fTree[kEvents]->Branch("fCovYZ", &collision.fCovYZ, "fCovYZ/F"); + fTree[kEvents]->Branch("fCovZZ", &collision.fCovZZ, "fCovZZ/F"); + fTree[kEvents]->Branch("fChi2", &collision.fChi2, "fChi2/F"); + fTree[kEvents]->Branch("fNumContrib", &collision.fN, "fNumContrib/i"); + fTree[kEvents]->Branch("fCollisionTime", &collision.fCollisionTime, "fCollisionTime/F"); + fTree[kEvents]->Branch("fCollisionTimeRes", &collision.fCollisionTimeRes, "fCollisionTimeRes/F"); + fTree[kEvents]->Branch("fCollisionTimeMask", &collision.fCollisionTimeMask, "fCollisionTimeMask/b"); + fTree[kEvents]->SetBasketSize("*", fBasketSizeEvents); + } + + if (gSaveTree[kTracks]) { + fTree[kTracks]->Branch("fCollisionsID", &tracks.fCollisionsID, "fCollisionsID/I"); + fTree[kTracks]->Branch("fTrackType", &tracks.fTrackType, "fTrackType/b"); + // fTree[kTracks]->Branch("fTOFclsIndex", &tracks.fTOFclsIndex, "fTOFclsIndex/I"); + // fTree[kTracks]->Branch("fNTOFcls", &tracks.fNTOFcls, "fNTOFcls/I"); + fTree[kTracks]->Branch("fX", &tracks.fX, "fX/F"); + fTree[kTracks]->Branch("fAlpha", &tracks.fAlpha, "fAlpha/F"); + fTree[kTracks]->Branch("fY", &tracks.fY, "fY/F"); + fTree[kTracks]->Branch("fZ", &tracks.fZ, "fZ/F"); + fTree[kTracks]->Branch("fSnp", &tracks.fSnp, "fSnp/F"); + fTree[kTracks]->Branch("fTgl", &tracks.fTgl, "fTgl/F"); + fTree[kTracks]->Branch("fSigned1Pt", &tracks.fSigned1Pt, "fSigned1Pt/F"); + // Modified covariance matrix + fTree[kTracks]->Branch("fSigmaY", &tracks.fSigmaY, "fSigmaY/F"); + fTree[kTracks]->Branch("fSigmaZ", &tracks.fSigmaZ, "fSigmaZ/F"); + fTree[kTracks]->Branch("fSigmaSnp", &tracks.fSigmaSnp, "fSigmaSnp/F"); + fTree[kTracks]->Branch("fSigmaTgl", &tracks.fSigmaTgl, "fSigmaTgl/F"); + fTree[kTracks]->Branch("fSigma1Pt", &tracks.fSigma1Pt, "fSigma1Pt/F"); + fTree[kTracks]->Branch("fRhoZY", &tracks.fRhoZY, "fRhoZY/B"); + fTree[kTracks]->Branch("fRhoSnpY", &tracks.fRhoSnpY, "fRhoSnpY/B"); + fTree[kTracks]->Branch("fRhoSnpZ", &tracks.fRhoSnpZ, "fRhoSnpZ/B"); + fTree[kTracks]->Branch("fRhoTglY", &tracks.fRhoTglY, "fRhoTglY/B"); + fTree[kTracks]->Branch("fRhoTglZ", &tracks.fRhoTglZ, "fRhoTglZ/B"); + fTree[kTracks]->Branch("fRhoTglSnp", &tracks.fRhoTglSnp, "fRhoTglSnp/B"); + fTree[kTracks]->Branch("fRho1PtY", &tracks.fRho1PtY, "fRho1PtY/B"); + fTree[kTracks]->Branch("fRho1PtZ", &tracks.fRho1PtZ, "fRho1PtZ/B"); + fTree[kTracks]->Branch("fRho1PtSnp", &tracks.fRho1PtSnp, "fRho1PtSnp/B"); + fTree[kTracks]->Branch("fRho1PtTgl", &tracks.fRho1PtTgl, "fRho1PtTgl/B"); + // + fTree[kTracks]->Branch("fTPCInnerParam", &tracks.fTPCinnerP, "fTPCInnerParam/F"); + fTree[kTracks]->Branch("fFlags", &tracks.fFlags, "fFlags/i"); + fTree[kTracks]->Branch("fITSClusterMap", &tracks.fITSClusterMap, "fITSClusterMap/b"); + fTree[kTracks]->Branch("fTPCNClsFindable", &tracks.fTPCNClsFindable, "fTPCNClsFindable/b"); + fTree[kTracks]->Branch("fTPCNClsFindableMinusFound", &tracks.fTPCNClsFindableMinusFound, "fTPCNClsFindableMinusFound/B"); + fTree[kTracks]->Branch("fTPCNClsFindableMinusCrossedRows", &tracks.fTPCNClsFindableMinusCrossedRows, "fTPCNClsFindableMinusCrossedRows/B"); + fTree[kTracks]->Branch("fTPCNClsShared", &tracks.fTPCNClsShared, "fTPCNClsShared/b"); + fTree[kTracks]->Branch("fTRDPattern", &tracks.fTRDPattern, "fTRDPattern/b"); + fTree[kTracks]->Branch("fITSChi2NCl", &tracks.fITSChi2NCl, "fITSChi2NCl/F"); + fTree[kTracks]->Branch("fTPCChi2NCl", &tracks.fTPCChi2NCl, "fTPCChi2NCl/F"); + fTree[kTracks]->Branch("fTRDChi2", &tracks.fTRDChi2, "fTRDChi2/F"); + fTree[kTracks]->Branch("fTOFChi2", &tracks.fTOFChi2, "fTOFChi2/F"); + fTree[kTracks]->Branch("fTPCSignal", &tracks.fTPCSignal, "fTPCSignal/F"); + fTree[kTracks]->Branch("fTRDSignal", &tracks.fTRDSignal, "fTRDSignal/F"); + fTree[kTracks]->Branch("fTOFSignal", &tracks.fTOFSignal, "fTOFSignal/F"); + fTree[kTracks]->Branch("fLength", &tracks.fLength, "fLength/F"); + fTree[kTracks]->Branch("fTOFExpMom", &tracks.fTOFExpMom, "fTOFExpMom/F"); + fTree[kTracks]->Branch("fTrackEtaEMCAL", &tracks.fTrackEtaEMCAL, "fTrackEtaEMCAL/F"); + fTree[kTracks]->Branch("fTrackPhiEMCAL", &tracks.fTrackPhiEMCAL, "fTrackPhiEMCAL/F"); + fTree[kTracks]->SetBasketSize("*", fBasketSizeTracks); + } + + if (gSaveTree[kMcTrackLabel]) { + fTree[kMcTrackLabel]->Branch("fLabel", &mctracklabel.fLabel, "fLabel/i"); + fTree[kMcTrackLabel]->Branch("fLabelMask", &mctracklabel.fLabelMask, "fLabelMask/s"); + fTree[kMcTrackLabel]->SetBasketSize("*", fBasketSizeTracks); + } + + if (gSaveTree[kMcCollision]) { + fTree[kMcCollision]->Branch("fBCsID", &mccollision.fBCsID, "fBCsID/I"); + fTree[kMcCollision]->Branch("fGeneratorsID", &mccollision.fGeneratorsID, "fGeneratorsID/S"); + fTree[kMcCollision]->Branch("fPosX", &mccollision.fPosX, "fPosX/F"); + fTree[kMcCollision]->Branch("fPosY", &mccollision.fPosY, "fPosY/F"); + fTree[kMcCollision]->Branch("fPosZ", &mccollision.fPosZ, "fPosZ/F"); + fTree[kMcCollision]->Branch("fT", &mccollision.fT, "fT/F"); + fTree[kMcCollision]->Branch("fWeight", &mccollision.fWeight, "fWeight/F"); + fTree[kMcCollision]->Branch("fImpactParameter", &mccollision.fImpactParameter, "fImpactParameter/F"); + fTree[kMcCollision]->SetBasketSize("*", fBasketSizeEvents); + } + + if (gSaveTree[kMcParticle]) { + fTree[kMcParticle]->Branch("fMcCollisionsID", &mcparticle.fMcCollisionsID, "fMcCollisionsID/I"); + fTree[kMcParticle]->Branch("fPdgCode", &mcparticle.fPdgCode, "fPdgCode/I"); + fTree[kMcParticle]->Branch("fStatusCode", &mcparticle.fStatusCode, "fStatusCode/I"); + fTree[kMcParticle]->Branch("fFlags", &mcparticle.fFlags, "fFlags/b"); + fTree[kMcParticle]->Branch("fMother0", &mcparticle.fMother0, "fMother0/I"); + fTree[kMcParticle]->Branch("fMother1", &mcparticle.fMother1, "fMother1/I"); + fTree[kMcParticle]->Branch("fDaughter0", &mcparticle.fDaughter0, "fDaughter0/I"); + fTree[kMcParticle]->Branch("fDaughter1", &mcparticle.fDaughter1, "fDaughter1/I"); + fTree[kMcParticle]->Branch("fWeight", &mcparticle.fWeight, "fWeight/F"); + + fTree[kMcParticle]->Branch("fPx", &mcparticle.fPx, "fPx/F"); + fTree[kMcParticle]->Branch("fPy", &mcparticle.fPy, "fPy/F"); + fTree[kMcParticle]->Branch("fPz", &mcparticle.fPz, "fPz/F"); + fTree[kMcParticle]->Branch("fE", &mcparticle.fE, "fE/F"); + + fTree[kMcParticle]->Branch("fVx", &mcparticle.fVx, "fVx/F"); + fTree[kMcParticle]->Branch("fVy", &mcparticle.fVy, "fVy/F"); + fTree[kMcParticle]->Branch("fVz", &mcparticle.fVz, "fVz/F"); + fTree[kMcParticle]->Branch("fVt", &mcparticle.fVt, "fVt/F"); + fTree[kMcParticle]->SetBasketSize("*", fBasketSizeTracks); + } + + if (gSaveTree[kMcCollisionLabel]) { + fTree[kMcCollisionLabel]->Branch("fLabel", &mccollisionlabel.fLabel, "fLabel/i"); + fTree[kMcCollisionLabel]->Branch("fLabelMask", &mccollisionlabel.fLabelMask, "fLabelMask/s"); + fTree[kMcCollisionLabel]->SetBasketSize("*", fBasketSizeEvents); + } + + if (gSaveTree[kBC]) { + fTree[kBC]->Branch("fRunNumber", &bc.fRunNumber, "fRunNumber/I"); + fTree[kBC]->Branch("fGlobalBC", &bc.fGlobalBC, "fGlobalBC/l"); + fTree[kBC]->Branch("fTriggerMask", &bc.fTriggerMask, "fTriggerMask/l"); + fTree[kBC]->SetBasketSize("*", fBasketSizeEvents); + } + + if (gSaveTree[kFDD]) { + fTree[kFDD]->Branch("fBCsID", &fdd.fBCsID, "fBCsID/I"); + fTree[kFDD]->Branch("fAmplitudeA", fdd.fAmplitudeA, "fAmplitudeA[4]/F"); + fTree[kFDD]->Branch("fAmplitudeC", fdd.fAmplitudeC, "fAmplitudeC[4]/F"); + fTree[kFDD]->Branch("fTimeA", &fdd.fTimeA, "fTimeA/F"); + fTree[kFDD]->Branch("fTimeC", &fdd.fTimeC, "fTimeC/F"); + fTree[kFDD]->Branch("fTriggerMask", &fdd.fTriggerMask, "fTriggerMask/b"); + fTree[kFDD]->SetBasketSize("*", fBasketSizeEvents); + } + + // Associate branches for V0A + if (gSaveTree[kFV0A]) { + fTree[kFV0A]->Branch("fBCsID", &fv0a.fBCsID, "fBCsID/I"); + fTree[kFV0A]->Branch("fAmplitude", fv0a.fAmplitude, "fAmplitude[48]/F"); + fTree[kFV0A]->Branch("fTime", &fv0a.fTime, "fTime/F"); + fTree[kFV0A]->Branch("fTriggerMask", &fv0a.fTriggerMask, "fTriggerMask/b"); + fTree[kFV0A]->SetBasketSize("*", fBasketSizeEvents); + } + + // Associate branches for V0C + if (gSaveTree[kFV0C]) { + fTree[kFV0C]->Branch("fBCsID", &fv0c.fBCsID, "fBCsID/I"); + fTree[kFV0C]->Branch("fAmplitude", fv0c.fAmplitude, "fAmplitude[32]/F"); + fTree[kFV0C]->Branch("fTime", &fv0c.fTime, "fTime/F"); + fTree[kFV0C]->SetBasketSize("*", fBasketSizeEvents); + } + + // Associate branches for FT0 + if (gSaveTree[kFT0]) { + fTree[kFT0]->Branch("fBCsID", &ft0.fBCsID, "fBCsID/I"); + fTree[kFT0]->Branch("fAmplitudeA", ft0.fAmplitudeA, "fAmplitudeA[96]/F"); + fTree[kFT0]->Branch("fAmplitudeC", ft0.fAmplitudeC, "fAmplitudeC[112]/F"); + fTree[kFT0]->Branch("fTimeA", &ft0.fTimeA, "fTimeA/F"); + fTree[kFT0]->Branch("fTimeC", &ft0.fTimeC, "fTimeC/F"); + fTree[kFT0]->Branch("fTriggerMask", &ft0.fTriggerMask, "fTriggerMask/b"); + fTree[kFT0]->SetBasketSize("*", fBasketSizeEvents); + } + + if (gSaveTree[kZdc]) { + fTree[kZdc]->Branch("fBCsID", &zdc.fBCsID, "fBCsID/I"); + fTree[kZdc]->Branch("fEnergyZEM1", &zdc.fEnergyZEM1, "fEnergyZEM1/F"); + fTree[kZdc]->Branch("fEnergyZEM2", &zdc.fEnergyZEM2, "fEnergyZEM2/F"); + fTree[kZdc]->Branch("fEnergyCommonZNA", &zdc.fEnergyCommonZNA, "fEnergyCommonZNA/F"); + fTree[kZdc]->Branch("fEnergyCommonZNC", &zdc.fEnergyCommonZNC, "fEnergyCommonZNC/F"); + fTree[kZdc]->Branch("fEnergyCommonZPA", &zdc.fEnergyCommonZPA, "fEnergyCommonZPA/F"); + fTree[kZdc]->Branch("fEnergyCommonZPC", &zdc.fEnergyCommonZPC, "fEnergyCommonZPC/F"); + fTree[kZdc]->Branch("fEnergySectorZNA", &zdc.fEnergySectorZNA, "fEnergySectorZNA[4]/F"); + fTree[kZdc]->Branch("fEnergySectorZNC", &zdc.fEnergySectorZNC, "fEnergySectorZNC[4]/F"); + fTree[kZdc]->Branch("fEnergySectorZPA", &zdc.fEnergySectorZPA, "fEnergySectorZPA[4]/F"); + fTree[kZdc]->Branch("fEnergySectorZPC", &zdc.fEnergySectorZPC, "fEnergySectorZPC[4]/F"); + fTree[kZdc]->Branch("fTimeZEM1", &zdc.fTimeZEM1, "fTimeZEM1/F"); + fTree[kZdc]->Branch("fTimeZEM2", &zdc.fTimeZEM2, "fTimeZEM2/F"); + fTree[kZdc]->Branch("fTimeZNA", &zdc.fTimeZNA, "fTimeZNA/F"); + fTree[kZdc]->Branch("fTimeZNC", &zdc.fTimeZNC, "fTimeZNC/F"); + fTree[kZdc]->Branch("fTimeZPA", &zdc.fTimeZPA, "fTimeZPA/F"); + fTree[kZdc]->Branch("fTimeZPC", &zdc.fTimeZPC, "fTimeZPC/F"); + fTree[kZdc]->SetBasketSize("*", fBasketSizeEvents); + } + + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Long_t lGoodEvents = 0; + Long_t fOffsetLabel = 0; + std::cout << "*- Number of events detected: " << itsHits.GetEntries() << std::endl; + for (int iEvent{0}; iEvent < itsHits.GetEntriesFast(); ++iEvent) { + itsHits.GetEntry(iEvent); + mcTree.GetEvent(iEvent); + o2::its::ROframe event{iEvent, 12}; + std::cout << "*- Processing event " << iEvent << "..." << std::endl; + + int id{0}; + + for (auto& hit : *hits) { + int layer{hit.GetDetectorID()}; + float xyz[3]{hit.GetX(), hit.GetY(), hit.GetZ()}; + float r{std::hypot(xyz[0], xyz[1])}; + float phi{std::atan2(-xyz[1], -xyz[0]) + o2::its::constants::math::Pi}; + + if (kUseSmearing) { + phi = gRandom->Gaus(phi, std::asin(0.0005f / r)); + xyz[0] = r * std::cos(phi); + xyz[1] = r * std::sin(phi); + xyz[2] = gRandom->Gaus(xyz[2], 0.0005f); + } + + //if you see radius + epsilon, it's still the N-th layer... likely a bug + if (r > 99.0 && r < 101) { + //std::cout << "*- Exception caught at a radius of "<< r << std::endl; + layer = 11; + } + event.addTrackingFrameInfoToLayer(layer, xyz[0], xyz[1], xyz[2], r, phi, std::array<float, 2>{0.f, xyz[2]}, + std::array<float, 3>{0.0005f * 0.0005f, 0.f, 0.0005f * 0.0005f}); + event.addClusterToLayer(layer, xyz[0], xyz[1], xyz[2], event.getClustersOnLayer(layer).size()); + // event.addClusterLabelToLayer(layer, o2::MCCompLabel(hit.GetTrackID(), iEvent, iEvent, false)); + event.addClusterExternalIndexToLayer(layer, id++); + } + roFrame = iEvent; + std::cout << "*- Event " << iEvent << " finished adding hits." << std::endl; + + vertexer.clustersToVertices(event); + + std::vector<Vertex> vertices = vertexer.exportVertices(); + std::cout << "*- Number of vertices found: " << vertices.size() << endl; + hNVertices->Fill(vertices.size()); + + tf.addPrimaryVertices(vertices); + } + + tracker.clustersToTracks(); + + for (int iROF{0}; iROF < tf.getNrof(); ++iROF) { + auto vertices{tf.getPrimaryVertices(iROF)}; + if (vertices.size() == 0) { + std::cout << "*- No primary vertex found, skipping event" << std::endl; + } + + o2::math_utils::Point3D<float> pos{vertices[0].getX(), vertices[0].getY(), vertices[0].getZ()}; + std::array<float, 6> cov; + for (Int_t jj = 0; jj < 6; jj++) + cov[jj] = vertices[0].getCov()[jj]; + o2::dataformats::VertexBase vtx(pos, cov); + o2::dataformats::DCA dca; + + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + std::cout << "*- Acquiring collision information..." << std::endl; + //---> Collision data + Long_t lEventNumber = lGoodEvents; + collision.fBCsID = fTree[kEvents]->GetEntries(); + fdd.fBCsID = collision.fBCsID; + ft0.fBCsID = collision.fBCsID; + fv0a.fBCsID = collision.fBCsID; + fv0c.fBCsID = collision.fBCsID; + zdc.fBCsID = collision.fBCsID; + collision.fPosX = vertices[0].getX(); + collision.fPosY = vertices[0].getY(); + collision.fPosZ = vertices[0].getZ(); + collision.fCovXX = cov[0]; + collision.fCovXY = cov[1]; + collision.fCovXZ = cov[2]; + collision.fCovYY = cov[3]; + collision.fCovYZ = cov[4]; + collision.fCovZZ = cov[5]; + collision.fChi2 = vertices[0].getChi2(); + collision.fN = vertices[0].getNContributors(); + collision.fCollisionTime = 10; + collision.fCollisionTimeRes = 1e-6; + ft0.fTimeA = 10; + ft0.fTimeC = 10; + + //---> MC collision data + mccollision.fBCsID = lGoodEvents; + if (!mcHead) { + std::cout << "*- Problem with MC header! " << std::endl; + return; + } + mccollision.fPosX = mcHead->GetX(); + mccollision.fPosY = mcHead->GetY(); + mccollision.fPosZ = mcHead->GetZ(); + mccollision.fT = mcHead->GetT(); + mccollision.fWeight = 1; + mccollision.fImpactParameter = mcHead->GetB(); + + mccollisionlabel.fLabel = lGoodEvents; + mccollisionlabel.fLabelMask = 0; + //---> Save fake hits on i-th layer for track + + //---> Dummy trigger mask to ensure nobody rejects this + bc.fTriggerMask = 0; + for (Int_t iii = 0; iii < 60; iii++) + bc.fTriggerMask |= 1ull << iii; + bc.fRunNumber = 246087; //ah, the good old days + + auto& lTracks = tf.getTracks(iROF); + auto& lTracksLabels = tf.getTracksLabel(iROF); + hNTracks->Fill(lTracks.size()); + + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + //---> Track data + Long_t lNTracks = lTracks.size(); + for (Int_t i = 0; i < lNTracks; i++) { + //get result from tracker + auto& lab = lTracksLabels[i]; + auto& track = lTracks[i]; + int trackID = std::abs(lab.getTrackID()); + + //Propagate to primary vertex as usual + o2::dataformats::DCA dca1; + if (!track.propagateToDCA(vtx, tracker.getBz(), &dca1)) { + std::cout << "Track propagation to primary vertex failed." << std::endl; + } + + //Fill QA histograms + hPtSpectra->Fill(track.getPt()); + if (lab.isFake()) + hPtSpectraFake->Fill(track.getPt()); + + tracks.fCollisionsID = lEventNumber; + tracks.fTrackType = o2::aod::track::TrackTypeEnum::Run2Track; //Make track selection happy, please + tracks.fFlags = 0x0; + //Assume it all worked, fool regular selections + tracks.fFlags |= o2::aod::track::TrackFlagsRun2Enum::ITSrefit; + tracks.fFlags |= o2::aod::track::TrackFlagsRun2Enum::TPCrefit; + tracks.fFlags |= o2::aod::track::TrackFlagsRun2Enum::GoldenChi2; + + //Main: X, alpha, track params + tracks.fX = track.getX(); + tracks.fY = track.getY(); + tracks.fZ = track.getZ(); + tracks.fAlpha = track.getAlpha(); + tracks.fSnp = track.getSnp(); + tracks.fTgl = track.getTgl(); + tracks.fSigned1Pt = track.getQ2Pt(); + + // diagonal elements of covariance matrix + tracks.fSigmaY = TMath::Sqrt(track.getSigmaY2()); + tracks.fSigmaZ = TMath::Sqrt(track.getSigmaZ2()); + tracks.fSigmaSnp = TMath::Sqrt(track.getSigmaSnp2()); + tracks.fSigmaTgl = TMath::Sqrt(track.getSigmaTgl2()); + tracks.fSigma1Pt = TMath::Sqrt(track.getSigma1Pt2()); + // off-diagonal elements of covariance matrix + tracks.fRhoZY = (Char_t)(128. * track.getSigmaZY() / tracks.fSigmaZ / tracks.fSigmaY); + tracks.fRhoSnpY = (Char_t)(128. * track.getSigmaSnpY() / tracks.fSigmaSnp / tracks.fSigmaY); + tracks.fRhoSnpZ = (Char_t)(128. * track.getSigmaSnpZ() / tracks.fSigmaSnp / tracks.fSigmaZ); + tracks.fRhoTglY = (Char_t)(128. * track.getSigmaTglY() / tracks.fSigmaTgl / tracks.fSigmaY); + tracks.fRhoTglZ = (Char_t)(128. * track.getSigmaTglZ() / tracks.fSigmaTgl / tracks.fSigmaZ); + tracks.fRhoTglSnp = (Char_t)(128. * track.getSigmaTglSnp() / tracks.fSigmaTgl / tracks.fSigmaSnp); + tracks.fRho1PtY = (Char_t)(128. * track.getSigma1PtY() / tracks.fSigma1Pt / tracks.fSigmaY); + tracks.fRho1PtZ = (Char_t)(128. * track.getSigma1PtZ() / tracks.fSigma1Pt / tracks.fSigmaZ); + tracks.fRho1PtSnp = (Char_t)(128. * track.getSigma1PtSnp() / tracks.fSigma1Pt / tracks.fSigmaSnp); + tracks.fRho1PtTgl = (Char_t)(128. * track.getSigma1PtTgl() / tracks.fSigma1Pt / tracks.fSigmaTgl); + + //insist it's good + tracks.fITSChi2NCl = 1.0; + tracks.fTPCChi2NCl = 1.0; + tracks.fTPCNClsFindable = (UChar_t)(120); + tracks.fTPCNClsFindableMinusFound = (Char_t)(0); + tracks.fTPCNClsFindableMinusCrossedRows = (Char_t)(0); + UChar_t fITSClusterMap = 0u; + fITSClusterMap |= 0x1 << 0; // flag manually + fITSClusterMap |= 0x1 << 1; // flag manually + tracks.fITSClusterMap = fITSClusterMap; + + //MC labels for MC use - negative, yes, but negative with offset + mctracklabel.fLabel = TMath::Abs(lab.getTrackID()) + fOffsetLabel; + mctracklabel.fLabelMask = 0; + //Tag as fake. Note: used first bit only. + if (lab.isFake()) + mctracklabel.fLabelMask = 1; + + fTree[kTracks]->Fill(); + fTree[kMcTrackLabel]->Fill(); + } + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + //---> MC stack information for de-referencing + for (Long_t iii = 0; iii < (Long_t)mcArr->size(); iii++) { + auto part = mcArr->at(iii); + + mcparticle.fMcCollisionsID = lGoodEvents; + + //Get the kinematic values of the particles + mcparticle.fPdgCode = part.GetPdgCode(); + mcparticle.fStatusCode = part.isPrimary(); + + mcparticle.fFlags = 0; + if (part.isSecondary()) + mcparticle.fFlags |= MCParticleFlags::ProducedInTransport; + + mcparticle.fMother0 = part.getMotherTrackId(); + if (mcparticle.fMother0 > -1) + mcparticle.fMother0 += fOffsetLabel; + mcparticle.fMother1 = -1; + mcparticle.fDaughter0 = part.getFirstDaughterTrackId(); + if (mcparticle.fDaughter0 > -1) + mcparticle.fDaughter0 += fOffsetLabel; + mcparticle.fDaughter1 = part.getLastDaughterTrackId(); + if (mcparticle.fDaughter1 > -1) + mcparticle.fDaughter1 += fOffsetLabel; + mcparticle.fWeight = 1; + + mcparticle.fPx = part.Px(); + mcparticle.fPy = part.Py(); + mcparticle.fPz = part.Pz(); + mcparticle.fE = part.GetEnergy(); + + mcparticle.fVx = part.Vx(); + mcparticle.fVy = part.Vy(); + mcparticle.fVz = part.Vz(); + mcparticle.fVt = part.T(); + + fTree[kMcParticle]->Fill(); + } + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Go for conversion: save info + fTree[kEvents]->Fill(); + fTree[kMcCollision]->Fill(); + fTree[kMcCollisionLabel]->Fill(); + fTree[kBC]->Fill(); + fTree[kFDD]->Fill(); + fTree[kFV0A]->Fill(); + fTree[kFV0C]->Fill(); + fTree[kFT0]->Fill(); + fTree[kZdc]->Fill(); + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + fOffsetLabel = fTree[kMcParticle]->GetEntries(); //processed total + lGoodEvents++; + } + + TFile output("conversion-output.root", "recreate"); + + //QA of conversion process: the basics + hNVertices->Write(); + hNTracks->Write(); + hPtSpectra->Write(); + hPtSpectraFake->Write(); + + fOutputDir->cd(); + fTree[kEvents]->Write(); + fTree[kBC]->Write(); + fTree[kFDD]->Write(); + fTree[kFV0A]->Write(); + fTree[kFV0C]->Write(); + fTree[kFT0]->Write(); + fTree[kZdc]->Write(); + fTree[kTracks]->Write(); + fTree[kMcTrackLabel]->Write(); + fTree[kMcParticle]->Write(); + fTree[kMcCollision]->Write(); + fTree[kMcCollisionLabel]->Write(); + + std::cout << "*- Saved " << lGoodEvents << " events with a PV (total processed: " << itsHits.GetEntries() << "). Enjoy! \U0001F596" << std::endl; +} +} // namespace o2::upgrades_utils diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/macros/CMakeLists.txt new file mode 100644 index 0000000000000..1640b69511409 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/macros/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(test) + +o2_add_test_root_macro(ALICE3toAO2D.C + PUBLIC_LINK_LIBRARIES O2::UpgradesAODUtils + O2::GPUTracking + O2::ITSMFTSimulation + LABELS its COMPILE_ONLY) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt new file mode 100644 index 0000000000000..bbfd7adac2b9e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt new file mode 100644 index 0000000000000..436196e4da2ea --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TRKSimulation + SOURCES src/V11Geometry.cxx src/V1Layer.cxx src/V3Layer.cxx + src/Detector.cxx src/V3Services.cxx + PUBLIC_LINK_LIBRARIES O2::TRKBase O2::ITSMFTSimulation + ROOT::Physics) + +o2_target_root_dictionary(TRKSimulation + HEADERS include/TRKSimulation/Detector.h + include/TRKSimulation/V1Layer.h + include/TRKSimulation/V3Layer.h + include/TRKSimulation/V11Geometry.h + include/TRKSimulation/V3Services.h + ) + +o2_data_file(COPY data DESTINATION Detectors/TRK/simulation) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/data/simcuts.dat b/Detectors/Upgrades/ALICE3/TRK/simulation/data/simcuts.dat new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h new file mode 100644 index 0000000000000..d0397ff9189bb --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h @@ -0,0 +1,387 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Detector.h +/// \brief Definition of the Detector class + +#ifndef ALICEO2_TRK_DETECTOR_H_ +#define ALICEO2_TRK_DETECTOR_H_ + +#include <vector> // for vector +#include "DetectorsBase/GeometryManager.h" // for getSensID +#include "DetectorsBase/Detector.h" // for Detector +#include "DetectorsCommonDataFormats/DetID.h" // for Detector +#include "ITSMFTSimulation/Hit.h" // for Hit +#include "Rtypes.h" // for Int_t, Double_t, Float_t, Bool_t, etc +#include "TArrayD.h" // for TArrayD +#include "TGeoManager.h" // for gGeoManager, TGeoManager (ptr only) +#include "TLorentzVector.h" // for TLorentzVector +#include "TVector3.h" // for TVector3 + +class FairVolume; +class TGeoVolume; + +class TParticle; + +class TString; + +namespace o2 +{ +namespace itsmft +{ +class Hit; +} +} // namespace o2 + +namespace o2 +{ +namespace trk +{ +class GeometryTGeo; +} +} // namespace o2 +namespace o2 +{ +namespace trk +{ +class V3Layer; +} +} // namespace o2 + +namespace o2 +{ +namespace trk +{ +class V3Layer; +class V3Services; + +class Detector : public o2::base::DetImpl<Detector> +{ + public: + enum Model { + kIBModelDummy = 0, + kIBModel0 = 1, + kIBModel1 = 2, + kIBModel21 = 3, + kIBModel22 = 4, + kIBModel3 = 5, + kIBModel4 = 10, + kOBModelDummy = 6, + kOBModel0 = 7, + kOBModel1 = 8, + kOBModel2 = 9 + }; + + static constexpr Int_t sNumberLayers = 12; ///< Number of layers in ITSU + static constexpr Int_t sNumberInnerLayers = 10; ///< Number of inner layers in ITSU + static constexpr Int_t sNumberOfWrapperVolumes = 3; ///< Number of wrapper volumes + + /// Name : Detector Name + /// Active: kTRUE for active detectors (ProcessHits() will be called) + /// kFALSE for inactive detectors + Detector(Bool_t active); + + /// Special version for TRK: add number on Inner Layers + Detector(Bool_t active, Int_t nlay); + + /// Default constructor + Detector(); + + /// Default destructor + ~Detector() override; + + /// Initialization of the detector is done here + void InitializeO2Detector() override; + + /// This method is called for each step during simulation (see FairMCApplication::Stepping()) + Bool_t ProcessHits(FairVolume* v = nullptr) override; + + /// Registers the produced collections in FAIRRootManager + void Register() override; + + /// Gets the produced collections + std::vector<o2::itsmft::Hit>* getHits(Int_t iColl) const + { + if (iColl == 0) { + return mHits; + } + return nullptr; + } + + public: + /// Has to be called after each event to reset the containers + void Reset() override; + + /// Base class to create the detector geometry + void ConstructGeometry() override; + + /// Creates the Service Barrel (as a simple cylinder) for IB and OB + /// \param innerBarrel if true, build IB service barrel, otherwise for OB + /// \param dest the mother volume holding the service barrel + /// \param mgr the gGeoManager pointer (used to get the material) + void createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr = gGeoManager); + + /// Sets the layer parameters + /// \param nlay layer number + /// \param phi0 layer phi0 + /// \param r layer radius + /// \param nstav number of staves + /// \param nunit IB: number of chips per stave + /// \param OB: number of modules per half stave + /// \param lthick stave thickness (if omitted, defaults to 0) + /// \param dthick detector thickness (if omitted, defaults to 0) + /// \param dettypeID ?? + /// \param buildLevel (if 0, all geometry is build, used for material budget studies) + void defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t lthick = 0., + Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; + + /// Sets the layer parameters for a "turbo" layer + /// (i.e. a layer whose staves overlap in phi) + /// \param nlay layer number + /// \param phi0 phi of 1st stave + /// \param r layer radius + /// \param nstav number of staves + /// \param nunit IB: number of chips per stave + /// \param OB: number of modules per half stave + /// \param width stave width + /// \param tilt layer tilt angle (degrees) + /// \param lthick stave thickness (if omitted, defaults to 0) + /// \param dthick detector thickness (if omitted, defaults to 0) + /// \param dettypeID ?? + /// \param buildLevel (if 0, all geometry is build, used for material budget studies) + // void defineLayerTurbo(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t width, Double_t tilt, + // Double_t lthick = 0., Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; + + /// Sets the layer parameters for new TRK geo + /// \param nlay layer number + /// \param r layer radius + /// \param zlen layer length + /// \param dthick detector thickness (if omitted, defaults to 0) + /// \param dettypeID ?? + /// \param buildLevel (if 0, all geometry is build, used for material budget studies) + void defineInnerLayerTRK(Int_t nlay, Double_t r, Double_t zlen, + Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0); + + /// Gets the layer parameters + /// \param nlay layer number + /// \param phi0 phi of 1st stave + /// \param r layer radius + /// \param nstav number of staves + /// \param nmod IB: number of chips per stave + /// \param OB: number of modules per half stave + /// \param width stave width + /// \param tilt stave tilt angle + /// \param lthick stave thickness + /// \param dthick detector thickness + /// \param dettype detector type + virtual void getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nladd, Int_t& nmod, Double_t& width, + Double_t& tilt, Double_t& lthick, Double_t& mthick, UInt_t& dettype) const; + + /// This method is an example of how to add your own point of type Hit to the clones array + o2::itsmft::Hit* addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, + unsigned char startStatus, unsigned char endStatus); + + /// Set per wrapper volume parameters + void defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan) override; + + /// Add alignable top volumes + void addAlignableVolumes() const override; + + /// Add alignable Layer volumes + /// \param lr layer number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesLayer(Int_t lr, TString& parent, Int_t& lastUID) const; + + /// Add alignable Stave volumes + /// \param lr layer number + /// \param st stave number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const; + + /// Add alignable HalfStave volumes + /// \param lr layer number + /// \param st stave number + /// \param hst half stave number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const; + + /// Add alignable Module volumes + /// \param lr layer number + /// \param st stave number + /// \param hst half stave number + /// \param md module number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const; + + /// Add alignable Chip volumes + /// \param lr layer number + /// \param st stave number + /// \param hst half stave number + /// \param md module number + /// \param ch chip number + /// \param parent path of the parent volume + /// \param lastUID on output, UID of the last volume + void addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, + Int_t& lastUID) const; + + /// Return Chip Volume UID + /// \param id volume id + Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID::TRK, id); } + + void EndOfEvent() override; + + void FinishPrimary() override { ; } + virtual void finishRun() { ; } + void BeginPrimary() override { ; } + void PostTrack() override { ; } + void PreTrack() override { ; } + /// Prints out the content of this class in ASCII format + /// \param ostream *os The output stream + void Print(std::ostream* os) const; + + /// Reads in the content of this class in the format of Print + /// \param istream *is The input stream + void Read(std::istream* is); + + /// Returns the number of layers + Int_t getNumberOfLayers() const { return sNumberLayers; } + virtual void setStaveModelIB(Model model) { mStaveModelInnerBarrel = model; } + virtual void setStaveModelOB(Model model) { mStaveModelOuterBarrel = model; } + virtual Model getStaveModelIB() const { return mStaveModelInnerBarrel; } + virtual Model getStaveModelOB() const { return mStaveModelOuterBarrel; } + + float getLayerRadius(const int layNo) const { return mLayerRadii[layNo]; } + float getLayerZLength(const int layNo) const { return mLayerZLen[layNo]; } + float getLayerThickness(const int layNo) const { return mDetectorThickness[layNo]; } + + void createOuterBarrel(const Bool_t ob) { mCreateOuterBarrel = ob; }; + Bool_t isCreateOuterBarrel() { return mCreateOuterBarrel; }; + + o2::trk::GeometryTGeo* mGeometryTGeo; //! access to geometry details + + protected: + Int_t* mLayerID; //! [sNumberLayers] layer identifier + TString* mLayerName; //! [sNumberLayers] layer identifier + + private: + /// this is transient data about track passing the sensor + struct TrackData { // this is transient + bool mHitStarted; //! hit creation started + unsigned char mTrkStatusStart; //! track status flag + TLorentzVector mPositionStart; //! position at entrance + TLorentzVector mMomentumStart; //! momentum + double mEnergyLoss; //! energy loss + } mTrackData; //! + + Int_t mNumberOfInnerLayers; //! number of TRK inner layers + Int_t mTotalNumberOfLayers; //! total number of TRK layers (IB+OB) + Bool_t mCreateOuterBarrel; //! true to create the Outer Barrel + + Int_t mNumberOfDetectors; + + Bool_t mModifyGeometry; + + Double_t mWrapperMinRadius[sNumberOfWrapperVolumes]; //! Min radius of wrapper volume + Double_t mWrapperMaxRadius[sNumberOfWrapperVolumes]; //! Max radius of wrapper volume + Double_t mWrapperZSpan[sNumberOfWrapperVolumes]; //! Z span of wrapper volume + Int_t* mWrapperLayerId; //! Id of wrapper layer to which layer belongs (-1 if not wrapped) + + Bool_t* mTurboLayer; //! True for "turbo" layers + Bool_t* mTRKLayer; //! True for new TRK layers + Double_t* mLayerPhi0; //! Vector of layer's 1st stave phi in lab + Double_t* mLayerRadii; //! Vector of layer radii + Double_t* mLayerZLen; //! Vector of layer lengths + Int_t* mStavePerLayer; //! Vector of number of staves per layer + Int_t* mUnitPerStave; //! Vector of number of "units" per stave + Double_t* mChipThickness; //! Vector of chip thicknesses + Double_t* mStaveWidth; //! Vector of stave width (only used for turbo) + Double_t* mStaveTilt; //! Vector of stave tilt (only used for turbo) + Double_t* mDetectorThickness; //! Vector of detector thicknesses + UInt_t* mChipTypeID; //! Vector of detector type id + Int_t* mBuildLevel; //! Vector of Material Budget Studies + + /// Container for hit data + std::vector<o2::itsmft::Hit>* mHits; + + /// We need this as a method to access members + void configITS(Detector* its); + + /// Creates all needed arrays + void createAllArrays(); + + /// Creates an air-filled wrapper cylindrical volume + TGeoVolume* createWrapperVolume(const Int_t nLay); + + /// Create the detector materials + virtual void createMaterials(); + + /// Construct the detector geometry + void constructDetectorGeometry(); + + /// Define the sensitive volumes of the geometry + void defineSensitiveVolumes(); + + /// Creates the Inner Barrel Services + /// \param motherVolume the TGeoVolume owing the volume structure + void createInnerBarrelServices(TGeoVolume* motherVolume); + + /// Creates the Middle Barrel Services + /// \param motherVolume the TGeoVolume owing the volume structure + void createMiddlBarrelServices(TGeoVolume* motherVolume); + + /// Creates the Outer Barrel Services + /// \param motherVolume the TGeoVolume owing the volume structure + void createOuterBarrelServices(TGeoVolume* motherVolume); + + /// Creates the Outer Barrel Supports + /// \param motherVolume the TGeoVolume owing the volume supports + void createOuterBarrelSupports(TGeoVolume* motherVolume); + + Detector(const Detector&); + + Detector& operator=(const Detector&); + + Model mStaveModelInnerBarrel; //! The stave model for the Inner Barrel + Model mStaveModelOuterBarrel; //! The stave model for the Outer Barrel + V3Layer** mGeometry; //! Geometry + V3Services* mServicesGeometry; //! Services Geometry + + template <typename Det> + friend class o2::base::DetImpl; + ClassDefOverride(Detector, 1); +}; + +// Input and output function for standard C++ input/output. +std::ostream& operator<<(std::ostream& os, Detector& source); + +std::istream& operator>>(std::istream& os, Detector& source); +} // namespace trk +} // namespace o2 + +#ifdef USESHM +namespace o2 +{ +namespace base +{ +template <> +struct UseShm<o2::trk::Detector> { + static constexpr bool value = true; +}; +} // namespace base +} // namespace o2 +#endif + +#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V11Geometry.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V11Geometry.h similarity index 98% rename from Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V11Geometry.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V11Geometry.h index e008c9bffd505..b0e2d3e5a0d47 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V11Geometry.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V11Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,8 @@ /// \file V11Geometry.h /// \brief Definition of the V11Geometry class -#ifndef ALICEO2_ITS4_V11GEOMETRY_H_ -#define ALICEO2_ITS4_V11GEOMETRY_H_ +#ifndef ALICEO2_TRK_V11GEOMETRY_H_ +#define ALICEO2_TRK_V11GEOMETRY_H_ #include <TMath.h> // for DegToRad, Cos, Sin, Tan #include <TObject.h> // for TObject @@ -27,7 +28,7 @@ class TGeoTubeSeg; // lines 14-14 namespace o2 { -namespace its4 +namespace trk { /// This class is a base class for the ITS geometry version 11. It contains common/standard @@ -452,7 +453,7 @@ class V11Geometry : public TObject Int_t mDebug; //! Debug flag/level ClassDefOverride(V11Geometry, 1); // Base class for ITS v11 geometry }; -} // namespace its4 +} // namespace trk } // namespace o2 #endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V1Layer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V1Layer.h new file mode 100644 index 0000000000000..a3325a30e93a1 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V1Layer.h @@ -0,0 +1,416 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_TRK_UPGRADEV1LAYER_H_ +#define ALICEO2_TRK_UPGRADEV1LAYER_H_ + +#include <TGeoManager.h> // for gGeoManager +#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc +#include "TRKSimulation/V11Geometry.h" // for V11Geometry +#include "TRKSimulation/Detector.h" // for Detector, Detector::Model + +class TGeoArb8; + +class TGeoCombiTrans; + +class TGeoVolume; // lines 15-15 + +namespace o2 +{ +namespace trk +{ + +/// This class defines the Geometry for the ITS using TGeo. This is a work class used +/// to study different configurations during the development of the new ITS structure +class V1Layer : public V11Geometry +{ + + public: + enum { + kStave, + kHalfStave, + kModule, + kChip, + kNHLevels + }; + + // Default constructor + V1Layer(); + + // Constructor setting debugging level + V1Layer(Int_t debug); + + // Constructor setting layer number and debugging level + V1Layer(Int_t lay, Int_t debug); + + /// Constructor setting layer number and debugging level + /// for a "turbo" layer (i.e. where staves overlap in phi) + V1Layer(Int_t lay, Bool_t turbo, Int_t debug); + + /// Copy constructor + V1Layer(const V1Layer& source); + + /// Assignment operator + V1Layer& operator=(const V1Layer& source); + + /// Default destructor + ~V1Layer() override; + + Bool_t isTurbo() const + { + return mIsTurbo; + }; + + Double_t getStaveThick() const + { + return mStaveThickness; + }; + + Double_t getStaveTilt() const + { + return mStaveTilt; + }; + + Double_t getStaveWidth() const + { + return mStaveWidth; + }; + + Double_t getSensorThick() const + { + return mSensorThickness; + }; + + Double_t getNumberOfStaves() const + { + return mNumberOfStaves; + }; + + Double_t getNumberOfChips() const + { + return mNumberOfChips; + }; + + Double_t getRadius() const + { + return mLayerRadius; + }; + + Double_t getPhi0() const + { + return mPhi0; + }; + + Double_t getZLength() const + { + return mZLength; + }; + + Int_t getChipType() const + { + return mChipTypeID; + } + + Int_t getNumberOfStavesPerParent() const + { + return mHierarchy[kStave]; + } + + Int_t getNumberOfHalfStavesPerParent() const + { + return mHierarchy[kHalfStave]; + } + + Int_t getNumberOfModulesPerParent() const + { + return mHierarchy[kModule]; + } + + Int_t getNumberOfChipsPerParent() const + { + return mHierarchy[kChip]; + } + + Detector::Model getStaveModel() const + { + return mStaveModel; + } + + void setStaveThick(Double_t t) + { + mStaveThickness = t; + }; + + /// Sets the Stave tilt angle (for turbo layers only) + /// \param t The stave tilt angle + void setStaveTilt(Double_t t); + + /// Sets the Stave width (for turbo layers only) + /// \param w The stave width + void setStaveWidth(Double_t w); + + void setSensorThick(Double_t t) + { + mSensorThickness = t; + }; + + void setNumberOfStaves(Int_t n) + { + mHierarchy[kStave] = mNumberOfStaves = n; + }; + + /// Sets the number of units in a stave: + /// for the Inner Barrel: the number of chips per stave + /// for the Outer Barrel: the number of modules per half stave + /// \param u the number of units + void setNumberOfUnits(Int_t u); + + void setRadius(Double_t r) + { + mLayerRadius = r; + }; + + void setPhi0(Double_t phi) + { + mPhi0 = phi; + } + + void setZLength(Double_t z) + { + mZLength = z; + }; + + void setChipType(Int_t tp) + { + mChipTypeID = tp; + } + + void setBuildLevel(Int_t buildLevel) + { + mBuildLevel = buildLevel; + } + + void setStaveModel(o2::trk::Detector::Model model) + { + mStaveModel = model; + } + + /// Creates the actual Layer and places inside its mother volume + /// \param motherVolume the TGeoVolume owing the volume structure + virtual void createLayer(TGeoVolume* motherVolume); + + private: + /// Creates the actual Layer and places inside its mother volume + /// A so-called "turbo" layer is a layer where staves overlap in phi + /// User can set width and tilt angle, no check is performed here + /// to avoid volume overlaps + /// \param motherVolume The TGeoVolume owing the volume structure + void createLayerTurbo(TGeoVolume* motherVolume); + + /// Computes the inner radius of the air container for the Turbo configuration + /// as the radius of either the circle tangent to the stave or the circle + /// passing for the stave's lower vertex. Returns the radius of the container + /// if >0, else flag to use the lower vertex + Double_t radiusOmTurboContainer(); + + /// Creates the actual Stave + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStave(const TGeoManager* mgr = gGeoManager); + + // TGeoVolume* createChip(Double_t x, Double_t z, const TGeoManager *mgr=gGeoManager); + + /// Creates the IB Module: (only the chips for the time being) + /// Returns the module as a TGeoVolume + /// \param xmod, ymod, zmod X, Y, Z module half lengths + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createModuleInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Creates the actual Chip + /// \param xchip,ychip,zchip The chip dimensions + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createChipInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Creates the OB Module: HIC + FPC + Carbon plate + /// Returns the module as a TGeoVolume + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createModuleOuterB(const TGeoManager* mgr = gGeoManager); + + /// Create the chip stave for the Inner Barrel(Here we fake the halfstave volume to have the + /// same formal geometry hierarchy as for the Outer Barrel) + /// \param xsta, ysta, zsta X, Y, Z stave half lengths + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical stave structure + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveStructInnerB(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create a dummy stave + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerBDummy(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager) const; + + /// Create the mechanical stave structure for Model 0 of TDR + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerB0(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical stave structure for Model 1 of TDR + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerB1(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical stave structure for Model 2.1 of TDR + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerB21(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical stave structure for Model 2.2 of TDR + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerB22(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical stave structure for Model 3 of TDR + /// \param xsta X length + /// \param zsta Z length + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelInnerB3(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); + + /// Create the chip stave for the Outer Barrel + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveOuterB(const TGeoManager* mgr = gGeoManager); + + /// Create dummy stave + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelOuterBDummy(const TGeoManager* mgr = gGeoManager) const; + + /// Creation of the mechanical stave structure for the Outer Barrel as in v0 + /// (we fake the module and halfstave volumes to have always + /// the same formal geometry hierarchy) + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelOuterB0(const TGeoManager* mgr = gGeoManager); + + /// Create the mechanical half stave structure or the Outer Barrel as in TDR + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createStaveModelOuterB1(const TGeoManager* mgr = gGeoManager); + + /// Create the space frame for the Outer Barrel + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createSpaceFrameOuterB(const TGeoManager* mgr = gGeoManager); + + /// Create dummy stave + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createSpaceFrameOuterBDummy(const TGeoManager* mgr = gGeoManager) const; + + /// Create the space frame for the Outer Barrel (Model 1) + /// Returns a TGeoVolume with the Space Frame of a stave + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createSpaceFrameOuterB1(const TGeoManager* mgr = gGeoManager); + + /// Creates the V-shaped sides of the OB space frame (from a similar method with same + /// name and function in V11GeometrySDD class by L.Gaudichet) + TGeoArb8* createStaveSide(const char* name, Double_t dz, Double_t angle, Double_t xSign, Double_t L, Double_t H, + Double_t l); + + /// Help method to create a TGeoCombiTrans matrix from a similar method with same name and + /// function in V11GeometrySDD class by L.Gaudichet) + /// Returns the TGeoCombiTrans which make a translation in y and z and a rotation in phi + /// in the global coord system. If planeSym = true, the rotation places the object + /// symetrically (with respect to the transverse plane) to its position in the + /// case planeSym = false + TGeoCombiTrans* createCombiTrans(const char* name, Double_t dy, Double_t dz, Double_t dphi, + Bool_t planeSym = kFALSE); + + /// Help method to add a translation to a TGeoCombiTrans matrix (from a similar method + /// with same name and function in V11GeometrySDD class by L.Gaudichet) + void addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx = 0, Double_t dy = 0, Double_t dz = 0) const; + + Int_t mLayerNumber; ///< Current layer number + Double_t mPhi0; ///< lab phi of 1st stave, in degrees!!! + Double_t mLayerRadius; ///< Inner radius of this layer + Double_t mZLength; ///< Z length of this layer + Double_t mSensorThickness; ///< Sensor thickness + Double_t mStaveThickness; ///< Stave thickness + Double_t mStaveWidth; ///< Stave width (for turbo layers only) + Double_t mStaveTilt; ///< Stave tilt angle (for turbo layers only) in degrees + Int_t mNumberOfStaves; ///< Number of staves in this layer + Int_t mNumberOfModules; ///< Number of modules per container if defined (HalfStave, Stave, whatever is + ///< container) + Int_t mNumberOfChips; ///< Number chips per container (module, HalfStave, Stave, whatever is + /// container) + Int_t mHierarchy[kNHLevels]; ///< array to query number of staves, hstaves, modules, chips per its parent volume + + UInt_t mChipTypeID; ///< detector type id + Bool_t mIsTurbo; ///< True if this layer is a "turbo" layer + Int_t mBuildLevel; ///< Used for material studies + + Detector::Model mStaveModel; ///< The stave model + + // Parameters for the geometry + + // General Parameters + static const Int_t sNumberOmInnerLayers; ///< Number of IB Layers + + static const Double_t sDefaultSensorThick; ///< Default sensor thickness + static const Double_t sDefaultStaveThick; ///< Default stave thickness + + // Inner Barrel Parameters + static const Int_t sIBChipsPerRow; ///< IB chips per row in module + static const Int_t sIBNChipRows; ///< IB chip rows in module + + // Outer Barrel Parameters + static const Int_t sOBChipsPerRow; ///< OB chips per row in module + static const Int_t sOBNChipRows; ///< OB chip rows in module + + static const Double_t sOBHalfStaveWidth; ///< OB Half Stave Width + static const Double_t sOBModuleWidth; ///< OB Module Width + static const Double_t sOBModuleGap; ///< Gap between OB modules + static const Double_t sOBChipXGap; ///< Gap between OB chips on X + static const Double_t sOBChipZGap; ///< Gap between OB chips on Z + static const Double_t sOBFlexCableAlThick; ///< Thickness of FPC Aluminum + static const Double_t sOBFlexCableKapThick; ///< Thickness of FPC Kapton + static const Double_t sOBBusCableAlThick; ///< Thickness of Bus Aluminum + static const Double_t sOBBusCableKapThick; ///< Thickness of Bus Kapton + static const Double_t sOBCarbonPlateThick; ///< OB Carbon Plate Thickness + static const Double_t sOBColdPlateThick; ///< OB Cold Plate Thickness + static const Double_t sOBGlueThick; ///< OB Glue total Thickness + static const Double_t sOBModuleZLength; ///< OB Chip Length along Z + static const Double_t sOBHalfStaveYTrans; ///< OB half staves Y transl. + static const Double_t sOBHalfStaveXOverlap; ///< OB half staves X overlap + static const Double_t sOBGraphiteFoilThick; ///< OB graphite foil thickness + static const Double_t sOBCoolTubeInnerD; ///< OB cooling inner diameter + static const Double_t sOBCoolTubeThick; ///< OB cooling tube thickness + static const Double_t sOBCoolTubeXDist; ///< OB cooling tube separation + + static const Double_t sOBSpaceFrameWidth; ///< OB Space Frame Width + static const Double_t sOBSpaceFrameTotHigh; ///< OB Total Y Height + static const Double_t sOBSFrameBeamRadius; ///< OB Space Frame Beam Radius + static const Double_t sOBSpaceFrameLa; ///< Parameters defining... + static const Double_t sOBSpaceFrameHa; ///< ...the V side shape... + static const Double_t sOBSpaceFrameLb; ///< ...of the carbon... + static const Double_t sOBSpaceFrameHb; ///< ...OB Space Frame + static const Double_t sOBSpaceFrameL; ///< OB SF + static const Double_t sOBSFBotBeamAngle; ///< OB SF bottom beam angle + static const Double_t sOBSFrameBeamSidePhi; ///< OB SF side beam angle + + ClassDefOverride(V1Layer, 0); // ITS v1 geometry +}; +} // namespace trk +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Layer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Layer.h similarity index 96% rename from Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Layer.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Layer.h index c04160e8997ad..2698d508c3938 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Layer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Layer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,13 @@ /// \author Mario Sitta <sitta@to.infn.it> /// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) -#ifndef ALICEO2_ITS4_UPGRADEV3LAYER_H_ -#define ALICEO2_ITS4_UPGRADEV3LAYER_H_ +#ifndef ALICEO2_TRK_UPGRADEV3LAYER_H_ +#define ALICEO2_TRK_UPGRADEV3LAYER_H_ -#include <TGeoManager.h> // for gGeoManager -#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc -#include "ITS4Simulation/V11Geometry.h" // for V11Geometry -#include "ITS4Simulation/Detector.h" // for Detector, Detector::Model +#include <TGeoManager.h> // for gGeoManager +#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc +#include "TRKSimulation/V11Geometry.h" // for V11Geometry +#include "TRKSimulation/Detector.h" // for Detector, Detector::Model class TGeoXtru; @@ -29,7 +30,7 @@ class TGeoVolume; // lines 15-15 namespace o2 { -namespace its4 +namespace trk { /// This class defines the Geometry for the ITS using TGeo. This is a work class used @@ -64,7 +65,7 @@ class V3Layer : public V11Geometry Bool_t isTurbo() const { return mIsTurbo; }; - Bool_t isITS4() const { return mIsITS4; }; + Bool_t isTRK() const { return mIsTRK; }; Double_t getChipThick() const { return mChipThickness; }; @@ -110,10 +111,10 @@ class V3Layer : public V11Geometry /// Gets the Gamma Conversion Rod X position Double_t getGammaConversionRodXPos(); - /// Sets whether this is a new ITS4 layer - void setIsITS4(const Bool_t its4) { mIsITS4 = its4; }; + /// Sets whether this is a new TRK layer + void setIsTRK(const Bool_t trk) { mIsTRK = trk; }; - /// Sets Module Z length (valid only for new ITS4 layer) + /// Sets Module Z length (valid only for new TRK layer) void setIBModuleZLength(const Double_t z) { mIBModuleZLength = z; }; /// Sets the Stave tilt angle (for turbo layers only) @@ -142,7 +143,7 @@ class V3Layer : public V11Geometry void setBuildLevel(Int_t buildLevel) { mBuildLevel = buildLevel; } - void setStaveModel(o2::its4::Detector::Model model) { mStaveModel = model; } + void setStaveModel(o2::trk::Detector::Model model) { mStaveModel = model; } void setNumberOfInnerLayers(const Int_t n) { mNumberOfInnerLayers = n; }; @@ -163,10 +164,10 @@ class V3Layer : public V11Geometry /// \param motherVolume The TGeoVolume owing the volume structure void createLayerTurbo(TGeoVolume* motherVolume); - /// Creates a new ITS4 Layer and places inside its mother volume + /// Creates a new TRK Layer and places inside its mother volume /// \param motherVolume The TGeoVolume owing the volume structure /// \param mgr The GeoManager (used only to get the proper material) - void createITS4Layer(TGeoVolume* motherVolume, const TGeoManager* mgr = gGeoManager); + void createTRKLayer(TGeoVolume* motherVolume, const TGeoManager* mgr = gGeoManager); /// Computes the inner radius of the air container for the Turbo configuration /// as the radius of either the circle tangent to the stave or the circle @@ -340,7 +341,7 @@ class V3Layer : public V11Geometry UInt_t mChipTypeID; ///< detector type id Bool_t mIsTurbo; ///< True if this layer is a "turbo" layer - Bool_t mIsITS4; ///< True if this layer is a new ITS4 layer + Bool_t mIsTRK; ///< True if this layer is a new TRK layer Int_t mBuildLevel; ///< Used for material studies Detector::Model mStaveModel; ///< The stave model @@ -564,7 +565,7 @@ class V3Layer : public V11Geometry ClassDefOverride(V3Layer, 0); // ITS v3 geometry }; -} // namespace its4 +} // namespace trk } // namespace o2 #endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Services.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Services.h similarity index 91% rename from Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Services.h rename to Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Services.h index c1ba390d07c10..26f060fbec6c5 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V3Services.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/V3Services.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,13 +14,13 @@ /// \author Mario Sitta <sitta@to.infn.it> /// \author Parinya Namwongsa <parinya.namwongsa@cern.ch> -#ifndef ALICEO2_ITS4_UPGRADEV3SERVICES_H_ -#define ALICEO2_ITS4_UPGRADEV3SERVICES_H_ +#ifndef ALICEO2_TRK_UPGRADEV3SERVICES_H_ +#define ALICEO2_TRK_UPGRADEV3SERVICES_H_ -#include <TGeoManager.h> // for gGeoManager -#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc -#include "ITS4Simulation/V11Geometry.h" // for V11Geometry -#include "ITS4Simulation/Detector.h" // for Detector, Detector::Model +#include <TGeoManager.h> // for gGeoManager +#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc +#include "TRKSimulation/V11Geometry.h" // for V11Geometry +#include "TRKSimulation/Detector.h" // for Detector, Detector::Model class TGeoXtru; @@ -29,7 +30,7 @@ class TGeoVolume; namespace o2 { -namespace its4 +namespace trk { /// This class defines the Geometry for the Services of the ITS Upgrade using TGeo. @@ -178,7 +179,7 @@ class V3Services : public V11Geometry ClassDefOverride(V3Services, 0); // ITS v3 support geometry }; -} // namespace its4 +} // namespace trk } // namespace o2 #endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx new file mode 100644 index 0000000000000..4eb4c55789626 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -0,0 +1,1333 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Detector.cxx +/// \brief Implementation of the Detector class + +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITSMFTSimulation/Hit.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKSimulation/Detector.h" +#include "TRKSimulation/V3Layer.h" +#include "TRKSimulation/V3Services.h" + +#include "SimulationDataFormat/Stack.h" +#include "SimulationDataFormat/TrackReference.h" + +// FairRoot includes +#include "FairDetector.h" // for FairDetector +#include "FairLogger.h" // for LOG, LOG_IF +#include "FairRootManager.h" // for FairRootManager +#include "FairRun.h" // for FairRun +#include "FairRuntimeDb.h" // for FairRuntimeDb +#include "FairVolume.h" // for FairVolume +#include "FairRootManager.h" + +#include "TGeoManager.h" // for TGeoManager, gGeoManager +#include "TGeoTube.h" // for TGeoTube +#include "TGeoPcon.h" // for TGeoPcon +#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly +#include "TString.h" // for TString, operator+ +#include "TVirtualMC.h" // for gMC, TVirtualMC +#include "TVirtualMCStack.h" // for TVirtualMCStack + +#include <cstdio> // for NULL, snprintf + +class FairModule; + +class TGeoMedium; + +class TParticle; + +using std::cout; +using std::endl; + +using o2::itsmft::Hit; +using Segmentation = o2::itsmft::SegmentationAlpide; +using namespace o2::trk; + +float getDetLengthFromEta(const float eta, const float radius) +{ + return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta)))); +} + +Detector::Detector() + : o2::base::DetImpl<Detector>("TRK", kTRUE), + mTrackData(), + mNumberOfDetectors(-1), + mModifyGeometry(kFALSE), + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), + mStaveModelInnerBarrel(kIBModel0), + mStaveModelOuterBarrel(kOBModel0) +{ +} + +static double radii2Turbo(double rMin, double rMid, double rMax, double sensW) +{ + // compute turbo angle from radii and sensor width + return TMath::ASin((rMax * rMax - rMin * rMin) / (2 * rMid * sensW)) * TMath::RadToDeg(); +} + +// We need this as a method to access members +void Detector::configITS(Detector* its) +{ + // build ITS upgrade detector + const int kNLr = 7; + const int kNLrInner = 3; + const int kBuildLevel = 0; + const int kSensTypeID = 0; // dummy id for Alpide sensor + + const float ChipThicknessIB = 50.e-4; + const float ChipThicknessOB = 100.e-4; + + enum { kRmn, + kRmd, + kRmx, + kNModPerStave, + kPhi0, + kNStave, + kNPar }; + + its->setStaveModelOB(o2::trk::Detector::kOBModel2); + + const int kNWrapVol = 3; + const double wrpRMin[kNWrapVol] = {2.1, 19.3, 33.32}; + const double wrpRMax[kNWrapVol] = {15.4, 29.14, 46.0}; + const double wrpZSpan[kNWrapVol] = {70., 93., 163.6}; + + for (int iw = 0; iw < kNWrapVol; iw++) { + its->defineWrapperVolume(iw, wrpRMin[iw], wrpRMax[iw], wrpZSpan[iw]); + } + + // Layout updated at December 18th 2020 [cm] + + std::vector<std::array<double, 2>> layers; + const int nLayers{12}; + layers.emplace_back(std::array<double, 2>{0.5f, 50.f}); + layers.emplace_back(std::array<double, 2>{1.2f, 50.f}); + layers.emplace_back(std::array<double, 2>{2.5f, 50.f}); + layers.emplace_back(std::array<double, 2>{3.75f, 124.f}); + layers.emplace_back(std::array<double, 2>{7.f, 124.f}); + layers.emplace_back(std::array<double, 2>{12.f, 124.f}); + layers.emplace_back(std::array<double, 2>{20.f, 124.f}); + layers.emplace_back(std::array<double, 2>{30.f, 124.f}); + layers.emplace_back(std::array<double, 2>{45.f, 264.f}); + layers.emplace_back(std::array<double, 2>{60.f, 264.f}); + layers.emplace_back(std::array<double, 2>{80.f, 264.f}); + layers.emplace_back(std::array<double, 2>{100.f, 264.f}); + + std::array<float, 12> sensorThicknesses = {100.e-4, 100.e-4, 100.e-4, 100.e-4, 100.e-3, 100.e-3, 100.e-3, 100.e-3, 100.e-3, 100.e-3, 100.e-3, 100.e-3}; + its->setStaveModelOB(o2::trk::Detector::kOBModel2); + + auto idLayer{0}; + for (auto& layerData : layers) { + its->defineInnerLayerTRK(idLayer, layerData[0], layerData[1], sensorThicknesses[idLayer], 0, 0); + ++idLayer; + } + its->createOuterBarrel(false); +} + +Detector::Detector(Bool_t active) + : o2::base::DetImpl<Detector>("TRK", active), + mTrackData(), + mNumberOfInnerLayers(12), + mNumberOfDetectors(-1), + mModifyGeometry(kFALSE), + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), + mStaveModelInnerBarrel(kIBModel0), + mStaveModelOuterBarrel(kOBModel0) +{ + + mTotalNumberOfLayers = mNumberOfInnerLayers; + + createAllArrays(); + + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer + } + + if (mTotalNumberOfLayers > 0) { // if not, we'll Fatal-ize in CreateGeometry + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + mTRKLayer[j] = kFALSE; + mLayerPhi0[j] = 0; + mLayerRadii[j] = 0.; + mLayerZLen[j] = 0.; + mStavePerLayer[j] = 0; + mUnitPerStave[j] = 0; + mChipThickness[j] = 0.; + mStaveWidth[j] = 0.; + mStaveTilt[j] = 0.; + mDetectorThickness[j] = 0.; + mChipTypeID[j] = 0; + mBuildLevel[j] = 0; + mGeometry[j] = nullptr; + } + } + mServicesGeometry = nullptr; + + for (int i = sNumberOfWrapperVolumes; i--;) { + mWrapperMinRadius[i] = mWrapperMaxRadius[i] = mWrapperZSpan[i] = -1; + } + + configITS(this); +} + +Detector::Detector(const Detector& rhs) + : o2::base::DetImpl<Detector>(rhs), + mTrackData(), + /* + mHitStarted(false), + mTrkStatusStart(), + mPositionStart(), + mMomentumStart(), + mEnergyLoss(), + */ + mNumberOfInnerLayers(rhs.mNumberOfInnerLayers), + mNumberOfDetectors(rhs.mNumberOfDetectors), + mModifyGeometry(rhs.mModifyGeometry), + + /// Container for data points + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), + mStaveModelInnerBarrel(rhs.mStaveModelInnerBarrel), + mStaveModelOuterBarrel(rhs.mStaveModelOuterBarrel) +{ + + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer + } +} + +Detector::~Detector() +{ + + if (mHits) { + // delete mHits; + o2::utils::freeSimVector(mHits); + } +} + +Detector& Detector::operator=(const Detector& rhs) +{ + // The standard = operator + // Inputs: + // Detector &h the sourse of this copy + // Outputs: + // none. + // Return: + // A copy of the sourse hit h + + if (this == &rhs) { + return *this; + } + + // base class assignment + base::Detector::operator=(rhs); + + mNumberOfDetectors = rhs.mNumberOfDetectors; + + mModifyGeometry = rhs.mModifyGeometry; + + /// Container for data points + mHits = nullptr; + + mStaveModelInnerBarrel = rhs.mStaveModelInnerBarrel; + mStaveModelOuterBarrel = rhs.mStaveModelOuterBarrel; + + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer + } + + return *this; +} + +void Detector::createAllArrays() +{ + // Create all arrays + // We have to do it here because now the number of Inner Layers is + // not fixed, so we don't know in advance how many to create: they + // cannot be anymore static arrays as in the default version + // M.S. 21 mar 2020 (13th day of Italian Coronavirus lockdown) + + mLayerID = new Int_t[mTotalNumberOfLayers]; + mLayerName = new TString[mTotalNumberOfLayers]; + + mWrapperLayerId = new Int_t[mTotalNumberOfLayers]; + mTurboLayer = new Bool_t[mTotalNumberOfLayers]; + mTRKLayer = new Bool_t[mTotalNumberOfLayers]; + + mLayerPhi0 = new Double_t[mTotalNumberOfLayers]; + mLayerRadii = new Double_t[mTotalNumberOfLayers]; + mLayerZLen = new Double_t[mTotalNumberOfLayers]; + mStavePerLayer = new Int_t[mTotalNumberOfLayers]; + mUnitPerStave = new Int_t[mTotalNumberOfLayers]; + mChipThickness = new Double_t[mTotalNumberOfLayers]; + mStaveWidth = new Double_t[mTotalNumberOfLayers]; + mStaveTilt = new Double_t[mTotalNumberOfLayers]; + mDetectorThickness = new Double_t[mTotalNumberOfLayers]; + mChipTypeID = new UInt_t[mTotalNumberOfLayers]; + mBuildLevel = new Int_t[mTotalNumberOfLayers]; + + mGeometry = new V3Layer*[mTotalNumberOfLayers]; +} + +void Detector::InitializeO2Detector() +{ + // Define the list of sensitive volumes + defineSensitiveVolumes(); + + for (int i = 0; i < mTotalNumberOfLayers; i++) { + mLayerID[i] = gMC ? TVirtualMC::GetMC()->VolId(mLayerName[i]) : 0; + } + + mGeometryTGeo = GeometryTGeo::Instance(); + // FairRuntimeDb* rtdb= FairRun::Instance()->GetRuntimeDb(); + // O2itsGeoPar* par=(O2itsGeoPar*)(rtdb->getContainer("O2itsGeoPar")); +} + +Bool_t Detector::ProcessHits(FairVolume* vol) +{ + // This method is called from the MC stepping + if (!(fMC->TrackCharge())) { + return kFALSE; + } + + Int_t lay = 0, volID = vol->getMCid(); + + // FIXME: Determine the layer number. Is this information available directly from the FairVolume? + bool notSens = false; + while ((lay < mTotalNumberOfLayers) && (notSens = (volID != mLayerID[lay]))) { + ++lay; + } + if (notSens) { + return kFALSE; // RS: can this happen? This method must be called for sensors only? + } + + // Is it needed to keep a track reference when the outer ITS volume is encountered? + auto stack = (o2::data::Stack*)fMC->GetStack(); + if (fMC->IsTrackExiting() && (lay == 0 || lay == 6)) { + // Keep the track refs for the innermost and outermost layers only + o2::TrackReference tr(*fMC, GetDetId()); + tr.setTrackID(stack->GetCurrentTrackNumber()); + tr.setUserId(lay); + stack->addTrackReference(tr); + } + bool startHit = false, stopHit = false; + unsigned char status = 0; + if (fMC->IsTrackEntering()) { + status |= Hit::kTrackEntering; + } + if (fMC->IsTrackInside()) { + status |= Hit::kTrackInside; + } + if (fMC->IsTrackExiting()) { + status |= Hit::kTrackExiting; + } + if (fMC->IsTrackOut()) { + status |= Hit::kTrackOut; + } + if (fMC->IsTrackStop()) { + status |= Hit::kTrackStopped; + } + if (fMC->IsTrackAlive()) { + status |= Hit::kTrackAlive; + } + + // track is entering or created in the volume + if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { + startHit = true; + } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { + stopHit = true; + } + + // increment energy loss at all steps except entrance + if (!startHit) { + mTrackData.mEnergyLoss += fMC->Edep(); + } + if (!(startHit | stopHit)) { + return kFALSE; // do noting + } + + if (startHit) { + mTrackData.mEnergyLoss = 0.; + fMC->TrackMomentum(mTrackData.mMomentumStart); + fMC->TrackPosition(mTrackData.mPositionStart); + mTrackData.mTrkStatusStart = status; + mTrackData.mHitStarted = true; + } + if (stopHit) { + TLorentzVector positionStop; + fMC->TrackPosition(positionStop); + // Retrieve the indices with the volume path + int stave(0), halfstave(0), chipinmodule(0), module; + fMC->CurrentVolOffID(1, chipinmodule); + fMC->CurrentVolOffID(2, module); + fMC->CurrentVolOffID(3, halfstave); + fMC->CurrentVolOffID(4, stave); + + Hit* p = addHit(stack->GetCurrentTrackNumber(), lay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), + mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); + // p->SetTotalEnergy(vmc->Etot()); + + // RS: not sure this is needed + // Increment number of Detector det points in TParticle + stack->addHit(GetDetId()); + } + + return kTRUE; +} + +void Detector::createMaterials() +{ + Int_t ifield = 2; + Float_t fieldm = 10.0; + o2::base::Detector::initFieldTrackingParams(ifield, fieldm); + //////////// + + Float_t tmaxfd = 0.1; // 1.0; // Degree + Float_t stemax = 1.0; // cm + Float_t deemax = 0.1; // 30.0; // Fraction of particle's energy 0<deemax<=1 + Float_t epsil = 1.0E-4; // 1.0; // cm + Float_t stmin = 0.0; // cm "Default value used" + + Float_t tmaxfdSi = 0.1; // .10000E+01; // Degree + Float_t stemaxSi = 0.0075; // .10000E+01; // cm + Float_t deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 + Float_t epsilSi = 1.0E-4; // .10000E+01; + Float_t stminSi = 0.0; // cm "Default value used" + + Float_t tmaxfdAir = 0.1; // .10000E+01; // Degree + Float_t stemaxAir = .10000E+01; // cm + Float_t deemaxAir = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 + Float_t epsilAir = 1.0E-4; // .10000E+01; + Float_t stminAir = 0.0; // cm "Default value used" + + // AIR + Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; + Float_t zAir[4] = {6., 7., 8., 18.}; + Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; + Float_t dAir = 1.20479E-3; + + // Water + Float_t aWater[2] = {1.00794, 15.9994}; + Float_t zWater[2] = {1., 8.}; + Float_t wWater[2] = {0.111894, 0.888106}; + Float_t dWater = 1.0; + + // PEEK CF30 + Float_t aPEEK[3] = {12.0107, 1.00794, 15.9994}; + Float_t zPEEK[3] = {6., 1., 8.}; + Float_t wPEEK[3] = {19., 12., 3}; + Float_t dPEEK = 1.32; + + // Kapton + Float_t aKapton[4] = {1.00794, 12.0107, 14.010, 15.9994}; + Float_t zKapton[4] = {1., 6., 7., 8.}; + Float_t wKapton[4] = {0.026362, 0.69113, 0.07327, 0.209235}; + Float_t dKapton = 1.42; + + // Tungsten Carbide + Float_t aWC[2] = {183.84, 12.0107}; + Float_t zWC[2] = {74, 6}; + Float_t wWC[2] = {0.5, 0.5}; + Float_t dWC = 15.63; + + // BEOL (Metal interconnection stack in Si sensors) + Float_t aBEOL[3] = {26.982, 28.086, 15.999}; + Float_t zBEOL[3] = {13, 14, 8}; // Al, Si, O + Float_t wBEOL[3] = {0.170, 0.388, 0.442}; + Float_t dBEOL = 2.28; + + // Inox 304 + Float_t aInox304[4] = {12.0107, 51.9961, 58.6928, 55.845}; + Float_t zInox304[4] = {6., 24., 28, 26}; // C, Cr, Ni, Fe + Float_t wInox304[4] = {0.0003, 0.18, 0.10, 0}; // [3] will be computed + Float_t dInox304 = 7.85; + + // Ceramic (for IB capacitors) (BaTiO3) + Float_t aCeramic[3] = {137.327, 47.867, 15.999}; + Float_t zCeramic[3] = {56, 22, 8}; // Ba, Ti, O + Float_t wCeramic[3] = {1, 1, 3}; // Molecular composition + Float_t dCeramic = 6.02; + + // Rohacell (C9 H13 N1 O2) + Float_t aRohac[4] = {12.01, 1.01, 14.010, 16.}; + Float_t zRohac[4] = {6., 1., 7., 8.}; + Float_t wRohac[4] = {9., 13., 1., 2.}; + Float_t dRohac = 0.05; + + o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir); + o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir); + + o2::base::Detector::Mixture(2, "WATER$", aWater, zWater, dWater, 2, wWater); + o2::base::Detector::Medium(2, "WATER$", 2, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + o2::base::Detector::Material(3, "SI$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03); + o2::base::Detector::Medium(3, "SI$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + + o2::base::Detector::Material(4, "BERILLIUM$", 9.01, 4., 1.848, 35.3, 36.7); // From AliPIPEv3 + o2::base::Detector::Medium(4, "BERILLIUM$", 4, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + o2::base::Detector::Material(5, "COPPER$", 0.63546E+02, 0.29000E+02, 0.89600E+01, 0.14300E+01, 0.99900E+03); + o2::base::Detector::Medium(5, "COPPER$", 5, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // needed for STAVE , Carbon, kapton, Epoxy, flexcable + + // AliceO2::Base::Detector::Material(6,"CARBON$",12.0107,6,2.210,999,999); + o2::base::Detector::Material(6, "CARBON$", 12.0107, 6, 2.210 / 1.3, 999, 999); + o2::base::Detector::Medium(6, "CARBON$", 6, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + + o2::base::Detector::Mixture(7, "KAPTON(POLYCH2)$", aKapton, zKapton, dKapton, 4, wKapton); + o2::base::Detector::Medium(7, "KAPTON(POLYCH2)$", 7, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // values below modified as compared to source AliITSv11 ! + + // BEOL (Metal interconnection stack in Si sensors) + o2::base::Detector::Mixture(29, "METALSTACK$", aBEOL, zBEOL, dBEOL, 3, wBEOL); + o2::base::Detector::Medium(29, "METALSTACK$", 29, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // Glue between IB chip and FPC: density reduced to take into account + // empty spaces (160 glue spots/chip , diam. 1 spot = 1 mm) + o2::base::Detector::Material(30, "GLUE_IBFPC$", 12.011, 6, 1.05 * 0.3, 999, 999); + o2::base::Detector::Medium(30, "GLUE_IBFPC$", 30, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // Ceramic for IB capacitors (nmat < 0 => wmat contains number of atoms) + o2::base::Detector::Mixture(31, "CERAMIC$", aCeramic, zCeramic, dCeramic, -3, wCeramic); + o2::base::Detector::Medium(31, "CERAMIC$", 31, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // All types of carbon + // Unidirectional prepreg + o2::base::Detector::Material(8, "K13D2U2k$", 12.0107, 6, 1.643, 999, 999); + o2::base::Detector::Medium(8, "K13D2U2k$", 8, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + o2::base::Detector::Material(17, "K13D2U120$", 12.0107, 6, 1.583, 999, 999); + o2::base::Detector::Medium(17, "K13D2U120$", 17, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // Carbon prepreg woven + o2::base::Detector::Material(18, "F6151B05M$", 12.0107, 6, 2.133, 999, 999); + o2::base::Detector::Medium(18, "F6151B05M$", 18, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // Impregnated thread + o2::base::Detector::Material(9, "M60J3K$", 12.0107, 6, 2.21, 999, 999); + o2::base::Detector::Medium(9, "M60J3K$", 9, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // Impregnated thread + o2::base::Detector::Material(10, "M55J6K$", 12.0107, 6, 1.63, 999, 999); + o2::base::Detector::Medium(10, "M55J6K$", 10, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // Fabric(0/90) + o2::base::Detector::Material(11, "T300$", 12.0107, 6, 1.725, 999, 999); + o2::base::Detector::Medium(11, "T300$", 11, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // AMEC Thermasol + o2::base::Detector::Material(12, "FGS003$", 12.0107, 6, 1.6, 999, 999); + o2::base::Detector::Medium(12, "FGS003$", 12, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // Carbon fleece + o2::base::Detector::Material(13, "CarbonFleece$", 12.0107, 6, 0.4, 999, 999); + o2::base::Detector::Medium(13, "CarbonFleece$", 13, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, + stminSi); + // Rohacell + o2::base::Detector::Mixture(32, "ROHACELL$", aRohac, zRohac, dRohac, -4, wRohac); + o2::base::Detector::Medium(32, "ROHACELL$", 32, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + + // PEEK CF30 + o2::base::Detector::Mixture(19, "PEEKCF30$", aPEEK, zPEEK, dPEEK, -3, wPEEK); + o2::base::Detector::Medium(19, "PEEKCF30$", 19, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + + // Flex cable + Float_t aFCm[5] = {12.0107, 1.00794, 14.0067, 15.9994, 26.981538}; + Float_t zFCm[5] = {6., 1., 7., 8., 13.}; + Float_t wFCm[5] = {0.520088819984, 0.01983871336, 0.0551367996, 0.157399667056, 0.247536}; + // Float_t dFCm = 1.6087; // original + // Float_t dFCm = 2.55; // conform with STAR + Float_t dFCm = 2.595; // conform with Corrado + + o2::base::Detector::Mixture(14, "FLEXCABLE$", aFCm, zFCm, dFCm, 5, wFCm); + o2::base::Detector::Medium(14, "FLEXCABLE$", 14, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + // AliceO2::Base::Detector::Material(7,"GLUE$",0.12011E+02,0.60000E+01,0.1930E+01/2.015,999,999); + // // original + o2::base::Detector::Material(15, "GLUE$", 12.011, 6, 1.93 / 2.015, 999, 999); // conform with ATLAS, Corrado, Stefan + o2::base::Detector::Medium(15, "GLUE$", 15, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + o2::base::Detector::Material(16, "ALUMINUM$", 0.26982E+02, 0.13000E+02, 0.26989E+01, 0.89000E+01, 0.99900E+03); + o2::base::Detector::Medium(16, "ALUMINUM$", 16, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); + + o2::base::Detector::Mixture(20, "TUNGCARB$", aWC, zWC, dWC, 2, wWC); + o2::base::Detector::Medium(20, "TUNGCARB$", 20, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi); + + wInox304[3] = 1. - wInox304[0] - wInox304[1] - wInox304[2]; + o2::base::Detector::Mixture(21, "INOX304$", aInox304, zInox304, dInox304, 4, wInox304); + o2::base::Detector::Medium(21, "INOX304$", 21, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi); + + // Tungsten (for gamma converter rods) + o2::base::Detector::Material(28, "TUNGSTEN$", 183.84, 74, 19.25, 999, 999); + o2::base::Detector::Medium(28, "TUNGSTEN$", 28, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); +} + +void Detector::EndOfEvent() { Reset(); } + +void Detector::Register() +{ + // This will create a branch in the output tree called Hit, setting the last + // parameter to kFALSE means that this collection will not be written to the file, + // it will exist only during the simulation + + if (FairRootManager::Instance()) { + FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); + } +} + +void Detector::Reset() +{ + if (!o2::utils::ShmManager::Instance().isOperational()) { + mHits->clear(); + } +} + +void Detector::defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan) +{ + // set parameters of id-th wrapper volume + if (id >= sNumberOfWrapperVolumes || id < 0) { + LOG(FATAL) << "id " << id << " of wrapper volume is not in 0-" << sNumberOfWrapperVolumes - 1 << " range"; + } + + mWrapperMinRadius[id] = rmin; + mWrapperMaxRadius[id] = rmax; + mWrapperZSpan[id] = zspan; +} + +void Detector::defineLayer(Int_t nlay, double phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick, + Double_t dthick, UInt_t dettypeID, Int_t buildLevel) +{ + // Sets the layer parameters + // Inputs: + // nlay layer number + // phi0 layer phi0 + // r layer radius + // nstav number of staves + // nunit IB: number of chips per stave + // OB: number of modules per half stave + // lthick stave thickness (if omitted, defaults to 0) + // dthick detector thickness (if omitted, defaults to 0) + // dettypeID ?? + // buildLevel (if 0, all geometry is build, used for material budget studies) + // Outputs: + // none. + // Return: + // none. + + LOG(INFO) << "L# " << nlay << " Phi:" << phi0 << " R:" << r << " Nst:" << nstav << " Nunit:" << nunit + << " Lthick:" << lthick << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel; + + if (nlay >= mTotalNumberOfLayers || nlay < 0) { + LOG(ERROR) << "Wrong layer number " << nlay; + return; + } + + mTurboLayer[nlay] = kFALSE; + mLayerPhi0[nlay] = phi0; + mLayerRadii[nlay] = r; + mStavePerLayer[nlay] = nstav; + mUnitPerStave[nlay] = nunit; + mChipThickness[nlay] = lthick; + mDetectorThickness[nlay] = dthick; + mChipTypeID[nlay] = dettypeID; + mBuildLevel[nlay] = buildLevel; +} + +void Detector::defineInnerLayerTRK(Int_t nlay, Double_t r, Double_t zlen, + Double_t dthick, UInt_t dettypeID, Int_t buildLevel) +{ + // Sets the layer parameters + // Inputs: + // nlay layer number + // r layer radius + // zlen layer length + // dthick detector thickness (if omitted, defaults to 0) + // dettypeID ?? + // buildLevel (if 0, all geometry is build, used for material budget studies) + // Outputs: + // none. + // Return: + // none. + + LOG(INFO) << "L# " << nlay << " with TRK geo R:" << r + << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel; + + if (nlay >= mTotalNumberOfLayers || nlay < 0) { + LOG(ERROR) << "Wrong layer number " << nlay; + return; + } + + mTurboLayer[nlay] = kFALSE; + mTRKLayer[nlay] = kTRUE; + mLayerRadii[nlay] = r; + mLayerZLen[nlay] = zlen; + mDetectorThickness[nlay] = dthick; + mChipTypeID[nlay] = dettypeID; + mBuildLevel[nlay] = buildLevel; + LOG(INFO) << "Added layer: " << nlay << std::endl; +} + +void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& width, + Double_t& tilt, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const +{ + // Gets the layer parameters + // Inputs: + // nlay layer number + // Outputs: + // phi0 phi of 1st stave + // r layer radius + // nstav number of staves + // nmod IB: number of chips per stave + // OB: number of modules per half stave + // width stave width + // tilt stave tilt angle + // lthick stave thickness + // dthick detector thickness + // dettype detector type + // Return: + // none. + + if (nlay >= mTotalNumberOfLayers || nlay < 0) { + LOG(ERROR) << "Wrong layer number " << nlay; + return; + } + + phi0 = mLayerPhi0[nlay]; + r = mLayerRadii[nlay]; + nstav = mStavePerLayer[nlay]; + nmod = mUnitPerStave[nlay]; + width = mStaveWidth[nlay]; + tilt = mStaveTilt[nlay]; + lthick = mChipThickness[nlay]; + dthick = mDetectorThickness[nlay]; + dettype = mChipTypeID[nlay]; +} + +TGeoVolume* Detector::createWrapperVolume(Int_t id) +{ + // Creates an air-filled wrapper cylindrical volume + // For OB a Pcon is needed to host the support rings + // while avoiding overlaps with MFT structures and OB cones + + const Double_t suppRingAZlen = 4.; + const Double_t coneRingARmax = 33.96; + const Double_t coneRingAZlen = 5.6; + const Double_t suppRingCZlen[3] = {4.8, 4.0, 2.4}; + const Double_t suppRingsRmin[3] = {23.35, 20.05, 35.4}; + + if (mWrapperMinRadius[id] < 0 || mWrapperMaxRadius[id] < 0 || mWrapperZSpan[id] < 0) { + LOG(FATAL) << "Wrapper volume " << id << " was requested but not defined"; + } + + // Now create the actual shape and volume + TGeoShape* tube; + Double_t zlen; + switch (id) { + case 0: // IB Layer 0,1,2: simple cylinder + { + TGeoTube* wrap = new TGeoTube(mWrapperMinRadius[id], mWrapperMaxRadius[id], mWrapperZSpan[id] / 2.); + tube = (TGeoShape*)wrap; + } break; + case 1: // MB Layer 3,4: complex Pcon to avoid MFT overlaps + { + TGeoPcon* wrap = new TGeoPcon(0, 360, 6); + zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[0]; + wrap->DefineSection(0, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]); + zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[1]; + wrap->DefineSection(1, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]); + wrap->DefineSection(2, -zlen, suppRingsRmin[1], mWrapperMaxRadius[id]); + wrap->DefineSection(3, -mWrapperZSpan[id] / 2., suppRingsRmin[1], mWrapperMaxRadius[id]); + wrap->DefineSection(4, -mWrapperZSpan[id] / 2., mWrapperMinRadius[id], mWrapperMaxRadius[id]); + zlen = mWrapperZSpan[id] / 2 + suppRingAZlen; + wrap->DefineSection(5, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); + tube = (TGeoShape*)wrap; + } break; + case 2: // OB Layer 5,6: simpler Pcon to avoid OB cones overlaps + { + TGeoPcon* wrap = new TGeoPcon(0, 360, 6); + zlen = mWrapperZSpan[id] / 2; + wrap->DefineSection(0, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]); + zlen -= suppRingCZlen[2]; + wrap->DefineSection(1, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]); + wrap->DefineSection(2, -zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); + zlen = mWrapperZSpan[id] / 2 - coneRingAZlen; + wrap->DefineSection(3, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); + wrap->DefineSection(4, zlen, coneRingARmax, mWrapperMaxRadius[id]); + wrap->DefineSection(5, mWrapperZSpan[id] / 2, coneRingARmax, mWrapperMaxRadius[id]); + tube = (TGeoShape*)wrap; + } break; + default: // Can never happen, keeps gcc quiet + break; + } + + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + + char volnam[30]; + snprintf(volnam, 29, "%s%d", GeometryTGeo::getITSWrapVolPattern(), id); + + auto* wrapper = new TGeoVolume(volnam, tube, medAir); + + return wrapper; +} + +void Detector::ConstructGeometry() +{ + // Create the detector materials + createMaterials(); + // Construct the detector geometry + constructDetectorGeometry(); +} + +void Detector::constructDetectorGeometry() +{ + // Create the geometry and insert it in the mother volume ITSV + TGeoManager* geoManager = gGeoManager; + + TGeoVolume* vALIC = geoManager->GetVolume("barrel"); + + if (!vALIC) { + LOG(FATAL) << "Could not find the top volume"; + } + new TGeoVolumeAssembly(GeometryTGeo::getITSVolPattern()); + TGeoVolume* vITSV = geoManager->GetVolume(GeometryTGeo::getITSVolPattern()); + vALIC->AddNode(vITSV, 2, new TGeoTranslation(0, 30., 0)); // Copy number is 2 to cheat AliGeoManager::CheckSymNamesLUT + + const Int_t kLength = 100; + Char_t vstrng[kLength] = "xxxRS"; //? + vITSV->SetTitle(vstrng); + + // Check that we have all needed parameters + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + if (mLayerRadii[j] <= 0) { + LOG(FATAL) << "Wrong layer radius for layer " << j << "(" << mLayerRadii[j] << ")"; + } + if (mStavePerLayer[j] <= 0 && !mTRKLayer[j]) { + LOG(FATAL) << "Wrong number of staves for layer " << j << "(" << mStavePerLayer[j] << ")"; + } + if (mUnitPerStave[j] <= 0 && !mTRKLayer[j]) { + LOG(FATAL) << "Wrong number of chips for layer " << j << "(" << mUnitPerStave[j] << ")"; + } + if (mChipThickness[j] < 0 && !mTRKLayer[j]) { + LOG(FATAL) << "Wrong chip thickness for layer " << j << "(" << mChipThickness[j] << ")"; + } + if (mTurboLayer[j] && mStaveWidth[j] <= 0) { + LOG(FATAL) << "Wrong stave width for layer " << j << "(" << mStaveWidth[j] << ")"; + } + if (mDetectorThickness[j] < 0) { + LOG(FATAL) << "Wrong Sensor thickness for layer " << j << "(" << mDetectorThickness[j] << ")"; + } + + if (j > 0 && // Always check IB, check OB only if present + ((j < mNumberOfInnerLayers) || mCreateOuterBarrel)) { + if (mLayerRadii[j] <= mLayerRadii[j - 1]) { + LOG(FATAL) << "Layer " << j << " radius (" << mLayerRadii[j] << ") is smaller than layer " << j - 1 + << " radius (" << mLayerRadii[j - 1] << ")"; + } + } + + if (mChipThickness[j] == 0 && !mTRKLayer[j]) { + LOG(INFO) << "Chip thickness for layer " << j << " not set, using default"; + } + } + + // Create the wrapper volumes + TGeoVolume** wrapVols = nullptr; + + if (sNumberOfWrapperVolumes && mCreateOuterBarrel) { + wrapVols = new TGeoVolume*[sNumberOfWrapperVolumes]; + for (int id = 1; id < sNumberOfWrapperVolumes; id++) { + wrapVols[id] = createWrapperVolume(id); + vITSV->AddNode(wrapVols[id], 1, nullptr); + } + } + if (!mCreateOuterBarrel) { + mTotalNumberOfLayers = mNumberOfInnerLayers; + } + + // Now create the actual geometry + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + TGeoVolume* dest = vITSV; + mWrapperLayerId[j] = -1; + + if (mTurboLayer[j]) { + mGeometry[j] = new V3Layer(j, kTRUE, kFALSE); + mGeometry[j]->setStaveWidth(mStaveWidth[j]); + mGeometry[j]->setStaveTilt(mStaveTilt[j]); + } else { + mGeometry[j] = new V3Layer(j, kFALSE); + } + + mGeometry[j]->setNumberOfInnerLayers(mNumberOfInnerLayers); + + if (mTRKLayer[j]) { + mGeometry[j]->setIsTRK(kTRUE); + mGeometry[j]->setIBModuleZLength(mLayerZLen[j]); + } + + mGeometry[j]->setPhi0(mLayerPhi0[j]); + mGeometry[j]->setRadius(mLayerRadii[j]); + mGeometry[j]->setNumberOfStaves(mStavePerLayer[j]); + mGeometry[j]->setNumberOfUnits(mUnitPerStave[j]); + mGeometry[j]->setChipType(mChipTypeID[j]); + mGeometry[j]->setBuildLevel(mBuildLevel[j]); + + if (j < mNumberOfInnerLayers) { + mGeometry[j]->setStaveModel(mStaveModelInnerBarrel); + } else { + mGeometry[j]->setStaveModel(mStaveModelOuterBarrel); + } + + LOG(DEBUG1) << "mBuildLevel: " << mBuildLevel[j]; + + if (mChipThickness[j] != 0) { + mGeometry[j]->setChipThick(mChipThickness[j]); + } + if (mDetectorThickness[j] != 0) { + mGeometry[j]->setSensorThick(mDetectorThickness[j]); + } + + if (mCreateOuterBarrel && j >= mNumberOfInnerLayers) { + for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) { + if (mLayerRadii[j] > mWrapperMinRadius[iw] && mLayerRadii[j] < mWrapperMaxRadius[iw]) { + LOG(DEBUG) << "Will embed layer " << j << " in wrapper volume " << iw; + + dest = wrapVols[iw]; + mWrapperLayerId[j] = iw; + break; + } + } + } + mGeometry[j]->createLayer(dest); + } + + // Finally create the services + mServicesGeometry = new V3Services(); + + // createInnerBarrelServices(wrapVols[0]); + // createMiddlBarrelServices(wrapVols[1]); + // createOuterBarrelServices(wrapVols[2]); + // createOuterBarrelSupports(vITSV); + + // TEMPORARY - These routines will be obsoleted once the new services are completed - TEMPORARY + // createServiceBarrel(kTRUE, wrapVols[0]); + // createServiceBarrel(kFALSE, wrapVols[2]); + delete[] wrapVols; // delete pointer only, not the volumes +} + +void Detector::createInnerBarrelServices(TGeoVolume* motherVolume) +{ + // + // Creates the Inner Barrel Service structures + // + // Input: + // motherVolume : the volume hosting the services + // + // Output: + // + // Return: + // + // Created: 15 May 2019 Mario Sitta + // (partially based on P.Namwongsa implementation in AliRoot) + // Updated: 19 Jun 2019 Mario Sitta IB Side A added + // Updated: 21 Oct 2019 Mario Sitta CYSS added + // + + // Create the End Wheels on Side A + TGeoVolume* endWheelsA = mServicesGeometry->createIBEndWheelsSideA(); + + motherVolume->AddNode(endWheelsA, 1, nullptr); + + // Create the End Wheels on Side C + TGeoVolume* endWheelsC = mServicesGeometry->createIBEndWheelsSideC(); + + motherVolume->AddNode(endWheelsC, 1, nullptr); + + // Create the CYSS Assembly (i.e. the supporting half cylinder and cone) + TGeoVolume* cyss = mServicesGeometry->createCYSSAssembly(); + + motherVolume->AddNode(cyss, 1, nullptr); +} + +void Detector::createMiddlBarrelServices(TGeoVolume* motherVolume) +{ + // + // Creates the Middle Barrel Service structures + // + // Input: + // motherVolume : the volume hosting the services + // + // Output: + // + // Return: + // + // Created: 24 Sep 2019 Mario Sitta + // + + // Create the End Wheels on Side A + mServicesGeometry->createMBEndWheelsSideA(motherVolume); + + // Create the End Wheels on Side C + mServicesGeometry->createMBEndWheelsSideC(motherVolume); +} + +void Detector::createOuterBarrelServices(TGeoVolume* motherVolume) +{ + // + // Creates the Outer Barrel Service structures + // + // Input: + // motherVolume : the volume hosting the services + // + // Output: + // + // Return: + // + // Created: 27 Sep 2019 Mario Sitta + // + + // Create the End Wheels on Side A + mServicesGeometry->createOBEndWheelsSideA(motherVolume); + + // Create the End Wheels on Side C + mServicesGeometry->createOBEndWheelsSideC(motherVolume); +} + +void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume) +{ + // + // Creates the Outer Barrel Service structures + // + // Input: + // motherVolume : the volume hosting the supports + // + // Output: + // + // Return: + // + // Created: 26 Jan 2020 Mario Sitta + // + + // Create the Cone on Side A + mServicesGeometry->createOBConeSideA(motherVolume); + + // Create the Cone on Side C + mServicesGeometry->createOBConeSideC(motherVolume); +} + +// Service Barrel +void Detector::createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr) +{ + // Creates the Service Barrel (as a simple cylinder) for IB and OB + // Inputs: + // innerBarrel : if true, build IB service barrel, otherwise for OB + // dest : the mother volume holding the service barrel + // mgr : the gGeoManager pointer (used to get the material) + // + + Double_t rminIB = 4.7; + Double_t rminOB = 43.9; + Double_t zLenOB; + Double_t cInt = 0.22; // dimensioni cilindro di supporto interno + Double_t cExt = 1.00; // dimensioni cilindro di supporto esterno + // Double_t phi1 = 180; + // Double_t phi2 = 360; + + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + + if (innerBarrel) { + zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); + // TGeoTube*ibSuppSh = new TGeoTubeSeg(rminIB,rminIB+cInt,zLenOB,phi1,phi2); + auto* ibSuppSh = new TGeoTube(rminIB, rminIB + cInt, zLenOB); + auto* ibSupp = new TGeoVolume("ibSuppCyl", ibSuppSh, medCarbonFleece); + dest->AddNode(ibSupp, 1); + } else { + zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); + auto* obSuppSh = new TGeoTube(rminOB, rminOB + cExt, zLenOB); + auto* obSupp = new TGeoVolume("obSuppCyl", obSuppSh, medCarbonFleece); + dest->AddNode(obSupp, 1); + } + + return; +} + +void Detector::addAlignableVolumes() const +{ + // + // Creates entries for alignable volumes associating the symbolic volume + // name with the corresponding volume path. + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + + LOG(INFO) << "Add ITS alignable volumes"; + + if (!gGeoManager) { + LOG(FATAL) << "TGeoManager doesn't exist !"; + return; + } + + TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern()); + TString sname = GeometryTGeo::composeSymNameTRK(); + + LOG(DEBUG) << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + Int_t lastUID = 0; + for (Int_t lr = 0; lr < mTotalNumberOfLayers; lr++) { + addAlignableVolumesLayer(lr, path, lastUID); + } + + return; +} + +void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const +{ + // + // Add alignable volumes for a Layer and its daughters + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + + TString wrpV = + mWrapperLayerId[lr] != -1 ? Form("%s%d_1", GeometryTGeo::getITSWrapVolPattern(), mWrapperLayerId[lr]) : ""; + TString path; + if (mCreateOuterBarrel && (lr >= mNumberOfInnerLayers)) { + path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr); + } else { + path = Form("%s/%s%d_1", parent.Data(), GeometryTGeo::getITSLayerPattern(), lr); + } + TString sname = GeometryTGeo::composeSymNameLayer(lr); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + const V3Layer* lrobj = mGeometry[lr]; + Int_t nstaves = lrobj->getNumberOfStavesPerParent(); + for (int st = 0; st < nstaves; st++) { + addAlignableVolumesStave(lr, st, path, lastUID); + } + + return; +} + +void Detector::addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const +{ + // + // Add alignable volumes for a Stave and its daughters + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSStavePattern(), lr, st); + TString sname = GeometryTGeo::composeSymNameStave(lr, st); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + const V3Layer* lrobj = mGeometry[lr]; + Int_t nhstave = lrobj->getNumberOfHalfStavesPerParent(); + Int_t start = nhstave > 0 ? 0 : -1; + for (Int_t sst = start; sst < nhstave; sst++) { + addAlignableVolumesHalfStave(lr, st, sst, path, lastUID); + } + + return; +} + +void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const +{ + // + // Add alignable volumes for a HalfStave (if any) and its daughters + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + + TString path = parent; + if (hst >= 0) { + path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfStavePattern(), lr, hst); + TString sname = GeometryTGeo::composeSymNameHalfStave(lr, st, hst); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + } + + const V3Layer* lrobj = mGeometry[lr]; + Int_t nmodules = lrobj->getNumberOfModulesPerParent(); + Int_t start = nmodules > 0 ? 0 : -1; + for (Int_t md = start; md < nmodules; md++) { + addAlignableVolumesModule(lr, st, hst, md, path, lastUID); + } + + return; +} + +void Detector::addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const +{ + // + // Add alignable volumes for a Module (if any) and its daughters + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + + TString path = parent; + if (md >= 0) { + path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSModulePattern(), lr, md); + TString sname = GeometryTGeo::composeSymNameModule(lr, st, hst, md); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + } + + const V3Layer* lrobj = mGeometry[lr]; + Int_t nchips = lrobj->getNumberOfChipsPerParent(); + for (Int_t ic = 0; ic < nchips; ic++) { + addAlignableVolumesChip(lr, st, hst, md, ic, path, lastUID); + } + + return; +} + +void Detector::addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, + Int_t& lastUID) const +{ + // + // Add alignable volumes for a Chip + // + // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) + // + + TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSChipPattern(), lr, ch); + TString sname = GeometryTGeo::composeSymNameChip(lr, st, hst, md, ch); + Int_t modUID = chipVolUID(lastUID++); + + LOG(DEBUG) << "Add " << sname << " <-> " << path; + + if (!gGeoManager->SetAlignableEntry(sname, path.Data(), modUID)) { + LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + return; +} + +void Detector::defineSensitiveVolumes() +{ + TGeoManager* geoManager = gGeoManager; + TGeoVolume* v; + + TString volumeName; + + // The names of the ITS sensitive volumes have the format: ITSUSensor(0...sNumberLayers-1) + for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { + volumeName = GeometryTGeo::getITSSensorPattern() + TString::Itoa(j, 10); + v = geoManager->GetVolume(volumeName.Data()); + AddSensitiveVolume(v); + } +} + +Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, + unsigned char endStatus) +{ + mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); + return &(mHits->back()); +} + +void Detector::Print(std::ostream* os) const +{ + // Standard output format for this class. + // Inputs: + // ostream *os The output stream + // Outputs: + // none. + // Return: + // none. + +#if defined __GNUC__ +#if __GNUC__ > 2 + std::ios::fmtflags fmt; +#else + Int_t fmt; +#endif +#else +#if defined __ICC || defined __ECC || defined __xlC__ + ios::fmtflags fmt; +#else + Int_t fmt; +#endif +#endif + // RS: why do we need to pring this garbage? + + // fmt = os->setf(std::ios::scientific); // set scientific floating point output + // fmt = os->setf(std::ios::hex); // set hex for mStatus only. + // fmt = os->setf(std::ios::dec); // every thing else decimel. + // *os << mModule << " "; + // *os << mEnergyDepositionStep << " " << mTof; + // *os << " " << mStartingStepX << " " << mStartingStepY << " " << mStartingStepZ; + // *os << " " << endl; + // os->flags(fmt); // reset back to old formating. + return; +} + +void Detector::Read(std::istream* is) +{ + // Standard input format for this class. + // Inputs: + // istream *is the input stream + // Outputs: + // none. + // Return: + // none. + // RS no need to read garbage + return; +} + +std::ostream& operator<<(std::ostream& os, Detector& p) +{ + // Standard output streaming function. + // Inputs: + // ostream os The output stream + // Detector p The his to be printed out + // Outputs: + // none. + // Return: + // The input stream + + p.Print(&os); + return os; +} + +std::istream& operator>>(std::istream& is, Detector& r) +{ + // Standard input streaming function. + // Inputs: + // istream is The input stream + // Detector p The Detector class to be filled from this input stream + // Outputs: + // none. + // Return: + // The input stream + + r.Read(&is); + return is; +} + +ClassImp(o2::trk::Detector); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h new file mode 100644 index 0000000000000..d2449d28293e2 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::trk::V11Geometry + ; +#pragma link C++ class o2::trk::V1Layer + ; +#pragma link C++ class o2::trk::V3Layer + ; +#pragma link C++ class o2::trk::V3Services + ; +#pragma link C++ class o2::trk::Detector + ; +#pragma link C++ class o2::base::DetImpl < o2::trk::Detector> + ; + +#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V11Geometry.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V11Geometry.cxx similarity index 93% rename from Detectors/Upgrades/PostLS4/IT4/simulation/src/V11Geometry.cxx rename to Detectors/Upgrades/ALICE3/TRK/simulation/src/V11Geometry.cxx index ce89b44ada297..8328bbdc5f0f4 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V11Geometry.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V11Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,7 @@ /// \file V11Geometry.cxx /// \brief Implementation of the V11Geometry class -#include "ITS4Simulation/V11Geometry.h" +#include "TRKSimulation/V11Geometry.h" #include "FairLogger.h" // for LOG @@ -38,9 +39,9 @@ using std::cin; using std::cout; using std::endl; -using namespace o2::its4; +using namespace o2::trk; -ClassImp(o2::its4::V11Geometry); +ClassImp(o2::trk::V11Geometry); const Double_t V11Geometry::sMicron = 1.0E-4; const Double_t V11Geometry::sMm = 0.10; @@ -392,30 +393,30 @@ void V11Geometry::createDefaultMaterials() Double_t w; // Define some elements - auto* itsH = new TGeoElement("IT4_H", "Hydrogen", 1, 1.00794); - auto* itsHe = new TGeoElement("IT4_He", "Helium", 2, 4.002602); - auto* itsC = new TGeoElement("IT4_C", "Carbon", 6, 12.0107); - auto* itsN = new TGeoElement("IT4_N", "Nitrogen", 7, 14.0067); - auto* itsO = new TGeoElement("IT4_O", "Oxygen", 8, 15.994); - auto* itsF = new TGeoElement("IT4_F", "Florine", 9, 18.9984032); - auto* itsNe = new TGeoElement("IT4_Ne", "Neon", 10, 20.1797); - auto* itsMg = new TGeoElement("IT4_Mg", "Magnesium", 12, 24.3050); - auto* itsAl = new TGeoElement("IT4_Al", "Aluminum", 13, 26981538); - auto* itsSi = new TGeoElement("IT4_Si", "Silicon", 14, 28.0855); - auto* itsP = new TGeoElement("IT4_P", "Phosphorous", 15, 30.973761); - auto* itsS = new TGeoElement("IT4_S", "Sulfur", 16, 32.065); - auto* itsAr = new TGeoElement("IT4_Ar", "Argon", 18, 39.948); - auto* itsTi = new TGeoElement("IT4_Ti", "Titanium", 22, 47.867); - auto* itsCr = new TGeoElement("IT4_Cr", "Chromium", 24, 51.9961); - auto* itsMn = new TGeoElement("IT4_Mn", "Manganese", 25, 54.938049); - auto* itsFe = new TGeoElement("IT4_Fe", "Iron", 26, 55.845); - auto* itsCo = new TGeoElement("IT4_Co", "Cobalt", 27, 58.933200); - auto* itsNi = new TGeoElement("IT4_Ni", "Nickrl", 28, 56.6930); - auto* itsCu = new TGeoElement("IT4_Cu", "Copper", 29, 63.546); - auto* itsZn = new TGeoElement("IT4_Zn", "Zinc", 30, 65.39); - auto* itsKr = new TGeoElement("IT4_Kr", "Krypton", 36, 83.80); - auto* itsMo = new TGeoElement("IT4_Mo", "Molylibdium", 42, 95.94); - auto* itsXe = new TGeoElement("IT4_Xe", "Zeon", 54, 131.293); + auto* itsH = new TGeoElement("TRK_H", "Hydrogen", 1, 1.00794); + auto* itsHe = new TGeoElement("TRK_He", "Helium", 2, 4.002602); + auto* itsC = new TGeoElement("TRK_C", "Carbon", 6, 12.0107); + auto* itsN = new TGeoElement("TRK_N", "Nitrogen", 7, 14.0067); + auto* itsO = new TGeoElement("TRK_O", "Oxygen", 8, 15.994); + auto* itsF = new TGeoElement("TRK_F", "Florine", 9, 18.9984032); + auto* itsNe = new TGeoElement("TRK_Ne", "Neon", 10, 20.1797); + auto* itsMg = new TGeoElement("TRK_Mg", "Magnesium", 12, 24.3050); + auto* itsAl = new TGeoElement("TRK_Al", "Aluminum", 13, 26981538); + auto* itsSi = new TGeoElement("TRK_Si", "Silicon", 14, 28.0855); + auto* itsP = new TGeoElement("TRK_P", "Phosphorous", 15, 30.973761); + auto* itsS = new TGeoElement("TRK_S", "Sulfur", 16, 32.065); + auto* itsAr = new TGeoElement("TRK_Ar", "Argon", 18, 39.948); + auto* itsTi = new TGeoElement("TRK_Ti", "Titanium", 22, 47.867); + auto* itsCr = new TGeoElement("TRK_Cr", "Chromium", 24, 51.9961); + auto* itsMn = new TGeoElement("TRK_Mn", "Manganese", 25, 54.938049); + auto* itsFe = new TGeoElement("TRK_Fe", "Iron", 26, 55.845); + auto* itsCo = new TGeoElement("TRK_Co", "Cobalt", 27, 58.933200); + auto* itsNi = new TGeoElement("TRK_Ni", "Nickrl", 28, 56.6930); + auto* itsCu = new TGeoElement("TRK_Cu", "Copper", 29, 63.546); + auto* itsZn = new TGeoElement("TRK_Zn", "Zinc", 30, 65.39); + auto* itsKr = new TGeoElement("TRK_Kr", "Krypton", 36, 83.80); + auto* itsMo = new TGeoElement("TRK_Mo", "Molylibdium", 42, 95.94); + auto* itsXe = new TGeoElement("TRK_Xe", "Zeon", 54, 131.293); // Start with the Materials since for any one material there // can be defined more than one Medium. @@ -426,7 +427,7 @@ void V11Geometry::createDefaultMaterials() // He 0.000524% (0.00007%), Kr 0.000114% (0.0003%), H2 0.00005% (3.5E-6%), // Xe 0.0000087% (0.00004 %), H2O 0.0% (dry) + trace amounts at the ppm // levels. - auto* itsAir = new TGeoMixture("IT4_Air", 9); + auto* itsAir = new TGeoMixture("TRK_Air", 9); w = 75.47E-2; itsAir->AddElement(itsN, w); // Nitorgen, atomic w = 23.29E-2 + // O2 @@ -453,12 +454,12 @@ void V11Geometry::createDefaultMaterials() itsAir->SetState(TGeoMaterial::kMatStateGas); // Silicone - auto* itsSiDet = new TGeoMaterial("IT4_Si", itsSi, 2.33 * sGCm3); + auto* itsSiDet = new TGeoMaterial("TRK_Si", itsSi, 2.33 * sGCm3); itsSiDet->SetTemperature(15.0 * sCelsius); itsSiDet->SetState(TGeoMaterial::kMatStateSolid); // Epoxy C18 H19 O3 - auto* itsEpoxy = new TGeoMixture("IT4_Epoxy", 3); + auto* itsEpoxy = new TGeoMixture("TRK_Epoxy", 3); itsEpoxy->AddElement(itsC, 18); itsEpoxy->AddElement(itsH, 19); itsEpoxy->AddElement(itsO, 3); @@ -474,7 +475,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsCarbonFiber = new TGeoMixture("IT4_CarbonFiber-M55J", 4); + auto* itsCarbonFiber = new TGeoMixture("TRK_CarbonFiber-M55J", 4); // Assume that the epoxy fill in the space between the fibers and so // no change in the total volume. To compute w, assume 1cm^3 total // volume. @@ -501,7 +502,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsFoam = new TGeoMixture("IT4_Foam", 4); + auto* itsFoam = new TGeoMixture("TRK_Foam", 4); itsFoam->AddElement(itsC, 9); itsFoam->AddElement(itsH, 13); itsFoam->AddElement(itsN, 1); @@ -521,7 +522,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsKapton = new TGeoMixture("IT4_Kapton", 4); + auto* itsKapton = new TGeoMixture("TRK_Kapton", 4); itsKapton->AddElement(itsH, 0.026362); itsKapton->AddElement(itsC, 0.691133); itsKapton->AddElement(itsN, 0.073270); @@ -541,7 +542,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsUpilex = new TGeoMixture("IT4_Upilex", 4); + auto* itsUpilex = new TGeoMixture("TRK_Upilex", 4); itsUpilex->AddElement(itsC, 16); itsUpilex->AddElement(itsH, 6); itsUpilex->AddElement(itsN, 2); @@ -563,7 +564,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsAl6061 = new TGeoMixture("IT4_Al6061", 9); + auto* itsAl6061 = new TGeoMixture("TRK_Al6061", 9); itsAl6061->AddElement(itsCr, 0.000375); itsAl6061->AddElement(itsCu, 0.00275); itsAl6061->AddElement(itsFe, 0.0035); @@ -590,7 +591,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsAl7075 = new TGeoMixture("IT4_Al7075", 9); + auto* itsAl7075 = new TGeoMixture("TRK_Al7075", 9); itsAl7075->AddElement(itsCr, 0.0023); itsAl7075->AddElement(itsCu, 0.016); itsAl7075->AddElement(itsFe, 0.0025); @@ -614,7 +615,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsRuby = new TGeoMixture("IT4_RubySphere", 2); + auto* itsRuby = new TGeoMixture("TRK_RubySphere", 2); itsRuby->AddElement(itsAl, 2); itsRuby->AddElement(itsO, 3); itsRuby->SetTitle("Ruby reference sphere"); @@ -633,7 +634,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsInox304L = new TGeoMixture("IT4_Inox304L", 9); + auto* itsInox304L = new TGeoMixture("TRK_Inox304L", 9); itsInox304L->AddElement(itsC, 0.00015); itsInox304L->AddElement(itsMn, 0.010); itsInox304L->AddElement(itsSi, 0.005); @@ -659,7 +660,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsInox316L = new TGeoMixture("IT4_Inox316L", 9); + auto* itsInox316L = new TGeoMixture("TRK_Inox316L", 9); itsInox316L->AddElement(itsC, 0.00015); itsInox316L->AddElement(itsMn, 0.010); itsInox316L->AddElement(itsSi, 0.005); @@ -688,7 +689,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsPhynox = new TGeoMixture("IT4_Phynox", 7); + auto* itsPhynox = new TGeoMixture("TRK_Phynox", 7); itsPhynox->AddElement(itsC, 0.0015); itsPhynox->AddElement(itsMn, 0.020); itsPhynox->AddElement(itsNi, 0.18); @@ -704,7 +705,7 @@ void V11Geometry::createDefaultMaterials() // G10FR4 // Demineralized Water H2O SDD & SSD Cooling liquid - auto* itsWater = new TGeoMixture("IT4_Water", 2); + auto* itsWater = new TGeoMixture("TRK_Water", 2); itsWater->AddElement(itsH, 2); itsWater->AddElement(itsO, 1); itsWater->SetTitle("ITS Cooling Water"); @@ -721,7 +722,7 @@ void V11Geometry::createDefaultMaterials() </A> */ // End_Html - auto* itsFreon = new TGeoMixture("IT4_SPD_Freon", 2); + auto* itsFreon = new TGeoMixture("TRK_SPD_Freon", 2); itsFreon->AddElement(itsC, 4); itsFreon->AddElement(itsF, 10); itsFreon->SetTitle("ITS SPD 2 phase Cooling freon"); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/V1Layer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V1Layer.cxx new file mode 100644 index 0000000000000..8be0023afb7cc --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V1Layer.cxx @@ -0,0 +1,2763 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file V1Layer.cxx +/// \brief Implementation of the V1Layer class +/// \author Mario Sitta <sitta@to.infn.it> +/// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) + +#include "TRKSimulation/V1Layer.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKSimulation/Detector.h" + +#include "FairLogger.h" // for LOG + +#include <TGeoArb8.h> // for TGeoArb8 +#include <TGeoBBox.h> // for TGeoBBox +#include <TGeoCone.h> // for TGeoConeSeg, TGeoCone +#include <TGeoManager.h> // for TGeoManager, gGeoManager +#include <TGeoMatrix.h> // for TGeoCombiTrans, TGeoRotation, etc +#include <TGeoTrd1.h> // for TGeoTrd1 +#include <TGeoTube.h> // for TGeoTube, TGeoTubeSeg +#include <TGeoVolume.h> // for TGeoVolume, TGeoVolumeAssembly +#include <TGeoXtru.h> // for TGeoXtru +#include "TMathBase.h" // for Abs +#include <TMath.h> // for Sin, RadToDeg, DegToRad, Cos, Tan, etc + +#include <cstdio> // for snprintf + +class TGeoMedium; + +using namespace TMath; +using namespace o2::trk; + +// General Parameters +const Int_t V1Layer::sNumberOmInnerLayers = 3; + +const Double_t V1Layer::sDefaultSensorThick = 300 * sMicron; +const Double_t V1Layer::sDefaultStaveThick = 1 * sCm; + +// Inner Barrel Parameters +const Int_t V1Layer::sIBChipsPerRow = 9; +const Int_t V1Layer::sIBNChipRows = 1; + +// Outer Barrel Parameters +const Int_t V1Layer::sOBChipsPerRow = 7; +const Int_t V1Layer::sOBNChipRows = 2; + +const Double_t V1Layer::sOBHalfStaveWidth = 3.01 * sCm; +const Double_t V1Layer::sOBModuleWidth = sOBHalfStaveWidth; +const Double_t V1Layer::sOBModuleGap = 0.01 * sCm; +const Double_t V1Layer::sOBChipXGap = 0.01 * sCm; +const Double_t V1Layer::sOBChipZGap = 0.01 * sCm; +const Double_t V1Layer::sOBFlexCableAlThick = 0.005 * sCm; +const Double_t V1Layer::sOBFlexCableKapThick = 0.01 * sCm; +const Double_t V1Layer::sOBBusCableAlThick = 0.02 * sCm; +const Double_t V1Layer::sOBBusCableKapThick = 0.02 * sCm; +const Double_t V1Layer::sOBColdPlateThick = 0.012 * sCm; +const Double_t V1Layer::sOBCarbonPlateThick = 0.012 * sCm; +const Double_t V1Layer::sOBGlueThick = 0.03 * sCm; +const Double_t V1Layer::sOBModuleZLength = 21.06 * sCm; +const Double_t V1Layer::sOBHalfStaveYTrans = 1.76 * sMm; +const Double_t V1Layer::sOBHalfStaveXOverlap = 4.3 * sMm; +const Double_t V1Layer::sOBGraphiteFoilThick = 30.0 * sMicron; +const Double_t V1Layer::sOBCoolTubeInnerD = 2.052 * sMm; +const Double_t V1Layer::sOBCoolTubeThick = 32.0 * sMicron; +const Double_t V1Layer::sOBCoolTubeXDist = 11.1 * sMm; + +const Double_t V1Layer::sOBSpaceFrameWidth = 42.0 * sMm; +const Double_t V1Layer::sOBSpaceFrameTotHigh = 43.1 * sMm; +const Double_t V1Layer::sOBSFrameBeamRadius = 0.6 * sMm; +const Double_t V1Layer::sOBSpaceFrameLa = 3.0 * sMm; +const Double_t V1Layer::sOBSpaceFrameHa = 0.721979 * sMm; +const Double_t V1Layer::sOBSpaceFrameLb = 3.7 * sMm; +const Double_t V1Layer::sOBSpaceFrameHb = 0.890428 * sMm; +const Double_t V1Layer::sOBSpaceFrameL = 0.25 * sMm; +const Double_t V1Layer::sOBSFBotBeamAngle = 56.5; +const Double_t V1Layer::sOBSFrameBeamSidePhi = 65.0; + +ClassImp(V1Layer); + +#define SQ(A) (A) * (A) + +V1Layer::V1Layer() + : V11Geometry(), + mLayerNumber(0), + mPhi0(0), + mLayerRadius(0), + mZLength(0), + mSensorThickness(0), + mStaveThickness(0), + mStaveWidth(0), + mStaveTilt(0), + mNumberOfStaves(0), + mNumberOfModules(0), + mNumberOfChips(0), + mChipTypeID(0), + mIsTurbo(false), + mBuildLevel(0), + mStaveModel(Detector::kIBModelDummy) +{ + for (int i = kNHLevels; i--;) { + mHierarchy[i] = 0; + } +} + +V1Layer::V1Layer(Int_t debug) + : V11Geometry(debug), + mLayerNumber(0), + mPhi0(0), + mLayerRadius(0), + mZLength(0), + mSensorThickness(0), + mStaveThickness(0), + mStaveWidth(0), + mStaveTilt(0), + mNumberOfStaves(0), + mNumberOfModules(0), + mNumberOfChips(0), + mChipTypeID(0), + mIsTurbo(false), + mBuildLevel(0), + mStaveModel(Detector::kIBModelDummy) +{ + for (int i = kNHLevels; i--;) { + mHierarchy[i] = 0; + } +} + +V1Layer::V1Layer(Int_t lay, Int_t debug) + : V11Geometry(debug), + mLayerNumber(lay), + mPhi0(0), + mLayerRadius(0), + mZLength(0), + mSensorThickness(0), + mStaveThickness(0), + mStaveWidth(0), + mStaveTilt(0), + mNumberOfStaves(0), + mNumberOfModules(0), + mNumberOfChips(0), + mChipTypeID(0), + mIsTurbo(false), + mBuildLevel(0), + mStaveModel(Detector::kIBModelDummy) +{ + for (int i = kNHLevels; i--;) { + mHierarchy[i] = 0; + } +} + +V1Layer::V1Layer(Int_t lay, Bool_t turbo, Int_t debug) + : V11Geometry(debug), + mLayerNumber(lay), + mPhi0(0), + mLayerRadius(0), + mZLength(0), + mSensorThickness(0), + mStaveThickness(0), + mStaveWidth(0), + mStaveTilt(0), + mNumberOfStaves(0), + mNumberOfModules(0), + mNumberOfChips(0), + mChipTypeID(0), + mIsTurbo(turbo), + mBuildLevel(0), + mStaveModel(Detector::kIBModelDummy) +{ + for (int i = kNHLevels; i--;) { + mHierarchy[i] = 0; + } +} + +V1Layer::V1Layer(const V1Layer& s) + : V11Geometry(s.getDebug()), + mLayerNumber(s.mLayerNumber), + mPhi0(s.mPhi0), + mLayerRadius(s.mLayerRadius), + mZLength(s.mZLength), + mSensorThickness(s.mSensorThickness), + mStaveThickness(s.mStaveThickness), + mStaveWidth(s.mStaveWidth), + mStaveTilt(s.mStaveTilt), + mNumberOfStaves(s.mNumberOfStaves), + mNumberOfModules(s.mNumberOfModules), + mNumberOfChips(s.mNumberOfChips), + mChipTypeID(s.mChipTypeID), + mIsTurbo(s.mIsTurbo), + mBuildLevel(s.mBuildLevel), + mStaveModel(s.mStaveModel) +{ + for (int i = kNHLevels; i--;) { + mHierarchy[i] = s.mHierarchy[i]; + } +} + +V1Layer& V1Layer::operator=(const V1Layer& s) +{ + if (&s == this) { + return *this; + } + + mLayerNumber = s.mLayerNumber; + mPhi0 = s.mPhi0; + mLayerRadius = s.mLayerRadius; + mZLength = s.mZLength; + mSensorThickness = s.mSensorThickness; + mStaveThickness = s.mStaveThickness; + mStaveWidth = s.mStaveWidth; + mStaveTilt = s.mStaveTilt; + mNumberOfStaves = s.mNumberOfStaves; + mNumberOfModules = s.mNumberOfModules; + mNumberOfChips = s.mNumberOfChips; + mIsTurbo = s.mIsTurbo; + mChipTypeID = s.mChipTypeID; + mBuildLevel = s.mBuildLevel; + mStaveModel = s.mStaveModel; + for (int i = kNHLevels; i--;) { + mHierarchy[i] = s.mHierarchy[i]; + } + + return *this; +} + +V1Layer::~V1Layer() = default; + +void V1Layer::createLayer(TGeoVolume* motherVolume) +{ + char volumeName[30]; + Double_t xpos, ypos, zpos; + Double_t alpha; + + // Check if the user set the proper parameters + if (mLayerRadius <= 0) { + LOG(FATAL) << "Wrong layer radius " << mLayerRadius; + } + + if (mZLength <= 0) { + LOG(FATAL) << "Wrong layer length " << mZLength; + } + + if (mNumberOfStaves <= 0) { + LOG(FATAL) << "Wrong number of staves " << mNumberOfStaves; + } + + if (mNumberOfChips <= 0) { + LOG(FATAL) << "Wrong number of chips " << mNumberOfChips; + } + + if (mLayerNumber >= sNumberOmInnerLayers && mNumberOfModules <= 0) { + LOG(FATAL) << "Wrong number of modules " << mNumberOfModules; + } + + if (mStaveThickness <= 0) { + LOG(INFO) << "Stave thickness wrong or not set " << mStaveThickness << " using default " + << sDefaultStaveThick; + mStaveThickness = sDefaultStaveThick; + } + + if (mSensorThickness <= 0) { + LOG(INFO) << "Sensor thickness wrong or not set " << mSensorThickness << " using default " + << sDefaultSensorThick; + mSensorThickness = sDefaultSensorThick; + } + + if (mSensorThickness > mStaveThickness) { + LOG(WARNING) << "Sensor thickness " << mSensorThickness << " is greater than stave thickness " + << mStaveThickness << " fixing"; + mSensorThickness = mStaveThickness; + } + + // If a Turbo layer is requested, do it and exit + if (mIsTurbo) { + createLayerTurbo(motherVolume); + return; + } + + // First create the stave container + alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); + + // mStaveWidth = mLayerRadius*Tan(alpha); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSLayerPattern(), mLayerNumber); + TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); + layerVolume->SetUniqueID(mChipTypeID); + + // layerVolume->SetVisibility(kFALSE); + layerVolume->SetVisibility(kTRUE); + layerVolume->SetLineColor(1); + + TGeoVolume* stavVol = createStave(); + + // Now build up the layer + alpha = 360. / mNumberOfStaves; + Double_t r = mLayerRadius + ((TGeoBBox*)stavVol->GetShape())->GetDY(); + for (Int_t j = 0; j < mNumberOfStaves; j++) { + Double_t phi = j * alpha + mPhi0; + xpos = r * cosD(phi); // r*sinD(-phi); + ypos = r * sinD(phi); // r*cosD(-phi); + zpos = 0.; + phi += 90; + layerVolume->AddNode(stavVol, j, + new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi, 0, 0))); + } + + // Finally put everything in the mother volume + motherVolume->AddNode(layerVolume, 1, nullptr); + + // geometry is served + return; +} + +void V1Layer::createLayerTurbo(TGeoVolume* motherVolume) +{ + char volumeName[30]; + Double_t xpos, ypos, zpos; + Double_t alpha; + + // Check if the user set the proper (remaining) parameters + if (mStaveWidth <= 0) { + LOG(FATAL) << "Wrong stave width " << mStaveWidth; + } + + if (Abs(mStaveTilt) > 45) { + LOG(WARNING) << "Stave tilt angle (" << mStaveTilt << ") greater than 45deg"; + } + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSLayerPattern(), mLayerNumber); + TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); + layerVolume->SetUniqueID(mChipTypeID); + layerVolume->SetVisibility(kTRUE); + layerVolume->SetLineColor(1); + TGeoVolume* stavVol = createStave(); + + // Now build up the layer + alpha = 360. / mNumberOfStaves; + Double_t r = mLayerRadius /* +chip thick ?! */; + for (Int_t j = 0; j < mNumberOfStaves; j++) { + Double_t phi = j * alpha + mPhi0; + xpos = r * cosD(phi); // r*sinD(-phi); + ypos = r * sinD(phi); // r*cosD(-phi); + zpos = 0.; + phi += 90; + layerVolume->AddNode( + stavVol, j, + new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi - mStaveTilt, 0, 0))); + } + + // Finally put everything in the mother volume + motherVolume->AddNode(layerVolume, 1, nullptr); + + return; +} + +TGeoVolume* V1Layer::createStave(const TGeoManager* /*mgr*/) +{ + char volumeName[30]; + + Double_t xlen, ylen, zlen; + Double_t xpos, ypos; + Double_t alpha; + + // First create all needed shapes + alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); + + // The stave + xlen = mLayerRadius * Tan(alpha); + if (mIsTurbo) { + xlen = 0.5 * mStaveWidth; + } + ylen = 0.5 * mStaveThickness; + zlen = 0.5 * mZLength; + + Double_t yplus = 0.46; + auto* stave = new TGeoXtru(2); // z sections + Double_t xv[5] = {xlen, xlen, 0, -xlen, -xlen}; + Double_t yv[5] = {ylen + 0.09, -0.15, -yplus - mSensorThickness, -0.15, ylen + 0.09}; + stave->DefinePolygon(5, xv, yv); + stave->DefineSection(0, -zlen, 0, 0, 1.); + stave->DefineSection(1, +zlen, 0, 0, 1.); + + // We have all shapes: now create the real volumes + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSStavePattern(), mLayerNumber); + // TGeoVolume *staveVol = new TGeoVolume(volumeName, stave, medAir); + TGeoVolume* staveVol = new TGeoVolumeAssembly(volumeName); + + // staveVol->SetVisibility(kFALSE); + staveVol->SetVisibility(kTRUE); + staveVol->SetLineColor(2); + TGeoVolume* mechStaveVol = nullptr; + + // Now build up the stave + if (mLayerNumber < sNumberOmInnerLayers) { + TGeoVolume* modVol = createStaveInnerB(xlen, ylen, zlen); + staveVol->AddNode(modVol, 0); + mHierarchy[kHalfStave] = 1; + + // Mechanical stave structure + mechStaveVol = createStaveStructInnerB(xlen, zlen); + if (mechStaveVol) { + ypos = ((TGeoBBox*)(modVol->GetShape()))->GetDY() + + ((TGeoBBox*)(mechStaveVol->GetShape()))->GetDY(); + staveVol->AddNode(mechStaveVol, 1, + new TGeoCombiTrans(0, -ypos, 0, new TGeoRotation("", 0, 0, 180))); + } + } else { + TGeoVolume* hstaveVol = createStaveOuterB(); + if (mStaveModel == Detector::kOBModel0) { // Create simplified stave struct as in v0 + staveVol->AddNode(hstaveVol, 0); + mHierarchy[kHalfStave] = 1; + } else { // (if mStaveModel) Create new stave struct as in TDR + xpos = ((TGeoBBox*)(hstaveVol->GetShape()))->GetDX() - sOBHalfStaveXOverlap / 2; + // ypos is CF height as computed in createSpaceFrameOuterB1 + ypos = (sOBSpaceFrameTotHigh - sOBHalfStaveYTrans) / 2; + staveVol->AddNode(hstaveVol, 0, new TGeoTranslation(-xpos, ypos, 0)); + staveVol->AddNode(hstaveVol, 1, new TGeoTranslation(xpos, ypos + sOBHalfStaveYTrans, 0)); + mHierarchy[kHalfStave] = 2; // RS + mechStaveVol = createSpaceFrameOuterB(); + + if (mechStaveVol) { + staveVol->AddNode(mechStaveVol, 1, + new TGeoCombiTrans(0, 0, 0, new TGeoRotation("", 180, 0, 0))); + } + } + } + // Done, return the stave + return staveVol; +} + +TGeoVolume* V1Layer::createStaveInnerB(const Double_t xsta, const Double_t ysta, + const Double_t zsta, const TGeoManager* mgr) +{ + Double_t xmod, ymod, zmod; + char volumeName[30]; + + // First we create the module (i.e. the HIC with 9 chips) + TGeoVolume* moduleVol = createModuleInnerB(xsta, ysta, zsta); + + // Then we create the fake halfstave and the actual stave + xmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDX(); + ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); + zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); + + auto* hstave = new TGeoBBox(xmod, ymod, zmod); + + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); + + // Finally build it up + hstaveVol->AddNode(moduleVol, 0); + mHierarchy[kModule] = 1; + + // Done, return the stave structure + return hstaveVol; +} + +TGeoVolume* V1Layer::createModuleInnerB(Double_t xmod, Double_t ymod, Double_t zmod, + const TGeoManager* mgr) +{ + Double_t zchip; + Double_t zpos; + char volumeName[30]; + + // First create the single chip + zchip = zmod / sIBChipsPerRow; + TGeoVolume* chipVol = createChipInnerB(xmod, ymod, zchip); + + // Then create the module and populate it with the chips + auto* module = new TGeoBBox(xmod, ymod, zmod); + + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); + auto* modVol = new TGeoVolume(volumeName, module, medAir); + + // mm (not used) zlen = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); + for (Int_t j = 0; j < sIBChipsPerRow; j++) { + zpos = -zmod + j * 2 * zchip + zchip; + modVol->AddNode(chipVol, j, new TGeoTranslation(0, 0, zpos)); + mHierarchy[kChip]++; + } + // Done, return the module + return modVol; +} + +TGeoVolume* V1Layer::createStaveStructInnerB(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + TGeoVolume* mechStavVol = nullptr; + + switch (mStaveModel) { + case Detector::kIBModelDummy: + mechStavVol = createStaveModelInnerBDummy(xsta, zsta, mgr); + break; + case Detector::kIBModel0: + mechStavVol = createStaveModelInnerB0(xsta, zsta, mgr); + break; + case Detector::kIBModel1: + mechStavVol = createStaveModelInnerB1(xsta, zsta, mgr); + break; + case Detector::kIBModel21: + mechStavVol = createStaveModelInnerB21(xsta, zsta, mgr); + break; + case Detector::kIBModel22: + mechStavVol = createStaveModelInnerB22(xsta, zsta, mgr); + break; + case Detector::kIBModel3: + mechStavVol = createStaveModelInnerB3(xsta, zsta, mgr); + break; + default: + LOG(FATAL) << "Unknown stave model " << mStaveModel; + break; + } + return mechStavVol; +} + +TGeoVolume* V1Layer::createStaveModelInnerBDummy(const Double_t, const Double_t, + const TGeoManager*) const +{ + // Done, return the stave structur + return nullptr; +} + +TGeoVolume* V1Layer::createStaveModelInnerB0(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + LOG(INFO) << "################################# pointer :" << medWater; + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + LOG(INFO) << "################################# pointer :" << medM60J3K; + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medFlexCable = mgr->GetMedium("TRK_FLEXCABLE$"); + + // Local parameters + Double_t kConeOutRadius = 0.15 / 2; + Double_t kConeInRadius = 0.1430 / 2; + Double_t kStaveLength = zsta * 2; + Double_t kStaveWidth = xsta * 2 - kConeOutRadius * 2; + Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth + Double_t kStaveHeight = 0.3; + Double_t kHeight = kStaveHeight / 2; + Double_t kAlpha = 90 - 67; // 90-33.69; + Double_t kTheta = kAlpha * TMath::DegToRad(); + Double_t kS1 = kWidth / TMath::Sin(kTheta); + Double_t kL1 = kWidth / TMath::Tan(kTheta); + Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); + Double_t kThe2 = TMath::ATan(kHeight / kS1); + Double_t kBeta = kThe2 * TMath::RadToDeg(); + // Int_t loop = kStaveLength/(kL1); + // Double_t s3 = kWidth/(2*TMath::Sin(kTheta)); + // Double_t s4 = 3*kWidth/(2*TMath::Sin(kTheta)); + + LOG(DEBUG1) << "BuildLevel " << mBuildLevel; + + char volumeName[30]; + snprintf(volumeName, 30, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), + mLayerNumber); + + Double_t z = 0, y = -0.011 + 0.0150, x = 0; + + TGeoVolume* mechStavVol = nullptr; + + if (mBuildLevel < 5) { + + // world (trapezoid) + auto* mechStruct = new TGeoXtru(2); // z sections + Double_t xv[5] = { + kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, + -kStaveWidth / 2 - 0.1}; + Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; + mechStruct->DefinePolygon(5, xv, yv); + mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); + mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); + + mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); + mechStavVol->SetLineColor(12); + mechStavVol->SetFillColor(12); + mechStavVol->SetVisibility(kTRUE); + + // detailed structure ++++++++++++++ + // Pipe Kapton grey-35 + auto* coolTube = new TGeoTube(kConeInRadius, kConeOutRadius, kStaveLength / 2); + auto* volCoolTube = new TGeoVolume("pipe", coolTube, medKapton); + volCoolTube->SetFillColor(35); + volCoolTube->SetLineColor(35); + mechStavVol->AddNode(volCoolTube, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); + mechStavVol->AddNode(volCoolTube, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); + } + + if (mBuildLevel < 4) { + auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength / 2); + auto* volCoolTubeW = new TGeoVolume("pipeWater", coolTubeW, medWater); + volCoolTubeW->SetFillColor(4); + volCoolTubeW->SetLineColor(4); + mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); + mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); + } + + // frequency of filament + // n = 4 means very dense(4 filaments per interval) + // n = 2 means dense(2 filaments per interval) + Int_t n = 4; + Int_t loop = (Int_t)(kStaveLength / (4 * kL1 / n) + 2 / n) - 1; + if (mBuildLevel < 3) { + // Top CFRP Filament black-12 Carbon structure TGeoBBox (length,thickness,width) + auto* t2 = new TGeoBBox(kS2, 0.007 / 2, 0.15 / 2); //(kS2,0.002,0.02); + auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); + volT2->SetLineColor(12); + volT2->SetFillColor(12); + + for (int i = 1; i < loop; i++) { // i<60;i++){ + mechStavVol->AddNode( + volT2, 4 * i + 0, + new TGeoCombiTrans( + x + kWidth, y + (2 * kConeOutRadius), + z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 1, + new TGeoCombiTrans( + x - kWidth, y + (2 * kConeOutRadius), + z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 2, + new TGeoCombiTrans( + x + kWidth, y + (2 * kConeOutRadius), + z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 3, + new TGeoCombiTrans( + x - kWidth, y + (2 * kConeOutRadius), + z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); + } + + // Bottom CFRP Filament black-12 Carbon structure TGeoBBox (thickness,width,length) + auto* t1 = new TGeoBBox(0.007 / 2, 0.15 / 2, kS1); //(0.002,0.02,kS1); + auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); + volT1->SetLineColor(12); + volT1->SetFillColor(12); + + for (int i = 1; i < loop; i++) { + mechStavVol->AddNode( + volT1, 4 * i + 0, + new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT1", -90, kAlpha, 0))); + mechStavVol->AddNode( + volT1, 4 * i + 1, + new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT1", 90, kAlpha, 0))); + mechStavVol->AddNode( + volT1, 4 * i + 2, + new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT1", -90, -kAlpha, 0))); + mechStavVol->AddNode( + volT1, 4 * i + 3, + new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volT1", -90, +kAlpha, 0))); + } + } + + if (mBuildLevel < 2) { + // Glue CFRP-Silicon layers TGeoBBox(thickness,width,kS1); + auto* tG = new TGeoBBox(0.0075 / 2, 0.18 / 2, kS1); + auto* volTG = new TGeoVolume("Glue1", tG, medGlue); + volTG->SetLineColor(5); + volTG->SetFillColor(5); + + for (int i = 1; i < loop; i++) { // i<60;i++){ + mechStavVol->AddNode( + volTG, 4 * i + 0, + new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), + new TGeoRotation("volTG", -90, kAlpha, 0))); + mechStavVol->AddNode( + volTG, 4 * i + 1, + new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), + new TGeoRotation("volTG", 90, kAlpha, 0))); + mechStavVol->AddNode( + volTG, 4 * i + 2, + new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * i * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volTG", -90, -kAlpha, 0))); + mechStavVol->AddNode( + volTG, 4 * i + 3, + new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), + new TGeoRotation("volTG", -90, +kAlpha, 0))); + } + + auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); + auto* volGlue = new TGeoVolume("Glue2", glue, medGlue); + volGlue->SetLineColor(5); + volGlue->SetFillColor(5); + // mechStavVol->AddNode(volGlue, 0, new TGeoCombiTrans(x, y-0.16, z, new TGeoRotation("",0, 0, + // 0))); + mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); + } + + if (mBuildLevel < 1) { + // Flex cable brown-28 TGeoBBox(width,thickness,length); + auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); + auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); + volCable->SetLineColor(28); + volCable->SetFillColor(28); + mechStavVol->AddNode(volCable, 0, + new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, + new TGeoRotation("", 0, 0, 0))); + } + // Done, return the stave structur + return mechStavVol; +} + +TGeoVolume* V1Layer::createStaveModelInnerB1(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medFlexCable = mgr->GetMedium("TRK_FLEXCABLE$"); + + // Local parameters + Double_t kConeOutRadius = 0.15 / 2; + // Double_t kConeInRadius = 0.1430/2; + Double_t kStaveLength = zsta * 2; + // Double_t kStaveWidth = xsta*2-kConeOutRadius*2; + Double_t kStaveWidth = xsta * 2; + Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth + Double_t kStaveHeight = 0.3; + Double_t kHeight = kStaveHeight / 2; + Double_t kAlpha = 90 - 33.; // 90-30; + Double_t kTheta = kAlpha * TMath::DegToRad(); + Double_t kS1 = kWidth / TMath::Sin(kTheta); + Double_t kL1 = kWidth / TMath::Tan(kTheta); + Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); + Double_t kThe2 = TMath::ATan(kHeight / kS1); + Double_t kBeta = kThe2 * TMath::RadToDeg(); + Int_t loop = (Int_t)((kStaveLength / (2 * kL1)) / 2); + + TGeoVolume* mechStavVol = nullptr; + + char volumeName[30]; + snprintf(volumeName, 30, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), + mLayerNumber); + + // detailed structure ++++++++++++++ + Double_t z = 0, y = -0.011 + 0.0150, x = 0; + + // Polimide micro channels numbers + Double_t yMC = y - kHeight + 0.01; + Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; + Double_t xstaMC = (nb * 0.1 - 0.08) / 2; + + if (mBuildLevel < 5) { + // world (trapezoid) + auto* mechStruct = new TGeoXtru(2); // z sections + Double_t xv[5] = { + kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, + -kStaveWidth / 2 - 0.1}; + Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; + mechStruct->DefinePolygon(5, xv, yv); + mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); + mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); + + mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); + mechStavVol->SetLineColor(12); + mechStavVol->SetFillColor(12); + mechStavVol->SetVisibility(kTRUE); + + // Polimide micro channels numbers + auto* tM0 = new TGeoBBox(xstaMC, 0.005 / 2, zsta); + auto* volTM0 = new TGeoVolume("MicroChanCover", tM0, medKapton); + volTM0->SetLineColor(35); + volTM0->SetFillColor(35); + mechStavVol->AddNode(volTM0, 0, + new TGeoCombiTrans(x, -0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); + mechStavVol->AddNode(volTM0, 1, + new TGeoCombiTrans(x, +0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); + + auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); + auto* volTM0b = new TGeoVolume("MicroChanWalls", tM0b, medKapton); + volTM0b->SetLineColor(35); + volTM0b->SetFillColor(35); + for (Int_t ib = 0; ib < nb; ib++) { + mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.01, yMC, z, new TGeoRotation("", 0, 0, 0))); + } + } + + if (mBuildLevel < 4) { + // Water in Polimide micro channels + auto* water = new TGeoBBox(0.08 / 2, 0.02 / 2, zsta + 0.1); + auto* volWater = new TGeoVolume("Water", water, medWater); + volWater->SetLineColor(4); + volWater->SetFillColor(4); + for (Int_t ib = 0; ib < (nb - 1); ib++) { + mechStavVol->AddNode(volWater, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.06, yMC, z, new TGeoRotation("", 0, 0, 0))); + } + } + + if (mBuildLevel < 3) { + // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) + Double_t filWidth = 0.04; + Double_t filHeight = 0.02; + auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, kS1); + auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); + volT1->SetLineColor(12); + volT1->SetFillColor(12); + for (int i = 0; i < loop; i++) { // i<30;i++){ + mechStavVol->AddNode(volT1, 4 * i + 0, + new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (4 * kL1) + kS1 / 2, + new TGeoRotation("volT1", -90, kAlpha, 0))); + mechStavVol->AddNode(volT1, 4 * i + 1, + new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, + new TGeoRotation("volT1", 90, kAlpha, 0))); + mechStavVol->AddNode( + volT1, 4 * i + 2, + new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT1", -90, -kAlpha, 0))); + mechStavVol->AddNode( + volT1, 4 * i + 3, + new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT1", -90, +kAlpha, 0))); + } + + // Top filament CFRP black-12 Carbon structure TGeoBBox (length,thickness,width) + auto* t2 = new TGeoBBox(kS2, filHeight / 2, filWidth / 2); + auto* volT2 = new TGeoVolume("CFRPTop", t2, medM60J3K); + volT2->SetLineColor(12); + volT2->SetFillColor(12); + for (int i = 0; i < loop; i++) { // i<30;i++){ + mechStavVol->AddNode( + volT2, 4 * i + 0, + new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 1, + new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 2, + new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, 4 * i + 3, + new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); + } + } + + if (mBuildLevel < 2) { + // Glue between filament and polimide micro channel + auto* t3 = new TGeoBBox(0.01 / 2, 0.04, kS1); + auto* volT3 = new TGeoVolume("FilamentGlue", t3, medGlue); + volT3->SetLineColor(5); + volT3->SetFillColor(5); + for (int i = 0; i < loop; i++) { // i<30;i++){ + mechStavVol->AddNode(volT3, 4 * i + 0, + new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, + z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, + new TGeoRotation("volT1", -90, kAlpha, 0))); + mechStavVol->AddNode(volT3, 4 * i + 1, + new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, + z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, + new TGeoRotation("volT1", 90, kAlpha, 0))); + mechStavVol->AddNode( + volT3, 4 * i + 2, + new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT1", -90, -kAlpha, 0))); + mechStavVol->AddNode( + volT3, 4 * i + 3, + new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, + z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT1", -90, +kAlpha, 0))); + } + + // Glue microchannel and sensor + auto* glueM = new TGeoBBox(xsta, 0.01 / 2, zsta); + auto* volGlueM = new TGeoVolume("MicroChanGlue", glueM, medGlue); + volGlueM->SetLineColor(5); + volGlueM->SetFillColor(5); + mechStavVol->AddNode(volGlueM, 0, + new TGeoCombiTrans(x, y - 0.16, z, new TGeoRotation("", 0, 0, 0))); + + // Glue sensor and kapton + auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); + auto* volGlue = new TGeoVolume("SensorGlue", glue, medGlue); + volGlue->SetLineColor(5); + volGlue->SetFillColor(5); + mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); + } + + if (mBuildLevel < 1) { + auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); + auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); + volCable->SetLineColor(28); + volCable->SetFillColor(28); + mechStavVol->AddNode(volCable, 0, + new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, + new TGeoRotation("", 0, 0, 0))); + } + // Done, return the stave structur + return mechStavVol; +} + +TGeoVolume* V1Layer::createStaveModelInnerB21(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medFlexCable = mgr->GetMedium("TRK_FLEXCABLE$"); + TGeoMedium* medK13D2U2k = mgr->GetMedium("TRK_K13D2U2k$"); + TGeoMedium* medFGS003 = mgr->GetMedium("TRK_FGS003$"); + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + + // Local parameters + Double_t kConeOutRadius = 0.151384 / 2; + Double_t kConeInRadius = 0.145034 / 2; + Double_t kStaveLength = zsta; + Double_t kStaveWidth = xsta * 2; + Double_t kWidth = (kStaveWidth + 0.005) / 4; + Double_t kStaveHeigth = 0.33; // 0.33; + Double_t kHeight = (kStaveHeigth + 0.025) / 2; + Double_t kAlpha = 57; // 56.31; + Double_t kTheta = kAlpha * TMath::DegToRad(); + Double_t kS1 = (kStaveWidth / 4) / TMath::Sin(kTheta); + Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); + Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); + Double_t kThe2 = TMath::ATan(kHeight / kS1); + Double_t kBeta = kThe2 * TMath::RadToDeg(); + // Double_t lay1 = 0.003157; + Double_t kLay1 = 0.003; // Amec carbon + // Double_t lay2 = 0.0043215;//C Fleece carbon + Double_t kLay2 = 0.002; // C Fleece carbon + Double_t kLay3 = 0.007; // K13D2U carbon + Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); + + char volumeName[30]; + snprintf(volumeName, 30, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), + mLayerNumber); + + Double_t z = 0, y = -(kConeOutRadius + 0.03) + 0.0385, x = 0; + + TGeoVolume* mechStavVol = nullptr; + + if (mBuildLevel < 5) { + // world (trapezoid) + auto* mechStruct = new TGeoXtru(2); // z sections + Double_t xv[5] = { + kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, + -kStaveWidth / 2 - 0.1}; + Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeigth, 0, -kConeOutRadius * 2 - 0.07}; + mechStruct->DefinePolygon(5, xv, yv); + mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); + mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); + + mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); + mechStavVol->SetLineColor(12); + mechStavVol->SetFillColor(12); + mechStavVol->SetVisibility(kTRUE); + + // Pipe Kapton grey-35 + auto* cone1 = + new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius, kConeInRadius, kConeOutRadius); + auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); + volCone1->SetFillColor(35); + volCone1->SetLineColor(35); + mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); + mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); + } + + if (mBuildLevel < 4) { + auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength); + auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); + volCoolTubeW->SetFillColor(4); + volCoolTubeW->SetLineColor(4); + mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); + mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); + } + + if (mBuildLevel < 3) { + // top fillament + // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) + auto* t2 = + new TGeoBBox(kS2, 0.02 / 2, 0.04 / 2); // TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02); + auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); + volT2->SetLineColor(12); + volT2->SetFillColor(12); + + for (int i = 0; i < loop; i++) { // i<28;i++){ + mechStavVol->AddNode( + volT2, i * 4 + 1, + new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, + z - kStaveLength + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, i * 4 + 2, + new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, + z - kStaveLength + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); + mechStavVol->AddNode( + volT2, i * 4 + 3, + new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, + z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); + mechStavVol->AddNode( + volT2, i * 4 + 4, + new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, + z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); + // mechStavVol->AddNode(volT2,i*4+1,new + // TGeoCombiTrans(x+kWidth+0.0036,y+kHeight-(0.12/2)+0.072,z+kStaveLength+(i*4*kL1)+kS1/2, new + // TGeoRotation("volT2",90,90-kAlpha,90-kBeta))); + } + + // wall side structure out + auto* box4 = new TGeoBBox(0.03 / 2, 0.12 / 2, kStaveLength - 0.50); + auto* plate4 = new TGeoVolume("WallOut", box4, medM60J3K); + plate4->SetFillColor(35); + plate4->SetLineColor(35); + mechStavVol->AddNode(plate4, 1, + new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - (0.03 / 2), + y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, + new TGeoRotation("plate4", 0, 0, 0))); + mechStavVol->AddNode(plate4, 2, + new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + (0.03 / 2), + y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, + new TGeoRotation("plate4", 0, 0, 0))); + // wall side in + auto* box5 = new TGeoBBox(0.015 / 2, 0.12 / 2, kStaveLength - 0.50); + auto* plate5 = new TGeoVolume("WallIn", box5, medM60J3K); + plate5->SetFillColor(12); + plate5->SetLineColor(12); + mechStavVol->AddNode(plate5, 1, + new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - 0.03 - 0.015 / 2, + y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, + new TGeoRotation("plate5", 0, 0, 0))); + mechStavVol->AddNode(plate5, 2, + new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + 0.03 + 0.015 / 2, + y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, + new TGeoRotation("plate5", 0, 0, 0))); + + // Amec Thermasol red-2 cover tube FGS300 + auto* cons1 = + new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius, kConeOutRadius + kLay1, kConeOutRadius, + kConeOutRadius + kLay1, 0, 180); + auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); + cone11->SetFillColor(2); + cone11->SetLineColor(2); + mechStavVol->AddNode(cone11, 1, + new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); + mechStavVol->AddNode(cone11, 2, + new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); + + auto* box2 = + new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, kLay1 / 2, kStaveLength - 0.50); + auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); + plate2->SetFillColor(2); + plate2->SetLineColor(2); + mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); + + auto* box21 = + new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay1 / 2, kStaveLength - 0.50); + auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); + plate21->SetFillColor(2); + plate21->SetLineColor(2); + mechStavVol->AddNode( + plate21, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); + mechStavVol->AddNode( + plate21, 2, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); + + auto* box22 = new TGeoBBox((kLay1 / 2), kConeOutRadius / 2, kStaveLength - 0.50); + auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); + plate22->SetFillColor(2); + plate22->SetLineColor(2); + mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + + // C Fleece + auto* cons2 = + new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, + kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, 0, 180); + auto* cone12 = new TGeoVolume("CFleecePipeCover", cons2, medCarbonFleece); + cone12->SetFillColor(28); + cone12->SetLineColor(28); + mechStavVol->AddNode(cone12, 1, + new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); + mechStavVol->AddNode(cone12, 2, + new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); + + auto* box3 = + new TGeoBBox((0.50 - (2 * (kConeOutRadius + kLay1))) / 2, kLay2 / 2, kStaveLength - 0.50); + auto* plate3 = new TGeoVolume("CFleeceMiddle", box3, medCarbonFleece); + plate3->SetFillColor(28); + plate3->SetLineColor(28); + mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); + + auto* box31 = + new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay2 / 2, kStaveLength - 0.50); + auto* plate31 = new TGeoVolume("CFleeceLeftRight", box31, medCarbonFleece); + plate31->SetFillColor(28); + plate31->SetLineColor(28); + mechStavVol->AddNode( + plate31, 1, + new TGeoCombiTrans( + x + 0.25 + kConeOutRadius + kLay1 + (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, + y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); + mechStavVol->AddNode( + plate31, 2, + new TGeoCombiTrans( + x - 0.25 - kConeOutRadius - kLay1 - (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, + y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); + + auto* box32 = new TGeoBBox((kLay2 / 2), (kConeOutRadius - kLay1) / 2, kStaveLength - 0.50); + auto* plate32 = new TGeoVolume("CFleeceVertical", box32, medCarbonFleece); + plate32->SetFillColor(28); + plate32->SetLineColor(28); + mechStavVol->AddNode(plate32, 1, + new TGeoCombiTrans(x + 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), + y + (kLay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 2, + new TGeoCombiTrans(x + 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), + y + (kLay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 3, + new TGeoCombiTrans(x - 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), + y + (kLay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 4, + new TGeoCombiTrans(x - 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), + y + (kLay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + + // K13D2U carbon plate + auto* box1 = new TGeoBBox(2 * kWidth, kLay3 / 2, kStaveLength - 0.50); + auto* plate1 = new TGeoVolume("CarbonPlate", box1, medK13D2U2k); + plate1->SetFillColor(5); + plate1->SetLineColor(5); + mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (kLay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); + + // C Fleece bottom plate + auto* box6 = new TGeoBBox(2 * kWidth, kLay2 / 2, kStaveLength - 0.50); + auto* plate6 = new TGeoVolume("CFleeceBottom", box6, medCarbonFleece); + plate6->SetFillColor(2); + plate6->SetLineColor(2); + mechStavVol->AddNode(plate6, 1, + new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2)), z, + new TGeoRotation("plate1", 0, 0, 0))); + } + + if (mBuildLevel < 2) { + // Glue layers and kapton + auto* glue = new TGeoBBox(kStaveWidth / 2, 0.005 / 2, zsta); + auto* volGlue = new TGeoVolume("Glue", glue, medGlue); + volGlue->SetLineColor(5); + volGlue->SetFillColor(5); + mechStavVol->AddNode( + volGlue, 0, new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + (0.01 / 2)), z, new TGeoRotation("", 0, 0, 0))); + mechStavVol->AddNode(volGlue, 1, + new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + (0.01 / 2)), + z, new TGeoRotation("", 0, 0, 0))); + } + + if (mBuildLevel < 1) { + auto* kapCable = new TGeoBBox(kStaveWidth / 2, 0.01 / 2, zsta); + auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); + volCable->SetLineColor(28); + volCable->SetFillColor(28); + mechStavVol->AddNode(volCable, 0, + new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + 0.01 + (0.01 / 2)), + z, new TGeoRotation("", 0, 0, 0))); + } + // Done, return the stave structure + return mechStavVol; +} + +// new model22 +TGeoVolume* V1Layer::createStaveModelInnerB22(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medFlexCable = mgr->GetMedium("TRK_FLEXCABLE$"); + TGeoMedium* medK13D2U2k = mgr->GetMedium("TRK_K13D2U2k$"); + TGeoMedium* medFGS003 = mgr->GetMedium("TRK_FGS003$"); + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + + // Local parameters + Double_t kConeOutRadius = (0.1024 + 0.0025) / 2; // 0.107/2; + Double_t kConeInRadius = 0.1024 / 2; // 0.10105/2 + Double_t kStaveLength = zsta; + Double_t kStaveWidth = xsta * 2; + Double_t kWidth = (kStaveWidth) / 4; + Double_t kStaveHeight = 0.283; // 0.33; + Double_t kHeight = (kStaveHeight) / 2; + Double_t kAlpha = 57; // 56.31; + Double_t kTheta = kAlpha * TMath::DegToRad(); + Double_t kS1 = ((kStaveWidth) / 4) / TMath::Sin(kTheta); + Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); + Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(kThe2); + Double_t kThe2 = TMath::ATan(kHeight / (0.375 - 0.036)); + Double_t kBeta = kThe2 * TMath::RadToDeg(); + Double_t klay1 = 0.003; // Amec carbon + Double_t klay2 = 0.002; // C Fleece carbon + Double_t klay3 = 0.007; // CFplate K13D2U carbon + Double_t klay4 = 0.007; // GluekStaveLength/2 + Double_t klay5 = 0.01; // Flex cable + Double_t kTopVertexMaxWidth = 0.072; + Double_t kTopVertexHeight = 0.04; + Double_t kSideVertexMWidth = 0.052; + Double_t kSideVertexHeight = 0.11; + + Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); + + char volumeName[30]; + snprintf(volumeName, 30, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), + mLayerNumber); + + Double_t z = 0, y = -(2 * kConeOutRadius) + klay1 + klay2 + mSensorThickness / 2 - 0.0004, x = 0; + + TGeoVolume* mechStavVol = nullptr; + + if (mBuildLevel < 5) { + // world (trapezoid) + auto* mechStruct = new TGeoXtru(2); // z sections + Double_t xv[6] = { + kStaveWidth / 2, kStaveWidth / 2, 0.012, + -0.012, -kStaveWidth / 2, -kStaveWidth / 2}; + // Double_t yv[6] = {-2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5), + // 0-0.02,kStaveHeight+0.01,kStaveHeight+0.01,0-0.02, + // -2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5)}; + // (kConeOutRadius*2)-0.0635 + Double_t yv[6] = { + -(kConeOutRadius * 2) - 0.06395, 0 - 0.02, kStaveHeight + 0.01, + kStaveHeight + 0.01, 0 - 0.02, -(kConeOutRadius * 2) - 0.06395}; // (kConeOutRadius*2)-0.064 + mechStruct->DefinePolygon(6, xv, yv); + mechStruct->DefineSection(0, -kStaveLength, 0, 0, 1.); + mechStruct->DefineSection(1, kStaveLength, 0, 0, 1.); + + mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); + mechStavVol->SetLineColor(12); + mechStavVol->SetFillColor(12); + mechStavVol->SetVisibility(kTRUE); + + // Polyimide Pipe Kapton grey-35 + auto* cone1 = new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius - 0.0001, + kConeInRadius, kConeOutRadius - 0.0001); + auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); + volCone1->SetFillColor(35); + volCone1->SetLineColor(35); + mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); + mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); + } + + if (mBuildLevel < 4) { + auto* coolTubeW = new TGeoTube(0., kConeInRadius - 0.0001, kStaveLength); + auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); + volCoolTubeW->SetFillColor(4); + volCoolTubeW->SetLineColor(4); + mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); + mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); + } + + if (mBuildLevel < 3) { + // top fillament + // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) + auto* t2 = new TGeoBBox( + kS2 - 0.028, 0.02 / 2, + 0.02 / 2); // 0.04/2//TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02);//kS2-0.03 old Config.C + auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); + volT2->SetLineColor(12); + volT2->SetFillColor(12); + for (int i = 0; i < loop; i++) { // i<28;i++){ + // 1) Front Left Top Filament + mechStavVol->AddNode( + volT2, i * 4 + 1, + new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, + z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); + // 2) Front Right Top Filament + mechStavVol->AddNode( + volT2, i * 4 + 2, + new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, + z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); + // 3) Back Left Top Filament + mechStavVol->AddNode( + volT2, i * 4 + 3, + new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, + z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); + // 4) Back Right Top Filament + mechStavVol->AddNode( + volT2, i * 4 + 4, + new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, + z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, + new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); + } + + // Vertex structure + // top ver trd1 + auto* trd1 = new TGeoTrd1(0, kTopVertexMaxWidth / 2, kStaveLength, kTopVertexHeight / 2); + auto* ibdv = new TGeoVolume("TopVertex", trd1, medM60J3K); + ibdv->SetFillColor(12); + ibdv->SetLineColor(12); + mechStavVol->AddNode( + ibdv, 1, new TGeoCombiTrans(x, y + kStaveHeight + 0.03, z, new TGeoRotation("ibdv", 0., -90, 0))); // y+kStaveHeight+0.056 + + // left trd2 + auto* trd2 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); + auto* ibdv2 = new TGeoVolume("LeftVertex", trd2, medM60J3K); + ibdv2->SetFillColor(12); + ibdv2->SetLineColor(12); + mechStavVol->AddNode( + ibdv2, 1, + new TGeoCombiTrans( + x + kStaveWidth / 2 - 0.06, y - 0.0355, z, + new TGeoRotation("ibdv2", -103.3, 90, 0))); // x-kStaveWidth/2-0.09 old Config.C y-0.0355, + + // right trd3 + auto* trd3 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); + auto* ibdv3 = new TGeoVolume("RightVertex", trd3, medM60J3K); + ibdv3->SetFillColor(12); + ibdv3->SetLineColor(12); + mechStavVol->AddNode( + ibdv3, 1, new TGeoCombiTrans(x - kStaveWidth / 2 + 0.06, y - 0.0355, z, new TGeoRotation("ibdv3", 103.3, 90, 0))); // x-kStaveWidth/2+0.09 old Config.C + + // Carbon Fleece + auto* cons2 = + new TGeoConeSeg(zsta, kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, + kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, 0, 180); + auto* cone12 = new TGeoVolume("CarbonFleecePipeCover", cons2, medCarbonFleece); + cone12->SetFillColor(28); + cone12->SetLineColor(28); + mechStavVol->AddNode(cone12, 1, + new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); + mechStavVol->AddNode(cone12, 2, + new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); + + auto* box3 = new TGeoBBox((0.50 - (2 * (kConeOutRadius + klay1))) / 2, klay2 / 2, + zsta); // kStaveLength-0.50); + auto* plate3 = new TGeoVolume("CarbonFleeceMiddle", box3, medCarbonFleece); + plate3->SetFillColor(28); + plate3->SetLineColor(28); + mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); + + auto* box31 = + new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, klay2 / 2, zsta); + auto* plate31 = new TGeoVolume("CarbonFleeceLeftRight", box31, medCarbonFleece); + plate31->SetFillColor(28); + plate31->SetLineColor(28); + mechStavVol->AddNode( + plate31, 1, + new TGeoCombiTrans( + x + 0.25 + kConeOutRadius + klay1 + (0.75 - 0.25 - kConeOutRadius - klay1) / 2, + y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); + mechStavVol->AddNode( + plate31, 2, + new TGeoCombiTrans( + x - 0.25 - kConeOutRadius - klay1 - (0.75 - 0.25 - kConeOutRadius - klay1) / 2, + y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); + + auto* box32 = new TGeoBBox((klay2 / 2), (kConeOutRadius - klay1) / 2, zsta); + auto* plate32 = new TGeoVolume("CarbonFleeceVertical", box32, medCarbonFleece); + plate32->SetFillColor(28); + plate32->SetLineColor(28); + mechStavVol->AddNode(plate32, 1, + new TGeoCombiTrans(x + 0.25 + kConeOutRadius + klay1 + (klay2 / 2), + y + (klay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 2, + new TGeoCombiTrans(x + 0.25 - kConeOutRadius - klay1 - (klay2 / 2), + y + (klay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 3, + new TGeoCombiTrans(x - 0.25 + kConeOutRadius + klay1 + (klay2 / 2), + y + (klay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + mechStavVol->AddNode(plate32, 4, + new TGeoCombiTrans(x - 0.25 - kConeOutRadius - klay1 - (klay2 / 2), + y + (klay1 - kConeOutRadius) / 2, z, + new TGeoRotation("plate32", 0, 0, 0))); + + // Amec Thermasol red-2 cover tube FGS300 or Carbon Paper + auto* cons1 = + new TGeoConeSeg(zsta, kConeOutRadius, kConeOutRadius + klay1 - 0.0001, kConeOutRadius, + kConeOutRadius + klay1 - 0.0001, 0, 180); // kConeOutRadius+klay1-0.0001 + auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); + cone11->SetFillColor(2); + cone11->SetLineColor(2); + mechStavVol->AddNode(cone11, 1, + new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); + mechStavVol->AddNode(cone11, 2, + new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); + + auto* box2 = + new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, (klay1 / 2), zsta); // kStaveLength-0.50); + auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); + plate2->SetFillColor(2); + plate2->SetLineColor(2); + mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); + + auto* box21 = + new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, (klay1 / 2), zsta); + auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); + plate21->SetFillColor(2); + plate21->SetLineColor(2); + mechStavVol->AddNode( + plate21, 1, + new TGeoCombiTrans( + x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (klay1 / 2) + 0.0025, + y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); + mechStavVol->AddNode( + plate21, 2, + new TGeoCombiTrans( + x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (klay1 / 2) - 0.0025, + y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); + + auto* box22 = new TGeoBBox((klay1 / 2), kConeOutRadius / 2, zsta); + auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); + plate22->SetFillColor(2); + plate22->SetLineColor(2); + mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); + + // K13D2U CF plate + auto* box1 = new TGeoBBox(2 * kWidth, (klay3) / 2, zsta); + auto* plate1 = new TGeoVolume("CFPlate", box1, medK13D2U2k); + plate1->SetFillColor(5); + plate1->SetLineColor(5); + mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (klay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); + + // C Fleece bottom plate + auto* box6 = new TGeoBBox(2 * kWidth, (klay2) / 2, zsta); + auto* plate6 = new TGeoVolume("CarbonFleeceBottom", box6, medCarbonFleece); + plate6->SetFillColor(2); + plate6->SetLineColor(2); + mechStavVol->AddNode(plate6, 1, + new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + (klay2 / 2)), z, + new TGeoRotation("plate6", 0, 0, 0))); + } + if (mBuildLevel < 2) { + // Glue klayers and kapton + auto* glue = new TGeoBBox(kStaveWidth / 2, (klay4) / 2, zsta); + auto* volGlue = new TGeoVolume("Glue", glue, medGlue); + volGlue->SetLineColor(5); + volGlue->SetFillColor(5); + // mechStavVol->AddNode(volGlue, 0, new + // TGeoCombiTrans(x,y-(kConeOutRadius+klay3+klay2+(klay4/2)), z, new TGeoRotation("",0, 0, 0))); + mechStavVol->AddNode( + volGlue, 0, + new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + klay2 + (klay4) / 2) + 0.00005, z, + new TGeoRotation("", 0, 0, 0))); + } + + if (mBuildLevel < 1) { + // Flex Cable or Bus + auto* kapCable = new TGeoBBox(kStaveWidth / 2, klay5 / 2, zsta); // klay5/2 + auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); + volCable->SetLineColor(28); + volCable->SetFillColor(28); + // mechStavVol->AddNode(volCable, 0, new TGeoCombiTrans(x, + // y-(kConeOutRadius+klay3+klay2+klay4+mSensorThickness+(klay5)/2)+0.0002, z, new + // TGeoRotation("",0, + // 0, 0))); + mechStavVol->AddNode( + volCable, 0, + new TGeoCombiTrans( + x, y - (kConeOutRadius + klay3 + klay2 + klay4 + mSensorThickness + (klay5) / 2) + 0.01185, + z, new TGeoRotation("", 0, 0, 0))); + } + // Done, return the stave structe + return mechStavVol; +} + +// model3 +TGeoVolume* V1Layer::createStaveModelInnerB3(const Double_t xsta, const Double_t zsta, + const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medFlexCable = mgr->GetMedium("TRK_FLEXCABLE$"); + // TGeoMedium *medK13D2U2k = mgr->GetMedium("TRK_K13D2U2k$"); + // TGeoMedium *medFGS003 = mgr->GetMedium("TRK_FGS003$"); + // TGeoMedium *medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + + // Local parameters + Double_t kConeOutRadius = 0.15 / 2; + Double_t kStaveLength = zsta * 2; + Double_t kStaveWidth = xsta * 2; + Double_t w = kStaveWidth / 4; // 1/2 of W + Double_t staveHeight = 0.3; + Double_t h = staveHeight / 2; + Double_t alpha = 90 - 33.; // 90-30; + Double_t the1 = alpha * TMath::DegToRad(); + Double_t s1 = w / TMath::Sin(the1); + Double_t l = w / TMath::Tan(the1); + Double_t s2 = TMath::Sqrt(h * h + s1 * s1); // TMath::Sin(the2); + Double_t the2 = TMath::ATan(h / s1); + Double_t beta = the2 * TMath::RadToDeg(); + Double_t klay4 = 0.007; // Glue + Double_t klay5 = 0.01; // Flexcable + Int_t loop = (Int_t)((kStaveLength / (2 * l)) / 2); + Double_t hh = 0.01; + Double_t ang1 = 0 * TMath::DegToRad(); + Double_t ang2 = 0 * TMath::DegToRad(); + Double_t ang3 = 0 * TMath::DegToRad(); + Int_t chips = 4; + Double_t headWidth = 0.25; + Double_t smcLength = kStaveLength / chips - 2 * headWidth; // 6.25; + Double_t smcWidth = kStaveWidth; + Double_t smcSide1Thick = 0.03; + Double_t vaporThick = 0.032; + Double_t liquidThick = 0.028; + Double_t smcSide2Thick = 0.01; + Double_t smcSide3Thick = 0.0055; + Double_t smcSide4Thick = 0.0095; + Double_t smcSide5Thick = 0.0075; + Double_t smcSpace = 0.01; + + char volumeName[30]; + snprintf(volumeName, 30, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), + mLayerNumber); + + // detailed structure ++++++++++++++ + Double_t z = 0, y = 0 - 0.007, x = 0; + + // Polimide micro channels numbers + Double_t yMC = y - h + 0.01; + Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; + Double_t xstaMC = (nb * 0.1 - 0.08) / 2; + + TGeoVolume* mechStavVol = nullptr; + if (mBuildLevel < 5) { + // world (trapezoid) + auto* mechStruct = new TGeoXtru(2); // z sections + Double_t xv[5] = { + kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, + -kStaveWidth / 2 - 0.1}; + Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, staveHeight, 0, -kConeOutRadius * 2 - 0.07}; + mechStruct->DefinePolygon(5, xv, yv); + mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); + mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); + mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); + mechStavVol->SetLineColor(12); + mechStavVol->SetFillColor(12); + mechStavVol->SetVisibility(kTRUE); + + // Silicon micro channels numbers + + auto* tM0a = new TGeoBBox(smcWidth / 2, 0.003 / 2, headWidth / 2); + auto* volTM0a = new TGeoVolume("microChanTop1", tM0a, medKapton); + volTM0a->SetLineColor(35); + volTM0a->SetFillColor(35); + + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0a, 0, + new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), + new TGeoRotation("", ang1, ang2, ang3))); + mechStavVol->AddNode( + volTM0a, 1, + new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), + new TGeoRotation("", ang1, ang2, ang3))); + } + auto* tM0c = new TGeoBBox(0.3 / 2, 0.003 / 2, smcLength / 2); + auto* volTM0c = new TGeoVolume("microChanTop2", tM0c, medKapton); + volTM0c->SetLineColor(35); + volTM0c->SetFillColor(35); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0c, 0, new TGeoCombiTrans(x + (smcWidth / 2) - (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); + mechStavVol->AddNode( + volTM0c, 1, new TGeoCombiTrans(x - (smcWidth / 2) + (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0c1 = new TGeoBBox(0.2225 / 2, 0.003 / 2, smcLength / 2); + auto* volTM0c1 = new TGeoVolume("microChanBot1", tM0c1, medKapton); + volTM0c1->SetLineColor(6); + volTM0c1->SetFillColor(6); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0c1, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick) - (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0c1, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0c2 = new TGeoBBox(0.072 / 2, 0.003 / 2, smcLength / 2); + auto* volTM0c2 = new TGeoVolume("microChanBot2", tM0c2, medKapton); + volTM0c2->SetLineColor(35); + volTM0c2->SetFillColor(35); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0c2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (0.072 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0c2r = new TGeoBBox(0.068 / 2, 0.003 / 2, smcLength / 2); + auto* volTM0c2r = new TGeoVolume("microChanBot3", tM0c2r, medKapton); + volTM0c2r->SetLineColor(35); + volTM0c2r->SetFillColor(35); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0c2r, 0, new TGeoCombiTrans(x - smcWidth / 2 + (0.068 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0d = new TGeoBBox(smcSide1Thick / 2, 0.035 / 2, smcLength / 2); + auto* volTM0d = new TGeoVolume("microChanSide1", tM0d, medKapton); + volTM0d->SetLineColor(12); + volTM0d->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0d, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0d, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + + auto* tM0d1 = new TGeoBBox(smcSide2Thick / 2, 0.035 / 2, smcLength / 2); + auto* volTM0d1 = new TGeoVolume("microChanSide2", tM0d1, medKapton); + volTM0d1->SetLineColor(12); + volTM0d1->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0d1, 0, + new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick / 2), + yMC + 0.03 - (0.003 + 0.035) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0d1, 1, + new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick / 2), + yMC + 0.03 - (0.003 + 0.035) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0d2 = new TGeoBBox(smcSide3Thick / 2, (hh + 0.003) / 2, smcLength / 2); + auto* volTM0d2 = new TGeoVolume("microChanSide3", tM0d2, medKapton); + volTM0d2->SetLineColor(12); + volTM0d2->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0d2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick / 2), yMC + 0.03 - (0.003 + hh + 0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0d2r = new TGeoBBox(smcSide4Thick / 2, (hh + 0.003) / 2, smcLength / 2); + auto* volTM0d2r = new TGeoVolume("microChanSide4", tM0d2r, medKapton); + volTM0d2r->SetLineColor(12); + volTM0d2r->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0d2r, 0, + new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + + (smcSide4Thick / 2), + yMC + 0.03 - (0.003 + hh + 0.003) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0e = new TGeoBBox(smcSide5Thick / 2, hh / 2, smcLength / 2); + auto* volTM0e = new TGeoVolume("microChanSide5", tM0e, medKapton); + volTM0e->SetLineColor(12); + volTM0e->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + for (Int_t ie = 0; ie < 11; ie++) { + mechStavVol->AddNode( + volTM0e, 0, + new TGeoCombiTrans(x - (ie * (smcSpace + smcSide5Thick)) + smcWidth / 2 - + (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace - (smcSide5Thick / 2), + yMC + 0.03 - (0.003 + hh) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0e, 1, + new TGeoCombiTrans(x + (ie * (smcSpace + smcSide5Thick)) - smcWidth / 2 + + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + + smcSpace + (smcSide5Thick / 2), + yMC + 0.03 - (0.003 + hh) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + } + + auto* tM0f = new TGeoBBox(0.02 / 2, hh / 2, smcLength / 2); + auto* volTM0f = new TGeoVolume("microChanTop3", tM0f, medKapton); + // Double_t smcChannels=12; + Double_t smcCloseWallvapor = smcWidth / 2 - smcSide1Thick - vaporThick - smcSide2Thick - + smcSide3Thick - 12 * smcSpace - 11 * smcSide5Thick; + Double_t smcCloseWallliquid = smcWidth / 2 - smcSide1Thick - liquidThick - smcSide2Thick - + smcSide4Thick - 12 * smcSpace - 11 * smcSide5Thick; + volTM0f->SetLineColor(12); + volTM0f->SetFillColor(12); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0f, 0, + new TGeoCombiTrans(x + smcCloseWallvapor - (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0f, 1, + new TGeoCombiTrans(x - smcCloseWallliquid + (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, + z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, + new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + // Head(back) microchannel + + auto* tM0hb = new TGeoBBox(smcWidth / 2, 0.025 / 2, headWidth / 2); + auto* volTM0hb = new TGeoVolume("microChanHeadBackBottom1", tM0hb, medKapton); + volTM0hb->SetLineColor(4); + volTM0hb->SetFillColor(4); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0hb, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0hb, 1, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0h1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.05 / 2); + auto* volTM0h1 = new TGeoVolume("microChanHeadBackBottom2", tM0h1, medKapton); + volTM0h1->SetLineColor(5); + volTM0h1->SetFillColor(5); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0h1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - headWidth + (0.05 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0h2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.18 / 2); + auto* volTM0h2 = new TGeoVolume("microChanHeadBackBottom7", tM0h2, medKapton); + volTM0h2->SetLineColor(6); + volTM0h2->SetFillColor(6); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0h2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - 0.02 - (0.18 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0h3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); + auto* volTM0h3 = new TGeoVolume("microChanHeadBackBottom3", tM0h3, medKapton); + volTM0h3->SetLineColor(5); + volTM0h3->SetFillColor(5); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0h3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0b1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.03 / 2); + auto* volTM0b1 = new TGeoVolume("microChanHeadBackBottom4", tM0b1, medKapton); + volTM0b1->SetLineColor(5); + volTM0b1->SetFillColor(5); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0b1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + headWidth - (0.03 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0b2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.2 / 2); + auto* volTM0b2 = new TGeoVolume("microChanHeadBackBottom5", tM0b2, medKapton); + volTM0b2->SetLineColor(6); + volTM0b2->SetFillColor(6); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0b2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + 0.02 + (0.2 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0b3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); + auto* volTM0b3 = new TGeoVolume("microChanHeadBackBottom6", tM0b3, medKapton); + volTM0b3->SetLineColor(5); + volTM0b3->SetFillColor(5); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0b3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + + auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); + auto* volTM0b = new TGeoVolume("microChanWalls", tM0b, medKapton); + volTM0b->SetLineColor(35); + volTM0b->SetFillColor(35); + for (Int_t ib = 0; ib < nb; ib++) { + // mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x+ib*0.1-xstaMC+0.01,yMC, z, new + // TGeoRotation("",0, 0, 0))); + } + } + + if (mBuildLevel < 4) { + // cooling inlet outlet + auto* tM0dv = new TGeoBBox(vaporThick / 2, 0.035 / 2, smcLength / 2); + auto* volTM0dv = new TGeoVolume("microChanVapor", tM0dv, medWater); + volTM0dv->SetLineColor(2); + volTM0dv->SetFillColor(2); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0dv, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + auto* tM0dl = new TGeoBBox(liquidThick / 2, 0.035 / 2, smcLength / 2); + auto* volTM0dl = new TGeoVolume("microChanLiquid", tM0dl, medWater); + volTM0dl->SetLineColor(3); + volTM0dl->SetFillColor(3); + for (Int_t mo = 1; mo <= chips; mo++) { + mechStavVol->AddNode( + volTM0dl, 0, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + // small cooling fluid now using water wait for freeon value + auto* tM0dlq = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); + auto* volTM0dlq = new TGeoVolume("smallLiquid", tM0dlq, medWater); + volTM0dlq->SetLineColor(3); + volTM0dlq->SetFillColor(3); + auto* tM0dvp = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); + auto* volTM0dvp = new TGeoVolume("microChanVapor", tM0dvp, medWater); + volTM0dvp->SetLineColor(2); + volTM0dvp->SetFillColor(2); + for (Int_t mo = 1; mo <= chips; mo++) { + for (Int_t is = 0; is < 12; is++) { + mechStavVol->AddNode( + volTM0dlq, 0, new TGeoCombiTrans(x + (is * (smcSpace + smcSide5Thick)) - smcWidth / 2 + (smcSide1Thick) + (vaporThick) + (smcSide2Thick) + (smcSide3Thick) + smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + mechStavVol->AddNode( + volTM0dvp, 1, new TGeoCombiTrans(x - (is * (smcSpace + smcSide5Thick)) + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); + } + } + } + + if (mBuildLevel < 3) { + // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) + Double_t filWidth = 0.04; + Double_t filHeight = 0.02; + auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, s1); + auto* volT1 = new TGeoVolume("bottomFilament", t1, medM60J3K); + volT1->SetLineColor(12); + volT1->SetFillColor(12); + for (int i = 0; i < loop; i++) { // i<30;i++){ + mechStavVol->AddNode(volT1, 4 * i + 0, + new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (4 * l * i) + s1 / 2, + new TGeoRotation("volT1", -90, alpha, 0))); + mechStavVol->AddNode(volT1, 4 * i + 1, + new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (4 * l * i) + s1 / 2, + new TGeoRotation("volT1", 90, alpha, 0))); + mechStavVol->AddNode(volT1, 4 * i + 2, + new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, + new TGeoRotation("volT1", -90, -alpha, 0))); + mechStavVol->AddNode(volT1, 4 * i + 3, + new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, + new TGeoRotation("volT1", -90, +alpha, 0))); + } + + // Top filament CERP black-12 Carbon structure TGeoBBox (length,thickness,width) + auto* t2 = new TGeoBBox(s2, filHeight / 2, filWidth / 2); + auto* volT2 = new TGeoVolume("topFilament", t2, medM60J3K); + volT2->SetLineColor(12); + volT2->SetFillColor(12); + for (int i = 0; i < loop; i++) { // i<30;i++){ + mechStavVol->AddNode( + volT2, 4 * i + 0, new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, new TGeoRotation("volT2", 90, 90 - alpha, 90 - beta))); + mechStavVol->AddNode( + volT2, 4 * i + 1, + new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, + new TGeoRotation("volT2", 90, -90 + alpha, -90 + beta))); + mechStavVol->AddNode( + volT2, 4 * i + 2, + new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, + new TGeoRotation("volT2", 90, -90 + alpha, 90 - beta))); + mechStavVol->AddNode( + volT2, 4 * i + 3, + new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, + z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, + new TGeoRotation("volT2", 90, 90 - alpha, -90 + beta))); + } + } + + if (mBuildLevel < 2) { + // Glue Filament and Silicon MicroChannel + auto* tM0 = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); + auto* volTM0 = new TGeoVolume("glueFM", tM0, medGlue); + volTM0->SetLineColor(5); + volTM0->SetFillColor(5); + mechStavVol->AddNode(volTM0, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); + mechStavVol->AddNode(volTM0, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); + + // Glue microchannel and sensor + auto* glueM = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); + auto* volGlueM = new TGeoVolume("glueMS", glueM, medGlue); + volGlueM->SetLineColor(5); + volGlueM->SetFillColor(5); + mechStavVol->AddNode(volGlueM, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); + mechStavVol->AddNode(volGlueM, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); + + // Glue sensor and kapton + auto* glue = new TGeoBBox(xsta, klay4 / 2, zsta); + auto* volGlue = new TGeoVolume("glueSensorBus", glue, medGlue); + volGlue->SetLineColor(5); + volGlue->SetFillColor(5); + mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 / 2, z, new TGeoRotation("", 0, 0, 0))); + } + + if (mBuildLevel < 1) { + auto* kapCable = new TGeoBBox(xsta, klay5 / 2, zsta); + auto* volCable = new TGeoVolume("Flexcable", kapCable, medFlexCable); + volCable->SetLineColor(28); + volCable->SetFillColor(28); + mechStavVol->AddNode(volCable, 0, + new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 - klay5 / 2, z, + new TGeoRotation("", 0, 0, 0))); + } + // Done, return the stave structure + return mechStavVol; +} + +TGeoVolume* V1Layer::createStaveOuterB(const TGeoManager* mgr) +{ + TGeoVolume* mechStavVol = nullptr; + + switch (mStaveModel) { + case Detector::kOBModelDummy: + mechStavVol = createStaveModelOuterBDummy(mgr); + break; + case Detector::kOBModel0: + mechStavVol = createStaveModelOuterB0(mgr); + break; + case Detector::kOBModel1: + mechStavVol = createStaveModelOuterB1(mgr); + break; + default: + LOG(FATAL) << "Unknown stave model " << mStaveModel; + break; + } + return mechStavVol; +} + +TGeoVolume* V1Layer::createStaveModelOuterBDummy(const TGeoManager*) const +{ + // Done, return the stave structure + return nullptr; +} + +TGeoVolume* V1Layer::createStaveModelOuterB0(const TGeoManager* mgr) +{ + Double_t xmod, ymod, zmod; + Double_t xlen, ylen, zlen; + Double_t ypos, zpos; + char volumeName[30]; + + // First create all needed shapes + // The chip + xlen = sOBHalfStaveWidth; + ylen = 0.5 * mStaveThickness; // TO BE CHECKED + zlen = sOBModuleZLength / 2; + + TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); + + xmod = ((TGeoBBox*)chipVol->GetShape())->GetDX(); + ymod = ((TGeoBBox*)chipVol->GetShape())->GetDY(); + zmod = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); + + auto* module = new TGeoBBox(xmod, ymod, zmod); + + zlen = sOBModuleZLength * mNumberOfModules; + auto* hstave = new TGeoBBox(xlen, ylen, zlen / 2); + + // We have all shapes: now create the real volumes + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); + auto* modVol = new TGeoVolume(volumeName, module, medAir); + modVol->SetVisibility(kTRUE); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); + + // Finally build it up + modVol->AddNode(chipVol, 0); + mHierarchy[kChip] = 1; + + for (Int_t j = 0; j < mNumberOfModules; j++) { + ypos = 0.021; // Remove small overlap - M.S: 21may13 + zpos = -hstave->GetDZ() + j * 2 * zmod + zmod; + hstaveVol->AddNode(modVol, j, new TGeoTranslation(0, ypos, zpos)); + mHierarchy[kModule]++; + } + // Done, return the stave structure + return hstaveVol; +} + +TGeoVolume* V1Layer::createStaveModelOuterB1(const TGeoManager* mgr) +{ + Double_t yFlex1 = sOBFlexCableAlThick; + Double_t yFlex2 = sOBFlexCableKapThick; + Double_t flexOverlap = 5; // to be checked + Double_t xHalmSt = sOBHalfStaveWidth / 2; + Double_t rCoolMin = sOBCoolTubeInnerD / 2; + Double_t rCoolMax = rCoolMin + sOBCoolTubeThick; + Double_t kLay1 = 0.004; // to be checked + Double_t kLay2 = sOBGraphiteFoilThick; + + Double_t xlen, ylen; + Double_t ymod, zmod; + Double_t xtru[12], ytru[12]; + Double_t xpos, ypos, ypos1, zpos /*, zpos5cm*/; + Double_t zlen; + char volumeName[30]; + + zlen = (mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap) / 2; + + // First create all needed shapes + TGeoVolume* moduleVol = createModuleOuterB(); + moduleVol->SetVisibility(kTRUE); + ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); + zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); + + auto* busAl = new TGeoBBox("BusAl", xHalmSt, sOBBusCableAlThick / 2, zlen); + auto* busKap = new TGeoBBox("BusKap", xHalmSt, sOBBusCableKapThick / 2, zlen); + + auto* coldPlate = + new TGeoBBox("ColdPlate", sOBHalfStaveWidth / 2, sOBColdPlateThick / 2, zlen); + + auto* coolTube = new TGeoTube("CoolingTube", rCoolMin, rCoolMax, zlen); + auto* coolWater = new TGeoTube("CoolingWater", 0., rCoolMin, zlen); + + xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax(); + auto* graphlat = new TGeoBBox("GraphLateral", xlen / 2, kLay2 / 2, zlen); + + xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax(); + auto* graphmid = new TGeoBBox("GraphMiddle", xlen, kLay2 / 2, zlen); + + ylen = coolTube->GetRmax() - kLay2; + auto* graphvert = new TGeoBBox("GraphVertical", kLay2 / 2, ylen / 2, zlen); + + auto* graphtub = + new TGeoTubeSeg("GraphTube", rCoolMax, rCoolMax + kLay2, zlen, 180., 360.); + + xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; + auto* fleeclat = new TGeoBBox("FleecLateral", xlen / 2, kLay1 / 2, zlen); + + xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; + auto* fleecmid = new TGeoBBox("FleecMiddle", xlen, kLay1 / 2, zlen); + + ylen = coolTube->GetRmax() - kLay2 - kLay1; + auto* fleecvert = new TGeoBBox("FleecVertical", kLay1 / 2, ylen / 2, zlen); + + auto* fleectub = + new TGeoTubeSeg("FleecTube", rCoolMax + kLay2, rCoolMax + kLay1 + kLay2, zlen, 180., 360.); + + auto* flex1_5cm = new TGeoBBox("Flex1MV_5cm", xHalmSt, yFlex1 / 2, flexOverlap / 2); + auto* flex2_5cm = new TGeoBBox("Flex2MV_5cm", xHalmSt, yFlex2 / 2, flexOverlap / 2); + + // The half stave container (an XTru to avoid overlaps between neightbours) + xtru[0] = xHalmSt; + ytru[0] = 0; + xtru[1] = xtru[0]; + ytru[1] = -2 * (ymod + busAl->GetDY() + busKap->GetDY() + coldPlate->GetDY() + graphlat->GetDY() + + fleeclat->GetDY()); + xtru[2] = sOBCoolTubeXDist / 2 + fleectub->GetRmax(); + ytru[2] = ytru[1]; + xtru[3] = xtru[2]; + ytru[3] = ytru[2] - (coolTube->GetRmax() + fleectub->GetRmax()); + xtru[4] = sOBCoolTubeXDist / 2 - fleectub->GetRmax(); + ytru[4] = ytru[3]; + xtru[5] = xtru[4]; + ytru[5] = ytru[2]; + for (Int_t i = 0; i < 6; i++) { + xtru[6 + i] = -xtru[5 - i]; + ytru[6 + i] = ytru[5 - i]; + } + auto* halmStave = new TGeoXtru(2); + halmStave->DefinePolygon(12, xtru, ytru); + halmStave->DefineSection(0, -mZLength / 2); + halmStave->DefineSection(1, mZLength / 2); + + // We have all shapes: now create the real volumes + + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); + TGeoMedium* medCarbon = mgr->GetMedium("TRK_CARBON$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + TGeoMedium* medFGS003 = mgr->GetMedium("TRK_FGS003$"); // amec thermasol + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + auto* busAlVol = new TGeoVolume("BusAlVol", busAl, medAluminum); + busAlVol->SetLineColor(kCyan); + busAlVol->SetFillColor(busAlVol->GetLineColor()); + busAlVol->SetFillStyle(4000); // 0% transparent + + auto* busKapVol = new TGeoVolume("BusKapVol", busKap, medKapton); + busKapVol->SetLineColor(kBlue); + busKapVol->SetFillColor(busKapVol->GetLineColor()); + busKapVol->SetFillStyle(4000); // 0% transparent + + auto* coldPlateVol = new TGeoVolume("ColdPlateVol", coldPlate, medCarbon); + coldPlateVol->SetLineColor(kYellow - 3); + coldPlateVol->SetFillColor(coldPlateVol->GetLineColor()); + coldPlateVol->SetFillStyle(4000); // 0% transparent + + auto* coolTubeVol = new TGeoVolume("CoolingTubeVol", coolTube, medKapton); + coolTubeVol->SetLineColor(kGray); + coolTubeVol->SetFillColor(coolTubeVol->GetLineColor()); + coolTubeVol->SetFillStyle(4000); // 0% transparent + + auto* coolWaterVol = new TGeoVolume("CoolingWaterVol", coolWater, medWater); + coolWaterVol->SetLineColor(kBlue); + coolWaterVol->SetFillColor(coolWaterVol->GetLineColor()); + coolWaterVol->SetFillStyle(4000); // 0% transparent + + auto* graphlatVol = new TGeoVolume("GraphiteFoilLateral", graphlat, medFGS003); + graphlatVol->SetLineColor(kGreen); + graphlatVol->SetFillColor(graphlatVol->GetLineColor()); + graphlatVol->SetFillStyle(4000); // 0% transparent + + auto* graphmidVol = new TGeoVolume("GraphiteFoilMiddle", graphmid, medFGS003); + graphmidVol->SetLineColor(kGreen); + graphmidVol->SetFillColor(graphmidVol->GetLineColor()); + graphmidVol->SetFillStyle(4000); // 0% transparent + + auto* graphvertVol = new TGeoVolume("GraphiteFoilVertical", graphvert, medFGS003); + graphvertVol->SetLineColor(kGreen); + graphvertVol->SetFillColor(graphvertVol->GetLineColor()); + graphvertVol->SetFillStyle(4000); // 0% transparent + + auto* graphtubVol = new TGeoVolume("GraphiteFoilPipeCover", graphtub, medFGS003); + graphtubVol->SetLineColor(kGreen); + graphtubVol->SetFillColor(graphtubVol->GetLineColor()); + graphtubVol->SetFillStyle(4000); // 0% transparent + + auto* fleeclatVol = new TGeoVolume("CarbonFleeceLateral", fleeclat, medCarbonFleece); + fleeclatVol->SetLineColor(kViolet); + fleeclatVol->SetFillColor(fleeclatVol->GetLineColor()); + fleeclatVol->SetFillStyle(4000); // 0% transparent + + auto* fleecmidVol = new TGeoVolume("CarbonFleeceMiddle", fleecmid, medCarbonFleece); + fleecmidVol->SetLineColor(kViolet); + fleecmidVol->SetFillColor(fleecmidVol->GetLineColor()); + fleecmidVol->SetFillStyle(4000); // 0% transparent + + auto* fleecvertVol = new TGeoVolume("CarbonFleeceVertical", fleecvert, medCarbonFleece); + fleecvertVol->SetLineColor(kViolet); + fleecvertVol->SetFillColor(fleecvertVol->GetLineColor()); + fleecvertVol->SetFillStyle(4000); // 0% transparent + + auto* fleectubVol = new TGeoVolume("CarbonFleecePipeCover", fleectub, medCarbonFleece); + fleectubVol->SetLineColor(kViolet); + fleectubVol->SetFillColor(fleectubVol->GetLineColor()); + fleectubVol->SetFillStyle(4000); // 0% transparent + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + auto* halmStaveVol = new TGeoVolume(volumeName, halmStave, medAir); + // halmStaveVol->SetLineColor(12); + // halmStaveVol->SetFillColor(12); + // halmStaveVol->SetVisibility(kTRUE); + + auto* flex1_5cmVol = new TGeoVolume("Flex1Vol5cm", flex1_5cm, medAluminum); + auto* flex2_5cmVol = new TGeoVolume("Flex2Vol5cm", flex2_5cm, medKapton); + + flex1_5cmVol->SetLineColor(kRed); + flex2_5cmVol->SetLineColor(kGreen); + + // Now build up the half stave + ypos = -busKap->GetDY(); + halmStaveVol->AddNode(busKapVol, 1, new TGeoTranslation(0, ypos, 0)); + + ypos -= (busKap->GetDY() + busAl->GetDY()); + halmStaveVol->AddNode(busAlVol, 1, new TGeoTranslation(0, ypos, 0)); + + ypos -= (busAl->GetDY() + ymod); + for (Int_t j = 0; j < mNumberOfModules; j++) { + zpos = -zlen + j * (2 * zmod + sOBModuleGap) + zmod; + halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(0, ypos, zpos)); + mHierarchy[kModule]++; + } + + ypos -= (ymod + coldPlate->GetDY()); + halmStaveVol->AddNode(coldPlateVol, 1, new TGeoTranslation(0, ypos, 0)); + + coolTubeVol->AddNode(coolWaterVol, 1, nullptr); + + xpos = sOBCoolTubeXDist / 2; + ypos1 = ypos - (coldPlate->GetDY() + coolTube->GetRmax()); + halmStaveVol->AddNode(coolTubeVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(coolTubeVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + + halmStaveVol->AddNode(graphtubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(graphtubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + + halmStaveVol->AddNode(fleectubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(fleectubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + + xpos = xHalmSt - graphlat->GetDX(); + ypos1 = ypos - (coldPlate->GetDY() + graphlat->GetDY()); + halmStaveVol->AddNode(graphlatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(graphlatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + + halmStaveVol->AddNode(graphmidVol, 1, new TGeoTranslation(0, ypos1, 0)); + + xpos = xHalmSt - 2 * graphlat->GetDX() + graphvert->GetDX(); + ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + graphvert->GetDY()); + halmStaveVol->AddNode(graphvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(graphvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + xpos = graphmid->GetDX() - graphvert->GetDX(); + halmStaveVol->AddNode(graphvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(graphvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); + + xpos = xHalmSt - fleeclat->GetDX(); + ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + fleeclat->GetDY()); + halmStaveVol->AddNode(fleeclatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(fleeclatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + + halmStaveVol->AddNode(fleecmidVol, 1, new TGeoTranslation(0, ypos1, 0)); + + xpos = xHalmSt - 2 * fleeclat->GetDX() + fleecvert->GetDX(); + ypos1 = ypos - + (coldPlate->GetDY() + 2 * graphlat->GetDY() + 2 * fleeclat->GetDY() + fleecvert->GetDY()); + halmStaveVol->AddNode(fleecvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(fleecvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); + xpos = fleecmid->GetDX() - fleecvert->GetDX(); + halmStaveVol->AddNode(fleecvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); + halmStaveVol->AddNode(fleecvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); + + // THE FOLLOWING IS ONLY A REMINDER FOR WHAT IS STILL MISSING + + // for (Int_t j=0; j<mNumberOfChips; j++) { + + // zpos = -(zact + (mNumberOfChips-1)*modGap)/2 + j*(zMod + modGap) + zMod/2; + // zpos5cm = -(zact + (mNumberOfChips-1)*modGap)/2 + (j+1)*(zMod + modGap) + flexOverlap/2 ; + + // halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(xPos, -ylen + yPos + 2*rCoolMax + + // yCPlate + yGlue + yModPlate + ymod, zpos)); + // halmStaveVol->AddNode(moduleVol, mNumberOfChips+j, new TGeoTranslation(-xPos, -ylen + yPos + // + + // 2*rCoolMax + yCPlate + yGlue + yModPlate + ymod +deltaY, zpos)); + + // if((j+1)!=mNumberOfChips){ + // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + + // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2,zpos5cm)); + // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + + // yPos + + // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2 + // +deltaY,zpos5cm)); + // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + + // yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2,zpos5cm)); + // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + + // yPos + + // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2 +deltaY,zpos5cm)); + // } + // else { + // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + + // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2,zpos5cm-modGap)); + // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + + // yPos + + // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2 +deltaY,zpos5cm-modGap)); + // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + + // yCPlate + yGlue + yModPlate +2*ymod + yFlex1 + yFlex2/2,zpos5cm-modGap)); + // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + + // yPos + + // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2/2 +deltaY,zpos5cm-modGap)); + + // } + // } + // Done, return the half stave structure + return halmStaveVol; +} + +TGeoVolume* V1Layer::createSpaceFrameOuterB(const TGeoManager* mgr) +{ + TGeoVolume* mechStavVol = nullptr; + + switch (mStaveModel) { + case Detector::kOBModelDummy: + case Detector::kOBModel0: + mechStavVol = createSpaceFrameOuterBDummy(mgr); + break; + case Detector::kOBModel1: + mechStavVol = createSpaceFrameOuterB1(mgr); + break; + default: + LOG(FATAL) << "Unknown stave model " << mStaveModel; + break; + } + + return mechStavVol; +} + +TGeoVolume* V1Layer::createSpaceFrameOuterBDummy(const TGeoManager*) const +{ + // Done, return the stave structur + return nullptr; +} + +TGeoVolume* V1Layer::createSpaceFrameOuterB1(const TGeoManager* mgr) +{ + // Materials defined in Detector + TGeoMedium* medCarbon = mgr->GetMedium("TRK_CARBON$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + + // Local parameters + Double_t sframeWidth = sOBSpaceFrameWidth; + Double_t sframeHeight = sOBSpaceFrameTotHigh - sOBHalfStaveYTrans; + Double_t staveBeamRadius = sOBSFrameBeamRadius; + Double_t staveLa = sOBSpaceFrameLa; + Double_t staveHa = sOBSpaceFrameHa; + Double_t staveLb = sOBSpaceFrameLb; + Double_t staveHb = sOBSpaceFrameHb; + Double_t stavel = sOBSpaceFrameL; + Double_t bottomBeamAngle = sOBSFBotBeamAngle; + Double_t triangleHeight = sframeHeight - staveBeamRadius; + Double_t halmTheta = TMath::ATan(0.5 * sframeWidth / triangleHeight); + // Double_t alpha = TMath::Pi()*3./4. - halmTheta/2.; + Double_t beta = (TMath::Pi() - 2. * halmTheta) / 4.; + // Double_t distCenterSideDown = 0.5*sframeWidth/TMath::Cos(beta); + + Double_t zlen; + Double_t xpos, ypos, zpos; + Double_t seglen; + char volumeName[30]; + + zlen = mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap; + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + if (gGeoManager->GetVolume(volumeName)) { // Should always be so + sframeHeight -= ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDY() * 2; + zlen = ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDZ() * 2; + } + seglen = zlen / mNumberOfModules; + + // First create all needed shapes and volumes + auto* spaceFrame = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, zlen / 2); + auto* segment = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, seglen / 2); + + auto* spaceFrameVol = new TGeoVolume("CarbonFrameVolume", spaceFrame, medAir); + spaceFrameVol->SetVisibility(kFALSE); + + auto* segmentVol = new TGeoVolume("segmentVol", segment, medAir); + + // SpaceFrame + + //--- the top V of the Carbon Fiber Stave (segment) + TGeoArb8* cmStavTop1 = createStaveSide("CFstavTopCornerVol1shape", seglen / 2., halmTheta, -1, + staveLa, staveHa, stavel); + auto* cmStavTopVol1 = new TGeoVolume("CFstavTopCornerVol1", cmStavTop1, medCarbon); + cmStavTopVol1->SetLineColor(35); + + TGeoArb8* cmStavTop2 = createStaveSide("CFstavTopCornerVol2shape", seglen / 2., halmTheta, 1, + staveLa, staveHa, stavel); + auto* cmStavTopVol2 = new TGeoVolume("CFstavTopCornerVol2", cmStavTop2, medCarbon); + cmStavTopVol2->SetLineColor(35); + + auto* trTop1 = new TGeoTranslation(0, sframeHeight / 2, 0); + + //--- the 2 side V + TGeoArb8* cmStavSide1 = + createStaveSide("CFstavSideCornerVol1shape", seglen / 2., beta, -1, staveLb, staveHb, stavel); + auto* cmStavSideVol1 = new TGeoVolume("CFstavSideCornerVol1", cmStavSide1, medCarbon); + cmStavSideVol1->SetLineColor(35); + + TGeoArb8* cmStavSide2 = + createStaveSide("CFstavSideCornerVol2shape", seglen / 2., beta, 1, staveLb, staveHb, stavel); + auto* cmStavSideVol2 = new TGeoVolume("CFstavSideCornerVol2", cmStavSide2, medCarbon); + cmStavSideVol2->SetLineColor(35); + + xpos = -sframeWidth / 2; + ypos = -sframeHeight / 2 + staveBeamRadius + staveHb * TMath::Sin(beta); + auto* ctSideR = new TGeoCombiTrans( + xpos, ypos, 0, new TGeoRotation("", 180 - 2 * beta * TMath::RadToDeg(), 0, 0)); + auto* ctSideL = new TGeoCombiTrans( + -xpos, ypos, 0, new TGeoRotation("", -180 + 2 * beta * TMath::RadToDeg(), 0, 0)); + + segmentVol->AddNode(cmStavTopVol1, 1, trTop1); + segmentVol->AddNode(cmStavTopVol2, 1, trTop1); + segmentVol->AddNode(cmStavSideVol1, 1, ctSideR); + segmentVol->AddNode(cmStavSideVol1, 2, ctSideL); + segmentVol->AddNode(cmStavSideVol2, 1, ctSideR); + segmentVol->AddNode(cmStavSideVol2, 2, ctSideL); + + //--- The beams + // Beams on the sides + Double_t beamPhiPrime = TMath::ASin( + 1. / TMath::Sqrt((1 + TMath::Sin(2 * beta) * TMath::Sin(2 * beta) / + (tanD(sOBSFrameBeamSidePhi) * tanD(sOBSFrameBeamSidePhi))))); + Double_t beamLength = TMath::Sqrt(sframeHeight * sframeHeight / + (TMath::Sin(beamPhiPrime) * TMath::Sin(beamPhiPrime)) + + sframeWidth * sframeWidth / 4.) - + staveLa / 2 - staveLb / 2; + auto* sideBeam = new TGeoTubeSeg(0, staveBeamRadius, beamLength / 2, 0, 180); + auto* sideBeamVol = new TGeoVolume("CFstavSideBeamVol", sideBeam, medCarbon); + sideBeamVol->SetLineColor(35); + + auto* beamRot1 = new TGeoRotation("", /*90-2*beta*/ halmTheta * TMath::RadToDeg(), + -beamPhiPrime * TMath::RadToDeg(), -90); + auto* beamRot2 = + new TGeoRotation("", 90 - 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); + auto* beamRot3 = + new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); + auto* beamRot4 = new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), + -beamPhiPrime * TMath::RadToDeg(), -90); + + TGeoCombiTrans* beamTransf[8]; + xpos = 0.49 * triangleHeight * TMath::Tan(halmTheta); // was 0.5, fix small overlap + ypos = staveBeamRadius / 2; + zpos = seglen / 8; + beamTransf[0] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); + + beamTransf[1] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); + addTranslationToCombiTrans(beamTransf[1], 0, 0, seglen / 2); + + beamTransf[2] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); + + beamTransf[3] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); + addTranslationToCombiTrans(beamTransf[3], 0, 0, seglen / 2); + + beamTransf[4] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); + + beamTransf[5] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); + addTranslationToCombiTrans(beamTransf[5], 0, 0, seglen / 2); + + beamTransf[6] = new TGeoCombiTrans(-xpos, ypos, -zpos, beamRot4); + beamTransf[7] = new TGeoCombiTrans(-xpos, ypos, 3 * zpos, beamRot4); + + //--- Beams of the bottom + auto* bottomBeam1 = + new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 180); + auto* bottomBeam1Vol = new TGeoVolume("CFstavBottomBeam1Vol", bottomBeam1, medCarbon); + bottomBeam1Vol->SetLineColor(35); + + auto* bottomBeam2 = + new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 90); + auto* bottomBeam2Vol = new TGeoVolume("CFstavBottomBeam2Vol", bottomBeam2, medCarbon); + bottomBeam2Vol->SetLineColor(35); + + auto* bottomBeam3 = new TGeoTubeSeg( + 0, staveBeamRadius, 0.5 * sframeWidth / sinD(bottomBeamAngle) - staveLb / 3, 0, 180); + auto* bottomBeam3Vol = new TGeoVolume("CFstavBottomBeam3Vol", bottomBeam3, medCarbon); + bottomBeam3Vol->SetLineColor(35); + + auto* bottomBeamRot1 = new TGeoRotation("", 90, 90, 90); + auto* bottomBeamRot2 = new TGeoRotation("", -90, 90, -90); + + auto* bottomBeamTransf1 = + new TGeoCombiTrans("", 0, -(sframeHeight / 2 - staveBeamRadius), 0, bottomBeamRot1); + auto* bottomBeamTransf2 = + new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 2, bottomBeamRot1); + auto* bottomBeamTransf3 = + new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 2, bottomBeamRot2); + // be careful for beams #3: when "reading" from -z to +z and + // from the bottom of the stave, it should draw a Lambda, and not a V + auto* bottomBeamRot4 = new TGeoRotation("", -90, bottomBeamAngle, -90); + auto* bottomBeamRot5 = new TGeoRotation("", -90, -bottomBeamAngle, -90); + + auto* bottomBeamTransf4 = + new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 4, bottomBeamRot4); + auto* bottomBeamTransf5 = + new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 4, bottomBeamRot5); + + segmentVol->AddNode(sideBeamVol, 1, beamTransf[0]); + segmentVol->AddNode(sideBeamVol, 2, beamTransf[1]); + segmentVol->AddNode(sideBeamVol, 3, beamTransf[2]); + segmentVol->AddNode(sideBeamVol, 4, beamTransf[3]); + segmentVol->AddNode(sideBeamVol, 5, beamTransf[4]); + segmentVol->AddNode(sideBeamVol, 6, beamTransf[5]); + segmentVol->AddNode(sideBeamVol, 7, beamTransf[6]); + segmentVol->AddNode(sideBeamVol, 8, beamTransf[7]); + segmentVol->AddNode(bottomBeam1Vol, 1, bottomBeamTransf1); + segmentVol->AddNode(bottomBeam2Vol, 1, bottomBeamTransf2); + segmentVol->AddNode(bottomBeam2Vol, 2, bottomBeamTransf3); + segmentVol->AddNode(bottomBeam3Vol, 1, bottomBeamTransf4); + segmentVol->AddNode(bottomBeam3Vol, 2, bottomBeamTransf5); + + // Then build up the space frame + for (Int_t i = 0; i < mNumberOfModules; i++) { + zpos = -spaceFrame->GetDZ() + (1 + 2 * i) * segment->GetDZ(); + spaceFrameVol->AddNode(segmentVol, i, new TGeoTranslation(0, 0, zpos)); + } + + // Done, return the space frame structure + return spaceFrameVol; +} + +TGeoVolume* V1Layer::createChipInnerB(const Double_t xchip, const Double_t ychip, + const Double_t zchip, const TGeoManager* mgr) +{ + char volumeName[30]; + Double_t xlen, ylen, zlen; + Double_t xpos, ypos, zpos; + + // First create all needed shapes + + // The chip + auto* chip = new TGeoBBox(xchip, ychip, zchip); + + // The sensor + xlen = chip->GetDX(); + ylen = 0.5 * mSensorThickness; + zlen = chip->GetDZ(); + auto* sensor = new TGeoBBox(xlen, ylen, zlen); + + // We have all shapes: now create the real volumes + TGeoMedium* medSi = mgr->GetMedium("TRK_SI$"); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSChipPattern(), mLayerNumber); + auto* chipVol = new TGeoVolume(volumeName, chip, medSi); + chipVol->SetVisibility(kTRUE); + chipVol->SetLineColor(1); + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSSensorPattern(), mLayerNumber); + auto* sensVol = new TGeoVolume(volumeName, sensor, medSi); + sensVol->SetVisibility(kTRUE); + sensVol->SetLineColor(8); + sensVol->SetLineWidth(1); + sensVol->SetFillColor(sensVol->GetLineColor()); + sensVol->SetFillStyle(4000); // 0% transparent + + // Now build up the chip + xpos = 0.; + ypos = -chip->GetDY() + sensor->GetDY(); + zpos = 0.; + + chipVol->AddNode(sensVol, 1, new TGeoTranslation(xpos, ypos, zpos)); + + // Done, return the chip + return chipVol; +} + +TGeoVolume* V1Layer::createModuleOuterB(const TGeoManager* mgr) +{ + char volumeName[30]; + + Double_t xGap = sOBChipXGap; + Double_t zGap = sOBChipZGap; + + Double_t xchip, ychip, zchip; + Double_t xlen, ylen, zlen; + Double_t xpos, ypos, zpos; + + // First create all needed shapes + + // The chip (the same as for IB) + xlen = (sOBHalfStaveWidth / 2 - xGap / 2) / sOBNChipRows; + ylen = 0.5 * mStaveThickness; // TO BE CHECKED + zlen = (sOBModuleZLength - (sOBChipsPerRow - 1) * zGap) / (2 * sOBChipsPerRow); + + TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); + + xchip = ((TGeoBBox*)chipVol->GetShape())->GetDX(); + ychip = ((TGeoBBox*)chipVol->GetShape())->GetDY(); + zchip = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); + + // The module carbon plate + xlen = sOBHalfStaveWidth / 2; + ylen = sOBCarbonPlateThick / 2; + zlen = sOBModuleZLength / 2; + auto* modPlate = new TGeoBBox("CarbonPlate", xlen, ylen, zlen); + + // The glue + ylen = sOBGlueThick / 2; + auto* glue = new TGeoBBox("Glue", xlen, ylen, zlen); + + // The flex cables + ylen = sOBFlexCableAlThick / 2; + auto* flexAl = new TGeoBBox("FlexAl", xlen, ylen, zlen); + + ylen = sOBFlexCableKapThick / 2; + auto* flexKap = new TGeoBBox("FlexKap", xlen, ylen, zlen); + + // The module + xlen = sOBHalfStaveWidth / 2; + ylen = ychip + modPlate->GetDY() + glue->GetDY() + flexAl->GetDY() + flexKap->GetDY(); + zlen = sOBModuleZLength / 2; + auto* module = new TGeoBBox("OBModule", xlen, ylen, zlen); + + // We have all shapes: now create the real volumes + + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medCarbon = mgr->GetMedium("TRK_CARBON$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + + auto* modPlateVol = new TGeoVolume("CarbonPlateVol", modPlate, medCarbon); + modPlateVol->SetLineColor(kMagenta - 8); + modPlateVol->SetFillColor(modPlateVol->GetLineColor()); + modPlateVol->SetFillStyle(4000); // 0% transparent + + auto* glueVol = new TGeoVolume("GlueVol", glue, medGlue); + glueVol->SetLineColor(kBlack); + glueVol->SetFillColor(glueVol->GetLineColor()); + glueVol->SetFillStyle(4000); // 0% transparent + + auto* flexAlVol = new TGeoVolume("FlexAlVol", flexAl, medAluminum); + flexAlVol->SetLineColor(kRed); + flexAlVol->SetFillColor(flexAlVol->GetLineColor()); + flexAlVol->SetFillStyle(4000); // 0% transparent + + auto* flexKapVol = new TGeoVolume("FlexKapVol", flexKap, medKapton); + flexKapVol->SetLineColor(kGreen); + flexKapVol->SetFillColor(flexKapVol->GetLineColor()); + flexKapVol->SetFillStyle(4000); // 0% transparent + + snprintf(volumeName, 30, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); + auto* modVol = new TGeoVolume(volumeName, module, medAir); + modVol->SetVisibility(kTRUE); + + // Now build up the module + ypos = -module->GetDY() + modPlate->GetDY(); + modVol->AddNode(modPlateVol, 1, new TGeoTranslation(0, ypos, 0)); + + ypos += (modPlate->GetDY() + glue->GetDY()); + modVol->AddNode(glueVol, 1, new TGeoTranslation(0, ypos, 0)); + + xpos = -module->GetDX() + xchip; + ypos += (glue->GetDY() + ychip); + for (Int_t k = 0; k < sOBChipsPerRow; k++) { // put 7x2 chip into one module + zpos = -module->GetDZ() + zchip + k * (2 * zchip + zGap); + modVol->AddNode(chipVol, 2 * k, new TGeoTranslation(xpos, ypos, zpos)); + modVol->AddNode(chipVol, 2 * k + 1, + new TGeoCombiTrans(-xpos, ypos, zpos, new TGeoRotation("", 0, 180, 180))); + mHierarchy[kChip] += 2; + } + + ypos += (ychip + flexAl->GetDY()); + modVol->AddNode(flexAlVol, 1, new TGeoTranslation(0, ypos, 0)); + + ypos += (flexAl->GetDY() + flexKap->GetDY()); + modVol->AddNode(flexKapVol, 1, new TGeoTranslation(0, ypos, 0)); + + // Done, return the module + return modVol; +} + +Double_t V1Layer::radiusOmTurboContainer() +{ + Double_t rr, delta, z, lstav, rstav; + + if (mStaveThickness > 89.) { // Very big angle: avoid overflows since surely + return -1; // the radius from lower vertex is the right value + } + + rstav = mLayerRadius + 0.5 * mStaveThickness; + delta = (0.5 * mStaveThickness) / cosD(mStaveTilt); + z = (0.5 * mStaveThickness) * tanD(mStaveTilt); + + rr = rstav - delta; + lstav = (0.5 * mStaveWidth) - z; + + if ((rr * sinD(mStaveTilt) < lstav)) { + return (rr * cosD(mStaveTilt)); + } else { + return -1; + } +} + +void V1Layer::setNumberOfUnits(Int_t u) +{ + if (mLayerNumber < sNumberOmInnerLayers) { + mNumberOfChips = u; + } else { + mNumberOfModules = u; + mNumberOfChips = sOBChipsPerRow; + } +} + +void V1Layer::setStaveTilt(const Double_t t) +{ + if (mIsTurbo) { + mStaveTilt = t; + } else { + LOG(ERROR) << "Not a Turbo layer"; + } +} + +void V1Layer::setStaveWidth(const Double_t w) +{ + if (mIsTurbo) { + mStaveWidth = w; + } else { + LOG(ERROR) << "Not a Turbo layer"; + } +} + +TGeoArb8* V1Layer::createStaveSide(const char* name, Double_t dz, Double_t angle, + Double_t xSign, Double_t L, Double_t H, Double_t l) +{ + // Create one half of the V shape corner of CF stave + + auto* cmStavSide = new TGeoArb8(dz); + cmStavSide->SetName(name); + + // Points must be in clockwise order + cmStavSide->SetVertex(0, 0, 0); + cmStavSide->SetVertex(2, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), + -L * TMath::Cos(angle) - l * TMath::Sin(angle)); + cmStavSide->SetVertex(4, 0, 0); + cmStavSide->SetVertex(6, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), + -L * TMath::Cos(angle) - l * TMath::Sin(angle)); + if (xSign < 0) { + cmStavSide->SetVertex(1, 0, -H); + cmStavSide->SetVertex(3, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); + cmStavSide->SetVertex(5, 0, -H); + cmStavSide->SetVertex(7, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); + } else { + cmStavSide->SetVertex(1, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); + cmStavSide->SetVertex(3, 0, -H); + cmStavSide->SetVertex(5, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); + cmStavSide->SetVertex(7, 0, -H); + } + return cmStavSide; +} + +TGeoCombiTrans* V1Layer::createCombiTrans(const char* name, Double_t dy, Double_t dz, + Double_t dphi, Bool_t planeSym) +{ + TGeoTranslation t1(dy * cosD(90. + dphi), dy * sinD(90. + dphi), dz); + TGeoRotation r1("", 0., 0., dphi); + TGeoRotation r2("", 90, 180, -90 - dphi); + + auto* combiTrans1 = new TGeoCombiTrans(name); + combiTrans1->SetTranslation(t1); + if (planeSym) { + combiTrans1->SetRotation(r1); + } else { + combiTrans1->SetRotation(r2); + } + return combiTrans1; +} + +void V1Layer::addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx, Double_t dy, + Double_t dz) const +{ + // Add a dx,dy,dz translation to the initial TGeoCombiTrans + const Double_t* vect = ct->GetTranslation(); + Double_t newVect[3] = {vect[0] + dx, vect[1] + dy, vect[2] + dz}; + ct->SetTranslation(newVect); +} diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Layer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Layer.cxx similarity index 96% rename from Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Layer.cxx rename to Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Layer.cxx index d9840e6ae6b7e..372d7d7191fe5 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Layer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Layer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,9 +14,9 @@ /// \author Mario Sitta <sitta@to.infn.it> /// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) -#include "ITS4Simulation/V3Layer.h" -#include "ITS4Base/GeometryTGeo.h" -#include "ITS4Simulation/Detector.h" +#include "TRKSimulation/V3Layer.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKSimulation/Detector.h" #include "ITSMFTSimulation/AlpideChip.h" #include "ITSMFTBase/SegmentationAlpide.h" @@ -40,7 +41,7 @@ class TGeoMedium; using namespace TMath; -using namespace o2::its4; +using namespace o2::trk; using namespace o2::itsmft; using AlpideChip = o2::itsmft::AlpideChip; @@ -267,7 +268,7 @@ V3Layer::V3Layer() mNumberOfChips(0), mChipTypeID(0), mIsTurbo(0), - mIsITS4(0), + mIsTRK(0), mBuildLevel(0), mStaveModel(Detector::kIBModelDummy), mAddGammaConv(kFALSE), @@ -296,7 +297,7 @@ V3Layer::V3Layer(Int_t lay, Bool_t turbo, Int_t debug) mNumberOfChips(0), mChipTypeID(0), mIsTurbo(turbo), - mIsITS4(0), + mIsTRK(0), mBuildLevel(0), mStaveModel(Detector::kIBModelDummy), mAddGammaConv(kFALSE), @@ -323,7 +324,7 @@ void V3Layer::createLayer(TGeoVolume* motherVolume) if (mLayerRadius <= 0) { LOG(FATAL) << "Wrong layer radius " << mLayerRadius; } - /* // These checks would fail with new ITS4 geo, let's trust the user here :) + /* // These checks would fail with new TRK geo, let's trust the user here :) if (mNumberOfStaves <= 0) { LOG(FATAL) << "Wrong number of staves " << mNumberOfStaves; } @@ -354,9 +355,9 @@ void V3Layer::createLayer(TGeoVolume* motherVolume) return; } - // If a new ITS4 layer is requested, do it and exit - if (mIsITS4) { - createITS4Layer(motherVolume); + // If a new TRK layer is requested, do it and exit + if (mIsTRK) { + createTRKLayer(motherVolume); return; } @@ -365,7 +366,7 @@ void V3Layer::createLayer(TGeoVolume* motherVolume) // mStaveWidth = mLayerRadius*Tan(alpha); - snprintf(volumeName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSLayerPattern(), mLayerNumber); + snprintf(volumeName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSLayerPattern(), mLayerNumber); TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); layerVolume->SetUniqueID(mChipTypeID); @@ -410,7 +411,7 @@ void V3Layer::createLayerTurbo(TGeoVolume* motherVolume) LOG(WARNING) << "Stave tilt angle (" << mStaveTilt << ") greater than 45deg"; } - snprintf(volumeName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSLayerPattern(), mLayerNumber); + snprintf(volumeName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSLayerPattern(), mLayerNumber); TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); layerVolume->SetUniqueID(mChipTypeID); layerVolume->SetVisibility(kTRUE); @@ -436,7 +437,7 @@ void V3Layer::createLayerTurbo(TGeoVolume* motherVolume) return; } -void V3Layer::createITS4Layer(TGeoVolume* motherVolume, const TGeoManager* mgr) +void V3Layer::createTRKLayer(TGeoVolume* motherVolume, const TGeoManager* mgr) { Double_t rmin = mLayerRadius; @@ -446,12 +447,12 @@ void V3Layer::createITS4Layer(TGeoVolume* motherVolume, const TGeoManager* mgr) char chipName[nameLen], sensName[nameLen], moduleName[nameLen], hsName[nameLen], staveName[nameLen], layerName[nameLen]; - snprintf(sensName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSSensorPattern(), mLayerNumber); - snprintf(chipName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSChipPattern(), mLayerNumber); - snprintf(moduleName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); - snprintf(hsName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - snprintf(staveName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSStavePattern(), mLayerNumber); - snprintf(layerName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSLayerPattern(), mLayerNumber); + snprintf(sensName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSSensorPattern(), mLayerNumber); + snprintf(chipName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSChipPattern(), mLayerNumber); + snprintf(moduleName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); + snprintf(hsName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + snprintf(staveName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSStavePattern(), mLayerNumber); + snprintf(layerName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSLayerPattern(), mLayerNumber); TGeoTube* sensor = new TGeoTube(rmin, rmax, mIBModuleZLength / 2); TGeoTube* chip = new TGeoTube(rmin, rmax, mIBModuleZLength / 2); @@ -460,8 +461,8 @@ void V3Layer::createITS4Layer(TGeoVolume* motherVolume, const TGeoManager* mgr) TGeoTube* stave = new TGeoTube(rmin, rmax, mIBModuleZLength / 2); TGeoTube* layer = new TGeoTube(rmin, rmax, mIBModuleZLength / 2); - TGeoMedium* medSi = mgr->GetMedium("IT4_SI$"); - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); + TGeoMedium* medSi = mgr->GetMedium("TRK_SI$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); TGeoVolume* sensVol = new TGeoVolume(sensName, sensor, medSi); TGeoVolume* chipVol = new TGeoVolume(chipName, chip, medAir); @@ -529,7 +530,7 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); // The stave - snprintf(volumeName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSStavePattern(), mLayerNumber); + snprintf(volumeName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSStavePattern(), mLayerNumber); TGeoVolume* staveVol = new TGeoVolumeAssembly(volumeName); staveVol->SetVisibility(kTRUE); staveVol->SetLineColor(2); @@ -597,9 +598,9 @@ TGeoVolume* V3Layer::createStaveInnerB(const TGeoManager* mgr) TGeoBBox* hstave = new TGeoBBox(xmod, ymod, zmod); - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); - snprintf(volumeName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + snprintf(volumeName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); TGeoVolume* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); // Finally build it up @@ -626,8 +627,8 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) } // First create the single chip - snprintf(chipName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSChipPattern(), mLayerNumber); - snprintf(sensName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSSensorPattern(), mLayerNumber); + snprintf(chipName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSChipPattern(), mLayerNumber); + snprintf(sensName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSSensorPattern(), mLayerNumber); ymod = 0.5 * mChipThickness; @@ -661,11 +662,11 @@ TGeoVolume* V3Layer::createModuleInnerB(const TGeoManager* mgr) TGeoBBox* module = new TGeoBBox(xtot, ytot, ztot); // Now the volumes - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE_IBFPC$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE_IBFPC$"); - snprintf(volumeName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); + snprintf(volumeName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); TGeoVolume* modVol = new TGeoVolume(volumeName, module, medAir); TGeoVolume* glueVol = new TGeoVolume("FPCGlue", glue, medGlue); @@ -763,7 +764,7 @@ void V3Layer::createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yz if (!capacitor) { TGeoBBox* capsh = new TGeoBBox(sIBFlexCapacitorXWid / 2, sIBFlexCapacitorYHi / 2, sIBFlexCapacitorZLen / 2); - TGeoMedium* medCeramic = mgr->GetMedium("IT4_CERAMIC$"); + TGeoMedium* medCeramic = mgr->GetMedium("TRK_CERAMIC$"); capacitor = new TGeoVolume("IBFPCCapacitor", capsh, medCeramic); capacitor->SetLineColor(kBlack); @@ -864,8 +865,8 @@ TGeoVolume* V3Layer::createIBFPCAlGnd(const Double_t xcable, const Double_t zcab TGeoBBox* aluminum = new TGeoBBox(xcable, sIBFlexCableAlThick / 2, zcable); // Then the volumes - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); TGeoVolume* coverlayVol = new TGeoVolume("FPCCoverlayGround", coverlay, medKapton); coverlayVol->SetLineColor(kBlue); @@ -916,8 +917,8 @@ TGeoVolume* V3Layer::createIBFPCAlAnode(const Double_t xcable, const Double_t zc aluminum->DefineSection(1, sIBFlexCableAlThick / 2); // Then the volumes - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); TGeoVolume* coverlayVol = new TGeoVolume("FPCCoverlayAnode", coverlay, medKapton); coverlayVol->SetLineColor(kBlue); @@ -1145,19 +1146,19 @@ TGeoVolume* V3Layer::createStaveModelInnerB4(const TGeoManager* mgr) // We have all shapes: now create the real volumes - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - TGeoMedium* medM55J6K = mgr->GetMedium("IT4_M55J6K$"); - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medK13D2U2k = mgr->GetMedium("IT4_K13D2U2k$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT4_FGS003$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + TGeoMedium* medM55J6K = mgr->GetMedium("TRK_M55J6K$"); + TGeoMedium* medM60J3K = mgr->GetMedium("TRK_M60J3K$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medK13D2U2k = mgr->GetMedium("TRK_K13D2U2k$"); + TGeoMedium* medFGS003 = mgr->GetMedium("TRK_FGS003$"); + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); const Int_t nameLen = 30; char volname[nameLen]; - snprintf(volname, nameLen, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), mLayerNumber); + snprintf(volname, nameLen, "%s%d_StaveStruct", o2::trk::GeometryTGeo::getITSStavePattern(), mLayerNumber); TGeoVolume* mechStavVol = new TGeoVolume(volname, mechStavSh, medAir); mechStavVol->SetLineColor(12); mechStavVol->SetFillColor(12); @@ -1396,9 +1397,9 @@ void V3Layer::createIBConnectorsASide(const TGeoManager* mgr) Double_t xpos, ypos, zpos; // Gather all material pointers - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); - TGeoMedium* medInox304 = mgr->GetMedium("IT4_INOX304$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); + TGeoMedium* medInox304 = mgr->GetMedium("TRK_INOX304$"); // First create all elements // (All measures refer to the blueprint ALIITSUP0051) @@ -1613,8 +1614,8 @@ void V3Layer::createIBConnectorsCSide(const TGeoManager* mgr) Double_t xpos, ypos, zpos; // Gather all material pointers - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); // First create all elements // (All measures refer to the blueprint ALIITSUP0051) @@ -2032,14 +2033,14 @@ TGeoVolume* V3Layer::createStaveModelOuterB2(const TGeoManager* mgr) // We have all shapes: now create the real volumes - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); - TGeoMedium* medK13D2U120 = mgr->GetMedium("IT4_K13D2U120$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT4_FGS003$"); // amec thermasol - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medTungsten = mgr->GetMedium("IT4_TUNGSTEN$"); + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); + TGeoMedium* medK13D2U120 = mgr->GetMedium("TRK_K13D2U120$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medWater = mgr->GetMedium("TRK_WATER$"); + TGeoMedium* medCarbonFleece = mgr->GetMedium("TRK_CarbonFleece$"); + TGeoMedium* medFGS003 = mgr->GetMedium("TRK_FGS003$"); // amec thermasol + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medTungsten = mgr->GetMedium("TRK_TUNGSTEN$"); TGeoVolume* coldPlateVol = new TGeoVolume("ColdPlateVol", coldPlate, medK13D2U120); coldPlateVol->SetLineColor(kYellow - 3); @@ -2110,7 +2111,7 @@ TGeoVolume* V3Layer::createStaveModelOuterB2(const TGeoManager* mgr) gammaConvRodVol->SetFillStyle(4000); // 0% transparent } - snprintf(volname, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); + snprintf(volname, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); TGeoVolume* halfStaveVol = new TGeoVolume(volname, halfStave, medAir); // halfStaveVol->SetLineColor(12); // halfStaveVol->SetFillColor(12); @@ -2273,9 +2274,9 @@ TGeoVolume* V3Layer::createOBPowerBiasBuses(const Double_t zcable, const TGeoMan TGeoBBox* topBB = new TGeoBBox(xcable, sOBBiasBusAlThick / 2, zcable); // Then the volumes - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medAluminum = mgr->GetMedium("TRK_ALUMINUM$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); TGeoVolume* gndPBVol = new TGeoVolume("PowerBusGround", gndPB, medAluminum); gndPBVol->SetLineColor(kCyan); @@ -2426,9 +2427,9 @@ void V3Layer::createOBColdPlateConnectorsASide() Double_t xpos, ypos, zpos; // Gather all material pointers - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); - TGeoMedium* medInox304 = mgr->GetMedium("IT4_INOX304$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); + TGeoMedium* medInox304 = mgr->GetMedium("TRK_INOX304$"); // First create all elements @@ -2583,8 +2584,8 @@ void V3Layer::createOBColdPlateConnectorsCSide() Double_t xpos, ypos, zpos; // Gather all material pointers - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); // First create all elements @@ -2767,7 +2768,7 @@ TGeoVolume* V3Layer::createSpaceFrameOuterB2(const TGeoManager* mgr) // Updated: 20 Jul 2017 Mario Sitta O2 version // - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); TGeoVolume *unitVol[2], *next2EndVol[2], *endVol[2]; Double_t *xtru, *ytru; @@ -2892,9 +2893,9 @@ void V3Layer::createOBSpaceFrameObjects(const TGeoManager* mgr) // // Materials defined in AliITSUv2 - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); - TGeoMedium* medF6151B05M = mgr->GetMedium("IT4_F6151B05M$"); - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); + TGeoMedium* medF6151B05M = mgr->GetMedium("TRK_F6151B05M$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); // Local parameters Double_t halfFrameWidth = sOBSpaceFrameWidth / 2; @@ -3333,7 +3334,7 @@ void V3Layer::createOBSpaceFrameConnector(TGeoVolume* mother, const Double_t ymo // Created: 09 Sep 2019 M. Sitta // Materials defined in AliITSUv2 - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); // Local parameters TString connName, compoShape; @@ -3489,8 +3490,8 @@ TGeoVolume* V3Layer::createModuleOuterB(const TGeoManager* mgr) } // The chip (the same as for IB) - snprintf(chipName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSChipPattern(), mLayerNumber); - snprintf(sensName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSSensorPattern(), mLayerNumber); + snprintf(chipName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSChipPattern(), mLayerNumber); + snprintf(sensName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSSensorPattern(), mLayerNumber); ylen = 0.5 * sOBChipThickness; @@ -3530,9 +3531,9 @@ TGeoVolume* V3Layer::createModuleOuterB(const TGeoManager* mgr) // We have all shapes: now create the real volumes - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); + TGeoMedium* medAir = mgr->GetMedium("TRK_AIR$"); + TGeoMedium* medGlue = mgr->GetMedium("TRK_GLUE$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); TGeoVolume* glueFPCVol = new TGeoVolume("GlueFPCVol", glueFPC, medGlue); glueFPCVol->SetLineColor(kBlack); @@ -3549,7 +3550,7 @@ TGeoVolume* V3Layer::createModuleOuterB(const TGeoManager* mgr) flexKapVol->SetFillColor(flexKapVol->GetLineColor()); flexKapVol->SetFillStyle(4000); // 0% transparent - snprintf(volName, nameLen, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); + snprintf(volName, nameLen, "%s%d", o2::trk::GeometryTGeo::getITSModulePattern(), mLayerNumber); TGeoVolume* modVol = new TGeoVolume(volName, module, medAir); modVol->SetVisibility(kTRUE); @@ -3629,8 +3630,8 @@ TGeoVolume* V3Layer::createOBFPCCuGnd(const Double_t zcable, const TGeoManager* TGeoBBox* copper = new TGeoBBox(xcable, sOBFPCCopperThick / 2, zcable); // Then the volumes - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medCopper = mgr->GetMedium("IT4_COPPER$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medCopper = mgr->GetMedium("TRK_COPPER$"); TGeoVolume* soldmaskVol = new TGeoVolume("FPCGndSolderMask", soldmask, medKapton); soldmaskVol->SetLineColor(kBlue); @@ -3675,8 +3676,8 @@ TGeoVolume* V3Layer::createOBFPCCuSig(const Double_t zcable, const TGeoManager* TGeoBBox* copper = new TGeoBBox(xcable, sOBFPCCopperThick / 2, zcable); // Then the volumes - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medCopper = mgr->GetMedium("IT4_COPPER$"); + TGeoMedium* medKapton = mgr->GetMedium("TRK_KAPTON(POLYCH2)$"); + TGeoMedium* medCopper = mgr->GetMedium("TRK_COPPER$"); TGeoVolume* soldmaskVol = new TGeoVolume("FPCSigSolderMask", soldmask, medKapton); soldmaskVol->SetLineColor(kBlue); diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Services.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Services.cxx similarity index 98% rename from Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Services.cxx rename to Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Services.cxx index ae775db4f3b96..415815c699dc8 100644 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V3Services.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/V3Services.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,10 +14,10 @@ /// \author Mario Sitta <sitta@to.infn.it> /// \author Parinya Namwongsa <parinya.namwongsa@cern.ch> -#include "ITS4Simulation/V3Services.h" -#include "ITS4Simulation/V11Geometry.h" -#include "ITS4Base/GeometryTGeo.h" -#include "ITS4Simulation/Detector.h" +#include "TRKSimulation/V3Services.h" +#include "TRKSimulation/V11Geometry.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKSimulation/Detector.h" #include "ITSMFTSimulation/AlpideChip.h" #include "FairLogger.h" // for LOG @@ -40,7 +41,7 @@ class TGeoMedium; using namespace TMath; -using namespace o2::its4; +using namespace o2::trk; // Parameters const Double_t V3Services::sIBWheelACZdist = 306.0 * sMm; @@ -494,8 +495,8 @@ void V3Services::ibEndWheelSideA(const Int_t iLay, TGeoVolume* endWheel, const T TGeoCompositeShape* stepASh = new TGeoCompositeShape(Form("stepBoxASh%d:stepBoxATr%d-stepPconASh%d", iLay, iLay, iLay)); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); TGeoVolume* coneABasisVol = new TGeoVolume(Form("ConeABasis%d", iLay), coneABasisSh, medCarbon); coneABasisVol->SetFillColor(kBlue); @@ -536,7 +537,7 @@ void V3Services::ibEndWheelSideA(const Int_t iLay, TGeoVolume* endWheel, const T // The position of the Steps is given wrt the holes (see eg. ALIITSUP0187) dphi = 180. - sConeAStepHolePhi0[iLay]; - Int_t numberOfStaves = o2::its4::GeometryTGeo::Instance()->getNumberOfStaves(iLay); + Int_t numberOfStaves = o2::trk::GeometryTGeo::Instance()->getNumberOfStaves(iLay); zpos = zref + (static_cast<TGeoBBox*>(stepAVol->GetShape()))->GetDZ(); for (Int_t j = 0; j < numberOfStaves; j++) { Double_t phi = dphi + j * sConeAStepHolePhi[iLay]; @@ -724,8 +725,8 @@ void V3Services::ibEndWheelSideC(const Int_t iLay, TGeoVolume* endWheel, const T TGeoCompositeShape* stepCSh = new TGeoCompositeShape(Form("stepBoxCSh%d:stepBoxCTr%d-stepPconCSh%d", iLay, iLay, iLay)); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED - TGeoMedium* medPEEK = mgr->GetMedium("IT4_PEEKCF30$"); + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED + TGeoMedium* medPEEK = mgr->GetMedium("TRK_PEEKCF30$"); TGeoVolume* endWheelCVol = new TGeoVolume(Form("EndWheelCBasis%d", iLay), endWheelCSh, medCarbon); endWheelCVol->SetFillColor(kBlue); @@ -742,7 +743,7 @@ void V3Services::ibEndWheelSideC(const Int_t iLay, TGeoVolume* endWheel, const T // The position of the Steps is given wrt the holes (see eg. ALIITSUP0187) dphi = sEndWCStepHolePhi0[iLay]; - Int_t numberOfStaves = o2::its4::GeometryTGeo::Instance()->getNumberOfStaves(iLay); + Int_t numberOfStaves = o2::trk::GeometryTGeo::Instance()->getNumberOfStaves(iLay); zpos += (static_cast<TGeoBBox*>(stepCVol->GetShape()))->GetDZ(); for (Int_t j = 0; j < numberOfStaves; j++) { Double_t phi = dphi + j * sEndWCStepHolePhi[iLay]; @@ -860,8 +861,8 @@ TGeoVolume* V3Services::ibCyssCylinder(const TGeoManager* mgr) TGeoTubeSeg* cyssInnerCylSh = new TGeoTubeSeg(rmin, rmax, zlen, phimin, phimax); // We have all shapes: now create the real volumes - TGeoMedium* medPrepreg = mgr->GetMedium("IT4_F6151B05M$"); - TGeoMedium* medRohacell = mgr->GetMedium("IT4_ROHACELL$"); + TGeoMedium* medPrepreg = mgr->GetMedium("TRK_F6151B05M$"); + TGeoMedium* medRohacell = mgr->GetMedium("TRK_ROHACELL$"); TGeoVolume* cyssOuterCylVol = new TGeoVolume("IBCYSSCylinder", cyssOuterCylSh, medPrepreg); cyssOuterCylVol->SetLineColor(35); @@ -982,8 +983,8 @@ TGeoVolume* V3Services::ibCyssCone(const TGeoManager* mgr) cyssConeFoamSh->DefineSection(4, zlen1, rmin, rmax); // We have all shapes: now create the real volumes - TGeoMedium* medPrepreg = mgr->GetMedium("IT4_F6151B05M$"); - TGeoMedium* medRohacell = mgr->GetMedium("IT4_ROHACELL$"); + TGeoMedium* medPrepreg = mgr->GetMedium("TRK_F6151B05M$"); + TGeoMedium* medRohacell = mgr->GetMedium("TRK_ROHACELL$"); TGeoVolume* cyssConeVol = new TGeoVolume("IBCYSSCone", cyssConeSh, medPrepreg); cyssConeVol->SetLineColor(35); @@ -1197,7 +1198,7 @@ TGeoVolume* V3Services::ibCyssFlangeSideA(const TGeoManager* mgr) TGeoCompositeShape* cyssFlangeASh = new TGeoCompositeShape(cyssFlangeAComposite.Data()); // We have all shapes: now create the real volumes - TGeoMedium* medAlu = mgr->GetMedium("IT4_ALUMINUM$"); + TGeoMedium* medAlu = mgr->GetMedium("TRK_ALUMINUM$"); TGeoVolume* cyssFlangeAVol = new TGeoVolume("IBCYSSFlangeA", cyssFlangeASh, medAlu); cyssFlangeAVol->SetLineColor(kCyan); @@ -1514,7 +1515,7 @@ TGeoVolume* V3Services::ibCyssFlangeSideC(const TGeoManager* mgr) TGeoCompositeShape* cyssFlangeCSh = new TGeoCompositeShape(cyssFlangeCComposite.Data()); // We have all shapes: now create the real volumes - TGeoMedium* medAlu = mgr->GetMedium("IT4_ALUMINUM$"); + TGeoMedium* medAlu = mgr->GetMedium("TRK_ALUMINUM$"); TGeoVolume* cyssFlangeCVol = new TGeoVolume("IBCYSSFlangeC", cyssFlangeCSh, medAlu); cyssFlangeCVol->SetLineColor(kCyan); @@ -1592,7 +1593,7 @@ void V3Services::obEndWheelSideA(const Int_t iLay, TGeoVolume* mother, const TGe TGeoBBox* shelfSh = new TGeoBBox(xlen / 2, ylen / 2, zlen / 2); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED Int_t nLay = iLay + sNumberInnerLayers; @@ -1636,7 +1637,7 @@ void V3Services::obEndWheelSideA(const Int_t iLay, TGeoVolume* mother, const TGe mother->AddNode(ringInnerVol, 1, new TGeoTranslation(0, 0, zpos)); // Then the support blocks - Int_t numberOfStaves = o2::its4::GeometryTGeo::Instance()->getNumberOfStaves(nLay); + Int_t numberOfStaves = o2::trk::GeometryTGeo::Instance()->getNumberOfStaves(nLay); Double_t alpha = 360. / numberOfStaves; rmin = sOBWheelShelfRpos[iLay] + shelfSh->GetDY(); @@ -1756,7 +1757,7 @@ void V3Services::mbEndWheelSideC(const Int_t iLay, TGeoVolume* mother, const TGe TGeoBBox* shelfSh = new TGeoBBox(xlen / 2, ylen / 2, zlen / 2); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED Int_t nLay = iLay + sNumberInnerLayers; @@ -1798,7 +1799,7 @@ void V3Services::mbEndWheelSideC(const Int_t iLay, TGeoVolume* mother, const TGe mother->AddNode(ringOuterVol, 1, new TGeoTranslation(0, 0, -zpos)); // Then the support blocks - Int_t numberOfStaves = o2::its4::GeometryTGeo::Instance()->getNumberOfStaves(nLay); + Int_t numberOfStaves = o2::trk::GeometryTGeo::Instance()->getNumberOfStaves(nLay); Double_t alpha = 360. / numberOfStaves; rmin = sOBWheelShelfRpos[iLay] + shelfSh->GetDY(); @@ -1923,7 +1924,7 @@ void V3Services::obEndWheelSideC(const Int_t iLay, TGeoVolume* mother, const TGe } // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED Int_t nLay = iLay + sNumberInnerLayers + sNumberMiddlLayers; @@ -2063,7 +2064,7 @@ void V3Services::obConeSideA(TGeoVolume* mother, const TGeoManager* mgr) obConeRibSh->DefineSection(1, sOBConeAThickAll); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED TGeoVolume* obConeVol = new TGeoVolume("OBConeSideA", obConeSh, medCarbon); obConeVol->SetFillColor(kBlue); @@ -2161,7 +2162,7 @@ void V3Services::obConeTraysSideA(TGeoVolume* mother, const TGeoManager* mgr) } // for (j = 0,1) // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED TGeoVolume *obTrayVol[2], *obTrayRibVol[2]; @@ -2315,7 +2316,7 @@ void V3Services::obConeSideC(TGeoVolume* mother, const TGeoManager* mgr) obConeRibSh->DefineSection(1, sOBConeCThickAll); // We have all shapes: now create the real volumes - TGeoMedium* medCarbon = mgr->GetMedium("IT4_M55J6K$"); // TO BE CHECKED + TGeoMedium* medCarbon = mgr->GetMedium("TRK_M55J6K$"); // TO BE CHECKED TGeoVolume* obConeVol = new TGeoVolume("OBConeSideC", obConeSh, medCarbon); obConeVol->SetFillColor(kBlue); diff --git a/Detectors/Upgrades/CMakeLists.txt b/Detectors/Upgrades/CMakeLists.txt index dd42de06dfdbf..291c1bc465329 100644 --- a/Detectors/Upgrades/CMakeLists.txt +++ b/Detectors/Upgrades/CMakeLists.txt @@ -1,13 +1,14 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. message(STATUS "Building detectors for upgrades") add_subdirectory(IT3) -add_subdirectory(PostLS4) \ No newline at end of file +add_subdirectory(ALICE3) \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/CMakeLists.txt b/Detectors/Upgrades/IT3/CMakeLists.txt index 4d58e2495d96f..55190f923bc94 100644 --- a/Detectors/Upgrades/IT3/CMakeLists.txt +++ b/Detectors/Upgrades/IT3/CMakeLists.txt @@ -1,13 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(simulation) add_subdirectory(base) -add_subdirectory(macros) \ No newline at end of file +add_subdirectory(macros) +add_subdirectory(workflow) +add_subdirectory(reconstruction) diff --git a/Detectors/Upgrades/IT3/README.md b/Detectors/Upgrades/IT3/README.md index 3d57a976c41fa..f8643db684fb6 100644 --- a/Detectors/Upgrades/IT3/README.md +++ b/Detectors/Upgrades/IT3/README.md @@ -1,3 +1,7 @@ +<!-- doxy +\page refDetectorsUpgradesIT3 UpgradesIT3 +/doxy --> + # IT3 Upgraded version of the ITS that includes upgraded truly-cylindrical inner barrel. @@ -14,4 +18,4 @@ o2-sim -m PIPE IT3 [...] ``` ## Reconstruction -Currently, the reconstruction is driven the `macro/run_trac_alice3.C`, which takes as input the hits generated by simulation. Hits can be smeared upon request (see `kUseSmearing`). \ No newline at end of file +Currently, the reconstruction is driven the `Detectors/Upgrades/ALICE3/TRK/macros/ALICE3toAO2D.C`, which takes as input the hits generated by simulation. Hits can be smeared upon request (see `kUseSmearing`). \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/base/CMakeLists.txt b/Detectors/Upgrades/IT3/base/CMakeLists.txt index 0dbe04da6d54b..8edcba1549c03 100644 --- a/Detectors/Upgrades/IT3/base/CMakeLists.txt +++ b/Detectors/Upgrades/IT3/base/CMakeLists.txt @@ -1,18 +1,21 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITS3Base SOURCES src/MisalignmentParameter.cxx src/GeometryTGeo.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase) + src/SegmentationSuperAlpide.cxx + PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::MathUtils O2::DetectorsBase O2::ITSMFTBase) o2_target_root_dictionary(ITS3Base - HEADERS include/ITS3Base/GeometryTGeo.h + HEADERS include/ITS3Base/SegmentationSuperAlpide.h + include/ITS3Base/GeometryTGeo.h include/ITS3Base/MisalignmentParameter.h) diff --git a/Detectors/Upgrades/IT3/base/include/ITS3Base/GeometryTGeo.h b/Detectors/Upgrades/IT3/base/include/ITS3Base/GeometryTGeo.h index 2857cf19c86f4..02366ba4f3ff4 100644 --- a/Detectors/Upgrades/IT3/base/include/ITS3Base/GeometryTGeo.h +++ b/Detectors/Upgrades/IT3/base/include/ITS3Base/GeometryTGeo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Upgrades/IT3/base/include/ITS3Base/MisalignmentParameter.h b/Detectors/Upgrades/IT3/base/include/ITS3Base/MisalignmentParameter.h index df44e3a517a5e..b0f572ca5891a 100644 --- a/Detectors/Upgrades/IT3/base/include/ITS3Base/MisalignmentParameter.h +++ b/Detectors/Upgrades/IT3/base/include/ITS3Base/MisalignmentParameter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Upgrades/IT3/base/include/ITS3Base/SegmentationSuperAlpide.h b/Detectors/Upgrades/IT3/base/include/ITS3Base/SegmentationSuperAlpide.h new file mode 100644 index 0000000000000..f8f557193c291 --- /dev/null +++ b/Detectors/Upgrades/IT3/base/include/ITS3Base/SegmentationSuperAlpide.h @@ -0,0 +1,183 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SegmentationSuperAlpide.h +/// \brief Definition of the SegmentationSuperAlpide class + +#ifndef ALICEO2_ITS3_SEGMENTATIONSUPERALPIDE_H_ +#define ALICEO2_ITS3_SEGMENTATIONSUPERALPIDE_H_ + +#include <Rtypes.h> +#include "MathUtils/Cartesian.h" +#include "CommonConstants/MathConstants.h" +#include "ITSMFTBase/SegmentationAlpide.h" + +namespace o2 +{ +namespace its3 +{ + +/// Segmentation and response for pixels in ITSMFT upgrade +class SegmentationSuperAlpide +{ + public: + SegmentationSuperAlpide(int layer = 0) : mLayer{layer}, + NRows{static_cast<int>(double(Radii[layer]) * double(constants::math::TwoPI) / double(itsmft::SegmentationAlpide::PitchRow) + 1)}, + NPixels{NRows * NCols}, + PitchRow{static_cast<float>(Radii[layer] * constants::math::TwoPI / NRows)}, + ActiveMatrixSizeRows{PitchRow * NRows}, + SensorSizeRows{ActiveMatrixSizeRows + PassiveEdgeTop + PassiveEdgeReadOut} + { + } + int mLayer; + static constexpr int NLayers = 4; + static constexpr float Length = 27.15f; + static constexpr float Radii[NLayers] = {1.8f, 2.4f, 3.0f, 7.0f}; + static constexpr int NCols = Length / itsmft::SegmentationAlpide::PitchCol; + int NRows; + int NPixels; + static constexpr float PitchCol = Length / NCols; + float PitchRow; + static constexpr float PassiveEdgeReadOut = 0.; // width of the readout edge (Passive bottom) + static constexpr float PassiveEdgeTop = 0.; // Passive area on top + static constexpr float PassiveEdgeSide = 0.; // width of Passive area on left/right of the sensor + static constexpr float ActiveMatrixSizeCols = PitchCol * NCols; // Active size along columns + float ActiveMatrixSizeRows; // Active size along rows + + // effective thickness of sensitive layer, accounting for charge collection non-unifoemity, https://alice.its.cern.ch/jira/browse/AOC-46 + static constexpr float SensorLayerThicknessEff = 28.e-4; + static constexpr float SensorLayerThickness = 30.e-4; // physical thickness of sensitive part + static constexpr float SensorSizeCols = ActiveMatrixSizeCols + PassiveEdgeSide + PassiveEdgeSide; // SensorSize along columns + float SensorSizeRows; // SensorSize along rows + + ~SegmentationSuperAlpide() = default; + + /// Transformation from Geant detector centered local coordinates (cm) to + /// Pixel cell numbers iRow and iCol. + /// Returns kTRUE if point x,z is inside sensitive volume, kFALSE otherwise. + /// A value of -1 for iRow or iCol indicates that this point is outside of the + /// detector segmentation as defined. + /// \param float x Detector local coordinate x in cm with respect to + /// the center of the sensitive volume. + /// \param float z Detector local coordinate z in cm with respect to + /// the center of the sensitive volulme. + /// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows + /// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns + bool localToDetector(float x, float z, int& iRow, int& iCol); + /// same but w/o check for row/column range + void localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol); + + /// Transformation from Detector cell coordiantes to Geant detector centered + /// local coordinates (cm) + /// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows + /// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns + /// \param float x Detector local coordinate x in cm with respect to the + /// center of the sensitive volume. + /// \param float z Detector local coordinate z in cm with respect to the + /// center of the sensitive volulme. + /// If iRow and or iCol is outside of the segmentation range a value of -0.5*Dx() + /// or -0.5*Dz() is returned. + bool detectorToLocal(int iRow, int iCol, float& xRow, float& zCol); + bool detectorToLocal(float row, float col, float& xRow, float& zCol); + bool detectorToLocal(float row, float col, math_utils::Point3D<float>& loc); + + // same but w/o check for row/col range + void detectorToLocalUnchecked(int iRow, int iCol, float& xRow, float& zCol); + void detectorToLocalUnchecked(float row, float col, float& xRow, float& zCol); + void detectorToLocalUnchecked(float row, float col, math_utils::Point3D<float>& loc); + + float getFirstRowCoordinate() + { + return 0.5 * ((ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - PitchRow); + } + static constexpr float getFirstColCoordinate() { return 0.5 * (PitchCol - ActiveMatrixSizeCols); } + + void print(); + + ClassDefNV(SegmentationSuperAlpide, 1); // Segmentation class upgrade pixels +}; + +inline void SegmentationSuperAlpide::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol) +{ + // convert to row/col w/o over/underflow check + xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix + zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix + iRow = int(xRow / PitchRow); + iCol = int(zCol / PitchCol); + if (xRow < 0) { + iRow -= 1; + } + if (zCol < 0) { + iCol -= 1; + } +} + +inline bool SegmentationSuperAlpide::localToDetector(float xRow, float zCol, int& iRow, int& iCol) +{ + // convert to row/col + xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt left edge of Active matrix + zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt bottom edge of Active matrix + if (xRow < 0 || xRow >= ActiveMatrixSizeRows || zCol < 0 || zCol >= ActiveMatrixSizeCols) { + iRow = iCol = -1; + return false; + } + iRow = int(xRow / PitchRow); + iCol = int(zCol / PitchCol); + return true; +} + +inline void SegmentationSuperAlpide::detectorToLocalUnchecked(int iRow, int iCol, float& xRow, float& zCol) +{ + xRow = getFirstRowCoordinate() - iRow * PitchRow; + zCol = iCol * PitchCol + getFirstColCoordinate(); +} + +inline void SegmentationSuperAlpide::detectorToLocalUnchecked(float row, float col, float& xRow, float& zCol) +{ + xRow = getFirstRowCoordinate() - row * PitchRow; + zCol = col * PitchCol + getFirstColCoordinate(); +} + +inline void SegmentationSuperAlpide::detectorToLocalUnchecked(float row, float col, math_utils::Point3D<float>& loc) +{ + loc.SetCoordinates(getFirstRowCoordinate() - row * PitchRow, 0.f, col * PitchCol + getFirstColCoordinate()); +} + +inline bool SegmentationSuperAlpide::detectorToLocal(int iRow, int iCol, float& xRow, float& zCol) +{ + if (iRow < 0 || iRow >= NRows || iCol < 0 || iCol >= NCols) { + return false; + } + detectorToLocalUnchecked(iRow, iCol, xRow, zCol); + return true; +} + +inline bool SegmentationSuperAlpide::detectorToLocal(float row, float col, float& xRow, float& zCol) +{ + if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + return false; + } + detectorToLocalUnchecked(row, col, xRow, zCol); + return true; +} + +inline bool SegmentationSuperAlpide::detectorToLocal(float row, float col, math_utils::Point3D<float>& loc) +{ + if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + return false; + } + detectorToLocalUnchecked(row, col, loc); + return true; +} +} // namespace its3 +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/IT3/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/IT3/base/src/GeometryTGeo.cxx index 210e677910de5..cc349fea8c44a 100644 --- a/Detectors/Upgrades/IT3/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/IT3/base/src/GeometryTGeo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "ITS3Base/GeometryTGeo.h" #include "DetectorsBase/GeometryManager.h" #include "ITSMFTBase/SegmentationAlpide.h" +#include "ITS3Base/SegmentationSuperAlpide.h" #include "MathUtils/Cartesian.h" #include "FairLogger.h" // for LOG @@ -279,45 +281,46 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const // // Therefore we need to add a shift - int lay, stav, sstav, mod, chipInMod; - getChipId(index, lay, stav, sstav, mod, chipInMod); - - int wrID = mLayerToWrapper[lay]; - - TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getITSVolPattern()); + static TGeoHMatrix matTmp; + if (index >= SegmentationSuperAlpide::NLayers) { + int lay, stav, sstav, mod, chipInMod; + getChipId(index, lay, stav, sstav, mod, chipInMod); - if (wrID >= 0) { - path += Form("%s%d_1/", getITSWrapVolPattern(), wrID); - } + int wrID = mLayerToWrapper[lay]; - path += - Form("%s%d_1/%s%d_%d/", GeometryTGeo::getITSLayerPattern(), lay, GeometryTGeo::getITSStavePattern(), lay, stav); + TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getITSVolPattern()); - if (mNumberOfHalfStaves[lay] > 0) { - path += Form("%s%d_%d/", GeometryTGeo::getITSHalfStavePattern(), lay, sstav); - } - if (mNumberOfModules[lay] > 0) { - path += Form("%s%d_%d/", GeometryTGeo::getITSModulePattern(), lay, mod); - } - path += - Form("%s%d_%d/%s%d_1", GeometryTGeo::getITSChipPattern(), lay, chipInMod, GeometryTGeo::getITSSensorPattern(), lay); + if (wrID >= 0) { + path += Form("%s%d_1/", getITSWrapVolPattern(), wrID); + } - static TGeoHMatrix matTmp; - gGeoManager->PushPath(); + path += + Form("%s%d_1/%s%d_%d/", GeometryTGeo::getITSLayerPattern(), lay, GeometryTGeo::getITSStavePattern(), lay, stav); - if (!gGeoManager->cd(path.Data())) { + if (mNumberOfHalfStaves[lay] > 0) { + path += Form("%s%d_%d/", GeometryTGeo::getITSHalfStavePattern(), lay, sstav); + } + if (mNumberOfModules[lay] > 0) { + path += Form("%s%d_%d/", GeometryTGeo::getITSModulePattern(), lay, mod); + } + path += + Form("%s%d_%d/%s%d_1", GeometryTGeo::getITSChipPattern(), lay, chipInMod, GeometryTGeo::getITSSensorPattern(), lay); + + gGeoManager->PushPath(); + + if (!gGeoManager->cd(path.Data())) { + gGeoManager->PopPath(); + LOG(ERROR) << "Error in cd-ing to " << path.Data(); + return nullptr; + } // end if !gGeoManager + + matTmp = *gGeoManager->GetCurrentMatrix(); // matrix may change after cd + // RSS + // printf("%d/%d/%d %s\n",lay,stav,detInSta,path.Data()); + // mat->Print(); + // Restore the modeler state. gGeoManager->PopPath(); - LOG(ERROR) << "Error in cd-ing to " << path.Data(); - return nullptr; - } // end if !gGeoManager - - matTmp = *gGeoManager->GetCurrentMatrix(); // matrix may change after cd - // RSS - // printf("%d/%d/%d %s\n",lay,stav,detInSta,path.Data()); - // mat->Print(); - // Restore the modeler state. - gGeoManager->PopPath(); - + } // account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor ticknesses static TGeoTranslation tra(0., 0.5 * (Segmentation::SensorLayerThickness - Segmentation::SensorLayerThicknessEff), 0.); @@ -699,6 +702,12 @@ void GeometryTGeo::extractSensorXAlpha(int isn, float& x, float& alp) { // calculate r and phi of the impact of the normal on the sensor // (i.e. phi of the tracking frame alpha and X of the sensor in this frame) + if (isn < SegmentationSuperAlpide::NLayers) { + x = SegmentationSuperAlpide::Radii[isn]; + alp = 0.f; + return; + } + double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; const TGeoHMatrix* matL2G = extractMatrixSensor(isn); diff --git a/Detectors/Upgrades/IT3/base/src/ITS3BaseLinkDef.h b/Detectors/Upgrades/IT3/base/src/ITS3BaseLinkDef.h index 7454001429112..8b7b225f3749c 100644 --- a/Detectors/Upgrades/IT3/base/src/ITS3BaseLinkDef.h +++ b/Detectors/Upgrades/IT3/base/src/ITS3BaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,12 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::its3::SegmentationSuperAlpide + ; + + #pragma link C++ class o2::its3::GeometryTGeo; #pragma link C++ class o2::its3::MisalignmentParameter + ; + + #endif diff --git a/Detectors/Upgrades/IT3/base/src/MisalignmentParameter.cxx b/Detectors/Upgrades/IT3/base/src/MisalignmentParameter.cxx index 8562ea757e36c..8b86523a69fce 100644 --- a/Detectors/Upgrades/IT3/base/src/MisalignmentParameter.cxx +++ b/Detectors/Upgrades/IT3/base/src/MisalignmentParameter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Upgrades/IT3/base/src/SegmentationSuperAlpide.cxx b/Detectors/Upgrades/IT3/base/src/SegmentationSuperAlpide.cxx new file mode 100644 index 0000000000000..10ce7f9a98fb4 --- /dev/null +++ b/Detectors/Upgrades/IT3/base/src/SegmentationSuperAlpide.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SegmentationSuperAlpide.cxx +/// \brief Implementation of the SegmentationSuperAlpide class + +#include "ITS3Base/SegmentationSuperAlpide.h" +#include <cstdio> + +ClassImp(o2::its3::SegmentationSuperAlpide); + +using namespace o2::its3; + +void SegmentationSuperAlpide::print() +{ + printf("ITS3 segmentation for layer: %d \n", mLayer); + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", PitchRow * 1e4, NRows, PitchCol * 1e4, NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", + PassiveEdgeReadOut * 1e4, PassiveEdgeTop * 1e4, PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", ActiveMatrixSizeRows, SensorSizeRows, + ActiveMatrixSizeCols, SensorSizeCols); +} diff --git a/Detectors/Upgrades/IT3/macros/CMakeLists.txt b/Detectors/Upgrades/IT3/macros/CMakeLists.txt index e2058e7d098e1..7904ec5695801 100644 --- a/Detectors/Upgrades/IT3/macros/CMakeLists.txt +++ b/Detectors/Upgrades/IT3/macros/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(test) \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/macros/test/CMakeLists.txt b/Detectors/Upgrades/IT3/macros/test/CMakeLists.txt index 10bb6dd71f256..bf89e984fa0e9 100644 --- a/Detectors/Upgrades/IT3/macros/test/CMakeLists.txt +++ b/Detectors/Upgrades/IT3/macros/test/CMakeLists.txt @@ -1,9 +1,33 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. \ No newline at end of file +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro(CheckDigitsITS3.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) + +o2_add_test_root_macro(CheckClustersITS3.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::ITS3Reconstruction + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/macros/test/CheckClustersITS3.C b/Detectors/Upgrades/IT3/macros/test/CheckClustersITS3.C new file mode 100644 index 0000000000000..69bbac7bdce24 --- /dev/null +++ b/Detectors/Upgrades/IT3/macros/test/CheckClustersITS3.C @@ -0,0 +1,253 @@ +/// \file CheckClusters.C +/// \brief Simple macro to check ITSU clusters + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#define ENABLE_UPGRADES +#include <TCanvas.h> +#include <TFile.h> +#include <TH2F.h> +#include <TNtuple.h> +#include <TString.h> +#include <TTree.h> + +#include "DetectorsCommonDataFormats/DetID.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "ITSBase/GeometryTGeo.h" +#include "DataFormatsITS3/CompCluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "ITS3Reconstruction/TopologyDictionary.h" +#include "ITSMFTSimulation/Hit.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "MathUtils/Cartesian.h" +#include "MathUtils/Utils.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#endif + +void CheckClustersITS3(std::string clusfile = "o2clus_it3.root", std::string hitfile = "o2sim_HitsIT3.root", + std::string inputGeom = "", std::string dictfile = "") +{ + const int QEDSourceID = 99; // Clusters from this MC source correspond to QED electrons + + using namespace o2::base; + using namespace o2::its; + + using o2::its3::SegmentationSuperAlpide; + using Segmentation = o2::itsmft::SegmentationAlpide; + using o2::its3::CompClusterExt; + using o2::itsmft::Hit; + using ROFRec = o2::itsmft::ROFRecord; + using MC2ROF = o2::itsmft::MC2ROFRecord; + using HitVec = std::vector<Hit>; + using MC2HITS_map = std::unordered_map<uint64_t, int>; // maps (track_ID<<16 + chip_ID) to entry in the hit vector + + std::vector<HitVec*> hitVecPool; + std::vector<MC2HITS_map> mc2hitVec; + + TFile fout("CheckClusters.root", "recreate"); + TNtuple nt("ntc", "cluster ntuple", "ev:lab:hlx:hlz:tx:tz:cgx:cgy:cgz:dx:dy:dz:ex:ez:patid:rof:npx:id"); + + // Geometry + o2::base::GeometryManager::loadGeometry(inputGeom); + auto gman = o2::its::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::L2G)); // request cached transforms + + // Hits + TFile fileH(hitfile.data()); + TTree* hitTree = (TTree*)fileH.Get("o2sim"); + std::vector<o2::itsmft::Hit>* hitArray = nullptr; + hitTree->SetBranchAddress("IT3Hit", &hitArray); + mc2hitVec.resize(hitTree->GetEntries()); + hitVecPool.resize(hitTree->GetEntries(), nullptr); + + // Clusters + TFile fileC(clusfile.data()); + TTree* clusTree = (TTree*)fileC.Get("o2sim"); + std::vector<CompClusterExt>* clusArr = nullptr; + clusTree->SetBranchAddress("IT3ClusterComp", &clusArr); + std::vector<unsigned char>* patternsPtr = nullptr; + auto pattBranch = clusTree->GetBranch("IT3ClusterPatt"); + if (pattBranch) { + pattBranch->SetAddress(&patternsPtr); + } + if (dictfile.empty()) { + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::IT3, "", ".bin"); + } + o2::itsmft::TopologyDictionary dict2; + std::ifstream file(dictfile.c_str()); + if (file.good()) { + LOG(INFO) << "Running with dictionary: " << dictfile.c_str(); + dict2.readBinaryFile(dictfile); + } else { + LOG(INFO) << "Running without dictionary !"; + } + o2::its3::TopologyDictionary dict = dict2; + + // ROFrecords + std::vector<ROFRec> rofRecVec, *rofRecVecP = &rofRecVec; + clusTree->SetBranchAddress("IT3ClustersROF", &rofRecVecP); + + // Cluster MC labels + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* clusLabArr = nullptr; + std::vector<MC2ROF> mc2rofVec, *mc2rofVecP = &mc2rofVec; + if (hitTree && clusTree->GetBranch("IT3ClusterMCTruth")) { + clusTree->SetBranchAddress("IT3ClusterMCTruth", &clusLabArr); + clusTree->SetBranchAddress("IT3ClustersMC2ROF", &mc2rofVecP); + } + + clusTree->GetEntry(0); + int nROFRec = (int)rofRecVec.size(); + std::vector<int> mcEvMin(nROFRec, hitTree->GetEntries()); + std::vector<int> mcEvMax(nROFRec, -1); + + // >> build min and max MC events used by each ROF + for (int imc = mc2rofVec.size(); imc--;) { + const auto& mc2rof = mc2rofVec[imc]; + printf("MCRecord: "); + mc2rof.print(); + if (mc2rof.rofRecordID < 0) { + continue; // this MC event did not contribute to any ROF + } + for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { + int irof = mc2rof.rofRecordID + irfd; + if (irof >= nROFRec) { + LOG(ERROR) << "ROF=" << irof << " from MC2ROF record is >= N ROFs=" << nROFRec; + } + if (mcEvMin[irof] > imc) { + mcEvMin[irof] = imc; + } + if (mcEvMax[irof] < imc) { + mcEvMax[irof] = imc; + } + } + } + + // << build min and max MC events used by each ROF + auto pattIt = patternsPtr->cbegin(); + for (int irof = 0; irof < nROFRec; irof++) { + const auto& rofRec = rofRecVec[irof]; + + rofRec.print(); + + // >> read and map MC events contributing to this ROF + for (int im = mcEvMin[irof]; im <= mcEvMax[irof]; im++) { + if (!hitVecPool[im]) { + hitTree->SetBranchAddress("IT3Hit", &hitVecPool[im]); + hitTree->GetEntry(im); + auto& mc2hit = mc2hitVec[im]; + const auto* hitArray = hitVecPool[im]; + for (int ih = hitArray->size(); ih--;) { + const auto& hit = (*hitArray)[ih]; + uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); + mc2hit.emplace(key, ih); + } + } + } + // << cache MC events contributing to this ROF + for (int icl = 0; icl < rofRec.getNEntries(); icl++) { + int clEntry = rofRec.getFirstEntry() + icl; // entry of icl-th cluster of this ROF in the vector of clusters + + const auto& cluster = (*clusArr)[clEntry]; + + float errX{0.f}; + float errZ{0.f}; + int npix = 0; + auto pattID = cluster.getPatternID(); + o2::math_utils::Point3D<float> locC; + auto chipID = cluster.getSensorID(); + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || dict.isGroup(pattID)) { + o2::itsmft::ClusterPattern patt(pattIt); + locC = dict.getClusterCoordinates(chipID, cluster, patt, false); + } else { + locC = dict.getClusterCoordinates(chipID, cluster); + errX = dict.getErrX(pattID); + errZ = dict.getErrZ(pattID); + npix = dict.getNpixels(pattID); + } + // Transformation to the local --> global + auto gloC = gman->getMatrixL2G(chipID) * locC; + if (chipID < o2::its3::SegmentationSuperAlpide::NLayers) { + double radius = SegmentationSuperAlpide::Radii[chipID]; + double phi = locC.X() / radius; + gloC.SetXYZ(radius * std::cos(phi), radius * std::sin(phi), locC.Z()); + } + + const auto& lab = (clusLabArr->getLabels(clEntry))[0]; + + if (!lab.isValid() || lab.getSourceID() == QEDSourceID) + continue; + + // get MC info + int trID = lab.getTrackID(); + const auto& mc2hit = mc2hitVec[lab.getEventID()]; + const auto* hitArray = hitVecPool[lab.getEventID()]; + uint64_t key = (uint64_t(trID) << 32) + chipID; + auto hitEntry = mc2hit.find(key); + if (hitEntry == mc2hit.end()) { + LOG(ERROR) << "Failed to find MC hit entry for Tr" << trID << " chipID" << chipID; + continue; + } + const auto& hit = (*hitArray)[hitEntry->second]; + // + float dx = 0, dz = 0; + int ievH = lab.getEventID(); + o2::math_utils::Point3D<float> locH, locHsta; + + // mean local position of the hit + locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local + locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); + + if (chipID < 4) { + float startPhi{std::atan2(-hit.GetPosStart().Y(), -hit.GetPosStart().X())}; + float endPhi{std::atan2(-hit.GetPos().Y(), -hit.GetPos().X())}; + locH.SetXYZ(SegmentationSuperAlpide::Radii[chipID] * endPhi, 0.f, hit.GetPos().Z()); + locHsta.SetXYZ(SegmentationSuperAlpide::Radii[chipID] * startPhi, 0.f, hit.GetPosStart().Z()); + } + + auto x0 = locHsta.X(), dltx = locH.X() - x0; + auto y0 = locHsta.Y(), dlty = locH.Y() - y0; + auto z0 = locHsta.Z(), dltz = locH.Z() - z0; + auto r = (0.5 * (Segmentation::SensorLayerThickness - Segmentation::SensorLayerThicknessEff) - y0) / dlty; + locH.SetXYZ(x0 + r * dltx, y0 + r * dlty, z0 + r * dltz); + //locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); + std::array<float, 18> data = {(float)lab.getEventID(), (float)trID, + locH.X(), locH.Z(), dltx / dlty, dltz / dlty, + gloC.X(), gloC.Y(), gloC.Z(), + locC.X() - locH.X(), locC.Y() - locH.Y(), locC.Z() - locH.Z(), + errX, errZ, (float)pattID, + (float)rofRec.getROFrame(), (float)npix, (float)chipID}; + nt.Fill(data.data()); + } + } + + new TCanvas; + nt.Draw("cgy:cgx"); + new TCanvas; + nt.Draw("dz:dx", "abs(dz)<0.01 && abs(dx)<0.01"); + new TCanvas; + nt.Draw("dz:tz", "abs(dz)<0.005 && abs(tz)<2"); + + auto c1 = new TCanvas("p1", "pullX"); + c1->cd(); + c1->SetLogy(); + nt.Draw("dx/ex", "abs(dx/ex)<10&&patid<10"); + auto c2 = new TCanvas("p2", "pullZ"); + c2->cd(); + c2->SetLogy(); + nt.Draw("dz/ez", "abs(dz/ez)<10&&patid<10"); + + auto d1 = new TCanvas("d1", "deltaX"); + d1->cd(); + d1->SetLogy(); + nt.Draw("dx", "abs(dx)<5"); + auto d2 = new TCanvas("d2", "deltaZ"); + d2->cd(); + d2->SetLogy(); + nt.Draw("dz", "abs(dz)<5"); + + fout.cd(); + nt.Write(); +} diff --git a/Detectors/Upgrades/IT3/macros/test/CheckDigitsITS3.C b/Detectors/Upgrades/IT3/macros/test/CheckDigitsITS3.C new file mode 100644 index 0000000000000..d9253ce958bca --- /dev/null +++ b/Detectors/Upgrades/IT3/macros/test/CheckDigitsITS3.C @@ -0,0 +1,235 @@ +/// \file CheckDigitsITS3.C +/// \brief Simple macro to check ITS3 digits + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#define ENABLE_UPGRADES +#include <TCanvas.h> +#include <TFile.h> +#include <TH2F.h> +#include <TNtuple.h> +#include <TString.h> +#include <TTree.h> + +#include <vector> +#include "ITS3Base/GeometryTGeo.h" +#include "DataFormatsITSMFT/Digit.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITSMFTSimulation/Hit.h" +#include "MathUtils/Utils.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DetectorsBase/GeometryManager.h" + +#include "DataFormatsITSMFT/ROFRecord.h" + +#endif + +void CheckDigitsITS3(std::string digifile = "it3digits.root", std::string hitfile = "o2sim_HitsIT3.root", std::string inputGeom = "", std::string paramfile = "o2sim_par.root") +{ + + using namespace o2::base; + + using o2::itsmft::Digit; + using o2::itsmft::Hit; + + using o2::its3::SegmentationSuperAlpide; + using o2::itsmft::SegmentationAlpide; + + TFile* f = TFile::Open("CheckDigits.root", "recreate"); + + TNtuple* nt = new TNtuple("ntd", "digit ntuple", "id:x:y:z:rowD:colD:rowH:colH:xlH:zlH:xlcH:zlcH:dx:dz"); + + // Geometry + o2::base::GeometryManager::loadGeometry(inputGeom); + auto* gman = o2::its3::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); + + SegmentationSuperAlpide segs[4]{SegmentationSuperAlpide(0), SegmentationSuperAlpide(1), SegmentationSuperAlpide(2), SegmentationSuperAlpide(3)}; + SegmentationSuperAlpide& seg = segs[0]; + + // Hits + TFile* hitFile = TFile::Open(hitfile.data()); + TTree* hitTree = (TTree*)hitFile->Get("o2sim"); + int nevH = hitTree->GetEntries(); // hits are stored as one event per entry + std::vector<std::vector<o2::itsmft::Hit>*> hitArray(nevH, nullptr); + + std::vector<std::unordered_map<uint64_t, int>> mc2hitVec(nevH); + + // Digits + TFile* digFile = TFile::Open(digifile.data()); + TTree* digTree = (TTree*)digFile->Get("o2sim"); + + std::vector<o2::itsmft::Digit>* digArr = nullptr; + digTree->SetBranchAddress("IT3Digit", &digArr); + + o2::dataformats::IOMCTruthContainerView* plabels = nullptr; + digTree->SetBranchAddress("IT3DigitMCTruth", &plabels); + + int nevD = digTree->GetEntries(); // digits in cont. readout may be grouped as few events per entry + + int lastReadHitEv = -1; + + int nDigitRead = 0, nDigitFilled = 0; + + // Get Read Out Frame arrays + std::vector<o2::itsmft::ROFRecord>* ROFRecordArrray = nullptr; + digTree->SetBranchAddress("IT3DigitROF", &ROFRecordArrray); + std::vector<o2::itsmft::ROFRecord>& ROFRecordArrrayRef = *ROFRecordArrray; + + std::vector<o2::itsmft::MC2ROFRecord>* MC2ROFRecordArrray = nullptr; + digTree->SetBranchAddress("IT3DigitMC2ROF", &MC2ROFRecordArrray); + std::vector<o2::itsmft::MC2ROFRecord>& MC2ROFRecordArrrayRef = *MC2ROFRecordArrray; + + digTree->GetEntry(0); + + int nROFRec = (int)ROFRecordArrrayRef.size(); + std::vector<int> mcEvMin(nROFRec, hitTree->GetEntries()); + std::vector<int> mcEvMax(nROFRec, -1); + o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel> labels; + plabels->copyandflatten(labels); + delete plabels; + + // >> build min and max MC events used by each ROF + for (int imc = MC2ROFRecordArrrayRef.size(); imc--;) { + const auto& mc2rof = MC2ROFRecordArrrayRef[imc]; + printf("MCRecord: "); + mc2rof.print(); + + if (mc2rof.rofRecordID < 0) { + continue; // this MC event did not contribute to any ROF + } + + for (int irfd = mc2rof.maxROF - mc2rof.minROF + 1; irfd--;) { + + int irof = mc2rof.rofRecordID + irfd; + + if (irof >= nROFRec) { + LOG(ERROR) << "ROF=" << irof << " from MC2ROF record is >= N ROFs=" << nROFRec; + } + if (mcEvMin[irof] > imc) { + mcEvMin[irof] = imc; + } + if (mcEvMax[irof] < imc) { + mcEvMax[irof] = imc; + } + } + } // << build min and max MC events used by each ROF + + unsigned int rofIndex = 0; + unsigned int rofNEntries = 0; + + // LOOP on : ROFRecord array + for (unsigned int iROF = 0; iROF < ROFRecordArrrayRef.size(); iROF++) { + + rofIndex = ROFRecordArrrayRef[iROF].getFirstEntry(); + rofNEntries = ROFRecordArrrayRef[iROF].getNEntries(); + + // >> read and map MC events contributing to this ROF + for (int im = mcEvMin[iROF]; im <= mcEvMax[iROF]; im++) { + + if (!hitArray[im]) { + + hitTree->SetBranchAddress("IT3Hit", &hitArray[im]); + hitTree->GetEntry(im); + + auto& mc2hit = mc2hitVec[im]; + + for (int ih = hitArray[im]->size(); ih--;) { + + const auto& hit = (*hitArray[im])[ih]; + uint64_t key = (uint64_t(hit.GetTrackID()) << 32) + hit.GetDetectorID(); + mc2hit.emplace(key, ih); + } + } + } + + // LOOP on : digits array + for (unsigned int iDigit = rofIndex; iDigit < rofIndex + rofNEntries; iDigit++) { + + Int_t ix = (*digArr)[iDigit].getRow(), iz = (*digArr)[iDigit].getColumn(); + Float_t x = 0.f, z = 0.f; + + Int_t chipID = (*digArr)[iDigit].getChipIndex(); + + if (chipID < 4) { + segs[chipID].detectorToLocal(ix, iz, x, z); + } else { + SegmentationAlpide::detectorToLocal(ix, iz, x, z); + } + + const o2::math_utils::Point3D<float> locD(x, 0., z); + + auto lab = (labels.getLabels(iDigit))[0]; + + int trID = lab.getTrackID(); + + if (lab.isValid()) { // not a noise + + nDigitRead++; + + auto gloD = gman->getMatrixL2G(chipID)(locD); // convert to global + if (chipID < 4) { + // + // invert + //xyzLocS = {SegmentationSuperAlpide::Radii[detID] * startPhi, 0.f, startPos.Z()}; + //xyzLocE = {SegmentationSuperAlpide::Radii[detID] * endPhi, 0.f, endPos.Z()}; + // + double radius = SegmentationSuperAlpide::Radii[chipID]; + double phi = locD.X() / radius; + gloD.SetXYZ(radius * std::cos(phi), radius * std::sin(phi), locD.Z()); + } + float dx = 0., dz = 0.; + + std::unordered_map<uint64_t, int>* mc2hit = &mc2hitVec[lab.getEventID()]; + + // get MC info + uint64_t key = (uint64_t(trID) << 32) + chipID; + auto hitEntry = mc2hit->find(key); + + if (hitEntry == mc2hit->end()) { + + LOG(ERROR) << "Failed to find MC hit entry for Tr" << trID << " chipID" << chipID; + continue; + } + + Hit& hit = (*hitArray[lab.getEventID()])[hitEntry->second]; + + // FIXME FOR INNER BARREL + auto locH = gman->getMatrixL2G(chipID) ^ (hit.GetPos()); // inverse conversion from global to local + auto locHsta = gman->getMatrixL2G(chipID) ^ (hit.GetPosStart()); + + if (chipID < 4) { + float startPhi{std::atan2(-hit.GetPosStart().Y(), -hit.GetPosStart().X())}; + float endPhi{std::atan2(-hit.GetPos().Y(), -hit.GetPos().X())}; + locH.SetXYZ(SegmentationSuperAlpide::Radii[chipID] * endPhi, 0.f, hit.GetPos().Z()); + locHsta.SetXYZ(SegmentationSuperAlpide::Radii[chipID] * startPhi, 0.f, hit.GetPosStart().Z()); + } + + locH.SetXYZ(0.5 * (locH.X() + locHsta.X()), 0.5 * (locH.Y() + locHsta.Y()), 0.5 * (locH.Z() + locHsta.Z())); + + int row, col; + float xlc = 0., zlc = 0.; + + segs[chipID < 4 ? chipID : 0].localToDetector(locH.X(), locH.Z(), row, col); + segs[chipID < 4 ? chipID : 0].detectorToLocal(row, col, xlc, zlc); + + nt->Fill(chipID, gloD.X(), gloD.Y(), gloD.Z(), ix, iz, row, col, locH.X(), locH.Z(), xlc, zlc, locH.X() - locD.X(), locH.Z() - locD.Z()); + + nDigitFilled++; + } // not noise + + } // end loop on digits array + + } // end loop on ROFRecords array + + new TCanvas; + nt->Draw("y:x"); + new TCanvas; + nt->Draw("dx:dz", "abs(dx)<0.02 && abs(dz)<0.02"); + + f->Write(); + f->Close(); + printf("read %d filled %d\n", nDigitRead, nDigitFilled); +} diff --git a/Detectors/Upgrades/IT3/reconstruction/CMakeLists.txt b/Detectors/Upgrades/IT3/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..e32106dfe261f --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(ITS3Reconstruction + TARGETVARNAME targetName + SOURCES src/Clusterer.cxx + src/TopologyDictionary.cxx + + PUBLIC_LINK_LIBRARIES O2::ITSMFTBase + O2::ITSMFTReconstruction + O2::ITS3Base + O2::CommonDataFormat + O2::DetectorsRaw + O2::SimulationDataFormat + O2::DataFormatsITSMFT + O2::DataFormatsITS3 + O2::DPLUtils + O2::rANS + O2::Headers) + +o2_target_root_dictionary( + ITS3Reconstruction + HEADERS include/ITS3Reconstruction/Clusterer.h + include/ITS3Reconstruction/TopologyDictionary.h +) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() + diff --git a/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/Clusterer.h b/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/Clusterer.h new file mode 100644 index 0000000000000..9be735ec39e4b --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/Clusterer.h @@ -0,0 +1,235 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Clusterer.h +/// \brief Definition of the ITS cluster finder +#ifndef ALICEO2_ITS_CLUSTERER_H +#define ALICEO2_ITS_CLUSTERER_H + +#define _PERFORM_TIMING_ + +#include <utility> +#include <vector> +#include <cstring> +#include <memory> +#include <gsl/span> +#include "ITSMFTBase/SegmentationAlpide.h" +#include "DataFormatsITS3/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITSMFTReconstruction/PixelReader.h" +#include "ITSMFTReconstruction/PixelData.h" +#include "ITSMFTReconstruction/LookUp.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "CommonConstants/LHCConstants.h" +#include "Rtypes.h" + +#ifdef _PERFORM_TIMING_ +#include <TStopwatch.h> +#endif + +class TTree; + +namespace o2 +{ +class MCCompLabel; +namespace dataformats +{ +template <typename T> +class ConstMCTruthContainerView; +template <typename T> +class MCTruthContainer; +} // namespace dataformats + +namespace its3 +{ + +using CompClusCont = std::vector<CompClusterExt>; +using PatternCont = std::vector<unsigned char>; +using ROFRecCont = std::vector<itsmft::ROFRecord>; + +//template <class CompClusCont, class PatternCont, class ROFRecCont> // container types (PMR or std::vectors) + +class Clusterer +{ + using PixelReader = o2::itsmft::PixelReader; + using PixelData = o2::itsmft::PixelData; + using ChipPixelData = o2::itsmft::ChipPixelData; + using Label = o2::MCCompLabel; + using MCTruth = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; + using ConstMCTruth = o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>; + + public: + static constexpr int MaxLabels = 10; + //========================================================= + /// methods and transient data used within a thread + struct ThreadStat { + uint16_t firstChip = 0; + uint16_t nChips = 0; + uint32_t firstClus = 0; + uint32_t firstPatt = 0; + uint32_t nClus = 0; + uint32_t nPatt = 0; + ThreadStat() = default; + }; + + struct ClustererThread { + + Clusterer* parent = nullptr; // parent clusterer + // buffers for entries in preClusterIndices in 2 columns, to avoid boundary checks, we reserve + // extra elements in the beginning and the end + int* column1 = nullptr; + int* column2 = nullptr; + int* curr = nullptr; // pointer on the 1st row of currently processed columnsX + int* prev = nullptr; // pointer on the 1st row of previously processed columnsX + int size = itsmft::SegmentationAlpide::NRows + 2; + // pixels[].first is the index of the next pixel of the same precluster in the pixels + // pixels[].second is the index of the referred pixel in the ChipPixelData (element of mChips) + std::vector<std::pair<int, uint32_t>> pixels; + std::vector<int> preClusterHeads; // index of precluster head in the pixels + std::vector<int> preClusterIndices; + uint16_t currCol = 0xffff; ///< Column being processed + bool noLeftCol = true; ///< flag that there is no column on the left to check + std::array<Label, MaxLabels> labelsBuff; //! temporary buffer for building cluster labels + std::vector<PixelData> pixArrBuff; //! temporary buffer for pattern calc. + // + /// temporary storage for the thread output + CompClusCont compClusters; + PatternCont patterns; + MCTruth labels; + std::vector<ThreadStat> stats; // statistics for each thread results, used at merging + /// + ///< reset column buffer, for the performance reasons we use memset + void resetColumn(int* buff) { std::memset(buff, -1, sizeof(int) * (size - 2)); } + + ///< swap current and previous column buffers + void swapColumnBuffers() { std::swap(prev, curr); } + + ///< add cluster at row (entry ip in the ChipPixeData) to the precluster with given index + void expandPreCluster(uint32_t ip, uint16_t row, int preClusIndex) + { + auto& firstIndex = preClusterHeads[preClusterIndices[preClusIndex]]; + pixels.emplace_back(firstIndex, ip); + firstIndex = pixels.size() - 1; + curr[row] = preClusIndex; + } + + ///< add new precluster at given row of current column for the fired pixel with index ip in the ChipPixelData + void addNewPrecluster(uint32_t ip, uint16_t row) + { + preClusterHeads.push_back(pixels.size()); + // new head does not point yet (-1) on other pixels, store just the entry of the pixel in the ChipPixelData + pixels.emplace_back(-1, ip); + int lastIndex = preClusterIndices.size(); + preClusterIndices.push_back(lastIndex); + curr[row] = lastIndex; // store index of the new precluster in the current column buffer + } + + void streamCluster(const std::vector<PixelData>& pixbuf, uint16_t rowMin, uint16_t rowSpanW, uint16_t colMin, uint16_t colSpanW, + uint16_t chipID, + CompClusCont* compClusPtr, PatternCont* patternsPtr, + MCTruth* labelsClusPtr, int nlab, bool isHuge = false); + + void fetchMCLabels(int digID, const ConstMCTruth* labelsDig, int& nfilled); + void initChip(const ChipPixelData* curChipData, uint32_t first, int chipID); + void updateChip(const ChipPixelData* curChipData, uint32_t ip); + void finishChip(ChipPixelData* curChipData, CompClusCont* compClus, PatternCont* patterns, + const ConstMCTruth* labelsDig, MCTruth* labelsClus); + void finishChipSingleHitFast(uint32_t hit, ChipPixelData* curChipData, CompClusCont* compClusPtr, + PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPTr); + void process(uint16_t chip, uint16_t nChips, CompClusCont* compClusPtr, PatternCont* patternsPtr, + const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const itsmft::ROFRecord& rofPtr); + + ClustererThread(Clusterer* par = nullptr) : parent(par) {} + ~ClustererThread() + { + if (column1) { + delete[] column1; + } + if (column2) { + delete[] column2; + } + } + }; + //========================================================= + + Clusterer(); + ~Clusterer() = default; + + Clusterer(const Clusterer&) = delete; + Clusterer& operator=(const Clusterer&) = delete; + + void process(int nThreads, PixelReader& r, CompClusCont* compClus, PatternCont* patterns, ROFRecCont* vecROFRec, MCTruth* labelsCl = nullptr); + + bool isContinuousReadOut() const { return mContinuousReadout; } + void setContinuousReadOut(bool v) { mContinuousReadout = v; } + + int getMaxBCSeparationToMask() const { return mMaxBCSeparationToMask; } + void setMaxBCSeparationToMask(int n) { mMaxBCSeparationToMask = n; } + + int getMaxRowColDiffToMask() const { return mMaxRowColDiffToMask; } + void setMaxRowColDiffToMask(int v) { mMaxRowColDiffToMask = v; } + + void print() const; + void clear(); + + void setNChips(int n) + { + mChips.resize(n); + mChipsOld.resize(n); + } + + ///< load the dictionary of cluster topologies + void loadDictionary(const std::string& fileName) { mPattIdConverter.loadDictionary(fileName); } + + TStopwatch& getTimer() { return mTimer; } // cannot be const + TStopwatch& getTimerMerge() { return mTimerMerge; } // cannot be const + + private: + ///< recalculate min max row and column of the cluster accounting for the position of pix + static void adjustBoundingBox(uint16_t row, uint16_t col, uint16_t& rMin, uint16_t& rMax, uint16_t& cMin, uint16_t& cMax) + { + if (row < rMin) { + rMin = row; + } + if (row > rMax) { + rMax = row; + } + if (col < cMin) { + cMin = col; + } + if (col > cMax) { + cMax = col; + } + } + + void flushClusters(CompClusCont* compClus, MCTruth* labels); + + // clusterization options + bool mContinuousReadout = true; ///< flag continuous readout + + ///< mask continuosly fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) + int mMaxBCSeparationToMask = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; + int mMaxRowColDiffToMask = 0; ///< provide their difference in col/row is <= than this + + std::vector<std::unique_ptr<ClustererThread>> mThreads; // buffers for threads + std::vector<ChipPixelData> mChips; // currently processed ROF's chips data + std::vector<ChipPixelData> mChipsOld; // previously processed ROF's chips data (for masking) + std::vector<ChipPixelData*> mFiredChipsPtr; // pointers on the fired chips data in the decoder cache + + itsmft::LookUp mPattIdConverter; //! Convert the cluster topology to the corresponding entry in the dictionary. + + TStopwatch mTimer; + TStopwatch mTimerMerge; +}; + +} // namespace its3 +} // namespace o2 +#endif /* ALICEO2_ITS_CLUSTERER_H */ \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/TopologyDictionary.h b/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/TopologyDictionary.h new file mode 100644 index 0000000000000..03b84e5336c29 --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/include/ITS3Reconstruction/TopologyDictionary.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TopologyDictionary.h +/// \brief Definition of the ClusterTopology class for ITS3 + +#ifndef ALICEO2_ITS3_TOPOLOGYDICTIONARY_H +#define ALICEO2_ITS3_TOPOLOGYDICTIONARY_H + +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITS3/CompCluster.h" + +namespace o2 +{ +namespace its3 +{ + +class TopologyDictionary : public itsmft::TopologyDictionary +{ + public: + TopologyDictionary(itsmft::TopologyDictionary top) : itsmft::TopologyDictionary{top} {} + + ///Returns the local position of a compact cluster + math_utils::Point3D<float> getClusterCoordinates(int detID, const its3::CompCluster& cl) const; + ///Returns the local position of a compact cluster + static math_utils::Point3D<float> getClusterCoordinates(int detID, const its3::CompCluster& cl, const itsmft::ClusterPattern& patt, bool isGroup = true); +}; +} // namespace its3 +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/IT3/reconstruction/src/Clusterer.cxx b/Detectors/Upgrades/IT3/reconstruction/src/Clusterer.cxx new file mode 100644 index 0000000000000..9224af44c795d --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/src/Clusterer.cxx @@ -0,0 +1,515 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Clusterer.cxx +/// \brief Implementation of the ITS cluster finder +#include <algorithm> +#include <TTree.h> +#include "Framework/Logger.h" +#include "ITSMFTBase/GeometryTGeo.h" +#include "ITS3Reconstruction/Clusterer.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "CommonDataFormat/InteractionRecord.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +using namespace o2::itsmft; + +namespace o2::its3 +{ +//__________________________________________________ +void Clusterer::process(int nThreads, PixelReader& reader, CompClusCont* compClus, + PatternCont* patterns, ROFRecCont* vecROFRec, MCTruth* labelsCl) +{ +#ifdef _PERFORM_TIMING_ + mTimer.Start(kFALSE); +#endif + if (nThreads < 1) { + nThreads = 1; + } + auto autoDecode = reader.getDecodeNextAuto(); + do { + if (autoDecode) { + reader.setDecodeNextAuto(false); // internally do not autodecode + if (!reader.decodeNextTrigger()) { + break; // on the fly decoding was requested, but there were no data left + } + } + // pre-fetch all non-empty chips of current ROF + ChipPixelData* curChipData = nullptr; + mFiredChipsPtr.clear(); + size_t nPix = 0; + while ((curChipData = reader.getNextChipData(mChips))) { + mFiredChipsPtr.push_back(curChipData); + nPix += curChipData->getData().size(); + } + + auto& rof = vecROFRec->emplace_back(reader.getInteractionRecord(), 0, compClus->size(), 0); // create new ROF + + uint16_t nFired = mFiredChipsPtr.size(); + if (!nFired) { + if (autoDecode) { + continue; + } + break; // just 1 ROF was asked to be processed + } + if (nFired < nThreads) { + nThreads = nFired; + } +#ifdef WITH_OPENMP + omp_set_num_threads(nThreads); +#else + nThreads = 1; +#endif + uint16_t chipStep = nThreads > 1 ? (nThreads == 2 ? 20 : (nThreads < 5 ? 5 : 1)) : nFired; + int dynGrp = std::min(4, std::max(1, nThreads / 2)); + if (nThreads > mThreads.size()) { + int oldSz = mThreads.size(); + mThreads.resize(nThreads); + for (int i = oldSz; i < nThreads; i++) { + mThreads[i] = std::make_unique<ClustererThread>(this); + } + } +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic, dynGrp) + //>> start of MT region + for (uint16_t ic = 0; ic < nFired; ic += chipStep) { + auto ith = omp_get_thread_num(); + if (nThreads > 1) { + mThreads[ith]->process(ic, std::min(chipStep, uint16_t(nFired - ic)), + &mThreads[ith]->compClusters, + patterns ? &mThreads[ith]->patterns : nullptr, + labelsCl ? reader.getDigitsMCTruth() : nullptr, + labelsCl ? &mThreads[ith]->labels : nullptr, rof); + } else { // put directly to the destination + mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.getDigitsMCTruth() : nullptr, labelsCl, rof); + } + } + //<< end of MT region +#else + mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.getDigitsMCTruth() : nullptr, labelsCl, rof); +#endif + // copy data of all threads but the 1st one to final destination + if (nThreads > 1) { +#ifdef _PERFORM_TIMING_ + mTimerMerge.Start(false); +#endif + size_t nClTot = 0, nPattTot = 0; + int chid = 0, thrStatIdx[nThreads]; + for (int ith = 0; ith < nThreads; ith++) { + thrStatIdx[ith] = 0; + nClTot += mThreads[ith]->compClusters.size(); + nPattTot += mThreads[ith]->patterns.size(); + } + compClus->reserve(nClTot); + if (patterns) { + patterns->reserve(nPattTot); + } + while (chid < nFired) { + for (int ith = 0; ith < nThreads; ith++) { + if (thrStatIdx[ith] >= mThreads[ith]->stats.size()) { + continue; + } + const auto& stat = mThreads[ith]->stats[thrStatIdx[ith]]; + if (stat.firstChip == chid) { + thrStatIdx[ith]++; + chid += stat.nChips; // next chip to look + const auto clbeg = mThreads[ith]->compClusters.begin() + stat.firstClus; + auto szold = compClus->size(); + compClus->insert(compClus->end(), clbeg, clbeg + stat.nClus); + if (patterns) { + const auto ptbeg = mThreads[ith]->patterns.begin() + stat.firstPatt; + patterns->insert(patterns->end(), ptbeg, ptbeg + stat.nPatt); + } + if (labelsCl) { + labelsCl->mergeAtBack(mThreads[ith]->labels, stat.firstClus, stat.nClus); + } + } + } + } + for (int ith = 0; ith < nThreads; ith++) { + mThreads[ith]->patterns.clear(); + mThreads[ith]->compClusters.clear(); + mThreads[ith]->labels.clear(); + mThreads[ith]->stats.clear(); + } +#ifdef _PERFORM_TIMING_ + mTimerMerge.Stop(); +#endif + } else { + mThreads[0]->stats.clear(); + } + rof.setNEntries(compClus->size() - rof.getFirstEntry()); // update + } while (autoDecode); + reader.setDecodeNextAuto(autoDecode); // restore setting +#ifdef _PERFORM_TIMING_ + mTimer.Stop(); +#endif +} + +//__________________________________________________ +void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClusCont* compClusPtr, PatternCont* patternsPtr, + const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const ROFRecord& rofPtr) +{ + if (stats.empty() || stats.back().firstChip + stats.back().nChips < chip) { // there is a jump, register new block + stats.emplace_back(ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0}); + } + + for (int ic = 0; ic < nChips; ic++) { + auto* curChipData = parent->mFiredChipsPtr[chip + ic]; + auto chipID = curChipData->getChipID(); + if (parent->mMaxBCSeparationToMask > 0) { // mask pixels fired from the previous ROF + const auto& chipInPrevROF = parent->mChipsOld[chipID]; + if (std::abs(rofPtr.getBCData().differenceInBC(chipInPrevROF.getInteractionRecord())) < parent->mMaxBCSeparationToMask) { + parent->mMaxRowColDiffToMask ? curChipData->maskFiredInSample(parent->mChipsOld[chipID], parent->mMaxRowColDiffToMask) : curChipData->maskFiredInSample(parent->mChipsOld[chipID]); + } + } + auto validPixID = curChipData->getFirstUnmasked(); + auto npix = curChipData->getData().size(); + if (validPixID < npix) { // chip data may have all of its pixels masked! + auto valp = validPixID++; + if (validPixID == npix) { // special case of a single pixel fired on the chip + finishChipSingleHitFast(valp, curChipData, compClusPtr, patternsPtr, labelsDigPtr, labelsClPtr); + } else { + initChip(curChipData, valp, chipID); + for (; validPixID < npix; validPixID++) { + if (!curChipData->getData()[validPixID].isMasked()) { + updateChip(curChipData, validPixID); + } + } + finishChip(curChipData, compClusPtr, patternsPtr, labelsDigPtr, labelsClPtr); + } + } + if (parent->mMaxBCSeparationToMask > 0) { // current chip data will be used in the next ROF to mask overflow pixels + parent->mChipsOld[chipID].swap(*curChipData); + } + } + auto& currStat = stats.back(); + currStat.nChips += nChips; + currStat.nClus = compClusPtr->size() - currStat.firstClus; + currStat.nPatt = patternsPtr ? (patternsPtr->size() - currStat.firstPatt) : 0; +} + +//__________________________________________________ +void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClusCont* compClusPtr, + PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPtr) +{ + auto clustersCount = compClusPtr->size(); + const auto& pixData = curChipData->getData(); + for (int i1 = 0; i1 < preClusterHeads.size(); ++i1) { + auto ci = preClusterIndices[i1]; + if (ci < 0) { + continue; + } + uint16_t rowMax = 0, rowMin = 65535; + uint16_t colMax = 0, colMin = 65535; + int nlab = 0; + int next = preClusterHeads[i1]; + pixArrBuff.clear(); + while (next >= 0) { + const auto& pixEntry = pixels[next]; + const auto pix = pixData[pixEntry.second]; + pixArrBuff.push_back(pix); // needed for cluster topology + adjustBoundingBox(pix.getRowDirect(), pix.getCol(), rowMin, rowMax, colMin, colMax); + if (labelsClusPtr) { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second + fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab); + } + next = pixEntry.first; + } + preClusterIndices[i1] = -1; + for (int i2 = i1 + 1; i2 < preClusterHeads.size(); ++i2) { + if (preClusterIndices[i2] != ci) { + continue; + } + next = preClusterHeads[i2]; + while (next >= 0) { + const auto& pixEntry = pixels[next]; + const auto pix = pixData[pixEntry.second]; // PixelData + pixArrBuff.push_back(pix); // needed for cluster topology + adjustBoundingBox(pix.getRowDirect(), pix.getCol(), rowMin, rowMax, colMin, colMax); + if (labelsClusPtr) { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second + fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab); + } + next = pixEntry.first; + } + preClusterIndices[i2] = -1; + } + + auto chipID = curChipData->getChipID(); + uint16_t colSpan = (colMax - colMin + 1); + uint16_t rowSpan = (rowMax - rowMin + 1); + if (colSpan <= o2::itsmft::ClusterPattern::MaxColSpan && + rowSpan <= o2::itsmft::ClusterPattern::MaxRowSpan) { + streamCluster(pixArrBuff, rowMin, rowSpan, colMin, colSpan, chipID, + compClusPtr, patternsPtr, labelsClusPtr, nlab); + } else { + LOG(WARNING) << "Splitting a huge cluster ! ChipID: " << chipID; + + colSpan %= o2::itsmft::ClusterPattern::MaxColSpan; + if (colSpan == 0) { + colSpan = o2::itsmft::ClusterPattern::MaxColSpan; + } + + rowSpan %= o2::itsmft::ClusterPattern::MaxRowSpan; + if (rowSpan == 0) { + rowSpan = o2::itsmft::ClusterPattern::MaxRowSpan; + } + + do { + uint16_t r = rowMin, rsp = rowSpan; + + do { + // Select a subset of pixels fitting the reduced bounding box + std::vector<PixelData> pixbuf; + auto colMax = colMin + colSpan, rowMax = r + rsp; + for (const auto& pix : pixArrBuff) { + if (pix.getRowDirect() >= r && pix.getRowDirect() < rowMax && + pix.getCol() >= colMin && pix.getCol() < colMax) { + pixbuf.push_back(pix); + } + } + // Stream a piece of cluster only if the reduced bounding box is not empty + if (!pixbuf.empty()) { + streamCluster(pixbuf, r, rsp, colMin, colSpan, chipID, + compClusPtr, patternsPtr, labelsClusPtr, nlab, true); + } + r += rsp; + rsp = o2::itsmft::ClusterPattern::MaxRowSpan; + } while (r < rowMax); + + colMin += colSpan; + colSpan = o2::itsmft::ClusterPattern::MaxColSpan; + } while (colMin < colMax); + } + } +} + +void Clusterer::ClustererThread::streamCluster(const std::vector<PixelData>& pixbuf, uint16_t rowMin, uint16_t rowSpanW, uint16_t colMin, uint16_t colSpanW, uint16_t chipID, CompClusCont* compClusPtr, PatternCont* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isHuge) +{ + if (labelsClusPtr) { // MC labels were requested + auto cnt = compClusPtr->size(); + for (int i = nlab; i--;) { + labelsClusPtr->addElement(cnt, labelsBuff[i]); + } + } + + // add to compact clusters, which must be always filled + unsigned char patt[ClusterPattern::MaxPatternBytes] = {0}; // RSTODO FIX pattern filling + for (const auto& pix : pixbuf) { + unsigned short ir = pix.getRowDirect() - rowMin, ic = pix.getCol() - colMin; + int nbits = ir * colSpanW + ic; + patt[nbits >> 3] |= (0x1 << (7 - (nbits % 8))); + } + uint16_t pattID = (isHuge || parent->mPattIdConverter.size() == 0) ? CompCluster::InvalidPatternID : parent->mPattIdConverter.findGroupID(rowSpanW, colSpanW, patt); + if (pattID == CompCluster::InvalidPatternID || parent->mPattIdConverter.isGroup(pattID)) { + if (pattID != CompCluster::InvalidPatternID) { + //For groupped topologies, the reference pixel is the COG pixel + float xCOG = 0., zCOG = 0.; + ClusterPattern::getCOG(rowSpanW, colSpanW, patt, xCOG, zCOG); + rowMin += round(xCOG); + colMin += round(zCOG); + } + if (patternsPtr) { + patternsPtr->emplace_back((unsigned char)rowSpanW); + patternsPtr->emplace_back((unsigned char)colSpanW); + int nBytes = rowSpanW * colSpanW / 8; + if (((rowSpanW * colSpanW) % 8) != 0) { + nBytes++; + } + patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + nBytes); + } + } + compClusPtr->emplace_back(rowMin, colMin, pattID, chipID); +} + +//__________________________________________________ +void Clusterer::ClustererThread::finishChipSingleHitFast(uint32_t hit, ChipPixelData* curChipData, CompClusCont* compClusPtr, + PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPtr) +{ + auto clustersCount = compClusPtr->size(); + auto pix = curChipData->getData()[hit]; + uint16_t row = pix.getRowDirect(), col = pix.getCol(); + + if (labelsClusPtr) { // MC labels were requested + int nlab = 0; + fetchMCLabels(curChipData->getStartID() + hit, labelsDigPtr, nlab); + auto cnt = compClusPtr->size(); + for (int i = nlab; i--;) { + labelsClusPtr->addElement(cnt, labelsBuff[i]); + } + } + + // add to compact clusters, which must be always filled + unsigned char patt[ClusterPattern::MaxPatternBytes]{0x1 << (7 - (0 % 8))}; // unrolled 1 hit version of full loop in finishChip + uint16_t pattID = (parent->mPattIdConverter.size() == 0) ? CompCluster::InvalidPatternID : parent->mPattIdConverter.findGroupID(1, 1, patt); + if ((pattID == CompCluster::InvalidPatternID || parent->mPattIdConverter.isGroup(pattID)) && patternsPtr) { + patternsPtr->emplace_back(1); // rowspan + patternsPtr->emplace_back(1); // colspan + patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + 1); + } + compClusPtr->emplace_back(row, col, pattID, curChipData->getChipID()); +} + +//__________________________________________________ +Clusterer::Clusterer() : mPattIdConverter() +{ +#ifdef _PERFORM_TIMING_ + mTimer.Stop(); + mTimer.Reset(); + mTimerMerge.Stop(); + mTimerMerge.Reset(); +#endif +} + +//__________________________________________________ +void Clusterer::ClustererThread::initChip(const ChipPixelData* curChipData, uint32_t first, int chip) +{ + // init chip with the 1st unmasked pixel (entry "from" in the mChipData) + size = itsmft::SegmentationAlpide::NRows + 2; + if (chip < SegmentationSuperAlpide::NLayers) { + SegmentationSuperAlpide seg(chip); + size = seg.NRows + 2; + } + if (column1) { + delete[] column1; + } + if (column2) { + delete[] column2; + } + column1 = new int[size]; + column2 = new int[size]; + column1[0] = column1[size - 1] = -1; + column2[0] = column2[size - 1] = -1; + // init chip with the 1st unmasked pixel (entry "from" in the mChipData) + prev = column1 + 1; + curr = column2 + 1; + resetColumn(curr); + + pixels.clear(); + preClusterHeads.clear(); + preClusterIndices.clear(); + auto pix = curChipData->getData()[first]; + currCol = pix.getCol(); + curr[pix.getRowDirect()] = 0; // can use getRowDirect since the pixel is not masked + // start the first pre-cluster + preClusterHeads.push_back(0); + preClusterIndices.push_back(0); + pixels.emplace_back(-1, first); // id of current pixel + noLeftCol = true; // flag that there is no column on the left to check yet +} + +//__________________________________________________ +void Clusterer::ClustererThread::updateChip(const ChipPixelData* curChipData, uint32_t ip) +{ + const auto pix = curChipData->getData()[ip]; + uint16_t row = pix.getRowDirect(); // can use getRowDirect since the pixel is not masked + if (currCol != pix.getCol()) { // switch the buffers + swapColumnBuffers(); + resetColumn(curr); + noLeftCol = false; + if (pix.getCol() > currCol + 1) { + // no connection with previous column, this pixel cannot belong to any of the + // existing preclusters, create a new precluster and flag to check only the row above for next pixels of this column + currCol = pix.getCol(); + addNewPrecluster(ip, row); + noLeftCol = true; + return; + } + currCol = pix.getCol(); + } + + Bool_t orphan = true; + + if (noLeftCol) { // check only the row above + if (curr[row - 1] >= 0) { + expandPreCluster(ip, row, curr[row - 1]); // attach to the precluster of the previous row + return; + } + } else { + int neighbours[]{curr[row - 1], prev[row], prev[row + 1], prev[row - 1]}; + for (auto pci : neighbours) { + if (pci < 0) { + continue; + } + if (orphan) { + expandPreCluster(ip, row, pci); // attach to the adjascent precluster + orphan = false; + continue; + } + // reassign precluster index to smallest one + if (preClusterIndices[pci] < preClusterIndices[curr[row]]) { + preClusterIndices[curr[row]] = preClusterIndices[pci]; + } else { + preClusterIndices[pci] = preClusterIndices[curr[row]]; + } + } + } + if (orphan) { + addNewPrecluster(ip, row); // start new precluster + } +} + +//__________________________________________________ +void Clusterer::ClustererThread::fetchMCLabels(int digID, const ConstMCTruth* labelsDig, int& nfilled) +{ + // transfer MC labels to cluster + if (nfilled >= MaxLabels) { + return; + } + const auto& lbls = labelsDig->getLabels(digID); + for (int i = lbls.size(); i--;) { + int ic = nfilled; + for (; ic--;) { // check if the label is already present + if (labelsBuff[ic] == lbls[i]) { + return; // label is found, do nothing + } + } + labelsBuff[nfilled++] = lbls[i]; + if (nfilled >= MaxLabels) { + break; + } + } + // +} + +//__________________________________________________ +void Clusterer::clear() +{ + // reset +#ifdef _PERFORM_TIMING_ + mTimer.Stop(); + mTimer.Reset(); + mTimerMerge.Stop(); + mTimerMerge.Reset(); +#endif +} + +//__________________________________________________ +void Clusterer::print() const +{ + // print settings + LOG(INFO) << "Clusterizer masks overflow pixels separated by < " << mMaxBCSeparationToMask << " BC and <= " + << mMaxRowColDiffToMask << " in row/col"; +#ifdef _PERFORM_TIMING_ + auto& tmr = const_cast<TStopwatch&>(mTimer); // ugly but this is what root does internally + auto& tmrm = const_cast<TStopwatch&>(mTimerMerge); + LOG(INFO) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime() + << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots"; + LOG(INFO) << "Threads output merging timing : Cpu: " << tmrm.CpuTime() + << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots"; + +#endif +} + +} // namespace o2::its3 \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/reconstruction/src/ITS3ReconstructionLinkDef.h b/Detectors/Upgrades/IT3/reconstruction/src/ITS3ReconstructionLinkDef.h new file mode 100644 index 0000000000000..012a991a0e840 --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/src/ITS3ReconstructionLinkDef.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::its3::Clusterer + ; +#pragma link C++ class o2::its3::TopologyDictionary + ; + +#endif diff --git a/Detectors/Upgrades/IT3/reconstruction/src/TopologyDictionary.cxx b/Detectors/Upgrades/IT3/reconstruction/src/TopologyDictionary.cxx new file mode 100644 index 0000000000000..ea632ea39401e --- /dev/null +++ b/Detectors/Upgrades/IT3/reconstruction/src/TopologyDictionary.cxx @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TopologyDictionary.cxx + +#include "ITS3Reconstruction/TopologyDictionary.h" +#include "ITS3Base/SegmentationSuperAlpide.h" + +namespace o2::its3 +{ + +math_utils::Point3D<float> TopologyDictionary::getClusterCoordinates(int detID, const its3::CompCluster& cl) const +{ + + static SegmentationSuperAlpide segmentations[SegmentationSuperAlpide::NLayers]{SegmentationSuperAlpide(0), SegmentationSuperAlpide(1), SegmentationSuperAlpide(2), SegmentationSuperAlpide(3)}; + math_utils::Point3D<float> locCl; + if (detID >= SegmentationSuperAlpide::NLayers) { + + o2::itsmft::SegmentationAlpide::detectorToLocalUnchecked(cl.getRow(), cl.getCol(), locCl); + } else { + segmentations[detID].detectorToLocalUnchecked(cl.getRow(), cl.getCol(), locCl); + } + locCl.SetX(locCl.X() + this->getXCOG(cl.getPatternID())); + locCl.SetZ(locCl.Z() + this->getZCOG(cl.getPatternID())); + return locCl; +} + +math_utils::Point3D<float> TopologyDictionary::getClusterCoordinates(int detID, const its3::CompCluster& cl, const itsmft::ClusterPattern& patt, bool isGroup) +{ + static SegmentationSuperAlpide segmentations[SegmentationSuperAlpide::NLayers]{SegmentationSuperAlpide(0), SegmentationSuperAlpide(1), SegmentationSuperAlpide(2), SegmentationSuperAlpide(3)}; + + auto refRow = cl.getRow(); + auto refCol = cl.getCol(); + float xCOG = 0, zCOG = 0; + patt.getCOG(xCOG, zCOG); + if (isGroup) { + refRow -= round(xCOG); + refCol -= round(zCOG); + } + math_utils::Point3D<float> locCl; + if (detID >= SegmentationSuperAlpide::NLayers) { + o2::itsmft::SegmentationAlpide::detectorToLocalUnchecked(refRow + xCOG, refCol + zCOG, locCl); + } else { + segmentations[detID].detectorToLocalUnchecked(refRow + xCOG, refCol + zCOG, locCl); + } + return locCl; +} + +} // namespace o2::its3 \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/simulation/CMakeLists.txt b/Detectors/Upgrades/IT3/simulation/CMakeLists.txt index e734dcf0c0551..12553dd45f551 100644 --- a/Detectors/Upgrades/IT3/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/IT3/simulation/CMakeLists.txt @@ -1,25 +1,27 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ITS3Simulation - SOURCES src/V11Geometry.cxx src/V1Layer.cxx src/V3Layer.cxx + SOURCES src/V11Geometry.cxx src/V3Layer.cxx src/Detector.cxx src/V3Services.cxx - PUBLIC_LINK_LIBRARIES O2::ITS3Base O2::ITSMFTSimulation + src/Digitizer.cxx + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::ITS3Base O2::ITSMFTSimulation ROOT::Physics) o2_target_root_dictionary(ITS3Simulation HEADERS include/ITS3Simulation/Detector.h - include/ITS3Simulation/V1Layer.h include/ITS3Simulation/V3Layer.h include/ITS3Simulation/V11Geometry.h include/ITS3Simulation/V3Services.h + include/ITS3Simulation/Digitizer.h ) o2_data_file(COPY data DESTINATION Detectors/ITS3/simulation) \ No newline at end of file diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Detector.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Detector.h index e65a3a1849eb1..3fbd07b8ada9c 100644 --- a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Detector.h +++ b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -79,9 +80,10 @@ class Detector : public o2::base::DetImpl<Detector> kOBModel2 = 9 }; - static constexpr Int_t sNumberLayers = 7; ///< Number of layers in ITSU - static constexpr Int_t sNumberInnerLayers = 3; ///< Number of inner layers in ITSU - static constexpr Int_t sNumberOfWrapperVolumes = 3; ///< Number of wrapper volumes + static constexpr Int_t sNumberInnerLayers = 4; ///< Number of inner layers in ITS3 + static constexpr Int_t sNumberOuterLayers = 4; ///< Number of outer layers in ITS3 + static constexpr Int_t sNumberLayers = sNumberInnerLayers + sNumberOuterLayers; ///< Total number of layers in ITS3 + static constexpr Int_t sNumberOfWrapperVolumes = 3; ///< Number of wrapper volumes /// Name : Detector Name /// Active: kTRUE for active detectors (ProcessHits() will be called) @@ -122,12 +124,6 @@ class Detector : public o2::base::DetImpl<Detector> /// Base class to create the detector geometry void ConstructGeometry() override; - /// Creates the Service Barrel (as a simple cylinder) for IB and OB - /// \param innerBarrel if true, build IB service barrel, otherwise for OB - /// \param dest the mother volume holding the service barrel - /// \param mgr the gGeoManager pointer (used to get the material) - void createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr = gGeoManager); - /// Sets the layer parameters /// \param nlay layer number /// \param phi0 layer phi0 @@ -142,23 +138,6 @@ class Detector : public o2::base::DetImpl<Detector> void defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t lthick = 0., Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; - /// Sets the layer parameters for a "turbo" layer - /// (i.e. a layer whose staves overlap in phi) - /// \param nlay layer number - /// \param phi0 phi of 1st stave - /// \param r layer radius - /// \param nstav number of staves - /// \param nunit IB: number of chips per stave - /// \param OB: number of modules per half stave - /// \param width stave width - /// \param tilt layer tilt angle (degrees) - /// \param lthick stave thickness (if omitted, defaults to 0) - /// \param dthick detector thickness (if omitted, defaults to 0) - /// \param dettypeID ?? - /// \param buildLevel (if 0, all geometry is build, used for material budget studies) - void defineLayerTurbo(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t width, Double_t tilt, - Double_t lthick = 0., Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; - /// Sets the layer parameters for new ITS3 geo /// \param nlay layer number /// \param r layer radius @@ -181,8 +160,7 @@ class Detector : public o2::base::DetImpl<Detector> /// \param lthick stave thickness /// \param dthick detector thickness /// \param dettype detector type - virtual void getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nladd, Int_t& nmod, Double_t& width, - Double_t& tilt, Double_t& lthick, Double_t& mthick, UInt_t& dettype) const; + virtual void getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nladd, Int_t& nmod, Double_t& lthick, Double_t& mthick, UInt_t& dettype) const; /// This method is an example of how to add your own point of type Hit to the clones array o2::itsmft::Hit* addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, @@ -247,20 +225,9 @@ class Detector : public o2::base::DetImpl<Detector> void BeginPrimary() override { ; } void PostTrack() override { ; } void PreTrack() override { ; } - /// Prints out the content of this class in ASCII format - /// \param ostream *os The output stream - void Print(std::ostream* os) const; - - /// Reads in the content of this class in the format of Print - /// \param istream *is The input stream - void Read(std::istream* is); /// Returns the number of layers Int_t getNumberOfLayers() const { return sNumberLayers; } - virtual void setStaveModelIB(Model model) { mStaveModelInnerBarrel = model; } - virtual void setStaveModelOB(Model model) { mStaveModelOuterBarrel = model; } - virtual Model getStaveModelIB() const { return mStaveModelInnerBarrel; } - virtual Model getStaveModelOB() const { return mStaveModelOuterBarrel; } void createOuterBarrel(const Bool_t ob) { mCreateOuterBarrel = ob; }; Bool_t isCreateOuterBarrel() { return mCreateOuterBarrel; }; @@ -294,7 +261,6 @@ class Detector : public o2::base::DetImpl<Detector> Double_t mWrapperZSpan[sNumberOfWrapperVolumes]; //! Z span of wrapper volume Int_t* mWrapperLayerId; //! Id of wrapper layer to which layer belongs (-1 if not wrapped) - Bool_t* mTurboLayer; //! True for "turbo" layers Bool_t* mITS3Layer; //! True for new ITS3 layers Double_t* mLayerPhi0; //! Vector of layer's 1st stave phi in lab Double_t* mLayerRadii; //! Vector of layer radii @@ -302,8 +268,6 @@ class Detector : public o2::base::DetImpl<Detector> Int_t* mStavePerLayer; //! Vector of number of staves per layer Int_t* mUnitPerStave; //! Vector of number of "units" per stave Double_t* mChipThickness; //! Vector of chip thicknesses - Double_t* mStaveWidth; //! Vector of stave width (only used for turbo) - Double_t* mStaveTilt; //! Vector of stave tilt (only used for turbo) Double_t* mDetectorThickness; //! Vector of detector thicknesses UInt_t* mChipTypeID; //! Vector of detector type id Int_t* mBuildLevel; //! Vector of Material Budget Studies @@ -312,7 +276,7 @@ class Detector : public o2::base::DetImpl<Detector> std::vector<o2::itsmft::Hit>* mHits; /// We need this as a method to access members - void configITS(Detector* its); + void configITS3(); /// Creates all needed arrays void createAllArrays(); @@ -349,8 +313,6 @@ class Detector : public o2::base::DetImpl<Detector> Detector& operator=(const Detector&); - Model mStaveModelInnerBarrel; //! The stave model for the Inner Barrel - Model mStaveModelOuterBarrel; //! The stave model for the Outer Barrel V3Layer** mGeometry; //! Geometry V3Services* mServicesGeometry; //! Services Geometry @@ -358,11 +320,6 @@ class Detector : public o2::base::DetImpl<Detector> friend class o2::base::DetImpl; ClassDefOverride(Detector, 1); }; - -// Input and output function for standard C++ input/output. -std::ostream& operator<<(std::ostream& os, Detector& source); - -std::istream& operator>>(std::istream& os, Detector& source); } // namespace its3 } // namespace o2 diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Digitizer.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Digitizer.h new file mode 100644 index 0000000000000..1ec5fce5beb39 --- /dev/null +++ b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/Digitizer.h @@ -0,0 +1,139 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digitizer.h +/// \brief Definition of the ITS digitizer +#ifndef ALICEO2_ITS3_DIGITIZER_H +#define ALICEO2_ITS3_DIGITIZER_H + +#include <vector> +#include <deque> +#include <memory> + +#include "Rtypes.h" // for Digitizer::Class +#include "TObject.h" // for TObject + +#include "ITSMFTSimulation/ChipDigitsContainer.h" +#include "ITSMFTSimulation/AlpideSimResponse.h" +#include "ITSMFTSimulation/DigiParams.h" +#include "ITSMFTSimulation/Hit.h" +#include "ITS3Base/GeometryTGeo.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" + +namespace o2 +{ + +namespace dataformats +{ +template <typename T> +class MCTruthContainer; +} + +namespace its3 +{ +class Digitizer : public TObject +{ + using ExtraDig = std::vector<itsmft::PreDigitLabelRef>; ///< container for extra contributions to PreDigits + + public: + Digitizer() = default; + ~Digitizer() override = default; + Digitizer(const Digitizer&) = delete; + Digitizer& operator=(const Digitizer&) = delete; + + void setDigits(std::vector<o2::itsmft::Digit>* dig) { mDigits = dig; } + void setMCLabels(o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mclb) { mMCLabels = mclb; } + void setROFRecords(std::vector<o2::itsmft::ROFRecord>* rec) { mROFRecords = rec; } + + o2::itsmft::DigiParams& getParams() { return (o2::itsmft::DigiParams&)mParams; } + const o2::itsmft::DigiParams& getParams() const { return mParams; } + + void init(); + + /// Steer conversion of hits to digits + void process(const std::vector<itsmft::Hit>* hits, int evID, int srcID); + void setEventTime(const o2::InteractionTimeRecord& irt); + double getEndTimeOfROFMax() const + { + ///< return the time corresponding to end of the last reserved ROFrame : mROFrameMax + return mParams.getROFrameLength() * (mROFrameMax + 1) + mParams.getTimeOffset(); + } + + void setContinuous(bool v) { mParams.setContinuous(v); } + bool isContinuous() const { return mParams.isContinuous(); } + void fillOutputContainer(uint32_t maxFrame = 0xffffffff); + + void setDigiParams(const o2::itsmft::DigiParams& par) { mParams = par; } + const o2::itsmft::DigiParams& getDigitParams() const { return mParams; } + + // provide the common itsmft::GeometryTGeo to access matrices and segmentation + void setGeometry(const o2::its3::GeometryTGeo* gm) { mGeometry = gm; } + + uint32_t getEventROFrameMin() const { return mEventROFrameMin; } + uint32_t getEventROFrameMax() const { return mEventROFrameMax; } + void resetEventROFrames() + { + mEventROFrameMin = 0xffffffff; + mEventROFrameMax = 0; + } + + private: + void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID); + void registerDigits(o2::itsmft::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl); + + ExtraDig* getExtraDigBuffer(uint32_t roFrame) + { + if (mROFrameMin > roFrame) { + return nullptr; // nothing to do + } + int ind = roFrame - mROFrameMin; + while (ind >= int(mExtraBuff.size())) { + mExtraBuff.emplace_back(std::make_unique<ExtraDig>()); + } + return mExtraBuff[ind].get(); + } + + std::vector<SegmentationSuperAlpide> mSuperSegmentations; + static constexpr float sec2ns = 1e9; + + o2::itsmft::DigiParams mParams; ///< digitization parameters + o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record + o2::InteractionRecord mIRFirstSampledTF; ///< IR of the 1st sampled IR, noise-only ROFs will be inserted till this IR only + double mCollisionTimeWrtROF; + uint32_t mROFrameMin = 0; ///< lowest RO frame of current digits + uint32_t mROFrameMax = 0; ///< highest RO frame of current digits + uint32_t mNewROFrame = 0; ///< ROFrame corresponding to provided time + + uint32_t mEventROFrameMin = 0xffffffff; ///< lowest RO frame for processed events (w/o automatic noise ROFs) + uint32_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) + + std::unique_ptr<o2::itsmft::AlpideSimResponse> mAlpSimResp; // simulated response + + const o2::its3::GeometryTGeo* mGeometry = nullptr; ///< ITS OR MFT upgrade geometry + + std::vector<o2::itsmft::ChipDigitsContainer> mChips; ///< Array of chips digits containers + std::deque<std::unique_ptr<ExtraDig>> mExtraBuff; ///< burrer (per roFrame) for extra digits + + std::vector<o2::itsmft::Digit>* mDigits = nullptr; //! output digits + std::vector<o2::itsmft::ROFRecord>* mROFRecords = nullptr; //! output ROF records + o2::dataformats::MCTruthContainer<o2::MCCompLabel>* mMCLabels = nullptr; //! output labels + + ClassDefOverride(Digitizer, 2); +}; +} // namespace its3 +} // namespace o2 + +#endif /* ALICEO2_ITS3_DIGITIZER_H */ diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V11Geometry.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V11Geometry.h index 6be69cd8cc3e1..12d0fc9ab38cc 100644 --- a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V11Geometry.h +++ b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V11Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,8 @@ /// \file V11Geometry.h /// \brief Definition of the V11Geometry class -#ifndef ALICEO2_ITS_V11GEOMETRY_H_ -#define ALICEO2_ITS_V11GEOMETRY_H_ +#ifndef ALICEO2_ITS3_V11GEOMETRY_H_ +#define ALICEO2_ITS3_V11GEOMETRY_H_ #include <TMath.h> // for DegToRad, Cos, Sin, Tan #include <TObject.h> // for TObject diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V1Layer.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V1Layer.h deleted file mode 100644 index 8c7035ca6d6e5..0000000000000 --- a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V1Layer.h +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_ITS_UPGRADEV1LAYER_H_ -#define ALICEO2_ITS_UPGRADEV1LAYER_H_ - -#include <TGeoManager.h> // for gGeoManager -#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc -#include "ITS3Simulation/V11Geometry.h" // for V11Geometry -#include "ITS3Simulation/Detector.h" // for Detector, Detector::Model - -class TGeoArb8; - -class TGeoCombiTrans; - -class TGeoVolume; // lines 15-15 - -namespace o2 -{ -namespace its3 -{ - -/// This class defines the Geometry for the ITS using TGeo. This is a work class used -/// to study different configurations during the development of the new ITS structure -class V1Layer : public V11Geometry -{ - - public: - enum { - kStave, - kHalfStave, - kModule, - kChip, - kNHLevels - }; - - // Default constructor - V1Layer(); - - // Constructor setting debugging level - V1Layer(Int_t debug); - - // Constructor setting layer number and debugging level - V1Layer(Int_t lay, Int_t debug); - - /// Constructor setting layer number and debugging level - /// for a "turbo" layer (i.e. where staves overlap in phi) - V1Layer(Int_t lay, Bool_t turbo, Int_t debug); - - /// Copy constructor - V1Layer(const V1Layer& source); - - /// Assignment operator - V1Layer& operator=(const V1Layer& source); - - /// Default destructor - ~V1Layer() override; - - Bool_t isTurbo() const - { - return mIsTurbo; - }; - - Double_t getStaveThick() const - { - return mStaveThickness; - }; - - Double_t getStaveTilt() const - { - return mStaveTilt; - }; - - Double_t getStaveWidth() const - { - return mStaveWidth; - }; - - Double_t getSensorThick() const - { - return mSensorThickness; - }; - - Double_t getNumberOfStaves() const - { - return mNumberOfStaves; - }; - - Double_t getNumberOfChips() const - { - return mNumberOfChips; - }; - - Double_t getRadius() const - { - return mLayerRadius; - }; - - Double_t getPhi0() const - { - return mPhi0; - }; - - Double_t getZLength() const - { - return mZLength; - }; - - Int_t getChipType() const - { - return mChipTypeID; - } - - Int_t getNumberOfStavesPerParent() const - { - return mHierarchy[kStave]; - } - - Int_t getNumberOfHalfStavesPerParent() const - { - return mHierarchy[kHalfStave]; - } - - Int_t getNumberOfModulesPerParent() const - { - return mHierarchy[kModule]; - } - - Int_t getNumberOfChipsPerParent() const - { - return mHierarchy[kChip]; - } - - Detector::Model getStaveModel() const - { - return mStaveModel; - } - - void setStaveThick(Double_t t) - { - mStaveThickness = t; - }; - - /// Sets the Stave tilt angle (for turbo layers only) - /// \param t The stave tilt angle - void setStaveTilt(Double_t t); - - /// Sets the Stave width (for turbo layers only) - /// \param w The stave width - void setStaveWidth(Double_t w); - - void setSensorThick(Double_t t) - { - mSensorThickness = t; - }; - - void setNumberOfStaves(Int_t n) - { - mHierarchy[kStave] = mNumberOfStaves = n; - }; - - /// Sets the number of units in a stave: - /// for the Inner Barrel: the number of chips per stave - /// for the Outer Barrel: the number of modules per half stave - /// \param u the number of units - void setNumberOfUnits(Int_t u); - - void setRadius(Double_t r) - { - mLayerRadius = r; - }; - - void setPhi0(Double_t phi) - { - mPhi0 = phi; - } - - void setZLength(Double_t z) - { - mZLength = z; - }; - - void setChipType(Int_t tp) - { - mChipTypeID = tp; - } - - void setBuildLevel(Int_t buildLevel) - { - mBuildLevel = buildLevel; - } - - void setStaveModel(o2::its3::Detector::Model model) - { - mStaveModel = model; - } - - /// Creates the actual Layer and places inside its mother volume - /// \param motherVolume the TGeoVolume owing the volume structure - virtual void createLayer(TGeoVolume* motherVolume); - - private: - /// Creates the actual Layer and places inside its mother volume - /// A so-called "turbo" layer is a layer where staves overlap in phi - /// User can set width and tilt angle, no check is performed here - /// to avoid volume overlaps - /// \param motherVolume The TGeoVolume owing the volume structure - void createLayerTurbo(TGeoVolume* motherVolume); - - /// Computes the inner radius of the air container for the Turbo configuration - /// as the radius of either the circle tangent to the stave or the circle - /// passing for the stave's lower vertex. Returns the radius of the container - /// if >0, else flag to use the lower vertex - Double_t radiusOmTurboContainer(); - - /// Creates the actual Stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStave(const TGeoManager* mgr = gGeoManager); - - // TGeoVolume* createChip(Double_t x, Double_t z, const TGeoManager *mgr=gGeoManager); - - /// Creates the IB Module: (only the chips for the time being) - /// Returns the module as a TGeoVolume - /// \param xmod, ymod, zmod X, Y, Z module half lengths - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createModuleInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Creates the actual Chip - /// \param xchip,ychip,zchip The chip dimensions - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createChipInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Creates the OB Module: HIC + FPC + Carbon plate - /// Returns the module as a TGeoVolume - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createModuleOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create the chip stave for the Inner Barrel(Here we fake the halfstave volume to have the - /// same formal geometry hierarchy as for the Outer Barrel) - /// \param xsta, ysta, zsta X, Y, Z stave half lengths - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveStructInnerB(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create a dummy stave - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerBDummy(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager) const; - - /// Create the mechanical stave structure for Model 0 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB0(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 1 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB1(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 2.1 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB21(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 2.2 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB22(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 3 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB3(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the chip stave for the Outer Barrel - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create dummy stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterBDummy(const TGeoManager* mgr = gGeoManager) const; - - /// Creation of the mechanical stave structure for the Outer Barrel as in v0 - /// (we fake the module and halfstave volumes to have always - /// the same formal geometry hierarchy) - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterB0(const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical half stave structure or the Outer Barrel as in TDR - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterB1(const TGeoManager* mgr = gGeoManager); - - /// Create the space frame for the Outer Barrel - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create dummy stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterBDummy(const TGeoManager* mgr = gGeoManager) const; - - /// Create the space frame for the Outer Barrel (Model 1) - /// Returns a TGeoVolume with the Space Frame of a stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterB1(const TGeoManager* mgr = gGeoManager); - - /// Creates the V-shaped sides of the OB space frame (from a similar method with same - /// name and function in V11GeometrySDD class by L.Gaudichet) - TGeoArb8* createStaveSide(const char* name, Double_t dz, Double_t angle, Double_t xSign, Double_t L, Double_t H, - Double_t l); - - /// Help method to create a TGeoCombiTrans matrix from a similar method with same name and - /// function in V11GeometrySDD class by L.Gaudichet) - /// Returns the TGeoCombiTrans which make a translation in y and z and a rotation in phi - /// in the global coord system. If planeSym = true, the rotation places the object - /// symetrically (with respect to the transverse plane) to its position in the - /// case planeSym = false - TGeoCombiTrans* createCombiTrans(const char* name, Double_t dy, Double_t dz, Double_t dphi, - Bool_t planeSym = kFALSE); - - /// Help method to add a translation to a TGeoCombiTrans matrix (from a similar method - /// with same name and function in V11GeometrySDD class by L.Gaudichet) - void addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx = 0, Double_t dy = 0, Double_t dz = 0) const; - - Int_t mLayerNumber; ///< Current layer number - Double_t mPhi0; ///< lab phi of 1st stave, in degrees!!! - Double_t mLayerRadius; ///< Inner radius of this layer - Double_t mZLength; ///< Z length of this layer - Double_t mSensorThickness; ///< Sensor thickness - Double_t mStaveThickness; ///< Stave thickness - Double_t mStaveWidth; ///< Stave width (for turbo layers only) - Double_t mStaveTilt; ///< Stave tilt angle (for turbo layers only) in degrees - Int_t mNumberOfStaves; ///< Number of staves in this layer - Int_t mNumberOfModules; ///< Number of modules per container if defined (HalfStave, Stave, whatever is - ///< container) - Int_t mNumberOfChips; ///< Number chips per container (module, HalfStave, Stave, whatever is - /// container) - Int_t mHierarchy[kNHLevels]; ///< array to query number of staves, hstaves, modules, chips per its parent volume - - UInt_t mChipTypeID; ///< detector type id - Bool_t mIsTurbo; ///< True if this layer is a "turbo" layer - Int_t mBuildLevel; ///< Used for material studies - - Detector::Model mStaveModel; ///< The stave model - - // Parameters for the geometry - - // General Parameters - static const Int_t sNumberOmInnerLayers; ///< Number of IB Layers - - static const Double_t sDefaultSensorThick; ///< Default sensor thickness - static const Double_t sDefaultStaveThick; ///< Default stave thickness - - // Inner Barrel Parameters - static const Int_t sIBChipsPerRow; ///< IB chips per row in module - static const Int_t sIBNChipRows; ///< IB chip rows in module - - // Outer Barrel Parameters - static const Int_t sOBChipsPerRow; ///< OB chips per row in module - static const Int_t sOBNChipRows; ///< OB chip rows in module - - static const Double_t sOBHalfStaveWidth; ///< OB Half Stave Width - static const Double_t sOBModuleWidth; ///< OB Module Width - static const Double_t sOBModuleGap; ///< Gap between OB modules - static const Double_t sOBChipXGap; ///< Gap between OB chips on X - static const Double_t sOBChipZGap; ///< Gap between OB chips on Z - static const Double_t sOBFlexCableAlThick; ///< Thickness of FPC Aluminum - static const Double_t sOBFlexCableKapThick; ///< Thickness of FPC Kapton - static const Double_t sOBBusCableAlThick; ///< Thickness of Bus Aluminum - static const Double_t sOBBusCableKapThick; ///< Thickness of Bus Kapton - static const Double_t sOBCarbonPlateThick; ///< OB Carbon Plate Thickness - static const Double_t sOBColdPlateThick; ///< OB Cold Plate Thickness - static const Double_t sOBGlueThick; ///< OB Glue total Thickness - static const Double_t sOBModuleZLength; ///< OB Chip Length along Z - static const Double_t sOBHalfStaveYTrans; ///< OB half staves Y transl. - static const Double_t sOBHalfStaveXOverlap; ///< OB half staves X overlap - static const Double_t sOBGraphiteFoilThick; ///< OB graphite foil thickness - static const Double_t sOBCoolTubeInnerD; ///< OB cooling inner diameter - static const Double_t sOBCoolTubeThick; ///< OB cooling tube thickness - static const Double_t sOBCoolTubeXDist; ///< OB cooling tube separation - - static const Double_t sOBSpaceFrameWidth; ///< OB Space Frame Width - static const Double_t sOBSpaceFrameTotHigh; ///< OB Total Y Height - static const Double_t sOBSFrameBeamRadius; ///< OB Space Frame Beam Radius - static const Double_t sOBSpaceFrameLa; ///< Parameters defining... - static const Double_t sOBSpaceFrameHa; ///< ...the V side shape... - static const Double_t sOBSpaceFrameLb; ///< ...of the carbon... - static const Double_t sOBSpaceFrameHb; ///< ...OB Space Frame - static const Double_t sOBSpaceFrameL; ///< OB SF - static const Double_t sOBSFBotBeamAngle; ///< OB SF bottom beam angle - static const Double_t sOBSFrameBeamSidePhi; ///< OB SF side beam angle - - ClassDefOverride(V1Layer, 0); // ITS v1 geometry -}; -} // namespace its3 -} // namespace o2 - -#endif diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Layer.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Layer.h index f4b90ba9c1f32..b5f31d3b03264 100644 --- a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Layer.h +++ b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Layer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h index 77db7214ad06f..3241e36517610 100644 --- a/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h +++ b/Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,6 +50,10 @@ class V3Services : public V11Geometry /// Default destructor ~V3Services() override; + /// Creates the supports for IB Layers (cylinder and foam wedges) + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createInnerBarrelSupports(const TGeoManager* mgr = gGeoManager); + /// Creates the Inner Barrel End Wheels on Side A /// \param mgr The GeoManager (used only to get the proper material) TGeoVolume* createIBEndWheelsSideA(const TGeoManager* mgr = gGeoManager); @@ -92,6 +97,14 @@ class V3Services : public V11Geometry void createOBConeSideC(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); private: + /// Creates a single Foam Wedge (with carbon fleece and glue attached) + /// \param rIn the inner radius + /// \param rOut the outer radius + /// \param zlen the half length along Z + /// \param phi the angular aperture + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createFoamWedge(const Double_t rIn, const Double_t rOut, const Double_t zLen, const Double_t phi, const TGeoManager* mgr = gGeoManager); + /// Creates a single Inner Barrel End Wheel on Side A /// \param iLay the layer number /// \param endWheel the End Wheel volume assembly diff --git a/Detectors/Upgrades/IT3/simulation/src/Detector.cxx b/Detectors/Upgrades/IT3/simulation/src/Detector.cxx index 760fecf285dc2..8660d33b79ef8 100644 --- a/Detectors/Upgrades/IT3/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/IT3/simulation/src/Detector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,33 +57,16 @@ using namespace o2::its3; Detector::Detector() : o2::base::DetImpl<Detector>("IT3", kTRUE), mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ mNumberOfDetectors(-1), mModifyGeometry(kFALSE), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(kIBModel0), - mStaveModelOuterBarrel(kOBModel0) + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) { } -static double radii2Turbo(double rMin, double rMid, double rMax, double sensW) -{ - // compute turbo angle from radii and sensor width - return TMath::ASin((rMax * rMax - rMin * rMin) / (2 * rMid * sensW)) * TMath::RadToDeg(); -} - // We need this as a method to access members -void Detector::configITS(Detector* its) +void Detector::configITS3() { - // build ITS upgrade detector - const int kNLr = 7; - const int kNLrInner = 3; + // build ITS3 upgrade detector const int kBuildLevel = 0; const int kSensTypeID = 0; // dummy id for Alpide sensor @@ -96,148 +80,72 @@ void Detector::configITS(Detector* its) kPhi0, kNStave, kNPar }; + + std::vector<std::array<double, 2>> IBtdr5dat; // 18 24 30 its2 = (22 mm, 31 mm and 39 mm and 194 mm, 247 mm, 353 mm and 405 mm) + IBtdr5dat.emplace_back(std::array<double, 2>{1.8f, 27.15}); + IBtdr5dat.emplace_back(std::array<double, 2>{2.4f, 27.15}); + IBtdr5dat.emplace_back(std::array<double, 2>{3.0f, 27.15}); + IBtdr5dat.emplace_back(std::array<double, 2>{7.0f, 27.15}); + // Radii are from last TDR (ALICE-TDR-017.pdf Tab. 1.1, rMid is mean value) - const double tdr5dat[kNLr][kNPar] = { - {2.24, 2.34, 2.67, 9., 16.42, 12}, // for each inner layer: rMin,rMid,rMax,NChip/Stave, phi0, nStaves - {3.01, 3.15, 3.46, 9., 12.18, 16}, - {3.78, 3.93, 4.21, 9., 9.55, 20}, + // OB only !! + const double OBtdr5dat[sNumberOuterLayers][kNPar] = { {-1, 19.6, -1, 4., 0., 24}, // for others: -, rMid, -, NMod/HStave, phi0, nStaves // 24 was 49 {-1, 24.55, -1, 4., 0., 30}, // 30 was 61 {-1, 34.39, -1, 7., 0., 42}, // 42 was 88 {-1, 39.34, -1, 7., 0., 48} // 48 was 100 }; - const int nChipsPerModule = 7; // For OB: how many chips in a row - const double zChipGap = 0.01; // For OB: gap in Z between chips - const double zModuleGap = 0.01; // For OB: gap in Z between modules - double dzLr, rLr, phi0, turbo; + double rLr, phi0; int nStaveLr, nModPerStaveLr; - // its->setStaveModelIB(o2::its3::Detector::kIBModel4); - its->setStaveModelOB(o2::its3::Detector::kOBModel2); - const int kNWrapVol = 3; const double wrpRMin[kNWrapVol] = {2.1, 19.3, 33.32}; const double wrpRMax[kNWrapVol] = {15.4, 29.14, 46.0}; const double wrpZSpan[kNWrapVol] = {70., 93., 163.6}; for (int iw = 0; iw < kNWrapVol; iw++) { - its->defineWrapperVolume(iw, wrpRMin[iw], wrpRMax[iw], wrpZSpan[iw]); + defineWrapperVolume(iw, wrpRMin[iw], wrpRMax[iw], wrpZSpan[iw]); } - // for (int idLr = 0; idLr < kNLr; idLr++) { // Build OB only (4 layers) - for (int idLr = mNumberOfInnerLayers; idLr < mTotalNumberOfLayers; idLr++) { - int im = idLr - mNumberOfInnerLayers + kNLrInner; - rLr = tdr5dat[im][kRmd]; - phi0 = tdr5dat[im][kPhi0]; + for (int idLr{0}; idLr < sNumberOuterLayers; idLr++) { + // int im = idLr - mNumberOfInnerLayers + sNumberInnerLayers; + rLr = OBtdr5dat[idLr][kRmd]; + phi0 = OBtdr5dat[idLr][kPhi0]; - nStaveLr = TMath::Nint(tdr5dat[im][kNStave]); - nModPerStaveLr = TMath::Nint(tdr5dat[im][kNModPerStave]); + nStaveLr = TMath::Nint(OBtdr5dat[idLr][kNStave]); + nModPerStaveLr = TMath::Nint(OBtdr5dat[idLr][kNModPerStave]); int nChipsPerStaveLr = nModPerStaveLr; - // if (idLr >= kNLrInner) { - its->defineLayer(idLr, phi0, rLr, nStaveLr, nModPerStaveLr, ChipThicknessOB, Segmentation::SensorLayerThickness, - kSensTypeID, kBuildLevel); - // } else { - // turbo = radii2Turbo(tdr5dat[idLr][kRmn], rLr, tdr5dat[idLr][kRmx], Segmentation::SensorSizeRows); - // its->defineLayerTurbo(idLr, phi0, rLr, nStaveLr, nChipsPerStaveLr, Segmentation::SensorSizeRows, turbo, - // ChipThicknessIB, Segmentation::SensorLayerThickness, kSensTypeID, kBuildLevel); - // } + defineLayer(sNumberInnerLayers + idLr, phi0, rLr, nStaveLr, nModPerStaveLr, ChipThicknessOB, Segmentation::SensorLayerThickness, + kSensTypeID, kBuildLevel); } - // From Mario Sitta's hack - std::vector<std::array<double, 2>> tdr5data; // 18 24 30 its2 = (22 mm, 31 mm and 39 mm and 194 mm, 247 mm, 353 mm and 405 mm) - tdr5data.emplace_back(std::array<double, 2>{1.8f, 27.15}); - tdr5data.emplace_back(std::array<double, 2>{2.4f, 27.15}); - tdr5data.emplace_back(std::array<double, 2>{3.0f, 27.15}); - tdr5data.emplace_back(std::array<double, 2>{7.0f, 27.15}); - static constexpr float SensorLayerThickness = 30.e-4; - its->setStaveModelOB(o2::its3::Detector::kOBModel2); - its->createOuterBarrel(kTRUE); + createOuterBarrel(kTRUE); auto idLayer{0}; - for (auto& layerData : tdr5data) { - its->defineInnerLayerITS3(idLayer, layerData[0], layerData[1], SensorLayerThickness, 0, 0); + for (auto& layerData : IBtdr5dat) { + defineInnerLayerITS3(idLayer, layerData[0], layerData[1], SensorLayerThickness, 0, 0); ++idLayer; } - its->createOuterBarrel(kTRUE); -} -// Detector::Detector(Bool_t active) -// : o2::base::DetImpl<Detector>("ITS3", active), -// mTrackData(), -// /* -// mHitStarted(false), -// mTrkStatusStart(), -// mPositionStart(), -// mMomentumStart(), -// mEnergyLoss(), -// */ -// mNumberOfInnerLayers(sNumberInnerLayers), -// mNumberOfDetectors(-1), -// mModifyGeometry(kFALSE), -// mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), -// mStaveModelInnerBarrel(kIBModel0), -// mStaveModelOuterBarrel(kOBModel2) -// { - -// mTotalNumberOfLayers = mNumberOfInnerLayers + (sNumberLayers - sNumberInnerLayers); - -// createAllArrays(); - -// for (Int_t j = 0; j < sNumberLayers; j++) { -// mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer -// } - -// if (sNumberLayers > 0) { // if not, we'll Fatal-ize in CreateGeometry -// for (Int_t j = 0; j < sNumberLayers; j++) { -// mITS3Layer[j] = kFALSE; -// mLayerPhi0[j] = 0; -// mLayerRadii[j] = 0.; -// mLayerZLen[j] = 0.; -// mStavePerLayer[j] = 0; -// mUnitPerStave[j] = 0; -// mChipThickness[j] = 0.; -// mStaveWidth[j] = 0.; -// mStaveTilt[j] = 0.; -// mDetectorThickness[j] = 0.; -// mChipTypeID[j] = 0; -// mBuildLevel[j] = 0; -// mGeometry[j] = nullptr; -// } -// } -// mServicesGeometry = nullptr; - -// for (int i = sNumberOfWrapperVolumes; i--;) { -// mWrapperMinRadius[i] = mWrapperMaxRadius[i] = mWrapperZSpan[i] = -1; -// } - -// configITS(this); -// } + // Redefine Wrapper Volume 0 using information on IB radii + static constexpr float safety = 0.5; // Educated guess, may be improved + defineWrapperVolume(0, IBtdr5dat[0][0] - safety, IBtdr5dat[3][0] + safety, wrpZSpan[0]); + LOG(INFO) << "HERE!\n"; +} Detector::Detector(Bool_t active) : o2::base::DetImpl<Detector>("IT3", active), mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ - mNumberOfInnerLayers(4), + mNumberOfInnerLayers(sNumberInnerLayers), + mTotalNumberOfLayers(sNumberLayers), mNumberOfDetectors(-1), mModifyGeometry(kFALSE), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(kIBModel0), - mStaveModelOuterBarrel(kOBModel0) + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) { - - mTotalNumberOfLayers = mNumberOfInnerLayers + (sNumberLayers - sNumberInnerLayers); - createAllArrays(); - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer } @@ -245,14 +153,11 @@ Detector::Detector(Bool_t active) if (mTotalNumberOfLayers > 0) { // if not, we'll Fatal-ize in CreateGeometry for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { mITS3Layer[j] = kFALSE; - mLayerPhi0[j] = 0; mLayerRadii[j] = 0.; mLayerZLen[j] = 0.; mStavePerLayer[j] = 0; mUnitPerStave[j] = 0; mChipThickness[j] = 0.; - mStaveWidth[j] = 0.; - mStaveTilt[j] = 0.; mDetectorThickness[j] = 0.; mChipTypeID[j] = 0; mBuildLevel[j] = 0; @@ -265,29 +170,17 @@ Detector::Detector(Bool_t active) mWrapperMinRadius[i] = mWrapperMaxRadius[i] = mWrapperZSpan[i] = -1; } - configITS(this); + configITS3(); } Detector::Detector(const Detector& rhs) : o2::base::DetImpl<Detector>(rhs), mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ mNumberOfInnerLayers(rhs.mNumberOfInnerLayers), mNumberOfDetectors(rhs.mNumberOfDetectors), mModifyGeometry(rhs.mModifyGeometry), - - /// Container for data points - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(rhs.mStaveModelInnerBarrel), - mStaveModelOuterBarrel(rhs.mStaveModelOuterBarrel) + mHits(o2::utils::createSimVector<o2::itsmft::Hit>()) { - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer } @@ -295,9 +188,7 @@ Detector::Detector(const Detector& rhs) Detector::~Detector() { - if (mHits) { - // delete mHits; o2::utils::freeSimVector(mHits); } } @@ -320,15 +211,9 @@ Detector& Detector::operator=(const Detector& rhs) base::Detector::operator=(rhs); mNumberOfDetectors = rhs.mNumberOfDetectors; - mModifyGeometry = rhs.mModifyGeometry; - - /// Container for data points mHits = nullptr; - mStaveModelInnerBarrel = rhs.mStaveModelInnerBarrel; - mStaveModelOuterBarrel = rhs.mStaveModelOuterBarrel; - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer } @@ -346,23 +231,17 @@ void Detector::createAllArrays() mLayerID = new Int_t[mTotalNumberOfLayers]; mLayerName = new TString[mTotalNumberOfLayers]; - mWrapperLayerId = new Int_t[mTotalNumberOfLayers]; - mTurboLayer = new Bool_t[mTotalNumberOfLayers]; mITS3Layer = new Bool_t[mTotalNumberOfLayers]; - mLayerPhi0 = new Double_t[mTotalNumberOfLayers]; mLayerRadii = new Double_t[mTotalNumberOfLayers]; mLayerZLen = new Double_t[mTotalNumberOfLayers]; mStavePerLayer = new Int_t[mTotalNumberOfLayers]; mUnitPerStave = new Int_t[mTotalNumberOfLayers]; mChipThickness = new Double_t[mTotalNumberOfLayers]; - mStaveWidth = new Double_t[mTotalNumberOfLayers]; - mStaveTilt = new Double_t[mTotalNumberOfLayers]; mDetectorThickness = new Double_t[mTotalNumberOfLayers]; mChipTypeID = new UInt_t[mTotalNumberOfLayers]; mBuildLevel = new Int_t[mTotalNumberOfLayers]; - mGeometry = new V3Layer*[mTotalNumberOfLayers]; } @@ -370,14 +249,10 @@ void Detector::InitializeO2Detector() { // Define the list of sensitive volumes defineSensitiveVolumes(); - for (int i = 0; i < mTotalNumberOfLayers; i++) { mLayerID[i] = gMC ? TVirtualMC::GetMC()->VolId(mLayerName[i]) : 0; } - mGeometryTGeo = GeometryTGeo::Instance(); - // FairRuntimeDb* rtdb= FairRun::Instance()->GetRuntimeDb(); - // O2itsGeoPar* par=(O2itsGeoPar*)(rtdb->getContainer("O2itsGeoPar")); } Bool_t Detector::ProcessHits(FairVolume* vol) @@ -553,6 +428,9 @@ void Detector::createMaterials() Float_t wRohac[4] = {9., 13., 1., 2.}; Float_t dRohac = 0.05; + // Araldite 2011 + Float_t dAraldite = 1.05; + o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir); o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir); @@ -621,6 +499,15 @@ void Detector::createMaterials() o2::base::Detector::Mixture(32, "ROHACELL$", aRohac, zRohac, dRohac, -4, wRohac); o2::base::Detector::Medium(32, "ROHACELL$", 32, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // ERG Duocel + o2::base::Detector::Material(33, "ERGDUOCEL$", 12.0107, 6, 0.06, 999, 999); + o2::base::Detector::Medium(33, "ERGDUOCEL$", 33, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + + // Impregnated carbon fleece + // (as educated guess we assume 50% carbon fleece 50% Araldite glue) + o2::base::Detector::Material(34, "IMPREG_FLEECE$", 12.0107, 6, 0.5 * (dAraldite + 0.4), 999, 999); + o2::base::Detector::Medium(34, "IMPREG_FLEECE$", 34, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + // PEEK CF30 o2::base::Detector::Mixture(19, "PEEKCF30$", aPEEK, zPEEK, dPEEK, -3, wPEEK); o2::base::Detector::Medium(19, "PEEKCF30$", 19, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); @@ -688,7 +575,7 @@ void Detector::defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Doubl mWrapperZSpan[id] = zspan; } -void Detector::defineLayer(Int_t nlay, double phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick, +void Detector::defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick, Double_t dthick, UInt_t dettypeID, Int_t buildLevel) { // Sets the layer parameters @@ -716,64 +603,17 @@ void Detector::defineLayer(Int_t nlay, double phi0, Double_t r, Int_t nstav, Int return; } - mTurboLayer[nlay] = kFALSE; - mLayerPhi0[nlay] = phi0; - mLayerRadii[nlay] = r; - mStavePerLayer[nlay] = nstav; - mUnitPerStave[nlay] = nunit; - mChipThickness[nlay] = lthick; - mDetectorThickness[nlay] = dthick; - mChipTypeID[nlay] = dettypeID; - mBuildLevel[nlay] = buildLevel; -} - -void Detector::defineLayerTurbo(Int_t nlay, Double_t phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t width, - Double_t tilt, Double_t lthick, Double_t dthick, UInt_t dettypeID, Int_t buildLevel) -{ - // Sets the layer parameters for a "turbo" layer - // (i.e. a layer whose staves overlap in phi) - // Inputs: - // nlay layer number - // phi0 phi of 1st stave - // r layer radius - // nstav number of staves - // nunit IB: number of chips per stave - // OB: number of modules per half stave - // width stave width - // tilt layer tilt angle (degrees) - // lthick stave thickness (if omitted, defaults to 0) - // dthick detector thickness (if omitted, defaults to 0) - // dettypeID ?? - // buildLevel (if 0, all geometry is build, used for material budget studies) - // Outputs: - // none. - // Return: - // none. - - LOG(INFO) << "L# " << nlay << " Phi:" << phi0 << " R:" << r << " Nst:" << nstav << " Nunit:" << nunit - << " W:" << width << " Tilt:" << tilt << " Lthick:" << lthick << " Dthick:" << dthick - << " DetID:" << dettypeID << " B:" << buildLevel; - - if (nlay >= mTotalNumberOfLayers || nlay < 0) { - LOG(ERROR) << "Wrong layer number " << nlay; - return; - } - - mTurboLayer[nlay] = kTRUE; mLayerPhi0[nlay] = phi0; mLayerRadii[nlay] = r; mStavePerLayer[nlay] = nstav; mUnitPerStave[nlay] = nunit; mChipThickness[nlay] = lthick; - mStaveWidth[nlay] = width; - mStaveTilt[nlay] = tilt; mDetectorThickness[nlay] = dthick; mChipTypeID[nlay] = dettypeID; mBuildLevel[nlay] = buildLevel; } -void Detector::defineInnerLayerITS3(Int_t nlay, Double_t r, Double_t zlen, - Double_t dthick, UInt_t dettypeID, Int_t buildLevel) +void Detector::defineInnerLayerITS3(Int_t nlay, Double_t r, Double_t zlen, Double_t dthick, UInt_t dettypeID, Int_t buildLevel) { // Sets the layer parameters // Inputs: @@ -796,7 +636,6 @@ void Detector::defineInnerLayerITS3(Int_t nlay, Double_t r, Double_t zlen, return; } - mTurboLayer[nlay] = kFALSE; mITS3Layer[nlay] = kTRUE; mLayerRadii[nlay] = r; mLayerZLen[nlay] = zlen; @@ -806,8 +645,7 @@ void Detector::defineInnerLayerITS3(Int_t nlay, Double_t r, Double_t zlen, LOG(INFO) << "Added layer: " << nlay << std::endl; } -void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& width, - Double_t& tilt, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const +void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const { // Gets the layer parameters // Inputs: @@ -835,8 +673,6 @@ void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t r = mLayerRadii[nlay]; nstav = mStavePerLayer[nlay]; nmod = mUnitPerStave[nlay]; - width = mStaveWidth[nlay]; - tilt = mStaveTilt[nlay]; lthick = mChipThickness[nlay]; dthick = mDetectorThickness[nlay]; dettype = mChipTypeID[nlay]; @@ -921,7 +757,6 @@ void Detector::constructDetectorGeometry() { // Create the geometry and insert it in the mother volume ITSV TGeoManager* geoManager = gGeoManager; - TGeoVolume* vALIC = geoManager->GetVolume("barrel"); if (!vALIC) { @@ -949,9 +784,6 @@ void Detector::constructDetectorGeometry() if (mChipThickness[j] < 0 && !mITS3Layer[j]) { LOG(FATAL) << "Wrong chip thickness for layer " << j << "(" << mChipThickness[j] << ")"; } - if (mTurboLayer[j] && mStaveWidth[j] <= 0) { - LOG(FATAL) << "Wrong stave width for layer " << j << "(" << mStaveWidth[j] << ")"; - } if (mDetectorThickness[j] < 0) { LOG(FATAL) << "Wrong Sensor thickness for layer " << j << "(" << mDetectorThickness[j] << ")"; } @@ -972,9 +804,9 @@ void Detector::constructDetectorGeometry() // Create the wrapper volumes TGeoVolume** wrapVols = nullptr; - if (sNumberOfWrapperVolumes && mCreateOuterBarrel) { + if (sNumberOfWrapperVolumes) { wrapVols = new TGeoVolume*[sNumberOfWrapperVolumes]; - for (int id = 1; id < sNumberOfWrapperVolumes; id++) { + for (int id = 0; id < sNumberOfWrapperVolumes; id++) { wrapVols[id] = createWrapperVolume(id); vITSV->AddNode(wrapVols[id], 1, nullptr); } @@ -987,15 +819,7 @@ void Detector::constructDetectorGeometry() for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { TGeoVolume* dest = vITSV; mWrapperLayerId[j] = -1; - - if (mTurboLayer[j]) { - mGeometry[j] = new V3Layer(j, kTRUE, kFALSE); - mGeometry[j]->setStaveWidth(mStaveWidth[j]); - mGeometry[j]->setStaveTilt(mStaveTilt[j]); - } else { - mGeometry[j] = new V3Layer(j, kFALSE); - } - + mGeometry[j] = new V3Layer(j, kFALSE); mGeometry[j]->setNumberOfInnerLayers(mNumberOfInnerLayers); if (mITS3Layer[j]) { @@ -1010,12 +834,6 @@ void Detector::constructDetectorGeometry() mGeometry[j]->setChipType(mChipTypeID[j]); mGeometry[j]->setBuildLevel(mBuildLevel[j]); - if (j < mNumberOfInnerLayers) { - mGeometry[j]->setStaveModel(mStaveModelInnerBarrel); - } else { - mGeometry[j]->setStaveModel(mStaveModelOuterBarrel); - } - LOG(DEBUG1) << "mBuildLevel: " << mBuildLevel[j]; if (mChipThickness[j] != 0) { @@ -1025,31 +843,27 @@ void Detector::constructDetectorGeometry() mGeometry[j]->setSensorThick(mDetectorThickness[j]); } - if (mCreateOuterBarrel && j >= mNumberOfInnerLayers) { - for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) { - if (mLayerRadii[j] > mWrapperMinRadius[iw] && mLayerRadii[j] < mWrapperMaxRadius[iw]) { - LOG(DEBUG) << "Will embed layer " << j << " in wrapper volume " << iw; + for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) { + if (mLayerRadii[j] > mWrapperMinRadius[iw] && mLayerRadii[j] < mWrapperMaxRadius[iw]) { + LOG(DEBUG) << "Will embed layer " << j << " in wrapper volume " << iw; - dest = wrapVols[iw]; - mWrapperLayerId[j] = iw; - break; - } + dest = wrapVols[iw]; + mWrapperLayerId[j] = iw; + break; } } + mGeometry[j]->createLayer(dest); } // Finally create the services mServicesGeometry = new V3Services(); - // createInnerBarrelServices(wrapVols[0]); - // createMiddlBarrelServices(wrapVols[1]); - // createOuterBarrelServices(wrapVols[2]); - // createOuterBarrelSupports(vITSV); + createInnerBarrelServices(wrapVols[0]); + createMiddlBarrelServices(wrapVols[1]); + createOuterBarrelServices(wrapVols[2]); + createOuterBarrelSupports(vITSV); - // TEMPORARY - These routines will be obsoleted once the new services are completed - TEMPORARY - // createServiceBarrel(kTRUE, wrapVols[0]); - // createServiceBarrel(kFALSE, wrapVols[2]); delete[] wrapVols; // delete pointer only, not the volumes } @@ -1065,26 +879,15 @@ void Detector::createInnerBarrelServices(TGeoVolume* motherVolume) // // Return: // - // Created: 15 May 2019 Mario Sitta - // (partially based on P.Namwongsa implementation in AliRoot) - // Updated: 19 Jun 2019 Mario Sitta IB Side A added - // Updated: 21 Oct 2019 Mario Sitta CYSS added + // Created: 11 Feb 2021 Mario Sitta + // (Version rewritten for ITS3 geometry) // - // Create the End Wheels on Side A - TGeoVolume* endWheelsA = mServicesGeometry->createIBEndWheelsSideA(); - - motherVolume->AddNode(endWheelsA, 1, nullptr); - - // Create the End Wheels on Side C - TGeoVolume* endWheelsC = mServicesGeometry->createIBEndWheelsSideC(); + // Create and insert the IB Layer supports (cylinder and foam wedges) + TGeoVolume* ibSupports = mServicesGeometry->createInnerBarrelSupports(); - motherVolume->AddNode(endWheelsC, 1, nullptr); - - // Create the CYSS Assembly (i.e. the supporting half cylinder and cone) - TGeoVolume* cyss = mServicesGeometry->createCYSSAssembly(); - - motherVolume->AddNode(cyss, 1, nullptr); + motherVolume->AddNode(ibSupports, 1, nullptr); + motherVolume->AddNode(ibSupports, 2, new TGeoRotation("", 180, 0, 0)); } void Detector::createMiddlBarrelServices(TGeoVolume* motherVolume) @@ -1153,42 +956,6 @@ void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume) mServicesGeometry->createOBConeSideC(motherVolume); } -// Service Barrel -void Detector::createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr) -{ - // Creates the Service Barrel (as a simple cylinder) for IB and OB - // Inputs: - // innerBarrel : if true, build IB service barrel, otherwise for OB - // dest : the mother volume holding the service barrel - // mgr : the gGeoManager pointer (used to get the material) - // - - Double_t rminIB = 4.7; - Double_t rminOB = 43.9; - Double_t zLenOB; - Double_t cInt = 0.22; // dimensioni cilindro di supporto interno - Double_t cExt = 1.00; // dimensioni cilindro di supporto esterno - // Double_t phi1 = 180; - // Double_t phi2 = 360; - - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT3_CarbonFleece$"); - - if (innerBarrel) { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - // TGeoTube*ibSuppSh = new TGeoTubeSeg(rminIB,rminIB+cInt,zLenOB,phi1,phi2); - auto* ibSuppSh = new TGeoTube(rminIB, rminIB + cInt, zLenOB); - auto* ibSupp = new TGeoVolume("ibSuppCyl", ibSuppSh, medCarbonFleece); - dest->AddNode(ibSupp, 1); - } else { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - auto* obSuppSh = new TGeoTube(rminOB, rminOB + cExt, zLenOB); - auto* obSupp = new TGeoVolume("obSuppCyl", obSuppSh, medCarbonFleece); - dest->AddNode(obSupp, 1); - } - - return; -} - void Detector::addAlignableVolumes() const { // @@ -1198,7 +965,7 @@ void Detector::addAlignableVolumes() const // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) // - LOG(INFO) << "Add ITS alignable volumes"; + LOG(INFO) << "Add ITS3 alignable volumes"; if (!gGeoManager) { LOG(FATAL) << "TGeoManager doesn't exist !"; @@ -1233,11 +1000,7 @@ void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) TString wrpV = mWrapperLayerId[lr] != -1 ? Form("%s%d_1", GeometryTGeo::getITSWrapVolPattern(), mWrapperLayerId[lr]) : ""; TString path; - if (mCreateOuterBarrel && (lr >= mNumberOfInnerLayers)) { - path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr); - } else { - path = Form("%s/%s%d_1", parent.Data(), GeometryTGeo::getITSLayerPattern(), lr); - } + path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr); TString sname = GeometryTGeo::composeSymNameLayer(lr); LOG(DEBUG) << "Add " << sname << " <-> " << path; @@ -1366,10 +1129,9 @@ void Detector::defineSensitiveVolumes() { TGeoManager* geoManager = gGeoManager; TGeoVolume* v; - TString volumeName; - // The names of the ITS sensitive volumes have the format: ITSUSensor(0...sNumberLayers-1) + // The names of the ITS3 sensitive volumes have the format: ITSUSensor(0...sNumberLayers-1) for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { volumeName = GeometryTGeo::getITSSensorPattern() + TString::Itoa(j, 10); v = geoManager->GetVolume(volumeName.Data()); @@ -1384,84 +1146,4 @@ Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TV mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); return &(mHits->back()); } - -void Detector::Print(std::ostream* os) const -{ - // Standard output format for this class. - // Inputs: - // ostream *os The output stream - // Outputs: - // none. - // Return: - // none. - -#if defined __GNUC__ -#if __GNUC__ > 2 - std::ios::fmtflags fmt; -#else - Int_t fmt; -#endif -#else -#if defined __ICC || defined __ECC || defined __xlC__ - ios::fmtflags fmt; -#else - Int_t fmt; -#endif -#endif - // RS: why do we need to pring this garbage? - - // fmt = os->setf(std::ios::scientific); // set scientific floating point output - // fmt = os->setf(std::ios::hex); // set hex for mStatus only. - // fmt = os->setf(std::ios::dec); // every thing else decimel. - // *os << mModule << " "; - // *os << mEnergyDepositionStep << " " << mTof; - // *os << " " << mStartingStepX << " " << mStartingStepY << " " << mStartingStepZ; - // *os << " " << endl; - // os->flags(fmt); // reset back to old formating. - return; -} - -void Detector::Read(std::istream* is) -{ - // Standard input format for this class. - // Inputs: - // istream *is the input stream - // Outputs: - // none. - // Return: - // none. - // RS no need to read garbage - return; -} - -std::ostream& operator<<(std::ostream& os, Detector& p) -{ - // Standard output streaming function. - // Inputs: - // ostream os The output stream - // Detector p The his to be printed out - // Outputs: - // none. - // Return: - // The input stream - - p.Print(&os); - return os; -} - -std::istream& operator>>(std::istream& is, Detector& r) -{ - // Standard input streaming function. - // Inputs: - // istream is The input stream - // Detector p The Detector class to be filled from this input stream - // Outputs: - // none. - // Return: - // The input stream - - r.Read(&is); - return is; -} - ClassImp(o2::its3::Detector); diff --git a/Detectors/Upgrades/IT3/simulation/src/Digitizer.cxx b/Detectors/Upgrades/IT3/simulation/src/Digitizer.cxx new file mode 100644 index 0000000000000..267be2426106a --- /dev/null +++ b/Detectors/Upgrades/IT3/simulation/src/Digitizer.cxx @@ -0,0 +1,447 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digitizer.cxx +/// \brief Implementation of the ITS3 digitizer + +#include "DataFormatsITSMFT/Digit.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITS3Simulation/Digitizer.h" +#include "MathUtils/Cartesian.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsRaw/HBFUtils.h" + +#include <TRandom.h> +#include <climits> +#include <vector> +#include <numeric> +#include "FairLogger.h" // for LOG + +using o2::itsmft::Digit; +using o2::itsmft::Hit; +using Segmentation = o2::itsmft::SegmentationAlpide; +using SuperSegmentation = o2::its3::SegmentationSuperAlpide; +using o2::itsmft::AlpideRespSimMat; +using o2::itsmft::PreDigit; + +using namespace o2::its3; +// using namespace o2::base; + +void Digitizer::init() +{ + for (int iLayer{0}; iLayer < SegmentationSuperAlpide::NLayers; ++iLayer) { + mSuperSegmentations.push_back(SegmentationSuperAlpide(iLayer)); + } + + const Int_t numOfChips = mGeometry->getNumberOfChips() + SegmentationSuperAlpide::NLayers; + mChips.resize(numOfChips); + for (int i = numOfChips; i--;) { + mChips[i].setChipIndex(i); + } + if (!mParams.getAlpSimResponse()) { + mAlpSimResp = std::make_unique<o2::itsmft::AlpideSimResponse>(); + mAlpSimResp->initData(); + mParams.setAlpSimResponse(mAlpSimResp.get()); + } + mParams.print(); + mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); +} + +void Digitizer::process(const std::vector<itsmft::Hit>* hits, int evID, int srcID) +{ + // digitize single event, the time must have been set beforehand + + LOG(INFO) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " + << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" + << " cont.mode: " << isContinuous() + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + + // is there something to flush ? + if (mNewROFrame > mROFrameMin) { + fillOutputContainer(mNewROFrame - 1); // flush out all frame preceding the new one + } + + int nHits = hits->size(); + std::vector<int> hitIdx(nHits); + std::iota(std::begin(hitIdx), std::end(hitIdx), 0); + // sort hits to improve memory access + std::sort(hitIdx.begin(), hitIdx.end(), + [hits](auto lhs, auto rhs) { + return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); + }); + for (int i : hitIdx) { + processHit((*hits)[i], mROFrameMax, evID, srcID); + } + // in the triggered mode store digits after every MC event + // TODO: in the real triggered mode this will not be needed, this is actually for the + // single event processing only + if (!mParams.isContinuous()) { + fillOutputContainer(mROFrameMax); + } +} + +void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) +{ + // assign event time in ns + mEventTime = irt; + if (!mParams.isContinuous()) { + mROFrameMin = 0; // in triggered mode reset the frame counters + mROFrameMax = 0; + } + // RO frame corresponding to provided time + mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?) + if (mParams.isContinuous()) { + auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF); + if (mCollisionTimeWrtROF < 0 && nbc > 0) { + nbc--; + } + mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + // in continuous mode depends on starts of periodic readout frame + mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; + } else { + mNewROFrame = 0; + } + + if (mNewROFrame < mROFrameMin) { + LOG(ERROR) << "New ROFrame " << mNewROFrame << " (" << irt << ") precedes currently cashed " << mROFrameMin; + throw std::runtime_error("deduced ROFrame precedes already processed one"); + } + + if (mParams.isContinuous() && mROFrameMax < mNewROFrame) { + mROFrameMax = mNewROFrame - 1; // all frames up to this are finished + } +} + +void Digitizer::fillOutputContainer(uint32_t frameLast) +{ + // fill output with digits from min.cached up to requested frame, generating the noise beforehand + if (frameLast > mROFrameMax) { + frameLast = mROFrameMax; + } + // make sure all buffers for extra digits are created up to the maxFrame + getExtraDigBuffer(mROFrameMax); + + LOG(INFO) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" + << frameLast; + + o2::itsmft::ROFRecord rcROF; + + // we have to write chips in RO increasing order, therefore have to loop over the frames here + for (; mROFrameMin <= frameLast; mROFrameMin++) { + rcROF.setROFrame(mROFrameMin); + rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits + + auto& extra = *(mExtraBuff.front().get()); + for (int iChip{0}; iChip < mChips.size(); ++iChip) { + auto& chip = mChips[iChip]; + if (iChip < SegmentationSuperAlpide::NLayers) { + chip.addNoise(mROFrameMin, mROFrameMin, &mParams, mSuperSegmentations[iChip].NRows, mSuperSegmentations[iChip].NCols); + } else { + chip.addNoise(mROFrameMin, mROFrameMin, &mParams); + } + auto& buffer = chip.getPreDigits(); + if (buffer.empty()) { + continue; + } + auto itBeg = buffer.begin(); + auto iter = itBeg; + ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1; // fetch digits with key below that + for (; iter != buffer.end(); ++iter) { + if (iter->first > maxKey) { + break; // is the digit ROFrame from the key > the max requested frame + } + auto& preDig = iter->second; // preDigit + if (preDig.charge >= mParams.getChargeThreshold()) { + int digID = mDigits->size(); + mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge); + mMCLabels->addElement(digID, preDig.labelRef.label); + auto& nextRef = preDig.labelRef; // extra contributors are in extra array + while (nextRef.next >= 0) { + nextRef = extra[nextRef.next]; + mMCLabels->addElement(digID, nextRef.label); + } + } + } + buffer.erase(itBeg, iter); + } + // finalize ROF record + rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits + if (isContinuous()) { + rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); + } else { + rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? + } + if (mROFRecords) { + mROFRecords->push_back(rcROF); + } + extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame + // and move it as a new slot in the end + mExtraBuff.emplace_back(mExtraBuff.front().release()); + mExtraBuff.pop_front(); + } +} + +void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) +{ + // convert single hit to digits + float timeInROF = hit.GetTime() * sec2ns; + if (timeInROF > 20e3) { + const int maxWarn = 10; + static int warnNo = 0; + if (warnNo < maxWarn) { + LOG(WARNING) << "Ignoring hit with time_in_event = " << timeInROF << " ns" + << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); + } + return; + } + if (isContinuous()) { + timeInROF += mCollisionTimeWrtROF; + } + // calculate RO Frame for this hit + if (timeInROF < 0) { + timeInROF = 0.; + } + float tTot = mParams.getSignalShape().getMaxDuration(); + // frame of the hit signal start wrt event ROFrame + int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); + // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame + uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; + int nFrames = roFrameRelMax + 1 - roFrameRel; + uint32_t roFrameMax = mNewROFrame + roFrameRelMax; + if (roFrameMax > maxFr) { + maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter + } + + // here we start stepping in the depth of the sensor to generate charge diffision + float nStepsInv = mParams.getNSimStepsInv(); + int nSteps = mParams.getNSimSteps(); + short detID{hit.GetDetectorID()}; + const auto& matrix = mGeometry->getMatrixL2G(detID); + bool innerBarrel{detID < SegmentationSuperAlpide::NLayers}; + auto startPos = hit.GetPosStart(); + float startPhi{std::atan2(-startPos.Y(), -startPos.X())}; + auto endPos = hit.GetPos(); + float endPhi{std::atan2(-endPos.Y(), -endPos.X())}; + math_utils::Vector3D<float> xyzLocS, xyzLocE; + if (innerBarrel) { + xyzLocS = {SegmentationSuperAlpide::Radii[detID] * startPhi, 0.f, startPos.Z()}; + xyzLocE = {SegmentationSuperAlpide::Radii[detID] * endPhi, 0.f, endPos.Z()}; + } else { + xyzLocS = matrix ^ (hit.GetPosStart()); + xyzLocE = matrix ^ (hit.GetPos()); + } + + math_utils::Vector3D<float> step(xyzLocE); + step -= xyzLocS; + step *= nStepsInv; // position increment at each step + // the electrons will injected in the middle of each step + math_utils::Vector3D<float> stepH(step * 0.5); + xyzLocS += stepH; + xyzLocE -= stepH; + + int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0; + if (innerBarrel) { + // get entrance pixel row and col + while (!mSuperSegmentations[detID].localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS)) { // guard-ring ? + if (++nSkip >= nSteps) { + return; // did not enter to sensitive matrix + } + xyzLocS += step; + } + // get exit pixel row and col + while (!mSuperSegmentations[detID].localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE)) { // guard-ring ? + if (++nSkip >= nSteps) { + return; // did not enter to sensitive matrix + } + xyzLocE -= step; + } + } else { + // get entrance pixel row and col + while (!Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS)) { // guard-ring ? + if (++nSkip >= nSteps) { + return; // did not enter to sensitive matrix + } + xyzLocS += step; + } + // get exit pixel row and col + while (!Segmentation::localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE)) { // guard-ring ? + if (++nSkip >= nSteps) { + return; // did not enter to sensitive matrix + } + xyzLocE -= step; + } + } + // estimate the limiting min/max row and col where the non-0 response is possible + if (rowS > rowE) { + std::swap(rowS, rowE); + } + if (colS > colE) { + std::swap(colS, colE); + } + rowS -= AlpideRespSimMat::NPix / 2; + rowE += AlpideRespSimMat::NPix / 2; + if (rowS < 0) { + rowS = 0; + } + + int maxNrows{innerBarrel ? mSuperSegmentations[detID].NRows : Segmentation::NRows}; + int maxNcols{innerBarrel ? mSuperSegmentations[detID].NCols : Segmentation::NCols}; + if (rowE >= maxNrows) { + rowE = maxNrows - 1; + } + colS -= AlpideRespSimMat::NPix / 2; + colE += AlpideRespSimMat::NPix / 2; + if (colS < 0) { + colS = 0; + } + if (colE >= maxNcols) { + colE = maxNcols - 1; + } + int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1; // size of plaquet where some response is expected + float respMatrix[rowSpan][colSpan]; // response accumulated here + std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f); + + float nElectrons = hit.GetEnergyLoss() * mParams.getEnergyToNElectrons(); // total number of deposited electrons + nElectrons *= nStepsInv; // N electrons injected per step + if (nSkip) { + nSteps -= nSkip; + } + // + int rowPrev = -1, colPrev = -1, row, col; + float cRowPix = 0.f, cColPix = 0.f; // local coordinated of the current pixel center + + const o2::itsmft::AlpideSimResponse* resp = mParams.getAlpSimResponse(); + + // take into account that the AlpideSimResponse depth defintion has different min/max boundaries + // although the max should coincide with the surface of the epitaxial layer, which in the chip + // local coordinates has Y = +SensorLayerThickness/2 + + xyzLocS.SetY(xyzLocS.Y() + resp->getDepthMax() - Segmentation::SensorLayerThickness / 2.); + + // collect charge in evey pixel which might be affected by the hit + for (int iStep = nSteps; iStep--;) { + // Get the pixel ID + if (innerBarrel) { + mSuperSegmentations[detID].localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col); + } else { + Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col); + } + if (row != rowPrev || col != colPrev) { // update pixel and coordinates of its center + if (innerBarrel) { + if (!mSuperSegmentations[detID].detectorToLocal(row, col, cRowPix, cColPix)) { + continue; + } + } else if (!Segmentation::detectorToLocal(row, col, cRowPix, cColPix)) { + continue; // should not happen + } + rowPrev = row; + colPrev = col; + } + bool flipCol, flipRow; + // note that response needs coordinates along column row (locX) (locZ) then depth (locY) + float rowMax{0.5f * (innerBarrel ? mSuperSegmentations[detID].PitchRow : Segmentation::PitchRow)}; + float colMax{0.5f * (innerBarrel ? mSuperSegmentations[detID].PitchCol : Segmentation::PitchCol)}; + auto rspmat = resp->getResponse(xyzLocS.X() - cRowPix, xyzLocS.Z() - cColPix, xyzLocS.Y(), flipRow, flipCol, rowMax, colMax); + + xyzLocS += step; + if (!rspmat) { + continue; + } + + for (int irow = AlpideRespSimMat::NPix; irow--;) { + int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix + if (rowDest < 0 || rowDest >= rowSpan) { + continue; + } + for (int icol = AlpideRespSimMat::NPix; icol--;) { + int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix + if (colDest < 0 || colDest >= colSpan) { + continue; + } + respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, flipRow, flipCol); + } + } + } + + // fire the pixels assuming Poisson(n_response_electrons) + o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); + auto& chip = mChips[detID]; + auto roFrameAbs = mNewROFrame + roFrameRel; + for (int irow = rowSpan; irow--;) { + uint16_t rowIS = irow + rowS; + for (int icol = colSpan; icol--;) { + float nEleResp = respMatrix[irow][icol]; + if (nEleResp <= 1.e-36) { + continue; + } + int nEle = gRandom->Poisson(nElectrons * nEleResp); // total charge in given pixel + // ignore charge which have no chance to fire the pixel + if (nEle < mParams.getMinChargeToAccount()) { + continue; + } + uint16_t colIS = icol + colS; + // + registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); + } + } +} + +void Digitizer::registerDigits(o2::itsmft::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl) +{ + // Register digits for given pixel, accounting for the possible signal contribution to + // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame + // In every ROFrame we check the collected signal during strobe + + float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start + for (int i = 0; i < nROF; i++) { + uint32_t roFr = roFrame + i; + int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); + tStrobe += mParams.getROFrameLength(); // for the next ROF + + // discard too small contributions, they have no chance to produce a digit + if (nEleROF < mParams.getMinChargeToAccount()) { + continue; + } + if (roFr > mEventROFrameMax) { + mEventROFrameMax = roFr; + } + if (roFr < mEventROFrameMin) { + mEventROFrameMin = roFr; + } + auto key = chip.getOrderingKey(roFr, row, col); + PreDigit* pd = chip.findDigit(key); + if (!pd) { + chip.addDigit(key, roFr, row, col, nEleROF, lbl); + } else { // there is already a digit at this slot, account as PreDigitExtra contribution + pd->charge += nEleROF; + if (pd->labelRef.label == lbl) { // don't store the same label twice + continue; + } + ExtraDig* extra = getExtraDigBuffer(roFr); + int& nxt = pd->labelRef.next; + bool skip = false; + while (nxt >= 0) { + if ((*extra)[nxt].label == lbl) { // don't store the same label twice + skip = true; + break; + } + nxt = (*extra)[nxt].next; + } + if (skip) { + continue; + } + // new predigit will be added in the end of the chain + nxt = extra->size(); + extra->emplace_back(lbl); + } + } +} diff --git a/Detectors/Upgrades/IT3/simulation/src/ITS3SimulationLinkDef.h b/Detectors/Upgrades/IT3/simulation/src/ITS3SimulationLinkDef.h index 9a25a76389d10..0d39aa497c59c 100644 --- a/Detectors/Upgrades/IT3/simulation/src/ITS3SimulationLinkDef.h +++ b/Detectors/Upgrades/IT3/simulation/src/ITS3SimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,10 +16,11 @@ #pragma link off all functions; #pragma link C++ class o2::its3::V11Geometry + ; -#pragma link C++ class o2::its3::V1Layer + ; #pragma link C++ class o2::its3::V3Layer + ; #pragma link C++ class o2::its3::V3Services + ; #pragma link C++ class o2::its3::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::its3::Detector> + ; +#pragma link C++ class o2::its3::Digitizer + ; + #endif diff --git a/Detectors/Upgrades/IT3/simulation/src/V11Geometry.cxx b/Detectors/Upgrades/IT3/simulation/src/V11Geometry.cxx index 57a9caddb5ebc..658d00c3c5549 100644 --- a/Detectors/Upgrades/IT3/simulation/src/V11Geometry.cxx +++ b/Detectors/Upgrades/IT3/simulation/src/V11Geometry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Upgrades/IT3/simulation/src/V1Layer.cxx b/Detectors/Upgrades/IT3/simulation/src/V1Layer.cxx deleted file mode 100644 index 07edcb3a403cf..0000000000000 --- a/Detectors/Upgrades/IT3/simulation/src/V1Layer.cxx +++ /dev/null @@ -1,2762 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file V1Layer.cxx -/// \brief Implementation of the V1Layer class -/// \author Mario Sitta <sitta@to.infn.it> -/// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) - -#include "ITS3Simulation/V1Layer.h" -#include "ITS3Base/GeometryTGeo.h" -#include "ITS3Simulation/Detector.h" - -#include "FairLogger.h" // for LOG - -#include <TGeoArb8.h> // for TGeoArb8 -#include <TGeoBBox.h> // for TGeoBBox -#include <TGeoCone.h> // for TGeoConeSeg, TGeoCone -#include <TGeoManager.h> // for TGeoManager, gGeoManager -#include <TGeoMatrix.h> // for TGeoCombiTrans, TGeoRotation, etc -#include <TGeoTrd1.h> // for TGeoTrd1 -#include <TGeoTube.h> // for TGeoTube, TGeoTubeSeg -#include <TGeoVolume.h> // for TGeoVolume, TGeoVolumeAssembly -#include <TGeoXtru.h> // for TGeoXtru -#include "TMathBase.h" // for Abs -#include <TMath.h> // for Sin, RadToDeg, DegToRad, Cos, Tan, etc - -#include <cstdio> // for snprintf - -class TGeoMedium; - -using namespace TMath; -using namespace o2::its3; - -// General Parameters -const Int_t V1Layer::sNumberOmInnerLayers = 3; - -const Double_t V1Layer::sDefaultSensorThick = 300 * sMicron; -const Double_t V1Layer::sDefaultStaveThick = 1 * sCm; - -// Inner Barrel Parameters -const Int_t V1Layer::sIBChipsPerRow = 9; -const Int_t V1Layer::sIBNChipRows = 1; - -// Outer Barrel Parameters -const Int_t V1Layer::sOBChipsPerRow = 7; -const Int_t V1Layer::sOBNChipRows = 2; - -const Double_t V1Layer::sOBHalfStaveWidth = 3.01 * sCm; -const Double_t V1Layer::sOBModuleWidth = sOBHalfStaveWidth; -const Double_t V1Layer::sOBModuleGap = 0.01 * sCm; -const Double_t V1Layer::sOBChipXGap = 0.01 * sCm; -const Double_t V1Layer::sOBChipZGap = 0.01 * sCm; -const Double_t V1Layer::sOBFlexCableAlThick = 0.005 * sCm; -const Double_t V1Layer::sOBFlexCableKapThick = 0.01 * sCm; -const Double_t V1Layer::sOBBusCableAlThick = 0.02 * sCm; -const Double_t V1Layer::sOBBusCableKapThick = 0.02 * sCm; -const Double_t V1Layer::sOBColdPlateThick = 0.012 * sCm; -const Double_t V1Layer::sOBCarbonPlateThick = 0.012 * sCm; -const Double_t V1Layer::sOBGlueThick = 0.03 * sCm; -const Double_t V1Layer::sOBModuleZLength = 21.06 * sCm; -const Double_t V1Layer::sOBHalfStaveYTrans = 1.76 * sMm; -const Double_t V1Layer::sOBHalfStaveXOverlap = 4.3 * sMm; -const Double_t V1Layer::sOBGraphiteFoilThick = 30.0 * sMicron; -const Double_t V1Layer::sOBCoolTubeInnerD = 2.052 * sMm; -const Double_t V1Layer::sOBCoolTubeThick = 32.0 * sMicron; -const Double_t V1Layer::sOBCoolTubeXDist = 11.1 * sMm; - -const Double_t V1Layer::sOBSpaceFrameWidth = 42.0 * sMm; -const Double_t V1Layer::sOBSpaceFrameTotHigh = 43.1 * sMm; -const Double_t V1Layer::sOBSFrameBeamRadius = 0.6 * sMm; -const Double_t V1Layer::sOBSpaceFrameLa = 3.0 * sMm; -const Double_t V1Layer::sOBSpaceFrameHa = 0.721979 * sMm; -const Double_t V1Layer::sOBSpaceFrameLb = 3.7 * sMm; -const Double_t V1Layer::sOBSpaceFrameHb = 0.890428 * sMm; -const Double_t V1Layer::sOBSpaceFrameL = 0.25 * sMm; -const Double_t V1Layer::sOBSFBotBeamAngle = 56.5; -const Double_t V1Layer::sOBSFrameBeamSidePhi = 65.0; - -ClassImp(V1Layer); - -#define SQ(A) (A) * (A) - -V1Layer::V1Layer() - : V11Geometry(), - mLayerNumber(0), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t debug) - : V11Geometry(debug), - mLayerNumber(0), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t lay, Int_t debug) - : V11Geometry(debug), - mLayerNumber(lay), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t lay, Bool_t turbo, Int_t debug) - : V11Geometry(debug), - mLayerNumber(lay), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(turbo), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(const V1Layer& s) - : V11Geometry(s.getDebug()), - mLayerNumber(s.mLayerNumber), - mPhi0(s.mPhi0), - mLayerRadius(s.mLayerRadius), - mZLength(s.mZLength), - mSensorThickness(s.mSensorThickness), - mStaveThickness(s.mStaveThickness), - mStaveWidth(s.mStaveWidth), - mStaveTilt(s.mStaveTilt), - mNumberOfStaves(s.mNumberOfStaves), - mNumberOfModules(s.mNumberOfModules), - mNumberOfChips(s.mNumberOfChips), - mChipTypeID(s.mChipTypeID), - mIsTurbo(s.mIsTurbo), - mBuildLevel(s.mBuildLevel), - mStaveModel(s.mStaveModel) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = s.mHierarchy[i]; - } -} - -V1Layer& V1Layer::operator=(const V1Layer& s) -{ - if (&s == this) { - return *this; - } - - mLayerNumber = s.mLayerNumber; - mPhi0 = s.mPhi0; - mLayerRadius = s.mLayerRadius; - mZLength = s.mZLength; - mSensorThickness = s.mSensorThickness; - mStaveThickness = s.mStaveThickness; - mStaveWidth = s.mStaveWidth; - mStaveTilt = s.mStaveTilt; - mNumberOfStaves = s.mNumberOfStaves; - mNumberOfModules = s.mNumberOfModules; - mNumberOfChips = s.mNumberOfChips; - mIsTurbo = s.mIsTurbo; - mChipTypeID = s.mChipTypeID; - mBuildLevel = s.mBuildLevel; - mStaveModel = s.mStaveModel; - for (int i = kNHLevels; i--;) { - mHierarchy[i] = s.mHierarchy[i]; - } - - return *this; -} - -V1Layer::~V1Layer() = default; - -void V1Layer::createLayer(TGeoVolume* motherVolume) -{ - char volumeName[30]; - Double_t xpos, ypos, zpos; - Double_t alpha; - - // Check if the user set the proper parameters - if (mLayerRadius <= 0) { - LOG(FATAL) << "Wrong layer radius " << mLayerRadius; - } - - if (mZLength <= 0) { - LOG(FATAL) << "Wrong layer length " << mZLength; - } - - if (mNumberOfStaves <= 0) { - LOG(FATAL) << "Wrong number of staves " << mNumberOfStaves; - } - - if (mNumberOfChips <= 0) { - LOG(FATAL) << "Wrong number of chips " << mNumberOfChips; - } - - if (mLayerNumber >= sNumberOmInnerLayers && mNumberOfModules <= 0) { - LOG(FATAL) << "Wrong number of modules " << mNumberOfModules; - } - - if (mStaveThickness <= 0) { - LOG(INFO) << "Stave thickness wrong or not set " << mStaveThickness << " using default " - << sDefaultStaveThick; - mStaveThickness = sDefaultStaveThick; - } - - if (mSensorThickness <= 0) { - LOG(INFO) << "Sensor thickness wrong or not set " << mSensorThickness << " using default " - << sDefaultSensorThick; - mSensorThickness = sDefaultSensorThick; - } - - if (mSensorThickness > mStaveThickness) { - LOG(WARNING) << "Sensor thickness " << mSensorThickness << " is greater than stave thickness " - << mStaveThickness << " fixing"; - mSensorThickness = mStaveThickness; - } - - // If a Turbo layer is requested, do it and exit - if (mIsTurbo) { - createLayerTurbo(motherVolume); - return; - } - - // First create the stave container - alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); - - // mStaveWidth = mLayerRadius*Tan(alpha); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); - - // layerVolume->SetVisibility(kFALSE); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); - - TGeoVolume* stavVol = createStave(); - - // Now build up the layer - alpha = 360. / mNumberOfStaves; - Double_t r = mLayerRadius + ((TGeoBBox*)stavVol->GetShape())->GetDY(); - for (Int_t j = 0; j < mNumberOfStaves; j++) { - Double_t phi = j * alpha + mPhi0; - xpos = r * cosD(phi); // r*sinD(-phi); - ypos = r * sinD(phi); // r*cosD(-phi); - zpos = 0.; - phi += 90; - layerVolume->AddNode(stavVol, j, - new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi, 0, 0))); - } - - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - - // geometry is served - return; -} - -void V1Layer::createLayerTurbo(TGeoVolume* motherVolume) -{ - char volumeName[30]; - Double_t xpos, ypos, zpos; - Double_t alpha; - - // Check if the user set the proper (remaining) parameters - if (mStaveWidth <= 0) { - LOG(FATAL) << "Wrong stave width " << mStaveWidth; - } - - if (Abs(mStaveTilt) > 45) { - LOG(WARNING) << "Stave tilt angle (" << mStaveTilt << ") greater than 45deg"; - } - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); - TGeoVolume* stavVol = createStave(); - - // Now build up the layer - alpha = 360. / mNumberOfStaves; - Double_t r = mLayerRadius /* +chip thick ?! */; - for (Int_t j = 0; j < mNumberOfStaves; j++) { - Double_t phi = j * alpha + mPhi0; - xpos = r * cosD(phi); // r*sinD(-phi); - ypos = r * sinD(phi); // r*cosD(-phi); - zpos = 0.; - phi += 90; - layerVolume->AddNode( - stavVol, j, - new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi - mStaveTilt, 0, 0))); - } - - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - - return; -} - -TGeoVolume* V1Layer::createStave(const TGeoManager* /*mgr*/) -{ - char volumeName[30]; - - Double_t xlen, ylen, zlen; - Double_t xpos, ypos; - Double_t alpha; - - // First create all needed shapes - alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); - - // The stave - xlen = mLayerRadius * Tan(alpha); - if (mIsTurbo) { - xlen = 0.5 * mStaveWidth; - } - ylen = 0.5 * mStaveThickness; - zlen = 0.5 * mZLength; - - Double_t yplus = 0.46; - auto* stave = new TGeoXtru(2); // z sections - Double_t xv[5] = {xlen, xlen, 0, -xlen, -xlen}; - Double_t yv[5] = {ylen + 0.09, -0.15, -yplus - mSensorThickness, -0.15, ylen + 0.09}; - stave->DefinePolygon(5, xv, yv); - stave->DefineSection(0, -zlen, 0, 0, 1.); - stave->DefineSection(1, +zlen, 0, 0, 1.); - - // We have all shapes: now create the real volumes - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSStavePattern(), mLayerNumber); - // TGeoVolume *staveVol = new TGeoVolume(volumeName, stave, medAir); - TGeoVolume* staveVol = new TGeoVolumeAssembly(volumeName); - - // staveVol->SetVisibility(kFALSE); - staveVol->SetVisibility(kTRUE); - staveVol->SetLineColor(2); - TGeoVolume* mechStaveVol = nullptr; - - // Now build up the stave - if (mLayerNumber < sNumberOmInnerLayers) { - TGeoVolume* modVol = createStaveInnerB(xlen, ylen, zlen); - staveVol->AddNode(modVol, 0); - mHierarchy[kHalfStave] = 1; - - // Mechanical stave structure - mechStaveVol = createStaveStructInnerB(xlen, zlen); - if (mechStaveVol) { - ypos = ((TGeoBBox*)(modVol->GetShape()))->GetDY() + - ((TGeoBBox*)(mechStaveVol->GetShape()))->GetDY(); - staveVol->AddNode(mechStaveVol, 1, - new TGeoCombiTrans(0, -ypos, 0, new TGeoRotation("", 0, 0, 180))); - } - } else { - TGeoVolume* hstaveVol = createStaveOuterB(); - if (mStaveModel == Detector::kOBModel0) { // Create simplified stave struct as in v0 - staveVol->AddNode(hstaveVol, 0); - mHierarchy[kHalfStave] = 1; - } else { // (if mStaveModel) Create new stave struct as in TDR - xpos = ((TGeoBBox*)(hstaveVol->GetShape()))->GetDX() - sOBHalfStaveXOverlap / 2; - // ypos is CF height as computed in createSpaceFrameOuterB1 - ypos = (sOBSpaceFrameTotHigh - sOBHalfStaveYTrans) / 2; - staveVol->AddNode(hstaveVol, 0, new TGeoTranslation(-xpos, ypos, 0)); - staveVol->AddNode(hstaveVol, 1, new TGeoTranslation(xpos, ypos + sOBHalfStaveYTrans, 0)); - mHierarchy[kHalfStave] = 2; // RS - mechStaveVol = createSpaceFrameOuterB(); - - if (mechStaveVol) { - staveVol->AddNode(mechStaveVol, 1, - new TGeoCombiTrans(0, 0, 0, new TGeoRotation("", 180, 0, 0))); - } - } - } - // Done, return the stave - return staveVol; -} - -TGeoVolume* V1Layer::createStaveInnerB(const Double_t xsta, const Double_t ysta, - const Double_t zsta, const TGeoManager* mgr) -{ - Double_t xmod, ymod, zmod; - char volumeName[30]; - - // First we create the module (i.e. the HIC with 9 chips) - TGeoVolume* moduleVol = createModuleInnerB(xsta, ysta, zsta); - - // Then we create the fake halfstave and the actual stave - xmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDX(); - ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); - zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); - - auto* hstave = new TGeoBBox(xmod, ymod, zmod); - - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); - - // Finally build it up - hstaveVol->AddNode(moduleVol, 0); - mHierarchy[kModule] = 1; - - // Done, return the stave structure - return hstaveVol; -} - -TGeoVolume* V1Layer::createModuleInnerB(Double_t xmod, Double_t ymod, Double_t zmod, - const TGeoManager* mgr) -{ - Double_t zchip; - Double_t zpos; - char volumeName[30]; - - // First create the single chip - zchip = zmod / sIBChipsPerRow; - TGeoVolume* chipVol = createChipInnerB(xmod, ymod, zchip); - - // Then create the module and populate it with the chips - auto* module = new TGeoBBox(xmod, ymod, zmod); - - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - - // mm (not used) zlen = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - for (Int_t j = 0; j < sIBChipsPerRow; j++) { - zpos = -zmod + j * 2 * zchip + zchip; - modVol->AddNode(chipVol, j, new TGeoTranslation(0, 0, zpos)); - mHierarchy[kChip]++; - } - // Done, return the module - return modVol; -} - -TGeoVolume* V1Layer::createStaveStructInnerB(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kIBModelDummy: - mechStavVol = createStaveModelInnerBDummy(xsta, zsta, mgr); - break; - case Detector::kIBModel0: - mechStavVol = createStaveModelInnerB0(xsta, zsta, mgr); - break; - case Detector::kIBModel1: - mechStavVol = createStaveModelInnerB1(xsta, zsta, mgr); - break; - case Detector::kIBModel21: - mechStavVol = createStaveModelInnerB21(xsta, zsta, mgr); - break; - case Detector::kIBModel22: - mechStavVol = createStaveModelInnerB22(xsta, zsta, mgr); - break; - case Detector::kIBModel3: - mechStavVol = createStaveModelInnerB3(xsta, zsta, mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerBDummy(const Double_t, const Double_t, - const TGeoManager*) const -{ - // Done, return the stave structur - return nullptr; -} - -TGeoVolume* V1Layer::createStaveModelInnerB0(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - LOG(INFO) << "################################# pointer :" << medWater; - TGeoMedium* medM60J3K = mgr->GetMedium("IT3_M60J3K$"); - LOG(INFO) << "################################# pointer :" << medM60J3K; - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT3_FLEXCABLE$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - Double_t kConeInRadius = 0.1430 / 2; - Double_t kStaveLength = zsta * 2; - Double_t kStaveWidth = xsta * 2 - kConeOutRadius * 2; - Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth - Double_t kStaveHeight = 0.3; - Double_t kHeight = kStaveHeight / 2; - Double_t kAlpha = 90 - 67; // 90-33.69; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = kWidth / TMath::Sin(kTheta); - Double_t kL1 = kWidth / TMath::Tan(kTheta); - Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - // Int_t loop = kStaveLength/(kL1); - // Double_t s3 = kWidth/(2*TMath::Sin(kTheta)); - // Double_t s4 = 3*kWidth/(2*TMath::Sin(kTheta)); - - LOG(DEBUG1) << "BuildLevel " << mBuildLevel; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its3::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -0.011 + 0.0150, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // detailed structure ++++++++++++++ - // Pipe Kapton grey-35 - auto* coolTube = new TGeoTube(kConeInRadius, kConeOutRadius, kStaveLength / 2); - auto* volCoolTube = new TGeoVolume("pipe", coolTube, medKapton); - volCoolTube->SetFillColor(35); - volCoolTube->SetLineColor(35); - mechStavVol->AddNode(volCoolTube, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - mechStavVol->AddNode(volCoolTube, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength / 2); - auto* volCoolTubeW = new TGeoVolume("pipeWater", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - } - - // frequency of filament - // n = 4 means very dense(4 filaments per interval) - // n = 2 means dense(2 filaments per interval) - Int_t n = 4; - Int_t loop = (Int_t)(kStaveLength / (4 * kL1 / n) + 2 / n) - 1; - if (mBuildLevel < 3) { - // Top CFRP Filament black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(kS2, 0.007 / 2, 0.15 / 2); //(kS2,0.002,0.02); - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - - for (int i = 1; i < loop; i++) { // i<60;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, - new TGeoCombiTrans( - x + kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans( - x - kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans( - x + kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans( - x - kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - - // Bottom CFRP Filament black-12 Carbon structure TGeoBBox (thickness,width,length) - auto* t1 = new TGeoBBox(0.007 / 2, 0.15 / 2, kS1); //(0.002,0.02,kS1); - auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - - for (int i = 1; i < loop; i++) { - mechStavVol->AddNode( - volT1, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - } - - if (mBuildLevel < 2) { - // Glue CFRP-Silicon layers TGeoBBox(thickness,width,kS1); - auto* tG = new TGeoBBox(0.0075 / 2, 0.18 / 2, kS1); - auto* volTG = new TGeoVolume("Glue1", tG, medGlue); - volTG->SetLineColor(5); - volTG->SetFillColor(5); - - for (int i = 1; i < loop; i++) { // i<60;i++){ - mechStavVol->AddNode( - volTG, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), - new TGeoRotation("volTG", -90, kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), - new TGeoRotation("volTG", 90, kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * i * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volTG", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volTG", -90, +kAlpha, 0))); - } - - auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("Glue2", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - // mechStavVol->AddNode(volGlue, 0, new TGeoCombiTrans(x, y-0.16, z, new TGeoRotation("",0, 0, - // 0))); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - // Flex cable brown-28 TGeoBBox(width,thickness,length); - auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structur - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerB1(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT3_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT3_FLEXCABLE$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - // Double_t kConeInRadius = 0.1430/2; - Double_t kStaveLength = zsta * 2; - // Double_t kStaveWidth = xsta*2-kConeOutRadius*2; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth - Double_t kStaveHeight = 0.3; - Double_t kHeight = kStaveHeight / 2; - Double_t kAlpha = 90 - 33.; // 90-30; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = kWidth / TMath::Sin(kTheta); - Double_t kL1 = kWidth / TMath::Tan(kTheta); - Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - Int_t loop = (Int_t)((kStaveLength / (2 * kL1)) / 2); - - TGeoVolume* mechStavVol = nullptr; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its3::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - // detailed structure ++++++++++++++ - Double_t z = 0, y = -0.011 + 0.0150, x = 0; - - // Polimide micro channels numbers - Double_t yMC = y - kHeight + 0.01; - Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; - Double_t xstaMC = (nb * 0.1 - 0.08) / 2; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Polimide micro channels numbers - auto* tM0 = new TGeoBBox(xstaMC, 0.005 / 2, zsta); - auto* volTM0 = new TGeoVolume("MicroChanCover", tM0, medKapton); - volTM0->SetLineColor(35); - volTM0->SetFillColor(35); - mechStavVol->AddNode(volTM0, 0, - new TGeoCombiTrans(x, -0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volTM0, 1, - new TGeoCombiTrans(x, +0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); - - auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); - auto* volTM0b = new TGeoVolume("MicroChanWalls", tM0b, medKapton); - volTM0b->SetLineColor(35); - volTM0b->SetFillColor(35); - for (Int_t ib = 0; ib < nb; ib++) { - mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.01, yMC, z, new TGeoRotation("", 0, 0, 0))); - } - } - - if (mBuildLevel < 4) { - // Water in Polimide micro channels - auto* water = new TGeoBBox(0.08 / 2, 0.02 / 2, zsta + 0.1); - auto* volWater = new TGeoVolume("Water", water, medWater); - volWater->SetLineColor(4); - volWater->SetFillColor(4); - for (Int_t ib = 0; ib < (nb - 1); ib++) { - mechStavVol->AddNode(volWater, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.06, yMC, z, new TGeoRotation("", 0, 0, 0))); - } - } - - if (mBuildLevel < 3) { - // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) - Double_t filWidth = 0.04; - Double_t filHeight = 0.02; - auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, kS1); - auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT1, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - - // Top filament CFRP black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(kS2, filHeight / 2, filWidth / 2); - auto* volT2 = new TGeoVolume("CFRPTop", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - } - - if (mBuildLevel < 2) { - // Glue between filament and polimide micro channel - auto* t3 = new TGeoBBox(0.01 / 2, 0.04, kS1); - auto* volT3 = new TGeoVolume("FilamentGlue", t3, medGlue); - volT3->SetLineColor(5); - volT3->SetFillColor(5); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT3, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode(volT3, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT3, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT3, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - - // Glue microchannel and sensor - auto* glueM = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volGlueM = new TGeoVolume("MicroChanGlue", glueM, medGlue); - volGlueM->SetLineColor(5); - volGlueM->SetFillColor(5); - mechStavVol->AddNode(volGlueM, 0, - new TGeoCombiTrans(x, y - 0.16, z, new TGeoRotation("", 0, 0, 0))); - - // Glue sensor and kapton - auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("SensorGlue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structur - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerB21(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT3_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT3_FLEXCABLE$"); - TGeoMedium* medK13D2U2k = mgr->GetMedium("IT3_K13D2U2k$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT3_FGS003$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT3_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = 0.151384 / 2; - Double_t kConeInRadius = 0.145034 / 2; - Double_t kStaveLength = zsta; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = (kStaveWidth + 0.005) / 4; - Double_t kStaveHeigth = 0.33; // 0.33; - Double_t kHeight = (kStaveHeigth + 0.025) / 2; - Double_t kAlpha = 57; // 56.31; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = (kStaveWidth / 4) / TMath::Sin(kTheta); - Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); - Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - // Double_t lay1 = 0.003157; - Double_t kLay1 = 0.003; // Amec carbon - // Double_t lay2 = 0.0043215;//C Fleece carbon - Double_t kLay2 = 0.002; // C Fleece carbon - Double_t kLay3 = 0.007; // K13D2U carbon - Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its3::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -(kConeOutRadius + 0.03) + 0.0385, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeigth, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Pipe Kapton grey-35 - auto* cone1 = - new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius, kConeInRadius, kConeOutRadius); - auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); - volCone1->SetFillColor(35); - volCone1->SetLineColor(35); - mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); - mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength); - auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); - } - - if (mBuildLevel < 3) { - // top fillament - // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = - new TGeoBBox(kS2, 0.02 / 2, 0.04 / 2); // TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02); - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - - for (int i = 0; i < loop; i++) { // i<28;i++){ - mechStavVol->AddNode( - volT2, i * 4 + 1, - new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 2, - new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 3, - new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 4, - new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - // mechStavVol->AddNode(volT2,i*4+1,new - // TGeoCombiTrans(x+kWidth+0.0036,y+kHeight-(0.12/2)+0.072,z+kStaveLength+(i*4*kL1)+kS1/2, new - // TGeoRotation("volT2",90,90-kAlpha,90-kBeta))); - } - - // wall side structure out - auto* box4 = new TGeoBBox(0.03 / 2, 0.12 / 2, kStaveLength - 0.50); - auto* plate4 = new TGeoVolume("WallOut", box4, medM60J3K); - plate4->SetFillColor(35); - plate4->SetLineColor(35); - mechStavVol->AddNode(plate4, 1, - new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - (0.03 / 2), - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate4", 0, 0, 0))); - mechStavVol->AddNode(plate4, 2, - new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + (0.03 / 2), - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate4", 0, 0, 0))); - // wall side in - auto* box5 = new TGeoBBox(0.015 / 2, 0.12 / 2, kStaveLength - 0.50); - auto* plate5 = new TGeoVolume("WallIn", box5, medM60J3K); - plate5->SetFillColor(12); - plate5->SetLineColor(12); - mechStavVol->AddNode(plate5, 1, - new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - 0.03 - 0.015 / 2, - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate5", 0, 0, 0))); - mechStavVol->AddNode(plate5, 2, - new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + 0.03 + 0.015 / 2, - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate5", 0, 0, 0))); - - // Amec Thermasol red-2 cover tube FGS300 - auto* cons1 = - new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius, kConeOutRadius + kLay1, kConeOutRadius, - kConeOutRadius + kLay1, 0, 180); - auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); - cone11->SetFillColor(2); - cone11->SetLineColor(2); - mechStavVol->AddNode(cone11, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); - mechStavVol->AddNode(cone11, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); - - auto* box2 = - new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, kLay1 / 2, kStaveLength - 0.50); - auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); - plate2->SetFillColor(2); - plate2->SetLineColor(2); - mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); - - auto* box21 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay1 / 2, kStaveLength - 0.50); - auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); - plate21->SetFillColor(2); - plate21->SetLineColor(2); - mechStavVol->AddNode( - plate21, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - mechStavVol->AddNode( - plate21, 2, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - - auto* box22 = new TGeoBBox((kLay1 / 2), kConeOutRadius / 2, kStaveLength - 0.50); - auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); - plate22->SetFillColor(2); - plate22->SetLineColor(2); - mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - - // C Fleece - auto* cons2 = - new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, - kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, 0, 180); - auto* cone12 = new TGeoVolume("CFleecePipeCover", cons2, medCarbonFleece); - cone12->SetFillColor(28); - cone12->SetLineColor(28); - mechStavVol->AddNode(cone12, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); - mechStavVol->AddNode(cone12, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); - - auto* box3 = - new TGeoBBox((0.50 - (2 * (kConeOutRadius + kLay1))) / 2, kLay2 / 2, kStaveLength - 0.50); - auto* plate3 = new TGeoVolume("CFleeceMiddle", box3, medCarbonFleece); - plate3->SetFillColor(28); - plate3->SetLineColor(28); - mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); - - auto* box31 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay2 / 2, kStaveLength - 0.50); - auto* plate31 = new TGeoVolume("CFleeceLeftRight", box31, medCarbonFleece); - plate31->SetFillColor(28); - plate31->SetLineColor(28); - mechStavVol->AddNode( - plate31, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + kLay1 + (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, - y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - mechStavVol->AddNode( - plate31, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - kLay1 - (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, - y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - - auto* box32 = new TGeoBBox((kLay2 / 2), (kConeOutRadius - kLay1) / 2, kStaveLength - 0.50); - auto* plate32 = new TGeoVolume("CFleeceVertical", box32, medCarbonFleece); - plate32->SetFillColor(28); - plate32->SetLineColor(28); - mechStavVol->AddNode(plate32, 1, - new TGeoCombiTrans(x + 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 2, - new TGeoCombiTrans(x + 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 3, - new TGeoCombiTrans(x - 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 4, - new TGeoCombiTrans(x - 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - - // K13D2U carbon plate - auto* box1 = new TGeoBBox(2 * kWidth, kLay3 / 2, kStaveLength - 0.50); - auto* plate1 = new TGeoVolume("CarbonPlate", box1, medK13D2U2k); - plate1->SetFillColor(5); - plate1->SetLineColor(5); - mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (kLay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); - - // C Fleece bottom plate - auto* box6 = new TGeoBBox(2 * kWidth, kLay2 / 2, kStaveLength - 0.50); - auto* plate6 = new TGeoVolume("CFleeceBottom", box6, medCarbonFleece); - plate6->SetFillColor(2); - plate6->SetLineColor(2); - mechStavVol->AddNode(plate6, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2)), z, - new TGeoRotation("plate1", 0, 0, 0))); - } - - if (mBuildLevel < 2) { - // Glue layers and kapton - auto* glue = new TGeoBBox(kStaveWidth / 2, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("Glue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode( - volGlue, 0, new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + (0.01 / 2)), z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volGlue, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + (0.01 / 2)), - z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(kStaveWidth / 2, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + 0.01 + (0.01 / 2)), - z, new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structure - return mechStavVol; -} - -// new model22 -TGeoVolume* V1Layer::createStaveModelInnerB22(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT3_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT3_FLEXCABLE$"); - TGeoMedium* medK13D2U2k = mgr->GetMedium("IT3_K13D2U2k$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT3_FGS003$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT3_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = (0.1024 + 0.0025) / 2; // 0.107/2; - Double_t kConeInRadius = 0.1024 / 2; // 0.10105/2 - Double_t kStaveLength = zsta; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = (kStaveWidth) / 4; - Double_t kStaveHeight = 0.283; // 0.33; - Double_t kHeight = (kStaveHeight) / 2; - Double_t kAlpha = 57; // 56.31; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = ((kStaveWidth) / 4) / TMath::Sin(kTheta); - Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); - Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(kThe2); - Double_t kThe2 = TMath::ATan(kHeight / (0.375 - 0.036)); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - Double_t klay1 = 0.003; // Amec carbon - Double_t klay2 = 0.002; // C Fleece carbon - Double_t klay3 = 0.007; // CFplate K13D2U carbon - Double_t klay4 = 0.007; // GluekStaveLength/2 - Double_t klay5 = 0.01; // Flex cable - Double_t kTopVertexMaxWidth = 0.072; - Double_t kTopVertexHeight = 0.04; - Double_t kSideVertexMWidth = 0.052; - Double_t kSideVertexHeight = 0.11; - - Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its3::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -(2 * kConeOutRadius) + klay1 + klay2 + mSensorThickness / 2 - 0.0004, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[6] = { - kStaveWidth / 2, kStaveWidth / 2, 0.012, - -0.012, -kStaveWidth / 2, -kStaveWidth / 2}; - // Double_t yv[6] = {-2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5), - // 0-0.02,kStaveHeight+0.01,kStaveHeight+0.01,0-0.02, - // -2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5)}; - // (kConeOutRadius*2)-0.0635 - Double_t yv[6] = { - -(kConeOutRadius * 2) - 0.06395, 0 - 0.02, kStaveHeight + 0.01, - kStaveHeight + 0.01, 0 - 0.02, -(kConeOutRadius * 2) - 0.06395}; // (kConeOutRadius*2)-0.064 - mechStruct->DefinePolygon(6, xv, yv); - mechStruct->DefineSection(0, -kStaveLength, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Polyimide Pipe Kapton grey-35 - auto* cone1 = new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius - 0.0001, - kConeInRadius, kConeOutRadius - 0.0001); - auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); - volCone1->SetFillColor(35); - volCone1->SetLineColor(35); - mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); - mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius - 0.0001, kStaveLength); - auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); - } - - if (mBuildLevel < 3) { - // top fillament - // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox( - kS2 - 0.028, 0.02 / 2, - 0.02 / 2); // 0.04/2//TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02);//kS2-0.03 old Config.C - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<28;i++){ - // 1) Front Left Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 1, - new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - // 2) Front Right Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 2, - new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - // 3) Back Left Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 3, - new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - // 4) Back Right Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 4, - new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - - // Vertex structure - // top ver trd1 - auto* trd1 = new TGeoTrd1(0, kTopVertexMaxWidth / 2, kStaveLength, kTopVertexHeight / 2); - auto* ibdv = new TGeoVolume("TopVertex", trd1, medM60J3K); - ibdv->SetFillColor(12); - ibdv->SetLineColor(12); - mechStavVol->AddNode( - ibdv, 1, new TGeoCombiTrans(x, y + kStaveHeight + 0.03, z, new TGeoRotation("ibdv", 0., -90, 0))); // y+kStaveHeight+0.056 - - // left trd2 - auto* trd2 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); - auto* ibdv2 = new TGeoVolume("LeftVertex", trd2, medM60J3K); - ibdv2->SetFillColor(12); - ibdv2->SetLineColor(12); - mechStavVol->AddNode( - ibdv2, 1, - new TGeoCombiTrans( - x + kStaveWidth / 2 - 0.06, y - 0.0355, z, - new TGeoRotation("ibdv2", -103.3, 90, 0))); // x-kStaveWidth/2-0.09 old Config.C y-0.0355, - - // right trd3 - auto* trd3 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); - auto* ibdv3 = new TGeoVolume("RightVertex", trd3, medM60J3K); - ibdv3->SetFillColor(12); - ibdv3->SetLineColor(12); - mechStavVol->AddNode( - ibdv3, 1, new TGeoCombiTrans(x - kStaveWidth / 2 + 0.06, y - 0.0355, z, new TGeoRotation("ibdv3", 103.3, 90, 0))); // x-kStaveWidth/2+0.09 old Config.C - - // Carbon Fleece - auto* cons2 = - new TGeoConeSeg(zsta, kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, - kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, 0, 180); - auto* cone12 = new TGeoVolume("CarbonFleecePipeCover", cons2, medCarbonFleece); - cone12->SetFillColor(28); - cone12->SetLineColor(28); - mechStavVol->AddNode(cone12, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); - mechStavVol->AddNode(cone12, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); - - auto* box3 = new TGeoBBox((0.50 - (2 * (kConeOutRadius + klay1))) / 2, klay2 / 2, - zsta); // kStaveLength-0.50); - auto* plate3 = new TGeoVolume("CarbonFleeceMiddle", box3, medCarbonFleece); - plate3->SetFillColor(28); - plate3->SetLineColor(28); - mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); - - auto* box31 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, klay2 / 2, zsta); - auto* plate31 = new TGeoVolume("CarbonFleeceLeftRight", box31, medCarbonFleece); - plate31->SetFillColor(28); - plate31->SetLineColor(28); - mechStavVol->AddNode( - plate31, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + klay1 + (0.75 - 0.25 - kConeOutRadius - klay1) / 2, - y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - mechStavVol->AddNode( - plate31, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - klay1 - (0.75 - 0.25 - kConeOutRadius - klay1) / 2, - y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - - auto* box32 = new TGeoBBox((klay2 / 2), (kConeOutRadius - klay1) / 2, zsta); - auto* plate32 = new TGeoVolume("CarbonFleeceVertical", box32, medCarbonFleece); - plate32->SetFillColor(28); - plate32->SetLineColor(28); - mechStavVol->AddNode(plate32, 1, - new TGeoCombiTrans(x + 0.25 + kConeOutRadius + klay1 + (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 2, - new TGeoCombiTrans(x + 0.25 - kConeOutRadius - klay1 - (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 3, - new TGeoCombiTrans(x - 0.25 + kConeOutRadius + klay1 + (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 4, - new TGeoCombiTrans(x - 0.25 - kConeOutRadius - klay1 - (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - - // Amec Thermasol red-2 cover tube FGS300 or Carbon Paper - auto* cons1 = - new TGeoConeSeg(zsta, kConeOutRadius, kConeOutRadius + klay1 - 0.0001, kConeOutRadius, - kConeOutRadius + klay1 - 0.0001, 0, 180); // kConeOutRadius+klay1-0.0001 - auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); - cone11->SetFillColor(2); - cone11->SetLineColor(2); - mechStavVol->AddNode(cone11, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); - mechStavVol->AddNode(cone11, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); - - auto* box2 = - new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, (klay1 / 2), zsta); // kStaveLength-0.50); - auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); - plate2->SetFillColor(2); - plate2->SetLineColor(2); - mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); - - auto* box21 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, (klay1 / 2), zsta); - auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); - plate21->SetFillColor(2); - plate21->SetLineColor(2); - mechStavVol->AddNode( - plate21, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (klay1 / 2) + 0.0025, - y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - mechStavVol->AddNode( - plate21, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (klay1 / 2) - 0.0025, - y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - - auto* box22 = new TGeoBBox((klay1 / 2), kConeOutRadius / 2, zsta); - auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); - plate22->SetFillColor(2); - plate22->SetLineColor(2); - mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - - // K13D2U CF plate - auto* box1 = new TGeoBBox(2 * kWidth, (klay3) / 2, zsta); - auto* plate1 = new TGeoVolume("CFPlate", box1, medK13D2U2k); - plate1->SetFillColor(5); - plate1->SetLineColor(5); - mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (klay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); - - // C Fleece bottom plate - auto* box6 = new TGeoBBox(2 * kWidth, (klay2) / 2, zsta); - auto* plate6 = new TGeoVolume("CarbonFleeceBottom", box6, medCarbonFleece); - plate6->SetFillColor(2); - plate6->SetLineColor(2); - mechStavVol->AddNode(plate6, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + (klay2 / 2)), z, - new TGeoRotation("plate6", 0, 0, 0))); - } - if (mBuildLevel < 2) { - // Glue klayers and kapton - auto* glue = new TGeoBBox(kStaveWidth / 2, (klay4) / 2, zsta); - auto* volGlue = new TGeoVolume("Glue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - // mechStavVol->AddNode(volGlue, 0, new - // TGeoCombiTrans(x,y-(kConeOutRadius+klay3+klay2+(klay4/2)), z, new TGeoRotation("",0, 0, 0))); - mechStavVol->AddNode( - volGlue, 0, - new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + klay2 + (klay4) / 2) + 0.00005, z, - new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - // Flex Cable or Bus - auto* kapCable = new TGeoBBox(kStaveWidth / 2, klay5 / 2, zsta); // klay5/2 - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - // mechStavVol->AddNode(volCable, 0, new TGeoCombiTrans(x, - // y-(kConeOutRadius+klay3+klay2+klay4+mSensorThickness+(klay5)/2)+0.0002, z, new - // TGeoRotation("",0, - // 0, 0))); - mechStavVol->AddNode( - volCable, 0, - new TGeoCombiTrans( - x, y - (kConeOutRadius + klay3 + klay2 + klay4 + mSensorThickness + (klay5) / 2) + 0.01185, - z, new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structe - return mechStavVol; -} - -// model3 -TGeoVolume* V1Layer::createStaveModelInnerB3(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT3_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT3_FLEXCABLE$"); - // TGeoMedium *medK13D2U2k = mgr->GetMedium("IT3_K13D2U2k$"); - // TGeoMedium *medFGS003 = mgr->GetMedium("IT3_FGS003$"); - // TGeoMedium *medCarbonFleece = mgr->GetMedium("IT3_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - Double_t kStaveLength = zsta * 2; - Double_t kStaveWidth = xsta * 2; - Double_t w = kStaveWidth / 4; // 1/2 of W - Double_t staveHeight = 0.3; - Double_t h = staveHeight / 2; - Double_t alpha = 90 - 33.; // 90-30; - Double_t the1 = alpha * TMath::DegToRad(); - Double_t s1 = w / TMath::Sin(the1); - Double_t l = w / TMath::Tan(the1); - Double_t s2 = TMath::Sqrt(h * h + s1 * s1); // TMath::Sin(the2); - Double_t the2 = TMath::ATan(h / s1); - Double_t beta = the2 * TMath::RadToDeg(); - Double_t klay4 = 0.007; // Glue - Double_t klay5 = 0.01; // Flexcable - Int_t loop = (Int_t)((kStaveLength / (2 * l)) / 2); - Double_t hh = 0.01; - Double_t ang1 = 0 * TMath::DegToRad(); - Double_t ang2 = 0 * TMath::DegToRad(); - Double_t ang3 = 0 * TMath::DegToRad(); - Int_t chips = 4; - Double_t headWidth = 0.25; - Double_t smcLength = kStaveLength / chips - 2 * headWidth; // 6.25; - Double_t smcWidth = kStaveWidth; - Double_t smcSide1Thick = 0.03; - Double_t vaporThick = 0.032; - Double_t liquidThick = 0.028; - Double_t smcSide2Thick = 0.01; - Double_t smcSide3Thick = 0.0055; - Double_t smcSide4Thick = 0.0095; - Double_t smcSide5Thick = 0.0075; - Double_t smcSpace = 0.01; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its3::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - // detailed structure ++++++++++++++ - Double_t z = 0, y = 0 - 0.007, x = 0; - - // Polimide micro channels numbers - Double_t yMC = y - h + 0.01; - Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; - Double_t xstaMC = (nb * 0.1 - 0.08) / 2; - - TGeoVolume* mechStavVol = nullptr; - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, staveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Silicon micro channels numbers - - auto* tM0a = new TGeoBBox(smcWidth / 2, 0.003 / 2, headWidth / 2); - auto* volTM0a = new TGeoVolume("microChanTop1", tM0a, medKapton); - volTM0a->SetLineColor(35); - volTM0a->SetFillColor(35); - - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0a, 0, - new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), - new TGeoRotation("", ang1, ang2, ang3))); - mechStavVol->AddNode( - volTM0a, 1, - new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), - new TGeoRotation("", ang1, ang2, ang3))); - } - auto* tM0c = new TGeoBBox(0.3 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c = new TGeoVolume("microChanTop2", tM0c, medKapton); - volTM0c->SetLineColor(35); - volTM0c->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c, 0, new TGeoCombiTrans(x + (smcWidth / 2) - (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); - mechStavVol->AddNode( - volTM0c, 1, new TGeoCombiTrans(x - (smcWidth / 2) + (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c1 = new TGeoBBox(0.2225 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c1 = new TGeoVolume("microChanBot1", tM0c1, medKapton); - volTM0c1->SetLineColor(6); - volTM0c1->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c1, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick) - (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0c1, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c2 = new TGeoBBox(0.072 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c2 = new TGeoVolume("microChanBot2", tM0c2, medKapton); - volTM0c2->SetLineColor(35); - volTM0c2->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (0.072 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c2r = new TGeoBBox(0.068 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c2r = new TGeoVolume("microChanBot3", tM0c2r, medKapton); - volTM0c2r->SetLineColor(35); - volTM0c2r->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c2r, 0, new TGeoCombiTrans(x - smcWidth / 2 + (0.068 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d = new TGeoBBox(smcSide1Thick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0d = new TGeoVolume("microChanSide1", tM0d, medKapton); - volTM0d->SetLineColor(12); - volTM0d->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0d, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - - auto* tM0d1 = new TGeoBBox(smcSide2Thick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0d1 = new TGeoVolume("microChanSide2", tM0d1, medKapton); - volTM0d1->SetLineColor(12); - volTM0d1->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d1, 0, - new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick / 2), - yMC + 0.03 - (0.003 + 0.035) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0d1, 1, - new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick / 2), - yMC + 0.03 - (0.003 + 0.035) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d2 = new TGeoBBox(smcSide3Thick / 2, (hh + 0.003) / 2, smcLength / 2); - auto* volTM0d2 = new TGeoVolume("microChanSide3", tM0d2, medKapton); - volTM0d2->SetLineColor(12); - volTM0d2->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick / 2), yMC + 0.03 - (0.003 + hh + 0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d2r = new TGeoBBox(smcSide4Thick / 2, (hh + 0.003) / 2, smcLength / 2); - auto* volTM0d2r = new TGeoVolume("microChanSide4", tM0d2r, medKapton); - volTM0d2r->SetLineColor(12); - volTM0d2r->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d2r, 0, - new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + - (smcSide4Thick / 2), - yMC + 0.03 - (0.003 + hh + 0.003) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0e = new TGeoBBox(smcSide5Thick / 2, hh / 2, smcLength / 2); - auto* volTM0e = new TGeoVolume("microChanSide5", tM0e, medKapton); - volTM0e->SetLineColor(12); - volTM0e->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - for (Int_t ie = 0; ie < 11; ie++) { - mechStavVol->AddNode( - volTM0e, 0, - new TGeoCombiTrans(x - (ie * (smcSpace + smcSide5Thick)) + smcWidth / 2 - - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace - (smcSide5Thick / 2), - yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0e, 1, - new TGeoCombiTrans(x + (ie * (smcSpace + smcSide5Thick)) - smcWidth / 2 + - (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + - smcSpace + (smcSide5Thick / 2), - yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - } - - auto* tM0f = new TGeoBBox(0.02 / 2, hh / 2, smcLength / 2); - auto* volTM0f = new TGeoVolume("microChanTop3", tM0f, medKapton); - // Double_t smcChannels=12; - Double_t smcCloseWallvapor = smcWidth / 2 - smcSide1Thick - vaporThick - smcSide2Thick - - smcSide3Thick - 12 * smcSpace - 11 * smcSide5Thick; - Double_t smcCloseWallliquid = smcWidth / 2 - smcSide1Thick - liquidThick - smcSide2Thick - - smcSide4Thick - 12 * smcSpace - 11 * smcSide5Thick; - volTM0f->SetLineColor(12); - volTM0f->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0f, 0, - new TGeoCombiTrans(x + smcCloseWallvapor - (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0f, 1, - new TGeoCombiTrans(x - smcCloseWallliquid + (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - // Head(back) microchannel - - auto* tM0hb = new TGeoBBox(smcWidth / 2, 0.025 / 2, headWidth / 2); - auto* volTM0hb = new TGeoVolume("microChanHeadBackBottom1", tM0hb, medKapton); - volTM0hb->SetLineColor(4); - volTM0hb->SetFillColor(4); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0hb, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0hb, 1, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.05 / 2); - auto* volTM0h1 = new TGeoVolume("microChanHeadBackBottom2", tM0h1, medKapton); - volTM0h1->SetLineColor(5); - volTM0h1->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - headWidth + (0.05 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.18 / 2); - auto* volTM0h2 = new TGeoVolume("microChanHeadBackBottom7", tM0h2, medKapton); - volTM0h2->SetLineColor(6); - volTM0h2->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - 0.02 - (0.18 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); - auto* volTM0h3 = new TGeoVolume("microChanHeadBackBottom3", tM0h3, medKapton); - volTM0h3->SetLineColor(5); - volTM0h3->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.03 / 2); - auto* volTM0b1 = new TGeoVolume("microChanHeadBackBottom4", tM0b1, medKapton); - volTM0b1->SetLineColor(5); - volTM0b1->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + headWidth - (0.03 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.2 / 2); - auto* volTM0b2 = new TGeoVolume("microChanHeadBackBottom5", tM0b2, medKapton); - volTM0b2->SetLineColor(6); - volTM0b2->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + 0.02 + (0.2 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); - auto* volTM0b3 = new TGeoVolume("microChanHeadBackBottom6", tM0b3, medKapton); - volTM0b3->SetLineColor(5); - volTM0b3->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - - auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); - auto* volTM0b = new TGeoVolume("microChanWalls", tM0b, medKapton); - volTM0b->SetLineColor(35); - volTM0b->SetFillColor(35); - for (Int_t ib = 0; ib < nb; ib++) { - // mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x+ib*0.1-xstaMC+0.01,yMC, z, new - // TGeoRotation("",0, 0, 0))); - } - } - - if (mBuildLevel < 4) { - // cooling inlet outlet - auto* tM0dv = new TGeoBBox(vaporThick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0dv = new TGeoVolume("microChanVapor", tM0dv, medWater); - volTM0dv->SetLineColor(2); - volTM0dv->SetFillColor(2); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0dv, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0dl = new TGeoBBox(liquidThick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0dl = new TGeoVolume("microChanLiquid", tM0dl, medWater); - volTM0dl->SetLineColor(3); - volTM0dl->SetFillColor(3); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0dl, 0, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - // small cooling fluid now using water wait for freeon value - auto* tM0dlq = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); - auto* volTM0dlq = new TGeoVolume("smallLiquid", tM0dlq, medWater); - volTM0dlq->SetLineColor(3); - volTM0dlq->SetFillColor(3); - auto* tM0dvp = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); - auto* volTM0dvp = new TGeoVolume("microChanVapor", tM0dvp, medWater); - volTM0dvp->SetLineColor(2); - volTM0dvp->SetFillColor(2); - for (Int_t mo = 1; mo <= chips; mo++) { - for (Int_t is = 0; is < 12; is++) { - mechStavVol->AddNode( - volTM0dlq, 0, new TGeoCombiTrans(x + (is * (smcSpace + smcSide5Thick)) - smcWidth / 2 + (smcSide1Thick) + (vaporThick) + (smcSide2Thick) + (smcSide3Thick) + smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0dvp, 1, new TGeoCombiTrans(x - (is * (smcSpace + smcSide5Thick)) + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - } - } - - if (mBuildLevel < 3) { - // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) - Double_t filWidth = 0.04; - Double_t filHeight = 0.02; - auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, s1); - auto* volT1 = new TGeoVolume("bottomFilament", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT1, 4 * i + 0, - new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * l * i) + s1 / 2, - new TGeoRotation("volT1", -90, alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 1, - new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * l * i) + s1 / 2, - new TGeoRotation("volT1", 90, alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 2, - new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT1", -90, -alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 3, - new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT1", -90, +alpha, 0))); - } - - // Top filament CERP black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(s2, filHeight / 2, filWidth / 2); - auto* volT2 = new TGeoVolume("topFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, new TGeoRotation("volT2", 90, 90 - alpha, 90 - beta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, -90 + alpha, -90 + beta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, -90 + alpha, 90 - beta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, 90 - alpha, -90 + beta))); - } - } - - if (mBuildLevel < 2) { - // Glue Filament and Silicon MicroChannel - auto* tM0 = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); - auto* volTM0 = new TGeoVolume("glueFM", tM0, medGlue); - volTM0->SetLineColor(5); - volTM0->SetFillColor(5); - mechStavVol->AddNode(volTM0, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volTM0, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); - - // Glue microchannel and sensor - auto* glueM = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); - auto* volGlueM = new TGeoVolume("glueMS", glueM, medGlue); - volGlueM->SetLineColor(5); - volGlueM->SetFillColor(5); - mechStavVol->AddNode(volGlueM, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volGlueM, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); - - // Glue sensor and kapton - auto* glue = new TGeoBBox(xsta, klay4 / 2, zsta); - auto* volGlue = new TGeoVolume("glueSensorBus", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 / 2, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(xsta, klay5 / 2, zsta); - auto* volCable = new TGeoVolume("Flexcable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 - klay5 / 2, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structure - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveOuterB(const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kOBModelDummy: - mechStavVol = createStaveModelOuterBDummy(mgr); - break; - case Detector::kOBModel0: - mechStavVol = createStaveModelOuterB0(mgr); - break; - case Detector::kOBModel1: - mechStavVol = createStaveModelOuterB1(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelOuterBDummy(const TGeoManager*) const -{ - // Done, return the stave structure - return nullptr; -} - -TGeoVolume* V1Layer::createStaveModelOuterB0(const TGeoManager* mgr) -{ - Double_t xmod, ymod, zmod; - Double_t xlen, ylen, zlen; - Double_t ypos, zpos; - char volumeName[30]; - - // First create all needed shapes - // The chip - xlen = sOBHalfStaveWidth; - ylen = 0.5 * mStaveThickness; // TO BE CHECKED - zlen = sOBModuleZLength / 2; - - TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); - - xmod = ((TGeoBBox*)chipVol->GetShape())->GetDX(); - ymod = ((TGeoBBox*)chipVol->GetShape())->GetDY(); - zmod = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - - auto* module = new TGeoBBox(xmod, ymod, zmod); - - zlen = sOBModuleZLength * mNumberOfModules; - auto* hstave = new TGeoBBox(xlen, ylen, zlen / 2); - - // We have all shapes: now create the real volumes - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - modVol->SetVisibility(kTRUE); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); - - // Finally build it up - modVol->AddNode(chipVol, 0); - mHierarchy[kChip] = 1; - - for (Int_t j = 0; j < mNumberOfModules; j++) { - ypos = 0.021; // Remove small overlap - M.S: 21may13 - zpos = -hstave->GetDZ() + j * 2 * zmod + zmod; - hstaveVol->AddNode(modVol, j, new TGeoTranslation(0, ypos, zpos)); - mHierarchy[kModule]++; - } - // Done, return the stave structure - return hstaveVol; -} - -TGeoVolume* V1Layer::createStaveModelOuterB1(const TGeoManager* mgr) -{ - Double_t yFlex1 = sOBFlexCableAlThick; - Double_t yFlex2 = sOBFlexCableKapThick; - Double_t flexOverlap = 5; // to be checked - Double_t xHalmSt = sOBHalfStaveWidth / 2; - Double_t rCoolMin = sOBCoolTubeInnerD / 2; - Double_t rCoolMax = rCoolMin + sOBCoolTubeThick; - Double_t kLay1 = 0.004; // to be checked - Double_t kLay2 = sOBGraphiteFoilThick; - - Double_t xlen, ylen; - Double_t ymod, zmod; - Double_t xtru[12], ytru[12]; - Double_t xpos, ypos, ypos1, zpos /*, zpos5cm*/; - Double_t zlen; - char volumeName[30]; - - zlen = (mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap) / 2; - - // First create all needed shapes - TGeoVolume* moduleVol = createModuleOuterB(); - moduleVol->SetVisibility(kTRUE); - ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); - zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); - - auto* busAl = new TGeoBBox("BusAl", xHalmSt, sOBBusCableAlThick / 2, zlen); - auto* busKap = new TGeoBBox("BusKap", xHalmSt, sOBBusCableKapThick / 2, zlen); - - auto* coldPlate = - new TGeoBBox("ColdPlate", sOBHalfStaveWidth / 2, sOBColdPlateThick / 2, zlen); - - auto* coolTube = new TGeoTube("CoolingTube", rCoolMin, rCoolMax, zlen); - auto* coolWater = new TGeoTube("CoolingWater", 0., rCoolMin, zlen); - - xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax(); - auto* graphlat = new TGeoBBox("GraphLateral", xlen / 2, kLay2 / 2, zlen); - - xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax(); - auto* graphmid = new TGeoBBox("GraphMiddle", xlen, kLay2 / 2, zlen); - - ylen = coolTube->GetRmax() - kLay2; - auto* graphvert = new TGeoBBox("GraphVertical", kLay2 / 2, ylen / 2, zlen); - - auto* graphtub = - new TGeoTubeSeg("GraphTube", rCoolMax, rCoolMax + kLay2, zlen, 180., 360.); - - xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; - auto* fleeclat = new TGeoBBox("FleecLateral", xlen / 2, kLay1 / 2, zlen); - - xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; - auto* fleecmid = new TGeoBBox("FleecMiddle", xlen, kLay1 / 2, zlen); - - ylen = coolTube->GetRmax() - kLay2 - kLay1; - auto* fleecvert = new TGeoBBox("FleecVertical", kLay1 / 2, ylen / 2, zlen); - - auto* fleectub = - new TGeoTubeSeg("FleecTube", rCoolMax + kLay2, rCoolMax + kLay1 + kLay2, zlen, 180., 360.); - - auto* flex1_5cm = new TGeoBBox("Flex1MV_5cm", xHalmSt, yFlex1 / 2, flexOverlap / 2); - auto* flex2_5cm = new TGeoBBox("Flex2MV_5cm", xHalmSt, yFlex2 / 2, flexOverlap / 2); - - // The half stave container (an XTru to avoid overlaps between neightbours) - xtru[0] = xHalmSt; - ytru[0] = 0; - xtru[1] = xtru[0]; - ytru[1] = -2 * (ymod + busAl->GetDY() + busKap->GetDY() + coldPlate->GetDY() + graphlat->GetDY() + - fleeclat->GetDY()); - xtru[2] = sOBCoolTubeXDist / 2 + fleectub->GetRmax(); - ytru[2] = ytru[1]; - xtru[3] = xtru[2]; - ytru[3] = ytru[2] - (coolTube->GetRmax() + fleectub->GetRmax()); - xtru[4] = sOBCoolTubeXDist / 2 - fleectub->GetRmax(); - ytru[4] = ytru[3]; - xtru[5] = xtru[4]; - ytru[5] = ytru[2]; - for (Int_t i = 0; i < 6; i++) { - xtru[6 + i] = -xtru[5 - i]; - ytru[6 + i] = ytru[5 - i]; - } - auto* halmStave = new TGeoXtru(2); - halmStave->DefinePolygon(12, xtru, ytru); - halmStave->DefineSection(0, -mZLength / 2); - halmStave->DefineSection(1, mZLength / 2); - - // We have all shapes: now create the real volumes - - TGeoMedium* medAluminum = mgr->GetMedium("IT3_ALUMINUM$"); - TGeoMedium* medCarbon = mgr->GetMedium("IT3_CARBON$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - TGeoMedium* medWater = mgr->GetMedium("IT3_WATER$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT3_CarbonFleece$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT3_FGS003$"); // amec thermasol - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - auto* busAlVol = new TGeoVolume("BusAlVol", busAl, medAluminum); - busAlVol->SetLineColor(kCyan); - busAlVol->SetFillColor(busAlVol->GetLineColor()); - busAlVol->SetFillStyle(4000); // 0% transparent - - auto* busKapVol = new TGeoVolume("BusKapVol", busKap, medKapton); - busKapVol->SetLineColor(kBlue); - busKapVol->SetFillColor(busKapVol->GetLineColor()); - busKapVol->SetFillStyle(4000); // 0% transparent - - auto* coldPlateVol = new TGeoVolume("ColdPlateVol", coldPlate, medCarbon); - coldPlateVol->SetLineColor(kYellow - 3); - coldPlateVol->SetFillColor(coldPlateVol->GetLineColor()); - coldPlateVol->SetFillStyle(4000); // 0% transparent - - auto* coolTubeVol = new TGeoVolume("CoolingTubeVol", coolTube, medKapton); - coolTubeVol->SetLineColor(kGray); - coolTubeVol->SetFillColor(coolTubeVol->GetLineColor()); - coolTubeVol->SetFillStyle(4000); // 0% transparent - - auto* coolWaterVol = new TGeoVolume("CoolingWaterVol", coolWater, medWater); - coolWaterVol->SetLineColor(kBlue); - coolWaterVol->SetFillColor(coolWaterVol->GetLineColor()); - coolWaterVol->SetFillStyle(4000); // 0% transparent - - auto* graphlatVol = new TGeoVolume("GraphiteFoilLateral", graphlat, medFGS003); - graphlatVol->SetLineColor(kGreen); - graphlatVol->SetFillColor(graphlatVol->GetLineColor()); - graphlatVol->SetFillStyle(4000); // 0% transparent - - auto* graphmidVol = new TGeoVolume("GraphiteFoilMiddle", graphmid, medFGS003); - graphmidVol->SetLineColor(kGreen); - graphmidVol->SetFillColor(graphmidVol->GetLineColor()); - graphmidVol->SetFillStyle(4000); // 0% transparent - - auto* graphvertVol = new TGeoVolume("GraphiteFoilVertical", graphvert, medFGS003); - graphvertVol->SetLineColor(kGreen); - graphvertVol->SetFillColor(graphvertVol->GetLineColor()); - graphvertVol->SetFillStyle(4000); // 0% transparent - - auto* graphtubVol = new TGeoVolume("GraphiteFoilPipeCover", graphtub, medFGS003); - graphtubVol->SetLineColor(kGreen); - graphtubVol->SetFillColor(graphtubVol->GetLineColor()); - graphtubVol->SetFillStyle(4000); // 0% transparent - - auto* fleeclatVol = new TGeoVolume("CarbonFleeceLateral", fleeclat, medCarbonFleece); - fleeclatVol->SetLineColor(kViolet); - fleeclatVol->SetFillColor(fleeclatVol->GetLineColor()); - fleeclatVol->SetFillStyle(4000); // 0% transparent - - auto* fleecmidVol = new TGeoVolume("CarbonFleeceMiddle", fleecmid, medCarbonFleece); - fleecmidVol->SetLineColor(kViolet); - fleecmidVol->SetFillColor(fleecmidVol->GetLineColor()); - fleecmidVol->SetFillStyle(4000); // 0% transparent - - auto* fleecvertVol = new TGeoVolume("CarbonFleeceVertical", fleecvert, medCarbonFleece); - fleecvertVol->SetLineColor(kViolet); - fleecvertVol->SetFillColor(fleecvertVol->GetLineColor()); - fleecvertVol->SetFillStyle(4000); // 0% transparent - - auto* fleectubVol = new TGeoVolume("CarbonFleecePipeCover", fleectub, medCarbonFleece); - fleectubVol->SetLineColor(kViolet); - fleectubVol->SetFillColor(fleectubVol->GetLineColor()); - fleectubVol->SetFillStyle(4000); // 0% transparent - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* halmStaveVol = new TGeoVolume(volumeName, halmStave, medAir); - // halmStaveVol->SetLineColor(12); - // halmStaveVol->SetFillColor(12); - // halmStaveVol->SetVisibility(kTRUE); - - auto* flex1_5cmVol = new TGeoVolume("Flex1Vol5cm", flex1_5cm, medAluminum); - auto* flex2_5cmVol = new TGeoVolume("Flex2Vol5cm", flex2_5cm, medKapton); - - flex1_5cmVol->SetLineColor(kRed); - flex2_5cmVol->SetLineColor(kGreen); - - // Now build up the half stave - ypos = -busKap->GetDY(); - halmStaveVol->AddNode(busKapVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos -= (busKap->GetDY() + busAl->GetDY()); - halmStaveVol->AddNode(busAlVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos -= (busAl->GetDY() + ymod); - for (Int_t j = 0; j < mNumberOfModules; j++) { - zpos = -zlen + j * (2 * zmod + sOBModuleGap) + zmod; - halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(0, ypos, zpos)); - mHierarchy[kModule]++; - } - - ypos -= (ymod + coldPlate->GetDY()); - halmStaveVol->AddNode(coldPlateVol, 1, new TGeoTranslation(0, ypos, 0)); - - coolTubeVol->AddNode(coolWaterVol, 1, nullptr); - - xpos = sOBCoolTubeXDist / 2; - ypos1 = ypos - (coldPlate->GetDY() + coolTube->GetRmax()); - halmStaveVol->AddNode(coolTubeVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(coolTubeVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(graphtubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphtubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(fleectubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleectubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - xpos = xHalmSt - graphlat->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + graphlat->GetDY()); - halmStaveVol->AddNode(graphlatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphlatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(graphmidVol, 1, new TGeoTranslation(0, ypos1, 0)); - - xpos = xHalmSt - 2 * graphlat->GetDX() + graphvert->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + graphvert->GetDY()); - halmStaveVol->AddNode(graphvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - xpos = graphmid->GetDX() - graphvert->GetDX(); - halmStaveVol->AddNode(graphvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); - - xpos = xHalmSt - fleeclat->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + fleeclat->GetDY()); - halmStaveVol->AddNode(fleeclatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleeclatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(fleecmidVol, 1, new TGeoTranslation(0, ypos1, 0)); - - xpos = xHalmSt - 2 * fleeclat->GetDX() + fleecvert->GetDX(); - ypos1 = ypos - - (coldPlate->GetDY() + 2 * graphlat->GetDY() + 2 * fleeclat->GetDY() + fleecvert->GetDY()); - halmStaveVol->AddNode(fleecvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleecvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - xpos = fleecmid->GetDX() - fleecvert->GetDX(); - halmStaveVol->AddNode(fleecvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleecvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); - - // THE FOLLOWING IS ONLY A REMINDER FOR WHAT IS STILL MISSING - - // for (Int_t j=0; j<mNumberOfChips; j++) { - - // zpos = -(zact + (mNumberOfChips-1)*modGap)/2 + j*(zMod + modGap) + zMod/2; - // zpos5cm = -(zact + (mNumberOfChips-1)*modGap)/2 + (j+1)*(zMod + modGap) + flexOverlap/2 ; - - // halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(xPos, -ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + ymod, zpos)); - // halmStaveVol->AddNode(moduleVol, mNumberOfChips+j, new TGeoTranslation(-xPos, -ylen + yPos - // + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + ymod +deltaY, zpos)); - - // if((j+1)!=mNumberOfChips){ - // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2,zpos5cm)); - // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2 - // +deltaY,zpos5cm)); - // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2,zpos5cm)); - // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2 +deltaY,zpos5cm)); - // } - // else { - // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2 +deltaY,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate +2*ymod + yFlex1 + yFlex2/2,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2/2 +deltaY,zpos5cm-modGap)); - - // } - // } - // Done, return the half stave structure - return halmStaveVol; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterB(const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kOBModelDummy: - case Detector::kOBModel0: - mechStavVol = createSpaceFrameOuterBDummy(mgr); - break; - case Detector::kOBModel1: - mechStavVol = createSpaceFrameOuterB1(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - - return mechStavVol; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterBDummy(const TGeoManager*) const -{ - // Done, return the stave structur - return nullptr; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterB1(const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medCarbon = mgr->GetMedium("IT3_CARBON$"); - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - - // Local parameters - Double_t sframeWidth = sOBSpaceFrameWidth; - Double_t sframeHeight = sOBSpaceFrameTotHigh - sOBHalfStaveYTrans; - Double_t staveBeamRadius = sOBSFrameBeamRadius; - Double_t staveLa = sOBSpaceFrameLa; - Double_t staveHa = sOBSpaceFrameHa; - Double_t staveLb = sOBSpaceFrameLb; - Double_t staveHb = sOBSpaceFrameHb; - Double_t stavel = sOBSpaceFrameL; - Double_t bottomBeamAngle = sOBSFBotBeamAngle; - Double_t triangleHeight = sframeHeight - staveBeamRadius; - Double_t halmTheta = TMath::ATan(0.5 * sframeWidth / triangleHeight); - // Double_t alpha = TMath::Pi()*3./4. - halmTheta/2.; - Double_t beta = (TMath::Pi() - 2. * halmTheta) / 4.; - // Double_t distCenterSideDown = 0.5*sframeWidth/TMath::Cos(beta); - - Double_t zlen; - Double_t xpos, ypos, zpos; - Double_t seglen; - char volumeName[30]; - - zlen = mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap; - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - if (gGeoManager->GetVolume(volumeName)) { // Should always be so - sframeHeight -= ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDY() * 2; - zlen = ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDZ() * 2; - } - seglen = zlen / mNumberOfModules; - - // First create all needed shapes and volumes - auto* spaceFrame = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, zlen / 2); - auto* segment = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, seglen / 2); - - auto* spaceFrameVol = new TGeoVolume("CarbonFrameVolume", spaceFrame, medAir); - spaceFrameVol->SetVisibility(kFALSE); - - auto* segmentVol = new TGeoVolume("segmentVol", segment, medAir); - - // SpaceFrame - - //--- the top V of the Carbon Fiber Stave (segment) - TGeoArb8* cmStavTop1 = createStaveSide("CFstavTopCornerVol1shape", seglen / 2., halmTheta, -1, - staveLa, staveHa, stavel); - auto* cmStavTopVol1 = new TGeoVolume("CFstavTopCornerVol1", cmStavTop1, medCarbon); - cmStavTopVol1->SetLineColor(35); - - TGeoArb8* cmStavTop2 = createStaveSide("CFstavTopCornerVol2shape", seglen / 2., halmTheta, 1, - staveLa, staveHa, stavel); - auto* cmStavTopVol2 = new TGeoVolume("CFstavTopCornerVol2", cmStavTop2, medCarbon); - cmStavTopVol2->SetLineColor(35); - - auto* trTop1 = new TGeoTranslation(0, sframeHeight / 2, 0); - - //--- the 2 side V - TGeoArb8* cmStavSide1 = - createStaveSide("CFstavSideCornerVol1shape", seglen / 2., beta, -1, staveLb, staveHb, stavel); - auto* cmStavSideVol1 = new TGeoVolume("CFstavSideCornerVol1", cmStavSide1, medCarbon); - cmStavSideVol1->SetLineColor(35); - - TGeoArb8* cmStavSide2 = - createStaveSide("CFstavSideCornerVol2shape", seglen / 2., beta, 1, staveLb, staveHb, stavel); - auto* cmStavSideVol2 = new TGeoVolume("CFstavSideCornerVol2", cmStavSide2, medCarbon); - cmStavSideVol2->SetLineColor(35); - - xpos = -sframeWidth / 2; - ypos = -sframeHeight / 2 + staveBeamRadius + staveHb * TMath::Sin(beta); - auto* ctSideR = new TGeoCombiTrans( - xpos, ypos, 0, new TGeoRotation("", 180 - 2 * beta * TMath::RadToDeg(), 0, 0)); - auto* ctSideL = new TGeoCombiTrans( - -xpos, ypos, 0, new TGeoRotation("", -180 + 2 * beta * TMath::RadToDeg(), 0, 0)); - - segmentVol->AddNode(cmStavTopVol1, 1, trTop1); - segmentVol->AddNode(cmStavTopVol2, 1, trTop1); - segmentVol->AddNode(cmStavSideVol1, 1, ctSideR); - segmentVol->AddNode(cmStavSideVol1, 2, ctSideL); - segmentVol->AddNode(cmStavSideVol2, 1, ctSideR); - segmentVol->AddNode(cmStavSideVol2, 2, ctSideL); - - //--- The beams - // Beams on the sides - Double_t beamPhiPrime = TMath::ASin( - 1. / TMath::Sqrt((1 + TMath::Sin(2 * beta) * TMath::Sin(2 * beta) / - (tanD(sOBSFrameBeamSidePhi) * tanD(sOBSFrameBeamSidePhi))))); - Double_t beamLength = TMath::Sqrt(sframeHeight * sframeHeight / - (TMath::Sin(beamPhiPrime) * TMath::Sin(beamPhiPrime)) + - sframeWidth * sframeWidth / 4.) - - staveLa / 2 - staveLb / 2; - auto* sideBeam = new TGeoTubeSeg(0, staveBeamRadius, beamLength / 2, 0, 180); - auto* sideBeamVol = new TGeoVolume("CFstavSideBeamVol", sideBeam, medCarbon); - sideBeamVol->SetLineColor(35); - - auto* beamRot1 = new TGeoRotation("", /*90-2*beta*/ halmTheta * TMath::RadToDeg(), - -beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot2 = - new TGeoRotation("", 90 - 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot3 = - new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot4 = new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), - -beamPhiPrime * TMath::RadToDeg(), -90); - - TGeoCombiTrans* beamTransf[8]; - xpos = 0.49 * triangleHeight * TMath::Tan(halmTheta); // was 0.5, fix small overlap - ypos = staveBeamRadius / 2; - zpos = seglen / 8; - beamTransf[0] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); - - beamTransf[1] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); - addTranslationToCombiTrans(beamTransf[1], 0, 0, seglen / 2); - - beamTransf[2] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); - - beamTransf[3] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); - addTranslationToCombiTrans(beamTransf[3], 0, 0, seglen / 2); - - beamTransf[4] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); - - beamTransf[5] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); - addTranslationToCombiTrans(beamTransf[5], 0, 0, seglen / 2); - - beamTransf[6] = new TGeoCombiTrans(-xpos, ypos, -zpos, beamRot4); - beamTransf[7] = new TGeoCombiTrans(-xpos, ypos, 3 * zpos, beamRot4); - - //--- Beams of the bottom - auto* bottomBeam1 = - new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 180); - auto* bottomBeam1Vol = new TGeoVolume("CFstavBottomBeam1Vol", bottomBeam1, medCarbon); - bottomBeam1Vol->SetLineColor(35); - - auto* bottomBeam2 = - new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 90); - auto* bottomBeam2Vol = new TGeoVolume("CFstavBottomBeam2Vol", bottomBeam2, medCarbon); - bottomBeam2Vol->SetLineColor(35); - - auto* bottomBeam3 = new TGeoTubeSeg( - 0, staveBeamRadius, 0.5 * sframeWidth / sinD(bottomBeamAngle) - staveLb / 3, 0, 180); - auto* bottomBeam3Vol = new TGeoVolume("CFstavBottomBeam3Vol", bottomBeam3, medCarbon); - bottomBeam3Vol->SetLineColor(35); - - auto* bottomBeamRot1 = new TGeoRotation("", 90, 90, 90); - auto* bottomBeamRot2 = new TGeoRotation("", -90, 90, -90); - - auto* bottomBeamTransf1 = - new TGeoCombiTrans("", 0, -(sframeHeight / 2 - staveBeamRadius), 0, bottomBeamRot1); - auto* bottomBeamTransf2 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 2, bottomBeamRot1); - auto* bottomBeamTransf3 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 2, bottomBeamRot2); - // be careful for beams #3: when "reading" from -z to +z and - // from the bottom of the stave, it should draw a Lambda, and not a V - auto* bottomBeamRot4 = new TGeoRotation("", -90, bottomBeamAngle, -90); - auto* bottomBeamRot5 = new TGeoRotation("", -90, -bottomBeamAngle, -90); - - auto* bottomBeamTransf4 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 4, bottomBeamRot4); - auto* bottomBeamTransf5 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 4, bottomBeamRot5); - - segmentVol->AddNode(sideBeamVol, 1, beamTransf[0]); - segmentVol->AddNode(sideBeamVol, 2, beamTransf[1]); - segmentVol->AddNode(sideBeamVol, 3, beamTransf[2]); - segmentVol->AddNode(sideBeamVol, 4, beamTransf[3]); - segmentVol->AddNode(sideBeamVol, 5, beamTransf[4]); - segmentVol->AddNode(sideBeamVol, 6, beamTransf[5]); - segmentVol->AddNode(sideBeamVol, 7, beamTransf[6]); - segmentVol->AddNode(sideBeamVol, 8, beamTransf[7]); - segmentVol->AddNode(bottomBeam1Vol, 1, bottomBeamTransf1); - segmentVol->AddNode(bottomBeam2Vol, 1, bottomBeamTransf2); - segmentVol->AddNode(bottomBeam2Vol, 2, bottomBeamTransf3); - segmentVol->AddNode(bottomBeam3Vol, 1, bottomBeamTransf4); - segmentVol->AddNode(bottomBeam3Vol, 2, bottomBeamTransf5); - - // Then build up the space frame - for (Int_t i = 0; i < mNumberOfModules; i++) { - zpos = -spaceFrame->GetDZ() + (1 + 2 * i) * segment->GetDZ(); - spaceFrameVol->AddNode(segmentVol, i, new TGeoTranslation(0, 0, zpos)); - } - - // Done, return the space frame structure - return spaceFrameVol; -} - -TGeoVolume* V1Layer::createChipInnerB(const Double_t xchip, const Double_t ychip, - const Double_t zchip, const TGeoManager* mgr) -{ - char volumeName[30]; - Double_t xlen, ylen, zlen; - Double_t xpos, ypos, zpos; - - // First create all needed shapes - - // The chip - auto* chip = new TGeoBBox(xchip, ychip, zchip); - - // The sensor - xlen = chip->GetDX(); - ylen = 0.5 * mSensorThickness; - zlen = chip->GetDZ(); - auto* sensor = new TGeoBBox(xlen, ylen, zlen); - - // We have all shapes: now create the real volumes - TGeoMedium* medSi = mgr->GetMedium("IT3_SI$"); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSChipPattern(), mLayerNumber); - auto* chipVol = new TGeoVolume(volumeName, chip, medSi); - chipVol->SetVisibility(kTRUE); - chipVol->SetLineColor(1); - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSSensorPattern(), mLayerNumber); - auto* sensVol = new TGeoVolume(volumeName, sensor, medSi); - sensVol->SetVisibility(kTRUE); - sensVol->SetLineColor(8); - sensVol->SetLineWidth(1); - sensVol->SetFillColor(sensVol->GetLineColor()); - sensVol->SetFillStyle(4000); // 0% transparent - - // Now build up the chip - xpos = 0.; - ypos = -chip->GetDY() + sensor->GetDY(); - zpos = 0.; - - chipVol->AddNode(sensVol, 1, new TGeoTranslation(xpos, ypos, zpos)); - - // Done, return the chip - return chipVol; -} - -TGeoVolume* V1Layer::createModuleOuterB(const TGeoManager* mgr) -{ - char volumeName[30]; - - Double_t xGap = sOBChipXGap; - Double_t zGap = sOBChipZGap; - - Double_t xchip, ychip, zchip; - Double_t xlen, ylen, zlen; - Double_t xpos, ypos, zpos; - - // First create all needed shapes - - // The chip (the same as for IB) - xlen = (sOBHalfStaveWidth / 2 - xGap / 2) / sOBNChipRows; - ylen = 0.5 * mStaveThickness; // TO BE CHECKED - zlen = (sOBModuleZLength - (sOBChipsPerRow - 1) * zGap) / (2 * sOBChipsPerRow); - - TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); - - xchip = ((TGeoBBox*)chipVol->GetShape())->GetDX(); - ychip = ((TGeoBBox*)chipVol->GetShape())->GetDY(); - zchip = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - - // The module carbon plate - xlen = sOBHalfStaveWidth / 2; - ylen = sOBCarbonPlateThick / 2; - zlen = sOBModuleZLength / 2; - auto* modPlate = new TGeoBBox("CarbonPlate", xlen, ylen, zlen); - - // The glue - ylen = sOBGlueThick / 2; - auto* glue = new TGeoBBox("Glue", xlen, ylen, zlen); - - // The flex cables - ylen = sOBFlexCableAlThick / 2; - auto* flexAl = new TGeoBBox("FlexAl", xlen, ylen, zlen); - - ylen = sOBFlexCableKapThick / 2; - auto* flexKap = new TGeoBBox("FlexKap", xlen, ylen, zlen); - - // The module - xlen = sOBHalfStaveWidth / 2; - ylen = ychip + modPlate->GetDY() + glue->GetDY() + flexAl->GetDY() + flexKap->GetDY(); - zlen = sOBModuleZLength / 2; - auto* module = new TGeoBBox("OBModule", xlen, ylen, zlen); - - // We have all shapes: now create the real volumes - - TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); - TGeoMedium* medCarbon = mgr->GetMedium("IT3_CARBON$"); - TGeoMedium* medGlue = mgr->GetMedium("IT3_GLUE$"); - TGeoMedium* medAluminum = mgr->GetMedium("IT3_ALUMINUM$"); - TGeoMedium* medKapton = mgr->GetMedium("IT3_KAPTON(POLYCH2)$"); - - auto* modPlateVol = new TGeoVolume("CarbonPlateVol", modPlate, medCarbon); - modPlateVol->SetLineColor(kMagenta - 8); - modPlateVol->SetFillColor(modPlateVol->GetLineColor()); - modPlateVol->SetFillStyle(4000); // 0% transparent - - auto* glueVol = new TGeoVolume("GlueVol", glue, medGlue); - glueVol->SetLineColor(kBlack); - glueVol->SetFillColor(glueVol->GetLineColor()); - glueVol->SetFillStyle(4000); // 0% transparent - - auto* flexAlVol = new TGeoVolume("FlexAlVol", flexAl, medAluminum); - flexAlVol->SetLineColor(kRed); - flexAlVol->SetFillColor(flexAlVol->GetLineColor()); - flexAlVol->SetFillStyle(4000); // 0% transparent - - auto* flexKapVol = new TGeoVolume("FlexKapVol", flexKap, medKapton); - flexKapVol->SetLineColor(kGreen); - flexKapVol->SetFillColor(flexKapVol->GetLineColor()); - flexKapVol->SetFillStyle(4000); // 0% transparent - - snprintf(volumeName, 30, "%s%d", o2::its3::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - modVol->SetVisibility(kTRUE); - - // Now build up the module - ypos = -module->GetDY() + modPlate->GetDY(); - modVol->AddNode(modPlateVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos += (modPlate->GetDY() + glue->GetDY()); - modVol->AddNode(glueVol, 1, new TGeoTranslation(0, ypos, 0)); - - xpos = -module->GetDX() + xchip; - ypos += (glue->GetDY() + ychip); - for (Int_t k = 0; k < sOBChipsPerRow; k++) { // put 7x2 chip into one module - zpos = -module->GetDZ() + zchip + k * (2 * zchip + zGap); - modVol->AddNode(chipVol, 2 * k, new TGeoTranslation(xpos, ypos, zpos)); - modVol->AddNode(chipVol, 2 * k + 1, - new TGeoCombiTrans(-xpos, ypos, zpos, new TGeoRotation("", 0, 180, 180))); - mHierarchy[kChip] += 2; - } - - ypos += (ychip + flexAl->GetDY()); - modVol->AddNode(flexAlVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos += (flexAl->GetDY() + flexKap->GetDY()); - modVol->AddNode(flexKapVol, 1, new TGeoTranslation(0, ypos, 0)); - - // Done, return the module - return modVol; -} - -Double_t V1Layer::radiusOmTurboContainer() -{ - Double_t rr, delta, z, lstav, rstav; - - if (mStaveThickness > 89.) { // Very big angle: avoid overflows since surely - return -1; // the radius from lower vertex is the right value - } - - rstav = mLayerRadius + 0.5 * mStaveThickness; - delta = (0.5 * mStaveThickness) / cosD(mStaveTilt); - z = (0.5 * mStaveThickness) * tanD(mStaveTilt); - - rr = rstav - delta; - lstav = (0.5 * mStaveWidth) - z; - - if ((rr * sinD(mStaveTilt) < lstav)) { - return (rr * cosD(mStaveTilt)); - } else { - return -1; - } -} - -void V1Layer::setNumberOfUnits(Int_t u) -{ - if (mLayerNumber < sNumberOmInnerLayers) { - mNumberOfChips = u; - } else { - mNumberOfModules = u; - mNumberOfChips = sOBChipsPerRow; - } -} - -void V1Layer::setStaveTilt(const Double_t t) -{ - if (mIsTurbo) { - mStaveTilt = t; - } else { - LOG(ERROR) << "Not a Turbo layer"; - } -} - -void V1Layer::setStaveWidth(const Double_t w) -{ - if (mIsTurbo) { - mStaveWidth = w; - } else { - LOG(ERROR) << "Not a Turbo layer"; - } -} - -TGeoArb8* V1Layer::createStaveSide(const char* name, Double_t dz, Double_t angle, - Double_t xSign, Double_t L, Double_t H, Double_t l) -{ - // Create one half of the V shape corner of CF stave - - auto* cmStavSide = new TGeoArb8(dz); - cmStavSide->SetName(name); - - // Points must be in clockwise order - cmStavSide->SetVertex(0, 0, 0); - cmStavSide->SetVertex(2, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), - -L * TMath::Cos(angle) - l * TMath::Sin(angle)); - cmStavSide->SetVertex(4, 0, 0); - cmStavSide->SetVertex(6, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), - -L * TMath::Cos(angle) - l * TMath::Sin(angle)); - if (xSign < 0) { - cmStavSide->SetVertex(1, 0, -H); - cmStavSide->SetVertex(3, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(5, 0, -H); - cmStavSide->SetVertex(7, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - } else { - cmStavSide->SetVertex(1, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(3, 0, -H); - cmStavSide->SetVertex(5, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(7, 0, -H); - } - return cmStavSide; -} - -TGeoCombiTrans* V1Layer::createCombiTrans(const char* name, Double_t dy, Double_t dz, - Double_t dphi, Bool_t planeSym) -{ - TGeoTranslation t1(dy * cosD(90. + dphi), dy * sinD(90. + dphi), dz); - TGeoRotation r1("", 0., 0., dphi); - TGeoRotation r2("", 90, 180, -90 - dphi); - - auto* combiTrans1 = new TGeoCombiTrans(name); - combiTrans1->SetTranslation(t1); - if (planeSym) { - combiTrans1->SetRotation(r1); - } else { - combiTrans1->SetRotation(r2); - } - return combiTrans1; -} - -void V1Layer::addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx, Double_t dy, - Double_t dz) const -{ - // Add a dx,dy,dz translation to the initial TGeoCombiTrans - const Double_t* vect = ct->GetTranslation(); - Double_t newVect[3] = {vect[0] + dx, vect[1] + dy, vect[2] + dz}; - ct->SetTranslation(newVect); -} diff --git a/Detectors/Upgrades/IT3/simulation/src/V3Layer.cxx b/Detectors/Upgrades/IT3/simulation/src/V3Layer.cxx index cbc2914b68a74..2a15f13c99bf0 100644 --- a/Detectors/Upgrades/IT3/simulation/src/V3Layer.cxx +++ b/Detectors/Upgrades/IT3/simulation/src/V3Layer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,7 @@ #include "ITS3Simulation/V3Layer.h" #include "ITS3Base/GeometryTGeo.h" -#include "ITS3Simulation/Detector.h" +// #include "ITS3Simulation/Detector.h" #include "ITSMFTSimulation/AlpideChip.h" #include "ITSMFTBase/SegmentationAlpide.h" @@ -543,8 +544,6 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) staveVol->AddNode(modVol, 0, new TGeoTranslation(0, ypos, 0)); mHierarchy[kHalfStave] = 1; - // Mechanical stave structure - // mechStaveVol = createStaveStructInnerB(); if (mechStaveVol) { ypos = (static_cast<TGeoBBox*>(modVol->GetShape()))->GetDY() - ypos; if (mStaveModel != Detector::kIBModel4) { @@ -553,7 +552,7 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) staveVol->AddNode(mechStaveVol, 1, new TGeoCombiTrans(0, -ypos, 0, new TGeoRotation("", 0, 0, 180))); } } else { - TGeoVolume* hstaveVol = createStaveOuterB(); + TGeoVolume* hstaveVol = createStaveModelOuterB2(); if (mStaveModel == Detector::kOBModel0) { // Create simplified stave struct as in v0 staveVol->AddNode(hstaveVol, 0); mHierarchy[kHalfStave] = 1; @@ -564,7 +563,7 @@ TGeoVolume* V3Layer::createStave(const TGeoManager* /*mgr*/) staveVol->AddNode(hstaveVol, 0, new TGeoTranslation(-xpos, ypos, 0)); staveVol->AddNode(hstaveVol, 1, new TGeoTranslation(xpos, ypos + sOBHalfStaveYTrans, 0)); mHierarchy[kHalfStave] = 2; // RS - mechStaveVol = createSpaceFrameOuterB(); + mechStaveVol = createSpaceFrameOuterB2(); if (mechStaveVol) { if (mBuildLevel < 6) { // Carbon @@ -935,40 +934,6 @@ TGeoVolume* V3Layer::createIBFPCAlAnode(const Double_t xcable, const Double_t zc return coverlayVol; } -TGeoVolume* V3Layer::createStaveStructInnerB(const TGeoManager* mgr) -{ - // - // Create the mechanical stave structure - // - // Created: 22 Mar 2013 Chinorat Kobdaj - // Updated: 26 Apr 2013 Mario Sitta - // Updated: 04 Apr 2017 Mario Sitta O2 version - All models obsolete except last one - // Updated: 25 Jan 2018 Mario Sitta Stave width is now a constant - // - - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kIBModelDummy: - mechStavVol = createStaveModelInnerBDummy(mgr); - break; - case Detector::kIBModel0: - case Detector::kIBModel1: - case Detector::kIBModel21: - case Detector::kIBModel22: - case Detector::kIBModel3: - LOG(FATAL) << "Stave model " << mStaveModel << " obsolete and no longer supported"; - break; - case Detector::kIBModel4: - mechStavVol = createStaveModelInnerB4(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - TGeoVolume* V3Layer::createStaveModelInnerBDummy(const TGeoManager*) const { // @@ -1812,41 +1777,6 @@ void V3Layer::createIBConnectorsCSide(const TGeoManager* mgr) connBoxCSide->AddNode(connPlug, 1, new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", 90, -90, 90))); } -TGeoVolume* V3Layer::createStaveOuterB(const TGeoManager* mgr) -{ - // Create the chip stave for the Outer Barrel - // - // Input: - // mgr : the GeoManager (used only to get the proper material) - // - // Output: - // - // Return: - // - // Created: 20 Dec 2013 Mario Sitta - // Updated: 12 Mar 2014 Mario Sitta - // Updated: 19 Jul 2017 Mario Sitta O2 version - // - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kOBModelDummy: - mechStavVol = createStaveModelOuterBDummy(mgr); - break; - case Detector::kOBModel0: - case Detector::kOBModel1: - LOG(FATAL) << "Stave model " << mStaveModel << " obsolete and no longer supported"; - break; - case Detector::kOBModel2: - mechStavVol = createStaveModelOuterB2(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - TGeoVolume* V3Layer::createStaveModelOuterBDummy(const TGeoManager*) const { // diff --git a/Detectors/Upgrades/IT3/simulation/src/V3Services.cxx b/Detectors/Upgrades/IT3/simulation/src/V3Services.cxx index 0f99e37b716cc..bcba51ea056a0 100644 --- a/Detectors/Upgrades/IT3/simulation/src/V3Services.cxx +++ b/Detectors/Upgrades/IT3/simulation/src/V3Services.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -61,6 +62,190 @@ V3Services::V3Services() V3Services::~V3Services() = default; +TGeoVolume* V3Services::createInnerBarrelSupports(const TGeoManager* mgr) +{ + // + // Creates the ITS3 Inner Barrel support half cylinder and foam wedges + // + // Input: + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // a TGeoVolume(Assembly) with the half cylinder and wedges + // + // Created: 11 Feb 2021 Mario Sitta + // Updated: 22 Feb 2021 Mario Sitta Impregnated carbon fleece added + // + + // For the time being we put all relevant parameters here + // May be changed into static const's when definitively set + const Double_t sIBSuppCylRint = 40.0 * sMm; + const Double_t sIBSuppCylThick = 2.20 * sMm; + const Double_t sIBSuppCylYvoid = 0.50 * sMm; + const Double_t sIBSuppCylZLen = 331.20 * sMm; + + const Int_t sNFoamWedges = 12; + const Double_t sFoamZLen = 10.0 * sMm; + const Double_t sFoamEdgeZDist = 5.20 * sMm; + const Double_t sFoamBaseWidth = 4.19 * sMm; + const Double_t sFoamYTrans = 1.59 * sMm; + + // Local variables + TGeoVolume* layerVol; + TGeoVolume* foamVol[3]; + TGeoTube* layerSh; + + Double_t rmin, rmax, zlen, alpha, phi; + Double_t xpos, ypos, zpos; + + // The support half cylinder: a TubeSeg + phi = (sIBSuppCylYvoid / sIBSuppCylRint) * TMath::RadToDeg(); + zlen = sIBSuppCylZLen / 2; + rmin = sIBSuppCylRint; + rmax = rmin + sIBSuppCylThick; + + TGeoTubeSeg* suppCylSh = new TGeoTubeSeg(rmin, rmax, zlen, phi, 180. - phi); + + // The foam wedges: three TubeSeg's + phi = (sFoamBaseWidth / sIBSuppCylRint) * TMath::RadToDeg(); + zlen = sFoamZLen / 2; + + // The inner and outer radii of each foam wedge are the outer and inner + // radii of the IB Layers where they are located + // (except the last one which extends till the support cylinder) + for (Int_t j = 0; j < 3; j++) { + layerVol = mgr->GetVolume(Form("%s%d", o2::its3::GeometryTGeo::getITSLayerPattern(), j)); + if (!layerVol) { // Should really never happen + LOG(FATAL) << "While building services: ITSU Layer " << j << " does not exist"; + } + layerSh = (TGeoTube*)layerVol->GetShape(); + rmin = layerSh->GetRmax(); + + if (j == 2) { + rmax = sIBSuppCylRint; + } else { + layerVol = mgr->GetVolume(Form("%s%d", o2::its3::GeometryTGeo::getITSLayerPattern(), j + 1)); + if (!layerVol) { // Should really never happen + LOG(FATAL) << "While building services: ITSU Layer " << j + 1 << " does not exist"; + } + layerSh = (TGeoTube*)layerVol->GetShape(); + rmax = layerSh->GetRmin(); + } + + foamVol[j] = createFoamWedge(rmin, rmax, zlen, phi); + foamVol[j]->SetName(Form("IBSupportWedge%d", j)); + } + + // We have all shapes: now create the real volumes + TGeoMedium* medCarbon = mgr->GetMedium("IT3_F6151B05M$"); + + TGeoVolume* suppCylVol = new TGeoVolume("IBSupportCylinder", suppCylSh, medCarbon); + suppCylVol->SetFillColor(kBlue); + suppCylVol->SetLineColor(kBlue); + + // Finally put everything in the container volume + TGeoVolumeAssembly* ibSupport = new TGeoVolumeAssembly("IBCylinderSupport"); + + // The support cylinder is aligned to the end of the IB Layers + // (layerSh points to the last Layer inside the support cylinder) + zpos = -layerSh->GetDz() + suppCylSh->GetDz(); + ibSupport->AddNode(suppCylVol, 1, new TGeoTranslation(0, 0, zpos)); + + alpha = ((sIBSuppCylYvoid + sFoamYTrans) / sIBSuppCylRint) * TMath::RadToDeg(); + + Double_t emptySpace = 2 * layerSh->GetDz() - sNFoamWedges * sFoamZLen - 2 * sFoamEdgeZDist; + emptySpace /= (sNFoamWedges - 1); + + for (Int_t i = 0; i < 3; i++) { + for (Int_t j = 0; j < sNFoamWedges; j++) { + zpos = -layerSh->GetDz() + sFoamEdgeZDist + j * (sFoamZLen + emptySpace) + 0.5 * sFoamZLen; + ibSupport->AddNode(foamVol[i], j + 1, new TGeoCombiTrans(0, 0, zpos, new TGeoRotation("", alpha, 0, 0))); + ibSupport->AddNode(foamVol[i], sNFoamWedges + j + 1, new TGeoCombiTrans(0, 0, zpos, new TGeoRotation("", 180. - alpha - phi, 0, 0))); + } + // There are only two wedges at 90deg located at the far ends + zpos = -layerSh->GetDz() + sFoamEdgeZDist + 0.5 * sFoamZLen; + ibSupport->AddNode(foamVol[i], 2 * sNFoamWedges + 1, new TGeoCombiTrans(0, 0, zpos, new TGeoRotation("", 90. - phi / 2, 0, 0))); + ibSupport->AddNode(foamVol[i], 2 * sNFoamWedges + 2, new TGeoCombiTrans(0, 0, -zpos, new TGeoRotation("", 90. - phi / 2, 0, 0))); + } + + // + return ibSupport; +} + +TGeoVolume* V3Services::createFoamWedge(const Double_t rIn, const Double_t rOut, const Double_t zLen, const Double_t phi, const TGeoManager* mgr) +{ + // + // Creates a single foam wedge with glue-impregnated carbon fleece attached + // + // Input: + // rIn : the inner radius + // rOut : the outer radius + // zLen : the half length along Z + // phi : the angular aperture + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // a TGeoVolume with all elements, ready to be displaced + // + // Created: 22 Feb 2021 Mario Sitta + // + + // For the time being we put all relevant parameters here + // May be changed into static const's when definitively set + const Double_t sIBSuppWedgeCFThick = 20.0 * sMicron; + + // Local variables + Double_t rmin, rmax; + + // The foam wedge container: a TubeSeg + TGeoTubeSeg* wedgeSh = new TGeoTubeSeg(rIn, rOut, zLen, 0, phi); + + // The foam wedge: a TubeSeg + rmin = rIn + sIBSuppWedgeCFThick; + rmax = rOut - sIBSuppWedgeCFThick; + TGeoTubeSeg* foamSh = new TGeoTubeSeg(rmin, rmax, zLen, 0, phi); + + // The two carbon fleece layers: two TubeSeg's + rmax = rIn + sIBSuppWedgeCFThick; + TGeoTubeSeg* fleeceInSh = new TGeoTubeSeg(rIn, rmax, zLen, 0, phi); + + rmin = rOut - sIBSuppWedgeCFThick; + TGeoTubeSeg* fleeceOutSh = new TGeoTubeSeg(rmin, rOut, zLen, 0, phi); + + // We have all shapes: now create the real volumes + TGeoMedium* medAir = mgr->GetMedium("IT3_AIR$"); + TGeoMedium* medFoam = mgr->GetMedium("IT3_ERGDUOCEL$"); + TGeoMedium* medFleece = mgr->GetMedium("IT3_IMPREG_FLEECE$"); + + TGeoVolume* wedgeVol = new TGeoVolume("IBSupportWedge", wedgeSh, medAir); + wedgeVol->SetFillColor(kGreen); + wedgeVol->SetLineColor(kGreen); + + TGeoVolume* foamVol = new TGeoVolume("IBSupportFoam", foamSh, medFoam); + foamVol->SetFillColor(kGreen); + foamVol->SetLineColor(kGreen); + + TGeoVolume* fleeceInVol = new TGeoVolume("IBSupportFleeceI", fleeceInSh, medFleece); + fleeceInVol->SetFillColor(kViolet); + fleeceInVol->SetLineColor(kViolet); + + TGeoVolume* fleeceOutVol = new TGeoVolume("IBSupportFleeceO", fleeceOutSh, medFleece); + fleeceOutVol->SetFillColor(kViolet); + fleeceOutVol->SetLineColor(kViolet); + + // Finally put everything in the container volume + wedgeVol->AddNode(foamVol, 1, nullptr); + wedgeVol->AddNode(fleeceInVol, 1, nullptr); + wedgeVol->AddNode(fleeceOutVol, 1, nullptr); + + // Done + return wedgeVol; +} + TGeoVolume* V3Services::createIBEndWheelsSideA(const TGeoManager* mgr) { // diff --git a/Detectors/Upgrades/IT3/workflow/CMakeLists.txt b/Detectors/Upgrades/IT3/workflow/CMakeLists.txt new file mode 100644 index 0000000000000..559c007bdd2f5 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(ITS3Workflow + SOURCES src/DigitReaderSpec.cxx + src/DigitWriterSpec.cxx + src/RecoWorkflow.cxx + src/ClusterWriterWorkflow.cxx + src/ClustererSpec.cxx + src/ClusterWriterSpec.cxx + # src/TrackerSpec.cxx + # src/CookedTrackerSpec.cxx + # src/TrackWriterSpec.cxx + # src/TrackReaderSpec.cxx + # src/VertexReaderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::SimConfig + O2::DataFormatsITS + O2::DataFormatsITS3 + O2::SimulationDataFormat + O2::ITS3Simulation + # O2::ITStracking + # O2::ITSReconstruction + O2::ITS3Reconstruction + # O2::ITSMFTWorkflow + O2::GPUTracking +) + +o2_add_executable(digit-writer-workflow + SOURCES src/digit-writer-workflow.cxx + COMPONENT_NAME its3 + PUBLIC_LINK_LIBRARIES O2::ITS3Workflow) + +o2_add_executable(digit-reader-workflow + SOURCES src/digit-reader-workflow.cxx + COMPONENT_NAME its3 + PUBLIC_LINK_LIBRARIES O2::ITS3Workflow) + +o2_add_executable(reco-workflow + SOURCES src/its3-reco-workflow.cxx + COMPONENT_NAME its3 + PUBLIC_LINK_LIBRARIES O2::ITS3Workflow) + +# o2_add_executable(cluster-writer-workflow +# SOURCES src/its-cluster-writer-workflow.cxx +# COMPONENT_NAME its +# PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) + +# o2_add_executable(cluster-reader-workflow +# SOURCES src/its-cluster-reader-workflow.cxx +# COMPONENT_NAME its +# PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) + diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterReaderSpec.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterReaderSpec.h new file mode 100644 index 0000000000000..2453653544f25 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterReaderSpec.h @@ -0,0 +1,80 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.h + +#ifndef O2_ITSMFT_CLUSTERREADER +#define O2_ITSMFT_CLUSTERREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsITS3/CompCluster.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its3 +{ + +class ClusterReader : public Task +{ + public: + ClusterReader() = delete; + ClusterReader(bool useMC, bool usePatterns = true); + ~ClusterReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector<o2::itsmft::ROFRecord> mClusROFRec, *mClusROFRecPtr = &mClusROFRec; + std::vector<o2::its3::CompClusterExt> mClusterCompArray, *mClusterCompArrayPtr = &mClusterCompArray; + std::vector<unsigned char> mPatternsArray, *mPatternsArrayPtr = &mPatternsArray; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mClusterMCTruth, *mClusterMCTruthPtr = &mClusterMCTruth; + std::vector<o2::itsmft::MC2ROFRecord> mClusMC2ROFs, *mClusMC2ROFsPtr = &mClusMC2ROFs; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginIT3; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + bool mUsePatterns = true; // send patterns + + std::string mDetName = "IT3"; + std::string mDetNameLC = "it3"; + std::string mFileName = ""; + std::string mClusTreeName = "o2sim"; + std::string mClusROFBranchName = "ClustersROF"; + std::string mClusterPattBranchName = "ClusterPatt"; + std::string mClusterCompBranchName = "ClusterComp"; + std::string mClustMCTruthBranchName = "ClusterMCTruth"; + std::string mClustMC2ROFBranchName = "ClustersMC2ROF"; +}; + +/// create a processor spec +/// read ITS/MFT cluster data from a root file +framework::DataProcessorSpec getITS3ClusterReaderSpec(bool useMC = true, bool usePatterns = true); + +} // namespace its3 +} // namespace o2 + +#endif /* O2_ITSMFT_CLUSTERREADER */ diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterSpec.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterSpec.h new file mode 100644 index 0000000000000..49106871d89d5 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterSpec.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.h + +#ifndef O2_ITS_CLUSTERWRITER +#define O2_ITS_CLUSTERWRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace its3 +{ + +/// create a processor spec +/// write ITS clusters to ROOT file +framework::DataProcessorSpec getClusterWriterSpec(bool useMC); + +} // namespace its3 +} // namespace o2 + +#endif /* O2_ITS_CLUSTERWRITER */ diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterWorkflow.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterWorkflow.h new file mode 100644 index 0000000000000..05268e7ca3a1e --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClusterWriterWorkflow.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS_CLUSTER_WRITER_WORKFLOW_H +#define O2_ITS_CLUSTER_WRITER_WORKFLOW_H + +/// @file ClusterWriterWorkflow.h + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace its3 +{ + +namespace cluster_writer_workflow +{ +framework::WorkflowSpec getWorkflow(bool useMC); +} + +} // namespace its3 +} // namespace o2 +#endif diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClustererSpec.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClustererSpec.h new file mode 100644 index 0000000000000..c1dd586a86766 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/ClustererSpec.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClustererSpec.h + +#ifndef O2_ITS_CLUSTERERDPL +#define O2_ITS_CLUSTERERDPL + +#include <fstream> + +#include "ITS3Reconstruction/Clusterer.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +using namespace o2::framework; + +namespace o2 +{ + +namespace its3 +{ + +class ClustererDPL : public Task +{ + public: + ClustererDPL(bool useMC) : mUseMC(useMC) {} + ~ClustererDPL() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + int mState = 0; + bool mUseMC = true; + bool mPatterns = true; + int mNThreads = 1; + std::unique_ptr<std::ifstream> mFile = nullptr; + std::unique_ptr<o2::its3::Clusterer> mClusterer = nullptr; +}; + +/// create a processor spec +/// run ITS cluster finder +framework::DataProcessorSpec getClustererSpec(bool useMC); + +} // namespace its3 +} // namespace o2 + +#endif /* O2_ITS_CLUSTERERDPL */ diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitReaderSpec.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitReaderSpec.h new file mode 100644 index 0000000000000..9d0379aa77d78 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitReaderSpec.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h + +#ifndef O2_ITS3_DIGITREADER +#define O2_ITS3_DIGITREADER + +#include "TFile.h" +#include "TTree.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/GBTCalibData.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its3 +{ + +class DigitReader : public Task +{ + public: + DigitReader() = delete; + DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib); + ~DigitReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector<o2::itsmft::Digit> mDigits, *mDigitsPtr = &mDigits; + std::vector<o2::itsmft::GBTCalibData> mCalib, *mCalibPtr = &mCalib; + std::vector<o2::itsmft::ROFRecord> mDigROFRec, *mDigROFRecPtr = &mDigROFRec; + std::vector<o2::itsmft::MC2ROFRecord> mDigMC2ROFs, *mDigMC2ROFsPtr = &mDigMC2ROFs; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + bool mUseCalib = true; // send calib data + + std::string mDetName = ""; + std::string mDetNameLC = ""; + std::string mFileName = ""; + std::string mDigTreeName = "o2sim"; + std::string mDigitBranchName = "Digit"; + std::string mDigROFBranchName = "DigitROF"; + std::string mCalibBranchName = "Calib"; + + std::string mDigtMCTruthBranchName = "DigitMCTruth"; + std::string mDigtMC2ROFBranchName = "DigitMC2ROF"; +}; + +class ITS3DigitReader : public DigitReader +{ + public: + ITS3DigitReader(bool useMC = true, bool useCalib = false) + : DigitReader(o2::detectors::DetID::IT3, useMC, useCalib) + { + mOrigin = o2::header::gDataOriginIT3; + } +}; + +/// create a processor spec +/// read ITS/MFT Digit data from a root file +framework::DataProcessorSpec getITS3DigitReaderSpec(bool useMC = true, bool useCalib = false, std::string defname = "it3digits.root"); + +} // namespace its3 +} // namespace o2 + +#endif /* O2_ITS3_DigitREADER */ diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitWriterSpec.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitWriterSpec.h new file mode 100644 index 0000000000000..309c515d92b93 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/DigitWriterSpec.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_ITS3DIGITWRITER_H_ +#define STEER_ITS3DIGITWRITER_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace its3 +{ + +o2::framework::DataProcessorSpec getITS3DigitWriterSpec(bool mctruth = true, bool dec = false, bool calib = false); +} // namespace its3 +} // end namespace o2 + +#endif /* STEER_ITSMFTDIGITWRITER_H_ */ diff --git a/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/RecoWorkflow.h b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/RecoWorkflow.h new file mode 100644 index 0000000000000..0d4dbe0564e41 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/include/ITS3Workflow/RecoWorkflow.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS_RECOWORKFLOW_H +#define O2_ITS_RECOWORKFLOW_H + +/// @file RecoWorkflow.h + +#include "Framework/WorkflowSpec.h" + +#include "GPUO2Interface.h" +#include "GPUReconstruction.h" +#include "GPUChainITS.h" + +namespace o2 +{ +namespace its3 +{ + +namespace reco_workflow +{ + +framework::WorkflowSpec getWorkflow(bool useMC, const std::string& trmode, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU, + bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, bool eencode = false); +} + +} // namespace its3 +} // namespace o2 +#endif diff --git a/Detectors/Upgrades/IT3/workflow/src/ClusterReaderSpec.cxx b/Detectors/Upgrades/IT3/workflow/src/ClusterReaderSpec.cxx new file mode 100644 index 0000000000000..6df7e6915dda2 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/ClusterReaderSpec.cxx @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.cxx + +#include <vector> + +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "ITS3Workflow/ClusterReaderSpec.h" +#include <cassert> +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::itsmft; + +namespace o2 +{ +namespace its3 +{ + +ClusterReader::ClusterReader(bool useMC, bool usePatterns) +{ + mUseMC = useMC; + mUsePatterns = usePatterns; +} + +void ClusterReader::init(InitContext& ic) +{ + mFileName = o2::utils::concat_string(o2::base::NameConf::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>((mDetNameLC + "-cluster-infile").c_str())); + connectTree(mFileName); +} + +void ClusterReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << mDetName << "ClusterReader pushes " << mClusROFRec.size() << " ROFRecords," + << mClusterCompArray.size() << " compact clusters at entry " << ent; + + // This is a very ugly way of providing DataDescription, which anyway does not need to contain detector name. + // To be fixed once the names-definition class is ready + pc.outputs().snapshot(Output{mOrigin, "CLUSTERSROF", 0, Lifetime::Timeframe}, mClusROFRec); + pc.outputs().snapshot(Output{mOrigin, "COMPCLUSTERS", 0, Lifetime::Timeframe}, mClusterCompArray); + if (mUsePatterns) { + pc.outputs().snapshot(Output{mOrigin, "PATTERNS", 0, Lifetime::Timeframe}, mPatternsArray); + } + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMCTR", 0, Lifetime::Timeframe}, mClusterMCTruth); + pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMC2ROF", 0, Lifetime::Timeframe}, mClusMC2ROFs); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void ClusterReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mClusTreeName.c_str())); + assert(mTree); + + mTree->SetBranchAddress((mDetName + mClusROFBranchName).c_str(), &mClusROFRecPtr); + mTree->SetBranchAddress((mDetName + mClusterCompBranchName).c_str(), &mClusterCompArrayPtr); + if (mUsePatterns) { + mTree->SetBranchAddress((mDetName + mClusterPattBranchName).c_str(), &mPatternsArrayPtr); + } + if (mUseMC) { + if (mTree->GetBranch((mDetName + mClustMCTruthBranchName).c_str()) && + mTree->GetBranch((mDetName + mClustMC2ROFBranchName).c_str())) { + mTree->SetBranchAddress((mDetName + mClustMCTruthBranchName).c_str(), &mClusterMCTruthPtr); + mTree->SetBranchAddress((mDetName + mClustMC2ROFBranchName).c_str(), &mClusMC2ROFsPtr); + } else { + LOG(INFO) << "MC-truth is missing"; + mUseMC = false; + } + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getITS3ClusterReaderSpec(bool useMC, bool usePatterns) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("IT3", "CLUSTERSROF", 0, Lifetime::Timeframe); + outputSpec.emplace_back("IT3", "COMPCLUSTERS", 0, Lifetime::Timeframe); + if (usePatterns) { + outputSpec.emplace_back("IT3", "PATTERNS", 0, Lifetime::Timeframe); + } + if (useMC) { + outputSpec.emplace_back("IT3", "CLUSTERSMCTR", 0, Lifetime::Timeframe); + outputSpec.emplace_back("IT3", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "its3-cluster-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<ClusterReader>(useMC, usePatterns)}, + Options{ + {"its3-cluster-infile", VariantType::String, "o2clus_it3.root", {"Name of the input cluster file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/ClusterWriterSpec.cxx b/Detectors/Upgrades/IT3/workflow/src/ClusterWriterSpec.cxx new file mode 100644 index 0000000000000..1e9722e2718fe --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/ClusterWriterSpec.cxx @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.cxx + +#include <vector> + +#include "ITS3Workflow/ClusterWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsITS3/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its3 +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using CompClusType = std::vector<o2::its3::CompClusterExt>; +using PatternsType = std::vector<unsigned char>; +using ROFrameRType = std::vector<o2::itsmft::ROFRecord>; +using LabelsType = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; +using ROFRecLblT = std::vector<o2::itsmft::MC2ROFRecord>; +using namespace o2::header; + +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto compClustersSize = std::make_shared<int>(0); + auto compClustersSizeGetter = [compClustersSize](CompClusType const& compClusters) { + *compClustersSize = compClusters.size(); + }; + auto logger = [compClustersSize](std::vector<o2::itsmft::ROFRecord> const& rofs) { + LOG(INFO) << "ITS3ClusterWriter pulled " << *compClustersSize << " clusters, in " << rofs.size() << " RO frames"; + }; + return MakeRootTreeWriterSpec("its3-cluster-writer", + "o2clus_it3.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with ITS clusters"}, + BranchDefinition<CompClusType>{InputSpec{"compclus", "IT3", "COMPCLUSTERS", 0}, + "IT3ClusterComp", + compClustersSizeGetter}, + BranchDefinition<PatternsType>{InputSpec{"patterns", "IT3", "PATTERNS", 0}, + "IT3ClusterPatt"}, + BranchDefinition<ROFrameRType>{InputSpec{"ROframes", "IT3", "CLUSTERSROF", 0}, + "IT3ClustersROF", + logger}, + BranchDefinition<LabelsType>{InputSpec{"labels", "IT3", "CLUSTERSMCTR", 0}, + "IT3ClusterMCTruth", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""}, + BranchDefinition<ROFRecLblT>{InputSpec{"MC2ROframes", "IT3", "CLUSTERSMC2ROF", 0}, + "IT3ClustersMC2ROF", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""})(); +} + +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/ClusterWriterWorkflow.cxx b/Detectors/Upgrades/IT3/workflow/src/ClusterWriterWorkflow.cxx new file mode 100644 index 0000000000000..ae79b7797d57d --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/ClusterWriterWorkflow.cxx @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterWorkflow.cxx + +#include "ITS3Workflow/ClusterWriterWorkflow.h" +#include "ITS3Workflow/ClusterWriterSpec.h" + +namespace o2 +{ +namespace its3 +{ + +namespace cluster_writer_workflow +{ + +framework::WorkflowSpec getWorkflow(bool useMC) +{ + framework::WorkflowSpec specs; + + specs.emplace_back(getClusterWriterSpec(useMC)); + + return specs; +} + +} // namespace cluster_writer_workflow +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/ClustererSpec.cxx b/Detectors/Upgrades/IT3/workflow/src/ClustererSpec.cxx new file mode 100644 index 0000000000000..cb671a2dbd7a2 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/ClustererSpec.cxx @@ -0,0 +1,163 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClustererSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "ITS3Workflow/ClustererSpec.h" +#include "DataFormatsITSMFT/Digit.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "ITSMFTReconstruction/ClustererParam.h" +#include "DataFormatsITS3/CompCluster.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsParameters/GRPObject.h" +#include "ITSMFTReconstruction/DigitPixelReader.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "CommonConstants/LHCConstants.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace its3 +{ + +void ClustererDPL::init(InitContext& ic) +{ + mClusterer = std::make_unique<o2::its3::Clusterer>(); + mClusterer->setNChips(o2::itsmft::ChipMappingITS::getNChips(o2::itsmft::ChipMappingITS::MB) + o2::itsmft::ChipMappingITS::getNChips(o2::itsmft::ChipMappingITS::OB) + SegmentationSuperAlpide::NLayers); + + auto filenameGRP = ic.options().get<std::string>("grp-file"); + const auto grp = o2::parameters::GRPObject::loadFrom(filenameGRP.c_str()); + + if (grp) { + mClusterer->setContinuousReadOut(grp->isDetContinuousReadOut("IT3")); + } else { + LOG(ERROR) << "Cannot retrieve GRP from the " << filenameGRP.c_str() << " file !"; + mState = 0; + return; + } + + mPatterns = !ic.options().get<bool>("no-patterns"); + mNThreads = std::max(1, ic.options().get<int>("nthreads")); + + // settings for the fired pixel overflow masking + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); + const auto& clParams = o2::itsmft::ClustererParam<o2::detectors::DetID::ITS>::Instance(); + auto nbc = clParams.maxBCDiffToMaskBias; + nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); + mClusterer->setMaxBCSeparationToMask(nbc); + mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); + + std::string dictPath = ic.options().get<std::string>("its-dictionary-path"); + std::string dictFile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, dictPath, ".bin"); + if (o2::utils::Str::pathExists(dictFile)) { + mClusterer->loadDictionary(dictFile); + LOG(INFO) << "ITS3Clusterer running with a provided dictionary: " << dictFile; + } else { + LOG(INFO) << "Dictionary " << dictFile << " is absent, ITSClusterer expects cluster patterns"; + } + mState = 1; + mClusterer->print(); +} + +void ClustererDPL::run(ProcessingContext& pc) +{ + auto digits = pc.inputs().get<gsl::span<o2::itsmft::Digit>>("digits"); + auto rofs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROframes"); + + gsl::span<const o2::itsmft::MC2ROFRecord> mc2rofs; + gsl::span<const char> labelbuffer; + if (mUseMC) { + labelbuffer = pc.inputs().get<gsl::span<char>>("labels"); + mc2rofs = pc.inputs().get<gsl::span<o2::itsmft::MC2ROFRecord>>("MC2ROframes"); + } + o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel> labels(labelbuffer); + + LOG(INFO) << "ITSClusterer pulled " << digits.size() << " digits, in " + << rofs.size() << " RO frames"; + LOG(INFO) << "ITSClusterer pulled " << labels.getNElements() << " labels "; + + o2::itsmft::DigitPixelReader reader; + reader.setDigits(digits); + reader.setROFRecords(rofs); + if (mUseMC) { + reader.setMC2ROFRecords(mc2rofs); + reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); + } + reader.init(); + auto orig = o2::header::gDataOriginIT3; + std::vector<o2::its3::CompClusterExt> clusCompVec; + std::vector<o2::itsmft::ROFRecord> clusROFVec; + std::vector<unsigned char> clusPattVec; + + std::unique_ptr<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> clusterLabels; + if (mUseMC) { + clusterLabels = std::make_unique<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>(); + } + mClusterer->process(mNThreads, reader, &clusCompVec, mPatterns ? &clusPattVec : nullptr, &clusROFVec, clusterLabels.get()); + pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0, Lifetime::Timeframe}, clusCompVec); + pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0, Lifetime::Timeframe}, clusROFVec); + pc.outputs().snapshot(Output{orig, "PATTERNS", 0, Lifetime::Timeframe}, clusPattVec); + + if (mUseMC) { + pc.outputs().snapshot(Output{orig, "CLUSTERSMCTR", 0, Lifetime::Timeframe}, *clusterLabels.get()); // at the moment requires snapshot + std::vector<o2::itsmft::MC2ROFRecord> clusterMC2ROframes(mc2rofs.size()); + for (int i = mc2rofs.size(); i--;) { + clusterMC2ROframes[i] = mc2rofs[i]; // Simply, replicate it from digits ? + } + pc.outputs().snapshot(Output{orig, "CLUSTERSMC2ROF", 0, Lifetime::Timeframe}, clusterMC2ROframes); + } + + // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF + // -> consider recalculationg maxROF + LOG(INFO) << "ITSClusterer pushed " << clusCompVec.size() << " clusters, in " << clusROFVec.size() << " RO frames"; +} + +DataProcessorSpec getClustererSpec(bool useMC) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("digits", "IT3", "DIGITS", 0, Lifetime::Timeframe); + inputs.emplace_back("ROframes", "IT3", "DIGITSROF", 0, Lifetime::Timeframe); + + std::vector<OutputSpec> outputs; + outputs.emplace_back("IT3", "COMPCLUSTERS", 0, Lifetime::Timeframe); + outputs.emplace_back("IT3", "PATTERNS", 0, Lifetime::Timeframe); + outputs.emplace_back("IT3", "CLUSTERSROF", 0, Lifetime::Timeframe); + + if (useMC) { + inputs.emplace_back("labels", "IT3", "DIGITSMCTR", 0, Lifetime::Timeframe); + inputs.emplace_back("MC2ROframes", "IT3", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + outputs.emplace_back("IT3", "CLUSTERSMCTR", 0, Lifetime::Timeframe); + outputs.emplace_back("IT3", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "its3-clusterer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<ClustererDPL>(useMC)}, + Options{ + {"its-dictionary-path", VariantType::String, "", {"Path of the cluster-topology dictionary file"}}, + {"grp-file", VariantType::String, "o2sim_grp.root", {"Name of the grp file"}}, + {"no-patterns", o2::framework::VariantType::Bool, false, {"Do not save rare cluster patterns"}}, + {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; +} + +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/DigitReaderSpec.cxx b/Detectors/Upgrades/IT3/workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..574ca48df6fa1 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include <vector> + +#include "TTree.h" + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" +#include "ITS3Workflow/DigitReaderSpec.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include <cassert> + +using namespace o2::framework; +using namespace o2::itsmft; + +namespace o2 +{ +namespace its3 +{ + +DigitReader::DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib) +{ + assert(id == o2::detectors::DetID::IT3); + mDetNameLC = mDetName = id.getName(); + mDigTreeName = "o2sim"; + + mDigitBranchName = mDetName + mDigitBranchName; + mDigROFBranchName = mDetName + mDigROFBranchName; + mCalibBranchName = mDetName + mCalibBranchName; + + mDigtMCTruthBranchName = mDetName + mDigtMCTruthBranchName; + mDigtMC2ROFBranchName = mDetName + mDigtMC2ROFBranchName; + + mUseMC = useMC; + mUseCalib = useCalib; + std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); +} + +void DigitReader::init(InitContext& ic) +{ + mFileName = ic.options().get<std::string>((mDetNameLC + "-digit-infile").c_str()); + connectTree(mFileName); +} + +void DigitReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + + o2::dataformats::IOMCTruthContainerView* plabels = nullptr; + if (mUseMC) { + mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); + } + mTree->GetEntry(ent); + LOG(INFO) << mDetName << "DigitReader pushes " << mDigROFRec.size() << " ROFRecords, " + << mDigits.size() << " digits at entry " << ent; + + // This is a very ugly way of providing DataDescription, which anyway does not need to contain detector name. + // To be fixed once the names-definition class is ready + pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0, Lifetime::Timeframe}, mDigROFRec); + pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0, Lifetime::Timeframe}, mDigits); + if (mUseCalib) { + pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0, Lifetime::Timeframe}, mCalib); + } + + if (mUseMC) { + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", 0, Lifetime::Timeframe}); + plabels->copyandflatten(sharedlabels); + delete plabels; + pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0, Lifetime::Timeframe}, mDigMC2ROFs); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void DigitReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str())); + assert(mTree); + + mTree->SetBranchAddress(mDigROFBranchName.c_str(), &mDigROFRecPtr); + mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsPtr); + if (mUseCalib) { + if (!mTree->GetBranch(mCalibBranchName.c_str())) { + throw std::runtime_error("GBT calibration data requested but not found in the tree"); + } + mTree->SetBranchAddress(mCalibBranchName.c_str(), &mCalibPtr); + } + if (mUseMC) { + if (!mTree->GetBranch(mDigtMC2ROFBranchName.c_str()) || !mTree->GetBranch(mDigtMCTruthBranchName.c_str())) { + throw std::runtime_error("MC data requested but not found in the tree"); + } + mTree->SetBranchAddress(mDigtMC2ROFBranchName.c_str(), &mDigMC2ROFsPtr); + } + LOG(INFO) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getITS3DigitReaderSpec(bool useMC, bool useCalib, std::string defname) +{ + std::vector<OutputSpec> outputSpec; + outputSpec.emplace_back("IT3", "DIGITS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("IT3", "DIGITSROF", 0, Lifetime::Timeframe); + if (useCalib) { + outputSpec.emplace_back("IT3", "GBTCALIB", 0, Lifetime::Timeframe); + } + if (useMC) { + outputSpec.emplace_back("IT3", "DIGITSMCTR", 0, Lifetime::Timeframe); + outputSpec.emplace_back("IT3", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "its3-digit-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask<ITS3DigitReader>(useMC, useCalib)}, + Options{ + {"it3-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}}}; +} + +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/DigitWriterSpec.cxx b/Detectors/Upgrades/IT3/workflow/src/DigitWriterSpec.cxx new file mode 100644 index 0000000000000..43c30d8880343 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/DigitWriterSpec.cxx @@ -0,0 +1,110 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @brief Processor spec for a ROOT file writer for ITSMFT digits + +#include "ITS3Workflow/DigitWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsITSMFT/GBTCalibData.h" +#include "Headers/DataHeader.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include <vector> +#include <string> +#include <algorithm> + +using namespace o2::framework; +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +namespace o2 +{ +namespace its3 +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +using MCCont = o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>; + +/// create the processor spec +/// describing a processor receiving digits for ITS/MFT and writing them to file +DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::header::DataOrigin detOrig, o2::detectors::DetID detId) +{ + std::string detStr = o2::detectors::DetID::getName(detId); + std::string detStrL = dec ? "o2_" : ""; // for decoded digits prepend by o2 + detStrL += detStr; + std::transform(detStrL.begin(), detStrL.end(), detStrL.begin(), ::tolower); + auto logger = [](std::vector<o2::itsmft::Digit> const& inDigits) { + LOG(INFO) << "RECEIVED DIGITS SIZE " << inDigits.size(); + }; + + // the callback to be set as hook for custom action when the writer is closed + auto finishWriting = [](TFile* outputfile, TTree* outputtree) { + const auto* brArr = outputtree->GetListOfBranches(); + int64_t nent = 0; + for (const auto* brc : *brArr) { + int64_t n = ((const TBranch*)brc)->GetEntries(); + if (nent && (nent != n)) { + LOG(ERROR) << "Branches have different number of entries"; + } + nent = n; + } + outputtree->SetEntries(nent); + outputtree->Write("", TObject::kOverwrite); + outputfile->Close(); + }; + + // handler for labels + // This is necessary since we can't store the original label buffer in a ROOT entry -- as is -- if it exceeds a certain size. + // We therefore convert it to a special split class. + auto fillLabels = [](TBranch& branch, std::vector<char> const& labelbuffer, DataRef const& /*ref*/) { + o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel> labels(labelbuffer); + LOG(INFO) << "WRITING " << labels.getNElements() << " LABELS "; + + o2::dataformats::IOMCTruthContainerView outputcontainer; + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); + outputcontainer.adopt(labelbuffer); + br->Fill(); + br->ResetAddress(); + }; + + return MakeRootTreeWriterSpec((detStr + "DigitWriter" + (dec ? "_dec" : "")).c_str(), + (detStrL + "digits.root").c_str(), + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Digits tree"}, + MakeRootTreeWriterSpec::CustomClose(finishWriting), + // in case of labels we first read them as std::vector<char> and process them correctly in the fillLabels hook + BranchDefinition<std::vector<char>>{InputSpec{"digitsMCTR", detOrig, "DIGITSMCTR", 0}, + (detStr + "DigitMCTruth").c_str(), + (mctruth ? 1 : 0), fillLabels}, + BranchDefinition<std::vector<itsmft::MC2ROFRecord>>{InputSpec{"digitsMC2ROF", detOrig, "DIGITSMC2ROF", 0}, + (detStr + "DigitMC2ROF").c_str(), + (mctruth ? 1 : 0)}, + BranchDefinition<std::vector<itsmft::Digit>>{InputSpec{"digits", detOrig, "DIGITS", 0}, + (detStr + "Digit").c_str(), + logger}, + BranchDefinition<std::vector<itsmft::GBTCalibData>>{InputSpec{"calib", detOrig, "GBTCALIB", 0}, + (detStr + "Calib").c_str(), + (calib ? 1 : 0)}, + BranchDefinition<std::vector<itsmft::ROFRecord>>{InputSpec{"digitsROF", detOrig, "DIGITSROF", 0}, + (detStr + "DigitROF").c_str()})(); +} + +DataProcessorSpec getITS3DigitWriterSpec(bool mctruth, bool dec, bool calib) +{ + return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginIT3, o2::detectors::DetID::IT3); +} + +} // end namespace its3 +} // end namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/IT3/workflow/src/RecoWorkflow.cxx new file mode 100644 index 0000000000000..325687aafac48 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/RecoWorkflow.cxx @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecoWorkflow.cxx + +#include "ITS3Workflow/RecoWorkflow.h" +#include "ITS3Workflow/ClustererSpec.h" +#include "ITS3Workflow/ClusterWriterSpec.h" +// #include "ITSWorkflow/TrackerSpec.h" +// #include "ITSWorkflow/TrackWriterSpec.h" +// #include "ITSMFTWorkflow/EntropyEncoderSpec.h" +#include "ITS3Workflow/DigitReaderSpec.h" + +namespace o2 +{ +namespace its3 +{ + +namespace reco_workflow +{ + +framework::WorkflowSpec getWorkflow(bool useMC, const std::string& trmode, o2::gpu::GPUDataTypes::DeviceType dtype, + bool upstreamDigits, bool upstreamClusters, bool disableRootOutput, + bool) +{ + framework::WorkflowSpec specs; + + if (!(upstreamDigits || upstreamClusters)) { + specs.emplace_back(o2::its3::getITS3DigitReaderSpec(useMC, false, "it3digits.root")); + } + + if (!upstreamClusters) { + specs.emplace_back(o2::its3::getClustererSpec(useMC)); + } + if (!disableRootOutput) { + specs.emplace_back(o2::its3::getClusterWriterSpec(useMC)); + } + // specs.emplace_back(o2::its::getTrackerSpec(useMC, trmode, dtype)); + // if (!disableRootOutput) { + // specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); + // } + + // if (eencode) { + // specs.emplace_back(o2::itsmft::getEntropyEncoderSpec("ITS")); + // } + return specs; +} + +} // namespace reco_workflow +} // namespace its3 +} // namespace o2 diff --git a/Detectors/Upgrades/IT3/workflow/src/digit-reader-workflow.cxx b/Detectors/Upgrades/IT3/workflow/src/digit-reader-workflow.cxx new file mode 100644 index 0000000000000..6bddb3ba6810b --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/digit-reader-workflow.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITS3Workflow/DigitReaderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ + ConfigParamSpec{"disable-mc", VariantType::Bool, false, {"disable mc truth"}}, + ConfigParamSpec{"enable-calib-data", VariantType::Bool, false, {"enable writing GBT calibration data"}}, + ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + bool useMC = !cfgc.options().get<bool>("disable-mc"); + bool calib = cfgc.options().get<bool>("enable-calib-data"); + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + wf.emplace_back(o2::its3::getITS3DigitReaderSpec(useMC, calib)); + return wf; +} diff --git a/Detectors/Upgrades/IT3/workflow/src/digit-writer-workflow.cxx b/Detectors/Upgrades/IT3/workflow/src/digit-writer-workflow.cxx new file mode 100644 index 0000000000000..9d6c3c8ecfda8 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/digit-writer-workflow.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITS3Workflow/DigitWriterSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ + ConfigParamSpec{"disable-mc", VariantType::Bool, false, {"disable mc truth"}}, + ConfigParamSpec{"enable-calib-data", VariantType::Bool, false, {"enable writing GBT calibration data"}}, + ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + bool useMC = !cfgc.options().get<bool>("disable-mc"); + bool calib = cfgc.options().get<bool>("enable-calib-data"); + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + wf.emplace_back(o2::its3::getITS3DigitWriterSpec(useMC, true, calib)); + return wf; +} diff --git a/Detectors/Upgrades/IT3/workflow/src/its3-reco-workflow.cxx b/Detectors/Upgrades/IT3/workflow/src/its3-reco-workflow.cxx new file mode 100644 index 0000000000000..436d4a5080bb1 --- /dev/null +++ b/Detectors/Upgrades/IT3/workflow/src/its3-reco-workflow.cxx @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITS3Workflow/RecoWorkflow.h" +#include "CommonUtils/ConfigurableParam.h" +#include "ITStracking/TrackingConfigParam.h" +#include "ITStracking/Configuration.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +#include "GPUO2Interface.h" +#include "GPUReconstruction.h" +#include "GPUChainITS.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<o2::framework::ConfigParamSpec> options{ + {"digits-from-upstream", o2::framework::VariantType::Bool, false, {"digits will be provided from upstream, skip digits reader"}}, + {"clusters-from-upstream", o2::framework::VariantType::Bool, false, {"clusters will be provided from upstream, skip clusterizer"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"tracking-mode", o2::framework::VariantType::String, "sync", {"sync,async,cosmics"}}, + {"entropy-encoding", o2::framework::VariantType::Bool, false, {"produce entropy encoded data"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"gpuDevice", o2::framework::VariantType::Int, 1, {"use gpu device: CPU=1,CUDA=2,HIP=3 (default: CPU)"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" +#include "Framework/Logger.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto trmode = configcontext.options().get<std::string>("tracking-mode"); + auto gpuDevice = static_cast<o2::gpu::GPUDataTypes::DeviceType>(configcontext.options().get<int>("gpuDevice")); + auto extDigits = configcontext.options().get<bool>("digits-from-upstream"); + auto extClusters = configcontext.options().get<bool>("clusters-from-upstream"); + auto disableRootOutput = configcontext.options().get<bool>("disable-root-output"); + auto eencode = configcontext.options().get<bool>("entropy-encoding"); + + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + + auto wf = o2::its3::reco_workflow::getWorkflow(useMC, trmode, gpuDevice, extDigits, extClusters, disableRootOutput, eencode); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + // write the configuration used for the reco workflow + o2::conf::ConfigurableParam::writeINI("o2its3recoflow_configuration.ini"); + + return std::move(wf); +} diff --git a/Detectors/Upgrades/PostLS4/CMakeLists.txt b/Detectors/Upgrades/PostLS4/CMakeLists.txt deleted file mode 100644 index 031729b79c5ed..0000000000000 --- a/Detectors/Upgrades/PostLS4/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -add_subdirectory(IT4) \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/CMakeLists.txt b/Detectors/Upgrades/PostLS4/IT4/CMakeLists.txt deleted file mode 100644 index 4d58e2495d96f..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -add_subdirectory(simulation) -add_subdirectory(base) -add_subdirectory(macros) \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/README.md b/Detectors/Upgrades/PostLS4/IT4/README.md deleted file mode 100644 index 672f26326d8e1..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# IT4 -At the moment the IT4 name is a placeholder for barrel detector. - -# Run the full simulation -Provided O2 has been compiled with upgrades enabled, it is possible to simulate IT4 geometry within the `o2-sim` executable. - -## Simulation -IT4 module is enabled via the `-m IT4` parameter. -In case of `PIPE` to be enabled, the size of the beam pipe is automatically scaled to what is foreseen for the upgrades. - -Typical command to generate MC data: -```bash -o2-sim -m PIPE IT4 [...] -``` - -## Reconstruction -Currently, the reconstruction is driven the `macro/run_trac_alice3.C`, which takes as input the hits generated by simulation. Hits can be smeared upon request (see `kUseSmearing`). \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/base/CMakeLists.txt b/Detectors/Upgrades/PostLS4/IT4/base/CMakeLists.txt deleted file mode 100644 index bcf29a286d57c..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/base/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(ITS4Base - SOURCES src/MisalignmentParameter.cxx - src/GeometryTGeo.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2::ITSMFTBase) - -o2_target_root_dictionary(ITS4Base - HEADERS include/ITS4Base/GeometryTGeo.h - include/ITS4Base/MisalignmentParameter.h) diff --git a/Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/GeometryTGeo.h b/Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/GeometryTGeo.h deleted file mode 100644 index 104b227f419ea..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/base/include/ITS4Base/GeometryTGeo.h +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GeometryTGeo.h -/// \brief Definition of the GeometryTGeo class -/// \author cvetan.cheshkov@cern.ch - 15/02/2007 -/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 - -#ifndef ALICEO2_ITS4_GEOMETRYTGEO_H_ -#define ALICEO2_ITS4_GEOMETRYTGEO_H_ - -#include <TGeoMatrix.h> // for TGeoHMatrix -#include <TObject.h> // for TObject -#include <array> -#include <string> -#include <vector> -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "ITSMFTBase/GeometryTGeo.h" -#include "MathUtils/Utils.h" -#include "Rtypes.h" // for Int_t, Double_t, Bool_t, UInt_t, etc - -class TGeoPNEntry; - -namespace o2 -{ -namespace its4 -{ -/// GeometryTGeo is a simple interface class to TGeoManager. It is used in the simulation -/// and reconstruction in order to query the TGeo ITS geometry. -/// RS: In order to preserve the static character of the class but make it dynamically access -/// geometry, we need to check in every method if the structures are initialized. To be converted -/// to singleton at later stage. - -class GeometryTGeo : public o2::itsmft::GeometryTGeo -{ - public: - typedef o2::math_utils::Transform3D Mat3D; - using DetMatrixCache::getMatrixL2G; - using DetMatrixCache::getMatrixT2GRot; - using DetMatrixCache::getMatrixT2L; - // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation - // it is cheaper to use T2GRot - using DetMatrixCache::getMatrixT2G; - - static GeometryTGeo* Instance() - { - // get (create if needed) a unique instance of the object - if (!sInstance) { - sInstance = std::unique_ptr<GeometryTGeo>(new GeometryTGeo(true, 0)); - } - return sInstance.get(); - } - - // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) - static void adopt(GeometryTGeo* raw); - - // constructor - // ATTENTION: this class is supposed to behave as a singleton, but to make it root-persistent - // we must define public default constructor. - // NEVER use it, it will throw exception if the class instance was already created - // Use GeometryTGeo::Instance() instead - GeometryTGeo(bool build = kFALSE, int loadTrans = 0 - /*o2::base::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, // default transformations to load - o2::math_utils::TransformType::T2G, - o2::math_utils::TransformType::L2G)*/ - ); - - /// Default destructor - ~GeometryTGeo() override = default; - - GeometryTGeo(const GeometryTGeo& src) = delete; - GeometryTGeo& operator=(const GeometryTGeo& geom) = delete; - - // implement filling of the matrix cache - using o2::itsmft::GeometryTGeo::fillMatrixCache; - void fillMatrixCache(int mask) override; - - // cache parameters of sensors tracking frames - void fillTrackingFramesCache(); - - /// Exract ITS parameters from TGeo - void Build(int loadTrans = 0) override; - - int getNumberOfChipRowsPerModule(int lay) const { return mNumberOfChipRowsPerModule[lay]; } - int getNumberOfChipColsPerModule(int lay) const - { - return mNumberOfChipRowsPerModule[lay] ? mNumberOfChipsPerModule[lay] / mNumberOfChipRowsPerModule[lay] : -1; - } - - int getNumberOfChipsPerModule(int lay) const { return mNumberOfChipsPerModule[lay]; } - int getNumberOfChipsPerHalfStave(int lay) const { return mNumberOfChipsPerHalfStave[lay]; } - int getNumberOfChipsPerStave(int lay) const { return mNumberOfChipsPerStave[lay]; } - int getNumberOfChipsPerLayer(int lay) const { return mNumberOfChipsPerLayer[lay]; } - int getNumberOfModules(int lay) const { return mNumberOfModules[lay]; } - int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } - int getNumberOfStaves(int lay) const { return mNumberOfStaves[lay]; } - int getNumberOfLayers() const { return mNumberOfLayers; } - int getChipIndex(int lay, int detInLay) const { return getFirstChipIndex(lay) + detInLay; } - /// This routine computes the chip index number from the layer, stave, and chip number in stave - /// \param int lay The layer number. Starting from 0. - /// \param int sta The stave number. Starting from 0 - /// \param int chipInStave The chip number in the stave. Starting from 0 - int getChipIndex(int lay, int sta, int detInSta) const; - - /// This routine computes the chip index number from the layer, stave, substave and chip number - /// in substave - /// \param int lay The layer number. Starting from 0. - /// \param int sta The stave number. Starting from 0 - /// \param int substa The substave number. Starting from 0 - /// \param int chipInSStave The chip number in the sub stave. Starting from 0 - int getChipIndex(int lay, int sta, int subSta, int detInSubSta) const; - - /// This routine computes the chip index number from the layer,stave, substave module and - /// chip number in module. - /// \param int lay The layer number. Starting from 0. - /// \param int sta The stave number. Starting from 0 - /// \param int substa The substave number. Starting from 0 - /// \param int module The module number ... - /// \param int chipInSStave The chip number in the module. Starting from 0 - int getChipIndex(int lay, int sta, int subSta, int md, int detInMod) const; - - /// This routine computes the layer, stave, substave, module and chip number - /// given the chip index number - /// \param int index The chip index number, starting from zero. - /// \param int lay The layer number. Starting from 0 - /// \param int sta The stave number. Starting from 0 - /// \param int ssta The halfstave number. Starting from 0 - /// \param int mod The module number. Starting from 0 - /// \param int chip The detector number. Starting from 0 - bool getChipId(int index, int& lay, int& sta, int& ssta, int& mod, int& chip) const; - - /// Get chip layer, from 0 - int getLayer(int index) const; - - /// Get chip stave, from 0 - int getStave(int index) const; - - /// Get chip substave id in stave, from 0 - int getHalfStave(int index) const; - - /// Get chip module id in substave, from 0 - int getModule(int index) const; - - /// Get chip number within layer, from 0 - int getChipIdInLayer(int index) const; - - /// Get chip number within stave, from 0 - int getChipIdInStave(int index) const; - - /// Get chip number within stave, from 0 - int getChipIdInHalfStave(int index) const; - - /// Get chip number within module, from 0 - int getChipIdInModule(int index) const; - - int getLastChipIndex(int lay) const { return mLastChipIndex[lay]; } - int getFirstChipIndex(int lay) const { return (lay == 0) ? 0 : mLastChipIndex[lay - 1] + 1; } - const char* getSymbolicName(int index) const - { - /// return symbolic name of sensor - return o2::base::GeometryManager::getSymbolicName(getDetID(), index); - } - - const char* getSymbolicName(int lay, int sta, int det) const - { - /// return symbolic name of sensor - return getSymbolicName(getChipIndex(lay, sta, det)); - } - - /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager - TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } - TGeoHMatrix* getMatrix(int lay, int sta, int sens) const { return getMatrix(getChipIndex(lay, sta, sens)); } - bool getOriginalMatrix(int index, TGeoHMatrix& m) const - { - /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' - /// The method is slow, so it should be used with great care (for caching only) - return o2::base::GeometryManager::getOriginalMatrix(getDetID(), index, m); - } - - bool getOriginalMatrix(int lay, int sta, int det, TGeoHMatrix& m) const - { - /// Get the original (ideal geometry) TGeo matrix for a given chip identified by 'index' - /// The method is slow, so it should be used with great care (for caching only) - return getOriginalMatrix(getChipIndex(lay, sta, det), m); - } - - const Mat3D& getMatrixT2L(int lay, int sta, int det) const { return getMatrixT2L(getChipIndex(lay, sta, det)); } - const Mat3D& getMatrixSensor(int index) const { return getMatrixL2G(index); } - const Mat3D& getMatrixSensor(int lay, int sta, int det) - { - // get positioning matrix of the sensor, alias to getMatrixL2G - return getMatrixSensor(getChipIndex(lay, sta, det)); - } - - const Rot2D& getMatrixT2GRot(int lay, int sta, int sens) - { - /// get matrix for tracking to global frame transformation - return getMatrixT2GRot(getChipIndex(lay, sta, sens)); - } - - bool isTrackingFrameCached() const { return !mCacheRefX.empty(); } - void getSensorXAlphaRefPlane(int index, float& x, float& alpha) const - { - x = getSensorRefX(index); - alpha = getSensorRefAlpha(index); - } - - float getSensorRefX(int isn) const { return mCacheRefX[isn]; } - float getSensorRefAlpha(int isn) const { return mCacheRefAlpha[isn]; } - // Attention: these are transformations wrt sensitive volume! - void localToGlobal(int index, const double* loc, double* glob); - - void localToGlobal(int lay, int sta, int det, const double* loc, double* glob); - - void globalToLocal(int index, const double* glob, double* loc); - - void globalToLocal(int lay, int sta, int det, const double* glob, double* loc); - - void localToGlobalVector(int index, const double* loc, double* glob); - - void globalToLocalVector(int index, const double* glob, double* loc); - - void Print(Option_t* opt = "") const; - - static const char* getITSVolPattern() { return sVolumeName.c_str(); } - static const char* getITSLayerPattern() { return sLayerName.c_str(); } - static const char* getITSWrapVolPattern() { return sWrapperVolumeName.c_str(); } - static const char* getITSStavePattern() { return sStaveName.c_str(); } - static const char* getITSHalfStavePattern() { return sHalfStaveName.c_str(); } - static const char* getITSModulePattern() { return sModuleName.c_str(); } - static const char* getITSChipPattern() { return sChipName.c_str(); } - static const char* getITSSensorPattern() { return sSensorName.c_str(); } - static void setITSVolPattern(const char* nm) { sVolumeName = nm; } - static void setITSLayerPattern(const char* nm) { sLayerName = nm; } - static void setITSWrapVolPattern(const char* nm) { sWrapperVolumeName = nm; } - static void setITSStavePattern(const char* nm) { sStaveName = nm; } - static void setITSHalfStavePattern(const char* nm) { sHalfStaveName = nm; } - static void setITSModulePattern(const char* nm) { sModuleName = nm; } - static void setITSChipPattern(const char* nm) { sChipName = nm; } - static void setITSSensorPattern(const char* nm) { sSensorName = nm; } - /// sym name of the layer - static const char* composeSymNameITS4() { return o2::detectors::DetID(o2::detectors::DetID::IT3).getName(); } - /// sym name of the layer - static const char* composeSymNameLayer(int lr); - - /// Sym name of the stave at given layer - static const char* composeSymNameStave(int lr, int sta); - - /// Sym name of the stave at given layer - static const char* composeSymNameHalfStave(int lr, int sta, int ssta); - - /// Sym name of the substave at given layer/stave - static const char* composeSymNameModule(int lr, int sta, int ssta, int mod); - - /// Sym name of the chip in the given layer/stave/substave/module - static const char* composeSymNameChip(int lr, int sta, int ssta, int mod, int chip); - - protected: - /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) - /// for a given chip 'index' by quering the TGeoManager - TGeoHMatrix* extractMatrixSensor(int index) const; - - // create matrix for transformation from sensor local frame to global one - TGeoHMatrix& createT2LMatrix(int isn); - - // get sensor tracking frame alpha and - void extractSensorXAlpha(int isn, float& x, float& alp); - - /// This routine computes the layer number a given the chip index - /// \param int index The chip index number, starting from zero. - /// \param int indexInLr The chip index inside a layer, starting from zero. - /// \param int lay The layer number. Starting from 0. - bool getLayer(int index, int& lay, int& index2) const; - - /// Determines the number of chips per module on the (sub)stave in the Geometry - /// Also extract the layout: span of module centers in Z and X - /// \param lay: layer number from 0 - int extractNumberOfChipsPerModule(int lay, int& nrow) const; - - /// Determines the number of layers in the Geometry - /// \param lay: layer number, starting from 0 - int extractNumberOfStaves(int lay) const; - - /// Determines the number of substaves in the stave of the layer - /// \param lay: layer number, starting from 0 - int extractNumberOfHalfStaves(int lay) const; - - /// Determines the number of modules in substave in the stave of the layer - /// \param lay: layer number, starting from 0 - /// For the setup w/o modules defined the module and the stave or the substave is the same thing - /// Legacy method, keep it just in case... - int extractNumberOfModules(int lay) const; - - /// Determines the layer detector type the Geometry and - /// returns the detector type id for the layer - /// \param lay: layer number from 0 - int extractLayerChipType(int lay) const; - - /// Determines the number of layers in the Geometry - int extractNumberOfLayers(); - - /// Extract number following the prefix in the name string - int extractVolumeCopy(const char* name, const char* prefix) const; - - TGeoPNEntry* getPNEntry(int index) const - { - /// Get a pointer to the TGeoPNEntry of a chip identified by 'index' - /// Returns NULL in case of invalid index, missing TGeoManager or invalid symbolic name - return o2::base::GeometryManager::getPNEntry(getDetID(), index); - } - - protected: - static constexpr int MAXLAYERS = 15; ///< max number of active layers - - Int_t mNumberOfLayers; ///< number of layers - std::vector<int> mNumberOfStaves; ///< number of staves/layer(layer) - std::vector<int> mNumberOfHalfStaves; ///< the number of substaves/stave(layer) - std::vector<int> mNumberOfModules; ///< number of modules/substave(layer) - std::vector<int> mNumberOfChipsPerModule; ///< number of chips per module (group of chips on substaves) - std::vector<int> mNumberOfChipRowsPerModule; ///< number of chips rows per module (relevant for OB modules) - std::vector<int> mNumberOfChipsPerHalfStave; ///< number of chips per substave - std::vector<int> mNumberOfChipsPerStave; ///< number of chips per stave - std::vector<int> mNumberOfChipsPerLayer; ///< number of chips per stave - std::vector<int> mLastChipIndex; ///< max ID of the detctor in the layer - std::array<char, MAXLAYERS> mLayerToWrapper; ///< Layer to wrapper correspondence - - std::vector<float> mCacheRefX; ///< sensors tracking plane reference X - std::vector<float> mCacheRefAlpha; ///< sensors tracking plane reference alpha - - static std::string sVolumeName; ///< Mother volume name - static std::string sLayerName; ///< Layer name - static std::string sStaveName; ///< Stave name - static std::string sHalfStaveName; ///< HalfStave name - static std::string sModuleName; ///< Module name - static std::string sChipName; ///< Chip name - static std::string sSensorName; ///< Sensor name - static std::string sWrapperVolumeName; ///< Wrapper volume name - - private: - static std::unique_ptr<o2::its4::GeometryTGeo> sInstance; ///< singletone instance - - ClassDefOverride(GeometryTGeo, 1); // ITS geometry based on TGeo -}; -} // namespace its4 -} // namespace o2 - -#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/PostLS4/IT4/base/src/GeometryTGeo.cxx deleted file mode 100644 index 1a12df0555369..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/base/src/GeometryTGeo.cxx +++ /dev/null @@ -1,743 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GeometryTGeo.cxx -/// \brief Implementation of the GeometryTGeo class -/// \author cvetan.cheshkov@cern.ch - 15/02/2007 -/// \author ruben.shahoyan@cern.ch - adapted to ITSupg 18/07/2012 - -// ATTENTION: In opposite to old AliITSgeomTGeo, all indices start from 0, not from 1!!! - -#include "ITS4Base/GeometryTGeo.h" -#include "DetectorsBase/GeometryManager.h" -#include "ITSMFTBase/SegmentationAlpide.h" -#include "MathUtils/Cartesian.h" - -#include "FairLogger.h" // for LOG - -#include <TGeoBBox.h> // for TGeoBBox -#include <TGeoManager.h> // for gGeoManager, TGeoManager -#include <TGeoPhysicalNode.h> // for TGeoPNEntry, TGeoPhysicalNode -#include <TGeoShape.h> // for TGeoShape -#include <TMath.h> // for Nint, ATan2, RadToDeg -#include <TString.h> // for TString, Form -#include "TClass.h" // for TClass -#include "TGeoMatrix.h" // for TGeoHMatrix -#include "TGeoNode.h" // for TGeoNode, TGeoNodeMatrix -#include "TGeoVolume.h" // for TGeoVolume -#include "TMathBase.h" // for Max -#include "TObjArray.h" // for TObjArray -#include "TObject.h" // for TObject - -#include <cctype> // for isdigit -#include <cstdio> // for snprintf, NULL, printf -#include <cstring> // for strstr, strlen - -using namespace TMath; -using namespace o2::its4; -using namespace o2::detectors; - -using Segmentation = o2::itsmft::SegmentationAlpide; - -ClassImp(o2::its4::GeometryTGeo); - -std::unique_ptr<o2::its4::GeometryTGeo> GeometryTGeo::sInstance; - -std::string GeometryTGeo::sVolumeName = "ITSV"; ///< Mother volume name -std::string GeometryTGeo::sLayerName = "ITSULayer"; ///< Layer name -std::string GeometryTGeo::sStaveName = "ITSUStave"; ///< Stave name -std::string GeometryTGeo::sHalfStaveName = "ITSUHalfStave"; ///< HalfStave name -std::string GeometryTGeo::sModuleName = "ITSUModule"; ///< Module name -std::string GeometryTGeo::sChipName = "ITSUChip"; ///< Chip name -std::string GeometryTGeo::sSensorName = "ITSUSensor"; ///< Sensor name -std::string GeometryTGeo::sWrapperVolumeName = "ITSUWrapVol"; ///< Wrapper volume name - -//__________________________________________________________________________ -GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : o2::itsmft::GeometryTGeo(DetID::IT3) -{ - // default c-tor, if build is true, the structures will be filled and the transform matrices - // will be cached - if (sInstance) { - LOG(FATAL) << "Invalid use of public constructor: o2::its4::GeometryTGeo instance exists"; - // throw std::runtime_error("Invalid use of public constructor: o2::its4::GeometryTGeo instance exists"); - } - - for (int i = MAXLAYERS; i--;) { - mLayerToWrapper[i] = -1; - } - if (build) { - Build(loadTrans); - } -} - -//__________________________________________________________________________ -void GeometryTGeo::adopt(GeometryTGeo* raw) -{ - // adopt the unique instance from external raw pointer (to be used only to read saved instance from file) - if (sInstance) { - LOG(FATAL) << "No adoption: o2::its4::GeometryTGeo instance exists"; - } - sInstance = std::unique_ptr<o2::its4::GeometryTGeo>(raw); -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int chipInStave) const -{ - return getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInStave; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int chipInSStave) const -{ - int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInSStave; - if (mNumberOfHalfStaves[lay] && substa > 0) { - n += mNumberOfChipsPerHalfStave[lay] * substa; - } - return n; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIndex(int lay, int sta, int substa, int md, int chipInMod) const -{ - int n = getFirstChipIndex(lay) + mNumberOfChipsPerStave[lay] * sta + chipInMod; - if (mNumberOfHalfStaves[lay] && substa > 0) { - n += mNumberOfChipsPerHalfStave[lay] * substa; - } - if (mNumberOfModules[lay] && md > 0) { - n += mNumberOfChipsPerModule[lay] * md; - } - return n; -} - -//__________________________________________________________________________ -bool GeometryTGeo::getLayer(int index, int& lay, int& indexInLr) const -{ - lay = getLayer(index); - indexInLr = index - getFirstChipIndex(lay); - return kTRUE; -} - -//__________________________________________________________________________ -int GeometryTGeo::getLayer(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - return lay; -} - -//__________________________________________________________________________ -int GeometryTGeo::getStave(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - index -= getFirstChipIndex(lay); - return index / mNumberOfChipsPerStave[lay]; -} - -//__________________________________________________________________________ -int GeometryTGeo::getHalfStave(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - if (mNumberOfHalfStaves[lay] < 0) { - return -1; - } - index -= getFirstChipIndex(lay); - index %= mNumberOfChipsPerStave[lay]; - return index / mNumberOfChipsPerHalfStave[lay]; -} - -//__________________________________________________________________________ -int GeometryTGeo::getModule(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - if (mNumberOfModules[lay] < 0) { - return 0; - } - index -= getFirstChipIndex(lay); - index %= mNumberOfChipsPerStave[lay]; - if (mNumberOfHalfStaves[lay]) { - index %= mNumberOfChipsPerHalfStave[lay]; - } - return index / mNumberOfChipsPerModule[lay]; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIdInLayer(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - index -= getFirstChipIndex(lay); - return index; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIdInStave(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - index -= getFirstChipIndex(lay); - return index % mNumberOfChipsPerStave[lay]; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIdInHalfStave(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - index -= getFirstChipIndex(lay); - return index % mNumberOfChipsPerHalfStave[lay]; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChipIdInModule(int index) const -{ - int lay = 0; - while (index > mLastChipIndex[lay]) { - lay++; - } - index -= getFirstChipIndex(lay); - return index % mNumberOfChipsPerModule[lay]; -} - -//__________________________________________________________________________ -bool GeometryTGeo::getChipId(int index, int& lay, int& sta, int& hsta, int& mod, int& chip) const -{ - lay = getLayer(index); - index -= getFirstChipIndex(lay); - sta = index / mNumberOfChipsPerStave[lay]; - index %= mNumberOfChipsPerStave[lay]; - hsta = mNumberOfHalfStaves[lay] > 0 ? index / mNumberOfChipsPerHalfStave[lay] : -1; - index %= mNumberOfChipsPerHalfStave[lay]; - mod = mNumberOfModules[lay] > 0 ? index / mNumberOfChipsPerModule[lay] : -1; - chip = index % mNumberOfChipsPerModule[lay]; - - return kTRUE; -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameLayer(int lr) -{ - return Form("%s/%s%d", composeSymNameITS4(), getITSLayerPattern(), lr); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameStave(int lr, int stave) -{ - return Form("%s/%s%d", composeSymNameLayer(lr), getITSStavePattern(), stave); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameHalfStave(int lr, int stave, int substave) -{ - return substave >= 0 ? Form("%s/%s%d", composeSymNameStave(lr, stave), getITSHalfStavePattern(), substave) - : composeSymNameStave(lr, stave); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameModule(int lr, int stave, int substave, int mod) -{ - return mod >= 0 ? Form("%s/%s%d", composeSymNameHalfStave(lr, stave, substave), getITSModulePattern(), mod) - : composeSymNameHalfStave(lr, stave, substave); -} - -//__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameChip(int lr, int sta, int substave, int mod, int chip) -{ - return Form("%s/%s%d", composeSymNameModule(lr, sta, substave, mod), getITSChipPattern(), chip); -} - -//__________________________________________________________________________ -TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const -{ - // extract matrix transforming from the PHYSICAL sensor frame to global one - // Note, the if the effective sensitive layer thickness is smaller than the - // total physical sensor tickness, this matrix is biased and connot be used - // directly for transformation from sensor frame to global one. - // - // Therefore we need to add a shift - - int lay, stav, sstav, mod, chipInMod; - getChipId(index, lay, stav, sstav, mod, chipInMod); - - int wrID = mLayerToWrapper[lay]; - - TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getITSVolPattern()); - - if (wrID >= 0) { - path += Form("%s%d_1/", getITSWrapVolPattern(), wrID); - } - - path += - Form("%s%d_1/%s%d_%d/", GeometryTGeo::getITSLayerPattern(), lay, GeometryTGeo::getITSStavePattern(), lay, stav); - - if (mNumberOfHalfStaves[lay] > 0) { - path += Form("%s%d_%d/", GeometryTGeo::getITSHalfStavePattern(), lay, sstav); - } - if (mNumberOfModules[lay] > 0) { - path += Form("%s%d_%d/", GeometryTGeo::getITSModulePattern(), lay, mod); - } - path += - Form("%s%d_%d/%s%d_1", GeometryTGeo::getITSChipPattern(), lay, chipInMod, GeometryTGeo::getITSSensorPattern(), lay); - - static TGeoHMatrix matTmp; - gGeoManager->PushPath(); - - if (!gGeoManager->cd(path.Data())) { - gGeoManager->PopPath(); - LOG(ERROR) << "Error in cd-ing to " << path.Data(); - return nullptr; - } // end if !gGeoManager - - matTmp = *gGeoManager->GetCurrentMatrix(); // matrix may change after cd - // RSS - // printf("%d/%d/%d %s\n",lay,stav,detInSta,path.Data()); - // mat->Print(); - // Restore the modeler state. - gGeoManager->PopPath(); - - // account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor ticknesses - static TGeoTranslation tra(0., 0.5 * (Segmentation::SensorLayerThickness - Segmentation::SensorLayerThicknessEff), 0.); - - matTmp *= tra; - - return &matTmp; -} - -//__________________________________________________________________________ -void GeometryTGeo::Build(int loadTrans) -{ - if (isBuilt()) { - LOG(WARNING) << "Already built"; - return; // already initialized - } - - if (!gGeoManager) { - // RSTODO: in future there will be a method to load matrices from the CDB - LOG(FATAL) << "Geometry is not loaded"; - } - - mNumberOfLayers = extractNumberOfLayers(); - if (!mNumberOfLayers) { - return; - } - - mNumberOfStaves.resize(mNumberOfLayers); - mNumberOfHalfStaves.resize(mNumberOfLayers); - mNumberOfModules.resize(mNumberOfLayers); - mNumberOfChipsPerModule.resize(mNumberOfLayers); - mNumberOfChipRowsPerModule.resize(mNumberOfLayers); - mNumberOfChipsPerHalfStave.resize(mNumberOfLayers); - mNumberOfChipsPerStave.resize(mNumberOfLayers); - mNumberOfChipsPerLayer.resize(mNumberOfLayers); - mLastChipIndex.resize(mNumberOfLayers); - int numberOfChips = 0; - - for (int i = 0; i < mNumberOfLayers; i++) { - mNumberOfStaves[i] = extractNumberOfStaves(i); - mNumberOfHalfStaves[i] = extractNumberOfHalfStaves(i); - mNumberOfModules[i] = extractNumberOfModules(i); - mNumberOfChipsPerModule[i] = extractNumberOfChipsPerModule(i, mNumberOfChipRowsPerModule[i]); - mNumberOfChipsPerHalfStave[i] = mNumberOfChipsPerModule[i] * Max(1, mNumberOfModules[i]); - mNumberOfChipsPerStave[i] = mNumberOfChipsPerHalfStave[i] * Max(1, mNumberOfHalfStaves[i]); - mNumberOfChipsPerLayer[i] = mNumberOfChipsPerStave[i] * mNumberOfStaves[i]; - numberOfChips += mNumberOfChipsPerLayer[i]; - mLastChipIndex[i] = numberOfChips - 1; - } - setSize(numberOfChips); - fillTrackingFramesCache(); - // - fillMatrixCache(loadTrans); -} - -//__________________________________________________________________________ -void GeometryTGeo::fillMatrixCache(int mask) -{ - // populate matrix cache for requested transformations - // - if (mSize < 1) { - LOG(WARNING) << "The method Build was not called yet"; - Build(mask); - return; - } - - // build matrices - if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) { - // Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation - LOG(INFO) << "Loading ITS L2G matrices from TGeo"; - auto& cacheL2G = getCacheL2G(); - cacheL2G.setSize(mSize); - - for (int i = 0; i < mSize; i++) { - TGeoHMatrix* hm = extractMatrixSensor(i); - cacheL2G.setMatrix(Mat3D(*hm), i); - } - } - - if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)) && !getCacheT2L().isFilled()) { - // matrices for Tracking to Local (Sensor!!! rather than the full chip) frame transformation - LOG(INFO) << "Loading ITS T2L matrices from TGeo"; - auto& cacheT2L = getCacheT2L(); - cacheT2L.setSize(mSize); - for (int i = 0; i < mSize; i++) { - TGeoHMatrix& hm = createT2LMatrix(i); - cacheT2L.setMatrix(Mat3D(hm), i); - } - } - - if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2G)) && !getCacheT2G().isFilled()) { - LOG(WARNING) << "It is faster to use 2D rotation for T2G instead of full Transform3D matrices"; - // matrices for Tracking to Global frame transformation - LOG(INFO) << "Loading ITS T2G matrices from TGeo"; - auto& cacheT2G = getCacheT2G(); - cacheT2G.setSize(mSize); - - for (int i = 0; i < mSize; i++) { - TGeoHMatrix& mat = createT2LMatrix(i); - mat.MultiplyLeft(extractMatrixSensor(i)); - cacheT2G.setMatrix(Mat3D(mat), i); - } - } - - if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)) && !getCacheT2GRot().isFilled()) { - // 2D rotation matrices for Tracking frame to Global rotations - LOG(INFO) << "Loading ITS T2G rotation 2D matrices"; - auto& cacheT2Gr = getCacheT2GRot(); - cacheT2Gr.setSize(mSize); - for (int i = 0; i < mSize; i++) { - cacheT2Gr.setMatrix(Rot2D(getSensorRefAlpha(i)), i); - } - } -} - -//__________________________________________________________________________ -void GeometryTGeo::fillTrackingFramesCache() -{ - // fill for every sensor its tracking frame parameteres - if (!isTrackingFrameCached()) { - // special cache for sensors tracking frame X and alpha params - mCacheRefX.resize(mSize); - mCacheRefAlpha.resize(mSize); - for (int i = 0; i < mSize; i++) { - extractSensorXAlpha(i, mCacheRefX[i], mCacheRefAlpha[i]); - } - } -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfLayers() -{ - // int numberOfLayers = 0; - - // TGeoVolume* itsV = gGeoManager->GetVolume(getITSVolPattern()); - // if (!itsV) { - // LOG(FATAL) << "ITS volume " << getITSVolPattern() << " is not in the geometry"; - // } - - // // Loop on all ITSV nodes, count Layer volumes by checking names - // // Build on the fly layer - wrapper correspondence - // TObjArray* nodes = itsV->GetNodes(); - // int nNodes = nodes->GetEntriesFast(); - - // for (int j = 0; j < nNodes; j++) { - // int lrID = -1; - // TGeoNode* nd = (TGeoNode*)nodes->At(j); - // const char* name = nd->GetName(); - - // if (strstr(name, getITSLayerPattern())) { - // numberOfLayers++; - // if ((lrID = extractVolumeCopy(name, GeometryTGeo::getITSLayerPattern())) < 0) { - // LOG(FATAL) << "Failed to extract layer ID from the " << name; - // exit(1); - // } - - // mLayerToWrapper[lrID] = -1; // not wrapped - // } else if (strstr(name, getITSWrapVolPattern())) { // this is a wrapper volume, may cointain layers - // int wrID = -1; - // if ((wrID = extractVolumeCopy(name, GeometryTGeo::getITSWrapVolPattern())) < 0) { - // LOG(FATAL) << "Failed to extract wrapper ID from the " << name; - // exit(1); - // } - - // TObjArray* nodesW = nd->GetNodes(); - // int nNodesW = nodesW->GetEntriesFast(); - - // for (int jw = 0; jw < nNodesW; jw++) { - // TGeoNode* ndW = (TGeoNode*)nodesW->At(jw); - // if (strstr(ndW->GetName(), getITSLayerPattern())) { - // if ((lrID = extractVolumeCopy(ndW->GetName(), GeometryTGeo::getITSLayerPattern())) < 0) { - // LOG(FATAL) << "Failed to extract layer ID from the " << name; - // exit(1); - // } - // numberOfLayers++; - // mLayerToWrapper[lrID] = wrID; - // } - // } - // } - // } - // return numberOfLayers; - return 10; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfStaves(int lay) const -{ - int numberOfStaves = 0; - char laynam[30]; - snprintf(laynam, 30, "%s%d", getITSLayerPattern(), lay); - TGeoVolume* volLr = gGeoManager->GetVolume(laynam); - if (!volLr) { - LOG(FATAL) << "can't find " << laynam << " volume"; - return -1; - } - - // Loop on all layer nodes, count Stave volumes by checking names - int nNodes = volLr->GetNodes()->GetEntries(); - for (int j = 0; j < nNodes; j++) { - // LOG(INFO) << "L" << lay << " " << j << " of " << nNodes << " " - // << volLr->GetNodes()->At(j)->GetName() << " " - // << getITSStavePattern() << " -> " << numberOfStaves; - if (strstr(volLr->GetNodes()->At(j)->GetName(), getITSStavePattern())) { - numberOfStaves++; - } - } - return numberOfStaves; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfHalfStaves(int lay) const -{ - if (sHalfStaveName.empty()) { - return 0; // for the setup w/o substave defined the stave and the substave is the same thing - } - int nSS = 0; - char stavnam[30]; - snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); - TGeoVolume* volLd = gGeoManager->GetVolume(stavnam); - if (!volLd) { - LOG(FATAL) << "can't find volume " << stavnam; - } - // Loop on all stave nodes, count Chip volumes by checking names - int nNodes = volLd->GetNodes()->GetEntries(); - for (int j = 0; j < nNodes; j++) { - if (strstr(volLd->GetNodes()->At(j)->GetName(), getITSHalfStavePattern())) { - nSS++; - } - } - return nSS; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfModules(int lay) const -{ - if (sModuleName.empty()) { - return 0; - } - - char stavnam[30]; - TGeoVolume* volLd = nullptr; - - if (!sHalfStaveName.empty()) { - snprintf(stavnam, 30, "%s%d", getITSHalfStavePattern(), lay); - volLd = gGeoManager->GetVolume(stavnam); - } - if (!volLd) { // no substaves, check staves - snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); - volLd = gGeoManager->GetVolume(stavnam); - } - if (!volLd) { - return 0; - } - - int nMod = 0; - - // Loop on all substave nodes, count module volumes by checking names - int nNodes = volLd->GetNodes()->GetEntries(); - - for (int j = 0; j < nNodes; j++) { - if (strstr(volLd->GetNodes()->At(j)->GetName(), getITSModulePattern())) { - nMod++; - } - } - return nMod; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfChipsPerModule(int lay, int& nrow) const -{ - int numberOfChips = 0; - char stavnam[30]; - TGeoVolume* volLd = nullptr; - - if (!sModuleName.empty()) { - snprintf(stavnam, 30, "%s%d", getITSModulePattern(), lay); - volLd = gGeoManager->GetVolume(stavnam); - } - if (!volLd) { // no modules on this layer, check substaves - if (!sHalfStaveName.empty()) { - snprintf(stavnam, 30, "%s%d", getITSHalfStavePattern(), lay); - volLd = gGeoManager->GetVolume(stavnam); - } - } - if (!volLd) { // no substaves on this layer, check staves - snprintf(stavnam, 30, "%s%d", getITSStavePattern(), lay); - volLd = gGeoManager->GetVolume(stavnam); - } - if (!volLd) { - LOG(FATAL) << "can't find volume containing chips on layer " << lay; - } - - // Loop on all stave nodes, count Chip volumes by checking names - int nNodes = volLd->GetNodes()->GetEntries(); - - double xmin = 1e9, xmax = -1e9, zmin = 1e9, zmax = -1e9; - double lab[3], loc[3] = {0, 0, 0}; - double dx = -1, dz = -1; - - for (int j = 0; j < nNodes; j++) { - // AliInfo(Form("L%d %d of %d %s %s -> - // %d",lay,j,nNodes,volLd->GetNodes()->At(j)->GetName(),GetITSChipPattern(),numberOfChips)); - TGeoNodeMatrix* node = (TGeoNodeMatrix*)volLd->GetNodes()->At(j); - if (!strstr(node->GetName(), getITSChipPattern())) { - continue; - } - node->LocalToMaster(loc, lab); - if (lab[0] > xmax) { - xmax = lab[0]; - } - if (lab[0] < xmin) { - xmin = lab[0]; - } - if (lab[2] > zmax) { - zmax = lab[2]; - } - if (lab[2] < zmin) { - zmin = lab[2]; - } - - numberOfChips++; - - if (dx < 0) { - TGeoShape* chShape = node->GetVolume()->GetShape(); - TGeoBBox* bbox = dynamic_cast<TGeoBBox*>(chShape); - if (!bbox) { - LOG(FATAL) << "Chip " << node->GetName() << " volume is of unprocessed shape " << chShape->IsA()->GetName(); - } else { - dx = 2 * bbox->GetDX(); - dz = 2 * bbox->GetDZ(); - } - } - } - - double spanX = xmax - xmin; - double spanZ = zmax - zmin; - nrow = TMath::Nint(spanX / dx + 1); - int ncol = TMath::Nint(spanZ / dz + 1); - if (nrow * ncol != numberOfChips) { - LOG(ERROR) << "Inconsistency between Nchips=" << numberOfChips << " and Nrow*Ncol=" << nrow << "*" << ncol << "->" - << nrow * ncol << "\n" - << "Extracted chip dimensions (x,z): " << dx << " " << dz << " Module Span: " << spanX << " " << spanZ; - } - return numberOfChips; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractLayerChipType(int lay) const -{ - char stavnam[30]; - snprintf(stavnam, 30, "%s%d", getITSLayerPattern(), lay); - TGeoVolume* volLd = gGeoManager->GetVolume(stavnam); - if (!volLd) { - LOG(FATAL) << "can't find volume " << stavnam; - return -1; - } - return volLd->GetUniqueID(); -} - -//__________________________________________________________________________ -void GeometryTGeo::Print(Option_t*) const -{ - printf("NLayers:%d NChips:%d\n", mNumberOfLayers, getNumberOfChips()); - if (!isBuilt()) { - return; - } - - for (int i = 0; i < mNumberOfLayers; i++) { - printf( - "Lr%2d\tNStav:%2d\tNChips:%2d " - "(%dx%-2d)\tNMod:%d\tNSubSt:%d\tNSt:%3d\tChip#:%5d:%-5d\tWrapVol:%d\n", - i, mNumberOfStaves[i], mNumberOfChipsPerModule[i], mNumberOfChipRowsPerModule[i], - mNumberOfChipRowsPerModule[i] ? mNumberOfChipsPerModule[i] / mNumberOfChipRowsPerModule[i] : 0, - mNumberOfModules[i], mNumberOfHalfStaves[i], mNumberOfStaves[i], getFirstChipIndex(i), getLastChipIndex(i), - mLayerToWrapper[i]); - } -} - -//__________________________________________________________________________ -void GeometryTGeo::extractSensorXAlpha(int isn, float& x, float& alp) -{ - // calculate r and phi of the impact of the normal on the sensor - // (i.e. phi of the tracking frame alpha and X of the sensor in this frame) - double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; - const TGeoHMatrix* matL2G = extractMatrixSensor(isn); - - matL2G->LocalToMaster(locA, gloA); - matL2G->LocalToMaster(locB, gloB); - double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1]; - double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy); - double xp = gloB[0] - dx * t, yp = gloB[1] - dy * t; - x = Sqrt(xp * xp + yp * yp); - alp = ATan2(yp, xp); - o2::math_utils::bringTo02Pi(alp); -} - -//__________________________________________________________________________ -TGeoHMatrix& GeometryTGeo::createT2LMatrix(int isn) -{ - // create for sensor isn the TGeo matrix for Tracking to Local frame transformations - static TGeoHMatrix t2l; - float x = 0.f, alp = 0.f; - extractSensorXAlpha(isn, x, alp); - t2l.Clear(); - t2l.RotateZ(alp * RadToDeg()); // rotate in direction of normal to the sensor plane - const TGeoHMatrix* matL2G = extractMatrixSensor(isn); - const TGeoHMatrix& matL2Gi = matL2G->Inverse(); - t2l.MultiplyLeft(&matL2Gi); - return t2l; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractVolumeCopy(const char* name, const char* prefix) const -{ - TString nms = name; - if (!nms.BeginsWith(prefix)) { - return -1; - } - nms.Remove(0, strlen(prefix)); - if (!isdigit(nms.Data()[0])) { - return -1; - } - return nms.Atoi(); -} diff --git a/Detectors/Upgrades/PostLS4/IT4/base/src/ITS4BaseLinkDef.h b/Detectors/Upgrades/PostLS4/IT4/base/src/ITS4BaseLinkDef.h deleted file mode 100644 index ffcb6d02c92fc..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/base/src/ITS4BaseLinkDef.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::its4::GeometryTGeo; -#pragma link C++ class o2::its4::MisalignmentParameter + ; - -#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/macros/CMakeLists.txt b/Detectors/Upgrades/PostLS4/IT4/macros/CMakeLists.txt deleted file mode 100644 index e2058e7d098e1..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/macros/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -add_subdirectory(test) \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/macros/test/CMakeLists.txt b/Detectors/Upgrades/PostLS4/IT4/macros/test/CMakeLists.txt deleted file mode 100644 index 10bb6dd71f256..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/macros/test/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/CMakeLists.txt b/Detectors/Upgrades/PostLS4/IT4/simulation/CMakeLists.txt deleted file mode 100644 index 483884d69a87d..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(ITS4Simulation - SOURCES src/V11Geometry.cxx src/V1Layer.cxx src/V3Layer.cxx - src/Detector.cxx src/V3Services.cxx - PUBLIC_LINK_LIBRARIES O2::ITS4Base O2::ITSMFTSimulation - ROOT::Physics) - -o2_target_root_dictionary(ITS4Simulation - HEADERS include/ITS4Simulation/Detector.h - include/ITS4Simulation/V1Layer.h - include/ITS4Simulation/V3Layer.h - include/ITS4Simulation/V11Geometry.h - include/ITS4Simulation/V3Services.h - ) - -o2_data_file(COPY data DESTINATION Detectors/ITS4/simulation) \ No newline at end of file diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/Detector.h b/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/Detector.h deleted file mode 100644 index 07a34c82af897..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/Detector.h +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Detector.h -/// \brief Definition of the Detector class - -#ifndef ALICEO2_ITS4_DETECTOR_H_ -#define ALICEO2_ITS4_DETECTOR_H_ - -#include <vector> // for vector -#include "DetectorsBase/GeometryManager.h" // for getSensID -#include "DetectorsBase/Detector.h" // for Detector -#include "DetectorsCommonDataFormats/DetID.h" // for Detector -#include "ITSMFTSimulation/Hit.h" // for Hit -#include "Rtypes.h" // for Int_t, Double_t, Float_t, Bool_t, etc -#include "TArrayD.h" // for TArrayD -#include "TGeoManager.h" // for gGeoManager, TGeoManager (ptr only) -#include "TLorentzVector.h" // for TLorentzVector -#include "TVector3.h" // for TVector3 - -class FairVolume; -class TGeoVolume; - -class TParticle; - -class TString; - -namespace o2 -{ -namespace itsmft -{ -class Hit; -} -} // namespace o2 - -namespace o2 -{ -namespace its4 -{ -class GeometryTGeo; -} -} // namespace o2 -namespace o2 -{ -namespace its4 -{ -class V3Layer; -} -} // namespace o2 - -namespace o2 -{ -namespace its4 -{ -class V3Layer; -class V3Services; - -class Detector : public o2::base::DetImpl<Detector> -{ - public: - enum Model { - kIBModelDummy = 0, - kIBModel0 = 1, - kIBModel1 = 2, - kIBModel21 = 3, - kIBModel22 = 4, - kIBModel3 = 5, - kIBModel4 = 10, - kOBModelDummy = 6, - kOBModel0 = 7, - kOBModel1 = 8, - kOBModel2 = 9 - }; - - static constexpr Int_t sNumberLayers = 10; ///< Number of layers in ITSU - static constexpr Int_t sNumberInnerLayers = 10; ///< Number of inner layers in ITSU - static constexpr Int_t sNumberOfWrapperVolumes = 3; ///< Number of wrapper volumes - - /// Name : Detector Name - /// Active: kTRUE for active detectors (ProcessHits() will be called) - /// kFALSE for inactive detectors - Detector(Bool_t active); - - /// Special version for ITS4: add number on Inner Layers - Detector(Bool_t active, Int_t nlay); - - /// Default constructor - Detector(); - - /// Default destructor - ~Detector() override; - - /// Initialization of the detector is done here - void InitializeO2Detector() override; - - /// This method is called for each step during simulation (see FairMCApplication::Stepping()) - Bool_t ProcessHits(FairVolume* v = nullptr) override; - - /// Registers the produced collections in FAIRRootManager - void Register() override; - - /// Gets the produced collections - std::vector<o2::itsmft::Hit>* getHits(Int_t iColl) const - { - if (iColl == 0) { - return mHits; - } - return nullptr; - } - - public: - /// Has to be called after each event to reset the containers - void Reset() override; - - /// Base class to create the detector geometry - void ConstructGeometry() override; - - /// Creates the Service Barrel (as a simple cylinder) for IB and OB - /// \param innerBarrel if true, build IB service barrel, otherwise for OB - /// \param dest the mother volume holding the service barrel - /// \param mgr the gGeoManager pointer (used to get the material) - void createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr = gGeoManager); - - /// Sets the layer parameters - /// \param nlay layer number - /// \param phi0 layer phi0 - /// \param r layer radius - /// \param nstav number of staves - /// \param nunit IB: number of chips per stave - /// \param OB: number of modules per half stave - /// \param lthick stave thickness (if omitted, defaults to 0) - /// \param dthick detector thickness (if omitted, defaults to 0) - /// \param dettypeID ?? - /// \param buildLevel (if 0, all geometry is build, used for material budget studies) - void defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t lthick = 0., - Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; - - /// Sets the layer parameters for a "turbo" layer - /// (i.e. a layer whose staves overlap in phi) - /// \param nlay layer number - /// \param phi0 phi of 1st stave - /// \param r layer radius - /// \param nstav number of staves - /// \param nunit IB: number of chips per stave - /// \param OB: number of modules per half stave - /// \param width stave width - /// \param tilt layer tilt angle (degrees) - /// \param lthick stave thickness (if omitted, defaults to 0) - /// \param dthick detector thickness (if omitted, defaults to 0) - /// \param dettypeID ?? - /// \param buildLevel (if 0, all geometry is build, used for material budget studies) - // void defineLayerTurbo(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t width, Double_t tilt, - // Double_t lthick = 0., Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0) override; - - /// Sets the layer parameters for new ITS4 geo - /// \param nlay layer number - /// \param r layer radius - /// \param zlen layer length - /// \param dthick detector thickness (if omitted, defaults to 0) - /// \param dettypeID ?? - /// \param buildLevel (if 0, all geometry is build, used for material budget studies) - void defineInnerLayerITS4(Int_t nlay, Double_t r, Double_t zlen, - Double_t dthick = 0., UInt_t detType = 0, Int_t buildFlag = 0); - - /// Gets the layer parameters - /// \param nlay layer number - /// \param phi0 phi of 1st stave - /// \param r layer radius - /// \param nstav number of staves - /// \param nmod IB: number of chips per stave - /// \param OB: number of modules per half stave - /// \param width stave width - /// \param tilt stave tilt angle - /// \param lthick stave thickness - /// \param dthick detector thickness - /// \param dettype detector type - virtual void getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nladd, Int_t& nmod, Double_t& width, - Double_t& tilt, Double_t& lthick, Double_t& mthick, UInt_t& dettype) const; - - /// This method is an example of how to add your own point of type Hit to the clones array - o2::itsmft::Hit* addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, - unsigned char startStatus, unsigned char endStatus); - - /// Set per wrapper volume parameters - void defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan) override; - - /// Add alignable top volumes - void addAlignableVolumes() const override; - - /// Add alignable Layer volumes - /// \param lr layer number - /// \param parent path of the parent volume - /// \param lastUID on output, UID of the last volume - void addAlignableVolumesLayer(Int_t lr, TString& parent, Int_t& lastUID) const; - - /// Add alignable Stave volumes - /// \param lr layer number - /// \param st stave number - /// \param parent path of the parent volume - /// \param lastUID on output, UID of the last volume - void addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const; - - /// Add alignable HalfStave volumes - /// \param lr layer number - /// \param st stave number - /// \param hst half stave number - /// \param parent path of the parent volume - /// \param lastUID on output, UID of the last volume - void addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const; - - /// Add alignable Module volumes - /// \param lr layer number - /// \param st stave number - /// \param hst half stave number - /// \param md module number - /// \param parent path of the parent volume - /// \param lastUID on output, UID of the last volume - void addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const; - - /// Add alignable Chip volumes - /// \param lr layer number - /// \param st stave number - /// \param hst half stave number - /// \param md module number - /// \param ch chip number - /// \param parent path of the parent volume - /// \param lastUID on output, UID of the last volume - void addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, - Int_t& lastUID) const; - - /// Return Chip Volume UID - /// \param id volume id - Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID::IT4, id); } - - void EndOfEvent() override; - - void FinishPrimary() override { ; } - virtual void finishRun() { ; } - void BeginPrimary() override { ; } - void PostTrack() override { ; } - void PreTrack() override { ; } - /// Prints out the content of this class in ASCII format - /// \param ostream *os The output stream - void Print(std::ostream* os) const; - - /// Reads in the content of this class in the format of Print - /// \param istream *is The input stream - void Read(std::istream* is); - - /// Returns the number of layers - Int_t getNumberOfLayers() const { return sNumberLayers; } - virtual void setStaveModelIB(Model model) { mStaveModelInnerBarrel = model; } - virtual void setStaveModelOB(Model model) { mStaveModelOuterBarrel = model; } - virtual Model getStaveModelIB() const { return mStaveModelInnerBarrel; } - virtual Model getStaveModelOB() const { return mStaveModelOuterBarrel; } - - void createOuterBarrel(const Bool_t ob) { mCreateOuterBarrel = ob; }; - Bool_t isCreateOuterBarrel() { return mCreateOuterBarrel; }; - - o2::its4::GeometryTGeo* mGeometryTGeo; //! access to geometry details - - protected: - Int_t* mLayerID; //! [sNumberLayers] layer identifier - TString* mLayerName; //! [sNumberLayers] layer identifier - - private: - /// this is transient data about track passing the sensor - struct TrackData { // this is transient - bool mHitStarted; //! hit creation started - unsigned char mTrkStatusStart; //! track status flag - TLorentzVector mPositionStart; //! position at entrance - TLorentzVector mMomentumStart; //! momentum - double mEnergyLoss; //! energy loss - } mTrackData; //! - - Int_t mNumberOfInnerLayers; //! number of ITS4 inner layers - Int_t mTotalNumberOfLayers; //! total number of ITS4 layers (IB+OB) - Bool_t mCreateOuterBarrel; //! true to create the Outer Barrel - - Int_t mNumberOfDetectors; - - Bool_t mModifyGeometry; - - Double_t mWrapperMinRadius[sNumberOfWrapperVolumes]; //! Min radius of wrapper volume - Double_t mWrapperMaxRadius[sNumberOfWrapperVolumes]; //! Max radius of wrapper volume - Double_t mWrapperZSpan[sNumberOfWrapperVolumes]; //! Z span of wrapper volume - Int_t* mWrapperLayerId; //! Id of wrapper layer to which layer belongs (-1 if not wrapped) - - Bool_t* mTurboLayer; //! True for "turbo" layers - Bool_t* mITS4Layer; //! True for new ITS4 layers - Double_t* mLayerPhi0; //! Vector of layer's 1st stave phi in lab - Double_t* mLayerRadii; //! Vector of layer radii - Double_t* mLayerZLen; //! Vector of layer lengths - Int_t* mStavePerLayer; //! Vector of number of staves per layer - Int_t* mUnitPerStave; //! Vector of number of "units" per stave - Double_t* mChipThickness; //! Vector of chip thicknesses - Double_t* mStaveWidth; //! Vector of stave width (only used for turbo) - Double_t* mStaveTilt; //! Vector of stave tilt (only used for turbo) - Double_t* mDetectorThickness; //! Vector of detector thicknesses - UInt_t* mChipTypeID; //! Vector of detector type id - Int_t* mBuildLevel; //! Vector of Material Budget Studies - - /// Container for hit data - std::vector<o2::itsmft::Hit>* mHits; - - /// We need this as a method to access members - void configITS(Detector* its); - - /// Creates all needed arrays - void createAllArrays(); - - /// Creates an air-filled wrapper cylindrical volume - TGeoVolume* createWrapperVolume(const Int_t nLay); - - /// Create the detector materials - virtual void createMaterials(); - - /// Construct the detector geometry - void constructDetectorGeometry(); - - /// Define the sensitive volumes of the geometry - void defineSensitiveVolumes(); - - /// Creates the Inner Barrel Services - /// \param motherVolume the TGeoVolume owing the volume structure - void createInnerBarrelServices(TGeoVolume* motherVolume); - - /// Creates the Middle Barrel Services - /// \param motherVolume the TGeoVolume owing the volume structure - void createMiddlBarrelServices(TGeoVolume* motherVolume); - - /// Creates the Outer Barrel Services - /// \param motherVolume the TGeoVolume owing the volume structure - void createOuterBarrelServices(TGeoVolume* motherVolume); - - /// Creates the Outer Barrel Supports - /// \param motherVolume the TGeoVolume owing the volume supports - void createOuterBarrelSupports(TGeoVolume* motherVolume); - - Detector(const Detector&); - - Detector& operator=(const Detector&); - - Model mStaveModelInnerBarrel; //! The stave model for the Inner Barrel - Model mStaveModelOuterBarrel; //! The stave model for the Outer Barrel - V3Layer** mGeometry; //! Geometry - V3Services* mServicesGeometry; //! Services Geometry - - template <typename Det> - friend class o2::base::DetImpl; - ClassDefOverride(Detector, 1); -}; - -// Input and output function for standard C++ input/output. -std::ostream& operator<<(std::ostream& os, Detector& source); - -std::istream& operator>>(std::istream& os, Detector& source); -} // namespace its4 -} // namespace o2 - -#ifdef USESHM -namespace o2 -{ -namespace base -{ -template <> -struct UseShm<o2::its4::Detector> { - static constexpr bool value = true; -}; -} // namespace base -} // namespace o2 -#endif - -#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V1Layer.h b/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V1Layer.h deleted file mode 100644 index 33e5e46ea0856..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/include/ITS4Simulation/V1Layer.h +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_ITS4_UPGRADEV1LAYER_H_ -#define ALICEO2_ITS4_UPGRADEV1LAYER_H_ - -#include <TGeoManager.h> // for gGeoManager -#include "Rtypes.h" // for Double_t, Int_t, Bool_t, etc -#include "ITS4Simulation/V11Geometry.h" // for V11Geometry -#include "ITS4Simulation/Detector.h" // for Detector, Detector::Model - -class TGeoArb8; - -class TGeoCombiTrans; - -class TGeoVolume; // lines 15-15 - -namespace o2 -{ -namespace its4 -{ - -/// This class defines the Geometry for the ITS using TGeo. This is a work class used -/// to study different configurations during the development of the new ITS structure -class V1Layer : public V11Geometry -{ - - public: - enum { - kStave, - kHalfStave, - kModule, - kChip, - kNHLevels - }; - - // Default constructor - V1Layer(); - - // Constructor setting debugging level - V1Layer(Int_t debug); - - // Constructor setting layer number and debugging level - V1Layer(Int_t lay, Int_t debug); - - /// Constructor setting layer number and debugging level - /// for a "turbo" layer (i.e. where staves overlap in phi) - V1Layer(Int_t lay, Bool_t turbo, Int_t debug); - - /// Copy constructor - V1Layer(const V1Layer& source); - - /// Assignment operator - V1Layer& operator=(const V1Layer& source); - - /// Default destructor - ~V1Layer() override; - - Bool_t isTurbo() const - { - return mIsTurbo; - }; - - Double_t getStaveThick() const - { - return mStaveThickness; - }; - - Double_t getStaveTilt() const - { - return mStaveTilt; - }; - - Double_t getStaveWidth() const - { - return mStaveWidth; - }; - - Double_t getSensorThick() const - { - return mSensorThickness; - }; - - Double_t getNumberOfStaves() const - { - return mNumberOfStaves; - }; - - Double_t getNumberOfChips() const - { - return mNumberOfChips; - }; - - Double_t getRadius() const - { - return mLayerRadius; - }; - - Double_t getPhi0() const - { - return mPhi0; - }; - - Double_t getZLength() const - { - return mZLength; - }; - - Int_t getChipType() const - { - return mChipTypeID; - } - - Int_t getNumberOfStavesPerParent() const - { - return mHierarchy[kStave]; - } - - Int_t getNumberOfHalfStavesPerParent() const - { - return mHierarchy[kHalfStave]; - } - - Int_t getNumberOfModulesPerParent() const - { - return mHierarchy[kModule]; - } - - Int_t getNumberOfChipsPerParent() const - { - return mHierarchy[kChip]; - } - - Detector::Model getStaveModel() const - { - return mStaveModel; - } - - void setStaveThick(Double_t t) - { - mStaveThickness = t; - }; - - /// Sets the Stave tilt angle (for turbo layers only) - /// \param t The stave tilt angle - void setStaveTilt(Double_t t); - - /// Sets the Stave width (for turbo layers only) - /// \param w The stave width - void setStaveWidth(Double_t w); - - void setSensorThick(Double_t t) - { - mSensorThickness = t; - }; - - void setNumberOfStaves(Int_t n) - { - mHierarchy[kStave] = mNumberOfStaves = n; - }; - - /// Sets the number of units in a stave: - /// for the Inner Barrel: the number of chips per stave - /// for the Outer Barrel: the number of modules per half stave - /// \param u the number of units - void setNumberOfUnits(Int_t u); - - void setRadius(Double_t r) - { - mLayerRadius = r; - }; - - void setPhi0(Double_t phi) - { - mPhi0 = phi; - } - - void setZLength(Double_t z) - { - mZLength = z; - }; - - void setChipType(Int_t tp) - { - mChipTypeID = tp; - } - - void setBuildLevel(Int_t buildLevel) - { - mBuildLevel = buildLevel; - } - - void setStaveModel(o2::its4::Detector::Model model) - { - mStaveModel = model; - } - - /// Creates the actual Layer and places inside its mother volume - /// \param motherVolume the TGeoVolume owing the volume structure - virtual void createLayer(TGeoVolume* motherVolume); - - private: - /// Creates the actual Layer and places inside its mother volume - /// A so-called "turbo" layer is a layer where staves overlap in phi - /// User can set width and tilt angle, no check is performed here - /// to avoid volume overlaps - /// \param motherVolume The TGeoVolume owing the volume structure - void createLayerTurbo(TGeoVolume* motherVolume); - - /// Computes the inner radius of the air container for the Turbo configuration - /// as the radius of either the circle tangent to the stave or the circle - /// passing for the stave's lower vertex. Returns the radius of the container - /// if >0, else flag to use the lower vertex - Double_t radiusOmTurboContainer(); - - /// Creates the actual Stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStave(const TGeoManager* mgr = gGeoManager); - - // TGeoVolume* createChip(Double_t x, Double_t z, const TGeoManager *mgr=gGeoManager); - - /// Creates the IB Module: (only the chips for the time being) - /// Returns the module as a TGeoVolume - /// \param xmod, ymod, zmod X, Y, Z module half lengths - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createModuleInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Creates the actual Chip - /// \param xchip,ychip,zchip The chip dimensions - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createChipInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Creates the OB Module: HIC + FPC + Carbon plate - /// Returns the module as a TGeoVolume - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createModuleOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create the chip stave for the Inner Barrel(Here we fake the halfstave volume to have the - /// same formal geometry hierarchy as for the Outer Barrel) - /// \param xsta, ysta, zsta X, Y, Z stave half lengths - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveInnerB(Double_t x, Double_t y, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveStructInnerB(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create a dummy stave - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerBDummy(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager) const; - - /// Create the mechanical stave structure for Model 0 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB0(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 1 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB1(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 2.1 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB21(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 2.2 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB22(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical stave structure for Model 3 of TDR - /// \param xsta X length - /// \param zsta Z length - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelInnerB3(Double_t x, Double_t z, const TGeoManager* mgr = gGeoManager); - - /// Create the chip stave for the Outer Barrel - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create dummy stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterBDummy(const TGeoManager* mgr = gGeoManager) const; - - /// Creation of the mechanical stave structure for the Outer Barrel as in v0 - /// (we fake the module and halfstave volumes to have always - /// the same formal geometry hierarchy) - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterB0(const TGeoManager* mgr = gGeoManager); - - /// Create the mechanical half stave structure or the Outer Barrel as in TDR - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createStaveModelOuterB1(const TGeoManager* mgr = gGeoManager); - - /// Create the space frame for the Outer Barrel - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterB(const TGeoManager* mgr = gGeoManager); - - /// Create dummy stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterBDummy(const TGeoManager* mgr = gGeoManager) const; - - /// Create the space frame for the Outer Barrel (Model 1) - /// Returns a TGeoVolume with the Space Frame of a stave - /// \param mgr The GeoManager (used only to get the proper material) - TGeoVolume* createSpaceFrameOuterB1(const TGeoManager* mgr = gGeoManager); - - /// Creates the V-shaped sides of the OB space frame (from a similar method with same - /// name and function in V11GeometrySDD class by L.Gaudichet) - TGeoArb8* createStaveSide(const char* name, Double_t dz, Double_t angle, Double_t xSign, Double_t L, Double_t H, - Double_t l); - - /// Help method to create a TGeoCombiTrans matrix from a similar method with same name and - /// function in V11GeometrySDD class by L.Gaudichet) - /// Returns the TGeoCombiTrans which make a translation in y and z and a rotation in phi - /// in the global coord system. If planeSym = true, the rotation places the object - /// symetrically (with respect to the transverse plane) to its position in the - /// case planeSym = false - TGeoCombiTrans* createCombiTrans(const char* name, Double_t dy, Double_t dz, Double_t dphi, - Bool_t planeSym = kFALSE); - - /// Help method to add a translation to a TGeoCombiTrans matrix (from a similar method - /// with same name and function in V11GeometrySDD class by L.Gaudichet) - void addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx = 0, Double_t dy = 0, Double_t dz = 0) const; - - Int_t mLayerNumber; ///< Current layer number - Double_t mPhi0; ///< lab phi of 1st stave, in degrees!!! - Double_t mLayerRadius; ///< Inner radius of this layer - Double_t mZLength; ///< Z length of this layer - Double_t mSensorThickness; ///< Sensor thickness - Double_t mStaveThickness; ///< Stave thickness - Double_t mStaveWidth; ///< Stave width (for turbo layers only) - Double_t mStaveTilt; ///< Stave tilt angle (for turbo layers only) in degrees - Int_t mNumberOfStaves; ///< Number of staves in this layer - Int_t mNumberOfModules; ///< Number of modules per container if defined (HalfStave, Stave, whatever is - ///< container) - Int_t mNumberOfChips; ///< Number chips per container (module, HalfStave, Stave, whatever is - /// container) - Int_t mHierarchy[kNHLevels]; ///< array to query number of staves, hstaves, modules, chips per its parent volume - - UInt_t mChipTypeID; ///< detector type id - Bool_t mIsTurbo; ///< True if this layer is a "turbo" layer - Int_t mBuildLevel; ///< Used for material studies - - Detector::Model mStaveModel; ///< The stave model - - // Parameters for the geometry - - // General Parameters - static const Int_t sNumberOmInnerLayers; ///< Number of IB Layers - - static const Double_t sDefaultSensorThick; ///< Default sensor thickness - static const Double_t sDefaultStaveThick; ///< Default stave thickness - - // Inner Barrel Parameters - static const Int_t sIBChipsPerRow; ///< IB chips per row in module - static const Int_t sIBNChipRows; ///< IB chip rows in module - - // Outer Barrel Parameters - static const Int_t sOBChipsPerRow; ///< OB chips per row in module - static const Int_t sOBNChipRows; ///< OB chip rows in module - - static const Double_t sOBHalfStaveWidth; ///< OB Half Stave Width - static const Double_t sOBModuleWidth; ///< OB Module Width - static const Double_t sOBModuleGap; ///< Gap between OB modules - static const Double_t sOBChipXGap; ///< Gap between OB chips on X - static const Double_t sOBChipZGap; ///< Gap between OB chips on Z - static const Double_t sOBFlexCableAlThick; ///< Thickness of FPC Aluminum - static const Double_t sOBFlexCableKapThick; ///< Thickness of FPC Kapton - static const Double_t sOBBusCableAlThick; ///< Thickness of Bus Aluminum - static const Double_t sOBBusCableKapThick; ///< Thickness of Bus Kapton - static const Double_t sOBCarbonPlateThick; ///< OB Carbon Plate Thickness - static const Double_t sOBColdPlateThick; ///< OB Cold Plate Thickness - static const Double_t sOBGlueThick; ///< OB Glue total Thickness - static const Double_t sOBModuleZLength; ///< OB Chip Length along Z - static const Double_t sOBHalfStaveYTrans; ///< OB half staves Y transl. - static const Double_t sOBHalfStaveXOverlap; ///< OB half staves X overlap - static const Double_t sOBGraphiteFoilThick; ///< OB graphite foil thickness - static const Double_t sOBCoolTubeInnerD; ///< OB cooling inner diameter - static const Double_t sOBCoolTubeThick; ///< OB cooling tube thickness - static const Double_t sOBCoolTubeXDist; ///< OB cooling tube separation - - static const Double_t sOBSpaceFrameWidth; ///< OB Space Frame Width - static const Double_t sOBSpaceFrameTotHigh; ///< OB Total Y Height - static const Double_t sOBSFrameBeamRadius; ///< OB Space Frame Beam Radius - static const Double_t sOBSpaceFrameLa; ///< Parameters defining... - static const Double_t sOBSpaceFrameHa; ///< ...the V side shape... - static const Double_t sOBSpaceFrameLb; ///< ...of the carbon... - static const Double_t sOBSpaceFrameHb; ///< ...OB Space Frame - static const Double_t sOBSpaceFrameL; ///< OB SF - static const Double_t sOBSFBotBeamAngle; ///< OB SF bottom beam angle - static const Double_t sOBSFrameBeamSidePhi; ///< OB SF side beam angle - - ClassDefOverride(V1Layer, 0); // ITS v1 geometry -}; -} // namespace its4 -} // namespace o2 - -#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/Detector.cxx b/Detectors/Upgrades/PostLS4/IT4/simulation/src/Detector.cxx deleted file mode 100644 index 30dc0658cd6be..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/Detector.cxx +++ /dev/null @@ -1,1374 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Detector.cxx -/// \brief Implementation of the Detector class - -#include "ITSMFTBase/SegmentationAlpide.h" -#include "ITSMFTSimulation/Hit.h" -#include "ITS4Base/GeometryTGeo.h" -#include "ITS4Simulation/Detector.h" -#include "ITS4Simulation/V3Layer.h" -#include "ITS4Simulation/V3Services.h" - -#include "SimulationDataFormat/Stack.h" -#include "SimulationDataFormat/TrackReference.h" - -// FairRoot includes -#include "FairDetector.h" // for FairDetector -#include "FairLogger.h" // for LOG, LOG_IF -#include "FairRootManager.h" // for FairRootManager -#include "FairRun.h" // for FairRun -#include "FairRuntimeDb.h" // for FairRuntimeDb -#include "FairVolume.h" // for FairVolume -#include "FairRootManager.h" - -#include "TGeoManager.h" // for TGeoManager, gGeoManager -#include "TGeoTube.h" // for TGeoTube -#include "TGeoPcon.h" // for TGeoPcon -#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly -#include "TString.h" // for TString, operator+ -#include "TVirtualMC.h" // for gMC, TVirtualMC -#include "TVirtualMCStack.h" // for TVirtualMCStack - -#include <cstdio> // for NULL, snprintf - -class FairModule; - -class TGeoMedium; - -class TParticle; - -using std::cout; -using std::endl; - -using o2::itsmft::Hit; -using Segmentation = o2::itsmft::SegmentationAlpide; -using namespace o2::its4; - -float getDetLengthFromEta(const float eta, const float radius) -{ - return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta)))); -} - -Detector::Detector() - : o2::base::DetImpl<Detector>("IT4", kTRUE), - mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ - mNumberOfDetectors(-1), - mModifyGeometry(kFALSE), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(kIBModel0), - mStaveModelOuterBarrel(kOBModel0) -{ -} - -static double radii2Turbo(double rMin, double rMid, double rMax, double sensW) -{ - // compute turbo angle from radii and sensor width - return TMath::ASin((rMax * rMax - rMin * rMin) / (2 * rMid * sensW)) * TMath::RadToDeg(); -} - -// We need this as a method to access members -void Detector::configITS(Detector* its) -{ - // build ITS upgrade detector - const int kNLr = 7; - const int kNLrInner = 3; - const int kBuildLevel = 0; - const int kSensTypeID = 0; // dummy id for Alpide sensor - - const float ChipThicknessIB = 50.e-4; - const float ChipThicknessOB = 100.e-4; - - enum { kRmn, - kRmd, - kRmx, - kNModPerStave, - kPhi0, - kNStave, - kNPar }; - // Radii are from last TDR (ALICE-TDR-017.pdf Tab. 1.1, rMid is mean value) - // const double tdr5dat[kNLr][kNPar] = { - // {2.24, 2.34, 2.67, 9., 16.42, 12}, // for each inner layer: rMin,rMid,rMax,NChip/Stave, phi0, nStaves - // {3.01, 3.15, 3.46, 9., 12.18, 16}, - // {3.78, 3.93, 4.21, 9., 9.55, 20}, - // {-1, 19.6, -1, 4., 0., 24}, // for others: -, rMid, -, NMod/HStave, phi0, nStaves // 24 was 49 - // {-1, 24.55, -1, 4., 0., 30}, // 30 was 61 - // {-1, 34.39, -1, 7., 0., 42}, // 42 was 88 - // {-1, 39.34, -1, 7., 0., 48} // 48 was 100 - // }; - // const int nChipsPerModule = 7; // For OB: how many chips in a row - // const double zChipGap = 0.01; // For OB: gap in Z between chips - // const double zModuleGap = 0.01; // For OB: gap in Z between modules - - // double dzLr, rLr, phi0, turbo; - // int nStaveLr, nModPerStaveLr; - - // its->setStaveModelIB(o2::its4::Detector::kIBModel4); - its->setStaveModelOB(o2::its4::Detector::kOBModel2); - - const int kNWrapVol = 3; - const double wrpRMin[kNWrapVol] = {2.1, 19.3, 33.32}; - const double wrpRMax[kNWrapVol] = {15.4, 29.14, 46.0}; - const double wrpZSpan[kNWrapVol] = {70., 93., 163.6}; - - for (int iw = 0; iw < kNWrapVol; iw++) { - its->defineWrapperVolume(iw, wrpRMin[iw], wrpRMax[iw], wrpZSpan[iw]); - } - - // Build OB only (4 layers) - // for (int idLr = mNumberOfInnerLayers; idLr < mTotalNumberOfLayers; idLr++) { - // int im = idLr - mNumberOfInnerLayers + kNLrInner; - // rLr = tdr5dat[im][kRmd]; - // phi0 = tdr5dat[im][kPhi0]; - - // nStaveLr = TMath::Nint(tdr5dat[im][kNStave]); - // nModPerStaveLr = TMath::Nint(tdr5dat[im][kNModPerStave]); - // int nChipsPerStaveLr = nModPerStaveLr; - // its->defineLayer(idLr, phi0, rLr, nStaveLr, nModPerStaveLr, ChipThicknessOB, Segmentation::SensorLayerThickness, - // kSensTypeID, kBuildLevel); - // } - - // From Mario Sitta's hack - std::vector<std::array<double, 2>> tdr5data; - tdr5data.emplace_back(std::array<double, 2>{1.8f, getDetLengthFromEta(1.44f, 1.8f)}); - tdr5data.emplace_back(std::array<double, 2>{2.8f, getDetLengthFromEta(1.44f, 2.8f)}); - tdr5data.emplace_back(std::array<double, 2>{3.8f, getDetLengthFromEta(1.44f, 3.8f)}); - tdr5data.emplace_back(std::array<double, 2>{8.0f, getDetLengthFromEta(1.44f, 8.0f)}); - tdr5data.emplace_back(std::array<double, 2>{20.0f, getDetLengthFromEta(1.44f, 20.0f)}); - tdr5data.emplace_back(std::array<double, 2>{25.0f, getDetLengthFromEta(1.44f, 25.0f)}); - tdr5data.emplace_back(std::array<double, 2>{40.0f, getDetLengthFromEta(1.44f, 40.0f)}); - tdr5data.emplace_back(std::array<double, 2>{55.f, getDetLengthFromEta(1.44f, 55.f)}); - tdr5data.emplace_back(std::array<double, 2>{80.0f, getDetLengthFromEta(1.44f, 80.0f)}); - tdr5data.emplace_back(std::array<double, 2>{100.f, getDetLengthFromEta(1.44f, 100.f)}); - - std::array<float, 10> sensorThicknesses = {50.e-4, 50.e-4, 50.e-4, 50.e-3, 50.e-3, 50.e-3, 50.e-3, 50.e-3, 50.e-3, 50.e-3}; - its->setStaveModelOB(o2::its4::Detector::kOBModel2); - // its->createOuterBarrel(false); - - auto idLayer{0}; - for (auto& layerData : tdr5data) { - its->defineInnerLayerITS4(idLayer, layerData[0], layerData[1], sensorThicknesses[idLayer], 0, 0); - ++idLayer; - } - its->createOuterBarrel(false); -} - -Detector::Detector(Bool_t active) - : o2::base::DetImpl<Detector>("IT4", active), - mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ - mNumberOfInnerLayers(10), - mNumberOfDetectors(-1), - mModifyGeometry(kFALSE), - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(kIBModel0), - mStaveModelOuterBarrel(kOBModel0) -{ - - mTotalNumberOfLayers = mNumberOfInnerLayers + (sNumberLayers - sNumberInnerLayers); - - createAllArrays(); - - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer - } - - if (mTotalNumberOfLayers > 0) { // if not, we'll Fatal-ize in CreateGeometry - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - mITS4Layer[j] = kFALSE; - mLayerPhi0[j] = 0; - mLayerRadii[j] = 0.; - mLayerZLen[j] = 0.; - mStavePerLayer[j] = 0; - mUnitPerStave[j] = 0; - mChipThickness[j] = 0.; - mStaveWidth[j] = 0.; - mStaveTilt[j] = 0.; - mDetectorThickness[j] = 0.; - mChipTypeID[j] = 0; - mBuildLevel[j] = 0; - mGeometry[j] = nullptr; - } - } - mServicesGeometry = nullptr; - - for (int i = sNumberOfWrapperVolumes; i--;) { - mWrapperMinRadius[i] = mWrapperMaxRadius[i] = mWrapperZSpan[i] = -1; - } - - configITS(this); -} - -Detector::Detector(const Detector& rhs) - : o2::base::DetImpl<Detector>(rhs), - mTrackData(), - /* - mHitStarted(false), - mTrkStatusStart(), - mPositionStart(), - mMomentumStart(), - mEnergyLoss(), - */ - mNumberOfInnerLayers(rhs.mNumberOfInnerLayers), - mNumberOfDetectors(rhs.mNumberOfDetectors), - mModifyGeometry(rhs.mModifyGeometry), - - /// Container for data points - mHits(o2::utils::createSimVector<o2::itsmft::Hit>()), - mStaveModelInnerBarrel(rhs.mStaveModelInnerBarrel), - mStaveModelOuterBarrel(rhs.mStaveModelOuterBarrel) -{ - - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer - } -} - -Detector::~Detector() -{ - - if (mHits) { - // delete mHits; - o2::utils::freeSimVector(mHits); - } -} - -Detector& Detector::operator=(const Detector& rhs) -{ - // The standard = operator - // Inputs: - // Detector &h the sourse of this copy - // Outputs: - // none. - // Return: - // A copy of the sourse hit h - - if (this == &rhs) { - return *this; - } - - // base class assignment - base::Detector::operator=(rhs); - - mNumberOfDetectors = rhs.mNumberOfDetectors; - - mModifyGeometry = rhs.mModifyGeometry; - - /// Container for data points - mHits = nullptr; - - mStaveModelInnerBarrel = rhs.mStaveModelInnerBarrel; - mStaveModelOuterBarrel = rhs.mStaveModelOuterBarrel; - - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer - } - - return *this; -} - -void Detector::createAllArrays() -{ - // Create all arrays - // We have to do it here because now the number of Inner Layers is - // not fixed, so we don't know in advance how many to create: they - // cannot be anymore static arrays as in the default version - // M.S. 21 mar 2020 (13th day of Italian Coronavirus lockdown) - - mLayerID = new Int_t[mTotalNumberOfLayers]; - mLayerName = new TString[mTotalNumberOfLayers]; - - mWrapperLayerId = new Int_t[mTotalNumberOfLayers]; - mTurboLayer = new Bool_t[mTotalNumberOfLayers]; - mITS4Layer = new Bool_t[mTotalNumberOfLayers]; - - mLayerPhi0 = new Double_t[mTotalNumberOfLayers]; - mLayerRadii = new Double_t[mTotalNumberOfLayers]; - mLayerZLen = new Double_t[mTotalNumberOfLayers]; - mStavePerLayer = new Int_t[mTotalNumberOfLayers]; - mUnitPerStave = new Int_t[mTotalNumberOfLayers]; - mChipThickness = new Double_t[mTotalNumberOfLayers]; - mStaveWidth = new Double_t[mTotalNumberOfLayers]; - mStaveTilt = new Double_t[mTotalNumberOfLayers]; - mDetectorThickness = new Double_t[mTotalNumberOfLayers]; - mChipTypeID = new UInt_t[mTotalNumberOfLayers]; - mBuildLevel = new Int_t[mTotalNumberOfLayers]; - - mGeometry = new V3Layer*[mTotalNumberOfLayers]; -} - -void Detector::InitializeO2Detector() -{ - // Define the list of sensitive volumes - defineSensitiveVolumes(); - - for (int i = 0; i < mTotalNumberOfLayers; i++) { - mLayerID[i] = gMC ? TVirtualMC::GetMC()->VolId(mLayerName[i]) : 0; - } - - mGeometryTGeo = GeometryTGeo::Instance(); - // FairRuntimeDb* rtdb= FairRun::Instance()->GetRuntimeDb(); - // O2itsGeoPar* par=(O2itsGeoPar*)(rtdb->getContainer("O2itsGeoPar")); -} - -Bool_t Detector::ProcessHits(FairVolume* vol) -{ - // This method is called from the MC stepping - if (!(fMC->TrackCharge())) { - return kFALSE; - } - - Int_t lay = 0, volID = vol->getMCid(); - - // FIXME: Determine the layer number. Is this information available directly from the FairVolume? - bool notSens = false; - while ((lay < mTotalNumberOfLayers) && (notSens = (volID != mLayerID[lay]))) { - ++lay; - } - if (notSens) { - return kFALSE; // RS: can this happen? This method must be called for sensors only? - } - - // Is it needed to keep a track reference when the outer ITS volume is encountered? - auto stack = (o2::data::Stack*)fMC->GetStack(); - if (fMC->IsTrackExiting() && (lay == 0 || lay == 6)) { - // Keep the track refs for the innermost and outermost layers only - o2::TrackReference tr(*fMC, GetDetId()); - tr.setTrackID(stack->GetCurrentTrackNumber()); - tr.setUserId(lay); - stack->addTrackReference(tr); - } - bool startHit = false, stopHit = false; - unsigned char status = 0; - if (fMC->IsTrackEntering()) { - status |= Hit::kTrackEntering; - } - if (fMC->IsTrackInside()) { - status |= Hit::kTrackInside; - } - if (fMC->IsTrackExiting()) { - status |= Hit::kTrackExiting; - } - if (fMC->IsTrackOut()) { - status |= Hit::kTrackOut; - } - if (fMC->IsTrackStop()) { - status |= Hit::kTrackStopped; - } - if (fMC->IsTrackAlive()) { - status |= Hit::kTrackAlive; - } - - // track is entering or created in the volume - if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { - startHit = true; - } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { - stopHit = true; - } - - // increment energy loss at all steps except entrance - if (!startHit) { - mTrackData.mEnergyLoss += fMC->Edep(); - } - if (!(startHit | stopHit)) { - return kFALSE; // do noting - } - - if (startHit) { - mTrackData.mEnergyLoss = 0.; - fMC->TrackMomentum(mTrackData.mMomentumStart); - fMC->TrackPosition(mTrackData.mPositionStart); - mTrackData.mTrkStatusStart = status; - mTrackData.mHitStarted = true; - } - if (stopHit) { - TLorentzVector positionStop; - fMC->TrackPosition(positionStop); - // Retrieve the indices with the volume path - int stave(0), halfstave(0), chipinmodule(0), module; - fMC->CurrentVolOffID(1, chipinmodule); - fMC->CurrentVolOffID(2, module); - fMC->CurrentVolOffID(3, halfstave); - fMC->CurrentVolOffID(4, stave); - int chipindex = mGeometryTGeo->getChipIndex(lay, stave, halfstave, module, chipinmodule); - - Hit* p = addHit(stack->GetCurrentTrackNumber(), chipindex, mTrackData.mPositionStart.Vect(), positionStop.Vect(), - mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), - mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); - // p->SetTotalEnergy(vmc->Etot()); - - // RS: not sure this is needed - // Increment number of Detector det points in TParticle - stack->addHit(GetDetId()); - } - - return kTRUE; -} - -void Detector::createMaterials() -{ - Int_t ifield = 2; - Float_t fieldm = 10.0; - o2::base::Detector::initFieldTrackingParams(ifield, fieldm); - //////////// - - Float_t tmaxfd = 0.1; // 1.0; // Degree - Float_t stemax = 1.0; // cm - Float_t deemax = 0.1; // 30.0; // Fraction of particle's energy 0<deemax<=1 - Float_t epsil = 1.0E-4; // 1.0; // cm - Float_t stmin = 0.0; // cm "Default value used" - - Float_t tmaxfdSi = 0.1; // .10000E+01; // Degree - Float_t stemaxSi = 0.0075; // .10000E+01; // cm - Float_t deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 - Float_t epsilSi = 1.0E-4; // .10000E+01; - Float_t stminSi = 0.0; // cm "Default value used" - - Float_t tmaxfdAir = 0.1; // .10000E+01; // Degree - Float_t stemaxAir = .10000E+01; // cm - Float_t deemaxAir = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1 - Float_t epsilAir = 1.0E-4; // .10000E+01; - Float_t stminAir = 0.0; // cm "Default value used" - - // AIR - Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; - Float_t zAir[4] = {6., 7., 8., 18.}; - Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; - Float_t dAir = 1.20479E-3; - - // Water - Float_t aWater[2] = {1.00794, 15.9994}; - Float_t zWater[2] = {1., 8.}; - Float_t wWater[2] = {0.111894, 0.888106}; - Float_t dWater = 1.0; - - // PEEK CF30 - Float_t aPEEK[3] = {12.0107, 1.00794, 15.9994}; - Float_t zPEEK[3] = {6., 1., 8.}; - Float_t wPEEK[3] = {19., 12., 3}; - Float_t dPEEK = 1.32; - - // Kapton - Float_t aKapton[4] = {1.00794, 12.0107, 14.010, 15.9994}; - Float_t zKapton[4] = {1., 6., 7., 8.}; - Float_t wKapton[4] = {0.026362, 0.69113, 0.07327, 0.209235}; - Float_t dKapton = 1.42; - - // Tungsten Carbide - Float_t aWC[2] = {183.84, 12.0107}; - Float_t zWC[2] = {74, 6}; - Float_t wWC[2] = {0.5, 0.5}; - Float_t dWC = 15.63; - - // BEOL (Metal interconnection stack in Si sensors) - Float_t aBEOL[3] = {26.982, 28.086, 15.999}; - Float_t zBEOL[3] = {13, 14, 8}; // Al, Si, O - Float_t wBEOL[3] = {0.170, 0.388, 0.442}; - Float_t dBEOL = 2.28; - - // Inox 304 - Float_t aInox304[4] = {12.0107, 51.9961, 58.6928, 55.845}; - Float_t zInox304[4] = {6., 24., 28, 26}; // C, Cr, Ni, Fe - Float_t wInox304[4] = {0.0003, 0.18, 0.10, 0}; // [3] will be computed - Float_t dInox304 = 7.85; - - // Ceramic (for IB capacitors) (BaTiO3) - Float_t aCeramic[3] = {137.327, 47.867, 15.999}; - Float_t zCeramic[3] = {56, 22, 8}; // Ba, Ti, O - Float_t wCeramic[3] = {1, 1, 3}; // Molecular composition - Float_t dCeramic = 6.02; - - // Rohacell (C9 H13 N1 O2) - Float_t aRohac[4] = {12.01, 1.01, 14.010, 16.}; - Float_t zRohac[4] = {6., 1., 7., 8.}; - Float_t wRohac[4] = {9., 13., 1., 2.}; - Float_t dRohac = 0.05; - - o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir); - o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir); - - o2::base::Detector::Mixture(2, "WATER$", aWater, zWater, dWater, 2, wWater); - o2::base::Detector::Medium(2, "WATER$", 2, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - o2::base::Detector::Material(3, "SI$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03); - o2::base::Detector::Medium(3, "SI$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - - o2::base::Detector::Material(4, "BERILLIUM$", 9.01, 4., 1.848, 35.3, 36.7); // From AliPIPEv3 - o2::base::Detector::Medium(4, "BERILLIUM$", 4, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - o2::base::Detector::Material(5, "COPPER$", 0.63546E+02, 0.29000E+02, 0.89600E+01, 0.14300E+01, 0.99900E+03); - o2::base::Detector::Medium(5, "COPPER$", 5, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // needed for STAVE , Carbon, kapton, Epoxy, flexcable - - // AliceO2::Base::Detector::Material(6,"CARBON$",12.0107,6,2.210,999,999); - o2::base::Detector::Material(6, "CARBON$", 12.0107, 6, 2.210 / 1.3, 999, 999); - o2::base::Detector::Medium(6, "CARBON$", 6, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - - o2::base::Detector::Mixture(7, "KAPTON(POLYCH2)$", aKapton, zKapton, dKapton, 4, wKapton); - o2::base::Detector::Medium(7, "KAPTON(POLYCH2)$", 7, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // values below modified as compared to source AliITSv11 ! - - // BEOL (Metal interconnection stack in Si sensors) - o2::base::Detector::Mixture(29, "METALSTACK$", aBEOL, zBEOL, dBEOL, 3, wBEOL); - o2::base::Detector::Medium(29, "METALSTACK$", 29, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // Glue between IB chip and FPC: density reduced to take into account - // empty spaces (160 glue spots/chip , diam. 1 spot = 1 mm) - o2::base::Detector::Material(30, "GLUE_IBFPC$", 12.011, 6, 1.05 * 0.3, 999, 999); - o2::base::Detector::Medium(30, "GLUE_IBFPC$", 30, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // Ceramic for IB capacitors (nmat < 0 => wmat contains number of atoms) - o2::base::Detector::Mixture(31, "CERAMIC$", aCeramic, zCeramic, dCeramic, -3, wCeramic); - o2::base::Detector::Medium(31, "CERAMIC$", 31, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // All types of carbon - // Unidirectional prepreg - o2::base::Detector::Material(8, "K13D2U2k$", 12.0107, 6, 1.643, 999, 999); - o2::base::Detector::Medium(8, "K13D2U2k$", 8, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - o2::base::Detector::Material(17, "K13D2U120$", 12.0107, 6, 1.583, 999, 999); - o2::base::Detector::Medium(17, "K13D2U120$", 17, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // Carbon prepreg woven - o2::base::Detector::Material(18, "F6151B05M$", 12.0107, 6, 2.133, 999, 999); - o2::base::Detector::Medium(18, "F6151B05M$", 18, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // Impregnated thread - o2::base::Detector::Material(9, "M60J3K$", 12.0107, 6, 2.21, 999, 999); - o2::base::Detector::Medium(9, "M60J3K$", 9, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // Impregnated thread - o2::base::Detector::Material(10, "M55J6K$", 12.0107, 6, 1.63, 999, 999); - o2::base::Detector::Medium(10, "M55J6K$", 10, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // Fabric(0/90) - o2::base::Detector::Material(11, "T300$", 12.0107, 6, 1.725, 999, 999); - o2::base::Detector::Medium(11, "T300$", 11, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // AMEC Thermasol - o2::base::Detector::Material(12, "FGS003$", 12.0107, 6, 1.6, 999, 999); - o2::base::Detector::Medium(12, "FGS003$", 12, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - // Carbon fleece - o2::base::Detector::Material(13, "CarbonFleece$", 12.0107, 6, 0.4, 999, 999); - o2::base::Detector::Medium(13, "CarbonFleece$", 13, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, - stminSi); - // Rohacell - o2::base::Detector::Mixture(32, "ROHACELL$", aRohac, zRohac, dRohac, -4, wRohac); - o2::base::Detector::Medium(32, "ROHACELL$", 32, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - - // PEEK CF30 - o2::base::Detector::Mixture(19, "PEEKCF30$", aPEEK, zPEEK, dPEEK, -3, wPEEK); - o2::base::Detector::Medium(19, "PEEKCF30$", 19, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); - - // Flex cable - Float_t aFCm[5] = {12.0107, 1.00794, 14.0067, 15.9994, 26.981538}; - Float_t zFCm[5] = {6., 1., 7., 8., 13.}; - Float_t wFCm[5] = {0.520088819984, 0.01983871336, 0.0551367996, 0.157399667056, 0.247536}; - // Float_t dFCm = 1.6087; // original - // Float_t dFCm = 2.55; // conform with STAR - Float_t dFCm = 2.595; // conform with Corrado - - o2::base::Detector::Mixture(14, "FLEXCABLE$", aFCm, zFCm, dFCm, 5, wFCm); - o2::base::Detector::Medium(14, "FLEXCABLE$", 14, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - // AliceO2::Base::Detector::Material(7,"GLUE$",0.12011E+02,0.60000E+01,0.1930E+01/2.015,999,999); - // // original - o2::base::Detector::Material(15, "GLUE$", 12.011, 6, 1.93 / 2.015, 999, 999); // conform with ATLAS, Corrado, Stefan - o2::base::Detector::Medium(15, "GLUE$", 15, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - o2::base::Detector::Material(16, "ALUMINUM$", 0.26982E+02, 0.13000E+02, 0.26989E+01, 0.89000E+01, 0.99900E+03); - o2::base::Detector::Medium(16, "ALUMINUM$", 16, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin); - - o2::base::Detector::Mixture(20, "TUNGCARB$", aWC, zWC, dWC, 2, wWC); - o2::base::Detector::Medium(20, "TUNGCARB$", 20, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi); - - wInox304[3] = 1. - wInox304[0] - wInox304[1] - wInox304[2]; - o2::base::Detector::Mixture(21, "INOX304$", aInox304, zInox304, dInox304, 4, wInox304); - o2::base::Detector::Medium(21, "INOX304$", 21, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi); - - // Tungsten (for gamma converter rods) - o2::base::Detector::Material(28, "TUNGSTEN$", 183.84, 74, 19.25, 999, 999); - o2::base::Detector::Medium(28, "TUNGSTEN$", 28, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); -} - -void Detector::EndOfEvent() { Reset(); } - -void Detector::Register() -{ - // This will create a branch in the output tree called Hit, setting the last - // parameter to kFALSE means that this collection will not be written to the file, - // it will exist only during the simulation - - if (FairRootManager::Instance()) { - FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); - } -} - -void Detector::Reset() -{ - if (!o2::utils::ShmManager::Instance().isOperational()) { - mHits->clear(); - } -} - -void Detector::defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan) -{ - // set parameters of id-th wrapper volume - if (id >= sNumberOfWrapperVolumes || id < 0) { - LOG(FATAL) << "id " << id << " of wrapper volume is not in 0-" << sNumberOfWrapperVolumes - 1 << " range"; - } - - mWrapperMinRadius[id] = rmin; - mWrapperMaxRadius[id] = rmax; - mWrapperZSpan[id] = zspan; -} - -void Detector::defineLayer(Int_t nlay, double phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick, - Double_t dthick, UInt_t dettypeID, Int_t buildLevel) -{ - // Sets the layer parameters - // Inputs: - // nlay layer number - // phi0 layer phi0 - // r layer radius - // nstav number of staves - // nunit IB: number of chips per stave - // OB: number of modules per half stave - // lthick stave thickness (if omitted, defaults to 0) - // dthick detector thickness (if omitted, defaults to 0) - // dettypeID ?? - // buildLevel (if 0, all geometry is build, used for material budget studies) - // Outputs: - // none. - // Return: - // none. - - LOG(INFO) << "L# " << nlay << " Phi:" << phi0 << " R:" << r << " Nst:" << nstav << " Nunit:" << nunit - << " Lthick:" << lthick << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel; - - if (nlay >= mTotalNumberOfLayers || nlay < 0) { - LOG(ERROR) << "Wrong layer number " << nlay; - return; - } - - mTurboLayer[nlay] = kFALSE; - mLayerPhi0[nlay] = phi0; - mLayerRadii[nlay] = r; - mStavePerLayer[nlay] = nstav; - mUnitPerStave[nlay] = nunit; - mChipThickness[nlay] = lthick; - mDetectorThickness[nlay] = dthick; - mChipTypeID[nlay] = dettypeID; - mBuildLevel[nlay] = buildLevel; -} - -void Detector::defineInnerLayerITS4(Int_t nlay, Double_t r, Double_t zlen, - Double_t dthick, UInt_t dettypeID, Int_t buildLevel) -{ - // Sets the layer parameters - // Inputs: - // nlay layer number - // r layer radius - // zlen layer length - // dthick detector thickness (if omitted, defaults to 0) - // dettypeID ?? - // buildLevel (if 0, all geometry is build, used for material budget studies) - // Outputs: - // none. - // Return: - // none. - - LOG(INFO) << "L# " << nlay << " with ITS4 geo R:" << r - << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel; - - if (nlay >= mTotalNumberOfLayers || nlay < 0) { - LOG(ERROR) << "Wrong layer number " << nlay; - return; - } - - mTurboLayer[nlay] = kFALSE; - mITS4Layer[nlay] = kTRUE; - mLayerRadii[nlay] = r; - mLayerZLen[nlay] = zlen; - mDetectorThickness[nlay] = dthick; - mChipTypeID[nlay] = dettypeID; - mBuildLevel[nlay] = buildLevel; - LOG(INFO) << "Added layer: " << nlay << std::endl; -} - -void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& width, - Double_t& tilt, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const -{ - // Gets the layer parameters - // Inputs: - // nlay layer number - // Outputs: - // phi0 phi of 1st stave - // r layer radius - // nstav number of staves - // nmod IB: number of chips per stave - // OB: number of modules per half stave - // width stave width - // tilt stave tilt angle - // lthick stave thickness - // dthick detector thickness - // dettype detector type - // Return: - // none. - - if (nlay >= mTotalNumberOfLayers || nlay < 0) { - LOG(ERROR) << "Wrong layer number " << nlay; - return; - } - - phi0 = mLayerPhi0[nlay]; - r = mLayerRadii[nlay]; - nstav = mStavePerLayer[nlay]; - nmod = mUnitPerStave[nlay]; - width = mStaveWidth[nlay]; - tilt = mStaveTilt[nlay]; - lthick = mChipThickness[nlay]; - dthick = mDetectorThickness[nlay]; - dettype = mChipTypeID[nlay]; -} - -TGeoVolume* Detector::createWrapperVolume(Int_t id) -{ - // Creates an air-filled wrapper cylindrical volume - // For OB a Pcon is needed to host the support rings - // while avoiding overlaps with MFT structures and OB cones - - const Double_t suppRingAZlen = 4.; - const Double_t coneRingARmax = 33.96; - const Double_t coneRingAZlen = 5.6; - const Double_t suppRingCZlen[3] = {4.8, 4.0, 2.4}; - const Double_t suppRingsRmin[3] = {23.35, 20.05, 35.4}; - - if (mWrapperMinRadius[id] < 0 || mWrapperMaxRadius[id] < 0 || mWrapperZSpan[id] < 0) { - LOG(FATAL) << "Wrapper volume " << id << " was requested but not defined"; - } - - // Now create the actual shape and volume - TGeoShape* tube; - Double_t zlen; - switch (id) { - case 0: // IB Layer 0,1,2: simple cylinder - { - TGeoTube* wrap = new TGeoTube(mWrapperMinRadius[id], mWrapperMaxRadius[id], mWrapperZSpan[id] / 2.); - tube = (TGeoShape*)wrap; - } break; - case 1: // MB Layer 3,4: complex Pcon to avoid MFT overlaps - { - TGeoPcon* wrap = new TGeoPcon(0, 360, 6); - zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[0]; - wrap->DefineSection(0, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]); - zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[1]; - wrap->DefineSection(1, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]); - wrap->DefineSection(2, -zlen, suppRingsRmin[1], mWrapperMaxRadius[id]); - wrap->DefineSection(3, -mWrapperZSpan[id] / 2., suppRingsRmin[1], mWrapperMaxRadius[id]); - wrap->DefineSection(4, -mWrapperZSpan[id] / 2., mWrapperMinRadius[id], mWrapperMaxRadius[id]); - zlen = mWrapperZSpan[id] / 2 + suppRingAZlen; - wrap->DefineSection(5, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); - tube = (TGeoShape*)wrap; - } break; - case 2: // OB Layer 5,6: simpler Pcon to avoid OB cones overlaps - { - TGeoPcon* wrap = new TGeoPcon(0, 360, 6); - zlen = mWrapperZSpan[id] / 2; - wrap->DefineSection(0, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]); - zlen -= suppRingCZlen[2]; - wrap->DefineSection(1, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]); - wrap->DefineSection(2, -zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); - zlen = mWrapperZSpan[id] / 2 - coneRingAZlen; - wrap->DefineSection(3, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]); - wrap->DefineSection(4, zlen, coneRingARmax, mWrapperMaxRadius[id]); - wrap->DefineSection(5, mWrapperZSpan[id] / 2, coneRingARmax, mWrapperMaxRadius[id]); - tube = (TGeoShape*)wrap; - } break; - default: // Can never happen, keeps gcc quiet - break; - } - - TGeoMedium* medAir = gGeoManager->GetMedium("IT4_AIR$"); - - char volnam[30]; - snprintf(volnam, 29, "%s%d", GeometryTGeo::getITSWrapVolPattern(), id); - - auto* wrapper = new TGeoVolume(volnam, tube, medAir); - - return wrapper; -} - -void Detector::ConstructGeometry() -{ - // Create the detector materials - createMaterials(); - // Construct the detector geometry - constructDetectorGeometry(); -} - -void Detector::constructDetectorGeometry() -{ - // Create the geometry and insert it in the mother volume ITSV - TGeoManager* geoManager = gGeoManager; - - TGeoVolume* vALIC = geoManager->GetVolume("barrel"); - - if (!vALIC) { - LOG(FATAL) << "Could not find the top volume"; - } - new TGeoVolumeAssembly(GeometryTGeo::getITSVolPattern()); - TGeoVolume* vITSV = geoManager->GetVolume(GeometryTGeo::getITSVolPattern()); - vALIC->AddNode(vITSV, 2, new TGeoTranslation(0, 30., 0)); // Copy number is 2 to cheat AliGeoManager::CheckSymNamesLUT - - const Int_t kLength = 100; - Char_t vstrng[kLength] = "xxxRS"; //? - vITSV->SetTitle(vstrng); - - // Check that we have all needed parameters - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - if (mLayerRadii[j] <= 0) { - LOG(FATAL) << "Wrong layer radius for layer " << j << "(" << mLayerRadii[j] << ")"; - } - if (mStavePerLayer[j] <= 0 && !mITS4Layer[j]) { - LOG(FATAL) << "Wrong number of staves for layer " << j << "(" << mStavePerLayer[j] << ")"; - } - if (mUnitPerStave[j] <= 0 && !mITS4Layer[j]) { - LOG(FATAL) << "Wrong number of chips for layer " << j << "(" << mUnitPerStave[j] << ")"; - } - if (mChipThickness[j] < 0 && !mITS4Layer[j]) { - LOG(FATAL) << "Wrong chip thickness for layer " << j << "(" << mChipThickness[j] << ")"; - } - if (mTurboLayer[j] && mStaveWidth[j] <= 0) { - LOG(FATAL) << "Wrong stave width for layer " << j << "(" << mStaveWidth[j] << ")"; - } - if (mDetectorThickness[j] < 0) { - LOG(FATAL) << "Wrong Sensor thickness for layer " << j << "(" << mDetectorThickness[j] << ")"; - } - - if (j > 0 && // Always check IB, check OB only if present - ((j < mNumberOfInnerLayers) || mCreateOuterBarrel)) { - if (mLayerRadii[j] <= mLayerRadii[j - 1]) { - LOG(FATAL) << "Layer " << j << " radius (" << mLayerRadii[j] << ") is smaller than layer " << j - 1 - << " radius (" << mLayerRadii[j - 1] << ")"; - } - } - - if (mChipThickness[j] == 0 && !mITS4Layer[j]) { - LOG(INFO) << "Chip thickness for layer " << j << " not set, using default"; - } - } - - // Create the wrapper volumes - TGeoVolume** wrapVols = nullptr; - - if (sNumberOfWrapperVolumes && mCreateOuterBarrel) { - wrapVols = new TGeoVolume*[sNumberOfWrapperVolumes]; - for (int id = 1; id < sNumberOfWrapperVolumes; id++) { - wrapVols[id] = createWrapperVolume(id); - vITSV->AddNode(wrapVols[id], 1, nullptr); - } - } - if (!mCreateOuterBarrel) { - mTotalNumberOfLayers = mNumberOfInnerLayers; - } - - // Now create the actual geometry - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - TGeoVolume* dest = vITSV; - mWrapperLayerId[j] = -1; - - if (mTurboLayer[j]) { - mGeometry[j] = new V3Layer(j, kTRUE, kFALSE); - mGeometry[j]->setStaveWidth(mStaveWidth[j]); - mGeometry[j]->setStaveTilt(mStaveTilt[j]); - } else { - mGeometry[j] = new V3Layer(j, kFALSE); - } - - mGeometry[j]->setNumberOfInnerLayers(mNumberOfInnerLayers); - - if (mITS4Layer[j]) { - mGeometry[j]->setIsITS4(kTRUE); - mGeometry[j]->setIBModuleZLength(mLayerZLen[j]); - } - - mGeometry[j]->setPhi0(mLayerPhi0[j]); - mGeometry[j]->setRadius(mLayerRadii[j]); - mGeometry[j]->setNumberOfStaves(mStavePerLayer[j]); - mGeometry[j]->setNumberOfUnits(mUnitPerStave[j]); - mGeometry[j]->setChipType(mChipTypeID[j]); - mGeometry[j]->setBuildLevel(mBuildLevel[j]); - - if (j < mNumberOfInnerLayers) { - mGeometry[j]->setStaveModel(mStaveModelInnerBarrel); - } else { - mGeometry[j]->setStaveModel(mStaveModelOuterBarrel); - } - - LOG(DEBUG1) << "mBuildLevel: " << mBuildLevel[j]; - - if (mChipThickness[j] != 0) { - mGeometry[j]->setChipThick(mChipThickness[j]); - } - if (mDetectorThickness[j] != 0) { - mGeometry[j]->setSensorThick(mDetectorThickness[j]); - } - - if (mCreateOuterBarrel && j >= mNumberOfInnerLayers) { - for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) { - if (mLayerRadii[j] > mWrapperMinRadius[iw] && mLayerRadii[j] < mWrapperMaxRadius[iw]) { - LOG(DEBUG) << "Will embed layer " << j << " in wrapper volume " << iw; - - dest = wrapVols[iw]; - mWrapperLayerId[j] = iw; - break; - } - } - } - mGeometry[j]->createLayer(dest); - } - - // Finally create the services - mServicesGeometry = new V3Services(); - - // createInnerBarrelServices(wrapVols[0]); - // createMiddlBarrelServices(wrapVols[1]); - // createOuterBarrelServices(wrapVols[2]); - // createOuterBarrelSupports(vITSV); - - // TEMPORARY - These routines will be obsoleted once the new services are completed - TEMPORARY - // createServiceBarrel(kTRUE, wrapVols[0]); - // createServiceBarrel(kFALSE, wrapVols[2]); - delete[] wrapVols; // delete pointer only, not the volumes -} - -void Detector::createInnerBarrelServices(TGeoVolume* motherVolume) -{ - // - // Creates the Inner Barrel Service structures - // - // Input: - // motherVolume : the volume hosting the services - // - // Output: - // - // Return: - // - // Created: 15 May 2019 Mario Sitta - // (partially based on P.Namwongsa implementation in AliRoot) - // Updated: 19 Jun 2019 Mario Sitta IB Side A added - // Updated: 21 Oct 2019 Mario Sitta CYSS added - // - - // Create the End Wheels on Side A - TGeoVolume* endWheelsA = mServicesGeometry->createIBEndWheelsSideA(); - - motherVolume->AddNode(endWheelsA, 1, nullptr); - - // Create the End Wheels on Side C - TGeoVolume* endWheelsC = mServicesGeometry->createIBEndWheelsSideC(); - - motherVolume->AddNode(endWheelsC, 1, nullptr); - - // Create the CYSS Assembly (i.e. the supporting half cylinder and cone) - TGeoVolume* cyss = mServicesGeometry->createCYSSAssembly(); - - motherVolume->AddNode(cyss, 1, nullptr); -} - -void Detector::createMiddlBarrelServices(TGeoVolume* motherVolume) -{ - // - // Creates the Middle Barrel Service structures - // - // Input: - // motherVolume : the volume hosting the services - // - // Output: - // - // Return: - // - // Created: 24 Sep 2019 Mario Sitta - // - - // Create the End Wheels on Side A - mServicesGeometry->createMBEndWheelsSideA(motherVolume); - - // Create the End Wheels on Side C - mServicesGeometry->createMBEndWheelsSideC(motherVolume); -} - -void Detector::createOuterBarrelServices(TGeoVolume* motherVolume) -{ - // - // Creates the Outer Barrel Service structures - // - // Input: - // motherVolume : the volume hosting the services - // - // Output: - // - // Return: - // - // Created: 27 Sep 2019 Mario Sitta - // - - // Create the End Wheels on Side A - mServicesGeometry->createOBEndWheelsSideA(motherVolume); - - // Create the End Wheels on Side C - mServicesGeometry->createOBEndWheelsSideC(motherVolume); -} - -void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume) -{ - // - // Creates the Outer Barrel Service structures - // - // Input: - // motherVolume : the volume hosting the supports - // - // Output: - // - // Return: - // - // Created: 26 Jan 2020 Mario Sitta - // - - // Create the Cone on Side A - mServicesGeometry->createOBConeSideA(motherVolume); - - // Create the Cone on Side C - mServicesGeometry->createOBConeSideC(motherVolume); -} - -// Service Barrel -void Detector::createServiceBarrel(const Bool_t innerBarrel, TGeoVolume* dest, const TGeoManager* mgr) -{ - // Creates the Service Barrel (as a simple cylinder) for IB and OB - // Inputs: - // innerBarrel : if true, build IB service barrel, otherwise for OB - // dest : the mother volume holding the service barrel - // mgr : the gGeoManager pointer (used to get the material) - // - - Double_t rminIB = 4.7; - Double_t rminOB = 43.9; - Double_t zLenOB; - Double_t cInt = 0.22; // dimensioni cilindro di supporto interno - Double_t cExt = 1.00; // dimensioni cilindro di supporto esterno - // Double_t phi1 = 180; - // Double_t phi2 = 360; - - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - - if (innerBarrel) { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - // TGeoTube*ibSuppSh = new TGeoTubeSeg(rminIB,rminIB+cInt,zLenOB,phi1,phi2); - auto* ibSuppSh = new TGeoTube(rminIB, rminIB + cInt, zLenOB); - auto* ibSupp = new TGeoVolume("ibSuppCyl", ibSuppSh, medCarbonFleece); - dest->AddNode(ibSupp, 1); - } else { - zLenOB = ((TGeoTube*)(dest->GetShape()))->GetDz(); - auto* obSuppSh = new TGeoTube(rminOB, rminOB + cExt, zLenOB); - auto* obSupp = new TGeoVolume("obSuppCyl", obSuppSh, medCarbonFleece); - dest->AddNode(obSupp, 1); - } - - return; -} - -void Detector::addAlignableVolumes() const -{ - // - // Creates entries for alignable volumes associating the symbolic volume - // name with the corresponding volume path. - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - - LOG(INFO) << "Add ITS alignable volumes"; - - if (!gGeoManager) { - LOG(FATAL) << "TGeoManager doesn't exist !"; - return; - } - - TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern()); - TString sname = GeometryTGeo::composeSymNameITS4(); - - LOG(DEBUG) << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - - Int_t lastUID = 0; - for (Int_t lr = 0; lr < mTotalNumberOfLayers; lr++) { - addAlignableVolumesLayer(lr, path, lastUID); - } - - return; -} - -void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const -{ - // - // Add alignable volumes for a Layer and its daughters - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - - TString wrpV = - mWrapperLayerId[lr] != -1 ? Form("%s%d_1", GeometryTGeo::getITSWrapVolPattern(), mWrapperLayerId[lr]) : ""; - TString path; - if (mCreateOuterBarrel && (lr >= mNumberOfInnerLayers)) { - path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr); - } else { - path = Form("%s/%s%d_1", parent.Data(), GeometryTGeo::getITSLayerPattern(), lr); - } - TString sname = GeometryTGeo::composeSymNameLayer(lr); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - - const V3Layer* lrobj = mGeometry[lr]; - Int_t nstaves = lrobj->getNumberOfStavesPerParent(); - for (int st = 0; st < nstaves; st++) { - addAlignableVolumesStave(lr, st, path, lastUID); - } - - return; -} - -void Detector::addAlignableVolumesStave(Int_t lr, Int_t st, TString& parent, Int_t& lastUID) const -{ - // - // Add alignable volumes for a Stave and its daughters - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSStavePattern(), lr, st); - TString sname = GeometryTGeo::composeSymNameStave(lr, st); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - - const V3Layer* lrobj = mGeometry[lr]; - Int_t nhstave = lrobj->getNumberOfHalfStavesPerParent(); - Int_t start = nhstave > 0 ? 0 : -1; - for (Int_t sst = start; sst < nhstave; sst++) { - addAlignableVolumesHalfStave(lr, st, sst, path, lastUID); - } - - return; -} - -void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const -{ - // - // Add alignable volumes for a HalfStave (if any) and its daughters - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - - TString path = parent; - if (hst >= 0) { - path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfStavePattern(), lr, hst); - TString sname = GeometryTGeo::composeSymNameHalfStave(lr, st, hst); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - } - - const V3Layer* lrobj = mGeometry[lr]; - Int_t nmodules = lrobj->getNumberOfModulesPerParent(); - Int_t start = nmodules > 0 ? 0 : -1; - for (Int_t md = start; md < nmodules; md++) { - addAlignableVolumesModule(lr, st, hst, md, path, lastUID); - } - - return; -} - -void Detector::addAlignableVolumesModule(Int_t lr, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const -{ - // - // Add alignable volumes for a Module (if any) and its daughters - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - - TString path = parent; - if (md >= 0) { - path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSModulePattern(), lr, md); - TString sname = GeometryTGeo::composeSymNameModule(lr, st, hst, md); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - } - - const V3Layer* lrobj = mGeometry[lr]; - Int_t nchips = lrobj->getNumberOfChipsPerParent(); - for (Int_t ic = 0; ic < nchips; ic++) { - addAlignableVolumesChip(lr, st, hst, md, ic, path, lastUID); - } - - return; -} - -void Detector::addAlignableVolumesChip(Int_t lr, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, - Int_t& lastUID) const -{ - // - // Add alignable volumes for a Chip - // - // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot) - // - - TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSChipPattern(), lr, ch); - TString sname = GeometryTGeo::composeSymNameChip(lr, st, hst, md, ch); - Int_t modUID = chipVolUID(lastUID++); - - LOG(DEBUG) << "Add " << sname << " <-> " << path; - - if (!gGeoManager->SetAlignableEntry(sname, path.Data(), modUID)) { - LOG(FATAL) << "Unable to set alignable entry ! " << sname << " : " << path; - } - - return; -} - -void Detector::defineSensitiveVolumes() -{ - TGeoManager* geoManager = gGeoManager; - TGeoVolume* v; - - TString volumeName; - - // The names of the ITS sensitive volumes have the format: ITSUSensor(0...sNumberLayers-1) - for (Int_t j = 0; j < mTotalNumberOfLayers; j++) { - volumeName = GeometryTGeo::getITSSensorPattern() + TString::Itoa(j, 10); - v = geoManager->GetVolume(volumeName.Data()); - AddSensitiveVolume(v); - } -} - -Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, - unsigned char endStatus) -{ - mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); - return &(mHits->back()); -} - -void Detector::Print(std::ostream* os) const -{ - // Standard output format for this class. - // Inputs: - // ostream *os The output stream - // Outputs: - // none. - // Return: - // none. - -#if defined __GNUC__ -#if __GNUC__ > 2 - std::ios::fmtflags fmt; -#else - Int_t fmt; -#endif -#else -#if defined __ICC || defined __ECC || defined __xlC__ - ios::fmtflags fmt; -#else - Int_t fmt; -#endif -#endif - // RS: why do we need to pring this garbage? - - // fmt = os->setf(std::ios::scientific); // set scientific floating point output - // fmt = os->setf(std::ios::hex); // set hex for mStatus only. - // fmt = os->setf(std::ios::dec); // every thing else decimel. - // *os << mModule << " "; - // *os << mEnergyDepositionStep << " " << mTof; - // *os << " " << mStartingStepX << " " << mStartingStepY << " " << mStartingStepZ; - // *os << " " << endl; - // os->flags(fmt); // reset back to old formating. - return; -} - -void Detector::Read(std::istream* is) -{ - // Standard input format for this class. - // Inputs: - // istream *is the input stream - // Outputs: - // none. - // Return: - // none. - // RS no need to read garbage - return; -} - -std::ostream& operator<<(std::ostream& os, Detector& p) -{ - // Standard output streaming function. - // Inputs: - // ostream os The output stream - // Detector p The his to be printed out - // Outputs: - // none. - // Return: - // The input stream - - p.Print(&os); - return os; -} - -std::istream& operator>>(std::istream& is, Detector& r) -{ - // Standard input streaming function. - // Inputs: - // istream is The input stream - // Detector p The Detector class to be filled from this input stream - // Outputs: - // none. - // Return: - // The input stream - - r.Read(&is); - return is; -} - -ClassImp(o2::its4::Detector); diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/ITS4SimulationLinkDef.h b/Detectors/Upgrades/PostLS4/IT4/simulation/src/ITS4SimulationLinkDef.h deleted file mode 100644 index b880f7208f756..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/ITS4SimulationLinkDef.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::its4::V11Geometry + ; -#pragma link C++ class o2::its4::V1Layer + ; -#pragma link C++ class o2::its4::V3Layer + ; -#pragma link C++ class o2::its4::V3Services + ; -#pragma link C++ class o2::its4::Detector + ; -#pragma link C++ class o2::base::DetImpl < o2::its4::Detector> + ; - -#endif diff --git a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V1Layer.cxx b/Detectors/Upgrades/PostLS4/IT4/simulation/src/V1Layer.cxx deleted file mode 100644 index 6147ed7467cb7..0000000000000 --- a/Detectors/Upgrades/PostLS4/IT4/simulation/src/V1Layer.cxx +++ /dev/null @@ -1,2762 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file V1Layer.cxx -/// \brief Implementation of the V1Layer class -/// \author Mario Sitta <sitta@to.infn.it> -/// \author Chinorat Kobdaj (kobdaj@g.sut.ac.th) - -#include "ITS4Simulation/V1Layer.h" -#include "ITS4Base/GeometryTGeo.h" -#include "ITS4Simulation/Detector.h" - -#include "FairLogger.h" // for LOG - -#include <TGeoArb8.h> // for TGeoArb8 -#include <TGeoBBox.h> // for TGeoBBox -#include <TGeoCone.h> // for TGeoConeSeg, TGeoCone -#include <TGeoManager.h> // for TGeoManager, gGeoManager -#include <TGeoMatrix.h> // for TGeoCombiTrans, TGeoRotation, etc -#include <TGeoTrd1.h> // for TGeoTrd1 -#include <TGeoTube.h> // for TGeoTube, TGeoTubeSeg -#include <TGeoVolume.h> // for TGeoVolume, TGeoVolumeAssembly -#include <TGeoXtru.h> // for TGeoXtru -#include "TMathBase.h" // for Abs -#include <TMath.h> // for Sin, RadToDeg, DegToRad, Cos, Tan, etc - -#include <cstdio> // for snprintf - -class TGeoMedium; - -using namespace TMath; -using namespace o2::its4; - -// General Parameters -const Int_t V1Layer::sNumberOmInnerLayers = 3; - -const Double_t V1Layer::sDefaultSensorThick = 300 * sMicron; -const Double_t V1Layer::sDefaultStaveThick = 1 * sCm; - -// Inner Barrel Parameters -const Int_t V1Layer::sIBChipsPerRow = 9; -const Int_t V1Layer::sIBNChipRows = 1; - -// Outer Barrel Parameters -const Int_t V1Layer::sOBChipsPerRow = 7; -const Int_t V1Layer::sOBNChipRows = 2; - -const Double_t V1Layer::sOBHalfStaveWidth = 3.01 * sCm; -const Double_t V1Layer::sOBModuleWidth = sOBHalfStaveWidth; -const Double_t V1Layer::sOBModuleGap = 0.01 * sCm; -const Double_t V1Layer::sOBChipXGap = 0.01 * sCm; -const Double_t V1Layer::sOBChipZGap = 0.01 * sCm; -const Double_t V1Layer::sOBFlexCableAlThick = 0.005 * sCm; -const Double_t V1Layer::sOBFlexCableKapThick = 0.01 * sCm; -const Double_t V1Layer::sOBBusCableAlThick = 0.02 * sCm; -const Double_t V1Layer::sOBBusCableKapThick = 0.02 * sCm; -const Double_t V1Layer::sOBColdPlateThick = 0.012 * sCm; -const Double_t V1Layer::sOBCarbonPlateThick = 0.012 * sCm; -const Double_t V1Layer::sOBGlueThick = 0.03 * sCm; -const Double_t V1Layer::sOBModuleZLength = 21.06 * sCm; -const Double_t V1Layer::sOBHalfStaveYTrans = 1.76 * sMm; -const Double_t V1Layer::sOBHalfStaveXOverlap = 4.3 * sMm; -const Double_t V1Layer::sOBGraphiteFoilThick = 30.0 * sMicron; -const Double_t V1Layer::sOBCoolTubeInnerD = 2.052 * sMm; -const Double_t V1Layer::sOBCoolTubeThick = 32.0 * sMicron; -const Double_t V1Layer::sOBCoolTubeXDist = 11.1 * sMm; - -const Double_t V1Layer::sOBSpaceFrameWidth = 42.0 * sMm; -const Double_t V1Layer::sOBSpaceFrameTotHigh = 43.1 * sMm; -const Double_t V1Layer::sOBSFrameBeamRadius = 0.6 * sMm; -const Double_t V1Layer::sOBSpaceFrameLa = 3.0 * sMm; -const Double_t V1Layer::sOBSpaceFrameHa = 0.721979 * sMm; -const Double_t V1Layer::sOBSpaceFrameLb = 3.7 * sMm; -const Double_t V1Layer::sOBSpaceFrameHb = 0.890428 * sMm; -const Double_t V1Layer::sOBSpaceFrameL = 0.25 * sMm; -const Double_t V1Layer::sOBSFBotBeamAngle = 56.5; -const Double_t V1Layer::sOBSFrameBeamSidePhi = 65.0; - -ClassImp(V1Layer); - -#define SQ(A) (A) * (A) - -V1Layer::V1Layer() - : V11Geometry(), - mLayerNumber(0), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t debug) - : V11Geometry(debug), - mLayerNumber(0), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t lay, Int_t debug) - : V11Geometry(debug), - mLayerNumber(lay), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(false), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(Int_t lay, Bool_t turbo, Int_t debug) - : V11Geometry(debug), - mLayerNumber(lay), - mPhi0(0), - mLayerRadius(0), - mZLength(0), - mSensorThickness(0), - mStaveThickness(0), - mStaveWidth(0), - mStaveTilt(0), - mNumberOfStaves(0), - mNumberOfModules(0), - mNumberOfChips(0), - mChipTypeID(0), - mIsTurbo(turbo), - mBuildLevel(0), - mStaveModel(Detector::kIBModelDummy) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = 0; - } -} - -V1Layer::V1Layer(const V1Layer& s) - : V11Geometry(s.getDebug()), - mLayerNumber(s.mLayerNumber), - mPhi0(s.mPhi0), - mLayerRadius(s.mLayerRadius), - mZLength(s.mZLength), - mSensorThickness(s.mSensorThickness), - mStaveThickness(s.mStaveThickness), - mStaveWidth(s.mStaveWidth), - mStaveTilt(s.mStaveTilt), - mNumberOfStaves(s.mNumberOfStaves), - mNumberOfModules(s.mNumberOfModules), - mNumberOfChips(s.mNumberOfChips), - mChipTypeID(s.mChipTypeID), - mIsTurbo(s.mIsTurbo), - mBuildLevel(s.mBuildLevel), - mStaveModel(s.mStaveModel) -{ - for (int i = kNHLevels; i--;) { - mHierarchy[i] = s.mHierarchy[i]; - } -} - -V1Layer& V1Layer::operator=(const V1Layer& s) -{ - if (&s == this) { - return *this; - } - - mLayerNumber = s.mLayerNumber; - mPhi0 = s.mPhi0; - mLayerRadius = s.mLayerRadius; - mZLength = s.mZLength; - mSensorThickness = s.mSensorThickness; - mStaveThickness = s.mStaveThickness; - mStaveWidth = s.mStaveWidth; - mStaveTilt = s.mStaveTilt; - mNumberOfStaves = s.mNumberOfStaves; - mNumberOfModules = s.mNumberOfModules; - mNumberOfChips = s.mNumberOfChips; - mIsTurbo = s.mIsTurbo; - mChipTypeID = s.mChipTypeID; - mBuildLevel = s.mBuildLevel; - mStaveModel = s.mStaveModel; - for (int i = kNHLevels; i--;) { - mHierarchy[i] = s.mHierarchy[i]; - } - - return *this; -} - -V1Layer::~V1Layer() = default; - -void V1Layer::createLayer(TGeoVolume* motherVolume) -{ - char volumeName[30]; - Double_t xpos, ypos, zpos; - Double_t alpha; - - // Check if the user set the proper parameters - if (mLayerRadius <= 0) { - LOG(FATAL) << "Wrong layer radius " << mLayerRadius; - } - - if (mZLength <= 0) { - LOG(FATAL) << "Wrong layer length " << mZLength; - } - - if (mNumberOfStaves <= 0) { - LOG(FATAL) << "Wrong number of staves " << mNumberOfStaves; - } - - if (mNumberOfChips <= 0) { - LOG(FATAL) << "Wrong number of chips " << mNumberOfChips; - } - - if (mLayerNumber >= sNumberOmInnerLayers && mNumberOfModules <= 0) { - LOG(FATAL) << "Wrong number of modules " << mNumberOfModules; - } - - if (mStaveThickness <= 0) { - LOG(INFO) << "Stave thickness wrong or not set " << mStaveThickness << " using default " - << sDefaultStaveThick; - mStaveThickness = sDefaultStaveThick; - } - - if (mSensorThickness <= 0) { - LOG(INFO) << "Sensor thickness wrong or not set " << mSensorThickness << " using default " - << sDefaultSensorThick; - mSensorThickness = sDefaultSensorThick; - } - - if (mSensorThickness > mStaveThickness) { - LOG(WARNING) << "Sensor thickness " << mSensorThickness << " is greater than stave thickness " - << mStaveThickness << " fixing"; - mSensorThickness = mStaveThickness; - } - - // If a Turbo layer is requested, do it and exit - if (mIsTurbo) { - createLayerTurbo(motherVolume); - return; - } - - // First create the stave container - alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); - - // mStaveWidth = mLayerRadius*Tan(alpha); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); - - // layerVolume->SetVisibility(kFALSE); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); - - TGeoVolume* stavVol = createStave(); - - // Now build up the layer - alpha = 360. / mNumberOfStaves; - Double_t r = mLayerRadius + ((TGeoBBox*)stavVol->GetShape())->GetDY(); - for (Int_t j = 0; j < mNumberOfStaves; j++) { - Double_t phi = j * alpha + mPhi0; - xpos = r * cosD(phi); // r*sinD(-phi); - ypos = r * sinD(phi); // r*cosD(-phi); - zpos = 0.; - phi += 90; - layerVolume->AddNode(stavVol, j, - new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi, 0, 0))); - } - - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - - // geometry is served - return; -} - -void V1Layer::createLayerTurbo(TGeoVolume* motherVolume) -{ - char volumeName[30]; - Double_t xpos, ypos, zpos; - Double_t alpha; - - // Check if the user set the proper (remaining) parameters - if (mStaveWidth <= 0) { - LOG(FATAL) << "Wrong stave width " << mStaveWidth; - } - - if (Abs(mStaveTilt) > 45) { - LOG(WARNING) << "Stave tilt angle (" << mStaveTilt << ") greater than 45deg"; - } - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSLayerPattern(), mLayerNumber); - TGeoVolume* layerVolume = new TGeoVolumeAssembly(volumeName); - layerVolume->SetUniqueID(mChipTypeID); - layerVolume->SetVisibility(kTRUE); - layerVolume->SetLineColor(1); - TGeoVolume* stavVol = createStave(); - - // Now build up the layer - alpha = 360. / mNumberOfStaves; - Double_t r = mLayerRadius /* +chip thick ?! */; - for (Int_t j = 0; j < mNumberOfStaves; j++) { - Double_t phi = j * alpha + mPhi0; - xpos = r * cosD(phi); // r*sinD(-phi); - ypos = r * sinD(phi); // r*cosD(-phi); - zpos = 0.; - phi += 90; - layerVolume->AddNode( - stavVol, j, - new TGeoCombiTrans(xpos, ypos, zpos, new TGeoRotation("", phi - mStaveTilt, 0, 0))); - } - - // Finally put everything in the mother volume - motherVolume->AddNode(layerVolume, 1, nullptr); - - return; -} - -TGeoVolume* V1Layer::createStave(const TGeoManager* /*mgr*/) -{ - char volumeName[30]; - - Double_t xlen, ylen, zlen; - Double_t xpos, ypos; - Double_t alpha; - - // First create all needed shapes - alpha = (360. / (2 * mNumberOfStaves)) * DegToRad(); - - // The stave - xlen = mLayerRadius * Tan(alpha); - if (mIsTurbo) { - xlen = 0.5 * mStaveWidth; - } - ylen = 0.5 * mStaveThickness; - zlen = 0.5 * mZLength; - - Double_t yplus = 0.46; - auto* stave = new TGeoXtru(2); // z sections - Double_t xv[5] = {xlen, xlen, 0, -xlen, -xlen}; - Double_t yv[5] = {ylen + 0.09, -0.15, -yplus - mSensorThickness, -0.15, ylen + 0.09}; - stave->DefinePolygon(5, xv, yv); - stave->DefineSection(0, -zlen, 0, 0, 1.); - stave->DefineSection(1, +zlen, 0, 0, 1.); - - // We have all shapes: now create the real volumes - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSStavePattern(), mLayerNumber); - // TGeoVolume *staveVol = new TGeoVolume(volumeName, stave, medAir); - TGeoVolume* staveVol = new TGeoVolumeAssembly(volumeName); - - // staveVol->SetVisibility(kFALSE); - staveVol->SetVisibility(kTRUE); - staveVol->SetLineColor(2); - TGeoVolume* mechStaveVol = nullptr; - - // Now build up the stave - if (mLayerNumber < sNumberOmInnerLayers) { - TGeoVolume* modVol = createStaveInnerB(xlen, ylen, zlen); - staveVol->AddNode(modVol, 0); - mHierarchy[kHalfStave] = 1; - - // Mechanical stave structure - mechStaveVol = createStaveStructInnerB(xlen, zlen); - if (mechStaveVol) { - ypos = ((TGeoBBox*)(modVol->GetShape()))->GetDY() + - ((TGeoBBox*)(mechStaveVol->GetShape()))->GetDY(); - staveVol->AddNode(mechStaveVol, 1, - new TGeoCombiTrans(0, -ypos, 0, new TGeoRotation("", 0, 0, 180))); - } - } else { - TGeoVolume* hstaveVol = createStaveOuterB(); - if (mStaveModel == Detector::kOBModel0) { // Create simplified stave struct as in v0 - staveVol->AddNode(hstaveVol, 0); - mHierarchy[kHalfStave] = 1; - } else { // (if mStaveModel) Create new stave struct as in TDR - xpos = ((TGeoBBox*)(hstaveVol->GetShape()))->GetDX() - sOBHalfStaveXOverlap / 2; - // ypos is CF height as computed in createSpaceFrameOuterB1 - ypos = (sOBSpaceFrameTotHigh - sOBHalfStaveYTrans) / 2; - staveVol->AddNode(hstaveVol, 0, new TGeoTranslation(-xpos, ypos, 0)); - staveVol->AddNode(hstaveVol, 1, new TGeoTranslation(xpos, ypos + sOBHalfStaveYTrans, 0)); - mHierarchy[kHalfStave] = 2; // RS - mechStaveVol = createSpaceFrameOuterB(); - - if (mechStaveVol) { - staveVol->AddNode(mechStaveVol, 1, - new TGeoCombiTrans(0, 0, 0, new TGeoRotation("", 180, 0, 0))); - } - } - } - // Done, return the stave - return staveVol; -} - -TGeoVolume* V1Layer::createStaveInnerB(const Double_t xsta, const Double_t ysta, - const Double_t zsta, const TGeoManager* mgr) -{ - Double_t xmod, ymod, zmod; - char volumeName[30]; - - // First we create the module (i.e. the HIC with 9 chips) - TGeoVolume* moduleVol = createModuleInnerB(xsta, ysta, zsta); - - // Then we create the fake halfstave and the actual stave - xmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDX(); - ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); - zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); - - auto* hstave = new TGeoBBox(xmod, ymod, zmod); - - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); - - // Finally build it up - hstaveVol->AddNode(moduleVol, 0); - mHierarchy[kModule] = 1; - - // Done, return the stave structure - return hstaveVol; -} - -TGeoVolume* V1Layer::createModuleInnerB(Double_t xmod, Double_t ymod, Double_t zmod, - const TGeoManager* mgr) -{ - Double_t zchip; - Double_t zpos; - char volumeName[30]; - - // First create the single chip - zchip = zmod / sIBChipsPerRow; - TGeoVolume* chipVol = createChipInnerB(xmod, ymod, zchip); - - // Then create the module and populate it with the chips - auto* module = new TGeoBBox(xmod, ymod, zmod); - - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - - // mm (not used) zlen = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - for (Int_t j = 0; j < sIBChipsPerRow; j++) { - zpos = -zmod + j * 2 * zchip + zchip; - modVol->AddNode(chipVol, j, new TGeoTranslation(0, 0, zpos)); - mHierarchy[kChip]++; - } - // Done, return the module - return modVol; -} - -TGeoVolume* V1Layer::createStaveStructInnerB(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kIBModelDummy: - mechStavVol = createStaveModelInnerBDummy(xsta, zsta, mgr); - break; - case Detector::kIBModel0: - mechStavVol = createStaveModelInnerB0(xsta, zsta, mgr); - break; - case Detector::kIBModel1: - mechStavVol = createStaveModelInnerB1(xsta, zsta, mgr); - break; - case Detector::kIBModel21: - mechStavVol = createStaveModelInnerB21(xsta, zsta, mgr); - break; - case Detector::kIBModel22: - mechStavVol = createStaveModelInnerB22(xsta, zsta, mgr); - break; - case Detector::kIBModel3: - mechStavVol = createStaveModelInnerB3(xsta, zsta, mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerBDummy(const Double_t, const Double_t, - const TGeoManager*) const -{ - // Done, return the stave structur - return nullptr; -} - -TGeoVolume* V1Layer::createStaveModelInnerB0(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - LOG(INFO) << "################################# pointer :" << medWater; - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - LOG(INFO) << "################################# pointer :" << medM60J3K; - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT4_FLEXCABLE$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - Double_t kConeInRadius = 0.1430 / 2; - Double_t kStaveLength = zsta * 2; - Double_t kStaveWidth = xsta * 2 - kConeOutRadius * 2; - Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth - Double_t kStaveHeight = 0.3; - Double_t kHeight = kStaveHeight / 2; - Double_t kAlpha = 90 - 67; // 90-33.69; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = kWidth / TMath::Sin(kTheta); - Double_t kL1 = kWidth / TMath::Tan(kTheta); - Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - // Int_t loop = kStaveLength/(kL1); - // Double_t s3 = kWidth/(2*TMath::Sin(kTheta)); - // Double_t s4 = 3*kWidth/(2*TMath::Sin(kTheta)); - - LOG(DEBUG1) << "BuildLevel " << mBuildLevel; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -0.011 + 0.0150, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // detailed structure ++++++++++++++ - // Pipe Kapton grey-35 - auto* coolTube = new TGeoTube(kConeInRadius, kConeOutRadius, kStaveLength / 2); - auto* volCoolTube = new TGeoVolume("pipe", coolTube, medKapton); - volCoolTube->SetFillColor(35); - volCoolTube->SetLineColor(35); - mechStavVol->AddNode(volCoolTube, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - mechStavVol->AddNode(volCoolTube, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength / 2); - auto* volCoolTubeW = new TGeoVolume("pipeWater", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x + (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x - (kStaveWidth / 2), y - (kHeight - kConeOutRadius), 0)); - } - - // frequency of filament - // n = 4 means very dense(4 filaments per interval) - // n = 2 means dense(2 filaments per interval) - Int_t n = 4; - Int_t loop = (Int_t)(kStaveLength / (4 * kL1 / n) + 2 / n) - 1; - if (mBuildLevel < 3) { - // Top CFRP Filament black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(kS2, 0.007 / 2, 0.15 / 2); //(kS2,0.002,0.02); - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - - for (int i = 1; i < loop; i++) { // i<60;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, - new TGeoCombiTrans( - x + kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans( - x - kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans( - x + kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans( - x - kWidth, y + (2 * kConeOutRadius), - z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - - // Bottom CFRP Filament black-12 Carbon structure TGeoBBox (thickness,width,length) - auto* t1 = new TGeoBBox(0.007 / 2, 0.15 / 2, kS1); //(0.002,0.02,kS1); - auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - - for (int i = 1; i < loop; i++) { - mechStavVol->AddNode( - volT1, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - } - - if (mBuildLevel < 2) { - // Glue CFRP-Silicon layers TGeoBBox(thickness,width,kS1); - auto* tG = new TGeoBBox(0.0075 / 2, 0.18 / 2, kS1); - auto* volTG = new TGeoVolume("Glue1", tG, medGlue); - volTG->SetLineColor(5); - volTG->SetFillColor(5); - - for (int i = 1; i < loop; i++) { // i<60;i++){ - mechStavVol->AddNode( - volTG, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), - new TGeoRotation("volTG", -90, kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * kL1 * i) + kS1 / 2, // z-14.25+(2*kL1*i), - new TGeoRotation("volTG", 90, kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - 0.16, z - kStaveLength / 2 + ((4 / n) * i * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volTG", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volTG, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - 0.16, z - kStaveLength / 2 + (i * (4 / n) * kL1) + kS1 / 2, // z-14.25+(i*2*kL1), - new TGeoRotation("volTG", -90, +kAlpha, 0))); - } - - auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("Glue2", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - // mechStavVol->AddNode(volGlue, 0, new TGeoCombiTrans(x, y-0.16, z, new TGeoRotation("",0, 0, - // 0))); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - // Flex cable brown-28 TGeoBBox(width,thickness,length); - auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structur - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerB1(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT4_FLEXCABLE$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - // Double_t kConeInRadius = 0.1430/2; - Double_t kStaveLength = zsta * 2; - // Double_t kStaveWidth = xsta*2-kConeOutRadius*2; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = kStaveWidth / 4; // 1/2 of kWidth - Double_t kStaveHeight = 0.3; - Double_t kHeight = kStaveHeight / 2; - Double_t kAlpha = 90 - 33.; // 90-30; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = kWidth / TMath::Sin(kTheta); - Double_t kL1 = kWidth / TMath::Tan(kTheta); - Double_t kS2 = TMath::Sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - Int_t loop = (Int_t)((kStaveLength / (2 * kL1)) / 2); - - TGeoVolume* mechStavVol = nullptr; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - // detailed structure ++++++++++++++ - Double_t z = 0, y = -0.011 + 0.0150, x = 0; - - // Polimide micro channels numbers - Double_t yMC = y - kHeight + 0.01; - Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; - Double_t xstaMC = (nb * 0.1 - 0.08) / 2; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Polimide micro channels numbers - auto* tM0 = new TGeoBBox(xstaMC, 0.005 / 2, zsta); - auto* volTM0 = new TGeoVolume("MicroChanCover", tM0, medKapton); - volTM0->SetLineColor(35); - volTM0->SetFillColor(35); - mechStavVol->AddNode(volTM0, 0, - new TGeoCombiTrans(x, -0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volTM0, 1, - new TGeoCombiTrans(x, +0.0125 + yMC, z, new TGeoRotation("", 0, 0, 0))); - - auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); - auto* volTM0b = new TGeoVolume("MicroChanWalls", tM0b, medKapton); - volTM0b->SetLineColor(35); - volTM0b->SetFillColor(35); - for (Int_t ib = 0; ib < nb; ib++) { - mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.01, yMC, z, new TGeoRotation("", 0, 0, 0))); - } - } - - if (mBuildLevel < 4) { - // Water in Polimide micro channels - auto* water = new TGeoBBox(0.08 / 2, 0.02 / 2, zsta + 0.1); - auto* volWater = new TGeoVolume("Water", water, medWater); - volWater->SetLineColor(4); - volWater->SetFillColor(4); - for (Int_t ib = 0; ib < (nb - 1); ib++) { - mechStavVol->AddNode(volWater, ib, new TGeoCombiTrans(x + ib * 0.1 - xstaMC + 0.06, yMC, z, new TGeoRotation("", 0, 0, 0))); - } - } - - if (mBuildLevel < 3) { - // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) - Double_t filWidth = 0.04; - Double_t filHeight = 0.02; - auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, kS1); - auto* volT1 = new TGeoVolume("CFRPBottom", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT1, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT1, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - - // Top filament CFRP black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(kS2, filHeight / 2, filWidth / 2); - auto* volT2 = new TGeoVolume("CFRPTop", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - } - - if (mBuildLevel < 2) { - // Glue between filament and polimide micro channel - auto* t3 = new TGeoBBox(0.01 / 2, 0.04, kS1); - auto* volT3 = new TGeoVolume("FilamentGlue", t3, medGlue); - volT3->SetLineColor(5); - volT3->SetFillColor(5); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT3, 4 * i + 0, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", -90, kAlpha, 0))); - mechStavVol->AddNode(volT3, 4 * i + 1, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + (4 * kL1 * i) + kS1 / 2, - new TGeoRotation("volT1", 90, kAlpha, 0))); - mechStavVol->AddNode( - volT3, 4 * i + 2, - new TGeoCombiTrans(x + kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, -kAlpha, 0))); - mechStavVol->AddNode( - volT3, 4 * i + 3, - new TGeoCombiTrans(x - kWidth, y - kHeight + 0.0325, - z - kStaveLength / 2 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT1", -90, +kAlpha, 0))); - } - - // Glue microchannel and sensor - auto* glueM = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volGlueM = new TGeoVolume("MicroChanGlue", glueM, medGlue); - volGlueM->SetLineColor(5); - volGlueM->SetFillColor(5); - mechStavVol->AddNode(volGlueM, 0, - new TGeoCombiTrans(x, y - 0.16, z, new TGeoRotation("", 0, 0, 0))); - - // Glue sensor and kapton - auto* glue = new TGeoBBox(xsta, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("SensorGlue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(xsta, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.165 - mSensorThickness - 0.005 - 0.01, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structur - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelInnerB21(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT4_FLEXCABLE$"); - TGeoMedium* medK13D2U2k = mgr->GetMedium("IT4_K13D2U2k$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT4_FGS003$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = 0.151384 / 2; - Double_t kConeInRadius = 0.145034 / 2; - Double_t kStaveLength = zsta; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = (kStaveWidth + 0.005) / 4; - Double_t kStaveHeigth = 0.33; // 0.33; - Double_t kHeight = (kStaveHeigth + 0.025) / 2; - Double_t kAlpha = 57; // 56.31; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = (kStaveWidth / 4) / TMath::Sin(kTheta); - Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); - Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(the2); - Double_t kThe2 = TMath::ATan(kHeight / kS1); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - // Double_t lay1 = 0.003157; - Double_t kLay1 = 0.003; // Amec carbon - // Double_t lay2 = 0.0043215;//C Fleece carbon - Double_t kLay2 = 0.002; // C Fleece carbon - Double_t kLay3 = 0.007; // K13D2U carbon - Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -(kConeOutRadius + 0.03) + 0.0385, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, kStaveHeigth, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Pipe Kapton grey-35 - auto* cone1 = - new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius, kConeInRadius, kConeOutRadius); - auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); - volCone1->SetFillColor(35); - volCone1->SetLineColor(35); - mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); - mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius, kStaveLength); - auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); - } - - if (mBuildLevel < 3) { - // top fillament - // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = - new TGeoBBox(kS2, 0.02 / 2, 0.04 / 2); // TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02); - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - - for (int i = 0; i < loop; i++) { // i<28;i++){ - mechStavVol->AddNode( - volT2, i * 4 + 1, - new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 2, - new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 3, - new TGeoCombiTrans(x + kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - mechStavVol->AddNode( - volT2, i * 4 + 4, - new TGeoCombiTrans(x - kWidth, y + kHeight + (0.12 / 2) - 0.014 + 0.007, - z - kStaveLength + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - // mechStavVol->AddNode(volT2,i*4+1,new - // TGeoCombiTrans(x+kWidth+0.0036,y+kHeight-(0.12/2)+0.072,z+kStaveLength+(i*4*kL1)+kS1/2, new - // TGeoRotation("volT2",90,90-kAlpha,90-kBeta))); - } - - // wall side structure out - auto* box4 = new TGeoBBox(0.03 / 2, 0.12 / 2, kStaveLength - 0.50); - auto* plate4 = new TGeoVolume("WallOut", box4, medM60J3K); - plate4->SetFillColor(35); - plate4->SetLineColor(35); - mechStavVol->AddNode(plate4, 1, - new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - (0.03 / 2), - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate4", 0, 0, 0))); - mechStavVol->AddNode(plate4, 2, - new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + (0.03 / 2), - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate4", 0, 0, 0))); - // wall side in - auto* box5 = new TGeoBBox(0.015 / 2, 0.12 / 2, kStaveLength - 0.50); - auto* plate5 = new TGeoVolume("WallIn", box5, medM60J3K); - plate5->SetFillColor(12); - plate5->SetLineColor(12); - mechStavVol->AddNode(plate5, 1, - new TGeoCombiTrans(x + (2 * kStaveWidth / 4) - 0.03 - 0.015 / 2, - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate5", 0, 0, 0))); - mechStavVol->AddNode(plate5, 2, - new TGeoCombiTrans(x - (2 * kStaveWidth / 4) + 0.03 + 0.015 / 2, - y - 0.0022 - kConeOutRadius + 0.12 / 2 + 0.007, z, - new TGeoRotation("plate5", 0, 0, 0))); - - // Amec Thermasol red-2 cover tube FGS300 - auto* cons1 = - new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius, kConeOutRadius + kLay1, kConeOutRadius, - kConeOutRadius + kLay1, 0, 180); - auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); - cone11->SetFillColor(2); - cone11->SetLineColor(2); - mechStavVol->AddNode(cone11, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); - mechStavVol->AddNode(cone11, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone11", 0, 0, 0))); - - auto* box2 = - new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, kLay1 / 2, kStaveLength - 0.50); - auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); - plate2->SetFillColor(2); - plate2->SetLineColor(2); - mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); - - auto* box21 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay1 / 2, kStaveLength - 0.50); - auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); - plate21->SetFillColor(2); - plate21->SetLineColor(2); - mechStavVol->AddNode( - plate21, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - mechStavVol->AddNode( - plate21, 2, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (kLay1 / 2), y - kConeOutRadius + (kLay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - - auto* box22 = new TGeoBBox((kLay1 / 2), kConeOutRadius / 2, kStaveLength - 0.50); - auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); - plate22->SetFillColor(2); - plate22->SetLineColor(2); - mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (kLay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - - // C Fleece - auto* cons2 = - new TGeoConeSeg(kStaveLength - 0.50, kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, - kConeOutRadius + kLay1, kConeOutRadius + kLay1 + kLay2, 0, 180); - auto* cone12 = new TGeoVolume("CFleecePipeCover", cons2, medCarbonFleece); - cone12->SetFillColor(28); - cone12->SetLineColor(28); - mechStavVol->AddNode(cone12, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); - mechStavVol->AddNode(cone12, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("Cone12", 0, 0, 0))); - - auto* box3 = - new TGeoBBox((0.50 - (2 * (kConeOutRadius + kLay1))) / 2, kLay2 / 2, kStaveLength - 0.50); - auto* plate3 = new TGeoVolume("CFleeceMiddle", box3, medCarbonFleece); - plate3->SetFillColor(28); - plate3->SetLineColor(28); - mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); - - auto* box31 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - kLay1) / 2, kLay2 / 2, kStaveLength - 0.50); - auto* plate31 = new TGeoVolume("CFleeceLeftRight", box31, medCarbonFleece); - plate31->SetFillColor(28); - plate31->SetLineColor(28); - mechStavVol->AddNode( - plate31, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + kLay1 + (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, - y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - mechStavVol->AddNode( - plate31, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - kLay1 - (0.75 - 0.25 - kConeOutRadius - kLay1) / 2, - y - kConeOutRadius + kLay1 + (kLay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - - auto* box32 = new TGeoBBox((kLay2 / 2), (kConeOutRadius - kLay1) / 2, kStaveLength - 0.50); - auto* plate32 = new TGeoVolume("CFleeceVertical", box32, medCarbonFleece); - plate32->SetFillColor(28); - plate32->SetLineColor(28); - mechStavVol->AddNode(plate32, 1, - new TGeoCombiTrans(x + 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 2, - new TGeoCombiTrans(x + 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 3, - new TGeoCombiTrans(x - 0.25 + kConeOutRadius + kLay1 + (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 4, - new TGeoCombiTrans(x - 0.25 - kConeOutRadius - kLay1 - (kLay2 / 2), - y + (kLay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - - // K13D2U carbon plate - auto* box1 = new TGeoBBox(2 * kWidth, kLay3 / 2, kStaveLength - 0.50); - auto* plate1 = new TGeoVolume("CarbonPlate", box1, medK13D2U2k); - plate1->SetFillColor(5); - plate1->SetLineColor(5); - mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (kLay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); - - // C Fleece bottom plate - auto* box6 = new TGeoBBox(2 * kWidth, kLay2 / 2, kStaveLength - 0.50); - auto* plate6 = new TGeoVolume("CFleeceBottom", box6, medCarbonFleece); - plate6->SetFillColor(2); - plate6->SetLineColor(2); - mechStavVol->AddNode(plate6, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2)), z, - new TGeoRotation("plate1", 0, 0, 0))); - } - - if (mBuildLevel < 2) { - // Glue layers and kapton - auto* glue = new TGeoBBox(kStaveWidth / 2, 0.005 / 2, zsta); - auto* volGlue = new TGeoVolume("Glue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode( - volGlue, 0, new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + (0.01 / 2)), z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volGlue, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + (0.01 / 2)), - z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(kStaveWidth / 2, 0.01 / 2, zsta); - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - (kConeOutRadius + kLay3 + (kLay2 / 2) + 0.01 + mSensorThickness + 0.01 + (0.01 / 2)), - z, new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structure - return mechStavVol; -} - -// new model22 -TGeoVolume* V1Layer::createStaveModelInnerB22(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT4_FLEXCABLE$"); - TGeoMedium* medK13D2U2k = mgr->GetMedium("IT4_K13D2U2k$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT4_FGS003$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = (0.1024 + 0.0025) / 2; // 0.107/2; - Double_t kConeInRadius = 0.1024 / 2; // 0.10105/2 - Double_t kStaveLength = zsta; - Double_t kStaveWidth = xsta * 2; - Double_t kWidth = (kStaveWidth) / 4; - Double_t kStaveHeight = 0.283; // 0.33; - Double_t kHeight = (kStaveHeight) / 2; - Double_t kAlpha = 57; // 56.31; - Double_t kTheta = kAlpha * TMath::DegToRad(); - Double_t kS1 = ((kStaveWidth) / 4) / TMath::Sin(kTheta); - Double_t kL1 = (kStaveWidth / 4) / TMath::Tan(kTheta); - Double_t kS2 = sqrt(kHeight * kHeight + kS1 * kS1); // TMath::Sin(kThe2); - Double_t kThe2 = TMath::ATan(kHeight / (0.375 - 0.036)); - Double_t kBeta = kThe2 * TMath::RadToDeg(); - Double_t klay1 = 0.003; // Amec carbon - Double_t klay2 = 0.002; // C Fleece carbon - Double_t klay3 = 0.007; // CFplate K13D2U carbon - Double_t klay4 = 0.007; // GluekStaveLength/2 - Double_t klay5 = 0.01; // Flex cable - Double_t kTopVertexMaxWidth = 0.072; - Double_t kTopVertexHeight = 0.04; - Double_t kSideVertexMWidth = 0.052; - Double_t kSideVertexHeight = 0.11; - - Int_t loop = (Int_t)(kStaveLength / (2 * kL1)); - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - Double_t z = 0, y = -(2 * kConeOutRadius) + klay1 + klay2 + mSensorThickness / 2 - 0.0004, x = 0; - - TGeoVolume* mechStavVol = nullptr; - - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[6] = { - kStaveWidth / 2, kStaveWidth / 2, 0.012, - -0.012, -kStaveWidth / 2, -kStaveWidth / 2}; - // Double_t yv[6] = {-2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5), - // 0-0.02,kStaveHeight+0.01,kStaveHeight+0.01,0-0.02, - // -2*(kConeOutRadius+klay1+1.5*klay2+klay3+klay4+mSensorThickness+klay5)}; - // (kConeOutRadius*2)-0.0635 - Double_t yv[6] = { - -(kConeOutRadius * 2) - 0.06395, 0 - 0.02, kStaveHeight + 0.01, - kStaveHeight + 0.01, 0 - 0.02, -(kConeOutRadius * 2) - 0.06395}; // (kConeOutRadius*2)-0.064 - mechStruct->DefinePolygon(6, xv, yv); - mechStruct->DefineSection(0, -kStaveLength, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength, 0, 0, 1.); - - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Polyimide Pipe Kapton grey-35 - auto* cone1 = new TGeoCone(kStaveLength, kConeInRadius, kConeOutRadius - 0.0001, - kConeInRadius, kConeOutRadius - 0.0001); - auto* volCone1 = new TGeoVolume("PolyimidePipe", cone1, medKapton); - volCone1->SetFillColor(35); - volCone1->SetLineColor(35); - mechStavVol->AddNode(volCone1, 1, new TGeoTranslation(x + 0.25, y, z)); - mechStavVol->AddNode(volCone1, 2, new TGeoTranslation(x - 0.25, y, z)); - } - - if (mBuildLevel < 4) { - auto* coolTubeW = new TGeoTube(0., kConeInRadius - 0.0001, kStaveLength); - auto* volCoolTubeW = new TGeoVolume("Water", coolTubeW, medWater); - volCoolTubeW->SetFillColor(4); - volCoolTubeW->SetLineColor(4); - mechStavVol->AddNode(volCoolTubeW, 0, new TGeoTranslation(x - 0.25, y, z)); - mechStavVol->AddNode(volCoolTubeW, 1, new TGeoTranslation(x + 0.25, y, z)); - } - - if (mBuildLevel < 3) { - // top fillament - // Top filament M60J black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox( - kS2 - 0.028, 0.02 / 2, - 0.02 / 2); // 0.04/2//TGeoBBox *t2=new TGeoBBox(kS2,0.01,0.02);//kS2-0.03 old Config.C - auto* volT2 = new TGeoVolume("TopFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<28;i++){ - // 1) Front Left Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 1, - new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, 90 - kBeta))); - // 2) Front Right Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 2, - new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, -90 + kBeta))); - // 3) Back Left Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 3, - new TGeoCombiTrans(x + kWidth + 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, -90 + kAlpha, 90 - kBeta))); - // 4) Back Right Top Filament - mechStavVol->AddNode( - volT2, i * 4 + 4, - new TGeoCombiTrans(x - kWidth - 0.0036, y + kHeight + 0.01, - z - kStaveLength + 0.1 + 2 * kL1 + (i * 4 * kL1) + kS1 / 2, - new TGeoRotation("volT2", 90, 90 - kAlpha, -90 + kBeta))); - } - - // Vertex structure - // top ver trd1 - auto* trd1 = new TGeoTrd1(0, kTopVertexMaxWidth / 2, kStaveLength, kTopVertexHeight / 2); - auto* ibdv = new TGeoVolume("TopVertex", trd1, medM60J3K); - ibdv->SetFillColor(12); - ibdv->SetLineColor(12); - mechStavVol->AddNode( - ibdv, 1, new TGeoCombiTrans(x, y + kStaveHeight + 0.03, z, new TGeoRotation("ibdv", 0., -90, 0))); // y+kStaveHeight+0.056 - - // left trd2 - auto* trd2 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); - auto* ibdv2 = new TGeoVolume("LeftVertex", trd2, medM60J3K); - ibdv2->SetFillColor(12); - ibdv2->SetLineColor(12); - mechStavVol->AddNode( - ibdv2, 1, - new TGeoCombiTrans( - x + kStaveWidth / 2 - 0.06, y - 0.0355, z, - new TGeoRotation("ibdv2", -103.3, 90, 0))); // x-kStaveWidth/2-0.09 old Config.C y-0.0355, - - // right trd3 - auto* trd3 = new TGeoTrd1(0, kSideVertexMWidth / 2, kStaveLength, kSideVertexHeight / 2); - auto* ibdv3 = new TGeoVolume("RightVertex", trd3, medM60J3K); - ibdv3->SetFillColor(12); - ibdv3->SetLineColor(12); - mechStavVol->AddNode( - ibdv3, 1, new TGeoCombiTrans(x - kStaveWidth / 2 + 0.06, y - 0.0355, z, new TGeoRotation("ibdv3", 103.3, 90, 0))); // x-kStaveWidth/2+0.09 old Config.C - - // Carbon Fleece - auto* cons2 = - new TGeoConeSeg(zsta, kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, - kConeOutRadius + klay1, kConeOutRadius + klay1 + klay2, 0, 180); - auto* cone12 = new TGeoVolume("CarbonFleecePipeCover", cons2, medCarbonFleece); - cone12->SetFillColor(28); - cone12->SetLineColor(28); - mechStavVol->AddNode(cone12, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); - mechStavVol->AddNode(cone12, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone12", 0, 0, 0))); - - auto* box3 = new TGeoBBox((0.50 - (2 * (kConeOutRadius + klay1))) / 2, klay2 / 2, - zsta); // kStaveLength-0.50); - auto* plate3 = new TGeoVolume("CarbonFleeceMiddle", box3, medCarbonFleece); - plate3->SetFillColor(28); - plate3->SetLineColor(28); - mechStavVol->AddNode(plate3, 1, new TGeoCombiTrans(x, y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate3", 0, 0, 0))); - - auto* box31 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, klay2 / 2, zsta); - auto* plate31 = new TGeoVolume("CarbonFleeceLeftRight", box31, medCarbonFleece); - plate31->SetFillColor(28); - plate31->SetLineColor(28); - mechStavVol->AddNode( - plate31, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + klay1 + (0.75 - 0.25 - kConeOutRadius - klay1) / 2, - y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - mechStavVol->AddNode( - plate31, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - klay1 - (0.75 - 0.25 - kConeOutRadius - klay1) / 2, - y - kConeOutRadius + klay1 + (klay2 / 2), z, new TGeoRotation("plate31", 0, 0, 0))); - - auto* box32 = new TGeoBBox((klay2 / 2), (kConeOutRadius - klay1) / 2, zsta); - auto* plate32 = new TGeoVolume("CarbonFleeceVertical", box32, medCarbonFleece); - plate32->SetFillColor(28); - plate32->SetLineColor(28); - mechStavVol->AddNode(plate32, 1, - new TGeoCombiTrans(x + 0.25 + kConeOutRadius + klay1 + (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 2, - new TGeoCombiTrans(x + 0.25 - kConeOutRadius - klay1 - (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 3, - new TGeoCombiTrans(x - 0.25 + kConeOutRadius + klay1 + (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - mechStavVol->AddNode(plate32, 4, - new TGeoCombiTrans(x - 0.25 - kConeOutRadius - klay1 - (klay2 / 2), - y + (klay1 - kConeOutRadius) / 2, z, - new TGeoRotation("plate32", 0, 0, 0))); - - // Amec Thermasol red-2 cover tube FGS300 or Carbon Paper - auto* cons1 = - new TGeoConeSeg(zsta, kConeOutRadius, kConeOutRadius + klay1 - 0.0001, kConeOutRadius, - kConeOutRadius + klay1 - 0.0001, 0, 180); // kConeOutRadius+klay1-0.0001 - auto* cone11 = new TGeoVolume("ThermasolPipeCover", cons1, medFGS003); - cone11->SetFillColor(2); - cone11->SetLineColor(2); - mechStavVol->AddNode(cone11, 1, - new TGeoCombiTrans(x + 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); - mechStavVol->AddNode(cone11, 2, - new TGeoCombiTrans(x - 0.25, y, z, new TGeoRotation("cone11", 0, 0, 0))); - - auto* box2 = - new TGeoBBox((0.50 - (2 * kConeOutRadius)) / 2, (klay1 / 2), zsta); // kStaveLength-0.50); - auto* plate2 = new TGeoVolume("ThermasolMiddle", box2, medFGS003); - plate2->SetFillColor(2); - plate2->SetLineColor(2); - mechStavVol->AddNode(plate2, 1, new TGeoCombiTrans(x, y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate2", 0, 0, 0))); - - auto* box21 = - new TGeoBBox((0.75 - 0.25 - kConeOutRadius - klay1) / 2 + 0.0025, (klay1 / 2), zsta); - auto* plate21 = new TGeoVolume("ThermasolLeftRight", box21, medFGS003); - plate21->SetFillColor(2); - plate21->SetLineColor(2); - mechStavVol->AddNode( - plate21, 1, - new TGeoCombiTrans( - x + 0.25 + kConeOutRadius + (0.75 - 0.25 - kConeOutRadius) / 2 - (klay1 / 2) + 0.0025, - y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - mechStavVol->AddNode( - plate21, 2, - new TGeoCombiTrans( - x - 0.25 - kConeOutRadius - (0.75 - 0.25 - kConeOutRadius) / 2 + (klay1 / 2) - 0.0025, - y - kConeOutRadius + (klay1 / 2), z, new TGeoRotation("plate21", 0, 0, 0))); - - auto* box22 = new TGeoBBox((klay1 / 2), kConeOutRadius / 2, zsta); - auto* plate22 = new TGeoVolume("ThermasolVertical", box22, medFGS003); - plate22->SetFillColor(2); - plate22->SetLineColor(2); - mechStavVol->AddNode(plate22, 1, new TGeoCombiTrans(x + 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 2, new TGeoCombiTrans(x + 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 3, new TGeoCombiTrans(x - 0.25 + kConeOutRadius + (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - mechStavVol->AddNode(plate22, 4, new TGeoCombiTrans(x - 0.25 - kConeOutRadius - (klay1 / 2), y - kConeOutRadius / 2, z, new TGeoRotation("plate22", 0, 0, 0))); - - // K13D2U CF plate - auto* box1 = new TGeoBBox(2 * kWidth, (klay3) / 2, zsta); - auto* plate1 = new TGeoVolume("CFPlate", box1, medK13D2U2k); - plate1->SetFillColor(5); - plate1->SetLineColor(5); - mechStavVol->AddNode(plate1, 1, new TGeoCombiTrans(x, y - (kConeOutRadius + (klay3 / 2)), z, new TGeoRotation("plate1", 0, 0, 0))); - - // C Fleece bottom plate - auto* box6 = new TGeoBBox(2 * kWidth, (klay2) / 2, zsta); - auto* plate6 = new TGeoVolume("CarbonFleeceBottom", box6, medCarbonFleece); - plate6->SetFillColor(2); - plate6->SetLineColor(2); - mechStavVol->AddNode(plate6, 1, - new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + (klay2 / 2)), z, - new TGeoRotation("plate6", 0, 0, 0))); - } - if (mBuildLevel < 2) { - // Glue klayers and kapton - auto* glue = new TGeoBBox(kStaveWidth / 2, (klay4) / 2, zsta); - auto* volGlue = new TGeoVolume("Glue", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - // mechStavVol->AddNode(volGlue, 0, new - // TGeoCombiTrans(x,y-(kConeOutRadius+klay3+klay2+(klay4/2)), z, new TGeoRotation("",0, 0, 0))); - mechStavVol->AddNode( - volGlue, 0, - new TGeoCombiTrans(x, y - (kConeOutRadius + klay3 + klay2 + (klay4) / 2) + 0.00005, z, - new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - // Flex Cable or Bus - auto* kapCable = new TGeoBBox(kStaveWidth / 2, klay5 / 2, zsta); // klay5/2 - auto* volCable = new TGeoVolume("FlexCable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - // mechStavVol->AddNode(volCable, 0, new TGeoCombiTrans(x, - // y-(kConeOutRadius+klay3+klay2+klay4+mSensorThickness+(klay5)/2)+0.0002, z, new - // TGeoRotation("",0, - // 0, 0))); - mechStavVol->AddNode( - volCable, 0, - new TGeoCombiTrans( - x, y - (kConeOutRadius + klay3 + klay2 + klay4 + mSensorThickness + (klay5) / 2) + 0.01185, - z, new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structe - return mechStavVol; -} - -// model3 -TGeoVolume* V1Layer::createStaveModelInnerB3(const Double_t xsta, const Double_t zsta, - const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - - TGeoMedium* medM60J3K = mgr->GetMedium("IT4_M60J3K$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medFlexCable = mgr->GetMedium("IT4_FLEXCABLE$"); - // TGeoMedium *medK13D2U2k = mgr->GetMedium("IT4_K13D2U2k$"); - // TGeoMedium *medFGS003 = mgr->GetMedium("IT4_FGS003$"); - // TGeoMedium *medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - - // Local parameters - Double_t kConeOutRadius = 0.15 / 2; - Double_t kStaveLength = zsta * 2; - Double_t kStaveWidth = xsta * 2; - Double_t w = kStaveWidth / 4; // 1/2 of W - Double_t staveHeight = 0.3; - Double_t h = staveHeight / 2; - Double_t alpha = 90 - 33.; // 90-30; - Double_t the1 = alpha * TMath::DegToRad(); - Double_t s1 = w / TMath::Sin(the1); - Double_t l = w / TMath::Tan(the1); - Double_t s2 = TMath::Sqrt(h * h + s1 * s1); // TMath::Sin(the2); - Double_t the2 = TMath::ATan(h / s1); - Double_t beta = the2 * TMath::RadToDeg(); - Double_t klay4 = 0.007; // Glue - Double_t klay5 = 0.01; // Flexcable - Int_t loop = (Int_t)((kStaveLength / (2 * l)) / 2); - Double_t hh = 0.01; - Double_t ang1 = 0 * TMath::DegToRad(); - Double_t ang2 = 0 * TMath::DegToRad(); - Double_t ang3 = 0 * TMath::DegToRad(); - Int_t chips = 4; - Double_t headWidth = 0.25; - Double_t smcLength = kStaveLength / chips - 2 * headWidth; // 6.25; - Double_t smcWidth = kStaveWidth; - Double_t smcSide1Thick = 0.03; - Double_t vaporThick = 0.032; - Double_t liquidThick = 0.028; - Double_t smcSide2Thick = 0.01; - Double_t smcSide3Thick = 0.0055; - Double_t smcSide4Thick = 0.0095; - Double_t smcSide5Thick = 0.0075; - Double_t smcSpace = 0.01; - - char volumeName[30]; - snprintf(volumeName, 30, "%s%d_StaveStruct", o2::its4::GeometryTGeo::getITSStavePattern(), - mLayerNumber); - - // detailed structure ++++++++++++++ - Double_t z = 0, y = 0 - 0.007, x = 0; - - // Polimide micro channels numbers - Double_t yMC = y - h + 0.01; - Int_t nb = (Int_t)(kStaveWidth / 0.1) + 1; - Double_t xstaMC = (nb * 0.1 - 0.08) / 2; - - TGeoVolume* mechStavVol = nullptr; - if (mBuildLevel < 5) { - // world (trapezoid) - auto* mechStruct = new TGeoXtru(2); // z sections - Double_t xv[5] = { - kStaveWidth / 2 + 0.1, kStaveWidth / 2 + 0.1, 0, -kStaveWidth / 2 - 0.1, - -kStaveWidth / 2 - 0.1}; - Double_t yv[5] = {-kConeOutRadius * 2 - 0.07, 0, staveHeight, 0, -kConeOutRadius * 2 - 0.07}; - mechStruct->DefinePolygon(5, xv, yv); - mechStruct->DefineSection(0, -kStaveLength - 0.1, 0, 0, 1.); - mechStruct->DefineSection(1, kStaveLength + 0.1, 0, 0, 1.); - mechStavVol = new TGeoVolume(volumeName, mechStruct, medAir); - mechStavVol->SetLineColor(12); - mechStavVol->SetFillColor(12); - mechStavVol->SetVisibility(kTRUE); - - // Silicon micro channels numbers - - auto* tM0a = new TGeoBBox(smcWidth / 2, 0.003 / 2, headWidth / 2); - auto* volTM0a = new TGeoVolume("microChanTop1", tM0a, medKapton); - volTM0a->SetLineColor(35); - volTM0a->SetFillColor(35); - - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0a, 0, - new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), - new TGeoRotation("", ang1, ang2, ang3))); - mechStavVol->AddNode( - volTM0a, 1, - new TGeoCombiTrans(x, yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), - new TGeoRotation("", ang1, ang2, ang3))); - } - auto* tM0c = new TGeoBBox(0.3 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c = new TGeoVolume("microChanTop2", tM0c, medKapton); - volTM0c->SetLineColor(35); - volTM0c->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c, 0, new TGeoCombiTrans(x + (smcWidth / 2) - (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); - mechStavVol->AddNode( - volTM0c, 1, new TGeoCombiTrans(x - (smcWidth / 2) + (0.3 / 2), yMC + 0.03, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c1 = new TGeoBBox(0.2225 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c1 = new TGeoVolume("microChanBot1", tM0c1, medKapton); - volTM0c1->SetLineColor(6); - volTM0c1->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c1, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick) - (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0c1, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + (0.2225 / 2), yMC + 0.03 - hh - (0.003), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c2 = new TGeoBBox(0.072 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c2 = new TGeoVolume("microChanBot2", tM0c2, medKapton); - volTM0c2->SetLineColor(35); - volTM0c2->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (0.072 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0c2r = new TGeoBBox(0.068 / 2, 0.003 / 2, smcLength / 2); - auto* volTM0c2r = new TGeoVolume("microChanBot3", tM0c2r, medKapton); - volTM0c2r->SetLineColor(35); - volTM0c2r->SetFillColor(35); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0c2r, 0, new TGeoCombiTrans(x - smcWidth / 2 + (0.068 / 2), yMC + 0.03 - (0.035 + 0.0015) - (0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d = new TGeoBBox(smcSide1Thick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0d = new TGeoVolume("microChanSide1", tM0d, medKapton); - volTM0d->SetLineColor(12); - volTM0d->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0d, 1, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - - auto* tM0d1 = new TGeoBBox(smcSide2Thick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0d1 = new TGeoVolume("microChanSide2", tM0d1, medKapton); - volTM0d1->SetLineColor(12); - volTM0d1->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d1, 0, - new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick / 2), - yMC + 0.03 - (0.003 + 0.035) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0d1, 1, - new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick / 2), - yMC + 0.03 - (0.003 + 0.035) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d2 = new TGeoBBox(smcSide3Thick / 2, (hh + 0.003) / 2, smcLength / 2); - auto* volTM0d2 = new TGeoVolume("microChanSide3", tM0d2, medKapton); - volTM0d2->SetLineColor(12); - volTM0d2->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d2, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick / 2), yMC + 0.03 - (0.003 + hh + 0.003) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0d2r = new TGeoBBox(smcSide4Thick / 2, (hh + 0.003) / 2, smcLength / 2); - auto* volTM0d2r = new TGeoVolume("microChanSide4", tM0d2r, medKapton); - volTM0d2r->SetLineColor(12); - volTM0d2r->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0d2r, 0, - new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + - (smcSide4Thick / 2), - yMC + 0.03 - (0.003 + hh + 0.003) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0e = new TGeoBBox(smcSide5Thick / 2, hh / 2, smcLength / 2); - auto* volTM0e = new TGeoVolume("microChanSide5", tM0e, medKapton); - volTM0e->SetLineColor(12); - volTM0e->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - for (Int_t ie = 0; ie < 11; ie++) { - mechStavVol->AddNode( - volTM0e, 0, - new TGeoCombiTrans(x - (ie * (smcSpace + smcSide5Thick)) + smcWidth / 2 - - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace - (smcSide5Thick / 2), - yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0e, 1, - new TGeoCombiTrans(x + (ie * (smcSpace + smcSide5Thick)) - smcWidth / 2 + - (smcSide1Thick) + (liquidThick) + (smcSide2Thick) + (smcSide4Thick) + - smcSpace + (smcSide5Thick / 2), - yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - } - - auto* tM0f = new TGeoBBox(0.02 / 2, hh / 2, smcLength / 2); - auto* volTM0f = new TGeoVolume("microChanTop3", tM0f, medKapton); - // Double_t smcChannels=12; - Double_t smcCloseWallvapor = smcWidth / 2 - smcSide1Thick - vaporThick - smcSide2Thick - - smcSide3Thick - 12 * smcSpace - 11 * smcSide5Thick; - Double_t smcCloseWallliquid = smcWidth / 2 - smcSide1Thick - liquidThick - smcSide2Thick - - smcSide4Thick - 12 * smcSpace - 11 * smcSide5Thick; - volTM0f->SetLineColor(12); - volTM0f->SetFillColor(12); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0f, 0, - new TGeoCombiTrans(x + smcCloseWallvapor - (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0f, 1, - new TGeoCombiTrans(x - smcCloseWallliquid + (0.02) / 2, yMC + 0.03 - (0.003 + hh) / 2, - z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, - new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - // Head(back) microchannel - - auto* tM0hb = new TGeoBBox(smcWidth / 2, 0.025 / 2, headWidth / 2); - auto* volTM0hb = new TGeoVolume("microChanHeadBackBottom1", tM0hb, medKapton); - volTM0hb->SetLineColor(4); - volTM0hb->SetFillColor(4); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0hb, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0hb, 1, new TGeoCombiTrans(x, yMC + 0.03 - 0.0145 - (0.025) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (headWidth / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.05 / 2); - auto* volTM0h1 = new TGeoVolume("microChanHeadBackBottom2", tM0h1, medKapton); - volTM0h1->SetLineColor(5); - volTM0h1->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - headWidth + (0.05 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.18 / 2); - auto* volTM0h2 = new TGeoVolume("microChanHeadBackBottom7", tM0h2, medKapton); - volTM0h2->SetLineColor(6); - volTM0h2->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - 0.02 - (0.18 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0h3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); - auto* volTM0h3 = new TGeoVolume("microChanHeadBackBottom3", tM0h3, medKapton); - volTM0h3->SetLineColor(5); - volTM0h3->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0h3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth - smcLength / 2 - (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b1 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.03 / 2); - auto* volTM0b1 = new TGeoVolume("microChanHeadBackBottom4", tM0b1, medKapton); - volTM0b1->SetLineColor(5); - volTM0b1->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b1, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + headWidth - (0.03 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b2 = new TGeoBBox(smcWidth / 2, 0.003 / 2, 0.2 / 2); - auto* volTM0b2 = new TGeoVolume("microChanHeadBackBottom5", tM0b2, medKapton); - volTM0b2->SetLineColor(6); - volTM0b2->SetFillColor(6); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b2, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - 0.01 - (0.003 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + 0.02 + (0.2 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0b3 = new TGeoBBox(smcWidth / 2, 0.013 / 2, 0.02 / 2); - auto* volTM0b3 = new TGeoVolume("microChanHeadBackBottom6", tM0b3, medKapton); - volTM0b3->SetLineColor(5); - volTM0b3->SetFillColor(5); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0b3, 0, new TGeoCombiTrans(x, yMC + 0.03 - 0.0015 - (0.013 / 2), z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth + smcLength / 2 + (0.02 / 2), new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - - auto* tM0b = new TGeoBBox(0.02 / 2, 0.02 / 2, zsta); - auto* volTM0b = new TGeoVolume("microChanWalls", tM0b, medKapton); - volTM0b->SetLineColor(35); - volTM0b->SetFillColor(35); - for (Int_t ib = 0; ib < nb; ib++) { - // mechStavVol->AddNode(volTM0b, ib, new TGeoCombiTrans(x+ib*0.1-xstaMC+0.01,yMC, z, new - // TGeoRotation("",0, 0, 0))); - } - } - - if (mBuildLevel < 4) { - // cooling inlet outlet - auto* tM0dv = new TGeoBBox(vaporThick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0dv = new TGeoVolume("microChanVapor", tM0dv, medWater); - volTM0dv->SetLineColor(2); - volTM0dv->SetFillColor(2); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0dv, 0, new TGeoCombiTrans(x + smcWidth / 2 - (smcSide1Thick) - (vaporThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - auto* tM0dl = new TGeoBBox(liquidThick / 2, 0.035 / 2, smcLength / 2); - auto* volTM0dl = new TGeoVolume("microChanLiquid", tM0dl, medWater); - volTM0dl->SetLineColor(3); - volTM0dl->SetFillColor(3); - for (Int_t mo = 1; mo <= chips; mo++) { - mechStavVol->AddNode( - volTM0dl, 0, new TGeoCombiTrans(x - smcWidth / 2 + (smcSide1Thick) + (liquidThick / 2), yMC + 0.03 - 0.0015 - (0.035) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - // small cooling fluid now using water wait for freeon value - auto* tM0dlq = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); - auto* volTM0dlq = new TGeoVolume("smallLiquid", tM0dlq, medWater); - volTM0dlq->SetLineColor(3); - volTM0dlq->SetFillColor(3); - auto* tM0dvp = new TGeoBBox(smcSpace / 2, hh / 2, smcLength / 2); - auto* volTM0dvp = new TGeoVolume("microChanVapor", tM0dvp, medWater); - volTM0dvp->SetLineColor(2); - volTM0dvp->SetFillColor(2); - for (Int_t mo = 1; mo <= chips; mo++) { - for (Int_t is = 0; is < 12; is++) { - mechStavVol->AddNode( - volTM0dlq, 0, new TGeoCombiTrans(x + (is * (smcSpace + smcSide5Thick)) - smcWidth / 2 + (smcSide1Thick) + (vaporThick) + (smcSide2Thick) + (smcSide3Thick) + smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - mechStavVol->AddNode( - volTM0dvp, 1, new TGeoCombiTrans(x - (is * (smcSpace + smcSide5Thick)) + smcWidth / 2 - (smcSide1Thick) - (vaporThick) - (smcSide2Thick) - (smcSide3Thick)-smcSpace / 2, yMC + 0.03 - (0.003 + hh) / 2, z + (mo - 3) * kStaveLength / 4 + smcLength / 2 + headWidth, new TGeoRotation("", ang1, ang2, ang3))); //("",0, 0, 0))); - } - } - } - - if (mBuildLevel < 3) { - // Bottom filament CFRP black-12 Carbon structure TGeoBBox (thickness,width,length) - Double_t filWidth = 0.04; - Double_t filHeight = 0.02; - auto* t1 = new TGeoBBox(filHeight / 2, filWidth / 2, s1); - auto* volT1 = new TGeoVolume("bottomFilament", t1, medM60J3K); - volT1->SetLineColor(12); - volT1->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode(volT1, 4 * i + 0, - new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * l * i) + s1 / 2, - new TGeoRotation("volT1", -90, alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 1, - new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (4 * l * i) + s1 / 2, - new TGeoRotation("volT1", 90, alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 2, - new TGeoCombiTrans(x + w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT1", -90, -alpha, 0))); - mechStavVol->AddNode(volT1, 4 * i + 3, - new TGeoCombiTrans(x - w, y - h + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT1", -90, +alpha, 0))); - } - - // Top filament CERP black-12 Carbon structure TGeoBBox (length,thickness,width) - auto* t2 = new TGeoBBox(s2, filHeight / 2, filWidth / 2); - auto* volT2 = new TGeoVolume("topFilament", t2, medM60J3K); - volT2->SetLineColor(12); - volT2->SetFillColor(12); - for (int i = 0; i < loop; i++) { // i<30;i++){ - mechStavVol->AddNode( - volT2, 4 * i + 0, new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, new TGeoRotation("volT2", 90, 90 - alpha, 90 - beta))); - mechStavVol->AddNode( - volT2, 4 * i + 1, - new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, -90 + alpha, -90 + beta))); - mechStavVol->AddNode( - volT2, 4 * i + 2, - new TGeoCombiTrans(x + w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, -90 + alpha, 90 - beta))); - mechStavVol->AddNode( - volT2, 4 * i + 3, - new TGeoCombiTrans(x - w, y + 0.04 + filHeight / 2, - z - kStaveLength / 2 + 2 * l + (i * 4 * l) + s1 / 2, - new TGeoRotation("volT2", 90, 90 - alpha, -90 + beta))); - } - } - - if (mBuildLevel < 2) { - // Glue Filament and Silicon MicroChannel - auto* tM0 = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); - auto* volTM0 = new TGeoVolume("glueFM", tM0, medGlue); - volTM0->SetLineColor(5); - volTM0->SetFillColor(5); - mechStavVol->AddNode(volTM0, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volTM0, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, 0.03 + yMC, z, new TGeoRotation("", 0, 0, 0))); - - // Glue microchannel and sensor - auto* glueM = new TGeoBBox(xstaMC / 5, klay4 / 2, zsta); - auto* volGlueM = new TGeoVolume("glueMS", glueM, medGlue); - volGlueM->SetLineColor(5); - volGlueM->SetFillColor(5); - mechStavVol->AddNode(volGlueM, 0, new TGeoCombiTrans(x - xsta / 2 - 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); - mechStavVol->AddNode(volGlueM, 1, new TGeoCombiTrans(x + xsta / 2 + 0.25, yMC - 0.01, z, new TGeoRotation("", 0, 0, 0))); - - // Glue sensor and kapton - auto* glue = new TGeoBBox(xsta, klay4 / 2, zsta); - auto* volGlue = new TGeoVolume("glueSensorBus", glue, medGlue); - volGlue->SetLineColor(5); - volGlue->SetFillColor(5); - mechStavVol->AddNode(volGlue, 1, new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 / 2, z, new TGeoRotation("", 0, 0, 0))); - } - - if (mBuildLevel < 1) { - auto* kapCable = new TGeoBBox(xsta, klay5 / 2, zsta); - auto* volCable = new TGeoVolume("Flexcable", kapCable, medFlexCable); - volCable->SetLineColor(28); - volCable->SetFillColor(28); - mechStavVol->AddNode(volCable, 0, - new TGeoCombiTrans(x, y - 0.154 - mSensorThickness - klay4 - klay5 / 2, z, - new TGeoRotation("", 0, 0, 0))); - } - // Done, return the stave structure - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveOuterB(const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kOBModelDummy: - mechStavVol = createStaveModelOuterBDummy(mgr); - break; - case Detector::kOBModel0: - mechStavVol = createStaveModelOuterB0(mgr); - break; - case Detector::kOBModel1: - mechStavVol = createStaveModelOuterB1(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - return mechStavVol; -} - -TGeoVolume* V1Layer::createStaveModelOuterBDummy(const TGeoManager*) const -{ - // Done, return the stave structure - return nullptr; -} - -TGeoVolume* V1Layer::createStaveModelOuterB0(const TGeoManager* mgr) -{ - Double_t xmod, ymod, zmod; - Double_t xlen, ylen, zlen; - Double_t ypos, zpos; - char volumeName[30]; - - // First create all needed shapes - // The chip - xlen = sOBHalfStaveWidth; - ylen = 0.5 * mStaveThickness; // TO BE CHECKED - zlen = sOBModuleZLength / 2; - - TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); - - xmod = ((TGeoBBox*)chipVol->GetShape())->GetDX(); - ymod = ((TGeoBBox*)chipVol->GetShape())->GetDY(); - zmod = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - - auto* module = new TGeoBBox(xmod, ymod, zmod); - - zlen = sOBModuleZLength * mNumberOfModules; - auto* hstave = new TGeoBBox(xlen, ylen, zlen / 2); - - // We have all shapes: now create the real volumes - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - modVol->SetVisibility(kTRUE); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* hstaveVol = new TGeoVolume(volumeName, hstave, medAir); - - // Finally build it up - modVol->AddNode(chipVol, 0); - mHierarchy[kChip] = 1; - - for (Int_t j = 0; j < mNumberOfModules; j++) { - ypos = 0.021; // Remove small overlap - M.S: 21may13 - zpos = -hstave->GetDZ() + j * 2 * zmod + zmod; - hstaveVol->AddNode(modVol, j, new TGeoTranslation(0, ypos, zpos)); - mHierarchy[kModule]++; - } - // Done, return the stave structure - return hstaveVol; -} - -TGeoVolume* V1Layer::createStaveModelOuterB1(const TGeoManager* mgr) -{ - Double_t yFlex1 = sOBFlexCableAlThick; - Double_t yFlex2 = sOBFlexCableKapThick; - Double_t flexOverlap = 5; // to be checked - Double_t xHalmSt = sOBHalfStaveWidth / 2; - Double_t rCoolMin = sOBCoolTubeInnerD / 2; - Double_t rCoolMax = rCoolMin + sOBCoolTubeThick; - Double_t kLay1 = 0.004; // to be checked - Double_t kLay2 = sOBGraphiteFoilThick; - - Double_t xlen, ylen; - Double_t ymod, zmod; - Double_t xtru[12], ytru[12]; - Double_t xpos, ypos, ypos1, zpos /*, zpos5cm*/; - Double_t zlen; - char volumeName[30]; - - zlen = (mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap) / 2; - - // First create all needed shapes - TGeoVolume* moduleVol = createModuleOuterB(); - moduleVol->SetVisibility(kTRUE); - ymod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDY(); - zmod = ((TGeoBBox*)(moduleVol->GetShape()))->GetDZ(); - - auto* busAl = new TGeoBBox("BusAl", xHalmSt, sOBBusCableAlThick / 2, zlen); - auto* busKap = new TGeoBBox("BusKap", xHalmSt, sOBBusCableKapThick / 2, zlen); - - auto* coldPlate = - new TGeoBBox("ColdPlate", sOBHalfStaveWidth / 2, sOBColdPlateThick / 2, zlen); - - auto* coolTube = new TGeoTube("CoolingTube", rCoolMin, rCoolMax, zlen); - auto* coolWater = new TGeoTube("CoolingWater", 0., rCoolMin, zlen); - - xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax(); - auto* graphlat = new TGeoBBox("GraphLateral", xlen / 2, kLay2 / 2, zlen); - - xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax(); - auto* graphmid = new TGeoBBox("GraphMiddle", xlen, kLay2 / 2, zlen); - - ylen = coolTube->GetRmax() - kLay2; - auto* graphvert = new TGeoBBox("GraphVertical", kLay2 / 2, ylen / 2, zlen); - - auto* graphtub = - new TGeoTubeSeg("GraphTube", rCoolMax, rCoolMax + kLay2, zlen, 180., 360.); - - xlen = xHalmSt - sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; - auto* fleeclat = new TGeoBBox("FleecLateral", xlen / 2, kLay1 / 2, zlen); - - xlen = sOBCoolTubeXDist / 2 - coolTube->GetRmax() - kLay2; - auto* fleecmid = new TGeoBBox("FleecMiddle", xlen, kLay1 / 2, zlen); - - ylen = coolTube->GetRmax() - kLay2 - kLay1; - auto* fleecvert = new TGeoBBox("FleecVertical", kLay1 / 2, ylen / 2, zlen); - - auto* fleectub = - new TGeoTubeSeg("FleecTube", rCoolMax + kLay2, rCoolMax + kLay1 + kLay2, zlen, 180., 360.); - - auto* flex1_5cm = new TGeoBBox("Flex1MV_5cm", xHalmSt, yFlex1 / 2, flexOverlap / 2); - auto* flex2_5cm = new TGeoBBox("Flex2MV_5cm", xHalmSt, yFlex2 / 2, flexOverlap / 2); - - // The half stave container (an XTru to avoid overlaps between neightbours) - xtru[0] = xHalmSt; - ytru[0] = 0; - xtru[1] = xtru[0]; - ytru[1] = -2 * (ymod + busAl->GetDY() + busKap->GetDY() + coldPlate->GetDY() + graphlat->GetDY() + - fleeclat->GetDY()); - xtru[2] = sOBCoolTubeXDist / 2 + fleectub->GetRmax(); - ytru[2] = ytru[1]; - xtru[3] = xtru[2]; - ytru[3] = ytru[2] - (coolTube->GetRmax() + fleectub->GetRmax()); - xtru[4] = sOBCoolTubeXDist / 2 - fleectub->GetRmax(); - ytru[4] = ytru[3]; - xtru[5] = xtru[4]; - ytru[5] = ytru[2]; - for (Int_t i = 0; i < 6; i++) { - xtru[6 + i] = -xtru[5 - i]; - ytru[6 + i] = ytru[5 - i]; - } - auto* halmStave = new TGeoXtru(2); - halmStave->DefinePolygon(12, xtru, ytru); - halmStave->DefineSection(0, -mZLength / 2); - halmStave->DefineSection(1, mZLength / 2); - - // We have all shapes: now create the real volumes - - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); - TGeoMedium* medCarbon = mgr->GetMedium("IT4_CARBON$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - TGeoMedium* medWater = mgr->GetMedium("IT4_WATER$"); - TGeoMedium* medCarbonFleece = mgr->GetMedium("IT4_CarbonFleece$"); - TGeoMedium* medFGS003 = mgr->GetMedium("IT4_FGS003$"); // amec thermasol - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - auto* busAlVol = new TGeoVolume("BusAlVol", busAl, medAluminum); - busAlVol->SetLineColor(kCyan); - busAlVol->SetFillColor(busAlVol->GetLineColor()); - busAlVol->SetFillStyle(4000); // 0% transparent - - auto* busKapVol = new TGeoVolume("BusKapVol", busKap, medKapton); - busKapVol->SetLineColor(kBlue); - busKapVol->SetFillColor(busKapVol->GetLineColor()); - busKapVol->SetFillStyle(4000); // 0% transparent - - auto* coldPlateVol = new TGeoVolume("ColdPlateVol", coldPlate, medCarbon); - coldPlateVol->SetLineColor(kYellow - 3); - coldPlateVol->SetFillColor(coldPlateVol->GetLineColor()); - coldPlateVol->SetFillStyle(4000); // 0% transparent - - auto* coolTubeVol = new TGeoVolume("CoolingTubeVol", coolTube, medKapton); - coolTubeVol->SetLineColor(kGray); - coolTubeVol->SetFillColor(coolTubeVol->GetLineColor()); - coolTubeVol->SetFillStyle(4000); // 0% transparent - - auto* coolWaterVol = new TGeoVolume("CoolingWaterVol", coolWater, medWater); - coolWaterVol->SetLineColor(kBlue); - coolWaterVol->SetFillColor(coolWaterVol->GetLineColor()); - coolWaterVol->SetFillStyle(4000); // 0% transparent - - auto* graphlatVol = new TGeoVolume("GraphiteFoilLateral", graphlat, medFGS003); - graphlatVol->SetLineColor(kGreen); - graphlatVol->SetFillColor(graphlatVol->GetLineColor()); - graphlatVol->SetFillStyle(4000); // 0% transparent - - auto* graphmidVol = new TGeoVolume("GraphiteFoilMiddle", graphmid, medFGS003); - graphmidVol->SetLineColor(kGreen); - graphmidVol->SetFillColor(graphmidVol->GetLineColor()); - graphmidVol->SetFillStyle(4000); // 0% transparent - - auto* graphvertVol = new TGeoVolume("GraphiteFoilVertical", graphvert, medFGS003); - graphvertVol->SetLineColor(kGreen); - graphvertVol->SetFillColor(graphvertVol->GetLineColor()); - graphvertVol->SetFillStyle(4000); // 0% transparent - - auto* graphtubVol = new TGeoVolume("GraphiteFoilPipeCover", graphtub, medFGS003); - graphtubVol->SetLineColor(kGreen); - graphtubVol->SetFillColor(graphtubVol->GetLineColor()); - graphtubVol->SetFillStyle(4000); // 0% transparent - - auto* fleeclatVol = new TGeoVolume("CarbonFleeceLateral", fleeclat, medCarbonFleece); - fleeclatVol->SetLineColor(kViolet); - fleeclatVol->SetFillColor(fleeclatVol->GetLineColor()); - fleeclatVol->SetFillStyle(4000); // 0% transparent - - auto* fleecmidVol = new TGeoVolume("CarbonFleeceMiddle", fleecmid, medCarbonFleece); - fleecmidVol->SetLineColor(kViolet); - fleecmidVol->SetFillColor(fleecmidVol->GetLineColor()); - fleecmidVol->SetFillStyle(4000); // 0% transparent - - auto* fleecvertVol = new TGeoVolume("CarbonFleeceVertical", fleecvert, medCarbonFleece); - fleecvertVol->SetLineColor(kViolet); - fleecvertVol->SetFillColor(fleecvertVol->GetLineColor()); - fleecvertVol->SetFillStyle(4000); // 0% transparent - - auto* fleectubVol = new TGeoVolume("CarbonFleecePipeCover", fleectub, medCarbonFleece); - fleectubVol->SetLineColor(kViolet); - fleectubVol->SetFillColor(fleectubVol->GetLineColor()); - fleectubVol->SetFillStyle(4000); // 0% transparent - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - auto* halmStaveVol = new TGeoVolume(volumeName, halmStave, medAir); - // halmStaveVol->SetLineColor(12); - // halmStaveVol->SetFillColor(12); - // halmStaveVol->SetVisibility(kTRUE); - - auto* flex1_5cmVol = new TGeoVolume("Flex1Vol5cm", flex1_5cm, medAluminum); - auto* flex2_5cmVol = new TGeoVolume("Flex2Vol5cm", flex2_5cm, medKapton); - - flex1_5cmVol->SetLineColor(kRed); - flex2_5cmVol->SetLineColor(kGreen); - - // Now build up the half stave - ypos = -busKap->GetDY(); - halmStaveVol->AddNode(busKapVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos -= (busKap->GetDY() + busAl->GetDY()); - halmStaveVol->AddNode(busAlVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos -= (busAl->GetDY() + ymod); - for (Int_t j = 0; j < mNumberOfModules; j++) { - zpos = -zlen + j * (2 * zmod + sOBModuleGap) + zmod; - halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(0, ypos, zpos)); - mHierarchy[kModule]++; - } - - ypos -= (ymod + coldPlate->GetDY()); - halmStaveVol->AddNode(coldPlateVol, 1, new TGeoTranslation(0, ypos, 0)); - - coolTubeVol->AddNode(coolWaterVol, 1, nullptr); - - xpos = sOBCoolTubeXDist / 2; - ypos1 = ypos - (coldPlate->GetDY() + coolTube->GetRmax()); - halmStaveVol->AddNode(coolTubeVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(coolTubeVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(graphtubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphtubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(fleectubVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleectubVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - xpos = xHalmSt - graphlat->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + graphlat->GetDY()); - halmStaveVol->AddNode(graphlatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphlatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(graphmidVol, 1, new TGeoTranslation(0, ypos1, 0)); - - xpos = xHalmSt - 2 * graphlat->GetDX() + graphvert->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + graphvert->GetDY()); - halmStaveVol->AddNode(graphvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - xpos = graphmid->GetDX() - graphvert->GetDX(); - halmStaveVol->AddNode(graphvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(graphvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); - - xpos = xHalmSt - fleeclat->GetDX(); - ypos1 = ypos - (coldPlate->GetDY() + 2 * graphlat->GetDY() + fleeclat->GetDY()); - halmStaveVol->AddNode(fleeclatVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleeclatVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - - halmStaveVol->AddNode(fleecmidVol, 1, new TGeoTranslation(0, ypos1, 0)); - - xpos = xHalmSt - 2 * fleeclat->GetDX() + fleecvert->GetDX(); - ypos1 = ypos - - (coldPlate->GetDY() + 2 * graphlat->GetDY() + 2 * fleeclat->GetDY() + fleecvert->GetDY()); - halmStaveVol->AddNode(fleecvertVol, 1, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleecvertVol, 2, new TGeoTranslation(xpos, ypos1, 0)); - xpos = fleecmid->GetDX() - fleecvert->GetDX(); - halmStaveVol->AddNode(fleecvertVol, 3, new TGeoTranslation(-xpos, ypos1, 0)); - halmStaveVol->AddNode(fleecvertVol, 4, new TGeoTranslation(xpos, ypos1, 0)); - - // THE FOLLOWING IS ONLY A REMINDER FOR WHAT IS STILL MISSING - - // for (Int_t j=0; j<mNumberOfChips; j++) { - - // zpos = -(zact + (mNumberOfChips-1)*modGap)/2 + j*(zMod + modGap) + zMod/2; - // zpos5cm = -(zact + (mNumberOfChips-1)*modGap)/2 + (j+1)*(zMod + modGap) + flexOverlap/2 ; - - // halmStaveVol->AddNode(moduleVol, j, new TGeoTranslation(xPos, -ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + ymod, zpos)); - // halmStaveVol->AddNode(moduleVol, mNumberOfChips+j, new TGeoTranslation(-xPos, -ylen + yPos - // + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + ymod +deltaY, zpos)); - - // if((j+1)!=mNumberOfChips){ - // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2,zpos5cm)); - // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2 + yFlex1/2 - // +deltaY,zpos5cm)); - // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2,zpos5cm)); - // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + 2*yFlex1 + 3*yFlex2/2 +deltaY,zpos5cm)); - // } - // else { - // halmStaveVol->AddNode(flex1_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex1_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1/2 +deltaY,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex2_5cmVol,j,new TGeoTranslation(xPos,-ylen + yPos + 2*rCoolMax + - // yCPlate + yGlue + yModPlate +2*ymod + yFlex1 + yFlex2/2,zpos5cm-modGap)); - // halmStaveVol->AddNode(flex2_5cmVol,mNumberOfChips+j,new TGeoTranslation(-xPos,-ylen + - // yPos + - // 2*rCoolMax + yCPlate + yGlue + yModPlate + 2*ymod + yFlex1 + yFlex2/2 +deltaY,zpos5cm-modGap)); - - // } - // } - // Done, return the half stave structure - return halmStaveVol; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterB(const TGeoManager* mgr) -{ - TGeoVolume* mechStavVol = nullptr; - - switch (mStaveModel) { - case Detector::kOBModelDummy: - case Detector::kOBModel0: - mechStavVol = createSpaceFrameOuterBDummy(mgr); - break; - case Detector::kOBModel1: - mechStavVol = createSpaceFrameOuterB1(mgr); - break; - default: - LOG(FATAL) << "Unknown stave model " << mStaveModel; - break; - } - - return mechStavVol; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterBDummy(const TGeoManager*) const -{ - // Done, return the stave structur - return nullptr; -} - -TGeoVolume* V1Layer::createSpaceFrameOuterB1(const TGeoManager* mgr) -{ - // Materials defined in Detector - TGeoMedium* medCarbon = mgr->GetMedium("IT4_CARBON$"); - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - - // Local parameters - Double_t sframeWidth = sOBSpaceFrameWidth; - Double_t sframeHeight = sOBSpaceFrameTotHigh - sOBHalfStaveYTrans; - Double_t staveBeamRadius = sOBSFrameBeamRadius; - Double_t staveLa = sOBSpaceFrameLa; - Double_t staveHa = sOBSpaceFrameHa; - Double_t staveLb = sOBSpaceFrameLb; - Double_t staveHb = sOBSpaceFrameHb; - Double_t stavel = sOBSpaceFrameL; - Double_t bottomBeamAngle = sOBSFBotBeamAngle; - Double_t triangleHeight = sframeHeight - staveBeamRadius; - Double_t halmTheta = TMath::ATan(0.5 * sframeWidth / triangleHeight); - // Double_t alpha = TMath::Pi()*3./4. - halmTheta/2.; - Double_t beta = (TMath::Pi() - 2. * halmTheta) / 4.; - // Double_t distCenterSideDown = 0.5*sframeWidth/TMath::Cos(beta); - - Double_t zlen; - Double_t xpos, ypos, zpos; - Double_t seglen; - char volumeName[30]; - - zlen = mNumberOfModules * sOBModuleZLength + (mNumberOfModules - 1) * sOBModuleGap; - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSHalfStavePattern(), mLayerNumber); - if (gGeoManager->GetVolume(volumeName)) { // Should always be so - sframeHeight -= ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDY() * 2; - zlen = ((TGeoBBox*)gGeoManager->GetVolume(volumeName)->GetShape())->GetDZ() * 2; - } - seglen = zlen / mNumberOfModules; - - // First create all needed shapes and volumes - auto* spaceFrame = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, zlen / 2); - auto* segment = new TGeoBBox(sframeWidth / 2, sframeHeight / 2, seglen / 2); - - auto* spaceFrameVol = new TGeoVolume("CarbonFrameVolume", spaceFrame, medAir); - spaceFrameVol->SetVisibility(kFALSE); - - auto* segmentVol = new TGeoVolume("segmentVol", segment, medAir); - - // SpaceFrame - - //--- the top V of the Carbon Fiber Stave (segment) - TGeoArb8* cmStavTop1 = createStaveSide("CFstavTopCornerVol1shape", seglen / 2., halmTheta, -1, - staveLa, staveHa, stavel); - auto* cmStavTopVol1 = new TGeoVolume("CFstavTopCornerVol1", cmStavTop1, medCarbon); - cmStavTopVol1->SetLineColor(35); - - TGeoArb8* cmStavTop2 = createStaveSide("CFstavTopCornerVol2shape", seglen / 2., halmTheta, 1, - staveLa, staveHa, stavel); - auto* cmStavTopVol2 = new TGeoVolume("CFstavTopCornerVol2", cmStavTop2, medCarbon); - cmStavTopVol2->SetLineColor(35); - - auto* trTop1 = new TGeoTranslation(0, sframeHeight / 2, 0); - - //--- the 2 side V - TGeoArb8* cmStavSide1 = - createStaveSide("CFstavSideCornerVol1shape", seglen / 2., beta, -1, staveLb, staveHb, stavel); - auto* cmStavSideVol1 = new TGeoVolume("CFstavSideCornerVol1", cmStavSide1, medCarbon); - cmStavSideVol1->SetLineColor(35); - - TGeoArb8* cmStavSide2 = - createStaveSide("CFstavSideCornerVol2shape", seglen / 2., beta, 1, staveLb, staveHb, stavel); - auto* cmStavSideVol2 = new TGeoVolume("CFstavSideCornerVol2", cmStavSide2, medCarbon); - cmStavSideVol2->SetLineColor(35); - - xpos = -sframeWidth / 2; - ypos = -sframeHeight / 2 + staveBeamRadius + staveHb * TMath::Sin(beta); - auto* ctSideR = new TGeoCombiTrans( - xpos, ypos, 0, new TGeoRotation("", 180 - 2 * beta * TMath::RadToDeg(), 0, 0)); - auto* ctSideL = new TGeoCombiTrans( - -xpos, ypos, 0, new TGeoRotation("", -180 + 2 * beta * TMath::RadToDeg(), 0, 0)); - - segmentVol->AddNode(cmStavTopVol1, 1, trTop1); - segmentVol->AddNode(cmStavTopVol2, 1, trTop1); - segmentVol->AddNode(cmStavSideVol1, 1, ctSideR); - segmentVol->AddNode(cmStavSideVol1, 2, ctSideL); - segmentVol->AddNode(cmStavSideVol2, 1, ctSideR); - segmentVol->AddNode(cmStavSideVol2, 2, ctSideL); - - //--- The beams - // Beams on the sides - Double_t beamPhiPrime = TMath::ASin( - 1. / TMath::Sqrt((1 + TMath::Sin(2 * beta) * TMath::Sin(2 * beta) / - (tanD(sOBSFrameBeamSidePhi) * tanD(sOBSFrameBeamSidePhi))))); - Double_t beamLength = TMath::Sqrt(sframeHeight * sframeHeight / - (TMath::Sin(beamPhiPrime) * TMath::Sin(beamPhiPrime)) + - sframeWidth * sframeWidth / 4.) - - staveLa / 2 - staveLb / 2; - auto* sideBeam = new TGeoTubeSeg(0, staveBeamRadius, beamLength / 2, 0, 180); - auto* sideBeamVol = new TGeoVolume("CFstavSideBeamVol", sideBeam, medCarbon); - sideBeamVol->SetLineColor(35); - - auto* beamRot1 = new TGeoRotation("", /*90-2*beta*/ halmTheta * TMath::RadToDeg(), - -beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot2 = - new TGeoRotation("", 90 - 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot3 = - new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), beamPhiPrime * TMath::RadToDeg(), -90); - auto* beamRot4 = new TGeoRotation("", 90 + 2. * beta * TMath::RadToDeg(), - -beamPhiPrime * TMath::RadToDeg(), -90); - - TGeoCombiTrans* beamTransf[8]; - xpos = 0.49 * triangleHeight * TMath::Tan(halmTheta); // was 0.5, fix small overlap - ypos = staveBeamRadius / 2; - zpos = seglen / 8; - beamTransf[0] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); - - beamTransf[1] = new TGeoCombiTrans(xpos, ypos, -3 * zpos, beamRot1); - addTranslationToCombiTrans(beamTransf[1], 0, 0, seglen / 2); - - beamTransf[2] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); - - beamTransf[3] = new TGeoCombiTrans(xpos, ypos, -zpos, beamRot2); - addTranslationToCombiTrans(beamTransf[3], 0, 0, seglen / 2); - - beamTransf[4] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); - - beamTransf[5] = new TGeoCombiTrans(-xpos, ypos, -3 * zpos, beamRot3); - addTranslationToCombiTrans(beamTransf[5], 0, 0, seglen / 2); - - beamTransf[6] = new TGeoCombiTrans(-xpos, ypos, -zpos, beamRot4); - beamTransf[7] = new TGeoCombiTrans(-xpos, ypos, 3 * zpos, beamRot4); - - //--- Beams of the bottom - auto* bottomBeam1 = - new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 180); - auto* bottomBeam1Vol = new TGeoVolume("CFstavBottomBeam1Vol", bottomBeam1, medCarbon); - bottomBeam1Vol->SetLineColor(35); - - auto* bottomBeam2 = - new TGeoTubeSeg(0, staveBeamRadius, sframeWidth / 2. - staveLb / 3, 0, 90); - auto* bottomBeam2Vol = new TGeoVolume("CFstavBottomBeam2Vol", bottomBeam2, medCarbon); - bottomBeam2Vol->SetLineColor(35); - - auto* bottomBeam3 = new TGeoTubeSeg( - 0, staveBeamRadius, 0.5 * sframeWidth / sinD(bottomBeamAngle) - staveLb / 3, 0, 180); - auto* bottomBeam3Vol = new TGeoVolume("CFstavBottomBeam3Vol", bottomBeam3, medCarbon); - bottomBeam3Vol->SetLineColor(35); - - auto* bottomBeamRot1 = new TGeoRotation("", 90, 90, 90); - auto* bottomBeamRot2 = new TGeoRotation("", -90, 90, -90); - - auto* bottomBeamTransf1 = - new TGeoCombiTrans("", 0, -(sframeHeight / 2 - staveBeamRadius), 0, bottomBeamRot1); - auto* bottomBeamTransf2 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 2, bottomBeamRot1); - auto* bottomBeamTransf3 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 2, bottomBeamRot2); - // be careful for beams #3: when "reading" from -z to +z and - // from the bottom of the stave, it should draw a Lambda, and not a V - auto* bottomBeamRot4 = new TGeoRotation("", -90, bottomBeamAngle, -90); - auto* bottomBeamRot5 = new TGeoRotation("", -90, -bottomBeamAngle, -90); - - auto* bottomBeamTransf4 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), -seglen / 4, bottomBeamRot4); - auto* bottomBeamTransf5 = - new TGeoCombiTrans(0, -(sframeHeight / 2 - staveBeamRadius), seglen / 4, bottomBeamRot5); - - segmentVol->AddNode(sideBeamVol, 1, beamTransf[0]); - segmentVol->AddNode(sideBeamVol, 2, beamTransf[1]); - segmentVol->AddNode(sideBeamVol, 3, beamTransf[2]); - segmentVol->AddNode(sideBeamVol, 4, beamTransf[3]); - segmentVol->AddNode(sideBeamVol, 5, beamTransf[4]); - segmentVol->AddNode(sideBeamVol, 6, beamTransf[5]); - segmentVol->AddNode(sideBeamVol, 7, beamTransf[6]); - segmentVol->AddNode(sideBeamVol, 8, beamTransf[7]); - segmentVol->AddNode(bottomBeam1Vol, 1, bottomBeamTransf1); - segmentVol->AddNode(bottomBeam2Vol, 1, bottomBeamTransf2); - segmentVol->AddNode(bottomBeam2Vol, 2, bottomBeamTransf3); - segmentVol->AddNode(bottomBeam3Vol, 1, bottomBeamTransf4); - segmentVol->AddNode(bottomBeam3Vol, 2, bottomBeamTransf5); - - // Then build up the space frame - for (Int_t i = 0; i < mNumberOfModules; i++) { - zpos = -spaceFrame->GetDZ() + (1 + 2 * i) * segment->GetDZ(); - spaceFrameVol->AddNode(segmentVol, i, new TGeoTranslation(0, 0, zpos)); - } - - // Done, return the space frame structure - return spaceFrameVol; -} - -TGeoVolume* V1Layer::createChipInnerB(const Double_t xchip, const Double_t ychip, - const Double_t zchip, const TGeoManager* mgr) -{ - char volumeName[30]; - Double_t xlen, ylen, zlen; - Double_t xpos, ypos, zpos; - - // First create all needed shapes - - // The chip - auto* chip = new TGeoBBox(xchip, ychip, zchip); - - // The sensor - xlen = chip->GetDX(); - ylen = 0.5 * mSensorThickness; - zlen = chip->GetDZ(); - auto* sensor = new TGeoBBox(xlen, ylen, zlen); - - // We have all shapes: now create the real volumes - TGeoMedium* medSi = mgr->GetMedium("IT4_SI$"); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSChipPattern(), mLayerNumber); - auto* chipVol = new TGeoVolume(volumeName, chip, medSi); - chipVol->SetVisibility(kTRUE); - chipVol->SetLineColor(1); - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSSensorPattern(), mLayerNumber); - auto* sensVol = new TGeoVolume(volumeName, sensor, medSi); - sensVol->SetVisibility(kTRUE); - sensVol->SetLineColor(8); - sensVol->SetLineWidth(1); - sensVol->SetFillColor(sensVol->GetLineColor()); - sensVol->SetFillStyle(4000); // 0% transparent - - // Now build up the chip - xpos = 0.; - ypos = -chip->GetDY() + sensor->GetDY(); - zpos = 0.; - - chipVol->AddNode(sensVol, 1, new TGeoTranslation(xpos, ypos, zpos)); - - // Done, return the chip - return chipVol; -} - -TGeoVolume* V1Layer::createModuleOuterB(const TGeoManager* mgr) -{ - char volumeName[30]; - - Double_t xGap = sOBChipXGap; - Double_t zGap = sOBChipZGap; - - Double_t xchip, ychip, zchip; - Double_t xlen, ylen, zlen; - Double_t xpos, ypos, zpos; - - // First create all needed shapes - - // The chip (the same as for IB) - xlen = (sOBHalfStaveWidth / 2 - xGap / 2) / sOBNChipRows; - ylen = 0.5 * mStaveThickness; // TO BE CHECKED - zlen = (sOBModuleZLength - (sOBChipsPerRow - 1) * zGap) / (2 * sOBChipsPerRow); - - TGeoVolume* chipVol = createChipInnerB(xlen, ylen, zlen); - - xchip = ((TGeoBBox*)chipVol->GetShape())->GetDX(); - ychip = ((TGeoBBox*)chipVol->GetShape())->GetDY(); - zchip = ((TGeoBBox*)chipVol->GetShape())->GetDZ(); - - // The module carbon plate - xlen = sOBHalfStaveWidth / 2; - ylen = sOBCarbonPlateThick / 2; - zlen = sOBModuleZLength / 2; - auto* modPlate = new TGeoBBox("CarbonPlate", xlen, ylen, zlen); - - // The glue - ylen = sOBGlueThick / 2; - auto* glue = new TGeoBBox("Glue", xlen, ylen, zlen); - - // The flex cables - ylen = sOBFlexCableAlThick / 2; - auto* flexAl = new TGeoBBox("FlexAl", xlen, ylen, zlen); - - ylen = sOBFlexCableKapThick / 2; - auto* flexKap = new TGeoBBox("FlexKap", xlen, ylen, zlen); - - // The module - xlen = sOBHalfStaveWidth / 2; - ylen = ychip + modPlate->GetDY() + glue->GetDY() + flexAl->GetDY() + flexKap->GetDY(); - zlen = sOBModuleZLength / 2; - auto* module = new TGeoBBox("OBModule", xlen, ylen, zlen); - - // We have all shapes: now create the real volumes - - TGeoMedium* medAir = mgr->GetMedium("IT4_AIR$"); - TGeoMedium* medCarbon = mgr->GetMedium("IT4_CARBON$"); - TGeoMedium* medGlue = mgr->GetMedium("IT4_GLUE$"); - TGeoMedium* medAluminum = mgr->GetMedium("IT4_ALUMINUM$"); - TGeoMedium* medKapton = mgr->GetMedium("IT4_KAPTON(POLYCH2)$"); - - auto* modPlateVol = new TGeoVolume("CarbonPlateVol", modPlate, medCarbon); - modPlateVol->SetLineColor(kMagenta - 8); - modPlateVol->SetFillColor(modPlateVol->GetLineColor()); - modPlateVol->SetFillStyle(4000); // 0% transparent - - auto* glueVol = new TGeoVolume("GlueVol", glue, medGlue); - glueVol->SetLineColor(kBlack); - glueVol->SetFillColor(glueVol->GetLineColor()); - glueVol->SetFillStyle(4000); // 0% transparent - - auto* flexAlVol = new TGeoVolume("FlexAlVol", flexAl, medAluminum); - flexAlVol->SetLineColor(kRed); - flexAlVol->SetFillColor(flexAlVol->GetLineColor()); - flexAlVol->SetFillStyle(4000); // 0% transparent - - auto* flexKapVol = new TGeoVolume("FlexKapVol", flexKap, medKapton); - flexKapVol->SetLineColor(kGreen); - flexKapVol->SetFillColor(flexKapVol->GetLineColor()); - flexKapVol->SetFillStyle(4000); // 0% transparent - - snprintf(volumeName, 30, "%s%d", o2::its4::GeometryTGeo::getITSModulePattern(), mLayerNumber); - auto* modVol = new TGeoVolume(volumeName, module, medAir); - modVol->SetVisibility(kTRUE); - - // Now build up the module - ypos = -module->GetDY() + modPlate->GetDY(); - modVol->AddNode(modPlateVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos += (modPlate->GetDY() + glue->GetDY()); - modVol->AddNode(glueVol, 1, new TGeoTranslation(0, ypos, 0)); - - xpos = -module->GetDX() + xchip; - ypos += (glue->GetDY() + ychip); - for (Int_t k = 0; k < sOBChipsPerRow; k++) { // put 7x2 chip into one module - zpos = -module->GetDZ() + zchip + k * (2 * zchip + zGap); - modVol->AddNode(chipVol, 2 * k, new TGeoTranslation(xpos, ypos, zpos)); - modVol->AddNode(chipVol, 2 * k + 1, - new TGeoCombiTrans(-xpos, ypos, zpos, new TGeoRotation("", 0, 180, 180))); - mHierarchy[kChip] += 2; - } - - ypos += (ychip + flexAl->GetDY()); - modVol->AddNode(flexAlVol, 1, new TGeoTranslation(0, ypos, 0)); - - ypos += (flexAl->GetDY() + flexKap->GetDY()); - modVol->AddNode(flexKapVol, 1, new TGeoTranslation(0, ypos, 0)); - - // Done, return the module - return modVol; -} - -Double_t V1Layer::radiusOmTurboContainer() -{ - Double_t rr, delta, z, lstav, rstav; - - if (mStaveThickness > 89.) { // Very big angle: avoid overflows since surely - return -1; // the radius from lower vertex is the right value - } - - rstav = mLayerRadius + 0.5 * mStaveThickness; - delta = (0.5 * mStaveThickness) / cosD(mStaveTilt); - z = (0.5 * mStaveThickness) * tanD(mStaveTilt); - - rr = rstav - delta; - lstav = (0.5 * mStaveWidth) - z; - - if ((rr * sinD(mStaveTilt) < lstav)) { - return (rr * cosD(mStaveTilt)); - } else { - return -1; - } -} - -void V1Layer::setNumberOfUnits(Int_t u) -{ - if (mLayerNumber < sNumberOmInnerLayers) { - mNumberOfChips = u; - } else { - mNumberOfModules = u; - mNumberOfChips = sOBChipsPerRow; - } -} - -void V1Layer::setStaveTilt(const Double_t t) -{ - if (mIsTurbo) { - mStaveTilt = t; - } else { - LOG(ERROR) << "Not a Turbo layer"; - } -} - -void V1Layer::setStaveWidth(const Double_t w) -{ - if (mIsTurbo) { - mStaveWidth = w; - } else { - LOG(ERROR) << "Not a Turbo layer"; - } -} - -TGeoArb8* V1Layer::createStaveSide(const char* name, Double_t dz, Double_t angle, - Double_t xSign, Double_t L, Double_t H, Double_t l) -{ - // Create one half of the V shape corner of CF stave - - auto* cmStavSide = new TGeoArb8(dz); - cmStavSide->SetName(name); - - // Points must be in clockwise order - cmStavSide->SetVertex(0, 0, 0); - cmStavSide->SetVertex(2, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), - -L * TMath::Cos(angle) - l * TMath::Sin(angle)); - cmStavSide->SetVertex(4, 0, 0); - cmStavSide->SetVertex(6, xSign * (L * TMath::Sin(angle) - l * TMath::Cos(angle)), - -L * TMath::Cos(angle) - l * TMath::Sin(angle)); - if (xSign < 0) { - cmStavSide->SetVertex(1, 0, -H); - cmStavSide->SetVertex(3, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(5, 0, -H); - cmStavSide->SetVertex(7, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - } else { - cmStavSide->SetVertex(1, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(3, 0, -H); - cmStavSide->SetVertex(5, xSign * L * TMath::Sin(angle), -L * TMath::Cos(angle)); - cmStavSide->SetVertex(7, 0, -H); - } - return cmStavSide; -} - -TGeoCombiTrans* V1Layer::createCombiTrans(const char* name, Double_t dy, Double_t dz, - Double_t dphi, Bool_t planeSym) -{ - TGeoTranslation t1(dy * cosD(90. + dphi), dy * sinD(90. + dphi), dz); - TGeoRotation r1("", 0., 0., dphi); - TGeoRotation r2("", 90, 180, -90 - dphi); - - auto* combiTrans1 = new TGeoCombiTrans(name); - combiTrans1->SetTranslation(t1); - if (planeSym) { - combiTrans1->SetRotation(r1); - } else { - combiTrans1->SetRotation(r2); - } - return combiTrans1; -} - -void V1Layer::addTranslationToCombiTrans(TGeoCombiTrans* ct, Double_t dx, Double_t dy, - Double_t dz) const -{ - // Add a dx,dy,dz translation to the initial TGeoCombiTrans - const Double_t* vect = ct->GetTranslation(); - Double_t newVect[3] = {vect[0] + dx, vect[1] + dy, vect[2] + dz}; - ct->SetTranslation(newVect); -} diff --git a/Detectors/Upgrades/README.md b/Detectors/Upgrades/README.md index c71db05187e1e..111faf6154118 100644 --- a/Detectors/Upgrades/README.md +++ b/Detectors/Upgrades/README.md @@ -1,19 +1,22 @@ <!-- doxy -\page refDetectorsITSMFT ITSMFT +\page refDetectorsUpgrades Upgrades /doxy --> # Upgrades This is a top page for detectors not included in Run 3 layout. -# Installation -To enable the compilation of this section it is required to prepend the `ENABLE_UPGRADES=ON` to the installation command, for instance: +# Installation +To enable the compilation of this section you need to have the environment variable `ENABLE_UPGRADES=ON` set. +An example for the installation command is: ```bash ENABLE_UPGRADES=ON aliBuild build O2 --defaults o2 ``` +Currently two sections are included: <!-- doxy -* \subpage refIT3 -* \subpage refPostLS4 -/doxy --> \ No newline at end of file +* \subpage refDetectorsUpgradesIT3 +* \subpage refDetectorsUpgradesALICE3FT3 +* \subpage refDetectorsUpgradesALICE3TRK +/doxy --> diff --git a/Detectors/Vertexing/CMakeLists.txt b/Detectors/Vertexing/CMakeLists.txt index b36d310a214f4..f876a779eb2ab 100644 --- a/Detectors/Vertexing/CMakeLists.txt +++ b/Detectors/Vertexing/CMakeLists.txt @@ -1,14 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DetectorsVertexing + TARGETVARNAME targetName SOURCES src/DCAFitterN.cxx src/PVertexer.cxx src/PVertexerHelpers.cxx @@ -16,28 +18,33 @@ o2_add_library(DetectorsVertexing src/VertexTrackMatcher.cxx src/SVertexer.cxx src/SVertexerParams.cxx - src/V0Hypothesis.cxx + src/SVertexHypothesis.cxx PUBLIC_LINK_LIBRARIES ROOT::Core - O2::CommonUtils + O2::CommonUtils O2::ReconstructionDataFormats + O2::DataFormatsParameters O2::DataFormatsTPC O2::DataFormatsITS O2::TPCBase O2::SimulationDataFormat O2::FT0Reconstruction O2::DataFormatsFT0 - ms_gsl::ms_gsl) + O2::GlobalTracking + Microsoft.GSL::GSL) o2_target_root_dictionary(DetectorsVertexing HEADERS include/DetectorsVertexing/HelixHelper.h - include/DetectorsVertexing/PVertexer.h include/DetectorsVertexing/PVertexerHelpers.h include/DetectorsVertexing/PVertexerParams.h - include/DetectorsVertexing/VertexTrackMatcher.h include/DetectorsVertexing/DCAFitterN.h - include/DetectorsVertexing/SVertexer.h include/DetectorsVertexing/SVertexerParams.h - include/DetectorsVertexing/V0Hypothesis.h) + include/DetectorsVertexing/SVertexHypothesis.h) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() + o2_add_test( DCAFitterN diff --git a/Detectors/Vertexing/README.md b/Detectors/Vertexing/README.md index bc8f41f9ecd59..4e079278e91cf 100644 --- a/Detectors/Vertexing/README.md +++ b/Detectors/Vertexing/README.md @@ -32,6 +32,7 @@ ft.setBz(5.0); ft.setPropagateToPCA(true); // After finding the vertex, propagate tracks to the DCA. This is default anyway ft.setMaxR(200); // do not consider V0 seeds with 2D circles crossing above this R. This is default anyway ft.setMaxDZIni(4); // do not consider V0 seeds with tracks Z-distance exceeding this. This is default anyway +ft.setMaxDXYIni(4); // do not consider V0 seeds with tracks XY-distance exceeding this. This is default anyway ft.setMinParamChange(1e-3); // stop iterations if max correction is below this value. This is default anyway ft.setMinRelChi2Change(0.9);// stop iterations if chi2 improves by less that this factor ft.setMaxChi2(10); // discard vertices with chi2/Nprongs (or sum{DCAi^2}/Nprongs for abs. distance minimization) @@ -55,3 +56,33 @@ if (nc) { See ``O2/Detectors/Base/test/testDCAFitterN.cxx`` for more extended example. Currently only 2 and 3 prongs permitted, thought this can be changed by modifying ``DCAFitterN::NMax`` constant. + +## Primary Vertexing + +The workflow is `o2-primary-vertexing-workflow`, the vertexing parameters are provided via configurable param `pvertexer...` of `PVertexerParams` class. The vertexing first runs an improvized version of `DBSCan` to group tracks losely converging to `MeanVertex` into `time-Z` clusters, then finds for each such a cluster vertices using as a seed the peaks from histogrammed tracks `time-Z` values. + +Lot of numerical values in the params must be fine-tuned when the tracking performance will be close to final, particularly the fake ITS-TPC matches (which are prone to create fake vertices). +By default the vertices will be fitted using the `MeanVertex` as an extra measured point. + +Two groups of parameters need particular attention: + +1) Debris (split vertices) reduction: after finding the vertices it tries to suppress low-multiplicity vertices in a close proximity (in Z and in time) of high-multiplicity ones. See `PVertexerParams.*Debris` parameters comments and `PVertexer::reduceDebris` method. +2) Tracks re-attachment: after finding the vertices and optionally reducing debris, it finds for each track closest vertex (in time and in Z) and refits these groups of tracks using corresponding vertices as seeds. The reason to apply this procedure is the bad time resolution of ITS standalone tracks (=ROF duration): high multiplicity vertex has high chances to steal such tracks belonging to nearby low-multiplicity ones (since it is found first). The reattachment allows to eliminate this effect of particular order of vertex finding. +It should be applied *only* in case the debris reduction was performed, otherwise the low-multiplicity split vertices will steal tracks from high-multiplicity ones. The tracks are tested for belonging to given vertex only if they are in certain `time-range` from the fitted vertex time. This `time-range` is defined as `PVertexerParams.timeMarginReattach` + half of `DBSCan` time difference cut value +`PVertexerParams.dbscanDeltaT` or half `ITS` strobe length (ROF), whichever larger. + +In order to tune the parameters, a special debug output file is written when the code is compiled with `_PV_DEBUG_TREE_` uncommented in `PVertexer.h`. It contains the (i) tree of `time-Z` clusters found by `DBSCan` (`pvtxDBScan`), the seeding histograms for every `time-Z` cluster after every vertexing iteration; (ii) the `pvtxComp` tree containing the pairs of vertices which were considered as close by the `reduceDebris` routine, their mutual `chi2` in `Z` and `time`, as well as the decision to reject the vertex with lower multiplicity (2nd one); +(iii) the `pvtx` tree with final vertices and their belonging tracks. + +To see the effect of running with and w/o `re-attachment`, one can compare the outputs of 2 tests, e.g. +```` +o2-primary-vertexing-workflow --run --configKeyValues "pvertexer.useMeanVertexConstraint=true;pvertexer.applyDebrisReduction=true;pvertexer.applyReattachment=false" +```` +and +```` +o2-primary-vertexing-workflow --run --configKeyValues "pvertexer.useMeanVertexConstraint=true;pvertexer.applyDebrisReduction=true;pvertexer.applyReattachment=true" +```` + +## Secondary Vertexing + +The workflow is `o2-secondary-vertexing-workflow` \ No newline at end of file diff --git a/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h b/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h index 3353526becf93..17a6b51792d95 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,7 @@ #ifndef _ALICEO2_DCA_FITTERN_ #define _ALICEO2_DCA_FITTERN_ #include <TMath.h> -#include <Math/SMatrix.h> -#include <Math/SVector.h> +#include "MathUtils/Cartesian.h" #include "ReconstructionDataFormats/Track.h" #include "DetectorsVertexing/HelixHelper.h" @@ -105,6 +105,11 @@ class DCAFitterN //========================================================================= ///< return PCA candidate, by default best on is provided (no check for the index validity) const Vec3D& getPCACandidate(int cand = 0) const { return mPCA[mOrder[cand]]; } + const auto getPCACandidatePos(int cand = 0) const + { + const auto& vd = mPCA[mOrder[cand]]; + return std::array<float, 3>{float(vd[0]), float(vd[1]), float(vd[2])}; + } ///< return Chi2 at PCA candidate (no check for its validity) float getChi2AtPCACandidate(int cand = 0) const { return mChi2[mOrder[cand]]; } @@ -118,6 +123,14 @@ class DCAFitterN ///< track param propagated to V0 candidate (no check for the candidate validity) /// propagateTracksToVertex must be called in advance + Track& getTrack(int i, int cand = 0) + { + if (!mTrPropDone[mOrder[cand]]) { + throw std::runtime_error("propagateTracksToVertex was not called yet"); + } + return mCandTr[mOrder[cand]][i]; + } + const Track& getTrack(int i, int cand = 0) const { if (!mTrPropDone[mOrder[cand]]) { @@ -126,11 +139,23 @@ class DCAFitterN return mCandTr[mOrder[cand]][i]; } + ///< create parent track param with errors for decay vertex + o2::track::TrackParCov createParentTrackParCov(int cand = 0, bool sectorAlpha = true) const; + + ///< create parent track param w/o errors for decay vertex + o2::track::TrackPar createParentTrackPar(int cand = 0, bool sectorAlpha = true) const; + ///< calculate on the fly track param (no cov mat) at candidate, check isValid to make sure propagation was successful o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0) const; MatSym3D calcPCACovMatrix(int cand = 0) const; + std::array<float, 6> calcPCACovMatrixFlat(int cand = 0) const + { + auto m = calcPCACovMatrix(cand); + return {float(m(0, 0)), float(m(1, 0)), float(m(1, 1)), float(m(2, 0)), float(m(2, 1)), float(m(2, 2))}; + } + const Track* getOrigTrackPtr(int i) const { return mOrigTrPtr[i]; } ///< return number of iterations during minimization (no check for its validity) @@ -139,6 +164,7 @@ class DCAFitterN void setMaxIter(int n = 20) { mMaxIter = n > 2 ? n : 2; } void setMaxR(float r = 200.) { mMaxR2 = r * r; } void setMaxDZIni(float d = 4.) { mMaxDZIni = d; } + void setMaxDXYIni(float d = 4.) { mMaxDXYIni = d > 0 ? d : 1e9; } void setMaxChi2(float chi2 = 999.) { mMaxChi2 = chi2; } void setBz(float bz) { mBz = std::abs(bz) > o2::constants::math::Almost0 ? bz : 0.f; } void setMinParamChange(float x = 1e-3) { mMinParamChange = x > 1e-4 ? x : 1.e-4; } @@ -150,6 +176,7 @@ class DCAFitterN int getMaxIter() const { return mMaxIter; } float getMaxR() const { return std::sqrt(mMaxR2); } float getMaxDZIni() const { return mMaxDZIni; } + float getMaxDXYIni() const { return mMaxDXYIni; } float getMaxChi2() const { return mMaxChi2; } float getMinParamChange() const { return mMinParamChange; } float getBz() const { return mBz; } @@ -195,7 +222,7 @@ class DCAFitterN mat(0, 0) = mat(1, 1) = mTrAux[i].c; mat(0, 1) = -mTrAux[i].s; mat(1, 0) = mTrAux[i].s; - return std::move(mat); + return mat; } MatSym3D getTrackCovMatrix(int i, int cand = 0) const // generate covariance matrix of track position, adding fake X error @@ -206,7 +233,7 @@ class DCAFitterN mat(1, 1) = trc.getSigmaY2(); mat(2, 2) = trc.getSigmaZ2(); mat(2, 1) = trc.getSigmaZY(); - return std::move(mat); + return mat; } void assign(int) {} @@ -267,6 +294,7 @@ class DCAFitterN float mBz = 0; // bz field, to be set by user float mMaxR2 = 200. * 200.; // reject PCA's above this radius float mMaxDZIni = 4.; // reject (if>0) PCA candidate if tracks DZ exceeds threshold + float mMaxDXYIni = 4.; // reject (if>0) PCA candidate if tracks dXY exceeds threshold float mMinParamChange = 1e-3; // stop iterations if largest change of any X is smaller than this float mMinRelChi2Change = 0.9; // stop iterations is chi2/chi2old > this float mMaxChi2 = 100; // abs cut on chi2 or abs distance @@ -287,7 +315,7 @@ int DCAFitterN<N, Args...>::process(const Tr&... args) for (int i = 0; i < N; i++) { mTrAux[i].set(*mOrigTrPtr[i], mBz); } - if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1])) { // even for N>2 it should be enough to test just 1 loop + if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni)) { // even for N>2 it should be enough to test just 1 loop return 0; // no crossing } if (mUseAbsDCA) { @@ -608,7 +636,7 @@ ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepSym<double, 3>> DCAFitterN<N for (int i = N; i--;) { covm += ROOT::Math::Similarity(mUseAbsDCA ? getTrackRotMatrix(i) : mTrCFVT[mOrder[cand]][i], getTrackCovMatrix(i, cand)); } - return std::move(covm); + return covm; } //___________________________________________________________________ @@ -878,6 +906,62 @@ void DCAFitterN<N, Args...>::print() const LOG(INFO) << "Discard candidates for : Rvtx > " << getMaxR() << " DZ between tracks > " << mMaxDZIni; } +//___________________________________________________________________ +template <int N, typename... Args> +o2::track::TrackParCov DCAFitterN<N, Args...>::createParentTrackParCov(int cand, bool sectorAlpha) const +{ + const auto& trP = getTrack(0, cand); + const auto& trN = getTrack(1, cand); + std::array<float, 21> covV = {0.}; + std::array<float, 3> pvecV = {0.}; + int q = 0; + for (int it = 0; it < N; it++) { + const auto& trc = getTrack(it, cand); + std::array<float, 3> pvecT = {0.}; + std::array<float, 21> covT = {0.}; + trc.getPxPyPzGlo(pvecT); + trc.getCovXYZPxPyPzGlo(covT); + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV[MomInd[i]] += covT[MomInd[i]]; + } + for (int i = 0; i < 3; i++) { + pvecV[i] += pvecT[i]; + } + q += trc.getCharge(); + } + auto covVtxV = calcPCACovMatrix(cand); + covV[0] = covVtxV(0, 0); + covV[1] = covVtxV(1, 0); + covV[2] = covVtxV(1, 1); + covV[3] = covVtxV(2, 0); + covV[4] = covVtxV(2, 1); + covV[5] = covVtxV(2, 2); + return std::move(o2::track::TrackParCov(getPCACandidatePos(cand), pvecV, covV, q, sectorAlpha)); +} + +//___________________________________________________________________ +template <int N, typename... Args> +o2::track::TrackPar DCAFitterN<N, Args...>::createParentTrackPar(int cand, bool sectorAlpha) const +{ + const auto& trP = getTrack(0, cand); + const auto& trN = getTrack(1, cand); + const auto& wvtx = getPCACandidate(cand); + std::array<float, 3> pvecV = {0.}; + int q = 0; + for (int it = 0; it < N; it++) { + const auto& trc = getTrack(it, cand); + std::array<float, 3> pvecT = {0.}; + trc.getPxPyPzGlo(pvecT); + for (int i = 0; i < 3; i++) { + pvecV[i] += pvecT[i]; + } + q += trc.getCharge(); + } + const std::array<float, 3> vertex = {(float)wvtx[0], (float)wvtx[1], (float)wvtx[2]}; + return std::move(o2::track::TrackPar(vertex, pvecV, q, sectorAlpha)); +} + using DCAFitter2 = DCAFitterN<2, o2::track::TrackParCov>; using DCAFitter3 = DCAFitterN<3, o2::track::TrackParCov>; diff --git a/Detectors/Vertexing/include/DetectorsVertexing/HelixHelper.h b/Detectors/Vertexing/include/DetectorsVertexing/HelixHelper.h index 97c7abca67de5..4888c217a49d7 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/HelixHelper.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/HelixHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -47,11 +48,12 @@ struct TrackAuxPar : public o2::math_utils::CircleXYf_t { //__________________________________________________________ //< crossing coordinates of 2 circles struct CrossInfo { - float xDCA[2]; - float yDCA[2]; - int nDCA; + static constexpr float MaxDistXYDef = 10.; + float xDCA[2] = {}; + float yDCA[2] = {}; + int nDCA = 0; - int circlesCrossInfo(const TrackAuxPar& trax0, const TrackAuxPar& trax1) + int circlesCrossInfo(const TrackAuxPar& trax0, const TrackAuxPar& trax1, float maxDistXY = MaxDistXYDef) { const auto& trcA = trax0.rC > trax1.rC ? trax0 : trax1; // designate the largest circle as A const auto& trcB = trax0.rC > trax1.rC ? trax1 : trax0; @@ -63,6 +65,9 @@ struct CrossInfo { if (dist > rsum) { // circles don't touch, chose a point in between // the parametric equation of lines connecting the centers is // x = x0 + t/dist * (x1-x0), y = y0 + t/dist * (y1-y0) + if (dist - rsum > maxDistXY) { // too large distance + return nDCA; + } notTouchingXY(dist, xDist, yDist, trcA, trcB.rC); } else if (dist + trcB.rC < trcA.rC) { // the small circle is nestled into large one w/o touching // select the point of closest approach of 2 circles @@ -120,7 +125,7 @@ struct CrossInfo { } int linesCrossInfo(const TrackAuxPar& trax0, const TrackPar& tr0, - const TrackAuxPar& trax1, const TrackPar& tr1) + const TrackAuxPar& trax1, const TrackPar& tr1, float maxDistXY = MaxDistXYDef) { /// closest approach of 2 straight lines /// TrackParam propagation can be parameterized in lab in a form @@ -166,15 +171,21 @@ struct CrossInfo { auto detI = 1. / det; auto t0 = det0 * detI; auto t1 = det1 * detI; - xDCA[0] = (trax0.xC + kx0 * t0 + trax1.xC + kx1 * t1) * 0.5; - yDCA[0] = (trax0.yC + ky0 * t0 + trax1.yC + ky1 * t1) * 0.5; + float addx0 = kx0 * t0, addy0 = ky0 * t0, addx1 = kx1 * t1, addy1 = ky1 * t1; + dx += addx1 - addx0; // recalculate XY distance at DCA + dy += addy1 - addy0; + if (dx * dx + dy * dy > maxDistXY * maxDistXY) { + return nDCA; + } + xDCA[0] = (trax0.xC + addx0 + trax1.xC + addx1) * 0.5; + yDCA[0] = (trax0.yC + addy0 + trax1.yC + addy1) * 0.5; nDCA = 1; } return nDCA; } int circleLineCrossInfo(const TrackAuxPar& trax0, const TrackPar& tr0, - const TrackAuxPar& trax1, const TrackPar& tr1) + const TrackAuxPar& trax1, const TrackPar& tr1, float maxDistXY = MaxDistXYDef) { /// closest approach of line and circle /// TrackParam propagation can be parameterized in lab in a form @@ -215,10 +226,14 @@ struct CrossInfo { yDCA[1] = traxL.yC + ky * t1; nDCA = 2; } else { - // there is no crossing, find the point of the closest approach on the line as the sames which is closest to the circle center + // there is no crossing, find the point of the closest approach on the line which is closest to the circle center float t = -dk * cspi2; float xL = traxL.xC + kx * t, yL = traxL.yC + ky * t; // point on the line, need to average with point on the circle - float dxc = xL - traxH.xC, dyc = yL - traxH.yC, drcf = traxH.rC / std::sqrt(dxc * dxc + dyc * dyc); // radius / distance to circle center + float dxc = xL - traxH.xC, dyc = yL - traxH.yC, dist = std::sqrt(dxc * dxc + dyc * dyc); + if (dist - traxH.rC > maxDistXY) { // too large distance + return nDCA; + } + float drcf = traxH.rC / dist; // radius / distance to circle center float xH = traxH.xC + dxc * drcf, yH = traxH.yC + dyc * drcf; xDCA[0] = (xL + xH) * 0.5; yDCA[0] = (yL + yH) * 0.5; @@ -227,16 +242,16 @@ struct CrossInfo { return nDCA; } - int set(const TrackAuxPar& trax0, const TrackPar& tr0, const TrackAuxPar& trax1, const TrackPar& tr1) + int set(const TrackAuxPar& trax0, const TrackPar& tr0, const TrackAuxPar& trax1, const TrackPar& tr1, float maxDistXY = MaxDistXYDef) { // calculate up to 2 crossings between 2 circles nDCA = 0; if (trax0.rC > o2::constants::math::Almost0 && trax1.rC > o2::constants::math::Almost0) { // both are not straight lines - nDCA = circlesCrossInfo(trax0, trax1); + nDCA = circlesCrossInfo(trax0, trax1, maxDistXY); } else if (trax0.rC < o2::constants::math::Almost0 && trax1.rC < o2::constants::math::Almost0) { // both are straigt lines - nDCA = linesCrossInfo(trax0, tr0, trax1, tr1); + nDCA = linesCrossInfo(trax0, tr0, trax1, tr1, maxDistXY); } else { - nDCA = circleLineCrossInfo(trax0, tr0, trax1, tr1); + nDCA = circleLineCrossInfo(trax0, tr0, trax1, tr1, maxDistXY); } // return nDCA; @@ -244,9 +259,9 @@ struct CrossInfo { CrossInfo() = default; - CrossInfo(const TrackAuxPar& trax0, const TrackPar& tr0, const TrackAuxPar& trax1, const TrackPar& tr1) + CrossInfo(const TrackAuxPar& trax0, const TrackPar& tr0, const TrackAuxPar& trax1, const TrackPar& tr1, float maxDistXY = MaxDistXYDef) { - set(trax0, tr0, trax1, tr1); + set(trax0, tr0, trax1, tr1, maxDistXY); } ClassDefNV(CrossInfo, 1); }; diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h index 443571c0f7a0b..049879036335e 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,14 +24,20 @@ #include "SimulationDataFormat/MCEventLabel.h" #include "SimulationDataFormat/MCCompLabel.h" #include "MathUtils/Utils.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" #include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/PrimaryVertex.h" -#include "DataFormatsFT0/RecPoints.h" #include "DetectorsVertexing/PVertexerHelpers.h" #include "DetectorsVertexing/PVertexerParams.h" -#include "FT0Reconstruction/InteractionTag.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "gsl/span" +#include <numeric> +#include <TTree.h> +#include <TFile.h> + +//TODO: MeanVertex and parameters input from CCDB + +//#define _PV_DEBUG_TREE_ // if enabled, produce dbscan and vertex comparison dump namespace o2 { @@ -50,16 +57,13 @@ class PVertexer OK }; void init(); - int process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span<const o2::ft0::RecPoints> ft0Data, - std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, - gsl::span<const o2::MCCompLabel> lblITS, gsl::span<const o2::MCCompLabel> lblTPC, std::vector<o2::MCEventLabel>& lblVtx); + void end(); - int process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span<const o2::ft0::RecPoints> ft0Data, - std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs); + template <typename TR> + int process(const TR& tracks, const gsl::span<o2d::GlobalTrackID> gids, const gsl::span<o2::InteractionRecord> bcData, + std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, + const gsl::span<const o2::MCCompLabel> lblTracks, std::vector<o2::MCEventLabel>& lblVtx); - static void createMCLabels(gsl::span<const o2::MCCompLabel> lblITS, gsl::span<const o2::MCCompLabel> lblTPC, - const std::vector<PVertex> vertices, const std::vector<o2d::VtxTrackIndex> vertexTrackIDs, const std::vector<V2TRef> v2tRefs, - std::vector<o2::MCEventLabel>& lblVtx); bool findVertex(const VertexingInput& input, PVertex& vtx); void setStartIR(const o2::InteractionRecord& ir) { mStartIR = ir; } ///< set InteractionRecods for the beginning of the TF @@ -70,18 +74,16 @@ class PVertexer } float getTukey() const; - void finalizeVertex(const VertexingInput& input, const PVertex& vtx, std::vector<PVertex>& vertices, std::vector<V2TRef>& v2tRefs, std::vector<int>& vertexTrackIDs, SeedHisto& histo); bool setCompatibleIR(PVertex& vtx); void setBunchFilling(const o2::BunchFilling& bf); void setBz(float bz) { mBz = bz; } - void setValidateWithFT0(bool v) { mValidateWithFT0 = v; } - bool getValidateWithFT0() const { return mValidateWithFT0; } + void setValidateWithIR(bool v) { mValidateWithIR = v; } + bool getValidateWithIR() const { return mValidateWithIR; } auto& getTracksPool() const { return mTracksPool; } - auto& getTimeClusters() const { return mTimesClusters; } - auto& getSortedTrackIndices() const { return mSortedTrackID; } + auto& getTimeZClusters() const { return mTimeZClusters; } auto& getMeanVertex() const { return mMeanVertex; } void setMeanVertex(const o2d::VertexBase& v) @@ -90,15 +92,22 @@ class PVertexer initMeanVertexConstraint(); } - float estimateScale2() + void setITSROFrameLength(float v) { - float minrange = std::min(mPVParams->zHistoBinSize, mPVParams->minZSeedRange); - auto sc = mPVParams->zHistoBinSize * mPVParams->zHistoBinSize * mTukey2I / (mStatZErr.getMean() * mStatZErr.getMean()); - return sc; + mITSROFrameLengthMUS = v; } private: + static constexpr int DBS_UNDEF = -2, DBS_NOISE = -1, DBS_INCHECK = -10; + + SeedHistoTZ buildHistoTZ(const VertexingInput& input); + int runVertexing(gsl::span<o2d::GlobalTrackID> gids, const gsl::span<o2::InteractionRecord> bcData, + std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, + gsl::span<const o2::MCCompLabel> lblTracks, std::vector<o2::MCEventLabel>& lblVtx); + void createMCLabels(gsl::span<const o2::MCCompLabel> lblTracks, const std::vector<uint32_t>& trackIDs, const std::vector<V2TRef>& v2tRefs, std::vector<o2::MCEventLabel>& lblVtx); + void reduceDebris(std::vector<PVertex>& vertices, std::vector<int>& timeSort, const std::vector<o2::MCEventLabel>& lblVtx); FitStatus fitIteration(const VertexingInput& input, VertexSeed& vtxSeed); + void finalizeVertex(const VertexingInput& input, const PVertex& vtx, std::vector<PVertex>& vertices, std::vector<V2TRef>& v2tRefs, std::vector<uint32_t>& trackIDs, SeedHistoTZ* histo = nullptr); void accountTrack(TrackVF& trc, VertexSeed& vtxSeed) const; bool solveVertex(VertexSeed& vtxSeed) const; FitStatus evalIterations(VertexSeed& vtxSeed, PVertex& vtx) const; @@ -107,11 +116,20 @@ class PVertexer void initMeanVertexConstraint(); void applyConstraint(VertexSeed& vtxSeed) const; bool upscaleSigma(VertexSeed& vtxSeed) const; - void createTracksPool(gsl::span<const o2d::TrackTPCITS> tracksITSTPC); - void clusterizeTimeBruteForce(float margin = 0.1, float cut = 25); - void clusterizeTime(float binSize = 0.1, float maxTDist = 0.6); - int findVertices(const VertexingInput& input, std::vector<PVertex>& vertices, std::vector<int>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs); - std::pair<int, int> getBestFT0Trigger(const PVertex& vtx, gsl::span<const o2::ft0::RecPoints> ft0Data, int& currEntry) const; + bool relateTrackToMeanVertex(o2::track::TrackParCov& trc, float vtxErr2) const; + + template <typename TR> + void createTracksPool(const TR& tracks, gsl::span<const o2d::GlobalTrackID> gids); + + int findVertices(const VertexingInput& input, std::vector<PVertex>& vertices, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs); + void reAttach(std::vector<PVertex>& vertices, std::vector<int>& timeSort, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs); + + std::pair<int, int> getBestIR(const PVertex& vtx, const gsl::span<o2::InteractionRecord> bcData, int& currEntry) const; + + int dbscan_RangeQuery(int idxs, std::vector<int>& cand, std::vector<int>& status); + void dbscan_clusterize(); + void doDBScanDump(const VertexingInput& input, gsl::span<const o2::MCCompLabel> lblTracks); + void doVtxDump(std::vector<PVertex>& vertices, std::vector<uint32_t> trackIDsLoc, std::vector<V2TRef>& v2tRefsLoc, gsl::span<const o2::MCCompLabel> lblTracks); o2::BunchFilling mBunchFilling; std::array<int16_t, o2::constants::lhc::LHCMaxBunches> mClosestBunchAbove; // closest filled bunch from above @@ -119,26 +137,41 @@ class PVertexer o2d::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; std::array<float, 3> mXYConstraintInvErr = {1.0f, 0.f, 1.0f}; ///< nominal vertex constraint inverted errors^2 // - o2::math_utils::StatAccumulator mStatZErr; - o2::math_utils::StatAccumulator mStatTErr; - std::vector<TrackVF> mTracksPool; ///< tracks in internal representation used for vertexing - std::vector<int> mSortedTrackID; ///< indices of tracks sorted in time - std::vector<TimeCluster> mTimesClusters; ///< set of time clusters + std::vector<TrackVF> mTracksPool; ///< tracks in internal representation used for vertexing, sorted in time + std::vector<TimeZCluster> mTimeZClusters; ///< set of time clusters + float mITSROFrameLengthMUS = 0; ///< ITS readout time span in \mus float mBz = 0.; ///< mag.field at beam line - bool mValidateWithFT0 = false; ///< require vertex validation with FT0 (if available) + bool mValidateWithIR = false; ///< require vertex validation with InteractionRecords (if available) o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF ///========== Parameters to be set externally, e.g. from CCDB ==================== const PVertexerParams* mPVParams = nullptr; - const o2::ft0::InteractionTag* mFT0Params = nullptr; float mTukey2I = 0; ///< 1./[Tukey parameter]^2 static constexpr float kDefTukey = 5.0f; ///< def.value for tukey constant static constexpr float kHugeF = 1.e12; ///< very large float static constexpr float kAlmost0F = 1e-12; ///< tiny float static constexpr double kAlmost0D = 1e-16; ///< tiny double - ClassDefNV(PVertexer, 1); +#ifdef _PV_DEBUG_TREE_ + std::unique_ptr<TFile> mDebugDumpFile; + std::unique_ptr<TTree> mDebugDBScanTree; + std::unique_ptr<TTree> mDebugVtxTree; + std::unique_ptr<TTree> mDebugVtxCompTree; + + std::vector<TrackVFDump> mDebugDumpDBSTrc; + std::vector<GTrackID> mDebugDumpDBSGID; + std::vector<o2::MCCompLabel> mDebugDumpDBSTrcMC; + + PVertex mDebugDumpVtx; + std::vector<TrackVFDump> mDebugDumpVtxTrc; + std::vector<GTrackID> mDebugDumpVtxGID; + std::vector<o2::MCCompLabel> mDebugDumpVtxTrcMC; + + std::vector<PVtxCompDump> mDebugDumpPVComp; + std::vector<o2::MCEventLabel> mDebugDumpPVCompLbl0; // for some reason the added as a class member + std::vector<o2::MCEventLabel> mDebugDumpPVCompLbl1; // gets stored as simple uint +#endif }; //___________________________________________________________________ @@ -164,6 +197,51 @@ inline bool PVertexer::upscaleSigma(VertexSeed& vtxSeed) const return false; } +//___________________________________________________________________ +template <typename TR> +void PVertexer::createTracksPool(const TR& tracks, gsl::span<const o2d::GlobalTrackID> gids) +{ + // create pull of all candidate tracks in a global array ordered in time + mTracksPool.clear(); + auto ntGlo = tracks.size(); + std::vector<int> sortedTrackID(ntGlo); + mTracksPool.reserve(ntGlo); + std::iota(sortedTrackID.begin(), sortedTrackID.end(), 0); + std::sort(sortedTrackID.begin(), sortedTrackID.end(), [&tracks](int i, int j) { + return tracks[i].timeEst.getTimeStamp() < tracks[j].timeEst.getTimeStamp(); + }); + + // check all containers + float vtxErr2 = 0.5 * (mMeanVertex.getSigmaX2() + mMeanVertex.getSigmaY2()); + o2d::DCA dca; + + for (uint32_t i = 0; i < ntGlo; i++) { + int id = sortedTrackID[i]; + o2::track::TrackParCov trc = tracks[id]; + if (!relateTrackToMeanVertex(trc, vtxErr2)) { + continue; + } + auto& tvf = mTracksPool.emplace_back(trc, tracks[id].getTimeMUS(), id, gids[id], mPVParams->addTimeSigma2, mPVParams->addZSigma2); + } + + if (mTracksPool.empty()) { + return; + } + // + auto tMin = mTracksPool.front().timeEst.getTimeStamp(); + auto tMax = mTracksPool.back().timeEst.getTimeStamp(); +} + +//___________________________________________________________________ +template <typename TR> +int PVertexer::process(const TR& tracks, const gsl::span<o2d::GlobalTrackID> gids, const gsl::span<o2::InteractionRecord> bcData, + std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, + const gsl::span<const o2::MCCompLabel> lblTracks, std::vector<o2::MCEventLabel>& lblVtx) +{ + createTracksPool(tracks, gids); + return runVertexing(gids, bcData, vertices, vertexTrackIDs, v2tRefs, lblTracks, lblVtx); +} + } // namespace vertexing } // namespace o2 #endif diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h index a9f022aac7b53..563a208896f33 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,8 @@ #include "ReconstructionDataFormats/VtxTrackIndex.h" #include "ReconstructionDataFormats/VtxTrackRef.h" #include "CommonDataFormat/TimeStamp.h" +#include "CommonDataFormat/FlatHisto2D.h" +#include "SimulationDataFormat/MCEventLabel.h" namespace o2 { @@ -31,6 +34,13 @@ using PVertex = o2::dataformats::PrimaryVertex; using TimeEst = o2::dataformats::TimeStampWithError<float, float>; using V2TRef = o2::dataformats::VtxTrackRef; using GIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::GlobalTrackID; + +struct VertexingInput { + gsl::span<int> idRange; + TimeEst timeEst{0, -1.}; // negative error means don't use time info + float scaleSigma2 = 10; +}; ///< weights and scaling params for current vertex struct VertexSeed : public PVertex { @@ -46,8 +56,6 @@ struct VertexSeed : public PVertex { int nScaleSlowConvergence = 0; int nScaleIncrease = 0; int nIterations = 0; - bool useConstraint = true; - bool fillErrors = true; void setScale(float scale2, float tukey2I) { @@ -68,12 +76,18 @@ struct VertexSeed : public PVertex { } VertexSeed() = default; - VertexSeed(const PVertex& vtx, bool _constraint, bool _errors) - : PVertex(vtx), useConstraint(_constraint), fillErrors(_errors) {} + VertexSeed(const PVertex& vtx) + : PVertex(vtx) {} void print() const; }; +/// generic track with timestamp +struct TrackWithTimeStamp : o2::track::TrackParCov { + TimeEst timeEst{}; + auto getTimeMUS() const { return timeEst; } +}; + struct TrackVF { /** Straight track parameterization in the frame defined by alpha angle. Assumed to be defined in the proximity to vertex, so that the @@ -96,12 +110,11 @@ struct TrackVF { TimeEst timeEst; float wgh = 0.; ///< track weight wrt current vertex seed - uint32_t entry = 0; - int16_t bin = -1; // seeds histo bin - uint8_t srcID = 0; - uint8_t flags = 0; + float wghHisto = 0.; // weight based on track errors, used for histogramming + int entry; ///< track entry in the input vector + int32_t bin = -1; // seeds histo bin + GTrackID gid{}; int vtxID = kNoVtx; ///< assigned vertex - // bool canAssign() const { return wgh > 0. && vtxID == kNoVtx; } bool canUse() const { return vtxID == kNoVtx; } @@ -116,6 +129,25 @@ struct TrackVF { return z + tgL * (vx * cosAlp + vy * sinAlp - x); } + // weighted distance^2 to other track (accounting for own errors only) + float getDist2(const TrackVF& o) const + { + auto dt = timeEst.getTimeStamp() - o.timeEst.getTimeStamp(); + auto dte2 = timeEst.getTimeStampError() * timeEst.getTimeStampError() + o.timeEst.getTimeStampError() * o.timeEst.getTimeStampError(); + auto dtnorm2 = dt * dt / dte2; + auto dz = z - o.z; + return dtnorm2 + dz * dz * sig2ZI; + } + + // weighted distance^2 to other track (accounting for both track errors errors only) + float getDist2Sym(const TrackVF& o) const + { + auto dt = timeEst.getTimeStamp() - o.timeEst.getTimeStamp(); + auto dz = z - o.z; + float dte2 = o.timeEst.getTimeStampError() * o.timeEst.getTimeStampError() + timeEst.getTimeStampError() * timeEst.getTimeStampError(); + return dt / dte2 + dz * dz / (1. / sig2ZI + 1. / o.sig2ZI); + } + float getResiduals(const PVertex& vtx, float& dy, float& dz) const { // get residuals (Y and Z DCA in track frame) and calculate chi2 @@ -125,9 +157,32 @@ struct TrackVF { return (dy * dy * sig2YI + dz * dz * sig2ZI) + 2. * dy * dz * sigYZI; } + float getResiduals(const PVertex& vtx) const + { + // get residuals (Y and Z DCA in track frame) and calculate chi2 + float dx = vtx.getX() * cosAlp + vtx.getY() * sinAlp - x; // VX rotated to track frame - trackX + auto dy = y + tgP * dx - (-vtx.getX() * sinAlp + vtx.getY() * cosAlp); + auto dz = z + tgL * dx - vtx.getZ(); + return (dy * dy * sig2YI + dz * dz * sig2ZI) + 2. * dy * dz * sigYZI; + } + + float evalChi2ToVertex(const PVertex& vtx, bool useTime) + { + constexpr float NDOF2I = 1. / 2, NDOF3I = 1. / 3; + float chi2T = getResiduals(vtx); // track-vertex residuals and chi2 + if (useTime) { + float dt = timeEst.getTimeStamp() - vtx.getTimeStamp().getTimeStamp(); + chi2T += dt * dt / (timeEst.getTimeStampError() * timeEst.getTimeStampError()); + chi2T *= NDOF3I; + } else { + chi2T *= NDOF2I; + } + return chi2T; + } + TrackVF() = default; - TrackVF(const o2::track::TrackParCov& src, const TimeEst& t_est, uint32_t _entry, uint8_t _srcID) - : x(src.getX()), y(src.getY()), z(src.getZ()), tgL(src.getTgl()), tgP(src.getSnp() / std::sqrt(1. - src.getSnp()) * (1. + src.getSnp())), timeEst(t_est), entry(_entry), srcID(_srcID) + TrackVF(const o2::track::TrackParCov& src, const TimeEst& t_est, int _entry, GTrackID _gid, float addHTErr2 = 0., float addHZErr2 = 0.) + : x(src.getX()), y(src.getY()), z(src.getZ()), tgL(src.getTgl()), tgP(src.getSnp() / std::sqrt(1. - src.getSnp()) * (1. + src.getSnp())), timeEst(t_est), entry(_entry), gid(_gid) { o2::math_utils::sincos(src.getAlpha(), sinAlp, cosAlp); auto det = src.getSigmaY2() * src.getSigmaZ2() - src.getSigmaZY() * src.getSigmaZY(); @@ -135,169 +190,64 @@ struct TrackVF { sig2YI = src.getSigmaZ2() * detI; sig2ZI = src.getSigmaY2() * detI; sigYZI = -src.getSigmaZY() * detI; + wghHisto = 1. / ((src.getSigmaZ2() + addHZErr2) * (t_est.getTimeStampError() * t_est.getTimeStampError() + addHTErr2)); } }; -struct VertexingInput { - gsl::span<TrackVF> tracks; - gsl::span<int> idRange; - TimeEst timeEst{0, -1.}; // negative error means don't use time info - float scaleSigma2 = 10; - bool useConstraint = false; - bool fillErrors = true; -}; - -struct SeedHisto { - float range = 20; - float binSize = 0.5; - float binSizeInv = 0.; - int nFilled = 0; - std::vector<int> data; - - SeedHisto() = delete; - SeedHisto(float _range = 20., float _binsize = 0.5) : range(_range), binSize(_binsize) - { - auto zr = 2 * range; - int nzb = zr / binSize; - if (nzb * binSize < zr - 1e-9) { - nzb++; - } - binSizeInv = 1. / binSize; - range = nzb * binSize / 2.; - data.resize(nzb); - } - - int size() const { return data.size(); } - - void fill(float z) - { - incrementBin(findBin(z)); - } - - void incrementBin(int bin) - { - data[bin]++; - nFilled++; - } - - void decrementBin(int bin) - { - data[bin]--; - nFilled--; - } - - int findBin(float z) - { - auto d = z + range; - if (d < 0.) { - return 0; - } - uint32_t n = d * binSizeInv; - return n < data.size() ? n : data.size() - 1; - } +struct SeedHistoTZ : public o2::dataformats::FlatHisto2D_f { + using o2::dataformats::FlatHisto2D<float>::FlatHisto2D; - int findHighestPeakBin() const + int fillAndFlagBin(float x, float y, float w) { - if (nFilled < 2) { - return -1; - } - int n = data.size(), maxBin = -1, maxv = 0; - for (int i = 0; i < n; i++) { - if (data[i] > maxv) { - maxv = data[(maxBin = i)]; + uint32_t bin = getBin(x, y); + if (isValidBin(bin)) { + if (isBinEmpty(bin)) { + filledBins.push_back(bin); } + fillBin(bin, w); + nEntries++; + return bin; } - return maxBin; + return -1; } - bool isValidBin(int ib) const + void clear() { - return static_cast<uint32_t>(ib) < data.size(); + o2::dataformats::FlatHisto2D<float>::clear(); + filledBins.clear(); } - float getBinCenter(int ib) const - { - return (ib + 0.5) * binSize - range; // no check for being in the range!!! - } + int findPeakBin(); - void discardBin(int ib) - { // no check for being in the range!!! - nFilled -= data[ib]; - data[ib] = 0; - } + std::vector<int> filledBins; + int nEntries{}; }; -struct TimeCluster { - TimeEst timeEst; - int first = -1; - int last = -1; - int count = 0; - - void clear() - { - first = last = -1; - count = 0; - } - - void addTrack(int i, const TimeEst& trcT) - { - auto trcTErr2 = trcT.getTimeStampError() * trcT.getTimeStampError(); - auto trcTErr2Inv = 1. / trcTErr2; - if (first < 0) { - first = last = i; - timeEst.setTimeStamp(trcT.getTimeStamp()); - timeEst.setTimeStampError(trcT.getTimeStampError()); - } else { - auto vtxTErr2Inv = 1. / (timeEst.getTimeStampError() * timeEst.getTimeStampError()); - auto vtxTErr2UpdInv = trcTErr2Inv + vtxTErr2Inv; - auto vtxTErr2Upd = 1. / vtxTErr2UpdInv; - timeEst.setTimeStamp((timeEst.getTimeStamp() * vtxTErr2Inv + trcT.getTimeStamp() * trcTErr2Inv) * vtxTErr2Upd); - timeEst.setTimeStampError(std::sqrt(vtxTErr2Upd)); - if (i > last) { - last = i; - } - } - count++; - } - - bool isCompatible(const TimeEst& c, float margin, float cut) const - { - if (first < 0) { - return true; - } - float dt = timeEst.getTimeStamp() - c.getTimeStamp(); - if (c.getTimeStampError() && timeEst.getTimeStampError()) { - float trcTErr2 = c.getTimeStampError() * c.getTimeStampError(); - float err = trcTErr2 + timeEst.getTimeStampError() + margin; - return dt * dt / err < cut; - } else { - return std::abs(dt) < cut; - } - } +struct TimeZCluster { + std::vector<int> trackIDs{}; + TimeEst timeEst{}; +}; - void merge(TimeCluster& c) - { - if (c.first < last) { - first = c.first; - } else { - last = c.last; - } - if (timeEst.getTimeStampError() && c.timeEst.getTimeStampError()) { // weighted average - auto cTErr2 = c.timeEst.getTimeStampError() * c.timeEst.getTimeStampError(); - auto cTErr2Inv = 1. / cTErr2; +// structure to produce debug dump for neighbouring vertices comparison +struct PVtxCompDump { + PVertex vtx0{}; + PVertex vtx1{}; + float chi2z{0}; + float chi2t{0}; + bool rej = false; + PVtxCompDump() = default; + ClassDefNV(PVtxCompDump, 1); +}; - auto tErr2 = timeEst.getTimeStampError(); - auto tErr2Inv = 1. / (tErr2 * tErr2); - auto tErr2UpdInv = cTErr2Inv + tErr2Inv; - auto tErr2Upd = 1. / tErr2UpdInv; - timeEst.setTimeStamp((timeEst.getTimeStamp() * tErr2Inv + c.timeEst.getTimeStamp() * cTErr2Inv) * tErr2Upd); - timeEst.setTimeStampError(std::sqrt(tErr2Upd)); - } else { - timeEst.setTimeStamp((timeEst.getTimeStamp() * count + c.timeEst.getTimeStamp() * c.count) / (count + c.count)); - count += c.count; - c.count = 0; - } - } +// structure to produce debug dump for DBSCAN clusters +struct TrackVFDump { + float z = 0; + float ze2i = 0.; + float t = 0; + float te = 0; + float wh = 0.; + TrackVFDump() = default; + ClassDefNV(TrackVFDump, 1); }; } // namespace vertexing diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h index 42c45afdadbe4..be82807a392cc 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,25 +26,52 @@ namespace vertexing struct PVertexerParams : public o2::conf::ConfigurableParamHelper<PVertexerParams> { static constexpr float kDefTukey = 5.0f; ///< def.value for tukey constant - // parameters - float minZSeedRange = 0.5; ///< min proximity of Zseed which should be covered by 1st iteration - float zHistoRange = 20.; ///< +-range of the Zseed histo - float zHistoBinSize = 0.5; ///< size of the Zseed histo bin - float tukey = kDefTukey; ///< 1./[Tukey parameter]^2 + // DBSCAN clustering settings + float dbscanMaxDist2 = 9.; ///< distance^2 cut (eps^2). + float dbscanDeltaT = 10.; ///< abs. time difference cut, should be >= ITS ROF duration if ITS SA tracks used + float dbscanAdaptCoef = 0.1; ///< adapt dbscan minPts for each cluster as minPts=max(minPts, currentSize*dbscanAdaptCoef). + + int maxVerticesPerCluster = 10; ///< max vertices per time-z cluster to look for + int maxTrialsPerCluster = 100; ///< max unsucessful trials for vertex search per vertex + + // track selection + float dcaTolerance = 1.3; ///< consider tracks within this abs DCA to mean vertex + float pullIniCut = 9; ///< cut on pull (n^2 sigma) on dca to mean vertex + float maxTimeErrorMUS = 10.0; ///< max time error in ms of the track to account + + // histogramming and its weigths params + float histoBinZSize = 0.05; ///< size of the seedTZ histo bin Z + float histoBinTSize = 0.05; ///< size of the seedTZ histo bin T + float addTimeSigma2 = 0.1 * 0.1; ///< increment time error^2 by this amount when calculating histo weight + float addZSigma2 = 0.005 * 0.005; ///< increment z error^2 by this amount when calculating histo weight + + // fitting parameters + bool useMeanVertexConstraint = true; ///< use MeanVertex as extra measured point + float tukey = kDefTukey; ///< Tukey parameter + float iniScale2 = 5.; ///< initial scale to assign float minScale2 = 1.; ///< min slaling factor^2 float acceptableScale2 = 4.; ///< if below this factor, try to refit with minScale2 - float maxScale2 = 1.e6; ///< max slaling factor^2 + float maxScale2 = 50; ///< max slaling factor^2 float upscaleFactor = 9.; ///< factor for upscaling if not candidate is found float slowConvergenceFactor = 0.5; ///< consider convergence as slow if ratio new/old scale2 exceeds it - // - // validation with FT0 - bool requireFT0ValidTimeMean = false; //true;///< require both FT0A/C - int minNContributorsForFT0cut = 4; ///< do not apply FT0 cut to vertice below FT0 efficiency threshold + + // cleanup + bool applyDebrisReduction = true; ///< apply algorithm reducing split vertices + bool applyReattachment = true; ///< refit vertices reattaching tracks to closest found vertex + float timeMarginReattach = 1.; ///< safety marging for track time vs vertex time difference during reattachment + float maxTDiffDebris = 7.0; ///< when reducing debris, don't consider vertices separated by time > this value in \mus + float maxZDiffDebris = 1.0; ///< don't consider vertices separated by Z > this value in cm + float maxMultRatDebris = 0.05; ///< don't consider vertices with multiplicity ratio above this + float maxChi2TZDebris = 2000.; ///< don't consider vertices with mutual chi2 exceeding this (for pp should be ~10) + float addTimeSigma2Debris = 0.05 * 0.05; ///< increment time error^2 by this amount when calculating vertex-to-vertex chi2 + float addZSigma2Debris = 0.005 * 0.005; ///< increment z error^2 by this amount when calculating vertex-to-vertex chi2 + + // validation with externally provided InteractionRecords (e.g. from FT0) + int minNContributorsForIRcut = 4; ///< do not apply IR cut to vertices below IR tagging efficiency threshold float maxTError = 0.2; ///< use min of vertex time error or this for nsigma evaluation float minTError = 0.003; ///< don't use error smaller than that (~BC/2/minNContributorsForFT0cut) float nSigmaTimeCut = 4.; ///< eliminate vertex if there is no FT0 signal within this cut - float timeBiasMS = -0.035; ///< relative bias in ms to add to TPCITS-based time stamp - + float timeBiasMS = 0; ///< relative bias in ms to add to TPCITS-based time stamp // // stopping condition params float maxChi2Mean = 10.; ///< max mean chi2 of vertex to accept diff --git a/Detectors/Vertexing/include/DetectorsVertexing/SVertexHypothesis.h b/Detectors/Vertexing/include/DetectorsVertexing/SVertexHypothesis.h new file mode 100644 index 0000000000000..8309e79e3424e --- /dev/null +++ b/Detectors/Vertexing/include/DetectorsVertexing/SVertexHypothesis.h @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SVertexHypothesis.h +/// \brief V0 or Cascade hypothesis checker +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_SVERTEX_HYPOTHESIS_H +#define ALICEO2_SVERTEX_HYPOTHESIS_H + +#include "ReconstructionDataFormats/PID.h" +#include <cmath> +#include <array> + +namespace o2 +{ +namespace vertexing +{ + +class SVertexHypothesis +{ + + public: + using PID = o2::track::PID; + enum PIDParams { SigmaM, // sigma of mass res at 0 pt + NSigmaM, // number of sigmas of mass res + MarginM, // additive safety margin in mass cut + CPt }; // pT dependence of mass resolution parameterized as mSigma*(1+mC1*pt); + + static constexpr int NPIDParams = 4; + + void set(PID v0, PID ppos, PID pneg, float sig, float nSig, float margin, float cpt, float bz = 0.f); + void set(PID v0, PID ppos, PID pneg, const float pars[NPIDParams], float bz = 0.f); + + float getMassV0Hyp() const { return PID::getMass(mPIDV0); } + float getMassPosProng() const { return PID::getMass(mPIDPosProng); } + float getMassNegProng() const { return PID::getMass(mPIDNegProng); } + + float calcMass2(float p2Pos, float p2Neg, float p2V0) const + { + // calculate v0 mass from squared momentum of its prongs and total momentum + float ePos = std::sqrt(p2Pos + getMass2PosProng()), eNeg = std::sqrt(p2Neg + getMass2NegProng()), eV0 = ePos + eNeg; + return eV0 * eV0 - p2V0; + } + + float calcMass(float p2Pos, float p2Neg, float p2V0) const { return std::sqrt(calcMass2(p2Pos, p2Neg, p2V0)); } + + bool check(float p2Pos, float p2Neg, float p2V0, float ptV0) const + { // check if given mass and pt is matching to hypothesis + return check(calcMass(p2Pos, p2Neg, p2V0), ptV0); + } + + bool check(float mass, float pt) const + { // check if given mass and pt is matching to hypothesis + return std::abs(mass - getMassV0Hyp()) < getMargin(pt); + } + + float getSigma(float pt) const { return mPars[SigmaM] * (1.f + mPars[CPt] * pt); } + float getMargin(float pt) const { return mPars[NSigmaM] * getSigma(pt) + mPars[MarginM]; } + + private: + float getMass2PosProng() const { return PID::getMass2(mPIDPosProng); } + float getMass2NegProng() const { return PID::getMass2(mPIDNegProng); } + + PID mPIDV0{PID::K0}; + PID mPIDPosProng{PID::Pion}; + PID mPIDNegProng{PID::Pion}; + + std::array<float, NPIDParams> mPars{}; + + ClassDefNV(SVertexHypothesis, 1); +}; + +} // namespace vertexing +} // namespace o2 + +#endif diff --git a/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h b/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h index db00b27d0c735..bbc127d1cc760 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,17 +16,18 @@ #define O2_S_VERTEXER_H #include "gsl/span" +#include "DataFormatsGlobalTracking/RecoContainer.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/Cascade.h" #include "ReconstructionDataFormats/VtxTrackIndex.h" #include "ReconstructionDataFormats/VtxTrackRef.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" -#include "DataFormatsTPC/TrackTPC.h" -#include "DataFormatsITS/TrackITS.h" #include "CommonDataFormat/RangeReference.h" #include "DetectorsVertexing/DCAFitterN.h" #include "DetectorsVertexing/SVertexerParams.h" -#include "DetectorsVertexing/V0Hypothesis.h" +#include "DetectorsVertexing/SVertexHypothesis.h" +#include <numeric> +#include <algorithm> namespace o2 { @@ -41,79 +43,165 @@ class SVertexer using VRef = o2::dataformats::VtxTrackRef; using PVertex = const o2::dataformats::PrimaryVertex; using V0 = o2::dataformats::V0; - using TrackTPCITS = o2::dataformats::TrackTPCITS; - using TrackITS = o2::its::TrackITS; - using TrackTPC = o2::tpc::TrackTPC; + using Cascade = o2::dataformats::Cascade; using RRef = o2::dataformats::RangeReference<int, int>; + using VBracket = o2::math_utils::Bracket<int>; - // struct to access tracks and extra info from different sources - struct TrackAccessor { - static constexpr std::array<size_t, GIndex::NSources> sizes{sizeof(TrackTPCITS), sizeof(TrackITS), sizeof(TrackTPC)}; - std::array<const char*, GIndex::NSources> startOfSource{}; - std::array<std::vector<char>, GIndex::NSources> charges; - - TrackAccessor(const gsl::span<const TrackTPCITS>& tpcits, const gsl::span<const TrackITS>& its, const gsl::span<const TrackTPC>& tpc) - { - if (tpcits.size()) { - startOfSource[GIndex::TPCITS] = reinterpret_cast<const char*>(tpcits.data()); - auto& ch = charges[GIndex::TPCITS]; - ch.resize(tpcits.size()); - for (uint32_t ic = 0; ic < tpcits.size(); ic++) { - ch[ic] = tpcits[ic].getCharge(); - } - } - if (its.size()) { - startOfSource[GIndex::ITS] = reinterpret_cast<const char*>(its.data()); - auto& ch = charges[GIndex::ITS]; - ch.resize(its.size()); - for (uint32_t ic = 0; ic < its.size(); ic++) { - ch[ic] = its[ic].getCharge(); - } - } - if (tpc.size()) { - startOfSource[GIndex::TPC] = reinterpret_cast<const char*>(tpc.data()); - auto& ch = charges[GIndex::TPC]; - ch.resize(tpc.size()); - for (uint32_t ic = 0; ic < tpc.size(); ic++) { - ch[ic] = tpc[ic].getCharge(); - } - } - } - char getCharge(GIndex id) const { return getCharge(id.getSource(), id.getIndex()); } - char getCharge(int src, int idx) const { return charges[src][idx]; } - const o2::track::TrackParCov& getTrack(GIndex id) const { return getTrack(id.getSource(), id.getIndex()); } - const o2::track::TrackParCov& getTrack(int src, int idx) const { return *reinterpret_cast<const o2::track::TrackParCov*>(startOfSource[src] + sizes[src] * idx); } + enum HypV0 { Photon, + K0, + Lambda, + AntiLambda, + HyperTriton, + AntiHyperTriton, + NHypV0 }; + + enum HypCascade { + XiMinus, + OmegaMinus, + NHypCascade + }; + + static constexpr int POS = 0, NEG = 1; + struct TrackCand : o2::track::TrackParCov { + GIndex gid{}; + VBracket vBracket{}; + float minR = 0; // track lowest point r }; + SVertexer(bool enabCascades = true) : mEnableCascades(enabCascades) {} + + void setEnableCascades(bool v) { mEnableCascades = v; } void init(); - void process(const gsl::span<const PVertex>& vertices, // primary vertices - const gsl::span<const GIndex>& trackIndex, // Global ID's for associated tracks - const gsl::span<const VRef>& vtxRefs, // references from vertex to these track IDs - const gsl::span<const TrackTPCITS>& tpcits, // global tracks - const gsl::span<const TrackITS>& its, // ITS tracks - const gsl::span<const TrackTPC>& tpc, // TPC tracks - std::vector<V0>& v0s, // found V0s - std::vector<RRef>& vtx2V0refs // references from PVertex to V0 - ); + void process(const o2::globaltracking::RecoContainer& recoTracks); // accessor to various tracks auto& getMeanVertex() const { return mMeanVertex; } void setMeanVertex(const o2d::VertexBase& v) { mMeanVertex = v; } + void setNThreads(int n); + int getNThreads() const { return mNThreads; } + + template <typename V0CONT, typename V0REFCONT, typename CASCCONT, typename CASCREFCONT> + void extractSecondaryVertices(V0CONT& v0s, V0REFCONT& vtx2V0Refs, CASCCONT& cascades, CASCREFCONT& vtx2CascRefs); private: + bool checkV0(const TrackCand& seed0, const TrackCand& seed1, int iP, int iN, int ithread); + int checkCascades(float rv0, std::array<float, 3> pV0, float p2v0, int avoidTrackID, int posneg, int ithread); + void setupThreads(); + void buildT2V(const o2::globaltracking::RecoContainer& recoTracks); + void updateTimeDependentParams(); + uint64_t getPairIdx(GIndex id1, GIndex id2) const { return (uint64_t(id1) << 32) | id2; } + + gsl::span<const PVertex> mPVertices; + std::vector<std::vector<V0>> mV0sTmp; + std::vector<std::vector<Cascade>> mCascadesTmp; + std::array<std::vector<TrackCand>, 2> mTracksPool{}; // pools of positive and negative seeds sorted in min VtxID + std::array<std::vector<int>, 2> mVtxFirstTrack{}; // 1st pos. and neg. track of the pools for each vertex o2d::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; const SVertexerParams* mSVParams = nullptr; - std::array<V0Hypothesis, SVertexerParams::NPIDV0> mV0Hyps; - DCAFitterN<2> mFitter2Prong; + std::array<SVertexHypothesis, NHypV0> mV0Hyps; + std::array<SVertexHypothesis, NHypCascade> mCascHyps; + std::vector<DCAFitterN<2>> mFitterV0; + std::vector<DCAFitterN<2>> mFitterCasc; + int mNThreads = 1; float mMinR2ToMeanVertex = 0; float mMaxDCAXY2ToMeanVertex = 0; - float mMinCosPointingAngle = 0; + float mMaxDCAXY2ToMeanVertexV0Casc = 0; + float mMinR2DiffV0Casc = 0; + float mMaxR2ToMeanVertexCascV0 = 0; + float mMinPt2V0 = 1e-6; + float mMaxTgl2V0 = 2. * 2.; + float mMinPt2Casc = 1e-4; + float mMaxTgl2Casc = 2. * 2.; + bool mEnableCascades = true; }; +// input containers can be std::vectors or pmr vectors +template <typename V0CONT, typename V0REFCONT, typename CASCCONT, typename CASCREFCONT> +void SVertexer::extractSecondaryVertices(V0CONT& v0s, V0REFCONT& vtx2V0Refs, CASCCONT& cascades, CASCREFCONT& vtx2CascRefs) +{ + v0s.clear(); + vtx2V0Refs.clear(); + vtx2V0Refs.resize(mPVertices.size()); + cascades.clear(); + vtx2CascRefs.clear(); + vtx2CascRefs.resize(mPVertices.size()); + + auto& tmpV0s = mV0sTmp[0]; + auto& tmpCascs = mCascadesTmp[0]; + int nv0 = tmpV0s.size(), nCasc = tmpCascs.size(); + std::vector<int> v0SortID(nv0), v0NewInd(nv0), cascSortID(nCasc); + std::iota(v0SortID.begin(), v0SortID.end(), 0); + std::sort(v0SortID.begin(), v0SortID.end(), [&](int i, int j) { return tmpV0s[i].getVertexID() < tmpV0s[j].getVertexID(); }); + std::iota(cascSortID.begin(), cascSortID.end(), 0); + std::sort(cascSortID.begin(), cascSortID.end(), [&](int i, int j) { return tmpCascs[i].getVertexID() < tmpCascs[j].getVertexID(); }); + + // relate V0s to primary vertices + int pvID = -1, nForPV = 0; + for (int iv = 0; iv < nv0; iv++) { + const auto& v0 = tmpV0s[v0SortID[iv]]; + if (pvID < v0.getVertexID()) { + if (pvID > -1) { + vtx2V0Refs[pvID].setEntries(nForPV); + } + pvID = v0.getVertexID(); + vtx2V0Refs[pvID].setFirstEntry(v0s.size()); + nForPV = 0; + } + v0NewInd[v0SortID[iv]] = v0s.size(); // memorise updated v0 id to fix its reference in the cascade + v0s.push_back(v0); + nForPV++; + } + if (pvID != -1) { // finalize + vtx2V0Refs[pvID].setEntries(nForPV); + // fill empty slots + int ent = v0s.size(); + for (int ip = vtx2V0Refs.size(); ip--;) { + if (vtx2V0Refs[ip].getEntries()) { + ent = vtx2V0Refs[ip].getFirstEntry(); + } else { + vtx2V0Refs[ip].setFirstEntry(ent); + } + } + } + // update V0s references in cascades + for (auto& casc : tmpCascs) { + casc.setV0ID(v0NewInd[casc.getV0ID()]); + } + + // relate Cascades to primary vertices + pvID = -1; + nForPV = 0; + for (int iv = 0; iv < nCasc; iv++) { + const auto& casc = tmpCascs[cascSortID[iv]]; + if (pvID < casc.getVertexID()) { + if (pvID > -1) { + vtx2CascRefs[pvID].setEntries(nForPV); + } + pvID = casc.getVertexID(); + vtx2CascRefs[pvID].setFirstEntry(cascades.size()); + nForPV = 0; + } + cascades.push_back(casc); + nForPV++; + } + if (pvID != -1) { // finalize + vtx2CascRefs[pvID].setEntries(nForPV); + // fill empty slots + int ent = cascades.size(); + for (int ip = vtx2CascRefs.size(); ip--;) { + if (vtx2CascRefs[ip].getEntries()) { + ent = vtx2CascRefs[ip].getFirstEntry(); + } else { + vtx2CascRefs[ip].setFirstEntry(ent); + } + } + } +} + } // namespace vertexing } // namespace o2 diff --git a/Detectors/Vertexing/include/DetectorsVertexing/SVertexerParams.h b/Detectors/Vertexing/include/DetectorsVertexing/SVertexerParams.h index 96ac7cfde2f14..c66361fd5dd66 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/SVertexerParams.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/SVertexerParams.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "CommonUtils/ConfigurableParam.h" #include "CommonUtils/ConfigurableParamHelper.h" +#include "DetectorsVertexing/SVertexHypothesis.h" namespace o2 { @@ -26,40 +28,49 @@ namespace vertexing // These are configurable params for Primary Vertexer struct SVertexerParams : public o2::conf::ConfigurableParamHelper<SVertexerParams> { - enum PIDV0 { Photon, - K0, - Lambda, - AntiLambda, - HyperTriton, - AntiHyperTriton, - NPIDV0 }; - enum PIDParams { SigmaMV0, - NSigmaMV0, - Margin, - CPt, - NPIDParams }; // parameters float maxChi2 = 2.; ///< max dca from prongs to vertex float minParamChange = 1e-3; ///< stop when tracks X-params being minimized change by less that this value float minRelChi2Change = 0.9; ///< stop when chi2 changes by less than this value float maxDZIni = 5.; ///< don't consider as a seed (circles intersection) if Z distance exceeds this float maxRIni = 150; ///< don't consider as a seed (circles intersection) if its R exceeds this - bool useAbsDCA = true; ///< use abs dca minimization // - float minRfromMeanVertex = 0.5; ///< min radial distance of V0 from beam line (mean vertex) - float maxDCAXYfromMeanVertex = 0.2; ///< min DCA of V0 from beam line (mean vertex) - float minCosPointingAngle = 0.8; - // cuts on different PID params - float pidCuts[NPIDV0][NPIDParams] = { - // - {0.001, 20, 0.6, 0.}, // Photon - {0.003, 20, 0.07, 0.5}, // K0 - {0.001, 20, 0.07, 0.5}, // Lambda - {0.001, 20, 0.07, 0.5}, // AntiLambda - {0.0025, 14, 0.07, 0.5}, // HyperTriton - {0.0025, 14, 0.07, 0.5} // AntiHyperTriton - }; + float minRToMeanVertex = 0.5; ///< min radial distance of V0 from beam line (mean vertex) + float maxDCAXYToMeanVertex = 0.2; ///< max DCA of V0 from beam line (mean vertex) for prompt V0 candidates + float maxDCAXYToMeanVertexV0Casc = 0.5; ///< max DCA of V0 from beam line (mean vertex) for cascade V0 candidates + float minPtV0 = 0.01; ///< v0 minimum pT + float maxTglV0 = 2.; ///< maximum tgLambda of V0 + + float causalityRTolerance = 1.; ///< V0 radius cannot exceed its contributors minR by more than this value + float maxV0ToProngsRDiff = 50.; ///< V0 radius cannot be lower than this ammount wrt minR of contributors + + float minCosPAXYMeanVertex = 0.85; ///< min cos of PA to beam line (mean vertex) in tr. plane for prompt V0 candidates + float minCosPAXYMeanVertexCascV0 = 0.8; ///< min cos of PA to beam line (mean vertex) in tr. plane for V0 of cascade cand. + + float maxRToMeanVertexCascV0 = 80; // don't consider as a cascade V0 seed if above this R + float minCosPACascV0 = 0.8; // min cos of pointing angle to PV for cascade V0 candidates + + float minCosPA = 0.9; ///< min cos of PA to PV for prompt V0 candidates + + float minRDiffV0Casc = 0.2; ///< cascade should be at least this radial distance below V0 + float maxRIniCasc = 50.; // don't consider as a cascade seed (circles/line intersection) if its R exceeds this + + float maxDCAXYCasc = 0.3; // max DCA of cascade to PV in XY // TODO RS: shall we use real chi2 to vertex? + float maxDCAZCasc = 0.3; // max DCA of cascade to PV in Z + float minCosPACasc = 0.7; ///< min cos of PA to PV for cascade candidates + float minPtCasc = 0.01; // cascade minimum pT + float maxTglCasc = 2.; // maximum tgLambda of cascade + + // cuts on different V0 PID params + float pidCutsPhoton[SVertexHypothesis::NPIDParams] = {0.001, 20, 0.60, 0.0}; // Photon + float pidCutsK0[SVertexHypothesis::NPIDParams] = {0.003, 20, 0.07, 0.5}; // K0 + float pidCutsLambda[SVertexHypothesis::NPIDParams] = {0.001, 20, 0.07, 0.5}; // Lambda + float pidCutsHTriton[SVertexHypothesis::NPIDParams] = {0.0025, 14, 0.07, 0.5}; // HyperTriton + // + // cuts on different Cascade PID params + float pidCutsXiMinus[SVertexHypothesis::NPIDParams] = {0.001, 20, 0.07, 0.5}; // XiMinus + float pidCutsOmegaMinus[SVertexHypothesis::NPIDParams] = {0.001, 20, 0.07, 0.5}; // OmegaMinus O2ParamDef(SVertexerParams, "svertexer"); }; diff --git a/Detectors/Vertexing/include/DetectorsVertexing/V0Hypothesis.h b/Detectors/Vertexing/include/DetectorsVertexing/V0Hypothesis.h deleted file mode 100644 index 8a95d9d6a6d9e..0000000000000 --- a/Detectors/Vertexing/include/DetectorsVertexing/V0Hypothesis.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file V0Hypothesis.h -/// \brief V0 hypothesis checker -/// \author ruben.shahoyan@cern.ch - -#ifndef ALICEO2_V0_HYPOTHESIS_H -#define ALICEO2_V0_HYPOTHESIS_H - -#include "ReconstructionDataFormats/PID.h" -#include "DetectorsVertexing/SVertexerParams.h" - -namespace o2 -{ -namespace vertexing -{ - -class V0Hypothesis -{ - - public: - using PID = o2::track::PID; - - void set(PID v0, PID ppos, PID pneg, float sig, float nSig, float margin, float cpt, float bz = 0.f); - void set(PID v0, PID ppos, PID pneg, const float pars[SVertexerParams::NPIDParams], float bz = 0.f); - - float getMassV0Hyp() const { return PID::getMass(mPIDV0); } - float getMassPosProng() const { return PID::getMass(mPIDPosProng); } - float getMassNegProng() const { return PID::getMass(mPIDNegProng); } - - float calcMass2(float p2Pos, float p2Neg, float p2V0) const - { - // calculate v0 mass from squared momentum of its prongs and total momentum - float ePos = std::sqrt(p2Pos + getMass2PosProng()), eNeg = std::sqrt(p2Neg + getMass2NegProng()), eV0 = ePos + eNeg; - return eV0 * eV0 - p2V0; - } - - float calcMass(float p2Pos, float p2Neg, float p2V0) const { return std::sqrt(calcMass2(p2Pos, p2Neg, p2V0)); } - - bool check(float p2Pos, float p2Neg, float p2V0, float ptV0) const - { // check if given mass and pt is matching to hypothesis - return check(calcMass(p2Pos, p2Neg, p2V0), ptV0); - } - - bool check(float mass, float pt) const - { // check if given mass and pt is matching to hypothesis - return std::abs(mass - getMassV0Hyp()) < getMargin(pt); - } - - float getSigma(float pt) const { return 1.f + mCPt * pt; } - float getMargin(float pt) const { return mNSigma * getSigma(pt) + mMargin; } - - private: - float getMass2PosProng() const { return PID::getMass2(mPIDPosProng); } - float getMass2NegProng() const { return PID::getMass2(mPIDNegProng); } - - PID mPIDV0 = PID::K0; - PID mPIDPosProng = PID::Pion; - PID mPIDNegProng = PID::Pion; - - float mNSigma = 0.; // number of sigmas of mass res - float mSigma = 0.; // sigma of mass res at 0 pt - float mMargin = 0.; // additive safety margin in mass cut - float mCPt = 0.; // pT dependence of mass resolution parameterized as mSigma*(1+mC1*pt); - - ClassDefNV(V0Hypothesis, 1); -}; - -} // namespace vertexing -} // namespace o2 - -#endif diff --git a/Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h b/Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h index 958ca4735a0bd..2bb12624120c9 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,13 +20,11 @@ #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/VtxTrackIndex.h" #include "ReconstructionDataFormats/VtxTrackRef.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" -#include "DataFormatsTPC/TrackTPC.h" -#include "DataFormatsITS/TrackITS.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "CommonDataFormat/InteractionRecord.h" #include "DetectorsVertexing/PVertexerParams.h" #include "MathUtils/Primitive2D.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" namespace o2 { @@ -35,52 +34,39 @@ namespace vertexing class VertexTrackMatcher { public: - using GIndex = o2::dataformats::VtxTrackIndex; + using GIndex = o2::dataformats::GlobalTrackID; + using VTIndex = o2::dataformats::VtxTrackIndex; using VRef = o2::dataformats::VtxTrackRef; using PVertex = const o2::dataformats::PrimaryVertex; - using TrackTPCITS = o2::dataformats::TrackTPCITS; - using TrackITS = o2::its::TrackITS; - using ITSROFR = o2::itsmft::ROFRecord; - using TrackTPC = o2::tpc::TrackTPC; - using TmpMap = std::unordered_map<int, std::vector<GIndex>>; + using TmpMap = std::vector<std::vector<VTIndex>>; using TimeEst = o2::dataformats::TimeStampWithError<float, float>; using TBracket = o2::math_utils::Bracketf_t; - void init(); - void process(const gsl::span<const PVertex>& vertices, // vertices - const gsl::span<const GIndex>& v2tfitIDs, // IDs of contributor tracks used in fit - const gsl::span<const VRef>& v2tfitRefs, // references on these tracks (we used special reference with multiple sources, but currently only TPCITS used) - const gsl::span<const TrackTPCITS>& tpcits, // global tracks - const gsl::span<const TrackITS>& its, // ITS tracks - const gsl::span<const ITSROFR>& itsROFR, // ITS tracks ROFRecords - const gsl::span<const TrackTPC>& tpc, // TPC tracks - std::vector<GIndex>& trackIndex, // Global ID's for associated tracks - std::vector<VRef>& vtxRefs); // references on these tracks + struct TrackTBracket { + TBracket tBracket{}; ///< bracketing time in ns + GIndex origID{}; ///< track origin id + }; + struct VtxTBracket { + TBracket tBracket{}; ///< bracketing time in ns + int origID = -1; ///< vertex origin id + }; - ///< set InteractionRecods for the beginning of the TF - void setStartIR(const o2::InteractionRecord& ir) { mStartIR = ir; } - void setITSROFrameLengthInBC(int nbc); - int getITSROFrameLengthInBC() const { return mITSROFrameLengthInBC; } + void init(); + void process(const o2::globaltracking::RecoContainer& recoData, + std::vector<VTIndex>& trackIndex, // Global ID's for associated tracks + std::vector<VRef>& vtxRefs); // references on these tracks private: - void attachTPCITS(TmpMap& tmpMap, const gsl::span<const TrackTPCITS>& tpcits, const std::vector<int>& idTPCITS, const gsl::span<const PVertex>& vertices); - void attachITS(TmpMap& tmpMap, const gsl::span<const TrackITS>& its, const gsl::span<const ITSROFR>& itsROFR, const std::vector<int>& flITS, - const gsl::span<const PVertex>& vertices, std::vector<int>& idxVtx); - void attachTPC(TmpMap& tmpMap, const std::vector<TBracket>& tpcTimes, const std::vector<int>& idTPC, const gsl::span<const PVertex>& vertices, std::vector<int>& idVtx); - bool compatibleTimes(const TimeEst& vtxT, const TimeEst& trcT) const; - void updateTPCTimeDependentParams(); - float tpcTimeBin2MUS(float t) - { // convert TPC time bin to microseconds - return t * mTPCBin2MUS; - } + void updateTimeDependentParams(); + void extractTracks(const o2::globaltracking::RecoContainer& data, const std::unordered_map<GIndex, bool>& vcont); - o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF - int mITSROFrameLengthInBC = 0; ///< ITS RO frame in BC (for ITS cont. mode only) + std::vector<TrackTBracket> mTBrackets; + float mITSROFrameLengthMUS = 0; ///< ITS RO frame in mus + float mMFTROFrameLengthMUS = 0; ///< MFT RO frame in mus float mMaxTPCDriftTimeMUS = 0; float mTPCBin2MUS = 0; const o2::vertexing::PVertexerParams* mPVParams = nullptr; - ClassDefNV(VertexTrackMatcher, 1); }; } // namespace vertexing diff --git a/Detectors/Vertexing/src/DCAFitterN.cxx b/Detectors/Vertexing/src/DCAFitterN.cxx index 204794651a9ed..e585648418bbc 100644 --- a/Detectors/Vertexing/src/DCAFitterN.cxx +++ b/Detectors/Vertexing/src/DCAFitterN.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Vertexing/src/DetectorsVertexingLinkDef.h b/Detectors/Vertexing/src/DetectorsVertexingLinkDef.h index 14703c3d763b6..d4ed40871e273 100644 --- a/Detectors/Vertexing/src/DetectorsVertexingLinkDef.h +++ b/Detectors/Vertexing/src/DetectorsVertexingLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,17 +15,13 @@ #pragma link off all classes; #pragma link off all functions; -// this aliase are defined in the DCAFitterN.h as o2::vertexing::DCAFitterN<2,o2::track::TrackParCov> -#pragma link C++ class o2::vertexing::DCAFitter2 + ; -// this aliase are defined in the DCAFitterN.h as o2::vertexing::DCAFitterN<3,o2::track::TrackParCov> -#pragma link C++ class o2::vertexing::DCAFitter3 + ; +#pragma link C++ class o2::vertexing::DCAFitterN < 2, o2::track::TrackParCov> + ; +#pragma link C++ class o2::vertexing::DCAFitterN < 3, o2::track::TrackParCov> + ; -#pragma link C++ class o2::vertexing::PVertexer + ; #pragma link C++ class o2::vertexing::PVertexerParams + ; -#pragma link C++ class o2::vertexing::VertexTrackMatcher + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::vertexing::PVertexerParams> + ; -#pragma link C++ class o2::vertexing::SVertexer + ; +#pragma link C++ class o2::vertexing::SVertexHypothesis + ; #pragma link C++ class o2::vertexing::SVertexerParams + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::vertexing::SVertexerParams> + ; @@ -34,4 +31,10 @@ #pragma link C++ function o2::vertexing::DCAFitter2::process(const o2::track::TrackParCov&, const o2::track::TrackParCov&); #pragma link C++ function o2::vertexing::DCAFitter3::process(const o2::track::TrackParCov&, const o2::track::TrackParCov&, const o2::track::TrackParCov&); +#pragma link C++ class o2::vertexing::TrackVFDump + ; +#pragma link C++ class std::vector < o2::vertexing::TrackVFDump> + ; + +#pragma link C++ class o2::vertexing::PVtxCompDump + ; +#pragma link C++ class std::vector < o2::vertexing::PVtxCompDump> + ; + #endif diff --git a/Detectors/Vertexing/src/PVertexer.cxx b/Detectors/Vertexing/src/PVertexer.cxx index 9bddad9bed829..030ac305d0c90 100644 --- a/Detectors/Vertexing/src/PVertexer.cxx +++ b/Detectors/Vertexing/src/PVertexer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,12 +14,13 @@ /// \author ruben.shahoyan@cern.ch #include "DetectorsVertexing/PVertexer.h" -#include "ReconstructionDataFormats/DCA.h" #include "DetectorsBase/Propagator.h" #include "Math/SMatrix.h" #include "Math/SVector.h" -#include <numeric> #include <unordered_map> +#include <TStopwatch.h> +#include "CommonUtils/StringUtils.h" // RS REM +#include <TH2F.h> using namespace o2::vertexing; @@ -27,25 +29,26 @@ constexpr double PVertexer::kAlmost0D; constexpr float PVertexer::kHugeF; //___________________________________________________________________ -int PVertexer::process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span<const o2::ft0::RecPoints> ft0Data, - std::vector<PVertex>& vertices, std::vector<GIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs) +int PVertexer::runVertexing(const gsl::span<o2d::GlobalTrackID> gids, const gsl::span<o2::InteractionRecord> bcData, + std::vector<PVertex>& vertices, std::vector<o2d::VtxTrackIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, + gsl::span<const o2::MCCompLabel> lblTracks, std::vector<o2::MCEventLabel>& lblVtx) { - createTracksPool(tracksITSTPC); - - //clusterizeTimeBruteForce(); - clusterizeTime(); - + dbscan_clusterize(); std::vector<PVertex> verticesLoc; - std::vector<int> vertexTrackIDsLoc; + std::vector<uint32_t> trackIDs; std::vector<V2TRef> v2tRefsLoc; std::vector<float> validationTimes; + std::vector<o2::MCEventLabel> lblVtxLoc; - for (auto tc : mTimesClusters) { + for (auto tc : mTimeZClusters) { VertexingInput inp; - inp.idRange = gsl::span<int>((int*)&mSortedTrackID[tc.first], tc.count); - inp.scaleSigma2 = 3. * estimateScale2(); + inp.idRange = gsl::span<int>(tc.trackIDs); + inp.scaleSigma2 = mPVParams->iniScale2; inp.timeEst = tc.timeEst; - findVertices(inp, verticesLoc, vertexTrackIDsLoc, v2tRefsLoc); +#ifdef _PV_DEBUG_TREE_ + doDBScanDump(inp, lblTracks); +#endif + findVertices(inp, verticesLoc, trackIDs, v2tRefsLoc); } // sort in time @@ -55,39 +58,67 @@ int PVertexer::process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span return verticesLoc[i].getTimeStamp().getTimeStamp() < verticesLoc[j].getTimeStamp().getTimeStamp(); }); +#ifdef _PV_DEBUG_TREE_ + if (lblTracks.size()) { // at this stage labels are needed just for the debug output + createMCLabels(lblTracks, trackIDs, v2tRefsLoc, lblVtxLoc); + } +#endif + + if (mPVParams->applyDebrisReduction) { + reduceDebris(verticesLoc, vtTimeSortID, lblVtxLoc); + } + if (mPVParams->applyReattachment) { + reAttach(verticesLoc, vtTimeSortID, trackIDs, v2tRefsLoc); + } + + if (lblTracks.size()) { // at this stage labels are needed just for the debug output + createMCLabels(lblTracks, trackIDs, v2tRefsLoc, lblVtxLoc); + } + +#ifdef _PV_DEBUG_TREE_ + doVtxDump(verticesLoc, trackIDs, v2tRefsLoc, lblTracks); +#endif + vertices.clear(); v2tRefs.clear(); vertexTrackIDs.clear(); vertices.reserve(verticesLoc.size()); v2tRefs.reserve(v2tRefsLoc.size()); - vertexTrackIDs.reserve(vertexTrackIDsLoc.size()); + vertexTrackIDs.reserve(trackIDs.size()); int trCopied = 0, count = 0, vtimeID = 0; for (auto i : vtTimeSortID) { + if (i < 0) { + continue; // vertex was suppressed + } auto& vtx = verticesLoc[i]; bool irSet = setCompatibleIR(vtx); if (!irSet) { continue; } - // do we need to validate by FT0 ? - if (mValidateWithFT0) { - auto bestMatch = getBestFT0Trigger(vtx, ft0Data, vtimeID); + // do we need to validate by Int. records ? + if (mValidateWithIR) { + auto bestMatch = getBestIR(vtx, bcData, vtimeID); if (bestMatch.first >= 0) { vtx.setFlags(PVertex::TimeValidated); if (bestMatch.second == 1) { - vtx.setIR(ft0Data[bestMatch.first].getInteractionRecord()); + vtx.setIR(bcData[bestMatch.first]); } LOG(DEBUG) << "Validated with t0 " << bestMatch.first << " with " << bestMatch.second << " candidates"; - } else if (vtx.getNContributors() >= mPVParams->minNContributorsForFT0cut) { + } else if (vtx.getNContributors() >= mPVParams->minNContributorsForIRcut) { LOG(DEBUG) << "Discarding " << vtx; continue; // reject } } vertices.push_back(vtx); + if (lblVtxLoc.size()) { + lblVtx.push_back(lblVtxLoc[i]); + } int it = v2tRefsLoc[i].getFirstEntry(), itEnd = it + v2tRefsLoc[i].getEntries(), dest0 = vertexTrackIDs.size(); for (; it < itEnd; it++) { - auto& gid = vertexTrackIDs.emplace_back(vertexTrackIDsLoc[it], GIndex::TPCITS); + const auto& trc = mTracksPool[trackIDs[it]]; + auto& gid = vertexTrackIDs.emplace_back(trc.gid); // assign global track ID gid.setPVContributor(); } v2tRefs.emplace_back(dest0, v2tRefsLoc[i].getEntries()); @@ -97,64 +128,55 @@ int PVertexer::process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span return vertices.size(); } -//___________________________________________________________________ -int PVertexer::process(gsl::span<const o2d::TrackTPCITS> tracksITSTPC, gsl::span<const o2::ft0::RecPoints> ft0Data, - std::vector<PVertex>& vertices, std::vector<GIndex>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs, - gsl::span<const o2::MCCompLabel> lblITS, gsl::span<const o2::MCCompLabel> lblTPC, std::vector<o2::MCEventLabel>& lblVtx) -{ - auto nv = process(tracksITSTPC, ft0Data, vertices, vertexTrackIDs, v2tRefs); - if (lblITS.size() && lblTPC.size()) { - createMCLabels(lblITS, lblTPC, vertices, vertexTrackIDs, v2tRefs, lblVtx); - } - return nv; -} - //______________________________________________ -int PVertexer::findVertices(const VertexingInput& input, std::vector<PVertex>& vertices, std::vector<int>& vertexTrackIDs, std::vector<V2TRef>& v2tRefs) +int PVertexer::findVertices(const VertexingInput& input, std::vector<PVertex>& vertices, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs) { // find vertices using tracks with indices (sorted in time) from idRange from "tracks" pool. The pool may containt arbitrary number of tracks, // only those which are in the idRange and have canUse()==true, will be used. // Results are placed in vertices and v2tRefs vectors - int nfound = 0, ntr = input.idRange.size(); - if (ntr < mPVParams->minTracksPerVtx) { - return nfound; - } - // - SeedHisto seedHisto(mPVParams->zHistoRange, mPVParams->zHistoBinSize); - for (int i : input.idRange) { - if (mTracksPool[i].canUse()) { - mTracksPool[i].bin = seedHisto.findBin(mTracksPool[i].getZForXY(mMeanVertex.getX(), mMeanVertex.getY())); - seedHisto.incrementBin(mTracksPool[i].bin); - } - } - if (seedHisto.nFilled < mPVParams->minTracksPerVtx) { - return nfound; - } - - while (1) { - int peakBin = seedHisto.findHighestPeakBin(); // find next seed - if (!seedHisto.isValidBin(peakBin)) { + int nfound = 0, ntr = 0; + auto seedHistoTZ = buildHistoTZ(input); // histo for seeding peak finding + +#ifdef _PV_DEBUG_TREE_ + static int dbsCount = -1; + dbsCount++; + int trialCount = 0; // TODO REM + auto hh = seedHistoTZ.createTH2F(o2::utils::Str::concat_string("htz", std::to_string(dbsCount))); + hh->SetDirectory(nullptr); + mDebugDumpFile->cd(); + hh->Write(); +#endif + + int nTrials = 0; + while (nfound < mPVParams->maxVerticesPerCluster && nTrials < mPVParams->maxTrialsPerCluster) { + int peakBin = seedHistoTZ.findPeakBin(); + if (!seedHistoTZ.isValidBin(peakBin)) { break; } - float zv = seedHisto.getBinCenter(peakBin); - LOG(DEBUG) << "Seeding with Z=" << zv << " bin " << peakBin; + int peakBinT = seedHistoTZ.getXBin(peakBin), peakBinZ = seedHistoTZ.getYBin(peakBin); + float tv = seedHistoTZ.getBinXCenter(peakBinT); + float zv = seedHistoTZ.getBinYCenter(peakBinZ); + LOG(DEBUG) << "Seeding with T=" << tv << " Z=" << zv << " bin " << peakBin << " on trial " << nTrials << " for vertex " << nfound; + PVertex vtx; vtx.setXYZ(mMeanVertex.getX(), mMeanVertex.getY(), zv); - vtx.setTimeStamp(input.timeEst); + vtx.setTimeStamp({tv, 0.f}); if (findVertex(input, vtx)) { - finalizeVertex(input, vtx, vertices, v2tRefs, vertexTrackIDs, seedHisto); + finalizeVertex(input, vtx, vertices, v2tRefs, trackIDs, &seedHistoTZ); nfound++; + nTrials = 0; } else { // suppress failed seeding bin and its proximities - auto delta = std::sqrt(vtx.getChi2()) * mStatZErr.getMean() * getTukey(); // largest scale used will be transferred as chi2 - int proximity = delta * seedHisto.binSizeInv; - int bmin = std::max(0, peakBin - proximity), bmax = std::min(peakBin + proximity + 1, seedHisto.size()); - LOG(DEBUG) << "suppress bins for delta=" << delta << " (" << std::sqrt(vtx.getChi2()) << "*" << mStatZErr.getMean() << "*" << getTukey() << ")" - << " bins " << bmin << " : " << bmax - 1; - for (int i = bmin; i < bmax; i++) { - seedHisto.discardBin(i); - } + seedHistoTZ.setBinContent(peakBin, -1); } + nTrials++; + +#ifdef _PV_DEBUG_TREE_ + auto hh1 = seedHistoTZ.createTH2F(o2::utils::Str::concat_string("htz", std::to_string(dbsCount), "_", std::to_string(trialCount++))); + hh1->SetDirectory(nullptr); + mDebugDumpFile->cd(); + hh1->Write(); +#endif } return nfound; } @@ -166,7 +188,9 @@ bool PVertexer::findVertex(const VertexingInput& input, PVertex& vtx) // tracks pool may contain arbitrary number of tracks, only those which are in // the idRange (indices of tracks sorted in time) will be used. - VertexSeed vtxSeed(vtx, input.useConstraint, input.fillErrors); + int ntr = input.idRange.size(); // RSREM + + VertexSeed vtxSeed(vtx); vtxSeed.setScale(input.scaleSigma2, mTukey2I); vtxSeed.scaleSigma2Prev = input.scaleSigma2; // vtxSeed.setTimeStamp( timeEstimate(input) ); @@ -178,7 +202,8 @@ bool PVertexer::findVertex(const VertexingInput& input, PVertex& vtx) while (result == FitStatus::IterateFurther) { vtxSeed.resetForNewIteration(); vtxSeed.nIterations++; - LOG(DEBUG) << "iter " << vtxSeed.nIterations << " with scale=" << vtxSeed.scaleSigma2 << " prevScale=" << vtxSeed.scaleSigma2Prev; + LOG(DEBUG) << "iter " << vtxSeed.nIterations << " with scale=" << vtxSeed.scaleSigma2 << " prevScale=" << vtxSeed.scaleSigma2Prev + << " ntr=" << ntr << " Zv=" << vtxSeed.getZ() << " Tv=" << vtxSeed.getTimeStamp().getTimeStamp(); result = fitIteration(input, vtxSeed); if (result == FitStatus::OK) { @@ -197,7 +222,7 @@ bool PVertexer::findVertex(const VertexingInput& input, PVertex& vtx) LOG(FATAL) << "Unknown fit status " << int(result); } } - LOG(DEBUG) << "Stopped with scale=" << vtxSeed.scaleSigma2 << " prevScale=" << vtxSeed.scaleSigma2Prev << " result = " << int(result); + LOG(DEBUG) << "Stopped with scale=" << vtxSeed.scaleSigma2 << " prevScale=" << vtxSeed.scaleSigma2Prev << " result = " << int(result) << " ntr=" << ntr; if (result != FitStatus::OK) { vtx.setChi2(vtxSeed.maxScaleSigma2Tested); @@ -213,15 +238,18 @@ PVertexer::FitStatus PVertexer::fitIteration(const VertexingInput& input, Vertex int nTested = 0; for (int i : input.idRange) { if (mTracksPool[i].canUse()) { - nTested++; accountTrack(mTracksPool[i], vtxSeed); + // printf("#%d z:%f t:%f te:%f w:%f wh:%f\n", nTested, mTracksPool[i].z, mTracksPool[i].timeEst.getTimeStamp(), + // mTracksPool[i].timeEst.getTimeStampError(), mTracksPool[i].wgh, mTracksPool[i].wghHisto); + nTested++; } } + vtxSeed.maxScaleSigma2Tested = vtxSeed.scaleSigma2; if (vtxSeed.getNContributors() < mPVParams->minTracksPerVtx) { return nTested < mPVParams->minTracksPerVtx ? FitStatus::PoolEmpty : FitStatus::NotEnoughTracks; } - if (vtxSeed.useConstraint) { + if (mPVParams->useMeanVertexConstraint) { applyConstraint(vtxSeed); } if (!solveVertex(vtxSeed)) { @@ -234,22 +262,8 @@ PVertexer::FitStatus PVertexer::fitIteration(const VertexingInput& input, Vertex void PVertexer::accountTrack(TrackVF& trc, VertexSeed& vtxSeed) const { // deltas defined as track - vertex - float dt, trErr2I = 0, dy, dz, chi2T = trc.getResiduals(vtxSeed, dy, dz); // track-vertex residuals and chi2 - auto& timeV = vtxSeed.getTimeStamp(); - auto& timeT = trc.timeEst; - float ndff = 1. / 2; - bool noTime = false; - if (timeV.getTimeStampError() < 0.) { - noTime = true; - } else { - dt = timeT.getTimeStamp() - timeV.getTimeStamp(); - trErr2I = 1. / (timeT.getTimeStampError() * timeT.getTimeStampError()); - if (mPVParams->useTimeInChi2) { - chi2T += dt * dt * trErr2I; - ndff = 1. / 3.; - } - } - chi2T *= ndff; + bool useTime = vtxSeed.getTimeStamp().getTimeStampError() >= 0.f; + auto chi2T = trc.evalChi2ToVertex(vtxSeed, useTime && mPVParams->useTimeInChi2); float wghT = (1.f - chi2T * vtxSeed.scaleSig2ITuk2I); // weighted distance to vertex if (wghT < kAlmost0F) { trc.wgh = 0.f; @@ -288,9 +302,9 @@ void PVertexer::accountTrack(TrackVF& trc, VertexSeed& vtxSeed) const vtxSeed.czz += szzI; // dchi^2/dz/dz vtxSeed.cz0 += tmpZXL * szzI + tmpYXP * syzI; // RHS // - if (!noTime) { - trErr2I *= wghT; - vtxSeed.tMeanAcc += timeT.getTimeStamp() * trErr2I; + if (useTime) { + float trErr2I = wghT / (trc.timeEst.getTimeStampError() * trc.timeEst.getTimeStampError()); + vtxSeed.tMeanAcc += trc.timeEst.getTimeStamp() * trErr2I; vtxSeed.tMeanAccErr += trErr2I; } vtxSeed.addContributor(); @@ -313,9 +327,7 @@ bool PVertexer::solveVertex(VertexSeed& vtxSeed) const ROOT::Math::SVector<double, 3> rhs(vtxSeed.cx0, vtxSeed.cy0, vtxSeed.cz0); auto sol = mat * rhs; vtxSeed.setXYZ(sol(0), sol(1), sol(2)); - if (vtxSeed.fillErrors) { - vtxSeed.setCov(mat(0, 0), mat(1, 0), mat(1, 1), mat(2, 0), mat(2, 1), mat(2, 2)); - } + vtxSeed.setCov(mat(0, 0), mat(1, 0), mat(1, 1), mat(2, 0), mat(2, 1), mat(2, 2)); if (vtxSeed.tMeanAccErr > 0.) { auto err2 = 1. / vtxSeed.tMeanAccErr; vtxSeed.setTimeStamp({float(vtxSeed.tMeanAcc * err2), float(std::sqrt(err2))}); @@ -324,7 +336,6 @@ bool PVertexer::solveVertex(VertexSeed& vtxSeed) const vtxSeed.setChi2((vtxSeed.getNContributors() - vtxSeed.wghSum) / vtxSeed.scaleSig2ITuk2I); // calculate chi^2 auto newScale = vtxSeed.wghChi2 / vtxSeed.wghSum; LOG(DEBUG) << "Solve: wghChi2=" << vtxSeed.wghChi2 << " wghSum=" << vtxSeed.wghSum << " -> scale= " << newScale << " old scale " << vtxSeed.scaleSigma2 << " prevScale: " << vtxSeed.scaleSigma2Prev; - //vtxSeed.print(); vtxSeed.setScale(newScale < mPVParams->minScale2 ? mPVParams->minScale2 : newScale, mTukey2I); return true; } @@ -386,6 +397,174 @@ PVertexer::FitStatus PVertexer::evalIterations(VertexSeed& vtxSeed, PVertex& vtx return result; } +//___________________________________________________________________ +void PVertexer::reAttach(std::vector<PVertex>& vertices, std::vector<int>& timeSort, std::vector<uint32_t>& trackIDs, std::vector<V2TRef>& v2tRefs) +{ + float tRange = 0.5 * std::max(mITSROFrameLengthMUS, mPVParams->dbscanDeltaT) + mPVParams->timeMarginReattach; // consider only vertices in this proximity to tracks + std::vector<std::pair<int, TimeEst>> vtvec; // valid vertex times and indices + int nvtOrig = vertices.size(); + vtvec.reserve(nvtOrig); + mTimeZClusters.resize(nvtOrig); + for (int ivt = 0; ivt < nvtOrig; ivt++) { + mTimeZClusters[ivt].trackIDs.clear(); + mTimeZClusters[ivt].trackIDs.reserve(int(vertices[ivt].getNContributors() * 1.2)); + } + for (auto ivt : timeSort) { + if (ivt >= 0) { + vtvec.emplace_back(ivt, vertices[ivt].getTimeStamp()); + } + } + int ntr = mTracksPool.size(), nvt = vtvec.size(); + int vtStart = 0; + for (int itr = 0; itr < ntr; itr++) { + auto& trc = mTracksPool[itr]; + trc.vtxID = TrackVF::kNoVtx; + trc.wgh = kAlmost0F; + for (int ivt = vtStart; ivt < nvt; ivt++) { + auto dt = vtvec[ivt].second.getTimeStamp() - trc.timeEst.getTimeStamp(); + if (dt < -tRange) { // all following tracks will have higher time than the vertex vtStart, move it + vtStart = ivt + 1; + continue; + } + if (dt > tRange) { // all following vertices will be have higher time than this track, stop checking + break; + } + bool useTime = trc.gid.getSource() != GTrackID::ITS && mPVParams->useTimeInChi2; // TODO Check if it is ok to not account time error for ITS tracks + float wgh = 1.f - mTukey2I * trc.evalChi2ToVertex(vertices[vtvec[ivt].first], useTime); + if (wgh > trc.wgh) { + trc.wgh = wgh; + trc.vtxID = vtvec[ivt].first; + } + } + if (trc.vtxID != TrackVF::kNoVtx) { + mTimeZClusters[trc.vtxID].trackIDs.push_back(itr); + trc.vtxID = TrackVF::kNoVtx; // to enable for using in the fit + trc.bin = -1; + } + } + // refit vertices with reattached tracks + v2tRefs.clear(); + trackIDs.clear(); + std::vector<PVertex> verticesUpd; + for (int ivt = 0; ivt < nvtOrig; ivt++) { + auto& clusZT = mTimeZClusters[ivt]; + auto& vtx = vertices[ivt]; + if (clusZT.trackIDs.size() < mPVParams->minTracksPerVtx) { + continue; + } + VertexingInput inp; + inp.idRange = gsl::span<int>(clusZT.trackIDs); + inp.scaleSigma2 = 1.; + inp.timeEst = vtx.getTimeStamp(); + if (!findVertex(inp, vtx)) { + vtx.setNContributors(0); + continue; + } + finalizeVertex(inp, vtx, verticesUpd, v2tRefs, trackIDs); + } + // reorder in time since the time-stamp of vertices might have been changed + vertices.swap(verticesUpd); + timeSort.resize(vertices.size()); + std::iota(timeSort.begin(), timeSort.end(), 0); + std::sort(timeSort.begin(), timeSort.end(), [&vertices](int i, int j) { + return vertices[i].getTimeStamp().getTimeStamp() < vertices[j].getTimeStamp().getTimeStamp(); + }); +} + +//___________________________________________________________________ +void PVertexer::reduceDebris(std::vector<PVertex>& vertices, std::vector<int>& timeSort, const std::vector<o2::MCEventLabel>& lblVtx) +{ + // eliminate low multiplicity vertices in the close proximity of high mult ones, assuming that these are their debries + // The timeSort vector indicates the time ordering of the vertices + int nv = vertices.size(); + std::vector<int> multSort(nv); // sort time indices in multiplicity + std::iota(multSort.begin(), multSort.end(), 0); + std::sort(multSort.begin(), multSort.end(), [&timeSort, vertices](int i, int j) { + return vertices[timeSort[i]].getNContributors() > vertices[timeSort[j]].getNContributors(); + }); + + // suppress vertex pointed by j if needed, if time difference between i and j is too large, return true to stop checking + // pairs starting with i. + auto checkPair = [&vertices, &timeSort, &lblVtx, this](int i, int j) { + auto &vtI = vertices[timeSort[i]], &vtJ = vertices[timeSort[j]]; + auto tDiff = std::abs(vtI.getTimeStamp().getTimeStamp() - vtJ.getTimeStamp().getTimeStamp()); + if (tDiff > this->mPVParams->maxTDiffDebris) { + return true; // don't continue checking other neighbours in time + } + if (vtI.getNContributors() < vtJ.getNContributors()) { + return false; // comparison goes from higher to lower mult vtx + } + bool rej = true; + float zDiff = std::abs(vtI.getZ() - vtJ.getZ()); + if (zDiff > this->mPVParams->maxZDiffDebris) { // cannot be reduced as too far in Z +#ifndef _PV_DEBUG_TREE_ + return false; +#endif + rej = false; + } + float multRat = float(vtJ.getNContributors()) / float(vtI.getNContributors()); + if (multRat > this->mPVParams->maxMultRatDebris) { +#ifndef _PV_DEBUG_TREE_ + return false; +#endif + rej = false; + } + float tiE = vtI.getTimeStamp().getTimeStampError(), tjE = vtJ.getTimeStamp().getTimeStampError(); + float chi2z = zDiff * zDiff / (vtI.getSigmaZ2() + vtJ.getSigmaZ2() + this->mPVParams->addZSigma2Debris); + float chi2t = tDiff * tDiff / (tiE * tiE + tjE * tjE + this->mPVParams->addTimeSigma2Debris); + if (chi2z + chi2t > this->mPVParams->maxChi2TZDebris) { +#ifndef _PV_DEBUG_TREE_ + return false; +#endif + rej = false; + } + // all veto cuts passed, declare as fake! +#ifdef _PV_DEBUG_TREE_ + o2::MCEventLabel dummyLbl; + this->mDebugDumpPVComp.emplace_back(PVtxCompDump{vtI, vtJ, chi2z, chi2t, rej}); + if (!lblVtx.empty()) { + this->mDebugDumpPVCompLbl0.push_back(lblVtx[timeSort[i]]); + this->mDebugDumpPVCompLbl1.push_back(lblVtx[timeSort[j]]); + } +#endif + if (rej) { + timeSort[j] = -1; + vtJ.setNContributors(0); + } + return false; + }; + + for (int im = 0; im < nv; im++) { // loop from highest multiplicity to lowest one + int it = multSort[im]; + if (timeSort[it] < 0) { // if <0, the vertex was already discarded + continue; + } + + int itL = it; // look for vertices with smaller time + while (itL) { + if (timeSort[--itL] >= 0) { // if <0, the vertex was already discarded + if (checkPair(it, itL)) { // if too far in time, don't compare further + break; + } + } + } // itL loop + int itH = it; // look for vertices with higher time + while (++itH < nv) { + if (timeSort[itH] >= 0) { // if <0, the vertex was already discarded + if (checkPair(it, itH)) { // if too far in time, don't compare further + break; + } + } + } // itH loop + } +#ifdef _PV_DEBUG_TREE_ + mDebugVtxCompTree->Fill(); + mDebugDumpPVComp.clear(); + mDebugDumpPVCompLbl0.clear(); + mDebugDumpPVCompLbl1.clear(); +#endif +} + //___________________________________________________________________ void PVertexer::initMeanVertexConstraint() { @@ -427,200 +606,78 @@ TimeEst PVertexer::timeEstimate(const VertexingInput& input) const void PVertexer::init() { mPVParams = &PVertexerParams::Instance(); - mFT0Params = &o2::ft0::InteractionTag::Instance(); setTukey(mPVParams->tukey); initMeanVertexConstraint(); auto* prop = o2::base::Propagator::Instance(); setBz(prop->getNominalBz()); -} - -//___________________________________________________________________ -void PVertexer::finalizeVertex(const VertexingInput& input, const PVertex& vtx, - std::vector<PVertex>& vertices, std::vector<V2TRef>& v2tRefs, std::vector<int>& vertexTrackIDs, - SeedHisto& histo) -{ - int lastID = vertices.size(); - vertices.emplace_back(vtx); - auto& ref = v2tRefs.emplace_back(vertexTrackIDs.size(), 0); - for (int i : input.idRange) { - if (mTracksPool[i].canAssign()) { - vertexTrackIDs.push_back(mTracksPool[i].entry); - mTracksPool[i].vtxID = lastID; - - // remove track from ZSeeds histo - histo.decrementBin(mTracksPool[i].bin); - } - } - ref.setEntries(vertexTrackIDs.size() - ref.getFirstEntry()); -} - -//___________________________________________________________________ -void PVertexer::createTracksPool(gsl::span<const o2d::TrackTPCITS> tracksITSTPC) -{ - // create pull of all candidate tracks in a global array ordered in time - mTracksPool.clear(); - mSortedTrackID.clear(); - - auto ntGlo = tracksITSTPC.size(); - mTracksPool.reserve(ntGlo); - // check all containers - float vtxErr2 = 0.5 * (mMeanVertex.getSigmaX2() + mMeanVertex.getSigmaY2()); - float dcaToler = 1.0 + 3. * std::sqrt(vtxErr2); // RS FIXME tolerance should be a parameter - float pullIniCut = 9.; // RS FIXME pullIniCut should be a parameter - o2d::DCA dca; - - for (uint32_t i = 0; i < ntGlo; i++) { - o2::track::TrackParCov trc = tracksITSTPC[i]; - if (!trc.propagateToDCA(mMeanVertex, mBz, &dca, dcaToler) || - dca.getY() * dca.getY() / (dca.getSigmaY2() + vtxErr2) > pullIniCut) { - continue; - } - auto& tvf = mTracksPool.emplace_back(trc, tracksITSTPC[i].getTimeMUS(), i, 0); - mStatZErr.add(std::sqrt(trc.getSigmaZ2())); - mStatTErr.add(tvf.timeEst.getTimeStampError()); - } - // TODO: try to narrow timestamps using tof times - auto [zerrMean, zerrRMS] = mStatZErr.getMeanRMS2<float>(); - - auto [terrMean, terrRMS] = mStatTErr.getMeanRMS2<float>(); - - if (mTracksPool.empty()) { - return; - } - // - mSortedTrackID.resize(mTracksPool.size()); - std::iota(mSortedTrackID.begin(), mSortedTrackID.end(), 0); - - std::sort(mSortedTrackID.begin(), mSortedTrackID.end(), [this](int i, int j) { - return this->mTracksPool[i].timeEst.getTimeStamp() < this->mTracksPool[j].timeEst.getTimeStamp(); - }); - auto tMin = mTracksPool[mSortedTrackID.front()].timeEst.getTimeStamp(); - auto tMax = mTracksPool[mSortedTrackID.back()].timeEst.getTimeStamp(); +#ifdef _PV_DEBUG_TREE_ + mDebugDumpFile = std::make_unique<TFile>("pvtxDebug.root", "recreate"); + mDebugDBScanTree = std::make_unique<TTree>("pvtxDBScan", "PVertexer DBScan debug output"); + mDebugDBScanTree->Branch("trc", &mDebugDumpDBSTrc); + mDebugDBScanTree->Branch("gid", &mDebugDumpDBSGID); + mDebugDBScanTree->Branch("mc", &mDebugDumpDBSTrcMC); + + mDebugVtxTree = std::make_unique<TTree>("pvtx", "final PVertexer debug output"); + mDebugVtxTree->Branch("vtx", &mDebugDumpVtx); + mDebugVtxTree->Branch("trc", &mDebugDumpVtxTrc); + mDebugVtxTree->Branch("gid", &mDebugDumpVtxGID); + mDebugVtxTree->Branch("mc", &mDebugDumpVtxTrcMC); + + mDebugVtxCompTree = std::make_unique<TTree>("pvtxComp", "PVertexer neighbouring vertices debud output"); + mDebugVtxCompTree->Branch("vtxComp", &mDebugDumpPVComp); + mDebugVtxCompTree->Branch("vtxCompLbl0", &mDebugDumpPVCompLbl0); + mDebugVtxCompTree->Branch("vtxCompLbl1", &mDebugDumpPVCompLbl1); +#endif } //___________________________________________________________________ -void PVertexer::clusterizeTimeBruteForce(float margin, float cut) +void PVertexer::end() { - std::vector<TimeCluster> tclist; - mTimesClusters.clear(); - auto* vtxT = &tclist.emplace_back(); - int ntr = mSortedTrackID.size(); - for (int i = 0; i < ntr; i++) { - int icur = mSortedTrackID[i]; - const auto& trc = mTracksPool[icur]; - if (!vtxT->isCompatible(trc.timeEst, margin, cut)) { - if (vtxT->count < mPVParams->minTracksPerVtx) { - vtxT->clear(); - } else { - vtxT = &tclist.emplace_back(); - } - } - vtxT->addTrack(i, trc.timeEst); - } - if (tclist.back().count < mPVParams->minTracksPerVtx) { - tclist.pop_back(); - } - // final sort in decreasing multiplicity - std::vector<int> tcselSort(tclist.size()); - std::iota(tcselSort.begin(), tcselSort.end(), 0); - - std::sort(tcselSort.begin(), tcselSort.end(), [&tclist](int i, int j) { return tclist[i].count > tclist[j].count; }); - mTimesClusters.reserve(tcselSort.size()); - for (auto i : tcselSort) { - if (tclist[i].count >= mPVParams->minTracksPerVtx) { - mTimesClusters.push_back(tclist[i]); - auto& tc = mTimesClusters.back(); - // tc.print(); - } - } +#ifdef _PV_DEBUG_TREE_ + mDebugDBScanTree->Write(); + mDebugVtxCompTree->Write(); + mDebugVtxTree->Write(); + mDebugDBScanTree.reset(); + mDebugVtxCompTree.reset(); + mDebugDumpFile->Close(); + mDebugDumpFile.reset(); +#endif } //___________________________________________________________________ -void PVertexer::clusterizeTime(float binSize, float maxTDist) +void PVertexer::finalizeVertex(const VertexingInput& input, const PVertex& vtx, + std::vector<PVertex>& vertices, std::vector<V2TRef>& v2tRefs, std::vector<uint32_t>& trackIDs, + SeedHistoTZ* histo) { - // moving average density - std::vector<int> tclistIdx, tcselSort; - std::vector<TimeCluster> tclist; - mTimesClusters.clear(); - - int ntr = mTracksPool.size(), first = 0, last = 0, count = 1; - float tfirst = mTracksPool[mSortedTrackID[first]].timeEst.getTimeStamp(), tlast = tfirst, tMean = tfirst; - for (int i = 1; i < ntr; i++) { - if (mTracksPool[mSortedTrackID[i]].timeEst.getTimeStamp() - tfirst < binSize) { - last = i; - tlast = mTracksPool[mSortedTrackID[last]].timeEst.getTimeStamp(); - tMean += tlast; - count++; - } else { - tclist.emplace_back(TimeCluster{{tMean / count, 0.}, first, last, count}); - first = last = i; - tMean = tfirst = mTracksPool[mSortedTrackID[last]].timeEst.getTimeStamp(); - count = 1; - } - } - tMean += mTracksPool[mSortedTrackID[last]].timeEst.getTimeStamp(); - tclist.emplace_back(TimeCluster{{tMean / count, 0.}, first, last, count}); - - int ncl = tclist.size(); - tclistIdx.resize(ncl); - tcselSort.reserve(ncl); - std::iota(tclistIdx.begin(), tclistIdx.end(), 0); - std::sort(tclistIdx.begin(), tclistIdx.end(), [&tclist](int i, int j) { return tclist[i].count > tclist[j].count; }); - - for (auto it : tclistIdx) { - auto& best = tclist[it]; - if (!best.count) { - continue; // already merged - } - // check if it can absorm neighbours - int iBef = it, iAft = it; - bool merged; - do { - merged = false; - if (--iBef >= 0) { - if (tclist[iBef].count && best.isCompatible(tclist[iBef].timeEst, 0, maxTDist)) { - best.merge(tclist[iBef]); - merged = true; - } else { - iBef = -1; // don't check those before - } - } - if (++iAft < ncl) { - if (tclist[iAft].count && best.isCompatible(tclist[iAft].timeEst, 0, maxTDist)) { - best.merge(tclist[iAft]); - merged = true; - } else { - iAft = ncl; // don't check those after - } + int lastID = vertices.size(); + vertices.emplace_back(vtx); + auto& ref = v2tRefs.emplace_back(trackIDs.size(), 0); + for (int i : input.idRange) { + auto& trc = mTracksPool[i]; + if (trc.canAssign()) { + trackIDs.push_back(i); + trc.vtxID = lastID; + if (trc.bin >= 0 && histo) { + histo->setBinContent(trc.bin, -1.f); // discard used bin } - } while (merged); - if (best.count > 1) { // RS FIXME - tcselSort.push_back(it); } } - // final sort in decreasing multiplicity - std::sort(tcselSort.begin(), tcselSort.end(), [&tclist](int i, int j) { return tclist[i].count > tclist[j].count; }); - mTimesClusters.reserve(tcselSort.size()); - for (auto i : tcselSort) { - mTimesClusters.push_back(tclist[i]); - // mTimesClusters.back().print(); - } + ref.setEntries(trackIDs.size() - ref.getFirstEntry()); } //___________________________________________________________________ -void PVertexer::createMCLabels(gsl::span<const o2::MCCompLabel> lblITS, gsl::span<const o2::MCCompLabel> lblTPC, - const std::vector<PVertex> vertices, const std::vector<o2::dataformats::VtxTrackIndex> vertexTrackIDs, const std::vector<V2TRef> v2tRefs, +void PVertexer::createMCLabels(gsl::span<const o2::MCCompLabel> lblTracks, + const std::vector<uint32_t>& trackIDs, const std::vector<V2TRef>& v2tRefs, std::vector<o2::MCEventLabel>& lblVtx) { lblVtx.clear(); - int nv = vertices.size(); - if (lblITS.size() != lblITS.size() || !lblITS.size()) { - LOG(ERROR) << "labels are not provided or incorrect"; + if (!lblTracks.size()) { + LOG(ERROR) << "Track labels are not provided"; return; } - std::unordered_map<o2::MCEventLabel, int> labelOccurenceCorr, labelOccurenceITS; + std::unordered_map<o2::MCEventLabel, int> labelOccurence; auto bestLbl = [](std::unordered_map<o2::MCEventLabel, int> mp, int norm) -> o2::MCEventLabel { o2::MCEventLabel best; @@ -639,58 +696,24 @@ void PVertexer::createMCLabels(gsl::span<const o2::MCCompLabel> lblITS, gsl::spa for (const auto& v2t : v2tRefs) { int tref = v2t.getFirstEntry(), last = tref + v2t.getEntries(); - labelOccurenceCorr.clear(); - labelOccurenceITS.clear(); + labelOccurence.clear(); o2::MCEventLabel winner; // unset at the moment for (; tref < last; tref++) { - int tid = vertexTrackIDs[tref].getIndex(); - const auto& lITS = lblITS[tid]; - const auto& lTPC = lblTPC[tid]; - if (!lITS.isSet() || !lTPC.isSet()) { + const auto& lbl = lblTracks[mTracksPool[trackIDs[tref]].entry]; + if (!lbl.isSet()) { break; } - if (lITS.getTrackID() == lITS.getTrackID() && lITS.getEventID() == lTPC.getEventID() && lITS.getSourceID() == lTPC.getSourceID()) { - labelOccurenceCorr[{lITS.getEventID(), lITS.getSourceID(), 0.}]++; - } else { - labelOccurenceITS[{lITS.getEventID(), lITS.getSourceID(), 0.}]++; - } + // if (!lbl.isFake()) { // RS account all labels, not only correct ones + labelOccurence[{lbl.getEventID(), lbl.getSourceID(), 0.}]++; + // } } - if (labelOccurenceCorr.size()) { - winner = bestLbl(labelOccurenceCorr, v2t.getEntries()); - } else if (labelOccurenceITS.size()) { - winner = bestLbl(labelOccurenceITS, 0); // in absence of correct matches, set the ITS only label but set its weight to 0 + if (labelOccurence.size()) { + winner = bestLbl(labelOccurence, v2t.getEntries()); } lblVtx.push_back(winner); } } -//___________________________________________________________________ -std::pair<int, int> PVertexer::getBestFT0Trigger(const PVertex& vtx, gsl::span<const o2::ft0::RecPoints> ft0Data, int& currEntry) const -{ - // select best matching FT0 recpoint - int best = -1, n = ft0Data.size(); - while (currEntry < n && ft0Data[currEntry].getInteractionRecord() < vtx.getIRMin()) { - currEntry++; // skip all times which have no chance to be matched - } - int i = currEntry, nCompatible = 0; - float bestDf = 1e12; - auto tVtxNS = (vtx.getTimeStamp().getTimeStamp() + mPVParams->timeBiasMS) * 1e3; // time in ns - while (i < n) { - if (ft0Data[i].getInteractionRecord() > vtx.getIRMax()) { - break; - } - if (mFT0Params->isSelected(ft0Data[i])) { - nCompatible++; - auto dfa = std::abs(mFT0Params->getInteractionTimeNS(ft0Data[i], mStartIR) - tVtxNS); - if (dfa <= bestDf) { - bestDf = dfa; - best = i; - } - } - i++; - } - return {best, nCompatible}; -} //___________________________________________________________________ void PVertexer::setBunchFilling(const o2::BunchFilling& bf) @@ -728,7 +751,10 @@ bool PVertexer::setCompatibleIR(PVertex& vtx) if (t > rangeT) { irMin += o2::InteractionRecord(1.e3 * (t - rangeT)); } - irMax += o2::InteractionRecord(1.e3 * (t + rangeT)); + if (t < -rangeT) { + return false; // discard vertex at negative time + } + irMax += o2::InteractionRecord(1.e3 * (t + rangeT)); // RS TODO: make sure that irMax does not exceed TF edge irMax++; // to account for rounding // restrict using bunch filling int bc = mClosestBunchAbove[irMin.bc]; @@ -748,3 +774,245 @@ bool PVertexer::setCompatibleIR(PVertex& vtx) vtx.setIRMax(irMax); return irMax >= irMin; } + +//___________________________________________________________________ +int PVertexer::dbscan_RangeQuery(int id, std::vector<int>& cand, std::vector<int>& status) +{ + // find neighbours for dbscan cluster core point candidate + // Since we use asymmetric distance definition, is it bit more complex than simple search within chi2 proximity + int nFound = 0; + const auto& tI = mTracksPool[id]; + int ntr = mTracksPool.size(); + + auto procPnt = [this, &tI, &status, &cand, &nFound, id](int idN) { + const auto& tL = this->mTracksPool[idN]; + if (std::abs(tI.timeEst.getTimeStamp() - tL.timeEst.getTimeStamp()) > this->mPVParams->dbscanDeltaT) { + return -1; + } + auto statN = status[idN], stat = status[id]; + if (statN >= 0 && (stat < 0 || (stat >= 0 && statN != stat))) { // do not consider as a neighbour if already added to other cluster + return 0; + } + auto dist2 = tL.getDist2(tI); + if (dist2 < this->mPVParams->dbscanMaxDist2) { + nFound++; + if (statN < 0 && statN > DBS_INCHECK) { // no point in adding for check already assigned point, or which is already in the list (i.e. < INCHECK) + cand.push_back(idN); + status[idN] += DBS_INCHECK; // flag that the track is in the candidates list (i.e. DBS_UDEF-10 = -12 or DPB_NOISE-10 = -11). + } + } + return 1; + }; + int idL = id; + while (--idL >= 0) { // index in time decreasing direction + if (procPnt(idL) < 0) { + break; + } + } + int idU = id; + while (++idU < ntr) { // index in time increasing direction + if (procPnt(idU) < 0) { + break; + } + } + return nFound; +} + +//_____________________________________________________ +void PVertexer::dbscan_clusterize() +{ + mTimeZClusters.clear(); + int ntr = mTracksPool.size(); + std::vector<int> status(ntr, DBS_UNDEF); + TStopwatch timer; + int clID = -1; + + std::vector<int> nbVec; + for (int it = 0; it < ntr; it++) { + if (status[it] != DBS_UNDEF) { + continue; + } + nbVec.clear(); + auto nnb0 = dbscan_RangeQuery(it, nbVec, status); + int minNeighbours = mPVParams->minTracksPerVtx - 1; + if (nnb0 < minNeighbours) { + status[it] = DBS_NOISE; // noise + continue; + } + if (nnb0 > minNeighbours) { + minNeighbours = std::max(minNeighbours, int(nnb0 * mPVParams->dbscanAdaptCoef)); + } + status[it] = ++clID; + auto& clusVec = mTimeZClusters.emplace_back().trackIDs; // new cluster + clusVec.push_back(it); + + for (int j = 0; j < nnb0; j++) { + int jt = nbVec[j]; + auto statjt = status[jt]; + if (statjt >= 0) { + LOG(ERROR) << "assigned track " << jt << " with status " << statjt << " head is " << it << " clID= " << clID; + continue; + } + status[jt] = clID; + clusVec.push_back(jt); + if (statjt == DBS_NOISE + DBS_INCHECK) { // was border point, no check for being core point is needed + continue; + } + int ncurr = nbVec.size(); + if (clusVec.size() > minNeighbours) { + minNeighbours = std::max(minNeighbours, int(clusVec.size() * mPVParams->dbscanAdaptCoef)); + } + auto nnb1 = dbscan_RangeQuery(jt, nbVec, status); + if (nnb1 < minNeighbours) { + for (unsigned k = ncurr; k < nbVec.size(); k++) { + if (status[nbVec[k]] < DBS_INCHECK) { + status[nbVec[k]] -= DBS_INCHECK; // remove from checks + } + } + nbVec.resize(ncurr); // not a core point, reset the seeds pool to the state before RangeQuery + } else { + nnb0 = nbVec.size(); // core point, its neighbours need to be checked + } + } + } + + for (auto& clus : mTimeZClusters) { + if (clus.trackIDs.size() < mPVParams->minTracksPerVtx) { + clus.trackIDs.clear(); + continue; + } + float tMean = 0; + for (const auto tid : clus.trackIDs) { + tMean += mTracksPool[tid].timeEst.getTimeStamp(); + } + clus.timeEst.setTimeStamp(tMean / clus.trackIDs.size()); + } + timer.Stop(); + LOG(INFO) << "Found " << mTimeZClusters.size() << " seeding clusters from DBSCAN in " << timer.CpuTime() << " CPU s"; +} + +//___________________________________________________________________ +std::pair<int, int> PVertexer::getBestIR(const PVertex& vtx, const gsl::span<o2::InteractionRecord> bcData, int& currEntry) const +{ + // select best matching interaction record + int best = -1, n = bcData.size(); + while (currEntry < n && bcData[currEntry] < vtx.getIRMin()) { + currEntry++; // skip all times which have no chance to be matched + } + int i = currEntry, nCompatible = 0; + float bestDf = 1e12; + auto tVtxNS = (vtx.getTimeStamp().getTimeStamp() + mPVParams->timeBiasMS) * 1e3; // time in ns + while (i < n) { + if (bcData[i] > vtx.getIRMax()) { + break; + } + nCompatible++; + auto dfa = std::abs(bcData[i].differenceInBCNS(mStartIR) - tVtxNS); + if (dfa <= bestDf) { + bestDf = dfa; + best = i; + } + i++; + } + return {best, nCompatible}; +} + +//___________________________________________________________________ +SeedHistoTZ PVertexer::buildHistoTZ(const VertexingInput& input) +{ + // build histo for tracks time / z entries weigthed by their inverse error, to be used for seeding peak finding + // estimat the range of TZ histo + + float hZMin = 1e9, hZMax = -1e8, hTMin = 1e9, hTMax = -1e9; + for (int i : input.idRange) { + const auto& trc = mTracksPool[i]; + if (trc.canUse()) { + if (trc.z > hZMax) { + hZMax = trc.z; + } + if (trc.z < hZMin) { + hZMin = trc.z; + } + if (trc.timeEst.getTimeStamp() > hTMax) { + hTMax = trc.timeEst.getTimeStamp(); + } + if (trc.timeEst.getTimeStamp() < hTMin) { + hTMin = trc.timeEst.getTimeStamp(); + } + } + } + + float dz = hZMax - hZMin, dt = hTMax - hTMin; + int nbz = 1 + int((dz) / mPVParams->histoBinZSize), nbt = 1 + int((dt) / mPVParams->histoBinTSize); + float dzh = 0.5f * (nbz * mPVParams->histoBinZSize - dz), dth = 0.5f * (nbt * mPVParams->histoBinTSize - dt); + SeedHistoTZ seedHistoTZ(nbt, hTMin - dth, hTMax + dth, nbz, hZMin - dzh, hZMax + dzh); + + for (int i : input.idRange) { + auto& trc = mTracksPool[i]; + if (trc.canUse()) { + trc.bin = seedHistoTZ.fillAndFlagBin(trc.timeEst.getTimeStamp(), trc.z, trc.wghHisto); + } + } + + return std::move(seedHistoTZ); +} + +//______________________________________________ +bool PVertexer::relateTrackToMeanVertex(o2::track::TrackParCov& trc, float vtxErr2) const +{ + o2d::DCA dca; + return o2::base::Propagator::Instance()->propagateToDCA(mMeanVertex, trc, mBz, 2.0f, + o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dca, nullptr, 0, mPVParams->dcaTolerance) && + (dca.getY() * dca.getY() / (dca.getSigmaY2() + vtxErr2) < mPVParams->pullIniCut); +} + +//______________________________________________ +void PVertexer::doDBScanDump(const VertexingInput& input, gsl::span<const o2::MCCompLabel> lblTracks) +{ + // dump tracks for T-Z clusters identified by the DBScan +#ifdef _PV_DEBUG_TREE_ + for (int i : input.idRange) { + const auto& trc = mTracksPool[i]; + if (trc.canUse()) { + mDebugDumpDBSTrc.emplace_back(TrackVFDump{trc.z, trc.sig2ZI, trc.timeEst.getTimeStamp(), trc.timeEst.getTimeStampError(), trc.wghHisto}); + mDebugDumpDBSGID.push_back(trc.gid); + if (lblTracks.size()) { + mDebugDumpDBSTrcMC.push_back(lblTracks[trc.entry]); + } + } + } + mDebugDBScanTree->Fill(); + mDebugDumpDBSTrc.clear(); + mDebugDumpDBSGID.clear(); + mDebugDumpDBSTrcMC.clear(); +#endif +} + +//______________________________________________ +void PVertexer::doVtxDump(std::vector<PVertex>& vertices, std::vector<uint32_t> trackIDsLoc, std::vector<V2TRef>& v2tRefsLoc, + gsl::span<const o2::MCCompLabel> lblTracks) +{ + // dump tracks for T-Z clusters identified by the DBScan +#ifdef _PV_DEBUG_TREE_ + int nv = vertices.size(); + for (int iv = 0; iv < nv; iv++) { + mDebugDumpVtx = vertices[iv]; + if (mDebugDumpVtx.getNContributors() == 0) { // discarded + continue; + } + int start = v2tRefsLoc[iv].getFirstEntry(), stop = start + v2tRefsLoc[iv].getEntries(); + for (int it = start; it < stop; it++) { + const auto& trc = mTracksPool[trackIDsLoc[it]]; + mDebugDumpVtxTrc.emplace_back(TrackVFDump{trc.z, trc.sig2ZI, trc.timeEst.getTimeStamp(), trc.timeEst.getTimeStampError(), trc.wgh}); + mDebugDumpVtxGID.push_back(trc.gid); + if (lblTracks.size()) { + mDebugDumpVtxTrcMC.push_back(lblTracks[trc.entry]); + } + } + mDebugVtxTree->Fill(); + mDebugDumpVtxTrc.clear(); + mDebugDumpVtxGID.clear(); + mDebugDumpVtxTrcMC.clear(); + } +#endif +} diff --git a/Detectors/Vertexing/src/PVertexerHelpers.cxx b/Detectors/Vertexing/src/PVertexerHelpers.cxx index d3cf1756172cc..7881bbf9bc4b7 100644 --- a/Detectors/Vertexing/src/PVertexerHelpers.cxx +++ b/Detectors/Vertexing/src/PVertexerHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,3 +26,24 @@ void VertexSeed::print() const double dZ, rmsZ, dT, rmsT; PVertex::print(); } + +int SeedHistoTZ::findPeakBin() +{ + if (nEntries < 2) { + return -1; + } + int maxBin = -1, ib = filledBins.size(), last = ib; + float maxv = 0.; + while (ib--) { + auto bin = filledBins[ib]; + auto v = getBinContent(bin); + if (v > maxv) { + maxv = v; + maxBin = bin; + } else if (v <= 0.) { // bin was emptied + filledBins[ib] = filledBins[--last]; // move last non-empty bin in place of emptied one + } + } + filledBins.resize(last); + return maxBin; +} diff --git a/Detectors/Vertexing/src/PVertexerParams.cxx b/Detectors/Vertexing/src/PVertexerParams.cxx index d18d70057f310..1ddfce357339b 100644 --- a/Detectors/Vertexing/src/PVertexerParams.cxx +++ b/Detectors/Vertexing/src/PVertexerParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Vertexing/src/SVertexHypothesis.cxx b/Detectors/Vertexing/src/SVertexHypothesis.cxx new file mode 100644 index 0000000000000..e8b9cbff9528f --- /dev/null +++ b/Detectors/Vertexing/src/SVertexHypothesis.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SVertexHypothesis.cxx +/// \brief V0 hypothesis checker +/// \author ruben.shahoyan@cern.ch + +#include "DetectorsVertexing/SVertexHypothesis.h" + +using namespace o2::vertexing; + +void SVertexHypothesis::set(PID v0, PID ppos, PID pneg, float sig, float nSig, float margin, float cpt, float bz) +{ + mPIDV0 = v0; + mPIDPosProng = ppos; + mPIDNegProng = pneg; + mPars[SigmaM] = sig; + mPars[NSigmaM] = nSig; + mPars[MarginM] = margin; + mPars[CPt] = std::abs(bz) > 1e-3 ? cpt * 5.0066791 / bz : 0.; // assume that pT dependent sigma is linear with B +} + +void SVertexHypothesis::set(PID v0, PID ppos, PID pneg, const float pars[NPIDParams], float bz) +{ + set(v0, ppos, pneg, pars[SigmaM], pars[NSigmaM], pars[MarginM], pars[CPt], bz); +} diff --git a/Detectors/Vertexing/src/SVertexer.cxx b/Detectors/Vertexing/src/SVertexer.cxx index cd659acee7e81..d74dc80fd2071 100644 --- a/Detectors/Vertexing/src/SVertexer.cxx +++ b/Detectors/Vertexing/src/SVertexer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,222 +15,417 @@ #include "DetectorsVertexing/SVertexer.h" #include "DetectorsBase/Propagator.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsITS/TrackITS.h" + +#ifdef WITH_OPENMP +#include <omp.h> +#endif using namespace o2::vertexing; using PID = o2::track::PID; +using TrackTPCITS = o2::dataformats::TrackTPCITS; +using TrackITS = o2::its::TrackITS; +using TrackTPC = o2::tpc::TrackTPC; -void SVertexer::init() +//__________________________________________________________________ +void SVertexer::process(const o2::globaltracking::RecoContainer& recoData) // accessor to various reconstrucred data types { - mSVParams = &SVertexerParams::Instance(); + updateTimeDependentParams(); // TODO RS: strictly speaking, one should do this only in case of the CCDB objects update + mPVertices = recoData.getPrimaryVertices(); + buildT2V(recoData); // build track->vertex refs from vertex->track (if other workflow will need this, consider producing a message in the VertexTrackMatcher) + int ntrP = mTracksPool[POS].size(), ntrN = mTracksPool[NEG].size(), iThread = 0; + mV0sTmp[0].clear(); + mCascadesTmp[0].clear(); + +#ifdef WITH_OPENMP + omp_set_num_threads(mNThreads); + int dynGrp = std::min(4, std::max(1, mNThreads / 2)); +#pragma omp parallel for schedule(dynamic, dynGrp) +#endif + for (int itp = 0; itp < ntrP; itp++) { + auto& seedP = mTracksPool[POS][itp]; + for (int itn = mVtxFirstTrack[NEG][seedP.vBracket.getMin()]; itn < ntrN; itn++) { // start from the 1st negative track of lowest-ID vertex of positive + auto& seedN = mTracksPool[NEG][itn]; + if (seedN.vBracket > seedP.vBracket) { // all vertices compatible with seedN are in future wrt that of seedP + break; + } +#ifdef WITH_OPENMP + iThread = omp_get_thread_num(); +#endif + checkV0(seedP, seedN, itp, itn, iThread); + } + } +#ifdef WITH_OPENMP + for (int i = 1; i < mNThreads; i++) { // merge results of all threads + for (auto& casc : mCascadesTmp[i]) { // before merging fix cascades references on v0 + casc.setV0ID(casc.getV0ID() + mV0sTmp[0].size()); + } + mV0sTmp[0].insert(mV0sTmp[0].end(), mV0sTmp[i].begin(), mV0sTmp[i].end()); + mCascadesTmp[0].insert(mCascadesTmp[0].end(), mCascadesTmp[i].begin(), mCascadesTmp[i].end()); + mV0sTmp[i].clear(); + mCascadesTmp[i].clear(); + } +#endif + LOG(INFO) << "DONE : " << mV0sTmp[0].size() << " " << mCascadesTmp[0].size(); +} - mFitter2Prong.setUseAbsDCA(mSVParams->useAbsDCA); - mFitter2Prong.setPropagateToPCA(false); - mFitter2Prong.setMaxR(mSVParams->maxRIni); - mFitter2Prong.setMinParamChange(mSVParams->minParamChange); - mFitter2Prong.setMinRelChi2Change(mSVParams->minRelChi2Change); - mFitter2Prong.setMaxDZIni(mSVParams->maxDZIni); - mFitter2Prong.setMaxChi2(mSVParams->maxChi2); +//__________________________________________________________________ +void SVertexer::init() +{ +} +//__________________________________________________________________ +void SVertexer::updateTimeDependentParams() +{ + // TODO RS: strictly speaking, one should do this only in case of the CCDB objects update + mSVParams = &SVertexerParams::Instance(); // precalculated selection cuts - mMinR2ToMeanVertex = mSVParams->minRfromMeanVertex * mSVParams->minRfromMeanVertex; - mMaxDCAXY2ToMeanVertex = mSVParams->maxDCAXYfromMeanVertex * mSVParams->maxDCAXYfromMeanVertex; - mMinCosPointingAngle = mSVParams->minCosPointingAngle; - // + mMinR2ToMeanVertex = mSVParams->minRToMeanVertex * mSVParams->minRToMeanVertex; + mMaxR2ToMeanVertexCascV0 = mSVParams->maxRToMeanVertexCascV0 * mSVParams->maxRToMeanVertexCascV0; + mMaxDCAXY2ToMeanVertex = mSVParams->maxDCAXYToMeanVertex * mSVParams->maxDCAXYToMeanVertex; + mMaxDCAXY2ToMeanVertexV0Casc = mSVParams->maxDCAXYToMeanVertexV0Casc * mSVParams->maxDCAXYToMeanVertexV0Casc; + mMinR2DiffV0Casc = mSVParams->minRDiffV0Casc * mSVParams->minRDiffV0Casc; + mMinPt2V0 = mSVParams->minPtV0 * mSVParams->minPtV0; + mMaxTgl2V0 = mSVParams->maxTglV0 * mSVParams->maxTglV0; + mMinPt2Casc = mSVParams->minPtCasc * mSVParams->minPtCasc; + mMaxTgl2Casc = mSVParams->maxTglCasc * mSVParams->maxTglCasc; + auto bz = o2::base::Propagator::Instance()->getNominalBz(); - mFitter2Prong.setBz(bz); - // - mV0Hyps[SVertexerParams::Photon].set(PID::Photon, PID::Electron, PID::Electron, mSVParams->pidCuts[SVertexerParams::Photon], bz); - mV0Hyps[SVertexerParams::K0].set(PID::K0, PID::Pion, PID::Pion, mSVParams->pidCuts[SVertexerParams::K0], bz); - mV0Hyps[SVertexerParams::Lambda].set(PID::Lambda, PID::Proton, PID::Pion, mSVParams->pidCuts[SVertexerParams::Lambda], bz); - mV0Hyps[SVertexerParams::AntiLambda].set(PID::Lambda, PID::Pion, PID::Proton, mSVParams->pidCuts[SVertexerParams::AntiLambda], bz); - mV0Hyps[SVertexerParams::HyperTriton].set(PID::HyperTriton, PID::Helium3, PID::Pion, mSVParams->pidCuts[SVertexerParams::HyperTriton], bz); - mV0Hyps[SVertexerParams::AntiHyperTriton].set(PID::HyperTriton, PID::Pion, PID::Helium3, mSVParams->pidCuts[SVertexerParams::AntiHyperTriton], bz); - // + + mV0Hyps[HypV0::Photon].set(PID::Photon, PID::Electron, PID::Electron, mSVParams->pidCutsPhoton, bz); + mV0Hyps[HypV0::K0].set(PID::K0, PID::Pion, PID::Pion, mSVParams->pidCutsK0, bz); + mV0Hyps[HypV0::Lambda].set(PID::Lambda, PID::Proton, PID::Pion, mSVParams->pidCutsLambda, bz); + mV0Hyps[HypV0::AntiLambda].set(PID::Lambda, PID::Pion, PID::Proton, mSVParams->pidCutsLambda, bz); + mV0Hyps[HypV0::HyperTriton].set(PID::HyperTriton, PID::Helium3, PID::Pion, mSVParams->pidCutsHTriton, bz); + mV0Hyps[HypV0::AntiHyperTriton].set(PID::HyperTriton, PID::Pion, PID::Helium3, mSVParams->pidCutsHTriton, bz); + + mCascHyps[HypCascade::XiMinus].set(PID::XiMinus, PID::Lambda, PID::Pion, mSVParams->pidCutsXiMinus, bz); + mCascHyps[HypCascade::OmegaMinus].set(PID::OmegaMinus, PID::Lambda, PID::Kaon, mSVParams->pidCutsOmegaMinus, bz); + + setupThreads(); + + for (auto& ft : mFitterV0) { + ft.setBz(bz); + } + for (auto& ft : mFitterCasc) { + ft.setBz(bz); + } } -void SVertexer::process(const gsl::span<const PVertex>& vertices, // primary vertices - const gsl::span<const GIndex>& trackIndex, // Global ID's for associated tracks - const gsl::span<const VRef>& vtxRefs, // references from vertex to these track IDs - const gsl::span<const TrackTPCITS>& tpcits, // global tracks - const gsl::span<const TrackITS>& its, // ITS tracks - const gsl::span<const TrackTPC>& tpc, // TPC tracks - std::vector<V0>& v0s, // found V0s - std::vector<RRef>& vtx2V0refs // references from PVertex to V0 -) +//__________________________________________________________________ +void SVertexer::setupThreads() { - std::unordered_map<uint64_t, int> cache; // cache for tested combinations, the value >0 will give the entry of prevalidated V0 in the v0sTmp - std::vector<V0> v0sTmp(1); // 1st one is dummy! - std::vector<int> v0sIdx; // id's in v0sTmp used attached to p.vertices - std::vector<RRef> pv2v0sRefs; // p.vertex to v0 index references + if (!mV0sTmp.empty()) { + return; + } + mV0sTmp.resize(mNThreads); + mCascadesTmp.resize(mNThreads); + mFitterV0.resize(mNThreads); + auto bz = o2::base::Propagator::Instance()->getNominalBz(); + for (auto& fitter : mFitterV0) { + fitter.setBz(bz); + fitter.setUseAbsDCA(mSVParams->useAbsDCA); + fitter.setPropagateToPCA(false); + fitter.setMaxR(mSVParams->maxRIni); + fitter.setMinParamChange(mSVParams->minParamChange); + fitter.setMinRelChi2Change(mSVParams->minRelChi2Change); + fitter.setMaxDZIni(mSVParams->maxDZIni); + fitter.setMaxChi2(mSVParams->maxChi2); + } + mFitterCasc.resize(mNThreads); + for (auto& fitter : mFitterCasc) { + fitter.setBz(bz); + fitter.setUseAbsDCA(mSVParams->useAbsDCA); + fitter.setPropagateToPCA(false); + fitter.setMaxR(mSVParams->maxRIniCasc); + fitter.setMinParamChange(mSVParams->minParamChange); + fitter.setMinRelChi2Change(mSVParams->minRelChi2Change); + fitter.setMaxDZIni(mSVParams->maxDZIni); + fitter.setMaxChi2(mSVParams->maxChi2); + } +} - TrackAccessor tracksPool(tpcits, its, tpc); +//__________________________________________________________________ +void SVertexer::buildT2V(const o2::globaltracking::RecoContainer& recoData) // accessor to various tracks +{ + // build track->vertices from vertices->tracks, rejecting vertex contributors + auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks + auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs - auto rejectTrack = [&tracksPool](GIndex id, char wantCharge) { - if (id.isPVContributor()) { - return true; - } - auto s = id.getSource(); - return (s != GIndex::TPCITS && s != GIndex::ITS) || tracksPool.getCharge(id) != wantCharge; + // track selector: at the moment reject prompt tracks contributing to vertex fit and unconstrained TPC tracks + auto selTrack = [&](GIndex gid) { + return (gid.isPVContributor() || !recoData.isTrackSourceLoaded(gid.getSource())) ? false : true; }; - int nv = vertices.size(); - size_t countTot = 0, countTotUnique = 0; + std::unordered_map<GIndex, std::pair<int, int>> tmap; + int nv = vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them + for (int i = 0; i < 2; i++) { + mTracksPool[i].clear(); + mVtxFirstTrack[i].clear(); + mVtxFirstTrack[i].resize(nv, -1); + } + for (int iv = 0; iv < nv; iv++) { - // - // select vertices - auto& pvrefs = pv2v0sRefs.emplace_back(v0sIdx.size(), 0); - const auto& pv = vertices[iv]; - if (pv.getNContributors() < 5) { - continue; - } - // const auto& vtref = vtxRefs[iv]; - //LOG(INFO) << "P.Vertex " << iv << pv; - //LOG(INFO) << "P.V. -> tracks " << vtref; - // - int first = vtref.getFirstEntry(); - int last = first + vtref.getEntries(); - size_t count = 0, countUnique = 0; - for (int ipos = first; ipos < last; ipos++) { - auto idpos = trackIndex[ipos]; - if (rejectTrack(idpos, 1)) { // skip at the moment TPC only tracks + int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries(); + for (; it < itLim; it++) { + auto tvid = trackIndex[it]; + if (!selTrack(tvid)) { continue; } - bool ambiguousPos = idpos.isAmbiguous(); // is this track compatible also with other vertex? - const auto& trPos = tracksPool.getTrack(idpos); - - for (int ineg = first; ineg < last; ineg++) { - auto idneg = trackIndex[ineg]; - if (rejectTrack(idneg, -1)) { // skip at the moment TPC only tracks + std::decay_t<decltype(tmap.find(tvid))> tref{}; + if (tvid.isAmbiguous()) { + auto tref = tmap.find(tvid); + if (tref != tmap.end()) { + mTracksPool[tref->second.second][tref->second.first].vBracket.setMax(iv); // this track was already processed with other vertex, account the latter continue; } - count++; - bool accept = false, newPair = true, ambiguousV0 = ambiguousPos && idneg.isAmbiguous(); // V0 is ambiguous if both tracks are compatible with other vertices - uint64_t idPosNeg = getPairIdx(idpos, idneg); - int* resPair = nullptr; - if (ambiguousV0) { // check if it was already processed - resPair = &cache[idPosNeg]; - if ((*resPair) < 0) { // was already checked and rejected - continue; - } else if ((*resPair) == 0) { // was not checked yet - countUnique++; - (*resPair) = -1; // this is rejection flag - } else { - newPair = false; - } - } - if (newPair) { - auto trNeg = tracksPool.getTrack(idneg); - // LOG(INFO) << "0: " << idpos << " " << tr0.o2::track::TrackPar::asString(); - // LOG(INFO) << "1: " << idneg << " " << tr1.o2::track::TrackPar::asString(); - int nCand = mFitter2Prong.process(trPos, trNeg); - if (nCand == 0) { // discard this pair - continue; - } - const auto& v0pos = mFitter2Prong.getPCACandidate(); - // check closeness to the beam-line - auto r2 = (v0pos[0] - mMeanVertex.getX()) * (v0pos[0] - mMeanVertex.getX()) + (v0pos[1] - mMeanVertex.getY()) * (v0pos[1] - mMeanVertex.getY()); - if (r2 < mMinR2ToMeanVertex) { - continue; - } - if (!mFitter2Prong.isPropagateTracksToVertexDone() && !mFitter2Prong.propagateTracksToVertex()) { - continue; - } - auto& trPosProp = mFitter2Prong.getTrack(0); - auto& trNegProp = mFitter2Prong.getTrack(1); - std::array<float, 3> pPos, pNeg; - trPosProp.getPxPyPzGlo(pPos); - trNegProp.getPxPyPzGlo(pNeg); - // estimate DCA of neutral V0 track to beamline: straight line with parametric equation - // x = X0 + pV0[0]*t, y = Y0 + pV0[1]*t reaches DCA to beamline (Xv, Yv) at - // t = -[ (x0-Xv)*pV0[0] + (y0-Yv)*pV0[1]) ] / ( pT(pV0)^2 ) - // Similar equation for 3D distance involving pV0[2] - std::array<float, 3> pV0 = {pPos[0] + pNeg[0], pPos[1] + pNeg[1], pPos[2] + pNeg[2]}; - float dx = v0pos[0] - mMeanVertex.getX(), dy = v0pos[1] - mMeanVertex.getY(); - float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXY = dx * pV0[0] + dy * pV0[1], tDCAXY = -prodXY / pt2V0; - float dcaX = dx + pV0[0] * tDCAXY, dcaY = dy + pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; - if (dca2 > mMaxDCAXY2ToMeanVertex) { - continue; - } - float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); - - // apply mass selections - float p2Pos = pPos[0] * pPos[0] + pPos[1] * pPos[1] + pPos[2] * pPos[2], p2Neg = pNeg[0] * pNeg[0] + pNeg[1] * pNeg[1] + pNeg[2] * pNeg[2]; - bool goodHyp = false; - for (int ipid = 0; ipid < SVertexerParams::NPIDV0; ipid++) { - if (mV0Hyps[ipid].check(p2Pos, p2Neg, p2V0, ptV0)) { - goodHyp = true; - break; - } - } - if (!goodHyp) { - continue; - } - // check cos of pointing angle - float dz = v0pos[2] - mMeanVertex.getZ(), cosPointingAngle = (prodXY + dz * pV0[2]) / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); - if (cosPointingAngle < mMinCosPointingAngle) { - if (ambiguousV0) { - continue; // no need to check this pair wrt other vertices - } - cosPointingAngle = mMinCosPointingAngle - 1e-6; - } else { // cuts passed, register v0 - accept = true; - } - // preliminary checks passed, cache V0 and proceed to specific vertex check - int szV0tmp = v0sTmp.size(); - if (resPair) { - *resPair = szV0tmp; // index of V0 to be created - } - // LOG(INFO) << "Adding new V0 " << szV0tmp; - - std::array<float, 3> v0posF = {float(v0pos[0]), float(v0pos[1]), float(v0pos[2])}; - auto& v0 = v0sTmp.emplace_back(v0posF, pV0, trPosProp, trNegProp, idpos, idneg); - if (accept) { - v0.setCosPA(cosPointingAngle); - v0.setDCA(mFitter2Prong.getChi2AtPCACandidate()); - v0.setVertexID(iv); - v0sIdx.push_back(szV0tmp); - pvrefs.changeEntriesBy(1); - } - } else { // check if already created V0 is good for this vertex - // LOG(INFO) << "Rechecking new V0 " << *resPair; - auto& v0 = v0sTmp[*resPair]; - std::array<float, 3> posV0, momV0; - v0.getXYZGlo(posV0); - v0.getPxPyPzGlo(momV0); - float cosPointingAngle = posV0[0] * momV0[0] + posV0[1] * momV0[1] + posV0[2] * momV0[2]; - cosPointingAngle /= std::sqrt((posV0[0] * posV0[0] + posV0[1] * posV0[1] + posV0[2] * posV0[2]) * (momV0[0] * momV0[0] + momV0[1] * momV0[1] + momV0[2] * momV0[2])); - if (cosPointingAngle > v0.getCosPA()) { // reassign - v0.setCosPA(cosPointingAngle); - v0.setVertexID(iv); - pvrefs.changeEntriesBy(1); - } - } + } + const auto& trc = recoData.getTrackParam(tvid); + int posneg = trc.getSign() < 0 ? 1 : 0; + float r = std::sqrt(trc.getX() * trc.getX() + trc.getY() * trc.getY()); + mTracksPool[posneg].emplace_back(TrackCand{trc, tvid, {iv, iv}, r}); + if (tvid.isAmbiguous()) { // track attached to >1 vertex, remember that it was already processed + tmap[tvid] = {mTracksPool[posneg].size() - 1, posneg}; } } - countTot += count; - countTotUnique += countUnique; - // LOG(INFO) << "Tried " << count << " combs with " << countUnique << " uniques"; } - // finalize V0s - for (int iv = 0; iv < nv; iv++) { - const auto& pvtx = vertices[iv]; - const auto& pvrefsTmp = pv2v0sRefs[iv]; - auto& pvrefsFin = vtx2V0refs.emplace_back(v0s.size(), 0); - int from = pvrefsTmp.getFirstEntry(), to = from + pvrefsTmp.getEntries(), nAdded = 0; - for (int iv0 = from; iv0 < to; iv0++) { - const auto& v0tmp = v0sTmp[v0sIdx[iv0]]; - if (v0tmp.getVertexID() != iv) { // this v0 - p.vertex association was reassigned - continue; + // register 1st track of each charge for each vertex + + for (int pn = 0; pn < 2; pn++) { + auto& vtxFirstT = mVtxFirstTrack[pn]; + const auto& tracksPool = mTracksPool[pn]; + for (unsigned i = 0; i < tracksPool.size(); i++) { + const auto& t = tracksPool[i]; + if (vtxFirstT[t.vBracket.getMin()] == -1) { + vtxFirstT[t.vBracket.getMin()] = i; + } + } + } + + LOG(INFO) << "Collected " << mTracksPool[POS].size() << " positive and " << mTracksPool[NEG].size() << " negative seeds"; +} + +//__________________________________________________________________ +bool SVertexer::checkV0(const TrackCand& seedP, const TrackCand& seedN, int iP, int iN, int ithread) +{ + auto& fitterV0 = mFitterV0[ithread]; + int nCand = fitterV0.process(seedP, seedN); + if (nCand == 0) { // discard this pair + return false; + } + const auto& v0XYZ = fitterV0.getPCACandidate(); + // validate V0 radial position + // check closeness to the beam-line + float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; + if (r2v0 < mMinR2ToMeanVertex) { + return false; + } + float rv0 = std::sqrt(r2v0), drv0P = rv0 - seedP.minR, drv0N = rv0 - seedN.minR; + if (drv0P > mSVParams->causalityRTolerance || drv0P < -mSVParams->maxV0ToProngsRDiff || + drv0N > mSVParams->causalityRTolerance || drv0N < -mSVParams->maxV0ToProngsRDiff) { + return false; + } + + if (!fitterV0.isPropagateTracksToVertexDone() && !fitterV0.propagateTracksToVertex()) { + return false; + } + int cand = 0; + auto& trPProp = fitterV0.getTrack(0, cand); + auto& trNProp = fitterV0.getTrack(1, cand); + std::array<float, 3> pP, pN; + trPProp.getPxPyPzGlo(pP); + trNProp.getPxPyPzGlo(pN); + // estimate DCA of neutral V0 track to beamline: straight line with parametric equation + // x = X0 + pV0[0]*t, y = Y0 + pV0[1]*t reaches DCA to beamline (Xv, Yv) at + // t = -[ (x0-Xv)*pV0[0] + (y0-Yv)*pV0[1]) ] / ( pT(pV0)^2 ) + // Similar equation for 3D distance involving pV0[2] + std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; + if (pt2V0 < mMinPt2V0) { // pt cut + return false; + } + if (pV0[2] * pV0[2] / pt2V0 > mMaxTgl2V0) { // tgLambda cut + return false; + } + float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); + // apply mass selections + float p2Pos = pP[0] * pP[0] + pP[1] * pP[1] + pP[2] * pP[2], p2Neg = pN[0] * pN[0] + pN[1] * pN[1] + pN[2] * pN[2]; + + bool goodHyp = false; + std::array<bool, NHypV0> hypCheckStatus{}; + for (int ipid = 0; ipid < NHypV0; ipid++) { + if (mV0Hyps[ipid].check(p2Pos, p2Neg, p2V0, ptV0)) { + goodHyp = hypCheckStatus[ipid] = true; + } + } + if (!goodHyp) { + return false; + } + + bool checkForCascade = mEnableCascades && r2v0 < mMaxR2ToMeanVertexCascV0 && (hypCheckStatus[HypV0::Lambda] || hypCheckStatus[HypV0::AntiLambda]); + bool rejectIfNotCascade = false; + float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; + float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0); + + if (checkForCascade) { // use loser cuts for cascade v0 candidates + if (dca2 > mMaxDCAXY2ToMeanVertexV0Casc || cosPAXY < mSVParams->minCosPAXYMeanVertexCascV0) { + return false; + } + } + if (dca2 > mMaxDCAXY2ToMeanVertex || cosPAXY < mSVParams->minCosPAXYMeanVertex) { + if (checkForCascade) { + rejectIfNotCascade = true; + } else { + return false; + } + } + + auto vlist = seedP.vBracket.getOverlap(seedN.vBracket); // indices of vertices shared by both seeds + bool added = false; + auto bestCosPA = checkForCascade ? mSVParams->minCosPACascV0 : mSVParams->minCosPA; + for (int iv = vlist.getMin(); iv <= vlist.getMax(); iv++) { + const auto& pv = mPVertices[iv]; + const auto v0XYZ = fitterV0.getPCACandidatePos(cand); + // check cos of pointing angle + float dx = v0XYZ[0] - pv.getX(), dy = v0XYZ[1] - pv.getY(), dz = v0XYZ[2] - pv.getZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); + if (cosPA < bestCosPA) { + continue; + } + if (!added) { + auto& v0new = mV0sTmp[ithread].emplace_back(v0XYZ, pV0, fitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp, seedP.gid, seedN.gid); + v0new.setDCA(fitterV0.getChi2AtPCACandidate()); + added = true; + } + auto& v0 = mV0sTmp[ithread].back(); + v0.setCosPA(cosPA); + v0.setVertexID(iv); + bestCosPA = cosPA; + } + if (!added) { + return false; + } + auto& v0 = mV0sTmp[ithread].back(); + + // check cascades + if (checkForCascade) { + int nCascAdded = 0; + if (hypCheckStatus[HypV0::Lambda]) { + nCascAdded += checkCascades(rv0, pV0, p2V0, iN, NEG, ithread); + } + if (hypCheckStatus[HypV0::AntiLambda]) { + nCascAdded += checkCascades(rv0, pV0, p2V0, iP, POS, ithread); + } + if (!nCascAdded && rejectIfNotCascade) { // v0 would be accepted only if it creates a cascade + mV0sTmp[ithread].pop_back(); + return false; + } + } + + return true; +} + +//__________________________________________________________________ +int SVertexer::checkCascades(float rv0, std::array<float, 3> pV0, float p2V0, int avoidTrackID, int posneg, int ithread) +{ + // check last added V0 for belonging to cascade + auto& fitterCasc = mFitterCasc[ithread]; + const auto& v0 = mV0sTmp[ithread].back(); + auto& tracks = mTracksPool[posneg]; + const auto& pv = mPVertices[v0.getVertexID()]; + int nCascIni = mCascadesTmp[ithread].size(); + // start from the 1st track compatible with V0's primary vertex + for (unsigned it = mVtxFirstTrack[posneg][v0.getVertexID()]; it < tracks.size(); it++) { + if (it == avoidTrackID) { + continue; // skip the track used by V0 + } + auto& bach = tracks[it]; + if (bach.vBracket > v0.getVertexID()) { + break; // all other bachelor candidates will be also not compatible with this PV + } + if (bach.vBracket.isOutside(v0.getVertexID())) { + LOG(ERROR) << "Incompatible bachelor: PV " << bach.vBracket.asString() << " vs V0 " << v0.getVertexID(); + } + if (bach.minR > rv0 + mSVParams->causalityRTolerance) { + continue; + } + int nCandC = fitterCasc.process(v0, bach); + if (nCandC == 0) { // discard this pair + continue; + } + int candC = 0; + const auto& cascXYZ = fitterCasc.getPCACandidatePos(candC); + // make sure the cascade radius is smaller than that of the vertex + float dxc = cascXYZ[0] - pv.getX(), dyc = cascXYZ[1] - pv.getY(), dzc = cascXYZ[2] - pv.getZ(), r2casc = dxc * dxc + dyc * dyc; + if (rv0 * rv0 - r2casc < mMinR2DiffV0Casc || r2casc < mMinR2ToMeanVertex) { + continue; + } + // do we want to apply mass cut ? + // + if (!fitterCasc.isPropagateTracksToVertexDone() && !fitterCasc.propagateTracksToVertex()) { + continue; + } + auto& trNeut = fitterCasc.getTrack(0, candC); + auto& trBach = fitterCasc.getTrack(1, candC); + trNeut.setPID(o2::track::PID::Lambda); + trBach.setPID(o2::track::PID::Pion); + std::array<float, 3> pNeut, pBach; + trNeut.getPxPyPzGlo(pNeut); + trBach.getPxPyPzGlo(pBach); + std::array<float, 3> pCasc = {pNeut[0] + pBach[0], pNeut[1] + pBach[1], pNeut[2] + pBach[2]}; + auto prodPPos = pV0[0] * dxc + pV0[1] * dyc + pV0[2] * dzc; + if (prodPPos < 0.) { // causality cut + continue; + } + float pt2Casc = pCasc[0] * pCasc[0] + pCasc[1] * pCasc[1], p2Casc = pt2Casc + pCasc[2] * pCasc[2]; + if (pt2Casc < mMinPt2Casc) { // pt cut + continue; + } + if (pCasc[2] * pCasc[2] / pt2Casc > mMaxTgl2Casc) { // tgLambda cut + continue; + } + // LOG(INFO) << "ptcasc2 " << pt2Casc << " tglcasc2 " << pCasc[2]*pCasc[2] / pt2Casc << " cut " << mMaxTgl2Casc; + float cosPA = (pCasc[0] * dxc + pCasc[1] * dyc + pCasc[2] * dzc) / std::sqrt(p2Casc * (r2casc + dzc * dzc)); + if (cosPA < mSVParams->minCosPACasc) { + continue; + } + float p2Bach = pBach[0] * pBach[0] + pBach[1] * pBach[1] + pBach[2] * pBach[2]; + float ptCasc = std::sqrt(pt2Casc); + bool goodHyp = false; + for (int ipid = 0; ipid < NHypCascade; ipid++) { + if (mCascHyps[ipid].check(p2V0, p2Bach, p2Casc, ptCasc)) { + goodHyp = true; + break; } - v0s.push_back(v0tmp); - nAdded++; } - pvrefsFin.setEntries(nAdded); - LOG(INFO) << nAdded << " V0s added for vertex " << iv << " with " << pvtx.getNContributors() << " tracks, out of initial " << pvrefsTmp.getEntries(); - pvtx.print(); + if (!goodHyp) { + continue; + } + auto& casc = mCascadesTmp[ithread].emplace_back(cascXYZ, pCasc, fitterCasc.calcPCACovMatrixFlat(candC), trNeut, trBach, mV0sTmp[ithread].size() - 1, bach.gid); + o2::track::TrackParCov trc = casc; + o2::dataformats::DCA dca; + if (!trc.propagateToDCA(pv, fitterCasc.getBz(), &dca, 5.) || + std::abs(dca.getY()) > mSVParams->maxDCAXYCasc || std::abs(dca.getZ()) > mSVParams->maxDCAZCasc) { + mCascadesTmp[ithread].pop_back(); + continue; + } + casc.setCosPA(cosPA); + casc.setVertexID(v0.getVertexID()); + casc.setDCA(fitterCasc.getChi2AtPCACandidate()); } + return mCascadesTmp[ithread].size() - nCascIni; +} - LOG(INFO) << "Tried " << countTot << " combs in total " << countTotUnique << " uniques"; +//__________________________________________________________________ +void SVertexer::setNThreads(int n) +{ +#ifdef WITH_OPENMP + mNThreads = n > 0 ? n : 1; +#else + mNThreads = 1; +#endif } diff --git a/Detectors/Vertexing/src/SVertexerParams.cxx b/Detectors/Vertexing/src/SVertexerParams.cxx index 802910be6c97b..bd80ca97d856c 100644 --- a/Detectors/Vertexing/src/SVertexerParams.cxx +++ b/Detectors/Vertexing/src/SVertexerParams.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/Vertexing/src/V0Hypothesis.cxx b/Detectors/Vertexing/src/V0Hypothesis.cxx deleted file mode 100644 index 7ccd60ea1d18f..0000000000000 --- a/Detectors/Vertexing/src/V0Hypothesis.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file V0Hypothesis.cxx -/// \brief V0 hypothesis checker -/// \author ruben.shahoyan@cern.ch - -#include "DetectorsVertexing/V0Hypothesis.h" - -using namespace o2::vertexing; - -void V0Hypothesis::set(PID v0, PID ppos, PID pneg, float sig, float nSig, float margin, float cpt, float bz) -{ - mPIDV0 = v0; - mPIDPosProng = ppos; - mPIDNegProng = pneg; - mSigma = sig; - mNSigma = nSig; - mMargin = margin; - mCPt = std::abs(bz) > 1e-3 ? cpt * 5.0066791 / bz : 0.; // assume that pT dependent sigma is linear with B -} - -void V0Hypothesis::set(PID v0, PID ppos, PID pneg, const float pars[SVertexerParams::NPIDParams], float bz) -{ - set(v0, ppos, pneg, pars[SVertexerParams::SigmaMV0], pars[SVertexerParams::NSigmaMV0], - pars[SVertexerParams::Margin], pars[SVertexerParams::CPt], bz); -} diff --git a/Detectors/Vertexing/src/VertexTrackMatcher.cxx b/Detectors/Vertexing/src/VertexTrackMatcher.cxx index e45f9da7d7fa5..e545e8eccde7e 100644 --- a/Detectors/Vertexing/src/VertexTrackMatcher.cxx +++ b/Detectors/Vertexing/src/VertexTrackMatcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,12 +13,16 @@ /// \brief Class for vertex track association /// \author ruben.shahoyan@cern.ch +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "DetectorsVertexing/VertexTrackMatcher.h" -#include <unordered_map> -#include <numeric> +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" #include "TPCBase/ParameterElectronics.h" #include "TPCBase/ParameterDetector.h" #include "TPCBase/ParameterGas.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include <unordered_map> +#include <numeric> using namespace o2::vertexing; @@ -25,243 +30,183 @@ using namespace o2::vertexing; void VertexTrackMatcher::init() { mPVParams = &o2::vertexing::PVertexerParams::Instance(); - updateTPCTimeDependentParams(); // RS FIXME eventually should be set from CCDB for every TF + updateTimeDependentParams(); // RS FIXME eventually should be set from CCDB for every TF } -void VertexTrackMatcher::updateTPCTimeDependentParams() +void VertexTrackMatcher::updateTimeDependentParams() { // tpc time bin in microseconds - auto& gasParam = o2::tpc::ParameterGas::Instance(); - auto& elParam = o2::tpc::ParameterElectronics::Instance(); - auto& detParam = o2::tpc::ParameterDetector::Instance(); - mTPCBin2MUS = elParam.ZbinWidth; - mMaxTPCDriftTimeMUS = detParam.TPClength / gasParam.DriftV; + if (mMaxTPCDriftTimeMUS == 0) { + auto& gasParam = o2::tpc::ParameterGas::Instance(); + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + auto& detParam = o2::tpc::ParameterDetector::Instance(); + mTPCBin2MUS = elParam.ZbinWidth; + mMaxTPCDriftTimeMUS = detParam.TPClength / gasParam.DriftV; + } + if (mITSROFrameLengthMUS == 0) { + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); + mITSROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParams.roFrameLengthTrig * 1.e-3; + LOG(INFO) << "VertexTrackMatcher::ITSROFrameLengthMUS = " << mITSROFrameLengthMUS; + } + if (mMFTROFrameLengthMUS == 0) { + std::unique_ptr<o2::parameters::GRPObject> grp{o2::parameters::GRPObject::loadFrom()}; + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::MFT>::Instance(); + mMFTROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::MFT) ? alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParams.roFrameLengthTrig * 1.e-3; + LOG(INFO) << "VertexTrackMatcher::MFTROFrameLengthMUS = " << mMFTROFrameLengthMUS; + } } -void VertexTrackMatcher::process(const gsl::span<const PVertex>& vertices, - const gsl::span<const GIndex>& v2tfitIDs, - const gsl::span<const VRef>& v2tfitRefs, - const gsl::span<const TrackTPCITS>& tpcitsTracks, - const gsl::span<const TrackITS>& itsTracks, - const gsl::span<const ITSROFR>& itsROFR, - const gsl::span<const TrackTPC>& tpcTracks, - std::vector<GIndex>& trackIndex, +void VertexTrackMatcher::process(const o2::globaltracking::RecoContainer& recoData, + std::vector<VTIndex>& trackIndex, std::vector<VRef>& vtxRefs) { + updateTimeDependentParams(); - TmpMap tmpMap; - tmpMap.reserve(vertices.size()); + auto vertices = recoData.getPrimaryVertices(); + auto v2tfitIDs = recoData.getPrimaryVertexContributors(); + auto v2tfitRefs = recoData.getPrimaryVertexContributorsRefs(); - // TPC/ITS and TPC tracks are not sorted in time, do this and exclude indiced of tracks used in the vertex fit - std::vector<int> idTPCITS(tpcitsTracks.size()); // indices of TPCITS tracks sorted in time - std::vector<int> idVtxIRMin(vertices.size()); // indices of vertices sorted in IRmin - std::vector<int> flgITS(itsTracks.size(), 0); - std::vector<int> idTPC(tpcTracks.size()); // indices of TPC tracks sorted in min time - std::iota(idTPC.begin(), idTPC.end(), 0); - std::iota(idTPCITS.begin(), idTPCITS.end(), 0); - std::iota(idVtxIRMin.begin(), idVtxIRMin.end(), 0); - for (auto id : v2tfitIDs) { // flag matched ITS-TPC tracks used in the vertex fit, we exclude them from this association - idTPCITS[id.getIndex()] = -1; - } - for (const auto& tpcits : tpcitsTracks) { // flag standalone ITS and TPC tracks used in global matched, we exclude them from association to vertex - flgITS[tpcits.getRefITS()] = -1; - idTPC[tpcits.getRefTPC()] = -1; - } - std::sort(idVtxIRMin.begin(), idVtxIRMin.end(), [&vertices](int i, int j) { // sort according to IRMin - return vertices[i].getIRMin() < vertices[j].getIRMin(); - }); - std::sort(idTPCITS.begin(), idTPCITS.end(), [&tpcitsTracks](int i, int j) { // sort according to central time - float tI = (i < 0) ? 1e9 : tpcitsTracks[i].getTimeMUS().getTimeStamp(); - float tJ = (j < 0) ? 1e9 : tpcitsTracks[j].getTimeMUS().getTimeStamp(); - return tI < tJ; - }); + int nv = vertices.size(), nv1 = nv + 1; + TmpMap tmpMap(nv1); + auto& orphans = tmpMap.back(); // in the last element we store unassigned track indices - std::vector<TBracket> tpcTimes; - tpcTimes.reserve(tpcTracks.size()); - for (const auto& trc : tpcTracks) { - tpcTimes.emplace_back(tpcTimeBin2MUS(trc.getTime0() - trc.getDeltaTBwd()), tpcTimeBin2MUS(trc.getTime0() + trc.getDeltaTFwd())); - } - std::sort(idTPC.begin(), idTPC.end(), [&tpcTimes](int i, int j) { // sort according to max time - float tI = (i < 0) ? 1e9 : tpcTimes[i].getMax(); - float tJ = (j < 0) ? 1e9 : tpcTimes[j].getMax(); - return tI < tJ; - }); - - // Important: do this in the same order in which VtxTrackIndex::Source enums are defined! - attachTPCITS(tmpMap, tpcitsTracks, idTPCITS, vertices); - attachITS(tmpMap, itsTracks, itsROFR, flgITS, vertices, idVtxIRMin); - attachTPC(tmpMap, tpcTimes, idTPC, vertices, idVtxIRMin); - - // build vector of global indices - trackIndex.clear(); - vtxRefs.clear(); - memset(idTPCITS.data(), 0, sizeof(int) * idTPCITS.size()); - memset(idTPC.data(), 0, sizeof(int) * idTPC.size()); - memset(flgITS.data(), 0, sizeof(int) * flgITS.size()); - std::array<std::vector<int>*, GIndex::NSources> vptr; - vptr[GIndex::TPCITS] = &idTPCITS; - vptr[GIndex::ITS] = &flgITS; - vptr[GIndex::TPC] = &idTPC; - int nv = vertices.size(); - // flag tracks attached to >1 vertex + // register vertex contributors + std::unordered_map<GIndex, bool> vcont; + std::vector<VtxTBracket> vtxOrdBrack; // vertex indices and brackets sorted in tmin + float maxVtxSpan = 0; for (int iv = 0; iv < nv; iv++) { - const auto& trvec = tmpMap[iv]; - for (auto gid : trvec) { - (*vptr[gid.getSource()])[gid.getIndex()]++; - } - } - - for (int iv = 0; iv < nv; iv++) { - int srcStart[GIndex::NSources + 1]; - int entry = trackIndex.size(); - srcStart[GIndex::TPCITS] = entry; - for (int is = 1; is < GIndex::NSources; is++) { - srcStart[is] = -1; - } - - // 1st: attach indices of global tracks used in vertex fit int idMin = v2tfitRefs[iv].getFirstEntry(), idMax = idMin + v2tfitRefs[iv].getEntries(); + auto& vtxIds = tmpMap[iv]; // global IDs of contibuting tracks + vtxIds.reserve(v2tfitRefs[iv].getEntries()); for (int id = idMin; id < idMax; id++) { - trackIndex.push_back(v2tfitIDs[id]); - } - - // 2nd: attach non-contributing tracks - const auto& trvec = tmpMap[iv]; - for (const auto gid0 : trvec) { - int src = gid0.getSource(); - if (srcStart[src] == -1) { - srcStart[src] = trackIndex.size(); - } - auto& gid = trackIndex.emplace_back(gid0); - if ((*vptr[src])[gid.getIndex()] > 1) { - gid.setAmbiguous(); - } + auto gid = v2tfitIDs[id]; + vtxIds.emplace_back(gid).setPVContributor(); + vcont[gid] = true; } - - auto& vr = vtxRefs.emplace_back(entry, trackIndex.size() - entry); - srcStart[GIndex::NSources] = trackIndex.size(); - for (int is = GIndex::NSources; is > 0; is--) { - if (srcStart[is] == -1) { // in case the source did not contribute - srcStart[is] = srcStart[is + 1]; - } - vr.setFirstEntryOfSource(is, srcStart[is]); + const auto& vtx = vertices[iv]; + const auto& vto = vtxOrdBrack.emplace_back(VtxTBracket{ + {float((vtx.getIRMin().differenceInBC(recoData.startIR) - 0.5f) * o2::constants::lhc::LHCBunchSpacingMUS), + float((vtx.getIRMax().differenceInBC(recoData.startIR) + 0.5f) * o2::constants::lhc::LHCBunchSpacingMUS)}, + iv}); + if (vto.tBracket.delta() > maxVtxSpan) { + maxVtxSpan = vto.tBracket.delta(); } } -} - -///______________________________________________________________________________________ -void VertexTrackMatcher::attachTPCITS(TmpMap& tmpMap, const gsl::span<const TrackTPCITS>& tpcits, const std::vector<int>& idTPCITS, const gsl::span<const PVertex>& vertices) -{ - int itrCurr = 0, nvt = vertices.size(), ntr = tpcits.size(); - // indices of tracks used for vertex fit will be in the end, find their start and max error - float maxErr = 0; - for (int i = 0; i < ntr; i++) { - if (idTPCITS[i] < 0) { - ntr = i; - break; - } - float err = tpcits[idTPCITS[i]].getTimeMUS().getTimeStampError(); - if (maxErr < err) { - maxErr = err; - } - } - auto maxErr2 = maxErr * maxErr; - for (int ivtCurr = 0; ivtCurr < nvt; ivtCurr++) { - const auto& vtxT = vertices[ivtCurr].getTimeStamp(); - auto rangeT = mPVParams->nSigmaTimeCut * std::sqrt(maxErr2 + vtxT.getTimeStampError() * vtxT.getTimeStampError()); - float minTime = vtxT.getTimeStamp() - rangeT, maxTime = vtxT.getTimeStamp() + rangeT; - // proceed to the 1st track having compatible time - int itr = itrCurr; - while (itr < ntr) { - const auto& trcT = tpcits[idTPCITS[itr]].getTimeMUS(); - if (trcT.getTimeStamp() < minTime) { - itrCurr = itr; - } else if (trcT.getTimeStamp() > maxTime) { + // sort vertices in tmin + std::sort(vtxOrdBrack.begin(), vtxOrdBrack.end(), [](const VtxTBracket& a, const VtxTBracket& b) { return a.tBracket.getMin() < b.tBracket.getMin(); }); + + extractTracks(recoData, vcont); // extract all track t-brackets, excluding those tracks which contribute to vertex (already attached) + + int ivStart = 0, nAssigned = 0, nAmbiguous = 0; + std::vector<int> vtxList; // list of vertices which match to checked track + for (const auto& tro : mTBrackets) { + vtxList.clear(); + for (int iv = ivStart; iv < nv; iv++) { + const auto& vto = vtxOrdBrack[iv]; + auto res = tro.tBracket.isOutside(vto.tBracket); + if (res == TBracket::Below) { // vertex preceeds the track + if (tro.tBracket.getMin() > vto.tBracket.getMin() + maxVtxSpan) { // all following vertices will be preceeding all following tracks times + ivStart = ++iv; + break; + } + continue; // following vertex with longer span might still match this track + } + if (res == TBracket::Above) { // track preceeds the vertex, so will preceed also all following vertices break; - } else if (compatibleTimes(vtxT, trcT)) { - tmpMap[ivtCurr].emplace_back(idTPCITS[itr], GIndex::TPCITS); } - itr++; + // track matches to vertex, register + vtxList.push_back(vto.origID); // flag matching vertex } - } -} - -///______________________________________________________________________________________ -void VertexTrackMatcher::attachITS(TmpMap& tmpMap, const gsl::span<const TrackITS>& itsTracks, const gsl::span<const ITSROFR>& itsROFR, const std::vector<int>& flITS, - const gsl::span<const PVertex>& vertices, std::vector<int>& idxVtx) -{ - int irofCurr = 0, nvt = vertices.size(), ntr = itsTracks.size(); - int nROFs = itsROFR.size(); - - for (int ivtCurr = 0; ivtCurr < nvt; ivtCurr++) { - const auto& vtx = vertices[idxVtx[ivtCurr]]; // we iterate over vertices in order of their getIRMin() - int irof = irofCurr; - while (irof < nROFs) { - const auto& rofr = itsROFR[irof]; - auto irMin = rofr.getBCData(), irMax = irMin + mITSROFrameLengthInBC; - if (irMax < vtx.getIRMin()) { - irofCurr = irof; - } else if (irMin > vtx.getIRMax()) { - break; + if ((tro.origID.getSource() == GIndex::Source::MFT) || (tro.origID.getSource() == GIndex::Source::MFTMCH)) { // Fwd tracks are treated differently: tracks with unresolved ambiguities are marked as orphans -> unassigned + if (vtxList.size() == 1) { + nAssigned++; + tmpMap[vtxList[0]].emplace_back(tro.origID).setAmbiguous(); } else { - if (irMax == vtx.getIRMin()) { - irofCurr = irof; + orphans.emplace_back(tro.origID); // register as unassigned MFT track + } + if (vtxList.size() > 1) { // did track match to multiple vertices? + nAmbiguous++; // Should count MFT tracks here even if they end up on the orphans/unassigned table? + } + } else { + if (vtxList.size()) { + nAssigned++; + for (auto v : vtxList) { + tmpMap[v].emplace_back(tro.origID).setAmbiguous(); } - int maxItr = rofr.getNEntries() + rofr.getFirstEntry(); - for (int itr = rofr.getFirstEntry(); itr < maxItr; itr++) { - if (flITS[itr] != -1) { - tmpMap[ivtCurr].emplace_back(itr, GIndex::ITS); - } + if (vtxList.size() > 1) { // did track match to multiple vertices? + nAmbiguous++; } + } else { + orphans.emplace_back(tro.origID); // register unassigned track } - irof++; } } -} -///______________________________________________________________________________________ -void VertexTrackMatcher::attachTPC(TmpMap& tmpMap, const std::vector<TBracket>& tpcTimes, const std::vector<int>& idTPC, - const gsl::span<const PVertex>& vertices, std::vector<int>& idVtx) -{ - int itrCurr = 0, nvt = vertices.size(), ntr = idTPC.size(); - // indices of tracks used for vertex fit will be in the end, find their start and max error - for (int i = 0; i < ntr; i++) { - if (idTPC[i] < 0) { - ntr = i; - break; - } - } - for (int ivtCurr = 0; ivtCurr < nvt; ivtCurr++) { - const auto& vtx = vertices[idVtx[ivtCurr]]; - TBracket tV(vtx.getIRMin().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3, - vtx.getIRMax().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS * 1e-3); - // proceed to the 1st track having compatible time, idTPC provides track IDs ordered in max time - int itr = itrCurr; - while (itr < ntr) { - const auto& tT = tpcTimes[idTPC[itr]]; - auto rel = tV.isOutside(tT); - if (rel == TBracket::Below) { // tmax of track < tmin of vtx - itrCurr = itr; - } else if (rel == TBracket::Inside) { - tmpMap[ivtCurr].emplace_back(idTPC[itr], GIndex::TPC); - } else if (tT.getMax() - mMaxTPCDriftTimeMUS > tV.getMax()) { - break; + // build final vector of global indices + trackIndex.clear(); + vtxRefs.clear(); + + for (int iv = 0; iv < nv1; iv++) { + auto& trvec = tmpMap[iv]; + // sort entries in each vertex track indices list according to the source + std::sort(trvec.begin(), trvec.end(), [](VTIndex a, VTIndex b) { return a.getSource() < b.getSource(); }); + + auto entry0 = trackIndex.size(); // start of entries for this vertex + auto& vr = vtxRefs.emplace_back(); + vr.setVtxID(iv < nv ? iv : -1); // flag table for unassigned tracks by VtxID = -1 + int oldSrc = -1; + for (const auto gid0 : trvec) { + int src = gid0.getSource(); + while (oldSrc < src) { + oldSrc++; + vr.setFirstEntryOfSource(oldSrc, trackIndex.size()); // register start of new source } - itr++; + trackIndex.push_back(gid0); + } + while (++oldSrc < GIndex::NSources) { + vr.setFirstEntryOfSource(oldSrc, trackIndex.size()); } + vr.setEnd(trackIndex.size()); + LOG(INFO) << vr; } + LOG(INFO) << "Assigned " << nAssigned << " (" << nAmbiguous << " ambiguously) out of " << mTBrackets.size() << " non-contributor tracks + " << vcont.size() << " contributors"; } -//______________________________________________ -void VertexTrackMatcher::setITSROFrameLengthInBC(int nbc) +//________________________________________________________ +void VertexTrackMatcher::extractTracks(const o2::globaltracking::RecoContainer& data, const std::unordered_map<GIndex, bool>& vcont) { - mITSROFrameLengthInBC = nbc; -} + // Scan all inputs and create tracks -//______________________________________________ -bool VertexTrackMatcher::compatibleTimes(const TimeEst& vtxT, const TimeEst& trcT) const -{ - float err2 = vtxT.getTimeStampError() * vtxT.getTimeStampError() + trcT.getTimeStampError() * trcT.getTimeStampError(); - float dfred = (vtxT.getTimeStamp() - trcT.getTimeStamp()) * mPVParams->nSigmaTimeCut; - return dfred * dfred < err2; + mTBrackets.clear(); + + auto creator = [this, &vcont](auto& _tr, GIndex _origID, float t0, float terr) { + if (vcont.find(_origID) != vcont.end()) { // track is contributor to vertex, already accounted + return true; + } + if constexpr (isTPCTrack<decltype(_tr)>()) { + // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins + t0 *= this->mTPCBin2MUS; + terr *= this->mTPCBin2MUS; + } else if constexpr (isITSTrack<decltype(_tr)>()) { + t0 += 0.5 * this->mITSROFrameLengthMUS; // ITS time is supplied in \mus as beginning of ROF + terr *= this->mITSROFrameLengthMUS; // error is supplied as a half-ROF duration, convert to \mus + } else if constexpr (isMFTTrack<decltype(_tr)>()) { // Same for MFT + t0 += 0.5 * this->mMFTROFrameLengthMUS; + terr *= this->mMFTROFrameLengthMUS; + } else if constexpr (isGlobalFwdTrack<decltype(_tr)>()) { + t0 = _tr.getTimeMUS().getTimeStamp(); + terr = _tr.getTimeMUS().getTimeStampError(); + } + // for all other tracks the time is in \mus with gaussian error + mTBrackets.emplace_back(TrackTBracket{{t0 - terr, t0 + terr}, _origID}); + return true; + }; + + data.createTracksVariadic(creator); + + // sort in increasing min.time + std::sort(mTBrackets.begin(), mTBrackets.end(), [](const TrackTBracket& a, const TrackTBracket& b) { return a.tBracket.getMin() < b.tBracket.getMin(); }); + + LOG(INFO) << "collected " << mTBrackets.size() << " non-contributor and " << vcont.size() << " contributor seeds"; } diff --git a/Detectors/Vertexing/test/testDCAFitterN.cxx b/Detectors/Vertexing/test/testDCAFitterN.cxx index add77c641f0f6..562ce6fca4ee5 100644 --- a/Detectors/Vertexing/test/testDCAFitterN.cxx +++ b/Detectors/Vertexing/test/testDCAFitterN.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,7 +31,7 @@ namespace vertexing using Vec3D = ROOT::Math::SVector<double, 3>; template <class FITTER> -float checkResults(o2::utils::TreeStreamRedirector& outs, std::string& treeName, const FITTER& fitter, +float checkResults(o2::utils::TreeStreamRedirector& outs, std::string& treeName, FITTER& fitter, Vec3D& vgen, TLorentzVector& genPar, const std::vector<double>& dtMass) { int nCand = fitter.getNCandidates(); @@ -160,6 +161,7 @@ BOOST_AUTO_TEST_CASE(DCAFitterNProngs) ft.setPropagateToPCA(true); // After finding the vertex, propagate tracks to the DCA. This is default anyway ft.setMaxR(200); // do not consider V0 seeds with 2D circles crossing above this R. This is default anyway ft.setMaxDZIni(4); // do not consider V0 seeds with tracks Z-distance exceeding this. This is default anyway + ft.setMaxDXYIni(4); // do not consider V0 seeds with tracks XY-distance exceeding this. This is default anyway ft.setMinParamChange(1e-3); // stop iterations if max correction is below this value. This is default anyway ft.setMinRelChi2Change(0.9); // stop iterations if chi2 improves by less that this factor diff --git a/Detectors/ZDC/CMakeLists.txt b/Detectors/ZDC/CMakeLists.txt index 364119694abdb..8a21afda4a4aa 100644 --- a/Detectors/ZDC/CMakeLists.txt +++ b/Detectors/ZDC/CMakeLists.txt @@ -1,13 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(base) add_subdirectory(simulation) +add_subdirectory(reconstruction) add_subdirectory(macro) +add_subdirectory(raw) +add_subdirectory(workflow) diff --git a/Detectors/ZDC/base/CMakeLists.txt b/Detectors/ZDC/base/CMakeLists.txt index 42d1b92530b47..49cbb36fe1520 100644 --- a/Detectors/ZDC/base/CMakeLists.txt +++ b/Detectors/ZDC/base/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ZDCBase SOURCES src/Geometry.cxx src/ModuleConfig.cxx - PUBLIC_LINK_LIBRARIES O2::CommonConstants ROOT::MathCore FairRoot::Base) + PUBLIC_LINK_LIBRARIES O2::CommonConstants ROOT::MathCore FairRoot::Base O2::FrameworkLogger) o2_target_root_dictionary(ZDCBase HEADERS include/ZDCBase/Geometry.h include/ZDCBase/Constants.h include/ZDCBase/ModuleConfig.h) diff --git a/Detectors/ZDC/base/include/ZDCBase/Constants.h b/Detectors/ZDC/base/include/ZDCBase/Constants.h index ce8b42800bb99..bdf35c6feec3e 100644 --- a/Detectors/ZDC/base/include/ZDCBase/Constants.h +++ b/Detectors/ZDC/base/include/ZDCBase/Constants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,10 +14,19 @@ #include "CommonConstants/PhysicsConstants.h" #include <cstdint> +#include <cstdlib> +#include <array> #include <string_view> #include <string> #include <type_traits> +// Enable debug printout in reconstruction +//#define O2_ZDC_DEBUG +// TDC arrays in debug output +//#define O2_ZDC_TDC_C_ARRAY +// Debug output of full interpolated function +//#define O2_ZDC_INTERP_DEBUG + namespace o2 { namespace zdc @@ -55,12 +65,33 @@ constexpr uint8_t ALICETriggerMask = 0x1; constexpr int NModules = 8; constexpr int NChPerModule = 4; +constexpr int NLinks = NModules * 2; constexpr int NDigiChannels = NModules * NChPerModule; constexpr int NWPerBc = 3; constexpr int MaxTriggerChannels = NChannels; +constexpr int ADCMin = -2048, ADCMax = 2047, ADCRange = 4096; // 12 bit ADC + +// Encoding of ZDC energy into an uint32_t value +// Most significant 5 bits are for channel id, least significant 27 bits are for energy +// with offset and unit as specified below +constexpr float EnergyOffset = 10000; // Energy offset (GeV) +constexpr float EnergyUnit = 0.01; // Energy unit (GeV) +constexpr uint32_t EnergyMask = 0x07ffffff; +constexpr uint32_t EnergyChMask = 0xf8000000; +// Temporary reconstructed event constexpr int MaxTDCValues = 5; // max number of TDC values to store in reconstructed event constexpr int NTDCChannels = 10; // max number of TDC values to store in reconstructed event +constexpr uint32_t ZDCRefInitVal = 0xffffffff; +// Parameters of interpolating function +constexpr int TSL = 6; // number of zeros on the right (and on the left) of central peak +constexpr int TSN = 200; // Number of interpolated points between each pair = TSN-1 +constexpr int TSNH = TSN / 2; // Half of TSN +constexpr int TSNS = 96; // Number of interpolated points per ns +constexpr int NTS = 2 * TSL * TSN + 1; // Tapered sinc function array size +constexpr static float FTDCAmp = 1. / 8.; // Multiplication factor in conversion from integer +constexpr static float FTDCVal = 1. / TSNS; // Multiplication factor in conversion from integer + enum TDCChannelID { TDCZNAC, TDCZNAS, @@ -153,6 +184,24 @@ constexpr std::string_view ChannelNames[] = { "ZPC4", "ZPCS"}; +const int TDCSignal[NTDCChannels] = { + IdZNAC, // TDCZNAC + IdZNASum, // TDCZNAS + IdZPAC, // TDCZPAC + IdZPASum, // TDCZPAS + IdZEM1, // TDCZEM1 + IdZEM2, // TDCZEM2 + IdZNCC, // TDCZNCC + IdZNCSum, // TDCZNCS + IdZPCC, // TDCZPCC + IdZPCSum // TDCZPCS +}; + +constexpr int DbgZero = 0; +constexpr int DbgMinimal = 1; +constexpr int DbgMedium = 2; +constexpr int DbgFull = 3; + // paths to CCDB objects // TODO: eventually these paths should be retrieved from NameConfigurator class // TODO: we would better use "constexpr string_view" here, but it makes sense only if @@ -160,6 +209,52 @@ constexpr std::string_view ChannelNames[] = { const std::string CCDBPathConfigSim = "ZDC/Config/Sim"; const std::string CCDBPathConfigModule = "ZDC/Config/Module"; +const std::string CCDBPathConfigReco = "ZDC/Calib/RecoParam"; +const std::string CCDBPathRecoConfigZDC = "ZDC/Calib/RecoConfigZDC"; +const std::string CCDBPathTDCCalib = "ZDC/Calib/TDCCalib"; +const std::string CCDBPathEnergyCalib = "ZDC/Calib/EnergyCalib"; +const std::string CCDBPathTowerCalib = "ZDC/Calib/TowerCalib"; + +enum Ped { PedND = 0, + PedEv = 1, + PedOr = 2, + PedQC = 3, + PedMissing = 4 }; + +enum Msg { MsgGeneric = 0, + MsgTDCPedQC = 1, + MsgTDCPedMissing = 2, + MsgADCPedOr = 3, + MsgADCPedQC = 4, + MsgADCPedMissing = 5, + MsgEnd }; + +constexpr std::string_view MsgText[] = { + "generic error", + "TDC QC ped", + "TDC missing ped", + "ADC Orbit ped", + "ADC QC ped", + "ADC missing ped"}; + +// List of channels that can be calibrated +constexpr std::array<int, 10> ChEnergyCalib{IdZNAC, IdZNASum, IdZPAC, IdZPASum, + IdZEM1, IdZEM2, + IdZNCC, IdZNCSum, IdZPCC, IdZPCSum}; + +constexpr std::array<int, 16> ChTowerCalib{IdZNA1, IdZNA2, IdZNA3, IdZNA4, + IdZPA1, IdZPA2, IdZPA3, IdZPA4, + IdZNC1, IdZNC2, IdZNC3, IdZNC4, + IdZPC1, IdZPC2, IdZPC3, IdZPC4}; + +constexpr std::array<int, NChannels> CaloCommonPM{IdZNAC, IdZNAC, IdZNAC, IdZNAC, IdZNAC, IdZNAC, + IdZPAC, IdZPAC, IdZPAC, IdZPAC, IdZPAC, IdZPAC, + IdZEM1, IdZEM2, + IdZNCC, IdZNCC, IdZNCC, IdZNCC, IdZNCC, IdZNCC, + IdZPCC, IdZPCC, IdZPCC, IdZPCC, IdZPCC, IdZPCC}; + +// Placeholders +constexpr int DummyIntRange = -NTimeBinsPerBC - 1; constexpr std::string_view DummyName = "Dumm"; constexpr std::string_view VoidName = " NA "; diff --git a/Detectors/ZDC/base/include/ZDCBase/Geometry.h b/Detectors/ZDC/base/include/ZDCBase/Geometry.h index 3eec00b9a3656..6691e19162499 100644 --- a/Detectors/ZDC/base/include/ZDCBase/Geometry.h +++ b/Detectors/ZDC/base/include/ZDCBase/Geometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,9 +51,9 @@ class Geometry static constexpr double ZEMPOSITION[3] = {9.69, 0., 760.}; private: - static Int_t getDetector(const Int_t det); - static Int_t getSector(const Int_t tow); - static Int_t getVolumeId(const Int_t* vol); + static int32_t getDetector(const int32_t det); + static int32_t getSector(const int32_t tow); + static int32_t getVolumeId(const int32_t* vol); ClassDefNV(Geometry, 1); }; diff --git a/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h b/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h index 1ffef071f7aa6..b9f7f650aace3 100644 --- a/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h +++ b/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,12 +35,12 @@ struct Module { static constexpr int MaxChannels = 4, MaxTriggChannels = 2; int id = -1; // not active std::array<int8_t, MaxChannels> channelID = {IdDummy, IdDummy, IdDummy, IdDummy}; - std::array<int16_t, MaxChannels> linkID = {-1, -1, -1, -1}; + std::array<int16_t, MaxChannels> feeID = {-1, -1, -1, -1}; std::array<bool, MaxChannels> readChannel = {false}; std::array<bool, MaxChannels> trigChannel = {false}; std::array<TriggerChannelConfig, MaxChannels> trigChannelConf; - void setChannel(int slot, int8_t chID, int16_t lID, bool read, bool trig = false, int tF = 0, int tL = 0, int tS = 0, int tT = 0); + void setChannel(int slot, int8_t chID, int16_t fID, bool read, bool trig = false, int tF = 0, int tL = 0, int tS = 0, int tT = 0); void print() const; void printCh() const; void printTrig() const; diff --git a/Detectors/ZDC/base/src/Geometry.cxx b/Detectors/ZDC/base/src/Geometry.cxx index d19ef41ee82c3..572c1c8e3a557 100644 --- a/Detectors/ZDC/base/src/Geometry.cxx +++ b/Detectors/ZDC/base/src/Geometry.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "ZDCBase/Geometry.h" -#include "FairLogger.h" +#include "Framework/Logger.h" ClassImp(o2::zdc::Geometry); diff --git a/Detectors/ZDC/base/src/ModuleConfig.cxx b/Detectors/ZDC/base/src/ModuleConfig.cxx index ca56b67c426eb..2f3417a493c1a 100644 --- a/Detectors/ZDC/base/src/ModuleConfig.cxx +++ b/Detectors/ZDC/base/src/ModuleConfig.cxx @@ -1,28 +1,30 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "ZDCBase/ModuleConfig.h" -#include "ZDCBase/ModuleConfig.h" -#include <FairLogger.h> +#include "Framework/Logger.h" using namespace o2::zdc; +//______________________________________________________________________________ void Module::printCh() const { - printf("Module %d [ChID/LinkID R:T ]", id); + printf("Module %d [ChID/FEEID R:T ]", id); for (int ic = 0; ic < MaxChannels; ic++) { - printf("[%s{%2d}/L%02d %c:%c ]", channelName(channelID[ic]), channelID[ic], linkID[ic], readChannel[ic] ? 'R' : ' ', trigChannel[ic] ? 'T' : ' '); + printf("[%s{%2d}/L%02d %c:%c ]", channelName(channelID[ic]), channelID[ic], feeID[ic], readChannel[ic] ? 'R' : ' ', trigChannel[ic] ? 'T' : ' '); } printf("\n"); } +//______________________________________________________________________________ void Module::printTrig() const { printf("Trigger conf %d: ", id); @@ -37,6 +39,7 @@ void Module::printTrig() const printf("\n"); } +//______________________________________________________________________________ void Module::print() const { printCh(); @@ -58,6 +61,7 @@ void ModuleConfig::print() const } } +//______________________________________________________________________________ void ModuleConfig::check() const { for (const auto& md : modules) { @@ -65,6 +69,7 @@ void ModuleConfig::check() const } } +//______________________________________________________________________________ void Module::check() const { // make sure that the channel has <= 2 triggers @@ -78,13 +83,14 @@ void Module::check() const } } -void Module::setChannel(int slot, int8_t chID, int16_t lID, bool read, bool trig, int tF, int tL, int tS, int tT) +//______________________________________________________________________________ +void Module::setChannel(int slot, int8_t chID, int16_t fID, bool read, bool trig, int tF, int tL, int tS, int tT) { if (slot < 0 || slot >= MaxChannels || chID < 0 || chID > NChannels) { - LOG(FATAL) << "Improper module channel settings" << slot << ' ' << chID << ' ' << lID << ' ' << read << ' ' << trig + LOG(FATAL) << "Improper module channel settings" << slot << ' ' << chID << ' ' << fID << ' ' << read << ' ' << trig << ' ' << tF << ' ' << tL << ' ' << tS << ' ' << tT; } - linkID[slot] = lID; + feeID[slot] = fID; channelID[slot] = chID; readChannel[slot] = read; // In the 2020 firmware implementation, autotrigger bits are computed for each channel diff --git a/Detectors/ZDC/base/src/ZDCBaseLinkDef.h b/Detectors/ZDC/base/src/ZDCBaseLinkDef.h index a8d41f9688ffe..332a059614e95 100644 --- a/Detectors/ZDC/base/src/ZDCBaseLinkDef.h +++ b/Detectors/ZDC/base/src/ZDCBaseLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/macro/CMakeLists.txt b/Detectors/ZDC/macro/CMakeLists.txt index 46f4575ceaf36..a8c8a6ada70d5 100644 --- a/Detectors/ZDC/macro/CMakeLists.txt +++ b/Detectors/ZDC/macro/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(CreateSimCondition.C PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCSimulation @@ -20,3 +21,23 @@ o2_add_test_root_macro(CreateModuleConfig.C o2_add_test_root_macro(readZDCDigits.C PUBLIC_LINK_LIBRARIES O2::ZDCSimulation O2::CCDB LABELS zdc) + +o2_add_test_root_macro(CreateRecoConfigZDC.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + LABELS zdc) + +o2_add_test_root_macro(CreateTDCCalib.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + LABELS zdc) + +o2_add_test_root_macro(CreateEnergyCalib.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + LABELS zdc) + +o2_add_test_root_macro(CreateTowerCalib.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + LABELS zdc) diff --git a/Detectors/ZDC/macro/CreateEnergyCalib.C b/Detectors/ZDC/macro/CreateEnergyCalib.C new file mode 100644 index 0000000000000..e58de77610f58 --- /dev/null +++ b/Detectors/ZDC/macro/CreateEnergyCalib.C @@ -0,0 +1,57 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" +#include "ZDCBase/Constants.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" +#include <string> +#include <TFile.h> +#include <map> + +#endif + +using namespace o2::zdc; +using namespace std; + +void CreateEnergyCalib(long tmin = 0, long tmax = -1, + std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + + ZDCEnergyParam conf; + + // This object allows for the calibration of 4 common photomultipliers and 2 ZEM + // Optionally also the analog sum can have a calibration coefficient otherwise + // the coefficient of the common PM will be used + conf.setEnergyCalib(IdZNAC, 1.); + conf.setEnergyCalib(IdZPAC, 1.); + conf.setEnergyCalib(IdZEM1, 1.); + conf.setEnergyCalib(IdZEM2, 1.); + conf.setEnergyCalib(IdZNCC, 1.); + conf.setEnergyCalib(IdZPCC, 1.); + + // conf.setEnergyCalib(IdZNASum, 1.); + // conf.setEnergyCalib(IdZPASum, 1.); + // conf.setEnergyCalib(IdZNCSum, 1.); + // conf.setEnergyCalib(IdZPCSum, 1.); + + conf.print(); + + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, CCDBPathEnergyCalib, metadata, tmin, tmax); + + // return conf; +} diff --git a/Detectors/ZDC/macro/CreateModuleConfig.C b/Detectors/ZDC/macro/CreateModuleConfig.C index d992c10230f01..94b53fc099705 100644 --- a/Detectors/ZDC/macro/CreateModuleConfig.C +++ b/Detectors/ZDC/macro/CreateModuleConfig.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ #if !defined(__CLING__) || defined(__ROOTCLING__) -#include "FairLogger.h" +#include "Framework/Logger.h" #include "CCDB/CcdbApi.h" #include "ZDCBase/ModuleConfig.h" #include "ZDCBase/Constants.h" @@ -33,9 +34,11 @@ void CreateModuleConfig(long tmin = 0, long tmax = -1, //------------------------------------------- // Up to 8 modules with four channels - // setChannel(int slot, int8_t chID, int16_t lID, bool read, bool trig = false, int tF = 0, int tL = 0, int tS = 0, int tT = 0) + // setChannel(int slot, int8_t chID, int16_t fID, bool read, bool trig = false, int tF = 0, int tL = 0, int tS = 0, int tT = 0) // module id must be in the range 0-7 // channel id must be in range 0-3 + // frontend id must be in range 0-15 and identify the pair of channels connected to + // each fibre { modID = 0; auto& module = conf.modules[modID]; diff --git a/Detectors/ZDC/macro/CreateRecoConfigZDC.C b/Detectors/ZDC/macro/CreateRecoConfigZDC.C new file mode 100644 index 0000000000000..4cec1e5eece63 --- /dev/null +++ b/Detectors/ZDC/macro/CreateRecoConfigZDC.C @@ -0,0 +1,109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" +#include "ZDCReconstruction/RecoConfigZDC.h" +#include "ZDCBase/Constants.h" +#include <string> +#include <TFile.h> +#include <map> + +#endif + +using namespace o2::zdc; +using namespace std; + +void CreateRecoConfigZDC(long tmin = 0, long tmax = -1, + std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + + RecoConfigZDC conf; + + // Offline trigger + // Set trigger bitsincoincidence to ignore dead channels + // conf.setBit(IdZNAC); + // conf.setBit(IdZNASum); + // conf.setBit(IdZPAC); + // conf.setBit(IdZPASum); + // conf.setBit(IdZEM1); + // conf.setBit(IdZEM2); + // conf.setBit(IdZNCC); + // conf.setBit(IdZNCSum); + // conf.setBit(IdZPCC); + // conf.setBit(IdZPCSum); + + // TDC + int def_search = 250; // Unit of ~10 ps + conf.setSearch(TDCZNAC, def_search); + conf.setSearch(TDCZNAS, def_search); + conf.setSearch(TDCZPAC, def_search); + conf.setSearch(TDCZPAS, def_search); + conf.setSearch(TDCZEM1, def_search); + conf.setSearch(TDCZEM2, def_search); + conf.setSearch(TDCZNCC, def_search); + conf.setSearch(TDCZNCS, def_search); + conf.setSearch(TDCZPCC, def_search); + conf.setSearch(TDCZPCS, def_search); + + // Charge integration + int beg_sig = 6; + int end_sig = 8; + int beg_ped = -12; + int end_ped = -8; + + // Integration limits for all signals + // Values should be in range -12..11 + // Channel ID, signal begin, end, pedestal begin, end + + conf.setIntegration(IdZNAC, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNA1, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNA2, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNA3, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNA4, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNASum, beg_sig, end_sig, beg_ped, end_ped); + // + conf.setIntegration(IdZPAC, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPA1, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPA2, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPA3, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPA4, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPASum, beg_sig, end_sig, beg_ped, end_ped); + // + conf.setIntegration(IdZEM1, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZEM2, beg_sig, end_sig, beg_ped, end_ped); + // + conf.setIntegration(IdZNCC, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNC1, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNC2, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNC3, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNC4, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZNCSum, beg_sig, end_sig, beg_ped, end_ped); + // + conf.setIntegration(IdZPCC, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPC1, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPC2, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPC3, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPC4, beg_sig, end_sig, beg_ped, end_ped); + conf.setIntegration(IdZPCSum, beg_sig, end_sig, beg_ped, end_ped); + + conf.print(); + + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, CCDBPathRecoConfigZDC, metadata, tmin, tmax); + + // return conf; +} diff --git a/Detectors/ZDC/macro/CreateSimCondition.C b/Detectors/ZDC/macro/CreateSimCondition.C index e93b14e883a28..5f9466151c7bd 100644 --- a/Detectors/ZDC/macro/CreateSimCondition.C +++ b/Detectors/ZDC/macro/CreateSimCondition.C @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #if !defined(__CLING__) || defined(__ROOTCLING__) -#include "FairLogger.h" +#include "Framework/Logger.h" #include "CCDB/CcdbApi.h" #include <string> #include <TH1.h> diff --git a/Detectors/ZDC/macro/CreateTDCCalib.C b/Detectors/ZDC/macro/CreateTDCCalib.C new file mode 100644 index 0000000000000..228349054a0d2 --- /dev/null +++ b/Detectors/ZDC/macro/CreateTDCCalib.C @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" +#include <string> +#include <TH1.h> +#include <TFile.h> +#include <TRandom.h> +#endif + +#include "ZDCBase/Constants.h" +#include "ZDCReconstruction/ZDCTDCParam.h" + +using namespace std; + +void CreateZDCTDCParam(long tmin = 0, long tmax = -1, std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + o2::zdc::ZDCTDCParam conf; + float def_shift = 14.5; + // TODO: extract shift from TDC spectra + conf.setShift(o2::zdc::TDCZNAC, def_shift); + conf.setShift(o2::zdc::TDCZNAS, def_shift); + conf.setShift(o2::zdc::TDCZPAC, def_shift); + conf.setShift(o2::zdc::TDCZPAS, def_shift); + conf.setShift(o2::zdc::TDCZEM1, def_shift); + conf.setShift(o2::zdc::TDCZEM2, def_shift); + conf.setShift(o2::zdc::TDCZNCC, def_shift); + conf.setShift(o2::zdc::TDCZNCS, def_shift); + conf.setShift(o2::zdc::TDCZPCC, def_shift); + conf.setShift(o2::zdc::TDCZPCS, def_shift); + + conf.print(); + + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, o2::zdc::CCDBPathTDCCalib, metadata, tmin, tmax); + + // return conf; +} diff --git a/Detectors/ZDC/macro/CreateTowerCalib.C b/Detectors/ZDC/macro/CreateTowerCalib.C new file mode 100644 index 0000000000000..8494dcded21fc --- /dev/null +++ b/Detectors/ZDC/macro/CreateTowerCalib.C @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" +#include "ZDCBase/Constants.h" +#include "ZDCReconstruction/ZDCTowerParam.h" +#include <string> +#include <TFile.h> +#include <map> + +#endif + +using namespace o2::zdc; +using namespace std; + +void CreateTowerCalib(long tmin = 0, long tmax = -1, + std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +{ + + ZDCTowerParam conf; + + // This object allows for the calibration of the 4 towers of each calorimeter + // The relative calibration coefficients of towers w.r.t. the common PM + // need to be provided + + conf.setTowerCalib(IdZNA1, 1.); + conf.setTowerCalib(IdZNA2, 1.); + conf.setTowerCalib(IdZNA3, 1.); + conf.setTowerCalib(IdZNA4, 1.); + + conf.setTowerCalib(IdZPA1, 1.); + conf.setTowerCalib(IdZPA2, 1.); + conf.setTowerCalib(IdZPA3, 1.); + conf.setTowerCalib(IdZPA4, 1.); + + conf.setTowerCalib(IdZNC1, 1.); + conf.setTowerCalib(IdZNC2, 1.); + conf.setTowerCalib(IdZNC3, 1.); + conf.setTowerCalib(IdZNC4, 1.); + + conf.setTowerCalib(IdZPC1, 1.); + conf.setTowerCalib(IdZPC2, 1.); + conf.setTowerCalib(IdZPC3, 1.); + conf.setTowerCalib(IdZPC4, 1.); + + conf.print(); + + o2::ccdb::CcdbApi api; + map<string, string> metadata; // can be empty + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, CCDBPathTowerCalib, metadata, tmin, tmax); + + // return conf; +} diff --git a/Detectors/ZDC/macro/readZDCDigits.C b/Detectors/ZDC/macro/readZDCDigits.C index d8691833c2244..5f148b87443f9 100644 --- a/Detectors/ZDC/macro/readZDCDigits.C +++ b/Detectors/ZDC/macro/readZDCDigits.C @@ -12,8 +12,8 @@ #endif -#include "ZDCSimulation/MCLabel.h" -#include "FairLogger.h" +#include "DataFormatsZDC/MCLabel.h" +#include "Framework/Logger.h" /// Example of accessing the ZDC digits diff --git a/Detectors/ZDC/raw/CMakeLists.txt b/Detectors/ZDC/raw/CMakeLists.txt new file mode 100644 index 0000000000000..b9f1ae7b4f25a --- /dev/null +++ b/Detectors/ZDC/raw/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(ZDCRaw + SOURCES + src/DumpRaw.cxx + src/RawReaderZDC.cxx + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DPLUtils + O2::DataFormatsZDC + O2::DetectorsRaw + O2::Headers + O2::SimConfig + O2::SimulationDataFormat + O2::ZDCBase + O2::ZDCSimulation) + +o2_target_root_dictionary(ZDCRaw + HEADERS include/ZDCRaw/DumpRaw.h) + +o2_add_executable(raw-parser + COMPONENT_NAME zdc + SOURCES src/raw-parser.cxx + PUBLIC_LINK_LIBRARIES + O2::CommonUtils + O2::DPLUtils + O2::DetectorsCommonDataFormats + O2::DetectorsRaw + O2::Framework + O2::ZDCRaw + O2::ZDCSimulation) diff --git a/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h b/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h new file mode 100644 index 0000000000000..660e91cf394cf --- /dev/null +++ b/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TH1.h> +#include <TH2.h> +#include "ZDCBase/Constants.h" +#include "ZDCSimulation/ZDCSimParam.h" +#include "DataFormatsZDC/RawEventData.h" +#ifndef ALICEO2_ZDC_DUMPRAW_H_ +#define ALICEO2_ZDC_DUMPRAW_H_ +namespace o2 +{ +namespace zdc +{ +class DumpRaw +{ + public: + DumpRaw() = default; + void init(); + int process(const EventData& ev); + int process(const EventChData& ch); + int processWord(const uint32_t* word); + int getHPos(uint32_t board, uint32_t ch); + void write(); + void setVerbosity(int v) + { + mVerbosity = v; + } + int getVerbosity() const { return mVerbosity; } + + private: + void setStat(TH1* h); + int mVerbosity = 1; + TH1* mBaseline[NDigiChannels] = {nullptr}; + TH1* mCounts[NDigiChannels] = {nullptr}; + TH2* mSignal[NDigiChannels] = {nullptr}; + TH2* mBunch[NDigiChannels] = {nullptr}; + EventChData mCh; +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/raw/include/ZDCRaw/RawReaderZDC.h b/Detectors/ZDC/raw/include/ZDCRaw/RawReaderZDC.h new file mode 100644 index 0000000000000..b0d411688b4d8 --- /dev/null +++ b/Detectors/ZDC/raw/include/ZDCRaw/RawReaderZDC.h @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +//file RawReaderZDC.h class for RAW data reading + +#ifndef ALICEO2_RAWREADERZDC_H_ +#define ALICEO2_RAWREADERZDC_H_ +#include <iostream> +#include <vector> +#include <Rtypes.h> +#include <CommonDataFormat/InteractionRecord.h> +#include <Framework/Logger.h> +#include "Headers/RAWDataHeader.h" +#include "DataFormatsZDC/RawEventData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "ZDCSimulation/Digits2Raw.h" +#include "ZDCBase/ModuleConfig.h" +#include "Framework/ProcessingContext.h" +#include "Framework/DataAllocator.h" +#include "Framework/OutputSpec.h" +#include "Framework/Lifetime.h" +#include <gsl/span> + +namespace o2 +{ +namespace zdc +{ +class RawReaderZDC +{ + const ModuleConfig* mModuleConfig = nullptr; // Trigger/readout configuration object + bool mVerifyTrigger = true; // Verify trigger condition during conversion to digits + uint32_t mTriggerMask = 0; // Trigger mask from ModuleConfig + std::map<InteractionRecord, EventData> mMapData; // Raw data cache + EventChData mCh; // Channel data to be decoded + std::vector<o2::zdc::BCData> mDigitsBC; // Digitized bunch crossing data + std::vector<o2::zdc::ChannelData> mDigitsCh; // Digitized channel data + std::vector<o2::zdc::OrbitData> mOrbitData; // Digitized orbit data + bool mDumpData; // Enable printout of all data + + public: + RawReaderZDC(bool dumpData) : mDumpData(dumpData) {} + RawReaderZDC(const RawReaderZDC&) = default; + + RawReaderZDC() = default; + ~RawReaderZDC() = default; + + void setModuleConfig(const ModuleConfig* moduleConfig) { mModuleConfig = moduleConfig; }; + const ModuleConfig* getModuleConfig() { return mModuleConfig; }; + void setTriggerMask(); + void setVerifyTrigger(const bool verifyTrigger) { mVerifyTrigger = verifyTrigger; }; + bool getVerifyTrigger() { return mVerifyTrigger; }; + + void clear(); + + //decoding binary data into data blocks + void processBinaryData(gsl::span<const uint8_t> payload, int linkID); //processing data blocks into digits + int processWord(const uint32_t* word); + void process(const EventChData& ch); + + void accumulateDigits() + { + getDigits(mDigitsBC, mDigitsCh, mOrbitData); + LOG(INFO) << "Number of Digits: " << mDigitsBC.size(); + LOG(INFO) << "Number of ChannelData: " << mDigitsCh.size(); + LOG(INFO) << "Number of OrbitData: " << mOrbitData.size(); + } + + int getDigits(std::vector<BCData>& digitsBC, std::vector<ChannelData>& digitsCh, std::vector<OrbitData>& orbitData); + + static void prepareOutputSpec(std::vector<o2::framework::OutputSpec>& outputSpec) + { + outputSpec.emplace_back("ZDC", "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); + outputSpec.emplace_back("ZDC", "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); + outputSpec.emplace_back("ZDC", "DIGITSPD", 0, o2::framework::Lifetime::Timeframe); + } + void makeSnapshot(o2::framework::ProcessingContext& pc) + { + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginZDC, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe}, mDigitsBC); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginZDC, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe}, mDigitsCh); + pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginZDC, "DIGITSPD", 0, o2::framework::Lifetime::Timeframe}, mOrbitData); + } +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/raw/src/DumpRaw.cxx b/Detectors/ZDC/raw/src/DumpRaw.cxx new file mode 100644 index 0000000000000..bb2a04c726053 --- /dev/null +++ b/Detectors/ZDC/raw/src/DumpRaw.cxx @@ -0,0 +1,264 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TROOT.h> +#include <TPad.h> +#include <TString.h> +#include <TStyle.h> +#include <TPaveStats.h> +#include "ZDCRaw/DumpRaw.h" +#include "CommonConstants/LHCConstants.h" +#include "ZDCSimulation/Digits2Raw.h" +#include "Framework/Logger.h" + +using namespace o2::zdc; + +void DumpRaw::setStat(TH1* h) +{ + TString hn = h->GetName(); + h->Draw(); + gPad->Update(); + TPaveStats* st = (TPaveStats*)h->GetListOfFunctions()->FindObject("stats"); + st->SetFillStyle(1001); + st->SetBorderSize(1); + if (hn.BeginsWith("hp")) { + st->SetOptStat(111111); + st->SetX1NDC(0.1); + st->SetX2NDC(0.3); + st->SetY1NDC(0.640); + st->SetY2NDC(0.9); + } else if (hn.BeginsWith("hc")) { + st->SetOptStat(1111); + st->SetX1NDC(0.799); + st->SetX2NDC(0.999); + st->SetY1NDC(0.829); + st->SetY2NDC(0.999); + } else if (hn.BeginsWith("hs") || hn.BeginsWith("hb")) { + st->SetOptStat(11); + st->SetX1NDC(0.799); + st->SetX2NDC(0.9995); + st->SetY1NDC(0.904); + st->SetY2NDC(0.999); + } +} + +void DumpRaw::init() +{ + gROOT->SetBatch(); + auto& sopt = ZDCSimParam::Instance(); + int nbx = (sopt.nBCAheadTrig + 1) * NTimeBinsPerBC; + double xmin = -sopt.nBCAheadTrig * NTimeBinsPerBC - 0.5; + double xmax = NTimeBinsPerBC - 0.5; + for (uint32_t i = 0; i < NDigiChannels; i++) { + uint32_t imod = i / NChPerModule; + uint32_t ich = i % NChPerModule; + if (mBaseline[i]) { + mBaseline[i]->Reset(); + } else { + TString hname = TString::Format("hp%d%d", imod, ich); + TString htit = TString::Format("Baseline mod. %d ch. %d;Average orbit baseline", imod, ich); + //mBaseline[i]=new TH1F(hname,htit,ADCRange,ADCMin-0.5,ADCMax+0.5); + mBaseline[i] = new TH1F(hname, htit, 16378, -0.125, ADCMax + 0.125); + } + if (mCounts[i]) { + mCounts[i]->Reset(); + } else { + TString hname = TString::Format("hc%d%d", imod, ich); + TString htit = TString::Format("Counts mod. %d ch. %d; Orbit hits", imod, ich); + mCounts[i] = new TH1F(hname, htit, o2::constants::lhc::LHCMaxBunches + 1, -0.5, o2::constants::lhc::LHCMaxBunches + 0.5); + } + if (mSignal[i]) { + mSignal[i]->Reset(); + } else { + TString hname = TString::Format("hs%d%d", imod, ich); + TString htit = TString::Format("Signal mod. %d ch. %d; Sample; ADC", imod, ich); + mSignal[i] = new TH2F(hname, htit, nbx, xmin, xmax, ADCRange, ADCMin - 0.5, ADCMax + 0.5); + } + if (mBunch[i]) { + mBunch[i]->Reset(); + } else { + TString hname = TString::Format("hb%d%d", imod, ich); + TString htit = TString::Format("Bunch mod. %d ch. %d; Sample; ADC", imod, ich); + mBunch[i] = new TH2F(hname, htit, 100, -0.5, 99.5, 36, -35.5, 0.5); + } + } + // Word id not present in payload + mCh.f.fixed_0 = Id_wn; + mCh.f.fixed_1 = Id_wn; + mCh.f.fixed_2 = Id_wn; +} + +void DumpRaw::write() +{ + TFile* f = new TFile("ZDCDumpRaw.root", "recreate"); + if (f->IsZombie()) { + LOG(FATAL) << "Cannot write to file " << f->GetName(); + return; + } + for (uint32_t i = 0; i < NDigiChannels; i++) { + if (mBunch[i] && mBunch[i]->GetEntries() > 0) { + setStat(mBunch[i]); + mBunch[i]->Write(); + } + } + for (uint32_t i = 0; i < NDigiChannels; i++) { + if (mBaseline[i] && mBaseline[i]->GetEntries() > 0) { + setStat(mBaseline[i]); + mBaseline[i]->Write(); + } + } + for (uint32_t i = 0; i < NDigiChannels; i++) { + if (mCounts[i] && mCounts[i]->GetEntries() > 0) { + setStat(mCounts[i]); + mCounts[i]->Write(); + } + } + for (uint32_t i = 0; i < NDigiChannels; i++) { + if (mSignal[i] && mSignal[i]->GetEntries() > 0) { + setStat(mSignal[i]); + mSignal[i]->Write(); + } + } + f->Close(); +} + +inline int DumpRaw::getHPos(uint32_t board, uint32_t ch) +{ + int ih = board * 4 + ch; + if (ih < NDigiChannels) { + return ih; + } else { + LOG(ERROR) << "Wrong ih " << ih << " board " << board << " ch " << ch; + return -1; + } +} + +int DumpRaw::processWord(const uint32_t* word) +{ + if (word == nullptr) { + printf("NULL\n"); + return 1; + } + if ((word[0] & 0x3) == Id_w0) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[0][iw] = word[iw]; + } + } else if ((word[0] & 0x3) == Id_w1) { + if (mCh.f.fixed_0 == Id_w0) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[1][iw] = word[iw]; + } + } else { + LOG(ERROR) << "Wrong word sequence"; + mCh.f.fixed_0 = Id_wn; + mCh.f.fixed_1 = Id_wn; + mCh.f.fixed_2 = Id_wn; + } + } else if ((word[0] & 0x3) == Id_w2) { + if (mCh.f.fixed_0 == Id_w0 && mCh.f.fixed_1 == Id_w1) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[2][iw] = word[iw]; + } + process(mCh); + } else { + LOG(ERROR) << "Wrong word sequence"; + } + mCh.f.fixed_0 = Id_wn; + mCh.f.fixed_1 = Id_wn; + mCh.f.fixed_2 = Id_wn; + } else { + // Word not present in payload + LOG(FATAL) << "Event format error"; + return 1; + } + return 0; +} + +int DumpRaw::process(const EventChData& ch) +{ + static constexpr int last_bc = o2::constants::lhc::LHCMaxBunches - 1; + // Not empty event + auto f = ch.f; + int ih = getHPos(f.board, f.ch); + if (mVerbosity > 0) { + for (int32_t iw = 0; iw < NWPerBc; iw++) { + Digits2Raw::print_gbt_word(ch.w[iw]); + } + } + uint16_t us[12]; + int16_t s[12]; + us[0] = f.s00; + us[1] = f.s01; + us[2] = f.s02; + us[3] = f.s03; + us[4] = f.s04; + us[5] = f.s05; + us[6] = f.s06; + us[7] = f.s07; + us[8] = f.s08; + us[9] = f.s09; + us[10] = f.s10; + us[11] = f.s11; + for (int32_t i = 0; i < 12; i++) { + if (us[i] > ADCMax) { + s[i] = us[i] - ADCRange; + } else { + s[i] = us[i]; + } + //printf("%d %u %d\n",i,us[i],s[i]); + } + if (f.Alice_3) { + for (int32_t i = 0; i < 12; i++) { + mSignal[ih]->Fill(i - 36., double(s[i])); + } + } + if (f.Alice_2) { + for (int32_t i = 0; i < 12; i++) { + mSignal[ih]->Fill(i - 24., double(s[i])); + } + } + if (f.Alice_1 || f.Auto_1) { + for (int32_t i = 0; i < 12; i++) { + mSignal[ih]->Fill(i - 12., double(s[i])); + } + } + if (f.Alice_0 || f.Auto_0) { + for (int32_t i = 0; i < 12; i++) { + mSignal[ih]->Fill(i + 0., double(s[i])); + } + double bc_d = uint32_t(f.bc / 100); + double bc_m = uint32_t(f.bc % 100); + mBunch[ih]->Fill(bc_m, -bc_d); + } + if (f.bc == last_bc) { + int32_t offset = f.offset - 32768; + double foffset = offset / 8.; + mBaseline[ih]->Fill(foffset); + mCounts[ih]->Fill(f.hits); + } + return 0; +} + +int DumpRaw::process(const EventData& ev) +{ + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) { + process(ev.data[im][ic]); + } else if (ev.data[im][ic].f.fixed_0 == 0 && ev.data[im][ic].f.fixed_1 == 0 && ev.data[im][ic].f.fixed_2 == 0) { + // Empty channel + } else { + LOG(ERROR) << "Data format error"; + } + } + } + return 0; +} diff --git a/Detectors/ZDC/raw/src/RawReaderZDC.cxx b/Detectors/ZDC/raw/src/RawReaderZDC.cxx new file mode 100644 index 0000000000000..e2bf02885da6b --- /dev/null +++ b/Detectors/ZDC/raw/src/RawReaderZDC.cxx @@ -0,0 +1,275 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ZDCRaw/RawReaderZDC.h" + +namespace o2 +{ +namespace zdc +{ + +void RawReaderZDC::clear() +{ + mDigitsBC.clear(); + mDigitsCh.clear(); + mOrbitData.clear(); +} + +void RawReaderZDC::processBinaryData(gsl::span<const uint8_t> payload, int linkID) +{ + if (0 <= linkID && linkID < 16) { + size_t payloadSize = payload.size(); + for (int32_t ip = 0; ip < payloadSize; ip += 16) { + //o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]); + processWord((const uint32_t*)&payload[ip]); + } + } else { + //put here code in case of bad rdh.linkID value + LOG(INFO) << "WARNING! WRONG LINK ID! " << linkID; + return; + } +} + +int RawReaderZDC::processWord(const uint32_t* word) +{ + if (word == nullptr) { + LOG(ERROR) << "NULL pointer"; + return 1; + } + if ((word[0] & 0x3) == Id_w0) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[0][iw] = word[iw]; + } + } else if ((word[0] & 0x3) == Id_w1) { + if (mCh.f.fixed_0 == Id_w0) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[1][iw] = word[iw]; + } + } else { + LOG(ERROR) << "Wrong word sequence"; + mCh.f.fixed_0 = Id_wn; + mCh.f.fixed_1 = Id_wn; + mCh.f.fixed_2 = Id_wn; + } + } else if ((word[0] & 0x3) == Id_w2) { + if (mCh.f.fixed_0 == Id_w0 && mCh.f.fixed_1 == Id_w1) { + for (int32_t iw = 0; iw < NWPerGBTW; iw++) { + mCh.w[2][iw] = word[iw]; + } + process(mCh); + } else { + LOG(ERROR) << "Wrong word sequence"; + } + mCh.f.fixed_0 = Id_wn; + mCh.f.fixed_1 = Id_wn; + mCh.f.fixed_2 = Id_wn; + } else { + // Word not present in payload + LOG(FATAL) << "Event format error"; + return 1; + } + return 0; +} + +void RawReaderZDC::process(const EventChData& ch) +{ + InteractionRecord ir(ch.f.bc, ch.f.orbit); + auto& mydata = mMapData[ir]; + int32_t im = ch.f.board; + int32_t ic = ch.f.ch; + for (int32_t iwb = 0; iwb < NWPerBc; iwb++) { + for (int32_t iwg = 0; iwg < NWPerGBTW; iwg++) { + mydata.data[im][ic].w[iwb][iwg] = mCh.w[iwb][iwg]; + } + } +} + +//pop digits +int RawReaderZDC::getDigits(std::vector<BCData>& digitsBC, std::vector<ChannelData>& digitsCh, std::vector<OrbitData>& orbitData) +{ + if (mModuleConfig == nullptr) { + LOG(FATAL) << "Missing ModuleConfig"; + return 0; + } + int bcCounter = mMapData.size(); + LOG(INFO) << "Processing #bc " << bcCounter; + for (auto& [ir, ev] : mMapData) { + // TODO: Error check + // Pedestal data + if (ir.bc == 3563) { + auto& pdata = orbitData.emplace_back(); + pdata.ir = ir; + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) { + // Identify connected channel + auto id = mModuleConfig->modules[im].channelID[ic]; + int offset = ev.data[im][ic].f.offset - 32768; + pdata.data[id] = offset; + pdata.scaler[id] = ev.data[im][ic].f.hits; + } else if (ev.data[im][ic].f.fixed_0 == 0 && ev.data[im][ic].f.fixed_1 == 0 && ev.data[im][ic].f.fixed_2 == 0) { + // Empty channel + } else { + LOG(ERROR) << "Data format error"; + } + } + } + } + // BC data + auto& bcdata = digitsBC.emplace_back(); + bcdata.ir = ir; + // An inconsistent event has as at least one inconsistent module + bool inconsistent_event = false; + bool filled_event = false; + bcdata.ref.setFirstEntry(digitsCh.size()); + uint32_t ncd = 0; + // Channel data + for (int32_t im = 0; im < NModules; im++) { + ModuleTriggerMapData mt; + mt.w = 0; + bool filled_module = false; + bool inconsistent_module = false; + for (int32_t ic = 0; ic < NChPerModule; ic++) { + // Check if payload is present for channel + if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) { + bcdata.channels |= 0x1 << (NChPerModule * im + ic); // Flag channel as present + auto& ch = ev.data[im][ic]; + uint16_t us[12]; + us[0] = ch.f.s00; + us[1] = ch.f.s01; + us[2] = ch.f.s02; + us[3] = ch.f.s03; + us[4] = ch.f.s04; + us[5] = ch.f.s05; + us[6] = ch.f.s06; + us[7] = ch.f.s07; + us[8] = ch.f.s08; + us[9] = ch.f.s09; + us[10] = ch.f.s10; + us[11] = ch.f.s11; + // Identify connected channel + auto& chd = digitsCh.emplace_back(); + auto id = mModuleConfig->modules[im].channelID[ic]; + chd.id = id; + for (int32_t is = 0; is < NTimeBinsPerBC; is++) { + if (us[is] > ADCMax) { + chd.data[is] = us[is] - ADCRange; + } else { + chd.data[is] = us[is]; + } + } + // Trigger bits + if (ch.f.Hit) { + bcdata.triggers |= (0x1 << (im * NChPerModule + ic)); + } + // TODO: Alice trigger bits + // TODO: consistency checks + if (filled_event == false) { + mt.f.Alice_0 = ch.f.Alice_0; + mt.f.Alice_1 = ch.f.Alice_1; + mt.f.Alice_2 = ch.f.Alice_2; + mt.f.Alice_3 = ch.f.Alice_3; + filled_event = true; + } else if (mt.f.Alice_0 != ch.f.Alice_0 || mt.f.Alice_1 != ch.f.Alice_1 || mt.f.Alice_2 != ch.f.Alice_2 || mt.f.Alice_3 != ch.f.Alice_3) { + inconsistent_event = true; + } + if (filled_module == false) { + mt.f.Auto_m = ch.f.Auto_m; + mt.f.Auto_0 = ch.f.Auto_0; + mt.f.Auto_1 = ch.f.Auto_1; + mt.f.Auto_2 = ch.f.Auto_2; + mt.f.Auto_3 = ch.f.Auto_3; + filled_module = true; + } else if (mt.f.Auto_m != ch.f.Auto_m || mt.f.Auto_0 != ch.f.Auto_0 || mt.f.Auto_1 != ch.f.Auto_1 || mt.f.Auto_2 != ch.f.Auto_2 || mt.f.Auto_3 != ch.f.Auto_3) { + inconsistent_module = true; + } + // Verify trigger condition (if requested) + if (mVerifyTrigger) { + if ((mt.f.Alice_0 || mt.f.Alice_1) || (mt.f.Alice_2 && (mt.f.Auto_0 || mt.f.Auto_m)) || (mt.f.Alice_3 && mt.f.Auto_0) || (mt.f.Auto_0 || mt.f.Auto_1)) { + ncd++; + } else { + digitsCh.pop_back(); + } + } else { + ncd++; + } + } else if (ev.data[im][ic].f.fixed_0 == 0 && ev.data[im][ic].f.fixed_1 == 0 && ev.data[im][ic].f.fixed_2 == 0) { + // Empty channel + } else { + LOG(ERROR) << "Data format error"; + } + } + bcdata.moduleTriggers[im] = mt.w; + if (inconsistent_module == true) { + inconsistent_event = true; + } + } + if (ncd == 0) { + // Remove empty orbits (keep pedestal information) + digitsBC.pop_back(); + } else { + bcdata.ref.setEntries(ncd); + if (mDumpData) { + bcdata.print(mTriggerMask); + auto first_entry = bcdata.ref.getFirstEntry(); + for (Int_t icd = 0; icd < ncd; icd++) { + digitsCh[icd + first_entry].print(); + } + } + } + if (inconsistent_event) { + LOG(ERROR) << "Inconsistent event"; + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) { + for (int32_t iw = 0; iw < NWPerBc; iw++) { + o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&ev.data[im][ic].w[iw][0]); + } + } + } + } + } + } + + mMapData.clear(); + return bcCounter; +} + +//______________________________________________________________________________ +void RawReaderZDC::setTriggerMask() +{ + mTriggerMask = 0; + std::string printTriggerMask{}; + + for (int im = 0; im < NModules; im++) { + if (im > 0) { + printTriggerMask += " "; + } + printTriggerMask += std::to_string(im); + printTriggerMask += "["; + for (int ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].trigChannel[ic]) { + uint32_t tmask = 0x1 << (im * NChPerModule + ic); + mTriggerMask = mTriggerMask | tmask; + printTriggerMask += "T"; + } else { + printTriggerMask += " "; + } + } + printTriggerMask += "]"; + uint32_t mytmask = mTriggerMask >> (im * NChPerModule); + LOGF(INFO, "Trigger mask for module %d 0123 %c%c%c%c", im, + mytmask & 0x1 ? 'T' : 'N', mytmask & 0x2 ? 'T' : 'N', mytmask & 0x4 ? 'T' : 'N', mytmask & 0x8 ? 'T' : 'N'); + } + LOGF(INFO, "trigger_mask=0x%08x %s", mTriggerMask, printTriggerMask.c_str()); +} +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/raw/src/ZDCRawLinkDef.h b/Detectors/ZDC/raw/src/ZDCRawLinkDef.h new file mode 100644 index 0000000000000..c85dd2d378ccb --- /dev/null +++ b/Detectors/ZDC/raw/src/ZDCRawLinkDef.h @@ -0,0 +1,18 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#endif diff --git a/Detectors/ZDC/raw/src/raw-parser.cxx b/Detectors/ZDC/raw/src/raw-parser.cxx new file mode 100644 index 0000000000000..7322e21041491 --- /dev/null +++ b/Detectors/ZDC/raw/src/raw-parser.cxx @@ -0,0 +1,111 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamSpec.h" +#include "DPLUtils/DPLRawParser.h" +#include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" +#include "DataFormatsZDC/RawEventData.h" +#include "ZDCSimulation/Digits2Raw.h" +#include "ZDCRaw/DumpRaw.h" +#include "CommonUtils/ConfigurableParam.h" +#include <vector> +#include <sstream> + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{"input-spec", VariantType::String, "A:ZDC/RAWDATA", {"selection string input specs"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "configKeyValues", + VariantType::String, + "", + {"Semicolon separated key=value strings"}}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues")); + workflow.emplace_back(DataProcessorSpec{ + "zdc-raw-parser", + select(config.options().get<std::string>("input-spec").c_str()), + Outputs{}, + AlgorithmSpec{[](InitContext& setup) { + auto loglevel = setup.options().get<int>("log-level"); + return adaptStateless([loglevel](InputRecord& inputs, DataAllocator& outputs) { + o2::zdc::DumpRaw zdc_dr; + zdc_dr.init(); + zdc_dr.setVerbosity(loglevel); + DPLRawParser parser(inputs); + o2::header::DataHeader const* lastDataHeader = nullptr; + std::stringstream rdhprintout; + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + // retrieving RDH v4 + auto const* rdh = it.get_if<o2::header::RAWDataHeaderV4>(); + // retrieving the raw pointer of the page + auto const* raw = it.raw(); + // retrieving payload pointer of the page + auto const* payload = it.data(); + // size of payload + size_t payloadSize = it.size(); + // offset of payload in the raw page + size_t offset = it.offset(); + // Note: the following code is only for printing out raw page information + const auto* dh = it.o2DataHeader(); + if (loglevel > 0) { + if (dh != lastDataHeader) { + // print the DataHeader information only for the first part or if we have high verbosity + if (loglevel > 1 || dh->splitPayloadIndex == 0) { + rdhprintout << fmt::format("{}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification) + << " "; + // at high verbosity print part number, otherwise only the total number of parts + if (loglevel > 1) { + rdhprintout << "part " + std::to_string(dh->splitPayloadIndex) + " of " + std::to_string(dh->splitPayloadParts); + } else { + rdhprintout << " " + std::to_string(dh->splitPayloadParts) + " part(s)"; + } + rdhprintout << " payload size " << dh->payloadSize << std::endl; + } + if (!rdhprintout.str().empty()) { + LOG(INFO) << rdhprintout.str(); + rdhprintout.str(std::string()); + } + } + if (payload != nullptr) { + for (int32_t ip = 0; ip < payloadSize; ip += 16) { + //o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]); + zdc_dr.processWord((const uint32_t*)&payload[ip]); + } + } + } + lastDataHeader = dh; + } + if (loglevel > 0) { + LOG(INFO) << rdhprintout.str(); + } + zdc_dr.write(); + }); }}, + Options{ + {"log-level", VariantType::Int, 1, {"Logging level [0-2]"}}}}); + return workflow; +} diff --git a/Detectors/ZDC/reconstruction/CMakeLists.txt b/Detectors/ZDC/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..20d4df17f48a8 --- /dev/null +++ b/Detectors/ZDC/reconstruction/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(ZDCReconstruction + SOURCES src/CTFCoder.cxx + src/CTFHelper.cxx + src/DigiReco.cxx + src/RecoParamZDC.cxx + src/ZDCTDCParam.cxx + src/ZDCEnergyParam.cxx + src/ZDCTowerParam.cxx + src/RecoConfigZDC.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCBase + O2::DataFormatsZDC + O2::ZDCSimulation + O2::DetectorsRaw + AliceO2::InfoLogger + O2::rANS + Microsoft.GSL::GSL) + +o2_target_root_dictionary(ZDCReconstruction + HEADERS include/ZDCReconstruction/RecoConfigZDC.h + include/ZDCReconstruction/RecoParamZDC.h + include/ZDCReconstruction/ZDCTDCParam.h + include/ZDCReconstruction/ZDCEnergyParam.h + include/ZDCReconstruction/ZDCTowerParam.h + ) diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h new file mode 100644 index 0000000000000..a17ad8808948f --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h @@ -0,0 +1,211 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.h +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of ZDC data + +#ifndef O2_ZDC_CTFCODER_H +#define O2_ZDC_CTFCODER_H + +#include <algorithm> +#include <iterator> +#include <string> +#include <array> +#include "DataFormatsZDC/CTF.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/CTFCoderBase.h" +#include "rANS/rans.h" +#include "ZDCReconstruction/CTFHelper.h" + +class TTree; + +namespace o2 +{ +namespace zdc +{ + +class CTFCoder : public o2::ctf::CTFCoderBase +{ + public: + CTFCoder() : o2::ctf::CTFCoderBase(CTF::getNBlocks(), o2::detectors::DetID::ZDC) {} + ~CTFCoder() = default; + + /// entropy-encode data to buffer with CTF + template <typename VEC> + void encode(VEC& buff, const gsl::span<const BCData>& trgData, const gsl::span<const ChannelData>& chanData, const gsl::span<const OrbitData>& pedData); + + /// entropy decode data from buffer with CTF + template <typename VTRG, typename VCHAN, typename VPED> + void decode(const CTF::base& ec, VTRG& trigVec, VCHAN& chanVec, VPED& pedVec); + + void createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op); + + private: + void appendToTree(TTree& tree, CTF& ec); + void readFromTree(TTree& tree, int entry, std::vector<BCData>& trigVec, std::vector<ChannelData>& chanVec, std::vector<OrbitData>& pedVec); +}; + +/// entropy-encode clusters to buffer with CTF +template <typename VEC> +void CTFCoder::encode(VEC& buff, const gsl::span<const BCData>& trigData, const gsl::span<const ChannelData>& chanData, const gsl::span<const OrbitData>& pedData) +{ + using MD = o2::ctf::Metadata::OptStore; + // what to do which each field: see o2::ctd::Metadata explanation + constexpr MD optField[CTF::getNBlocks()] = { + MD::EENCODE, // _bcIncTrig + MD::EENCODE, // _orbitIncTrig, + MD::EENCODE, // _moduleTrig, + MD::EENCODE, // _channelsHL, + MD::EENCODE, // _triggersHL, + MD::EENCODE, // _extTriggers, + MD::EENCODE, // _nchanTrig, + // + MD::EENCODE, // _chanID, + MD::EENCODE, // _chanData, + // + MD::EENCODE, // _orbitIncEOD, + MD::EENCODE, // _pedData + MD::EENCODE, // _sclInc + }; + + CTFHelper helper(trigData, chanData, pedData); + + // book output size with some margin + auto szIni = sizeof(CTFHeader) + helper.getSize() * 2. / 3; // will be autoexpanded if needed + buff.resize(szIni); + + auto ec = CTF::create(buff); + using ECB = CTF::base; + + ec->setHeader(helper.createHeader()); + assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader())); + ec->getANSHeader().majorVersion = 0; + ec->getANSHeader().minorVersion = 1; + // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec +#define ENCODEZDC(beg, end, slot, bits) CTF::get(buff.data())->encode(beg, end, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)].get()); + // clang-format off + ENCODEZDC(helper.begin_bcIncTrig(), helper.end_bcIncTrig(), CTF::BLC_bcIncTrig, 0); + ENCODEZDC(helper.begin_orbitIncTrig(), helper.end_orbitIncTrig(), CTF::BLC_orbitIncTrig, 0); + ENCODEZDC(helper.begin_moduleTrig(), helper.end_moduleTrig(), CTF::BLC_moduleTrig, 0); + ENCODEZDC(helper.begin_channelsHL(), helper.end_channelsHL(), CTF::BLC_channelsHL, 0); + ENCODEZDC(helper.begin_triggersHL(), helper.end_triggersHL(), CTF::BLC_triggersHL, 0); + ENCODEZDC(helper.begin_extTriggers(), helper.end_extTriggers(), CTF::BLC_extTriggers, 0); + ENCODEZDC(helper.begin_nchanTrig(), helper.end_nchanTrig(), CTF::BLC_nchanTrig, 0); + // + ENCODEZDC(helper.begin_chanID(), helper.end_chanID(), CTF::BLC_chanID, 0); + ENCODEZDC(helper.begin_chanData(), helper.end_chanData(), CTF::BLC_chanData, 0); + // + ENCODEZDC(helper.begin_orbitIncEOD(), helper.end_orbitIncEOD(), CTF::BLC_orbitIncEOD, 0); + ENCODEZDC(helper.begin_pedData(), helper.end_pedData(), CTF::BLC_pedData, 0); + ENCODEZDC(helper.begin_sclInc(), helper.end_sclInc(), CTF::BLC_sclInc, 0); + + // clang-format on + CTF::get(buff.data())->print(getPrefix()); +} + +/// decode entropy-encoded clusters to standard compact clusters +template <typename VTRG, typename VCHAN, typename VPED> +void CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VCHAN& chanVec, VPED& pedVec) +{ + auto header = ec.getHeader(); + checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(header)); + ec.print(getPrefix()); + std::vector<uint16_t> bcIncTrig, moduleTrig, nchanTrig, chanData, pedData, scalerInc, triggersHL, channelsHL; + std::vector<uint32_t> orbitIncTrig, orbitIncEOD; + std::vector<uint8_t> extTriggers, chanID; + +#define DECODEZDC(part, slot) ec.decode(part, int(slot), mCoders[int(slot)].get()) + // clang-format off + DECODEZDC(bcIncTrig, CTF::BLC_bcIncTrig); + DECODEZDC(orbitIncTrig, CTF::BLC_orbitIncTrig); + DECODEZDC(moduleTrig, CTF::BLC_moduleTrig); + DECODEZDC(channelsHL, CTF::BLC_channelsHL); + DECODEZDC(triggersHL, CTF::BLC_triggersHL); + DECODEZDC(extTriggers, CTF::BLC_extTriggers); + DECODEZDC(nchanTrig, CTF::BLC_nchanTrig); + // + DECODEZDC(chanID, CTF::BLC_chanID); + DECODEZDC(chanData, CTF::BLC_chanData); + // + DECODEZDC(orbitIncEOD, CTF::BLC_orbitIncEOD); + DECODEZDC(pedData, CTF::BLC_pedData); + DECODEZDC(scalerInc, CTF::BLC_sclInc); + // clang-format on + // + trigVec.clear(); + chanVec.clear(); + pedVec.clear(); + trigVec.reserve(header.nTriggers); + chanVec.reserve(header.nChannels); + pedVec.reserve(header.nEOData); + + // triggers and channels + uint32_t firstEntry = 0; + o2::InteractionRecord ir(header.firstBC, header.firstOrbit); + auto chanDataIt = chanData.begin(); + auto chanIdIt = chanID.begin(); + auto modTrigIt = moduleTrig.begin(); + auto pedValIt = pedData.begin(); + auto sclIncIt = scalerInc.begin(); + auto channelsHLIt = channelsHL.begin(); + auto triggersHLIt = triggersHL.begin(); + auto scalers = header.firstScaler; + + for (uint32_t itrig = 0; itrig < header.nTriggers; itrig++) { + // restore TrigRecord + if (orbitIncTrig[itrig]) { // non-0 increment => new orbit + ir.bc = bcIncTrig[itrig]; // bcInc has absolute meaning + ir.orbit += orbitIncTrig[itrig]; + } else { + ir.bc += bcIncTrig[itrig]; + } + + auto firstChanEntry = chanVec.size(); + for (uint16_t ic = 0; ic < nchanTrig[itrig]; ic++) { + auto& chan = chanVec.emplace_back(); + chan.id = *chanIdIt++; + std::copy_n(chanDataIt, NTimeBinsPerBC, chan.data.begin()); + chanDataIt += NTimeBinsPerBC; + } + uint32_t chHL = (uint32_t(*channelsHLIt++) << 16) + *channelsHLIt++; + uint32_t trHL = (uint32_t(*triggersHLIt++) << 16) + *triggersHLIt++; + + auto& bcTrig = trigVec.emplace_back(firstChanEntry, chanVec.size() - firstChanEntry, ir, chHL, trHL, extTriggers[itrig]); + std::copy_n(modTrigIt, NModules, bcTrig.moduleTriggers.begin()); + modTrigIt += NModules; + } + + // pedestal data + ir = {o2::constants::lhc::LHCMaxBunches - 1, header.firstOrbitEOData}; + for (uint32_t ip = 0; ip < header.nEOData; ip++) { + ir.orbit += orbitIncEOD[ip]; + for (uint32_t ic = 0; ic < NChannels; ic++) { + scalers[ic] += *sclIncIt++; // increment scaler + } + auto& ped = pedVec.emplace_back(OrbitData{ir, {}, scalers}); + std::copy_n(pedValIt, NChannels, ped.data.begin()); + pedValIt += NChannels; + } + // make sure whole data was used + assert(chanDataIt == chanData.end()); + assert(chanIdIt == chanID.end()); + assert(modTrigIt == moduleTrig.end()); + assert(pedValIt == pedData.end()); + assert(channelsHLIt == channelsHL.end()); + assert(triggersHLIt == triggersHL.end()); + assert(sclIncIt == scalerInc.end()); +} + +} // namespace zdc +} // namespace o2 + +#endif // O2_ZDC_CTFCODER_H diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFHelper.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFHelper.h new file mode 100644 index 0000000000000..bcf69073a1879 --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFHelper.h @@ -0,0 +1,276 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.h +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for ZDC CTF creation + +#ifndef O2_ZDC_CTF_HELPER_H +#define O2_ZDC_CTF_HELPER_H + +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include "DataFormatsZDC/CTF.h" +#include <gsl/span> + +namespace o2 +{ +namespace zdc +{ + +class CTFHelper +{ + + public: + CTFHelper(const gsl::span<const BCData>& trgData, + const gsl::span<const ChannelData>& chanData, + const gsl::span<const OrbitData>& pedData) + : mTrigData(trgData), mChanData(chanData), mEOData(pedData) {} + + CTFHeader createHeader() + { + CTFHeader h{0, 1, 0, // dummy timestamp, version 1.0 + uint32_t(mTrigData.size()), uint32_t(mChanData.size()), uint32_t(mEOData.size()), 0, 0, 0}; + if (mTrigData.size()) { + h.firstOrbit = mTrigData[0].ir.orbit; + h.firstBC = mTrigData[0].ir.bc; + } + if (mEOData.size()) { + h.firstOrbitEOData = mEOData[0].ir.orbit; + h.firstScaler = mEOData[0].scaler; // then we store increments + } + return h; + } + + size_t getSize() const { return mTrigData.size() * sizeof(BCData) + mChanData.size() * sizeof(ChannelData) + mEOData.size() * sizeof(OrbitData); } + + //>>> =========================== ITERATORS ======================================== + + template <typename I, typename D, typename T, int M = 1> + class _Iter + { + public: + using difference_type = int64_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + _Iter(const gsl::span<const D>& data, bool end = false) : mData(data), mIndex(end ? M * data.size() : 0){}; + _Iter() = default; + + const I& operator++() + { + ++mIndex; + return (I&)(*this); + } + + const I& operator--() + { + mIndex--; + return (I&)(*this); + } + + difference_type operator-(const I& other) const { return mIndex - other.mIndex; } + + difference_type operator-(size_t idx) const { return mIndex - idx; } + + const I& operator-(size_t idx) + { + mIndex -= idx; + return (I&)(*this); + } + + bool operator!=(const I& other) const { return mIndex != other.mIndex; } + bool operator==(const I& other) const { return mIndex == other.mIndex; } + bool operator>(const I& other) const { return mIndex > other.mIndex; } + bool operator<(const I& other) const { return mIndex < other.mIndex; } + + protected: + gsl::span<const D> mData{}; + size_t mIndex = 0; + }; + + //_______________________________________________ + // BC difference wrt previous if in the same orbit, otherwise the abs.value. + // For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_bcIncTrig : public _Iter<Iter_bcIncTrig, BCData, uint16_t> + { + public: + using _Iter<Iter_bcIncTrig, BCData, uint16_t>::_Iter; + value_type operator*() const + { + if (mIndex) { + if (mData[mIndex].ir.orbit == mData[mIndex - 1].ir.orbit) { + return mData[mIndex].ir.bc - mData[mIndex - 1].ir.bc; + } else { + return mData[mIndex].ir.bc; + } + } + return 0; + } + }; + + /////////////////////////////////// BCData iterators //////////////////////////////////////// + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncTrig : public _Iter<Iter_orbitIncTrig, BCData, uint32_t> + { + public: + using _Iter<Iter_orbitIncTrig, BCData, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].ir.orbit - mData[mIndex - 1].ir.orbit : 0; } + }; + + //_______________________________________________ + // Modules trigger words, NModules words per trigger, iterate over the BCData and its modules + class Iter_moduleTrig : public _Iter<Iter_moduleTrig, BCData, uint16_t, NModules> + { + public: + using _Iter<Iter_moduleTrig, BCData, uint16_t, NModules>::_Iter; + value_type operator*() const { return mData[mIndex / NModules].moduleTriggers[mIndex % NModules]; } + }; + + //_______________________________________________ + // ZDC channels pattern word: 32b word is saved as 2 16 bit words + class Iter_channelsHL : public _Iter<Iter_channelsHL, BCData, uint16_t, 2> + { + public: + using _Iter<Iter_channelsHL, BCData, uint16_t, 2>::_Iter; + value_type operator*() const { return uint16_t(mIndex & 0x1 ? mData[mIndex / 2].channels : mData[mIndex / 2].channels >> 16); } + }; + + //_______________________________________________ + // ZDC trigger word: 32b word is saved as 2 16 bit words + class Iter_triggersHL : public _Iter<Iter_triggersHL, BCData, uint16_t, 2> + { + public: + using _Iter<Iter_triggersHL, BCData, uint16_t, 2>::_Iter; + value_type operator*() const { return uint16_t(mIndex & 0x1 ? mData[mIndex / 2].triggers : mData[mIndex / 2].triggers >> 16); } + }; + + //_______________________________________________ + // Alice external trigger word + class Iter_extTriggers : public _Iter<Iter_extTriggers, BCData, uint8_t> + { + public: + using _Iter<Iter_extTriggers, BCData, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].ext_triggers; } + }; + + //_______________________________________________ + // Number of channels for trigger + class Iter_nchanTrig : public _Iter<Iter_nchanTrig, BCData, uint16_t> + { + public: + using _Iter<Iter_nchanTrig, BCData, uint16_t>::_Iter; + value_type operator*() const { return mData[mIndex].ref.getEntries(); } + }; + + ////////////////////////// ChannelData iterators ///////////////////////////// + + //_______________________________________________ + class Iter_chanID : public _Iter<Iter_chanID, ChannelData, uint8_t> + { + public: + using _Iter<Iter_chanID, ChannelData, uint8_t>::_Iter; + value_type operator*() const { return mData[mIndex].id; } + }; + + //_______________________________________________ + class Iter_chanData : public _Iter<Iter_chanData, ChannelData, uint16_t, NTimeBinsPerBC> + { + public: + using _Iter<Iter_chanData, ChannelData, uint16_t, NTimeBinsPerBC>::_Iter; + value_type operator*() const { return mData[mIndex / NTimeBinsPerBC].data[mIndex % NTimeBinsPerBC]; } + }; + + ////////////////////////// OrbitData iterators ///////////////////////////// + + //_______________________________________________ + // Orbit difference wrt previous. For the very 1st entry return 0 (diff wrt 1st BC in the CTF header) + class Iter_orbitIncEOD : public _Iter<Iter_orbitIncEOD, OrbitData, uint32_t> + { + public: + using _Iter<Iter_orbitIncEOD, OrbitData, uint32_t>::_Iter; + value_type operator*() const { return mIndex ? mData[mIndex].ir.orbit - mData[mIndex - 1].ir.orbit : 0; } + }; + + //_______________________________________________ + class Iter_pedData : public _Iter<Iter_pedData, OrbitData, int16_t, NChannels> + { + public: + using _Iter<Iter_pedData, OrbitData, int16_t, NChannels>::_Iter; + value_type operator*() const { return mData[mIndex / NChannels].data[mIndex % NChannels]; } + }; + + //_______________________________________________ + class Iter_sclInc : public _Iter<Iter_sclInc, OrbitData, int16_t, NChannels> + { + public: + using _Iter<Iter_sclInc, OrbitData, int16_t, NChannels>::_Iter; + value_type operator*() const + { + // define with respect to previous orbit + int slot = mIndex / NChannels, chan = mIndex % NChannels; + return slot ? mData[slot].scaler[chan] - mData[slot - 1].scaler[chan] : 0; + } + }; + + //<<< =========================== ITERATORS ======================================== + + Iter_bcIncTrig begin_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, false); } + Iter_bcIncTrig end_bcIncTrig() const { return Iter_bcIncTrig(mTrigData, true); } + + Iter_orbitIncTrig begin_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, false); } + Iter_orbitIncTrig end_orbitIncTrig() const { return Iter_orbitIncTrig(mTrigData, true); } + + Iter_moduleTrig begin_moduleTrig() const { return Iter_moduleTrig(mTrigData, false); } + Iter_moduleTrig end_moduleTrig() const { return Iter_moduleTrig(mTrigData, true); } + + Iter_channelsHL begin_channelsHL() const { return Iter_channelsHL(mTrigData, false); } + Iter_channelsHL end_channelsHL() const { return Iter_channelsHL(mTrigData, true); } + + Iter_triggersHL begin_triggersHL() const { return Iter_triggersHL(mTrigData, false); } + Iter_triggersHL end_triggersHL() const { return Iter_triggersHL(mTrigData, true); } + + Iter_extTriggers begin_extTriggers() const { return Iter_extTriggers(mTrigData, false); } + Iter_extTriggers end_extTriggers() const { return Iter_extTriggers(mTrigData, true); } + + Iter_nchanTrig begin_nchanTrig() const { return Iter_nchanTrig(mTrigData, false); } + Iter_nchanTrig end_nchanTrig() const { return Iter_nchanTrig(mTrigData, true); } + + Iter_chanID begin_chanID() const { return Iter_chanID(mChanData, false); } + Iter_chanID end_chanID() const { return Iter_chanID(mChanData, true); } + + Iter_chanData begin_chanData() const { return Iter_chanData(mChanData, false); } + Iter_chanData end_chanData() const { return Iter_chanData(mChanData, true); } + + Iter_orbitIncEOD begin_orbitIncEOD() const { return Iter_orbitIncEOD(mEOData, false); } + Iter_orbitIncEOD end_orbitIncEOD() const { return Iter_orbitIncEOD(mEOData, true); } + + Iter_pedData begin_pedData() const { return Iter_pedData(mEOData, false); } + Iter_pedData end_pedData() const { return Iter_pedData(mEOData, true); } + + Iter_sclInc begin_sclInc() const { return Iter_sclInc(mEOData, false); } + Iter_sclInc end_sclInc() const { return Iter_sclInc(mEOData, true); } + + private: + const gsl::span<const o2::zdc::BCData> mTrigData; + const gsl::span<const o2::zdc::ChannelData> mChanData; + const gsl::span<const o2::zdc::OrbitData> mEOData; +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h new file mode 100644 index 0000000000000..90b5dd32ddb73 --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <map> +#include <gsl/span> +#include <TFile.h> +#include <TTree.h> +#include "Framework/Logger.h" +#include "ZDCBase/Constants.h" +#include "ZDCSimulation/ZDCSimParam.h" +#include "ZDCReconstruction/RecoParamZDC.h" +#include "ZDCReconstruction/ZDCTDCParam.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" +#include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCReconstruction/RecoConfigZDC.h" +#include "ZDCBase/ModuleConfig.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/RecEventAux.h" + +#ifndef ALICEO2_ZDC_DIGI_RECO_H +#define ALICEO2_ZDC_DIGI_RECO_H +namespace o2 +{ +namespace zdc +{ +using O2_ZDC_DIGIRECO_FLT = float; +class DigiReco +{ + public: + DigiReco() = default; + ~DigiReco() = default; + void init(); + int process(const gsl::span<const o2::zdc::OrbitData>& orbitdata, + const gsl::span<const o2::zdc::BCData>& bcdata, + const gsl::span<const o2::zdc::ChannelData>& chdata); + int write(); + void setVerbosity(int v) + { + mVerbosity = v; + } + int getVerbosity() const { return mVerbosity; } + void setDebugOutput(bool state = true) + { + mTreeDbg = state; + } + void eor() + { + if (mTreeDbg) { + LOG(INFO) << "ZDC DigiReco: closing debug output"; + mTDbg->Write(); + mTDbg.reset(); + mDbg->Close(); + mDbg.reset(); + } + LOG(INFO) << "Detected " << mNLonely << " lonely bunches"; + LOG(INFO) << "Detected " << mNLastLonely << " lonely bunches at end of orbit"; + } + + void setModuleConfig(const ModuleConfig* moduleConfig) { mModuleConfig = moduleConfig; }; + const ModuleConfig* getModuleConfig() { return mModuleConfig; }; + void setTDCParam(const ZDCTDCParam* param) { mTDCParam = param; }; + const ZDCTDCParam* getTDCParam() { return mTDCParam; }; + void setEnergyParam(const ZDCEnergyParam* param) { mEnergyParam = param; }; + const ZDCEnergyParam* getEnergyParam() { return mEnergyParam; }; + void setTowerParam(const ZDCTowerParam* param) { mTowerParam = param; }; + const ZDCTowerParam* getTowerParam() { return mTowerParam; }; + void setRecoConfigZDC(const RecoConfigZDC* cfg) { mRecoConfigZDC = cfg; }; + const RecoConfigZDC* getRecoConfigZDC() { return mRecoConfigZDC; }; + + const std::vector<o2::zdc::RecEventAux>& getReco() { return mReco; } + + private: + const ModuleConfig* mModuleConfig = nullptr; /// Trigger/readout configuration object + void updateOffsets(int ibun); /// Update offsets to process current bunch + int reconstruct(int seq_beg, int seq_end); /// Main method for data reconstruction + void processTrigger(int itdc, int ibeg, int iend); /// Replay of trigger algorithm on acquired data + void interpolate(int itdc, int ibeg, int iend); /// Interpolation of samples to evaluate signal amplitude and arrival time + O2_ZDC_DIGIRECO_FLT getPoint(int itdc, int ibeg, int iend, int i); /// Interpolation for current TDC +#ifdef O2_ZDC_INTERP_DEBUG + void setPoint(int itdc, int ibeg, int iend, int i); /// Interpolation for current TDC +#endif + void assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float amp); /// Set reconstructed TDC values + bool mIsContinuous = true; /// continuous (self-triggered) or externally-triggered readout + int mNBCAHead = 0; /// when storing triggered BC, store also mNBCAHead BCs + const ZDCTDCParam* mTDCParam = nullptr; /// TDC calibration object + const ZDCEnergyParam* mEnergyParam = nullptr; /// Energy calibration object + const ZDCTowerParam* mTowerParam = nullptr; /// Tower calibration object + uint32_t mTDCMask[NTDCChannels] = {0}; /// Identify TDC channels in trigger mask + const RecoConfigZDC* mRecoConfigZDC = nullptr; /// CCDB configuration parameters + int32_t mVerbosity = DbgMinimal; + Double_t mTS[NTS]; /// Tapered sinc function + bool mTreeDbg = false; /// Write reconstructed data in debug output file + std::unique_ptr<TFile> mDbg = nullptr; /// Debug output file + std::unique_ptr<TTree> mTDbg = nullptr; /// Debug tree + gsl::span<const o2::zdc::OrbitData> mOrbitData; /// Reconstructed data + gsl::span<const o2::zdc::BCData> mBCData; /// BC info + gsl::span<const o2::zdc::ChannelData> mChData; /// Payload + std::vector<o2::zdc::RecEventAux> mReco; /// Reconstructed data + std::map<uint32_t, int> mOrbit; /// Information about orbit + float mOffset[NChannels]; /// Offset in current orbit + uint32_t mOffsetOrbit = 0xffffffff; /// Current orbit + uint32_t mSource[NChannels]; /// Source of pedestal + static constexpr int mNSB = TSN * NTimeBinsPerBC; /// Total number of interpolated points per bunch crossing + RecEventAux mRec; /// Debug reconstruction event + int mNBC = 0; + int mNLonely = 0; + int mNLastLonely = 0; + int16_t tdc_shift[NTDCChannels] = {0}; /// TDC correction (units of 1/96 ns) + constexpr static uint16_t mMask[NTimeBinsPerBC] = {0x0001, 0x002, 0x004, 0x008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800}; + // Configuration of interpolation for current TDC + int mNbun; // Number of adjacent bunches + int mNsam; // Number of acquired samples + int mNtot; // Total number of points in the interpolated arrays + int mIlast; // Index of last acquired sample + int mNint; // Total points in the interpolation region (-1) + O2_ZDC_DIGIRECO_FLT mFirstSample; + O2_ZDC_DIGIRECO_FLT mLastSample; +}; +} // namespace zdc +} // namespace o2 +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h new file mode 100644 index 0000000000000..0818383c94fbe --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_RECOCONFIGZDC_H +#define O2_ZDC_RECOCONFIGZDC_H + +#include <array> +#include <Rtypes.h> +#include "ZDCBase/Constants.h" + +/// \file RecoConfigZDC.h +/// \brief ZDC reconstruction parameters +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct RecoConfigZDC { + // Trigger + Int_t tsh[NTDCChannels] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // Trigger shift + Int_t tth[NTDCChannels] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // Trigger threshold + std::array<bool, NTDCChannels> bitset = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Set bits in coincidence + void setBit(uint32_t ibit, bool val = true); + + // TDC + int tdc_search[NTDCChannels] = {250, 250, 250, 250, 250, 250, 250, 250, 250, 250}; // Search zone for a TDC signal ideally 2.5 ns (units of ~10 ps) + void setSearch(uint32_t ich, int val); + int getSearch(uint32_t ich) const; + + // Charge integration + // Beginning and end of integration range: signal + Int_t beg_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + // Beginning and end of integration range: pedestal + Int_t beg_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + void setIntegration(uint32_t ich, int beg, int end, int beg_ped, int end_ped); + + void print(); + + ClassDefNV(RecoConfigZDC, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h new file mode 100644 index 0000000000000..af37d0cc4967f --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_RECOPARAMZDC_H +#define O2_ZDC_RECOPARAMZDC_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "ZDCBase/Constants.h" + +/// \file RecoParamZDC.h +/// \brief ZDC reconstruction parameters +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct RecoParamZDC : public o2::conf::ConfigurableParamHelper<RecoParamZDC> { + // Trigger + Int_t tsh[NTDCChannels] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // Trigger shift + Int_t tth[NTDCChannels] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // Trigger threshold + bool bitset[NTDCChannels] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Set bits in coincidence + void setBit(uint32_t ibit, bool val = true); + + // TDC + Int_t tmod[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of TDC channel in raw data + Int_t tch[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of TDC channel in raw data + float tdc_shift[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Correction of TDC position (0-25 ns, units of ~10 ps) + float tdc_search[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Search zone for a TDC signal ideally 2.5 ns (units of ~10 ps) + + // Charge integration + Int_t amod[NChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of ADC channel in raw data + Int_t ach[NChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of ADC channel in raw data + // Beginning and end of integration range: signal + Int_t beg_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + // Beginning and end of integration range: pedestal + Int_t beg_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + + // Energy calibration + float energy_calib[NChannels] = {0}; // Energy calibration coefficients + float tower_calib[NChannels] = {0}; // Tower calibration coefficients + O2ParamDef(RecoParamZDC, "recoparamzdc"); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCEnergyParam.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCEnergyParam.h new file mode 100644 index 0000000000000..2a420814a553e --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCEnergyParam.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_ENERGYPARAM_H +#define O2_ZDC_ENERGYPARAM_H + +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <array> + +/// \file ZDCEnergyParam.h +/// \brief ZDC Energy calibration +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct ZDCEnergyParam { + float energy_calib[NChannels] = {0}; // Energy calibration coefficients + void setEnergyCalib(uint32_t ich, float val); + float getEnergyCalib(uint32_t ich) const; + void print(); + ClassDefNV(ZDCEnergyParam, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTDCParam.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTDCParam.h new file mode 100644 index 0000000000000..5781464e9f782 --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTDCParam.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_TDCPARAM_H_ +#define O2_ZDC_TDCPARAM_H_ + +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <array> + +/// \file ZDCTDCParam.h +/// \brief Parameters to correct TDCs (produced by QA) +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct ZDCTDCParam { + //std::array<float, NTDCChannels> tdcShift{} + float tdc_shift[NTDCChannels] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Correction of TDC position (ns) + void setShift(uint32_t ich, float val); + float getShift(uint32_t ich) const; + void print(); + ClassDefNV(ZDCTDCParam, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTowerParam.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTowerParam.h new file mode 100644 index 0000000000000..7e2eb82b11671 --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/ZDCTowerParam.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_TOWERPARAM_H +#define O2_ZDC_TOWERPARAM_H + +#include "ZDCBase/Constants.h" +#include <Rtypes.h> +#include <array> + +/// \file ZDCTowerParam.h +/// \brief ZDC Tower calibration +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct ZDCTowerParam { + float tower_calib[NChannels] = {0}; // Tower calibration coefficients + void setTowerCalib(uint32_t ich, float val); + float getTowerCalib(uint32_t ich) const; + void print(); + ClassDefNV(ZDCTowerParam, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/reconstruction/src/CTFCoder.cxx b/Detectors/ZDC/reconstruction/src/CTFCoder.cxx new file mode 100644 index 0000000000000..c660ff05734fa --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/CTFCoder.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFCoder.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief class for entropy encoding/decoding of ZDC data + +#include "ZDCReconstruction/CTFCoder.h" +#include "CommonUtils/StringUtils.h" +#include <TTree.h> + +using namespace o2::zdc; + +///___________________________________________________________________________________ +// Register encoded data in the tree (Fill is not called, will be done by caller) +void CTFCoder::appendToTree(TTree& tree, CTF& ec) +{ + ec.appendToTree(tree, mDet.getName()); +} + +///___________________________________________________________________________________ +// extract and decode data from the tree +void CTFCoder::readFromTree(TTree& tree, int entry, std::vector<BCData>& trigVec, std::vector<ChannelData>& chanVec, std::vector<OrbitData>& eodVec) +{ + assert(entry >= 0 && entry < tree.GetEntries()); + CTF ec; + ec.readFromTree(tree, mDet.getName(), entry); + decode(ec, trigVec, chanVec, eodVec); +} + +///________________________________ +void CTFCoder::createCoders(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op) +{ + bool mayFail = true; // RS FIXME if the dictionary file is not there, do not produce exception + auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail); + if (!buff.size()) { + if (mayFail) { + return; + } + throw std::runtime_error("Failed to create CTF dictionaty"); + } + const auto* ctf = CTF::get(buff.data()); + + auto getFreq = [ctf](CTF::Slots slot) -> o2::rans::FrequencyTable { + o2::rans::FrequencyTable ft; + auto bl = ctf->getBlock(slot); + auto md = ctf->getMetadata(slot); + ft.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min, md.max); + return std::move(ft); + }; + auto getProbBits = [ctf](CTF::Slots slot) -> int { + return ctf->getMetadata(slot).probabilityBits; + }; + + // just to get types + uint16_t bcIncTrig, moduleTrig, nchanTrig, chanData, pedData, sclInc, triggersHL, channelsHL; + uint32_t orbitIncTrig, orbitIncEOD; + uint8_t extTriggers, chanID; +#define MAKECODER(part, slot) createCoder<decltype(part)>(op, getFreq(slot), getProbBits(slot), int(slot)) + // clang-format off + MAKECODER(bcIncTrig, CTF::BLC_bcIncTrig); + MAKECODER(orbitIncTrig, CTF::BLC_orbitIncTrig); + MAKECODER(moduleTrig, CTF::BLC_moduleTrig); + MAKECODER(channelsHL, CTF::BLC_channelsHL); + MAKECODER(triggersHL, CTF::BLC_triggersHL); + MAKECODER(extTriggers, CTF::BLC_extTriggers); + MAKECODER(nchanTrig, CTF::BLC_nchanTrig); + // + MAKECODER(chanID, CTF::BLC_chanID); + MAKECODER(chanData, CTF::BLC_chanData); + // + MAKECODER(orbitIncEOD, CTF::BLC_orbitIncEOD); + MAKECODER(pedData, CTF::BLC_pedData); + MAKECODER(sclInc, CTF::BLC_sclInc); + // clang-format on +} diff --git a/Detectors/ZDC/reconstruction/src/CTFHelper.cxx b/Detectors/ZDC/reconstruction/src/CTFHelper.cxx new file mode 100644 index 0000000000000..aacff0648eac4 --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/CTFHelper.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CTFHelper.cxx +/// \author ruben.shahoyan@cern.ch +/// \brief Helper for ZDC CTF creation + +#include "ZDCReconstruction/CTFHelper.h" diff --git a/Detectors/ZDC/reconstruction/src/DigiReco.cxx b/Detectors/ZDC/reconstruction/src/DigiReco.cxx new file mode 100644 index 0000000000000..2bdab6a8690e8 --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/DigiReco.cxx @@ -0,0 +1,1006 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <TMath.h> +#include "Framework/Logger.h" +#include "ZDCReconstruction/DigiReco.h" +#include "ZDCReconstruction/RecoParamZDC.h" + +namespace o2 +{ +namespace zdc +{ + +void DigiReco::init() +{ + LOG(INFO) << "Initialization of ZDC reconstruction"; + // Load configuration parameters + auto& sopt = ZDCSimParam::Instance(); + mIsContinuous = sopt.continuous; + mNBCAHead = mIsContinuous ? sopt.nBCAheadCont : sopt.nBCAheadTrig; + + if (!mModuleConfig) { + LOG(FATAL) << "Missing ModuleConfig configuration object"; + return; + } + + // Prepare tapered sinc function + // tsc/TSN =3.75 (~ 4) and TSL*TSN*sqrt(2)/tsc >> 1 (n. of sigma) + const O2_ZDC_DIGIRECO_FLT tsc = 750; + int n = TSL * TSN; + for (int tsi = 0; tsi <= n; tsi++) { + O2_ZDC_DIGIRECO_FLT arg1 = TMath::Pi() * O2_ZDC_DIGIRECO_FLT(tsi) / O2_ZDC_DIGIRECO_FLT(TSN); + O2_ZDC_DIGIRECO_FLT fs = 1; + if (arg1 != 0) { + fs = TMath::Sin(arg1) / arg1; + } + O2_ZDC_DIGIRECO_FLT arg2 = O2_ZDC_DIGIRECO_FLT(tsi) / tsc; + O2_ZDC_DIGIRECO_FLT fg = TMath::Exp(-arg2 * arg2); + mTS[n + tsi] = fs * fg; + mTS[n - tsi] = mTS[n + tsi]; // Function is even + } + + if (mTreeDbg) { + // Open debug file + LOG(INFO) << "ZDC DigiReco: opening debug output"; + mDbg = std::make_unique<TFile>("ZDCRecoDbg.root", "recreate"); + mTDbg = std::make_unique<TTree>("zdcr", "ZDCReco"); + mTDbg->Branch("zdcr", "RecEventAux", &mRec); + } + + // Update reconstruction parameters + //auto& ropt=RecoParamZDC::Instance(); + o2::zdc::RecoParamZDC& ropt = const_cast<o2::zdc::RecoParamZDC&>(RecoParamZDC::Instance()); + + // Fill maps to decode the pattern of channels with hit + for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) { + // If the reconstruction parameters were not manually set + if (ropt.tmod[itdc] < 0 || ropt.tch[itdc] < 0) { + int isig = TDCSignal[itdc]; + for (int im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].channelID[ic] == isig && mModuleConfig->modules[im].readChannel[ic]) { + //ropt.updateFromString(TString::Format("RecoParamZDC.tmod[%d]=%d;",itdc,im)); + //ropt.updateFromString(TString::Format("RecoParamZDC.tch[%d]=%d;",itdc,ic)); + ropt.tmod[itdc] = im; + ropt.tch[itdc] = ic; + // Fill mask to identify TDC channels + mTDCMask[itdc] = (0x1 << (4 * im + ic)); + goto next_itdc; + } + } + } + } + next_itdc:; + LOG(INFO) << "TDC " << itdc << "(" << ChannelNames[TDCSignal[itdc]] << ")" + << " mod " << ropt.tmod[itdc] << " ch " << ropt.tch[itdc]; + } + + // TDC calibration + for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) { + float fval = ropt.tdc_shift[itdc]; + // If the reconstruction parameters were not manually set + if (fval < 0) { + // Check if calibration object is present + if (!mTDCParam) { + LOG(FATAL) << "TDC " << itdc << " missing configuration object and no manual override"; + } else { + fval = mTDCParam->getShift(itdc) / FTDCVal; + } + } + auto val = std::nearbyint(fval); + if (val < kMinShort) { + LOG(FATAL) << "Shift for TDC " << itdc << " " << val << " is out of range"; + } + if (val > kMaxShort) { + LOG(FATAL) << "Shift for TDC " << itdc << " " << val << " is out of range"; + } + tdc_shift[itdc] = val; + LOG(INFO) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " shift= " << tdc_shift[itdc] << " i.s. = " << val * FTDCVal << " ns"; + } + + // TDC search zone + for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) { + // If the reconstruction parameters were not manually set + if (ropt.tdc_search[itdc] <= 0) { + if (!mRecoConfigZDC) { + LOG(FATAL) << "Search zone for TDC " << itdc << " missing configuration object and no manual override"; + } else { + ropt.tdc_search[itdc] = mRecoConfigZDC->tdc_search[itdc]; + } + } + LOG(INFO) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << ropt.tdc_search[itdc] << " i.s. = " << ropt.tdc_search[itdc] * FTDCVal << " ns"; + } + + // Energy calibration + for (int il = 0; il < ChEnergyCalib.size(); il++) { + if (ropt.energy_calib[ChEnergyCalib[il]] > 0) { + LOG(INFO) << "Energy Calibration from command line " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]]; + } else if (mEnergyParam && mEnergyParam->energy_calib[ChEnergyCalib[il]] > 0) { + ropt.energy_calib[ChEnergyCalib[il]] = mEnergyParam->energy_calib[ChEnergyCalib[il]]; + LOG(INFO) << "Energy Calibration from CCDB " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]]; + } else { + if (ChEnergyCalib[il] == CaloCommonPM[ChEnergyCalib[il]]) { + // Is a common PM or a ZEM + ropt.energy_calib[ChEnergyCalib[il]] = 1; + LOG(WARNING) << "Default Energy Calibration " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]]; + } else { + // Is one of the analog sums -> same calibration as common PM + // N.B. the calibration for common has already been set in the loop + ropt.energy_calib[ChEnergyCalib[il]] = ropt.energy_calib[CaloCommonPM[il]]; + LOG(INFO) << "SUM Energy Calibration " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]]; + } + } + } + + // Tower calibration + for (int il = 0; il < ChTowerCalib.size(); il++) { + if (ropt.tower_calib[ChTowerCalib[il]] > 0) { + LOG(INFO) << "Tower Calibration from command line " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]]; + } else if (mTowerParam && mTowerParam->tower_calib[ChTowerCalib[il]] > 0) { + ropt.tower_calib[ChTowerCalib[il]] = mTowerParam->tower_calib[ChTowerCalib[il]]; + LOG(INFO) << "Tower Calibration from CCDB " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]]; + } else { + ropt.tower_calib[ChTowerCalib[il]] = 1; + LOG(WARNING) << "Default Tower Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]]; + } + } + + // Tower energy calibration + for (int il = 0; il < ChTowerCalib.size(); il++) { + if (ropt.energy_calib[ChTowerCalib[il]] > 0) { + LOG(INFO) << "Tower Energy Calibration from command line " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]]; + } else { + ropt.energy_calib[ChTowerCalib[il]] = ropt.tower_calib[ChTowerCalib[il]] * ropt.energy_calib[CaloCommonPM[ChTowerCalib[il]]]; + LOG(INFO) << "Tower Energy Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]]; + } + } + + // Fill maps channel maps for integration + for (int ich = 0; ich < NChannels; ich++) { + // If the reconstruction parameters were not manually set + if (ropt.amod[ich] < 0 || ropt.ach[ich] < 0) { + for (int im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].channelID[ic] == ich && mModuleConfig->modules[im].readChannel[ic]) { + ropt.amod[ich] = im; + ropt.ach[ich] = ic; + goto next_ich; + } + } + } + } + next_ich:; + LOG(INFO) << "ADC " << ich << "(" << ChannelNames[ich] << ") mod " << ropt.amod[ich] << " ch " << ropt.ach[ich]; + } + + // Integration ranges + for (int ich = 0; ich < NChannels; ich++) { + // If the reconstruction parameters were not manually set + if (ropt.beg_int[ich] == DummyIntRange || ropt.end_int[ich] == DummyIntRange) { + if (!mRecoConfigZDC) { + LOG(FATAL) << "Integration for signal " << ich << " missing configuration object and no manual override"; + } else { + ropt.beg_int[ich] = mRecoConfigZDC->beg_int[ich]; + ropt.end_int[ich] = mRecoConfigZDC->end_int[ich]; + } + } + if (ropt.beg_ped_int[ich] == DummyIntRange || ropt.end_ped_int[ich] == DummyIntRange) { + if (!mRecoConfigZDC) { + LOG(ERROR) << "Integration for pedestal " << ich << " missing configuration object and no manual override"; + } else { + ropt.beg_ped_int[ich] = mRecoConfigZDC->beg_ped_int[ich]; + ropt.end_ped_int[ich] = mRecoConfigZDC->end_ped_int[ich]; + } + } + LOG(INFO) << ChannelNames[ich] << " integration: signal=[" << ropt.beg_int[ich] << ":" << ropt.end_int[ich] << "] pedestal=[" << ropt.beg_ped_int[ich] << ":" << ropt.end_ped_int[ich] << "]"; + } +} // init + +int DigiReco::process(const gsl::span<const o2::zdc::OrbitData>& orbitdata, const gsl::span<const o2::zdc::BCData>& bcdata, const gsl::span<const o2::zdc::ChannelData>& chdata) +{ + // We assume that vectors contain data from a full time frame + mOrbitData = orbitdata; + mBCData = bcdata; + mChData = chdata; + + // Initialization of lookup structure for pedestals + mOrbit.clear(); + int norb = mOrbitData.size(); + if (mVerbosity >= DbgFull) { + LOG(INFO) << "Dump of pedestal data lookup table"; + } + for (int iorb = 0; iorb < norb; iorb++) { + mOrbit[mOrbitData[iorb].ir.orbit] = iorb; + if (mVerbosity >= DbgFull) { + LOG(INFO) << "mOrbitData[" << mOrbitData[iorb].ir.orbit << "] = " << iorb; + } + } + mNBC = mBCData.size(); + mReco.clear(); + mReco.resize(mNBC); + // Initialization of reco structure + for (int ibc = 0; ibc < mNBC; ibc++) { + auto& bcr = mReco[ibc]; +#ifdef O2_ZDC_TDC_C_ARRAY + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + for (int i = 0; i < MaxTDCValues; i++) { + bcr.tdcVal[itdc][i] = kMinShort; + bcr.tdcAmp[itdc][i] = kMinShort; + } + } +#endif + auto& bcd = mBCData[ibc]; + bcr.ir = bcd.ir; + int chEnt = bcd.ref.getFirstEntry(); + for (int ic = 0; ic < bcd.ref.getEntries(); ic++) { + auto& chd = mChData[chEnt]; + if (chd.id > IdDummy && chd.id < NChannels) { + bcr.ref[chd.id] = chEnt; + } + chEnt++; + } + } + + // Probably this is not necessary + // for(int itdc=0; itdc<NTDCChannels; itdc++){ + // mReco.pattern[itdc]=0; + // for(int itb=0; itb<NTimeBinsPerBC; itb++){ + // mReco.fired[itdc][itb]=0; + // } + // for(int isb=0; isb<mNSB; isb++){ + // mReco.inter[itdc][isb]=0; + // } + // } + + // Assign interaction record and event information + for (int ibc = 0; ibc < mNBC; ibc++) { + mReco[ibc].ir = mBCData[ibc].ir; + mReco[ibc].channels = mBCData[ibc].channels; + mReco[ibc].triggers = mBCData[ibc].triggers; + } + + // Find consecutive bunch crossings and perform signal interpolation + // in the identified ranges (in the reconstruction method we take into + // account for signals that do not span the entire reange) + int seq_beg = 0; + int seq_end = 0; + LOG(INFO) << "ZDC reconstruction for " << mNBC << " bunch crossings"; + for (int ibc = 0; ibc < mNBC; ibc++) { + auto& ir = mBCData[seq_end].ir; + auto bcd = mBCData[ibc].ir.differenceInBC(ir); + if (bcd < 0) { + LOG(FATAL) << "Orbit number is not increasing " << mBCData[seq_end].ir.orbit << "." << mBCData[seq_end].ir.bc << " followed by " << mBCData[ibc].ir.orbit << "." << mBCData[ibc].ir.bc; + return __LINE__; + } else if (bcd > 1) { + // Detected a gap + reconstruct(seq_beg, seq_end); + seq_beg = ibc; + seq_end = ibc; + } else if (ibc == (mNBC - 1)) { + // Last bunch + seq_end = ibc; + reconstruct(seq_beg, seq_end); + seq_beg = mNBC; + seq_end = mNBC; + } else { + // Look for another bunch + seq_end = ibc; + } + } + + return 0; +} // process + +int DigiReco::reconstruct(int ibeg, int iend) +{ + // Process consecutive BCs + if (ibeg == iend) { + if (mReco[ibeg].ir.bc == (o2::constants::lhc::LHCMaxBunches - 1)) { + mNLastLonely++; + } else { + mNLonely++; + LOG(INFO) << "Lonely bunch " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc; + } + return 0; + } + + if (mVerbosity >= DbgFull) { + LOG(INFO) << __func__ << "(" << ibeg << "," << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; + } + + // Get reconstruction parameters + auto& ropt = RecoParamZDC::Instance(); + + // Apply differential discrimination with triple condition + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + // Check if channel has valid data for consecutive bunches in current bunch range + // N.B. there are events recorded from ibeg-iend but we are not sure if it is the + // case for every TDC channel + int istart = -1, istop = -1; + // Loop allows for gaps in the data sequence for each TDC channel + for (int ibun = ibeg; ibun <= iend; ibun++) { + if (mBCData[ibun].channels & mTDCMask[itdc]) { // TDC channel has data for this event + if (istart < 0) { + istart = ibun; + } + istop = ibun; + } else { // No data from channel + // A gap is detected + if (istart >= 0 && (istop - istart) > 0) { + // Need data for at least two consecutive bunch crossings + processTrigger(itdc, istart, istop); + } + istart = -1; + istop = -1; + } + } + // Check if there are consecutive bunch crossings at the end of group + if (istart >= 0 && (istop - istart) > 0) { + processTrigger(itdc, istart, istop); + } + } + + // Loop on bunches after trigger evaluation + // Reconstruct integrated charges and fill output tree + // TODO: compare average pedestal with estimation from current event + // TODO: failover in case of discrepancy + for (int ibun = ibeg; ibun <= iend; ibun++) { + updateOffsets(ibun); + auto& rec = mReco[ibun]; + for (int itdc = 0; itdc < NTDCChannels; itdc++) { +#ifdef O2_ZDC_DEBUG + if (rec.fired[itdc] != 0x0) { + printf("%d %u.%u TDC %d [%s] %04hx -> ", ibun, rec.ir.orbit, rec.ir.bc, itdc, ChannelNames[TDCSignal[itdc]].data(), rec.fired[itdc]); + for (int isam = 0; isam < NTimeBinsPerBC; isam++) { + printf("%d", rec.fired[itdc] & mMask[isam] ? 1 : 0); + } + printf("\n"); + } +#endif + rec.pattern[itdc] = 0; + for (int32_t i = 0; i < rec.ntdc[itdc]; i++) { +#ifdef O2_ZDC_DEBUG + LOG(INFO) << "tdc " << i << " [" << ChannelNames[TDCSignal[itdc]] << "] " << rec.TDCAmp[itdc][i] << " @ " << rec.TDCVal[itdc][i]; +#endif + // There is a TDC value in the search zone around main-main position + if (std::abs(rec.TDCVal[itdc][i]) < ropt.tdc_search[itdc]) { + rec.pattern[itdc] = 1; + } +#ifdef O2_ZDC_DEBUG + else { + LOG(INFO) << rec.TDCVal[itdc][i] << " " << ropt.tdc_search[itdc]; + } +#endif + } + } +#ifdef O2_ZDC_DEBUG + printf("%d %u.%-4u TDC PATTERN: ", ibun, mReco[ibun].ir.orbit, mReco[ibun].ir.bc); + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + printf("%d", rec.pattern[itdc]); + } + printf("\n"); +#endif + // Check if coincidence of common PM and sum of towers is satisfied + bool fired[NChannels] = {0}; + // Side A + if ((rec.pattern[TDCZNAC] || ropt.bitset[TDCZNAC]) && (rec.pattern[TDCZNAS] || ropt.bitset[TDCZNAS])) { + for (int ich = IdZNAC; ich <= IdZNASum; ich++) { + fired[ich] = true; + } + } + if ((rec.pattern[TDCZPAC] || ropt.bitset[TDCZPAC]) && (rec.pattern[TDCZPAS] || ropt.bitset[TDCZPAS])) { + for (int ich = IdZPAC; ich <= IdZPASum; ich++) { + fired[ich] = true; + } + } + // ZEM1 and ZEM2 are not in coincidence + fired[IdZEM1] = rec.pattern[TDCZEM1]; + fired[IdZEM2] = rec.pattern[TDCZEM2]; + // Side C + if ((rec.pattern[TDCZNCC] || ropt.bitset[TDCZNCC]) && (rec.pattern[TDCZNCS] || ropt.bitset[TDCZNCS])) { + for (int ich = IdZNCC; ich <= IdZNCSum; ich++) { + fired[ich] = true; + } + } + if ((rec.pattern[TDCZPCC] || ropt.bitset[TDCZPCC]) && (rec.pattern[TDCZPCS] || ropt.bitset[TDCZPCS])) { + for (int ich = IdZPCC; ich <= IdZPCSum; ich++) { + fired[ich] = true; + } + } + // TODO: option to use a less restrictive definition of "fired" using for example + // just the autotrigger bits instead of using TDCs + if (mVerbosity >= DbgFull) { + printf("%d FIRED ", ibun); + printf("ZNA:%d%d%d%d%d%d ZPA:%d%d%d%d%d%d ZEM:%d%d ZNC:%d%d%d%d%d%d ZPC:%d%d%d%d%d%d\n", + fired[IdZNAC], fired[IdZNA1], fired[IdZNA2], fired[IdZNA3], fired[IdZNA4], fired[IdZNASum], + fired[IdZPAC], fired[IdZPA1], fired[IdZPA2], fired[IdZPA3], fired[IdZPA4], fired[IdZPASum], + fired[IdZEM1], fired[IdZEM2], + fired[IdZNCC], fired[IdZNC1], fired[IdZNC2], fired[IdZNC3], fired[IdZNC4], fired[IdZNCSum], + fired[IdZPCC], fired[IdZPC1], fired[IdZPC2], fired[IdZPC3], fired[IdZPC4], fired[IdZPCSum]); + } + // Get Orbit pedestals + updateOffsets(ibun); + for (int ich = 0; ich < NChannels; ich++) { + // Check if the corresponding TDC is fired + if (fired[ich]) { + // Check if channel data are present in payload + auto ref = mReco[ibun].ref[ich]; + if (ref < ZDCRefInitVal) { + // Energy reconstruction Assignment of TDCs + // Compute event by event pedestal + bool hasEvPed = false; + float evPed = 0; + if (ibun > ibeg) { + auto ref_m = mReco[ibun - 1].ref[ich]; + if (ropt.beg_ped_int[ich] >= 0 || ref_m < ZDCRefInitVal) { + for (int is = ropt.beg_ped_int[ich]; is <= ropt.end_ped_int[ich]; is++) { + if (is < 0) { + // Sample is in previous BC + evPed += float(mChData[ref_m].data[is + NTimeBinsPerBC]); + } else { + // Sample is in current BC + evPed += float(mChData[ref].data[is]); + } + } + evPed /= float(ropt.end_ped_int[ich] - ropt.beg_ped_int[ich] + 1); + hasEvPed = true; + } + } + float myPed = std::numeric_limits<float>::infinity(); + // TODO: compare event pedestal with orbit pedestal to detect pile-up + // from previous bunch. If this is the case we use orbit pedestal + // instead of event pedestal + if (hasEvPed) { + myPed = evPed; + rec.adcPedEv[ich] = true; + } else if (mSource[ich] == PedOr) { + myPed = mOffset[ich]; + rec.adcPedOr[ich] = true; + } else if (mSource[ich] == PedQC) { + myPed = mOffset[ich]; + rec.adcPedQC[ich] = true; + } else { + rec.adcPedMissing[ich] = true; + } + if (myPed < std::numeric_limits<float>::infinity()) { + float sum = 0; + for (int is = ropt.beg_int[ich]; is <= ropt.end_int[ich]; is++) { + // TODO: pile-up correction + // TODO: manage signal positioned across boundary + sum += (myPed - float(mChData[ref].data[is])); + } + rec.ezdc[ich] = sum * ropt.energy_calib[ich]; + } else { + LOGF(WARN, "%d.%-4d CH %2d %s missing pedestal", rec.ir.orbit, rec.ir.bc, ich, ChannelNames[ich].data()); + } + } else { + LOG(FATAL) << "Serious mess in reconstruction code"; + rec.err[ich] = true; + } + } + } // Loop on channels + } // Loop on bunches + if (mTreeDbg) { + for (int ibun = ibeg; ibun <= iend; ibun++) { + auto& rec = mReco[ibun]; + mRec = rec; + mTDbg->Fill(); + } + } + return 0; +} //reconstruct + +void DigiReco::updateOffsets(int ibun) +{ + auto orbit = mBCData[ibun].ir.orbit; + if (orbit == mOffsetOrbit) { + return; + } + mOffsetOrbit = orbit; + + // Reset information about pedestal origin + for (int ich = 0; ich < NChannels; ich++) { + mSource[ich] = PedND; + mOffset[ich] = std::numeric_limits<float>::infinity(); + } + + // Default TDC pedestal is from orbit + // Look for Orbit pedestal offset + std::map<uint32_t, int>::iterator it = mOrbit.find(orbit); + if (it != mOrbit.end()) { + auto& orbitdata = mOrbitData[it->second]; + for (int ich = 0; ich < NChannels; ich++) { + auto myped = orbitdata.asFloat(ich); + if (myped >= ADCMin && myped <= ADCMax) { + // Pedestal information is present for this channel + mOffset[ich] = myped; + mSource[ich] = PedOr; + } + } + } + + // TODO: use QC pedestal if orbit pedestals are missing + + for (int ich = 0; ich < NChannels; ich++) { + if (mSource[ich] == PedND) { + LOGF(ERROR, "Missing pedestal for ch %2d %s orbit %u ", ich, ChannelNames[ich], mOffsetOrbit); + } +#ifdef O2_ZDC_DEBUG + LOGF(INFO, "Pedestal for ch %2d %s orbit %u %s: %f", ich, ChannelNames[ich], mOffsetOrbit, mSource[ich] == PedOr ? "OR" : (mSource[ich] == PedQC ? "QC" : "??"), mOffset[ich]); +#endif + } +} // updateOffsets + +void DigiReco::processTrigger(int itdc, int ibeg, int iend) +{ +#ifdef O2_ZDC_DEBUG + LOG(INFO) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[TDCSignal[itdc]] << "] ," << ibeg << "," << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; +#endif + // Get reconstruction parameters + auto& ropt = RecoParamZDC::Instance(); + + int nbun = iend - ibeg + 1; + int maxs2 = NTimeBinsPerBC * nbun - 1; + int shift = ropt.tsh[itdc]; + int thr = ropt.tth[itdc]; + + int is1 = 0, is2 = 1; + uint8_t isfired = 0; +#ifdef O2_ZDC_DEBUG + int16_t m[3] = {0}; + int16_t s[3] = {0}; +#endif + int it1 = 0, it2 = 0, ib1 = -1, ib2 = -1; + for (;;) { + // Shift data + isfired = isfired << 1; +#ifdef O2_ZDC_DEBUG + for (int i = 2; i > 0; i--) { + m[i] = m[i - 1]; + s[i] = s[i - 1]; + } +#endif + // Bunches and samples that are used in the difference + int b1 = ibeg + is1 / NTimeBinsPerBC; + int b2 = ibeg + is2 / NTimeBinsPerBC; + int s1 = is1 % NTimeBinsPerBC; + int s2 = is2 % NTimeBinsPerBC; + auto ref_m = mReco[b1].ref[TDCSignal[itdc]]; // reference to minuend + auto ref_s = mReco[b2].ref[TDCSignal[itdc]]; // reference to subtrahend + // Check data consistency before computing difference + if (ref_m == ZDCRefInitVal || ref_s == ZDCRefInitVal) { + LOG(FATAL) << "Missing information for bunch crossing"; + return; + } + // TODO: More checks that bunch crossings are indeed consecutive + int diff = mChData[ref_m].data[s1] - mChData[ref_s].data[s2]; + // Triple trigger condition +#ifdef O2_ZDC_DEBUG + m[0] = mChData[ref_m].data[s1]; + s[0] = mChData[ref_s].data[s2]; +#endif + if (diff > thr) { + isfired = isfired | 0x1; + if ((isfired & 0x7) == 0x7) { + // Fired bit is assigned to the second sample, i.e. to the one that can identify the + // signal peak position + mReco[b2].fired[itdc] |= mMask[s2]; +#ifdef O2_ZDC_DEBUG + LOG(INFO) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " Fired @ " << mReco[b2].ir.orbit << "." << mReco[b2].ir.bc << ".s" << s2 + << " (" << m[2] << " - (" << s[2] << ")) = " << (m[2] - s[2]) << " > " << thr + << " && (" << m[1] << " - (" << s[1] << ")) = " << (m[1] - s[1]) << " > " << thr + << " && (s" << s1 << ":" << m[0] << " - (s" << s2 << ":" << s[0] << ")) = " << diff << " > " << thr; +#endif + } + } + if (is2 >= shift) { + is1++; + } + if (is2 < maxs2) { + is2++; + } + if (is1 == maxs2) { + break; + } + } + interpolate(itdc, ibeg, iend); +} // processTrigger + +O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) +{ + constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing + if (i >= mNtot || i < 0) { + LOG(FATAL) << "Error addressing TDC itdc=" << itdc << " i=" << i << " mNtot=" << mNtot; + return std::numeric_limits<float>::infinity(); + } + // Constant extrapolation at the beginning and at the end of the array + if (i < TSNH) { + // Return value of first sample + return mFirstSample; + } else if (i >= mIlast) { + // Return value of last sample + return mLastSample; + } else { + // Identification of the point to be assigned + int ibun = ibeg + i / nsbun; + // Interpolation between acquired points (N.B. from 0 to mNint) + i = i - TSNH; + int im = i % TSN; + if (im == 0) { + // This is an acquired point + int ip = (i / TSN) % NTimeBinsPerBC; + int ib = ibeg + (i / TSN) / NTimeBinsPerBC; + if (ib != ibun) { + LOG(FATAL) << "ib=" << ib << " ibun=" << ibun; + return std::numeric_limits<float>::infinity(); + } + return mChData[mReco[ibun].ref[TDCSignal[itdc]]].data[ip]; + } else { + // Do the actual interpolation + O2_ZDC_DIGIRECO_FLT y = 0; + int ip = i / TSN; + O2_ZDC_DIGIRECO_FLT sum = 0; + for (int is = TSN - im, ii = ip - TSL + 1; is < NTS; is += TSN, ii++) { + // Default is first point in the array + O2_ZDC_DIGIRECO_FLT yy = mFirstSample; + if (ii > 0) { + if (ii < mNsam) { + int ip = ii % NTimeBinsPerBC; + int ib = ibeg + ii / NTimeBinsPerBC; + yy = mChData[mReco[ib].ref[TDCSignal[itdc]]].data[ip]; + } else { + // Last acquired point + yy = mLastSample; + } + } + sum += mTS[is]; + y += yy * mTS[is]; + } + y = y / sum; + return y; + } + } +} + +#ifdef O2_ZDC_INTERP_DEBUG +void DigiReco::setPoint(int itdc, int ibeg, int iend, int i) +{ + constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing + if (i >= mNtot || i < 0) { + LOG(FATAL) << "Error addressing TDC itdc=" << itdc << " i=" << i << " mNtot=" << mNtot; + return; + } + // Constant extrapolation at the beginning and at the end of the array + if (i < TSNH) { + // Assign value of first sample + mReco[ibeg].inter[itdc][i] = mFirstSample; + } else if (i >= mIlast) { + // Assign value of last sample + int isam = i % nsbun; + mReco[iend].inter[itdc][isam] = mLastSample; + } else { + // Identification of the point to be assigned + int ibun = ibeg + i / nsbun; + int isam = i % nsbun; + // Interpolation between acquired points (N.B. from 0 to mNint) + i = i - TSNH; + int im = i % TSN; + if (im == 0) { + // This is an acquired point + int ip = (i / TSN) % NTimeBinsPerBC; + int ib = ibeg + (i / TSN) / NTimeBinsPerBC; + if (ib != ibun) { + LOG(FATAL) << "ib=" << ib << " ibun=" << ibun; + return; + } + mReco[ibun].inter[itdc][isam] = mChData[mReco[ibun].ref[TDCSignal[itdc]]].data[ip]; + } else { + // Do the actual interpolation + O2_ZDC_DIGIRECO_FLT y = 0; + int ip = i / TSN; + O2_ZDC_DIGIRECO_FLT sum = 0; + for (int is = TSN - im, ii = ip - TSL + 1; is < NTS; is += TSN, ii++) { + // Default is first point in the array + O2_ZDC_DIGIRECO_FLT yy = mFirstSample; + if (ii > 0) { + if (ii < mNsam) { + int ip = ii % NTimeBinsPerBC; + int ib = ibeg + ii / NTimeBinsPerBC; + yy = mChData[mReco[ib].ref[TDCSignal[itdc]]].data[ip]; + } else { + // Last acquired point + yy = mLastSample; + } + } + sum += mTS[is]; + y += yy * mTS[is]; + } + y = y / sum; + mReco[ibun].inter[itdc][isam] = y; + } + } +} // setPoint +#endif + +void DigiReco::interpolate(int itdc, int ibeg, int iend) +{ +#ifdef O2_ZDC_DEBUG + LOG(INFO) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[TDCSignal[itdc]] << "] ," << ibeg << "," << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; +#endif + // TODO: get data from preceding time frame + constexpr int MaxTimeBin = NTimeBinsPerBC - 1; //< number of samples per BC + constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing + // Set data members for interpolation of the current TDC + mNbun = iend - ibeg + 1; // Number of adjacent bunches + mNsam = mNbun * NTimeBinsPerBC; // Number of acquired samples + mNtot = mNsam * TSN; // Total number of points in the interpolated arrays + mNint = (mNbun * NTimeBinsPerBC - 1) * TSN; // Total points in the interpolation region (-1) + mIlast = mNtot - TSNH; // Index of last acquired sample + + constexpr int nsp = 5; // Number of points to be searched + + // At this level there should be no need to check if the TDC channel is connected + // since a fatal should have been raised already + for (int ibun = ibeg; ibun <= iend; ibun++) { + auto ref = mReco[ibun].ref[TDCSignal[itdc]]; + if (ref == ZDCRefInitVal) { + LOG(FATAL) << "Missing information for bunch crossing"; + } + } + + // Get reconstruction parameters + auto& ropt = RecoParamZDC::Instance(); + + int imod = ropt.tmod[itdc]; // Module corresponding to TDC channel + int ich = ropt.tch[itdc]; // Hardware channel corresponding to TDC channel + + auto ref_beg = mReco[ibeg].ref[TDCSignal[itdc]]; + auto ref_end = mReco[iend].ref[TDCSignal[itdc]]; + + mFirstSample = mChData[ref_beg].data[0]; + mLastSample = mChData[ref_end].data[NTimeBinsPerBC - 1]; + + // Full interpolation +#ifdef O2_ZDC_INTERP_DEBUG + for (int i = 0; i < mNtot; i++) { + setPoint(itdc, ibeg, iend, i); + } +#endif + + // Looking for a local maximum in a search zone + float amp = std::numeric_limits<float>::infinity(); // Amplitude to be stored + int isam_amp = 0; // Sample at maximum amplitude (relative to beginning of group) + int ip_old = -1, ip_cur = -1, ib_cur = -1; // Current and old points + bool is_searchable = false; // Flag for point in the search zone for maximum amplitude + bool was_searchable = false; // Flag for point in the search zone for maximum amplitude + int ib[nsp] = {-1, -1, -1, -1, -1}; + int ip[nsp] = {-1, -1, -1, -1, -1}; + // N.B. Points at the extremes are constant therefore no local maximum + // can occur in these two regions + for (int i = 0; i < mNint; i++) { + int isam = i + TSNH; + // Check if trigger is fired for this point + // For the moment we don't take into account possible extensions of the search zone + // ip_cur can span several bunches and is used just to identify transitions + ip_cur = isam / TSN; + // Speed up computation + if (ip_cur != ip_old) { + ip_old = ip_cur; + for (int j = 0; j < 5; j++) { + ib[j] = -1; + ip[j] = -1; + } + // There are three possible triple conditions that involve current point (middle is current point) + ip[2] = ip_cur % NTimeBinsPerBC; + ib[2] = ibeg + ip_cur / NTimeBinsPerBC; + ib_cur = ib[2]; + if (ip[2] > 0) { + ip[1] = ip[2] - 1; + ib[1] = ib[2]; + } else if (ip[2] == 0) { + if (ib[2] > ibeg) { + ib[1] = ib[2] - 1; + ip[1] = MaxTimeBin; + } + } + if (ip[1] > 0) { + ip[0] = ip[1] - 1; + ib[0] = ib[1]; + } else if (ip[1] == 0) { + if (ib[1] > ibeg) { + ib[0] = ib[1] - 1; + ip[0] = MaxTimeBin; + } + } + if (ip[2] < MaxTimeBin) { + ip[3] = ip[2] + 1; + ib[3] = ib[2]; + } else if (ip[2] == MaxTimeBin) { + if (ib[2] < iend) { + ib[3] = ib[2] + 1; + ip[3] = 0; + } + } + if (ip[3] < MaxTimeBin) { + ip[4] = ip[3] + 1; + ib[4] = ib[3]; + } else if (ip[3] == MaxTimeBin) { + if (ib[3] < iend) { + ib[4] = ib[3] + 1; + ip[4] = 0; + } + } + // meet the threshold condition + was_searchable = is_searchable; + // Search conditions with list of allowed patterns + // No need to double check ib[?] and ip[?] because either we assign both or none + uint16_t triggered = 0x0000; + for (int j = 0; j < 5; j++) { + if (ib[j] >= 0 && (mReco[ib[j]].fired[itdc] & mMask[ip[j]]) > 0) { + triggered |= (0x1 << j); + } + } + // Reject conditions: + // 00000 + // 10001 + // One among 10000 and 00001 + // Accept conditions: + constexpr uint16_t accept[14] = { + // 0x01, // 00001 extend search zone before maximum + 0x02, // 00010 + 0x04, // 00100 + 0x08, // 01000 + 0x10, // 10000 extend after + 0x03, // 00011 + 0x06, // 00110 + 0x0c, // 01100 + 0x18, // 11000 + 0x07, // 00111 + 0x0e, // 01110 + 0x1c, // 11100 + 0x0f, // 01111 + 0x1e, // 11110 + 0x1f // 11111 + }; + // All other are not correct (->reject) + is_searchable = 0; + if (triggered != 0) { + for (int j = 0; j < 14; j++) { + if (triggered == accept[j]) { + is_searchable = 1; + break; + } + } + } + } + // We do not restrict search zone around expected main-main collision + // because we would like to be able to identify pile-up from collisions + // with satellites (buggy) + + // If we exit from searching zone + if (was_searchable && !is_searchable) { + if (amp <= ADCMax) { + // Store identified peak + int ibun = ibeg + isam_amp / nsbun; + updateOffsets(ibun); + if (mSource[ich] != PedND) { + amp = mOffset[ich] - amp; + } else { + LOGF(ERROR, "%u.%-4d Missing pedestal for TDC %d %s ", mBCData[ibun].ir.orbit, mBCData[ibun].ir.bc, itdc, ChannelNames[TDCSignal[itdc]]); + amp = std::numeric_limits<float>::infinity(); + } + int tdc = isam_amp % nsbun; + assignTDC(ibun, ibeg, iend, itdc, tdc, amp); + } + amp = std::numeric_limits<float>::infinity(); + isam_amp = 0; + was_searchable = 0; + } + if (is_searchable) { + int mysam = isam % nsbun; +#ifndef O2_ZDC_INTERP_DEBUG + // Perform interpolation for the searched point + //setPoint(itdc, ibeg, iend, isam); + float myval = getPoint(itdc, ibeg, iend, isam); +#else + float myval = mReco[ib_cur].inter[itdc][mysam]; +#endif + if (myval < amp) { + amp = myval; + isam_amp = isam; + } + } + } + // Trigger flag still present at the of the scan + if (is_searchable) { + // Add last identified peak + if (amp <= ADCMax) { + // Store identified peak + int ibun = ibeg + isam_amp / nsbun; + updateOffsets(ibun); + if (mSource[ich] != PedND) { + amp = mOffset[ich] - amp; + } else { + LOGF(ERROR, "%u.%-4d Missing pedestal for TDC %d %s ", mBCData[ibun].ir.orbit, mBCData[ibun].ir.bc, itdc, ChannelNames[TDCSignal[itdc]]); + amp = std::numeric_limits<float>::infinity(); + } + int tdc = isam_amp % nsbun; + assignTDC(ibun, ibeg, iend, itdc, tdc, amp); + } + } +} // interpolate + +void DigiReco::assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float amp) +{ + constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing + constexpr int tdc_max = nsbun / 2; + constexpr int tdc_min = -tdc_max; + + // Apply tdc shift correction + int tdc_cor = tdc - tdc_shift[itdc]; + // Correct bunch assignment + if (tdc_cor < tdc_min && ibun >= ibeg) { + // Assign to preceding bunch + ibun = ibun - 1; + tdc_cor = tdc_cor + nsbun; + } else if (tdc_cor >= tdc_max && ibun < iend) { + // Assign to following bunch + ibun = ibun + 1; + tdc_cor = tdc_cor - nsbun; + } + if (tdc_cor < kMinShort) { + LOG(ERROR) << "TDC " << itdc << " " << tdc_cor << " is out of range"; + tdc_cor = kMinShort; + } + if (tdc_cor > kMaxShort) { + LOG(ERROR) << "TDC " << itdc << " " << tdc_cor << " is out of range"; + tdc_cor = kMaxShort; + } + + auto& rec = mReco[ibun]; + + // Assign to correct bunch + auto myamp = std::nearbyint(amp / FTDCAmp); + rec.TDCVal[itdc].push_back(tdc_cor); + rec.TDCAmp[itdc].push_back(myamp); + int& ihit = mReco[ibun].ntdc[itdc]; +#ifdef O2_ZDC_TDC_C_ARRAY + if (ihit < MaxTDCValues) { + rec.tdcVal[itdc][ihit] = tdc_cor; + rec.tdcAmp[itdc][ihit] = myamp; + } else { + LOG(ERROR) << rec.ir.orbit << "." << rec.ir.bc << " " + << "ibun=" << ibun << " itdc=" << itdc << " tdc=" << tdc << " tdc_cor=" << tdc_cor * FTDCVal << " amp=" << amp * FTDCAmp << " OVERFLOW"; + } +#endif + int ich = TDCSignal[itdc]; + // Assign info about pedestal subtration + if (mSource[ich] == PedOr) { + rec.tdcPedOr[ich] = true; + } else if (mSource[ich] == PedQC) { + rec.tdcPedQC[ich] = true; + } else if (mSource[ich] == PedEv) { + // In present implementation this never happens + rec.tdcPedEv[ich] = true; + } else { + rec.tdcPedMissing[ich] = true; + } +#ifdef O2_ZDC_DEBUG + LOG(INFO) << mReco[ibun].ir.orbit << "." << mReco[ibun].ir.bc + << " ibun=" << ibun << " itdc=" << itdc << " tdc=" << tdc << " tdc_cor=" << tdc_cor * FTDCVal << " amp=" << amp << " -> " << myamp + << " pedSrc = " << mSource[ich]; +#endif + ihit++; +} // assignTDC + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx new file mode 100644 index 0000000000000..f19cb6a737b3d --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCReconstruction/RecoConfigZDC.h" + +using namespace o2::zdc; + +void RecoConfigZDC::setSearch(uint32_t ich, int val) +{ + if (ich >= 0 && ich < NTDCChannels) { + tdc_search[ich] = val; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + } +} + +int RecoConfigZDC::getSearch(uint32_t ich) const +{ + if (ich >= 0 && ich < NTDCChannels) { + return tdc_search[ich]; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + return -1; + } +} + +void RecoConfigZDC::setIntegration(uint32_t ich, int beg, int end, int beg_ped, int end_ped) +{ + int sig_l = 0; + int sig_h = NTimeBinsPerBC - 1; + int ped_l = -NTimeBinsPerBC; + int ped_h = NTimeBinsPerBC - 1; + + if (ich >= 0 && ich < NChannels) { + if (beg < sig_l || beg > sig_h) { + LOG(FATAL) << "Integration start = " << beg << " for signal " << ich << " (" << ChannelNames[ich] << ") not in allowed range [" << sig_l << "-" << sig_h << "]"; + return; + } + if (end < sig_l || end > sig_h) { + LOG(FATAL) << "Integration end = " << beg << " for signal " << ich << " (" << ChannelNames[ich] << ") not in allowed range [" << sig_l << "-" << sig_h << "]"; + return; + } + if (end < beg) { + LOG(FATAL) << "Inconsistent integration range for signal " << ich << " (" << ChannelNames[ich] << "): [" << beg << "-" << end << "]"; + return; + } + if (beg_ped < ped_l || beg_ped > ped_h) { + LOG(FATAL) << "Pedestal integration start = " << beg_ped << " for signal " << ich << " (" << ChannelNames[ich] << ") not in allowed range [" << ped_l << "-" << ped_h << "]"; + return; + } + if (end_ped < ped_l || end_ped > ped_h) { + LOG(FATAL) << "Pedestal integration end = " << end_ped << " for signal " << ich << " (" << ChannelNames[ich] << ") not in allowed range [" << ped_l << "-" << ped_h << "]"; + return; + } + if (end_ped < beg_ped) { + LOG(FATAL) << "Inconsistent integration range for pedestal " << ich << " (" << ChannelNames[ich] << "): [" << beg_ped << "-" << end_ped << "]"; + return; + } + beg_int[ich] = beg; + end_int[ich] = end; + beg_ped_int[ich] = beg_ped; + end_ped_int[ich] = end_ped; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + } +} + +void RecoConfigZDC::print() +{ + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + LOG(INFO) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << tdc_search[itdc] << " = " << tdc_search[itdc] * FTDCVal << " ns"; + } + for (Int_t ich = 0; ich < NChannels; ich++) { + LOG(INFO) << ChannelNames[ich] << " integration: signal=[" << beg_int[ich] << ":" << end_int[ich] << "] pedestal=[" << beg_ped_int[ich] << ":" << end_ped_int[ich] << "]"; + } +} diff --git a/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx b/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx new file mode 100644 index 0000000000000..1d135c038d11f --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCReconstruction/RecoParamZDC.h" + +O2ParamImpl(o2::zdc::RecoParamZDC); + +void o2::zdc::RecoParamZDC::setBit(uint32_t ibit, bool val) +{ + if (ibit >= 0 && ibit < NTDCChannels) { + bitset[ibit] = val; + } else { + LOG(FATAL) << __func__ << " bit " << ibit << " not in allowed range"; + } +} diff --git a/Detectors/ZDC/reconstruction/src/ZDCEnergyParam.cxx b/Detectors/ZDC/reconstruction/src/ZDCEnergyParam.cxx new file mode 100644 index 0000000000000..b66f13ae4d2c5 --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/ZDCEnergyParam.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" + +using namespace o2::zdc; + +void ZDCEnergyParam::setEnergyCalib(uint32_t ich, float val) +{ + bool in_list = false; + for (int il = 0; il < ChEnergyCalib.size(); il++) { + if (ich == ChEnergyCalib[il]) { + in_list = true; + break; + } + } + if (in_list) { + energy_calib[ich] = val; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + for (int il = 0; il < ChEnergyCalib.size(); il++) { + LOG(info) << __func__ << " channel " << ChEnergyCalib[il] << " " << ChannelNames[ChEnergyCalib[il]]; + } + } +} + +float ZDCEnergyParam::getEnergyCalib(uint32_t ich) const +{ + if (ich >= 0 && ich < NChannels) { + return energy_calib[ich]; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + return 0; + } +} + +void ZDCEnergyParam::print() +{ + for (Int_t ich = 0; ich < NChannels; ich++) { + if (energy_calib[ich] > 0) { + LOG(INFO) << ChannelNames[ich] << " calibration factor = " << energy_calib[ich]; + } + } +} diff --git a/Detectors/ZDC/reconstruction/src/ZDCReconstructionLinkDef.h b/Detectors/ZDC/reconstruction/src/ZDCReconstructionLinkDef.h new file mode 100644 index 0000000000000..4892af277a9be --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/ZDCReconstructionLinkDef.h @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::zdc::RecoConfigZDC + ; +#pragma link C++ class o2::zdc::RecoParamZDC + ; +#pragma link C++ class o2::zdc::ZDCTDCParam + ; +#pragma link C++ class o2::zdc::ZDCEnergyParam + ; +#pragma link C++ class o2::zdc::ZDCTowerParam + ; + +#endif diff --git a/Detectors/ZDC/reconstruction/src/ZDCTDCParam.cxx b/Detectors/ZDC/reconstruction/src/ZDCTDCParam.cxx new file mode 100644 index 0000000000000..537996da7507b --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/ZDCTDCParam.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCReconstruction/ZDCTDCParam.h" + +using namespace o2::zdc; + +void ZDCTDCParam::setShift(uint32_t ich, float val) +{ + if (ich >= 0 && ich < NTDCChannels) { + tdc_shift[ich] = val; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + } +} + +float ZDCTDCParam::getShift(uint32_t ich) const +{ + if (ich >= 0 && ich < NTDCChannels) { + return tdc_shift[ich]; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + return 0; + } +} + +void ZDCTDCParam::print() +{ + for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) { + LOG(INFO) << ChannelNames[TDCSignal[itdc]] << " shift = " << tdc_shift[itdc] << " ns"; + } +} diff --git a/Detectors/ZDC/reconstruction/src/ZDCTowerParam.cxx b/Detectors/ZDC/reconstruction/src/ZDCTowerParam.cxx new file mode 100644 index 0000000000000..ec76526ecd235 --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/ZDCTowerParam.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCReconstruction/ZDCTowerParam.h" + +using namespace o2::zdc; + +void ZDCTowerParam::setTowerCalib(uint32_t ich, float val) +{ + bool in_list = false; + for (int il = 0; il < ChTowerCalib.size(); il++) { + if (ich == ChTowerCalib[il]) { + in_list = true; + break; + } + } + if (in_list) { + tower_calib[ich] = val; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + for (int il = 0; il < ChTowerCalib.size(); il++) { + LOG(info) << __func__ << " channel " << ChTowerCalib[il] << " " << ChannelNames[ChTowerCalib[il]]; + } + } +} + +float ZDCTowerParam::getTowerCalib(uint32_t ich) const +{ + if (ich >= 0 && ich < NChannels) { + return tower_calib[ich]; + } else { + LOG(FATAL) << __func__ << " channel " << ich << " not in allowed range"; + return 0; + } +} + +void ZDCTowerParam::print() +{ + for (Int_t ich = 0; ich < NChannels; ich++) { + if (tower_calib[ich] > 0) { + LOG(INFO) << ChannelNames[ich] << " calibration factor = " << tower_calib[ich]; + } + } +} diff --git a/Detectors/ZDC/simulation/CMakeLists.txt b/Detectors/ZDC/simulation/CMakeLists.txt index f58348a73e05d..e9c9029dbd7c7 100644 --- a/Detectors/ZDC/simulation/CMakeLists.txt +++ b/Detectors/ZDC/simulation/CMakeLists.txt @@ -1,25 +1,35 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(ZDCSimulation SOURCES src/Detector.cxx src/Digitizer.cxx src/SimCondition.cxx - src/ZDCSimParam.cxx src/SpatialPhotonResponse.cxx + src/ZDCSimParam.cxx src/SpatialPhotonResponse.cxx src/Digits2Raw.cxx PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::ZDCBase - O2::DataFormatsZDC O2::CCDB O2::SimConfig) + O2::DataFormatsZDC O2::CCDB O2::SimConfig + O2::DetectorsRaw O2::Headers) o2_target_root_dictionary(ZDCSimulation - HEADERS include/ZDCSimulation/Hit.h - include/ZDCSimulation/Digitizer.h + HEADERS include/ZDCSimulation/Digitizer.h include/ZDCSimulation/Detector.h include/ZDCSimulation/SimCondition.h include/ZDCSimulation/ZDCSimParam.h include/ZDCSimulation/SpatialPhotonResponse.h) o2_data_file(COPY data DESTINATION Detectors/ZDC/simulation) + +o2_add_executable(digi2raw + COMPONENT_NAME zdc + SOURCES src/digi2raw.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCSimulation + O2::DetectorsRaw + O2::DetectorsCommonDataFormats + O2::CommonUtils + Boost::program_options) diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h b/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h index b6e79327cd041..7ad1187323bf1 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,13 +13,12 @@ #define ALICEO2_ZDC_DETECTOR_H_ #include <vector> // for vector -#include "Rtypes.h" // for Int_t, Double_t, Float_t, Bool_t, etc #include "TGeoManager.h" // for gGeoManager, TGeoManager (ptr only) #include "DetectorsBase/GeometryManager.h" // for getSensID #include "DetectorsBase/Detector.h" // for Detector #include "DetectorsCommonDataFormats/DetID.h" // for Detector #include "ZDCBase/Geometry.h" -#include "ZDCSimulation/Hit.h" +#include "DataFormatsZDC/Hit.h" #include "ZDCSimulation/SpatialPhotonResponse.h" #include "TParticle.h" #include <utility> @@ -63,7 +63,7 @@ class Detector : public o2::base::DetImpl<Detector> void Register() override; /// Gets the produced collections - std::vector<o2::zdc::Hit>* getHits(Int_t iColl) const + std::vector<o2::zdc::Hit>* getHits(int32_t iColl) const { if (iColl == 0) { return mHits; @@ -82,9 +82,9 @@ class Detector : public o2::base::DetImpl<Detector> void createMaterials(); void addAlignableVolumes() const override {} - o2::zdc::Hit* addHit(Int_t trackID, Int_t parentID, Int_t sFlag, Float_t primaryEnergy, Int_t detID, Int_t secID, - math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, Double_t energyloss, - Int_t nphePMC, Int_t nphePMQ); + o2::zdc::Hit* addHit(int32_t trackID, int32_t parentID, int32_t sFlag, float primaryEnergy, int32_t detID, int32_t secID, + math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, float tof, math_utils::Vector3D<float> xImpact, double energyloss, + int32_t nphePMC, int32_t nphePMQ); private: /// copy constructor @@ -162,22 +162,22 @@ class Detector : public o2::base::DetImpl<Detector> // helper function taking care of writing the photon response pattern at certain moments void flushSpatialResponse(); - Float_t mTrackEta; - Float_t mPrimaryEnergy; + float mTrackEta; + float mPrimaryEnergy; math_utils::Vector3D<float> mXImpact; - Float_t mTotLightPMC; - Float_t mTotLightPMQ; - Int_t mMediumPMCid = -1; - Int_t mMediumPMQid = -2; + float mTotLightPMC; + float mTotLightPMQ; + int32_t mMediumPMCid = -1; + int32_t mMediumPMQid = -2; // /// Container for hit data std::vector<o2::zdc::Hit>* mHits; - Float_t mLumiLength = 0; //TODO: make part of configurable params - Float_t mTCLIAAPERTURE = 3.5; //TODO: make part of configurable params - Float_t mTCLIAAPERTURENEG = 3.5; //TODO: make part of configurable params - Float_t mVCollSideCCentreY = 0.; //TODO: make part of configurable params + float mLumiLength = 0; //TODO: make part of configurable params + float mTCLIAAPERTURE = 3.5; //TODO: make part of configurable params + float mTCLIAAPERTURENEG = 3.5; //TODO: make part of configurable params + float mVCollSideCCentreY = 0.; //TODO: make part of configurable params int mZNENVVolID = -1; // the volume id for the neutron det envelope volume int mZPENVVolID = -1; // the volume id for the proton det envelope volume diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/Digitizer.h b/Detectors/ZDC/simulation/include/ZDCSimulation/Digitizer.h index ce717e5a97593..038d46cbaa64c 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/Digitizer.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/Digitizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,11 +12,12 @@ #ifndef DETECTORS_ZDC_DIGITIZER_H_ #define DETECTORS_ZDC_DIGITIZER_H_ -#include "ZDCSimulation/Hit.h" // for the hit -#include "ZDCSimulation/MCLabel.h" +#include "DataFormatsZDC/Hit.h" // for the hit +#include "DataFormatsZDC/MCLabel.h" #include "ZDCBase/ModuleConfig.h" #include "DataFormatsZDC/ChannelData.h" #include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/OrbitData.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "CommonDataFormat/InteractionRecord.h" #include <vector> @@ -104,23 +106,30 @@ class Digitizer void setContinuous(bool v = true) { mIsContinuous = v; } bool isContinuous() const { return mIsContinuous; } - + void updatePedestalReference(OrbitData& pdata); void refreshCCDB(); void setCCDBServer(const std::string& s) { mCCDBServer = s; } + void findEmptyBunches(const std::bitset<o2::constants::lhc::LHCMaxBunches>& bunchPattern); + int getNEmptyBunches() const { return mNEmptyBCs; } + void assignTriggerBits(uint32_t ibc, std::vector<BCData>& bcData); // Assign trigger bits for nearby bunch crossings + void Finalize(std::vector<BCData>& bcData, std::vector<o2::zdc::OrbitData>& pData); // Mask trigger bits for current bunch crossing + void setMaskTriggerBits(bool v = true) { mMaskTriggerBits = v; } + bool getMaskTriggerBits() { return mMaskTriggerBits; } + void setSkipMCLabels(bool v = true) { mSkipMCLabels = v; } + bool getSkipMCLabels() { return mSkipMCLabels; } private: static constexpr int BCCacheMin = -1, BCCacheMax = 5, NBC2Cache = 1 + BCCacheMax - BCCacheMin; - static constexpr int ADCMin = -2048, ADCMax = 2047; // 12 bit ADC std::bitset<NChannels> chanPattern(uint32_t v) const { return std::bitset<NChannels>(v); } void phe2Sample(int nphe, int parID, double timeHit, std::array<o2::InteractionRecord, NBC2Cache> const& cachedIR, int nCachedIR, int channel); - BCCache& getCreateBCCache(const o2::InteractionRecord& ir); BCCache* getBCCache(const o2::InteractionRecord& ir); - + void setTriggerMask(); + void setReadoutMask(); void generatePedestal(); void digitizeBC(BCCache& bc); bool triggerBC(int ibc); @@ -140,6 +149,11 @@ class Digitizer int mTrigBinMin = 0xffff; // prefetched min and max int mTrigBinMax = -0xffff; // bins to be checked for trigger int mNBCAHead = 0; // when storing triggered BC, store also mNBCAHead BCs + uint32_t mTriggerMask = 0; // Trigger mask from ModuleConfig + uint32_t mReadoutMask = 0; // Readout mask from ModuleConfig + int32_t mNEmptyBCs = -1; // Number of clean empty bunches for pedestal evaluation + bool mMaskTriggerBits = true; // Mask trigger bits with readout mask + bool mSkipMCLabels = false; // Skip MC labels in output std::string mCCDBServer = ""; const SimCondition* mSimCondition = nullptr; ///< externally set SimCondition diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/Digits2Raw.h b/Detectors/ZDC/simulation/include/ZDCSimulation/Digits2Raw.h new file mode 100644 index 0000000000000..9669ab747a2a0 --- /dev/null +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/Digits2Raw.h @@ -0,0 +1,107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Digits2Raw.h +/// \brief converts digits to raw format +/// \author pietro.cortese@cern.ch + +#ifndef ALICEO2_ZDC_DIGITS2RAW_H_ +#define ALICEO2_ZDC_DIGITS2RAW_H_ +#include <string> +#include <bitset> +#include <Rtypes.h> +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DataFormatsZDC/RawEventData.h" +#include "ZDCBase/ModuleConfig.h" +#include "ZDCSimulation/SimCondition.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" + +namespace o2 +{ +namespace zdc +{ +class Digits2Raw +{ + public: + Digits2Raw() = default; + void emptyBunches(std::bitset<3564>& bunchPattern); /// Prepare list of clean empty bunches for baseline evaluation + void processDigits(const std::string& outDir, const std::string& fileDigitsName); + void setModuleConfig(const ModuleConfig* moduleConfig) { mModuleConfig = moduleConfig; }; + const ModuleConfig* getModuleConfig() { return mModuleConfig; }; + void setSimCondition(const SimCondition* SimCondition) { mSimCondition = SimCondition; }; + const SimCondition* getSimCondition() { return mSimCondition; }; + + o2::raw::RawFileWriter& getWriter() { return mWriter; } + + void setFileFor(const std::string v) { mFileFor = v; } + std::string getFileFor() const { return mFileFor; } + + void setVerbosity(int v) + { + mVerbosity = v; + mWriter.setVerbosity(v); + } + int getVerbosity() const { return mVerbosity; } + + // void setContinuous(bool v = true) { mIsContinuous = v; } + bool isContinuous() const { return mIsContinuous; } + static void print_gbt_word(const uint32_t* word, const ModuleConfig* moduleConfig = nullptr); + + private: + void setTriggerMask(); + void updatePedestalReference(int bc); + void resetSums(uint32_t orbit); + void resetOutputStructure(uint16_t bc, uint32_t orbit, bool is_dummy); /// Reset output structure not incrementing scalers for dummy bunches + void assignTriggerBits(int ibc, uint16_t bc, uint32_t orbit, bool is_dummy); /// Assign trigger bits + void insertLastBunch(int ibc, uint32_t orbit); /// Insert an empty bunch at last position in orbit + void convertDigits(int ibc); /// Convert digits into raw data + void writeDigits(); /// Writes raw data to file + std::vector<o2::zdc::BCData> mzdcBCData, *mzdcBCDataPtr = &mzdcBCData; + std::vector<o2::zdc::ChannelData> mzdcChData, *mzdcChDataPtr = &mzdcChData; + std::vector<o2::zdc::OrbitData> mzdcPedData, *mzdcPedDataPtr = &mzdcPedData; + int mNbc = 0; + BCData mBCD; + EventData mZDC; /// Output structure + bool mIsContinuous = true; /// Continuous (self-triggered) or externally-triggered readout + bool mOutputPerLink = false; /// Split output + const ModuleConfig* mModuleConfig = nullptr; /// Trigger/readout configuration object + const SimCondition* mSimCondition = nullptr; /// Pedestal/noise configuration object + uint16_t mScalers[NModules][NChPerModule] = {0}; /// ZDC orbit scalers + uint32_t mLastOrbit = 0; /// Last processed orbit + uint32_t mTriggerMask = 0; /// Trigger mask from ModuleConfig + std::string mPrintTriggerMask = ""; /// Nice printout of trigger mask + int32_t mNEmpty = -1; /// Number of clean empty bunches for pedestal evaluation + std::array<uint16_t, o2::constants::lhc::LHCMaxBunches> mEmpty = {0}; /// Clean empty bunches along orbit + uint32_t mLastNEmpty = 0; /// Last number of empty bunches used + double mSumPed[NModules][NChPerModule] = {0}; /// Pedestal integrated on clean empty bunches + uint16_t mPed[NModules][NChPerModule] = {0}; /// Current pedestal + std::string mFileFor = "all"; /// Output file splitting + std::string mFLP = "alio2-cr1-flp181"; /// FLP assigned to ZDC + o2::raw::RawFileWriter mWriter{"ZDC"}; + uint32_t mLinkID = 0; + uint16_t mCruID = 0; + uint16_t mFLPID = 0; + uint32_t mEndPointID = 0; + + int mVerbosity = 0; + + ///////////////////////////////////////////////// + ClassDefNV(Digits2Raw, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/Hit.h b/Detectors/ZDC/simulation/include/ZDCSimulation/Hit.h deleted file mode 100644 index 9df0246c5f5db..0000000000000 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/Hit.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Hit.h -/// \brief Definition of the ZDC Hit class - -#ifndef ALICEO2_ZDC_HIT_H_ -#define ALICEO2_ZDC_HIT_H_ - -#include "SimulationDataFormat/BaseHits.h" // for BasicXYZEHit -#include "CommonUtils/ShmAllocator.h" - -namespace o2 -{ -namespace zdc -{ - -class Hit : public o2::BasicXYZEHit<Float_t, Float_t> -{ - - public: - // Default constructor - Hit() = default; - - /// Class Constructor - /// \param trackID Index of MCTrack - /// \param detID Detector ID - /// \param parent mother of the track - /// \param sflag true if it is a secondary - /// \param primaryEnergy energy of the primary [GeV] - /// \param detID detector ID (1-ZNA, 2-ZPA, 3-ZEM, 4-ZNC, 5-ZPC) - /// \param sectorID sector ID - /// \param pos track position - /// \param mom track momentum - /// \param tof track TOF - /// \param xImpact x,y,z of the impact of the 1st particle - /// \param energyloss deposited energy - /// \param nphePMC light output on common PMT - /// \param nphePMQ light output on sector PMT - Hit(int trackID, int parent, Bool_t sFlag, Float_t primaryEnergy, Int_t detID, Int_t sectorID, - math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, Float_t energyloss, Int_t nphePMC, - Int_t nphePMQ); - - void setPMCLightYield(float val) { mNphePMC = val; } - void setPMQLightYield(float val) { mNphePMQ = val; } - void setNoNumContributingSteps(int val) { mNoContributingSteps = val; } - - int getParentID() const { return mParentID; } - int getSector() const { return mSectorID; } - float getPMCLightYield() const { return mNphePMC; } - float getPMQLightYield() const { return mNphePMQ; } - int getNumContributingSteps() const { return mNoContributingSteps; } - - private: - Int_t mParentID; - Bool_t mSecFlag; - Float_t mPrimaryEnergy; - Int_t mNoContributingSteps = 1; - Int_t mSectorID; - math_utils::Vector3D<float> mMomentum; - math_utils::Vector3D<float> mXImpact; - Int_t mNphePMC; - Int_t mNphePMQ; - - ClassDefNV(Hit, 1); -}; - -inline Hit::Hit(int trackID, int parent, Bool_t sFlag, Float_t primaryEnergy, Int_t detID, Int_t sectorID, - math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, Float_t energyloss, - Int_t nphePMC, Int_t nphePMQ) - : BasicXYZEHit(pos.X(), pos.Y(), pos.Z(), tof, energyloss, trackID, detID), - mParentID(parent), - mSecFlag(sFlag), - mPrimaryEnergy(primaryEnergy), - mSectorID(sectorID), - mMomentum(mom.X(), mom.Y(), mom.Z()), - mXImpact(xImpact), - mNphePMC(nphePMC), - mNphePMQ(nphePMQ) -{ -} -} // namespace zdc -} // namespace o2 - -#ifdef USESHM -namespace std -{ -template <> -class allocator<o2::zdc::Hit> : public o2::utils::ShmAllocator<o2::zdc::Hit> -{ -}; -} // namespace std - -#endif - -#endif diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/MCLabel.h b/Detectors/ZDC/simulation/include/ZDCSimulation/MCLabel.h deleted file mode 100644 index 6ec251aec6b2a..0000000000000 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/MCLabel.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// Declaration of a transient MC label class for ZDC - -#ifndef ALICEO2_ZDC_MCLABEL_H_ -#define ALICEO2_ZDC_MCLABEL_H_ - -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace zdc -{ -class MCLabel : public o2::MCCompLabel -{ - private: - Int_t mChannel = -1; - - public: - MCLabel() = default; - MCLabel(Int_t trackID, Int_t eventID, Int_t srcID, Int_t chID) - : o2::MCCompLabel(trackID, eventID, srcID, false), mChannel(chID) {} - - Int_t getChannel() const { return mChannel; } - - ClassDefNV(MCLabel, 1); -}; -} // namespace zdc -} // namespace o2 - -#endif diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/SimCondition.h b/Detectors/ZDC/simulation/include/ZDCSimulation/SimCondition.h index 3b53d0fee32a1..5daf69c395a53 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/SimCondition.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/SimCondition.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/SpatialPhotonResponse.h b/Detectors/ZDC/simulation/include/ZDCSimulation/SpatialPhotonResponse.h index 735d474a68ec0..19b37fc62ff3b 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/SpatialPhotonResponse.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/SpatialPhotonResponse.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h b/Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h index 5866096476387..9c46629ffb75f 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/src/Detector.cxx b/Detectors/ZDC/simulation/src/Detector.cxx index 4b872f55346db..399a55e7cecd5 100644 --- a/Detectors/ZDC/simulation/src/Detector.cxx +++ b/Detectors/ZDC/simulation/src/Detector.cxx @@ -1,21 +1,22 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // FairRoot includes -#include "FairLogger.h" // for LOG, LOG_IF +#include "Framework/Logger.h" #include "FairRootManager.h" // for FairRootManager #include "FairVolume.h" // for FairVolume #include "DetectorsBase/MaterialManager.h" #include "SimulationDataFormat/Stack.h" #include "ZDCSimulation/Detector.h" -#include "ZDCSimulation/Hit.h" +#include "DataFormatsZDC/Hit.h" #include "TMath.h" #include "TGeoManager.h" // for TGeoManager, gGeoManager @@ -124,8 +125,8 @@ void Detector::InitializeO2Detector() // check a few values to test correctness of reading from file light22620362207s /*assert(std::abs(mLightTableZN[0][ZNRADIUSBINS - 1][0] - 1.39742) < 1.E-4); // beta=0; radius = ZNRADIUSBINS - 1; anglebin = 2; assert(std::abs(mLightTableZN[0][ZNRADIUSBINS - 1][1] - .45017) < 1.E-4); // beta=1; radius = ZNRADIUSBINS - 1; anglebin = 2; - assert(std::abs(mLightTableZN[0][0][2] - .47985) < 1.E-4); // beta=0; radius = 0; anglebin = 2; - assert(std::abs(mLightTableZN[0][0][11] - .01358) < 1.E-4); // beta=0; radius = 0; anglebin = 11; + assert(std::abs(mLightTableZN[0][0][2] - .47985) < 1.E-4); // beta=0; radius = 0; anglebin = 2; + assert(std::abs(mLightTableZN[0][0][11] - .01358) < 1.E-4); // beta=0; radius = 0; anglebin = 11; */ //ZP case @@ -288,7 +289,7 @@ Bool_t Detector::ProcessHits(FairVolume* v) { // Method called from MC stepping for the sensitive volumes TString volname = fMC->CurrentVolName(); - Float_t x[3] = {0., 0., 0.}; + float x[3] = {0., 0., 0.}; fMC->TrackPosition(x[0], x[1], x[2]); // determine detectorID and sectorID @@ -304,7 +305,7 @@ Bool_t Detector::ProcessHits(FairVolume* v) int volID, copy; volID = fMC->CurrentVolID(copy); //printf("\t ---> track %d in vol. %d %d (volID %d) mother %d \n", - //trackn, detector, sector, volID, stack->GetCurrentTrack()->GetMother(0)); + //trackn, detector, sector, volID, stack->GetCurrentTrack()->GetMother(0)); // If the particle is in a ZN or ZP fiber connected to the common PMT // then the assigned sector is 0 (PMC) NB-> does not work for ZEM @@ -320,45 +321,45 @@ Bool_t Detector::ProcessHits(FairVolume* v) return false; } - Float_t p[3] = {0., 0., 0.}; - Float_t trackenergy = 0.; + float p[3] = {0., 0., 0.}; + float trackenergy = 0.; fMC->TrackMomentum(p[0], p[1], p[2], trackenergy); - Float_t eDep = fMC->Edep(); + float eDep = fMC->Edep(); int pdgCode = fMC->TrackPid(); float lightoutput = 0.; auto currentMediumid = fMC->CurrentMedium(); int nphe = 0; if (((currentMediumid == mMediumPMCid) || (currentMediumid == mMediumPMQid))) { - if(eDep){ - int ibeta = 0, iangle = 0, iradius = 0; - Bool_t isLightProduced = calculateTableIndexes(ibeta, iangle, iradius); - if (isLightProduced) { - int charge = 0; - if (pdgCode < 10000) { - charge = fMC->TrackCharge(); - } else { - charge = TMath::Abs(pdgCode / 10000 - 100000); - } - - //look into the light tables if the particle is charged - if (TMath::Abs(charge) > 0) { - if (detector == 1 || detector == 4) { - iradius = std::min((int)Geometry::ZNFIBREDIAMETER, iradius); - lightoutput = charge * charge * mLightTableZN[ibeta][iangle][iradius]; - //printf(" \t ZNtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZN[ibeta][iangle][iradius], lightoutput); + if (eDep) { + int ibeta = 0, iangle = 0, iradius = 0; + Bool_t isLightProduced = calculateTableIndexes(ibeta, iangle, iradius); + if (isLightProduced) { + int charge = 0; + if (pdgCode < 10000) { + charge = fMC->TrackCharge(); } else { - iradius = std::min((int)Geometry::ZPFIBREDIAMETER, iradius); - lightoutput = charge * charge * mLightTableZP[ibeta][iangle][iradius]; - //printf(" \t ZPtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZP[ibeta][iangle][iradius], lightoutput); + charge = TMath::Abs(pdgCode / 10000 - 100000); } - if (lightoutput > 0) { - nphe = gRandom->Poisson(lightoutput); - //printf(" \t\t-> nphe %d \n", nphe); + + //look into the light tables if the particle is charged + if (TMath::Abs(charge) > 0) { + if (detector == 1 || detector == 4) { + iradius = std::min((int)Geometry::ZNFIBREDIAMETER, iradius); + lightoutput = charge * charge * mLightTableZN[ibeta][iangle][iradius]; + //printf(" \t ZNtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZN[ibeta][iangle][iradius], lightoutput); + } else { + iradius = std::min((int)Geometry::ZPFIBREDIAMETER, iradius); + lightoutput = charge * charge * mLightTableZP[ibeta][iangle][iradius]; + //printf(" \t ZPtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZP[ibeta][iangle][iradius], lightoutput); + } + if (lightoutput > 0) { + nphe = gRandom->Poisson(lightoutput); + //printf(" \t\t-> nphe %d \n", nphe); + } } } } - } } auto tof = 1.e09 * fMC->TrackTime(); //TOF in ns @@ -498,9 +499,9 @@ bool Detector::createHitsFromImage(SpatialPhotonResponse const& image, int detec } // end function //_____________________________________________________________________________ -o2::zdc::Hit* Detector::addHit(Int_t trackID, Int_t parentID, Int_t sFlag, Float_t primaryEnergy, Int_t detID, - Int_t secID, math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, Float_t tof, math_utils::Vector3D<float> xImpact, - Double_t energyloss, Int_t nphePMC, Int_t nphePMQ) +o2::zdc::Hit* Detector::addHit(int32_t trackID, int32_t parentID, int32_t sFlag, float primaryEnergy, int32_t detID, + int32_t secID, math_utils::Vector3D<float> pos, math_utils::Vector3D<float> mom, float tof, math_utils::Vector3D<float> xImpact, + double energyloss, int32_t nphePMC, int32_t nphePMQ) { LOG(DEBUG4) << "Adding hit for track " << trackID << " X (" << pos.X() << ", " << pos.Y() << ", " << pos.Z() << ") P (" << mom.X() << ", " << mom.Y() << ", " << mom.Z() << ") Ekin " @@ -513,94 +514,94 @@ o2::zdc::Hit* Detector::addHit(Int_t trackID, Int_t parentID, Int_t sFlag, Float //_____________________________________________________________________________ void Detector::createMaterials() { - Int_t ifield = 2; - Float_t fieldm = 10.0; + int32_t ifield = 2; + float fieldm = 10.0; o2::base::Detector::initFieldTrackingParams(ifield, fieldm); LOG(INFO) << "Detector::CreateMaterials >>>>> magnetic field: type " << ifield << " max " << fieldm << "\n"; // ******** MATERIAL DEFINITION ******** // --- W alloy -> ZN passive material - Float_t aW[3] = {183.85, 55.85, 58.71}; - Float_t zW[3] = {74., 26., 28.}; - Float_t wW[3] = {0.93, 0.03, 0.04}; - Float_t dW = 17.6; + float aW[3] = {183.85, 55.85, 58.71}; + float zW[3] = {74., 26., 28.}; + float wW[3] = {0.93, 0.03, 0.04}; + float dW = 17.6; // --- Brass (CuZn) -> ZP passive material - Float_t aCuZn[2] = {63.546, 65.39}; - Float_t zCuZn[2] = {29., 30.}; - Float_t wCuZn[2] = {0.63, 0.37}; - Float_t dCuZn = 8.48; + float aCuZn[2] = {63.546, 65.39}; + float zCuZn[2] = {29., 30.}; + float wCuZn[2] = {0.63, 0.37}; + float dCuZn = 8.48; // --- SiO2 -> fibres - Float_t aq[2] = {28.0855, 15.9994}; - Float_t zq[2] = {14., 8.}; - Float_t wq[2] = {1., 2.}; - Float_t dq = 2.64; + float aq[2] = {28.0855, 15.9994}; + float zq[2] = {14., 8.}; + float wq[2] = {1., 2.}; + float dq = 2.64; // --- Lead -> ZEM passive material - Float_t aPb = 207.2; - Float_t zPb = 82.; - Float_t dPb = 11.35; - Float_t radPb = 6.37 / dPb; - Float_t absPb = 199.6 / dPb; + float aPb = 207.2; + float zPb = 82.; + float dPb = 11.35; + float radPb = 6.37 / dPb; + float absPb = 199.6 / dPb; // --- Copper -> beam pipe - Float_t aCu = 63.546; - Float_t zCu = 29.; - Float_t dCu = 8.96; - Float_t radCu = 12.86 / dCu; - Float_t absCu = 137.3 / dCu; - // Int_t nCu = 1.10; + float aCu = 63.546; + float zCu = 29.; + float dCu = 8.96; + float radCu = 12.86 / dCu; + float absCu = 137.3 / dCu; + // int32_t nCu = 1.10; // --- Iron -> beam pipe - Float_t aFe = 55.845; - Float_t zFe = 26.; - Float_t dFe = 7.874; - Float_t radFe = 13.84 / dFe; - Float_t absFe = 132.1 / dFe; + float aFe = 55.845; + float zFe = 26.; + float dFe = 7.874; + float radFe = 13.84 / dFe; + float absFe = 132.1 / dFe; // --- Aluminum -> beam pipe - Float_t aAl = 26.98; - Float_t zAl = 13.; - Float_t dAl = 2.699; - Float_t radAl = 24.01 / dAl; - Float_t absAl = 107.2 / dAl; + float aAl = 26.98; + float zAl = 13.; + float dAl = 2.699; + float radAl = 24.01 / dAl; + float absAl = 107.2 / dAl; // --- Carbon -> beam pipe - Float_t aCarb = 12.01; - Float_t zCarb = 6.; - Float_t dCarb = 2.265; - Float_t radCarb = 18.8; - Float_t absCarb = 49.9; + float aCarb = 12.01; + float zCarb = 6.; + float dCarb = 2.265; + float radCarb = 18.8; + float absCarb = 49.9; // --- Residual gas -> inside beam pipe - Float_t aResGas[3] = {1.008, 12.0107, 15.9994}; - Float_t zResGas[3] = {1., 6., 8.}; - Float_t wResGas[3] = {0.28, 0.28, 0.44}; - Float_t dResGas = 3.2E-14; + float aResGas[3] = {1.008, 12.0107, 15.9994}; + float zResGas[3] = {1., 6., 8.}; + float wResGas[3] = {0.28, 0.28, 0.44}; + float dResGas = 3.2E-14; // --- Air - Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; - Float_t zAir[4] = {6., 7., 8., 18.}; - Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; - Float_t dAir = 1.20479E-3; + float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; + float zAir[4] = {6., 7., 8., 18.}; + float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; + float dAir = 1.20479E-3; // ******** TRACKING MEDIA PARAMETERS ******** - Int_t notactiveMed = 0, sensMed = 1; // sensitive or not sensitive medium + int32_t notactiveMed = 0, sensMed = 1; // sensitive or not sensitive medium // field integration 0 no field -1 user in guswim 1 Runge Kutta 2 helix 3 const field along z - Int_t inofld = 0; // Max. field value (no field) - Int_t ifld = 2; //TODO: ????CHECK!!!! secondo me va -1!!!!! - Float_t nofieldm = 0.; - - Float_t maxnofld = 0.; // max field value (no field) - Float_t maxfld = 45.; // max field value (with field) - Float_t tmaxnofd = 0.; // max deflection angle due to magnetic field in one step - Float_t tmaxfd = 0.1; // max deflection angle due to magnetic field in one step - Float_t deemax = -1.; // maximum fractional energy loss in one step 0<deemax<=1 - Float_t epsil = 0.001; // tracking precision [cm] - Float_t stemax = 1.; // max step allowed [cm] ????CHECK!!!! - Float_t stmin = 0.01; // minimum step due to continuous processes [cm] (negative value: choose it automatically) ????CHECK!!!! 0.01 in aliroot + int32_t inofld = 0; // Max. field value (no field) + int32_t ifld = 2; //TODO: ????CHECK!!!! secondo me va -1!!!!! + float nofieldm = 0.; + + float maxnofld = 0.; // max field value (no field) + float maxfld = 45.; // max field value (with field) + float tmaxnofd = 0.; // max deflection angle due to magnetic field in one step + float tmaxfd = 0.1; // max deflection angle due to magnetic field in one step + float deemax = -1.; // maximum fractional energy loss in one step 0<deemax<=1 + float epsil = 0.001; // tracking precision [cm] + float stemax = 1.; // max step allowed [cm] ????CHECK!!!! + float stmin = 0.01; // minimum step due to continuous processes [cm] (negative value: choose it automatically) ????CHECK!!!! 0.01 in aliroot // ******** MATERIAL DEFINITION ******** Mixture(0, "Walloy$", aW, zW, dW, 3, wW); @@ -635,12 +636,12 @@ void Detector::createMaterials() void Detector::createAsideBeamLine() { - Double_t tubpar[3] = {0., 0., 0}; - Float_t boxpar[3] = {0., 0., 0}; - Double_t tubspar[5] = {0., 0., 0., 0., 0.}; - Double_t conpar[15] = {0.}; // all elements will be 0 + double tubpar[3] = {0., 0., 0}; + float boxpar[3] = {0., 0., 0}; + double tubspar[5] = {0., 0., 0., 0., 0.}; + double conpar[15] = {0.}; // all elements will be 0 - Float_t zA = 1910.4; + float zA = 1910.4; conpar[0] = 0.; conpar[1] = 360.; @@ -810,9 +811,9 @@ void Detector::createAsideBeamLine() zA += 2. * conpar[0]; // Upper section : one single phi segment of a tube - // 5 parameters for tubs: inner radius = 0., - // outer radius = 7. cm, half length = 50 cm - // phi1 = 0., phi2 = 180. + // 5 parameters for tubs: inner radius = 0., + // outer radius = 7. cm, half length = 50 cm + // phi1 = 0., phi2 = 180. tubspar[0] = 0.0 / 2.; tubspar[1] = 14.0 / 2.; tubspar[2] = 100.0 / 2.; @@ -899,7 +900,7 @@ void Detector::createAsideBeamLine() zA += 2. * conpar[0]; //-- rotation matrices for the tilted cone after the TDI to recenter vacuum chamber - Int_t irotpipe3, irotpipe4, irotpipe5; + int32_t irotpipe3, irotpipe4, irotpipe5; double rang3[6] = {90. - 1.8934, 0., 90., 90., 1.8934, 180.}; double rang4[6] = {90. - 3.8, 0., 90., 90., 3.8, 180.}; double rang5[6] = {90. + 9.8, 0., 90., 90., 9.8, 0.}; @@ -994,7 +995,7 @@ void Detector::createAsideBeamLine() // The following tube ID 212.7 mm // represents VMBGA (400 mm) + VCDWE (300 mm) + VMBGA (400 mm) + - // BTVTS (600 mm) + VMLGB (400 mm) + // BTVTS (600 mm) + VMLGB (400 mm) tubpar[0] = 21.27 / 2.; tubpar[1] = 21.87 / 2.; tubpar[2] = 210.0 / 2.; @@ -1016,7 +1017,7 @@ void Detector::createAsideBeamLine() zA += 2. * conpar[0] + 0.37 + 1.35; // The following tube ID 797 mm represents the second part of VCTCC (4272 mm) + - // 4 x VCDGA (4 x 4272 mm) + the first part of VCTCR (850 mm) + // 4 x VCDGA (4 x 4272 mm) + the first part of VCTCR (850 mm) tubpar[0] = 79.7 / 2.; tubpar[1] = 81.3 / 2.; tubpar[2] = (2221. - 136.) / 2.; @@ -1194,7 +1195,7 @@ void Detector::createAsideBeamLine() rotMatrix4->RegisterYourself(); //-- rotation matrices for the legs - Int_t irotpipe1, irotpipe2; + int32_t irotpipe1, irotpipe2; double rang1[6] = {90. - 1.0027, 0., 90., 90., 1.0027, 180.}; double rang2[6] = {90. + 1.0027, 0., 90., 90., 1.0027, 0.}; TVirtualMC::GetMC()->Matrix(irotpipe1, rang1[0], rang1[1], rang1[2], rang1[3], rang1[4], rang1[5]); @@ -1228,7 +1229,7 @@ void Detector::createAsideBeamLine() pQALext->SetLineColor(kBlue); pQALext->SetVisLeaves(kTRUE); // - TGeoTranslation* tr1 = new TGeoTranslation(0., 0., (Double_t)conpar[0] + 0.95 + zA); + TGeoTranslation* tr1 = new TGeoTranslation(0., 0., (double)conpar[0] + 0.95 + zA); pZDCA->AddNode(pQALext, 1, tr1); // Inner trousers TGeoCompositeShape* pIntTrousers = new TGeoCompositeShape("intTrousers", "QALint:ZDC_c1+QALint:ZDC_c2"); @@ -1269,7 +1270,7 @@ void Detector::createAsideBeamLine() TVirtualMC::GetMC()->Gsvolu("QA29", "TUBE", getMediumID(kFe), tubpar, 3); TVirtualMC::GetMC()->Gspos("QA29", 1, "ZDCA", -16.5 / 2., 0., tubpar[2] + zA, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("QA29", 2, "ZDCA", 16.5 / 2., 0., tubpar[2] + zA, 0, "ONLY"); - //printf(" QA29 TUBE from z = %1.2f to z= %1.2f (separate pipes)\n",zA,2*tubpar[2]+zA); + //printf("QA29 TUBE from z = %1.2f to z= %1.2f (separate pipes)\n",zA,2*tubpar[2]+zA); zA += 2. * tubpar[2]; @@ -1280,22 +1281,22 @@ void Detector::createAsideBeamLine() boxpar[2] = mLumiLength / 2.; TVirtualMC::GetMC()->Gsvolu("QLUA", "BOX ", getMediumID(kCuLumi), boxpar, 3); TVirtualMC::GetMC()->Gspos("QLUA", 1, "ZDCA", 0., 0., Geometry::ZNAPOSITION[1] /*fPosZNA[2]*/ - 66. - boxpar[2], 0, "ONLY"); - LOG(DEBUG) << " A-side luminometer positioned in front of ZNA\n"; + LOG(DEBUG) << "A-side luminometer positioned in front of ZNA\n"; } } //_____________________________________________________________________________ void Detector::createCsideBeamLine() { - Double_t tubpar[3] = {0., 0., 0}; - Float_t boxpar[3] = {0., 0., 0}; - Double_t tubspar[5] = {0., 0., 0., 0., 0.}; - Double_t conpar[15] = { + double tubpar[3] = {0., 0., 0}; + float boxpar[3] = {0., 0., 0}; + double tubspar[5] = {0., 0., 0., 0., 0.}; + double conpar[15] = { 0., }; - Float_t zC = 1947.2; - Float_t zCompensator = 1974.; + float zC = 1947.2; + float zCompensator = 1974.; conpar[0] = 0.; conpar[1] = 360.; @@ -1327,7 +1328,7 @@ void Detector::createCsideBeamLine() //-- BEAM PIPE from the end of D1 to the beginning of D2 //-- FROM MAGNETIC BEGINNING OF D1 TO MAGNETIC END OF D1 - //-- Cylindrical pipe (r = 3.47) + conical flare + //-- Cylindrical pipe (r = 3.47) + conical flare tubpar[0] = 6.94 / 2.; tubpar[1] = 7.34 / 2.; tubpar[2] = (6909.8 - zC) / 2.; @@ -1363,7 +1364,7 @@ void Detector::createCsideBeamLine() zC += conpar[0] * 2.; // 2nd section of VCTCQ+VAMTF+TCLIA+VAMTF+1st part of VCTCP - Float_t totLength1 = 160.8 + 78. + 148. + 78. + 9.3; + float totLength1 = 160.8 + 78. + 148. + 78. + 9.3; // tubpar[0] = 18.6 / 2.; tubpar[1] = 7.6 / 2.; @@ -1415,7 +1416,7 @@ void Detector::createCsideBeamLine() zC += conpar[0] * 2.; // 3rd section of VCTCP+VCDWC+VMLGB - Float_t totLenght2 = (8373.3 - zC); + float totLenght2 = (8373.3 - zC); tubpar[0] = 21.2 / 2.; tubpar[1] = 21.9 / 2.; tubpar[2] = totLenght2 / 2.; @@ -1570,16 +1571,16 @@ void Detector::createCsideBeamLine() // -------------------------------------------------------- // RECOMBINATION CHAMBER // TRANSFORMATION MATRICES - Double_t dx = -3.970000; - Double_t dy = 0.000000; - Double_t dz = 0.0; + double dx = -3.970000; + double dy = 0.000000; + double dz = 0.0; // Rotation: - Double_t thx = 84.989100; - Double_t phx = 180.000000; - Double_t thy = 90.000000; - Double_t phy = 90.000000; - Double_t thz = 185.010900; - Double_t phz = 0.000000; + double thx = 84.989100; + double phx = 180.000000; + double thy = 90.000000; + double phy = 90.000000; + double thz = 185.010900; + double phz = 0.000000; TGeoRotation* rotMatrix1c = new TGeoRotation("c", thx, phx, thy, phy, thz, phz); // Combi transformation: dx = -3.970000; @@ -1631,7 +1632,7 @@ void Detector::createCsideBeamLine() pQCLext->SetLineColor(kAzure); pQCLext->SetVisLeaves(kTRUE); // - TGeoTranslation* tr1c = new TGeoTranslation(0., 0., (Double_t)-conpar[0] - 0.95 - zC); + TGeoTranslation* tr1c = new TGeoTranslation(0., 0., (double)-conpar[0] - 0.95 - zC); // pZDCC->AddNode(pQCLext, 1, tr1c); // Inner trousers @@ -1644,7 +1645,7 @@ void Detector::createCsideBeamLine() pQCLext->AddNode(pQCLint, 1); zC += 90.1; - Double_t offset = 0.5; + double offset = 0.5; zC = zC + offset; // second section : 2 tubes (ID = 54. OD = 58.) @@ -1658,7 +1659,7 @@ void Detector::createCsideBeamLine() zC += 2. * tubpar[2]; //-- rotation matrices for the legs - Int_t irotpipe1, irotpipe2; + int32_t irotpipe1, irotpipe2; double rang1[6] = {90. - 1.0027, 0., 90., 90., 1.0027, 180.}; double rang2[6] = {90. + 1.0027, 0., 90., 90., 1.0027, 0.}; TVirtualMC::GetMC()->Matrix(irotpipe1, rang1[0], rang1[1], rang1[2], rang1[3], rang1[4], rang1[5]); @@ -1693,15 +1694,15 @@ void Detector::createCsideBeamLine() boxpar[2] = mLumiLength / 2.; // FIX IT!!!!!!!!!!!!!!!!!!!!!!!! TVirtualMC::GetMC()->Gsvolu("QLUC", "BOX ", getMediumID(kCuLumi), boxpar, 3); TVirtualMC::GetMC()->Gspos("QLUC", 1, "ZDCC", 0., 0., Geometry::ZNCPOSITION[1] + 66. + boxpar[2], 0, "ONLY"); - LOG(DEBUG) << " C-side luminometer positioned in front of ZNC\n"; + LOG(DEBUG) << "C-side luminometer positioned in front of ZNC\n"; } } //_____________________________________________________________________________ void Detector::createMagnets() { - Float_t tubpar[3] = {0., 0., 0.}; - Float_t boxpar[3] = {0., 0., 0.}; + float tubpar[3] = {0., 0., 0.}; + float boxpar[3] = {0., 0., 0.}; // Parameters from magnet DEFINITION double zCompensatorField = 1972.5; double zITField = 2296.5; @@ -1709,7 +1710,7 @@ void Detector::createMagnets() double zD2Field = 12167.8; // *************************************************************** - // SIDE C + //SIDE C // *************************************************************** // -- COMPENSATOR DIPOLE (MBXW) // -- GAP (VACUUM WITH MAGNETIC FIELD) @@ -1811,7 +1812,7 @@ void Detector::createMagnets() TVirtualMC::GetMC()->Gspos("MD2 ", 2, "YD2 ", 9.4, 0., 0., 0, "ONLY"); // *************************************************************** - // SIDE A + //SIDE A // *************************************************************** // COMPENSATOR DIPOLE (MCBWA) (2nd compensator) @@ -1974,7 +1975,7 @@ void Detector::createDetectors() double znSupportWallsud[3] = {3.52, 1., 50.}; //Top and bottom walls double znSupportWallside[3] = {0.4, 5.52, 50.}; //Side walls - Float_t dimPb[6], dimVoid[6]; + float dimPb[6], dimVoid[6]; // ------------------------------------------------------------------------------- //--> Neutron calorimeter (ZN) @@ -2007,8 +2008,8 @@ void Detector::createDetectors() TVirtualMC::GetMC()->Gsdvn("ZNST", "ZNSL", Geometry::ZNDIVISION[0], 1); // Sticks // --- Position the empty grooves in the sticks (4 grooves per stick) - Float_t dx = Geometry::ZNDIMENSION[0] / Geometry::ZNDIVISION[0] / 4.; - Float_t dy = Geometry::ZNDIMENSION[1] / Geometry::ZNDIVISION[1] / 4.; + float dx = Geometry::ZNDIMENSION[0] / Geometry::ZNDIVISION[0] / 4.; + float dy = Geometry::ZNDIMENSION[1] / Geometry::ZNDIVISION[1] / 4.; TVirtualMC::GetMC()->Gspos("ZNG1", 1, "ZNST", 0. - dx, 0. + dy, 0., 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZNG2", 1, "ZNST", 0. + dx, 0. + dy, 0., 0, "ONLY"); @@ -2023,7 +2024,7 @@ void Detector::createDetectors() // --- Position the neutron calorimeter in ZDC // -- Rotation of C side ZN - Int_t irotznc; + int32_t irotznc; double rangznc[6] = {90., 180., 90., 90., 180., 0.}; TVirtualMC::GetMC()->Matrix(irotznc, rangznc[0], rangznc[1], rangznc[2], rangznc[3], rangznc[4], rangznc[5]); // @@ -2198,7 +2199,7 @@ void Detector::createDetectors() // ------------------------------------------------------------------------------- // -> EM calorimeter (ZEM) - Int_t irotzem1, irotzem2; + int32_t irotzem1, irotzem2; double rangzem1[6] = {0., 0., 90., 90., -90., 0.}; double rangzem2[6] = {180., 0., 90., 45. + 90., 90., 45.}; TVirtualMC::GetMC()->Matrix(irotzem1, rangzem1[0], rangzem1[1], rangzem1[2], rangzem1[3], rangzem1[4], rangzem1[5]); @@ -2242,33 +2243,33 @@ void Detector::createDetectors() TVirtualMC::GetMC()->Gspos("ZEMF", 1, "ZES1", 0., 0., 0., irotzem2, "ONLY"); // --- Positioning the vacuum slice into the tranche - //Float_t displFib = fDimZEM[1]/fDivZEM[0]; + //float displFib = fDimZEM[1]/fDivZEM[0]; TVirtualMC::GetMC()->Gspos("ZEV0", 1, "ZETR", -zemVoidLayer[0], 0., 0., 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEV1", 1, "ZETR", -zemVoidLayer[0] + zemPbSlice[0], 0., 0., 0, "ONLY"); // --- Positioning the ZEM into the ZDC - rotation for 90 degrees // NB -> ZEM is positioned in cave volume - const Float_t z0 = 1313.3475; // center of caveRB24 mother volume + const float z0 = 1313.3475; // center of caveRB24 mother volume TVirtualMC::GetMC()->Gspos("ZEM ", 1, "caveRB24", -Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + Geometry::ZEMDIMENSION[0] - z0, irotzem1, "ONLY"); // Second EM ZDC (same side w.r.t. IP, just on the other side w.r.t. beam pipe) TVirtualMC::GetMC()->Gspos("ZEM ", 2, "caveRB24", Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + Geometry::ZEMDIMENSION[0] - z0, irotzem1, "ONLY"); // --- Adding last slice at the end of the EM calorimeter - Float_t zLastSlice = Geometry::ZEMPOSITION[2] + zemPbSlice[0] + 2 * Geometry::ZEMDIMENSION[0]; + float zLastSlice = Geometry::ZEMPOSITION[2] + zemPbSlice[0] + 2 * Geometry::ZEMDIMENSION[0]; TVirtualMC::GetMC()->Gspos("ZEL2", 1, "caveRB24", Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], zLastSlice - z0, irotzem1, "ONLY"); // ------------------------------------------------------------------------------- // -> ZEM supports // Platform and supports - Float_t ybox = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] + zemSupportBox[1]; - Float_t zSupport = Geometry::ZEMPOSITION[2] - 3.5; //to take into account the titlted front face - Float_t zbox = zSupport + zemSupportBox[2]; + float ybox = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] + zemSupportBox[1]; + float zSupport = Geometry::ZEMPOSITION[2] - 3.5; //to take into account the titlted front face + float zbox = zSupport + zemSupportBox[2]; // Bridge TVirtualMC::GetMC()->Gsvolu("ZESH", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupport1), 3); - Float_t ybridge = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] - 5. - zemSupport1[1]; + float ybridge = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] - 5. - zemSupport1[1]; TVirtualMC::GetMC()->Gspos("ZESH", 1, "caveRB24", Geometry::ZEMPOSITION[0], ybridge, zbox - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZESH", 2, "caveRB24", -Geometry::ZEMPOSITION[0], ybridge, zbox - z0, 0, "ONLY"); // @@ -2280,7 +2281,7 @@ void Detector::createDetectors() // Table TVirtualMC::GetMC()->Gsvolu("ZETA", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupportTable), 3); - Float_t ytable = ybridge - zemSupport1[1] - zemSupportTable[1]; + float ytable = ybridge - zemSupport1[1] - zemSupportTable[1]; TVirtualMC::GetMC()->Gspos("ZETA", 1, "caveRB24", 0.0, ytable, zbox - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZETA", 2, "caveRB24", 0.0, ytable - 13. + 2. * zemSupportTable[1], zbox - z0, 0, "ONLY"); @@ -2301,8 +2302,8 @@ void Detector::createDetectors() TVirtualMC::GetMC()->Gsvolu("ZEW3", "BOX ", getMediumID(kAl), const_cast<double*>(zemWallVbkw), 3); TVirtualMC::GetMC()->Gsvolu("ZEW4", "BOX ", getMediumID(kFe), const_cast<double*>(zemWallVside), 3); // - Float_t yh1 = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2 * zemSupport3[1] - zemWallH[1]; - Float_t zh1 = zSupport + zemWallH[2]; + float yh1 = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2 * zemSupport3[1] - zemWallH[1]; + float zh1 = zSupport + zemWallH[2]; TVirtualMC::GetMC()->Gspos("ZEW1", 1, "caveRB24", Geometry::ZEMPOSITION[0], yh1, zh1 - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEW1", 2, "caveRB24", Geometry::ZEMPOSITION[0], yh1 + 2 * zemSupportBox[1], zh1 - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEW1", 3, "caveRB24", -Geometry::ZEMPOSITION[0], yh1, zh1 - z0, 0, "ONLY"); @@ -2313,8 +2314,8 @@ void Detector::createDetectors() TVirtualMC::GetMC()->Gspos("ZEW2", 2, "caveRB24", -Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport - zemWallVfwd[2] - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEW3", 2, "caveRB24", -Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport + 2 * zemWallH[2] - z0, 0, "ONLY"); // - Float_t xl1 = Geometry::ZEMPOSITION[0] - Geometry::ZEMDIMENSION[2] - 2. * zemSupport4[2] - zemWallVside[0]; - Float_t xl2 = Geometry::ZEMPOSITION[0] + Geometry::ZEMDIMENSION[2] + 2. * zemSupport4[2] + zemWallVside[0]; + float xl1 = Geometry::ZEMPOSITION[0] - Geometry::ZEMDIMENSION[2] - 2. * zemSupport4[2] - zemWallVside[0]; + float xl2 = Geometry::ZEMPOSITION[0] + Geometry::ZEMDIMENSION[2] + 2. * zemSupport4[2] + zemWallVside[0]; TVirtualMC::GetMC()->Gspos("ZEW4", 1, "caveRB24", xl1, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEW4", 2, "caveRB24", xl2, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY"); TVirtualMC::GetMC()->Gspos("ZEW4", 3, "caveRB24", -xl1, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY"); diff --git a/Detectors/ZDC/simulation/src/Digitizer.cxx b/Detectors/ZDC/simulation/src/Digitizer.cxx index ae03970780442..c9b86506538d2 100644 --- a/Detectors/ZDC/simulation/src/Digitizer.cxx +++ b/Detectors/ZDC/simulation/src/Digitizer.cxx @@ -1,29 +1,32 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "CommonConstants/LHCConstants.h" #include "CCDB/BasicCCDBManager.h" #include "CCDB/CCDBTimeStampUtils.h" +#include "Framework/Logger.h" #include "ZDCSimulation/Digitizer.h" -#include "ZDCSimulation/Hit.h" #include "ZDCSimulation/SimCondition.h" #include "ZDCSimulation/ZDCSimParam.h" #include <TRandom.h> -#include <FairLogger.h> using namespace o2::zdc; +//______________________________________________________________________________ Digitizer::BCCache::BCCache() { memset(&data, 0, NChannels * sizeof(ChannelBCDataF)); } +//______________________________________________________________________________ Digitizer::ModuleConfAux::ModuleConfAux(const Module& md) : id(md.id) { if (md.id < 0 || md.id >= NModules) { @@ -42,6 +45,7 @@ Digitizer::ModuleConfAux::ModuleConfAux(const Module& md) : id(md.id) } } +//______________________________________________________________________________ // this will process hits and fill the digit vector with digits which are finalized void Digitizer::process(const std::vector<o2::zdc::Hit>& hits, std::vector<o2::zdc::BCData>& digitsBC, @@ -61,8 +65,9 @@ void Digitizer::process(const std::vector<o2::zdc::Hit>& hits, int detID = hit.GetDetectorID(); int secID = hit.getSector(); float nPhotons; - if (detID == ZEM) { // TODO: ZEMCh1 and Common are both 0, could skip the check for detID - nPhotons = (secID == ZEMCh1) ? hit.getPMCLightYield() : hit.getPMQLightYield(); + if (detID == ZEM) { + // ZEM calorimeters have only common PM + nPhotons = hit.getPMCLightYield(); } else { nPhotons = (secID == Common) ? hit.getPMCLightYield() : hit.getPMQLightYield(); } @@ -98,6 +103,7 @@ void Digitizer::process(const std::vector<o2::zdc::Hit>& hits, } } +//______________________________________________________________________________ void Digitizer::flush(std::vector<o2::zdc::BCData>& digitsBC, std::vector<o2::zdc::ChannelData>& digitsCh, o2::dataformats::MCTruthContainer<o2::zdc::MCLabel>& labels) @@ -163,6 +169,7 @@ void Digitizer::flush(std::vector<o2::zdc::BCData>& digitsBC, mCache.erase(mCache.begin(), mCache.end()); } +//______________________________________________________________________________ void Digitizer::generatePedestal() { for (int idet : {ZNA, ZPA, ZNC, ZPC}) { @@ -179,6 +186,7 @@ void Digitizer::generatePedestal() mPedestalBLFluct[IdZEM2] = gRandom->Gaus(0, mSimCondition->channels[IdZEM2].pedestalFluct); } +//______________________________________________________________________________ void Digitizer::digitizeBC(BCCache& bc) { auto& bcdata = bc.data; @@ -230,10 +238,10 @@ void Digitizer::digitizeBC(BCCache& bc) } } } - bc.digitized = true; } +//______________________________________________________________________________ bool Digitizer::triggerBC(int ibc) { // check trigger for the cached BC in the position ibc @@ -250,8 +258,9 @@ bool Digitizer::triggerBC(int ibc) int id = trigCh.id; if (id >= 0 && id < NChannels) { auto ipos = NChPerModule * md.id + ic; + int last1 = trigCh.last + 2; bool okPrev = false; - int last1 = trigCh.last + 2; // To be modified. The new requirement is 3 consecutive samples +#ifdef ZDC_DOUBLE_TRIGGER_CONDITION // look for 2 consecutive bins (the 1st one spanning trigCh.first : trigCh.last range) so that // signal[bin]-signal[bin+trigCh.shift] > trigCh.threshold for (int ib = trigCh.first; ib < last1; ib++) { // ib may be negative, so we shift by offs and look in the ADC cache @@ -268,6 +277,26 @@ bool Digitizer::triggerBC(int ibc) } okPrev = ok; } +#else + bool okPPrev = false; + // look for 3 consecutive bins (the 1st one spanning trigCh.first : trigCh.last range) so that + // signal[bin]-signal[bin+trigCh.shift] > trigCh.threshold + for (int ib = trigCh.first - 1; ib < last1; ib++) { // ib may be negative, so we shift by offs and look in the ADC cache + int binF, bcFidx = ibc + binHelper(ib, binF); + int binL, bcLidx = ibc + binHelper(ib + trigCh.shift, binL); + const auto& bcF = (bcFidx < 0 || !mFastCache[bcFidx]) ? mDummyBC : *mFastCache[bcFidx]; + const auto& bcL = (bcLidx < 0 || !mFastCache[bcLidx]) ? mDummyBC : *mFastCache[bcLidx]; + bool ok = bcF.digi[ipos][binF] - bcL.digi[ipos][binL] > trigCh.threshold; + if (ok && okPrev && okPPrev) { // trigger ok! + bcCached.trigChanMask |= 0x1 << (NChPerModule * md.id + ic); // register trigger mask + LOG(DEBUG) << bcF.digi[ipos][binF] << " - " << bcL.digi[ipos][binL] << " = " << bcF.digi[ipos][binF] - bcL.digi[ipos][binL] << " > " << trigCh.threshold; + LOG(DEBUG) << " hit [" << md.id << "," << ic << "] " << int(id) << "(" << ChannelNames[id] << ") => " << bcCached.trigChanMask; + break; + } + okPPrev = okPrev; + okPrev = ok; + } +#endif } } } @@ -293,6 +322,7 @@ bool Digitizer::triggerBC(int ibc) return bcCached.trigChanMask; } +//______________________________________________________________________________ void Digitizer::storeBC(const BCCache& bc, uint32_t chan2Store, std::vector<o2::zdc::BCData>& digitsBC, std::vector<o2::zdc::ChannelData>& digitsCh, o2::dataformats::MCTruthContainer<o2::zdc::MCLabel>& labels) @@ -319,13 +349,16 @@ void Digitizer::storeBC(const BCCache& bc, uint32_t chan2Store, int nBC = digitsBC.size(); digitsBC.emplace_back(first, nSto, bc, chan2Store, bc.trigChanMask, bc.extTrig); // TODO clarify if we want to store MC labels for all channels or only for stored ones - for (const auto& lbl : bc.labels) { - if (chan2Store & (0x1 << lbl.getChannel())) { - labels.addElement(nBC, lbl); + if (!mSkipMCLabels) { + for (const auto& lbl : bc.labels) { + if (chan2Store & (0x1 << lbl.getChannel())) { + labels.addElement(nBC, lbl); + } } } } +//______________________________________________________________________________ void Digitizer::phe2Sample(int nphe, int parID, double timeHit, std::array<o2::InteractionRecord, NBC2Cache> const& cachedIR, int nCachedIR, int channel) { //function to simulate the waveform from no. of photoelectrons seen in a given sample @@ -360,6 +393,7 @@ void Digitizer::phe2Sample(int nphe, int parID, double timeHit, std::array<o2::I } while (++ir < nCachedIR && !stop); } +//______________________________________________________________________________ o2::zdc::Digitizer::BCCache& Digitizer::getCreateBCCache(const o2::InteractionRecord& ir) { if (mCache.empty() || mCache.back() < ir) { @@ -388,6 +422,7 @@ o2::zdc::Digitizer::BCCache& Digitizer::getCreateBCCache(const o2::InteractionRe return mCache.front(); } +//______________________________________________________________________________ o2::zdc::Digitizer::BCCache* Digitizer::getBCCache(const o2::InteractionRecord& ir) { // get pointer on existing cache @@ -399,6 +434,7 @@ o2::zdc::Digitizer::BCCache* Digitizer::getBCCache(const o2::InteractionRecord& return nullptr; } +//______________________________________________________________________________ void Digitizer::init() { if (mCCDBServer.empty()) { @@ -412,8 +448,11 @@ void Digitizer::init() mNBCAHead = mIsContinuous ? sopt.nBCAheadCont : sopt.nBCAheadTrig; LOG(INFO) << "Initialized in " << (mIsContinuous ? "Cont" : "Trig") << " mode, " << mNBCAHead << " BCs will be stored ahead of Trigger"; + LOG(INFO) << "Trigger bit masking is " << (mMaskTriggerBits ? "ON (default)" : "OFF (debugging)"); + LOG(INFO) << "MC Labels are " << (mSkipMCLabels ? "SKIPPED" : "SAVED (default)"); } +//______________________________________________________________________________ void Digitizer::refreshCCDB() { // fetch ccdb objects. TODO: decide if this stays here or goes to the Spec @@ -437,7 +476,7 @@ void Digitizer::refreshCCDB() if (md.trigChannel[ic] || (md.trigChannelConf[ic].shift > 0 && md.trigChannelConf[ic].threshold > 0)) { const auto& trgChanConf = md.trigChannelConf[ic]; if (trgChanConf.last + trgChanConf.shift + 1 >= NTimeBinsPerBC) { - LOG(FATAL) << "Wrong trigger settings"; + LOG(ERROR) << "Wrong trigger settings"; } mTriggerConfig.emplace_back(trgChanConf); // We insert in the trigger mask only the channels that are actually triggering @@ -457,6 +496,9 @@ void Digitizer::refreshCCDB() mTrigBinMax = trgChanConf.last + trgChanConf.shift; } } + if (md.feeID[ic] < 0 || md.feeID[ic] >= NLinks) { + LOG(FATAL) << "FEEID " << md.feeID[ic] << " not in allowed range [0:" << NLinks << ")"; + } } } else { LOG(FATAL) << "Module id: " << md.id << " is out of range"; @@ -470,9 +512,12 @@ void Digitizer::refreshCCDB() LOG(INFO) << "Loaded simulation configuration for timestamp " << mTimeStamp; mSimCondition->print(); } + + setTriggerMask(); + setReadoutMask(); } -//______________________________________________________________ +//______________________________________________________________________________ void Digitizer::BCCache::print() const { std::bitset<NChannels> tmsk(trigChanMask); @@ -486,3 +531,185 @@ void Digitizer::BCCache::print() const printf("\n"); } } + +//______________________________________________________________________________ +void Digitizer::setTriggerMask() +{ + mTriggerMask = 0; + std::string printTriggerMask{}; + + for (int im = 0; im < NModules; im++) { + if (im > 0) { + printTriggerMask += " "; + } + printTriggerMask += std::to_string(im); + printTriggerMask += "["; + for (int ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].trigChannel[ic]) { + uint32_t tmask = 0x1 << (im * NChPerModule + ic); + mTriggerMask = mTriggerMask | tmask; + printTriggerMask += "T"; + } else { + printTriggerMask += " "; + } + } + printTriggerMask += "]"; + uint32_t mytmask = mTriggerMask >> (im * NChPerModule); + LOGF(INFO, "Trigger mask for module %d 0123 %c%c%c%c\n", im, + mytmask & 0x1 ? 'T' : 'N', mytmask & 0x2 ? 'T' : 'N', mytmask & 0x4 ? 'T' : 'N', mytmask & 0x8 ? 'T' : 'N'); + } + LOGF(INFO, "TriggerMask=0x%08x %s\n", mTriggerMask, printTriggerMask.c_str()); +} + +//______________________________________________________________________________ +void Digitizer::setReadoutMask() +{ + mReadoutMask = 0; + std::string printReadoutMask{}; + + for (int im = 0; im < NModules; im++) { + if (im > 0) { + printReadoutMask += " "; + } + printReadoutMask += std::to_string(im); + printReadoutMask += "["; + for (int ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].readChannel[ic]) { + uint32_t rmask = 0x1 << (im * NChPerModule + ic); + mReadoutMask = mReadoutMask | rmask; + printReadoutMask += "R"; + } else { + printReadoutMask += " "; + } + } + printReadoutMask += "]"; + uint32_t myrmask = mReadoutMask >> (im * NChPerModule); + LOGF(INFO, "Readout mask for module %d 0123 %c%c%c%c\n", im, + myrmask & 0x1 ? 'R' : 'N', myrmask & 0x2 ? 'R' : 'N', myrmask & 0x4 ? 'R' : 'N', myrmask & 0x8 ? 'R' : 'N'); + } + LOGF(INFO, "ReadoutMask=0x%08x %s\n", mReadoutMask, printReadoutMask.c_str()); +} + +//______________________________________________________________________________ +void Digitizer::assignTriggerBits(uint32_t ibc, std::vector<BCData>& bcData) +{ + // Triggers refer to the HW trigger conditions (32 possible channels) + + uint32_t nbcTot = bcData.size(); + auto& currBC = bcData[ibc]; + + for (int is = -1; is < 4; is++) { + int ibc_peek = ibc + is; + if (ibc_peek < 0) { + continue; + } + if (ibc_peek >= nbcTot) { + break; + } + const auto& otherBC = bcData[ibc_peek]; + auto diffBC = otherBC.ir.differenceInBC(currBC.ir); + if (diffBC < -1) { + continue; + } + if (diffBC > 3) { + break; + } + if (otherBC.ext_triggers && diffBC >= 0) { + for (int im = 0; im < NModules; im++) { + currBC.moduleTriggers[im] |= 0x1 << diffBC; + } + } + if (otherBC.triggers) { + // Assign trigger bits in payload + for (int im = 0; im < NModules; im++) { + uint32_t tmask = (0xf << (im * NChPerModule)) & mTriggerMask; + if (otherBC.triggers & tmask) { + currBC.moduleTriggers[im] |= 0x1 << (5 + diffBC); + } + } + } + } + // Printout before cleanup + //currBC.print(mTriggerMask); +} + +void Digitizer::Finalize(std::vector<BCData>& bcData, std::vector<o2::zdc::OrbitData>& pData) +{ + // Compute scalers for digitized data (works only for triggering channels) + for (Int_t ipd = 0; ipd < pData.size(); ipd++) { + for (int id = 0; id < NChannels; id++) { + pData[ipd].scaler[id] = 0; + } + } + for (int im = 0; im < NModules; im++) { + for (int ic = 0; ic < NChPerModule; ic++) { + uint32_t mask = 0x1 << (im * NChPerModule + ic); + auto id = mModuleConfig->modules[im].channelID[ic]; + for (uint32_t ibc = 0; ibc < bcData.size(); ibc++) { + auto& currBC = bcData[ibc]; + if ((currBC.triggers & mask) && (mReadoutMask & mask)) { + for (Int_t ipd = 0; ipd < pData.size(); ipd++) { + if (pData[ipd].ir.orbit == currBC.ir.orbit) { + pData[ipd].scaler[id]++; + } + } + } + } + } + } + // Default is to mask trigger bits, we can leave them for debugging + if (mMaskTriggerBits) { + for (uint32_t ibc = 0; ibc < bcData.size(); ibc++) { + auto& currBC = bcData[ibc]; + for (int im = 0; im < NModules; im++) { + // Cleanup hits if module has no trigger + uint32_t mmask = 0xf << im; + if ((currBC.triggers & mTriggerMask & mmask) == 0) { + currBC.triggers = currBC.triggers & (~mmask); + } + } + // Cleanup trigger bits for channels that are not readout + currBC.triggers &= mReadoutMask; + // Printout after cleanup + //currBC.print(mTriggerMask); + } + } +} + +//______________________________________________________________________________ +void Digitizer::findEmptyBunches(const std::bitset<o2::constants::lhc::LHCMaxBunches>& bunchPattern) +{ + mNEmptyBCs = 0; + for (int ib = 0; ib < o2::constants::lhc::LHCMaxBunches; ib++) { + int mb = (ib + 31) % o2::constants::lhc::LHCMaxBunches; // beam gas from back of calorimeter + int m1 = ib ? ((ib - 1) % o2::constants::lhc::LHCMaxBunches) : (o2::constants::lhc::LHCMaxBunches - 1); // previous bunch + int cb = ib; // current bunch crossing + int p1 = (ib + 1) % o2::constants::lhc::LHCMaxBunches; // colliding + 1 + int p2 = (ib + 2) % o2::constants::lhc::LHCMaxBunches; // colliding + 2 + int p3 = (ib + 3) % o2::constants::lhc::LHCMaxBunches; // colliding + 3 + if (!(bunchPattern[mb] || bunchPattern[m1] || bunchPattern[cb] || bunchPattern[p1] || bunchPattern[p2] || bunchPattern[p3])) { + mNEmptyBCs++; + } + } + LOG(INFO) << "There are " << mNEmptyBCs << " clean empty bunches"; +} + +//______________________________________________________________________________ +void Digitizer::updatePedestalReference(OrbitData& pdata) +{ + // Compute or update baseline reference + for (uint32_t id = 0; id < NChannels; id++) { + auto base_m = mSimCondition->channels[id].pedestal; // Average pedestal + auto base_s = mSimCondition->channels[id].pedestalFluct; // Baseline oscillations + auto base_n = mSimCondition->channels[id].pedestalNoise; // Electronic noise + float ped = gRandom->Gaus(12. * mNEmptyBCs * base_m, 12. * 2. * base_s * std::sqrt(0.5 * mNEmptyBCs)) // 2 for fluctuation every 2 BCs + + gRandom->Gaus(0, base_n * std::sqrt(12. * mNEmptyBCs)); + int16_t peds = std::round(8. * ped / mNEmptyBCs / 12.); + if (peds < SHRT_MIN) { + peds = SHRT_MIN; + } else if (peds > SHRT_MAX) { + peds = SHRT_MAX; + } + pdata.data[id] = peds; + } +} diff --git a/Detectors/ZDC/simulation/src/Digits2Raw.cxx b/Detectors/ZDC/simulation/src/Digits2Raw.cxx new file mode 100644 index 0000000000000..a373188ac98eb --- /dev/null +++ b/Detectors/ZDC/simulation/src/Digits2Raw.cxx @@ -0,0 +1,622 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <string> +#include <TFile.h> +#include <TTree.h> +#include <TRandom.h> +#include <TMath.h> +#include "ZDCBase/Constants.h" +#include "ZDCBase/ModuleConfig.h" +#include "ZDCSimulation/Digitizer.h" +#include "ZDCSimulation/Digits2Raw.h" +#include "ZDCSimulation/ZDCSimParam.h" +#include "CommonUtils/StringUtils.h" +#include "Framework/Logger.h" + +using namespace o2::zdc; + +//______________________________________________________________________________ +void Digits2Raw::processDigits(const std::string& outDir, const std::string& fileDigitsName) +{ + auto& sopt = ZDCSimParam::Instance(); + mIsContinuous = sopt.continuous; + + if (!mModuleConfig) { + LOG(FATAL) << "Missing ModuleConfig configuration object"; + return; + } + + if (!mSimCondition) { + LOG(FATAL) << "Missing SimCondition configuration object"; + return; + } + + if (mNEmpty < 0) { + LOG(FATAL) << "Bunch crossing map is not initialized"; + return; + } + + if (mNEmpty == 0) { + LOG(WARNING) << "Bunch crossing map has zero clean empty bunches"; + } + + setTriggerMask(); + + std::string outd = outDir; + if (outd.back() != '/') { + outd += '/'; + } + + mLinkID = uint32_t(0); + mCruID = uint16_t(0); + mFLPID = uint16_t(0); + mEndPointID = uint32_t(0); + // TODO: assign FeeID from configuration object + for (int ilink = 0; ilink < NLinks; ilink++) { + uint64_t FeeID = uint64_t(ilink); + std::string outFileLink = o2::utils::Str::concat_string(outDir, "/", "ZDC"); + if (mFileFor != "all") { + outFileLink += fmt::format("_{}", mFLP); + if (mFileFor != "flp") { + outFileLink += fmt::format("_cru{}_{}", mCruID, mEndPointID); + if (mFileFor != "cru") { + outFileLink += fmt::format("_lnk{}_feeid{}", ilink, FeeID); + if (mFileFor != "link") { + LOG(FATAL) << "Not supported output file splitting: " << mFileFor; + throw std::runtime_error("invalid option provided for file grouping"); + } + } + } + } + outFileLink += ".raw"; + mWriter.registerLink(FeeID, mCruID, mLinkID, mEndPointID, outFileLink); + } + + std::unique_ptr<TFile> digiFile(TFile::Open(fileDigitsName.c_str())); + if (!digiFile || digiFile->IsZombie()) { + LOG(FATAL) << "Failed to open input digits file " << fileDigitsName; + return; + } + + TTree* digiTree = (TTree*)digiFile->Get("o2sim"); + if (!digiTree) { + LOG(FATAL) << "Failed to get digits tree"; + return; + } + + if (digiTree->GetBranch("ZDCDigitBC")) { + digiTree->SetBranchAddress("ZDCDigitBC", &mzdcBCDataPtr); + } else { + LOG(FATAL) << "Branch ZDCDigitBC is missing"; + return; + } + + if (digiTree->GetBranch("ZDCDigitCh")) { + digiTree->SetBranchAddress("ZDCDigitCh", &mzdcChDataPtr); + } else { + LOG(FATAL) << "Branch ZDCDigitCh is missing"; + return; + } + + if (digiTree->GetBranch("ZDCDigitOrbit")) { + digiTree->SetBranchAddress("ZDCDigitOrbit", &mzdcPedDataPtr); + } else { + LOG(FATAL) << "Branch ZDCDigitOrbit is missing"; + return; + } + + if (digiTree->GetBranchStatus("ZDCDigitLabels")) { + digiTree->SetBranchStatus("ZDCDigitLabel*", 0); + } + + for (int ient = 0; ient < digiTree->GetEntries(); ient++) { + digiTree->GetEntry(ient); + mNbc = mzdcBCData.size(); + LOG(INFO) << "Entry " << ient << " : " << mNbc << " BCs stored"; + for (int ibc = 0; ibc < mNbc; ibc++) { + mBCD = mzdcBCData[ibc]; + convertDigits(ibc); + writeDigits(); + // Detect last event or orbit change and insert last bunch + if (ibc == (mNbc - 1)) { + // For last event we need to close last orbit (if it is needed) + if (mzdcBCData[ibc].ir.bc != 3563) { + insertLastBunch(ibc, mzdcBCData[ibc].ir.orbit); + writeDigits(); + } + } else { + auto this_orbit = mzdcBCData[ibc].ir.orbit; + auto next_orbit = mzdcBCData[ibc + 1].ir.orbit; + // If current bunch is last bunch in the orbit we don't insert it again + if (mzdcBCData[ibc].ir.bc == 3563) { + this_orbit = this_orbit + 1; + } + // We may need to insert more than one orbit + for (auto orbit = this_orbit; orbit < next_orbit; orbit++) { + insertLastBunch(ibc, orbit); + writeDigits(); + } + } + } + } + digiFile->Close(); +} + +//______________________________________________________________________________ +void Digits2Raw::setTriggerMask() +{ + mTriggerMask = 0; + mPrintTriggerMask = ""; + for (int32_t im = 0; im < NModules; im++) { + if (im > 0) { + mPrintTriggerMask += " "; + } + mPrintTriggerMask += std::to_string(im); + mPrintTriggerMask += "["; + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].trigChannel[ic]) { + uint32_t tmask = 0x1 << (im * NChPerModule + ic); + mTriggerMask = mTriggerMask | tmask; + mPrintTriggerMask += "T"; + } else { + mPrintTriggerMask += " "; + } + } + mPrintTriggerMask += "]"; + uint32_t mytmask = mTriggerMask >> (im * NChPerModule); + printf("Trigger mask for module %d 0123 %s%s%s%s\n", im, + mytmask & 0x1 ? "T" : "N", + mytmask & 0x2 ? "T" : "N", + mytmask & 0x4 ? "T" : "N", + mytmask & 0x8 ? "T" : "N"); + } + printf("trigger_mask=0x%08x %s\n", mTriggerMask, mPrintTriggerMask.data()); +} + +//______________________________________________________________________________ +inline void Digits2Raw::resetSums(uint32_t orbit) +{ + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + mScalers[im][ic] = 0; + mSumPed[im][ic] = 0; + mPed[im][ic] = 0; + } + } + mLastOrbit = orbit; + mLastNEmpty = 0; +} + +//______________________________________________________________________________ +inline void Digits2Raw::updatePedestalReference(int bc) +{ + // Compute or update baseline reference + // In the last BC we copy what is stored in the digits + if (bc == 3563) { + int io = 0; + for (; io < mzdcPedData.size(); io++) { + uint32_t orbit = mBCD.ir.orbit; + if (orbit == mzdcPedData[io].ir.orbit) { + break; + } + } + if (io == mzdcPedData.size()) { + LOG(FATAL) << "Cannot find orbit"; + } + + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + // Identify connected channel + auto id = mModuleConfig->modules[im].channelID[ic]; + double myped = mzdcPedData[io].data[id] + 32768.; + if (myped < 0) { + myped = 0; + } + if (myped > 65535) { + myped = 65535; + } + mPed[im][ic] = myped; + } + } + } else if (mEmpty[bc] > 0 && mEmpty[bc] != mLastNEmpty) { + // For the preceding bunch crossing we make-up the fields in a random walk + // fashion like in the hardware. The result however cannot be coherent with + // what is stored in the last bunch + for (int32_t im = 0; im < NModules; im++) { + for (int32_t ic = 0; ic < NChPerModule; ic++) { + // Identify connected channel + auto id = mModuleConfig->modules[im].channelID[ic]; + auto base_m = mSimCondition->channels[id].pedestal; // Average pedestal + auto base_s = mSimCondition->channels[id].pedestalFluct; // Baseline oscillations + auto base_n = mSimCondition->channels[id].pedestalNoise; // Electronic noise + double deltan = mEmpty[bc] - mLastNEmpty; + // We assume to have a fluctuation every two bunch crossings + // Will need to tune this parameter + double k = 2.; + mSumPed[im][ic] += gRandom->Gaus(12. * deltan * base_m, 12. * k * base_s * TMath::Sqrt(deltan / k)); + // Adding in quadrature the RMS of pedestal electronic noise + mSumPed[im][ic] += gRandom->Gaus(0, base_n * TMath::Sqrt(12. * deltan)); + double myped = TMath::Nint(8. * mSumPed[im][ic] / double(mEmpty[bc]) / 12. + 32768); + if (myped < 0) { + myped = 0; + } + if (myped > 65535) { + myped = 65535; + } + mPed[im][ic] = myped; + } + } + mLastNEmpty = mEmpty[bc]; + } +} + +//______________________________________________________________________________ +inline void Digits2Raw::resetOutputStructure(uint16_t bc, uint32_t orbit, bool is_dummy) +{ + // Increment scalers and reset output structure + for (uint32_t im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + // Fixed words + mZDC.data[im][ic].w[0][0] = Id_w0; + mZDC.data[im][ic].w[0][1] = 0; + mZDC.data[im][ic].w[0][2] = 0; + mZDC.data[im][ic].w[0][3] = 0; + mZDC.data[im][ic].w[1][0] = Id_w1; + mZDC.data[im][ic].w[1][1] = 0; + mZDC.data[im][ic].w[1][2] = 0; + mZDC.data[im][ic].w[1][3] = 0; + mZDC.data[im][ic].w[2][0] = Id_w2; + mZDC.data[im][ic].w[2][1] = 0; + mZDC.data[im][ic].w[2][2] = 0; + mZDC.data[im][ic].w[2][3] = 0; + // Module and channel numbers + mZDC.data[im][ic].f.board = im; + mZDC.data[im][ic].f.ch = ic; + // Orbit and bunch crossing + mZDC.data[im][ic].f.orbit = orbit; + mZDC.data[im][ic].f.bc = bc; + // If channel is hit in current bunch crossing + if (!is_dummy) { + if (mBCD.triggers & (0x1 << (im * NChPerModule + ic))) { + mScalers[im][ic]++; // increment scalers + mZDC.data[im][ic].f.Hit = 1; // flag bunch crossing + } + } + mZDC.data[im][ic].f.hits = mScalers[im][ic]; + mZDC.data[im][ic].f.offset = mPed[im][ic]; + } + } +} + +//______________________________________________________________________________ +inline void Digits2Raw::assignTriggerBits(int ibc, uint16_t bc, uint32_t orbit, bool is_dummy) +{ + // Triggers refer to the HW trigger conditions (32 possible channels) + // Autotrigger, current bunch crossing + ModuleTriggerMapData triggers; + // Autotrigger and ALICE trigger bits are zero for a dummy bunch crossing + if (!is_dummy) { + for (uint32_t im = 0; im < NModules; im++) { + triggers.w = mzdcBCData[ibc].moduleTriggers[im]; + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + mZDC.data[im][ic].f.Alice_0 = triggers.f.Alice_0; + mZDC.data[im][ic].f.Alice_1 = triggers.f.Alice_1; + mZDC.data[im][ic].f.Alice_2 = triggers.f.Alice_2; + mZDC.data[im][ic].f.Alice_3 = triggers.f.Alice_3; + mZDC.data[im][ic].f.Auto_m = triggers.f.Auto_m; + mZDC.data[im][ic].f.Auto_0 = triggers.f.Auto_0; + mZDC.data[im][ic].f.Auto_1 = triggers.f.Auto_1; + mZDC.data[im][ic].f.Auto_2 = triggers.f.Auto_2; + mZDC.data[im][ic].f.Auto_3 = triggers.f.Auto_3; + } + } + } +} + +//______________________________________________________________________________ +void Digits2Raw::insertLastBunch(int ibc, uint32_t orbit) +{ + + // Orbit and bunch crossing identifiers + uint16_t bc = 3563; + + // Reset scalers at orbit change + if (orbit != mLastOrbit) { + resetSums(orbit); + } + + updatePedestalReference(bc); + + // Dummy bunch -> Do not increment scalers but reset output structure + resetOutputStructure(bc, orbit, true); + + // Compute autotrigger bits and assign ALICE trigger bits + assignTriggerBits(ibc, bc, orbit, true); + + // Insert payload for all channels + for (int32_t im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].readChannel[ic]) { + auto id = mModuleConfig->modules[im].channelID[ic]; + auto base_m = mSimCondition->channels[id].pedestal; // Average pedestal + auto base_s = mSimCondition->channels[id].pedestalFluct; // Baseline oscillations + auto base_n = mSimCondition->channels[id].pedestalNoise; // Electronic noise + double base = gRandom->Gaus(base_m, base_s); + double val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s00 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s01 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s02 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s03 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s04 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s05 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s06 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s07 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s08 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s09 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s10 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + val = base + gRandom->Gaus(0, base_n); + mZDC.data[im][ic].f.s11 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax; + } + } + } +} // insertLastBunch + +//______________________________________________________________________________ +void Digits2Raw::convertDigits(int ibc) +{ + + // Orbit and bunch crossing identifiers + uint16_t bc = mBCD.ir.bc; + uint32_t orbit = mBCD.ir.orbit; + + // Reset scalers at orbit change + if (orbit != mLastOrbit) { + resetSums(orbit); + } + + updatePedestalReference(bc); + + // Not a dummy bunch -> Reset output structure and eventually flag hits and increment scalers + resetOutputStructure(bc, orbit, false); + + // Compute autotrigger bits and assign ALICE trigger bits + assignTriggerBits(ibc, bc, orbit, false); + + if (mVerbosity > 0) { + mBCD.print(mTriggerMask); + } + + int chEnt = mBCD.ref.getFirstEntry(); + for (int ic = 0; ic < mBCD.ref.getEntries(); ic++) { + const auto& chd = mzdcChData[chEnt++]; + if (mVerbosity > 0) { + chd.print(); + } + uint16_t bc = mBCD.ir.bc; + uint32_t orbit = mBCD.ir.orbit; + // Look for channel ID in digits and store channel (just one copy in output) + // This is a limitation of software but we are not supposed to acquire the + // same signal twice anyway + for (int32_t im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].channelID[ic] == chd.id && + mModuleConfig->modules[im].readChannel[ic]) { + int32_t is = 0; + mZDC.data[im][ic].f.s00 = chd.data[is++]; + mZDC.data[im][ic].f.s01 = chd.data[is++]; + mZDC.data[im][ic].f.s02 = chd.data[is++]; + mZDC.data[im][ic].f.s03 = chd.data[is++]; + mZDC.data[im][ic].f.s04 = chd.data[is++]; + mZDC.data[im][ic].f.s05 = chd.data[is++]; + mZDC.data[im][ic].f.s06 = chd.data[is++]; + mZDC.data[im][ic].f.s07 = chd.data[is++]; + mZDC.data[im][ic].f.s08 = chd.data[is++]; + mZDC.data[im][ic].f.s09 = chd.data[is++]; + mZDC.data[im][ic].f.s10 = chd.data[is++]; + mZDC.data[im][ic].f.s11 = chd.data[is++]; + break; + } + } + } + } +} + +//______________________________________________________________________________ +void Digits2Raw::writeDigits() +{ + constexpr static int data_size = sizeof(uint32_t) * NWPerGBTW; + constexpr static gsl::span<char> empty; + // Local interaction record (true and empty bunches) + o2::InteractionRecord ir(mZDC.data[0][0].f.bc, mZDC.data[0][0].f.orbit); + for (uint32_t im = 0; im < o2::zdc::NModules; im++) { + // Check if module has been filled with data + // N.B. All channels are initialized if module is supposed to be readout + // Trigger bits are the same for all the channels connected to a module + bool TM = mZDC.data[im][0].f.Auto_m; + bool T0 = mZDC.data[im][0].f.Auto_0; + bool T1 = mZDC.data[im][0].f.Auto_1; + bool T2 = mZDC.data[im][0].f.Auto_2; + bool T3 = mZDC.data[im][0].f.Auto_3; + bool A0 = mZDC.data[im][0].f.Alice_0; + bool A1 = mZDC.data[im][0].f.Alice_1; + bool A2 = mZDC.data[im][0].f.Alice_2; + bool A3 = mZDC.data[im][0].f.Alice_3; + bool tcond_continuous = T0 || T1; + bool tcond_triggered = A0 || A1 || (A2 && (T0 || TM)) || (A3 && T0); + bool tcond_last = mZDC.data[im][0].f.bc == 3563; + // Condition to write GBT data + bool addedChData[NChPerModule] = {false, false, false, false}; + if (tcond_triggered || (mIsContinuous && tcond_continuous) || (mZDC.data[im][0].f.bc == 3563)) { + for (uint32_t ic = 0; ic < o2::zdc::NChPerModule; ic++) { + uint64_t FeeID = 2 * im + ic / 2; + if (mModuleConfig->modules[im].readChannel[ic]) { + for (int32_t iw = 0; iw < o2::zdc::NWPerBc; iw++) { + gsl::span<char> payload{reinterpret_cast<char*>(&mZDC.data[im][ic].w[iw][0]), data_size}; + mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, payload); + } + addedChData[ic] = true; + } + } + } + // All links are registered, we add explicitly zero payload + if (addedChData[0] == false && addedChData[1] == false) { + uint64_t FeeID = 2 * im; + mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, empty); + } + if (addedChData[2] == false && addedChData[3] == false) { + uint64_t FeeID = 2 * im + 1; + mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, empty); + } + if (mVerbosity > 1) { + if (tcond_continuous) { + printf("M%d Cont. T0=%d || T1=%d\n", im, T0, T1); + } + if (tcond_triggered) { + printf("M%d Trig. %s A0=%d || A1=%d || (A2=%d && (T0=%d || TM=%d))=%d || (A3=%d && T0=%d )=%d\n", im, mIsContinuous ? "CM" : "TM", A0, A1, A2, T0, TM, A2 && (T0 || TM), A3, T0, A3 && T0); + } + if (mZDC.data[im][0].f.bc == 3563) { + printf("M%d is last BC\n", im); + } + if (tcond_triggered || (mIsContinuous && tcond_continuous) || (mZDC.data[im][0].f.bc == 3563)) { + for (uint32_t ic = 0; ic < o2::zdc::NChPerModule; ic++) { + if (mModuleConfig->modules[im].readChannel[ic]) { + for (int32_t iw = 0; iw < o2::zdc::NWPerBc; iw++) { + print_gbt_word(&mZDC.data[im][ic].w[iw][0], mModuleConfig); + } + } + } + } else { + if (mVerbosity > 2) { + printf("orbit %9u bc %4u M%d SKIP\n", mZDC.data[im][0].f.orbit, mZDC.data[im][0].f.bc, im); + } + } + } + } +} + +//______________________________________________________________________________ +void Digits2Raw::print_gbt_word(const uint32_t* word, const ModuleConfig* moduleConfig) +{ + if (word == nullptr) { + printf("NULL\n"); + return; + } + unsigned __int128 val = word[2]; + val = val << 32; + val = val | word[1]; + val = val << 32; + val = val | word[0]; + static uint32_t last_orbit = 0, last_bc = 0; + + ULong64_t lsb = val; + ULong64_t msb = val >> 64; + uint32_t a = word[0]; + uint32_t b = word[1]; + uint32_t c = word[2]; + //uint32_t d=(msb>>32)&0xffffffff; + //printf("\n%llx %llx ",lsb,msb); + //printf("\n%8x %8x %8x %8x ",d,c,b,a); + if ((a & 0x3) == 0) { + uint32_t myorbit = (val >> 48) & 0xffffffff; + uint32_t mybc = (val >> 36) & 0xfff; + if (myorbit != last_orbit || mybc != last_bc) { + printf("Orbit %9u bc %4u\n", myorbit, mybc); + last_orbit = myorbit; + last_bc = mybc; + } + printf("%04x %08x %08x ", c, b, a); + uint32_t hits = (val >> 24) & 0xfff; + int32_t offset = (lsb >> 8) & 0xffff - 32768; + float foffset = offset / 8.; + uint32_t board = (lsb >> 2) & 0xf; + uint32_t ch = (lsb >> 6) & 0x3; + //printf("orbit %9u bc %4u hits %4u offset %+6i Board %2u Ch %1u", myorbit, mybc, hits, offset, board, ch); + printf("orbit %9u bc %4u hits %4u offset %+8.3f Board %2u Ch %1u", myorbit, mybc, hits, foffset, board, ch); + if (board >= NModules) { + printf(" ERROR with board"); + } + if (ch >= NChPerModule) { + printf(" ERROR with ch"); + } + if (moduleConfig) { + auto id = moduleConfig->modules[board].channelID[ch]; + if (id >= 0 && id < NChannels) { + printf(" %s", ChannelNames[id].data()); + } else { + printf(" error with ch id"); + } + } + } else if ((a & 0x3) == 1) { + printf("%04x %08x %08x ", c, b, a); + printf(" %s %s %s %s ", a & 0x10 ? "A0" : " ", a & 0x20 ? "A1" : " ", a & 0x40 ? "A2" : " ", a & 0x80 ? "A3" : " "); + printf("0-5 "); + int16_t s[6]; + val = val >> 8; + for (int32_t i = 0; i < 6; i++) { + s[i] = val & 0xfff; + if (s[i] > ADCMax) { + s[i] = s[i] - ADCRange; + } + val = val >> 12; + } + printf(" %5d %5d %5d %5d %5d %5d", s[0], s[1], s[2], s[3], s[4], s[5]); + } else if ((a & 0x3) == 2) { + printf("%04x %08x %08x ", c, b, a); + printf("%s %s %s %s %s %s ", a & 0x4 ? "H" : " ", a & 0x8 ? "TM" : " ", a & 0x10 ? "T0" : " ", a & 0x20 ? "T1" : " ", a & 0x40 ? "T2" : " ", a & 0x80 ? "T3" : " "); + printf("6-b "); + int16_t s[6]; + val = val >> 8; + for (int32_t i = 0; i < 6; i++) { + s[i] = val & 0xfff; + if (s[i] > ADCMax) { + s[i] = s[i] - ADCRange; + } + val = val >> 12; + } + printf(" %5d %5d %5d %5d %5d %5d", s[0], s[1], s[2], s[3], s[4], s[5]); + } else if ((a & 0x3) == 3) { + printf("%04x %08x %08x ", c, b, a); + printf("HB "); + } + printf("\n"); +} + +//______________________________________________________________________________ +void Digits2Raw::emptyBunches(std::bitset<3564>& bunchPattern) +{ + const int LHCMaxBunches = o2::constants::lhc::LHCMaxBunches; + mNEmpty = 0; + for (int32_t ib = 0; ib < LHCMaxBunches; ib++) { + int32_t mb = (ib + 31) % LHCMaxBunches; // beam gas from back of calorimeter (31 bc earlier than a colliding bunch) + int32_t m1 = (ib + 1) % LHCMaxBunches; // next bunch is colliding (position -1) + int32_t p1 = (ib - 1 + LHCMaxBunches) % LHCMaxBunches; // current bc is 1 bc after colliding (position +1) + int32_t p2 = (ib - 2 + LHCMaxBunches) % LHCMaxBunches; // current bc is 2 bc after colliding + int32_t p3 = (ib - 3 + LHCMaxBunches) % LHCMaxBunches; // current bc is 3 bc after colliding + if (bunchPattern[mb] || bunchPattern[m1] || bunchPattern[ib] || bunchPattern[p1] || bunchPattern[p2] || bunchPattern[p3]) { + mEmpty[ib] = mNEmpty; + } else { + mNEmpty++; + mEmpty[ib] = mNEmpty; + } + } + LOG(INFO) << "There are " << mNEmpty << " clean empty bunches"; +} diff --git a/Detectors/ZDC/simulation/src/SimCondition.cxx b/Detectors/ZDC/simulation/src/SimCondition.cxx index ea7e2e4e1597b..7c046838ec255 100644 --- a/Detectors/ZDC/simulation/src/SimCondition.cxx +++ b/Detectors/ZDC/simulation/src/SimCondition.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/src/SpatialPhotonResponse.cxx b/Detectors/ZDC/simulation/src/SpatialPhotonResponse.cxx index 6c3ccbcf34ff8..2cb9c09b1ae41 100644 --- a/Detectors/ZDC/simulation/src/SpatialPhotonResponse.cxx +++ b/Detectors/ZDC/simulation/src/SpatialPhotonResponse.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/src/ZDCSimParam.cxx b/Detectors/ZDC/simulation/src/ZDCSimParam.cxx index 0a66bfa901ea0..3e8f9046fbdac 100644 --- a/Detectors/ZDC/simulation/src/ZDCSimParam.cxx +++ b/Detectors/ZDC/simulation/src/ZDCSimParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/ZDC/simulation/src/ZDCSimulationLinkDef.h b/Detectors/ZDC/simulation/src/ZDCSimulationLinkDef.h index cd3455b1a5b83..8b37988bcc635 100644 --- a/Detectors/ZDC/simulation/src/ZDCSimulationLinkDef.h +++ b/Detectors/ZDC/simulation/src/ZDCSimulationLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,12 +18,10 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::zdc::Hit + ; #pragma link C++ class o2::zdc::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::zdc::Detector> + ; #pragma link C++ class o2::zdc::Digitizer + ; -#pragma link C++ class o2::zdc::MCLabel + ; #pragma link C++ class o2::zdc::ChannelSimCondition + ; #pragma link C++ class o2::zdc::SimCondition + ; @@ -30,7 +29,6 @@ #pragma link C++ class o2::zdc::ZDCSimParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::zdc::ZDCSimParam> + ; -#pragma link C++ class o2::dataformats::MCTruthContainer < o2::zdc::MCLabel> + ; #pragma link C++ class std::vector < std::vector < int>> + ; #pragma link C++ class o2::zdc::SpatialPhotonResponse + ; diff --git a/Detectors/ZDC/simulation/src/digi2raw.cxx b/Detectors/ZDC/simulation/src/digi2raw.cxx new file mode 100644 index 0000000000000..139e847633738 --- /dev/null +++ b/Detectors/ZDC/simulation/src/digi2raw.cxx @@ -0,0 +1,173 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digi2raw.cxx +/// \author ruben.shahoyan@cern.ch + +#include <boost/program_options.hpp> +#include <filesystem> +#include <TFile.h> +#include <TStopwatch.h> +#include "Framework/Logger.h" +#include <string> +#include <iomanip> +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CommonUtils/StringUtils.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsRaw/HBFUtils.h" +#include "ZDCBase/Constants.h" +#include "ZDCBase/ModuleConfig.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "ZDCSimulation/Digits2Raw.h" +#include "DataFormatsParameters/GRPObject.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include "SimConfig/DigiParams.h" + +/// MC->raw conversion for ZDC + +namespace bpo = boost::program_options; + +void digi2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV = 4, + const std::string& ccdbHost = "", int superPageSizeInB = 1024 * 1024); + +int main(int argc, char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + "Convert ZDC digits to CRU raw data\n"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbosity,v", bpo::value<int>()->default_value(0), "verbosity level"); + // add_option("input-file,i", bpo::value<std::string>()->default_value(o2::base::NameConf::getDigitsFileName(o2::detectors::DetID::ZDC)),"input ZDC digits file"); // why not used? + add_option("input-file,i", bpo::value<std::string>()->default_value("zdcdigits.root"), "input ZDC digits file"); + add_option("file-for,f", bpo::value<std::string>()->default_value("all"), "single file per: all,flp,cru,link"); + add_option("output-dir,o", bpo::value<std::string>()->default_value("./"), "output directory for raw data"); + add_option("ccdb-url,c", bpo::value<std::string>()->default_value(""), "url of the ccdb repository"); + uint32_t defRDH = o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>(); + add_option("rdh-version,r", bpo::value<uint32_t>()->default_value(defRDH), "RDH version to use"); + add_option("hbfutils-config,u", bpo::value<std::string>()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); + add_option("configKeyValues", bpo::value<std::string>()->default_value(""), "comma-separated configKeyValues"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help")) { + std::cout << opt_general << std::endl; + exit(0); + } + + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + std::string confDig = vm["hbfutils-config"].as<std::string>(); + if (!confDig.empty() && confDig != "none") { + o2::conf::ConfigurableParam::updateFromFile(confDig, "HBFUtils"); + } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as<std::string>()); + + std::string ccdb_url = vm["ccdb-url"].as<std::string>(); + auto& dopt = o2::conf::DigiParams::Instance(); + std::string ccdbHost = dopt.ccdb; + if (ccdb_url.length() > 0) { + ccdbHost = ccdb_url; + LOG(INFO) << "CCDB url set to " << ccdb_url; + } + LOG(INFO) << "CCDB url " << ccdbHost; + digi2raw(vm["input-file"].as<std::string>(), + vm["output-dir"].as<std::string>(), + vm["verbosity"].as<int>(), + vm["file-for"].as<std::string>(), + vm["rdh-version"].as<uint32_t>(), + ccdbHost); + + o2::raw::HBFUtils::Instance().print(); + + return 0; +} + +void digi2raw(const std::string& inpName, const std::string& outDir, int verbosity, const std::string& fileFor, uint32_t rdhV, const std::string& ccdbHost, int superPageSizeInB) +{ + long timeStamp = 0; + //std::string ccdbHost = "http://ccdb-test.cern.ch:8080"; + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(ccdbHost); + if (timeStamp == mgr.getTimestamp()) { + return; + } + mgr.setTimestamp(timeStamp); + auto moduleConfig = mgr.get<o2::zdc::ModuleConfig>(o2::zdc::CCDBPathConfigModule); + if (!moduleConfig) { + LOG(FATAL) << "Cannot module configuratio for timestamp " << timeStamp; + return; + } + LOG(INFO) << "Loaded module configuration for timestamp " << timeStamp; + + auto simCondition = mgr.get<o2::zdc::SimCondition>(o2::zdc::CCDBPathConfigSim); + if (!simCondition) { + LOG(FATAL) << "Cannot get simulation configuration for timestamp " << timeStamp; + return; + } + LOG(INFO) << "Loaded simulation configuration for timestamp " << timeStamp; + simCondition->print(); + + const auto* ctx = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto& bcfill = ctx->getBunchFilling(); + auto bf = ctx->getBunchFilling(); + if (verbosity > 0) { + bf.print(); + } + auto bp = bf.getPattern(); + + TStopwatch swTot; + swTot.Start(); + + o2::zdc::Digits2Raw d2r; + d2r.setFileFor(fileFor); + d2r.setVerbosity(verbosity); + auto& wr = d2r.getWriter(); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); + wr.setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::ZDC)); // must be set explicitly + wr.setSuperPageSize(superPageSizeInB); + wr.useRDHVersion(rdhV); + + o2::raw::assertOutputDirectory(outDir); + + std::string outDirName(outDir); + if (outDirName.back() != '/') { + outDirName += '/'; + } + + d2r.setModuleConfig(moduleConfig); + d2r.setSimCondition(simCondition); + d2r.emptyBunches(bp); + d2r.setVerbosity(verbosity); + d2r.processDigits(outDirName, inpName); + wr.writeConfFile(wr.getOrigin().str, "RAWDATA", o2::utils::Str::concat_string(outDirName, wr.getOrigin().str, "raw.cfg")); + // + swTot.Stop(); + swTot.Print(); +} diff --git a/Detectors/ZDC/workflow/CMakeLists.txt b/Detectors/ZDC/workflow/CMakeLists.txt new file mode 100644 index 0000000000000..ad4a5f4abd63e --- /dev/null +++ b/Detectors/ZDC/workflow/CMakeLists.txt @@ -0,0 +1,54 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(ZDCWorkflow + SOURCES src/DigitReaderSpec.cxx + src/EntropyEncoderSpec.cxx + src/EntropyDecoderSpec.cxx + src/ZDCDataReaderDPLSpec.cxx + src/ZDCDigitWriterDPLSpec.cxx + src/ZDCRecoWriterDPLSpec.cxx + src/RecEventReaderSpec.cxx + src/RecoWorkflow.cxx + src/DigitRecoSpec.cxx + src/DigitReaderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsZDC + O2::ZDCRaw + O2::SimulationDataFormat + O2::DPLUtils + O2::ZDCReconstruction + O2::DataFormatsZDC) + +o2_add_executable(raw2digits + COMPONENT_NAME zdc + SOURCES src/o2-zdc-raw2digits.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow) + +o2_add_executable(entropy-encoder-workflow + COMPONENT_NAME zdc + SOURCES src/entropy-encoder-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow) + +o2_add_executable(digits-read + COMPONENT_NAME zdc + SOURCES src/digits-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow) + +o2_add_executable(digits-reco + COMPONENT_NAME zdc + SOURCES src/zdc-reco-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCReconstruction) + +o2_add_executable(write-reco + COMPONENT_NAME zdc + SOURCES src/reco-writer-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow) diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitReaderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitReaderSpec.h new file mode 100644 index 0000000000000..269ea33352a11 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitReaderSpec.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_DIGITREADERSPEC_H +#define O2_ZDC_DIGITREADERSPEC_H + +#include "TFile.h" +#include "TTree.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" + +namespace o2 +{ +namespace zdc +{ + +class DigitReader : public framework::Task +{ + public: + DigitReader(bool useMC) : mUseMC(useMC) {} + ~DigitReader() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + + private: + bool mUseMC = true; + std::unique_ptr<TTree> mTree; + std::unique_ptr<TFile> mFile; +}; + +/// create a processor spec +/// read simulated ZDC digits from a root file +framework::DataProcessorSpec getDigitReaderSpec(bool useMC); + +} // end namespace zdc +} // end namespace o2 + +#endif // O2_ZDC_DIGITREADERSPEC_H diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h new file mode 100644 index 0000000000000..6cbdf616041a1 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitRecoSpec.h +/// @brief Convert ZDC data to CTF (EncodedBlocks) +/// @author pietro.cortese@cern.ch + +#ifndef O2_ZDC_DIGITRECO_SPEC +#define O2_ZDC_DIGITRECO_SPEC + +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "ZDCReconstruction/DigiReco.h" +#include <TStopwatch.h> + +namespace o2 +{ +namespace zdc +{ + +class DigitRecoSpec : public o2::framework::Task +{ + public: + DigitRecoSpec(); + DigitRecoSpec(const int verbosity, const bool debugOut); + ~DigitRecoSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + DigiReco mDR; // Reconstruction object + std::string mccdbHost{"http://ccdb-test.cern.ch:8080"}; // Alternative ccdb server + int mVerbosity = 0; // Verbosity level during recostruction + bool mDebugOut = false; // Save temporary reconstruction structures on root file + bool mInitialized = false; // Connect once to CCDB during initialization + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getDigitRecoSpec(const int verbosity, const bool enableDebugOut); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h new file mode 100644 index 0000000000000..6d0f76452ac99 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.h +/// @brief Convert CTF (EncodedBlocks) to ZDC BCData/ChannelData/OrbitData stream + +#ifndef O2_ZDC_ENTROPYDECODER_SPEC +#define O2_ZDC_ENTROPYDECODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "ZDCReconstruction/CTFCoder.h" +#include <TStopwatch.h> + +namespace o2 +{ +namespace zdc +{ + +class EntropyDecoderSpec : public o2::framework::Task +{ + public: + EntropyDecoderSpec(); + ~EntropyDecoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::zdc::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyDecoderSpec(); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h new file mode 100644 index 0000000000000..7c247c42ceb8f --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.h +/// @brief Convert ZDC data to CTF (EncodedBlocks) +/// @author ruben.shahoyan@cern.ch + +#ifndef O2_ZDC_ENTROPYENCODER_SPEC +#define O2_ZDC_ENTROPYENCODER_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include <TStopwatch.h> +#include "ZDCReconstruction/CTFCoder.h" + +namespace o2 +{ +namespace zdc +{ + +class EntropyEncoderSpec : public o2::framework::Task +{ + public: + EntropyEncoderSpec(); + ~EntropyEncoderSpec() override = default; + void run(o2::framework::ProcessingContext& pc) final; + void init(o2::framework::InitContext& ic) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + o2::zdc::CTFCoder mCTFCoder; + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getEntropyEncoderSpec(); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/RecEventReaderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecEventReaderSpec.h new file mode 100644 index 0000000000000..2816d9556287b --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecEventReaderSpec.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecEventReaderSpec.h + +#ifndef O2_ZDC_RECEVENTREADER_SPEC +#define O2_ZDC_RECEVENTREADER_SPEC + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/RootSerializationSupport.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DataFormatsZDC/RecEvent.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +class RecEventReader : public Task +{ + public: + RecEventReader(bool useMC = true); + ~RecEventReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + + std::unique_ptr<TFile> mFile; + std::unique_ptr<TTree> mTree; + + bool mUseMC = true; // use MC truth + o2::header::DataOrigin mOrigin = o2::header::gDataOriginZDC; + + std::vector<o2::zdc::BCRecData>* mBCRecData = nullptr; + std::vector<o2::zdc::ZDCEnergy>* mZDCEnergy = nullptr; + std::vector<o2::zdc::ZDCTDCData>* mZDCTDCData = nullptr; + std::vector<uint16_t>* mZDCInfo = nullptr; + + std::string mInputFileName = "zdcreco.root"; + std::string mRecEventTreeName = "o2rec"; + std::string mBCRecDataBranchName = "ZDCRecBC"; + std::string mZDCEnergyBranchName = "ZDCRecE"; + std::string mZDCTDCDataBranchName = "ZDCRecTDC"; + std::string mZDCInfoBranchName = "ZDCRecInfo"; +}; + +/// create a processor spec +/// read reconstructed ZDC event parts +framework::DataProcessorSpec getRecEventReaderSpec(bool useMC); + +} // namespace zdc +} // namespace o2 + +#endif /* O2_ZDC_RECEVENTREADER_SPEC */ diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h new file mode 100644 index 0000000000000..aa2586d2488b9 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_RECOWORKFLOW_H +#define O2_ZDC_RECOWORKFLOW_H + +/// @file RecoWorkflow.h + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace zdc +{ +framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut); +} // namespace zdc +} // namespace o2 +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDataReaderDPLSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDataReaderDPLSpec.h new file mode 100644 index 0000000000000..91306aa73a566 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDataReaderDPLSpec.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ZDCDataReaderDPLSpec.h + +#ifndef O2_ZDCDATAREADERDPLSPEC_H +#define O2_ZDCDATAREADERDPLSPEC_H + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/SerializationMethods.h" +#include "Framework/InputRecordWalker.h" +#include "DPLUtils/DPLRawParser.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/InputSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "ZDCBase/Constants.h" +#include "ZDCBase/ModuleConfig.h" +#include "ZDCRaw/RawReaderZDC.h" +#include <iostream> +#include <vector> +#include <gsl/span> + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ +class ZDCDataReaderDPLSpec : public Task +{ + public: + ZDCDataReaderDPLSpec() = default; + ZDCDataReaderDPLSpec(const RawReaderZDC& rawReader, const bool verifyTrigger); + ~ZDCDataReaderDPLSpec() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + std::string mccdbHost = "http://ccdb-test.cern.ch:8080"; + bool mVerifyTrigger = true; + RawReaderZDC mRawReader; +}; + +framework::DataProcessorSpec getZDCDataReaderDPLSpec(const RawReaderZDC& rawReader, const bool verifyTrigger, const bool askSTFDist); + +} // namespace zdc +} // namespace o2 + +#endif /* O2_ZDCDATAREADERDPL_H */ diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDigitWriterDPLSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDigitWriterDPLSpec.h new file mode 100644 index 0000000000000..089894e9c2d02 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDigitWriterDPLSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ZDCDigitWriterDPLSpec.h + +#ifndef O2_ZDCDIGITWRITERDPLSPEC_H +#define O2_ZDCDIGITWRITERDPLSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsZDC/MCLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +/// create a processor spec +framework::DataProcessorSpec getZDCDigitWriterDPLSpec(bool mctruth, bool simVersion); + +} // namespace zdc +} // namespace o2 + +#endif /* O2_ZDCDIGITWRITERDPLSPEC_H */ diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCRecoWriterDPLSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCRecoWriterDPLSpec.h new file mode 100644 index 0000000000000..a09083f69373b --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCRecoWriterDPLSpec.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ZDCRecoWriterSpec.h + +#ifndef O2_ZDCRECOTWRITERDPLSPEC_H +#define O2_ZDCRECOTWRITERDPLSPEC_H + +#include "Framework/DataProcessorSpec.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsZDC/MCLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +/// create a processor spec +framework::DataProcessorSpec getZDCRecoWriterDPLSpec(); + +} // namespace zdc +} // namespace o2 + +#endif /* O2_ZDCRECOTWRITERDPLSPEC_H */ diff --git a/Detectors/ZDC/workflow/src/DigitReaderSpec.cxx b/Detectors/ZDC/workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..09f7c5c7ca6c5 --- /dev/null +++ b/Detectors/ZDC/workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include <vector> + +#include "TTree.h" + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "ZDCWorkflow/DigitReaderSpec.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/MCLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +void DigitReader::init(InitContext& ic) +{ + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("zdc-digit-infile")); + mFile = std::make_unique<TFile>(filename.c_str()); + if (!mFile->IsOpen()) { + LOG(ERROR) << "Cannot open the " << filename.c_str() << " file !"; + throw std::runtime_error("cannot open input digits file"); + } + mTree.reset((TTree*)mFile->Get("o2sim")); + if (!mTree) { + LOG(ERROR) << "Did not find o2sim tree in " << filename.c_str(); + throw std::runtime_error("Did not fine o2sim file in ZDC digits tree"); + } +} + +void DigitReader::run(ProcessingContext& pc) +{ + + std::vector<o2::zdc::OrbitData> zdcOrbitData, *zdcOrbitDataPtr = &zdcOrbitData; + std::vector<o2::zdc::BCData> zdcBCData, *zdcBCDataPtr = &zdcBCData; + std::vector<o2::zdc::ChannelData> zdcChData, *zdcChDataPtr = &zdcChData; + + mTree->SetBranchAddress("ZDCDigitOrbit", &zdcOrbitDataPtr); + mTree->SetBranchAddress("ZDCDigitBC", &zdcBCDataPtr); + mTree->SetBranchAddress("ZDCDigitCh", &zdcChDataPtr); + o2::dataformats::MCTruthContainer<o2::zdc::MCLabel> labels, *plabels = &labels; + if (mUseMC) { + mTree->SetBranchAddress("ZDCDigitLabels", &plabels); + } + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(INFO) << "ZDCDigitReader pushed " << zdcOrbitData.size() << " orbits with " << zdcBCData.size() << " bcs and " << zdcChData.size() << " digits"; + pc.outputs().snapshot(Output{"ZDC", "DIGITSPD", 0, Lifetime::Timeframe}, zdcOrbitData); + pc.outputs().snapshot(Output{"ZDC", "DIGITSBC", 0, Lifetime::Timeframe}, zdcBCData); + pc.outputs().snapshot(Output{"ZDC", "DIGITSCH", 0, Lifetime::Timeframe}, zdcChData); + if (mUseMC) { + pc.outputs().snapshot(Output{"ZDC", "DIGITSLBL", 0, Lifetime::Timeframe}, labels); + } + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +DataProcessorSpec getDigitReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("ZDC", "DIGITSBC", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "DIGITSCH", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "DIGITSPD", 0, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back("ZDC", "DIGITSLBL", 0, Lifetime::Timeframe); + } + return DataProcessorSpec{ + "zdc-digit-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<DigitReader>(useMC)}, + Options{ + {"zdc-digit-infile", VariantType::String, "zdcdigits.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx new file mode 100644 index 0000000000000..7775a37ee17dd --- /dev/null +++ b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx @@ -0,0 +1,215 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitRecoSpec.cxx +/// @brief ZDC reconstruction +/// @author pietro.cortese@cern.ch + +#include <vector> +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "Framework/Logger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "ZDCWorkflow/DigitRecoSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "ZDCBase/ModuleConfig.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "ZDCReconstruction/RecoConfigZDC.h" +#include "ZDCReconstruction/ZDCTDCParam.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +DigitRecoSpec::DigitRecoSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +DigitRecoSpec::DigitRecoSpec(const int verbosity, const bool debugOut) + : mVerbosity(verbosity), mDebugOut(debugOut) +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void DigitRecoSpec::init(o2::framework::InitContext& ic) +{ + mccdbHost = ic.options().get<std::string>("ccdb-url"); +} + +void DigitRecoSpec::run(ProcessingContext& pc) +{ + if (!mInitialized) { + mInitialized = true; + // Initialization from CCDB + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(mccdbHost); + long timeStamp = 0; + if (timeStamp == mgr.getTimestamp()) { + return; + } + mgr.setTimestamp(timeStamp); + auto* moduleConfig = mgr.get<o2::zdc::ModuleConfig>(o2::zdc::CCDBPathConfigModule); + if (!moduleConfig) { + LOG(FATAL) << "Missing configuration object"; + return; + } + LOG(INFO) << "Loaded module configuration for timestamp " << timeStamp; + moduleConfig->print(); + + // Configuration parameters for ZDC reconstruction + auto* recoConfigZDC = mgr.get<o2::zdc::RecoConfigZDC>(o2::zdc::CCDBPathRecoConfigZDC); + if (!recoConfigZDC) { + LOG(FATAL) << "Missing RecoConfigZDC object"; + return; + } + LOG(INFO) << "Loaded RecoConfigZDC for timestamp " << timeStamp; + recoConfigZDC->print(); + + // TDC centering + auto* tdcParam = mgr.get<o2::zdc::ZDCTDCParam>(o2::zdc::CCDBPathTDCCalib); + if (!tdcParam) { + LOG(FATAL) << "Missing ZDCTDCParam calibration object"; + return; + } + LOG(INFO) << "Loaded TDC centering ZDCTDCParam for timestamp " << timeStamp; + tdcParam->print(); + + // Energy calibration + auto* energyParam = mgr.get<o2::zdc::ZDCEnergyParam>(o2::zdc::CCDBPathEnergyCalib); + if (!energyParam) { + LOG(WARNING) << "Missing ZDCEnergyParam calibration object - using default"; + } else { + LOG(INFO) << "Loaded Energy calibration ZDCEnergyParam for timestamp " << timeStamp; + energyParam->print(); + } + + // Tower calibration + auto* towerParam = mgr.get<o2::zdc::ZDCTowerParam>(o2::zdc::CCDBPathTowerCalib); + if (!towerParam) { + LOG(WARNING) << "Missing ZDCTowerParam calibration object - using default"; + } else { + LOG(INFO) << "Loaded Tower calibration ZDCTowerParam for timestamp " << timeStamp; + towerParam->print(); + } + + mDR.setModuleConfig(moduleConfig); + mDR.setRecoConfigZDC(recoConfigZDC); + mDR.setTDCParam(tdcParam); + mDR.setEnergyParam(energyParam); + mDR.setTowerParam(towerParam); + + if (mDebugOut) { + mDR.setDebugOutput(); + } + + mDR.setVerbosity(mVerbosity); + + mDR.init(); + } + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto bcdata = pc.inputs().get<gsl::span<o2::zdc::BCData>>("trig"); + auto chans = pc.inputs().get<gsl::span<o2::zdc::ChannelData>>("chan"); + auto peds = pc.inputs().get<gsl::span<o2::zdc::OrbitData>>("peds"); + + mDR.process(peds, bcdata, chans); + const std::vector<o2::zdc::RecEventAux>& recAux = mDR.getReco(); + + RecEvent recEvent; + LOG(INFO) << "BC processed during reconstruction " << recAux.size(); + int32_t nte = 0, ntt = 0; + for (auto reca : recAux) { + int32_t ne = reca.ezdc.size(); + int32_t nt = 0; + for (int32_t it = 0; it < o2::zdc::NTDCChannels; it++) { + for (int32_t ih = 0; ih < reca.ntdc[it]; ih++) { + if (nt == 0) { + recEvent.addBC(reca.ir, reca.channels, reca.triggers); + } + nt++; + recEvent.addTDC(it, reca.TDCVal[it][ih], reca.TDCAmp[it][ih]); + } + } + if (ne > 0 && nt == 0) { + recEvent.addBC(reca.ir); + } + if (ne > 0) { + std::map<uint8_t, float>::iterator it; + for (it = reca.ezdc.begin(); it != reca.ezdc.end(); it++) { + recEvent.addEnergy(it->first, it->second); + } + } + nte += ne; + ntt += nt; + if (mVerbosity > 0 && (nt > 0 || ne > 0)) { + printf("Orbit %9u bc %4u ntdc %2d ne %2d\n", reca.ir.orbit, reca.ir.bc, nt, ne); + } + // Event information + recEvent.addInfo(reca.tdcPedQC, MsgTDCPedQC); + recEvent.addInfo(reca.tdcPedMissing, MsgTDCPedMissing); + recEvent.addInfo(reca.adcPedOr, MsgADCPedOr); + recEvent.addInfo(reca.adcPedQC, MsgADCPedQC); + recEvent.addInfo(reca.adcPedMissing, MsgADCPedMissing); + } + LOG(INFO) << "Reconstructed " << ntt << " signal TDCs and " << nte << " energies"; + // TODO: rate information for all channels + // TODO: summary of reconstruction to be collected by DQM? + pc.outputs().snapshot(Output{"ZDC", "BCREC", 0, Lifetime::Timeframe}, recEvent.mRecBC); + pc.outputs().snapshot(Output{"ZDC", "ENERGY", 0, Lifetime::Timeframe}, recEvent.mEnergy); + pc.outputs().snapshot(Output{"ZDC", "TDCDATA", 0, Lifetime::Timeframe}, recEvent.mTDCData); + pc.outputs().snapshot(Output{"ZDC", "INFO", 0, Lifetime::Timeframe}, recEvent.mInfo); + mTimer.Stop(); + LOG(INFO) << "Reconstructed ZDC data for " << recEvent.mRecBC.size() << " b.c. in " << mTimer.CpuTime() - cput << " s"; +} + +void DigitRecoSpec::endOfStream(EndOfStreamContext& ec) +{ + mDR.eor(); + LOGF(INFO, "ZDC Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +framework::DataProcessorSpec getDigitRecoSpec(const int verbosity = 0, const bool enableDebugOut = false) +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("trig", "ZDC", "DIGITSBC", 0, Lifetime::Timeframe); + inputs.emplace_back("chan", "ZDC", "DIGITSCH", 0, Lifetime::Timeframe); + inputs.emplace_back("peds", "ZDC", "DIGITSPD", 0, Lifetime::Timeframe); + + std::vector<OutputSpec> outputs; + outputs.emplace_back("ZDC", "BCREC", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "ENERGY", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "TDCDATA", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "INFO", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "zdc-digi-reco", + inputs, + outputs, + AlgorithmSpec{adaptFromTask<DigitRecoSpec>(verbosity, enableDebugOut)}, + o2::framework::Options{{"ccdb-url", o2::framework::VariantType::String, "http://ccdb-test.cern.ch:8080", {"CCDB Url"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx new file mode 100644 index 0000000000000..9c7f8cc166d1e --- /dev/null +++ b/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx @@ -0,0 +1,82 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyDecoderSpec.cxx + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "ZDCWorkflow/EntropyDecoderSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +EntropyDecoderSpec::EntropyDecoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Decoder); + } +} + +void EntropyDecoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto buff = pc.inputs().get<gsl::span<o2::ctf::BufferType>>("ctf"); + + auto& bcdata = pc.outputs().make<std::vector<o2::zdc::BCData>>(OutputRef{"trig"}); + auto& chans = pc.outputs().make<std::vector<o2::zdc::ChannelData>>(OutputRef{"chan"}); + auto& peds = pc.outputs().make<std::vector<o2::zdc::OrbitData>>(OutputRef{"peds"}); + + // since the buff is const, we cannot use EncodedBlocks::relocate directly, instead we wrap its data to another flat object + const auto ctfImage = o2::zdc::CTF::getImage(buff.data()); + mCTFCoder.decode(ctfImage, bcdata, chans, peds); + + mTimer.Stop(); + LOG(INFO) << "Decoded " << chans.size() << " ZDC channels in " << bcdata.size() << " triggers and " << peds.size() << " pedestals in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "ZDC Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyDecoderSpec() +{ + std::vector<OutputSpec> outputs{ + OutputSpec{{"trig"}, "ZDC", "DIGITSBC", 0, Lifetime::Timeframe}, + OutputSpec{{"chan"}, "ZDC", "DIGITSCH", 0, Lifetime::Timeframe}, + OutputSpec{{"peds"}, "ZDC", "DIGITSPD", 0, Lifetime::Timeframe}}; + + return DataProcessorSpec{ + "zdc-entropy-decoder", + Inputs{InputSpec{"ctf", "ZDC", "CTFDATA", 0, Lifetime::Timeframe}}, + outputs, + AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF decoding dictionary"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx new file mode 100644 index 0000000000000..9cfe4434da42b --- /dev/null +++ b/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EntropyEncoderSpec.cxx +/// @brief Convert ZDC DATA to CTF (EncodedBlocks) +/// @author ruben.shahoyan@cern.ch + +#include <vector> + +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "ZDCWorkflow/EntropyEncoderSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +EntropyEncoderSpec::EntropyEncoderSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void EntropyEncoderSpec::init(o2::framework::InitContext& ic) +{ + std::string dictPath = ic.options().get<std::string>("ctf-dict"); + if (!dictPath.empty() && dictPath != "none") { + mCTFCoder.createCoders(dictPath, o2::ctf::CTFCoderBase::OpType::Encoder); + } +} + +void EntropyEncoderSpec::run(ProcessingContext& pc) +{ + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + auto bcdata = pc.inputs().get<gsl::span<o2::zdc::BCData>>("trig"); + auto chans = pc.inputs().get<gsl::span<o2::zdc::ChannelData>>("chan"); + auto peds = pc.inputs().get<gsl::span<o2::zdc::OrbitData>>("peds"); + + auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"ZDC", "CTFDATA", 0, Lifetime::Timeframe}); + mCTFCoder.encode(buffer, bcdata, chans, peds); + auto eeb = CTF::get(buffer.data()); // cast to container pointer + eeb->compactify(); // eliminate unnecessary padding + buffer.resize(eeb->size()); // shrink buffer to strictly necessary size + // eeb->print(); + mTimer.Stop(); + LOG(INFO) << "Created encoded data of size " << eeb->size() << " for ZDC in " << mTimer.CpuTime() - cput << " s"; +} + +void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) +{ + LOGF(INFO, "ZDC Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots", + mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +DataProcessorSpec getEntropyEncoderSpec() +{ + std::vector<InputSpec> inputs; + inputs.emplace_back("trig", "ZDC", "DIGITSBC", 0, Lifetime::Timeframe); + inputs.emplace_back("chan", "ZDC", "DIGITSCH", 0, Lifetime::Timeframe); + inputs.emplace_back("peds", "ZDC", "DIGITSPD", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "zdc-entropy-encoder", + inputs, + Outputs{{"ZDC", "CTFDATA", 0, Lifetime::Timeframe}}, + AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>()}, + Options{{"ctf-dict", VariantType::String, o2::base::NameConf::getCTFDictFileName(), {"File of CTF encoding dictionary"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/RecEventReaderSpec.cxx b/Detectors/ZDC/workflow/src/RecEventReaderSpec.cxx new file mode 100644 index 0000000000000..f408ce0ab3e2a --- /dev/null +++ b/Detectors/ZDC/workflow/src/RecEventReaderSpec.cxx @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecEventReaderSpec.cxx + +#include <vector> + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/Logger.h" +#include "ZDCWorkflow/RecEventReaderSpec.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +using namespace o2::framework; +using namespace o2::zdc; + +namespace o2 +{ +namespace zdc +{ + +RecEventReader::RecEventReader(bool useMC) +{ + mUseMC = useMC; + if (useMC) { + LOG(WARNING) << "ZDC RecEvent reader at the moment does not process MC"; + } +} + +void RecEventReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")), + ic.options().get<std::string>("zdc-reco-infile")); + connectTree(mInputFileName); +} + +void RecEventReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + + LOG(INFO) << "ZDC RecEventReader pushes " << mBCRecData->size() << " events with " << mBCRecData->size() << " energy, " << mZDCTDCData->size() << " TDC and " << mZDCInfo->size() << " info records at entry " << ent; + pc.outputs().snapshot(Output{"ZDC", "BCREC", 0, Lifetime::Timeframe}, *mBCRecData); + pc.outputs().snapshot(Output{"ZDC", "ENERGY", 0, Lifetime::Timeframe}, *mZDCEnergy); + pc.outputs().snapshot(Output{"ZDC", "TDCDATA", 0, Lifetime::Timeframe}, *mZDCTDCData); + pc.outputs().snapshot(Output{"ZDC", "INFO", 0, Lifetime::Timeframe}, *mZDCInfo); + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get<ControlService>().endOfStream(); + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + } +} + +void RecEventReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mRecEventTreeName.c_str())); + assert(mTree); + + mTree->SetBranchAddress(mBCRecDataBranchName.c_str(), &mBCRecData); + mTree->SetBranchAddress(mZDCEnergyBranchName.c_str(), &mZDCEnergy); + mTree->SetBranchAddress(mZDCTDCDataBranchName.c_str(), &mZDCTDCData); + mTree->SetBranchAddress(mZDCInfoBranchName.c_str(), &mZDCInfo); + if (mUseMC) { + LOG(WARNING) << "MC-truth is not supported for ZDC recpoints currently"; + mUseMC = false; + } + + LOG(INFO) << "Loaded ZDC RecEvents tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getRecEventReaderSpec(bool useMC) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back("ZDC", "BCREC", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "ENERGY", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "TDCDATA", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "INFO", 0, Lifetime::Timeframe); + if (useMC) { + LOG(WARNING) << "MC-truth is not supported for ZDC RecEvents currently"; + } + + return DataProcessorSpec{ + "zdc-reco-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask<RecEventReader>()}, + Options{ + {"zdc-reco-infile", VariantType::String, "zdcreco.root", {"Name of the input file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/RecoWorkflow.cxx b/Detectors/ZDC/workflow/src/RecoWorkflow.cxx new file mode 100644 index 0000000000000..098533cfe057f --- /dev/null +++ b/Detectors/ZDC/workflow/src/RecoWorkflow.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RecoWorkflow.cxx + +#include "ZDCWorkflow/RecoWorkflow.h" +#include "ZDCWorkflow/DigitReaderSpec.h" +#include "ZDCWorkflow/ZDCRecoWriterDPLSpec.h" +#include "ZDCWorkflow/DigitRecoSpec.h" + +namespace o2 +{ +namespace zdc +{ + +framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut) +{ + framework::WorkflowSpec specs; + if (!disableRootInp) { + specs.emplace_back(o2::zdc::getDigitReaderSpec(useMC)); + } + specs.emplace_back(o2::zdc::getDigitRecoSpec(verbosity, enableDebugOut)); + if (!disableRootOut) { + specs.emplace_back(o2::zdc::getZDCRecoWriterDPLSpec()); + } + // specs.emplace_back(o2::zdc::getReconstructionSpec(useMC)); + // if (!disableRootOut) { + // specs.emplace_back(o2::zdc::getRecPointWriterSpec(useMC)); + // } + return specs; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/ZDCDataReaderDPLSpec.cxx b/Detectors/ZDC/workflow/src/ZDCDataReaderDPLSpec.cxx new file mode 100644 index 0000000000000..058b2f7c2d474 --- /dev/null +++ b/Detectors/ZDC/workflow/src/ZDCDataReaderDPLSpec.cxx @@ -0,0 +1,102 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ZDCDataReaderDPLSpec.cxx + +#include "ZDCWorkflow/ZDCDataReaderDPLSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +ZDCDataReaderDPLSpec::ZDCDataReaderDPLSpec(const RawReaderZDC& rawReader, const bool verifyTrigger) + : mRawReader(rawReader), mVerifyTrigger(verifyTrigger) +{ +} + +void ZDCDataReaderDPLSpec::init(InitContext& ic) +{ + mccdbHost = ic.options().get<std::string>("ccdb-url"); + o2::ccdb::BasicCCDBManager::instance().setURL(mccdbHost); +} + +void ZDCDataReaderDPLSpec::run(ProcessingContext& pc) +{ + mRawReader.clear(); + + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + std::vector<InputSpec> dummy{InputSpec{"dummy", ConcreteDataMatcher{o2::header::gDataOriginZDC, o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; + for (const auto& ref : InputRecordWalker(pc.inputs(), dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + if (dh->payloadSize == 0) { + LOGP(WARNING, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, dh->payloadSize); + mRawReader.makeSnapshot(pc); // send empty output + return; + } + } + } + + DPLRawParser parser(pc.inputs(), o2::framework::select("zdc:ZDC/RAWDATA")); + + //>> update Time-dependent CCDB stuff, at the moment set the moduleconfig only once + if (!mRawReader.getModuleConfig()) { + long timeStamp = 0; + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setTimestamp(timeStamp); + auto moduleConfig = mgr.get<o2::zdc::ModuleConfig>(o2::zdc::CCDBPathConfigModule); + if (!moduleConfig) { + LOG(FATAL) << "Cannot module configuratio for timestamp " << timeStamp; + return; + } else { + LOG(INFO) << "Loaded module configuration for timestamp " << timeStamp; + } + mRawReader.setModuleConfig(moduleConfig); + mRawReader.setTriggerMask(); + mRawReader.setVerifyTrigger(mVerifyTrigger); + LOG(INFO) << "Check of trigger condition during conversion is " << (mVerifyTrigger ? "ON" : "OFF"); + } + uint64_t count = 0; + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + //Proccessing each page + count++; + auto rdhPtr = it.get_if<o2::header::RAWDataHeader>(); + gsl::span<const uint8_t> payload(it.data(), it.size()); + mRawReader.processBinaryData(payload, rdhPtr->linkID); + } + LOG(INFO) << "Pages: " << count; + mRawReader.accumulateDigits(); + mRawReader.makeSnapshot(pc); +} + +framework::DataProcessorSpec getZDCDataReaderDPLSpec(const RawReaderZDC& rawReader, const bool verifyTrigger, const bool askSTFDist) +{ + LOG(INFO) << "DataProcessorSpec initDataProcSpec() for RawReaderZDC"; + std::vector<OutputSpec> outputSpec; + RawReaderZDC::prepareOutputSpec(outputSpec); + std::vector<InputSpec> inputSpec{{"STF", ConcreteDataTypeMatcher{o2::header::gDataOriginZDC, "RAWDATA"}, Lifetime::Optional}}; + if (askSTFDist) { + inputSpec.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + return DataProcessorSpec{ + "zdc-datareader-dpl", + inputSpec, + outputSpec, + adaptFromTask<ZDCDataReaderDPLSpec>(rawReader, verifyTrigger), + Options{{"ccdb-url", o2::framework::VariantType::String, "http://ccdb-test.cern.ch:8080", {"CCDB Url"}}}}; +} +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/ZDCDigitWriterDPLSpec.cxx b/Detectors/ZDC/workflow/src/ZDCDigitWriterDPLSpec.cxx new file mode 100644 index 0000000000000..52126e6d4b7e5 --- /dev/null +++ b/Detectors/ZDC/workflow/src/ZDCDigitWriterDPLSpec.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file FT0DigitWriterSpec.cxx + +#include <vector> + +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/OrbitData.h" + +#include "ZDCWorkflow/ZDCDigitWriterDPLSpec.h" +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +DataProcessorSpec getZDCDigitWriterDPLSpec(bool mctruth, bool simVersion) +{ + std::string writerName = simVersion ? "ZDCDigitWriterSim" : "ZDCDigitWriterDec"; + std::string fnameDef = simVersion ? "zdcdigits.root" : "o2digit_zdc.root"; + + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + return MakeRootTreeWriterSpec(writerName.data(), + fnameDef.data(), + "o2sim", + BranchDefinition<std::vector<o2::zdc::BCData>>{InputSpec{"digitBCinput", "ZDC", "DIGITSBC"}, "ZDCDigitBC"}, + BranchDefinition<std::vector<o2::zdc::ChannelData>>{InputSpec{"digitChinput", "ZDC", "DIGITSCH"}, "ZDCDigitCh"}, + BranchDefinition<std::vector<o2::zdc::OrbitData>>{InputSpec{"digitPDinput", "ZDC", "DIGITSPD"}, "ZDCDigitOrbit"}, + BranchDefinition<o2::dataformats::MCTruthContainer<o2::zdc::MCLabel>>{InputSpec{"labelinput", "ZDC", "DIGITSLBL"}, "ZDCDigitLabels", mctruth ? 1 : 0})(); +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx b/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx new file mode 100644 index 0000000000000..5ecb4c5938e11 --- /dev/null +++ b/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ZDCRecoWriterDPLSpec.cxx + +#include <vector> + +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsZDC/BCRecData.h" +#include "DataFormatsZDC/ZDCEnergy.h" +#include "DataFormatsZDC/ZDCTDCData.h" + +#include "ZDCWorkflow/ZDCRecoWriterDPLSpec.h" +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +template <typename T> +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; +// Unused arguments: bool mctruth, bool simVersion +DataProcessorSpec getZDCRecoWriterDPLSpec() +{ + std::string writerName = "ZDCRecoWriter"; + std::string fnameDef = "zdcreco.root"; + + using InputSpec = framework::InputSpec; + using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; + return MakeRootTreeWriterSpec(writerName.data(), + fnameDef.data(), + "o2rec", + BranchDefinition<std::vector<o2::zdc::BCRecData>>{InputSpec{"bcrec", "ZDC", "BCREC"}, "ZDCRecBC"}, + BranchDefinition<std::vector<o2::zdc::ZDCEnergy>>{InputSpec{"energy", "ZDC", "ENERGY"}, "ZDCRecE"}, + BranchDefinition<std::vector<o2::zdc::ZDCTDCData>>{InputSpec{"tdcdata", "ZDC", "TDCDATA"}, "ZDCRecTDC"}, + BranchDefinition<std::vector<uint16_t>>{InputSpec{"info", "ZDC", "INFO"}, "ZDCRecInfo"})(); +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/digits-reader-workflow.cxx b/Detectors/ZDC/workflow/src/digits-reader-workflow.cxx new file mode 100644 index 0000000000000..698188042e5dd --- /dev/null +++ b/Detectors/ZDC/workflow/src/digits-reader-workflow.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file digits-reader-workflow.cxx +/// \brief Implementation of ZDC digits reader +/// +/// \author ruben.shahoyan@cern.ch + +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" +#include "ZDCWorkflow/DigitReaderSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + + std::vector<o2::framework::ConfigParamSpec> options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}}; + + std::string keyvaluehelp("Semicolon separated key=value strings"); + options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& ctx) +{ + WorkflowSpec specs; + + DataProcessorSpec producer = o2::zdc::getDigitReaderSpec(ctx.options().get<bool>("disable-mc")); + specs.push_back(producer); + return specs; +} diff --git a/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx b/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx new file mode 100644 index 0000000000000..5705c4236e540 --- /dev/null +++ b/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ZDCWorkflow/EntropyEncoderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + wf.emplace_back(o2::zdc::getEntropyEncoderSpec()); + return wf; +} diff --git a/Detectors/ZDC/workflow/src/o2-zdc-raw2digits.cxx b/Detectors/ZDC/workflow/src/o2-zdc-raw2digits.cxx new file mode 100644 index 0000000000000..a312f19238152 --- /dev/null +++ b/Detectors/ZDC/workflow/src/o2-zdc-raw2digits.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + std::vector<ConfigParamSpec> options{ + {"use-process", VariantType::Bool, false, {"enable processor for data taking/dumping"}}, + {"dump-blocks-process", VariantType::Bool, false, {"enable dumping of event blocks at processor side"}}, + {"dump-blocks-reader", VariantType::Bool, false, {"enable dumping of event blocks at reader side"}}, + {"disable-root-output", VariantType::Bool, false, {"disable root-files output writers"}}, + {"not-check-trigger", VariantType::Bool, false, {"avoid to check trigger condition during conversion"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ +#include "Framework/runDataProcessing.h" +#include "ZDCWorkflow/ZDCDataReaderDPLSpec.h" +#include "ZDCWorkflow/ZDCDigitWriterDPLSpec.h" +#include "ZDCRaw/RawReaderZDC.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + auto useProcessor = configcontext.options().get<bool>("use-process"); + auto dumpProcessor = configcontext.options().get<bool>("dump-blocks-process"); + auto dumpReader = configcontext.options().get<bool>("dump-blocks-reader"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto checkTrigger = true; + auto notCheckTrigger = configcontext.options().get<bool>("not-check-trigger"); + if (notCheckTrigger) { + LOG(INFO) << "Not checking trigger condition during conversion"; + checkTrigger = false; + } + auto askSTFDist = true; + auto notaskSTFDist = configcontext.options().get<bool>("ignore-dist-stf"); + if (notaskSTFDist) { + LOG(INFO) << "Not subscribing to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"; + askSTFDist = false; + } + + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + WorkflowSpec specs; + specs.emplace_back(o2::zdc::getZDCDataReaderDPLSpec(o2::zdc::RawReaderZDC{dumpReader}, checkTrigger, askSTFDist)); + // if (useProcess) { + // specs.emplace_back(o2::zdc::getZDCDataProcessDPLSpec(dumpProcessor)); + // } + if (!disableRootOut) { + specs.emplace_back(o2::zdc::getZDCDigitWriterDPLSpec(false, false)); + } + return std::move(specs); +} diff --git a/Detectors/ZDC/workflow/src/reco-writer-workflow.cxx b/Detectors/ZDC/workflow/src/reco-writer-workflow.cxx new file mode 100644 index 0000000000000..6d38b149695fa --- /dev/null +++ b/Detectors/ZDC/workflow/src/reco-writer-workflow.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ZDCWorkflow/ZDCRecoWriterDPLSpec.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "disable-mc", + o2::framework::VariantType::Bool, + false, + {"disable MC propagation even if available"}}); +} + +#include "Framework/runDataProcessing.h" +#include "Framework/Logger.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + auto useMC = !configcontext.options().get<bool>("disable-mc"); + if (useMC) { + LOG(WARNING) << "ZDC reconstruction does not support MC labels at the moment"; + } + WorkflowSpec specs{o2::zdc::getZDCRecoWriterDPLSpec()}; + return std::move(specs); +} diff --git a/Detectors/ZDC/workflow/src/zdc-reco-workflow.cxx b/Detectors/ZDC/workflow/src/zdc-reco-workflow.cxx new file mode 100644 index 0000000000000..4633b00879a24 --- /dev/null +++ b/Detectors/ZDC/workflow/src/zdc-reco-workflow.cxx @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ZDCWorkflow/RecoWorkflow.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}); + workflowOptions.push_back(ConfigParamSpec{"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}); + workflowOptions.push_back(ConfigParamSpec{"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}); + workflowOptions.push_back(ConfigParamSpec{"reco-verbosity", VariantType::Int, 0, {"reco verbosity level"}}); + workflowOptions.push_back(ConfigParamSpec{"enable-debug-output", VariantType::Bool, false, {"enable debug tree output"}}); + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); + + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + LOG(INFO) << "WorkflowSpec defineDataProcessing"; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get<std::string>("configKeyValues")); + // write the configuration used for the digitizer workflow + //o2::conf::ConfigurableParam::writeINI("o2tpcits-match-recoflow_configuration.ini"); + + auto useMC = !configcontext.options().get<bool>("disable-mc"); + auto disableRootInp = configcontext.options().get<bool>("disable-root-input"); + auto disableRootOut = configcontext.options().get<bool>("disable-root-output"); + auto verbosity = configcontext.options().get<int>("reco-verbosity"); + auto enableDebugOut = configcontext.options().get<bool>("enable-debug-output"); + + LOG(INFO) << "WorkflowSpec getRecoWorkflow useMC " << useMC; + auto wf = o2::zdc::getRecoWorkflow(useMC, disableRootInp, disableRootOut, verbosity, enableDebugOut); + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); +} diff --git a/Detectors/gconfig/CMakeLists.txt b/Detectors/gconfig/CMakeLists.txt index 77281e03b978e..043035593edcf 100644 --- a/Detectors/gconfig/CMakeLists.txt +++ b/Detectors/gconfig/CMakeLists.txt @@ -1,33 +1,39 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(G3Setup + SOURCES src/G3Config.cxx + PUBLIC_LINK_LIBRARIES MC::Geant3 FairRoot::Base O2::SimulationDataFormat O2::Generators +) + +o2_add_library(G4Setup + SOURCES src/G4Config.cxx + PUBLIC_LINK_LIBRARIES MC::Geant4VMC MC::Geant4 FairRoot::Base O2::SimulationDataFormat O2::Generators ROOT::EGPythia6 +) + +o2_add_library(FLUKASetup + SOURCES src/FlukaConfig.cxx + PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimulationDataFormat O2::Generators ROOT::EGPythia6 O2::SimSetup + ) o2_add_library(SimSetup - SOURCES src/G3Config.cxx src/G4Config.cxx - src/GlobalProcessCutSimParam.cxx src/SimSetup.cxx - PUBLIC_LINK_LIBRARIES MC::Geant3 - MC::Geant4VMC - MC::Geant4 - O2::SimulationDataFormat - O2::DetectorsPassive - O2::Generators - MC::Pythia6 # this is needed by Geant3 and - # EGPythia6 - ROOT::EGPythia6 # this is needed by Geant4 - # (TPythia6Decayer) - ) + SOURCES src/GlobalProcessCutSimParam.cxx src/SimSetup.cxx src/SetCuts.cxx src/FlukaParam.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtils O2::DetectorsBase + ) o2_target_root_dictionary(SimSetup HEADERS include/SimSetup/SimSetup.h include/SimSetup/GlobalProcessCutSimParam.h + include/SimSetup/FlukaParam.h LINKDEF src/GConfLinkDef.h) - o2_add_test_root_macro(DecayConfig.C PUBLIC_LINK_LIBRARIES O2::SimSetup LABELS simsetup) @@ -49,3 +55,6 @@ o2_add_test_root_macro(g3Config.C o2_add_test_root_macro(g4Config.C PUBLIC_LINK_LIBRARIES O2::SimSetup LABELS simsetup) + +o2_data_file(COPY data DESTINATION Detectors/gconfig/) +install(FILES src/FlukaRuntimeConfig.macro DESTINATION share/Detectors/gconfig/) diff --git a/Detectors/gconfig/SetCuts.h b/Detectors/gconfig/SetCuts.h deleted file mode 100644 index 089f7c8636d2c..0000000000000 --- a/Detectors/gconfig/SetCuts.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/******************************************************************************** - * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence version 3 (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ - -/** Configuration macro for setting common cuts and processes for G3, G4 and Fluka (M. Al-Turany 27.03.2008) - specific cuts and processes to g3 or g4 should be set in the g3Config.C, g4Config.C or flConfig.C - -*/ - -void SetCuts() -{ - cout << "SetCuts Macro: Setting Processes.." << endl; - - // ------>>>> IMPORTANT!!!! - // For a correct comparison between GEANE and MC (pull distributions) - // or for a simulation without the generation of secondary particles: - // 1. set LOSS = 2, DRAY = 0, BREM = 1 - // 2. set the following cut values: CUTGAM, CUTELE, CUTNEU, CUTHAD, CUTMUO = 1 MeV or less - // BCUTE, BCUTM, DCUTE, DCUTM, PPCUTM = 10 TeV - // (For an explanation of the chosen values, please refer to the GEANT User's Guide - // or to message #5362 in the PandaRoot Forum >> Monte Carlo Engines >> g3Config.C thread) - // - // The default settings refer to a complete simulation which generates and follows also the secondary particles. - - // \note All following settings could also be set in Cave since it is always loaded. - // Use MaterialManager to set processes and cuts - auto& mgr = MaterialManager::Instance(); - auto& params = GlobalProcessCutSimParam::Instance(); - - LOG(INFO) << "Set default settings for processes and cuts."; - mgr.DefaultProcesses({{EProc::kPAIR, params.PAIR}, /** pair production */ - {EProc::kCOMP, params.COMP}, /** Compton scattering */ - {EProc::kPHOT, params.PHOT}, /** photo electric effect */ - {EProc::kPFIS, params.PFIS}, /** photofission */ - {EProc::kDRAY, params.DRAY}, /** delta ray */ - {EProc::kANNI, params.ANNI}, /** annihilation */ - {EProc::kBREM, params.BREM}, /** bremsstrahlung */ - {EProc::kHADR, params.HADR}, /** hadronic process */ - {EProc::kMUNU, params.MUNU}, /** muon nuclear interaction */ - {EProc::kDCAY, params.DCAY}, /** decay */ - {EProc::kLOSS, params.LOSS}, /** energy loss */ - {EProc::kMULS, params.MULS}, /** multiple scattering */ - {EProc::kCKOV, params.CKOV}}); /** Cherenkov */ - - mgr.DefaultCuts({{ECut::kCUTGAM, params.CUTGAM}, /** gammas */ - {ECut::kCUTELE, params.CUTELE}, /** electrons */ - {ECut::kCUTNEU, params.CUTNEU}, /** neutral hadrons */ - {ECut::kCUTHAD, params.CUTHAD}, /** charged hadrons */ - {ECut::kCUTMUO, params.CUTMUO}, /** muons */ - {ECut::kBCUTE, params.BCUTE}, /** electron bremsstrahlung */ - {ECut::kBCUTM, params.BCUTM}, /** muon and hadron bremsstrahlung */ - {ECut::kDCUTE, params.DCUTE}, /** delta-rays by electrons */ - {ECut::kDCUTM, params.DCUTM}, /** delta-rays by muons */ - {ECut::kPPCUTM, params.PPCUTM}, /** direct pair production by muons */ - {ECut::kTOFMAX, params.TOFMAX}}); /** time of flight */ - - const char* settingProc = mgr.specialProcessesEnabled() ? "enabled" : "disabled"; - const char* settingCut = mgr.specialCutsEnabled() ? "enabled" : "disabled"; - LOG(INFO) << "Special process settings are " << settingProc << "."; - LOG(INFO) << "Special cut settings are " << settingCut << "."; -} diff --git a/Detectors/gconfig/data/coreFlukaVmc.inp b/Detectors/gconfig/data/coreFlukaVmc.inp new file mode 100755 index 0000000000000..cb3d48c9ad09f --- /dev/null +++ b/Detectors/gconfig/data/coreFlukaVmc.inp @@ -0,0 +1,29 @@ +GLOBAL 50000. 4.0 +DEFAULTS NEW-DEFA +OPEN 1. OLD +random.dat +GEOBEGIN COMBINAT +GEOEND +* +*...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+ +* +EVENTYPE 1.0 +BEAM 7000.0 MUON- +MGNFIELD 10.0 0.001 +SOURCE +*...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+ +USERDUMP 200. 37.0 -2.0 1.0 TRAKFILE +START 42000.99999999.0 2.0 +STOP + + + + + + + + + + + + diff --git a/Detectors/gconfig/g3libs.C b/Detectors/gconfig/g3libs.C index ce95807d40d08..dc9912ef54f9c 100644 --- a/Detectors/gconfig/g3libs.C +++ b/Detectors/gconfig/g3libs.C @@ -24,7 +24,7 @@ void g3libs() std::cout << "Loading Geant3 libraries ..." << std::endl; if (isLibrary("libdummies")) - gSystem->Load("libdummies.so"); + gSystem->Load("libdummies"); // libdummies.so needed from geant3_+vmc version 0.5 gSystem->Load("libgeant321"); diff --git a/Detectors/gconfig/g4config.in b/Detectors/gconfig/g4config.in index e36d1056884dd..b1a0aa626e376 100644 --- a/Detectors/gconfig/g4config.in +++ b/Detectors/gconfig/g4config.in @@ -23,7 +23,7 @@ /process/optical/processActivation Scintillation 0 /process/optical/processActivation OpWLS 0 /process/optical/processActivation OpMieHG 0 -/process/optical/setTrackSecondariesFirst Cerenkov 0 +/process/optical/cerenkov/setTrackSecondariesFirst false /mcMagField/stepperType NystromRK4 # PAI for TRD diff --git a/Detectors/gconfig/include/SimSetup/FlukaParam.h b/Detectors/gconfig/include/SimSetup/FlukaParam.h new file mode 100644 index 0000000000000..408e4e4df1471 --- /dev/null +++ b/Detectors/gconfig/include/SimSetup/FlukaParam.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author A+Morsch + +#include <string> +#ifndef ALICEO2_EVENTGEN_FLUKAPARAM_H_ +#define ALICEO2_EVENTGEN_FLUKAPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +/** + ** A parameter class/struct holding values for + ** FLUKA Transport Code + **/ +struct FlukaParam : public o2::conf::ConfigurableParamHelper<FlukaParam> { + bool activationSimulation = false; // whether FLUKA is used for activation studies + float activationHadronCut = 0.003; // hadron kinetic energy cut for activation studies + std::string scoringFile = ""; // input file for user scoring options + O2ParamDef(FlukaParam, "FlukaParam"); +}; +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_FLUKAPARAM_H_ diff --git a/Detectors/gconfig/include/SimSetup/GlobalProcessCutSimParam.h b/Detectors/gconfig/include/SimSetup/GlobalProcessCutSimParam.h index e3cc3e751c87d..c8bacfa7c4e7c 100644 --- a/Detectors/gconfig/include/SimSetup/GlobalProcessCutSimParam.h +++ b/Detectors/gconfig/include/SimSetup/GlobalProcessCutSimParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/gconfig/include/SimSetup/SimSetup.h b/Detectors/gconfig/include/SimSetup/SimSetup.h index 28f582dafd540..5bf685ab9a4f5 100644 --- a/Detectors/gconfig/include/SimSetup/SimSetup.h +++ b/Detectors/gconfig/include/SimSetup/SimSetup.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/gconfig/src/FlukaConfig.cxx b/Detectors/gconfig/src/FlukaConfig.cxx new file mode 100644 index 0000000000000..4048ca4eac0e3 --- /dev/null +++ b/Detectors/gconfig/src/FlukaConfig.cxx @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FairRunSim.h" +#include "SimulationDataFormat/Stack.h" +#include "SimulationDataFormat/StackParam.h" +#include <iostream> +#include "FairLogger.h" +#include "FairModule.h" +#include "Generators/DecayerPythia8.h" +#include "SimSetup/FlukaParam.h" +#include "../commonConfig.C" +#include "CommonUtils/ConfigurationMacroHelper.h" + +// these are used in commonConfig.C +using o2::eventgen::DecayerPythia8; + +namespace o2 +{ +namespace flukaconfig +{ + +void linkFlukaFiles() +{ + // Link here some special Fluka files needed + gSystem->Exec("ln -s $FLUKADATA/neuxsc.bin ."); + gSystem->Exec("ln -s $FLUKADATA/elasct.bin ."); + gSystem->Exec("ln -s $FLUKADATA/gxsect.bin ."); + gSystem->Exec("ln -s $FLUKADATA/nuclear.bin ."); + gSystem->Exec("ln -s $FLUKADATA/sigmapi.bin ."); + gSystem->Exec("ln -s $FLUKADATA/brems_fin.bin ."); + gSystem->Exec("ln -s $FLUKADATA/cohff.bin ."); + gSystem->Exec("ln -s $FLUKADATA/fluodt.dat ."); + gSystem->Exec("ln -s $FLUKADATA/random.dat ."); + gSystem->Exec("ln -s $FLUKADATA/dnr.dat ."); + gSystem->Exec("ln -s $FLUKADATA/nunstab.data ."); + // Give some meaningfull name to the output + gSystem->Exec("ln -s fluka.out fort.11"); + gSystem->Exec("ln -s fluka.err fort.15"); + gSystem->Exec("ln -fs $O2_ROOT/share/Detectors/gconfig/data/coreFlukaVmc.inp ."); +} + +void Config() +{ + linkFlukaFiles(); + FairRunSim* run = FairRunSim::Instance(); + // try to see if Fluka is available in the runtime + auto status = gSystem->Load("libflukavmc"); + if (status == 0 || status == 1) { + // we load Fluka as a real plugin via a ROOT Macro + auto fluka = o2::conf::GetFromMacro<TVirtualMC*>("$O2_ROOT/share/Detectors/gconfig/FlukaRuntimeConfig.macro", "FlukaRuntimeConfig()", "TVirtualMC*", "foo"); + stackSetup(fluka, run); + decayerSetup(fluka); + } else { + LOG(ERROR) << "FLUKA is not available in the runtime environment"; + LOG(ERROR) << "Please compile and load by including FLUKA_VMC/latest in the alienv package list"; + LOG(FATAL) << "Quitting here due to FLUKA_VMC not being available"; + } + return; +} + +void FlukaConfig() +{ + LOG(INFO) << "Setting up FLUKA sim from library code"; + Config(); +} +} // namespace flukaconfig +} // namespace o2 diff --git a/Detectors/gconfig/src/FlukaParam.cxx b/Detectors/gconfig/src/FlukaParam.cxx new file mode 100644 index 0000000000000..a1a218ffd8d8e --- /dev/null +++ b/Detectors/gconfig/src/FlukaParam.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "SimSetup/FlukaParam.h" +O2ParamImpl(o2::FlukaParam); diff --git a/Detectors/gconfig/src/FlukaRuntimeConfig.macro b/Detectors/gconfig/src/FlukaRuntimeConfig.macro new file mode 100644 index 0000000000000..ca1bfa776a3b4 --- /dev/null +++ b/Detectors/gconfig/src/FlukaRuntimeConfig.macro @@ -0,0 +1,22 @@ +#include "SimSetup/FlukaParam.h" + +TVirtualMC* FlukaRuntimeConfig() { + FairRunSim* run = FairRunSim::Instance(); + TString* gModel = run->GetGeoModel(); + TFluka* fluka = new TFluka("C++ Interface to Fluka", 0); + + // additional configuration paramters if requested from command line + auto& params = o2::FlukaParam::Instance(); + auto isAct = params.activationSimulation; + if (isAct) { + LOG(INFO) << "Set special FLUKA parameters for activation simulation"; + auto hadronCut = params.activationHadronCut; + auto inpFile = params.scoringFile; + fluka->SetActivationSimulation(true, hadronCut); + fluka->SetUserScoringFileName(inpFile.c_str()); + } + + std::cout << "FLUKA ptr " << fluka << "\n"; + std::cout << "VMC ptr " << TVirtualMC::GetMC() << "\n"; + return fluka; +} diff --git a/Detectors/gconfig/src/G3Config.cxx b/Detectors/gconfig/src/G3Config.cxx index 96192c0ca1705..a3115e22a8d0f 100644 --- a/Detectors/gconfig/src/G3Config.cxx +++ b/Detectors/gconfig/src/G3Config.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,39 +14,23 @@ #include "TGeant3TGeo.h" #include "SimulationDataFormat/Stack.h" #include "SimulationDataFormat/StackParam.h" -#include <iostream> #include "FairLogger.h" #include "FairModule.h" -#include <DetectorsPassive/Cave.h> -#include "DetectorsBase/MaterialManager.h" -#include "SimSetup/GlobalProcessCutSimParam.h" #include "Generators/DecayerPythia8.h" -//using declarations here since SetCuts.C and g3Config.C are included within namespace -// these are needed for SetCuts.C inclusion -using o2::GlobalProcessCutSimParam; -using o2::base::ECut; -using o2::base::EProc; -using o2::base::MaterialManager; -// these are used in g3Config.C -using std::cout; -using std::endl; // these are used in commonConfig.C using o2::eventgen::DecayerPythia8; -#include <SimSetup/SimSetup.h> namespace o2 { namespace g3config { #include "../g3Config.C" -#include "../SetCuts.h" void G3Config() { LOG(INFO) << "Setting up G3 sim from library code"; Config(); - SetCuts(); } } // namespace g3config } // namespace o2 diff --git a/Detectors/gconfig/src/G4Config.cxx b/Detectors/gconfig/src/G4Config.cxx index e6d043d10ef4b..82a84d4c1c18b 100644 --- a/Detectors/gconfig/src/G4Config.cxx +++ b/Detectors/gconfig/src/G4Config.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,18 +18,10 @@ #include "TG4RunConfiguration.h" #include "TPythia6Decayer.h" #include "FairModule.h" -#include <DetectorsPassive/Cave.h> -#include "DetectorsBase/MaterialManager.h" -#include "SimSetup/GlobalProcessCutSimParam.h" #include "SimConfig/G4Params.h" #include "Generators/DecayerPythia8.h" //using declarations here since SetCuts.C and g4Config.C are included within namespace -// these are needed for SetCuts.C inclusion -using o2::GlobalProcessCutSimParam; -using o2::base::ECut; -using o2::base::EProc; -using o2::base::MaterialManager; // these are used in g4Config.C using std::cout; using std::endl; @@ -40,13 +33,11 @@ namespace o2 namespace g4config { #include "../g4Config.C" -#include "../SetCuts.h" void G4Config() { LOG(INFO) << "Setting up G4 sim from library code"; Config(); - SetCuts(); } } // namespace g4config } // namespace o2 diff --git a/Detectors/gconfig/src/GConfLinkDef.h b/Detectors/gconfig/src/GConfLinkDef.h index e24e3e66fd7a7..64fd13f6938eb 100644 --- a/Detectors/gconfig/src/GConfLinkDef.h +++ b/Detectors/gconfig/src/GConfLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,5 +19,7 @@ #pragma link C++ class o2::conf::ConfigurableParam + ; #pragma link C++ class o2::GlobalProcessCutSimParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::GlobalProcessCutSimParam> + ; +#pragma link C++ class o2::FlukaParam+ ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::FlukaParam> + ; #endif diff --git a/Detectors/gconfig/src/GlobalProcessCutSimParam.cxx b/Detectors/gconfig/src/GlobalProcessCutSimParam.cxx index 888c97424b213..4f30020133996 100644 --- a/Detectors/gconfig/src/GlobalProcessCutSimParam.cxx +++ b/Detectors/gconfig/src/GlobalProcessCutSimParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Detectors/gconfig/src/SetCuts.cxx b/Detectors/gconfig/src/SetCuts.cxx new file mode 100644 index 0000000000000..49b25a8736a4f --- /dev/null +++ b/Detectors/gconfig/src/SetCuts.cxx @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "SetCuts.h" +#include "SimSetup/GlobalProcessCutSimParam.h" +#include "DetectorsBase/MaterialManager.h" +#include "FairLogger.h" + +using namespace o2::base; + +namespace o2 +{ + +void SetCuts() +{ + LOG(INFO) << "Setup global cuts and processes"; + + // ------>>>> IMPORTANT!!!! + // For a correct comparison between GEANE and MC (pull distributions) + // or for a simulation without the generation of secondary particles: + // 1. set LOSS = 2, DRAY = 0, BREM = 1 + // 2. set the following cut values: CUTGAM, CUTELE, CUTNEU, CUTHAD, CUTMUO = 1 MeV or less + // BCUTE, BCUTM, DCUTE, DCUTM, PPCUTM = 10 TeV + // (For an explanation of the chosen values, please refer to the GEANT User's Guide + // or to message #5362 in the PandaRoot Forum >> Monte Carlo Engines >> g3Config.C thread) + // + // The default settings refer to a complete simulation which generates and follows also the secondary particles. + + // \note All following settings could also be set in Cave since it is always loaded. + // Use MaterialManager to set processes and cuts + auto& mgr = o2::base::MaterialManager::Instance(); + auto& params = o2::GlobalProcessCutSimParam::Instance(); + + LOG(INFO) << "Set default settings for processes and cuts."; + mgr.DefaultProcesses({{EProc::kPAIR, params.PAIR}, /** pair production */ + {EProc::kCOMP, params.COMP}, /** Compton scattering */ + {EProc::kPHOT, params.PHOT}, /** photo electric effect */ + {EProc::kPFIS, params.PFIS}, /** photofission */ + {EProc::kDRAY, params.DRAY}, /** delta ray */ + {EProc::kANNI, params.ANNI}, /** annihilation */ + {EProc::kBREM, params.BREM}, /** bremsstrahlung */ + {EProc::kHADR, params.HADR}, /** hadronic process */ + {EProc::kMUNU, params.MUNU}, /** muon nuclear interaction */ + {EProc::kDCAY, params.DCAY}, /** decay */ + {EProc::kLOSS, params.LOSS}, /** energy loss */ + {EProc::kMULS, params.MULS}, /** multiple scattering */ + {EProc::kCKOV, params.CKOV}}); /** Cherenkov */ + + mgr.DefaultCuts({{ECut::kCUTGAM, params.CUTGAM}, /** gammas */ + {ECut::kCUTELE, params.CUTELE}, /** electrons */ + {ECut::kCUTNEU, params.CUTNEU}, /** neutral hadrons */ + {ECut::kCUTHAD, params.CUTHAD}, /** charged hadrons */ + {ECut::kCUTMUO, params.CUTMUO}, /** muons */ + {ECut::kBCUTE, params.BCUTE}, /** electron bremsstrahlung */ + {ECut::kBCUTM, params.BCUTM}, /** muon and hadron bremsstrahlung */ + {ECut::kDCUTE, params.DCUTE}, /** delta-rays by electrons */ + {ECut::kDCUTM, params.DCUTM}, /** delta-rays by muons */ + {ECut::kPPCUTM, params.PPCUTM}, /** direct pair production by muons */ + {ECut::kTOFMAX, params.TOFMAX}}); /** time of flight */ + + const char* settingProc = mgr.specialProcessesEnabled() ? "enabled" : "disabled"; + const char* settingCut = mgr.specialCutsEnabled() ? "enabled" : "disabled"; + LOG(INFO) << "Special process settings are " << settingProc << "."; + LOG(INFO) << "Special cut settings are " << settingCut << "."; +} + +} // namespace o2 diff --git a/Detectors/gconfig/src/SetCuts.h b/Detectors/gconfig/src/SetCuts.h new file mode 100644 index 0000000000000..3541334d1b9db --- /dev/null +++ b/Detectors/gconfig/src/SetCuts.h @@ -0,0 +1,20 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SIMSETUP_SETCUTS_H +#define O2_SIMSETUP_SETCUTS_H + +namespace o2 +{ +void SetCuts(); +} + +#endif diff --git a/Detectors/gconfig/src/SimSetup.cxx b/Detectors/gconfig/src/SimSetup.cxx index 8d8af5886a560..bb98ea5ac329c 100644 --- a/Detectors/gconfig/src/SimSetup.cxx +++ b/Detectors/gconfig/src/SimSetup.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,27 +12,53 @@ #include <cstring> #include "SimSetup/SimSetup.h" #include "FairLogger.h" +#include "SetCuts.h" +#include <dlfcn.h> +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> +#include <sstream> namespace o2 { -// forward declarations of functions -namespace g3config -{ -void G3Config(); -} -namespace g4config + +typedef void (*setup_fnc)(); + +void setupFromPlugin(const char* libname, const char* setupfuncname) { -void G4Config(); + LOG(INFO) << "Loading simulation plugin " << libname; + auto libHandle = dlopen(libname, RTLD_NOW); + // try to make the library loading a bit more portable: + if (!libHandle) { + // try appending *.so + std::stringstream stream; + stream << libname << ".so"; + libHandle = dlopen(stream.str().c_str(), RTLD_NOW); + } + if (!libHandle) { + // try appending *.dylib + std::stringstream stream; + stream << libname << ".dylib"; + libHandle = dlopen(stream.str().c_str(), RTLD_NOW); + } + assert(libHandle); + auto setup = (setup_fnc)dlsym(libHandle, setupfuncname); + assert(setup); + setup(); } void SimSetup::setup(const char* engine) { if (strcmp(engine, "TGeant3") == 0) { - g3config::G3Config(); + setupFromPlugin("libO2G3Setup", "_ZN2o28g3config8G3ConfigEv"); } else if (strcmp(engine, "TGeant4") == 0) { - g4config::G4Config(); + setupFromPlugin("libO2G4Setup", "_ZN2o28g4config8G4ConfigEv"); + } else if (strcmp(engine, "TFluka") == 0) { + setupFromPlugin("libO2FLUKASetup", "_ZN2o211flukaconfig11FlukaConfigEv"); } else { LOG(FATAL) << "Unsupported engine " << engine; } + o2::SetCuts(); } } // namespace o2 diff --git a/EventVisualisation/Base/CMakeLists.txt b/EventVisualisation/Base/CMakeLists.txt index 229aa5adf6c98..0b690afab4aac 100644 --- a/EventVisualisation/Base/CMakeLists.txt +++ b/EventVisualisation/Base/CMakeLists.txt @@ -1,21 +1,24 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EventVisualisationBase SOURCES src/ConfigurationManager.cxx src/DataInterpreter.cxx + src/DataReader.cxx src/DataSourceOffline.cxx + src/DataSourceOnline.cxx src/GeometryManager.cxx + src/FileWatcher.cxx PUBLIC_LINK_LIBRARIES ROOT::Eve O2::CCDB O2::EventVisualisationDataConverter - O2::DetectorsBase - + O2::DetectorsBase ) diff --git a/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h b/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h index 781f63d7504de..8df289b118ccc 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/Base/include/EventVisualisationBase/DataInterpreter.h b/EventVisualisation/Base/include/EventVisualisationBase/DataInterpreter.h index 3568492c0fd98..7cc9a6cc68915 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/DataInterpreter.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/DataInterpreter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,7 +55,7 @@ class DataInterpreter } // Should return visualisation objects for required data type - virtual std::unique_ptr<VisualisationEvent> interpretDataForType(TObject* data, EVisualisationDataType type) = 0; + virtual VisualisationEvent interpretDataForType(TObject* data, EVisualisationDataType type) = 0; static DataInterpreter* getInstance(EVisualisationGroup type) { return instance[type]; } //static void setInstance(DataInterpreter* instance, EVisualisationGroup type) { DataInterpreter::instance[type] = instance; } diff --git a/EventVisualisation/Base/include/EventVisualisationBase/DataReader.h b/EventVisualisation/Base/include/EventVisualisationBase/DataReader.h index 27b95bc51e1f6..a867fec4edaf5 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/DataReader.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/DataReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,9 @@ #ifndef ALICE_O2_EVENTVISUALISATION_BASE_DATAREADER_H #define ALICE_O2_EVENTVISUALISATION_BASE_DATAREADER_H +#include "EventVisualisationDataConverter/VisualisationEvent.h" +#include "EventVisualisationBase/DataInterpreter.h" + class TObject; namespace o2 @@ -24,11 +28,15 @@ namespace event_visualisation class DataReader { + DataInterpreter* mInterpreter; + virtual TObject* getEventData(int /*no*/) { return nullptr; }; + public: + DataReader(DataInterpreter* interpreter); virtual int GetEventCount() const = 0; virtual ~DataReader() = default; virtual void open() = 0; - virtual TObject* getEventData(int no) = 0; + virtual VisualisationEvent getEvent(int no, EVisualisationDataType dataType); }; } // namespace event_visualisation diff --git a/EventVisualisation/Base/include/EventVisualisationBase/DataSource.h b/EventVisualisation/Base/include/EventVisualisationBase/DataSource.h index ba0be3f206b52..2254930b6ad48 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/DataSource.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/DataSource.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,9 @@ #define ALICE_O2_EVENTVISUALISATION_BASE_DATASOURCE_H #include <EventVisualisationBase/VisualisationConstants.h> +#include <EventVisualisationBase/DataReader.h> +#include <EventVisualisationDataConverter/VisualisationEvent.h> +#include <utility> class TObject; @@ -28,9 +32,10 @@ namespace event_visualisation class DataSource { public: - virtual TObject* getEventData(int /*no*/, EVisualisationGroup /*purpose*/) { return nullptr; }; - virtual int GetEventCount() { return 0; }; - + virtual Int_t getCurrentEvent() { return 0; }; + virtual void setCurrentEvent(Int_t /*currentEvent*/){}; + virtual int getEventCount() { return 0; }; + virtual bool refresh() { return false; }; // recompute DataSource() = default; /// Default destructor @@ -41,6 +46,9 @@ class DataSource /// Deleted assignemt operator void operator=(DataSource const&) = delete; + + virtual std::vector<std::pair<VisualisationEvent, std::string>> getVisualisationList(int no) = 0; + virtual void registerDetector(DataReader* /*reader*/, EVisualisationGroup /*type*/){}; }; } // namespace event_visualisation diff --git a/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOffline.h b/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOffline.h index eb36151b51e20..2c78432b65d0d 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOffline.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOffline.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,25 +30,26 @@ namespace event_visualisation class DataSourceOffline : public DataSource { protected: - static DataReader* instance[EVisualisationGroup::NvisualisationGroups]; + Int_t mCurrentEvent = 0; + DataReader* mDataReaders[EVisualisationGroup::NvisualisationGroups]; + VisualisationEvent getEventData(int no, EVisualisationGroup purpose, EVisualisationDataType dataType); public: - DataSourceOffline() = default; + DataSourceOffline(); ~DataSourceOffline() override = default; DataSourceOffline(DataSourceOffline const&) = delete; + void setCurrentEvent(Int_t currentEvent) override; + Int_t getCurrentEvent() override; /// Deleted assigment operator void operator=(DataSourceOffline const&) = delete; - int GetEventCount() override; + int getEventCount() override; - void registerReader(DataReader* reader, EVisualisationGroup purpose) - { - instance[purpose] = reader; - } + void registerReader(DataReader* reader, EVisualisationGroup type); - TObject* getEventData(int no, EVisualisationGroup purpose) override; + std::vector<std::pair<VisualisationEvent, std::string>> getVisualisationList(int no) override; }; } // namespace event_visualisation diff --git a/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOnline.h b/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOnline.h new file mode 100644 index 0000000000000..bc0b3a6f8c595 --- /dev/null +++ b/EventVisualisation/Base/include/EventVisualisationBase/DataSourceOnline.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataSourceOnline.h +/// \brief Grouping reading from file(s) +/// \author julian.myrcha@cern.ch + +#ifndef O2EVE_DATASOURCEONLINE_H +#define O2EVE_DATASOURCEONLINE_H + +#include <EventVisualisationBase/DataSource.h> +#include <EventVisualisationBase/DataReader.h> +#include <EventVisualisationBase/FileWatcher.h> + +class TObject; + +namespace o2 +{ +namespace event_visualisation +{ + +class DataSourceOnline : public DataSource +{ + protected: + FileWatcher mFileWatcher; + + public: + DataSourceOnline(const std::string path); + + ~DataSourceOnline() override = default; + DataSourceOnline(DataSourceOnline const&) = delete; + + /// Deleted assigment operator + void operator=(DataSourceOnline const&) = delete; + + int getEventCount() override; + void setCurrentEvent(Int_t currentEvent) override; + Int_t getCurrentEvent() override; + + bool refresh() override; // recompute + + std::vector<std::pair<VisualisationEvent, std::string>> getVisualisationList(int no) override; +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif //O2EVE_DATASOURCEONLINE_H diff --git a/EventVisualisation/Base/include/EventVisualisationBase/FileWatcher.h b/EventVisualisation/Base/include/EventVisualisationBase/FileWatcher.h new file mode 100644 index 0000000000000..2e17fd6537904 --- /dev/null +++ b/EventVisualisation/Base/include/EventVisualisationBase/FileWatcher.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file FileWatcher.h +/// \brief Observing folder for created and removed files - preserving current +/// \author julian.myrcha@cern.ch + +#ifndef WATCHER_FILEWATCHER_H +#define WATCHER_FILEWATCHER_H + +#include <string> +#include <deque> + +namespace o2 +{ +namespace event_visualisation +{ + +class FileWatcher +{ + static const char* mLowGuard; ///< "artificial" file name meaning "on the first" (guard) + static const char* mEndGard; ///< "artificial" file name meaning "on the last" (guard) + std::deque<std::string> mFiles; ///< sorted file list with guards at the beginning and end + std::string nextItem(const std::string& item) const; + std::string prevItem(const std::string& item) const; + static std::deque<std::string> load(const std::string path); + std::string mDataFolder; ///< folder being observed + std::string mCurrentFile; ///< "current" file name + bool currentFileExist(); + + public: + FileWatcher(const std::string& path); + int getSize() const; ///< include guards (so >=2 ) + int getPos() const; ///< include guards -> 0 points to mLowGuard + void setFirst(); + void setLast(); + void setNext(); + void setPrev(); + bool refresh(); ///< reads folder content, updates current if points to not existing file + std::string currentItem() const; ///< name of the file (without path) but guards replaced with file names + void setCurrentItem(int no); ///< sets using index + std::string currentFilePath() const; ///< name of the file (with path) but guards replaced with file names +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif //WATCHER_FILEWATCHER_H diff --git a/EventVisualisation/Base/include/EventVisualisationBase/GeometryManager.h b/EventVisualisation/Base/include/EventVisualisationBase/GeometryManager.h index c29175e2f72e3..a5405282d455a 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/GeometryManager.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/GeometryManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/Base/include/EventVisualisationBase/VisualisationConstants.h b/EventVisualisation/Base/include/EventVisualisationBase/VisualisationConstants.h index 1bb9ef1ca8f5d..4135183543fff 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/VisualisationConstants.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/VisualisationConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,7 @@ enum EVisualisationGroup { TRD, RND, VSD, + JSON, NvisualisationGroups }; @@ -58,7 +60,8 @@ const std::string gVisualisationGroupName[NvisualisationGroups] = { "TPC", "TRD", "RND", - "VSD"}; + "VSD", + "JSON"}; const bool R2Visualisation[NvisualisationGroups] = { true, //"ACO", @@ -75,7 +78,8 @@ const bool R2Visualisation[NvisualisationGroups] = { true, //"TPC", true, //"TRD", true, //"RND", - true //"VSD" + true, //"VSD" + true //"JSON" }; const bool R3Visualisation[NvisualisationGroups] = { @@ -93,7 +97,8 @@ const bool R3Visualisation[NvisualisationGroups] = { true, //"TPC", false, //"TRD", false, //"RND", - false //"VSD" + false, //"VSD" + true //"JSON" }; enum EVisualisationDataType { diff --git a/EventVisualisation/Base/src/ConfigurationManager.cxx b/EventVisualisation/Base/src/ConfigurationManager.cxx index 77a4619e02a48..4070585e80bd2 100644 --- a/EventVisualisation/Base/src/ConfigurationManager.cxx +++ b/EventVisualisation/Base/src/ConfigurationManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/Base/src/DataInterpreter.cxx b/EventVisualisation/Base/src/DataInterpreter.cxx index f74d09c1ab72c..9e61a65f308a7 100644 --- a/EventVisualisation/Base/src/DataInterpreter.cxx +++ b/EventVisualisation/Base/src/DataInterpreter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/Base/src/DataReader.cxx b/EventVisualisation/Base/src/DataReader.cxx new file mode 100644 index 0000000000000..ef40d985f9ab5 --- /dev/null +++ b/EventVisualisation/Base/src/DataReader.cxx @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DataInterpreter.cxx +/// \author julian.myrcha@cern.ch + +#include "EventVisualisationBase/DataReader.h" +#include "FairLogger.h" + +using namespace std; + +namespace o2 +{ +namespace event_visualisation +{ + +DataReader::DataReader(DataInterpreter* interpreter) : mInterpreter(interpreter) +{ +} + +VisualisationEvent DataReader::getEvent(int no, EVisualisationDataType dataType) +{ + TObject* data = this->getEventData(no); + VisualisationEvent event = mInterpreter->interpretDataForType(data, dataType); + return event; +} + +} // namespace event_visualisation +} // namespace o2 diff --git a/EventVisualisation/Base/src/DataSourceOffline.cxx b/EventVisualisation/Base/src/DataSourceOffline.cxx index 9f5021c9d6759..13e53ad0bdb35 100644 --- a/EventVisualisation/Base/src/DataSourceOffline.cxx +++ b/EventVisualisation/Base/src/DataSourceOffline.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,30 +29,79 @@ #include <TVector3.h> #include <TObject.h> +#define elemof(e) (unsigned int)(sizeof(e) / sizeof(e[0])) + namespace o2 { namespace event_visualisation { -DataReader* DataSourceOffline::instance[EVisualisationGroup::NvisualisationGroups]; - -TObject* DataSourceOffline::getEventData(int no, EVisualisationGroup purpose) +VisualisationEvent DataSourceOffline::getEventData(int no, EVisualisationGroup purpose, EVisualisationDataType dataType) { - if (instance[purpose] == nullptr) { - return nullptr; + if (mDataReaders[purpose] == nullptr) { + return VisualisationEvent({.eventNumber = -1, + .runNumber = -1, + .energy = -1, + .multiplicity = -1, + .collidingSystem = "", + .timeStamp = 0}); } - return instance[purpose]->getEventData(no); + return mDataReaders[purpose]->getEvent(no, dataType); } -int DataSourceOffline::GetEventCount() +int DataSourceOffline::getEventCount() { for (int i = 0; i < EVisualisationGroup::NvisualisationGroups; i++) { - if (instance[i] != nullptr) { - return instance[i]->GetEventCount(); + if (mDataReaders[i] != nullptr) { + return mDataReaders[i]->GetEventCount(); } } return 1; }; +void DataSourceOffline::setCurrentEvent(Int_t currentEvent) +{ + this->mCurrentEvent = currentEvent; +} + +std::vector<std::pair<VisualisationEvent, std::string>> DataSourceOffline::getVisualisationList(int no) +{ + std::vector<std::pair<VisualisationEvent, std::string>> res; + for (int i = 0; i < EVisualisationGroup::NvisualisationGroups; ++i) { + DataReader* reader = mDataReaders[i]; + if (reader) { + for (int dataType = 0; dataType < EVisualisationDataType::NdataTypes; ++dataType) { + VisualisationEvent event = getEventData(no, (EVisualisationGroup)i, (EVisualisationDataType)dataType); + res.push_back(std::make_pair(event, gVisualisationGroupName[i])); + } + } + } + + return res; +} + +DataSourceOffline::DataSourceOffline() +{ + for (unsigned int i = 0; i < elemof(mDataReaders); i++) { + mDataReaders[i] = nullptr; + } + for (int i = 0; i < EVisualisationGroup::NvisualisationGroups; i++) { + if (mDataReaders[i] != nullptr) { + mDataReaders[i]->open(); + this->registerReader(mDataReaders[i], static_cast<EVisualisationGroup>(i)); + } + } +} + +void DataSourceOffline::registerReader(DataReader* reader, EVisualisationGroup type) +{ + mDataReaders[type] = reader; +} + +Int_t DataSourceOffline::getCurrentEvent() +{ + return this->mCurrentEvent; +} + } // namespace event_visualisation } // namespace o2 diff --git a/EventVisualisation/Base/src/DataSourceOnline.cxx b/EventVisualisation/Base/src/DataSourceOnline.cxx new file mode 100644 index 0000000000000..67ef138613f79 --- /dev/null +++ b/EventVisualisation/Base/src/DataSourceOnline.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataSourceOnline.h +/// \brief Grouping reading from file(s) +/// \author julian.myrcha@cern.ch + +#include <EventVisualisationBase/DataSourceOnline.h> + +#include <TSystem.h> +#include <TEveTreeTools.h> +#include <TEveTrack.h> +#include <TEveManager.h> +#include <TFile.h> +#include <TPRegexp.h> +#include <TEveTrackPropagator.h> +#include <TEveVSD.h> +#include <TObject.h> + +namespace o2 +{ +namespace event_visualisation +{ + +std::vector<std::pair<VisualisationEvent, std::string>> DataSourceOnline::getVisualisationList(int no) +{ + std::vector<std::pair<VisualisationEvent, std::string>> res; + if (no < getEventCount()) { + assert(no >= 0); + VisualisationEvent vEvent; + mFileWatcher.setCurrentItem(no); + vEvent.fromFile(mFileWatcher.currentFilePath()); + res.push_back(std::make_pair(vEvent, gVisualisationGroupName[EVisualisationGroup::TPC])); + } + return res; +} + +DataSourceOnline::DataSourceOnline(const std::string path) : mFileWatcher(path) +{ +} + +int DataSourceOnline::getEventCount() +{ + return this->mFileWatcher.getSize(); +} + +void DataSourceOnline::setCurrentEvent(Int_t currentEvent) +{ + this->mFileWatcher.setCurrentItem(currentEvent); +} + +bool DataSourceOnline::refresh() +{ + return this->mFileWatcher.refresh(); +} + +Int_t DataSourceOnline::getCurrentEvent() +{ + return mFileWatcher.getPos(); +} + +} // namespace event_visualisation +} // namespace o2 diff --git a/EventVisualisation/Base/src/FileWatcher.cxx b/EventVisualisation/Base/src/FileWatcher.cxx new file mode 100644 index 0000000000000..f33dd7c5b9694 --- /dev/null +++ b/EventVisualisation/Base/src/FileWatcher.cxx @@ -0,0 +1,167 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file FileWatcher.h +/// \brief Observing folder for created and removed files - preserving current +/// \author julian.myrcha@cern.ch + +#include "EventVisualisationBase/FileWatcher.h" +#include "FairLogger.h" + +#include <list> +#include <filesystem> +#include <algorithm> +#include <sys/stat.h> +using namespace std; + +namespace o2 +{ +namespace event_visualisation +{ + +const char* FileWatcher::mLowGuard = " 0"; /// start guard +const char* FileWatcher::mEndGard = "~0"; /// stop guard + +deque<string> FileWatcher::load(string path) +{ + LOG(INFO) << "FileWatcher::load(" << path << ")"; + deque<string> result; + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (entry.path().extension() == ".json") { + result.push_back(entry.path().filename()); + } + } + LOG(INFO) << result.size(); + return result; +} + +FileWatcher::FileWatcher(const string& path) +{ + LOG(INFO) << "FileWatcher::FileWatcher(" << path << ")"; + this->mDataFolder = path; + this->mCurrentFile = mLowGuard; + this->mFiles.clear(); + this->mFiles.push_front(mLowGuard); + this->mFiles.push_back(mEndGard); + LOG(INFO) << "FileWatcher" << this->getSize(); +} + +string FileWatcher::nextItem(const string& item) const +{ + if (item == mEndGard) { + return mEndGard; + } + return *(std::find(this->mFiles.begin(), this->mFiles.end(), item) + 1); +} + +string FileWatcher::prevItem(const string& item) const +{ + if (item == mLowGuard) { + return mLowGuard; + } + return *(std::find(mFiles.begin(), mFiles.end(), item) - 1); +} + +string FileWatcher::currentItem() const +{ + if (this->mFiles.size() == 2) { // only guards on the list + return ""; + } + if (this->mCurrentFile == mLowGuard) { + return *(this->mFiles.begin() + 1); + } + if (this->mCurrentFile == mEndGard) { + return *(this->mFiles.end() - 2); + } + return this->mCurrentFile; +} + +void FileWatcher::setFirst() +{ + this->mCurrentFile = mLowGuard; +} + +void FileWatcher::setLast() +{ + this->mCurrentFile = mEndGard; +} + +void FileWatcher::setNext() +{ + this->mCurrentFile = nextItem(this->mCurrentFile); +} + +void FileWatcher::setPrev() +{ + this->mCurrentFile = prevItem(this->mCurrentFile); +} + +int FileWatcher::getSize() const +{ + return this->mFiles.size(); // guards +} + +int FileWatcher::getPos() const +{ + return std::distance(mFiles.begin(), std::find(mFiles.begin(), mFiles.end(), this->mCurrentFile)); +} + +bool FileWatcher::refresh() +{ + string previous = this->currentItem(); + LOG(INFO) << "previous:" << previous; + LOG(INFO) << "currentFile:" << this->mCurrentFile; + + this->mFiles = load(this->mDataFolder); + std::sort(this->mFiles.begin(), this->mFiles.end()); + if (this->mCurrentFile != mEndGard) { + if (this->mFiles.empty()) { + this->mCurrentFile = mEndGard; // list empty - stick to last element + } else if (this->mCurrentFile < *(this->mFiles.begin())) { + this->mCurrentFile = mLowGuard; // lower then first => go to first + } else { + auto it = std::find(mFiles.begin(), mFiles.end(), this->mCurrentFile); + if (it == this->mFiles.end()) { + this->mCurrentFile = mEndGard; // not on the list -> go to last element + } + } + } + for (auto it = this->mFiles.begin(); it != this->mFiles.end(); ++it) { + LOG(INFO) << *it; + } + this->mFiles.push_front(mLowGuard); + this->mFiles.push_back(mEndGard); + + LOG(INFO) << "this->mFiles.size() = " << this->mFiles.size(); + LOG(INFO) << "this->mCurrentFile = " << this->mCurrentFile; + LOG(INFO) << "current:" << this->currentItem(); + return previous != this->currentItem(); +} + +void FileWatcher::setCurrentItem(int no) +{ + this->mCurrentFile = this->mFiles[no]; + LOG(INFO) << "this->setCurrentItem(" << no << ")"; + LOG(INFO) << "this->mCurrentFile = " << this->mCurrentFile; +} + +std::string FileWatcher::currentFilePath() const +{ + return this->mDataFolder + "/" + this->currentItem(); +} + +bool FileWatcher::currentFileExist() +{ + struct stat buffer; + return (stat(this->currentFilePath().c_str(), &buffer) == 0); +} +} // namespace event_visualisation +} // namespace o2 diff --git a/EventVisualisation/Base/src/GeometryManager.cxx b/EventVisualisation/Base/src/GeometryManager.cxx index 92c595478c6d6..a732c0609d619 100644 --- a/EventVisualisation/Base/src/GeometryManager.cxx +++ b/EventVisualisation/Base/src/GeometryManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/CMakeLists.txt b/EventVisualisation/CMakeLists.txt index 73828a9961a30..ea5b5f2c187f3 100644 --- a/EventVisualisation/CMakeLists.txt +++ b/EventVisualisation/CMakeLists.txt @@ -1,14 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(DataConverter) add_subdirectory(Base) add_subdirectory(Detectors) add_subdirectory(View) +add_subdirectory(Workflow) + diff --git a/EventVisualisation/DataConverter/CMakeLists.txt b/EventVisualisation/DataConverter/CMakeLists.txt index 7d8139ecca9f7..3495ebab84022 100644 --- a/EventVisualisation/DataConverter/CMakeLists.txt +++ b/EventVisualisation/DataConverter/CMakeLists.txt @@ -1,16 +1,18 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EventVisualisationDataConverter SOURCES src/VisualisationEvent.cxx src/VisualisationTrack.cxx src/VisualisationCluster.cxx - + PUBLIC_LINK_LIBRARIES RapidJSON::RapidJSON + O2::ReconstructionDataFormats ) diff --git a/EventVisualisation/DataConverter/README.md b/EventVisualisation/DataConverter/README.md new file mode 100644 index 0000000000000..09d19f97f14c8 --- /dev/null +++ b/EventVisualisation/DataConverter/README.md @@ -0,0 +1,7 @@ +<!-- doxy +\page refEventVisualisationDataConverter EventVisualisation DataConverter +/doxy --> + +# Event Visualisation DataConverter + +A description of this module is not yet available. diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/ConversionConstants.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/ConversionConstants.h index 2d69cbee1f2bb..9e4162a54c538 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/ConversionConstants.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/ConversionConstants.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h index 81e36d813ea92..73e9388baae8b 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #define ALICE_O2_DATACONVERTER_VISUALISATIONCLUSTER_H #include "EventVisualisationDataConverter/VisualisationTrack.h" +#include "rapidjson/document.h" #include <vector> #include <ctime> @@ -35,18 +37,19 @@ namespace event_visualisation class VisualisationCluster { public: - // Default constructor - VisualisationCluster(double XYZ[]); + VisualisationCluster(rapidjson::Value& tree); + rapidjson::Value jsonTree(rapidjson::Document::AllocatorType& allocator); - double X() const { return mCoordinates[0]; } - double Y() const { return mCoordinates[1]; } - double Z() const { return mCoordinates[2]; } + // Default constructor + VisualisationCluster(float XYZ[]); - private: - void setCoordinates(double xyz[3]); - double mCoordinates[3]; /// Vector of cluster's coordinates + float X() const { return mCoordinates[0]; } + float Y() const { return mCoordinates[1]; } + float Z() const { return mCoordinates[2]; } private: + void setCoordinates(float xyz[3]); + float mCoordinates[3]; /// Vector of cluster's coordinates }; } // namespace event_visualisation } // namespace o2 diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h index 21ea814c6c723..9dc4827ffb58b 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include "EventVisualisationDataConverter/VisualisationTrack.h" #include "EventVisualisationDataConverter/VisualisationCluster.h" -#include <vector> +#include <forward_list> #include <ctime> namespace o2 @@ -37,27 +38,86 @@ namespace event_visualisation class VisualisationEvent { public: + std::string toJson(); + void fromJson(std::string json); + bool fromFile(std::string fileName); + VisualisationEvent() = default; + VisualisationEvent(std::string fileName); + void toFile(std::string fileName); + static std::string fileNameIndexed(const std::string fileName, const int index); + + //VisualisationEvent() {} + + /// constructor parametrisation (Value Object) for VisualisationEvent class + /// + /// Simplifies passing parameters to constructor of VisualisationEvent + /// by providing their names + struct VisualisationEventVO { + int eventNumber; + int runNumber; + double energy; + int multiplicity; + std::string collidingSystem; + time_t timeStamp; + }; // Default constructor - VisualisationEvent(int eventNumber, int runNumber, double energy, int multiplicity, std::string collidingSystem, time_t timeStamp); + VisualisationEvent(const VisualisationEventVO vo); // Adds visualisation track inside visualisation event - void addTrack(const VisualisationTrack& track) { mTracks.push_back(track); } + //void addTrack(const VisualisationTrack& track) + //{ mTracks.push_back(track); } + + VisualisationTrack* addTrack(VisualisationTrack::VisualisationTrackVO vo) + { + mTracks.emplace_back(vo); + return &mTracks.back(); + } + void remove_last_track() { mTracks.pop_back(); } // used to remove track assigned optimistically + + // Adds visualisation cluster inside visualisation event - // Adds visualisation cluser inside visualisation event - void addCluster(const VisualisationCluster& cluster) { mClusters.push_back(cluster); } + VisualisationCluster& addCluster(float XYZ[]) + { + mClusters.emplace_back(XYZ); + return mClusters.back(); + } + + VisualisationCluster& addCluster(float X, float Y, float Z) + { + float pos[] = {X, Y, Z}; + mClusters.emplace_back(pos); + return mClusters.back(); + } // Multiplicity getter - int GetMultiplicity() const { return mMultiplicity; } + int GetMultiplicity() const + { + return mMultiplicity; + } // Returns track with index i - const VisualisationTrack& getTrack(int i) const { return mTracks[i]; }; + const VisualisationTrack& getTrack(int i) const + { + return mTracks[i]; + }; + // Returns number of tracks - size_t getTrackCount() const { return mTracks.size(); } + size_t getTrackCount() const + { + return mTracks.size(); + } // Returns cluster with index i - const VisualisationCluster& getCluster(int i) const { return mClusters[i]; }; + const VisualisationCluster& getCluster(int i) const + { + return mClusters[i]; + }; + // Returns number of clusters - size_t getClusterCount() const { return mClusters.size(); } + size_t getClusterCount() const + { + return mClusters.size(); + } private: int mEventNumber; /// event number in file diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationTrack.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationTrack.h index 82747545510ff..0e0cc226a367f 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationTrack.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,12 +13,15 @@ /// \file VisualisationTrack.h /// \author Jeremi Niedziela /// \author Maciej Grochowicz +/// \author Julian Myrcha /// #ifndef ALICE_O2_EVENTVISUALISATION_BASE_VISUALISATIONTRACK_H #define ALICE_O2_EVENTVISUALISATION_BASE_VISUALISATIONTRACK_H +#include "ReconstructionDataFormats/GlobalTrackID.h" #include "ConversionConstants.h" +#include "rapidjson/document.h" #include <iosfwd> #include <string> @@ -41,76 +45,62 @@ class VisualisationTrack public: // Default constructor VisualisationTrack(); - + // create track from their JSON representation + VisualisationTrack(rapidjson::Value& tree); + // create JSON representation of the track + rapidjson::Value jsonTree(rapidjson::Document::AllocatorType& allocator); + + /// constructor parametrisation (Value Object) for VisualisationTrack class + /// + /// Simplifies passing parameters to constructor of VisualisationTrack + /// by providing their names + struct VisualisationTrackVO { + float time; + int charge; + int PID; + float startXYZ[3]; + float phi; + float theta; + o2::dataformats::GlobalTrackID::Source source; + }; // Constructor with properties initialisation - VisualisationTrack( - int charge, - double energy, - int ID, - int PID, - double mass, - double signedPT, - double startXYZ[], - double endXYZ[], - double pxpypz[], - int parentID, - double phi, - double theta, - double helixCurvature, - int type); + VisualisationTrack(const VisualisationTrackVO& vo); // Add child particle (coming from decay of this particle) void addChild(int childID); // Add xyz coordinates of the point along the track - void addPolyPoint(double x, double y, double z); - // Add xyz coordinates of the point along the track - void addPolyPoint(double xyz[3]); - // Track type setter (standard track, V0, kink, cascade) - void setTrackType(ETrackType type); - - // Vertex getter - double* getVertex() { return mStartCoordinates; } - // Momentum vector getter - double* getMomentum() { return mMomentum; } - // Beta (velocity) getter - double getBeta() const { return sqrt(1 - std::pow(mMass / mEnergy, 2)); } + void addPolyPoint(float x, float y, float z); + // Time getter + float getTime() const { return mTime; } // Charge getter int getCharge() const { return mCharge; } // PID (particle identification code) getter int getPID() const { return mPID; } size_t getPointCount() const { return mPolyX.size(); } - std::array<double, 3> getPoint(size_t i) const { return std::array<double, 3>{mPolyX[i], mPolyY[i], mPolyZ[i]}; } + std::array<float, 3> getPoint(size_t i) const { return std::array<float, 3>{mPolyX[i], mPolyY[i], mPolyZ[i]}; } private: // Set coordinates of the beginning of the track - void addStartCoordinates(double xyz[3]); - // Set coordinates of the end of the track - void addEndCoordinates(double xyz[3]); - /// Set momentum vector - void addMomentum(double pxpypz[3]); - - int mID; /// Unique identifier of the track - std::string mType; /// Type (standard, V0 mother, daughter etc.) + void addStartCoordinates(const float xyz[3]); + + float mTime; /// track time int mCharge; /// Charge of the particle - double mEnergy; /// Energy of the particle - int mParentID; /// ID of the parent-track (-1 means no parent) + int mPID; /// PDG code of the particle - double mSignedPT; /// Signed transverse momentum - double mMass; /// Mass of the particle - double mMomentum[3]; /// Momentum vector + double mStartCoordinates[3]; /// Vector of track's start coordinates - double mEndCoordinates[3]; /// Vector of track's end coordinates - double mHelixCurvature; /// Helix curvature of the trajectory + double mTheta; /// An angle from Z-axis to the radius vector pointing to the particle double mPhi; /// An angle from X-axis to the radius vector pointing to the particle - std::vector<int> mChildrenIDs; /// Uniqe IDs of children particles + // std::vector<int> mChildrenIDs; /// Uniqe IDs of children particles + o2::dataformats::GlobalTrackID::Source mSource; /// data source of the track (debug) /// Polylines -- array of points along the trajectory of the track - std::vector<double> mPolyX; - std::vector<double> mPolyY; - std::vector<double> mPolyZ; + std::vector<float> mPolyX; + std::vector<float> mPolyY; + std::vector<float> mPolyZ; }; } // namespace event_visualisation diff --git a/EventVisualisation/DataConverter/src/VisualisationCluster.cxx b/EventVisualisation/DataConverter/src/VisualisationCluster.cxx index 0b287a14a2573..c5216992d9b6f 100644 --- a/EventVisualisation/DataConverter/src/VisualisationCluster.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationCluster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,17 +24,43 @@ namespace o2 namespace event_visualisation { -VisualisationCluster::VisualisationCluster(double XYZ[]) +VisualisationCluster::VisualisationCluster(float XYZ[]) { setCoordinates(XYZ); } -void VisualisationCluster::setCoordinates(double xyz[3]) +void VisualisationCluster::setCoordinates(float xyz[3]) { for (int i = 0; i < 3; i++) { mCoordinates[i] = xyz[i]; } } +VisualisationCluster::VisualisationCluster(rapidjson::Value& tree) +{ + rapidjson::Value& jsonX = tree["X"]; + rapidjson::Value& jsonY = tree["Y"]; + rapidjson::Value& jsonZ = tree["Z"]; + + this->mCoordinates[0] = jsonX.GetDouble(); + this->mCoordinates[1] = jsonY.GetDouble(); + this->mCoordinates[2] = jsonZ.GetDouble(); +} + +rapidjson::Value VisualisationCluster::jsonTree(rapidjson::MemoryPoolAllocator<>& allocator) +{ + rapidjson::Value tree(rapidjson::kObjectType); + rapidjson::Value jsonX(rapidjson::kNumberType); + rapidjson::Value jsonY(rapidjson::kNumberType); + rapidjson::Value jsonZ(rapidjson::kNumberType); + jsonX.SetDouble(mCoordinates[0]); + jsonY.SetDouble(mCoordinates[1]); + jsonZ.SetDouble(mCoordinates[2]); + tree.AddMember("X", jsonX, allocator); + tree.AddMember("Y", jsonY, allocator); + tree.AddMember("Z", jsonZ, allocator); + return tree; +} + } // namespace event_visualisation } // namespace o2 diff --git a/EventVisualisation/DataConverter/src/VisualisationEvent.cxx b/EventVisualisation/DataConverter/src/VisualisationEvent.cxx index d68ec8c8fadef..4c671297551f4 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEvent.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEvent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,27 +16,131 @@ /// #include "EventVisualisationDataConverter/VisualisationEvent.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" + +#include <string> +#include <sstream> +#include <fstream> +#include <iostream> +#include <iomanip> using namespace std; +using namespace rapidjson; namespace o2 { namespace event_visualisation { +constexpr int JSON_FILE_VERSION = 1; /// Ctor -- set the minimalistic event up -VisualisationEvent::VisualisationEvent(int eventNumber, - int runNumber, - double energy, - int multiplicity, - string collidingSystem, - time_t timeStamp) : mEventNumber(eventNumber), - mRunNumber(runNumber), - mEnergy(energy), - mMultiplicity(multiplicity), - mCollidingSystem(collidingSystem), - mTimeStamp(timeStamp) +VisualisationEvent::VisualisationEvent(VisualisationEventVO vo) +{ + this->mEventNumber = vo.eventNumber; + this->mRunNumber = vo.runNumber; + this->mEnergy = vo.energy; + this->mMultiplicity = vo.multiplicity; + this->mCollidingSystem = vo.collidingSystem; + this->mTimeStamp = vo.timeStamp; +} + +std::string VisualisationEvent::toJson() +{ + Document tree(kObjectType); + Document::AllocatorType& allocator = tree.GetAllocator(); + + // compatibility verification + tree.AddMember("fileVersion", rapidjson::Value().SetInt(JSON_FILE_VERSION), allocator); + // Tracks + tree.AddMember("trackCount", rapidjson::Value().SetInt(this->getTrackCount()), allocator); + + Value jsonTracks(kArrayType); + for (size_t i = 0; i < this->getTrackCount(); i++) { + jsonTracks.PushBack(this->mTracks[i].jsonTree(allocator), allocator); + } + tree.AddMember("mTracks", jsonTracks, allocator); + + // Clusters + rapidjson::Value clusterCount(rapidjson::kNumberType); + clusterCount.SetInt(this->getClusterCount()); + tree.AddMember("clusterCount", clusterCount, allocator); + Value jsonClusters(kArrayType); + for (size_t i = 0; i < this->getClusterCount(); i++) { + jsonClusters.PushBack(this->mClusters[i].jsonTree(allocator), allocator); + } + tree.AddMember("mClusters", jsonClusters, allocator); + + // stringify + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); + tree.Accept(writer); + std::string json_str = std::string(buffer.GetString(), buffer.GetSize()); + return json_str; +} + +VisualisationEvent::VisualisationEvent(std::string fileName) +{ + this->fromFile(fileName); +} + +void VisualisationEvent::fromJson(std::string json) { + mTracks.clear(); + mClusters.clear(); + + rapidjson::Document tree; + tree.Parse(json.c_str()); + + rapidjson::Value& fileVersion = tree["fileVersion"]; + rapidjson::Value& trackCount = tree["trackCount"]; + this->mTracks.reserve(trackCount.GetInt()); + rapidjson::Value& jsonTracks = tree["mTracks"]; + for (auto& v : jsonTracks.GetArray()) { + mTracks.emplace_back(v); + } + + rapidjson::Value& clusterCount = tree["clusterCount"]; + this->mClusters.reserve(clusterCount.GetInt()); + rapidjson::Value& jsonClusters = tree["mClusters"]; + for (auto& v : jsonClusters.GetArray()) { + mClusters.emplace_back(v); + } +} + +void VisualisationEvent::toFile(std::string fileName) +{ + std::string json = toJson(); + std::ofstream out(fileName); + out << json; + out.close(); +} + +std::string VisualisationEvent::fileNameIndexed(const std::string fileName, const int index) +{ + std::stringstream buffer; + buffer << fileName << std::setfill('0') << std::setw(3) << index << ".json"; + return buffer.str(); +} + +bool VisualisationEvent::fromFile(std::string fileName) +{ + if (FILE* file = fopen(fileName.c_str(), "r")) { + fclose(file); // file exists + } else { + return false; + } + std::ifstream inFile; + inFile.open(fileName); + + std::stringstream strStream; + strStream << inFile.rdbuf(); //read the file + inFile.close(); + std::string str = strStream.str(); //str holds the content of the file + fromJson(str); + return true; } } // namespace event_visualisation diff --git a/EventVisualisation/DataConverter/src/VisualisationTrack.cxx b/EventVisualisation/DataConverter/src/VisualisationTrack.cxx index 8a64472ed8ef0..38096007b254a 100644 --- a/EventVisualisation/DataConverter/src/VisualisationTrack.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,10 +13,10 @@ /// \file VisualisationTrack.cxx /// \author Jeremi Niedziela /// \author Maciej Grochowicz +/// \author Julian Myrcha /// #include "EventVisualisationDataConverter/VisualisationTrack.h" -#include <iostream> using namespace std; @@ -26,81 +27,76 @@ namespace event_visualisation VisualisationTrack::VisualisationTrack() = default; -VisualisationTrack::VisualisationTrack( - int charge, - double energy, - int ID, - int PID, - double mass, - double signedPT, - double startXYZ[], - double endXYZ[], - double pxpypz[], - int parentID, - double phi, - double theta, - double helixCurvature, - int type) - : mCharge(charge), - mEnergy(energy), - mParentID(parentID), - mPID(PID), - mSignedPT(signedPT), - mMass(mass), - mHelixCurvature(helixCurvature), - mTheta(theta), - mPhi(phi) +VisualisationTrack::VisualisationTrack(const VisualisationTrackVO& vo) { - addMomentum(pxpypz); - addStartCoordinates(startXYZ); - addEndCoordinates(endXYZ); - mID = ID; - mType = gTrackTypes[type]; + this->mCharge = vo.charge; + this->mPID = vo.PID; + this->mTheta = vo.theta; + this->mPhi = vo.phi; + this->addStartCoordinates(vo.startXYZ); + this->mSource = vo.source; } -void VisualisationTrack::addChild(int childID) -{ - mChildrenIDs.push_back(childID); -} - -void VisualisationTrack::addMomentum(double pxpypz[3]) -{ - for (int i = 0; i < 3; i++) { - mMomentum[i] = pxpypz[i]; - } -} - -void VisualisationTrack::addStartCoordinates(double xyz[3]) +void VisualisationTrack::addStartCoordinates(const float xyz[3]) { for (int i = 0; i < 3; i++) { mStartCoordinates[i] = xyz[i]; } } -void VisualisationTrack::addEndCoordinates(double xyz[3]) -{ - for (int i = 0; i < 3; i++) { - mEndCoordinates[i] = xyz[i]; - } -} - -void VisualisationTrack::addPolyPoint(double x, double y, double z) +void VisualisationTrack::addPolyPoint(float x, float y, float z) { mPolyX.push_back(x); mPolyY.push_back(y); mPolyZ.push_back(z); } -void VisualisationTrack::addPolyPoint(double* xyz) +VisualisationTrack::VisualisationTrack(rapidjson::Value& tree) { - mPolyX.push_back(xyz[0]); - mPolyY.push_back(xyz[1]); - mPolyZ.push_back(xyz[2]); + rapidjson::Value& jsonPolyX = tree["mPolyX"]; + rapidjson::Value& jsonPolyY = tree["mPolyY"]; + rapidjson::Value& jsonPolyZ = tree["mPolyZ"]; + rapidjson::Value& count = tree["count"]; + + this->mSource = (o2::dataformats::GlobalTrackID::Source)tree["source"].GetInt(); + this->mPID = (o2::dataformats::GlobalTrackID::Source)tree["source"].GetInt(); + //this->mTime = (o2::dataformats::GlobalTrackID::Source)tree["time"].GetFloat(); + this->mPolyX.reserve(count.GetInt()); + this->mPolyY.reserve(count.GetInt()); + this->mPolyZ.reserve(count.GetInt()); + for (auto& v : jsonPolyX.GetArray()) { + mPolyX.push_back(v.GetDouble()); + } + for (auto& v : jsonPolyY.GetArray()) { + mPolyY.push_back(v.GetDouble()); + } + for (auto& v : jsonPolyZ.GetArray()) { + mPolyZ.push_back(v.GetDouble()); + } } -void VisualisationTrack::setTrackType(ETrackType type) +rapidjson::Value VisualisationTrack::jsonTree(rapidjson::Document::AllocatorType& allocator) { - mType = gTrackTypes[type]; + rapidjson::Value tree(rapidjson::kObjectType); + rapidjson::Value jsonPolyX(rapidjson::kArrayType); + rapidjson::Value jsonPolyY(rapidjson::kArrayType); + rapidjson::Value jsonPolyZ(rapidjson::kArrayType); + + tree.AddMember("count", rapidjson::Value().SetInt(this->getPointCount()), allocator); + tree.AddMember("source", rapidjson::Value().SetInt(this->mSource), allocator); + //tree.AddMember("time", rapidjson::Value().SetFloat(this->mTime), allocator); + tree.AddMember("PID", rapidjson::Value().SetInt(this->mPID), allocator); + + for (size_t i = 0; i < this->getPointCount(); i++) { + jsonPolyX.PushBack((float)mPolyX[i], allocator); + jsonPolyY.PushBack((float)mPolyY[i], allocator); + jsonPolyZ.PushBack((float)mPolyZ[i], allocator); + } + tree.AddMember("mPolyX", jsonPolyX, allocator); + tree.AddMember("mPolyY", jsonPolyY, allocator); + tree.AddMember("mPolyZ", jsonPolyZ, allocator); + + return tree; } } // namespace event_visualisation diff --git a/EventVisualisation/Detectors/CMakeLists.txt b/EventVisualisation/Detectors/CMakeLists.txt index 5390b15ed4cfd..e3e9e110ff82a 100644 --- a/EventVisualisation/Detectors/CMakeLists.txt +++ b/EventVisualisation/Detectors/CMakeLists.txt @@ -1,20 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EventVisualisationDetectors SOURCES - src/DataInterpreterTPC.cxx - src/DataReaderTPC.cxx src/DataInterpreterITS.cxx - src/DataReaderITS.cxx + src/DataInterpreterTPC.cxx src/DataInterpreterVSD.cxx + src/DataReaderITS.cxx + src/DataReaderJSON.cxx + src/DataReaderTPC.cxx src/DataReaderVSD.cxx PUBLIC_LINK_LIBRARIES O2::EventVisualisationBase diff --git a/EventVisualisation/Detectors/README.md b/EventVisualisation/Detectors/README.md new file mode 100644 index 0000000000000..cef1d1675fa30 --- /dev/null +++ b/EventVisualisation/Detectors/README.md @@ -0,0 +1,7 @@ +<!-- doxy +\page refEventVisualisationDetectors EventVisualisation Detectors +/doxy --> + +# Event Visualisation Detectors + +A description of this module is not yet available. diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterITS.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterITS.h index 20755fd52a93e..e834dc6088126 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterITS.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ class DataInterpreterITS final : public DataInterpreter ~DataInterpreterITS() final = default; // Returns a visualisation Event for this data type - std::unique_ptr<VisualisationEvent> interpretDataForType(TObject* data, EVisualisationDataType type) final; + VisualisationEvent interpretDataForType(TObject* data, EVisualisationDataType type) final; }; } // namespace event_visualisation diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterTPC.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterTPC.h index c0572e468c861..9b19c9dce0729 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterTPC.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterTPC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ class DataInterpreterTPC final : public DataInterpreter ~DataInterpreterTPC() final; // Returns a visualisation Event for this data type - std::unique_ptr<VisualisationEvent> interpretDataForType(TObject* data, EVisualisationDataType type) final; + VisualisationEvent interpretDataForType(TObject* data, EVisualisationDataType type) final; }; } // namespace event_visualisation diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterVSD.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterVSD.h index 6f7a18614a5c5..eec259285447d 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterVSD.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataInterpreterVSD.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,7 +59,7 @@ class DataInterpreterVSD final : public DataInterpreter ~DataInterpreterVSD() final; // Returns a visualisation Event for this data type - std::unique_ptr<VisualisationEvent> interpretDataForType(TObject* data, EVisualisationDataType type) final; + VisualisationEvent interpretDataForType(TObject* data, EVisualisationDataType type) final; }; } // namespace event_visualisation diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderITS.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderITS.h index a66d37a190784..efea911d4b525 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderITS.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,8 +32,8 @@ class DataReaderITS : public DataReader TFile* mTracFile; public: - DataReaderITS() = default; - ; + DataReaderITS(DataInterpreter* interpreter) : DataReader(interpreter) {} + void open() override; int GetEventCount() const override { return mMaxEv; } diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderJSON.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderJSON.h new file mode 100644 index 0000000000000..9e42e11e408a9 --- /dev/null +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderJSON.h @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DataReaderITS.h +/// \brief JSON specific reading from file(s) +/// \author julian.myrcha@cern.ch + +#ifndef O2EVE_EVENTVISUALISATION_DETECTORS_DATAREADERJSON_H +#define O2EVE_EVENTVISUALISATION_DETECTORS_DATAREADERJSON_H + +#include <TFile.h> +#include "EventVisualisationBase/DataReader.h" + +namespace o2 +{ +namespace event_visualisation +{ + +class DataReaderJSON : public DataReader +{ + private: + Int_t mMaxEv; + std::string mFileName; + + public: + DataReaderJSON(DataInterpreter* interpreter) : DataReader(interpreter) {} + + void open() override; + int GetEventCount() const override { return mMaxEv; } + VisualisationEvent getEvent(int no, EVisualisationDataType dataType) override; +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif //O2EVE_DATAREADERJSON_H diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderTPC.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderTPC.h index 9de5cb109e9a8..af30c20d64b3c 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderTPC.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderTPC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ class DataReaderTPC : public DataReader TFile* mTracFile; public: - DataReaderTPC(); + DataReaderTPC(DataInterpreter* interpreter); void open() override; Int_t GetEventCount() const override { return mMaxEv; }; TObject* getEventData(int no) override; diff --git a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderVSD.h b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderVSD.h index fce3c4d26e8bf..8e48726285afa 100644 --- a/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderVSD.h +++ b/EventVisualisation/Detectors/include/EventVisualisationDetectors/DataReaderVSD.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ class DataReaderVSD : public DataReader public: //Int_t GetEventCount() override { return mEvDirKeys->GetEntriesFast(); }; int GetEventCount() const override { return mEvDirKeys.size(); }; - DataReaderVSD(); + DataReaderVSD(DataInterpreter* interpreter); ~DataReaderVSD() override; void open() override; TObject* getEventData(int no) override; diff --git a/EventVisualisation/Detectors/src/DataInterpreterITS.cxx b/EventVisualisation/Detectors/src/DataInterpreterITS.cxx index ef2269ac5666f..6780bf1555c11 100644 --- a/EventVisualisation/Detectors/src/DataInterpreterITS.cxx +++ b/EventVisualisation/Detectors/src/DataInterpreterITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include "DataFormatsITSMFT/Cluster.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "ITSBase/GeometryTGeo.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" #include <TEveManager.h> #include <TEveTrackPropagator.h> @@ -31,8 +33,7 @@ #include <TVector2.h> #include <gsl/span> - -using namespace std; +#include <gsl/span_ext> namespace o2 { @@ -47,12 +48,17 @@ DataInterpreterITS::DataInterpreterITS() gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)); } -std::unique_ptr<VisualisationEvent> DataInterpreterITS::interpretDataForType(TObject* data, EVisualisationDataType type) +VisualisationEvent DataInterpreterITS::interpretDataForType(TObject* data, EVisualisationDataType type) { TList* list = (TList*)data; Int_t event = ((TVector2*)list->At(2))->X(); - auto ret_event = std::make_unique<VisualisationEvent>(0, 0, 0, 0, "", 0); + VisualisationEvent ret_event({.eventNumber = 0, + .runNumber = 0, + .energy = 0, + .multiplicity = 0, + .collidingSystem = "", + .timeStamp = 0}); if (type == Clusters) { its::GeometryTGeo* gman = its::GeometryTGeo::Instance(); @@ -78,10 +84,8 @@ std::unique_ptr<VisualisationEvent> DataInterpreterITS::interpretDataForType(TOb for (const auto& c : mClusters) { const auto& gloC = c.getXYZGloRot(*gman); - double xyz[3] = {gloC.X(), gloC.Y(), gloC.Z()}; - VisualisationCluster cluster(xyz); - - ret_event->addCluster(cluster); + float xyz[3] = {gloC.X(), gloC.Y(), gloC.Z()}; + ret_event.addCluster(xyz); } } else if (type == ESD) { TFile* trackFile = (TFile*)list->At(0); @@ -134,16 +138,20 @@ std::unique_ptr<VisualisationEvent> DataInterpreterITS::interpretDataForType(TOb auto start = eve_track->GetLineStart(); auto end = eve_track->GetLineEnd(); - double track_start[3] = {start.fX, start.fY, start.fZ}; - double track_end[3] = {end.fX, end.fY, end.fZ}; - double track_p[3] = {p[0], p[1], p[2]}; - - VisualisationTrack track(rec.getSign(), 0.0, 0, 0, 0.0, 0.0, track_start, track_end, track_p, 0, 0.0, 0.0, 0.0, 0); + VisualisationTrack* track = ret_event.addTrack({.charge = rec.getSign(), + .PID = 0, + .startXYZ = {start.fX, start.fY, start.fZ}, + //.endXYZ = {end.fX, end.fY, end.fZ}, + //.pxpypz = {p[0], p[1], p[2]}, + //.parentID = 0, + .phi = 0.0, + .theta = 0.0, + .source = o2::dataformats::GlobalTrackID::ITS}); for (Int_t i = 0; i < eve_track->GetN(); ++i) { Float_t x, y, z; eve_track->GetPoint(i, x, y, z); - track.addPolyPoint(x, y, z); + track->addPolyPoint(x, y, z); } delete eve_track; @@ -155,8 +163,6 @@ std::unique_ptr<VisualisationEvent> DataInterpreterITS::interpretDataForType(TOb // const auto& gloC = c.getXYZGloRot(*gman); // tpoints->SetNextPoint(gloC.X(), gloC.Y(), gloC.Z()); // } - - ret_event->addTrack(track); } delete trackList; } diff --git a/EventVisualisation/Detectors/src/DataInterpreterTPC.cxx b/EventVisualisation/Detectors/src/DataInterpreterTPC.cxx index 9e78c98c2e40b..24bb5408ed01d 100644 --- a/EventVisualisation/Detectors/src/DataInterpreterTPC.cxx +++ b/EventVisualisation/Detectors/src/DataInterpreterTPC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,8 +35,6 @@ #include <iostream> #include <gsl/span> -using namespace std; - namespace o2 { namespace event_visualisation @@ -43,12 +42,17 @@ namespace event_visualisation DataInterpreterTPC::~DataInterpreterTPC() = default; -std::unique_ptr<VisualisationEvent> DataInterpreterTPC::interpretDataForType(TObject* data, EVisualisationDataType type) +VisualisationEvent DataInterpreterTPC::interpretDataForType(TObject* data, EVisualisationDataType type) { TList* list = (TList*)data; // Int_t event = ((TVector2*)list->At(2))->X(); - auto ret_event = std::make_unique<VisualisationEvent>(0, 0, 0, 0, "", 0); + VisualisationEvent ret_event({.eventNumber = 0, + .runNumber = 0, + .energy = 0, + .multiplicity = 0, + .collidingSystem = "", + .timeStamp = 0}); if (type == Clusters) { TFile* clustFile = (TFile*)list->At(1); @@ -74,10 +78,9 @@ std::unique_ptr<VisualisationEvent> DataInterpreterTPC::interpretDataForType(TOb const auto pad = mapper.globalPadNumber(tpc::PadPos(row, c->getPad())); const tpc::LocalPosition3D localXYZ(mapper.padCentre(pad).X(), mapper.padCentre(pad).Y(), c->getTime()); const auto globalXYZ = mapper.LocalToGlobal(localXYZ, sector); - double xyz[3] = {globalXYZ.X(), globalXYZ.Y(), globalXYZ.Z()}; + float xyz[3] = {globalXYZ.X(), globalXYZ.Y(), globalXYZ.Z()}; - VisualisationCluster cluster(xyz); - ret_event->addCluster(cluster); + ret_event.addCluster(xyz); } } } else if (type == ESD) { @@ -112,20 +115,19 @@ std::unique_ptr<VisualisationEvent> DataInterpreterTPC::interpretDataForType(TOb auto start = eve_track->GetLineStart(); auto end = eve_track->GetLineEnd(); - double track_start[3] = {start.fX, start.fY, start.fZ}; - double track_end[3] = {end.fX, end.fY, end.fZ}; - double track_p[3] = {p[0], p[1], p[2]}; - - VisualisationTrack track(rec.getSign(), 0.0, 0, 0, 0.0, 0.0, track_start, track_end, track_p, 0, 0.0, 0.0, 0.0, 0); + VisualisationTrack* track = ret_event.addTrack({.charge = rec.getSign(), + .PID = 0, + .startXYZ = {start.fX, start.fY, start.fZ}, + .phi = 0.0, + .theta = 0.0, + .source = o2::dataformats::GlobalTrackID::ITS}); for (Int_t i = 0; i < eve_track->GetN(); ++i) { Float_t x, y, z; eve_track->GetPoint(i, x, y, z); - track.addPolyPoint(x, y, z); + track->addPolyPoint(x, y, z); } delete eve_track; - - ret_event->addTrack(track); } delete trackList; } diff --git a/EventVisualisation/Detectors/src/DataInterpreterVSD.cxx b/EventVisualisation/Detectors/src/DataInterpreterVSD.cxx index be63509e60f94..6fcab8783f908 100644 --- a/EventVisualisation/Detectors/src/DataInterpreterVSD.cxx +++ b/EventVisualisation/Detectors/src/DataInterpreterVSD.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,8 +26,6 @@ #include <TEveTrackPropagator.h> #include <TGListTree.h> -using namespace std; - namespace o2 { namespace event_visualisation @@ -41,7 +40,7 @@ DataInterpreterVSD::~DataInterpreterVSD() } } -std::unique_ptr<VisualisationEvent> DataInterpreterVSD::interpretDataForType(TObject* data, EVisualisationDataType type) +VisualisationEvent DataInterpreterVSD::interpretDataForType(TObject* data, EVisualisationDataType type) { if (mVSD == nullptr) { mVSD = new TEveVSD; @@ -54,16 +53,17 @@ std::unique_ptr<VisualisationEvent> DataInterpreterVSD::interpretDataForType(TOb this->AttachEvent(); - auto ret_event = std::make_unique<VisualisationEvent>(0, 0, 0, 0, "", 0); - // Load event data into visualization structures. + VisualisationEvent ret_event({.eventNumber = 0, + .runNumber = 0, + .energy = 0, + .multiplicity = 0, + .collidingSystem = "", + .timeStamp = 0}); - // this->LoadClusters(this->fITSClusters, "ITS", 0); - // this->LoadClusters(this->fTPCClusters, "TPC", 1); - // this->LoadClusters(this->fTRDClusters, "TRD", 2); - // this->LoadClusters(this->fTOFClusters, "TOF", 3); + // Load event data into visualization structures. if (type == ESD) { - LoadEsdTracks(*ret_event); + LoadEsdTracks(ret_event); } return ret_event; @@ -156,4 +156,4 @@ void DataInterpreterVSD::LoadEsdTracks(VisualisationEvent& /*event*/) } } // namespace event_visualisation -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/EventVisualisation/Detectors/src/DataReaderITS.cxx b/EventVisualisation/Detectors/src/DataReaderITS.cxx index db5c404cfe786..b7998b4bf5812 100644 --- a/EventVisualisation/Detectors/src/DataReaderITS.cxx +++ b/EventVisualisation/Detectors/src/DataReaderITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/Detectors/src/DataReaderJSON.cxx b/EventVisualisation/Detectors/src/DataReaderJSON.cxx new file mode 100644 index 0000000000000..e49429392b367 --- /dev/null +++ b/EventVisualisation/Detectors/src/DataReaderJSON.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file DataReaderJSON.cxx +/// \brief JSON specific reading from file(s) +/// \author julian.myrcha@cern.ch + +#include "EventVisualisationDetectors/DataReaderJSON.h" + +#include <TTree.h> + +namespace o2 +{ +namespace event_visualisation +{ + +void DataReaderJSON::open() +{ + this->mFileName = "/home/jmy/CERN/event"; + this->mMaxEv = 0; + while (true) { + FILE* file = fopen(VisualisationEvent::fileNameIndexed(this->mFileName, this->mMaxEv).c_str(), "r"); + if (file == nullptr) { + break; + } + fclose(file); + this->mMaxEv++; + } +} + +VisualisationEvent DataReaderJSON::getEvent(int no, EVisualisationDataType /*dataType*/) +{ + VisualisationEvent vEvent; + vEvent.fromFile(VisualisationEvent::fileNameIndexed(this->mFileName, no)); + return vEvent; +} + +} // namespace event_visualisation +} // namespace o2 diff --git a/EventVisualisation/Detectors/src/DataReaderTPC.cxx b/EventVisualisation/Detectors/src/DataReaderTPC.cxx index 2dea82284bd4f..89e90135c49cb 100644 --- a/EventVisualisation/Detectors/src/DataReaderTPC.cxx +++ b/EventVisualisation/Detectors/src/DataReaderTPC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,7 +26,7 @@ namespace o2 namespace event_visualisation { -DataReaderTPC::DataReaderTPC() = default; +DataReaderTPC::DataReaderTPC(DataInterpreter* interpreter) : DataReader(interpreter) {} void DataReaderTPC::open() { diff --git a/EventVisualisation/Detectors/src/DataReaderVSD.cxx b/EventVisualisation/Detectors/src/DataReaderVSD.cxx index 77b902caa1591..7334bbf646967 100644 --- a/EventVisualisation/Detectors/src/DataReaderVSD.cxx +++ b/EventVisualisation/Detectors/src/DataReaderVSD.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,8 +28,8 @@ namespace o2 namespace event_visualisation { -DataReaderVSD::DataReaderVSD() - : DataReader(), +DataReaderVSD::DataReaderVSD(DataInterpreter* interpreter) + : DataReader(interpreter), mFile(nullptr), mMaxEv(-1), mCurEv(-1) diff --git a/EventVisualisation/README.md b/EventVisualisation/README.md index 6024acf34791e..129f4e69d0a09 100644 --- a/EventVisualisation/README.md +++ b/EventVisualisation/README.md @@ -4,11 +4,18 @@ # Event Visualisation -There is no module description yet. +Module define `o2-eve` desktop application (build on top of ROOT) used to display tracks and clusters. In View module the desktop application is described (see \ref refEventVisualisationView). In Workflow module workflow used to prepare data is descrived (see \ref refEventVisualisationWorkflow) + + <!-- doxy This module contains the following submodules: * \subpage refEventVisualisationBase +* \subpage refEventVisualisationDataConverter +* \subpage refEventVisualisationDetectors +* \subpage refEventVisualisationScripts +* \subpage refEventVisualisationView +* \subpage refEventVisualisationWorkflow /doxy --> diff --git a/EventVisualisation/Scripts/.bashrc b/EventVisualisation/Scripts/.bashrc new file mode 100644 index 0000000000000..7156d3944b0a7 --- /dev/null +++ b/EventVisualisation/Scripts/.bashrc @@ -0,0 +1,39 @@ +# .bashrc + +# Source global definitions +if [ -f /etc/bashrc ]; then + . /etc/bashrc +fi + +# User specific environment +if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]] +then + PATH="$HOME/.local/bin:$HOME/bin:$PATH" +fi +export PATH + +# Uncomment the following line if you don't like systemctl's auto-paging feature: +# export SYSTEMD_PAGER= + +# User specific aliases and functions + +alias enter='alienv enter O2/latest-dev-o2' + +function sync-alice() { + rsync -arvz -e'ssh -p 2020' --progress --delete ed@alihlt-gw-prod.cern.ch:/home/ed/jsons /home/ed +} + +function query-alice() { + while true + do + sync-alice + sleep 2 + done +} + +function o2eve() { + o2-eve -o -d /home/ed/jsons +} + +export ALIBUILD_WORK_DIR=~/alice/sw +eval "`alienv shell-helper`" diff --git a/EventVisualisation/Scripts/.o2eve_config b/EventVisualisation/Scripts/.o2eve_config new file mode 100755 index 0000000000000..41339ef9d3549 --- /dev/null +++ b/EventVisualisation/Scripts/.o2eve_config @@ -0,0 +1,104 @@ +#===============================================================# +# This is o2-eve config file. # +# # +# You can copy it to your home directory and set custom values. # +# please remember to change paths # +# # +#===============================================================# + +trigger.class.filter: none + +axes.show: 0 +fullscreen.mode: 0 +background.color: 1 + +camera.3D.rotation.horizontal: -0.4 +camera.3D.rotation.vertical: 1.0 +camera.3D.zoom: 1.0 +camera.R-Phi.zoom: 1.0 +camera.Rho-Z.zoom: 1.0 + +simple.geom.default: R3 +simple.geom.R3.path: /home/ed/geom/O2 + +tracks.width: 2 + +tracks.byType.electron: 600 +tracks.byType.muon: 416 +tracks.byType.pion: 632 +tracks.byType.kaon: 400 +tracks.byType.proton: 797 +tracks.byType.unknown: 920 + +PHS.draw: 1 +TPC.draw: 1 +HMP.draw: 1 +TRD.draw: 1 +MCH.draw: 1 +EMC.draw: 1 +ACO.draw: 1 +ITS.draw: 1 +TOF.draw: 1 +MFT.draw: 1 +T00.draw: 1 +FIT.draw: 1 +AD0.draw: 1 +FMD.draw: 1 + +PHS.color: 53 +TPC.color: 3 +HMP.color: 5 +TRD.color: 921 +MCH.color: 920 +EMC.color: 53 +ACO.color: 920 +ITS.color: 634 +TOF.color: 634 +MFT.color: 920 +T00.color: 2 +FIT.color: 2 +AD0.color: 5 +FMD.color: 906 + +PHS.trans: 70 +TPC.trans: 60 +HMP.trans: 70 +TRD.trans: 80 +MCH.trans: 80 +EMC.trans: 80 +ACO.trans: 50 +ITS.trans: 50 +TOF.trans: 60 +MFT.trans: 80 +T00.trans: 70 +FIT.trans: 40 +AD0.trans: 40 +FMD.trans: 50 + +MCH.line.color: 920 +TPC.line.color: 1 +HMP.line.color: 1 +PHS.line.color: 1 +TRD.line.color: 1 +TOF.line.color: 1 +EMC.line.color: 1 +ITS.line.color: 1 +MFT.line.color: 0 +T00.line.color: 1 +FIT.line.color: 1 +AD0.line.color: 1 +FMD.line.color: 907 + +OCDB.default.path: local:///home/ed/cdb + + +#Gui.DefaultFont: -*-helvetica-medium-r-*-*-20-*-*-*-*-*-iso8859-1 +#Gui.MenuFont: -*-helvetica-medium-r-*-*-20-*-*-*-*-*-iso8859-1 +#Gui.MenuHiFont: -*-helvetica-bold-r-*-*-20-*-*-*-*-*-iso8859-1 +#Gui.DocFixedFont: -*-courier-medium-r-*-*-20-*-*-*-*-*-iso8859-1 +#Gui.DocPropFont: -*-helvetica-medium-r-*-*-20-*-*-*-*-*-iso8859-1 +#Gui.IconFont: -*-helvetica-medium-r-*-*-32-*-*-*-*-*-iso8859-1 +#Gui.StatusFont: -*-helvetica-medium-r-*-*-20-*-*-*-*-*-iso8859-1 +# +# EOF +# diff --git a/EventVisualisation/Scripts/README.md b/EventVisualisation/Scripts/README.md new file mode 100644 index 0000000000000..446d7126c5568 --- /dev/null +++ b/EventVisualisation/Scripts/README.md @@ -0,0 +1,24 @@ +<!-- doxy +\page refEventVisualisationScripts EventVisualisation Scripts +/doxy --> + +# Event Visualisation Scripts + +## Configuration of the online event display in P2 + +There are 2 processes to be run on the visualisation machine in P2. To simplify deployment there are `bash` functions declared in `.bashrc` functions of the `ed` user. + +* Process which synchronises (every 2 seconds) local folder `/home/ed/jsons` with folder on EPN which is run in terminal by calling `query-alice`. That process should be run from one of the terminals. Because files in folder on EPN are produced in FIFO scheme (so creating new ones results in deletion the same number of the old ones) files in local folders also are created and deleted. +```shell +query-alice +``` +* Process which starts `o2-eve` application in mode when contents of the `/home/ed/jsons` folder is observed which is run in terminal by calling `o2eve`. Before calling `o2eve` user must enter O2 environment - it can be done by calling `enter` function declared in `.bashrc` +```shell +enter +o2eve +``` +## navigation in o2-eve events using << < > >> buttons +Event display shows defined pool of data (by default there are 300+2) which are present in observed folder. The first and last data are duplicated (so 1 and 2 show the same and 301 and 302 show the same) because: +* position 1 means 'show the latest available data'. When observed latest data disappear (because new data has arrived and old one deleted) the new latest data is displayed +* positions 2-301: as long as data exists in the folder o2-eve displays the same data (but their positions decreases as new data is arriving and old data is deleted). Finally, the position become 1. +* position 302 means 'show the newest available data'. If we are on position 302 as soon as new data file is presented in the observed folder that data is immediately displayed by the o2-eve. The position remains the same, but the data displayed changes. diff --git a/EventVisualisation/View/CMakeLists.txt b/EventVisualisation/View/CMakeLists.txt index 97069d9d14b8d..53a5e25286c14 100644 --- a/EventVisualisation/View/CMakeLists.txt +++ b/EventVisualisation/View/CMakeLists.txt @@ -1,28 +1,34 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(EventVisualisationView SOURCES src/MultiView.cxx src/Initializer.cxx src/EventManager.cxx + src/Options.cxx src/EventManagerFrame.cxx PUBLIC_LINK_LIBRARIES O2::EventVisualisationBase - O2::EventVisualisationDetectors) + O2::EventVisualisationDetectors + RapidJSON::RapidJSON) o2_target_root_dictionary(EventVisualisationView - HEADERS include/EventVisualisationView/MultiView.h - include/EventVisualisationView/Initializer.h - include/EventVisualisationView/EventManagerFrame.h - LINKDEF src/EventVisualisationViewLinkDef.h) + HEADERS include/EventVisualisationView/MultiView.h + include/EventVisualisationView/Initializer.h + include/EventVisualisationView/Options.h + include/EventVisualisationView/EventManagerFrame.h + LINKDEF src/EventVisualisationViewLinkDef.h) o2_add_executable(eve - SOURCES src/main.cxx - PUBLIC_LINK_LIBRARIES O2::EventVisualisationView - ) + SOURCES src/main.cxx + PUBLIC_LINK_LIBRARIES O2::EventVisualisationView + ) + + diff --git a/EventVisualisation/View/README.md b/EventVisualisation/View/README.md new file mode 100644 index 0000000000000..689d3a903d266 --- /dev/null +++ b/EventVisualisation/View/README.md @@ -0,0 +1,36 @@ +<!-- doxy +\page refEventVisualisationView EventVisualisation View +/doxy --> + +# Event Visualisation View + +To run `o2-eve` you need to have a computer with linux or mac with properly build O2. There are no special hardware requirements, but for performance it is better to have discrete graphic card. + +## Prerequisites +for `o2-eve` to run you should: +* have in the working folder: + * `.o2eve_config` file (available from EventVisualisation/Scripts) + * `o2sim_geometry.root` (copied from simulation folder) + * `o2sim_grp.root` (copied from simulation folder) +* have (somewhere, specified by command line parameter) folder with json files (f.e `/home/ed/jsons`) +* have (somewhere, specified in `.o2eve_config` file) folder with simplify geometry files (f.e `/home/ed/geom/O2`) + +## Running o2-eve +Here are sample commands: +```shell +alienv enter O2/latest-dev-o2 +cd /home/ed # working folder containing .o2eve_config, o2sim_geometry.root and o2sim_grp.root +o2-eve -o -d /home/ed/jsons +``` + +## o2-eve command line parameters: +| *parameter*| *description* | *status* | +|-----|---|---| +|i |displaying ITS tracks from `o2trac_its.root` and clusters from `o2clus_its.root` |(under development) | +|j |reading from *.json files (non online mode). require specification of json folder with `-d` | | +|o |online mode. require specification of json folder with `-d` | | +|r |randomly generated tracks | (test option, switched off) | +|t |displaying TPC tracks from `o2trac_its.root` and clusters from `o2clus_its.root` |(under development) | +|v |displaying data from sample ROOT file (vsd) | (development test usage only) | +|f file |location of AOD file containing data to be displayed | (under development) | +|d folder|location of json folder - a folder where json files from workflow data are located | | diff --git a/EventVisualisation/View/include/EventVisualisationView/EventManager.h b/EventVisualisation/View/include/EventVisualisationView/EventManager.h index b76b8d178e260..c437287428b19 100644 --- a/EventVisualisation/View/include/EventVisualisationView/EventManager.h +++ b/EventVisualisation/View/include/EventVisualisationView/EventManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -65,7 +66,6 @@ class EventManager final : public TEveEventManager, public TQObject ccdbApi.init(path.Data()); } - Int_t getCurrentEvent() const { return currentEvent; } DataSource* getDataSource() { return dataSource; } void setDataSource(DataSource* dataSource) { this->dataSource = dataSource; } @@ -74,6 +74,7 @@ class EventManager final : public TEveEventManager, public TQObject void NextEvent() override; void PrevEvent() override; void Close() override; + void displayCurrentEvent(); void AfterNewEventLoaded() override; @@ -81,19 +82,15 @@ class EventManager final : public TEveEventManager, public TQObject void RemoveNewEventCommand(const TString& cmd) override; void ClearNewEventCommands() override; - void registerDetector(DataReader* reader, DataInterpreter* interpreter, EVisualisationGroup type); void DropEvent(); private: static EventManager* instance; o2::ccdb::CcdbApi ccdbApi; - DataInterpreter* dataInterpreters[EVisualisationGroup::NvisualisationGroups]; - DataReader* dataReaders[EVisualisationGroup::NvisualisationGroups]; TEveElementList* dataTypeLists[EVisualisationDataType::NdataTypes]; EDataSource mCurrentDataSourceType = EDataSource::SourceOffline; DataSource* dataSource = nullptr; TString dataPath = ""; - Int_t currentEvent = 0; /// Default constructor EventManager(); diff --git a/EventVisualisation/View/include/EventVisualisationView/EventManagerFrame.h b/EventVisualisation/View/include/EventVisualisationView/EventManagerFrame.h index 1ca7d7f384442..9cf8a64cc8372 100644 --- a/EventVisualisation/View/include/EventVisualisationView/EventManagerFrame.h +++ b/EventVisualisation/View/include/EventVisualisationView/EventManagerFrame.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,6 +33,11 @@ namespace event_visualisation class EventManagerFrame : public TGMainFrame { private: + Float_t mTime; // Auto-load time in seconds + TTimer* mTimer; // Timer for automatic event loading + bool mTimerRunning; + bool inTick = false; + static TGTextButton* makeButton(TGCompositeFrame* p, const char* txt, Int_t width = 0, Int_t lo = 0, Int_t ro = 0, Int_t to = 0, Int_t bo = 0); @@ -40,7 +46,7 @@ class EventManagerFrame : public TGMainFrame TGNumberEntry* mEventId; // Display/edit current event id public: EventManagerFrame(o2::event_visualisation::EventManager& eventManager); - ~EventManagerFrame() override = default; + ~EventManagerFrame() override; ClassDefOverride(EventManagerFrame, 0); // GUI window for AliEveEventManager. public: // slots @@ -50,6 +56,9 @@ class EventManagerFrame : public TGMainFrame void DoLastEvent(); void DoSetEvent(); void DoScreenshot(); + void DoTimeTick(); + void StopTimer(); + void StartTimer(); }; } // namespace event_visualisation diff --git a/EventVisualisation/View/include/EventVisualisationView/Initializer.h b/EventVisualisation/View/include/EventVisualisationView/Initializer.h index d97633645ffe3..0d206e181fbd2 100644 --- a/EventVisualisation/View/include/EventVisualisationView/Initializer.h +++ b/EventVisualisation/View/include/EventVisualisationView/Initializer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,13 +24,6 @@ namespace o2 namespace event_visualisation { -struct Options { - bool randomTracks; // -r - bool vsd; // -v - bool itc; // -i - std::string fileName; // -f 'data.root' -}; - /// This class initializes a core of the visualisation system. /// /// Initializer should be created only once when starting @@ -41,7 +35,8 @@ class Initializer { public: /// Default constructor - static void setup(const Options options, const EventManager::EDataSource defaultDataSource = EventManager::SourceOffline); // default data source will be moved to a config file + static void setup(const EventManager::EDataSource defaultDataSource); + private: /// Loads geometry for all detectors static void setupGeometry(); diff --git a/EventVisualisation/View/include/EventVisualisationView/MultiView.h b/EventVisualisation/View/include/EventVisualisationView/MultiView.h index 9441cf40afff7..1a0c8ec9b28ae 100644 --- a/EventVisualisation/View/include/EventVisualisationView/MultiView.h +++ b/EventVisualisation/View/include/EventVisualisationView/MultiView.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/View/include/EventVisualisationView/Options.h b/EventVisualisation/View/include/EventVisualisationView/Options.h new file mode 100644 index 0000000000000..523a3d81beef9 --- /dev/null +++ b/EventVisualisation/View/include/EventVisualisationView/Options.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Options.cxx +/// \author Julian Myrcha + +#ifndef ALICE_O2_EVENTVISUALISATION_VIEW_OPTIONS_H +#define ALICE_O2_EVENTVISUALISATION_VIEW_OPTIONS_H + +#include <string> + +namespace o2 +{ +namespace event_visualisation +{ + +class Options +{ + private: + // stored options + bool mIts; // -i + bool mJSON; // -j + bool mOnline; // -o (must specify -d!) + bool mRandomTracks; // -r + bool mTpc; // -t + bool mVsd; // -v + std::string mFileName; // -f 'data.root' + std::string mDataFolder; // -d './' + + // helper methods + static Options instance; + bool saveToJSON(std::string filename); // stores options to current folder + bool readFromJSON(std::string filename); // read options from option file + Options() + { + mFileName = "data.root"; + mDataFolder = "./"; + } + + public: + static Options* Instance() { return &instance; } + std::string printOptions(); + std::string usage(); + bool processCommandLine(int argc, char* argv[]); + + // get access methods + bool its() { return this->mIts; } + bool json() { return this->mJSON; } + bool online() { return this->mOnline; } + std::string dataFolder() { return this->mDataFolder; } + std::string fileName() { return this->mFileName; } + bool randomTracks() { return this->mRandomTracks; } + bool vsd() { return this->mVsd; } + bool tpc() { return this->mTpc; } +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif //ALICE_O2_EVENTVISUALISATION_VIEW_OPTIONS_H diff --git a/EventVisualisation/View/src/EventManager.cxx b/EventVisualisation/View/src/EventManager.cxx index 15fcdd8cd8b41..cbcc0173058d7 100644 --- a/EventVisualisation/View/src/EventManager.cxx +++ b/EventVisualisation/View/src/EventManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,11 +15,13 @@ #include "EventVisualisationView/EventManager.h" #include "EventVisualisationView/MultiView.h" +#include "EventVisualisationView/Options.h" #include "EventVisualisationDataConverter/VisualisationEvent.h" #include "EventVisualisationBase/ConfigurationManager.h" #include "EventVisualisationBase/DataSource.h" #include "EventVisualisationBase/DataInterpreter.h" #include <EventVisualisationBase/DataSourceOffline.h> +#include <EventVisualisationBase/DataSourceOnline.h> #include <EventVisualisationDetectors/DataReaderVSD.h> #include <TEveManager.h> @@ -52,12 +55,6 @@ EventManager& EventManager::getInstance() EventManager::EventManager() : TEveEventManager("Event", "") { LOG(INFO) << "Initializing TEveManager"; - for (unsigned int i = 0; i < elemof(dataInterpreters); i++) { - dataInterpreters[i] = nullptr; - } - for (unsigned int i = 0; i < elemof(dataReaders); i++) { - dataReaders[i] = nullptr; - } for (unsigned int i = 0; i < elemof(dataTypeLists); i++) { dataTypeLists[i] = nullptr; } @@ -66,16 +63,12 @@ EventManager::EventManager() : TEveEventManager("Event", "") void EventManager::Open() { switch (mCurrentDataSourceType) { - case SourceOnline: - break; + case SourceOnline: { + DataSourceOnline* source = new DataSourceOnline(Options::Instance()->dataFolder()); + setDataSource(source); + } break; case SourceOffline: { DataSourceOffline* source = new DataSourceOffline(); - for (int i = 0; i < EVisualisationGroup::NvisualisationGroups; i++) { - if (dataInterpreters[i] != nullptr) { - dataReaders[i]->open(); - source->registerReader(dataReaders[i], static_cast<EVisualisationGroup>(i)); - } - } setDataSource(source); } break; case SourceHLT: @@ -83,47 +76,56 @@ void EventManager::Open() } } -void EventManager::GotoEvent(Int_t no) +void EventManager::displayCurrentEvent() { - if (no == -1) { - no = getDataSource()->GetEventCount() - 1; - } - - this->currentEvent = no; - MultiView::getInstance()->destroyAllEvents(); + if (getDataSource()->getEventCount() > 0) { + int no = getDataSource()->getCurrentEvent(); - for (int i = 0; i < EVisualisationDataType::NdataTypes; ++i) { - dataTypeLists[i] = new TEveElementList(gDataTypeNames[i].c_str()); - } + for (int i = 0; i < EVisualisationDataType::NdataTypes; ++i) { + dataTypeLists[i] = new TEveElementList(gDataTypeNames[i].c_str()); + } - for (int i = 0; i < EVisualisationGroup::NvisualisationGroups; ++i) { - for (int dataType = 0; dataType < EVisualisationDataType::NdataTypes; ++dataType) { - DataInterpreter* interpreter = dataInterpreters[i]; - if (interpreter) { - TObject* data = getDataSource()->getEventData(no, (EVisualisationGroup)i); - std::unique_ptr<VisualisationEvent> event = interpreter->interpretDataForType(data, (EVisualisationDataType)dataType); - displayVisualisationEvent(*event, gVisualisationGroupName[i]); - } + auto displayList = getDataSource()->getVisualisationList(no); + for (auto it = displayList.begin(); it != displayList.end(); ++it) { + displayVisualisationEvent(it->first, it->second); } - } - for (int i = 0; i < EVisualisationDataType::NdataTypes; ++i) { - MultiView::getInstance()->registerElement(dataTypeLists[i]); + for (int i = 0; i < EVisualisationDataType::NdataTypes; ++i) { + MultiView::getInstance()->registerElement(dataTypeLists[i]); + } } - MultiView::getInstance()->redraw3D(); } +void EventManager::GotoEvent(Int_t no) +{ + if (getDataSource()->getEventCount() > 0) { + if (no == -1) { + no = getDataSource()->getEventCount() - 1; + } + this->getDataSource()->setCurrentEvent(no); + displayCurrentEvent(); + } +} + void EventManager::NextEvent() { - Int_t event = (this->currentEvent + 1) % getDataSource()->GetEventCount(); - GotoEvent(event); + if (getDataSource()->getEventCount() > 0) { + if (this->getDataSource()->getCurrentEvent() < getDataSource()->getEventCount() - 1) { + Int_t event = (this->getDataSource()->getCurrentEvent() + 1) % getDataSource()->getEventCount(); + GotoEvent(event); + } + } } void EventManager::PrevEvent() { - GotoEvent(this->currentEvent - 1); + if (getDataSource()->getEventCount() > 0) { + if (this->getDataSource()->getCurrentEvent() > 0) { + GotoEvent(this->getDataSource()->getCurrentEvent() - 1); + } + } } void EventManager::Close() @@ -172,8 +174,8 @@ void EventManager::displayVisualisationEvent(VisualisationEvent& event, const st for (size_t i = 0; i < trackCount; ++i) { VisualisationTrack track = event.getTrack(i); TEveRecTrackD t; - double* p = track.getMomentum(); - t.fP = {p[0], p[1], p[2]}; + //double* p = track.getMomentum(); + //t.fP = {p[0], p[1], p[2]}; t.fSign = track.getCharge() > 0 ? 1 : -1; auto* vistrack = new TEveTrack(&t, &TEveTrackPropagator::fgDefault); vistrack->SetLineColor(kMagenta); @@ -206,11 +208,5 @@ void EventManager::displayVisualisationEvent(VisualisationEvent& event, const st } } -void EventManager::registerDetector(DataReader* reader, DataInterpreter* interpreter, EVisualisationGroup type) -{ - dataReaders[type] = reader; - dataInterpreters[type] = interpreter; -} - } // namespace event_visualisation } // namespace o2 diff --git a/EventVisualisation/View/src/EventManagerFrame.cxx b/EventVisualisation/View/src/EventManagerFrame.cxx index a5021ba53de9c..9f1b76c44c2ea 100644 --- a/EventVisualisation/View/src/EventManagerFrame.cxx +++ b/EventVisualisation/View/src/EventManagerFrame.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,12 +17,15 @@ #include <TGButton.h> #include <TGNumberEntry.h> #include <TGLabel.h> +#include <TTimer.h> #include <EventVisualisationView/EventManagerFrame.h> #include <EventVisualisationView/MultiView.h> #include <EventVisualisationBase/DataSourceOffline.h> #include <EventVisualisationDetectors/DataReaderVSD.h> #include <Rtypes.h> -#include <iostream> +#include <mutex> + +std::mutex mtx; // mutex for critical section ClassImp(o2::event_visualisation::EventManagerFrame); @@ -30,10 +34,18 @@ namespace o2 namespace event_visualisation { + EventManagerFrame::~EventManagerFrame() + { + this->StopTimer(); + } + EventManagerFrame::EventManagerFrame(o2::event_visualisation::EventManager& eventManager) : TGMainFrame(gClient->GetRoot(), 400, 100, kVerticalFrame) { mEventManager = &eventManager; + this->mTimer = new TTimer(); // Auto-load time in seconds + this->mTime = 2; + this->mTimer->Connect("Timeout()", "o2::event_visualisation::EventManagerFrame", this, "DoTimeTick()"); const TString cls("o2::event_visualisation::EventManagerFrame"); TGTextButton* b = nullptr; @@ -85,25 +97,25 @@ namespace o2 void EventManagerFrame::DoFirstEvent() { mEventManager->GotoEvent(0); - mEventId->SetIntNumber(mEventManager->getCurrentEvent()); + mEventId->SetIntNumber(mEventManager->getDataSource()->getCurrentEvent()); } void EventManagerFrame::DoPrevEvent() { mEventManager->PrevEvent(); - mEventId->SetIntNumber(mEventManager->getCurrentEvent()); + mEventId->SetIntNumber(mEventManager->getDataSource()->getCurrentEvent()); } void EventManagerFrame::DoNextEvent() { mEventManager->NextEvent(); - mEventId->SetIntNumber(mEventManager->getCurrentEvent()); + mEventId->SetIntNumber(mEventManager->getDataSource()->getCurrentEvent()); } void EventManagerFrame::DoLastEvent() { mEventManager->GotoEvent(-1); /// -1 means last available - mEventId->SetIntNumber(mEventManager->getCurrentEvent()); + mEventId->SetIntNumber(mEventManager->getDataSource()->getCurrentEvent()); } void EventManagerFrame::DoSetEvent() @@ -114,5 +126,42 @@ namespace o2 { } + void EventManagerFrame::DoTimeTick() + { + std::unique_lock<std::mutex> lck(mtx, std::defer_lock); + bool inTick; + lck.lock(); + inTick = this->inTick; + this->inTick = true; + lck.unlock(); + if (inTick) { + return; + } + + if (mEventManager->getDataSource()->refresh()) { + mEventManager->displayCurrentEvent(); + } + lck.lock(); + this->inTick = false; + lck.unlock(); + } + + void EventManagerFrame::StopTimer() + { + this->mTimerRunning = kFALSE; + if (this->mTimer != nullptr) { + this->mTimer->TurnOff(); + } + } + void EventManagerFrame::StartTimer() + { + if (this->mTimer != nullptr) { + this->mTimer->SetTime((Long_t)(1000 * this->mTime)); + this->mTimer->Reset(); + this->mTimer->TurnOn(); + } + this->mTimerRunning = kTRUE; + } + } // namespace event_visualisation } diff --git a/EventVisualisation/View/src/EventVisualisationViewLinkDef.h b/EventVisualisation/View/src/EventVisualisationViewLinkDef.h index bd1b2b0f08a45..3f96972fc3802 100644 --- a/EventVisualisation/View/src/EventVisualisationViewLinkDef.h +++ b/EventVisualisation/View/src/EventVisualisationViewLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/EventVisualisation/View/src/Initializer.cxx b/EventVisualisation/View/src/Initializer.cxx index 5df21b9f0fc15..1059af48c3d1f 100644 --- a/EventVisualisation/View/src/Initializer.cxx +++ b/EventVisualisation/View/src/Initializer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,11 +24,16 @@ #include "EventVisualisationView/MultiView.h" #include "EventVisualisationBase/VisualisationConstants.h" #include "EventVisualisationBase/DataSourceOffline.h" -#include "EventVisualisationDetectors/DataReaderTPC.h" -#include "EventVisualisationDetectors/DataInterpreterTPC.h" -#include "EventVisualisationDetectors/DataReaderITS.h" -#include "EventVisualisationDetectors/DataInterpreterITS.h" #include "EventVisualisationView/EventManagerFrame.h" +#include "EventVisualisationView/Options.h" + +#include "EventVisualisationDetectors/DataInterpreterITS.h" +#include "EventVisualisationDetectors/DataReaderITS.h" +#include "EventVisualisationDetectors/DataInterpreterTPC.h" +#include "EventVisualisationDetectors/DataReaderTPC.h" + +#include "EventVisualisationDetectors/DataReaderJSON.h" + #include "FairLogger.h" #include <TGTab.h> @@ -37,7 +43,6 @@ #include <TRegexp.h> #include <TSystem.h> #include <TEveWindowManager.h> -#include <TFile.h> using namespace std; namespace o2 @@ -45,7 +50,7 @@ namespace o2 namespace event_visualisation { -void Initializer::setup(const Options options, EventManager::EDataSource defaultDataSource) +void Initializer::setup(EventManager::EDataSource defaultDataSource) { TEnv settings; ConfigurationManager::getInstance().getConfig(settings); @@ -55,18 +60,25 @@ void Initializer::setup(const Options options, EventManager::EDataSource default LOG(INFO) << "Initializer -- OCDB path:" << ocdbStorage; auto& eventManager = EventManager::getInstance(); - eventManager.setDataSourceType(defaultDataSource); eventManager.setCdbPath(ocdbStorage); - eventManager.registerDetector(new DataReaderTPC(), new DataInterpreterTPC(), EVisualisationGroup::TPC); - eventManager.registerDetector(new DataReaderITS(), new DataInterpreterITS(), EVisualisationGroup::ITS); - - eventManager.setDataSourceType(EventManager::EDataSource::SourceOffline); + eventManager.setDataSourceType(defaultDataSource); eventManager.Open(); + if (Options::Instance()->tpc()) { + eventManager.getDataSource()->registerDetector(new DataReaderTPC(new DataInterpreterTPC()), EVisualisationGroup::TPC); + } + if (Options::Instance()->its()) { + eventManager.getDataSource()->registerDetector(new DataReaderITS(new DataInterpreterITS()), EVisualisationGroup::ITS); + } + if (Options::Instance()->json()) { + eventManager.getDataSource()->registerDetector(new DataReaderJSON(nullptr), EVisualisationGroup::JSON); + } + GeometryManager::getInstance().setR2Geometry(std::string(settings.GetValue("simple.geom.default", "R3")).compare("R2") == 0); setupGeometry(); + gSystem->ProcessEvents(); gEve->Redraw3D(true); @@ -94,8 +106,9 @@ void Initializer::setup(const Options options, EventManager::EDataSource default // For the time being we draw single random event on startup. // Later this will be triggered by button, and finally moved to configuration. gEve->AddEvent(&EventManager::getInstance()); - + eventManager.getDataSource()->refresh(); frame->DoFirstEvent(); + frame->StartTimer(); } void Initializer::setupGeometry() @@ -106,13 +119,16 @@ void Initializer::setupGeometry() // get geometry from Geometry Manager and register in multiview auto multiView = MultiView::getInstance(); + //auto geometry_enabled = GeometryManager::getInstance().getR2Geometry()? R2Visualisation:R3Visualisation; for (int iDet = 0; iDet < NvisualisationGroups; ++iDet) { + if (GeometryManager::getInstance().getR2Geometry()) { if (!R2Visualisation[iDet]) { continue; } } + if (!GeometryManager::getInstance().getR2Geometry()) { if (!R3Visualisation[iDet]) { continue; @@ -121,15 +137,19 @@ void Initializer::setupGeometry() EVisualisationGroup det = static_cast<EVisualisationGroup>(iDet); string detName = gVisualisationGroupName[det]; + LOG(INFO) << detName; + if (settings.GetValue((detName + ".draw").c_str(), false)) { - if (detName == "TPC" || detName == "MCH" || detName == "MTR" || detName == "MID" || detName == "MFT" || detName == "AD0" || detName == "FMD") { // don't load MUON+MFT and AD and standard TPC to R-Phi view + if (detName == "TPC" || detName == "MCH" || detName == "MID" || detName == "MFT") { // don't load MUON+MFT and AD and standard TPC to R-Phi view multiView->drawGeometryForDetector(detName, true, false); } else if (detName == "RPH") { // special TPC geom from R-Phi view multiView->drawGeometryForDetector(detName, false, true, false); } else { // default - multiView->drawGeometryForDetector(detName); + if (detName != "ACO") { + multiView->drawGeometryForDetector(detName); + } } } } diff --git a/EventVisualisation/View/src/MultiView.cxx b/EventVisualisation/View/src/MultiView.cxx index 2d04cb4ef254f..d8b6bd9517f58 100644 --- a/EventVisualisation/View/src/MultiView.cxx +++ b/EventVisualisation/View/src/MultiView.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -80,6 +81,7 @@ MultiView::MultiView() TEnv settings; ConfigurationManager::getInstance().getConfig(settings); const bool showAxes = settings.GetValue("axes.show", false); + if (showAxes) { for (int i = 0; i < NumberOfProjections; ++i) { TEveProjectionAxes axes(mProjections[static_cast<EProjections>(i)]); @@ -92,7 +94,6 @@ MultiView::MultiView() mScenes[getSceneOfProjection(static_cast<EProjections>(i))]->AddElement(&axes); } } - setupMultiview(); sInstance = this; } @@ -119,8 +120,8 @@ void MultiView::setupMultiview() pack->SetElementName("Multi View"); pack->SetHorizontal(); pack->SetShowTitleBar(kFALSE); - pack->NewSlotWithWeight(2)->MakeCurrent(); // new slot is created from pack + mViews[View3d] = gEve->SpawnNewViewer("3D View", ""); mViews[View3d]->AddScene(mScenes[Scene3dGeom]); mViews[View3d]->AddScene(mScenes[Scene3dEvent]); diff --git a/EventVisualisation/View/src/Options.cxx b/EventVisualisation/View/src/Options.cxx new file mode 100644 index 0000000000000..ec7be3b2d84bb --- /dev/null +++ b/EventVisualisation/View/src/Options.cxx @@ -0,0 +1,199 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Options.cxx +/// \author Julian Myrcha + +#include "EventVisualisationView/Options.h" +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/prettywriter.h" +#include "FairLogger.h" +#include <unistd.h> +#include <iostream> +#include <string> +#include <sstream> + +namespace o2 +{ +namespace event_visualisation +{ + +Options Options::instance; + +std::string Options::printOptions() +{ + static const char* str[2] = {"false", "true"}; + std::stringstream ss; + ss << "fileName : " << this->fileName() << std::endl; + ss << "randomTracks: " << str[this->randomTracks()] << std::endl; + ss << "itc : " << str[this->its()] << std::endl; + ss << "json : " << str[this->json()] << std::endl; + ss << "online : " << str[this->online()] << std::endl; + ss << "vsd : " << str[this->vsd()] << std::endl; + ss << "tpc : " << str[this->tpc()] << std::endl; + return ss.str(); +} + +std::string Options::usage() +{ + std::stringstream ss; + ss << "usage:" << std::endl; + ss << "\t" + << "o2eve <options>" << std::endl; + ss << "\t\t" + << "where <options> are any from the following:" << std::endl; + ss << "\t\t" + << "-h this help message" << std::endl; + ss << "\t\t" + << "-d name name of the data folder" << std::endl; + ss << "\t\t" + << "-f name name of the data file" << std::endl; + ss << "\t\t" + << "-i use itc reading from files as a source" << std::endl; + ss << "\t\t" + << "-j use json files as a source" << std::endl; + ss << "\t\t" + << "-o use online json files as a source" << std::endl; + ss << "\t\t" + << "-p name name of the options file" << std::endl; + ss << "\t\t" + << "-r use random tracks" << std::endl; + ss << "\t\t" + << "-s save options to o2eve.json in current folder" << std::endl; + ss << "\t\t" + << "-t use tpc reading from files as a source" << std::endl; + ss << "\t\t" + << "-v use vsd files as a source" << std::endl; + ss << "\tdefault values are always taken from o2eve.json in current folder if present" << std::endl; + return ss.str(); +} + +bool Options::processCommandLine(int argc, char* argv[]) +{ + int opt; + bool save = false; + std::string optionsFileName = "o2eve.json"; // name with options to use + + // put ':' in the starting of the + // string so that program can + //distinguish between '?' and ':' + while ((opt = getopt(argc, argv, ":d:f:hijop:rsvt")) != -1) { + switch (opt) { + case 'd': + this->mDataFolder = optarg; + break; + case 'f': + this->mFileName = optarg; + break; + case 'i': + this->mIts = true; + break; + case 'h': + std::cout << usage() << std::endl; + return false; + case 'j': + this->mJSON = true; + break; + case 'o': + this->mOnline = true; + break; + case 'p': + optionsFileName = optarg; + break; + case 'r': + this->mRandomTracks = true; + break; + case 's': + save = true; + break; + case 't': + this->mTpc = true; + break; + case 'v': + this->mVsd = true; + break; + case ':': + LOG(ERROR) << "option needs a value: " << char(optopt); + LOG(INFO) << usage(); + return false; + case '?': + LOG(ERROR) << "unknown option: " << char(optopt); + LOG(INFO) << usage(); + return false; + } + } + + // optind is for the extra arguments + // which are not parsed + for (; optind < argc; optind++) { + LOG(ERROR) << "extra arguments: " << argv[optind]; + LOG(INFO) << usage(); + return false; + } + + if (save) { + this->saveToJSON("o2eve.json"); + return false; + } + + return true; +} + +bool Options::saveToJSON(std::string filename) +{ + rapidjson::Value dataFolder; + rapidjson::Value fileName; + rapidjson::Value its(rapidjson::kNumberType); + rapidjson::Value json(rapidjson::kNumberType); + rapidjson::Value online(rapidjson::kNumberType); + rapidjson::Value randomTracks(rapidjson::kNumberType); + rapidjson::Value tpc(rapidjson::kNumberType); + rapidjson::Value vsd(rapidjson::kNumberType); + + dataFolder.SetString(rapidjson::StringRef(this->dataFolder().c_str())); + fileName.SetString(rapidjson::StringRef(this->fileName().c_str())); + its.SetBool(this->its()); + json.SetBool(this->json()); + online.SetBool(this->online()); + randomTracks.SetBool(this->randomTracks()); + tpc.SetBool(this->tpc()); + vsd.SetBool(this->vsd()); + + rapidjson::Document tree(rapidjson::kObjectType); + rapidjson::Document::AllocatorType& allocator = tree.GetAllocator(); + tree.AddMember("dataFolder", dataFolder, allocator); + tree.AddMember("fileName", fileName, allocator); + tree.AddMember("its", its, allocator); + tree.AddMember("json", json, allocator); + tree.AddMember("online", online, allocator); + tree.AddMember("randomTracks", randomTracks, allocator); + tree.AddMember("tpc", tpc, allocator); + tree.AddMember("vsd", vsd, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); + tree.Accept(writer); + + std::ofstream out(filename); + out << buffer.GetString(); + out.close(); + return true; +} + +bool Options::readFromJSON(std::string /*filename*/) +{ + return false; +} + +} // namespace event_visualisation +} // namespace o2 diff --git a/EventVisualisation/View/src/main.cxx b/EventVisualisation/View/src/main.cxx index f9d2c57aaf7d0..db828b3a23f6a 100644 --- a/EventVisualisation/View/src/main.cxx +++ b/EventVisualisation/View/src/main.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,9 @@ #include "EventVisualisationView/Initializer.h" #include "EventVisualisationBase/ConfigurationManager.h" + #include "EventVisualisationBase/DataInterpreter.h" +#include "EventVisualisationView/Options.h" #include "FairLogger.h" @@ -25,67 +28,16 @@ #include <TEveManager.h> #include <TEnv.h> -#include <unistd.h> #include <ctime> using namespace std; using namespace o2::event_visualisation; -std::string printOptions(Options* o) -{ - std::string res; - res.append(std::string("randomTracks: ") + (o->randomTracks ? "true" : "false") + "\n"); - res.append(std::string("vds : ") + (o->vsd ? "true" : "false") + "\n"); - res.append(std::string("itc : ") + (o->itc ? "true" : "false") + "\n"); - return res; -} - -Options* processCommandLine(int argc, char* argv[]) -{ - static Options options; - int opt; - - // put ':' in the starting of the - // string so that program can - //distinguish between '?' and ':' - while ((opt = getopt(argc, argv, ":if:rv")) != -1) { - switch (opt) { - case 'r': - options.randomTracks = true; - break; - case 'i': - options.itc = true; - break; - case 'v': - options.vsd = true; - break; - case 'f': - options.fileName = optarg; - break; - case ':': - printf("option needs a value\n"); - return nullptr; - case '?': - printf("unknown option: %c\n", optopt); - return nullptr; - } - } - - // optind is for the extra arguments - // which are not parsed - for (; optind < argc; optind++) { - printf("extra arguments: %s\n", argv[optind]); - return nullptr; - } - - return &options; -} - int main(int argc, char** argv) { LOG(INFO) << "Welcome in O2 event visualisation tool"; - Options* options = processCommandLine(argc, argv); - if (options == nullptr) { + + if (!Options::Instance()->processCommandLine(argc, argv)) { exit(-1); } @@ -112,13 +64,15 @@ int main(int argc, char** argv) exit(0); } + //gEve->SpawnNewViewer("3D View", ""); exit(0); + // Initialize o2 Event Visualisation - Initializer::setup(*options); + Initializer::setup(Options::Instance()->online() ? EventManager::SourceOnline : EventManager::SourceOffline); // Start the application app->Run(kTRUE); - DataInterpreter::removeInstances(); + //DataInterpreter::removeInstances(); // Terminate application TEveManager::Terminate(); app->Terminate(0); diff --git a/EventVisualisation/Workflow/CMakeLists.txt b/EventVisualisation/Workflow/CMakeLists.txt new file mode 100644 index 0000000000000..36f12dc61652f --- /dev/null +++ b/EventVisualisation/Workflow/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + + +if(ALIGPU_BUILD_TYPE STREQUAL "O2" + AND OPENGL_FOUND + AND GLFW_FOUND + AND TARGET AliceO2::DebugGUI + AND OPENGL_GLU_FOUND + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin" +) + o2_add_executable(display + COMPONENT_NAME eve + TARGETVARNAME targetName + SOURCES + src/O2DPLDisplay.cxx + src/FileProducer.cxx + src/EveWorkflowHelper.cxx + src/EveConfiguration.cxx + PUBLIC_LINK_LIBRARIES + O2::DataFormatsGlobalTracking + O2::DetectorsRaw + O2::DetectorsVertexing + O2::EventVisualisationBase + O2::EventVisualisationDetectors + O2::FrameworkFoundation + O2::FT0Workflow + O2::GlobalTrackingWorkflowHelpers + O2::GlobalTrackingWorkflowReaders + O2::ITSMFTWorkflow + O2::MFTWorkflow + O2::TOFBase + O2::TOFWorkflowIO + O2::TPCReconstruction + O2::TPCWorkflow + O2::TRDBase + O2::TRDWorkflowIO + ) + target_include_directories(${targetName} PUBLIC "include") +endif() diff --git a/EventVisualisation/Workflow/README.md b/EventVisualisation/Workflow/README.md new file mode 100644 index 0000000000000..b8912ca74e237 --- /dev/null +++ b/EventVisualisation/Workflow/README.md @@ -0,0 +1,64 @@ +<!-- doxy +\page refEventVisualisationWorkflow EventVisualisation Workflow +/doxy --> + +# Event Visualisation Workflow + +This module contains DPL worflow, which can be used to produce data (in JSON format) to be displayed be `o2-eve`. Workflow may be used: +* on EPN to produce data which are then copied to online visualisation machine in P2 (see process description \subpage refEventVisualisationScripts) +* locally to make visualisation based on simulated data + + +## Prepare data based on simulated data +before one starts steps described below, please verify that: +* for `o2-eve-display` step you should: + * start within the folder where simulated data was produced + * you need to store in the folder file ```ITSdictionary.bin``` (available from O2-2288 jira) +* for `o2-eve` step you should: + * have in the working folder: + * `.o2eve_config` file (available from EventVisualisation/Scripts) + * `o2sim_geometry.root` (copied from simulation folder) + * `o2sim_grp.root` (copied from simulation folder) + * have (somewhere) folder with json files (f.e `/home/ed/jsons`) + * have (somewhere) folder with simplify geometry files (f.e `/home/ed/geom/O2`) + + + +To visualise a simulated data one should: +* Run simulation +```shell +# for example: +enter dev +$O2_ROOT/prodtests/sim_challenge.sh -n 5 -s pbpb +``` +* Run Workflow in folder with files produced by simulation +```shell +o2-global-track-cluster-reader --track-types TPC,ITS --cluster-types TPC,ITS | o2-eve-display --display-tracks TPC,ITS --display-clusters TPC,ITS +``` +* Run `o2-eve` pointing a folder where produced `*.json` files were stored (see description # Event Visualisation View) +```shell +enter dev +o2-eve -j -d /home/ed/jsons -o +``` + + +## o2-eve-display command line parameters: + +| *parameter*| *default value* | *description* | +|-----|---|---| +|jsons-folder | jsons |name of the host allowed to produce files | +|eve-hostname | |name of the host allowed to produce files (empty means no limit) | +|eve-dds-collection-index |-1 |number of dpl collection allowed to produce files (-1 means no limit) | +|number-of_files |300 |maximum number of json files in folder (newer one will replace oldest) | +|number-of_tracks |-1 |maximum number of track stored in json file (-1 means no limit) | +|enable-mc |false |enable visualization of MC data | +|disable-mc |false |disable visualization of MC data | +|display-clusters |ITS,TPC,TRD,TOF |comma-separated list of clusters to display | +|display-tracks |TPC,ITS,ITS-TPC,TPC-TRD,ITS-TPC-TRD,TPC-TOF,ITS-TPC-TOF |comma-separated list of tracks to display | +|read-from-files |false | | +|disable-root-input |false |Disable root input overriding read-from-files | +|configKeyValues | |Semicolon separated key=value strings ..." | + + + + diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveConfiguration.h b/EventVisualisation/Workflow/include/EveWorkflow/EveConfiguration.h new file mode 100644 index 0000000000000..d7657e4f13f6a --- /dev/null +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveConfiguration.h @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file +/// \author Julian Myrcha + +#ifndef ALICE_O2_EVENTVISUALISATION_WORKFLOW_EVECONFIGURATION_H +#define ALICE_O2_EVENTVISUALISATION_WORKFLOW_EVECONFIGURATION_H + +#include "DataFormatsTPC/Constants.h" +#include "TRDBase/GeometryFlat.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" + +#include <memory> +#include <array> +#include <vector> +#include <functional> +#include <gsl/gsl> + +class TH1F; + +namespace o2 +{ +namespace event_visualisation +{ +template <class T> +struct DefaultPtr { + typedef T type; +}; +template <class T> +struct ConstPtr { + typedef const T type; +}; + +template <template <typename T> class S> +struct CalibObjectsTemplate { + typename S<o2::trd::GeometryFlat>::type* trdGeometry = nullptr; + typename S<o2::itsmft::TopologyDictionary>::type* itsPatternDict = nullptr; +}; + +typedef CalibObjectsTemplate<DefaultPtr> CalibObjects; // NOTE: These 2 must have identical layout since they are memcopied +typedef CalibObjectsTemplate<ConstPtr> CalibObjectsConst; + +struct SettingsGRP { + // All new members must be sizeof(int) resp. sizeof(float) for alignment reasons! + float solenoidBz = -5.00668; // solenoid field strength + int constBz = 0; // for test-MC events with constant Bz + int homemadeEvents = 0; // Toy-MC events + int continuousMaxTimeBin = 0; // 0 for triggered events, -1 for default of 23ms + int needsClusterer = 0; // Set to true if the data requires the clusterizer +}; + +struct SettingsProcessing { + bool runMC; +}; + +struct EveConfiguration { + EveConfiguration() = default; + ~EveConfiguration() = default; + EveConfiguration(const EveConfiguration&) = default; + SettingsGRP configGRP; + CalibObjectsConst configCalib; + SettingsProcessing configProcessing; + void ReadConfigurableParam(); +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h new file mode 100644 index 0000000000000..23d24b30a418c --- /dev/null +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file EveWorkflowHelper.h +/// \author julian.myrcha@cern.ch + +#ifndef ALICE_O2_EVENTVISUALISATION_WORKFLOW_EVEWORKFLOWHELPER_H +#define ALICE_O2_EVENTVISUALISATION_WORKFLOW_EVEWORKFLOWHELPER_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "EveWorkflow/EveConfiguration.h" +#include "EventVisualisationDataConverter/VisualisationEvent.h" + +namespace o2::event_visualisation +{ +using GID = o2::dataformats::GlobalTrackID; +using PNT = std::array<float, 3>; + +struct TracksSet { + std::vector<GID> trackGID; + std::vector<float> trackTime; +}; + +class EveWorkflowHelper +{ + static constexpr std::array<std::pair<float, float>, GID::NSources> minmaxR{{ + {1., 40.}, // ITS + {85., 240.}, // TPC + {-1, -1}, // TRD + {-1, -1}, // TOF + {-1, -1}, // PHS + {-1, -1}, // CPV + {-1, -1}, // EMC + {-1, -1}, // HMP + {-1, -1}, // MFT + {-1, -1}, // MCH + {-1, -1}, // MID + {-1, -1}, // ZDC + {-1, -1}, // FT0 + {-1, -1}, // VF0 + {-1, -1}, // FDD + {1., 240}, // ITSTPC + {85., 430.}, // TPCTOF + {85., 380.}, // TPCTRD + {1., 380.}, // ITSTPCTRD + {-1, -1}, // ITSTPCTOF, + {-1, -1}, // TPCTRDTOF, + {-1, -1}, // ITSTPCTRDTOF, // full barrel track + {-1, -1}, // ITSAB, + }}; + + public: + static std::vector<PNT> getTrackPoints(const o2::track::TrackPar& trc, float minR, float maxR, float maxStep); + void selectTracks(const CalibObjectsConst* calib, GID::mask_t maskCl, + GID::mask_t maskTrk, GID::mask_t maskMatch); + template <typename Functor> + void addTrackToEvent(Functor source, GID gid, float trackTime, float z = 0.); // store track in mEvent + void draw(std::string jsonPath, int numberOfFiles, int numberOfTracks = -1); + void drawTPC(GID gid, float trackTime); + void drawITS(GID gid, float trackTime); + void drawITSTPC(GID gid, float trackTime); + void drawITSTPCTOF(GID gid, float trackTime); + void drawITSClusters(GID gid, float trackTime); + void drawTPCClusters(GID gid, float trackTime); + void drawPoint(o2::BaseCluster<float> pnt); + void prepareITSClusters(std::string dictfile = ""); + o2::globaltracking::RecoContainer mRecoCont; + o2::globaltracking::RecoContainer& getRecoContainer() { return mRecoCont; } + TracksSet mTrackSet; + o2::event_visualisation::VisualisationEvent mEvent; + std::vector<o2::BaseCluster<float>> mITSClustersArray; +}; +} // namespace o2::event_visualisation + +#endif //ALICE_O2_EVENTVISUALISATION_WORKFLOW_EVEWORKFLOWHELPER_H diff --git a/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h b/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h new file mode 100644 index 0000000000000..71b2ee4d51a42 --- /dev/null +++ b/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file FileProducer.h +/// \author julian.myrcha@cern.ch + +#ifndef ALICE_O2_EVENTVISUALISATION_WORKFLOW_FILEPRODUCER_H +#define ALICE_O2_EVENTVISUALISATION_WORKFLOW_FILEPRODUCER_H + +#include <string> +#include <deque> + +namespace o2 +{ +namespace event_visualisation +{ +class FileProducer +{ + private: + static std::deque<std::string> load(const std::string& path); + + size_t mFilesInFolder; + std::string mPath; + std::string mName; + + public: + explicit FileProducer(const std::string& path, int filesInFolder = 10, + const std::string& name = "tracks{}.json"); + + [[nodiscard]] std::string newFileName() const; +}; + +} // namespace event_visualisation +} // namespace o2 + +#endif //ALICE_O2_EVENTVISUALISATION_WORKFLOW_FILEPRODUCER_H diff --git a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h new file mode 100644 index 0000000000000..fad7257245ea5 --- /dev/null +++ b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file EveWorkflowHelper.h +/// \author julian.myrcha@cern.ch + +#ifndef ALICE_O2_EVENTVISUALISATION_WORKFLOW_O2DPLDISPLAY_H +#define ALICE_O2_EVENTVISUALISATION_WORKFLOW_O2DPLDISPLAY_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "EveWorkflow/EveConfiguration.h" +#include "Framework/Task.h" +#include <memory> + +using GID = o2::dataformats::GlobalTrackID; + +namespace o2::trd +{ +class GeometryFlat; +} + +namespace o2::globaltracking +{ +struct DataRequest; +} + +namespace o2::itsmft +{ +class TopologyDictionary; +} + +namespace o2::event_visualisation +{ +class TPCFastTransform; + +class O2DPLDisplaySpec : public o2::framework::Task +{ + public: + O2DPLDisplaySpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t trkMask, + o2::dataformats::GlobalTrackID::mask_t clMask, + std::shared_ptr<o2::globaltracking::DataRequest> dataRequest, std::string jsonPath, + std::chrono::milliseconds timeInterval, int numberOfFiles, int numberOfTracks, bool eveHostNameMatch) + : mUseMC(useMC), mTrkMask(trkMask), mClMask(clMask), mDataRequest(dataRequest), mJsonPath(jsonPath), mTimeInteval(timeInterval), mNumberOfFiles(numberOfFiles), mNumberOfTracks(numberOfTracks), mEveHostNameMatch(eveHostNameMatch) + { + this->mTimeStamp = std::chrono::high_resolution_clock::now() - timeInterval; // first run meets condition + } + ~O2DPLDisplaySpec() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + bool mUseMC = false; + bool mEveHostNameMatch; // empty or correct hostname + std::string mJsonPath; // folder where files are stored + std::chrono::milliseconds mTimeInteval; // minimal interval between files in miliseconds + int mNumberOfFiles; // maximun number of files in folder - newer replaces older + int mNumberOfTracks; // maximun number of track in single file (0 means no limit) + std::chrono::time_point<std::chrono::high_resolution_clock> mTimeStamp; + + o2::dataformats::GlobalTrackID::mask_t mTrkMask; + o2::dataformats::GlobalTrackID::mask_t mClMask; + std::unique_ptr<EveConfiguration> mConfig; + std::unique_ptr<o2::trd::GeometryFlat> mTrdGeo; + std::unique_ptr<o2::itsmft::TopologyDictionary> mITSDict; + std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest; +}; + +} // namespace o2::event_visualisation + +#endif diff --git a/EventVisualisation/Workflow/src/EveConfiguration.cxx b/EventVisualisation/Workflow/src/EveConfiguration.cxx new file mode 100644 index 0000000000000..259009503cc75 --- /dev/null +++ b/EventVisualisation/Workflow/src/EveConfiguration.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EveConfiguration.cxx +/// \author julian.myrcha@cern.ch + +#include "EveWorkflow/EveConfiguration.h" + +using namespace o2::event_visualisation; + +void EveConfiguration::ReadConfigurableParam() +{ +} diff --git a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx new file mode 100644 index 0000000000000..87a35ce9fdd5e --- /dev/null +++ b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx @@ -0,0 +1,220 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EveWorkflowHelper.cxx +/// \author julian.myrcha@cern.ch + +#include <EveWorkflow/EveWorkflowHelper.h> +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "EveWorkflow/FileProducer.h" +#include "DataFormatsTRD/TrackTRD.h" + +#include "ITStracking/IOUtils.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsBase/Propagator.h" +#include <type_traits> + +using namespace o2::event_visualisation; + +void EveWorkflowHelper::selectTracks(const CalibObjectsConst* calib, + GID::mask_t maskCl, GID::mask_t maskTrk, GID::mask_t maskMatch) +{ + auto creator = [maskTrk, this](auto& trk, GID gid, float time, float) { + if (!maskTrk[gid.getSource()]) { + return true; + } + mTrackSet.trackGID.push_back(gid); + mTrackSet.trackTime.push_back(time); + return true; + }; + this->mRecoCont.createTracksVariadic(creator); +} + +void EveWorkflowHelper::draw(std::string jsonPath, int numberOfFiles, int numberOfTracks) +{ + EveWorkflowHelper::prepareITSClusters(); + + size_t nTracks = mTrackSet.trackGID.size(); + if (numberOfTracks != -1 && numberOfTracks < nTracks) { + nTracks = numberOfTracks; // less than available + } + for (size_t it = 0; it < nTracks; it++) { + const auto& gid = mTrackSet.trackGID[it]; + auto tim = mTrackSet.trackTime[it]; + + if (gid.getSource() == GID::TPC) { + drawTPC(gid, tim); + } + if (gid.getSource() == GID::ITS) { + drawITS(gid, tim); + } + if (gid.getSource() == GID::ITSTPC) { + drawITSTPC(gid, tim); + } else if (gid.getSource() == GID::ITSTPCTOF) { + drawITSTPCTOF(gid, tim); + } + } + FileProducer producer(jsonPath, numberOfFiles); + mEvent.toFile(producer.newFileName()); +} + +void EveWorkflowHelper::drawITSTPC(GID gid, float trackTime) +{ + const auto& track = mRecoCont.getTPCITSTrack(gid); + auto pnts = getTrackPoints(track, minmaxR[gid.getSource()].first, minmaxR[gid.getSource()].second, 4); + addTrackToEvent([this, trackTime](GID gid) { return mRecoCont.getTPCITSTrack(gid); }, trackTime, 0.); + GID gidTPC = track.getRefTPC(); + GID gidITS = track.getRefITS(); + drawITSClusters(gidITS, trackTime); + drawTPCClusters(gidTPC, trackTime); +} + +void EveWorkflowHelper::drawITSTPCTOF(GID gid, float trackTime) +{ + const auto& track = mRecoCont.getITSTPCTOFTrack(gid); + addTrackToEvent([this, trackTime](GID gid) { return mRecoCont.getITSTPCTOFTrack(gid); }, trackTime, 0.); + GID gidTPC = track.getRefTPC(); + GID gidITS = track.getRefITS(); + + drawITSClusters(gidITS, trackTime); + drawTPCClusters(gidTPC, trackTime); +} + +std::vector<PNT> EveWorkflowHelper::getTrackPoints(const o2::track::TrackPar& trc, float minR, float maxR, float maxStep) +{ + // adjust minR according to real track start fro track starting point + float rMin = std::sqrt(trc.getX() * trc.getX() + trc.getY() * trc.getY()); + if (rMin > minR) { + minR = rMin; + } + // prepare space points from the track param + std::vector<PNT> pnts; + int nSteps = std::max(2, int((maxR - minR) / maxStep)); + const auto prop = o2::base::Propagator::Instance(); + float xMin = trc.getX(), xMax = maxR * maxR - trc.getY() * trc.getY(); + if (xMax > 0) { + xMax = std::sqrt(xMax); + } + LOG(INFO) << "R: " << minR << " " << maxR << " || X: " << xMin << " " << xMax; + float dx = (xMax - xMin) / nSteps; + auto tp = trc; + float dxmin = std::abs(xMin - tp.getX()), dxmax = std::abs(xMax - tp.getX()); + bool res = false; + if (dxmin > dxmax) { //start from closest end + std::swap(xMin, xMax); + dx = -dx; + } + if (!prop->propagateTo(tp, xMin, false, 0.99, maxStep, o2::base::PropagatorF::MatCorrType::USEMatCorrNONE)) { + return pnts; + } + auto xyz = tp.getXYZGlo(); + pnts.emplace_back(PNT{xyz.X(), xyz.Y(), xyz.Z()}); + for (int is = 0; is < nSteps; is++) { + if (!prop->propagateTo(tp, tp.getX() + dx, false, 0.99, 999., o2::base::PropagatorF::MatCorrType::USEMatCorrNONE)) { + return pnts; + } + xyz = tp.getXYZGlo(); + pnts.emplace_back(PNT{xyz.X(), xyz.Y(), xyz.Z()}); + } + return pnts; +} + +void EveWorkflowHelper::drawPoint(o2::BaseCluster<float> pnt) +{ + mEvent.addCluster(pnt.getX(), pnt.getY(), pnt.getZ()); +} + +void EveWorkflowHelper::prepareITSClusters(std::string dictfile) +{ + o2::itsmft::TopologyDictionary dict; + if (dictfile.empty()) { + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); + dict.readBinaryFile(dictfile); + } + const auto& ITSClusterROFRec = mRecoCont.getITSClustersROFRecords(); + const auto& clusITS = mRecoCont.getITSClusters(); + if (clusITS.size() && ITSClusterROFRec.size()) { + const auto& patterns = mRecoCont.getITSClustersPatterns(); + auto pattIt = patterns.begin(); + mITSClustersArray.reserve(clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, dict); + } +} + +void EveWorkflowHelper::drawITSClusters(GID gid, float trackTime) +{ + + const auto& trc = mRecoCont.getITSTrack(gid); + auto refs = mRecoCont.getITSTracksClusterRefs(); + int entry0 = trc.getClusterEntry(gid.getIndex()); // correct? + int ncl = trc.getNumberOfClusters(); + for (int icl = 0; icl < ncl; icl++) { + const auto& pnt = mITSClustersArray[refs[icl]]; + drawPoint(pnt); + } +} + +void EveWorkflowHelper::drawTPCClusters(GID gid, float trackTime) +{ + const auto& trc = mRecoCont.getTPCTrack(gid); + auto refs = mRecoCont.getTPCTracksClusterRefs(); + + /* + int entry0 = trc.getClusterEntry(gid.getIndex()); // correct? + int ncl = trc.getNumberOfClusters(); + for (int icl=0;icl<ncl;icl++) { + const auto& pnt = mITSClustersArray[ refs[icl] ]; + drawPoint(pnt); + } + */ +} + +void EveWorkflowHelper::drawTPC(GID gid, float trackTime) +{ + const auto& tr = mRecoCont.getTPCTrack(gid); + auto vTrack = mEvent.addTrack({.time = static_cast<float>(trackTime * 8 * o2::constants::lhc::LHCBunchSpacingMUS), + .charge = tr.getCharge(), + .PID = tr.getPID(), + .startXYZ = {tr.getX(), tr.getY(), tr.getZ()}, + .phi = tr.getPhi(), + .theta = tr.getTheta(), + .source = GID::TPC}); + auto pnts = getTrackPoints(tr, minmaxR[gid.getSource()].first, minmaxR[gid.getSource()].second, 4); + float dz = 0.0; + for (size_t ip = 0; ip < pnts.size(); ip++) { + vTrack->addPolyPoint(pnts[ip][0], pnts[ip][1], pnts[ip][2] + dz); + } +} + +void EveWorkflowHelper::drawITS(GID gid, float trackTime) +{ + addTrackToEvent([this, trackTime](GID gid) { return mRecoCont.getITSTrack(gid); }, trackTime, 0.); +} + +template <typename Functor> +void EveWorkflowHelper::addTrackToEvent(Functor source, GID gid, float trackTime, float dz) +{ + const auto& tr = source(gid); + + auto vTrack = mEvent.addTrack({.time = trackTime, + .charge = tr.getCharge(), + .PID = tr.getPID(), + .startXYZ = {tr.getX(), tr.getY(), tr.getZ()}, + .phi = tr.getPhi(), + .theta = tr.getTheta(), + .source = (o2::dataformats::GlobalTrackID::Source)gid.getSource()}); + auto pnts = getTrackPoints(tr, minmaxR[gid.getSource()].first, minmaxR[gid.getSource()].second, 4); + + for (size_t ip = 0; ip < pnts.size(); ip++) { + vTrack->addPolyPoint(pnts[ip][0], pnts[ip][1], pnts[ip][2] + dz); + } +} diff --git a/EventVisualisation/Workflow/src/FileProducer.cxx b/EventVisualisation/Workflow/src/FileProducer.cxx new file mode 100644 index 0000000000000..c14a382b1ca55 --- /dev/null +++ b/EventVisualisation/Workflow/src/FileProducer.cxx @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file FileProducer.cxx +/// \author julian.myrcha@cern.ch + +#include "EveWorkflow/FileProducer.h" + +#include <deque> +#include <iostream> +#include <chrono> +#include <cstdio> +#include <filesystem> +#include <algorithm> + +using namespace std; +using namespace o2::event_visualisation; + +using std::cout; +using std::endl; +using std::chrono::duration_cast; +using std::chrono::milliseconds; +using std::chrono::seconds; +using std::chrono::system_clock; + +std::deque<std::string> FileProducer::load(const std::string& path) +{ + deque<string> result; + + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (entry.path().extension() == ".json") { + result.push_back(entry.path().filename()); + } + } + return result; +} + +FileProducer::FileProducer(const std::string& path, int filesInFolder, const std::string& name) +{ + this->mFilesInFolder = filesInFolder; + this->mPath = path; + this->mName = name; + std::filesystem::create_directories(this->mPath); // create folder if not exists (fails if no rights) +} + +std::string FileProducer::newFileName() const +{ + string pholder = "{}"; + string result = this->mName; + auto millisec_since_epoch = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); + string stamp = std::to_string(millisec_since_epoch); + result.replace(result.find(pholder), pholder.length(), stamp); + auto files = this->load(this->mPath); + std::sort(files.begin(), files.end()); + while (files.size() > this->mFilesInFolder) { + string front = files.front(); + files.pop_front(); + std::remove((this->mPath + "/" + front).c_str()); // delete file + } + return this->mPath + "/" + result; +} diff --git a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx new file mode 100644 index 0000000000000..db574571d03fe --- /dev/null +++ b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file +/// \author Julian Myrcha + +#include "EveWorkflow/O2DPLDisplay.h" +#include "EveWorkflow/EveWorkflowHelper.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "ITSBase/GeometryTGeo.h" +#include "TRDBase/GeometryFlat.h" +#include "TOFBase/Geo.h" +#include "TPCFastTransform.h" +#include "TRDBase/Geometry.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/ConfigParamSpec.h" + +#include <unistd.h> +#include <climits> + +using namespace o2::event_visualisation; +using namespace o2::framework; +using namespace o2::dataformats; +using namespace o2::globaltracking; +using namespace o2::tpc; +using namespace o2::trd; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"jsons-folder", VariantType::String, "jsons", {"name of the folder to store json files"}}, + {"eve-hostname", VariantType::String, "", {"name of the host allowed to produce files (empty means no limit)"}}, + {"eve-dds-collection-index", VariantType::Int, -1, {"number of dpl collection allowed to produce files (-1 means no limit)"}}, + {"number-of_files", VariantType::Int, 300, {"maximum number of json files in folder"}}, + {"number-of_tracks", VariantType::Int, -1, {"maximum number of track stored in json file (-1 means no limit)"}}, + {"time-interval", VariantType::Int, 5000, {"time interval in milliseconds between stored files"}}, + {"enable-mc", o2::framework::VariantType::Bool, false, {"enable visualization of MC data"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable visualization of MC data"}}, // for compatibility, overrides enable-mc + {"display-clusters", VariantType::String, "ITS,TPC,TRD,TOF", {"comma-separated list of clusters to display"}}, + {"display-tracks", VariantType::String, "TPC,ITS,ITS-TPC,TPC-TRD,ITS-TPC-TRD,TPC-TOF,ITS-TPC-TOF", {"comma-separated list of tracks to display"}}, + {"read-from-files", o2::framework::VariantType::Bool, false, {"comma-separated list of tracks to display"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"Disable root input overriding read-from-files"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // main method must be included here (otherwise customize not used) +void O2DPLDisplaySpec::init(InitContext& ic) +{ + const auto grp = o2::parameters::GRPObject::loadFrom(); + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + mConfig.reset(new EveConfiguration); + mConfig->configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + mConfig->configGRP.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; // Number of timebins in timeframe if continuous, 0 otherwise + mConfig->ReadConfigurableParam(); + + auto gm = o2::trd::Geometry::instance(); + gm->createPadPlaneArray(); + gm->createClusterMatrixArray(); + mTrdGeo.reset(new o2::trd::GeometryFlat(*gm)); + mConfig->configCalib.trdGeometry = mTrdGeo.get(); + + mITSDict = std::make_unique<o2::itsmft::TopologyDictionary>(); + mConfig->configCalib.itsPatternDict = mITSDict.get(); + mConfig->configProcessing.runMC = mUseMC; + + o2::tof::Geo::Init(); + + o2::its::GeometryTGeo::Instance()->fillMatrixCache( + o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::T2G, + o2::math_utils::TransformType::L2G, + o2::math_utils::TransformType::T2L)); +} + +void O2DPLDisplaySpec::run(ProcessingContext& pc) +{ + if (!this->mEveHostNameMatch) { + return; + } + + // filtering out any run which occur before reaching next time interval + std::chrono::time_point<std::chrono::high_resolution_clock> currentTime = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double> elapsed = currentTime - this->mTimeStamp; + if (elapsed < this->mTimeInteval) { + return; // skip this run - it is too often + } + this->mTimeStamp = currentTime; + + EveWorkflowHelper helper; + helper.getRecoContainer().collectData(pc, *mDataRequest); + helper.selectTracks(&(mConfig->configCalib), mClMask, mTrkMask, mTrkMask); + helper.draw(this->mJsonPath, this->mNumberOfFiles, this->mNumberOfTracks); +} + +void O2DPLDisplaySpec::endOfStream(EndOfStreamContext& ec) +{ +} + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + + std::string jsonFolder = cfgc.options().get<std::string>("jsons-folder"); + std::string eveHostName = cfgc.options().get<std::string>("eve-hostname"); + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + bool useMC = cfgc.options().get<bool>("enable-mc") && !cfgc.options().get<bool>("disable-mc"); + + char hostname[HOST_NAME_MAX]; + gethostname(hostname, HOST_NAME_MAX); + bool eveHostNameMatch = eveHostName.empty() || eveHostName == hostname; + + int eveDDSColIdx = cfgc.options().get<int>("eve-dds-collection-index"); + char* colIdx = getenv("DDS_COLLECTION_INDEX"); + eveHostNameMatch &= eveDDSColIdx == -1 || (colIdx && atoi(colIdx) == eveDDSColIdx); + + std::chrono::milliseconds timeInterval(cfgc.options().get<int>("time-interval")); + int numberOfFiles = cfgc.options().get<int>("number-of_files"); + int numberOfTracks = cfgc.options().get<int>("number-of_tracks"); + + GlobalTrackID::mask_t srcTrk = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("display-tracks")); + GlobalTrackID::mask_t srcCl = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("display-clusters")); + if (!srcTrk.any() && !srcCl.any()) { + throw std::runtime_error("No input configured"); + } + std::shared_ptr<DataRequest> dataRequest = std::make_shared<DataRequest>(); + dataRequest->requestTracks(srcTrk, useMC); + dataRequest->requestClusters(srcCl, useMC); + + if (cfgc.options().get<bool>("read-from-files")) { + InputHelper::addInputSpecs(cfgc, specs, srcCl, srcTrk, srcTrk, useMC); + } + + specs.emplace_back(DataProcessorSpec{ + "o2-eve-display", + dataRequest->inputs, + {}, + AlgorithmSpec{adaptFromTask<O2DPLDisplaySpec>(useMC, srcTrk, srcCl, dataRequest, jsonFolder, timeInterval, numberOfFiles, numberOfTracks, eveHostNameMatch)}}); + + return std::move(specs); +} diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 808de6e45cc11..45add9117f372 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Ex1) add_subdirectory(Ex2) diff --git a/Examples/Ex1/CMakeLists.txt b/Examples/Ex1/CMakeLists.txt index d1964b5451fb6..8b0ce72f00b16 100644 --- a/Examples/Ex1/CMakeLists.txt +++ b/Examples/Ex1/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Ex1 SOURCES src/A.cxx src/B.cxx diff --git a/Examples/Ex1/include/Ex1/A.h b/Examples/Ex1/include/Ex1/A.h index 9a013ba0f293a..dd329dde78b9f 100644 --- a/Examples/Ex1/include/Ex1/A.h +++ b/Examples/Ex1/include/Ex1/A.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex1/src/A.cxx b/Examples/Ex1/src/A.cxx index 68c34e02d5ed8..f428c8d3abedf 100644 --- a/Examples/Ex1/src/A.cxx +++ b/Examples/Ex1/src/A.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex1/src/B.cxx b/Examples/Ex1/src/B.cxx index c90c44f05fa7a..9251061809021 100644 --- a/Examples/Ex1/src/B.cxx +++ b/Examples/Ex1/src/B.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex1/src/B.h b/Examples/Ex1/src/B.h index 274c53309e8ed..8a620c762a28d 100644 --- a/Examples/Ex1/src/B.h +++ b/Examples/Ex1/src/B.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex2/CMakeLists.txt b/Examples/Ex2/CMakeLists.txt index 8ed7d61e5b61d..9ee1395cb3e3d 100644 --- a/Examples/Ex2/CMakeLists.txt +++ b/Examples/Ex2/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Ex2 SOURCES src/A.cxx src/B.cxx diff --git a/Examples/Ex2/include/Ex2/A.h b/Examples/Ex2/include/Ex2/A.h index 5367bac7d6bba..6176570e1be60 100644 --- a/Examples/Ex2/include/Ex2/A.h +++ b/Examples/Ex2/include/Ex2/A.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex2/src/A.cxx b/Examples/Ex2/src/A.cxx index 70369e8859942..7a2900b895a5f 100644 --- a/Examples/Ex2/src/A.cxx +++ b/Examples/Ex2/src/A.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex2/src/B.cxx b/Examples/Ex2/src/B.cxx index c90c44f05fa7a..9251061809021 100644 --- a/Examples/Ex2/src/B.cxx +++ b/Examples/Ex2/src/B.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex2/src/B.h b/Examples/Ex2/src/B.h index 274c53309e8ed..8a620c762a28d 100644 --- a/Examples/Ex2/src/B.h +++ b/Examples/Ex2/src/B.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex2/src/Ex2LinkDef.h b/Examples/Ex2/src/Ex2LinkDef.h index 70724b9ec69cd..81447323dade3 100644 --- a/Examples/Ex2/src/Ex2LinkDef.h +++ b/Examples/Ex2/src/Ex2LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/CMakeLists.txt b/Examples/Ex3/CMakeLists.txt index 01268c6b21a5d..ccd41c593d5d4 100644 --- a/Examples/Ex3/CMakeLists.txt +++ b/Examples/Ex3/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Ex3 SOURCES src/A.cxx src/B.cxx diff --git a/Examples/Ex3/include/Ex3/A.h b/Examples/Ex3/include/Ex3/A.h index e71ab6dc8e09c..9f6e1f2e021fb 100644 --- a/Examples/Ex3/include/Ex3/A.h +++ b/Examples/Ex3/include/Ex3/A.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/src/A.cxx b/Examples/Ex3/src/A.cxx index 191760646d18b..1135e6ee9c80d 100644 --- a/Examples/Ex3/src/A.cxx +++ b/Examples/Ex3/src/A.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/src/B.cxx b/Examples/Ex3/src/B.cxx index c90c44f05fa7a..9251061809021 100644 --- a/Examples/Ex3/src/B.cxx +++ b/Examples/Ex3/src/B.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/src/B.h b/Examples/Ex3/src/B.h index 274c53309e8ed..8a620c762a28d 100644 --- a/Examples/Ex3/src/B.h +++ b/Examples/Ex3/src/B.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/src/Ex3LinkDef.h b/Examples/Ex3/src/Ex3LinkDef.h index eb747c25a543c..a4c17ae49cb32 100644 --- a/Examples/Ex3/src/Ex3LinkDef.h +++ b/Examples/Ex3/src/Ex3LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex3/src/run.cxx b/Examples/Ex3/src/run.cxx index f84e232248ce6..fae2b40f8a616 100644 --- a/Examples/Ex3/src/run.cxx +++ b/Examples/Ex3/src/run.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/CMakeLists.txt b/Examples/Ex4/CMakeLists.txt index 1163e7073f363..18f7cdbcde280 100644 --- a/Examples/Ex4/CMakeLists.txt +++ b/Examples/Ex4/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Ex4 SOURCES src/A.cxx src/B.cxx diff --git a/Examples/Ex4/include/Ex4/A.h b/Examples/Ex4/include/Ex4/A.h index 4569b68cc2bf2..02418867b33b7 100644 --- a/Examples/Ex4/include/Ex4/A.h +++ b/Examples/Ex4/include/Ex4/A.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/src/A.cxx b/Examples/Ex4/src/A.cxx index 5470c69d007fb..fcc5e848ddc1a 100644 --- a/Examples/Ex4/src/A.cxx +++ b/Examples/Ex4/src/A.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/src/B.cxx b/Examples/Ex4/src/B.cxx index c90c44f05fa7a..9251061809021 100644 --- a/Examples/Ex4/src/B.cxx +++ b/Examples/Ex4/src/B.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/src/B.h b/Examples/Ex4/src/B.h index 274c53309e8ed..8a620c762a28d 100644 --- a/Examples/Ex4/src/B.h +++ b/Examples/Ex4/src/B.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/src/Ex4LinkDef.h b/Examples/Ex4/src/Ex4LinkDef.h index 3e733480cf211..62dfcdf1c0d73 100644 --- a/Examples/Ex4/src/Ex4LinkDef.h +++ b/Examples/Ex4/src/Ex4LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/src/run.cxx b/Examples/Ex4/src/run.cxx index 126248c4b755b..f14db42feaf64 100644 --- a/Examples/Ex4/src/run.cxx +++ b/Examples/Ex4/src/run.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/test/test1.cxx b/Examples/Ex4/test/test1.cxx index 6039b637fad63..534f114702976 100644 --- a/Examples/Ex4/test/test1.cxx +++ b/Examples/Ex4/test/test1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex4/test/test2.cxx b/Examples/Ex4/test/test2.cxx index 36e97dacd4502..33a0621512581 100644 --- a/Examples/Ex4/test/test2.cxx +++ b/Examples/Ex4/test/test2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Examples/Ex5/CMakeLists.txt b/Examples/Ex5/CMakeLists.txt index dd691ec774794..3951709a8a050 100644 --- a/Examples/Ex5/CMakeLists.txt +++ b/Examples/Ex5/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_executable(ex5 SOURCES src/run.cxx diff --git a/Examples/Ex5/src/run.cxx b/Examples/Ex5/src/run.cxx index 0ade248892b47..7ac6faff35e75 100644 --- a/Examples/Ex5/src/run.cxx +++ b/Examples/Ex5/src/run.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/AnalysisSupport/CMakeLists.txt b/Framework/AnalysisSupport/CMakeLists.txt new file mode 100644 index 0000000000000..d65d70190fb87 --- /dev/null +++ b/Framework/AnalysisSupport/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +# Given GCC 7.3 does not provide std::filesystem we use Boost instead +# Drop this once we move to GCC 8.2+ + +if(TARGET JAliEn::JAliEn) + set(EXTRA_TARGETS XRootD::Client JAliEn::JAliEn) +endif() + +o2_add_library(FrameworkAnalysisSupport + SOURCES src/Plugin.cxx + src/AODJAlienReaderHelpers.cxx + PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/src + PUBLIC_LINK_LIBRARIES O2::Framework ${EXTRA_TARGETS}) diff --git a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx new file mode 100644 index 0000000000000..d732deffec0d6 --- /dev/null +++ b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx @@ -0,0 +1,334 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "AODJAlienReaderHelpers.h" +#include "Framework/TableTreeHelpers.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/RootTableBuilderHelpers.h" +#include "Framework/AlgorithmSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/CallbackService.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/DeviceSpec.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DataInputDirector.h" +#include "Framework/SourceInfoHeader.h" +#include "Framework/ChannelInfo.h" +#include "Framework/Logger.h" + +#if __has_include(<TJAlienFile.h>) +#include <TJAlienFile.h> +#endif +#include <TGrid.h> +#include <TFile.h> +#include <TTreeCache.h> + +#include <arrow/ipc/reader.h> +#include <arrow/ipc/writer.h> +#include <arrow/io/interfaces.h> +#include <arrow/table.h> +#include <arrow/util/key_value_metadata.h> + +#include <thread> + +using namespace o2; +using namespace o2::aod; + +struct RuntimeWatchdog { + int numberTimeFrames; + uint64_t startTime; + uint64_t lastTime; + double runTime; + uint64_t runTimeLimit; + + RuntimeWatchdog(Long64_t limit) + { + numberTimeFrames = -1; + startTime = uv_hrtime(); + lastTime = startTime; + runTime = 0.; + runTimeLimit = limit; + } + + bool update() + { + numberTimeFrames++; + if (runTimeLimit <= 0) { + return true; + } + + auto nowTime = uv_hrtime(); + + // time spent to process the time frame + double time_spent = numberTimeFrames < 1 ? (double)(nowTime - lastTime) / 1.E9 : 0.; + runTime += time_spent; + lastTime = nowTime; + + return ((double)(lastTime - startTime) / 1.E9 + runTime / (numberTimeFrames + 1)) < runTimeLimit; + } + + void printOut() + { + LOGP(INFO, "RuntimeWatchdog"); + LOGP(INFO, " run time limit: {}", runTimeLimit); + LOGP(INFO, " number of time frames: {}", numberTimeFrames); + LOGP(INFO, " estimated run time per time frame: {}", (numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.); + LOGP(INFO, " estimated total run time: {}", (double)(lastTime - startTime) / 1.E9 + ((numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.)); + } +}; + +template <typename... C> +static constexpr auto columnNamesTrait(framework::pack<C...>) +{ + return std::vector<std::string>{C::columnLabel()...}; +} + +std::vector<std::string> getColumnNames(header::DataHeader dh) +{ + auto description = std::string(dh.dataDescription.str); + auto origin = std::string(dh.dataOrigin.str); + + // default: column names = {} + return std::vector<std::string>({}); +} + +using o2::monitoring::Metric; +using o2::monitoring::Monitoring; +using o2::monitoring::tags::Key; +using o2::monitoring::tags::Value; + +namespace o2::framework::readers +{ +auto setEOSCallback(InitContext& ic) +{ + ic.services().get<CallbackService>().set(CallbackService::Id::EndOfStream, + [](EndOfStreamContext& eosc) { + auto& control = eosc.services().get<ControlService>(); + control.endOfStream(); + control.readyToQuit(QuitRequest::Me); + }); +} + +template <typename O> +static inline auto extractTypedOriginal(ProcessingContext& pc) +{ + ///FIXME: this should be done in invokeProcess() as some of the originals may be compound tables + return O{pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable()}; +} + +template <typename... Os> +static inline auto extractOriginalsTuple(framework::pack<Os...>, ProcessingContext& pc) +{ + return std::make_tuple(extractTypedOriginal<Os>(pc)...); +} + +void AODJAlienReaderHelpers::dumpFileMetrics(Monitoring& monitoring, TFile* currentFile, uint64_t startedAt, uint64_t ioTime, int dfPerFile, int dfRead) +{ + if (currentFile == nullptr) { + return; + } + std::string monitoringInfo(fmt::format("lfn={},size={},total_df={},read_df={},read_bytes={},read_calls={},io_time={:.1f},wait_time={:.1f}", currentFile->GetName(), + currentFile->GetSize(), dfPerFile, dfRead, currentFile->GetBytesRead(), currentFile->GetReadCalls(), + ((float)ioTime / 1e9), ((float)(uv_hrtime() - startedAt - ioTime) / 1e9))); +#if __has_include(<TJAlienFile.h>) + auto alienFile = dynamic_cast<TJAlienFile*>(currentFile); + if (alienFile) { + monitoringInfo += fmt::format(",se={},open_time={:.1f}", alienFile->GetSE(), alienFile->GetElapsed()); + } +#endif + monitoring.send(Metric{monitoringInfo, "aod-file-read-info"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + LOGP(INFO, "Read info: {}", monitoringInfo); +} + +AlgorithmSpec AODJAlienReaderHelpers::rootFileReaderCallback() +{ + auto callback = AlgorithmSpec{adaptStateful([](ConfigParamRegistry const& options, + DeviceSpec const& spec, + Monitoring& monitoring) { + monitoring.send(Metric{(uint64_t)0, "arrow-bytes-created"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)0, "arrow-messages-created"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)0, "arrow-bytes-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)0, "arrow-messages-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)0, "arrow-bytes-expired"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.flushBuffer(); + + if (!options.isSet("aod-file")) { + LOGP(FATAL, "No input file defined!"); + throw std::runtime_error("Processing is stopped!"); + } + + auto filename = options.get<std::string>("aod-file"); + + // create a DataInputDirector + auto didir = std::make_shared<DataInputDirector>(filename); + if (options.isSet("aod-reader-json")) { + auto jsonFile = options.get<std::string>("aod-reader-json"); + if (!didir->readJson(jsonFile)) { + LOGP(ERROR, "Check the JSON document! Can not be properly parsed!"); + } + } + + // get the run time watchdog + auto* watchdog = new RuntimeWatchdog(options.get<int64_t>("time-limit")); + + // selected the TFN input and + // create list of requested tables + header::DataHeader TFNumberHeader; + std::vector<OutputRoute> requestedTables; + std::vector<OutputRoute> routes(spec.outputs); + for (auto route : routes) { + if (DataSpecUtils::partialMatch(route.matcher, header::DataOrigin("TFN"))) { + auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher); + TFNumberHeader = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec); + } else { + requestedTables.emplace_back(route); + } + } + + auto fileCounter = std::make_shared<int>(0); + auto numTF = std::make_shared<int>(-1); + return adaptStateless([TFNumberHeader, + requestedTables, + fileCounter, + numTF, + watchdog, + didir](Monitoring& monitoring, DataAllocator& outputs, ControlService& control, DeviceSpec const& device) { + // Each parallel reader device.inputTimesliceId reads the files fileCounter*device.maxInputTimeslices+device.inputTimesliceId + // the TF to read is numTF + assert(device.inputTimesliceId < device.maxInputTimeslices); + uint64_t timeFrameNumber = 0; + int fcnt = (*fileCounter * device.maxInputTimeslices) + device.inputTimesliceId; + int ntf = *numTF + 1; + static int currentFileCounter = -1; + static int filesProcessed = 0; + if (currentFileCounter != *fileCounter) { + currentFileCounter = *fileCounter; + monitoring.send(Metric{(uint64_t)++filesProcessed, "files-opened"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + } + + // loop over requested tables + bool first = true; + static size_t totalSizeUncompressed = 0; + static size_t totalSizeCompressed = 0; + static TFile* currentFile = nullptr; + static int tfCurrentFile = -1; + static auto currentFileStartedAt = uv_hrtime(); + static uint64_t currentFileIOTime = 0; + + // check if RuntimeLimit is reached + if (!watchdog->update()) { + LOGP(INFO, "Run time exceeds run time limit of {} seconds. Exiting gracefully...", watchdog->runTimeLimit); + LOGP(INFO, "Stopping reader {} after time frame {}.", device.inputTimesliceId, watchdog->numberTimeFrames - 1); + dumpFileMetrics(monitoring, currentFile, currentFileStartedAt, currentFileIOTime, tfCurrentFile, ntf); + monitoring.flushBuffer(); + didir->closeInputFiles(); + control.endOfStream(); + control.readyToQuit(QuitRequest::Me); + return; + } + + auto ioStart = uv_hrtime(); + + for (auto& route : requestedTables) { + if ((device.inputTimesliceId % route.maxTimeslices) != route.timeslice) { + continue; + } + + // create header + auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher); + auto dh = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec); + + // create a TreeToTable object + TTree* tr = didir->getDataTree(dh, fcnt, ntf); + if (!tr) { + if (first) { + // dump metrics of file which is done for reading + dumpFileMetrics(monitoring, currentFile, currentFileStartedAt, currentFileIOTime, tfCurrentFile, ntf); + currentFile = nullptr; + currentFileStartedAt = uv_hrtime(); + currentFileIOTime = 0; + + // check if there is a next file to read + fcnt += device.maxInputTimeslices; + if (didir->atEnd(fcnt)) { + LOGP(INFO, "No input files left to read for reader {}!", device.inputTimesliceId); + didir->closeInputFiles(); + control.endOfStream(); + control.readyToQuit(QuitRequest::Me); + return; + } + // get first folder of next file + ntf = 0; + tr = didir->getDataTree(dh, fcnt, ntf); + if (!tr) { + LOGP(FATAL, "Can not retrieve tree for table {}: fileCounter {}, timeFrame {}", concrete.origin, fcnt, ntf); + throw std::runtime_error("Processing is stopped!"); + } + } else { + LOGP(FATAL, "Can not retrieve tree for table {}: fileCounter {}, timeFrame {}", concrete.origin, fcnt, ntf); + throw std::runtime_error("Processing is stopped!"); + } + } + + if (first) { + timeFrameNumber = didir->getTimeFrameNumber(dh, fcnt, ntf); + auto o = Output(TFNumberHeader); + outputs.make<uint64_t>(o) = timeFrameNumber; + } + + // create table output + auto o = Output(dh); + auto& t2t = outputs.make<TreeToTable>(o); + + // add branches to read + // fill the table + auto colnames = getColumnNames(dh); + t2t.setLabel(tr->GetName()); + if (colnames.size() == 0) { + totalSizeCompressed += tr->GetZipBytes(); + totalSizeUncompressed += tr->GetTotBytes(); + t2t.addAllColumns(tr); + } else { + for (auto& colname : colnames) { + TBranch* branch = tr->GetBranch(colname.c_str()); + totalSizeCompressed += branch->GetZipBytes("*"); + totalSizeUncompressed += branch->GetTotBytes("*"); + } + t2t.addAllColumns(tr, std::move(colnames)); + } + t2t.fill(tr); + delete tr; + + // needed for metrics dumping (upon next file read, or terminate due to watchdog) + if (currentFile == nullptr) { + currentFile = didir->getFileFolder(dh, fcnt, ntf).file; + tfCurrentFile = didir->getTimeFramesInFile(dh, fcnt); + } + + first = false; + } + monitoring.send(Metric{(uint64_t)ntf, "df-sent"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)totalSizeUncompressed / 1000, "aod-bytes-read-uncompressed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)totalSizeCompressed / 1000, "aod-bytes-read-compressed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + + // save file number and time frame + *fileCounter = (fcnt - device.inputTimesliceId) / device.maxInputTimeslices; + *numTF = ntf; + currentFileIOTime += (uv_hrtime() - ioStart); + }); + })}; + + return callback; +} + +} // namespace o2::framework::readers diff --git a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.h b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.h new file mode 100644 index 0000000000000..655e4b6c0b439 --- /dev/null +++ b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.h @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_AODJALIENREADERHELPERS_H_ +#define O2_FRAMEWORK_AODJALIENREADERHELPERS_H_ + +#include "Framework/TableBuilder.h" +#include "Framework/AlgorithmSpec.h" +#include "Framework/Logger.h" +#include <Monitoring/Monitoring.h> +#include <uv.h> + +namespace o2::framework::readers +{ + +struct AODJAlienReaderHelpers { + static AlgorithmSpec rootFileReaderCallback(); + static void dumpFileMetrics(o2::monitoring::Monitoring& monitoring, TFile* currentFile, uint64_t startedAt, uint64_t ioTime, int tfPerFile, int tfRead); +}; + +} // namespace o2::framework::readers + +#endif // O2_FRAMEWORK_AODREADERHELPERS_H_ diff --git a/Framework/AnalysisSupport/src/Plugin.cxx b/Framework/AnalysisSupport/src/Plugin.cxx new file mode 100644 index 0000000000000..0113717fe0cc0 --- /dev/null +++ b/Framework/AnalysisSupport/src/Plugin.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/Plugins.h" +#include "Framework/AlgorithmSpec.h" +#include "AODJAlienReaderHelpers.h" + +struct ROOTFileReader : o2::framework::AlgorithmPlugin { + o2::framework::AlgorithmSpec create() override + { + return o2::framework::readers::AODJAlienReaderHelpers::rootFileReaderCallback(); + } +}; + +DEFINE_DPL_PLUGINS_BEGIN +DEFINE_DPL_PLUGIN_INSTANCE(ROOTFileReader, CustomAlgorithm); +DEFINE_DPL_PLUGINS_END diff --git a/Framework/AnalysisTools/CMakeLists.txt b/Framework/AnalysisTools/CMakeLists.txt deleted file mode 100644 index 17a188a04298b..0000000000000 --- a/Framework/AnalysisTools/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(AnalysisTools - SOURCES src/StepTHn.cxx - PUBLIC_LINK_LIBRARIES O2::Framework) - -o2_target_root_dictionary(AnalysisTools - HEADERS include/Framework/StepTHn.h - LINKDEF src/AnalysisToolsLinkDef.h) diff --git a/Framework/AnalysisTools/include/Framework/StepTHn.h b/Framework/AnalysisTools/include/Framework/StepTHn.h deleted file mode 100644 index 33a06d260ef77..0000000000000 --- a/Framework/AnalysisTools/include/Framework/StepTHn.h +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef StepTHn_H -#define StepTHn_H - -// optimized data container reusing functionality of THn -// A THnSparse is used to have the axis functionality "for free" - -#include "TNamed.h" -#include "THnSparse.h" -#include "TAxis.h" -#include "TArray.h" - -#include "Framework/Logger.h" - -class TArray; -class TArrayF; -class TArrayD; -class TCollection; - -class StepTHn : public TNamed -{ - public: - StepTHn(); - StepTHn(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxis, Int_t* nBins, std::vector<Double_t> binLimits[], const char** axisTitles); - ~StepTHn() override; - - template <typename... Ts> - void Fill(Int_t istep, const Ts&... valuesAndWeight); - - THnBase* getTHn(Int_t step, Bool_t sparse = kFALSE) - { - if (!mTarget || !mTarget[step]) { - createTarget(step, sparse); - } - return mTarget[step]; - } - Int_t getNSteps() { return mNSteps; } - Int_t getNVar() { return mNVars; } - - TArray* getValues(Int_t step) { return mValues[step]; } - TArray* getSumw2(Int_t step) { return mSumw2[step]; } - - StepTHn(const StepTHn& c); - StepTHn& operator=(const StepTHn& corr); - void Copy(TObject& c) const override; - - virtual Long64_t Merge(TCollection* list) = 0; - - protected: - void init(); - virtual TArray* createArray(const TArray* src = nullptr) const = 0; - void createTarget(Int_t step, Bool_t sparse); - void deleteContainers(); - - Long64_t getGlobalBinIndex(const Int_t* binIdx); - - Long64_t mNBins; // number of total bins - Int_t mNVars; // number of variables - Int_t mNSteps; // number of selection steps - TArray** mValues; //[mNSteps] data container - TArray** mSumw2; //[mNSteps] data container - - THnBase** mTarget; //! target histogram - - TAxis** mAxisCache; //! cache axis pointers (about 50% of the time in Fill is spent in GetAxis otherwise) - Int_t* mNbinsCache; //! cache Nbins per axis - Double_t* mLastVars; //! caching of last used bins (in many loops some vars are the same for a while) - Int_t* mLastBins; //! caching of last used bins (in many loops some vars are the same for a while) - - THnSparse* mPrototype; // not filled used as prototype histogram for axis functionality etc. - - ClassDef(StepTHn, 1) // THn like container -}; - -template <class TemplateArray> -class StepTHnT : public StepTHn -{ - public: - StepTHnT() : StepTHn() {} - StepTHnT(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxis, Int_t* nBins, std::vector<Double_t> binLimits[], const char** axisTitles); - ~StepTHnT() override = default; - - protected: - TArray* createArray(const TArray* src = nullptr) const override - { - if (src == nullptr) { - return new TemplateArray(mNBins); - } else { - return new TemplateArray(*((TemplateArray*)src)); - } - } - - Long64_t Merge(TCollection* list) override; - - ClassDef(StepTHnT, 1) // THn like container -}; - -typedef StepTHnT<TArrayF> StepTHnF; -typedef StepTHnT<TArrayD> StepTHnD; - -template <typename... Ts> -void StepTHn::Fill(Int_t istep, const Ts&... valuesAndWeight) -{ - constexpr int nParams = sizeof...(Ts); - // TODO Find a way to avoid the array - double tempArray[nParams] = {static_cast<double>(valuesAndWeight)...}; - - double weight = 1.0; - if (nParams == mNVars + 1) { - weight = tempArray[mNVars]; - } else if (nParams != mNVars) { - LOGF(fatal, "Fill called with invalid number of parameters (%d vs %d)", mNVars, nParams); - } - - // fill axis cache - if (!mAxisCache) { - mAxisCache = new TAxis*[mNVars]; - mNbinsCache = new Int_t[mNVars]; - for (Int_t i = 0; i < mNVars; i++) { - mAxisCache[i] = mPrototype->GetAxis(i); - mNbinsCache[i] = mAxisCache[i]->GetNbins(); - } - - mLastVars = new Double_t[mNVars]; - mLastBins = new Int_t[mNVars]; - - // initial values to prevent checking for 0 below - for (Int_t i = 0; i < mNVars; i++) { - mLastVars[i] = tempArray[i]; - mLastBins[i] = mAxisCache[i]->FindBin(mLastVars[i]); - } - } - - // calculate global bin index - Long64_t bin = 0; - for (Int_t i = 0; i < mNVars; i++) { - bin *= mNbinsCache[i]; - - Int_t tmpBin = 0; - if (mLastVars[i] == tempArray[i]) { - tmpBin = mLastBins[i]; - } else { - tmpBin = mAxisCache[i]->FindBin(tempArray[i]); - mLastBins[i] = tmpBin; - mLastVars[i] = tempArray[i]; - } - //Printf("%d", tmpBin); - - // under/overflow not supported - if (tmpBin < 1 || tmpBin > mNbinsCache[i]) { - return; - } - - // bins start from 0 here - bin += tmpBin - 1; - // Printf("%lld", bin); - } - - if (!mValues[istep]) { - mValues[istep] = createArray(); - LOGF(info, "Created values container for step %d", istep); - } - - if (weight != 1) { - // initialize with already filled entries (which have been filled with weight == 1), in this case mSumw2 := mValues - if (!mSumw2[istep]) { - mSumw2[istep] = createArray(); - LOGF(info, "Created sumw2 container for step %d", istep); - } - } - - // TODO probably slow; add StepTHnT::add ? - mValues[istep]->SetAt(mValues[istep]->GetAt(bin) + weight, bin); - if (mSumw2[istep]) { - mSumw2[istep]->SetAt(mSumw2[istep]->GetAt(bin) + weight, bin); - } -} - -#endif diff --git a/Framework/AnalysisTools/src/AnalysisToolsLinkDef.h b/Framework/AnalysisTools/src/AnalysisToolsLinkDef.h deleted file mode 100644 index 368cb36e4b745..0000000000000 --- a/Framework/AnalysisTools/src/AnalysisToolsLinkDef.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class StepTHn + ; -#pragma link C++ class StepTHnT < TArrayF> + ; -#pragma link C++ class StepTHnT < TArrayD> + ; -#pragma link C++ typedef StepTHnF; -#pragma link C++ typedef StepTHnD; diff --git a/Framework/AnalysisTools/src/StepTHn.cxx b/Framework/AnalysisTools/src/StepTHn.cxx deleted file mode 100644 index 9bc3fe8391138..0000000000000 --- a/Framework/AnalysisTools/src/StepTHn.cxx +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// Use StepTHn instead of THn and your memory consumption will be drastically reduced -// Once you have the merged output, use getTHn() to get a standard histogram -// -// this storage container is optimized for small memory usage -// under/over flow bins do not exist -// sumw2 structure is float only and only create when the weight != 1 -// -// Templated version allows also the use of double as storage container - -#include "Framework/StepTHn.h" -#include "TList.h" -#include "TCollection.h" -#include "TArrayF.h" -#include "TArrayD.h" -#include "THn.h" -#include "TMath.h" - -ClassImp(StepTHn) - templateClassImp(StepTHnT) - - StepTHn::StepTHn() : mNBins(0), - mNVars(0), - mNSteps(0), - mValues(nullptr), - mSumw2(nullptr), - mTarget(nullptr), - mAxisCache(nullptr), - mNbinsCache(nullptr), - mLastVars(nullptr), - mLastBins(nullptr), - mPrototype(nullptr) -{ - // Default constructor (for streaming) -} - -StepTHn::StepTHn(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxis, Int_t* nBins, std::vector<Double_t> binEdges[], const char** axisTitles) : TNamed(name, title), - mNBins(0), - mNVars(nAxis), - mNSteps(nSteps), - mValues(nullptr), - mSumw2(nullptr), - mTarget(nullptr), - mAxisCache(nullptr), - mNbinsCache(nullptr), - mLastVars(nullptr), - mLastBins(nullptr), - mPrototype(nullptr) -{ - // Constructor - // - // This will create a container for <nSteps> steps. The memory for such a step is only allocated once the first value is filled. - // Therefore you can easily create many steps which are only filled under certain analysis settings. - // For each step a <nAxis> dimensional histogram is created. - // The axis have <nBins[i]> bins. The bin edges are given in <binEdges[i]>. If there are only two bin edges, equidistant binning is set. - - init(); -} - -template <class TemplateArray> -StepTHnT<TemplateArray>::StepTHnT(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxis, - Int_t* nBins, std::vector<Double_t> binEdges[], const char** axisTitles) : StepTHn(name, title, nSteps, nAxis, nBins, binEdges, axisTitles) -{ - mNBins = 1; - for (Int_t i = 0; i < mNVars; i++) { - mNBins *= nBins[i]; - } - if constexpr (std::is_same_v<TemplateArray, TArrayD>) { - mPrototype = new THnSparseD(Form("%s_sparse", name), title, nAxis, nBins); - } else { - mPrototype = new THnSparseF(Form("%s_sparse", name), title, nAxis, nBins); - } - for (Int_t i = 0; i < mNVars; i++) { - if (nBins[i] + 1 == binEdges[i].size()) { // variable-width binning - mPrototype->GetAxis(i)->Set(nBins[i], &(binEdges[i])[0]); - } else if (binEdges[i].size() == 2) { // equidistant binning - mPrototype->GetAxis(i)->Set(nBins[i], binEdges[i][0], binEdges[i][1]); - } else { - LOGF(fatal, "Invalid binning information for axis %d with %d bins and %d entries for bin edges", i, nBins[i], binEdges[i].size()); - } - LOGF(debug, "Histogram %s Axis %d created with %d bins and %d edges", name, i, nBins[i], binEdges[i].size()); - mPrototype->GetAxis(i)->SetTitle(axisTitles[i]); - } -} - -void StepTHn::init() -{ - // initialize - - mValues = new TArray*[mNSteps]; - mSumw2 = new TArray*[mNSteps]; - - for (Int_t i = 0; i < mNSteps; i++) { - mValues[i] = nullptr; - mSumw2[i] = nullptr; - } -} - -StepTHn::StepTHn(const StepTHn& c) : mNBins(c.mNBins), - mNVars(c.mNVars), - mNSteps(c.mNSteps), - mValues(new TArray*[c.mNSteps]), - mSumw2(new TArray*[c.mNSteps]), - mTarget(nullptr), - mAxisCache(nullptr), - mNbinsCache(nullptr), - mLastVars(nullptr), - mLastBins(nullptr), - mPrototype(nullptr) -{ - // - // StepTHn copy constructor - // - - ((StepTHn&)c).Copy(*this); -} - -StepTHn::~StepTHn() -{ - // Destructor - - deleteContainers(); - - delete[] mValues; - delete[] mSumw2; - delete[] mTarget; - delete[] mAxisCache; - delete[] mNbinsCache; - delete[] mLastVars; - delete[] mLastBins; - delete mPrototype; -} - -void StepTHn::deleteContainers() -{ - // delete data containers - - for (Int_t i = 0; i < mNSteps; i++) { - if (mValues && mValues[i]) { - delete mValues[i]; - mValues[i] = nullptr; - } - - if (mSumw2 && mSumw2[i]) { - delete mSumw2[i]; - mSumw2[i] = nullptr; - } - - if (mTarget && mTarget[i]) { - delete mTarget[i]; - mTarget[i] = nullptr; - } - } -} - -StepTHn& StepTHn::operator=(const StepTHn& c) -{ - // assigment operator - - if (this != &c) { - ((StepTHn&)c).Copy(*this); - } - - return *this; -} - -void StepTHn::Copy(TObject& c) const -{ - // copy function - - StepTHn& target = (StepTHn&)c; - - TNamed::Copy(c); - - target.mNBins = mNBins; - target.mNVars = mNVars; - target.mNSteps = mNSteps; - - target.init(); - - for (Int_t i = 0; i < mNSteps; i++) { - if (mValues[i]) { - target.mValues[i] = createArray(mValues[i]); - } else { - target.mValues[i] = nullptr; - } - - if (mSumw2[i]) { - target.mSumw2[i] = createArray(mSumw2[i]); - } else { - target.mSumw2[i] = nullptr; - } - } - - if (mPrototype) { - target.mPrototype = dynamic_cast<THnSparseF*>(mPrototype->Clone()); - } -} - -template <class TemplateArray> -Long64_t StepTHnT<TemplateArray>::Merge(TCollection* list) -{ - // Merge a list of StepTHn objects with this (needed for - // PROOF). - // Returns the number of merged objects (including this). - - if (!list) { - return 0; - } - - if (list->IsEmpty()) { - return 1; - } - - TIterator* iter = list->MakeIterator(); - TObject* obj; - - Int_t count = 0; - while ((obj = iter->Next())) { - - StepTHnT<TemplateArray>* entry = dynamic_cast<StepTHnT<TemplateArray>*>(obj); - if (entry == nullptr) { - continue; - } - - for (Int_t i = 0; i < mNSteps; i++) { - if (entry->mValues[i]) { - if (!mValues[i]) { - mValues[i] = createArray(); - } - - auto source = dynamic_cast<TemplateArray*>(entry->mValues[i])->GetArray(); - auto target = dynamic_cast<TemplateArray*>(mValues[i])->GetArray(); - for (Long64_t l = 0; l < mNBins; l++) { - target[l] += source[l]; - } - } - - if (entry->mSumw2[i]) { - if (!mSumw2[i]) { - mSumw2[i] = createArray(); - } - - auto source = dynamic_cast<TemplateArray*>(entry->mSumw2[i])->GetArray(); - auto target = dynamic_cast<TemplateArray*>(mSumw2[i])->GetArray(); - for (Long64_t l = 0; l < mNBins; l++) { - target[l] += source[l]; - } - } - } - - count++; - } - - return count + 1; -} - -Long64_t StepTHn::getGlobalBinIndex(const Int_t* binIdx) -{ - // calculates global bin index - // binIdx contains TAxis bin indexes - // here bin count starts at 0 because we do not have over/underflow bins - - Long64_t bin = 0; - for (Int_t i = 0; i < mNVars; i++) { - bin *= mPrototype->GetAxis(i)->GetNbins(); - bin += binIdx[i] - 1; - } - - return bin; -} - -void StepTHn::createTarget(Int_t step, Bool_t sparse) -{ - // fills the information stored in the buffer in this class into the target THn - - if (!mValues[step]) { - LOGF(fatal, "Histogram request for step %d which is empty.", step); - return; - } - - if (!mTarget) { - mTarget = new THnBase*[mNSteps]; - for (Int_t i = 0; i < mNSteps; i++) { - mTarget[i] = nullptr; - } - } - - if (mTarget[step]) { - return; - } - - TArray* source = mValues[step]; - // if mSumw2 is not stored, the sqrt of the number of bin entries in source is filled below; otherwise we use mSumw2 - TArray* sourceSumw2 = source; - if (mSumw2[step]) { - sourceSumw2 = mSumw2[step]; - } - - if (sparse) { - mTarget[step] = THnSparse::CreateSparse(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype); - } else { - mTarget[step] = THn::CreateHn(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype); - } - - THnBase* target = mTarget[step]; - - Int_t* binIdx = new Int_t[mNVars]; - Int_t* nBins = new Int_t[mNVars]; - for (Int_t j = 0; j < mNVars; j++) { - binIdx[j] = 1; - nBins[j] = target->GetAxis(j)->GetNbins(); - } - - Long64_t count = 0; - - while (1) { - // for (Int_t j=0; j<mNVars; j++) - // printf("%d ", binIdx[j]); - - Long64_t globalBin = getGlobalBinIndex(binIdx); - // Printf(" --> %lld", globalBin); - - // TODO probably slow - double value = source->GetAt(globalBin); - if (value != 0) { - target->SetBinContent(binIdx, value); - target->SetBinError(binIdx, TMath::Sqrt(sourceSumw2->GetAt(globalBin))); - - count++; - } - - binIdx[mNVars - 1]++; - - for (Int_t j = mNVars - 1; j > 0; j--) { - if (binIdx[j] > nBins[j]) { - binIdx[j] = 1; - binIdx[j - 1]++; - } - } - - if (binIdx[0] > nBins[0]) { - break; - } - } - - LOGF(info, "Step %d: copied %lld entries out of %lld bins", step, count, getGlobalBinIndex(binIdx)); - - delete[] binIdx; - delete[] nBins; - - delete mValues[step]; - mValues[step] = nullptr; -} - -template class StepTHnT<TArrayF>; -template class StepTHnT<TArrayD>; diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index 17b18bebad581..92830e8d2e563 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. add_subdirectory(Logger) @@ -16,6 +17,11 @@ add_subdirectory(Core) add_subdirectory(Utils) -add_subdirectory(TestWorkflows) +add_subdirectory(AnalysisSupport) + +# Build the GUI support only if we have DebugGUI +if (TARGET AliceO2::DebugGUI) +add_subdirectory(GUISupport) +endif() -add_subdirectory(AnalysisTools) +add_subdirectory(TestWorkflows) diff --git a/Framework/Core/ANALYSIS.md b/Framework/Core/ANALYSIS.md index bb625129078dd..c68caf93f195f 100644 --- a/Framework/Core/ANALYSIS.md +++ b/Framework/Core/ANALYSIS.md @@ -2,6 +2,21 @@ \page refFrameworkCoreANALYSIS Core ANALYSIS /doxy --> +The comprehensive documentation of the O2 Analysis Framework is located at [https://aliceo2group.github.io/analysis-framework/](https://aliceo2group.github.io/analysis-framework/). + +```note +Please do not update this document, but contribute directly to the O2 Analysis Framework documentation at + +https://github.com/AliceO2Group/analysis-framework/tree/master/docs/framework + +status May 17, 2021 +``` + +--- +--- + + + ## Core ANALYSIS This document is WIP and provides an idea of what kind of API to expect from the DPL enabled analysis framework. APIs are neither final nor fully implemented in O2. @@ -28,7 +43,7 @@ struct MyTask : AnalysisTask { defineDataProcessing() { return { - adaptAnalysisTask<MyTask>("my-task-unique-name"); + adaptAnalysisTask<MyTask>(TaskName{"my-task-unique-name"}); }; } ``` diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index badffa9815841..0d2df3fd4497f 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -1,32 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -if (TARGET AliceO2::DebugGUI) - set(GUI_SOURCES src/FrameworkGUIDebugger.cxx src/FrameworkGUIDevicesGraph.cxx - src/FrameworkGUIDeviceInspector.cxx - src/FrameworkGUIDataRelayerUsage.cxx src/PaletteHelpers.cxx) - set(DEBUGGUI_TARGET AliceO2::DebugGUI) -else() - set(GUI_SOURCES src/FrameworkDummyDebugger.cxx) -endif() - -# Given GCC 7.3 does not provide std::filesystem we use Boost instead -# Drop this once we move to GCC 8.2+ -# if (NOT __APPLE__) - set(BOOST_FILESYSTEM Boost::filesystem) -# endif() +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Framework SOURCES src/AODReaderHelpers.cxx + src/ArrowSupport.cxx + src/AnalysisDataModel.cxx src/ASoA.cxx - ${GUI_SOURCES} src/AnalysisHelpers.cxx src/AnalysisDataModelHelpers.cxx src/BoostOptionsRetriever.cxx @@ -34,13 +21,19 @@ o2_add_library(Framework src/ChannelMatching.cxx src/ChannelConfigurationPolicyHelpers.cxx src/ChannelSpecHelpers.cxx + src/CCDBParamSpec.cxx + src/CommandInfo.cxx src/CommonDataProcessors.cxx src/CommonServices.cxx src/CommonMessageBackends.cxx + src/CommonDriverServices.cxx src/CompletionPolicy.cxx src/CompletionPolicyHelpers.cxx + src/ComputingQuotaEvaluator.cxx src/ComputingResourceHelpers.cxx src/ConfigContext.cxx + src/ControlService.cxx + src/ControlServiceHelpers.cxx src/DispatchPolicy.cxx src/ConfigParamStore.cxx src/ConfigParamsHelper.cxx @@ -51,16 +44,22 @@ o2_add_library(Framework src/DataProcessingDevice.cxx src/DataProcessingHeader.cxx src/DataProcessingHelpers.cxx + src/DataRefUtils.cxx src/SourceInfoHeader.cxx src/DataProcessor.cxx src/DataRelayer.cxx src/DataRelayerHelpers.cxx src/DataSpecUtils.cxx src/DeviceConfigInfo.cxx + src/DevicesManager.cxx src/DeviceMetricsInfo.cxx + src/DeviceMetricsHelper.cxx src/DeviceSpec.cxx + src/DeviceController.cxx src/DeviceSpecHelpers.cxx + src/DPLMonitoringBackend.cxx src/DriverControl.cxx + src/DriverClient.cxx src/DriverInfo.cxx src/Expressions.cxx src/FairMQDeviceProxy.cxx @@ -69,22 +68,31 @@ o2_add_library(Framework src/ConfigurationOptionsRetriever.cxx src/FreePortFinder.cxx src/GraphvizHelpers.cxx + src/HTTPParser.cxx src/InputRecord.cxx + src/InputRouteHelpers.cxx + src/InputSpan.cxx src/InputSpec.cxx src/OutputSpec.cxx src/LifetimeHelpers.cxx src/LocalRootFileService.cxx src/RootConfigParamHelpers.cxx + src/RawBufferContext.cxx + src/StringContext.cxx src/LogParsingHelpers.cxx src/MessageContext.cxx src/Metric2DViewIndex.cxx src/SimpleOptionsRetriever.cxx src/O2ControlHelpers.cxx + src/O2ControlLabels.cxx src/OutputSpec.cxx src/PropertyTreeHelpers.cxx + src/Plugins.cxx src/RCombinedDS.cxx src/ReadoutAdapter.cxx src/ResourcesMonitoringHelper.cxx + src/ResourcePolicy.cxx + src/ResourcePolicyHelpers.cxx src/ServiceRegistry.cxx src/SimpleResourceManager.cxx src/SimpleRawDeviceService.cxx @@ -93,21 +101,28 @@ o2_add_library(Framework src/TableBuilder.cxx src/TableConsumer.cxx src/TableTreeHelpers.cxx + src/TopologyPolicy.cxx + src/TextDriverClient.cxx src/DataInputDirector.cxx src/DataOutputDirector.cxx src/Task.cxx - src/TextControlService.cxx + src/Array2D.cxx src/Variant.cxx + src/WorkflowCustomizationHelpers.cxx src/WorkflowHelpers.cxx src/WorkflowSerializationHelpers.cxx src/WorkflowSpec.cxx + src/WSDriverClient.cxx src/runDataProcessing.cxx src/ExternalFairMQDeviceProxy.cxx + src/HistogramSpec.cxx src/HistogramRegistry.cxx + src/StepTHn.cxx + src/Base64.cxx + src/DPLWebSocket.cxx test/TestClasses.cxx PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/src - PUBLIC_LINK_LIBRARIES ${DEBUGGUI_TARGET} - AliceO2::Common + PUBLIC_LINK_LIBRARIES AliceO2::Common AliceO2::Configuration AliceO2::InfoLogger AliceO2::Monitoring @@ -115,13 +130,14 @@ o2_add_library(Framework FairMQ::FairMQ O2::CommonUtils O2::MathUtils + O2::CCDB O2::FrameworkFoundation O2::Headers O2::MemoryResources O2::PCG RapidJSON::RapidJSON arrow::arrow_shared - ms_gsl::ms_gsl + Microsoft.GSL::GSL ROOT::ROOTDataFrame O2::FrameworkLogger Boost::serialization @@ -132,6 +148,7 @@ o2_add_library(Framework o2_target_root_dictionary(Framework HEADERS test/TestClasses.h + include/Framework/StepTHn.h LINKDEF test/FrameworkCoreTestLinkDef.h) foreach(t @@ -144,8 +161,10 @@ foreach(t ConfigurationOptionsRetriever CallbackRegistry ChannelSpecHelpers + CheckTypes CompletionPolicy ComputingResourceHelpers + ComputingQuotaEvaluator ConfigParamStore ConfigParamRegistry DataDescriptorMatcher @@ -160,10 +179,13 @@ foreach(t ExternalFairMQDeviceProxy FairMQOptionsRetriever FairMQResizableBuffer + FairMQ FrameworkDataFlowToDDS + FrameworkDataFlowToO2Control Graphviz GroupSlicer HistogramRegistry + HTTPParser IndexBuilder InfoLogger InputRecord @@ -172,11 +194,13 @@ foreach(t InputSpec Kernels LogParsingHelpers + OverrideLabels PtrHelpers Root2ArrowTable RootConfigParamHelpers Services StringHelpers + StaticFor SuppressionGenerator TMessageSerializer TableBuilder @@ -188,7 +212,7 @@ foreach(t WorkflowSerialization TreeToTable DataOutputDirector - DataInputDirector) + DataInputDirector) # FIXME ? The NAME parameter of o2_add_test is only needed to help the current # o2.sh recipe. If the recipe is changed, those params can go away, if needed. @@ -244,24 +268,17 @@ foreach(b HistogramRegistry TableToTree TreeToTable + ExternalFairMQDeviceProxies ) o2_add_executable(benchmark-${b} SOURCES test/benchmark_${b}.cxx COMPONENT_NAME Framework - IS_BENCHMARK + IS_BENCHMARK PUBLIC_LINK_LIBRARIES O2::Framework benchmark::benchmark) endforeach() # #####################################################@ -if (TARGET AliceO2::DebugGUI) -set (DEBUG_GUI_TESTS_WORKFLOW - CustomGUIGL - CustomGUISokol - SimpleTracksED - ) -endif() - foreach(w BoostSerializedProcessing CallbackService @@ -273,6 +290,7 @@ foreach(w Forwarding ParallelPipeline ParallelProducer + SlowConsumer SimpleDataProcessingDevice01 SimpleRDataFrameProcessing SimpleStatefulProcessing01 @@ -283,7 +301,6 @@ foreach(w SingleDataSource Task ExternalFairMQDeviceWorkflow - ${DEBUG_GUI_TESTS_WORKFLOW} ) o2_add_test(${w} NAME test_Framework_test_${w} SOURCES test/test_${w}.cxx @@ -295,23 +312,15 @@ foreach(w COMMAND_LINE_ARGS ${DPL_WORKFLOW_TESTS_EXTRA_OPTIONS} --run --shm-segment-size 20000000) endforeach() +if (BUILD_TESTING) # TODO: DanglingInput test not working for the moment [ERROR] Unable to relay # part. [WARN] Incoming data is already obsolete, not relaying. set_property(TEST test_Framework_test_DanglingInputs PROPERTY DISABLED TRUE) -if (TARGET AliceO2::DebugGUI) -# TODO: investigate the problem with the two unit tests, maybe setup of the CI -# environment assertion fired X11: The DISPLAY environment variable is missing -# glfw-3.2.1/src/window.c:579: glfwGetFramebufferSize: Assertion `window != -# ((void *)0)' failed. -set_property(TEST test_Framework_test_SimpleTracksED PROPERTY DISABLED TRUE) -set_property(TEST test_Framework_test_CustomGUIGL PROPERTY DISABLED TRUE) -set_property(TEST test_Framework_test_CustomGUISokol PROPERTY DISABLED TRUE) -endif() - # TODO: investigate the problem and re-enable set_property(TEST test_Framework_test_BoostSerializedProcessing PROPERTY DISABLED TRUE) +endif() # specific tests which needs command line options o2_add_test( diff --git a/Framework/Core/COOKBOOK.md b/Framework/Core/COOKBOOK.md index 1cb2ce4870500..240919c9574ad 100644 --- a/Framework/Core/COOKBOOK.md +++ b/Framework/Core/COOKBOOK.md @@ -60,6 +60,13 @@ attach -pid <pid> Note: On some systems, attaching might fail due to missing permission, and `gdb` has to be started with `sudo`. +Once you have attached to the children you are interested in, make sure you send a SIGCONT +to the others by using something along the lines of: + +``` +kill -SIGCONT <all-other-pids> +``` + In case you are building the DPL with the support for the debug GUI, you can also attach a debugger to the running process by clicking on the DataProcessorSpec you want to debug, which will show the Device inspector on @@ -80,6 +87,16 @@ export O2DPLDEBUG='xterm -hold -e sudo gdb attach $O2DEBUGGEDPID &' Be sure to use single quotes to avoid direct expansion of O2DEBUGGEDPID variable. The `&` character add the end is needed to start gdb in a separate process. +### Dumping stacktraces on a signal + +If you are on linux you can get stacktraces on a various signals via the: + +``` +--stacktrace-on-signal "<signal> [<signal>..]" +``` + +option, where `<signal>` can be: all, segv, bus, ill, abrt, fpe and sys. + ### Debug GUI @@ -215,8 +232,6 @@ the the Origin and Description of the `InputSpec` to be: If the timestamp is not specified, DPL will look it up in the `DataProcessingHeader`. -# Future features - ## Lifetime support While initially foreseen in the design, Lifetime for Inputs / Outputs has not @@ -231,10 +246,6 @@ to specify the following Lifetime types: of the Message Passing API to create * QA: an output which once send is also proposed as input to the subsequent computation, allowing for accumulating data (e.g. histograms). -* SubTimeframe: an input which gets processed only once which has a - granularity of less than a timeframe. Within one computation - multiple of these can be created. They get sent as soon as - they go out of scope. ## Wildcard support for InputSpec / OutputSpec @@ -348,18 +359,17 @@ timePipeline(DataProcessorSpec{ ``` which will result in two devices, one for even time periods, the other one for -odd timeperiods. +odd timeperiods. This can also be achieved on the command line via the `--pipeline <processor name>:<N>` option, e.g. `--pipeline processor:2` in this case. +You can get programmatically the number of time pipelined devices you belong and the rank by looking it up in the `DeviceSpec`, e.g.: -### Disabling monitoring - -Sometimes (e.g. when running a child inside valgrind) it might be useful to disable metrics which might pollute STDOUT. In order to disable monitoring you can use the `no-op://` backend: - -```bash -some-workflow --monitoring-backend=no-op:// +```cpp +ctx.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; +ctx.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices; ``` -notice that the GUI will not function properly if you do so. +Where ctx is either the ProcessingContext or the InitContext. + ### Vectorised input @@ -415,3 +425,56 @@ undefined. Thus to read an option without default value do e.g. vopt1 = ic.options().get<std::string>("opt1"); } ``` + +## Monitoring + +By default DPL exposes the following metrics to the back-end specified with: +`--monitoring-backend`: + +* `malformed_inputs`: number of messages which did not match the O2 DataModel +* `dropped_computations`: number of messages which DPL could not process +* `dropped_incoming_messages`: number of messages which DPL could + not accept in its own queue. +* `relayed_messages`: number of messages received by DPL. + +* `errors`: number of errors recorded inside DPL (not in the actual processing). +* `exceptions`: number of exceptions raised by the DPL. +* `inputs/relayed/pending`: number of entries in the DPL queue which are waiting for extra data. +* `inputs/relayed/incomplete` : 1 if the device is waiting for extra data. +* `inputs/relayed/total`: how many inputs the processor has. +* `elapsed_time_ms`: +* `last_processed_input_size_byte`: how many bytes were processed on last iteration by a given device +* `total_processed_input_size_byte`: how many bytes were processed in total since the beginning a given device +* `last_processing_rate_mb_s`: at what rate the last message was processed +* `min_input_latency_ms`: the shortest it took for any message to be processed by this dataprocessor (since created) +* `max_input_latency_ms`: the maximum it took for any message to be processed by this dataprocessor (since created) +* `input_rate_mb_s`: + +Moreover if you specify `--resources-monitoring <poll-interval>` the +process monitoring metrics described at: + +<https://github.com/AliceO2Group/Monitoring/#process-monitoring> + +will be pushed every `<poll-interval>` seconds to the same backend and dumped in the `performanceMetrics.json` file on exit. + +### Disabling monitoring + +Sometimes (e.g. when running a child inside valgrind) it might be useful to disable metrics which might pollute STDOUT. In order to disable monitoring you can use the `no-op://` backend: + +```bash +some-workflow --monitoring-backend=no-op:// +``` + +notice that the GUI will not function properly if you do so. + +## Profiling + +The DPL GUI comes with support to run a profiler on a device for 30s. In order to do so you must click on the device you want to profile, which will show the device inspector for the selected device on the right. Then you can click on "Profile 30s" to start the profiler on the selected dataprocessor. + +By default results are either dumped to a `perf-$O2PROFILEDPID.data` (on linux) or displayed in Instruments (on macOS). In order to visualise the perf file you have to then convert it to a flamegraph via: + +``` +perf script -i perf.data > profile.linux-perf.txt +``` + +and then you can either upload it to https://www.speedscope.app or use chrome://tracing. diff --git a/Framework/Core/PROFILING.md b/Framework/Core/PROFILING.md new file mode 100644 index 0000000000000..c0d510b99c8a6 --- /dev/null +++ b/Framework/Core/PROFILING.md @@ -0,0 +1,39 @@ +# Profiling using perf + +## Setup + +the perf suite is a great profiler suite which is part of the Linux kernel itself. It provides very fine grained view of the state of a running system. By default, however the result you get on Ubuntu or Centos are not particulary good due to security reasons. However if the workstation you are running perf is your own, those defaults can probably be relaxed to provide a better profile expirience. First of all, allow profiling at all: + +```bash +echo -1 > /proc/sys/kernel/perf_event_paranoid +``` + +then allow users to see the addres of kernel functions: + +```bash +echo 0 > /proc/sys/kernel/kptr_restrict +``` + +In order to profile one needs to either run a command prefixing it with: + +``` +perf record -F 999 -g --call-graph dwarf +``` + +or the PID of the running process must be provided via + +``` +-p <PID> +``` + +alternatively you can profile all the processes on a given box using `-a`. + +The above will accumulate results in a file called `perf.data`. Make sure you remove `perf.data` between runs, because they will otherwise accumulate. + +In order to view the results, one must run `perf script`. e.g.: + +``` +perf script -i perf.data --no-inline | c++filt -r -t > profile.linux-perf.txt +``` + +results can then be visualised by drag and dropping them at <https://speedscope.app>. diff --git a/Framework/Core/README.md b/Framework/Core/README.md index 58b5f405fdd27..82b6dd3102e1e 100644 --- a/Framework/Core/README.md +++ b/Framework/Core/README.md @@ -350,7 +350,7 @@ Integration with the InfoLogger subsystem of O2 happens in two way: ```c++ #include <InfoLogger/InfoLogger.hxx> //... -auto logger = context.services().get<InfoLogger>(); // In the DataProcessor lambda +auto& logger = context.services().get<InfoLogger>(); // In the DataProcessor processing lambda ``` * Implicitly, by using the standard FairLogger `LOG` macro. In order to enable this @@ -363,6 +363,13 @@ auto logger = context.services().get<InfoLogger>(); // In the DataProcessor lamb Finally, one can configure the bahavior of the InfoLogger by using the `--infologger-mode` option. +Notice also that you can actually customise the `InfoLoggerContext` which DPL uses to match your needs. This can be done getting it from the InitContext: + +```c++ +auto& context = initContext.services().get<InfoLoggerContext>(); // In the DataProcessor init lambda +context.setField(InfoLoggerContext::FieldName::Facility, "my-custom-facility"); +``` + #### Callback service A service that data processors can register callback functions invoked by the framework at defined steps in the process flow. This allows you to have customisation points for the following event: diff --git a/Framework/Core/include/Framework/AODReaderHelpers.h b/Framework/Core/include/Framework/AODReaderHelpers.h index f428f46bce6f5..4a5802bea2761 100644 --- a/Framework/Core/include/Framework/AODReaderHelpers.h +++ b/Framework/Core/include/Framework/AODReaderHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,53 +20,11 @@ namespace o2::framework::readers { -struct RuntimeWatchdog { - int numberTimeFrames; - uint64_t startTime; - uint64_t lastTime; - double runTime; - uint64_t runTimeLimit; - - RuntimeWatchdog(Long64_t limit) - { - numberTimeFrames = -1; - startTime = uv_hrtime(); - lastTime = startTime; - runTime = 0.; - runTimeLimit = limit; - } - - bool update() - { - numberTimeFrames++; - if (runTimeLimit <= 0) { - return true; - } - - auto nowTime = uv_hrtime(); - - // time spent to process the time frame - double time_spent = numberTimeFrames < 1 ? (double)(nowTime - lastTime) / 1.E9 : 0.; - runTime += time_spent; - lastTime = nowTime; - - return ((double)(lastTime - startTime) / 1.E9 + runTime / (numberTimeFrames + 1)) < runTimeLimit; - } - - void printOut() - { - LOGP(INFO, "RuntimeWatchdog"); - LOGP(INFO, " run time limit: {}", runTimeLimit); - LOGP(INFO, " number of time frames: {}", numberTimeFrames); - LOGP(INFO, " estimated run time per time frame: {}", (numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.); - LOGP(INFO, " estimated total run time: {}", (double)(lastTime - startTime) / 1.E9 + ((numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.)); - } -}; struct AODReaderHelpers { static AlgorithmSpec rootFileReaderCallback(); - static AlgorithmSpec aodSpawnerCallback(std::vector<InputSpec> requested); - static AlgorithmSpec indexBuilderCallback(std::vector<InputSpec> requested); + static AlgorithmSpec aodSpawnerCallback(std::vector<InputSpec>& requested); + static AlgorithmSpec indexBuilderCallback(std::vector<InputSpec>& requested); }; } // namespace o2::framework::readers diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index a31588e003489..afa73eeda2874 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,11 +24,12 @@ #include <arrow/array.h> #include <arrow/util/variant.h> #include <arrow/compute/kernel.h> +#include <arrow/compute/api_aggregate.h> #include <gandiva/selection_vector.h> #include <cassert> #include <fmt/format.h> - -using o2::framework::runtime_error_f; +#include <typeinfo> +#include <gsl/span> namespace o2::soa { @@ -74,6 +76,18 @@ constexpr bool is_type_spawnable_v = false; template <typename T> constexpr bool is_type_spawnable_v<T, std::void_t<decltype(sizeof(typename T::spawnable_t))>> = true; +template <typename T, typename = void> +constexpr bool is_index_table_v = false; + +template <typename T> +constexpr bool is_index_table_v<T, std::void_t<decltype(sizeof(typename T::indexing_t))>> = true; + +template <typename, typename = void> +constexpr bool is_self_index_column_v = false; + +template <typename T> +constexpr bool is_self_index_column_v<T, std::void_t<decltype(sizeof(typename T::self_index_t))>> = true; + template <typename T, typename TLambda> void call_if_has_originals(TLambda&& lambda) { @@ -100,7 +114,7 @@ constexpr auto make_originals_from_type() } else if constexpr (is_type_with_originals_v<typename decayed::table_t>) { return typename decayed::table_t::originals{}; } else if constexpr (is_type_with_parent_v<decayed>) { - return make_originals_from_type(decayed::parent_t); + return make_originals_from_type<typename decayed::parent_t>(); } else { return framework::pack<decayed>{}; } @@ -113,6 +127,12 @@ constexpr auto make_originals_from_type() } } +template <typename... T> +constexpr auto make_originals_from_type(framework::pack<T...>) +{ + return make_originals_from_type<T...>(); +} + /// Policy class for columns which are chunked. This /// will make the compiler take the most generic (and /// slow approach). @@ -126,6 +146,20 @@ struct Flat { constexpr static bool chunked = false; }; +/// unwrapper +template <typename T> +struct unwrap { + using type = T; +}; + +template <typename T> +struct unwrap<std::vector<T>> { + using type = T; +}; + +template <typename T> +using unwrap_t = typename unwrap<T>::type; + /// Iterator on a single column. /// FIXME: the ChunkingPolicy for now is fixed to Flat and is a mere boolean /// which is used to switch off slow "chunking aware" parts. This is ok for @@ -147,7 +181,7 @@ class ColumnIterator : ChunkingPolicy mCurrentChunk{0} { auto array = getCurrentArray(); - mCurrent = reinterpret_cast<T const*>(array->values()->data()) + array->offset(); + mCurrent = reinterpret_cast<unwrap_t<T> const*>(array->values()->data()) + array->offset(); mLast = mCurrent + array->length(); } @@ -166,7 +200,7 @@ class ColumnIterator : ChunkingPolicy mCurrentChunk++; auto array = getCurrentArray(); - mCurrent = reinterpret_cast<T const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); + mCurrent = reinterpret_cast<unwrap_t<T> const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); mLast = mCurrent + array->length() + (mFirstIndex >> SCALE_FACTOR); } @@ -177,7 +211,7 @@ class ColumnIterator : ChunkingPolicy mCurrentChunk--; auto array = getCurrentArray(); - mCurrent = reinterpret_cast<T const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); + mCurrent = reinterpret_cast<unwrap_t<T> const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); mLast = mCurrent + array->length() + (mFirstIndex >> SCALE_FACTOR); } @@ -200,7 +234,7 @@ class ColumnIterator : ChunkingPolicy mCurrentChunk = mColumn->num_chunks() - 1; auto array = getCurrentArray(); mFirstIndex = mColumn->length() - array->length(); - mCurrent = reinterpret_cast<T const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); + mCurrent = reinterpret_cast<unwrap_t<T> const*>(array->values()->data()) + array->offset() - (mFirstIndex >> SCALE_FACTOR); mLast = mCurrent + array->length() + (mFirstIndex >> SCALE_FACTOR); } @@ -216,6 +250,11 @@ class ColumnIterator : ChunkingPolicy // masked char to a bool, because it's undefined behavior. // FIXME: check if shifting the masked bit to the first position is better than != 0 return (*((char*)mCurrent + (*mCurrentPos >> SCALE_FACTOR)) & (1 << (*mCurrentPos & 0x7))) != 0; + } else if constexpr (o2::framework::is_base_of_template<std::vector, T>::value) { + auto list = std::static_pointer_cast<arrow::ListArray>(mColumn->chunk(mCurrentChunk)); + auto offset = list->value_offset(*mCurrentPos - mFirstIndex); + auto length = list->value_length(*mCurrentPos - mFirstIndex); + return gsl::span{mCurrent + offset, mCurrent + offset + length}; } else { return *(mCurrent + (*mCurrentPos >> SCALE_FACTOR)); } @@ -245,9 +284,9 @@ class ColumnIterator : ChunkingPolicy return *this; } - mutable T const* mCurrent; + mutable unwrap_t<T> const* mCurrent; int64_t const* mCurrentPos; - mutable T const* mLast; + mutable unwrap_t<T> const* mLast; arrow::ChunkedArray const* mColumn; mutable int mFirstIndex; mutable int mCurrentChunk; @@ -260,6 +299,9 @@ class ColumnIterator : ChunkingPolicy if constexpr (std::is_same_v<arrow_array_for_t<T>, arrow::FixedSizeListArray>) { chunkToUse = std::dynamic_pointer_cast<arrow::FixedSizeListArray>(chunkToUse)->values(); return std::static_pointer_cast<arrow_array_for_t<value_for_t<T>>>(chunkToUse); + } else if constexpr (std::is_same_v<arrow_array_for_t<T>, arrow::ListArray>) { + chunkToUse = std::dynamic_pointer_cast<arrow::ListArray>(chunkToUse)->values(); + return std::static_pointer_cast<arrow_array_for_t<value_for_t<T>>>(chunkToUse); } else { return std::static_pointer_cast<arrow_array_for_t<T>>(chunkToUse); } @@ -401,6 +443,9 @@ using is_persistent_t = typename std::decay_t<T>::persistent::type; template <typename T> using is_external_index_t = typename std::conditional<is_index_column_v<T>, std::true_type, std::false_type>::type; +template <typename T> +using is_self_index_t = typename std::conditional<is_self_index_column_v<T>, std::true_type, std::false_type>::type; + template <typename T, template <auto...> class Ref> struct is_index : std::false_type { }; @@ -629,6 +674,7 @@ struct RowViewCore : public IP, C... { using index_columns_t = framework::selected_pack<is_index_t, C...>; constexpr inline static bool has_index_v = framework::pack_size(index_columns_t{}) > 0; using external_index_columns_t = framework::selected_pack<is_external_index_t, C...>; + using internal_index_columns_t = framework::selected_pack<is_self_index_t, C...>; RowViewCore(arrow::ChunkedArray* columnData[sizeof...(C)], IP&& policy) : IP{policy}, @@ -691,6 +737,19 @@ struct RowViewCore : public IP, C... { return copy; } + RowViewCore& operator--() + { + this->moveByIndex(-1); + return *this; + } + + RowViewCore operator--(int) + { + RowViewCore<IP, C...> copy = *this; + this->operator--(); + return copy; + } + /// Allow incrementing by more than one the iterator RowViewCore operator+(int64_t inc) const { @@ -723,12 +782,52 @@ struct RowViewCore : public IP, C... { (CL::setCurrent(current), ...); } + template <typename CL> + auto getCurrent() const + { + return CL::getCurrentRaw(); + } + + template <typename... Cs> + auto getIndexBindingsImpl(framework::pack<Cs...>) const + { + return std::vector<void*>{static_cast<Cs const&>(*this).getCurrentRaw()...}; + } + + auto getIndexBindings() const + { + return getIndexBindingsImpl(external_index_columns_t{}); + } + template <typename... TA> void bindExternalIndices(TA*... current) { (doSetCurrentIndex(external_index_columns_t{}, current), ...); } + template <typename... Cs> + void doSetCurrentIndexRaw(framework::pack<Cs...> p, std::vector<void*>&& ptrs) + { + (Cs::setCurrentRaw(ptrs[framework::has_type_at_v<Cs>(p)]), ...); + } + + template <typename... Cs, typename E> + void doSetCurrentInternal(framework::pack<Cs...>, E* ptr) + { + (Cs::setCurrentRaw(ptr), ...); + } + + void bindExternalIndicesRaw(std::vector<void*>&& ptrs) + { + doSetCurrentIndexRaw(external_index_columns_t{}, std::forward<std::vector<void*>>(ptrs)); + } + + template <typename E> + void bindInternalIndices(E* table) + { + doSetCurrentInternal(internal_index_columns_t{}, table); + } + private: /// Helper to move to the correct chunk, if needed. /// FIXME: not needed? @@ -808,6 +907,34 @@ static constexpr auto extractBindings(framework::pack<Is...>) return framework::pack<typename Is::binding_t...>{}; } +template <typename T> +class Filtered; + +template <typename T> +auto select(T const& t, framework::expressions::Filter&& f) +{ + return Filtered<T>({t.asArrowTable()}, framework::expressions::createExpressionTree( + framework::expressions::createOperations(f), + t.asArrowTable()->schema())); +} + +arrow::Status getSliceFor(int value, char const* key, std::shared_ptr<arrow::Table> const& input, std::shared_ptr<arrow::Table>& output, uint64_t& offset); + +template <typename T> +auto sliceBy(T const& t, framework::expressions::BindingNode const& node, int value) +{ + uint64_t offset = 0; + std::shared_ptr<arrow::Table> result = nullptr; + auto status = getSliceFor(value, node.name.c_str(), t.asArrowTable(), result, offset); + if (status.ok()) { + return T({result}, offset); + } + o2::framework::throw_error(o2::framework::runtime_error("Failed to slice table")); + O2_BUILTIN_UNREACHABLE(); +} + +arrow::ChunkedArray* getIndexFromLabel(arrow::Table* table, const char* label); + /// A Table class which observes an arrow::Table and provides /// It is templated on a set of Column / DynamicColumn types. template <typename... C> @@ -818,6 +945,12 @@ class Table using columns = framework::pack<C...>; using column_types = framework::pack<typename C::type...>; using persistent_columns_t = framework::selected_pack<is_persistent_t, C...>; + using external_index_columns_t = framework::selected_pack<is_external_index_t, C...>; + + static constexpr auto hashes() + { + return std::set{typeid(C).hash_code()...}; + } template <typename IP, typename Parent, typename... T> struct RowViewBase : public RowViewCore<IP, C...> { @@ -865,10 +998,11 @@ class Table template <typename TI> auto getId() const { - if constexpr (framework::has_type_v<std::decay_t<TI>, bindings_pack_t>) { - constexpr auto idx = framework::has_type_at_v<std::decay_t<TI>>(bindings_pack_t{}); + using decayed = std::decay_t<TI>; + if constexpr (framework::has_type_v<decayed, bindings_pack_t>) { + constexpr auto idx = framework::has_type_at_v<decayed>(bindings_pack_t{}); return framework::pack_element_t<idx, external_index_columns_t>::getId(); - } else if constexpr (std::is_same_v<std::decay_t<TI>, Parent>) { + } else if constexpr (std::is_same_v<decayed, Parent>) { return this->globalIndex(); } else { return static_cast<int32_t>(-1); @@ -926,6 +1060,7 @@ class Table mColumnChunks[ci] = lookups[ci]; } mBegin = unfiltered_iterator{mColumnChunks, {table->num_rows(), offset}}; + bindInternalIndices(); } } @@ -956,9 +1091,16 @@ class Table return filtered_iterator(mColumnChunks, {selection, mOffset}); } - unfiltered_iterator iteratorAt(uint64_t i) const + iterator iteratorAt(uint64_t i) const + { + return rawIteratorAt(i); + } + + unfiltered_iterator rawIteratorAt(uint64_t i) const { - return mBegin + (i - mOffset); + auto it = mBegin + (i - mOffset); + it.bindInternalIndices((void*)this); + return it; } unfiltered_const_iterator begin() const @@ -1000,17 +1142,69 @@ class Table mBegin.bindExternalIndices(current...); } + void bindInternalIndices() + { + mBegin.bindInternalIndices(this); + } + + template <typename T> + void bindInternalIndicesTo(T* ptr) + { + mBegin.bindInternalIndices(ptr); + } + + void bindExternalIndicesRaw(std::vector<void*>&& ptrs) + { + mBegin.bindExternalIndicesRaw(std::forward<std::vector<void*>>(ptrs)); + } + + template <typename T, typename... Cs> + void doCopyIndexBindings(framework::pack<Cs...>, T& dest) const + { + dest.bindExternalIndicesRaw(mBegin.getIndexBindings()); + } + + template <typename T> + void copyIndexBindings(T& dest) const + { + doCopyIndexBindings(external_index_columns_t{}, dest); + } + + auto select(framework::expressions::Filter&& f) const + { + auto t = o2::soa::select(*this, std::forward<framework::expressions::Filter>(f)); + copyIndexBindings(t); + return t; + } + + auto sliceBy(framework::expressions::BindingNode const& node, int value) const + { + auto t = o2::soa::sliceBy(*this, node, value); + copyIndexBindings(t); + return t; + } + + auto slice(uint64_t start, uint64_t end) + { + return rawSlice(start, end); + } + + auto rawSlice(uint64_t start, uint64_t end) + { + return table_t{mTable->Slice(start, end - start + 1), start}; + } + + protected: + /// Offset of the table within a larger table. + uint64_t mOffset; + private: template <typename T> arrow::ChunkedArray* lookupColumn() { if constexpr (T::persistent::value) { auto label = T::columnLabel(); - auto index = mTable->schema()->GetFieldIndex(label); - if (index == -1) { - throw runtime_error_f("Unable to find column with label %s", label); - } - return mTable->column(index).get(); + return getIndexFromLabel(mTable.get(), label); } else { return nullptr; } @@ -1022,8 +1216,6 @@ class Table unfiltered_iterator mBegin; /// Cached end iterator for this table. RowViewSentinel mEnd; - /// Offset of the table within a larger table. - uint64_t mOffset; }; template <typename T> @@ -1054,12 +1246,23 @@ class TableMetadata static std::string sourceSpec() { return fmt::format("{}/{}/{}", INHERIT::mLabel, INHERIT::mOrigin, INHERIT::mDescription); }; }; +/// Helper template to define universal join +template <typename Key, typename H, typename... Ts> +struct IndexTable; + template <typename... C1, typename... C2> constexpr auto joinTables(o2::soa::Table<C1...> const& t1, o2::soa::Table<C2...> const& t2) { return o2::soa::Table<C1..., C2...>(ArrowHelpers::joinTables({t1.asArrowTable(), t2.asArrowTable()})); } +// special case for appending an index +template <typename... C1, typename Key, typename H, typename... C2> +constexpr auto joinTables(o2::soa::Table<C1...> const& t1, o2::soa::IndexTable<Key, H, C2...> const& t2) +{ + return joinTables(t1, o2::soa::Table<H, C2...>{t2.asArrowTable()}); +} + template <typename T, typename... C, typename... O> constexpr auto joinLeft(T const& t1, o2::soa::Table<C...> const& t2, framework::pack<O...>) { @@ -1130,27 +1333,28 @@ constexpr auto is_binding_compatible_v() using metadata = std::void_t<T>; \ } -#define DECLARE_SOA_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_) \ - struct _Name_ : o2::soa::Column<_Type_, _Name_> { \ - static constexpr const char* mLabel = _Label_; \ - using base = o2::soa::Column<_Type_, _Name_>; \ - using type = _Type_; \ - using column_t = _Name_; \ - _Name_(arrow::ChunkedArray const* column) \ - : o2::soa::Column<_Type_, _Name_>(o2::soa::ColumnIterator<type>(column)) \ - { \ - } \ - \ - _Name_() = default; \ - _Name_(_Name_ const& other) = default; \ - _Name_& operator=(_Name_ const& other) = default; \ - \ - decltype(auto) _Getter_() const \ - { \ - return *mColumnIterator; \ - } \ - }; \ - static const o2::framework::expressions::BindingNode _Getter_ { _Label_, \ +#define DECLARE_SOA_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_) \ + struct _Name_ : o2::soa::Column<_Type_, _Name_> { \ + static constexpr const char* mLabel = _Label_; \ + static_assert(!((*(mLabel + 1) == 'I' && *(mLabel + 2) == 'n' && *(mLabel + 3) == 'd' && *(mLabel + 4) == 'e' && *(mLabel + 5) == 'x')), "Index is not a valid column name"); \ + using base = o2::soa::Column<_Type_, _Name_>; \ + using type = _Type_; \ + using column_t = _Name_; \ + _Name_(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_, _Name_>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_() = default; \ + _Name_(_Name_ const& other) = default; \ + _Name_& operator=(_Name_ const& other) = default; \ + \ + decltype(auto) _Getter_() const \ + { \ + return *mColumnIterator; \ + } \ + }; \ + static const o2::framework::expressions::BindingNode _Getter_ { _Label_, typeid(_Name_).hash_code(), \ o2::framework::expressions::selectArrowType<_Type_>() } #define DECLARE_SOA_COLUMN(_Name_, _Getter_, _Type_) \ @@ -1158,32 +1362,32 @@ constexpr auto is_binding_compatible_v() /// An 'expression' column. i.e. a column that can be calculated from other /// columns with gandiva based on supplied C++ expression. -#define DECLARE_SOA_EXPRESSION_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_, _Expression_) \ - struct _Name_ : o2::soa::Column<_Type_, _Name_> { \ - static constexpr const char* mLabel = _Label_; \ - using base = o2::soa::Column<_Type_, _Name_>; \ - using type = _Type_; \ - using column_t = _Name_; \ - using spawnable_t = std::true_type; \ - _Name_(arrow::ChunkedArray const* column) \ - : o2::soa::Column<_Type_, _Name_>(o2::soa::ColumnIterator<type>(column)) \ - { \ - } \ - \ - _Name_() = default; \ - _Name_(_Name_ const& other) = default; \ - _Name_& operator=(_Name_ const& other) = default; \ - \ - decltype(auto) _Getter_() const \ - { \ - return *mColumnIterator; \ - } \ - static o2::framework::expressions::Projector Projector() \ - { \ - return _Expression_; \ - } \ - }; \ - static const o2::framework::expressions::BindingNode _Getter_ { _Label_, \ +#define DECLARE_SOA_EXPRESSION_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_, _Expression_) \ + struct _Name_ : o2::soa::Column<_Type_, _Name_> { \ + static constexpr const char* mLabel = _Label_; \ + using base = o2::soa::Column<_Type_, _Name_>; \ + using type = _Type_; \ + using column_t = _Name_; \ + using spawnable_t = std::true_type; \ + _Name_(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_, _Name_>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_() = default; \ + _Name_(_Name_ const& other) = default; \ + _Name_& operator=(_Name_ const& other) = default; \ + \ + decltype(auto) _Getter_() const \ + { \ + return *mColumnIterator; \ + } \ + static o2::framework::expressions::Projector Projector() \ + { \ + return _Expression_; \ + } \ + }; \ + static const o2::framework::expressions::BindingNode _Getter_ { _Label_, typeid(_Name_).hash_code(), \ o2::framework::expressions::selectArrowType<_Type_>() } #define DECLARE_SOA_EXPRESSION_COLUMN(_Name_, _Getter_, _Type_, _Expression_) \ @@ -1191,7 +1395,9 @@ constexpr auto is_binding_compatible_v() /// An index column is a column of indices to elements / of another table named /// _Name_##s. The column name will be _Name_##Id and will always be stored in -/// "f"#_Name__#Id . It will also have two special methods, setCurrent(...) +/// "fIndex"#_Table_#[_Suffix_]. If _Suffix_ is not empty it has to begin +/// with _ (underscore) to make the columns identifiable for the table merging +/// It will also have two special methods, setCurrent(...) /// and getCurrent(...) which allow you to set / retrieve associated table. /// It also exposes a getter _Getter_ which allows you to retrieve the pointed /// object. @@ -1201,66 +1407,284 @@ constexpr auto is_binding_compatible_v() /// needs to go from parent to child, the only way is to either have /// a separate "association" with the two indices, or to use the standard /// grouping mechanism of AnalysisTask. -#define DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Table_, _Label_) \ - struct _Name_##Id : o2::soa::Column<_Type_, _Name_##Id> { \ - static_assert(std::is_integral_v<_Type_>, "Index type must be integral"); \ - static constexpr const char* mLabel = _Label_; \ - using base = o2::soa::Column<_Type_, _Name_##Id>; \ - using type = _Type_; \ - using column_t = _Name_##Id; \ - using binding_t = _Table_; \ - _Name_##Id(arrow::ChunkedArray const* column) \ - : o2::soa::Column<_Type_, _Name_##Id>(o2::soa::ColumnIterator<type>(column)) \ - { \ - } \ - \ - _Name_##Id() = default; \ - _Name_##Id(_Name_##Id const& other) = default; \ - _Name_##Id& operator=(_Name_##Id const& other) = default; \ - type inline getId() const \ - { \ - return _Getter_##Id(); \ - } \ - \ - type _Getter_##Id() const \ - { \ - return *mColumnIterator; \ - } \ - \ - bool has_##_Getter_() const \ - { \ - return *mColumnIterator >= 0; \ - } \ - \ - template <typename T> \ - auto _Getter_##_as() const \ - { \ - assert(mBinding != nullptr); \ - return static_cast<T*>(mBinding)->begin() + *mColumnIterator; \ - } \ - \ - auto _Getter_() const \ - { \ - return _Getter_##_as<binding_t>(); \ - } \ - \ - template <typename T> \ - bool setCurrent(T* current) \ - { \ - if constexpr (o2::soa::is_binding_compatible_v<T, binding_t>()) { \ - assert(current != nullptr); \ - this->mBinding = current; \ - return true; \ - } \ - return false; \ - } \ - binding_t* getCurrent() { return static_cast<binding_t*>(mBinding); } \ - void* mBinding = nullptr; \ - }; \ - static const o2::framework::expressions::BindingNode _Getter_##Id { _Label_, \ +/// +/// Normal index: returns iterator to a bound table +/// Slice index: return an instance of the bound table type with a slice defined by the values in 0 and 1st elements +/// Array index: return an array of iterators, defined by values in its elements + +/// SLICE +#define DECLARE_SOA_SLICE_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Table_, _Suffix_) \ + struct _Name_##IdSlice : o2::soa::Column<_Type_[2], _Name_##IdSlice> { \ + static_assert(std::is_integral_v<_Type_>, "Index type must be integral"); \ + static_assert((*_Suffix_ == '\0') || (*_Suffix_ == '_'), "Suffix has to begin with _"); \ + static constexpr const char* mLabel = "fIndexSlice" #_Table_ _Suffix_; \ + using base = o2::soa::Column<_Type_[2], _Name_##IdSlice>; \ + using type = _Type_[2]; \ + using column_t = _Name_##IdSlice; \ + using binding_t = _Table_; \ + _Name_##IdSlice(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_[2], _Name_##IdSlice>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_##IdSlice() = default; \ + _Name_##IdSlice(_Name_##IdSlice const& other) = default; \ + _Name_##IdSlice& operator=(_Name_##IdSlice const& other) = default; \ + std::array<_Type_, 2> inline getIds() const \ + { \ + return _Getter_##Ids(); \ + } \ + \ + std::array<_Type_, 2> _Getter_##Ids() const \ + { \ + return std::array{(*mColumnIterator)[0], (*mColumnIterator)[1]}; \ + } \ + \ + bool has_##_Getter_() const \ + { \ + return (*mColumnIterator)[0] >= 0; \ + } \ + \ + template <typename T> \ + auto _Getter_##_as() const \ + { \ + assert(mBinding != nullptr); \ + auto t = static_cast<T*>(mBinding)->rawSlice((*mColumnIterator)[0], (*mColumnIterator)[1]); \ + static_cast<T*>(mBinding)->copyIndexBindings(t); \ + return t; \ + } \ + \ + auto _Getter_() const \ + { \ + return _Getter_##_as<binding_t>(); \ + } \ + \ + template <typename T> \ + bool setCurrent(T* current) \ + { \ + if constexpr (o2::soa::is_binding_compatible_v<T, binding_t>()) { \ + assert(current != nullptr); \ + this->mBinding = current; \ + return true; \ + } \ + return false; \ + } \ + \ + bool setCurrentRaw(void* current) \ + { \ + this->mBinding = current; \ + return true; \ + } \ + binding_t* getCurrent() const { return static_cast<binding_t*>(mBinding); } \ + void* getCurrentRaw() const { return mBinding; } \ + void* mBinding = nullptr; \ + }; + +#define DECLARE_SOA_SLICE_INDEX_COLUMN(_Name_, _Getter_) DECLARE_SOA_SLICE_INDEX_COLUMN_FULL(_Name_, _Getter_, int32_t, _Name_##s, "") + +///ARRAY +#define DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _N_, _Table_, _Suffix_) \ + struct _Name_##Ids : o2::soa::Column<_Type_[_N_], _Name_##Ids> { \ + static_assert(std::is_integral_v<_Type_>, "Index type must be integral"); \ + static_assert((*_Suffix_ == '\0') || (*_Suffix_ == '_'), "Suffix has to begin with _"); \ + static constexpr const char* mLabel = "fIndexArray" #_Table_ _Suffix_; \ + using base = o2::soa::Column<_Type_[_N_], _Name_##Ids>; \ + using type = _Type_[_N_]; \ + using column_t = _Name_##Ids; \ + using binding_t = _Table_; \ + _Name_##Ids(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_[_N_], _Name_##Ids>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_##Ids() = default; \ + _Name_##Ids(_Name_##Ids const& other) = default; \ + _Name_##Ids& operator=(_Name_##Ids const& other) = default; \ + \ + std::array<_Type_, _N_> inline getIds() const \ + { \ + return _Getter_##Ids(); \ + } \ + \ + std::array<_Type_, _N_> _Getter_##Ids() const \ + { \ + return getIds(std::make_index_sequence<_N_>{}); \ + } \ + \ + template <size_t... N> \ + std::array<_Type_, _N_> getIds(std::index_sequence<N...>) const \ + { \ + return std::array<_Type_, _N_>{(*mColumnIterator)[N]...}; \ + } \ + \ + template <int N> \ + bool has_##_Getter_() const \ + { \ + static_assert(N < _N_, "Out-of-bounds"); \ + return (*mColumnIterator)[N] >= 0; \ + } \ + \ + template <typename T> \ + auto _Getter_##_as() const \ + { \ + assert(mBinding != nullptr); \ + return getIterators<T>(std::make_index_sequence<_N_>{}); \ + } \ + template <typename T, size_t... N> \ + auto getIterators(std::index_sequence<N...>) const \ + { \ + return std::array{(static_cast<T*>(mBinding)->rawIteratorAt((*mColumnIterator)[N]))...}; \ + } \ + \ + auto _Getter_() const \ + { \ + return _Getter_##_as<binding_t>(); \ + } \ + \ + template <typename T> \ + bool setCurrent(T* current) \ + { \ + if constexpr (o2::soa::is_binding_compatible_v<T, binding_t>()) { \ + assert(current != nullptr); \ + this->mBinding = current; \ + return true; \ + } \ + return false; \ + } \ + \ + bool setCurrentRaw(void* current) \ + { \ + this->mBinding = current; \ + return true; \ + } \ + binding_t* getCurrent() const { return static_cast<binding_t*>(mBinding); } \ + void* getCurrentRaw() const { return mBinding; } \ + void* mBinding = nullptr; \ + }; + +#define DECLARE_SOA_ARRAY_INDEX_COLUMN(_Name_, _Getter_, _Size_) DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL(_Name_, _Getter_, int32_t, _Size_, _Name_##s, "") + +///NORMAL +#define DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Table_, _Suffix_) \ + struct _Name_##Id : o2::soa::Column<_Type_, _Name_##Id> { \ + static_assert(std::is_integral_v<_Type_>, "Index type must be integral"); \ + static_assert((*_Suffix_ == '\0') || (*_Suffix_ == '_'), "Suffix has to begin with _"); \ + static constexpr const char* mLabel = "fIndex" #_Table_ _Suffix_; \ + using base = o2::soa::Column<_Type_, _Name_##Id>; \ + using type = _Type_; \ + using column_t = _Name_##Id; \ + using binding_t = _Table_; \ + _Name_##Id(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_, _Name_##Id>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_##Id() = default; \ + _Name_##Id(_Name_##Id const& other) = default; \ + _Name_##Id& operator=(_Name_##Id const& other) = default; \ + type inline getId() const \ + { \ + return _Getter_##Id(); \ + } \ + \ + type _Getter_##Id() const \ + { \ + return *mColumnIterator; \ + } \ + \ + bool has_##_Getter_() const \ + { \ + return *mColumnIterator >= 0; \ + } \ + \ + template <typename T> \ + auto _Getter_##_as() const \ + { \ + assert(mBinding != nullptr); \ + return static_cast<T*>(mBinding)->rawIteratorAt(*mColumnIterator); \ + } \ + \ + auto _Getter_() const \ + { \ + return _Getter_##_as<binding_t>(); \ + } \ + \ + template <typename T> \ + bool setCurrent(T* current) \ + { \ + if constexpr (o2::soa::is_binding_compatible_v<T, binding_t>()) { \ + assert(current != nullptr); \ + this->mBinding = current; \ + return true; \ + } \ + return false; \ + } \ + \ + bool setCurrentRaw(void* current) \ + { \ + this->mBinding = current; \ + return true; \ + } \ + binding_t* getCurrent() const { return static_cast<binding_t*>(mBinding); } \ + void* getCurrentRaw() const { return mBinding; } \ + void* mBinding = nullptr; \ + }; \ + static const o2::framework::expressions::BindingNode _Getter_##Id { "fIndex" #_Table_ _Suffix_, typeid(_Name_##Id).hash_code(), \ + o2::framework::expressions::selectArrowType<_Type_>() } + +#define DECLARE_SOA_INDEX_COLUMN(_Name_, _Getter_) DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, int32_t, _Name_##s, "") + +///SELF +#define DECLARE_SOA_SELF_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_) \ + struct _Name_##Id : o2::soa::Column<_Type_, _Name_##Id> { \ + static_assert(std::is_integral_v<_Type_>, "Index type must be integral"); \ + static constexpr const char* mLabel = "fIndex" _Label_; \ + using base = o2::soa::Column<_Type_, _Name_##Id>; \ + using type = _Type_; \ + using column_t = _Name_##Id; \ + using self_index_t = std::true_type; \ + _Name_##Id(arrow::ChunkedArray const* column) \ + : o2::soa::Column<_Type_, _Name_##Id>(o2::soa::ColumnIterator<type>(column)) \ + { \ + } \ + \ + _Name_##Id() = default; \ + _Name_##Id(_Name_##Id const& other) = default; \ + _Name_##Id& operator=(_Name_##Id const& other) = default; \ + type inline getId() const \ + { \ + return _Getter_##Id(); \ + } \ + \ + type _Getter_##Id() const \ + { \ + return *mColumnIterator; \ + } \ + \ + bool has_##_Getter_() const \ + { \ + return *mColumnIterator >= 0; \ + } \ + \ + template <typename T> \ + auto _Getter_##_as() const \ + { \ + assert(mBinding != nullptr); \ + return static_cast<T*>(mBinding)->rawIteratorAt(*mColumnIterator); \ + } \ + \ + bool setCurrentRaw(void* current) \ + { \ + this->mBinding = current; \ + return true; \ + } \ + void* getCurrentRaw() const { return mBinding; } \ + void* mBinding = nullptr; \ + }; \ + static const o2::framework::expressions::BindingNode _Getter_##Id { "fIndex" _Label_, typeid(_Name_##Id).hash_code(), \ o2::framework::expressions::selectArrowType<_Type_>() } -#define DECLARE_SOA_INDEX_COLUMN(_Name_, _Getter_) DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, int32_t, _Name_##s, "f" #_Name_ "sID") +#define DECLARE_SOA_SELF_INDEX_COLUMN(_Name_, _Getter_) DECLARE_SOA_SELF_INDEX_COLUMN_FULL(_Name_, _Getter_, int32_t, #_Name_) /// A dynamic column is a column whose values are derived /// from those of other real columns. These can be used for /// example to provide different coordinate systems (e.g. polar, @@ -1354,23 +1778,31 @@ constexpr auto is_binding_compatible_v() #define DECLARE_SOA_TABLE(_Name_, _Origin_, _Description_, ...) \ DECLARE_SOA_TABLE_FULL(_Name_, #_Name_, _Origin_, _Description_, __VA_ARGS__); -#define DECLARE_SOA_EXTENDED_TABLE_FULL(_Name_, _Table_, _Origin_, _Description_, ...) \ - using _Name_##Extension = o2::soa::Table<__VA_ARGS__>; \ - using _Name_ = o2::soa::Join<_Name_##Extension, _Table_>; \ - \ - struct _Name_##ExtensionMetadata : o2::soa::TableMetadata<_Name_##ExtensionMetadata> { \ - using table_t = _Name_##Extension; \ - using base_table_t = typename _Table_::table_t; \ - using expression_pack_t = framework::pack<__VA_ARGS__>; \ - using originals = soa::originals_pack_t<_Table_>; \ - static constexpr char const* mLabel = #_Name_ "Extension"; \ - static constexpr char const mOrigin[4] = _Origin_; \ - static constexpr char const mDescription[16] = _Description_; \ - }; \ - \ - template <> \ - struct MetadataTrait<_Name_##Extension> { \ - using metadata = _Name_##ExtensionMetadata; \ +#define DECLARE_SOA_EXTENDED_TABLE_FULL(_Name_, _Table_, _Origin_, _Description_, ...) \ + struct _Name_##Extension : o2::soa::Table<__VA_ARGS__> { \ + using base_t = o2::soa::Table<__VA_ARGS__>; \ + _Name_##Extension(std::shared_ptr<arrow::Table> table, uint64_t offset = 0) : o2::soa::Table<__VA_ARGS__>(table, offset){}; \ + _Name_##Extension(_Name_##Extension const&) = default; \ + _Name_##Extension(_Name_##Extension&&) = default; \ + using iterator = typename base_t::template RowView<_Name_##Extension, _Name_##Extension>; \ + using const_iterator = iterator; \ + }; \ + using _Name_ = o2::soa::Join<_Name_##Extension, _Table_>; \ + \ + struct _Name_##ExtensionMetadata : o2::soa::TableMetadata<_Name_##ExtensionMetadata> { \ + using table_t = _Name_##Extension; \ + using base_table_t = typename _Table_::table_t; \ + using expression_pack_t = framework::pack<__VA_ARGS__>; \ + using originals = soa::originals_pack_t<_Table_>; \ + using sources = originals; \ + static constexpr char const* mLabel = #_Name_ "Extension"; \ + static constexpr char const mOrigin[4] = _Origin_; \ + static constexpr char const mDescription[16] = _Description_; \ + }; \ + \ + template <> \ + struct MetadataTrait<_Name_##Extension> { \ + using metadata = _Name_##ExtensionMetadata; \ }; #define DECLARE_SOA_EXTENDED_TABLE(_Name_, _Table_, _Description_, ...) \ @@ -1392,6 +1824,7 @@ constexpr auto is_binding_compatible_v() using Key = _Key_; \ using index_pack_t = framework::pack<__VA_ARGS__>; \ using originals = decltype(soa::extractBindings(index_pack_t{})); \ + using sources = typename _Name_::sources_t; \ static constexpr char const* mLabel = #_Name_; \ static constexpr char const mOrigin[4] = _Origin_; \ static constexpr char const mDescription[16] = _Description_; \ @@ -1424,23 +1857,16 @@ namespace o2::soa { template <typename... Ts> struct Join : JoinBase<Ts...> { - Join(std::vector<std::shared_ptr<arrow::Table>>&& tables, uint64_t offset = 0) - : JoinBase<Ts...>{ArrowHelpers::joinTables(std::move(tables)), offset} {} + Join(std::vector<std::shared_ptr<arrow::Table>>&& tables, uint64_t offset = 0); template <typename... ATs> - Join(uint64_t offset, std::shared_ptr<arrow::Table> t1, std::shared_ptr<arrow::Table> t2, ATs... ts) - : Join<Ts...>(std::vector<std::shared_ptr<arrow::Table>>{t1, t2, ts...}, offset) - { - } + Join(uint64_t offset, std::shared_ptr<arrow::Table> t1, std::shared_ptr<arrow::Table> t2, ATs... ts); using base = JoinBase<Ts...>; using originals = originals_pack_t<Ts...>; template <typename... TA> - void bindExternalIndices(TA*... externals) - { - base::bindExternalIndices(externals...); - } + void bindExternalIndices(TA*... externals); using table_t = base; using persistent_columns_t = typename table_t::persistent_columns_t; @@ -1450,6 +1876,26 @@ struct Join : JoinBase<Ts...> { using filtered_const_iterator = filtered_iterator; }; +template <typename... Ts> +Join<Ts...>::Join(std::vector<std::shared_ptr<arrow::Table>>&& tables, uint64_t offset) + : JoinBase<Ts...>{ArrowHelpers::joinTables(std::move(tables)), offset} +{ +} + +template <typename... Ts> +template <typename... ATs> +Join<Ts...>::Join(uint64_t offset, std::shared_ptr<arrow::Table> t1, std::shared_ptr<arrow::Table> t2, ATs... ts) + : Join<Ts...>(std::vector<std::shared_ptr<arrow::Table>>{t1, t2, ts...}, offset) +{ +} + +template <typename... Ts> +template <typename... TA> +void Join<Ts...>::bindExternalIndices(TA*... externals) +{ + base::bindExternalIndices(externals...); +} + template <typename T1, typename T2> struct Concat : ConcatBase<T1, T2> { Concat(std::shared_ptr<arrow::Table> t1, std::shared_ptr<arrow::Table> t2, uint64_t offset = 0) @@ -1486,9 +1932,11 @@ template <typename T> class FilteredPolicy : public T { public: + using self_t = FilteredPolicy<T>; using originals = originals_pack_t<T>; using table_t = typename T::table_t; using persistent_columns_t = typename T::persistent_columns_t; + using external_index_columns_t = typename T::external_index_columns_t; template <typename P, typename... Os> constexpr static auto make_it(framework::pack<Os...> const&) @@ -1579,6 +2027,35 @@ class FilteredPolicy : public T mFilteredBegin.bindExternalIndices(current...); } + void bindExternalIndicesRaw(std::vector<void*>&& ptrs) + { + mFilteredBegin.bindExternalIndicesRaw(std::forward<std::vector<void*>>(ptrs)); + } + + template <typename T1, typename... Cs> + void doCopyIndexBindings(framework::pack<Cs...>, T1& dest) const + { + dest.bindExternalIndicesRaw(mFilteredBegin.getIndexBindings()); + } + + template <typename T1> + void copyIndexBindings(T1& dest) const + { + doCopyIndexBindings(external_index_columns_t{}, dest); + } + + auto slice(uint64_t start, uint64_t end) + { + auto start_iterator = std::lower_bound(mSelectedRows.begin(), mSelectedRows.end(), start); + auto stop_iterator = std::lower_bound(start_iterator, mSelectedRows.end(), end); + SelectionVector slicedSelection{start_iterator, stop_iterator}; + std::transform(slicedSelection.begin(), slicedSelection.end(), slicedSelection.begin(), + [&](int64_t idx) { + return idx - static_cast<int64_t>(start); + }); + return self_t{{this->asArrowTable()->Slice(start, end - start + 1)}, std::move(slicedSelection), start}; + } + protected: void sumWithSelection(SelectionVector const& selection) { @@ -1762,12 +2239,6 @@ class Filtered<Filtered<T>> : public FilteredPolicy<typename T::table_t> template <typename T> using is_soa_filtered_t = typename framework::is_base_of_template<soa::FilteredPolicy, T>; -template <typename T> -auto filter(T&& t, framework::expressions::Filter const& expr) -{ - return Filtered<T>(t.asArrowTable(), expr); -} - /// Template for building an index table to access matching rows from non- /// joinable, but compatible tables, e.g. Collisions and ZDCs. /// First argument is the key table (BCs for the Collisions+ZDCs case), the rest @@ -1776,10 +2247,12 @@ auto filter(T&& t, framework::expressions::Filter const& expr) template <typename Key, typename H, typename... Ts> struct IndexTable : Table<soa::Index<>, H, Ts...> { using base_t = Table<soa::Index<>, H, Ts...>; + using table_t = base_t; + using safe_base_t = Table<H, Ts...>; using indexing_t = Key; using first_t = typename H::binding_t; using rest_t = framework::pack<typename Ts::binding_t...>; - using sources_t = framework::pack<Key, typename H::binding_t, typename Ts::binding_t...>; + using sources_t = originals_pack_t<Key, first_t, typename Ts::binding_t...>; IndexTable(std::shared_ptr<arrow::Table> table, uint64_t offset = 0) : base_t{table, offset} diff --git a/Framework/Core/include/Framework/ASoAHelpers.h b/Framework/Core/include/Framework/ASoAHelpers.h index f82b58da8242f..495cd591874ff 100644 --- a/Framework/Core/include/Framework/ASoAHelpers.h +++ b/Framework/Core/include/Framework/ASoAHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -363,11 +364,11 @@ struct CombinationsBlockUpperIndexPolicy : public CombinationsBlockIndexPolicyBa constexpr auto curInd = k - i.value - 1; std::get<curInd>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices); - std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].second); uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + this->mSlidingWindowSize; // If we remain within the same sliding window if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) { + std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].second); modify = false; for_<i.value>([&, this](auto j) { constexpr auto curJ = k - i.value + j.value; @@ -388,10 +389,10 @@ struct CombinationsBlockUpperIndexPolicy : public CombinationsBlockIndexPolicyBa std::get<0>(this->mCurrentIndices)++; std::get<0>(this->mBeginIndices)++; uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); - std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].second); // If we remain within the same category - slide window if (curGroupedInd < std::get<0>(this->mMaxOffset)) { + std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].second); modify = false; for_<k - 1>([&, this](auto j) { constexpr auto curJ = j.value + 1; @@ -458,12 +459,12 @@ struct CombinationsBlockFullIndexPolicy : public CombinationsBlockIndexPolicyBas constexpr auto curInd = k - i.value - 1; std::get<curInd>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices); - std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].second); uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize; uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + windowOffset; // If we remain within the same sliding window and fixed index if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) { + std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].second); for_<i.value>([&, this](auto j) { constexpr auto curJ = k - i.value + j.value; if (curJ < this->mCurrentlyFixed) { // To assure no repetitions @@ -498,11 +499,11 @@ struct CombinationsBlockFullIndexPolicy : public CombinationsBlockIndexPolicyBas this->mCurrentlyFixed = 0; std::get<0>(this->mBeginIndices)++; std::get<0>(this->mCurrentIndices) = std::get<0>(this->mBeginIndices); - uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); - std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].second); // If we remain within the same category - slide window if (std::get<0>(this->mBeginIndices) < std::get<0>(this->mMaxOffset)) { + uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); + std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].second); modify = false; for_<k - 1>([&, this](auto j) { constexpr auto curJ = j.value + 1; @@ -601,11 +602,11 @@ struct CombinationsBlockUpperSameIndexPolicy : public CombinationsBlockSameIndex constexpr auto curInd = k - i.value - 1; std::get<curInd>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices); - std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize; // If we remain within the same sliding window if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) { + std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<i.value>([&, this](auto j) { constexpr auto curJ = k - i.value + j.value; std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices); @@ -621,10 +622,10 @@ struct CombinationsBlockUpperSameIndexPolicy : public CombinationsBlockSameIndex if (modify) { std::get<0>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); - std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); // If we remain within the same category - slide window if (curGroupedInd < std::get<0>(this->mMaxOffset)) { + std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<k - 1>([&, this](auto j) { constexpr auto curJ = j.value + 1; std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices); @@ -679,11 +680,11 @@ struct CombinationsBlockStrictlyUpperSameIndexPolicy : public CombinationsBlockS constexpr auto curInd = k - i.value - 1; std::get<curInd>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices); - std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize - i.value; // If we remain within the same sliding window if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) { + std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<i.value>([&, this](auto j) { constexpr auto curJ = k - i.value + j.value; std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1; @@ -699,10 +700,10 @@ struct CombinationsBlockStrictlyUpperSameIndexPolicy : public CombinationsBlockS if (modify) { std::get<0>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); - std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); // If we remain within the same category - slide window if (curGroupedInd < std::get<0>(this->mMaxOffset)) { + std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<k - 1>([&, this](auto j) { constexpr auto curJ = j.value + 1; std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1; @@ -761,12 +762,12 @@ struct CombinationsBlockFullSameIndexPolicy : public CombinationsBlockSameIndexP constexpr auto curInd = k - i.value - 1; std::get<curInd>(this->mCurrentIndices)++; uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices); - std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize; uint64_t maxForWindow = this->mBeginIndex + windowOffset; // If we remain within the same sliding window and fixed index if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) { + std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<i.value>([&, this](auto j) { constexpr auto curJ = k - i.value + j.value; if (curJ < this->mCurrentlyFixed) { // To assure no repetitions @@ -801,11 +802,11 @@ struct CombinationsBlockFullSameIndexPolicy : public CombinationsBlockSameIndexP this->mCurrentlyFixed = 0; this->mBeginIndex++; std::get<0>(this->mCurrentIndices) = this->mBeginIndex; - uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); - std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); // If we remain within the same category - slide window if (this->mBeginIndex < std::get<0>(this->mMaxOffset)) { + uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices); + std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].second); for_<k - 1>([&, this](auto j) { constexpr auto curJ = j.value + 1; std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex; diff --git a/Framework/Core/include/Framework/AlgorithmSpec.h b/Framework/Core/include/Framework/AlgorithmSpec.h index 49dd495ba0178..d50168cd066c7 100644 --- a/Framework/Core/include/Framework/AlgorithmSpec.h +++ b/Framework/Core/include/Framework/AlgorithmSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,9 +19,7 @@ #include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { /// This is the class holding the actual algorithm to be used. Notice that the @@ -88,6 +87,11 @@ struct AlgorithmSpec { ErrorCallback onError = nullptr; }; +/// Helper class for an algorithm which is loaded as a plugin. +struct AlgorithmPlugin { + virtual AlgorithmSpec create() = 0; +}; + template <typename T> struct ContextElementTraits { static decltype(auto) get(ProcessingContext& ctx) @@ -180,7 +184,6 @@ AlgorithmSpec::InitCallback adaptStateful(LAMBDA l) return adaptStatefulF(FFL(l)); } -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // FRAMEWORK_ALGORITHMSPEC_H diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index 6c8d89a7985c2..7b9d6bd28594f 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,188 +26,251 @@ DECLARE_SOA_STORE(); namespace bc { -DECLARE_SOA_COLUMN(RunNumber, runNumber, int); -DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); -DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint64_t); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); //! Run number +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); //! Bunch crossing number (globally unique in this run) +DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint64_t); //! CTP trigger mask } // namespace bc -DECLARE_SOA_TABLE(BCs, "AOD", "BC", o2::soa::Index<>, +DECLARE_SOA_TABLE(BCs, "AOD", "BC", o2::soa::Index<>, //! Root of data model for tables pointing to a bunch crossing bc::RunNumber, bc::GlobalBC, bc::TriggerMask); using BC = BCs::iterator; namespace timestamp { -DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); //! Timestamp of a BC in ms (epoch style) } // namespace timestamp -DECLARE_SOA_TABLE(Timestamps, "AOD", "TIMESTAMPS", timestamp::Timestamp); - +DECLARE_SOA_TABLE(Timestamps, "AOD", "TIMESTAMPS", //! Table which holds the timestamp of a BC + timestamp::Timestamp); +} // namespace aod +namespace soa +{ +extern template struct Join<aod::BCs, aod::Timestamps>; +} +namespace aod +{ using BCsWithTimestamps = soa::Join<aod::BCs, aod::Timestamps>; namespace collision { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(PosX, posX, float); -DECLARE_SOA_COLUMN(PosY, posY, float); -DECLARE_SOA_COLUMN(PosZ, posZ, float); -DECLARE_SOA_COLUMN(CovXX, covXX, float); -DECLARE_SOA_COLUMN(CovXY, covXY, float); -DECLARE_SOA_COLUMN(CovXZ, covXZ, float); -DECLARE_SOA_COLUMN(CovYY, covYY, float); -DECLARE_SOA_COLUMN(CovYZ, covYZ, float); -DECLARE_SOA_COLUMN(CovZZ, covZZ, float); -DECLARE_SOA_COLUMN(Chi2, chi2, float); -DECLARE_SOA_COLUMN(NumContrib, numContrib, uint32_t); -DECLARE_SOA_COLUMN(CollisionTime, collisionTime, float); -DECLARE_SOA_COLUMN(CollisionTimeRes, collisionTimeRes, float); -DECLARE_SOA_COLUMN(CollisionTimeMask, collisionTimeMask, uint8_t); // TODO put nature of CollisionTimeRes here, e.g. MSB 0 = exact range / 1 = Gaussian uncertainty +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! Most probably BC to where this collision has occured +DECLARE_SOA_COLUMN(PosX, posX, float); //! X Vertex position in cm +DECLARE_SOA_COLUMN(PosY, posY, float); //! Y Vertex position in cm +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! Z Vertex position in cm +DECLARE_SOA_COLUMN(CovXX, covXX, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(CovXY, covXY, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(CovXZ, covXZ, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(CovYY, covYY, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(CovYZ, covYZ, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(CovZZ, covZZ, float); //! Vertex covariance matrix +DECLARE_SOA_COLUMN(Flags, flags, uint16_t); //! Run 2: see CollisionFlagsRun2 | Run 3: see Vertex::Flags +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! Chi2 of vertex fit +DECLARE_SOA_COLUMN(NumContrib, numContrib, uint16_t); //! Number of tracks used for the vertex +DECLARE_SOA_COLUMN(CollisionTime, collisionTime, float); //! Collision time in ns relative to BC stored in bc() +DECLARE_SOA_COLUMN(CollisionTimeRes, collisionTimeRes, float); //! Resolution of collision time } // namespace collision -DECLARE_SOA_TABLE(Collisions, "AOD", "COLLISION", o2::soa::Index<>, collision::BCId, collision::PosX, collision::PosY, collision::PosZ, collision::CovXX, collision::CovXY, collision::CovXZ, collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2, collision::NumContrib, collision::CollisionTime, collision::CollisionTimeRes, collision::CollisionTimeMask); +DECLARE_SOA_TABLE(Collisions, "AOD", "COLLISION", //! Time and vertex information of collision + o2::soa::Index<>, collision::BCId, + collision::PosX, collision::PosY, collision::PosZ, + collision::CovXX, collision::CovXY, collision::CovXZ, collision::CovYY, collision::CovYZ, collision::CovZZ, + collision::Flags, collision::Chi2, collision::NumContrib, + collision::CollisionTime, collision::CollisionTimeRes); using Collision = Collisions::iterator; // NOTE Relation between Collisions and BC table -// (important for pp in case of ambigous assignment) +// (important for pp in case of ambiguous assignment) // A collision entry points to the entry in the BC table based on the calculated BC from the collision time -// To study other compatible triggers with the collision time, use this helper (not yet implemented :)): -// auto compatibleBCs = getCompatibleBCs(collision, BCs, /* sigma */ 3); +// To study other compatible triggers with the collision time, check the tutorial: compatibleBCs.cxx namespace track { // TRACKPAR TABLE definition -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_COLUMN(TrackType, trackType, uint8_t); // TODO change to TrackTypeEnum when enums are supported -DECLARE_SOA_COLUMN(X, x, float); -DECLARE_SOA_COLUMN(Alpha, alpha, float); -DECLARE_SOA_COLUMN(Y, y, float); -DECLARE_SOA_COLUMN(Z, z, float); -DECLARE_SOA_COLUMN(Snp, snp, float); -DECLARE_SOA_COLUMN(Tgl, tgl, float); -DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); -DECLARE_SOA_EXPRESSION_COLUMN(RawPhi, phiraw, float, nasin(aod::track::snp) + aod::track::alpha); +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision to which this track belongs +// TODO change to TrackTypeEnum when enums are supported +DECLARE_SOA_COLUMN(TrackType, trackType, uint8_t); //! Type of track. See enum TrackTypeEnum +DECLARE_SOA_COLUMN(X, x, float); //! +DECLARE_SOA_COLUMN(Alpha, alpha, float); //! +DECLARE_SOA_COLUMN(Y, y, float); //! +DECLARE_SOA_COLUMN(Z, z, float); //! +DECLARE_SOA_COLUMN(Snp, snp, float); //! +DECLARE_SOA_COLUMN(Tgl, tgl, float); //! +DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); //! (sign of charge)/Pt in c/GeV. Use pt() and sign() instead +DECLARE_SOA_EXPRESSION_COLUMN(RawPhi, phiraw, float, //! Raw Phi (not folded onto [0, 2pi)). Use phi() instead + nasin(aod::track::snp) + aod::track::alpha); // FIXME: make expression column when conditional nodes are supported in Gandiva -DECLARE_SOA_DYNAMIC_COLUMN(NormalizedPhi, phi, [](float phi) -> float { - constexpr float twopi = 2.0f * static_cast<float>(M_PI); - if (phi < 0) - phi += twopi; - if (phi > twopi) - phi -= twopi; - return phi; -}); -DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, -1.f * nlog(ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl)))); -DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, nabs(1.f / aod::track::signed1Pt)); - -DECLARE_SOA_DYNAMIC_COLUMN(Charge, charge, [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float signed1Pt, float snp, float alpha) -> float { - auto pt = 1.f / std::abs(signed1Pt); - float cs, sn; - math_utils::sincos(alpha, sn, cs); - auto r = std::sqrt((1.f - snp) * (1.f + snp)); - return pt * (r * cs - snp * sn); -}); -DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float signed1Pt, float snp, float alpha) -> float { - auto pt = 1.f / std::abs(signed1Pt); - float cs, sn; - math_utils::sincos(alpha, sn, cs); - auto r = std::sqrt((1.f - snp) * (1.f + snp)); - return pt * (snp * cs + r * sn); -}); -DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float signed1Pt, float tgl) -> float { - auto pt = 1.f / std::abs(signed1Pt); - return pt * tgl; -}); - -DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, 0.5f * (ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl)) + 1.f / ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl))) / nabs(aod::track::signed1Pt)); +DECLARE_SOA_DYNAMIC_COLUMN(NormalizedPhi, phi, //! Phi of the track, in radians within [0, 2pi) + [](float phi) -> float { + constexpr float twopi = 2.0f * static_cast<float>(M_PI); + if (phi < 0) + phi += twopi; + if (phi > twopi) + phi -= twopi; + return phi; + }); +DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity + -1.f * nlog(ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl)))); +DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! Transverse momentum of the track in GeV/c + nabs(1.f / aod::track::signed1Pt)); + +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! Charge: positive: 1, negative: -1 + [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! Momentum in x-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + float cs, sn; + math_utils::sincos(alpha, sn, cs); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (r * cs - snp * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! Momentum in y-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + float cs, sn; + math_utils::sincos(alpha, sn, cs); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (snp * cs + r * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Momentum in z-direction in GeV/c + [](float signed1Pt, float tgl) -> float { + auto pt = 1.f / std::abs(signed1Pt); + return pt * tgl; + }); + +DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Momentum in Gev/c + 0.5f * (ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl)) + 1.f / ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::track::tgl))) / nabs(aod::track::signed1Pt)); // TRACKPARCOV TABLE definition -DECLARE_SOA_COLUMN(SigmaY, sigmaY, float); -DECLARE_SOA_COLUMN(SigmaZ, sigmaZ, float); -DECLARE_SOA_COLUMN(SigmaSnp, sigmaSnp, float); -DECLARE_SOA_COLUMN(SigmaTgl, sigmaTgl, float); -DECLARE_SOA_COLUMN(Sigma1Pt, sigma1Pt, float); -DECLARE_SOA_COLUMN(RhoZY, rhoZY, int8_t); -DECLARE_SOA_COLUMN(RhoSnpY, rhoSnpY, int8_t); -DECLARE_SOA_COLUMN(RhoSnpZ, rhoSnpZ, int8_t); -DECLARE_SOA_COLUMN(RhoTglY, rhoTglY, int8_t); -DECLARE_SOA_COLUMN(RhoTglZ, rhoTglZ, int8_t); -DECLARE_SOA_COLUMN(RhoTglSnp, rhoTglSnp, int8_t); -DECLARE_SOA_COLUMN(Rho1PtY, rho1PtY, int8_t); -DECLARE_SOA_COLUMN(Rho1PtZ, rho1PtZ, int8_t); -DECLARE_SOA_COLUMN(Rho1PtSnp, rho1PtSnp, int8_t); -DECLARE_SOA_COLUMN(Rho1PtTgl, rho1PtTgl, int8_t); - -DECLARE_SOA_EXPRESSION_COLUMN(CYY, cYY, float, aod::track::sigmaY* aod::track::sigmaY); -DECLARE_SOA_EXPRESSION_COLUMN(CZY, cZY, float, (aod::track::rhoZY / 128.f) * (aod::track::sigmaZ * aod::track::sigmaY)); -DECLARE_SOA_EXPRESSION_COLUMN(CZZ, cZZ, float, aod::track::sigmaZ* aod::track::sigmaZ); -DECLARE_SOA_EXPRESSION_COLUMN(CSnpY, cSnpY, float, (aod::track::rhoSnpY / 128.f) * (aod::track::sigmaSnp * aod::track::sigmaY)); -DECLARE_SOA_EXPRESSION_COLUMN(CSnpZ, cSnpZ, float, (aod::track::rhoSnpZ / 128.f) * (aod::track::sigmaSnp * aod::track::sigmaZ)); -DECLARE_SOA_EXPRESSION_COLUMN(CSnpSnp, cSnpSnp, float, aod::track::sigmaSnp* aod::track::sigmaSnp); -DECLARE_SOA_EXPRESSION_COLUMN(CTglY, cTglY, float, (aod::track::rhoTglY / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaY)); -DECLARE_SOA_EXPRESSION_COLUMN(CTglZ, cTglZ, float, (aod::track::rhoTglZ / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaZ)); -DECLARE_SOA_EXPRESSION_COLUMN(CTglSnp, cTglSnp, float, (aod::track::rhoTglSnp / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaSnp)); -DECLARE_SOA_EXPRESSION_COLUMN(CTglTgl, cTglTgl, float, aod::track::sigmaTgl* aod::track::sigmaTgl); -DECLARE_SOA_EXPRESSION_COLUMN(C1PtY, c1PtY, float, (aod::track::rho1PtY / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaY)); -DECLARE_SOA_EXPRESSION_COLUMN(C1PtZ, c1PtZ, float, (aod::track::rho1PtZ / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaZ)); -DECLARE_SOA_EXPRESSION_COLUMN(C1PtSnp, c1PtSnp, float, (aod::track::rho1PtSnp / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaSnp)); -DECLARE_SOA_EXPRESSION_COLUMN(C1PtTgl, c1PtTgl, float, (aod::track::rho1PtTgl / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaTgl)); -DECLARE_SOA_EXPRESSION_COLUMN(C1Pt21Pt2, c1Pt21Pt2, float, aod::track::sigma1Pt* aod::track::sigma1Pt); +DECLARE_SOA_COLUMN(SigmaY, sigmaY, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaZ, sigmaZ, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaSnp, sigmaSnp, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaTgl, sigmaTgl, float); //! Covariance matrix +DECLARE_SOA_COLUMN(Sigma1Pt, sigma1Pt, float); //! Covariance matrix +DECLARE_SOA_COLUMN(RhoZY, rhoZY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoSnpY, rhoSnpY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoSnpZ, rhoSnpZ, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglY, rhoTglY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglZ, rhoTglZ, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglSnp, rhoTglSnp, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtY, rho1PtY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtZ, rho1PtZ, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtSnp, rho1PtSnp, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtTgl, rho1PtTgl, int8_t); //! Covariance matrix in compressed form + +DECLARE_SOA_EXPRESSION_COLUMN(CYY, cYY, float, //! + aod::track::sigmaY* aod::track::sigmaY); +DECLARE_SOA_EXPRESSION_COLUMN(CZY, cZY, float, //! + (aod::track::rhoZY / 128.f) * (aod::track::sigmaZ * aod::track::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CZZ, cZZ, float, //! + aod::track::sigmaZ* aod::track::sigmaZ); +DECLARE_SOA_EXPRESSION_COLUMN(CSnpY, cSnpY, float, //! + (aod::track::rhoSnpY / 128.f) * (aod::track::sigmaSnp * aod::track::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CSnpZ, cSnpZ, float, //! + (aod::track::rhoSnpZ / 128.f) * (aod::track::sigmaSnp * aod::track::sigmaZ)); +DECLARE_SOA_EXPRESSION_COLUMN(CSnpSnp, cSnpSnp, float, //! + aod::track::sigmaSnp* aod::track::sigmaSnp); +DECLARE_SOA_EXPRESSION_COLUMN(CTglY, cTglY, float, //! + (aod::track::rhoTglY / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglZ, cTglZ, float, //! + (aod::track::rhoTglZ / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaZ)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglSnp, cTglSnp, float, //! + (aod::track::rhoTglSnp / 128.f) * (aod::track::sigmaTgl * aod::track::sigmaSnp)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglTgl, cTglTgl, float, //! + aod::track::sigmaTgl* aod::track::sigmaTgl); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtY, c1PtY, float, //! + (aod::track::rho1PtY / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtZ, c1PtZ, float, //! + (aod::track::rho1PtZ / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaZ)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtSnp, c1PtSnp, float, //! + (aod::track::rho1PtSnp / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaSnp)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtTgl, c1PtTgl, float, //! + (aod::track::rho1PtTgl / 128.f) * (aod::track::sigma1Pt * aod::track::sigmaTgl)); +DECLARE_SOA_EXPRESSION_COLUMN(C1Pt21Pt2, c1Pt21Pt2, float, //! + aod::track::sigma1Pt* aod::track::sigma1Pt); // TRACKEXTRA TABLE definition -DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); -DECLARE_SOA_COLUMN(Flags, flags, uint32_t); -DECLARE_SOA_COLUMN(ITSClusterMap, itsClusterMap, uint8_t); -DECLARE_SOA_COLUMN(TPCNClsFindable, tpcNClsFindable, uint8_t); -DECLARE_SOA_COLUMN(TPCNClsFindableMinusFound, tpcNClsFindableMinusFound, int8_t); -DECLARE_SOA_COLUMN(TPCNClsFindableMinusCrossedRows, tpcNClsFindableMinusCrossedRows, int8_t); -DECLARE_SOA_COLUMN(TPCNClsShared, tpcNClsShared, uint8_t); -DECLARE_SOA_COLUMN(TRDPattern, trdPattern, uint8_t); -DECLARE_SOA_COLUMN(ITSChi2NCl, itsChi2NCl, float); -DECLARE_SOA_COLUMN(TPCChi2NCl, tpcChi2NCl, float); -DECLARE_SOA_COLUMN(TRDChi2, trdChi2, float); -DECLARE_SOA_COLUMN(TOFChi2, tofChi2, float); -DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); -DECLARE_SOA_COLUMN(TRDSignal, trdSignal, float); -DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); -DECLARE_SOA_COLUMN(Length, length, float); -DECLARE_SOA_COLUMN(TOFExpMom, tofExpMom, float); -DECLARE_SOA_COLUMN(TrackEtaEMCAL, trackEtaEmcal, float); -DECLARE_SOA_COLUMN(TrackPhiEMCAL, trackPhiEmcal, float); -DECLARE_SOA_DYNAMIC_COLUMN(TPCNClsFound, tpcNClsFound, [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> int16_t { return (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, [](uint8_t tpcNClsFindable, int8_t TPCNClsFindableMinusCrossedRows) -> int16_t { return (int16_t)tpcNClsFindable - TPCNClsFindableMinusCrossedRows; }); -DECLARE_SOA_DYNAMIC_COLUMN(ITSNCls, itsNCls, [](uint8_t itsClusterMap) -> uint8_t { - uint8_t itsNcls = 0; - constexpr uint8_t bit = 1; - for (int layer = 0; layer < 7; layer++) { - if (itsClusterMap & (bit << layer)) - itsNcls++; - } - return itsNcls; -}); -DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, [](uint8_t itsClusterMap) -> uint8_t { - uint8_t itsNclsInnerBarrel = 0; - constexpr uint8_t bit = 1; - for (int layer = 0; layer < 3; layer++) { - if (itsClusterMap & (bit << layer)) - itsNclsInnerBarrel++; - } - return itsNclsInnerBarrel; -}); - -DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, +DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); //! Momentum at inner wall of the TPC +DECLARE_SOA_COLUMN(Flags, flags, uint32_t); //! Track flags. Run 2: see TrackFlagsRun2Enum | Run 3: see TrackFlags +DECLARE_SOA_COLUMN(ITSClusterMap, itsClusterMap, uint8_t); //! ITS cluster map, one bit per a layer, starting from the innermost +DECLARE_SOA_COLUMN(TPCNClsFindable, tpcNClsFindable, uint8_t); //! Findable TPC clusters for this track geometry +DECLARE_SOA_COLUMN(TPCNClsFindableMinusFound, tpcNClsFindableMinusFound, int8_t); //! TPC Clusters: Findable - Found +DECLARE_SOA_COLUMN(TPCNClsFindableMinusCrossedRows, tpcNClsFindableMinusCrossedRows, int8_t); //! TPC Clusters: Findable - crossed rows +DECLARE_SOA_COLUMN(TPCNClsShared, tpcNClsShared, uint8_t); //! Number of shared TPC clusters +DECLARE_SOA_COLUMN(TRDPattern, trdPattern, uint8_t); //! Contributor to the track on TRD layer in bits 0-5, starting from the innermost +DECLARE_SOA_COLUMN(ITSChi2NCl, itsChi2NCl, float); //! Chi2 / cluster for the ITS track segment +DECLARE_SOA_COLUMN(TPCChi2NCl, tpcChi2NCl, float); //! Chi2 / cluster for the TPC track segment +DECLARE_SOA_COLUMN(TRDChi2, trdChi2, float); //! Chi2 for the TRD track segment +DECLARE_SOA_COLUMN(TOFChi2, tofChi2, float); //! Chi2 for the TOF track segment +DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); //! dE/dx signal in the TPC +DECLARE_SOA_COLUMN(TRDSignal, trdSignal, float); //! dE/dx signal in the TRD +DECLARE_SOA_COLUMN(Length, length, float); //! Track length +DECLARE_SOA_COLUMN(TOFExpMom, tofExpMom, float); //! TOF expected momentum obtained in tracking, used to compute the expected times +DECLARE_SOA_COLUMN(TrackEtaEMCAL, trackEtaEmcal, float); //! +DECLARE_SOA_COLUMN(TrackPhiEMCAL, trackPhiEmcal, float); //! +DECLARE_SOA_COLUMN(TrackTime, trackTime, float); //! Estimated time of the track in ns wrt collision().bc() or ambiguoustrack.bcSlice()[0] +DECLARE_SOA_COLUMN(TrackTimeRes, trackTimeRes, float); //! Resolution of the track time in ns (see TrackFlags::TrackTimeResIsRange) +DECLARE_SOA_EXPRESSION_COLUMN(DetectorMap, detectorMap, uint8_t, //! Detector map: see enum DetectorMapEnum + ifnode(aod::track::itsClusterMap > (uint8_t)0, static_cast<uint8_t>(o2::aod::track::ITS), (uint8_t)0x0) | + ifnode(aod::track::tpcNClsFindable > (uint8_t)0, static_cast<uint8_t>(o2::aod::track::TPC), (uint8_t)0x0) | + ifnode(aod::track::trdPattern > (uint8_t)0, static_cast<uint8_t>(o2::aod::track::TRD), (uint8_t)0x0) | + ifnode((aod::track::tofChi2 >= 0.f) && (aod::track::tofExpMom > 0.f), static_cast<uint8_t>(o2::aod::track::TOF), (uint8_t)0x0)); +DECLARE_SOA_DYNAMIC_COLUMN(HasITS, hasITS, //! Flag to check if track has a ITS match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPC, hasTPC, //! Flag to check if track has a TPC match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TPC; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTRD, hasTRD, //! Flag to check if track has a TRD match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, //! Flag to check if track has a TOF measurement + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); +DECLARE_SOA_DYNAMIC_COLUMN(PIDForTracking, pidForTracking, //! PID hypothesis used during tracking. See the constants in the class PID in PID.h + [](uint32_t flags) -> uint32_t { return flags >> 28; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNClsFound, tpcNClsFound, //! Number of found TPC clusters + [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> int16_t { return (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, //! Number of crossed TPC Rows + [](uint8_t tpcNClsFindable, int8_t TPCNClsFindableMinusCrossedRows) -> int16_t { return (int16_t)tpcNClsFindable - TPCNClsFindableMinusCrossedRows; }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNCls, itsNCls, //! Number of ITS clusters + [](uint8_t itsClusterMap) -> uint8_t { + uint8_t itsNcls = 0; + constexpr uint8_t bit = 1; + for (int layer = 0; layer < 7; layer++) { + if (itsClusterMap & (bit << layer)) + itsNcls++; + } + return itsNcls; + }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, //! Number of ITS clusters in the Inner Barrel + [](uint8_t itsClusterMap) -> uint8_t { + uint8_t itsNclsInnerBarrel = 0; + constexpr uint8_t bit = 1; + for (int layer = 0; layer < 3; layer++) { + if (itsClusterMap & (bit << layer)) + itsNclsInnerBarrel++; + } + return itsNclsInnerBarrel; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TPCFoundOverFindableCls, tpcFoundOverFindableCls, //! Ratio of found over findable clusters + [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> float { + int16_t tpcNClsFound = (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; + return (float)tpcNClsFound / (float)tpcNClsFindable; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, //! Ratio crossed rows over findable clusters [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusCrossedRows) -> float { int16_t tpcNClsCrossedRows = (int16_t)tpcNClsFindable - tpcNClsFindableMinusCrossedRows; return (float)tpcNClsCrossedRows / (float)tpcNClsFindable; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCFractionSharedCls, tpcFractionSharedCls, [](uint8_t tpcNClsShared, uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> float { - int16_t tpcNClsFound = (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; - return (float)tpcNClsShared / (float)tpcNClsFound; -}); +DECLARE_SOA_DYNAMIC_COLUMN(TPCFractionSharedCls, tpcFractionSharedCls, //! Fraction of shared TPC clusters + [](uint8_t tpcNClsShared, uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> float { + int16_t tpcNClsFound = (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; + return (float)tpcNClsShared / (float)tpcNClsFound; + }); } // namespace track -DECLARE_SOA_TABLE_FULL(StoredTracks, "Tracks", "AOD", "TRACK:PAR", +DECLARE_SOA_TABLE_FULL(StoredTracks, "Tracks", "AOD", "TRACK", //! On disk version of the Track table o2::soa::Index<>, track::CollisionId, track::TrackType, track::X, track::Alpha, track::Y, track::Z, track::Snp, track::Tgl, @@ -215,20 +279,20 @@ DECLARE_SOA_TABLE_FULL(StoredTracks, "Tracks", "AOD", "TRACK:PAR", track::Px<track::Signed1Pt, track::Snp, track::Alpha>, track::Py<track::Signed1Pt, track::Snp, track::Alpha>, track::Pz<track::Signed1Pt, track::Tgl>, - track::Charge<track::Signed1Pt>); + track::Sign<track::Signed1Pt>); -DECLARE_SOA_EXTENDED_TABLE(Tracks, StoredTracks, "TRACK:PAR", +DECLARE_SOA_EXTENDED_TABLE(Tracks, StoredTracks, "TRACK", //! Basic track properties aod::track::Pt, aod::track::P, aod::track::Eta, aod::track::RawPhi); -DECLARE_SOA_TABLE_FULL(StoredTracksCov, "TracksCov", "AOD", "TRACK:PARCOV", +DECLARE_SOA_TABLE_FULL(StoredTracksCov, "TracksCov", "AOD", "TRACKCOV", //! On disk version of the TracksCov table track::SigmaY, track::SigmaZ, track::SigmaSnp, track::SigmaTgl, track::Sigma1Pt, track::RhoZY, track::RhoSnpY, track::RhoSnpZ, track::RhoTglY, track::RhoTglZ, track::RhoTglSnp, track::Rho1PtY, track::Rho1PtZ, track::Rho1PtSnp, track::Rho1PtTgl); -DECLARE_SOA_EXTENDED_TABLE(TracksCov, StoredTracksCov, "TRACK:PARCOV", +DECLARE_SOA_EXTENDED_TABLE(TracksCov, StoredTracksCov, "TRACKCOV", //! Track covariance matrix aod::track::CYY, aod::track::CZY, aod::track::CZZ, @@ -245,187 +309,326 @@ DECLARE_SOA_EXTENDED_TABLE(TracksCov, StoredTracksCov, "TRACK:PARCOV", aod::track::C1PtTgl, aod::track::C1Pt21Pt2); -DECLARE_SOA_TABLE(TracksExtra, "AOD", "TRACK:EXTRA", - track::TPCInnerParam, track::Flags, track::ITSClusterMap, - track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, - track::TPCNClsShared, track::TRDPattern, track::ITSChi2NCl, - track::TPCChi2NCl, track::TRDChi2, track::TOFChi2, - track::TPCSignal, track::TRDSignal, track::TOFSignal, track::Length, track::TOFExpMom, - track::TPCNClsFound<track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, - track::TPCNClsCrossedRows<track::TPCNClsFindable, track::TPCNClsFindableMinusCrossedRows>, - track::ITSNCls<track::ITSClusterMap>, track::ITSNClsInnerBarrel<track::ITSClusterMap>, - track::TPCCrossedRowsOverFindableCls<track::TPCNClsFindable, track::TPCNClsFindableMinusCrossedRows>, - track::TPCFractionSharedCls<track::TPCNClsShared, track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, - track::TrackEtaEMCAL, track::TrackPhiEMCAL); +DECLARE_SOA_TABLE_FULL(StoredTracksExtra, "TracksExtra", "AOD", "TRACKEXTRA", //! On disk version of TracksExtra + track::TPCInnerParam, track::Flags, track::ITSClusterMap, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, + track::TPCNClsShared, track::TRDPattern, track::ITSChi2NCl, + track::TPCChi2NCl, track::TRDChi2, track::TOFChi2, + track::TPCSignal, track::TRDSignal, track::Length, track::TOFExpMom, + track::PIDForTracking<track::Flags>, + track::HasITS<track::DetectorMap>, track::HasTPC<track::DetectorMap>, + track::HasTRD<track::DetectorMap>, track::HasTOF<track::DetectorMap>, + track::TPCNClsFound<track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, + track::TPCNClsCrossedRows<track::TPCNClsFindable, track::TPCNClsFindableMinusCrossedRows>, + track::ITSNCls<track::ITSClusterMap>, track::ITSNClsInnerBarrel<track::ITSClusterMap>, + track::TPCCrossedRowsOverFindableCls<track::TPCNClsFindable, track::TPCNClsFindableMinusCrossedRows>, + track::TPCFoundOverFindableCls<track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, + track::TPCFractionSharedCls<track::TPCNClsShared, track::TPCNClsFindable, track::TPCNClsFindableMinusFound>, + track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); + +DECLARE_SOA_EXTENDED_TABLE(TracksExtra, StoredTracksExtra, "TRACKEXTRA", //! Additional track information (clusters, PID, etc.) + track::DetectorMap); using Track = Tracks::iterator; using TrackCov = TracksCov::iterator; using TrackExtra = TracksExtra::iterator; +} // namespace aod +namespace soa +{ +extern template struct soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra>; +extern template struct soa::Join<aod::TracksExtension, aod::StoredTracks>; +} // namespace soa +namespace aod +{ using FullTracks = soa::Join<Tracks, TracksCov, TracksExtra>; using FullTrack = FullTracks::iterator; -namespace unassignedtracks +namespace fwdtrack { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_INDEX_COLUMN(Track, track); -} // namespace unassignedtracks +// FwdTracks and MFTTracks Columns definitions +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_COLUMN(TrackType, trackType, uint8_t); //! Type of track. See enum ForwardTrackTypeEnum +DECLARE_SOA_COLUMN(X, x, float); //! TrackParFwd parameter x +DECLARE_SOA_COLUMN(Y, y, float); //! TrackParFwd parameter y +DECLARE_SOA_COLUMN(Z, z, float); //! TrackParFwd propagation parameter z +DECLARE_SOA_COLUMN(Phi, phi, float); //! TrackParFwd parameter phi; (i.e. pt pointing direction) +DECLARE_SOA_COLUMN(Tgl, tgl, float); //! TrackParFwd parameter tan(\lamba); (\lambda = 90 - \theta_{polar}) +DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); //! TrackParFwd parameter: charged inverse transverse momentum; (q/pt) +DECLARE_SOA_COLUMN(NClusters, nClusters, int8_t); //! Number of clusters +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! Track chi^2 +DECLARE_SOA_COLUMN(PDca, pDca, float); //! PDca for MUONStandalone +DECLARE_SOA_COLUMN(RAtAbsorberEnd, rAtAbsorberEnd, float); //! RAtAbsorberEnd for MUONStandalone tracks and GlobalMuonTrackstracks +DECLARE_SOA_COLUMN(Chi2MatchMCHMID, chi2MatchMCHMID, float); //! MCH-MID Match Chi2 for MUONStandalone tracks +DECLARE_SOA_COLUMN(Chi2MatchMCHMFT, chi2MatchMCHMFT, float); //! MCH-MFT Match Chi2 for GlobalMuonTracks +DECLARE_SOA_COLUMN(MatchScoreMCHMFT, matchScoreMCHMFT, float); //! MCH-MFT Machine Learning Matching Score for GlobalMuonTracks +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(MCHTrack, matchMCHTrack, int, "FwdTracks_MatchMCHTrack"); //! Index of matching MCH track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_COLUMN(MCHBitMap, mchBitMap, uint16_t); //! Fired muon trackig chambers bitmap +DECLARE_SOA_COLUMN(MIDBitMap, midBitMap, uint8_t); //! MID bitmap: non-bending plane (4bit), bending plane (4bit) +DECLARE_SOA_COLUMN(MIDBoards, midBoards, uint32_t); //! Local boards on each MID plane (8 bits per plane) +DECLARE_SOA_COLUMN(TrackTime, trackTime, float); //! Estimated time of the track in ns wrt collision().bc() or ambiguoustrack.bcSlice()[0] +DECLARE_SOA_COLUMN(TrackTimeRes, trackTimeRes, float); //! Resolution of the track time in ns +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! Sign of the track eletric charge + [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); +DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! + -1.f * nlog(ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::fwdtrack::tgl)))); +DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! + nabs(1.f / aod::fwdtrack::signed1Pt)); +DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! + 0.5f * (ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::fwdtrack::tgl)) + 1.f / ntan(0.25f * static_cast<float>(M_PI) - 0.5f * natan(aod::fwdtrack::tgl))) / nabs(aod::fwdtrack::signed1Pt)); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pt, float phi) -> float { + return pt * std::cos(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pt, float phi) -> float { + return pt * std::sin(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pt, float tgl) -> float { + return pt * tgl; + }); +DECLARE_SOA_DYNAMIC_COLUMN(MIDBoardCh1, midBoardCh1, //! + [](uint32_t midBoards) -> int { + return static_cast<int>(midBoards & 0xFF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(MIDBoardCh2, midBoardCh2, //! + [](uint32_t midBoards) -> int { + return static_cast<int>((midBoards >> 8) & 0xFF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(MIDBoardCh3, midBoardCh3, //! + [](uint32_t midBoards) -> int { + return static_cast<int>((midBoards >> 16) & 0xFF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(MIDBoardCh4, midBoardCh4, //! + [](uint32_t midBoards) -> int { + return static_cast<int>((midBoards >> 24) & 0xFF); + }); + +// FwdTracksCov columns definitions +DECLARE_SOA_COLUMN(SigmaX, sigmaX, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaY, sigmaY, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaPhi, sigmaPhi, float); //! Covariance matrix +DECLARE_SOA_COLUMN(SigmaTgl, sigmaTgl, float); //! Covariance matrix +DECLARE_SOA_COLUMN(Sigma1Pt, sigma1Pt, float); //! Covariance matrix +DECLARE_SOA_COLUMN(RhoXY, rhoXY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoPhiX, rhoPhiX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoPhiY, rhoPhiY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglX, rhoTglX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglY, rhoTglY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(RhoTglPhi, rhoTglPhi, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtX, rho1PtX, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtY, rho1PtY, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtPhi, rho1PtPhi, int8_t); //! Covariance matrix in compressed form +DECLARE_SOA_COLUMN(Rho1PtTgl, rho1PtTgl, int8_t); //! Covariance matrix in compressed form + +DECLARE_SOA_EXPRESSION_COLUMN(CXX, cXX, float, //! + aod::fwdtrack::sigmaX* aod::fwdtrack::sigmaX); +DECLARE_SOA_EXPRESSION_COLUMN(CXY, cXY, float, //! + (aod::fwdtrack::rhoXY / 128.f) * (aod::fwdtrack::sigmaX * aod::fwdtrack::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CYY, cYY, float, //! + aod::fwdtrack::sigmaY* aod::fwdtrack::sigmaY); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiX, cPhiX, float, //! + (aod::fwdtrack::rhoPhiX / 128.f) * (aod::fwdtrack::sigmaPhi * aod::fwdtrack::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiY, cPhiY, float, //! + (aod::fwdtrack::rhoPhiY / 128.f) * (aod::fwdtrack::sigmaPhi * aod::fwdtrack::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CPhiPhi, cPhiPhi, float, //! + aod::fwdtrack::sigmaPhi* aod::fwdtrack::sigmaPhi); +DECLARE_SOA_EXPRESSION_COLUMN(CTglX, cTglX, float, //! + (aod::fwdtrack::rhoTglX / 128.f) * (aod::fwdtrack::sigmaTgl * aod::fwdtrack::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglY, cTglY, float, //! + (aod::fwdtrack::rhoTglY / 128.f) * (aod::fwdtrack::sigmaTgl * aod::fwdtrack::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglPhi, cTglPhi, float, //! + (aod::fwdtrack::rhoTglPhi / 128.f) * (aod::fwdtrack::sigmaTgl * aod::fwdtrack::sigmaPhi)); +DECLARE_SOA_EXPRESSION_COLUMN(CTglTgl, cTglTgl, float, //! + aod::fwdtrack::sigmaTgl* aod::fwdtrack::sigmaTgl); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtY, c1PtY, float, //! + (aod::fwdtrack::rho1PtY / 128.f) * (aod::fwdtrack::sigma1Pt * aod::fwdtrack::sigmaY)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtX, c1PtX, float, //! + (aod::fwdtrack::rho1PtX / 128.f) * (aod::fwdtrack::sigma1Pt * aod::fwdtrack::sigmaX)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtPhi, c1PtPhi, float, //! + (aod::fwdtrack::rho1PtPhi / 128.f) * (aod::fwdtrack::sigma1Pt * aod::fwdtrack::sigmaPhi)); +DECLARE_SOA_EXPRESSION_COLUMN(C1PtTgl, c1PtTgl, float, //! + (aod::fwdtrack::rho1PtTgl / 128.f) * (aod::fwdtrack::sigma1Pt * aod::fwdtrack::sigmaTgl)); +DECLARE_SOA_EXPRESSION_COLUMN(C1Pt21Pt2, c1Pt21Pt2, float, //! + aod::fwdtrack::sigma1Pt* aod::fwdtrack::sigma1Pt); +} // namespace fwdtrack + +// MFTStandalone tracks +DECLARE_SOA_TABLE_FULL(StoredMFTTracks, "MFTTracks", "AOD", "MFTTRACK", //! + o2::soa::Index<>, fwdtrack::CollisionId, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, + fwdtrack::Signed1Pt, fwdtrack::NClusters, + fwdtrack::Px<fwdtrack::Pt, fwdtrack::Phi>, + fwdtrack::Py<fwdtrack::Pt, fwdtrack::Phi>, + fwdtrack::Pz<fwdtrack::Pt, fwdtrack::Tgl>, + fwdtrack::Sign<fwdtrack::Signed1Pt>, fwdtrack::Chi2); + +DECLARE_SOA_EXTENDED_TABLE(MFTTracks, StoredMFTTracks, "MFTTRACK", //! + aod::fwdtrack::Pt, + aod::fwdtrack::Eta, + aod::fwdtrack::P); + +using MFTTrack = MFTTracks::iterator; + +namespace fwdtrack // Index to MFTtrack column must be defined after table definition. +{ +DECLARE_SOA_INDEX_COLUMN(MFTTrack, matchMFTTrack); //! ID of matching MFT track for GlobalMuonTracks and GlobalForwardTracks +} + +// Tracks including MCH and/or MCH (plus optionally MFT) //! +DECLARE_SOA_TABLE_FULL(StoredFwdTracks, "FwdTracks", "AOD", "FWDTRACK", + o2::soa::Index<>, fwdtrack::CollisionId, fwdtrack::TrackType, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, + fwdtrack::Signed1Pt, fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Px<fwdtrack::Pt, fwdtrack::Phi>, + fwdtrack::Py<fwdtrack::Pt, fwdtrack::Phi>, + fwdtrack::Pz<fwdtrack::Pt, fwdtrack::Tgl>, + fwdtrack::Sign<fwdtrack::Signed1Pt>, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MatchScoreMCHMFT, fwdtrack::MFTTrackId, fwdtrack::MCHTrackId, + fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, + fwdtrack::TrackTime, fwdtrack::TrackTimeRes); + +DECLARE_SOA_EXTENDED_TABLE(FwdTracks, StoredFwdTracks, "FWDTRACK", //! + aod::fwdtrack::Eta, // NOTE the order is different here than in MFTTracks as table extension has to be unique + aod::fwdtrack::Pt, + aod::fwdtrack::P); + +DECLARE_SOA_TABLE_FULL(StoredFwdTracksCov, "FwdTracksCov", "AOD", "FWDTRACKCOV", //! + fwdtrack::SigmaX, fwdtrack::SigmaY, fwdtrack::SigmaPhi, fwdtrack::SigmaTgl, fwdtrack::Sigma1Pt, + fwdtrack::RhoXY, fwdtrack::RhoPhiY, fwdtrack::RhoPhiX, fwdtrack::RhoTglX, fwdtrack::RhoTglY, + fwdtrack::RhoTglPhi, fwdtrack::Rho1PtX, fwdtrack::Rho1PtY, fwdtrack::Rho1PtPhi, fwdtrack::Rho1PtTgl); + +DECLARE_SOA_EXTENDED_TABLE(FwdTracksCov, StoredFwdTracksCov, "FWDTRACKCOV", //! + aod::fwdtrack::CXX, + aod::fwdtrack::CXY, + aod::fwdtrack::CYY, + aod::fwdtrack::CPhiX, + aod::fwdtrack::CPhiY, + aod::fwdtrack::CPhiPhi, + aod::fwdtrack::CTglX, + aod::fwdtrack::CTglY, + aod::fwdtrack::CTglPhi, + aod::fwdtrack::CTglTgl, + aod::fwdtrack::C1PtX, + aod::fwdtrack::C1PtY, + aod::fwdtrack::C1PtPhi, + aod::fwdtrack::C1PtTgl, + aod::fwdtrack::C1Pt21Pt2); + +using FwdTrack = FwdTracks::iterator; +using FwdTrackCovFwd = FwdTracksCov::iterator; -DECLARE_SOA_TABLE(UnassignedTracks, "AOD", "UNASSIGNEDTRACK", - unassignedtracks::CollisionId, unassignedtracks::TrackId); +} // namespace aod +namespace soa +{ +extern template struct Join<aod::FwdTracks, aod::FwdTracksCov>; +} +namespace aod +{ +using FullFwdTracks = soa::Join<FwdTracks, FwdTracksCov>; +using FullFwdTrack = FullFwdTracks::iterator; + +// Some tracks cannot be uniquely identified with a collision. Some tracks cannot be assigned to a collision at all. +// Those tracks have -1 as collision index and have an entry in the AmbiguousTracks table. +// The estimated track time is used to assign BCs which are compatible with this track. Those are stored as a slice. +// All collisions compatible with these BCs may then have produced the ambiguous track. +// In the future possibly the DCA information can be exploited to reduce the possible collisions and then this table will be extended. +namespace ambiguous +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index +DECLARE_SOA_INDEX_COLUMN(MFTTrack, mfttrack); //! MFTTrack index +DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index +DECLARE_SOA_SLICE_INDEX_COLUMN(BC, bc); //! BC index (slice for 1 to N entries) +} // namespace ambiguous -using UnassignedTrack = UnassignedTracks::iterator; +DECLARE_SOA_TABLE(AmbiguousTracks, "AOD", "AMBIGUOUSTRACK", //! Table for tracks which are not uniquely associated with a collision + ambiguous::TrackId, ambiguous::BCIdSlice); + +using AmbiguousTrack = AmbiguousTracks::iterator; + +DECLARE_SOA_TABLE(AmbiguousMFTTracks, "AOD", "AMBIGUOUSMFTTR", //! Table for MFT tracks which are not uniquely associated with a collision + ambiguous::MFTTrackId, ambiguous::BCIdSlice); + +using AmbiguousMFTTrack = AmbiguousMFTTracks::iterator; + +DECLARE_SOA_TABLE(AmbiguousFwdTracks, "AOD", "AMBIGUOUSFWDTR", //! Table for Fwd tracks which are not uniquely associated with a collision + ambiguous::FwdTrackId, ambiguous::BCIdSlice); + +using AmbiguousFwdTrack = AmbiguousFwdTracks::iterator; + +// HMPID information +namespace hmpid +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index +DECLARE_SOA_COLUMN(HMPIDSignal, hmpidSignal, float); //! Signal of the HMPID +DECLARE_SOA_COLUMN(HMPIDDistance, hmpidDistance, float); //! Distance between the matched HMPID signal and the propagated track +DECLARE_SOA_COLUMN(HMPIDNPhotons, hmpidNPhotons, short); //! Number of detected photons in HMPID +DECLARE_SOA_COLUMN(HMPIDQMip, hmpidQMip, short); //! Collected charge in the HMPID +} // namespace hmpid + +DECLARE_SOA_TABLE(HMPIDs, "AOD", "HMPID", //! HMPID information + o2::soa::Index<>, + hmpid::TrackId, + hmpid::HMPIDSignal, + hmpid::HMPIDDistance, + hmpid::HMPIDNPhotons, + hmpid::HMPIDQMip); +using HMPID = HMPIDs::iterator; namespace calo { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(CellNumber, cellNumber, int16_t); -DECLARE_SOA_COLUMN(Amplitude, amplitude, float); -DECLARE_SOA_COLUMN(Time, time, float); -DECLARE_SOA_COLUMN(CellType, cellType, int8_t); -DECLARE_SOA_COLUMN(CaloType, caloType, int8_t); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(CellNumber, cellNumber, int16_t); //! +DECLARE_SOA_COLUMN(Amplitude, amplitude, float); //! +DECLARE_SOA_COLUMN(Time, time, float); //! +DECLARE_SOA_COLUMN(CellType, cellType, int8_t); //! +DECLARE_SOA_COLUMN(CaloType, caloType, int8_t); //! } // namespace calo -DECLARE_SOA_TABLE(Calos, "AOD", "CALO", calo::BCId, +DECLARE_SOA_TABLE(Calos, "AOD", "CALO", calo::BCId, //! calo::CellNumber, calo::Amplitude, calo::Time, calo::CellType, calo::CaloType); using Calo = Calos::iterator; namespace calotrigger { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(FastOrAbsId, fastOrAbsId, int32_t); -DECLARE_SOA_COLUMN(L0Amplitude, l0Amplitude, float); -DECLARE_SOA_COLUMN(L0Time, l0Time, float); -DECLARE_SOA_COLUMN(L1TimeSum, l1TimeSum, int32_t); -DECLARE_SOA_COLUMN(NL0Times, nl0Times, int8_t); -DECLARE_SOA_COLUMN(TriggerBits, triggerBits, int32_t); -DECLARE_SOA_COLUMN(CaloType, caloType, int8_t); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(FastOrAbsID, fastOrAbsID, int16_t); //! FastOR absolute ID +DECLARE_SOA_COLUMN(LnAmplitude, lnAmplitude, int16_t); //! L0 amplitude (ADC) := Peak Amplitude +DECLARE_SOA_COLUMN(TriggerBits, triggerBits, int32_t); //! Online trigger bits +DECLARE_SOA_COLUMN(CaloType, caloType, int8_t); //! Calorimeter type (-1 is undefined, 0 is PHOS, 1 is EMCAL) } // namespace calotrigger -DECLARE_SOA_TABLE(CaloTriggers, "AOD", "CALOTRIGGER", - calotrigger::BCId, calotrigger::FastOrAbsId, - calotrigger::L0Amplitude, calotrigger::L0Time, - calotrigger::L1TimeSum, calotrigger::NL0Times, +DECLARE_SOA_TABLE(CaloTriggers, "AOD", "CALOTRIGGER", //! Trigger information from the calorimeter detectors + calotrigger::BCId, calotrigger::FastOrAbsID, calotrigger::LnAmplitude, calotrigger::TriggerBits, calotrigger::CaloType); using CaloTrigger = CaloTriggers::iterator; -namespace muon -{ -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(InverseBendingMomentum, inverseBendingMomentum, float); -DECLARE_SOA_COLUMN(ThetaX, thetaX, float); -DECLARE_SOA_COLUMN(ThetaY, thetaY, float); -DECLARE_SOA_COLUMN(ZMu, zMu, float); -DECLARE_SOA_COLUMN(BendingCoor, bendingCoor, float); -DECLARE_SOA_COLUMN(NonBendingCoor, nonBendingCoor, float); -DECLARE_SOA_COLUMN(Covariances, covariances, float[15]); -DECLARE_SOA_COLUMN(Chi2, chi2, float); -DECLARE_SOA_COLUMN(Chi2MatchTrigger, chi2MatchTrigger, float); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float inverseBendingMomentum, float thetaX, float thetaY) -> float { - float pz = -std::sqrt(1.0 + std::tan(thetaY) * std::tan(thetaY)) / std::abs(inverseBendingMomentum); - float pt = std::abs(pz) * std::sqrt(std::tan(thetaX) * std::tan(thetaX) + std::tan(thetaY) * std::tan(thetaY)); - float eta = std::acos(pz / std::sqrt(pt * pt + pz * pz)); - eta = std::tan(0.5 * eta); - if (eta > 0.0) - return -std::log(eta); - else - return 0.0; -}); -DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float thetaX, float thetaY) -> float { - float phi = std::atan2(std::tan(thetaY), std::tan(thetaX)); - constexpr float twopi = 2.0f * static_cast<float>(M_PI); - return (phi >= 0.0 ? phi : phi + twopi); -}); -DECLARE_SOA_DYNAMIC_COLUMN(RAtAbsorberEnd, rAtAbsorberEnd, [](float bendingCoor, float nonBendingCoor, float zMu, float thetaX, float thetaY) -> float { - // linear extrapolation of the coordinates of the track to the position of the end of the absorber (-505 cm) - float dZ = -505. - zMu; - float NonBendingSlope = std::tan(thetaX); - float BendingSlope = std::tan(thetaY); - float xAbs = nonBendingCoor + NonBendingSlope * dZ; - float yAbs = bendingCoor + BendingSlope * dZ; - float rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); - return rAtAbsorberEnd; -}); -DECLARE_SOA_DYNAMIC_COLUMN(PDca, pDca, [](float inverseBendingMomentum, float thetaX, float thetaY, float bendingCoor, float nonBendingCoor, float zMu) -> float { - // linear extrapolation of the coordinates of the track to the position of the end of the absorber (-505 cm) - float dca = std::sqrt(bendingCoor * bendingCoor + nonBendingCoor * nonBendingCoor + zMu * zMu); - float pz = -std::sqrt(1.0 + std::tan(thetaY) * std::tan(thetaY)) / std::abs(inverseBendingMomentum); - float pt = std::abs(pz) * std::sqrt(std::tan(thetaX) * std::tan(thetaX) + std::tan(thetaY) * std::tan(thetaY)); - float pTot = std::sqrt(pt * pt + pz * pz); - float pDca = pTot * dca; - return pDca; -}); -DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, nsqrt(1.0f + ntan(aod::muon::thetaY) * ntan(aod::muon::thetaY)) * nsqrt(ntan(aod::muon::thetaX) * ntan(aod::muon::thetaX) + ntan(aod::muon::thetaY) * ntan(aod::muon::thetaY)) / nabs(aod::muon::inverseBendingMomentum)); -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, float, -1.0f * ntan(aod::muon::thetaX) * nsqrt(1.0f + ntan(aod::muon::thetaY) * ntan(aod::muon::thetaY)) / nabs(aod::muon::inverseBendingMomentum)); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, float, -1.0f * ntan(aod::muon::thetaY) * nsqrt(1.0f + ntan(aod::muon::thetaY) * ntan(aod::muon::thetaY)) / nabs(aod::muon::inverseBendingMomentum)); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, float, -1.0f * nsqrt(1.0f + ntan(aod::muon::thetaY) * ntan(aod::muon::thetaY)) / nabs(aod::muon::inverseBendingMomentum)); -DECLARE_SOA_DYNAMIC_COLUMN(Charge, charge, [](float inverseBendingMomentum) -> short { return (inverseBendingMomentum > 0.0f) ? 1 : -1; }); -} // namespace muon - -DECLARE_SOA_TABLE_FULL(StoredMuons, "Muons", "AOD", "MUON", - muon::BCId, muon::InverseBendingMomentum, - muon::ThetaX, muon::ThetaY, muon::ZMu, - muon::BendingCoor, muon::NonBendingCoor, - muon::Covariances, muon::Chi2, muon::Chi2MatchTrigger, - muon::Eta<muon::InverseBendingMomentum, muon::ThetaX, muon::ThetaY>, - muon::Phi<muon::ThetaX, muon::ThetaY>, - muon::RAtAbsorberEnd<muon::BendingCoor, muon::NonBendingCoor, muon::ThetaX, muon::ThetaY, muon::ZMu>, - muon::PDca<muon::InverseBendingMomentum, muon::ThetaX, muon::ThetaY, muon::BendingCoor, muon::NonBendingCoor, muon::ZMu>, - muon::Charge<muon::InverseBendingMomentum>); - -DECLARE_SOA_EXTENDED_TABLE(Muons, StoredMuons, "MUON", - aod::muon::Pt, - aod::muon::Px, - aod::muon::Py, - aod::muon::Pz); - -using Muon = Muons::iterator; - -// NOTE for now muon tracks are uniquely assigned to a BC / GlobalBC assuming they contain an MID hit. Discussion on tracks without MID hit is ongoing. - -namespace muoncluster -{ -DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Muons, "fMuonsID"); // points to a muon track in the Muon table -DECLARE_SOA_COLUMN(X, x, float); -DECLARE_SOA_COLUMN(Y, y, float); -DECLARE_SOA_COLUMN(Z, z, float); -DECLARE_SOA_COLUMN(ErrX, errX, float); -DECLARE_SOA_COLUMN(ErrY, errY, float); -DECLARE_SOA_COLUMN(Charge, charge, float); -DECLARE_SOA_COLUMN(Chi2, chi2, float); -} // namespace muoncluster - -DECLARE_SOA_TABLE(MuonClusters, "AOD", "MUONCLUSTER", - muoncluster::TrackId, - muoncluster::X, muoncluster::Y, muoncluster::Z, - muoncluster::ErrX, muoncluster::ErrY, - muoncluster::Charge, muoncluster::Chi2); - -using MuonCluster = MuonClusters::iterator; - namespace zdc { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(EnergyZEM1, energyZEM1, float); -DECLARE_SOA_COLUMN(EnergyZEM2, energyZEM2, float); -DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); -DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); -DECLARE_SOA_COLUMN(EnergyCommonZPA, energyCommonZPA, float); -DECLARE_SOA_COLUMN(EnergyCommonZPC, energyCommonZPC, float); -DECLARE_SOA_COLUMN(EnergySectorZNA, energySectorZNA, float[4]); -DECLARE_SOA_COLUMN(EnergySectorZNC, energySectorZNC, float[4]); -DECLARE_SOA_COLUMN(EnergySectorZPA, energySectorZPA, float[4]); -DECLARE_SOA_COLUMN(EnergySectorZPC, energySectorZPC, float[4]); -DECLARE_SOA_COLUMN(TimeZEM1, timeZEM1, float); -DECLARE_SOA_COLUMN(TimeZEM2, timeZEM2, float); -DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); -DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); -DECLARE_SOA_COLUMN(TimeZPA, timeZPA, float); -DECLARE_SOA_COLUMN(TimeZPC, timeZPC, float); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(EnergyZEM1, energyZEM1, float); //! +DECLARE_SOA_COLUMN(EnergyZEM2, energyZEM2, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZPA, energyCommonZPA, float); //! +DECLARE_SOA_COLUMN(EnergyCommonZPC, energyCommonZPC, float); //! +DECLARE_SOA_COLUMN(EnergySectorZNA, energySectorZNA, float[4]); //! +DECLARE_SOA_COLUMN(EnergySectorZNC, energySectorZNC, float[4]); //! +DECLARE_SOA_COLUMN(EnergySectorZPA, energySectorZPA, float[4]); //! +DECLARE_SOA_COLUMN(EnergySectorZPC, energySectorZPC, float[4]); //! +DECLARE_SOA_COLUMN(TimeZEM1, timeZEM1, float); //! +DECLARE_SOA_COLUMN(TimeZEM2, timeZEM2, float); //! +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); //! +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); //! +DECLARE_SOA_COLUMN(TimeZPA, timeZPA, float); //! +DECLARE_SOA_COLUMN(TimeZPC, timeZPC, float); //! } // namespace zdc -DECLARE_SOA_TABLE(Zdcs, "AOD", "ZDC", o2::soa::Index<>, zdc::BCId, zdc::EnergyZEM1, zdc::EnergyZEM2, +DECLARE_SOA_TABLE(Zdcs, "AOD", "ZDC", //! ZDC information + o2::soa::Index<>, zdc::BCId, zdc::EnergyZEM1, zdc::EnergyZEM2, zdc::EnergyCommonZNA, zdc::EnergyCommonZNC, zdc::EnergyCommonZPA, zdc::EnergyCommonZPC, zdc::EnergySectorZNA, zdc::EnergySectorZNC, zdc::EnergySectorZPA, zdc::EnergySectorZPC, zdc::TimeZEM1, zdc::TimeZEM2, zdc::TimeZNA, zdc::TimeZNC, zdc::TimeZPA, zdc::TimeZPC); @@ -433,200 +636,324 @@ using Zdc = Zdcs::iterator; namespace fv0a { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(Amplitude, amplitude, float[48]); -DECLARE_SOA_COLUMN(Time, time, float); -DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(Amplitude, amplitude, float[48]); //! Amplitudes per cell +DECLARE_SOA_COLUMN(Time, time, float); //! Time in ns +DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); //! } // namespace fv0a -DECLARE_SOA_TABLE(FV0As, "AOD", "FV0A", o2::soa::Index<>, fv0a::BCId, fv0a::Amplitude, fv0a::Time, fv0a::TriggerMask); +DECLARE_SOA_TABLE(FV0As, "AOD", "FV0A", //! + o2::soa::Index<>, fv0a::BCId, fv0a::Amplitude, fv0a::Time, fv0a::TriggerMask); using FV0A = FV0As::iterator; // V0C table for Run2 only namespace fv0c { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(Amplitude, amplitude, float[32]); -DECLARE_SOA_COLUMN(Time, time, float); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(Amplitude, amplitude, float[32]); //! Amplitudes per cell +DECLARE_SOA_COLUMN(Time, time, float); //! Time in ns } // namespace fv0c -DECLARE_SOA_TABLE(FV0Cs, "AOD", "FV0C", o2::soa::Index<>, fv0c::BCId, fv0c::Amplitude, fv0c::Time); +DECLARE_SOA_TABLE(FV0Cs, "AOD", "FV0C", //! Only for RUN 2 converted data: V0C table + o2::soa::Index<>, fv0c::BCId, fv0c::Amplitude, fv0c::Time); using FV0C = FV0Cs::iterator; namespace ft0 { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, float[96]); -DECLARE_SOA_COLUMN(AmplitudeC, amplitudeC, float[112]); -DECLARE_SOA_COLUMN(TimeA, timeA, float); -DECLARE_SOA_COLUMN(TimeC, timeC, float); -DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, float[96]); //! +DECLARE_SOA_COLUMN(AmplitudeC, amplitudeC, float[112]); //! +DECLARE_SOA_COLUMN(TimeA, timeA, float); //! +DECLARE_SOA_COLUMN(TimeC, timeC, float); //! +DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); //! } // namespace ft0 -DECLARE_SOA_TABLE(FT0s, "AOD", "FT0", o2::soa::Index<>, ft0::BCId, +DECLARE_SOA_TABLE(FT0s, "AOD", "FT0", //! + o2::soa::Index<>, ft0::BCId, ft0::AmplitudeA, ft0::AmplitudeC, ft0::TimeA, ft0::TimeC, ft0::TriggerMask); using FT0 = FT0s::iterator; namespace fdd { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, float[4]); -DECLARE_SOA_COLUMN(AmplitudeC, amplitudeC, float[4]); -DECLARE_SOA_COLUMN(TimeA, timeA, float); -DECLARE_SOA_COLUMN(TimeC, timeC, float); -DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, float[4]); //! +DECLARE_SOA_COLUMN(AmplitudeC, amplitudeC, float[4]); //! +DECLARE_SOA_COLUMN(TimeA, timeA, float); //! +DECLARE_SOA_COLUMN(TimeC, timeC, float); //! +DECLARE_SOA_COLUMN(TriggerMask, triggerMask, uint8_t); //! } // namespace fdd -DECLARE_SOA_TABLE(FDDs, "AOD", "FDD", o2::soa::Index<>, fdd::BCId, - fdd::AmplitudeA, fdd::AmplitudeC, fdd::TimeA, fdd::TimeC, +DECLARE_SOA_TABLE(FDDs, "AOD", "FDD", //! + o2::soa::Index<>, fdd::BCId, + fdd::AmplitudeA, fdd::AmplitudeC, + fdd::TimeA, fdd::TimeC, fdd::TriggerMask); using FDD = FDDs::iterator; namespace v0 { -DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, FullTracks, "fPosTrackID"); -DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, FullTracks, "fNegTrackID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, Tracks, "_Pos"); //! Positive track +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, Tracks, "_Neg"); //! Negative track +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index } // namespace v0 -DECLARE_SOA_TABLE(StoredV0s, "AOD", "V0", o2::soa::Index<>, v0::PosTrackId, v0::NegTrackId); -DECLARE_SOA_TABLE(TransientV0s, "AOD", "V0INDEX", v0::CollisionId); +DECLARE_SOA_TABLE(StoredV0s, "AOD", "V0", //! On disk V0 table + o2::soa::Index<>, + v0::PosTrackId, v0::NegTrackId); +DECLARE_SOA_TABLE(TransientV0s, "AOD", "V0INDEX", //! In-memory V0 table + v0::CollisionId); +} // namespace aod +namespace soa +{ +extern template struct Join<aod::TransientV0s, aod::StoredV0s>; +} +namespace aod +{ using V0s = soa::Join<TransientV0s, StoredV0s>; using V0 = V0s::iterator; namespace cascade { -DECLARE_SOA_INDEX_COLUMN(V0, v0); -DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int, FullTracks, "fTracksID"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_INDEX_COLUMN(V0, v0); //! V0 index +DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int, Tracks, ""); //! Bachelor track index +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index } // namespace cascade -DECLARE_SOA_TABLE(StoredCascades, "AOD", "CASCADE", o2::soa::Index<>, cascade::V0Id, cascade::BachelorId); -DECLARE_SOA_TABLE(TransientCascades, "AOD", "CASCADEINDEX", cascade::CollisionId); +DECLARE_SOA_TABLE(StoredCascades, "AOD", "CASCADE", //! On disk cascade table + o2::soa::Index<>, cascade::V0Id, cascade::BachelorId); +DECLARE_SOA_TABLE(TransientCascades, "AOD", "CASCADEINDEX", //! In-memory cascade table + cascade::CollisionId); +} // namespace aod +namespace soa +{ +extern template struct Join<aod::TransientCascades, aod::StoredCascades>; +} +namespace aod +{ using Cascades = soa::Join<TransientCascades, StoredCascades>; using Cascade = Cascades::iterator; -// ---- MC tables ---- +// ---- Run 2 tables ---- +namespace run2 +{ +DECLARE_SOA_COLUMN(EventCuts, eventCuts, uint32_t); //! Event selection flags. Check enum Run2EventSelectionCut +DECLARE_SOA_COLUMN(TriggerMaskNext50, triggerMaskNext50, uint64_t); //! 50 further trigger classes after bc.triggerMask() +DECLARE_SOA_COLUMN(L0TriggerInputMask, l0TriggerInputMask, uint32_t); //! CTP L0 trigger input mask +DECLARE_SOA_COLUMN(SPDClustersL0, spdClustersL0, uint16_t); //! Number of clusters in the first layer of the SPD +DECLARE_SOA_COLUMN(SPDClustersL1, spdClustersL1, uint16_t); //! Number of clusters in the second layer of the SPD +DECLARE_SOA_COLUMN(SPDFiredChipsL0, spdFiredChipsL0, uint16_t); //! Fired chips in the first layer of the SPD (offline) +DECLARE_SOA_COLUMN(SPDFiredChipsL1, spdFiredChipsL1, uint16_t); //! Fired chips in the second layer of the SPD (offline) +DECLARE_SOA_COLUMN(SPDFiredFastOrL0, spdFiredFastOrL0, uint16_t); //! Fired FASTOR signals in the first layer of the SPD (online) +DECLARE_SOA_COLUMN(SPDFiredFastOrL1, spdFiredFastOrL1, uint16_t); //! Fired FASTOR signals in the first layer of the SPD (online) +DECLARE_SOA_COLUMN(V0TriggerChargeA, v0TriggerChargeA, uint16_t); //! V0A trigger charge +DECLARE_SOA_COLUMN(V0TriggerChargeC, v0TriggerChargeC, uint16_t); //! V0C trigger charge +} // namespace run2 + +DECLARE_SOA_TABLE(Run2BCInfos, "AOD", "RUN2BCINFO", run2::EventCuts, //! Legacy information for Run 2 event selection + run2::TriggerMaskNext50, run2::L0TriggerInputMask, + run2::SPDClustersL0, run2::SPDClustersL1, + run2::SPDFiredChipsL0, run2::SPDFiredChipsL1, + run2::SPDFiredFastOrL0, run2::SPDFiredFastOrL1, + run2::V0TriggerChargeA, run2::V0TriggerChargeC); +using Run2BCInfo = Run2BCInfos::iterator; +// ---- MC tables ---- namespace mccollision { -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_COLUMN(GeneratorsID, generatorsID, short); -DECLARE_SOA_COLUMN(PosX, posX, float); -DECLARE_SOA_COLUMN(PosY, posY, float); -DECLARE_SOA_COLUMN(PosZ, posZ, float); -DECLARE_SOA_COLUMN(T, t, float); -DECLARE_SOA_COLUMN(Weight, weight, float); -DECLARE_SOA_COLUMN(ImpactParameter, impactParameter, float); +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +// TODO enum to be added to O2 +DECLARE_SOA_COLUMN(GeneratorsID, generatorsID, short); //! +DECLARE_SOA_COLUMN(PosX, posX, float); //! X vertex position in cm +DECLARE_SOA_COLUMN(PosY, posY, float); //! Y vertex position in cm +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! Z vertex position in cm +DECLARE_SOA_COLUMN(T, t, float); //! Collision time relative to given bc in ns +DECLARE_SOA_COLUMN(Weight, weight, float); //! MC weight +DECLARE_SOA_COLUMN(ImpactParameter, impactParameter, float); //! Impact parameter for A-A } // namespace mccollision -DECLARE_SOA_TABLE(McCollisions, "AOD", "MCCOLLISION", o2::soa::Index<>, mccollision::BCId, +DECLARE_SOA_TABLE(McCollisions, "AOD", "MCCOLLISION", //! MC collision table + o2::soa::Index<>, mccollision::BCId, mccollision::GeneratorsID, - mccollision::PosX, mccollision::PosY, mccollision::PosZ, mccollision::T, mccollision::Weight, + mccollision::PosX, mccollision::PosY, mccollision::PosZ, + mccollision::T, mccollision::Weight, mccollision::ImpactParameter); using McCollision = McCollisions::iterator; namespace mcparticle { -DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); -DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); -DECLARE_SOA_COLUMN(StatusCode, statusCode, int); -DECLARE_SOA_COLUMN(Flags, flags, uint8_t); -DECLARE_SOA_COLUMN(Mother0, mother0, int); -DECLARE_SOA_COLUMN(Mother1, mother1, int); -DECLARE_SOA_COLUMN(Daughter0, daughter0, int); -DECLARE_SOA_COLUMN(Daughter1, daughter1, int); -DECLARE_SOA_COLUMN(Weight, weight, float); -DECLARE_SOA_COLUMN(Px, px, float); -DECLARE_SOA_COLUMN(Py, py, float); -DECLARE_SOA_COLUMN(Pz, pz, float); -DECLARE_SOA_COLUMN(E, e, float); -DECLARE_SOA_COLUMN(Vx, vx, float); -DECLARE_SOA_COLUMN(Vy, vy, float); -DECLARE_SOA_COLUMN(Vz, vz, float); -DECLARE_SOA_COLUMN(Vt, vt, float); -DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return static_cast<float>(M_PI) + std::atan2(-py, -px); }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { return 0.5f * std::log((std::sqrt(px * px + py * py + pz * pz) + pz) / (std::sqrt(px * px + py * py + pz * pz) - pz)); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return std::sqrt(px * px + py * py); }); -DECLARE_SOA_DYNAMIC_COLUMN(ProducedByGenerator, producedByGenerator, [](uint8_t flags) -> bool { return (flags & 0x1) == 0x0; }); +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! MC collision of this particle +DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); //! PDG code +DECLARE_SOA_COLUMN(StatusCode, statusCode, int); //! Status code directly from the generator +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); //! ALICE specific flags. Do not use directly. Use the dynamic columns, e.g. producedByGenerator() +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother0, mother0, int, "McParticles_Mother0"); //! Track index of the first mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother1, mother1, int, "McParticles_Mother1"); //! Track index of the last mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter0, daughter0, int, "McParticles_Daughter0"); //! Track index of the first daugther +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter1, daughter1, int, "McParticles_Daughter1"); //! Track index of the last daugther +DECLARE_SOA_COLUMN(Weight, weight, float); //! MC weight +DECLARE_SOA_COLUMN(Px, px, float); //! Momentum in x in GeV/c +DECLARE_SOA_COLUMN(Py, py, float); //! Momentum in y in GeV/c +DECLARE_SOA_COLUMN(Pz, pz, float); //! Momentum in z in GeV/c +DECLARE_SOA_COLUMN(E, e, float); //! Energy +DECLARE_SOA_COLUMN(Vx, vx, float); //! X production vertex in cm +DECLARE_SOA_COLUMN(Vy, vy, float); //! Y production vertex in cm +DECLARE_SOA_COLUMN(Vz, vz, float); //! Z production vertex in cm +DECLARE_SOA_COLUMN(Vt, vt, float); //! Production time +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! Phi + [](float px, float py) -> float { return static_cast<float>(M_PI) + std::atan2(-py, -px); }); +DECLARE_SOA_DYNAMIC_COLUMN(ProducedByGenerator, producedByGenerator, //! Particle produced by the generator or by the transport code + [](uint8_t flags) -> bool { return (flags & 0x1) == 0x0; }); + +// DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi: NOTE this waits that the atan2 function is defined for expression columns +// static_cast<float>(M_PI) + natan2(-aod::mcparticle::py, -aod::mcparticle::px)); +DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity, conditionally defined to avoid FPEs + ifnode((nsqrt(aod::mcparticle::px * aod::mcparticle::px + + aod::mcparticle::py * aod::mcparticle::py + + aod::mcparticle::pz * aod::mcparticle::pz) - + aod::mcparticle::pz) < static_cast<float>(1e-7), + ifnode(aod::mcparticle::pz < 0.f, -100.f, 100.f), + 0.5f * nlog((nsqrt(aod::mcparticle::px * aod::mcparticle::px + + aod::mcparticle::py * aod::mcparticle::py + + aod::mcparticle::pz * aod::mcparticle::pz) + + aod::mcparticle::pz) / + (nsqrt(aod::mcparticle::px * aod::mcparticle::px + + aod::mcparticle::py * aod::mcparticle::py + + aod::mcparticle::pz * aod::mcparticle::pz) - + aod::mcparticle::pz)))); +DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! Transverse momentum in GeV/c + nsqrt(aod::mcparticle::px* aod::mcparticle::px + + aod::mcparticle::py * aod::mcparticle::py)); +DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Total momentum in GeV/c + nsqrt(aod::mcparticle::px* aod::mcparticle::px + + aod::mcparticle::py * aod::mcparticle::py + + aod::mcparticle::pz * aod::mcparticle::pz)); +DECLARE_SOA_EXPRESSION_COLUMN(Y, y, float, //! Particle rapidity, conditionally defined to avoid FPEs + ifnode((aod::mcparticle::e - aod::mcparticle::pz) < static_cast<float>(1e-7), + ifnode(aod::mcparticle::pz < 0.f, -100.f, 100.f), + 0.5f * nlog((aod::mcparticle::e + aod::mcparticle::pz) / + (aod::mcparticle::e - aod::mcparticle::pz)))); } // namespace mcparticle -DECLARE_SOA_TABLE(McParticles, "AOD", "MCPARTICLE", - o2::soa::Index<>, mcparticle::McCollisionId, - mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, - mcparticle::Mother0, mcparticle::Mother1, mcparticle::Daughter0, mcparticle::Daughter1, mcparticle::Weight, - mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, - mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, - mcparticle::Phi<mcparticle::Px, mcparticle::Py>, - mcparticle::Eta<mcparticle::Px, mcparticle::Py, mcparticle::Pz>, - mcparticle::Pt<mcparticle::Px, mcparticle::Py>, - mcparticle::ProducedByGenerator<mcparticle::Flags>); +DECLARE_SOA_TABLE_FULL(StoredMcParticles, "McParticles", "AOD", "MCPARTICLE", //! On disk version of the MC particle table + o2::soa::Index<>, mcparticle::McCollisionId, + mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, + mcparticle::Mother0Id, mcparticle::Mother1Id, + mcparticle::Daughter0Id, mcparticle::Daughter1Id, mcparticle::Weight, + mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, + mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + mcparticle::Phi<mcparticle::Px, mcparticle::Py>, + // mcparticle::Eta<mcparticle::Px, mcparticle::Py, mcparticle::Pz>, + mcparticle::ProducedByGenerator<mcparticle::Flags>); + +DECLARE_SOA_EXTENDED_TABLE(McParticles, StoredMcParticles, "MCPARTICLE", //! Basic MC particle properties + // mcparticle::Phi, + mcparticle::Eta, + mcparticle::Pt, + mcparticle::P, + mcparticle::Y); + using McParticle = McParticles::iterator; namespace mctracklabel { -DECLARE_SOA_INDEX_COLUMN_FULL(Label, label, uint32_t, McParticles, "fLabel"); -DECLARE_SOA_COLUMN(LabelMask, labelMask, uint16_t); -/// Bit mask to indicate detector mismatches (bit ON means mismatch) -/// Bit 0-6: mismatch at ITS layer -/// Bit 7-9: # of TPC mismatches in the ranges 0, 1, 2-3, 4-7, 8-15, 16-31, 32-63, >64 -/// Bit 10: TRD, bit 11: TOF, bit 15: indicates negative label +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate detector mismatches (bit ON means mismatch). Bit 0-6: mismatch at ITS layer. Bit 7-9: # of TPC mismatches in the ranges 0, 1, 2-3, 4-7, 8-15, 16-31, 32-63, >64. Bit 10: TRD, bit 11: TOF, bit 15: indicates negative label } // namespace mctracklabel -DECLARE_SOA_TABLE(McTrackLabels, "AOD", "MCTRACKLABEL", - mctracklabel::LabelId, mctracklabel::LabelMask); +DECLARE_SOA_TABLE(McTrackLabels, "AOD", "MCTRACKLABEL", //! Table joined to the track table containing the MC index + mctracklabel::McParticleId, mctracklabel::McMask); using McTrackLabel = McTrackLabels::iterator; +namespace mcmfttracklabel +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle +DECLARE_SOA_COLUMN(McMask, mcMask, uint8_t); +} // namespace mcmfttracklabel + +DECLARE_SOA_TABLE(McMFTTrackLabels, "AOD", "MCMFTTRACKLABEL", //! Table joined to the mft track table containing the MC index + mcmfttracklabel::McParticleId, mcmfttracklabel::McMask); +using McMFTTrackLabel = McMFTTrackLabels::iterator; + +namespace mcfwdtracklabel +{ +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle +DECLARE_SOA_COLUMN(McMask, mcMask, uint8_t); +} // namespace mcfwdtracklabel + +DECLARE_SOA_TABLE(McFwdTrackLabels, "AOD", "MCFWDTRACKLABEL", //! Table joined to the mft track table containing the MC index + mcfwdtracklabel::McParticleId, mcfwdtracklabel::McMask); +using McFwdTrackLabel = McFwdTrackLabels::iterator; + namespace mccalolabel { -DECLARE_SOA_INDEX_COLUMN_FULL(Label, label, uint32_t, McParticles, "fLabel"); -DECLARE_SOA_COLUMN(LabelMask, labelMask, uint16_t); -/// Bit mask to indicate detector mismatches (bit ON means mismatch) -/// Bit 15: indicates negative label +DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate detector mismatches (bit ON means mismatch). Bit 15: indicates negative label } // namespace mccalolabel -DECLARE_SOA_TABLE(McCaloLabels, "AOD", "MCCALOLABEL", - mccalolabel::LabelId, mccalolabel::LabelMask); +DECLARE_SOA_TABLE(McCaloLabels, "AOD", "MCCALOLABEL", //! Table joined to the calo table containing the MC index + mccalolabel::McParticleId, mccalolabel::McMask); using McCaloLabel = McCaloLabels::iterator; namespace mccollisionlabel { -DECLARE_SOA_INDEX_COLUMN_FULL(Label, label, uint32_t, McCollisions, "fLabel"); -DECLARE_SOA_COLUMN(LabelMask, labelMask, uint16_t); -/// Bit mask to indicate collision mismatches (bit ON means mismatch) -/// Bit 15: indicates negative label +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! MC collision +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label } // namespace mccollisionlabel -DECLARE_SOA_TABLE(McCollisionLabels, "AOD", "MCCOLLISLABEL", - mccollisionlabel::LabelId, mccollisionlabel::LabelMask); +DECLARE_SOA_TABLE(McCollisionLabels, "AOD", "MCCOLLISLABEL", //! Table joined to the collision table containing the MC index + mccollisionlabel::McCollisionId, mccollisionlabel::McMask); using McCollisionLabel = McCollisionLabels::iterator; // --- Matching between collisions and other tables through BC --- namespace indices { -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -DECLARE_SOA_INDEX_COLUMN(BC, bc); -DECLARE_SOA_INDEX_COLUMN(Zdc, zdc); -DECLARE_SOA_INDEX_COLUMN(FV0A, fv0a); -DECLARE_SOA_INDEX_COLUMN(FV0C, fv0c); -DECLARE_SOA_INDEX_COLUMN(FT0, ft0); -DECLARE_SOA_INDEX_COLUMN(FDD, fdd); +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! +DECLARE_SOA_INDEX_COLUMN(Zdc, zdc); //! +DECLARE_SOA_INDEX_COLUMN(FV0A, fv0a); //! +DECLARE_SOA_INDEX_COLUMN(FV0C, fv0c); //! +DECLARE_SOA_INDEX_COLUMN(FT0, ft0); //! +DECLARE_SOA_INDEX_COLUMN(FDD, fdd); //! } // namespace indices +// First entry: Collision #define INDEX_LIST_RUN2 indices::CollisionId, indices::ZdcId, indices::BCId, indices::FT0Id, indices::FV0AId, indices::FV0CId, indices::FDDId -DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(Run2MatchedExclusive, BCs, "MA_RN2_EX", INDEX_LIST_RUN2); -DECLARE_SOA_INDEX_TABLE(Run2MatchedSparse, BCs, "MA_RN2_SP", INDEX_LIST_RUN2); +DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(Run2MatchedExclusive, BCs, "MA_RN2_EX", INDEX_LIST_RUN2); //! +DECLARE_SOA_INDEX_TABLE(Run2MatchedSparse, BCs, "MA_RN2_SP", INDEX_LIST_RUN2); //! #define INDEX_LIST_RUN3 indices::CollisionId, indices::ZdcId, indices::BCId, indices::FT0Id, indices::FV0AId, indices::FDDId -DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(Run3MatchedExclusive, BCs, "MA_RN3_EX", INDEX_LIST_RUN3); -DECLARE_SOA_INDEX_TABLE(Run3MatchedSparse, BCs, "MA_RN3_SP", INDEX_LIST_RUN3); +DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(Run3MatchedExclusive, BCs, "MA_RN3_EX", INDEX_LIST_RUN3); //! +DECLARE_SOA_INDEX_TABLE(Run3MatchedSparse, BCs, "MA_RN3_SP", INDEX_LIST_RUN3); //! + +// First entry: BC +DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(MatchedBCCollisionsExclusive, BCs, "MA_BCCOL_EX", //! + indices::BCId, indices::CollisionId); +DECLARE_SOA_INDEX_TABLE(MatchedBCCollisionsSparse, BCs, "MA_BCCOL_SP", //! + indices::BCId, indices::CollisionId); + +DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(Run3MatchedToBCExclusive, BCs, "MA_RN3_BC_EX", //! + indices::BCId, indices::ZdcId, indices::FT0Id, indices::FV0AId, indices::FDDId); +DECLARE_SOA_INDEX_TABLE(Run3MatchedToBCSparse, BCs, "MA_RN3_BC_SP", //! + indices::BCId, indices::ZdcId, indices::FT0Id, indices::FV0AId, indices::FDDId); + +DECLARE_SOA_INDEX_TABLE(Run2MatchedToBCSparse, BCs, "MA_RN2_BC_SP", //! + indices::BCId, indices::ZdcId, indices::FT0Id, indices::FV0AId, indices::FV0CId, indices::FDDId); -DECLARE_SOA_INDEX_TABLE_EXCLUSIVE(BCCollisionsExclusive, BCs, "MA_BCCOL_EX", indices::BCId, indices::CollisionId); -DECLARE_SOA_INDEX_TABLE(BCCollisionsSparse, BCs, "MA_BCCOL_SP", indices::BCId, indices::CollisionId); +// Joins with collisions (only for sparse ones) +// NOTE: index table needs to be always last argument +} // namespace aod +namespace soa +{ +extern template struct Join<aod::Collisions, aod::Run2MatchedSparse>; +extern template struct Join<aod::Collisions, aod::Run3MatchedSparse>; +} // namespace soa +namespace aod +{ +using CollisionMatchedRun2Sparse = soa::Join<Collisions, Run2MatchedSparse>::iterator; +using CollisionMatchedRun3Sparse = soa::Join<Collisions, Run3MatchedSparse>::iterator; } // namespace aod diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 0745170ebf804..20901f7f45c40 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,8 +20,8 @@ #include "Framework/OutputObjHeader.h" #include "Framework/StringHelpers.h" #include "Framework/Output.h" -#include <ROOT/RDataFrame.hxx> #include <string> +#include "Framework/Logger.h" namespace o2::framework { @@ -60,6 +61,11 @@ struct WritingCursor<soa::Table<PC...>> { return true; } + void setLabel(const char* label) + { + mBuilder->setLabel(label); + } + /// reserve @a size rows when filling, so that we do not /// spend time reallocating the buffers. void reserve(int64_t size) @@ -117,7 +123,8 @@ struct Produces<soa::Table<C...>> : WritingCursor<typename soa::PackToTable<type /// Helper template for table transformations template <typename METADATA> struct TableTransform { - using SOURCES = typename METADATA::originals; + using SOURCES = typename METADATA::sources; + using ORIGINALS = typename METADATA::originals; using metadata = METADATA; using sources = SOURCES; @@ -127,6 +134,11 @@ struct TableTransform { return SOURCES{}; } + constexpr auto originals_pack() const + { + return ORIGINALS{}; + } + template <typename Oi> constexpr auto base_spec() const { @@ -199,7 +211,7 @@ struct Spawns : TableTransform<typename aod::MetadataTrait<framework::pack_head_ struct IndexExclusive { /// Generic builder for in index table template <typename... Cs, typename Key, typename T1, typename... T> - static auto indexBuilder(framework::pack<Cs...>, Key const&, std::tuple<T1, T...> tables) + static auto indexBuilder(const char* label, framework::pack<Cs...>, Key const&, std::tuple<T1, T...> tables) { static_assert(sizeof...(Cs) == sizeof...(T) + 1, "Number of columns does not coincide with number of supplied tables"); using tables_t = framework::pack<T...>; @@ -257,6 +269,7 @@ struct IndexExclusive { cursor(0, row.globalIndex(), values[framework::has_type_at_v<T>(tables_t{})]...); } } + builder.setLabel(label); return builder.finalize(); } }; @@ -264,7 +277,7 @@ struct IndexExclusive { /// to T1 struct IndexSparse { template <typename... Cs, typename Key, typename T1, typename... T> - static auto indexBuilder(framework::pack<Cs...>, Key const&, std::tuple<T1, T...> tables) + static auto indexBuilder(const char* label, framework::pack<Cs...>, Key const&, std::tuple<T1, T...> tables) { static_assert(sizeof...(Cs) == sizeof...(T) + 1, "Number of columns does not coincide with number of supplied tables"); using tables_t = framework::pack<T...>; @@ -283,36 +296,46 @@ struct IndexSparse { using rest_it_t = decltype(pack_from_tuple(iterators)); - int32_t idx = -1; - auto setValue = [&](auto& x) -> bool { + auto setValue = [&](auto& x, int idx) -> bool { using type = std::decay_t<decltype(x)>; constexpr auto position = framework::has_type_at_v<type>(rest_it_t{}); - lowerBound<Key>(idx, x); - if (x == soa::RowViewSentinel{static_cast<uint64_t>(x.mMaxRow)}) { - values[position] = -1; - return false; - } else if (x.template getId<Key>() != idx) { - values[position] = -1; - return false; - } else { - values[position] = x.globalIndex(); - ++x; + if constexpr (std::is_same_v<framework::pack_element_t<position, framework::pack<std::decay_t<T>...>>, Key>) { + values[position] = idx; return true; + } else { + lowerBound<Key>(idx, x); + if (x == soa::RowViewSentinel{static_cast<uint64_t>(x.mMaxRow)}) { + values[position] = -1; + return false; + } else if (x.template getId<Key>() != idx) { + values[position] = -1; + return false; + } else { + values[position] = x.globalIndex(); + ++x; + return true; + } } }; auto first = std::get<first_t>(tables); for (auto& row : first) { - idx = row.template getId<Key>(); + auto idx = -1; + if constexpr (std::is_same_v<first_t, Key>) { + idx = row.globalIndex(); + } else { + idx = row.template getId<Key>(); + } std::apply( [&](auto&... x) { - (setValue(x), ...); + (setValue(x, idx), ...); }, iterators); cursor(0, row.globalIndex(), values[framework::has_type_at_v<T>(tables_t{})]...); } + builder.setLabel(label); return builder.finalize(); } }; @@ -348,7 +371,7 @@ struct Builds : TableTransform<typename aod::MetadataTrait<T>::metadata> { template <typename... Cs, typename Key, typename T1, typename... Ts> auto build(framework::pack<Cs...>, Key const& key, std::tuple<T1, Ts...> tables) { - this->table = std::make_shared<T>(IP::indexBuilder(framework::pack<Cs...>{}, key, tables)); + this->table = std::make_shared<T>(IP::indexBuilder(aod::MetadataTrait<T>::metadata::tableLabel(), framework::pack<Cs...>{}, key, tables)); return (this->table != nullptr); } }; @@ -367,18 +390,20 @@ template <typename T> struct OutputObj { using obj_t = T; - OutputObj(T&& t, OutputObjHandlingPolicy policy_ = OutputObjHandlingPolicy::AnalysisObject) + OutputObj(T&& t, OutputObjHandlingPolicy policy_ = OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType sourceType_ = OutputObjSourceType::OutputObjSource) : object(std::make_shared<T>(t)), label(t.GetName()), policy{policy_}, + sourceType{sourceType_}, mTaskHash{0} { } - OutputObj(std::string const& label_, OutputObjHandlingPolicy policy_ = OutputObjHandlingPolicy::AnalysisObject) + OutputObj(std::string const& label_, OutputObjHandlingPolicy policy_ = OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType sourceType_ = OutputObjSourceType::OutputObjSource) : object(nullptr), label(label_), policy{policy_}, + sourceType{sourceType_}, mTaskHash{0} { } @@ -439,12 +464,13 @@ struct OutputObj { OutputRef ref() { return OutputRef{std::string{label}, 0, - o2::header::Stack{OutputObjHeader{policy, mTaskHash}}}; + o2::header::Stack{OutputObjHeader{policy, sourceType, mTaskHash}}}; } std::shared_ptr<T> object; std::string label; OutputObjHandlingPolicy policy; + OutputObjSourceType sourceType; uint32_t mTaskHash; }; @@ -486,6 +512,13 @@ struct Partition { { } + void bindTable(T& table) + { + mFiltered.reset(getTableFromFilter(table, filter)); + bindExternalIndices(&table); + getBoundToExternalIndices(table); + } + void setTable(const T& table) { mFiltered.reset(getTableFromFilter(table, filter)); @@ -499,6 +532,21 @@ struct Partition { } } + void bindInternalIndices() + { + if (mFiltered != nullptr) { + mFiltered->bindInternalIndices(); + } + } + + template <typename E> + void bindInternalIndicesTo(E* ptr) + { + if (mFiltered != nullptr) { + mFiltered->bindInternalIndicesTo(ptr); + } + } + template <typename T2> void getBoundToExternalIndices(T2& table) { @@ -515,6 +563,8 @@ struct Partition { expressions::Filter filter; std::unique_ptr<o2::soa::Filtered<T>> mFiltered = nullptr; + using iterator = typename o2::soa::Filtered<T>::iterator; + using const_iterator = typename o2::soa::Filtered<T>::const_iterator; using filtered_iterator = typename o2::soa::Filtered<T>::iterator; using filtered_const_iterator = typename o2::soa::Filtered<T>::const_iterator; inline filtered_iterator begin() @@ -550,7 +600,7 @@ auto Extend(T const& table) { static_assert((soa::is_type_spawnable_v<Cs> && ...), "You can only extend a table with expression columns"); using output_t = Join<T, soa::Table<Cs...>>; - return output_t{{o2::framework::spawner(framework::pack<Cs...>{}, table.asArrowTable().get()), table.asArrowTable()}, 0}; + return output_t{{o2::framework::spawner(framework::pack<Cs...>{}, table.asArrowTable().get(), "dynamic extension"), table.asArrowTable()}, 0}; } /// Template function to attach dynamic columns on-the-fly (e.g. inside diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h new file mode 100644 index 0000000000000..cd3dd57bcb33f --- /dev/null +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -0,0 +1,509 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef FRAMEWORK_ANALYSISMANAGERS_H +#define FRAMEWORK_ANALYSISMANAGERS_H +#include "Framework/AnalysisHelpers.h" +#include "Framework/Kernels.h" +#include "Framework/ASoA.h" +#include "Framework/ProcessingContext.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ConfigurableHelpers.h" +#include "Framework/InitContext.h" +#include "Framework/ConfigContext.h" +#include "Framework/RootConfigParamHelpers.h" +#include "Framework/ExpressionHelpers.h" +#include "Framework/CommonServices.h" + +namespace o2::framework +{ + +template <typename ANY> +struct PartitionManager { + template <typename... T2s> + static void setPartition(ANY&, T2s&...) + { + } + + template <typename... Ts> + static void bindExternalIndices(ANY&, Ts*...) + { + } + + template <typename E> + static void bindInternalIndices(ANY&, E*) + { + } + + template <typename... Ts> + static void getBoundToExternalIndices(ANY&, Ts&...) + { + } + + static void updatePlaceholders(ANY&, InitContext&) + { + } +}; + +template <typename T> +struct PartitionManager<Partition<T>> { + template <typename T2> + static void doSetPartition(Partition<T>& partition, T2& table) + { + if constexpr (std::is_same_v<T, T2>) { + partition.setTable(table); + } + } + + template <typename... T2s> + static void setPartition(Partition<T>& partition, T2s&... tables) + { + (doSetPartition(partition, tables), ...); + } + + template <typename... Ts> + static void bindExternalIndices(Partition<T>& partition, Ts*... tables) + { + partition.bindExternalIndices(tables...); + } + + template <typename E> + static void bindInternalIndices(Partition<T>& partition, E* table) + { + if constexpr (o2::soa::is_binding_compatible_v<T, std::decay_t<E>>()) { + partition.bindInternalIndicesTo(table); + } + } + + template <typename... Ts> + static void getBoundToExternalIndices(Partition<T>& partition, Ts&... tables) + { + partition.getBoundToExternalIndices(tables...); + } + + static void updatePlaceholders(Partition<T>& partition, InitContext& context) + { + partition.updatePlaceholders(context); + } +}; + +template <typename ANY> +struct FilterManager { + static bool createExpressionTrees(ANY&, std::vector<ExpressionInfo>&) + { + return false; + } + + static bool updatePlaceholders(ANY&, InitContext&) + { + return false; + } +}; + +template <> +struct FilterManager<expressions::Filter> { + static bool createExpressionTrees(expressions::Filter const& filter, std::vector<ExpressionInfo>& expressionInfos) + { + expressions::updateExpressionInfos(filter, expressionInfos); + return true; + } + + static bool updatePlaceholders(expressions::Filter& filter, InitContext& ctx) + { + expressions::updatePlaceholders(filter, ctx); + return true; + } +}; + +/// SFINAE placeholder +template <typename T> +struct OutputManager { + template <typename ANY> + static bool appendOutput(std::vector<OutputSpec>&, ANY&, uint32_t) + { + return false; + } + + template <typename ANY> + static bool prepare(ProcessingContext&, ANY&) + { + return false; + } + + template <typename ANY> + static bool postRun(EndOfStreamContext&, ANY&) + { + return true; + } + + template <typename ANY> + static bool finalize(ProcessingContext&, ANY&) + { + return true; + } +}; + +/// Produces specialization +template <typename TABLE> +struct OutputManager<Produces<TABLE>> { + static bool appendOutput(std::vector<OutputSpec>& outputs, Produces<TABLE>& what, uint32_t) + { + outputs.emplace_back(what.spec()); + return true; + } + static bool prepare(ProcessingContext& context, Produces<TABLE>& what) + { + what.resetCursor(context.outputs().make<TableBuilder>(what.ref())); + return true; + } + static bool finalize(ProcessingContext&, Produces<TABLE>& what) + { + what.setLabel(o2::aod::MetadataTrait<TABLE>::metadata::tableLabel()); + return true; + } + static bool postRun(EndOfStreamContext&, Produces<TABLE>&) + { + return true; + } +}; + +/// HistogramRegistry specialization +template <> +struct OutputManager<HistogramRegistry> { + static bool appendOutput(std::vector<OutputSpec>& outputs, HistogramRegistry& what, uint32_t hash) + { + what.setHash(hash); + outputs.emplace_back(what.spec()); + return true; + } + static bool prepare(ProcessingContext&, HistogramRegistry&) + { + return true; + } + + static bool finalize(ProcessingContext&, HistogramRegistry&) + { + return true; + } + + static bool postRun(EndOfStreamContext& context, HistogramRegistry& what) + { + context.outputs().snapshot(what.ref(), *(*what)); + return true; + } +}; + +/// OutputObj specialization +template <typename T> +struct OutputManager<OutputObj<T>> { + static bool appendOutput(std::vector<OutputSpec>& outputs, OutputObj<T>& what, uint32_t hash) + { + what.setHash(hash); + outputs.emplace_back(what.spec()); + return true; + } + static bool prepare(ProcessingContext&, OutputObj<T>&) + { + return true; + } + + static bool finalize(ProcessingContext&, OutputObj<T>&) + { + return true; + } + + static bool postRun(EndOfStreamContext& context, OutputObj<T>& what) + { + context.outputs().snapshot(what.ref(), *what); + return true; + } +}; + +/// Spawns specializations +template <typename O> +static auto extractOriginal(ProcessingContext& pc) +{ + return pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable(); +} + +template <typename... Os> +static std::vector<std::shared_ptr<arrow::Table>> extractOriginals(framework::pack<Os...>, ProcessingContext& pc) +{ + return {extractOriginal<Os>(pc)...}; +} + +template <typename T> +struct OutputManager<Spawns<T>> { + static bool appendOutput(std::vector<OutputSpec>& outputs, Spawns<T>& what, uint32_t) + { + outputs.emplace_back(what.spec()); + return true; + } + + static bool prepare(ProcessingContext& pc, Spawns<T>& what) + { + auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(what.sources_pack(), pc)); + if (original_table->schema()->fields().empty() == true) { + using base_table_t = typename Spawns<T>::base_table_t; + original_table = makeEmptyTable<base_table_t>(aod::MetadataTrait<typename Spawns<T>::extension_t>::metadata::tableLabel()); + } + + what.extension = std::make_shared<typename Spawns<T>::extension_t>(o2::framework::spawner(what.pack(), original_table.get(), aod::MetadataTrait<typename Spawns<T>::extension_t>::metadata::tableLabel())); + what.table = std::make_shared<typename T::table_t>(soa::ArrowHelpers::joinTables({what.extension->asArrowTable(), original_table})); + return true; + } + + static bool finalize(ProcessingContext& pc, Spawns<T>& what) + { + pc.outputs().adopt(what.output(), what.asArrowTable()); + return true; + } + + static bool postRun(EndOfStreamContext&, Spawns<T>&) + { + return true; + } +}; + +/// Builds specialization +template <typename... Os> +static inline auto extractOriginalsVector(framework::pack<Os...>, ProcessingContext& pc) +{ + return std::vector{extractOriginal<Os>(pc)...}; +} + +template <typename O> +static inline auto extractTypedOriginal(ProcessingContext& pc) +{ + if constexpr (soa::is_type_with_originals_v<O>) { + return O{extractOriginalsVector(soa::originals_pack_t<O>{}, pc)}; + } else { + return O{pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable()}; + } +} + +template <typename... Os> +static inline auto extractOriginalsTuple(framework::pack<Os...>, ProcessingContext& pc) +{ + return std::make_tuple(extractTypedOriginal<Os>(pc)...); +} + +template <typename T, typename P> +struct OutputManager<Builds<T, P>> { + static bool appendOutput(std::vector<OutputSpec>& outputs, Builds<T, P>& what, uint32_t) + { + outputs.emplace_back(what.spec()); + return true; + } + + static bool prepare(ProcessingContext& pc, Builds<T, P>& what) + { + return what.build(what.pack(), + extractTypedOriginal<typename Builds<T, P>::Key>(pc), + extractOriginalsTuple(what.originals_pack(), pc)); + } + + static bool finalize(ProcessingContext& pc, Builds<T, P>& what) + { + pc.outputs().adopt(what.output(), what.asArrowTable()); + return true; + } + + static bool postRun(EndOfStreamContext&, Builds<T, P>&) + { + return true; + } +}; + +template <typename T> +class has_instance +{ + typedef char one; + struct two { + char x[2]; + }; + + template <typename C> + static one test(decltype(&C::instance)); + template <typename C> + static two test(...); + + public: + enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; +}; + +template <typename T> +struct ServiceManager { + template <typename ANY> + static bool add(std::vector<ServiceSpec>&, ANY&) + { + return false; + } + + template <typename ANY> + static bool prepare(InitContext&, ANY&) + { + return false; + } +}; + +template <typename T> +struct ServiceManager<Service<T>> { + static bool add(std::vector<ServiceSpec>& specs, Service<T>&) + { + CommonAnalysisServices::addAnalysisService<T>(specs); + return true; + } + + static bool prepare(InitContext& context, Service<T>& service) + { + if constexpr (has_instance<T>::value) { + service.service = &(T::instance()); // Sigh... + return true; + } else { + service.service = &(context.services().get<T>()); + return true; + } + return false; + } +}; + +template <typename T> +struct OptionManager { + template <typename ANY> + static bool appendOption(std::vector<ConfigParamSpec>&, ANY&) + { + return false; + } + + template <typename ANY> + static bool prepare(InitContext&, ANY&) + { + return false; + } +}; + +template <typename T, ConfigParamKind K, typename IP> +struct OptionManager<Configurable<T, K, IP>> { + static bool appendOption(std::vector<ConfigParamSpec>& options, Configurable<T, K, IP>& what) + { + return ConfigurableHelpers::appendOption(options, what); + } + + static bool prepare(InitContext& context, Configurable<T, K, IP>& what) + { + if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) { + what.value = context.options().get<T>(what.name.c_str()); + } else { + auto pt = context.options().get<boost::property_tree::ptree>(what.name.c_str()); + what.value = RootConfigParamHelpers::as<T>(pt); + } + return true; + } +}; + +template <typename R, typename T, typename... As> +struct OptionManager<ProcessConfigurable<R, T, As...>> { + static bool appendOption(std::vector<ConfigParamSpec>& options, ProcessConfigurable<R, T, As...>& what) + { + options.emplace_back(ConfigParamSpec{what.name, variant_trait_v<std::decay_t<bool>>, what.value, {what.help}, what.kind}); + return true; + } + + static bool prepare(InitContext& context, ProcessConfigurable<R, T, As...>& what) + { + what.value = context.options().get<bool>(what.name.c_str()); + return true; + } +}; + +template <typename ANY> +struct UpdateProcessSwitches { + static bool set(std::pair<std::string, bool>, ANY&) + { + return false; + } +}; + +template <typename R, typename T, typename... As> +struct UpdateProcessSwitches<ProcessConfigurable<R, T, As...>> { + static bool set(std::pair<std::string, bool> setting, ProcessConfigurable<R, T, As...>& what) + { + if (what.name == setting.first) { + what.value = setting.second; + return true; + } + return false; + } +}; + +/// Manager template to facilitate extended tables spawning +template <typename T> +struct SpawnManager { + static bool requestInputs(std::vector<InputSpec>&, T const&) { return false; } +}; + +namespace +{ +void updateInputs(std::string type, bool value, std::vector<InputSpec>& inputs, InputSpec& spec) +{ + auto locate = std::find_if(inputs.begin(), inputs.end(), [&](InputSpec& input) { return input.binding == spec.binding; }); + if (locate != inputs.end()) { + // amend entry + auto& entryMetadata = locate->metadata; + entryMetadata.push_back(ConfigParamSpec{std::string{"control:"} + type, VariantType::Bool, value, {"\"\""}}); + std::sort(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name < b.name; }); + auto new_end = std::unique(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name == b.name; }); + entryMetadata.erase(new_end, entryMetadata.end()); + } else { + //add entry + spec.metadata.push_back(ConfigParamSpec{std::string{"control:"} + type, VariantType::Bool, value, {"\"\""}}); + inputs.emplace_back(spec); + } +} +} // namespace + +template <typename TABLE> +struct SpawnManager<Spawns<TABLE>> { + static bool requestInputs(std::vector<InputSpec>& inputs, Spawns<TABLE>& spawns) + { + auto base_specs = spawns.base_specs(); + for (auto& base_spec : base_specs) { + updateInputs("spawn", true, inputs, base_spec); + } + return true; + } +}; + +/// Manager template for building index tables +template <typename T> +struct IndexManager { + static bool requestInputs(std::vector<InputSpec>&, T const&) { return false; }; +}; + +template <typename IDX, typename P> +struct IndexManager<Builds<IDX, P>> { + static bool requestInputs(std::vector<InputSpec>& inputs, Builds<IDX, P>& builds) + { + auto base_specs = builds.base_specs(); + for (auto& base_spec : base_specs) { + updateInputs("build", true, inputs, base_spec); + } + return true; + } +}; + +} // namespace o2::framework + +#endif // ANALYSISMANAGERS_H diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index e6867177bb734..88a0e2e9dba36 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,13 +12,14 @@ #ifndef FRAMEWORK_ANALYSIS_TASK_H_ #define FRAMEWORK_ANALYSIS_TASK_H_ -#include "../../src/AnalysisManagers.h" +#include "Framework/AnalysisManagers.h" #include "Framework/AlgorithmSpec.h" #include "Framework/CallbackService.h" +#include "Framework/ConfigContext.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Expressions.h" -#include "../src/ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "Framework/EndOfStreamContext.h" #include "Framework/Logger.h" #include "Framework/StructToTuple.h" @@ -25,6 +27,7 @@ #include "Framework/Traits.h" #include "Framework/VariantHelpers.h" #include "Framework/RuntimeError.h" +#include "Framework/TypeIdHelpers.h" #include <arrow/compute/kernel.h> #include <arrow/table.h> @@ -57,10 +60,10 @@ struct AnalysisDataProcessorBuilder { static ConfigParamSpec getSpec() { if constexpr (soa::is_type_with_metadata_v<aod::MetadataTrait<T>>) { - return ConfigParamSpec{aod::MetadataTrait<T>::metadata::tableLabel(), VariantType::String, aod::MetadataTrait<T>::metadata::sourceSpec(), {"\"\""}}; + return ConfigParamSpec{std::string{"input:"} + aod::MetadataTrait<T>::metadata::tableLabel(), VariantType::String, aod::MetadataTrait<T>::metadata::sourceSpec(), {"\"\""}}; } else { using O1 = framework::pack_element_t<0, typename T::originals>; - return ConfigParamSpec{aod::MetadataTrait<T>::metadata::tableLabel(), VariantType::String, aod::MetadataTrait<O1>::metadata::sourceSpec(), {"\"\""}}; + return ConfigParamSpec{std::string{"input:"} + aod::MetadataTrait<T>::metadata::tableLabel(), VariantType::String, aod::MetadataTrait<O1>::metadata::sourceSpec(), {"\"\""}}; } } @@ -78,46 +81,64 @@ struct AnalysisDataProcessorBuilder { } template <typename Arg> - static void doAppendInputWithMetadata(std::vector<InputSpec>& inputs) + static void doAppendInputWithMetadata(const char* name, bool value, std::vector<InputSpec>& inputs) { using metadata = typename aod::MetadataTrait<std::decay_t<Arg>>::metadata; static_assert(std::is_same_v<metadata, void> == false, "Could not find metadata. Did you register your type?"); + std::vector<ConfigParamSpec> inputMetadata; + inputMetadata.emplace_back(ConfigParamSpec{std::string{"control:"} + name, VariantType::Bool, value, {"\"\""}}); if constexpr (soa::is_soa_index_table_t<std::decay_t<Arg>>::value) { auto inputSources = getIndexSources<std::decay_t<Arg>>(); std::sort(inputSources.begin(), inputSources.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name < b.name; }); auto last = std::unique(inputSources.begin(), inputSources.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name == b.name; }); inputSources.erase(last, inputSources.end()); - inputs.push_back(InputSpec{metadata::tableLabel(), metadata::origin(), metadata::description(), Lifetime::Timeframe, inputSources}); + inputMetadata.insert(inputMetadata.end(), inputSources.begin(), inputSources.end()); + } + auto locate = std::find_if(inputs.begin(), inputs.end(), [](InputSpec& input) { return input.binding == metadata::tableLabel(); }); + if (locate != inputs.end()) { + // amend entry + auto& entryMetadata = locate->metadata; + entryMetadata.insert(entryMetadata.end(), inputMetadata.begin(), inputMetadata.end()); + std::sort(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name < b.name; }); + auto new_end = std::unique(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name == b.name; }); + entryMetadata.erase(new_end, entryMetadata.end()); } else { - inputs.push_back({metadata::tableLabel(), metadata::origin(), metadata::description()}); + // add entry + inputs.push_back(InputSpec{metadata::tableLabel(), metadata::origin(), metadata::description(), Lifetime::Timeframe, inputMetadata}); } } template <typename... Args> - static void doAppendInputWithMetadata(framework::pack<Args...>, std::vector<InputSpec>& inputs) + static void doAppendInputWithMetadata(framework::pack<Args...>, const char* name, bool value, std::vector<InputSpec>& inputs) { - (doAppendInputWithMetadata<Args>(inputs), ...); + (doAppendInputWithMetadata<Args>(name, value, inputs), ...); } - template <typename T> - static void appendSomethingWithMetadata(std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, size_t at) + template <typename T, int AI> + static void appendSomethingWithMetadata(const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, size_t hash) { using dT = std::decay_t<T>; if constexpr (framework::is_specialization<dT, soa::Filtered>::value) { - eInfos.push_back({at, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); + eInfos.push_back({AI, hash, dT::hashes(), o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); } else if constexpr (soa::is_soa_iterator_t<dT>::value) { if constexpr (std::is_same_v<typename dT::policy_t, soa::FilteredIndexPolicy>) { - eInfos.push_back({at, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); + eInfos.push_back({AI, hash, dT::parent_t::hashes(), o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); } } - doAppendInputWithMetadata(soa::make_originals_from_type<dT>(), inputs); + doAppendInputWithMetadata(soa::make_originals_from_type<dT>(), name, value, inputs); } + // template <typename... T> + // static void inputsFromArgsTuple(std::tuple<T...>& processTuple, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos) + // { + // (inputsFromArgs<o2::framework::has_type_at_v<T>(pack<T...>{})>(std::get<T>(processTuple), inputs, eInfos), ...); + // } + template <typename R, typename C, typename... Args> - static void inputsFromArgs(R (C::*)(Args...), std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos) + static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos) { - (appendSomethingWithMetadata<Args>(inputs, eInfos, o2::framework::has_type_at_v<Args>(pack<Args...>{})), ...); + (appendSomethingWithMetadata<Args, o2::framework::has_type_at_v<Args>(pack<Args...>{})>(name, value, inputs, eInfos, typeHash<R (C::*)(Args...)>()), ...); } template <typename R, typename C, typename Grouping, typename... Args> @@ -129,7 +150,7 @@ struct AnalysisDataProcessorBuilder { template <typename R, typename C, typename Grouping, typename... Args> static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector<ExpressionInfo> const& infos) { - return extractSomethingFromRecord<Grouping>(record, infos, 0); + return extractSomethingFromRecord<Grouping, 0>(record, infos, typeHash<R (C::*)(Grouping, Args...)>()); } template <typename R, typename C> @@ -145,7 +166,7 @@ struct AnalysisDataProcessorBuilder { if constexpr (soa::is_type_with_metadata_v<aod::MetadataTrait<T>>) { auto table = record.get<TableConsumer>(aod::MetadataTrait<T>::metadata::tableLabel())->asArrowTable(); if (table->num_rows() == 0) { - table = makeEmptyTable<T>(); + table = makeEmptyTable<T>(aod::MetadataTrait<T>::metadata::tableLabel()); } return table; } else if constexpr (soa::is_type_with_originals_v<T>) { @@ -174,24 +195,16 @@ struct AnalysisDataProcessorBuilder { } } - template <typename T> - static auto extractSomethingFromRecord(InputRecord& record, std::vector<ExpressionInfo> const infos, size_t at) + template <typename T, int AI> + static auto extractSomethingFromRecord(InputRecord& record, std::vector<ExpressionInfo> const infos, size_t phash) { using decayed = std::decay_t<T>; if constexpr (soa::is_soa_filtered_t<decayed>::value) { - for (auto& info : infos) { - if (info.index == at) { - return extractFilteredFromRecord<decayed>(record, info, soa::make_originals_from_type<decayed>()); - } - } + return extractFilteredFromRecord<decayed>(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type<decayed>()); } else if constexpr (soa::is_soa_iterator_t<decayed>::value) { if constexpr (std::is_same_v<typename decayed::policy_t, soa::FilteredIndexPolicy>) { - for (auto& info : infos) { - if (info.index == at) { - return extractFilteredFromRecord<decayed>(record, info, soa::make_originals_from_type<decayed>()); - } - } + return extractFilteredFromRecord<decayed>(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type<decayed>()); } else { return extractFromRecord<decayed>(record, soa::make_originals_from_type<decayed>()); } @@ -204,7 +217,7 @@ struct AnalysisDataProcessorBuilder { template <typename R, typename C, typename Grouping, typename... Args> static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector<ExpressionInfo> const infos) { - return std::make_tuple(extractSomethingFromRecord<Args>(record, infos, has_type_at_v<Args>(pack<Args...>{}) + 1u)...); + return std::make_tuple(extractSomethingFromRecord<Args, has_type_at_v<Args>(pack<Args...>{}) + 1>(record, infos, typeHash<R (C::*)(Grouping, Args...)>())...); } template <typename R, typename C> @@ -246,18 +259,18 @@ struct AnalysisDataProcessorBuilder { if constexpr (soa::is_type_with_originals_v<std::decay_t<T>>) { using O = typename framework::pack_element_t<0, typename std::decay_t<G>::originals>; using groupingMetadata = typename aod::MetadataTrait<O>::metadata; - return std::string("f") + groupingMetadata::tableLabel() + "ID"; + return std::string("fIndex") + groupingMetadata::tableLabel(); } else { using groupingMetadata = typename aod::MetadataTrait<T>::metadata; - return std::string("f") + groupingMetadata::tableLabel() + "ID"; + return std::string("fIndex") + groupingMetadata::tableLabel(); } } else if constexpr (soa::is_type_with_originals_v<std::decay_t<G>>) { using T = typename framework::pack_element_t<0, typename std::decay_t<G>::originals>; using groupingMetadata = typename aod::MetadataTrait<T>::metadata; - return std::string("f") + groupingMetadata::tableLabel() + "ID"; + return std::string("fIndex") + groupingMetadata::tableLabel(); } else { using groupingMetadata = typename aod::MetadataTrait<std::decay_t<G>>::metadata; - return std::string("f") + groupingMetadata::tableLabel() + "ID"; + return std::string("fIndex") + groupingMetadata::tableLabel(); } } @@ -281,12 +294,13 @@ struct AnalysisDataProcessorBuilder { x.asArrowTable(), static_cast<int32_t>(gt.tableSize()), &groups[index], - &offsets[index]); + &offsets[index], + &sizes[index]); if (result.ok() == false) { throw runtime_error("Cannot split collection"); } - if (groups[index].size() != gt.tableSize()) { - throw runtime_error_f("Splitting collection resulted in different group number (%d) than there is rows in the grouping table (%d).", groups[index].size(), gt.tableSize()); + if (groups[index].size() > gt.tableSize()) { + throw runtime_error_f("Splitting collection resulted in a larger group number (%d) than there is rows in the grouping table (%d).", groups[index].size(), gt.tableSize()); }; } }; @@ -345,7 +359,7 @@ struct AnalysisDataProcessorBuilder { return false; } - GroupSlicerIterator operator++() + GroupSlicerIterator& operator++() { ++position; ++mGroupingElement; @@ -393,7 +407,7 @@ struct AnalysisDataProcessorBuilder { // for each grouping element we need to slice the selection vector auto start_iterator = std::lower_bound(starts[index], selections[index]->end(), (offsets[index])[pos]); - auto stop_iterator = std::lower_bound(start_iterator, selections[index]->end(), (offsets[index])[pos + 1]); + auto stop_iterator = std::lower_bound(start_iterator, selections[index]->end(), (offsets[index])[pos] + (sizes[index])[pos]); starts[index] = stop_iterator; soa::SelectionVector slicedSelection{start_iterator, stop_iterator}; std::transform(slicedSelection.begin(), slicedSelection.end(), slicedSelection.begin(), @@ -402,10 +416,12 @@ struct AnalysisDataProcessorBuilder { }); std::decay_t<A1> typedTable{{groupedElementsTable}, std::move(slicedSelection), (offsets[index])[pos]}; + typedTable.bindInternalIndicesTo(&std::get<A1>(*mAt)); return typedTable; } else { auto groupedElementsTable = arrow::util::get<std::shared_ptr<arrow::Table>>(((groups[index])[pos]).value); std::decay_t<A1> typedTable{{groupedElementsTable}, (offsets[index])[pos]}; + typedTable.bindInternalIndicesTo(&std::get<A1>(*mAt)); return typedTable; } } else { @@ -418,9 +434,9 @@ struct AnalysisDataProcessorBuilder { typename grouping_t::iterator mGroupingElement; uint64_t position = 0; soa::SelectionVector const* groupSelection = nullptr; - std::array<std::vector<arrow::Datum>, sizeof...(A)> groups; std::array<std::vector<uint64_t>, sizeof...(A)> offsets; + std::array<std::vector<int>, sizeof...(A)> sizes; std::array<soa::SelectionVector const*, sizeof...(A)> selections; std::array<soa::SelectionVector::const_iterator, sizeof...(A)> starts; }; @@ -438,48 +454,70 @@ struct AnalysisDataProcessorBuilder { GroupSlicerIterator mBegin; }; + template <typename Task, typename... T> + static void invokeProcessTuple(Task& task, InputRecord& inputs, std::tuple<T...> const& processTuple, std::vector<ExpressionInfo> const& infos) + { + (invokeProcess<o2::framework::has_type_at_v<T>(pack<T...>{})>(task, inputs, std::get<T>(processTuple), infos), ...); + } + template <typename Task, typename R, typename C, typename Grouping, typename... Associated> - static void invokeProcess(Task& task, InputRecord& inputs, R (C::*)(Grouping, Associated...), std::vector<ExpressionInfo> const& infos) + static void invokeProcess(Task& task, InputRecord& inputs, R (C::*processingFunction)(Grouping, Associated...), std::vector<ExpressionInfo> const& infos) { - auto tupledTask = o2::framework::to_tuple_refs(task); using G = std::decay_t<Grouping>; - auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, &C::process, infos); + auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, processingFunction, infos); // set filtered tables for partitions with grouping - std::apply([&groupingTable](auto&... x) { - (PartitionManager<std::decay_t<decltype(x)>>::setPartition(x, groupingTable), ...); + homogeneous_apply_refs([&groupingTable](auto& x) { + PartitionManager<std::decay_t<decltype(x)>>::setPartition(x, groupingTable); + PartitionManager<std::decay_t<decltype(x)>>::bindInternalIndices(x, &groupingTable); + return true; }, - tupledTask); + task); if constexpr (sizeof...(Associated) == 0) { // single argument to process - std::apply([&groupingTable](auto&... x) { - (PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable), ...); - (PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable), ...); + homogeneous_apply_refs([&groupingTable](auto& x) { + PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable); + PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable); + return true; }, - tupledTask); + task); if constexpr (soa::is_soa_iterator_t<G>::value) { for (auto& element : groupingTable) { - task.process(*element); + std::invoke(processingFunction, task, *element); } } else { static_assert(soa::is_soa_table_like_t<G>::value, "Single argument of process() should be a table-like or an iterator"); - task.process(groupingTable); + std::invoke(processingFunction, task, groupingTable); } } else { // multiple arguments to process static_assert(((soa::is_soa_iterator_t<std::decay_t<Associated>>::value == false) && ...), "Associated arguments of process() should not be iterators"); - auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, &C::process, infos); + auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, processingFunction, infos); + //pre-bind self indices + std::apply( + [&](auto&... t) { + (homogeneous_apply_refs( + [&](auto& p) { + PartitionManager<std::decay_t<decltype(p)>>::bindInternalIndices(p, &t); + return true; + }, + task), + ...); + }, + associatedTables); + auto binder = [&](auto&& x) { x.bindExternalIndices(&groupingTable, &std::get<std::decay_t<Associated>>(associatedTables)...); - std::apply([&x](auto&... t) { - (PartitionManager<std::decay_t<decltype(t)>>::setPartition(t, x), ...); - (PartitionManager<std::decay_t<decltype(t)>>::bindExternalIndices(t, &x), ...); - (PartitionManager<std::decay_t<decltype(t)>>::getBoundToExternalIndices(t, x), ...); + homogeneous_apply_refs([&x](auto& t) { + PartitionManager<std::decay_t<decltype(t)>>::setPartition(t, x); + PartitionManager<std::decay_t<decltype(t)>>::bindExternalIndices(t, &x); + PartitionManager<std::decay_t<decltype(t)>>::getBoundToExternalIndices(t, x); + return true; }, - tupledTask); + task); }; groupingTable.bindExternalIndices(&std::get<std::decay_t<Associated>>(associatedTables)...); @@ -503,29 +541,37 @@ struct AnalysisDataProcessorBuilder { associatedSlices); // bind partitions and grouping table - std::apply([&groupingTable](auto&... x) { - (PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable), ...); - (PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable), ...); + homogeneous_apply_refs([&groupingTable](auto& x) { + PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable); + PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable); + return true; }, - tupledTask); + task); - invokeProcessWithArgs(task, slice.groupingElement(), associatedSlices); + invokeProcessWithArgsGeneric(task, processingFunction, slice.groupingElement(), associatedSlices); } } else { // non-grouping case // bind partitions and grouping table - std::apply([&groupingTable](auto&... x) { - (PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable), ...); - (PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable), ...); + homogeneous_apply_refs([&groupingTable](auto& x) { + PartitionManager<std::decay_t<decltype(x)>>::bindExternalIndices(x, &groupingTable); + PartitionManager<std::decay_t<decltype(x)>>::getBoundToExternalIndices(x, groupingTable); + return true; }, - tupledTask); + task); - invokeProcessWithArgs(task, groupingTable, associatedTables); + invokeProcessWithArgsGeneric(task, processingFunction, groupingTable, associatedTables); } } } + template <typename C, typename T, typename G, typename... A> + static void invokeProcessWithArgsGeneric(C& task, T processingFunction, G g, std::tuple<A...>& at) + { + std::invoke(processingFunction, task, g, std::get<A>(at)...); + } + template <typename T, typename G, typename... A> static void invokeProcessWithArgs(T& task, G g, std::tuple<A...>& at) { @@ -533,141 +579,259 @@ struct AnalysisDataProcessorBuilder { } }; -// SFINAE test +namespace +{ template <typename T> class has_process { - typedef char one; - struct two { - char x[2]; - }; - template <typename C> - static one test(decltype(&C::process)); + static std::true_type test(decltype(&C::process)); template <typename C> - static two test(...); + static std::false_type test(...); public: - enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; + static constexpr bool value = decltype(test<T>(nullptr))::value; }; +template <class T> +inline constexpr bool has_process_v = has_process<T>::value; + template <typename T> class has_run { - typedef char one; - struct two { - char x[2]; - }; - template <typename C> - static one test(decltype(&C::run)); + static std::true_type test(decltype(&C::run)); template <typename C> - static two test(...); + static std::false_type test(...); public: - enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; + static constexpr bool value = decltype(test<T>(nullptr))::value; }; +template <class T> +inline constexpr bool has_run_v = has_run<T>::value; + template <typename T> class has_init { - typedef char one; - struct two { - char x[2]; - }; - template <typename C> - static one test(decltype(&C::init)); + static std::true_type test(decltype(&C::init)); template <typename C> - static two test(...); + static std::false_type test(...); public: - enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; + static constexpr bool value = decltype(test<T>(nullptr))::value; }; +template <class T> +inline constexpr bool has_init_v = has_init<T>::value; +} // namespace + +struct SetDefaultProcesses { + std::vector<std::pair<std::string, bool>> map; +}; + +/// Struct to differentiate task names from possible task string arguments +struct TaskName { + TaskName(std::string const& name) : value{name} {} + std::string value; +}; + +template <typename T, typename... A> +auto getTaskNameSetProcesses(TaskName first, SetDefaultProcesses second, A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + for (auto& setting : second.map) { + homogeneous_apply_refs( + [&](auto& x) { + return UpdateProcessSwitches<std::decay_t<decltype(x)>>::set(setting, x); + }, + *task.get()); + } + return std::make_tuple(first.value, task); +} + +template <typename T, typename... A> +auto getTaskNameSetProcesses(SetDefaultProcesses first, TaskName second, A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + for (auto& setting : first.map) { + homogeneous_apply_refs( + [&](auto& x) { + return UpdateProcessSwitches<std::decay_t<decltype(x)>>::set(setting, x); + }, + *task.get()); + } + return std::make_tuple(second.value, task); +} + +template <typename T, typename... A> +auto getTaskNameSetProcesses(SetDefaultProcesses first, A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + for (auto& setting : first.map) { + homogeneous_apply_refs( + [&](auto& x) { + return UpdateProcessSwitches<std::decay_t<decltype(x)>>::set(setting, x); + }, + *task.get()); + } + auto type_name_str = type_name<T>(); + std::string name = type_to_task_name(type_name_str); + return std::make_tuple(name, task); +} + +template <typename T, typename... A> +auto getTaskNameSetProcesses(TaskName first, A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + return std::make_tuple(first.value, task); +} + +template <typename T, typename... A> +auto getTaskNameSetProcesses(A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + auto type_name_str = type_name<T>(); + std::string name = type_to_task_name(type_name_str); + return std::make_tuple(name, task); +} + +template <typename T, typename... A> +auto getTaskName(TaskName first, A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + return std::make_tuple(first.value, task); +} + +template <typename T, typename... A> +auto getTaskName(A... args) +{ + auto task = std::make_shared<T>(std::forward<A>(args)...); + auto type_name_str = type_name<T>(); + std::string name = type_to_task_name(type_name_str); + return std::make_tuple(name, task); +} + /// Adaptor to make an AlgorithmSpec from a o2::framework::Task /// template <typename T, typename... Args> -DataProcessorSpec adaptAnalysisTask(char const* name, Args&&... args) +DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) { TH1::AddDirectory(false); - auto task = std::make_shared<T>(std::forward<Args>(args)...); - auto hash = compile_time_hash(name); - std::vector<OutputSpec> outputs; - std::vector<ConfigParamSpec> options; + auto [name_str, task] = getTaskNameSetProcesses<T>(args...); - auto tupledTask = o2::framework::to_tuple_refs(*task.get()); - static_assert(has_process<T>::value || has_run<T>::value || has_init<T>::value, - "At least one of process(...), T::run(...), init(...) must be defined"); + auto suffix = ctx.options().get<std::string>("workflow-suffix"); + if (!suffix.empty()) { + name_str += suffix; + } + const char* name = name_str.c_str(); + + auto hash = compile_time_hash(name); + std::vector<OutputSpec> outputs; std::vector<InputSpec> inputs; + std::vector<ConfigParamSpec> options; std::vector<ExpressionInfo> expressionInfos; /// make sure options and configurables are set before expression infos are created - std::apply([&options, &hash](auto&... x) { return (OptionManager<std::decay_t<decltype(x)>>::appendOption(options, x), ...); }, tupledTask); + homogeneous_apply_refs([&options, &hash](auto& x) { return OptionManager<std::decay_t<decltype(x)>>::appendOption(options, x); }, *task.get()); - if constexpr (has_process<T>::value) { - // this pushes (I,schemaPtr,nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators - AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, inputs, expressionInfos); + /// parse process functions defined by corresponding configurables + if constexpr (has_process_v<T>) { + AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos); } - //request base tables for spawnable extended tables - std::apply([&inputs](auto&... x) { - return (SpawnManager<std::decay_t<decltype(x)>>::requestInputs(inputs, x), ...); + homogeneous_apply_refs( + [name = name_str, &expressionInfos, &inputs](auto& x) { + using D = std::decay_t<decltype(x)>; + if constexpr (is_base_of_template<ProcessConfigurable, D>::value) { + // this pushes (argumentIndex,processHash,schemaPtr,nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators + AnalysisDataProcessorBuilder::inputsFromArgs(x.process, (name + "/" + x.name).c_str(), x.value, inputs, expressionInfos); + return true; + } + return false; + }, + *task.get()); + + // avoid self-forwarding if process methods subscribe to same tables + std::sort(inputs.begin(), inputs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding < b.binding; }); + auto last = std::unique(inputs.begin(), inputs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding == b.binding; }); + inputs.erase(last, inputs.end()); + + // request base tables for spawnable extended tables + // this checks for duplications + homogeneous_apply_refs([&inputs](auto& x) { + return SpawnManager<std::decay_t<decltype(x)>>::requestInputs(inputs, x); }, - tupledTask); + *task.get()); //request base tables for indices to be built - std::apply([&inputs](auto&... x) { - return (IndexManager<std::decay_t<decltype(x)>>::requestInputs(inputs, x), ...); + homogeneous_apply_refs([&inputs](auto& x) { + return IndexManager<std::decay_t<decltype(x)>>::requestInputs(inputs, x); }, - tupledTask); + *task.get()); + + // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something + if (inputs.empty() == true) { + LOG(WARN) << "Task " << name_str << " has no inputs"; + } - std::apply([&outputs, &hash](auto&... x) { return (OutputManager<std::decay_t<decltype(x)>>::appendOutput(outputs, x, hash), ...); }, tupledTask); + homogeneous_apply_refs([&outputs, &hash](auto& x) { return OutputManager<std::decay_t<decltype(x)>>::appendOutput(outputs, x, hash); }, *task.get()); - auto algo = AlgorithmSpec::InitCallback{[task, expressionInfos](InitContext& ic) mutable { - auto tupledTask = o2::framework::to_tuple_refs(*task.get()); - std::apply([&ic](auto&&... x) { return (OptionManager<std::decay_t<decltype(x)>>::prepare(ic, x), ...); }, tupledTask); - std::apply([&ic](auto&&... x) { return (ServiceManager<std::decay_t<decltype(x)>>::prepare(ic, x), ...); }, tupledTask); + std::vector<ServiceSpec> requiredServices = CommonServices::defaultServices(); + homogeneous_apply_refs([&requiredServices](auto& x) { return ServiceManager<std::decay_t<decltype(x)>>::add(requiredServices, x); }, *task.get()); + + auto algo = AlgorithmSpec::InitCallback{[task = task, expressionInfos](InitContext& ic) mutable { + homogeneous_apply_refs([&ic](auto&& x) { return OptionManager<std::decay_t<decltype(x)>>::prepare(ic, x); }, *task.get()); + homogeneous_apply_refs([&ic](auto&& x) { return ServiceManager<std::decay_t<decltype(x)>>::prepare(ic, x); }, *task.get()); auto& callbacks = ic.services().get<CallbackService>(); auto endofdatacb = [task](EndOfStreamContext& eosContext) { - auto tupledTask = o2::framework::to_tuple_refs(*task.get()); - std::apply([&eosContext](auto&&... x) { return (OutputManager<std::decay_t<decltype(x)>>::postRun(eosContext, x), ...); }, tupledTask); + homogeneous_apply_refs([&eosContext](auto&& x) { return OutputManager<std::decay_t<decltype(x)>>::postRun(eosContext, x); }, *task.get()); eosContext.services().get<ControlService>().readyToQuit(QuitRequest::Me); }; callbacks.set(CallbackService::Id::EndOfStream, endofdatacb); - if constexpr (has_process<T>::value) { - /// update configurables in filters - std::apply( - [&ic](auto&&... x) { return (FilterManager<std::decay_t<decltype(x)>>::updatePlaceholders(x, ic), ...); }, - tupledTask); - /// update configurables in partitions - std::apply( - [&ic](auto&&... x) { return (PartitionManager<std::decay_t<decltype(x)>>::updatePlaceholders(x, ic), ...); }, - tupledTask); - /// create for filters gandiva trees matched to schemas and store the pointers into expressionInfos - std::apply([&expressionInfos](auto&... x) { - return (FilterManager<std::decay_t<decltype(x)>>::createExpressionTrees(x, expressionInfos), ...); - }, - tupledTask); - } + /// update configurables in filters + homogeneous_apply_refs( + [&ic](auto& x) -> bool { return FilterManager<std::decay_t<decltype(x)>>::updatePlaceholders(x, ic); }, + *task.get()); + /// update configurables in partitions + homogeneous_apply_refs( + [&ic](auto& x) -> bool { PartitionManager<std::decay_t<decltype(x)>>::updatePlaceholders(x, ic); return true; }, + *task.get()); + /// create for filters gandiva trees matched to schemas and store the pointers into expressionInfos + homogeneous_apply_refs([&expressionInfos](auto& x) { + return FilterManager<std::decay_t<decltype(x)>>::createExpressionTrees(x, expressionInfos); + }, + *task.get()); - if constexpr (has_init<T>::value) { + if constexpr (has_init_v<T>) { task->init(ic); } return [task, expressionInfos](ProcessingContext& pc) { - auto tupledTask = o2::framework::to_tuple_refs(*task.get()); - std::apply([&pc](auto&&... x) { return (OutputManager<std::decay_t<decltype(x)>>::prepare(pc, x), ...); }, tupledTask); - if constexpr (has_run<T>::value) { + homogeneous_apply_refs([&pc](auto&& x) { return OutputManager<std::decay_t<decltype(x)>>::prepare(pc, x); }, *task.get()); + if constexpr (has_run_v<T>) { task->run(pc); } - if constexpr (has_process<T>::value) { + if constexpr (has_process_v<T>) { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos); } - std::apply([&pc](auto&&... x) { return (OutputManager<std::decay_t<decltype(x)>>::finalize(pc, x), ...); }, tupledTask); + homogeneous_apply_refs( + [&pc, &expressionInfos, &task](auto& x) { + if constexpr (is_base_of_template<ProcessConfigurable, std::decay_t<decltype(x)>>::value) { + if (x.value == true) { + AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), x.process, expressionInfos); + return true; + } + } + return false; + }, + *task.get()); + + homogeneous_apply_refs([&pc](auto&& x) { return OutputManager<std::decay_t<decltype(x)>>::finalize(pc, x); }, *task.get()); }; }}; @@ -679,7 +843,8 @@ DataProcessorSpec adaptAnalysisTask(char const* name, Args&&... args) inputs, outputs, algo, - options}; + options, + requiredServices}; return spec; } diff --git a/Framework/Core/include/Framework/Array2D.h b/Framework/Core/include/Framework/Array2D.h new file mode 100644 index 0000000000000..5a1ed57408f30 --- /dev/null +++ b/Framework/Core/include/Framework/Array2D.h @@ -0,0 +1,273 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_ARRAY2D_H +#define FRAMEWORK_ARRAY2D_H + +#include <cstdint> +#include <vector> +#include <unordered_map> +#include <memory> +#include <string> +extern template class std::unordered_map<std::string, u_int32_t>; + +namespace o2::framework +{ +// matrix-like wrapper for C-array +// has no range checks +template <typename T> +struct Array2D { + using element_t = T; + + Array2D() + : data{nullptr}, + rows{0}, + cols{0} + { + } + + Array2D(T const* data_, uint32_t r, uint32_t c) + : rows{r}, cols{c} + { + data = new T[rows * cols]; + for (auto i = 0U; i < rows; ++i) { + for (auto j = 0U; j < cols; ++j) { + data[i * cols + j] = data_[i * cols + j]; + } + } + } + Array2D(std::vector<T> data_, uint32_t r, uint32_t c) + : rows{r}, cols{c} + { + data = new T[rows * cols]; + for (auto i = 0U; i < rows; ++i) { + for (auto j = 0U; j < cols; ++j) { + data[i * cols + j] = data_[i * cols + j]; + } + } + } + + Array2D(Array2D<T> const& other) + : rows{other.rows}, + cols{other.cols} + { + data = new T[rows * cols]; + for (auto i = 0U; i < rows; ++i) { + for (auto j = 0U; j < cols; ++j) { + data[i * cols + j] = other.data[i * cols + j]; + } + } + } + + Array2D(Array2D<T>&& other) + : rows{other.rows}, + cols{other.cols} + { + data = other.data; + other.data = nullptr; + other.rows = 0; + other.cols = 0; + } + + Array2D& operator=(Array2D<T> const& other) + { + this->rows = other.rows; + this->cols = other.cols; + data = new T[rows * cols]; + for (auto i = 0U; i < rows; ++i) { + for (auto j = 0U; j < cols; ++j) { + data[i * cols + j] = *(other.data + (i * cols + j)); + } + } + return *this; + } + + Array2D& operator=(Array2D<T>&& other) + { + this->rows = other.rows; + this->cols = other.cols; + data = other.data; + other.data = nullptr; + other.rows = 0; + other.cols = 0; + return *this; + } + + ~Array2D() + { + if (data != nullptr) { + delete[] data; + } + } + + T operator()(uint32_t y, uint32_t x) const + { + return data[y * cols + x]; + } + T* operator[](uint32_t y) const + { + return data + y * cols; + } + + T* data; + uint32_t rows; + uint32_t cols; +}; + +static constexpr const char* const labels_rows_str = "labels_rows"; +static constexpr const char* const labels_cols_str = "labels_cols"; +using labelmap_t = std::unordered_map<std::string, uint32_t>; +struct LabelMap { + LabelMap(); + LabelMap(uint32_t rows, uint32_t cols, std::vector<std::string> labels_rows_, std::vector<std::string> labels_cols_); + + LabelMap(uint32_t size, std::vector<std::string> labels); + + LabelMap(LabelMap const& other); + LabelMap(LabelMap&& other); + LabelMap& operator=(LabelMap const& other); + LabelMap& operator=(LabelMap&& other); + + labelmap_t rowmap; + labelmap_t colmap; + + std::vector<std::string> labels_rows; + std::vector<std::string> labels_cols; + + static labelmap_t populate(uint32_t size, std::vector<std::string> labels); + + auto getLabelsRows() const + { + return labels_rows; + } + + auto getLabelsCols() const + { + return labels_cols; + } + + void replaceLabelsRows(uint32_t size, std::vector<std::string> const& labels); + void replaceLabelsCols(uint32_t size, std::vector<std::string> const& labels); +}; + +template <typename T> +class LabeledArray : public LabelMap +{ + public: + using element_t = T; + + LabeledArray() + : values{}, + LabelMap{} + { + } + + LabeledArray(T const* data, uint32_t rows_, uint32_t cols_, std::vector<std::string> labels_rows_ = {}, std::vector<std::string> labels_cols_ = {}) + : values{data, rows_, cols_}, + LabelMap{rows_, cols_, labels_rows_, labels_cols_} + { + } + + LabeledArray(T const* data, uint32_t size, std::vector<std::string> labels_ = {}) + : values{data, 1, size}, + LabelMap{size, labels_} + { + } + + LabeledArray(Array2D<T> const& data, std::vector<std::string> labels_rows_ = {}, std::vector<std::string> labels_cols_ = {}) + : values{data}, + LabelMap{data.rows, data.cols, labels_rows_, labels_cols_} + { + } + + LabeledArray(LabeledArray<T> const& other) = default; + LabeledArray(LabeledArray<T>&& other) = default; + LabeledArray& operator=(LabeledArray<T> const& other) = default; + LabeledArray& operator=(LabeledArray<T>&& other) = default; + + ~LabeledArray() = default; + + T get(uint32_t y, uint32_t x) const + { + return values(y, x); + } + + T get(const char* y, const char* x) const + { + return values(rowmap.find(y)->second, colmap.find(x)->second); + } + + T get(const char* y, uint32_t x) const + { + return values(rowmap.find(y)->second, x); + } + + T get(uint32_t y, const char* x) const + { + return values(y, colmap.find(x)->second); + } + + T get(uint32_t x) const + { + return values[0][x]; + } + + T get(const char* x) const + { + return values[0][colmap.find(x)->second]; + } + + T* getRow(uint32_t y) const + { + return values[y]; + } + + T* operator[](uint32_t y) const + { + return values[y]; + } + + auto getData() const + { + return values; + } + + auto rows() const + { + return values.rows; + } + + auto cols() const + { + return values.cols; + } + + auto copy() const + { + LabeledArray<T> copy = *this; + return copy; + } + + void replaceLabelsRows(std::vector<std::string> const& labels) + { + LabelMap::replaceLabelsRows(values.rows, labels); + } + + void replaceLabelsCols(std::vector<std::string> const& labels) + { + LabelMap::replaceLabelsCols(values.cols, labels); + } + + private: + Array2D<T> values; +}; +} // namespace o2::framework + +#endif // FRAMEWORK_ARRAY2D_H diff --git a/Framework/Core/include/Framework/ArrowContext.h b/Framework/Core/include/Framework/ArrowContext.h index 4fc2f1e320462..a3b266b206e45 100644 --- a/Framework/Core/include/Framework/ArrowContext.h +++ b/Framework/Core/include/Framework/ArrowContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #include <string> #include <vector> -class FairMQMessage; +#include <fairmq/FwdDecls.h> namespace o2::framework { diff --git a/Framework/Core/include/Framework/ArrowTypes.h b/Framework/Core/include/Framework/ArrowTypes.h index c8c144c3568ba..474b2611a5eea 100644 --- a/Framework/Core/include/Framework/ArrowTypes.h +++ b/Framework/Core/include/Framework/ArrowTypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -76,6 +77,21 @@ struct arrow_array_for<double[N]> { using type = arrow::FixedSizeListArray; using value_type = double; }; +template <> +struct arrow_array_for<std::vector<int>> { + using type = arrow::ListArray; + using value_type = int; +}; +template <> +struct arrow_array_for<std::vector<float>> { + using type = arrow::ListArray; + using value_type = float; +}; +template <> +struct arrow_array_for<std::vector<double>> { + using type = arrow::ListArray; + using value_type = double; +}; template <typename T> using arrow_array_for_t = typename arrow_array_for<T>::type; diff --git a/Framework/Core/include/Framework/BasicOps.h b/Framework/Core/include/Framework/BasicOps.h index f6bbc0ebe4f08..230936832f85b 100644 --- a/Framework/Core/include/Framework/BasicOps.h +++ b/Framework/Core/include/Framework/BasicOps.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,9 @@ enum BasicOp : unsigned int { Subtraction, Division, Multiplication, + BitwiseAnd, + BitwiseOr, + BitwiseXor, LessThan, LessThanOrEqual, GreaterThan, @@ -36,7 +40,9 @@ enum BasicOp : unsigned int { Asin, Acos, Atan, - Abs + Abs, + BitwiseNot, + Conditional }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/BoostOptionsRetriever.h b/Framework/Core/include/Framework/BoostOptionsRetriever.h index 148d5c4192b20..418e4037559a4 100644 --- a/Framework/Core/include/Framework/BoostOptionsRetriever.h +++ b/Framework/Core/include/Framework/BoostOptionsRetriever.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/CCDBParamSpec.h b/Framework/Core/include/Framework/CCDBParamSpec.h new file mode 100644 index 0000000000000..21b0dc756bc37 --- /dev/null +++ b/Framework/Core/include/Framework/CCDBParamSpec.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_CCDBPARAMSPEC_H_ +#define O2_FRAMEWORK_CCDBPARAMSPEC_H_ +#include "Framework/ConfigParamSpec.h" +#include <vector> +#include <string> + +namespace o2::framework +{ + +ConfigParamSpec ccdbPathSpec(std::string const& path); +ConfigParamSpec ccdbRunDependent(bool defaultValue = true); +std::vector<ConfigParamSpec> ccdbParamSpec(std::string const& path, bool runDependent = false); +ConfigParamSpec startTimeParamSpec(int64_t t); + +} // namespace o2::framework +#endif diff --git a/Framework/Core/include/Framework/CallbackRegistry.h b/Framework/Core/include/Framework/CallbackRegistry.h index 1b72025d9a5f2..ae80a98dfdbef 100644 --- a/Framework/Core/include/Framework/CallbackRegistry.h +++ b/Framework/Core/include/Framework/CallbackRegistry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/CallbackService.h b/Framework/Core/include/Framework/CallbackService.h index a44ba60977484..5e934290d73d6 100644 --- a/Framework/Core/include/Framework/CallbackService.h +++ b/Framework/Core/include/Framework/CallbackService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include "Framework/ServiceHandle.h" #include <tuple> -class FairMQRegionInfo; +#include <fairmq/FwdDecls.h> namespace o2 { diff --git a/Framework/Core/include/Framework/ChannelConfigurationPolicy.h b/Framework/Core/include/Framework/ChannelConfigurationPolicy.h index 0fa3be6f1dd86..7ceed050092ce 100644 --- a/Framework/Core/include/Framework/ChannelConfigurationPolicy.h +++ b/Framework/Core/include/Framework/ChannelConfigurationPolicy.h @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H -#define FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H +#ifndef O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H_ +#define O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H_ #include "Framework/ChannelConfigurationPolicyHelpers.h" #include "Framework/ChannelSpec.h" @@ -16,11 +17,11 @@ #include <vector> #include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { +struct ConfigContext; + /// A ChannelConfigurationPolicy allows the user /// to customise connection method and type /// for a channel created between two devices. @@ -37,10 +38,10 @@ struct ChannelConfigurationPolicy { Helpers::InputChannelModifier modifyInput = nullptr; Helpers::OutputChannelModifier modifyOutput = nullptr; - static std::vector<ChannelConfigurationPolicy> createDefaultPolicies(); + /// Default policies to use, based on the contents of the @configContex content + static std::vector<ChannelConfigurationPolicy> createDefaultPolicies(ConfigContext const& configContext); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H +#endif // O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H_ diff --git a/Framework/Core/include/Framework/ChannelConfigurationPolicyHelpers.h b/Framework/Core/include/Framework/ChannelConfigurationPolicyHelpers.h index 5703cc3e902b1..acb24dcebfd3a 100644 --- a/Framework/Core/include/Framework/ChannelConfigurationPolicyHelpers.h +++ b/Framework/Core/include/Framework/ChannelConfigurationPolicyHelpers.h @@ -1,24 +1,30 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_CHANNELCONFIGURATIONPOLICYHELPERS_H -#define FRAMEWORK_CHANNELCONFIGURATIONPOLICYHELPERS_H +#ifndef O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICYHELPERS_H_ +#define O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICYHELPERS_H_ #include "Framework/ChannelSpec.h" #include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { +struct FairMQChannelConfigSpec { + int64_t rateLogging; + int64_t recvBufferSize; + int64_t sendBufferSize; + std::string ipcPrefix; +}; + /// A set of helpers for common ChannelConfigurationPolicy behaviors struct ChannelConfigurationPolicyHelpers { // TODO: currently we allow matching of the policy only based on @@ -41,24 +47,23 @@ struct ChannelConfigurationPolicyHelpers { // Some trivial modifier which can be used by the policy. /// Makes the passed input channel connect and subscribe - static InputChannelModifier subscribeInput; + static InputChannelModifier subscribeInput(FairMQChannelConfigSpec const& spec); /// Makes the passed output channel bind and subscribe - static OutputChannelModifier publishOutput; + static OutputChannelModifier publishOutput(FairMQChannelConfigSpec const& spec); /// Makes the passed input channel connect and pull - static InputChannelModifier pullInput; + static InputChannelModifier pullInput(FairMQChannelConfigSpec const& spec); /// Makes the passed output channel bind and push - static OutputChannelModifier pushOutput; + static OutputChannelModifier pushOutput(FairMQChannelConfigSpec const& spec); /// Makes the passed input channel connect and request - static InputChannelModifier reqInput; + static InputChannelModifier reqInput(FairMQChannelConfigSpec const& spec); /// Makes the passed output channel bind and reply - static OutputChannelModifier replyOutput; + static OutputChannelModifier replyOutput(FairMQChannelConfigSpec const& spec); /// Makes the passed input channel connect and pair - static InputChannelModifier pairInput; + static InputChannelModifier pairInput(FairMQChannelConfigSpec const& spec); /// Makes the passed output channel bind and pair - static OutputChannelModifier pairOutput; + static OutputChannelModifier pairOutput(FairMQChannelConfigSpec const& spec); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H +#endif // O2_FRAMEWORK_CHANNELCONFIGURATIONPOLICY_H_ diff --git a/Framework/Core/include/Framework/ChannelInfo.h b/Framework/Core/include/Framework/ChannelInfo.h index 45779f3866a74..360b578ce9d48 100644 --- a/Framework/Core/include/Framework/ChannelInfo.h +++ b/Framework/Core/include/Framework/ChannelInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,9 @@ #define O2_FRAMEWORK_CHANNELINFO_H #include <string> +#include <FairMQParts.h> + +#include <fairmq/FwdDecls.h> namespace o2::framework { @@ -31,6 +35,9 @@ enum struct InputChannelState { /// updated by Control or by the by the incoming flow of messages. struct InputChannelInfo { InputChannelState state = InputChannelState::Running; + uint32_t hasPendingEvents = 0; + FairMQChannel* channel = nullptr; + FairMQParts parts; }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/ChannelMatching.h b/Framework/Core/include/Framework/ChannelMatching.h index f12f9586b9d8f..87b2b70576919 100644 --- a/Framework/Core/include/Framework/ChannelMatching.h +++ b/Framework/Core/include/Framework/ChannelMatching.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ChannelSpec.h b/Framework/Core/include/Framework/ChannelSpec.h index 7b9601722edab..5cc2bfb5d5a7a 100644 --- a/Framework/Core/include/Framework/ChannelSpec.h +++ b/Framework/Core/include/Framework/ChannelSpec.h @@ -1,20 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_CHANNELSPEC_H -#define FRAMEWORK_CHANNELSPEC_H +#ifndef O2_FRAMEWORK_CHANNELSPEC_H_ +#define O2_FRAMEWORK_CHANNELSPEC_H_ #include <string> -namespace o2 -{ -namespace framework +namespace o2::framework { /// These map to zeromq connection @@ -50,6 +49,10 @@ struct InputChannelSpec { std::string hostname; unsigned short port; ChannelProtocol protocol = ChannelProtocol::Network; + size_t rateLogging = 0; + size_t recvBufferSize = 1000; + size_t sendBufferSize = 1000; + std::string ipcPrefix = "."; }; /// This describes an output channel. Output channels are semantically @@ -65,9 +68,12 @@ struct OutputChannelSpec { unsigned short port; size_t listeners; ChannelProtocol protocol = ChannelProtocol::Network; + size_t rateLogging = 0; + size_t recvBufferSize = 1000; + size_t sendBufferSize = 1000; + std::string ipcPrefix = "."; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_CHANNELSPEC_H +#endif // O2_FRAMEWORK_CHANNELSPEC_H_ diff --git a/Framework/Core/include/Framework/CommandInfo.h b/Framework/Core/include/Framework/CommandInfo.h new file mode 100644 index 0000000000000..b101867c6eda0 --- /dev/null +++ b/Framework/Core/include/Framework/CommandInfo.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_COMMANDINFO_H_ +#define O2_FRAMEWORK_COMMANDINFO_H_ + +#include <string> + +namespace o2::framework +{ + +struct CommandInfo { + CommandInfo() = default; + CommandInfo(std::string command) : command(std::move(command)) {} + CommandInfo(int argc, char* const* argv); + + void merge(CommandInfo const& other); + + std::string command; +}; + +} // namespace o2::framework + +#endif //O2_FRAMEWORK_COMMANDINFO_H_ \ No newline at end of file diff --git a/Framework/Core/include/Framework/CommonDataProcessors.h b/Framework/Core/include/Framework/CommonDataProcessors.h index fbdff88521022..738eb7a48a059 100644 --- a/Framework/Core/include/Framework/CommonDataProcessors.h +++ b/Framework/Core/include/Framework/CommonDataProcessors.h @@ -1,32 +1,47 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef o2_framework_CommonDataProcessors_H_INCLUDED -#define o2_framework_CommonDataProcessors_H_INCLUDED +#ifndef O2_FRAMEWORK_COMMONDATAPROCESSORS_H_ +#define O2_FRAMEWORK_COMMONDATAPROCESSORS_H_ #include "Framework/DataProcessorSpec.h" #include "Framework/InputSpec.h" -#include "Framework/DataOutputDirector.h" -#include "TTree.h" #include <vector> +#include <string> namespace o2::framework { -using outputTasks = std::vector<std::pair<uint32_t, std::string>>; -using outputObjects = std::vector<std::pair<uint32_t, std::vector<std::string>>>; +class DataOutputDirector; + +struct OutputTaskInfo { + uint32_t id; + std::string name; +}; + +struct OutputObjectInfo { + uint32_t id; + std::vector<std::string> bindings; +}; +} // namespace o2::framework +extern template class std::vector<o2::framework::OutputObjectInfo>; +extern template class std::vector<o2::framework::OutputTaskInfo>; +namespace o2::framework +{ /// Helpers to create a few general data processors struct CommonDataProcessors { /// Match all inputs of kind ATSK and write them to a ROOT file, /// one root file per originating task. - static DataProcessorSpec getOutputObjHistSink(outputObjects const& objmap, const outputTasks& tskmap); + static DataProcessorSpec getOutputObjHistSink(std::vector<OutputObjectInfo> const& objmap, + std::vector<OutputTaskInfo> const& tskmap); /// Given the list of @a danglingInputs @return a DataProcessor which does /// a binary dump for all the dangling inputs matching the Timeframe /// lifetime. @a unmatched will be filled with all the InputSpecs which are diff --git a/Framework/Core/include/Framework/CommonMessageBackends.h b/Framework/Core/include/Framework/CommonMessageBackends.h index 048e2ef6648b4..bb5d16e5fcf35 100644 --- a/Framework/Core/include/Framework/CommonMessageBackends.h +++ b/Framework/Core/include/Framework/CommonMessageBackends.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,10 +19,6 @@ namespace o2::framework /// A few ServiceSpecs data sending backends struct CommonMessageBackends { - // Rate limiting service - static ServiceSpec rateLimitingSpec(); - // Create spec for backend used to send Arrow messages - static ServiceSpec arrowBackendSpec(); static ServiceSpec fairMQBackendSpec(); static ServiceSpec stringBackendSpec(); static ServiceSpec rawBufferBackendSpec(); diff --git a/Framework/Core/include/Framework/CommonServices.h b/Framework/Core/include/Framework/CommonServices.h index 6c26583efedd8..a25485ad8d1ca 100644 --- a/Framework/Core/include/Framework/CommonServices.h +++ b/Framework/Core/include/Framework/CommonServices.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,8 @@ #include "Framework/ServiceSpec.h" #include "Framework/TypeIdHelpers.h" +class TDatabasePDG; + namespace o2::framework { @@ -47,7 +50,9 @@ struct CommonServices { return [](InitContext&, void* service) -> void* { return service; }; } + static ServiceSpec driverClientSpec(); static ServiceSpec monitoringSpec(); + static ServiceSpec datatakingContextSpec(); static ServiceSpec infologgerContextSpec(); static ServiceSpec infologgerSpec(); static ServiceSpec configurationSpec(); @@ -66,6 +71,18 @@ struct CommonServices { static std::vector<ServiceSpec> requiredServices(); }; +struct CommonAnalysisServices { + static ServiceSpec databasePDGSpec(); + + template <typename T> + static void addAnalysisService(std::vector<ServiceSpec>& specs) + { + if constexpr (std::is_same_v<T, TDatabasePDG>) { + specs.push_back(databasePDGSpec()); + } + } +}; + } // namespace o2::framework #endif // O2_FRAMEWORK_COMMONSERVICES_H_ diff --git a/Framework/Core/include/Framework/CompletionPolicy.h b/Framework/Core/include/Framework/CompletionPolicy.h index 267274c68ed4c..8e9702fb2ce5b 100644 --- a/Framework/Core/include/Framework/CompletionPolicy.h +++ b/Framework/Core/include/Framework/CompletionPolicy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,6 @@ #define FRAMEWORK_COMPLETIONPOLICY_H #include "Framework/DataRef.h" -#include "Framework/InputSpan.h" #include <functional> #include <string> @@ -24,6 +24,7 @@ namespace framework struct DeviceSpec; struct InputRecord; +struct InputSpan; /// Policy to describe what to do for a matching DeviceSpec /// whenever a new message arrives. The InputRecord being passed to @@ -50,8 +51,7 @@ struct CompletionPolicy { using Matcher = std::function<bool(DeviceSpec const& device)>; using InputSetElement = DataRef; - using InputSet = InputSpan const&; - using Callback = std::function<CompletionOp(InputSet)>; + using Callback = std::function<CompletionOp(InputSpan const&)>; /// Name of the policy itself. std::string name = ""; diff --git a/Framework/Core/include/Framework/CompletionPolicyHelpers.h b/Framework/Core/include/Framework/CompletionPolicyHelpers.h index ea892feb1852d..041f509db3e2a 100644 --- a/Framework/Core/include/Framework/CompletionPolicyHelpers.h +++ b/Framework/Core/include/Framework/CompletionPolicyHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ComputingQuotaEvaluator.h b/Framework/Core/include/Framework/ComputingQuotaEvaluator.h new file mode 100644 index 0000000000000..a90e1062b42e4 --- /dev/null +++ b/Framework/Core/include/Framework/ComputingQuotaEvaluator.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_COMPUTINGQUOTAEVALUATOR_H_ +#define O2_COMPUTINGQUOTAEVALUATOR_H_ + +#include "Framework/ComputingQuotaOffer.h" + +#include <cstdint> +#include <functional> +#include <array> +#include <vector> +#include <cstddef> + +typedef struct uv_loop_s uv_loop_t; + +namespace o2::framework +{ +struct ServiceRegistry; + +class ComputingQuotaEvaluator +{ + public: + // Maximum number of offers this evaluator can hold + static constexpr int MAX_INFLIGHT_OFFERS = 16; + // @a now the current time when the register was created. E.g. what uv_now returns. + ComputingQuotaEvaluator(uint64_t now); + /// @a task the task which needs some quota + /// @a request the resource request the @a task needs + /// @a now the time (e.g. uv_now) when invoked. + bool selectOffer(int task, ComputingQuotaRequest const& request, uint64_t now); + /// Consume offers for a given taskId + /// @a reportConsumedOffer callback which reports back that an offer has been consumed. + void consume(int taskId, + ComputingQuotaConsumer& consumed, + std::function<void(ComputingQuotaOffer const& accumulatedConsumed, ComputingQuotaStats&)>& reportConsumedOffer); + /// Dispose offers for a given taskId + void dispose(int taskId); + /// Handle all the offers which have timed out giving + /// them back to the driver. + /// @a expirator callback with expired offers + void handleExpired(std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats const&)> reportExpired); + /// @a now the time (e.g. uv_now) when invoked. + void updateOffers(std::vector<ComputingQuotaOffer>& offers, uint64_t now); + + /// All the available offerts + std::array<ComputingQuotaOffer, MAX_INFLIGHT_OFFERS> mOffers; + /// The offers which expired and need to be given back. + std::vector<ComputingQuotaOfferRef> mExpiredOffers; + /// Information about a given computing offer (e.g. when it was started to be used) + std::array<ComputingQuotaInfo, MAX_INFLIGHT_OFFERS> mInfos; + ComputingQuotaStats mStats; +}; + +} // namespace o2::framework + +#endif // O2_COMPUTINGQUOTAEVALUATOR_H_ diff --git a/Framework/Core/include/Framework/ComputingQuotaOffer.h b/Framework/Core/include/Framework/ComputingQuotaOffer.h new file mode 100644 index 0000000000000..f457f46eef774 --- /dev/null +++ b/Framework/Core/include/Framework/ComputingQuotaOffer.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_COMPUTINGQUOTAOFFER_H_ +#define O2_COMPUTINGQUOTAOFFER_H_ + +#include <functional> +#include <cstdint> +#include <cstddef> + +namespace o2::framework +{ + +struct ComputingQuotaOfferRef { + int index; +}; + +enum struct OfferScore { + // The offers seen so far are enough. We can proceed with the dataprocessing. + Enough, + // The offers seen so far are not enough, but the current one + // is ok and we need to look for more. + More, + // The offer is not needed, but something else in the device + // might use it. + Unneeded, + // The offer is not suitable and should be given back to the + // driver. + Unsuitable +}; + +struct ComputingQuotaOffer { + /// How many cores it can use + int cpu = 0; + /// How much memory it can use + int64_t memory = 0; + /// How much shared memory it can allocate + int64_t sharedMemory = 0; + /// How much runtime it can use before giving back the resource + /// in milliseconds. + int64_t runtime = 0; + /// Which task is using the offer + int user = -1; + /// The score for the given offer + OfferScore score = OfferScore::Unneeded; + /// Whether or not the offer is valid, invalid offers can + /// be reused whe we get some more quota from the system. + bool valid = false; +}; + +struct ComputingQuotaInfo { + // When the offer was received + size_t received = 0; + // First time it was used + size_t firstUsed = 0; + // Last time it was used + size_t lastUsed = 0; +}; + +/// Statistics on the offers consumed, expired +struct ComputingQuotaStats { + int64_t totalConsumedBytes = 0; + int64_t totalConsumedOffers = 0; + int64_t totalExpiredBytes = 0; + int64_t totalExpiredOffers = 0; +}; + +/// A request is a function which gets applied to all available +/// offers one after the other. If the offer itself is deemed +/// is ok for running. +using ComputingQuotaRequest = std::function<OfferScore(ComputingQuotaOffer const& offer, ComputingQuotaOffer const& accumulated)>; + +/// A consumer is a function which updates a given function removing the +/// amount of resources which are considered as consumed. +using ComputingQuotaConsumer = std::function<void(int id, std::array<ComputingQuotaOffer, 16>&, ComputingQuotaStats&, std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats& stats)>)>; + +} // namespace o2::framework + +#endif // O2_COMPUTINGQUOTAOFFER_H_ diff --git a/Framework/Core/include/Framework/ComputingResource.h b/Framework/Core/include/Framework/ComputingResource.h index 27b54005ff315..686142684c3d7 100644 --- a/Framework/Core/include/Framework/ComputingResource.h +++ b/Framework/Core/include/Framework/ComputingResource.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ConcreteDataMatcher.h b/Framework/Core/include/Framework/ConcreteDataMatcher.h index 9f3f7cbf0474e..247e3cd6ed8b9 100644 --- a/Framework/Core/include/Framework/ConcreteDataMatcher.h +++ b/Framework/Core/include/Framework/ConcreteDataMatcher.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ConfigContext.h b/Framework/Core/include/Framework/ConfigContext.h index b134e11fe9edf..7eaa2b873fb92 100644 --- a/Framework/Core/include/Framework/ConfigContext.h +++ b/Framework/Core/include/Framework/ConfigContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ConfigParamRegistry.h b/Framework/Core/include/Framework/ConfigParamRegistry.h index f0b96fe8bf75b..f7bf011abaf00 100644 --- a/Framework/Core/include/Framework/ConfigParamRegistry.h +++ b/Framework/Core/include/Framework/ConfigParamRegistry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,15 +13,34 @@ #include "Framework/ParamRetriever.h" #include "Framework/ConfigParamStore.h" +#include "Framework/Traits.h" +#include "Framework/VariantPropertyTreeHelpers.h" #include <boost/property_tree/ptree.hpp> #include <memory> #include <string> #include <cassert> -namespace o2::framework +namespace +{ +template <typename T> +constexpr auto isSimpleType() { + return std::is_same_v<T, int> || + std::is_same_v<T, uint8_t> || + std::is_same_v<T, uint16_t> || + std::is_same_v<T, uint32_t> || + std::is_same_v<T, uint64_t> || + std::is_same_v<T, int64_t> || + std::is_same_v<T, long> || + std::is_same_v<T, float> || + std::is_same_v<T, double> || + std::is_same_v<T, bool>; +} +} // namespace +namespace o2::framework +{ class ConfigParamStore; /// This provides unified access to the parameters specified in the workflow @@ -52,17 +72,18 @@ class ConfigParamRegistry { assert(mStore.get()); try { - if constexpr (std::is_same_v<T, int> || - std::is_same_v<T, int64_t> || - std::is_same_v<T, long> || - std::is_same_v<T, float> || - std::is_same_v<T, double> || - std::is_same_v<T, bool>) { + if constexpr (isSimpleType<T>()) { return mStore->store().get<T>(key); } else if constexpr (std::is_same_v<T, std::string>) { return mStore->store().get<std::string>(key); } else if constexpr (std::is_same_v<T, std::string_view>) { return std::string_view{mStore->store().get<std::string>(key)}; + } else if constexpr (is_base_of_template<std::vector, T>::value) { + return vectorFromBranch<typename T::value_type>(mStore->store().get_child(key)); + } else if constexpr (is_base_of_template<o2::framework::Array2D, T>::value) { + return array2DFromBranch<typename T::element_t>(mStore->store().get_child(key)); + } else if constexpr (is_base_of_template<o2::framework::LabeledArray, T>::value) { + return labeledArrayFromBranch<typename T::element_t>(mStore->store().get_child(key)); } else if constexpr (std::is_same_v<T, boost::property_tree::ptree>) { return mStore->store().get_child(key); } else if constexpr (std::is_constructible_v<T, boost::property_tree::ptree>) { @@ -76,6 +97,7 @@ class ConfigParamRegistry } catch (...) { throw std::invalid_argument(std::string("error parsing option: ") + key); } + throw std::invalid_argument(std::string("bad type for option: ") + key); } private: diff --git a/Framework/Core/include/Framework/ConfigParamSpec.h b/Framework/Core/include/Framework/ConfigParamSpec.h index 7065ab0a53d3e..5936cc0bde192 100644 --- a/Framework/Core/include/Framework/ConfigParamSpec.h +++ b/Framework/Core/include/Framework/ConfigParamSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,14 +12,12 @@ #define FRAMEWORK_CONFIGPARAMSPEC_H #include "Framework/Variant.h" +#include "Framework/ConfigurableKinds.h" #include <string> -namespace o2 +namespace o2::framework { -namespace framework -{ - /// @class ConfigParamSpec Definition of options for a processor /// An option definition consists of a name, a type, a help message, and /// an optional default value. The type of the argument has to be specified @@ -38,28 +37,30 @@ struct ConfigParamSpec { }; template <typename T> ConfigParamSpec(std::string, ParamType, Variant, T) - : type(VariantType::Unknown) + : type(VariantType::Unknown), kind{ConfigParamKind::kGeneric} { static_assert(std::is_same<T, HelpString>::value, R"(help string must be brace-enclosed, e.g. '{"help"}')"); } ConfigParamSpec(std::string _name, ParamType _type, - Variant _defaultValue, HelpString _help) - : name(_name), type(_type), defaultValue(_defaultValue), help(_help) {} + Variant _defaultValue, HelpString _help, ConfigParamKind kind_ = ConfigParamKind::kGeneric) + : name(_name), type(_type), defaultValue(_defaultValue), help(_help), kind{kind_} + { + } /// config spec without default value, explicitely marked as 'empty' /// and will be ignored at other places ConfigParamSpec(std::string _name, ParamType _type, HelpString _help) - : name(_name), type(_type), defaultValue(VariantType::Empty), help(_help) {} + : name(_name), type(_type), defaultValue(VariantType::Empty), help(_help), kind{ConfigParamKind::kGeneric} {} std::string name; ParamType type; Variant defaultValue; HelpString help; + ConfigParamKind kind; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // FRAMEWORK_CONFIGPARAMSPEC_H diff --git a/Framework/Core/include/Framework/ConfigParamStore.h b/Framework/Core/include/Framework/ConfigParamStore.h index ff775818af844..37442a6cf7f41 100644 --- a/Framework/Core/include/Framework/ConfigParamStore.h +++ b/Framework/Core/include/Framework/ConfigParamStore.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,12 @@ class ConfigParamStore boost::property_tree::ptree& store() { return *mStore; }; boost::property_tree::ptree& provenanceTree() { return *mProvenance; }; + /// Get the specs + std::vector<ConfigParamSpec> const& specs() const + { + return mSpecs; + } + /// Activate the next store void activate(); diff --git a/Framework/Core/include/Framework/ConfigParamsHelper.h b/Framework/Core/include/Framework/ConfigParamsHelper.h index 54c2c28e8cf0a..4dc974549a2bb 100644 --- a/Framework/Core/include/Framework/ConfigParamsHelper.h +++ b/Framework/Core/include/Framework/ConfigParamsHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,9 +19,7 @@ #include <string> #include <type_traits> -namespace o2 -{ -namespace framework +namespace o2::framework { using options_description = boost::program_options::options_description; @@ -36,7 +35,11 @@ struct ConfigParamsHelper { /// all options which are found in the vetos are skipped static bool dpl2BoostOptions(const std::vector<ConfigParamSpec>& spec, options_description& options, - options_description vetos = options_description()); + boost::program_options::options_description vetos = options_description()); + + /// Add the ConfigParamSpec @a spec to @a specs if there is no parameter with + /// the same name already. + static void addOptionIfMissing(std::vector<ConfigParamSpec>& specs, ConfigParamSpec spec); /// populate boost program options for a complete workflow template <typename ContainerType> @@ -101,22 +104,33 @@ struct ConfigParamsHelper { { const char* name = spec.name.c_str(); const char* help = spec.help.c_str(); - using Type = typename variant_type<V>::type; - using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type; - auto value = boost::program_options::value<BoostType>(); - if (spec.defaultValue.type() != VariantType::Empty) { - // set the default value if provided in the config spec - value = value->default_value(spec.defaultValue.get<Type>()); - } - if (V == VariantType::Bool) { - // for bool values we also support the zero_token option to make - // the option usable as a single switch - value = value->zero_tokens(); + + if constexpr (isSimpleVariant<V>()) { + using Type = typename variant_type<V>::type; + using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type; + auto value = boost::program_options::value<BoostType>(); + value = value->default_value(spec.defaultValue.get<BoostType>()); + if constexpr (V == VariantType::Bool) { + // for bool values we also support the zero_token option to make + // the option usable as a single switch + value = value->zero_tokens(); + } + options.add_options()(name, value, help); + } else if constexpr (isArray<V>() || isArray2D<V>()) { + auto value = boost::program_options::value<std::string>(); + value = value->default_value(spec.defaultValue.asString()); + if constexpr (V != VariantType::String) { + value = value->multitoken(); + } + options.add_options()(name, value, help); + } else { + using Type = typename variant_type<V>::type; + using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type; + auto value = boost::program_options::value<BoostType>(); + options.add_options()(name, value, help); } - options.add_options()(name, value, help); } }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // FRAMEWORK_CONFIGPARAMSHELPER_H diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index 118e7afa99d93..df82d479edbc2 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -1,33 +1,42 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #ifndef O2_FRAMEWORK_CONFIGURABLE_H_ #define O2_FRAMEWORK_CONFIGURABLE_H_ +#include "Framework/ConfigurableKinds.h" #include <string> +#include <vector> namespace o2::framework { -template <typename T> +namespace expressions +{ +struct PlaceholderNode; +} + +template <typename T, ConfigParamKind K> struct ConfigurableBase { ConfigurableBase(std::string const& name, T&& defaultValue, std::string const& help) - : name(name), value{std::move(defaultValue)}, help(help) + : name(name), value{std::forward<T>(defaultValue)}, help(help) { } using type = T; std::string name; T value; std::string help; + static constexpr ConfigParamKind kind = K; }; -template <typename T> -struct ConfigurablePolicyConst : ConfigurableBase<T> { +template <typename T, ConfigParamKind K> +struct ConfigurablePolicyConst : ConfigurableBase<T, K> { ConfigurablePolicyConst(std::string const& name, T&& defaultValue, std::string const& help) - : ConfigurableBase<T>{name, std::forward<T>(defaultValue), help} + : ConfigurableBase<T, K>{name, std::forward<T>(defaultValue), help} { } operator T() @@ -40,10 +49,10 @@ struct ConfigurablePolicyConst : ConfigurableBase<T> { } }; -template <typename T> -struct ConfigurablePolicyMutable : ConfigurableBase<T> { +template <typename T, ConfigParamKind K> +struct ConfigurablePolicyMutable : ConfigurableBase<T, K> { ConfigurablePolicyMutable(std::string const& name, T&& defaultValue, std::string const& help) - : ConfigurableBase<T>{name, std::forward<T>(defaultValue), help} + : ConfigurableBase<T, K>{name, std::forward<T>(defaultValue), help} { } operator T() @@ -58,22 +67,43 @@ struct ConfigurablePolicyMutable : ConfigurableBase<T> { /// This helper allows you to create a configurable option associated to a task. /// Internally it will be bound to a ConfigParamSpec. -template <typename T, typename IP = ConfigurablePolicyConst<T>> +template <typename T, ConfigParamKind K = ConfigParamKind::kGeneric, typename IP = ConfigurablePolicyConst<T, K>> struct Configurable : IP { Configurable(std::string const& name, T&& defaultValue, std::string const& help) : IP{name, std::forward<T>(defaultValue), help} { } + auto node() + { + return expressions::PlaceholderNode{*this}; + } +}; + +template <typename T, ConfigParamKind K = ConfigParamKind::kGeneric> +using MutableConfigurable = Configurable<T, K, ConfigurablePolicyMutable<T, K>>; + +using ConfigurableAxis = Configurable<std::vector<double>, ConfigParamKind::kAxisSpec, ConfigurablePolicyConst<std::vector<double>, ConfigParamKind::kAxisSpec>>; + +template <typename R, typename T, typename... As> +struct ProcessConfigurable : Configurable<bool, ConfigParamKind::kProcessFlag> { + ProcessConfigurable(R (T::*process_)(As...), std::string const& name_, bool&& value_, std::string const& help_) + : process{process_}, + Configurable<bool, ConfigParamKind::kProcessFlag>(name_, std::forward<bool>(value_), help_) + { + } + R(T::*process) + (As...); }; -template <typename T> -using MutableConfigurable = Configurable<T, ConfigurablePolicyMutable<T>>; +#define PROCESS_SWITCH(_Class_, _Name_, _Help_, _Default_) \ + decltype(ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}) do##_Name_ = ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}; -template <typename T, typename IP> -std::ostream& operator<<(std::ostream& os, Configurable<T, IP> const& c) +template <typename T, ConfigParamKind K, typename IP> +std::ostream& operator<<(std::ostream& os, Configurable<T, K, IP> const& c) { os << c.value; return os; } + } // namespace o2::framework #endif // O2_FRAMEWORK_CONFIGURABLE_H_ diff --git a/Framework/Core/include/Framework/ConfigurableHelpers.h b/Framework/Core/include/Framework/ConfigurableHelpers.h new file mode 100644 index 0000000000000..a60b95bbf4053 --- /dev/null +++ b/Framework/Core/include/Framework/ConfigurableHelpers.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_CONFIGURABLEHELPERS_H_ +#define O2_FRAMEWORK_CONFIGURABLEHELPERS_H_ + +#include "Framework/ConfigParamSpec.h" +#include "Framework/Configurable.h" +#include "Framework/RootConfigParamHelpers.h" + +namespace o2::framework +{ + +struct ConfigurableHelpers { + template <typename T, ConfigParamKind K, typename IP> + static bool appendOption(std::vector<ConfigParamSpec>& options, Configurable<T, K, IP>& what) + { + if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) { + options.emplace_back(ConfigParamSpec{what.name, variant_trait_v<std::decay_t<T>>, what.value, {what.help}, what.kind}); + } else { + auto specs = RootConfigParamHelpers::asConfigParamSpecs<T>(what.name, what.value); + options.insert(options.end(), specs.begin(), specs.end()); + } + return true; + } +}; + +} // namespace o2::framework +#endif // O2_FRAMEWORK_CONFIGURABLEHELPERS_H_ diff --git a/Framework/Core/include/Framework/ConfigurableKinds.h b/Framework/Core/include/Framework/ConfigurableKinds.h new file mode 100644 index 0000000000000..1b811e176ab9e --- /dev/null +++ b/Framework/Core/include/Framework/ConfigurableKinds.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_CONFIGURABLEKINDS_H_ +#define O2_FRAMEWORK_CONFIGURABLEKINDS_H_ +namespace o2::framework +{ +enum ConfigParamKind : int { + kGeneric = 0, + kAxisSpec = 1, + kProcessFlag = 2 +}; +} +#endif // O2_FRAMEWORK_CONFIGURABLEKINDS_H_ diff --git a/Framework/Core/include/Framework/ControlService.h b/Framework/Core/include/Framework/ControlService.h index 0fcfdcc696b42..cfe2a83c39f42 100644 --- a/Framework/Core/include/Framework/ControlService.h +++ b/Framework/Core/include/Framework/ControlService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,10 +12,15 @@ #define O2_FRAMEWORK_CONTROLSERVICE_H_ #include "Framework/ServiceHandle.h" +#include <mutex> namespace o2::framework { +struct ServiceRegistry; +struct DeviceState; +struct DriverClient; + enum struct StreamingState : int; /// Kind of request we want to issue to control @@ -33,16 +39,24 @@ class ControlService public: constexpr static ServiceKind service_kind = ServiceKind::Global; + ControlService(ServiceRegistry& registry, DeviceState& deviceState); /// Compatibility with old API. void readyToQuit(bool all) { this->readyToQuit(all ? QuitRequest::All : QuitRequest::Me); } /// Signal control that we are potentially ready to quit some / all /// dataprocessor. - virtual void readyToQuit(QuitRequest kind) = 0; + void readyToQuit(QuitRequest kind); /// Signal that we are done with the current stream - virtual void endOfStream() = 0; + void endOfStream(); /// Report the current streaming state of a given device - virtual void notifyStreamingState(StreamingState state) = 0; + void notifyStreamingState(StreamingState state); + + private: + bool mOnce = false; + ServiceRegistry& mRegistry; + DeviceState& mDeviceState; + DriverClient& mDriverClient; + std::mutex mMutex; }; } // namespace o2::framework -#endif // O2_FRAMEWORK_ROOTFILESERVICE_H_ +#endif // O2_FRAMEWORK_CONTROLSERVICE_H_ diff --git a/Framework/Core/include/Framework/CustomWorkflowTerminationHook.h b/Framework/Core/include/Framework/CustomWorkflowTerminationHook.h index 33f8cda30543e..840b1fe2c9d15 100644 --- a/Framework/Core/include/Framework/CustomWorkflowTerminationHook.h +++ b/Framework/Core/include/Framework/CustomWorkflowTerminationHook.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,9 +11,9 @@ #ifndef CUSTOMWORKFLOWTERMINATIONHOOK_H #define CUSTOMWORKFLOWTERMINATIONHOOK_H -namespace o2 -{ -namespace framework +#include <functional> + +namespace o2::framework { /// A callback definition for a hook to be invoked when processes terminate @@ -40,7 +41,6 @@ namespace framework /// #include "Framework/runDataProcessing.h" using OnWorkflowTerminationHook = std::function<void(const char*)>; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif diff --git a/Framework/Core/include/Framework/DPLBoostSerializer.h b/Framework/Core/include/Framework/DPLBoostSerializer.h deleted file mode 100644 index 37ef91e2e541b..0000000000000 --- a/Framework/Core/include/Framework/DPLBoostSerializer.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Framework/DPLBoostSerializer.h -/// \brief DPL wrapper of common utils BoostSeralizer -/// \author Gabriele G. Fronzé <gfronze at cern.ch> -/// \date 17 July 2018 - -#ifndef ALICEO2_DPLBOOSTSERIALIZER_H -#define ALICEO2_DPLBOOSTSERIALIZER_H - -#include "Framework/DataRef.h" -#include "Framework/Output.h" -#include "CommonUtils/BoostSerializer.h" -#include "ProcessingContext.h" - -namespace o2 -{ -namespace framework -{ - -template <typename ContT> -void DPLBoostSerialize(o2::framework::ProcessingContext& ctx, const std::string& outBinding, - const ContT& dataSet) -{ - /// Serialises a data set (in the form of vector, array or list) in a message - auto buffer = o2::utils::SerializeContainer<ContT>(dataSet); - int size = buffer.str().length(); - auto msg = ctx.outputs().make<char>({outBinding}, size); - std::memcpy(&(msg[0]), buffer.str().c_str(), size); -} - -template <typename ContT> -void DPLBoostSerialize(o2::framework::ProcessingContext& ctx, const std::string& outBinding, - const ContT& dataSet, const unsigned long& nData) -{ - /// Serialises the nData elements of a data set (in the form of vector, array or list) in a message - ContT subSet(std::begin(dataSet), std::next(std::begin(dataSet), nData)); - DPLBoostSerialize(ctx, outBinding, subSet); -} - -template <typename ContT> -void DPLBoostDeserialize(const o2::framework::DataRef& msg, ContT& output) -{ - /// Deserialises a DPL msg to a container type (vector, array or list) of the provided type. - using dataH = o2::header::DataHeader; - auto payloadSize = const_cast<dataH*>(reinterpret_cast<const dataH*>(msg.header))->payloadSize; - output.clear(); - std::string msgStr(msg.payload, payloadSize); - output = std::move(o2::utils::DeserializeContainer<ContT>(msgStr)); -} -} // namespace framework -} // namespace o2 - -#endif //ALICEO2_DPLBOOSTSERIALIZER_H diff --git a/Framework/Core/include/Framework/DanglingContext.h b/Framework/Core/include/Framework/DanglingContext.h index 7b02baeb40aa5..36bbbb15b0bfa 100644 --- a/Framework/Core/include/Framework/DanglingContext.h +++ b/Framework/Core/include/Framework/DanglingContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 22f08b1f1ed9b..66428dc08afd5 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,8 +41,7 @@ #include <cstddef> // Do not change this for a full inclusion of FairMQDevice. -class FairMQDevice; -class FairMQMessage; +#include <fairmq/FwdDecls.h> namespace arrow { @@ -80,6 +80,11 @@ class DataAllocator using DataOrigin = o2::header::DataOrigin; using DataDescription = o2::header::DataDescription; using SubSpecificationType = o2::header::DataHeader::SubSpecificationType; + template <typename T> + struct UninitializedVector { + static_assert(std::is_fundamental<T>::value, "UninitializedVector only allowed for fundamental types"); + using value_type = T; + }; DataAllocator(TimingInfo* timingInfo, ServiceRegistry* contextes, @@ -100,7 +105,18 @@ class DataAllocator template <typename T, typename... Args> decltype(auto) make(const Output& spec, Args... args) { - if constexpr (is_specialization<T, std::vector>::value && has_messageable_value_type<T>::value) { + if constexpr (is_specialization<T, UninitializedVector>::value) { + // plain buffer as polymorphic spectator std::vector, which does not run constructors / destructors + using ValueType = typename T::value_type; + std::string const& channel = matchDataHeader(spec, mTimingInfo->timeslice); + auto& context = mRegistry->get<MessageContext>(); + + // Note: initial payload size is 0 and will be set by the context before sending + FairMQMessagePtr headerMessage = headerMessageFromOutput(spec, channel, o2::header::gSerializationMethodNone, 0); + return context.add<MessageContext::VectorObject<ValueType, MessageContext::ContainerRefObject<std::vector<ValueType, o2::pmr::NoConstructAllocator<ValueType>>>>>( + std::move(headerMessage), channel, 0, std::forward<Args>(args)...) + .get(); + } else if constexpr (is_specialization<T, std::vector>::value && has_messageable_value_type<T>::value) { // this catches all std::vector objects with messageable value type before checking if is also // has a root dictionary, so non-serialized transmission is preferred using ValueType = typename T::value_type; @@ -139,11 +155,12 @@ class DataAllocator }); return *reinterpret_cast<TreeToTable*>(t2tr); } else if constexpr (sizeof...(Args) == 0) { + constexpr bool isBoostSerializable = framework::is_boost_serializable<T>::value; if constexpr (is_messageable<T>::value == true) { return *reinterpret_cast<T*>(newChunk(spec, sizeof(T)).data()); } else if constexpr (is_specialization<T, BoostSerialized>::value == true) { return make_boost<typename T::wrapped_type>(std::move(spec)); - } else if constexpr (is_specialization<T, BoostSerialized>::value == false && framework::is_boost_serializable<T>::value == true && std::is_base_of<std::string, T>::value == false) { + } else if constexpr (is_specialization<T, BoostSerialized>::value == false && isBoostSerializable == true && std::is_base_of<std::string, T>::value == false) { return make_boost<T>(std::move(spec)); } else { static_assert(always_static_assert_v<T>, ERROR_STRING); @@ -281,7 +298,9 @@ class DataAllocator if constexpr (std::is_pointer<typename T::value_type>::value == false) { // vector of elements - memcpy(payloadMessage->GetData(), object.data(), sizeInBytes); + if (object.data() && sizeInBytes) { + memcpy(payloadMessage->GetData(), object.data(), sizeInBytes); + } } else { // serialize vector of pointers to elements auto target = reinterpret_cast<unsigned char*>(payloadMessage->GetData()); diff --git a/Framework/Core/include/Framework/DataChunk.h b/Framework/Core/include/Framework/DataChunk.h index 9e172029a99ca..664092216a0ee 100644 --- a/Framework/Core/include/Framework/DataChunk.h +++ b/Framework/Core/include/Framework/DataChunk.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataDescriptorMatcher.h b/Framework/Core/include/Framework/DataDescriptorMatcher.h index fc72f5d2f0d8c..bb809faa0c8cc 100644 --- a/Framework/Core/include/Framework/DataDescriptorMatcher.h +++ b/Framework/Core/include/Framework/DataDescriptorMatcher.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,14 +21,12 @@ #include <cstdint> #include <iosfwd> #include <string> +#if !defined(__CLING__) && !defined(__ROOTCLING__) #include <variant> +#endif #include <vector> -namespace o2 -{ -namespace framework -{ -namespace data_matcher +namespace o2::framework::data_matcher { /// Marks an empty item in the context @@ -43,12 +42,25 @@ struct ContextRef { inline bool operator==(ContextRef const& other) const; }; +/// Special positions for variables in context. +enum ContextPos { + STARTTIME_POS = 0, /// The DataProcessingHeader::startTime associated to the timeslice + TFCOUNTER_POS = 14, /// The DataHeader::tfCounter associated to the timeslice + FIRSTTFORBIT_POS = 15, /// The DataHeader::firstTFOrbit associated to the timeslice + RUNNUMBER_POS = 13 /// The DataHeader::runNumber associated to the timeslice +}; + /// An element of the matching context. Context itself is really a vector of /// those. It's up to the matcher builder to build the vector in a suitable way. /// We do not have any float in the value, because AFAICT there is no need for /// it in the O2 DataHeader, however we could add it later on. struct ContextElement { + +#if !defined(__CLING__) && !defined(__ROOTCLING__) using Value = std::variant<uint32_t, uint64_t, std::string, None>; +#else + using Value = None; +#endif std::string label; /// The name of the variable contained in this element. Value value = None{}; /// The actual contents of the element. }; @@ -115,11 +127,17 @@ class ValueHolder template <typename VISITOR> decltype(auto) visit(VISITOR visitor) const { +#if !defined(__CLING__) && !defined(__ROOTCLING__) return std::visit(visitor, mValue); +#else + return ContextRef{}; +#endif } protected: +#if !defined(__CLING__) && !defined(__ROOTCLING__) std::variant<T, ContextRef> mValue; +#endif }; /// Something which can be matched against a header::DataOrigin @@ -180,7 +198,7 @@ class StartTimeValueMatcher : public ValueHolder<uint64_t> /// This will match the timing information which is currently in /// the DataProcessingHeader. Notice how we apply the scale to the /// actual values found. - bool match(DataProcessingHeader const& dph, VariableContext& context) const; + bool match(header::DataHeader const& dh, DataProcessingHeader const& dph, VariableContext& context) const; private: uint64_t mScale; @@ -220,8 +238,12 @@ struct DescriptorMatcherTrait<header::DataHeader::SubSpecificationType> { using Matcher = SubSpecificationTypeValueMatcher; }; +#if !defined(__CLING__) && !defined(__ROOTCLING__) class DataDescriptorMatcher; using Node = std::variant<OriginValueMatcher, DescriptionValueMatcher, SubSpecificationTypeValueMatcher, std::unique_ptr<DataDescriptorMatcher>, ConstantValueMatcher, StartTimeValueMatcher>; +#else +using Node = ConstantValueMatcher; +#endif // A matcher for a given O2 Data Model descriptor. We use a variant to hold // the different kind of matchers so that we can have a hierarchy or @@ -244,7 +266,7 @@ class DataDescriptorMatcher DataDescriptorMatcher& operator=(DataDescriptorMatcher&& other) = default; /// Unary operator on a node - DataDescriptorMatcher(Op op, Node&& lhs, Node&& rhs = std::move(ConstantValueMatcher{false})); + DataDescriptorMatcher(Op op, Node&& lhs, Node&& rhs = ConstantValueMatcher{false}); inline ~DataDescriptorMatcher() = default; @@ -276,9 +298,7 @@ class DataDescriptorMatcher Node mRight; }; -} // namespace data_matcher -} // namespace framework -} // namespace o2 +} // namespace o2::framework::data_matcher // This is to work around CLING issues when parsing // GCC 7.3.0 std::variant implementation as described by: diff --git a/Framework/Core/include/Framework/DataDescriptorMatcher.inc b/Framework/Core/include/Framework/DataDescriptorMatcher.inc index 8e1b86d45d585..4890bbd35fe3c 100644 --- a/Framework/Core/include/Framework/DataDescriptorMatcher.inc +++ b/Framework/Core/include/Framework/DataDescriptorMatcher.inc @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataDescriptorQueryBuilder.h b/Framework/Core/include/Framework/DataDescriptorQueryBuilder.h index fd3d82328e751..8df647f5243d4 100644 --- a/Framework/Core/include/Framework/DataDescriptorQueryBuilder.h +++ b/Framework/Core/include/Framework/DataDescriptorQueryBuilder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataInputDirector.h b/Framework/Core/include/Framework/DataInputDirector.h index a059dafa8348d..d9ef37763e611 100644 --- a/Framework/Core/include/Framework/DataInputDirector.h +++ b/Framework/Core/include/Framework/DataInputDirector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,11 +19,8 @@ #include <regex> #include "rapidjson/fwd.h" -namespace o2 +namespace o2::framework { -namespace framework -{ -using namespace rapidjson; struct FileNameHolder { std::string fileName; @@ -72,6 +70,7 @@ struct DataInputDescriptor { uint64_t getTimeFrameNumber(int counter, int numTF); FileAndFolder getFileFolder(int counter, int numTF); + int getTimeFramesInFile(int counter); void closeInputFile(); bool isAlienSupportOn() { return mAlienSupport; } @@ -117,6 +116,7 @@ struct DataInputDirector { TTree* getDataTree(header::DataHeader dh, int counter, int numTF); uint64_t getTimeFrameNumber(header::DataHeader dh, int counter, int numTF); FileAndFolder getFileFolder(header::DataHeader dh, int counter, int numTF); + int getTimeFramesInFile(header::DataHeader dh, int counter); private: std::string minputfilesFile; @@ -130,11 +130,10 @@ struct DataInputDirector { bool mDebugMode = false; bool mAlienSupport = false; - bool readJsonDocument(Document* doc); + bool readJsonDocument(rapidjson::Document* doc); bool isValid(); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // o2_framework_DataInputDirector_H_INCLUDED diff --git a/Framework/Core/include/Framework/DataMatcherWalker.h b/Framework/Core/include/Framework/DataMatcherWalker.h index c6029905f83ee..aa2b1af7177f1 100644 --- a/Framework/Core/include/Framework/DataMatcherWalker.h +++ b/Framework/Core/include/Framework/DataMatcherWalker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataOutputDirector.h b/Framework/Core/include/Framework/DataOutputDirector.h index 4cf2fa13ad6b7..e4db6134465ef 100644 --- a/Framework/Core/include/Framework/DataOutputDirector.h +++ b/Framework/Core/include/Framework/DataOutputDirector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,8 +11,6 @@ #ifndef o2_framework_DataOutputDirector_H_INCLUDED #define o2_framework_DataOutputDirector_H_INCLUDED -#include "TFile.h" - #include "Framework/DataDescriptorQueryBuilder.h" #include "Framework/DataDescriptorMatcher.h" #include "Framework/DataSpecUtils.h" @@ -20,9 +19,9 @@ #include "rapidjson/fwd.h" -namespace o2 -{ -namespace framework +class TFile; + +namespace o2::framework { using namespace rapidjson; @@ -105,7 +104,6 @@ struct DataOutputDirector { const std::tuple<std::string, std::string, int> memptyanswer = std::make_tuple(std::string(""), std::string(""), -1); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // o2_framework_DataOutputDirector_H_INCLUDED diff --git a/Framework/Core/include/Framework/DataProcessingDevice.h b/Framework/Core/include/Framework/DataProcessingDevice.h index 89d8dd90d9f20..d51578900cbb6 100644 --- a/Framework/Core/include/Framework/DataProcessingDevice.h +++ b/Framework/Core/include/Framework/DataProcessingDevice.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define FRAMEWORK_DATAPROCESSING_DEVICE_H #include "Framework/AlgorithmSpec.h" +#include "Framework/ComputingQuotaOffer.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/DataAllocator.h" #include "Framework/DataRelayer.h" @@ -23,18 +25,21 @@ #include "Framework/TimingInfo.h" #include "Framework/TerminationPolicy.h" #include "Framework/Tracing.h" +#include "Framework/RunningWorkflowInfo.h" #include <fairmq/FairMQDevice.h> #include <fairmq/FairMQParts.h> #include <memory> #include <mutex> +#include <uv.h> namespace o2::framework { struct InputChannelInfo; struct DeviceState; +struct ComputingQuotaEvaluator; /// Context associated to a given DataProcessor. /// For the time being everything points to @@ -45,6 +50,21 @@ struct DeviceState; /// per thread and relax the locks. class DataProcessingDevice; +/// Context associated to a device. In principle +/// multiple DataProcessors can run on a Device (even if we +/// do not do it for now). +struct DeviceContext { + // These are pointers to the one owned by the DataProcessingDevice + // and therefore require actual locking + DataProcessingDevice* device = nullptr; + DeviceSpec const* spec = nullptr; + DeviceState* state = nullptr; + ComputingQuotaEvaluator* quotaEvaluator = nullptr; + DataProcessingStats* stats = nullptr; + ComputingQuotaStats* quotaStats = nullptr; + int expectedRegionCallbacks = 0; +}; + struct DataProcessorContext { // These are specific of a given context and therefore // not shared by threads. @@ -56,13 +76,7 @@ struct DataProcessorContext { // be accessed without a lock. // FIXME: move stuff here from the list below... ;-) - - // These are pointers to the one owned by the DataProcessingDevice - // and therefore require actual locking - DataProcessingDevice* device = nullptr; - DeviceSpec const* spec = nullptr; - DeviceState* state = nullptr; - + DeviceContext* deviceContext = nullptr; DataRelayer* relayer = nullptr; ServiceRegistry* registry = nullptr; std::vector<DataRelayer::RecordAction>* completed = nullptr; @@ -73,8 +87,29 @@ struct DataProcessorContext { AlgorithmSpec::ProcessCallback* statelessProcess = nullptr; AlgorithmSpec::ErrorCallback* error = nullptr; + /// Wether or not the associated DataProcessor can forward things early + bool canForwardEarly = true; + std::function<void(o2::framework::RuntimeErrorRef e, InputRecord& record)>* errorHandling = nullptr; - int* errorCount = nullptr; +}; + +struct TaskStreamRef { + int index = -1; +}; + +struct TaskStreamInfo { + /// The id of this stream + TaskStreamRef id; + /// The context of the DataProcessor being run by this task + DataProcessorContext* context; + /// The libuv task handle + uv_work_t task; + /// Wether or not this task is running + bool running = false; +}; + +struct DeviceConfigurationHelpers { + static std::unique_ptr<ConfigParamStore> getConfiguration(ServiceRegistry& registry, const char* name, std::vector<ConfigParamSpec> const& options); }; /// A device actually carrying out all the DPL @@ -82,28 +117,29 @@ struct DataProcessorContext { class DataProcessingDevice : public FairMQDevice { public: - DataProcessingDevice(DeviceSpec const& spec, ServiceRegistry&, DeviceState& state); + DataProcessingDevice(RunningDeviceRef ref, ServiceRegistry&); void Init() final; void InitTask() final; void PreRun() final; void PostRun() final; void Reset() final; void ResetTask() final; - bool ConditionalRun() final; + void Run() final; void SetErrorPolicy(enum TerminationPolicy policy) { mErrorPolicy = policy; } // Processing functions are now renetrant static void doRun(DataProcessorContext& context); static void doPrepare(DataProcessorContext& context); - static void handleData(DataProcessorContext& context, FairMQParts&, InputChannelInfo&); + static void handleData(DataProcessorContext& context, InputChannelInfo&); static bool tryDispatchComputation(DataProcessorContext& context, std::vector<DataRelayer::RecordAction>& completed); std::vector<DataProcessorContext> mDataProcessorContexes; protected: void error(const char* msg); - void fillContext(DataProcessorContext& context); + void fillContext(DataProcessorContext& context, DeviceContext& deviceContext); private: + DeviceContext mDeviceContext; /// The specification used to create the initial state of this device DeviceSpec const& mSpec; /// The current internal state of this device. @@ -124,7 +160,6 @@ class DataProcessingDevice : public FairMQDevice /// Completed actions std::vector<DataRelayer::RecordAction> mCompleted; - int mErrorCount; uint64_t mLastSlowMetricSentTimestamp = 0; /// The timestamp of the last time we sent slow metrics uint64_t mLastMetricFlushedTimestamp = 0; /// The timestamp of the last time we actually flushed metrics uint64_t mBeginIterationTimestamp = 0; /// The timestamp of when the current ConditionalRun was started @@ -133,6 +168,12 @@ class DataProcessingDevice : public FairMQDevice std::mutex mRegionInfoMutex; enum TerminationPolicy mErrorPolicy = TerminationPolicy::WAIT; /// What to do when an error arises bool mWasActive = false; /// Whether or not the device was active at last iteration. + std::vector<uv_work_t> mHandles; /// Handles to use to schedule work. + std::vector<TaskStreamInfo> mStreams; /// Information about the task running in the associated mHandle. + ComputingQuotaEvaluator& mQuotaEvaluator; /// The component which evaluates if the offer can be used to run a task + /// Handle to wake up the main loop from other threads + /// e.g. when FairMQ notifies some callback in an asynchronous way + uv_async_t* mAwakeHandle = nullptr; }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/DataProcessingHeader.h b/Framework/Core/include/Framework/DataProcessingHeader.h index 0627cf8887d6d..d295e5fc286f7 100644 --- a/Framework/Core/include/Framework/DataProcessingHeader.h +++ b/Framework/Core/include/Framework/DataProcessingHeader.h @@ -1,26 +1,24 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DATAPROCESSINGHEADER_H -#define FRAMEWORK_DATAPROCESSINGHEADER_H +#ifndef O2_FRAMEWORK_DATAPROCESSINGHEADER_H_ +#define O2_FRAMEWORK_DATAPROCESSINGHEADER_H_ #include "Headers/DataHeader.h" #include <cstdint> -#include <cstdio> #include <memory> #include <cassert> #include <chrono> -namespace o2 -{ -namespace framework +namespace o2::framework { //__________________________________________________________________________________________________ @@ -99,7 +97,6 @@ struct DataProcessingHeader : public header::BaseHeader { } }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_DATAPROCESSINGHEADER_H +#endif // O2_FRAMEWORK_DATAPROCESSINGHEADER_H_ diff --git a/Framework/Core/include/Framework/DataProcessingStats.h b/Framework/Core/include/Framework/DataProcessingStats.h index b4d9fb5c26210..1858c77a68f83 100644 --- a/Framework/Core/include/Framework/DataProcessingStats.h +++ b/Framework/Core/include/Framework/DataProcessingStats.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #ifndef O2_FRAMEWORK_DATAPROCESSINGSTATS_H_ #define O2_FRAMEWORK_DATAPROCESSINGSTATS_H_ +#include <atomic> #include <cstdint> namespace o2::framework @@ -25,11 +27,15 @@ struct DataProcessingStats { int minLatency = 0; int maxLatency = 0; }; + std::atomic<int> errorCount = 0; + std::atomic<int> exceptionCount = 0; std::atomic<int> pendingInputs = 0; std::atomic<int> incomplete = 0; std::atomic<int> inputParts = 0; std::atomic<int> lastElapsedTimeMs = 0; - std::atomic<int> lastTotalProcessedSize = 0; + std::atomic<int> lastProcessedSize = 0; + std::atomic<int> totalProcessedSize = 0; + std::atomic<int> totalSigusr1 = 0; std::atomic<uint64_t> lastSlowMetricSentTimestamp = 0; /// The timestamp of the last time we sent slow metrics std::atomic<uint64_t> lastMetricFlushedTimestamp = 0; /// The timestamp of the last time we actually flushed metrics diff --git a/Framework/Core/include/Framework/DataProcessor.h b/Framework/Core/include/Framework/DataProcessor.h index 8aa83108c5851..b0a4f97bbb60a 100644 --- a/Framework/Core/include/Framework/DataProcessor.h +++ b/Framework/Core/include/Framework/DataProcessor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,8 +11,7 @@ #ifndef O2_FRAMEWORK_DATAPROCESSOR_H_ #define O2_FRAMEWORK_DATAPROCESSOR_H_ -class FairMQDevice; -class FairMQParts; +#include <fairmq/FwdDecls.h> namespace o2::framework { @@ -21,6 +21,7 @@ class StringContext; class ArrowContext; class RawBufferContext; class ServiceRegistry; +class DeviceState; /// Helper class to send messages from a contex at the end /// of a computation. diff --git a/Framework/Core/src/DataProcessorInfo.h b/Framework/Core/include/Framework/DataProcessorInfo.h similarity index 77% rename from Framework/Core/src/DataProcessorInfo.h rename to Framework/Core/include/Framework/DataProcessorInfo.h index 5e399bc41898a..20578b99eef5d 100644 --- a/Framework/Core/src/DataProcessorInfo.h +++ b/Framework/Core/include/Framework/DataProcessorInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataProcessorLabel.h b/Framework/Core/include/Framework/DataProcessorLabel.h index 361413458b4b4..d8b5f7b78428d 100644 --- a/Framework/Core/include/Framework/DataProcessorLabel.h +++ b/Framework/Core/include/Framework/DataProcessorLabel.h @@ -1,23 +1,28 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DATAPROCESSORLABEL_H -#define FRAMEWORK_DATAPROCESSORLABEL_H +#ifndef O2_FRAMEWORK_DATAPROCESSORLABEL_H_ +#define O2_FRAMEWORK_DATAPROCESSORLABEL_H_ -namespace o2 -{ -namespace framework +#include <string> + +namespace o2::framework { /// A label that can be associated to a DataProcessorSpec struct DataProcessorLabel { std::string value; + + bool operator==(const DataProcessorLabel& rhs) const + { + return value == rhs.value; + } }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_DATAPROCESSORLABEL_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_DATAPROCESSORLABEL_H_ diff --git a/Framework/Core/include/Framework/DataProcessorSpec.h b/Framework/Core/include/Framework/DataProcessorSpec.h index c60346dc5dc4c..b3fe89a36cdb3 100644 --- a/Framework/Core/include/Framework/DataProcessorSpec.h +++ b/Framework/Core/include/Framework/DataProcessorSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataRef.h b/Framework/Core/include/Framework/DataRef.h index badd3eff57344..6aa2b8278def8 100644 --- a/Framework/Core/include/Framework/DataRef.h +++ b/Framework/Core/include/Framework/DataRef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DataRefUtils.h b/Framework/Core/include/Framework/DataRefUtils.h index 5640cde2d2d50..97ded9972bc2d 100644 --- a/Framework/Core/include/Framework/DataRefUtils.h +++ b/Framework/Core/include/Framework/DataRefUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #include <gsl/gsl> #include <type_traits> +#include <typeinfo> namespace o2::framework { @@ -149,8 +151,15 @@ struct DataRefUtils { } }); return std::move(result); + } else if constexpr (is_specialization<T, CCDBSerialized>::value == true) { + using wrapped = typename T::wrapped_type; + using DataHeader = o2::header::DataHeader; + std::unique_ptr<wrapped> result(static_cast<wrapped*>(DataRefUtils::decodeCCDB(ref, typeid(wrapped)))); + return std::move(result); } } + // Decode a CCDB object using the CcdbApi. + static void* decodeCCDB(DataRef const& ref, std::type_info const& info); static o2::header::DataHeader::PayloadSizeType getPayloadSize(const DataRef& ref) { diff --git a/Framework/Core/include/Framework/DataRelayer.h b/Framework/Core/include/Framework/DataRelayer.h index 506213c72f4b8..e318f5d1354da 100644 --- a/Framework/Core/include/Framework/DataRelayer.h +++ b/Framework/Core/include/Framework/DataRelayer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ #include <mutex> #include <vector> -class FairMQMessage; +#include <fairmq/FwdDecls.h> namespace o2::monitoring { @@ -41,6 +42,13 @@ struct DataRelayerStats { uint64_t relayedMessages = 0; /// How many messages have been successfully relayed }; +enum struct CacheEntryStatus : int { + EMPTY, + PENDING, + RUNNING, + DONE +}; + class DataRelayer { public: @@ -49,8 +57,10 @@ class DataRelayer /// methods need to be called. constexpr static ServiceKind service_kind = ServiceKind::Global; enum RelayChoice { - WillRelay, - WillNotRelay + WillRelay, /// Ownership of the data has been taken + Invalid, /// The incoming data was not valid and has been dropped + Backpressured, /// The incoming data was not relayed, because we are backpressured + Dropped /// The incoming data was not relayed and has been dropped }; struct ActivityStats { @@ -71,15 +81,27 @@ class DataRelayer /// This invokes the appropriate `InputRoute::danglingChecker` on every /// entry in the cache and if it returns true, it creates a new /// cache entry by invoking the associated `InputRoute::expirationHandler`. + /// @a createNew true if the dangling inputs are allowed to create new slots. /// @return true if there were expirations, false if not. ActivityStats processDanglingInputs(std::vector<ExpirationHandler> const&, - ServiceRegistry& context); + ServiceRegistry& context, bool createNew); + + /// This is to relay a whole set of FairMQMessages, all which are part + /// of the same set of split parts. + /// @a firstHeader is the first message of such set + /// @a restOfParts is a pointer to the rest of the messages + /// @a restSize is how many messages are there in restOfParts + /// is the header which is common across all subsequent elements. + /// Notice that we expect that the header is an O2 Header Stack + RelayChoice relay(std::unique_ptr<FairMQMessage>& firstHeader, + std::unique_ptr<FairMQMessage>* restOfParts, + size_t restSize); /// This is used to ask for relaying a given (header,payload) pair. /// Notice that we expect that the header is an O2 Header Stack /// with a DataProcessingHeader inside so that we can assess time. - RelayChoice relay(std::unique_ptr<FairMQMessage>&& header, - std::unique_ptr<FairMQMessage>&& payload); + RelayChoice relay(std::unique_ptr<FairMQMessage>& header, + std::unique_ptr<FairMQMessage>& payload); /// @returns the actions ready to be performed. void getReadyToProcess(std::vector<RecordAction>& completed); @@ -106,6 +128,16 @@ class DataRelayer /// Notice how this avoids exposing the timesliceIndex directly /// so that we can mutex on it. TimesliceId getTimesliceForSlot(TimesliceSlot slot); + + /// Mark a given slot as done so that the GUI + /// can reflect that. + void updateCacheStatus(TimesliceSlot slot, CacheEntryStatus oldStatus, CacheEntryStatus newStatus); + /// Get the firstTFOrbit associate to a given slot. + uint32_t getFirstTFOrbitForSlot(TimesliceSlot slot); + /// Get the firstTFCounter associate to a given slot. + uint32_t getFirstTFCounterForSlot(TimesliceSlot slot); + /// Get the runNumber associated to a given slot + uint32_t getRunNumberForSlot(TimesliceSlot slot); /// Remove all pending messages void clear(); @@ -126,7 +158,8 @@ class DataRelayer std::vector<size_t> mDistinctRoutesIndex; std::vector<data_matcher::DataDescriptorMatcher> mInputMatchers; std::vector<data_matcher::VariableContext> mVariableContextes; - std::vector<int> mCachedStateMetrics; + std::vector<CacheEntryStatus> mCachedStateMetrics; + size_t mMaxLanes; static std::vector<std::string> sMetricsNames; static std::vector<std::string> sVariablesMetricsNames; diff --git a/Framework/Core/include/Framework/DataSpecUtils.h b/Framework/Core/include/Framework/DataSpecUtils.h index 8af549a8f6642..252e44ac22e90 100644 --- a/Framework/Core/include/Framework/DataSpecUtils.h +++ b/Framework/Core/include/Framework/DataSpecUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -174,12 +175,21 @@ struct DataSpecUtils { /// OutputSpec static InputSpec matchingInput(OutputSpec const& spec); + /// Get the origin, if available + static std::optional<header::DataOrigin> getOptionalOrigin(InputSpec const& spec); + + /// Get the description, if available + static std::optional<header::DataDescription> getOptionalDescription(InputSpec const& spec); + /// Get the subspec, if available static std::optional<header::DataHeader::SubSpecificationType> getOptionalSubSpec(OutputSpec const& spec); /// Get the subspec, if available static std::optional<header::DataHeader::SubSpecificationType> getOptionalSubSpec(InputSpec const& spec); + /// Build a DataDescriptMatcher which does not care about the subSpec. + static data_matcher::DataDescriptorMatcher dataDescriptorMatcherFrom(ConcreteDataMatcher const& concrete); + /// Build a DataDescriptMatcher which does not care about the subSpec. static data_matcher::DataDescriptorMatcher dataDescriptorMatcherFrom(ConcreteDataTypeMatcher const& dataType); diff --git a/Framework/Core/include/Framework/DataTakingContext.h b/Framework/Core/include/Framework/DataTakingContext.h new file mode 100644 index 0000000000000..25439a24b64dc --- /dev/null +++ b/Framework/Core/include/Framework/DataTakingContext.h @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DATATAKINGCONTEXT_H_ +#define O2_FRAMEWORK_DATATAKINGCONTEXT_H_ + +#include <string> +#include <cstdint> + +namespace o2::framework +{ + +enum struct OrbitResetTimeSource : int { + Default, // The information is dummy an should not be used + User, // The information was provided by the user via either ECS or command line + Data, // The information was retrieved from the first message processed. + CTP // The information was retrieved from the CTP object in CCDB +}; + +struct DataTakingContext { + static constexpr uint64_t INVALID_RESET_TIME = 490917600; + /// The current run number + std::string runNumber = "unknown"; + /// How many orbits in a timeframe + uint64_t nOrbitsPerTF = 128; + /// The start time of the first orbit + uint64_t orbitResetTime = INVALID_RESET_TIME; + // What currently set the orbitResetTime value. + OrbitResetTimeSource source = OrbitResetTimeSource::Default; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DATATAKINGCONTEXT_H_ diff --git a/Framework/Core/include/Framework/DataTypes.h b/Framework/Core/include/Framework/DataTypes.h index 9ea0d1f9fb4c3..fe830272b4d1a 100644 --- a/Framework/Core/include/Framework/DataTypes.h +++ b/Framework/Core/include/Framework/DataTypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,20 +13,78 @@ #include <cstdint> +namespace o2::aod::collision +{ +enum CollisionFlagsRun2 : uint16_t { + Run2VertexerTracks = 0x1, + Run2VertexerZ = 0x2, + Run2Vertexer3D = 0x4, + // upper 8 bits for flags + Run2VertexerTracksWithConstraint = 0x10, + Run2VertexerTracksOnlyFitter = 0x20, + Run2VertexerTracksMultiVertex = 0x40 +}; +} // namespace o2::aod::collision namespace o2::aod::track { enum TrackTypeEnum : uint8_t { - GlobalTrack = 0, - ITSStandalone, - MFTStandalone, - Run2GlobalTrack = 254, + Track = 0, + ITSStandaloneTrack, + Run2Track = 254, Run2Tracklet = 255 }; +enum TrackFlags { + TrackTimeResIsRange = 0x1 // Gaussian or range +}; enum TrackFlagsRun2Enum { ITSrefit = 0x1, TPCrefit = 0x2, - GoldenChi2 = 0x4 + GoldenChi2 = 0x4, + // NOTE Highest 4 (29..32) bits reserved for PID hypothesis +}; +enum DetectorMapEnum : uint8_t { + ITS = 0x1, + TPC = 0x2, + TRD = 0x4, + TOF = 0x8 }; } // namespace o2::aod::track +namespace o2::aod::fwdtrack +{ +enum ForwardTrackTypeEnum : uint8_t { + GlobalMuonTrack = 0, // MFT-MCH-MID + GlobalMuonTrackOtherMatch, // MFT-MCH-MID (MCH-MID used another time) + GlobalForwardTrack, // MFT-MCH + MuonStandaloneTrack, // MCH-MID + MCHStandaloneTrack // MCH +}; +} // namespace o2::aod::fwdtrack + +namespace o2::aod::run2 +{ +enum Run2EventSelectionCut { + kINELgtZERO = 0, + kPileupInMultBins, + kConsistencySPDandTrackVertices, + kTrackletsVsClusters, + kNonZeroNContribs, + kIncompleteDAQ, + kPileUpMV, + kTPCPileUp, + kTimeRangeCut, + kEMCALEDCut, + kAliEventCutsAccepted, + kIsPileupFromSPD, + kIsV0PFPileup, + kIsTPCHVdip, + kIsTPCLaserWarmUp, + kTRDHCO, // Offline TRD cosmic trigger decision + kTRDHJT, // Offline TRD jet trigger decision + kTRDHSE, // Offline TRD single electron trigger decision + kTRDHQU, // Offline TRD quarkonium trigger decision + kTRDHEE // Offline TRD single-electron-in-EMCAL-acceptance trigger decision +}; +} // namespace o2::aod::run2 + #endif // O2_FRAMEWORK_DATATYPES_H_ diff --git a/Framework/Core/include/Framework/DebugGUI.h b/Framework/Core/include/Framework/DebugGUI.h new file mode 100644 index 0000000000000..3d779781ba103 --- /dev/null +++ b/Framework/Core/include/Framework/DebugGUI.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DEBUGUIINTERFACE_H_ +#define O2_FRAMEWORK_DEBUGUIINTERFACE_H_ + +#include "Framework/DeviceInfo.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DeviceControl.h" +#include "Framework/DataProcessorInfo.h" +#include "Framework/DeviceMetricsInfo.h" +#include "Framework/DriverInfo.h" +#include "Framework/DriverControl.h" + +#include <functional> +#include <vector> + +namespace o2::framework +{ +/// Plugin interface for DPL GUIs. +struct DebugGUI { + virtual std::function<void(void)> getGUIDebugger(std::vector<o2::framework::DeviceInfo> const& infos, + std::vector<o2::framework::DeviceSpec> const& devices, + std::vector<o2::framework::DataProcessorInfo> const& metadata, + std::vector<o2::framework::DeviceMetricsInfo> const& metricsInfos, + o2::framework::DriverInfo const& driverInfo, + std::vector<o2::framework::DeviceControl>& controls, + o2::framework::DriverControl& driverControl) = 0; + virtual void updateMousePos(float x, float y) = 0; + virtual void updateMouseButton(bool isClicked) = 0; + virtual void updateMouseWheel(int direction) = 0; + virtual void updateWindowSize(int x, int y) = 0; + virtual void keyDown(char key) = 0; + virtual void keyUp(char key) = 0; + virtual void charIn(char key) = 0; + + virtual void* initGUI(char const* windowTitle) = 0; + virtual bool pollGUI(void* context, std::function<void(void)> guiCallback) = 0; + virtual void getFrameJSON(void* data, std::ostream& json_data) = 0; + virtual void getFrameRaw(void* data, void** raw_data, int* size) = 0; + virtual bool pollGUIPreRender(void* context, float delta) = 0; + virtual void* pollGUIRender(std::function<void(void)> guiCallback) = 0; + virtual void pollGUIPostRender(void* context, void* draw_data) = 0; + virtual void disposeGUI() = 0; +}; +} // namespace o2::framework +#endif // O2_FRAMEWORK_DEBUGUIINTERFACE_H_ diff --git a/Framework/Core/include/Framework/DeviceConfigInfo.h b/Framework/Core/include/Framework/DeviceConfigInfo.h index d343021d8fd57..e4a15615df728 100644 --- a/Framework/Core/include/Framework/DeviceConfigInfo.h +++ b/Framework/Core/include/Framework/DeviceConfigInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DeviceControl.h b/Framework/Core/include/Framework/DeviceControl.h index e25b176e352d2..70cf8c9aa29dd 100644 --- a/Framework/Core/include/Framework/DeviceControl.h +++ b/Framework/Core/include/Framework/DeviceControl.h @@ -1,24 +1,26 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DEVICECONTROL_H -#define FRAMEWORK_DEVICECONTROL_H +#ifndef O2_FRAMEWORK_DEVICECONTROL_H_ +#define O2_FRAMEWORK_DEVICECONTROL_H_ + +#include "Framework/LogParsingHelpers.h" #include <map> #include <string> -#include "Framework/LogParsingHelpers.h" -namespace o2 -{ -namespace framework +namespace o2::framework { +struct DeviceController; + constexpr int MAX_USER_FILTER_SIZE = 256; /// Controller state for the Device. This is useful for both GUI and batch @@ -42,9 +44,10 @@ struct DeviceControl { char logStopTrigger[MAX_USER_FILTER_SIZE] = {0}; /// Where the GUI should store the options it wants. std::map<std::string, std::string> options; + /// Handler used to communicate with the device (if available) + DeviceController* controller = nullptr; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_DEVICECONTROL_H +#endif // O2_FRAMEWORK_DEVICECONTROL_H_ diff --git a/Framework/Core/include/Framework/DeviceController.h b/Framework/Core/include/Framework/DeviceController.h new file mode 100644 index 0000000000000..8ccfeff2efe60 --- /dev/null +++ b/Framework/Core/include/Framework/DeviceController.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_DEVICECONTROLLER_H_ +#define O2_FRAMEWORK_DEVICECONTROLLER_H_ + +#include <cstddef> + +namespace o2::framework +{ + +struct WSDPLHandler; + +struct DeviceController { + DeviceController(WSDPLHandler* handler); + void hello(); + void write(const char* message, size_t s); + + WSDPLHandler* mHandler; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DEVICECONTROLLER_H_ diff --git a/Framework/Core/include/Framework/DeviceExecution.h b/Framework/Core/include/Framework/DeviceExecution.h index 8e3b57b6bc291..d417a6980cf58 100644 --- a/Framework/Core/include/Framework/DeviceExecution.h +++ b/Framework/Core/include/Framework/DeviceExecution.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/DeviceInfo.h b/Framework/Core/include/Framework/DeviceInfo.h index 3cf0e1c46e105..bba8935628cfd 100644 --- a/Framework/Core/include/Framework/DeviceInfo.h +++ b/Framework/Core/include/Framework/DeviceInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,12 +40,17 @@ struct DeviceInfo { size_t historySize; /// The maximum log level ever seen by this device LogParsingHelpers::LogLevel maxLogLevel; + + /// The minimum level after which the device will exit with 0 + LogParsingHelpers::LogLevel minFailureLevel; + /// A circular buffer for the history of logs entries received /// by this device std::vector<std::string> history; /// A circular buffer for the severity of each of the entries /// in the circular buffer associated to the device. std::vector<LogParsingHelpers::LogLevel> historyLevel; + std::string firstSevereError; std::string lastError; /// An unterminated string which is not ready to be printed yet std::string unprinted; @@ -66,6 +72,8 @@ struct DeviceInfo { boost::property_tree::ptree currentProvenance; /// Port to use to connect to tracy profiler short tracyPort; + /// Timestamp of the last signal received + size_t lastSignal; }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/DeviceMetricsHelper.h b/Framework/Core/include/Framework/DeviceMetricsHelper.h new file mode 100644 index 0000000000000..6db4ef26f348e --- /dev/null +++ b/Framework/Core/include/Framework/DeviceMetricsHelper.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +#ifndef O2_FRAMEWORK_DEVICEMETRICSHELPERS_H_ +#define O2_FRAMEWORK_DEVICEMETRICSHELPERS_H_ + +#include "Framework/DeviceMetricsInfo.h" +#include "Framework/RuntimeError.h" +#include <array> +#include <cstddef> +#include <cstring> +#include <functional> +#include <string> +#include <string_view> +#include <vector> + +namespace o2::framework +{ + +struct DeviceMetricsHelper { + /// Type of the callback which can be provided to be invoked every time a new + /// metric is found by the system. + using NewMetricCallback = std::function<void(std::string const&, MetricInfo const&, int value, size_t metricIndex)>; + + /// Helper function to parse a metric string. + static bool parseMetric(std::string_view const s, ParsedMetricMatch& results); + + /// Processes a parsed metric and stores in the backend store. + /// + /// @matches is the regexp_matches from the metric identifying regex + /// @info is the DeviceInfo associated to the device posting the metric + /// @newMetricsCallback is a callback that will be invoked every time a new metric is added to the list. + static bool processMetric(ParsedMetricMatch& results, + DeviceMetricsInfo& info, + NewMetricCallback newMetricCallback = nullptr); + /// @return the index in metrics for the information of given metric + static size_t metricIdxByName(const std::string& name, + const DeviceMetricsInfo& info); + + /// Typesafe way to get the actual store + template <typename T> + static auto& getMetricsStore(DeviceMetricsInfo& metrics) + { + if constexpr (std::is_same_v<T, int>) { + return metrics.intMetrics; + } else if constexpr (std::is_same_v<T, float>) { + return metrics.floatMetrics; + } else if constexpr (std::is_same_v<T, uint64_t>) { + return metrics.uint64Metrics; + } else { + throw runtime_error("Unhandled metric type"); + }; + } + + template <typename T> + static auto getMetricType() + { + if constexpr (std::is_same_v<T, int>) { + return MetricType::Int; + } else if constexpr (std::is_same_v<T, float>) { + return MetricType::Float; + } else if constexpr (std::is_same_v<T, uint64_t>) { + return MetricType::Uint64; + } else { + throw runtime_error("Unhandled metric type"); + }; + } + + template <typename T> + static auto getNumericMetricCursor(size_t metricIndex) + { + return [metricIndex](DeviceMetricsInfo& metrics, T value, size_t timestamp) { + MetricInfo& metric = metrics.metrics[metricIndex]; + + metrics.minDomain[metricIndex] = std::min(metrics.minDomain[metricIndex], timestamp); + metrics.maxDomain[metricIndex] = std::max(metrics.maxDomain[metricIndex], timestamp); + metrics.max[metricIndex] = std::max(metrics.max[metricIndex], (float)value); + metrics.min[metricIndex] = std::min(metrics.min[metricIndex], (float)value); + metrics.changed.at(metricIndex) = true; + auto& store = getMetricsStore<T>(metrics); + size_t pos = metric.pos++ % store[metric.storeIdx].size(); + metrics.timestamps[metricIndex][pos] = timestamp; + store[metric.storeIdx][pos] = value; + metric.filledMetrics++; + }; + } + + static size_t bookMetricInfo(DeviceMetricsInfo& metrics, char const* name); + + /// @return helper to insert a given value in the metrics + template <typename T> + static size_t + bookNumericMetric(DeviceMetricsInfo& metrics, + char const* name, + NewMetricCallback newMetricsCallback = nullptr) + { + static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint64_t> || std::is_same_v<T, float>, "Unsupported metric type"); + size_t metricIndex = bookMetricInfo(metrics, name); + auto& metricInfo = metrics.metrics[metricIndex]; + metricInfo.type = getMetricType<T>(); + metricInfo.storeIdx = getMetricsStore<T>(metrics).size(); + getMetricsStore<T>(metrics).emplace_back(std::array<T, 1024>{}); + if (newMetricsCallback != nullptr) { + newMetricsCallback(name, metricInfo, 0, metricIndex); + } + return metricIndex; + } + + /// @return helper to insert a given value in the metrics + template <typename T> + static std::function<void(DeviceMetricsInfo&, T value, size_t timestamp)> + createNumericMetric(DeviceMetricsInfo& metrics, + char const* name, + NewMetricCallback newMetricsCallback = nullptr) + { + static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint64_t> || std::is_same_v<T, float>, "Unsupported metric type"); + size_t metricIndex = bookNumericMetric<T>(metrics, name, newMetricsCallback); + return getNumericMetricCursor<T>(metricIndex); + } +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DEVICEMETRICSINFO_H_ diff --git a/Framework/Core/include/Framework/DeviceMetricsInfo.h b/Framework/Core/include/Framework/DeviceMetricsInfo.h index 439537083e373..7ad569a0c057c 100644 --- a/Framework/Core/include/Framework/DeviceMetricsInfo.h +++ b/Framework/Core/include/Framework/DeviceMetricsInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,10 +15,7 @@ #include "Framework/RuntimeError.h" #include <array> #include <cstddef> -#include <cstring> -#include <functional> #include <string> -#include <string_view> #include <vector> namespace o2::framework @@ -43,16 +41,20 @@ struct MetricInfo { // We keep only fixed lenght strings for metrics, as in the end this is not // really needed. They should be nevertheless 0 terminated. struct StringMetric { - static constexpr ptrdiff_t MAX_SIZE = 128; + static constexpr ptrdiff_t MAX_SIZE = 512; char data[MAX_SIZE]; }; -// Also for the keys it does not make much sense to keep more than 256 chars. +// Also for the keys it does not make much sense to keep more than 255 chars. // They should be nevertheless 0 terminated. +struct MetricLabel { + static constexpr size_t MAX_METRIC_LABEL_SIZE = 256 - sizeof(unsigned char); // Maximum size for a metric name. + unsigned char size = 0; + char label[MAX_METRIC_LABEL_SIZE]; +}; + struct MetricLabelIndex { - static constexpr size_t MAX_METRIC_LABEL_SIZE = 256 - sizeof(size_t); // Maximum size for a metric name. size_t index; - char label[MAX_METRIC_LABEL_SIZE]; }; /// Temporary struct to hold a metric after it has been parsed. @@ -69,7 +71,8 @@ struct ParsedMetricMatch { }; /// This struct hold information about device metrics when running -/// in standalone mode +/// in standalone mode. It's position in the holding vector is +/// the same as the DeviceSpec in its own vector. struct DeviceMetricsInfo { // We keep the size of each metric to 4096 bytes. No need for more // for the debug GUI @@ -80,120 +83,15 @@ struct DeviceMetricsInfo { std::vector<std::array<size_t, 1024>> timestamps; std::vector<float> max; std::vector<float> min; + std::vector<float> average; std::vector<size_t> minDomain; std::vector<size_t> maxDomain; - std::vector<MetricLabelIndex> metricLabelsIdx; + std::vector<MetricLabel> metricLabels; + std::vector<MetricLabelIndex> metricLabelsAlphabeticallySortedIdx; std::vector<MetricInfo> metrics; std::vector<bool> changed; }; -struct DeviceMetricsHelper { - /// Type of the callback which can be provided to be invoked every time a new - /// metric is found by the system. - using NewMetricCallback = std::function<void(std::string const&, MetricInfo const&, int value, size_t metricIndex)>; - - /// Helper function to parse a metric string. - static bool parseMetric(std::string_view const s, ParsedMetricMatch& results); - - /// Processes a parsed metric and stores in the backend store. - /// - /// @matches is the regexp_matches from the metric identifying regex - /// @info is the DeviceInfo associated to the device posting the metric - /// @newMetricsCallback is a callback that will be invoked every time a new metric is added to the list. - static bool processMetric(ParsedMetricMatch& results, - DeviceMetricsInfo& info, - NewMetricCallback newMetricCallback = nullptr); - /// @return the index in metrics for the information of given metric - static size_t metricIdxByName(const std::string& name, - const DeviceMetricsInfo& info); - - /// Typesafe way to get the actual store - template <typename T> - static auto& getMetricsStore(DeviceMetricsInfo& metrics) - { - if constexpr (std::is_same_v<T, int>) { - return metrics.intMetrics; - } else if constexpr (std::is_same_v<T, float>) { - return metrics.floatMetrics; - } else if constexpr (std::is_same_v<T, uint64_t>) { - return metrics.uint64Metrics; - } else { - throw runtime_error("Unhandled metric type"); - }; - } - - template <typename T> - static auto getMetricType() - { - if constexpr (std::is_same_v<T, int>) { - return MetricType::Int; - } else if constexpr (std::is_same_v<T, float>) { - return MetricType::Float; - } else if constexpr (std::is_same_v<T, uint64_t>) { - return MetricType::Uint64; - } else { - throw runtime_error("Unhandled metric type"); - }; - } - - /// @return helper to insert a given value in the metrics - template <typename T> - static std::function<void(DeviceMetricsInfo&, T value, size_t timestamp)> - createNumericMetric(DeviceMetricsInfo& metrics, - char const* name, - NewMetricCallback newMetricsCallback = nullptr) - { - static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint64_t> || std::is_same_v<T, float>, "Unsupported metric type"); - // Create a new metric - MetricInfo metricInfo; - metricInfo.pos = 0; - metricInfo.type = getMetricType<T>(); - metricInfo.filledMetrics = 0; - metricInfo.storeIdx = getMetricsStore<T>(metrics).size(); - getMetricsStore<T>(metrics).emplace_back(std::array<T, 1024>{}); - - // Add the timestamp buffer for it - metrics.timestamps.emplace_back(std::array<size_t, 1024>{}); - metrics.max.push_back(std::numeric_limits<float>::lowest()); - metrics.min.push_back(std::numeric_limits<float>::max()); - metrics.maxDomain.push_back(std::numeric_limits<size_t>::lowest()); - metrics.minDomain.push_back(std::numeric_limits<size_t>::max()); - metrics.changed.push_back(true); - - // Add the index by name in the correct position - // this will require moving the tail of the index, - // but inserting should happen only once for each metric, - // so who cares. - // Add the the actual Metric info to the store - MetricLabelIndex metricLabelIdx; - strncpy(metricLabelIdx.label, name, MetricLabelIndex::MAX_METRIC_LABEL_SIZE - 1); - metricLabelIdx.label[MetricLabelIndex::MAX_METRIC_LABEL_SIZE - 1] = '\0'; - metricLabelIdx.index = metrics.metrics.size(); - metrics.metricLabelsIdx.push_back(metricLabelIdx); - - // Add the the actual Metric info to the store - auto metricIndex = metrics.metrics.size(); - metrics.metrics.push_back(metricInfo); - - if (newMetricsCallback != nullptr) { - newMetricsCallback(metricLabelIdx.label, metricInfo, 0, metricIndex); - } - return [metricIndex](DeviceMetricsInfo& metrics, T value, size_t timestamp) { - MetricInfo& metric = metrics.metrics[metricIndex]; - - metrics.minDomain[metricIndex] = std::min(metrics.minDomain[metricIndex], timestamp); - metrics.maxDomain[metricIndex] = std::max(metrics.maxDomain[metricIndex], timestamp); - metrics.max[metricIndex] = std::max(metrics.max[metricIndex], (float)value); - metrics.min[metricIndex] = std::min(metrics.min[metricIndex], (float)value); - metrics.changed.at(metricIndex) = true; - auto& store = getMetricsStore<T>(metrics); - size_t pos = metric.pos++ % store[metric.storeIdx].size(); - metrics.timestamps[metricIndex][pos] = timestamp; - store[metric.storeIdx][pos] = value; - }; - } -}; - } // namespace o2::framework #endif // O2_FRAMEWORK_DEVICEMETRICSINFO_H_ diff --git a/Framework/Core/include/Framework/DeviceSpec.h b/Framework/Core/include/Framework/DeviceSpec.h index 3ba159076b9a8..b5574cf7f7980 100644 --- a/Framework/Core/include/Framework/DeviceSpec.h +++ b/Framework/Core/include/Framework/DeviceSpec.h @@ -1,18 +1,20 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DEVICESPEC_H -#define FRAMEWORK_DEVICESPEC_H +#ifndef O2_FRAMEWORK_DEVICESPEC_H_ +#define O2_FRAMEWORK_DEVICESPEC_H_ #include "Framework/WorkflowSpec.h" #include "Framework/ComputingResource.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/DataProcessorLabel.h" #include "Framework/ChannelSpec.h" #include "Framework/ChannelInfo.h" #include "Framework/DeviceControl.h" @@ -23,6 +25,7 @@ #include "Framework/OutputRoute.h" #include "Framework/CompletionPolicy.h" #include "Framework/DispatchPolicy.h" +#include "Framework/ResourcePolicy.h" #include "Framework/ServiceSpec.h" #include <vector> @@ -30,16 +33,17 @@ #include <map> #include <utility> -namespace o2 -{ -namespace framework +namespace o2::framework { /// Concrete description of the device which will actually run /// a DataProcessor. struct DeviceSpec { + /// The name of the associated DataProcessorSpec std::string name; + /// The id of the device, including time-pipelining and suffix std::string id; + std::string channelPrefix; std::vector<InputChannelSpec> inputChannels; std::vector<OutputChannelSpec> outputChannels; std::vector<std::string> arguments; @@ -60,10 +64,13 @@ struct DeviceSpec { /// The completion policy to use for this device. CompletionPolicy completionPolicy; DispatchPolicy dispatchPolicy; + /// Policy on when the available resources are enough to run + /// a computation. + ResourcePolicy resourcePolicy; ComputingResource resource; unsigned short resourceMonitoringInterval; + std::vector<DataProcessorLabel> labels; }; -} // namespace framework -} // namespace o2 -#endif +} // namespace o2::framework +#endif // O2_FRAMEWORK_DEVICESPEC_H_ diff --git a/Framework/Core/include/Framework/DeviceState.h b/Framework/Core/include/Framework/DeviceState.h index b16d07e94dd4e..2fd782cf87d36 100644 --- a/Framework/Core/include/Framework/DeviceState.h +++ b/Framework/Core/include/Framework/DeviceState.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,8 @@ #define O2_FRAMEWORK_DEVICESTATE_H_ #include "Framework/ChannelInfo.h" +#include "Framework/ComputingQuotaOffer.h" + #include <vector> #include <string> #include <map> @@ -20,6 +23,7 @@ typedef struct uv_loop_s uv_loop_t; typedef struct uv_timer_s uv_timer_t; typedef struct uv_poll_s uv_poll_t; typedef struct uv_signal_s uv_signal_t; +typedef struct uv_async_s uv_async_t; namespace o2::framework { @@ -28,20 +32,45 @@ namespace o2::framework /// device. enum struct StreamingState { /// Data is being processed - Streaming, + Streaming = 0, /// End of streaming requested, but not notified - EndOfStreaming, + EndOfStreaming = 1, /// End of streaming notified - Idle, + Idle = 2, }; /// Running state information of a given device struct DeviceState { + /// Motivation for the loop being triggered. + enum LoopReason : int { + NO_REASON = 0, // No tracked reason to wake up + METRICS_MUST_FLUSH = 1, // Metrics available to flush + SIGNAL_ARRIVED = 2, // Signal has arrived + DATA_SOCKET_POLLED = 4, // Data has arrived + DATA_INCOMING = 8, // Data was read + DATA_OUTGOING = 16, // Data was written + WS_COMMUNICATION = 32, // Communication over WS + TIMER_EXPIRED = 64, // Timer expired + WS_CONNECTED = 128, // Connection to driver established + WS_CLOSING = 256, // Events related to WS shutting down + WS_READING = 512, // Events related to WS shutting down + WS_WRITING = 1024, // Events related to WS shutting down + ASYNC_NOTIFICATION = 2048 + }; + std::vector<InputChannelInfo> inputChannelInfos; StreamingState streaming = StreamingState::Streaming; bool quitRequested = false; + + /// ComputingQuotaOffers which have not yet been + /// evaluated by the ComputingQuotaEvaluator + std::vector<ComputingQuotaOffer> pendingOffers; + /// ComputingQuotaOffers which should be removed + /// from the queue. + std::vector<ComputingQuotaConsumer> offerConsumers; + // The libuv event loop which serves this device. - uv_loop_t* loop; + uv_loop_t* loop = nullptr; // The list of active timers which notify this device. std::vector<uv_timer_t*> activeTimers; // The list of pollers for active input channels @@ -50,6 +79,10 @@ struct DeviceState { std::vector<uv_poll_t*> activeOutputPollers; /// The list of active signal handlers std::vector<uv_signal_t*> activeSignals; + + uv_async_t* awakeMainThread = nullptr; + + int loopReason = 0; }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/DevicesManager.h b/Framework/Core/include/Framework/DevicesManager.h new file mode 100644 index 0000000000000..8930e1cf72279 --- /dev/null +++ b/Framework/Core/include/Framework/DevicesManager.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_DEVICESMANAGER_H_ +#define O2_FRAMEWORK_DEVICESMANAGER_H_ + +#include "Framework/DeviceControl.h" +#include "Framework/DeviceInfo.h" +#include "Framework/DeviceSpec.h" +#include <string> +#include <vector> + +namespace o2::framework +{ + +struct DeviceIndex { + int index; +}; +struct DeviceControl; + +struct DeviceMessageHandle { + DeviceIndex ref; + std::string message; +}; + +struct DevicesManager { + void queueMessage(char const* receiver, char const* msg); + void flush(); + + std::vector<DeviceControl>& controls; + std::vector<DeviceInfo>& infos; + std::vector<DeviceSpec>& specs; + std::vector<DeviceMessageHandle> messages; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DEVICESMANAGER_H_ diff --git a/Framework/Core/include/Framework/DispatchControl.h b/Framework/Core/include/Framework/DispatchControl.h index 175b57fb1987e..f1e78f6a792a8 100644 --- a/Framework/Core/include/Framework/DispatchControl.h +++ b/Framework/Core/include/Framework/DispatchControl.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include <functional> #include <string> -class FairMQParts; +#include <fairmq/FwdDecls.h> namespace o2 { diff --git a/Framework/Core/include/Framework/DispatchPolicy.h b/Framework/Core/include/Framework/DispatchPolicy.h index 2ac7498aa58e7..030a72b75e9ce 100644 --- a/Framework/Core/include/Framework/DispatchPolicy.h +++ b/Framework/Core/include/Framework/DispatchPolicy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,7 +50,9 @@ struct DispatchPolicy { /// the action to be used for matched devices DispatchOp action = DispatchOp::AfterComputation; /// matcher on specific output to trigger sending - TriggerMatcher triggerMatcher = [](Output const&) { return true; }; + TriggerMatcher triggerMatcher = defaultDispatchPolicy(); + + static TriggerMatcher defaultDispatchPolicy(); /// Helper to create the default configuration. static std::vector<DispatchPolicy> createDefaultPolicies(); diff --git a/Framework/Core/include/Framework/DriverClient.h b/Framework/Core/include/Framework/DriverClient.h new file mode 100644 index 0000000000000..7435775bcf9cf --- /dev/null +++ b/Framework/Core/include/Framework/DriverClient.h @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DRIVERCLIENT_H_ +#define O2_FRAMEWORK_DRIVERCLIENT_H_ + +#include "Framework/ServiceHandle.h" +#include <functional> +#include <string> +#include <string_view> +#include <vector> + +namespace o2::framework +{ + +struct DriverEventMatcher { + std::string prefix; + std::function<void(std::string_view)> callback; +}; + +/// A service API to communicate with the driver +class DriverClient +{ + public: + constexpr static ServiceKind service_kind = ServiceKind::Global; + + /// Report some message to the Driver + /// @a msg the message to be sent. + /// @a size size of the message to be sent. + /// @a flush whether the message should be flushed immediately, + /// if possible. + virtual void tell(char const* msg, size_t s, bool flush = true) = 0; + void tell(std::string_view const& msg, bool flush = true) + { + tell(msg.data(), msg.size(), flush); + }; + + /// Request action on some @a eventType notified by the driver + void observe(char const* eventType, std::function<void(std::string_view)> callback); + + /// Dispatch an event + void dispatch(std::string_view event); + + /// Flush all pending events (if connected) + virtual void flushPending() = 0; + + private: + std::vector<DriverEventMatcher> mEventMatchers; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DRIVERCLIENT_H_ diff --git a/Framework/Core/src/DriverControl.h b/Framework/Core/include/Framework/DriverControl.h similarity index 78% rename from Framework/Core/src/DriverControl.h rename to Framework/Core/include/Framework/DriverControl.h index 606e1c8ef6bff..001f441243523 100644 --- a/Framework/Core/src/DriverControl.h +++ b/Framework/Core/include/Framework/DriverControl.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,8 @@ #include <functional> #include <vector> -#include "DriverInfo.h" +#include "Framework/CommandInfo.h" +#include "Framework/DriverInfo.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DeviceSpec.h" #include "Framework/DeviceExecution.h" @@ -37,7 +39,8 @@ struct DriverControl { using Callback = std::function<void(std::vector<DataProcessorSpec> const& workflow, std::vector<DeviceSpec> const&, std::vector<DeviceExecution> const&, - std::vector<DataProcessorInfo>&)>; + std::vector<DataProcessorInfo>&, + CommandInfo const&)>; /// States to be added to the stack on next iteration /// of the state machine processing. std::vector<DriverState> forcedTransitions; diff --git a/Framework/Core/src/DriverInfo.h b/Framework/Core/include/Framework/DriverInfo.h similarity index 75% rename from Framework/Core/src/DriverInfo.h rename to Framework/Core/include/Framework/DriverInfo.h index 2b2d4b0c8cfbc..8cec4b70ff46c 100644 --- a/Framework/Core/src/DriverInfo.h +++ b/Framework/Core/include/Framework/DriverInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,9 @@ #include "Framework/CompletionPolicy.h" #include "Framework/DispatchPolicy.h" #include "Framework/DeviceMetricsInfo.h" +#include "Framework/LogParsingHelpers.h" #include "DataProcessorInfo.h" +#include "ResourcePolicy.h" namespace o2::framework { @@ -33,6 +36,8 @@ class ConfigContext; /// Possible states for the DPL Driver application /// /// INIT => Initial state where global initialization should happen +/// MERGE_CONFIGS => Invoked to rework the configuration so that common +/// options are homogeneous between different invokations. /// SCHEDULE => Invoked whenever the topology or the resources associated /// to it change. /// RUNNING => At least one device is running and processing data. @@ -69,6 +74,7 @@ enum struct DriverState { MATERIALISE_WORKFLOW, IMPORT_CURRENT_WORKFLOW, DO_CHILD, + MERGE_CONFIGS, LAST }; @@ -92,6 +98,10 @@ struct DriverInfo { /// These are the policies which can be applied to decide when complete /// objects/messages are sent out std::vector<DispatchPolicy> dispatchPolicies; + + /// These are the policies which can be applied to decide when there + /// is enough resources to process data. + std::vector<ResourcePolicy> resourcePolicies; /// The argc with which the driver was started. int argc; /// The argv with which the driver was started. @@ -133,13 +143,29 @@ struct DriverInfo { /// The unique id used for ipc communications std::string uniqueWorkflowId = ""; /// Metrics gathering interval - unsigned short resourcesMonitoringInterval; + unsigned short resourcesMonitoringInterval = 0; + /// Metrics gathering dump to disk interval + unsigned short resourcesMonitoringDumpInterval = 0; + /// Port used by the websocket control. 0 means not initialised. + unsigned short port = 0; /// Last port used for tracy short tracyPort = 8086; + /// The minimum level after which the device will exit with 1 + LogParsingHelpers::LogLevel minFailureLevel = LogParsingHelpers::LogLevel::Fatal; + /// Aggregate metrics calculated in the driver itself DeviceMetricsInfo metrics; /// Skip shared memory cleanup if set bool noSHMCleanup; + /// Default value for the --driver-client-backend. Notice that if we start from + /// the driver, the default backend will be the websocket one. On the other hand, + /// if the device is started standalone, the default becomes the old stdout:// so + /// that it works as it used to in AliECS. + std::string defaultDriverClient = "invalid"; +}; + +struct DriverInfoHelper { + static char const* stateToString(enum DriverState state); }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/EndOfStreamContext.h b/Framework/Core/include/Framework/EndOfStreamContext.h index f162feb3ea57e..bdf43d30e08ae 100644 --- a/Framework/Core/include/Framework/EndOfStreamContext.h +++ b/Framework/Core/include/Framework/EndOfStreamContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ErrorContext.h b/Framework/Core/include/Framework/ErrorContext.h index 96528afa69c49..06ed125358d03 100644 --- a/Framework/Core/include/Framework/ErrorContext.h +++ b/Framework/Core/include/Framework/ErrorContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ExpirationHandler.h b/Framework/Core/include/Framework/ExpirationHandler.h index 82e609cc6bd13..ea106015e4095 100644 --- a/Framework/Core/include/Framework/ExpirationHandler.h +++ b/Framework/Core/include/Framework/ExpirationHandler.h @@ -1,24 +1,24 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_EXPIRATIONHANDLER_H -#define FRAMEWORK_EXPIRATIONHANDLER_H +#ifndef O2_FRAMEWORK_EXPIRATIONHANDLER_H_ +#define O2_FRAMEWORK_EXPIRATIONHANDLER_H_ #include "Framework/Lifetime.h" #include "Framework/RoutingIndices.h" +#include "Framework/DataDescriptorMatcher.h" #include <cstdint> #include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { struct PartRef; @@ -28,8 +28,10 @@ struct TimesliceSlot; struct ExpirationHandler { using Creator = std::function<TimesliceSlot(TimesliceIndex&)>; - using Checker = std::function<bool(uint64_t timestamp)>; - using Handler = std::function<void(ServiceRegistry&, PartRef& expiredInput, uint64_t timestamp)>; + /// Callback type to check if the record must be expired + using Checker = std::function<bool(ServiceRegistry&, uint64_t timestamp)>; + /// Callback type to actually materialise a given record + using Handler = std::function<void(ServiceRegistry&, PartRef& expiredInput, data_matcher::VariableContext& variables)>; RouteIndex routeIndex; Lifetime lifetime; @@ -38,7 +40,6 @@ struct ExpirationHandler { Handler handler; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_EXPIRATIONHANDLER_H +#endif // O2_FRAMEWORK_EXPIRATIONHANDLER_H_ diff --git a/Framework/Core/include/Framework/ExpressionHelpers.h b/Framework/Core/include/Framework/ExpressionHelpers.h new file mode 100644 index 0000000000000..7630e2f799bce --- /dev/null +++ b/Framework/Core/include/Framework/ExpressionHelpers.h @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ +#define O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ +#include "Framework/Expressions.h" + +#include <vector> +#include <iosfwd> +#include <fmt/format.h> + +namespace o2::framework::expressions +{ +/// a map between BasicOp and gandiva node definitions +/// note that logical 'and' and 'or' are created separately +static std::array<std::string, BasicOp::Conditional + 1> basicOperationsMap = { + "and", + "or", + "add", + "subtract", + "divide", + "multiply", + "bitwise_and", + "bitwise_or", + "bitwise_xor", + "less_than", + "less_than_or_equal_to", + "greater_than", + "greater_than_or_equal_to", + "equal", + "not_equal", + "powerf", + "sqrtf", + "expf", + "logf", + "log10f", + "sinf", + "cosf", + "tanf", + "asinf", + "acosf", + "atanf", + "absf", + "bitwise_not", + "if"}; + +struct DatumSpec { + /// datum spec either contains an index, a value of a literal or a binding label + using datum_t = std::variant<std::monostate, size_t, LiteralNode::var_t, std::string>; + datum_t datum = std::monostate{}; + size_t hash = 0; + atype::type type = atype::NA; + + explicit DatumSpec(size_t index, atype::type type_) : datum{index}, type{type_} {} + explicit DatumSpec(LiteralNode::var_t literal, atype::type type_) : datum{literal}, type{type_} {} + explicit DatumSpec(std::string binding, size_t hash_, atype::type type_) : datum{binding}, hash{hash_}, type{type_} {} + DatumSpec() = default; + DatumSpec(DatumSpec const&) = default; + DatumSpec(DatumSpec&&) = default; + DatumSpec& operator=(DatumSpec const&) = default; + DatumSpec& operator=(DatumSpec&&) = default; +}; + +bool operator==(DatumSpec const& lhs, DatumSpec const& rhs); + +std::ostream& operator<<(std::ostream& os, DatumSpec const& spec); + +struct ColumnOperationSpec { + size_t index = 0; + BasicOp op; + DatumSpec left; + DatumSpec right; + DatumSpec condition; + DatumSpec result; + atype::type type = atype::NA; + ColumnOperationSpec() = default; + explicit ColumnOperationSpec(BasicOp op_, size_t index_ = 0) + : index{index_}, + op{op_}, + left{}, + right{}, + condition{}, + result{} + { + switch (op) { + case BasicOp::LogicalOr: + case BasicOp::LogicalAnd: + case BasicOp::LessThan: + case BasicOp::LessThanOrEqual: + case BasicOp::GreaterThan: + case BasicOp::GreaterThanOrEqual: + case BasicOp::Equal: + case BasicOp::NotEqual: + type = atype::BOOL; + break; + case BasicOp::Division: + type = atype::FLOAT; + default: + type = atype::NA; + } + result.type = type; + } +}; + +/// helper struct used to parse trees +struct NodeRecord { + /// pointer to the actual tree node + Node* node_ptr = nullptr; + size_t index = 0; + explicit NodeRecord(Node* node_, size_t index_) : node_ptr(node_), index{index_} {} + bool operator!=(NodeRecord const& rhs) + { + return this->node_ptr != rhs.node_ptr; + } +}; +} // namespace o2::framework::expressions + +#endif // O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ diff --git a/Framework/Core/include/Framework/Expressions.h b/Framework/Core/include/Framework/Expressions.h index 743ae75ba974a..0cce00c04634c 100644 --- a/Framework/Core/include/Framework/Expressions.h +++ b/Framework/Core/include/Framework/Expressions.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,10 +41,14 @@ class Filter; #include <variant> #include <string> #include <memory> +#include <typeinfo> +#include <set> using atype = arrow::Type; struct ExpressionInfo { - size_t index; + int argumentIndex; + size_t processHash; + std::set<size_t> hashes; gandiva::SchemaPtr schema; gandiva::NodePtr tree; }; @@ -56,7 +61,7 @@ struct LiteralStorage { using stored_pack = framework::pack<T...>; }; -using LiteralValue = LiteralStorage<int, bool, float, double, uint8_t>; +using LiteralValue = LiteralStorage<int, bool, float, double, uint8_t, int64_t, int16_t, uint16_t, int8_t, uint32_t, uint64_t>; template <typename T> constexpr auto selectArrowType() @@ -69,12 +74,20 @@ constexpr auto selectArrowType() return atype::FLOAT; } else if constexpr (std::is_same_v<T, double>) { return atype::DOUBLE; + } else if constexpr (std::is_same_v<T, uint8_t>) { + return atype::UINT8; } else if constexpr (std::is_same_v<T, int8_t>) { return atype::INT8; } else if constexpr (std::is_same_v<T, uint16_t>) { + return atype::UINT16; + } else if constexpr (std::is_same_v<T, int16_t>) { return atype::INT16; - } else if constexpr (std::is_same_v<T, uint8_t>) { - return atype::UINT8; + } else if constexpr (std::is_same_v<T, int64_t>) { + return atype::INT64; + } else if constexpr (std::is_same_v<T, uint32_t>) { + return atype::UINT32; + } else if constexpr (std::is_same_v<T, uint64_t>) { + return atype::UINT64; } else { return atype::NA; } @@ -100,8 +113,9 @@ struct LiteralNode { struct BindingNode { BindingNode(BindingNode const&) = default; BindingNode(BindingNode&&) = delete; - BindingNode(std::string const& name_, atype::type type_) : name{name_}, type{type_} {} + BindingNode(std::string const& name_, std::size_t hash_, atype::type type_) : name{name_}, hash{hash_}, type{type_} {} std::string name; + std::size_t hash; atype::type type; }; @@ -114,415 +128,289 @@ struct OpNode { /// A placeholder node for simple type configurable struct PlaceholderNode : LiteralNode { template <typename T> - PlaceholderNode(Configurable<T> v) : LiteralNode{v.value} + PlaceholderNode(Configurable<T> const& v) : LiteralNode{v.value}, name{v.name} { if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) { - retrieve = [name = v.name](InitContext& context) { return LiteralNode::var_t{context.options().get<T>(name.c_str())}; }; + retrieve = [](InitContext& context, std::string const& name) { return LiteralNode::var_t{context.options().get<T>(name.c_str())}; }; } else { - retrieve = [name = v.name](InitContext& context) { - auto pt = context.options().get<boost::property_tree::ptree>(name.c_str()); - return LiteralNode::var_t{RootConfigParamHelpers::as<T>(pt)}; - }; + runtime_error("Unknown parameter used in expression."); } } void reset(InitContext& context) { - value = retrieve(context); + value = retrieve(context, name); } - std::function<LiteralNode::var_t(InitContext&)> retrieve; + std::string name; + LiteralNode::var_t (*retrieve)(InitContext&, std::string const& name); +}; + +/// A conditional node +struct ConditionalNode { }; /// A generic tree node struct Node { - Node(LiteralNode v) : self{v}, left{nullptr}, right{nullptr} + Node(LiteralNode v) : self{v}, left{nullptr}, right{nullptr}, condition{nullptr} { } - Node(PlaceholderNode v) : self{v}, left{nullptr}, right{nullptr} + Node(PlaceholderNode v) : self{v}, left{nullptr}, right{nullptr}, condition{nullptr} { } - Node(Node&& n) : self{n.self}, left{std::move(n.left)}, right{std::move(n.right)} + Node(Node&& n) : self{n.self}, left{std::move(n.left)}, right{std::move(n.right)}, condition{std::move(n.condition)} { } - Node(BindingNode n) : self{n}, left{nullptr}, right{nullptr} + Node(BindingNode n) : self{n}, left{nullptr}, right{nullptr}, condition{nullptr} { } + Node(ConditionalNode op, Node&& then_, Node&& else_, Node&& condition_) + : self{op}, + left{std::make_unique<Node>(std::move(then_))}, + right{std::make_unique<Node>(std::move(else_))}, + condition{std::make_unique<Node>(std::move(condition_))} {} + Node(OpNode op, Node&& l, Node&& r) : self{op}, left{std::make_unique<Node>(std::move(l))}, - right{std::make_unique<Node>(std::move(r))} {} + right{std::make_unique<Node>(std::move(r))}, + condition{nullptr} {} Node(OpNode op, Node&& l) : self{op}, left{std::make_unique<Node>(std::move(l))}, - right{nullptr} {} + right{nullptr}, + condition{nullptr} {} /// variant with possible nodes - using self_t = std::variant<LiteralNode, BindingNode, OpNode, PlaceholderNode>; + using self_t = std::variant<LiteralNode, BindingNode, OpNode, PlaceholderNode, ConditionalNode>; self_t self; + size_t index = 0; /// pointers to children std::unique_ptr<Node> left; std::unique_ptr<Node> right; + std::unique_ptr<Node> condition; }; /// overloaded operators to build the tree from an expression -/// literal comparisons -template <typename T> -inline Node operator>(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::GreaterThan}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator<(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::LessThan}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator>=(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::GreaterThanOrEqual}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator<=(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::LessThanOrEqual}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator==(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::Equal}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator!=(Node left, T rightValue) -{ - return Node{OpNode{BasicOp::NotEqual}, std::move(left), LiteralNode{rightValue}}; -} - -template <typename T> -inline Node operator>(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::GreaterThan}, std::move(left), PlaceholderNode{rightValue}}; -} - -template <typename T> -inline Node operator<(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::LessThan}, std::move(left), PlaceholderNode{rightValue}}; -} - -template <typename T> -inline Node operator>=(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::GreaterThanOrEqual}, std::move(left), PlaceholderNode{rightValue}}; -} - -template <typename T> -inline Node operator<=(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::LessThanOrEqual}, std::move(left), PlaceholderNode{rightValue}}; -} - -template <typename T> -inline Node operator==(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::Equal}, std::move(left), PlaceholderNode{rightValue}}; -} +#define BINARY_OP_NODES(_operator_, _operation_) \ + template <typename T> \ + inline Node operator _operator_(Node left, T right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, std::move(left), LiteralNode{right}}; \ + } \ + template <typename T> \ + inline Node operator _operator_(T left, Node right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, LiteralNode{left}, std::move(right)}; \ + } \ + template <typename T> \ + inline Node operator _operator_(Node left, Configurable<T> right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, std::move(left), PlaceholderNode{right}}; \ + } \ + template <typename T> \ + inline Node operator _operator_(Configurable<T> left, Node right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, PlaceholderNode{left}, std::move(right)}; \ + } \ + inline Node operator _operator_(Node left, Node right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, std::move(left), std::move(right)}; \ + } \ + inline Node operator _operator_(BindingNode left, BindingNode right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, left, right}; \ + } \ + template <> \ + inline Node operator _operator_(BindingNode left, Node right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, left, std::move(right)}; \ + } \ + template <> \ + inline Node operator _operator_(Node left, BindingNode right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, std::move(left), right}; \ + } \ + \ + template <typename T> \ + inline Node operator _operator_(Configurable<T> left, BindingNode right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, PlaceholderNode{left}, right}; \ + } \ + template <typename T> \ + inline Node operator _operator_(BindingNode left, Configurable<T> right) \ + { \ + return Node{OpNode{BasicOp::_operation_}, left, PlaceholderNode{right}}; \ + } +BINARY_OP_NODES(&, BitwiseAnd); +BINARY_OP_NODES(^, BitwiseXor); +BINARY_OP_NODES(|, BitwiseOr); +BINARY_OP_NODES(+, Addition); +BINARY_OP_NODES(-, Subtraction); +BINARY_OP_NODES(*, Multiplication); +BINARY_OP_NODES(/, Division); +BINARY_OP_NODES(>, GreaterThan); +BINARY_OP_NODES(>=, GreaterThanOrEqual); +BINARY_OP_NODES(<, LessThan); +BINARY_OP_NODES(<=, LessThanOrEqual); +BINARY_OP_NODES(==, Equal); +BINARY_OP_NODES(!=, NotEqual); +BINARY_OP_NODES(&&, LogicalAnd); +BINARY_OP_NODES(||, LogicalOr); + +/// functions template <typename T> -inline Node operator!=(Node left, Configurable<T> rightValue) -{ - return Node{OpNode{BasicOp::NotEqual}, std::move(left), PlaceholderNode{rightValue}}; -} - -/// node comparisons -inline Node operator>(Node left, Node right) -{ - return Node{OpNode{BasicOp::GreaterThan}, std::move(left), std::move(right)}; -} - -inline Node operator<(Node left, Node right) -{ - return Node{OpNode{BasicOp::LessThan}, std::move(left), std::move(right)}; -} - -inline Node operator>=(Node left, Node right) -{ - return Node{OpNode{BasicOp::GreaterThanOrEqual}, std::move(left), std::move(right)}; -} - -inline Node operator<=(Node left, Node right) -{ - return Node{OpNode{BasicOp::LessThanOrEqual}, std::move(left), std::move(right)}; -} - -inline Node operator==(Node left, Node right) -{ - return Node{OpNode{BasicOp::Equal}, std::move(left), std::move(right)}; -} - -inline Node operator!=(Node left, Node right) -{ - return Node{OpNode{BasicOp::NotEqual}, std::move(left), std::move(right)}; -} - -/// logical operations -inline Node operator&&(Node left, Node right) -{ - return Node{OpNode{BasicOp::LogicalAnd}, std::move(left), std::move(right)}; -} - -inline Node operator||(Node left, Node right) -{ - return Node{OpNode{BasicOp::LogicalOr}, std::move(left), std::move(right)}; -} - -/// arithmetical operations between nodes -inline Node operator*(Node left, Node right) -{ - return Node{OpNode{BasicOp::Multiplication}, std::move(left), std::move(right)}; -} - -inline Node operator*(BindingNode left, BindingNode right) -{ - return Node{OpNode{BasicOp::Multiplication}, left, right}; -} - -inline Node operator*(BindingNode left, Node right) -{ - return Node{OpNode{BasicOp::Multiplication}, left, std::move(right)}; -} - -inline Node operator/(Node left, Node right) +inline Node npow(Node left, T right) { - return Node{OpNode{BasicOp::Division}, std::move(left), std::move(right)}; + return Node{OpNode{BasicOp::Power}, std::move(left), LiteralNode{right}}; } -inline Node operator/(BindingNode left, Node right) +/// unary functions on nodes +inline Node nsqrt(Node left) { - return Node{OpNode{BasicOp::Division}, left, std::move(right)}; + return Node{OpNode{BasicOp::Sqrt}, std::move(left)}; } -inline Node operator/(Node left, BindingNode right) +inline Node nexp(Node left) { - return Node{OpNode{BasicOp::Division}, std::move(left), right}; + return Node{OpNode{BasicOp::Exp}, std::move(left)}; } -inline Node operator/(BindingNode left, BindingNode right) +inline Node nlog(Node left) { - return Node{OpNode{BasicOp::Division}, left, right}; + return Node{OpNode{BasicOp::Log}, std::move(left)}; } -inline Node operator+(Node left, Node right) +inline Node nlog10(Node left) { - return Node{OpNode{BasicOp::Addition}, std::move(left), std::move(right)}; + return Node{OpNode{BasicOp::Log10}, std::move(left)}; } -inline Node operator-(Node left, Node right) +inline Node nabs(Node left) { - return Node{OpNode{BasicOp::Subtraction}, std::move(left), std::move(right)}; + return Node{OpNode{BasicOp::Abs}, std::move(left)}; } -inline Node operator-(BindingNode left, BindingNode right) +inline Node nsin(Node left) { - return Node{OpNode{BasicOp::Subtraction}, left, right}; + return Node{OpNode{BasicOp::Sin}, std::move(left)}; } -/// arithmetical operations between node and literal -template <typename T> -inline Node operator*(Node left, T right) +inline Node ncos(Node left) { - return Node{OpNode{BasicOp::Multiplication}, std::move(left), LiteralNode{right}}; + return Node{OpNode{BasicOp::Cos}, std::move(left)}; } -template <typename T> -inline Node operator*(T left, Node right) +inline Node ntan(Node left) { - return Node{OpNode{BasicOp::Multiplication}, LiteralNode{left}, std::move(right)}; + return Node{OpNode{BasicOp::Tan}, std::move(left)}; } -template <typename T> -inline Node operator/(Node left, T right) +inline Node nasin(Node left) { - return Node{OpNode{BasicOp::Division}, std::move(left), LiteralNode{right}}; + return Node{OpNode{BasicOp::Asin}, std::move(left)}; } -template <typename T> -inline Node operator/(T left, Node right) +inline Node nacos(Node left) { - return Node{OpNode{BasicOp::Division}, LiteralNode{left}, std::move(right)}; + return Node{OpNode{BasicOp::Acos}, std::move(left)}; } -template <typename T> -inline Node operator+(Node left, T right) +inline Node natan(Node left) { - return Node{OpNode{BasicOp::Addition}, std::move(left), LiteralNode{right}}; + return Node{OpNode{BasicOp::Atan}, std::move(left)}; } -template <typename T> -inline Node operator+(T left, Node right) +inline Node nbitwise_not(Node left) { - return Node{OpNode{BasicOp::Addition}, LiteralNode{left}, std::move(right)}; + return Node{OpNode{BasicOp::BitwiseNot}, std::move(left)}; } -template <> -inline Node operator+(Node left, BindingNode right) +/// conditionals +template <typename C, typename T, typename E> +inline Node ifnode(C condition_, T then_, E else_) { - return Node{OpNode{BasicOp::Addition}, std::move(left), right}; + return Node{ConditionalNode{}, std::move(then_), std::move(else_), std::move(condition_)}; } template <> -inline Node operator+(BindingNode left, Node right) +inline Node ifnode(Node condition_, Node then_, Node else_) { - return Node{OpNode{BasicOp::Addition}, left, std::move(right)}; + return Node{ConditionalNode{}, std::move(then_), std::move(else_), std::move(condition_)}; } -template <typename T> -inline Node operator-(Node left, T right) +template <typename L, std::enable_if_t<std::is_integral<L>::value || std::is_floating_point<L>::value, bool> = true> +inline Node ifnode(Node condition_, Node then_, L else_) { - return Node{OpNode{BasicOp::Subtraction}, std::move(left), LiteralNode{right}}; + return Node{ConditionalNode{}, std::move(then_), LiteralNode{else_}, std::move(condition_)}; } -template <typename T> -inline Node operator-(T left, Node right) +template <typename L, std::enable_if_t<std::is_integral<L>::value || std::is_floating_point<L>::value, bool> = true> +inline Node ifnode(Node condition_, L then_, Node else_) { - return Node{OpNode{BasicOp::Subtraction}, LiteralNode{left}, std::move(right)}; + return Node{ConditionalNode{}, LiteralNode{then_}, std::move(else_), std::move(condition_)}; } -template <typename T> -inline Node operator*(Node left, Configurable<T> right) -{ - return Node{OpNode{BasicOp::Multiplication}, std::move(left), PlaceholderNode{right}}; -} - -template <typename T> -inline Node operator*(Configurable<T> left, Node right) +template <typename L1, typename L2, std::enable_if_t<(std::is_integral<L1>::value || std::is_floating_point<L1>::value) && (std::is_integral<L2>::value || std::is_floating_point<L2>::value), bool> = true> +inline Node ifnode(Node condition_, L1 then_, L2 else_) { - return Node{OpNode{BasicOp::Multiplication}, PlaceholderNode{left}, std::move(right)}; + return Node{ConditionalNode{}, LiteralNode{then_}, LiteralNode{else_}, std::move(condition_)}; } template <typename T> -inline Node operator/(Node left, Configurable<T> right) -{ - return Node{OpNode{BasicOp::Division}, std::move(left), PlaceholderNode{right}}; -} - -template <typename T> -inline Node operator/(Configurable<T> left, Node right) -{ - return Node{OpNode{BasicOp::Division}, PlaceholderNode{left}, std::move(right)}; -} - -template <typename T> -inline Node operator+(Node left, Configurable<T> right) -{ - return Node{OpNode{BasicOp::Addition}, std::move(left), PlaceholderNode{right}}; -} - -template <typename T> -inline Node operator+(Configurable<T> left, Node right) -{ - return Node{OpNode{BasicOp::Addition}, PlaceholderNode{left}, std::move(right)}; -} - -template <typename T> -inline Node operator-(Node left, Configurable<T> right) -{ - return Node{OpNode{BasicOp::Subtraction}, std::move(left), PlaceholderNode{right}}; -} - -template <typename T> -inline Node operator-(Configurable<T> left, Node right) -{ - return Node{OpNode{BasicOp::Subtraction}, PlaceholderNode{left}, std::move(right)}; -} -/// semi-binary -template <typename T> -inline Node npow(Node left, T right) -{ - return Node{OpNode{BasicOp::Power}, std::move(left), LiteralNode{right}}; -} - -/// unary operations on nodes -inline Node nsqrt(Node left) -{ - return Node{OpNode{BasicOp::Sqrt}, std::move(left)}; -} - -inline Node nexp(Node left) -{ - return Node{OpNode{BasicOp::Exp}, std::move(left)}; -} - -inline Node nlog(Node left) +inline Node ifnode(Configurable<T> condition_, Node then_, Node else_) { - return Node{OpNode{BasicOp::Log}, std::move(left)}; + return Node{ConditionalNode{}, std::move(then_), std::move(else_), PlaceholderNode{condition_}}; } -inline Node nlog10(Node left) +template <typename L> +inline Node ifnode(Node condition_, Node then_, Configurable<L> else_) { - return Node{OpNode{BasicOp::Log10}, std::move(left)}; + return Node{ConditionalNode{}, std::move(then_), PlaceholderNode{else_}, std::move(condition_)}; } -inline Node nabs(Node left) +template <typename L> +inline Node ifnode(Node condition_, Configurable<L> then_, Node else_) { - return Node{OpNode{BasicOp::Abs}, std::move(left)}; + return Node{ConditionalNode{}, PlaceholderNode{then_}, std::move(else_), std::move(condition_)}; } -inline Node nsin(Node left) +template <typename L1, typename L2> +inline Node ifnode(Node condition_, Configurable<L1> then_, Configurable<L2> else_) { - return Node{OpNode{BasicOp::Sin}, std::move(left)}; -} - -inline Node ncos(Node left) -{ - return Node{OpNode{BasicOp::Cos}, std::move(left)}; -} - -inline Node ntan(Node left) -{ - return Node{OpNode{BasicOp::Tan}, std::move(left)}; -} - -inline Node nasin(Node left) -{ - return Node{OpNode{BasicOp::Asin}, std::move(left)}; -} - -inline Node nacos(Node left) -{ - return Node{OpNode{BasicOp::Acos}, std::move(left)}; -} - -inline Node natan(Node left) -{ - return Node{OpNode{BasicOp::Atan}, std::move(left)}; + return Node{ConditionalNode{}, PlaceholderNode{then_}, PlaceholderNode{else_}, std::move(condition_)}; } /// A struct, containing the root of the expression tree struct Filter { - Filter(Node&& node_) : node{std::make_unique<Node>(std::move(node_))} {} - Filter(Filter&& other) : node{std::move(other.node)} {} + Filter(Node&& node_) : node{std::make_unique<Node>(std::move(node_))} + { + (void)designateSubtrees(node.get()); + } + + Filter(Filter&& other) : node{std::move(other.node)} + { + (void)designateSubtrees(node.get()); + } std::unique_ptr<Node> node; + + size_t designateSubtrees(Node* node, size_t index = 0); }; using Projector = Filter; using Selection = std::shared_ptr<gandiva::SelectionVector>; /// Function for creating gandiva selection from our internal filter tree -Selection createSelection(std::shared_ptr<arrow::Table> table, Filter const& expression); +Selection createSelection(std::shared_ptr<arrow::Table> const& table, Filter const& expression); /// Function for creating gandiva selection from prepared gandiva expressions tree -Selection createSelection(std::shared_ptr<arrow::Table> table, std::shared_ptr<gandiva::Filter> gfilter); +Selection createSelection(std::shared_ptr<arrow::Table> const& table, std::shared_ptr<gandiva::Filter> gfilter); struct ColumnOperationSpec; using Operations = std::vector<ColumnOperationSpec>; diff --git a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h index 45f22623ad0f4..c8c0b67b6f6eb 100644 --- a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,15 +18,14 @@ #include <vector> #include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { /// A callback function to retrieve the FairMQChannel name to be used for sending /// messages of the specified OutputSpec using ChannelRetriever = std::function<std::string(OutputSpec const&, DataProcessingHeader::StartTime)>; using InjectorFunction = std::function<void(FairMQDevice& device, FairMQParts& inputs, ChannelRetriever)>; +using ChannelSelector = std::function<std::string(InputSpec const& input, const std::unordered_map<std::string, std::vector<FairMQChannel>>& channels)>; struct InputChannelSpec; struct OutputChannelSpec; @@ -66,9 +66,12 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& specs = {{header /// The default connection method for the custom source static auto gDefaultConverter = incrementalConverter(OutputSpec{"TST", "TEST", 0}, 0, 1); +/// Default way to select an output channel for multi-output proxy. +std::string defaultOutputProxyChannelSelector(InputSpec const& input, const std::unordered_map<std::string, std::vector<FairMQChannel>>& channels); + /// Create a DataProcessorSpec which can be used to inject /// messages in the DPL. -/// @param label is the label of the DataProcessorSpec associated. +/// @param label is the label of the DataProcessorSpec associated and name of the input channel. /// @param outputs is the type of messages which this source produces. /// @param channelConfig is string to be passed to fairmq to create the device. /// notice that the name of the device will be added as the name of the channel if the @@ -82,6 +85,9 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* label, const char* defaultChannelConfig, InjectorFunction converter); +DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* label, + Inputs const& inputSpecs, + const char* defaultChannelConfig); /// Create a DataProcessorSpec for a DPL processor with an out-of-band channel to relay DPL /// workflow data to an external FairMQDevice channel. /// @@ -100,11 +106,11 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* label, /// by command line option '--channel-config' /// notice that the name of the device will be added as the name of the channel if the /// name tag is not yet in the configuration -DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* label, - Inputs const& inputSpecs, - const char* defaultChannelConfig); +DataProcessorSpec specifyFairMQDeviceMultiOutputProxy(char const* label, + Inputs const& inputSpecs, + const char* defaultChannelConfig, + ChannelSelector channelSelector = defaultOutputProxyChannelSelector); -} // namespace framework } // namespace o2 #endif // FRAMEWORK_RAWDEVICESOURCE_H diff --git a/Framework/Core/include/Framework/FairMQDeviceProxy.h b/Framework/Core/include/Framework/FairMQDeviceProxy.h index ad208e00baa0f..1c57f5d573e5d 100644 --- a/Framework/Core/include/Framework/FairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/FairMQDeviceProxy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,9 +13,7 @@ #include <memory> -class FairMQDevice; -class FairMQMessage; -class FairMQTransportFactory; +#include <fairmq/FwdDecls.h> namespace o2 { diff --git a/Framework/Core/include/Framework/FairOptionsRetriever.h b/Framework/Core/include/Framework/FairOptionsRetriever.h index 3774706db72f0..d37e511ebd6bd 100644 --- a/Framework/Core/include/Framework/FairOptionsRetriever.h +++ b/Framework/Core/include/Framework/FairOptionsRetriever.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ForwardRoute.h b/Framework/Core/include/Framework/ForwardRoute.h index d54b44cb8349c..bae2eaacf1a44 100644 --- a/Framework/Core/include/Framework/ForwardRoute.h +++ b/Framework/Core/include/Framework/ForwardRoute.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/FrameworkGUIDataRelayerUsage.h b/Framework/Core/include/Framework/FrameworkGUIDataRelayerUsage.h deleted file mode 100644 index 85d79a5d26782..0000000000000 --- a/Framework/Core/include/Framework/FrameworkGUIDataRelayerUsage.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -class ImVec2; - -namespace o2 -{ -namespace framework -{ -class DeviceMetricsInfo; -class DeviceInfo; - -namespace gui -{ - -/// View of the DataRelayer metrics for a given DeviceInfo -void displayDataRelayer(DeviceMetricsInfo const& metrics, DeviceInfo const& info, ImVec2 const& size); - -} // namespace gui -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/include/Framework/FrameworkGUIDebugger.h b/Framework/Core/include/Framework/FrameworkGUIDebugger.h deleted file mode 100644 index 20cb8d1671e07..0000000000000 --- a/Framework/Core/include/Framework/FrameworkGUIDebugger.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef FRAMEWORK_FRAMEWORKGUIDEBUGGER_H_ -#define FRAMEWORK_FRAMEWORKGUIDEBUGGER_H_ - -#include "DataProcessorInfo.h" -#include "Framework/DeviceControl.h" -#include "Framework/DeviceInfo.h" -#include "Framework/DeviceMetricsInfo.h" -#include "Framework/DeviceSpec.h" - -#include <functional> -#include <vector> - -namespace o2 -{ -namespace framework -{ - -class DriverInfo; -class DriverControl; - -namespace gui -{ -/// Helper to get the callback to draw the debug GUI -std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, - std::vector<DeviceSpec> const& devices, - std::vector<DataProcessorInfo> const& metadata, - std::vector<DeviceMetricsInfo> const& metricsInfos, - DriverInfo const& driverInfo, - std::vector<DeviceControl>& controls, - DriverControl& driverControl); -} // namespace gui -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_FRAMEWORKGUIDEBUGGER_H diff --git a/Framework/Core/include/Framework/FrameworkGUIDevicesGraph.h b/Framework/Core/include/Framework/FrameworkGUIDevicesGraph.h deleted file mode 100644 index 7842fcdec2343..0000000000000 --- a/Framework/Core/include/Framework/FrameworkGUIDevicesGraph.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ -#define FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ - -#include "../../src/DataProcessorInfo.h" -#include "Framework/DeviceSpec.h" -#include "Framework/DeviceInfo.h" -#include "Framework/DeviceMetricsInfo.h" - -#include <vector> - -namespace o2 -{ -namespace framework -{ -namespace gui -{ - -class WorkspaceGUIState; - -void showTopologyNodeGraph(WorkspaceGUIState& state, - std::vector<DeviceInfo> const& infos, - std::vector<DeviceSpec> const& specs, - std::vector<DataProcessorInfo> const& metadata, - std::vector<DeviceControl>& controls, - std::vector<DeviceMetricsInfo> const& metricsInfos); - -} // namespace gui -} // namespace framework -} // namespace o2 - -#endif // FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ diff --git a/Framework/Core/include/Framework/FrameworkGUIState.h b/Framework/Core/include/Framework/FrameworkGUIState.h deleted file mode 100644 index 245029d88a589..0000000000000 --- a/Framework/Core/include/Framework/FrameworkGUIState.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// State for the main GUI window - -#include <vector> -#include <string> - -namespace o2 -{ -namespace framework -{ -namespace gui -{ - -/// State for the Device specific inspector -struct DeviceGUIState { - std::string label; -}; - -/// State for the workspace -struct WorkspaceGUIState { - int selectedMetric; - size_t metricMinRange; - size_t metricMaxRange; - std::vector<DeviceGUIState> devices; - float leftPaneSize; - float rightPaneSize; - float bottomPaneSize; - bool leftPaneVisible; - bool rightPaneVisible; - bool bottomPaneVisible; -}; - -} // namespace gui -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/include/Framework/FreePortFinder.h b/Framework/Core/include/Framework/FreePortFinder.h index 0bc83a5cf7617..5b1c7aa1cd87c 100644 --- a/Framework/Core/include/Framework/FreePortFinder.h +++ b/Framework/Core/include/Framework/FreePortFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index 2b7d0e3aa1e83..6a19b140c2e56 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #ifndef FRAMEWORK_HISTOGRAMREGISTRY_H_ #define FRAMEWORK_HISTOGRAMREGISTRY_H_ +#include "Framework/HistogramSpec.h" #include "Framework/ASoA.h" #include "Framework/FunctionalHelpers.h" #include "Framework/Logger.h" @@ -18,568 +20,119 @@ #include "Framework/OutputObjHeader.h" #include "Framework/OutputSpec.h" #include "Framework/SerializationMethods.h" -#include "Framework/StringHelpers.h" #include "Framework/TableBuilder.h" #include "Framework/RuntimeError.h" -#include <TH1.h> -#include <TH2.h> -#include <TH3.h> -#include <THn.h> -#include <THnSparse.h> -#include <TProfile.h> -#include <TProfile2D.h> -#include <TProfile3D.h> -#include <TList.h> #include <TDataMember.h> #include <TDataType.h> -#include <string> -#include <variant> #include <deque> -namespace o2::framework -{ -// Available root histogram types -enum HistType : unsigned int { - kUndefinedHist = 0, - kTH1D, - kTH1F, - kTH1I, - kTH1C, - kTH1S, - kTH2D, - kTH2F, - kTH2I, - kTH2C, - kTH2S, - kTH3D, - kTH3F, - kTH3I, - kTH3C, - kTH3S, - kTHnD, - kTHnF, - kTHnI, - kTHnC, - kTHnS, - kTHnL, - kTHnSparseD, - kTHnSparseF, - kTHnSparseI, - kTHnSparseC, - kTHnSparseS, - kTHnSparseL, - kTProfile, - kTProfile2D, - kTProfile3D, - kStepTHnF, // FIXME: for these two to work we need to align StepTHn ctors with the root THn ones - kStepTHnD -}; - -// variant of all possible root pointers; here we use only the interface types since the underlying data representation (int,float,double,long,char) is irrelevant -using HistPtr = std::variant<std::shared_ptr<THn>, std::shared_ptr<THnSparse>, std::shared_ptr<TH3>, std::shared_ptr<TH2>, std::shared_ptr<TH1>, std::shared_ptr<TProfile3D>, std::shared_ptr<TProfile2D>, std::shared_ptr<TProfile>>; - -//************************************************************************************************** -/** - * Specification of an Axis. - */ -//************************************************************************************************** -struct AxisSpec { - AxisSpec(std::vector<double> binEdges_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) - : nBins(std::nullopt), - binEdges(binEdges_), - title(title_), - name(name_) - { - } - - AxisSpec(int nBins_, double binMin_, double binMax_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) - : nBins(nBins_), - binEdges({binMin_, binMax_}), - title(title_), - name(name_) - { - } - - std::optional<int> nBins{}; - std::vector<double> binEdges{}; - std::optional<std::string> title{}; - std::optional<std::string> name{}; // optional axis name for ndim histograms -}; - -//************************************************************************************************** -/** - * Specification of a histogram configuration. - */ -//************************************************************************************************** -struct HistogramConfigSpec { - HistogramConfigSpec(HistType type_, std::vector<AxisSpec> axes_) - : type(type_), - axes(axes_) - { - } - HistogramConfigSpec() = default; - HistogramConfigSpec(HistogramConfigSpec const& other) = default; - HistogramConfigSpec(HistogramConfigSpec&& other) = default; - - void addAxis(const AxisSpec& axis) - { - axes.push_back(axis); - } - - void addAxis(int nBins_, double binMin_, double binMax_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) - { - axes.push_back({nBins_, binMin_, binMax_, title_, name_}); - } - - void addAxis(std::vector<double> binEdges_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) - { - axes.push_back({binEdges_, title_, name_}); - } - - void addAxes(std::vector<AxisSpec> axes_) - { - axes.insert(axes.end(), axes_.begin(), axes_.end()); - } - - // add axes defined in other HistogramConfigSpec object - void addAxes(const HistogramConfigSpec& other) - { - axes.insert(axes.end(), other.axes.begin(), other.axes.end()); - } - - HistType type{HistType::kUndefinedHist}; - std::vector<AxisSpec> axes{}; -}; - -//************************************************************************************************** -/** - * Specification of a histogram. - */ -//************************************************************************************************** -struct HistogramSpec { - HistogramSpec(char const* const name_, char const* const title_, HistogramConfigSpec config_, bool callSumw2_ = false) - : name(name_), - id(compile_time_hash(name_)), - title(title_), - config(config_), - callSumw2(callSumw2_) - { - } - - HistogramSpec() - : name(""), - id(0), - config() - { - } - HistogramSpec(HistogramSpec const& other) = default; - HistogramSpec(HistogramSpec&& other) = default; - - std::string name{}; - uint32_t id{}; - std::string title{}; - HistogramConfigSpec config{}; - bool callSumw2{}; // wether or not hist needs heavy error structure produced by Sumw2() -}; - -//************************************************************************************************** -/** - * Static helper class to generate histograms from the specifications. - * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. - */ -//************************************************************************************************** -struct HistFactory { - - // create histogram of type T with the axes defined in HistogramSpec - template <typename T> - static std::shared_ptr<T> createHist(const HistogramSpec& histSpec) - { - constexpr std::size_t MAX_DIM{10}; - const std::size_t nAxes{histSpec.config.axes.size()}; - if (nAxes == 0 || nAxes > MAX_DIM) { - LOGF(FATAL, "The histogram specification contains no (or too many) axes."); - return nullptr; - } - - int nBins[MAX_DIM]{0}; - double lowerBounds[MAX_DIM]{0.}; - double upperBounds[MAX_DIM]{0.}; - - // first figure out number of bins and dimensions - for (std::size_t i = 0; i < nAxes; i++) { - nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; - lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); - upperBounds[i] = histSpec.config.axes[i].binEdges.back(); - } - - // create histogram - std::shared_ptr<T> hist{generateHist<T>(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds)}; - if (!hist) { - LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); - return nullptr; - } - - // set axis properties - for (std::size_t i = 0; i < nAxes; i++) { - TAxis* axis{getAxis(i, hist)}; - if (axis) { - if (histSpec.config.axes[i].title) { - axis->SetTitle((*histSpec.config.axes[i].title).data()); - } - - // this helps to have axes not only called 0,1,2... in ndim histos - if constexpr (std::is_base_of_v<THnBase, T>) { - if (histSpec.config.axes[i].name) { - axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); - } - } - - // move the bin edges in case a variable binning was requested - if (!histSpec.config.axes[i].nBins) { - if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { - LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); - return nullptr; - } - axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); - } - } - } - if (histSpec.callSumw2) { - hist->Sumw2(); - } - - return hist; - } - - // create histogram and return it casted to the correct alternative held in HistPtr variant - template <typename T> - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - if (auto hist = castToVariant(createHist<T>(histSpec))) { - return *hist; - } else { - throw runtime_error("Histogram was not created properly."); - } - } +class TList; - // runtime version of the above - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - if (histSpec.config.type == HistType::kUndefinedHist) { - throw runtime_error("Histogram type was not specified."); - } else { - return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); - } - } - - // helper function to get the axis via index for any type of root histogram - template <typename T> - static TAxis* getAxis(const int i, std::shared_ptr<T>& hist) - { - if constexpr (std::is_base_of_v<THnBase, T>) { - return hist->GetAxis(i); - } else { - return (i == 0) ? hist->GetXaxis() - : (i == 1) ? hist->GetYaxis() - : (i == 2) ? hist->GetZaxis() - : nullptr; - } - } - - private: - static const std::map<HistType, std::function<HistPtr(const HistogramSpec&)>> HistogramCreationCallbacks; - - // helper function to generate the actual histograms - template <typename T> - static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, - const int nBins[], const double lowerBounds[], const double upperBounds[]) - { - if constexpr (std::is_base_of_v<THnBase, T>) { - return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v<TH3, T>) { - return (nDim != 3) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], - nBins[2], lowerBounds[2], upperBounds[2]); - } else if constexpr (std::is_base_of_v<TH2, T>) { - return (nDim != 2) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); - } else if constexpr (std::is_base_of_v<TH1, T>) { - return (nDim != 1) - ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); - } - return nullptr; - } - - // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant - template <typename T> - static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj) - { - if (obj->InheritsFrom(T::Class())) { - return std::static_pointer_cast<T>(obj); - } - return std::nullopt; - } - - template <typename T, typename Next, typename... Rest> - static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj) - { - if (auto hist = castToVariant<T>(obj)) { - return hist; - } - return castToVariant<Next, Rest...>(obj); - } - - static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj) - { - if (obj) { - // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 - return castToVariant<THn, THnSparse, TProfile3D, TH3, TProfile2D, TH2, TProfile, TH1>(obj); - } - return std::nullopt; - } -}; +#define HIST(name) CONST_STR(name) +namespace o2::framework +{ //************************************************************************************************** /** - * Static helper class to fill existing root histograms of any type. - * Contains functionality to fill once per call or a whole (filtered) table at once. + * Static helper class to fill root histograms of any type. Contains functionality to fill once per call or a whole (filtered) table at once. */ //************************************************************************************************** struct HistFiller { // fill any type of histogram (if weight was requested it must be the last argument) template <typename T, typename... Ts> - static void fillHistAny(std::shared_ptr<T>& hist, const Ts&... positionAndWeight) - { - constexpr int nArgs = sizeof...(Ts); - - constexpr bool validTH3 = (std::is_same_v<TH3, T> && (nArgs == 3 || nArgs == 4)); - constexpr bool validTH2 = (std::is_same_v<TH2, T> && (nArgs == 2 || nArgs == 3)); - constexpr bool validTH1 = (std::is_same_v<TH1, T> && (nArgs == 1 || nArgs == 2)); - constexpr bool validTProfile3D = (std::is_same_v<TProfile3D, T> && (nArgs == 4 || nArgs == 5)); - constexpr bool validTProfile2D = (std::is_same_v<TProfile2D, T> && (nArgs == 3 || nArgs == 4)); - constexpr bool validTProfile = (std::is_same_v<TProfile, T> && (nArgs == 2 || nArgs == 3)); - - constexpr bool validSimpleFill = validTH1 || validTH2 || validTH3 || validTProfile || validTProfile2D || validTProfile3D; - // unfortunately we dont know at compile the dimension of THn(Sparse) - constexpr bool validComplexFill = std::is_base_of_v<THnBase, T>; - - if constexpr (validSimpleFill) { - hist->Fill(static_cast<double>(positionAndWeight)...); - } else if constexpr (validComplexFill) { - double tempArray[] = {static_cast<double>(positionAndWeight)...}; - double weight{1.}; - if (hist->GetNdimensions() == nArgs - 1) { - weight = tempArray[nArgs - 1]; - } else if (hist->GetNdimensions() != nArgs) { - LOGF(FATAL, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", hist->GetName()); - } - hist->Fill(tempArray, weight); - } else { - LOGF(FATAL, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", hist->GetName()); - } - } + static void fillHistAny(std::shared_ptr<T> hist, const Ts&... positionAndWeight); // fill any type of histogram with columns (Cs) of a filtered table (if weight is requested it must reside the last specified column) template <typename... Cs, typename R, typename T> - static void fillHistAny(std::shared_ptr<R>& hist, const T& table, const o2::framework::expressions::Filter& filter) - { - auto filtered = o2::soa::Filtered<T>{{table.asArrowTable()}, o2::framework::expressions::createSelection(table.asArrowTable(), filter)}; - for (auto& t : filtered) { - fillHistAny(hist, (*(static_cast<Cs>(t).getIterator()))...); - } - } + static void fillHistAny(std::shared_ptr<R> hist, const T& table, const o2::framework::expressions::Filter& filter); // function that returns rough estimate for the size of a histogram in MB template <typename T> - static double getSize(std::shared_ptr<T>& hist, double fillFraction = 1.) - { - double size{0.}; - if constexpr (std::is_base_of_v<TH1, T>) { - size = hist->GetNcells() * (HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2()->fN) ? sizeof(double) : 0.)); - } else if constexpr (std::is_base_of_v<THn, T>) { - size = hist->GetNbins() * (HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2() != -1.) ? sizeof(double) : 0.)); - } else if constexpr (std::is_base_of_v<THnSparse, T>) { - // THnSparse has massive overhead and should only be used when histogram is large and a very small fraction of bins is filled - double nBinsTotal = 1.; - int compCoordSize = 0; // size required to store a compact coordinate representation - for (int d = 0; d < hist->GetNdimensions(); ++d) { - int nBins = hist->GetAxis(d)->GetNbins() + 2; - nBinsTotal *= nBins; - - // number of bits needed to store compact coordinates - int b = 1; - while (nBins /= 2) { - ++b; - } - compCoordSize += b; - } - compCoordSize = (compCoordSize + 7) / 8; // turn bits into bytes - - // THnSparse stores the data in an array of chunks (THnSparseArrayChunk), each containing a fixed number of bins (e.g. 1024 * 16) - double nBinsFilled = fillFraction * nBinsTotal; - int nCunks = ceil(nBinsFilled / hist->GetChunkSize()); - int chunkOverhead = sizeof(THnSparseArrayChunk); - - // each chunk holds array of compact bin-coordinates and an array of bin content (+ one of bin error if requested) - double binSize = compCoordSize + HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2() != -1.) ? sizeof(double) : 0.); - size = nCunks * (chunkOverhead + hist->GetChunkSize() * binSize); - // since THnSparse must keep track of all the stored bins, it stores a map that - // relates the compact bin coordinates (or a hash thereof) to a linear index - // this index determines in which chunk and therein at which position to find / store bin coordinate and content - size += nBinsFilled * 3 * sizeof(Long64_t); // hash, key, value; not sure why 3 are needed here... - } - return size / 1048576.; - } + static double getSize(std::shared_ptr<T> hist, double fillFraction = 1.); private: // helper function to determine base element size of histograms (in bytes) - // the complicated casting gymnastics are needed here since we only store the interface types in the registry template <typename T> - static int getBaseElementSize(T* ptr) - { - if constexpr (std::is_base_of_v<TH1, T> || std::is_base_of_v<THnSparse, T>) { - return getBaseElementSize<TArrayD, TArrayF, TArrayC, TArrayI, TArrayC, TArrayL>(ptr); - } else { - return getBaseElementSize<double, float, int, short, char, long>(ptr); - } - } + static int getBaseElementSize(T* ptr); template <typename T, typename Next, typename... Rest, typename P> - static int getBaseElementSize(P* ptr) - { - if (auto size = getBaseElementSize<T>(ptr)) { - return size; - } - return getBaseElementSize<Next, Rest...>(ptr); - } + static int getBaseElementSize(P* ptr); template <typename B, typename T> - static int getBaseElementSize(T* ptr) - { - if constexpr (std::is_base_of_v<THn, T>) { - if (dynamic_cast<THnT<B>*>(ptr)) { - return sizeof(B); - } - } else if constexpr (std::is_base_of_v<THnSparse, T>) { - if (dynamic_cast<THnSparseT<B>*>(ptr)) { - TDataMember* dm = B::Class()->GetDataMember("fArray"); - return dm ? dm->GetDataType()->Size() : 0; - } - } else if constexpr (std::is_base_of_v<TH1, T>) { - if (auto arrayPtr = dynamic_cast<B*>(ptr)) { - return sizeof(arrayPtr->At(0)); - } - } - return 0; - }; + static int getBaseElementSize(T* ptr); }; //************************************************************************************************** /** - * Histogram registry that can be used to store and fill histograms of any type. + * HistogramRegistry for storing and filling histograms of any type. */ //************************************************************************************************** class HistogramRegistry { + // HistogramName class providing the associated hash and a first guess for the index in the registry + struct HistName { + // ctor for histogram names that are already hashed at compile time via HIST("myHistName") + template <char... chars> + constexpr HistName(const ConstStr<chars...>& hashedHistName); + char const* const str{}; + const uint32_t hash{}; + const uint32_t idx{}; + + protected: + friend class HistogramRegistry; + // ctor that does the hashing at runtime (for internal use only) + constexpr HistName(char const* const name); + }; + public: - HistogramRegistry(char const* const name, std::vector<HistogramSpec> histSpecs = {}, OutputObjHandlingPolicy policy = OutputObjHandlingPolicy::AnalysisObject, bool sortHistos = true, bool createRegistryDir = false) - : mName(name), mPolicy(policy), mRegistryKey(), mRegistryValue(), mSortHistos(sortHistos), mCreateRegistryDir(createRegistryDir) - { - mRegistryKey.fill(0u); - for (auto& histSpec : histSpecs) { - insert(histSpec); - } - } + HistogramRegistry(char const* const name = "histograms", std::vector<HistogramSpec> histSpecs = {}, OutputObjHandlingPolicy policy = OutputObjHandlingPolicy::AnalysisObject, bool sortHistos = true, bool createRegistryDir = false); // functions to add histograms to the registry - void add(const HistogramSpec& histSpec); - void add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2 = false); - void add(char const* const name, char const* const title, HistType histType, std::vector<AxisSpec> axes, bool callSumw2 = false); + HistPtr add(const HistogramSpec& histSpec); + HistPtr add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2 = false); + HistPtr add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2 = false); + + template <typename T> + std::shared_ptr<T> add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2 = false); + template <typename T> + std::shared_ptr<T> add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2 = false); + void addClone(const std::string& source, const std::string& target); // function to query if name is already in use - bool contains(char const* const name) - { - return contains(compile_time_hash(name), name); - } + bool contains(const HistName& histName); - // gets the underlying histogram pointer - // we cannot automatically infer type here so it has to be explicitly specified - // -> get<TH1>(), get<TH2>(), get<TH3>(), get<THn>(), get<THnSparse>(), get<TProfile>(), get<TProfile2D>(), get<TProfile3D>() - /// @return the histogram registered with name @a name + // get the underlying histogram pointer template <typename T> - auto& get(char const* const name) - { - if (auto histPtr = std::get_if<std::shared_ptr<T>>(&mRegistryValue[getHistIndex(name)])) { - return *histPtr; - } else { - throw runtime_error("Histogram type specified in get() does not match actual histogram type!"); - } - } + std::shared_ptr<T> get(const HistName& histName); - /// @return the histogram registered with name @a name template <typename T> - auto& operator()(char const* const name) - { - return get<T>(name); - } + std::shared_ptr<T> operator()(const HistName& histName); - /// @return the associated OutputSpec - OutputSpec const spec() - { - ConcreteDataMatcher matcher{"ATSK", "\0", 0}; - strncpy(matcher.description.str, mName.data(), 16); - return OutputSpec{OutputLabel{mName}, matcher}; - } + // return the OutputSpec associated to the HistogramRegistry + OutputSpec const spec(); - OutputRef ref() - { - return OutputRef{std::string{mName}, 0, o2::header::Stack{OutputObjHeader{mPolicy, mTaskHash}}}; - } + OutputRef ref(); - void setHash(uint32_t hash) - { - mTaskHash = hash; - } + void setHash(uint32_t hash); TList* operator*(); // fill hist with values template <typename... Ts> - void fill(char const* const name, Ts&&... positionAndWeight) - { - std::visit([&positionAndWeight...](auto&& hist) { HistFiller::fillHistAny(hist, std::forward<Ts>(positionAndWeight)...); }, mRegistryValue[getHistIndex(name)]); - } + void fill(const HistName& histName, Ts&&... positionAndWeight); // fill hist with content of (filtered) table columns template <typename... Cs, typename T> - void fill(char const* const name, const T& table, const o2::framework::expressions::Filter& filter) - { - std::visit([&table, &filter](auto&& hist) { HistFiller::fillHistAny<Cs...>(hist, table, filter); }, mRegistryValue[getHistIndex(name)]); - } + void fill(const HistName& histName, const T& table, const o2::framework::expressions::Filter& filter); // get rough estimate for size of histogram stored in registry - double getSize(char const* const name, double fillFraction = 1.) - { - double size{}; - std::visit([&fillFraction, &size](auto&& hist) { size = HistFiller::getSize(hist, fillFraction); }, mRegistryValue[getHistIndex(name)]); - return size; - } + double getSize(const HistName& histName, double fillFraction = 1.); // get rough estimate for size of all histograms stored in registry - double getSize(double fillFraction = 1.) - { - double size{}; - for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) { - std::visit([&fillFraction, &size](auto&& hist) { if(hist) { size += HistFiller::getSize(hist, fillFraction);} }, mRegistryValue[j]); - } - return size; - } + double getSize(double fillFraction = 1.); // print summary of the histograms stored in registry void print(bool showAxisDetails = false); @@ -589,65 +142,24 @@ class HistogramRegistry private: // create histogram from specification and insert it into the registry - void insert(const HistogramSpec& histSpec) - { - const uint32_t i = imask(histSpec.id); - for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) { - TObject* rawPtr = nullptr; - std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(j + i)]); - if (!rawPtr) { - registerName(histSpec.name); - mRegistryKey[imask(j + i)] = histSpec.id; - mRegistryValue[imask(j + i)] = HistFactory::createHistVariant(histSpec); - lookup += j; - return; - } - } - LOGF(FATAL, "Internal array of HistogramRegistry %s is full.", mName); - } + HistPtr insert(const HistogramSpec& histSpec); // clone an existing histogram and insert it into the registry template <typename T> - void insertClone(char const* const name, const std::shared_ptr<T>& originalHist) - { - const uint32_t id = compile_time_hash(name); - const uint32_t i = imask(id); - for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) { - TObject* rawPtr = nullptr; - std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(j + i)]); - if (!rawPtr) { - registerName(name); - mRegistryKey[imask(j + i)] = id; - mRegistryValue[imask(j + i)] = std::shared_ptr<T>(static_cast<T*>(originalHist->Clone(name))); - lookup += j; - return; - } - } - LOGF(FATAL, "Internal array of HistogramRegistry %s is full.", mName); - } + HistPtr insertClone(const HistName& histName, const std::shared_ptr<T> originalHist); - constexpr uint32_t imask(uint32_t i) const - { - return i & MASK; - } + // helper function that checks if histogram name can be used in registry + void validateHistName(const char* name, const uint32_t hash); + + // helper function to find the histogram position in the registry + template <typename T> + uint32_t getHistIndex(const T& histName); - uint32_t getHistIndex(char const* const name) + constexpr uint32_t imask(uint32_t i) const { - const uint32_t id = compile_time_hash(name); - const uint32_t i = imask(id); - if (O2_BUILTIN_LIKELY(id == mRegistryKey[i])) { - return i; - } - for (auto j = 1u; j < MAX_REGISTRY_SIZE; ++j) { - if (id == mRegistryKey[imask(j + i)]) { - return imask(j + i); - } - } - throw runtime_error("No matching histogram found in HistogramRegistry!"); + return i & REGISTRY_BITMASK; } - bool contains(const uint32_t id, char const* const name); - // helper function to create resp. find the subList defined by path TList* getSubList(TList* list, std::deque<std::string>& path); @@ -664,13 +176,245 @@ class HistogramRegistry uint32_t mTaskHash{}; std::vector<std::string> mRegisteredNames{}; - // The maximum number of histograms in buffer is currently set to 512 + // the maximum number of histograms in buffer is currently set to 512 // which seems to be both reasonably large and allowing for very fast lookup - static constexpr uint32_t MASK{0x1FF}; - static constexpr uint32_t MAX_REGISTRY_SIZE{MASK + 1}; + static constexpr uint32_t REGISTRY_BITMASK{0x1FF}; + static constexpr uint32_t MAX_REGISTRY_SIZE{REGISTRY_BITMASK + 1}; std::array<uint32_t, MAX_REGISTRY_SIZE> mRegistryKey{}; std::array<HistPtr, MAX_REGISTRY_SIZE> mRegistryValue{}; }; +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +// Implementation of HistFiller template functions. +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +template <typename T, typename... Ts> +void HistFiller::fillHistAny(std::shared_ptr<T> hist, const Ts&... positionAndWeight) +{ + constexpr int nArgs = sizeof...(Ts); + + constexpr bool validTH3 = (std::is_same_v<TH3, T> && (nArgs == 3 || nArgs == 4)); + constexpr bool validTH2 = (std::is_same_v<TH2, T> && (nArgs == 2 || nArgs == 3)); + constexpr bool validTH1 = (std::is_same_v<TH1, T> && (nArgs == 1 || nArgs == 2)); + constexpr bool validTProfile3D = (std::is_same_v<TProfile3D, T> && (nArgs == 4 || nArgs == 5)); + constexpr bool validTProfile2D = (std::is_same_v<TProfile2D, T> && (nArgs == 3 || nArgs == 4)); + constexpr bool validTProfile = (std::is_same_v<TProfile, T> && (nArgs == 2 || nArgs == 3)); + + constexpr bool validSimpleFill = validTH1 || validTH2 || validTH3 || validTProfile || validTProfile2D || validTProfile3D; + // unfortunately we dont know at compile the dimension of THn(Sparse) + constexpr bool validComplexFill = std::is_base_of_v<THnBase, T>; + constexpr bool validComplexFillStep = std::is_base_of_v<StepTHn, T>; + + if constexpr (validSimpleFill) { + hist->Fill(static_cast<double>(positionAndWeight)...); + } else if constexpr (validComplexFillStep) { + hist->Fill(positionAndWeight...); // first argument in pack is iStep, dimension check is done in StepTHn itself + } else if constexpr (validComplexFill) { + double tempArray[] = {static_cast<double>(positionAndWeight)...}; + double weight{1.}; + constexpr int nArgsMinusOne = nArgs - 1; + if (hist->GetNdimensions() == nArgsMinusOne) { + weight = tempArray[nArgsMinusOne]; + } else if (hist->GetNdimensions() != nArgs) { + LOGF(FATAL, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", hist->GetName()); + } + hist->Fill(tempArray, weight); + } else { + LOGF(FATAL, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", hist->GetName()); + } +} + +template <typename... Cs, typename R, typename T> +void HistFiller::fillHistAny(std::shared_ptr<R> hist, const T& table, const o2::framework::expressions::Filter& filter) +{ + if constexpr (std::is_base_of_v<StepTHn, T>) { + LOGF(FATAL, "Table filling is not (yet?) supported for StepTHn."); + return; + } + auto filtered = o2::soa::Filtered<T>{{table.asArrowTable()}, o2::framework::expressions::createSelection(table.asArrowTable(), filter)}; + for (auto& t : filtered) { + fillHistAny(hist, (*(static_cast<Cs>(t).getIterator()))...); + } +} + +template <typename T> +double HistFiller::getSize(std::shared_ptr<T> hist, double fillFraction) +{ + double size{0.}; + if constexpr (std::is_base_of_v<TH1, T>) { + size = hist->GetNcells() * (HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2()->fN) ? sizeof(double) : 0.)); + } else if constexpr (std::is_base_of_v<THn, T>) { + size = hist->GetNbins() * (HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2() != -1.) ? sizeof(double) : 0.)); + } else if constexpr (std::is_base_of_v<THnSparse, T>) { + // THnSparse has massive overhead and should only be used when histogram is large and a very small fraction of bins is filled + double nBinsTotal = 1.; + int compCoordSize = 0; // size required to store a compact coordinate representation + for (int d = 0; d < hist->GetNdimensions(); ++d) { + int nBins = hist->GetAxis(d)->GetNbins() + 2; + nBinsTotal *= nBins; + + // number of bits needed to store compact coordinates + int b = 1; + while (nBins /= 2) { + ++b; + } + compCoordSize += b; + } + compCoordSize = (compCoordSize + 7) / 8; // turn bits into bytes + + // THnSparse stores the data in an array of chunks (THnSparseArrayChunk), each containing a fixed number of bins (e.g. 1024 * 16) + double nBinsFilled = fillFraction * nBinsTotal; + int nCunks = ceil(nBinsFilled / hist->GetChunkSize()); + int chunkOverhead = sizeof(THnSparseArrayChunk); + + // each chunk holds array of compact bin-coordinates and an array of bin content (+ one of bin error if requested) + double binSize = compCoordSize + HistFiller::getBaseElementSize(hist.get()) + ((hist->GetSumw2() != -1.) ? sizeof(double) : 0.); + size = nCunks * (chunkOverhead + hist->GetChunkSize() * binSize); + // since THnSparse must keep track of all the stored bins, it stores a map that + // relates the compact bin coordinates (or a hash thereof) to a linear index + // this index determines in which chunk and therein at which position to find / store bin coordinate and content + size += nBinsFilled * 3 * sizeof(Long64_t); // hash, key, value; not sure why 3 are needed here... + } + return size / 1048576.; +} + +template <typename T> +int HistFiller::getBaseElementSize(T* ptr) +{ + if constexpr (std::is_base_of_v<TH1, T> || std::is_base_of_v<THnSparse, T>) { + return getBaseElementSize<TArrayD, TArrayF, TArrayC, TArrayI, TArrayC, TArrayL>(ptr); + } else { + return getBaseElementSize<double, float, int, short, char, long>(ptr); + } +} + +template <typename T, typename Next, typename... Rest, typename P> +int HistFiller::getBaseElementSize(P* ptr) +{ + if (auto size = getBaseElementSize<T>(ptr)) { + return size; + } + return getBaseElementSize<Next, Rest...>(ptr); +} + +template <typename B, typename T> +int HistFiller::getBaseElementSize(T* ptr) +{ + if constexpr (std::is_base_of_v<THn, T>) { + if (dynamic_cast<THnT<B>*>(ptr)) { + return sizeof(B); + } + } else if constexpr (std::is_base_of_v<THnSparse, T>) { + if (dynamic_cast<THnSparseT<B>*>(ptr)) { + TDataMember* dm = B::Class()->GetDataMember("fArray"); + return dm ? dm->GetDataType()->Size() : 0; + } + } else if constexpr (std::is_base_of_v<TH1, T>) { + if (auto arrayPtr = dynamic_cast<B*>(ptr)) { + return sizeof(arrayPtr->At(0)); + } + } + return 0; +} + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +// Implementation of HistogramRegistry template functions. +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +template <char... chars> +constexpr HistogramRegistry::HistName::HistName(const ConstStr<chars...>& hashedHistName) + : str(hashedHistName.str), + hash(hashedHistName.hash), + idx(hash & REGISTRY_BITMASK) +{ +} + +template <typename T> +std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2) +{ + auto histVariant = add(name, title, histConfigSpec, callSumw2); + if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) { + return *histPtr; + } else { + throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name); + } +} + +template <typename T> +std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2) +{ + auto histVariant = add(name, title, histType, axes, callSumw2); + if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) { + return *histPtr; + } else { + throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name); + } +} + +template <typename T> +std::shared_ptr<T> HistogramRegistry::get(const HistName& histName) +{ + if (auto histPtr = std::get_if<std::shared_ptr<T>>(&mRegistryValue[getHistIndex(histName)])) { + return *histPtr; + } else { + throw runtime_error_f(R"(Histogram type specified in get<>(HIST("%s")) does not match the actual type of the histogram!)", histName.str); + } +} + +template <typename T> +std::shared_ptr<T> HistogramRegistry::operator()(const HistName& histName) +{ + return get<T>(histName); +} + +template <typename T> +HistPtr HistogramRegistry::insertClone(const HistName& histName, const std::shared_ptr<T> originalHist) +{ + validateHistName(histName.str, histName.hash); + for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) { + TObject* rawPtr = nullptr; + std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(histName.idx + i)]); + if (!rawPtr) { + registerName(histName.str); + mRegistryKey[imask(histName.idx + i)] = histName.hash; + mRegistryValue[imask(histName.idx + i)] = std::shared_ptr<T>(static_cast<T*>(originalHist->Clone(histName.str))); + lookup += i; + return mRegistryValue[imask(histName.idx + i)]; + } + } + LOGF(FATAL, R"(Internal array of HistogramRegistry "%s" is full.)", mName); + return HistPtr(); +} + +template <typename T> +uint32_t HistogramRegistry::getHistIndex(const T& histName) +{ + if (O2_BUILTIN_LIKELY(histName.hash == mRegistryKey[histName.idx])) { + return histName.idx; + } + for (auto i = 1u; i < MAX_REGISTRY_SIZE; ++i) { + if (histName.hash == mRegistryKey[imask(histName.idx + i)]) { + return imask(histName.idx + i); + } + } + throw runtime_error_f(R"(Could not find histogram "%s" in HistogramRegistry "%s"!)", histName.str, mName.data()); +} + +template <typename... Ts> +void HistogramRegistry::fill(const HistName& histName, Ts&&... positionAndWeight) +{ + std::visit([&positionAndWeight...](auto&& hist) { HistFiller::fillHistAny(hist, std::forward<Ts>(positionAndWeight)...); }, mRegistryValue[getHistIndex(histName)]); +} + +template <typename... Cs, typename T> +void HistogramRegistry::fill(const HistName& histName, const T& table, const o2::framework::expressions::Filter& filter) +{ + std::visit([&table, &filter](auto&& hist) { HistFiller::fillHistAny<Cs...>(hist, table, filter); }, mRegistryValue[getHistIndex(histName)]); +} + } // namespace o2::framework #endif // FRAMEWORK_HISTOGRAMREGISTRY_H_ diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h new file mode 100644 index 0000000000000..f8f97529f71fd --- /dev/null +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -0,0 +1,299 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef FRAMEWORK_HISTOGRAMSPEC_H_ +#define FRAMEWORK_HISTOGRAMSPEC_H_ + +#include <string> +#include <variant> +#include <optional> + +#include "Framework/StringHelpers.h" +#include "Framework/Configurable.h" + +#include "Framework/StepTHn.h" +#include <TH1.h> +#include <TH2.h> +#include <TH3.h> +#include <THn.h> +#include <THnSparse.h> +#include <TProfile.h> +#include <TProfile2D.h> +#include <TProfile3D.h> + +namespace o2::framework +{ +// Available root histogram types +enum HistType : unsigned int { + kUndefinedHist = 0, + kTH1D, + kTH1F, + kTH1I, + kTH1C, + kTH1S, + kTH2D, + kTH2F, + kTH2I, + kTH2C, + kTH2S, + kTH3D, + kTH3F, + kTH3I, + kTH3C, + kTH3S, + kTHnD, + kTHnF, + kTHnI, + kTHnC, + kTHnS, + kTHnL, + kTHnSparseD, + kTHnSparseF, + kTHnSparseI, + kTHnSparseC, + kTHnSparseS, + kTHnSparseL, + kTProfile, + kTProfile2D, + kTProfile3D, + kStepTHnF, + kStepTHnD +}; + +// variant of all possible root pointers; here we use only the interface types since the underlying data representation (int,float,double,long,char) is irrelevant +using HistPtr = std::variant<std::shared_ptr<THn>, std::shared_ptr<THnSparse>, std::shared_ptr<TH3>, std::shared_ptr<TH2>, std::shared_ptr<TH1>, std::shared_ptr<TProfile3D>, std::shared_ptr<TProfile2D>, std::shared_ptr<TProfile>, std::shared_ptr<StepTHn>>; + +//************************************************************************************************** +/** + * Specification of an Axis. + */ +//************************************************************************************************** +// flag to mark variable bin size in configurable bin edges +constexpr double VARIABLE_WIDTH = 0.; + +struct AxisSpec { + AxisSpec(std::vector<double> binEdges_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) + : nBins(std::nullopt), + binEdges(binEdges_), + title(title_), + name(name_) + { + } + + AxisSpec(int nBins_, double binMin_, double binMax_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) + : nBins(nBins_), + binEdges({binMin_, binMax_}), + title(title_), + name(name_) + { + if (binMin_ > binMax_) { + LOG(FATAL) << "Defined ill-defined axis"; + } + } + + // first entry is assumed to be the number of bins; in case of variable size binning it must be set to zero + AxisSpec(ConfigurableAxis binEdges_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) + : nBins(std::nullopt), + binEdges(std::vector<double>(binEdges_)), + title(title_), + name(name_) + { + if (binEdges.empty()) { + return; + } + if (binEdges[0] != VARIABLE_WIDTH) { + nBins = static_cast<int>(binEdges[0]); + binEdges.resize(3); // nBins, lowerBound, upperBound, disregard whatever else is stored in vecotr + } + binEdges.erase(binEdges.begin()); // remove first entry that we assume to be number of bins + } + + /// Function to make the axis logartitmic + void makeLogaritmic() + { + if (binEdges.size() > 2) { + LOG(FATAL) << "Cannot make a variabled bin width axis logaritmic"; + } + + const double min = binEdges[0]; + const double width = (binEdges[1] - binEdges[0]) / nBins.value(); + binEdges.clear(); + binEdges.resize(0); + for (int i = 0; i < nBins.value() + 1; i++) { + binEdges.push_back(std::pow(10., min + i * width)); + } + nBins = std::nullopt; + } + + /// Data members + std::optional<int> nBins{}; /// Number of bins (only used for fixed bin width axis) + std::vector<double> binEdges{}; /// Edges of the bin. For fixed bin width these are the limits of the binning + std::optional<std::string> title{}; /// Optional title of the axis + std::optional<std::string> name{}; /// Optional axis name for ndim histograms +}; + +//************************************************************************************************** +/** + * Specification of a histogram configuration. + */ +//************************************************************************************************** +struct HistogramConfigSpec { + HistogramConfigSpec(HistType type_, std::vector<AxisSpec> axes_, uint8_t nSteps_ = 1) + : type(type_), + axes(axes_), + nSteps(nSteps_) + { + } + HistogramConfigSpec() = default; + HistogramConfigSpec(HistogramConfigSpec const& other) = default; + HistogramConfigSpec(HistogramConfigSpec&& other) = default; + + void addAxis(const AxisSpec& axis) + { + axes.push_back(axis); + } + + void addAxis(int nBins_, double binMin_, double binMax_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) + { + axes.push_back({nBins_, binMin_, binMax_, title_, name_}); + } + + void addAxis(std::vector<double> binEdges_, std::optional<std::string> title_ = std::nullopt, std::optional<std::string> name_ = std::nullopt) + { + axes.push_back({binEdges_, title_, name_}); + } + + void addAxes(std::vector<AxisSpec> axes_) + { + axes.insert(axes.end(), axes_.begin(), axes_.end()); + } + + // add axes defined in other HistogramConfigSpec object + void addAxes(const HistogramConfigSpec& other) + { + axes.insert(axes.end(), other.axes.begin(), other.axes.end()); + } + + HistType type{HistType::kUndefinedHist}; + std::vector<AxisSpec> axes{}; + uint32_t nSteps{1}; // variable used only in StepTHn +}; + +//************************************************************************************************** +/** + * Specification of a histogram. + */ +//************************************************************************************************** +struct HistogramSpec { + HistogramSpec(char const* const name_, char const* const title_, HistogramConfigSpec config_, bool callSumw2_ = false) + : name(name_), + hash(compile_time_hash(name_)), + title(title_), + config(config_), + callSumw2(callSumw2_) + { + } + + HistogramSpec() + : name(""), + hash(0), + config() + { + } + HistogramSpec(HistogramSpec const& other) = default; + HistogramSpec(HistogramSpec&& other) = default; + + std::string name{}; + uint32_t hash{}; + std::string title{}; + HistogramConfigSpec config{}; + bool callSumw2{}; // wether or not hist needs heavy error structure produced by Sumw2() +}; + +//************************************************************************************************** +/** + * Static helper class to generate histograms from the specifications. + * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. + */ +//************************************************************************************************** +struct HistFactory { + + // create histogram of type T with the axes defined in HistogramSpec + template <typename T> + static std::unique_ptr<T> createHist(const HistogramSpec& histSpec); + + // create histogram and return it casted to the correct alternative held in HistPtr variant + template <typename T> + static HistPtr createHistVariant(const HistogramSpec& histSpec); + + // runtime version of the above + static HistPtr createHistVariant(const HistogramSpec& histSpec); + + // helper function to get the axis via index for any type of root histogram + template <typename T> + static TAxis* getAxis(const int i, T* hist); + + private: + static const std::map<HistType, std::function<HistPtr(const HistogramSpec&)>> HistogramCreationCallbacks; + + // helper function to generate the actual histograms + template <typename T> + static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, + const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps = 1); + + // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant + template <typename T> + static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj); + + template <typename T, typename Next, typename... Rest> + static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj); + + static std::optional<HistPtr> castToVariant(std::shared_ptr<TObject> obj); +}; + +#define DECLAREEXT(HType) \ + extern template std::unique_ptr<HType> HistFactory::createHist<HType>(const HistogramSpec& histSpec); +DECLAREEXT(TH1D); +DECLAREEXT(TH1F); +DECLAREEXT(TH1I); +DECLAREEXT(TH1C); +DECLAREEXT(TH1S); +DECLAREEXT(TH2D); +DECLAREEXT(TH2F); +DECLAREEXT(TH2I); +DECLAREEXT(TH2C); +DECLAREEXT(TH2S); +DECLAREEXT(TH3D); +DECLAREEXT(TH3F); +DECLAREEXT(TH3I); +DECLAREEXT(TH3C); +DECLAREEXT(TH3S); +DECLAREEXT(THnD); +DECLAREEXT(THnF); +DECLAREEXT(THnI); +DECLAREEXT(THnC); +DECLAREEXT(THnS); +DECLAREEXT(THnL); +DECLAREEXT(THnSparseD); +DECLAREEXT(THnSparseF); +DECLAREEXT(THnSparseI); +DECLAREEXT(THnSparseC); +DECLAREEXT(THnSparseS); +DECLAREEXT(THnSparseL); +DECLAREEXT(TProfile); +DECLAREEXT(TProfile2D); +DECLAREEXT(TProfile3D); +DECLAREEXT(StepTHnF); +DECLAREEXT(StepTHnD) +#undef DECLAREEXT + +} // namespace o2::framework +#endif // FRAMEWORK_HISTOGRAMSPEC_H_ diff --git a/Framework/Core/include/Framework/InitContext.h b/Framework/Core/include/Framework/InitContext.h index 9119921634e75..e1049c8f91337 100644 --- a/Framework/Core/include/Framework/InitContext.h +++ b/Framework/Core/include/Framework/InitContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/InputRecord.h b/Framework/Core/include/Framework/InputRecord.h index 47813bdb89757..62a0d19fccfac 100644 --- a/Framework/Core/include/Framework/InputRecord.h +++ b/Framework/Core/include/Framework/InputRecord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,11 +15,9 @@ #include "Framework/DataRefUtils.h" #include "Framework/InputRoute.h" #include "Framework/TypeTraits.h" -#include "Framework/InputSpan.h" #include "Framework/TableConsumer.h" #include "Framework/Traits.h" #include "Framework/RuntimeError.h" -#include "MemoryResources/Types.h" #include "Headers/DataHeader.h" #include "CommonUtils/BoostSerializer.h" @@ -33,7 +32,7 @@ #include <memory> #include <type_traits> -class FairMQMessage; +#include <fairmq/FwdDecls.h> namespace o2 { @@ -41,6 +40,7 @@ namespace framework { struct InputSpec; +struct InputSpan; /// @class InputRecord /// @brief The input API of the Data Processing Layer @@ -99,7 +99,7 @@ class InputRecord using DataHeader = o2::header::DataHeader; InputRecord(std::vector<InputRoute> const& inputs, - InputSpan&& span); + InputSpan& span); /// A deleter type to be used with unique_ptr, which can be marked that /// it does not own the underlying resource and thus should not delete it. @@ -177,30 +177,12 @@ class InputRecord int getPos(const char* name) const; int getPos(const std::string& name) const; - DataRef getByPos(int pos, int part = 0) const - { - if (pos >= mSpan.size() || pos < 0) { - throw runtime_error_f("Unknown message requested at position %d", pos); - } - if (part > 0 && part >= getNofParts(pos)) { - throw runtime_error_f("Invalid message part index at %d:%d", pos, part); - } - if (pos >= mInputsSchema.size()) { - throw runtime_error_f("Unknown schema at position %d", pos); - } - auto ref = mSpan.get(pos, part); - ref.spec = &mInputsSchema[pos].matcher; - return ref; - } + DataRef getByPos(int pos, int part = 0) const; - size_t getNofParts(int pos) const - { - if (pos < 0 || pos >= mSpan.size()) { - return 0; - } - return mSpan.getNofParts(pos); - } + /// Get the ref of the first valid input. If requested, throw an error if none is found. + DataRef getFirstValid(bool throwOnFailure = false) const; + size_t getNofParts(int pos) const; /// Get the object of specified type T for the binding R. /// If R is a string like object, we look up by name the InputSpec and /// return the data associated to the given label. @@ -216,13 +198,14 @@ class InputRecord decltype(auto) get(R binding, int part = 0) const { DataRef ref{nullptr, nullptr}; + using decayed = std::decay_t<R>; // Get the actual dataref - if constexpr (std::is_same_v<std::decay_t<R>, char const*> || - std::is_same_v<std::decay_t<R>, char*> || - std::is_same_v<std::decay_t<R>, std::string>) { + if constexpr (std::is_same_v<decayed, char const*> || + std::is_same_v<decayed, char*> || + std::is_same_v<decayed, std::string>) { try { int pos = -1; - if constexpr (std::is_same_v<std::decay_t<R>, std::string>) { + if constexpr (std::is_same_v<decayed, std::string>) { pos = getPos(binding.c_str()); } else { pos = getPos(binding); @@ -232,13 +215,13 @@ class InputRecord } ref = this->getByPos(pos, part); } catch (const std::exception& e) { - if constexpr (std::is_same_v<std::decay_t<R>, std::string>) { + if constexpr (std::is_same_v<decayed, std::string>) { throw runtime_error_f("Unknown argument requested %s - %s", binding.c_str(), e.what()); } else { throw runtime_error_f("Unknown argument requested %s - %s", binding, e.what()); } } - } else if constexpr (std::is_same_v<std::decay_t<R>, DataRef>) { + } else if constexpr (std::is_same_v<decayed, DataRef>) { ref = binding; } else { static_assert(always_static_assert_v<R>, "Unknown binding type"); @@ -251,7 +234,7 @@ class InputRecord // the buffer to be deleted when it goes out of scope. The string is built // from the data and its lengh, null-termination is not necessary. // return std::string object - auto header = header::get<const header::DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); assert(header); return std::string(ref.payload, header->payloadSize); @@ -270,7 +253,7 @@ class InputRecord // substitution for TableConsumer // For the moment this is dummy, as it requires proper support to // create the RDataSource from the arrow buffer. - auto header = header::get<const header::DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); assert(header); auto data = reinterpret_cast<uint8_t const*>(ref.payload); return std::make_unique<TableConsumer>(data, header->payloadSize); @@ -281,7 +264,7 @@ class InputRecord // We have to deserialize the ostringstream. // FIXME: check that the string is null terminated. // @return deserialized copy of payload - auto header = header::get<const header::DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); assert(header); auto str = std::string(ref.payload, header->payloadSize); assert(header->payloadSize == sizeof(T)); @@ -296,7 +279,7 @@ class InputRecord // substitution for span of messageable objects // FIXME: there will be std::span in C++20 static_assert(is_messageable<typename T::value_type>::value, "span can only be created for messageable types"); - auto header = header::get<const header::DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); assert(header); if (sizeof(typename T::value_type) > 1 && header->payloadSerializationMethod != o2::header::gSerializationMethodNone) { throw runtime_error("Inconsistent serialization method for extracting span"); @@ -314,7 +297,7 @@ class InputRecord } else if constexpr (is_container<T>::value) { // currently implemented only for vectors if constexpr (is_specialization<typename std::remove_const<T>::type, std::vector>::value) { - auto header = o2::header::get<const DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); auto method = header->payloadSerializationMethod; if (method == o2::header::gSerializationMethodNone) { // TODO: construct a vector spectator @@ -357,7 +340,7 @@ class InputRecord // unserialized objects using DataHeader = o2::header::DataHeader; - auto header = o2::header::get<const DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); auto method = header->payloadSerializationMethod; if (method != o2::header::gSerializationMethodNone) { // FIXME: we could in principle support serialized content here as well if we @@ -374,7 +357,7 @@ class InputRecord using DataHeader = o2::header::DataHeader; using ValueT = typename std::remove_pointer<T>::type; - auto header = o2::header::get<const DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); auto method = header->payloadSerializationMethod; if (method == o2::header::gSerializationMethodNone) { if constexpr (is_messageable<ValueT>::value) { @@ -403,6 +386,9 @@ class InputRecord // return type with owning Deleter instance, forwarding to default_deleter std::unique_ptr<ValueT const, Deleter<ValueT const>> result(DataRefUtils::as<ROOTSerialized<ValueT>>(ref).release()); return result; + } else if (method == o2::header::gSerializationMethodCCDB) { + std::unique_ptr<ValueT const, Deleter<ValueT const>> result(DataRefUtils::as<CCDBSerialized<ValueT>>(ref).release()); + return result; } else { throw runtime_error("Attempt to extract object from message with unsupported serialization type"); } @@ -416,7 +402,7 @@ class InputRecord // the operation depends on the transmitted serialization method using DataHeader = o2::header::DataHeader; - auto header = o2::header::get<const DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); auto method = header->payloadSerializationMethod; if (method == o2::header::gSerializationMethodNone) { // this code path is only selected if the type is non-messageable @@ -439,7 +425,7 @@ class InputRecord T get_boost(char const* binding) const { DataRef ref = get<DataRef>(binding); - auto header = header::get<const header::DataHeader*>(ref.header); + auto header = DataRefUtils::getHeader<header::DataHeader*>(ref); assert(header); auto str = std::string(ref.payload, header->payloadSize); auto desData = o2::utils::BoostDeserialize<T>(str); @@ -459,10 +445,7 @@ class InputRecord /// @return the total number of inputs in the InputRecord. Notice that these will include /// both valid and invalid inputs (i.e. inputs which have not arrived yet), depending /// on the CompletionPolicy you have (using the default policy all inputs will be valid). - size_t size() const - { - return mSpan.size(); - } + size_t size() const; /// @return the total number of valid inputs in the InputRecord. /// Invalid inputs might happen if the CompletionPolicy allows @@ -650,7 +633,7 @@ class InputRecord private: std::vector<InputRoute> const& mInputsSchema; - InputSpan mSpan; + InputSpan& mSpan; }; } // namespace framework diff --git a/Framework/Core/include/Framework/InputRecordWalker.h b/Framework/Core/include/Framework/InputRecordWalker.h index 995e4b76bdf7d..3bb8a65ddffe9 100644 --- a/Framework/Core/include/Framework/InputRecordWalker.h +++ b/Framework/Core/include/Framework/InputRecordWalker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/InputRoute.h b/Framework/Core/include/Framework/InputRoute.h index d748a672a2182..781ae2bf8e319 100644 --- a/Framework/Core/include/Framework/InputRoute.h +++ b/Framework/Core/include/Framework/InputRoute.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/InputSpan.h b/Framework/Core/include/Framework/InputSpan.h index 661e5bfe3eba3..dffd89ca3ff5d 100644 --- a/Framework/Core/include/Framework/InputSpan.h +++ b/Framework/Core/include/Framework/InputSpan.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,9 +14,10 @@ #include "Framework/DataRef.h" #include <functional> -namespace o2 -{ -namespace framework +extern template class std::function<o2::framework::DataRef(size_t)>; +extern template class std::function<o2::framework::DataRef(size_t, size_t)>; + +namespace o2::framework { /// Mapping helper between the store of all inputs being processed and the @@ -33,30 +35,18 @@ class InputSpan /// @a getter is the mapping between an element of the span referred by /// index and the buffer associated. /// @a size is the number of elements in the span. - InputSpan(std::function<DataRef(size_t)> getter, size_t size) - : mGetter{}, mNofPartsGetter{}, mSize{size} - { - mGetter = [getter](size_t index, size_t) -> DataRef { - return getter(index); - }; - } + InputSpan(std::function<DataRef(size_t)> getter, size_t size); /// @a getter is the mapping between an element of the span referred by /// index and the buffer associated. /// @a size is the number of elements in the span. - InputSpan(std::function<DataRef(size_t, size_t)> getter, size_t size) - : mGetter{getter}, mNofPartsGetter{}, mSize{size} - { - } + InputSpan(std::function<DataRef(size_t, size_t)> getter, size_t size); /// @a getter is the mapping between an element of the span referred by /// index and the buffer associated. /// @nofPartsGetter is the getter for the number of parts associated with an index /// @a size is the number of elements in the span. - InputSpan(std::function<DataRef(size_t, size_t)> getter, std::function<size_t(size_t)> nofPartsGetter, size_t size) - : mGetter{getter}, mNofPartsGetter{nofPartsGetter}, mSize{size} - { - } + InputSpan(std::function<DataRef(size_t, size_t)> getter, std::function<size_t(size_t)> nofPartsGetter, size_t size); /// @a i-th element of the InputSpan DataRef get(size_t i, size_t partidx = 0) const @@ -250,7 +240,6 @@ class InputSpan size_t mSize; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // FRAMEWORK_INPUTSSPAN_H diff --git a/Framework/Core/include/Framework/InputSpec.h b/Framework/Core/include/Framework/InputSpec.h index d9e3f3201d66d..d8a84249d3b47 100644 --- a/Framework/Core/include/Framework/InputSpec.h +++ b/Framework/Core/include/Framework/InputSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,9 @@ #include <string> #include <ostream> +#if !defined(__CLING__) && !defined(__ROOTCLING__) #include <variant> +#endif namespace o2::framework { @@ -49,6 +52,11 @@ struct InputSpec { ConcreteDataTypeMatcher const& dataType, enum Lifetime lifetime_ = Lifetime::Timeframe, std::vector<ConfigParamSpec> const& metadata_ = {}); + /// Create an InputSpec which does not check for the description and the subSpec. + InputSpec(std::string binding_, + header::DataOrigin const& dataType, + enum Lifetime lifetime_ = Lifetime::Timeframe, + std::vector<ConfigParamSpec> const& metadata_ = {}); InputSpec(std::string binding, data_matcher::DataDescriptorMatcher&& matcher, std::vector<ConfigParamSpec> const& metadata_ = {}); @@ -57,7 +65,9 @@ struct InputSpec { std::string binding; /// The actual matcher for the input spec. +#if !defined(__CLING__) && !defined(__ROOTCLING__) std::variant<ConcreteDataMatcher, data_matcher::DataDescriptorMatcher> matcher; +#endif enum Lifetime lifetime; diff --git a/Framework/Core/include/Framework/Kernels.h b/Framework/Core/include/Framework/Kernels.h index 75dc919c9fd75..36fc125a4a45d 100644 --- a/Framework/Core/include/Framework/Kernels.h +++ b/Framework/Core/include/Framework/Kernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include <arrow/status.h> #include <arrow/util/visibility.h> #include <arrow/util/variant.h> +#include <arrow/util/config.h> #include <string> @@ -29,14 +31,18 @@ namespace o2::framework /// @a offset the offset in the original table at which the corresponding /// slice was split. template <typename T> -auto sliceByColumn(char const* key, - std::shared_ptr<arrow::Table> const& input, - T fullSize, - std::vector<arrow::Datum>* slices, - std::vector<uint64_t>* offsets = nullptr) +auto sliceByColumn( + char const* key, + std::shared_ptr<arrow::Table> const& input, + T fullSize, + std::vector<arrow::Datum>* slices, + std::vector<uint64_t>* offsets = nullptr, + std::vector<int>* sizes = nullptr, + std::vector<arrow::Datum>* unassignedSlices = nullptr, + std::vector<uint64_t>* unassignedOffsets = nullptr) { arrow::Datum value_counts; - auto options = arrow::compute::CountOptions::Defaults(); + auto options = arrow::compute::ScalarAggregateOptions::Defaults(); ARROW_ASSIGN_OR_RAISE(value_counts, arrow::compute::CallFunction("value_counts", {input->GetColumnByName(key)}, &options)); @@ -45,47 +51,60 @@ auto sliceByColumn(char const* key, auto counts = static_cast<arrow::NumericArray<arrow::Int64Type>>(pair.field(1)->data()); // create slices and offsets - auto offset = 0; + uint64_t offset = 0; auto count = 0; - auto size = values.length(); - auto makeSlice = [&](T count) { - slices->emplace_back(arrow::Datum{input->Slice(offset, count)}); + auto makeSlice = [&](uint64_t offset_, T count_) { + slices->emplace_back(arrow::Datum{input->Slice(offset_, count_)}); if (offsets) { - offsets->emplace_back(offset); + offsets->emplace_back(offset_); + } + if (sizes) { + sizes->emplace_back(count_); } }; - auto current = 0; - auto v = values.Value(0); - while (v - current >= 1) { - makeSlice(0); - ++current; - } + auto makeUnassignedSlice = [&](uint64_t offset_, T count_) { + if (unassignedSlices) { + unassignedSlices->emplace_back(arrow::Datum{input->Slice(offset_, count_)}); + } + if (unassignedOffsets) { + unassignedOffsets->emplace_back(offset_); + } + }; - for (auto r = 0; r < size - 1; ++r) { - count = counts.Value(r); - makeSlice(count); - offset += count; - auto nextValue = values.Value(r + 1); - auto value = values.Value(r); - while (nextValue - value > 1) { - makeSlice(0); - ++value; + auto v = 0; + auto vprev = v; + auto nzeros = 0; + + for (auto i = 0; i < size; ++i) { + count = counts.Value(i); + if (v >= 0) { + vprev = v; + } + v = values.Value(i); + if (v < 0) { + makeUnassignedSlice(offset, count); + offset += count; + continue; } + nzeros = v - vprev - ((i == 0 || slices->empty() == true) ? 0 : 1); + for (auto z = 0; z < nzeros; ++z) { + makeSlice(offset, 0); + } + makeSlice(offset, count); + offset += count; } - makeSlice(counts.Value(size - 1)); if (values.Value(size - 1) < fullSize - 1) { for (auto v = values.Value(size - 1) + 1; v < fullSize; ++v) { - makeSlice(0); + makeSlice(offset, 0); } } return arrow::Status::OK(); } - } // namespace o2::framework #endif // O2_FRAMEWORK_KERNELS_H_ diff --git a/Framework/Core/include/Framework/Lifetime.h b/Framework/Core/include/Framework/Lifetime.h index 6bad4de842d5e..b139254223652 100644 --- a/Framework/Core/include/Framework/Lifetime.h +++ b/Framework/Core/include/Framework/Lifetime.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,15 +15,28 @@ namespace o2::framework { /// Possible Lifetime of objects being exchanged by the DPL. -/// FIXME: currently only Timeframe behaves as expected. enum struct Lifetime { + /// A message which is associated to a timeframe. DPL will wait indefinitely for it by default. Timeframe, + /// Eventually a message whose content is retrieved from CCDB Condition, + /// Do not use for now QA, + /// Do not use for now. Transient, + /// A message which is created whenever a Timer expires Timer, + /// A message which is created immediately, with payload / containing a + /// single value which gets incremented for every / invokation. Enumeration, - Signal + /// A message which is created every time a SIGUSR1 is received. + Signal, + /// An optional message. When data arrives, if not already part of the data, + /// a dummy entry will be generated. + /// This comes handy e.g. to handle Raw Data, since DataDistribution will provide + /// everything in one go so whatever is expected but not there, for whatever reason + /// will be substituted with a dummy entry. + Optional }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/LifetimeHelpers.h b/Framework/Core/include/Framework/LifetimeHelpers.h index 2c358af5a095b..ae2a30c9b6b73 100644 --- a/Framework/Core/include/Framework/LifetimeHelpers.h +++ b/Framework/Core/include/Framework/LifetimeHelpers.h @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_LIFETIMEHELPERS_H -#define FRAMEWORK_LIFETIMEHELPERS_H +#ifndef O2_FRAMEWORK_LIFETIMEHELPERS_H_ +#define O2_FRAMEWORK_LIFETIMEHELPERS_H_ #include "Framework/ExpirationHandler.h" #include "Framework/PartRef.h" @@ -17,9 +18,7 @@ #include <functional> #include <string> -namespace o2 -{ -namespace framework +namespace o2::framework { struct ConcreteDataMatcher; @@ -33,6 +32,7 @@ struct LifetimeHelpers { /// Callback which creates a new timeslice as soon as one is available and /// uses an incremental number as timestamp. static ExpirationHandler::Creator enumDrivenCreation(size_t first, size_t last, size_t step, size_t inputTimeslice, size_t maxTimeSliceId); + /// Callback which creates a new timeslice when timer /// expires and there is not a compatible datadriven callback /// available. @@ -52,11 +52,14 @@ struct LifetimeHelpers { /// expires via this mechanism). static ExpirationHandler::Handler doNothing(); + /// Fetches CTP if not requested via @a waitForCTP and not available + /// Sets DataTakingContext::orbitResetTime accordingly + static ExpirationHandler::Checker expectCTP(std::string const& serverUrl, bool waitForCTP); /// Build a fetcher for an object from CCDB when the record is expired. - /// @a prefix is the lookup prefix in CCDB. + /// @a spec is the associated InputSpec + /// @a prefix is the lookup prefix in CCDB /// @a overrideTimestamp can be used to override the timestamp found in the data. - /// FIXME: provide a way to customize the namespace from the ProcessingContext - static ExpirationHandler::Handler fetchFromCCDBCache(ConcreteDataMatcher const& matcher, + static ExpirationHandler::Handler fetchFromCCDBCache(InputSpec const& spec, std::string const& prefix, std::string const& overrideTimestamp, std::string const& sourceChannel); @@ -77,10 +80,14 @@ struct LifetimeHelpers { /// dataOrigin, dataDescrition and dataSpecification of the given @a route. /// The payload of each message will contain an incremental number for each /// message being created. - static ExpirationHandler::Handler enumerate(ConcreteDataMatcher const& spec, std::string const& sourceChannel); + static ExpirationHandler::Handler enumerate(ConcreteDataMatcher const& spec, std::string const& sourceChannel, + int64_t orbitOffset, int64_t orbitMultiplier); + + /// Create a dummy (empty) message every time a record expires, suing @a spec + /// as content of the payload. + static ExpirationHandler::Handler dummy(ConcreteDataMatcher const& spec, std::string const& sourceChannel); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif // FRAMEWORK_LIFETIMEHELPERS_H +#endif // O2_FRAMEWORK_LIFETIMEHELPERS_H_ diff --git a/Framework/Core/include/Framework/LocalRootFileService.h b/Framework/Core/include/Framework/LocalRootFileService.h index 713edba089665..de6ee9be192ab 100644 --- a/Framework/Core/include/Framework/LocalRootFileService.h +++ b/Framework/Core/include/Framework/LocalRootFileService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/LogParsingHelpers.h b/Framework/Core/include/Framework/LogParsingHelpers.h index d9218a244f1c7..9799f0e9160e5 100644 --- a/Framework/Core/include/Framework/LogParsingHelpers.h +++ b/Framework/Core/include/Framework/LogParsingHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,6 +27,7 @@ struct LogParsingHelpers { Info, Warning, Error, + Fatal, Unknown, Size }; diff --git a/Framework/Core/include/Framework/MessageContext.h b/Framework/Core/include/Framework/MessageContext.h index fca8d7069ea32..f16aea6b1ed97 100644 --- a/Framework/Core/include/Framework/MessageContext.h +++ b/Framework/Core/include/Framework/MessageContext.h @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_MESSAGECONTEXT_H -#define FRAMEWORK_MESSAGECONTEXT_H +#ifndef O2_FRAMEWORK_MESSAGECONTEXT_H_ +#define O2_FRAMEWORK_MESSAGECONTEXT_H_ #include "Framework/DispatchControl.h" #include "Framework/FairMQDeviceProxy.h" @@ -29,12 +30,11 @@ #include <unordered_map> #include <vector> -class FairMQDevice; +#include <fairmq/FwdDecls.h> -namespace o2 -{ -namespace framework +namespace o2::framework { + class Output; class MessageContext @@ -217,7 +217,7 @@ class MessageContext using value_type = typename T::value_type; using return_type = T; using buffer_type = return_type; - static_assert(std::is_same<typename T::allocator_type, o2::pmr::polymorphic_allocator<value_type>>::value, "container must have polymorphic allocator"); + static_assert(std::is_base_of<o2::pmr::polymorphic_allocator<value_type>, typename T::allocator_type>::value, "container must have polymorphic allocator"); /// default contructor forbidden, object always has to control message instances ContainerRefObject() = delete; /// constructor taking header message by move and creating the paypload message @@ -471,7 +471,7 @@ class MessageContext if (mDispatchControl.trigger == nullptr || mDispatchControl.trigger(*header)) { std::unordered_map<std::string const*, FairMQParts> outputs; for (auto& message : mScheduledMessages) { - FairMQParts parts = std::move(message->finalize()); + FairMQParts parts = message->finalize(); assert(message->empty()); assert(parts.Size() == 2); for (auto& part : parts) { @@ -550,6 +550,5 @@ class MessageContext DispatchControl mDispatchControl; std::unordered_map<std::string, std::unique_ptr<std::string>> mChannelRefs; }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_MESSAGECONTEXT_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_MESSAGECONTEXT_H_ diff --git a/Framework/Core/include/Framework/MessageSet.h b/Framework/Core/include/Framework/MessageSet.h index 2a9f805a2b446..e651c7d5960ff 100644 --- a/Framework/Core/include/Framework/MessageSet.h +++ b/Framework/Core/include/Framework/MessageSet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/Metric2DViewIndex.h b/Framework/Core/include/Framework/Metric2DViewIndex.h index 524df539cb6cb..f7cea4aa7393b 100644 --- a/Framework/Core/include/Framework/Metric2DViewIndex.h +++ b/Framework/Core/include/Framework/Metric2DViewIndex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/Monitoring.h b/Framework/Core/include/Framework/Monitoring.h index 26d4c1c38c34a..e52cda653d789 100644 --- a/Framework/Core/include/Framework/Monitoring.h +++ b/Framework/Core/include/Framework/Monitoring.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #define O2_FRAMEWORK_MONITORING_H_ #include "Framework/ServiceHandle.h" +#include "Framework/ServiceRegistry.h" #include <Monitoring/Monitoring.h> diff --git a/Framework/Core/include/Framework/NoDebugGUI.h b/Framework/Core/include/Framework/NoDebugGUI.h deleted file mode 100644 index 2b0c373068c97..0000000000000 --- a/Framework/Core/include/Framework/NoDebugGUI.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef FRAMEWORK_NODEBUGGUI_H -#define FRAMEWORK_NODEBUGGUI_H - -#include <functional> - -namespace o2 -{ -namespace framework -{ - -// The DebugGUI has been moved to a separate package, this is a dummy header file -// included when the DebugGUI package is not found or disabled. -static inline void* initGUI(const char* name) -{ - return nullptr; -} - -static inline bool pollGUI(void* context, std::function<void(void)> guiCallback) -{ - // returns whether quit is requested, we return 'no' - return false; -} -static inline void disposeGUI() -{ -} - -} // namespace framework -} // namespace o2 - -#endif // FRAMEWORK_NODEBUGGUI_H diff --git a/Framework/Core/include/Framework/O2ControlLabels.h b/Framework/Core/include/Framework/O2ControlLabels.h new file mode 100644 index 0000000000000..eb05f156cf58d --- /dev/null +++ b/Framework/Core/include/Framework/O2ControlLabels.h @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_O2CONTROLLABELS_H +#define O2_FRAMEWORK_O2CONTROLLABELS_H + +#include "Framework/DataProcessorLabel.h" + +namespace o2::framework +{ + +/// DataProcessorLabels which are recognized by the --o2-control dump tool +/// and influence its output. +namespace ecs +{ + +// This label makes AliECS templates register raw (proxy) channels in the global +// template space without regard for the avoiding the duplicates (i.e. not adding "-{{ it }}"). +// Effectively, it allows us to declare cross-machine channels, e.g. for QC. +const extern DataProcessorLabel uniqueProxyLabel; + +// This label makes AliECS templates use the originally declared addresses for raw FairMQ channels. +// Thus, AliECS will not perform host and port allocation automatically. It takes priority over `uniqueProxyLabel`. +const extern DataProcessorLabel preserveRawChannelsLabel; + +} // namespace ecs +} // namespace o2::framework + +#endif //O2_FRAMEWORK_O2CONTROLLABELS_H diff --git a/Framework/Core/include/Framework/Output.h b/Framework/Core/include/Framework/Output.h index 0ab5ef0df96db..0737d87b9b754 100644 --- a/Framework/Core/include/Framework/Output.h +++ b/Framework/Core/include/Framework/Output.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/OutputObjHeader.h b/Framework/Core/include/Framework/OutputObjHeader.h index ba539382db286..6fb46dff47f35 100644 --- a/Framework/Core/include/Framework/OutputObjHeader.h +++ b/Framework/Core/include/Framework/OutputObjHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,6 +27,12 @@ enum OutputObjHandlingPolicy : unsigned int { numPolicies }; +enum OutputObjSourceType : unsigned int { + OutputObjSource, + HistogramRegistrySource, + numTypes +}; + /// @struct OutputObjHeader /// @brief O2 header for OutputObj metadata struct OutputObjHeader : public BaseHeader { @@ -33,15 +40,18 @@ struct OutputObjHeader : public BaseHeader { constexpr static const o2::header::HeaderType sHeaderType = "OutObjMD"; constexpr static const o2::header::SerializationMethod sSerializationMethod = o2::header::gSerializationMethodNone; OutputObjHandlingPolicy mPolicy; + OutputObjSourceType mSourceType; uint32_t mTaskHash; constexpr OutputObjHeader() : BaseHeader(sizeof(OutputObjHeader), sHeaderType, sSerializationMethod, sVersion), mPolicy{OutputObjHandlingPolicy::AnalysisObject}, + mSourceType{OutputObjSourceType::OutputObjSource}, mTaskHash{0} {} - constexpr OutputObjHeader(OutputObjHandlingPolicy policy, uint32_t hash) + constexpr OutputObjHeader(OutputObjHandlingPolicy policy, OutputObjSourceType sourceType, uint32_t hash) : BaseHeader(sizeof(OutputObjHeader), sHeaderType, sSerializationMethod, sVersion), mPolicy{policy}, + mSourceType{sourceType}, mTaskHash{hash} {} constexpr OutputObjHeader(OutputObjHeader const&) = default; }; diff --git a/Framework/Core/include/Framework/OutputRef.h b/Framework/Core/include/Framework/OutputRef.h index 22d829aee1d30..6713d85c45433 100644 --- a/Framework/Core/include/Framework/OutputRef.h +++ b/Framework/Core/include/Framework/OutputRef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/OutputRoute.h b/Framework/Core/include/Framework/OutputRoute.h index c88e2e6f5947d..99702aa507a2b 100644 --- a/Framework/Core/include/Framework/OutputRoute.h +++ b/Framework/Core/include/Framework/OutputRoute.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/OutputSpec.h b/Framework/Core/include/Framework/OutputSpec.h index 8bb008774661e..7a0a0c55d8124 100644 --- a/Framework/Core/include/Framework/OutputSpec.h +++ b/Framework/Core/include/Framework/OutputSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,9 @@ #include "Framework/Lifetime.h" #include "Framework/ConcreteDataMatcher.h" +#if !defined(__CLING__) && !defined(__ROOTCLING__) #include <variant> +#endif namespace o2::framework { @@ -28,7 +31,9 @@ struct OutputLabel { /// topology. struct OutputSpec { OutputLabel binding; +#if !defined(__CLING__) && !defined(__ROOTCLING__) std::variant<ConcreteDataMatcher, ConcreteDataTypeMatcher> matcher; +#endif enum Lifetime lifetime = Lifetime::Timeframe; /// Build a fully qualified tuple for the OutputSpec diff --git a/Framework/Core/include/Framework/PaletteHelpers.h b/Framework/Core/include/Framework/PaletteHelpers.h deleted file mode 100644 index 11881c79e1d63..0000000000000 --- a/Framework/Core/include/Framework/PaletteHelpers.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef FRAMEWORK_PALETTE_HELPER_H -#define FRAMEWORK_PALETTE_HELPER_H - -#include "DebugGUI/imgui.h" - -namespace o2 -{ -namespace framework -{ - -/// An helper class for colors and palettes -struct PaletteHelpers { - static const ImVec4 RED; - static const ImVec4 GREEN; - static const ImVec4 BLUE; - static const ImVec4 YELLOW; - static const ImVec4 SHADED_RED; - static const ImVec4 SHADED_GREEN; - static const ImVec4 SHADED_BLUE; - static const ImVec4 SHADED_YELLOW; - static const ImVec4 DARK_RED; - static const ImVec4 DARK_GREEN; - static const ImVec4 DARK_YELLOW; - static const ImVec4 WHITE; - static const ImVec4 BLACK; - static const ImVec4 GRAY; - static const ImVec4 LIGHT_GRAY; -}; - -} // namespace framework -} // namespace o2 - -#endif diff --git a/Framework/Core/include/Framework/ParallelContext.h b/Framework/Core/include/Framework/ParallelContext.h index 79c0de7d70a4f..dae2a5bccfcbd 100644 --- a/Framework/Core/include/Framework/ParallelContext.h +++ b/Framework/Core/include/Framework/ParallelContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ParamRetriever.h b/Framework/Core/include/Framework/ParamRetriever.h index 34c6ad53a30ab..a1a185f668b1f 100644 --- a/Framework/Core/include/Framework/ParamRetriever.h +++ b/Framework/Core/include/Framework/ParamRetriever.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/PartRef.h b/Framework/Core/include/Framework/PartRef.h index 092ea573da0be..6fda1962b1e92 100644 --- a/Framework/Core/include/Framework/PartRef.h +++ b/Framework/Core/include/Framework/PartRef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #include <memory> -class FairMQMessage; +#include <fairmq/FwdDecls.h> namespace o2 { diff --git a/Framework/Core/include/Framework/Plugins.h b/Framework/Core/include/Framework/Plugins.h new file mode 100644 index 0000000000000..448ee4626d204 --- /dev/null +++ b/Framework/Core/include/Framework/Plugins.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_PLUGINS_H_ +#define O2_FRAMEWORK_PLUGINS_H_ + +#include "Framework/AlgorithmSpec.h" +#include <cstring> +#include <string> +#include <functional> +#include <uv.h> + +namespace o2::framework +{ + +enum struct DplPluginKind : int { + // A plugin which can customise the workflow. Needs to return + // an object of kind o2::framework::WorkflowCustomizationService + CustomAlgorithm, + // A plugin which implements a ImGUI GUI. Needs to return an + // object of the kind o2::framework::DebugGUIImpl + DebugGUIImpl, + // A plugin which implements a custom Services. Needs to return + // an object of the kind o2::framework::ServiceSpec + CustomService +}; + +} // namespace o2::framework + +/// An handle for a generic DPL plugin. +/// The handle is returned by the dpl_plugin_callback() +struct DPLPluginHandle { + void* instance; + char const* name; + enum o2::framework::DplPluginKind kind; + DPLPluginHandle* previous; +}; + +// Struct to hold live plugin information which the plugin itself cannot +// know and that is owned by the framework. +struct PluginInfo { + uv_lib_t* dso = nullptr; + std::string name; + DPLPluginHandle* instance = nullptr; +}; + +#define DEFINE_DPL_PLUGIN(NAME, KIND) \ + extern "C" { \ + DPLPluginHandle* dpl_plugin_callback(DPLPluginHandle* previous) \ + { \ + return new DPLPluginHandle{new NAME{}, strdup(#NAME), o2::framework::DplPluginKind::KIND, previous}; \ + } \ + } + +#define DEFINE_DPL_PLUGINS_BEGIN \ + extern "C" { \ + DPLPluginHandle* dpl_plugin_callback(DPLPluginHandle* previous) \ + { + +#define DEFINE_DPL_PLUGIN_INSTANCE(NAME, KIND) \ + previous = new DPLPluginHandle{new NAME{}, strdup(#NAME), o2::framework::DplPluginKind::KIND, previous}; + +#define DEFINE_DPL_PLUGINS_END \ + return previous; \ + } \ + } + +namespace o2::framework +{ +struct PluginManager { + template <typename T> + static T* getByName(DPLPluginHandle* handle, char const* name) + { + while (handle != nullptr) { + if (strncmp(handle->name, name, strlen(name)) == 0) { + return reinterpret_cast<T*>(handle->instance); + } + handle = handle->previous; + } + return nullptr; + } + /// Load a DSO called @a dso and insert its handle in @a infos + /// On successfull completion @a onSuccess is called passing + /// the DPLPluginHandle provided by the library. + static void load(std::vector<PluginInfo>& infos, const char* dso, std::function<void(DPLPluginHandle*)>& onSuccess); +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_PLUGINS_H_ diff --git a/Framework/Core/include/Framework/ProcessingContext.h b/Framework/Core/include/Framework/ProcessingContext.h index 264b0679019f8..a904134e8b422 100644 --- a/Framework/Core/include/Framework/ProcessingContext.h +++ b/Framework/Core/include/Framework/ProcessingContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RCombinedDS.h b/Framework/Core/include/Framework/RCombinedDS.h index 3a6724d3122c9..6da222418ef3e 100644 --- a/Framework/Core/include/Framework/RCombinedDS.h +++ b/Framework/Core/include/Framework/RCombinedDS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RawBufferContext.h b/Framework/Core/include/Framework/RawBufferContext.h index d7590ca3b10fe..e6bcb2e936ecb 100644 --- a/Framework/Core/include/Framework/RawBufferContext.h +++ b/Framework/Core/include/Framework/RawBufferContext.h @@ -1,34 +1,26 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file RawBufferContext.h -/// \brief ********** -/// \author Gabriele G. Fronzé <gfronze at cern.ch> -/// \date 31/07/2018 - -#ifndef FRAMEWORK_RAWBUFFERCONTEXT_H -#define FRAMEWORK_RAWBUFFERCONTEXT_H +#ifndef O2_FRAMEWORK_RAWBUFFERCONTEXT_H_ +#define O2_FRAMEWORK_RAWBUFFERCONTEXT_H_ #include "Framework/FairMQDeviceProxy.h" #include "CommonUtils/BoostSerializer.h" #include <vector> -#include <cassert> #include <string> #include <memory> -#include "boost/any.hpp" -class FairMQMessage; +#include <fairmq/FwdDecls.h> -namespace o2 -{ -namespace framework +namespace o2::framework { /// A context which holds bytes streams being passed around @@ -40,10 +32,7 @@ class RawBufferContext : mProxy{proxy} { } - RawBufferContext(RawBufferContext&& other) - : mProxy{other.mProxy}, mMessages{std::move(other.mMessages)} - { - } + RawBufferContext(RawBufferContext&& other); struct MessageRef { std::unique_ptr<FairMQMessage> header; @@ -59,10 +48,7 @@ class RawBufferContext char* payload, std::string channel, std::function<std::ostringstream()> serialize, - std::function<void()> destructor) - { - mMessages.push_back(std::move(MessageRef{std::move(header), std::move(payload), std::move(channel), std::move(serialize), std::move(destructor)})); - } + std::function<void()> destructor); Messages::iterator begin() { @@ -79,22 +65,7 @@ class RawBufferContext return mMessages.size(); } - void clear() - { - // On send we move the header, but the payload remains - // there because what's really sent is the copy of the raw - // payload will be cleared by the mMessages.clear() - for (auto& m : mMessages) { - assert(m.header == nullptr); - // NOTE: payloads can be empty so m.payload == nullptr should - // be an actual issue. - assert(m.payload != nullptr); - m.destroyPayload(); - m.payload = nullptr; - } - - mMessages.clear(); - } + void clear(); FairMQDeviceProxy& proxy() { @@ -106,7 +77,6 @@ class RawBufferContext Messages mMessages; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif //FRAMEWORK_RAWBUFFERCONTEXT_H +#endif // O2_FRAMEWORK_RAWBUFFERCONTEXT_H_ diff --git a/Framework/Core/include/Framework/RawDeviceService.h b/Framework/Core/include/Framework/RawDeviceService.h index 700df3c9b62a4..f5ccc2e574fa7 100644 --- a/Framework/Core/include/Framework/RawDeviceService.h +++ b/Framework/Core/include/Framework/RawDeviceService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,7 @@ #include "Framework/ServiceHandle.h" -class FairMQDevice; +#include <fairmq/FwdDecls.h> namespace o2::framework { diff --git a/Framework/Core/include/Framework/ReadoutAdapter.h b/Framework/Core/include/Framework/ReadoutAdapter.h index f46252b045e61..873ba9cf807d2 100644 --- a/Framework/Core/include/Framework/ReadoutAdapter.h +++ b/Framework/Core/include/Framework/ReadoutAdapter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ResourcePolicy.h b/Framework/Core/include/Framework/ResourcePolicy.h new file mode 100644 index 0000000000000..eb8d77b209a8f --- /dev/null +++ b/Framework/Core/include/Framework/ResourcePolicy.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_RESOURCEPOLICY_H_ +#define O2_FRAMEWORK_RESOURCEPOLICY_H_ + +#include "Framework/ComputingQuotaOffer.h" +#include <functional> +#include <string> + +namespace o2::framework +{ +struct DeviceSpec; + +/// A policy which specify how a device matched by +/// @a matcher should react to a given offer by specifying +/// a given @a request. +struct ResourcePolicy { + using Matcher = std::function<bool(DeviceSpec const& device)>; + + static std::vector<ResourcePolicy> createDefaultPolicies(); + + std::string name; + Matcher matcher; + ComputingQuotaRequest request; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_RESOURCEPOLICY_H_ diff --git a/Framework/Core/include/Framework/ResourcePolicyHelpers.h b/Framework/Core/include/Framework/ResourcePolicyHelpers.h new file mode 100644 index 0000000000000..abee264d75104 --- /dev/null +++ b/Framework/Core/include/Framework/ResourcePolicyHelpers.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_RESOURCEPOLICYHELPERS_H_ +#define O2_FRAMEWORK_RESOURCEPOLICYHELPERS_H_ + +#include "Framework/ResourcePolicy.h" +#include <functional> +#include <string> + +namespace o2::framework +{ + +struct ResourcePolicyHelpers { + static ResourcePolicy trivialTask(char const* taskMatcher); + static ResourcePolicy cpuBoundTask(char const* taskMatcher, int maxCPUs = 1); + static ResourcePolicy sharedMemoryBoundTask(char const* taskMatcher, int maxMemory); +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_RESOURCEPOLICYHELPERS_H_ diff --git a/Framework/Core/include/Framework/RootAnalysisHelpers.h b/Framework/Core/include/Framework/RootAnalysisHelpers.h index 7341d330b736f..a3d09b515401a 100644 --- a/Framework/Core/include/Framework/RootAnalysisHelpers.h +++ b/Framework/Core/include/Framework/RootAnalysisHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RootConfigParamHelpers.h b/Framework/Core/include/Framework/RootConfigParamHelpers.h index 31e1c35712f37..b5bc266f0b013 100644 --- a/Framework/Core/include/Framework/RootConfigParamHelpers.h +++ b/Framework/Core/include/Framework/RootConfigParamHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RootFileService.h b/Framework/Core/include/Framework/RootFileService.h index 0c0835c1d6a97..e293628d7015f 100644 --- a/Framework/Core/include/Framework/RootFileService.h +++ b/Framework/Core/include/Framework/RootFileService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RootSerializationSupport.h b/Framework/Core/include/Framework/RootSerializationSupport.h index 605d9652c3e50..cbf7408b13c7d 100644 --- a/Framework/Core/include/Framework/RootSerializationSupport.h +++ b/Framework/Core/include/Framework/RootSerializationSupport.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RootTableBuilderHelpers.h b/Framework/Core/include/Framework/RootTableBuilderHelpers.h index 5ead9d8e69412..72f5ee5c570a1 100644 --- a/Framework/Core/include/Framework/RootTableBuilderHelpers.h +++ b/Framework/Core/include/Framework/RootTableBuilderHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RoutingIndices.h b/Framework/Core/include/Framework/RoutingIndices.h index 30bd478fa9f16..a5834a106b085 100644 --- a/Framework/Core/include/Framework/RoutingIndices.h +++ b/Framework/Core/include/Framework/RoutingIndices.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/RunningWorkflowInfo.h b/Framework/Core/include/Framework/RunningWorkflowInfo.h new file mode 100644 index 0000000000000..c842057042681 --- /dev/null +++ b/Framework/Core/include/Framework/RunningWorkflowInfo.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_RUNNINGWORKFLOWINFO_H_ +#define O2_FRAMEWORK_RUNNINGWORKFLOWINFO_H_ + +#include "Framework/DeviceSpec.h" +#include <vector> + +namespace o2::framework +{ + +struct RunningDeviceRef { + size_t index; // Index in the RunningWorkflowInfo::devices vector; +}; + +/// Information about the running workflow +struct RunningWorkflowInfo { + std::vector<DeviceSpec> devices; +}; + +} // namespace o2::framework +#endif // RunningWorkflowInfo diff --git a/Framework/Core/include/Framework/SerializationMethods.h b/Framework/Core/include/Framework/SerializationMethods.h index 33686443d959f..4d20e8861fad5 100644 --- a/Framework/Core/include/Framework/SerializationMethods.h +++ b/Framework/Core/include/Framework/SerializationMethods.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -99,6 +100,31 @@ class BoostSerialized private: wrapped_type& mRef; }; + +template <typename T, typename HintType = void> +class CCDBSerialized +{ + public: + using non_messageable = o2::framework::MarkAsNonMessageable; + using wrapped_type = T; + using hint_type = HintType; + + static_assert(std::is_pointer<T>::value == false, "wrapped type can not be a pointer"); + static_assert(std::is_pointer<HintType>::value == false, "hint type can not be a pointer"); + + CCDBSerialized() = delete; + CCDBSerialized(wrapped_type& ref, hint_type* hint = nullptr) : mRef(ref), mHint(hint) {} + + T& operator()() { return mRef; } + T const& operator()() const { return mRef; } + + hint_type* getHint() const { return mHint; } + + private: + wrapped_type& mRef; + hint_type* mHint; // optional hint e.g. class info or class name +}; + } // namespace framework } // namespace o2 #endif // FRAMEWORK_SERIALIZATIONMETHODS_H diff --git a/Framework/Core/include/Framework/ServiceHandle.h b/Framework/Core/include/Framework/ServiceHandle.h index 3f3759bd1e9ca..80286b64f2ba1 100644 --- a/Framework/Core/include/Framework/ServiceHandle.h +++ b/Framework/Core/include/Framework/ServiceHandle.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/ServiceRegistry.h b/Framework/Core/include/Framework/ServiceRegistry.h index b9bf54eddacce..559adbf22d2e7 100644 --- a/Framework/Core/include/Framework/ServiceRegistry.h +++ b/Framework/Core/include/Framework/ServiceRegistry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -94,6 +95,13 @@ struct ServiceRegistry { std::vector<ServiceEOSHandle> mPostEOSHandles; /// Callbacks for services to be executed after every dispatching std::vector<ServiceDispatchingHandle> mPostDispatchingHandles; + /// Callbacks for services to be executed before Start + std::vector<ServiceStartHandle> mPreStartHandles; + /// Callbacks for services to be executed on exit + std::vector<ServiceExitHandle> mPreExitHandles; + + /// To hide exception throwing from QC + void throwError(RuntimeErrorRef const& ref) const; public: using hash_type = decltype(TypeIdHelpers::uniqueId<void>()); @@ -101,7 +109,9 @@ struct ServiceRegistry { ServiceRegistry(ServiceRegistry const& other) { - mServicesKey = other.mServicesKey; + for (size_t i = 0; i < MAX_SERVICES; ++i) { + mServicesKey[i].store(other.mServicesKey[i].load()); + } mServicesValue = other.mServicesValue; mServicesMeta = other.mServicesMeta; for (size_t i = 0; i < other.mServicesBooked.size(); ++i) { @@ -111,7 +121,9 @@ struct ServiceRegistry { ServiceRegistry& operator=(ServiceRegistry const& other) { - mServicesKey = other.mServicesKey; + for (size_t i = 0; i < MAX_SERVICES; ++i) { + mServicesKey[i].store(other.mServicesKey[i].load()); + } mServicesValue = other.mServicesValue; mServicesMeta = other.mServicesMeta; for (size_t i = 0; i < other.mServicesBooked.size(); ++i) { @@ -120,6 +132,8 @@ struct ServiceRegistry { return *this; } + /// Invoke callbacks to be executed in PreRun(), before the User Start callbacks + void preStartCallbacks(); /// Invoke callbacks to be executed before every process method invokation void preProcessingCallbacks(ProcessingContext&); /// Invoke callbacks to be executed after every process method invokation @@ -135,6 +149,8 @@ struct ServiceRegistry { /// Invoke callbacks to monitor inputs after dispatching, regardless of them /// being discarded, consumed or processed. void postDispatchingCallbacks(ProcessingContext&); + /// Invoke callbacks on exit. + void preExitCallbacks(); /// Declare a service by its ServiceSpec. If of type Global /// / Serial it will be immediately registered for tid 0, @@ -164,9 +180,8 @@ struct ServiceRegistry { int getPos(uint32_t typeHash, uint64_t threadId) const { auto threadHashId = (typeHash ^ threadId) & MAX_SERVICES_MASK; - std::atomic_thread_fence(std::memory_order_acquire); for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { - if (mServicesKey[i + threadHashId] == typeHash) { + if (mServicesKey[i + threadHashId].load() == typeHash) { return i + threadHashId; } } @@ -188,7 +203,14 @@ struct ServiceRegistry { // find it with getPos, but the value can still // be nullptr. auto pos = getPos(typeHash, threadId); + if (pos != -1 && mServicesMeta[pos].kind == ServiceKind::Stream && mServicesMeta[pos].threadId != threadId) { + throwError(runtime_error_f("Inconsistent registry for thread %d. Expected %d", threadId, mServicesMeta[pos].threadId)); + O2_BUILTIN_UNREACHABLE(); + } + if (pos != -1) { + mServicesKey[pos].load(); + std::atomic_thread_fence(std::memory_order_acquire); void* ptr = mServicesValue[pos]; if (ptr) { return ptr; @@ -200,9 +222,17 @@ struct ServiceRegistry { if (threadId != 0) { int pos = getPos(typeHash, 0); if (pos != -1 && kind != ServiceKind::Stream) { + mServicesKey[pos].load(); + std::atomic_thread_fence(std::memory_order_acquire); registerService(typeHash, mServicesValue[pos], kind, threadId, name); } - return mServicesValue[pos]; + if (pos != -1) { + mServicesKey[pos].load(); + std::atomic_thread_fence(std::memory_order_acquire); + return mServicesValue[pos]; + } else { + throwError(runtime_error_f("Unable to find requested service %s", name)); + } } // If we are here it means we never registered a // service for the 0 thread (i.e. the main thread). @@ -218,7 +248,7 @@ struct ServiceRegistry { } mutable std::vector<ServiceSpec> mSpecs; - mutable std::array<uint32_t, MAX_SERVICES + MAX_DISTANCE> mServicesKey; + mutable std::array<std::atomic<uint32_t>, MAX_SERVICES + MAX_DISTANCE> mServicesKey; mutable std::array<void*, MAX_SERVICES + MAX_DISTANCE> mServicesValue; mutable std::array<ServiceMeta, MAX_SERVICES + MAX_DISTANCE> mServicesMeta; mutable std::array<std::atomic<bool>, MAX_SERVICES + MAX_DISTANCE> mServicesBooked; @@ -285,8 +315,8 @@ struct ServiceRegistry { return *reinterpret_cast<T*>(ptr); } } - throw runtime_error_f("Unable to find service of kind %s. Make sure you use const / non-const correctly.", - typeid(T).name()); + throwError(runtime_error_f("Unable to find service of kind %s. Make sure you use const / non-const correctly.", typeid(T).name())); + O2_BUILTIN_UNREACHABLE(); } }; diff --git a/Framework/Core/include/Framework/ServiceRegistryHelpers.h b/Framework/Core/include/Framework/ServiceRegistryHelpers.h index f738517c4a254..5c3742772d2ba 100644 --- a/Framework/Core/include/Framework/ServiceRegistryHelpers.h +++ b/Framework/Core/include/Framework/ServiceRegistryHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,8 @@ struct ServiceRegistryHelpers { // This only works for concrete implementations of the type T. // We need type elision as we do not want to know all the services in // advance + static_assert(std::is_const_v<I> == false, + "Service interface must not be const if service object is not const"); static_assert(std::is_base_of<I, C>::value == true, "Registered service is not derived from declared interface"); constexpr auto typeHash = TypeIdHelpers::uniqueId<I>(); @@ -53,9 +56,11 @@ struct ServiceRegistryHelpers { // This only works for concrete implementations of the type T. // We need type elision as we do not want to know all the services in // advance + static_assert(std::is_const_v<I> == true, + "Service interface must be const if service object is const"); static_assert(std::is_base_of<I, C>::value == true, "Registered service is not derived from declared interface"); - constexpr auto typeHash = TypeIdHelpers::uniqueId<I const>(); + constexpr auto typeHash = TypeIdHelpers::uniqueId<I>(); return ServiceHandle{typeHash, reinterpret_cast<void*>(const_cast<C*>(service)), K, typeid(C).name()}; } }; diff --git a/Framework/Core/include/Framework/ServiceSpec.h b/Framework/Core/include/Framework/ServiceSpec.h index e4f80382edc9a..fc690afca94db 100644 --- a/Framework/Core/include/Framework/ServiceSpec.h +++ b/Framework/Core/include/Framework/ServiceSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,10 @@ class DanglingContext; /// A callback to create a given Service. using ServiceInit = std::function<ServiceHandle(ServiceRegistry&, DeviceState&, fair::mq::ProgOptions&)>; +/// A callback invoked whenever we start running, before the user callback. +using ServiceStartCallback = std::function<void(ServiceRegistry&, void*)>; +/// A callback invoked whenever we stop running, before we exit. +using ServiceExitCallback = std::function<void(ServiceRegistry&, void*)>; /// A callback to configure a given Service. Notice that the /// service itself is type erased and it's responsibility of @@ -82,6 +87,12 @@ using ServiceMetricHandling = std::function<void(ServiceRegistry&, /// Callback executed in the child after dispatching happened. using ServicePostDispatching = std::function<void(ProcessingContext&, void*)>; +/// Callback invoked when the driver enters the init phase. +using ServiceDriverInit = std::function<void(ServiceRegistry&, boost::program_options::variables_map const&)>; + +/// Callback invoked when the driver enters the init phase. +using ServiceDriverStartup = std::function<void(ServiceRegistry&, boost::program_options::variables_map const&)>; + /// A specification for a Service. /// A Service is a utility class which does not perform /// data processing itself, but it can be used by the data processor @@ -90,11 +101,11 @@ using ServicePostDispatching = std::function<void(ProcessingContext&, void*)>; /// messages after a computation happended). struct ServiceSpec { /// Name of the service - std::string name; + std::string name = "please specify name"; /// Callback to initialise the service. - ServiceInit init; + ServiceInit init = nullptr; /// Callback to configure the service. - ServiceConfigureCallback configure; + ServiceConfigureCallback configure = nullptr; /// Callback executed before actual processing happens. ServiceProcessingCallback preProcessing = nullptr; /// Callback executed once actual processing happened. @@ -114,8 +125,7 @@ struct ServiceSpec { /// Callback executed after forking a given device in the driver, /// but before doing exec / starting the device. ServicePostForkChild postForkChild = nullptr; - /// Callback executed after forking a given device in the driver, - /// but before doing exec / starting the device. + /// Callback executed after forking a given device in the driver. ServicePostForkParent postForkParent = nullptr; /// Callback executed before and after we schedule a topology @@ -129,8 +139,17 @@ struct ServiceSpec { /// dispatched. ServicePostDispatching postDispatching = nullptr; + /// Callback invoked on Start + ServiceStartCallback start = nullptr; + /// Callback invoked on exit + ServiceExitCallback exit = nullptr; + /// Callback invoked on driver entering the INIT state + ServiceDriverInit driverInit = nullptr; + /// Callback invoked when starting the driver + ServiceDriverStartup driverStartup = nullptr; + /// Kind of service being specified. - ServiceKind kind; + ServiceKind kind = ServiceKind::Serial; }; struct ServiceConfigureHandle { @@ -158,6 +177,20 @@ struct ServiceDispatchingHandle { void* service; }; +struct ServiceStartHandle { + ServiceStartCallback callback; + void* service; +}; + +struct ServiceExitHandle { + ServiceExitCallback callback; + void* service; +}; + +struct ServicePlugin { + virtual ServiceSpec* create() = 0; +}; + } // namespace o2::framework #endif // O2_FRAMEWORK_SERVICESPEC_H_ diff --git a/Framework/Core/include/Framework/SimpleOptionsRetriever.h b/Framework/Core/include/Framework/SimpleOptionsRetriever.h index 55a01e0a87974..a775c4bbc79eb 100644 --- a/Framework/Core/include/Framework/SimpleOptionsRetriever.h +++ b/Framework/Core/include/Framework/SimpleOptionsRetriever.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/SimpleRawDeviceService.h b/Framework/Core/include/Framework/SimpleRawDeviceService.h index 03e3e75e0c2db..83aeb3627dfbb 100644 --- a/Framework/Core/include/Framework/SimpleRawDeviceService.h +++ b/Framework/Core/include/Framework/SimpleRawDeviceService.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/SourceInfoHeader.h b/Framework/Core/include/Framework/SourceInfoHeader.h index cc024d69e2b66..2f2d2edd87928 100644 --- a/Framework/Core/include/Framework/SourceInfoHeader.h +++ b/Framework/Core/include/Framework/SourceInfoHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,6 @@ #include "Framework/ChannelInfo.h" #include <cstdint> -#include <cstdio> #include <memory> #include <cassert> diff --git a/Framework/Core/include/Framework/StaticFor.h b/Framework/Core/include/Framework/StaticFor.h new file mode 100644 index 0000000000000..34e1f5fb9704b --- /dev/null +++ b/Framework/Core/include/Framework/StaticFor.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_STATICFOR_H_ +#define O2_FRAMEWORK_STATICFOR_H_ + +namespace o2::framework +{ +namespace staticFor_details +{ +template <int FirstIndex, std::size_t... IndexSequence, typename F> +void applyFunction(F const& f, std::index_sequence<IndexSequence...>) +{ + (f(std::integral_constant<int, FirstIndex + IndexSequence>{}), ...); +} +} // namespace staticFor_details + +template <int FirstIndex, int LastIndex, typename IndexSequence = std::make_index_sequence<(LastIndex - FirstIndex) + 1>, typename F> +static inline constexpr void static_for(F const& f) +{ + staticFor_details::applyFunction<FirstIndex>(f, IndexSequence{}); +} +} // namespace o2::framework + +#endif // O2_FRAMEWORK_STATICFOR_H_ diff --git a/Framework/Core/include/Framework/StepTHn.h b/Framework/Core/include/Framework/StepTHn.h new file mode 100644 index 0000000000000..61c664e094a29 --- /dev/null +++ b/Framework/Core/include/Framework/StepTHn.h @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef StepTHn_H +#define StepTHn_H + +// optimized data container reusing functionality of THn +// A THnSparse is used to have the axis functionality "for free" + +#include "TNamed.h" +#include "THnSparse.h" +#include "TAxis.h" +#include "TArray.h" + +#include "Framework/Logger.h" + +class TArray; +class TArrayF; +class TArrayD; +class TCollection; + +class StepTHn : public TNamed +{ + public: + StepTHn(); + StepTHn(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes); + ~StepTHn() override; + + template <typename... Ts> + void Fill(int iStep, const Ts&... valuesAndWeight); + void Fill(int iStep, int nParams, double positionAndWeight[]); + + THnBase* getTHn(Int_t step, Bool_t sparse = kFALSE) + { + if (!mTarget || !mTarget[step]) { + createTarget(step, sparse); + } + return mTarget[step]; + } + Int_t getNSteps() { return mNSteps; } + Int_t getNVar() { return mNVars; } + + TArray* getValues(Int_t step) { return mValues[step]; } + TArray* getSumw2(Int_t step) { return mSumw2[step]; } + + StepTHn(const StepTHn& c); + StepTHn& operator=(const StepTHn& corr); + void Copy(TObject& c) const override; + + virtual Long64_t Merge(TCollection* list) = 0; + + TAxis* GetAxis(int i) { return mPrototype->GetAxis(i); } + void Sumw2(){}; // TODO: added for compatibiltiy with registry, but maybe it would be useful also in StepTHn as toggle for error weights + + protected: + void init(); + virtual TArray* createArray(const TArray* src = nullptr) const = 0; + void createTarget(Int_t step, Bool_t sparse); + void deleteContainers(); + + Long64_t getGlobalBinIndex(const Int_t* binIdx); + + Long64_t mNBins; // number of total bins + Int_t mNVars; // number of variables + Int_t mNSteps; // number of selection steps + TArray** mValues; //[mNSteps] data container + TArray** mSumw2; //[mNSteps] data container + + THnBase** mTarget; //! target histogram + + TAxis** mAxisCache; //! cache axis pointers (about 50% of the time in Fill is spent in GetAxis otherwise) + Int_t* mNbinsCache; //! cache Nbins per axis + Double_t* mLastVars; //! caching of last used bins (in many loops some vars are the same for a while) + Int_t* mLastBins; //! caching of last used bins (in many loops some vars are the same for a while) + + THnSparse* mPrototype; // not filled used as prototype histogram for axis functionality etc. + + ClassDef(StepTHn, 1) // THn like container +}; + +template <class TemplateArray> +class StepTHnT : public StepTHn +{ + public: + StepTHnT() : StepTHn() {} + StepTHnT(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes, Int_t* nBins, std::vector<Double_t> binEdges[], const char** axisTitles); + StepTHnT(const char* name, const char* title, const int nSteps, const int nAxes, const int* nBins, const double* xmin, const double* xmax); + ~StepTHnT() override = default; + + protected: + TArray* createArray(const TArray* src = nullptr) const override + { + if (src == nullptr) { + return new TemplateArray(mNBins); + } else { + return new TemplateArray(*((TemplateArray*)src)); + } + } + + Long64_t Merge(TCollection* list) override; + + ClassDef(StepTHnT, 1) // THn like container +}; + +typedef StepTHnT<TArrayF> StepTHnF; +typedef StepTHnT<TArrayD> StepTHnD; + +template <typename... Ts> +void StepTHn::Fill(int iStep, const Ts&... valuesAndWeight) +{ + constexpr int nArgs = sizeof...(Ts); + double tempArray[] = {static_cast<double>(valuesAndWeight)...}; + Fill(iStep, nArgs, tempArray); +} + +#endif diff --git a/Framework/Core/include/Framework/StringContext.h b/Framework/Core/include/Framework/StringContext.h index 3098c77cdc628..d0bd8e2d8c3e4 100644 --- a/Framework/Core/include/Framework/StringContext.h +++ b/Framework/Core/include/Framework/StringContext.h @@ -1,26 +1,24 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_STRINGCONTEXT_H -#define FRAMEWORK_STRINGCONTEXT_H +#ifndef O2_FRAMEWORK_STRINGCONTEXT_H_ +#define O2_FRAMEWORK_STRINGCONTEXT_H_ #include "Framework/FairMQDeviceProxy.h" #include <vector> -#include <cassert> #include <string> #include <memory> -class FairMQMessage; +#include <fairmq/FwdDecls.h> -namespace o2 -{ -namespace framework +namespace o2::framework { /// A context which holds `std::string`s being passed around @@ -44,12 +42,7 @@ class StringContext void addString(std::unique_ptr<FairMQMessage> header, std::unique_ptr<std::string> s, - const std::string& channel) - { - mMessages.push_back(std::move(MessageRef{std::move(header), - std::move(s), - channel})); - } + const std::string& channel); Messages::iterator begin() { @@ -66,17 +59,7 @@ class StringContext return mMessages.size(); } - void clear() - { - // On send we move the header, but the payload remains - // there because what's really sent is the copy of the string - // payload will be cleared by the mMessages.clear() - for (auto& m : mMessages) { - assert(m.header.get() == nullptr); - assert(m.payload.get() != nullptr); - } - mMessages.clear(); - } + void clear(); FairMQDeviceProxy& proxy() { @@ -88,6 +71,5 @@ class StringContext Messages mMessages; }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_STRINGCONTEXT_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_STRINGCONTEXT_H_ diff --git a/Framework/Core/include/Framework/StringHelpers.h b/Framework/Core/include/Framework/StringHelpers.h index 778aba4efa3e7..26d572d934257 100644 --- a/Framework/Core/include/Framework/StringHelpers.h +++ b/Framework/Core/include/Framework/StringHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,9 @@ #define O2_FRAMEWORK_STRINGHELPERS_H_ #include <cstdint> +#include <utility> +#include <type_traits> +#include <string_view> // CRC32 Table (zlib polynomial) static constexpr uint32_t crc_table[256] = {0x0L, 0x77073096L, 0xee0e612cL, @@ -73,4 +77,96 @@ constexpr uint32_t compile_time_hash(char const* str) return crc32(str, static_cast<int>(__builtin_strlen(str)) - 1) ^ 0xFFFFFFFF; } +template <int N> +constexpr uint32_t compile_time_hash_from_literal(const char (&str)[N]) +{ + return crc32(str, N - 2) ^ 0xFFFFFFFF; +} + +template <char... chars> +struct ConstStr { + static constexpr char str[] = {chars..., '\0'}; + static constexpr uint32_t hash = compile_time_hash_from_literal(str); +}; + +template <typename> +struct is_const_str : std::false_type { +}; + +template <char... chars> +struct is_const_str<ConstStr<chars...>> : std::true_type { +}; + +template <typename T> +constexpr bool is_const_str_v(T) +{ + return is_const_str<T>::value; +} + +template <char... chars1, char... chars2> +constexpr auto operator+(const ConstStr<chars1...>&, const ConstStr<chars2...>&) +{ + return ConstStr<chars1..., chars2...>{}; +} + +namespace const_str_details +{ + +template <typename T, std::size_t... Is> +constexpr auto as_chars_impl(std::index_sequence<Is...>) +{ + return ConstStr<T::str()[Is]...>{}; +} + +template <typename T> +constexpr auto as_chars() +{ + return as_chars_impl<T>( + std::make_index_sequence<T::size() - 1>{}); +} + +template <int N> +constexpr auto get_str(const char (&str)[N]) +{ + return str; +} + +template <int N> +constexpr auto get_size(const char (&str)[N]) +{ + return N; +} + +constexpr auto get_str(const std::string_view& str) +{ + return str.data(); +} + +constexpr auto get_size(const std::string_view& str) +{ + return str.size() + 1; +} +} // namespace const_str_details + +#define CONST_STR(literal) \ + [] { \ + struct literal_to_chars { \ + static constexpr decltype(auto) str() \ + { \ + return const_str_details::get_str(literal); \ + } \ + static constexpr decltype(auto) size() \ + { \ + return const_str_details::get_size(literal); \ + } \ + }; \ + return const_str_details::as_chars<literal_to_chars>(); \ + }() + +template <typename T> +constexpr auto typeHash() +{ + return compile_time_hash(typeid(T).name()); +} + #endif // O2_FRAMEWORK_STRINGHELPERS_H diff --git a/Framework/Core/include/Framework/TMessageSerializer.h b/Framework/Core/include/Framework/TMessageSerializer.h index b041125800396..23c336eeb8078 100644 --- a/Framework/Core/include/Framework/TMessageSerializer.h +++ b/Framework/Core/include/Framework/TMessageSerializer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,7 @@ #include <gsl/span> #include <memory> #include <mutex> -#include <MemoryResources/Types.h> +#include <cstddef> namespace o2 { @@ -32,8 +33,8 @@ class FairTMessage; // utilities to produce a span over a byte buffer held by various message types // this is to avoid littering code with casts and conversions (span has a signed index type(!)) -gsl::span<o2::byte> as_span(const FairTMessage& msg); -gsl::span<o2::byte> as_span(const FairMQMessage& msg); +gsl::span<std::byte> as_span(const FairTMessage& msg); +gsl::span<std::byte> as_span(const FairMQMessage& msg); class FairTMessage : public TMessage { @@ -41,7 +42,7 @@ class FairTMessage : public TMessage using TMessage::TMessage; FairTMessage() : TMessage(kMESS_OBJECT) {} FairTMessage(void* buf, Int_t len) : TMessage(buf, len) { ResetBit(kIsOwner); } - FairTMessage(gsl::span<o2::byte> buf) : TMessage(buf.data(), buf.size()) { ResetBit(kIsOwner); } + FairTMessage(gsl::span<std::byte> buf) : TMessage(buf.data(), buf.size()) { ResetBit(kIsOwner); } // helper function to clean up the object holding the data after it is transported. static void free(void* /*data*/, void* hint); }; @@ -74,13 +75,13 @@ struct TMessageSerializer { CompressionLevel compressionLevel = -1); template <typename T = TObject> - static std::unique_ptr<T> deserialize(gsl::span<o2::byte> buffer); + static std::unique_ptr<T> deserialize(gsl::span<std::byte> buffer); template <typename T = TObject> - static inline std::unique_ptr<T> deserialize(byte* buffer, size_t size); + static inline std::unique_ptr<T> deserialize(std::byte* buffer, size_t size); // load the schema information from a message/buffer static void loadSchema(const FairMQMessage& msg); - static void loadSchema(gsl::span<o2::byte> buffer); + static void loadSchema(gsl::span<std::byte> buffer); // write the schema into an empty message/buffer static void fillSchema(FairMQMessage& msg, const StreamerList& streamers); @@ -135,7 +136,7 @@ inline void TMessageSerializer::serialize(FairTMessage& tm, const T* input, } template <typename T> -inline std::unique_ptr<T> TMessageSerializer::deserialize(gsl::span<o2::byte> buffer) +inline std::unique_ptr<T> TMessageSerializer::deserialize(gsl::span<std::byte> buffer) { TClass* tgtClass = TClass::GetClass(typeid(T)); if (tgtClass == nullptr) { @@ -158,9 +159,9 @@ inline std::unique_ptr<T> TMessageSerializer::deserialize(gsl::span<o2::byte> bu } template <typename T> -inline std::unique_ptr<T> TMessageSerializer::deserialize(byte* buffer, size_t size) +inline std::unique_ptr<T> TMessageSerializer::deserialize(std::byte* buffer, size_t size) { - return deserialize<T>(gsl::span<o2::byte>(buffer, gsl::narrow<gsl::span<o2::byte>::index_type>(size))); + return deserialize<T>(gsl::span<std::byte>(buffer, gsl::narrow<gsl::span<std::byte>::size_type>(size))); } inline void FairTMessage::free(void* /*data*/, void* hint) @@ -211,15 +212,15 @@ inline TMessageSerializer::StreamerList TMessageSerializer::getStreamers() // gsl::narrow is used to do a runtime narrowing check, this might be a bit paranoid, // we would probably be fine with e.g. gsl::narrow_cast (or just a static_cast) -inline gsl::span<o2::byte> as_span(const FairMQMessage& msg) +inline gsl::span<std::byte> as_span(const FairMQMessage& msg) { - return gsl::span<o2::byte>{static_cast<o2::byte*>(msg.GetData()), gsl::narrow<gsl::span<o2::byte>::index_type>(msg.GetSize())}; + return gsl::span<std::byte>{static_cast<std::byte*>(msg.GetData()), gsl::narrow<gsl::span<std::byte>::size_type>(msg.GetSize())}; } -inline gsl::span<o2::byte> as_span(const FairTMessage& msg) +inline gsl::span<std::byte> as_span(const FairTMessage& msg) { - return gsl::span<o2::byte>{reinterpret_cast<o2::byte*>(msg.Buffer()), - gsl::narrow<gsl::span<o2::byte>::index_type>(msg.BufferSize())}; + return gsl::span<std::byte>{reinterpret_cast<std::byte*>(msg.Buffer()), + gsl::narrow<gsl::span<std::byte>::size_type>(msg.BufferSize())}; } } // namespace framework diff --git a/Framework/Core/include/Framework/TableBuilder.h b/Framework/Core/include/Framework/TableBuilder.h index 43e45b9d79bb0..ef73646a7a273 100644 --- a/Framework/Core/include/Framework/TableBuilder.h +++ b/Framework/Core/include/Framework/TableBuilder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ // Apparently needs to be on top of the arrow includes. #include <sstream> +#include <arrow/chunked_array.h> #include <arrow/status.h> #include <arrow/memory_pool.h> #include <arrow/stl.h> @@ -28,7 +30,6 @@ #include <arrow/table.h> #include <arrow/builder.h> -#include <functional> #include <vector> #include <string> #include <memory> @@ -72,6 +73,11 @@ struct ConversionTraits<T[N]> { using ArrowType = ::arrow::FixedSizeListType; }; +template <typename T> +struct ConversionTraits<std::vector<T>> { + using ArrowType = ::arrow::ListType; +}; + #define O2_ARROW_STL_CONVERSION(c_type, ArrowType_) \ template <> \ struct ConversionTraits<c_type> { \ @@ -95,6 +101,8 @@ O2_ARROW_STL_CONVERSION(double, DoubleType) O2_ARROW_STL_CONVERSION(std::string, StringType) } // namespace detail +void addLabelToSchema(std::shared_ptr<arrow::Schema>& schema, const char* label); + struct BuilderUtils { template <typename T> static arrow::Status appendToList(std::unique_ptr<arrow::FixedSizeListBuilder>& builder, T* data, int size = 1) @@ -148,6 +156,29 @@ struct BuilderUtils { return holder.builder->Append(reinterpret_cast<const uint8_t*>(data.data())); } + /// Appender for the vector case. + template <typename HolderType, typename T> + static arrow::Status append(HolderType& holder, std::vector<T> const& data) + { + using ArrowType = typename detail::ConversionTraits<T>::ArrowType; + using ValueBuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType; + auto status = holder.builder->Reserve(data.size()); + status &= holder.builder->Append(); + auto vbuilder = static_cast<ValueBuilderType*>(holder.builder->value_builder()); + status &= vbuilder->AppendValues(data.begin(), data.end()); + + return status; + } + + template <typename HolderType, typename T> + static void unsafeAppend(HolderType& holder, std::vector<T> const& value) + { + auto status = append(holder, value); + if (!status.ok()) { + throw runtime_error("Unable to append to column"); + } + } + template <typename HolderType, typename T> static void unsafeAppend(HolderType& holder, T value) { @@ -335,6 +366,28 @@ struct BuilderMaker<T[N]> { return arrow::fixed_size_list(arrow::TypeTraits<ElementType>::type_singleton(), N); } }; + +template <typename T> +struct BuilderMaker<std::vector<T>> { + using FillType = std::vector<T>; + using BuilderType = arrow::ListBuilder; + using ArrowType = arrow::ListType; + using ElementType = typename detail::ConversionTraits<T>::ArrowType; + + static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool) + { + std::unique_ptr<arrow::ArrayBuilder> valueBuilder; + auto status = + arrow::MakeBuilder(pool, arrow::TypeTraits<ElementType>::type_singleton(), &valueBuilder); + return std::make_unique<BuilderType>(pool, std::move(valueBuilder)); + } + + static std::shared_ptr<arrow::DataType> make_datatype() + { + return arrow::list(arrow::TypeTraits<ElementType>::type_singleton()); + } +}; + template <typename... ARGS> auto make_builders() { @@ -363,6 +416,12 @@ struct BuilderTraits<T[N]> { using BuilderType = arrow::FixedSizeListBuilder; }; +template <typename T> +struct BuilderTraits<std::vector<T>> { + using ArrowType = arrow::ListType; + using BuilderType = arrow::ListBuilder; +}; + template <typename T> struct DirectInsertion { template <typename BUILDER> @@ -551,33 +610,48 @@ struct HolderTrait<int64_t> { using Holder = BuilderHolder<int64_t, CachedInsertion>; }; +/// Helper function to convert a brace-initialisable struct to +/// a tuple. +template <class T> +auto constexpr to_tuple(T&& object) noexcept +{ + using type = std::decay_t<T>; + if constexpr (is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) { + auto&& [p0, p1, p2, p3] = object; + return std::make_tuple(p0, p1, p2, p3); + } else if constexpr (is_braces_constructible<type, any_type, any_type, any_type>{}) { + auto&& [p0, p1, p2] = object; + return std::make_tuple(p0, p1, p2); + } else if constexpr (is_braces_constructible<type, any_type, any_type>{}) { + auto&& [p0, p1] = object; + return std::make_tuple(p0, p1); + } else if constexpr (is_braces_constructible<type, any_type>{}) { + auto&& [p0] = object; + return std::make_tuple(p0); + } else { + return std::make_tuple(); + } +} + /// Helper class which creates a lambda suitable for building /// an arrow table from a tuple. This can be used, for example /// to build an arrow::Table from a TDataFrame. class TableBuilder { + static void throwError(RuntimeErrorRef const& ref); + template <typename... ARGS> using HoldersTuple = typename std::tuple<typename HolderTrait<ARGS>::Holder...>; /// Get the builders, assumning they were created with a given pack /// of basic types template <typename... ARGS> - auto getBuilders(o2::framework::pack<ARGS...> pack) + auto getBuilders(o2::framework::pack<ARGS...>) { return (HoldersTuple<ARGS...>*)mHolders; } - template <typename... ARGS> - void validate(std::vector<std::string> const& columnNames) - { - constexpr int nColumns = sizeof...(ARGS); - if (nColumns != columnNames.size()) { - throw runtime_error("Mismatching number of column types and names"); - } - if (mHolders != nullptr) { - throw runtime_error("TableBuilder::persist can only be invoked once per instance"); - } - } + void validate(const int nColumns, std::vector<std::string> const& columnNames) const; template <typename... ARGS> auto makeBuilders(std::vector<std::string> const& columnNames, size_t nRows) @@ -595,15 +669,14 @@ class TableBuilder template <typename... ARGS> auto makeFinalizer() { - mFinalizer = [schema = mSchema, &arrays = mArrays, holders = mHolders]() -> void { - auto status = TableBuilderHelpers::finalize(arrays, *(HoldersTuple<ARGS...>*)holders, std::make_index_sequence<sizeof...(ARGS)>{}); - if (status == false) { - throw runtime_error("Unable to finalize"); - } + mFinalizer = [](std::shared_ptr<arrow::Schema> schema, std::vector<std::shared_ptr<arrow::Array>>& arrays, void* holders) -> bool { + return TableBuilderHelpers::finalize(arrays, *(HoldersTuple<ARGS...>*)holders, std::make_index_sequence<sizeof...(ARGS)>{}); }; } public: + void setLabel(const char* label); + TableBuilder(arrow::MemoryPool* pool = arrow::default_memory_pool()) : mHolders{nullptr}, mMemoryPool{pool} @@ -650,7 +723,7 @@ class TableBuilder auto persistTuple(framework::pack<ARGS...>, std::vector<std::string> const& columnNames) { constexpr int nColumns = sizeof...(ARGS); - validate<ARGS...>(columnNames); + validate(nColumns, columnNames); mArrays.resize(nColumns); makeBuilders<ARGS...>(columnNames, 1000); makeFinalizer<ARGS...>(); @@ -660,7 +733,7 @@ class TableBuilder return [holders = mHolders](unsigned int slot, FillTuple const& t) -> void { auto status = TableBuilderHelpers::append(*(HoldersTuple<ARGS...>*)holders, std::index_sequence_for<ARGS...>{}, t); if (status == false) { - throw runtime_error("Unable to append"); + throwError(runtime_error("Unable to append")); } }; } @@ -687,7 +760,7 @@ class TableBuilder auto preallocatedPersist(std::vector<std::string> const& columnNames, int nRows) { constexpr int nColumns = sizeof...(ARGS); - validate<ARGS...>(columnNames); + validate(nColumns, columnNames); mArrays.resize(nColumns); makeBuilders<ARGS...>(columnNames, nRows); makeFinalizer<ARGS...>(); @@ -702,7 +775,7 @@ class TableBuilder auto bulkPersist(std::vector<std::string> const& columnNames, size_t nRows) { constexpr int nColumns = sizeof...(ARGS); - validate<ARGS...>(columnNames); + validate(nColumns, columnNames); mArrays.resize(nColumns); makeBuilders<ARGS...>(columnNames, nRows); makeFinalizer<ARGS...>(); @@ -716,7 +789,7 @@ class TableBuilder auto bulkPersistChunked(std::vector<std::string> const& columnNames, size_t nRows) { constexpr int nColumns = sizeof...(ARGS); - validate<ARGS...>(columnNames); + validate(nColumns, columnNames); mArrays.resize(nColumns); makeBuilders<ARGS...>(columnNames, nRows); makeFinalizer<ARGS...>(); @@ -764,7 +837,7 @@ class TableBuilder return this->template persist<E>(columnNames); } - std::function<void(void)> mFinalizer; + bool (*mFinalizer)(std::shared_ptr<arrow::Schema> schema, std::vector<std::shared_ptr<arrow::Array>>& arrays, void* holders); void* mHolders; arrow::MemoryPool* mMemoryPool; std::shared_ptr<arrow::Schema> mSchema; @@ -772,23 +845,24 @@ class TableBuilder }; template <typename T> -auto makeEmptyTable() +auto makeEmptyTable(const char* name) { TableBuilder b; - auto writer = b.cursor<T>(); + [[maybe_unused]] auto writer = b.cursor<T>(); + b.setLabel(name); return b.finalize(); } /// Expression-based column generator to materialize columns template <typename... C> -auto spawner(framework::pack<C...> columns, arrow::Table* atable) +auto spawner(framework::pack<C...> columns, arrow::Table* atable, const char* name) { - static auto new_schema = o2::soa::createSchemaFromColumns(columns); - static auto projectors = framework::expressions::createProjectors(columns, atable->schema()); - + std::string s = std::string{name} + "Extension"; if (atable->num_rows() == 0) { - return makeEmptyTable<soa::Table<C...>>(); + return makeEmptyTable<soa::Table<C...>>(s.c_str()); } + static auto new_schema = o2::soa::createSchemaFromColumns(columns); + static auto projectors = framework::expressions::createProjectors(columns, atable->schema()); arrow::TableBatchReader reader(*atable); std::shared_ptr<arrow::RecordBatch> batch; @@ -799,15 +873,20 @@ auto spawner(framework::pack<C...> columns, arrow::Table* atable) while (true) { auto s = reader.ReadNext(&batch); if (!s.ok()) { - throw runtime_error_f("Cannot read batches from table: %s", s.ToString().c_str()); + throw runtime_error_f("Cannot read batches from table %s: %s", name, s.ToString().c_str()); } if (batch == nullptr) { break; } - s = projectors->Evaluate(*batch, arrow::default_memory_pool(), &v); - if (!s.ok()) { - throw runtime_error_f("Cannot apply projector: %s", s.ToString().c_str()); + try { + s = projectors->Evaluate(*batch, arrow::default_memory_pool(), &v); + if (!s.ok()) { + throw runtime_error_f("Cannot apply projector to table %s: %s", name, s.ToString().c_str()); + } + } catch (std::exception& e) { + throw runtime_error_f("Cannot apply projector to table %s: exception caught: %s", name, e.what()); } + for (auto i = 0u; i < sizeof...(C); ++i) { chunks[i].emplace_back(v.at(i)); } @@ -817,6 +896,7 @@ auto spawner(framework::pack<C...> columns, arrow::Table* atable) arrays.push_back(std::make_shared<arrow::ChunkedArray>(chunks[i])); } + addLabelToSchema(new_schema, s.c_str()); return arrow::Table::Make(new_schema, arrays); } @@ -845,7 +925,7 @@ void lowerBound(int32_t value, T& start) while (count > 0) { step = count / 2; start.moveByIndex(step); - if (start.template getId<Key>() < value) { + if (start.template getId<Key>() <= value) { count -= step + 1; } else { start.moveByIndex(-step); diff --git a/Framework/Core/include/Framework/TableConsumer.h b/Framework/Core/include/Framework/TableConsumer.h index 5d4629aaaa4d8..f2a041952470c 100644 --- a/Framework/Core/include/Framework/TableConsumer.h +++ b/Framework/Core/include/Framework/TableConsumer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/TableTreeHelpers.h b/Framework/Core/include/Framework/TableTreeHelpers.h index 519c2aa418878..afc6bad35983f 100644 --- a/Framework/Core/include/Framework/TableTreeHelpers.h +++ b/Framework/Core/include/Framework/TableTreeHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,119 +22,122 @@ namespace o2::framework { // ----------------------------------------------------------------------------- -// TableToTree allows to save the contents of a given arrow::Table to a TTree -// BranchIterator is used by TableToTree +// TableToTree allows to save the contents of a given arrow::Table into +// a TTree +// ColumnToBranch is used by GenericTableToTree // // To write the contents of a table ta to a tree tr on file f do: -// . TableToTree t2t(ta,f,treename); -// . t2t.addBranch(coumn1); t2t.addBranch(coumn1); ... -// OR -// t2t.addAllBranches(); +// . GenericTableToTree t2t(ta, f,treename); +// . t2t.addBranches(); +// OR t2t.addBranch(column.get(), field.get()), ...; // . t2t.process(); // // ............................................................................. -class BranchIterator -{ +// ----------------------------------------------------------------------------- +// TreeToTable allows to fill the contents of a given TTree to an arrow::Table +// ColumnIterator is used by TreeToTable +// +// To copy the contents of a tree tr to a table ta do: +// . TreeToTable t2t(tr); +// . t2t.addColumn(columnname1); t2t.addColumn(columnname2); ... +// OR +// t2t.addAllColumns(); +// . auto ta = t2t.process(); +// +// ............................................................................. +struct ROOTTypeInfo { + EDataType type; + char suffix[3]; + int size; +}; - private: - std::string mBranchName; // branch name - arrow::ArrayVector mChunks; // chunks - Int_t mNumberChuncs; // number of chunks - Int_t mCounterChunk; // chunk counter - Int_t mNumberRows; // number of rows - Int_t mCounterRow; // row counter - - // data buffers for each data type - bool mStatus = false; - arrow::Field* mField; - arrow::Type::type mFieldType; - arrow::Type::type mElementType; - int32_t mNumberElements; - std::string mLeaflistString; - - TBranch* mBranchPtr = nullptr; - - char* mBranchBuffer = nullptr; - void* mValueBuffer = nullptr; - - std::shared_ptr<arrow::BooleanArray> mArray_o = nullptr; - //bool mBoolValueHolder; - bool* mVariable_o = nullptr; - - uint8_t* mVariable_ub = nullptr; - uint16_t* mVariable_us = nullptr; - uint32_t* mVariable_ui = nullptr; - uint64_t* mVariable_ul = nullptr; - int8_t* mVariable_b = nullptr; - int16_t* mVariable_s = nullptr; - int32_t* mVariable_i = nullptr; - int64_t* mVariable_l = nullptr; - float* mVariable_f = nullptr; - double* mVariable_d = nullptr; - - // initialize a branch - bool initBranch(TTree* tree); - - // initialize chunk ib - bool initDataBuffer(Int_t ib); +auto arrowTypeFromROOT(EDataType type, int size); +auto basicROOTTypeFromArrow(arrow::Type::type id); +class BranchToColumn +{ public: - BranchIterator(TTree* tree, std::shared_ptr<arrow::ChunkedArray> col, std::shared_ptr<arrow::Field> field); - ~BranchIterator(); + BranchToColumn(TBranch* branch, const char* name, EDataType type, int listSize, arrow::MemoryPool* pool); + ~BranchToColumn() = default; + TBranch* branch(); - // has the iterator been properly initialized - bool getStatus(); + std::pair<std::shared_ptr<arrow::ChunkedArray>, std::shared_ptr<arrow::Field>> read(TBuffer* buffer); - // fills buffer with next value - // returns false if end of buffer reached - bool push(); + private: + arrow::Status appendValues(unsigned char const* buffer, int numEntries); + arrow::Status finish(std::shared_ptr<arrow::Array>* array); + arrow::Status reserve(int numEntries); + TBranch* mBranch = nullptr; + std::string mColumnName; + EDataType mType; + std::shared_ptr<arrow::DataType> mArrowType; + arrow::ArrayBuilder* mValueBuilder = nullptr; + std::unique_ptr<arrow::FixedSizeListBuilder> mListBuilder = nullptr; + int mListSize = 1; + std::unique_ptr<arrow::ArrayBuilder> mBuilder = nullptr; }; -class TableToTree +class ColumnToBranch { + public: + ColumnToBranch(TTree* tree, std::shared_ptr<arrow::ChunkedArray> const& column, std::shared_ptr<arrow::Field> const& field); + ColumnToBranch(ColumnToBranch const& other) = delete; + ColumnToBranch(ColumnToBranch&& other) = delete; + void at(const int64_t* pos); private: - TTree* mTreePtr; - - // a list of BranchIterator - std::vector<BranchIterator*> mBranchIterators; - - // table to convert - std::shared_ptr<arrow::Table> mTable; + auto getCurrentBuffer(); + void resetBuffer(); + void accessChunk(int64_t at); + void nextChunk(); + + std::string mBranchName; + std::string mLeafList; + TBranch* mBranch = nullptr; + arrow::ChunkedArray* mColumn = nullptr; + int64_t const* mCurrentPos = nullptr; + int64_t mFirstIndex = 0; + int mCurrentChunk = 0; + int mListSize = 1; + ROOTTypeInfo mType; + std::vector<uint8_t> cache; + uint8_t const* mCurrent = nullptr; + uint8_t const* mLast = nullptr; + bool allocated = false; +}; +class TableToTree +{ public: - TableToTree(std::shared_ptr<arrow::Table> table, - TFile* file, - const char* treename); - ~TableToTree(); + TableToTree(std::shared_ptr<arrow::Table> const& table, TFile* file, const char* treename); - // add branches - bool addBranch(std::shared_ptr<arrow::ChunkedArray> col, std::shared_ptr<arrow::Field> field); - bool addAllBranches(); - - // write table to tree TTree* process(); + void addBranch(std::shared_ptr<arrow::ChunkedArray> const& column, std::shared_ptr<arrow::Field> const& field); + void addAllBranches(); + + private: + arrow::Table* mTable; + int64_t mRows = 0; + TTree* mTree = nullptr; + std::vector<std::unique_ptr<ColumnToBranch>> mColumnReaders; }; class TreeToTable { + public: + TreeToTable(arrow::MemoryPool* pool = arrow::default_memory_pool()); + void setLabel(const char* label); + void addAllColumns(TTree* tree, std::vector<std::string>&& names = {}); + void fill(TTree*); + std::shared_ptr<arrow::Table> finalize(); private: + arrow::MemoryPool* mArrowMemoryPool; + std::vector<std::unique_ptr<BranchToColumn>> mBranchReaders; + std::string mTableLabel; std::shared_ptr<arrow::Table> mTable; - std::vector<std::string> mColumnNames; - - public: - // add a column to be included in the arrow::table - void addColumn(const char* colname); - // add all branches in @a tree as columns - bool addAllColumns(TTree* tree); - - // do the looping with the TTreeReader - void fill(TTree* tree); - - // create the table - std::shared_ptr<arrow::Table> finalize(); + void addReader(TBranch* branch, const char* name); }; // ----------------------------------------------------------------------------- diff --git a/Framework/Core/include/Framework/Task.h b/Framework/Core/include/Framework/Task.h index e2cbf32f1a4f0..46a906b630331 100644 --- a/Framework/Core/include/Framework/Task.h +++ b/Framework/Core/include/Framework/Task.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/TerminationPolicy.h b/Framework/Core/include/Framework/TerminationPolicy.h index 13eda6f9567c3..2a366cd231a18 100644 --- a/Framework/Core/include/Framework/TerminationPolicy.h +++ b/Framework/Core/include/Framework/TerminationPolicy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/TextControlService.h b/Framework/Core/include/Framework/TextControlService.h deleted file mode 100644 index fd2e207cb479c..0000000000000 --- a/Framework/Core/include/Framework/TextControlService.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_FRAMEWORK_TEXTCONTROLSERVICE_H_ -#define O2_FRAMEWORK_TEXTCONTROLSERVICE_H_ - -#include "Framework/ServiceHandle.h" -#include "Framework/ControlService.h" - -#include <string> -#include <regex> -#include <mutex> - -namespace o2::framework -{ - -class ServiceRegistry; -class DeviceState; - -/// A service that data processors can use to talk to control and ask for -/// their own state change or others. -class TextControlService : public ControlService -{ - public: - TextControlService(ServiceRegistry& registry, DeviceState& deviceState); - /// Tell the control that I am ready to quit. This will be - /// done by printing (only once) - /// - /// CONTROL_ACTION: READY_TO_QUIT_ME - /// - /// or - /// - /// CONTROL_ACTION: READY_TO_QUIT_ALL - /// - /// depending on the value of \param all. - /// - /// It's up to the driver to actually react on that and terminate the - /// child. - void readyToQuit(QuitRequest all = QuitRequest::Me) final; - - void endOfStream() final; - - void notifyStreamingState(StreamingState state) final; - - private: - bool mOnce = false; - ServiceRegistry& mRegistry; - DeviceState& mDeviceState; - std::mutex mMutex; -}; - -bool parseControl(std::string const& s, std::smatch& match); - -} // namespace o2::framework -#endif // O2_FRAMEWORK_TEXTCONTROLSERVICE_H_ diff --git a/Framework/Core/include/Framework/TimesliceIndex.h b/Framework/Core/include/Framework/TimesliceIndex.h index 43cef66bcee5e..e0cf80851c6a1 100644 --- a/Framework/Core/include/Framework/TimesliceIndex.h +++ b/Framework/Core/include/Framework/TimesliceIndex.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #define O2_FRAMEWORK_TIMESLICEINDEX_H_ #include "Framework/DataDescriptorMatcher.h" +#include "Framework/CompilerBuiltins.h" #include "Framework/ServiceHandle.h" #include <cstdint> @@ -48,14 +50,24 @@ class TimesliceIndex /// TimesliceIndex is threadsafe because it's accessed only by the /// DataRelayer. constexpr static ServiceKind service_kind = ServiceKind::Global; + + /// What to do when there is backpressure + enum struct BackpressureOp { + Wait, // Do nothing and wait for the oldest slot to complete + DropAncient, // Drop the message with the least recent timestamp + DropRecent // Drop the message with the most recent timestamp + }; + /// The outcome for the processing of a given timeslot enum struct ActionTaken { ReplaceUnused, /// An unused / invalid slot is used to hold the new context ReplaceObsolete, /// An obsolete slot is used to hold the new context and the old one is dropped + Wait, /// We wait for the oldest slot to complete. DropInvalid, /// An invalid context is not inserted in the index and dropped DropObsolete /// An obsolete context is not inserted in the index and dropped }; + TimesliceIndex(size_t maxLanes); inline void resize(size_t s); inline size_t size() const; inline bool isValid(TimesliceSlot const& slot) const; @@ -68,12 +80,7 @@ class TimesliceIndex /// now the information about the timeslot to associate needs to be /// determined outside the TimesliceIndex. inline void associate(TimesliceId timestamp, TimesliceSlot slot); - /// Give a slot, @return the TimesliceId (i.e. the variable at position 0) - /// associated to it. Notice that there is no unique way to - /// determine the other way around anymore, because a single TimesliceId - /// could correspond to different slots once we implement wildcards - /// (e.g. if we ask for InputSpec{"*", "CLUSTERS"}). - inline TimesliceId getTimesliceForSlot(TimesliceSlot slot) const; + /// Given a slot, @return the VariableContext associated to it. /// This effectively means that the TimesliceIndex is now owner of the /// VariableContext. @@ -86,14 +93,15 @@ class TimesliceIndex /// Find the LRU entry in the cache and replace it with @a newContext /// @a slot is filled with the slot used to hold the context, if applicable. + /// @a timestamp must be provided to select the correct lane, in case of pipelining /// @return the action taken on insertion, which can be used for bookkeeping /// of the messages. - inline std::tuple<ActionTaken, TimesliceSlot> replaceLRUWith(data_matcher::VariableContext& newContext); + inline std::tuple<ActionTaken, TimesliceSlot> replaceLRUWith(data_matcher::VariableContext& newContext, TimesliceId timestamp); private: /// @return the oldest slot possible so that we can eventually override it. /// This is the timeslices for all the in flight parts. - inline TimesliceSlot findOldestSlot() const; + inline TimesliceSlot findOldestSlot(TimesliceId) const; /// The variables for each cacheline. std::vector<data_matcher::VariableContext> mVariables; @@ -104,6 +112,11 @@ class TimesliceIndex /// This keeps track whether or not something was relayed /// since last time we called getReadyToProcess() std::vector<bool> mDirty; + + /// What to do in case of backpressure + BackpressureOp mBackpressurePolicy = BackpressureOp::Wait; + /// The maximum number of lanes for this timeslice index + size_t mMaxLanes; }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/TimesliceIndex.inc b/Framework/Core/include/Framework/TimesliceIndex.inc index 59067e1975c3c..37157ae05c577 100644 --- a/Framework/Core/include/Framework/TimesliceIndex.inc +++ b/Framework/Core/include/Framework/TimesliceIndex.inc @@ -1,17 +1,20 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -namespace o2 -{ -namespace framework +namespace o2::framework { +inline TimesliceIndex::TimesliceIndex(size_t maxLanes) +: mMaxLanes {maxLanes} +{} + inline bool TimesliceId::isValid(TimesliceId const& timeslice) { return timeslice.value != INVALID; } inline bool TimesliceSlot::isValid(TimesliceSlot const& slot) { return slot.index != INVALID; } @@ -83,16 +86,17 @@ inline void TimesliceIndex::associate(TimesliceId timestamp, TimesliceSlot slot) mDirty[slot.index] = true; } -inline TimesliceSlot TimesliceIndex::findOldestSlot() const +inline TimesliceSlot TimesliceIndex::findOldestSlot(TimesliceId timestamp) const { - TimesliceSlot oldest{0}; + size_t lane = timestamp.value % mMaxLanes; + TimesliceSlot oldest{lane}; auto oldPVal = std::get_if<uint64_t>(&mVariables[oldest.index].get(0)); if (oldPVal == nullptr) { return oldest; } uint64_t oldTimestamp = *oldPVal; - for (size_t i = 1; i < mVariables.size(); ++i) { + for (size_t i = lane + mMaxLanes; i < mVariables.size(); i += mMaxLanes) { auto newPVal = std::get_if<uint64_t>(&mVariables[i].get(0)); if (newPVal == nullptr) { return TimesliceSlot{i}; @@ -107,16 +111,6 @@ inline TimesliceSlot TimesliceIndex::findOldestSlot() const return oldest; } -inline TimesliceId TimesliceIndex::getTimesliceForSlot(TimesliceSlot slot) const -{ - assert(mVariables.size() > slot.index); - auto pval = std::get_if<uint64_t>(&mVariables[slot.index].get(0)); - if (pval == nullptr) { - return TimesliceId{TimesliceId::INVALID}; - } - return TimesliceId{*pval}; -} - inline data_matcher::VariableContext& TimesliceIndex::getVariablesForSlot(TimesliceSlot slot) { assert(mVariables.size() > slot.index); @@ -129,9 +123,9 @@ inline data_matcher::VariableContext& TimesliceIndex::getPublishedVariablesForSl return mPublishedVariables[slot.index]; } -inline std::tuple<TimesliceIndex::ActionTaken, TimesliceSlot> TimesliceIndex::replaceLRUWith(data_matcher::VariableContext& newContext) +inline std::tuple<TimesliceIndex::ActionTaken, TimesliceSlot> TimesliceIndex::replaceLRUWith(data_matcher::VariableContext& newContext, TimesliceId timestamp) { - auto oldestSlot = findOldestSlot(); + auto oldestSlot = findOldestSlot(timestamp); if (TimesliceIndex::isValid(oldestSlot) == false) { mVariables[oldestSlot.index] = newContext; return std::make_tuple(ActionTaken::ReplaceUnused, oldestSlot); @@ -148,11 +142,27 @@ inline std::tuple<TimesliceIndex::ActionTaken, TimesliceSlot> TimesliceIndex::re } if (*newTimestamp > *oldTimestamp) { - mVariables[oldestSlot.index] = newContext; - return std::make_tuple(ActionTaken::ReplaceObsolete, oldestSlot); + switch (mBackpressurePolicy) { + case BackpressureOp::DropAncient: + mVariables[oldestSlot.index] = newContext; + return std::make_tuple(ActionTaken::ReplaceObsolete, oldestSlot); + case BackpressureOp::DropRecent: + return std::make_tuple(ActionTaken::DropObsolete, TimesliceSlot{TimesliceSlot::INVALID}); + case BackpressureOp::Wait: + return std::make_tuple(ActionTaken::Wait, TimesliceSlot{TimesliceSlot::INVALID}); + } + } else { + switch (mBackpressurePolicy) { + case BackpressureOp::DropRecent: + mVariables[oldestSlot.index] = newContext; + return std::make_tuple(ActionTaken::ReplaceObsolete, oldestSlot); + case BackpressureOp::DropAncient: + return std::make_tuple(ActionTaken::DropObsolete, TimesliceSlot{TimesliceSlot::INVALID}); + case BackpressureOp::Wait: + return std::make_tuple(ActionTaken::Wait, TimesliceSlot{TimesliceSlot::INVALID}); + } } - return std::make_tuple(ActionTaken::DropObsolete, TimesliceSlot{TimesliceSlot::INVALID}); + O2_BUILTIN_UNREACHABLE(); } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/include/Framework/TimingInfo.h b/Framework/Core/include/Framework/TimingInfo.h index 74ed67b19c270..39d2fd52c480c 100644 --- a/Framework/Core/include/Framework/TimingInfo.h +++ b/Framework/Core/include/Framework/TimingInfo.h @@ -1,22 +1,27 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_TIMINGINFO_H -#define FRAMEWORK_TIMINGINFO_H +#ifndef O2_FRAMEWORK_TIMINGINFO_H_ +#define O2_FRAMEWORK_TIMINGINFO_H_ #include <cstddef> +#include <cstdint> /// This class holds the information about timing /// of the messages being processed. struct TimingInfo { size_t timeslice; /// the timeslice associated to current processing + uint32_t firstTFOrbit = -1; /// the orbit the TF begins + uint32_t tfCounter = -1; // the counter associated to a TF + uint32_t runNumber = -1; }; -#endif // Timing information for the current computation +#endif // O2_FRAMEWORK_TIMINGINFO_H_ diff --git a/Framework/Core/include/Framework/TopologyPolicy.h b/Framework/Core/include/Framework/TopologyPolicy.h new file mode 100644 index 0000000000000..14e5aca775ec1 --- /dev/null +++ b/Framework/Core/include/Framework/TopologyPolicy.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_TOPOLOGYPOLICY_H_ +#define O2_FRAMEWORK_TOPOLOGYPOLICY_H_ + +#include <functional> +#include <vector> + +namespace o2::framework +{ +struct DataProcessorSpec; + +struct TopologyPolicy { + using DataProcessorMatcher = std::function<bool(DataProcessorSpec const& device)>; + using DependencyChecker = std::function<bool(DataProcessorSpec const& dependent, DataProcessorSpec const& ascendant)>; + DataProcessorMatcher matcher; + DependencyChecker checkDependency; + static std::vector<TopologyPolicy> createDefaultPolicies(); +}; + +} // namespace o2::framework +#endif // O2_FRAMEWORK_TOPOLOGYPOLICY_H_ diff --git a/Framework/Core/include/Framework/TypeTraits.h b/Framework/Core/include/Framework/TypeTraits.h index 7837efcb83e06..844402f445428 100644 --- a/Framework/Core/include/Framework/TypeTraits.h +++ b/Framework/Core/include/Framework/TypeTraits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -220,38 +221,5 @@ struct is_boost_serializable<Type, boost::archive::binary_oarchive, std::void_t< : is_boost_serializable<typename Type::value_type, boost::archive::binary_oarchive> { }; -/// Helper to get the corresponding std::function type for a callable object -/// the default is void -template <typename T> -struct get_function { - using type = void; -}; - -/// the matching specialization builds the function type from the return type -/// and types in the argument pack -template <typename Ret, typename Class, typename... Args> -struct get_function<Ret (Class::*)(Args...) const> { - using type = std::function<Ret(Args...)>; -}; - -/// check if a lambda can be assigned to concrete std::function -/// default is false -template <typename From, typename To, typename _ = void> -struct can_assign : public std::false_type { -}; - -/// specialize for callable types, i.e. having operator(), the 'From' type can be -/// assigned if its corresponding function type is the same as 'To' type -/// a direct comparison is not possible because lambdas are their own type -template <typename From, typename To> -struct can_assign< - From, To, - std::conditional_t< - false, - class_member_checker< - decltype(&From::operator())>, - void>> : public std::is_same<typename get_function<decltype(&From::operator())>::type, To> { -}; - } // namespace o2::framework #endif // FRAMEWORK_TYPETRAITS_H diff --git a/Framework/Core/include/Framework/VariableContextHelpers.h b/Framework/Core/include/Framework/VariableContextHelpers.h new file mode 100644 index 0000000000000..85ffb9c9ea561 --- /dev/null +++ b/Framework/Core/include/Framework/VariableContextHelpers.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DATADESCRIPTORMATCHER_H_ +#define O2_FRAMEWORK_DATADESCRIPTORMATCHER_H_ + +#include "Framework/DataDescriptorMatcher.h" +#include <variant> + +namespace o2::framework +{ + +/// Helpers to fetch common variables +struct VariableContextHelpers { + static inline uint32_t getFirstTFOrbit(data_matcher::VariableContext const& variables) + { + // tfCounter is always at register 14 + auto pval = std::get_if<uint32_t>(&variables.get(data_matcher::FIRSTTFORBIT_POS)); + if (pval == nullptr) { + return -1; + } + return *pval; + } + + static inline TimesliceId getTimeslice(data_matcher::VariableContext const& variables) + { + // timeslice is always at register 0 + auto pval = std::get_if<uint64_t>(&variables.get(data_matcher::STARTTIME_POS)); + if (pval == nullptr) { + return TimesliceId{TimesliceId::INVALID}; + } + return TimesliceId{*pval}; + } + + static inline uint32_t getRunNumber(data_matcher::VariableContext const& variables) + { + // firstTForbit is always at register 15 + auto pval = std::get_if<uint32_t>(&variables.get(data_matcher::RUNNUMBER_POS)); + if (pval == nullptr) { + return -1; + } + return *pval; + } + + static inline uint32_t getFirstTFCounter(data_matcher::VariableContext const& variables) + { + // tfCounter is always at register 14 + auto pval = std::get_if<uint32_t>(&variables.get(data_matcher::TFCOUNTER_POS)); + if (pval == nullptr) { + return -1; + } + return *pval; + } +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DATADESCRIPTORMATCHER_H_ diff --git a/Framework/Core/include/Framework/Variant.h b/Framework/Core/include/Framework/Variant.h index f14b2c99ffeb7..cff20ab6bb752 100644 --- a/Framework/Core/include/Framework/Variant.h +++ b/Framework/Core/include/Framework/Variant.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define FRAMEWORK_VARIANT_H #include "Framework/RuntimeError.h" +#include "Framework/Array2D.h" #include <type_traits> #include <cstring> #include <cstdint> @@ -21,11 +23,10 @@ #include <vector> #include <string> -namespace o2 -{ -namespace framework +namespace o2::framework { +// Do NOT insert entries in this enum, only append at the end (before "Empty"). Hyperloop depends on the order. enum class VariantType : int { Int = 0, Int64, Float, @@ -36,9 +37,60 @@ enum class VariantType : int { Int = 0, ArrayFloat, ArrayDouble, ArrayBool, + ArrayString, + Array2DInt, + Array2DFloat, + Array2DDouble, + LabeledArrayInt, + LabeledArrayFloat, + LabeledArrayDouble, + UInt8, + UInt16, + UInt32, + UInt64, Empty, Unknown }; +template <VariantType V> +constexpr auto isArray() +{ + return (V == VariantType::ArrayBool || + V == VariantType::ArrayDouble || + V == VariantType::ArrayFloat || + V == VariantType::ArrayInt || + V == VariantType::ArrayString); +} + +template <VariantType V> +constexpr auto isArray2D() +{ + return (V == VariantType::Array2DInt || + V == VariantType::Array2DFloat || + V == VariantType::Array2DDouble); +} + +template <VariantType V> +constexpr auto isLabeledArray() +{ + return (V == VariantType::LabeledArrayInt || + V == VariantType::LabeledArrayFloat || + V == VariantType::LabeledArrayDouble); +} + +template <VariantType V> +constexpr auto isSimpleVariant() +{ + return (V == VariantType::Int) || + (V == VariantType::Int64) || + (V == VariantType::UInt8) || + (V == VariantType::UInt16) || + (V == VariantType::UInt32) || + (V == VariantType::UInt64) || + (V == VariantType::Float) || + (V == VariantType::Double) || + (V == VariantType::Bool); +} + template <typename T> struct variant_trait : std::integral_constant<VariantType, VariantType::Unknown> { }; @@ -51,19 +103,71 @@ struct variant_trait : std::integral_constant<VariantType, VariantType::Unknown> DECLARE_VARIANT_TRAIT(int, Int); DECLARE_VARIANT_TRAIT(long int, Int64); DECLARE_VARIANT_TRAIT(long long int, Int64); +DECLARE_VARIANT_TRAIT(uint8_t, UInt8); +DECLARE_VARIANT_TRAIT(uint16_t, UInt16); +DECLARE_VARIANT_TRAIT(uint32_t, UInt32); +DECLARE_VARIANT_TRAIT(uint64_t, UInt64); + DECLARE_VARIANT_TRAIT(float, Float); DECLARE_VARIANT_TRAIT(double, Double); +DECLARE_VARIANT_TRAIT(bool, Bool); + DECLARE_VARIANT_TRAIT(const char*, String); DECLARE_VARIANT_TRAIT(char*, String); DECLARE_VARIANT_TRAIT(char* const, String); DECLARE_VARIANT_TRAIT(const char* const, String); DECLARE_VARIANT_TRAIT(std::string_view, String); DECLARE_VARIANT_TRAIT(std::string, String); -DECLARE_VARIANT_TRAIT(bool, Bool); + DECLARE_VARIANT_TRAIT(int*, ArrayInt); DECLARE_VARIANT_TRAIT(float*, ArrayFloat); DECLARE_VARIANT_TRAIT(double*, ArrayDouble); DECLARE_VARIANT_TRAIT(bool*, ArrayBool); +DECLARE_VARIANT_TRAIT(std::string*, ArrayString); + +DECLARE_VARIANT_TRAIT(std::vector<int>, ArrayInt); +DECLARE_VARIANT_TRAIT(std::vector<float>, ArrayFloat); +DECLARE_VARIANT_TRAIT(std::vector<double>, ArrayDouble); +DECLARE_VARIANT_TRAIT(std::vector<bool>, ArrayBool); +DECLARE_VARIANT_TRAIT(std::vector<std::string>, ArrayString); + +DECLARE_VARIANT_TRAIT(Array2D<int>, Array2DInt); +DECLARE_VARIANT_TRAIT(Array2D<float>, Array2DFloat); +DECLARE_VARIANT_TRAIT(Array2D<double>, Array2DDouble); + +DECLARE_VARIANT_TRAIT(LabeledArray<int>, LabeledArrayInt); +DECLARE_VARIANT_TRAIT(LabeledArray<float>, LabeledArrayFloat); +DECLARE_VARIANT_TRAIT(LabeledArray<double>, LabeledArrayDouble); + +template <typename T> +struct variant_array_symbol { + constexpr static char symbol = 'u'; +}; + +template <> +struct variant_array_symbol<int> { + constexpr static char symbol = 'i'; +}; + +template <> +struct variant_array_symbol<float> { + constexpr static char symbol = 'f'; +}; + +template <> +struct variant_array_symbol<double> { + constexpr static char symbol = 'd'; +}; + +template <> +struct variant_array_symbol<bool> { + constexpr static char symbol = 'b'; +}; + +template <> +struct variant_array_symbol<std::string> { + constexpr static char symbol = 's'; +}; template <typename T> inline constexpr VariantType variant_trait_v = variant_trait<T>::value; @@ -80,25 +184,65 @@ struct variant_type { DECLARE_VARIANT_TYPE(int, Int); DECLARE_VARIANT_TYPE(int64_t, Int64); +DECLARE_VARIANT_TYPE(uint8_t, UInt8); +DECLARE_VARIANT_TYPE(uint16_t, UInt16); +DECLARE_VARIANT_TYPE(uint32_t, UInt32); +DECLARE_VARIANT_TYPE(uint64_t, UInt64); DECLARE_VARIANT_TYPE(float, Float); DECLARE_VARIANT_TYPE(double, Double); DECLARE_VARIANT_TYPE(const char*, String); DECLARE_VARIANT_TYPE(bool, Bool); + DECLARE_VARIANT_TYPE(int*, ArrayInt); DECLARE_VARIANT_TYPE(float*, ArrayFloat); DECLARE_VARIANT_TYPE(double*, ArrayDouble); DECLARE_VARIANT_TYPE(bool*, ArrayBool); +DECLARE_VARIANT_TYPE(std::string*, ArrayString); + +DECLARE_VARIANT_TYPE(Array2D<int>, Array2DInt); +DECLARE_VARIANT_TYPE(Array2D<float>, Array2DFloat); +DECLARE_VARIANT_TYPE(Array2D<double>, Array2DDouble); + +DECLARE_VARIANT_TYPE(LabeledArray<int>, LabeledArrayInt); +DECLARE_VARIANT_TYPE(LabeledArray<float>, LabeledArrayFloat); +DECLARE_VARIANT_TYPE(LabeledArray<double>, LabeledArrayDouble); + +template <VariantType type> +struct variant_array_element_type { +}; + +#define DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(_Type1_, _Type2_) \ + template <> \ + struct variant_array_element_type<VariantType::_Type2_> { \ + using type = _Type1_; \ + }; + +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, ArrayInt); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, Array2DInt); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, ArrayFloat); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, Array2DFloat); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, ArrayDouble); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, Array2DDouble); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(bool, ArrayBool); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, ArrayString); + +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, LabeledArrayInt); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, LabeledArrayFloat); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, LabeledArrayDouble); + +template <VariantType V> +using variant_array_element_type_t = typename variant_array_element_type<V>::type; template <typename S, typename T> struct variant_helper { - static void set(S* store, T value) { *(reinterpret_cast<T*>(store)) = value; } - static void set(S* store, T values, size_t size) + static void set(S* store, T value) { - *reinterpret_cast<T*>(store) = reinterpret_cast<T>(std::memcpy(std::malloc(size * sizeof(std::remove_pointer_t<T>)), reinterpret_cast<void*>(values), size * sizeof(std::remove_pointer_t<T>))); + new (reinterpret_cast<T*>(store)) T{}; + *(reinterpret_cast<T*>(store)) = value; } - static void reset(S* store, T values, size_t) + static void set(S* store, T values, size_t size) { - *reinterpret_cast<T*>(store) = values; + *reinterpret_cast<T*>(store) = reinterpret_cast<T>(std::memcpy(std::malloc(size * sizeof(std::remove_pointer_t<T>)), reinterpret_cast<void*>(values), size * sizeof(std::remove_pointer_t<T>))); } static T get(const S* store) { return *(reinterpret_cast<const T*>(store)); } @@ -128,7 +272,11 @@ struct variant_helper<S, std::string> { /// Variant for configuration parameter storage. Owns stored data. class Variant { - using storage_t = std::aligned_union<8, int, int64_t, const char*, float, double, bool, int*, float*, double*, bool*>::type; + using storage_t = std::aligned_union<8, int, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, + const char*, float, double, bool, + int*, float*, double*, bool*, + Array2D<int>, Array2D<float>, Array2D<double>, + LabeledArray<int>, LabeledArray<float>, LabeledArray<double>>::type; public: Variant(VariantType type = VariantType::Unknown) : mType{type}, mSize{1} {} @@ -159,109 +307,11 @@ class Variant "\n did you accidentally put braces around the default value?"); } - Variant(const Variant& other) : mType(other.mType) - { - // In case this is an array we need to duplicate it to avoid - // double deletion. - switch (mType) { - case variant_trait_v<const char*>: - mSize = other.mSize; - variant_helper<storage_t, const char*>::set(&mStore, other.get<const char*>()); - return; - case variant_trait_v<int*>: - mSize = other.mSize; - variant_helper<storage_t, int*>::set(&mStore, other.get<int*>(), mSize); - return; - case variant_trait_v<float*>: - mSize = other.mSize; - variant_helper<storage_t, float*>::set(&mStore, other.get<float*>(), mSize); - return; - case variant_trait_v<double*>: - mSize = other.mSize; - variant_helper<storage_t, double*>::set(&mStore, other.get<double*>(), mSize); - return; - case variant_trait_v<bool*>: - mSize = other.mSize; - variant_helper<storage_t, bool*>::set(&mStore, other.get<bool*>(), mSize); - return; - default: - mStore = other.mStore; - mSize = other.mSize; - } - } - - Variant(Variant&& other) : mType(other.mType) - { - mStore = other.mStore; - mSize = other.mSize; - switch (mType) { - case variant_trait_v<const char*>: - *reinterpret_cast<char**>(&(other.mStore)) = nullptr; - return; - case variant_trait_v<int*>: - *reinterpret_cast<int**>(&(other.mStore)) = nullptr; - return; - case variant_trait_v<float*>: - *reinterpret_cast<float**>(&(other.mStore)) = nullptr; - return; - case variant_trait_v<double*>: - *reinterpret_cast<double**>(&(other.mStore)) = nullptr; - return; - case variant_trait_v<bool*>: - *reinterpret_cast<bool**>(&(other.mStore)) = nullptr; - return; - default: - return; - } - } - - ~Variant() - { - // In case we allocated an array, we - // should delete it. - switch (mType) { - case variant_trait_v<const char*>: - case variant_trait_v<int*>: - case variant_trait_v<float*>: - case variant_trait_v<double*>: - case variant_trait_v<bool*>: - if (reinterpret_cast<void**>(&mStore) != nullptr) { - free(*reinterpret_cast<void**>(&mStore)); - } - return; - default: - return; - } - } - - void operator=(const Variant& other) - { - switch (mType) { - case variant_trait_v<const char*>: - mSize = other.mSize; - variant_helper<storage_t, const char*>::set(&mStore, other.get<const char*>()); - return; - case variant_trait_v<int*>: - mSize = other.mSize; - variant_helper<storage_t, int*>::set(&mStore, other.get<int*>(), mSize); - return; - case variant_trait_v<float*>: - mSize = other.mSize; - variant_helper<storage_t, float*>::set(&mStore, other.get<float*>(), mSize); - return; - case variant_trait_v<double*>: - mSize = other.mSize; - variant_helper<storage_t, double*>::set(&mStore, other.get<double*>(), mSize); - return; - case variant_trait_v<bool*>: - mSize = other.mSize; - variant_helper<storage_t, bool*>::set(&mStore, other.get<bool*>(), mSize); - return; - default: - mStore = other.mStore; - mSize = other.mSize; - } - } + Variant(const Variant& other); + Variant(Variant&& other) noexcept; + ~Variant(); + Variant& operator=(const Variant& other); + Variant& operator=(Variant&& other) noexcept; template <typename T> T get() const @@ -293,6 +343,7 @@ class Variant VariantType type() const { return mType; } size_t size() const { return mSize; } + std::string asString() const; private: friend std::ostream& operator<<(std::ostream& oss, Variant const& val); @@ -301,7 +352,6 @@ class Variant size_t mSize = 1; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif diff --git a/Framework/Core/include/Framework/VariantJSONHelpers.h b/Framework/Core/include/Framework/VariantJSONHelpers.h new file mode 100644 index 0000000000000..4585ff787ee57 --- /dev/null +++ b/Framework/Core/include/Framework/VariantJSONHelpers.h @@ -0,0 +1,445 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_VARIANTJSONHELPERS_H +#define FRAMEWORK_VARIANTJSONHELPERS_H + +#include "Framework/Variant.h" + +#include <rapidjson/reader.h> +#include <rapidjson/prettywriter.h> +#include <rapidjson/istreamwrapper.h> +#include <rapidjson/ostreamwrapper.h> +#include <rapidjson/error/en.h> + +#include <stack> +#include <iostream> +#include <sstream> + +namespace o2::framework +{ +namespace +{ +template <VariantType V> +struct VariantReader : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, VariantReader<V>> { + using Ch = rapidjson::UTF8<>::Ch; + using SizeType = rapidjson::SizeType; + + enum struct State { + IN_START, + IN_STOP, + IN_DATA, + IN_KEY, + IN_ARRAY, + IN_ROW, + IN_ERROR + }; + + VariantReader() + : states{}, + rows{0}, + cols{0} + { + debug << "Start" << std::endl; + states.push(State::IN_START); + } + + bool Null() + { + debug << "Null value encountered" << std::endl; + return true; + } + + bool Int(int i) + { + debug << "Int(" << i << ")" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if constexpr (!std::is_same_v<int, variant_array_element_type_t<V>>) { + states.push(State::IN_ERROR); + return true; + } else { + if (states.top() == State::IN_ARRAY || states.top() == State::IN_ROW) { + debug << "added to array" << std::endl; + accumulatedData.push_back(i); + return true; + } + } + states.push(State::IN_ERROR); + return true; + } + + bool Uint(unsigned i) + { + debug << "Uint -> Int" << std::endl; + return Int(static_cast<int>(i)); + } + + bool Int64(int64_t i) + { + debug << "Int64 -> Int" << std::endl; + return Int(static_cast<int>(i)); + } + + bool Uint64(uint64_t i) + { + debug << "Uint64 -> Int" << std::endl; + return Int(static_cast<int>(i)); + } + + bool Double(double d) + { + debug << "Double(" << d << ")" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if constexpr (!(std::is_same_v<float, variant_array_element_type_t<V>> || std::is_same_v<double, variant_array_element_type_t<V>>)) { + states.push(State::IN_ERROR); + return true; + } + if (states.top() == State::IN_ARRAY || states.top() == State::IN_ROW) { + if constexpr (std::is_same_v<double, variant_array_element_type_t<V>>) { + debug << "added to array as double" << std::endl; + accumulatedData.push_back(d); + return true; + } else if constexpr (std::is_same_v<float, variant_array_element_type_t<V>>) { + debug << "added to array as float" << std::endl; + accumulatedData.push_back(static_cast<float>(d)); + return true; + } + } + states.push(State::IN_ERROR); + return true; + } + + bool Bool(bool b) + { + debug << "Bool(" << b << ")" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if constexpr (!std::is_same_v<bool, variant_array_element_type_t<V>>) { + states.push(State::IN_ERROR); + return false; + } else { + if (states.top() == State::IN_ARRAY) { + debug << "added to array" << std::endl; + accumulatedData.push_back(b); + return true; + } + states.push(State::IN_ERROR); + return true; + } + } + + bool String(const Ch* str, SizeType, bool) + { + debug << "String(" << str << ")" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if constexpr (!(V == VariantType::ArrayString || isLabeledArray<V>())) { + states.push(State::IN_ERROR); + return true; + } else { + if (states.top() == State::IN_ARRAY) { + debug << "added to array" << std::endl; + if constexpr (isLabeledArray<V>()) { + if (currentKey == labels_rows_str) { + labels_rows.push_back(str); + return true; + } else if (currentKey == labels_cols_str) { + labels_cols.push_back(str); + return true; + } else { + states.push(State::IN_ERROR); + return true; + } + } else { + accumulatedData.push_back(str); + } + return true; + } + states.push(State::IN_ERROR); + return true; + } + } + + bool StartObject() + { + debug << "StartObject()" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if (states.top() == State::IN_START) { + states.push(State::IN_DATA); + return true; + } + states.push(State::IN_ERROR); + return true; + } + + bool Key(const Ch* str, SizeType, bool) + { + debug << "Key(" << str << ")" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + currentKey = str; + return false; + } + if (states.top() == State::IN_DATA) { + //no previous keys + states.push(State::IN_KEY); + currentKey = str; + return true; + } + if (states.top() == State::IN_KEY) { + currentKey = str; + if constexpr (!isLabeledArray<V>()) { + debug << "extra keys in a single-key variant" << std::endl; + states.push(State::IN_ERROR); + return true; + } + return true; + } + currentKey = str; + states.push(State::IN_ERROR); + return true; + } + + bool EndObject(SizeType) + { + debug << "EndObject()" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if (states.top() == State::IN_KEY) { + if constexpr (isArray<V>()) { + debug << "creating 1d-array variant" << std::endl; + result = Variant(accumulatedData); + } else if constexpr (isArray2D<V>()) { + debug << "creating 2d-array variant" << std::endl; + assert(accumulatedData.size() == rows * cols); + result = Variant(Array2D{accumulatedData, rows, cols}); + } else if constexpr (isLabeledArray<V>()) { + debug << "creating labeled array variant" << std::endl; + assert(accumulatedData.size() == rows * cols); + if (labels_rows.empty() == false) { + assert(labels_rows.size() == rows); + } + if (labels_cols.empty() == false) { + assert(labels_cols.size() == cols); + } + result = Variant(LabeledArray{Array2D{accumulatedData, rows, cols}, labels_rows, labels_cols}); + } + states.push(State::IN_STOP); + return true; + } + states.push(State::IN_ERROR); + return true; + } + + bool StartArray() + { + debug << "StartArray()" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if (states.top() == State::IN_KEY) { + states.push(State::IN_ARRAY); + return true; + } else if (states.top() == State::IN_ARRAY) { + if constexpr (isArray2D<V>() || isLabeledArray<V>()) { + states.push(State::IN_ROW); + return true; + } + } + states.push(State::IN_ERROR); + return true; + } + + bool EndArray(SizeType elementCount) + { + debug << "EndArray()" << std::endl; + if (states.top() == State::IN_ERROR) { + debug << "In ERROR state" << std::endl; + return false; + } + if (states.top() == State::IN_ARRAY) { + //finish up array + states.pop(); + if constexpr (isArray2D<V>() || isLabeledArray<V>()) { + rows = elementCount; + } + return true; + } else if (states.top() == State::IN_ROW) { + //finish up row + states.pop(); + if constexpr (isArray2D<V>() || isLabeledArray<V>()) { + cols = elementCount; + } + return true; + } + states.push(State::IN_ERROR); + return true; + } + + std::stack<State> states; + std::ostringstream debug; + + uint32_t rows; + uint32_t cols; + std::string currentKey; + std::vector<variant_array_element_type_t<V>> accumulatedData; + std::vector<std::string> labels_rows; + std::vector<std::string> labels_cols; + Variant result; +}; + +template <VariantType V> +void writeVariant(std::ostream& o, Variant const& v) +{ + if constexpr (isArray<V>() || isArray2D<V>() || isLabeledArray<V>()) { + using type = variant_array_element_type_t<V>; + rapidjson::OStreamWrapper osw(o); + rapidjson::Writer<rapidjson::OStreamWrapper> w(osw); + + auto writeArray = [&](auto* values, size_t size) { + using T = std::remove_pointer_t<decltype(values)>; + w.StartArray(); + for (auto i = 0u; i < size; ++i) { + if constexpr (std::is_same_v<int, T>) { + w.Int(values[i]); + } else if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>) { + w.Double(values[i]); + } else if constexpr (std::is_same_v<bool, T>) { + w.Bool(values[i]); + } else if constexpr (std::is_same_v<std::string, T>) { + w.String(values[i].c_str()); + } + } + w.EndArray(); + }; + + auto writeVector = [&](auto&& vector) { + return writeArray(vector.data(), vector.size()); + }; + + auto writeArray2D = [&](auto&& array2d) { + using T = typename std::decay_t<decltype(array2d)>::element_t; + w.StartArray(); + for (auto i = 0u; i < array2d.rows; ++i) { + w.StartArray(); + for (auto j = 0u; j < array2d.cols; ++j) { + if constexpr (std::is_same_v<int, T>) { + w.Int(array2d(i, j)); + } else if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>) { + w.Double(array2d(i, j)); + } + } + w.EndArray(); + } + w.EndArray(); + }; + + auto writeLabeledArray = [&](auto&& array) { + w.Key(labels_rows_str); + writeVector(array.getLabelsRows()); + w.Key(labels_cols_str); + writeVector(array.getLabelsCols()); + w.Key("values"); + writeArray2D(array.getData()); + }; + + w.StartObject(); + if constexpr (isArray<V>()) { + w.Key("values"); + writeArray(v.get<type*>(), v.size()); + } else if constexpr (isArray2D<V>()) { + w.Key("values"); + writeArray2D(v.get<Array2D<type>>()); + } else if constexpr (isLabeledArray<V>()) { + writeLabeledArray(v.get<LabeledArray<type>>()); + } + w.EndObject(); + } +} +} // namespace + +struct VariantJSONHelpers { + template <VariantType V> + static Variant read(std::istream& s) + { + rapidjson::Reader reader; + rapidjson::IStreamWrapper isw(s); + VariantReader<V> vreader; + bool ok = reader.Parse(isw, vreader); + + if (ok == false) { + std::stringstream error; + error << "Cannot parse serialized Variant, error: " << rapidjson::GetParseError_En(reader.GetParseErrorCode()) << " at offset: " << reader.GetErrorOffset(); + throw std::runtime_error(error.str()); + } + return vreader.result; + } + + static void write(std::ostream& o, Variant const& v) + { + switch (v.type()) { + case VariantType::ArrayInt: + writeVariant<VariantType::ArrayInt>(o, v); + break; + case VariantType::ArrayFloat: + writeVariant<VariantType::ArrayFloat>(o, v); + break; + case VariantType::ArrayDouble: + writeVariant<VariantType::ArrayDouble>(o, v); + break; + case VariantType::ArrayBool: + throw std::runtime_error("Bool vectors not implemented yet"); + // writeVariant<VariantType::ArrayBool>(o, v); + break; + case VariantType::ArrayString: + writeVariant<VariantType::ArrayString>(o, v); + break; + case VariantType::Array2DInt: + writeVariant<VariantType::Array2DInt>(o, v); + break; + case VariantType::Array2DFloat: + writeVariant<VariantType::Array2DFloat>(o, v); + break; + case VariantType::Array2DDouble: + writeVariant<VariantType::Array2DDouble>(o, v); + break; + case VariantType::LabeledArrayInt: + writeVariant<VariantType::LabeledArrayInt>(o, v); + break; + case VariantType::LabeledArrayFloat: + writeVariant<VariantType::LabeledArrayFloat>(o, v); + break; + case VariantType::LabeledArrayDouble: + writeVariant<VariantType::LabeledArrayDouble>(o, v); + break; + default: + break; + } + } +}; +} + +#endif // FRAMEWORK_VARIANTJSONHELPERS_H diff --git a/Framework/Core/include/Framework/VariantPropertyTreeHelpers.h b/Framework/Core/include/Framework/VariantPropertyTreeHelpers.h new file mode 100644 index 0000000000000..484501a18991e --- /dev/null +++ b/Framework/Core/include/Framework/VariantPropertyTreeHelpers.h @@ -0,0 +1,156 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_VARIANTPTREEHELPERS_H +#define FRAMEWORK_VARIANTPTREEHELPERS_H + +#include "Framework/Variant.h" +#include <boost/property_tree/ptree.hpp> + +namespace o2::framework +{ +namespace +{ +template <typename T> +auto basicVectorToBranch(T* values, size_t size) +{ + boost::property_tree::ptree branch; + for (auto i = 0u; i < size; ++i) { + boost::property_tree::ptree leaf; + leaf.put("", values[i]); + branch.push_back(std::make_pair("", leaf)); + } + return branch; +} + +template <typename T> +auto basicVectorToBranch(std::vector<T>&& values) +{ + return basicVectorToBranch(values.data(), values.size()); +} + +template <typename T> +auto vectorToBranch(T* values, size_t size) +{ + boost::property_tree::ptree branch; + branch.put_child("values", basicVectorToBranch(values, size)); + return branch; +} +} // namespace + +template <typename T> +auto vectorToBranch(std::vector<T>&& values) +{ + return vectorToBranch(values.data(), values.size()); +} + +namespace +{ +template <typename T> +auto basicArray2DToBranch(Array2D<T>&& array) +{ + boost::property_tree::ptree subtree; + for (auto i = 0u; i < array.rows; ++i) { + boost::property_tree::ptree branch; + for (auto j = 0u; j < array.cols; ++j) { + boost::property_tree::ptree leaf; + leaf.put("", array(i, j)); + branch.push_back(std::make_pair("", leaf)); + } + subtree.push_back(std::make_pair("", branch)); + } + return subtree; +} +} // namespace + +template <typename T> +auto array2DToBranch(Array2D<T>&& array) +{ + boost::property_tree::ptree subtree; + subtree.put_child("values", basicArray2DToBranch(std::forward<Array2D<T>>(array))); + return subtree; +} + +namespace +{ +template <typename T> +auto basicVectorFromBranch(boost::property_tree::ptree const& branch) +{ + std::vector<T> result(branch.size()); + auto count = 0U; + for (auto const& entry : branch) { + result[count++] = entry.second.get_value<T>(); + } + return result; +} +} // namespace + +template <typename T> +auto vectorFromBranch(boost::property_tree::ptree const& branch) +{ + return basicVectorFromBranch<T>(branch.get_child("values")); +} + +namespace +{ +template <typename T> +auto basicArray2DFromBranch(boost::property_tree::ptree const& branch) +{ + std::vector<T> cache; + uint32_t nrows = branch.size(); + uint32_t ncols = 0; + bool first = true; + auto irow = 0u; + for (auto const& row : branch) { + if (first) { + ncols = row.second.size(); + first = false; + } + auto icol = 0u; + for (auto const& entry : row.second) { + cache.push_back(entry.second.get_value<T>()); + ++icol; + } + ++irow; + } + return Array2D<T>{cache, nrows, ncols}; +} +} // namespace + +template <typename T> +auto array2DFromBranch(boost::property_tree::ptree const& ptree) +{ + return basicArray2DFromBranch<T>(ptree.get_child("values")); +} + +std::pair<std::vector<std::string>, std::vector<std::string>> extractLabels(boost::property_tree::ptree const& tree); + +template <typename T> +auto labeledArrayFromBranch(boost::property_tree::ptree const& tree) +{ + auto [labels_rows, labels_cols] = extractLabels(tree); + auto values = basicArray2DFromBranch<T>(tree.get_child("values")); + + return LabeledArray<T>{values, labels_rows, labels_cols}; +} + +template <typename T> +auto labeledArrayToBranch(LabeledArray<T>&& array) +{ + boost::property_tree::ptree subtree; + subtree.put_child(labels_rows_str, basicVectorToBranch(array.getLabelsRows())); + subtree.put_child(labels_cols_str, basicVectorToBranch(array.getLabelsCols())); + subtree.put_child("values", basicArray2DToBranch(array.getData())); + + return subtree; +} +} // namespace o2::framework + +#endif // FRAMEWORK_VARIANTPTREEHELPERS_H diff --git a/Framework/Core/include/Framework/VariantStringHelpers.h b/Framework/Core/include/Framework/VariantStringHelpers.h new file mode 100644 index 0000000000000..63270167544df --- /dev/null +++ b/Framework/Core/include/Framework/VariantStringHelpers.h @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_VARIANTSTRINGHELPERS_H +#define FRAMEWORK_VARIANTSTRINGHELPERS_H + +#include "Framework/Variant.h" +#include <regex> + +namespace o2::framework +{ + +template <typename T> +T lexical_cast(std::string const& input) +{ + if constexpr (std::is_same_v<T, int>) { + return std::stoi(input, nullptr); + } else if constexpr (std::is_same_v<T, int64_t>) { + return std::stol(input, nullptr); + } else if constexpr (std::is_same_v<T, float>) { + return std::stof(input, nullptr); + } else if constexpr (std::is_same_v<T, double>) { + return std::stod(input, nullptr); + } else if constexpr (std::is_same_v<T, bool>) { + return static_cast<bool>(std::stoi(input, nullptr)); + } +} + +template <typename T> +std::vector<T> stringToVector(std::string const& input) +{ + std::vector<T> result; + //check if the array string has correct array type symbol + assert(input[0] == variant_array_symbol<T>::symbol); + std::regex nmatch(R"((?:(?!=,)|(?!=\[))[+-]?\d+\.?\d*(?:[eE][+-]?\d+)?(?=,|\]))"); + auto end = std::sregex_iterator(); + auto values = std::sregex_iterator(input.begin(), input.end(), nmatch); + for (auto& v = values; v != end; ++v) { + result.push_back(lexical_cast<T>(v->str())); + } + return result; +} + +template <> +std::vector<std::string> stringToVector(std::string const& input) +{ + std::vector<std::string> result; + //check if the array string has correct array type symbol + assert(input[0] == variant_array_symbol<std::string>::symbol); + std::regex smatch(R"((?:(?!=,)|(?!=\[))\w+(?=,|\]))"); + auto end = std::sregex_iterator(); + auto values = std::sregex_iterator(input.begin(), input.end(), smatch); + for (auto v = values; v != end; ++v) { + result.push_back(v->str()); + } + return result; +} + +template <typename T> +Array2D<T> stringToArray2D(std::string const& input) +{ + std::vector<T> cache; + assert(input[0] == variant_array_symbol<T>::symbol); + std::regex mrows(R"(\[[^\[\]]+\])"); + std::regex marray(R"((?:(?!=,)|(?!=\[))[+-]?\d+\.?\d*(?:[eE][+-]?\d+)?(?=,|\]))"); + auto end = std::sregex_iterator(); + auto rows = std::sregex_iterator(input.begin(), input.end(), mrows); + uint32_t nrows = 0; + uint32_t ncols = 0; + bool first = true; + for (auto& row = rows; row != end; ++row) { + auto str = row->str(); + auto values = std::sregex_iterator(str.begin(), str.end(), marray); + if (first) { + ncols = 0; + } + for (auto& v = values; v != end; ++v) { + cache.push_back(lexical_cast<T>(v->str())); + if (first) { + ++ncols; + } + } + if (first) { + first = false; + } + ++nrows; + } + return Array2D<T>{cache, nrows, ncols}; +} + +} // namespace o2::framework + +#endif // FRAMEWORK_VARIANTSTRINGHELPERS_H diff --git a/Framework/Core/include/Framework/WorkflowCustomizationHelpers.h b/Framework/Core/include/Framework/WorkflowCustomizationHelpers.h new file mode 100644 index 0000000000000..9f313aae3496f --- /dev/null +++ b/Framework/Core/include/Framework/WorkflowCustomizationHelpers.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_WORKFLOWCUSTOMIZATIONHELPERS_H_ +#define O2_FRAMEWORK_WORKFLOWCUSTOMIZATIONHELPERS_H_ + +#include "Framework/ConfigParamSpec.h" +#include <vector> + +namespace o2::framework +{ + +struct WorkflowCustomizationHelpers { + static std::vector<ConfigParamSpec> requiredWorkflowOptions(); +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_WORKFLOWCUSTOMIZATIONHELPERS_H_ diff --git a/Framework/Core/include/Framework/WorkflowSpec.h b/Framework/Core/include/Framework/WorkflowSpec.h index 9620a10e7f70f..49a7c5bf11820 100644 --- a/Framework/Core/include/Framework/WorkflowSpec.h +++ b/Framework/Core/include/Framework/WorkflowSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/include/Framework/runDataProcessing.h b/Framework/Core/include/Framework/runDataProcessing.h index 853735ff13f52..7454baa3b8e1f 100644 --- a/Framework/Core/include/Framework/runDataProcessing.h +++ b/Framework/Core/include/Framework/runDataProcessing.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #include "Framework/ChannelConfigurationPolicy.h" #include "Framework/CompletionPolicy.h" +#include "Framework/ConfigurableHelpers.h" #include "Framework/DispatchPolicy.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataAllocator.h" @@ -20,9 +22,13 @@ #include "Framework/BoostOptionsRetriever.h" #include "Framework/CustomWorkflowTerminationHook.h" #include "Framework/CommonServices.h" +#include "Framework/WorkflowCustomizationHelpers.h" +#include "Framework/RuntimeError.h" +#include "Framework/ResourcePolicyHelpers.h" #include "Framework/Logger.h" +#include "Framework/CheckTypes.h" +#include "Framework/StructToTuple.h" -#include <unistd.h> #include <vector> #include <cstring> #include <exception> @@ -66,15 +72,32 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co // By default we leave the channel policies unchanged. Notice that the default still include // a "match all" policy which uses pub / sub // FIXME: add a debug statement saying that the default policy was used? + void defaultConfiguration(std::vector<o2::framework::ChannelConfigurationPolicy>& channelPolicies) {} -void defaultConfiguration(std::vector<o2::framework::ConfigParamSpec>& globalWorkflowOptions) {} +void defaultConfiguration(std::vector<o2::framework::ConfigParamSpec>& globalWorkflowOptions) +{ + o2::framework::call_if_defined<struct WorkflowOptions>([&](auto* ptr) { + ptr = new std::decay_t<decltype(*ptr)>; + o2::framework::homogeneous_apply_refs([&globalWorkflowOptions](auto what) { + return o2::framework::ConfigurableHelpers::appendOption(globalWorkflowOptions, what); + }, + *ptr); + }); +} + void defaultConfiguration(std::vector<o2::framework::CompletionPolicy>& completionPolicies) {} void defaultConfiguration(std::vector<o2::framework::DispatchPolicy>& dispatchPolicies) {} +void defaultConfiguration(std::vector<o2::framework::ResourcePolicy>& resourcePolicies) {} void defaultConfiguration(std::vector<o2::framework::ServiceSpec>& services) { - services = o2::framework::CommonServices::defaultServices(); + if (services.empty()) { + services = o2::framework::CommonServices::defaultServices(); + } } +/// Workflow options which are required by DPL in order to work. +std::vector<o2::framework::ConfigParamSpec> requiredWorkflowOptions(); + void defaultConfiguration(o2::framework::OnWorkflowTerminationHook& hook) { hook = [](const char*) {}; @@ -102,103 +125,124 @@ class ConfigContext; /// Helper used to customize a workflow pipelining options void overridePipeline(o2::framework::ConfigContext& ctx, std::vector<o2::framework::DataProcessorSpec>& workflow); +/// Helper used to customize a workflow via a template data processor +void overrideCloning(o2::framework::ConfigContext& ctx, std::vector<o2::framework::DataProcessorSpec>& workflow); + +/// Helper used to add labels to Data Processors +void overrideLabels(o2::framework::ConfigContext& ctx, std::vector<o2::framework::DataProcessorSpec>& workflow); + // This comes from the framework itself. This way we avoid code duplication. int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& specs, std::vector<o2::framework::ChannelConfigurationPolicy> const& channelPolicies, std::vector<o2::framework::CompletionPolicy> const& completionPolicies, std::vector<o2::framework::DispatchPolicy> const& dispatchPolicies, + std::vector<o2::framework::ResourcePolicy> const& resourcePolicies, std::vector<o2::framework::ConfigParamSpec> const& workflowOptions, o2::framework::ConfigContext& configContext); -void doBoostException(boost::exception& e); +void doBoostException(boost::exception& e, const char*); +void doDPLException(o2::framework::RuntimeErrorRef& ref, char const*); +void doUnknownException(std::string const& s, char const*); +void doDefaultWorkflowTerminationHook(); + +template <typename T> +std::vector<T> injectCustomizations() +{ + std::vector<T> policies; + UserCustomizationsHelper::userDefinedCustomization(policies, 0); + auto defaultPolicies = T::createDefaultPolicies(); + policies.insert(std::end(policies), std::begin(policies), std::end(policies)); +} + +int mainNoCatch(int argc, char** argv) +{ + using namespace o2::framework; + using namespace boost::program_options; + + std::vector<o2::framework::ConfigParamSpec> workflowOptions; + UserCustomizationsHelper::userDefinedCustomization(workflowOptions, 0); + auto requiredWorkflowOptions = WorkflowCustomizationHelpers::requiredWorkflowOptions(); + workflowOptions.insert(std::end(workflowOptions), std::begin(requiredWorkflowOptions), std::end(requiredWorkflowOptions)); + + std::vector<CompletionPolicy> completionPolicies; + UserCustomizationsHelper::userDefinedCustomization(completionPolicies, 0); + auto defaultCompletionPolicies = CompletionPolicy::createDefaultPolicies(); + completionPolicies.insert(std::end(completionPolicies), std::begin(defaultCompletionPolicies), std::end(defaultCompletionPolicies)); + + std::vector<DispatchPolicy> dispatchPolicies; + UserCustomizationsHelper::userDefinedCustomization(dispatchPolicies, 0); + auto defaultDispatchPolicies = DispatchPolicy::createDefaultPolicies(); + dispatchPolicies.insert(std::end(dispatchPolicies), std::begin(defaultDispatchPolicies), std::end(defaultDispatchPolicies)); + + std::vector<ResourcePolicy> resourcePolicies; + UserCustomizationsHelper::userDefinedCustomization(resourcePolicies, 0); + auto defaultResourcePolicies = ResourcePolicy::createDefaultPolicies(); + resourcePolicies.insert(std::end(resourcePolicies), std::begin(defaultResourcePolicies), std::end(defaultResourcePolicies)); + + std::vector<std::unique_ptr<ParamRetriever>> retrievers; + std::unique_ptr<ParamRetriever> retriever{new BoostOptionsRetriever(true, argc, argv)}; + retrievers.emplace_back(std::move(retriever)); + auto workflowOptionsStore = std::make_unique<ConfigParamStore>(workflowOptions, std::move(retrievers)); + workflowOptionsStore->preload(); + workflowOptionsStore->activate(); + ConfigParamRegistry workflowOptionsRegistry(std::move(workflowOptionsStore)); + ConfigContext configContext(workflowOptionsRegistry, argc, argv); + o2::framework::WorkflowSpec specs = defineDataProcessing(configContext); + overrideCloning(configContext, specs); + overridePipeline(configContext, specs); + overrideLabels(configContext, specs); + for (auto& spec : specs) { + UserCustomizationsHelper::userDefinedCustomization(spec.requiredServices, 0); + } + std::vector<ChannelConfigurationPolicy> channelPolicies; + UserCustomizationsHelper::userDefinedCustomization(channelPolicies, 0); + auto defaultChannelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(configContext); + channelPolicies.insert(std::end(channelPolicies), std::begin(defaultChannelPolicies), std::end(defaultChannelPolicies)); + return doMain(argc, argv, specs, channelPolicies, completionPolicies, dispatchPolicies, resourcePolicies, workflowOptions, configContext); +} int main(int argc, char** argv) { using namespace o2::framework; using namespace boost::program_options; + static bool noCatch = getenv("O2_NO_CATCHALL_EXCEPTIONS") && strcmp(getenv("O2_NO_CATCHALL_EXCEPTIONS"), "0"); int result = 1; - try { - // The 0 here is an int, therefore having the template matching in the - // SFINAE expression above fit better the version which invokes user code over - // the default one. - // The default policy is a catch all pub/sub setup to be consistent with the past. - std::vector<o2::framework::ConfigParamSpec> workflowOptions; - UserCustomizationsHelper::userDefinedCustomization(workflowOptions, 0); - workflowOptions.push_back(ConfigParamSpec{"readers", VariantType::Int64, 1ll, {"number of parallel readers to use"}}); - workflowOptions.push_back(ConfigParamSpec{"pipeline", VariantType::String, "", {"override default pipeline size"}}); - - // options for AOD rate limiting - workflowOptions.push_back(ConfigParamSpec{"aod-memory-rate-limit", VariantType::Int64, 0LL, {"Rate limit AOD processing based on memory"}}); - - // options for AOD writer - workflowOptions.push_back(ConfigParamSpec{"aod-writer-json", VariantType::String, "", {"Name of the json configuration file"}}); - workflowOptions.push_back(ConfigParamSpec{"aod-writer-resfile", VariantType::String, "", {"Default name of the output file"}}); - workflowOptions.push_back(ConfigParamSpec{"aod-writer-resmode", VariantType::String, "RECREATE", {"Creation mode of the result files: NEW, CREATE, RECREATE, UPDATE"}}); - workflowOptions.push_back(ConfigParamSpec{"aod-writer-ntfmerge", VariantType::Int, -1, {"Number of time frames to merge into one file"}}); - workflowOptions.push_back(ConfigParamSpec{"aod-writer-keep", VariantType::String, "", {"Comma separated list of ORIGIN/DESCRIPTION/SUBSPECIFICATION:treename:col1/col2/..:filename"}}); - - workflowOptions.push_back(ConfigParamSpec{"forwarding-policy", - VariantType::String, - "dangling", - {"Which messages to forward." - " dangling: dangling outputs," - " all: all messages"}}); - workflowOptions.push_back(ConfigParamSpec{"forwarding-destination", - VariantType::String, - "file", - {"Destination for forwarded messages." - " file: write to file," - " fairmq: send to output proxy"}}); - std::vector<ChannelConfigurationPolicy> channelPolicies; - UserCustomizationsHelper::userDefinedCustomization(channelPolicies, 0); - auto defaultChannelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); - channelPolicies.insert(std::end(channelPolicies), std::begin(defaultChannelPolicies), std::end(defaultChannelPolicies)); - - std::vector<CompletionPolicy> completionPolicies; - UserCustomizationsHelper::userDefinedCustomization(completionPolicies, 0); - auto defaultCompletionPolicies = CompletionPolicy::createDefaultPolicies(); - completionPolicies.insert(std::end(completionPolicies), std::begin(defaultCompletionPolicies), std::end(defaultCompletionPolicies)); - - std::vector<DispatchPolicy> dispatchPolicies; - UserCustomizationsHelper::userDefinedCustomization(dispatchPolicies, 0); - auto defaultDispatchPolicies = DispatchPolicy::createDefaultPolicies(); - dispatchPolicies.insert(std::end(dispatchPolicies), std::begin(defaultDispatchPolicies), std::end(defaultDispatchPolicies)); - - std::vector<std::unique_ptr<ParamRetriever>> retrievers; - std::unique_ptr<ParamRetriever> retriever{new BoostOptionsRetriever(true, argc, argv)}; - retrievers.emplace_back(std::move(retriever)); - auto workflowOptionsStore = std::make_unique<ConfigParamStore>(workflowOptions, std::move(retrievers)); - workflowOptionsStore->preload(); - workflowOptionsStore->activate(); - ConfigParamRegistry workflowOptionsRegistry(std::move(workflowOptionsStore)); - ConfigContext configContext(workflowOptionsRegistry, argc, argv); - o2::framework::WorkflowSpec specs = defineDataProcessing(configContext); - overridePipeline(configContext, specs); - for (auto& spec : specs) { - UserCustomizationsHelper::userDefinedCustomization(spec.requiredServices, 0); + if (noCatch) { + result = mainNoCatch(argc, argv); + } else { + try { + // The 0 here is an int, therefore having the template matching in the + // SFINAE expression above fit better the version which invokes user code over + // the default one. + // The default policy is a catch all pub/sub setup to be consistent with the past. + result = mainNoCatch(argc, argv); + } catch (boost::exception& e) { + doBoostException(e, argv[0]); + throw; + } catch (std::exception const& error) { + doUnknownException(error.what(), argv[0]); + throw; + } catch (o2::framework::RuntimeErrorRef& ref) { + doDPLException(ref, argv[0]); + throw; + } catch (...) { + doUnknownException("", argv[0]); + throw; } - result = doMain(argc, argv, specs, channelPolicies, completionPolicies, dispatchPolicies, workflowOptions, configContext); - } catch (boost::exception& e) { - doBoostException(e); - } catch (std::exception const& error) { - LOG(ERROR) << "error while setting up workflow: " << error.what(); - } catch (...) { - LOG(ERROR) << "Unknown error while setting up workflow."; - } - char* idstring = nullptr; - for (int argi = 0; argi < argc; argi++) { - if (strcmp(argv[argi], "--id") == 0 && argi + 1 < argc) { - idstring = argv[argi + 1]; - break; + char* idstring = nullptr; + for (int argi = 0; argi < argc; argi++) { + if (strcmp(argv[argi], "--id") == 0 && argi + 1 < argc) { + idstring = argv[argi + 1]; + break; + } } + o2::framework::OnWorkflowTerminationHook onWorkflowTerminationHook; + UserCustomizationsHelper::userDefinedCustomization(onWorkflowTerminationHook, 0); + onWorkflowTerminationHook(idstring); + doDefaultWorkflowTerminationHook(); } - o2::framework::OnWorkflowTerminationHook onWorkflowTerminationHook; - UserCustomizationsHelper::userDefinedCustomization(onWorkflowTerminationHook, 0); - onWorkflowTerminationHook(idstring); - LOG(INFO) << "Process " << getpid() << " is exiting."; return result; } - #endif diff --git a/Framework/Core/src/AODReaderHelpers.cxx b/Framework/Core/src/AODReaderHelpers.cxx index f7300b825bfcb..2edf0af7a4fe6 100644 --- a/Framework/Core/src/AODReaderHelpers.cxx +++ b/Framework/Core/src/AODReaderHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include "Framework/AnalysisHelpers.h" #include "AnalysisDataModelHelpers.h" #include "DataProcessingHelpers.h" -#include "ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "Framework/RootTableBuilderHelpers.h" #include "Framework/AlgorithmSpec.h" #include "Framework/ConfigParamRegistry.h" @@ -30,9 +31,10 @@ #include <Monitoring/Monitoring.h> -#include <ROOT/RDataFrame.hxx> #include <TGrid.h> #include <TFile.h> +#include <TTreeCache.h> +#include <TTreePerfStats.h> #include <arrow/ipc/reader.h> #include <arrow/ipc/writer.h> @@ -59,11 +61,20 @@ auto setEOSCallback(InitContext& ic) }); } +template <typename... Ts> +static inline auto doExtractTypedOriginal(framework::pack<Ts...>, ProcessingContext& pc) +{ + if constexpr (sizeof...(Ts) == 1) { + return pc.inputs().get<TableConsumer>(aod::MetadataTrait<framework::pack_element_t<0, framework::pack<Ts...>>>::metadata::tableLabel())->asArrowTable(); + } else { + return std::vector{pc.inputs().get<TableConsumer>(aod::MetadataTrait<Ts>::metadata::tableLabel())->asArrowTable()...}; + } +} + template <typename O> static inline auto extractTypedOriginal(ProcessingContext& pc) { - ///FIXME: this should be done in invokeProcess() as some of the originals may be compound tables - return O{pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable()}; + return O{doExtractTypedOriginal(soa::make_originals_from_type<O>(), pc)}; } template <typename... Os> @@ -72,25 +83,14 @@ static inline auto extractOriginalsTuple(framework::pack<Os...>, ProcessingConte return std::make_tuple(extractTypedOriginal<Os>(pc)...); } -AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector<InputSpec> requested) +AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector<InputSpec>& requested) { return AlgorithmSpec::InitCallback{[requested](InitContext& ic) { - return [requested](ProcessingContext& pc) { auto outputs = pc.outputs(); // spawn tables for (auto& input : requested) { - auto description = std::visit( - overloaded{ - [](ConcreteDataMatcher const& matcher) { return matcher.description; }, - [](auto&&) { return header::DataDescription{""}; }}, - input.matcher); - - auto origin = std::visit( - overloaded{ - [](ConcreteDataMatcher const& matcher) { return matcher.origin; }, - [](auto&&) { return header::DataOrigin{""}; }}, - input.matcher); + auto&& [origin, description] = DataSpecUtils::asConcreteDataTypeMatcher(input); auto maker = [&](auto metadata) { using metadata_t = decltype(metadata); @@ -98,11 +98,11 @@ AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector<InputSpec> requ using index_pack_t = typename metadata_t::index_pack_t; using sources = typename metadata_t::originals; if constexpr (metadata_t::exclusive == true) { - return o2::framework::IndexExclusive::indexBuilder(index_pack_t{}, + return o2::framework::IndexExclusive::indexBuilder(input.binding.c_str(), index_pack_t{}, extractTypedOriginal<Key>(pc), extractOriginalsTuple(sources{}, pc)); } else { - return o2::framework::IndexSparse::indexBuilder(index_pack_t{}, + return o2::framework::IndexSparse::indexBuilder(input.binding.c_str(), index_pack_t{}, extractTypedOriginal<Key>(pc), extractOriginalsTuple(sources{}, pc)); } @@ -117,9 +117,15 @@ AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector<InputSpec> requ } else if (description == header::DataDescription{"MA_RN3_SP"}) { outputs.adopt(Output{origin, description}, maker(o2::aod::Run3MatchedSparseMetadata{})); } else if (description == header::DataDescription{"MA_BCCOL_EX"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::BCCollisionsExclusiveMetadata{})); + outputs.adopt(Output{origin, description}, maker(o2::aod::MatchedBCCollisionsExclusiveMetadata{})); } else if (description == header::DataDescription{"MA_BCCOL_SP"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::BCCollisionsSparseMetadata{})); + outputs.adopt(Output{origin, description}, maker(o2::aod::MatchedBCCollisionsSparseMetadata{})); + } else if (description == header::DataDescription{"MA_RN3_BC_SP"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::Run3MatchedToBCSparseMetadata{})); + } else if (description == header::DataDescription{"MA_RN3_BC_EX"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::Run3MatchedToBCExclusiveMetadata{})); + } else if (description == header::DataDescription{"MA_RN2_BC_SP"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::Run2MatchedToBCSparseMetadata{})); } else { throw std::runtime_error("Not an index table"); } @@ -128,39 +134,36 @@ AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector<InputSpec> requ }}; } -AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector<InputSpec> requested) +AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector<InputSpec>& requested) { return AlgorithmSpec::InitCallback{[requested](InitContext& ic) { - return [requested](ProcessingContext& pc) { auto outputs = pc.outputs(); // spawn tables for (auto& input : requested) { - auto description = std::visit( - overloaded{ - [](ConcreteDataMatcher const& matcher) { return matcher.description; }, - [](auto&&) { return header::DataDescription{""}; }}, - input.matcher); - - auto origin = std::visit( - overloaded{ - [](ConcreteDataMatcher const& matcher) { return matcher.origin; }, - [](auto&&) { return header::DataOrigin{""}; }}, - input.matcher); + auto&& [origin, description] = DataSpecUtils::asConcreteDataTypeMatcher(input); auto maker = [&](auto metadata) { using metadata_t = decltype(metadata); using expressions = typename metadata_t::expression_pack_t; auto original_table = pc.inputs().get<TableConsumer>(input.binding)->asArrowTable(); - return o2::framework::spawner(expressions{}, original_table.get()); + return o2::framework::spawner(expressions{}, original_table.get(), input.binding.c_str()); }; - if (description == header::DataDescription{"TRACK:PAR"}) { + if (description == header::DataDescription{"TRACK"}) { outputs.adopt(Output{origin, description}, maker(o2::aod::TracksExtensionMetadata{})); - } else if (description == header::DataDescription{"TRACK:PARCOV"}) { + } else if (description == header::DataDescription{"TRACKCOV"}) { outputs.adopt(Output{origin, description}, maker(o2::aod::TracksCovExtensionMetadata{})); - } else if (description == header::DataDescription{"MUON"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::MuonsExtensionMetadata{})); + } else if (description == header::DataDescription{"TRACKEXTRA"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::TracksExtraExtensionMetadata{})); + } else if (description == header::DataDescription{"MFTTRACK"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::MFTTracksExtensionMetadata{})); + } else if (description == header::DataDescription{"FWDTRACK"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::FwdTracksExtensionMetadata{})); + } else if (description == header::DataDescription{"FWDTRACKCOV"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::FwdTracksCovExtensionMetadata{})); + } else if (description == header::DataDescription{"MCPARTICLE"}) { + outputs.adopt(Output{origin, description}, maker(o2::aod::McParticlesExtensionMetadata{})); } else { throw runtime_error("Not an extended table"); } @@ -169,142 +172,4 @@ AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector<InputSpec> reques }}; } -AlgorithmSpec AODReaderHelpers::rootFileReaderCallback() -{ - auto callback = AlgorithmSpec{adaptStateful([](ConfigParamRegistry const& options, - DeviceSpec const& spec, - Monitoring& monitoring) { - monitoring.send(Metric{(uint64_t)0, "arrow-bytes-created"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.send(Metric{(uint64_t)0, "arrow-messages-created"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.send(Metric{(uint64_t)0, "arrow-bytes-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.send(Metric{(uint64_t)0, "arrow-messages-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.flushBuffer(); - - if (!options.isSet("aod-file")) { - LOGP(ERROR, "No input file defined!"); - throw std::runtime_error("Processing is stopped!"); - } - - auto filename = options.get<std::string>("aod-file"); - - // create a DataInputDirector - auto didir = std::make_shared<DataInputDirector>(filename); - if (options.isSet("aod-reader-json")) { - auto jsonFile = options.get<std::string>("aod-reader-json"); - if (!didir->readJson(jsonFile)) { - LOGP(ERROR, "Check the JSON document! Can not be properly parsed!"); - } - } - - // get the run time watchdog - auto* watchdog = new RuntimeWatchdog(options.get<int64_t>("time-limit")); - - // selected the TFN input and - // create list of requested tables - header::DataHeader TFNumberHeader; - std::vector<OutputRoute> requestedTables; - std::vector<OutputRoute> routes(spec.outputs); - for (auto route : routes) { - if (DataSpecUtils::partialMatch(route.matcher, header::DataOrigin("TFN"))) { - auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher); - TFNumberHeader = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec); - } else { - requestedTables.emplace_back(route); - } - } - - auto fileCounter = std::make_shared<int>(0); - auto numTF = std::make_shared<int>(-1); - return adaptStateless([TFNumberHeader, - requestedTables, - fileCounter, - numTF, - watchdog, - didir](Monitoring& monitoring, DataAllocator& outputs, ControlService& control, DeviceSpec const& device) { - // check if RuntimeLimit is reached - if (!watchdog->update()) { - LOGP(INFO, "Run time exceeds run time limit of {} seconds!", watchdog->runTimeLimit); - LOGP(INFO, "Stopping reader {} after time frame {}.", device.inputTimesliceId, watchdog->numberTimeFrames - 1); - didir->closeInputFiles(); - control.endOfStream(); - control.readyToQuit(QuitRequest::Me); - return; - } - - // Each parallel reader device.inputTimesliceId reads the files fileCounter*device.maxInputTimeslices+device.inputTimesliceId - // the TF to read is numTF - assert(device.inputTimesliceId < device.maxInputTimeslices); - uint64_t timeFrameNumber = 0; - int fcnt = (*fileCounter * device.maxInputTimeslices) + device.inputTimesliceId; - int ntf = *numTF + 1; - monitoring.send(Metric{(uint64_t)ntf, "tf-sent"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - - // loop over requested tables - TTree* tr = nullptr; - bool first = true; - for (auto route : requestedTables) { - - // create header - auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher); - auto dh = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec); - - // create a TreeToTable object - tr = didir->getDataTree(dh, fcnt, ntf); - if (!tr) { - if (first) { - // check if there is a next file to read - fcnt += device.maxInputTimeslices; - if (didir->atEnd(fcnt)) { - LOGP(INFO, "No input files left to read for reader {}!", device.inputTimesliceId); - didir->closeInputFiles(); - control.endOfStream(); - control.readyToQuit(QuitRequest::Me); - return; - } - // get first folder of next file - ntf = 0; - tr = didir->getDataTree(dh, fcnt, ntf); - if (!tr) { - LOGP(FATAL, "Can not retrieve tree for table {}: fileCounter {}, timeFrame {}", concrete.origin, fcnt, ntf); - throw std::runtime_error("Processing is stopped!"); - } - } else { - LOGP(FATAL, "Can not retrieve tree for table {}: fileCounter {}, timeFrame {}", concrete.origin, fcnt, ntf); - throw std::runtime_error("Processing is stopped!"); - } - } - if (first) { - timeFrameNumber = didir->getTimeFrameNumber(dh, fcnt, ntf); - auto o = Output(TFNumberHeader); - outputs.make<uint64_t>(o) = timeFrameNumber; - } - - // create table output - auto o = Output(dh); - auto& t2t = outputs.make<TreeToTable>(o); - - // add branches to read - auto colnames = aod::datamodel::getColumnNames(dh); - if (colnames.size() == 0) { - t2t.addAllColumns(tr); - } else { - for (auto colname : colnames) { - t2t.addColumn(colname.c_str()); - } - } - - // fill the table - t2t.fill(tr); - first = false; - } - - // save file number and time frame - *fileCounter = (fcnt - device.inputTimesliceId) / device.maxInputTimeslices; - *numTF = ntf; - }); - })}; - - return callback; -} - } // namespace o2::framework::readers diff --git a/Framework/Core/src/ASoA.cxx b/Framework/Core/src/ASoA.cxx index 256fafc438c2e..9e0bda0977044 100644 --- a/Framework/Core/src/ASoA.cxx +++ b/Framework/Core/src/ASoA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,9 @@ #include "Framework/ASoA.h" #include "ArrowDebugHelpers.h" +#include "Framework/RuntimeError.h" +#include <arrow/util/key_value_metadata.h> +#include <arrow/util/config.h> namespace o2::soa { @@ -20,7 +24,13 @@ std::shared_ptr<arrow::Table> ArrowHelpers::joinTables(std::vector<std::shared_p return tables[0]; } for (auto i = 0u; i < tables.size() - 1; ++i) { - assert(tables[i]->num_rows() == tables[i + 1]->num_rows()); + if (tables[i]->num_rows() != tables[i + 1]->num_rows()) { + throw o2::framework::runtime_error_f("Tables %s and %s have different sizes (%d vs %d) and cannot be joined!", + tables[i]->schema()->metadata()->Get("label").ValueOrDie().c_str(), + tables[i + 1]->schema()->metadata()->Get("label").ValueOrDie().c_str(), + tables[i]->num_rows(), + tables[i + 1]->num_rows()); + } } std::vector<std::shared_ptr<arrow::Field>> fields; std::vector<std::shared_ptr<arrow::ChunkedArray>> columns; @@ -81,4 +91,36 @@ std::shared_ptr<arrow::Table> ArrowHelpers::concatTables(std::vector<std::shared return result; } +arrow::ChunkedArray* getIndexFromLabel(arrow::Table* table, const char* label) +{ + auto index = table->schema()->GetAllFieldIndices(label); + if (index.empty() == true) { + o2::framework::throw_error(o2::framework::runtime_error_f("Unable to find column with label %s", label)); + } + return table->column(index[0]).get(); +} + +arrow::Status getSliceFor(int value, char const* key, std::shared_ptr<arrow::Table> const& input, std::shared_ptr<arrow::Table>& output, uint64_t& offset) +{ + arrow::Datum value_counts; + auto options = arrow::compute::ScalarAggregateOptions::Defaults(); + ARROW_ASSIGN_OR_RAISE(value_counts, + arrow::compute::CallFunction("value_counts", {input->GetColumnByName(key)}, + &options)); + auto pair = static_cast<arrow::StructArray>(value_counts.array()); + auto values = static_cast<arrow::NumericArray<arrow::Int32Type>>(pair.field(0)->data()); + auto counts = static_cast<arrow::NumericArray<arrow::Int64Type>>(pair.field(1)->data()); + + int slice; + for (slice = 0; slice < values.length(); ++slice) { + if (values.Value(slice) == value) { + offset = slice; + output = input->Slice(slice, counts.Value(slice)); + return arrow::Status::OK(); + } + } + output = input->Slice(0, 0); + return arrow::Status::OK(); +} + } // namespace o2::soa diff --git a/Framework/Core/src/AnalysisDataModel.cxx b/Framework/Core/src/AnalysisDataModel.cxx new file mode 100644 index 0000000000000..d986486d94c69 --- /dev/null +++ b/Framework/Core/src/AnalysisDataModel.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/AnalysisDataModel.h" + +namespace o2::soa +{ +template struct Join<aod::BCs, aod::Timestamps>; +template struct Join<aod::Tracks, aod::TracksCov, aod::TracksExtra>; +template struct Join<aod::FwdTracks, aod::FwdTracksCov>; +template struct Join<aod::TransientV0s, aod::StoredV0s>; +template struct Join<aod::TransientCascades, aod::StoredCascades>; +template struct Join<aod::Collisions, aod::Run2MatchedSparse>; +template struct Join<aod::Collisions, aod::Run3MatchedSparse>; + +template struct Join<aod::TracksExtension, aod::StoredTracks>; +} // namespace o2::soa diff --git a/Framework/Core/src/AnalysisDataModelHelpers.cxx b/Framework/Core/src/AnalysisDataModelHelpers.cxx index b089ebe8f68d0..3ad780a67bdb3 100644 --- a/Framework/Core/src/AnalysisDataModelHelpers.cxx +++ b/Framework/Core/src/AnalysisDataModelHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,14 @@ #include "Framework/AnalysisDataModel.h" #include "Framework/StringHelpers.h" #include "Framework/Logger.h" -#include <boost/algorithm/string.hpp> + +std::string str_tolower(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::tolower(c); } // correct + ); + return s; +} namespace o2::aod::datamodel { @@ -23,7 +31,7 @@ std::string getTreeName(header::DataHeader dh) // lower case of first part of description auto found = description.find_first_of(":"); - std::string treeName = boost::algorithm::to_lower_copy(description).substr(0, found); + std::string treeName = str_tolower(description).substr(0, found); // add prefix according to origin if (origin == "AOD") { @@ -40,31 +48,5 @@ std::string getTreeName(header::DataHeader dh) return treeName; } -template <typename... C> -static constexpr auto columnNamesTrait(framework::pack<C...>) -{ - return std::vector<std::string>{C::columnLabel()...}; -} - -std::vector<std::string> getColumnNames(header::DataHeader dh) -{ - auto description = std::string(dh.dataDescription.str); - auto origin = std::string(dh.dataOrigin.str); - - // get column names - // AOD / RN2 - if (origin == "AOD") { - if (description == "TRACK:PAR") { - return columnNamesTrait(typename StoredTracksMetadata::table_t::persistent_columns_t{}); - } else if (description == "TRACK:PARCOV") { - return columnNamesTrait(typename StoredTracksCovMetadata::table_t::persistent_columns_t{}); - } else if (description == "TRACK:EXTRA") { - return columnNamesTrait(typename TracksExtraMetadata::table_t::persistent_columns_t{}); - } - } - - // default: column names = {} - return std::vector<std::string>({}); -} } // namespace o2::aod::datamodel diff --git a/Framework/Core/src/AnalysisDataModelHelpers.h b/Framework/Core/src/AnalysisDataModelHelpers.h index 59f69782c845c..dc7e722e0fd91 100644 --- a/Framework/Core/src/AnalysisDataModelHelpers.h +++ b/Framework/Core/src/AnalysisDataModelHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,5 @@ namespace o2::aod::datamodel { std::string getTreeName(header::DataHeader dh); -std::vector<std::string> getColumnNames(header::DataHeader dh); } // namespace o2::aod::datamodel #endif // O2_FRAMEWORK_ANALYSISDATAMODELHELPERS_H_ diff --git a/Framework/Core/src/AnalysisHelpers.cxx b/Framework/Core/src/AnalysisHelpers.cxx index 65dc086d2509d..a68547d1e670c 100644 --- a/Framework/Core/src/AnalysisHelpers.cxx +++ b/Framework/Core/src/AnalysisHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/AnalysisManagers.h b/Framework/Core/src/AnalysisManagers.h deleted file mode 100644 index c59225b8364d0..0000000000000 --- a/Framework/Core/src/AnalysisManagers.h +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef FRAMEWORK_ANALYSISMANAGERS_H -#define FRAMEWORK_ANALYSISMANAGERS_H -#include "Framework/AnalysisHelpers.h" -#include "Framework/Kernels.h" -#include "Framework/ASoA.h" -#include "Framework/ProcessingContext.h" -#include "Framework/EndOfStreamContext.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/InitContext.h" -#include "Framework/RootConfigParamHelpers.h" -#include "../src/ExpressionHelpers.h" - -namespace o2::framework -{ - -template <typename ANY> -struct PartitionManager { - template <typename... T2s> - static void setPartition(ANY&, T2s&...) - { - } - - template <typename... Ts> - static void bindExternalIndices(ANY&, Ts*...) - { - } - - template <typename... Ts> - static void getBoundToExternalIndices(ANY&, Ts&...) - { - } - - static void updatePlaceholders(ANY&, InitContext&) - { - } -}; - -template <typename T> -struct PartitionManager<Partition<T>> { - template <typename T2> - static void doSetPartition(Partition<T>& partition, T2& table) - { - if constexpr (std::is_same_v<T, T2>) { - partition.setTable(table); - } - } - - template <typename... T2s> - static void setPartition(Partition<T>& partition, T2s&... tables) - { - (doSetPartition(partition, tables), ...); - } - - template <typename... Ts> - static void bindExternalIndices(Partition<T>& partition, Ts*... tables) - { - partition.bindExternalIndices(tables...); - } - - template <typename... Ts> - static void getBoundToExternalIndices(Partition<T>& partition, Ts&... tables) - { - partition.getBoundToExternalIndices(tables...); - } - - static void updatePlaceholders(Partition<T>& partition, InitContext& context) - { - partition.updatePlaceholders(context); - } -}; - -template <typename ANY> -struct FilterManager { - static bool createExpressionTrees(ANY&, std::vector<ExpressionInfo>&) - { - return false; - } - - static bool updatePlaceholders(ANY&, InitContext&) - { - return false; - } -}; - -template <> -struct FilterManager<expressions::Filter> { - static bool createExpressionTrees(expressions::Filter const& filter, std::vector<ExpressionInfo>& expressionInfos) - { - expressions::updateExpressionInfos(filter, expressionInfos); - return true; - } - - static bool updatePlaceholders(expressions::Filter& filter, InitContext& ctx) - { - expressions::updatePlaceholders(filter, ctx); - return true; - } -}; - -/// SFINAE placeholder -template <typename T> -struct OutputManager { - template <typename ANY> - static bool appendOutput(std::vector<OutputSpec>&, ANY&, uint32_t) - { - return false; - } - - template <typename ANY> - static bool prepare(ProcessingContext&, ANY&) - { - return false; - } - - template <typename ANY> - static bool postRun(EndOfStreamContext&, ANY&) - { - return true; - } - - template <typename ANY> - static bool finalize(ProcessingContext&, ANY&) - { - return true; - } -}; - -/// Produces specialization -template <typename TABLE> -struct OutputManager<Produces<TABLE>> { - static bool appendOutput(std::vector<OutputSpec>& outputs, Produces<TABLE>& what, uint32_t) - { - outputs.emplace_back(what.spec()); - return true; - } - static bool prepare(ProcessingContext& context, Produces<TABLE>& what) - { - what.resetCursor(context.outputs().make<TableBuilder>(what.ref())); - return true; - } - static bool finalize(ProcessingContext&, Produces<TABLE>&) - { - return true; - } - static bool postRun(EndOfStreamContext&, Produces<TABLE>&) - { - return true; - } -}; - -/// HistogramRegistry specialization -template <> -struct OutputManager<HistogramRegistry> { - static bool appendOutput(std::vector<OutputSpec>& outputs, HistogramRegistry& what, uint32_t hash) - { - what.setHash(hash); - outputs.emplace_back(what.spec()); - return true; - } - static bool prepare(ProcessingContext&, HistogramRegistry&) - { - return true; - } - - static bool finalize(ProcessingContext&, HistogramRegistry&) - { - return true; - } - - static bool postRun(EndOfStreamContext& context, HistogramRegistry& what) - { - context.outputs().snapshot(what.ref(), *(*what)); - return true; - } -}; - -/// OutputObj specialization -template <typename T> -struct OutputManager<OutputObj<T>> { - static bool appendOutput(std::vector<OutputSpec>& outputs, OutputObj<T>& what, uint32_t hash) - { - what.setHash(hash); - outputs.emplace_back(what.spec()); - return true; - } - static bool prepare(ProcessingContext&, OutputObj<T>&) - { - return true; - } - - static bool finalize(ProcessingContext&, OutputObj<T>&) - { - return true; - } - - static bool postRun(EndOfStreamContext& context, OutputObj<T>& what) - { - context.outputs().snapshot(what.ref(), *what); - return true; - } -}; - -/// Spawns specializations -template <typename O> -static auto extractOriginal(ProcessingContext& pc) -{ - return pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable(); -} - -template <typename... Os> -static std::vector<std::shared_ptr<arrow::Table>> extractOriginals(framework::pack<Os...>, ProcessingContext& pc) -{ - return {extractOriginal<Os>(pc)...}; -} - -template <typename T> -struct OutputManager<Spawns<T>> { - static bool appendOutput(std::vector<OutputSpec>& outputs, Spawns<T>& what, uint32_t) - { - outputs.emplace_back(what.spec()); - return true; - } - - static bool prepare(ProcessingContext& pc, Spawns<T>& what) - { - auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(what.sources_pack(), pc)); - if (original_table->schema()->fields().empty() == true) { - using base_table_t = typename Spawns<T>::base_table_t; - original_table = makeEmptyTable<base_table_t>(); - } - - what.extension = std::make_shared<typename Spawns<T>::extension_t>(o2::framework::spawner(what.pack(), original_table.get())); - what.table = std::make_shared<typename T::table_t>(soa::ArrowHelpers::joinTables({what.extension->asArrowTable(), original_table})); - return true; - } - - static bool finalize(ProcessingContext& pc, Spawns<T>& what) - { - pc.outputs().adopt(what.output(), what.asArrowTable()); - return true; - } - - static bool postRun(EndOfStreamContext&, Spawns<T>&) - { - return true; - } -}; - -/// Builds specialization -template <typename O> -static inline auto extractTypedOriginal(ProcessingContext& pc) -{ - ///FIXME: this should be done in invokeProcess() as some of the originals may be compound tables - return O{pc.inputs().get<TableConsumer>(aod::MetadataTrait<O>::metadata::tableLabel())->asArrowTable()}; -} - -template <typename... Os> -static inline auto extractOriginalsTuple(framework::pack<Os...>, ProcessingContext& pc) -{ - return std::make_tuple(extractTypedOriginal<Os>(pc)...); -} - -template <typename T, typename P> -struct OutputManager<Builds<T, P>> { - static bool appendOutput(std::vector<OutputSpec>& outputs, Builds<T, P>& what, uint32_t) - { - outputs.emplace_back(what.spec()); - return true; - } - - static bool prepare(ProcessingContext& pc, Builds<T, P>& what) - { - return what.build(what.pack(), - extractTypedOriginal<typename Builds<T, P>::Key>(pc), - extractOriginalsTuple(what.sources_pack(), pc)); - } - - static bool finalize(ProcessingContext& pc, Builds<T, P>& what) - { - pc.outputs().adopt(what.output(), what.asArrowTable()); - return true; - } - - static bool postRun(EndOfStreamContext&, Builds<T, P>&) - { - return true; - } -}; - -template <typename T> -class has_instance -{ - typedef char one; - struct two { - char x[2]; - }; - - template <typename C> - static one test(decltype(&C::instance)); - template <typename C> - static two test(...); - - public: - enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; -}; - -template <typename T> -struct ServiceManager { - template <typename ANY> - static bool prepare(InitContext&, ANY&) - { - return false; - } -}; - -template <typename T> -struct ServiceManager<Service<T>> { - static bool prepare(InitContext& context, Service<T>& service) - { - if constexpr (has_instance<T>::value) { - service.service = &(T::instance()); // Sigh... - return true; - } else { - service.service = context.services().get<T>(); - return true; - } - return false; - } -}; - -template <typename T> -struct OptionManager { - template <typename ANY> - static bool appendOption(std::vector<ConfigParamSpec>&, ANY&) - { - return false; - } - - template <typename ANY> - static bool prepare(InitContext&, ANY&) - { - return false; - } -}; - -template <typename T, typename IP> -struct OptionManager<Configurable<T, IP>> { - static bool appendOption(std::vector<ConfigParamSpec>& options, Configurable<T, IP>& what) - { - if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) { - options.emplace_back(ConfigParamSpec{what.name, variant_trait_v<typename std::decay<T>::type>, what.value, {what.help}}); - } else { - auto specs = RootConfigParamHelpers::asConfigParamSpecs<T>(what.name, what.value); - options.insert(options.end(), specs.begin(), specs.end()); - } - return true; - } - - static bool prepare(InitContext& context, Configurable<T, IP>& what) - { - if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) { - what.value = context.options().get<T>(what.name.c_str()); - } else { - auto pt = context.options().get<boost::property_tree::ptree>(what.name.c_str()); - what.value = RootConfigParamHelpers::as<T>(pt); - } - return true; - } -}; - -/// Manager template to facilitate extended tables spawning -template <typename T> -struct SpawnManager { - static bool requestInputs(std::vector<InputSpec>&, T const&) { return false; } -}; - -template <typename TABLE> -struct SpawnManager<Spawns<TABLE>> { - static bool requestInputs(std::vector<InputSpec>& inputs, Spawns<TABLE>& spawns) - { - auto base_specs = spawns.base_specs(); - for (auto& base_spec : base_specs) { - if (std::find_if(inputs.begin(), inputs.end(), [&](InputSpec const& spec) { return base_spec.binding == spec.binding; }) == inputs.end()) { - inputs.emplace_back(base_spec); - } - } - return true; - } -}; - -/// Manager template for building index tables -template <typename T> -struct IndexManager { - static bool requestInputs(std::vector<InputSpec>&, T const&) { return false; }; -}; - -template <typename IDX, typename P> -struct IndexManager<Builds<IDX, P>> { - static bool requestInputs(std::vector<InputSpec>& inputs, Builds<IDX, P>& builds) - { - auto base_specs = builds.base_specs(); - for (auto& base_spec : base_specs) { - if (std::find_if(inputs.begin(), inputs.end(), [&](InputSpec const& spec) { return base_spec.binding == spec.binding; }) == inputs.end()) { - inputs.emplace_back(base_spec); - } - } - return true; - } -}; -} // namespace o2::framework - -#endif // ANALYSISMANAGERS_H diff --git a/Framework/Core/src/Array2D.cxx b/Framework/Core/src/Array2D.cxx new file mode 100644 index 0000000000000..fbd8f0ef4c90a --- /dev/null +++ b/Framework/Core/src/Array2D.cxx @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <Framework/Array2D.h> +#include <Framework/RuntimeError.h> +#include <Framework/CompilerBuiltins.h> + +template class std::unordered_map<std::string, u_int32_t>; + +namespace o2::framework +{ + +labelmap_t LabelMap::populate(uint32_t size, std::vector<std::string> labels) +{ + labelmap_t map; + if (labels.empty() == false) { + if (labels.size() != size) { + throw runtime_error("labels array size != array dimension"); + } + for (auto i = 0u; i < size; ++i) { + map.emplace(labels[i], (uint32_t)i); + } + } + return map; +} + +void LabelMap::replaceLabelsRows(uint32_t size, std::vector<std::string> const& labels) +{ + if (O2_BUILTIN_UNLIKELY(size != labels.size())) { + throw runtime_error_f("Row labels array has different size (%d) than number of rows (%d)", labels.size(), size); + }; + labels_rows = labels; + rowmap.clear(); + rowmap = populate(labels.size(), labels); +} + +void LabelMap::replaceLabelsCols(uint32_t size, std::vector<std::string> const& labels) +{ + if (O2_BUILTIN_UNLIKELY(size != labels.size())) { + throw runtime_error_f("Column labels array has different size (%d) than number of columns (%d)", labels.size(), size); + }; + labels_cols = labels; + colmap.clear(); + colmap = populate(labels.size(), labels); +} +LabelMap::LabelMap() + : rowmap{}, + colmap{}, + labels_rows{}, + labels_cols{} +{ +} + +LabelMap::LabelMap(uint32_t rows, uint32_t cols, std::vector<std::string> labels_rows_, std::vector<std::string> labels_cols_) + : rowmap{populate(rows, labels_rows_)}, + colmap{populate(cols, labels_cols_)}, + labels_rows{labels_rows_}, + labels_cols{labels_cols_} +{ +} + +LabelMap::LabelMap(uint32_t size, std::vector<std::string> labels) + : rowmap{}, + colmap{populate(size, labels)}, + labels_rows{}, + labels_cols{labels} +{ +} + +LabelMap::LabelMap(LabelMap const& other) = default; +LabelMap::LabelMap(LabelMap&& other) = default; +LabelMap& LabelMap::operator=(LabelMap const& other) = default; +LabelMap& LabelMap::operator=(LabelMap&& other) = default; + +} // namespace o2::framework diff --git a/Framework/Core/src/ArrowDebugHelpers.h b/Framework/Core/src/ArrowDebugHelpers.h index e7800e949a6da..eb98ac1054689 100644 --- a/Framework/Core/src/ArrowDebugHelpers.h +++ b/Framework/Core/src/ArrowDebugHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,16 +11,4 @@ #ifndef O2_FRAMEWORK_ARROWDEBUGHELPERS_H_ #define O2_FRAMEWORK_ARROWDEBUGHELPERS_H_ -// Explicit template declarations to help LLDB debug arrow related parts. - -#ifndef NDEBUG -template class std::shared_ptr<arrow::Array>; -template class std::shared_ptr<arrow::ChunkedArray>; -template class std::shared_ptr<arrow::Field>; -template class std::shared_ptr<arrow::Schema>; -template class std::shared_ptr<arrow::Table>; -template class std::vector<std::shared_ptr<arrow::Table>>; -template class std::vector<std::shared_ptr<arrow::Field>>; -#endif - #endif // O2_FRAMEWORK_ARROWDEBUGHELPERS_H_ diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx new file mode 100644 index 0000000000000..ced10a8b12e4a --- /dev/null +++ b/Framework/Core/src/ArrowSupport.cxx @@ -0,0 +1,392 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "ArrowSupport.h" +#include "Framework/ArrowContext.h" +#include "Framework/DataProcessor.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/DeviceSpec.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/Tracing.h" +#include "Framework/DeviceMetricsInfo.h" +#include "Framework/DeviceMetricsHelper.h" +#include "Framework/DeviceInfo.h" +#include "Framework/DevicesManager.h" + +#include "CommonMessageBackendsHelpers.h" +#include <Monitoring/Monitoring.h> +#include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" + +#include <options/FairMQProgOptions.h> + +#include <uv.h> +#include <boost/program_options/variables_map.hpp> +#include <csignal> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +namespace o2::framework +{ + +struct EndOfStreamContext; +struct ProcessingContext; + +enum struct RateLimitingState { + UNKNOWN = 0, // No information received yet. + STARTED = 1, // Information received, new timeframe not requested. + CHANGED = 2, // Information received, new timeframe requested but not yet accounted. + BELOW_LIMIT = 3, // New metric received, we are below limit. + NEXT_ITERATION_FROM_BELOW = 4, // Iteration when previously in BELOW_LIMIT. + ABOVE_LIMIT = 5, // New metric received, we are above limit. + EMPTY = 6, // +}; + +struct RateLimitConfig { + int64_t maxMemory = 2000; +}; + +static int64_t memLimit = 0; + +struct MetricIndices { + size_t arrowBytesCreated = -1; + size_t arrowBytesDestroyed = -1; + size_t arrowMessagesCreated = -1; + size_t arrowMessagesDestroyed = -1; + size_t arrowBytesExpired = -1; + size_t shmOfferConsumed = -1; + size_t timeframesRead = -1; +}; + +std::vector<MetricIndices> createDefaultIndices(std::vector<DeviceMetricsInfo>& allDevicesMetrics) +{ + std::vector<MetricIndices> results; + + for (auto& info : allDevicesMetrics) { + MetricIndices indices; + indices.arrowBytesCreated = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "arrow-bytes-created"); + indices.arrowBytesDestroyed = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "arrow-bytes-destroyed"); + indices.arrowMessagesCreated = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "arrow-messages-created"); + indices.arrowMessagesDestroyed = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "arrow-messages-destroyed"); + indices.arrowBytesExpired = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "arrow-bytes-expired"); + indices.shmOfferConsumed = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "shm-offer-bytes-consumed"); + indices.timeframesRead = DeviceMetricsHelper::bookNumericMetric<uint64_t>(info, "df-sent"); + results.push_back(indices); + } + return results; +} + +uint64_t calculateAvailableSharedMemory(ServiceRegistry& registry) +{ + return registry.get<RateLimitConfig>().maxMemory; +} + +o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() +{ + using o2::monitoring::Metric; + using o2::monitoring::Monitoring; + using o2::monitoring::tags::Key; + using o2::monitoring::tags::Value; + + return ServiceSpec{"arrow-backend", + CommonMessageBackendsHelpers<ArrowContext>::createCallback(), + CommonServices::noConfiguration(), + CommonMessageBackendsHelpers<ArrowContext>::clearContext(), + CommonMessageBackendsHelpers<ArrowContext>::sendCallback(), + nullptr, + nullptr, + CommonMessageBackendsHelpers<ArrowContext>::clearContextEOS(), + CommonMessageBackendsHelpers<ArrowContext>::sendCallbackEOS(), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + [](ServiceRegistry& registry, + std::vector<DeviceMetricsInfo>& allDeviceMetrics, + std::vector<DeviceSpec>& specs, + std::vector<DeviceInfo>& infos, + DeviceMetricsInfo& driverMetrics, + size_t timestamp) { + int64_t totalBytesCreated = 0; + int64_t shmOfferConsumed = 0; + int64_t totalBytesDestroyed = 0; + int64_t totalBytesExpired = 0; + int64_t totalMessagesCreated = 0; + int64_t totalMessagesDestroyed = 0; + int64_t totalTimeframesRead = 0; + static RateLimitingState currentState = RateLimitingState::UNKNOWN; + static auto stateMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "rate-limit-state"); + static auto totalBytesCreatedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-bytes-created"); + static auto shmOfferConsumedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-shm-offer-bytes-consumed"); + static auto unusedOfferedMemoryMetric = DeviceMetricsHelper::createNumericMetric<int>(driverMetrics, "total-unusedOfferedMemory"); + static auto availableSharedMemoryMetric = DeviceMetricsHelper::createNumericMetric<int>(driverMetrics, "total-available-shared-memory"); + static auto offeredSharedMemoryMetric = DeviceMetricsHelper::createNumericMetric<int>(driverMetrics, "total-offered-shared-memory"); + static auto totalBytesDestroyedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-bytes-destroyed"); + static auto totalBytesExpiredMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-bytes-expired"); + static auto totalMessagesCreatedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-messages-created"); + static auto totalMessagesDestroyedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-messages-destroyed"); + static auto totalTimeframesReadMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-timeframes-read"); + static auto totalBytesDeltaMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "arrow-bytes-delta"); + static auto totalSignalsMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-reader-signals"); + static auto signalLatencyMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-signal-latency"); + static auto skippedSignalsMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-skipped-signals"); + static auto remainingBytes = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-remaining-bytes"); + static auto timeframesInFly = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "timeframes-in-fly"); + auto& manager = registry.get<DevicesManager>(); + + bool changed = false; + bool hasMetrics = false; + // Find the last timestamp when we signaled. + static size_t signalIndex = DeviceMetricsHelper::metricIdxByName("aod-reader-signals", driverMetrics); + if (signalIndex < driverMetrics.metrics.size()) { + MetricInfo& info = driverMetrics.metrics.at(signalIndex); + } + + size_t lastTimestamp = 0; + size_t firstTimestamp = -1; + size_t lastDecision = 0; + static std::vector<MetricIndices> allIndices = createDefaultIndices(allDeviceMetrics); + for (size_t mi = 0; mi < allDeviceMetrics.size(); ++mi) { + auto& deviceMetrics = allDeviceMetrics[mi]; + auto& indices = allIndices[mi]; + { + size_t index = indices.arrowBytesCreated; + if (index < deviceMetrics.metrics.size()) { + hasMetrics = true; + changed |= deviceMetrics.changed.at(index); + MetricInfo info = deviceMetrics.metrics.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + auto value = (int64_t)data.at((info.pos - 1) % data.size()); + totalBytesCreated += value; + lastTimestamp = std::max(lastTimestamp, deviceMetrics.timestamps[index][(info.pos - 1) % data.size()]); + firstTimestamp = std::min(lastTimestamp, firstTimestamp); + } + } + { + size_t index = indices.shmOfferConsumed; + if (index < deviceMetrics.metrics.size()) { + hasMetrics = true; + changed |= deviceMetrics.changed.at(index); + MetricInfo info = deviceMetrics.metrics.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + auto value = (int64_t)data.at((info.pos - 1) % data.size()); + shmOfferConsumed += value; + lastTimestamp = std::max(lastTimestamp, deviceMetrics.timestamps[index][(info.pos - 1) % data.size()]); + firstTimestamp = std::min(lastTimestamp, firstTimestamp); + } + } + { + size_t index = indices.arrowBytesDestroyed; + if (index < deviceMetrics.metrics.size()) { + hasMetrics = true; + changed |= deviceMetrics.changed.at(index); + MetricInfo info = deviceMetrics.metrics.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + totalBytesDestroyed += (int64_t)data.at((info.pos - 1) % data.size()); + firstTimestamp = std::min(lastTimestamp, firstTimestamp); + } + } + { + size_t index = indices.arrowBytesExpired; + if (index < deviceMetrics.metrics.size()) { + hasMetrics = true; + changed |= deviceMetrics.changed.at(index); + MetricInfo info = deviceMetrics.metrics.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + totalBytesExpired += (int64_t)data.at((info.pos - 1) % data.size()); + firstTimestamp = std::min(lastTimestamp, firstTimestamp); + } + } + { + size_t index = indices.arrowMessagesCreated; + if (index < deviceMetrics.metrics.size()) { + MetricInfo info = deviceMetrics.metrics.at(index); + changed |= deviceMetrics.changed.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + totalMessagesCreated += (int64_t)data.at((info.pos - 1) % data.size()); + } + } + { + size_t index = indices.arrowMessagesDestroyed; + if (index < deviceMetrics.metrics.size()) { + MetricInfo info = deviceMetrics.metrics.at(index); + changed |= deviceMetrics.changed.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + totalMessagesDestroyed += (int64_t)data.at((info.pos - 1) % data.size()); + } + } + { + size_t index = indices.timeframesRead; + if (index < deviceMetrics.metrics.size()) { + MetricInfo info = deviceMetrics.metrics.at(index); + changed |= deviceMetrics.changed.at(index); + auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); + totalTimeframesRead += (int64_t)data.at((info.pos - 1) % data.size()); + } + } + } + if (changed) { + totalBytesCreatedMetric(driverMetrics, totalBytesCreated, timestamp); + totalBytesDestroyedMetric(driverMetrics, totalBytesDestroyed, timestamp); + totalBytesExpiredMetric(driverMetrics, totalBytesExpired, timestamp); + shmOfferConsumedMetric(driverMetrics, shmOfferConsumed, timestamp); + totalMessagesCreatedMetric(driverMetrics, totalMessagesCreated, timestamp); + totalMessagesDestroyedMetric(driverMetrics, totalMessagesDestroyed, timestamp); + totalTimeframesReadMetric(driverMetrics, totalTimeframesRead, timestamp); + totalBytesDeltaMetric(driverMetrics, totalBytesCreated - totalBytesExpired - totalBytesDestroyed, timestamp); + } + bool done = false; + static int stateTransitions = 0; + static int signalsCount = 0; + static int skippedCount = 0; + static uint64_t now = 0; + now = uv_hrtime(); + static RateLimitingState lastReportedState = RateLimitingState::UNKNOWN; + static uint64_t lastReportTime = 0; + static int64_t MAX_SHARED_MEMORY = calculateAvailableSharedMemory(registry); + constexpr int64_t MAX_QUANTUM_SHARED_MEMORY = 100; + constexpr int64_t MIN_QUANTUM_SHARED_MEMORY = 50; + + static int64_t availableSharedMemory = MAX_SHARED_MEMORY; + static int64_t offeredSharedMemory = 0; + static int64_t lastDeviceOffered = 0; + /// We loop over the devices, starting from where we stopped last time + /// offering MIN_QUANTUM_SHARED_MEMORY of shared memory to each reader. + int64_t lastCandidate = -1; + static int enoughSharedMemoryCount = availableSharedMemory - MIN_QUANTUM_SHARED_MEMORY > 0 ? 1 : 0; + static int lowSharedMemoryCount = availableSharedMemory - MIN_QUANTUM_SHARED_MEMORY > 0 ? 0 : 1; + int64_t possibleOffer = MIN_QUANTUM_SHARED_MEMORY; + for (size_t di = 0; di < specs.size(); di++) { + if (availableSharedMemory < possibleOffer) { + if (lowSharedMemoryCount == 0) { + LOGP(INFO, "We do not have enough shared memory ({}MB) to offer {}MB", availableSharedMemory, possibleOffer); + } + lowSharedMemoryCount++; + enoughSharedMemoryCount = 0; + break; + } else { + if (enoughSharedMemoryCount == 0) { + LOGP(INFO, "We are back in a state where we enough shared memory: {}MB", availableSharedMemory); + } + enoughSharedMemoryCount++; + lowSharedMemoryCount = 0; + } + size_t candidate = (lastDeviceOffered + di) % specs.size(); + + auto& spec = specs[candidate]; + auto& info = infos[candidate]; + // Do not bother for inactive devices + // FIXME: there is probably a race condition if the device died and we did not + // took notice yet... + if (info.active == false || info.readyToQuit) { + continue; + } + if (specs[candidate].name != "internal-dpl-aod-reader") { + continue; + } + possibleOffer = std::min(MAX_QUANTUM_SHARED_MEMORY, availableSharedMemory); + LOGP(info, "Offering {}MB out of {} to {}", possibleOffer, availableSharedMemory, specs[candidate].id); + manager.queueMessage(specs[candidate].id.c_str(), fmt::format("/shm-offer {}", possibleOffer).data()); + availableSharedMemory -= possibleOffer; + offeredSharedMemory += possibleOffer; + lastCandidate = candidate; + } + // We had at least a valid candidate, so + // next time we offer to the next device. + if (lastCandidate >= 0) { + lastDeviceOffered = lastCandidate + 1; + } + + // unusedOfferedMemory is the amount of memory which was offered and which we know it was + // not used so far. So we need to account for the amount which got actually read (readerBytesCreated) + // and the amount which we know was given back. + static int64_t lastShmOfferConsumed = 0; + static int64_t lastUnusedOfferedMemory = 0; + if (shmOfferConsumed != lastShmOfferConsumed) { + LOGP(INFO, "Offer consumed so far {}", shmOfferConsumed); + lastShmOfferConsumed = shmOfferConsumed; + } + int unusedOfferedMemory = (offeredSharedMemory - (totalBytesExpired + shmOfferConsumed) / 1000000); + if (lastUnusedOfferedMemory != unusedOfferedMemory) { + LOGP(INFO, "unusedOfferedMemory:{} = offered:{} - (expired:{} + consumed:{}) / 1000000", unusedOfferedMemory, offeredSharedMemory, totalBytesExpired / 1000000, shmOfferConsumed / 1000000); + lastUnusedOfferedMemory = unusedOfferedMemory; + } + // availableSharedMemory is the amount of memory which we know is available to be offered. + // We subtract the amount which we know was already offered but it's unused and we then balance how + // much was created with how much was destroyed. + availableSharedMemory = MAX_SHARED_MEMORY + ((totalBytesDestroyed - totalBytesCreated) / 1000000) - unusedOfferedMemory; + availableSharedMemoryMetric(driverMetrics, availableSharedMemory, timestamp); + unusedOfferedMemoryMetric(driverMetrics, unusedOfferedMemory, timestamp); + + offeredSharedMemoryMetric(driverMetrics, offeredSharedMemory, timestamp); + }, + [](ProcessingContext& ctx, void* service) { + using DataHeader = o2::header::DataHeader; + ArrowContext* arrow = reinterpret_cast<ArrowContext*>(service); + auto totalBytes = 0; + auto totalMessages = 0; + for (auto& input : ctx.inputs()) { + if (input.header == nullptr) { + continue; + } + auto dh = o2::header::get<DataHeader*>(input.header); + if (dh->serialization != o2::header::gSerializationMethodArrow) { + LOGP(DEBUG, "Message {}/{} is not of kind arrow, therefore we are not accounting its shared memory", dh->dataOrigin, dh->dataDescription); + continue; + } + auto dph = o2::header::get<DataProcessingHeader*>(input.header); + bool forwarded = false; + for (auto const& forward : ctx.services().get<DeviceSpec const>().forwards) { + if (DataSpecUtils::match(forward.matcher, dh->dataOrigin, dh->dataDescription, dh->subSpecification)) { + forwarded = true; + break; + } + } + if (forwarded) { + LOGP(DEBUG, "Message {}/{} is forwarded so we are not returning its memory.", dh->dataOrigin, dh->dataDescription); + continue; + } + LOGP(DEBUG, "Message {}/{} is being deleted. We will return {}MB.", dh->dataOrigin, dh->dataDescription, dh->payloadSize / 1000000.); + totalBytes += dh->payloadSize; + totalMessages += 1; + } + arrow->updateBytesDestroyed(totalBytes); + LOGP(DEBUG, "{}MB bytes being given back to reader, totaling {}MB", totalBytes / 1000000., arrow->bytesDestroyed() / 1000000.); + arrow->updateMessagesDestroyed(totalMessages); + auto& monitoring = ctx.services().get<Monitoring>(); + monitoring.send(Metric{(uint64_t)arrow->bytesDestroyed(), "arrow-bytes-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.send(Metric{(uint64_t)arrow->messagesDestroyed(), "arrow-messages-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); + monitoring.flushBuffer(); + }, + nullptr, + nullptr, + [](ServiceRegistry& registry, boost::program_options::variables_map const& vm) { + auto config = new RateLimitConfig{}; + int readers = std::stoll(vm["readers"].as<std::string>()); + if (vm.count("aod-memory-rate-limit") && vm["aod-memory-rate-limit"].defaulted() == false) { + config->maxMemory = std::stoll(vm["aod-memory-rate-limit"].as<std::string>()) / 1000000; + } else { + config->maxMemory = readers * 500; + } + static bool once = false; + // Until we guarantee this is called only once... + if (!once) { + LOGP(INFO, "Rate limiting set up at {}MB distributed over {} readers", config->maxMemory, readers); + registry.registerService(ServiceRegistryHelpers::handleForService<RateLimitConfig>(config)); + once = true; + } + }, + nullptr, + ServiceKind::Global}; +} + +} // namespace o2::framework +#pragma GGC diagnostic pop diff --git a/Framework/Core/src/ArrowSupport.h b/Framework/Core/src/ArrowSupport.h new file mode 100644 index 0000000000000..3b260c0494a79 --- /dev/null +++ b/Framework/Core/src/ArrowSupport.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_ARROWSUPPORT_H_ +#define O2_FRAMEWORK_ARROWSUPPORT_H_ + +#include "Framework/ServiceSpec.h" +#include "Framework/TypeIdHelpers.h" + +namespace o2::framework +{ + +/// A few ServiceSpecs data sending backends +struct ArrowSupport { + // Create spec for backend used to send Arrow messages + static ServiceSpec arrowBackendSpec(); +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_ARROWSUPPORT_H_ diff --git a/Framework/Core/src/Base64.cxx b/Framework/Core/src/Base64.cxx new file mode 100644 index 0000000000000..85b4422e43ee9 --- /dev/null +++ b/Framework/Core/src/Base64.cxx @@ -0,0 +1,238 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Base64.h" + +#include <cstdint> +#include <cstdlib> +#include <cstring> + +#include <cstdio> +#include <cassert> + +namespace o2::framework::internal +{ +static char encoder[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static char decoder[256]; +static int initialized; + +static void + base64_init_decoder() +{ + int i = 0; + + if (initialized) { + return; + } + + // -1 is used for error detection + memset(decoder, -1, sizeof decoder); + + for (; i < 64; decoder[(int)encoder[i]] = i, ++i) { + } + + initialized = 1; + + return; +} + +static int + base64_encsize(int size) +{ + return 4 * ((size + 2) / 3); +} + +int base64_encode(char* dest, int size, unsigned char* src, int slen) +{ + int dlen, i, j; + uint32_t a, b, c, triple; + + dlen = base64_encsize(slen); + + // Sanity checks + if (src == nullptr || dest == nullptr) { + return -1; + } + if (dlen + 1 > size) { + return -1; + } + if (slen == 0) { + if (size > 0) { + dest[0] = 0; + return 0; + } + return -1; + } + + for (i = 0, j = 0; i < slen;) { + a = src[i++]; + + // b and c may be off limit + b = i < slen ? src[i++] : 0; + c = i < slen ? src[i++] : 0; + + triple = (a << 16) + (b << 8) + c; + + dest[j++] = encoder[(triple >> 18) & 0x3F]; + dest[j++] = encoder[(triple >> 12) & 0x3F]; + dest[j++] = encoder[(triple >> 6) & 0x3F]; + dest[j++] = encoder[triple & 0x3F]; + } + + // Pad zeroes at the end + switch (slen % 3) { + case 1: + dest[j - 2] = '='; + case 2: + dest[j - 1] = '='; + } + + // Always add \0 + dest[j] = 0; + + return dlen; +} + +char* base64_enc_malloc(unsigned char* src, int slen) +{ + int size; + char* buffer; + + size = base64_encsize(slen) + 1; + + buffer = (char*)malloc(size); + if (buffer == nullptr) { + return nullptr; + } + + size = base64_encode(buffer, size, src, slen); + if (size == -1) { + free(buffer); + return nullptr; + } + + return buffer; +} + +static int + base64_decsize(char* src) +{ + int slen, size, i; + + if (src == nullptr) { + return 0; + } + + slen = strlen(src); + size = slen / 4 * 3; + + // Count pad chars + for (i = 0; src[slen - i - 1] == '='; ++i) { + } + + // Remove at most 2 bytes. + return size - (i >= 2 ? 2 : i); +} + +int base64_decode(unsigned char* dest, int size, char* src) +{ + int slen, dlen, padlen, i, j; + uint32_t a, b, c, d, triple; + + // Initialize decoder + base64_init_decoder(); + + // Sanity checks + if (src == nullptr || dest == nullptr) { + return -1; + } + + slen = strlen(src); + if (slen == 0) { + if (size > 0) { + dest[0] = 0; + return 0; + } + return -1; + } + + // Remove trailing pad characters. + for (padlen = 0; src[slen - padlen - 1] == '='; ++padlen) { + } + if (padlen > 2) { + slen -= padlen - 2; + } + if (slen % 4) { + return -1; + } + + dlen = base64_decsize(src); + + // Check buffer size + if (dlen + 1 > size) { + return -1; + } + + for (i = 0, j = 0; i < slen;) { + a = decoder[(int)src[i++]]; + b = decoder[(int)src[i++]]; + c = decoder[(int)src[i++]]; + d = decoder[(int)src[i++]]; + + // Sextet 3 and 4 may be zero at the end + if (i == slen) { + if (src[slen - 1] == '=') { + d = 0; + if (src[slen - 2] == '=') { + c = 0; + } + } + } + + // Non-Base64 char + if (a == -1 || b == -1 || c == -1 || d == -1) { + return -1; + } + + triple = (a << 18) + (b << 12) + (c << 6) + d; + + dest[j++] = (triple >> 16) & 0xFF; + dest[j++] = (triple >> 8) & 0xFF; + dest[j++] = triple & 0xFF; + } + + // Always add \0 + dest[j] = 0; + + return dlen; +} + +unsigned char* + base64_dec_malloc(char* src) +{ + int size; + unsigned char* buffer; + + size = base64_decsize(src) + 1; + + buffer = (unsigned char*)malloc(size); + if (buffer == nullptr) { + return nullptr; + } + + size = base64_decode(buffer, size, src); + if (size == -1) { + free(buffer); + return nullptr; + } + + return buffer; +} +} // namespace o2::framework::internal diff --git a/Framework/Core/src/Base64.h b/Framework/Core/src/Base64.h new file mode 100644 index 0000000000000..6920205c2cc97 --- /dev/null +++ b/Framework/Core/src/Base64.h @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_BASE64_H_ +#define O2_FRAMEWORK_BASE64_H_ + +namespace o2::framework::internal +{ +int base64_encode(char* dest, int size, unsigned char* src, int slen); +char* base64_enc_malloc(unsigned char* src, int slen); +int base64_decode(unsigned char* dest, int size, char* src); +unsigned char* base64_dec_malloc(char* src); +} // namespace o2::framework::internal + +#endif // O2_FRAMEWORK_BASE64_H_ diff --git a/Framework/Core/src/BoostOptionsRetriever.cxx b/Framework/Core/src/BoostOptionsRetriever.cxx index df87c691a60b3..63b8c07fbb946 100644 --- a/Framework/Core/src/BoostOptionsRetriever.cxx +++ b/Framework/Core/src/BoostOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,9 +31,9 @@ namespace o2::framework BoostOptionsRetriever::BoostOptionsRetriever(bool ignoreUnknown, int argc, char** argv) : mDescription{std::make_unique<boost::program_options::options_description>("ALICE O2 Framework - Available options")}, - mIgnoreUnknown{ignoreUnknown}, mArgc{argc}, - mArgv{argv} + mArgv{argv}, + mIgnoreUnknown{ignoreUnknown} { } @@ -41,7 +42,7 @@ void BoostOptionsRetriever::update(std::vector<ConfigParamSpec> const& specs, boost::property_tree::ptree& provenance) { auto options = mDescription->add_options(); - for (auto& spec : specs) { + for (const auto& spec : specs) { const char* name = spec.name.c_str(); const char* help = spec.help.c_str(); // FIXME: propagate default value? @@ -49,6 +50,18 @@ void BoostOptionsRetriever::update(std::vector<ConfigParamSpec> const& specs, case VariantType::Int: options = options(name, bpo::value<int>()->default_value(spec.defaultValue.get<int>()), help); break; + case VariantType::UInt8: + options = options(name, bpo::value<int>()->default_value(spec.defaultValue.get<uint8_t>()), help); + break; + case VariantType::UInt16: + options = options(name, bpo::value<int>()->default_value(spec.defaultValue.get<uint16_t>()), help); + break; + case VariantType::UInt32: + options = options(name, bpo::value<int>()->default_value(spec.defaultValue.get<uint32_t>()), help); + break; + case VariantType::UInt64: + options = options(name, bpo::value<int>()->default_value(spec.defaultValue.get<uint64_t>()), help); + break; case VariantType::Int64: options = options(name, bpo::value<int64_t>()->default_value(spec.defaultValue.get<int64_t>()), help); break; @@ -68,6 +81,15 @@ void BoostOptionsRetriever::update(std::vector<ConfigParamSpec> const& specs, case VariantType::ArrayFloat: case VariantType::ArrayDouble: case VariantType::ArrayBool: + case VariantType::ArrayString: + case VariantType::Array2DInt: + case VariantType::Array2DFloat: + case VariantType::Array2DDouble: + options = options(name, bpo::value<std::string>()->default_value(spec.defaultValue.asString()), help); + break; + case VariantType::LabeledArrayInt: + case VariantType::LabeledArrayFloat: + case VariantType::LabeledArrayDouble: case VariantType::Unknown: case VariantType::Empty: break; diff --git a/Framework/Core/src/CCDBParamSpec.cxx b/Framework/Core/src/CCDBParamSpec.cxx new file mode 100644 index 0000000000000..6876bdbe1fd51 --- /dev/null +++ b/Framework/Core/src/CCDBParamSpec.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/CCDBParamSpec.h" +#include <fmt/format.h> +#include <algorithm> + +namespace o2::framework +{ + +ConfigParamSpec ccdbPathSpec(std::string const& path) +{ + return ConfigParamSpec{"ccdb-path", VariantType::String, path, {fmt::format("Path in CCDB ({})", path)}, ConfigParamKind::kGeneric}; +} + +ConfigParamSpec ccdbRunDependent(bool defaultValue) +{ + return ConfigParamSpec{"ccdb-run-dependent", VariantType::Bool, defaultValue, {"Give object for specific run number"}, ConfigParamKind::kGeneric}; +} + +std::vector<ConfigParamSpec> ccdbParamSpec(std::string const& path, bool runDependent) +{ + // Add here CCDB objecs which should be considered run dependent + static std::vector<std::string> runDependentObjects = {"GLO/GRP"}; + if (std::any_of(runDependentObjects.begin(), runDependentObjects.end(), [&path](std::string const& s) { return path == s; })) { + runDependent = true; + } + return {ccdbPathSpec(path), ccdbRunDependent(runDependent)}; +} + +ConfigParamSpec startTimeParamSpec(int64_t t) +{ + return ConfigParamSpec{"start-value-enumeration", VariantType::Int64, t, {fmt::format("start time for enumeration ({})", t)}, ConfigParamKind::kGeneric}; +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ChannelConfigurationPolicy.cxx b/Framework/Core/src/ChannelConfigurationPolicy.cxx index 1e7ad06d89b41..e0e4122ed68e5 100644 --- a/Framework/Core/src/ChannelConfigurationPolicy.cxx +++ b/Framework/Core/src/ChannelConfigurationPolicy.cxx @@ -1,28 +1,34 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/ChannelConfigurationPolicy.h" +#include "Framework/ConfigContext.h" -namespace o2 -{ -namespace framework +namespace o2::framework { -std::vector<ChannelConfigurationPolicy> ChannelConfigurationPolicy::createDefaultPolicies() +std::vector<ChannelConfigurationPolicy> ChannelConfigurationPolicy::createDefaultPolicies(ConfigContext const& configContext) { ChannelConfigurationPolicy defaultPolicy; + FairMQChannelConfigSpec spec; + spec.rateLogging = configContext.options().get<int>("fairmq-rate-logging"); + spec.recvBufferSize = configContext.options().get<int>("fairmq-recv-buffer-size"); + spec.sendBufferSize = configContext.options().get<int>("fairmq-send-buffer-size"); + spec.ipcPrefix = configContext.options().get<std::string>("fairmq-ipc-prefix"); + defaultPolicy.match = ChannelConfigurationPolicyHelpers::matchAny; - defaultPolicy.modifyInput = ChannelConfigurationPolicyHelpers::pullInput; - defaultPolicy.modifyOutput = ChannelConfigurationPolicyHelpers::pushOutput; + defaultPolicy.modifyInput = ChannelConfigurationPolicyHelpers::pullInput(spec); + defaultPolicy.modifyOutput = ChannelConfigurationPolicyHelpers::pushOutput(spec); + return {defaultPolicy}; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/ChannelConfigurationPolicyHelpers.cxx b/Framework/Core/src/ChannelConfigurationPolicyHelpers.cxx index 3c33d1a612d1f..c0821f0567865 100644 --- a/Framework/Core/src/ChannelConfigurationPolicyHelpers.cxx +++ b/Framework/Core/src/ChannelConfigurationPolicyHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,9 +14,7 @@ #include <string> #include "Framework/ChannelSpec.h" -namespace o2 -{ -namespace framework +namespace o2::framework { ChannelConfigurationPolicyHelpers::PolicyMatcher ChannelConfigurationPolicyHelpers::matchAny = @@ -37,41 +36,76 @@ ChannelConfigurationPolicyHelpers::PolicyMatcher ChannelConfigurationPolicyHelpe return [nameString](std::string const&, std::string const& consumerId) -> bool { return consumerId == nameString; }; } -ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::subscribeInput = - [](InputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::subscribeInput(FairMQChannelConfigSpec const& spec) +{ + return [spec](InputChannelSpec& channel) { channel.method = ChannelMethod::Connect; channel.type = ChannelType::Sub; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::publishOutput = - [](OutputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::publishOutput(FairMQChannelConfigSpec const& spec) +{ + return [spec](OutputChannelSpec& channel) { channel.method = ChannelMethod::Bind; channel.type = ChannelType::Pub; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::pullInput = - [](InputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::pullInput(FairMQChannelConfigSpec const& spec) +{ + return [spec](InputChannelSpec& channel) { channel.method = ChannelMethod::Connect; channel.type = ChannelType::Pull; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::pushOutput = - [](OutputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::pushOutput(FairMQChannelConfigSpec const& spec) +{ + return [spec](OutputChannelSpec& channel) { channel.method = ChannelMethod::Bind; channel.type = ChannelType::Push; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::pairInput = - [](InputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::InputChannelModifier ChannelConfigurationPolicyHelpers::pairInput(FairMQChannelConfigSpec const& spec) +{ + return [spec](InputChannelSpec& channel) { channel.method = ChannelMethod::Connect; channel.type = ChannelType::Pair; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::pairOutput = - [](OutputChannelSpec& channel) { +ChannelConfigurationPolicyHelpers::OutputChannelModifier ChannelConfigurationPolicyHelpers::pairOutput(FairMQChannelConfigSpec const& spec) +{ + return [spec](OutputChannelSpec& channel) { channel.method = ChannelMethod::Bind; channel.type = ChannelType::Pair; + channel.rateLogging = spec.rateLogging; + channel.recvBufferSize = spec.recvBufferSize; + channel.sendBufferSize = spec.sendBufferSize; + channel.ipcPrefix = spec.ipcPrefix; }; +} -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/ChannelMatching.cxx b/Framework/Core/src/ChannelMatching.cxx index 16151474dacb8..d3a3f5db0d418 100644 --- a/Framework/Core/src/ChannelMatching.cxx +++ b/Framework/Core/src/ChannelMatching.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ChannelSpecHelpers.cxx b/Framework/Core/src/ChannelSpecHelpers.cxx index 7c04beecb19ea..8e6b6ef82a3d4 100644 --- a/Framework/Core/src/ChannelSpecHelpers.cxx +++ b/Framework/Core/src/ChannelSpecHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,9 +16,9 @@ #if 0 #include <filesystem> namespace fs = std::filesystem; -#elif __has_include(<boost/filesystem.hpp>) -#include <boost/filesystem.hpp> -namespace fs = boost::filesystem; +#elif __has_include(<filesystem>) +#include <filesystem> +namespace fs = std::filesystem; #endif namespace @@ -63,11 +64,25 @@ char const* ChannelSpecHelpers::methodAsString(enum ChannelMethod method) throw runtime_error("Unknown ChannelMethod"); } +namespace +{ +std::string composeIPCName(std::string const& prefix, std::string const& hostname, short port) +{ + if (prefix == "@") { + return fmt::format("ipc://@{}_{},transport=shmem", hostname, port); + } + if (prefix.back() == '/') { + return fmt::format("ipc://{}{}_{},transport=shmem", prefix, hostname, port); + } + return fmt::format("ipc://{}/{}_{},transport=shmem", prefix, hostname, port); +} +} // namespace + std::string ChannelSpecHelpers::channelUrl(OutputChannelSpec const& channel) { switch (channel.protocol) { case ChannelProtocol::IPC: - return fmt::format("ipc://{}/{}_{},transport=shmem", getTmpFolder(), channel.hostname, channel.port); + return composeIPCName(channel.ipcPrefix, channel.hostname, channel.port); default: return channel.method == ChannelMethod::Bind ? fmt::format("tcp://*:{}", channel.port) : fmt::format("tcp://{}:{}", channel.hostname, channel.port); @@ -78,7 +93,7 @@ std::string ChannelSpecHelpers::channelUrl(InputChannelSpec const& channel) { switch (channel.protocol) { case ChannelProtocol::IPC: - return fmt::format("ipc://{}/{}_{},transport=shmem", getTmpFolder(), channel.hostname, channel.port); + return composeIPCName(channel.ipcPrefix, channel.hostname, channel.port); default: return channel.method == ChannelMethod::Bind ? fmt::format("tcp://*:{}", channel.port) : fmt::format("tcp://{}:{}", channel.hostname, channel.port); diff --git a/Framework/Core/src/ChannelSpecHelpers.h b/Framework/Core/src/ChannelSpecHelpers.h index 41276e50a2f90..78e43c30f58a4 100644 --- a/Framework/Core/src/ChannelSpecHelpers.h +++ b/Framework/Core/src/ChannelSpecHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/CommandInfo.cxx b/Framework/Core/src/CommandInfo.cxx new file mode 100644 index 0000000000000..7127ecdc3c8ca --- /dev/null +++ b/Framework/Core/src/CommandInfo.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/CommandInfo.h" + +#include <sstream> +#include <cassert> +#include <cstring> + +namespace o2::framework +{ + +CommandInfo::CommandInfo(int argc, char* const* argv) +{ + assert(argc > 0); + + std::stringstream commandStream; + commandStream << argv[0]; + + for (size_t ai = 1; ai < argc; ++ai) { + const char* arg = argv[ai]; + if (strpbrk(arg, "\" ;@") != nullptr || arg[0] == 0) { + commandStream << " '" << arg << "'"; + } else if (strpbrk(arg, "'") != nullptr) { + commandStream << " \"" << arg << "\""; + } else { + commandStream << " " << arg; + } + } + command = commandStream.str(); +} + +void CommandInfo::merge(CommandInfo const& other) +{ + if (!command.empty()) { + command += " | "; + } + command += other.command; +} + +} // namespace o2::framework \ No newline at end of file diff --git a/Framework/Core/src/CommonDataProcessors.cxx b/Framework/Core/src/CommonDataProcessors.cxx index 5132375603223..756ca03a01059 100644 --- a/Framework/Core/src/CommonDataProcessors.cxx +++ b/Framework/Core/src/CommonDataProcessors.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "Framework/DataProcessingHeader.h" #include "Framework/DataDescriptorQueryBuilder.h" #include "Framework/DataDescriptorMatcher.h" +#include "Framework/DataOutputDirector.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" #include "Framework/TableBuilder.h" @@ -47,6 +49,8 @@ #include <string> #include <thread> +template class std::vector<o2::framework::OutputObjectInfo>; +template class std::vector<o2::framework::OutputTaskInfo>; using namespace o2::framework::data_matcher; namespace o2 @@ -60,6 +64,7 @@ struct InputObjectRoute { std::string directory; uint32_t taskHash; OutputObjHandlingPolicy policy; + OutputObjSourceType sourceType; }; struct InputObject { @@ -72,7 +77,7 @@ const static std::unordered_map<OutputObjHandlingPolicy, std::string> ROOTfileNa {OutputObjHandlingPolicy::QAObject, "QAResults.root"}}; // ============================================================================= -DataProcessorSpec CommonDataProcessors::getOutputObjHistSink(outputObjects const& objmap, outputTasks const& tskmap) +DataProcessorSpec CommonDataProcessors::getOutputObjHistSink(std::vector<OutputObjectInfo> const& objmap, std::vector<OutputTaskInfo> const& tskmap) { auto writerFunction = [objmap, tskmap](InitContext& ic) -> std::function<void(ProcessingContext&)> { auto& callbacks = ic.services().get<CallbackService>(); @@ -123,8 +128,7 @@ DataProcessorSpec CommonDataProcessors::getOutputObjHistSink(outputObjects const }; TDirectory* currentDir = f[route.policy]->GetDirectory(currentDirectory.c_str()); - TNamed* named = static_cast<TNamed*>(entry.obj); - if (named->InheritsFrom(TList::Class())) { + if (route.sourceType == OutputObjSourceType::HistogramRegistrySource) { TList* outputList = (TList*)entry.obj; outputList->SetOwner(false); @@ -185,29 +189,30 @@ DataProcessorSpec CommonDataProcessors::getOutputObjHistSink(outputObjects const } auto policy = objh->mPolicy; + auto sourceType = objh->mSourceType; auto hash = objh->mTaskHash; obj.obj = tm.ReadObjectAny(obj.kind); TNamed* named = static_cast<TNamed*>(obj.obj); obj.name = named->GetName(); - auto hpos = std::find_if(tskmap.begin(), tskmap.end(), [&](auto&& x) { return x.first == hash; }); + auto hpos = std::find_if(tskmap.begin(), tskmap.end(), [&](auto&& x) { return x.id == hash; }); if (hpos == tskmap.end()) { LOG(ERROR) << "No task found for hash " << hash; return; } - auto taskname = hpos->second; - auto opos = std::find_if(objmap.begin(), objmap.end(), [&](auto&& x) { return x.first == hash; }); + auto taskname = hpos->name; + auto opos = std::find_if(objmap.begin(), objmap.end(), [&](auto&& x) { return x.id == hash; }); if (opos == objmap.end()) { LOG(ERROR) << "No object list found for task " << taskname << " (hash=" << hash << ")"; return; } - auto objects = opos->second; + auto objects = opos->bindings; if (std::find(objects.begin(), objects.end(), obj.name) == objects.end()) { LOG(ERROR) << "No object " << obj.name << " in map for task " << taskname; return; } auto nameHash = compile_time_hash(obj.name.c_str()); - InputObjectRoute key{obj.name, nameHash, taskname, hash, policy}; + InputObjectRoute key{obj.name, nameHash, taskname, hash, policy, sourceType}; auto existing = std::find_if(inputObjects->begin(), inputObjects->end(), [&](auto&& x) { return (x.first.uniqueId == nameHash) && (x.first.taskHash == hash); }); if (existing == inputObjects->end()) { inputObjects->push_back(std::make_pair(key, obj)); @@ -306,8 +311,8 @@ DataProcessorSpec // loop over the DataRefs which are contained in pc.inputs() for (const auto& ref : pc.inputs()) { - if (!ref.spec || !ref.payload) { - LOGP(WARNING, "The input \"{}\" is not valid and will be skipped!", ref.spec->binding); + if (!ref.spec) { + LOGP(DEBUG, "The input \"{}\" is not valid and will be skipped!", ref.spec->binding); continue; } @@ -319,53 +324,59 @@ DataProcessorSpec // does this need to be saved? auto dh = DataRefUtils::getHeader<header::DataHeader*>(ref); + auto tableName = std::string(dh->dataDescription.str); auto ds = dod->getDataOutputDescriptors(*dh); - if (ds.size() > 0) { + if (ds.size() <= 0) { + continue; + } - // get TF number fro startTime - auto it = tfNumbers.find(startTime); - if (it != tfNumbers.end()) { - tfNumber = (it->second / dod->getNumberTimeFramesToMerge()) * dod->getNumberTimeFramesToMerge(); - } else { - LOGP(FATAL, "No time frame number found for output with start time {}", startTime); - throw std::runtime_error("Processing is stopped!"); - } + // get TF number fro startTime + auto it = tfNumbers.find(startTime); + if (it != tfNumbers.end()) { + tfNumber = (it->second / dod->getNumberTimeFramesToMerge()) * dod->getNumberTimeFramesToMerge(); + } else { + LOGP(FATAL, "No time frame number found for output with start time {}", startTime); + throw std::runtime_error("Processing is stopped!"); + } - // get the TableConsumer and corresponding arrow table - auto s = pc.inputs().get<TableConsumer>(ref.spec->binding); - auto table = s->asArrowTable(); - if (!table->Validate().ok()) { - LOGP(WARNING, "The table \"{}\" is not valid and will not be saved!", dh->description.str); - continue; - } else if (table->num_rows() <= 0) { - LOGP(WARNING, "The table \"{}\" is empty but will be saved anyway!", dh->description.str); - } + // get the TableConsumer and corresponding arrow table + auto msg = pc.inputs().get(ref.spec->binding); + if (msg.header == nullptr) { + LOGP(ERROR, "No header for message {}:{}", ref.spec->binding, *ref.spec); + continue; + } + auto s = pc.inputs().get<TableConsumer>(ref.spec->binding); + auto table = s->asArrowTable(); + if (!table->Validate().ok()) { + LOGP(WARNING, "The table \"{}\" is not valid and will not be saved!", tableName); + continue; + } else if (table->schema()->fields().empty() == true) { + LOGP(DEBUG, "The table \"{}\" is empty but will be saved anyway!", tableName); + } - // loop over all DataOutputDescriptors - // a table can be saved in multiple ways - // e.g. different selections of columns to different files - for (auto d : ds) { - - auto fileAndFolder = dod->getFileFolder(d, tfNumber); - auto treename = fileAndFolder.folderName + d->treename; - TableToTree ta2tr(table, - fileAndFolder.file, - treename.c_str()); - - if (d->colnames.size() > 0) { - for (auto cn : d->colnames) { - auto idx = table->schema()->GetFieldIndex(cn); - auto col = table->column(idx); - auto field = table->schema()->field(idx); - if (idx != -1) { - ta2tr.addBranch(col, field); - } + // loop over all DataOutputDescriptors + // a table can be saved in multiple ways + // e.g. different selections of columns to different files + for (auto d : ds) { + auto fileAndFolder = dod->getFileFolder(d, tfNumber); + auto treename = fileAndFolder.folderName + d->treename; + TableToTree ta2tr(table, + fileAndFolder.file, + treename.c_str()); + + if (d->colnames.size() > 0) { + for (auto cn : d->colnames) { + auto idx = table->schema()->GetFieldIndex(cn); + auto col = table->column(idx); + auto field = table->schema()->field(idx); + if (idx != -1) { + ta2tr.addBranch(col, field); } - } else { - ta2tr.addAllBranches(); } - ta2tr.process(); + } else { + ta2tr.addAllBranches(); } + ta2tr.process(); } } }); @@ -449,7 +460,7 @@ DataProcessorSpec std::back_inserter(unmatched), noTimeframe); DataProcessorSpec spec{ - "internal-dpl-global-binary-file-sink", + "internal-dpl-injected-global-binary-file-sink", validBinaryInputs, Outputs{}, AlgorithmSpec(writerFunction), diff --git a/Framework/Core/src/CommonDriverServices.cxx b/Framework/Core/src/CommonDriverServices.cxx new file mode 100644 index 0000000000000..aa65348f8fc99 --- /dev/null +++ b/Framework/Core/src/CommonDriverServices.cxx @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonDriverServices.h" +#include "Framework/CommonServices.h" + +// Make sure we can use aggregated initialisers. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + +namespace o2::framework +{ + +std::vector<ServiceSpec> o2::framework::CommonDriverServices::defaultServices() +{ + return { + CommonServices::configurationSpec()}; +} +} // namespace o2::framework + +#pragma GCC diagnostic pop diff --git a/Framework/Core/src/CommonDriverServices.h b/Framework/Core/src/CommonDriverServices.h new file mode 100644 index 0000000000000..56b00010b1ebc --- /dev/null +++ b/Framework/Core/src/CommonDriverServices.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_COMMONDRIVERSERVICES_H_ +#define O2_FRAMEWORK_COMMONDRIVERSERVICES_H_ + +#include "Framework/ServiceSpec.h" +#include <vector> + +namespace o2::framework +{ +struct CommonDriverServices { + static std::vector<ServiceSpec> defaultServices(); +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_COMMONDRIVERSERVICES_H_ diff --git a/Framework/Core/src/CommonMessageBackends.cxx b/Framework/Core/src/CommonMessageBackends.cxx index c2a855820d36c..797c36daea765 100644 --- a/Framework/Core/src/CommonMessageBackends.cxx +++ b/Framework/Core/src/CommonMessageBackends.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,8 @@ #include "Framework/DeviceMetricsInfo.h" #include "Framework/DeviceInfo.h" +#include "CommonMessageBackendsHelpers.h" + #include <Monitoring/Monitoring.h> #include <Headers/DataHeader.h> @@ -30,389 +33,75 @@ #include <boost/program_options/variables_map.hpp> #include <csignal> +// This is to allow C++20 aggregate initialisation +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + namespace o2::framework { struct EndOfStreamContext; struct ProcessingContext; -namespace -{ -template <typename T> -struct CommonMessageBackendsHelpers { - static ServiceInit createCallback() - { - return [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) { - auto& device = services.get<RawDeviceService>(); - return ServiceHandle{TypeIdHelpers::uniqueId<T>(), new T(FairMQDeviceProxy{device.device()})}; - }; - } - - static ServiceProcessingCallback sendCallback() - { - return [](ProcessingContext& ctx, void* service) { - ZoneScopedN("send message callback"); - T* context = reinterpret_cast<T*>(service); - auto& device = ctx.services().get<RawDeviceService>(); - DataProcessor::doSend(*device.device(), *context, ctx.services()); - }; - } - - static ServiceProcessingCallback clearContext() - { - return [](ProcessingContext&, void* service) { - T* context = reinterpret_cast<T*>(service); - context->clear(); - }; - } - - static ServiceEOSCallback clearContextEOS() - { - return [](EndOfStreamContext&, void* service) { - T* context = reinterpret_cast<T*>(service); - context->clear(); - }; - } - - static ServiceEOSCallback sendCallbackEOS() - { - return [](EndOfStreamContext& ctx, void* service) { - T* context = reinterpret_cast<T*>(service); - auto& device = ctx.services().get<RawDeviceService>(); - DataProcessor::doSend(*device.device(), *context, ctx.services()); - }; - } -}; -} // namespace - -enum struct RateLimitingState { - UNKNOWN = 0, // No information received yet. - STARTED = 1, // Information received, new timeframe not requested. - CHANGED = 2, // Information received, new timeframe requested but not yet accounted. - BELOW_LIMIT = 3, // New metric received, we are below limit. - NEXT_ITERATION_FROM_BELOW = 4, // Iteration when previously in BELOW_LIMIT. - ABOVE_LIMIT = 5, // New metric received, we are above limit. -}; - -struct RateLimitConfig { - int64_t maxMemory = 0; -}; - -static int64_t memLimit = 0; - -/// Service for common handling of rate limiting -o2::framework::ServiceSpec CommonMessageBackends::rateLimitingSpec() -{ - return ServiceSpec{"aod-rate-limiting", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) { - return ServiceHandle{TypeIdHelpers::uniqueId<RateLimitConfig>(), new RateLimitConfig{}}; - }, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - [](ServiceRegistry& registry, boost::program_options::variables_map const& vm) { - if (!vm["aod-memory-rate-limit"].defaulted()) { - memLimit = std::stoll(vm["aod-memory-rate-limit"].as<std::string const>()); - // registry.registerService(ServiceRegistryHelpers::handleForService<RateLimitConfig>(new RateLimitConfig{memLimit})); - } - }, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; -} - -o2::framework::ServiceSpec CommonMessageBackends::arrowBackendSpec() -{ - using o2::monitoring::Metric; - using o2::monitoring::Monitoring; - using o2::monitoring::tags::Key; - using o2::monitoring::tags::Value; - - return ServiceSpec{"arrow-backend", - CommonMessageBackendsHelpers<ArrowContext>::createCallback(), - CommonServices::noConfiguration(), - CommonMessageBackendsHelpers<ArrowContext>::clearContext(), - CommonMessageBackendsHelpers<ArrowContext>::sendCallback(), - nullptr, - nullptr, - CommonMessageBackendsHelpers<ArrowContext>::clearContextEOS(), - CommonMessageBackendsHelpers<ArrowContext>::sendCallbackEOS(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - [](ServiceRegistry& registry, - std::vector<DeviceMetricsInfo>& allDeviceMetrics, - std::vector<DeviceSpec>& specs, - std::vector<DeviceInfo>& infos, - DeviceMetricsInfo& driverMetrics, - size_t timestamp) { - int64_t totalBytesCreated = 0; - int64_t totalBytesDestroyed = 0; - int64_t totalMessagesCreated = 0; - int64_t totalMessagesDestroyed = 0; - static RateLimitingState currentState = RateLimitingState::UNKNOWN; - static auto stateMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "rate-limit-state"); - static auto totalBytesCreatedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-bytes-created"); - static auto totalBytesDestroyedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-bytes-destroyed"); - static auto totalMessagesCreatedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-messages-created"); - static auto totalMessagesDestroyedMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "total-arrow-messages-destroyed"); - static auto totalBytesDeltaMetric = DeviceMetricsHelper::createNumericMetric<int>(driverMetrics, "arrow-bytes-delta"); - static auto totalSignalsMetric = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-reader-signals"); - static auto remainingBytes = DeviceMetricsHelper::createNumericMetric<uint64_t>(driverMetrics, "aod-remaining-bytes"); - - bool changed = false; - bool hasMetrics = false; - // Find the last timestamp when we signaled. - size_t signalIndex = DeviceMetricsHelper::metricIdxByName("aod-reader-signals", driverMetrics); - size_t lastSignalTimestamp = 0; - if (signalIndex < driverMetrics.metrics.size()) { - MetricInfo info = driverMetrics.metrics.at(signalIndex); - lastSignalTimestamp = driverMetrics.timestamps[signalIndex][info.pos - 1]; - } - - size_t lastCreatedBytesTimestamp = 0; - size_t lastDestroyedBytesTimestamp = 0; - for (auto& deviceMetrics : allDeviceMetrics) { - { - size_t index = DeviceMetricsHelper::metricIdxByName("arrow-bytes-created", deviceMetrics); - if (index < deviceMetrics.metrics.size()) { - hasMetrics = true; - changed |= deviceMetrics.changed.at(index); - MetricInfo info = deviceMetrics.metrics.at(index); - auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); - totalBytesCreated += (int64_t)data.at((info.pos - 1) % data.size()); - lastCreatedBytesTimestamp = deviceMetrics.timestamps[index][info.pos - 1]; - } - } - { - size_t index = DeviceMetricsHelper::metricIdxByName("arrow-bytes-destroyed", deviceMetrics); - if (index < deviceMetrics.metrics.size()) { - hasMetrics = true; - changed |= deviceMetrics.changed.at(index); - MetricInfo info = deviceMetrics.metrics.at(index); - auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); - totalBytesDestroyed += (int64_t)data.at((info.pos - 1) % data.size()); - lastDestroyedBytesTimestamp = deviceMetrics.timestamps[index][info.pos - 1]; - } - } - { - size_t index = DeviceMetricsHelper::metricIdxByName("arrow-messages-created", deviceMetrics); - if (index < deviceMetrics.metrics.size()) { - MetricInfo info = deviceMetrics.metrics.at(index); - auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); - totalMessagesCreated += (int64_t)data.at((info.pos - 1) % data.size()); - } - } - { - size_t index = DeviceMetricsHelper::metricIdxByName("arrow-messages-destroyed", deviceMetrics); - if (index < deviceMetrics.metrics.size()) { - MetricInfo info = deviceMetrics.metrics.at(index); - auto& data = deviceMetrics.uint64Metrics.at(info.storeIdx); - totalMessagesDestroyed += (int64_t)data.at((info.pos - 1) % data.size()); - } - } - } - if (changed) { - totalBytesCreatedMetric(driverMetrics, totalBytesCreated, timestamp); - totalBytesDestroyedMetric(driverMetrics, totalBytesDestroyed, timestamp); - totalMessagesCreatedMetric(driverMetrics, totalMessagesCreated, timestamp); - totalMessagesDestroyedMetric(driverMetrics, totalMessagesDestroyed, timestamp); - totalBytesDeltaMetric(driverMetrics, totalBytesCreated - totalBytesDestroyed, timestamp); - } - bool done = false; - static int stateTransitions = 0; - while (!done) { - stateMetric(driverMetrics, (uint64_t)(currentState), stateTransitions++); - switch (currentState) { - case RateLimitingState::UNKNOWN: { - for (auto& deviceMetrics : allDeviceMetrics) { - size_t index = DeviceMetricsHelper::metricIdxByName("arrow-bytes-created", deviceMetrics); - if (index < deviceMetrics.metrics.size()) { - currentState = RateLimitingState::STARTED; - } - } - done = true; - } break; - case RateLimitingState::STARTED: { - for (size_t di = 0; di < specs.size(); ++di) { - if (specs[di].name == "internal-dpl-aod-reader") { - if (di < infos.size()) { - kill(infos[di].pid, SIGUSR1); - totalSignalsMetric(driverMetrics, 1, timestamp); - } - } - } - changed = false; - currentState = RateLimitingState::CHANGED; - } break; - case RateLimitingState::CHANGED: { - remainingBytes(driverMetrics, totalBytesCreated <= (totalBytesDestroyed + memLimit) ? (totalBytesDestroyed + memLimit) - totalBytesCreated : 0, timestamp); - if (totalBytesCreated <= (totalBytesDestroyed + memLimit)) { - currentState = RateLimitingState::BELOW_LIMIT; - } else { - currentState = RateLimitingState::ABOVE_LIMIT; - } - changed = false; - } break; - case RateLimitingState::BELOW_LIMIT: { - for (size_t di = 0; di < specs.size(); ++di) { - if (specs[di].name == "internal-dpl-aod-reader") { - if (di < infos.size()) { - kill(infos[di].pid, SIGUSR1); - totalSignalsMetric(driverMetrics, 1, timestamp); - } - } - } - changed = false; - currentState = RateLimitingState::NEXT_ITERATION_FROM_BELOW; - } break; - case RateLimitingState::NEXT_ITERATION_FROM_BELOW: { - if (!changed) { - done = true; - } else { - currentState = RateLimitingState::CHANGED; - } - } break; - case RateLimitingState::ABOVE_LIMIT: { - if (!changed) { - done = true; - } else if (totalBytesCreated > (totalBytesDestroyed + memLimit / 3)) { - done = true; - } else { - currentState = RateLimitingState::CHANGED; - } - }; - }; - } - }, - [](ProcessingContext& ctx, void* service) { - using DataHeader = o2::header::DataHeader; - ArrowContext* arrow = reinterpret_cast<ArrowContext*>(service); - auto totalBytes = 0; - auto totalMessages = 0; - for (auto& input : ctx.inputs()) { - if (input.header == nullptr) { - continue; - } - auto dh = o2::header::get<DataHeader*>(input.header); - if (dh->serialization != o2::header::gSerializationMethodArrow) { - continue; - } - auto dph = o2::header::get<DataProcessingHeader*>(input.header); - bool forwarded = false; - for (auto const& forward : ctx.services().get<DeviceSpec const>().forwards) { - if (DataSpecUtils::match(forward.matcher, dh->dataOrigin, dh->dataDescription, dh->subSpecification)) { - forwarded = true; - break; - } - } - if (forwarded) { - continue; - } - totalBytes += dh->payloadSize; - totalMessages += 1; - } - arrow->updateBytesDestroyed(totalBytes); - arrow->updateMessagesDestroyed(totalMessages); - auto& monitoring = ctx.services().get<Monitoring>(); - monitoring.send(Metric{(uint64_t)arrow->bytesDestroyed(), "arrow-bytes-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.send(Metric{(uint64_t)arrow->messagesDestroyed(), "arrow-messages-destroyed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL)); - monitoring.flushBuffer(); - }, - ServiceKind::Serial}; -} - o2::framework::ServiceSpec CommonMessageBackends::fairMQBackendSpec() { - return ServiceSpec{"fairmq-backend", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle { - auto& device = services.get<RawDeviceService>(); - auto context = new MessageContext(FairMQDeviceProxy{device.device()}); - auto& spec = services.get<DeviceSpec const>(); - - auto dispatcher = [&device](FairMQParts&& parts, std::string const& channel, unsigned int index) { - DataProcessor::doSend(*device.device(), std::move(parts), channel.c_str(), index); - }; - - auto matcher = [policy = spec.dispatchPolicy](o2::header::DataHeader const& header) { - if (policy.triggerMatcher == nullptr) { - return true; - } - return policy.triggerMatcher(Output{header}); - }; - - if (spec.dispatchPolicy.action == DispatchPolicy::DispatchOp::WhenReady) { - context->init(DispatchControl{dispatcher, matcher}); - } - return ServiceHandle{TypeIdHelpers::uniqueId<MessageContext>(), context}; - }, - CommonServices::noConfiguration(), - CommonMessageBackendsHelpers<MessageContext>::clearContext(), - CommonMessageBackendsHelpers<MessageContext>::sendCallback(), - nullptr, - nullptr, - CommonMessageBackendsHelpers<MessageContext>::clearContextEOS(), - CommonMessageBackendsHelpers<MessageContext>::sendCallbackEOS(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "fairmq-backend", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle { + auto& device = services.get<RawDeviceService>(); + auto context = new MessageContext(FairMQDeviceProxy{device.device()}); + auto& spec = services.get<DeviceSpec const>(); + + auto dispatcher = [&device](FairMQParts&& parts, std::string const& channel, unsigned int index) { + DataProcessor::doSend(*device.device(), std::move(parts), channel.c_str(), index); + }; + + auto matcher = [policy = spec.dispatchPolicy](o2::header::DataHeader const& header) { + if (policy.triggerMatcher == nullptr) { + return true; + } + return policy.triggerMatcher(Output{header}); + }; + + if (spec.dispatchPolicy.action == DispatchPolicy::DispatchOp::WhenReady) { + context->init(DispatchControl{dispatcher, matcher}); + } + return ServiceHandle{TypeIdHelpers::uniqueId<MessageContext>(), context}; + }, + .configure = CommonServices::noConfiguration(), + .preProcessing = CommonMessageBackendsHelpers<MessageContext>::clearContext(), + .postProcessing = CommonMessageBackendsHelpers<MessageContext>::sendCallback(), + .preEOS = CommonMessageBackendsHelpers<MessageContext>::clearContextEOS(), + .postEOS = CommonMessageBackendsHelpers<MessageContext>::sendCallbackEOS(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonMessageBackends::stringBackendSpec() { - return ServiceSpec{"string-backend", - CommonMessageBackendsHelpers<StringContext>::createCallback(), - CommonServices::noConfiguration(), - CommonMessageBackendsHelpers<StringContext>::clearContext(), - CommonMessageBackendsHelpers<StringContext>::sendCallback(), - nullptr, - nullptr, - CommonMessageBackendsHelpers<StringContext>::clearContextEOS(), - CommonMessageBackendsHelpers<StringContext>::sendCallbackEOS(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "string-backend", + .init = CommonMessageBackendsHelpers<StringContext>::createCallback(), + .configure = CommonServices::noConfiguration(), + .preProcessing = CommonMessageBackendsHelpers<StringContext>::clearContext(), + .postProcessing = CommonMessageBackendsHelpers<StringContext>::sendCallback(), + .preEOS = CommonMessageBackendsHelpers<StringContext>::clearContextEOS(), + .postEOS = CommonMessageBackendsHelpers<StringContext>::sendCallbackEOS(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonMessageBackends::rawBufferBackendSpec() { - return ServiceSpec{"raw-backend", - CommonMessageBackendsHelpers<RawBufferContext>::createCallback(), - CommonServices::noConfiguration(), - CommonMessageBackendsHelpers<RawBufferContext>::clearContext(), - CommonMessageBackendsHelpers<RawBufferContext>::sendCallback(), - nullptr, - nullptr, - CommonMessageBackendsHelpers<RawBufferContext>::clearContextEOS(), - CommonMessageBackendsHelpers<RawBufferContext>::sendCallbackEOS(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "raw-backend", + .init = CommonMessageBackendsHelpers<RawBufferContext>::createCallback(), + .configure = CommonServices::noConfiguration(), + .preProcessing = CommonMessageBackendsHelpers<RawBufferContext>::clearContext(), + .postProcessing = CommonMessageBackendsHelpers<RawBufferContext>::sendCallback(), + .preEOS = CommonMessageBackendsHelpers<RawBufferContext>::clearContextEOS(), + .postEOS = CommonMessageBackendsHelpers<RawBufferContext>::sendCallbackEOS(), + .kind = ServiceKind::Serial}; } } // namespace o2::framework + +#pragma GCC diagnostic pop diff --git a/Framework/Core/src/CommonMessageBackendsHelpers.h b/Framework/Core/src/CommonMessageBackendsHelpers.h new file mode 100644 index 0000000000000..06e3dffcd2d18 --- /dev/null +++ b/Framework/Core/src/CommonMessageBackendsHelpers.h @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_COMMONMESSAGEBACKENDSHELPERS_H_ +#define O2_FRAMEWORK_COMMONMESSAGEBACKENDSHELPERS_H_ + +#include "Framework/RawDeviceService.h" +#include "Framework/DataProcessor.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/Tracing.h" + +#include <options/FairMQProgOptions.h> + +namespace o2::framework +{ + +template <typename T> +struct CommonMessageBackendsHelpers { + static ServiceInit createCallback() + { + return [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) { + auto& device = services.get<RawDeviceService>(); + return ServiceHandle{TypeIdHelpers::uniqueId<T>(), new T(FairMQDeviceProxy{device.device()})}; + }; + } + + static ServiceProcessingCallback sendCallback() + { + return [](ProcessingContext& ctx, void* service) { + ZoneScopedN("send message callback"); + T* context = reinterpret_cast<T*>(service); + auto& device = ctx.services().get<RawDeviceService>(); + DataProcessor::doSend(*device.device(), *context, ctx.services()); + }; + } + + static ServiceProcessingCallback clearContext() + { + return [](ProcessingContext&, void* service) { + T* context = reinterpret_cast<T*>(service); + context->clear(); + }; + } + + static ServiceEOSCallback clearContextEOS() + { + return [](EndOfStreamContext&, void* service) { + T* context = reinterpret_cast<T*>(service); + context->clear(); + }; + } + + static ServiceEOSCallback sendCallbackEOS() + { + return [](EndOfStreamContext& ctx, void* service) { + T* context = reinterpret_cast<T*>(service); + auto& device = ctx.services().get<RawDeviceService>(); + DataProcessor::doSend(*device.device(), *context, ctx.services()); + }; + } +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_COMMONMESSAGEBACKENDSHELPERS_H_ diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index f92114b1de2bd..67002503daf78 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -1,17 +1,21 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/CommonServices.h" #include "Framework/ParallelContext.h" -#include "Framework/TextControlService.h" +#include "Framework/ControlService.h" +#include "Framework/DriverClient.h" #include "Framework/CallbackService.h" +#include "Framework/ServiceSpec.h" #include "Framework/TimesliceIndex.h" +#include "Framework/DataTakingContext.h" #include "Framework/ServiceRegistry.h" #include "Framework/DeviceSpec.h" #include "Framework/LocalRootFileService.h" @@ -20,19 +24,29 @@ #include "Framework/DataProcessingStats.h" #include "Framework/CommonMessageBackends.h" #include "Framework/DanglingContext.h" +#include "InputRouteHelpers.h" #include "Framework/EndOfStreamContext.h" +#include "Framework/RawDeviceService.h" #include "Framework/Tracing.h" #include "Framework/Monitoring.h" +#include "TextDriverClient.h" +#include "WSDriverClient.h" +#include "HTTPParser.h" #include "../src/DataProcessingStatus.h" +#include "ArrowSupport.h" +#include "DPLMonitoringBackend.h" +#include "TDatabasePDG.h" #include <Configuration/ConfigurationInterface.h> #include <Configuration/ConfigurationFactory.h> #include <Monitoring/MonitoringFactory.h> #include <InfoLogger/InfoLogger.hxx> +#include <FairMQDevice.h> #include <options/FairMQProgOptions.h> #include <cstdlib> +#include <cstring> using AliceO2::InfoLogger::InfoLogger; using AliceO2::InfoLogger::InfoLoggerContext; @@ -44,6 +58,10 @@ using Metric = o2::monitoring::Metric; using Key = o2::monitoring::tags::Key; using Value = o2::monitoring::tags::Value; +// This is to allow C++20 aggregate initialisation +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + namespace o2::framework { @@ -53,49 +71,110 @@ struct ServiceKindExtractor<InfoLoggerContext> { constexpr static ServiceKind kind = ServiceKind::Global; }; +#define MONITORING_QUEUE_SIZE 100 o2::framework::ServiceSpec CommonServices::monitoringSpec() { - return ServiceSpec{"monitoring", - [](ServiceRegistry&, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { - void* service = MonitoringFactory::Get(options.GetPropertyAsString("monitoring-backend")).release(); - return ServiceHandle{TypeIdHelpers::uniqueId<Monitoring>(), service}; - }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "monitoring", + .init = [](ServiceRegistry& registry, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + void* service = nullptr; + bool isWebsocket = strncmp(options.GetPropertyAsString("driver-client-backend").c_str(), "ws://", 4) == 0; + bool isDefault = options.GetPropertyAsString("monitoring-backend") == "default"; + bool useDPL = (isWebsocket && isDefault) || options.GetPropertyAsString("monitoring-backend") == "dpl://"; + o2::monitoring::Monitoring* monitoring; + if (useDPL) { + monitoring = new Monitoring(); + auto dplBackend = std::make_unique<DPLMonitoringBackend>(registry); + (dynamic_cast<o2::monitoring::Backend*>(dplBackend.get()))->setVerbosity(o2::monitoring::Verbosity::Debug); + monitoring->addBackend(std::move(dplBackend)); + } else { + auto backend = isDefault ? "infologger://" : options.GetPropertyAsString("monitoring-backend"); + monitoring = MonitoringFactory::Get(backend).release(); + } + service = monitoring; + monitoring->enableBuffering(MONITORING_QUEUE_SIZE); + assert(registry.get<DeviceSpec const>().name.empty() == false); + monitoring->addGlobalTag("dataprocessor_id", registry.get<DeviceSpec const>().name); + try { + auto run = registry.get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("runNumber", "unspecified"); + monitoring->setRunNumber(stoul(run)); + } catch (...) { + } + return ServiceHandle{TypeIdHelpers::uniqueId<Monitoring>(), service}; + }, + .configure = noConfiguration(), + .exit = [](ServiceRegistry& registry, void* service) { + Monitoring* monitoring = reinterpret_cast<Monitoring*>(service); + delete monitoring; }, + .kind = ServiceKind::Serial}; +} + +o2::framework::ServiceSpec CommonServices::datatakingContextSpec() +{ + return ServiceSpec{ + .name = "datataking-contex", + .init = simpleServiceInit<DataTakingContext, DataTakingContext>(), + .configure = noConfiguration(), + .preProcessing = [](ProcessingContext& processingContext, void* service) { + auto& context = processingContext.services().get<DataTakingContext>(); + // Only on the first message + if (context.source == OrbitResetTimeSource::Data) { + return; + } + // Only if we do not have already the proper number from CTP + if (context.source == OrbitResetTimeSource::CTP) { + return; + } + context.source = OrbitResetTimeSource::Data; + context.orbitResetTime = -1; + for (auto const& ref : processingContext.inputs()) { + const o2::framework::DataProcessingHeader *dph = o2::header::get<DataProcessingHeader*>(ref.header); + if (!dph) { + continue; + } + LOGP(DEBUG, "Orbit reset time from data: {} ", dph->creation); + context.orbitResetTime = dph->creation; + break; + } }, + .start = [](ServiceRegistry& services, void* service) { + auto& context = services.get<DataTakingContext>(); + context.runNumber = services.get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("runNumber", "unspecified"); + // FIXME: we actually need to get the orbit, not only to know where it is + std::string orbitResetTimeUrl = services.get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("orbit-reset-time", "ccdb://CTP/Calib/OrbitResetTime"); + auto is_number = [](const std::string& s) -> bool { + return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit); + }; + + if (orbitResetTimeUrl.rfind("file://") == 0) { + // FIXME: read it from a file + context.orbitResetTime = 490917600; + } else if (orbitResetTimeUrl.rfind("http://") == 0) { + // FIXME: read it from ccdb + context.orbitResetTime = 490917600; + } else if (is_number(orbitResetTimeUrl)) { + context.orbitResetTime = std::stoull(orbitResetTimeUrl.data()); + // FIXME: specify it from the command line + } else { + context.orbitResetTime = 490917600; + } + context.nOrbitsPerTF = services.get<RawDeviceService>().device()->fConfig->GetProperty<uint64_t>("Norbits_per_TF", 128); }, + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::infologgerContextSpec() { - return ServiceSpec{"infologger-contex", - simpleServiceInit<InfoLoggerContext, InfoLoggerContext>(), - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "infologger-contex", + .init = simpleServiceInit<InfoLoggerContext, InfoLoggerContext>(), + .configure = noConfiguration(), + .start = [](ServiceRegistry& services, void* service) { + auto& infoLoggerContext = services.get<InfoLoggerContext>(); + auto run = services.get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("runNumber", "unspecified"); + infoLoggerContext.setField(InfoLoggerContext::FieldName::Run, run); + auto partition = services.get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("environment_id", "unspecified"); + infoLoggerContext.setField(InfoLoggerContext::FieldName::Partition, partition); + }, + .kind = ServiceKind::Serial}; } // Creates the sink for FairLogger / InfoLogger integration @@ -112,29 +191,34 @@ auto createInfoLoggerSinkHelper(InfoLogger* logger, InfoLoggerContext* ctx) return; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::fatal)) { severity = InfoLogger::Severity::Fatal; + level = 1; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::error)) { severity = InfoLogger::Severity::Error; + level = 3; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::warn)) { severity = InfoLogger::Severity::Warning; + level = 6; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::state)) { severity = InfoLogger::Severity::Info; - level = 10; + level = 8; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::info)) { severity = InfoLogger::Severity::Info; + level = 10; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::debug)) { severity = InfoLogger::Severity::Debug; + level = 11; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::debug1)) { severity = InfoLogger::Severity::Debug; - level = 10; + level = 12; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::debug2)) { severity = InfoLogger::Severity::Debug; - level = 20; + level = 13; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::debug3)) { severity = InfoLogger::Severity::Debug; - level = 30; + level = 14; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::debug4)) { severity = InfoLogger::Severity::Debug; - level = 40; + level = 15; } else if (metadata.severity_name == fair::Logger::SeverityName(fair::Severity::trace)) { severity = InfoLogger::Severity::Debug; level = 50; @@ -155,43 +239,34 @@ auto createInfoLoggerSinkHelper(InfoLogger* logger, InfoLoggerContext* ctx) o2::framework::ServiceSpec CommonServices::infologgerSpec() { - return ServiceSpec{"infologger", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { - auto infoLoggerMode = options.GetPropertyAsString("infologger-mode"); - if (infoLoggerMode != "") { - setenv("INFOLOGGER_MODE", infoLoggerMode.c_str(), 1); - } - auto infoLoggerService = new InfoLogger; - auto infoLoggerContext = &services.get<InfoLoggerContext>(); - - auto infoLoggerSeverity = options.GetPropertyAsString("infologger-severity"); - if (infoLoggerSeverity != "") { - fair::Logger::AddCustomSink("infologger", infoLoggerSeverity, createInfoLoggerSinkHelper(infoLoggerService, infoLoggerContext)); - } - return ServiceHandle{TypeIdHelpers::uniqueId<InfoLogger>(), infoLoggerService}; - }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + return ServiceSpec{ + .name = "infologger", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + auto infoLoggerMode = options.GetPropertyAsString("infologger-mode"); + if (infoLoggerMode != "") { + setenv("O2_INFOLOGGER_MODE", infoLoggerMode.c_str(), 1); + } + auto infoLoggerService = new InfoLogger; + auto infoLoggerContext = &services.get<InfoLoggerContext>(); + infoLoggerContext->setField(InfoLoggerContext::FieldName::Facility, std::string("dpl/") + services.get<DeviceSpec const>().name); + infoLoggerContext->setField(InfoLoggerContext::FieldName::System, std::string("DPL")); + infoLoggerService->setContext(*infoLoggerContext); + + auto infoLoggerSeverity = options.GetPropertyAsString("infologger-severity"); + if (infoLoggerSeverity != "") { + fair::Logger::AddCustomSink("infologger", infoLoggerSeverity, createInfoLoggerSinkHelper(infoLoggerService, infoLoggerContext)); + } + return ServiceHandle{TypeIdHelpers::uniqueId<InfoLogger>(), infoLoggerService}; + }, + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::configurationSpec() { return ServiceSpec{ - "configuration", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "configuration", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { auto backend = options.GetPropertyAsString("configuration"); if (backend == "command-line") { return ServiceHandle{0, nullptr}; @@ -199,145 +274,96 @@ o2::framework::ServiceSpec CommonServices::configurationSpec() return ServiceHandle{TypeIdHelpers::uniqueId<ConfigurationInterface>(), ConfigurationFactory::getConfiguration(backend).release()}; }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Global}; + .configure = noConfiguration(), + .driverStartup = [](ServiceRegistry& registry, boost::program_options::variables_map const& vmap) { + if (vmap.count("configuration") == 0) { + registry.registerService(ServiceHandle{0, nullptr}); + return; + } + auto backend = vmap["configuration"].as<std::string>(); + registry.registerService(ServiceHandle{TypeIdHelpers::uniqueId<ConfigurationInterface>(), + ConfigurationFactory::getConfiguration(backend).release()}); }, + .kind = ServiceKind::Global}; +} + +o2::framework::ServiceSpec CommonServices::driverClientSpec() +{ + return ServiceSpec{ + .name = "driverClient", + .init = [](ServiceRegistry& services, DeviceState& state, fair::mq::ProgOptions& options) -> ServiceHandle { + auto backend = options.GetPropertyAsString("driver-client-backend"); + if (backend == "stdout://") { + return ServiceHandle{TypeIdHelpers::uniqueId<DriverClient>(), + new TextDriverClient(services, state)}; + } + auto [ip, port] = o2::framework::parse_websocket_url(backend.c_str()); + return ServiceHandle{TypeIdHelpers::uniqueId<DriverClient>(), + new WSDriverClient(services, state, ip.c_str(), port)}; + }, + .configure = noConfiguration(), + .kind = ServiceKind::Global}; } o2::framework::ServiceSpec CommonServices::controlSpec() { return ServiceSpec{ - "control", - [](ServiceRegistry& services, DeviceState& state, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "control", + .init = [](ServiceRegistry& services, DeviceState& state, fair::mq::ProgOptions& options) -> ServiceHandle { return ServiceHandle{TypeIdHelpers::uniqueId<ControlService>(), - new TextControlService(services, state)}; + new ControlService(services, state)}; }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::rootFileSpec() { return ServiceSpec{ - "localrootfile", - simpleServiceInit<LocalRootFileService, LocalRootFileService>(), - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .name = "localrootfile", + .init = simpleServiceInit<LocalRootFileService, LocalRootFileService>(), + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::parallelSpec() { return ServiceSpec{ - "parallel", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "parallel", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { auto& spec = services.get<DeviceSpec const>(); return ServiceHandle{TypeIdHelpers::uniqueId<ParallelContext>(), new ParallelContext(spec.rank, spec.nSlots)}; }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::timesliceIndex() { return ServiceSpec{ - "timesliceindex", - simpleServiceInit<TimesliceIndex, TimesliceIndex>(), - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .name = "timesliceindex", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + return ServiceHandle{TypeIdHelpers::uniqueId<TimesliceIndex>(), + new TimesliceIndex(InputRouteHelpers::maxLanes(services.get<DeviceSpec const>().inputs))}; + }, + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::callbacksSpec() { return ServiceSpec{ - "callbacks", - simpleServiceInit<CallbackService, CallbackService>(), - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .name = "callbacks", + .init = simpleServiceInit<CallbackService, CallbackService>(), + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } o2::framework::ServiceSpec CommonServices::dataRelayer() { return ServiceSpec{ - "datarelayer", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "datarelayer", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { auto& spec = services.get<DeviceSpec const>(); return ServiceHandle{TypeIdHelpers::uniqueId<DataRelayer>(), new DataRelayer(spec.completionPolicy, @@ -345,21 +371,8 @@ o2::framework::ServiceSpec CommonServices::dataRelayer() services.get<Monitoring>(), services.get<TimesliceIndex>())}; }, - noConfiguration(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .configure = noConfiguration(), + .kind = ServiceKind::Serial}; } struct TracingInfrastructure { @@ -369,31 +382,18 @@ struct TracingInfrastructure { o2::framework::ServiceSpec CommonServices::tracingSpec() { return ServiceSpec{ - "tracing", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "tracing", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { return ServiceHandle{TypeIdHelpers::uniqueId<TracingInfrastructure>(), new TracingInfrastructure()}; }, - noConfiguration(), - [](ProcessingContext&, void* service) { + .configure = noConfiguration(), + .preProcessing = [](ProcessingContext&, void* service) { TracingInfrastructure* t = reinterpret_cast<TracingInfrastructure*>(service); - t->processingCount += 1; - }, - [](ProcessingContext&, void* service) { + t->processingCount += 1; }, + .postProcessing = [](ProcessingContext&, void* service) { TracingInfrastructure* t = reinterpret_cast<TracingInfrastructure*>(service); - t->processingCount += 1; - }, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + t->processingCount += 1; }, + .kind = ServiceKind::Serial}; } // FIXME: allow configuring the default number of threads per device @@ -403,34 +403,22 @@ o2::framework::ServiceSpec CommonServices::tracingSpec() o2::framework::ServiceSpec CommonServices::threadPool(int numWorkers) { return ServiceSpec{ - "threadpool", - [numWorkers](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "threadpool", + .init = [numWorkers](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { ThreadPool* pool = new ThreadPool(); pool->poolSize = numWorkers; return ServiceHandle{TypeIdHelpers::uniqueId<ThreadPool>(), pool}; }, - [numWorkers](InitContext&, void* service) -> void* { + .configure = [numWorkers](InitContext&, void* service) -> void* { ThreadPool* t = reinterpret_cast<ThreadPool*>(service); t->poolSize = numWorkers; return service; }, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - [numWorkers](ServiceRegistry& service) -> void { + .postForkParent = [numWorkers](ServiceRegistry& service) -> void { auto numWorkersS = std::to_string(numWorkers); setenv("UV_THREADPOOL_SIZE", numWorkersS.c_str(), 0); }, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + .kind = ServiceKind::Serial}; } namespace @@ -453,20 +441,25 @@ auto sendRelayerMetrics(ServiceRegistry& registry, DataProcessingStats& stats) - monitoring.send(Metric{(int)relayerStats.droppedIncomingMessages, "dropped_incoming_messages"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{(int)relayerStats.relayedMessages, "relayed_messages"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{(int)stats.errorCount, "errors"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{(int)stats.exceptionCount, "exceptions"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{(int)stats.pendingInputs, "inputs/relayed/pending"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{(int)stats.incomplete, "inputs/relayed/incomplete"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{(int)stats.inputParts, "inputs/relayed/total"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{stats.lastElapsedTimeMs, "elapsed_time_ms"}.addTag(Key::Subsystem, Value::DPL)); - monitoring.send(Metric{stats.lastTotalProcessedSize, "processed_input_size_byte"} + monitoring.send(Metric{stats.lastProcessedSize, "last_processed_input_size_byte"} + .addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{stats.totalProcessedSize, "total_processed_input_size_byte"} .addTag(Key::Subsystem, Value::DPL)); - monitoring.send(Metric{(stats.lastTotalProcessedSize.load() / (stats.lastElapsedTimeMs.load() ? stats.lastElapsedTimeMs.load() : 1) / 1000), + monitoring.send(Metric{stats.totalSigusr1.load(), "total_sigusr1"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{(stats.lastProcessedSize.load() / (stats.lastElapsedTimeMs.load() ? stats.lastElapsedTimeMs.load() : 1) / 1000), "processing_rate_mb_s"} .addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{stats.lastLatency.minLatency, "min_input_latency_ms"} .addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{stats.lastLatency.maxLatency, "max_input_latency_ms"} .addTag(Key::Subsystem, Value::DPL)); - monitoring.send(Metric{(stats.lastTotalProcessedSize / (stats.lastLatency.maxLatency ? stats.lastLatency.maxLatency : 1) / 1000), "input_rate_mb_s"} + monitoring.send(Metric{(stats.lastProcessedSize / (stats.lastLatency.maxLatency ? stats.lastLatency.maxLatency : 1) / 1000), "input_rate_mb_s"} .addTag(Key::Subsystem, Value::DPL)); stats.lastSlowMetricSentTimestamp.store(stats.beginIterationTimestamp.load()); @@ -490,7 +483,7 @@ auto flushMetrics(ServiceRegistry& registry, DataProcessingStats& stats) -> void for (size_t si = 0; si < stats.statesSize.load(); ++si) { auto value = std::atomic_load_explicit(&stats.relayerState[si], std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_acquire); - monitoring.send({value, fmt::format("data_relayer/{}", si)}); + monitoring.send({value, fmt::format("data_relayer/{}", si, o2::monitoring::Verbosity::Debug)}); } relayer.sendContextState(); monitoring.flushBuffer(); @@ -502,45 +495,34 @@ auto flushMetrics(ServiceRegistry& registry, DataProcessingStats& stats) -> void o2::framework::ServiceSpec CommonServices::dataProcessingStats() { return ServiceSpec{ - "data-processing-stats", - [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { + .name = "data-processing-stats", + .init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { DataProcessingStats* stats = new DataProcessingStats(); return ServiceHandle{TypeIdHelpers::uniqueId<DataProcessingStats>(), stats}; }, - noConfiguration(), - nullptr, - nullptr, - [](DanglingContext& context, void* service) { + .configure = noConfiguration(), + .preDangling = [](DanglingContext& context, void* service) { DataProcessingStats* stats = (DataProcessingStats*)service; sendRelayerMetrics(context.services(), *stats); - flushMetrics(context.services(), *stats); - }, - [](DanglingContext& context, void* service) { + flushMetrics(context.services(), *stats); }, + .postDangling = [](DanglingContext& context, void* service) { DataProcessingStats* stats = (DataProcessingStats*)service; sendRelayerMetrics(context.services(), *stats); - flushMetrics(context.services(), *stats); - }, - [](EndOfStreamContext& context, void* service) { + flushMetrics(context.services(), *stats); }, + .preEOS = [](EndOfStreamContext& context, void* service) { DataProcessingStats* stats = (DataProcessingStats*)service; sendRelayerMetrics(context.services(), *stats); - flushMetrics(context.services(), *stats); - }, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ServiceKind::Serial}; + flushMetrics(context.services(), *stats); }, + .kind = ServiceKind::Serial}; } std::vector<ServiceSpec> CommonServices::defaultServices(int numThreads) { std::vector<ServiceSpec> specs{ timesliceIndex(), + driverClientSpec(), monitoringSpec(), + datatakingContextSpec(), infologgerContextSpec(), infologgerSpec(), configurationSpec(), @@ -551,7 +533,7 @@ std::vector<ServiceSpec> CommonServices::defaultServices(int numThreads) dataRelayer(), dataProcessingStats(), CommonMessageBackends::fairMQBackendSpec(), - CommonMessageBackends::arrowBackendSpec(), + ArrowSupport::arrowBackendSpec(), CommonMessageBackends::stringBackendSpec(), CommonMessageBackends::rawBufferBackendSpec()}; if (numThreads) { @@ -560,4 +542,18 @@ std::vector<ServiceSpec> CommonServices::defaultServices(int numThreads) return specs; } +o2::framework::ServiceSpec CommonAnalysisServices::databasePDGSpec() +{ + return ServiceSpec{ + .name = "database-pdg", + .init = [](ServiceRegistry&, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle { + auto* ptr = new TDatabasePDG(); + ptr->ReadPDGTable(); + return ServiceHandle{TypeIdHelpers::uniqueId<TDatabasePDG>(), ptr, ServiceKind::Serial, "database-pdg"}; + }, + .configure = CommonServices::noConfiguration(), + .exit = [](ServiceRegistry&, void* service) { reinterpret_cast<TDatabasePDG*>(service)->Delete(); }, + .kind = ServiceKind::Serial}; +} } // namespace o2::framework +#pragma GCC diagnostic pop diff --git a/Framework/Core/src/CompletionPolicy.cxx b/Framework/Core/src/CompletionPolicy.cxx index 06e1ef159fe3b..49a4067ef995f 100644 --- a/Framework/Core/src/CompletionPolicy.cxx +++ b/Framework/Core/src/CompletionPolicy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,7 @@ std::vector<CompletionPolicy> { return { CompletionPolicyHelpers::defineByNameOrigin("internal-dpl-aod-writer", "TFN", CompletionOp::Consume), + CompletionPolicyHelpers::defineByName("internal-dpl-injected-dummy-sink", CompletionOp::Discard), CompletionPolicyHelpers::consumeWhenAll()}; } diff --git a/Framework/Core/src/CompletionPolicyHelpers.cxx b/Framework/Core/src/CompletionPolicyHelpers.cxx index ab19536a93843..8b6465a758dec 100644 --- a/Framework/Core/src/CompletionPolicyHelpers.cxx +++ b/Framework/Core/src/CompletionPolicyHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "Framework/CompletionPolicyHelpers.h" #include "Framework/CompletionPolicy.h" +#include "Framework/InputSpan.h" #include "Framework/DeviceSpec.h" #include "Framework/CompilerBuiltins.h" #include "Framework/Logger.h" @@ -30,7 +32,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByNameOrigin(std::string const& auto originReceived = std::make_shared<std::vector<uint64_t>>(); - auto callback = [originReceived, origin, op](CompletionPolicy::InputSet inputRefs) -> CompletionPolicy::CompletionOp { + auto callback = [originReceived, origin, op](InputSpan const& inputRefs) -> CompletionPolicy::CompletionOp { // update list of the start times of inputs with origin @origin for (auto& ref : inputRefs) { if (ref.header != nullptr) { @@ -72,7 +74,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByName(std::string const& name, auto matcher = [name](DeviceSpec const& device) -> bool { return std::regex_match(device.name.begin(), device.name.end(), std::regex(name)); }; - auto callback = [op](CompletionPolicy::InputSet) -> CompletionPolicy::CompletionOp { + auto callback = [op](InputSpan const&) -> CompletionPolicy::CompletionOp { return op; }; switch (op) { @@ -94,7 +96,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByName(std::string const& name, CompletionPolicy CompletionPolicyHelpers::consumeWhenAll(const char* name, CompletionPolicy::Matcher matcher) { - auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp { + auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp { for (auto& input : inputs) { if (input.header == nullptr) { return CompletionPolicy::CompletionOp::Wait; @@ -107,7 +109,7 @@ CompletionPolicy CompletionPolicyHelpers::consumeWhenAll(const char* name, Compl CompletionPolicy CompletionPolicyHelpers::consumeWhenAny(const char* name, CompletionPolicy::Matcher matcher) { - auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp { + auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp { for (auto& input : inputs) { if (input.header != nullptr) { return CompletionPolicy::CompletionOp::Consume; @@ -120,7 +122,7 @@ CompletionPolicy CompletionPolicyHelpers::consumeWhenAny(const char* name, Compl CompletionPolicy CompletionPolicyHelpers::processWhenAny(const char* name, CompletionPolicy::Matcher matcher) { - auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp { + auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp { size_t present = 0; for (auto& input : inputs) { if (input.header != nullptr) { diff --git a/Framework/Core/src/ComputingQuotaEvaluator.cxx b/Framework/Core/src/ComputingQuotaEvaluator.cxx new file mode 100644 index 0000000000000..23193992f460e --- /dev/null +++ b/Framework/Core/src/ComputingQuotaEvaluator.cxx @@ -0,0 +1,255 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ComputingQuotaEvaluator.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/DeviceState.h" +#include "Framework/DriverClient.h" +#include "Framework/Monitoring.h" +#include "Framework/Logger.h" +#include <Monitoring/Monitoring.h> + +#include <vector> +#include <uv.h> +#include <cassert> + +namespace o2::framework +{ + +ComputingQuotaEvaluator::ComputingQuotaEvaluator(uint64_t now) +{ + // The first offer is valid, but does not contain any resource + // so this will only work with some device which does not require + // any CPU. Notice this will have troubles if a given DPL process + // runs for more than a year. + mOffers[0] = { + 0, + 0, + 0, + -1, + -1, + OfferScore::Unneeded, + true}; + mInfos[0] = { + now, + 0, + 0}; +} + +struct QuotaEvaluatorStats { + std::vector<int> invalidOffers; + std::vector<int> otherUser; + std::vector<int> unexpiring; + std::vector<int> selectedOffers; + std::vector<int> expired; +}; + +bool ComputingQuotaEvaluator::selectOffer(int task, ComputingQuotaRequest const& selector, uint64_t now) +{ + auto selectOffer = [&offers = this->mOffers, &infos = this->mInfos, task](int ref, uint64_t now) { + auto& selected = offers[ref]; + auto& info = infos[ref]; + selected.user = task; + if (info.firstUsed == 0) { + info.firstUsed = now; + } + info.lastUsed = now; + }; + + ComputingQuotaOffer accumulated; + static QuotaEvaluatorStats stats; + + stats.invalidOffers.clear(); + stats.otherUser.clear(); + stats.unexpiring.clear(); + stats.selectedOffers.clear(); + stats.expired.clear(); + + auto summarizeWhatHappended = [](bool enough, std::vector<int> const& result, ComputingQuotaOffer const& totalOffer, QuotaEvaluatorStats& stats) -> bool { + if (result.size() == 1 && result[0] == 0) { + // LOG(INFO) << "No particular resource was requested, so we schedule task anyways"; + return enough; + } + if (enough) { + LOGP(INFO, "{} offers were selected for a total of: cpu {}, memory {}, shared memory {}", result.size(), totalOffer.cpu, totalOffer.memory, totalOffer.sharedMemory); + LOGP(INFO, " The following offers were selected for computation: {} ", fmt::join(result, ",")); + } else { + LOG(INFO) << "No offer was selected"; + if (result.size()) { + LOGP(INFO, " The following offers were selected for computation but not enough: {} ", fmt::join(result, ",")); + } + } + if (stats.invalidOffers.size()) { + LOGP(INFO, " The following offers were invalid: {}", fmt::join(stats.invalidOffers, ", ")); + } + if (stats.otherUser.size()) { + LOGP(INFO, " The following offers were owned by other users: {}", fmt::join(stats.otherUser, ", ")); + } + if (stats.expired.size()) { + LOGP(INFO, " The following offers are expired: {}", fmt::join(stats.expired, ", ")); + } + if (stats.unexpiring.size() > 1) { + LOGP(INFO, " The following offers will never expire: {}", fmt::join(stats.unexpiring, ", ")); + } + + return enough; + }; + + bool enough = false; + + for (int i = 0; i != mOffers.size(); ++i) { + auto& offer = mOffers[i]; + auto& info = mInfos[i]; + if (enough) { + break; + } + // Ignore: + // - Invalid offers + // - Offers which belong to another task + // - Expired offers + if (offer.valid == false) { + stats.invalidOffers.push_back(i); + continue; + } + if (offer.user != -1 && offer.user != task) { + stats.otherUser.push_back(i); + continue; + } + if (offer.runtime < 0) { + stats.unexpiring.push_back(i); + } else if (offer.runtime + info.received < now) { + LOGP(INFO, "Offer {} expired since {} milliseconds and holds {}MB", i, now - offer.runtime - info.received, offer.sharedMemory / 1000000); + mExpiredOffers.push_back(ComputingQuotaOfferRef{i}); + stats.expired.push_back(i); + continue; + } else { + LOGP(INFO, "Offer {} still valid for {} milliseconds, providing {}MB", i, offer.runtime + info.received - now, offer.sharedMemory / 1000000); + } + /// We then check if the offer is suitable + assert(offer.sharedMemory >= 0); + auto tmp = accumulated; + tmp.cpu += offer.cpu; + tmp.memory += offer.memory; + tmp.sharedMemory += offer.sharedMemory; + offer.score = selector(offer, tmp); + switch (offer.score) { + case OfferScore::Unneeded: + continue; + case OfferScore::Unsuitable: + continue; + case OfferScore::More: + selectOffer(i, now); + accumulated = tmp; + stats.selectedOffers.push_back(i); + continue; + case OfferScore::Enough: + selectOffer(i, now); + accumulated = tmp; + stats.selectedOffers.push_back(i); + enough = true; + break; + }; + } + // If we get here it means we never got enough offers, so we return false. + return summarizeWhatHappended(enough, stats.selectedOffers, accumulated, stats); +} + +void ComputingQuotaEvaluator::consume(int id, ComputingQuotaConsumer& consumer, std::function<void(ComputingQuotaOffer const& accumulatedConsumed, ComputingQuotaStats& reportConsumedOffer)>& reportConsumedOffer) +{ + // This will report how much of the offers has to be considered consumed. + // Notice that actual memory usage might be larger, because we can over + // allocate. + consumer(id, mOffers, mStats, reportConsumedOffer); +} + +void ComputingQuotaEvaluator::dispose(int taskId) +{ + for (int oi = 0; oi < mOffers.size(); ++oi) { + auto& offer = mOffers[oi]; + if (offer.user != taskId) { + continue; + } + offer.user = -1; + // Disposing the offer so that the resource can be recyled. + /// An offer with index 0 is always there. + /// All the others are reset. + if (oi == 0) { + return; + } + if (offer.valid == false) { + continue; + } + if (offer.sharedMemory <= 0) { + offer.valid = false; + offer.score = OfferScore::Unneeded; + } + } +} + +/// Move offers from the pending list to the actual available offers +void ComputingQuotaEvaluator::updateOffers(std::vector<ComputingQuotaOffer>& pending, uint64_t now) +{ + for (size_t oi = 0; oi < mOffers.size(); oi++) { + auto& storeOffer = mOffers[oi]; + auto& info = mInfos[oi]; + if (pending.empty()) { + return; + } + if (storeOffer.valid == true) { + continue; + } + info.received = now; + auto& offer = pending.back(); + storeOffer = offer; + storeOffer.valid = true; + pending.pop_back(); + } +} + +void ComputingQuotaEvaluator::handleExpired(std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats const& stats)> expirator) +{ + static int nothingToDoCount = mExpiredOffers.size(); + if (mExpiredOffers.size()) { + LOGP(INFO, "Handling {} expired offers", mExpiredOffers.size()); + nothingToDoCount = 0; + } else { + if (nothingToDoCount == 0) { + nothingToDoCount++; + LOGP(INFO, "No expired offers"); + } + } + /// Whenever an offer is expired, we give back the resources + /// to the driver. + for (auto& ref : mExpiredOffers) { + auto& offer = mOffers[ref.index]; + if (offer.sharedMemory < 0) { + LOGP(INFO, "Offer {} does not have any more memory. Marking it as invalid.", ref.index); + offer.valid = false; + offer.score = OfferScore::Unneeded; + continue; + } + // FIXME: offers should go through the driver client, not the monitoring + // api. + LOGP(INFO, "Offer {} expired. Giving back {}MB and {} cores", ref.index, offer.sharedMemory / 1000000, offer.cpu); + assert(offer.sharedMemory > 0); + mStats.totalExpiredBytes += offer.sharedMemory; + mStats.totalExpiredOffers++; + expirator(offer, mStats); + //driverClient.tell("expired shmem {}", offer.sharedMemory); + //driverClient.tell("expired cpu {}", offer.cpu); + offer.sharedMemory = -1; + offer.valid = false; + offer.score = OfferScore::Unneeded; + } + mExpiredOffers.clear(); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ComputingResourceHelpers.cxx b/Framework/Core/src/ComputingResourceHelpers.cxx index 551a98118f30c..e0d82cd62505b 100644 --- a/Framework/Core/src/ComputingResourceHelpers.cxx +++ b/Framework/Core/src/ComputingResourceHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ComputingResourceHelpers.h b/Framework/Core/src/ComputingResourceHelpers.h index deea2b9219e4e..b1eb6060bd8e0 100644 --- a/Framework/Core/src/ComputingResourceHelpers.h +++ b/Framework/Core/src/ComputingResourceHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ConfigContext.cxx b/Framework/Core/src/ConfigContext.cxx index 5148a2640ba05..726332e1d0ae3 100644 --- a/Framework/Core/src/ConfigContext.cxx +++ b/Framework/Core/src/ConfigContext.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ConfigParamStore.cxx b/Framework/Core/src/ConfigParamStore.cxx index 00d64302dc9bc..249a8b0052a67 100644 --- a/Framework/Core/src/ConfigParamStore.cxx +++ b/Framework/Core/src/ConfigParamStore.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ConfigParamsHelper.cxx b/Framework/Core/src/ConfigParamsHelper.cxx index e41ab45af7bb1..b52d44a294a97 100644 --- a/Framework/Core/src/ConfigParamsHelper.cxx +++ b/Framework/Core/src/ConfigParamsHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,9 +18,7 @@ namespace bpo = boost::program_options; -namespace o2 -{ -namespace framework +namespace o2::framework { /// this creates the boost program options description from the ConfigParamSpec @@ -30,13 +29,11 @@ void ConfigParamsHelper::populateBoostProgramOptions( bpo::options_description vetos) { auto proxy = options.add_options(); - for (auto& spec : specs) { + for (auto const& spec : specs) { // skip everything found in the veto definition - if (vetos.find_nothrow(spec.name, false)) { + if (vetos.find_nothrow(spec.name, false) != nullptr) { continue; } - const char* name = spec.name.c_str(); - const char* help = spec.help.c_str(); switch (spec.type) { // FIXME: Should we handle int and size_t diffently? @@ -47,6 +44,18 @@ void ConfigParamsHelper::populateBoostProgramOptions( case VariantType::Int64: addConfigSpecOption<VariantType::Int64>(spec, options); break; + case VariantType::UInt8: + addConfigSpecOption<VariantType::UInt8>(spec, options); + break; + case VariantType::UInt16: + addConfigSpecOption<VariantType::UInt16>(spec, options); + break; + case VariantType::UInt32: + addConfigSpecOption<VariantType::UInt32>(spec, options); + break; + case VariantType::UInt64: + addConfigSpecOption<VariantType::UInt64>(spec, options); + break; case VariantType::Float: addConfigSpecOption<VariantType::Float>(spec, options); break; @@ -60,9 +69,32 @@ void ConfigParamsHelper::populateBoostProgramOptions( addConfigSpecOption<VariantType::Bool>(spec, options); break; case VariantType::ArrayInt: + addConfigSpecOption<VariantType::ArrayInt>(spec, options); + break; case VariantType::ArrayFloat: + addConfigSpecOption<VariantType::ArrayFloat>(spec, options); + break; case VariantType::ArrayDouble: + addConfigSpecOption<VariantType::ArrayDouble>(spec, options); + break; case VariantType::ArrayBool: + addConfigSpecOption<VariantType::ArrayBool>(spec, options); + break; + case VariantType::ArrayString: + addConfigSpecOption<VariantType::ArrayString>(spec, options); + break; + case VariantType::Array2DInt: + addConfigSpecOption<VariantType::Array2DInt>(spec, options); + break; + case VariantType::Array2DFloat: + addConfigSpecOption<VariantType::Array2DFloat>(spec, options); + break; + case VariantType::Array2DDouble: + addConfigSpecOption<VariantType::Array2DDouble>(spec, options); + break; + case VariantType::LabeledArrayInt: + case VariantType::LabeledArrayFloat: + case VariantType::LabeledArrayDouble: case VariantType::Unknown: case VariantType::Empty: break; @@ -70,6 +102,16 @@ void ConfigParamsHelper::populateBoostProgramOptions( } } +void ConfigParamsHelper::addOptionIfMissing(std::vector<ConfigParamSpec>& specs, ConfigParamSpec spec) +{ + for (auto& old : specs) { + if (old.name == spec.name) { + return; + } + } + specs.push_back(spec); +} + /// populate boost program options making all options of type string /// this is used for filtering the command line argument bool ConfigParamsHelper::dpl2BoostOptions(const std::vector<ConfigParamSpec>& spec, @@ -80,11 +122,11 @@ bool ConfigParamsHelper::dpl2BoostOptions(const std::vector<ConfigParamSpec>& sp for (const auto& configSpec : spec) { // skip everything found in the veto definition try { - if (vetos.find_nothrow(configSpec.name, false)) { + if (vetos.find_nothrow(configSpec.name, false) != nullptr) { continue; } } catch (boost::program_options::ambiguous_option& e) { - for (auto& alternative : e.alternatives()) { + for (auto const& alternative : e.alternatives()) { std::cerr << alternative << std::endl; } throw; @@ -96,7 +138,7 @@ bool ConfigParamsHelper::dpl2BoostOptions(const std::vector<ConfigParamSpec>& sp if (configSpec.type != VariantType::Bool) { if (configSpec.defaultValue.type() != VariantType::Empty) { options.add_options()(configSpec.name.c_str(), - bpo::value<std::string>()->default_value(defaultValue.str().c_str()), + bpo::value<std::string>()->default_value(defaultValue.str()), configSpec.help.c_str()); } else { options.add_options()(configSpec.name.c_str(), @@ -119,5 +161,4 @@ bool ConfigParamsHelper::dpl2BoostOptions(const std::vector<ConfigParamSpec>& sp return haveOption; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/ConfigurationOptionsRetriever.cxx b/Framework/Core/src/ConfigurationOptionsRetriever.cxx index f7848a6b723d6..c0e3d67502e37 100644 --- a/Framework/Core/src/ConfigurationOptionsRetriever.cxx +++ b/Framework/Core/src/ConfigurationOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ConfigurationOptionsRetriever.h b/Framework/Core/src/ConfigurationOptionsRetriever.h index 2ec6907eaf2c2..d993ad9bf55ef 100644 --- a/Framework/Core/src/ConfigurationOptionsRetriever.h +++ b/Framework/Core/src/ConfigurationOptionsRetriever.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ControlService.cxx b/Framework/Core/src/ControlService.cxx new file mode 100644 index 0000000000000..fc2de65d05054 --- /dev/null +++ b/Framework/Core/src/ControlService.cxx @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ControlService.h" +#include "Framework/DriverClient.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DeviceState.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/RawDeviceService.h" +#include "Framework/Logger.h" +#include "DataProcessingHelpers.h" +#include <string> +#include <string_view> +#include <regex> +#include <iostream> + +namespace o2::framework +{ + +ControlService::ControlService(ServiceRegistry& registry, DeviceState& deviceState) + : mRegistry{registry}, + mDeviceState{deviceState}, + mDriverClient{registry.get<DriverClient>()} +{ +} + +// This will send an end of stream to all the devices downstream. +void ControlService::endOfStream() +{ + std::scoped_lock lock(mMutex); + mDeviceState.streaming = StreamingState::EndOfStreaming; +} + +// All we do is to printout +void ControlService::readyToQuit(QuitRequest what) +{ + std::scoped_lock lock(mMutex); + if (mOnce == true) { + return; + } + mOnce = true; + switch (what) { + case QuitRequest::All: + mDeviceState.quitRequested = true; + mDriverClient.tell("CONTROL_ACTION: READY_TO_QUIT_ALL"); + break; + case QuitRequest::Me: + mDeviceState.quitRequested = true; + mDriverClient.tell("CONTROL_ACTION: READY_TO_QUIT_ME"); + break; + } + mDriverClient.flushPending(); +} + +void ControlService::notifyStreamingState(StreamingState state) +{ + std::scoped_lock lock(mMutex); + switch (state) { + case StreamingState::Idle: + mDriverClient.tell("CONTROL_ACTION: NOTIFY_STREAMING_STATE IDLE"); + break; + case StreamingState::Streaming: + mDriverClient.tell("CONTROL_ACTION: NOTIFY_STREAMING_STATE STREAMING"); + break; + case StreamingState::EndOfStreaming: + mDriverClient.tell("CONTROL_ACTION: NOTIFY_STREAMING_STATE EOS"); + break; + default: + throw std::runtime_error("Unknown streaming state"); + } + mDriverClient.flushPending(); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ControlServiceHelpers.cxx b/Framework/Core/src/ControlServiceHelpers.cxx new file mode 100644 index 0000000000000..1b372bf998a71 --- /dev/null +++ b/Framework/Core/src/ControlServiceHelpers.cxx @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "ControlServiceHelpers.h" +#include "Framework/RawDeviceService.h" +#include "Framework/Logger.h" +#include "Framework/DeviceInfo.h" +#include <string> +#include <string_view> +#include <regex> +#include <iostream> + +namespace o2::framework +{ + +bool ControlServiceHelpers::parseControl(std::string const& s, std::smatch& match) +{ + char const* action = strstr(s.data(), "CONTROL_ACTION:"); + if (action == nullptr) { + return false; + } + const static std::regex controlRE1(".*CONTROL_ACTION: READY_TO_(QUIT)_(ME|ALL)", std::regex::optimize); + const static std::regex controlRE2(".*CONTROL_ACTION: (NOTIFY_STREAMING_STATE) (IDLE|STREAMING|EOS)", std::regex::optimize); + return std::regex_search(s, match, controlRE1) || std::regex_search(s, match, controlRE2); +} + +void ControlServiceHelpers::processCommand(std::vector<DeviceInfo>& infos, + pid_t pid, + std::string const& command, + std::string const& arg) +{ + auto doToMatchingPid = [](std::vector<DeviceInfo>& infos, pid_t pid, auto lambda) { + for (auto& deviceInfo : infos) { + if (deviceInfo.pid == pid) { + return lambda(deviceInfo); + } + } + LOGP(error, "Command received for pid {} which does not exists.", pid); + }; + LOGP(debug2, "Found control command {} from pid {} with argument {}.", command, pid, arg); + if (command == "QUIT" && arg == "ALL") { + for (auto& deviceInfo : infos) { + deviceInfo.readyToQuit = true; + } + } else if (command == "QUIT" && arg == "ME") { + doToMatchingPid(infos, pid, [](DeviceInfo& info) { info.readyToQuit = true; }); + } else if (command == "NOTIFY_STREAMING_STATE" && arg == "IDLE") { + // FIXME: this should really be a policy... + doToMatchingPid(infos, pid, [](DeviceInfo& info) { info.readyToQuit = true; info.streamingState = StreamingState::Idle; }); + } else if (command == "NOTIFY_STREAMING_STATE" && arg == "STREAMING") { + // FIXME: this should really be a policy... + doToMatchingPid(infos, pid, [](DeviceInfo& info) { info.streamingState = StreamingState::Streaming; }); + } else if (command == "NOTIFY_STREAMING_STATE" && arg == "EOS") { + // FIXME: this should really be a policy... + doToMatchingPid(infos, pid, [](DeviceInfo& info) { info.streamingState = StreamingState::EndOfStreaming; }); + } else { + LOGP(error, "Unknown command {} with argument {}", command, arg); + } +}; + +} // namespace o2::framework diff --git a/Framework/Core/src/ControlServiceHelpers.h b/Framework/Core/src/ControlServiceHelpers.h new file mode 100644 index 0000000000000..ac64d76303032 --- /dev/null +++ b/Framework/Core/src/ControlServiceHelpers.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_CONTROLSERVICEHELPERS_H_ +#define O2_FRAMEWORK_CONTROLSERVICEHELPERS_H_ + +#include "Framework/DeviceInfo.h" + +#include <unistd.h> +#include <vector> +#include <string> +#include <regex> + +namespace o2::framework +{ +struct ControlServiceHelpers { + static bool parseControl(std::string const& s, std::smatch& match); + static void processCommand(std::vector<DeviceInfo>& infos, + pid_t pid, + std::string const& command, + std::string const& arg); +}; + +} // namespace o2::framework +#endif // O2_FRAMEWORK_CONTROLSERVICEHELPERS_H_ diff --git a/Framework/Core/src/DDSConfigHelpers.cxx b/Framework/Core/src/DDSConfigHelpers.cxx index d2d76ccbd7a6a..b4296d7e3eca0 100644 --- a/Framework/Core/src/DDSConfigHelpers.cxx +++ b/Framework/Core/src/DDSConfigHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,15 +12,28 @@ #include <map> #include <iostream> #include <cstring> +#include <fmt/format.h> +#include <libgen.h> -namespace o2 +namespace o2::framework { -namespace framework + +std::string replaceFirstOccurrence( + std::string s, + const std::string& toReplace, + const std::string& replaceWith) { + std::size_t pos = s.find(toReplace); + if (pos == std::string::npos) { + return s; + } + return s.replace(pos, toReplace.length(), replaceWith); +} void dumpDeviceSpec2DDS(std::ostream& out, const std::vector<DeviceSpec>& specs, - const std::vector<DeviceExecution>& executions) + const std::vector<DeviceExecution>& executions, + const CommandInfo& commandInfo) { out << R"(<topology name="o2-dataflow">)" "\n"; @@ -28,37 +42,66 @@ void dumpDeviceSpec2DDS(std::ostream& out, for (size_t di = 0; di < specs.size(); ++di) { auto& spec = specs[di]; auto& execution = executions[di]; - - auto id = spec.id; - std::replace(id.begin(), id.end(), '-', '_'); // replace all 'x' to 'y' + if (execution.args.empty()) { + continue; + } out << " " - << R"(<decltask name=")" << id << R"(">)" - "\n"; + << fmt::format("<decltask name=\"{}\">\n", spec.id); out << " " << R"(<exe reachable="true">)"; - for (size_t ai = 0; ai < execution.args.size(); ++ai) { + out << replaceFirstOccurrence(commandInfo.command, "--dds", "--dump") << " | "; + for (size_t ei = 0; ei < execution.environ.size(); ++ei) { + out << fmt::format(execution.environ[ei], + fmt::arg("timeslice0", spec.inputTimesliceId), + fmt::arg("timeslice1", spec.inputTimesliceId + 1), + fmt::arg("timeslice4", spec.inputTimesliceId + 4)) + << " "; + } + std::string accumulatedChannelPrefix; + char* s = strdup(execution.args[0]); + out << basename(s) << " "; + free(s); + for (size_t ai = 1; ai < execution.args.size(); ++ai) { const char* arg = execution.args[ai]; if (!arg) { break; } - // Do not print out channel information - if (strcmp(arg, "--channel-config") == 0) { + // Do not print out the driver client explicitly + if (strcmp(arg, "--driver-client-backend") == 0) { + ai++; + continue; + } + if (strcmp(arg, "--control") == 0) { ai++; continue; } - out << arg << " "; + if (strcmp(arg, "--channel-prefix") == 0 && + ai + 1 < execution.args.size() && + *execution.args[ai + 1] == 0) { + ai++; + continue; + } + if (strpbrk(arg, "' ;@") != nullptr || arg[0] == 0) { + out << fmt::format(R"("{}" )", arg); + } else if (strpbrk(arg, "\"") != nullptr || arg[0] == 0) { + out << fmt::format(R"('{}' )", arg); + } else { + out << fmt::format(R"({} )", arg); + } + } + out << "--plugin odc"; + if (accumulatedChannelPrefix.empty() == false) { + out << " --channel-config \"" << accumulatedChannelPrefix << "\""; } - out << "--plugin-search-path $FAIRMQ_ROOT/lib --plugin dds"; out << "</exe>\n"; out << " </decltask>\n"; } out << " <declcollection name=\"DPL\">\n <tasks>\n"; for (size_t di = 0; di < specs.size(); ++di) { - out << " <name>" << specs[di].name << "</name>\n"; + out << fmt::format(" <name>{}</name>\n", specs[di].id); } out << " </tasks>\n </declcollection>\n"; out << "</topology>\n"; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/DDSConfigHelpers.h b/Framework/Core/src/DDSConfigHelpers.h index f65e06c8eb591..aafe6f568cae6 100644 --- a/Framework/Core/src/DDSConfigHelpers.h +++ b/Framework/Core/src/DDSConfigHelpers.h @@ -1,23 +1,23 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DDSCONFIGHELPERS_H -#define FRAMEWORK_DDSCONFIGHELPERS_H +#ifndef O2_FRAMEWORK_DDSCONFIGHELPERS_H_ +#define O2_FRAMEWORK_DDSCONFIGHELPERS_H_ #include "Framework/DeviceSpec.h" #include "Framework/DeviceExecution.h" +#include "Framework/CommandInfo.h" #include <vector> #include <iosfwd> -namespace o2 -{ -namespace framework +namespace o2::framework { /// Helper to dump DDS configuration to run in a deployed @@ -27,10 +27,11 @@ namespace framework /// which we want to dump. /// @a executions is the transient parameters for the afore mentioned /// specifications +/// @a the full command being used void dumpDeviceSpec2DDS(std::ostream& out, std::vector<DeviceSpec> const& specs, - std::vector<DeviceExecution> const& executions); + std::vector<DeviceExecution> const& executions, + CommandInfo const& commandInfo); -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_DDSCONFIGHELPERS_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_DDSCONFIGHELPERS_H_ diff --git a/Framework/Core/src/DPLMonitoringBackend.cxx b/Framework/Core/src/DPLMonitoringBackend.cxx new file mode 100644 index 0000000000000..2de54fbd1ab12 --- /dev/null +++ b/Framework/Core/src/DPLMonitoringBackend.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DPLMonitoringBackend.h" +#include "Framework/DriverClient.h" +#include "Framework/ServiceRegistry.h" +#include <fmt/format.h> +#include <sstream> + +namespace o2::framework +{ + +template <class... Ts> +struct overloaded : Ts... { + using Ts::operator()...; +}; +template <class... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + + +DPLMonitoringBackend::DPLMonitoringBackend(ServiceRegistry& registry) + : mRegistry{registry} +{ +} + +void DPLMonitoringBackend::addGlobalTag(std::string_view name, std::string_view value) +{ + // FIXME: tags are ignored by DPL in any case... + mTagString += fmt::format("{}{}={}", mTagString.empty() ? "" : ",", name.data(), value); +} + +void DPLMonitoringBackend::send(std::vector<o2::monitoring::Metric>&& metrics) +{ + for (auto& m : metrics) { + send(m); + } +} + +inline unsigned long convertTimestamp(const std::chrono::time_point<std::chrono::system_clock>& timestamp) +{ + return std::chrono::duration_cast<std::chrono::milliseconds>( + timestamp.time_since_epoch()) + .count(); +} + +void DPLMonitoringBackend::send(o2::monitoring::Metric const& metric) +{ + std::array<char, 4096> buffer; + auto mStream = fmt::format_to(buffer.begin(), "[METRIC] {}", metric.getName()); + for (auto& value : metric.getValues()) { + auto stringValue = std::visit(overloaded{ + [](const std::string& value) -> std::string { return value; }, + [](auto value) -> std::string { return std::to_string(value); }}, + value.second); + if (metric.getValuesSize() == 1) { + mStream = fmt::format_to(mStream, ",{} {}", metric.getFirstValueType(), stringValue); + } else { + mStream = fmt::format_to(mStream, " {}={}", value.first, stringValue); + } + } + // FIXME: tags are ignored by the DPL backend in any case... + mStream = fmt::format_to(mStream, " {} {}", convertTimestamp(metric.getTimestamp()), mTagString); + + bool first = mTagString.empty(); + for (const auto& [key, value] : metric.getTags()) { + if (!first) { + mStream = fmt::format_to(mStream, ","); + } + first = true; + mStream = fmt::format_to(mStream, "{}={}", o2::monitoring::tags::TAG_KEY[key], o2::monitoring::tags::GetValue(value)); + } + mStream = fmt::format_to(mStream, "\n"); + auto size = std::distance(buffer.begin(), mStream); + if (size + 1 >= 4096) { + throw runtime_error_f("Metric too long"); + } + buffer[size] = '\0'; + mRegistry.get<framework::DriverClient>().tell(buffer.data(), size); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DPLMonitoringBackend.h b/Framework/Core/src/DPLMonitoringBackend.h new file mode 100644 index 0000000000000..7e08383f03adf --- /dev/null +++ b/Framework/Core/src/DPLMonitoringBackend.h @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DPLMONITORINGBACKEND_H_ +#define O2_FRAMEWORK_DPLMONITORINGBACKEND_H_ + +#include "Monitoring/Backend.h" +#include <string> + +namespace o2::framework +{ + +struct ServiceRegistry; + +/// \brief Prints metrics to standard output via std::cout +class DPLMonitoringBackend final : public o2::monitoring::Backend +{ + public: + /// Default constructor + DPLMonitoringBackend(ServiceRegistry& registry); + + /// Default destructor + ~DPLMonitoringBackend() override = default; + + /// Prints metric + /// \param metric reference to metric object + void send(const o2::monitoring::Metric& metric) override; + + /// Prints vector of metrics + /// \@param metrics vector of metrics + void send(std::vector<o2::monitoring::Metric>&& metrics) override; + + /// Adds tag + /// \param name tag name + /// \param value tag value + void addGlobalTag(std::string_view name, std::string_view value) override; + + private: + std::string mTagString; ///< Global tagset (common for each metric) + const std::string mPrefix; ///< Metric prefix + ServiceRegistry& mRegistry; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DPLMONITORINGBACKEND_H_ diff --git a/Framework/Core/src/DPLWebSocket.cxx b/Framework/Core/src/DPLWebSocket.cxx new file mode 100644 index 0000000000000..be5d6ac48f935 --- /dev/null +++ b/Framework/Core/src/DPLWebSocket.cxx @@ -0,0 +1,424 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/Logger.h" +#include "DPLWebSocket.h" +#include "Framework/RuntimeError.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DeviceController.h" +#include "Framework/DevicesManager.h" +#include "DriverServerContext.h" +#include "DriverClientContext.h" +#include "HTTPParser.h" +#include <algorithm> +#include <atomic> +#include <uv.h> +#include <sys/types.h> +#include <unistd.h> + +namespace o2::framework +{ + +static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) +{ + buf->base = (char*)malloc(suggested_size); + buf->len = suggested_size; +} + +/// Free any resource associated with the device - driver channel +void websocket_server_close_callback(uv_handle_t* handle) +{ + LOG(DEBUG) << "socket closed"; + delete (WSDPLHandler*)handle->data; + free(handle); +} + +void ws_error_write_callback(uv_write_t* h, int status) +{ + LOG(ERROR) << "Error in write callback: " << uv_strerror(status); + if (h->data) { + free(h->data); + } + uv_close((uv_handle_t*)h->handle, websocket_server_close_callback); + free(h); +} + +/// Actually replies to any incoming websocket stuff. +void websocket_server_callback(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) +{ + WSDPLHandler* server = (WSDPLHandler*)stream->data; + assert(server); + if (nread == 0) { + return; + } + if (nread == UV_EOF) { + LOG(DEBUG) << "websocket_server_callback: communication with driver closed"; + uv_close((uv_handle_t*)stream, websocket_server_close_callback); + return; + } + if (nread < 0) { + LOG(ERROR) << "websocket_server_callback: Error while reading from websocket"; + uv_close((uv_handle_t*)stream, websocket_server_close_callback); + return; + } + try { + parse_http_request(buf->base, nread, server); + free(buf->base); + } catch (RuntimeErrorRef& ref) { + auto& err = o2::framework::error_from_ref(ref); + LOG(ERROR) << "Error while parsing request: " << err.what; + } +} + +/// Whenever we have handshaken correctly, we can wait for the +/// actual frames until we get an error. +void ws_handshake_done_callback(uv_write_t* h, int status) +{ + if (status) { + LOG(ERROR) << "uv_write error: " << uv_err_name(status); + free(h); + return; + } + uv_read_start((uv_stream_t*)h->handle, (uv_alloc_cb)my_alloc_cb, websocket_server_callback); +} + +WSDPLHandler::WSDPLHandler(uv_stream_t* s, DriverServerContext* context, std::unique_ptr<WebSocketHandler> h) + : mStream{s}, + mServerContext{context}, + mHandler{std::move(h)} +{ +} + +void WSDPLHandler::method(std::string_view const& s) +{ + if (s != "GET") { + throw WSError{400, "Bad Request"}; + } +} + +void WSDPLHandler::target(std::string_view const& s) +{ + if (s != "/") { + throw WSError{404, "Unknown"}; + } +} + +void populateHeader(std::map<std::string, std::string>& headers, std::string_view const& k, std::string_view const& v) +{ + std::string kk{k}; + std::string vv{v}; + std::transform(kk.begin(), kk.end(), kk.begin(), + [](unsigned char c) { return std::tolower(c); }); + if (kk != "sec-websocket-accept" && kk != "sec-websocket-key") { + std::transform(vv.begin(), vv.end(), vv.begin(), + [](unsigned char c) { return std::tolower(c); }); + } + headers.insert(std::make_pair(kk, vv)); +} + +void WSDPLHandler::header(std::string_view const& k, std::string_view const& v) +{ + populateHeader(mHeaders, k, v); +} + +void WSDPLHandler::endHeaders() +{ + /// Make sure this is a websocket upgrade request. + if (mHeaders["upgrade"] != "websocket") { + throw WSError{400, "Bad Request: not a websocket upgrade"}; + } + if (mHeaders["connection"] != "upgrade") { + throw WSError{400, "Bad Request: connection not for upgrade"}; + } + if (mHeaders["sec-websocket-protocol"] != "dpl") { + throw WSError{400, "Bad Request: websocket protocol not \"dpl\"."}; + } + if (mHeaders.count("sec-websocket-key") == 0) { + throw WSError{400, "Bad Request: sec-websocket-key missing"}; + } + if (mHeaders["sec-websocket-version"] != "13") { + throw WSError{400, "Bad Request: wrong protocol version"}; + } + mHandler->headers(mHeaders); + /// Create an appropriate reply + LOG(debug) << "Got upgrade request with nonce " << mHeaders["sec-websocket-key"].c_str(); + std::string reply = encode_websocket_handshake_reply(mHeaders["sec-websocket-key"].c_str()); + mHandshaken = true; + + uv_buf_t bfr = uv_buf_init(strdup(reply.data()), reply.size()); + uv_write_t* info_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + uv_write(info_req, (uv_stream_t*)mStream, &bfr, 1, ws_handshake_done_callback); + auto header = mHeaders.find("x-dpl-pid"); + if (header != mHeaders.end()) { + LOG(debug) << "Driver connected to PID : " << header->second; + for (size_t i = 0; i < mServerContext->infos->size(); ++i) { + if (std::to_string((*mServerContext->infos)[i].pid) == header->second) { + (*mServerContext->controls)[i].controller = new DeviceController{this}; + break; + } + } + } else { + LOG(INFO) << "Connection not bound to a PID"; + } +} + +/// Actual handling of WS frames happens inside here. +void WSDPLHandler::body(char* data, size_t s) +{ + decode_websocket(data, s, *mHandler.get()); +} + +void ws_server_write_callback(uv_write_t* h, int status) +{ + if (status) { + LOG(ERROR) << "uv_write error: " << uv_err_name(status); + free(h); + return; + } + if (h->data) { + free(h->data); + } + free(h); +} + +void ws_server_bulk_write_callback(uv_write_t* h, int status) +{ + if (status) { + LOG(ERROR) << "uv_write error: " << uv_err_name(status); + free(h); + return; + } + std::vector<uv_buf_t>* buffers = (std::vector<uv_buf_t>*)h->data; + if (buffers) { + for (auto& b : *buffers) { + free(b.base); + } + } + delete buffers; + free(h); +} + +void WSDPLHandler::write(char const* message, size_t s) +{ + uv_buf_t bfr = uv_buf_init(strdup(message), s); + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + write_req->data = bfr.base; + uv_write(write_req, (uv_stream_t*)mStream, &bfr, 1, ws_server_write_callback); +} + +void WSDPLHandler::write(std::vector<uv_buf_t>& outputs) +{ + if (outputs.empty()) { + return; + } + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + std::vector<uv_buf_t>* buffers = new std::vector<uv_buf_t>; + buffers->swap(outputs); + write_req->data = buffers; + uv_write(write_req, (uv_stream_t*)mStream, &buffers->at(0), buffers->size(), ws_server_bulk_write_callback); +} + +/// Helper to return an error +void WSDPLHandler::error(int code, char const* message) +{ + static char const* errorFMT = "HTTP/1.1 {} {}\r\ncontent-type: text/plain\r\n\r\n{}: {}\r\n"; + std::string error = fmt::format(errorFMT, code, message, code, message); + char* reply = strdup(error.data()); + uv_buf_t bfr = uv_buf_init(reply, error.size()); + uv_write_t* error_rep = (uv_write_t*)malloc(sizeof(uv_write_t)); + error_rep->data = reply; + uv_write(error_rep, (uv_stream_t*)mStream, &bfr, 1, ws_error_write_callback); +} + +void close_client_websocket(uv_handle_t* stream) +{ + LOG(debug) << "Closing websocket connection to server"; +} + +void websocket_client_callback(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) +{ + DriverClientContext* context = (DriverClientContext*)stream->data; + context->state->loopReason |= DeviceState::WS_COMMUNICATION; + assert(context->client); + if (nread == 0) { + return; + } + if (nread == UV_EOF) { + LOG(debug) << "EOF received from server, closing."; + uv_read_stop(stream); + uv_close((uv_handle_t*)stream, close_client_websocket); + return; + } + if (nread < 0) { + // FIXME: improve error message + // FIXME: should I close? + LOG(ERROR) << "Error while reading from websocket"; + uv_read_stop(stream); + uv_close((uv_handle_t*)stream, close_client_websocket); + return; + } + try { + LOG(debug) << "Data received from server"; + parse_http_request(buf->base, nread, context->client); + } catch (RuntimeErrorRef& ref) { + auto& err = o2::framework::error_from_ref(ref); + LOG(ERROR) << "Error while parsing request: " << err.what; + } +} + +// FIXME: mNonce should be random +WSDPLClient::WSDPLClient(uv_stream_t* s, std::unique_ptr<DriverClientContext> context, std::function<void()> handshake, std::unique_ptr<WebSocketHandler> handler) + : mStream{s}, + mNonce{"dGhlIHNhbXBsZSBub25jZQ=="}, + mContext{std::move(context)}, + mHandshake{handshake}, + mHandler{std::move(handler)} +{ + mContext->client = this; + s->data = mContext.get(); + uv_read_start((uv_stream_t*)s, (uv_alloc_cb)my_alloc_cb, websocket_client_callback); +} + +void WSDPLClient::sendHandshake() +{ + std::vector<std::pair<std::string, std::string>> headers = { + {{"x-dpl-pid"}, std::to_string(getpid())}, + {{"x-dpl-id"}, mContext->spec.id}, + {{"x-dpl-name"}, mContext->spec.name}}; + std::string handShakeString = encode_websocket_handshake_request("/", "dpl", 13, mNonce.c_str(), headers); + this->write(handShakeString.c_str(), handShakeString.size()); +} + +void WSDPLClient::replyVersion(std::string_view const& s) +{ + if (s != "HTTP/1.1") { + throw runtime_error("Not an HTTP reply"); + } +} + +void WSDPLClient::replyCode(std::string_view const& s) +{ + if (s != "101") { + throw runtime_error("Upgrade denied"); + } +} + +void WSDPLClient::header(std::string_view const& k, std::string_view const& v) +{ + populateHeader(mHeaders, k, v); +} + +void WSDPLClient::dumpHeaders() +{ + for (auto [k, v] : mHeaders) { + LOG(INFO) << k << ": " << v; + } +} + +void WSDPLClient::endHeaders() +{ + /// Make sure this is a websocket upgrade request. + if (mHeaders["upgrade"] != "websocket") { + throw runtime_error_f("No websocket upgrade"); + } + if (mHeaders["connection"] != "upgrade") { + throw runtime_error_f("No connection upgrade"); + } + if (mHeaders.count("sec-websocket-accept") == 0) { + throw runtime_error("sec-websocket-accept not found"); + } + + std::string expectedAccept = HTTPParserHelpers::calculateAccept(mNonce.c_str()); + if (mHeaders["sec-websocket-accept"] != expectedAccept) { + throw runtime_error_f(R"(Invalid accept received: "%s", expected "%s")", mHeaders["sec-websocket-accept"].c_str(), expectedAccept.c_str()); + } + + LOG(INFO) << "Correctly handshaken websocket connection."; + /// Create an appropriate reply + mHandshaken = true; + mHandshake(); +} + +struct WriteRequestContext { + uv_buf_t buf; + DeviceState* state; +}; + +struct BulkWriteRequestContext { + std::vector<uv_buf_t> buffers; + DeviceState* state; +}; + +void ws_client_write_callback(uv_write_t* h, int status) +{ + WriteRequestContext* context = (WriteRequestContext*)h->data; + if (status) { + LOG(ERROR) << "uv_write error: " << uv_err_name(status); + free(h); + return; + } + context->state->loopReason |= DeviceState::WS_COMMUNICATION; + if (context->buf.base) { + free(context->buf.base); + } + delete context; + free(h); +} + +void ws_client_bulk_write_callback(uv_write_t* h, int status) +{ + BulkWriteRequestContext* context = (BulkWriteRequestContext*)h->data; + context->state->loopReason |= DeviceState::WS_COMMUNICATION; + if (status < 0) { + LOG(ERROR) << "uv_write error: " << uv_err_name(status); + free(h); + return; + } + if (context->buffers.size()) { + for (auto& b : context->buffers) { + free(b.base); + } + } + delete context; + free(h); +} + +/// Actual handling of WS frames happens inside here. +void WSDPLClient::body(char* data, size_t s) +{ + decode_websocket(data, s, *mHandler.get()); +} + +/// Helper to return an error +void WSDPLClient::write(char const* message, size_t s) +{ + WriteRequestContext* context = new WriteRequestContext; + context->buf = uv_buf_init(strdup(message), s); + context->state = mContext->state; + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + write_req->data = context; + uv_write(write_req, (uv_stream_t*)mStream, &context->buf, 1, ws_client_write_callback); +} + +void WSDPLClient::write(std::vector<uv_buf_t>& outputs) +{ + if (outputs.empty()) { + return; + } + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + BulkWriteRequestContext* context = new BulkWriteRequestContext; + context->buffers.swap(outputs); + context->state = mContext->state; + write_req->data = context; + uv_write(write_req, (uv_stream_t*)mStream, &context->buffers.at(0), + context->buffers.size(), ws_client_bulk_write_callback); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DPLWebSocket.h b/Framework/Core/src/DPLWebSocket.h new file mode 100644 index 0000000000000..a52b9c5859d0d --- /dev/null +++ b/Framework/Core/src/DPLWebSocket.h @@ -0,0 +1,103 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DPLWEBSOCKET_H_ +#define O2_FRAMEWORK_DPLWEBSOCKET_H_ + +#include <uv.h> +#include "HTTPParser.h" +#include <memory> +#include <string> +#include <map> +#include <functional> +#include <atomic> + +class uv_stream_s; + +namespace o2::framework +{ + +struct DeviceSpec; +struct DriverServerContext; +struct DriverClientContext; + +struct WSError { + int code; + std::string message; +}; + +struct WSDPLHandler : public HTTPParser { + /// A http parser suitable to be used by DPL as a server + /// @a stream is the stream from which the data is read, + /// @a context to use to register the Handler to the appropriate + /// DeviceInfo. + /// @a handler is the websocket handler to react on the + /// various frames + WSDPLHandler(uv_stream_t* stream, DriverServerContext* context, std::unique_ptr<WebSocketHandler> handler); + void method(std::string_view const& s) override; + void target(std::string_view const& s) override; + void header(std::string_view const& k, std::string_view const& v) override; + void endHeaders() override; + /// Actual handling of WS frames happens inside here. + void body(char* data, size_t s) override; + /// Helper to write a message to the associated client + void write(char const*, size_t); + + /// Helper to write n buffers containing websockets frames to a server + void write(std::vector<uv_buf_t>& outputs); + + /// Helper to return an error + void error(int code, char const* message); + + std::unique_ptr<WebSocketHandler> mHandler; + bool mHandshaken = false; + uv_stream_t* mStream = nullptr; + std::map<std::string, std::string> mHeaders; + DriverServerContext* mServerContext; +}; + +struct WSDPLClient : public HTTPParser { + /// @a stream where the communication happens and @a spec of the device connecting + /// to the driver. + /// @a spec the DeviceSpec associated with this client + /// @a handshake a callback to invoke whenever we have a successful handshake + WSDPLClient(uv_stream_t* stream, + std::unique_ptr<DriverClientContext> context, + std::function<void()> handshake, + std::unique_ptr<WebSocketHandler> handler); + + void replyVersion(std::string_view const& s) override; + void replyCode(std::string_view const& s) override; + void header(std::string_view const& k, std::string_view const& v) override; + void endHeaders() override; + /// Actual handling of WS frames happens inside here. + void body(char* data, size_t s) override; + /// Helper to write a message to the server + void write(char const*, size_t); + + /// Helper to write n buffers containing websockets frames to a server + void write(std::vector<uv_buf_t>& outputs); + + /// Dump headers + void dumpHeaders(); + void sendHandshake(); + bool isHandshaken() { return mHandshaken; } + + std::string mNonce; + std::atomic<bool> mHandshaken = false; + std::function<void()> mHandshake; + std::unique_ptr<DriverClientContext> mContext; + std::unique_ptr<WebSocketHandler> mHandler; + uv_stream_t* mStream = nullptr; + std::map<std::string, std::string> mHeaders; +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DPL_WEBSOCKET_H_ diff --git a/Framework/Core/src/DataAllocator.cxx b/Framework/Core/src/DataAllocator.cxx index 48d9eacaf3586..bb6b66be8b752 100644 --- a/Framework/Core/src/DataAllocator.cxx +++ b/Framework/Core/src/DataAllocator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include <arrow/ipc/writer.h> #include <arrow/type.h> #include <arrow/io/memory.h> +#include <arrow/util/config.h> #include <TClonesArray.h> @@ -98,6 +100,9 @@ FairMQMessagePtr DataAllocator::headerMessageFromOutput(Output const& spec, dh.subSpecification = spec.subSpec; dh.payloadSize = payloadSize; dh.payloadSerializationMethod = method; + dh.tfCounter = mTimingInfo->tfCounter; + dh.firstTForbit = mTimingInfo->firstTFOrbit; + dh.runNumber = mTimingInfo->runNumber; DataProcessingHeader dph{mTimingInfo->timeslice, 1}; auto& context = mRegistry->get<MessageContext>(); @@ -150,19 +155,43 @@ void DataAllocator::adopt(const Output& spec, TableBuilder* tb) std::shared_ptr<TableBuilder> p(tb); auto finalizer = [payload = p](std::shared_ptr<FairMQResizableBuffer> b) -> void { auto table = payload->finalize(); - if (O2_BUILTIN_UNLIKELY(table->num_rows() == 0)) { - LOG(DEBUG) << "Empty table was produced: " << table->ToString(); + + auto mock = std::make_shared<arrow::io::MockOutputStream>(); + int64_t expectedSize = 0; + if (O2_BUILTIN_UNLIKELY(table->num_rows() != 0)) { + auto mockBatch = arrow::ipc::MakeStreamWriter(mock.get(), table->schema()); + auto outStatus = mockBatch.ValueOrDie()->WriteTable(*table); + expectedSize = mock->Tell().ValueOrDie(); + // Arrow grows buffers by multiplying by 2x, regardless of the + // fact we actually know the size. + auto expectedPow2 = (1 << (64 - __builtin_clzl(expectedSize))); + auto reserve = b->Reserve(expectedSize + 2048 * 1024); + if (reserve.ok() == false) { + throw std::runtime_error("Unable to reserve memory for table"); + } } - auto stream = std::make_shared<arrow::io::BufferOutputStream>(b); - auto outBatch = arrow::ipc::NewStreamWriter(stream.get(), table->schema()); - if (outBatch.ok() == true) { - auto outStatus = outBatch.ValueOrDie()->WriteTable(*table); - if (outStatus.ok() == false) { - throw std::runtime_error("Unable to Write table"); + auto stream = std::make_shared<FairMQOutputStream>(b); + auto outBatch = arrow::ipc::MakeStreamWriter(stream.get(), table->schema()); + if (outBatch.ok() == false) { + throw ::std::runtime_error("Unable to create batch writer"); + } + arrow::Status outStatus; + + if (O2_BUILTIN_UNLIKELY(table->num_rows() == 0)) { + std::vector<std::shared_ptr<arrow::Array>> columns; + columns.resize(table->columns().size()); + for (size_t ci = 0; ci < table->columns().size(); ci++) { + columns[ci] = table->column(ci)->chunk(0); } + auto batch = arrow::RecordBatch::Make(table->schema(), 0, columns); + outStatus = outBatch.ValueOrDie()->WriteRecordBatch(*batch); } else { - throw ::std::runtime_error("Unable to create batch writer"); + outStatus = outBatch.ValueOrDie()->WriteTable(*table); + } + + if (outStatus.ok() == false) { + throw std::runtime_error("Unable to Write table"); } }; @@ -187,8 +216,21 @@ void DataAllocator::adopt(const Output& spec, TreeToTable* t2t) auto finalizer = [payload = t2t](std::shared_ptr<FairMQResizableBuffer> b) -> void { auto table = payload->finalize(); - auto stream = std::make_shared<arrow::io::BufferOutputStream>(b); - auto outBatch = arrow::ipc::NewStreamWriter(stream.get(), table->schema()); + auto mock = std::make_shared<arrow::io::MockOutputStream>(); + auto mockBatch = arrow::ipc::MakeStreamWriter(mock.get(), table->schema()); + auto outStatus = mockBatch.ValueOrDie()->WriteTable(*table); + auto expectedSize = mock->Tell(); + + auto stream = std::make_shared<FairMQOutputStream>(b); + + // Arrow grows buffers by multiplying by 2x, regardless of the + // fact we actually know the size. + auto expectedPow2 = (1 << (64 - __builtin_clzl(*expectedSize))); + auto reserve = b->Reserve(*expectedSize + 1024 * 2048); + if (reserve.ok() == false) { + throw std::runtime_error("Unable to reserve memory for table"); + } + auto outBatch = arrow::ipc::MakeStreamWriter(stream.get(), table->schema()); if (outBatch.ok() == true) { auto outStatus = outBatch.ValueOrDie()->WriteTable(*table); if (outStatus.ok() == false) { @@ -215,8 +257,20 @@ void DataAllocator::adopt(const Output& spec, std::shared_ptr<arrow::Table> ptr) auto buffer = std::make_shared<FairMQResizableBuffer>(creator); auto writer = [table = ptr](std::shared_ptr<FairMQResizableBuffer> b) -> void { - auto stream = std::make_shared<arrow::io::BufferOutputStream>(b); - auto outBatch = arrow::ipc::NewStreamWriter(stream.get(), table->schema()); + auto mock = std::make_shared<arrow::io::MockOutputStream>(); + auto mockBatch = arrow::ipc::MakeStreamWriter(mock.get(), table->schema()); + auto outStatus = mockBatch.ValueOrDie()->WriteTable(*table); + auto expectedSize = mock->Tell(); + + auto stream = std::make_shared<FairMQOutputStream>(b); + // Arrow grows buffers by multiplying by 2x, regardless of the + // fact we actually know the size. + auto expectedPow2 = (1 << (64 - __builtin_clzl(*expectedSize))); + auto reserve = b->Reserve(*expectedSize + 1024 * 2048); + if (reserve.ok() == false) { + throw std::runtime_error("Unable to reserve memory for table"); + } + auto outBatch = arrow::ipc::MakeStreamWriter(stream.get(), table->schema()); if (outBatch.ok() == true) { auto outStatus = outBatch.ValueOrDie()->WriteTable(*table); if (outStatus.ok() == false) { diff --git a/Framework/Core/src/DataDescriptorMatcher.cxx b/Framework/Core/src/DataDescriptorMatcher.cxx index ba08fd67ff50e..6e31bb3087ca9 100644 --- a/Framework/Core/src/DataDescriptorMatcher.cxx +++ b/Framework/Core/src/DataDescriptorMatcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,11 +17,7 @@ #include "Framework/RuntimeError.h" #include <iostream> -namespace o2 -{ -namespace framework -{ -namespace data_matcher +namespace o2::framework::data_matcher { ContextElement::Value const& VariableContext::get(size_t pos) const @@ -101,7 +98,7 @@ bool SubSpecificationTypeValueMatcher::match(header::DataHeader const& header, V /// This will match the timing information which is currently in /// the DataProcessingHeader. Notice how we apply the scale to the /// actual values found. -bool StartTimeValueMatcher::match(DataProcessingHeader const& dph, VariableContext& context) const +bool StartTimeValueMatcher::match(header::DataHeader const& dh, DataProcessingHeader const& dph, VariableContext& context) const { if (auto ref = std::get_if<ContextRef>(&mValue)) { auto& variable = context.get(ref->index); @@ -109,6 +106,12 @@ bool StartTimeValueMatcher::match(DataProcessingHeader const& dph, VariableConte return (dph.startTime / mScale) == *value; } context.put({ref->index, dph.startTime / mScale}); + // We always put in 13 the runNumber + context.put({RUNNUMBER_POS, dh.runNumber}); + // We always put in 14 the tfCounter + context.put({TFCOUNTER_POS, dh.tfCounter}); + // We always put in 15 the firstTForbit + context.put({FIRSTTFORBIT_POS, dh.firstTForbit}); return true; } else if (auto v = std::get_if<uint64_t>(&mValue)) { return (dph.startTime / mScale) == *v; @@ -262,11 +265,12 @@ bool DataDescriptorMatcher::match(char const* d, VariableContext& context) const } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&mLeft)) { leftValue = pval4->match(); } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&mLeft)) { + auto dh = o2::header::get<header::DataHeader*>(d); auto dph = o2::header::get<DataProcessingHeader*>(d); if (dph == nullptr) { throw runtime_error("Cannot find DataProcessingHeader"); } - leftValue = pval5->match(*dph, context); + leftValue = pval5->match(*dh, *dph, context); } else { throw runtime_error("Bad parsing tree"); } @@ -295,8 +299,9 @@ bool DataDescriptorMatcher::match(char const* d, VariableContext& context) const } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&mRight)) { rightValue = pval4->match(); } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&mRight)) { + auto dh = o2::header::get<header::DataHeader*>(d); auto dph = o2::header::get<DataProcessingHeader*>(d); - rightValue = pval5->match(*dph, context); + rightValue = pval5->match(*dh, *dph, context); } // There are cases in which not having a rightValue might be legitimate, // so we do not throw an exception. @@ -478,6 +483,4 @@ std::ostream& operator<<(std::ostream& os, DataDescriptorMatcher::Op const& op) return os; } -} // namespace data_matcher -} // namespace framework -} // namespace o2 +} // namespace o2::framework::data_matcher diff --git a/Framework/Core/src/DataDescriptorQueryBuilder.cxx b/Framework/Core/src/DataDescriptorQueryBuilder.cxx index 2edbb4f84be5d..fa01609270c1b 100644 --- a/Framework/Core/src/DataDescriptorQueryBuilder.cxx +++ b/Framework/Core/src/DataDescriptorQueryBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DataInputDirector.cxx b/Framework/Core/src/DataInputDirector.cxx index 24dd25cdc7b90..31c8e86ee5ebd 100644 --- a/Framework/Core/src/DataInputDirector.cxx +++ b/Framework/Core/src/DataInputDirector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -102,10 +103,11 @@ bool DataInputDescriptor::setFile(int counter) if (!mcurrentFile) { throw std::runtime_error(fmt::format("Couldn't open file \"{}\"!", filename)); } + mcurrentFile->SetReadaheadSize(50 * 1024 * 1024); // get the directory names if (mfilenames[counter]->numberOfTimeFrames <= 0) { - std::regex TFRegex = std::regex("TF_[0-9]+"); + std::regex TFRegex = std::regex("DF_[0-9]+"); TList* keyList = mcurrentFile->GetListOfKeys(); // extract TF numbers and sort accordingly @@ -118,7 +120,7 @@ bool DataInputDescriptor::setFile(int counter) std::sort(mfilenames[counter]->listOfTimeFrameNumbers.begin(), mfilenames[counter]->listOfTimeFrameNumbers.end()); for (auto folderNumber : mfilenames[counter]->listOfTimeFrameNumbers) { - auto folderName = "TF_" + std::to_string(folderNumber); + auto folderName = "DF_" + std::to_string(folderNumber); mfilenames[counter]->listOfTimeFrameKeys.emplace_back(folderName); } mfilenames[counter]->numberOfTimeFrames = mfilenames[counter]->listOfTimeFrameKeys.size(); @@ -163,6 +165,11 @@ FileAndFolder DataInputDescriptor::getFileFolder(int counter, int numTF) return fileAndFolder; } +int DataInputDescriptor::getTimeFramesInFile(int counter) +{ + return mfilenames.at(counter)->numberOfTimeFrames; +} + void DataInputDescriptor::closeInputFile() { if (mcurrentFile) { @@ -525,6 +532,17 @@ FileAndFolder DataInputDirector::getFileFolder(header::DataHeader dh, int counte return didesc->getFileFolder(counter, numTF); } +int DataInputDirector::getTimeFramesInFile(header::DataHeader dh, int counter) +{ + auto didesc = getDataInputDescriptor(dh); + // if NOT match then use defaultDataInputDescriptor + if (!didesc) { + didesc = mdefaultDataInputDescriptor; + } + + return didesc->getTimeFramesInFile(counter); +} + uint64_t DataInputDirector::getTimeFrameNumber(header::DataHeader dh, int counter, int numTF) { auto didesc = getDataInputDescriptor(dh); @@ -558,7 +576,7 @@ TTree* DataInputDirector::getDataTree(header::DataHeader dh, int counter, int nu treename = fileAndFolder.folderName + "/" + treename; tree = (TTree*)fileAndFolder.file->Get(treename.c_str()); if (!tree) { - throw std::runtime_error(fmt::format(R"(Couldn't get TTree "{}" from "{}")", treename, fileAndFolder.file->GetName())); + throw std::runtime_error(fmt::format(R"(Couldn't get TTree "{}" from "{}". Please check https://aliceo2group.github.io/analysis-framework/docs/troubleshooting/treenotfound.html for more information.)", treename, fileAndFolder.file->GetName())); } } diff --git a/Framework/Core/src/DataOutputDirector.cxx b/Framework/Core/src/DataOutputDirector.cxx index 4c71b4ef1e554..3ac517636db2d 100644 --- a/Framework/Core/src/DataOutputDirector.cxx +++ b/Framework/Core/src/DataOutputDirector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -439,12 +440,12 @@ FileAndFolder DataOutputDirector::getFileFolder(DataOutputDescriptor* dodesc, ui int ind = std::distance(mfilenameBases.begin(), it); if (!mfilePtrs[ind]->IsOpen()) { auto fn = mfilenameBases[ind] + ".root"; - mfilePtrs[ind] = new TFile(fn.c_str(), mfileMode.c_str()); + mfilePtrs[ind] = new TFile(fn.c_str(), mfileMode.c_str(), "", 501); } fileAndFolder.file = mfilePtrs[ind]; - // check if folder TF_* exists - fileAndFolder.folderName = "TF_" + std::to_string(folderNumber) + "/"; + // check if folder DF_* exists + fileAndFolder.folderName = "DF_" + std::to_string(folderNumber) + "/"; auto key = fileAndFolder.file->GetKey(fileAndFolder.folderName.c_str()); if (!key) { fileAndFolder.file->mkdir(fileAndFolder.folderName.c_str()); diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index b47fb52cac873..79d371d8ae7b8 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "Framework/DataProcessingDevice.h" #include "Framework/ChannelMatching.h" #include "Framework/ControlService.h" +#include "Framework/ComputingQuotaEvaluator.h" #include "Framework/DataProcessingHeader.h" #include "Framework/DataProcessor.h" #include "Framework/DataSpecUtils.h" @@ -21,6 +23,7 @@ #include "Framework/DispatchPolicy.h" #include "Framework/DispatchControl.h" #include "Framework/DanglingContext.h" +#include "Framework/DriverClient.h" #include "Framework/EndOfStreamContext.h" #include "Framework/FairOptionsRetriever.h" #include "ConfigurationOptionsRetriever.h" @@ -28,9 +31,11 @@ #include "Framework/CallbackService.h" #include "Framework/TMessageSerializer.h" #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/Signpost.h" #include "Framework/SourceInfoHeader.h" #include "Framework/Logger.h" +#include "Framework/DriverClient.h" #include "Framework/Monitoring.h" #include "PropertyTreeHelpers.h" #include "DataProcessingStatus.h" @@ -55,18 +60,13 @@ #include <unordered_map> #include <uv.h> #include <execinfo.h> +#include <sstream> +#include <boost/property_tree/json_parser.hpp> using namespace o2::framework; -using Key = o2::monitoring::tags::Key; -using Value = o2::monitoring::tags::Value; -using Metric = o2::monitoring::Metric; -using Monitoring = o2::monitoring::Monitoring; using ConfigurationInterface = o2::configuration::ConfigurationInterface; using DataHeader = o2::header::DataHeader; -constexpr unsigned int MONITORING_QUEUE_SIZE = 100; -constexpr unsigned int MIN_RATE_LOGGING = 60; - namespace o2::framework { @@ -77,22 +77,31 @@ struct ServiceKindExtractor<ConfigurationInterface> { /// We schedule a timer to reduce CPU usage. /// Watching stdin for commands probably a better approach. -void idle_timer(uv_timer_t* handle) +void on_idle_timer(uv_timer_t* handle) { ZoneScopedN("Idle timer"); + DeviceState* state = (DeviceState*)handle->data; + state->loopReason |= DeviceState::TIMER_EXPIRED; } -DataProcessingDevice::DataProcessingDevice(DeviceSpec const& spec, ServiceRegistry& registry, DeviceState& state) - : mSpec{spec}, - mState{state}, - mInit{spec.algorithm.onInit}, +void on_communication_requested(uv_async_t* s) +{ + DeviceState* state = (DeviceState*)s->data; + state->loopReason |= DeviceState::METRICS_MUST_FLUSH; +} + +DataProcessingDevice::DataProcessingDevice(RunningDeviceRef ref, ServiceRegistry& registry) + : mSpec{registry.get<RunningWorkflowInfo const>().devices[ref.index]}, + mState{registry.get<DeviceState>()}, + mInit{mSpec.algorithm.onInit}, mStatefulProcess{nullptr}, - mStatelessProcess{spec.algorithm.onProcess}, - mError{spec.algorithm.onError}, + mStatelessProcess{mSpec.algorithm.onProcess}, + mError{mSpec.algorithm.onError}, mConfigRegistry{nullptr}, - mAllocator{&mTimingInfo, ®istry, spec.outputs}, mServiceRegistry{registry}, - mErrorCount{0} + mAllocator{&mTimingInfo, ®istry, mSpec.outputs}, + mQuotaEvaluator{registry.get<ComputingQuotaEvaluator>()}, + mAwakeHandle{nullptr} { /// FIXME: move erro handling to a service? if (mError != nullptr) { @@ -102,7 +111,7 @@ DataProcessingDevice::DataProcessingDevice(DeviceSpec const& spec, ServiceRegist auto& err = error_from_ref(e); LOGP(ERROR, "Exception caught: {} ", err.what); backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); - serviceRegistry.get<Monitoring>().send({1, "error"}); + serviceRegistry.get<DataProcessingStats>().exceptionCount++; ErrorContext errorContext{record, serviceRegistry, e}; errorCallback(errorContext); }; @@ -113,7 +122,7 @@ DataProcessingDevice::DataProcessingDevice(DeviceSpec const& spec, ServiceRegist auto& err = error_from_ref(e); LOGP(ERROR, "Exception caught: {} ", err.what); backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); - serviceRegistry.get<Monitoring>().send({1, "error"}); + serviceRegistry.get<DataProcessingStats>().exceptionCount++; switch (errorPolicy) { case TerminationPolicy::QUIT: throw e; @@ -122,6 +131,32 @@ DataProcessingDevice::DataProcessingDevice(DeviceSpec const& spec, ServiceRegist } }; } + // One task for now. + mStreams.resize(1); + mHandles.resize(1); + + mDeviceContext.device = this; + mDeviceContext.spec = &mSpec; + mDeviceContext.state = &mState; + mDeviceContext.quotaEvaluator = &mQuotaEvaluator; + mDeviceContext.stats = &mStats; + + mAwakeHandle = (uv_async_t*)malloc(sizeof(uv_async_t)); + assert(mState.loop); + int res = uv_async_init(mState.loop, mAwakeHandle, on_communication_requested); + mAwakeHandle->data = &mState; + if (res < 0) { + LOG(ERROR) << "Unable to initialise subscription"; + } + + /// This should post a message on the queue... + SubscribeToNewTransition("dpl", [wakeHandle = mAwakeHandle, deviceContext = &mDeviceContext](fair::mq::Transition t) { + int res = uv_async_send(wakeHandle); + if (res < 0) { + LOG(ERROR) << "Unable to notify subscription"; + } + LOG(debug) << "State transition requested"; + }); } // Callback to execute the processing. Notice how the data is @@ -130,8 +165,8 @@ DataProcessingDevice::DataProcessingDevice(DeviceSpec const& spec, ServiceRegist void run_callback(uv_work_t* handle) { ZoneScopedN("run_callback"); - std::vector<DataProcessorContext>* contexes = (std::vector<DataProcessorContext>*)handle->data; - DataProcessorContext& context = contexes->at(0); + TaskStreamInfo* task = (TaskStreamInfo*)handle->data; + DataProcessorContext& context = *task->context; DataProcessingDevice::doPrepare(context); DataProcessingDevice::doRun(context); // FrameMark; @@ -140,28 +175,59 @@ void run_callback(uv_work_t* handle) // Once the processing in a thread is done, this is executed on the main thread. void run_completion(uv_work_t* handle, int status) { + TaskStreamInfo* task = (TaskStreamInfo*)handle->data; + DataProcessorContext& context = *task->context; + + using o2::monitoring::Metric; + using o2::monitoring::Monitoring; + using o2::monitoring::tags::Key; + using o2::monitoring::tags::Value; + + static std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats&)> reportConsumedOffer = [&monitoring = context.registry->get<Monitoring>()](ComputingQuotaOffer const& accumulatedConsumed, ComputingQuotaStats& stats) { + stats.totalConsumedBytes += accumulatedConsumed.sharedMemory; + monitoring.send(Metric{(uint64_t)stats.totalConsumedBytes, "shm-offer-bytes-consumed"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.flushBuffer(); + }; + + static std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats const&)> reportExpiredOffer = [&monitoring = context.registry->get<Monitoring>()](ComputingQuotaOffer const& offer, ComputingQuotaStats const& stats) { + monitoring.send(Metric{(uint64_t)stats.totalExpiredOffers, "resource-offer-expired"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{(uint64_t)stats.totalExpiredBytes, "arrow-bytes-expired"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.flushBuffer(); + }; + + for (auto& consumer : context.deviceContext->state->offerConsumers) { + context.deviceContext->quotaEvaluator->consume(task->id.index, consumer, reportConsumedOffer); + } + context.deviceContext->state->offerConsumers.clear(); + context.deviceContext->quotaEvaluator->handleExpired(reportExpiredOffer); + context.deviceContext->quotaEvaluator->dispose(task->id.index); + task->running = false; ZoneScopedN("run_completion"); } // Context for polling struct PollerContext { - char const* name; - uv_loop_t* loop; - DataProcessingDevice* device; + char const* name = nullptr; + uv_loop_t* loop = nullptr; + DataProcessingDevice* device = nullptr; + DeviceState* state = nullptr; int fd; }; void on_socket_polled(uv_poll_t* poller, int status, int events) { PollerContext* context = (PollerContext*)poller->data; + context->state->loopReason |= DeviceState::DATA_SOCKET_POLLED; switch (events) { case UV_READABLE: { ZoneScopedN("socket readable event"); LOG(debug) << "socket polled UV_READABLE: " << context->name; + context->state->loopReason |= DeviceState::DATA_INCOMING; } break; case UV_WRITABLE: { ZoneScopedN("socket writeable"); LOG(debug) << "socket polled UV_WRITEABLE"; + context->state->loopReason |= DeviceState::DATA_OUTGOING; } break; case UV_DISCONNECT: { ZoneScopedN("socket disconnect"); @@ -175,6 +241,7 @@ void on_socket_polled(uv_poll_t* poller, int status, int events) // We do nothing, all the logic for now stays in DataProcessingDevice::doRun() } + /// This takes care of initialising the device from its specification. In /// particular it needs to: /// @@ -187,57 +254,33 @@ void DataProcessingDevice::Init() TracyAppInfo(mSpec.name.data(), mSpec.name.size()); ZoneScopedN("DataProcessingDevice::Init"); mRelayer = &mServiceRegistry.get<DataRelayer>(); - // For some reason passing rateLogging does not work anymore. - // This makes sure we never have more than one notification per minute. - for (auto& x : fChannels) { - for (auto& c : x.second) { - if (c.GetRateLogging() < MIN_RATE_LOGGING) { - c.UpdateRateLogging(MIN_RATE_LOGGING); - } - } - } - // If available use the ConfigurationInterface, otherwise go for - // the command line options. - bool hasConfiguration = false; - bool hasOverrides = false; - if (mServiceRegistry.active<ConfigurationInterface>()) { - auto& cfg = mServiceRegistry.get<ConfigurationInterface>(); - hasConfiguration = true; - try { - cfg.getRecursive(mSpec.name); - hasOverrides = true; - } catch (...) { - // No overrides... - } - } - // We only use the configuration file if we have a stanza for the given - // dataprocessor - std::vector<std::unique_ptr<ParamRetriever>> retrievers; - if (hasConfiguration && hasOverrides) { - auto& cfg = mServiceRegistry.get<ConfigurationInterface>(); - retrievers.emplace_back(std::make_unique<ConfigurationOptionsRetriever>(&cfg, mSpec.name)); - } else { + + auto configStore = DeviceConfigurationHelpers::getConfiguration(mServiceRegistry, mSpec.name.c_str(), mSpec.options); + if (configStore == nullptr) { + std::vector<std::unique_ptr<ParamRetriever>> retrievers; retrievers.emplace_back(std::make_unique<FairOptionsRetriever>(GetConfig())); + configStore = std::make_unique<ConfigParamStore>(mSpec.options, std::move(retrievers)); + configStore->preload(); + configStore->activate(); } - auto configStore = std::move(std::make_unique<ConfigParamStore>(mSpec.options, std::move(retrievers))); - configStore->preload(); - configStore->activate(); + using boost::property_tree::ptree; /// Dump the configuration so that we can get it from the driver. for (auto& entry : configStore->store()) { - LOG(INFO) << "[CONFIG] " << entry.first << "=" << configStore->store().get<std::string>(entry.first) << " 1 " << configStore->provenance(entry.first.c_str()); - PropertyTreeHelpers::WalkerFunction printer = [&configStore, topLevel = entry.first](ptree const& parent, ptree::path_type childPath, ptree const& child) { - // FIXME: not clear why we get invoked for the root entry - // and twice for each node. It nevertheless works - // because the net result is that we call twice - // ptree put. - if (childPath.dump() != "") { - LOG(INFO) << "[CONFIG] " << topLevel << "." << childPath.dump() << "=" << child.data() << " 1 " << configStore->provenance(topLevel.c_str()); - } - }; - PropertyTreeHelpers::traverse(entry.second, printer); + std::stringstream ss; + std::string str; + if (entry.second.empty() == false) { + boost::property_tree::json_parser::write_json(ss, entry.second, false); + str = ss.str(); + str.pop_back(); //remove EoL + } else { + str = entry.second.get_value<std::string>(); + } + std::string configString = fmt::format("[CONFIG];{}={};1;{}", entry.first, str, configStore->provenance(entry.first.c_str())).c_str(); + mServiceRegistry.get<DriverClient>().tell(configString.c_str()); } + mConfigRegistry = std::make_unique<ConfigParamRegistry>(std::move(configStore)); mExpirationHandlers.clear(); @@ -259,12 +302,6 @@ void DataProcessingDevice::Init() mExpirationHandlers.emplace_back(std::move(handler)); } - auto& monitoring = mServiceRegistry.get<Monitoring>(); - monitoring.enableBuffering(MONITORING_QUEUE_SIZE); - static const std::string dataProcessorIdMetric = "dataprocessor_id"; - static const std::string dataProcessorIdValue = mSpec.name; - monitoring.addGlobalTag("dataprocessor_id", dataProcessorIdValue); - if (mInit) { InitContext initContext{*mConfigRegistry, mServiceRegistry}; mStatefulProcess = mInit(initContext); @@ -275,9 +312,9 @@ void DataProcessingDevice::Init() /// expect them to create any data. for (size_t ci = 0; ci < mSpec.inputChannels.size(); ++ci) { auto& name = mSpec.inputChannels[ci].name; - if (name.find("from_internal-dpl-clock") == 0) { + if (name.find(mSpec.channelPrefix + "from_internal-dpl-clock") == 0) { mState.inputChannelInfos[ci].state = InputChannelState::Pull; - } else if (name.find("from_internal-dpl-ccdb-backend") == 0) { + } else if (name.find(mSpec.channelPrefix + "from_internal-dpl-ccdb-backend") == 0) { mState.inputChannelInfos[ci].state = InputChannelState::Pull; } } @@ -287,19 +324,82 @@ void on_signal_callback(uv_signal_t* handle, int signum) { ZoneScopedN("Signal callaback"); LOG(debug) << "Signal " << signum << " received."; + DeviceContext* context = (DeviceContext*)handle->data; + context->state->loopReason |= DeviceState::SIGNAL_ARRIVED; + size_t ri = 0; + while (ri != context->quotaEvaluator->mOffers.size()) { + auto& offer = context->quotaEvaluator->mOffers[ri]; + // We were already offered some sharedMemory, so we + // do not consider the offer. + // FIXME: in principle this should account for memory + // available and being offered, however we + // want to get out of the woods for now. + if (offer.valid && offer.sharedMemory != 0) { + return; + } + ri++; + } + // Find the first empty offer and have 1GB of shared memory there + for (size_t i = 0; i < context->quotaEvaluator->mOffers.size(); ++i) { + auto& offer = context->quotaEvaluator->mOffers[i]; + if (offer.valid == false) { + offer.cpu = 0; + offer.memory = 0; + offer.sharedMemory = 1000000000; + offer.valid = true; + offer.user = -1; + break; + } + } + context->stats->totalSigusr1 += 1; } +/// Invoke the callbacks for the mPendingRegionInfos +void handleRegionCallbacks(ServiceRegistry& registry, std::vector<FairMQRegionInfo>& infos) +{ + if (infos.empty() == false) { + std::vector<FairMQRegionInfo> toBeNotified; + toBeNotified.swap(infos); // avoid any MT issue. + for (auto const& info : toBeNotified) { + registry.get<CallbackService>()(CallbackService::Id::RegionInfoCallback, info); + } + } +} + +namespace +{ +void on_awake_main_thread(uv_async_t* handle) +{ + DeviceState* state = (DeviceState*)handle->data; + state->loopReason |= DeviceState::ASYNC_NOTIFICATION; +} +} // namespace void DataProcessingDevice::InitTask() { + if (mState.awakeMainThread == nullptr) { + mState.awakeMainThread = (uv_async_t*)malloc(sizeof(uv_async_t)); + mState.awakeMainThread->data = &mState; + uv_async_init(mState.loop, mState.awakeMainThread, on_awake_main_thread); + } + + mDeviceContext.expectedRegionCallbacks = std::stoi(fConfig->GetValue<std::string>("expected-region-callbacks")); + for (auto& channel : fChannels) { - channel.second.at(0).Transport()->SubscribeToRegionEvents([& pendingRegionInfos = mPendingRegionInfos, ®ionInfoMutex = mRegionInfoMutex](FairMQRegionInfo info) { + channel.second.at(0).Transport()->SubscribeToRegionEvents([this, + &context = mDeviceContext, + ®istry = mServiceRegistry, + &pendingRegionInfos = mPendingRegionInfos, + ®ionInfoMutex = mRegionInfoMutex](FairMQRegionInfo info) { std::lock_guard<std::mutex> lock(regionInfoMutex); LOG(debug) << ">>> Region info event" << info.event; LOG(debug) << "id: " << info.id; LOG(debug) << "ptr: " << info.ptr; LOG(debug) << "size: " << info.size; LOG(debug) << "flags: " << info.flags; + context.expectedRegionCallbacks -= 1; pendingRegionInfos.push_back(info); + // We always want to handle these on the main loop + uv_async_send(registry.get<DeviceState>().awakeMainThread); }); } @@ -309,12 +409,8 @@ void DataProcessingDevice::InitTask() // is no data pending to be processed. uv_signal_t* sigusr1Handle = (uv_signal_t*)malloc(sizeof(uv_signal_t)); uv_signal_init(mState.loop, sigusr1Handle); + sigusr1Handle->data = &mDeviceContext; uv_signal_start(sigusr1Handle, on_signal_callback, SIGUSR1); - // Handle SIGWINCH by simply forcing the event loop to continue. - // This will hopefully hide it from FairMQ on linux. - uv_signal_t* sigwinchHandle = (uv_signal_t*)malloc(sizeof(uv_signal_t)); - uv_signal_init(mState.loop, sigwinchHandle); - uv_signal_start(sigwinchHandle, on_signal_callback, SIGWINCH); // We add a timer only in case a channel poller is not there. if ((mStatefulProcess != nullptr) || (mStatelessProcess != nullptr)) { @@ -344,6 +440,7 @@ void DataProcessingDevice::InitTask() pCtx->name = strdup(x.first.c_str()); pCtx->loop = mState.loop; pCtx->device = this; + pCtx->state = &mState; pCtx->fd = zmq_fd; poller->data = pCtx; uv_poll_init(mState.loop, poller, zmq_fd); @@ -355,11 +452,11 @@ void DataProcessingDevice::InitTask() // devices to allow for enumerations. if (mState.activeInputPollers.empty() && mState.activeTimers.empty() && mState.activeSignals.empty()) { for (auto& x : fChannels) { - if (x.first.rfind("from_internal-dpl", 0) == 0) { + if (x.first.rfind(mSpec.channelPrefix + "from_internal-dpl", 0) == 0) { LOG(debug) << x.first << " is an internal channel. Not polling." << std::endl; continue; } - assert(x.first.rfind("from_" + mSpec.name + "_", 0) == 0); + assert(x.first.rfind(mSpec.channelPrefix + "from_" + mSpec.name + "_", 0) == 0); // We assume there is always a ZeroMQ socket behind. int zmq_fd = 0; size_t zmq_fd_len = sizeof(zmq_fd); @@ -376,6 +473,7 @@ void DataProcessingDevice::InitTask() pCtx->name = strdup(x.first.c_str()); pCtx->loop = mState.loop; pCtx->device = this; + pCtx->state = &mState; pCtx->fd = zmq_fd; poller->data = pCtx; uv_poll_init(mState.loop, poller, zmq_fd); @@ -389,7 +487,8 @@ void DataProcessingDevice::InitTask() // A two second timer to stop internal devices which do not want to uv_timer_t* timer = (uv_timer_t*)malloc(sizeof(uv_timer_t)); uv_timer_init(mState.loop, timer); - uv_timer_start(timer, idle_timer, 2000, 2000); + timer->data = &mState; + uv_timer_start(timer, on_idle_timer, 2000, 2000); mState.activeTimers.push_back(timer); } @@ -402,16 +501,30 @@ void DataProcessingDevice::InitTask() // required parts in the DataProcessorContext. Eventually we should // do so on a per thread basis, with fine grained locks. mDataProcessorContexes.resize(1); - this->fillContext(mDataProcessorContexes.at(0)); + this->fillContext(mDataProcessorContexes.at(0), mDeviceContext); + + /// We now run an event loop also in InitTask. This is needed to: + /// * Make sure region registration callbacks are invoked + /// on the main thread. + /// * Wait for enough callbacks to be delivered before moving to START + while (mDeviceContext.expectedRegionCallbacks > 0 && uv_run(mState.loop, UV_RUN_ONCE)) { + // Handle callbacks if any + { + std::lock_guard<std::mutex> lock(mRegionInfoMutex); + handleRegionCallbacks(mServiceRegistry, mPendingRegionInfos); + } + } } -void DataProcessingDevice::fillContext(DataProcessorContext& context) +void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceContext& deviceContext) { context.wasActive = &mWasActive; - context.device = this; - context.spec = &mSpec; - context.state = &mState; + deviceContext.device = this; + deviceContext.spec = &mSpec; + deviceContext.state = &mState; + deviceContext.quotaEvaluator = &mQuotaEvaluator; + deviceContext.stats = &mStats; context.relayer = mRelayer; context.registry = &mServiceRegistry; @@ -422,55 +535,135 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context) context.statefulProcess = &mStatefulProcess; context.statelessProcess = &mStatelessProcess; context.error = &mError; + context.deviceContext = &deviceContext; /// Callback for the error handling context.errorHandling = &mErrorHandling; - context.errorCount = &mErrorCount; + /// We must make sure there is no optional + /// if we want to optimize the forwarding + for (auto& input : mSpec.inputs) { + if (strncmp(DataSpecUtils::asConcreteOrigin(input.matcher).str, "AOD", 3) == 0) { + context.canForwardEarly = false; + break; + } + if (input.matcher.lifetime == Lifetime::Optional) { + context.canForwardEarly = false; + break; + } + } } void DataProcessingDevice::PreRun() { + mServiceRegistry.preStartCallbacks(); mServiceRegistry.get<CallbackService>()(CallbackService::Id::Start); } -void DataProcessingDevice::PostRun() { mServiceRegistry.get<CallbackService>()(CallbackService::Id::Stop); } +void DataProcessingDevice::PostRun() +{ + mServiceRegistry.get<CallbackService>()(CallbackService::Id::Stop); + mServiceRegistry.preExitCallbacks(); +} void DataProcessingDevice::Reset() { mServiceRegistry.get<CallbackService>()(CallbackService::Id::Reset); } -bool DataProcessingDevice::ConditionalRun() +void DataProcessingDevice::Run() { - // This will block for the correct delay (or until we get data - // on a socket). We also do not block on the first iteration - // so that devices which do not have a timer can still start an - // enumeration. - if (mState.loop) { - ZoneScopedN("uv idle"); - TracyPlot("past activity", (int64_t)mWasActive); - auto shouldNotWait = (mWasActive && - (mDataProcessorContexes.at(0).state->streaming != StreamingState::Idle) && (mState.activeSignals.empty())) || - (mDataProcessorContexes.at(0).state->streaming == StreamingState::EndOfStreaming); - uv_run(mState.loop, shouldNotWait ? UV_RUN_NOWAIT : UV_RUN_ONCE); - } + while (!NewStatePending()) { + // Notify on the main thread the new region callbacks, making sure + // no callback is issued if there is something still processing. + { + std::lock_guard<std::mutex> lock(mRegionInfoMutex); + handleRegionCallbacks(mServiceRegistry, mPendingRegionInfos); + } + // This will block for the correct delay (or until we get data + // on a socket). We also do not block on the first iteration + // so that devices which do not have a timer can still start an + // enumeration. + { + ZoneScopedN("uv idle"); + TracyPlot("past activity", (int64_t)mWasActive); + mServiceRegistry.get<DriverClient>().flushPending(); + auto shouldNotWait = (mWasActive && + (mState.streaming != StreamingState::Idle) && (mState.activeSignals.empty())) || + (mState.streaming == StreamingState::EndOfStreaming); + if (NewStatePending()) { + shouldNotWait = true; + } + TracyPlot("shouldNotWait", (int)shouldNotWait); + uv_run(mState.loop, shouldNotWait ? UV_RUN_NOWAIT : UV_RUN_ONCE); + TracyPlot("loopReason", (int64_t)(uint64_t)mState.loopReason); - // Notify on the main thread the new region callbacks, making sure - // no callback is issued if there is something still processing. - { - std::lock_guard<std::mutex> lock(mRegionInfoMutex); - if (mPendingRegionInfos.empty() == false) { - std::vector<FairMQRegionInfo> toBeNotified; - toBeNotified.swap(mPendingRegionInfos); // avoid any MT issue. - for (auto const& info : toBeNotified) { - mServiceRegistry.get<CallbackService>()(CallbackService::Id::RegionInfoCallback, info); + mState.loopReason = DeviceState::NO_REASON; + if (!mState.pendingOffers.empty()) { + mQuotaEvaluator.updateOffers(mState.pendingOffers, uv_now(mState.loop)); } } + + // Notify on the main thread the new region callbacks, making sure + // no callback is issued if there is something still processing. + // Notice that we still need to perform callbacks also after + // the socket epolled, because otherwise we would end up serving + // the callback after the first data arrives is the system is too + // fast to transition from Init to Run. + { + std::lock_guard<std::mutex> lock(mRegionInfoMutex); + handleRegionCallbacks(mServiceRegistry, mPendingRegionInfos); + } + + assert(mStreams.size() == mHandles.size()); + /// Decide which task to use + TaskStreamRef streamRef{-1}; + for (int ti = 0; ti < mStreams.size(); ti++) { + auto& taskInfo = mStreams[ti]; + if (taskInfo.running) { + continue; + } + streamRef.index = ti; + } + using o2::monitoring::Metric; + using o2::monitoring::Monitoring; + using o2::monitoring::tags::Key; + using o2::monitoring::tags::Value; + // We have an empty stream, let's check if we have enough + // resources for it to run something + if (streamRef.index != -1) { + // Synchronous execution of the callbacks. This will be moved in the + // moved in the on_socket_polled once we have threading in place. + auto& handle = mHandles[streamRef.index]; + auto& stream = mStreams[streamRef.index]; + handle.data = &mStreams[streamRef.index]; + + static std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats const& stats)> reportExpiredOffer = [&monitoring = mServiceRegistry.get<o2::monitoring::Monitoring>()](ComputingQuotaOffer const& offer, ComputingQuotaStats const& stats) { + monitoring.send(Metric{(uint64_t)stats.totalExpiredOffers, "resource-offer-expired"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.send(Metric{(uint64_t)stats.totalExpiredBytes, "arrow-bytes-expired"}.addTag(Key::Subsystem, Value::DPL)); + monitoring.flushBuffer(); + }; + + // Deciding wether to run or not can be done by passing a request to + // the evaluator. In this case, the request is always satisfied and + // we run on whatever resource is available. + bool enough = mQuotaEvaluator.selectOffer(streamRef.index, mSpec.resourcePolicy.request, uv_now(mState.loop)); + + if (enough) { + stream.id = streamRef; + stream.running = true; + stream.context = &mDataProcessorContexes.at(0); +#ifdef DPL_ENABLE_THREADING + stream.task.data = &handle; + uv_queue_work(mState.loop, &stream.task, run_callback, run_completion); +#else + run_callback(&handle); + run_completion(&handle, 0); +#endif + } else { + mDataProcessorContexes.at(0).deviceContext->quotaEvaluator->handleExpired(reportExpiredOffer); + mWasActive = false; + } + } else { + mWasActive = false; + } + FrameMark; } - // Synchronous execution of the callbacks. This will be moved in the - // moved in the on_socket_polled once we have threading in place. - uv_work_t handle; - handle.data = &mDataProcessorContexes; - run_callback(&handle); - run_completion(&handle, 0); - FrameMark; - return true; } /// We drive the state loop ourself so that we will be able to support @@ -491,71 +684,94 @@ void DataProcessingDevice::doPrepare(DataProcessorContext& context) // expect to receive an EndOfStream signal. Thus we do not wait for these // to be completed. In the case of data source devices, as they do not have // real data input channels, they have to signal EndOfStream themselves. - context.allDone = std::any_of(context.state->inputChannelInfos.begin(), context.state->inputChannelInfos.end(), [](const auto& info) { - return info.state != InputChannelState::Pull; + context.allDone = std::any_of(context.deviceContext->state->inputChannelInfos.begin(), context.deviceContext->state->inputChannelInfos.end(), [](const auto& info) { + return info.parts.fParts.empty() == true && info.state != InputChannelState::Pull; }); + // Whether or not all the channels are completed - for (size_t ci = 0; ci < context.spec->inputChannels.size(); ++ci) { - auto& channel = context.spec->inputChannels[ci]; - auto& info = context.state->inputChannelInfos[ci]; + for (size_t ci = 0; ci < context.deviceContext->spec->inputChannels.size(); ++ci) { + auto& channel = context.deviceContext->spec->inputChannels[ci]; + auto& info = context.deviceContext->state->inputChannelInfos[ci]; if (info.state != InputChannelState::Completed && info.state != InputChannelState::Pull) { context.allDone = false; } if (info.state != InputChannelState::Running) { + // Remember to flush data if we are not running + // and there is some message pending. + if (info.parts.Size()) { + DataProcessingDevice::handleData(context, info); + } continue; } int64_t result = -2; - auto& fairMQChannel = context.device->GetChannel(channel.name, 0); - auto& socket = fairMQChannel.GetSocket(); - uint32_t events; - socket.Events(&events); - if ((events & 1) == 0) { - continue; + if (info.channel == nullptr) { + info.channel = &context.deviceContext->device->GetChannel(channel.name, 0); + } + auto& socket = info.channel->GetSocket(); + // If we have pending events from a previous iteration, + // we do receive in any case. + // Otherwise we check if there is any pending event and skip + // this channel in case there is none. + if (info.hasPendingEvents == 0) { + socket.Events(&info.hasPendingEvents); + // If we do not read, we can continue. + if ((info.hasPendingEvents & 1) == 0 && (info.parts.Size() == 0)) { + continue; + } } // Notice that there seems to be a difference between the documentation // of zeromq and the observed behavior. The fact that ZMQ_POLLIN // is raised does not mean that a message is immediately available to // read, just that it will be available soon, so the receive can // still return -2. To avoid this we keep receiving on the socket until - // we get a message, consume all the consecutive messages, and then go back - // to the usual loop. - do { - if (events & 1) { - bool oneMessage = false; - while (true) { - FairMQParts parts; - result = fairMQChannel.Receive(parts, 0); - if (result >= 0) { - // Receiving data counts as activity now, so that - // We can make sure we process all the pending - // messages without hanging on the uv_run. - *context.wasActive = true; - DataProcessingDevice::handleData(context, parts, info); - oneMessage = true; - } else { - if (oneMessage) { - break; - } - } + // we get a message. In order not to overflow the DPL queue we process + // one message at the time and we keep track of wether there were more + // to process. + bool newMessages = false; + while (true) { + if (info.parts.Size() < 64) { + FairMQParts parts; + info.channel->Receive(parts, 0); + for (auto&& part : parts) { + info.parts.fParts.emplace_back(std::move(part)); } - } else { + newMessages |= true; + } + + if (info.parts.Size() >= 0) { + DataProcessingDevice::handleData(context, info); + // Receiving data counts as activity now, so that + // We can make sure we process all the pending + // messages without hanging on the uv_run. break; } - socket.Events(&events); - } while (events & 1); + } + // We check once again for pending events, keeping track if this was the + // case so that we can immediately repeat this loop and avoid remaining + // stuck in uv_run. This is because we will not get notified on the socket + // if more events are pending due to zeromq level triggered approach. + socket.Events(&info.hasPendingEvents); + if (info.hasPendingEvents) { + *context.wasActive |= newMessages; + } } } void DataProcessingDevice::doRun(DataProcessorContext& context) { - auto switchState = [& registry = context.registry, - &state = context.state](StreamingState newState) { + auto switchState = [®istry = context.registry, + &state = context.deviceContext->state](StreamingState newState) { LOG(debug) << "New state " << (int)newState << " old state " << (int)state->streaming; state->streaming = newState; registry->get<ControlService>().notifyStreamingState(state->streaming); }; + if (context.deviceContext->state->streaming == StreamingState::Idle) { + *context.wasActive = false; + return; + } + context.completed->clear(); context.completed->reserve(16); *context.wasActive |= DataProcessingDevice::tryDispatchComputation(context, *context.completed); @@ -565,7 +781,7 @@ void DataProcessingDevice::doRun(DataProcessorContext& context) if (*context.wasActive == false) { context.registry->get<CallbackService>()(CallbackService::Id::Idle); } - auto activity = context.relayer->processDanglingInputs(*context.expirationHandlers, *context.registry); + auto activity = context.relayer->processDanglingInputs(*context.expirationHandlers, *context.registry, true); *context.wasActive |= activity.expiredSlots > 0; context.completed->clear(); @@ -577,17 +793,21 @@ void DataProcessingDevice::doRun(DataProcessorContext& context) // callback and return false. Notice that what happens next is actually // dependent on the callback, not something which is controlled by the // framework itself. - if (context.allDone == true && context.state->streaming == StreamingState::Streaming) { + if (context.allDone == true && context.deviceContext->state->streaming == StreamingState::Streaming) { switchState(StreamingState::EndOfStreaming); *context.wasActive = true; } - if (context.state->streaming == StreamingState::EndOfStreaming) { + if (context.deviceContext->state->streaming == StreamingState::EndOfStreaming) { + context.registry->get<DriverClient>().flushPending(); // We keep processing data until we are Idle. // FIXME: not sure this is the correct way to drain the queues, but // I guess we will see. - while (DataProcessingDevice::tryDispatchComputation(context, *context.completed)) { - context.relayer->processDanglingInputs(*context.expirationHandlers, *context.registry); + /// Besides flushing the queues we must make sure we do not have only + /// timers as they do not need to be further processed. + bool hasOnlyGenerated = (context.deviceContext->spec->inputChannels.size() == 1) && (context.deviceContext->spec->inputs[0].matcher.lifetime == Lifetime::Timer || context.deviceContext->spec->inputs[0].matcher.lifetime == Lifetime::Enumeration); + while (DataProcessingDevice::tryDispatchComputation(context, *context.completed) && hasOnlyGenerated == false) { + context.relayer->processDanglingInputs(*context.expirationHandlers, *context.registry, false); } EndOfStreamContext eosContext{*context.registry, *context.allocator}; @@ -595,16 +815,33 @@ void DataProcessingDevice::doRun(DataProcessorContext& context) context.registry->get<CallbackService>()(CallbackService::Id::EndOfStream, eosContext); context.registry->postEOSCallbacks(eosContext); - for (auto& channel : context.spec->outputChannels) { - DataProcessingHelpers::sendEndOfStream(*context.device, channel); + for (auto& channel : context.deviceContext->spec->outputChannels) { + DataProcessingHelpers::sendEndOfStream(*context.deviceContext->device, channel); } // This is needed because the transport is deleted before the device. context.relayer->clear(); switchState(StreamingState::Idle); - *context.wasActive = true; + if (hasOnlyGenerated) { + *context.wasActive = false; + } else { + *context.wasActive = true; + } + // On end of stream we shut down all output pollers. + for (auto& poller : context.deviceContext->state->activeOutputPollers) { + uv_poll_stop(poller); + } + context.deviceContext->state->activeOutputPollers.clear(); return; } + if (context.deviceContext->state->streaming == StreamingState::Idle) { + // On end of stream we shut down all output pollers. + for (auto& poller : context.deviceContext->state->activeOutputPollers) { + uv_poll_stop(poller); + } + context.deviceContext->state->activeOutputPollers.clear(); + } + return; } @@ -613,19 +850,27 @@ void DataProcessingDevice::ResetTask() mRelayer->clear(); } +struct WaitBackpressurePolicy { + void backpressure(InputChannelInfo const& info) + { + // FIXME: fill metrics rather than log. + LOGP(WARN, "Backpressure on channel {}. Waiting.", info.channel->GetName()); + } +}; + /// This is the inner loop of our framework. The actual implementation /// is divided in two parts. In the first one we define a set of lambdas /// which describe what is actually going to happen, hiding all the state /// boilerplate which the user does not need to care about at top level. -void DataProcessingDevice::handleData(DataProcessorContext& context, FairMQParts& parts, InputChannelInfo& info) +void DataProcessingDevice::handleData(DataProcessorContext& context, InputChannelInfo& info) { ZoneScopedN("DataProcessingDevice::handleData"); - assert(context.spec->inputChannels.empty() == false); - assert(parts.Size() > 0); + assert(context.deviceContext->spec->inputChannels.empty() == false); + assert(info.parts.Size() > 0); // Initial part. Let's hide all the unnecessary and have // simple lambdas for each of the steps I am planning to have. - assert(!context.spec->inputs.empty()); + assert(!context.deviceContext->spec->inputs.empty()); enum struct InputType { Invalid, @@ -638,7 +883,8 @@ void DataProcessingDevice::handleData(DataProcessorContext& context, FairMQParts // than an input, because we do not want the outer loop actually be exposed // to the implementation details of the messaging layer. auto getInputTypes = [&stats = context.registry->get<DataProcessingStats>(), - &parts, &info, &context]() -> std::optional<std::vector<InputType>> { + &info, &context]() -> std::optional<std::vector<InputType>> { + auto& parts = info.parts; stats.inputParts = parts.Size(); TracyPlot("messages received", (int64_t)parts.Size()); @@ -675,17 +921,31 @@ void DataProcessingDevice::handleData(DataProcessorContext& context, FairMQParts LOGP(error, "Header stack does not contain DataProcessingHeader"); continue; } - results[hi] = InputType::Data; + // We can set the type for the next splitPayloadParts + // because we are guaranteed they are all the same. + // If splitPayloadParts = 0, we assume that means there is only one (header, payload) + // pair. + size_t finalSplitPayloadIndex = hi + (dh->splitPayloadParts > 0 ? dh->splitPayloadParts : 1); + if (finalSplitPayloadIndex > results.size()) { + LOGP(error, "DataHeader::splitPayloadParts invalid"); + results[hi] = InputType::Invalid; + continue; + } + for (; hi < finalSplitPayloadIndex; ++hi) { + results[hi] = InputType::Data; + } + hi = finalSplitPayloadIndex - 1; } return results; }; - auto reportError = [& registry = *context.registry, &context](const char* message) { - context.errorCount++; - registry.get<Monitoring>().send(Metric{*context.errorCount, "errors"}.addTag(Key::Subsystem, Value::DPL)); + auto reportError = [®istry = *context.registry, &context](const char* message) { + registry.get<DataProcessingStats>().errorCount++; }; - auto handleValidMessages = [&parts, &context = context, &relayer = *context.relayer, &reportError](std::vector<InputType> const& types) { + auto handleValidMessages = [&info, &context = context, &relayer = *context.relayer, &reportError](std::vector<InputType> const& types) { + static WaitBackpressurePolicy policy; + auto& parts = info.parts; // We relay execution to make sure we have a complete set of parts // available. for (size_t pi = 0; pi < (parts.Size() / 2); ++pi) { @@ -694,14 +954,34 @@ void DataProcessingDevice::handleData(DataProcessorContext& context, FairMQParts auto headerIndex = 2 * pi; auto payloadIndex = 2 * pi + 1; assert(payloadIndex < parts.Size()); - auto relayed = relayer.relay(std::move(parts.At(headerIndex)), - std::move(parts.At(payloadIndex))); - if (relayed == DataRelayer::WillNotRelay) { - reportError("Unable to relay part."); + auto dh = o2::header::get<DataHeader*>(parts.At(headerIndex)->GetData()); + auto relayed = relayer.relay(parts.At(headerIndex), + &parts.At(payloadIndex), dh->splitPayloadParts > 0 ? dh->splitPayloadParts * 2 - 1 : 0); + pi += dh->splitPayloadParts > 0 ? dh->splitPayloadParts - 1 : 0; + switch (relayed) { + case DataRelayer::Backpressured: + policy.backpressure(info); + break; + case DataRelayer::Dropped: + case DataRelayer::Invalid: + case DataRelayer::WillRelay: + break; } } break; case InputType::SourceInfo: { *context.wasActive = true; + auto headerIndex = 2 * pi; + auto payloadIndex = 2 * pi + 1; + assert(payloadIndex < parts.Size()); + auto dh = o2::header::get<DataHeader*>(parts.At(headerIndex)->GetData()); + // FIXME: the message with the end of stream cannot contain + // split parts. + parts.At(headerIndex).reset(nullptr); + parts.At(payloadIndex).reset(nullptr); + //for (size_t i = 0; i < dh->splitPayloadParts > 0 ? dh->splitPayloadParts * 2 - 1 : 1; ++i) { + // parts.At(headerIndex + 1 + i).reset(nullptr); + //} + //pi += dh->splitPayloadParts > 0 ? dh->splitPayloadParts - 1 : 0; } break; case InputType::Invalid: { @@ -709,6 +989,12 @@ void DataProcessingDevice::handleData(DataProcessorContext& context, FairMQParts } break; } } + auto it = std::remove_if(parts.fParts.begin(), parts.fParts.end(), [](auto& msg) -> bool { return msg.get() == nullptr; }); + auto r = std::distance(it, parts.fParts.end()); + parts.fParts.erase(it, parts.end()); + if (parts.fParts.size()) { + LOG(DEBUG) << parts.fParts.size() << " messages backpressured"; + } }; // Second part. This is the actual outer loop we want to obtain, with @@ -778,9 +1064,8 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, // should work just fine. std::vector<MessageSet> currentSetOfInputs; - auto reportError = [& registry = *context.registry, &context](const char* message) { - context.errorCount++; - registry.get<Monitoring>().send(Metric{*context.errorCount, "errors"}.addTag(Key::Subsystem, Value::DPL)); + auto reportError = [®istry = *context.registry, &context](const char* message) { + registry.get<DataProcessingStats>().errorCount++; }; // For the moment we have a simple "immediately dispatch" policy for stuff @@ -797,7 +1082,7 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, // indicate a complete set of inputs. Notice how I fill the completed // vector and return it, so that I can have a nice for loop iteration later // on. - auto getReadyActions = [& relayer = context.relayer, + auto getReadyActions = [&relayer = context.relayer, &completed, &stats = context.registry->get<DataProcessingStats>()]() -> std::vector<DataRelayer::RecordAction> { stats.pendingInputs = (int)relayer->getParallelTimeslices() - completed.size(); @@ -805,12 +1090,9 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, return completed; }; - // This is needed to convert from a pair of pointers to an actual DataRef - // and to make sure the ownership is moved from the cache in the relayer to - // the execution. - auto fillInputs = [& relayer = context.relayer, - &spec = context.spec, - ¤tSetOfInputs](TimesliceSlot slot) -> InputRecord { + // + auto getInputSpan = [&relayer = context.relayer, + ¤tSetOfInputs](TimesliceSlot slot) { currentSetOfInputs = std::move(relayer->getInputsForTimeslice(slot)); auto getter = [¤tSetOfInputs](size_t i, size_t partindex) -> DataRef { if (currentSetOfInputs[i].size() > partindex) { @@ -823,19 +1105,25 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, auto nofPartsGetter = [¤tSetOfInputs](size_t i) -> size_t { return currentSetOfInputs[i].size(); }; - InputSpan span{getter, nofPartsGetter, currentSetOfInputs.size()}; - return InputRecord{spec->inputs, std::move(span)}; + return InputSpan{getter, nofPartsGetter, currentSetOfInputs.size()}; + }; + + auto markInputsAsDone = [&relayer = context.relayer](TimesliceSlot slot) -> void { + relayer->updateCacheStatus(slot, CacheEntryStatus::RUNNING, CacheEntryStatus::DONE); }; // I need a preparation step which gets the current timeslice id and // propagates it to the various contextes (i.e. the actual entities which // create messages) because the messages need to have the timeslice id into // it. - auto prepareAllocatorForCurrentTimeSlice = [& timingInfo = context.timingInfo, + auto prepareAllocatorForCurrentTimeSlice = [&timingInfo = context.timingInfo, &relayer = context.relayer](TimesliceSlot i) { ZoneScopedN("DataProcessingDevice::prepareForCurrentTimeslice"); auto timeslice = relayer->getTimesliceForSlot(i); timingInfo->timeslice = timeslice.value; + timingInfo->tfCounter = relayer->getFirstTFCounterForSlot(i); + timingInfo->firstTFOrbit = relayer->getFirstTFOrbitForSlot(i); + timingInfo->runNumber = relayer->getRunNumberForSlot(i); }; // When processing them, timers will have to be cleaned up @@ -884,8 +1172,8 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, // to the next one in the daisy chain. // FIXME: do it in a smarter way than O(N^2) auto forwardInputs = [&reportError, - &spec = context.spec, - &device = context.device, ¤tSetOfInputs](TimesliceSlot slot, InputRecord& record) { + &spec = context.deviceContext->spec, + &device = context.deviceContext->device, ¤tSetOfInputs](TimesliceSlot slot, InputRecord& record, bool copy) { ZoneScopedN("forward inputs"); assert(record.size() == currentSetOfInputs.size()); // we collect all messages per forward in a map and send them together @@ -927,7 +1215,7 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, if (header.get() == nullptr) { // FIXME: this should not happen, however it's actually harmless and // we can simply discard it for the moment. - // LOG(ERROR) << "Missing header! " << dh->dataDescription.as<std::string>(); + // LOG(ERROR) << "Missing header! " << dh->dataDescription; continue; } auto fdph = o2::header::get<DataProcessingHeader*>(header.get()->GetData()); @@ -940,9 +1228,20 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, LOG(ERROR) << "Forwarded data does not have a DataHeader"; continue; } - - forwardedParts[forward.channel].AddPart(std::move(header)); - forwardedParts[forward.channel].AddPart(std::move(payload)); + + if (copy) { + auto&& newHeader = header->GetTransport()->CreateMessage(); + auto&& newPayload = header->GetTransport()->CreateMessage(); + newHeader->Copy(*header); + newPayload->Copy(*payload); + + forwardedParts[forward.channel].AddPart(std::move(newHeader)); + forwardedParts[forward.channel].AddPart(std::move(newPayload)); + break; + } else { + forwardedParts[forward.channel].AddPart(std::move(header)); + forwardedParts[forward.channel].AddPart(std::move(payload)); + } } } } @@ -957,8 +1256,8 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, } }; - auto switchState = [& control = context.registry->get<ControlService>(), - &state = context.state](StreamingState newState) { + auto switchState = [&control = context.registry->get<ControlService>(), + &state = context.deviceContext->state](StreamingState newState) { state->streaming = newState; control.notifyStreamingState(state->streaming); }; @@ -967,7 +1266,7 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, return false; } - auto postUpdateStats = [& stats = context.registry->get<DataProcessingStats>()](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart) { + auto postUpdateStats = [&stats = context.registry->get<DataProcessingStats>()](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart) { std::atomic_thread_fence(std::memory_order_release); for (size_t ai = 0; ai != record.size(); ai++) { auto cacheId = action.slot.index * record.size() + ai; @@ -978,11 +1277,12 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, } uint64_t tEnd = uv_hrtime(); stats.lastElapsedTimeMs = tEnd - tStart; - stats.lastTotalProcessedSize = calculateTotalInputRecordSize(record); + stats.lastProcessedSize = calculateTotalInputRecordSize(record); + stats.totalProcessedSize += stats.lastProcessedSize; stats.lastLatency = calculateInputRecordLatency(record, tStart); }; - auto preUpdateStats = [& stats = context.registry->get<DataProcessingStats>()](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart) { + auto preUpdateStats = [&stats = context.registry->get<DataProcessingStats>()](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart) { std::atomic_thread_fence(std::memory_order_release); for (size_t ai = 0; ai != record.size(); ai++) { auto cacheId = action.slot.index * record.size() + ai; @@ -993,13 +1293,15 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, } }; + // This is the main dispatching loop for (auto action : getReadyActions()) { if (action.op == CompletionPolicy::CompletionOp::Wait) { continue; } prepareAllocatorForCurrentTimeSlice(TimesliceSlot{action.slot}); - InputRecord record = fillInputs(action.slot); + InputSpan span = getInputSpan(action.slot); + InputRecord record{context.deviceContext->spec->inputs, span}; ProcessingContext processContext{record, *context.registry, *context.allocator}; { ZoneScopedN("service pre processing"); @@ -1007,17 +1309,27 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, } if (action.op == CompletionPolicy::CompletionOp::Discard) { context.registry->postDispatchingCallbacks(processContext); - if (context.spec->forwards.empty() == false) { - forwardInputs(action.slot, record); + if (context.deviceContext->spec->forwards.empty() == false) { + forwardInputs(action.slot, record, false); continue; } } + // If there is no optional inputs we canForwardEarly + // the messages to that parallel processing can happen. + // In this case we pass true to indicate that we want to + // copy the messages to the subsequent data processor. + if (context.canForwardEarly && context.deviceContext->spec->forwards.empty() == false && action.op == CompletionPolicy::CompletionOp::Consume) { + forwardInputs(action.slot, record, true); + } + markInputsAsDone(action.slot); uint64_t tStart = uv_hrtime(); preUpdateStats(action, record, tStart); - try { - if (context.state->quitRequested == false) { + static bool noCatch = getenv("O2_NO_CATCHALL_EXCEPTIONS") && strcmp(getenv("O2_NO_CATCHALL_EXCEPTIONS"), "0"); + + auto runNoCatch = [&context, &processContext]() { + if (context.deviceContext->state->quitRequested == false) { if (*context.statefulProcess) { ZoneScopedN("statefull process"); (*context.statefulProcess)(processContext); @@ -1032,16 +1344,24 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, context.registry->postProcessingCallbacks(processContext); } } - } catch (std::exception& ex) { - ZoneScopedN("error handling"); - /// Convert a standatd exception to a RuntimeErrorRef - /// Notice how this will lose the backtrace information - /// and report the exception coming from here. - auto e = runtime_error(ex.what()); - (*context.errorHandling)(e, record); - } catch (o2::framework::RuntimeErrorRef e) { - ZoneScopedN("error handling"); - (*context.errorHandling)(e, record); + }; + + if (noCatch) { + runNoCatch(); + } else { + try { + runNoCatch(); + } catch (std::exception& ex) { + ZoneScopedN("error handling"); + /// Convert a standard exception to a RuntimeErrorRef + /// Notice how this will lose the backtrace information + /// and report the exception coming from here. + auto e = runtime_error(ex.what()); + (*context.errorHandling)(e, record); + } catch (o2::framework::RuntimeErrorRef e) { + ZoneScopedN("error handling"); + (*context.errorHandling)(e, record); + } } postUpdateStats(action, record, tStart); @@ -1049,20 +1369,20 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, // we keep them for next message arriving. if (action.op == CompletionPolicy::CompletionOp::Consume) { context.registry->postDispatchingCallbacks(processContext); - if (context.spec->forwards.empty() == false) { - forwardInputs(action.slot, record); + if ((context.canForwardEarly == false) && context.deviceContext->spec->forwards.empty() == false) { + forwardInputs(action.slot, record, false); } #ifdef TRACY_ENABLE - cleanupRecord(record); + cleanupRecord(record); #endif } else if (action.op == CompletionPolicy::CompletionOp::Process) { cleanTimers(action.slot, record); } } // We now broadcast the end of stream if it was requested - if (context.state->streaming == StreamingState::EndOfStreaming) { - for (auto& channel : context.spec->outputChannels) { - DataProcessingHelpers::sendEndOfStream(*context.device, channel); + if (context.deviceContext->state->streaming == StreamingState::EndOfStreaming) { + for (auto& channel : context.deviceContext->spec->outputChannels) { + DataProcessingHelpers::sendEndOfStream(*context.deviceContext->device, channel); } switchState(StreamingState::Idle); } @@ -1073,8 +1393,27 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, void DataProcessingDevice::error(const char* msg) { LOG(ERROR) << msg; - mErrorCount++; - mServiceRegistry.get<Monitoring>().send(Metric{mErrorCount, "errors"}.addTag(Key::Subsystem, Value::DPL)); + mServiceRegistry.get<DataProcessingStats>().errorCount++; +} + +std::unique_ptr<ConfigParamStore> DeviceConfigurationHelpers::getConfiguration(ServiceRegistry& registry, const char* name, std::vector<ConfigParamSpec> const& options) +{ + + if (registry.active<ConfigurationInterface>()) { + auto& cfg = registry.get<ConfigurationInterface>(); + try { + cfg.getRecursive(name); + std::vector<std::unique_ptr<ParamRetriever>> retrievers; + retrievers.emplace_back(std::make_unique<ConfigurationOptionsRetriever>(&cfg, name)); + auto configStore = std::make_unique<ConfigParamStore>(options, std::move(retrievers)); + configStore->preload(); + configStore->activate(); + return configStore; + } catch (...) { + // No overrides... + } + } + return std::unique_ptr<ConfigParamStore>(nullptr); } } // namespace o2::framework diff --git a/Framework/Core/src/DataProcessingHeader.cxx b/Framework/Core/src/DataProcessingHeader.cxx index e14231a7e671a..18be3019ea77c 100644 --- a/Framework/Core/src/DataProcessingHeader.cxx +++ b/Framework/Core/src/DataProcessingHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 4c65520774cea..07dfe3d53eb5a 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DataProcessingHelpers.h b/Framework/Core/src/DataProcessingHelpers.h index 3ea3001222f51..b4b6d9d5378d9 100644 --- a/Framework/Core/src/DataProcessingHelpers.h +++ b/Framework/Core/src/DataProcessingHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,7 +11,7 @@ #ifndef O2_FRAMEWORK_DATAPROCESSINGHELPERS_H_ #define O2_FRAMEWORK_DATAPROCESSINGHELPERS_H_ -class FairMQDevice; +#include <fairmq/FwdDecls.h> namespace o2::framework { diff --git a/Framework/Core/src/DataProcessingStatus.h b/Framework/Core/src/DataProcessingStatus.h index 5be6933b9871c..377a9f0630625 100644 --- a/Framework/Core/src/DataProcessingStatus.h +++ b/Framework/Core/src/DataProcessingStatus.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DataProcessor.cxx b/Framework/Core/src/DataProcessor.cxx index 35a4ce1d12cbd..d9cc5c778ba23 100644 --- a/Framework/Core/src/DataProcessor.cxx +++ b/Framework/Core/src/DataProcessor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "FairMQResizableBuffer.h" #include "CommonUtils/BoostSerializer.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include <Monitoring/Monitoring.h> #include <fairmq/FairMQParts.h> @@ -80,6 +82,7 @@ void DataProcessor::doSend(FairMQDevice& device, ArrowContext& context, ServiceR using o2::monitoring::Monitoring; using o2::monitoring::tags::Key; using o2::monitoring::tags::Value; + auto& monitoring = registry.get<Monitoring>(); for (auto& messageRef : context) { FairMQParts parts; @@ -95,13 +98,39 @@ void DataProcessor::doSend(FairMQDevice& device, ArrowContext& context, ServiceR DataHeader* dh = const_cast<DataHeader*>(cdh); dh->payloadSize = payload->GetSize(); dh->serialization = o2::header::gSerializationMethodArrow; + monitoring.send(Metric{(uint64_t)payload->GetSize(), fmt::format("table-bytes-{}-{}-created", dh->dataOrigin.as<std::string>(), dh->dataDescription.as<std::string>())}.addTag(Key::Subsystem, Value::DPL)); + LOGP(INFO, "Creating {}MB for table {}/{}.", payload->GetSize() / 1000000., dh->dataOrigin, dh->dataDescription); context.updateBytesSent(payload->GetSize()); context.updateMessagesSent(1); parts.AddPart(std::move(messageRef.header)); parts.AddPart(std::move(payload)); device.Send(parts, messageRef.channel, 0); } - auto& monitoring = registry.get<Monitoring>(); + static int64_t previousBytesSent = 0; + auto disposeResources = [bs = context.bytesSent() - previousBytesSent](int taskId, + std::array<ComputingQuotaOffer, 16>& offers, + ComputingQuotaStats& stats, + std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats&)> accountDisposed) { + ComputingQuotaOffer disposed; + disposed.sharedMemory = 0; + int64_t bytesSent = bs; + for (size_t oi = 0; oi < offers.size(); oi++) { + auto& offer = offers[oi]; + if (offer.user != taskId) { + continue; + } + int64_t toRemove = std::min((int64_t)bytesSent, offer.sharedMemory); + offer.sharedMemory -= toRemove; + bytesSent -= toRemove; + disposed.sharedMemory += toRemove; + if (bytesSent <= 0) { + break; + } + } + return accountDisposed(disposed, stats); + }; + registry.get<DeviceState>().offerConsumers.push_back(disposeResources); + previousBytesSent = context.bytesSent(); monitoring.send(Metric{(uint64_t)context.bytesSent(), "arrow-bytes-created"}.addTag(Key::Subsystem, Value::DPL)); monitoring.send(Metric{(uint64_t)context.messagesCreated(), "arrow-messages-created"}.addTag(Key::Subsystem, Value::DPL)); monitoring.flushBuffer(); diff --git a/Framework/Core/src/DataRefUtils.cxx b/Framework/Core/src/DataRefUtils.cxx new file mode 100644 index 0000000000000..e25311942ae14 --- /dev/null +++ b/Framework/Core/src/DataRefUtils.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <typeinfo> +#include "CCDB/CcdbApi.h" +#include "Framework/DataRefUtils.h" +#include <TMemFile.h> +#include <TError.h> +#include "Framework/RuntimeError.h" + +namespace o2::framework +{ +// Adapted from CcdbApi private method interpretAsTMemFileAndExtract +// If the former is moved to public, throws on error and could be changed to +// not require a mutex we could use it. +void* DataRefUtils::decodeCCDB(DataRef const& ref, std::type_info const& tinfo) +{ + void* result = nullptr; + Int_t previousErrorLevel = gErrorIgnoreLevel; + gErrorIgnoreLevel = kFatal; + auto* dh = o2::header::get<o2::header::DataHeader*>(ref.header); + TMemFile memFile("name", const_cast<char*>(ref.payload), dh->payloadSize, "READ"); + gErrorIgnoreLevel = previousErrorLevel; + if (memFile.IsZombie()) { + return nullptr; + } + TClass* tcl = TClass::GetClass(tinfo); + result = ccdb::CcdbApi::extractFromTFile(memFile, tcl); + if (!result) { + throw runtime_error_f("Couldn't retrieve object corresponding to %s from TFile", tcl->GetName()); + } + memFile.Close(); + return result; +} +} // namespace o2::framework diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index b332304ca432d..daf873424939a 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,22 +11,30 @@ #include "Framework/RootSerializationSupport.h" #include "Framework/DataRelayer.h" +#include "Framework/CompilerBuiltins.h" #include "Framework/DataDescriptorMatcher.h" #include "Framework/DataSpecUtils.h" #include "Framework/DataProcessingHeader.h" #include "Framework/DataRef.h" #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/CompletionPolicy.h" #include "Framework/Logger.h" #include "Framework/PartRef.h" #include "Framework/TimesliceIndex.h" #include "Framework/Signpost.h" #include "Framework/RoutingIndices.h" +#include "Framework/VariableContextHelpers.h" #include "DataProcessingStatus.h" #include "DataRelayerHelpers.h" +#include "InputRouteHelpers.h" +#include "Headers/DataHeaderHelpers.h" + +#include <Monitoring/Metric.h> #include <Monitoring/Monitoring.h> +#include <fmt/format.h> #include <gsl/span> #include <numeric> #include <string> @@ -33,6 +42,7 @@ using namespace o2::framework::data_matcher; using DataHeader = o2::header::DataHeader; using DataProcessingHeader = o2::framework::DataProcessingHeader; +using Verbosity = o2::monitoring::Verbosity; namespace o2::framework { @@ -41,7 +51,7 @@ constexpr int INVALID_INPUT = -1; // 16 is just some reasonable numer // The number should really be tuned at runtime for each processor. -constexpr int DEFAULT_PIPELINE_LENGTH = 16; +constexpr int DEFAULT_PIPELINE_LENGTH = 32; DataRelayer::DataRelayer(const CompletionPolicy& policy, std::vector<InputRoute> const& routes, @@ -51,7 +61,8 @@ DataRelayer::DataRelayer(const CompletionPolicy& policy, mMetrics{metrics}, mCompletionPolicy{policy}, mDistinctRoutesIndex{DataRelayerHelpers::createDistinctRouteIndex(routes)}, - mInputMatchers{DataRelayerHelpers::createInputMatchers(routes)} + mInputMatchers{DataRelayerHelpers::createInputMatchers(routes)}, + mMaxLanes{InputRouteHelpers::maxLanes(routes)} { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); @@ -60,26 +71,27 @@ DataRelayer::DataRelayer(const CompletionPolicy& policy, // The queries are all the same, so we only have width 1 auto numInputTypes = mDistinctRoutesIndex.size(); sQueriesMetricsNames.resize(numInputTypes * 1); - mMetrics.send({(int)numInputTypes, "data_queries/h"}); - mMetrics.send({(int)1, "data_queries/w"}); + mMetrics.send({(int)numInputTypes, "data_queries/h", Verbosity::Debug}); + mMetrics.send({(int)1, "data_queries/w", Verbosity::Debug}); for (size_t i = 0; i < numInputTypes; ++i) { sQueriesMetricsNames[i] = std::string("data_queries/") + std::to_string(i); char buffer[128]; assert(mDistinctRoutesIndex[i] < routes.size()); auto& matcher = routes[mDistinctRoutesIndex[i]].matcher; DataSpecUtils::describe(buffer, 127, matcher); - mMetrics.send({std::string{buffer}, sQueriesMetricsNames[i]}); + mMetrics.send({std::string{buffer}, sQueriesMetricsNames[i], Verbosity::Debug}); } } TimesliceId DataRelayer::getTimesliceForSlot(TimesliceSlot slot) { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); - return mTimesliceIndex.getTimesliceForSlot(slot); + auto& variables = mTimesliceIndex.getVariablesForSlot(slot); + return VariableContextHelpers::getTimeslice(variables); } DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector<ExpirationHandler> const& expirationHandlers, - ServiceRegistry& services) + ServiceRegistry& services, bool createNew) { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); @@ -90,8 +102,10 @@ DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector<Expira } // Create any slot for the time based fields std::vector<TimesliceSlot> slotsCreatedByHandlers; - for (auto& handler : expirationHandlers) { - slotsCreatedByHandlers.push_back(handler.creator(mTimesliceIndex)); + if (createNew) { + for (auto& handler : expirationHandlers) { + slotsCreatedByHandlers.push_back(handler.creator(mTimesliceIndex)); + } } if (slotsCreatedByHandlers.empty() == false) { activity.newSlots++; @@ -104,7 +118,8 @@ DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector<Expira continue; } assert(mDistinctRoutesIndex.empty() == false); - auto timestamp = mTimesliceIndex.getTimesliceForSlot(slot); + auto& variables = mTimesliceIndex.getVariablesForSlot(slot); + auto timestamp = VariableContextHelpers::getTimeslice(variables); // We iterate on all the hanlders checking if they need to be expired. for (size_t ei = 0; ei < expirationHandlers.size(); ++ei) { auto& expirator = expirationHandlers[ei]; @@ -124,7 +139,7 @@ DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector<Expira if (slotsCreatedByHandlers[ei] != slot) { continue; } - if (expirator.checker(timestamp.value) == false) { + if (expirator.checker(services, timestamp.value) == false) { continue; } @@ -134,7 +149,7 @@ DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector<Expira if (part.size() == 0) { part.parts.resize(1); } - expirator.handler(services, part[0], timestamp.value); + expirator.handler(services, part[0], variables); activity.expiredSlots++; mTimesliceIndex.markAsDirty(slot, true); @@ -174,21 +189,33 @@ void sendVariableContextMetrics(VariableContext& context, TimesliceSlot slot, for (size_t i = 0; i < MAX_MATCHING_VARIABLE; i++) { auto& var = context.get(i); + auto& name = names[16 * slot.index + i]; if (auto pval = std::get_if<uint64_t>(&var)) { - metrics.send(monitoring::Metric{std::to_string(*pval), names[16 * slot.index + i]}); + metrics.send(monitoring::Metric{std::to_string(*pval), name, Verbosity::Debug}); + } else if (auto pval = std::get_if<uint32_t>(&var)) { + metrics.send(monitoring::Metric{std::to_string(*pval), name, Verbosity::Debug}); } else if (auto pval2 = std::get_if<std::string>(&var)) { - metrics.send(monitoring::Metric{*pval2, names[16 * slot.index + i]}); + metrics.send(monitoring::Metric{*pval2, name, Verbosity::Debug}); } else { - metrics.send(monitoring::Metric{nullstring, names[16 * slot.index + i]}); + metrics.send(monitoring::Metric{nullstring, name, Verbosity::Debug}); } } } DataRelayer::RelayChoice - DataRelayer::relay(std::unique_ptr<FairMQMessage>&& header, - std::unique_ptr<FairMQMessage>&& payload) + DataRelayer::relay(std::unique_ptr<FairMQMessage>& header, + std::unique_ptr<FairMQMessage>& payload) +{ + return relay(header, &payload, 1); +} + +DataRelayer::RelayChoice + DataRelayer::relay(std::unique_ptr<FairMQMessage>& firstPart, + std::unique_ptr<FairMQMessage>* restOfParts, + size_t restOfPartsSize) { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); + DataProcessingHeader const* dph = o2::header::get<DataProcessingHeader*>(firstPart->GetData()); // STATE HOLDING VARIABLES // This is the class level state of the relaying. If we start supporting // multithreading this will have to be made thread safe before we can invoke @@ -202,17 +229,21 @@ DataRelayer::RelayChoice // IMPLEMENTATION DETAILS // + // This returns true if a given slot is available for the current number of lanes + auto isSlotInLane = [currentLane = dph->startTime, maxLanes = mMaxLanes](TimesliceSlot slot) { + return (slot.index % maxLanes) == (currentLane % maxLanes); + }; // This returns the identifier for the given input. We use a separate // function because while it's trivial now, the actual matchmaking will // become more complicated when we will start supporting ranges. - auto getInputTimeslice = [& matchers = mInputMatchers, + auto getInputTimeslice = [&matchers = mInputMatchers, &distinctRoutes = mDistinctRoutesIndex, - &header, + &firstPart, &index](VariableContext& context) -> std::tuple<int, TimesliceId> { /// FIXME: for the moment we only use the first context and reset /// between one invokation and the other. - auto input = matchToContext(header->GetData(), matchers, distinctRoutes, context); + auto input = matchToContext(firstPart->GetData(), matchers, distinctRoutes, context); if (input == INVALID_INPUT) { return { @@ -249,25 +280,30 @@ DataRelayer::RelayChoice assert(numInputTypes * slot.index < cache.size()); for (size_t ai = slot.index * numInputTypes, ae = ai + numInputTypes; ai != ae; ++ai) { cache[ai].clear(); - cachedStateMetrics[ai] = 0; + cachedStateMetrics[ai] = CacheEntryStatus::EMPTY; } }; // Actually save the header / payload in the slot - auto saveInSlot = [&header, + auto saveInSlot = [&firstPart, &cachedStateMetrics = mCachedStateMetrics, - &payload, + &restOfParts, + &restOfPartsSize, &cache, &numInputTypes, &metrics](TimesliceId timeslice, int input, TimesliceSlot slot) { auto cacheIdx = numInputTypes * slot.index + input; std::vector<PartRef>& parts = cache[cacheIdx].parts; - cachedStateMetrics[cacheIdx] = 1; + cachedStateMetrics[cacheIdx] = CacheEntryStatus::PENDING; // TODO: make sure that multiple parts can only be added within the same call of // DataRelayer::relay - PartRef entry{std::move(header), std::move(payload)}; + PartRef entry{std::move(firstPart), std::move(restOfParts[0])}; parts.emplace_back(std::move(entry)); - assert(header.get() == nullptr && payload.get() == nullptr); + auto rest = restOfParts + 1; + for (size_t pi = 0; pi < (restOfPartsSize - 1) / 2; ++pi) { + PartRef entry{std::move(rest[pi * 2]), std::move(rest[pi * 2 + 1])}; + parts.emplace_back(std::move(entry)); + } }; auto updateStatistics = [& stats = mStats](TimesliceIndex::ActionTaken action) { @@ -287,6 +323,8 @@ DataRelayer::RelayChoice stats.droppedComputations++; stats.relayedMessages++; break; + case TimesliceIndex::ActionTaken::Wait: + break; } }; @@ -298,10 +336,14 @@ DataRelayer::RelayChoice auto timeslice = TimesliceId{TimesliceId::INVALID}; auto slot = TimesliceSlot{TimesliceSlot::INVALID}; + bool needsCleaning = false; // First look for matching slots which already have some // partial match. for (size_t ci = 0; ci < index.size(); ++ci) { slot = TimesliceSlot{ci}; + if (!isSlotInLane(slot)) { + continue; + } if (index.isValid(slot) == false) { continue; } @@ -319,8 +361,12 @@ DataRelayer::RelayChoice if (index.isValid(slot) == true) { continue; } + if (!isSlotInLane(slot)) { + continue; + } std::tie(input, timeslice) = getInputTimeslice(index.getVariablesForSlot(slot)); if (input != INVALID_INPUT) { + needsCleaning = true; break; } } @@ -329,6 +375,9 @@ DataRelayer::RelayChoice /// If we get a valid result, we can store the message in cache. if (input != INVALID_INPUT && TimesliceId::isValid(timeslice) && TimesliceSlot::isValid(slot)) { O2_SIGNPOST(O2_PROBE_DATARELAYER, timeslice.value, 0, 0, 0); + if (needsCleaning) { + pruneCache(slot); + } saveInSlot(timeslice, input, slot); index.publishSlot(slot); index.markAsDirty(slot, true); @@ -341,11 +390,11 @@ DataRelayer::RelayChoice VariableContext pristineContext; std::tie(input, timeslice) = getInputTimeslice(pristineContext); - auto DataHeaderInfo = [&header]() { + auto DataHeaderInfo = [&firstPart]() { std::string error; - const auto* dh = o2::header::get<o2::header::DataHeader*>(header->GetData()); + const auto* dh = o2::header::get<o2::header::DataHeader*>(firstPart->GetData()); if (dh) { - error += dh->dataOrigin.as<std::string>() + "/" + dh->dataDescription.as<std::string>() + "/" + dh->subSpecification; + error += fmt::format("{}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); } else { error += "invalid header"; } @@ -356,39 +405,65 @@ DataRelayer::RelayChoice LOG(ERROR) << "Could not match incoming data to any input route: " << DataHeaderInfo(); mStats.malformedInputs++; mStats.droppedIncomingMessages++; - return WillNotRelay; + firstPart.reset(nullptr); + for (size_t pi = 0; pi < restOfPartsSize; ++pi) { + auto& payload = restOfParts[pi]; + payload.reset(nullptr); + } + return Invalid; } if (TimesliceId::isValid(timeslice) == false) { LOG(ERROR) << "Could not determine the timeslice for input: " << DataHeaderInfo(); mStats.malformedInputs++; mStats.droppedIncomingMessages++; - return WillNotRelay; + firstPart.reset(nullptr); + for (size_t pi = 0; pi < restOfPartsSize; ++pi) { + auto& payload = restOfParts[pi]; + payload.reset(nullptr); + } + return Invalid; } TimesliceIndex::ActionTaken action; - std::tie(action, slot) = index.replaceLRUWith(pristineContext); + std::tie(action, slot) = index.replaceLRUWith(pristineContext, timeslice); updateStatistics(action); - if (action == TimesliceIndex::ActionTaken::DropObsolete) { - LOG(WARNING) << "Incoming data is already obsolete, not relaying."; - return WillNotRelay; - } - - if (action == TimesliceIndex::ActionTaken::DropInvalid) { - LOG(WARNING) << "Incoming data is invalid, not relaying."; - return WillNotRelay; + switch (action) { + case TimesliceIndex::ActionTaken::Wait: + return Backpressured; + case TimesliceIndex::ActionTaken::DropObsolete: + static std::atomic<size_t> obsoleteCount = 0; + static std::atomic<size_t> mult = 1; + if ((obsoleteCount++ % (1 * mult)) == 0) { + LOGP(WARNING, "Over {} incoming messages are already obsolete, not relaying.", obsoleteCount); + if (obsoleteCount > mult * 10) { + mult = mult * 10; + } + } + return Dropped; + case TimesliceIndex::ActionTaken::DropInvalid: + LOG(WARNING) << "Incoming data is invalid, not relaying."; + mStats.malformedInputs++; + mStats.droppedIncomingMessages++; + firstPart.reset(nullptr); + for (size_t pi = 0; pi < restOfPartsSize; ++pi) { + auto& payload = restOfParts[pi]; + payload.reset(nullptr); + } + return Invalid; + case TimesliceIndex::ActionTaken::ReplaceUnused: + case TimesliceIndex::ActionTaken::ReplaceObsolete: + // At this point the variables match the new input but the + // cache still holds the old data, so we prune it. + pruneCache(slot); + saveInSlot(timeslice, input, slot); + index.publishSlot(slot); + index.markAsDirty(slot, true); + return WillRelay; } - - // At this point the variables match the new input but the - // cache still holds the old data, so we prune it. - pruneCache(slot); - saveInSlot(timeslice, input, slot); - index.publishSlot(slot); - index.markAsDirty(slot, true); - - return WillRelay; + O2_BUILTIN_UNREACHABLE(); } void DataRelayer::getReadyToProcess(std::vector<DataRelayer::RecordAction>& completed) @@ -435,8 +510,8 @@ void DataRelayer::getReadyToProcess(std::vector<DataRelayer::RecordAction>& comp size_t cacheLines = cache.size() / numInputTypes; assert(cacheLines * numInputTypes == cache.size()); - for (size_t li = 0; li < cacheLines; ++li) { - TimesliceSlot slot{li}; + for (int li = cacheLines - 1; li >= 0; --li) { + TimesliceSlot slot{(size_t)li}; // We only check the cachelines which have been updated by an incoming // message. if (mTimesliceIndex.isDirty(slot) == false) { @@ -454,7 +529,8 @@ void DataRelayer::getReadyToProcess(std::vector<DataRelayer::RecordAction>& comp auto nPartsGetter = [&partial](size_t idx) { return partial[idx].size(); }; - auto action = mCompletionPolicy.callback({getter, nPartsGetter, static_cast<size_t>(partial.size())}); + InputSpan span{getter, nPartsGetter, static_cast<size_t>(partial.size())}; + auto action = mCompletionPolicy.callback(span); switch (action) { case CompletionPolicy::CompletionOp::Consume: case CompletionPolicy::CompletionOp::Process: @@ -470,6 +546,25 @@ void DataRelayer::getReadyToProcess(std::vector<DataRelayer::RecordAction>& comp } } +void DataRelayer::updateCacheStatus(TimesliceSlot slot, CacheEntryStatus oldStatus, CacheEntryStatus newStatus) +{ + std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); + const auto numInputTypes = mDistinctRoutesIndex.size(); + auto& index = mTimesliceIndex; + + auto markInputDone = [&cachedStateMetrics = mCachedStateMetrics, + &index, &numInputTypes](TimesliceSlot s, size_t arg, CacheEntryStatus oldStatus, CacheEntryStatus newStatus) { + auto cacheId = s.index * numInputTypes + arg; + if (cachedStateMetrics[cacheId] == oldStatus) { + cachedStateMetrics[cacheId] = newStatus; + } + }; + + for (size_t ai = 0, ae = numInputTypes; ai != ae; ++ai) { + markInputDone(slot, ai, oldStatus, newStatus); + } +} + std::vector<o2::framework::MessageSet> DataRelayer::getInputsForTimeslice(TimesliceSlot slot) { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); @@ -494,7 +589,7 @@ std::vector<o2::framework::MessageSet> DataRelayer::getInputsForTimeslice(Timesl &cachedStateMetrics = mCachedStateMetrics, &cache, &index, &numInputTypes, &metrics](TimesliceSlot s, size_t arg) { auto cacheId = s.index * numInputTypes + arg; - cachedStateMetrics[cacheId] = 2; + cachedStateMetrics[cacheId] = CacheEntryStatus::RUNNING; // TODO: in the original implementation of the cache, there have been only two messages per entry, // check if the 2 above corresponds to the number of messages. if (cache[cacheId].size() > 0) { @@ -507,7 +602,7 @@ std::vector<o2::framework::MessageSet> DataRelayer::getInputsForTimeslice(Timesl // timeslice, so I can simply do that. I keep the assertion there because in principle // we should have dispatched the timeslice already! // FIXME: what happens when we have enough timeslices to hit the invalid one? - auto invalidateCacheFor = [&numInputTypes, &index, &cache](TimesliceSlot s) { + auto invalidateCacheFor = [&numInputTypes, &cachedStateMetrics = mCachedStateMetrics, &index, &cache](TimesliceSlot s) { for (size_t ai = s.index * numInputTypes, ae = ai + numInputTypes; ai != ae; ++ai) { assert(std::accumulate(cache[ai].begin(), cache[ai].end(), true, [](bool result, auto const& element) { return result && element.header.get() == nullptr && element.payload.get() == nullptr; })); cache[ai].clear(); @@ -562,8 +657,8 @@ void DataRelayer::publishMetrics() auto numInputTypes = mDistinctRoutesIndex.size(); mCache.resize(numInputTypes * mTimesliceIndex.size()); - mMetrics.send({(int)numInputTypes, "data_relayer/h"}); - mMetrics.send({(int)mTimesliceIndex.size(), "data_relayer/w"}); + mMetrics.send({(int)numInputTypes, "data_relayer/h", Verbosity::Debug}); + mMetrics.send({(int)mTimesliceIndex.size(), "data_relayer/w", Verbosity::Debug}); sMetricsNames.resize(mCache.size()); mCachedStateMetrics.resize(mCache.size()); for (size_t i = 0; i < sMetricsNames.size(); ++i) { @@ -573,20 +668,20 @@ void DataRelayer::publishMetrics() // that we can take mod 16 of the index to understand which variable we // are talking about. sVariablesMetricsNames.resize(mVariableContextes.size() * 16); - mMetrics.send({(int)16, "matcher_variables/w"}); - mMetrics.send({(int)mVariableContextes.size(), "matcher_variables/h"}); + mMetrics.send({(int)16, "matcher_variables/w", Verbosity::Debug}); + mMetrics.send({(int)mVariableContextes.size(), "matcher_variables/h", Verbosity::Debug}); for (size_t i = 0; i < sVariablesMetricsNames.size(); ++i) { sVariablesMetricsNames[i] = std::string("matcher_variables/") + std::to_string(i); - mMetrics.send({std::string("null"), sVariablesMetricsNames[i % 16]}); + mMetrics.send({std::string("null"), sVariablesMetricsNames[i % 16], Verbosity::Debug}); } for (size_t ci = 0; ci < mCache.size(); ci++) { assert(ci < sMetricsNames.size()); - mMetrics.send({0, sMetricsNames[ci]}); + mMetrics.send({0, sMetricsNames[ci], Verbosity::Debug}); } for (size_t ci = 0; ci < mVariableContextes.size() * 16; ci++) { assert(ci < sVariablesMetricsNames.size()); - mMetrics.send({std::string("null"), sVariablesMetricsNames[ci]}); + mMetrics.send({std::string("null"), sVariablesMetricsNames[ci], Verbosity::Debug}); } } @@ -595,6 +690,24 @@ DataRelayerStats const& DataRelayer::getStats() const return mStats; } +uint32_t DataRelayer::getFirstTFOrbitForSlot(TimesliceSlot slot) +{ + std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); + return VariableContextHelpers::getFirstTFOrbit(mTimesliceIndex.getVariablesForSlot(slot)); +} + +uint32_t DataRelayer::getFirstTFCounterForSlot(TimesliceSlot slot) +{ + std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); + return VariableContextHelpers::getFirstTFCounter(mTimesliceIndex.getVariablesForSlot(slot)); +} + +uint32_t DataRelayer::getRunNumberForSlot(TimesliceSlot slot) +{ + std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); + return VariableContextHelpers::getRunNumber(mTimesliceIndex.getVariablesForSlot(slot)); +} + void DataRelayer::sendContextState() { std::scoped_lock<LockableBase(std::recursive_mutex)> lock(mMutex); @@ -604,7 +717,12 @@ void DataRelayer::sendContextState() mMetrics, sVariablesMetricsNames); } for (size_t si = 0; si < mCachedStateMetrics.size(); ++si) { - mMetrics.send({mCachedStateMetrics[si], sMetricsNames[si]}); + mMetrics.send({static_cast<int>(mCachedStateMetrics[si]), sMetricsNames[si], Verbosity::Debug}); + // Anything which is done is actually already empty, + // so after we report it we mark it as such. + if (mCachedStateMetrics[si] == CacheEntryStatus::DONE) { + mCachedStateMetrics[si] = CacheEntryStatus::EMPTY; + } } } diff --git a/Framework/Core/src/DataRelayerHelpers.cxx b/Framework/Core/src/DataRelayerHelpers.cxx index d28e71d87103c..d3ae5f2abfb54 100644 --- a/Framework/Core/src/DataRelayerHelpers.cxx +++ b/Framework/Core/src/DataRelayerHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "DataRelayerHelpers.h" #include "Framework/DataDescriptorMatcher.h" +#include "Framework/InputRoute.h" #include <stdexcept> using namespace o2::framework::data_matcher; diff --git a/Framework/Core/src/DataRelayerHelpers.h b/Framework/Core/src/DataRelayerHelpers.h index eee703b6d7621..8d53acc3df18b 100644 --- a/Framework/Core/src/DataRelayerHelpers.h +++ b/Framework/Core/src/DataRelayerHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DataSpecUtils.cxx b/Framework/Core/src/DataSpecUtils.cxx index ab36bde400a47..b44eded813c92 100644 --- a/Framework/Core/src/DataSpecUtils.cxx +++ b/Framework/Core/src/DataSpecUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -278,8 +279,11 @@ bool DataSpecUtils::partialMatch(InputSpec const& input, header::DataDescription bool DataSpecUtils::partialMatch(OutputSpec const& output, header::DataDescription const& description) { - auto dataType = DataSpecUtils::asConcreteDataTypeMatcher(output); - return dataType.description == description; + try { + return DataSpecUtils::asConcreteDataTypeMatcher(output).description == description; + } catch (...) { + return false; + } } struct MatcherInfo { @@ -467,6 +471,22 @@ OutputSpec DataSpecUtils::asOutputSpec(InputSpec const& spec) spec.matcher); } +DataDescriptorMatcher DataSpecUtils::dataDescriptorMatcherFrom(ConcreteDataMatcher const& concrete) +{ + DataDescriptorMatcher matchEverything{ + DataDescriptorMatcher::Op::And, + OriginValueMatcher{concrete.origin.as<std::string>()}, + std::make_unique<DataDescriptorMatcher>( + DataDescriptorMatcher::Op::And, + DescriptionValueMatcher{concrete.description.as<std::string>()}, + std::make_unique<DataDescriptorMatcher>( + DataDescriptorMatcher::Op::And, + SubSpecificationTypeValueMatcher{concrete.subSpec}, + std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Just, + StartTimeValueMatcher{ContextRef{0}})))}; + return std::move(matchEverything); +} + DataDescriptorMatcher DataSpecUtils::dataDescriptorMatcherFrom(ConcreteDataTypeMatcher const& dataType) { auto timeDescriptionMatcher = std::make_unique<DataDescriptorMatcher>( @@ -535,6 +555,44 @@ InputSpec DataSpecUtils::matchingInput(OutputSpec const& spec) spec.matcher); } +std::optional<header::DataOrigin> DataSpecUtils::getOptionalOrigin(InputSpec const& spec) +{ + // FIXME: try to address at least a few cases. + return std::visit(overloaded{ + [](ConcreteDataMatcher const& concrete) -> std::optional<header::DataOrigin> { + return std::make_optional(concrete.origin); + }, + [](DataDescriptorMatcher const& matcher) -> std::optional<header::DataOrigin> { + auto state = extractMatcherInfo(matcher); + if (state.hasUniqueOrigin) { + return std::make_optional(state.origin); + } else if (state.hasError) { + throw runtime_error("Could not extract origin from query"); + } + return {}; + }}, + spec.matcher); +} + +std::optional<header::DataDescription> DataSpecUtils::getOptionalDescription(InputSpec const& spec) +{ + // FIXME: try to address at least a few cases. + return std::visit(overloaded{ + [](ConcreteDataMatcher const& concrete) -> std::optional<header::DataDescription> { + return std::make_optional(concrete.description); + }, + [](DataDescriptorMatcher const& matcher) -> std::optional<header::DataDescription> { + auto state = extractMatcherInfo(matcher); + if (state.hasUniqueDescription) { + return std::make_optional(state.description); + } else if (state.hasError) { + throw runtime_error("Could not extract description from query"); + } + return {}; + }}, + spec.matcher); +} + std::optional<header::DataHeader::SubSpecificationType> DataSpecUtils::getOptionalSubSpec(OutputSpec const& spec) { return std::visit(overloaded{ @@ -586,7 +644,7 @@ bool DataSpecUtils::includes(const InputSpec& left, const InputSpec& right) auto leftInfo = extractMatcherInfo(leftMatcher); return (!leftInfo.hasOrigin || (rightInfo.hasOrigin && leftInfo.origin == rightInfo.origin)) && (!leftInfo.hasDescription || (rightInfo.hasDescription && leftInfo.description == rightInfo.description)) && - (!leftInfo.hasSubSpec || (rightInfo.hasSubSpec && leftInfo.subSpec == rightInfo.hasSubSpec)); + (!leftInfo.hasSubSpec || (rightInfo.hasSubSpec && leftInfo.subSpec == rightInfo.subSpec)); }}, left.matcher); }}, diff --git a/Framework/Core/src/DeviceConfigInfo.cxx b/Framework/Core/src/DeviceConfigInfo.cxx index 62266282d5f89..47d726fc15c6a 100644 --- a/Framework/Core/src/DeviceConfigInfo.cxx +++ b/Framework/Core/src/DeviceConfigInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,15 +11,9 @@ #include "Framework/DeviceConfigInfo.h" #include "Framework/DeviceInfo.h" -#include <cassert> -#include <cinttypes> #include <cstdlib> - -#include <algorithm> -#include <regex> #include <string_view> -#include <tuple> -#include <iostream> +#include <boost/property_tree/json_parser.hpp> namespace o2::framework { @@ -30,7 +25,7 @@ bool DeviceConfigHelper::parseConfig(std::string_view s, ParsedConfigMatch& matc { const char* begin = s.begin(); const char* end = s.end(); - if (s.size() > 17 && (strncmp("[CONFIG] ", begin + 17, 9) != 0)) { + if (s.size() > 17 && (strncmp("[CONFIG];", begin + 17, 9) != 0)) { return false; } if (s.size() < 17 + 9) { @@ -42,14 +37,15 @@ bool DeviceConfigHelper::parseConfig(std::string_view s, ParsedConfigMatch& matc return false; } match.beginValue = match.endKey + 1; - match.endValue = (char const*)memchr(match.beginValue, ' ', end - match.beginValue); + match.endValue = (char const*)memchr(match.beginValue, ';', end - match.beginValue); if (match.endValue == nullptr) { return false; } + char* next = nullptr; - match.timestamp = strtoll(match.endValue, &next, 10); + match.timestamp = strtoll(match.endValue + 1, &next, 10); - if (!next || *next != ' ') { + if (!next || *next != ';') { return false; } @@ -67,10 +63,20 @@ bool DeviceConfigHelper::processConfig(ParsedConfigMatch& match, match.beginProvenance == nullptr || match.endProvenance == nullptr) { return false; } - info.currentConfig.put(std::string(match.beginKey, match.endKey - match.beginKey), - std::string(match.beginValue, match.endValue - match.beginValue)); - info.currentProvenance.put(std::string(match.beginKey, match.endKey - match.beginKey), - std::string(match.beginProvenance, match.endProvenance - match.beginProvenance)); + auto keyString = std::string(match.beginKey, match.endKey - match.beginKey); + auto valueString = std::string(match.beginValue, match.endValue - match.beginValue); + auto provenanceString = std::string(match.beginProvenance, match.endProvenance - match.beginProvenance); + boost::property_tree::ptree branch; + std::stringstream ss{valueString}; + try { + boost::property_tree::json_parser::read_json(ss, branch); + info.currentConfig.put_child(keyString, branch); + } catch (boost::exception&) { + // in case it is not a tree but a single value + info.currentConfig.put(keyString, valueString); + } + + info.currentProvenance.put(keyString, provenanceString); return true; } diff --git a/Framework/Core/src/DeviceController.cxx b/Framework/Core/src/DeviceController.cxx new file mode 100644 index 0000000000000..e7793ac1c4c23 --- /dev/null +++ b/Framework/Core/src/DeviceController.cxx @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DeviceController.h" +#include "DPLWebSocket.h" +#include "HTTPParser.h" +#include "Framework/Logger.h" +#include <uv.h> +#include <vector> + +namespace o2::framework +{ + +DeviceController::DeviceController(WSDPLHandler* handler) + : mHandler{handler} +{ +} + +void DeviceController::hello() +{ + LOG(debug) << "Saying hello"; + std::vector<uv_buf_t> outputs; + encode_websocket_frames(outputs, "hello", strlen("hello"), WebSocketOpCode::Binary, 0); + mHandler->write(outputs); +} + +void DeviceController::write(char const* message, size_t s) +{ + LOGP(debug, "Saying {} to device", message); + std::vector<uv_buf_t> outputs; + encode_websocket_frames(outputs, message, s, WebSocketOpCode::Binary, 0); + mHandler->write(outputs); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DeviceMetricsHelper.cxx b/Framework/Core/src/DeviceMetricsHelper.cxx new file mode 100644 index 0000000000000..c0f87446bc18a --- /dev/null +++ b/Framework/Core/src/DeviceMetricsHelper.cxx @@ -0,0 +1,335 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DeviceMetricsHelper.h" +#include "Framework/RuntimeError.h" +#include <cassert> +#include <cinttypes> +#include <cstdlib> + +#include <algorithm> +#include <regex> +#include <string_view> +#include <tuple> +#include <iostream> +#include <limits> + +namespace o2::framework +{ + +// Parses a metric in the form +// +// [METRIC] <name>,<type> <value> <timestamp> [<tag>,<tag>] +bool DeviceMetricsHelper::parseMetric(std::string_view const s, ParsedMetricMatch& match) +{ + /// Must start with "[METRIC] " + /// 012345678 + constexpr size_t PREFIXSIZE = 9; + if (s.size() < PREFIXSIZE) { + return false; + } + if (memcmp(s.data(), "[METRIC] ", 9) != 0) { + return false; + } + char const* comma; // first comma + char const* spaces[256]; // list of spaces + char const** space = spaces; // first element to fill + + comma = (char const*)memchr((void*)s.data(), ',', s.size()); + if (comma == nullptr) { + return false; + } + // Find all spaces + char const* nextSpace = s.data(); + while (space - spaces < 256) { + *space = strchr(nextSpace, ' '); + if (*space == nullptr) { + break; + } + nextSpace = *space + 1; + space++; + } + // First space should always come before comma + if (spaces[0] > comma) { + return false; + } + match.beginKey = spaces[0] + 1; + match.endKey = comma; + // type is alway 1 char after the comma, followed by space + if ((spaces[1] - comma) != 2) { + return false; + } + char* ep = nullptr; + match.type = static_cast<MetricType>(strtol(comma + 1, &ep, 10)); + if (ep != spaces[1]) { + return false; + } + // We need at least 4 spaces + if (space - spaces < 4) { + return false; + } + // Value is between the second and the last but one space + switch (match.type) { + case MetricType::Int: + match.intValue = strtol(spaces[1] + 1, &ep, 10); + if (ep != *(space - 2)) { + return false; + } + match.floatValue = (float)match.intValue; + break; + case MetricType::Float: + match.floatValue = strtof(spaces[1] + 1, &ep); + if (ep != *(space - 2)) { + return false; + } + break; + case MetricType::String: + match.beginStringValue = spaces[1] + 1; + match.endStringValue = *(space - 2); + match.floatValue = 0; + break; + case MetricType::Uint64: + match.uint64Value = strtoul(spaces[1] + 1, &ep, 10); + if (ep != *(space - 2)) { + return false; + } + match.floatValue = (float)match.uint64Value; + break; + + default: + return false; + } + // Timestamp is between the last but one and the last space + match.timestamp = strtol(*(space - 2) + 1, &ep, 10); + if (ep != *(space - 1)) { + return false; + } + return true; +} + +size_t DeviceMetricsHelper::bookMetricInfo(DeviceMetricsInfo& info, char const* name) +{ + // Add the index by name in the correct position + // this will require moving the tail of the index, + // but inserting should happen only once for each metric, + // so who cares. + // Add the the actual Metric info to the store + MetricLabel metricLabel; + strncpy(metricLabel.label, name, MetricLabel::MAX_METRIC_LABEL_SIZE - 1); + metricLabel.label[MetricLabel::MAX_METRIC_LABEL_SIZE - 1] = '\0'; + metricLabel.size = strlen(metricLabel.label); + + // Find the insertion point for the sorted index + auto cmpFn = [namePtr = metricLabel.label, + &labels = info.metricLabels, + nameSize = metricLabel.size](MetricLabelIndex const& a, MetricLabelIndex const& b) + -> bool { + return strncmp(labels[a.index].label, namePtr, nameSize) < 0; + }; + + auto mi = std::lower_bound(info.metricLabelsAlphabeticallySortedIdx.begin(), + info.metricLabelsAlphabeticallySortedIdx.end(), + MetricLabelIndex{}, + cmpFn); + + // If it was already there, return the old index. + if (mi != info.metricLabelsAlphabeticallySortedIdx.end() && (strncmp(info.metricLabels[mi->index].label, metricLabel.label, std::min((size_t)metricLabel.size, (size_t)MetricLabel::MAX_METRIC_LABEL_SIZE - 1)) == 0)) { + return mi->index; + } + + // Add the the actual Metric info to the store + auto metricIndex = info.metrics.size(); + + // Insert the sorted location where it belongs to. + MetricLabelIndex metricLabelIdx{metricIndex}; + info.metricLabelsAlphabeticallySortedIdx.insert(mi, metricLabelIdx); + info.metrics.push_back(MetricInfo{}); + + // Create a new metric + auto& metricInfo = info.metrics.back(); + metricInfo.pos = 0; + metricInfo.filledMetrics = 0; + + // Add the timestamp buffer for it + info.timestamps.emplace_back(std::array<size_t, 1024>{}); + info.max.push_back(std::numeric_limits<float>::lowest()); + info.min.push_back(std::numeric_limits<float>::max()); + info.average.push_back(0); + info.maxDomain.push_back(std::numeric_limits<size_t>::lowest()); + info.minDomain.push_back(std::numeric_limits<size_t>::max()); + info.changed.push_back(true); + + info.metricLabels.push_back(metricLabel); + + return metricIndex; +} + +bool DeviceMetricsHelper::processMetric(ParsedMetricMatch& match, + DeviceMetricsInfo& info, + DeviceMetricsHelper::NewMetricCallback newMetricsCallback) +{ + // get the type + size_t metricIndex = -1; + + StringMetric stringValue; + switch (match.type) { + case MetricType::Float: + case MetricType::Int: + case MetricType::Uint64: + break; + case MetricType::String: { + auto lastChar = std::min(match.endStringValue - match.beginStringValue, StringMetric::MAX_SIZE - 1); + memcpy(stringValue.data, match.beginStringValue, lastChar); + stringValue.data[lastChar] = '\0'; + } break; + default: + return false; + break; + }; + + // Find the metric based on the label. Create it if not found. + auto cmpFn = [namePtr = match.beginKey, + &labels = info.metricLabels, + nameSize = match.endKey - match.beginKey](MetricLabelIndex const& a, MetricLabelIndex const& b) + -> bool { + return strncmp(labels[a.index].label, namePtr, nameSize) < 0; + }; + auto mi = std::lower_bound(info.metricLabelsAlphabeticallySortedIdx.begin(), + info.metricLabelsAlphabeticallySortedIdx.end(), + MetricLabelIndex{}, + cmpFn); + + // We could not find the metric, lets insert a new one. + auto matchSize = match.endKey - match.beginKey; + if (mi == info.metricLabelsAlphabeticallySortedIdx.end() || (strncmp(info.metricLabels[mi->index].label, match.beginKey, std::min(matchSize, (long)MetricLabel::MAX_METRIC_LABEL_SIZE - 1)) != 0)) { + // Create a new metric + MetricInfo metricInfo; + metricInfo.pos = 0; + metricInfo.type = match.type; + metricInfo.filledMetrics = 0; + // Add a new empty buffer for it of the correct kind + switch (match.type) { + case MetricType::Int: + metricInfo.storeIdx = info.intMetrics.size(); + info.intMetrics.emplace_back(std::array<int, 1024>{}); + break; + case MetricType::String: + metricInfo.storeIdx = info.stringMetrics.size(); + info.stringMetrics.emplace_back(std::array<StringMetric, 32>{}); + break; + case MetricType::Float: + metricInfo.storeIdx = info.floatMetrics.size(); + info.floatMetrics.emplace_back(std::array<float, 1024>{}); + break; + case MetricType::Uint64: + metricInfo.storeIdx = info.uint64Metrics.size(); + info.uint64Metrics.emplace_back(std::array<uint64_t, 1024>{}); + break; + + default: + return false; + }; + // Add the timestamp buffer for it + info.timestamps.emplace_back(std::array<size_t, 1024>{}); + info.max.push_back(std::numeric_limits<float>::lowest()); + info.min.push_back(std::numeric_limits<float>::max()); + info.average.push_back(0); + info.maxDomain.push_back(std::numeric_limits<size_t>::lowest()); + info.minDomain.push_back(std::numeric_limits<size_t>::max()); + info.changed.push_back(false); + + // Add the index by name in the correct position + // this will require moving the tail of the index, + // but inserting should happen only once for each metric, + // so who cares. + MetricLabel metricLabel; + auto lastChar = std::min(match.endKey - match.beginKey, (ptrdiff_t)MetricLabel::MAX_METRIC_LABEL_SIZE - 1); + memcpy(metricLabel.label, match.beginKey, lastChar); + metricLabel.label[lastChar] = '\0'; + metricLabel.size = lastChar; + MetricLabelIndex metricLabelIdx; + metricLabelIdx.index = info.metrics.size(); + info.metricLabels.push_back(metricLabel); + info.metricLabelsAlphabeticallySortedIdx.insert(mi, metricLabelIdx); + // Add the the actual Metric info to the store + metricIndex = info.metrics.size(); + assert(metricInfo.storeIdx != -1); + assert(metricLabel.label[0] != '\0'); + if (newMetricsCallback != nullptr) { + newMetricsCallback(metricLabel.label, metricInfo, match.intValue, metricIndex); + } + info.metrics.push_back(metricInfo); + } else { + metricIndex = mi->index; + } + assert(metricIndex != -1); + // We are now guaranteed our metric is present at metricIndex. + MetricInfo& metricInfo = info.metrics[metricIndex]; + + // auto mod = info.timestamps[metricIndex].size(); + auto sizeOfCollection = 0; + switch (metricInfo.type) { + case MetricType::Int: { + info.intMetrics[metricInfo.storeIdx][metricInfo.pos] = match.intValue; + sizeOfCollection = info.intMetrics[metricInfo.storeIdx].size(); + } break; + case MetricType::String: { + info.stringMetrics[metricInfo.storeIdx][metricInfo.pos] = stringValue; + sizeOfCollection = info.stringMetrics[metricInfo.storeIdx].size(); + } break; + case MetricType::Float: { + info.floatMetrics[metricInfo.storeIdx][metricInfo.pos] = match.floatValue; + sizeOfCollection = info.floatMetrics[metricInfo.storeIdx].size(); + } break; + case MetricType::Uint64: { + info.uint64Metrics[metricInfo.storeIdx][metricInfo.pos] = match.uint64Value; + sizeOfCollection = info.uint64Metrics[metricInfo.storeIdx].size(); + } break; + default: + return false; + break; + }; + // We do all the updates here, so that not update timestamps for broken metrics + // Notice how we always fill floatValue with the float equivalent of the metric + // regardless of it's type. + info.minDomain[metricIndex] = std::min(info.minDomain[metricIndex], (size_t)match.timestamp); + info.maxDomain[metricIndex] = std::max(info.maxDomain[metricIndex], (size_t)match.timestamp); + info.max[metricIndex] = std::max(info.max[metricIndex], match.floatValue); + info.min[metricIndex] = std::min(info.min[metricIndex], match.floatValue); + auto onlineAverage = [](float nextValue, float previousAverage, float previousCount) { + return previousAverage + (nextValue - previousAverage) / (previousCount + 1); + }; + info.average[metricIndex] = onlineAverage(match.floatValue, info.average[metricIndex], metricInfo.filledMetrics); + info.timestamps[metricIndex][metricInfo.pos] = match.timestamp; + // We point to the next metric + metricInfo.pos = (metricInfo.pos + 1) % sizeOfCollection; + ++metricInfo.filledMetrics; + // Note that we updated a given metric. + info.changed[metricIndex] = true; + return true; +} + +size_t DeviceMetricsHelper::metricIdxByName(const std::string& name, const DeviceMetricsInfo& info) +{ + size_t i = 0; + while (i < info.metricLabels.size()) { + auto& metricName = info.metricLabels[i]; + // We check the size first and then the last character because that's + // likely to be different for multi-index metrics + if (metricName.size == name.size() && metricName.label[metricName.size - 1] == name[metricName.size - 1] && memcmp(metricName.label, name.c_str(), metricName.size) == 0) { + return i; + } + ++i; + } + return i; +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DeviceMetricsInfo.cxx b/Framework/Core/src/DeviceMetricsInfo.cxx index 7b4c467fdadbd..621ade8a7da8a 100644 --- a/Framework/Core/src/DeviceMetricsInfo.cxx +++ b/Framework/Core/src/DeviceMetricsInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,258 +24,6 @@ namespace o2::framework { -// Parses a metric in the form -// -// [METRIC] <name>,<type> <value> <timestamp> [<tag>,<tag>] -bool DeviceMetricsHelper::parseMetric(std::string_view const s, ParsedMetricMatch& match) -{ - /// Must start with "[METRIC] " - /// 012345678 - constexpr size_t PREFIXSIZE = 9; - if (s.size() < PREFIXSIZE) { - return false; - } - if (memcmp(s.data(), "[METRIC] ", 9) != 0) { - return false; - } - char const* comma; // first comma - char const* spaces[256]; // list of spaces - char const** space = spaces; // first element to fill - - comma = (char const*)memchr((void*)s.data(), ',', s.size()); - if (comma == nullptr) { - return false; - } - // Find all spaces - char const* nextSpace = s.data(); - while (space - spaces < 256) { - *space = strchr(nextSpace, ' '); - if (*space == nullptr) { - break; - } - nextSpace = *space + 1; - space++; - } - // First space should always come before comma - if (spaces[0] > comma) { - return false; - } - match.beginKey = spaces[0] + 1; - match.endKey = comma; - // type is alway 1 char after the comma, followed by space - if ((spaces[1] - comma) != 2) { - return false; - } - char* ep = nullptr; - match.type = static_cast<MetricType>(strtol(comma + 1, &ep, 10)); - if (ep != spaces[1]) { - return false; - } - // We need at least 4 spaces - if (space - spaces < 4) { - return false; - } - // Value is between the second and the last but one space - switch (match.type) { - case MetricType::Int: - match.intValue = strtol(spaces[1] + 1, &ep, 10); - if (ep != *(space - 2)) { - return false; - } - break; - case MetricType::Float: - match.floatValue = strtof(spaces[1] + 1, &ep); - if (ep != *(space - 2)) { - return false; - } - break; - case MetricType::String: - match.beginStringValue = spaces[1] + 1; - match.endStringValue = *(space - 2); - break; - case MetricType::Uint64: - match.uint64Value = strtoul(spaces[1] + 1, &ep, 10); - if (ep != *(space - 2)) { - return false; - } - break; - - default: - return false; - } - // Timestamp is between the last but one and the last space - match.timestamp = strtol(*(space - 2) + 1, &ep, 10); - if (ep != *(space - 1)) { - return false; - } - return true; -} - -bool DeviceMetricsHelper::processMetric(ParsedMetricMatch& match, - DeviceMetricsInfo& info, - DeviceMetricsHelper::NewMetricCallback newMetricsCallback) -{ - // get the type - size_t metricIndex = -1; - - StringMetric stringValue; - switch (match.type) { - case MetricType::Float: - case MetricType::Int: - case MetricType::Uint64: - break; - case MetricType::String: { - auto lastChar = std::min(match.endStringValue - match.beginStringValue, StringMetric::MAX_SIZE - 1); - memcpy(stringValue.data, match.beginStringValue, lastChar); - stringValue.data[lastChar] = '\0'; - } break; - default: - return false; - break; - }; - - // Find the metric based on the label. Create it if not found. - auto cmpFn = [namePtr = match.beginKey, - nameSize = match.endKey - match.beginKey](MetricLabelIndex const& a, MetricLabelIndex const& b) - -> bool { - return strncmp(a.label, namePtr, nameSize) < 0; - }; - auto mi = std::lower_bound(info.metricLabelsIdx.begin(), - info.metricLabelsIdx.end(), - MetricLabelIndex{}, - cmpFn); - - // We could not find the metric, lets insert a new one. - if (mi == info.metricLabelsIdx.end() || (strncmp(mi->label, match.beginKey, std::min(match.endKey - match.beginKey, (long)MetricLabelIndex::MAX_METRIC_LABEL_SIZE - 1)) != 0)) { - // Create a new metric - MetricInfo metricInfo; - metricInfo.pos = 0; - metricInfo.type = match.type; - metricInfo.filledMetrics = 0; - // Add a new empty buffer for it of the correct kind - switch (match.type) { - case MetricType::Int: - metricInfo.storeIdx = info.intMetrics.size(); - info.intMetrics.emplace_back(std::array<int, 1024>{}); - break; - case MetricType::String: - metricInfo.storeIdx = info.stringMetrics.size(); - info.stringMetrics.emplace_back(std::array<StringMetric, 32>{}); - break; - case MetricType::Float: - metricInfo.storeIdx = info.floatMetrics.size(); - info.floatMetrics.emplace_back(std::array<float, 1024>{}); - break; - case MetricType::Uint64: - metricInfo.storeIdx = info.uint64Metrics.size(); - info.uint64Metrics.emplace_back(std::array<uint64_t, 1024>{}); - break; - - default: - return false; - }; - // Add the timestamp buffer for it - info.timestamps.emplace_back(std::array<size_t, 1024>{}); - info.max.push_back(std::numeric_limits<float>::lowest()); - info.min.push_back(std::numeric_limits<float>::max()); - info.maxDomain.push_back(std::numeric_limits<size_t>::lowest()); - info.minDomain.push_back(std::numeric_limits<size_t>::max()); - info.changed.push_back(false); - - // Add the index by name in the correct position - // this will require moving the tail of the index, - // but inserting should happen only once for each metric, - // so who cares. - MetricLabelIndex metricLabelIdx; - auto lastChar = std::min(match.endKey - match.beginKey, (ptrdiff_t)MetricLabelIndex::MAX_METRIC_LABEL_SIZE - 1); - memcpy(metricLabelIdx.label, match.beginKey, lastChar); - metricLabelIdx.label[lastChar] = '\0'; - metricLabelIdx.index = info.metrics.size(); - info.metricLabelsIdx.insert(mi, metricLabelIdx); - // Add the the actual Metric info to the store - metricIndex = info.metrics.size(); - assert(metricInfo.storeIdx != -1); - assert(metricLabelIdx.label[0] != '\0'); - if (newMetricsCallback != nullptr) { - newMetricsCallback(metricLabelIdx.label, metricInfo, match.intValue, metricIndex); - } - info.metrics.push_back(metricInfo); - } else { - metricIndex = mi->index; - } - assert(metricIndex != -1); - // We are now guaranteed our metric is present at metricIndex. - MetricInfo& metricInfo = info.metrics[metricIndex]; - - // auto mod = info.timestamps[metricIndex].size(); - info.minDomain[metricIndex] = std::min(info.minDomain[metricIndex], (size_t)match.timestamp); - info.maxDomain[metricIndex] = std::max(info.maxDomain[metricIndex], (size_t)match.timestamp); - - switch (metricInfo.type) { - case MetricType::Int: { - info.intMetrics[metricInfo.storeIdx][metricInfo.pos] = match.intValue; - info.max[metricIndex] = std::max(info.max[metricIndex], (float)match.intValue); - info.min[metricIndex] = std::min(info.min[metricIndex], (float)match.intValue); - // Save the timestamp for the current metric we do it here - // so that we do not update timestamps for broken metrics - info.timestamps[metricIndex][metricInfo.pos] = match.timestamp; - // Update the position where to write the next metric - metricInfo.pos = (metricInfo.pos + 1) % info.intMetrics[metricInfo.storeIdx].size(); - ++metricInfo.filledMetrics; - } break; - case MetricType::String: { - info.stringMetrics[metricInfo.storeIdx][metricInfo.pos] = stringValue; - // Save the timestamp for the current metric we do it here - // so that we do not update timestamps for broken metrics - info.timestamps[metricIndex][metricInfo.pos] = match.timestamp; - metricInfo.pos = (metricInfo.pos + 1) % info.stringMetrics[metricInfo.storeIdx].size(); - ++metricInfo.filledMetrics; - } break; - case MetricType::Float: { - info.floatMetrics[metricInfo.storeIdx][metricInfo.pos] = match.floatValue; - info.max[metricIndex] = std::max(info.max[metricIndex], match.floatValue); - info.min[metricIndex] = std::min(info.min[metricIndex], match.floatValue); - // Save the timestamp for the current metric we do it here - // so that we do not update timestamps for broken metrics - info.timestamps[metricIndex][metricInfo.pos] = match.timestamp; - metricInfo.pos = (metricInfo.pos + 1) % info.floatMetrics[metricInfo.storeIdx].size(); - ++metricInfo.filledMetrics; - } break; - case MetricType::Uint64: { - info.uint64Metrics[metricInfo.storeIdx][metricInfo.pos] = match.uint64Value; - info.max[metricIndex] = std::max(info.max[metricIndex], (float)match.uint64Value); - info.min[metricIndex] = std::min(info.min[metricIndex], (float)match.uint64Value); - // Save the timestamp for the current metric we do it here - // so that we do not update timestamps for broken metrics - info.timestamps[metricIndex][metricInfo.pos] = match.timestamp; - // Update the position where to write the next metric - metricInfo.pos = (metricInfo.pos + 1) % info.uint64Metrics[metricInfo.storeIdx].size(); - ++metricInfo.filledMetrics; - } break; - - default: - return false; - break; - }; - // Note that we updated a given metric. - info.changed[metricIndex] = true; - return true; -} - -size_t - DeviceMetricsHelper::metricIdxByName(const std::string& name, const DeviceMetricsInfo& info) -{ - size_t i = 0; - while (i < info.metricLabelsIdx.size()) { - auto& metricName = info.metricLabelsIdx[i]; - if (metricName.label == name) { - return metricName.index; - } - ++i; - } - return i; -} - std::ostream& operator<<(std::ostream& oss, MetricType const& val) { switch (val) { diff --git a/Framework/Core/src/DeviceSpec.cxx b/Framework/Core/src/DeviceSpec.cxx index 06f8f7d561a3f..46485ced0589f 100644 --- a/Framework/Core/src/DeviceSpec.cxx +++ b/Framework/Core/src/DeviceSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/DeviceSpecHelpers.cxx b/Framework/Core/src/DeviceSpecHelpers.cxx index 0cc4ea56c7dea..720b2ab4ead6c 100644 --- a/Framework/Core/src/DeviceSpecHelpers.cxx +++ b/Framework/Core/src/DeviceSpecHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,6 +37,7 @@ #include <uv.h> #include <iostream> +#include <fmt/format.h> #include <sys/time.h> #include <sys/resource.h> @@ -50,14 +52,20 @@ namespace o2::framework namespace detail { -void timer_callback(uv_timer_t*) +void timer_callback(uv_timer_t* handle) { // We simply wake up the event loop. Nothing to be done here. + DeviceState* state = (DeviceState*)handle->data; + state->loopReason |= DeviceState::TIMER_EXPIRED; + state->loopReason |= DeviceState::DATA_INCOMING; } -void signal_callback(uv_signal_t*, int) +void signal_callback(uv_signal_t* handle, int) { // We simply wake up the event loop. Nothing to be done here. + DeviceState* state = (DeviceState*)handle->data; + state->loopReason |= DeviceState::SIGNAL_ARRIVED; + state->loopReason |= DeviceState::DATA_INCOMING; } } // namespace detail @@ -76,6 +84,7 @@ struct ExpirationHandlerHelpers { // timeslot creation and record expiration still happens // in a synchronous way. uv_timer_t* timer = (uv_timer_t*)(malloc(sizeof(uv_timer_t))); + timer->data = &state; uv_timer_init(state.loop, timer); uv_timer_start(timer, detail::timer_callback, period / 1000, period / 1000); state.activeTimers.push_back(timer); @@ -98,6 +107,7 @@ struct ExpirationHandlerHelpers { // in a synchronous way. uv_signal_t* sh = (uv_signal_t*)(malloc(sizeof(uv_signal_t))); uv_signal_init(state.loop, sh); + sh->data = &state; uv_signal_start(sh, detail::signal_callback, SIGUSR1); state.activeSignals.push_back(sh); @@ -130,21 +140,18 @@ struct ExpirationHandlerHelpers { static RouteConfigurator::DanglingConfigurator danglingConditionConfigurator() { - return [](DeviceState&, ConfigParamRegistry const&) { return LifetimeHelpers::expireAlways(); }; + return [](DeviceState&, ConfigParamRegistry const& options) { + auto serverUrl = options.get<std::string>("condition-backend"); + return LifetimeHelpers::expectCTP(serverUrl, true); + }; } static RouteConfigurator::ExpirationConfigurator expiringConditionConfigurator(InputSpec const& spec, std::string const& sourceChannel) { - /// FIXME: seems convoluted... Maybe there is a way to avoid all this checking??? - auto m = std::get_if<ConcreteDataMatcher>(&spec.matcher); - if (m == nullptr) { - throw runtime_error("InputSpec for Conditions must be fully qualified"); - } - - return [s = spec, matcher = *m, sourceChannel](DeviceState&, ConfigParamRegistry const& options) { + return [spec, sourceChannel](DeviceState&, ConfigParamRegistry const& options) { auto serverUrl = options.get<std::string>("condition-backend"); - auto timestamp = options.get<std::string>("condition-timestamp"); - return LifetimeHelpers::fetchFromCCDBCache(matcher, serverUrl, timestamp, sourceChannel); + auto forceTimestamp = options.get<std::string>("condition-timestamp"); + return LifetimeHelpers::fetchFromCCDBCache(spec, serverUrl, forceTimestamp, sourceChannel); }; } @@ -182,7 +189,10 @@ struct ExpirationHandlerHelpers { throw runtime_error("InputSpec for Timers must be fully qualified"); } // We copy the matcher to avoid lifetime issues. - return [matcher = *m, sourceChannel](DeviceState&, ConfigParamRegistry const&) { return LifetimeHelpers::enumerate(matcher, sourceChannel); }; + return [matcher = *m, sourceChannel](DeviceState&, ConfigParamRegistry const& config) { + // Timers do not have any orbit associated to them + return LifetimeHelpers::enumerate(matcher, sourceChannel, 0, 0); + }; } static RouteConfigurator::ExpirationConfigurator expiringEnumerationConfigurator(InputSpec const& spec, std::string const& sourceChannel) @@ -192,8 +202,10 @@ struct ExpirationHandlerHelpers { throw runtime_error("InputSpec for Enumeration must be fully qualified"); } // We copy the matcher to avoid lifetime issues. - return [matcher = *m, sourceChannel](DeviceState&, ConfigParamRegistry const&) { - return LifetimeHelpers::enumerate(matcher, sourceChannel); + return [matcher = *m, sourceChannel](DeviceState&, ConfigParamRegistry const& config) { + size_t orbitOffset = config.get<int64_t>("orbit-offset-enumeration"); + size_t orbitMultiplier = config.get<int64_t>("orbit-multiplier-enumeration"); + return LifetimeHelpers::enumerate(matcher, sourceChannel, orbitOffset, orbitMultiplier); }; } @@ -209,38 +221,62 @@ struct ExpirationHandlerHelpers { { return [](DeviceState&, ConfigParamRegistry const&) { return LifetimeHelpers::fetchFromObjectRegistry(); }; } + + /// This behaves as data. I.e. we never create it unless data arrives. + static RouteConfigurator::CreationConfigurator createOptionalConfigurator() + { + return [](DeviceState&, ConfigParamRegistry const&) { return LifetimeHelpers::dataDrivenCreation(); }; + } + + /// This will always exipire an optional record when no data is received. + static RouteConfigurator::DanglingConfigurator danglingOptionalConfigurator() + { + return [](DeviceState&, ConfigParamRegistry const&) { return LifetimeHelpers::expireAlways(); }; + } + + /// When the record expires, simply create a dummy entry. + static RouteConfigurator::ExpirationConfigurator expiringOptionalConfigurator(InputSpec const& spec, std::string const& sourceChannel) + { + try { + ConcreteDataMatcher concrete = DataSpecUtils::asConcreteDataMatcher(spec); + return [concrete, sourceChannel](DeviceState&, ConfigParamRegistry const& config) { + return LifetimeHelpers::dummy(concrete, sourceChannel); + }; + } catch (...) { + ConcreteDataTypeMatcher dataType = DataSpecUtils::asConcreteDataTypeMatcher(spec); + ConcreteDataMatcher concrete{dataType.origin, dataType.description, 0xdeadbeef}; + return [concrete, sourceChannel](DeviceState&, ConfigParamRegistry const& config) { + return LifetimeHelpers::dummy(concrete, sourceChannel); + }; + // We copy the matcher to avoid lifetime issues. + } + } }; /// This creates a string to configure channels of a FairMQDevice /// FIXME: support shared memory std::string DeviceSpecHelpers::inputChannel2String(const InputChannelSpec& channel) { - std::string result; - - if (!channel.name.empty()) { - result += "name=" + channel.name + ","; - } - result += std::string("type=") + ChannelSpecHelpers::typeAsString(channel.type); - result += std::string(",method=") + ChannelSpecHelpers::methodAsString(channel.method); - result += std::string(",address=") + ChannelSpecHelpers::channelUrl(channel); - result += std::string(",rateLogging=60"); - - return result; + return fmt::format("{}type={},method={},address={},rateLogging={},rcvBufSize={},sndBufSize={}", + channel.name.empty() ? "" : "name=" + channel.name + ",", + ChannelSpecHelpers::typeAsString(channel.type), + ChannelSpecHelpers::methodAsString(channel.method), + ChannelSpecHelpers::channelUrl(channel), + channel.rateLogging, + channel.recvBufferSize, + channel.sendBufferSize); } std::string DeviceSpecHelpers::outputChannel2String(const OutputChannelSpec& channel) { - std::string result; - - if (!channel.name.empty()) { - result += "name=" + channel.name + ","; - } - result += std::string("type=") + ChannelSpecHelpers::typeAsString(channel.type); - result += std::string(",method=") + ChannelSpecHelpers::methodAsString(channel.method); - result += std::string(",address=") + ChannelSpecHelpers::channelUrl(channel); - result += std::string(",rateLogging=60"); - - return result; + return fmt::format("{}type={},method={},address={},rateLogging={},rcvBufSize={},sndBufSize={}", + channel.name.empty() ? "" : "name=" + channel.name + ",", + ChannelSpecHelpers::typeAsString(channel.type), + ChannelSpecHelpers::methodAsString(channel.method), + ChannelSpecHelpers::channelUrl(channel), + channel.rateLogging, + channel.recvBufferSize, + channel.sendBufferSize); } void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, @@ -252,6 +288,7 @@ void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, const std::vector<EdgeAction>& actions, const WorkflowSpec& workflow, const std::vector<OutputSpec>& outputsMatchers, const std::vector<ChannelConfigurationPolicy>& channelPolicies, + std::string const& channelPrefix, ComputingOffer const& defaultOffer) { // The topology cannot be empty or not connected. If that is the case, than @@ -261,7 +298,9 @@ void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, // Edges are navigated in order for each device, so the device associaited to // an edge is always the last one created. - auto deviceForEdge = [&actions, &workflow, &devices, &logicalEdges, &resourceManager, &defaultOffer](size_t ei, ComputingOffer& acceptedOffer) { + auto deviceForEdge = [&actions, &workflow, &devices, + &logicalEdges, &resourceManager, + &defaultOffer, &channelPrefix](size_t ei, ComputingOffer& acceptedOffer) { auto& edge = logicalEdges[ei]; auto& action = actions[ei]; @@ -293,6 +332,7 @@ void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, DeviceSpec device; device.name = processor.name; device.id = processor.name; + device.channelPrefix = channelPrefix; if (processor.maxInputTimeslices != 1) { device.id = processor.name + "_t" + std::to_string(edge.producerTimeIndex); } @@ -304,6 +344,7 @@ void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, device.inputTimesliceId = edge.producerTimeIndex; device.maxInputTimeslices = processor.maxInputTimeslices; device.resource = {acceptedOffer}; + device.labels = processor.labels; devices.push_back(device); return devices.size() - 1; }; @@ -318,7 +359,7 @@ void DeviceSpecHelpers::processOutEdgeActions(std::vector<DeviceSpec>& devices, if (consumer.maxInputTimeslices != 1) { consumerDeviceId += "_t" + std::to_string(edge.timeIndex); } - channel.name = "from_" + device.id + "_to_" + consumerDeviceId; + channel.name = device.channelPrefix + "from_" + device.id + "_to_" + consumerDeviceId; channel.port = acceptedOffer.startPort + acceptedOffer.rangeSize; channel.hostname = acceptedOffer.hostname; deviceResource.usedPorts += 1; @@ -433,6 +474,7 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, const std::vector<EdgeAction>& actions, const WorkflowSpec& workflow, std::vector<LogicalForwardInfo> const& availableForwardsInfo, std::vector<ChannelConfigurationPolicy> const& channelPolicies, + std::string const& channelPrefix, ComputingOffer const& defaultOffer) { auto const& constDeviceIndex = deviceIndex; @@ -448,6 +490,20 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, return deviceIt->deviceIndex; }; + auto findConsumerForEdge = [&logicalEdges, &constDeviceIndex](size_t ei) { + auto& edge = logicalEdges[ei]; + if (!std::is_sorted(constDeviceIndex.cbegin(), constDeviceIndex.cend())) { + throw o2::framework::runtime_error("Needs a sorted vector to be correct"); + } + + DeviceId pid{edge.consumer, edge.timeIndex, 0}; + auto deviceIt = std::lower_bound(constDeviceIndex.cbegin(), constDeviceIndex.cend(), pid); + // We search for a consumer only if we know it's is already there. + assert(deviceIt != constDeviceIndex.end()); + assert(deviceIt->processorIndex == pid.processorIndex && deviceIt->timeslice == pid.timeslice); + return deviceIt->deviceIndex; + }; + // Notice that to start with, consumer exists only if they also are // producers, so we need to create one if it does not exist. Given this is // stateful, we keep an eye on what edge was last searched to make sure we @@ -473,7 +529,9 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, return lastConsumerSearch->deviceIndex; }; - auto createNewDeviceForEdge = [&workflow, &logicalEdges, &devices, &deviceIndex, &resourceManager, &defaultOffer](size_t ei, ComputingOffer& acceptedOffer) { + auto createNewDeviceForEdge = [&workflow, &logicalEdges, &devices, + &deviceIndex, &resourceManager, &defaultOffer, + &channelPrefix](size_t ei, ComputingOffer& acceptedOffer) { auto& edge = logicalEdges[ei]; if (acceptedOffer.hostname != "") { @@ -500,6 +558,7 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, DeviceSpec device; device.name = processor.name; device.id = processor.name; + device.channelPrefix = channelPrefix; if (processor.maxInputTimeslices != 1) { device.id += "_t" + std::to_string(edge.timeIndex); } @@ -511,6 +570,7 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, device.inputTimesliceId = edge.timeIndex; device.maxInputTimeslices = processor.maxInputTimeslices; device.resource = {acceptedOffer}; + device.labels = processor.labels; // FIXME: maybe I should use an std::map in the end // but this is really not performance critical @@ -552,7 +612,7 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, auto const& producerDevice = devices[pi]; auto& consumerDevice = devices[ci]; InputChannelSpec channel; - channel.name = "from_" + producerDevice.id + "_to_" + consumerDevice.id; + channel.name = producerDevice.channelPrefix + "from_" + producerDevice.id + "_to_" + consumerDevice.id; channel.hostname = producerDevice.resource.hostname; channel.port = port; for (auto& policy : channelPolicies) { @@ -630,6 +690,12 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, ExpirationHandlerHelpers::danglingTransientConfigurator(), ExpirationHandlerHelpers::expiringTransientConfigurator(inputSpec)}; break; + case Lifetime::Optional: + route.configurator = { + ExpirationHandlerHelpers::createOptionalConfigurator(), + ExpirationHandlerHelpers::danglingOptionalConfigurator(), + ExpirationHandlerHelpers::expiringOptionalConfigurator(inputSpec, sourceChannel)}; + break; default: break; } @@ -659,7 +725,7 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, for (size_t edge : inEdgeIndex) { auto& action = actions[edge]; - size_t consumerDevice; + size_t consumerDevice = -1; if (action.requiresNewDevice) { if (hasConsumerForEdge(edge)) { @@ -667,6 +733,8 @@ void DeviceSpecHelpers::processInEdgeActions(std::vector<DeviceSpec>& devices, } else { consumerDevice = createNewDeviceForEdge(edge, acceptedOffer); } + } else { + consumerDevice = findConsumerForEdge(edge); } size_t producerDevice = findProducerForEdge(edge); @@ -691,13 +759,14 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf std::vector<ChannelConfigurationPolicy> const& channelPolicies, std::vector<CompletionPolicy> const& completionPolicies, std::vector<DispatchPolicy> const& dispatchPolicies, + std::vector<ResourcePolicy> const& resourcePolicies, std::vector<DeviceSpec>& devices, ResourceManager& resourceManager, std::string const& uniqueWorkflowId, bool optimizeTopology, - unsigned short resourcesMonitoringInterval) + unsigned short resourcesMonitoringInterval, + std::string const& channelPrefix) { - std::vector<LogicalForwardInfo> availableForwardsInfo; std::vector<DeviceConnectionEdge> logicalEdges; std::vector<DeviceConnectionId> connections; @@ -747,13 +816,13 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf defaultOffer.memory /= deviceCount + 1; processOutEdgeActions(devices, deviceIndex, connections, resourceManager, outEdgeIndex, logicalEdges, - outActions, workflow, outputs, channelPolicies, defaultOffer); + outActions, workflow, outputs, channelPolicies, channelPrefix, defaultOffer); // FIXME: is this not the case??? std::sort(connections.begin(), connections.end()); processInEdgeActions(devices, deviceIndex, connections, resourceManager, inEdgeIndex, logicalEdges, - inActions, workflow, availableForwardsInfo, channelPolicies, defaultOffer); + inActions, workflow, availableForwardsInfo, channelPolicies, channelPrefix, defaultOffer); // We apply the completion policies here since this is where we have all the // devices resolved. for (auto& device : devices) { @@ -769,6 +838,17 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf break; } } + bool hasPolicy = false; + for (auto& policy : resourcePolicies) { + if (policy.matcher(device) == true) { + device.resourcePolicy = policy; + hasPolicy = true; + break; + } + } + if (hasPolicy == false) { + throw runtime_error_f("Unable to find a resource policy for %s", device.id.c_str()); + } } for (auto& device : devices) { @@ -812,6 +892,67 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf } } +void DeviceSpecHelpers::reworkHomogeneousOption(std::vector<DataProcessorInfo>& infos, char const* name, char const* defaultValue) +{ + std::string finalValue; + for (auto& info : infos) { + auto it = std::find(info.cmdLineArgs.begin(), info.cmdLineArgs.end(), name); + if (it == info.cmdLineArgs.end()) { + continue; + } + auto value = it + 1; + if (value == info.cmdLineArgs.end()) { + throw runtime_error_f("%s requires an argument", name); + } + if (!finalValue.empty() && finalValue != *value) { + throw runtime_error_f("Found incompatible %s values: %s amd %s", name, finalValue.c_str(), value->c_str()); + } + finalValue = *value; + info.cmdLineArgs.erase(it, it + 2); + } + if (finalValue.empty() && defaultValue == nullptr) { + return; + } + if (finalValue.empty()) { + finalValue = defaultValue; + } + for (auto& info : infos) { + info.cmdLineArgs.push_back(name); + info.cmdLineArgs.push_back(finalValue); + } +} + +void DeviceSpecHelpers::reworkIntegerOption(std::vector<DataProcessorInfo>& infos, char const* name, std::function<long long()> defaultValueCallback, long long startValue, std::function<long long(long long, long long)> bestValue) +{ + int64_t finalValue = startValue; + bool wasModified = false; + for (auto& info : infos) { + auto it = std::find(info.cmdLineArgs.begin(), info.cmdLineArgs.end(), name); + if (it == info.cmdLineArgs.end()) { + continue; + } + auto valueS = it + 1; + if (valueS == info.cmdLineArgs.end()) { + throw runtime_error_f("%s requires an integer argument", name); + } + char* err = nullptr; + long long value = strtoll(valueS->c_str(), &err, 10); + finalValue = bestValue(value, finalValue); + wasModified = true; + info.cmdLineArgs.erase(it, it + 2); + } + if (!wasModified && defaultValueCallback == nullptr) { + return; + } + if (!wasModified) { + finalValue = defaultValueCallback(); + } + for (auto& info : infos) { + info.cmdLineArgs.push_back(name); + info.cmdLineArgs.push_back(std::to_string(finalValue)); + } +} + void DeviceSpecHelpers::reworkShmSegmentSize(std::vector<DataProcessorInfo>& infos) { int64_t segmentSize = 0; @@ -860,7 +1001,7 @@ void split(const std::string& str, Container& cont) } } // namespace -void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, +void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, unsigned short driverPort, std::vector<DataProcessorInfo> const& processorInfos, std::vector<DeviceSpec> const& deviceSpecs, std::vector<DeviceExecution>& deviceExecutions, @@ -883,20 +1024,16 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, /// Lookup the executable name in the metadata associated with the workflow. /// If we find it, we rewrite the command line arguments to be processed /// so that they look like the ones passed to the merged workflow. - for (auto& processorInfo : processorInfos) { - if (processorInfo.name == spec.id) { - argc = processorInfo.cmdLineArgs.size() + 1; - argv = (char**)malloc(sizeof(char**) * (argc + 1)); - argv[0] = strdup(processorInfo.executable.data()); - for (size_t ai = 0; ai < processorInfo.cmdLineArgs.size(); ++ai) { - auto& arg = processorInfo.cmdLineArgs[ai]; - argv[ai + 1] = strdup(arg.data()); - } - argv[argc] = nullptr; - workflowOptions = processorInfo.workflowOptions; - break; - } + auto pi = std::find_if(processorInfos.begin(), processorInfos.end(), [&](auto const& x) { return x.name == spec.id; }); + argc = pi->cmdLineArgs.size() + 1; + argv = (char**)malloc(sizeof(char**) * (argc + 1)); + argv[0] = strdup(pi->executable.data()); + for (size_t ai = 0; ai < pi->cmdLineArgs.size(); ++ai) { + auto const& arg = pi->cmdLineArgs[ai]; + argv[ai + 1] = strdup(arg.data()); } + argv[argc] = nullptr; + workflowOptions = pi->workflowOptions; // We duplicate the list of options, filtering only those // which are actually relevant for the given device. The additional @@ -940,6 +1077,7 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, // has option --session been specified on the command line? bool haveSessionArg = false; using FilterFunctionT = std::function<void(decltype(argc), decltype(argv), decltype(od))>; + bool useDefaultWS = true; // the filter function will forward command line arguments based on the option // definition passed to it. All options of the program option definition will be forwarded @@ -961,6 +1099,17 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, split(environment, tmpEnv); } + /// Add libSegFault to the stack if provided. + if (varmap.count("stacktrace-on-signal") && varmap["stacktrace-on-signal"].as<std::string>() != "none") { + char const* preload = getenv("LD_PRELOAD"); + if (preload == nullptr || strcmp(preload, "libSegFault.so") == 0) { + tmpEnv.push_back("LD_PRELOAD=libSegFault.so"); + } else { + tmpEnv.push_back(fmt::format("LD_PRELOAD=\"{}:libSegFault.so\"", preload)); + } + tmpEnv.push_back(fmt::format("SEGFAULT_SIGNALS=\"{}\"", varmap["stacktrace-on-signal"].as<std::string>())); + } + // options can be grouped per processor spec, the group is entered by // the option created from the actual processor spec name // if specified, the following string is interpreted as a sequence @@ -976,14 +1125,19 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, realOdesc.add_options()("severity", bpo::value<std::string>()); realOdesc.add_options()("child-driver", bpo::value<std::string>()); realOdesc.add_options()("rate", bpo::value<std::string>()); + realOdesc.add_options()("expected-region-callbacks", bpo::value<std::string>()); realOdesc.add_options()("environment", bpo::value<std::string>()); + realOdesc.add_options()("stacktrace-on-signal", bpo::value<std::string>()); realOdesc.add_options()("post-fork-command", bpo::value<std::string>()); realOdesc.add_options()("shm-segment-size", bpo::value<std::string>()); realOdesc.add_options()("shm-mlock-segment", bpo::value<std::string>()); + realOdesc.add_options()("shm-mlock-segment-on-creation", bpo::value<std::string>()); realOdesc.add_options()("shm-zero-segment", bpo::value<std::string>()); realOdesc.add_options()("shm-throw-bad-alloc", bpo::value<std::string>()); realOdesc.add_options()("shm-segment-id", bpo::value<std::string>()); realOdesc.add_options()("shm-monitor", bpo::value<std::string>()); + realOdesc.add_options()("channel-prefix", bpo::value<std::string>()); + realOdesc.add_options()("network-interface", bpo::value<std::string>()); realOdesc.add_options()("session", bpo::value<std::string>()); filterArgsFct(expansions.we_wordc, expansions.we_wordv, realOdesc); wordfree(&expansions); @@ -999,6 +1153,20 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, } haveSessionArg = haveSessionArg || varmap.count("session") != 0; + useDefaultWS = useDefaultWS && ((varmap.count("driver-client-backend") == 0) || varmap["driver-client-backend"].as<std::string>() == "ws://"); + + auto processRawChannelConfig = [&tmpArgs](const std::string& conf) { + std::stringstream ss(conf); + std::string token; + while (std::getline(ss, token, ';')) { // split to tokens, trim spaces and add each non-empty one with channel-config options + token.erase(token.begin(), std::find_if(token.begin(), token.end(), [](int ch) { return !std::isspace(ch); })); + token.erase(std::find_if(token.rbegin(), token.rend(), [](int ch) { return !std::isspace(ch); }).base(), token.end()); + if (!token.empty()) { + tmpArgs.emplace_back("--channel-config"); + tmpArgs.emplace_back(token); + } + } + }; for (const auto varit : varmap) { // find the option belonging to key, add if the option has been parsed @@ -1015,10 +1183,14 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, assert(semantic->min_tokens() <= 1); //assert(semantic->max_tokens() && semantic->min_tokens()); if (semantic->min_tokens() > 0) { - tmpArgs.emplace_back("--"); - tmpArgs.back() += varit.first; - // add the token - tmpArgs.emplace_back(varit.second.as<std::string>()); + if (varit.first == "channel-config") { + processRawChannelConfig(varit.second.as<std::string>()); + } else { + tmpArgs.emplace_back("--"); + tmpArgs.back() += varit.first; + // add the token + tmpArgs.emplace_back(varit.second.as<std::string>()); + } optarg = tmpArgs.back().c_str(); } else if (semantic->min_tokens() == 0 && varit.second.as<bool>()) { tmpArgs.emplace_back("--"); @@ -1050,6 +1222,16 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, tmpArgs.emplace_back(std::string("--session")); tmpArgs.emplace_back("dpl_" + uniqueWorkflowId); } + // In case we use only ws://, we need to expand the address + // with the correct port. + if (useDefaultWS) { + auto it = std::find(tmpArgs.begin(), tmpArgs.end(), "--driver-client-backend"); + if ((it != tmpArgs.end()) && (it + 1 != tmpArgs.end())) { + tmpArgs.erase(it, it + 2); + } + tmpArgs.emplace_back(std::string("--driver-client-backend")); + tmpArgs.emplace_back("ws://0.0.0.0:" + std::to_string(driverPort)); + } if (spec.resourceMonitoringInterval > 0) { tmpArgs.emplace_back(std::string("--resources-monitoring")); @@ -1087,26 +1269,33 @@ boost::program_options::options_description DeviceSpecHelpers::getForwardedDevic // - rate is an option of FairMQ device for ConditionalRun // - child-driver is not a FairMQ device option but used per device to start to process bpo::options_description forwardedDeviceOptions; - forwardedDeviceOptions.add_options() // - ("severity", bpo::value<std::string>()->default_value("info"), "severity level of the log") // - ("plugin,P", bpo::value<std::string>(), "FairMQ plugin list") // - ("plugin-search-path,S", bpo::value<std::string>(), "FairMQ plugins search path") // - ("control-port", bpo::value<std::string>(), "Utility port to be used by O2 Control") // - ("rate", bpo::value<std::string>(), "rate for a data source device (Hz)") // - ("shm-monitor", bpo::value<std::string>(), "whether to use the shared memory monitor") // - ("shm-segment-size", bpo::value<std::string>(), "size of the shared memory segment in bytes") // - ("shm-mlock-segment", bpo::value<std::string>()->default_value("false"), "mlock shared memory segment") // - ("shm-zero-segment", bpo::value<std::string>()->default_value("false"), "zero shared memory segment") // - ("shm-throw-bad-alloc", bpo::value<std::string>()->default_value("true"), "throw if insufficient shm memory") // - ("shm-segment-id", bpo::value<std::string>()->default_value("0"), "shm segment id") // - ("environment", bpo::value<std::string>(), "comma separated list of environment variables to set for the device") // - ("post-fork-command", bpo::value<std::string>(), "post fork command to execute (e.g. numactl {pid}") // - ("session", bpo::value<std::string>(), "unique label for the shared memory session") // - ("configuration,cfg", bpo::value<std::string>(), "configuration connection string") // - ("monitoring-backend", bpo::value<std::string>(), "monitoring connection string") // - ("infologger-mode", bpo::value<std::string>(), "INFOLOGGER_MODE override") // - ("infologger-severity", bpo::value<std::string>(), "minimun FairLogger severity which goes to info logger") // - ("child-driver", bpo::value<std::string>(), "external driver to start childs with (e.g. valgrind)"); // + forwardedDeviceOptions.add_options() // + ("severity", bpo::value<std::string>()->default_value("info"), "severity level of the log") // + ("plugin,P", bpo::value<std::string>(), "FairMQ plugin list") // + ("plugin-search-path,S", bpo::value<std::string>(), "FairMQ plugins search path") // + ("control-port", bpo::value<std::string>(), "Utility port to be used by O2 Control") // + ("rate", bpo::value<std::string>(), "rate for a data source device (Hz)") // + ("expected-region-callbacks", bpo::value<std::string>(), "region callbacks to expect before starting") // + ("shm-monitor", bpo::value<std::string>(), "whether to use the shared memory monitor") // + ("channel-prefix", bpo::value<std::string>()->default_value(""), "prefix to use for multiplexing multiple workflows in the same session") // + ("shm-segment-size", bpo::value<std::string>(), "size of the shared memory segment in bytes") // + ("shm-mlock-segment", bpo::value<std::string>()->default_value("false"), "mlock shared memory segment") // + ("shm-mlock-segment-on-creation", bpo::value<std::string>()->default_value("false"), "mlock shared memory segment once on creation") // + ("shm-zero-segment", bpo::value<std::string>()->default_value("false"), "zero shared memory segment") // + ("shm-throw-bad-alloc", bpo::value<std::string>()->default_value("true"), "throw if insufficient shm memory") // + ("shm-segment-id", bpo::value<std::string>()->default_value("0"), "shm segment id") // + ("environment", bpo::value<std::string>(), "comma separated list of environment variables to set for the device") // + ("stacktrace-on-signal", bpo::value<std::string>()->default_value("all"), // + "dump stacktrace on specified signal(s) (any of `all`, `segv`, `bus`, `ill`, `abrt`, `fpe`, `sys`.)") // + ("post-fork-command", bpo::value<std::string>(), "post fork command to execute (e.g. numactl {pid}") // + ("session", bpo::value<std::string>(), "unique label for the shared memory session") // + ("network-interface", bpo::value<std::string>(), "network interface to which to bind tpc fmq ports without specified address") // + ("configuration,cfg", bpo::value<std::string>(), "configuration connection string") // + ("driver-client-backend", bpo::value<std::string>(), "driver connection string") // + ("monitoring-backend", bpo::value<std::string>(), "monitoring connection string") // + ("infologger-mode", bpo::value<std::string>(), "O2_INFOLOGGER_MODE override") // + ("infologger-severity", bpo::value<std::string>(), "minimun FairLogger severity which goes to info logger") // + ("child-driver", bpo::value<std::string>(), "external driver to start childs with (e.g. valgrind)"); // return forwardedDeviceOptions; } diff --git a/Framework/Core/src/DeviceSpecHelpers.h b/Framework/Core/src/DeviceSpecHelpers.h index a37c70471e12f..b9deaa3209bce 100644 --- a/Framework/Core/src/DeviceSpecHelpers.h +++ b/Framework/Core/src/DeviceSpecHelpers.h @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_DEVICESPECHELPERS_H -#define FRAMEWORK_DEVICESPECHELPERS_H +#ifndef O2_FRAMEWORK_DEVICESPECHELPERS_H_ +#define O2_FRAMEWORK_DEVICESPECHELPERS_H_ #include "Framework/WorkflowSpec.h" #include "Framework/ChannelConfigurationPolicy.h" @@ -22,18 +23,17 @@ #include "Framework/AlgorithmSpec.h" #include "Framework/ConfigParamSpec.h" #include "Framework/OutputRoute.h" +#include "Framework/DataProcessorInfo.h" #include "ResourceManager.h" -#include "DataProcessorInfo.h" #include "WorkflowHelpers.h" #include <boost/program_options.hpp> #include <vector> #include <string> #include <map> +#include <functional> -namespace o2 -{ -namespace framework +namespace o2::framework { struct InputChannelSpec; struct OutputChannelSpec; @@ -46,11 +46,13 @@ struct DeviceSpecHelpers { std::vector<ChannelConfigurationPolicy> const& channelPolicies, std::vector<CompletionPolicy> const& completionPolicies, std::vector<DispatchPolicy> const& dispatchPolicies, + std::vector<ResourcePolicy> const& resourcePolicies, std::vector<DeviceSpec>& devices, ResourceManager& resourceManager, std::string const& uniqueWorkflowId, bool optimizeTopology = false, - unsigned short resourcesMonitoringInterval = 0); + unsigned short resourcesMonitoringInterval = 0, + std::string const& channelPrefix = ""); static void dataProcessorSpecs2DeviceSpecs( const WorkflowSpec& workflow, @@ -60,11 +62,15 @@ struct DeviceSpecHelpers { ResourceManager& resourceManager, std::string const& uniqueWorkflowId, bool optimizeTopology = false, - unsigned short resourcesMonitoringInterval = 0) + unsigned short resourcesMonitoringInterval = 0, + std::string const& channelPrefix = "") { std::vector<DispatchPolicy> dispatchPolicies = DispatchPolicy::createDefaultPolicies(); + std::vector<ResourcePolicy> resourcePolicies = ResourcePolicy::createDefaultPolicies(); dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, - dispatchPolicies, devices, resourceManager, uniqueWorkflowId, optimizeTopology, resourcesMonitoringInterval); + dispatchPolicies, resourcePolicies, devices, + resourceManager, uniqueWorkflowId, optimizeTopology, + resourcesMonitoringInterval, channelPrefix); } /// Helper to provide the channel configuration string for an input channel @@ -73,7 +79,26 @@ struct DeviceSpecHelpers { /// Helper to provide the channel configuration string for an output channel static std::string outputChannel2String(const OutputChannelSpec& channel); - /// Rework the infos so that they have a consisten --shm-section-size + /// Rework a given command line option so that all the sub workflows + /// either have the same value, or they leave it unspecified. + /// @a infos the DataProcessorInfos to modify + /// @a name of the option to modify, including -- + /// @a defaultValue the default value for the option. If default is nullptr, not finding the + /// option will not not add a default value. + static void reworkHomogeneousOption(std::vector<DataProcessorInfo>& infos, + char const* name, char const* defaultValue); + + /// Rework a given command line option so that we pick the largest value + /// which has been specified or a default one. + /// @a defaultValueCallback a callback which returns the default value, if nullptr, the option + /// will not be added. + /// @a bestValue given to possible values of the option, return the one which should be used. + static void reworkIntegerOption(std::vector<DataProcessorInfo>& infos, + char const* name, + std::function<long long()> defaultValueCallback, + long long startValue, + std::function<long long(long long, long long)> bestValue); + /// Rework the infos so that they have a consistent --shm-section-size /// which is the maximum of the specified value. static void reworkShmSegmentSize(std::vector<DataProcessorInfo>& infos); /// Helper to prepare the arguments which will be used to @@ -81,6 +106,7 @@ struct DeviceSpecHelpers { static void prepareArguments( bool defaultQuiet, bool defaultStopped, + unsigned short driverPort, std::vector<DataProcessorInfo> const& processorInfos, std::vector<DeviceSpec> const& deviceSpecs, std::vector<DeviceExecution>& deviceExecutions, @@ -102,6 +128,7 @@ struct DeviceSpecHelpers { const WorkflowSpec& workflow, const std::vector<OutputSpec>& outputs, std::vector<ChannelConfigurationPolicy> const& channelPolicies, + std::string const& channelPrefix, ComputingOffer const& defaultOffer); /// This takes the list of preprocessed edges of a graph @@ -119,6 +146,7 @@ struct DeviceSpecHelpers { const WorkflowSpec& workflow, const std::vector<LogicalForwardInfo>& availableForwardsInfo, std::vector<ChannelConfigurationPolicy> const& channelPolicies, + std::string const& channelPrefix, ComputingOffer const& defaultOffer); /// return a description of all options to be forwarded to the device @@ -126,6 +154,5 @@ struct DeviceSpecHelpers { static boost::program_options::options_description getForwardedDeviceOptions(); }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_DEVICESPECHELPERS_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_DEVICESPECHELPERS_H_ diff --git a/Framework/Core/src/DevicesManager.cxx b/Framework/Core/src/DevicesManager.cxx new file mode 100644 index 0000000000000..8e8635d6e8334 --- /dev/null +++ b/Framework/Core/src/DevicesManager.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DevicesManager.h" +#include "Framework/RuntimeError.h" +#include "Framework/Logger.h" +#include "Framework/DeviceController.h" + +namespace o2::framework +{ + +void DevicesManager::queueMessage(char const* target, char const* message) +{ + for (int di = 0; di < specs.size(); ++di) { + if (specs[di].id == target) { + messages.push_back({di, message}); + } + } +} + +void DevicesManager::flush() +{ + static bool notifiedUnavailable = false; + static bool notifiedAvailable = false; + for (auto& handle : messages) { + auto controller = controls[handle.ref.index].controller; + // Device might not be started yet, by the time we write to it. + if (!controller) { + if (!notifiedUnavailable) { + LOGP(INFO, "Controller for {} not yet available.", specs[handle.ref.index].id); + notifiedUnavailable = true; + } + continue; + } + if (notifiedUnavailable && !notifiedAvailable) { + LOGP(INFO, "Controller for {} now available.", specs[handle.ref.index].id); + notifiedAvailable = true; + } + controller->write(handle.message.c_str(), handle.message.size()); + } + + auto checkIfController = [this](DeviceMessageHandle const& handle) { + return this->controls[handle.ref.index].controller != nullptr; + }; + auto it = std::remove_if(messages.begin(), messages.end(), checkIfController); + auto r = std::distance(it, messages.end()); + messages.erase(it, messages.end()); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DispatchPolicy.cxx b/Framework/Core/src/DispatchPolicy.cxx index 9baea731a56f4..56323cabfa669 100644 --- a/Framework/Core/src/DispatchPolicy.cxx +++ b/Framework/Core/src/DispatchPolicy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,6 +26,11 @@ std::vector<DispatchPolicy> DispatchPolicy::createDefaultPolicies() return {DispatchPolicy{"dispatch-all-after-computation", [](DeviceSpec const&) { return true; }, DispatchPolicy::DispatchOp::AfterComputation}}; } +DispatchPolicy::TriggerMatcher DispatchPolicy::defaultDispatchPolicy() +{ + return DispatchPolicy::TriggerMatcher{[](Output const&) -> bool { return true; }}; +} + std::ostream& operator<<(std::ostream& oss, DispatchPolicy::DispatchOp const& val) { switch (val) { diff --git a/Framework/Core/src/DriverClient.cxx b/Framework/Core/src/DriverClient.cxx new file mode 100644 index 0000000000000..54710dede609c --- /dev/null +++ b/Framework/Core/src/DriverClient.cxx @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DriverClient.h" +#include <regex> + +namespace o2::framework +{ + +void DriverClient::observe(const char* eventPrefix, std::function<void(std::string_view)> callback) +{ + mEventMatchers.push_back({eventPrefix, callback}); +} + +void DriverClient::dispatch(std::string_view event) +{ + for (auto& handle : mEventMatchers) { + if (event.rfind(handle.prefix, 0) == 0) { + handle.callback(event); + } + } +} + +} // namespace o2::framework diff --git a/Framework/Core/src/DriverClientContext.h b/Framework/Core/src/DriverClientContext.h new file mode 100644 index 0000000000000..bf3b9cfc7cbf4 --- /dev/null +++ b/Framework/Core/src/DriverClientContext.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// Helper struct which holds all the lists the Driver needs to know about. +#ifndef O2_FRAMEWORK_DRIVERCLIENTCONTEXT_H_ +#define O2_FRAMEWORK_DRIVERCLIENTCONTEXT_H_ + +namespace o2::framework +{ +struct DeviceSpec; +struct DeviceState; +struct WSDPLClient; + +/// Context for the client callbacks +struct DriverClientContext { + DeviceSpec const& spec; + DeviceState* state = nullptr; + WSDPLClient* client = nullptr; +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DRIVERCLIENTCONTEXT_H_ diff --git a/Framework/Core/src/DriverControl.cxx b/Framework/Core/src/DriverControl.cxx index e36ec3c49c0c4..4ff9a49525add 100644 --- a/Framework/Core/src/DriverControl.cxx +++ b/Framework/Core/src/DriverControl.cxx @@ -1,10 +1,11 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DriverControl.h" +#include "Framework/DriverControl.h" diff --git a/Framework/Core/src/DriverInfo.cxx b/Framework/Core/src/DriverInfo.cxx index 8df33b8452a83..7a128efd66ef3 100644 --- a/Framework/Core/src/DriverInfo.cxx +++ b/Framework/Core/src/DriverInfo.cxx @@ -1,10 +1,30 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DriverInfo.h" +#include "Framework/DriverInfo.h" + +char const* o2::framework::DriverInfoHelper::stateToString(enum DriverState state) +{ + static const char* names[static_cast<int>(DriverState::LAST)] = { + "INIT", // + "SCHEDULE", // + "RUNNING", // + "REDEPLOY_GUI", // + "QUIT_REQUESTED", // + "HANDLE_CHILDREN", // + "EXIT", // + "UNKNOWN", // + "PERFORM_CALLBACKS", // + "MATERIALISE_WORKFLOW", // + "IMPORT_CURRENT_WORKFLOW", // + "DO_CHILD" // + }; + return names[static_cast<int>(state)]; +} diff --git a/Framework/Core/src/DriverServerContext.h b/Framework/Core/src/DriverServerContext.h new file mode 100644 index 0000000000000..6e9526d11b4f6 --- /dev/null +++ b/Framework/Core/src/DriverServerContext.h @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// Helper struct which holds all the lists the Driver needs to know about. +#ifndef O2_FRAMEWORK_DRIVERSERVERCONTEXT_H_ +#define O2_FRAMEWORK_DRIVERSERVERCONTEXT_H_ + +#include "Framework/DeviceInfo.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DeviceControl.h" +#include "Framework/DeviceMetricsInfo.h" +#include "Framework/ServiceSpec.h" + +#include <uv.h> +#include <vector> + +namespace o2::framework +{ +struct DriverInfo; +struct ServiceRegistry; + +struct DriverServerContext { + uv_loop_t* loop; + ServiceRegistry* registry = nullptr; + std::vector<DeviceControl>* controls = nullptr; + std::vector<DeviceInfo>* infos = nullptr; + std::vector<DeviceSpec>* specs = nullptr; + std::vector<DeviceMetricsInfo>* metrics = nullptr; + std::vector<ServiceMetricHandling>* metricProcessingCallbacks; + DriverInfo* driver; +}; +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DRIVERSERVERCONTEXT_H_ diff --git a/Framework/Core/src/ExpressionHelpers.h b/Framework/Core/src/ExpressionHelpers.h deleted file mode 100644 index 2d3f9cb704029..0000000000000 --- a/Framework/Core/src/ExpressionHelpers.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ -#define O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ -#include "Framework/Expressions.h" - -#include <vector> -#include <iosfwd> -#include <fmt/format.h> - -namespace o2::framework::expressions -{ -/// a map between BasicOp and gandiva node definitions -/// note that logical 'and' and 'or' are created separately -static std::array<std::string, BasicOp::Abs + 1> binaryOperationsMap = { - "and", - "or", - "add", - "subtract", - "divide", - "multiply", - "less_than", - "less_than_or_equal_to", - "greater_than", - "greater_than_or_equal_to", - "equal", - "not_equal", - "powerf", - "sqrtf", - "expf", - "logf", - "log10f", - "sinf", - "cosf", - "tanf", - "asinf", - "acosf", - "atanf", - "absf"}; - -struct DatumSpec { - /// datum spec either contains an index, a value of a literal or a binding label - using datum_t = std::variant<std::monostate, size_t, LiteralNode::var_t, std::string>; - datum_t datum = std::monostate{}; - atype::type type = atype::NA; - explicit DatumSpec(size_t index, atype::type type_) : datum{index}, type{type_} {} - explicit DatumSpec(LiteralNode::var_t literal, atype::type type_) : datum{literal}, type{type_} {} - explicit DatumSpec(std::string binding, atype::type type_) : datum{binding}, type{type_} {} - DatumSpec() = default; - DatumSpec(DatumSpec const&) = default; - DatumSpec(DatumSpec&&) = default; - DatumSpec& operator=(DatumSpec const&) = default; - DatumSpec& operator=(DatumSpec&&) = default; -}; - -bool operator==(DatumSpec const& lhs, DatumSpec const& rhs); - -std::ostream& operator<<(std::ostream& os, DatumSpec const& spec); - -struct ColumnOperationSpec { - BasicOp op; - DatumSpec left; - DatumSpec right; - DatumSpec result; - atype::type type = atype::NA; - ColumnOperationSpec() = default; - // TODO: extend this to support unary ops seamlessly - explicit ColumnOperationSpec(BasicOp op_) : op{op_}, - left{}, - right{}, - result{} - { - switch (op) { - case BasicOp::LogicalOr: - case BasicOp::LogicalAnd: - case BasicOp::LessThan: - case BasicOp::LessThanOrEqual: - case BasicOp::GreaterThan: - case BasicOp::GreaterThanOrEqual: - case BasicOp::Equal: - case BasicOp::NotEqual: - type = atype::BOOL; - break; - case BasicOp::Division: - type = atype::FLOAT; - default: - type = atype::NA; - } - result.type = type; - } -}; - -/// helper struct used to parse trees -struct NodeRecord { - /// pointer to the actual tree node - Node* node_ptr = nullptr; - size_t index = 0; - explicit NodeRecord(Node* node_, size_t index_) : node_ptr(node_), index{index_} {} -}; -} // namespace o2::framework::expressions - -#endif // O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ diff --git a/Framework/Core/src/Expressions.cxx b/Framework/Core/src/Expressions.cxx index 94f63dd75353b..0d19e21a1eacb 100644 --- a/Framework/Core/src/Expressions.cxx +++ b/Framework/Core/src/Expressions.cxx @@ -1,14 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "../src/ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "Framework/VariantHelpers.h" #include "Framework/Logger.h" #include "Framework/RuntimeError.h" @@ -25,31 +26,61 @@ using namespace o2::framework; namespace o2::framework::expressions { + +size_t Filter::designateSubtrees(Node* node, size_t index) +{ + std::stack<NodeRecord> path; + auto local_index = index; + path.emplace(node, 0); + + while (path.empty() == false) { + auto& top = path.top(); + top.node_ptr->index = local_index; + path.pop(); + if (top.node_ptr->condition != nullptr) { + // start new subtrees + index = designateSubtrees(top.node_ptr->left.get(), local_index + 1); + index = designateSubtrees(top.node_ptr->condition.get(), index + 1); + index = designateSubtrees(top.node_ptr->right.get(), index + 1); + } else { + // continue current subtree + if (top.node_ptr->left != nullptr) { + path.emplace(top.node_ptr->left.get(), 0); + } + if (top.node_ptr->right != nullptr) { + path.emplace(top.node_ptr->right.get(), 0); + } + } + } + + return index; +} + namespace { struct LiteralNodeHelper { - DatumSpec operator()(LiteralNode node) const + DatumSpec operator()(LiteralNode const& node) const { return DatumSpec{node.value, node.type}; } }; struct BindingNodeHelper { - DatumSpec operator()(BindingNode node) const + DatumSpec operator()(BindingNode const& node) const { - return DatumSpec{node.name, node.type}; + return DatumSpec{node.name, node.hash, node.type}; } }; struct OpNodeHelper { - ColumnOperationSpec operator()(OpNode node) const + ColumnOperationSpec operator()(OpNode const& node) const { return ColumnOperationSpec{node.op}; } }; struct PlaceholderNodeHelper { - DatumSpec operator()(PlaceholderNode node) const + DatumSpec operator()(PlaceholderNode const& node) const { return DatumSpec{node.value, node.type}; } @@ -65,8 +96,16 @@ std::shared_ptr<arrow::DataType> concreteArrowType(atype::type type) return arrow::int8(); case atype::INT16: return arrow::int16(); + case atype::UINT16: + return arrow::uint16(); case atype::INT32: return arrow::int32(); + case atype::UINT32: + return arrow::uint32(); + case atype::INT64: + return arrow::int64(); + case atype::UINT64: + return arrow::uint64(); case atype::FLOAT: return arrow::float32(); case atype::DOUBLE: @@ -128,31 +167,24 @@ void updatePlaceholders(Filter& filter, InitContext& context) } }; - auto isLeaf = [](Node const* const node) { - return ((node->left == nullptr) && (node->right == nullptr)); - }; - // while the stack is not empty while (path.empty() == false) { auto& top = path.top(); - updateNode(top.node_ptr); + auto* leftp = top.node_ptr->left.get(); + auto* rightp = top.node_ptr->right.get(); + auto* condp = top.node_ptr->condition.get(); path.pop(); - if (top.node_ptr->left != nullptr) { - if (isLeaf(top.node_ptr->left.get())) { - updateNode(top.node_ptr->left.get()); - } else { - path.emplace(top.node_ptr->left.get(), 0); - } + if (leftp != nullptr) { + path.emplace(leftp, 0); } - if (top.node_ptr->right != nullptr) { - if (isLeaf(top.node_ptr->right.get())) { - updateNode(top.node_ptr->right.get()); - } else { - path.emplace(top.node_ptr->right.get(), 0); - } + if (rightp != nullptr) { + path.emplace(rightp, 0); + } + if (condp != nullptr) { + path.emplace(condp, 0); } } } @@ -168,9 +200,9 @@ Operations createOperations(Filter const& expression) auto processLeaf = [](Node const* const node) { return std::visit( overloaded{ - [lh = LiteralNodeHelper{}](LiteralNode node) { return lh(node); }, - [bh = BindingNodeHelper{}](BindingNode node) { return bh(node); }, - [ph = PlaceholderNodeHelper{}](PlaceholderNode node) { return ph(node); }, + [lh = LiteralNodeHelper{}](LiteralNode const& node) { return lh(node); }, + [bh = BindingNodeHelper{}](BindingNode const& node) { return bh(node); }, + [ph = PlaceholderNodeHelper{}](PlaceholderNode const& node) { return ph(node); }, [](auto&&) { return DatumSpec{}; }}, node->self); }; @@ -187,14 +219,15 @@ Operations createOperations(Filter const& expression) auto operationSpec = std::visit( overloaded{ - [](OpNode node) { return ColumnOperationSpec{node.op}; }, + [&](OpNode node) { return ColumnOperationSpec{node.op, top.node_ptr->index}; }, + [&](ConditionalNode) { return ColumnOperationSpec{BasicOp::Conditional, top.node_ptr->index}; }, [](auto&&) { return ColumnOperationSpec{}; }}, top.node_ptr->self); operationSpec.result = DatumSpec{top.index, operationSpec.type}; path.pop(); - auto left = top.node_ptr->left.get(); + auto* left = top.node_ptr->left.get(); bool leftLeaf = isLeaf(left); size_t li = 0; if (leftLeaf) { @@ -226,6 +259,23 @@ Operations createOperations(Filter const& expression) } } + decltype(left) condition = nullptr; + if (top.node_ptr->condition != nullptr) { + condition = top.node_ptr->condition.get(); + } + bool condleaf = condition != nullptr ? isLeaf(condition) : true; + size_t ci = 0; + if (condition != nullptr) { + if (condleaf) { + operationSpec.condition = processLeaf(condition); + } else { + ci = index; + operationSpec.condition = DatumSpec{index++, atype::BOOL}; + } + } else { + operationSpec.condition = DatumSpec{}; + } + OperationSpecs.push_back(std::move(operationSpec)); if (!leftLeaf) { path.emplace(left, li); @@ -233,6 +283,9 @@ Operations createOperations(Filter const& expression) if (!isUnary && !rightLeaf) { path.emplace(right, ri); } + if (!condleaf) { + path.emplace(condition, ci); + } } // at this stage the operations vector is created, but the field types are // only set for the logical operations and leaf nodes @@ -268,19 +321,26 @@ Operations createOperations(Filter const& expression) return t1; } - if (t1 == atype::INT32 || t1 == atype::INT8 || t1 == atype::INT16 || t1 == atype::UINT8) { - if (t2 == atype::INT32 || t2 == atype::INT8 || t2 == atype::INT16 || t2 == atype::UINT8) { - return atype::FLOAT; - } + auto isIntType = [](auto t) { + return (t == atype::UINT8) || (t == atype::INT8) || (t == atype::UINT16) || (t == atype::INT16) || (t == atype::UINT32) || (t == atype::INT32) || (t == atype::UINT64) || (t == atype::INT64); + }; + + if (isIntType(t1)) { if (t2 == atype::FLOAT) { return atype::FLOAT; } if (t2 == atype::DOUBLE) { return atype::DOUBLE; } + if (isIntType(t2)) { + if (t1 > t2) { + return t1; + } + return t2; + } } if (t1 == atype::FLOAT) { - if (t2 == atype::INT32 || t2 == atype::INT8 || t2 == atype::INT16 || t2 == atype::UINT8) { + if (isIntType(t2)) { return atype::FLOAT; } if (t2 == atype::DOUBLE) { @@ -298,6 +358,7 @@ Operations createOperations(Filter const& expression) if (it->type == atype::NA) { it->type = type; } + it->result.type = it->type; resultTypes[std::get<size_t>(it->result.datum)] = it->type; } @@ -307,12 +368,12 @@ Operations createOperations(Filter const& expression) gandiva::ConditionPtr makeCondition(gandiva::NodePtr node) { - return gandiva::TreeExprBuilder::MakeCondition(node); + return gandiva::TreeExprBuilder::MakeCondition(std::move(node)); } gandiva::ExpressionPtr makeExpression(gandiva::NodePtr node, gandiva::FieldPtr result) { - return gandiva::TreeExprBuilder::MakeExpression(node, result); + return gandiva::TreeExprBuilder::MakeExpression(std::move(node), std::move(result)); } std::shared_ptr<gandiva::Filter> @@ -333,7 +394,7 @@ std::shared_ptr<gandiva::Filter> { std::shared_ptr<gandiva::Filter> filter; auto s = gandiva::Filter::Make(Schema, - condition, + std::move(condition), &filter); if (!s.ok()) { throw runtime_error_f("Failed to create filter: %s", s.ToString().c_str()); @@ -346,7 +407,7 @@ std::shared_ptr<gandiva::Projector> { std::shared_ptr<gandiva::Projector> projector; auto s = gandiva::Projector::Make(Schema, - {makeExpression(createExpressionTree(opSpecs, Schema), result)}, + {makeExpression(createExpressionTree(opSpecs, Schema), std::move(result))}, &projector); if (!s.ok()) { throw runtime_error_f("Failed to create projector: %s", s.ToString().c_str()); @@ -357,10 +418,10 @@ std::shared_ptr<gandiva::Projector> std::shared_ptr<gandiva::Projector> createProjector(gandiva::SchemaPtr const& Schema, Projector&& p, gandiva::FieldPtr result) { - return createProjector(std::move(Schema), createOperations(std::move(p)), std::move(result)); + return createProjector(Schema, createOperations(p), std::move(result)); } -Selection createSelection(std::shared_ptr<arrow::Table> table, std::shared_ptr<gandiva::Filter> gfilter) +Selection createSelection(std::shared_ptr<arrow::Table> const& table, std::shared_ptr<gandiva::Filter> gfilter) { Selection selection; auto s = gandiva::SelectionVector::MakeInt64(table->num_rows(), @@ -391,13 +452,13 @@ Selection createSelection(std::shared_ptr<arrow::Table> table, std::shared_ptr<g return selection; } -Selection createSelection(std::shared_ptr<arrow::Table> table, - const Filter& expression) +Selection createSelection(std::shared_ptr<arrow::Table> const& table, + Filter const& expression) { return createSelection(table, createFilter(table->schema(), createOperations(std::move(expression)))); } -auto createProjection(std::shared_ptr<arrow::Table> table, std::shared_ptr<gandiva::Projector> gprojector) +auto createProjection(std::shared_ptr<arrow::Table> const& table, std::shared_ptr<gandiva::Projector> const& gprojector) { arrow::TableBatchReader reader(*table); std::shared_ptr<arrow::RecordBatch> batch; @@ -425,6 +486,7 @@ gandiva::NodePtr createExpressionTree(Operations const& opSpecs, opNodes.resize(opSpecs.size()); std::fill(opNodes.begin(), opNodes.end(), nullptr); std::unordered_map<std::string, gandiva::NodePtr> fieldNodes; + std::unordered_map<size_t, gandiva::NodePtr> subtrees; auto datumNode = [Schema, &opNodes, &fieldNodes](DatumSpec const& spec) { if (spec.datum.index() == 0) { @@ -436,22 +498,32 @@ gandiva::NodePtr createExpressionTree(Operations const& opSpecs, if (spec.datum.index() == 2) { auto content = std::get<LiteralNode::var_t>(spec.datum); - if (content.index() == 0) { - return gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(std::get<int>(content))); - } - if (content.index() == 1) { - return gandiva::TreeExprBuilder::MakeLiteral(std::get<bool>(content)); - } - if (content.index() == 2) { - return gandiva::TreeExprBuilder::MakeLiteral(std::get<float>(content)); - } - if (content.index() == 3) { - return gandiva::TreeExprBuilder::MakeLiteral(std::get<double>(content)); + switch (content.index()) { + case 0: //int + return gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(std::get<int>(content))); + case 1: //bool + return gandiva::TreeExprBuilder::MakeLiteral(std::get<bool>(content)); + case 2: //float + return gandiva::TreeExprBuilder::MakeLiteral(std::get<float>(content)); + case 3: //double + return gandiva::TreeExprBuilder::MakeLiteral(std::get<double>(content)); + case 4: //uint8 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<uint8_t>(content)); + case 5: //int64 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<int64_t>(content)); + case 6: //int16 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<int16_t>(content)); + case 7: //uint16 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<uint16_t>(content)); + case 8: //int8 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<int8_t>(content)); + case 9: //uint32 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<uint32_t>(content)); + case 10: //uint64 + return gandiva::TreeExprBuilder::MakeLiteral(std::get<uint64_t>(content)); + default: + throw runtime_error("Malformed LiteralNode"); } - if (content.index() == 4) { - return gandiva::TreeExprBuilder::MakeLiteral(std::get<uint8_t>(content)); - } - throw runtime_error("Malformed LiteralNode"); } if (spec.datum.index() == 3) { @@ -475,6 +547,7 @@ gandiva::NodePtr createExpressionTree(Operations const& opSpecs, for (auto it = opSpecs.rbegin(); it != opSpecs.rend(); ++it) { auto leftNode = datumNode(it->left); auto rightNode = datumNode(it->right); + auto condNode = datumNode(it->condition); auto insertUpcastNode = [&](gandiva::NodePtr node, atype::type t) { if (t != it->type) { @@ -494,12 +567,17 @@ gandiva::NodePtr createExpressionTree(Operations const& opSpecs, } }; + gandiva::NodePtr temp_node; + switch (it->op) { case BasicOp::LogicalOr: - tree = gandiva::TreeExprBuilder::MakeOr({leftNode, rightNode}); + temp_node = gandiva::TreeExprBuilder::MakeOr({leftNode, rightNode}); break; case BasicOp::LogicalAnd: - tree = gandiva::TreeExprBuilder::MakeAnd({leftNode, rightNode}); + temp_node = gandiva::TreeExprBuilder::MakeAnd({leftNode, rightNode}); + break; + case BasicOp::Conditional: + temp_node = gandiva::TreeExprBuilder::MakeIf(condNode, leftNode, rightNode, concreteArrowType(it->type)); break; default: if (it->op < BasicOp::Sqrt) { @@ -509,19 +587,45 @@ gandiva::NodePtr createExpressionTree(Operations const& opSpecs, } else if (it->op == BasicOp::Equal || it->op == BasicOp::NotEqual) { insertEqualizeUpcastNode(leftNode, rightNode, it->left.type, it->right.type); } - tree = gandiva::TreeExprBuilder::MakeFunction(binaryOperationsMap[it->op], {leftNode, rightNode}, concreteArrowType(it->type)); + temp_node = gandiva::TreeExprBuilder::MakeFunction(basicOperationsMap[it->op], {leftNode, rightNode}, concreteArrowType(it->type)); } else { leftNode = insertUpcastNode(leftNode, it->left.type); - tree = gandiva::TreeExprBuilder::MakeFunction(binaryOperationsMap[it->op], {leftNode}, concreteArrowType(it->type)); + temp_node = gandiva::TreeExprBuilder::MakeFunction(basicOperationsMap[it->op], {leftNode}, concreteArrowType(it->type)); } break; } - opNodes[std::get<size_t>(it->result.datum)] = tree; + if (it->index == 0) { + tree = temp_node; + } else { + auto subtree = subtrees.find(it->index); + if (subtree == subtrees.end()) { + subtrees.insert({it->index, temp_node}); + } else { + subtree->second = temp_node; + } + } + opNodes[std::get<size_t>(it->result.datum)] = temp_node; } return tree; } +bool isTableCompatible(std::set<size_t> const& hashes, Operations const& specs) +{ + std::set<size_t> opHashes; + for (auto& spec : specs) { + if (spec.left.datum.index() == 3) { + opHashes.insert(spec.left.hash); + } + if (spec.right.datum.index() == 3) { + opHashes.insert(spec.right.hash); + } + } + + return std::includes(hashes.begin(), hashes.end(), + opHashes.begin(), opHashes.end()); +} + bool isSchemaCompatible(gandiva::SchemaPtr const& Schema, Operations const& opSpecs) { std::set<std::string> opFieldNames; @@ -550,7 +654,7 @@ void updateExpressionInfos(expressions::Filter const& filter, std::vector<Expres } Operations ops = createOperations(filter); for (auto& info : eInfos) { - if (isSchemaCompatible(info.schema, ops)) { + if (isTableCompatible(info.hashes, ops)) { auto tree = createExpressionTree(ops, info.schema); /// If the tree is already set, add a new tree to it with logical 'and' if (info.tree != nullptr) { diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 105b3b3acbc57..be34bde5aa2c1 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,10 +19,13 @@ #include "Framework/ProcessingContext.h" #include "Framework/RawDeviceService.h" #include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/SourceInfoHeader.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" #include "./DeviceSpecHelpers.h" +#include "./DataProcessingHelpers.h" #include <fairmq/FairMQParts.h> #include <fairmq/FairMQDevice.h> @@ -34,9 +38,7 @@ #include <sstream> #include <stdexcept> -namespace o2 -{ -namespace framework +namespace o2::framework { using DataHeader = o2::header::DataHeader; @@ -93,7 +95,8 @@ void sendOnChannel(FairMQDevice& device, FairMQParts& messages, std::string cons break; } } - if (timeout > 0 && timeout <= maxTimeout) { + // FIXME: we need a better logic for avoiding message spam + if (timeout > 1 && timeout <= maxTimeout) { LOG(WARNING) << "dispatching on channel " << channel << " was delayed by " << timeout << " ms"; } // TODO: feeling this is a bit awkward, but the interface of FairMQParts does not provide a @@ -214,29 +217,28 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, boo return [filterSpecs = std::move(filterSpecs), throwOnUnmatchedInputs, droppedDataSpecs = std::make_shared<DroppedDataSpecs>()](FairMQDevice& device, FairMQParts& parts, ChannelRetriever channelRetriever) { std::unordered_map<std::string, FairMQParts> outputs; - std::vector<bool> indicesDone(parts.Size() / 2, false); std::vector<std::string> unmatchedDescriptions; int lastSplitPartIndex = -1; std::string channelNameForSplitParts; + static int64_t dplCounter = -1; + dplCounter++; for (size_t msgidx = 0; msgidx < parts.Size() / 2; ++msgidx) { - if (indicesDone[msgidx]) { - continue; - } - const auto dh = o2::header::get<DataHeader*>(parts.At(msgidx * 2)->GetData()); if (!dh) { LOG(ERROR) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; continue; } - const auto dph = o2::header::get<DataProcessingHeader*>(parts.At(msgidx * 2)->GetData()); + auto dph = o2::header::get<DataProcessingHeader*>(parts.At(msgidx * 2)->GetData()); if (!dph) { LOG(ERROR) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; continue; } + const_cast<DataProcessingHeader*>(dph)->startTime = dplCounter; LOG(DEBUG) << msgidx << ": " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}) << " part " << dh->splitPayloadIndex << " of " << dh->splitPayloadParts << " payload " << parts.At(msgidx * 2 + 1)->GetSize(); OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification}; LOG(DEBUG) << "processing " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}) << " time slice " << dph->startTime << " part " << dh->splitPayloadIndex << " of " << dh->splitPayloadParts; + bool indexDone = false; for (auto const& spec : filterSpecs) { // filter on the specified OutputSpecs, the default value is a ConcreteDataTypeMatcher with origin and description 'any' if (DataSpecUtils::match(spec, OutputSpec{{header::gDataOriginAny, header::gDataDescriptionAny}}) || @@ -271,11 +273,11 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, boo outputs[channelName].AddPart(std::move(parts.At(msgidx * 2))); outputs[channelName].AddPart(std::move(parts.At(msgidx * 2 + 1))); LOG(DEBUG) << "associating part with index " << msgidx << " to channel " << channelName << " (" << outputs[channelName].Size() << ")"; - indicesDone[msgidx] = true; + indexDone = true; break; } } - if (indicesDone[msgidx] == false) { + if (indexDone == false && !DataSpecUtils::match(query, "DPL", "EOS", 0)) { unmatchedDescriptions.emplace_back(DataSpecUtils::describe(query)); } } @@ -356,6 +358,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, auto device = ctx.services().get<RawDeviceService>().device(); // make a copy of the output routes and pass to the lambda by move auto outputRoutes = ctx.services().get<RawDeviceService>().spec().outputs; + auto outputChannels = ctx.services().get<RawDeviceService>().spec().outputChannels; assert(device); // check that the name used for registering the OnData callback corresponds @@ -370,10 +373,11 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, } }; ctx.services().get<CallbackService>().set(CallbackService::Id::Start, channelConfigurationChecker); - // Converter should pump messages - auto handler = [device, converter, outputRoutes = std::move(outputRoutes)](FairMQParts& inputs, int) { - auto channelRetriever = [outputRoutes = std::move(outputRoutes)](OutputSpec const& query, DataProcessingHeader::StartTime timeslice) -> std::string { + + auto dataHandler = [device, converter, outputRoutes = std::move(outputRoutes), control = &ctx.services().get<ControlService>(), outputChannels = std::move(outputChannels)](FairMQParts& inputs, int) { + // pass a copy of the outputRoutes + auto channelRetriever = [&outputRoutes](OutputSpec const& query, DataProcessingHeader::StartTime timeslice) -> std::string { for (auto& route : outputRoutes) { LOG(DEBUG) << "matching: " << DataSpecUtils::describe(query) << " to route " << DataSpecUtils::describe(route.matcher); if (DataSpecUtils::match(route.matcher, query) && ((timeslice % route.maxTimeslices) == route.timeslice)) { @@ -382,12 +386,36 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, } return std::string(""); }; + + auto checkEos = [&inputs]() -> bool { + std::string channelNameForSplitParts; + for (size_t msgidx = 0; msgidx < inputs.Size() / 2; ++msgidx) { + auto const sih = o2::header::get<SourceInfoHeader*>(inputs.At(msgidx * 2)->GetData()); + if (sih != nullptr && sih->state == InputChannelState::Completed) { + return true; + } + } + return false; + }; + // we buffer the condition since the converter will forward messages by move + bool doEos = checkEos(); converter(*device, inputs, channelRetriever); - return true; + + if (doEos) { + for (auto const& channel : outputChannels) { + DataProcessingHelpers::sendEndOfStream(*device, channel); + } + control->readyToQuit(QuitRequest::Me); + } }; - device->OnData(channel, handler); - return [](ProcessingContext&) {}; + auto runHandler = [dataHandler, device, channel](ProcessingContext&) { + FairMQParts parts; + device->Receive(parts, channel, 0); + dataHandler(parts, 0); + }; + + return runHandler; }}; const char* d = strdup(((std::string(defaultChannelConfig).find("name=") == std::string::npos ? (std::string("name=") + name + ",") : "") + std::string(defaultChannelConfig)).c_str()); spec.options = { @@ -395,14 +423,12 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, return spec; } -namespace -{ +static char const* gDefaultChannel = "downstream"; // Decide where to sent the output. Everything to "downstream" if there is such a channel. -std::string decideChannel(InputSpec const& input, const std::unordered_map<std::string, std::vector<FairMQChannel>>& channels) +std::string defaultOutputProxyChannelSelector(InputSpec const& input, const std::unordered_map<std::string, std::vector<FairMQChannel>>& channels) { return channels.count("downstream") ? "downstream" : input.binding; } -} // namespace DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, Inputs const& inputSpecs, @@ -412,61 +438,190 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, spec.name = name; spec.inputs = inputSpecs; spec.outputs = {}; - spec.algorithm = adaptStateful([inputSpecs](CallbackService& callbacks, RawDeviceService& rds) { - auto device = rds.device(); + spec.algorithm = adaptStateful([inputSpecs](CallbackService& callbacks, RawDeviceService& rds, DeviceSpec const& deviceSpec) { + auto* device = rds.device(); // check that the input spec bindings have corresponding output channels // FairMQDevice calls the custom init before the channels have been configured // so we do the check before starting in a dedicated callback auto channelConfigurationChecker = [inputSpecs = std::move(inputSpecs), device]() { LOG(INFO) << "checking channel configuration"; - for (auto const& spec : inputSpecs) { - auto channel = decideChannel(spec, device->fChannels); - if (device->fChannels.count(channel) == 0) { - throw std::runtime_error("no corresponding output channel found for input '" + channel + "'"); - } + if (device->fChannels.count("downstream") == 0) { + throw std::runtime_error("no corresponding output channel found for input 'downstream'"); } }; callbacks.set(CallbackService::Id::Start, channelConfigurationChecker); - return adaptStateless([](RawDeviceService& rds, InputRecord& inputs) { - std::unordered_map<std::string, FairMQParts> outputs; - auto& device = *rds.device(); + auto lastDataProcessingHeader = std::make_shared<DataProcessingHeader>(0, 0); + + if (deviceSpec.forwards.size() > 0) { + // check that no internal forwards are existing, i.e. that proxy is at the end of the workflow + // in principle we can be less strict here if we check only for the defined input specs that there + // are no internal forwards + throw std::runtime_error("can not add forward targets outside DPL if internal forwards are existing, the proxy must be at the end of the workflow"); + } + for (auto const& inputSpec : inputSpecs) { + // this is a prototype, in principle we want to have all spec objects const + // and so only the const object can be retrieved from service registry + ForwardRoute route{0, 1, inputSpec, "downstream"}; + const_cast<DeviceSpec&>(deviceSpec).forwards.emplace_back(route); + } + + auto forwardEos = [device, lastDataProcessingHeader](EndOfStreamContext&) { + // DPL implements an internal end of stream signal, which is propagated through + // all downstream channels if a source is dry, make it available to other external + // devices via a message of type {DPL/EOS/0} + for (auto& channelInfo : device->fChannels) { + // FIXME: in this function the channel name is hardcoded to 'downstream' + // have to check if this simply should be combined with the function below + // supporting multiple outputs + auto& channelName = channelInfo.first; + if (channelName != "downstream") { + continue; + } + DataHeader dh; + dh.dataOrigin = "DPL"; + dh.dataDescription = "EOS"; + dh.subSpecification = 0; + dh.payloadSize = 0; + dh.payloadSerializationMethod = o2::header::gSerializationMethodNone; + dh.tfCounter = 0; + dh.firstTForbit = 0; + SourceInfoHeader sih; + sih.state = InputChannelState::Completed; + // allocate the header message using the underlying transport of the channel + auto channelAlloc = o2::pmr::getTransportAllocator(channelInfo.second[0].Transport()); + auto headerMessage = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, *lastDataProcessingHeader, sih}); + FairMQParts out; + out.AddPart(std::move(headerMessage)); + // add empty payload message + out.AddPart(std::move(device->NewMessageFor(channelName, 0, 0))); + sendOnChannel(*device, out, channelName); + } + }; + callbacks.set(CallbackService::Id::EndOfStream, forwardEos); + + return adaptStateless([lastDataProcessingHeader](RawDeviceService& rds, InputRecord& inputs) { for (size_t ii = 0; ii != inputs.size(); ++ii) { - auto first = inputs.getByPos(ii, 0); - // we could probably do something like this but we do not know when the message is going to be sent - // and if DPL is still owning a valid copy. - //auto headerMessage = device.NewMessageFor(input.spec->binding, input.header, headerMsgSize, [](void*, void*) {}); - - // Note: DPL is only setting up one instance of a channel while FairMQ allows to have an - // array of channels, the index is 0 in the call - constexpr auto index = 0; for (size_t pi = 0; pi < inputs.getNofParts(ii); ++pi) { auto part = inputs.getByPos(ii, pi); - // TODO: we need to make a copy of the messages, maybe we can implement functionality in - // the RawDeviceService to forward messages, but this also needs to take into account that - // other consumers might exist - size_t headerMsgSize = o2::header::Stack::headerStackSize(reinterpret_cast<o2::byte const*>(part.header)); - auto* dh = o2::header::get<DataHeader*>(part.header); - if (!dh) { - std::stringstream errorMessage; - errorMessage << "no data header in " << *first.spec; - throw std::runtime_error(errorMessage.str()); + const auto* dph = o2::header::get<DataProcessingHeader*>(part.header); + if (dph) { + // FIXME: should we implement an assignment operator for DataProcessingHeader? + lastDataProcessingHeader->startTime = dph->startTime; + lastDataProcessingHeader->duration = dph->duration; + lastDataProcessingHeader->creation = dph->creation; } - size_t payloadMsgSize = dh->payloadSize; - - auto channel = decideChannel(*first.spec, device.fChannels); - auto headerMessage = device.NewMessageFor(channel, index, headerMsgSize); - memcpy(headerMessage->GetData(), part.header, headerMsgSize); - auto payloadMessage = device.NewMessageFor(channel, index, payloadMsgSize); - memcpy(payloadMessage->GetData(), part.payload, payloadMsgSize); - outputs[channel].AddPart(std::move(headerMessage)); - outputs[channel].AddPart(std::move(payloadMessage)); } } - for (auto& [channelName, channelParts] : outputs) { - if (channelParts.Size() == 0) { + }); + }); + const char* d = strdup(((std::string(defaultChannelConfig).find("name=") == std::string::npos ? (std::string("name=") + name + ",") : "") + std::string(defaultChannelConfig)).c_str()); + spec.options = { + ConfigParamSpec{"channel-config", VariantType::String, d, {"Out-of-band channel config"}}, + }; + + return spec; +} + +DataProcessorSpec specifyFairMQDeviceMultiOutputProxy(char const* name, + Inputs const& inputSpecs, + const char* defaultChannelConfig, + ChannelSelector channelSelector) +{ + // FIXME: this looks like a code duplication with the function above, check if the + // two can be combined + DataProcessorSpec spec; + spec.name = name; + spec.inputs = inputSpecs; + spec.outputs = {}; + spec.algorithm = adaptStateful([inputSpecs, channelSelector](CallbackService& callbacks, RawDeviceService& rds, const DeviceSpec& deviceSpec) { + auto device = rds.device(); + // check that the input spec bindings have corresponding output channels + // FairMQDevice calls the custom init before the channels have been configured + // so we do the check before starting in a dedicated callback + // also we set forwards for all input specs and keep a list of all channels so we can send EOS on them + auto channelNames = std::make_shared<std::vector<std::string>>(); + auto channelConfigurationInitializer = [inputSpecs = std::move(inputSpecs), device, channelSelector, &deviceSpec, channelNames]() { + if (deviceSpec.forwards.size() > 0) { + // check that no internal forwards are existing, i.e. that proxy is at the end of the workflow + // in principle we can be less strict here if we check only for the defined input specs that there + // are no internal forwards + throw std::runtime_error("can not add forward targets outside DPL if internal forwards are existing, the proxy must be at the end of the workflow"); + } + for (auto const& spec : inputSpecs) { + auto channel = channelSelector(spec, device->fChannels); + if (device->fChannels.count(channel) == 0) { + throw std::runtime_error("no corresponding output channel found for input '" + channel + "'"); + } + ForwardRoute route{0, 1, spec, channel}; + // this we will try to fix on the framework level, there will be an API to + // set external routes. Basically, this has to be added while setting up the + // workflow. After that, the actual spec provided by the service is supposed + // to be const by design + const_cast<DeviceSpec&>(deviceSpec).forwards.emplace_back(route); + + channelNames->emplace_back(std::move(channel)); + } + }; + callbacks.set(CallbackService::Id::Start, channelConfigurationInitializer); + + auto lastDataProcessingHeader = std::make_shared<DataProcessingHeader>(0, 0); + auto forwardEos = [device, lastDataProcessingHeader, channelNames](EndOfStreamContext&) { + // DPL implements an internal end of stream signal, which is propagated through + // all downstream channels if a source is dry, make it available to other external + // devices via a message of type {DPL/EOS/0} + for (auto& channelInfo : device->fChannels) { + // FIXME: in this function the channel name is hardcoded to 'downstream' + // have to check if this simply should be combined with the function below + // supporting multiple outputs + auto& channelName = channelInfo.first; + auto checkChannel = [channelNames = std::move(*channelNames)](std::string const& name) -> bool { + for (auto const& n : channelNames) { + if (n == name) { + return true; + } + } + return false; + }; + if (!checkChannel(channelName)) { continue; } - sendOnChannel(device, channelParts, channelName); + DataHeader dh; + dh.dataOrigin = "DPL"; + dh.dataDescription = "EOS"; + dh.subSpecification = 0; + dh.payloadSize = 0; + dh.payloadSerializationMethod = o2::header::gSerializationMethodNone; + dh.tfCounter = 0; + dh.firstTForbit = 0; + SourceInfoHeader sih; + sih.state = InputChannelState::Completed; + // allocate the header message using the underlying transport of the channel + auto channelAlloc = o2::pmr::getTransportAllocator(channelInfo.second[0].Transport()); + auto headerMessage = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, *lastDataProcessingHeader, sih}); + FairMQParts out; + out.AddPart(std::move(headerMessage)); + // add empty payload message + out.AddPart(std::move(device->NewMessageFor(channelName, 0, 0))); + sendOnChannel(*device, out, channelName); + } + }; + callbacks.set(CallbackService::Id::EndOfStream, forwardEos); + + return adaptStateless([channelSelector, lastDataProcessingHeader](RawDeviceService& rds, InputRecord& inputs) { + // there is nothing to do if the forwarding is handled on the framework level + // as forward routes but we need to keep a copy of the last DataProcessingHeader + // for sending the EOS + for (size_t ii = 0; ii != inputs.size(); ++ii) { + for (size_t pi = 0; pi < inputs.getNofParts(ii); ++pi) { + auto part = inputs.getByPos(ii, pi); + const auto* dph = o2::header::get<DataProcessingHeader*>(part.header); + if (dph) { + // FIXME: should we implement an assignment operator for DataProcessingHeader? + lastDataProcessingHeader->startTime = dph->startTime; + lastDataProcessingHeader->duration = dph->duration; + lastDataProcessingHeader->creation = dph->creation; + } + } } }); }); @@ -478,5 +633,4 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, return spec; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/FairMQDeviceProxy.cxx b/Framework/Core/src/FairMQDeviceProxy.cxx index bdc72afa4917d..06dc0a12c5549 100644 --- a/Framework/Core/src/FairMQDeviceProxy.cxx +++ b/Framework/Core/src/FairMQDeviceProxy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/FairMQResizableBuffer.cxx b/Framework/Core/src/FairMQResizableBuffer.cxx index 6646afc009ce7..8ddbbb3979549 100644 --- a/Framework/Core/src/FairMQResizableBuffer.cxx +++ b/Framework/Core/src/FairMQResizableBuffer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,40 +12,122 @@ #include "FairMQResizableBuffer.h" #include <fairmq/FairMQMessage.h> #include <arrow/status.h> +#include <arrow/util/config.h> #include <cassert> -namespace o2 +namespace arrow::io::internal { -namespace framework +void CloseFromDestructor(FileInterface* file); +} + +namespace o2::framework +{ +static constexpr int64_t kBufferMinimumSize = 256; + +FairMQOutputStream::FairMQOutputStream() + : is_open_(false), capacity_(0), position_(0), mutable_data_(nullptr) {} + +FairMQOutputStream::FairMQOutputStream(const std::shared_ptr<ResizableBuffer>& buffer) + : buffer_(buffer), + is_open_(true), + capacity_(buffer->size()), + position_(0), + mutable_data_(buffer->mutable_data()) {} + +Result<std::shared_ptr<FairMQOutputStream>> FairMQOutputStream::Create( + int64_t initial_capacity, MemoryPool* pool) +{ + // ctor is private, so cannot use make_shared + auto ptr = std::shared_ptr<FairMQOutputStream>(new FairMQOutputStream); + RETURN_NOT_OK(ptr->Reset(initial_capacity, pool)); + return ptr; +} + +Status FairMQOutputStream::Reset(int64_t initial_capacity, MemoryPool* pool) { + ARROW_ASSIGN_OR_RAISE(buffer_, AllocateResizableBuffer(initial_capacity, pool)); + is_open_ = true; + capacity_ = initial_capacity; + position_ = 0; + mutable_data_ = buffer_->mutable_data(); + return Status::OK(); +} + +Status FairMQOutputStream::Close() +{ + if (is_open_) { + is_open_ = false; + if (position_ < capacity_) { + RETURN_NOT_OK(buffer_->Resize(position_, false)); + } + } + return Status::OK(); +} + +bool FairMQOutputStream::closed() const { return !is_open_; } + +Result<std::shared_ptr<Buffer>> FairMQOutputStream::Finish() +{ + RETURN_NOT_OK(Close()); + buffer_->ZeroPadding(); + is_open_ = false; + return std::move(buffer_); +} + +Result<int64_t> FairMQOutputStream::Tell() const { return position_; } + +Status FairMQOutputStream::Write(const void* data, int64_t nbytes) +{ + if (ARROW_PREDICT_FALSE(!is_open_)) { + return Status::IOError("OutputStream is closed"); + } + if (ARROW_PREDICT_TRUE(nbytes > 0)) { + if (ARROW_PREDICT_FALSE(position_ + nbytes >= capacity_)) { + RETURN_NOT_OK(Reserve(nbytes)); + } + memcpy(mutable_data_ + position_, data, nbytes); + position_ += nbytes; + } + return Status::OK(); +} + +Status FairMQOutputStream::Reserve(int64_t nbytes) +{ + // Always overallocate by doubling. It seems that it is a better growth + // strategy, at least for memory_benchmark.cc. + // This may be because it helps match the allocator's allocation buckets + // more exactly. Or perhaps it hits a sweet spot in jemalloc. + int64_t new_capacity = std::max(kBufferMinimumSize, capacity_); + while (new_capacity < position_ + nbytes) { + new_capacity = new_capacity + 1024 * 1024; + } + if (new_capacity > capacity_) { + RETURN_NOT_OK(buffer_->Resize(new_capacity)); + capacity_ = new_capacity; + mutable_data_ = buffer_->mutable_data(); + } + return Status::OK(); +} FairMQResizableBuffer::~FairMQResizableBuffer() = default; // Creates an empty message FairMQResizableBuffer::FairMQResizableBuffer(Creator creator) : ResizableBuffer(nullptr, 0), - mMessage{std::move(creator(4096))}, + mMessage{nullptr}, mCreator{creator} { - this->mutable_data_ = reinterpret_cast<uint8_t*>(mMessage->GetData()); - this->data_ = this->mutable_data_; - assert(this->data_); - this->capacity_ = static_cast<int64_t>(mMessage->GetSize()); + this->data_ = nullptr; + this->capacity_ = 0; this->size_ = 0; } arrow::Status FairMQResizableBuffer::Resize(const int64_t newSize, bool shrink_to_fit) { - if (newSize < this->capacity_ && shrink_to_fit == true) { - auto newMessage = mCreator(newSize); - memcpy(newMessage->GetData(), mMessage->GetData(), newSize); - mMessage = std::move(newMessage); - this->mutable_data_ = reinterpret_cast<uint8_t*>(mMessage->GetData()); - this->data_ = this->mutable_data_; - assert(this->data_); - this->capacity_ = static_cast<int64_t>(mMessage->GetSize()); - assert(newSize == this->capacity_); - } else if (newSize > this->capacity_) { + // NOTE: we ignore "shrink_to_fit" because in any case we + // invoke SetUsedSize when we send the message. This + // way we avoid unneeded copies at the arrow level. + if (newSize > this->capacity_) { auto status = this->Reserve(newSize); if (status.ok() == false) { return status; @@ -71,8 +154,7 @@ arrow::Status FairMQResizableBuffer::Reserve(const int64_t capacity) } mMessage = std::move(newMessage); assert(mMessage); - this->mutable_data_ = reinterpret_cast<uint8_t*>(mMessage->GetData()); - this->data_ = this->mutable_data_; + this->data_ = reinterpret_cast<uint8_t*>(mMessage->GetData()); this->capacity_ = static_cast<int64_t>(mMessage->GetSize()); assert(this->data_); return arrow::Status::OK(); @@ -82,11 +164,9 @@ std::unique_ptr<FairMQMessage> FairMQResizableBuffer::Finalise() { mMessage->SetUsedSize(this->size_); this->data_ = nullptr; - this->mutable_data_ = nullptr; this->capacity_ = 0; this->size_ = 0; return std::move(mMessage); } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/FairMQResizableBuffer.h b/Framework/Core/src/FairMQResizableBuffer.h index 78612b852c4dd..4fb85ac16ef0a 100644 --- a/Framework/Core/src/FairMQResizableBuffer.h +++ b/Framework/Core/src/FairMQResizableBuffer.h @@ -1,26 +1,87 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_FAIRMQRESIZABLEBUFFER_H -#define FRAMEWORK_FAIRMQRESIZABLEBUFFER_H +#ifndef O2_FRAMEWORK_FAIRMQRESIZABLEBUFFER_H_ +#define O2_FRAMEWORK_FAIRMQRESIZABLEBUFFER_H_ #include <memory> #include <functional> #include <arrow/buffer.h> +#include "arrow/io/interfaces.h" +#include "arrow/status.h" +#include "arrow/util/future.h" -class FairMQMessage; +#include <fairmq/FwdDecls.h> -namespace o2 +namespace o2::framework { -namespace framework + +using namespace arrow; +using namespace arrow::io; + +class FairMQOutputStream : public OutputStream { + public: + explicit FairMQOutputStream(const std::shared_ptr<ResizableBuffer>& buffer); + + /// \brief Create in-memory output stream with indicated capacity using a + /// memory pool + /// \param[in] initial_capacity the initial allocated internal capacity of + /// the OutputStream + /// \param[in,out] pool a MemoryPool to use for allocations + /// \return the created stream + static Result<std::shared_ptr<FairMQOutputStream>> Create( + int64_t initial_capacity = 4096, MemoryPool* pool = default_memory_pool()); + + // By the time we call the destructor, the contents + // of the buffer are already moved to fairmq + // for being sent. + ~FairMQOutputStream() override = default; + + // Implement the OutputStream interface + + /// Close the stream, preserving the buffer (retrieve it with Finish()). + Status Close() override; + bool closed() const override; + Result<int64_t> Tell() const override; + Status Write(const void* data, int64_t nbytes) override; + + /// \cond FALSE + using OutputStream::Write; + /// \endcond + + /// Close the stream and return the buffer + Result<std::shared_ptr<Buffer>> Finish(); + + /// \brief Initialize state of OutputStream with newly allocated memory and + /// set position to 0 + /// \param[in] initial_capacity the starting allocated capacity + /// \param[in,out] pool the memory pool to use for allocations + /// \return Status + Status Reset(int64_t initial_capacity = 1024, MemoryPool* pool = default_memory_pool()); + + int64_t capacity() const { return capacity_; } + + private: + FairMQOutputStream(); + + // Ensures there is sufficient space available to write nbytes + Status Reserve(int64_t nbytes); + + std::shared_ptr<ResizableBuffer> buffer_; + bool is_open_; + int64_t capacity_; + int64_t position_; + uint8_t* mutable_data_; +}; /// An arrow::ResizableBuffer implemented on top of a FairMQMessage /// FIXME: this is an initial attempt to integrate arrow and FairMQ @@ -58,7 +119,6 @@ class FairMQResizableBuffer : public ::arrow::ResizableBuffer Creator mCreator; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif +#endif // O2_FRAMEWORK_FAIRMQRESIZABLEBUFFER_H_ diff --git a/Framework/Core/src/FairOptionsRetriever.cxx b/Framework/Core/src/FairOptionsRetriever.cxx index 890d7e0fc1818..57f78a16c52b4 100644 --- a/Framework/Core/src/FairOptionsRetriever.cxx +++ b/Framework/Core/src/FairOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/FrameworkDummyDebugger.cxx b/Framework/Core/src/FrameworkDummyDebugger.cxx deleted file mode 100644 index 0520e260cf071..0000000000000 --- a/Framework/Core/src/FrameworkDummyDebugger.cxx +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "DataProcessorInfo.h" -#include "Framework/FrameworkGUIDebugger.h" - -#include <algorithm> -#include <vector> - -namespace o2 -{ -namespace framework -{ -namespace gui -{ -// Dummy function in case we want to build without debugger. -std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, - std::vector<DeviceSpec> const& devices, - std::vector<DataProcessorInfo> const& metadata, - std::vector<DeviceMetricsInfo> const& metricsInfos, - DriverInfo const& driverInfo, - std::vector<DeviceControl>& controls, - DriverControl& driverControl) -{ - return []() {}; -} - -void showNodeGraph(bool* opened) {} - -} // namespace gui -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/src/FrameworkGUIDebugger.cxx b/Framework/Core/src/FrameworkGUIDebugger.cxx deleted file mode 100644 index f7a173b0e647e..0000000000000 --- a/Framework/Core/src/FrameworkGUIDebugger.cxx +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/FrameworkGUIDebugger.h" -#include <algorithm> -#include <iostream> -#include <set> -#include <string> -#include <cinttypes> -#include "Framework/ConfigContext.h" -#include "Framework/ConfigParamRegistry.h" -#include "DebugGUI/imgui.h" -#include "DebugGUI/implot.h" -#include "DebugGUI/imgui_extras.h" -#include "DriverControl.cxx" -#include "DriverInfo.cxx" -#include "FrameworkGUIDeviceInspector.h" -#include "Framework/FrameworkGUIDevicesGraph.h" -#include "Framework/FrameworkGUIDataRelayerUsage.h" -#include "Framework/PaletteHelpers.h" -#include "Framework/FrameworkGUIState.h" - -// Simplify debugging -template class std::vector<o2::framework::DeviceMetricsInfo>; - -static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } - -namespace o2 -{ -namespace framework -{ -namespace gui -{ -// Type erased information for the plotting -struct MultiplotData { - int mod; - size_t first; - size_t size; - const void* Y; - const void* X; - MetricType type; -}; - -} // namespace gui -} // namespace framework -} // namespace o2 - -template class std::vector<o2::framework::gui::MultiplotData>; - -namespace o2 -{ -namespace framework -{ -namespace gui -{ - -ImVec4 colorForLogLevel(LogParsingHelpers::LogLevel logLevel) -{ - switch (logLevel) { - case LogParsingHelpers::LogLevel::Info: - return PaletteHelpers::GREEN; - case LogParsingHelpers::LogLevel::Debug: - return ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); - case LogParsingHelpers::LogLevel::Warning: - return PaletteHelpers::DARK_YELLOW; - case LogParsingHelpers::LogLevel::Error: - return PaletteHelpers::RED; - case LogParsingHelpers::LogLevel::Unknown: - return ImVec4(194. / 255, 195. / 255, 199. / 255, 255. / 255); - default: - return ImVec4(194. / 255, 195. / 255, 199. / 255, 255. / 255); - }; -} - -void displayHistory(const DeviceInfo& info, DeviceControl& control) -{ - if (info.history.empty()) { - return; - } - int startPos = info.historyPos; - const int historySize = info.history.size(); - - int triggerStartPos = startPos + 1 % historySize; - int triggerStopPos = startPos % historySize; - - int j = startPos; - // We look for a stop trigger, so that we know where to stop the search for - // out start search. If no stop trigger is found, we search until the end - if (control.logStopTrigger[0]) { - while ((j % historySize) != ((startPos + 1) % historySize)) { - assert(j >= 0); - assert(j < historySize); - auto& line = info.history[j]; - if (strstr(line.c_str(), control.logStopTrigger)) { - triggerStopPos = (j + 1) % historySize; - break; - } - // Wrap in case we end up below 0 - j = (j == 0) ? historySize - 1 : j - 1; - } - } - - // Look for the last instance of the start trigger before the - // last stop trigger. - j = startPos + 1; - if (control.logStartTrigger[0]) { - while ((j % historySize) != triggerStopPos) { - assert(historySize > j); - assert(historySize == 1000); - auto& line = info.history[j]; - if (strstr(line.c_str(), control.logStartTrigger)) { - triggerStartPos = j; - } - j = (j + 1) % historySize; - } - } - - // We start from the last trigger found. Eventually this is the first - // line in the ring buffer, if no trigger is specified. - size_t ji = triggerStartPos % historySize; - size_t je = triggerStopPos % historySize; - size_t iterations = 0; - while (historySize && ((ji % historySize) != je)) { - assert(iterations < historySize); - iterations++; - assert(historySize == 1000); - assert(ji < historySize); - auto& line = info.history[ji]; - auto logLevel = info.historyLevel[ji]; - - // Skip empty lines - if (line.empty()) { - ji = (ji + 1) % historySize; - continue; - } - // Print matching lines - if (strstr(line.c_str(), control.logFilter) != nullptr) { - auto color = colorForLogLevel(logLevel); - // We filter twice, once on input, to reduce the - // stream, a second time at display time, to avoid - // showing unrelevant messages from past. - if (logLevel >= control.logLevel) { - if (line.find('%', 0) != std::string::npos) { - ImGui::TextUnformatted(line.c_str(), line.c_str() + line.size()); - } else { - ImGui::TextColored(color, line.c_str(), line.c_str() + line.size()); - } - } - } - ji = (ji + 1) % historySize; - } -} - -template <typename T> -struct HistoData { - int mod; - size_t first; - size_t size; - const T* points; -}; - -enum struct MetricsDisplayStyle : int { - Lines = 0, - Histos = 1, - Sparks = 2, - Table = 3, - Stems = 4 -}; - -void displayDeviceMetrics(const char* label, std::string const& selectedMetricName, - size_t rangeBegin, size_t rangeEnd, size_t bins, MetricsDisplayStyle displayType, - std::vector<DeviceSpec> const& specs, - std::vector<DeviceMetricsInfo> const& metricsInfos, - DeviceMetricsInfo const& driverMetric) -{ - std::vector<void*> metricsToDisplay; - std::vector<const char*> deviceNames; - std::vector<MultiplotData> userData; - MetricType metricType; - size_t metricSize = 0; - assert(specs.size() == metricsInfos.size()); - float maxValue = std::numeric_limits<float>::lowest(); - float minValue = 0; - size_t maxDomain = std::numeric_limits<size_t>::lowest(); - size_t minDomain = std::numeric_limits<size_t>::max(); - - for (int mi = 0; mi < metricsInfos.size(); ++mi) { - auto vi = DeviceMetricsHelper::metricIdxByName(selectedMetricName, metricsInfos[mi]); - if (vi == metricsInfos[mi].metricLabelsIdx.size()) { - continue; - } - auto& metric = metricsInfos[mi].metrics[vi]; - deviceNames.push_back(specs[mi].name.c_str()); - metricType = metric.type; - MultiplotData data; - data.mod = metricsInfos[mi].timestamps[vi].size(); - data.first = metric.pos - data.mod; - data.X = metricsInfos[mi].timestamps[vi].data(); - minValue = std::min(minValue, metricsInfos[mi].min[vi]); - maxValue = std::max(maxValue, metricsInfos[mi].max[vi]); - minDomain = std::min(minDomain, metricsInfos[mi].minDomain[vi]); - maxDomain = std::max(maxDomain, metricsInfos[mi].maxDomain[vi]); - metricType = metric.type; - data.type = metric.type; - switch (metric.type) { - case MetricType::Int: { - data.size = metricsInfos[mi].intMetrics[metric.storeIdx].size(); - data.Y = metricsInfos[mi].intMetrics[metric.storeIdx].data(); - } break; - case MetricType::Uint64: { - data.size = metricsInfos[mi].uint64Metrics[metric.storeIdx].size(); - data.Y = metricsInfos[mi].uint64Metrics[metric.storeIdx].data(); - } break; - case MetricType::Float: { - data.size = metricsInfos[mi].floatMetrics[metric.storeIdx].size(); - data.Y = metricsInfos[mi].floatMetrics[metric.storeIdx].data(); - } break; - case MetricType::Unknown: - case MetricType::String: { - data.size = metricsInfos[mi].stringMetrics[metric.storeIdx].size(); - data.Y = nullptr; - data.type = MetricType::String; - metricType = MetricType::String; - } break; - } - metricSize = data.size; - userData.emplace_back(data); - } - if (true) { - auto vi = DeviceMetricsHelper::metricIdxByName(selectedMetricName, driverMetric); - if (vi < driverMetric.metricLabelsIdx.size()) { - auto& metric = driverMetric.metrics[vi]; - deviceNames.push_back("driver"); - metricType = metric.type; - MultiplotData data; - data.mod = driverMetric.timestamps[vi].size(); - data.first = metric.pos - data.mod; - data.X = driverMetric.timestamps[vi].data(); - minValue = std::min(minValue, driverMetric.min[vi]); - maxValue = std::max(maxValue, driverMetric.max[vi]); - minDomain = std::min(minDomain, driverMetric.minDomain[vi]); - maxDomain = std::max(maxDomain, driverMetric.maxDomain[vi]); - metricType = metric.type; - data.type = metric.type; - switch (metric.type) { - case MetricType::Int: { - data.size = driverMetric.intMetrics[metric.storeIdx].size(); - data.Y = driverMetric.intMetrics[metric.storeIdx].data(); - } break; - case MetricType::Uint64: { - data.size = driverMetric.uint64Metrics[metric.storeIdx].size(); - data.Y = driverMetric.uint64Metrics[metric.storeIdx].data(); - } break; - case MetricType::Float: { - data.size = driverMetric.floatMetrics[metric.storeIdx].size(); - data.Y = driverMetric.floatMetrics[metric.storeIdx].data(); - } break; - case MetricType::Unknown: - case MetricType::String: { - data.size = driverMetric.stringMetrics[metric.storeIdx].size(); - data.Y = nullptr; - data.type = MetricType::String; - metricType = MetricType::String; - } break; - } - metricSize = data.size; - userData.emplace_back(data); - } - } - - maxDomain = std::max(minDomain + 1024, maxDomain); - - for (size_t ui = 0; ui < userData.size(); ++ui) { - metricsToDisplay.push_back(&(userData[ui])); - } - auto getterXY = [](void* hData, int idx) -> ImPlotPoint { - auto histoData = reinterpret_cast<const MultiplotData*>(hData); - size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; - double x = static_cast<const size_t*>(histoData->X)[pos]; - double y = 0.; - if (histoData->type == MetricType::Int) { - y = static_cast<const int*>(histoData->Y)[pos]; - } else if (histoData->type == MetricType::Uint64) { - y = static_cast<const uint64_t*>(histoData->Y)[pos]; - } else if (histoData->type == MetricType::Float) { - y = static_cast<const float*>(histoData->Y)[pos]; - } - return ImPlotPoint{x, y}; - }; - - switch (displayType) { - case MetricsDisplayStyle::Histos: - ImPlot::SetNextPlotLimitsX(minDomain, maxDomain, ImGuiCond_Once); - ImPlot::SetNextPlotLimitsY(minValue, maxValue, ImGuiCond_Always); - ImPlot::SetNextPlotTicksX(minDomain, maxDomain, 5); - if (ImPlot::BeginPlot(selectedMetricName.c_str(), "time", "value")) { - for (size_t pi = 0; pi < metricsToDisplay.size(); ++pi) { - ImPlot::PlotBarsG(deviceNames[pi], getterXY, metricsToDisplay[pi], metricSize, 1, 0); - } - ImPlot::EndPlot(); - } - - break; - case MetricsDisplayStyle::Lines: - ImPlot::SetNextPlotLimitsX(minDomain, maxDomain, ImGuiCond_Once); - ImPlot::SetNextPlotLimitsY(minValue, maxValue * 1.2, ImGuiCond_Always); - ImPlot::SetNextPlotTicksX(minDomain, maxDomain, 5); - if (ImPlot::BeginPlot("##Some plot", "time", "value")) { - for (size_t pi = 0; pi < metricsToDisplay.size(); ++pi) { - ImPlot::PlotLineG(deviceNames[pi], getterXY, metricsToDisplay[pi], metricSize, 0); - } - ImPlot::EndPlot(); - } - break; - case MetricsDisplayStyle::Stems: - ImPlot::SetNextPlotLimitsX(minDomain, maxDomain, ImGuiCond_Once); - ImPlot::SetNextPlotLimitsY(minValue, maxValue * 1.2, ImGuiCond_Always); - ImPlot::SetNextPlotTicksX(minDomain, maxDomain, 5); - if (ImPlot::BeginPlot("##Some plot", "time", "value")) { - for (size_t pi = 0; pi < userData.size(); ++pi) { - auto stemsData = reinterpret_cast<const MultiplotData*>(metricsToDisplay[pi]); - // FIXME: display a message for other metrics - if (stemsData->type == MetricType::Uint64) { - ImPlot::PlotStems(deviceNames[pi], (const ImU64*)stemsData->X, (const ImU64*)stemsData->Y, metricSize); - } - } - ImPlot::EndPlot(); - } - break; - default: - break; - } -} - -struct ColumnInfo { - MetricType type; - int index; -}; - -void metricsTableRow(std::vector<ColumnInfo> columnInfos, - std::vector<DeviceMetricsInfo> const& metricsInfos, - int row) -{ - ImGui::Text("%d", row); - ImGui::NextColumn(); - - for (size_t j = 0; j < columnInfos.size(); j++) { - auto& info = columnInfos[j]; - auto& metricsInfo = metricsInfos[j]; - - if (info.index == -1) { - ImGui::TextUnformatted("-"); - ImGui::NextColumn(); - continue; - } - switch (info.type) { - case MetricType::Int: { - ImGui::Text("%i (%i)", metricsInfo.intMetrics[info.index][row], info.index); - ImGui::NextColumn(); - } break; - case MetricType::Uint64: { - ImGui::Text("%" PRIu64 " (%i)", metricsInfo.uint64Metrics[info.index][row], info.index); - ImGui::NextColumn(); - } break; - case MetricType::Float: { - ImGui::Text("%f (%i)", metricsInfo.floatMetrics[info.index][row], info.index); - ImGui::NextColumn(); - } break; - case MetricType::String: { - ImGui::Text("%s (%i)", metricsInfo.stringMetrics[info.index][row].data, info.index); - ImGui::NextColumn(); - } break; - default: - ImGui::NextColumn(); - break; - } - } -} - -void historyBar(gui::WorkspaceGUIState& globalGUIState, - size_t rangeBegin, size_t rangeEnd, - gui::DeviceGUIState& state, - DriverInfo const& driverInfo, - DeviceSpec const& spec, - DeviceMetricsInfo const& metricsInfo) -{ - bool open = ImGui::TreeNode(state.label.c_str()); - if (open) { - ImGui::Text("# channels: %lu", spec.outputChannels.size() + spec.inputChannels.size()); - ImGui::TreePop(); - } - ImGui::NextColumn(); - - if (globalGUIState.selectedMetric == -1) { - ImGui::NextColumn(); - return; - } - - auto currentMetricName = driverInfo.availableMetrics[globalGUIState.selectedMetric]; - - size_t i = DeviceMetricsHelper::metricIdxByName(currentMetricName, metricsInfo); - // We did not find any plot, skipping this. - if (i == metricsInfo.metricLabelsIdx.size()) { - ImGui::NextColumn(); - return; - } - auto& metric = metricsInfo.metrics[i]; - - switch (metric.type) { - case MetricType::Int: { - HistoData<int> data; - data.mod = metricsInfo.timestamps[i].size(); - data.first = metric.pos - data.mod; - data.size = metricsInfo.intMetrics[metric.storeIdx].size(); - data.points = metricsInfo.intMetrics[metric.storeIdx].data(); - - auto getter = [](void* hData, int idx) -> float { - auto histoData = reinterpret_cast<HistoData<int>*>(hData); - size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; - assert(pos >= 0 && pos < 1024); - return histoData->points[pos]; - }; - ImGui::PlotLines(("##" + currentMetricName).c_str(), getter, &data, data.size); - ImGui::NextColumn(); - } break; - case MetricType::Uint64: { - HistoData<uint64_t> data; - data.mod = metricsInfo.timestamps[i].size(); - data.first = metric.pos - data.mod; - data.size = metricsInfo.uint64Metrics[metric.storeIdx].size(); - data.points = metricsInfo.uint64Metrics[metric.storeIdx].data(); - - auto getter = [](void* hData, int idx) -> float { - auto histoData = reinterpret_cast<HistoData<uint64_t>*>(hData); - size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; - assert(pos >= 0 && pos < 1024); - return histoData->points[pos]; - }; - ImGui::PlotLines(("##" + currentMetricName).c_str(), getter, &data, data.size); - ImGui::NextColumn(); - } break; - case MetricType::Float: { - HistoData<float> data; - data.mod = metricsInfo.timestamps[i].size(); - data.first = metric.pos - data.mod; - data.size = metricsInfo.floatMetrics[metric.storeIdx].size(); - data.points = metricsInfo.floatMetrics[metric.storeIdx].data(); - - auto getter = [](void* hData, int idx) -> float { - auto histoData = reinterpret_cast<HistoData<float>*>(hData); - size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; - assert(pos >= 0 && pos < 1024); - return histoData->points[pos]; - }; - ImGui::PlotLines(("##" + currentMetricName).c_str(), getter, &data, data.size); - ImGui::NextColumn(); - } break; - default: - ImGui::NextColumn(); - return; - break; - } -} - -/// Calculate where to find the coliumns for a give metric -std::vector<ColumnInfo> calculateTableIndex(gui::WorkspaceGUIState& globalGUIState, - int selectedMetric, - DriverInfo const& driverInfo, - std::vector<DeviceMetricsInfo> const& metricsInfos) -{ - std::vector<ColumnInfo> columns; - for (size_t j = 0; j < globalGUIState.devices.size(); ++j) { - const DeviceMetricsInfo& metricsInfo = metricsInfos[j]; - /// Nothing to draw, if no metric selected. - if (selectedMetric == -1) { - columns.push_back({MetricType::Int, -1}); - continue; - } - auto currentMetricName = driverInfo.availableMetrics[selectedMetric]; - size_t idx = DeviceMetricsHelper::metricIdxByName(currentMetricName, metricsInfo); - - // We did not find any plot, skipping this. - if (idx == metricsInfo.metricLabelsIdx.size()) { - columns.push_back({MetricType::Int, -1}); - continue; - } - auto metric = metricsInfos[j].metrics[idx]; - columns.push_back({metric.type, static_cast<int>(metric.storeIdx)}); - } - return columns; -}; - -void displayDeviceHistograms(gui::WorkspaceGUIState& state, - DriverInfo const& driverInfo, - std::vector<DeviceInfo> const& infos, - std::vector<DeviceSpec> const& devices, - std::vector<DataProcessorInfo> const& metadata, - std::vector<DeviceControl>& controls, - std::vector<DeviceMetricsInfo> const& metricsInfos) -{ - showTopologyNodeGraph(state, infos, devices, metadata, controls, metricsInfos); - if (state.bottomPaneVisible == false) { - return; - } - ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - state.bottomPaneSize), 0); - ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, state.bottomPaneSize), 0); - - ImGui::Begin("Devices", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); - ImGui::BeginGroup(); - char const* currentMetric = nullptr; - if (state.selectedMetric != -1) { - currentMetric = driverInfo.availableMetrics[state.selectedMetric].c_str(); - } else { - currentMetric = "Click to select metric"; - } - if (ImGui::BeginCombo("###Select metric", currentMetric, 0)) { - for (size_t mi = 0; mi < driverInfo.availableMetrics.size(); ++mi) { - auto metric = driverInfo.availableMetrics[mi]; - bool isSelected = mi == state.selectedMetric; - if (ImGui::Selectable(driverInfo.availableMetrics[mi].c_str(), isSelected)) { - state.selectedMetric = mi; - } - if (isSelected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - }; - - static char const* plotStyles[] = { - "lines", - "histograms", - "sparks", - "table", - "stems"}; - ImGui::SameLine(); - static enum MetricsDisplayStyle currentStyle = MetricsDisplayStyle::Lines; - ImGui::Combo("##Select style", reinterpret_cast<int*>(¤tStyle), plotStyles, IM_ARRAYSIZE(plotStyles)); - - // Calculate the full timestamp range for the selected metric - size_t minTime = -1; - size_t maxTime = 0; - std::string currentMetricName; - if (state.selectedMetric >= 0) { - currentMetricName = driverInfo.availableMetrics[state.selectedMetric]; - for (auto& metricInfo : metricsInfos) { - size_t mi = DeviceMetricsHelper::metricIdxByName(currentMetricName, metricInfo); - if (mi == metricInfo.metricLabelsIdx.size()) { - continue; - } - auto& metric = metricInfo.metrics[mi]; - auto& timestamps = metricInfo.timestamps[mi]; - - for (size_t ti = 0; ti != metricInfo.timestamps.size(); ++ti) { - size_t minRangePos = (metric.pos + ti) % metricInfo.timestamps.size(); - size_t curMinTime = timestamps[minRangePos]; - if (curMinTime == 0) { - continue; - } - minTime = minTime < curMinTime ? minTime : curMinTime; - if (minTime != 0 && minTime != -1) { - break; - } - } - size_t maxRangePos = (size_t)(metric.pos) - 1 % metricInfo.timestamps.size(); - size_t curMaxTime = timestamps[maxRangePos]; - maxTime = maxTime > curMaxTime ? maxTime : curMaxTime; - } - } - ImGui::EndGroup(); - if (!currentMetricName.empty()) { - switch (currentStyle) { - case MetricsDisplayStyle::Stems: - case MetricsDisplayStyle::Histos: - case MetricsDisplayStyle::Lines: { - displayDeviceMetrics("Metrics", - currentMetricName, minTime, maxTime, 1024, - currentStyle, devices, metricsInfos, driverInfo.metrics); - } break; - case MetricsDisplayStyle::Sparks: { -#if defined(ImGuiCol_ChildWindowBg) - ImGui::BeginChild("##ScrollingRegion", ImVec2(ImGui::GetIO().DisplaySize.x + state.leftPaneSize + state.rightPaneSize - 10, -ImGui::GetItemsLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar); -#else - ImGui::BeginChild("##ScrollingRegion", ImVec2(ImGui::GetIO().DisplaySize.x + state.leftPaneSize + state.rightPaneSize - 10, -ImGui::GetTextLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar); -#endif - ImGui::Columns(2); - ImGui::SetColumnOffset(1, 300); - for (size_t i = 0; i < state.devices.size(); ++i) { - gui::DeviceGUIState& deviceGUIState = state.devices[i]; - const DeviceSpec& spec = devices[i]; - const DeviceMetricsInfo& metricsInfo = metricsInfos[i]; - - historyBar(state, minTime, maxTime, deviceGUIState, driverInfo, spec, metricsInfo); - } - ImGui::Columns(1); - ImGui::EndChild(); - } break; - case MetricsDisplayStyle::Table: { -#if defined(ImGuiCol_ChildWindowBg) - ImGui::BeginChild("##ScrollingRegion", ImVec2(ImGui::GetIO().DisplaySize.x + state.leftPaneSize + state.rightPaneSize - 10, -ImGui::GetItemsLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar); -#else - ImGui::BeginChild("##ScrollingRegion", ImVec2(ImGui::GetIO().DisplaySize.x + state.leftPaneSize + state.rightPaneSize - 10, -ImGui::GetTextLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar); -#endif - - // The +1 is for the timestamp column - ImGui::Columns(state.devices.size() + 1); - ImGui::TextUnformatted("entry"); - ImGui::NextColumn(); - ImVec2 textsize = ImGui::CalcTextSize("extry", nullptr, true); - float offset = 0.f; - offset += std::max(100.f, textsize.x); - for (size_t j = 0; j < state.devices.size(); ++j) { - gui::DeviceGUIState& deviceGUIState = state.devices[j]; - const DeviceSpec& spec = devices[j]; - - ImGui::SetColumnOffset(-1, offset); - textsize = ImGui::CalcTextSize(spec.name.c_str(), nullptr, true); - offset += std::max(100.f, textsize.x); - ImGui::TextUnformatted(spec.name.c_str()); - ImGui::NextColumn(); - } - ImGui::Separator(); - - auto columns = calculateTableIndex(state, state.selectedMetric, driverInfo, metricsInfos); - - // Calculate which columns we want to see. - // FIXME: only one column for now. - for (size_t i = 0; i < 10; ++i) { - metricsTableRow(columns, metricsInfos, i); - } - ImGui::Columns(1); - - ImGui::EndChild(); - } break; - } - } - ImGui::End(); -} - -void pushWindowColorDueToStatus(const DeviceInfo& info) -{ - using LogLevel = LogParsingHelpers::LogLevel; - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.); - if (info.active == false) { - ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::DARK_RED); - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::RED); - ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::RED); - return; - } - switch (info.maxLogLevel) { - case LogLevel::Error: - ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_RED); - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::RED); - ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_RED); - break; - case LogLevel::Warning: - ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_YELLOW); - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::YELLOW); - ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_YELLOW); - break; - case LogLevel::Info: - ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_GREEN); - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::GREEN); - ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_GREEN); - break; - default: - ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_BLUE); - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::BLUE); - ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_BLUE); - break; - } -} - -void popWindowColorDueToStatus() -{ - ImGui::PopStyleColor(3); - ImGui::PopStyleVar(1); -} - -struct DriverHelper { - static char const* stateToString(enum DriverState state) - { - static const char* names[static_cast<int>(DriverState::LAST)] = { - "INIT", // - "SCHEDULE", // - "RUNNING", // - "GUI", // - "REDEPLOY_GUI", // - "QUIT_REQUESTED", // - "HANDLE_CHILDREN", // - "EXIT", // - "UNKNOWN" // - "PERFORM_CALLBACKS" // - }; - return names[static_cast<int>(state)]; - } -}; - -/// Display information window about the driver -/// and its state. -void displayDriverInfo(DriverInfo const& driverInfo, DriverControl& driverControl) -{ - ImGui::Begin("Driver information"); - static int pid = getpid(); - - if (driverControl.state == DriverControlState::STEP) { - driverControl.state = DriverControlState::PAUSE; - } - auto state = reinterpret_cast<int*>(&driverControl.state); - ImGui::RadioButton("Play", state, static_cast<int>(DriverControlState::PLAY)); - ImGui::SameLine(); - ImGui::RadioButton("Pause", state, static_cast<int>(DriverControlState::PAUSE)); - ImGui::SameLine(); - ImGui::RadioButton("Step", state, static_cast<int>(DriverControlState::STEP)); - - auto& registry = driverInfo.configContext->options(); - ImGui::Columns(); - - ImGui::Text("PID: %d", pid); - ImGui::Text("Frame cost (latency): %.1f(%.1f)ms", driverInfo.frameCost, driverInfo.frameLatency); - ImGui::Text("Input parsing cost (latency): %.1f(%.1f)ms", driverInfo.inputProcessingCost, driverInfo.inputProcessingLatency); - ImGui::Text("State stack (depth %lu)", driverInfo.states.size()); - if (ImGui::Button("SIGCONT all children")) { - kill(0, SIGCONT); - } - - for (size_t i = 0; i < driverInfo.states.size(); ++i) { - ImGui::Text("#%lu: %s", i, DriverHelper::stateToString(driverInfo.states[i])); - } - - ImGui::End(); -} - -// FIXME: return empty function in case we were not built -// with GLFW support. -/// -std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, - std::vector<DeviceSpec> const& devices, - std::vector<DataProcessorInfo> const& metadata, - std::vector<DeviceMetricsInfo> const& metricsInfos, - DriverInfo const& driverInfo, - std::vector<DeviceControl>& controls, - DriverControl& driverControl) -{ - static gui::WorkspaceGUIState globalGUIState; - gui::WorkspaceGUIState& guiState = globalGUIState; - guiState.selectedMetric = -1; - guiState.metricMaxRange = 0UL; - guiState.metricMinRange = -1; - // FIXME: this should probaly have a better mapping between our window state and - guiState.devices.resize(infos.size()); - for (size_t i = 0; i < guiState.devices.size(); ++i) { - gui::DeviceGUIState& state = guiState.devices[i]; - state.label = devices[i].id + "(" + std::to_string(infos[i].pid) + ")"; - } - guiState.bottomPaneSize = 340; - guiState.leftPaneSize = 200; - guiState.rightPaneSize = 300; - - // Show all the panes by default. - guiState.bottomPaneVisible = true; - guiState.leftPaneVisible = true; - guiState.rightPaneVisible = true; - - return [&guiState, &infos, &devices, &metadata, &controls, &metricsInfos, &driverInfo, &driverControl]() { - ImGuiStyle& style = ImGui::GetStyle(); - style.FrameRounding = 0.; - style.WindowRounding = 0.; - style.Colors[ImGuiCol_WindowBg] = ImVec4(0x1b / 255.f, 0x1b / 255.f, 0x1b / 255.f, 1.00f); - style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0x1b / 255.f, 0x1b / 255.f, 0x1b / 255.f, 1.00f); - - displayDeviceHistograms(guiState, driverInfo, infos, devices, metadata, controls, metricsInfos); - displayDriverInfo(driverInfo, driverControl); - - int windowPosStepping = (ImGui::GetIO().DisplaySize.y - 500) / guiState.devices.size(); - - for (size_t i = 0; i < guiState.devices.size(); ++i) { - gui::DeviceGUIState& state = guiState.devices[i]; - assert(i < infos.size()); - assert(i < devices.size()); - const DeviceInfo& info = infos[i]; - const DeviceSpec& spec = devices[i]; - const DeviceMetricsInfo& metrics = metricsInfos[i]; - - assert(controls.size() == devices.size()); - DeviceControl& control = controls[i]; - - pushWindowColorDueToStatus(info); - if (control.logVisible) { - ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x / 3 * 2, i * windowPosStepping), ImGuiCond_Once); - ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x / 3, ImGui::GetIO().DisplaySize.y - 300), - ImGuiCond_Once); - ImGui::Begin(state.label.c_str(), &control.logVisible); - - ImGui::InputText("Log filter", control.logFilter, sizeof(control.logFilter)); - ImGui::InputText("Log start trigger", control.logStartTrigger, sizeof(control.logStartTrigger)); - ImGui::InputText("Log stop trigger", control.logStopTrigger, sizeof(control.logStopTrigger)); - ImGui::Checkbox("Stop logging", &control.quiet); - ImGui::SameLine(); - ImGui::Combo("Log level", reinterpret_cast<int*>(&control.logLevel), LogParsingHelpers::LOG_LEVELS, - (int)LogParsingHelpers::LogLevel::Size, 5); - - ImGui::Separator(); -#if defined(ImGuiCol_ChildWindowBg) - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -ImGui::GetItemsLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove); -#else - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -ImGui::GetTextLineHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove); -#endif - displayHistory(info, control); - ImGui::EndChild(); - ImGui::End(); - } - popWindowColorDueToStatus(); - } - }; -} - -} // namespace gui -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/src/FrameworkGUIDeviceInspector.h b/Framework/Core/src/FrameworkGUIDeviceInspector.h deleted file mode 100644 index 5ace46f95f28e..0000000000000 --- a/Framework/Core/src/FrameworkGUIDeviceInspector.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// Helper to display information about a device - -namespace o2 -{ -namespace framework -{ - -struct DeviceSpec; -struct DeviceControl; -struct DeviceInfo; -struct DeviceMetricsInfo; -struct DataProcessorInfo; - -namespace gui -{ - -void displayDeviceInspector(DeviceSpec const& spec, DeviceInfo const& info, DeviceMetricsInfo const& metrics, DataProcessorInfo const& metadata, DeviceControl& control); - -} // namespace gui -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/src/FreePortFinder.cxx b/Framework/Core/src/FreePortFinder.cxx index 95a7b76e83efa..b869c3b2e8005 100644 --- a/Framework/Core/src/FreePortFinder.cxx +++ b/Framework/Core/src/FreePortFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/GraphvizHelpers.cxx b/Framework/Core/src/GraphvizHelpers.cxx index 2bd2309811edf..47411235faba6 100644 --- a/Framework/Core/src/GraphvizHelpers.cxx +++ b/Framework/Core/src/GraphvizHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/GraphvizHelpers.h b/Framework/Core/src/GraphvizHelpers.h index 28d29d27bb138..1f6fadfac10ba 100644 --- a/Framework/Core/src/GraphvizHelpers.h +++ b/Framework/Core/src/GraphvizHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/HTTPParser.cxx b/Framework/Core/src/HTTPParser.cxx new file mode 100644 index 0000000000000..feafb9818fd86 --- /dev/null +++ b/Framework/Core/src/HTTPParser.cxx @@ -0,0 +1,446 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "HTTPParser.h" +#include "Framework/RuntimeError.h" +#include <string_view> +#include "Framework/SHA1.h" +#include "Base64.h" +#include <regex> +#include <cassert> + +using namespace o2::framework::internal; +namespace o2::framework +{ + +namespace +{ +/// WebSocket RFC requires XOR masking from the client +void memmask(char* dst, char const* src, size_t size, uint32_t mask) +{ + if (mask) { + char* m = (char*)&mask; + for (size_t len = 0; len < size; ++len) { + *dst++ = *src++ ^ m[len % 4]; + } + } else { + memcpy(dst, src, size); + } +} + +void memunmask(char* data, size_t size, uint32_t mask) +{ + char* m = (char*)&mask; + for (size_t len = 0; len < size; ++len) { + *data++ ^= m[len % 4]; + } +} +} // namespace + +void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, size_t size, WebSocketOpCode opcode, uint32_t mask) +{ + void* finalHeader; + size_t headerSize; + char* buffer = nullptr; + char* startPayload = nullptr; + std::vector<uv_buf_t> result; + + if (size < 126) { + headerSize = sizeof(WebSocketFrameTiny); + buffer = (char*)malloc(headerSize + size); + WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer; + memset(buffer, 0, headerSize); + header->len = size; + } else if (size < 1 << 16) { + headerSize = sizeof(WebSocketFrameShort); + buffer = (char*)malloc(headerSize + size); + WebSocketFrameShort* header = (WebSocketFrameShort*)buffer; + memset(buffer, 0, headerSize); + header->len = 126; + header->len16 = htons(size); + } else { + headerSize = sizeof(WebSocketFrameHuge); + buffer = (char*)malloc(headerSize + size); + WebSocketFrameHuge* header = (WebSocketFrameHuge*)buffer; + memset(buffer, 0, headerSize); + header->len = 127; + header->len64 = htonll(size); + } + size_t fullHeaderSize = (mask ? 4 : 0) + headerSize; + startPayload = buffer + fullHeaderSize; + WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer; + header->fin = 1; + header->opcode = (unsigned char)opcode; // binary or text for now + // Mask is right before payload. + if (mask) { + *((uint32_t*)(startPayload - 4)) = mask; + } + header->mask = mask ? 1 : 0; + memmask(startPayload, src, size, mask); + outputs.push_back(uv_buf_init(buffer, size + fullHeaderSize)); +} + +void decode_websocket(char* start, size_t size, WebSocketHandler& handler) +{ + // Handle the case in whiche the header is cut + if (handler.pendingHeaderSize) { + assert(handler.pendingHeader); + size_t pendingFullSize = handler.pendingHeaderSize + size; + char* pendingFull = new char[handler.pendingHeaderSize + size]; + memcpy(pendingFull, handler.pendingHeader, handler.pendingHeaderSize); + memcpy(pendingFull + handler.pendingHeaderSize, start, size); + // We do not need the intermediate buffer anymore. + handler.pendingHeaderSize = 0; + delete[] handler.pendingHeader; + handler.pendingHeader = nullptr; + decode_websocket(pendingFull, pendingFullSize, handler); + delete[] pendingFull; + return; + } + + // Handle the case the previous message was cut in half + // by the I/O stack. + char* cur = start + handler.remainingSize; + if (handler.remainingSize) { + assert(handler.pendingBuffer); + auto newChunkSize = std::min(handler.remainingSize, size); + memcpy(handler.pendingBuffer + handler.pendingSize, start, newChunkSize); + handler.pendingSize += newChunkSize; + handler.remainingSize -= newChunkSize; + if (handler.remainingSize == 0) { + // One recursion should be enough. + decode_websocket(handler.pendingBuffer, handler.pendingSize, handler); + delete[] handler.pendingBuffer; + handler.pendingBuffer = nullptr; + } + } + handler.beginChunk(); + // The + 2 is there because we need at least 2 bytes. + while (cur - start < size) { + WebSocketFrameTiny* header = (WebSocketFrameTiny*)cur; + size_t payloadSize = 0; + size_t headerSize = 0; + if ((cur + 2 - start >= size) || + ((cur + 2 + 2 - start >= size) && header->len >= 126) || + ((cur + 2 + 8 - start >= size) && header->len == 127)) { + // We do not have enough bytes for a tiny header. We copy in the pending header + handler.pendingHeaderSize = size - (cur - start); + handler.pendingHeader = new char[handler.pendingHeaderSize]; + memcpy(handler.pendingHeader, cur, handler.pendingHeaderSize); + break; + } + + if (header->len < 126) { + payloadSize = header->len; + headerSize = 2 + (header->mask ? 4 : 0); + } else if (header->len == 126) { + WebSocketFrameShort* headerSmall = (WebSocketFrameShort*)cur; + payloadSize = ntohs(headerSmall->len16); + headerSize = 2 + 2 + (header->mask ? 4 : 0); + } else if (header->len == 127) { + WebSocketFrameHuge* headerSmall = (WebSocketFrameHuge*)cur; + payloadSize = ntohs(headerSmall->len64); + headerSize = 2 + 8 + (header->mask ? 4 : 0); + } + size_t availableSize = size - (cur - start); + if (availableSize < payloadSize + headerSize) { + handler.remainingSize = payloadSize + headerSize - availableSize; + handler.pendingSize = availableSize; + handler.pendingBuffer = new char[payloadSize + headerSize]; + memcpy(handler.pendingBuffer, cur, availableSize); + break; + } + if (header->mask) { + int32_t mask = *(int32_t*)(cur + headerSize - 4); + memunmask(cur + headerSize, payloadSize, mask); + } + handler.frame(cur + headerSize, payloadSize); + cur += headerSize + payloadSize; + } + handler.endChunk(); +} + +std::string encode_websocket_handshake_request(const char* endpoint, const char* protocol, int version, char const* nonce, + std::vector<std::pair<std::string, std::string>> headers) +{ + char const* res = + "GET {} HTTP/1.1\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: {}\r\n" + "Sec-WebSocket-Protocol: {}\r\n" + "Sec-WebSocket-Version: {}\r\n" + "{}\r\n"; + std::string encodedHeaders; + for (auto [k, v] : headers) { + encodedHeaders += std::string(fmt::format("{}: {}\r\n", k, v)); + } + return fmt::format(res, endpoint, nonce, protocol, version, encodedHeaders); +} + +std::string HTTPParserHelpers::calculateAccept(const char* nonce) +{ + std::string reply = std::string(nonce) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + char sha[21]; + SHA1(sha, reply.data(), reply.size()); + char base[64]; + base64_encode(base, 64, (unsigned char*)sha, 20); + return fmt::format("{}", base); +} + +std::string encode_websocket_handshake_reply(char const* nonce) +{ + char const* res = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: {}\r\n\r\n"; + return fmt::format(res, HTTPParserHelpers::calculateAccept(nonce)); +} + +void parse_http_request(char* start, size_t size, HTTPParser* parser) +{ + enum HTTPState state = HTTPState::IN_START; + // Too short, let's try again... + if (size < 2) { + parser->remaining += std::string_view(start, size); + } + char* cur = start; + char* next = cur; + std::string_view lastToken(cur, 0); + std::string_view lastKey; + std::string_view lastValue; + std::string lastError; + if (parser->states.empty()) { + parser->states.push_back(HTTPState::IN_START); + } + char const* delimiters = nullptr; + char const* skippable = nullptr; + char const* separator = nullptr; + char const* spaces = "\t \v"; + char const* colon = ":"; + char const* newline = "\r\n"; + bool done = false; + + while (!done) { + HTTPState state = parser->states.back(); + parser->states.pop_back(); + switch (state) { + case HTTPState::IN_START: + parser->states.push_back(HTTPState::BEGIN_METHOD); + break; + case HTTPState::IN_START_REPLY: + parser->states.push_back(HTTPState::BEGIN_REPLY_VERSION); + break; + case HTTPState::BEGIN_REPLY_VERSION: + parser->states.push_back(HTTPState::END_REPLY_VERSION); + parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS); + delimiters = spaces; + break; + case HTTPState::END_REPLY_VERSION: + parser->replyVersion(lastToken); + parser->states.push_back(HTTPState::BEGIN_REPLY_CODE); + parser->states.push_back(HTTPState::IN_SKIP_CHARS); + skippable = spaces; + break; + case HTTPState::BEGIN_REPLY_CODE: + parser->states.push_back(HTTPState::END_REPLY_CODE); + parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS); + delimiters = spaces; + break; + case HTTPState::END_REPLY_CODE: + parser->replyCode(lastToken); + parser->states.push_back(HTTPState::BEGIN_REPLY_MESSAGE); + parser->states.push_back(HTTPState::IN_SKIP_CHARS); + skippable = spaces; + break; + case HTTPState::BEGIN_REPLY_MESSAGE: + parser->states.push_back(HTTPState::END_REPLY_MESSAGE); + parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR); + separator = newline; + break; + case HTTPState::END_REPLY_MESSAGE: + parser->replyMessage(lastToken); + parser->states.push_back(HTTPState::BEGIN_HEADERS); + break; + case HTTPState::BEGIN_METHOD: + parser->states.push_back(HTTPState::END_METHOD); + parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS); + delimiters = spaces; + break; + case HTTPState::END_METHOD: + parser->method(lastToken); + parser->states.push_back(HTTPState::BEGIN_TARGET); + parser->states.push_back(HTTPState::IN_SKIP_CHARS); + skippable = spaces; + break; + case HTTPState::BEGIN_TARGET: + parser->states.push_back(HTTPState::END_TARGET); + parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS); + delimiters = spaces; + break; + case HTTPState::END_TARGET: + parser->target(lastToken); + parser->states.push_back(HTTPState::BEGIN_VERSION); + parser->states.push_back(HTTPState::IN_SKIP_CHARS); + skippable = spaces; + break; + case HTTPState::BEGIN_VERSION: + parser->states.push_back(HTTPState::END_VERSION); + parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR); + separator = newline; + break; + case HTTPState::END_VERSION: + parser->version(lastToken); + parser->states.push_back(HTTPState::BEGIN_HEADERS); + break; + case HTTPState::BEGIN_HEADERS: + parser->states.push_back(HTTPState::BEGIN_HEADER); + break; + case HTTPState::BEGIN_HEADER: + parser->states.push_back(HTTPState::BEGIN_HEADER_KEY); + break; + case HTTPState::BEGIN_HEADER_KEY: + parser->states.push_back(HTTPState::END_HEADER_KEY); + parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR); + separator = colon; + break; + case HTTPState::END_HEADER_KEY: + lastKey = lastToken; + parser->states.push_back(HTTPState::BEGIN_HEADER_VALUE); + parser->states.push_back(HTTPState::IN_SKIP_CHARS); + skippable = spaces; + break; + case HTTPState::BEGIN_HEADER_VALUE: + parser->states.push_back(HTTPState::END_HEADER_VALUE); + parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR); + separator = newline; + break; + case HTTPState::END_HEADER_VALUE: + lastValue = lastToken; + parser->states.push_back(HTTPState::END_HEADER); + break; + case HTTPState::END_HEADER: + if (strncmp("\r\n", next, 2) == 0) { + parser->header(lastKey, lastValue); + parser->states.push_back(HTTPState::END_HEADERS); + next += 2; + cur = next; + } else { + parser->header(lastKey, lastValue); + parser->states.push_back(HTTPState::BEGIN_HEADER); + cur = next; + } + break; + case HTTPState::END_HEADERS: + parser->endHeaders(); + parser->states.push_back(HTTPState::BEGIN_BODY); + break; + case HTTPState::BEGIN_BODY: { + size_t bodySize = size - (cur - start); + parser->body(cur, bodySize); + next = cur + bodySize; + cur = next; + parser->states.push_back(HTTPState::BEGIN_BODY); + parser->states.push_back(HTTPState::IN_DONE); + } break; + case HTTPState::IN_SKIP_CHARS: + while (true) { + if (next - start == size) { + parser->remaining += std::string_view(cur, next - cur); + } + if (strchr(skippable, *next)) { + next++; + continue; + } + cur = next; + break; + } + break; + case HTTPState::IN_SEPARATOR: + if (memcmp(separator, cur, strlen(separator)) != 0) { + parser->states.push_back(HTTPState::IN_ERROR); + break; + } + next += strlen(separator); + cur = next; + break; + case HTTPState::IN_CAPTURE_DELIMITERS: + while (true) { + if (next - start == size) { + parser->remaining += std::string_view(cur, next - cur); + } + if (strchr(delimiters, *next) == nullptr) { + next++; + continue; + } + lastToken = std::string_view(cur, next - cur); + cur = next; + break; + } + break; + case HTTPState::IN_CAPTURE_SEPARATOR: + while (true) { + if (next + strlen(separator) - start == size) { + parser->remaining += std::string_view(cur, next - cur); + } + if (memcmp(separator, next, strlen(separator)) != 0) { + next++; + continue; + } + lastToken = std::string_view(cur, next - cur); + next += strlen(separator); + cur = next; + break; + } + break; + case HTTPState::IN_DONE: + // The only case in which there can be a pending state when IN_DONE, is if + // we plan to resume processing. + if (parser->states.size() == 1 && parser->states.back() == HTTPState::BEGIN_BODY) { + done = true; + } else if (parser->states.empty()) { + done = true; + } else { + parser->states.push_back(HTTPState::IN_ERROR); + } + break; + case HTTPState::IN_ERROR: + parser->error = lastError; + parser->states.clear(); + done = true; + break; + default: + parser->states.push_back(HTTPState::IN_ERROR); + break; + } + } +} + +std::pair<std::string, unsigned short> parse_websocket_url(char const* url) +{ + std::string s = url; + if (s == "ws://") { + s = "ws://127.0.0.1:8080"; + } + const std::regex urlMatcher("^ws://([0-9-_.]+)[:]([0-9]+)$"); + std::smatch parts; + if (!std::regex_match(s, parts, urlMatcher)) { + throw runtime_error_f( + "Unable to parse driver client url: %s.\n" + "Format should be ws://[<driver ip>:<port>] e.g. ws://127.0.0.1:8080 or just ws://"); + } + std::string ip = std::string{parts[1]}; + auto portS = std::string(parts[2]); + unsigned short port = std::stoul(portS); + return {ip, port}; +} +} // namespace o2::framework diff --git a/Framework/Core/src/HTTPParser.h b/Framework/Core/src/HTTPParser.h new file mode 100644 index 0000000000000..14f3872de6e0f --- /dev/null +++ b/Framework/Core/src/HTTPParser.h @@ -0,0 +1,221 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_HTTPPARSER_H_ +#define O2_FRAMEWORK_HTTPPARSER_H_ + +#include "Framework/Endian.h" +#include <fmt/format.h> +#include <uv.h> +#include <string> +#include <vector> +#include <map> + +namespace o2::framework +{ + +struct __attribute__((__packed__)) WebSocketFrameTiny { +#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN + unsigned char opcode : 4; + unsigned char rsv3 : 1; + unsigned char rsv2 : 1; + unsigned char rsv1 : 1; + unsigned char fin : 1; + unsigned char len : 7; + unsigned char mask : 1; +#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN + unsigned char fin : 1; + unsigned char rsv1 : 1; + unsigned char rsv2 : 1; + unsigned char rsv3 : 1; + unsigned char opcode : 4; + unsigned char mask : 1; + unsigned char len : 7; +#else +#error Uknown endiannes +#endif +}; + +struct __attribute__((__packed__)) WebSocketFrameShort { +#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN + unsigned char opcode : 4; + unsigned char rsv3 : 1; + unsigned char rsv2 : 1; + unsigned char rsv1 : 1; + unsigned char fin : 1; + unsigned char len : 7; + unsigned char mask : 1; +#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN + unsigned char fin : 1; + unsigned char rsv1 : 1; + unsigned char rsv2 : 1; + unsigned char rsv3 : 1; + unsigned char opcode : 4; + unsigned char mask : 1; + unsigned char len : 7; +#else +#error Uknown endiannes +#endif + uint16_t len16; +}; + +struct __attribute__((__packed__)) WebSocketFrameHuge { +#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN + unsigned char opcode : 4; + unsigned char rsv3 : 1; + unsigned char rsv2 : 1; + unsigned char rsv1 : 1; + unsigned char fin : 1; + unsigned char len : 7; + unsigned char mask : 1; +#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN + unsigned char fin : 1; + unsigned char rsv1 : 1; + unsigned char rsv2 : 1; + unsigned char rsv3 : 1; + unsigned char opcode : 4; + unsigned char mask : 1; + unsigned char len : 7; +#else +#error Uknown endiannes +#endif + uint64_t len64; +}; + +enum struct WebSocketFrameKind { + Tiny, + Short, + Huge +}; + +enum struct WebSocketOpCode : uint8_t { + Continuation = 0, + Text = 1, + Binary = 2, + Close = 8, + Ping = 9, + Pong = 10 +}; + +/// Encodes the request handshake for a given path / protocol / version. +/// @a path is the path of the websocket endpoint +/// @a protocol is the protocol required for the websocket connection +/// @a version is the protocol version +/// @a nonce is a unique randomly selected 16-byte value that has been base64-encoded. +/// @a headers with extra headers to be added to the request +std::string encode_websocket_handshake_request(const char* path, const char* protocol, int version, char const* nonce, + std::vector<std::pair<std::string, std::string>> headers = {}); + +/// Encodes the server reply for a given websocket connection +/// @a nonce the nonce of the request. +std::string encode_websocket_handshake_reply(char const* nonce); + +/// Encodes the buffer @a src which is @a size long to a number of buffers suitable to be sent via libuv. +/// If @a binary is provided the binary bit is set. +/// If @a mask is non zero, payload will be xored with the mask, as required by the WebSockets RFC +void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, size_t size, WebSocketOpCode opcode, uint32_t mask); + +/// An handler for a websocket message stream. +struct WebSocketHandler { + virtual ~WebSocketHandler() = default; + + /// Invoked when all the headers are received. + virtual void headers(std::map<std::string, std::string> const& headers){}; + /// FIXME: not implemented + virtual void beginFragmentation(){}; + /// Invoked when a frame it's parsed. Notice you do not own the data and you must + /// not free the memory. + virtual void frame(char const* frame, size_t s) {} + /// Invoked before processing the next round of input + virtual void beginChunk() {} + /// Invoked whenever we have no more input to process + virtual void endChunk() {} + /// FIXME: not implemented + virtual void endFragmentation() {} + /// FIXME: not implemented + virtual void control(char const* frame, size_t s) {} + + /// Bytes which are still to be received for the previous, half delivered frame. + size_t remainingSize = 0; + /// Bytes which are already there from the previous, half delivered frame. + size_t pendingSize = 0; + /// A buffer large enough to contain the next frame to be processed. + char* pendingBuffer = nullptr; + /// Bytes from an incomplete header + size_t pendingHeaderSize = 0; + char* pendingHeader = nullptr; +}; + +/// Decoder for websocket data. For now we assume that the frame was not split. However multiple +/// frames might be present. +void decode_websocket(char* src, size_t size, WebSocketHandler& handler); + +enum struct HTTPState { + IN_START, + IN_START_REPLY, + BEGIN_REPLY_VERSION, + END_REPLY_VERSION, + BEGIN_REPLY_CODE, + END_REPLY_CODE, + BEGIN_REPLY_MESSAGE, + END_REPLY_MESSAGE, + BEGIN_METHOD, + END_METHOD, + BEGIN_TARGET, + END_TARGET, + BEGIN_VERSION, + END_VERSION, + BEGIN_HEADERS, + BEGIN_HEADER, + BEGIN_HEADER_KEY, + END_HEADER_KEY, + BEGIN_HEADER_VALUE, + END_HEADER_VALUE, + END_HEADER, + END_HEADERS, + BEGIN_BODY, + IN_DONE, + IN_ERROR, + IN_SKIP_CHARS, /// skip any "delimiters" char. + IN_CAPTURE_DELIMITERS, /// capture until any or the "delimiters" characters + IN_CAPTURE_SEPARATOR, /// capture until a specific "separator" + IN_SEPARATOR, /// skip a specific "separator" + IN_CHUNKED +}; + +struct HTTPParser { + std::string remaining; + std::string error; + std::vector<HTTPState> states; + virtual void method(std::string_view const& s){}; + virtual void target(std::string_view const& s){}; + virtual void version(std::string_view const& s){}; + virtual void header(std::string_view const& k, std::string_view const& v){}; + virtual void endHeaders(){}; + /// Invoked whenever we are parsing data. + /// In order to allow for xoring (as required by the websocket standard) + /// in place, we pass it as a mutable pointer. + virtual void body(char* data, size_t s){}; + virtual void replyVersion(std::string_view const& s){}; + virtual void replyCode(std::string_view const& s){}; + virtual void replyMessage(std::string_view const& s){}; +}; + +struct HTTPParserHelpers { + /// Helper to calculate the reply to a nonce + static std::string calculateAccept(const char* nonce); +}; + +void parse_http_request(char* start, size_t size, HTTPParser* parser); + +std::pair<std::string, unsigned short> parse_websocket_url(const char* s); +} // namespace o2::framework +#endif diff --git a/Framework/Core/src/HistogramRegistry.cxx b/Framework/Core/src/HistogramRegistry.cxx index b7ec3d9c0060c..5ece83eaf1f8e 100644 --- a/Framework/Core/src/HistogramRegistry.cxx +++ b/Framework/Core/src/HistogramRegistry.cxx @@ -1,52 +1,114 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/HistogramRegistry.h" +#include <regex> +#include <TList.h> namespace o2::framework { -// define histogram callbacks for runtime histogram creation -#define CALLB(HType) \ - { \ - k##HType, \ - [](HistogramSpec const& histSpec) { \ - return HistFactory::createHistVariant<HType>(histSpec); \ - } \ +constexpr HistogramRegistry::HistName::HistName(char const* const name) + : str(name), + hash(compile_time_hash(name)), + idx(hash & REGISTRY_BITMASK) +{ +} + +HistogramRegistry::HistogramRegistry(char const* const name, std::vector<HistogramSpec> histSpecs, OutputObjHandlingPolicy policy, bool sortHistos, bool createRegistryDir) + : mName(name), mPolicy(policy), mRegistryKey(), mRegistryValue(), mSortHistos(sortHistos), mCreateRegistryDir(createRegistryDir) +{ + mRegistryKey.fill(0u); + for (auto& histSpec : histSpecs) { + insert(histSpec); } +} -const std::map<HistType, std::function<HistPtr(const HistogramSpec&)>> HistFactory::HistogramCreationCallbacks{ - CALLB(TH1D), CALLB(TH1F), CALLB(TH1I), CALLB(TH1C), CALLB(TH1S), - CALLB(TH2D), CALLB(TH2F), CALLB(TH2I), CALLB(TH2C), CALLB(TH2S), - CALLB(TH3D), CALLB(TH3F), CALLB(TH3I), CALLB(TH3C), CALLB(TH3S), - CALLB(THnD), CALLB(THnF), CALLB(THnI), CALLB(THnC), CALLB(THnS), CALLB(THnL), - CALLB(THnSparseD), CALLB(THnSparseF), CALLB(THnSparseI), CALLB(THnSparseC), CALLB(THnSparseS), CALLB(THnSparseL), - CALLB(TProfile), CALLB(TProfile2D), CALLB(TProfile3D), - //CALLB(StepTHnF), CALLB(StepTHnD) -}; +// return the OutputSpec associated to the HistogramRegistry +OutputSpec const HistogramRegistry::spec() +{ + header::DataDescription desc{}; + auto lhash = compile_time_hash(mName.data()); + std::memset(desc.str, '_', 16); + std::stringstream s; + s << std::hex << lhash; + s << std::hex << mTaskHash; + s << std::hex << reinterpret_cast<uint64_t>(this); + std::memcpy(desc.str, s.str().data(), 12); + return OutputSpec{OutputLabel{mName}, "ATSK", desc, 0}; +} -#undef CALLB +OutputRef HistogramRegistry::ref() +{ + return OutputRef{std::string{mName}, 0, o2::header::Stack{OutputObjHeader{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash}}}; +} -void HistogramRegistry::add(const HistogramSpec& histSpec) +void HistogramRegistry::setHash(uint32_t hash) { - insert(histSpec); + mTaskHash = hash; } -void HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2) +// create histogram from specification and insert it into the registry +HistPtr HistogramRegistry::insert(const HistogramSpec& histSpec) { - insert({name, title, histConfigSpec, callSumw2}); + validateHistName(histSpec.name.data(), histSpec.hash); + const uint32_t idx = imask(histSpec.hash); + for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) { + TObject* rawPtr = nullptr; + std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(idx + i)]); + if (!rawPtr) { + registerName(histSpec.name); + mRegistryKey[imask(idx + i)] = histSpec.hash; + mRegistryValue[imask(idx + i)] = HistFactory::createHistVariant(histSpec); + lookup += i; + return mRegistryValue[imask(idx + i)]; + } + } + LOGF(FATAL, R"(Internal array of HistogramRegistry "%s" is full.)", mName); + return HistPtr(); +} + +// helper function that checks if histogram name can be used in registry +void HistogramRegistry::validateHistName(const char* name, const uint32_t hash) +{ + // validate that hash is unique + auto it = std::find(mRegistryKey.begin(), mRegistryKey.end(), hash); + if (it != mRegistryKey.end()) { + auto idx = it - mRegistryKey.begin(); + std::string collidingName{}; + std::visit([&](const auto& hist) { collidingName = hist->GetName(); }, mRegistryValue[idx]); + LOGF(FATAL, R"(Hash collision in HistogramRegistry "%s"! Please rename histogram "%s" or "%s".)", mName, name, collidingName); + } + // validate that name contains only allowed characters + /* + TODO: exactly determine constraints for valid histogram names + if (!std::regex_match(name, std::regex("[A-Za-z0-9\-_/]+"))) { + LOGF(FATAL, R"(Histogram name "%s" contains invalid characters.)", name); + } + */ } -void HistogramRegistry::add(char const* const name, char const* const title, HistType histType, std::vector<AxisSpec> axes, bool callSumw2) +HistPtr HistogramRegistry::add(const HistogramSpec& histSpec) { - insert({name, title, {histType, axes}, callSumw2}); + return insert(histSpec); +} + +HistPtr HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2) +{ + return insert({name, title, histConfigSpec, callSumw2}); +} + +HistPtr HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2) +{ + return insert({name, title, {histType, axes}, callSumw2}); } // store a copy of an existing histogram (or group of histograms) under a different name @@ -79,21 +141,39 @@ void HistogramRegistry::addClone(const std::string& source, const std::string& t } // function to query if name is already in use -bool HistogramRegistry::contains(const uint32_t id, char const* const name) +bool HistogramRegistry::contains(const HistName& histName) { // check for all occurances of the hash auto iter = mRegistryKey.begin(); - while ((iter = std::find(iter, mRegistryKey.end(), id)) != mRegistryKey.end()) { + while ((iter = std::find(iter, mRegistryKey.end(), histName.hash)) != mRegistryKey.end()) { const char* curName = nullptr; std::visit([&](auto&& hist) { if(hist) { curName = hist->GetName(); } }, mRegistryValue[iter - mRegistryKey.begin()]); // if hash is the same, make sure that name is indeed the same - if (strcmp(curName, name) == 0) { + if (strcmp(curName, histName.str) == 0) { return true; } } return false; } +// get rough estimate for size of histogram stored in registry +double HistogramRegistry::getSize(const HistName& histName, double fillFraction) +{ + double size{}; + std::visit([&fillFraction, &size](auto&& hist) { size = HistFiller::getSize(hist, fillFraction); }, mRegistryValue[getHistIndex(histName)]); + return size; +} + +// get rough estimate for size of all histograms stored in registry +double HistogramRegistry::getSize(double fillFraction) +{ + double size{}; + for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) { + std::visit([&fillFraction, &size](auto&& hist) { if(hist) { size += HistFiller::getSize(hist, fillFraction);} }, mRegistryValue[j]); + } + return size; +} + // print some useful meta-info about the stored histograms void HistogramRegistry::print(bool showAxisDetails) { @@ -136,8 +216,19 @@ void HistogramRegistry::print(bool showAxisDetails) } else if constexpr (std::is_base_of_v<TH1, T>) { nDim = hist->GetDimension(); } + TAxis* axis{nullptr}; for (int d = 0; d < nDim; ++d) { - TAxis* axis = HistFactory::getAxis(d, hist); + if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) { + axis = hist->GetAxis(d); + } else { + if (d == 0) { + axis = hist->GetXaxis(); + } else if (d == 1) { + axis = hist->GetYaxis(); + } else if (d == 2) { + axis = hist->GetZaxis(); + } + } LOGF(INFO, "- Axis %d: %-20s (%d bins)", d, axis->GetTitle(), axis->GetNbins()); } } @@ -150,7 +241,7 @@ void HistogramRegistry::print(bool showAxisDetails) LOGF(INFO, "%s\"%s\"", std::string((int)(0.5 * titleString.size() - (1 + 0.5 * mName.size())), ' '), mName); std::sort(mRegisteredNames.begin(), mRegisteredNames.end()); for (auto& curHistName : mRegisteredNames) { - std::visit(printHistInfo, mRegistryValue[getHistIndex(curHistName.data())]); + std::visit(printHistInfo, mRegistryValue[getHistIndex(HistName{curHistName.data()})]); } std::string totalSizeInfo{}; if (containsSparseHist) { @@ -165,6 +256,9 @@ void HistogramRegistry::print(bool showAxisDetails) } LOGF(INFO, "%s", std::string(titleString.size(), '='), titleString); LOGF(INFO, "Total: %d histograms, ca. %s", nHistos, totalSizeInfo); + if (lookup) { + LOGF(INFO, "Due to index collisions, histograms were shifted by %d registry slots in total.", lookup); + } LOGF(INFO, "%s", std::string(titleString.size(), '='), titleString); LOGF(INFO, ""); } @@ -175,9 +269,9 @@ TList* HistogramRegistry::operator*() TList* list = new TList(); list->SetName(mName.data()); - for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) { + for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) { TNamed* rawPtr = nullptr; - std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[j]); + std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[i]); if (rawPtr) { std::deque<std::string> path = splitPath(rawPtr->GetName()); std::string name = path.back(); @@ -271,18 +365,18 @@ void HistogramRegistry::registerName(const std::string& name) int depth = path.size(); for (auto& step : path) { if (step.empty()) { - LOGF(FATAL, "Found empty group name in path for histogram %s.", name); + LOGF(FATAL, R"(Found empty group name in path for histogram "%s".)", name); } cumulativeName += step; for (auto& curName : mRegisteredNames) { // there is already a histogram where we want to put a folder or histogram if (cumulativeName == curName) { - LOGF(FATAL, "Histogram name %s is not compatible with existing names.", name); + LOGF(FATAL, R"(Histogram name "%s" is not compatible with existing names.)", name); } // for the full new histogram name we need to check that none of the existing histograms already uses this as a group name if (depth == 1) { if (curName.rfind(cumulativeName, 0) == 0 && curName.size() > cumulativeName.size() && curName.at(cumulativeName.size()) == '/') { - LOGF(FATAL, "Histogram name %s is not compatible with existing names.", name); + LOGF(FATAL, R"(Histogram name "%s" is not compatible with existing names.)", name); } } } diff --git a/Framework/Core/src/HistogramSpec.cxx b/Framework/Core/src/HistogramSpec.cxx new file mode 100644 index 0000000000000..288dc435a9788 --- /dev/null +++ b/Framework/Core/src/HistogramSpec.cxx @@ -0,0 +1,227 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/HistogramSpec.h" +#include "Framework/RuntimeError.h" + +namespace o2::framework +{ + +// main function for creating arbirtary histograms +template <typename T> +std::unique_ptr<T> HistFactory::createHist(const HistogramSpec& histSpec) +{ + constexpr std::size_t MAX_DIM{10}; + const std::size_t nAxes{histSpec.config.axes.size()}; + if (nAxes == 0 || nAxes > MAX_DIM) { + LOGF(FATAL, "The histogram specification contains no (or too many) axes."); + return nullptr; + } + + int nBins[MAX_DIM]{0}; + double lowerBounds[MAX_DIM]{0.}; + double upperBounds[MAX_DIM]{0.}; + + // first figure out number of bins and dimensions + for (std::size_t i = 0; i < nAxes; i++) { + nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; + lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); + upperBounds[i] = histSpec.config.axes[i].binEdges.back(); + } + + // create histogram + std::unique_ptr<T> hist{generateHist<T>(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; + if (!hist) { + LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); + return nullptr; + } + + // set axis properties + for (std::size_t i = 0; i < nAxes; i++) { + TAxis* axis{getAxis(i, hist.get())}; + if (axis) { + if (histSpec.config.axes[i].title) { + axis->SetTitle((*histSpec.config.axes[i].title).data()); + } + + // this helps to have axes not only called 0,1,2... in ndim histos + if constexpr (std::is_base_of_v<THnBase, T>) { + if (histSpec.config.axes[i].name) { + axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); + } + } + + // move the bin edges in case a variable binning was requested + if (!histSpec.config.axes[i].nBins) { + if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { + LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); + return nullptr; + } + axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); + } + } + } + if (histSpec.callSumw2) { + hist->Sumw2(); + } + return hist; +} + +// create histogram and return it casted to the correct alternative held in HistPtr variant +template <typename T> +HistPtr HistFactory::createHistVariant(const HistogramSpec& histSpec) +{ + if (auto hist = castToVariant(createHist<T>(histSpec))) { + return *hist; + } else { + throw runtime_error("Histogram was not created properly."); + } +} + +// runtime version of the above +HistPtr HistFactory::createHistVariant(const HistogramSpec& histSpec) +{ + if (histSpec.config.type == HistType::kUndefinedHist) { + throw runtime_error("Histogram type was not specified."); + } else { + return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); + } +} + +// helper function to get the axis via index for any type of root histogram +template <typename T> +TAxis* HistFactory::getAxis(const int i, T* hist) +{ + if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) { + return hist->GetAxis(i); + } else { + if (i == 0) { + return hist->GetXaxis(); + } else if (i == 1) { + return hist->GetYaxis(); + } else if (i == 2) { + return hist->GetZaxis(); + } else { + return nullptr; + } + } +} + +// helper function to generate the actual histograms +template <typename T> +T* HistFactory::generateHist(const std::string& name, const std::string& title, const std::size_t nDim, + const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps) +{ + if constexpr (std::is_base_of_v<StepTHn, T>) { + return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v<THnBase, T>) { + return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v<TH3, T>) { + return (nDim != 3) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], + nBins[2], lowerBounds[2], upperBounds[2]); + } else if constexpr (std::is_base_of_v<TH2, T>) { + return (nDim != 2) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); + } else if constexpr (std::is_base_of_v<TH1, T>) { + return (nDim != 1) + ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); + } + return nullptr; +} + +// helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant +template <typename T> +std::optional<HistPtr> HistFactory::castToVariant(std::shared_ptr<TObject> obj) +{ + if (obj->InheritsFrom(T::Class())) { + return std::static_pointer_cast<T>(obj); + } + return std::nullopt; +} + +template <typename T, typename Next, typename... Rest> +std::optional<HistPtr> HistFactory::castToVariant(std::shared_ptr<TObject> obj) +{ + if (auto hist = castToVariant<T>(obj)) { + return hist; + } + return castToVariant<Next, Rest...>(obj); +} + +std::optional<HistPtr> HistFactory::castToVariant(std::shared_ptr<TObject> obj) +{ + if (obj) { + // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 + return castToVariant<THn, THnSparse, TProfile3D, TH3, TProfile2D, TH2, TProfile, TH1, StepTHn>(obj); + } + return std::nullopt; +} + +// explicitly instantiate createHist templates for all histogram types +#define EXPIMPL(HType) \ + template std::unique_ptr<HType> HistFactory::createHist<HType>(const HistogramSpec& histSpec); +EXPIMPL(TH1D); +EXPIMPL(TH1F); +EXPIMPL(TH1I); +EXPIMPL(TH1C); +EXPIMPL(TH1S); +EXPIMPL(TH2D); +EXPIMPL(TH2F); +EXPIMPL(TH2I); +EXPIMPL(TH2C); +EXPIMPL(TH2S); +EXPIMPL(TH3D); +EXPIMPL(TH3F); +EXPIMPL(TH3I); +EXPIMPL(TH3C); +EXPIMPL(TH3S); +EXPIMPL(THnD); +EXPIMPL(THnF); +EXPIMPL(THnI); +EXPIMPL(THnC); +EXPIMPL(THnS); +EXPIMPL(THnL); +EXPIMPL(THnSparseD); +EXPIMPL(THnSparseF); +EXPIMPL(THnSparseI); +EXPIMPL(THnSparseC); +EXPIMPL(THnSparseS); +EXPIMPL(THnSparseL); +EXPIMPL(TProfile); +EXPIMPL(TProfile2D); +EXPIMPL(TProfile3D); +EXPIMPL(StepTHnF); +EXPIMPL(StepTHnD) +#undef EXPIMPL + +// define histogram callbacks for runtime histogram creation +#define CALLB(HType) \ + { \ + k##HType, \ + [](HistogramSpec const& histSpec) { \ + return HistFactory::createHistVariant<HType>(histSpec); \ + } \ + } +const std::map<HistType, std::function<HistPtr(const HistogramSpec&)>> HistFactory::HistogramCreationCallbacks{ + CALLB(TH1D), CALLB(TH1F), CALLB(TH1I), CALLB(TH1C), CALLB(TH1S), + CALLB(TH2D), CALLB(TH2F), CALLB(TH2I), CALLB(TH2C), CALLB(TH2S), + CALLB(TH3D), CALLB(TH3F), CALLB(TH3I), CALLB(TH3C), CALLB(TH3S), + CALLB(THnD), CALLB(THnF), CALLB(THnI), CALLB(THnC), CALLB(THnS), CALLB(THnL), + CALLB(THnSparseD), CALLB(THnSparseF), CALLB(THnSparseI), CALLB(THnSparseC), CALLB(THnSparseS), CALLB(THnSparseL), + CALLB(TProfile), CALLB(TProfile2D), CALLB(TProfile3D), + CALLB(StepTHnF), CALLB(StepTHnD)}; +#undef CALLB + +} // namespace o2::framework diff --git a/Framework/Core/src/InputRecord.cxx b/Framework/Core/src/InputRecord.cxx index 48ff01ddda2f5..3f3ce09519ec4 100644 --- a/Framework/Core/src/InputRecord.cxx +++ b/Framework/Core/src/InputRecord.cxx @@ -1,13 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/InputSpec.h" #include <fairmq/FairMQMessage.h> #include <cassert> @@ -30,9 +32,9 @@ namespace o2::framework { InputRecord::InputRecord(std::vector<InputRoute> const& inputsSchema, - InputSpan&& span) + InputSpan& span) : mInputsSchema{inputsSchema}, - mSpan{std::move(span)} + mSpan{span} { } @@ -57,6 +59,62 @@ int InputRecord::getPos(std::string const& binding) const return this->getPos(binding.c_str()); } +DataRef InputRecord::getByPos(int pos, int part) const +{ + if (pos >= mSpan.size() || pos < 0) { + throw runtime_error_f("Unknown message requested at position %d", pos); + } + if (part > 0 && part >= getNofParts(pos)) { + throw runtime_error_f("Invalid message part index at %d:%d", pos, part); + } + if (pos >= mInputsSchema.size()) { + throw runtime_error_f("Unknown schema at position %d", pos); + } + auto ref = mSpan.get(pos, part); + auto inputIndex = 0; + auto schemaIndex = 0; + for (size_t i = 0; i < mInputsSchema.size(); ++i) { + schemaIndex = i; + auto& route = mInputsSchema[i]; + if (route.timeslice != 0) { + continue; + } + if (inputIndex == pos) { + break; + } + ++inputIndex; + } + ref.spec = &mInputsSchema[schemaIndex].matcher; + return ref; +} + +DataRef InputRecord::getFirstValid(bool throwOnFailure) const +{ + for (size_t i = 0; i < size(); i++) { + auto ref = mSpan.get(i); + if (ref.header != nullptr) { + ref.spec = &mInputsSchema[i].matcher; + return ref; + } + } + if (throwOnFailure) { + throw runtime_error_f("No valid input found out of total ", size()); + } + return {}; +} + +size_t InputRecord::getNofParts(int pos) const +{ + if (pos < 0 || pos >= mSpan.size()) { + return 0; + } + return mSpan.getNofParts(pos); +} +size_t InputRecord::size() const +{ + return mSpan.size(); +} + bool InputRecord::isValid(char const* s) const { DataRef ref = get(s); diff --git a/Framework/Core/src/InputRouteHelpers.cxx b/Framework/Core/src/InputRouteHelpers.cxx new file mode 100644 index 0000000000000..812b23d60bf6e --- /dev/null +++ b/Framework/Core/src/InputRouteHelpers.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "InputRouteHelpers.h" + +namespace o2::framework +{ +size_t InputRouteHelpers::maxLanes(std::vector<InputRoute> const& routes) +{ + size_t maxTimeslice = 0; + for (auto& route : routes) { + maxTimeslice = std::max(maxTimeslice, route.timeslice); + } + + return maxTimeslice + 1; +} +} // namespace o2::framework diff --git a/Framework/Core/src/InputRouteHelpers.h b/Framework/Core/src/InputRouteHelpers.h new file mode 100644 index 0000000000000..f732d69edb4a7 --- /dev/null +++ b/Framework/Core/src/InputRouteHelpers.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_INPUTROUTESHELPERS_H_ +#define O2_FRAMEWORK_INPUTROUTESHELPERS_H_ + +#include "Framework/InputRoute.h" +#include <vector> + +namespace o2::framework +{ + +struct InputRouteHelpers { + /// @return the maximum number of lanes (i.e. max timeslice) which + /// is associated to a set of input @a routes. This is needed to + /// make sure we can reserve a set of slots to the given lane. + static size_t maxLanes(std::vector<InputRoute> const& routes); +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_INPUTROUTESHELPERS_H_ diff --git a/Framework/Core/src/InputSpan.cxx b/Framework/Core/src/InputSpan.cxx new file mode 100644 index 0000000000000..510b55cd0b9b9 --- /dev/null +++ b/Framework/Core/src/InputSpan.cxx @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/InputSpan.h" + +template class std::function<o2::framework::DataRef(size_t)>; +template class std::function<o2::framework::DataRef(size_t, size_t)>; + +namespace o2::framework +{ +InputSpan::InputSpan(std::function<DataRef(size_t)> getter, size_t size) + : mGetter{}, mNofPartsGetter{}, mSize{size} +{ + mGetter = [getter](size_t index, size_t) -> DataRef { + return getter(index); + }; +} + +InputSpan::InputSpan(std::function<DataRef(size_t, size_t)> getter, size_t size) + : mGetter{getter}, mNofPartsGetter{}, mSize{size} +{ +} + +InputSpan::InputSpan(std::function<DataRef(size_t, size_t)> getter, std::function<size_t(size_t)> nofPartsGetter, size_t size) + : mGetter{getter}, mNofPartsGetter{nofPartsGetter}, mSize{size} +{ +} + +} // namespace o2::framework diff --git a/Framework/Core/src/InputSpec.cxx b/Framework/Core/src/InputSpec.cxx index d52adfc24564c..5a6eff28ec241 100644 --- a/Framework/Core/src/InputSpec.cxx +++ b/Framework/Core/src/InputSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -55,6 +56,17 @@ InputSpec::InputSpec(std::string binding_, { } +InputSpec::InputSpec(std::string binding_, + header::DataOrigin const& origin_, + enum Lifetime lifetime_, + std::vector<ConfigParamSpec> const& metadata_) + : binding{binding_}, + matcher{DataSpecUtils::dataDescriptorMatcherFrom(origin_)}, + lifetime{lifetime_}, + metadata{metadata_} +{ +} + InputSpec::InputSpec(std::string binding_, ConcreteDataTypeMatcher const& dataType, enum Lifetime lifetime_, diff --git a/Framework/Core/src/LifetimeHelpers.cxx b/Framework/Core/src/LifetimeHelpers.cxx index 3bd1b26d390ee..4c29ca46b7066 100644 --- a/Framework/Core/src/LifetimeHelpers.cxx +++ b/Framework/Core/src/LifetimeHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,14 +12,23 @@ #include "Framework/DataProcessingHeader.h" #include "Framework/InputSpec.h" #include "Framework/LifetimeHelpers.h" +#include "Framework/DataDescriptorMatcher.h" #include "Framework/Logger.h" #include "Framework/RawDeviceService.h" #include "Framework/ServiceRegistry.h" #include "Framework/TimesliceIndex.h" +#include "Framework/VariableContextHelpers.h" +#include "Framework/DataTakingContext.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "Headers/Stack.h" +#include "CommonConstants/LHCConstants.h" #include "MemoryResources/MemoryResources.h" +#include "CCDB/CcdbApi.h" +#include <typeinfo> +#include <TError.h> +#include <TMemFile.h> #include <curl/curl.h> #include <fairmq/FairMQDevice.h> @@ -28,9 +38,7 @@ using namespace o2::header; using namespace fair; -namespace o2 -{ -namespace framework +namespace o2::framework { namespace @@ -90,7 +98,8 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::chrono::micr if (index.isValid(slot) == false) { continue; } - if (index.getTimesliceForSlot(slot).value == current) { + auto& variables = index.getVariablesForSlot(slot); + if (VariableContextHelpers::getTimeslice(variables).value == current) { return TimesliceSlot{TimesliceSlot::INVALID}; } } @@ -100,7 +109,7 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::chrono::micr data_matcher::VariableContext newContext; newContext.put({0, static_cast<uint64_t>(current)}); newContext.commit(); - auto [action, slot] = index.replaceLRUWith(newContext); + auto [action, slot] = index.replaceLRUWith(newContext, TimesliceId{current}); switch (action) { case TimesliceIndex::ActionTaken::ReplaceObsolete: case TimesliceIndex::ActionTaken::ReplaceUnused: @@ -108,6 +117,7 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::chrono::micr break; case TimesliceIndex::ActionTaken::DropInvalid: case TimesliceIndex::ActionTaken::DropObsolete: + case TimesliceIndex::ActionTaken::Wait: break; } return slot; @@ -116,19 +126,19 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::chrono::micr ExpirationHandler::Checker LifetimeHelpers::expireNever() { - return [](int64_t) -> bool { return false; }; + return [](ServiceRegistry&, int64_t) -> bool { return false; }; } ExpirationHandler::Checker LifetimeHelpers::expireAlways() { - return [](int64_t) -> bool { return true; }; + return [](ServiceRegistry&, int64_t) -> bool { return true; }; } ExpirationHandler::Checker LifetimeHelpers::expireTimed(std::chrono::microseconds period) { auto start = getCurrentTime(); auto last = std::make_shared<decltype(start)>(start); - return [last, period](int64_t) -> bool { + return [last, period](ServiceRegistry&, int64_t) -> bool { auto current = getCurrentTime(); auto delta = current - *last; if (delta > period.count()) { @@ -144,7 +154,23 @@ ExpirationHandler::Checker LifetimeHelpers::expireTimed(std::chrono::microsecond /// expires via this mechanism). ExpirationHandler::Handler LifetimeHelpers::doNothing() { - return [](ServiceRegistry&, PartRef& ref, uint64_t) -> void { return; }; + return [](ServiceRegistry&, PartRef& ref, data_matcher::VariableContext&) -> void { return; }; +} + +// We simply put everything +size_t readToBuffer(void* p, size_t size, size_t nmemb, void* userdata) +{ + if (nmemb == 0) { + return 0; + } + if (size == 0) { + return 0; + } + std::vector<char>* buffer = (std::vector<char>*)userdata; + size_t oldSize = buffer->size(); + buffer->resize(oldSize + nmemb * size); + memcpy(buffer->data() + oldSize, p, nmemb * size); + return size * nmemb; } // We simply put everything in a stringstream and read it afterwards. @@ -159,10 +185,68 @@ size_t readToMessage(void* p, size_t size, size_t nmemb, void* userdata) o2::vector<char>* buffer = (o2::vector<char>*)userdata; size_t oldSize = buffer->size(); buffer->resize(oldSize + nmemb * size); - memcpy(buffer->data() + oldSize, userdata, nmemb * size); + memcpy(buffer->data() + oldSize, p, nmemb * size); return size * nmemb; } +ExpirationHandler::Checker + LifetimeHelpers::expectCTP(std::string const& serverUrl, bool waitForCTP) +{ + return [serverUrl, waitForCTP](ServiceRegistry& services, int64_t timestamp) -> bool { + auto& dataTakingContext = services.get<DataTakingContext>(); + if (waitForCTP == false || dataTakingContext.source == OrbitResetTimeSource::CTP) { + return true; + } + LOG(INFO) << "CTP is not there, fetching."; + std::vector<char> buffer; + CURL* curl = curl_easy_init(); + if (curl == nullptr) { + throw runtime_error("fetchFromCCDBCache: Unable to initialise CURL"); + } + CURLcode res; + std::string path = "CTP/OrbitReset"; + auto url = fmt::format("{}/{}/{}", serverUrl, path, timestamp / 1000); + LOG(INFO) << "Fetching CTP from " << url; + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readToBuffer); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + throw runtime_error_f("Unable to fetch %s from CCDB", url.c_str()); + } + long responseCode; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); + + if (responseCode != 200) { + throw runtime_error_f("HTTP error %d while fetching %s from CCDB", responseCode, url.c_str()); + } + + curl_easy_cleanup(curl); + + Int_t previousErrorLevel = gErrorIgnoreLevel; + gErrorIgnoreLevel = kFatal; + TMemFile memFile("name", const_cast<char*>(buffer.data()), buffer.size(), "READ"); + gErrorIgnoreLevel = previousErrorLevel; + if (memFile.IsZombie()) { + return false; + } + TClass* tcl = TClass::GetClass(typeid(std::vector<Long64_t>)); + void* result = ccdb::CcdbApi::extractFromTFile(memFile, tcl); + if (!result) { + throw runtime_error_f("Couldn't retrieve object corresponding to %s from TFile", tcl->GetName()); + } + memFile.Close(); + std::vector<Long64_t>* ctp = (std::vector<Long64_t>*)result; + LOG(INFO) << "Orbit reset time now at " << (*ctp)[0]; + dataTakingContext.orbitResetTime = (*ctp)[0]; + dataTakingContext.source = OrbitResetTimeSource::CTP; + return true; + }; +} + /// Fetch an object from CCDB if the record is expired. The actual /// name of the object is given by: /// @@ -172,7 +256,7 @@ size_t readToMessage(void* p, size_t size, size_t nmemb, void* userdata) /// \todo this should really be done in the common fetcher. /// \todo provide a way to customize the namespace from the ProcessingContext ExpirationHandler::Handler - LifetimeHelpers::fetchFromCCDBCache(ConcreteDataMatcher const& matcher, + LifetimeHelpers::fetchFromCCDBCache(InputSpec const& spec, std::string const& prefix, std::string const& overrideTimestamp, std::string const& sourceChannel) @@ -185,28 +269,63 @@ ExpirationHandler::Handler if (overrideTimestampMilliseconds) { LOGP(info, "fetchFromCCDBCache: forcing timestamp for conditions to {} milliseconds from epoch UTC", overrideTimestampMilliseconds); } - return [matcher, sourceChannel, serverUrl = prefix, overrideTimestampMilliseconds](ServiceRegistry& services, PartRef& ref, uint64_t timestamp) -> void { + auto matcher = std::get_if<ConcreteDataMatcher>(&spec.matcher); + if (matcher == nullptr) { + throw runtime_error("InputSpec for Conditions must be fully qualified"); + } + return [spec, matcher, sourceChannel, serverUrl = prefix, overrideTimestampMilliseconds](ServiceRegistry& services, PartRef& ref, data_matcher::VariableContext& variables) -> void { // We should invoke the handler only once. assert(!ref.header); assert(!ref.payload); auto& rawDeviceService = services.get<RawDeviceService>(); + auto& dataTakingContext = services.get<DataTakingContext>(); + auto&& transport = rawDeviceService.device()->GetChannel(sourceChannel, 0).Transport(); auto channelAlloc = o2::pmr::getTransportAllocator(transport); - o2::vector<char> payloadBuffer; + o2::vector<char> payloadBuffer{transport->GetMemoryResource()}; payloadBuffer.reserve(10000); // we begin with messages of 10KB - auto payload = o2::pmr::getMessage(std::forward<o2::vector<char>>(payloadBuffer), transport->GetMemoryResource()); CURL* curl = curl_easy_init(); if (curl == nullptr) { throw runtime_error("fetchFromCCDBCache: Unable to initialise CURL"); } CURLcode res; + + // * By default we use the time when the data was created. + // * If an override is specified, we use it. + // * If the orbit reset time comes from CTP, we use it for precise + // timestamp evaluation via the firstTFOrbit + uint64_t timestamp = -1; if (overrideTimestampMilliseconds) { timestamp = overrideTimestampMilliseconds; + } else if (dataTakingContext.source == OrbitResetTimeSource::CTP) { + // Orbit reset time is in microseconds, LHCOrbitNS is in nanoseconds, CCDB uses milliseconds + timestamp = ceilf((VariableContextHelpers::getFirstTFOrbit(variables) * o2::constants::lhc::LHCOrbitNS / 1000 + dataTakingContext.orbitResetTime) / 1000); + } else { + // The timestamp used by DPL is in nanoseconds + timestamp = ceilf(VariableContextHelpers::getTimeslice(variables).value / 1000); + } + + std::string path = ""; + bool runDependent = false; + for (auto& meta : spec.metadata) { + if (meta.name == "ccdb-path") { + path = meta.defaultValue.get<std::string>(); + } + if (meta.name == "ccdb-run-dependent") { + runDependent = meta.defaultValue.get<bool>(); + } + } + if (path.empty()) { + path = fmt::format("{}/{}", matcher->origin, matcher->description); + } + std::string url; + if (runDependent == false) { + url = fmt::format("{}/{}/{}", serverUrl, path, timestamp); + } else { + url = fmt::format("{}/{}/{}/runNumber={}", serverUrl, path, timestamp, dataTakingContext.runNumber); } - auto path = std::string("/") + matcher.origin.as<std::string>() + "/" + matcher.description.as<std::string>() + "/" + std::to_string(timestamp / 1000); - auto url = serverUrl + path; LOG(INFO) << "fetchFromCCDBCache: Fetching " << url; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); @@ -228,18 +347,19 @@ ExpirationHandler::Handler curl_easy_cleanup(curl); DataHeader dh; - dh.dataOrigin = matcher.origin; - dh.dataDescription = matcher.description; - dh.subSpecification = matcher.subSpec; + dh.dataOrigin = matcher->origin; + dh.dataDescription = matcher->description; + dh.subSpecification = matcher->subSpec; // FIXME: should use curl_off_t and CURLINFO_SIZE_DOWNLOAD_T, but // apparently not there on some platforms. double dl; res = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dl); dh.payloadSize = payloadBuffer.size(); - dh.payloadSerializationMethod = gSerializationMethodNone; + dh.payloadSerializationMethod = gSerializationMethodCCDB; DataProcessingHeader dph{timestamp, 1}; auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph}); + auto payload = o2::pmr::getMessage(std::forward<o2::vector<char>>(payloadBuffer), transport->GetMemoryResource()); ref.header = std::move(header); ref.payload = std::move(payload); @@ -253,7 +373,7 @@ ExpirationHandler::Handler /// FIXME: provide a way to customise the histogram from the configuration. ExpirationHandler::Handler LifetimeHelpers::fetchFromQARegistry() { - return [](ServiceRegistry&, PartRef& ref, uint64_t) -> void { + return [](ServiceRegistry&, PartRef& ref, data_matcher::VariableContext&) -> void { throw runtime_error("fetchFromQARegistry: Not yet implemented"); return; }; @@ -264,29 +384,35 @@ ExpirationHandler::Handler LifetimeHelpers::fetchFromQARegistry() /// FIXME: provide a way to customise the histogram from the configuration. ExpirationHandler::Handler LifetimeHelpers::fetchFromObjectRegistry() { - return [](ServiceRegistry&, PartRef& ref, uint64_t) -> void { + return [](ServiceRegistry&, PartRef& ref, data_matcher::VariableContext&) -> void { throw runtime_error("fetchFromObjectRegistry: Not yet implemented"); return; }; } /// Enumerate entries on every invokation. -ExpirationHandler::Handler LifetimeHelpers::enumerate(ConcreteDataMatcher const& matcher, std::string const& sourceChannel) +ExpirationHandler::Handler LifetimeHelpers::enumerate(ConcreteDataMatcher const& matcher, std::string const& sourceChannel, + int64_t orbitOffset, int64_t orbitMultiplier) { using counter_t = int64_t; auto counter = std::make_shared<counter_t>(0); - auto f = [matcher, counter, sourceChannel](ServiceRegistry& services, PartRef& ref, uint64_t timestamp) -> void { + return [matcher, counter, sourceChannel, orbitOffset, orbitMultiplier](ServiceRegistry& services, PartRef& ref, data_matcher::VariableContext& variables) -> void { // We should invoke the handler only once. assert(!ref.header); assert(!ref.payload); auto& rawDeviceService = services.get<RawDeviceService>(); + auto timestamp = VariableContextHelpers::getTimeslice(variables).value; DataHeader dh; dh.dataOrigin = matcher.origin; dh.dataDescription = matcher.description; dh.subSpecification = matcher.subSpec; dh.payloadSize = sizeof(counter_t); dh.payloadSerializationMethod = gSerializationMethodNone; + dh.tfCounter = timestamp; + dh.firstTForbit = timestamp * orbitMultiplier + orbitOffset; + variables.put({data_matcher::FIRSTTFORBIT_POS, dh.firstTForbit}); + variables.put({data_matcher::TFCOUNTER_POS, dh.tfCounter}); DataProcessingHeader dph{timestamp, 1}; @@ -300,8 +426,54 @@ ExpirationHandler::Handler LifetimeHelpers::enumerate(ConcreteDataMatcher const& ref.payload = std::move(payload); (*counter)++; }; +} + +/// Create a dummy message with the provided ConcreteDataMatcher +ExpirationHandler::Handler LifetimeHelpers::dummy(ConcreteDataMatcher const& matcher, std::string const& sourceChannel) +{ + using counter_t = int64_t; + auto counter = std::make_shared<counter_t>(0); + auto f = [matcher, counter, sourceChannel](ServiceRegistry& services, PartRef& ref, data_matcher::VariableContext& variables) -> void { + // We should invoke the handler only once. + assert(!ref.header); + assert(!ref.payload); + auto& rawDeviceService = services.get<RawDeviceService>(); + + auto timestamp = VariableContextHelpers::getTimeslice(variables).value; + DataHeader dh; + dh.dataOrigin = matcher.origin; + dh.dataDescription = matcher.description; + dh.subSpecification = matcher.subSpec; + dh.payloadSize = 0; + dh.payloadSerializationMethod = gSerializationMethodNone; + + { + auto pval = std::get_if<uint32_t>(&variables.get(data_matcher::FIRSTTFORBIT_POS)); + if (pval == nullptr) { + dh.firstTForbit = -1; + } else { + dh.firstTForbit = *pval; + } + } + { + auto pval = std::get_if<uint32_t>(&variables.get(data_matcher::TFCOUNTER_POS)); + if (pval == nullptr) { + dh.tfCounter = timestamp; + } else { + dh.tfCounter = *pval; + } + } + + DataProcessingHeader dph{timestamp, 1}; + + auto&& transport = rawDeviceService.device()->GetChannel(sourceChannel, 0).Transport(); + auto channelAlloc = o2::pmr::getTransportAllocator(transport); + auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph}); + ref.header = std::move(header); + auto payload = rawDeviceService.device()->NewMessage(0); + ref.payload = std::move(payload); + }; return f; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/LocalRootFileService.cxx b/Framework/Core/src/LocalRootFileService.cxx index 6d2ae0b2aab13..d16307fecdd0a 100644 --- a/Framework/Core/src/LocalRootFileService.cxx +++ b/Framework/Core/src/LocalRootFileService.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/LogParsingHelpers.cxx b/Framework/Core/src/LogParsingHelpers.cxx index dc6c19959c9ae..cf47fb2dfbfea 100644 --- a/Framework/Core/src/LogParsingHelpers.cxx +++ b/Framework/Core/src/LogParsingHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ char const* const LogParsingHelpers::LOG_LEVELS[(int)LogParsingHelpers::LogLevel "INFO", "WARNING", "ERROR", + "FATAL", "UNKNOWN"}; using LogLevel = o2::framework::LogParsingHelpers::LogLevel; @@ -52,6 +54,8 @@ LogLevel LogParsingHelpers::parseTokenLevel(std::string_view const s) return LogLevel::Warning; } else if (s.compare(LABELPOS, 8, "[ERROR] ") == 0) { return LogLevel::Error; + } else if (s.compare(LABELPOS, 8, "[FATAL] ") == 0) { + return LogLevel::Fatal; } return LogLevel::Unknown; } diff --git a/Framework/Core/src/MessageContext.cxx b/Framework/Core/src/MessageContext.cxx index 039fbbb590849..1c4053d6507cd 100644 --- a/Framework/Core/src/MessageContext.cxx +++ b/Framework/Core/src/MessageContext.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/Metric2DViewIndex.cxx b/Framework/Core/src/Metric2DViewIndex.cxx index 7f4258e7288fa..98eae954d311d 100644 --- a/Framework/Core/src/Metric2DViewIndex.cxx +++ b/Framework/Core/src/Metric2DViewIndex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/O2ControlHelpers.cxx b/Framework/Core/src/O2ControlHelpers.cxx index e3410b2446bfa..448fd11186328 100644 --- a/Framework/Core/src/O2ControlHelpers.cxx +++ b/Framework/Core/src/O2ControlHelpers.cxx @@ -1,114 +1,422 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "O2ControlHelpers.h" +#include "Framework/O2ControlLabels.h" #include "ChannelSpecHelpers.h" -#include <map> +#include "Framework/Logger.h" + #include <iostream> #include <cstring> +#include <string> +#include <filesystem> + +namespace bfs = std::filesystem; -namespace o2 +namespace o2::framework { -namespace framework + +const char* indScheme = " "; + +namespace implementation { -void dumpDeviceSpec2O2Control(std::ostream& out, - const std::vector<DeviceSpec>& specs, - const std::vector<DeviceExecution>& executions) +std::string taskName(const std::string& workflowName, const std::string& deviceName) { - out << R"(- o2:)" - << "\n"; - out << R"( tasks:)" - << "\n"; - assert(specs.size() == executions.size()); + return workflowName + "-" + deviceName; +} - for (size_t di = 0; di < specs.size(); ++di) { - auto& spec = specs[di]; - auto& execution = executions[di]; +template <typename T> +void dumpChannelBind(std::ostream& dumpOut, const T& channel, std::string indLevel) +{ + dumpOut << indLevel << "- name: " << channel.name << "\n"; + dumpOut << indLevel << indScheme << "type: " << ChannelSpecHelpers::typeAsString(channel.type) << "\n"; + // todo: i shouldn't guess here + dumpOut << indLevel << indScheme << "transport: " << (channel.protocol == ChannelProtocol::IPC ? "shmem" : "zeromq") << "\n"; + dumpOut << indLevel << indScheme << "addressing: " << (channel.protocol == ChannelProtocol::IPC ? "ipc" : "tcp") << "\n"; + dumpOut << indLevel << indScheme << "rateLogging: \"{{ fmq_rate_logging }}\"\n"; +} + +template <typename T> +void dumpChannelConnect(std::ostream& dumpOut, const T& channel, const std::string& binderName, std::string indLevel) +{ + dumpOut << indLevel << "- name: " << channel.name << "\n"; + dumpOut << indLevel << indScheme << "type: " << ChannelSpecHelpers::typeAsString(channel.type) << "\n"; + // todo: i shouldn't guess here + dumpOut << indLevel << indScheme << "transport: " << (channel.protocol == ChannelProtocol::IPC ? "shmem" : "zeromq") << "\n"; + dumpOut << indLevel << indScheme << "target: \"{{ Parent().Path }}." << binderName << ":" << channel.name << "\"\n"; + dumpOut << indLevel << indScheme << "rateLogging: \"{{ fmq_rate_logging }}\"\n"; +} + +struct RawChannel { + std::string_view name; + std::string_view type; + std::string_view method; + std::string_view address; + std::string_view rateLogging; + std::string_view transport; +}; + +std::string rawChannelReference(std::string_view channelName, bool isUniqueChannel) +{ + if (isUniqueChannel) { + return std::string(channelName); + } else { + return std::string(channelName) + "-{{ it }}"; + } +} + +void dumpRawChannelConnect(std::ostream& dumpOut, const RawChannel& channel, bool isUniqueChannel, bool preserveRawChannels, std::string indLevel) +{ + + dumpOut << indLevel << "- name: " << channel.name << "\n"; + dumpOut << indLevel << indScheme << "type: " << channel.type << "\n"; + dumpOut << indLevel << indScheme << "transport: " << channel.transport << "\n"; + if (preserveRawChannels) { + dumpOut << indLevel << indScheme << "target: \"" << channel.address << "\"\n"; + LOG(INFO) << "This topology will connect to the channel '" << channel.name << "', which is most likely bound outside." + << " Please make sure it is available under the address '" << channel.address + << "' in the mother workflow or another subworkflow."; + } else { + auto channelRef = rawChannelReference(channel.name, isUniqueChannel); + LOG(INFO) << "This topology will connect to the channel '" << channel.name << "', which is most likely bound outside." + << " Please make sure it is declared in the global channel space under the name '" << channelRef + << "' in the mother workflow or another subworkflow."; + dumpOut << indLevel << indScheme << "target: \"::" << channelRef << "\"\n"; + } + dumpOut << indLevel << indScheme << "rateLogging: \"{{ fmq_rate_logging }}\"\n"; +} + +void dumpRawChannelBind(std::ostream& dumpOut, const RawChannel& channel, bool isUniqueChannel, bool preserveRawChannels, std::string indLevel) +{ + dumpOut << indLevel << "- name: " << channel.name << "\n"; + dumpOut << indLevel << indScheme << "type: " << channel.type << "\n"; + dumpOut << indLevel << indScheme << "transport: " << channel.transport << "\n"; + dumpOut << indLevel << indScheme << "addressing: " << (channel.address.find("ipc") != std::string_view::npos ? "ipc" : "tcp") << "\n"; + dumpOut << indLevel << indScheme << "rateLogging: \"{{ fmq_rate_logging }}\"\n"; + if (preserveRawChannels) { + LOG(INFO) << "This topology will bind a dangling channel '" << channel.name << "'" + << " with the address '" << channel.address << "'." + << " Please make sure that another device connects to this channel elsewhere." + << " Also, don't mind seeing the message twice, it will be addressed in future releases."; + dumpOut << indLevel << indScheme << "target: \"" << channel.address << "\"\n"; + } else { + auto channelRef = rawChannelReference(channel.name, isUniqueChannel); + LOG(INFO) << "This topology will bind a dangling channel '" << channel.name << "'" + << " and declare it in the global channel space under the name '" << channelRef << "'." + << " Please make sure that another device connects to this channel elsewhere." + << " Also, don't mind seeing the message twice, it will be addressed in future releases."; + dumpOut << indLevel << indScheme << "global: \"" << channelRef << "\"\n"; + } +} + +std::string_view extractValueFromChannelConfig(std::string_view string, std::string_view token) +{ + size_t tokenStart = string.find(token); + if (tokenStart == std::string_view::npos) { + return {}; + } + size_t valueStart = tokenStart + token.size(); + if (valueStart >= string.size()) { + return {}; + } + size_t valueEnd = string.find(',', valueStart); + return valueEnd == std::string_view::npos + ? string.substr(valueStart, string.size() - valueStart) + : string.substr(valueStart, valueEnd - valueStart); +} + +// fixme: For now we extract information about raw FairMQ channels from execution. +// However, we risk that it break if a channel configuration method changes, +// thus this information should be provided in DeviceSpec. Find a way to do that. +std::vector<RawChannel> extractRawChannels(const DeviceSpec& spec, const DeviceExecution& execution) +{ + std::vector<std::string> dplChannels; + for (const auto& channel : spec.inputChannels) { + dplChannels.emplace_back(channel.name); + } + for (const auto& channel : spec.outputChannels) { + dplChannels.emplace_back(channel.name); + } - out << R"( - name: )" << spec.id << "\n"; - out << R"( control: )" - << "\n"; - out << R"( mode: "fairmq")" - << "\n"; - if (spec.outputChannels.empty()) { - out << R"( bind: [])" - << "\n"; - } else { - out << R"( bind: )" - << "\n"; - for (auto& channel : spec.outputChannels) { - out << R"( - name: ")" << channel.name << "\"\n"; - out << R"( type: ")" << ChannelSpecHelpers::typeAsString(channel.type) << "\"\n"; + std::vector<RawChannel> rawChannels; + for (size_t i = 0; i < execution.args.size(); i++) { + if (execution.args[i] != nullptr && strcmp(execution.args[i], "--channel-config") == 0 && i + 1 < execution.args.size()) { + auto channelConfig = execution.args[i + 1]; + auto channelName = extractValueFromChannelConfig(channelConfig, "name="); + if (std::find(dplChannels.begin(), dplChannels.end(), channelName) == dplChannels.end()) { + // "name=readout-proxy,type=pair,method=connect,address=ipc:///tmp/readout-pipe-0,rateLogging=1,transport=shmem" + rawChannels.push_back({channelName, + extractValueFromChannelConfig(channelConfig, "type="), + extractValueFromChannelConfig(channelConfig, "method="), + extractValueFromChannelConfig(channelConfig, "address="), + extractValueFromChannelConfig(channelConfig, "rateLogging="), + extractValueFromChannelConfig(channelConfig, "transport=")}); } } - out << R"( command:)" - << "\n"; - out << R"( - shell: true)" - << "\n"; - out << R"( - value: )" << execution.args[0] << "\n"; - out << R"( - arguments:)" - << "\n"; - out << R"( - -b)" - << "\n"; - out << R"( - --monitoring-backend)" - << "\n"; - out << R"( - no-op://)" - << "\n"; - for (size_t ai = 1; ai < execution.args.size(); ++ai) { - const char* option = execution.args[ai]; - const char* value = nullptr; // no value by default (i.e. a boolean) - // If the subsequent option exists and does not start with -, we assume - // it is an argument to the previous one. - if (ai + 1 < execution.args.size() && execution.args[ai + 1][0] != '-') { - value = execution.args[ai + 1]; - ai++; - } - if (!option) { - break; + } + return rawChannels; +} + +void dumpCommand(std::ostream& dumpOut, const DeviceExecution& execution, std::string indLevel) +{ + dumpOut << indLevel << "shell: true\n"; + dumpOut << indLevel << "log: \"{{ log_task_output }}\"\n"; + dumpOut << indLevel << "env: [\"O2_DETECTOR={{ detector }}\"]\n"; + dumpOut << indLevel << "user: \"{{ user }}\"\n"; + dumpOut << indLevel << "value: \"{{ len(modulepath)>0 ? _module_cmdline : _plain_cmdline }}\"\n"; + + dumpOut << indLevel << "arguments:\n"; + dumpOut << indLevel << indScheme << "- \"-b\"\n"; + dumpOut << indLevel << indScheme << "- \"--monitoring-backend\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ monitoring_dpl_url }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--session\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ session_id }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--infologger-severity\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ infologger_severity }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--infologger-mode\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ infologger_mode }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--driver-client-backend\"\n"; + dumpOut << indLevel << indScheme << "- \"'stdout://'\"\n"; + dumpOut << indLevel << indScheme << "- \"--shm-segment-size\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ shm_segment_size }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--shm-throw-bad-alloc\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ shm_throw_bad_alloc }}'\"\n"; + dumpOut << indLevel << indScheme << "- \"--resources-monitoring\"\n"; + dumpOut << indLevel << indScheme << "- \"'{{ resources_monitoring }}'\"\n"; + + for (size_t ai = 1; ai < execution.args.size(); ++ai) { + const char* option = execution.args[ai]; + const char* value = nullptr; // no value by default (i.e. a boolean) + // If the subsequent option exists and does not start with -, we assume + // it is an argument to the previous one. + // ...that is unless it is a "-1" for example. + if (ai + 1 < execution.args.size() && execution.args[ai + 1][0] != '-') { + value = execution.args[ai + 1]; + ai++; + } + if (!option) { + break; + } + + static const std::set<std::string> omitOptions = { + "--channel-config", "--o2-control", "--control", "--session", "--monitoring-backend", + "-b", "--color", "--infologger-severity", "--infologger-mode", "--driver-client-backend", + "--shm-segment-size", "--shm-throw-bad-alloc", "--resources-monitoring"}; + if (omitOptions.find(option) != omitOptions.end()) { + continue; + } + // todo: possible improvement - do not print if default values are used + // todo: check if '' are there already. + dumpOut << indLevel << indScheme << R"(- ")" << option << "\"\n"; + if (value) { + dumpOut << indLevel << indScheme << R"(- "')" << value << "'\"\n"; + } + } +} + +std::string findBinder(const std::vector<DeviceSpec>& specs, const std::string& channel) +{ + // fixme: it is not crucial to be fast here, but ideally we should check only input OR output channels. + for (const auto& spec : specs) { + for (const auto& inputChannel : spec.inputChannels) { + if (inputChannel.method == ChannelMethod::Bind && inputChannel.name == channel) { + return spec.id; } - // Do not print out channel information - if (strcmp(option, "--channel-config") == 0) { - ai += 2; - continue; - } else if (strcmp(option, "--control") == 0) { - continue; + } + for (const auto& outputChannel : spec.outputChannels) { + if (outputChannel.method == ChannelMethod::Bind && outputChannel.name == channel) { + return spec.id; } - out << R"( - )" << option << "\n"; - if (value) { - out << R"( - )" << value << "\n"; + } + } + throw std::runtime_error("Could not find a device which binds the '" + channel + "' channel."); +} + +bool isUniqueProxy(const DeviceSpec& spec) +{ + return std::find(spec.labels.begin(), spec.labels.end(), ecs::uniqueProxyLabel) != spec.labels.end(); +} + +bool shouldPreserveRawChannels(const DeviceSpec& spec) +{ + return std::find(spec.labels.begin(), spec.labels.end(), ecs::preserveRawChannelsLabel) != spec.labels.end(); +} + +void dumpRole(std::ostream& dumpOut, const std::string& taskName, const DeviceSpec& spec, const std::vector<DeviceSpec>& allSpecs, const DeviceExecution& execution, const std::string indLevel) +{ + dumpOut << indLevel << "- name: \"" << spec.id << "\"\n"; + + dumpOut << indLevel << indScheme << "connect:\n"; + + for (const auto& outputChannel : spec.outputChannels) { + if (outputChannel.method == ChannelMethod::Connect) { + dumpChannelConnect(dumpOut, outputChannel, findBinder(allSpecs, outputChannel.name), indLevel + indScheme); + } + } + for (const auto& inputChannel : spec.inputChannels) { + if (inputChannel.method == ChannelMethod::Connect) { + dumpChannelConnect(dumpOut, inputChannel, findBinder(allSpecs, inputChannel.name), indLevel + indScheme); + } + } + bool uniqueProxy = isUniqueProxy(spec); + bool preserveRawChannels = shouldPreserveRawChannels(spec); + bool bindsRawChannels = false; + auto rawChannels = extractRawChannels(spec, execution); + for (const auto& rawChannel : rawChannels) { + if (rawChannel.method == "connect") { + dumpRawChannelConnect(dumpOut, rawChannel, uniqueProxy, preserveRawChannels, indLevel + indScheme); + } else if (rawChannel.method == "bind") { + bindsRawChannels = true; + } + } + + // for the time being we have to publish global bound channels also in WFT + if (bindsRawChannels) { + dumpOut << indLevel << indScheme << "bind:\n"; + for (const auto& rawChannel : rawChannels) { + if (rawChannel.method == "bind") { + dumpRawChannelBind(dumpOut, rawChannel, uniqueProxy, preserveRawChannels, indLevel + indScheme); } } - out << "\n"; } - out << " workflows:\n"; - out << " o2-workflow:\n"; - out << " name: \"o2-workflow-roles\"\n"; - out << " roles: \"\n"; + + dumpOut << indLevel << indScheme << "task:\n"; + dumpOut << indLevel << indScheme << indScheme << "load: " << taskName << "\n"; +} + +std::string removeO2ControlArg(std::string_view command) +{ + const char* o2ControlArg = " --o2-control "; + size_t o2ControlArgStart = command.find(o2ControlArg); + if (o2ControlArgStart == std::string_view::npos) { + return std::string(command); + } + size_t o2ControlArgEnd = command.find(" ", o2ControlArgStart + std::strlen(o2ControlArg)); + auto result = std::string(command.substr(0, o2ControlArgStart)); + if (o2ControlArgEnd != std::string_view::npos) { + result += command.substr(o2ControlArgEnd); + } + return result; +} + +} // namespace implementation + +void dumpTask(std::ostream& dumpOut, const DeviceSpec& spec, const DeviceExecution& execution, std::string taskName, std::string indLevel) +{ + dumpOut << indLevel << "name: " << taskName << "\n"; + dumpOut << indLevel << "defaults:\n"; + dumpOut << indLevel << indScheme << "log_task_output: none\n"; + + if (bfs::path(execution.args[0]).filename().string() != execution.args[0]) { + LOG(WARNING) << "The workflow template generation was started with absolute or relative executables paths." + " Please use the symlinks exported by the build infrastructure or remove the paths manually in the generated templates," + " unless you really need executables within concrete directories"; + } + dumpOut << indLevel << indScheme << "_module_cmdline: >-\n"; + dumpOut << indLevel << indScheme << indScheme << "source /etc/profile.d/modules.sh && MODULEPATH={{ modulepath }} module load O2 QualityControl Control-OCCPlugin &&\n"; + dumpOut << indLevel << indScheme << indScheme << "{{ dpl_command }} | " << execution.args[0] << "\n"; + dumpOut << indLevel << indScheme << "_plain_cmdline: \"source /etc/profile.d/o2.sh && {{ dpl_command }} | " << execution.args[0] << "\"\n"; + + dumpOut << indLevel << "control:\n"; + dumpOut << indLevel << indScheme << "mode: \"fairmq\"\n"; + + // todo: find out proper values perhaps... + dumpOut << indLevel << "wants:\n"; + dumpOut << indLevel << indScheme << "cpu: 0.01\n"; + dumpOut << indLevel << indScheme << "memory: 1\n"; + + dumpOut << indLevel << "bind:\n"; + for (const auto& outputChannel : spec.outputChannels) { + if (outputChannel.method == ChannelMethod::Bind) { + implementation::dumpChannelBind(dumpOut, outputChannel, indLevel + indScheme); + } + } + for (const auto& inputChannel : spec.inputChannels) { + if (inputChannel.method == ChannelMethod::Bind) { + implementation::dumpChannelBind(dumpOut, inputChannel, indLevel + indScheme); + } + } + bool uniqueProxy = implementation::isUniqueProxy(spec); + bool preserveRawChannels = implementation::shouldPreserveRawChannels(spec); + auto rawChannels = implementation::extractRawChannels(spec, execution); + for (const auto& rawChannel : rawChannels) { + if (rawChannel.method == "bind") { + dumpRawChannelBind(dumpOut, rawChannel, uniqueProxy, preserveRawChannels, indLevel + indScheme); + } + } + + dumpOut << indLevel << "command:\n"; + implementation::dumpCommand(dumpOut, execution, indLevel + indScheme); +} + +void dumpWorkflow(std::ostream& dumpOut, const std::vector<DeviceSpec>& specs, const std::vector<DeviceExecution>& executions, const CommandInfo& commandInfo, std::string workflowName, std::string indLevel) +{ + dumpOut << indLevel << "name: " << workflowName << "\n"; + + dumpOut << indLevel << "vars:\n"; + dumpOut << indLevel << indScheme << "dpl_command: >-\n"; + dumpOut << indLevel << indScheme << indScheme << implementation::removeO2ControlArg(commandInfo.command) << "\n"; + + dumpOut << indLevel << "defaults:\n"; + dumpOut << indLevel << indScheme << "monitoring_dpl_url: \"no-op://\"\n"; + dumpOut << indLevel << indScheme << "user: \"flp\"\n"; + dumpOut << indLevel << indScheme << "fmq_rate_logging: 0\n"; + dumpOut << indLevel << indScheme << "shm_segment_size: 10000000000\n"; + dumpOut << indLevel << indScheme << "shm_throw_bad_alloc: false\n"; + dumpOut << indLevel << indScheme << "session_id: default\n"; + dumpOut << indLevel << indScheme << "resources_monitoring: 15\n"; + + dumpOut << indLevel << "roles:\n"; + for (size_t di = 0; di < specs.size(); di++) { + auto& spec = specs[di]; + auto& execution = executions[di]; + implementation::dumpRole(dumpOut, implementation::taskName(workflowName, spec.id), spec, specs, execution, indLevel + indScheme); + } +} + +void dumpDeviceSpec2O2Control(std::string workflowName, + const std::vector<DeviceSpec>& specs, + const std::vector<DeviceExecution>& executions, + const CommandInfo& commandInfo) +{ + const char* tasksDirectory = "tasks"; + const char* workflowsDirectory = "workflows"; + + LOG(INFO) << "Dumping the workflow configuration for AliECS."; + + LOG(INFO) << "Creating directories '" << workflowsDirectory << "' and '" << tasksDirectory << "'."; + std::filesystem::create_directory(workflowsDirectory); + std::filesystem::create_directory(tasksDirectory); + LOG(INFO) << "... created."; + + assert(specs.size() == executions.size()); + + LOG(INFO) << "Creating a workflow dump '" + workflowName + "'."; + std::string wfDumpPath = std::string(workflowsDirectory) + bfs::path::preferred_separator + workflowName + ".yaml"; + std::ofstream wfDump(wfDumpPath); + dumpWorkflow(wfDump, specs, executions, commandInfo, workflowName, ""); + wfDump.close(); + for (size_t di = 0; di < specs.size(); ++di) { auto& spec = specs[di]; - out << " - name: \"" << spec.name << "\"\n"; - out << " connect:\n"; - for (auto& channel : spec.inputChannels) { - out << R"( - name: ")" << channel.name << "\"\n"; - // FIXME: Until we get a {{workflow}} placeholder. - std::string sourceDevice = channel.name; - sourceDevice.erase(0, 5); - auto startSuffix = sourceDevice.find_last_of("_to_"); - sourceDevice = sourceDevice.substr(0, startSuffix - 3); - out << R"( target: "{{parent}}.)" << sourceDevice << ":" << channel.name << "\"\n"; - out << R"( type: ")" << ChannelSpecHelpers::typeAsString(channel.type) << "\"\n"; - } - out << " task:\n"; - out << " load: " << spec.name << "\n"; + auto& execution = executions[di]; + + LOG(INFO) << "Creating a task dump for '" + spec.id + "'."; + std::string taskName = implementation::taskName(workflowName, spec.id); + std::string taskDumpPath = std::string(tasksDirectory) + bfs::path::preferred_separator + taskName + ".yaml"; + std::ofstream taskDump(taskDumpPath); + dumpTask(taskDump, spec, execution, taskName, ""); + taskDump.close(); + LOG(INFO) << "...created."; } } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/O2ControlHelpers.h b/Framework/Core/src/O2ControlHelpers.h index ce5241840832b..4ec1cf045f687 100644 --- a/Framework/Core/src/O2ControlHelpers.h +++ b/Framework/Core/src/O2ControlHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #include "Framework/DeviceSpec.h" #include "Framework/DeviceExecution.h" +#include "Framework/CommandInfo.h" #include <vector> #include <iosfwd> @@ -20,9 +22,36 @@ namespace o2 namespace framework { -void dumpDeviceSpec2O2Control(std::ostream& out, +/// \brief Dumps the AliECS compatible workflow and task templates for a DPL workflow. +/// +/// Dumps the AliECS compatible workflow (WFT) and task templates (TT) for a DPL workflow. +/// The current procedure to obtain working templates: +/// - Build the project(s) +/// - Enter the environment and go to ControlWorkflows local repository. +/// - Run the DPL workflow(s) with the argument `--o2-control <workflow-name>`. +/// The WFT will be created in the "workflows" directory and, analogously, TTs will be put in "tasks". +/// It can be included by a mother workflow at the deployment time. +/// - Replace arguments with templates if needed. +/// - Commit, push, test, merge to master. +void dumpDeviceSpec2O2Control(std::string workflowName, std::vector<DeviceSpec> const& specs, - std::vector<DeviceExecution> const& executions); + std::vector<DeviceExecution> const& executions, + CommandInfo const& commandInfo); + +/// \brief Dumps only the workflow file +void dumpWorkflow(std::ostream& dumpOut, + const std::vector<DeviceSpec>& specs, + const std::vector<DeviceExecution>& executions, + const CommandInfo& commandInfo, + std::string workflowName, + std::string indLevel); + +/// \brief Dumps only one task +void dumpTask(std::ostream& dumpOut, + const DeviceSpec& spec, + const DeviceExecution& execution, + std::string taskName, + std::string indLevel); } // namespace framework } // namespace o2 diff --git a/Framework/Core/src/O2ControlLabels.cxx b/Framework/Core/src/O2ControlLabels.cxx new file mode 100644 index 0000000000000..aa22d858f6e44 --- /dev/null +++ b/Framework/Core/src/O2ControlLabels.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/O2ControlLabels.h" + +namespace o2::framework::ecs +{ + +const DataProcessorLabel uniqueProxyLabel = {"ecs-unique-proxy"}; +const DataProcessorLabel preserveRawChannelsLabel = {"ecs-preserve-raw-channels"}; +} \ No newline at end of file diff --git a/Framework/Core/src/OutputSpec.cxx b/Framework/Core/src/OutputSpec.cxx index d42b522bf05e2..f47e3bab97da4 100644 --- a/Framework/Core/src/OutputSpec.cxx +++ b/Framework/Core/src/OutputSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/PaletteHelpers.cxx b/Framework/Core/src/PaletteHelpers.cxx deleted file mode 100644 index 57405823bce57..0000000000000 --- a/Framework/Core/src/PaletteHelpers.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/PaletteHelpers.h" - -namespace o2 -{ -namespace framework -{ - -const ImVec4 PaletteHelpers::RED = ImVec4(0xe3 / 255., 0x67 / 255., 0x44 / 255., 1); -const ImVec4 PaletteHelpers::GREEN = ImVec4(0x7e / 255., 0xc4 / 255., 0x52 / 255., 1); -const ImVec4 PaletteHelpers::BLUE = ImVec4(0x3d / 255., 0xb7 / 255., 0xe0 / 255., 1); -const ImVec4 PaletteHelpers::YELLOW = ImVec4(0xf0 / 255., 0xc3 / 255., 0x30 / 255., 1); -const ImVec4 PaletteHelpers::SHADED_RED = ImVec4(0xd5 / 255., 0x72 / 255., 0x73 / 255., 1); -const ImVec4 PaletteHelpers::SHADED_GREEN = ImVec4(0x98 / 255., 0xba / 255., 0x96 / 255., 1); -const ImVec4 PaletteHelpers::SHADED_BLUE = ImVec4(0x7a / 255., 0xab / 255., 0xea / 255., 1); -const ImVec4 PaletteHelpers::SHADED_YELLOW = ImVec4(0xeb / 255., 0xb9 / 255., 0x7a / 255., 1); -const ImVec4 PaletteHelpers::DARK_RED = ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); -const ImVec4 PaletteHelpers::DARK_GREEN = ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); -const ImVec4 PaletteHelpers::DARK_YELLOW = ImVec4(0xf1 / 255., 0x9b / 255., 0x2c / 255., 255. / 255); -const ImVec4 PaletteHelpers::WHITE = ImVec4(0xce / 255., 0xbe / 255., 0x91 / 255., 1); -const ImVec4 PaletteHelpers::BLACK = ImVec4(0x28 / 255., 0x28 / 255., 0x28 / 255., 1); -const ImVec4 PaletteHelpers::GRAY = ImVec4(60 / 255., 60 / 255., 60 / 255., 1); -const ImVec4 PaletteHelpers::LIGHT_GRAY = ImVec4(75 / 255., 75 / 255., 75 / 255., 1); - -} // namespace framework -} // namespace o2 diff --git a/Framework/Core/src/Plugins.cxx b/Framework/Core/src/Plugins.cxx new file mode 100644 index 0000000000000..614f67add02cb --- /dev/null +++ b/Framework/Core/src/Plugins.cxx @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/Plugins.h" +#include "Framework/Logger.h" +#include <uv.h> +#include <functional> +#include <vector> + +namespace o2::framework +{ + +void PluginManager::load(std::vector<PluginInfo>& libs, const char* dso, std::function<void(DPLPluginHandle*)>& onSuccess) +{ + auto plugin = std::find_if(libs.begin(), libs.end(), [dso](PluginInfo& info) { return info.name == dso; }); + if (plugin != libs.end()) { + return onSuccess(plugin->instance); + } + uv_lib_t* supportLib = (uv_lib_t*)malloc(sizeof(uv_lib_t)); + int result = 0; +#ifdef __APPLE__ + char const* extension = "dylib"; +#else + char const* extension = "so"; +#endif + std::string filename = fmt::format("lib{}.{}", dso, extension); + result = uv_dlopen(filename.c_str(), supportLib); + if (result == -1) { + LOG(FATAL) << uv_dlerror(supportLib); + return; + } + void* callback = nullptr; + DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*); + + result = uv_dlsym(supportLib, "dpl_plugin_callback", (void**)&dpl_plugin_callback); + if (result == -1) { + LOG(FATAL) << uv_dlerror(supportLib); + return; + } + if (dpl_plugin_callback == nullptr) { + LOGP(FATAL, "Could not find the {} plugin.", dso); + return; + } + DPLPluginHandle* pluginInstance = dpl_plugin_callback(nullptr); + libs.push_back({supportLib, dso}); + onSuccess(pluginInstance); +} +} // namespace o2::framework diff --git a/Framework/Core/src/PropertyTreeHelpers.cxx b/Framework/Core/src/PropertyTreeHelpers.cxx index 70b9c21fd3d69..dbbfc0a97a93f 100644 --- a/Framework/Core/src/PropertyTreeHelpers.cxx +++ b/Framework/Core/src/PropertyTreeHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,9 +11,9 @@ #include "PropertyTreeHelpers.h" #include "Framework/ConfigParamSpec.h" -#include "Framework/Variant.h" +#include "Framework/VariantStringHelpers.h" +#include "Framework/VariantPropertyTreeHelpers.h" -#include <boost/property_tree/ptree.hpp> #include <boost/program_options/variables_map.hpp> #include <vector> @@ -25,8 +26,8 @@ void PropertyTreeHelpers::populateDefaults(std::vector<ConfigParamSpec> const& s boost::property_tree::ptree& pt, boost::property_tree::ptree& provenance) { - for (auto& spec : schema) { - std::string key = spec.name.substr(0, spec.name.find(",")); + for (auto const& spec : schema) { + std::string key = spec.name.substr(0, spec.name.find(',')); try { if (spec.defaultValue.type() == VariantType::Empty) { continue; @@ -35,6 +36,18 @@ void PropertyTreeHelpers::populateDefaults(std::vector<ConfigParamSpec> const& s case VariantType::Int: pt.put(key, spec.defaultValue.get<int>()); break; + case VariantType::UInt8: + pt.put(key, spec.defaultValue.get<uint8_t>()); + break; + case VariantType::UInt16: + pt.put(key, spec.defaultValue.get<uint16_t>()); + break; + case VariantType::UInt32: + pt.put(key, spec.defaultValue.get<uint32_t>()); + break; + case VariantType::UInt64: + pt.put(key, spec.defaultValue.get<uint64_t>()); + break; case VariantType::Int64: pt.put(key, spec.defaultValue.get<int64_t>()); break; @@ -50,6 +63,39 @@ void PropertyTreeHelpers::populateDefaults(std::vector<ConfigParamSpec> const& s case VariantType::Bool: pt.put(key, spec.defaultValue.get<bool>()); break; + case VariantType::ArrayInt: + pt.put_child(key, vectorToBranch(spec.defaultValue.get<int*>(), spec.defaultValue.size())); + break; + case VariantType::ArrayFloat: + pt.put_child(key, vectorToBranch(spec.defaultValue.get<float*>(), spec.defaultValue.size())); + break; + case VariantType::ArrayDouble: + pt.put_child(key, vectorToBranch(spec.defaultValue.get<double*>(), spec.defaultValue.size())); + break; + case VariantType::ArrayBool: + pt.put_child(key, vectorToBranch(spec.defaultValue.get<bool*>(), spec.defaultValue.size())); + break; + case VariantType::ArrayString: + pt.put_child(key, vectorToBranch(spec.defaultValue.get<std::string*>(), spec.defaultValue.size())); + break; + case VariantType::Array2DInt: + pt.put_child(key, array2DToBranch(spec.defaultValue.get<Array2D<int>>())); + break; + case VariantType::Array2DFloat: + pt.put_child(key, array2DToBranch(spec.defaultValue.get<Array2D<float>>())); + break; + case VariantType::Array2DDouble: + pt.put_child(key, array2DToBranch(spec.defaultValue.get<Array2D<double>>())); + break; + case VariantType::LabeledArrayInt: + pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get<LabeledArray<int>>())); + break; + case VariantType::LabeledArrayFloat: + pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get<LabeledArray<float>>())); + break; + case VariantType::LabeledArrayDouble: + pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get<LabeledArray<double>>())); + break; case VariantType::Unknown: case VariantType::Empty: default: @@ -57,7 +103,7 @@ void PropertyTreeHelpers::populateDefaults(std::vector<ConfigParamSpec> const& s } provenance.put(key, "default"); } catch (std::runtime_error& re) { - throw re; + throw; } catch (std::exception& e) { throw std::invalid_argument(std::string("missing option: ") + key + " (" + e.what() + ")"); } catch (...) { @@ -71,9 +117,9 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, boost::program_options::variables_map const& vmap, boost::property_tree::ptree& provenance) { - for (auto& spec : schema) { + for (auto const& spec : schema) { // strip short version to get the correct key - std::string key = spec.name.substr(0, spec.name.find(",")); + std::string key = spec.name.substr(0, spec.name.find(',')); if (vmap.count(key) == 0) { continue; } @@ -82,6 +128,18 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, case VariantType::Int: pt.put(key, vmap[key].as<int>()); break; + case VariantType::UInt8: + pt.put(key, vmap[key].as<uint8_t>()); + break; + case VariantType::UInt16: + pt.put(key, vmap[key].as<uint16_t>()); + break; + case VariantType::UInt32: + pt.put(key, vmap[key].as<uint32_t>()); + break; + case VariantType::UInt64: + pt.put(key, vmap[key].as<uint64_t>()); + break; case VariantType::Int64: pt.put(key, vmap[key].as<int64_t>()); break; @@ -92,13 +150,37 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, pt.put(key, vmap[key].as<double>()); break; case VariantType::String: - if (auto v = boost::any_cast<std::string>(&vmap[key].value())) { + if (auto const* v = boost::any_cast<std::string>(&vmap[key].value())) { pt.put(key, *v); } break; case VariantType::Bool: pt.put(key, vmap[key].as<bool>()); break; + case VariantType::ArrayInt: + pt.put_child(key, vectorToBranch<int>(stringToVector<int>(vmap[key].as<std::string>()))); + break; + case VariantType::ArrayFloat: + pt.put_child(key, vectorToBranch<float>(stringToVector<float>(vmap[key].as<std::string>()))); + break; + case VariantType::ArrayDouble: + pt.put_child(key, vectorToBranch<double>(stringToVector<double>(vmap[key].as<std::string>()))); + break; + case VariantType::ArrayBool: + // pt.put_child(key, vectorToBranch<bool>(stringToVector<bool>(vmap[key].as<std::string>()))); + break; + case VariantType::ArrayString: + pt.put_child(key, vectorToBranch<std::string>(stringToVector<std::string>(vmap[key].as<std::string>()))); + break; + case VariantType::Array2DInt: + pt.put_child(key, array2DToBranch<int>(stringToArray2D<int>(vmap[key].as<std::string>()))); + break; + case VariantType::Array2DFloat: + pt.put_child(key, array2DToBranch<float>(stringToArray2D<float>(vmap[key].as<std::string>()))); + break; + case VariantType::Array2DDouble: + pt.put_child(key, array2DToBranch<double>(stringToArray2D<double>(vmap[key].as<std::string>()))); + break; case VariantType::Unknown: case VariantType::Empty: default: @@ -106,7 +188,7 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, } provenance.put(key, "fairmq"); } catch (std::runtime_error& re) { - throw re; + throw; } catch (std::exception& e) { throw std::invalid_argument(std::string("missing option: ") + key + " (" + e.what() + ")"); } catch (...) { @@ -115,16 +197,34 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, } } +template <typename T> +auto replaceLabels(LabeledArray<T>& input, LabeledArray<T>&& spec) +{ + if (!input.getLabelsCols().empty() || !input.getLabelsRows().empty()) { + return false; + } + if (spec.getLabelsCols().empty() == false) { + input.replaceLabelsCols(spec.getLabelsCols()); + } + if (spec.getLabelsRows().empty() == false) { + input.replaceLabelsRows(spec.getLabelsRows()); + } + return true; +} + void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, boost::property_tree::ptree& pt, boost::property_tree::ptree const& in, boost::property_tree::ptree& provenance, std::string const& provenanceLabel) { - for (auto& spec : schema) { + for (auto const& spec : schema) { // strip short version to get the correct key - std::string key = spec.name.substr(0, spec.name.find(",")); + std::string key = spec.name.substr(0, spec.name.find(',')); auto it = in.get_child_optional(key); + if (!it) { + it = in.get_child_optional(boost::property_tree::path(key, '/')); + } if (!it) { continue; } @@ -133,6 +233,18 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, case VariantType::Int: pt.put(key, (*it).get_value<int>()); break; + case VariantType::UInt8: + pt.put(key, (*it).get_value<uint8_t>()); + break; + case VariantType::UInt16: + pt.put(key, (*it).get_value<uint16_t>()); + break; + case VariantType::UInt32: + pt.put(key, (*it).get_value<uint32_t>()); + break; + case VariantType::UInt64: + pt.put(key, (*it).get_value<uint64_t>()); + break; case VariantType::Int64: pt.put(key, (*it).get_value<int64_t>()); break; @@ -148,6 +260,40 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, case VariantType::Bool: pt.put(key, (*it).get_value<bool>()); break; + case VariantType::ArrayInt: + case VariantType::ArrayFloat: + case VariantType::ArrayDouble: + case VariantType::ArrayBool: + case VariantType::ArrayString: + case VariantType::Array2DInt: + case VariantType::Array2DFloat: + case VariantType::Array2DDouble: + pt.put_child(key, *it); + break; + case VariantType::LabeledArrayInt: { + auto v = labeledArrayFromBranch<int>(it.value()); + if (!replaceLabels(v, spec.defaultValue.get<LabeledArray<int>>())) { + pt.put_child(key, *it); + } else { + pt.put_child(key, labeledArrayToBranch(std::move(v))); + } + }; break; + case VariantType::LabeledArrayFloat: { + auto v = labeledArrayFromBranch<float>(it.value()); + if (!replaceLabels(v, spec.defaultValue.get<LabeledArray<float>>())) { + pt.put_child(key, *it); + } else { + pt.put_child(key, labeledArrayToBranch(std::move(v))); + } + }; break; + case VariantType::LabeledArrayDouble: { + auto v = labeledArrayFromBranch<double>(it.value()); + if (!replaceLabels(v, spec.defaultValue.get<LabeledArray<double>>())) { + pt.put_child(key, *it); + } else { + pt.put_child(key, labeledArrayToBranch(std::move(v))); + } + }; break; case VariantType::Unknown: case VariantType::Empty: default: @@ -155,7 +301,7 @@ void PropertyTreeHelpers::populate(std::vector<ConfigParamSpec> const& schema, } provenance.put(key, provenanceLabel); } catch (std::runtime_error& re) { - throw re; + throw; } catch (std::exception& e) { throw std::invalid_argument(std::string("missing option: ") + key + " (" + e.what() + ")"); } catch (...) { @@ -186,15 +332,4 @@ void PropertyTreeHelpers::traverse(const boost::property_tree::ptree& parent, Pr traverseRecursive(parent, "", parent, method); } -void PropertyTreeHelpers::merge(boost::property_tree::ptree& dest, - boost::property_tree::ptree const& source, - boost::property_tree::ptree::path_type const& mergePoint) -{ - using boost::property_tree::ptree; - WalkerFunction merge = [&dest, &mergePoint](ptree const& parent, ptree::path_type childPath, ptree const& child) { - dest.put(mergePoint / childPath, child.data()); - }; - traverse(source, merge); -} - } // namespace o2::framework diff --git a/Framework/Core/src/PropertyTreeHelpers.h b/Framework/Core/src/PropertyTreeHelpers.h index e6fa3c8f7d71b..7d2850fbcdafb 100644 --- a/Framework/Core/src/PropertyTreeHelpers.h +++ b/Framework/Core/src/PropertyTreeHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/RCombinedDS.cxx b/Framework/Core/src/RCombinedDS.cxx index c1bbf015fe6de..0c56d967dcc05 100644 --- a/Framework/Core/src/RCombinedDS.cxx +++ b/Framework/Core/src/RCombinedDS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/RawBufferContext.cxx b/Framework/Core/src/RawBufferContext.cxx new file mode 100644 index 0000000000000..1e979eab4acf0 --- /dev/null +++ b/Framework/Core/src/RawBufferContext.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/RawBufferContext.h" +#include <FairMQMessage.h> + +namespace o2::framework +{ + +void RawBufferContext::addRawBuffer(std::unique_ptr<FairMQMessage> header, + char* payload, + std::string channel, + std::function<std::ostringstream()> serialize, + std::function<void()> destructor) +{ + mMessages.push_back(std::move(MessageRef{std::move(header), std::move(payload), std::move(channel), std::move(serialize), std::move(destructor)})); +} + +void RawBufferContext::clear() +{ + // On send we move the header, but the payload remains + // there because what's really sent is the copy of the raw + // payload will be cleared by the mMessages.clear() + for (auto& m : mMessages) { + assert(m.header == nullptr); + // NOTE: payloads can be empty so m.payload == nullptr should + // be an actual issue. + assert(m.payload != nullptr); + m.destroyPayload(); + m.payload = nullptr; + } + + mMessages.clear(); +} + +RawBufferContext::RawBufferContext(RawBufferContext&& other) + : mProxy{other.mProxy}, mMessages{std::move(other.mMessages)} +{ +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ReadoutAdapter.cxx b/Framework/Core/src/ReadoutAdapter.cxx index a002d3b8ff3ad..c67ee4e8ce22d 100644 --- a/Framework/Core/src/ReadoutAdapter.cxx +++ b/Framework/Core/src/ReadoutAdapter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ResourceManager.h b/Framework/Core/src/ResourceManager.h index 93ba16711a1cc..4464762f023a4 100644 --- a/Framework/Core/src/ResourceManager.h +++ b/Framework/Core/src/ResourceManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ResourcePolicy.cxx b/Framework/Core/src/ResourcePolicy.cxx new file mode 100644 index 0000000000000..42d4735f5e1ea --- /dev/null +++ b/Framework/Core/src/ResourcePolicy.cxx @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ResourcePolicy.h" +#include "Framework/ResourcePolicyHelpers.h" +#include <vector> + +namespace o2::framework +{ + +std::vector<ResourcePolicy> ResourcePolicy::createDefaultPolicies() +{ + return { + ResourcePolicyHelpers::sharedMemoryBoundTask("internal-dpl-aod-reader.*", 150000000), + ResourcePolicyHelpers::trivialTask(".*")}; +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ResourcePolicyHelpers.cxx b/Framework/Core/src/ResourcePolicyHelpers.cxx new file mode 100644 index 0000000000000..aad783cdc1f60 --- /dev/null +++ b/Framework/Core/src/ResourcePolicyHelpers.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ResourcePolicyHelpers.h" +#include "Framework/DeviceSpec.h" +#include "ResourcesMonitoringHelper.h" + +#include <string> +#include <regex> + +namespace o2::framework +{ + +/// A trivial task is a task which will execute regardless of +/// the resources available. +ResourcePolicy ResourcePolicyHelpers::trivialTask(char const* s) +{ + return ResourcePolicy{ + "trivial", + [matcher = std::regex(s)](DeviceSpec const& spec) -> bool { + return std::regex_match(spec.name, matcher); + }, + [](ComputingQuotaOffer const&, ComputingQuotaOffer const&) -> OfferScore { return OfferScore::Enough; }}; +} + +ResourcePolicy ResourcePolicyHelpers::cpuBoundTask(char const* s, int requestedCPUs) +{ + return ResourcePolicy{ + "cpu-bound", + [matcher = std::regex(s)](DeviceSpec const& spec) -> bool { + return std::regex_match(spec.name, matcher); + }, + [requestedCPUs](ComputingQuotaOffer const& offer, ComputingQuotaOffer const& accumulated) -> OfferScore { return accumulated.cpu >= requestedCPUs ? OfferScore::Enough : OfferScore::More; }}; +} + +ResourcePolicy ResourcePolicyHelpers::sharedMemoryBoundTask(char const* s, int requestedSharedMemory) +{ + return ResourcePolicy{ + "shm-bound", + [matcher = std::regex(s)](DeviceSpec const& spec) -> bool { + return std::regex_match(spec.name, matcher); + }, + [requestedSharedMemory](ComputingQuotaOffer const& offer, ComputingQuotaOffer const& accumulated) -> OfferScore { + if (offer.sharedMemory == 0) { + return OfferScore::Unneeded; + } + return accumulated.sharedMemory >= requestedSharedMemory ? OfferScore::Enough : OfferScore::More; }}; +} + +} // namespace o2::framework diff --git a/Framework/Core/src/ResourcesMonitoringHelper.cxx b/Framework/Core/src/ResourcesMonitoringHelper.cxx index 28d90351816f7..96c51bbe31db7 100644 --- a/Framework/Core/src/ResourcesMonitoringHelper.cxx +++ b/Framework/Core/src/ResourcesMonitoringHelper.cxx @@ -1,23 +1,59 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "ResourcesMonitoringHelper.h" +#include "Framework/DeviceMetricsInfo.h" #include <boost/property_tree/json_parser.hpp> #include <fstream> #include <string_view> #include <algorithm> #include <cassert> +#include <regex> using namespace o2::framework; +template <typename T> +inline static T retriveValue(T val) +{ + return val; +} + +inline static std::string retriveValue(const std::reference_wrapper<const StringMetric> val) +{ + return std::string(val.get().data); +} + +template <typename T> +boost::property_tree::ptree fillNodeWithValue(const DeviceMetricsInfo& deviceMetrics, + const T& metricsStorage, size_t labelIndex, size_t storageIndex) +{ + + unsigned int loopRange = std::min(deviceMetrics.metrics[labelIndex].filledMetrics, metricsStorage[storageIndex].size()); + boost::property_tree::ptree metricNode; + + for (unsigned int idx = 0; idx < loopRange; ++idx) { + boost::property_tree::ptree values; + values.add("timestamp", deviceMetrics.timestamps[labelIndex][idx]); + if constexpr (std::is_arithmetic_v<T>) { + values.add("value", std::to_string(retriveValue(std::cref(metricsStorage[storageIndex][idx])))); + } else { + values.add("value", retriveValue(std::cref(metricsStorage[storageIndex][idx]))); + } + metricNode.push_back(std::make_pair("", values)); + } + return metricNode; +} + bool ResourcesMonitoringHelper::dumpMetricsToJSON(const std::vector<DeviceMetricsInfo>& metrics, + const DeviceMetricsInfo& driverMetrics, const std::vector<DeviceSpec>& specs, std::vector<std::string> const& performanceMetrics) noexcept { @@ -34,10 +70,15 @@ bool ResourcesMonitoringHelper::dumpMetricsToJSON(const std::vector<DeviceMetric const auto& deviceMetrics = metrics[idx]; boost::property_tree::ptree deviceRoot; - for (const auto& metricLabel : deviceMetrics.metricLabelsIdx) { + for (size_t mi = 0; mi < deviceMetrics.metricLabels.size(); mi++) { + std::string metricLabel = deviceMetrics.metricLabels[mi].label; + auto same = [metricLabel](std::string const& matcher) -> bool { + std::regex r{matcher}; + return std::regex_match(metricLabel, r); + }; //check if we are interested - if (std::find(std::begin(performanceMetrics), std::end(performanceMetrics), metricLabel.label) == std::end(performanceMetrics)) { + if (std::find_if(std::begin(performanceMetrics), std::end(performanceMetrics), same) == performanceMetrics.end()) { continue; } @@ -45,36 +86,74 @@ bool ResourcesMonitoringHelper::dumpMetricsToJSON(const std::vector<DeviceMetric boost::property_tree::ptree metricNode; - switch (deviceMetrics.metrics[metricLabel.index].type) { + switch (deviceMetrics.metrics[mi].type) { case MetricType::Int: - metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.intMetrics, - metricLabel.index, deviceMetrics.metrics[metricLabel.index].storeIdx); + metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.intMetrics, mi, deviceMetrics.metrics[mi].storeIdx); break; case MetricType::Float: - metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.floatMetrics, - metricLabel.index, deviceMetrics.metrics[metricLabel.index].storeIdx); + metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.floatMetrics, mi, deviceMetrics.metrics[mi].storeIdx); break; case MetricType::String: - metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.stringMetrics, - metricLabel.index, deviceMetrics.metrics[metricLabel.index].storeIdx); + metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.stringMetrics, mi, deviceMetrics.metrics[mi].storeIdx); break; case MetricType::Uint64: - metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.uint64Metrics, - metricLabel.index, deviceMetrics.metrics[metricLabel.index].storeIdx); + metricNode = fillNodeWithValue(deviceMetrics, deviceMetrics.uint64Metrics, mi, deviceMetrics.metrics[mi].storeIdx); break; default: continue; } - deviceRoot.add_child(metricLabel.label, metricNode); + deviceRoot.add_child(metricLabel, metricNode); } - root.add_child(specs[idx].name, deviceRoot); + root.add_child(specs[idx].id, deviceRoot); } + boost::property_tree::ptree driverRoot; + for (size_t mi = 0; mi < driverMetrics.metricLabels.size(); mi++) { + const char* metricLabel = driverMetrics.metricLabels[mi].label; + + //check if we are interested + if (std::find(std::begin(performanceMetrics), std::end(performanceMetrics), metricLabel) == std::end(performanceMetrics)) { + continue; + } + + //if so + + boost::property_tree::ptree metricNode; + + switch (driverMetrics.metrics[mi].type) { + case MetricType::Int: + metricNode = fillNodeWithValue(driverMetrics, driverMetrics.intMetrics, + mi, driverMetrics.metrics[mi].storeIdx); + break; + + case MetricType::Float: + metricNode = fillNodeWithValue(driverMetrics, driverMetrics.floatMetrics, + mi, driverMetrics.metrics[mi].storeIdx); + break; + + case MetricType::String: + metricNode = fillNodeWithValue(driverMetrics, driverMetrics.stringMetrics, + mi, driverMetrics.metrics[mi].storeIdx); + break; + + case MetricType::Uint64: + metricNode = fillNodeWithValue(driverMetrics, driverMetrics.uint64Metrics, + mi, driverMetrics.metrics[mi].storeIdx); + break; + + default: + continue; + } + driverRoot.add_child(metricLabel, metricNode); + } + + root.add_child("driver", driverRoot); + std::ofstream file("performanceMetrics.json", std::ios::out); if (file.is_open()) { boost::property_tree::json_parser::write_json(file, root); diff --git a/Framework/Core/src/ResourcesMonitoringHelper.h b/Framework/Core/src/ResourcesMonitoringHelper.h index d520f903b8b20..0585f5bbfd1ec 100644 --- a/Framework/Core/src/ResourcesMonitoringHelper.h +++ b/Framework/Core/src/ResourcesMonitoringHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,45 +27,12 @@ struct ResourcesMonitoringHelper { /// Dump the metrics in @a metrics which match the names specified in @a metricsToDump /// @a specs are the DeviceSpecs associated to the metrics. static bool dumpMetricsToJSON(std::vector<DeviceMetricsInfo> const& metrics, + DeviceMetricsInfo const& driverMetrics, std::vector<DeviceSpec> const& specs, std::vector<std::string> const& metricsToDump) noexcept; static bool isResourcesMonitoringEnabled(unsigned short interval) noexcept { return interval > 0; } - - template <typename T> - static boost::property_tree::ptree fillNodeWithValue(const DeviceMetricsInfo& deviceMetrics, - const T& metricsStorage, size_t labelIndex, size_t storageIndex); - - template <typename T> - inline static T retriveValue(T val) - { - return val; - } - inline static std::string retriveValue(const std::reference_wrapper<const StringMetric> val) - { - return std::string(val.get().data); - } }; -template <typename T> -boost::property_tree::ptree ResourcesMonitoringHelper::fillNodeWithValue(const DeviceMetricsInfo& deviceMetrics, - const T& metricsStorage, size_t labelIndex, size_t storageIndex) -{ - - unsigned int loopRange = std::min(deviceMetrics.metrics[labelIndex].filledMetrics, metricsStorage[storageIndex].size()); - boost::property_tree::ptree metricNode; - - for (unsigned int idx = 0; idx < loopRange; ++idx) { - boost::property_tree::ptree values; - values.add("timestamp", deviceMetrics.timestamps[labelIndex][idx]); - if constexpr (std::is_arithmetic_v<T>) { - values.add("value", std::to_string(retriveValue(std::cref(metricsStorage[storageIndex][idx])))); - } else { - values.add("value", retriveValue(std::cref(metricsStorage[storageIndex][idx]))); - } - metricNode.push_back(std::make_pair("", values)); - } - return metricNode; -} } // namespace o2::framework diff --git a/Framework/Core/src/RootConfigParamHelpers.cxx b/Framework/Core/src/RootConfigParamHelpers.cxx index 6c1cb07efb02c..d938e8be51aa7 100644 --- a/Framework/Core/src/RootConfigParamHelpers.cxx +++ b/Framework/Core/src/RootConfigParamHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,8 @@ #include "Framework/RootConfigParamHelpers.h" #include "Framework/ConfigParamSpec.h" +#include "Framework/StringHelpers.h" +#include "Framework/VariantPropertyTreeHelpers.h" #include <TClass.h> #include <TDataMember.h> #include <TDataType.h> @@ -35,14 +38,18 @@ bool isString(TDataMember const& dm) // a generic looper of data members of a TClass; calling a callback // reused in various functions below void loopOverMembers(TClass* cl, void* obj, - std::function<void(const TDataMember*, int, int)>&& callback) + std::function<void(TDataMember*, int, int)>&& callback) { - auto memberlist = cl->GetListOfDataMembers(); + auto* memberlist = cl->GetListOfDataMembers(); for (int i = 0; i < memberlist->GetEntries(); ++i) { - auto dm = (TDataMember*)memberlist->At(i); + auto* dm = (TDataMember*)memberlist->At(i); auto isValidComplex = [dm]() { - return isString(*dm) || dm->IsEnum(); + auto typehash = compile_time_hash(dm->GetTypeName()); + return isString(*dm) || dm->IsEnum() || dm->IsSTLContainer() || + (typehash == compile_time_hash("o2::framework::Array2D<int>")) || + (typehash == compile_time_hash("o2::framework::Array2D<float>")) || + (typehash == compile_time_hash("o2::framework::Array2D<double>")); }; // filter out static members for now @@ -83,10 +90,44 @@ std::string getName(const TDataMember* dm, int index, int size) void ptreeToMember(boost::property_tree::ptree const& value, char const* tname, - TDataMember const* dm, + TDataMember* dm, void* ptr) { - auto dt = dm->GetDataType(); + auto typehash = compile_time_hash(dm->GetTypeName()); + if (dm->IsSTLContainer()) { + switch (typehash) { + case compile_time_hash("vector<int>"): + *static_cast<std::vector<int>*>(ptr) = vectorFromBranch<int>(value); + return; + case compile_time_hash("vector<float>"): + *static_cast<std::vector<float>*>(ptr) = vectorFromBranch<float>(value); + return; + case compile_time_hash("vector<double>"): + *static_cast<std::vector<double>*>(ptr) = vectorFromBranch<double>(value); + return; + case compile_time_hash("vector<bool>"): + throw std::runtime_error("Bool arrays are not implemented yet"); + case compile_time_hash("vector<std::string>"): + case compile_time_hash("vector<string>"): + *static_cast<std::vector<std::string>*>(ptr) = vectorFromBranch<std::string>(value); + return; + default: + throw std::runtime_error("Not an int/float/double/bool vector"); + } + } else { + switch (typehash) { + case compile_time_hash("o2::framework::Array2D<int>"): + *static_cast<Array2D<int>*>(ptr) = array2DFromBranch<int>(value); + return; + case compile_time_hash("o2::framework::Array2D<float>"): + *static_cast<Array2D<float>*>(ptr) = array2DFromBranch<float>(value); + return; + case compile_time_hash("o2::framework::Array2D<double>"): + *static_cast<Array2D<double>*>(ptr) = array2DFromBranch<double>(value); + return; + } + } + auto* dt = dm->GetDataType(); if (dt != nullptr) { switch (dt->GetType()) { case kChar_t: { @@ -125,10 +166,7 @@ void ptreeToMember(boost::property_tree::ptree const& value, *(float*)ptr = value.get_value<float>(); return; } - case kDouble_t: { - *(double*)ptr = value.get_value<double>(); - return; - } + case kDouble_t: case kDouble32_t: { *(double*)ptr = value.get_value<double>(); return; @@ -151,16 +189,44 @@ void ptreeToMember(boost::property_tree::ptree const& value, } } // if we get here none of the above worked - if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string")) { + if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string") == 0) { *(std::string*)ptr = value.get_value<std::string>(); } throw std::runtime_error("Unable to override value"); } // Convert a DataMember to a ConfigParamSpec -ConfigParamSpec memberToConfigParamSpec(const char* tname, TDataMember const* dm, void* ptr) +ConfigParamSpec memberToConfigParamSpec(const char* tname, TDataMember* dm, void* ptr) { - auto dt = dm->GetDataType(); + auto typehash = compile_time_hash(dm->GetTypeName()); + if (dm->IsSTLContainer()) { + switch (typehash) { + case compile_time_hash("vector<int>"): + return ConfigParamSpec{tname, VariantType::ArrayInt, *static_cast<std::vector<int>*>(ptr), {"No help"}}; + case compile_time_hash("vector<float>"): + return ConfigParamSpec{tname, VariantType::ArrayFloat, *static_cast<std::vector<float>*>(ptr), {"No help"}}; + case compile_time_hash("vector<double>"): + return ConfigParamSpec{tname, VariantType::ArrayDouble, *static_cast<std::vector<double>*>(ptr), {"No help"}}; + case compile_time_hash("vector<bool>"): + throw std::runtime_error("bool vector not supported yet"); + // return ConfigParamSpec{tname, VariantType::ArrayBool, *static_cast<std::vector<bool>*>(ptr), {"No help"}}; + case compile_time_hash("vector<std::string>"): + case compile_time_hash("vector<string>"): + return ConfigParamSpec{tname, VariantType::ArrayString, *static_cast<std::vector<std::string>*>(ptr), {"No help"}}; + default: + throw std::runtime_error("Not an int/float/double/bool vector"); + } + } else { + switch (typehash) { + case compile_time_hash("o2::framework::Array2D<int>"): + return ConfigParamSpec{tname, VariantType::Array2DInt, *static_cast<Array2D<int>*>(ptr), {"No help"}}; + case compile_time_hash("o2::framework::Array2D<float>"): + return ConfigParamSpec{tname, VariantType::Array2DFloat, *static_cast<Array2D<float>*>(ptr), {"No help"}}; + case compile_time_hash("o2::framework::Array2D<double>"): + return ConfigParamSpec{tname, VariantType::Array2DDouble, *static_cast<Array2D<double>*>(ptr), {"No help"}}; + } + } + auto* dt = dm->GetDataType(); if (dt != nullptr) { switch (dt->GetType()) { case kChar_t: { @@ -190,9 +256,7 @@ ConfigParamSpec memberToConfigParamSpec(const char* tname, TDataMember const* dm case kFloat_t: { return ConfigParamSpec{tname, VariantType::Float, *(float*)ptr, {"No help"}}; } - case kDouble_t: { - return ConfigParamSpec{tname, VariantType::Double, *(double*)ptr, {"No help"}}; - } + case kDouble_t: case kDouble32_t: { return ConfigParamSpec{tname, VariantType::Double, *(double*)ptr, {"No help"}}; } @@ -211,7 +275,7 @@ ConfigParamSpec memberToConfigParamSpec(const char* tname, TDataMember const* dm } } // if we get here none of the above worked - if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string")) { + if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string") == 0) { return ConfigParamSpec{tname, VariantType::String, *(std::string*)ptr, {"No help"}}; } throw std::runtime_error("Cannot use " + std::string(tname)); @@ -226,9 +290,9 @@ std::vector<ConfigParamSpec> { std::vector<ConfigParamSpec> specs; - auto toDataMember = [&mainKey, &specs, obj](const TDataMember* dm, int index, int size) { - auto dt = dm->GetDataType(); - auto TS = dt ? dt->Size() : 0; + auto toDataMember = [&mainKey, &specs, obj](TDataMember* dm, int index, int size) { + auto* dt = dm->GetDataType(); + auto TS = dt != nullptr ? dt->Size() : 0; char* ptr = ((char*)obj) + dm->GetOffset() + index * TS; const std::string name = mainKey + "." + getName(dm, index, size); @@ -243,9 +307,9 @@ std::vector<ConfigParamSpec> /// using the values in the ptree to override, where appropriate. void RootConfigParamHelpers::fillFromPtree(TClass* cl, void* obj, boost::property_tree::ptree const& pt) { - auto toDataMember = [obj, &pt](const TDataMember* dm, int index, int size) { - auto dt = dm->GetDataType(); - auto TS = dt ? dt->Size() : 0; + auto toDataMember = [obj, &pt](TDataMember* dm, int index, int size) { + auto* dt = dm->GetDataType(); + auto TS = dt != nullptr ? dt->Size() : 0; char* ptr = ((char*)obj) + dm->GetOffset() + index * TS; const std::string name = getName(dm, index, size); auto it = pt.get_child_optional(name); diff --git a/Framework/Core/src/ScopedExit.h b/Framework/Core/src/ScopedExit.h index cf5533591fcd9..aca3c1a19d8b1 100644 --- a/Framework/Core/src/ScopedExit.h +++ b/Framework/Core/src/ScopedExit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/ServiceRegistry.cxx b/Framework/Core/src/ServiceRegistry.cxx index 55d25a6abd67d..1b34e198c22af 100644 --- a/Framework/Core/src/ServiceRegistry.cxx +++ b/Framework/Core/src/ServiceRegistry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,10 @@ namespace o2::framework ServiceRegistry::ServiceRegistry() { - mServicesKey.fill(0L); + for (size_t i = 0; i < MAX_SERVICES; ++i) { + mServicesKey[i].store(0L); + } + mServicesValue.fill(nullptr); for (size_t i = 0; i < mServicesBooked.size(); ++i) { mServicesBooked[i] = false; @@ -96,6 +100,12 @@ void ServiceRegistry::bindService(ServiceSpec const& spec, void* service) if (spec.postDispatching) { mPostDispatchingHandles.push_back(ServiceDispatchingHandle{spec.postDispatching, service}); } + if (spec.start) { + mPreStartHandles.push_back(ServiceStartHandle{spec.start, service}); + } + if (spec.exit) { + mPreExitHandles.push_back(ServiceExitHandle{spec.exit, service}); + } } /// Invoke callbacks to be executed before every process method invokation @@ -152,4 +162,29 @@ void ServiceRegistry::postDispatchingCallbacks(ProcessingContext& processContext } } +/// Callbacks to be called in FairMQDevice::PreRun() +void ServiceRegistry::preStartCallbacks() +{ + // FIXME: we need to call the callback only once for the global services + /// I guess... + for (auto startHandle = mPreStartHandles.begin(); startHandle != mPreStartHandles.end(); ++startHandle) { + startHandle->callback(*this, startHandle->service); + } +} + +/// Invoke callback to be executed on exit, in reverse order. +void ServiceRegistry::preExitCallbacks() +{ + // FIXME: we need to call the callback only once for the global services + /// I guess... + for (auto exitHandle = mPreExitHandles.rbegin(); exitHandle != mPreExitHandles.rend(); ++exitHandle) { + exitHandle->callback(*this, exitHandle->service); + } +} + +void ServiceRegistry::throwError(RuntimeErrorRef const& ref) const +{ + throw ref; +} + } // namespace o2::framework diff --git a/Framework/Core/src/SimpleOptionsRetriever.cxx b/Framework/Core/src/SimpleOptionsRetriever.cxx index d8f725b771ff4..449e2f3d01a5f 100644 --- a/Framework/Core/src/SimpleOptionsRetriever.cxx +++ b/Framework/Core/src/SimpleOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/SimpleRawDeviceService.cxx b/Framework/Core/src/SimpleRawDeviceService.cxx index daf1cb54e0c4d..c268b147ec09b 100644 --- a/Framework/Core/src/SimpleRawDeviceService.cxx +++ b/Framework/Core/src/SimpleRawDeviceService.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/SimpleResourceManager.cxx b/Framework/Core/src/SimpleResourceManager.cxx index 7becac3926160..d8dec64ecfc2c 100644 --- a/Framework/Core/src/SimpleResourceManager.cxx +++ b/Framework/Core/src/SimpleResourceManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/SimpleResourceManager.h b/Framework/Core/src/SimpleResourceManager.h index 8f383ce31f96b..33bc5805e6d39 100644 --- a/Framework/Core/src/SimpleResourceManager.h +++ b/Framework/Core/src/SimpleResourceManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/SourceInfoHeader.cxx b/Framework/Core/src/SourceInfoHeader.cxx index e5e792e1205e7..440dc9424e682 100644 --- a/Framework/Core/src/SourceInfoHeader.cxx +++ b/Framework/Core/src/SourceInfoHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/StepTHn.cxx b/Framework/Core/src/StepTHn.cxx new file mode 100644 index 0000000000000..abc7a37e68bcc --- /dev/null +++ b/Framework/Core/src/StepTHn.cxx @@ -0,0 +1,451 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Use StepTHn instead of THn and your memory consumption will be drastically reduced +// Once you have the merged output, use getTHn() to get a standard histogram +// +// this storage container is optimized for small memory usage +// under/over flow bins do not exist +// sumw2 structure is float only and only create when the weight != 1 +// +// Templated version allows also the use of double as storage container + +#include "Framework/StepTHn.h" +#include "TList.h" +#include "TCollection.h" +#include "TArrayF.h" +#include "TArrayD.h" +#include "THn.h" +#include "TMath.h" + +ClassImp(StepTHn); +templateClassImp(StepTHnT); + +StepTHn::StepTHn() : mNBins(0), + mNVars(0), + mNSteps(0), + mValues(nullptr), + mSumw2(nullptr), + mTarget(nullptr), + mAxisCache(nullptr), + mNbinsCache(nullptr), + mLastVars(nullptr), + mLastBins(nullptr), + mPrototype(nullptr) +{ + // Default constructor (for streaming) +} + +StepTHn::StepTHn(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes) : TNamed(name, title), + mNBins(0), + mNVars(nAxes), + mNSteps(nSteps), + mValues(nullptr), + mSumw2(nullptr), + mTarget(nullptr), + mAxisCache(nullptr), + mNbinsCache(nullptr), + mLastVars(nullptr), + mLastBins(nullptr), + mPrototype(nullptr) +{ + // Constructor + // + // This will create a container for <nSteps> steps. The memory for such a step is only allocated once the first value is filled. + // Therefore you can easily create many steps which are only filled under certain analysis settings. + // For each step a <nAxes> dimensional histogram is created. + // The axis have <nBins[i]> bins. The bin edges are given in <binEdges[i]>. If there are only two bin edges, equidistant binning is set. + + init(); +} + +// root-like constructor +template <class TemplateArray> +StepTHnT<TemplateArray>::StepTHnT(const char* name, const char* title, const int nSteps, const int nAxes, const int* nBins, const double* xmin, const double* xmax) : StepTHn(name, title, nSteps, nAxes) +{ + mNBins = 1; + for (Int_t i = 0; i < mNVars; i++) { + mNBins *= nBins[i]; + } + mPrototype = new THnSparseT<TemplateArray>(Form("%s_sparse", name), title, nAxes, nBins, xmin, xmax); +} + +template <class TemplateArray> +StepTHnT<TemplateArray>::StepTHnT(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes, + Int_t* nBins, std::vector<Double_t> binEdges[], const char** axisTitles) : StepTHn(name, title, nSteps, nAxes) +{ + mNBins = 1; + for (Int_t i = 0; i < mNVars; i++) { + mNBins *= nBins[i]; + } + mPrototype = new THnSparseT<TemplateArray>(Form("%s_sparse", name), title, nAxes, nBins); + + for (Int_t i = 0; i < mNVars; i++) { + if (nBins[i] + 1 == binEdges[i].size()) { // variable-width binning + mPrototype->GetAxis(i)->Set(nBins[i], &(binEdges[i])[0]); + } else if (binEdges[i].size() == 2) { // equidistant binning + mPrototype->GetAxis(i)->Set(nBins[i], binEdges[i][0], binEdges[i][1]); + } else { + LOGF(fatal, "Invalid binning information for axis %d with %d bins and %d entries for bin edges", i, nBins[i], binEdges[i].size()); + } + LOGF(debug, "Histogram %s Axis %d created with %d bins and %d edges", name, i, nBins[i], binEdges[i].size()); + mPrototype->GetAxis(i)->SetTitle(axisTitles[i]); + } +} + +void StepTHn::init() +{ + // initialize + + mValues = new TArray*[mNSteps]; + mSumw2 = new TArray*[mNSteps]; + + for (Int_t i = 0; i < mNSteps; i++) { + mValues[i] = nullptr; + mSumw2[i] = nullptr; + } +} + +StepTHn::StepTHn(const StepTHn& c) : mNBins(c.mNBins), + mNVars(c.mNVars), + mNSteps(c.mNSteps), + mValues(new TArray*[c.mNSteps]), + mSumw2(new TArray*[c.mNSteps]), + mTarget(nullptr), + mAxisCache(nullptr), + mNbinsCache(nullptr), + mLastVars(nullptr), + mLastBins(nullptr), + mPrototype(nullptr) +{ + // + // StepTHn copy constructor + // + + ((StepTHn&)c).Copy(*this); +} + +StepTHn::~StepTHn() +{ + // Destructor + + deleteContainers(); + + delete[] mValues; + delete[] mSumw2; + delete[] mTarget; + delete[] mAxisCache; + delete[] mNbinsCache; + delete[] mLastVars; + delete[] mLastBins; + delete mPrototype; +} + +void StepTHn::deleteContainers() +{ + // delete data containers + + for (Int_t i = 0; i < mNSteps; i++) { + if (mValues && mValues[i]) { + delete mValues[i]; + mValues[i] = nullptr; + } + + if (mSumw2 && mSumw2[i]) { + delete mSumw2[i]; + mSumw2[i] = nullptr; + } + + if (mTarget && mTarget[i]) { + delete mTarget[i]; + mTarget[i] = nullptr; + } + } +} + +StepTHn& StepTHn::operator=(const StepTHn& c) +{ + // assigment operator + + if (this != &c) { + ((StepTHn&)c).Copy(*this); + } + + return *this; +} + +void StepTHn::Copy(TObject& c) const +{ + // copy function + + StepTHn& target = (StepTHn&)c; + + TNamed::Copy(c); + + target.mNBins = mNBins; + target.mNVars = mNVars; + target.mNSteps = mNSteps; + + target.init(); + + for (Int_t i = 0; i < mNSteps; i++) { + if (mValues[i]) { + target.mValues[i] = createArray(mValues[i]); + } else { + target.mValues[i] = nullptr; + } + + if (mSumw2[i]) { + target.mSumw2[i] = createArray(mSumw2[i]); + } else { + target.mSumw2[i] = nullptr; + } + } + + if (mPrototype) { + target.mPrototype = dynamic_cast<THnSparse*>(mPrototype->Clone()); + } +} + +template <class TemplateArray> +Long64_t StepTHnT<TemplateArray>::Merge(TCollection* list) +{ + // Merge a list of StepTHn objects with this (needed for PROOF). + // Returns the number of merged objects (including this). + + if (!list) { + return 0; + } + + if (list->IsEmpty()) { + return 1; + } + + TIterator* iter = list->MakeIterator(); + TObject* obj; + + Int_t count = 0; + while ((obj = iter->Next())) { + + StepTHnT<TemplateArray>* entry = dynamic_cast<StepTHnT<TemplateArray>*>(obj); + if (entry == nullptr) { + continue; + } + + for (Int_t i = 0; i < mNSteps; i++) { + if (entry->mValues[i]) { + if (!mValues[i]) { + mValues[i] = createArray(); + } + + auto source = dynamic_cast<TemplateArray*>(entry->mValues[i])->GetArray(); + auto target = dynamic_cast<TemplateArray*>(mValues[i])->GetArray(); + for (Long64_t l = 0; l < mNBins; l++) { + target[l] += source[l]; + } + } + + if (entry->mSumw2[i]) { + if (!mSumw2[i]) { + mSumw2[i] = createArray(); + } + + auto source = dynamic_cast<TemplateArray*>(entry->mSumw2[i])->GetArray(); + auto target = dynamic_cast<TemplateArray*>(mSumw2[i])->GetArray(); + for (Long64_t l = 0; l < mNBins; l++) { + target[l] += source[l]; + } + } + } + + count++; + } + + return count + 1; +} + +Long64_t StepTHn::getGlobalBinIndex(const Int_t* binIdx) +{ + // calculates global bin index + // binIdx contains TAxis bin indexes + // here bin count starts at 0 because we do not have over/underflow bins + + Long64_t bin = 0; + for (Int_t i = 0; i < mNVars; i++) { + bin *= mPrototype->GetAxis(i)->GetNbins(); + bin += binIdx[i] - 1; + } + + return bin; +} + +void StepTHn::createTarget(Int_t step, Bool_t sparse) +{ + // fills the information stored in the buffer in this class into the target THn + + if (!mValues[step]) { + LOGF(fatal, "Histogram request for step %d which is empty.", step); + return; + } + + if (!mTarget) { + mTarget = new THnBase*[mNSteps]; + for (Int_t i = 0; i < mNSteps; i++) { + mTarget[i] = nullptr; + } + } + + if (mTarget[step]) { + return; + } + + TArray* source = mValues[step]; + // if mSumw2 is not stored, the sqrt of the number of bin entries in source is filled below; otherwise we use mSumw2 + TArray* sourceSumw2 = source; + if (mSumw2[step]) { + sourceSumw2 = mSumw2[step]; + } + + if (sparse) { + mTarget[step] = THnSparse::CreateSparse(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype); + } else { + mTarget[step] = THn::CreateHn(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype); + } + + THnBase* target = mTarget[step]; + + Int_t* binIdx = new Int_t[mNVars]; + Int_t* nBins = new Int_t[mNVars]; + for (Int_t j = 0; j < mNVars; j++) { + binIdx[j] = 1; + nBins[j] = target->GetAxis(j)->GetNbins(); + } + + Long64_t count = 0; + + while (1) { + // for (Int_t j=0; j<mNVars; j++) + // printf("%d ", binIdx[j]); + + Long64_t globalBin = getGlobalBinIndex(binIdx); + // Printf(" --> %lld", globalBin); + + // TODO probably slow + double value = source->GetAt(globalBin); + if (value != 0) { + target->SetBinContent(binIdx, value); + target->SetBinError(binIdx, TMath::Sqrt(sourceSumw2->GetAt(globalBin))); + + count++; + } + + binIdx[mNVars - 1]++; + + for (Int_t j = mNVars - 1; j > 0; j--) { + if (binIdx[j] > nBins[j]) { + binIdx[j] = 1; + binIdx[j - 1]++; + } + } + + if (binIdx[0] > nBins[0]) { + break; + } + } + + LOGF(info, "Step %d: copied %lld entries out of %lld bins", step, count, getGlobalBinIndex(binIdx)); + + delete[] binIdx; + delete[] nBins; + + delete mValues[step]; + mValues[step] = nullptr; +} + +void StepTHn::Fill(int iStep, int nParams, double positionAndWeight[]) +{ + if (iStep >= mNSteps) { + LOGF(FATAL, "Selected step for filling is not in range of StepTHn."); + } + + double weight = 1.0; + if (nParams == mNVars + 1) { + weight = positionAndWeight[mNVars]; + } else if (nParams != mNVars) { + LOGF(FATAL, "Fill called with invalid number of parameters (%d vs %d)", mNVars, nParams); + } + + // fill axis cache + if (!mAxisCache) { + mAxisCache = new TAxis*[mNVars]; + mNbinsCache = new Int_t[mNVars]; + for (Int_t i = 0; i < mNVars; i++) { + mAxisCache[i] = mPrototype->GetAxis(i); + mNbinsCache[i] = mAxisCache[i]->GetNbins(); + } + + mLastVars = new Double_t[mNVars]; + mLastBins = new Int_t[mNVars]; + + // initial values to prevent checking for 0 below + for (Int_t i = 0; i < mNVars; i++) { + mLastVars[i] = positionAndWeight[i]; + mLastBins[i] = mAxisCache[i]->FindBin(mLastVars[i]); + } + } + + // calculate global bin index + Long64_t bin = 0; + for (Int_t i = 0; i < mNVars; i++) { + bin *= mNbinsCache[i]; + + Int_t tmpBin = 0; + if (mLastVars[i] == positionAndWeight[i]) { + tmpBin = mLastBins[i]; + } else { + tmpBin = mAxisCache[i]->FindBin(positionAndWeight[i]); + mLastBins[i] = tmpBin; + mLastVars[i] = positionAndWeight[i]; + } + //Printf("%d", tmpBin); + + // under/overflow not supported + if (tmpBin < 1 || tmpBin > mNbinsCache[i]) { + return; + } + + // bins start from 0 here + bin += tmpBin - 1; + // Printf("%lld", bin); + } + + if (!mValues[iStep]) { + mValues[iStep] = createArray(); + LOGF(info, "Created values container for step %d", iStep); + } + + if (weight != 1.) { + // initialize with already filled entries (which have been filled with weight == 1), in this case mSumw2 := mValues + if (!mSumw2[iStep]) { + mSumw2[iStep] = createArray(); + LOGF(info, "Created sumw2 container for step %d", iStep); + } + } + + // TODO probably slow; add StepTHnT::add ? + mValues[iStep]->SetAt(mValues[iStep]->GetAt(bin) + weight, bin); + if (mSumw2[iStep]) { + mSumw2[iStep]->SetAt(mSumw2[iStep]->GetAt(bin) + weight, bin); + } +} + +template class StepTHnT<TArrayF>; +template class StepTHnT<TArrayD>; diff --git a/Framework/Core/src/StreamOperators.cxx b/Framework/Core/src/StreamOperators.cxx index 66a11d3df8e9d..d9267ec90d854 100644 --- a/Framework/Core/src/StreamOperators.cxx +++ b/Framework/Core/src/StreamOperators.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/StringContext.cxx b/Framework/Core/src/StringContext.cxx new file mode 100644 index 0000000000000..627ec7c501513 --- /dev/null +++ b/Framework/Core/src/StringContext.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/StringContext.h" +#include <FairMQMessage.h> +#include <cassert> + +namespace o2::framework +{ + +void StringContext::addString(std::unique_ptr<FairMQMessage> header, + std::unique_ptr<std::string> s, + const std::string& channel) +{ + mMessages.push_back(std::move(MessageRef{std::move(header), + std::move(s), + channel})); +} + +void StringContext::clear() +{ + // On send we move the header, but the payload remains + // there because what's really sent is the copy of the string + // payload will be cleared by the mMessages.clear() + for (auto& m : mMessages) { + assert(m.header.get() == nullptr); + assert(m.payload.get() != nullptr); + } + mMessages.clear(); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/TMessageSerializer.cxx b/Framework/Core/src/TMessageSerializer.cxx index c8b5f5d95d99c..e50a97e2d0b87 100644 --- a/Framework/Core/src/TMessageSerializer.cxx +++ b/Framework/Core/src/TMessageSerializer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,7 @@ using namespace o2::framework; TMessageSerializer::StreamerList TMessageSerializer::sStreamers{}; std::mutex TMessageSerializer::sStreamersLock{}; -void TMessageSerializer::loadSchema(gsl::span<o2::byte> buffer) +void TMessageSerializer::loadSchema(gsl::span<std::byte> buffer) { std::unique_ptr<TObject> obj = deserialize(buffer); diff --git a/Framework/Core/src/TableBuilder.cxx b/Framework/Core/src/TableBuilder.cxx index f05604c365f38..54b779d01dc80 100644 --- a/Framework/Core/src/TableBuilder.cxx +++ b/Framework/Core/src/TableBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include <arrow/table.h> #include <arrow/type_traits.h> #include <arrow/status.h> +#include <arrow/util/key_value_metadata.h> #if defined(__GNUC__) #pragma GCC diagnostic pop #endif @@ -46,13 +48,43 @@ void ArrayFromVector(const std::vector<C_TYPE>& values, std::shared_ptr<arrow::A namespace o2::framework { +void addLabelToSchema(std::shared_ptr<arrow::Schema>& schema, const char* label) +{ + schema = schema->WithMetadata( + std::make_shared<arrow::KeyValueMetadata>( + std::vector{std::string{"label"}}, + std::vector{std::string{label}})); +} std::shared_ptr<arrow::Table> TableBuilder::finalize() { - mFinalizer(); + bool status = mFinalizer(mSchema, mArrays, mHolders); + if (status == false) { + throwError(runtime_error("Unable to finalize")); + } assert(mSchema->num_fields() > 0 && "Schema needs to be non-empty"); return arrow::Table::Make(mSchema, mArrays); } +void TableBuilder::throwError(RuntimeErrorRef const& ref) +{ + throw ref; +} + +void TableBuilder::validate(const int nColumns, std::vector<std::string> const& columnNames) const +{ + if (nColumns != columnNames.size()) { + throwError(runtime_error("Mismatching number of column types and names")); + } + if (mHolders != nullptr) { + throwError(runtime_error("TableBuilder::persist can only be invoked once per instance")); + } +} + +void TableBuilder::setLabel(const char* label) +{ + mSchema = mSchema->WithMetadata(std::make_shared<arrow::KeyValueMetadata>(std::vector{std::string{"label"}}, std::vector{std::string{label}})); +} + } // namespace o2::framework diff --git a/Framework/Core/src/TableConsumer.cxx b/Framework/Core/src/TableConsumer.cxx index 85b877dd8e046..67c3e5765731b 100644 --- a/Framework/Core/src/TableConsumer.cxx +++ b/Framework/Core/src/TableConsumer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/TableTreeHelpers.cxx b/Framework/Core/src/TableTreeHelpers.cxx index 6f0537fdfdbf1..68e2d674488f0 100644 --- a/Framework/Core/src/TableTreeHelpers.cxx +++ b/Framework/Core/src/TableTreeHelpers.cxx @@ -1,902 +1,427 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/TableTreeHelpers.h" -#include <stdexcept> #include "Framework/Logger.h" #include "arrow/type_traits.h" +#include <arrow/util/key_value_metadata.h> +#include <TBufferFile.h> namespace o2::framework { - -namespace -{ -// ----------------------------------------------------------------------------- -// TreeToTable allows to fill the contents of a given TTree to an arrow::Table -// ColumnIterator is used by TreeToTable -// -// To copy the contents of a tree tr to a table ta do: -// . TreeToTable t2t(tr); -// . t2t.addColumn(columnname1); t2t.addColumn(columnname2); ... -// OR -// t2t.addAllColumns(); -// . auto ta = t2t.process(); -// -// ............................................................................. -class ColumnIterator -{ - - private: - // all the possible TTreeReaderValue<T> types - TTreeReaderValue<bool>* mReaderValue_o = nullptr; - TTreeReaderValue<uint8_t>* mReaderValue_ub = nullptr; - TTreeReaderValue<uint16_t>* mReaderValue_us = nullptr; - TTreeReaderValue<uint32_t>* mReaderValue_ui = nullptr; - TTreeReaderValue<ULong64_t>* mReaderValue_ul = nullptr; - TTreeReaderValue<int8_t>* mReaderValue_b = nullptr; - TTreeReaderValue<int16_t>* mReaderValue_s = nullptr; - TTreeReaderValue<int32_t>* mReaderValue_i = nullptr; - TTreeReaderValue<int64_t>* mReaderValue_l = nullptr; - TTreeReaderValue<float>* mReaderValue_f = nullptr; - TTreeReaderValue<double>* mReaderValue_d = nullptr; - - // all the possible TTreeReaderArray<T> types - TTreeReaderArray<bool>* mReaderArray_o = nullptr; - TTreeReaderArray<uint8_t>* mReaderArray_ub = nullptr; - TTreeReaderArray<uint16_t>* mReaderArray_us = nullptr; - TTreeReaderArray<uint32_t>* mReaderArray_ui = nullptr; - TTreeReaderArray<uint64_t>* mReaderArray_ul = nullptr; - TTreeReaderArray<int8_t>* mReaderArray_b = nullptr; - TTreeReaderArray<int16_t>* mReaderArray_s = nullptr; - TTreeReaderArray<int32_t>* mReaderArray_i = nullptr; - TTreeReaderArray<int64_t>* mReaderArray_l = nullptr; - TTreeReaderArray<float>* mReaderArray_f = nullptr; - TTreeReaderArray<double>* mReaderArray_d = nullptr; - - // all the possible arrow::TBuilder types - arrow::FixedSizeListBuilder* mTableBuilder_list = nullptr; - - arrow::BooleanBuilder* mTableBuilder_o = nullptr; - arrow::UInt8Builder* mTableBuilder_ub = nullptr; - arrow::UInt16Builder* mTableBuilder_us = nullptr; - arrow::UInt32Builder* mTableBuilder_ui = nullptr; - arrow::UInt64Builder* mTableBuilder_ul = nullptr; - arrow::Int8Builder* mTableBuilder_b = nullptr; - arrow::Int16Builder* mTableBuilder_s = nullptr; - arrow::Int32Builder* mTableBuilder_i = nullptr; - arrow::Int64Builder* mTableBuilder_l = nullptr; - arrow::FloatBuilder* mTableBuilder_f = nullptr; - arrow::DoubleBuilder* mTableBuilder_d = nullptr; - - bool mStatus = false; - EDataType mElementType; - int64_t mNumberElements; - const char* mColumnName; - - std::shared_ptr<arrow::Field> mField; - std::shared_ptr<arrow::Array> mArray; - - public: - ColumnIterator(TTreeReader& reader, const char* colname); - ~ColumnIterator(); - - // has the iterator been properly initialized - bool getStatus(); - - // copy the TTreeReaderValue to the arrow::TBuilder - void push(); - - // reserve enough space to push s elements without reallocating - void reserve(size_t s); - - std::shared_ptr<arrow::Array> getArray() { return mArray; } - std::shared_ptr<arrow::Field> getSchema() { return mField; } - - // finish the arrow::TBuilder - // with this mArray is prepared to be used in arrow::Table::Make - void finish(); -}; -} // namespace - -// is used in TableToTree -BranchIterator::BranchIterator(TTree* tree, std::shared_ptr<arrow::ChunkedArray> col, std::shared_ptr<arrow::Field> field) +auto arrowTypeFromROOT(EDataType type, int size) { - mField = field.get(); - mBranchName = mField->name(); - - mFieldType = mField->type()->id(); - mChunks = col->chunks(); - mNumberChuncs = mChunks.size(); - - mLeaflistString = mBranchName; - mElementType = mFieldType; - mNumberElements = 1; - if (mFieldType == arrow::Type::type::FIXED_SIZE_LIST) { - - // element type - if (mField->type()->num_fields() <= 0) { - LOGP(FATAL, "Field {} of type {} has no children!", mField->name(), mField->type()->ToString().c_str()); + auto typeGenerator = [](std::shared_ptr<arrow::DataType>&& type, int size) -> std::shared_ptr<arrow::DataType> { + if (size == 1) { + return std::move(type); } - mElementType = mField->type()->field(0)->type()->id(); - // number of elements - mNumberElements = static_cast<const arrow::FixedSizeListType*>(mField->type().get())->list_size(); - mLeaflistString += "[" + std::to_string(mNumberElements) + "]"; - } + return arrow::fixed_size_list(type, size); + }; - // initialize the branch - mStatus = initBranch(tree); + switch (type) { + case EDataType::kBool_t: + return typeGenerator(arrow::boolean(), size); + case EDataType::kUChar_t: + return typeGenerator(arrow::uint8(), size); + case EDataType::kUShort_t: + return typeGenerator(arrow::uint16(), size); + case EDataType::kUInt_t: + return typeGenerator(arrow::uint32(), size); + case EDataType::kULong64_t: + return typeGenerator(arrow::uint64(), size); + case EDataType::kChar_t: + return typeGenerator(arrow::int8(), size); + case EDataType::kShort_t: + return typeGenerator(arrow::int16(), size); + case EDataType::kInt_t: + return typeGenerator(arrow::int32(), size); + case EDataType::kLong64_t: + return typeGenerator(arrow::int64(), size); + case EDataType::kFloat_t: + return typeGenerator(arrow::float32(), size); + case EDataType::kDouble_t: + return typeGenerator(arrow::float64(), size); + default: + throw runtime_error("Unsupported branch type"); + } +} - mCounterChunk = 0; - mStatus &= initDataBuffer(mCounterChunk); +auto basicROOTTypeFromArrow(arrow::Type::type id) +{ + switch (id) { + case arrow::Type::BOOL: + return ROOTTypeInfo{EDataType::kBool_t, "/O", TDataType::GetDataType(EDataType::kBool_t)->Size()}; + case arrow::Type::UINT8: + return ROOTTypeInfo{EDataType::kUChar_t, "/b", TDataType::GetDataType(EDataType::kUChar_t)->Size()}; + case arrow::Type::UINT16: + return ROOTTypeInfo{EDataType::kUShort_t, "/s", TDataType::GetDataType(EDataType::kUShort_t)->Size()}; + case arrow::Type::UINT32: + return ROOTTypeInfo{EDataType::kUInt_t, "/i", TDataType::GetDataType(EDataType::kUInt_t)->Size()}; + case arrow::Type::UINT64: + return ROOTTypeInfo{EDataType::kULong64_t, "/l", TDataType::GetDataType(EDataType::kULong64_t)->Size()}; + case arrow::Type::INT8: + return ROOTTypeInfo{EDataType::kChar_t, "/B", TDataType::GetDataType(EDataType::kChar_t)->Size()}; + case arrow::Type::INT16: + return ROOTTypeInfo{EDataType::kShort_t, "/S", TDataType::GetDataType(EDataType::kShort_t)->Size()}; + case arrow::Type::INT32: + return ROOTTypeInfo{EDataType::kInt_t, "/I", TDataType::GetDataType(EDataType::kInt_t)->Size()}; + case arrow::Type::INT64: + return ROOTTypeInfo{EDataType::kLong64_t, "/L", TDataType::GetDataType(EDataType::kLong64_t)->Size()}; + case arrow::Type::FLOAT: + return ROOTTypeInfo{EDataType::kFloat_t, "/F", TDataType::GetDataType(EDataType::kFloat_t)->Size()}; + case arrow::Type::DOUBLE: + return ROOTTypeInfo{EDataType::kDouble_t, "/D", TDataType::GetDataType(EDataType::kDouble_t)->Size()}; + default: + throw runtime_error("Unsupported arrow column type"); + } } -BranchIterator::~BranchIterator() +TBranch* BranchToColumn::branch() { - delete mBranchBuffer; - - delete mVariable_o; - delete mVariable_ub; - delete mVariable_us; - delete mVariable_ui; - delete mVariable_ul; - delete mVariable_s; - delete mVariable_i; - delete mVariable_l; - delete mVariable_f; - delete mVariable_d; + return mBranch; } -bool BranchIterator::getStatus() +BranchToColumn::BranchToColumn(TBranch* branch, const char* name, EDataType type, int listSize, arrow::MemoryPool* pool) + : mBranch{branch}, + mColumnName{name}, + mType{type}, + mArrowType{arrowTypeFromROOT(type, listSize)}, + mListSize{listSize} + { - return mStatus; + if (mListSize > 1) { + auto status = arrow::MakeBuilder(pool, mArrowType->field(0)->type(), &mBuilder); + if (!status.ok()) { + throw runtime_error("Cannot create value builder"); + } + mListBuilder = std::make_unique<arrow::FixedSizeListBuilder>(pool, std::move(mBuilder), mListSize); + mValueBuilder = mListBuilder->value_builder(); + } else { + auto status = arrow::MakeBuilder(pool, mArrowType, &mBuilder); + if (!status.ok()) { + throw runtime_error("Cannot create builder"); + } + mValueBuilder = mBuilder.get(); + } } -bool BranchIterator::initBranch(TTree* tree) +std::pair<std::shared_ptr<arrow::ChunkedArray>, std::shared_ptr<arrow::Field>> BranchToColumn::read(TBuffer* buffer) { - // try to find branch in tree - mBranchPtr = tree->GetBranch(mBranchName.c_str()); - if (mBranchPtr) { - return true; + auto totalEntries = static_cast<int>(mBranch->GetEntries()); + auto status = reserve(totalEntries); + if (!status.ok()) { + throw runtime_error("Failed to reserve memory for array builder"); + } + int readEntries = 0; + buffer->Reset(); + while (readEntries < totalEntries) { + auto readLast = mBranch->GetBulkRead().GetBulkEntries(readEntries, *buffer); + readEntries += readLast; + status &= appendValues(reinterpret_cast<unsigned char const*>(buffer->GetCurrent()), readLast); + } + if (!status.ok()) { + throw runtime_error("Failed to append values to array"); } + std::shared_ptr<arrow::Array> array; + status &= finish(&array); + if (!status.ok()) { + throw runtime_error("Failed to create boolean array"); + } + auto fullArray = std::make_shared<arrow::ChunkedArray>(array); + auto field = std::make_shared<arrow::Field>(mBranch->GetName(), mArrowType); + + mBranch->SetStatus(0); + mBranch->DropBaskets("all"); + mBranch->Reset(); + mBranch->GetTransientBuffer(0)->Expand(0); - // create new branch of given data type - switch (mElementType) { - case arrow::Type::type::BOOL: - mLeaflistString += "/O"; + return std::make_pair(fullArray, field); +} + +arrow::Status BranchToColumn::appendValues(unsigned char const* buffer, int numEntries) +{ + arrow::Status status; + switch (mType) { + case EDataType::kBool_t: + status = static_cast<arrow::BooleanBuilder*>(mValueBuilder)->AppendValues(reinterpret_cast<uint8_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::UINT8: - mLeaflistString += "/b"; + case EDataType::kUChar_t: + status = static_cast<arrow::UInt8Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<uint8_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::UINT16: - mLeaflistString += "/s"; + case EDataType::kUShort_t: + status = static_cast<arrow::UInt16Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<uint16_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::UINT32: - mLeaflistString += "/i"; + case EDataType::kUInt_t: + status = static_cast<arrow::UInt32Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<uint32_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::UINT64: - mLeaflistString += "/l"; + case EDataType::kULong64_t: + status = static_cast<arrow::UInt64Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<uint64_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::INT8: - mLeaflistString += "/B"; + case EDataType::kChar_t: + status = static_cast<arrow::Int8Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<int8_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::INT16: - mLeaflistString += "/S"; + case EDataType::kShort_t: + status = static_cast<arrow::Int16Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<int16_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::INT32: - mLeaflistString += "/I"; + case EDataType::kInt_t: + status = static_cast<arrow::Int32Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<int32_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::INT64: - mLeaflistString += "/L"; + case EDataType::kLong64_t: + status = static_cast<arrow::Int64Builder*>(mValueBuilder)->AppendValues(reinterpret_cast<int64_t const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::FLOAT: - mLeaflistString += "/F"; + case EDataType::kFloat_t: + status = static_cast<arrow::FloatBuilder*>(mValueBuilder)->AppendValues(reinterpret_cast<float const*>(buffer), numEntries * mListSize); break; - case arrow::Type::type::DOUBLE: - mLeaflistString += "/D"; + case EDataType::kDouble_t: + status = static_cast<arrow::DoubleBuilder*>(mValueBuilder)->AppendValues(reinterpret_cast<double const*>(buffer), numEntries * mListSize); break; default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + throw runtime_error("Unsupported branch type"); } - - mBranchPtr = tree->Branch(mBranchName.c_str(), mBranchBuffer, mLeaflistString.c_str()); - if (mBranchPtr) { - return true; - } else { - return false; + if (mListSize > 1) { + status &= mListBuilder->AppendValues(numEntries); } + + return status; } -bool BranchIterator::initDataBuffer(Int_t ib) +arrow::Status BranchToColumn::finish(std::shared_ptr<arrow::Array>* array) { - - auto chunkToUse = mChunks.at(ib); - if (mFieldType == arrow::Type::type::FIXED_SIZE_LIST) { - chunkToUse = std::dynamic_pointer_cast<arrow::FixedSizeListArray>(chunkToUse)->values(); + if (mListSize > 1) { + return mListBuilder->Finish(array); } + return mValueBuilder->Finish(array); +} - // reset actual row number - mCounterRow = 0; +arrow::Status BranchToColumn::reserve(int numEntries) +{ + auto status = mValueBuilder->Reserve(numEntries * mListSize); + if (mListSize > 1) { + status &= mListBuilder->Reserve(numEntries); + } + return status; +} - // get next chunk of given data type mElementType - switch (mElementType) { - case arrow::Type::type::BOOL: - if (!mVariable_o) { - mVariable_o = new bool(mNumberElements); - } - mArray_o = std::dynamic_pointer_cast<arrow::BooleanArray>(chunkToUse); - for (int ii = 0; ii < mNumberElements; ii++) { - mVariable_o[ii] = (bool)mArray_o->Value(ii); - } - mValueBuffer = (void*)mVariable_o; - break; - case arrow::Type::type::UINT8: - mVariable_ub = (uint8_t*)std::dynamic_pointer_cast<arrow::UInt8Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_ub; - break; - case arrow::Type::type::UINT16: - mVariable_us = (uint16_t*)std::dynamic_pointer_cast<arrow::UInt16Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_us; - break; - case arrow::Type::type::UINT32: - mVariable_ui = (uint32_t*)std::dynamic_pointer_cast<arrow::UInt32Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_ui; - break; - case arrow::Type::type::UINT64: - mVariable_ul = (uint64_t*)std::dynamic_pointer_cast<arrow::UInt64Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_ul; - break; - case arrow::Type::type::INT8: - mVariable_b = (int8_t*)std::dynamic_pointer_cast<arrow::Int8Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_b; - break; - case arrow::Type::type::INT16: - mVariable_s = (int16_t*)std::dynamic_pointer_cast<arrow::Int16Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_s; - break; - case arrow::Type::type::INT32: - mVariable_i = (int32_t*)std::dynamic_pointer_cast<arrow::Int32Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_i; - break; - case arrow::Type::type::INT64: - mVariable_l = (int64_t*)std::dynamic_pointer_cast<arrow::Int64Array>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_l; - break; - case arrow::Type::type::FLOAT: - mVariable_f = (Float_t*)std::dynamic_pointer_cast<arrow::FloatArray>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_f; +ColumnToBranch::ColumnToBranch(TTree* tree, std::shared_ptr<arrow::ChunkedArray> const& column, std::shared_ptr<arrow::Field> const& field) + : mBranchName{field->name()}, + mColumn{column.get()} +{ + auto arrowType = field->type(); + switch (arrowType->id()) { + case arrow::Type::FIXED_SIZE_LIST: + mListSize = std::static_pointer_cast<arrow::FixedSizeListType>(arrowType)->list_size(); + arrowType = arrowType->field(0)->type(); break; - case arrow::Type::type::DOUBLE: - mVariable_d = (double*)std::dynamic_pointer_cast<arrow::DoubleArray>(chunkToUse)->raw_values(); - mValueBuffer = (void*)mVariable_d; default: break; - LOGP(FATAL, "Type {} not handled!", mElementType); - break; } - mBranchPtr->SetAddress(mValueBuffer); + mType = basicROOTTypeFromArrow(arrowType->id()); + if (mListSize > 1) { + mLeafList = mBranchName + "[" + std::to_string(mListSize) + "]" + mType.suffix; + } else { + mLeafList = mBranchName + mType.suffix; + } + mBranch = tree->GetBranch(mBranchName.c_str()); + if (mBranch == nullptr) { + mBranch = tree->Branch(mBranchName.c_str(), (char*)nullptr, mLeafList.c_str()); + } + if (mType.type == EDataType::kBool_t) { + cache.reserve(mListSize); + mCurrent = reinterpret_cast<uint8_t*>(cache.data()); + mLast = mCurrent + mListSize * mType.size; + allocated = true; + } + accessChunk(0); +} - // reset number of rows mNumberRows and row counter mCounterRow - mNumberRows = mChunks.at(ib)->length(); +void ColumnToBranch::at(const int64_t* pos) +{ + mCurrentPos = pos; + resetBuffer(); +} - return true; +auto ColumnToBranch::getCurrentBuffer() +{ + std::shared_ptr<arrow::PrimitiveArray> array; + if (mListSize > 1) { + array = std::static_pointer_cast<arrow::PrimitiveArray>(std::static_pointer_cast<arrow::FixedSizeListArray>(mColumn->chunk(mCurrentChunk))->values()); + } else { + array = std::static_pointer_cast<arrow::PrimitiveArray>(mColumn->chunk(mCurrentChunk)); + } + return array; } -bool BranchIterator::push() +void ColumnToBranch::resetBuffer() { - // increment row counter - mCounterRow++; - - // mCounterChunk and mCounterRow contain the current chunk and row - // return the next element if available - if (mCounterRow >= mNumberRows) { - mCounterChunk++; - if (mCounterChunk < mNumberChuncs) { - initDataBuffer(mCounterChunk); - } else { - // end of data buffer reached - return false; + if (mType.type == EDataType::kBool_t) { + if (O2_BUILTIN_UNLIKELY((*mCurrentPos - mFirstIndex) * mListSize >= getCurrentBuffer()->length())) { + nextChunk(); } } else { - switch (mElementType) { - case arrow::Type::type::BOOL: - for (int ii = 0; ii < mNumberElements; ii++) { - mVariable_o[ii] = (bool)mArray_o->Value(mCounterRow * mNumberElements + ii); - } - mValueBuffer = (void*)mVariable_o; - break; - case arrow::Type::type::UINT8: - mVariable_ub += mNumberElements; - mValueBuffer = (void*)mVariable_ub; - break; - case arrow::Type::type::UINT16: - mVariable_us += mNumberElements; - mValueBuffer = (void*)mVariable_us; - break; - case arrow::Type::type::UINT32: - mVariable_ui += mNumberElements; - mValueBuffer = (void*)mVariable_ui; - break; - case arrow::Type::type::UINT64: - mVariable_ul += mNumberElements; - mValueBuffer = (void*)mVariable_ul; - break; - case arrow::Type::type::INT8: - mVariable_b += mNumberElements; - mValueBuffer = (void*)mVariable_b; - break; - case arrow::Type::type::INT16: - mVariable_s += mNumberElements; - mValueBuffer = (void*)mVariable_s; - break; - case arrow::Type::type::INT32: - mVariable_i += mNumberElements; - mValueBuffer = (void*)mVariable_i; - break; - case arrow::Type::type::INT64: - mVariable_l += mNumberElements; - mValueBuffer = (void*)mVariable_l; - break; - case arrow::Type::type::FLOAT: - mVariable_f += mNumberElements; - mValueBuffer = (void*)mVariable_f; - break; - case arrow::Type::type::DOUBLE: - mVariable_d += mNumberElements; - mValueBuffer = (void*)mVariable_d; - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + if (O2_BUILTIN_UNLIKELY(mCurrent >= mLast)) { + nextChunk(); } } - mBranchPtr->SetAddress(mValueBuffer); - - return true; + accessChunk(*mCurrentPos); + mBranch->SetAddress((void*)(mCurrent)); } -TableToTree::TableToTree(std::shared_ptr<arrow::Table> table, - TFile* file, - const char* treename) +void ColumnToBranch::accessChunk(int64_t at) { - mTable = table; - - // try to get the tree - mTreePtr = (TTree*)file->Get(treename); - - // create the tree if it does not exist already - if (!mTreePtr) { - // does treename containe folder? - std::string treeName(treename); - auto pos = treeName.find_first_of("/"); - if (pos != std::string::npos) { - file->cd(treeName.substr(0, pos).c_str()); + auto array = getCurrentBuffer(); + + if (mType.type == EDataType::kBool_t) { + auto boolArray = std::static_pointer_cast<arrow::BooleanArray>(array); + for (auto i = 0; i < mListSize; ++i) { + cache[i] = (bool)boolArray->Value((at - mFirstIndex) * mListSize + i); } - treeName = treeName.substr(pos + 1, std::string::npos); - mTreePtr = new TTree(treeName.c_str(), treeName.c_str()); + } else { + mCurrent = array->values()->data() + (at - mFirstIndex) * mListSize * mType.size; + mLast = mCurrent + array->length() * mListSize * mType.size; } } -TableToTree::~TableToTree() +void ColumnToBranch::nextChunk() { - // clean up branch iterators - mBranchIterators.clear(); + ++mCurrentChunk; + mFirstIndex += getCurrentBuffer()->length(); } -bool TableToTree::addBranch(std::shared_ptr<arrow::ChunkedArray> col, std::shared_ptr<arrow::Field> field) +TableToTree::TableToTree(std::shared_ptr<arrow::Table> const& table, TFile* file, const char* treename) { - BranchIterator* brit = new BranchIterator(mTreePtr, col, field); - if (brit->getStatus()) { - mBranchIterators.push_back(brit); + mTable = table.get(); + mTree = static_cast<TTree*>(file->Get(treename)); + if (mTree != nullptr) { + return; } - - return brit->getStatus(); + std::string treeName(treename); + auto pos = treeName.find_first_of('/'); + if (pos != std::string::npos) { + file->cd(treeName.substr(0, pos).c_str()); + treeName = treeName.substr(pos + 1, std::string::npos); + } + mTree = new TTree(treeName.c_str(), treeName.c_str()); } -bool TableToTree::addAllBranches() +void TableToTree::addAllBranches() { - - bool status = mTable->num_columns() > 0; - for (auto ii = 0; ii < mTable->num_columns(); ii++) { - BranchIterator* brit = - new BranchIterator(mTreePtr, mTable->column(ii), mTable->schema()->field(ii)); - if (brit->getStatus()) { - mBranchIterators.push_back(brit); - } else { - status = false; - } + mRows = mTable->num_rows(); + auto columns = mTable->columns(); + auto fields = mTable->schema()->fields(); + assert(columns.size() == fields.size()); + for (auto i = 0u; i < columns.size(); ++i) { + addBranch(columns[i], fields[i]); } - - return status; } -TTree* TableToTree::process() +void TableToTree::addBranch(std::shared_ptr<arrow::ChunkedArray> const& column, std::shared_ptr<arrow::Field> const& field) { - - bool togo = true; - while (togo) { - // fill the tree - mTreePtr->Fill(); - - // update the branches - for (auto brit : mBranchIterators) { - togo &= brit->push(); - } + if (mRows == 0) { + mRows = column->length(); + } else if (mRows != column->length()) { + throw runtime_error_f("Adding incompatible column with size %d (num rows = %d)", column->length(), mRows); } - mTreePtr->Write("", TObject::kOverwrite); - - return mTreePtr; + mColumnReaders.emplace_back(new ColumnToBranch{mTree, column, field}); } -// ----------------------------------------------------------------------------- -#define MAKE_LIST_BUILDER(ElementType, NumElements) \ - std::unique_ptr<arrow::ArrayBuilder> ValueBuilder; \ - arrow::MemoryPool* MemoryPool = arrow::default_memory_pool(); \ - auto stat = MakeBuilder(MemoryPool, ElementType, &ValueBuilder); \ - mTableBuilder_list = new arrow::FixedSizeListBuilder( \ - MemoryPool, \ - std::move(ValueBuilder), \ - NumElements); - -#define MAKE_FIELD(ElementType, NumElements) \ - if (NumElements == 1) { \ - mField = \ - std::make_shared<arrow::Field>(mColumnName, ElementType); \ - } else { \ - mField = \ - std::make_shared<arrow::Field>(mColumnName, arrow::fixed_size_list(ElementType, NumElements)); \ - } - -#define MAKE_FIELD_AND_BUILDER(ElementCType, NumElements, Builder) \ - MAKE_FIELD(arrow::TypeTraits<arrow::CTypeTraits<ElementCType>::ArrowType>::type_singleton(), NumElements); \ - if (NumElements == 1) { \ - arrow::MemoryPool* MemoryPool = arrow::default_memory_pool(); \ - Builder = new arrow::TypeTraits<arrow::CTypeTraits<ElementCType>::ArrowType>::BuilderType(MemoryPool); \ - } else { \ - MAKE_LIST_BUILDER(arrow::TypeTraits<arrow::CTypeTraits<ElementCType>::ArrowType>::type_singleton(), NumElements); \ - Builder = static_cast<arrow::TypeTraits<arrow::CTypeTraits<ElementCType>::ArrowType>::BuilderType*>(mTableBuilder_list->value_builder()); \ - } - -// is used in TreeToTable -ColumnIterator::ColumnIterator(TTreeReader& reader, const char* colname) +TTree* TableToTree::process() { - - // find branch - auto tree = reader.GetTree(); - if (!tree) { - LOGP(FATAL, "Can not locate tree!"); - return; + int64_t row = 0; + if (mTree->GetNbranches() == 0 || mRows == 0) { + mTree->Write("", TObject::kOverwrite); + return mTree; } - auto br = tree->GetBranch(colname); - if (!br) { - LOGP(WARNING, "Can not locate branch {}", colname); - return; - } - mColumnName = colname; - - // type of the branch elements - TClass* cl; - br->GetExpectedType(cl, mElementType); - - // currently only single-value or single-array branches are accepted - // thus of the form e.g. alpha/D or alpha[5]/D - // check if this is a single-value or single-array branch - mNumberElements = 1; - std::string branchTitle = br->GetTitle(); - Int_t pos0 = branchTitle.find("["); - Int_t pos1 = branchTitle.find("]"); - if (pos0 > 0 && pos1 > 0) { - mNumberElements = atoi(branchTitle.substr(pos0 + 1, pos1 - pos0 - 1).c_str()); - } - - // initialize the TTreeReaderValue<T> / TTreeReaderArray<T> - // the corresponding arrow::TBuilder - // the column field - // the TTreeReaderValue is incremented by reader->Next() - // switch according to mElementType - mStatus = true; - - if (mNumberElements == 1) { - switch (mElementType) { - case EDataType::kBool_t: - mReaderValue_o = new TTreeReaderValue<bool>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(bool, 1, mTableBuilder_o); - break; - case EDataType::kUChar_t: - mReaderValue_ub = new TTreeReaderValue<uint8_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint8_t, 1, mTableBuilder_ub); - break; - case EDataType::kUShort_t: - mReaderValue_us = new TTreeReaderValue<uint16_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint16_t, 1, mTableBuilder_us); - break; - case EDataType::kUInt_t: - mReaderValue_ui = new TTreeReaderValue<uint32_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint32_t, 1, mTableBuilder_ui); - break; - case EDataType::kULong64_t: - mReaderValue_ul = new TTreeReaderValue<ULong64_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint64_t, 1, mTableBuilder_ul); - break; - case EDataType::kChar_t: - mReaderValue_b = new TTreeReaderValue<int8_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int8_t, 1, mTableBuilder_b); - break; - case EDataType::kShort_t: - mReaderValue_s = new TTreeReaderValue<int16_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int16_t, 1, mTableBuilder_s); - break; - case EDataType::kInt_t: - mReaderValue_i = new TTreeReaderValue<int32_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int32_t, 1, mTableBuilder_i); - break; - case EDataType::kLong64_t: - mReaderValue_l = new TTreeReaderValue<int64_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int64_t, 1, mTableBuilder_l); - break; - case EDataType::kFloat_t: - mReaderValue_f = new TTreeReaderValue<float>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(float, 1, mTableBuilder_f); - break; - case EDataType::kDouble_t: - mReaderValue_d = new TTreeReaderValue<double>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(double, 1, mTableBuilder_d); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; - } - } else { - switch (mElementType) { - case EDataType::kBool_t: - mReaderArray_o = new TTreeReaderArray<bool>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(bool, mNumberElements, mTableBuilder_o); - break; - case EDataType::kUChar_t: - mReaderArray_ub = new TTreeReaderArray<uint8_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint8_t, mNumberElements, mTableBuilder_ub); - break; - case EDataType::kUShort_t: - mReaderArray_us = new TTreeReaderArray<uint16_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint16_t, mNumberElements, mTableBuilder_us); - break; - case EDataType::kUInt_t: - mReaderArray_ui = new TTreeReaderArray<uint32_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint32_t, mNumberElements, mTableBuilder_ui); - break; - case EDataType::kULong64_t: - mReaderArray_ul = new TTreeReaderArray<uint64_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(uint64_t, mNumberElements, mTableBuilder_ul); - break; - case EDataType::kChar_t: - mReaderArray_b = new TTreeReaderArray<int8_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int8_t, mNumberElements, mTableBuilder_b); - break; - case EDataType::kShort_t: - mReaderArray_s = new TTreeReaderArray<int16_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int16_t, mNumberElements, mTableBuilder_s); - break; - case EDataType::kInt_t: - mReaderArray_i = new TTreeReaderArray<int32_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int32_t, mNumberElements, mTableBuilder_i); - break; - case EDataType::kLong64_t: - mReaderArray_l = new TTreeReaderArray<int64_t>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(int64_t, mNumberElements, mTableBuilder_l); - break; - case EDataType::kFloat_t: - mReaderArray_f = new TTreeReaderArray<float>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(float, mNumberElements, mTableBuilder_f); - break; - case EDataType::kDouble_t: - mReaderArray_d = new TTreeReaderArray<double>(reader, mColumnName); - MAKE_FIELD_AND_BUILDER(double, mNumberElements, mTableBuilder_d); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + while (row < mRows) { + for (auto& reader : mColumnReaders) { + reader->at(&row); } + mTree->Fill(); + ++row; } + mTree->Write("", TObject::kOverwrite); + return mTree; } -ColumnIterator::~ColumnIterator() -{ - // delete all pointers - delete mReaderValue_o; - delete mReaderValue_ub; - delete mReaderValue_us; - delete mReaderValue_ui; - delete mReaderValue_ul; - delete mReaderValue_b; - delete mReaderValue_s; - delete mReaderValue_i; - delete mReaderValue_l; - delete mReaderValue_f; - delete mReaderValue_d; - - delete mReaderArray_o; - delete mReaderArray_ub; - delete mReaderArray_us; - delete mReaderArray_ui; - delete mReaderArray_ul; - delete mReaderArray_b; - delete mReaderArray_s; - delete mReaderArray_i; - delete mReaderArray_l; - delete mReaderArray_f; - delete mReaderArray_d; - - if (mTableBuilder_list) { - delete mTableBuilder_list; - } else { - delete mTableBuilder_o; - delete mTableBuilder_ub; - delete mTableBuilder_us; - delete mTableBuilder_ui; - delete mTableBuilder_ul; - delete mTableBuilder_b; - delete mTableBuilder_s; - delete mTableBuilder_i; - delete mTableBuilder_l; - delete mTableBuilder_f; - delete mTableBuilder_d; - } -}; - -bool ColumnIterator::getStatus() +TreeToTable::TreeToTable(arrow::MemoryPool* pool) + : mArrowMemoryPool{pool} { - return mStatus; } -void ColumnIterator::reserve(size_t s) +void TreeToTable::addAllColumns(TTree* tree, std::vector<std::string>&& names) { - arrow::Status stat; - - switch (mElementType) { - case EDataType::kBool_t: - stat = mTableBuilder_o->Reserve(s * mNumberElements); - break; - case EDataType::kUChar_t: - stat = mTableBuilder_ub->Reserve(s * mNumberElements); - break; - case EDataType::kUShort_t: - stat = mTableBuilder_us->Reserve(s * mNumberElements); - break; - case EDataType::kUInt_t: - stat = mTableBuilder_ui->Reserve(s * mNumberElements); - break; - case EDataType::kULong64_t: - stat = mTableBuilder_ul->Reserve(s * mNumberElements); - break; - case EDataType::kChar_t: - stat = mTableBuilder_b->Reserve(s * mNumberElements); - break; - case EDataType::kShort_t: - stat = mTableBuilder_s->Reserve(s * mNumberElements); - break; - case EDataType::kInt_t: - stat = mTableBuilder_i->Reserve(s * mNumberElements); - break; - case EDataType::kLong64_t: - stat = mTableBuilder_l->Reserve(s * mNumberElements); - break; - case EDataType::kFloat_t: - stat = mTableBuilder_f->Reserve(s * mNumberElements); - break; - case EDataType::kDouble_t: - stat = mTableBuilder_d->Reserve(s * mNumberElements); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + auto branches = tree->GetListOfBranches(); + auto n = branches->GetEntries(); + if (n == 0) { + throw runtime_error("Tree has no branches"); } -} -void ColumnIterator::push() -{ - arrow::Status stat; - - // switch according to mElementType - if (mNumberElements == 1) { - switch (mElementType) { - case EDataType::kBool_t: - mTableBuilder_o->UnsafeAppend((bool)**mReaderValue_o); - break; - case EDataType::kUChar_t: - mTableBuilder_ub->UnsafeAppend(**mReaderValue_ub); - break; - case EDataType::kUShort_t: - mTableBuilder_us->UnsafeAppend(**mReaderValue_us); - break; - case EDataType::kUInt_t: - mTableBuilder_ui->UnsafeAppend(**mReaderValue_ui); - break; - case EDataType::kULong64_t: - mTableBuilder_ul->UnsafeAppend(**mReaderValue_ul); - break; - case EDataType::kChar_t: - mTableBuilder_b->UnsafeAppend(**mReaderValue_b); - break; - case EDataType::kShort_t: - mTableBuilder_s->UnsafeAppend(**mReaderValue_s); - break; - case EDataType::kInt_t: - mTableBuilder_i->UnsafeAppend(**mReaderValue_i); - break; - case EDataType::kLong64_t: - mTableBuilder_l->UnsafeAppend(**mReaderValue_l); - break; - case EDataType::kFloat_t: - mTableBuilder_f->UnsafeAppend(**mReaderValue_f); - break; - case EDataType::kDouble_t: - mTableBuilder_d->UnsafeAppend(**mReaderValue_d); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + if (names.empty()) { + for (auto i = 0; i < n; ++i) { + auto branch = static_cast<TBranch*>(branches->At(i)); + addReader(branch, branch->GetName()); } } else { - stat = mTableBuilder_list->AppendValues(1); - switch (mElementType) { - case EDataType::kBool_t: - stat &= mTableBuilder_o->AppendValues((uint8_t*)&((*mReaderArray_o)[0]), mNumberElements); - break; - case EDataType::kUChar_t: - stat &= mTableBuilder_ub->AppendValues(&((*mReaderArray_ub)[0]), mNumberElements); - break; - case EDataType::kUShort_t: - stat &= mTableBuilder_us->AppendValues(&((*mReaderArray_us)[0]), mNumberElements); - break; - case EDataType::kUInt_t: - stat &= mTableBuilder_ui->AppendValues(&((*mReaderArray_ui)[0]), mNumberElements); - break; - case EDataType::kULong64_t: - stat &= mTableBuilder_ul->AppendValues(&((*mReaderArray_ul)[0]), mNumberElements); - break; - case EDataType::kChar_t: - stat &= mTableBuilder_b->AppendValues(&((*mReaderArray_b)[0]), mNumberElements); - break; - case EDataType::kShort_t: - stat &= mTableBuilder_s->AppendValues(&((*mReaderArray_s)[0]), mNumberElements); - break; - case EDataType::kInt_t: - stat &= mTableBuilder_i->AppendValues(&((*mReaderArray_i)[0]), mNumberElements); - break; - case EDataType::kLong64_t: - stat &= mTableBuilder_l->AppendValues(&((*mReaderArray_l)[0]), mNumberElements); - break; - case EDataType::kFloat_t: - stat &= mTableBuilder_f->AppendValues(&((*mReaderArray_f)[0]), mNumberElements); - break; - case EDataType::kDouble_t: - stat &= mTableBuilder_d->AppendValues(&((*mReaderArray_d)[0]), mNumberElements); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; + for (auto i = 0; i < n; ++i) { + auto branch = static_cast<TBranch*>(branches->At(i)); + auto lookup = std::find_if(names.begin(), names.end(), [&](auto name) { return name == branch->GetName(); }); + if (lookup != names.end()) { + addReader(branch, branch->GetName()); + } + if (mBranchReaders.size() != names.size()) { + LOGF(warn, "Not all requested columns were found in the tree"); + } } } -} - -void ColumnIterator::finish() -{ - arrow::Status stat; - - // switch according to mElementType - if (mNumberElements == 1) { - switch (mElementType) { - case EDataType::kBool_t: - stat = mTableBuilder_o->Finish(&mArray); - break; - case EDataType::kUChar_t: - stat = mTableBuilder_ub->Finish(&mArray); - break; - case EDataType::kUShort_t: - stat = mTableBuilder_us->Finish(&mArray); - break; - case EDataType::kUInt_t: - stat = mTableBuilder_ui->Finish(&mArray); - break; - case EDataType::kULong64_t: - stat = mTableBuilder_ul->Finish(&mArray); - break; - case EDataType::kChar_t: - stat = mTableBuilder_b->Finish(&mArray); - break; - case EDataType::kShort_t: - stat = mTableBuilder_s->Finish(&mArray); - break; - case EDataType::kInt_t: - stat = mTableBuilder_i->Finish(&mArray); - break; - case EDataType::kLong64_t: - stat = mTableBuilder_l->Finish(&mArray); - break; - case EDataType::kFloat_t: - stat = mTableBuilder_f->Finish(&mArray); - break; - case EDataType::kDouble_t: - stat = mTableBuilder_d->Finish(&mArray); - break; - default: - LOGP(FATAL, "Type {} not handled!", mElementType); - break; - } - } else { - stat = mTableBuilder_list->Finish(&mArray); + if (mBranchReaders.empty()) { + throw runtime_error("No columns will be read"); } + //tree->SetCacheSize(50000000); + //// FIXME: see https://github.com/root-project/root/issues/8962 and enable + //// again once fixed. + ////tree->SetClusterPrefetch(true); + //for (auto& reader : mBranchReaders) { + // tree->AddBranchToCache(reader->branch()); + //} + //tree->StopCacheLearningPhase(); } -void TreeToTable::addColumn(const char* colname) +void TreeToTable::setLabel(const char* label) { - mColumnNames.push_back(colname); + mTableLabel = label; } -bool TreeToTable::addAllColumns(TTree* tree) +void TreeToTable::fill(TTree*) { - auto branchList = tree->GetListOfBranches(); - - // loop over branches - if (branchList->IsEmpty()) { - return false; + std::vector<std::shared_ptr<arrow::ChunkedArray>> columns; + std::vector<std::shared_ptr<arrow::Field>> fields; + static TBufferFile buffer{TBuffer::EMode::kWrite, 4 * 1024 * 1024}; + for (auto& reader : mBranchReaders) { + buffer.Reset(); + auto arrayAndField = reader->read(&buffer); + columns.push_back(arrayAndField.first); + fields.push_back(arrayAndField.second); } - for (Int_t ii = 0; ii < branchList->GetEntries(); ii++) { - auto br = (TBranch*)branchList->At(ii); - // IMPROVE: make sure that a column is not added more than one time - mColumnNames.push_back(br->GetName()); - } - return true; + auto schema = std::make_shared<arrow::Schema>(fields, std::make_shared<arrow::KeyValueMetadata>(std::vector{std::string{"label"}}, std::vector{mTableLabel})); + mTable = arrow::Table::Make(schema, columns); } -void TreeToTable::fill(TTree* tree) +void TreeToTable::addReader(TBranch* branch, const char* name) { - std::vector<std::unique_ptr<ColumnIterator>> columnIterators; - TTreeReader treeReader{tree}; - - for (auto&& columnName : mColumnNames) { - auto colit = std::make_unique<ColumnIterator>(treeReader, columnName.c_str()); - auto stat = colit->getStatus(); - if (!stat) { - throw std::runtime_error("Unable to convert column " + columnName); - } - columnIterators.push_back(std::move(colit)); - } - auto numEntries = treeReader.GetEntries(true); - - for (auto&& column : columnIterators) { - column->reserve(numEntries); - } - // copy all values from the tree to the table builders - treeReader.Restart(); - while (treeReader.Next()) { - for (auto&& column : columnIterators) { - column->push(); - } - } - - // prepare the elements needed to create the final table - std::vector<std::shared_ptr<arrow::Array>> array_vector; - std::vector<std::shared_ptr<arrow::Field>> schema_vector; - for (auto&& colit : columnIterators) { - colit->finish(); - array_vector.push_back(colit->getArray()); - schema_vector.push_back(colit->getSchema()); - } - auto fields = std::make_shared<arrow::Schema>(schema_vector); - - // create the final table - // ta is of type std::shared_ptr<arrow::Table> - mTable = (arrow::Table::Make(fields, array_vector)); + static TClass* cls; + EDataType type; + branch->GetExpectedType(cls, type); + auto listSize = static_cast<TLeaf*>(branch->GetListOfLeaves()->At(0))->GetLenStatic(); + mBranchReaders.emplace_back(std::make_unique<BranchToColumn>(branch, name, type, listSize, mArrowMemoryPool)); } std::shared_ptr<arrow::Table> TreeToTable::finalize() diff --git a/Framework/Core/src/Task.cxx b/Framework/Core/src/Task.cxx index 8f947f18755fe..a6d52f292645f 100644 --- a/Framework/Core/src/Task.cxx +++ b/Framework/Core/src/Task.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/TextControlService.cxx b/Framework/Core/src/TextControlService.cxx deleted file mode 100644 index 15f15cd565774..0000000000000 --- a/Framework/Core/src/TextControlService.cxx +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/TextControlService.h" -#include "Framework/DeviceSpec.h" -#include "Framework/DeviceState.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/RawDeviceService.h" -#include "Framework/Logger.h" -#include "DataProcessingHelpers.h" -#include <string> -#include <string_view> -#include <regex> -#include <iostream> - -namespace o2::framework -{ - -TextControlService::TextControlService(ServiceRegistry& registry, DeviceState& deviceState) - : mRegistry{registry}, - mDeviceState{deviceState} -{ -} - -// This will send an end of stream to all the devices downstream. -void TextControlService::endOfStream() -{ - std::scoped_lock lock(mMutex); - mDeviceState.streaming = StreamingState::EndOfStreaming; -} - -// All we do is to printout -void TextControlService::readyToQuit(QuitRequest what) -{ - std::scoped_lock lock(mMutex); - if (mOnce == true) { - return; - } - mOnce = true; - switch (what) { - case QuitRequest::All: - mDeviceState.quitRequested = true; - LOG(INFO) << "CONTROL_ACTION: READY_TO_QUIT_ALL"; - break; - case QuitRequest::Me: - mDeviceState.quitRequested = true; - LOG(INFO) << "CONTROL_ACTION: READY_TO_QUIT_ME"; - break; - } -} - -void TextControlService::notifyStreamingState(StreamingState state) -{ - std::scoped_lock lock(mMutex); - switch (state) { - case StreamingState::Idle: - LOG(INFO) << "CONTROL_ACTION: NOTIFY_STREAMING_STATE IDLE"; - break; - case StreamingState::Streaming: - LOG(INFO) << "CONTROL_ACTION: NOTIFY_STREAMING_STATE STREAMING"; - break; - case StreamingState::EndOfStreaming: - LOG(INFO) << "CONTROL_ACTION: NOTIFY_STREAMING_STATE EOS"; - break; - default: - throw std::runtime_error("Unknown streaming state"); - } -} - -bool parseControl(std::string const& s, std::smatch& match) -{ - char const* action = strstr(s.data(), "CONTROL_ACTION:"); - if (action == nullptr) { - return false; - } - const static std::regex controlRE1(".*CONTROL_ACTION: READY_TO_(QUIT)_(ME|ALL)", std::regex::optimize); - const static std::regex controlRE2(".*CONTROL_ACTION: (NOTIFY_STREAMING_STATE) (IDLE|STREAMING|EOS)", std::regex::optimize); - return std::regex_search(s, match, controlRE1) || std::regex_search(s, match, controlRE2); -} - -} // namespace o2::framework diff --git a/Framework/Core/src/TextDriverClient.cxx b/Framework/Core/src/TextDriverClient.cxx new file mode 100644 index 0000000000000..185db847abb44 --- /dev/null +++ b/Framework/Core/src/TextDriverClient.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "TextDriverClient.h" +#include "Framework/Logger.h" + +namespace o2::framework +{ + +TextDriverClient::TextDriverClient(ServiceRegistry& registry, DeviceState& deviceState) +{ +} + +void TextDriverClient::tell(const char* msg, size_t s, bool flush) +{ + LOG(INFO) << std::string_view{msg, s}; +} + +void TextDriverClient::flushPending() +{ +} + +} // namespace o2::framework diff --git a/Framework/Core/src/TextDriverClient.h b/Framework/Core/src/TextDriverClient.h new file mode 100644 index 0000000000000..04cd9efaa0c84 --- /dev/null +++ b/Framework/Core/src/TextDriverClient.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_TEXTDRIVERCLIENT_H_ +#define O2_FRAMEWORK_TEXTDRIVERCLIENT_H_ + +#include "Framework/DriverClient.h" + +namespace o2::framework +{ + +struct ServiceRegistry; +struct DeviceState; + +/// A text based way of communicating with the driver. +class TextDriverClient : public DriverClient +{ + public: + constexpr static ServiceKind service_kind = ServiceKind::Global; + + TextDriverClient(ServiceRegistry& registry, DeviceState& deviceState); + + /// The text based client simply sends a message on stdout which is + /// (potentially) captured by the driver. + void tell(char const* msg, size_t s, bool flush = true) final; + void flushPending() final; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_TEXTDRIVERCLIENT_H_ diff --git a/Framework/Core/src/TopologyPolicy.cxx b/Framework/Core/src/TopologyPolicy.cxx new file mode 100644 index 0000000000000..d391902a4c945 --- /dev/null +++ b/Framework/Core/src/TopologyPolicy.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/DataProcessorSpec.h" +#include "Framework/TopologyPolicy.h" +#include <string> + +namespace o2::framework +{ + +struct TopologyPolicyHelpers { + static TopologyPolicy::DataProcessorMatcher matchAll(); + static TopologyPolicy::DataProcessorMatcher matchByName(std::string const& name); + static TopologyPolicy::DependencyChecker dataDependency(); + static TopologyPolicy::DependencyChecker alwaysDependent(); +}; + +TopologyPolicy::DataProcessorMatcher TopologyPolicyHelpers::matchAll() +{ + return [](DataProcessorSpec const& spec) { + return true; + }; +} + +TopologyPolicy::DataProcessorMatcher TopologyPolicyHelpers::matchByName(std::string const& name) +{ + return [name](DataProcessorSpec const& spec) { + return spec.name == name; + }; +} + +TopologyPolicy::DependencyChecker TopologyPolicyHelpers::dataDependency() +{ + return [](DataProcessorSpec const& a, DataProcessorSpec const& b) { + for (size_t ii = 0; ii < a.inputs.size(); ++ii) { + for (size_t oi = 0; oi < b.outputs.size(); ++oi) { + try { + if (DataSpecUtils::match(a.inputs[ii], b.outputs[oi])) { + return true; + } + } catch (...) { + continue; + } + } + } + return false; + }; +} + +TopologyPolicy::DependencyChecker TopologyPolicyHelpers::alwaysDependent() +{ + return [](DataProcessorSpec const& dependent, DataProcessorSpec const& ancestor) { + if (dependent.name == ancestor.name) { + return false; + } + return true; + }; +} + +std::vector<TopologyPolicy> TopologyPolicy::createDefaultPolicies() +{ + return { + {TopologyPolicyHelpers::matchByName("dpl-output-proxy"), TopologyPolicyHelpers::alwaysDependent()}, + {TopologyPolicyHelpers::matchAll(), TopologyPolicyHelpers::dataDependency()}}; +} + +} // namespace o2::framework diff --git a/Framework/Core/src/Variant.cxx b/Framework/Core/src/Variant.cxx index 53d75228ef388..41c46e98629cb 100644 --- a/Framework/Core/src/Variant.cxx +++ b/Framework/Core/src/Variant.cxx @@ -1,14 +1,17 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/Variant.h" +#include "Framework/VariantPropertyTreeHelpers.h" #include <iostream> +#include <sstream> namespace o2::framework { @@ -18,12 +21,32 @@ namespace template <typename T> void printArray(std::ostream& oss, T* array, size_t size) { - for (auto i = 0u; i < size; ++i) { - oss << array[i]; - if (i < size - 1) { - oss << ", "; + oss << variant_array_symbol<T>::symbol << "["; + oss << array[0]; + for (auto i = 1U; i < size; ++i) { + oss << ", " << array[i]; + } + oss << "]"; +} + +template <typename T> +void printMatrix(std::ostream& oss, Array2D<T> const& m) +{ + oss << variant_array_symbol<T>::symbol << "[["; + oss << m(0, 0); + for (auto j = 1U; j < m.cols; ++j) { + oss << ", " << m(0, j); + } + oss << "]"; + for (auto i = 1U; i < m.rows; ++i) { + oss << ", ["; + oss << m(i, 0); + for (auto j = 1U; j < m.cols; ++j) { + oss << ", " << m(i, j); } + oss << "]"; } + oss << "]"; } } // namespace @@ -33,6 +56,18 @@ std::ostream& operator<<(std::ostream& oss, Variant const& val) case VariantType::Int: oss << val.get<int>(); break; + case VariantType::UInt8: + oss << val.get<uint8_t>(); + break; + case VariantType::UInt16: + oss << val.get<uint16_t>(); + break; + case VariantType::UInt32: + oss << val.get<uint32_t>(); + break; + case VariantType::UInt64: + oss << val.get<uint64_t>(); + break; case VariantType::Int64: oss << val.get<int64_t>(); break; @@ -60,6 +95,18 @@ std::ostream& operator<<(std::ostream& oss, Variant const& val) case VariantType::ArrayBool: printArray<bool>(oss, val.get<bool*>(), val.size()); break; + case VariantType::ArrayString: + printArray<std::string>(oss, val.get<std::string*>(), val.size()); + break; + case VariantType::Array2DInt: + printMatrix<int>(oss, val.get<Array2D<int>>()); + break; + case VariantType::Array2DFloat: + printMatrix<float>(oss, val.get<Array2D<float>>()); + break; + case VariantType::Array2DDouble: + printMatrix<double>(oss, val.get<Array2D<double>>()); + break; case VariantType::Empty: break; default: @@ -69,4 +116,172 @@ std::ostream& operator<<(std::ostream& oss, Variant const& val) return oss; } +std::string Variant::asString() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +Variant::Variant(const Variant& other) : mType(other.mType) +{ + // In case this is an array we need to duplicate it to avoid + // double deletion. + switch (mType) { + case variant_trait_v<const char*>: + mSize = other.mSize; + variant_helper<storage_t, const char*>::set(&mStore, other.get<const char*>()); + return; + case variant_trait_v<int*>: + mSize = other.mSize; + variant_helper<storage_t, int*>::set(&mStore, other.get<int*>(), mSize); + return; + case variant_trait_v<float*>: + mSize = other.mSize; + variant_helper<storage_t, float*>::set(&mStore, other.get<float*>(), mSize); + return; + case variant_trait_v<double*>: + mSize = other.mSize; + variant_helper<storage_t, double*>::set(&mStore, other.get<double*>(), mSize); + return; + case variant_trait_v<bool*>: + mSize = other.mSize; + variant_helper<storage_t, bool*>::set(&mStore, other.get<bool*>(), mSize); + return; + case variant_trait_v<std::string*>: + mSize = other.mSize; + variant_helper<storage_t, std::string*>::set(&mStore, other.get<std::string*>(), mSize); + return; + default: + mStore = other.mStore; + mSize = other.mSize; + } +} + +Variant::Variant(Variant&& other) noexcept : mType(other.mType) +{ + mStore = other.mStore; + mSize = other.mSize; + switch (mType) { + case variant_trait_v<const char*>: + *reinterpret_cast<char**>(&(other.mStore)) = nullptr; + return; + case variant_trait_v<int*>: + *reinterpret_cast<int**>(&(other.mStore)) = nullptr; + return; + case variant_trait_v<float*>: + *reinterpret_cast<float**>(&(other.mStore)) = nullptr; + return; + case variant_trait_v<double*>: + *reinterpret_cast<double**>(&(other.mStore)) = nullptr; + return; + case variant_trait_v<bool*>: + *reinterpret_cast<bool**>(&(other.mStore)) = nullptr; + return; + case variant_trait_v<std::string*>: + *reinterpret_cast<std::string**>(&(other.mStore)) = nullptr; + default: + return; + } +} + +Variant::~Variant() +{ + // In case we allocated an array, we + // should delete it. + switch (mType) { + case variant_trait_v<const char*>: + case variant_trait_v<int*>: + case variant_trait_v<float*>: + case variant_trait_v<double*>: + case variant_trait_v<bool*>: + case variant_trait_v<std::string*>: + if (reinterpret_cast<void**>(&mStore) != nullptr) { + free(*reinterpret_cast<void**>(&mStore)); + } + return; + default: + return; + } +} + +Variant& Variant::operator=(const Variant& other) +{ + mSize = other.mSize; + mType = other.mType; + switch (mType) { + case variant_trait_v<const char*>: + variant_helper<storage_t, const char*>::set(&mStore, other.get<const char*>()); + return *this; + case variant_trait_v<int*>: + variant_helper<storage_t, int*>::set(&mStore, other.get<int*>(), mSize); + return *this; + case variant_trait_v<float*>: + variant_helper<storage_t, float*>::set(&mStore, other.get<float*>(), mSize); + return *this; + case variant_trait_v<double*>: + variant_helper<storage_t, double*>::set(&mStore, other.get<double*>(), mSize); + return *this; + case variant_trait_v<bool*>: + variant_helper<storage_t, bool*>::set(&mStore, other.get<bool*>(), mSize); + return *this; + case variant_trait_v<std::string*>: + variant_helper<storage_t, std::string*>::set(&mStore, other.get<std::string*>(), mSize); + return *this; + default: + mStore = other.mStore; + return *this; + } +} + +Variant& Variant::operator=(Variant&& other) noexcept +{ + mSize = other.mSize; + mType = other.mType; + switch (mType) { + case variant_trait_v<const char*>: + variant_helper<storage_t, const char*>::set(&mStore, other.get<const char*>()); + *reinterpret_cast<char**>(&(other.mStore)) = nullptr; + return *this; + case variant_trait_v<int*>: + variant_helper<storage_t, int*>::set(&mStore, other.get<int*>(), mSize); + *reinterpret_cast<int**>(&(other.mStore)) = nullptr; + return *this; + case variant_trait_v<float*>: + variant_helper<storage_t, float*>::set(&mStore, other.get<float*>(), mSize); + *reinterpret_cast<float**>(&(other.mStore)) = nullptr; + return *this; + case variant_trait_v<double*>: + variant_helper<storage_t, double*>::set(&mStore, other.get<double*>(), mSize); + *reinterpret_cast<double**>(&(other.mStore)) = nullptr; + return *this; + case variant_trait_v<bool*>: + variant_helper<storage_t, bool*>::set(&mStore, other.get<bool*>(), mSize); + *reinterpret_cast<bool**>(&(other.mStore)) = nullptr; + return *this; + case variant_trait_v<std::string*>: + variant_helper<storage_t, std::string*>::set(&mStore, other.get<std::string*>(), mSize); + *reinterpret_cast<std::string**>(&(other.mStore)) = nullptr; + return *this; + default: + mStore = other.mStore; + return *this; + } +} + +std::pair<std::vector<std::string>, std::vector<std::string>> extractLabels(boost::property_tree::ptree const& tree) +{ + std::vector<std::string> labels_rows; + std::vector<std::string> labels_cols; + auto lrc = tree.get_child_optional(labels_rows_str); + if (lrc) { + labels_rows = basicVectorFromBranch<std::string>(lrc.value()); + } + auto lcc = tree.get_child_optional(labels_cols_str); + if (lcc) { + labels_cols = basicVectorFromBranch<std::string>(lcc.value()); + } + return std::make_pair(labels_rows, labels_cols); +} + } // namespace o2::framework diff --git a/Framework/Core/src/WSDriverClient.cxx b/Framework/Core/src/WSDriverClient.cxx new file mode 100644 index 0000000000000..b37483a7ba2cc --- /dev/null +++ b/Framework/Core/src/WSDriverClient.cxx @@ -0,0 +1,226 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "WSDriverClient.h" +#include "Framework/DeviceState.h" +#include "Framework/DeviceSpec.h" +#include "Framework/Logger.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/DeviceSpec.h" +#include "DriverClientContext.h" +#include "DPLWebSocket.h" +#include <uv.h> +#include <string_view> +#include <charconv> + +namespace o2::framework +{ + +struct ClientWebSocketHandler : public WebSocketHandler { + ClientWebSocketHandler(WSDriverClient& client) + : mClient{client} + { + } + + void headers(std::map<std::string, std::string> const& headers) override + { + } + /// FIXME: not implemented by the backend. + void beginFragmentation() override {} + + /// Invoked when a frame it's parsed. Notice you do not own the data and you must + /// not free the memory. + void frame(char const* frame, size_t s) override + { + mClient.dispatch(std::string_view(frame, s)); + } + + void endFragmentation() override{}; + void control(char const* frame, size_t s) override{}; + + /// Invoked at the beginning of some incoming data. We simply + /// reset actions which need to happen on a per chunk basis. + void beginChunk() override + { + } + + /// Invoked after we have processed all the available incoming data. + /// In this particular case we must handle the metric callbacks, if + /// needed. + void endChunk() override + { + } + + /// The driver context were we want to accumulate changes + /// which we got from the websocket. + WSDriverClient& mClient; +}; + +struct ConnectionContext { + WSDriverClient* client; + DeviceState* state; +}; + +void on_connect(uv_connect_t* connection, int status) +{ + if (status < 0) { + LOG(ERROR) << "Unable to connect to driver."; + return; + } + ConnectionContext* context = (ConnectionContext*)connection->data; + WSDriverClient* client = context->client; + context->state->loopReason |= DeviceState::WS_CONNECTED; + auto onHandshake = [client]() { + client->flushPending(); + }; + std::lock_guard<std::mutex> lock(client->mutex()); + auto handler = std::make_unique<ClientWebSocketHandler>(*client); + client->observe("/ping", [](std::string_view) { + LOG(INFO) << "ping"; + }); + /// FIXME: for now we simply take any offer as 1GB of SHM available + client->observe("/shm-offer", [state = context->state](std::string_view cmd) { + static constexpr int prefixSize = std::string_view{"/shm-offer "}.size(); + if (prefixSize > cmd.size()) { + LOG(ERROR) << "Malformed shared memory offer"; + return; + } + cmd.remove_prefix(prefixSize); + size_t offerSize; + auto offerSizeError = std::from_chars(cmd.data(), cmd.data() + cmd.size(), offerSize); + if (offerSizeError.ec != std::errc()) { + LOG(ERROR) << "Malformed shared memory offer"; + return; + } + LOGP(info, "Received {}MB shared memory offer", offerSize); + ComputingQuotaOffer offer; + offer.cpu = 0; + offer.memory = 0; + offer.sharedMemory = offerSize * 1000000; + offer.runtime = 10000; + offer.user = -1; + offer.valid = true; + + state->pendingOffers.push_back(offer); + }); + + client->observe("/quit", [state = context->state](std::string_view offer) { + state->quitRequested = true; + }); + auto clientContext = std::make_unique<o2::framework::DriverClientContext>(DriverClientContext{client->spec(), context->state}); + client->setDPLClient(std::make_unique<WSDPLClient>(connection->handle, std::move(clientContext), onHandshake, std::move(handler))); + client->sendHandshake(); +} + +/// Helper to connect to a +void connectToDriver(WSDriverClient* driver, DeviceState* state, char const* address, short port) +{ + uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); + uv_tcp_init(state->loop, socket); + uv_connect_t* connection = (uv_connect_t*)malloc(sizeof(uv_connect_t)); + ConnectionContext* context = new ConnectionContext; + context->client = driver; + context->state = state; + connection->data = context; + + struct sockaddr_in dest; + uv_ip4_addr(strdup(address), port, &dest); + + uv_tcp_connect(connection, socket, (const struct sockaddr*)&dest, on_connect); +} + +void on_awake_main_thread(uv_async_t* handle) +{ + DeviceState* state = (DeviceState*)handle->data; + state->loopReason |= DeviceState::ASYNC_NOTIFICATION; +} + +WSDriverClient::WSDriverClient(ServiceRegistry& registry, DeviceState& state, char const* ip, unsigned short port) + : mSpec{registry.get<const DeviceSpec>()} +{ + // Must connect the device to the server and send a websocket request. + // On successful connection we can then start to send commands to the driver. + // We keep a backlog to make sure we do not lose messages. + connectToDriver(this, &state, ip, port); + this->mAwakeMainThread = (uv_async_t*)malloc(sizeof(uv_async_t)); + this->mAwakeMainThread->data = &state; + uv_async_init(state.loop, this->mAwakeMainThread, on_awake_main_thread); +} + +WSDriverClient::~WSDriverClient() +{ + free(this->mAwakeMainThread); +} + +void sendMessageToDriver(std::unique_ptr<o2::framework::WSDPLClient>& client, char const* message, size_t s) +{ +} + +void WSDriverClient::setDPLClient(std::unique_ptr<WSDPLClient> client) +{ + mClient = std::move(client); + mConnected = true; +} + +void WSDriverClient::sendHandshake() +{ + mClient->sendHandshake(); + /// FIXME: nonce should be random +} + +void WSDriverClient::tell(const char* msg, size_t s, bool flush) +{ + // Tell will always accumulate and we signal the main thread we + // have metrics to push + std::lock_guard<std::mutex> lock(mClientMutex); + encode_websocket_frames(mBacklog, msg, s, WebSocketOpCode::Binary, 0); + if (flush) { + this->awake(); + } +} + +void WSDriverClient::awake() +{ + uv_async_send(mAwakeMainThread); +} + +void WSDriverClient::flushPending() +{ + std::lock_guard<std::mutex> lock(mClientMutex); + static bool printed1 = false; + static bool printed2 = false; + if (!mClient) { + if (mBacklog.size() > 2000) { + if (!printed1) { + LOG(WARNING) << "Unable to communicate with driver because client does not exist. Continuing connection attempts."; + printed1 = true; + } + } + return; + } + if (!(mClient->isHandshaken())) { + if (mBacklog.size() > 2000) { + if (!printed2) { + LOG(WARNING) << "Unable to communicate with driver because client is not connected. Continuing connection attempts."; + printed2 = true; + } + } + return; + } + if (printed1 || printed2) { + LOGP(warning, "DriverClient connected successfully. Flushing message backlog of {} messages. All is good.", mBacklog.size()); + printed1 = false; + printed2 = false; + } + mClient->write(mBacklog); + mBacklog.resize(0); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/WSDriverClient.h b/Framework/Core/src/WSDriverClient.h new file mode 100644 index 0000000000000..abf44ec6ed789 --- /dev/null +++ b/Framework/Core/src/WSDriverClient.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_WSDRIVERCLIENT_H_ +#define O2_FRAMEWORK_WSDRIVERCLIENT_H_ + +#include "Framework/DriverClient.h" +#include <uv.h> +#include <functional> +#include <memory> +#include <string> +#include <vector> +#include <mutex> +#include <atomic> + +typedef struct uv_connect_s uv_connect_t; +typedef struct uv_async_s uv_async_t; + +namespace o2::framework +{ + +struct ServiceRegistry; +struct DeviceState; +struct WSDPLClient; +struct DeviceSpec; + +/// Communicate between driver and devices via a websocket +/// This implementation is enabled if you pass --driver-client ws:// +/// as an option. +class WSDriverClient : public DriverClient +{ + public: + WSDriverClient(ServiceRegistry& registry, DeviceState& state, char const* ip, unsigned short port); + ~WSDriverClient(); + void tell(const char* msg, size_t s, bool flush = true) final; + void flushPending() final; + void setDPLClient(std::unique_ptr<WSDPLClient>); + void setConnection(uv_connect_t* connection) { mConnection = connection; }; + DeviceSpec const& spec() { return mSpec; } + // Initiate a websocket session + void sendHandshake(); + std::mutex& mutex() { return mClientMutex; } + + private: + /// Use this to awake the main thread. + void awake(); + // Whether or not we managed to connect. + std::atomic<bool> mConnected = false; + std::mutex mClientMutex; + DeviceSpec const& mSpec; + std::vector<uv_buf_t> mBacklog; + uv_async_t* mAwakeMainThread = nullptr; + uv_connect_t* mConnection = nullptr; + std::unique_ptr<WSDPLClient> mClient; +}; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_WSDRIVERCLIENT_H_ diff --git a/Framework/Core/src/WorkflowCustomizationHelpers.cxx b/Framework/Core/src/WorkflowCustomizationHelpers.cxx new file mode 100644 index 0000000000000..43089703a4e8c --- /dev/null +++ b/Framework/Core/src/WorkflowCustomizationHelpers.cxx @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/WorkflowCustomizationHelpers.h" +#include <string> +#include <cstdlib> +#include <unistd.h> + +namespace +{ +std::string defaultIPCFolder() +{ + /// Find out a place where we can write the sockets + char const* channelPrefix = getenv("TMPDIR"); + if (channelPrefix) { + return std::string(channelPrefix); + } + return access("/tmp", W_OK) == 0 ? "/tmp" : "."; +} +} // namespace + +namespace o2::framework +{ + +std::vector<ConfigParamSpec> WorkflowCustomizationHelpers::requiredWorkflowOptions() +{ + return std::vector<ConfigParamSpec>{{ConfigParamSpec{"readers", VariantType::Int64, 1ll, {"number of parallel readers to use"}}, + ConfigParamSpec{"spawners", VariantType::Int64, 1ll, {"number of parallel spawners to use"}}, + ConfigParamSpec{"pipeline", VariantType::String, "", {"override default pipeline size"}}, + ConfigParamSpec{"clone", VariantType::String, "", {"clone processors from a template"}}, + ConfigParamSpec{"labels", VariantType::String, "", {"add labels to dataprocessors"}}, + ConfigParamSpec{"workflow-suffix", VariantType::String, "", {"suffix to add to all dataprocessors"}}, + + // options for AOD rate limiting + ConfigParamSpec{"aod-memory-rate-limit", VariantType::Int64, 0LL, {"Rate limit AOD processing based on memory"}}, + + // options for AOD writer + ConfigParamSpec{"aod-writer-json", VariantType::String, "", {"Name of the json configuration file"}}, + ConfigParamSpec{"aod-writer-resfile", VariantType::String, "", {"Default name of the output file"}}, + ConfigParamSpec{"aod-writer-resmode", VariantType::String, "RECREATE", {"Creation mode of the result files: NEW, CREATE, RECREATE, UPDATE"}}, + ConfigParamSpec{"aod-writer-ntfmerge", VariantType::Int, -1, {"Number of time frames to merge into one file"}}, + ConfigParamSpec{"aod-writer-keep", VariantType::String, "", {"Comma separated list of ORIGIN/DESCRIPTION/SUBSPECIFICATION:treename:col1/col2/..:filename"}}, + + ConfigParamSpec{"fairmq-rate-logging", VariantType::Int, 0, {"Rate logging for FairMQ channels"}}, + ConfigParamSpec{"fairmq-recv-buffer-size", VariantType::Int, 4, {"recvBufferSize option for FairMQ channels"}}, + ConfigParamSpec{"fairmq-send-buffer-size", VariantType::Int, 4, {"sendBufferSize option for FairMQ channels"}}, + /// Find out a place where we can write the sockets + ConfigParamSpec{"fairmq-ipc-prefix", VariantType::String, defaultIPCFolder(), {"Prefix for FairMQ channels location"}}, + + ConfigParamSpec{"forwarding-policy", VariantType::String, "dangling", {"Which messages to forward." + " *dangling*: dangling outputs," + " all: all messages," + " none: no forwarding - it will complain if you try to create dangling outputs"}}, + ConfigParamSpec{"forwarding-destination", + VariantType::String, + "drop", + {"Destination for forwarded messages." + " drop: simply drop them," + " file: write to file," + " fairmq: send to output proxy"}}}}; +} +} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 9ace1c786f61f..531d032af4b49 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #include "Framework/AlgorithmSpec.h" #include "Framework/AODReaderHelpers.h" #include "Framework/ChannelMatching.h" +#include "Framework/ConfigParamsHelper.h" #include "Framework/CommonDataProcessors.h" #include "Framework/ConfigContext.h" #include "Framework/DeviceSpec.h" @@ -20,6 +22,9 @@ #include "Framework/RawDeviceService.h" #include "Framework/StringHelpers.h" #include "Framework/CommonMessageBackends.h" +#include "Framework/ExternalFairMQDeviceProxy.h" +#include "Framework/Plugins.h" +#include "ArrowSupport.h" #include "Headers/DataHeader.h" #include <algorithm> @@ -30,9 +35,7 @@ #include <climits> #include <thread> -namespace o2 -{ -namespace framework +namespace o2::framework { std::ostream& operator<<(std::ostream& out, TopoIndexInfo const& info) @@ -177,7 +180,7 @@ void addMissingOutputsToBuilder(std::vector<InputSpec>&& requestedIDXs, std::regex word_regex("(\\w+)"); auto words = std::sregex_iterator(s.begin(), s.end(), word_regex); if (std::distance(words, std::sregex_iterator()) != 3) { - throw runtime_error_f("Malformed spec: %s", s.c_str()); + throw runtime_error_f("Malformed input spec metadata: %s", s.c_str()); } std::vector<std::string> data; for (auto i = words; i != std::sregex_iterator(); ++i) { @@ -194,12 +197,14 @@ void addMissingOutputsToBuilder(std::vector<InputSpec>&& requestedIDXs, auto concrete = DataSpecUtils::asConcreteDataMatcher(input); publisher.outputs.emplace_back(OutputSpec{concrete.origin, concrete.description, concrete.subSpec}); for (auto& i : input.metadata) { - auto spec = inputSpecFromString(i.defaultValue.get<std::string>()); - auto j = std::find_if(publisher.inputs.begin(), publisher.inputs.end(), [&](auto x) { return x.binding == spec.binding; }); - if (j == publisher.inputs.end()) { - publisher.inputs.push_back(spec); + if ((i.type == VariantType::String) && (i.name.find("input:") != std::string::npos)) { + auto spec = inputSpecFromString(i.defaultValue.get<std::string>()); + auto j = std::find_if(publisher.inputs.begin(), publisher.inputs.end(), [&](auto x) { return x.binding == spec.binding; }); + if (j == publisher.inputs.end()) { + publisher.inputs.push_back(spec); + } + requestedAODs.push_back(spec); } - requestedAODs.push_back(spec); } } } @@ -247,8 +252,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext if (ctx.options().get<int64_t>("aod-memory-rate-limit")) { aodLifetime = Lifetime::Signal; } - auto readerServices = CommonServices::defaultServices(); - readerServices.push_back(CommonMessageBackends::rateLimitingSpec()); DataProcessorSpec aodReader{ "internal-dpl-aod-reader", @@ -258,14 +261,16 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext static_cast<DataAllocator::SubSpecificationType>(compile_time_hash("internal-dpl-aod-reader")), aodLifetime}}, {}, - readers::AODReaderHelpers::rootFileReaderCallback(), + AlgorithmSpec::dummyAlgorithm(), {ConfigParamSpec{"aod-file", VariantType::String, {"Input AOD file"}}, ConfigParamSpec{"aod-reader-json", VariantType::String, {"json configuration file"}}, ConfigParamSpec{"time-limit", VariantType::Int64, 0ll, {"Maximum run time limit in seconds"}}, + ConfigParamSpec{"orbit-offset-enumeration", VariantType::Int64, 0ll, {"initial value for the orbit"}}, + ConfigParamSpec{"orbit-multiplier-enumeration", VariantType::Int64, 0ll, {"multiplier to get the orbit from the counter"}}, ConfigParamSpec{"start-value-enumeration", VariantType::Int64, 0ll, {"initial value for the enumeration"}}, ConfigParamSpec{"end-value-enumeration", VariantType::Int64, -1ll, {"final value for the enumeration"}}, ConfigParamSpec{"step-value-enumeration", VariantType::Int64, 1ll, {"step between one value and the other"}}}, - readerServices}; + }; std::vector<InputSpec> requestedAODs; std::vector<OutputSpec> providedAODs; @@ -276,8 +281,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext std::vector<OutputSpec> providedCCDBs; std::vector<OutputSpec> providedOutputObjHist; - outputTasks outTskMap; - outputObjects outObjHistMap; + std::vector<OutputTaskInfo> outTskMap; + std::vector<OutputObjectInfo> outObjHistMap; for (size_t wi = 0; wi < workflow.size(); ++wi) { auto& processor = workflow[wi]; @@ -288,6 +293,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext std::string prefix = "internal-dpl-"; if (processor.inputs.empty() && processor.name.compare(0, prefix.size(), prefix) != 0) { processor.inputs.push_back(InputSpec{"enumeration", "DPL", "ENUM", static_cast<DataAllocator::SubSpecificationType>(compile_time_hash(processor.name.c_str())), Lifetime::Enumeration}); + ConfigParamsHelper::addOptionIfMissing(processor.options, ConfigParamSpec{"orbit-offset-enumeration", VariantType::Int64, 0ll, {"1st injected orbit"}}); + ConfigParamsHelper::addOptionIfMissing(processor.options, ConfigParamSpec{"orbit-multiplier-enumeration", VariantType::Int64, 0ll, {"orbits/TForbit"}}); processor.options.push_back(ConfigParamSpec{"start-value-enumeration", VariantType::Int64, 0ll, {"initial value for the enumeration"}}); processor.options.push_back(ConfigParamSpec{"end-value-enumeration", VariantType::Int64, -1ll, {"final value for the enumeration"}}); processor.options.push_back(ConfigParamSpec{"step-value-enumeration", VariantType::Int64, 1ll, {"step between one value and the other"}}); @@ -315,7 +322,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext case Lifetime::Condition: { if (hasConditionOption == false) { processor.options.emplace_back(ConfigParamSpec{"condition-backend", VariantType::String, "http://localhost:8080", {"URL for CCDB"}}); - processor.options.emplace_back(ConfigParamSpec{"condition-timestamp", VariantType::String, "", {"Force timestamp for CCDB lookup"}}); + processor.options.emplace_back(ConfigParamSpec{"condition-timestamp", VariantType::Int64, 0ll, {"Force timestamp for CCDB lookup"}}); hasConditionOption = true; } requestedCCDBs.emplace_back(input); @@ -323,6 +330,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext case Lifetime::QA: case Lifetime::Transient: case Lifetime::Timeframe: + case Lifetime::Optional: break; } if (DataSpecUtils::partialMatch(input, header::DataOrigin{"AOD"})) { @@ -353,11 +361,11 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext providedAODs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATSK"})) { providedOutputObjHist.emplace_back(output); - auto it = std::find_if(outObjHistMap.begin(), outObjHistMap.end(), [&](auto&& x) { return x.first == hash; }); + auto it = std::find_if(outObjHistMap.begin(), outObjHistMap.end(), [&](auto&& x) { return x.id == hash; }); if (it == outObjHistMap.end()) { outObjHistMap.push_back({hash, {output.binding.value}}); } else { - it->second.push_back(output.binding.value); + it->bindings.push_back(output.binding.value); } } if (output.lifetime == Lifetime::Condition) { @@ -407,7 +415,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } if (aodSpawner.outputs.empty() == false) { - extraSpecs.push_back(aodSpawner); + extraSpecs.push_back(timePipeline(aodSpawner, ctx.options().get<int64_t>("spawners"))); } if (indexBuilder.outputs.empty() == false) { @@ -416,6 +424,32 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // add the reader if (aodReader.outputs.empty() == false) { + uv_lib_t supportLib; + int result = 0; +#ifdef __APPLE__ + result = uv_dlopen("libO2FrameworkAnalysisSupport.dylib", &supportLib); +#else + result = uv_dlopen("libO2FrameworkAnalysisSupport.so", &supportLib); +#endif + if (result == -1) { + LOG(FATAL) << uv_dlerror(&supportLib); + return; + } + void* callback = nullptr; + DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*); + + result = uv_dlsym(&supportLib, "dpl_plugin_callback", (void**)&dpl_plugin_callback); + if (result == -1) { + LOG(FATAL) << uv_dlerror(&supportLib); + return; + } + if (dpl_plugin_callback == nullptr) { + LOG(FATAL) << "Could not find the AnalysisSupport plugin."; + return; + } + DPLPluginHandle* pluginInstance = dpl_plugin_callback(nullptr); + AlgorithmPlugin* creator = PluginManager::getByName<AlgorithmPlugin>(pluginInstance, "ROOTFileReader"); + aodReader.algorithm = creator->create(); aodReader.outputs.emplace_back(OutputSpec{"TFN", "TFNumber"}); extraSpecs.push_back(timePipeline(aodReader, ctx.options().get<int64_t>("readers"))); auto concrete = DataSpecUtils::asConcreteDataMatcher(aodReader.inputs[0]); @@ -463,6 +497,12 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext outputsInputsAOD.emplace_back(InputSpec{"tfn", "TFN", "TFNumber"}); auto fileSink = CommonDataProcessors::getGlobalAODSink(dod, outputsInputsAOD); extraSpecs.push_back(fileSink); + + auto it = std::find_if(outputsInputs.begin(), outputsInputs.end(), [](InputSpec& spec) -> bool { + return DataSpecUtils::partialMatch(spec, o2::header::DataOrigin("TFN")); + }); + size_t ii = std::distance(outputsInputs.begin(), it); + outputTypes[ii] &= ~((char)OutputType::DANGLING); } workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); @@ -487,29 +527,131 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } std::vector<InputSpec> unmatched; - if (redirectedOutputsInputs.size() > 0 && ctx.options().get<std::string>("forwarding-destination") == "file") { + auto forwardingDestination = ctx.options().get<std::string>("forwarding-destination"); + if (redirectedOutputsInputs.size() > 0 && forwardingDestination == "file") { auto fileSink = CommonDataProcessors::getGlobalFileSink(redirectedOutputsInputs, unmatched); if (unmatched.size() != redirectedOutputsInputs.size()) { extraSpecs.push_back(fileSink); } - } else if (redirectedOutputsInputs.size() > 0 && ctx.options().get<std::string>("forwarding-destination") == "fairmq") { + } else if (redirectedOutputsInputs.size() > 0 && forwardingDestination == "fairmq") { auto fairMQSink = CommonDataProcessors::getGlobalFairMQSink(redirectedOutputsInputs); extraSpecs.push_back(fairMQSink); + } else if (forwardingDestination != "drop") { + throw runtime_error_f("Unknown forwarding destination %s", forwardingDestination.c_str()); } - if (unmatched.size() > 0) { - extraSpecs.push_back(CommonDataProcessors::getDummySink(unmatched)); + if (unmatched.size() > 0 || redirectedOutputsInputs.size() > 0) { + std::vector<InputSpec> ignored = unmatched; + ignored.insert(ignored.end(), redirectedOutputsInputs.begin(), redirectedOutputsInputs.end()); + extraSpecs.push_back(CommonDataProcessors::getDummySink(ignored)); } workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); extraSpecs.clear(); } +void WorkflowHelpers::adjustServiceDevices(WorkflowSpec& workflow) +{ + auto spawner = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec& spec) { return spec.name == "internal-dpl-aod-spawner"; }); + auto builder = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec& spec) { return spec.name == "internal-dpl-aod-index-builder"; }); + auto reader = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec& spec) { return spec.name == "internal-dpl-aod-reader"; }); + + if (spawner != workflow.end()) { + std::vector<InputSpec> requestedDYNs; + // collect currently requested DYNs + for (auto& d : workflow) { + if (d.name == spawner->name) { + continue; + } + for (auto& i : d.inputs) { + if (DataSpecUtils::partialMatch(i, header::DataOrigin{"DYN"})) { + requestedDYNs.emplace_back(i); + } + } + std::sort(requestedDYNs.begin(), requestedDYNs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding < b.binding; }); + auto end = std::unique(requestedDYNs.begin(), requestedDYNs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding == b.binding; }); + requestedDYNs.erase(end, requestedDYNs.end()); + } + + // remove unmatched outputs + auto o_end = std::remove_if(spawner->outputs.begin(), spawner->outputs.end(), [&](OutputSpec const& o) { + return std::none_of(requestedDYNs.begin(), requestedDYNs.end(), [&](InputSpec const& i) { return DataSpecUtils::match(i, o); }); + }); + spawner->outputs.erase(o_end, spawner->outputs.end()); + + // remove unmatched inputs + auto i_end = std::remove_if(spawner->inputs.begin(), spawner->inputs.end(), [&](InputSpec const& i) { + auto&& [origin, description] = DataSpecUtils::asConcreteDataTypeMatcher(i); + return std::none_of(spawner->outputs.begin(), spawner->outputs.end(), [description = description](OutputSpec const& o) { + return DataSpecUtils::partialMatch(o, description); + }); + }); + spawner->inputs.erase(i_end, spawner->inputs.end()); + + // replace AlgorithmSpec + // FIXME: it should be made more generic, so it does not need replacement... + spawner->algorithm = readers::AODReaderHelpers::aodSpawnerCallback(requestedDYNs); + } + + if (builder != workflow.end()) { + // collect currently requested IDXs + std::vector<InputSpec> requestedIDXs; + std::vector<InputSpec> dummy_i; + std::vector<OutputSpec> dummy_o; + for (auto& d : workflow) { + if (d.name == builder->name) { + continue; + } + for (auto& i : d.inputs) { + if (DataSpecUtils::partialMatch(i, header::DataOrigin{"IDX"})) { + requestedIDXs.emplace_back(i); + } + } + std::sort(requestedIDXs.begin(), requestedIDXs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding < b.binding; }); + auto end = std::unique(requestedIDXs.begin(), requestedIDXs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding == b.binding; }); + requestedIDXs.erase(end, requestedIDXs.end()); + } + + // recreate inputs and outputs + builder->inputs = dummy_i; + builder->outputs = dummy_o; + auto copy = requestedIDXs; + addMissingOutputsToBuilder(std::move(copy), dummy_i, *builder); + + //replace AlgorithmSpec + // FIXME: it should be made more generic, so it does not need replacement... + builder->algorithm = readers::AODReaderHelpers::indexBuilderCallback(requestedIDXs); + } + + if (reader != workflow.end() && (spawner != workflow.end() || builder != workflow.end())) { + // If reader and/or builder were adjusted, remove unneeded outputs + std::vector<InputSpec> requestedAODs; + // collect currently requested AODs + for (auto& d : workflow) { + for (auto& i : d.inputs) { + if (DataSpecUtils::partialMatch(i, header::DataOrigin{"AOD"})) { + requestedAODs.emplace_back(i); + } + } + std::sort(requestedAODs.begin(), requestedAODs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding < b.binding; }); + auto end = std::unique(requestedAODs.begin(), requestedAODs.end(), [](InputSpec const& a, InputSpec const& b) { return a.binding == b.binding; }); + requestedAODs.erase(end, requestedAODs.end()); + } + + // remove unmatched outputs + auto o_end = std::remove_if(reader->outputs.begin(), reader->outputs.end(), [&](OutputSpec const& o) { + return !DataSpecUtils::partialMatch(o, o2::header::DataDescription{"TFNumber"}) && std::none_of(requestedAODs.begin(), requestedAODs.end(), [&](InputSpec const& i) { return DataSpecUtils::match(i, o); }); + }); + reader->outputs.erase(o_end, reader->outputs.end()); + } +} + void WorkflowHelpers::constructGraph(const WorkflowSpec& workflow, std::vector<DeviceConnectionEdge>& logicalEdges, std::vector<OutputSpec>& outputs, std::vector<LogicalForwardInfo>& forwardedInputsInfo) { assert(!workflow.empty()); + // This is the state. Oif is the iterator I use for the searches. std::list<LogicalOutputInfo> availableOutputsInfo; auto const& constOutputs = outputs; // const version of the outputs @@ -618,7 +760,7 @@ void WorkflowHelpers::constructGraph(const WorkflowSpec& workflow, auto input = workflow[ci].inputs[ii]; std::ostringstream str; str << "No matching output found for " - << DataSpecUtils::describe(input) << ". Candidates:\n"; + << DataSpecUtils::describe(input) << " as requested by data processor \"" << workflow[ci].name << "\". Candidates:\n"; for (auto& output : constOutputs) { str << "-" << DataSpecUtils::describe(output) << "\n"; @@ -776,6 +918,9 @@ WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::Workfl if (spec.name.empty()) { throw std::runtime_error("Invalid DataProcessorSpec name"); } + if (strpbrk(spec.name.data(), ",;:\"'$") != nullptr) { + throw std::runtime_error("Cannot use any of ,;:\"'$ as DataProcessor name"); + } if (validNames.find(spec.name) != validNames.end()) { throw std::runtime_error("Name " + spec.name + " is used twice."); } @@ -983,5 +1128,4 @@ std::vector<InputSpec> WorkflowHelpers::computeDanglingOutputs(WorkflowSpec cons return results; } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowHelpers.h b/Framework/Core/src/WorkflowHelpers.h index c673b1e9940b0..7d3c98bb5cb42 100644 --- a/Framework/Core/src/WorkflowHelpers.h +++ b/Framework/Core/src/WorkflowHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,7 @@ #include "Framework/ForwardRoute.h" #include "Framework/WorkflowSpec.h" #include "Framework/DataOutputDirector.h" -#include "DataProcessorInfo.h" +#include "Framework/DataProcessorInfo.h" #include <cstddef> #include <vector> @@ -177,6 +178,10 @@ struct WorkflowHelpers { // @a ctx the context for the configuration phase static void injectServiceDevices(WorkflowSpec& workflow, ConfigContext const& ctx); + // Re-adjust service devices if the inputs of other devices were modified + // @a workflow to analyze + static void adjustServiceDevices(WorkflowSpec& workflow); + static void constructGraph(const WorkflowSpec& workflow, std::vector<DeviceConnectionEdge>& logicalEdges, std::vector<OutputSpec>& outputs, diff --git a/Framework/Core/src/WorkflowSerializationHelpers.cxx b/Framework/Core/src/WorkflowSerializationHelpers.cxx index 20bb11ee7407e..fc4d0765a20ed 100644 --- a/Framework/Core/src/WorkflowSerializationHelpers.cxx +++ b/Framework/Core/src/WorkflowSerializationHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,9 @@ #include "Framework/WorkflowSpec.h" #include "Framework/DataDescriptorQueryBuilder.h" #include "Framework/DataSpecUtils.h" +#include "Framework/VariantJSONHelpers.h" +#include "Framework/DataDescriptorMatcher.h" +#include "Framework/Logger.h" #include <rapidjson/reader.h> #include <rapidjson/prettywriter.h> @@ -21,12 +25,11 @@ #include <algorithm> #include <memory> -namespace o2 -{ -namespace framework +namespace o2::framework { using namespace rapidjson; +using namespace o2::framework::data_matcher; struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, WorkflowImporter> { enum struct State { @@ -34,6 +37,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, IN_EXECUTION, IN_WORKFLOW, IN_METADATA, + IN_COMMAND, IN_DATAPROCESSORS, IN_DATAPROCESSOR, IN_DATAPROCESSOR_NAME, @@ -44,6 +48,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, IN_INPUTS, IN_OUTPUTS, IN_OPTIONS, + IN_LABELS, IN_WORKFLOW_OPTIONS, IN_INPUT, IN_INPUT_BINDING, @@ -63,6 +68,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, IN_OPTION_TYPE, IN_OPTION_DEFAULT, IN_OPTION_HELP, + IN_OPTION_KIND, + IN_LABEL, IN_METADATUM, IN_METADATUM_NAME, IN_METADATUM_EXECUTABLE, @@ -85,6 +92,9 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, case State::IN_WORKFLOW: s << "IN_WORKFLOW"; break; + case State::IN_COMMAND: + s << "IN_COMMAND"; + break; case State::IN_DATAPROCESSORS: s << "IN_DATAPROCESSORS"; break; @@ -115,6 +125,9 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, case State::IN_OPTIONS: s << "IN_OPTIONS"; break; + case State::IN_LABELS: + s << "IN_LABELS"; + break; case State::IN_WORKFLOW_OPTIONS: s << "IN_WORKFLOW_OPTIONS"; break; @@ -172,6 +185,12 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, case State::IN_OPTION_HELP: s << "IN_OPTION_HELP"; break; + case State::IN_OPTION_KIND: + s << "IN_OPTION_KIND"; + break; + case State::IN_LABEL: + s << "IN_LABEL"; + break; case State::IN_ERROR: s << "IN_ERROR"; break; @@ -204,10 +223,12 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, } WorkflowImporter(std::vector<DataProcessorSpec>& o, - std::vector<DataProcessorInfo>& m) + std::vector<DataProcessorInfo>& m, + CommandInfo& c) : states{}, dataProcessors{o}, - metadata{m} + metadata{m}, + command{c} { push(State::IN_START); } @@ -224,6 +245,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, dataProcessors.push_back(DataProcessorSpec{}); } else if (in(State::IN_INPUTS)) { push(State::IN_INPUT); + inputHasDescription = false; inputHasSubSpec = false; } else if (in(State::IN_OUTPUTS)) { push(State::IN_OUTPUT); @@ -239,6 +261,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, metadata.push_back(DataProcessorInfo{}); } else if (in(State::IN_METADATUM)) { metadata.push_back(DataProcessorInfo{}); + } else if (in(State::IN_COMMAND)) { + command = CommandInfo{}; } return true; } @@ -247,12 +271,33 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, { enter("END_OBJECT"); if (in(State::IN_INPUT)) { - if (inputHasSubSpec) { - dataProcessors.back().inputs.push_back(InputSpec(binding, origin, description, subspec, lifetime, inputOptions)); + if (!inputHasDescription && !inputHasSubSpec) { + + DataDescriptorMatcher expectedMatcher00{ + DataDescriptorMatcher::Op::And, + OriginValueMatcher{origin.str}, + std::make_unique<DataDescriptorMatcher>( + DataDescriptorMatcher::Op::And, + DescriptionValueMatcher{ContextRef{1}}, + std::make_unique<DataDescriptorMatcher>( + DataDescriptorMatcher::Op::And, + SubSpecificationTypeValueMatcher{ContextRef{2}}, + std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Just, + StartTimeValueMatcher{ContextRef{0}})))}; + + dataProcessors.back().inputs.push_back(InputSpec({binding}, std::move(expectedMatcher00))); + } else if (inputHasDescription) { + if (inputHasSubSpec) { + dataProcessors.back().inputs.push_back(InputSpec(binding, origin, description, subspec, lifetime, inputOptions)); + } else { + dataProcessors.back().inputs.push_back(InputSpec(binding, {origin, description}, lifetime, inputOptions)); + } } else { - dataProcessors.back().inputs.push_back(InputSpec(binding, {origin, description}, lifetime, inputOptions)); + LOG(ERROR) << "Input w/o description but with subspec is not supported"; } + inputOptions.clear(); + inputHasDescription = false; inputHasSubSpec = false; } else if (in(State::IN_OUTPUT)) { if (outputHasSubSpec) { @@ -265,27 +310,74 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, std::unique_ptr<ConfigParamSpec> opt{nullptr}; using HelpString = ConfigParamSpec::HelpString; + std::stringstream is; + is.str(optionDefault); switch (optionType) { case VariantType::String: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, optionDefault.c_str(), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, optionDefault.c_str(), HelpString{optionHelp}, optionKind); break; case VariantType::Int: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stoi(optionDefault, nullptr), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stoi(optionDefault, nullptr), HelpString{optionHelp}, optionKind); + break; + case VariantType::UInt8: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, static_cast<uint8_t>(std::stoul(optionDefault, nullptr)), HelpString{optionHelp}, optionKind); + break; + case VariantType::UInt16: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, static_cast<uint16_t>(std::stoul(optionDefault, nullptr)), HelpString{optionHelp}, optionKind); + break; + case VariantType::UInt32: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, static_cast<uint32_t>(std::stoul(optionDefault, nullptr)), HelpString{optionHelp}, optionKind); + break; + case VariantType::UInt64: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stoul(optionDefault, nullptr), HelpString{optionHelp}, optionKind); break; case VariantType::Int64: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stol(optionDefault, nullptr), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stol(optionDefault, nullptr), HelpString{optionHelp}, optionKind); break; case VariantType::Float: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stof(optionDefault, nullptr), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stof(optionDefault, nullptr), HelpString{optionHelp}, optionKind); break; case VariantType::Double: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stod(optionDefault, nullptr), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, std::stod(optionDefault, nullptr), HelpString{optionHelp}, optionKind); break; case VariantType::Bool: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, (bool)std::stoi(optionDefault, nullptr), HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, (bool)std::stoi(optionDefault, nullptr), HelpString{optionHelp}, optionKind); + break; + case VariantType::ArrayInt: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::ArrayInt>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::ArrayFloat: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::ArrayFloat>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::ArrayDouble: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::ArrayDouble>(is), HelpString{optionHelp}, optionKind); + break; + // case VariantType::ArrayBool: + // opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::ArrayBool>(is), HelpString{optionHelp}, optionKind); + // break; + case VariantType::ArrayString: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::ArrayString>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::Array2DInt: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::Array2DInt>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::Array2DFloat: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::Array2DFloat>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::Array2DDouble: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::Array2DDouble>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::LabeledArrayInt: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::LabeledArrayInt>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::LabeledArrayFloat: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::LabeledArrayFloat>(is), HelpString{optionHelp}, optionKind); + break; + case VariantType::LabeledArrayDouble: + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, VariantJSONHelpers::read<VariantType::LabeledArrayDouble>(is), HelpString{optionHelp}, optionKind); break; default: - opt = std::make_unique<ConfigParamSpec>(optionName, optionType, optionDefault, HelpString{optionHelp}); + opt = std::make_unique<ConfigParamSpec>(optionName, optionType, optionDefault, HelpString{optionHelp}, optionKind); } // Depending on the previous state, push options to the right place. if (previousIs(State::IN_OPTIONS)) { @@ -309,6 +401,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_DATAPROCESSORS); } else if (in(State::IN_INPUTS)) { push(State::IN_INPUT); + inputHasDescription = false; inputHasSubSpec = false; } else if (in(State::IN_INPUT_OPTIONS)) { push(State::IN_OPTION); @@ -319,6 +412,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_OPTION); } else if (in(State::IN_WORKFLOW_OPTIONS)) { push(State::IN_OPTION); + } else if (in(State::IN_LABELS)) { + push(State::IN_LABEL); } else if (in(State::IN_METADATA)) { push(State::IN_METADATUM); } else if (in(State::IN_METADATUM_ARGS)) { @@ -334,7 +429,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, enter("END_ARRAY"); // Handle the case in which inputs / options / outputs are // empty. - if (in(State::IN_INPUT) || in(State::IN_OUTPUT) || in(State::IN_OPTION) || in(State::IN_METADATUM) || in(State::IN_METADATUM_ARG) || in(State::IN_METADATUM_CHANNEL) || in(State::IN_DATAPROCESSORS)) { + if (in(State::IN_INPUT) || in(State::IN_OUTPUT) || in(State::IN_OPTION) || in(State::IN_LABEL) || in(State::IN_METADATUM) || in(State::IN_METADATUM_ARG) || in(State::IN_METADATUM_CHANNEL) || in(State::IN_DATAPROCESSORS)) { pop(); } pop(); @@ -351,6 +446,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_INPUT_ORIGIN); } else if (in(State::IN_INPUT) && strncmp(str, "description", length) == 0) { push(State::IN_INPUT_DESCRIPTION); + inputHasDescription = true; } else if (in(State::IN_INPUT) && strncmp(str, "subspec", length) == 0) { push(State::IN_INPUT_SUBSPEC); inputHasSubSpec = true; @@ -385,6 +481,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_OUTPUTS); } else if (in(State::IN_DATAPROCESSOR) && strncmp(str, "options", length) == 0) { push(State::IN_OPTIONS); + } else if (in(State::IN_DATAPROCESSOR) && strncmp(str, "labels", length) == 0) { + push(State::IN_LABELS); } else if (in(State::IN_EXECUTION) && strncmp(str, "workflow", length) == 0) { push(State::IN_WORKFLOW); } else if (in(State::IN_EXECUTION) && strncmp(str, "metadata", length) == 0) { @@ -397,6 +495,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_OPTION_DEFAULT); } else if (in(State::IN_OPTION) && strncmp(str, "help", length) == 0) { push(State::IN_OPTION_HELP); + } else if (in(State::IN_OPTION) && strncmp(str, "kind", length) == 0) { + push(State::IN_OPTION_KIND); } else if (in(State::IN_METADATUM) && strncmp(str, "name", length) == 0) { push(State::IN_METADATUM_NAME); } else if (in(State::IN_METADATUM) && strncmp(str, "executable", length) == 0) { @@ -407,6 +507,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, push(State::IN_WORKFLOW_OPTIONS); } else if (in(State::IN_METADATUM) && strncmp(str, "channels", length) == 0) { push(State::IN_METADATUM_CHANNELS); + } else if (in(State::IN_EXECUTION) && strncmp(str, "command", length) == 0) { + push(State::IN_COMMAND); } return true; } @@ -428,23 +530,30 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, } else if (in(State::IN_INPUT_BINDING)) { binding = s; } else if (in(State::IN_INPUT_ORIGIN)) { - origin.runtimeInit(s.c_str(), std::min(s.size(), 16UL)); + origin.runtimeInit(s.c_str(), std::min(s.size(), 4UL)); } else if (in(State::IN_INPUT_DESCRIPTION)) { description.runtimeInit(s.c_str(), std::min(s.size(), 16UL)); } else if (in(State::IN_OUTPUT_BINDING)) { binding = s; } else if (in(State::IN_OUTPUT_ORIGIN)) { - origin.runtimeInit(s.c_str(), std::min(s.size(), 16UL)); + origin.runtimeInit(s.c_str(), std::min(s.size(), 4UL)); } else if (in(State::IN_OUTPUT_DESCRIPTION)) { description.runtimeInit(s.c_str(), std::min(s.size(), 16UL)); } else if (in(State::IN_OPTION_NAME)) { optionName = s; } else if (in(State::IN_OPTION_TYPE)) { optionType = (VariantType)std::stoi(s, nullptr); + } else if (in(State::IN_OPTION_KIND)) { + optionKind = (ConfigParamKind)std::stoi(s, nullptr); } else if (in(State::IN_OPTION_DEFAULT)) { optionDefault = s; } else if (in(State::IN_OPTION_HELP)) { optionHelp = s; + } else if (in(State::IN_LABEL)) { + dataProcessors.back().labels.push_back({s}); + // This is in an array, so we do not actually want to + // exit from the state. + push(State::IN_LABEL); } else if (in(State::IN_METADATUM_ARG)) { metadata.back().cmdLineArgs.push_back(s); // This is in an array, so we do not actually want to @@ -455,6 +564,8 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, // This is in an array, so we do not actually want to // exit from the state. push(State::IN_METADATUM_CHANNEL); + } else if (in(State::IN_COMMAND)) { + command.merge({s}); } pop(); return true; @@ -541,6 +652,7 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, std::string spec; std::vector<DataProcessorSpec>& dataProcessors; std::vector<DataProcessorInfo>& metadata; + CommandInfo& command; std::vector<ConfigParamSpec> inputOptions; std::string binding; header::DataOrigin origin; @@ -551,13 +663,16 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, VariantType optionType; std::string optionDefault; std::string optionHelp; + ConfigParamKind optionKind; bool outputHasSubSpec; bool inputHasSubSpec; + bool inputHasDescription; }; -void WorkflowSerializationHelpers::import(std::istream& s, +bool WorkflowSerializationHelpers::import(std::istream& s, std::vector<DataProcessorSpec>& workflow, - std::vector<DataProcessorInfo>& metadata) + std::vector<DataProcessorInfo>& metadata, + CommandInfo& command) { // Skip any line which does not start with '{' // If we do not find a starting {, we simply assume that no workflow @@ -565,27 +680,46 @@ void WorkflowSerializationHelpers::import(std::istream& s, // FIXME: not particularly resilient, but works for now. // FIXME: this will fail if { is found at char 1024. char buf[1024]; + bool hasFatalImportError = false; while (s.peek() != '{') { if (s.eof()) { - return; + return !hasFatalImportError; } if (s.fail() || s.bad()) { throw std::runtime_error("Malformatted input workflow"); } s.getline(buf, 1024, '\n'); + // FairLogger messages (starting with [) simply get forwarded. + // Other messages we consider them as ERRORs since they + // were printed out without FairLogger. + if (buf[0] == '[') { + if (strncmp(buf, "[ERROR] invalid workflow in", strlen("[ERROR] invalid workflow in")) == 0 || + strncmp(buf, "[ERROR] error while setting up workflow", strlen("[ERROR] error while setting up workflow")) == 0 || + strncmp(buf, "[ERROR] error parsing options of", strlen("[ERROR] error parsing options of")) == 0) { + hasFatalImportError = true; + } + std::cout << buf << std::endl; + } else { + LOG(ERROR) << buf; + } + } + if (hasFatalImportError) { + return false; } rapidjson::Reader reader; rapidjson::IStreamWrapper isw(s); - WorkflowImporter importer{workflow, metadata}; + WorkflowImporter importer{workflow, metadata, command}; bool ok = reader.Parse(isw, importer); if (ok == false) { throw std::runtime_error("Error while parsing serialised workflow"); } + return true; } void WorkflowSerializationHelpers::dump(std::ostream& out, std::vector<DataProcessorSpec> const& workflow, - std::vector<DataProcessorInfo> const& metadata) + std::vector<DataProcessorInfo> const& metadata, + CommandInfo const& commandInfo) { rapidjson::OStreamWrapper osw(out); rapidjson::PrettyWriter<rapidjson::OStreamWrapper> w(osw); @@ -608,17 +742,19 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, /// FIXME: this only works for a selected set of InputSpecs... /// a proper way to fully serialize an InputSpec with /// a DataDescriptorMatcher is needed. - auto dataType = DataSpecUtils::asConcreteDataTypeMatcher(input); - if (dataType.origin == header::DataOrigin("DPL")) { - continue; - } w.StartObject(); w.Key("binding"); w.String(input.binding.c_str()); - w.Key("origin"); - w.String(dataType.origin.str, strnlen(dataType.origin.str, 4)); - w.Key("description"); - w.String(dataType.description.str, strnlen(dataType.description.str, 16)); + auto origin = DataSpecUtils::getOptionalOrigin(input); + if (origin.has_value()) { + w.Key("origin"); + w.String(origin->str, strnlen(origin->str, 4)); + } + auto description = DataSpecUtils::getOptionalDescription(input); + if (description.has_value()) { + w.Key("description"); + w.String(description->str, strnlen(description->str, 16)); + } auto subSpec = DataSpecUtils::getOptionalSubSpec(input); if (subSpec.has_value()) { w.Key("subspec"); @@ -682,7 +818,7 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, w.Key("options"); w.StartArray(); for (auto& option : processor.options) { - if (option.name == "start-value-enumeration" || option.name == "end-value-enumeration" || option.name == "step-value-enumeration") { + if (option.name == "start-value-enumeration" || option.name == "end-value-enumeration" || option.name == "step-value-enumeration" || option.name == "orbit-offset-enumeration" || option.name == "orbit-multiplier-enumeration") { continue; } w.StartObject(); @@ -692,14 +828,39 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, w.Key("type"); w.String(s.c_str()); std::ostringstream oss; - oss << option.defaultValue; + switch (option.type) { + case VariantType::ArrayInt: + case VariantType::ArrayFloat: + case VariantType::ArrayDouble: + case VariantType::ArrayBool: + case VariantType::ArrayString: + case VariantType::Array2DInt: + case VariantType::Array2DFloat: + case VariantType::Array2DDouble: + case VariantType::LabeledArrayInt: + case VariantType::LabeledArrayFloat: + case VariantType::LabeledArrayDouble: + VariantJSONHelpers::write(oss, option.defaultValue); + break; + default: + oss << option.defaultValue; + break; + } w.Key("defaultValue"); w.String(oss.str().c_str()); w.Key("help"); w.String(option.help.c_str()); + w.Key("kind"); + w.String(std::to_string((int)option.kind).c_str()); w.EndObject(); } w.EndArray(); + w.Key("labels"); + w.StartArray(); + for (auto& label : processor.labels) { + w.String(label.value.c_str()); + } + w.EndArray(); w.Key("rank"); w.Int(processor.rank); w.Key("nSlots"); @@ -754,8 +915,11 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, w.EndObject(); } w.EndArray(); + + w.Key("command"); + w.String(commandInfo.command.c_str()); + w.EndObject(); } -} // namespace framework -} // namespace o2 +} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowSerializationHelpers.h b/Framework/Core/src/WorkflowSerializationHelpers.h index 671c14ef60dd7..9b306d9d15aee 100644 --- a/Framework/Core/src/WorkflowSerializationHelpers.h +++ b/Framework/Core/src/WorkflowSerializationHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,26 +12,27 @@ #define O2_FRAMEWORK_CORE_WORKFLOWSERIALIZATIONHELPERS_H_ #include "Framework/DataProcessorSpec.h" -#include "DataProcessorInfo.h" +#include "Framework/DataProcessorInfo.h" +#include "Framework/CommandInfo.h" #include <iosfwd> #include <vector> -namespace o2 -{ -namespace framework +namespace o2::framework { struct WorkflowSerializationHelpers { - static void import(std::istream& s, + ///@return false if the previous workflow failed to generate a valid config, true otherwise + static bool import(std::istream& s, std::vector<DataProcessorSpec>& workflow, - std::vector<DataProcessorInfo>& metadata); + std::vector<DataProcessorInfo>& metadata, + CommandInfo& command); static void dump(std::ostream& o, std::vector<DataProcessorSpec> const& workflow, - std::vector<DataProcessorInfo> const& metadata); + std::vector<DataProcessorInfo> const& metadata, + CommandInfo const& commandInfo); }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework #endif // O2_FRAMEWORK_CORE_WORKFLOWSERIALIZATIONHELPERS_H_ diff --git a/Framework/Core/src/WorkflowSpec.cxx b/Framework/Core/src/WorkflowSpec.cxx index cda674725d947..55ccd2e1e441b 100644 --- a/Framework/Core/src/WorkflowSpec.cxx +++ b/Framework/Core/src/WorkflowSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/dplRun.cxx b/Framework/Core/src/dplRun.cxx index da986e7211a73..608ee05d7f35c 100644 --- a/Framework/Core/src/dplRun.cxx +++ b/Framework/Core/src/dplRun.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/o2NullSink.cxx b/Framework/Core/src/o2NullSink.cxx index 79c18a9f6ba11..4d8e9d83f753c 100644 --- a/Framework/Core/src/o2NullSink.cxx +++ b/Framework/Core/src/o2NullSink.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index bdeed2f1a5e43..29798a2e1bf21 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1,36 +1,35 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include <stdexcept> #include "Framework/BoostOptionsRetriever.h" #include "Framework/ChannelConfigurationPolicy.h" #include "Framework/ChannelMatching.h" #include "Framework/ConfigParamsHelper.h" #include "Framework/ConfigParamSpec.h" #include "Framework/ConfigContext.h" +#include "Framework/ComputingQuotaEvaluator.h" +#include "CommonDriverServices.h" #include "Framework/DataProcessingDevice.h" #include "Framework/DataProcessorSpec.h" -#if __has_include(<DebugGUI/DebugGUI.h>) -#include <DebugGUI/DebugGUI.h> -#else -// the DebugGUI is in a separate package and is optional for O2, -// we include a header implementing GUI interface dummy methods -#pragma message "Building DPL without Debug GUI" -#include "Framework/NoDebugGUI.h" -#endif +#include "Framework/Plugins.h" #include "Framework/DeviceControl.h" #include "Framework/DeviceExecution.h" #include "Framework/DeviceInfo.h" #include "Framework/DeviceMetricsInfo.h" +#include "Framework/DeviceMetricsHelper.h" #include "Framework/DeviceConfigInfo.h" #include "Framework/DeviceSpec.h" #include "Framework/DeviceState.h" -#include "Framework/FrameworkGUIDebugger.h" +#include "Framework/DevicesManager.h" +#include "Framework/DebugGUI.h" #include "Framework/LocalRootFileService.h" #include "Framework/LogParsingHelpers.h" #include "Framework/Logger.h" @@ -39,19 +38,26 @@ #include "Framework/SimpleRawDeviceService.h" #define O2_SIGNPOST_DEFINE_CONTEXT #include "Framework/Signpost.h" -#include "Framework/TextControlService.h" +#include "Framework/ControlService.h" #include "Framework/CallbackService.h" #include "Framework/WorkflowSpec.h" #include "Framework/Monitoring.h" +#include "Framework/DataProcessorInfo.h" +#include "Framework/DriverInfo.h" +#include "Framework/DriverControl.h" +#include "Framework/CommandInfo.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/TopologyPolicy.h" +#include "DriverServerContext.h" +#include "ControlServiceHelpers.h" +#include "HTTPParser.h" +#include "DPLWebSocket.h" #include "ComputingResourceHelpers.h" #include "DataProcessingStatus.h" #include "DDSConfigHelpers.h" #include "O2ControlHelpers.h" #include "DeviceSpecHelpers.h" -#include "DriverControl.h" -#include "DriverInfo.h" -#include "DataProcessorInfo.h" #include "GraphvizHelpers.h" #include "PropertyTreeHelpers.h" #include "SimpleResourceManager.h" @@ -112,7 +118,7 @@ #include <sched.h> #elif __has_include(<linux/getcpu.h>) #include <linux/getcpu.h> -#elif __has_include(<cpuid.h>) +#elif __has_include(<cpuid.h>) && (__x86_64__ || __i386__) #include <cpuid.h> #define CPUID(INFO, LEAF, SUBLEAF) __cpuid_count(LEAF, SUBLEAF, INFO[0], INFO[1], INFO[2], INFO[3]) #define GETCPU(CPU) \ @@ -153,9 +159,7 @@ std::vector<DeviceMetricsInfo> gDeviceMetricsInfos; bpo::options_description gHiddenDeviceOptions("Hidden child options"); // To be used to allow specifying the TerminationPolicy on the command line. -namespace o2 -{ -namespace framework +namespace o2::framework { std::istream& operator>>(std::istream& in, enum TerminationPolicy& policy) { @@ -182,8 +186,45 @@ std::ostream& operator<<(std::ostream& out, const enum TerminationPolicy& policy } return out; } -} // namespace framework -} // namespace o2 + +std::istream& operator>>(std::istream& in, enum LogParsingHelpers::LogLevel& level) +{ + std::string token; + in >> token; + if (token == "debug") { + level = LogParsingHelpers::LogLevel::Debug; + } else if (token == "info") { + level = LogParsingHelpers::LogLevel::Info; + } else if (token == "warning") { + level = LogParsingHelpers::LogLevel::Warning; + } else if (token == "error") { + level = LogParsingHelpers::LogLevel::Error; + } else if (token == "fatal") { + level = LogParsingHelpers::LogLevel::Fatal; + } else { + in.setstate(std::ios_base::failbit); + } + return in; +} + +std::ostream& operator<<(std::ostream& out, const enum LogParsingHelpers::LogLevel& level) +{ + if (level == LogParsingHelpers::LogLevel::Debug) { + out << "debug"; + } else if (level == LogParsingHelpers::LogLevel::Info) { + out << "info"; + } else if (level == LogParsingHelpers::LogLevel::Warning) { + out << "warning"; + } else if (level == LogParsingHelpers::LogLevel::Error) { + out << "error"; + } else if (level == LogParsingHelpers::LogLevel::Fatal) { + out << "fatal"; + } else { + out.setstate(std::ios_base::failbit); + } + return out; +} +} // namespace o2::framework size_t current_time_with_ms() { @@ -274,21 +315,27 @@ bool areAllChildrenGone(std::vector<DeviceInfo>& infos) } /// Calculate exit code -int calculateExitCode(DeviceSpecs& deviceSpecs, DeviceInfos& infos) +namespace +{ +int calculateExitCode(DriverInfo& driverInfo, DeviceSpecs& deviceSpecs, DeviceInfos& infos) { std::regex regexp(R"(^\[([\d+:]*)\]\[\w+\] )"); int exitCode = 0; for (size_t di = 0; di < deviceSpecs.size(); ++di) { auto& info = infos[di]; auto& spec = deviceSpecs[di]; - if (exitCode == 0 && info.maxLogLevel >= LogParsingHelpers::LogLevel::Error) { - LOG(ERROR) << "SEVERE: Device " << spec.name << " (" << info.pid << ") had at least one " - << "message above severity ERROR: " << std::regex_replace(info.lastError, regexp, ""); + if (info.maxLogLevel >= driverInfo.minFailureLevel) { + LOGP(ERROR, "SEVERE: Device {} ({}) had at least one message above severity {}: {}", + spec.name, + info.pid, + info.minFailureLevel, + std::regex_replace(info.firstSevereError, regexp, "")); exitCode = 1; } } return exitCode; } +} // namespace void createPipes(int* pipes) { @@ -368,6 +415,8 @@ void spawnRemoteDevice(std::string const& forwardedStdin, info.dataRelayerViewIndex = Metric2DViewIndex{"data_relayer", 0, 0, {}}; info.variablesViewIndex = Metric2DViewIndex{"matcher_variables", 0, 0, {}}; info.queriesViewIndex = Metric2DViewIndex{"data_queries", 0, 0, {}}; + // FIXME: use uv_now. + info.lastSignal = uv_hrtime() - 10000000; deviceInfos.emplace_back(info); // Let's add also metrics information for the given device @@ -377,6 +426,7 @@ void spawnRemoteDevice(std::string const& forwardedStdin, struct DeviceLogContext { int fd; int index; + uv_loop_t* loop; std::vector<DeviceInfo>* infos; }; @@ -397,32 +447,358 @@ void log_callback(uv_poll_t* handle, int status, int events) } } +void close_websocket(uv_handle_t* handle) +{ + LOG(debug) << "Handle is being closed"; + delete (WSDPLHandler*)handle->data; +} + +void websocket_callback(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) +{ + WSDPLHandler* handler = (WSDPLHandler*)stream->data; + if (nread == 0) { + return; + } + if (nread == UV_EOF) { + uv_read_stop(stream); + uv_close((uv_handle_t*)stream, close_websocket); + return; + } + if (nread < 0) { + // FIXME: should I close? + LOG(ERROR) << "websocket_callback: Error while reading from websocket"; + uv_read_stop(stream); + uv_close((uv_handle_t*)stream, close_websocket); + return; + } + try { + LOG(debug3) << "Parsing request with " << handler << " with " << nread << " bytes"; + parse_http_request(buf->base, nread, handler); + } catch (WSError& e) { + LOG(ERROR) << "Error while parsing request: " << e.message; + handler->error(e.code, e.message.c_str()); + } +} + +static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) +{ + buf->base = (char*)malloc(suggested_size); + buf->len = suggested_size; +} + +void updateMetricsNames(DriverInfo& driverInfo, std::vector<DeviceMetricsInfo> const& metricsInfos) +{ + // Calculate the unique set of metrics, as available in the metrics service + static std::unordered_set<std::string> allMetricsNames; + for (const auto& metricsInfo : metricsInfos) { + for (const auto& labelsPairs : metricsInfo.metricLabels) { + allMetricsNames.insert(std::string(labelsPairs.label)); + } + } + for (const auto& labelsPairs : driverInfo.metrics.metricLabels) { + allMetricsNames.insert(std::string(labelsPairs.label)); + } + std::vector<std::string> result(allMetricsNames.begin(), allMetricsNames.end()); + std::sort(result.begin(), result.end()); + driverInfo.availableMetrics.swap(result); +} + +/// An handler for a websocket message stream. +struct ControlWebSocketHandler : public WebSocketHandler { + ControlWebSocketHandler(DriverServerContext& context) + : mContext{context} + { + } + ~ControlWebSocketHandler() override = default; + + /// Invoked at the end of the headers. + /// as a special header we have "x-dpl-pid" which devices can use + /// to identify themselves. + /// FIXME: No effort is done to guarantee their identity. Maybe each device + /// should be started with a unique secret if we wanted to provide + /// some secutity. + void headers(std::map<std::string, std::string> const& headers) override + { + if (headers.count("x-dpl-pid")) { + auto s = headers.find("x-dpl-pid"); + this->mPid = std::stoi(s->second); + for (size_t di = 0; di < mContext.infos->size(); ++di) { + if ((*mContext.infos)[di].pid == mPid) { + mIndex = di; + return; + } + } + } + } + /// FIXME: not implemented by the backend. + void beginFragmentation() override {} + + /// Invoked when a frame it's parsed. Notice you do not own the data and you must + /// not free the memory. + void frame(char const* frame, size_t s) override + { + bool hasNewMetric = false; + auto updateMetricsViews = Metric2DViewIndex::getUpdater({&(*mContext.infos)[mIndex].dataRelayerViewIndex, + &(*mContext.infos)[mIndex].variablesViewIndex, + &(*mContext.infos)[mIndex].queriesViewIndex}); + + auto newMetricCallback = [&updateMetricsViews, &metrics = mContext.metrics, &hasNewMetric](std::string const& name, MetricInfo const& metric, int value, size_t metricIndex) { + updateMetricsViews(name, metric, value, metricIndex); + hasNewMetric = true; + }; + std::string token(frame, s); + std::smatch match; + ParsedConfigMatch configMatch; + ParsedMetricMatch metricMatch; + + auto doParseConfig = [](std::string const& token, ParsedConfigMatch& configMatch, DeviceInfo& info) -> bool { + auto ts = " " + token; + if (DeviceConfigHelper::parseConfig(ts, configMatch)) { + DeviceConfigHelper::processConfig(configMatch, info); + return true; + } + return false; + }; + LOG(debug3) << "Data received: " << std::string_view(frame, s); + if (DeviceMetricsHelper::parseMetric(token, metricMatch)) { + // We use this callback to cache which metrics are needed to provide a + // the DataRelayer view. + assert(mContext.metrics); + DeviceMetricsHelper::processMetric(metricMatch, (*mContext.metrics)[mIndex], newMetricCallback); + didProcessMetric = true; + didHaveNewMetric |= hasNewMetric; + } else if (ControlServiceHelpers::parseControl(token, match) && mContext.infos) { + ControlServiceHelpers::processCommand(*mContext.infos, mPid, match[1].str(), match[2].str()); + } else if (doParseConfig(token, configMatch, (*mContext.infos)[mIndex]) && mContext.infos) { + LOG(debug2) << "Found configuration information for pid " << mPid; + } else { + LOG(error) << "Unexpected control data: " << std::string_view(frame, s); + } + } + + /// FIXME: not implemented + void endFragmentation() override{}; + /// FIXME: not implemented + void control(char const* frame, size_t s) override{}; + + /// Invoked at the beginning of some incoming data. We simply + /// reset actions which need to happen on a per chunk basis. + void beginChunk() override + { + didProcessMetric = false; + didHaveNewMetric = false; + } + + /// Invoked after we have processed all the available incoming data. + /// In this particular case we must handle the metric callbacks, if + /// needed. + void endChunk() override + { + if (!didProcessMetric) { + return; + } + size_t timestamp = current_time_with_ms(); + for (auto& callback : *mContext.metricProcessingCallbacks) { + callback(*mContext.registry, *mContext.metrics, *mContext.specs, *mContext.infos, mContext.driver->metrics, timestamp); + } + for (auto& metricsInfo : *mContext.metrics) { + std::fill(metricsInfo.changed.begin(), metricsInfo.changed.end(), false); + } + if (didHaveNewMetric) { + updateMetricsNames(*mContext.driver, *mContext.metrics); + } + } + + /// The driver context were we want to accumulate changes + /// which we got from the websocket. + DriverServerContext& mContext; + /// The pid of the remote process actually associated to this + /// handler. Notice that this information comes as part of + /// the HTTP headers via x-dpl-pid. + pid_t mPid = 0; + /// The index of the remote process associated to this handler. + size_t mIndex = (size_t)-1; + /// Wether any frame operation between beginChunk and endChunk + /// actually processed some metric. + bool didProcessMetric = false; + bool didHaveNewMetric = false; +}; + +/// A callback for the rest engine +void ws_connect_callback(uv_stream_t* server, int status) +{ + DriverServerContext* serverContext = reinterpret_cast<DriverServerContext*>(server->data); + if (status < 0) { + LOGF(error, "New connection error %s\n", uv_strerror(status)); + // error! + return; + } + + uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); + uv_tcp_init(serverContext->loop, client); + if (uv_accept(server, (uv_stream_t*)client) == 0) { + auto handler = std::make_unique<ControlWebSocketHandler>(*serverContext); + client->data = new WSDPLHandler((uv_stream_t*)client, serverContext, std::move(handler)); + uv_read_start((uv_stream_t*)client, (uv_alloc_cb)my_alloc_cb, websocket_callback); + } else { + uv_close((uv_handle_t*)client, nullptr); + } +} + +struct StreamConfigContext { + std::string configuration; + int fd; +}; + +void stream_config(uv_work_t* req) +{ + StreamConfigContext* context = (StreamConfigContext*)req->data; + size_t result = write(context->fd, context->configuration.data(), context->configuration.size()); + if (result != context->configuration.size()) { + LOG(ERROR) << "Unable to pass configuration to children"; + } + { + auto error = fsync(context->fd); + switch (error) { + case EBADF: + LOGP(ERROR, "EBADF while flushing child stdin"); + break; + case EINVAL: + LOGP(ERROR, "EINVAL while flushing child stdin"); + break; + case EINTR: + LOGP(ERROR, "EINTR while flushing child stdin"); + break; + case EIO: + LOGP(ERROR, "EIO while flushing child stdin"); + break; + default:; + } + } + { + auto error = close(context->fd); // Not allowing further communication... + switch (error) { + case EBADF: + LOGP(ERROR, "EBADF while closing child stdin"); + break; + case EINTR: + LOGP(ERROR, "EINTR while closing child stdin"); + break; + case EIO: + LOGP(ERROR, "EIO while closing child stdin"); + break; + default:; + } + } +} + +struct DeviceRef { + int index; +}; + +struct DeviceStdioContext { + int childstdin[2]; + int childstdout[2]; + int childstderr[2]; +}; + +void prepareStdio(std::vector<DeviceStdioContext>& deviceStdio) +{ + for (auto& context : deviceStdio) { + createPipes(context.childstdin); + createPipes(context.childstdout); + createPipes(context.childstderr); + } +} +void handleSignals() +{ + struct sigaction sa_handle_int; + sa_handle_int.sa_handler = handle_sigint; + sigemptyset(&sa_handle_int.sa_mask); + sa_handle_int.sa_flags = SA_RESTART; + if (sigaction(SIGINT, &sa_handle_int, nullptr) == -1) { + perror("Unable to install signal handler"); + exit(1); + } + struct sigaction sa_handle_term; + sa_handle_term.sa_handler = handle_sigint; + sigemptyset(&sa_handle_term.sa_mask); + sa_handle_term.sa_flags = SA_RESTART; + if (sigaction(SIGTERM, &sa_handle_int, nullptr) == -1) { + perror("Unable to install signal handler"); + exit(1); + } +} + +void handleChildrenStdio(uv_loop_t* loop, + std::string const& forwardedStdin, + std::vector<DeviceInfo>& deviceInfos, + std::vector<DeviceStdioContext>& childFds, + std::vector<uv_poll_t*>& handles) +{ + for (size_t i = 0; i < childFds.size(); ++i) { + auto& childstdin = childFds[i].childstdin; + auto& childstdout = childFds[i].childstdout; + auto& childstderr = childFds[i].childstderr; + close(childstdin[0]); + close(childstdout[1]); + close(childstderr[1]); + + uv_work_t* req = (uv_work_t*)malloc(sizeof(uv_work_t)); + req->data = new StreamConfigContext{forwardedStdin, childstdin[1]}; + uv_queue_work(loop, req, stream_config, nullptr); + + // Setting them to non-blocking to avoid haing the driver hang when + // reading from child. + int resultCode = fcntl(childstdout[0], F_SETFL, O_NONBLOCK); + if (resultCode == -1) { + LOGP(ERROR, "Error while setting the socket to non-blocking: {}", strerror(errno)); + } + resultCode = fcntl(childstderr[0], F_SETFL, O_NONBLOCK); + if (resultCode == -1) { + LOGP(ERROR, "Error while setting the socket to non-blocking: {}", strerror(errno)); + } + + /// Add pollers for stdout and stderr + auto addPoller = [&handles, &deviceInfos, &loop](int index, int fd) { + DeviceLogContext* context = new DeviceLogContext{}; + context->index = index; + context->fd = fd; + context->loop = loop; + context->infos = &deviceInfos; + handles.push_back((uv_poll_t*)malloc(sizeof(uv_poll_t))); + auto handle = handles.back(); + handle->data = context; + uv_poll_init(loop, handle, fd); + uv_poll_start(handle, UV_READABLE, log_callback); + }; + + addPoller(i, childstdout[0]); + addPoller(i, childstderr[0]); + } +} + /// This will start a new device by forking and executing a /// new child -void spawnDevice(std::string const& forwardedStdin, - DeviceSpec const& spec, +void spawnDevice(DeviceRef ref, + std::vector<DeviceSpec> const& specs, DriverInfo& driverInfo, - DeviceControl& control, - DeviceExecution& execution, + std::vector<DeviceControl>& controls, + std::vector<DeviceExecution>& executions, std::vector<DeviceInfo>& deviceInfos, ServiceRegistry& serviceRegistry, boost::program_options::variables_map& varmap, - uv_loop_t* loop, - std::vector<uv_poll_t*> handles, + std::vector<DeviceStdioContext>& childFds, unsigned parentCPU, unsigned parentNode) { - int childstdin[2]; - int childstdout[2]; - int childstderr[2]; - - createPipes(childstdin); - createPipes(childstdout); - createPipes(childstderr); - // FIXME: this might not work when more than one DPL driver on the same // machine. Hopefully we do not care. // Not how the first port is actually used to broadcast clients. + auto& spec = specs[ref.index]; + auto& control = controls[ref.index]; + auto& execution = executions[ref.index]; + driverInfo.tracyPort++; for (auto& service : spec.services) { @@ -445,15 +821,25 @@ void spawnDevice(std::string const& forwardedStdin, // old descriptor, and then replace it with the write part of the pipe. // For stdin, we close the write part of the pipe, the old descriptor, // and then we replace it with the read part of the pipe. - close(childstdin[1]); - close(childstdout[0]); - close(childstderr[0]); + // We also close all the filedescriptors for our sibilings. + for (size_t i = 0; i < childFds.size(); ++i) { + close(childFds[i].childstdin[1]); + close(childFds[i].childstdout[0]); + close(childFds[i].childstderr[0]); + if (i == ref.index) { + continue; + } + close(childFds[i].childstdin[0]); + close(childFds[i].childstdout[1]); + close(childFds[i].childstderr[1]); + } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); - dup2(childstdin[0], STDIN_FILENO); - dup2(childstdout[1], STDOUT_FILENO); - dup2(childstderr[1], STDERR_FILENO); + dup2(childFds[ref.index].childstdin[0], STDIN_FILENO); + dup2(childFds[ref.index].childstdout[1], STDOUT_FILENO); + dup2(childFds[ref.index].childstderr[1], STDERR_FILENO); + auto portS = std::to_string(driverInfo.tracyPort); setenv("TRACY_PORT", portS.c_str(), 1); for (auto& service : spec.services) { @@ -498,15 +884,6 @@ void spawnDevice(std::string const& forwardedStdin, } } - struct sigaction sa_handle_int; - sa_handle_int.sa_handler = handle_sigint; - sigemptyset(&sa_handle_int.sa_mask); - sa_handle_int.sa_flags = SA_RESTART; - if (sigaction(SIGINT, &sa_handle_int, nullptr) == -1) { - perror("Unable to install signal handler"); - exit(1); - } - LOG(INFO) << "Starting " << spec.id << " on pid " << id; DeviceInfo info; info.pid = id; @@ -515,66 +892,16 @@ void spawnDevice(std::string const& forwardedStdin, info.historySize = 1000; info.historyPos = 0; info.maxLogLevel = LogParsingHelpers::LogLevel::Debug; + info.minFailureLevel = driverInfo.minFailureLevel; info.dataRelayerViewIndex = Metric2DViewIndex{"data_relayer", 0, 0, {}}; info.variablesViewIndex = Metric2DViewIndex{"matcher_variables", 0, 0, {}}; info.queriesViewIndex = Metric2DViewIndex{"data_queries", 0, 0, {}}; info.tracyPort = driverInfo.tracyPort; + info.lastSignal = uv_hrtime() - 10000000; deviceInfos.emplace_back(info); // Let's add also metrics information for the given device gDeviceMetricsInfos.emplace_back(DeviceMetricsInfo{}); - - close(childstdin[0]); - close(childstdout[1]); - close(childstderr[1]); - size_t result = write(childstdin[1], forwardedStdin.data(), forwardedStdin.size()); - if (result != forwardedStdin.size()) { - LOG(ERROR) << "Unable to pass configuration to children"; - } - close(childstdin[1]); // Not allowing further communication... - - // Setting them to non-blocking to avoid haing the driver hang when - // reading from child. - int resultCode = fcntl(childstdout[0], F_SETFL, O_NONBLOCK); - if (resultCode == -1) { - LOGP(ERROR, "Error while setting the socket to non-blocking: {}", strerror(errno)); - } - resultCode = fcntl(childstderr[0], F_SETFL, O_NONBLOCK); - if (resultCode == -1) { - LOGP(ERROR, "Error while setting the socket to non-blocking: {}", strerror(errno)); - } - /// Add pollers for stdout and stderr - auto addPoller = [&handles, &deviceInfos, &loop](int index, int fd) { - DeviceLogContext* context = new DeviceLogContext{}; - context->index = index; - context->fd = fd; - context->infos = &deviceInfos; - handles.push_back((uv_poll_t*)malloc(sizeof(uv_poll_t))); - auto handle = handles.back(); - handle->data = context; - uv_poll_init(loop, handle, fd); - uv_poll_start(handle, UV_READABLE, log_callback); - }; - - addPoller(deviceInfos.size() - 1, childstdout[0]); - addPoller(deviceInfos.size() - 1, childstderr[0]); -} - -void updateMetricsNames(DriverInfo& driverInfo, std::vector<DeviceMetricsInfo> const& metricsInfos) -{ - // Calculate the unique set of metrics, as available in the metrics service - static std::unordered_set<std::string> allMetricsNames; - for (const auto& metricsInfo : metricsInfos) { - for (const auto& labelsPairs : metricsInfo.metricLabelsIdx) { - allMetricsNames.insert(std::string(labelsPairs.label)); - } - } - for (const auto& labelsPairs : driverInfo.metrics.metricLabelsIdx) { - allMetricsNames.insert(std::string(labelsPairs.label)); - } - std::vector<std::string> result(allMetricsNames.begin(), allMetricsNames.end()); - std::sort(result.begin(), result.end()); - driverInfo.availableMetrics.swap(result); } struct LogProcessingState { @@ -634,15 +961,6 @@ LogProcessingState processChildrenOutput(DriverInfo& driverInfo, hasNewMetric = true; }; - auto doToMatchingPid = [&infos](int pid, auto lambda) { - for (auto& deviceInfo : infos) { - if (deviceInfo.pid == pid) { - lambda(deviceInfo); - break; - } - } - }; - while ((pos = s.find(delimiter)) != std::string::npos) { std::string token{s.substr(0, pos)}; auto logLevel = LogParsingHelpers::parseTokenLevel(token); @@ -657,26 +975,8 @@ LogProcessingState processChildrenOutput(DriverInfo& driverInfo, // the DataRelayer view. DeviceMetricsHelper::processMetric(metricMatch, metrics, newMetricCallback); result.didProcessMetric = true; - } else if (logLevel == LogParsingHelpers::LogLevel::Info && parseControl(token, match)) { - auto command = match[1]; - auto arg = match[2]; - LOGP(debug, "Found control command {} from pid {} with argument {}.", command, info.pid, arg); - if (command == "QUIT" && arg == "ALL") { - for (auto& deviceInfo : infos) { - deviceInfo.readyToQuit = true; - } - } else if (command == "QUIT" && arg == "ME") { - doToMatchingPid(info.pid, [](DeviceInfo& info) { info.readyToQuit = true; }); - } else if (command == "NOTIFY_STREAMING_STATE" && arg == "IDLE") { - // FIXME: this should really be a policy... - doToMatchingPid(info.pid, [](DeviceInfo& info) { info.readyToQuit = true; info.streamingState = StreamingState::Idle; }); - } else if (command == "NOTIFY_STREAMING_STATE" && arg == "STREAMING") { - // FIXME: this should really be a policy... - doToMatchingPid(info.pid, [](DeviceInfo& info) { info.streamingState = StreamingState::Streaming; }); - } else if (command == "NOTIFY_STREAMING_STATE" && arg == "EOS") { - // FIXME: this should really be a policy... - doToMatchingPid(info.pid, [](DeviceInfo& info) { info.streamingState = StreamingState::EndOfStreaming; }); - } + } else if (logLevel == LogParsingHelpers::LogLevel::Info && ControlServiceHelpers::parseControl(token, match)) { + ControlServiceHelpers::processCommand(infos, info.pid, match[1].str(), match[2].str()); result.didProcessControl = true; } else if (logLevel == LogParsingHelpers::LogLevel::Info && DeviceConfigHelper::parseConfig(token, configMatch)) { DeviceConfigHelper::processConfig(configMatch, info); @@ -688,17 +988,22 @@ LogProcessingState processChildrenOutput(DriverInfo& driverInfo, info.history[info.historyPos] = token; info.historyLevel[info.historyPos] = logLevel; info.historyPos = (info.historyPos + 1) % info.history.size(); - std::cout << "[" << info.pid << ":" << spec.name << "]: " << token << std::endl; + fmt::print("[{}:{}]: {}\n", info.pid, spec.id, token); result.didProcessLog = true; } // We keep track of the maximum log error a // device has seen. + bool maxLogLevelIncreased = false; if (logLevel > info.maxLogLevel && logLevel > LogParsingHelpers::LogLevel::Info && logLevel != LogParsingHelpers::LogLevel::Unknown) { info.maxLogLevel = logLevel; + maxLogLevelIncreased = true; } - if (logLevel == LogParsingHelpers::LogLevel::Error) { + if (logLevel >= driverInfo.minFailureLevel) { info.lastError = token; + if (info.firstSevereError.empty() || maxLogLevelIncreased) { + info.firstSevereError = token; + } } s.remove_prefix(pos + delimiter.length()); } @@ -742,85 +1047,116 @@ bool processSigChild(DeviceInfos& infos) return hasError; } -int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry, const o2::framework::DeviceSpec& spec, TerminationPolicy errorPolicy, +void doDPLException(RuntimeErrorRef& e, char const* processName) +{ + auto& err = o2::framework::error_from_ref(e); + if (err.maxBacktrace != 0) { + LOGP(ERROR, + "Unhandled o2::framework::runtime_error reached the top of main of {}, device shutting down." + "\n Reason: " + "\n Backtrace follow: \n", + processName, err.what); + backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); + } else { + LOGP(ERROR, + "Unhandled o2::framework::runtime_error reached the top of main of {}, device shutting down." + "\n Reason: " + "\n Recompile with DPL_ENABLE_BACKTRACE=1 to get more information.", + processName, err.what); + } +} + +void doUnknownException(std::string const& s, char const* processName) +{ + if (s.empty()) { + LOGP(ERROR, "unknown error while setting up workflow in {}.", processName); + } else { + LOGP(ERROR, "error while setting up workflow in {}: {}", processName, s); + } +} + +void doDefaultWorkflowTerminationHook() +{ + //LOG(INFO) << "Process " << getpid() << " is exiting."; +} + +int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry, + RunningWorkflowInfo const& runningWorkflow, + RunningDeviceRef ref, + TerminationPolicy errorPolicy, + std::string const& defaultDriverClient, uv_loop_t* loop) { fair::Logger::SetConsoleColor(false); + DeviceSpec const& spec = runningWorkflow.devices[ref.index]; LOG(INFO) << "Spawing new device " << spec.id << " in process with pid " << getpid(); - try { - fair::mq::DeviceRunner runner{argc, argv}; - - // Populate options from the command line. Notice that only the options - // declared in the workflow definition are allowed. - runner.AddHook<fair::mq::hooks::SetCustomCmdLineOptions>([&spec](fair::mq::DeviceRunner& r) { - boost::program_options::options_description optsDesc; - ConfigParamsHelper::populateBoostProgramOptions(optsDesc, spec.options, gHiddenDeviceOptions); - optsDesc.add_options()("monitoring-backend", bpo::value<std::string>()->default_value("infologger://"), "monitoring backend info") // - ("infologger-severity", bpo::value<std::string>()->default_value(""), "minimum FairLogger severity to send to InfoLogger") // - ("configuration,cfg", bpo::value<std::string>()->default_value("command-line"), "configuration backend") // - ("infologger-mode", bpo::value<std::string>()->default_value(""), "INFOLOGGER_MODE override"); - r.fConfig.AddToCmdLineOptions(optsDesc, true); - }); + fair::mq::DeviceRunner runner{argc, argv}; + + // Populate options from the command line. Notice that only the options + // declared in the workflow definition are allowed. + runner.AddHook<fair::mq::hooks::SetCustomCmdLineOptions>([&spec, defaultDriverClient](fair::mq::DeviceRunner& r) { + boost::program_options::options_description optsDesc; + ConfigParamsHelper::populateBoostProgramOptions(optsDesc, spec.options, gHiddenDeviceOptions); + optsDesc.add_options()("monitoring-backend", bpo::value<std::string>()->default_value("default"), "monitoring backend info") // + ("driver-client-backend", bpo::value<std::string>()->default_value(defaultDriverClient), "backend for device -> driver communicataon: stdout://: use stdout, ws://: use websockets") // + ("infologger-severity", bpo::value<std::string>()->default_value(""), "minimum FairLogger severity to send to InfoLogger") // + ("expected-region-callbacks", bpo::value<std::string>()->default_value("0"), "how many region callbacks we are expecting") // + ("configuration,cfg", bpo::value<std::string>()->default_value("command-line"), "configuration backend") // + ("infologger-mode", bpo::value<std::string>()->default_value(""), "O2_INFOLOGGER_MODE override"); + r.fConfig.AddToCmdLineOptions(optsDesc, true); + }); - // This is to control lifetime. All these services get destroyed - // when the runner is done. - std::unique_ptr<SimpleRawDeviceService> simpleRawDeviceService; - std::unique_ptr<DeviceState> deviceState; - - auto afterConfigParsingCallback = [&simpleRawDeviceService, - &spec, - &serviceRegistry, - &deviceState, - &errorPolicy, - &loop](fair::mq::DeviceRunner& r) { - deviceState = std::make_unique<DeviceState>(); - deviceState->loop = loop; - - simpleRawDeviceService = std::make_unique<SimpleRawDeviceService>(nullptr, spec); - - serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<RawDeviceService>(simpleRawDeviceService.get())); - serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<DeviceSpec>(&spec)); - - // The decltype stuff is to be able to compile with both new and old - // FairMQ API (one which uses a shared_ptr, the other one a unique_ptr. - decltype(r.fDevice) device; - device = std::move(make_matching<decltype(device), DataProcessingDevice>(spec, serviceRegistry, *deviceState.get())); - dynamic_cast<DataProcessingDevice*>(device.get())->SetErrorPolicy(errorPolicy); - - serviceRegistry.get<RawDeviceService>().setDevice(device.get()); - r.fDevice = std::move(device); - fair::Logger::SetConsoleColor(false); - - /// Create all the requested services and initialise them - for (auto& service : spec.services) { - LOG(debug) << "Declaring service " << service.name; - serviceRegistry.declareService(service, *deviceState.get(), r.fConfig); - } - if (ResourcesMonitoringHelper::isResourcesMonitoringEnabled(spec.resourceMonitoringInterval)) { - serviceRegistry.get<Monitoring>().enableProcessMonitoring(spec.resourceMonitoringInterval); - } - }; + // This is to control lifetime. All these services get destroyed + // when the runner is done. + std::unique_ptr<SimpleRawDeviceService> simpleRawDeviceService; + std::unique_ptr<DeviceState> deviceState; + std::unique_ptr<ComputingQuotaEvaluator> quotaEvaluator; + + auto afterConfigParsingCallback = [&simpleRawDeviceService, + &runningWorkflow, + ref, + &spec, + "aEvaluator, + &serviceRegistry, + &deviceState, + &errorPolicy, + &loop](fair::mq::DeviceRunner& r) { + simpleRawDeviceService = std::make_unique<SimpleRawDeviceService>(nullptr, spec); + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<RawDeviceService>(simpleRawDeviceService.get())); + + deviceState = std::make_unique<DeviceState>(); + deviceState->loop = loop; + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<DeviceState>(deviceState.get())); + + quotaEvaluator = std::make_unique<ComputingQuotaEvaluator>(uv_now(loop)); + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<ComputingQuotaEvaluator>(quotaEvaluator.get())); + + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<DeviceSpec const>(&spec)); + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<RunningWorkflowInfo const>(&runningWorkflow)); + + // The decltype stuff is to be able to compile with both new and old + // FairMQ API (one which uses a shared_ptr, the other one a unique_ptr. + decltype(r.fDevice) device; + device = std::move(make_matching<decltype(device), DataProcessingDevice>(ref, serviceRegistry)); + dynamic_cast<DataProcessingDevice*>(device.get())->SetErrorPolicy(errorPolicy); + + serviceRegistry.get<RawDeviceService>().setDevice(device.get()); + r.fDevice = std::move(device); + fair::Logger::SetConsoleColor(false); + + /// Create all the requested services and initialise them + for (auto& service : spec.services) { + LOG(debug) << "Declaring service " << service.name; + serviceRegistry.declareService(service, *deviceState.get(), r.fConfig); + } + if (ResourcesMonitoringHelper::isResourcesMonitoringEnabled(spec.resourceMonitoringInterval)) { + serviceRegistry.get<Monitoring>().enableProcessMonitoring(spec.resourceMonitoringInterval); + } + }; - runner.AddHook<fair::mq::hooks::InstantiateDevice>(afterConfigParsingCallback); - return runner.Run(); - } catch (boost::exception& e) { - LOG(ERROR) << "Unhandled boost::exception reached the top of main, device shutting down. Details follow: \n" - << boost::current_exception_diagnostic_information(true); - return 1; - } catch (o2::framework::RuntimeErrorRef e) { - LOG(ERROR) << "Unhandled o2::framework::runtime_error reached the top of main, device shutting down. Details follow: \n"; - auto& err = o2::framework::error_from_ref(e); - backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); - return 1; - } catch (std::exception& e) { - LOG(ERROR) << "Unhandled std::exception reached the top of main: " << e.what() << ", device shutting down."; - return 1; - } catch (...) { - LOG(ERROR) << "Unknown exception reached the top of main.\n"; - return 1; - } - return 0; + runner.AddHook<fair::mq::hooks::InstantiateDevice>(afterConfigParsingCallback); + return runner.Run(); } struct WorkflowInfo { @@ -833,6 +1169,7 @@ struct GuiCallbackContext { uint64_t frameLast; float* frameLatency; float* frameCost; + DebugGUI* plugin; void* window; bool* guiQuitRequested; std::function<void(void)> callback; @@ -841,9 +1178,12 @@ struct GuiCallbackContext { void gui_callback(uv_timer_s* ctx) { GuiCallbackContext* gui = reinterpret_cast<GuiCallbackContext*>(ctx->data); + if (gui->plugin == nullptr) { + return; + } uint64_t frameStart = uv_hrtime(); uint64_t frameLatency = frameStart - gui->frameLast; - *(gui->guiQuitRequested) = (pollGUI(gui->window, gui->callback) == false); + *(gui->guiQuitRequested) = (gui->plugin->pollGUI(gui->window, gui->callback) == false); uint64_t frameEnd = uv_hrtime(); *(gui->frameCost) = (frameEnd - frameStart) / 1000000; *(gui->frameLatency) = frameLatency / 1000000; @@ -857,23 +1197,41 @@ void single_step_callback(uv_timer_s* ctx) killChildren(*infos, SIGUSR1); } +void dumpMetricsCallback(uv_timer_t* handle) +{ + DriverServerContext* context = (DriverServerContext*)handle->data; + + auto performanceMetrics = o2::monitoring::ProcessMonitor::getAvailableMetricsNames(); + performanceMetrics.push_back("arrow-bytes-delta"); + performanceMetrics.push_back("aod-bytes-read-uncompressed"); + performanceMetrics.push_back("aod-bytes-read-compressed"); + performanceMetrics.push_back("aod-file-read-info"); + performanceMetrics.push_back("table-bytes-.*"); + ResourcesMonitoringHelper::dumpMetricsToJSON(*(context->metrics), + context->driver->metrics, *(context->specs), performanceMetrics); +} + // This is the handler for the parent inner loop. int runStateMachine(DataProcessorSpecs const& workflow, WorkflowInfo const& workflowInfo, DataProcessorInfos const& previousDataProcessorInfos, + CommandInfo const& commandInfo, DriverControl& driverControl, DriverInfo& driverInfo, std::vector<DeviceMetricsInfo>& metricsInfos, boost::program_options::variables_map& varmap, std::string frameworkId) { - DeviceSpecs deviceSpecs; + RunningWorkflowInfo runningWorkflow; DeviceInfos infos; DeviceControls controls; + DevicesManager* devicesManager = new DevicesManager{controls, infos, runningWorkflow.devices}; DeviceExecutions deviceExecutions; DataProcessorInfos dataProcessorInfos = previousDataProcessorInfos; std::vector<uv_poll_t*> pollHandles; + std::vector<DeviceStdioContext> childFds; + std::vector<ComputingResource> resources; if (driverInfo.resources != "") { @@ -884,12 +1242,39 @@ int runStateMachine(DataProcessorSpecs const& workflow, auto resourceManager = std::make_unique<SimpleResourceManager>(resources); + DebugGUI* debugGUI = nullptr; void* window = nullptr; - decltype(gui::getGUIDebugger(infos, deviceSpecs, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl)) debugGUICallback; + decltype(debugGUI->getGUIDebugger(infos, runningWorkflow.devices, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl)) debugGUICallback; // An empty frameworkId means this is the driver, so we initialise the GUI if (driverInfo.batch == false && frameworkId.empty()) { - window = initGUI("O2 Framework debug GUI"); + auto initDebugGUI = []() -> DebugGUI* { + uv_lib_t supportLib; + int result = 0; +#ifdef __APPLE__ + result = uv_dlopen("libO2FrameworkGUISupport.dylib", &supportLib); +#else + result = uv_dlopen("libO2FrameworkGUISupport.so", &supportLib); +#endif + if (result == -1) { + LOG(ERROR) << uv_dlerror(&supportLib); + return nullptr; + } + void* callback = nullptr; + DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*); + + result = uv_dlsym(&supportLib, "dpl_plugin_callback", (void**)&dpl_plugin_callback); + if (result == -1) { + LOG(ERROR) << uv_dlerror(&supportLib); + return nullptr; + } + DPLPluginHandle* pluginInstance = dpl_plugin_callback(nullptr); + return PluginManager::getByName<DebugGUI>(pluginInstance, "ImGUIDebugGUI"); + }; + debugGUI = initDebugGUI(); + if (debugGUI) { + window = debugGUI->initGUI("O2 Framework debug GUI"); + } } if (driverInfo.batch == false && window == nullptr && frameworkId.empty()) { LOG(WARN) << "Could not create GUI. Switching to batch mode. Do you have GLFW on your system?"; @@ -911,7 +1296,71 @@ int runStateMachine(DataProcessorSpecs const& workflow, uv_timer_init(loop, &gui_timer); } + // We initialise this in the driver, because different drivers might have + // different versions of the service + ServiceRegistry serviceRegistry; + std::vector<ServiceMetricHandling> metricProcessingCallbacks; + std::vector<ServicePreSchedule> preScheduleCallbacks; + std::vector<ServicePostSchedule> postScheduleCallbacks; + std::vector<ServiceDriverInit> driverInitCallbacks; + std::vector<ServiceSpec> driverServices = CommonDriverServices::defaultServices(); + for (auto& service : driverServices) { + service.driverStartup(serviceRegistry, varmap); + } + + serviceRegistry.registerService(ServiceRegistryHelpers::handleForService<DevicesManager>(devicesManager)); + + // This is to make sure we can process metrics, commands, configuration + // changes coming from websocket (or even via any standard uv_stream_t, I guess). + DriverServerContext serverContext; + serverContext.registry = &serviceRegistry; + serverContext.loop = loop; + serverContext.controls = &controls; + serverContext.infos = &infos; + serverContext.specs = &runningWorkflow.devices; + serverContext.metrics = &metricsInfos; + serverContext.driver = &driverInfo; + serverContext.metricProcessingCallbacks = &metricProcessingCallbacks; + + uv_tcp_t serverHandle; + serverHandle.data = &serverContext; + uv_tcp_init(loop, &serverHandle); + driverInfo.port = 8080 + (getpid() % 30000); + int result = 0; + struct sockaddr_in* serverAddr = nullptr; + + // Do not offer websocket endpoint for devices + // FIXME: this was blocking david's workflows. For now + // there is no point in any case to have devices + // offering a web based API, but it might make sense in + // the future to inspect them via some web based interface. + if (frameworkId.empty()) { + do { + if (serverAddr) { + free(serverAddr); + } + if (driverInfo.port > 64000) { + throw runtime_error_f("Unable to find a free port for the driver. Last attempt returned %d", result); + } + serverAddr = (sockaddr_in*)malloc(sizeof(sockaddr_in)); + uv_ip4_addr("0.0.0.0", driverInfo.port, serverAddr); + auto bindResult = uv_tcp_bind(&serverHandle, (const struct sockaddr*)serverAddr, 0); + if (bindResult != 0) { + driverInfo.port++; + usleep(1000); + continue; + } + result = uv_listen((uv_stream_t*)&serverHandle, 100, ws_connect_callback); + if (result != 0) { + driverInfo.port++; + usleep(1000); + continue; + } + } while (result != 0); + } + GuiCallbackContext guiContext; + guiContext.plugin = debugGUI; guiContext.frameLast = uv_hrtime(); guiContext.frameLatency = &driverInfo.frameLatency; guiContext.frameCost = &driverInfo.frameCost; @@ -921,14 +1370,11 @@ int runStateMachine(DataProcessorSpecs const& workflow, uv_timer_t force_step_timer; uv_timer_init(loop, &force_step_timer); - // We initialise this in the driver, because different drivers might have - // different versions of the service - ServiceRegistry serviceRegistry; - std::vector<ServiceMetricHandling> metricProcessingCallbacks; - std::vector<ServicePreSchedule> preScheduleCallbacks; - std::vector<ServicePostSchedule> postScheduleCallbacks; - bool guiDeployedOnce = false; + bool once = false; + + uv_timer_t metricDumpTimer; + metricDumpTimer.data = &serverContext; while (true) { // If control forced some transition on us, we push it to the queue. @@ -969,7 +1415,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, driverInfo.states.pop_back(); switch (current) { case DriverState::INIT: - LOG(INFO) << "Initialising O2 Data Processing Layer"; + LOGP(info, "Initialising O2 Data Processing Layer. Driver PID: {}.", getpid()); // Install signal handler for quitting children. driverInfo.sa_handle_child.sa_handler = &handle_sigchld; @@ -991,6 +1437,9 @@ int runStateMachine(DataProcessorSpecs const& workflow, /// there and back into running. This is because the general case /// would be that we start an application and then we wait for /// resource offers from DDS or whatever resource manager we use. + for (auto& callback : driverInitCallbacks) { + callback(serviceRegistry, varmap); + } driverInfo.states.push_back(DriverState::RUNNING); // driverInfo.states.push_back(DriverState::REDEPLOY_GUI); LOG(INFO) << "O2 Data Processing Layer initialised. We brake for nobody."; @@ -1002,7 +1451,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, // This state is needed to fill the metadata structure // which contains how to run the current workflow dataProcessorInfos = previousDataProcessorInfos; - for (auto const& device : deviceSpecs) { + for (auto const& device : runningWorkflow.devices) { auto exists = std::find_if(dataProcessorInfos.begin(), dataProcessorInfos.end(), [id = device.id](DataProcessorInfo const& info) -> bool { return info.name == id; }); @@ -1031,17 +1480,101 @@ int runStateMachine(DataProcessorSpecs const& workflow, if (driverInfo.batch == true && workflowState == WorkflowParsingState::Empty) { throw runtime_error("Empty workflow provided while running in batch mode."); } - DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, + + /// extract and apply process switches + /// prune device inputs + auto altered_workflow = workflow; + + auto confNameFromParam = [](std::string const& paramName) { + std::regex name_regex(R"(^control:([\w-]+)\/(\w+))"); + auto match = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 0); + if (match == std::sregex_token_iterator()) { + throw runtime_error_f("Malformed process control spec: %s", paramName.c_str()); + } + std::string task = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 1)->str(); + std::string conf = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 2)->str(); + return std::pair{task, conf}; + }; + bool altered = false; + for (auto& device : altered_workflow) { + LOGF(DEBUG, "Adjusting device %s", device.name.c_str()); + // ignore internal devices + if (device.name.find("internal") != std::string::npos) { + continue; + } + // ignore devices with no inputs + if (device.inputs.empty() == true) { + continue; + } + //ignore devices with no metadata in inputs + auto hasMetadata = std::any_of(device.inputs.begin(), device.inputs.end(), [](InputSpec const& spec) { + return spec.metadata.empty() == false; + }); + if (!hasMetadata) { + continue; + } + // ignore devices with no control options + auto hasControls = std::any_of(device.inputs.begin(), device.inputs.end(), [](InputSpec const& spec) { + return std::any_of(spec.metadata.begin(), spec.metadata.end(), [](ConfigParamSpec const& param) { + return param.type == VariantType::Bool && param.name.find("control:") != std::string::npos; + }); + }); + if (!hasControls) { + continue; + } + + auto configStore = DeviceConfigurationHelpers::getConfiguration(serviceRegistry, device.name.c_str(), device.options); + if (configStore != nullptr) { + auto reg = std::make_unique<ConfigParamRegistry>(std::move(configStore)); + for (auto& input : device.inputs) { + for (auto& param : input.metadata) { + if (param.type == VariantType::Bool && param.name.find("control:") != std::string::npos) { + if (param.name != "control:default" && param.name != "control:spawn" && param.name != "control:build") { + auto confName = confNameFromParam(param.name).second; + param.defaultValue = reg->get<bool>(confName.c_str()); + } + } + } + } + } + /// FIXME: use commandline arguments as alternative + LOGF(DEBUG, "Original inputs: "); + for (auto& input : device.inputs) { + LOGF(DEBUG, "-> %s", input.binding); + } + auto end = device.inputs.end(); + auto new_end = std::remove_if(device.inputs.begin(), device.inputs.end(), [](InputSpec& input) { + return !std::any_of(input.metadata.begin(), input.metadata.end(), [](ConfigParamSpec& param) { + if (param.type == VariantType::Bool && param.name.find("control:") != std::string::npos) { + return param.defaultValue.get<bool>() == true; + } + return true; + }); + }); + device.inputs.erase(new_end, end); + LOGF(DEBUG, "Adjusted inputs: "); + for (auto& input : device.inputs) { + LOGF(DEBUG, "-> %s", input.binding); + } + altered = true; + } + if (altered) { + WorkflowHelpers::adjustServiceDevices(altered_workflow); + } + + DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(altered_workflow, driverInfo.channelPolicies, driverInfo.completionPolicies, driverInfo.dispatchPolicies, - deviceSpecs, + driverInfo.resourcePolicies, + runningWorkflow.devices, *resourceManager, driverInfo.uniqueWorkflowId, !varmap["no-IPC"].as<bool>(), - driverInfo.resourcesMonitoringInterval); + driverInfo.resourcesMonitoringInterval, + varmap["channel-prefix"].as<std::string>()); metricProcessingCallbacks.clear(); - for (auto& device : deviceSpecs) { + for (auto& device : runningWorkflow.devices) { for (auto& service : device.services) { if (service.metricHandling) { metricProcessingCallbacks.push_back(service.metricHandling); @@ -1049,7 +1582,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, } } preScheduleCallbacks.clear(); - for (auto& device : deviceSpecs) { + for (auto& device : runningWorkflow.devices) { for (auto& service : device.services) { if (service.preSchedule) { preScheduleCallbacks.push_back(service.preSchedule); @@ -1057,27 +1590,35 @@ int runStateMachine(DataProcessorSpecs const& workflow, } } postScheduleCallbacks.clear(); - for (auto& device : deviceSpecs) { + for (auto& device : runningWorkflow.devices) { for (auto& service : device.services) { if (service.postSchedule) { postScheduleCallbacks.push_back(service.postSchedule); } } } + driverInitCallbacks.clear(); + for (auto& device : runningWorkflow.devices) { + for (auto& service : device.services) { + if (service.driverInit) { + driverInitCallbacks.push_back(service.driverInit); + } + } + } // This should expand nodes so that we can build a consistent DAG. } catch (std::runtime_error& e) { - std::cerr << "Invalid workflow: " << e.what() << std::endl; + LOGP(ERROR, "invalid workflow in {}: {}", driverInfo.argv[0], e.what()); return 1; } catch (o2::framework::RuntimeErrorRef ref) { - auto& e = o2::framework::error_from_ref(ref); + auto& err = o2::framework::error_from_ref(ref); #ifdef DPL_ENABLE_BACKTRACE backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); #endif - std::cerr << "Invalid workflow: " << e.what << std::endl; + LOGP(ERROR, "invalid workflow in {}: {}", driverInfo.argv[0], err.what); return 1; } catch (...) { - std::cerr << "Unknown error while materialising workflow"; + LOGP(ERROR, "invalid workflow in {}: Unknown error while materialising workflow", driverInfo.argv[0]); return 1; } break; @@ -1086,11 +1627,15 @@ int runStateMachine(DataProcessorSpecs const& workflow, if (driverControl.defaultStopped) { kill(getpid(), SIGSTOP); } - for (auto& spec : deviceSpecs) { - if (spec.id == frameworkId) { + for (size_t di = 0; di < runningWorkflow.devices.size(); di++) { + RunningDeviceRef ref{di}; + if (runningWorkflow.devices[di].id == frameworkId) { return doChild(driverInfo.argc, driverInfo.argv, - serviceRegistry, spec, - driverInfo.errorPolicy, loop); + serviceRegistry, + runningWorkflow, ref, + driverInfo.errorPolicy, + driverInfo.defaultDriverClient, + loop); } } { @@ -1098,7 +1643,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, for (auto& processor : workflow) { ss << " - " << processor.name << "\n"; } - for (auto& spec : deviceSpecs) { + for (auto& spec : runningWorkflow.devices) { ss << " - " << spec.name << "(" << spec.id << ")" << "\n"; } @@ -1116,33 +1661,68 @@ int runStateMachine(DataProcessorSpecs const& workflow, // because getGUIDebugger actually recreates the GUI state. if (window) { uv_timer_stop(&gui_timer); - guiContext.callback = gui::getGUIDebugger(infos, deviceSpecs, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl); + guiContext.callback = debugGUI->getGUIDebugger(infos, runningWorkflow.devices, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl); guiContext.window = window; gui_timer.data = &guiContext; uv_timer_start(&gui_timer, gui_callback, 0, 20); guiDeployedOnce = true; } break; + case DriverState::MERGE_CONFIGS: { + try { + controls.resize(runningWorkflow.devices.size()); + deviceExecutions.resize(runningWorkflow.devices.size()); + + // Options which should be uniform across all + // teh subworkflow invokations. + const auto uniformOptions = { + "--aod-file", + "--aod-memory-rate-limit", + "--aod-writer-json", + "--aod-writer-ntfmerge", + "--aod-writer-resfile", + "--aod-writer-resmode", + "--aod-writer-keep", + "--driver-client-backend", + "--fairmq-ipc-prefix", + "--readers", + "--resources-monitoring", + "--resources-monitoring-dump-interval", + "--time-limit", + }; + + for (auto& option : uniformOptions) { + DeviceSpecHelpers::reworkHomogeneousOption(dataProcessorInfos, option, nullptr); + } + + DeviceSpecHelpers::reworkShmSegmentSize(dataProcessorInfos); + DeviceSpecHelpers::prepareArguments(driverControl.defaultQuiet, + driverControl.defaultStopped, + driverInfo.port, + dataProcessorInfos, + runningWorkflow.devices, + deviceExecutions, + controls, + driverInfo.uniqueWorkflowId); + } catch (o2::framework::RuntimeErrorRef& ref) { + auto& err = o2::framework::error_from_ref(ref); + LOGP(ERROR, "unable to merge configurations in {}: {}", driverInfo.argv[0], err.what); +#ifdef DPL_ENABLE_BACKTRACE + std::cerr << "\nStacktrace follows:\n\n"; + backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); +#endif + return 1; + } + } break; case DriverState::SCHEDULE: { // FIXME: for the moment modifying the topology means we rebuild completely // all the devices and we restart them. This is also what DDS does at // a larger scale. In principle one could try to do a delta and only // restart the data processors which need to be restarted. LOG(INFO) << "Redeployment of configuration asked."; - controls.resize(deviceSpecs.size()); - deviceExecutions.resize(deviceSpecs.size()); - - DeviceSpecHelpers::reworkShmSegmentSize(dataProcessorInfos); - DeviceSpecHelpers::prepareArguments(driverControl.defaultQuiet, - driverControl.defaultStopped, - dataProcessorInfos, - deviceSpecs, - deviceExecutions, controls, - driverInfo.uniqueWorkflowId); - std::ostringstream forwardedStdin; - WorkflowSerializationHelpers::dump(forwardedStdin, workflow, dataProcessorInfos); - infos.reserve(deviceSpecs.size()); + WorkflowSerializationHelpers::dump(forwardedStdin, workflow, dataProcessorInfos, commandInfo); + infos.reserve(runningWorkflow.devices.size()); // This is guaranteed to be a single CPU. unsigned parentCPU = -1; @@ -1151,7 +1731,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, parentCPU = sched_getcpu(); #elif __has_include(<linux/getcpu.h>) getcpu(&parentCPU, &parentNode, nullptr); -#elif __has_include(<cpuid.h>) +#elif __has_include(<cpuid.h>) && (__x86_64__ || __i386__) // FIXME: this is a last resort as it is apparently buggy // on some Intel CPUs. GETCPU(parentCPU); @@ -1159,28 +1739,45 @@ int runStateMachine(DataProcessorSpecs const& workflow, for (auto& callback : preScheduleCallbacks) { callback(serviceRegistry, varmap); } - for (size_t di = 0; di < deviceSpecs.size(); ++di) { - if (deviceSpecs[di].resource.hostname != driverInfo.deployHostname) { + childFds.resize(runningWorkflow.devices.size()); + prepareStdio(childFds); + for (int di = 0; di < runningWorkflow.devices.size(); ++di) { + if (runningWorkflow.devices[di].resource.hostname != driverInfo.deployHostname) { spawnRemoteDevice(forwardedStdin.str(), - deviceSpecs[di], controls[di], deviceExecutions[di], infos); + runningWorkflow.devices[di], controls[di], deviceExecutions[di], infos); } else { - spawnDevice(forwardedStdin.str(), - deviceSpecs[di], driverInfo, - controls[di], deviceExecutions[di], infos, - serviceRegistry, varmap, loop, pollHandles, parentCPU, parentNode); + DeviceRef ref{di}; + spawnDevice(ref, + runningWorkflow.devices, driverInfo, + controls, deviceExecutions, infos, + serviceRegistry, varmap, + childFds, parentCPU, parentNode); } } + handleSignals(); + handleChildrenStdio(loop, forwardedStdin.str(), infos, childFds, pollHandles); for (auto& callback : postScheduleCallbacks) { callback(serviceRegistry, varmap); } assert(infos.empty() == false); + + // In case resource monitoring is requested, we dump metrics to disk + // every 3 minutes. + if (driverInfo.resourcesMonitoringDumpInterval && ResourcesMonitoringHelper::isResourcesMonitoringEnabled(driverInfo.resourcesMonitoringInterval)) { + uv_timer_init(loop, &metricDumpTimer); + uv_timer_start(&metricDumpTimer, dumpMetricsCallback, + driverInfo.resourcesMonitoringDumpInterval * 1000, + driverInfo.resourcesMonitoringDumpInterval * 1000); + } LOG(INFO) << "Redeployment of configuration done."; } break; case DriverState::RUNNING: // Run any pending libUV event loop, block if // any, so that we do not consume CPU time when the driver is // idle. - uv_run(loop, UV_RUN_ONCE); + devicesManager->flush(); + uv_run(loop, once ? UV_RUN_ONCE : UV_RUN_NOWAIT); + once = true; // Calculate what we should do next and eventually // show the GUI if (guiQuitRequested || @@ -1191,19 +1788,20 @@ int runStateMachine(DataProcessorSpecs const& workflow, // Let's update the GUI one more time and then EXIT. LOG(INFO) << "Quitting"; driverInfo.states.push_back(DriverState::QUIT_REQUESTED); - } else if (infos.size() != deviceSpecs.size()) { - // If the number of deviceSpecs is different from + } else if (infos.size() != runningWorkflow.devices.size()) { + // If the number of devices is different from // the DeviceInfos it means the speicification // does not match what is running, so we need to do // further scheduling. driverInfo.states.push_back(DriverState::RUNNING); driverInfo.states.push_back(DriverState::REDEPLOY_GUI); driverInfo.states.push_back(DriverState::SCHEDULE); - } else if (deviceSpecs.empty() && driverInfo.batch == true) { + driverInfo.states.push_back(DriverState::MERGE_CONFIGS); + } else if (runningWorkflow.devices.empty() && driverInfo.batch == true) { LOG(INFO) << "No device resulting from the workflow. Quitting."; // If there are no deviceSpecs, we exit. driverInfo.states.push_back(DriverState::EXIT); - } else if (deviceSpecs.empty() && driverInfo.batch == false && !guiDeployedOnce) { + } else if (runningWorkflow.devices.empty() && driverInfo.batch == false && !guiDeployedOnce) { // In case of an empty workflow, we need to deploy the GUI at least once. driverInfo.states.push_back(DriverState::RUNNING); driverInfo.states.push_back(DriverState::REDEPLOY_GUI); @@ -1213,11 +1811,11 @@ int runStateMachine(DataProcessorSpecs const& workflow, { uint64_t inputProcessingStart = uv_hrtime(); auto inputProcessingLatency = inputProcessingStart - inputProcessingLast; - auto outputProcessing = processChildrenOutput(driverInfo, infos, deviceSpecs, controls, metricsInfos); + auto outputProcessing = processChildrenOutput(driverInfo, infos, runningWorkflow.devices, controls, metricsInfos); if (outputProcessing.didProcessMetric) { size_t timestamp = current_time_with_ms(); for (auto& callback : metricProcessingCallbacks) { - callback(serviceRegistry, metricsInfos, deviceSpecs, infos, driverInfo.metrics, timestamp); + callback(serviceRegistry, metricsInfos, runningWorkflow.devices, infos, driverInfo.metrics, timestamp); } for (auto& metricsInfo : metricsInfos) { std::fill(metricsInfo.changed.begin(), metricsInfo.changed.end(), false); @@ -1246,7 +1844,8 @@ int runStateMachine(DataProcessorSpecs const& workflow, // Run any pending libUV event loop, block if // any, so that we do not consume CPU time when the driver is // idle. - uv_run(loop, UV_RUN_ONCE); + uv_run(loop, once ? UV_RUN_ONCE : UV_RUN_NOWAIT); + once = true; // I allow queueing of more sigchld only when // I process the previous call if (forceful_exit == true) { @@ -1260,11 +1859,11 @@ int runStateMachine(DataProcessorSpecs const& workflow, } sigchld_requested = false; driverInfo.sigchldRequested = false; - auto outputProcessing = processChildrenOutput(driverInfo, infos, deviceSpecs, controls, metricsInfos); + auto outputProcessing = processChildrenOutput(driverInfo, infos, runningWorkflow.devices, controls, metricsInfos); if (outputProcessing.didProcessMetric) { size_t timestamp = current_time_with_ms(); for (auto& callback : metricProcessingCallbacks) { - callback(serviceRegistry, metricsInfos, deviceSpecs, infos, driverInfo.metrics, timestamp); + callback(serviceRegistry, metricsInfos, runningWorkflow.devices, infos, driverInfo.metrics, timestamp); } } hasError = processSigChild(infos); @@ -1285,20 +1884,27 @@ int runStateMachine(DataProcessorSpecs const& workflow, } break; case DriverState::EXIT: { if (ResourcesMonitoringHelper::isResourcesMonitoringEnabled(driverInfo.resourcesMonitoringInterval)) { + if (driverInfo.resourcesMonitoringDumpInterval) { + uv_timer_stop(&metricDumpTimer); + } LOG(INFO) << "Dumping performance metrics to performanceMetrics.json file"; - auto performanceMetrics = o2::monitoring::ProcessMonitor::getAvailableMetricsNames(); - performanceMetrics.push_back("arrow-bytes-delta"); - ResourcesMonitoringHelper::dumpMetricsToJSON(metricsInfos, deviceSpecs, performanceMetrics); + dumpMetricsCallback(&metricDumpTimer); } // This is a clean exit. Before we do so, if required, // we dump the configuration of all the devices so that - // we can reuse it + // we can reuse it. Notice we do not dump anything if + // the workflow was not really run. + // NOTE: is this really what we want? should we run + // SCHEDULE and dump the full configuration as well? + if (infos.empty()) { + return 0; + } boost::property_tree::ptree finalConfig; - assert(infos.size() == deviceSpecs.size()); + assert(infos.size() == runningWorkflow.devices.size()); for (size_t di = 0; di < infos.size(); ++di) { auto info = infos[di]; - auto spec = deviceSpecs[di]; - PropertyTreeHelpers::merge(finalConfig, info.currentConfig, spec.name); + auto spec = runningWorkflow.devices[di]; + finalConfig.put_child(spec.name, info.currentConfig); } LOG(INFO) << "Dumping used configuration in dpl-config.json"; boost::property_tree::write_json("dpl-config.json", finalConfig); @@ -1307,11 +1913,11 @@ int runStateMachine(DataProcessorSpecs const& workflow, } else { cleanupSHM(driverInfo.uniqueWorkflowId); } - return calculateExitCode(deviceSpecs, infos); + return calculateExitCode(driverInfo, runningWorkflow.devices, infos); } case DriverState::PERFORM_CALLBACKS: for (auto& callback : driverControl.callbacks) { - callback(workflow, deviceSpecs, deviceExecutions, dataProcessorInfos); + callback(workflow, runningWorkflow.devices, deviceExecutions, dataProcessorInfos, commandInfo); } driverControl.callbacks.clear(); break; @@ -1370,6 +1976,70 @@ bool isOutputToPipe() return ((s.st_mode & S_IFIFO) != 0); } +bool isInputConfig() +{ + struct stat s; + int r = fstat(STDIN_FILENO, &s); + // If stdin cannot be statted, we assume the shell is some sort of + // non-interactive container thing + if (r < 0) { + return false; + } + // If stdin is a pipe or a file, we try to fetch configuration from there + return ((s.st_mode & S_IFIFO) != 0 || (s.st_mode & S_IFREG) != 0); +} + +void overrideCloning(ConfigContext& ctx, WorkflowSpec& workflow) +{ + struct CloningSpec { + std::string templateMatcher; + std::string cloneName; + }; + auto s = ctx.options().get<std::string>("clone"); + std::vector<CloningSpec> specs; + std::string delimiter = ","; + + size_t pos = 0; + while (s.empty() == false) { + auto newPos = s.find(delimiter); + auto token = s.substr(0, newPos); + auto split = token.find(":"); + if (split == std::string::npos) { + throw std::runtime_error("bad clone definition. Syntax <template-processor>:<clone-name>"); + } + auto key = token.substr(0, split); + token.erase(0, split + 1); + size_t error; + std::string value = ""; + try { + auto numValue = std::stoll(token, &error, 10); + if (token[error] != '\0') { + throw std::runtime_error("bad name for clone:" + token); + } + value = key + "_c" + std::to_string(numValue); + } catch (std::invalid_argument& e) { + value = token; + } + specs.push_back({key, value}); + s.erase(0, newPos + (newPos == std::string::npos ? 0 : 1)); + } + if (s.empty() == false && specs.empty() == true) { + throw std::runtime_error("bad pipeline definition. Syntax <processor>:<pipeline>"); + } + + std::vector<DataProcessorSpec> extraSpecs; + for (auto& spec : specs) { + for (auto& processor : workflow) { + if (processor.name == spec.templateMatcher) { + auto clone = processor; + clone.name = spec.cloneName; + extraSpecs.push_back(clone); + } + } + } + workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); +} + void overridePipeline(ConfigContext& ctx, WorkflowSpec& workflow) { struct PipelineSpec { @@ -1411,6 +2081,71 @@ void overridePipeline(ConfigContext& ctx, WorkflowSpec& workflow) } } +void overrideLabels(ConfigContext& ctx, WorkflowSpec& workflow) +{ + struct LabelsSpec { + std::string_view matcher; + std::vector<std::string> labels; + }; + std::vector<LabelsSpec> specs; + + auto labelsString = ctx.options().get<std::string>("labels"); + if (labelsString.empty()) { + return; + } + std::string_view sv{labelsString}; + + size_t specStart = 0; + size_t specEnd = 0; + constexpr char specDelim = ','; + constexpr char labelDelim = ':'; + do { + specEnd = sv.find(specDelim, specStart); + auto token = sv.substr(specStart, specEnd == std::string_view::npos ? std::string_view::npos : specEnd - specStart); + if (token.empty()) { + throw std::runtime_error("bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]"); + } + + size_t labelDelimPos = token.find(labelDelim); + if (labelDelimPos == 0 || labelDelimPos == std::string_view::npos) { + throw std::runtime_error("bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]"); + } + LabelsSpec spec{token.substr(0, labelDelimPos)}; + + size_t labelEnd = labelDelimPos + 1; + do { + size_t labelStart = labelDelimPos + 1; + labelEnd = token.find(labelDelim, labelStart); + auto label = labelEnd == std::string_view::npos ? token.substr(labelStart) : token.substr(labelStart, labelEnd - labelStart); + if (label.empty()) { + throw std::runtime_error("bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]"); + } + spec.labels.emplace_back(label); + labelDelimPos = labelEnd; + } while (labelEnd != std::string_view::npos); + + specs.push_back(spec); + specStart = specEnd + 1; + } while (specEnd != std::string_view::npos); + + if (labelsString.empty() == false && specs.empty() == true) { + throw std::runtime_error("bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]"); + } + + for (auto& spec : specs) { + for (auto& processor : workflow) { + if (processor.name == spec.matcher) { + for (const auto& label : spec.labels) { + if (std::find_if(processor.labels.begin(), processor.labels.end(), + [label](const auto& procLabel) { return procLabel.value == label; }) == processor.labels.end()) { + processor.labels.push_back({label}); + } + } + } + } + } +} + /// Helper function to initialise the controller from the command line options. void initialiseDriverControl(bpo::variables_map const& varmap, DriverControl& control) @@ -1431,12 +2166,14 @@ void initialiseDriverControl(bpo::variables_map const& varmap, control.callbacks = {[](WorkflowSpec const& workflow, DeviceSpecs const& specs, DeviceExecutions const&, - DataProcessorInfos&) { + DataProcessorInfos&, + CommandInfo const&) { GraphvizHelpers::dumpDeviceSpec2Graphviz(std::cout, specs); }}; control.forcedTransitions = { DriverState::EXIT, // DriverState::PERFORM_CALLBACKS, // + DriverState::MERGE_CONFIGS, // DriverState::IMPORT_CURRENT_WORKFLOW, // DriverState::MATERIALISE_WORKFLOW // }; @@ -1448,30 +2185,34 @@ void initialiseDriverControl(bpo::variables_map const& varmap, control.callbacks = {[](WorkflowSpec const& workflow, DeviceSpecs const& specs, DeviceExecutions const& executions, - DataProcessorInfos&) { - dumpDeviceSpec2DDS(std::cout, specs, executions); + DataProcessorInfos&, + CommandInfo const& commandInfo) { + dumpDeviceSpec2DDS(std::cout, specs, executions, commandInfo); }}; control.forcedTransitions = { DriverState::EXIT, // DriverState::PERFORM_CALLBACKS, // - DriverState::SCHEDULE, // + DriverState::MERGE_CONFIGS, // DriverState::IMPORT_CURRENT_WORKFLOW, // DriverState::MATERIALISE_WORKFLOW // }; - } else if (varmap["o2-control"].as<bool>()) { - control.callbacks = {[](WorkflowSpec const& workflow, - DeviceSpecs const& specs, - DeviceExecutions const& executions, - DataProcessorInfos&) { - dumpDeviceSpec2O2Control(std::cout, specs, executions); - }}; + } else if (!varmap["o2-control"].as<std::string>().empty()) { + control.callbacks = {[workflowName = varmap["o2-control"].as<std::string>()] // + (WorkflowSpec const& workflow, + DeviceSpecs const& specs, + DeviceExecutions const& executions, + DataProcessorInfos&, + CommandInfo const& commandInfo) { + dumpDeviceSpec2O2Control(workflowName, specs, executions, commandInfo); + }}; control.forcedTransitions = { DriverState::EXIT, // DriverState::PERFORM_CALLBACKS, // - DriverState::SCHEDULE, // + DriverState::MERGE_CONFIGS, // DriverState::IMPORT_CURRENT_WORKFLOW, // DriverState::MATERIALISE_WORKFLOW // }; + } else if (varmap.count("id")) { // FIXME: for the time being each child needs to recalculate the workflow, // so that it can understand what it needs to do. This is obviously @@ -1479,6 +2220,7 @@ void initialiseDriverControl(bpo::variables_map const& varmap, // it's own configuration by the driver. control.forcedTransitions = { DriverState::DO_CHILD, // + DriverState::MERGE_CONFIGS, // DriverState::IMPORT_CURRENT_WORKFLOW, // DriverState::MATERIALISE_WORKFLOW // }; @@ -1486,19 +2228,21 @@ void initialiseDriverControl(bpo::variables_map const& varmap, control.callbacks = {[filename = varmap["dump-workflow-file"].as<std::string>()](WorkflowSpec const& workflow, DeviceSpecs const devices, DeviceExecutions const&, - DataProcessorInfos& dataProcessorInfos) { + DataProcessorInfos& dataProcessorInfos, + CommandInfo const& commandInfo) { if (filename == "-") { - WorkflowSerializationHelpers::dump(std::cout, workflow, dataProcessorInfos); + WorkflowSerializationHelpers::dump(std::cout, workflow, dataProcessorInfos, commandInfo); // FIXME: this is to avoid trailing garbage.. exit(0); } else { std::ofstream output(filename); - WorkflowSerializationHelpers::dump(output, workflow, dataProcessorInfos); + WorkflowSerializationHelpers::dump(output, workflow, dataProcessorInfos, commandInfo); } }}; control.forcedTransitions = { DriverState::EXIT, // DriverState::PERFORM_CALLBACKS, // + DriverState::MERGE_CONFIGS, // DriverState::IMPORT_CURRENT_WORKFLOW, // DriverState::MATERIALISE_WORKFLOW // }; @@ -1582,11 +2326,14 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, std::vector<ChannelConfigurationPolicy> const& channelPolicies, std::vector<CompletionPolicy> const& completionPolicies, std::vector<DispatchPolicy> const& dispatchPolicies, + std::vector<ResourcePolicy> const& resourcePolicies, std::vector<ConfigParamSpec> const& currentWorkflowOptions, o2::framework::ConfigContext& configContext) { O2_SIGNPOST_INIT(); std::vector<std::string> currentArgs; + std::vector<PluginInfo> plugins; + for (size_t ai = 1; ai < argc; ++ai) { currentArgs.push_back(argv[ai]); } @@ -1598,32 +2345,37 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, enum TerminationPolicy policy; enum TerminationPolicy errorPolicy; + enum LogParsingHelpers::LogLevel minFailureLevel; bpo::options_description executorOptions("Executor options"); const char* helpDescription = "print help: short, full, executor, or processor name"; - executorOptions.add_options() // - ("help,h", bpo::value<std::string>()->implicit_value("short"), helpDescription) // // - ("quiet,q", bpo::value<bool>()->zero_tokens()->default_value(false), "quiet operation") // // - ("stop,s", bpo::value<bool>()->zero_tokens()->default_value(false), "stop before device start") // // - ("single-step", bpo::value<bool>()->zero_tokens()->default_value(false), "start in single step mode") // // - ("batch,b", bpo::value<bool>()->zero_tokens()->default_value(isatty(fileno(stdout)) == 0), "batch processing mode") // // - ("no-cleanup", bpo::value<bool>()->zero_tokens()->default_value(false), "do not cleanup the shm segment") // // - ("hostname", bpo::value<std::string>()->default_value("localhost"), "hostname to deploy") // // - ("resources", bpo::value<std::string>()->default_value(""), "resources allocated for the workflow") // // - ("start-port,p", bpo::value<unsigned short>()->default_value(22000), "start port to allocate") // // - ("port-range,pr", bpo::value<unsigned short>()->default_value(1000), "ports in range") // // - ("completion-policy,c", bpo::value<TerminationPolicy>(&policy)->default_value(TerminationPolicy::QUIT), // // - "what to do when processing is finished: quit, wait") // // - ("error-policy", bpo::value<TerminationPolicy>(&errorPolicy)->default_value(TerminationPolicy::QUIT), // // - "what to do when a device has an error: quit, wait") // // - ("graphviz,g", bpo::value<bool>()->zero_tokens()->default_value(false), "produce graph output") // // - ("timeout,t", bpo::value<uint64_t>()->default_value(0), "forced exit timeout (in seconds)") // // - ("dds,D", bpo::value<bool>()->zero_tokens()->default_value(false), "create DDS configuration") // // - ("dump-workflow,dump", bpo::value<bool>()->zero_tokens()->default_value(false), "dump workflow as JSON") // // - ("dump-workflow-file", bpo::value<std::string>()->default_value("-"), "file to which do the dump") // // - ("run", bpo::value<bool>()->zero_tokens()->default_value(false), "run workflow merged so far") // // - ("no-IPC", bpo::value<bool>()->zero_tokens()->default_value(false), "disable IPC topology optimization") // // - ("o2-control,o2", bpo::value<bool>()->zero_tokens()->default_value(false), "create O2 Control configuration") // - ("resources-monitoring", bpo::value<unsigned short>()->default_value(0), "enable cpu/memory monitoring for provided interval in seconds"); // + executorOptions.add_options() // + ("help,h", bpo::value<std::string>()->implicit_value("short"), helpDescription) // // + ("quiet,q", bpo::value<bool>()->zero_tokens()->default_value(false), "quiet operation") // // + ("stop,s", bpo::value<bool>()->zero_tokens()->default_value(false), "stop before device start") // // + ("single-step", bpo::value<bool>()->zero_tokens()->default_value(false), "start in single step mode") // // + ("batch,b", bpo::value<bool>()->zero_tokens()->default_value(isatty(fileno(stdout)) == 0), "batch processing mode") // // + ("no-batch", bpo::value<bool>()->zero_tokens()->default_value(false), "force gui processing mode") // // + ("no-cleanup", bpo::value<bool>()->zero_tokens()->default_value(false), "do not cleanup the shm segment") // // + ("hostname", bpo::value<std::string>()->default_value("localhost"), "hostname to deploy") // // + ("resources", bpo::value<std::string>()->default_value(""), "resources allocated for the workflow") // // + ("start-port,p", bpo::value<unsigned short>()->default_value(22000), "start port to allocate") // // + ("port-range,pr", bpo::value<unsigned short>()->default_value(1000), "ports in range") // // + ("completion-policy,c", bpo::value<TerminationPolicy>(&policy)->default_value(TerminationPolicy::QUIT), // // + "what to do when processing is finished: quit, wait") // // + ("error-policy", bpo::value<TerminationPolicy>(&errorPolicy)->default_value(TerminationPolicy::QUIT), // // + "what to do when a device has an error: quit, wait") // // + ("min-failure-level", bpo::value<LogParsingHelpers::LogLevel>(&minFailureLevel)->default_value(LogParsingHelpers::LogLevel::Fatal), // // + "minimum message level which will be considered as fatal and exit with 1") // // + ("graphviz,g", bpo::value<bool>()->zero_tokens()->default_value(false), "produce graph output") // // + ("timeout,t", bpo::value<uint64_t>()->default_value(0), "forced exit timeout (in seconds)") // // + ("dds,D", bpo::value<bool>()->zero_tokens()->default_value(false), "create DDS configuration") // // + ("dump-workflow,dump", bpo::value<bool>()->zero_tokens()->default_value(false), "dump workflow as JSON") // // + ("dump-workflow-file", bpo::value<std::string>()->default_value("-"), "file to which do the dump") // // + ("run", bpo::value<bool>()->zero_tokens()->default_value(false), "run workflow merged so far") // // + ("no-IPC", bpo::value<bool>()->zero_tokens()->default_value(false), "disable IPC topology optimization") // // + ("o2-control,o2", bpo::value<std::string>()->default_value(""), "dump O2 Control workflow configuration under the specified name") // + ("resources-monitoring", bpo::value<unsigned short>()->default_value(0), "enable cpu/memory monitoring for provided interval in seconds") // + ("resources-monitoring-dump-interval", bpo::value<unsigned short>()->default_value(0), "dump monitoring information to disk every provided seconds"); // // some of the options must be forwarded by default to the device executorOptions.add(DeviceSpecHelpers::getForwardedDeviceOptions()); @@ -1656,9 +2408,14 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, } std::vector<DataProcessorInfo> dataProcessorInfos; - if (isatty(STDIN_FILENO) == false) { + CommandInfo commandInfo{}; + + if (isatty(STDIN_FILENO) == false && isInputConfig()) { std::vector<DataProcessorSpec> importedWorkflow; - WorkflowSerializationHelpers::import(std::cin, importedWorkflow, dataProcessorInfos); + bool previousWorked = WorkflowSerializationHelpers::import(std::cin, importedWorkflow, dataProcessorInfos, commandInfo); + if (previousWorked == false) { + exit(1); + } size_t workflowHashB = 0; for (auto& dp : importedWorkflow) { @@ -1700,22 +2457,24 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, [](OutputSpec const& a, OutputSpec const& b) { return DataSpecUtils::describe(a) < DataSpecUtils::describe(b); }); } - // check if DataProcessorSpec at i depends on j - auto checkDependencies = [& workflow = physicalWorkflow](int i, int j) { - DataProcessorSpec const& a = workflow[i]; - DataProcessorSpec const& b = workflow[j]; - for (size_t ii = 0; ii < a.inputs.size(); ++ii) { - for (size_t oi = 0; oi < b.outputs.size(); ++oi) { - try { - if (DataSpecUtils::match(a.inputs[ii], b.outputs[oi])) { - return true; - } - } catch (...) { - continue; - } + std::vector<TopologyPolicy> topologyPolicies = TopologyPolicy::createDefaultPolicies(); + std::vector<TopologyPolicy::DependencyChecker> dependencyCheckers; + dependencyCheckers.reserve(physicalWorkflow.size()); + + for (auto& spec : physicalWorkflow) { + for (auto& policy : topologyPolicies) { + if (policy.matcher(spec)) { + dependencyCheckers.push_back(policy.checkDependency); + break; } } - return false; + } + assert(dependencyCheckers.size() == physicalWorkflow.size()); + // check if DataProcessorSpec at i depends on j + auto checkDependencies = [&workflow = physicalWorkflow, + &dependencyCheckers](int i, int j) { + TopologyPolicy::DependencyChecker& checker = dependencyCheckers[i]; + return checker(workflow[i], workflow[j]); }; // Create a list of all the edges, so that we can do a topological sort @@ -1788,7 +2547,7 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, .run(), varmap); } catch (std::exception const& e) { - std::cerr << "Error: " << e.what() << std::endl; + LOGP(ERROR, "error parsing options of {}: {}", argv[0], e.what()); exit(1); } conflicting_options(varmap, "dds", "o2-control"); @@ -1801,6 +2560,7 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, conflicting_options(varmap, "run", "dump-workflow"); conflicting_options(varmap, "run", "graphviz"); conflicting_options(varmap, "dump-workflow", "graphviz"); + conflicting_options(varmap, "no-batch", "batch"); if (varmap.count("help")) { printHelp(varmap, executorOptions, physicalWorkflow, currentWorkflowOptions); @@ -1816,9 +2576,10 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, driverInfo.channelPolicies = channelPolicies; driverInfo.completionPolicies = completionPolicies; driverInfo.dispatchPolicies = dispatchPolicies; + driverInfo.resourcePolicies = resourcePolicies; driverInfo.argc = argc; driverInfo.argv = argv; - driverInfo.batch = varmap["batch"].as<bool>(); + driverInfo.batch = varmap["no-batch"].defaulted() ? varmap["batch"].as<bool>() : false; driverInfo.noSHMCleanup = varmap["no-cleanup"].as<bool>(); driverInfo.terminationPolicy = varmap["completion-policy"].as<TerminationPolicy>(); if (varmap["error-policy"].defaulted() && driverInfo.batch == false) { @@ -1826,28 +2587,35 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, } else { driverInfo.errorPolicy = varmap["error-policy"].as<TerminationPolicy>(); } + driverInfo.minFailureLevel = varmap["min-failure-level"].as<LogParsingHelpers::LogLevel>(); driverInfo.startTime = uv_hrtime(); driverInfo.timeout = varmap["timeout"].as<uint64_t>(); driverInfo.deployHostname = varmap["hostname"].as<std::string>(); driverInfo.resources = varmap["resources"].as<std::string>(); driverInfo.resourcesMonitoringInterval = varmap["resources-monitoring"].as<unsigned short>(); + driverInfo.resourcesMonitoringDumpInterval = varmap["resources-monitoring-dump-interval"].as<unsigned short>(); // FIXME: should use the whole dataProcessorInfos, actually... driverInfo.processorInfo = dataProcessorInfos; driverInfo.configContext = &configContext; + commandInfo.merge(CommandInfo(argc, argv)); + std::string frameworkId; // If the id is set, this means this is a device, // otherwise this is the driver. if (varmap.count("id")) { frameworkId = varmap["id"].as<std::string>(); driverInfo.uniqueWorkflowId = fmt::format("{}", getppid()); + driverInfo.defaultDriverClient = "stdout://"; } else { driverInfo.uniqueWorkflowId = fmt::format("{}", getpid()); + driverInfo.defaultDriverClient = "ws://"; } return runStateMachine(physicalWorkflow, currentWorkflow, dataProcessorInfos, + commandInfo, driverControl, driverInfo, gDeviceMetricsInfos, @@ -1855,8 +2623,8 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, frameworkId); } -void doBoostException(boost::exception& e) +void doBoostException(boost::exception& e, char const* processName) { - LOG(ERROR) << "error while setting up workflow: \n" - << boost::current_exception_diagnostic_information(true); + LOGP(ERROR, "error while setting up workflow in {}: {}", + processName, boost::current_exception_diagnostic_information(true)); } diff --git a/Framework/Core/src/verifyAODFile.cxx b/Framework/Core/src/verifyAODFile.cxx index 6c4d8aa23f163..7301ccbc95cc1 100644 --- a/Framework/Core/src/verifyAODFile.cxx +++ b/Framework/Core/src/verifyAODFile.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,8 +47,8 @@ int main(int argc, char** argv) verifyTable<o2::aod::Collisions>(infile.get(), "O2collision"); verifyTable<o2::aod::StoredTracks>(infile.get(), "O2track"); verifyTable<o2::aod::StoredTracksCov>(infile.get(), "O2track"); - verifyTable<o2::aod::TracksExtra>(infile.get(), "O2track"); + verifyTable<o2::aod::StoredTracksExtra>(infile.get(), "O2track"); verifyTable<o2::aod::Calos>(infile.get(), "O2calo"); - verifyTable<o2::aod::StoredMuons>(infile.get(), "O2muon"); + verifyTable<o2::aod::StoredFwdTracks>(infile.get(), "O2fwdtrack"); return 0; } diff --git a/Framework/Core/test/FrameworkCoreTestLinkDef.h b/Framework/Core/test/FrameworkCoreTestLinkDef.h index e7aa30ec99193..aed39406da87c 100644 --- a/Framework/Core/test/FrameworkCoreTestLinkDef.h +++ b/Framework/Core/test/FrameworkCoreTestLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,3 +19,9 @@ #pragma link C++ class o2::test::SimplePODClass + ; #pragma link C++ class std::vector < o2::test::TriviallyCopyable > +; #pragma link C++ class std::vector < o2::test::Polymorphic > +; + +#pragma link C++ class StepTHn + ; +#pragma link C++ class StepTHnT < TArrayF> + ; +#pragma link C++ class StepTHnT < TArrayD> + ; +#pragma link C++ typedef StepTHnF; +#pragma link C++ typedef StepTHnD; diff --git a/Framework/Core/test/Mocking.h b/Framework/Core/test/Mocking.h new file mode 100644 index 0000000000000..5387290dcae0e --- /dev/null +++ b/Framework/Core/test/Mocking.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "test_HelperMacros.h" +#include "Framework/ConfigContext.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/SimpleOptionsRetriever.h" +#include "Framework/WorkflowCustomizationHelpers.h" +#include "Framework/ChannelConfigurationPolicy.h" + +std::unique_ptr<o2::framework::ConfigContext> makeEmptyConfigContext() +{ + using namespace o2::framework; + // FIXME: Ugly... We need to fix ownership and make sure the ConfigContext + // either owns or shares ownership of the registry. + std::vector<std::unique_ptr<ParamRetriever>> retrievers; + static std::vector<ConfigParamSpec> specs = WorkflowCustomizationHelpers::requiredWorkflowOptions(); + auto store = std::make_unique<ConfigParamStore>(specs, std::move(retrievers)); + store->preload(); + store->activate(); + static ConfigParamRegistry registry(std::move(store)); + auto context = std::make_unique<ConfigContext>(registry, 0, nullptr); + return context; +} + +using namespace o2::framework; + +std::vector<ChannelConfigurationPolicy> makeTrivialChannelPolicies(ConfigContext const& configContext) +{ + ChannelConfigurationPolicy defaultPolicy; + FairMQChannelConfigSpec spec; + spec.rateLogging = 0; + spec.recvBufferSize = 1; + spec.sendBufferSize = 1; + spec.ipcPrefix = "@"; + + defaultPolicy.match = ChannelConfigurationPolicyHelpers::matchAny; + defaultPolicy.modifyInput = ChannelConfigurationPolicyHelpers::pullInput(spec); + defaultPolicy.modifyOutput = ChannelConfigurationPolicyHelpers::pushOutput(spec); + + return {defaultPolicy}; +} diff --git a/Framework/Core/test/TestClasses.cxx b/Framework/Core/test/TestClasses.cxx index 8bcbe41103afd..777110423e670 100644 --- a/Framework/Core/test/TestClasses.cxx +++ b/Framework/Core/test/TestClasses.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/TestClasses.h b/Framework/Core/test/TestClasses.h index 8c6cd9e304dc3..4f03c59b2d8ef 100644 --- a/Framework/Core/test/TestClasses.h +++ b/Framework/Core/test/TestClasses.h @@ -1,20 +1,20 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_TEST_CLASSES_H -#define FRAMEWORK_TEST_CLASSES_H +#ifndef O2_FRAMEWORK_TEST_CLASSES_H_ +#define O2_FRAMEWORK_TEST_CLASSES_H_ #include <Rtypes.h> +#include "Framework/OutputSpec.h" -namespace o2 -{ -namespace test +namespace o2::test { class TriviallyCopyable @@ -84,6 +84,5 @@ class SimplePODClass ClassDefNV(SimplePODClass, 1); }; -} // namespace test -} // namespace o2 -#endif // FRAMEWORK_TEST_CLASSES_H +} // namespace o2::test +#endif // O2_FRAMEWORK_TEST_CLASSES_H_ diff --git a/Framework/Core/test/benchmark_ASoA.cxx b/Framework/Core/test/benchmark_ASoA.cxx index 941187159c9cb..b0fa78b855d11 100644 --- a/Framework/Core/test/benchmark_ASoA.cxx +++ b/Framework/Core/test/benchmark_ASoA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/benchmark_ASoAHelpers.cxx b/Framework/Core/test/benchmark_ASoAHelpers.cxx index 4c8bb53a0c0b9..59775bf02ff01 100644 --- a/Framework/Core/test/benchmark_ASoAHelpers.cxx +++ b/Framework/Core/test/benchmark_ASoAHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -579,9 +580,9 @@ static void BM_ASoAHelpersCombGenCollisionsPairsSameCategories(benchmark::State& uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), uniform_dist_int(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist_int(e1)); + uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); @@ -616,9 +617,9 @@ static void BM_ASoAHelpersCombGenCollisionsFivesSameCategories(benchmark::State& uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), uniform_dist_int(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist_int(e1)); + uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); @@ -653,9 +654,9 @@ static void BM_ASoAHelpersCombGenCollisionsPairsCategories(benchmark::State& sta uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), uniform_dist_int(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist_int(e1)); + uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); @@ -690,9 +691,9 @@ static void BM_ASoAHelpersCombGenCollisionsFivesCategories(benchmark::State& sta uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), uniform_dist_int(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist_int(e1)); + uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); diff --git a/Framework/Core/test/benchmark_DataDescriptorMatcher.cxx b/Framework/Core/test/benchmark_DataDescriptorMatcher.cxx index 1a6d38c6e3ee7..d195a46e46c4f 100644 --- a/Framework/Core/test/benchmark_DataDescriptorMatcher.cxx +++ b/Framework/Core/test/benchmark_DataDescriptorMatcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/benchmark_DataRelayer.cxx b/Framework/Core/test/benchmark_DataRelayer.cxx index 2770b22745809..1bc215ac015b8 100644 --- a/Framework/Core/test/benchmark_DataRelayer.cxx +++ b/Framework/Core/test/benchmark_DataRelayer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,7 +37,7 @@ static void BM_RelayMessageCreation(benchmark::State& state) InputRoute{spec, 0, "Fake", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -77,7 +78,7 @@ static void BM_RelaySingleSlot(benchmark::State& state) InputRoute{spec, 0, "Fake", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -102,7 +103,7 @@ static void BM_RelaySingleSlot(benchmark::State& state) memcpy(header->GetData(), stack.data(), stack.size()); //state.ResumeTiming(); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); assert(ready.size() == 1); @@ -127,7 +128,7 @@ static void BM_RelayMultipleSlots(benchmark::State& state) InputRoute{spec, 0, "Fake", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -155,7 +156,7 @@ static void BM_RelayMultipleSlots(benchmark::State& state) memcpy(header->GetData(), stack.data(), stack.size()); //state.ResumeTiming(); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); assert(ready.size() == 1); @@ -181,7 +182,7 @@ static void BM_RelayMultipleRoutes(benchmark::State& state) InputRoute{spec2, 1, "Fake2", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -223,13 +224,13 @@ static void BM_RelayMultipleRoutes(benchmark::State& state) memcpy(header2->GetData(), stack2.data(), stack2.size()); //state.ResumeTiming(); - relayer.relay(std::move(header1), std::move(payload1)); + relayer.relay(header1, payload1); std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); assert(ready.size() == 1); assert(ready[0].op == CompletionPolicy::CompletionOp::Consume); - relayer.relay(std::move(header2), std::move(payload2)); + relayer.relay(header2, payload2); ready.clear(); relayer.getReadyToProcess(ready); assert(ready.size() == 1); @@ -244,4 +245,62 @@ static void BM_RelayMultipleRoutes(benchmark::State& state) BENCHMARK(BM_RelayMultipleRoutes); +/// In this case we have a record with two entries +static void BM_RelaySplitParts(benchmark::State& state) +{ + Monitoring metrics; + InputSpec spec1{"clusters", "TPC", "CLUSTERS"}; + + std::vector<InputRoute> inputs = { + InputRoute{spec1, 0, "Fake1", 0}, + }; + + std::vector<ForwardRoute> forwards; + TimesliceIndex index{1}; + + auto policy = CompletionPolicyHelpers::consumeWhenAny(); + DataRelayer relayer(policy, inputs, metrics, index); + relayer.setPipelineLength(4); + + // Let's create a dummy O2 Message with two headers in the stack: + // - DataHeader matching the one provided in the input + DataHeader dh1; + dh1.dataDescription = "CLUSTERS"; + dh1.dataOrigin = "TPC"; + dh1.subSpecification = 0; + + auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); + size_t timeslice = 0; + + for (auto _ : state) { + // FIXME: Understand why pausing the timer makes it slower.. + state.PauseTiming(); + std::vector<std::unique_ptr<FairMQMessage>> splitParts; + + for (size_t i = 0; i < 100; ++i) { + DataProcessingHeader dph1{timeslice, 1}; + dh1.splitPayloadIndex = i; + dh1.splitPayloadParts = 10; + Stack stack1{dh1, dph1}; + + FairMQMessagePtr header1 = transport->CreateMessage(stack1.size()); + FairMQMessagePtr payload1 = transport->CreateMessage(100); + + memcpy(header1->GetData(), stack1.data(), stack1.size()); + splitParts.emplace_back(std::move(header1)); + splitParts.emplace_back(std::move(payload1)); + } + state.ResumeTiming(); + + relayer.relay(splitParts[0], &splitParts[1], splitParts.size() - 1); + std::vector<RecordAction> ready; + relayer.getReadyToProcess(ready); + assert(ready.size() == 1); + assert(ready[0].op == CompletionPolicy::CompletionOp::Consume); + } + // One for the header, one for the payload +} + +BENCHMARK(BM_RelaySplitParts); + BENCHMARK_MAIN(); diff --git a/Framework/Core/test/benchmark_DeviceMetricsInfo.cxx b/Framework/Core/test/benchmark_DeviceMetricsInfo.cxx index d355de1a21645..2518ec3ab748d 100644 --- a/Framework/Core/test/benchmark_DeviceMetricsInfo.cxx +++ b/Framework/Core/test/benchmark_DeviceMetricsInfo.cxx @@ -1,13 +1,15 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/DeviceMetricsInfo.h" +#include "Framework/DeviceMetricsHelper.h" #include <benchmark/benchmark.h> #include <regex> diff --git a/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx new file mode 100644 index 0000000000000..3cf7ec51cff1e --- /dev/null +++ b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx @@ -0,0 +1,333 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ExternalFairMQDeviceProxy.h" + +using namespace o2::framework; + +#include "Framework/AlgorithmSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ChannelSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ExternalFairMQDeviceProxy.h" +#include "Framework/ControlService.h" +#include "Framework/CallbackService.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" +#include "Headers/DataHeader.h" +#include "fairmq/FairMQDevice.h" +#include <chrono> + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "default-transport", VariantType::String, "shmem", {"default transport: shmem, zeromq"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "nChannels", VariantType::Int, 1, {"number of output channels of the producer"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "msgSize", VariantType::Int, 1024, {"message size in kB"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "runningTime", VariantType::Int, 30, {"time to run the workflow"}}); +} + +#include "Framework/runDataProcessing.h" + +using benchclock = std::chrono::high_resolution_clock; + +#define ASSERT_ERROR(condition) \ + if ((condition) == false) { \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ + } + +std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) +{ + std::string defaultTransportConfig = config.options().get<std::string>("default-transport"); + if (defaultTransportConfig == "zeromq") { + // nothing to do for the moment + } else if (defaultTransportConfig == "shmem") { + // nothing to do for the moment + } else { + throw std::runtime_error("invalid argument for option --default-transport : '" + defaultTransportConfig + "'"); + } + std::vector<DataProcessorSpec> workflow; + + struct BenchmarkState { + size_t msgSize = 1024 * 1024; + size_t nChannels = 1; + size_t logPeriod = 2; + size_t runningTime = 30; + size_t counter = 0; + size_t totalCount = 0; + benchclock::time_point startTime = benchclock::now(); + benchclock::time_point idleTime = benchclock::now(); + benchclock::time_point lastLogTime = benchclock::now(); + float maxMsgPerSec = .0; + float maxDataRatePerSec = .0; + float totalIdleTime = .0; + float maxIdleTime = .0; + }; + + auto makeBenchmarkState = [&config]() -> std::shared_ptr<BenchmarkState> { + auto state = std::make_shared<BenchmarkState>(); + state->msgSize = 1024 * config.options().get<int>("msgSize"); + state->nChannels = config.options().get<int>("nChannels"); + state->runningTime = config.options().get<int>("runningTime"); + return state; + }; + + auto loggerInit = [](BenchmarkState& state) { + state.startTime = benchclock::now(); + state.idleTime = benchclock::now(); + state.lastLogTime = benchclock::now(); + state.totalIdleTime = 0.; + }; + + auto loggerCycle = [](BenchmarkState& state) { + ++state.counter; + auto secSinceLastLog = std::chrono::duration_cast<std::chrono::seconds>(benchclock::now() - state.lastLogTime); + if (secSinceLastLog.count() >= state.logPeriod) { + // TODO: introduce real counters for accumulated number of messages and message size + state.totalCount += state.counter; + float eventRate = state.counter / secSinceLastLog.count(); + float msgPerSec = eventRate * state.nChannels; + float kbPerSec = msgPerSec * state.msgSize / 1024; + auto elapsedTime = std::chrono::duration_cast<std::chrono::seconds>(benchclock::now() - state.startTime); + LOG(info) << fmt::format( + "{: 3d} Total messages: {} - Event rate {:.2f} Hz {:.2f} msg/s {:.2f} MB/s, " + "Accumulated idle time {:.2f} ms", + elapsedTime.count(), state.totalCount, eventRate, msgPerSec, + kbPerSec / 1024, state.totalIdleTime / 1000); + if (state.maxMsgPerSec < msgPerSec) { + state.maxMsgPerSec = msgPerSec; + } + if (state.maxDataRatePerSec < kbPerSec) { + state.maxDataRatePerSec = kbPerSec; + } + state.counter = 0; + state.lastLogTime = benchclock::now(); + } + }; + + struct ActiveGuard { + ActiveGuard(BenchmarkState& _state) : state(_state) + { + auto idleTime = std::chrono::duration_cast<std::chrono::microseconds>(benchclock::now() - state.idleTime); + state.totalIdleTime += idleTime.count(); + } + ~ActiveGuard() + { + state.idleTime = benchclock::now(); + } + BenchmarkState& state; + }; + + auto loggerSummary = [](BenchmarkState& state) { + auto totalTime = std::chrono::duration_cast<std::chrono::seconds>(benchclock::now() - state.startTime); + float eventRate = state.totalCount / totalTime.count(); + float msgPerSec = eventRate * state.nChannels; + float kbPerSec = msgPerSec * state.msgSize / 1024; + LOG(info) << fmt::format( + "Benchmarking " +#ifndef NDEBUG + "accumulated " +#endif + "for {} s: Avrg event rate {:.2f} Hz, " + "Avrg message rate {:.2f}/s (max {:.2f}/s), Avrg data rate {:.2f} MB/s (max {:.2f} MB/s), " + "Avrg idle time {:.2f} ms", + totalTime.count(), eventRate, + msgPerSec, state.maxMsgPerSec, + kbPerSec / 1024, state.maxDataRatePerSec / 1024, + state.totalIdleTime / (state.totalCount * 1000)); + }; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // a producer process steered by a timer + // + // the compute callback of the producer + auto pState = makeBenchmarkState(); + auto producerInitCallback = [pState, loggerInit, loggerCycle, loggerSummary](CallbackService& callbacks) { + auto producerBenchInit = [pState, loggerInit]() { + loggerInit(*pState); + }; + callbacks.set(CallbackService::Id::Start, producerBenchInit); + auto producerCallback = [pState, loggerCycle, loggerSummary](DataAllocator& outputs, ControlService& control) { + auto& state = *pState; + ActiveGuard g(state); + for (unsigned int i = 0; i < state.nChannels; i++) { + outputs.make<char>(OutputRef{"data", i}, state.msgSize); + } + loggerCycle(*pState); + auto elapsedTime = std::chrono::duration_cast<std::chrono::seconds>(benchclock::now() - state.startTime); + if (elapsedTime.count() >= state.runningTime) { + loggerSummary(*pState); + // send the end of stream signal, this is transferred by the proxies + // and allows to properly terminate downstream devices + control.endOfStream(); + } + }; + + return adaptStateless(producerCallback); + }; + + Outputs outputs; + for (unsigned int i = 0; i < pState->nChannels; i++) { + outputs.emplace_back(OutputSpec{{"data"}, "TST", "DATA", i, Lifetime::Timeframe}); + } + workflow.emplace_back(DataProcessorSpec{"producer", + {}, + {std::move(outputs)}, + AlgorithmSpec{adaptStateful(producerInitCallback)}, + {}}); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // the dpl sink proxy process + + // use the OutputChannelSpec as a tool to create the default configuration for the out-of-band channel + OutputChannelSpec externalChannelSpec; + // Note: the name is hardcoded for now + externalChannelSpec.name = "downstream"; + externalChannelSpec.type = ChannelType::Push; + externalChannelSpec.method = ChannelMethod::Bind; + externalChannelSpec.hostname = "localhost"; + externalChannelSpec.port = 42042; + externalChannelSpec.listeners = 0; + externalChannelSpec.rateLogging = 10; + externalChannelSpec.sendBufferSize = 1000; + externalChannelSpec.recvBufferSize = 1000; + if (!defaultTransportConfig.empty()) { + if (defaultTransportConfig == "zeromq") { + externalChannelSpec.protocol = ChannelProtocol::Network; + } else if (defaultTransportConfig == "shmem") { + externalChannelSpec.protocol = ChannelProtocol::IPC; + } + } + std::string channelConfig = formatExternalChannelConfiguration(externalChannelSpec); + // at some point the formatting tool might add the transport as well so we have to check + if (!defaultTransportConfig.empty() && defaultTransportConfig.find("transport=") == std::string::npos) { + channelConfig += ",transport=" + defaultTransportConfig; + } + + Inputs sinkInputs; + for (unsigned int i = 0; i < pState->nChannels; i++) { + sinkInputs.emplace_back(InputSpec{{"external"}, "TST", "DATA", i, Lifetime::Timeframe}); + } + auto channelSelector = [](InputSpec const&, const std::unordered_map<std::string, std::vector<FairMQChannel>>&) -> std::string { + return "downstream"; + }; + workflow.emplace_back(std::move(specifyFairMQDeviceOutputProxy("dpl-sink", sinkInputs, channelConfig.c_str()))); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // a simple checker process subscribing to the output of the input proxy + // + // the compute callback of the checker + auto cState = makeBenchmarkState(); + auto checkerCallback = [cState, loggerCycle](InputRecord& inputs) { + ActiveGuard g(*cState); + LOG(DEBUG) << "got inputs " << inputs.size(); + for (auto const& ref : InputRecordWalker(inputs)) { + auto data = inputs.get<gsl::span<char>>(ref); + } + loggerCycle(*cState); + }; + auto checkerBenchInit = [cState, loggerInit]() { + loggerInit(*cState); + }; + auto checkerBenchSummary = [cState, loggerSummary](EndOfStreamContext&) { + loggerSummary(*cState); + }; + auto checkerInit = [checkerCallback, checkerBenchInit, checkerBenchSummary](CallbackService& callbacks) { + callbacks.set(CallbackService::Id::Start, checkerBenchInit); + callbacks.set(CallbackService::Id::EndOfStream, checkerBenchSummary); + return adaptStateless(checkerCallback); + }; + + // the checker process connects to the proxy + workflow.emplace_back(DataProcessorSpec{"checker", + {InputSpec{"datain", ConcreteDataTypeMatcher{"PRX", "DATA"}, Lifetime::Timeframe}}, + {}, + AlgorithmSpec{adaptStateful(checkerInit)}}); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // the input proxy process + // reads the messages from the output proxy via the out-of-band channel + + // converter callback for the external FairMQ device proxy ProcessorSpec generator + auto converter = [](FairMQDevice& device, FairMQParts& inputs, ChannelRetriever channelRetriever) { + ASSERT_ERROR(inputs.Size() >= 2); + if (inputs.Size() < 2) { + return; + } + int msgidx = 0; + auto dh = o2::header::get<o2::header::DataHeader*>(inputs.At(msgidx)->GetData()); + if (!dh) { + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; + return; + } + auto dph = o2::header::get<DataProcessingHeader*>(inputs.At(msgidx)->GetData()); + if (!dph) { + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; + return; + } + // Note: we want to run both the output and input proxy in the same workflow and thus we need + // different data identifiers and change the data origin in the forwarding + OutputSpec query{"PRX", dh->dataDescription, dh->subSpecification}; + auto channelName = channelRetriever(query, dph->startTime); + bool isData = DataSpecUtils::match(OutputSpec{"TST", "DATA", 0}, dh->dataOrigin, dh->dataDescription, dh->subSpecification); + // for the configured data channel we require the channel name, the EOS message containing + // the forwarded SourceInfoHeader created by the output proxy will be skipped here since the + // input proxy handles this internally + ASSERT_ERROR(!isData || !channelName.empty()); + LOG(DEBUG) << "using channel '" << channelName << "' for " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}); + if (channelName.empty()) { + return; + } + // make a copy of the header message, get the data header and change origin + auto outHeaderMessage = device.NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); + memcpy(outHeaderMessage->GetData(), inputs.At(msgidx)->GetData(), inputs.At(msgidx)->GetSize()); + // this we obviously need to fix in the get API, const'ness of the returned header pointer + // should depend on const'ness of the buffer + auto odh = const_cast<o2::header::DataHeader*>(o2::header::get<o2::header::DataHeader*>(outHeaderMessage->GetData())); + odh->dataOrigin = o2::header::DataOrigin("PRX"); + FairMQParts output; + output.AddPart(std::move(outHeaderMessage)); + output.AddPart(std::move(inputs.At(msgidx + 1))); + LOG(DEBUG) << "sending " << DataSpecUtils::describe(OutputSpec{odh->dataOrigin, odh->dataDescription, odh->subSpecification}); + o2::framework::sendOnChannel(device, output, channelName); + }; + + // we use the same spec to build the configuration string, ideally we would have some helpers + // which convert an OutputChannelSpec to an InputChannelSpec replacing 'bind' <--> 'connect' + // and 'push' <--> 'pull' + // + // skip the name in the configuration string as it is added in specifyExternalFairMQDeviceProxy + externalChannelSpec.name = ""; + externalChannelSpec.type = ChannelType::Pull; + externalChannelSpec.method = ChannelMethod::Connect; + channelConfig = formatExternalChannelConfiguration(externalChannelSpec); + if (!defaultTransportConfig.empty() && defaultTransportConfig.find("transport=") == std::string::npos) { + channelConfig += ",transport=" + defaultTransportConfig; + } + + // Note: in order to make the DPL output proxy and an input proxy working in the same + // workflow, we use different data description + Outputs inputProxyOutputs = {OutputSpec{ConcreteDataTypeMatcher{"PRX", "DATA"}, Lifetime::Timeframe}}; + workflow.emplace_back(specifyExternalFairMQDeviceProxy( + "input-proxy", + std::move(inputProxyOutputs), + channelConfig.c_str(), + converter)); + + return workflow; +} diff --git a/Framework/Core/test/benchmark_GandivaExpressions.cxx b/Framework/Core/test/benchmark_GandivaExpressions.cxx index 053b3eff2019a..2715afc9226ba 100644 --- a/Framework/Core/test/benchmark_GandivaExpressions.cxx +++ b/Framework/Core/test/benchmark_GandivaExpressions.cxx @@ -1,19 +1,19 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/Expressions.h" -#include "../src/ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" -#include "../src/ExpressionHelpers.h" #include <benchmark/benchmark.h> #include <random> diff --git a/Framework/Core/test/benchmark_HistogramRegistry.cxx b/Framework/Core/test/benchmark_HistogramRegistry.cxx index 009d7eb35e462..aec1cfa9c8aaf 100644 --- a/Framework/Core/test/benchmark_HistogramRegistry.cxx +++ b/Framework/Core/test/benchmark_HistogramRegistry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,7 +37,7 @@ static void BM_HashedNameLookup(benchmark::State& state) state.ResumeTiming(); for (auto i = 0; i < nLookups; ++i) { - auto& x = registry.get<TH1>("histo4"); + auto x = registry.get<TH1>(HIST("histo4")); benchmark::DoNotOptimize(x); } state.counters["Average lookup distance"] = ((double)registry.lookup / (double)(state.range(0))); diff --git a/Framework/Core/test/benchmark_InputRecord.cxx b/Framework/Core/test/benchmark_InputRecord.cxx index 7a50f1f7a78c2..d971712d410dd 100644 --- a/Framework/Core/test/benchmark_InputRecord.cxx +++ b/Framework/Core/test/benchmark_InputRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "Framework/DataRelayer.h" #include "Framework/DataProcessingHeader.h" #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include <Monitoring/Monitoring.h> #include <fairmq/FairMQTransportFactory.h> #include <cstring> @@ -45,7 +47,8 @@ static void BM_InputRecordGenericGetters(benchmark::State& state) createRoute("z_source", spec3)}; // First of all we test if an empty registry behaves as expected, raising a // bunch of exceptions. - InputRecord emptyRecord(schema, {[](size_t) { return DataRef{nullptr, nullptr, nullptr}; }, 0}); + InputSpan span{[](size_t) { return DataRef{nullptr, nullptr, nullptr}; }, 0}; + InputRecord emptyRecord(schema, span); std::vector<void*> inputs; @@ -78,8 +81,8 @@ static void BM_InputRecordGenericGetters(benchmark::State& state) createMessage(dh1, 1); createMessage(dh2, 2); createEmpty(); - InputSpan span{[&inputs](size_t i) { return DataRef{nullptr, static_cast<char const*>(inputs[2 * i]), static_cast<char const*>(inputs[2 * i + 1])}; }, inputs.size() / 2}; - InputRecord record{schema, std::move(span)}; + InputSpan span2{[&inputs](size_t i) { return DataRef{nullptr, static_cast<char const*>(inputs[2 * i]), static_cast<char const*>(inputs[2 * i + 1])}; }, inputs.size() / 2}; + InputRecord record{schema, span2}; for (auto _ : state) { // Checking we can get the whole ref by name diff --git a/Framework/Core/test/benchmark_TableBuilder.cxx b/Framework/Core/test/benchmark_TableBuilder.cxx index e79d66f31da4a..25ebd7f780d71 100644 --- a/Framework/Core/test/benchmark_TableBuilder.cxx +++ b/Framework/Core/test/benchmark_TableBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/benchmark_TableToTree.cxx b/Framework/Core/test/benchmark_TableToTree.cxx index 378c1db01c40f..0a7963518f00b 100644 --- a/Framework/Core/test/benchmark_TableToTree.cxx +++ b/Framework/Core/test/benchmark_TableToTree.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -61,9 +62,8 @@ static void BM_TableToTree(benchmark::State& state) // benchmark TableToTree TableToTree ta2tr(table, &fout, "table2tree"); - if (ta2tr.addAllBranches()) { - ta2tr.process(); - } + ta2tr.addAllBranches(); + ta2tr.process(); // clean up fout.Close(); diff --git a/Framework/Core/test/benchmark_TreeToTable.cxx b/Framework/Core/test/benchmark_TreeToTable.cxx index 381b8c09bad4a..6eca853a90ce4 100644 --- a/Framework/Core/test/benchmark_TreeToTable.cxx +++ b/Framework/Core/test/benchmark_TreeToTable.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -73,13 +74,11 @@ static void BM_TreeToTable(benchmark::State& state) // benchmark TreeToTable if (tr) { tr2ta = new TreeToTable; - if (tr2ta->addAllColumns(tr)) { - tr2ta->fill(tr); - auto ta = tr2ta->finalize(); - } - + tr2ta->addAllColumns(tr); + tr2ta->fill(tr); + auto ta = tr2ta->finalize(); } else { - LOG(INFO) << "tree is empty!"; + LOG(info) << "tree is empty!"; } // clean up diff --git a/Framework/Core/test/benchmark_WorkflowHelpers.cxx b/Framework/Core/test/benchmark_WorkflowHelpers.cxx index 2eb8f15dea25f..f1c070d8a0f4e 100644 --- a/Framework/Core/test/benchmark_WorkflowHelpers.cxx +++ b/Framework/Core/test/benchmark_WorkflowHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,7 +57,9 @@ static void BM_CreateGraphOverhead(benchmark::State& state) std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; - WorkflowHelpers::verifyWorkflow(workflow); + if (WorkflowHelpers::verifyWorkflow(workflow) != WorkflowParsingState::Valid) { + throw std::runtime_error("invalid workflow"); + }; auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); WorkflowHelpers::constructGraph(workflow, @@ -92,7 +95,9 @@ static void BM_CreateGraphReverseOverhead(benchmark::State& state) std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; - WorkflowHelpers::verifyWorkflow(workflow); + if (WorkflowHelpers::verifyWorkflow(workflow) != WorkflowParsingState::Valid) { + throw std::runtime_error("invalid workflow"); + }; auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); WorkflowHelpers::constructGraph(workflow, logicalEdges, diff --git a/Framework/Core/test/test_ASoA.cxx b/Framework/Core/test/test_ASoA.cxx index 74dc0e7706262..9d8ca82aeba6c 100644 --- a/Framework/Core/test/test_ASoA.cxx +++ b/Framework/Core/test/test_ASoA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,11 +17,12 @@ #include "Framework/ASoAHelpers.h" #include "Framework/Expressions.h" #include "Framework/AnalysisHelpers.h" -#include "../src/ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "gandiva/tree_expr_builder.h" #include "arrow/status.h" #include "gandiva/filter.h" #include <boost/test/unit_test.hpp> +#include <arrow/util/key_value_metadata.h> using namespace o2::framework; using namespace arrow; @@ -37,6 +39,7 @@ DECLARE_SOA_EXPRESSION_COLUMN(ESum, esum, int32_t, 1 * test::x + test::y); } // namespace test DECLARE_SOA_TABLE(Points, "TST", "POINTS", test::X, test::Y); +DECLARE_SOA_TABLE(Points3Ds, "TST", "PTS3D", o2::soa::Index<>, test::X, test::Y, test::Z); namespace test { @@ -49,15 +52,23 @@ DECLARE_SOA_TABLE(Infos, "TST", "INFOS", test::Color, test::SomeBool); namespace test { DECLARE_SOA_COLUMN(N, n, int); -DECLARE_SOA_INDEX_COLUMN_FULL(Info, info, int, Infos, "fInfosID"); -DECLARE_SOA_INDEX_COLUMN_FULL(PointA, pointA, int, Points, "fPointAID"); -DECLARE_SOA_INDEX_COLUMN_FULL(PointB, pointB, int, Points, "fPointBID"); +DECLARE_SOA_INDEX_COLUMN(Info, info); +DECLARE_SOA_INDEX_COLUMN_FULL(PointA, pointA, int, Points, "_A"); +DECLARE_SOA_INDEX_COLUMN_FULL(PointB, pointB, int, Points, "_B"); DECLARE_SOA_COLUMN_FULL(Thickness, thickness, int, "thickness"); } // namespace test DECLARE_SOA_TABLE(Segments, "TST", "SEGMENTS", test::N, test::PointAId, test::PointBId, test::InfoId); DECLARE_SOA_TABLE(SegmentsExtras, "TST", "SEGMENTSEX", test::Thickness); +namespace test +{ +DECLARE_SOA_COLUMN(L1, l1, std::vector<float>); +DECLARE_SOA_COLUMN(L2, l2, std::vector<int>); +} // namespace test + +DECLARE_SOA_TABLE(Lists, "TST", "LISTS", o2::soa::Index<>, test::L1, test::L2); + BOOST_AUTO_TEST_CASE(TestTableIteration) { TableBuilder builder; @@ -646,3 +657,172 @@ BOOST_AUTO_TEST_CASE(TestEmptyTables) auto spawned = Extend<Points, test::ESum>(p); BOOST_CHECK_EQUAL(spawned.size(), 0); } + +DECLARE_SOA_TABLE(Origins, "TST", "ORIG", o2::soa::Index<>, test::X, test::SomeBool); +namespace test +{ +DECLARE_SOA_INDEX_COLUMN(Origin, origin); +} +DECLARE_SOA_TABLE(References, "TST", "REFS", o2::soa::Index<>, test::OriginId); + +BOOST_AUTO_TEST_CASE(TestIndexToFiltered) +{ + TableBuilder b; + auto writer = b.cursor<Origins>(); + for (auto i = 0; i < 20; ++i) { + writer(0, i, i % 3 == 0); + } + auto origins = b.finalize(); + Origins o{origins}; + + TableBuilder w; + auto writer_w = w.cursor<References>(); + for (auto i = 0; i < 5 * 20; ++i) { + writer_w(0, i % 20); + } + auto refs = w.finalize(); + References r{refs}; + expressions::Filter flt = test::someBool == true; + using Flt = o2::soa::Filtered<Origins>; + Flt f{{o.asArrowTable()}, expressions::createSelection(o.asArrowTable(), flt)}; + r.bindExternalIndices(&f); + auto it = r.begin(); + it.moveByIndex(23); + BOOST_CHECK_EQUAL(it.origin().globalIndex(), 3); + it++; + BOOST_CHECK_EQUAL(it.origin().globalIndex(), 4); + it++; + BOOST_CHECK_EQUAL(it.origin().globalIndex(), 5); +} + +namespace test +{ +DECLARE_SOA_ARRAY_INDEX_COLUMN(Points3D, pointGroup, 3); +DECLARE_SOA_SLICE_INDEX_COLUMN(Points3D, pointSlice); +DECLARE_SOA_SELF_INDEX_COLUMN(OtherPoint, otherPoint); +} // namespace test + +DECLARE_SOA_TABLE(PointsRef, "TST", "PTSREF", test::Points3DIdSlice, test::Points3DIds); +DECLARE_SOA_TABLE(PointsSelfIndex, "TST", "PTSSLF", o2::soa::Index<>, test::X, test::Y, test::Z, test::OtherPointId); + +BOOST_AUTO_TEST_CASE(TestAdvancedIndices) +{ + TableBuilder b1; + auto pwriter = b1.cursor<Points3Ds>(); + for (auto i = 0; i < 20; ++i) { + pwriter(0, -1 * i, 0.5 * i, 2 * i); + } + auto t1 = b1.finalize(); + + TableBuilder b2; + auto prwriter = b2.cursor<PointsRef>(); + auto a = std::array{0, 1}; + auto aa = std::array{2, 3, 4}; + prwriter(0, &a[0], &aa[0]); + a = {4, 10}; + aa = {12, 2, 19}; + prwriter(0, &a[0], &aa[0]); + auto t2 = b2.finalize(); + + auto pt = Points3Ds{t1}; + auto prt = PointsRef{t2}; + prt.bindExternalIndices(&pt); + + auto it = prt.begin(); + auto s1 = it.pointSlice(); + auto g1 = it.pointGroup(); + auto bb = std::is_same_v<decltype(s1), Points3Ds>; + BOOST_CHECK(bb); + BOOST_CHECK_EQUAL(s1.size(), 2); + aa = {2, 3, 4}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL(g1[i].globalIndex(), aa[i]); + } + + ++it; + auto s2 = it.pointSlice(); + auto g2 = it.pointGroup(); + BOOST_CHECK_EQUAL(s2.size(), 7); + aa = {12, 2, 19}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL(g2[i].globalIndex(), aa[i]); + } + + using Flt = o2::soa::Filtered<Points3Ds>; + expressions::Filter flt = test::x <= -6; + Flt f{{pt.asArrowTable()}, expressions::createSelection(pt.asArrowTable(), flt)}; + prt.bindExternalIndices(&f); + + auto it2 = prt.begin(); + auto s1f = it2.pointSlice_as<Flt>(); + auto g1f = it2.pointGroup_as<Flt>(); + BOOST_CHECK_EQUAL(s1f.size(), 2); + aa = {2, 3, 4}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL(g1f[i].globalIndex(), aa[i]); + } + + ++it2; + auto s2f = it2.pointSlice_as<Flt>(); + auto g2f = it2.pointGroup_as<Flt>(); + BOOST_CHECK_EQUAL(s2f.size(), 7); + aa = {12, 2, 19}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL(g2f[i].globalIndex(), aa[i]); + } + + TableBuilder b3; + auto pswriter = b3.cursor<PointsSelfIndex>(); + int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7}; + for (auto i = 0; i < 20; ++i) { + pswriter(0, -1 * i, 0.5 * i, 2 * i, references[i]); + } + auto t3 = b3.finalize(); + auto pst = PointsSelfIndex{t3}; + pst.bindInternalIndices(); + auto i = 0; + for (auto& p : pst) { + auto op = p.otherPoint_as<PointsSelfIndex>(); + auto bbb = std::is_same_v<decltype(op), PointsSelfIndex::iterator>; + BOOST_CHECK(bbb); + BOOST_CHECK_EQUAL(op.globalIndex(), references[i]); + ++i; + } +} + +BOOST_AUTO_TEST_CASE(TestListColumns) +{ + TableBuilder b; + auto writer = b.cursor<Lists>(); + std::vector<float> floats; + std::vector<int> ints; + for (auto i = 1; i < 11; ++i) { + floats.clear(); + ints.clear(); + for (auto j = 0; j < i; ++j) { + floats.push_back(0.1231233f * (float)j + 0.1982798f); + ints.push_back(j + 10); + } + + writer(0, floats, ints); + } + auto lt = b.finalize(); + Lists tbl{lt}; + int s = 1; + for (auto& row : tbl) { + auto f = row.l1(); + auto i = row.l2(); + auto constexpr bf = std::is_same_v<decltype(f), gsl::span<const float, (size_t)-1>>; + auto constexpr bi = std::is_same_v<decltype(i), gsl::span<const int, (size_t)-1>>; + BOOST_CHECK(bf); + BOOST_CHECK(bi); + BOOST_CHECK_EQUAL(f.size(), s); + BOOST_CHECK_EQUAL(i.size(), s); + + for (auto j = 0u; j < f.size(); ++j) { + BOOST_CHECK_EQUAL(f[j], 0.1231233f * (float)j + 0.1982798f); + BOOST_CHECK_EQUAL(i[j], j + 10); + } + ++s; + } +} diff --git a/Framework/Core/test/test_ASoAHelpers.cxx b/Framework/Core/test/test_ASoAHelpers.cxx index 9fb4e598ebe63..66113c1a7c99e 100644 --- a/Framework/Core/test/test_ASoAHelpers.cxx +++ b/Framework/Core/test/test_ASoAHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_AlgorithmSpec.cxx b/Framework/Core/test/test_AlgorithmSpec.cxx index 355c100f6a8a6..b5baa70f81281 100644 --- a/Framework/Core/test/test_AlgorithmSpec.cxx +++ b/Framework/Core/test/test_AlgorithmSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_AnalysisDataModel.cxx b/Framework/Core/test/test_AnalysisDataModel.cxx index 77b4264b289db..8fed7bfd85f44 100644 --- a/Framework/Core/test/test_AnalysisDataModel.cxx +++ b/Framework/Core/test/test_AnalysisDataModel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_AnalysisTask.cxx b/Framework/Core/test/test_AnalysisTask.cxx index fb4a0e70cd13b..538072a666cb9 100644 --- a/Framework/Core/test/test_AnalysisTask.cxx +++ b/Framework/Core/test/test_AnalysisTask.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include "TestClasses.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -59,7 +61,7 @@ struct ATask { // FIXME: for the moment we do not derive from AnalysisTask as // we need GCC 7.4+ to fix a bug. struct BTask { - void process(o2::aod::Collision const&, o2::soa::Join<o2::aod::Tracks, o2::aod::TracksExtra, o2::aod::TracksCov> const&, o2::aod::UnassignedTracks const&, o2::soa::Join<o2::aod::Calos, o2::aod::CaloTriggers> const&) + void process(o2::aod::Collision const&, o2::soa::Join<o2::aod::Tracks, o2::aod::TracksExtra, o2::aod::TracksCov> const&, o2::aod::AmbiguousTracks const&, o2::soa::Join<o2::aod::Calos, o2::aod::CaloTriggers> const&) { } }; @@ -145,54 +147,57 @@ struct JTask { BOOST_AUTO_TEST_CASE(AdaptorCompilation) { - auto task1 = adaptAnalysisTask<ATask>("test1"); + auto cfgc = makeEmptyConfigContext(); + + auto task1 = adaptAnalysisTask<ATask>(*cfgc, TaskName{"test1"}); BOOST_CHECK_EQUAL(task1.inputs.size(), 2); BOOST_CHECK_EQUAL(task1.outputs.size(), 1); - BOOST_CHECK_EQUAL(task1.inputs[0].binding, std::string("TracksExtension")); - BOOST_CHECK_EQUAL(task1.inputs[1].binding, std::string("Tracks")); + BOOST_CHECK_EQUAL(task1.inputs[1].binding, std::string("TracksExtension")); + BOOST_CHECK_EQUAL(task1.inputs[0].binding, std::string("Tracks")); BOOST_CHECK_EQUAL(task1.outputs[0].binding.value, std::string("FooBars")); - auto task2 = adaptAnalysisTask<BTask>("test2"); - BOOST_CHECK_EQUAL(task2.inputs.size(), 9); - BOOST_CHECK_EQUAL(task2.inputs[0].binding, "Collisions"); - BOOST_CHECK_EQUAL(task2.inputs[1].binding, "TracksExtension"); - BOOST_CHECK_EQUAL(task2.inputs[2].binding, "Tracks"); - BOOST_CHECK_EQUAL(task2.inputs[3].binding, "TracksExtra"); - BOOST_CHECK_EQUAL(task2.inputs[4].binding, "TracksCovExtension"); + auto task2 = adaptAnalysisTask<BTask>(*cfgc, TaskName{"test2"}); + BOOST_CHECK_EQUAL(task2.inputs.size(), 10); + BOOST_CHECK_EQUAL(task2.inputs[1].binding, "CaloTriggers"); + BOOST_CHECK_EQUAL(task2.inputs[2].binding, "Calos"); + BOOST_CHECK_EQUAL(task2.inputs[3].binding, "Collisions"); + BOOST_CHECK_EQUAL(task2.inputs[4].binding, "Tracks"); BOOST_CHECK_EQUAL(task2.inputs[5].binding, "TracksCov"); - BOOST_CHECK_EQUAL(task2.inputs[6].binding, "UnassignedTracks"); - BOOST_CHECK_EQUAL(task2.inputs[7].binding, "Calos"); - BOOST_CHECK_EQUAL(task2.inputs[8].binding, "CaloTriggers"); + BOOST_CHECK_EQUAL(task2.inputs[6].binding, "TracksCovExtension"); + BOOST_CHECK_EQUAL(task2.inputs[7].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task2.inputs[8].binding, "TracksExtra"); + BOOST_CHECK_EQUAL(task2.inputs[9].binding, "TracksExtraExtension"); + BOOST_CHECK_EQUAL(task2.inputs[0].binding, "AmbiguousTracks"); - auto task3 = adaptAnalysisTask<CTask>("test3"); + auto task3 = adaptAnalysisTask<CTask>(*cfgc, TaskName{"test3"}); BOOST_CHECK_EQUAL(task3.inputs.size(), 3); BOOST_CHECK_EQUAL(task3.inputs[0].binding, "Collisions"); - BOOST_CHECK_EQUAL(task3.inputs[1].binding, "TracksExtension"); - BOOST_CHECK_EQUAL(task3.inputs[2].binding, "Tracks"); + BOOST_CHECK_EQUAL(task3.inputs[2].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task3.inputs[1].binding, "Tracks"); - auto task4 = adaptAnalysisTask<DTask>("test4"); + auto task4 = adaptAnalysisTask<DTask>(*cfgc, TaskName{"test4"}); BOOST_CHECK_EQUAL(task4.inputs.size(), 2); - BOOST_CHECK_EQUAL(task4.inputs[0].binding, "TracksExtension"); - BOOST_CHECK_EQUAL(task4.inputs[1].binding, "Tracks"); + BOOST_CHECK_EQUAL(task4.inputs[1].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task4.inputs[0].binding, "Tracks"); - auto task5 = adaptAnalysisTask<ETask>("test5"); + auto task5 = adaptAnalysisTask<ETask>(*cfgc, TaskName{"test5"}); BOOST_CHECK_EQUAL(task5.inputs.size(), 1); BOOST_CHECK_EQUAL(task5.inputs[0].binding, "FooBars"); - auto task6 = adaptAnalysisTask<FTask>("test6"); + auto task6 = adaptAnalysisTask<FTask>(*cfgc, TaskName{"test6"}); BOOST_CHECK_EQUAL(task6.inputs.size(), 1); BOOST_CHECK_EQUAL(task6.inputs[0].binding, "FooBars"); - auto task7 = adaptAnalysisTask<GTask>("test7"); + auto task7 = adaptAnalysisTask<GTask>(*cfgc, TaskName{"test7"}); BOOST_CHECK_EQUAL(task7.inputs.size(), 3); - auto task8 = adaptAnalysisTask<HTask>("test8"); + auto task8 = adaptAnalysisTask<HTask>(*cfgc, TaskName{"test8"}); BOOST_CHECK_EQUAL(task8.inputs.size(), 3); - auto task9 = adaptAnalysisTask<ITask>("test9"); + auto task9 = adaptAnalysisTask<ITask>(*cfgc, TaskName{"test9"}); BOOST_CHECK_EQUAL(task9.inputs.size(), 4); - auto task10 = adaptAnalysisTask<JTask>("test10"); + auto task10 = adaptAnalysisTask<JTask>(*cfgc, TaskName{"test10"}); } BOOST_AUTO_TEST_CASE(TestPartitionIteration) diff --git a/Framework/Core/test/test_BoostOptionsRetriever.cxx b/Framework/Core/test/test_BoostOptionsRetriever.cxx index 42110510a0c3e..812e184a54354 100644 --- a/Framework/Core/test/test_BoostOptionsRetriever.cxx +++ b/Framework/Core/test/test_BoostOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,6 +29,10 @@ BOOST_AUTO_TEST_CASE(TrivialBoostOptionsRetrieverTest) auto specs = std::vector<ConfigParamSpec>{ {"someInt", VariantType::Int, 2, {"some int option"}}, + {"someUInt8", VariantType::UInt8, static_cast<uint8_t>(2u), {"some uint8 option"}}, + {"someUInt16", VariantType::UInt16, static_cast<uint16_t>(2u), {"some uint16 option"}}, + {"someUInt32", VariantType::UInt32, 2u, {"some uint32 option"}}, + {"someUInt64", VariantType::UInt64, static_cast<uint64_t>(2ul), {"some uint64 option"}}, {"someInt64", VariantType::Int64, 4ll, {"some int64 option"}}, {"someBool", VariantType::Bool, false, {"some bool option"}}, {"someFloat", VariantType::Float, 2.0f, {"some float option"}}, @@ -37,6 +42,10 @@ BOOST_AUTO_TEST_CASE(TrivialBoostOptionsRetrieverTest) "test", "--someBool", "--someInt", "1", + "--someUInt8", "1", + "--someUInt16", "1", + "--someUInt32", "1", + "--someUInt64", "1", "--someInt64", "50000000000000", "--someFloat", "0.5", "--someDouble", "0.5", @@ -49,6 +58,10 @@ BOOST_AUTO_TEST_CASE(TrivialBoostOptionsRetrieverTest) bpo::store(parse_command_line(sizeof(args) / sizeof(char*), args, opts), vm); bpo::notify(vm); BOOST_CHECK(vm["someInt"].as<int>() == 1); + BOOST_CHECK(vm["someUInt8"].as<uint8_t>() == '1'); + BOOST_CHECK(vm["someUInt16"].as<uint16_t>() == 1); + BOOST_CHECK(vm["someUInt32"].as<uint32_t>() == 1); + BOOST_CHECK(vm["someUInt64"].as<uint64_t>() == 1); BOOST_CHECK(vm["someInt64"].as<int64_t>() == 50000000000000ll); BOOST_CHECK(vm["someBool"].as<bool>() == true); BOOST_CHECK(vm["someString"].as<std::string>() == "foobar"); diff --git a/Framework/Core/test/test_BoostSerializedProcessing.cxx b/Framework/Core/test/test_BoostSerializedProcessing.cxx index 86c9aab29f6b8..2994cc55ebdde 100644 --- a/Framework/Core/test/test_BoostSerializedProcessing.cxx +++ b/Framework/Core/test/test_BoostSerializedProcessing.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -92,7 +93,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) Outputs{}, // AlgorithmSpec{ [](ProcessingContext& ctx) { - LOG(INFO) << "Buffer ready to receive"; + LOG(info) << "Buffer ready to receive"; auto in = ctx.inputs().get<BoostSerialized<std::vector<Foo>>>("make"); std::vector<Foo> check; diff --git a/Framework/Core/test/test_CCDBFetcher.cxx b/Framework/Core/test/test_CCDBFetcher.cxx index 45375ed9a6d14..034f96fc3a0fa 100644 --- a/Framework/Core/test/test_CCDBFetcher.cxx +++ b/Framework/Core/test/test_CCDBFetcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "Framework/runDataProcessing.h" #include "Framework/ServiceRegistry.h" #include "Framework/ControlService.h" +#include "Framework/CCDBParamSpec.h" #include <chrono> #include <thread> @@ -23,19 +25,17 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) return WorkflowSpec{ { "A", - {InputSpec{"somecondition", "TST", "FOO", 0, Lifetime::Condition}, - InputSpec{"sometimer", "TST", "BAR", 0, Lifetime::Timer}}, + {InputSpec{"somecondition", "TOF", "LHCphase", 0, Lifetime::Condition, ccdbParamSpec("TOF/LHCphase")}, + InputSpec{"sometimer", "TST", "BAR", 0, Lifetime::Timer, {startTimeParamSpec{1638548475371}}}}, {OutputSpec{"TST", "A1", 0, Lifetime::Timeframe}}, AlgorithmSpec{ adaptStateless([](DataAllocator& outputs, InputRecord& inputs, ControlService& control) { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); DataRef condition = inputs.get("somecondition"); - auto* header = o2::header::get<const DataHeader*>(condition.header); - if (header->payloadSize != 1024) { - LOG(ERROR) << "Wrong size for condition payload (expected " << 1024 << ", found " << header->payloadSize; + auto payloadSize = DataRefUtils::getPayloadSize(condition); + if (payloadSize != 2048) { + LOGP(ERROR, "Wrong size for condition payload (expected {}, found {}", 2048, payloadSize); } - header->payloadSize; - auto& aData = outputs.make<int>(Output{"TST", "A1", 0}, 1); + payloadSize; control.readyToQuit(QuitRequest::All); })}, Options{ diff --git a/Framework/Core/test/test_CallbackRegistry.cxx b/Framework/Core/test/test_CallbackRegistry.cxx index 6c3dbccf9beb1..345fa0b4c97c3 100644 --- a/Framework/Core/test/test_CallbackRegistry.cxx +++ b/Framework/Core/test/test_CallbackRegistry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_CallbackService.cxx b/Framework/Core/test/test_CallbackService.cxx index b8953577f1b4f..eb8aa538ee2bd 100644 --- a/Framework/Core/test/test_CallbackService.cxx +++ b/Framework/Core/test/test_CallbackService.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_ChannelSpecHelpers.cxx b/Framework/Core/test/test_ChannelSpecHelpers.cxx index 1166c706bd083..d8fd03f7c3588 100644 --- a/Framework/Core/test/test_ChannelSpecHelpers.cxx +++ b/Framework/Core/test/test_ChannelSpecHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_CheckTypes.cxx b/Framework/Core/test/test_CheckTypes.cxx new file mode 100644 index 0000000000000..45e0870bf92be --- /dev/null +++ b/Framework/Core/test/test_CheckTypes.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test Framework Traits +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "Framework/CheckTypes.h" + +using namespace o2::framework; + +struct Foo { + bool foo; +}; + +BOOST_AUTO_TEST_CASE(CallIfUndefined) +{ + bool shouldBeCalled = false; + bool shouldNotBeCalled = false; + bool shouldBeCalledOnUndefined = false; + + call_if_defined<struct Foo>([&shouldBeCalled](auto) { shouldBeCalled = true; }); + call_if_defined<struct Bar>([&shouldNotBeCalled](auto) { shouldNotBeCalled = true; }); + BOOST_REQUIRE_EQUAL(shouldBeCalled, true); + BOOST_REQUIRE_EQUAL(shouldNotBeCalled, false); + + shouldBeCalled = false; + shouldNotBeCalled = false; + shouldBeCalledOnUndefined = false; + + call_if_defined_full<struct Bar>([&shouldNotBeCalled](auto) { shouldNotBeCalled = true; }, []() {}); + BOOST_REQUIRE_EQUAL(shouldNotBeCalled, false); + BOOST_REQUIRE_EQUAL(shouldBeCalledOnUndefined, false); + call_if_defined_full<struct Bar>([&shouldNotBeCalled](auto) { shouldNotBeCalled = true; }, [&shouldBeCalledOnUndefined]() { shouldBeCalledOnUndefined = true; }); + BOOST_REQUIRE_EQUAL(shouldNotBeCalled, false); + BOOST_REQUIRE_EQUAL(shouldBeCalledOnUndefined, true); +} diff --git a/Framework/Core/test/test_CompletionPolicy.cxx b/Framework/Core/test/test_CompletionPolicy.cxx index a335e731b0aba..c9b7d5fb6263e 100644 --- a/Framework/Core/test/test_CompletionPolicy.cxx +++ b/Framework/Core/test/test_CompletionPolicy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #include "Framework/CompletionPolicyHelpers.h" #include "Headers/DataHeader.h" #include "Headers/NameHeader.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/InputSpan.h" #include "Headers/Stack.h" using namespace o2::framework; @@ -40,7 +43,7 @@ BOOST_AUTO_TEST_CASE(TestCompletionPolicy_callback) return true; }; - auto callback = [&stack](CompletionPolicy::InputSet inputRefs) { + auto callback = [&stack](InputSpan const& inputRefs) { for (auto const& ref : inputRefs) { auto const* header = CompletionPolicyHelpers::getHeader<o2::header::DataHeader>(ref); BOOST_CHECK_EQUAL(header, reinterpret_cast<o2::header::DataHeader*>(stack.data())); @@ -54,7 +57,7 @@ BOOST_AUTO_TEST_CASE(TestCompletionPolicy_callback) policies.emplace_back("test", matcher, callback); CompletionPolicy::InputSetElement ref{nullptr, reinterpret_cast<const char*>(stack.data()), nullptr}; - CompletionPolicy::InputSet inputs{[&ref](size_t) { return ref; }, 1}; + InputSpan const& inputs{[&ref](size_t) { return ref; }, 1}; for (auto& policy : policies) { policy.callback(inputs); } diff --git a/Framework/Core/test/test_ComputingQuotaEvaluator.cxx b/Framework/Core/test/test_ComputingQuotaEvaluator.cxx new file mode 100644 index 0000000000000..830b81faaf2d9 --- /dev/null +++ b/Framework/Core/test/test_ComputingQuotaEvaluator.cxx @@ -0,0 +1,183 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test Framework ComputingQuotaEvaluator +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include "Framework/ComputingQuotaEvaluator.h" +#include "Framework/ResourcePolicyHelpers.h" +#include "Framework/Logger.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +using namespace o2::framework; + +BOOST_AUTO_TEST_CASE(TestBasics) +{ + static std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats&)> reportConsumedOffer = [](ComputingQuotaOffer const& accumulatedConsumed, ComputingQuotaStats& stats) { + stats.totalConsumedBytes += accumulatedConsumed.sharedMemory; + }; + + ComputingQuotaConsumer dispose2MB = [bs = 2000000](int taskId, + std::array<ComputingQuotaOffer, 16>& offers, + ComputingQuotaStats& stats, + std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats&)> accountDisposed) { + ComputingQuotaOffer disposed; + disposed.sharedMemory = 0; + int64_t bytesSent = bs; + for (size_t oi = 0; oi < offers.size(); oi++) { + auto& offer = offers[oi]; + if (offer.user != taskId) { + continue; + } + int64_t toRemove = std::min((int64_t)bytesSent, offer.sharedMemory); + offer.sharedMemory -= toRemove; + bytesSent -= toRemove; + disposed.sharedMemory += toRemove; + if (bytesSent <= 0) { + break; + } + } + return accountDisposed(disposed, stats); + }; + + ComputingQuotaConsumer dispose10MB = [bs = 10000000](int taskId, + std::array<ComputingQuotaOffer, 16>& offers, + ComputingQuotaStats& stats, + std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats&)> accountDisposed) { + ComputingQuotaOffer disposed; + disposed.sharedMemory = 0; + int64_t bytesSent = bs; + for (size_t oi = 0; oi < offers.size(); oi++) { + auto& offer = offers[oi]; + if (offer.user != taskId) { + continue; + } + int64_t toRemove = std::min((int64_t)bytesSent, offer.sharedMemory); + offer.sharedMemory -= toRemove; + bytesSent -= toRemove; + disposed.sharedMemory += toRemove; + if (bytesSent <= 0) { + break; + } + } + return accountDisposed(disposed, stats); + }; + + ComputingQuotaEvaluator evaluator{0}; + std::vector<ComputingQuotaOffer> offers{{.sharedMemory = 1000000}}; + evaluator.updateOffers(offers, 1); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].sharedMemory, 1000000); + std::vector<ComputingQuotaOffer> offers2{{.sharedMemory = 1000000}}; + evaluator.updateOffers(offers2, 2); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, 1000000); + std::vector<ComputingQuotaOffer> offers3{{.sharedMemory = 2000000}, {.sharedMemory = 3000000}}; + evaluator.updateOffers(offers3, 3); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 3000000); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 2000000); + auto policy = ResourcePolicyHelpers::sharedMemoryBoundTask("internal-dpl-aod-reader.*", 2000000); + bool selected = evaluator.selectOffer(1, policy.request, 3); + BOOST_CHECK(selected); + BOOST_CHECK_EQUAL(evaluator.mOffers[0].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].user, 1); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].user, -1); + + evaluator.consume(1, dispose2MB, reportConsumedOffer); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].user, 1); + + static std::function<void(ComputingQuotaOffer const&, ComputingQuotaStats const&)> reportExpiredOffer = [](ComputingQuotaOffer const& offer, ComputingQuotaStats const& stats) { + }; + + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, 1000000); + evaluator.handleExpired(reportExpiredOffer); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 1000000); + evaluator.dispose(1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mStats.totalExpiredBytes, 2000000); + BOOST_CHECK_EQUAL(evaluator.mStats.totalConsumedBytes, 2000000); + + selected = evaluator.selectOffer(1, policy.request, 3); + BOOST_CHECK(selected); + + BOOST_CHECK_EQUAL(evaluator.mOffers[0].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].user, 1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].valid, true); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].user, 1); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 2000000); + + evaluator.consume(1, dispose2MB, reportConsumedOffer); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 1000000); + evaluator.handleExpired(reportExpiredOffer); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 1000000); + evaluator.dispose(1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mStats.totalExpiredBytes, 2000000); + BOOST_CHECK_EQUAL(evaluator.mStats.totalConsumedBytes, 4000000); + + std::vector<ComputingQuotaOffer> offers4{{.sharedMemory = 1000000, .runtime = 100}}; + evaluator.updateOffers(offers4, 2); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, 1000000); + + selected = evaluator.selectOffer(1, policy.request, 10); + evaluator.handleExpired(reportExpiredOffer); + selected = evaluator.selectOffer(1, policy.request, 11); + evaluator.handleExpired(reportExpiredOffer); + std::vector<ComputingQuotaOffer> offers5{{.sharedMemory = 1000000, .runtime = 100}}; + evaluator.updateOffers(offers5, 4); + selected = evaluator.selectOffer(1, policy.request, 13); + evaluator.consume(1, dispose2MB, reportConsumedOffer); + evaluator.handleExpired(reportExpiredOffer); + evaluator.dispose(1); + BOOST_CHECK_EQUAL(evaluator.mStats.totalExpiredBytes, 3000000); + BOOST_CHECK_EQUAL(evaluator.mStats.totalConsumedBytes, 6000000); + + BOOST_CHECK_EQUAL(evaluator.mOffers[1].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[3].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[4].sharedMemory, -1); + + std::vector<ComputingQuotaOffer> offers6{{.sharedMemory = 2000000, .runtime = 100}, {.sharedMemory = 1000000, .runtime = 100}}; + evaluator.updateOffers(offers6, 19); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].sharedMemory, 1000000); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, 2000000); + /// Check if we request 2MB and consume 10 works + selected = evaluator.selectOffer(1, policy.request, 20); + evaluator.consume(1, dispose10MB, reportConsumedOffer); + evaluator.handleExpired(reportExpiredOffer); + evaluator.dispose(1); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].sharedMemory, 0); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].user, -1); + BOOST_CHECK_EQUAL(evaluator.mOffers[1].valid, false); + BOOST_CHECK_EQUAL(evaluator.mOffers[2].valid, false); +} + +#pragma GGC diagnostic pop diff --git a/Framework/Core/test/test_ComputingResourceHelpers.cxx b/Framework/Core/test/test_ComputingResourceHelpers.cxx index a1d8e2a3baae1..07e2eee0cffa6 100644 --- a/Framework/Core/test/test_ComputingResourceHelpers.cxx +++ b/Framework/Core/test/test_ComputingResourceHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_ConfigParamRegistry.cxx b/Framework/Core/test/test_ConfigParamRegistry.cxx index f676aba1eddbd..5f00986529344 100644 --- a/Framework/Core/test/test_ConfigParamRegistry.cxx +++ b/Framework/Core/test/test_ConfigParamRegistry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamRegistry) ("aFloat", bpo::value<float>()->default_value(10.f)) // ("aDouble", bpo::value<double>()->default_value(20.)) // ("anInt", bpo::value<int>()->default_value(1)) // + ("anUInt8", bpo::value<uint8_t>()->default_value(1)) // + ("anUInt16", bpo::value<uint16_t>()->default_value(1)) // + ("anUInt32", bpo::value<uint32_t>()->default_value(1)) // + ("anUInt64", bpo::value<uint64_t>()->default_value(1)) // ("anInt64", bpo::value<int64_t>()->default_value(1ll)) // ("aBoolean", bpo::value<bool>()->zero_tokens()->default_value(false)) // ("aString,s", bpo::value<std::string>()->default_value("something")) // @@ -51,6 +56,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamRegistry) options->ParseAll({"cmd", "--aFloat", "1.0", "--aDouble", "2.0", "--anInt", "10", + "--anUInt8", "2", + "--anUInt16", "10", + "--anUInt32", "10", + "--anUInt64", "10", "--anInt64", "50000000000000", "--aBoolean", "-s", "somethingelse", @@ -59,6 +68,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamRegistry) true); std::vector<ConfigParamSpec> specs{ ConfigParamSpec{"anInt", VariantType::Int, 1, {"an int option"}}, + ConfigParamSpec{"anUInt8", VariantType::UInt8, static_cast<uint8_t>(1u), {"an uint8 option"}}, + ConfigParamSpec{"anUInt16", VariantType::UInt16, static_cast<uint16_t>(1u), {"an uint16 option"}}, + ConfigParamSpec{"anUInt32", VariantType::UInt32, 1u, {"an uint32 option"}}, + ConfigParamSpec{"anUInt64", VariantType::UInt64, static_cast<uint64_t>(1ul), {"an uint64 option"}}, ConfigParamSpec{"anInt64", VariantType::Int64, 1ll, {"an int64_t option"}}, ConfigParamSpec{"aFloat", VariantType::Float, 2.0f, {"a float option"}}, ConfigParamSpec{"aDouble", VariantType::Double, 3., {"a double option"}}, @@ -81,6 +94,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamRegistry) BOOST_CHECK_EQUAL(registry.get<float>("aFloat"), 1.0); BOOST_CHECK_EQUAL(registry.get<double>("aDouble"), 2.0); BOOST_CHECK_EQUAL(registry.get<int>("anInt"), 10); + BOOST_CHECK_EQUAL(registry.get<uint8_t>("anUInt8"), '2'); + BOOST_CHECK_EQUAL(registry.get<uint16_t>("anUInt16"), 10); + BOOST_CHECK_EQUAL(registry.get<uint32_t>("anUInt32"), 10); + BOOST_CHECK_EQUAL(registry.get<uint64_t>("anUInt64"), 10); BOOST_CHECK_EQUAL(registry.get<int64_t>("anInt64"), 50000000000000ll); BOOST_CHECK_EQUAL(registry.get<bool>("aBoolean"), true); BOOST_CHECK_EQUAL(registry.get<std::string>("aString"), "somethingelse"); diff --git a/Framework/Core/test/test_ConfigParamStore.cxx b/Framework/Core/test/test_ConfigParamStore.cxx index 8269f8090c726..df56fdf8a0e18 100644 --- a/Framework/Core/test/test_ConfigParamStore.cxx +++ b/Framework/Core/test/test_ConfigParamStore.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamStore) ("aFloat", bpo::value<float>()->default_value(10.f)) // ("aDouble", bpo::value<double>()->default_value(20.)) // ("anInt", bpo::value<int>()->default_value(1)) // + ("anUInt8", bpo::value<uint8_t>()->default_value(1)) // + ("anUInt16", bpo::value<uint16_t>()->default_value(1)) // + ("anUInt32", bpo::value<uint32_t>()->default_value(1)) // + ("anUInt64", bpo::value<uint64_t>()->default_value(1)) // ("anInt64", bpo::value<int64_t>()->default_value(1ll)) // ("aBoolean", bpo::value<bool>()->zero_tokens()->default_value(false)) // ("aString,s", bpo::value<std::string>()->default_value("something")) // @@ -41,6 +46,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamStore) options->ParseAll({"cmd", "--aFloat", "1.0", "--aDouble", "2.0", "--anInt", "10", + "--anUInt8", "2", + "--anUInt16", "10", + "--anUInt32", "10", + "--anUInt64", "10", "--anInt64", "50000000000000", "--aBoolean", "-s", "somethingelse", @@ -49,6 +58,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamStore) true); std::vector<ConfigParamSpec> specs{ ConfigParamSpec{"anInt", VariantType::Int, 1, {"an int option"}}, + ConfigParamSpec{"anUInt8", VariantType::UInt8, static_cast<uint8_t>(1u), {"an int option"}}, + ConfigParamSpec{"anUInt16", VariantType::UInt16, static_cast<uint16_t>(1u), {"an int option"}}, + ConfigParamSpec{"anUInt32", VariantType::UInt32, 1u, {"an int option"}}, + ConfigParamSpec{"anUInt64", VariantType::UInt64, static_cast<uint64_t>(1ul), {"an int option"}}, ConfigParamSpec{"anInt64", VariantType::Int64, 1ll, {"an int64_t option"}}, ConfigParamSpec{"aFloat", VariantType::Float, 2.0f, {"a float option"}}, ConfigParamSpec{"aDouble", VariantType::Double, 3., {"a double option"}}, @@ -70,6 +83,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamStore) BOOST_CHECK_EQUAL(store.store().get<float>("aFloat"), 1.0); BOOST_CHECK_EQUAL(store.store().get<double>("aDouble"), 2.0); BOOST_CHECK_EQUAL(store.store().get<int>("anInt"), 10); + BOOST_CHECK_EQUAL(store.store().get<uint8_t>("anUInt8"), '2'); + BOOST_CHECK_EQUAL(store.store().get<uint16_t>("anUInt16"), 10); + BOOST_CHECK_EQUAL(store.store().get<uint32_t>("anUInt32"), 10); + BOOST_CHECK_EQUAL(store.store().get<uint64_t>("anUInt64"), 10); BOOST_CHECK_EQUAL(store.store().get<int64_t>("anInt64"), 50000000000000ll); BOOST_CHECK_EQUAL(store.store().get<bool>("aBoolean"), true); BOOST_CHECK_EQUAL(store.store().get<std::string>("aString"), "somethingelse"); @@ -86,6 +103,10 @@ BOOST_AUTO_TEST_CASE(TestConfigParamStore) BOOST_CHECK_EQUAL(store.provenance("aFloat"), "fairmq"); BOOST_CHECK_EQUAL(store.provenance("aDouble"), "fairmq"); BOOST_CHECK_EQUAL(store.provenance("anInt"), "fairmq"); + BOOST_CHECK_EQUAL(store.provenance("anUInt8"), "fairmq"); + BOOST_CHECK_EQUAL(store.provenance("anUInt16"), "fairmq"); + BOOST_CHECK_EQUAL(store.provenance("anUInt32"), "fairmq"); + BOOST_CHECK_EQUAL(store.provenance("anUInt64"), "fairmq"); BOOST_CHECK_EQUAL(store.provenance("anInt64"), "fairmq"); BOOST_CHECK_EQUAL(store.provenance("aBoolean"), "fairmq"); BOOST_CHECK_EQUAL(store.provenance("aString"), "fairmq"); diff --git a/Framework/Core/test/test_ConfigurationOptionsRetriever.cxx b/Framework/Core/test/test_ConfigurationOptionsRetriever.cxx index bba681ef59ea6..ca84dc2d8ed34 100644 --- a/Framework/Core/test/test_ConfigurationOptionsRetriever.cxx +++ b/Framework/Core/test/test_ConfigurationOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DanglingInputs.cxx b/Framework/Core/test/test_DanglingInputs.cxx index fe41a36d65ae9..9c483d3556e27 100644 --- a/Framework/Core/test/test_DanglingInputs.cxx +++ b/Framework/Core/test/test_DanglingInputs.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DanglingOutputs.cxx b/Framework/Core/test/test_DanglingOutputs.cxx index 157cacf071e40..330b16d12a8bd 100644 --- a/Framework/Core/test/test_DanglingOutputs.cxx +++ b/Framework/Core/test/test_DanglingOutputs.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataAllocator.cxx b/Framework/Core/test/test_DataAllocator.cxx index 448ab70bd4626..215ea3ddafc81 100644 --- a/Framework/Core/test/test_DataAllocator.cxx +++ b/Framework/Core/test/test_DataAllocator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include "Framework/SerializationMethods.h" #include "Framework/OutputRoute.h" #include "Framework/ConcreteDataMatcher.h" +#include "Framework/DataRefUtils.h" #include "Headers/DataHeader.h" #include "TestClasses.h" #include "Framework/Logger.h" @@ -35,7 +37,7 @@ using namespace o2::framework; #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed)"; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ } // this function is only used to do the static checks for API return types @@ -187,19 +189,19 @@ DataProcessorSpec getSinkSpec() using DataHeader = o2::header::DataHeader; for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { auto const& input = *iit; - LOG(INFO) << (*iit).spec->binding << " " << (iit.isValid() ? "is valid" : "is not valid"); + LOG(info) << (*iit).spec->binding << " " << (iit.isValid() ? "is valid" : "is not valid"); if (iit.isValid() == false) { continue; } - auto* dh = o2::header::get<const DataHeader*>(input.header); - LOG(INFO) << "{" << dh->dataOrigin.str << ":" << dh->dataDescription.str << ":" << dh->subSpecification << "}" + auto* dh = DataRefUtils::getHeader<const DataHeader*>(input); + LOG(info) << "{" << dh->dataOrigin.str << ":" << dh->dataDescription.str << ":" << dh->subSpecification << "}" << " payload size " << dh->payloadSize; using DumpStackFctType = std::function<void(const o2::header::BaseHeader*)>; DumpStackFctType dumpStack = [&](const o2::header::BaseHeader* h) { o2::header::hexDump("", h, h->size()); if (h->flagsNextHeader) { - auto next = reinterpret_cast<const o2::byte*>(h) + h->size(); + auto next = reinterpret_cast<const std::byte*>(h) + h->size(); dumpStack(reinterpret_cast<const o2::header::BaseHeader*>(next)); } }; @@ -207,10 +209,10 @@ DataProcessorSpec getSinkSpec() dumpStack(dh); if ((*iit).spec->binding == "inputMP") { - LOG(INFO) << "inputMP with " << iit.size() << " part(s)"; + LOG(info) << "inputMP with " << iit.size() << " part(s)"; int nPart = 0; for (auto const& ref : iit) { - LOG(INFO) << "accessing part " << nPart++ << " of input slot 'inputMP':" + LOG(info) << "accessing part " << nPart++ << " of input slot 'inputMP':" << pc.inputs().get<int>(ref); ASSERT_ERROR(pc.inputs().get<int>(ref) == nPart * 10); } @@ -218,10 +220,10 @@ DataProcessorSpec getSinkSpec() } } // plain, unserialized object in input1 channel - LOG(INFO) << "extracting o2::test::TriviallyCopyable from input1"; + LOG(info) << "extracting o2::test::TriviallyCopyable from input1"; auto object1 = pc.inputs().get<o2::test::TriviallyCopyable>("input1"); ASSERT_ERROR(object1 == o2::test::TriviallyCopyable(42, 23, 0xdead)); - LOG(INFO) << "extracting span of o2::test::TriviallyCopyable from input1"; + LOG(info) << "extracting span of o2::test::TriviallyCopyable from input1"; auto object1span = pc.inputs().get<gsl::span<o2::test::TriviallyCopyable>>("input1"); ASSERT_ERROR(object1span.size() == 1); ASSERT_ERROR(sizeof(typename decltype(object1span)::value_type) == sizeof(o2::test::TriviallyCopyable)); @@ -234,68 +236,68 @@ DataProcessorSpec getSinkSpec() ASSERT_ERROR(metaHeader2 != nullptr && metaHeader2->secret == 23); // ROOT-serialized messageable object in input2 channel - LOG(INFO) << "extracting o2::test::TriviallyCopyable pointer from input2"; + LOG(info) << "extracting o2::test::TriviallyCopyable pointer from input2"; auto object2 = pc.inputs().get<o2::test::TriviallyCopyable*>("input2"); ASSERT_ERROR(object2 != nullptr); ASSERT_ERROR(*object2 == o2::test::TriviallyCopyable(42, 23, 0xdead)); // ROOT-serialized, non-messageable object in input3 channel - LOG(INFO) << "extracting o2::test::Polymorphic pointer from input3"; + LOG(info) << "extracting o2::test::Polymorphic pointer from input3"; auto object3 = pc.inputs().get<o2::test::Polymorphic*>("input3"); ASSERT_ERROR(object3 != nullptr); ASSERT_ERROR(*object3 == o2::test::Polymorphic(0xbeef)); // container of objects - LOG(INFO) << "extracting vector of o2::test::Polymorphic from input4"; + LOG(info) << "extracting vector of o2::test::Polymorphic from input4"; auto object4 = pc.inputs().get<std::vector<o2::test::Polymorphic>>("input4"); ASSERT_ERROR(object4.size() == 2); ASSERT_ERROR(object4[0] == o2::test::Polymorphic(0xaffe)); ASSERT_ERROR(object4[1] == o2::test::Polymorphic(0xd00f)); // container of objects - LOG(INFO) << "extracting vector of o2::test::Polymorphic from input5"; + LOG(info) << "extracting vector of o2::test::Polymorphic from input5"; auto object5 = pc.inputs().get<std::vector<o2::test::Polymorphic>>("input5"); ASSERT_ERROR(object5.size() == 2); ASSERT_ERROR(object5[0] == o2::test::Polymorphic(0xaffe)); ASSERT_ERROR(object5[1] == o2::test::Polymorphic(0xd00f)); // container of objects - LOG(INFO) << "extracting vector of o2::test::Polymorphic from input6"; + LOG(info) << "extracting vector of o2::test::Polymorphic from input6"; auto object6 = pc.inputs().get<std::vector<o2::test::Polymorphic>>("input6"); ASSERT_ERROR(object6.size() == 2); ASSERT_ERROR(object6[0] == o2::test::Polymorphic(0xaffe)); ASSERT_ERROR(object6[1] == o2::test::Polymorphic(0xd00f)); // checking retrieving buffer as raw char*, and checking content by cast - LOG(INFO) << "extracting raw char* from input1"; + LOG(info) << "extracting raw char* from input1"; auto rawchar = pc.inputs().get<const char*>("input1"); const auto& data1 = *reinterpret_cast<const o2::test::TriviallyCopyable*>(rawchar); ASSERT_ERROR(data1 == o2::test::TriviallyCopyable(42, 23, 0xdead)); - LOG(INFO) << "extracting o2::test::TriviallyCopyable from input7"; + LOG(info) << "extracting o2::test::TriviallyCopyable from input7"; auto object7 = pc.inputs().get<o2::test::TriviallyCopyable>("input7"); ASSERT_ERROR(object1 == o2::test::TriviallyCopyable(42, 23, 0xdead)); - LOG(INFO) << "extracting span of o2::test::TriviallyCopyable from input8"; + LOG(info) << "extracting span of o2::test::TriviallyCopyable from input8"; auto objectspan8 = DataRefUtils::as<o2::test::TriviallyCopyable>(pc.inputs().get("input8")); ASSERT_ERROR(objectspan8.size() == 3); for (auto const& object8 : objectspan8) { ASSERT_ERROR(object8 == o2::test::TriviallyCopyable(42, 23, 0xdead)); } - LOG(INFO) << "extracting std::string from input9"; + LOG(info) << "extracting std::string from input9"; auto object9 = pc.inputs().get<std::string>("input9"); ASSERT_ERROR(object9 == "adoptchunk"); - LOG(INFO) << "extracting o2::test::TriviallyCopyable from input10"; + LOG(info) << "extracting o2::test::TriviallyCopyable from input10"; auto object10 = pc.inputs().get<o2::test::TriviallyCopyable>("input10"); ASSERT_ERROR(object10 == o2::test::TriviallyCopyable(42, 23, 0xdead)); - LOG(INFO) << "extracting o2::test::TriviallyCopyable from input11"; + LOG(info) << "extracting o2::test::TriviallyCopyable from input11"; auto object11 = pc.inputs().get<o2::test::TriviallyCopyable>("input11"); ASSERT_ERROR(object11 == o2::test::TriviallyCopyable(42, 23, 0xdead)); - LOG(INFO) << "extracting the original std::vector<o2::test::TriviallyCopyable> as span from input12"; + LOG(info) << "extracting the original std::vector<o2::test::TriviallyCopyable> as span from input12"; auto object12 = pc.inputs().get<gsl::span<o2::test::TriviallyCopyable>>("input12"); ASSERT_ERROR(object12.size() == 2); ASSERT_ERROR((object12[0] == o2::test::TriviallyCopyable{42, 23, 0xdead})); @@ -303,28 +305,28 @@ DataProcessorSpec getSinkSpec() // forward the read-only span on a different route pc.outputs().snapshot(Output{"TST", "MSGABLVECTORCPY", 0, Lifetime::Timeframe}, object12); - LOG(INFO) << "extracting TNamed object from input13"; + LOG(info) << "extracting TNamed object from input13"; auto object13 = pc.inputs().get<TNamed*>("input13"); ASSERT_ERROR(strcmp(object13->GetName(), "a_name") == 0); ASSERT_ERROR(strcmp(object13->GetTitle(), "a_title") == 0); - LOG(INFO) << "extracting Root-serialized Non-TObject from input14"; + LOG(info) << "extracting Root-serialized Non-TObject from input14"; auto object14 = pc.inputs().get<o2::test::Polymorphic*>("input14"); ASSERT_ERROR(*object14 == o2::test::Polymorphic{0xbeef}); - LOG(INFO) << "extracting Root-serialized vector from input15"; + LOG(info) << "extracting Root-serialized vector from input15"; auto object15 = pc.inputs().get<std::vector<o2::test::Polymorphic>>("input15"); ASSERT_ERROR(object15[0] == o2::test::Polymorphic{0xacdc}); ASSERT_ERROR(object15[1] == o2::test::Polymorphic{0xbeef}); - LOG(INFO) << "extracting PMR vector"; + LOG(info) << "extracting PMR vector"; auto pmrspan = pc.inputs().get<gsl::span<o2::test::TriviallyCopyable>>("inputPMR"); ASSERT_ERROR((pmrspan[0] == o2::test::TriviallyCopyable{1, 2, 3})); auto dataref = pc.inputs().get<DataRef>("inputPMR"); - auto header = o2::header::get<const o2::header::DataHeader*>(dataref.header); + auto header = DataRefUtils::getHeader<const o2::header::DataHeader*>(dataref); ASSERT_ERROR((header->payloadSize == sizeof(o2::test::TriviallyCopyable))); - LOG(INFO) << "extracting POD vector"; + LOG(info) << "extracting POD vector"; // TODO: use the ReturnType helper once implemented //InputRecord::ReturnType<std::vector<int>> podvector; decltype(std::declval<InputRecord>().get<std::vector<int>>(DataRef{nullptr, nullptr, nullptr})) podvector; @@ -366,18 +368,18 @@ DataProcessorSpec getSpectatorSinkSpec() int nPart = 0; for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { auto const& input = *iit; - LOG(INFO) << (*iit).spec->binding << " " << (iit.isValid() ? "is valid" : "is not valid"); + LOG(info) << (*iit).spec->binding << " " << (iit.isValid() ? "is valid" : "is not valid"); if (iit.isValid() == false) { continue; } - auto* dh = o2::header::get<const DataHeader*>(input.header); - LOG(INFO) << "{" << dh->dataOrigin.str << ":" << dh->dataDescription.str << ":" << dh->subSpecification << "}" + auto* dh = DataRefUtils::getHeader<const DataHeader*>(input); + LOG(info) << "{" << dh->dataOrigin.str << ":" << dh->dataDescription.str << ":" << dh->subSpecification << "}" << " payload size " << dh->payloadSize; if ((*iit).spec->binding == "inputMP") { - LOG(INFO) << "inputMP with " << iit.size() << " part(s)"; + LOG(info) << "inputMP with " << iit.size() << " part(s)"; for (auto const& ref : iit) { - LOG(INFO) << "accessing part " << nPart << " of input slot 'inputMP':" + LOG(info) << "accessing part " << nPart << " of input slot 'inputMP':" << pc.inputs().get<int>(ref); nPart++; ASSERT_ERROR(pc.inputs().get<int>(ref) == nPart * 10); @@ -385,7 +387,7 @@ DataProcessorSpec getSpectatorSinkSpec() } } ASSERT_ERROR(nPart == 3); - LOG(INFO) << "extracting the forwarded gsl::span<o2::test::TriviallyCopyable> as span from input12"; + LOG(info) << "extracting the forwarded gsl::span<o2::test::TriviallyCopyable> as span from input12"; auto object12 = pc.inputs().get<gsl::span<o2::test::TriviallyCopyable>>("input12"); ASSERT_ERROR(object12.size() == 2); ASSERT_ERROR((object12[0] == o2::test::TriviallyCopyable{42, 23, 0xdead})); diff --git a/Framework/Core/test/test_DataDescriptorMatcher.cxx b/Framework/Core/test/test_DataDescriptorMatcher.cxx index 6501a31a7e705..03feed72d4643 100644 --- a/Framework/Core/test/test_DataDescriptorMatcher.cxx +++ b/Framework/Core/test/test_DataDescriptorMatcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataInputDirector.cxx b/Framework/Core/test/test_DataInputDirector.cxx index f8456d7935380..5f067a8fe0bd3 100644 --- a/Framework/Core/test/test_DataInputDirector.cxx +++ b/Framework/Core/test/test_DataInputDirector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataOutputDirector.cxx b/Framework/Core/test/test_DataOutputDirector.cxx index f9f2becd04044..3bb40fb3a8ffe 100644 --- a/Framework/Core/test/test_DataOutputDirector.cxx +++ b/Framework/Core/test/test_DataOutputDirector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataProcessorSpec.cxx b/Framework/Core/test/test_DataProcessorSpec.cxx index d4935112cdcda..feb805ffc8949 100644 --- a/Framework/Core/test/test_DataProcessorSpec.cxx +++ b/Framework/Core/test/test_DataProcessorSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataRefUtils.cxx b/Framework/Core/test/test_DataRefUtils.cxx index 57e19c55362b8..3bd79fbf1e7f1 100644 --- a/Framework/Core/test/test_DataRefUtils.cxx +++ b/Framework/Core/test/test_DataRefUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_DataRelayer.cxx b/Framework/Core/test/test_DataRelayer.cxx index 014d0cb99718a..9c54830a48b38 100644 --- a/Framework/Core/test/test_DataRelayer.cxx +++ b/Framework/Core/test/test_DataRelayer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,7 +42,7 @@ BOOST_AUTO_TEST_CASE(TestNoWait) InputRoute{spec, 0, "Fake", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -53,6 +54,8 @@ BOOST_AUTO_TEST_CASE(TestNoWait) dh.dataDescription = "CLUSTERS"; dh.dataOrigin = "TPC"; dh.subSpecification = 0; + dh.splitPayloadIndex = 0; + dh.splitPayloadParts = 1; DataProcessingHeader dph{0, 1}; Stack stack{dh, dph}; @@ -60,12 +63,14 @@ BOOST_AUTO_TEST_CASE(TestNoWait) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); BOOST_REQUIRE_EQUAL(ready.size(), 1); BOOST_CHECK_EQUAL(ready[0].slot.index, 0); BOOST_CHECK_EQUAL(ready[0].op, CompletionPolicy::CompletionOp::Consume); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); auto result = relayer.getInputsForTimeslice(ready[0].slot); // one MessageSet with one PartRef with header and payload BOOST_REQUIRE_EQUAL(result.size(), 1); @@ -82,7 +87,7 @@ BOOST_AUTO_TEST_CASE(TestNoWaitMatcher) InputRoute{specs[0], 0, "Fake", 0}}; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -94,6 +99,8 @@ BOOST_AUTO_TEST_CASE(TestNoWaitMatcher) dh.dataDescription = "CLUSTERS"; dh.dataOrigin = "TPC"; dh.subSpecification = 0; + dh.splitPayloadIndex = 0; + dh.splitPayloadParts = 1; DataProcessingHeader dph{0, 1}; Stack stack{dh, dph}; @@ -101,12 +108,14 @@ BOOST_AUTO_TEST_CASE(TestNoWaitMatcher) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); BOOST_REQUIRE_EQUAL(ready.size(), 1); BOOST_CHECK_EQUAL(ready[0].slot.index, 0); BOOST_CHECK_EQUAL(ready[0].op, CompletionPolicy::CompletionOp::Consume); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); auto result = relayer.getInputsForTimeslice(ready[0].slot); // one MessageSet with one PartRef with header and payload BOOST_REQUIRE_EQUAL(result.size(), 1); @@ -135,7 +144,7 @@ BOOST_AUTO_TEST_CASE(TestRelay) std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAll(); DataRelayer relayer(policy, inputs, metrics, index); @@ -149,7 +158,9 @@ BOOST_AUTO_TEST_CASE(TestRelay) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); }; // Let's create a dummy O2 Message with two headers in the stack: @@ -158,12 +169,16 @@ BOOST_AUTO_TEST_CASE(TestRelay) dh1.dataDescription = "CLUSTERS"; dh1.dataOrigin = "TPC"; dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; // Let's create the second O2 Message: DataHeader dh2; dh2.dataDescription = "CLUSTERS"; dh2.dataOrigin = "ITS"; dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; createMessage(dh1, 0); std::vector<RecordAction> ready; @@ -206,7 +221,7 @@ BOOST_AUTO_TEST_CASE(TestRelayBug) std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::consumeWhenAll(); DataRelayer relayer(policy, inputs, metrics, index); @@ -220,7 +235,9 @@ BOOST_AUTO_TEST_CASE(TestRelayBug) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - relayer.relay(std::move(header), std::move(payload)); + relayer.relay(header, payload); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); }; // Let's create a dummy O2 Message with two headers in the stack: @@ -229,18 +246,24 @@ BOOST_AUTO_TEST_CASE(TestRelayBug) dh1.dataDescription = "CLUSTERS"; dh1.dataOrigin = "TPC"; dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; // Let's create the second O2 Message: DataHeader dh2; dh2.dataDescription = "CLUSTERS"; dh2.dataOrigin = "ITS"; dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; // Let's create the second O2 Message: DataHeader dh3; dh3.dataDescription = "CLUSTERS"; dh3.dataOrigin = "FOO"; dh3.subSpecification = 0; + dh3.splitPayloadIndex = 0; + dh3.splitPayloadParts = 1; /// Reproduce the bug reported by Matthias in https://github.com/AliceO2Group/AliceO2/pull/1483 createMessage(dh1, 0); @@ -279,7 +302,7 @@ BOOST_AUTO_TEST_CASE(TestCache) std::vector<ForwardRoute> forwards; auto policy = CompletionPolicyHelpers::consumeWhenAll(); - TimesliceIndex index; + TimesliceIndex index{1}; DataRelayer relayer(policy, inputs, metrics, index); // Only two messages to fill the cache. relayer.setPipelineLength(2); @@ -290,6 +313,8 @@ BOOST_AUTO_TEST_CASE(TestCache) dh.dataDescription = "CLUSTERS"; dh.dataOrigin = "TPC"; dh.subSpecification = 0; + dh.splitPayloadIndex = 0; + dh.splitPayloadParts = 1; DataProcessingHeader dph{0, 1}; auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); @@ -298,9 +323,11 @@ BOOST_AUTO_TEST_CASE(TestCache) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - relayer.relay(std::move(header), std::move(payload)); - assert(header.get() == nullptr); - assert(payload.get() == nullptr); + auto res = relayer.relay(header, payload); + BOOST_REQUIRE(res != DataRelayer::RelayChoice::WillRelay || header.get() == nullptr); + BOOST_REQUIRE(res != DataRelayer::RelayChoice::WillRelay || payload.get() == nullptr); + BOOST_REQUIRE(res != DataRelayer::RelayChoice::Backpressured || header.get() != nullptr); + BOOST_REQUIRE(res != DataRelayer::RelayChoice::Backpressured || payload.get() != nullptr); }; // This fills the cache, and then empties it. @@ -309,8 +336,8 @@ BOOST_AUTO_TEST_CASE(TestCache) std::vector<RecordAction> ready; relayer.getReadyToProcess(ready); BOOST_REQUIRE_EQUAL(ready.size(), 2); - BOOST_CHECK_EQUAL(ready[0].slot.index, 0); - BOOST_CHECK_EQUAL(ready[1].slot.index, 1); + BOOST_CHECK_EQUAL(ready[0].slot.index, 1); + BOOST_CHECK_EQUAL(ready[1].slot.index, 0); BOOST_CHECK_EQUAL(ready[0].op, CompletionPolicy::CompletionOp::Consume); BOOST_CHECK_EQUAL(ready[1].op, CompletionPolicy::CompletionOp::Consume); for (size_t i = 0; i < ready.size(); ++i) { @@ -346,7 +373,7 @@ BOOST_AUTO_TEST_CASE(TestPolicies) }; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::processWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -359,11 +386,15 @@ BOOST_AUTO_TEST_CASE(TestPolicies) dh1.dataDescription = "CLUSTERS"; dh1.dataOrigin = "TPC"; dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; DataHeader dh2; dh2.dataDescription = "TRACKS"; dh2.dataOrigin = "TPC"; dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); auto createMessage = [&transport, &relayer](DataHeader const& dh, DataProcessingHeader const& h) { @@ -371,7 +402,7 @@ BOOST_AUTO_TEST_CASE(TestPolicies) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - return relayer.relay(std::move(header), std::move(payload)); + return relayer.relay(header, payload); }; // This fills the cache, and then empties it. @@ -410,7 +441,7 @@ BOOST_AUTO_TEST_CASE(TestClear) }; std::vector<ForwardRoute> forwards; - TimesliceIndex index; + TimesliceIndex index{1}; auto policy = CompletionPolicyHelpers::processWhenAny(); DataRelayer relayer(policy, inputs, metrics, index); @@ -423,11 +454,15 @@ BOOST_AUTO_TEST_CASE(TestClear) dh1.dataDescription = "CLUSTERS"; dh1.dataOrigin = "TPC"; dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; DataHeader dh2; dh2.dataDescription = "TRACKS"; dh2.dataOrigin = "TPC"; dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); auto createMessage = [&transport, &relayer](DataHeader const& dh, DataProcessingHeader const& h) { @@ -435,7 +470,7 @@ BOOST_AUTO_TEST_CASE(TestClear) FairMQMessagePtr header = transport->CreateMessage(stack.size()); FairMQMessagePtr payload = transport->CreateMessage(1000); memcpy(header->GetData(), stack.data(), stack.size()); - return relayer.relay(std::move(header), std::move(payload)); + return relayer.relay(header, payload); }; // This fills the cache, and then empties it. @@ -447,3 +482,114 @@ BOOST_AUTO_TEST_CASE(TestClear) relayer.getReadyToProcess(ready); BOOST_REQUIRE_EQUAL(ready.size(), 0); } + +/// Test that the clear method actually works. +BOOST_AUTO_TEST_CASE(TestTooMany) +{ + Monitoring metrics; + InputSpec spec1{"clusters", "TPC", "CLUSTERS"}; + InputSpec spec2{"tracks", "TPC", "TRACKS"}; + + std::vector<InputRoute> inputs = { + InputRoute{spec1, 0, "Fake1", 0}, + InputRoute{spec2, 1, "Fake2", 0}, + }; + + std::vector<ForwardRoute> forwards; + TimesliceIndex index{1}; + + auto policy = CompletionPolicyHelpers::processWhenAny(); + DataRelayer relayer(policy, inputs, metrics, index); + // Only two messages to fill the cache. + relayer.setPipelineLength(1); + + // Let's create a dummy O2 Message with two headers in the stack: + // - DataHeader matching the one provided in the input + DataHeader dh1; + dh1.dataDescription = "CLUSTERS"; + dh1.dataOrigin = "TPC"; + dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; + + DataHeader dh2; + dh2.dataDescription = "TRACKS"; + dh2.dataOrigin = "TPC"; + dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; + + auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); + + Stack s1{dh1, DataProcessingHeader{0, 1}}; + FairMQMessagePtr header = transport->CreateMessage(s1.size()); + FairMQMessagePtr payload = transport->CreateMessage(1000); + memcpy(header->GetData(), s1.data(), s1.size()); + relayer.relay(header, payload); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); + // This fills the cache, and then waits. + Stack s2{dh1, DataProcessingHeader{1, 1}}; + FairMQMessagePtr header2 = transport->CreateMessage(s2.size()); + FairMQMessagePtr payload2 = transport->CreateMessage(1000); + memcpy(header2->GetData(), s2.data(), s2.size()); + auto action = relayer.relay(header2, payload2); + BOOST_CHECK_EQUAL(action, DataRelayer::Backpressured); + BOOST_CHECK_NE(header2.get(), nullptr); + BOOST_CHECK_NE(payload2.get(), nullptr); +} + +BOOST_AUTO_TEST_CASE(SplitParts) +{ + Monitoring metrics; + InputSpec spec1{"clusters", "TPC", "CLUSTERS"}; + InputSpec spec2{"its", "ITS", "CLUSTERS"}; + + std::vector<InputRoute> inputs = { + InputRoute{spec1, 0, "Fake1", 0}, + InputRoute{spec2, 0, "Fake2", 0}, + }; + + std::vector<ForwardRoute> forwards; + TimesliceIndex index{1}; + + auto policy = CompletionPolicyHelpers::processWhenAny(); + DataRelayer relayer(policy, inputs, metrics, index); + // Only two messages to fill the cache. + relayer.setPipelineLength(1); + + // Let's create a dummy O2 Message with two headers in the stack: + // - DataHeader matching the one provided in the input + DataHeader dh1; + dh1.dataDescription = "CLUSTERS"; + dh1.dataOrigin = "TPC"; + dh1.subSpecification = 0; + dh1.splitPayloadIndex = 0; + dh1.splitPayloadParts = 1; + + DataHeader dh2; + dh2.dataDescription = "TRACKS"; + dh2.dataOrigin = "TPC"; + dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; + + auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); + + Stack s1{dh1, DataProcessingHeader{0, 1}}; + FairMQMessagePtr header = transport->CreateMessage(s1.size()); + FairMQMessagePtr payload = transport->CreateMessage(1000); + memcpy(header->GetData(), s1.data(), s1.size()); + relayer.relay(header, payload); + BOOST_CHECK_EQUAL(header.get(), nullptr); + BOOST_CHECK_EQUAL(payload.get(), nullptr); + // This fills the cache, and then waits. + Stack s2{dh1, DataProcessingHeader{1, 1}}; + FairMQMessagePtr header2 = transport->CreateMessage(s2.size()); + FairMQMessagePtr payload2 = transport->CreateMessage(1000); + memcpy(header2->GetData(), s2.data(), s2.size()); + auto action = relayer.relay(header2, payload2); + BOOST_CHECK_EQUAL(action, DataRelayer::Backpressured); + BOOST_CHECK_NE(header2.get(), nullptr); + BOOST_CHECK_NE(payload2.get(), nullptr); +} diff --git a/Framework/Core/test/test_DeviceConfigInfo.cxx b/Framework/Core/test/test_DeviceConfigInfo.cxx index de38eecc02164..e3890754effcd 100644 --- a/Framework/Core/test/test_DeviceConfigInfo.cxx +++ b/Framework/Core/test/test_DeviceConfigInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,10 +14,32 @@ #include "Framework/DeviceConfigInfo.h" #include "Framework/DeviceInfo.h" +#include "Framework/Variant.h" #include <boost/test/unit_test.hpp> +#include <boost/tokenizer.hpp> +#include <boost/lexical_cast.hpp> #include <string_view> +#include <regex> -BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) +template <typename T> +std::string arrayPrinter(boost::property_tree::ptree const& tree) +{ + std::stringstream ss; + int size = tree.size(); + int count = 0; + ss << o2::framework::variant_array_symbol<T>::symbol << "["; + for (auto& element : tree) { + ss << element.second.get_value<T>(); + if (count < size - 1) { + ss << ","; + } + ++count; + } + ss << "]"; + return ss.str(); +} + +BOOST_AUTO_TEST_CASE(TestDeviceConfigInfo) { using namespace o2::framework; std::string configString; @@ -61,9 +84,9 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_REQUIRE_EQUAL(result, false); // Parse a simple configuration bit - configString = "foo[XX:XX:XX][INFO] [CONFIG] foo=bar 1789372894 prov\n"; + configString = "foo[XX:XX:XX][INFO] [CONFIG];foo=bar;1789372894;prov\n"; std::string_view config{configString.data() + 3, configString.size() - 4}; - BOOST_REQUIRE_EQUAL(config, std::string("[XX:XX:XX][INFO] [CONFIG] foo=bar 1789372894 prov")); + BOOST_REQUIRE_EQUAL(config, std::string("[XX:XX:XX][INFO] [CONFIG];foo=bar;1789372894;prov")); result = DeviceConfigHelper::parseConfig(config, match); BOOST_REQUIRE_EQUAL(result, true); BOOST_CHECK(strncmp(match.beginKey, "foo", 3) == 0); @@ -76,4 +99,22 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(result, true); BOOST_CHECK_EQUAL(info.currentConfig.get<std::string>("foo"), "bar"); BOOST_CHECK_EQUAL(info.currentProvenance.get<std::string>("foo"), "prov"); + + // Parse an array + configString = "foo[XX:XX:XX][INFO] [CONFIG];array={\"\":\"1\",\"\":\"2\",\"\":\"3\",\"\":\"4\",\"\":\"5\"};1789372894;prov\n"; + std::string_view configa{configString.data() + 3, configString.size() - 4}; + result = DeviceConfigHelper::parseConfig(configa, match); + auto valueString = std::string(match.beginValue, match.endValue - match.beginValue); + + BOOST_REQUIRE_EQUAL(result, true); + BOOST_CHECK(strncmp(match.beginKey, "array", 5) == 0); + BOOST_CHECK_EQUAL(match.timestamp, 1789372894); + BOOST_CHECK(strncmp(match.beginValue, "{\"\":\"1\",\"\":\"2\",\"\":\"3\",\"\":\"4\",\"\":\"5\"}", 35) == 0); + BOOST_CHECK(strncmp(match.beginProvenance, "prov", 4) == 0); + + // Process a given config entry + result = DeviceConfigHelper::processConfig(match, info); + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(info.currentProvenance.get<std::string>("array"), "prov"); + BOOST_CHECK_EQUAL(arrayPrinter<int>(info.currentConfig.get_child("array")), "i[1,2,3,4,5]"); } diff --git a/Framework/Core/test/test_DeviceMetricsInfo.cxx b/Framework/Core/test/test_DeviceMetricsInfo.cxx index 9b056b315549d..b0fa81047caf8 100644 --- a/Framework/Core/test/test_DeviceMetricsInfo.cxx +++ b/Framework/Core/test/test_DeviceMetricsInfo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #define BOOST_TEST_DYN_LINK #include "Framework/DeviceMetricsInfo.h" +#include "Framework/DeviceMetricsHelper.h" #include <boost/test/unit_test.hpp> #include <iostream> #include <regex> @@ -38,9 +40,10 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) // Add the first metric to the store result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); - BOOST_CHECK_EQUAL(info.metricLabelsIdx.size(), 1); - BOOST_CHECK(strncmp(info.metricLabelsIdx[0].label, "bkey", 4) == 0); - BOOST_CHECK_EQUAL(info.metricLabelsIdx[0].index, 0); + BOOST_CHECK_EQUAL(info.metricLabelsAlphabeticallySortedIdx.size(), 1); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 1); + BOOST_CHECK(strncmp(info.metricLabels[0].label, "bkey", 4) == 0); + BOOST_CHECK_EQUAL(info.metricLabelsAlphabeticallySortedIdx[0].index, 0); BOOST_CHECK_EQUAL(info.intMetrics.size(), 1); BOOST_CHECK_EQUAL(info.floatMetrics.size(), 0); BOOST_CHECK_EQUAL(info.timestamps.size(), 1); @@ -60,7 +63,7 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(match.intValue, 13); result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); - BOOST_CHECK_EQUAL(info.metricLabelsIdx.size(), 1); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 1); BOOST_CHECK_EQUAL(info.intMetrics.size(), 1); BOOST_CHECK_EQUAL(info.intMetrics[0][0], 12); BOOST_CHECK_EQUAL(info.intMetrics[0][1], 13); @@ -73,7 +76,7 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(result, true); result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); - BOOST_CHECK_EQUAL(info.metricLabelsIdx.size(), 2); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 2); BOOST_CHECK_EQUAL(info.intMetrics.size(), 2); BOOST_CHECK_EQUAL(info.intMetrics[0][0], 12); BOOST_CHECK_EQUAL(info.intMetrics[0][1], 13); @@ -90,7 +93,7 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(result, true); result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); - BOOST_CHECK_EQUAL(info.metricLabelsIdx.size(), 3); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 3); BOOST_CHECK_EQUAL(info.intMetrics.size(), 2); BOOST_CHECK_EQUAL(info.floatMetrics.size(), 1); BOOST_CHECK_EQUAL(info.metrics.size(), 3); @@ -106,7 +109,7 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(result, true); result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); - BOOST_CHECK_EQUAL(info.metricLabelsIdx.size(), 3); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 3); BOOST_CHECK_EQUAL(info.intMetrics.size(), 2); BOOST_CHECK_EQUAL(info.floatMetrics.size(), 1); BOOST_CHECK_EQUAL(info.metrics.size(), 3); @@ -128,6 +131,29 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo) BOOST_CHECK_EQUAL(result, true); result = DeviceMetricsHelper::processMetric(match, info); BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 4); + BOOST_CHECK_EQUAL(info.metricLabelsAlphabeticallySortedIdx.size(), 4); + BOOST_CHECK_EQUAL(info.metrics.size(), 4); + BOOST_CHECK_EQUAL(info.stringMetrics.size(), 1); + BOOST_CHECK_EQUAL(info.metrics[3].type, MetricType::String); + BOOST_CHECK_EQUAL(info.metrics[3].storeIdx, 0); + BOOST_CHECK_EQUAL(info.metrics[3].pos, 1); + + // Parse a string metric with a file description in it + memset(&match, 0, sizeof(match)); + metric = "[METRIC] alien-file-name,1 alien:///alice/data/2015/LHC15o/000244918/pass5_lowIR/PWGZZ/Run3_Conversion/96_20201013-1346_child_1/0028/AO2D.root:/,631838549,ALICE::CERN::EOS 1789372895 hostname=test.cern.ch"; + result = DeviceMetricsHelper::parseMetric(metric, match); + BOOST_CHECK_EQUAL(result, true); + result = DeviceMetricsHelper::processMetric(match, info); + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(info.metricLabels.size(), 5); + BOOST_CHECK_EQUAL(info.metricLabelsAlphabeticallySortedIdx.size(), 5); + BOOST_CHECK_EQUAL(info.metrics.size(), 5); + BOOST_CHECK_EQUAL(info.stringMetrics.size(), 2); + BOOST_CHECK_EQUAL(info.metrics[4].type, MetricType::String); + BOOST_CHECK_EQUAL(info.metrics[4].storeIdx, 1); + BOOST_CHECK_EQUAL(info.metrics[4].pos, 1); + BOOST_CHECK_EQUAL(std::string(info.stringMetrics[1][0].data), std::string("alien:///alice/data/2015/LHC15o/000244918/pass5_lowIR/PWGZZ/Run3_Conversion/96_20201013-1346_child_1/0028/AO2D.root:/,631838549,ALICE::CERN::EOS")); } BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo2) @@ -185,3 +211,15 @@ BOOST_AUTO_TEST_CASE(TestDeviceMetricsInfo2) BOOST_CHECK_EQUAL(info.uint64Metrics[0][1], 1025); BOOST_CHECK_EQUAL(info.uint64Metrics[0][2], 2); } + +BOOST_AUTO_TEST_CASE(TestHelpers) +{ + using namespace o2::framework; + DeviceMetricsInfo info; + auto metric1 = DeviceMetricsHelper::bookMetricInfo(info, "bkey"); + auto metric2 = DeviceMetricsHelper::bookMetricInfo(info, "bkey"); + auto metric3 = DeviceMetricsHelper::bookMetricInfo(info, "akey"); + BOOST_CHECK_EQUAL(metric1, 0); + BOOST_CHECK_EQUAL(metric2, 0); + BOOST_CHECK_EQUAL(metric3, 1); +} diff --git a/Framework/Core/test/test_DeviceSpec.cxx b/Framework/Core/test/test_DeviceSpec.cxx index fcf2f096e61d5..546abd9e5786f 100644 --- a/Framework/Core/test/test_DeviceSpec.cxx +++ b/Framework/Core/test/test_DeviceSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include <boost/test/unit_test.hpp> #include "../src/ChannelSpecHelpers.h" #include "../src/DeviceSpecHelpers.h" @@ -40,7 +42,8 @@ WorkflowSpec defineDataProcessing1() BOOST_AUTO_TEST_CASE(TestDeviceSpec1) { auto workflow = defineDataProcessing1(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); BOOST_REQUIRE_EQUAL(channelPolicies.empty(), false); BOOST_REQUIRE_EQUAL(completionPolicies.empty(), false); @@ -80,10 +83,11 @@ BOOST_AUTO_TEST_CASE(TestDeviceSpec1PushPull) auto workflow = defineDataProcessing1(); ChannelConfigurationPolicy pushPullPolicy; pushPullPolicy.match = ChannelConfigurationPolicyHelpers::matchAny; - pushPullPolicy.modifyInput = ChannelConfigurationPolicyHelpers::pullInput; - pushPullPolicy.modifyOutput = ChannelConfigurationPolicyHelpers::pushOutput; + pushPullPolicy.modifyInput = ChannelConfigurationPolicyHelpers::pullInput({60}); + pushPullPolicy.modifyOutput = ChannelConfigurationPolicyHelpers::pushOutput({60}); std::vector<ChannelConfigurationPolicy> channelPolicies = {pushPullPolicy}; + auto configContext = makeEmptyConfigContext(); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); BOOST_REQUIRE_EQUAL(channelPolicies.empty(), false); @@ -128,7 +132,8 @@ WorkflowSpec defineDataProcessing2() BOOST_AUTO_TEST_CASE(TestDeviceSpec2) { auto workflow = defineDataProcessing2(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<DeviceSpec> devices; @@ -170,7 +175,8 @@ WorkflowSpec defineDataProcessing3() BOOST_AUTO_TEST_CASE(TestDeviceSpec3) { auto workflow = defineDataProcessing3(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<DeviceSpec> devices; @@ -218,7 +224,8 @@ WorkflowSpec defineDataProcessing4() BOOST_AUTO_TEST_CASE(TestDeviceSpec4) { auto workflow = defineDataProcessing4(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<DeviceSpec> devices; std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; @@ -287,7 +294,8 @@ WorkflowSpec defineDataProcessing5() BOOST_AUTO_TEST_CASE(TestTopologyForwarding) { auto workflow = defineDataProcessing5(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<DeviceSpec> devices; @@ -404,7 +412,8 @@ BOOST_AUTO_TEST_CASE(TestOutEdgeProcessingHelpers) }; WorkflowSpec workflow = defineDataProcessing7(); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); @@ -413,7 +422,7 @@ BOOST_AUTO_TEST_CASE(TestOutEdgeProcessingHelpers) defaultOffer.memory = 0.01; DeviceSpecHelpers::processOutEdgeActions(devices, deviceIndex, connections, rm, edgeOutIndex, logicalEdges, - actions, workflow, globalOutputs, channelPolicies, defaultOffer); + actions, workflow, globalOutputs, channelPolicies, "", defaultOffer); std::vector<DeviceId> expectedDeviceIndex = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 1}, {1, 0, 1}, {1, 1, 2}, {1, 1, 2}, {1, 2, 3}, {1, 2, 3}}; BOOST_REQUIRE_EQUAL(devices.size(), 4); // For producers @@ -461,7 +470,7 @@ BOOST_AUTO_TEST_CASE(TestOutEdgeProcessingHelpers) std::sort(connections.begin(), connections.end()); DeviceSpecHelpers::processInEdgeActions(devices, deviceIndex, connections, rm, edgeInIndex, logicalEdges, - inActions, workflow, availableForwardsInfo, channelPolicies, defaultOffer); + inActions, workflow, availableForwardsInfo, channelPolicies, "", defaultOffer); // std::vector<DeviceId> expectedDeviceIndexFinal = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 1}, {1, 0, 1}, {1, 1, 2}, {1, 1, 2}, {1, 2, 3}, {1, 2, 3}, {2, 0, 4}, {2, 1, 5}}; BOOST_REQUIRE_EQUAL(expectedDeviceIndexFinal.size(), deviceIndex.size()); @@ -566,7 +575,8 @@ BOOST_AUTO_TEST_CASE(TestTopologyLayeredTimePipeline) { auto workflow = defineDataProcessing7(); std::vector<DeviceSpec> devices; - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); @@ -690,7 +700,8 @@ BOOST_AUTO_TEST_CASE(TestSimpleWildcard) auto workflow = defineDataProcessing8(); std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); std::vector<DeviceSpec> devices; std::vector<DeviceId> deviceIndex; @@ -729,7 +740,7 @@ BOOST_AUTO_TEST_CASE(TestSimpleWildcard) defaultOffer.memory = 0.01; DeviceSpecHelpers::processOutEdgeActions(devices, deviceIndex, connections, rm, edgeOutIndex, logicalEdges, - outActions, workflow, globalOutputs, channelPolicies, defaultOffer); + outActions, workflow, globalOutputs, channelPolicies, "", defaultOffer); BOOST_REQUIRE_EQUAL(devices.size(), 2); // Two devices have outputs: A and Timer BOOST_CHECK_EQUAL(devices[0].name, "A"); @@ -745,7 +756,7 @@ BOOST_AUTO_TEST_CASE(TestSimpleWildcard) std::sort(connections.begin(), connections.end()); DeviceSpecHelpers::processInEdgeActions(devices, deviceIndex, connections, rm, edgeInIndex, logicalEdges, - inActions, workflow, availableForwardsInfo, channelPolicies, defaultOffer); + inActions, workflow, availableForwardsInfo, channelPolicies, "", defaultOffer); BOOST_REQUIRE_EQUAL(devices.size(), 3); // Now we also have B BOOST_CHECK_EQUAL(devices[0].name, "A"); diff --git a/Framework/Core/test/test_DeviceSpecHelpers.cxx b/Framework/Core/test/test_DeviceSpecHelpers.cxx index df953aab44dca..c06fbe378c4fe 100644 --- a/Framework/Core/test/test_DeviceSpecHelpers.cxx +++ b/Framework/Core/test/test_DeviceSpecHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include "Framework/WorkflowSpec.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DeviceExecution.h" @@ -22,12 +24,11 @@ #include <cstring> #include <vector> #include <map> +#include <cstring> #include "../src/SimpleResourceManager.h" #include "../src/ComputingResourceHelpers.h" -namespace o2 -{ -namespace framework +namespace o2::framework { using CheckMatrix = std::map<std::string, std::vector<std::pair<std::string, std::string>>>; @@ -63,7 +64,6 @@ void check(const std::vector<std::string>& arguments, for (auto const& arg : arguments) { output << " " << arg; } - std::cout << "checking for arguments: " << output.str() << std::endl; std::vector<DeviceExecution> deviceExecutions(deviceSpecs.size()); std::vector<DeviceControl> deviceControls(deviceSpecs.size()); @@ -76,19 +76,16 @@ void check(const std::vector<std::string>& arguments, workflowOptions, }); } - DeviceSpecHelpers::prepareArguments(true, true, + DeviceSpecHelpers::prepareArguments(true, true, 8080, dataProcessorInfos, deviceSpecs, deviceExecutions, deviceControls, "workflow-id"); - std::cout << "created execution for " << deviceSpecs.size() << " device(s)" << std::endl; - for (size_t index = 0; index < deviceSpecs.size(); index++) { const auto& deviceSpec = deviceSpecs[index]; const auto& deviceExecution = deviceExecutions[index]; - std::cout << deviceSpec.name << std::endl; std::stringstream execArgs; for (const auto& arg : deviceExecution.args) { if (arg == nullptr) { @@ -97,7 +94,6 @@ void check(const std::vector<std::string>& arguments, } execArgs << " " << arg; } - std::cout << execArgs.str() << std::endl; for (auto const& testCase : matrix[deviceSpec.name]) { BOOST_TEST_INFO(std::string("can not find option: ") + testCase.first + " " + testCase.second); BOOST_CHECK(search(deviceExecution, testCase.first, testCase.second)); @@ -136,8 +132,10 @@ BOOST_AUTO_TEST_CASE(test_prepareArguments) std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; auto rm = std::make_unique<SimpleResourceManager>(resources); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, - ChannelConfigurationPolicy::createDefaultPolicies(), + channelPolicies, CompletionPolicy::createDefaultPolicies(), deviceSpecs, *rm, "workflow-id"); @@ -179,5 +177,113 @@ BOOST_AUTO_TEST_CASE(test_prepareArguments) matrix["processor1"] = {{"--depth", "2"}, {"--foo", "bar"}, {"--mode", "default"}}; check({"--depth", "2", "--processor0", "--mode silly"}, workflowOptions, deviceSpecs, matrix); } -} // namespace framework -} // namespace o2 + +BOOST_AUTO_TEST_CASE(CheckOptionReworking) +{ + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--driver-client-backend", "foo"}}, + {}}; + DeviceSpecHelpers::reworkHomogeneousOption(infos, "--driver-client-backend", "stdout://"); + BOOST_REQUIRE_EQUAL(infos[0].cmdLineArgs[1], "foo"); + BOOST_REQUIRE_EQUAL(infos[1].cmdLineArgs[1], "foo"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--driver-client-backend", "foo"}}, + {{}, {}, {"--driver-client-backend", "bar"}}}; + BOOST_CHECK_THROW( + DeviceSpecHelpers::reworkHomogeneousOption(infos, "--driver-client-backend", "stdout://"), o2::framework::RuntimeErrorRef); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--driver-client-backend", "foo"}}, + {{}, {}, {"--driver-client-backend", "foo"}}}; + DeviceSpecHelpers::reworkHomogeneousOption(infos, "--driver-client-backend", "stdout://"); + BOOST_REQUIRE_EQUAL(infos[0].cmdLineArgs[1], "foo"); + BOOST_REQUIRE_EQUAL(infos[1].cmdLineArgs[1], "foo"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"foo", "bar"}}, + {{}, {}, {"fnjcnak", "foo"}}}; + DeviceSpecHelpers::reworkHomogeneousOption(infos, "--driver-client-backend", "stdout://"); + BOOST_REQUIRE_EQUAL(infos[0].cmdLineArgs[3], "stdout://"); + BOOST_REQUIRE_EQUAL(infos[1].cmdLineArgs[3], "stdout://"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"foo", "bar", "--driver-client-backend", "bar"}}, + {{}, {}, {"fnjcnak", "foo"}}}; + DeviceSpecHelpers::reworkHomogeneousOption(infos, "--driver-client-backend", "stdout://"); + BOOST_REQUIRE_EQUAL(infos[0].cmdLineArgs[3], "bar"); + BOOST_REQUIRE_EQUAL(infos[1].cmdLineArgs[3], "bar"); + } +} + +BOOST_AUTO_TEST_CASE(CheckIntegerReworking) +{ + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--readers", "2"}}, + {}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", nullptr, 1, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs[1], "2"); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs[1], "2"); + } + { + std::vector<DataProcessorInfo> infos = { + {}, + {}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", nullptr, 1, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs.size(), 0); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs.size(), 0); + } + { + std::vector<DataProcessorInfo> infos = { + {}, + {}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", []() { return 1; }, 3, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs[1], "1"); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs[1], "1"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--readers", "2"}}, + {{}, {}, {"--readers", "3"}}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", []() { return 1; }, 1, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs[1], "3"); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs[1], "3"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"--readers", "3"}}, + {{}, {}, {"--readers", "2"}}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", []() { return 1; }, 1, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs[1], "3"); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs[1], "3"); + } + { + std::vector<DataProcessorInfo> infos = { + {{}, {}, {"foo", "bar", "--readers", "3"}}, + {{}, {}, {"--readers", "2"}}}; + DeviceSpecHelpers::reworkIntegerOption( + infos, "--readers", []() { return 1; }, 1, [](long long x, long long y) { return x > y ? x : y; }); + BOOST_REQUIRE_EQUAL(infos[0].cmdLineArgs.size(), 4); + BOOST_REQUIRE_EQUAL(infos[1].cmdLineArgs.size(), 2); + BOOST_CHECK_EQUAL(infos[0].cmdLineArgs[3], "3"); + BOOST_CHECK_EQUAL(infos[1].cmdLineArgs[1], "3"); + } +} +} // namespace o2::framework diff --git a/Framework/Core/test/test_Expressions.cxx b/Framework/Core/test/test_Expressions.cxx index c188a5710af99..f9ad543cb152a 100644 --- a/Framework/Core/test/test_Expressions.cxx +++ b/Framework/Core/test/test_Expressions.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,39 +14,40 @@ #define BOOST_TEST_DYN_LINK #include "Framework/Configurable.h" -#include "../src/ExpressionHelpers.h" +#include "Framework/ExpressionHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AODReaderHelpers.h" #include <boost/test/unit_test.hpp> +#include <arrow/util/config.h> using namespace o2::framework; using namespace o2::framework::expressions; namespace nodes { -static BindingNode pt{"pt", atype::FLOAT}; -static BindingNode phi{"phi", atype::FLOAT}; -static BindingNode eta{"eta", atype::FLOAT}; +static BindingNode pt{"pt", 1, atype::FLOAT}; +static BindingNode phi{"phi", 2, atype::FLOAT}; +static BindingNode eta{"eta", 3, atype::FLOAT}; -static BindingNode tgl{"tgl", atype::FLOAT}; -static BindingNode signed1Pt{"signed1Pt", atype::FLOAT}; -static BindingNode testInt{"testInt", atype::INT32}; +static BindingNode tgl{"tgl", 4, atype::FLOAT}; +static BindingNode signed1Pt{"signed1Pt", 5, atype::FLOAT}; +static BindingNode testInt{"testInt", 6, atype::INT32}; } // namespace nodes namespace o2::aod::track { DECLARE_SOA_EXPRESSION_COLUMN(Pze, pz, float, o2::aod::track::tgl*(1.f / o2::aod::track::signed1Pt)); -} +} // namespace o2::aod::track BOOST_AUTO_TEST_CASE(TestTreeParsing) { expressions::Filter f = ((nodes::phi > 1) && (nodes::phi < 2)) && (nodes::eta < 1); - auto specs = createOperations(std::move(f)); + auto specs = createOperations(f); BOOST_REQUIRE_EQUAL(specs[0].left, (DatumSpec{1u, atype::BOOL})); BOOST_REQUIRE_EQUAL(specs[0].right, (DatumSpec{2u, atype::BOOL})); BOOST_REQUIRE_EQUAL(specs[0].result, (DatumSpec{0u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(specs[1].left, (DatumSpec{std::string{"eta"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(specs[1].left, (DatumSpec{std::string{"eta"}, 3, atype::FLOAT})); BOOST_REQUIRE_EQUAL(specs[1].right, (DatumSpec{LiteralNode::var_t{1}, atype::INT32})); BOOST_REQUIRE_EQUAL(specs[1].result, (DatumSpec{2u, atype::BOOL})); @@ -53,16 +55,16 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(specs[2].right, (DatumSpec{4u, atype::BOOL})); BOOST_REQUIRE_EQUAL(specs[2].result, (DatumSpec{1u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(specs[3].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(specs[3].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(specs[3].right, (DatumSpec{LiteralNode::var_t{2}, atype::INT32})); BOOST_REQUIRE_EQUAL(specs[3].result, (DatumSpec{4u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(specs[4].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(specs[4].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(specs[4].right, (DatumSpec{LiteralNode::var_t{1}, atype::INT32})); BOOST_REQUIRE_EQUAL(specs[4].result, (DatumSpec{3u, atype::BOOL})); expressions::Filter g = ((nodes::eta + 2.f) > 0.5) || ((nodes::phi - M_PI) < 3); - auto gspecs = createOperations(std::move(g)); + auto gspecs = createOperations(g); BOOST_REQUIRE_EQUAL(gspecs[0].left, (DatumSpec{1u, atype::BOOL})); BOOST_REQUIRE_EQUAL(gspecs[0].right, (DatumSpec{2u, atype::BOOL})); BOOST_REQUIRE_EQUAL(gspecs[0].result, (DatumSpec{0u, atype::BOOL})); @@ -71,7 +73,7 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(gspecs[1].right, (DatumSpec{LiteralNode::var_t{3}, atype::INT32})); BOOST_REQUIRE_EQUAL(gspecs[1].result, (DatumSpec{2u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(gspecs[2].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(gspecs[2].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(gspecs[2].right, (DatumSpec{LiteralNode::var_t{M_PI}, atype::DOUBLE})); BOOST_REQUIRE_EQUAL(gspecs[2].result, (DatumSpec{3u, atype::DOUBLE})); @@ -79,22 +81,22 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(gspecs[3].right, (DatumSpec{LiteralNode::var_t{0.5}, atype::DOUBLE})); BOOST_REQUIRE_EQUAL(gspecs[3].result, (DatumSpec{1u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(gspecs[4].left, (DatumSpec{std::string{"eta"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(gspecs[4].left, (DatumSpec{std::string{"eta"}, 3, atype::FLOAT})); BOOST_REQUIRE_EQUAL(gspecs[4].right, (DatumSpec{LiteralNode::var_t{2.f}, atype::FLOAT})); BOOST_REQUIRE_EQUAL(gspecs[4].result, (DatumSpec{4u, atype::FLOAT})); expressions::Filter h = (nodes::phi == 0) || (nodes::phi == 3); - auto hspecs = createOperations(std::move(h)); + auto hspecs = createOperations(h); BOOST_REQUIRE_EQUAL(hspecs[0].left, (DatumSpec{1u, atype::BOOL})); BOOST_REQUIRE_EQUAL(hspecs[0].right, (DatumSpec{2u, atype::BOOL})); BOOST_REQUIRE_EQUAL(hspecs[0].result, (DatumSpec{0u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(hspecs[1].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(hspecs[1].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(hspecs[1].right, (DatumSpec{LiteralNode::var_t{3}, atype::INT32})); BOOST_REQUIRE_EQUAL(hspecs[1].result, (DatumSpec{2u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(hspecs[2].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(hspecs[2].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(hspecs[2].right, (DatumSpec{LiteralNode::var_t{0}, atype::INT32})); BOOST_REQUIRE_EQUAL(hspecs[2].result, (DatumSpec{1u, atype::BOOL})); @@ -112,7 +114,7 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(uspecs[2].right, (DatumSpec{})); BOOST_REQUIRE_EQUAL(uspecs[2].result, (DatumSpec{3u, atype::DOUBLE})); - BOOST_REQUIRE_EQUAL(uspecs[3].left, (DatumSpec{std::string{"phi"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(uspecs[3].left, (DatumSpec{std::string{"phi"}, 2, atype::FLOAT})); BOOST_REQUIRE_EQUAL(uspecs[3].right, (DatumSpec{LiteralNode::var_t{2.0 * M_PI}, atype::DOUBLE})); BOOST_REQUIRE_EQUAL(uspecs[3].result, (DatumSpec{4u, atype::DOUBLE})); @@ -120,7 +122,7 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(uspecs[4].right, (DatumSpec{LiteralNode::var_t{1.0}, atype::DOUBLE})); BOOST_REQUIRE_EQUAL(uspecs[4].result, (DatumSpec{1u, atype::BOOL})); - BOOST_REQUIRE_EQUAL(uspecs[5].left, (DatumSpec{std::string{"eta"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(uspecs[5].left, (DatumSpec{std::string{"eta"}, 3, atype::FLOAT})); BOOST_REQUIRE_EQUAL(uspecs[5].right, (DatumSpec{})); BOOST_REQUIRE_EQUAL(uspecs[5].result, (DatumSpec{5u, atype::FLOAT})); @@ -130,7 +132,7 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_REQUIRE_EQUAL(ptfilter.node->left->self.index(), 1); BOOST_REQUIRE_EQUAL(ptfilter.node->right->self.index(), 3); auto ptfilterspecs = createOperations(ptfilter); - BOOST_REQUIRE_EQUAL(ptfilterspecs[0].left, (DatumSpec{std::string{"fPt"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(ptfilterspecs[0].left, (DatumSpec{std::string{"fPt"}, typeid(o2::aod::track::Pt).hash_code(), atype::FLOAT})); BOOST_REQUIRE_EQUAL(ptfilterspecs[0].right, (DatumSpec{LiteralNode::var_t{0.5f}, atype::FLOAT})); BOOST_REQUIRE_EQUAL(ptfilterspecs[0].result, (DatumSpec{0u, atype::BOOL})); } @@ -138,13 +140,13 @@ BOOST_AUTO_TEST_CASE(TestTreeParsing) BOOST_AUTO_TEST_CASE(TestGandivaTreeCreation) { Projector pze = o2::aod::track::Pze::Projector(); - auto pzspecs = createOperations(std::move(pze)); - BOOST_REQUIRE_EQUAL(pzspecs[0].left, (DatumSpec{std::string{"fTgl"}, atype::FLOAT})); + auto pzspecs = createOperations(pze); + BOOST_REQUIRE_EQUAL(pzspecs[0].left, (DatumSpec{std::string{"fTgl"}, typeid(o2::aod::track::Tgl).hash_code(), atype::FLOAT})); BOOST_REQUIRE_EQUAL(pzspecs[0].right, (DatumSpec{1u, atype::FLOAT})); BOOST_REQUIRE_EQUAL(pzspecs[0].result, (DatumSpec{0u, atype::FLOAT})); BOOST_REQUIRE_EQUAL(pzspecs[1].left, (DatumSpec{LiteralNode::var_t{1.f}, atype::FLOAT})); - BOOST_REQUIRE_EQUAL(pzspecs[1].right, (DatumSpec{std::string{"fSigned1Pt"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(pzspecs[1].right, (DatumSpec{std::string{"fSigned1Pt"}, typeid(o2::aod::track::Signed1Pt).hash_code(), atype::FLOAT})); BOOST_REQUIRE_EQUAL(pzspecs[1].result, (DatumSpec{1u, atype::FLOAT})); auto infield1 = o2::aod::track::Signed1Pt::asArrowField(); auto infield2 = o2::aod::track::Tgl::asArrowField(); @@ -157,13 +159,13 @@ BOOST_AUTO_TEST_CASE(TestGandivaTreeCreation) auto projector = createProjector(schema, pzspecs, resfield); Projector pte = o2::aod::track::Pt::Projector(); - auto ptespecs = createOperations(std::move(pte)); + auto ptespecs = createOperations(pte); BOOST_REQUIRE_EQUAL(ptespecs[0].left, (DatumSpec{1u, atype::FLOAT})); BOOST_REQUIRE_EQUAL(ptespecs[0].right, (DatumSpec{})); BOOST_REQUIRE_EQUAL(ptespecs[0].result, (DatumSpec{0u, atype::FLOAT})); BOOST_REQUIRE_EQUAL(ptespecs[1].left, (DatumSpec{LiteralNode::var_t{1.f}, atype::FLOAT})); - BOOST_REQUIRE_EQUAL(ptespecs[1].right, (DatumSpec{std::string{"fSigned1Pt"}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(ptespecs[1].right, (DatumSpec{std::string{"fSigned1Pt"}, typeid(o2::aod::track::Signed1Pt).hash_code(), atype::FLOAT})); BOOST_REQUIRE_EQUAL(ptespecs[1].result, (DatumSpec{1u, atype::FLOAT})); auto infield3 = o2::aod::track::Signed1Pt::asArrowField(); @@ -177,4 +179,82 @@ BOOST_AUTO_TEST_CASE(TestGandivaTreeCreation) auto projector_b = createProjector(schema2, ptespecs, resfield2); auto schema_p = o2::soa::createSchemaFromColumns(o2::aod::Tracks::persistent_columns_t{}); auto projector_alt = o2::framework::expressions::createProjectors(o2::framework::pack<o2::aod::track::Pt>{}, schema_p); + + Filter bitwiseFilter = (o2::aod::track::flags & static_cast<uint32_t>(o2::aod::track::TPCrefit)) != 0u; + auto bwf = createOperations(bitwiseFilter); + BOOST_REQUIRE_EQUAL(bwf[0].left, (DatumSpec{1u, atype::UINT32})); + BOOST_REQUIRE_EQUAL(bwf[0].right, (DatumSpec{LiteralNode::var_t{0u}, atype::UINT32})); + BOOST_REQUIRE_EQUAL(bwf[0].result, (DatumSpec{0u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(bwf[1].left, (DatumSpec{std::string{"fFlags"}, typeid(o2::aod::track::Flags).hash_code(), atype::UINT32})); + BOOST_REQUIRE_EQUAL(bwf[1].right, (DatumSpec{LiteralNode::var_t{static_cast<uint32_t>(o2::aod::track::TPCrefit)}, atype::UINT32})); + BOOST_REQUIRE_EQUAL(bwf[1].result, (DatumSpec{1u, atype::UINT32})); + + auto infield4 = o2::aod::track::Flags::asArrowField(); + auto resfield3 = std::make_shared<arrow::Field>("out", arrow::boolean()); + auto schema_b = std::make_shared<arrow::Schema>(std::vector{infield4, resfield3}); + auto gandiva_tree3 = createExpressionTree(bwf, schema_b); + BOOST_CHECK_EQUAL(gandiva_tree3->ToString(), "bool not_equal(uint32 bitwise_and((uint32) fFlags, (const uint32) 2), (const uint32) 0)"); + auto condition = expressions::makeCondition(gandiva_tree3); + std::shared_ptr<gandiva::Filter> flt; + auto s = gandiva::Filter::Make(schema_b, condition, &flt); + BOOST_REQUIRE(s.ok()); +} + +BOOST_AUTO_TEST_CASE(TestConditionalExpressions) +{ + // simple conditional + Filter cf = nabs(o2::aod::track::eta) < 1.0f && ifnode((o2::aod::track::pt < 1.0f), (o2::aod::track::phiraw > (float)(M_PI / 2.)), (o2::aod::track::phiraw < (float)(M_PI / 2.))); + auto cfspecs = createOperations(cf); + BOOST_REQUIRE_EQUAL(cfspecs[0].left, (DatumSpec{1u, atype::BOOL})); + BOOST_REQUIRE_EQUAL(cfspecs[0].right, (DatumSpec{2u, atype::BOOL})); + BOOST_REQUIRE_EQUAL(cfspecs[0].result, (DatumSpec{0u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[1].left, (DatumSpec{3u, atype::BOOL})); + BOOST_REQUIRE_EQUAL(cfspecs[1].right, (DatumSpec{4u, atype::BOOL})); + BOOST_REQUIRE_EQUAL(cfspecs[1].condition, (DatumSpec{5u, atype::BOOL})); + BOOST_REQUIRE_EQUAL(cfspecs[1].result, (DatumSpec{2u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[2].left, (DatumSpec{std::string{"fPt"}, typeid(o2::aod::track::Pt).hash_code(), atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[2].right, (DatumSpec{LiteralNode::var_t{1.0f}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[2].result, (DatumSpec{5u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[3].left, (DatumSpec{std::string{"fRawPhi"}, typeid(o2::aod::track::RawPhi).hash_code(), atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[3].right, (DatumSpec{LiteralNode::var_t{(float)(M_PI / 2.)}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[3].result, (DatumSpec{4u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[4].left, (DatumSpec{std::string{"fRawPhi"}, typeid(o2::aod::track::RawPhi).hash_code(), atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[4].right, (DatumSpec{LiteralNode::var_t{(float)(M_PI / 2.)}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[4].result, (DatumSpec{3u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[5].left, (DatumSpec{6u, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[5].right, (DatumSpec{LiteralNode::var_t{1.0f}, atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[5].result, (DatumSpec{1u, atype::BOOL})); + + BOOST_REQUIRE_EQUAL(cfspecs[6].left, (DatumSpec{std::string{"fEta"}, typeid(o2::aod::track::Eta).hash_code(), atype::FLOAT})); + BOOST_REQUIRE_EQUAL(cfspecs[6].right, (DatumSpec{})); + BOOST_REQUIRE_EQUAL(cfspecs[6].result, (DatumSpec{6u, atype::FLOAT})); + + auto infield1 = o2::aod::track::Pt::asArrowField(); + auto infield2 = o2::aod::track::Eta::asArrowField(); + auto infield3 = o2::aod::track::RawPhi::asArrowField(); + auto schema = std::make_shared<arrow::Schema>(std::vector{infield1, infield2, infield3}); + auto gandiva_tree = createExpressionTree(cfspecs, schema); + auto gandiva_condition = makeCondition(gandiva_tree); + auto gandiva_filter = createFilter(schema, gandiva_condition); + + BOOST_CHECK_EQUAL(gandiva_tree->ToString(), "bool less_than(float absf((float) fEta), (const float) 1 raw(3f800000)) && if (bool less_than((float) fPt, (const float) 1 raw(3f800000))) { bool greater_than((float) fRawPhi, (const float) 1.5708 raw(3fc90fdb)) } else { bool less_than((float) fRawPhi, (const float) 1.5708 raw(3fc90fdb)) }"); + + // nested conditional + Filter cfn = o2::aod::track::signed1Pt > 0.f && ifnode(std::move(*cf.node), nabs(o2::aod::track::x) > 1.0f, nabs(o2::aod::track::y) > 1.0f); + auto cfnspecs = createOperations(cfn); + auto infield4 = o2::aod::track::Signed1Pt::asArrowField(); + auto infield5 = o2::aod::track::X::asArrowField(); + auto infield6 = o2::aod::track::Y::asArrowField(); + auto schema2 = std::make_shared<arrow::Schema>(std::vector{infield1, infield2, infield3, infield4, infield5, infield6}); + auto gandiva_tree2 = createExpressionTree(cfnspecs, schema2); + auto gandiva_condition2 = makeCondition(gandiva_tree2); + auto gandiva_filter2 = createFilter(schema2, gandiva_condition2); + BOOST_REQUIRE_EQUAL(gandiva_tree2->ToString(), + "bool greater_than((float) fSigned1Pt, (const float) 0 raw(0)) && if (bool less_than(float absf((float) fEta), (const float) 1 raw(3f800000)) && if (bool less_than((float) fPt, (const float) 1 raw(3f800000))) { bool greater_than((float) fRawPhi, (const float) 1.5708 raw(3fc90fdb)) } else { bool less_than((float) fRawPhi, (const float) 1.5708 raw(3fc90fdb)) }) { bool greater_than(float absf((float) fX), (const float) 1 raw(3f800000)) } else { bool greater_than(float absf((float) fY), (const float) 1 raw(3f800000)) }"); } diff --git a/Framework/Core/test/test_ExternalFairMQDeviceProxy.cxx b/Framework/Core/test/test_ExternalFairMQDeviceProxy.cxx index 5a6cb474df7ae..26dc7a1dec4db 100644 --- a/Framework/Core/test/test_ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/test/test_ExternalFairMQDeviceProxy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx index 9adab2a7236a1..db47c951692e6 100644 --- a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx +++ b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ using namespace o2::framework; #include "Framework/DataSpecUtils.h" #include "Framework/ExternalFairMQDeviceProxy.h" #include "Framework/ControlService.h" +#include "Framework/CallbackService.h" #include "Framework/Logger.h" #include "Headers/DataHeader.h" #include "fairmq/FairMQDevice.h" @@ -30,13 +32,16 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) workflowOptions.push_back( ConfigParamSpec{ "number-of-events,n", VariantType::Int, 10, {"number of events to process"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "output-proxy-only", VariantType::Bool, false, {"create only the workflow up to output proxy"}}); } #include "Framework/runDataProcessing.h" #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed)"; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ } std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) @@ -59,8 +64,9 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) auto producerCallback = [nRolls, counter = std::make_shared<int>()](DataAllocator& outputs, ControlService& control) { outputs.make<int>(OutputRef{"data", 0}) = *counter; if (++(*counter) >= nRolls) { + // send the end of stream signal, this is transferred by the proxies + // and allows to properly terminate downstream devices control.endOfStream(); - control.readyToQuit(QuitRequest::Me); } }; @@ -96,26 +102,37 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) } Inputs sinkInputs = {InputSpec{"external", "TST", "DATA", 0, Lifetime::Timeframe}}; - workflow.emplace_back(std::move(specifyFairMQDeviceOutputProxy("dpl-sink", sinkInputs, channelConfig.c_str()))); + auto channelSelector = [](InputSpec const&, const std::unordered_map<std::string, std::vector<FairMQChannel>>&) -> std::string { + return "downstream"; + }; + workflow.emplace_back(std::move(specifyFairMQDeviceMultiOutputProxy("dpl-sink", sinkInputs, channelConfig.c_str(), channelSelector))); ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // a simple checker process subscribing to the output of the input proxy // // the compute callback of the checker - auto checkerCallback = [nRolls](InputRecord& inputs, ControlService& control) { + auto counter = std::make_shared<int>(0); + auto checkerCallback = [counter](InputRecord& inputs, ControlService& control) { LOG(DEBUG) << "got inputs " << inputs.size(); - if (inputs.get<int>("datain") == nRolls - 1) { - LOG(INFO) << "terminating after " << nRolls << " successful event(s)"; - control.endOfStream(); - control.readyToQuit(QuitRequest::All); + ASSERT_ERROR(inputs.get<int>("datain") == *counter); + ++(*counter); + }; + auto checkCounter = [counter, nRolls](EndOfStreamContext&) { + ASSERT_ERROR(*counter == nRolls); + if (*counter == nRolls) { + LOG(info) << "checker has received " << nRolls << " successful event(s)"; } }; + auto checkerInit = [checkerCallback, checkCounter](CallbackService& callbacks) { + callbacks.set(CallbackService::Id::EndOfStream, checkCounter); + return adaptStateless(checkerCallback); + }; // the checker process connects to the proxy workflow.emplace_back(DataProcessorSpec{"checker", {InputSpec{"datain", "PRX", "DATA", 0, Lifetime::Timeframe}}, {}, - AlgorithmSpec{adaptStateless(checkerCallback)}}); + AlgorithmSpec{adaptStateful(checkerInit)}}); ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // the input proxy process @@ -130,19 +147,23 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) int msgidx = 0; auto dh = o2::header::get<o2::header::DataHeader*>(inputs.At(msgidx)->GetData()); if (!dh) { - LOG(ERROR) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; return; } auto dph = o2::header::get<DataProcessingHeader*>(inputs.At(msgidx)->GetData()); if (!dph) { - LOG(ERROR) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; return; } // Note: we want to run both the output and input proxy in the same workflow and thus we need // different data identifiers and change the data origin in the forwarding OutputSpec query{"PRX", dh->dataDescription, dh->subSpecification}; auto channelName = channelRetriever(query, dph->startTime); - ASSERT_ERROR(!channelName.empty()); + bool isData = DataSpecUtils::match(OutputSpec{"TST", "DATA", 0}, dh->dataOrigin, dh->dataDescription, dh->subSpecification); + // for the configured data channel we require the channel name, the EOS message containing + // the forwarded SourceInfoHeader created by the output proxy will be skipped here since the + // input proxy handles this internally + ASSERT_ERROR(!isData || !channelName.empty()); LOG(DEBUG) << "using channel '" << channelName << "' for " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}); if (channelName.empty()) { return; @@ -183,5 +204,10 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const& config) channelConfig.c_str(), converter)); + if (config.options().get<bool>("output-proxy-only")) { + // remove the input proxy and checker from the workflow + workflow.pop_back(); + workflow.pop_back(); + } return workflow; } diff --git a/Framework/Core/test/test_FairMQ.cxx b/Framework/Core/test/test_FairMQ.cxx new file mode 100644 index 0000000000000..b7141dc2a4331 --- /dev/null +++ b/Framework/Core/test/test_FairMQ.cxx @@ -0,0 +1,228 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test O2Device +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include "Headers/NameHeader.h" + +#include "MemoryResources/MemoryResources.h" +#include "Headers/DataHeader.h" +#include "Headers/Stack.h" + +#include <boost/test/unit_test.hpp> +#include <iostream> +#include <vector> +#include <fairmq/Tools.h> +#include <fairmq/ProgOptions.h> +#include <gsl/gsl> + +using namespace o2::header; +using namespace o2::pmr; + +//__________________________________________________________________________________________________ +// addDataBlock for generic (compatible) containers, that is contiguous containers using the pmr allocator +template <typename ContainerT, typename std::enable_if<!std::is_same<ContainerT, FairMQMessagePtr>::value, int>::type = 0> +bool addDataBlock(FairMQParts& parts, o2::header::Stack&& inputStack, ContainerT&& inputData, o2::pmr::FairMQMemoryResource* targetResource = nullptr) +{ + using std::forward; + using std::move; + + auto headerMessage = o2::pmr::getMessage(move(inputStack), targetResource); + auto dataMessage = o2::pmr::getMessage(forward<ContainerT>(inputData), targetResource); + + parts.AddPart(move(headerMessage)); + parts.AddPart(move(dataMessage)); + + return true; +} + +//__________________________________________________________________________________________________ +// addDataBlock for data already wrapped in FairMQMessagePtr +// note: since we cannot partially specialize function templates, use SFINAE here instead +template <typename ContainerT, typename std::enable_if<std::is_same<ContainerT, FairMQMessagePtr>::value, int>::type = 0> +bool addDataBlock(FairMQParts& parts, o2::header::Stack&& inputStack, ContainerT&& dataMessage, o2::pmr::FairMQMemoryResource* targetResource = nullptr) +{ + using std::move; + + //make sure the payload size in DataHeader corresponds to message size + using o2::header::DataHeader; + DataHeader* dataHeader = const_cast<DataHeader*>(o2::header::get<DataHeader*>(inputStack.data())); + dataHeader->payloadSize = dataMessage->GetSize(); + + auto headerMessage = o2::pmr::getMessage(move(inputStack), targetResource); + + parts.AddPart(move(headerMessage)); + parts.AddPart(move(dataMessage)); + + return true; +} + +template <typename I, typename F> +auto forEach(I begin, I end, F&& function) +{ + + using span = gsl::span<const std::byte>; + using SPAN_SIZE_TYPE = span::size_type; + using gsl::narrow_cast; + for (auto it = begin; it != end; ++it) { + std::byte* headerBuffer{nullptr}; + SPAN_SIZE_TYPE headerBufferSize{0}; + if (*it != nullptr) { + headerBuffer = reinterpret_cast<std::byte*>((*it)->GetData()); + headerBufferSize = narrow_cast<SPAN_SIZE_TYPE>((*it)->GetSize()); + } + ++it; + std::byte* dataBuffer{nullptr}; + SPAN_SIZE_TYPE dataBufferSize{0}; + if (*it != nullptr) { + dataBuffer = reinterpret_cast<std::byte*>((*it)->GetData()); + dataBufferSize = narrow_cast<SPAN_SIZE_TYPE>((*it)->GetSize()); + } + + // call the user provided function + function(span{headerBuffer, headerBufferSize}, span{dataBuffer, dataBufferSize}); + } + return std::move(function); +} + +/// Execute user code (e.g. a lambda) on each data block (header-payload pair) +/// returns the function (same as std::for_each) +template <typename F> +auto forEach(FairMQParts& parts, F&& function) +{ + if ((parts.Size() % 2) != 0) { + throw std::invalid_argument( + "number of parts in message not even (n%2 != 0), cannot be considered an O2 compliant message"); + } + + return forEach(parts.begin(), parts.end(), std::forward<F>(function)); +} + +BOOST_AUTO_TEST_CASE(getMessage_Stack) +{ + size_t session{fair::mq::tools::UuidHash()}; + fair::mq::ProgOptions config; + config.SetProperty<std::string>("session", std::to_string(session)); + + auto factoryZMQ = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto factorySHM = FairMQTransportFactory::CreateTransportFactory("shmem"); + BOOST_REQUIRE(factorySHM != nullptr); + BOOST_REQUIRE(factoryZMQ != nullptr); + auto allocZMQ = getTransportAllocator(factoryZMQ.get()); + BOOST_REQUIRE(allocZMQ != nullptr); + auto allocSHM = getTransportAllocator(factorySHM.get()); + BOOST_REQUIRE(allocSHM != nullptr); + { + //check that a message is constructed properly with the default new_delete_resource + Stack s1{DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}, + NameHeader<9>{"somename"}}; + + auto message = o2::pmr::getMessage(std::move(s1), allocZMQ); + + BOOST_REQUIRE(s1.data() == nullptr); + BOOST_REQUIRE(message != nullptr); + auto* h3 = get<NameHeader<0>*>(message->GetData()); + BOOST_REQUIRE(h3 != nullptr); + BOOST_CHECK(h3->getNameLength() == 9); + BOOST_CHECK(0 == std::strcmp(h3->getName(), "somename")); + BOOST_CHECK(message->GetType() == fair::mq::Transport::ZMQ); + } + { + //check that a message is constructed properly, cross resource + Stack s1{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}, + NameHeader<9>{"somename"}}; + BOOST_TEST(allocZMQ->getNumberOfMessages() == 1); + + auto message = o2::pmr::getMessage(std::move(s1), allocSHM); + + BOOST_TEST(allocZMQ->getNumberOfMessages() == 0); + BOOST_TEST(allocSHM->getNumberOfMessages() == 0); + BOOST_REQUIRE(s1.data() == nullptr); + BOOST_REQUIRE(message != nullptr); + auto* h3 = get<NameHeader<0>*>(message->GetData()); + BOOST_REQUIRE(h3 != nullptr); + BOOST_CHECK(h3->getNameLength() == 9); + BOOST_CHECK(0 == std::strcmp(h3->getName(), "somename")); + BOOST_CHECK(message->GetType() == fair::mq::Transport::SHM); + } +} + +BOOST_AUTO_TEST_CASE(addDataBlockForEach_test) +{ + size_t session{fair::mq::tools::UuidHash()}; + fair::mq::ProgOptions config; + config.SetProperty<std::string>("session", std::to_string(session)); + + auto factoryZMQ = FairMQTransportFactory::CreateTransportFactory("zeromq"); + BOOST_REQUIRE(factoryZMQ); + auto allocZMQ = getTransportAllocator(factoryZMQ.get()); + BOOST_REQUIRE(allocZMQ); + + { + //simple addition of a data block from an exisiting message + FairMQParts message; + auto simpleMessage = factoryZMQ->CreateMessage(10); + addDataBlock(message, + Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, + std::move(simpleMessage)); + BOOST_CHECK(message.Size() == 2); + } + + { + int sizeofDataHeader = sizeof(o2::header::DataHeader); + struct elem { + int i; + int j; + }; + using namespace boost::container::pmr; + FairMQParts message; + std::vector<elem, polymorphic_allocator<elem>> vec(polymorphic_allocator<elem>{allocZMQ}); + vec.reserve(100); + vec.push_back({1, 2}); + vec.push_back({3, 4}); + + addDataBlock(message, + Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, + std::move(vec)); + BOOST_CHECK(message.Size() == 2); + BOOST_CHECK(vec.size() == 0); + BOOST_CHECK(message[0].GetSize() == sizeofDataHeader); + BOOST_CHECK(message[1].GetSize() == 2 * sizeof(elem)); //check the size of the buffer is set correctly + + //check contents + int sum{0}; + forEach(message, [&](auto header, auto data) { + const int* numbers = reinterpret_cast<const int*>(data.data()); + sum = numbers[0] + numbers[1] + numbers[2] + numbers[3]; + }); + BOOST_CHECK(sum == 10); + + //add one more data block and check total size using forEach; + addDataBlock(message, + Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, + factoryZMQ->CreateMessage(10)); + int size{0}; + forEach(message, [&](auto header, auto data) { size += header.size() + data.size(); }); + BOOST_CHECK(size == sizeofDataHeader + 2 * sizeof(elem) + sizeofDataHeader + 10); + + //check contents (headers) + int checkOK{0}; + forEach(message, [&](auto header, auto data) { + auto dh = get<DataHeader*>(header.data()); + if (dh->dataDescription == gDataDescriptionInvalid && dh->dataOrigin == gDataOriginInvalid) { + checkOK++; + }; + }); + BOOST_CHECK(checkOK == 2); + } +} diff --git a/Framework/Core/test/test_FairMQOptionsRetriever.cxx b/Framework/Core/test/test_FairMQOptionsRetriever.cxx index e0bacd9169ea8..f3fe7685c339d 100644 --- a/Framework/Core/test/test_FairMQOptionsRetriever.cxx +++ b/Framework/Core/test/test_FairMQOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_FairMQResizableBuffer.cxx b/Framework/Core/test/test_FairMQResizableBuffer.cxx index 7885ba5ea0f91..b38d81f0b4d94 100644 --- a/Framework/Core/test/test_FairMQResizableBuffer.cxx +++ b/Framework/Core/test/test_FairMQResizableBuffer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include <arrow/io/memory.h> #include <arrow/ipc/writer.h> #include <ROOT/RDataFrame.hxx> +#include <arrow/util/config.h> using namespace o2::framework; @@ -70,7 +72,7 @@ BOOST_AUTO_TEST_CASE(TestInvariants) status = buffer.Resize(9000, true); BOOST_REQUIRE(status.ok()); - BOOST_REQUIRE_EQUAL(buffer.capacity(), 9000); + BOOST_REQUIRE_EQUAL(buffer.capacity(), 11000); BOOST_REQUIRE_EQUAL(buffer.size(), 9000); status = buffer.Resize(19000, true); @@ -112,7 +114,7 @@ BOOST_AUTO_TEST_CASE(TestContents) status = buffer.Resize(40, true); BOOST_REQUIRE(status.ok()); - BOOST_REQUIRE_EQUAL(buffer.capacity(), 40); + BOOST_REQUIRE_EQUAL(buffer.capacity(), 9000); BOOST_REQUIRE_EQUAL(buffer.size(), 40); BOOST_REQUIRE(strncmp((const char*)buffer.data(), "foo", 3) == 0); } @@ -131,12 +133,12 @@ BOOST_AUTO_TEST_CASE(TestStreaming) auto table = builder.finalize(); auto transport = FairMQTransportFactory::CreateTransportFactory("zeromq"); auto creator = [&transport](size_t size) -> std::unique_ptr<FairMQMessage> { - return std::move(transport->CreateMessage(size)); + return transport->CreateMessage(size); }; auto buffer = std::make_shared<FairMQResizableBuffer>(creator); /// Writing to a stream auto stream = std::make_shared<arrow::io::BufferOutputStream>(buffer); - auto outBatch = arrow::ipc::NewStreamWriter(stream.get(), table->schema()); + auto outBatch = arrow::ipc::MakeStreamWriter(stream.get(), table->schema()); auto outStatus = outBatch.ValueOrDie()->WriteTable(*table); if (outStatus.ok() == false) { throw std::runtime_error("Unable to Write table"); diff --git a/Framework/Core/test/test_Forwarding.cxx b/Framework/Core/test/test_Forwarding.cxx index 4e5ba6b13a5e6..02972837f8a08 100644 --- a/Framework/Core/test/test_Forwarding.cxx +++ b/Framework/Core/test/test_Forwarding.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx b/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx index 2b03b3a0cc5e3..1265587c922a1 100644 --- a/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx +++ b/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include <boost/test/unit_test.hpp> #include "../src/DDSConfigHelpers.h" #include "../src/DeviceSpecHelpers.h" @@ -62,19 +64,34 @@ WorkflowSpec defineDataProcessing() Outputs{}, AlgorithmSpec{ [](ProcessingContext& context) {}, + }, + { + ConfigParamSpec{"a-param", VariantType::Int, 1, {"A parameter which should not be escaped"}}, + ConfigParamSpec{"b-param", VariantType::String, "", {"a parameter which will be escaped"}}, + ConfigParamSpec{"c-param", VariantType::String, "foo;bar", {"another parameter which will be escaped"}}, }}}; } +char* strdiffchr(const char* s1, const char* s2) +{ + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + return (*s1 == *s2) ? nullptr : (char*)s1; +} + BOOST_AUTO_TEST_CASE(TestDDS) { auto workflow = defineDataProcessing(); std::ostringstream ss{""}; - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = makeTrivialChannelPolicies(*configContext); std::vector<DeviceSpec> devices; std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); - DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, devices, rm, "workflow-id"); + DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, devices, rm, "workflow-id", true); std::vector<DeviceControl> controls; std::vector<DeviceExecution> executions; controls.resize(devices.size()); @@ -85,28 +102,29 @@ BOOST_AUTO_TEST_CASE(TestDDS) std::vector<DataProcessorInfo> dataProcessorInfos = { { - {"A", "foo", {}, workflowOptions}, + {"A", "bcsadc/foo", {}, workflowOptions}, {"B", "foo", {}, workflowOptions}, {"C", "foo", {}, workflowOptions}, {"D", "foo", {}, workflowOptions}, }}; - DeviceSpecHelpers::prepareArguments(false, false, + DeviceSpecHelpers::prepareArguments(false, false, 8080, dataProcessorInfos, devices, executions, controls, "workflow-id"); - dumpDeviceSpec2DDS(ss, devices, executions); - BOOST_CHECK_EQUAL(ss.str(), R"EXPECTED(<topology name="o2-dataflow"> + CommandInfo command{"foo"}; + dumpDeviceSpec2DDS(ss, devices, executions, command); + auto expected = R"EXPECTED(<topology name="o2-dataflow"> <decltask name="A"> - <exe reachable="true">foo --id A --control static --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --session dpl_workflow-id --plugin-search-path $FAIRMQ_ROOT/lib --plugin dds</exe> + <exe reachable="true">foo | LD_PRELOAD=libSegFault.so SEGFAULT_SIGNALS="all" foo --id A --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal all --channel-config "name=from_A_to_B,type=push,method=bind,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=push,method=bind,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --session dpl_workflow-id --plugin odc</exe> </decltask> <decltask name="B"> - <exe reachable="true">foo --id B --control static --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --session dpl_workflow-id --plugin-search-path $FAIRMQ_ROOT/lib --plugin dds</exe> + <exe reachable="true">foo | LD_PRELOAD=libSegFault.so SEGFAULT_SIGNALS="all" foo --id B --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal all --channel-config "name=from_B_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_B,type=pull,method=connect,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --session dpl_workflow-id --plugin odc</exe> </decltask> <decltask name="C"> - <exe reachable="true">foo --id C --control static --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --session dpl_workflow-id --plugin-search-path $FAIRMQ_ROOT/lib --plugin dds</exe> + <exe reachable="true">foo | LD_PRELOAD=libSegFault.so SEGFAULT_SIGNALS="all" foo --id C --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal all --channel-config "name=from_C_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=pull,method=connect,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --session dpl_workflow-id --plugin odc</exe> </decltask> <decltask name="D"> - <exe reachable="true">foo --id D --control static --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --session dpl_workflow-id --plugin-search-path $FAIRMQ_ROOT/lib --plugin dds</exe> + <exe reachable="true">foo | LD_PRELOAD=libSegFault.so SEGFAULT_SIGNALS="all" foo --id D --shm-monitor false --log-color false --color false --jobs 4 --severity info --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal all --a-param 1 --b-param "" --c-param "foo;bar" --channel-config "name=from_B_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_C_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --session dpl_workflow-id --plugin odc</exe> </decltask> <declcollection name="DPL"> <tasks> @@ -117,5 +135,7 @@ BOOST_AUTO_TEST_CASE(TestDDS) </tasks> </declcollection> </topology> -)EXPECTED"); +)EXPECTED"; + BOOST_REQUIRE_EQUAL(strdiffchr(ss.str().data(), expected), strdiffchr(expected, ss.str().data())); + BOOST_CHECK_EQUAL(ss.str(), expected); } diff --git a/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx b/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx new file mode 100644 index 0000000000000..e89e99fdf0463 --- /dev/null +++ b/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx @@ -0,0 +1,445 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#define BOOST_TEST_MODULE Test Framework DDSConfigHelpers +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include "Mocking.h" +#include <boost/test/unit_test.hpp> +#include "../src/O2ControlHelpers.h" +#include "../src/DeviceSpecHelpers.h" +#include "../src/SimpleResourceManager.h" +#include "../src/ComputingResourceHelpers.h" +#include "Framework/DataAllocator.h" +#include "Framework/DeviceControl.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ProcessingContext.h" +#include "Framework/WorkflowSpec.h" + +#include <sstream> + +using namespace o2::framework; + +WorkflowSpec defineDataProcessing() +{ + return {{"A", // + Inputs{}, // + Outputs{OutputSpec{"TST", "A1"}, OutputSpec{"TST", "A2"}}, // A1 will be consumed twice, A2 is dangling + AlgorithmSpec{}, // + {ConfigParamSpec{"channel-config", VariantType::String, // raw input channel + "name=into_dpl,type=pull,method=connect,address=ipc:///tmp/pipe-into-dpl,transport=shmem,rateLogging=10", + {"Out-of-band channel config"}}}}, + {"B", // producer, no inputs + Inputs{}, + Outputs{OutputSpec{"TST", "B1"}}}, + {"C", // first consumer of A1, consumer of B1 + {InputSpec{"y", "TST", "A1"}, InputSpec{"y", "TST", "B1"}}, + Outputs{}}, + {"D", // second consumer of A1 + Inputs{ + InputSpec{"x", "TST", "A1"}}, + Outputs{}, + AlgorithmSpec{}, + {ConfigParamSpec{"a-param", VariantType::Int, 1, {"A parameter which should not be escaped"}}, + ConfigParamSpec{"b-param", VariantType::String, "", {"a parameter which will be escaped"}}, + ConfigParamSpec{"c-param", VariantType::String, "foo;bar", {"another parameter which will be escaped"}}, + ConfigParamSpec{"channel-config", VariantType::String, // raw output channel + "name=outta_dpl,type=push,method=bind,address=ipc:///tmp/pipe-outta-dpl,transport=shmem,rateLogging=10", + {"Out-of-band channel config"}}}}}; +} + +char* strdiffchr(const char* s1, const char* s2) +{ + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + return (*s1 == *s2) ? nullptr : (char*)s1; +} + +const auto expectedWorkflow = R"EXPECTED(name: testwf +vars: + dpl_command: >- + o2-exe --abdf -defg 'asdf fdsa' | o2-exe-2 -b --zxcv "asdf zxcv" +defaults: + monitoring_dpl_url: "no-op://" + user: "flp" + fmq_rate_logging: 0 + shm_segment_size: 10000000000 + shm_throw_bad_alloc: false + session_id: default + resources_monitoring: 15 +roles: + - name: "A" + connect: + - name: into_dpl + type: pull + transport: shmem + target: "::into_dpl-{{ it }}" + rateLogging: "{{ fmq_rate_logging }}" + task: + load: testwf-A + - name: "B" + connect: + task: + load: testwf-B + - name: "C" + connect: + - name: from_A_to_C + type: pull + transport: shmem + target: "{{ Parent().Path }}.A:from_A_to_C" + rateLogging: "{{ fmq_rate_logging }}" + - name: from_B_to_C + type: pull + transport: shmem + target: "{{ Parent().Path }}.B:from_B_to_C" + rateLogging: "{{ fmq_rate_logging }}" + task: + load: testwf-C + - name: "D" + connect: + - name: from_C_to_D + type: pull + transport: shmem + target: "{{ Parent().Path }}.C:from_C_to_D" + rateLogging: "{{ fmq_rate_logging }}" + bind: + - name: outta_dpl + type: push + transport: shmem + addressing: ipc + rateLogging: "{{ fmq_rate_logging }}" + global: "outta_dpl-{{ it }}" + task: + load: testwf-D +)EXPECTED"; + +const std::vector expectedTasks{ + R"EXPECTED(name: A +defaults: + log_task_output: none + _module_cmdline: >- + source /etc/profile.d/modules.sh && MODULEPATH={{ modulepath }} module load O2 QualityControl Control-OCCPlugin && + {{ dpl_command }} | bcsadc/foo + _plain_cmdline: "source /etc/profile.d/o2.sh && {{ dpl_command }} | bcsadc/foo" +control: + mode: "fairmq" +wants: + cpu: 0.01 + memory: 1 +bind: + - name: from_A_to_C + type: push + transport: shmem + addressing: ipc + rateLogging: "{{ fmq_rate_logging }}" +command: + shell: true + log: "{{ log_task_output }}" + env: ["O2_DETECTOR={{ detector }}"] + user: "{{ user }}" + value: "{{ len(modulepath)>0 ? _module_cmdline : _plain_cmdline }}" + arguments: + - "-b" + - "--monitoring-backend" + - "'{{ monitoring_dpl_url }}'" + - "--session" + - "'{{ session_id }}'" + - "--infologger-severity" + - "'{{ infologger_severity }}'" + - "--infologger-mode" + - "'{{ infologger_mode }}'" + - "--driver-client-backend" + - "'stdout://'" + - "--shm-segment-size" + - "'{{ shm_segment_size }}'" + - "--shm-throw-bad-alloc" + - "'{{ shm_throw_bad_alloc }}'" + - "--resources-monitoring" + - "'{{ resources_monitoring }}'" + - "--id" + - "'A'" + - "--shm-monitor" + - "'false'" + - "--log-color" + - "'false'" + - "--channel-prefix" + - "''" + - "--jobs" + - "'1'" + - "--severity" + - "'info'" + - "--shm-mlock-segment" + - "'false'" + - "--shm-mlock-segment-on-creation" + - "'false'" + - "--shm-segment-id" + - "'0'" + - "--shm-zero-segment" + - "'false'" + - "--stacktrace-on-signal" + - "'all'" +)EXPECTED", + R"EXPECTED(name: B +defaults: + log_task_output: none + _module_cmdline: >- + source /etc/profile.d/modules.sh && MODULEPATH={{ modulepath }} module load O2 QualityControl Control-OCCPlugin && + {{ dpl_command }} | foo + _plain_cmdline: "source /etc/profile.d/o2.sh && {{ dpl_command }} | foo" +control: + mode: "fairmq" +wants: + cpu: 0.01 + memory: 1 +bind: + - name: from_B_to_C + type: push + transport: shmem + addressing: ipc + rateLogging: "{{ fmq_rate_logging }}" +command: + shell: true + log: "{{ log_task_output }}" + env: ["O2_DETECTOR={{ detector }}"] + user: "{{ user }}" + value: "{{ len(modulepath)>0 ? _module_cmdline : _plain_cmdline }}" + arguments: + - "-b" + - "--monitoring-backend" + - "'{{ monitoring_dpl_url }}'" + - "--session" + - "'{{ session_id }}'" + - "--infologger-severity" + - "'{{ infologger_severity }}'" + - "--infologger-mode" + - "'{{ infologger_mode }}'" + - "--driver-client-backend" + - "'stdout://'" + - "--shm-segment-size" + - "'{{ shm_segment_size }}'" + - "--shm-throw-bad-alloc" + - "'{{ shm_throw_bad_alloc }}'" + - "--resources-monitoring" + - "'{{ resources_monitoring }}'" + - "--id" + - "'B'" + - "--shm-monitor" + - "'false'" + - "--log-color" + - "'false'" + - "--channel-prefix" + - "''" + - "--jobs" + - "'1'" + - "--severity" + - "'info'" + - "--shm-mlock-segment" + - "'false'" + - "--shm-mlock-segment-on-creation" + - "'false'" + - "--shm-segment-id" + - "'0'" + - "--shm-zero-segment" + - "'false'" + - "--stacktrace-on-signal" + - "'all'" +)EXPECTED", + R"EXPECTED(name: C +defaults: + log_task_output: none + _module_cmdline: >- + source /etc/profile.d/modules.sh && MODULEPATH={{ modulepath }} module load O2 QualityControl Control-OCCPlugin && + {{ dpl_command }} | foo + _plain_cmdline: "source /etc/profile.d/o2.sh && {{ dpl_command }} | foo" +control: + mode: "fairmq" +wants: + cpu: 0.01 + memory: 1 +bind: + - name: from_C_to_D + type: push + transport: shmem + addressing: ipc + rateLogging: "{{ fmq_rate_logging }}" +command: + shell: true + log: "{{ log_task_output }}" + env: ["O2_DETECTOR={{ detector }}"] + user: "{{ user }}" + value: "{{ len(modulepath)>0 ? _module_cmdline : _plain_cmdline }}" + arguments: + - "-b" + - "--monitoring-backend" + - "'{{ monitoring_dpl_url }}'" + - "--session" + - "'{{ session_id }}'" + - "--infologger-severity" + - "'{{ infologger_severity }}'" + - "--infologger-mode" + - "'{{ infologger_mode }}'" + - "--driver-client-backend" + - "'stdout://'" + - "--shm-segment-size" + - "'{{ shm_segment_size }}'" + - "--shm-throw-bad-alloc" + - "'{{ shm_throw_bad_alloc }}'" + - "--resources-monitoring" + - "'{{ resources_monitoring }}'" + - "--id" + - "'C'" + - "--shm-monitor" + - "'false'" + - "--log-color" + - "'false'" + - "--channel-prefix" + - "''" + - "--jobs" + - "'1'" + - "--severity" + - "'info'" + - "--shm-mlock-segment" + - "'false'" + - "--shm-mlock-segment-on-creation" + - "'false'" + - "--shm-segment-id" + - "'0'" + - "--shm-zero-segment" + - "'false'" + - "--stacktrace-on-signal" + - "'all'" +)EXPECTED", + R"EXPECTED(name: D +defaults: + log_task_output: none + _module_cmdline: >- + source /etc/profile.d/modules.sh && MODULEPATH={{ modulepath }} module load O2 QualityControl Control-OCCPlugin && + {{ dpl_command }} | foo + _plain_cmdline: "source /etc/profile.d/o2.sh && {{ dpl_command }} | foo" +control: + mode: "fairmq" +wants: + cpu: 0.01 + memory: 1 +bind: + - name: outta_dpl + type: push + transport: shmem + addressing: ipc + rateLogging: "{{ fmq_rate_logging }}" + global: "outta_dpl-{{ it }}" +command: + shell: true + log: "{{ log_task_output }}" + env: ["O2_DETECTOR={{ detector }}"] + user: "{{ user }}" + value: "{{ len(modulepath)>0 ? _module_cmdline : _plain_cmdline }}" + arguments: + - "-b" + - "--monitoring-backend" + - "'{{ monitoring_dpl_url }}'" + - "--session" + - "'{{ session_id }}'" + - "--infologger-severity" + - "'{{ infologger_severity }}'" + - "--infologger-mode" + - "'{{ infologger_mode }}'" + - "--driver-client-backend" + - "'stdout://'" + - "--shm-segment-size" + - "'{{ shm_segment_size }}'" + - "--shm-throw-bad-alloc" + - "'{{ shm_throw_bad_alloc }}'" + - "--resources-monitoring" + - "'{{ resources_monitoring }}'" + - "--id" + - "'D'" + - "--shm-monitor" + - "'false'" + - "--log-color" + - "'false'" + - "--channel-prefix" + - "''" + - "--jobs" + - "'1'" + - "--severity" + - "'info'" + - "--shm-mlock-segment" + - "'false'" + - "--shm-mlock-segment-on-creation" + - "'false'" + - "--shm-segment-id" + - "'0'" + - "--shm-zero-segment" + - "'false'" + - "--stacktrace-on-signal" + - "'all'" + - "--a-param" + - "'1'" + - "--b-param" + - "''" + - "--c-param" + - "'foo;bar'" +)EXPECTED"}; + +BOOST_AUTO_TEST_CASE(TestO2ControlDump) +{ + auto workflow = defineDataProcessing(); + std::ostringstream ss{""}; + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = makeTrivialChannelPolicies(*configContext); + std::vector<DeviceSpec> devices; + std::vector<ComputingResource> resources{ComputingResourceHelpers::getLocalhostResource()}; + SimpleResourceManager rm(resources); + auto completionPolicies = CompletionPolicy::createDefaultPolicies(); + DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, devices, rm, "workflow-id", true); + std::vector<DeviceControl> controls; + std::vector<DeviceExecution> executions; + controls.resize(devices.size()); + executions.resize(devices.size()); + CommandInfo commandInfo{R"(o2-exe --abdf -defg 'asdf fdsa' | o2-exe-2 -b --zxcv "asdf zxcv")"}; + + std::vector<ConfigParamSpec> workflowOptions = { + ConfigParamSpec{"jobs", VariantType::Int, 1, {"number of producer jobs"}}}; + + std::vector<DataProcessorInfo> dataProcessorInfos = { + { + {"A", "bcsadc/foo", {}, workflowOptions}, + {"B", "foo", {}, workflowOptions}, + {"C", "foo", {}, workflowOptions}, + {"D", "foo", {}, workflowOptions}, + }}; + DeviceSpecHelpers::prepareArguments(false, false, 8080, + dataProcessorInfos, + devices, executions, controls, + "workflow-id"); + + dumpWorkflow(ss, devices, executions, commandInfo, "testwf", ""); + + BOOST_REQUIRE_EQUAL(strdiffchr(ss.str().data(), expectedWorkflow), strdiffchr(expectedWorkflow, ss.str().data())); + BOOST_CHECK_EQUAL(ss.str(), expectedWorkflow); + + BOOST_REQUIRE_EQUAL(devices.size(), executions.size()); + BOOST_REQUIRE_EQUAL(devices.size(), expectedTasks.size()); + for (size_t di = 0; di < devices.size(); ++di) { + auto& spec = devices[di]; + auto& execution = executions[di]; + auto& expected = expectedTasks[di]; + + ss.str({}); + ss.clear(); + dumpTask(ss, devices[di], executions[di], devices[di].name, ""); + BOOST_REQUIRE_EQUAL(strdiffchr(ss.str().data(), expected), strdiffchr(expected, ss.str().data())); + BOOST_CHECK_EQUAL(ss.str(), expected); + } +} diff --git a/Framework/Core/test/test_GenericSource.cxx b/Framework/Core/test/test_GenericSource.cxx index 3f5ea6d7922bc..5e5d096ce6c50 100644 --- a/Framework/Core/test/test_GenericSource.cxx +++ b/Framework/Core/test/test_GenericSource.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_Graphviz.cxx b/Framework/Core/test/test_Graphviz.cxx index 262c104714900..a4c7d0d9c334d 100644 --- a/Framework/Core/test/test_Graphviz.cxx +++ b/Framework/Core/test/test_Graphviz.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include "../src/ComputingResourceHelpers.h" #include "../src/DeviceSpecHelpers.h" #include "../src/GraphvizHelpers.h" @@ -95,7 +97,8 @@ BOOST_AUTO_TEST_CASE(TestGraphviz) for (auto& device : devices) { BOOST_CHECK(device.id != ""); } - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); @@ -133,7 +136,8 @@ BOOST_AUTO_TEST_CASE(TestGraphvizWithPipeline) for (auto& device : devices) { BOOST_CHECK(device.id != ""); } - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); diff --git a/Framework/Core/test/test_GroupSlicer.cxx b/Framework/Core/test/test_GroupSlicer.cxx index 4117d629e0eda..f3b753c7eb0ec 100644 --- a/Framework/Core/test/test_GroupSlicer.cxx +++ b/Framework/Core/test/test_GroupSlicer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -207,7 +208,7 @@ BOOST_AUTO_TEST_CASE(GroupSlicerMismatchedGroups) TableBuilder builderT; auto trksWriter = builderT.cursor<aod::TrksX>(); for (auto i = 0; i < 20; ++i) { - if (i == 3 || i == 10 || i == 12 || i == 16) { + if (i == 3 || i == 10 || i == 12 || i == 16 || i == 19) { continue; } for (auto j = 0.f; j < 5; j += 0.5f) { @@ -218,7 +219,7 @@ BOOST_AUTO_TEST_CASE(GroupSlicerMismatchedGroups) aod::Events e{evtTable}; aod::TrksX t{trkTable}; BOOST_CHECK_EQUAL(e.size(), 20); - BOOST_CHECK_EQUAL(t.size(), 10 * (20 - 4)); + BOOST_CHECK_EQUAL(t.size(), 10 * (20 - 5)); auto tt = std::make_tuple(t); o2::framework::AnalysisDataProcessorBuilder::GroupSlicer g(e, tt); @@ -229,7 +230,7 @@ BOOST_AUTO_TEST_CASE(GroupSlicerMismatchedGroups) auto gg = slice.groupingElement(); BOOST_CHECK_EQUAL(gg.globalIndex(), count); auto trks = std::get<aod::TrksX>(as); - if (count == 3 || count == 10 || count == 12 || count == 16) { + if (count == 3 || count == 10 || count == 12 || count == 16 || count == 19) { BOOST_CHECK_EQUAL(trks.size(), 0); } else { BOOST_CHECK_EQUAL(trks.size(), 10); diff --git a/Framework/Core/test/test_HTTPParser.cxx b/Framework/Core/test/test_HTTPParser.cxx new file mode 100644 index 0000000000000..7d5e79744c98b --- /dev/null +++ b/Framework/Core/test/test_HTTPParser.cxx @@ -0,0 +1,359 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/test/tools/old/interface.hpp> +#define BOOST_TEST_MODULE Test Framework HTTPParser +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include "../src/HTTPParser.h" +#include <boost/test/unit_test.hpp> + +using namespace o2::framework; + +class DPLParser : public HTTPParser +{ + public: + std::string mMethod; + std::string mPath; + std::string mVersion; + std::string mBody; + std::map<std::string, std::string> mHeaders; + void method(std::string_view const& m) override + { + mMethod = m; + } + void target(std::string_view const& p) override + { + mPath = p; + } + + void version(std::string_view const& v) override + { + mVersion = v; + } + void header(std::string_view const& k, std::string_view const& v) override + { + mHeaders[std::string(k)] = v; + } + void body(char* buf, size_t s) override + { + mBody = buf; + } +}; + +class DPLClientParser : public HTTPParser +{ + public: + std::string mReplyVersion; + std::string mReplyCode; + std::string mReplyMessage; + std::string mBody; + std::map<std::string, std::string> mHeaders; + + void replyMessage(std::string_view const& s) override + { + mReplyMessage = s; + } + void replyCode(std::string_view const& s) override + { + mReplyCode = s; + } + void replyVersion(std::string_view const& s) override + { + mReplyVersion = s; + } + + void header(std::string_view const& k, std::string_view const& v) override + { + mHeaders[std::string(k)] = v; + } + void body(char* buf, size_t s) override + { + mBody = buf; + } +}; + +class TestWSHandler : public WebSocketHandler +{ + public: + std::vector<char const*> mFrame; + std::vector<size_t> mSize; + void frame(const char* f, size_t s) final + { + mFrame.push_back(strdup(f)); + mSize.push_back(s); + } +}; + +BOOST_AUTO_TEST_CASE(HTTPParser1) +{ + { + char* request = strdup( + "GET / HTTP/1.1\r\n" + "x-dpl-pid: 124679842\r\n\r\nCONTROL QUIT"); + DPLParser parser; + parse_http_request(request, strlen(request), &parser); + BOOST_REQUIRE_EQUAL(std::string(parser.mMethod), std::string("GET")); + BOOST_REQUIRE_EQUAL(std::string(parser.mPath), std::string("/")); + BOOST_REQUIRE_EQUAL(std::string(parser.mVersion), std::string("HTTP/1.1")); + BOOST_REQUIRE_EQUAL(parser.mHeaders.size(), 1); + } + { + char* request = strdup( + "GET / HTTP/1.1\r\n" + "x-dpl-pid: 124679842\r\n" + "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"); + DPLParser parser; + parse_http_request(request, strlen(request), &parser); + BOOST_REQUIRE_EQUAL(std::string(parser.mMethod), std::string("GET")); + BOOST_REQUIRE_EQUAL(std::string(parser.mPath), std::string("/")); + BOOST_REQUIRE_EQUAL(std::string(parser.mVersion), std::string("HTTP/1.1")); + BOOST_REQUIRE_EQUAL(parser.mHeaders.size(), 2); + BOOST_REQUIRE_EQUAL(parser.mHeaders["x-dpl-pid"], "124679842"); + BOOST_REQUIRE_EQUAL(parser.mHeaders["Somethingelse"], "cjnjsdnjks"); + BOOST_REQUIRE_EQUAL(parser.mBody, "CONTROL QUIT"); + } + { + // handle continuations... + char* request = strdup( + "GET / HTTP/1.1\r\n" + "x-dpl-pid: 124679842\r\n" + "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"); + char* request2 = strdup("FOO BAR"); + DPLParser parser; + parse_http_request(request, strlen(request), &parser); + BOOST_REQUIRE_EQUAL(std::string(parser.mMethod), std::string("GET")); + BOOST_REQUIRE_EQUAL(std::string(parser.mPath), std::string("/")); + BOOST_REQUIRE_EQUAL(std::string(parser.mVersion), std::string("HTTP/1.1")); + BOOST_REQUIRE_EQUAL(parser.mHeaders.size(), 2); + BOOST_REQUIRE_EQUAL(parser.mHeaders["x-dpl-pid"], "124679842"); + BOOST_REQUIRE_EQUAL(parser.mHeaders["Somethingelse"], "cjnjsdnjks"); + BOOST_REQUIRE_EQUAL(parser.mBody, "CONTROL QUIT"); + parse_http_request(request2, strlen(request2), &parser); + BOOST_REQUIRE_EQUAL(parser.mBody, "FOO BAR"); + } + + { + // WebSocket example + char* request = strdup( + "GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" + "Sec-WebSocket-Protocol: chat, superchat\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Origin: http://example.com\r\n\r\n"); + + DPLParser parser; + parse_http_request(request, strlen(request), &parser); + BOOST_REQUIRE_EQUAL(std::string(parser.mMethod), std::string("GET")); + BOOST_REQUIRE_EQUAL(std::string(parser.mPath), std::string("/chat")); + BOOST_REQUIRE_EQUAL(std::string(parser.mVersion), std::string("HTTP/1.1")); + BOOST_REQUIRE_EQUAL(parser.mHeaders.size(), 7); + BOOST_REQUIRE_EQUAL(parser.mHeaders["Sec-WebSocket-Protocol"], "chat, superchat"); + } + { + // WebSocket example + char* request = strdup( + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"); + + DPLClientParser parser; + parser.states.push_back(HTTPState::IN_START_REPLY); + parse_http_request(request, strlen(request), &parser); + BOOST_REQUIRE_EQUAL(std::string(parser.mReplyCode), std::string("101")); + BOOST_REQUIRE_EQUAL(std::string(parser.mReplyMessage), std::string("Switching Protocols")); + BOOST_REQUIRE_EQUAL(std::string(parser.mReplyVersion), std::string("HTTP/1.1")); + BOOST_REQUIRE_EQUAL(parser.mHeaders.size(), 3); + BOOST_REQUIRE_EQUAL(parser.mHeaders["Sec-WebSocket-Accept"], "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="); + BOOST_REQUIRE_EQUAL(parser.mBody, ""); + } + { + // WebSocket frame encoding / decoding + char* buffer = strdup("hello websockets!"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + TestWSHandler handler; + BOOST_REQUIRE_EQUAL(encoded[0].len, strlen(buffer) + 1 + 2); // 1 for the 0, 2 for the header + decode_websocket(encoded[0].base, encoded[0].len, handler); + BOOST_REQUIRE_EQUAL(handler.mSize[0], strlen(buffer) + 1); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + } + { + // WebSocket multiple frame encoding / decoding + char* buffer = strdup("hello websockets!"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + char const* buffer2 = "and again."; + encode_websocket_frames(encoded, buffer2, strlen(buffer2) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 2); + char* multiBuffer = (char*)malloc(encoded[0].len + encoded[1].len + 4); + memcpy(multiBuffer, encoded[0].base, encoded[0].len); + memcpy(multiBuffer + encoded[0].len, encoded[1].base, encoded[1].len); + + TestWSHandler handler; + decode_websocket(multiBuffer, encoded[0].len + encoded[1].len, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 2); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 2); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[1], handler.mSize[1] - 1), std::string(buffer2)); + } + { + // Decode a frame which is split in two. + char* buffer = strdup("hello websockets!1"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + + TestWSHandler handler; + decode_websocket(encoded[0].base, encoded[0].len / 2, handler); + decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 1); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 1); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + } + { + // Decode a long frame which is split in two. + char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + + TestWSHandler handler; + decode_websocket(encoded[0].base, encoded[0].len / 2, handler); + decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 1); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 1); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + } + { + // WebSocket multiple frame encoding / decoding, long frames + char* buffer = strdup("dwqnocewnclkanklcdanslkcndklsnclkdsnckldsnclk cnldcl dsklc dslk cljdnsck sdlakcn askc sdkla cnsd c sdcn dsklncn dklsc nsdkl cklds clkds ckls dklc shello websockets!"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + char const* buffer2 = "xsanjkcnsadjknc dsjc nsdnc dlscndsck dsc ds clds cds vnlsfl nklnjk nj nju n nio nkmnklfmdkl mkld mkl mkl mkl mlk m lkm klfdnkln jkafdnk nk mkldfm lkdamlkdmlkdmlk m klml km lkm kl."; + encode_websocket_frames(encoded, buffer2, strlen(buffer2) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 2); + char* multiBuffer = (char*)malloc(encoded[0].len + encoded[1].len + 4); + memcpy(multiBuffer, encoded[0].base, encoded[0].len); + memcpy(multiBuffer + encoded[0].len, encoded[1].base, encoded[1].len); + + TestWSHandler handler; + decode_websocket(multiBuffer, encoded[0].len + encoded[1].len, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 2); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 2); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[1], handler.mSize[1] - 1), std::string(buffer2)); + } + { + // Decode a long frame which is split in two, after the first byte. + char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + + for (size_t i = 1; i < strlen(buffer); ++i) { + char buffer1[1024]; + char buffer2[1024]; + memset(buffer1, 0xfa, 1024); + memset(buffer2, 0xfb, 1024); + memcpy(buffer1, encoded[0].base, i); + memcpy(buffer2, encoded[0].base + i, encoded[0].len - i); + TestWSHandler handler; + decode_websocket(buffer1, i, handler); + decode_websocket(buffer2, encoded[0].len - i, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 1); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 1); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + } + } + { + // Decode a long frame which is split in two, after the first byte. + char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::vector<uv_buf_t> encoded; + encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + BOOST_REQUIRE_EQUAL(encoded.size(), 1); + + for (size_t i = 0; i < strlen(buffer) - 1; ++i) { + for (size_t j = i + 1; j < strlen(buffer); ++j) { + char buffer1[1024]; + char buffer2[1024]; + char buffer3[1024]; + memset(buffer1, 0xfa, 1024); + memset(buffer2, 0xfb, 1024); + memset(buffer3, 0xfc, 1024); + memcpy(buffer1, encoded[0].base, i); + memcpy(buffer2, encoded[0].base + i, (j - i)); + memcpy(buffer3, encoded[0].base + j, encoded[0].len - j); + TestWSHandler handler; + decode_websocket(buffer1, i, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 0); + decode_websocket(buffer2, (j - i), handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 0); + decode_websocket(buffer3, encoded[0].len - j, handler); + BOOST_REQUIRE_EQUAL(handler.mFrame.size(), 1); + BOOST_REQUIRE_EQUAL(handler.mSize.size(), 1); + BOOST_REQUIRE_EQUAL(std::string(handler.mFrame[0], handler.mSize[0] - 1), std::string(buffer)); + } + } + } + { + std::string checkRequest = + "GET /chat HTTP/1.1\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Protocol: myprotocol\r\n" + "Sec-WebSocket-Version: 13\r\n\r\n"; + std::string checkReply = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"; + int someSeed = 123; + std::string result = encode_websocket_handshake_request("/chat", "myprotocol", 13, "dGhlIHNhbXBsZSBub25jZQ=="); + BOOST_REQUIRE_EQUAL(result, checkRequest); + + std::string reply = encode_websocket_handshake_reply("dGhlIHNhbXBsZSBub25jZQ=="); + BOOST_CHECK_EQUAL(reply, checkReply); + } +} + +BOOST_AUTO_TEST_CASE(URLParser) +{ + { + auto [ip, port] = o2::framework::parse_websocket_url("ws://"); + BOOST_CHECK_EQUAL(ip, "127.0.0.1"); + BOOST_CHECK_EQUAL(port, 8080); + } + { + auto [ip, port] = o2::framework::parse_websocket_url("ws://127.0.0.1:8080"); + BOOST_CHECK_EQUAL(ip, "127.0.0.1"); + BOOST_CHECK_EQUAL(port, 8080); + } + { + auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8080"); + BOOST_CHECK_EQUAL(ip, "0.0.0.0"); + BOOST_CHECK_EQUAL(port, 8080); + } + { + auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8081"); + BOOST_CHECK_EQUAL(ip, "0.0.0.0"); + BOOST_CHECK_EQUAL(port, 8081); + } +} diff --git a/Framework/Core/test/test_HelperMacros.h b/Framework/Core/test/test_HelperMacros.h index 04969bee4d33c..613218458254d 100644 --- a/Framework/Core/test/test_HelperMacros.h +++ b/Framework/Core/test/test_HelperMacros.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_HistogramRegistry.cxx b/Framework/Core/test/test_HistogramRegistry.cxx index 39d5618392a2d..0c1c9d69a3e2f 100644 --- a/Framework/Core/test/test_HistogramRegistry.cxx +++ b/Framework/Core/test/test_HistogramRegistry.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "Framework/HistogramRegistry.h" #include <boost/test/unit_test.hpp> +#include <iostream> using namespace o2; using namespace o2::framework; @@ -41,20 +43,35 @@ BOOST_AUTO_TEST_CASE(HistogramRegistryLookup) }; /// Get histograms by name - BOOST_REQUIRE_EQUAL(registry.get<TH1>("eta")->GetNbinsX(), 100); - BOOST_REQUIRE_EQUAL(registry.get<TH1>("phi")->GetNbinsX(), 102); - BOOST_REQUIRE_EQUAL(registry.get<TH1>("pt")->GetNbinsX(), 1002); - BOOST_REQUIRE_EQUAL(registry.get<TH2>("ptToPt")->GetNbinsX(), 100); - BOOST_REQUIRE_EQUAL(registry.get<TH2>("ptToPt")->GetNbinsY(), 100); + BOOST_REQUIRE_EQUAL(registry.get<TH1>(HIST("eta"))->GetNbinsX(), 100); + BOOST_REQUIRE_EQUAL(registry.get<TH1>(HIST("phi"))->GetNbinsX(), 102); + BOOST_REQUIRE_EQUAL(registry.get<TH1>(HIST("pt"))->GetNbinsX(), 1002); + BOOST_REQUIRE_EQUAL(registry.get<TH2>(HIST("ptToPt"))->GetNbinsX(), 100); + BOOST_REQUIRE_EQUAL(registry.get<TH2>(HIST("ptToPt"))->GetNbinsY(), 100); /// Get a pointer to the histogram - auto histo = registry.get<TH1>("pt").get(); + auto histo = registry.get<TH1>(HIST("pt")).get(); BOOST_REQUIRE_EQUAL(histo->GetNbinsX(), 1002); /// Get registry object from a function auto r = foo(); - auto histo2 = r.get<TH1>("histo").get(); + auto histo2 = r.get<TH1>(HIST("histo")).get(); BOOST_REQUIRE_EQUAL(histo2->GetNbinsX(), 100); + + registry.print(); + + // check that registry behaves correctly when two different names have equal hash: + /* + auto str1 = "Maria has nine red beds."; + auto str2 = "Steven has fifteen white tables."; + BOOST_REQUIRE_EQUAL(compile_time_hash(str1), compile_time_hash(str2)); + try { + registry.add(str1, "", kTH1F, {{20, 0.0f, 10.01f}}); + registry.add(str2, "", kTH1F, {{20, 0.0f, 10.01f}}); + } catch (...) { + std::cout << "Hash collision was detected correctly!" << std::endl; + } + */ } BOOST_AUTO_TEST_CASE(HistogramRegistryExpressionFill) @@ -84,10 +101,31 @@ BOOST_AUTO_TEST_CASE(HistogramRegistryExpressionFill) }; /// Fill histogram with expression and table - registry.fill<test::X>("x", tests, test::x > 3.0f); - BOOST_CHECK_EQUAL(registry.get<TH1>("x")->GetEntries(), 4); + registry.fill<test::X>(HIST("x"), tests, test::x > 3.0f); + BOOST_CHECK_EQUAL(registry.get<TH1>(HIST("x"))->GetEntries(), 4); /// Fill histogram with expression and table - registry.fill<test::X, test::Y>("xy", tests, test::x > 3.0f && test::y > -5.0f); - BOOST_CHECK_EQUAL(registry.get<TH2>("xy")->GetEntries(), 2); + registry.fill<test::X, test::Y>(HIST("xy"), tests, test::x > 3.0f && test::y > -5.0f); + BOOST_CHECK_EQUAL(registry.get<TH2>(HIST("xy"))->GetEntries(), 2); +} + +BOOST_AUTO_TEST_CASE(HistogramRegistryStepTHn) +{ + HistogramRegistry registry{"registry"}; + + registry.add("stepTHnF", "a", {kStepTHnF, {{100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}, 2}); + registry.add("stepTHnD", "b", {kStepTHnD, {{100, -10.0f, 10.01f}, {100, -10.0f, 10.01f}}, 3}); + registry.addClone("stepTHnD", "stepTHnD2"); + + auto histo = registry.get<StepTHn>(HIST("stepTHnD")); + BOOST_REQUIRE_EQUAL(histo->getNSteps(), 3); + + // fill first step at position (0,3) + registry.fill(HIST("stepTHnF"), 0, 0., 3.); + // fill second step (0,4) + registry.fill(HIST("stepTHnF"), 1, 0., 4.); + + registry.fill(HIST("stepTHnD2"), 1, 0., 4.); + + registry.print(); } diff --git a/Framework/Core/test/test_IndexBuilder.cxx b/Framework/Core/test/test_IndexBuilder.cxx index 907f160a6a0d0..351efdead9704 100644 --- a/Framework/Core/test/test_IndexBuilder.cxx +++ b/Framework/Core/test/test_IndexBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,6 +60,7 @@ DECLARE_SOA_INDEX_COLUMN(Category, category); } // namespace indices DECLARE_SOA_TABLE(IDXs, "TST", "Index", Index<>, indices::PointId, indices::DistanceId, indices::FlagId, indices::CategoryId); +DECLARE_SOA_TABLE(IDX2s, "TST", "Index2", Index<>, indices::DistanceId, indices::PointId, indices::FlagId, indices::CategoryId); BOOST_AUTO_TEST_CASE(TestIndexBuilder) { @@ -100,7 +102,7 @@ BOOST_AUTO_TEST_CASE(TestIndexBuilder) auto t4 = b4.finalize(); Categorys st4{t4}; - auto t5 = IndexExclusive::indexBuilder(typename IDXs::persistent_columns_t{}, st1, std::tie(st1, st2, st3, st4)); + auto t5 = IndexExclusive::indexBuilder("test1", typename IDXs::persistent_columns_t{}, st1, std::tie(st1, st2, st3, st4)); BOOST_REQUIRE_EQUAL(t5->num_rows(), 4); IDXs idxt{t5}; idxt.bindExternalIndices(&st1, &st2, &st3, &st4); @@ -110,30 +112,24 @@ BOOST_AUTO_TEST_CASE(TestIndexBuilder) BOOST_REQUIRE(row.category().pointId() == row.pointId()); } - auto t6 = IndexSparse::indexBuilder(typename IDXs::persistent_columns_t{}, st1, std::tie(st1, st2, st3, st4)); - BOOST_REQUIRE_EQUAL(t6->num_rows(), st1.size()); + auto t6 = IndexSparse::indexBuilder("test2", typename IDX2s::persistent_columns_t{}, st1, std::tie(st2, st1, st3, st4)); + BOOST_REQUIRE_EQUAL(t6->num_rows(), st2.size()); IDXs idxs{t6}; - std::array<int, 10> ds{0, 1, 2, -1, 4, -1, -1, 7, 8, 9}; - std::array<int, 10> fs{0, 1, 2, -1, -1, 5, -1, -1, 8, -1}; - std::array<int, 10> cs{0, 1, 2, 3, -1, 5, -1, 7, 8, -1}; + std::array<int, 7> fs{0, 1, 2, -1, -1, 4, -1}; + std::array<int, 7> cs{0, 1, 2, -1, 5, 6, -1}; idxs.bindExternalIndices(&st1, &st2, &st3, &st4); auto i = 0; - for (auto& row : idxs) { - if (row.has_distance()) { - BOOST_REQUIRE(row.distance().pointId() == ds[i]); - } else { - BOOST_REQUIRE(row.distanceId() == ds[i]); - } + for (auto const& row : idxs) { + BOOST_REQUIRE(row.has_distance()); + BOOST_REQUIRE(row.has_point()); if (row.has_flag()) { - BOOST_REQUIRE(row.flag().pointId() == fs[i]); - } else { - BOOST_REQUIRE(row.flagId() == fs[i]); + BOOST_REQUIRE(row.flag().pointId() == row.pointId()); } if (row.has_category()) { - BOOST_REQUIRE(row.category().pointId() == cs[i]); - } else { - BOOST_REQUIRE(row.categoryId() == cs[i]); + BOOST_REQUIRE(row.category().pointId() == row.pointId()); } + BOOST_REQUIRE(row.flagId() == fs[i]); + BOOST_REQUIRE(row.categoryId() == cs[i]); ++i; } } diff --git a/Framework/Core/test/test_InfoLogger.cxx b/Framework/Core/test/test_InfoLogger.cxx index e287f6d70a180..4fde33c8775d7 100644 --- a/Framework/Core/test/test_InfoLogger.cxx +++ b/Framework/Core/test/test_InfoLogger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ BOOST_AUTO_TEST_CASE(InfoLoggerTest) { // define infologger output to stdout, as we don't want to use the default infoLoggerD pipe which might not be running here - setenv("INFOLOGGER_MODE", "stdout", 1); + setenv("O2_INFOLOGGER_MODE", "stdout", 1); // create the infologger interface InfoLogger theLog; diff --git a/Framework/Core/test/test_InputRecord.cxx b/Framework/Core/test/test_InputRecord.cxx index 56276be56c1ab..7ce3d116141de 100644 --- a/Framework/Core/test/test_InputRecord.cxx +++ b/Framework/Core/test/test_InputRecord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include <boost/test/unit_test.hpp> #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/DataProcessingHeader.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" @@ -46,7 +48,10 @@ BOOST_AUTO_TEST_CASE(TestInputRecord) createRoute("z_source", spec3)}; // First of all we test if an empty registry behaves as expected, raising a // bunch of exceptions. - InputRecord emptyRecord(schema, {[](size_t) { return DataRef{nullptr, nullptr, nullptr}; }, 0}); + InputSpan span{ + [](size_t) { return DataRef{nullptr, nullptr, nullptr}; }, + 0}; + InputRecord emptyRecord(schema, span); BOOST_CHECK_EXCEPTION(emptyRecord.get("x"), RuntimeErrorRef, any_exception); BOOST_CHECK_EXCEPTION(emptyRecord.get("y"), RuntimeErrorRef, any_exception); @@ -87,8 +92,8 @@ BOOST_AUTO_TEST_CASE(TestInputRecord) createMessage(dh1, 1); createMessage(dh2, 2); createEmpty(); - InputSpan span{[&inputs](size_t i) { return DataRef{nullptr, static_cast<char const*>(inputs[2 * i]), static_cast<char const*>(inputs[2 * i + 1])}; }, inputs.size() / 2}; - InputRecord record{schema, std::move(span)}; + InputSpan span2{[&inputs](size_t i) { return DataRef{nullptr, static_cast<char const*>(inputs[2 * i]), static_cast<char const*>(inputs[2 * i + 1])}; }, inputs.size() / 2}; + InputRecord record{schema, span2}; // Checking we can get the whole ref by name BOOST_CHECK_NO_THROW(record.get("x")); diff --git a/Framework/Core/test/test_InputRecordWalker.cxx b/Framework/Core/test/test_InputRecordWalker.cxx index 719626c7a0a82..92d1a3f260bae 100644 --- a/Framework/Core/test/test_InputRecordWalker.cxx +++ b/Framework/Core/test/test_InputRecordWalker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,10 +14,12 @@ #define BOOST_TEST_DYN_LINK #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/InputRecordWalker.h" #include "Framework/WorkflowSpec.h" // o2::framework::select #include "Framework/DataRefUtils.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "Headers/Stack.h" #include <boost/test/unit_test.hpp> #include <vector> @@ -37,14 +40,15 @@ struct DataSet { using Messages = std::vector<TaggedSet>; using CheckType = std::vector<std::string>; DataSet(std::vector<InputRoute>&& s, Messages&& m, CheckType&& v) - : schema{std::move(s)}, messages{std::move(m)}, record{schema, {[this](size_t i, size_t part) { - BOOST_REQUIRE(i < this->messages.size()); - BOOST_REQUIRE(part < this->messages[i].second.size() / 2); - auto header = static_cast<char const*>(this->messages[i].second.at(2 * part)->data()); - auto payload = static_cast<char const*>(this->messages[i].second.at(2 * part + 1)->data()); - return DataRef{nullptr, header, payload}; - }, - [this](size_t i) { return i < this->messages.size() ? messages[i].second.size() / 2 : 0; }, this->messages.size()}}, + : schema{std::move(s)}, messages{std::move(m)}, span{[this](size_t i, size_t part) { + BOOST_REQUIRE(i < this->messages.size()); + BOOST_REQUIRE(part < this->messages[i].second.size() / 2); + auto header = static_cast<char const*>(this->messages[i].second.at(2 * part)->data()); + auto payload = static_cast<char const*>(this->messages[i].second.at(2 * part + 1)->data()); + return DataRef{nullptr, header, payload}; + }, + [this](size_t i) { return i < this->messages.size() ? messages[i].second.size() / 2 : 0; }, this->messages.size()}, + record{schema, span}, values{std::move(v)} { BOOST_REQUIRE(messages.size() == schema.size()); @@ -52,6 +56,7 @@ struct DataSet { std::vector<InputRoute> schema; Messages messages; + InputSpan span; InputRecord record; CheckType values; }; @@ -81,7 +86,7 @@ DataSet createData() DataSet::Messages messages; auto createMessage = [&messages, &checkValues](DataHeader dh) { - checkValues.emplace_back(dh.dataOrigin.as<std::string>() + "_" + dh.dataDescription.as<std::string>() + "_" + std::to_string(dh.subSpecification)); + checkValues.emplace_back(fmt::format("{}_{}_{}", dh.dataOrigin, dh.dataDescription, dh.subSpecification)); std::string const& data = checkValues.back(); dh.payloadSize = data.size(); DataProcessingHeader dph{0, 1}; diff --git a/Framework/Core/test/test_InputSpan.cxx b/Framework/Core/test/test_InputSpan.cxx index 65ca043035ad9..ef207e60231d2 100644 --- a/Framework/Core/test/test_InputSpan.cxx +++ b/Framework/Core/test/test_InputSpan.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_InputSpec.cxx b/Framework/Core/test/test_InputSpec.cxx index 67dc5c7333b59..d85654ec15f44 100644 --- a/Framework/Core/test/test_InputSpec.cxx +++ b/Framework/Core/test/test_InputSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "Framework/InputSpec.h" #include "Framework/DataSpecUtils.h" +#include "Headers/DataHeader.h" #include <boost/test/unit_test.hpp> #include <algorithm> #include <vector> @@ -33,3 +35,19 @@ BOOST_AUTO_TEST_CASE(TestSorting) }; std::stable_sort(inputs.begin(), inputs.end(), sorter); } + +BOOST_AUTO_TEST_CASE(TestCreation) +{ + // At some point + std::vector<InputSpec> inputs{ + InputSpec{"everything", "TST", "B", 0}, + InputSpec{"0-subspec", "TST", "B"}, + InputSpec{"wildcard-subspec", {"TST", "A"}}, + InputSpec{"wildcard-desc-and-subspec", o2::header::DataOrigin{"TST"}}, + InputSpec{"everything-again", {"TST", "B", 0}}}; + std::swap(inputs[0], inputs[1]); + auto sorter = [](InputSpec const& a, InputSpec const& b) { + return a.binding < b.binding; + }; + std::stable_sort(inputs.begin(), inputs.end(), sorter); +} diff --git a/Framework/Core/test/test_Kernels.cxx b/Framework/Core/test/test_Kernels.cxx index b7f48bcc82c9f..ed41fca1cbaf5 100644 --- a/Framework/Core/test/test_Kernels.cxx +++ b/Framework/Core/test/test_Kernels.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "Framework/TableBuilder.h" #include "Framework/Pack.h" #include <boost/test/unit_test.hpp> +#include <arrow/util/config.h> using namespace o2::framework; using namespace arrow; @@ -36,7 +38,7 @@ BOOST_AUTO_TEST_CASE(TestSlicing) rowWriter(0, 5, 10); auto table = builder.finalize(); - auto options = arrow::compute::CountOptions::Defaults(); + auto options = arrow::compute::ScalarAggregateOptions::Defaults(); auto value_counts = arrow::compute::CallFunction("value_counts", {table->GetColumnByName("x")}, &options).ValueOrDie(); auto array = static_cast<arrow::StructArray>(value_counts.array()); diff --git a/Framework/Core/test/test_LogParsingHelpers.cxx b/Framework/Core/test/test_LogParsingHelpers.cxx index 66f95d3550310..80d636dde2b60 100644 --- a/Framework/Core/test/test_LogParsingHelpers.cxx +++ b/Framework/Core/test/test_LogParsingHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_OverrideLabels.cxx b/Framework/Core/test/test_OverrideLabels.cxx new file mode 100644 index 0000000000000..c384a87c21aff --- /dev/null +++ b/Framework/Core/test/test_OverrideLabels.cxx @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test Framework OverrideLabels +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +// We prevent runDataProcessing from starting a workflow +#define main anything_else_than_main +#include "Framework/runDataProcessing.h" +#undef main +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const&) { return {}; } + +using namespace o2::framework; + +// Mockup for a workflow with labels as args. It will behave as expected only in single-threaded code!!! +static std::vector<ConfigParamSpec> specs; +static ConfigParamRegistry registry{nullptr}; +std::unique_ptr<o2::framework::ConfigContext> mockupLabels(std::string labelArg) +{ + // FIXME: Ugly... We need to fix ownership and make sure the ConfigContext + // either owns or shares ownership of the registry. + std::vector<std::unique_ptr<ParamRetriever>> retrievers; + specs = WorkflowCustomizationHelpers::requiredWorkflowOptions(); + specs.push_back(ConfigParamSpec{"labels", VariantType::String, std::move(labelArg), {"labels specification"}}); + auto store = std::make_unique<ConfigParamStore>(specs, std::move(retrievers)); + store->preload(); + store->activate(); + registry = ConfigParamRegistry(std::move(store)); + auto context = std::make_unique<ConfigContext>(registry, 0, nullptr); + return context; +} + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE(OverrideLabels) +{ + { + // invalid format + WorkflowSpec workflow{{"A"}}; + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A:"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels(":A"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A:asdf,:"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A:asdf,:A"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A:asdf,B:"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A:asdf,B"), workflow), std::runtime_error); + BOOST_CHECK_THROW(overrideLabels(*mockupLabels("A,B:asdf"), workflow), std::runtime_error); + } + { + // one processor, one label + WorkflowSpec workflow{{"A"}}; + auto ctx = mockupLabels("A:abc"); + overrideLabels(*ctx, workflow); + BOOST_CHECK_EQUAL(workflow[0].labels[0].value, "abc"); + } + { + // many processors, many labels + WorkflowSpec workflow{{"A"}, {"B"}, {"C"}}; + auto ctx = mockupLabels("A:a1:a2,B:b1,C:c1:c2:c3"); + overrideLabels(*ctx, workflow); + BOOST_CHECK_EQUAL(workflow[0].labels[0].value, "a1"); + BOOST_CHECK_EQUAL(workflow[0].labels[1].value, "a2"); + BOOST_CHECK_EQUAL(workflow[1].labels[0].value, "b1"); + BOOST_CHECK_EQUAL(workflow[2].labels[0].value, "c1"); + BOOST_CHECK_EQUAL(workflow[2].labels[1].value, "c2"); + BOOST_CHECK_EQUAL(workflow[2].labels[2].value, "c3"); + } + { + // duplicate labels in arg + WorkflowSpec workflow{{"A"}}; + auto ctx = mockupLabels("A:a1:a1"); + overrideLabels(*ctx, workflow); + BOOST_CHECK_EQUAL(workflow[0].labels.size(), 1); + BOOST_CHECK_EQUAL(workflow[0].labels[0].value, "a1"); + } + { + // duplicate labels - one in WF, one in arg + WorkflowSpec workflow{{"A"}}; + workflow[0].labels.push_back({"a1"}); + auto ctx = mockupLabels("A:a1"); + overrideLabels(*ctx, workflow); + BOOST_CHECK_EQUAL(workflow[0].labels.size(), 1); + BOOST_CHECK_EQUAL(workflow[0].labels[0].value, "a1"); + } +} diff --git a/Framework/Core/test/test_Parallel.cxx b/Framework/Core/test/test_Parallel.cxx index 64d3a52ae413c..7017049064e64 100644 --- a/Framework/Core/test/test_Parallel.cxx +++ b/Framework/Core/test/test_Parallel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" +#include "Framework/DataRefUtils.h" #include "Framework/ParallelContext.h" #include "Framework/runDataProcessing.h" @@ -110,7 +112,7 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) LOG(DEBUG) << "DataSampler sends data from subSpec: " << matcher.subSpec; - const auto* inputHeader = o2::header::get<o2::header::DataHeader*>(input.header); + const auto* inputHeader = DataRefUtils::getHeader<o2::header::DataHeader*>(input); auto& output = ctx.outputs().make<char>(description, inputHeader->size()); //todo: use some std function or adopt(), when it is available for POD data diff --git a/Framework/Core/test/test_ParallelPipeline.cxx b/Framework/Core/test/test_ParallelPipeline.cxx index 30f2a2ef8e0bd..399a014892a84 100644 --- a/Framework/Core/test/test_ParallelPipeline.cxx +++ b/Framework/Core/test/test_ParallelPipeline.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,7 +39,7 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies) #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed)"; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ } using DataHeader = o2::header::DataHeader; @@ -200,7 +201,7 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) auto const* dataheader = DataRefUtils::getHeader<o2::header::DataHeader*>(input); if (input.spec->binding.compare(0, 6, "datain") == 0) { if (input.spec->binding != bindings.at(dataheader->subSpecification)) { - LOG(ERROR) << "data with subspec " << dataheader->subSpecification << " at unexpected binding " << input.spec->binding << ", expected " << bindings.at(dataheader->subSpecification); + LOG(error) << "data with subspec " << dataheader->subSpecification << " at unexpected binding " << input.spec->binding << ", expected " << bindings.at(dataheader->subSpecification); } haveDataIn = true; ASSERT_ERROR(checkMap->at(dataheader->subSpecification) == inputs.get<int>(input.spec->binding.c_str())); diff --git a/Framework/Core/test/test_ParallelProducer.cxx b/Framework/Core/test/test_ParallelProducer.cxx index 106df7115d05d..9face4ada6c6e 100644 --- a/Framework/Core/test/test_ParallelProducer.cxx +++ b/Framework/Core/test/test_ParallelProducer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_ProcessorOptions.cxx b/Framework/Core/test/test_ProcessorOptions.cxx index 6023e69f71a8c..bbadf5b23a062 100644 --- a/Framework/Core/test/test_ProcessorOptions.cxx +++ b/Framework/Core/test/test_ProcessorOptions.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,7 @@ #include "Framework/runDataProcessing.h" #include "Framework/CallbackService.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include <memory> @@ -17,7 +19,7 @@ using namespace o2::framework; #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed at )" << __FILE__ << ":" << __LINE__; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed at )" << __FILE__ << ":" << __LINE__; \ } // This is how you can define your processing in a declarative way diff --git a/Framework/Core/test/test_PtrHelpers.cxx b/Framework/Core/test/test_PtrHelpers.cxx index e7e710b7d1c52..996ccc1797dfe 100644 --- a/Framework/Core/test/test_PtrHelpers.cxx +++ b/Framework/Core/test/test_PtrHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_RegionInfoCallbackService.cxx b/Framework/Core/test/test_RegionInfoCallbackService.cxx index 571da32501584..69c1a2ebab095 100644 --- a/Framework/Core/test/test_RegionInfoCallbackService.cxx +++ b/Framework/Core/test/test_RegionInfoCallbackService.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/ParallelContext.h" #include "Framework/runDataProcessing.h" +#include "Framework/Logger.h" #include <chrono> #include <iostream> diff --git a/Framework/Core/test/test_Root2ArrowTable.cxx b/Framework/Core/test/test_Root2ArrowTable.cxx index 346790dc76388..36fbc0f0fba9d 100644 --- a/Framework/Core/test/test_Root2ArrowTable.cxx +++ b/Framework/Core/test/test_Root2ArrowTable.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_RootConfigParamHelpers.cxx b/Framework/Core/test/test_RootConfigParamHelpers.cxx index e0f8589503b7d..07dd3235e11a2 100644 --- a/Framework/Core/test/test_RootConfigParamHelpers.cxx +++ b/Framework/Core/test/test_RootConfigParamHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_Services.cxx b/Framework/Core/test/test_Services.cxx index ccba588e4c665..b00bdaff3cea4 100644 --- a/Framework/Core/test/test_Services.cxx +++ b/Framework/Core/test/test_Services.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(TestServiceRegistry) ConcreteC const serviceC; registry.registerService(ServiceRegistryHelpers::handleForService<InterfaceA>(&serviceA)); registry.registerService(ServiceRegistryHelpers::handleForService<InterfaceB>(&serviceB)); - registry.registerService(ServiceRegistryHelpers::handleForService<InterfaceC>(&serviceC)); + registry.registerService(ServiceRegistryHelpers::handleForService<InterfaceC const>(&serviceC)); BOOST_CHECK(registry.get<InterfaceA>().method() == true); BOOST_CHECK(registry.get<InterfaceB>().method() == false); BOOST_CHECK(registry.get<InterfaceC const>().method() == false); diff --git a/Framework/Core/test/test_SimpleCondition.cxx b/Framework/Core/test/test_SimpleCondition.cxx index 0145bbfca3a60..a5cfabc5127b2 100644 --- a/Framework/Core/test/test_SimpleCondition.cxx +++ b/Framework/Core/test/test_SimpleCondition.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,9 +36,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto s = ctx.inputs().get<std::string>("condition"); if (s != "Hello") { - LOG(ERROR) << "Expecting `Hello', found `" << s << "'"; + LOG(error) << "Expecting `Hello', found `" << s << "'"; } else { - LOG(INFO) << "Everything OK"; + LOG(info) << "Everything OK"; } ctx.services().get<ControlService>().readyToQuit(QuitRequest::All); } // diff --git a/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx b/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx index 5b485bb186be4..4f75d330498d6 100644 --- a/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx +++ b/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_SimpleRDataFrameProcessing.cxx b/Framework/Core/test/test_SimpleRDataFrameProcessing.cxx index 6af1a87b4d114..4c533c8a6feaa 100644 --- a/Framework/Core/test/test_SimpleRDataFrameProcessing.cxx +++ b/Framework/Core/test/test_SimpleRDataFrameProcessing.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,9 +24,6 @@ #include <memory> using namespace o2::framework; -using DataHeader = o2::header::DataHeader; - -template class std::shared_ptr<arrow::Buffer>; /// Example of how to use ROOT::RDataFrame using DPL. WorkflowSpec defineDataProcessing(ConfigContext const&) @@ -75,22 +73,22 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) /// auto rdf = ctx.inputs().get<RDataSource>("xz"); auto table = s->asArrowTable(); if (table->num_rows() != 100) { - LOG(ERROR) << "Wrong number of entries for the arrow table" << table->num_rows(); + LOG(error) << "Wrong number of entries for the arrow table" << table->num_rows(); } if (table->num_columns() != 2) { - LOG(ERROR) << "Wrong number of columns for the arrow table" << table->num_columns(); + LOG(error) << "Wrong number of columns for the arrow table" << table->num_columns(); } auto source = std::make_unique<ROOT::RDF::RArrowDS>(s->asArrowTable(), std::vector<std::string>{}); ROOT::RDataFrame rdf(std::move(source)); if (*rdf.Count() != 100) { - LOG(ERROR) << "Wrong number of entries for the DataFrame" << *rdf.Count(); + LOG(error) << "Wrong number of entries for the DataFrame" << *rdf.Count(); } if (*rdf.Mean("z") - 3.f > 0.1f) { - LOG(ERROR) << "Wrong average for z"; + LOG(error) << "Wrong average for z"; } control.readyToQuit(QuitRequest::All); diff --git a/Framework/Core/test/test_SimpleStatefulProcessing01.cxx b/Framework/Core/test/test_SimpleStatefulProcessing01.cxx index 2b4c20bd4f0c0..c6c8e3db45d55 100644 --- a/Framework/Core/test/test_SimpleStatefulProcessing01.cxx +++ b/Framework/Core/test/test_SimpleStatefulProcessing01.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,15 +40,15 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) static int step = 0; // incremented in registered callbacks auto startcb = []() { ++step; - LOG(INFO) << "start " << step; + LOG(info) << "start " << step; }; auto stopcb = []() { ++step; - LOG(INFO) << "stop " << step; + LOG(info) << "stop " << step; }; auto resetcb = []() { ++step; - LOG(INFO) << "reset " << step; + LOG(info) << "reset " << step; }; callbacks.set(CallbackService::Id::Start, startcb); callbacks.set(CallbackService::Id::Stop, stopcb); @@ -55,7 +56,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) return adaptStateless([](DataAllocator& outputs, ControlService& control) { auto& out = outputs.newChunk({"TES", "STATEFUL", 0}, sizeof(int)); auto outI = reinterpret_cast<int*>(out.data()); - LOG(INFO) << "foo " << foo; + LOG(info) << "foo " << foo; outI[0] = foo++; control.endOfStream(); control.readyToQuit(QuitRequest::Me); @@ -75,9 +76,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) const int* in = reinterpret_cast<const int*>(inputs.get("test").payload); if (*in != expected++) { - LOG(ERROR) << "Expecting " << expected << " found " << *in; + LOG(error) << "Expecting " << expected << " found " << *in; } else { - LOG(INFO) << "Everything OK for " << (expected - 1); + LOG(info) << "Everything OK for " << (expected - 1); } }); }) // diff --git a/Framework/Core/test/test_SimpleStringProcessing.cxx b/Framework/Core/test/test_SimpleStringProcessing.cxx index c66a4e3678868..0563281f81091 100644 --- a/Framework/Core/test/test_SimpleStringProcessing.cxx +++ b/Framework/Core/test/test_SimpleStringProcessing.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,9 +50,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto s = ctx.inputs().get<std::string>("make"); if (s != "Hello") { - LOG(ERROR) << "Expecting `Hello', found `" << s << "'"; + LOG(error) << "Expecting `Hello', found `" << s << "'"; } else { - LOG(INFO) << "Everything OK"; + LOG(info) << "Everything OK"; } } // } // diff --git a/Framework/Core/test/test_SimpleTimer.cxx b/Framework/Core/test/test_SimpleTimer.cxx index 50c38113e0033..df935eb6eb2a0 100644 --- a/Framework/Core/test/test_SimpleTimer.cxx +++ b/Framework/Core/test/test_SimpleTimer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_SimpleWildcard.cxx b/Framework/Core/test/test_SimpleWildcard.cxx index a5101e8f87478..ffd2d2565b971 100644 --- a/Framework/Core/test/test_SimpleWildcard.cxx +++ b/Framework/Core/test/test_SimpleWildcard.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "Framework/CallbackService.h" #include "Framework/ControlService.h" #include "Framework/EndOfStreamContext.h" +#include "Framework/Logger.h" #include <iostream> #include <algorithm> #include <memory> @@ -52,6 +54,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) }); return adaptStateless([](InputRecord& inputs) { auto s = inputs.get<TObjString*>("in"); - LOG(INFO) << "String is " << s->GetString().Data(); + LOG(info) << "String is " << s->GetString().Data(); }); })}}}; } diff --git a/Framework/Core/test/test_SimpleWildcard02.cxx b/Framework/Core/test/test_SimpleWildcard02.cxx index bd4acbc48b08f..2f630a7fcacd5 100644 --- a/Framework/Core/test/test_SimpleWildcard02.cxx +++ b/Framework/Core/test/test_SimpleWildcard02.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,8 @@ #include "Framework/CallbackService.h" #include "Framework/ControlService.h" #include "Framework/EndOfStreamContext.h" +#include "Framework/Logger.h" +#include "Framework/DataRefUtils.h" #include <iostream> #include <algorithm> #include <memory> @@ -51,14 +54,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) return adaptStateless([](InputRecord& inputs) { auto s = inputs.get<TObjString*>("in"); auto n = inputs.getNofParts(0); - LOG(INFO) << "Number of parts " << inputs.getNofParts(0); + LOG(info) << "Number of parts " << inputs.getNofParts(0); if (n != 2) { - LOG(ERROR) << "Bad number of parts" << inputs.getNofParts(0); + LOG(error) << "Bad number of parts" << inputs.getNofParts(0); } for (size_t i = 0; i < n; ++i) { auto ref = inputs.getByPos(0, i); - auto dh = o2::header::get<o2::header::DataHeader*>(ref.header); - LOG(INFO) << "String is " << s->GetString().Data() << " " << dh->subSpecification; + auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); + LOG(info) << "String is " << s->GetString().Data() << " " << dh->subSpecification; } }); })}}}; } diff --git a/Framework/Core/test/test_SingleDataSource.cxx b/Framework/Core/test/test_SingleDataSource.cxx index 46ac1a7ed1ad8..82127ed4580d8 100644 --- a/Framework/Core/test/test_SingleDataSource.cxx +++ b/Framework/Core/test/test_SingleDataSource.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_SlowConsumer.cxx b/Framework/Core/test/test_SlowConsumer.cxx new file mode 100644 index 0000000000000..33cf533546ef5 --- /dev/null +++ b/Framework/Core/test/test_SlowConsumer.cxx @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DeviceSpec.h" +#include "Framework/RawDeviceService.h" +#include "Framework/ControlService.h" +#include <FairMQDevice.h> +#include <InfoLogger/InfoLogger.hxx> + +#include <chrono> +#include <thread> +#include <vector> + +#include "Framework/runDataProcessing.h" +using namespace o2::framework; + +// This is how you can define your processing in a declarative way +WorkflowSpec defineDataProcessing(ConfigContext const& specs) +{ + return WorkflowSpec{ + {"A", + Inputs{}, + {OutputSpec{{"a"}, "TST", "A"}}, + AlgorithmSpec{adaptStateful([]() { return adaptStateless( + [](DataAllocator& outputs, RawDeviceService& device, ControlService& control) { + static int count = 0; + auto& aData = outputs.make<int>(OutputRef{"a"}); + LOG(info) << count; + aData = count++; + if (count > 1000) { + control.endOfStream(); + control.readyToQuit(QuitRequest::Me); + } + }); })}}, + {"B", + {InputSpec{"x", "TST", "A", Lifetime::Timeframe}}, + {}, + AlgorithmSpec{adaptStateful([]() { return adaptStateless( + [](InputRecord& inputs, RawDeviceService& device, ControlService& control) { + static int expected = 0; + device.device()->WaitFor(std::chrono::milliseconds(3)); + auto& count = inputs.get<int>("x"); + if (expected != count) { + LOGP(ERROR, "Missing message. Expected: {}, Found {}.", expected, count); + control.readyToQuit(QuitRequest::All); + } + expected++; + }); })}}}; +} diff --git a/Framework/Core/test/test_StaggeringWorkflow.cxx b/Framework/Core/test/test_StaggeringWorkflow.cxx index f124d099dc4ba..b2ef8de7986e9 100644 --- a/Framework/Core/test/test_StaggeringWorkflow.cxx +++ b/Framework/Core/test/test_StaggeringWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -62,7 +63,7 @@ using namespace o2::framework; #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed)"; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ } constexpr size_t nPipelines = 3; @@ -96,14 +97,14 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) auto processorFct = [](ProcessingContext& pc) { int nActiveInputs = 0; - LOG(INFO) << "processing ..."; + LOG(info) << "processing ..."; for (auto const& input : pc.inputs()) { if (pc.inputs().isValid(input.spec->binding) == false) { // this input slot is empty continue; } auto& data = pc.inputs().get<MyDataType>(input.spec->binding.c_str()); - LOG(INFO) << "processing " << input.spec->binding << " " << data; + LOG(info) << "processing " << input.spec->binding << " " << data; // check if the channel binding starts with 'trigger' if (input.spec->binding.find("trigger") == 0) { pc.outputs().make<MyDataType>(Output{"PROC", "CHANNEL", data, Lifetime::Timeframe}) = data; @@ -125,7 +126,7 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) return adaptStateless([](InputRecord& inputs) { for (auto const& input : inputs) { auto& data = inputs.get<MyDataType>(input.spec->binding.c_str()); - LOG(INFO) << "received channel " << data; + LOG(info) << "received channel " << data; } }); }); diff --git a/Framework/Core/test/test_StaticFor.cxx b/Framework/Core/test/test_StaticFor.cxx new file mode 100644 index 0000000000000..78298d987e1b8 --- /dev/null +++ b/Framework/Core/test/test_StaticFor.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test Framework StaticFor +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include "Framework/StringHelpers.h" +#include "Framework/StaticFor.h" + +using namespace o2::framework; + +template <int someNumber> +void dummyFunc() +{ + std::cout << "calling function with non-type template argument " << someNumber << std::endl; +} + +BOOST_AUTO_TEST_CASE(TestStaticFor) +{ + // check if it is actually static + static_for<0, 0>([&](auto i) { + static_assert(std::is_same_v<decltype(i), std::integral_constant<int, 0>>); + + static_assert(std::is_same_v<decltype(i.value), const int>); + BOOST_CHECK_EQUAL(i.value, 0); + BOOST_CHECK_EQUAL(i, 0); + + // the following checks will fail + //static_assert(std::is_same_v<decltype(i), std::integral_constant<int, 1>>); + //BOOST_CHECK_EQUAL(i.value, 1); + //BOOST_CHECK_EQUAL(i, 1); + }); + + // dont start at 0 + static_for<5, 5>([&](auto i) { + static_assert(std::is_same_v<decltype(i), std::integral_constant<int, 5>>); + }); + + // check if argument can be used as non-type template argument + static_for<0, 2>([&](auto i) { + dummyFunc<i>(); + dummyFunc<i.value>(); + constexpr auto index = i.value; + dummyFunc<index>(); + }); + + // use static loop in combination with CONST_STR + static constexpr std::string_view staticNames[] = {"Bob", "Alice", "Eve"}; + static_for<0, 2>([&](auto i) { + constexpr int index = i.value; + + // compiler will complain if constexpr is not enforced for index access: + //CONST_STR(staticNames[index]); // works + //CONST_STR(staticNames[i.value]); // fails + + constexpr auto sayHello = CONST_STR("Hello ") + CONST_STR(staticNames[index]); + + std::cout << sayHello.str << std::endl; + }); +} diff --git a/Framework/Core/test/test_StringHelpers.cxx b/Framework/Core/test/test_StringHelpers.cxx index ee03e585f46ca..3551c6a2bb4c0 100644 --- a/Framework/Core/test/test_StringHelpers.cxx +++ b/Framework/Core/test/test_StringHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,9 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK -#include "Framework/StringHelpers.h" #include <boost/test/unit_test.hpp> +#include "Framework/StringHelpers.h" +#include <iostream> BOOST_AUTO_TEST_CASE(StringHelpersHash) { @@ -22,3 +24,46 @@ BOOST_AUTO_TEST_CASE(StringHelpersHash) BOOST_CHECK_EQUAL(compile_time_hash(cs), compile_time_hash("test-string")); BOOST_CHECK_EQUAL(compile_time_hash(s.c_str()), compile_time_hash(cs)); } + +template <typename T> +void printString(const T& constStr) +{ + static_assert(is_const_str<T>::value, "This function can only print compile-time strings!"); + + std::cout << "ConstStr:" << std::endl; + std::cout << "str -> " << constStr.str << std::endl; + std::cout << "hash -> " << constStr.hash << std::endl; +}; + +BOOST_AUTO_TEST_CASE(StringHelpersConstStr) +{ + printString(CONST_STR("this/is/a/histogram")); + + auto myConstStr = CONST_STR("helloWorld"); + printString(myConstStr); + static_assert(std::is_same_v<decltype(myConstStr), ConstStr<'h', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'>>); + static_assert(myConstStr.hash == (uint32_t)942280617); + BOOST_CHECK_EQUAL(myConstStr.hash, compile_time_hash("helloWorld")); + + if constexpr (is_const_str_v(myConstStr)) { + std::cout << "myConstStr is a compile-time string" << std::endl; + } + + auto myConstStr2 = CONST_STR("hello") + CONST_STR("Universe"); + printString(myConstStr2); + static_assert(std::is_same_v<decltype(myConstStr2), ConstStr<'h', 'e', 'l', 'l', 'o', 'U', 'n', 'i', 'v', 'e', 'r', 's', 'e'>>); + + enum ParticleSpecies { + kPion, + kKaon + }; + static constexpr std::string_view hist[] = {"ptDist", "etaDist"}; + static constexpr std::string_view particleSuffix[] = {"_pions", "_kaons"}; + + printString(CONST_STR(hist[0]) + CONST_STR(particleSuffix[kPion])); + printString(CONST_STR(hist[0]) + CONST_STR(particleSuffix[kKaon])); + printString(CONST_STR(hist[1]) + CONST_STR(particleSuffix[kPion])); + printString(CONST_STR(hist[1]) + CONST_STR(particleSuffix[kKaon])); + + BOOST_CHECK_EQUAL(CONST_STR(hist[0]).hash, CONST_STR("ptDist").hash); +} diff --git a/Framework/Core/test/test_SuppressionGenerator.cxx b/Framework/Core/test/test_SuppressionGenerator.cxx index ff6a92a9c9e8a..115f44f171766 100644 --- a/Framework/Core/test/test_SuppressionGenerator.cxx +++ b/Framework/Core/test/test_SuppressionGenerator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_TMessageSerializer.cxx b/Framework/Core/test/test_TMessageSerializer.cxx index bea66936c3452..f482d7dac80ae 100644 --- a/Framework/Core/test/test_TMessageSerializer.cxx +++ b/Framework/Core/test/test_TMessageSerializer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -90,7 +91,7 @@ BOOST_AUTO_TEST_CASE(TestTMessageSerializer_InvalidBuffer) // FIXME: at the moment, TMessage fails directly with a segfault, which it shouldn't do /* try { - auto out = TMessageSerializer::deserialize((o2::byte*)buffer, strlen(buffer)); + auto out = TMessageSerializer::deserialize((std::byte*)buffer, strlen(buffer)); BOOST_ERROR("here we should never get, the function call must fail with exception"); } catch (std::exception& e) { std::string expected(""); @@ -100,7 +101,7 @@ BOOST_AUTO_TEST_CASE(TestTMessageSerializer_InvalidBuffer) // test deserialization of invalid target class and check the exception struct Dummy { }; - BOOST_CHECK_EXCEPTION(TMessageSerializer::deserialize<Dummy>((o2::byte*)buffer, strlen(buffer)), + BOOST_CHECK_EXCEPTION(TMessageSerializer::deserialize<Dummy>((std::byte*)buffer, strlen(buffer)), RuntimeErrorRef, [](RuntimeErrorRef const& ref) { auto& err = error_from_ref(ref); diff --git a/Framework/Core/test/test_TableBuilder.cxx b/Framework/Core/test/test_TableBuilder.cxx index 018847df84641..28d05c2fa9bbf 100644 --- a/Framework/Core/test/test_TableBuilder.cxx +++ b/Framework/Core/test/test_TableBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_Task.cxx b/Framework/Core/test/test_Task.cxx index 379c56960a614..94de22765e081 100644 --- a/Framework/Core/test/test_Task.cxx +++ b/Framework/Core/test/test_Task.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,10 +12,11 @@ #include "Framework/Task.h" #include "Framework/ControlService.h" #include "Framework/Monitoring.h" +#include "Framework/Logger.h" #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed at )" << __FILE__ << ":" << __LINE__; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed at )" << __FILE__ << ":" << __LINE__; \ } using namespace o2::framework; diff --git a/Framework/Core/test/test_TimeParallelPipelining.cxx b/Framework/Core/test/test_TimeParallelPipelining.cxx index 07b4113f5faa9..873d8967ccc88 100644 --- a/Framework/Core/test/test_TimeParallelPipelining.cxx +++ b/Framework/Core/test/test_TimeParallelPipelining.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include <boost/test/unit_test.hpp> #include "../src/DeviceSpecHelpers.h" #include "../src/SimpleResourceManager.h" @@ -52,7 +54,8 @@ BOOST_AUTO_TEST_CASE(TimePipeliningSimple) { auto workflow = defineSimplePipelining(); std::vector<DeviceSpec> devices; - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); @@ -104,7 +107,8 @@ BOOST_AUTO_TEST_CASE(TimePipeliningFull) { auto workflow = defineDataProcessing(); std::vector<DeviceSpec> devices; - auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(); + auto configContext = makeEmptyConfigContext(); + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); auto completionPolicies = CompletionPolicy::createDefaultPolicies(); std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; SimpleResourceManager rm(resources); diff --git a/Framework/Core/test/test_TimePipeline.cxx b/Framework/Core/test/test_TimePipeline.cxx index 976d06b841452..59ee0514bd9c9 100644 --- a/Framework/Core/test/test_TimePipeline.cxx +++ b/Framework/Core/test/test_TimePipeline.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_TimesliceIndex.cxx b/Framework/Core/test/test_TimesliceIndex.cxx index fc34de4162e00..8c78a107fe8e9 100644 --- a/Framework/Core/test/test_TimesliceIndex.cxx +++ b/Framework/Core/test/test_TimesliceIndex.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,11 +15,12 @@ #include <boost/test/unit_test.hpp> #include "Framework/TimesliceIndex.h" +#include "Framework/VariableContextHelpers.h" BOOST_AUTO_TEST_CASE(TestBasics) { using namespace o2::framework; - TimesliceIndex index; + TimesliceIndex index{1}; TimesliceSlot slot; BOOST_REQUIRE_EQUAL(index.size(), 0); @@ -31,11 +33,11 @@ BOOST_AUTO_TEST_CASE(TestBasics) BOOST_CHECK(index.isDirty({0}) == true); index.associate(TimesliceId{20}, TimesliceSlot{0}); BOOST_CHECK(index.isValid(TimesliceSlot{0})); - BOOST_CHECK_EQUAL(index.getTimesliceForSlot(TimesliceSlot{0}).value, 20); + BOOST_CHECK_EQUAL(VariableContextHelpers::getTimeslice(index.getVariablesForSlot(TimesliceSlot{0})).value, 20); BOOST_CHECK(index.isDirty(TimesliceSlot{0})); index.associate(TimesliceId{1}, TimesliceSlot{1}); - BOOST_CHECK_EQUAL(index.getTimesliceForSlot(TimesliceSlot{0}).value, 20); - BOOST_CHECK_EQUAL(index.getTimesliceForSlot(TimesliceSlot{1}).value, 1); + BOOST_CHECK_EQUAL(VariableContextHelpers::getTimeslice(index.getVariablesForSlot(TimesliceSlot{0})).value, 20); + BOOST_CHECK_EQUAL(VariableContextHelpers::getTimeslice(index.getVariablesForSlot(TimesliceSlot{1})).value, 1); BOOST_CHECK(index.isValid(TimesliceSlot{2}) == false); slot = TimesliceSlot{0}; BOOST_CHECK(index.isDirty(slot)); @@ -50,50 +52,50 @@ BOOST_AUTO_TEST_CASE(TestBasics) BOOST_AUTO_TEST_CASE(TestLRUReplacement) { using namespace o2::framework; - TimesliceIndex index; + TimesliceIndex index{1}; index.resize(3); data_matcher::VariableContext context; { context.put({0, uint64_t{10}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); + auto [action, slot] = index.replaceLRUWith(context, {10}); BOOST_CHECK_EQUAL(slot.index, 0); BOOST_CHECK(action == TimesliceIndex::ActionTaken::ReplaceUnused); } { context.put({0, uint64_t{20}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); + auto [action, slot] = index.replaceLRUWith(context, {20}); BOOST_CHECK_EQUAL(slot.index, 1); BOOST_CHECK(action == TimesliceIndex::ActionTaken::ReplaceUnused); } { context.put({0, uint64_t{30}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); + auto [action, slot] = index.replaceLRUWith(context, {30}); BOOST_CHECK_EQUAL(slot.index, 2); BOOST_CHECK(action == TimesliceIndex::ActionTaken::ReplaceUnused); } { context.put({0, uint64_t{40}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); - BOOST_CHECK_EQUAL(slot.index, 0); - BOOST_CHECK(action == TimesliceIndex::ActionTaken::ReplaceObsolete); + auto [action, slot] = index.replaceLRUWith(context, {40}); + BOOST_CHECK_EQUAL(slot.index, TimesliceSlot::INVALID); + BOOST_CHECK(action == TimesliceIndex::ActionTaken::Wait); } { context.put({0, uint64_t{50}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); - BOOST_CHECK_EQUAL(slot.index, 1); - BOOST_CHECK(action == TimesliceIndex::ActionTaken::ReplaceObsolete); + auto [action, slot] = index.replaceLRUWith(context, {50}); + BOOST_CHECK_EQUAL(slot.index, TimesliceSlot::INVALID); + BOOST_CHECK(action == TimesliceIndex::ActionTaken::Wait); } { context.put({0, uint64_t{10}}); context.commit(); - auto [action, slot] = index.replaceLRUWith(context); + auto [action, slot] = index.replaceLRUWith(context, {10}); BOOST_CHECK_EQUAL(slot.index, TimesliceSlot::INVALID); - BOOST_CHECK(action == TimesliceIndex::ActionTaken::DropObsolete); + BOOST_CHECK(action == TimesliceIndex::ActionTaken::Wait); } } diff --git a/Framework/Core/test/test_TreeToTable.cxx b/Framework/Core/test/test_TreeToTable.cxx index de5eb1048eba4..84a4075bbae06 100644 --- a/Framework/Core/test/test_TreeToTable.cxx +++ b/Framework/Core/test/test_TreeToTable.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,11 +35,14 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) Float_t px, py, pz; Double_t random; Int_t ev; + uint8_t b; const Int_t nelem = 9; Double_t ij[nelem] = {0}; + float xyzw[96]; + memset(xyzw, 1, 96 * 4); TString leaflist = Form("ij[%i]/D", nelem); - Int_t ncols = 8; + Int_t ncols = 10; t1.Branch("ok", &ok, "ok/O"); t1.Branch("px", &px, "px/F"); t1.Branch("py", &py, "py/F"); @@ -47,6 +51,8 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) t1.Branch("ev", &ev, "ev/I"); t1.Branch("ij", ij, leaflist.Data()); t1.Branch("tests", ts, "tests[5]/O"); + t1.Branch("xyzw", xyzw, "xyzw[96]/F"); + t1.Branch("small", &b, "small/b"); //fill the tree int ntruein[2] = {0}; @@ -59,6 +65,7 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) pz = px * px + py * py; random = gRandom->Rndm(); ev = i + 1; + b = i % 3; for (Int_t jj = 0; jj < nelem; jj++) { ij[jj] = i + 100 * jj; } @@ -75,12 +82,7 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) // Create an arrow table from this. TreeToTable tr2ta; - auto stat = tr2ta.addAllColumns(&t1); - if (!stat) { - LOG(ERROR) << "Table was not created!"; - return; - } - + tr2ta.addAllColumns(&t1); tr2ta.fill(&t1); auto table = tr2ta.finalize(); f1.Close(); @@ -89,14 +91,28 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) BOOST_REQUIRE_EQUAL(table->Validate().ok(), true); BOOST_REQUIRE_EQUAL(table->num_rows(), ndp); BOOST_REQUIRE_EQUAL(table->num_columns(), ncols); - BOOST_REQUIRE_EQUAL(table->column(0)->type()->id(), arrow::boolean()->id()); - BOOST_REQUIRE_EQUAL(table->column(1)->type()->id(), arrow::float32()->id()); - BOOST_REQUIRE_EQUAL(table->column(2)->type()->id(), arrow::float32()->id()); - BOOST_REQUIRE_EQUAL(table->column(3)->type()->id(), arrow::float32()->id()); - BOOST_REQUIRE_EQUAL(table->column(4)->type()->id(), arrow::float64()->id()); - BOOST_REQUIRE_EQUAL(table->column(5)->type()->id(), arrow::int32()->id()); - BOOST_REQUIRE_EQUAL(table->column(6)->type()->id(), arrow::fixed_size_list(arrow::float64(), nelem)->id()); - BOOST_REQUIRE_EQUAL(table->column(7)->type()->id(), arrow::fixed_size_list(arrow::boolean(), 5)->id()); + + BOOST_REQUIRE_EQUAL(table->column(0)->type()->id(), arrow::Type::BOOL); + BOOST_REQUIRE_EQUAL(table->column(1)->type()->id(), arrow::Type::FLOAT); + BOOST_REQUIRE_EQUAL(table->column(2)->type()->id(), arrow::Type::FLOAT); + BOOST_REQUIRE_EQUAL(table->column(3)->type()->id(), arrow::Type::FLOAT); + BOOST_REQUIRE_EQUAL(table->column(4)->type()->id(), arrow::Type::DOUBLE); + BOOST_REQUIRE_EQUAL(table->column(5)->type()->id(), arrow::Type::INT32); + BOOST_REQUIRE_EQUAL(table->column(6)->type()->id(), arrow::Type::FIXED_SIZE_LIST); + BOOST_REQUIRE_EQUAL(table->column(7)->type()->id(), arrow::Type::FIXED_SIZE_LIST); + BOOST_REQUIRE_EQUAL(table->column(8)->type()->id(), arrow::Type::FIXED_SIZE_LIST); + BOOST_REQUIRE_EQUAL(table->column(9)->type()->id(), arrow::Type::UINT8); + + BOOST_REQUIRE(table->column(0)->type()->Equals(arrow::boolean())); + BOOST_REQUIRE(table->column(1)->type()->Equals(arrow::float32())); + BOOST_REQUIRE(table->column(2)->type()->Equals(arrow::float32())); + BOOST_REQUIRE(table->column(3)->type()->Equals(arrow::float32())); + BOOST_REQUIRE(table->column(4)->type()->Equals(arrow::float64())); + BOOST_REQUIRE(table->column(5)->type()->Equals(arrow::int32())); + BOOST_REQUIRE(table->column(6)->type()->Equals(arrow::fixed_size_list(arrow::float64(), nelem))); + BOOST_REQUIRE(table->column(7)->type()->Equals(arrow::fixed_size_list(arrow::boolean(), 5))); + BOOST_REQUIRE(table->column(8)->type()->Equals(arrow::fixed_size_list(arrow::float32(), 96))); + BOOST_REQUIRE(table->column(9)->type()->Equals(arrow::uint8())); // count number of rows with ok==true int ntrueout = 0; @@ -126,9 +142,9 @@ BOOST_AUTO_TEST_CASE(TreeToTableConversion) BOOST_REQUIRE_EQUAL(ntruein[1], ntrueout); // save table as tree - TFile* f2 = new TFile("table2tree.root", "RECREATE"); + TFile* f2 = TFile::Open("table2tree.root", "RECREATE"); TableToTree ta2tr(table, f2, "mytree"); - stat = ta2tr.addAllBranches(); + ta2tr.addAllBranches(); auto t2 = ta2tr.process(); auto br = (TBranch*)t2->GetBranch("ok"); diff --git a/Framework/Core/test/test_TypeTraits.cxx b/Framework/Core/test/test_TypeTraits.cxx index 6447593fefee0..7488d172b1f07 100644 --- a/Framework/Core/test/test_TypeTraits.cxx +++ b/Framework/Core/test/test_TypeTraits.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -141,20 +142,3 @@ BOOST_AUTO_TEST_CASE(TestIsSpan) BOOST_REQUIRE_EQUAL(is_span<decltype(b)>::value, false); BOOST_REQUIRE_EQUAL(is_span<decltype(c)>::value, false); } - -BOOST_AUTO_TEST_CASE(TestCanAssign) -{ - using Callback = std::function<bool(int, float)>; - auto matching = [](int, float) -> bool { - return true; - }; - auto otherReturn = [](int, float) -> int { - return 0; - }; - auto otherParam = [](int, int) -> bool { - return true; - }; - BOOST_REQUIRE((can_assign<decltype(matching), Callback>::value == true)); - BOOST_REQUIRE((can_assign<decltype(otherReturn), Callback>::value == false)); - BOOST_REQUIRE((can_assign<decltype(otherParam), Callback>::value == false)); -} diff --git a/Framework/Core/test/test_Variants.cxx b/Framework/Core/test/test_Variants.cxx index 0b34a853f8713..82426fdef70a3 100644 --- a/Framework/Core/test/test_Variants.cxx +++ b/Framework/Core/test/test_Variants.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,9 @@ #include <boost/test/unit_test.hpp> #include "Framework/Variant.h" +#include "Framework/VariantStringHelpers.h" +#include "Framework/VariantPropertyTreeHelpers.h" +#include "Framework/VariantJSONHelpers.h" #include <sstream> #include <cstring> @@ -20,7 +24,7 @@ using namespace o2::framework; bool unknown_type(RuntimeErrorRef const& ref) { - auto& err = error_from_ref(ref); + auto const& err = error_from_ref(ref); return strcmp(err.what, "Mismatch between types") == 0; } @@ -105,4 +109,173 @@ BOOST_AUTO_TEST_CASE(VariantTest) for (auto i = 0u; i < fd.size(); ++i) { BOOST_CHECK(farr[i] == (fd.get<float*>())[i]); } + + std::vector<std::string> vstrings{"s1", "s2", "s3"}; + std::string strings[] = {"l1", "l2", "l3"}; + Variant vstr(strings, 3); + Variant vvstr(vstrings); + + BOOST_CHECK(vstr.size() == 3); + BOOST_CHECK(vvstr.size() == 3); + for (auto i = 0u; i < vstr.size(); ++i) { + BOOST_CHECK(strings[i] == (vstr.get<std::string*>())[i]); + } + for (auto i = 0u; i < vvstr.size(); ++i) { + BOOST_CHECK(vstrings[i] == (vvstr.get<std::string*>())[i]); + } + + Variant vsc(vstr); // Copy constructor + Variant vsm(std::move(vstr)); // Move constructor + Variant vscc = vsm; // Copy assignment + for (auto i = 0u; i < vsm.size(); ++i) { + BOOST_CHECK(strings[i] == (vsm.get<std::string*>())[i]); + } + for (auto i = 0u; i < vscc.size(); ++i) { + BOOST_CHECK(strings[i] == (vscc.get<std::string*>())[i]); + } + + float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + Array2D mm(&m[0][0], 3, 4); + Variant vmm(mm); + auto const& mmc = vmm.get<Array2D<float>>(); + for (auto i = 0u; i < 3; ++i) { + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(mmc(i, j) == mm(i, j)); + } + } + + Variant vmmc(vmm); // Copy constructor + Variant vmmm(std::move(vmm)); // Move constructor + Variant vmma = vmmm; // Copy assignment + auto const& mmc2 = vmmc.get<Array2D<float>>(); + for (auto i = 0u; i < 3; ++i) { + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(mmc2(i, j) == mm(i, j)); + } + } + auto const& mmc3 = vmma.get<Array2D<float>>(); + for (auto i = 0u; i < 3; ++i) { + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(mmc3(i, j) == mm(i, j)); + } + } + std::stringstream ssm; + ssm << vmma; + BOOST_CHECK(ssm.str() == "f[[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8], [0.9, 1, 1.1, 1.2]]"); + + LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; + Variant vlaf(laf); + auto const& lafc = vlaf.get<LabeledArray<float>>(); + for (auto i = 0u; i < 3; ++i) { + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(laf.get(i, j) == lafc.get(i, j)); + } + } + + Variant vlafc(vlaf); // Copy constructor + Variant vlafm(std::move(vlaf)); // Move constructor + Variant vlafa = vlafm; // Copy assignment + auto const& lafc2 = vlafc.get<LabeledArray<float>>(); + for (auto i = 0U; i < 3; ++i) { + for (auto j = 0U; j < 4; ++j) { + BOOST_CHECK(lafc2.get(i, j) == mm(i, j)); + } + } + auto const& lafc3 = vlafa.get<LabeledArray<float>>(); + for (auto i = 0U; i < 3; ++i) { + for (auto j = 0U; j < 4; ++j) { + BOOST_CHECK(lafc3.get(i, j) == mm(i, j)); + } + } + + std::vector<Variant> collection; + collection.push_back(vlafc); + collection.push_back(vlafm); + collection.push_back(vlafa); +} + +BOOST_AUTO_TEST_CASE(Array2DTest) +{ + float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + Array2D mm(&m[0][0], 3, 4); + for (auto i = 0U; i < 3; ++i) { + for (auto j = 0U; j < 4; ++j) { + BOOST_CHECK(mm(i, j) == m[i][j]); + } + } + std::vector<float> v = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2}; + Array2D mv(v, 3, 4); + for (auto i = 0U; i < 3; ++i) { + for (auto j = 0U; j < 4; ++j) { + BOOST_CHECK(mm(i, j) == v[i * 4 + j]); + } + } + for (auto i = 0U; i < 3; ++i) { + auto const& vv = mm[i]; + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(vv[j] == mm(i, j)); + } + } +} + +BOOST_AUTO_TEST_CASE(LabeledArrayTest) +{ + float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + std::string xl[] = {"c1", "c2", "c3", "c4"}; + std::string yl[] = {"r1", "r2", "r3"}; + LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; + for (auto i = 0u; i < 3; ++i) { + for (auto j = 0u; j < 4; ++j) { + BOOST_CHECK(laf.get(yl[i].c_str(), xl[j].c_str()) == laf.get(i, j)); + BOOST_CHECK(laf.get(i, xl[j].c_str()) == laf.get(i, j)); + BOOST_CHECK(laf.get(yl[i].c_str(), j) == laf.get(i, j)); + } + } +} + +BOOST_AUTO_TEST_CASE(VariantConversionsTest) +{ + int iarr[] = {1, 2, 3, 4, 5}; + Variant viarr(iarr, 5); + std::stringstream os; + VariantJSONHelpers::write(os, viarr); + + std::stringstream is; + is.str(os.str()); + auto v = VariantJSONHelpers::read<VariantType::ArrayInt>(is); + for (auto i = 0u; i < viarr.size(); ++i) { + BOOST_CHECK_EQUAL(v.get<int*>()[i], viarr.get<int*>()[i]); + } + os.str(""); + + float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + Array2D mm(&m[0][0], 3, 4); + Variant vmm(mm); + std::stringstream osm; + VariantJSONHelpers::write(osm, vmm); + + std::stringstream ism; + ism.str(osm.str()); + auto vm = VariantJSONHelpers::read<VariantType::Array2DFloat>(ism); + + for (auto i = 0u; i < mm.rows; ++i) { + for (auto j = 0u; j < mm.cols; ++j) { + BOOST_CHECK_EQUAL(vmm.get<Array2D<float>>()(i, j), vm.get<Array2D<float>>()(i, j)); + } + } + + LabeledArray<float> laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; + Variant vlaf(laf); + std::stringstream osl; + VariantJSONHelpers::write(osl, vlaf); + + std::stringstream isl; + isl.str(osl.str()); + auto vlafc = VariantJSONHelpers::read<VariantType::LabeledArrayFloat>(isl); + + for (auto i = 0u; i < vlafc.get<LabeledArray<float>>().rows(); ++i) { + for (auto j = 0u; j < vlafc.get<LabeledArray<float>>().cols(); ++j) { + BOOST_CHECK_EQUAL(vlaf.get<LabeledArray<float>>().get(i, j), vlafc.get<LabeledArray<float>>().get(i, j)); + } + } } diff --git a/Framework/Core/test/test_WorkflowHelpers.cxx b/Framework/Core/test/test_WorkflowHelpers.cxx index 9b9c36a171a12..039fae13c202a 100644 --- a/Framework/Core/test/test_WorkflowHelpers.cxx +++ b/Framework/Core/test/test_WorkflowHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,6 +12,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "Mocking.h" #include "test_HelperMacros.h" #include "Framework/ConfigContext.h" #include "Framework/WorkflowSpec.h" @@ -24,46 +26,27 @@ using namespace o2::framework; -std::unique_ptr<ConfigContext> makeEmptyConfigContext() -{ - // FIXME: Ugly... We need to fix ownership and make sure the ConfigContext - // either owns or shares ownership of the registry. - std::vector<std::unique_ptr<ParamRetriever>> retrievers; - static std::vector<ConfigParamSpec> specs = { - ConfigParamSpec{"forwarding-policy", - VariantType::String, - "dangling", - {""}}, - ConfigParamSpec{"forwarding-destination", - VariantType::String, - "file", - {"what to do with dangling outputs. file: write to file, fairmq: send to output proxy"}}, - }; - specs.push_back(ConfigParamSpec{"aod-memory-rate-limit", VariantType::String, "0", {"rate"}}); - auto store = std::make_unique<ConfigParamStore>(specs, std::move(retrievers)); - store->preload(); - store->activate(); - static ConfigParamRegistry registry(std::move(store)); - auto context = std::make_unique<ConfigContext>(registry, 0, nullptr); - return context; -} - BOOST_AUTO_TEST_CASE(TestVerifyWorkflow) { using namespace o2::framework; auto checkIncompleteInput = [](WorkflowSpec const& workflow) { // Empty workflows should be invalid. - BOOST_CHECK_THROW(WorkflowHelpers::verifyWorkflow(workflow), std::runtime_error); + BOOST_CHECK_THROW((void)WorkflowHelpers::verifyWorkflow(workflow), std::runtime_error); + }; + + auto checkSpecialChars = [](WorkflowSpec const& workflow) { + // Empty workflows should be invalid. + BOOST_CHECK_THROW((void)WorkflowHelpers::verifyWorkflow(workflow), std::runtime_error); }; auto checkOk = [](WorkflowSpec const& workflow) { // Empty workflows should be invalid. - BOOST_CHECK_NO_THROW(WorkflowHelpers::verifyWorkflow(workflow)); + BOOST_CHECK_NO_THROW((void)WorkflowHelpers::verifyWorkflow(workflow)); }; auto checkNotOk = [](WorkflowSpec const& workflow) { // Empty workflows should be invalid. - BOOST_CHECK_THROW(WorkflowHelpers::verifyWorkflow(workflow), std::runtime_error); + BOOST_CHECK_THROW((void)WorkflowHelpers::verifyWorkflow(workflow), std::runtime_error); }; // A non fully specified input is an error, given the result is ambiguous. @@ -73,6 +56,8 @@ BOOST_AUTO_TEST_CASE(TestVerifyWorkflow) checkIncompleteInput(WorkflowSpec{{"A", {InputSpec{"x", "", ""}}}}); // missing description checkIncompleteInput(WorkflowSpec{{"A", {InputSpec{"x", "TST", ""}}}}); + // comma is not allowed + checkSpecialChars(WorkflowSpec{{"A,B", {}}}); // This is fine, since by default both subSpec == 0 and // Timeframe are assumed. checkOk(WorkflowSpec{{"A", {InputSpec{"x", "TST", "A"}}}}); @@ -232,7 +217,8 @@ BOOST_AUTO_TEST_CASE(TestSimpleConnection) std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; - WorkflowHelpers::verifyWorkflow(workflow); + auto result = WorkflowHelpers::verifyWorkflow(workflow); + BOOST_REQUIRE(result == WorkflowParsingState::Valid); auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); BOOST_CHECK_EQUAL(workflow.size(), 3); @@ -273,7 +259,7 @@ BOOST_AUTO_TEST_CASE(TestSimpleForward) std::vector<DeviceConnectionEdge> logicalEdges; std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; - WorkflowHelpers::verifyWorkflow(workflow); + BOOST_REQUIRE(WorkflowHelpers::verifyWorkflow(workflow) == WorkflowParsingState::Valid); auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); WorkflowHelpers::constructGraph(workflow, logicalEdges, @@ -330,7 +316,7 @@ BOOST_AUTO_TEST_CASE(TestGraphConstruction) // channels, so that we can construct them before assigning to a device. std::vector<OutputSpec> outputs; - WorkflowHelpers::verifyWorkflow(workflow); + BOOST_REQUIRE(WorkflowHelpers::verifyWorkflow(workflow) == WorkflowParsingState::Valid); auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); WorkflowHelpers::constructGraph(workflow, logicalEdges, @@ -449,7 +435,7 @@ BOOST_AUTO_TEST_CASE(TestExternalInput) InputSpec{"external", "TST", "A", 0, Lifetime::Timer}}, Outputs{ OutputSpec{"TST", "B"}}}}; - WorkflowHelpers::verifyWorkflow(workflow); + BOOST_REQUIRE(WorkflowHelpers::verifyWorkflow(workflow) == WorkflowParsingState::Valid); std::vector<DeviceConnectionEdge> logicalEdges; std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; @@ -536,7 +522,7 @@ BOOST_AUTO_TEST_CASE(TestOriginWildcard) std::vector<OutputSpec> outputs; std::vector<LogicalForwardInfo> availableForwardsInfo; - WorkflowHelpers::verifyWorkflow(workflow); + BOOST_REQUIRE(WorkflowHelpers::verifyWorkflow(workflow) == WorkflowParsingState::Valid); auto context = makeEmptyConfigContext(); WorkflowHelpers::injectServiceDevices(workflow, *context); BOOST_CHECK_EQUAL(workflow.size(), 3); diff --git a/Framework/Core/test/test_WorkflowSerialization.cxx b/Framework/Core/test/test_WorkflowSerialization.cxx index 4618b5e28813c..5c00fe8b88be8 100644 --- a/Framework/Core/test/test_WorkflowSerialization.cxx +++ b/Framework/Core/test/test_WorkflowSerialization.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,7 +49,9 @@ BOOST_AUTO_TEST_CASE(TestVerifyWorkflow) DataProcessorSpec{"D", {InputSpec{"foo", {"C", "D"}}}, // {OutputSpec{{"bar"}, {"I", "L"}}}, // AlgorithmSpec{[](ProcessingContext& ctx) {}}, // - {}}}; // + {}, // + CommonServices::defaultServices(), // + {{"label a"}, {"label \"b\""}}}}; std::vector<DataProcessorInfo> metadataOut{ {"A", "test_Framework_test_SerializationWorkflow", {"foo"}, {ConfigParamSpec{"aBool", VariantType::Bool, true, {"A Bool"}}}}, @@ -57,19 +60,23 @@ BOOST_AUTO_TEST_CASE(TestVerifyWorkflow) {"D", "test_Framework_test_SerializationWorkflow", {}}, }; + CommandInfo commandInfoOut{"o2-dpl-workflow -b --option 1 --option 2"}; + std::vector<DataProcessorInfo> metadataIn{}; + CommandInfo commandInfoIn; std::ostringstream firstDump; - WorkflowSerializationHelpers::dump(firstDump, w0, metadataOut); + WorkflowSerializationHelpers::dump(firstDump, w0, metadataOut, commandInfoOut); std::istringstream is; is.str(firstDump.str()); WorkflowSpec w1; - WorkflowSerializationHelpers::import(is, w1, metadataIn); + WorkflowSerializationHelpers::import(is, w1, metadataIn, commandInfoIn); std::ostringstream secondDump; - WorkflowSerializationHelpers::dump(secondDump, w1, metadataIn); + WorkflowSerializationHelpers::dump(secondDump, w1, metadataIn, commandInfoIn); BOOST_REQUIRE_EQUAL(w0.size(), 4); BOOST_REQUIRE_EQUAL(w0.size(), w1.size()); BOOST_CHECK_EQUAL(firstDump.str(), secondDump.str()); + BOOST_CHECK_EQUAL(commandInfoIn.command, commandInfoOut.command); } diff --git a/Framework/Core/test/unittest_DataSpecUtils.cxx b/Framework/Core/test/unittest_DataSpecUtils.cxx index f35c214a149a1..7ba9c691c8003 100644 --- a/Framework/Core/test/unittest_DataSpecUtils.cxx +++ b/Framework/Core/test/unittest_DataSpecUtils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -256,6 +257,20 @@ BOOST_AUTO_TEST_CASE(TestMatcherFromDescription) BOOST_CHECK_EQUAL(DataSpecUtils::asConcreteDataDescription(ddSpec).as<std::string>(), "TSET"); } +BOOST_AUTO_TEST_CASE(TestMatcherFromConcrete) +{ + auto fromQueryInputSpec = DataSpecUtils::dataDescriptorMatcherFrom(ConcreteDataMatcher{"TSET", "FOO", 1}); + InputSpec ddSpec{ + "binding", + std::move(fromQueryInputSpec)}; + + auto concrete = DataSpecUtils::asConcreteDataMatcher(ddSpec); + + BOOST_CHECK_EQUAL(concrete.origin.as<std::string>(), "TSET"); + BOOST_CHECK_EQUAL(concrete.description.as<std::string>(), "FOO"); + BOOST_CHECK_EQUAL(concrete.subSpec, 1); +} + BOOST_AUTO_TEST_CASE(FindOutputSpec) { std::vector<OutputSpec> specs = { @@ -327,4 +342,8 @@ BOOST_AUTO_TEST_CASE(Includes) BOOST_CHECK(DataSpecUtils::includes(wildcardInput1, wildcardInput1)); BOOST_CHECK(!DataSpecUtils::includes(wildcardInput1, wildcardInput2)); BOOST_CHECK(!DataSpecUtils::includes(wildcardInput2, wildcardInput1)); + + auto inputsFromQuery = DataDescriptorQueryBuilder::parse("b0:TST/FOO/0;b1:TST/FOO/1"); + BOOST_CHECK(!DataSpecUtils::includes(inputsFromQuery[0], inputsFromQuery[1])); + BOOST_CHECK(!DataSpecUtils::includes(inputsFromQuery[1], inputsFromQuery[0])); } diff --git a/Framework/Core/test/unittest_SimpleOptionsRetriever.cxx b/Framework/Core/test/unittest_SimpleOptionsRetriever.cxx index 957b174e6a58e..5d39158077400 100644 --- a/Framework/Core/test/unittest_SimpleOptionsRetriever.cxx +++ b/Framework/Core/test/unittest_SimpleOptionsRetriever.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/3rdparty/CMakeLists.txt b/Framework/Foundation/3rdparty/CMakeLists.txt new file mode 100644 index 0000000000000..70b96641025c4 --- /dev/null +++ b/Framework/Foundation/3rdparty/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_header_only_library(FrameworkFoundation3rdparty) diff --git a/Framework/Foundation/3rdparty/include/Framework/SHA1.h b/Framework/Foundation/3rdparty/include/Framework/SHA1.h new file mode 100644 index 0000000000000..cdf6bf18b17d9 --- /dev/null +++ b/Framework/Foundation/3rdparty/include/Framework/SHA1.h @@ -0,0 +1,294 @@ +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#ifndef O2_FRAMEWORK_SHA1_H_ +#define O2_FRAMEWORK_SHA1_H_ + +#define SHA1HANDSOFF + +#include <cstdio> +#include <cstring> + +/* for uint32_t */ +#include <cstdint> + +#define SHA_rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define SHA_blk0(i) (block->l[i] = (SHA_rol(block->l[i], 24) & 0xFF00FF00) | (SHA_rol(block->l[i], 8) & 0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define SHA_blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define SHA_blk(i) (block->l[i & 15] = SHA_rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define SHA_R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + SHA_blk0(i) + 0x5A827999 + SHA_rol(v, 5); \ + w = SHA_rol(w, 30); +#define SHA_R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + SHA_blk(i) + 0x5A827999 + SHA_rol(v, 5); \ + w = SHA_rol(w, 30); +#define SHA_R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + SHA_blk(i) + 0x6ED9EBA1 + SHA_rol(v, 5); \ + w = SHA_rol(w, 30); +#define SHA_R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + SHA_blk(i) + 0x8F1BBCDC + SHA_rol(v, 5); \ + w = SHA_rol(w, 30); +#define SHA_R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + SHA_blk(i) + 0xCA62C1D6 + SHA_rol(v, 5); \ + w = SHA_rol(w, 30); + +namespace o2::framework::internal +{ + +typedef struct +{ + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64]) +{ + uint32_t a, b, c, d, e; + + typedef union { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + +#ifdef SHA1HANDSOFF + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ + CHAR64LONG16* block = (const CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + SHA_R0(a, b, c, d, e, 0); + SHA_R0(e, a, b, c, d, 1); + SHA_R0(d, e, a, b, c, 2); + SHA_R0(c, d, e, a, b, 3); + SHA_R0(b, c, d, e, a, 4); + SHA_R0(a, b, c, d, e, 5); + SHA_R0(e, a, b, c, d, 6); + SHA_R0(d, e, a, b, c, 7); + SHA_R0(c, d, e, a, b, 8); + SHA_R0(b, c, d, e, a, 9); + SHA_R0(a, b, c, d, e, 10); + SHA_R0(e, a, b, c, d, 11); + SHA_R0(d, e, a, b, c, 12); + SHA_R0(c, d, e, a, b, 13); + SHA_R0(b, c, d, e, a, 14); + SHA_R0(a, b, c, d, e, 15); + SHA_R1(e, a, b, c, d, 16); + SHA_R1(d, e, a, b, c, 17); + SHA_R1(c, d, e, a, b, 18); + SHA_R1(b, c, d, e, a, 19); + SHA_R2(a, b, c, d, e, 20); + SHA_R2(e, a, b, c, d, 21); + SHA_R2(d, e, a, b, c, 22); + SHA_R2(c, d, e, a, b, 23); + SHA_R2(b, c, d, e, a, 24); + SHA_R2(a, b, c, d, e, 25); + SHA_R2(e, a, b, c, d, 26); + SHA_R2(d, e, a, b, c, 27); + SHA_R2(c, d, e, a, b, 28); + SHA_R2(b, c, d, e, a, 29); + SHA_R2(a, b, c, d, e, 30); + SHA_R2(e, a, b, c, d, 31); + SHA_R2(d, e, a, b, c, 32); + SHA_R2(c, d, e, a, b, 33); + SHA_R2(b, c, d, e, a, 34); + SHA_R2(a, b, c, d, e, 35); + SHA_R2(e, a, b, c, d, 36); + SHA_R2(d, e, a, b, c, 37); + SHA_R2(c, d, e, a, b, 38); + SHA_R2(b, c, d, e, a, 39); + SHA_R3(a, b, c, d, e, 40); + SHA_R3(e, a, b, c, d, 41); + SHA_R3(d, e, a, b, c, 42); + SHA_R3(c, d, e, a, b, 43); + SHA_R3(b, c, d, e, a, 44); + SHA_R3(a, b, c, d, e, 45); + SHA_R3(e, a, b, c, d, 46); + SHA_R3(d, e, a, b, c, 47); + SHA_R3(c, d, e, a, b, 48); + SHA_R3(b, c, d, e, a, 49); + SHA_R3(a, b, c, d, e, 50); + SHA_R3(e, a, b, c, d, 51); + SHA_R3(d, e, a, b, c, 52); + SHA_R3(c, d, e, a, b, 53); + SHA_R3(b, c, d, e, a, 54); + SHA_R3(a, b, c, d, e, 55); + SHA_R3(e, a, b, c, d, 56); + SHA_R3(d, e, a, b, c, 57); + SHA_R3(c, d, e, a, b, 58); + SHA_R3(b, c, d, e, a, 59); + SHA_R4(a, b, c, d, e, 60); + SHA_R4(e, a, b, c, d, 61); + SHA_R4(d, e, a, b, c, 62); + SHA_R4(c, d, e, a, b, 63); + SHA_R4(b, c, d, e, a, 64); + SHA_R4(a, b, c, d, e, 65); + SHA_R4(e, a, b, c, d, 66); + SHA_R4(d, e, a, b, c, 67); + SHA_R4(c, d, e, a, b, 68); + SHA_R4(b, c, d, e, a, 69); + SHA_R4(a, b, c, d, e, 70); + SHA_R4(e, a, b, c, d, 71); + SHA_R4(d, e, a, b, c, 72); + SHA_R4(c, d, e, a, b, 73); + SHA_R4(b, c, d, e, a, 74); + SHA_R4(a, b, c, d, e, 75); + SHA_R4(e, a, b, c, d, 76); + SHA_R4(d, e, a, b, c, 77); + SHA_R4(c, d, e, a, b, 78); + SHA_R4(b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + +/* SHA1Init - Initialize new context */ + +static void SHA1Init( + SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +/* Run your data through this. */ + +static void SHA1Update( + SHA1_CTX* context, + const unsigned char* data, + uint32_t len) +{ + uint32_t i; + + uint32_t j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) { + context->count[1]++; + } + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } else { + i = 0; + } + memcpy(&context->buffer[j], &data[i], len - i); +} + +/* Add padding and return the message digest. */ + +static void SHA1Final( + unsigned char digest[20], + SHA1_CTX* context) +{ + unsigned i; + + unsigned char finalcount[8]; + + unsigned char c; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + } + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +void SHA1( + char* hash_out, + const char* str, + unsigned int len) +{ + SHA1_CTX ctx; + unsigned int ii; + + SHA1Init(&ctx); + for (ii = 0; ii < len; ii += 1) { + SHA1Update(&ctx, (const unsigned char*)str + ii, 1); + } + SHA1Final((unsigned char*)hash_out, &ctx); + hash_out[20] = '\0'; +} + +} // namespace o2::framework::internal + +#undef SHA1HANDSOFF +#undef SHA_rol +#undef SHA_blk0 +#undef SHA_blk +#undef SHA_R0 +#undef SHA_R1 +#undef SHA_R2 +#undef SHA_R3 +#undef SHA_R4 + +#endif // O2_FRAMEWORK_SHA1_H_ diff --git a/Framework/Foundation/CMakeLists.txt b/Framework/Foundation/CMakeLists.txt index ab4c3d7c4fe99..4f7f45704bee6 100644 --- a/Framework/Foundation/CMakeLists.txt +++ b/Framework/Foundation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/Framework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) @@ -14,7 +15,10 @@ install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/Framework o2_add_library(FrameworkFoundation SOURCES src/RuntimeError.cxx TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::FrameworkFoundation3rdparty ) +set(DPL_ENABLE_BACKTRACE ON CACHE BOOL "Enable backtrace on o2::framework::runtime_error") + if (DPL_ENABLE_BACKTRACE) target_compile_definitions(${targetName} PUBLIC -DDPL_ENABLE_BACKTRACE) endif() @@ -49,3 +53,5 @@ o2_add_test(test_RuntimeError NAME test_FrameworkFoundation_RuntimeError COMPONENT_NAME FrameworkFoundation SOURCES test/test_RuntimeError.cxx PUBLIC_LINK_LIBRARIES O2::FrameworkFoundation) + +add_subdirectory(3rdparty) diff --git a/Framework/Foundation/include/Framework/CheckTypes.h b/Framework/Foundation/include/Framework/CheckTypes.h index 681a787d071b9..5cd49f1b55719 100644 --- a/Framework/Foundation/include/Framework/CheckTypes.h +++ b/Framework/Foundation/include/Framework/CheckTypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,16 +22,25 @@ constexpr bool is_type_complete_v = false; template <typename T> constexpr bool is_type_complete_v<T, std::void_t<decltype(sizeof(T))>> = true; -/// Helper which will invoke lambda if the type T is actually available. +/// Helper which will invoke @a onDefined if the type T is actually available +/// or @a onUndefined if the type T is a forward declaration. /// Can be used to check for existence or not of a given type. -template <typename T, typename TLambda> -void call_if_defined(TLambda&& lambda) +template <typename T, typename TDefined, typename TUndefined> +void call_if_defined_full(TDefined&& onDefined, TUndefined&& onUndefined) { if constexpr (is_type_complete_v<T>) { - lambda(static_cast<T*>(nullptr)); + onDefined(static_cast<T*>(nullptr)); + } else { + onUndefined(); } } +template <typename T, typename TDefined> +void call_if_defined(TDefined&& onDefined) +{ + call_if_defined_full<T>(onDefined, []() -> void {}); +} + } // namespace o2::framework #endif // O2_FRAMEWORK_CHECKTYPES_H_ diff --git a/Framework/Foundation/include/Framework/CompilerBuiltins.h b/Framework/Foundation/include/Framework/CompilerBuiltins.h index 93d0215bcb25c..8906cdcacc332 100644 --- a/Framework/Foundation/include/Framework/CompilerBuiltins.h +++ b/Framework/Foundation/include/Framework/CompilerBuiltins.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,8 +29,8 @@ #define O2_BUILTIN_LIKELY(x) __builtin_expect((x), 1) #define O2_BUILTIN_UNLIKELY(x) __builtin_expect((x), 0) #else -#define O2_BUILTIN_LIKELY(x) -#define O2_BUILTIN_UNLIKELY(x) +#define O2_BUILTIN_LIKELY(x) (x) +#define O2_BUILTIN_UNLIKELY(x) (x) #endif #if __GNUC__ diff --git a/Framework/Foundation/include/Framework/Endian.h b/Framework/Foundation/include/Framework/Endian.h new file mode 100644 index 0000000000000..16b45500c26cb --- /dev/null +++ b/Framework/Foundation/include/Framework/Endian.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_ENDIAN_H_ +#define O2_FRAMEWORK_ENDIAN_H_ + +// Lookup file for __BYTE_ORDER +#ifdef __APPLE__ +#include <machine/endian.h> +#else +#include <endian.h> +#define ntohll be64toh +#define htonll htobe64 +#endif +#define O2_HOST_BYTE_ORDER __BYTE_ORDER +#define O2_BIG_ENDIAN __BIG_ENDIAN +#define O2_LITTLE_ENDIAN __LITTLE_ENDIAN +#endif // O2_FRAMEWORK_ENDIAN_H_ diff --git a/Framework/Foundation/include/Framework/FunctionalHelpers.h b/Framework/Foundation/include/Framework/FunctionalHelpers.h index ccf89a0c1c5f8..7e060e8816e3b 100644 --- a/Framework/Foundation/include/Framework/FunctionalHelpers.h +++ b/Framework/Foundation/include/Framework/FunctionalHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/include/Framework/Pack.h b/Framework/Foundation/include/Framework/Pack.h index 59282108fb434..62c1f10338777 100644 --- a/Framework/Foundation/include/Framework/Pack.h +++ b/Framework/Foundation/include/Framework/Pack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,6 @@ #include <cstddef> #include <utility> -#include <cstdio> namespace o2::framework { diff --git a/Framework/Foundation/include/Framework/RuntimeError.h b/Framework/Foundation/include/Framework/RuntimeError.h index 05692690d1bc7..2e0b086a2e047 100644 --- a/Framework/Foundation/include/Framework/RuntimeError.h +++ b/Framework/Foundation/include/Framework/RuntimeError.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,8 @@ RuntimeErrorRef runtime_error(const char*); RuntimeErrorRef runtime_error_f(const char*, ...); RuntimeError& error_from_ref(RuntimeErrorRef); +void throw_error(RuntimeErrorRef); + } // namespace o2::framework #endif // O2_FRAMEWORK_RUNTIMEERROR_H_ diff --git a/Framework/Foundation/include/Framework/Signpost.h b/Framework/Foundation/include/Framework/Signpost.h index 8d0d98e168a36..51a80d3c2f5b9 100644 --- a/Framework/Foundation/include/Framework/Signpost.h +++ b/Framework/Foundation/include/Framework/Signpost.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/include/Framework/StructToTuple.h b/Framework/Foundation/include/Framework/StructToTuple.h index 305516c2cbc76..20dcdcb734e32 100644 --- a/Framework/Foundation/include/Framework/StructToTuple.h +++ b/Framework/Foundation/include/Framework/StructToTuple.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,7 @@ #define O2_FRAMEWORK_STRUCTTOTUPLE_H_ #include <Framework/Traits.h> -#include <tuple> -#include <type_traits> +#include <vector> namespace o2::framework { @@ -33,36 +33,31 @@ template <class T, typename... Args> struct is_braces_constructible : decltype(test<T, Args...>(0)) { }; -/// Helper function to convert a brace-initialisable struct to -/// a tuple. -template <class T> -auto constexpr to_tuple(T&& object) noexcept -{ - using type = std::decay_t<T>; - if constexpr (is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) { - auto&& [p0, p1, p2, p3] = object; - return std::make_tuple(p0, p1, p2, p3); - } else if constexpr (is_braces_constructible<type, any_type, any_type, any_type>{}) { - auto&& [p0, p1, p2] = object; - return std::make_tuple(p0, p1, p2); - } else if constexpr (is_braces_constructible<type, any_type, any_type>{}) { - auto&& [p0, p1] = object; - return std::make_tuple(p0, p1); - } else if constexpr (is_braces_constructible<type, any_type>{}) { - auto&& [p0] = object; - return std::make_tuple(p0); - } else { - return std::make_tuple(); +#if __cplusplus >= 202002L +struct UniversalType { + template <typename T> + operator T() + { } -} +}; template <typename T> -constexpr int brace_constructible_size() +consteval auto brace_constructible_size(auto... Members) +{ + if constexpr (requires { T{Members...}; } == false) + return sizeof...(Members) - 1; + else + return brace_constructible_size<T>(Members..., UniversalType{}); +} +#else +template <typename T> +constexpr long brace_constructible_size() { using A = any_type; using type = std::decay_t<T>; - - if constexpr (is_braces_constructible<type, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A>{}) { + if constexpr (is_braces_constructible<type, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A>{}) { + return 40; + } else if constexpr (is_braces_constructible<type, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A>{}) { return 39; } else if constexpr (is_braces_constructible<type, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A>{}) { return 38; @@ -144,136 +139,135 @@ constexpr int brace_constructible_size() return 0; } } +#endif -/// Helper function to convert a brace-initialisable struct to -/// a tuple. -template <class T> -auto constexpr to_tuple_refs(T&& object) noexcept +template <typename L, class T> +auto constexpr homogeneous_apply_refs(L l, T&& object) noexcept { using type = std::decay_t<T>; - constexpr int numElements = brace_constructible_size<T>(); + constexpr unsigned long numElements = brace_constructible_size<T>(); if constexpr (numElements == 40) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34), l(p35), l(p36), l(p37), l(p38), l(p39)}; } else if constexpr (numElements == 39) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34), l(p35), l(p36), l(p37), l(p38)}; } else if constexpr (numElements == 38) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34), l(p35), l(p36), l(p37)}; } else if constexpr (numElements == 37) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34), l(p35), l(p36)}; } else if constexpr (numElements == 36) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34), l(p35)}; } else if constexpr (numElements == 35) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33), l(p34)}; } else if constexpr (numElements == 34) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32), l(p33)}; } else if constexpr (numElements == 33) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31), l(p32)}; } else if constexpr (numElements == 32) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30), l(p31)}; } else if constexpr (numElements == 31) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29), l(p30)}; } else if constexpr (numElements == 30) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28), l(p29)}; } else if constexpr (numElements == 29) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27), l(p28)}; } else if constexpr (numElements == 28) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26), l(p27)}; } else if constexpr (numElements == 27) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25), l(p26)}; } else if constexpr (numElements == 26) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24), l(p25)}; } else if constexpr (numElements == 25) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23), l(p24)}; } else if constexpr (numElements == 24) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22), l(p23)}; } else if constexpr (numElements == 23) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21), l(p22)}; } else if constexpr (numElements == 22) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20), l(p21)}; } else if constexpr (numElements == 21) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19), l(p20)}; } else if constexpr (numElements == 20) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18), l(p19)}; } else if constexpr (numElements == 19) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17), l(p18)}; } else if constexpr (numElements == 18) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16), l(p17)}; } else if constexpr (numElements == 17) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15), l(p16)}; } else if constexpr (numElements == 16) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14), l(p15)}; } else if constexpr (numElements == 15) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13), l(p14)}; } else if constexpr (numElements == 14) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12), l(p13)}; } else if constexpr (numElements == 13) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11), l(p12)}; } else if constexpr (numElements == 12) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10), l(p11)}; } else if constexpr (numElements == 11) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9), l(p10)}; } else if constexpr (numElements == 10) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8), l(p9)}; } else if constexpr (numElements == 9) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7, p8] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7, p8); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7), l(p8)}; } else if constexpr (numElements == 8) { auto&& [p0, p1, p2, p3, p4, p5, p6, p7] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6, p7); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6), l(p7)}; } else if constexpr (numElements == 7) { auto&& [p0, p1, p2, p3, p4, p5, p6] = object; - return std::tie(p0, p1, p2, p3, p4, p5, p6); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5), l(p6)}; } else if constexpr (numElements == 6) { auto&& [p0, p1, p2, p3, p4, p5] = object; - return std::tie(p0, p1, p2, p3, p4, p5); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4), l(p5)}; } else if constexpr (numElements == 5) { auto&& [p0, p1, p2, p3, p4] = object; - return std::tie(p0, p1, p2, p3, p4); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3), l(p4)}; } else if constexpr (numElements == 4) { auto&& [p0, p1, p2, p3] = object; - return std::tie(p0, p1, p2, p3); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2), l(p3)}; } else if constexpr (numElements == 3) { auto&& [p0, p1, p2] = object; - return std::tie(p0, p1, p2); + return std::vector<decltype(l(p0))>{l(p0), l(p1), l(p2)}; } else if constexpr (numElements == 2) { auto&& [p0, p1] = object; - return std::tie(p0, p1); + return std::vector<decltype(l(p0))>{l(p0), l(p1)}; } else if constexpr (numElements == 1) { auto&& [p0] = object; - return std::tie(p0); + return std::vector<decltype(l(p0))>{l(p0)}; } else { - return std::make_tuple(); + return false; } } diff --git a/Framework/Foundation/include/Framework/Tracing.h b/Framework/Foundation/include/Framework/Tracing.h index e1ec3d57c52a2..f5bcecd3889d7 100644 --- a/Framework/Foundation/include/Framework/Tracing.h +++ b/Framework/Foundation/include/Framework/Tracing.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/include/Framework/Traits.h b/Framework/Foundation/include/Framework/Traits.h index 4fa561f021a8b..ecf4484f61f59 100644 --- a/Framework/Foundation/include/Framework/Traits.h +++ b/Framework/Foundation/include/Framework/Traits.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/include/Framework/TypeIdHelpers.h b/Framework/Foundation/include/Framework/TypeIdHelpers.h index 7139211a856f2..2d5367bb6cd13 100644 --- a/Framework/Foundation/include/Framework/TypeIdHelpers.h +++ b/Framework/Foundation/include/Framework/TypeIdHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #define O2_FRAMEWORK_TYPEIDHELPERS_H_ #include <string_view> +#include <sstream> #include "Framework/StringHelpers.h" #if defined(__GNUC__) && (__GNUC__ < 8) @@ -50,6 +52,37 @@ struct TypeIdHelpers { } }; +/// Return pure type name with no namespaces etc. +/// Works fine with GCC and CLANG +template <typename T> +constexpr static std::string_view type_name() +{ + constexpr std::string_view wrapped_name{unique_type_id_v<T>}; + const std::string_view left_marker{"T = "}; + const std::string_view right_marker{"]"}; + const auto left_marker_index = wrapped_name.find(left_marker); + const auto start_index = left_marker_index + left_marker.size(); + const auto end_index = wrapped_name.find(right_marker, left_marker_index); + const auto length = end_index - start_index; + return wrapped_name.substr(start_index, length); +} + +/// Convert a CamelCase task struct name to snake-case task name +inline static std::string type_to_task_name(std::string_view& camelCase) +{ + std::ostringstream str; + str << static_cast<char>(std::tolower(camelCase[0])); + + for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) { + if (std::isupper(*it) && *(it - 1) != '-') { + str << "-"; + } + str << static_cast<char>(std::tolower(*it)); + } + + return str.str(); +} + } // namespace o2::framework #endif // O2_FRAMEWORK_TYPEIDHELPERS_H_ diff --git a/Framework/Foundation/include/Framework/VariantHelpers.h b/Framework/Foundation/include/Framework/VariantHelpers.h index e4427fe40ac55..363e56da1f8ce 100644 --- a/Framework/Foundation/include/Framework/VariantHelpers.h +++ b/Framework/Foundation/include/Framework/VariantHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/src/RuntimeError.cxx b/Framework/Foundation/src/RuntimeError.cxx index 0bb39a70601a7..6cdfbe10b3dda 100644 --- a/Framework/Foundation/src/RuntimeError.cxx +++ b/Framework/Foundation/src/RuntimeError.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -61,6 +62,7 @@ RuntimeErrorRef runtime_error_f(const char* format, ...) va_list args; va_start(args, format); vsnprintf(gError[i].what, RuntimeError::MAX_RUNTIME_ERROR_SIZE, format, args); + va_end(args); gError[i].maxBacktrace = canDumpBacktrace() ? backtrace(gError[i].backtrace, RuntimeError::MAX_BACKTRACE_SIZE) : 0; return RuntimeErrorRef{i}; } @@ -77,4 +79,9 @@ RuntimeErrorRef runtime_error(const char* s) return RuntimeErrorRef{i}; } +void throw_error(RuntimeErrorRef ref) +{ + throw ref; +} + } // namespace o2::framework diff --git a/Framework/Foundation/src/Traits.cxx b/Framework/Foundation/src/Traits.cxx index ab2179b8eb11c..faff430964e73 100644 --- a/Framework/Foundation/src/Traits.cxx +++ b/Framework/Foundation/src/Traits.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/test/test_CompilerBuiltins.cxx b/Framework/Foundation/test/test_CompilerBuiltins.cxx index c7024dc342fbf..fa45a785891f8 100644 --- a/Framework/Foundation/test/test_CompilerBuiltins.cxx +++ b/Framework/Foundation/test/test_CompilerBuiltins.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/test/test_FunctionalHelpers.cxx b/Framework/Foundation/test/test_FunctionalHelpers.cxx index af49a4c3ce7c8..e77f9a0b88504 100644 --- a/Framework/Foundation/test/test_FunctionalHelpers.cxx +++ b/Framework/Foundation/test/test_FunctionalHelpers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/test/test_RuntimeError.cxx b/Framework/Foundation/test/test_RuntimeError.cxx index 44867d627f5df..9dfd73e6f4b19 100644 --- a/Framework/Foundation/test/test_RuntimeError.cxx +++ b/Framework/Foundation/test/test_RuntimeError.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/test/test_Signpost.cxx b/Framework/Foundation/test/test_Signpost.cxx index ce78f21c0e318..fc5d3fb6422fb 100644 --- a/Framework/Foundation/test/test_Signpost.cxx +++ b/Framework/Foundation/test/test_Signpost.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Foundation/test/test_StructToTuple.cxx b/Framework/Foundation/test/test_StructToTuple.cxx index ac51df4d36bf7..6b13ffcf9396e 100644 --- a/Framework/Foundation/test/test_StructToTuple.cxx +++ b/Framework/Foundation/test/test_StructToTuple.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -71,29 +72,10 @@ struct FooMax { BOOST_AUTO_TEST_CASE(TestStructToTuple) { - Foo foo; - //auto t1 = o2::framework::to_tuple(foo); - //#BOOST_CHECK_EQUAL(std::get<0>(t1), 1); - // Expand a struct which inherits from - // another.. - Bar bar{4, 5}; - BOOST_CHECK_EQUAL(bar.foo, 4); - BOOST_CHECK_EQUAL(bar.bar, 5); - auto t2 = o2::framework::to_tuple(bar); - BOOST_CHECK_EQUAL(std::get<0>(t2), 4); - BOOST_CHECK_EQUAL(std::get<1>(t2), 5); - std::get<0>(t2) = 10; - BOOST_CHECK_EQUAL(std::get<0>(t2), 10); - BOOST_CHECK_EQUAL(bar.foo, 4); - - auto t3 = o2::framework::to_tuple_refs(bar); - BOOST_CHECK_EQUAL(std::get<0>(t3), 4); - BOOST_CHECK_EQUAL(std::get<1>(t3), 5); - - std::get<0>(t3) = 10; - BOOST_CHECK_EQUAL(std::get<0>(t3), 10); - BOOST_CHECK_EQUAL(bar.foo, 10); - FooMax fooMax; - auto t4 = o2::framework::to_tuple_refs(fooMax); + + auto t5 = o2::framework::homogeneous_apply_refs([](auto i) -> bool { return i > 20; }, fooMax); + BOOST_CHECK_EQUAL(t5[0], false); + BOOST_CHECK_EQUAL(t5[19], false); + BOOST_CHECK_EQUAL(t5[20], true); } diff --git a/Framework/Foundation/test/test_Traits.cxx b/Framework/Foundation/test/test_Traits.cxx index 916e31d6d06d0..c3a510ef300f4 100644 --- a/Framework/Foundation/test/test_Traits.cxx +++ b/Framework/Foundation/test/test_Traits.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/GUISupport/CMakeLists.txt b/Framework/GUISupport/CMakeLists.txt new file mode 100644 index 0000000000000..6fc3ef3e48e13 --- /dev/null +++ b/Framework/GUISupport/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +# Given GCC 7.3 does not provide std::filesystem we use Boost instead +# Drop this once we move to GCC 8.2+ +o2_add_library(FrameworkGUISupport + SOURCES src/Plugin.cxx + src/FrameworkGUIDebugger.cxx + src/FrameworkGUIDevicesGraph.cxx + src/FrameworkGUIDeviceInspector.cxx + src/FrameworkGUIDataRelayerUsage.cxx + src/PaletteHelpers.cxx + PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/src + PUBLIC_LINK_LIBRARIES O2::Framework AliceO2::DebugGUI) + +if (NOT APPLE) +set (DEBUG_GUI_TESTS_WORKFLOW + CustomGUIGL + CustomGUISokol + SimpleTracksED + ) +endif() + +foreach(w + ${DEBUG_GUI_TESTS_WORKFLOW} + ) + o2_add_test(${w} NAME test_Framework_test_${w} + SOURCES test/test_${w}.cxx + COMPONENT_NAME Framework + LABELS framework workflow + PUBLIC_LINK_LIBRARIES O2::Framework AliceO2::DebugGUI + TIMEOUT 30 + NO_BOOST_TEST + COMMAND_LINE_ARGS ${DPL_WORKFLOW_TESTS_EXTRA_OPTIONS} --run --shm-segment-size 20000000) +endforeach() + +# TODO: investigate the problem with the two unit tests, maybe setup of the CI +# environment assertion fired X11: The DISPLAY environment variable is missing +# glfw-3.2.1/src/window.c:579: glfwGetFramebufferSize: Assertion `window != +# ((void *)0)' failed. +if(NOT APPLE AND BUILD_TESTING) +set_property(TEST test_Framework_test_SimpleTracksED PROPERTY DISABLED TRUE) +set_property(TEST test_Framework_test_CustomGUIGL PROPERTY DISABLED TRUE) +set_property(TEST test_Framework_test_CustomGUISokol PROPERTY DISABLED TRUE) +endif() diff --git a/Framework/Core/src/FrameworkGUIDataRelayerUsage.cxx b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx similarity index 80% rename from Framework/Core/src/FrameworkGUIDataRelayerUsage.cxx rename to Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx index 0a5b5e865793d..2f431cd9445e4 100644 --- a/Framework/Core/src/FrameworkGUIDataRelayerUsage.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,10 @@ #include <functional> #include "Framework/DeviceMetricsInfo.h" #include "Framework/DeviceInfo.h" +#include "Framework/DataDescriptorMatcher.h" +#include "PaletteHelpers.h" #include <iostream> +#include <cstring> #include <cmath> static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } @@ -39,7 +43,7 @@ struct HeatMapHelper { constexpr float MAX_BOX_X_SIZE = 16.f; constexpr float MAX_BOX_Y_SIZE = 16.f; ImDrawList* drawList = ImGui::GetWindowDrawList(); - ImVec2 winPos = ImGui::GetCursorScreenPos(); + ImVec2 winPos = ImGui::GetCursorScreenPos() + ImVec2{0, 7}; auto records = getNumRecords(); auto boxSizeX = std::min(size.x / records, MAX_BOX_X_SIZE); @@ -56,8 +60,8 @@ struct HeatMapHelper { ImVec2{size.x, size.y} + winPos, BACKGROUND_COLOR); drawList->AddRect( - ImVec2(0., 0.) + winPos, - ImVec2{size.x - 1, size.y} + winPos, + ImVec2(0. - 1, -1) + winPos, + ImVec2{size.x + 1, size.y - 1} + winPos, BORDER_COLOR); float padding = 1; for (size_t ri = 0, re = getNumRecords(); ri < re; ri++) { @@ -115,9 +119,9 @@ void displayDataRelayer(DeviceMetricsInfo const& metrics, auto getValue = [](int const& item) -> int { return item; }; auto getColor = [](int value) { const ImU32 SLOT_EMPTY = ImColor(70, 70, 70, 255); - const ImU32 SLOT_FULL = ImColor(0xf9, 0xcd, 0xad, 255); - const ImU32 SLOT_DISPATCHED = ImColor(0xc8, 0xc8, 0xa9, 255); - const ImU32 SLOT_DONE = ImColor(0x83, 0xaf, 0, 255); + const ImU32 SLOT_FULL = ImColor(PaletteHelpers::RED); + const ImU32 SLOT_DISPATCHED = ImColor(PaletteHelpers::YELLOW); + const ImU32 SLOT_DONE = ImColor(PaletteHelpers::GREEN); const ImU32 SLOT_ERROR = ImColor(0xfe, 0x43, 0x65, 255); switch (value) { case 0: @@ -140,10 +144,22 @@ void displayDataRelayer(DeviceMetricsInfo const& metrics, MetricInfo const& metricInfo = metrics.metrics[variablesIndex.indexes[idx]]; assert(metricInfo.storeIdx < metrics.stringMetrics.size()); auto& data = metrics.stringMetrics[metricInfo.storeIdx]; - if (vi == 0) { - ImGui::Text("$%zu (timeslice): %s", vi, data[(metricInfo.pos - 1) % data.size()].data); - } else { - ImGui::Text("$%zu: %s", vi, data[(metricInfo.pos - 1) % data.size()].data); + char const* value = data[(metricInfo.pos - 1) % data.size()].data; + if (strncmp("null", value, 4) == 0) { + continue; + } + switch (vi) { + case o2::framework::data_matcher::STARTTIME_POS: + ImGui::Text("$%zu (startTime): %s", vi, value); + break; + case o2::framework::data_matcher::TFCOUNTER_POS: + ImGui::Text("$%zu (tfCounter): %s", vi, value); + break; + case o2::framework::data_matcher::FIRSTTFORBIT_POS: + ImGui::Text("$%zu (firstTFOrbit): %s", vi, value); + break; + default: + ImGui::Text("$%zu: %s", vi, value); } } ImGui::EndTooltip(); diff --git a/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.h b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.h new file mode 100644 index 0000000000000..e89a54c858ddb --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +class ImVec2; + +namespace o2 +{ +namespace framework +{ +class DeviceMetricsInfo; +class DeviceInfo; + +namespace gui +{ + +/// View of the DataRelayer metrics for a given DeviceInfo +void displayDataRelayer(DeviceMetricsInfo const& metrics, DeviceInfo const& info, ImVec2 const& size); + +} // namespace gui +} // namespace framework +} // namespace o2 diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.cxx b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx new file mode 100644 index 0000000000000..beeb42a03d8dd --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx @@ -0,0 +1,1114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "FrameworkGUIDebugger.h" +#include "Framework/ConfigContext.h" +#include "Framework/ConfigParamRegistry.h" +#include "DebugGUI/imgui.h" +#include "DebugGUI/implot.h" +#include "DebugGUI/imgui_extras.h" +#include "Framework/DriverControl.h" +#include "Framework/DriverInfo.h" +#include "Framework/DeviceMetricsHelper.h" +#include "FrameworkGUIDeviceInspector.h" +#include "FrameworkGUIDevicesGraph.h" +#include "FrameworkGUIDataRelayerUsage.h" +#include "PaletteHelpers.h" +#include "FrameworkGUIState.h" + +#include <fmt/format.h> + +#include <algorithm> +#include <iostream> +#include <set> +#include <string> +#include <cinttypes> + +// Simplify debugging +template class std::vector<o2::framework::DeviceMetricsInfo>; + +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } + +namespace o2::framework::gui +{ +// Type erased information for the plotting +struct MultiplotData { + int mod; + size_t first; + size_t size; + const void* Y = nullptr; + const void* X = nullptr; + MetricType type; + const char* legend = nullptr; + int axis = 0; +}; + +} // namespace o2::framework::gui + +template class std::vector<o2::framework::gui::MultiplotData>; + +namespace o2::framework::gui +{ + +ImVec4 colorForLogLevel(LogParsingHelpers::LogLevel logLevel) +{ + switch (logLevel) { + case LogParsingHelpers::LogLevel::Info: + return PaletteHelpers::GREEN; + case LogParsingHelpers::LogLevel::Debug: + return ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); + case LogParsingHelpers::LogLevel::Warning: + return PaletteHelpers::DARK_YELLOW; + case LogParsingHelpers::LogLevel::Error: + return PaletteHelpers::RED; + case LogParsingHelpers::LogLevel::Unknown: + return ImVec4(194. / 255, 195. / 255, 199. / 255, 255. / 255); + default: + return ImVec4(194. / 255, 195. / 255, 199. / 255, 255. / 255); + }; +} + +void displayHistory(const DeviceInfo& info, DeviceControl& control) +{ + if (info.history.empty()) { + return; + } + int startPos = info.historyPos; + const int historySize = info.history.size(); + + int triggerStartPos = startPos + 1 % historySize; + int triggerStopPos = startPos % historySize; + + int j = startPos; + // We look for a stop trigger, so that we know where to stop the search for + // out start search. If no stop trigger is found, we search until the end + if (control.logStopTrigger[0]) { + while ((j % historySize) != ((startPos + 1) % historySize)) { + assert(j >= 0); + assert(j < historySize); + auto& line = info.history[j]; + if (strstr(line.c_str(), control.logStopTrigger)) { + triggerStopPos = (j + 1) % historySize; + break; + } + // Wrap in case we end up below 0 + j = (j == 0) ? historySize - 1 : j - 1; + } + } + + // Look for the last instance of the start trigger before the + // last stop trigger. + j = startPos + 1; + if (control.logStartTrigger[0]) { + while ((j % historySize) != triggerStopPos) { + assert(historySize > j); + assert(historySize == 1000); + auto& line = info.history[j]; + if (strstr(line.c_str(), control.logStartTrigger)) { + triggerStartPos = j; + } + j = (j + 1) % historySize; + } + } + + // We start from the last trigger found. Eventually this is the first + // line in the ring buffer, if no trigger is specified. + size_t ji = triggerStartPos % historySize; + size_t je = triggerStopPos % historySize; + size_t iterations = 0; + while (historySize && ((ji % historySize) != je)) { + assert(iterations < historySize); + iterations++; + assert(historySize == 1000); + assert(ji < historySize); + auto& line = info.history[ji]; + auto logLevel = info.historyLevel[ji]; + + // Skip empty lines + if (line.empty()) { + ji = (ji + 1) % historySize; + continue; + } + // Print matching lines + if (strstr(line.c_str(), control.logFilter) != nullptr) { + auto color = colorForLogLevel(logLevel); + // We filter twice, once on input, to reduce the + // stream, a second time at display time, to avoid + // showing unrelevant messages from past. + if (logLevel >= control.logLevel) { + if (line.find('%', 0) != std::string::npos) { + ImGui::TextUnformatted(line.c_str(), line.c_str() + line.size()); + } else { + ImGui::TextColored(color, line.c_str(), line.c_str() + line.size()); + } + } + } + ji = (ji + 1) % historySize; + } +} + +struct HistoData { + int mod; + size_t first; + size_t size; + void* points = nullptr; + const size_t* time = nullptr; + char const* legend = nullptr; +}; + +enum struct MetricsDisplayStyle : int { + Lines = 0, + Histos = 1, + Sparks = 2, + Table = 3, + Stems = 4 +}; + +/// Information associated to a node in the topology +struct TopologyNodeInfo { + std::string label; +}; + +struct MetricDisplayState { + int axis = 0; // The Axis to use for Y + bool visible = false; + bool selected = false; + std::string legend; + size_t legendHash = -1; +}; + +struct MetricIndex { + size_t storeIndex; + size_t deviceIndex; + size_t metricIndex; + size_t stateIndex; +}; + +enum MetricTypes { + DEVICE_METRICS = 0, + DRIVER_METRICS, + TOTAL_TYPES_OF_METRICS +}; + +// We use this to keep together all the kind of metrics +// so that we can display driver and device metrics in the same plot +// without an if. +struct AllMetricsStore { + std::vector<DeviceMetricsInfo> const* metrics[TOTAL_TYPES_OF_METRICS]; + std::vector<TopologyNodeInfo> const* specs[TOTAL_TYPES_OF_METRICS]; +}; + +void displaySparks( + double startTime, + std::vector<MetricIndex>& visibleMetricsIndex, + std::vector<MetricDisplayState>& metricDisplayStates, + AllMetricsStore const& metricStore) +{ + static bool locked = false; + ImGui::Checkbox("Lock scrolling", &locked); + ImGui::BeginTable("##sparks table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY, ImVec2{-1, -1}); + ImGui::TableSetupColumn("##close button", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, 25); + ImGui::TableSetupColumn("##plot name", ImGuiTableColumnFlags_WidthFixed, 200); + ImGui::TableSetupColumn("##plot", ImGuiTableColumnFlags_WidthFixed, 0); + ImGui::TableSetupScrollFreeze(2, 0); + for (size_t i = 0; i < visibleMetricsIndex.size(); ++i) { + auto& index = visibleMetricsIndex[i]; + auto& metricsInfos = *metricStore.metrics[index.storeIndex]; + auto& nodes = *metricStore.specs[index.storeIndex]; + auto& metricsInfo = metricsInfos[index.deviceIndex]; + auto& label = metricsInfo.metricLabels[index.metricIndex]; + auto& metric = metricsInfo.metrics[index.metricIndex]; + auto& state = metricDisplayStates[index.stateIndex]; + + ImGui::TableNextColumn(); + ImGui::PushID(index.stateIndex); + state.visible = !ImGui::Button("-"); + ImGui::PopID(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(state.legend.c_str()); + ImGui::TableNextColumn(); + static ImPlotAxisFlags rtx_axis = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickMarks; + static ImPlotAxisFlags rty_axis = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickMarks; + ImGui::PushID(index.stateIndex); + HistoData data; + data.mod = std::min(metric.filledMetrics, metricsInfo.timestamps[index.metricIndex].size()); + data.first = metric.pos - data.mod; + data.size = metric.filledMetrics; + data.time = metricsInfo.timestamps[index.metricIndex].data(); + data.legend = state.legend.c_str(); + + if (!locked) { + ImPlot::SetNextPlotLimitsX((startTime + ImGui::GetTime() - 100) * 1000, (startTime + ImGui::GetTime()) * 1000, ImGuiCond_Always); + ImPlot::SetNextPlotLimitsY(metricsInfo.min[index.metricIndex], metricsInfo.max[index.metricIndex] * 1.1, ImGuiCond_Always); + rty_axis |= ImPlotAxisFlags_LockMin; + } + if (ImPlot::BeginPlot("##sparks", "time", "value", ImVec2(700, 100), 0, rtx_axis, rty_axis)) { + ImPlot::SetPlotYAxis(state.axis); + switch (metric.type) { + case MetricType::Int: { + data.points = (void*)metricsInfo.intMetrics[metric.storeIdx].data(); + + auto getter = [](void* hData, int idx) -> ImPlotPoint { + auto histoData = reinterpret_cast<HistoData*>(hData); + size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; + assert(pos >= 0 && pos < 1024); + return ImPlotPoint(histoData->time[pos], ((int*)(histoData->points))[pos]); + }; + ImPlot::PlotLineG("##plot", getter, &data, data.size); + } break; + case MetricType::Uint64: { + data.points = (void*)metricsInfo.uint64Metrics[metric.storeIdx].data(); + + auto getter = [](void* hData, int idx) -> ImPlotPoint { + auto histoData = reinterpret_cast<HistoData*>(hData); + size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; + assert(pos >= 0 && pos < 1024); + return ImPlotPoint(histoData->time[pos], ((uint64_t*)histoData->points)[pos]); + }; + ImPlot::PlotLineG("##plot", getter, &data, data.size, 0); + } break; + case MetricType::Float: { + data.points = (void*)metricsInfo.floatMetrics[metric.storeIdx].data(); + + auto getter = [](void* hData, int idx) -> ImPlotPoint { + auto histoData = reinterpret_cast<HistoData*>(hData); + size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; + assert(pos >= 0 && pos < 1024); + return ImPlotPoint(histoData->time[pos], ((float*)histoData->points)[pos]); + }; + ImPlot::PlotLineG("##plot", getter, &data, data.size, 0); + } break; + default: + return; + break; + } + ImPlot::EndPlot(); + } + ImGui::PopID(); + } + ImGui::EndTable(); +} + +void displayDeviceMetrics(const char* label, + size_t rangeBegin, size_t rangeEnd, size_t bins, MetricsDisplayStyle displayType, + std::vector<MetricDisplayState>& state, + AllMetricsStore const& metricStore) +{ + std::vector<void*> metricsToDisplay; + std::vector<const char*> deviceNames; + std::vector<MultiplotData> userData; + MetricType metricType; +#ifdef NDEBUG + for (size_t si = 0; si < TOTAL_TYPES_OF_METRICS; ++si) { + assert(metricsStore.metrics[si].size() == metricStore.specs[si].size()); + } +#endif + float maxValue[3] = {std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest()}; + float minValue[3] = {0, 0, 0}; + size_t maxDomain = std::numeric_limits<size_t>::lowest(); + size_t minDomain = std::numeric_limits<size_t>::max(); + size_t gmi = 0; + + ImPlotFlags axisFlags = 0; + + for (size_t si = 0; si < TOTAL_TYPES_OF_METRICS; ++si) { + std::vector<DeviceMetricsInfo> const& metricsInfos = *metricStore.metrics[si]; + auto const& specs = *metricStore.specs[si]; + for (int di = 0; di < metricsInfos.size(); ++di) { + for (size_t mi = 0; mi < metricsInfos[di].metrics.size(); ++mi) { + auto& label = metricsInfos[di].metricLabels[mi]; + if (state[gmi].visible == false) { + gmi++; + continue; + } + auto& metric = metricsInfos[di].metrics[mi]; + deviceNames.push_back(specs[di].label.c_str()); + metricType = metric.type; + MultiplotData data; + data.size = metric.filledMetrics; + data.mod = std::min(metric.filledMetrics, metricsInfos[di].timestamps[mi].size()); + data.first = metric.pos - data.mod; + data.X = metricsInfos[di].timestamps[mi].data(); + data.legend = state[gmi].legend.c_str(); + data.type = metric.type; + data.axis = state[gmi].axis; + minValue[data.axis] = std::min(minValue[data.axis], metricsInfos[di].min[mi]); + maxValue[data.axis] = std::max(maxValue[data.axis], metricsInfos[di].max[mi]); + minDomain = std::min(minDomain, metricsInfos[di].minDomain[mi]); + maxDomain = std::max(maxDomain, metricsInfos[di].maxDomain[mi]); + axisFlags |= data.axis == 1 ? ImPlotFlags_YAxis2 : ImPlotFlags_None; + axisFlags |= data.axis == 2 ? ImPlotFlags_YAxis3 : ImPlotFlags_None; + switch (metric.type) { + case MetricType::Int: { + data.Y = metricsInfos[di].intMetrics[metric.storeIdx].data(); + } break; + case MetricType::Uint64: { + data.Y = metricsInfos[di].uint64Metrics[metric.storeIdx].data(); + } break; + case MetricType::Float: { + data.Y = metricsInfos[di].floatMetrics[metric.storeIdx].data(); + } break; + case MetricType::Unknown: + case MetricType::String: { + data.Y = nullptr; + data.type = MetricType::String; + metricType = MetricType::String; + } break; + } + + userData.emplace_back(data); + gmi++; + } + } + } + + maxDomain = std::max(minDomain + 1024, maxDomain); + for (size_t ai = 0; ai < 3; ++ai) { + maxValue[ai] = std::max(minValue[ai] + 1.f, maxValue[ai]); + } + + static size_t lastMinRange = minDomain; + static size_t lastMaxRange = maxDomain; + + // Nothing to show. + if (userData.empty()) { + return; + } + for (size_t ui = 0; ui < userData.size(); ++ui) { + metricsToDisplay.push_back(&(userData[ui])); + } + + auto getterXY = [](void* hData, int idx) -> ImPlotPoint { + auto histoData = reinterpret_cast<const MultiplotData*>(hData); + size_t pos = (histoData->first + static_cast<size_t>(idx)) % histoData->mod; + double x = static_cast<const size_t*>(histoData->X)[pos]; + double y = 0.; + if (histoData->type == MetricType::Int) { + y = static_cast<const int*>(histoData->Y)[pos]; + } else if (histoData->type == MetricType::Uint64) { + y = static_cast<const uint64_t*>(histoData->Y)[pos]; + } else if (histoData->type == MetricType::Float) { + y = static_cast<const float*>(histoData->Y)[pos]; + } + auto point = ImPlotPoint{x, y}; + return point; + }; + static bool logScale = false; + ImGui::Checkbox("Log scale", &logScale); + + ImPlot::SetNextPlotLimitsX(minDomain, maxDomain, ImGuiCond_Once); + ImPlot::SetNextPlotTicksX(minDomain, maxDomain, 5); + auto axisPadding = 0.; + if (displayType == MetricsDisplayStyle::Lines) { + axisPadding = 0.2; + } + + for (size_t ai = 0; ai < 3; ++ai) { + ImPlot::SetNextPlotLimitsY(minValue[ai] - (maxValue[ai] - minValue[ai]) * axisPadding, + maxValue[ai] * (1. + axisPadding), ImGuiCond_Always, ai); + } + + switch (displayType) { + case MetricsDisplayStyle::Histos: + if (ImPlot::BeginPlot("##Some plot", "time", "value")) { + for (size_t pi = 0; pi < metricsToDisplay.size(); ++pi) { + ImGui::PushID(pi); + auto data = (const MultiplotData*)metricsToDisplay[pi]; + const char* label = ((MultiplotData*)metricsToDisplay[pi])->legend; + ImPlot::PlotBarsG(label, getterXY, metricsToDisplay[pi], data->size, 1, 0); + ImGui::PopID(); + } + ImPlot::EndPlot(); + } + + break; + case MetricsDisplayStyle::Lines: { + auto xAxisFlags = ImPlotAxisFlags_None; + auto yAxisFlags = ImPlotAxisFlags_LockMin; + //ImPlot::FitNextPlotAxes(true, true, true, true); + if (ImPlot::BeginPlot("##Some plot", "time", "value", {-1, -1}, axisFlags, xAxisFlags, yAxisFlags)) { + for (size_t pi = 0; pi < metricsToDisplay.size(); ++pi) { + ImGui::PushID(pi); + auto data = (const MultiplotData*)metricsToDisplay[pi]; + const char* label = data->legend; + ImPlot::SetPlotYAxis(data->axis); + ImPlot::PlotLineG(data->legend, getterXY, metricsToDisplay[pi], data->size, 0); + ImGui::PopID(); + } + ImPlot::EndPlot(); + } + } break; + case MetricsDisplayStyle::Stems: + if (ImPlot::BeginPlot("##Some plot", "time", "value")) { + for (size_t pi = 0; pi < userData.size(); ++pi) { + auto data = reinterpret_cast<const MultiplotData*>(metricsToDisplay[pi]); + // FIXME: display a message for other metrics + if (data->type == MetricType::Uint64) { + ImGui::PushID(pi); + ImPlot::PlotScatterG(((MultiplotData*)metricsToDisplay[pi])->legend, getterXY, metricsToDisplay[pi], data->size, 0); + ImGui::PopID(); + } + } + ImPlot::EndPlot(); + } + break; + default: + break; + } +} + +struct ColumnInfo { + MetricType type; + int index; +}; + +void metricsTableRow(std::vector<MetricIndex> metricIndex, + AllMetricsStore const& metricsStore, + int row) +{ + ImGui::TableNextColumn(); + ImGui::Text("%d", row); + + for (auto index : metricIndex) { + auto& metricsInfos = *metricsStore.metrics[index.storeIndex]; + auto& metricsInfo = metricsInfos[index.deviceIndex]; + auto& info = metricsInfos[index.deviceIndex].metrics[index.metricIndex]; + + ImGui::TableNextColumn(); + auto time = metricsInfo.timestamps[index.metricIndex][row]; + switch (info.type) { + case MetricType::Int: { + ImGui::Text("%i, %" PRIu64, metricsInfo.intMetrics[info.storeIdx][row], (uint64_t)time); + } break; + case MetricType::Uint64: { + ImGui::Text("%" PRIu64 ", %" PRIu64, metricsInfo.uint64Metrics[info.storeIdx][row], (uint64_t)time); + } break; + case MetricType::Float: { + ImGui::Text("%f, %" PRIu64, metricsInfo.floatMetrics[info.storeIdx][row], (uint64_t)time); + } break; + case MetricType::String: { + ImGui::Text("%s, %" PRIu64, metricsInfo.stringMetrics[info.storeIdx][row].data, (uint64_t)time); + } break; + default: + break; + } + } +} + +bool hasAll(const char* s, const char* q) +{ + /* base case: empty query */ + if (*q == 0) { + return true; + } + do { + s = strchr(s, (int)*q); + if (s == nullptr) { + return false; + } + s++; + q++; + } while ((int)*q != 0); + return true; +} + +void TextCenter(char const* text) +{ + float font_size = ImGui::GetFontSize() * strlen(text) / 2; + ImGui::Dummy(ImVec2( + ImGui::GetWindowSize().x / 2 - + font_size + (font_size / 2), + 120)); + + ImGui::TextUnformatted(text); +} + +void displayMetrics(gui::WorkspaceGUIState& state, + DriverInfo const& driverInfo, + std::vector<DeviceInfo> const& infos, + std::vector<DataProcessorInfo> const& metadata, + std::vector<DeviceControl>& controls, + AllMetricsStore const& metricsStore) +{ + if (state.bottomPaneVisible == false) { + return; + } + auto metricDisplayPos = 0; + static bool metricSelectorVisible = true; + static std::vector<MetricDisplayState> metricDisplayState; + static bool showInternalMetrics = false; + + // Calculate the full timestamp range for the selected metric + size_t minTime = -1; + size_t maxTime = 0; + constexpr size_t MAX_QUERY_SIZE = 256; + static char query[MAX_QUERY_SIZE]; + static char lastSelectedQuery[MAX_QUERY_SIZE]; + + size_t totalMetrics = 0; + for (auto& metricsInfos : metricsStore.metrics) { + for (auto& metricInfo : *metricsInfos) { + totalMetrics += metricInfo.metrics.size(); + } + } + + if (totalMetrics != metricDisplayState.size() || strcmp(lastSelectedQuery, query)) { + size_t gmi = 0; + std::vector<MetricDisplayState> newMetricDisplayStates; + newMetricDisplayStates.resize(totalMetrics); + for (size_t si = 0; si < TOTAL_TYPES_OF_METRICS; ++si) { + auto& metricsInfos = *metricsStore.metrics[si]; + auto& specs = *metricsStore.specs[si]; + for (size_t di = 0; di < metricsInfos.size(); ++di) { + auto& metricInfo = metricsInfos[di]; + auto& spec = specs[di]; + for (size_t li = 0; li != metricInfo.metricLabels.size(); ++li) { + char const* metricLabel = metricInfo.metricLabels[li].label; + std::string legend = fmt::format("{}/{}", spec.label, metricLabel); + auto hasher = std::hash<std::string>(); + size_t legendHash = hasher(legend); + auto old = std::find_if(metricDisplayState.begin(), metricDisplayState.end(), [&legend, &legendHash](MetricDisplayState const& state) { return state.legendHash == legendHash && state.legend == legend; }); + if (old != metricDisplayState.end()) { + newMetricDisplayStates[gmi].visible = old->visible; + newMetricDisplayStates[gmi].axis = old->axis; + } else { + newMetricDisplayStates[gmi].visible = false; + } + + newMetricDisplayStates[gmi].selected = hasAll(metricLabel, query); + newMetricDisplayStates[gmi].legend = legend; + newMetricDisplayStates[gmi].legendHash = legendHash; + gmi++; + } + } + } + metricDisplayState.swap(newMetricDisplayStates); + strcpy(lastSelectedQuery, query); + } + + static std::vector<MetricIndex> selectedMetricIndex; + + if (metricSelectorVisible) { + selectedMetricIndex.clear(); + size_t gmi = 0; + for (size_t si = 0; si < TOTAL_TYPES_OF_METRICS; ++si) { + auto& metricsInfos = *metricsStore.metrics[si]; + auto& devices = metricsStore.specs[si]; + + for (size_t di = 0; di < metricsInfos.size(); ++di) { + auto& metricInfo = metricsInfos[di]; + auto& deviceSpec = devices[di]; + for (size_t li = 0; li != metricInfo.metricLabels.size(); ++li) { + auto& label = metricInfo.metricLabels[li]; + auto& state = metricDisplayState[gmi]; + if (state.selected) { + selectedMetricIndex.emplace_back(MetricIndex{si, di, li, gmi}); + } + gmi++; + } + } + } + + metricDisplayPos = ImGui::GetIO().DisplaySize.x / 4; + ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - state.bottomPaneSize), 0); + ImGui::SetNextWindowSize(ImVec2(metricDisplayPos, state.bottomPaneSize), 0); + ImGui::Begin("Available metrics", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); + + ImGui::Text("Find metrics: "); + ImGui::SameLine(); + ImGui::InputText("##query-metrics", query, MAX_QUERY_SIZE); + static const char* possibleAxis[] = { + "Y", + "Y1", + "Y2", + }; + if (ImGui::BeginTable("##metrics-table", 3, ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, ImVec2{-1, -1})) { + ImGui::TableSetupColumn("##close button", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, 20); + ImGui::TableSetupColumn("##axis kind", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, 30); + ImGui::TableSetupScrollFreeze(1, 0); + ImGuiListClipper clipper; + clipper.Begin(selectedMetricIndex.size()); + while (clipper.Step()) { + for (size_t i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i) { + auto& index = selectedMetricIndex[i]; + auto& metricsInfos = *metricsStore.metrics[index.storeIndex]; + auto& nodes = *metricsStore.specs[index.storeIndex]; + auto& metricInfo = metricsInfos[index.deviceIndex]; + auto& node = nodes[index.deviceIndex]; + auto& label = metricInfo.metricLabels[index.metricIndex]; + auto& metric = metricInfo.metrics[index.metricIndex]; + auto& state = metricDisplayState[index.stateIndex]; + ImGui::PushID(index.stateIndex); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("##checkbox", &metricDisplayState[index.stateIndex].visible); + ImGui::TableNextColumn(); + if (metricDisplayState[index.stateIndex].visible) { + if (ImGui::BeginCombo("##Select style", possibleAxis[metricDisplayState[index.stateIndex].axis], ImGuiComboFlags_NoArrowButton)) { + for (int n = 0; n < IM_ARRAYSIZE(possibleAxis); n++) { + bool is_selected = (metricDisplayState[index.stateIndex].axis == n); + if (ImGui::Selectable(possibleAxis[n], is_selected)) { + metricDisplayState[index.stateIndex].axis = n; + } + if (is_selected) { + ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support) + } + } + ImGui::EndCombo(); + } + } + ImGui::TableNextColumn(); + ImGui::Text("%s/%s", node.label.c_str(), label.label); + ImGui::PopID(); + } + } + ImGui::EndTable(); + } + ImGui::End(); + } + ImGui::SetNextWindowPos(ImVec2(metricDisplayPos, ImGui::GetIO().DisplaySize.y - state.bottomPaneSize), 0); + ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x - metricDisplayPos, state.bottomPaneSize), 0); + + ImGui::Begin("Devices", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); + + if (!metricSelectorVisible) { + metricSelectorVisible = ImGui::Button(">> Show metric selector"); + } else { + metricSelectorVisible = !ImGui::Button("<< Hide metric selector"); + } + static char const* plotStyles[] = { + "lines", + "histograms", + "sparks", + "table", + "stems"}; + ImGui::SameLine(); + static enum MetricsDisplayStyle currentStyle = MetricsDisplayStyle::Lines; + static char const* currentStyleStr = plotStyles[0]; + ImGui::TextUnformatted("Metric display style:"); + ImGui::SameLine(); + ImGui::PushItemWidth(100); + if (ImGui::BeginCombo("##Select style", currentStyleStr)) { + for (int n = 0; n < IM_ARRAYSIZE(plotStyles); n++) { + bool is_selected = (currentStyleStr == plotStyles[n]); // You can store your selection however you want, outside or inside your objects + if (ImGui::Selectable(plotStyles[n], is_selected)) { + currentStyleStr = plotStyles[n]; + currentStyle = (MetricsDisplayStyle)n; + } + if (is_selected) { + ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support) + } + } + ImGui::EndCombo(); + } + ImGui::PopItemWidth(); + bool locked = false; + + size_t gmi = 0; + int visibleMetrics = 0; + static std::vector<int> visibleDevicesIndex; + static std::vector<MetricIndex> visibleMetricsIndex; + + visibleDevicesIndex.reserve(totalMetrics); + visibleDevicesIndex.clear(); + visibleMetricsIndex.clear(); + + for (size_t si = 0; si < TOTAL_TYPES_OF_METRICS; ++si) { + auto& metricsInfos = *metricsStore.metrics[si]; + for (size_t di = 0; di < metricsInfos.size(); ++di) { + auto& metricInfo = metricsInfos[di]; + bool deviceVisible = false; + for (size_t mi = 0; mi < metricInfo.metrics.size(); ++mi) { + auto& label = metricInfo.metricLabels[mi]; + auto& state = metricDisplayState[gmi]; + if (state.visible) { + deviceVisible = true; + visibleMetrics++; + auto& metric = metricInfo.metrics[mi]; + auto& timestamps = metricInfo.timestamps[mi]; + + for (size_t ti = 0; ti != metricInfo.timestamps.size(); ++ti) { + size_t minRangePos = (metric.pos + ti) % metricInfo.timestamps.size(); + size_t curMinTime = timestamps[minRangePos]; + if (curMinTime == 0) { + continue; + } + minTime = minTime < curMinTime ? minTime : curMinTime; + if (minTime != 0 && minTime != -1) { + break; + } + } + size_t maxRangePos = (size_t)(metric.pos) - 1 % metricInfo.timestamps.size(); + size_t curMaxTime = timestamps[maxRangePos]; + maxTime = std::max(maxTime, curMaxTime); + visibleMetricsIndex.push_back(MetricIndex{si, di, mi, gmi}); + } + gmi++; + } + if (deviceVisible) { + visibleDevicesIndex.push_back(di); + } + } + } + if (visibleMetricsIndex.empty()) { + TextCenter("Please enable some metric."); + ImGui::End(); + return; + }; + + switch (currentStyle) { + case MetricsDisplayStyle::Stems: + case MetricsDisplayStyle::Histos: + case MetricsDisplayStyle::Lines: { + displayDeviceMetrics("Metrics", + minTime, maxTime, 1024, + currentStyle, metricDisplayState, metricsStore); + } break; + case MetricsDisplayStyle::Sparks: { + displaySparks(state.startTime, visibleMetricsIndex, metricDisplayState, metricsStore); + } break; + case MetricsDisplayStyle::Table: { + static std::vector<float> visibleDevicesOffsets; + visibleDevicesOffsets.clear(); + visibleDevicesOffsets.resize(visibleDevicesIndex.size()); + + size_t lastDevice = -1; + int visibleDeviceCount = -1; + /// Calculate the size of all the metrics for a given device + for (auto index : visibleMetricsIndex) { + auto& metricsInfos = *metricsStore.metrics[index.storeIndex]; + if (lastDevice != index.deviceIndex) { + visibleDeviceCount++; + lastDevice = index.deviceIndex; + } + auto label = metricsInfos[index.deviceIndex].metricLabels[index.metricIndex].label; + visibleDevicesOffsets[visibleDeviceCount] += ImGui::CalcTextSize(label, nullptr, true).x; + } + // The Device name header. + if (ImGui::BeginTable("##metrics-table", visibleMetricsIndex.size() + 1, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX, ImVec2{-1, -1})) { + ImGui::TableSetupColumn("##close button", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, 20); + for (auto index : visibleMetricsIndex) { + ImGui::TableSetupColumn("##device-header", ImGuiTableColumnFlags_WidthFixed, 100); + } + ImGui::TableSetupScrollFreeze(1, 2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(""); + visibleDeviceCount = -1; + lastDevice = -1; + for (auto index : visibleMetricsIndex) { + ImGui::TableNextColumn(); + auto& metricsInfos = *metricsStore.metrics[index.storeIndex]; + auto& devices = *metricsStore.specs[index.storeIndex]; + auto& metric = metricsInfos[index.deviceIndex]; + auto label = metricsInfos[index.deviceIndex].metricLabels[index.metricIndex].label; + if (lastDevice == index.deviceIndex) { + continue; + } + visibleDeviceCount++; + lastDevice = index.deviceIndex; + auto& spec = devices[index.deviceIndex]; + + ImGui::TextUnformatted(spec.label.c_str()); + } + + // The metrics headers + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("#"); + lastDevice = -1; + for (auto index : visibleMetricsIndex) { + ImGui::TableNextColumn(); + auto& metricsInfos = *metricsStore.metrics[index.storeIndex]; + auto& metric = metricsInfos[index.deviceIndex]; + auto label = metricsInfos[index.deviceIndex].metricLabels[index.metricIndex].label; + ImGui::Text("%s (%" PRIu64 ")", label, (uint64_t)metric.metrics[index.metricIndex].filledMetrics); + } + + // Calculate which columns we want to see. + ImGuiListClipper clipper; + // For now + clipper.Begin(1024); + + while (clipper.Step()) { + for (size_t i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i) { + ImGui::TableNextRow(); + metricsTableRow(visibleMetricsIndex, metricsStore, i); + } + } + ImGui::EndTable(); + } + } break; + } + ImGui::End(); +} + +void pushWindowColorDueToStatus(const DeviceInfo& info) +{ + using LogLevel = LogParsingHelpers::LogLevel; + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.); + if (info.active == false) { + ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::DARK_RED); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::RED); + ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::RED); + return; + } + switch (info.maxLogLevel) { + case LogLevel::Error: + ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_RED); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::RED); + ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_RED); + break; + case LogLevel::Warning: + ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_YELLOW); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::YELLOW); + ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_YELLOW); + break; + case LogLevel::Info: + ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_GREEN); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::GREEN); + ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_GREEN); + break; + default: + ImGui::PushStyleColor(ImGuiCol_TitleBg, PaletteHelpers::SHADED_BLUE); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, PaletteHelpers::BLUE); + ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, PaletteHelpers::SHADED_BLUE); + break; + } +} + +void popWindowColorDueToStatus() +{ + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(1); +} + +/// Display information window about the driver +/// and its state. +void displayDriverInfo(DriverInfo const& driverInfo, DriverControl& driverControl) +{ + ImGui::Begin("Driver information"); + static int pid = getpid(); + + if (driverControl.state == DriverControlState::STEP) { + driverControl.state = DriverControlState::PAUSE; + } + auto state = reinterpret_cast<int*>(&driverControl.state); + ImGui::RadioButton("Play", state, static_cast<int>(DriverControlState::PLAY)); + ImGui::SameLine(); + ImGui::RadioButton("Pause", state, static_cast<int>(DriverControlState::PAUSE)); + ImGui::SameLine(); + ImGui::RadioButton("Step", state, static_cast<int>(DriverControlState::STEP)); + + auto& registry = driverInfo.configContext->options(); + ImGui::Columns(); + + ImGui::Text("PID: %d - Control port %d", pid, driverInfo.port); + ImGui::Text("Frame cost (latency): %.1f(%.1f)ms", driverInfo.frameCost, driverInfo.frameLatency); + ImGui::Text("Input parsing cost (latency): %.1f(%.1f)ms", driverInfo.inputProcessingCost, driverInfo.inputProcessingLatency); + ImGui::Text("State stack (depth %lu)", driverInfo.states.size()); + if (ImGui::Button("SIGCONT all children")) { + kill(0, SIGCONT); + } + ImGui::SameLine(); + if (ImGui::Button("Debug driver")) { + std::string pidStr = std::to_string(pid); + setenv("O2DEBUGGEDPID", pidStr.c_str(), 1); +#ifdef __APPLE__ + std::string defaultAppleDebugCommand = + "osascript -e 'tell application \"Terminal\"'" + " -e 'activate'" + " -e 'do script \"lldb -p \" & (system attribute \"O2DEBUGGEDPID\") & \"; exit\"'" + " -e 'end tell'"; + setenv("O2DPLDEBUG", defaultAppleDebugCommand.c_str(), 0); +#else + setenv("O2DPLDEBUG", "xterm -hold -e gdb attach $O2DEBUGGEDPID &", 0); +#endif + int retVal = system(getenv("O2DPLDEBUG")); + (void)retVal; + } + + ImGui::SameLine(); + if (ImGui::Button("Profile")) { + std::string pidStr = std::to_string(pid); + setenv("O2PROFILEDPID", pidStr.c_str(), 1); +#ifdef __APPLE__ + auto defaultAppleProfileCommand = fmt::format( + "osascript -e 'tell application \"Terminal\"'" + " -e 'activate'" + " -e 'do script \"xcrun xctrace record --output dpl-profile-{0}.trace" + " --time-limit 30s --template Time\\\\ Profiler --attach {0} " + " && open dpl-profile-{0}.trace && exit\"'" + " -e 'end tell'", + pid); + std::cout << defaultAppleProfileCommand << std::endl; + setenv("O2DPLPROFILE", defaultAppleProfileCommand.c_str(), 0); +#else + setenv("O2DPLPROFILE", "xterm -hold -e perf record -a -g -p $O2PROFILEDPID > perf-$O2PROFILEDPID.data &", 0); +#endif + int retVal = system(getenv("O2DPLPROFILE")); + (void)retVal; + } + + for (size_t i = 0; i < driverInfo.states.size(); ++i) { + ImGui::Text("#%lu: %s", i, DriverInfoHelper::stateToString(driverInfo.states[i])); + } + + ImGui::End(); +} + +// FIXME: return empty function in case we were not built +// with GLFW support. +/// +std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, + std::vector<DeviceSpec> const& devices, + std::vector<DataProcessorInfo> const& metadata, + std::vector<DeviceMetricsInfo> const& metricsInfos, + DriverInfo const& driverInfo, + std::vector<DeviceControl>& controls, + DriverControl& driverControl) +{ + static gui::WorkspaceGUIState globalGUIState; + gui::WorkspaceGUIState& guiState = globalGUIState; + guiState.selectedMetric = -1; + guiState.metricMaxRange = 0UL; + guiState.metricMinRange = -1; + // FIXME: this should probaly have a better mapping between our window state and + guiState.devices.resize(infos.size()); + for (size_t i = 0; i < guiState.devices.size(); ++i) { + gui::DeviceGUIState& state = guiState.devices[i]; + state.label = devices[i].id + "(" + std::to_string(infos[i].pid) + ")"; + } + guiState.bottomPaneSize = 340; + guiState.leftPaneSize = 200; + guiState.rightPaneSize = 300; + + // Show all the panes by default. + guiState.bottomPaneVisible = true; + guiState.leftPaneVisible = true; + guiState.rightPaneVisible = true; + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + guiState.startTime = now.tv_sec - ImGui::GetTime(); + std::vector<TopologyNodeInfo> deviceNodesInfos; + for (auto& device : devices) { + deviceNodesInfos.push_back(TopologyNodeInfo{device.id}); + } + std::vector<TopologyNodeInfo> driverNodesInfos; + driverNodesInfos.push_back(TopologyNodeInfo{"driver"}); + + return [&guiState, &infos, &devices, &metadata, &controls, &metricsInfos, &driverInfo, &driverControl, deviceNodesInfos, driverNodesInfos]() { + ImGuiStyle& style = ImGui::GetStyle(); + style.FrameRounding = 0.; + style.WindowRounding = 0.; + style.Colors[ImGuiCol_WindowBg] = ImVec4(0x1b / 255.f, 0x1b / 255.f, 0x1b / 255.f, 1.00f); + style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0x1b / 255.f, 0x1b / 255.f, 0x1b / 255.f, 1.00f); + + showTopologyNodeGraph(guiState, infos, devices, metadata, controls, metricsInfos); + + static AllMetricsStore metricsStore; + static std::vector<DeviceMetricsInfo> driverMetrics{driverInfo.metrics}; + driverMetrics.clear(); + + metricsStore.metrics[DEVICE_METRICS] = &metricsInfos; + metricsStore.metrics[DRIVER_METRICS] = &driverMetrics; + metricsStore.specs[DEVICE_METRICS] = &deviceNodesInfos; + metricsStore.specs[DRIVER_METRICS] = &driverNodesInfos; + displayMetrics(guiState, driverInfo, infos, metadata, controls, metricsStore); + displayDriverInfo(driverInfo, driverControl); + + int windowPosStepping = (ImGui::GetIO().DisplaySize.y - 500) / guiState.devices.size(); + + for (size_t i = 0; i < guiState.devices.size(); ++i) { + gui::DeviceGUIState& state = guiState.devices[i]; + assert(i < infos.size()); + assert(i < devices.size()); + const DeviceInfo& info = infos[i]; + const DeviceSpec& spec = devices[i]; + const DeviceMetricsInfo& metrics = metricsInfos[i]; + + assert(controls.size() == devices.size()); + DeviceControl& control = controls[i]; + + pushWindowColorDueToStatus(info); + if (control.logVisible) { + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x / 3 * 2, i * windowPosStepping), ImGuiCond_Once); + ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x / 3, ImGui::GetIO().DisplaySize.y - 300), + ImGuiCond_Once); + ImGui::Begin(state.label.c_str(), &control.logVisible); + + ImGui::InputText("Log filter", control.logFilter, sizeof(control.logFilter)); + ImGui::InputText("Log start trigger", control.logStartTrigger, sizeof(control.logStartTrigger)); + ImGui::InputText("Log stop trigger", control.logStopTrigger, sizeof(control.logStopTrigger)); + ImGui::Checkbox("Stop logging", &control.quiet); + ImGui::SameLine(); + ImGui::Combo("Log level", reinterpret_cast<int*>(&control.logLevel), LogParsingHelpers::LOG_LEVELS, + (int)LogParsingHelpers::LogLevel::Size, 5); + + ImGui::Separator(); + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -ImGui::GetTextLineHeightWithSpacing()), false, + ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove); + displayHistory(info, control); + ImGui::EndChild(); + ImGui::End(); + } + popWindowColorDueToStatus(); + } + }; +} + +void updateMousePos(float x, float y) +{ + ImGuiIO& io = ImGui::GetIO(); + io.MousePos = ImVec2(x, y); +} + +void updateMouseButton(bool clicked) +{ + ImGuiIO& io = ImGui::GetIO(); + io.MouseDown[0] = clicked; +} + +void updateMouseWheel(int direction) +{ + ImGuiIO& io = ImGui::GetIO(); + if (direction > 0) { + io.MouseWheel++; + } else { + io.MouseWheel--; + } +} + +void updateWindowSize(int x, int y) +{ + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2(x, y); +} + +void keyDown(char key) +{ + ImGuiIO& io = ImGui::GetIO(); + io.KeysDown[io.KeyMap[key]] = true; +} + +void keyUp(char key) +{ + ImGuiIO& io = ImGui::GetIO(); + io.KeysDown[io.KeyMap[key]] = false; +} + +void charIn(char key) +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharacter((unsigned short)key); +} + +} // namespace o2::framework::gui diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.h b/Framework/GUISupport/src/FrameworkGUIDebugger.h new file mode 100644 index 0000000000000..d7ca5707af5a1 --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_FRAMEWORKGUIDEBUGGER_H_ +#define O2_FRAMEWORK_FRAMEWORKGUIDEBUGGER_H_ + +#include "Framework/DataProcessorInfo.h" +#include "Framework/DeviceControl.h" +#include "Framework/DeviceInfo.h" +#include "Framework/DeviceMetricsInfo.h" +#include "Framework/DeviceSpec.h" + +#include <functional> +#include <vector> + +namespace o2::framework +{ + +class DriverInfo; +class DriverControl; + +namespace gui +{ +/// Helper to get the callback to draw the debug GUI +std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, + std::vector<DeviceSpec> const& devices, + std::vector<DataProcessorInfo> const& metadata, + std::vector<DeviceMetricsInfo> const& metricsInfos, + DriverInfo const& driverInfo, + std::vector<DeviceControl>& controls, + DriverControl& driverControl); + +void updateMousePos(float x, float y); +void updateMouseButton(bool clicked); +void updateMouseWheel(int direction); +void updateWindowSize(int x, int y); +void keyDown(char key); +void keyUp(char key); +void charIn(char key); + +} // namespace gui +} // namespace o2::framework +#endif // O2_FRAMEWORK_FRAMEWORKGUIDEBUGGER_H_ diff --git a/Framework/Core/src/FrameworkGUIDeviceInspector.cxx b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx similarity index 82% rename from Framework/Core/src/FrameworkGUIDeviceInspector.cxx rename to Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx index 8322ed1b87d6e..02f4a78e57234 100644 --- a/Framework/Core/src/FrameworkGUIDeviceInspector.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx @@ -1,15 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "FrameworkGUIDeviceInspector.h" -#include "DataProcessorInfo.h" +#include "Framework/DataProcessorInfo.h" #include "Framework/DeviceControl.h" #include "Framework/DeviceSpec.h" @@ -17,8 +18,10 @@ #include "Framework/DeviceMetricsInfo.h" #include "Framework/ChannelSpec.h" #include "Framework/Logger.h" +#include "Framework/DeviceController.h" #include "DebugGUI/imgui.h" +#include <cinttypes> #include <csignal> #include <cstdlib> #include <iostream> @@ -120,6 +123,21 @@ void optionsTable(const char* label, std::vector<ConfigParamSpec> const& options case VariantType::Int: ImGui::Text("%d (default)", option.defaultValue.get<int>()); break; + case VariantType::Int64: + ImGui::Text("%" PRId64 " (default)", option.defaultValue.get<int64_t>()); + break; + case VariantType::UInt8: + ImGui::Text("%d (default)", option.defaultValue.get<uint8_t>()); + break; + case VariantType::UInt16: + ImGui::Text("%d (default)", option.defaultValue.get<uint16_t>()); + break; + case VariantType::UInt32: + ImGui::Text("%d (default)", option.defaultValue.get<uint32_t>()); + break; + case VariantType::UInt64: + ImGui::Text("%" PRIu64 " (default)", option.defaultValue.get<uint64_t>()); + break; case VariantType::Float: ImGui::Text("%f (default)", option.defaultValue.get<float>()); break; @@ -128,6 +146,7 @@ void optionsTable(const char* label, std::vector<ConfigParamSpec> const& options break; case VariantType::Empty: ImGui::TextUnformatted(""); // no default value + break; default: ImGui::TextUnformatted("unknown"); } @@ -154,7 +173,11 @@ void servicesTable(const char* label, std::vector<ServiceSpec> const& services) ImGui::NextColumn(); } for (auto& service : services) { - ImGui::TextUnformatted(service.name.c_str()); + if (!service.name.empty()) { + ImGui::TextUnformatted(service.name.c_str()); + } else { + ImGui::TextUnformatted("unknown"); + } ImGui::NextColumn(); switch (service.kind) { case ServiceKind::Serial: @@ -200,7 +223,7 @@ void displayDeviceInspector(DeviceSpec const& spec, #ifdef __APPLE__ std::string defaultAppleDebugCommand = "osascript -e 'tell application \"Terminal\" to activate'" - " -e 'tell application \"Terminal\" to do script \"lldb -p \" & (system attribute \"O2DEBUGGEDPID\")'"; + " -e 'tell application \"Terminal\" to do script \"lldb -p \" & (system attribute \"O2DEBUGGEDPID\") & \"; exit\"'"; setenv("O2DPLDEBUG", defaultAppleDebugCommand.c_str(), 0); #else setenv("O2DPLDEBUG", "xterm -hold -e gdb attach $O2DEBUGGEDPID &", 0); @@ -214,12 +237,15 @@ void displayDeviceInspector(DeviceSpec const& spec, std::string pid = std::to_string(info.pid); setenv("O2PROFILEDPID", pid.c_str(), 1); #ifdef __APPLE__ - std::string defaultAppleProfileCommand = - "osascript -e 'tell application \"Terminal\" to activate'" - " -e 'tell application \"Terminal\" to do script \"instruments -D dpl-profile-" + - pid + - ".trace -l 30000 -t Time\\\\ Profiler -p " + - pid + " && open dpl-profile-" + pid + ".trace && exit\"'"; + auto defaultAppleProfileCommand = fmt::format( + "osascript -e 'tell application \"Terminal\"'" + " -e 'activate'" + " -e 'do script \"xcrun xctrace record --output dpl-profile-{0}.trace" + " --time-limit 30s --template Time\\\\ Profiler --attach {0} " + " && open dpl-profile-{0}.trace && exit\"'" + " -e 'end tell'", + pid); + setenv("O2DPLPROFILE", defaultAppleProfileCommand.c_str(), 0); #else setenv("O2DPLPROFILE", "xterm -hold -e perf record -a -g -p $O2PROFILEDPID > perf-$O2PROFILEDPID.data &", 0); @@ -229,8 +255,8 @@ void displayDeviceInspector(DeviceSpec const& spec, (void)retVal; } - ImGui::SameLine(); #if DPL_ENABLE_TRACING + ImGui::SameLine(); if (ImGui::Button("Tracy")) { std::string tracyPort = std::to_string(info.tracyPort); auto cmd = fmt::format("tracy-profiler -p {} -a 127.0.0.1 &", info.tracyPort); @@ -239,6 +265,11 @@ void displayDeviceInspector(DeviceSpec const& spec, (void)retVal; } #endif + if (control.controller) { + if (ImGui::Button("Offer SHM")) { + control.controller->write("/shm-offer 1000", strlen("/shm-offer 1000")); + } + } deviceInfoTable(info, metrics); for (auto& option : info.currentConfig) { diff --git a/Framework/GUISupport/src/FrameworkGUIDeviceInspector.h b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.h new file mode 100644 index 0000000000000..d9e9a5e23e797 --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// Helper to display information about a device + +namespace o2 +{ +namespace framework +{ + +struct DeviceSpec; +struct DeviceControl; +struct DeviceInfo; +struct DeviceMetricsInfo; +struct DataProcessorInfo; + +namespace gui +{ + +void displayDeviceInspector(DeviceSpec const& spec, DeviceInfo const& info, DeviceMetricsInfo const& metrics, DataProcessorInfo const& metadata, DeviceControl& control); + +} // namespace gui +} // namespace framework +} // namespace o2 diff --git a/Framework/Core/src/FrameworkGUIDevicesGraph.cxx b/Framework/GUISupport/src/FrameworkGUIDevicesGraph.cxx similarity index 78% rename from Framework/Core/src/FrameworkGUIDevicesGraph.cxx rename to Framework/GUISupport/src/FrameworkGUIDevicesGraph.cxx index 488a77ccc176d..81839aac9c436 100644 --- a/Framework/Core/src/FrameworkGUIDevicesGraph.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDevicesGraph.cxx @@ -1,34 +1,32 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/FrameworkGUIDevicesGraph.h" -#include "Framework/FrameworkGUIDataRelayerUsage.h" -#include "Framework/FrameworkGUIState.h" +#include "FrameworkGUIDevicesGraph.h" +#include "FrameworkGUIDataRelayerUsage.h" +#include "FrameworkGUIState.h" +#include "PaletteHelpers.h" #include "Framework/DeviceSpec.h" #include "Framework/DeviceInfo.h" #include "Framework/LogParsingHelpers.h" -#include "Framework/PaletteHelpers.h" #include "Framework/Logger.h" #include "FrameworkGUIDeviceInspector.h" #include "Framework/Logger.h" #include "../src/WorkflowHelpers.h" #include "DebugGUI/imgui.h" -#if __has_include("DebugGUI/icons_font_awesome.h") -#include "DebugGUI/icons_font_awesome.h" -#else -#define ICON_FA_EXCLAMATION_CIRCLE "(Errors!)" -#define ICON_FA_EXCLAMATION_TRIANGLE "(Warnings!)" -#endif +#include <DebugGUI/icons_font_awesome.h> #include <algorithm> #include <cmath> #include <vector> +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } @@ -43,47 +41,63 @@ struct NodeColor { using LogLevel = LogParsingHelpers::LogLevel; -NodeColor - decideColorForNode(const DeviceInfo& info) +NodeColor decideColorForNode(const DeviceInfo& info) { - NodeColor result; if (info.active == false) { - result.normal = PaletteHelpers::RED; - result.hovered = PaletteHelpers::SHADED_RED; - return result; + return NodeColor{ + .normal = PaletteHelpers::RED, + .hovered = PaletteHelpers::SHADED_RED}; } switch (info.streamingState) { case StreamingState::EndOfStreaming: - result.normal = PaletteHelpers::SHADED_YELLOW; - result.hovered = PaletteHelpers::YELLOW; - result.title = PaletteHelpers::YELLOW; - result.title_hovered = PaletteHelpers::DARK_YELLOW; - break; + return NodeColor{ + .normal = PaletteHelpers::SHADED_YELLOW, + .hovered = PaletteHelpers::YELLOW, + .title = PaletteHelpers::YELLOW, + .title_hovered = PaletteHelpers::DARK_YELLOW}; case StreamingState::Idle: - result.normal = PaletteHelpers::SHADED_GREEN; - result.hovered = PaletteHelpers::GREEN; - result.title = PaletteHelpers::GREEN; - result.title_hovered = PaletteHelpers::DARK_GREEN; - break; + return NodeColor{ + .normal = PaletteHelpers::SHADED_GREEN, + .hovered = PaletteHelpers::GREEN, + .title = PaletteHelpers::GREEN, + .title_hovered = PaletteHelpers::DARK_GREEN}; case StreamingState::Streaming: default: - result.normal = PaletteHelpers::GRAY; - result.hovered = PaletteHelpers::LIGHT_GRAY; - result.title = PaletteHelpers::GRAY; - result.title_hovered = PaletteHelpers::BLACK; - break; + return NodeColor{ + .normal = PaletteHelpers::GRAY, + .hovered = PaletteHelpers::LIGHT_GRAY, + .title = PaletteHelpers::GRAY, + .title_hovered = PaletteHelpers::BLACK}; } - return result; } +/// Color choices +const static ImColor INPUT_SLOT_COLOR = {150, 150, 150, 150}; +const static ImColor OUTPUT_SLOT_COLOR = {150, 150, 150, 150}; +const static ImVec4& ERROR_MESSAGE_COLOR = PaletteHelpers::RED; +const static ImVec4& WARNING_MESSAGE_COLOR = PaletteHelpers::YELLOW; +const static ImColor ARROW_COLOR = {200, 200, 100}; +const static ImU32 GRID_COLOR = ImColor(200, 200, 200, 40); +const static ImColor NODE_BORDER_COLOR = {100, 100, 100}; +const static ImColor LEGEND_COLOR = {100, 100, 100}; + +/// Layout choices +const static float GRID_SZ = 64.0f; +const static float ARROW_THICKNESS = 3.f; +const static float NODE_BORDER_THICKNESS = 4.f; +const static ImVec4 LEGEND_BACKGROUND_COLOR = {0.125, 0.180, 0.196, 1}; + +const static ImVec4 SLOT_EMPTY_COLOR = {0.275, 0.275, 0.275, 1.}; +const static ImVec4& SLOT_PENDING_COLOR = PaletteHelpers::RED; +const static ImVec4& SLOT_DISPATCHED_COLOR = PaletteHelpers::YELLOW; +const static ImVec4& SLOT_DONE_COLOR = PaletteHelpers::GREEN; + /// Displays a grid void displayGrid(bool show_grid, ImVec2 offset, ImDrawList* draw_list) { if (show_grid == false) { return; } - ImU32 GRID_COLOR = ImColor(200, 200, 200, 40); - float GRID_SZ = 64.0f; ImVec2 win_pos = ImGui::GetCursorScreenPos(); ImVec2 canvas_sz = ImGui::GetWindowSize(); for (float x = fmodf(offset.x, GRID_SZ); x < canvas_sz.x; x += GRID_SZ) { @@ -94,6 +108,40 @@ void displayGrid(bool show_grid, ImVec2 offset, ImDrawList* draw_list) } } +void displayLegend(bool show_legend, ImVec2 offset, ImDrawList* draw_list) +{ + if (show_legend == false) { + return; + } + struct LegendItem { + std::string label; + const ImVec4& color; + }; + static auto legend = { + LegendItem{" Slot empty", SLOT_EMPTY_COLOR}, + LegendItem{" Slot pending", SLOT_PENDING_COLOR}, + LegendItem{" Slot dispatched", SLOT_DISPATCHED_COLOR}, + LegendItem{" Slot done", SLOT_DONE_COLOR}, + }; + ImGui::PushStyleColor(ImGuiCol_WindowBg, LEGEND_BACKGROUND_COLOR); + ImGui::PushStyleColor(ImGuiCol_TitleBg, LEGEND_BACKGROUND_COLOR); + ImGui::PushStyleColor(ImGuiCol_ResizeGrip, 0); + + ImGui::Begin("Legend"); + ImGui::Dummy(ImVec2(0.0f, 10.0f)); + for (auto [label, color] : legend) { + ImVec2 vMin = ImGui::GetWindowPos() + ImGui::GetCursorPos() + ImVec2(9, 0); + ImVec2 vMax = vMin + ImGui::CalcTextSize(" "); + ImGui::PushStyleColor(ImGuiCol_ChildBg, color); + ImGui::GetWindowDrawList()->AddRectFilled(vMin, vMax, ImColor(color)); + ImGui::GetWindowDrawList()->AddRect(vMin, vMax, GRID_COLOR); + ImGui::Text("%s", label.data()); + ImGui::PopStyleColor(); + } + ImGui::End(); + ImGui::PopStyleColor(3); +} + #define MAX_GROUP_NAME_SIZE 128 // Private helper struct to keep track of node groups @@ -189,6 +237,7 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, static bool inited = false; static ImVec2 scrolling = ImVec2(0.0f, 0.0f); static bool show_grid = true; + static bool show_legend = true; static int node_selected = -1; auto prepareChannelView = [&specs, &metadata](ImVector<Node>& nodeList, ImVector<Group>& groupList) { @@ -232,7 +281,7 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, int groupId = 0; auto metadatum = std::find_if(metadata.begin(), metadata.end(), - [& name = spec.name](DataProcessorInfo const& info) { return info.name == name; }); + [&name = spec.name](DataProcessorInfo const& info) { return info.name == name; }); for (size_t gi = 0; gi < groupList.Size; ++gi) { if (metadatum == metadata.end()) { @@ -295,7 +344,7 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, auto& node = sortedNodes[si]; assert(node.index == si); int xpos = 40 + 240 * node.layer; - int ypos = 300 + (600 / (layerMax[node.layer] + 1)) * (layerEntries[node.layer] - layerMax[node.layer] / 2); + int ypos = 300 + (std::max(600, 60 * (int)layerMax[node.layer]) / (layerMax[node.layer] + 1)) * (layerEntries[node.layer] - layerMax[node.layer] / 2); positions.push_back(NodePos{ImVec2(xpos, ypos)}); layerEntries[node.layer] += 1; } @@ -310,6 +359,8 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, ImGui::BeginGroup(); ImGui::Checkbox("Show grid", &show_grid); ImGui::SameLine(); + ImGui::Checkbox("Show legend", &show_legend); + ImGui::SameLine(); if (ImGui::Button("Center")) { scrolling = ImVec2(0., 0.); } @@ -413,7 +464,7 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, NodeLink* link = &links[link_idx]; ImVec2 p1 = offset + NodePos::GetOutputSlotPos(nodes, positions, link->InputIdx, link->InputSlot); ImVec2 p2 = ImVec2(-3 * NODE_SLOT_RADIUS, 0) + offset + NodePos::GetInputSlotPos(nodes, positions, link->OutputIdx, link->OutputSlot); - draw_list->AddBezierCurve(p1, p1 + ImVec2(+50, 0), p2 + ImVec2(-50, 0), p2, ImColor(200, 200, 100), 3.0f); + draw_list->AddBezierCurve(p1, p1 + ImVec2(+50, 0), p2 + ImVec2(-50, 0), p2, ARROW_COLOR, ARROW_THICKNESS); } // Display nodes @@ -429,9 +480,16 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, NodePos* pos = &positions[node_idx]; const DeviceInfo& info = infos[node_idx]; - ImGui::PushID(node->ID); ImVec2 node_rect_min = offset + pos->pos; + // Do not even start if we are sure the box is not visible + if ((node_rect_min.x > ImGui::GetCursorScreenPos().x + ImGui::GetWindowSize().x + 50) || + (node_rect_min.y > ImGui::GetCursorScreenPos().y + ImGui::GetWindowSize().y + 50)) { + continue; + } + + ImGui::PushID(node->ID); + // Display node contents first draw_list->ChannelsSetCurrent(foregroundLayer); bool old_any_active = ImGui::IsAnyItemActive(); @@ -441,11 +499,11 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, switch (info.maxLogLevel) { case LogLevel::Error: ImGui::SameLine(); - ImGui::TextColored(ImVec4(1, 0, 0, 1), "%s", ICON_FA_EXCLAMATION_CIRCLE); + ImGui::TextColored(ERROR_MESSAGE_COLOR, "%s", ICON_FA_EXCLAMATION_CIRCLE); break; case LogLevel::Warning: ImGui::SameLine(); - ImGui::TextColored(ImVec4(0, 1, 1, 1), "%s", ICON_FA_EXCLAMATION_TRIANGLE); + ImGui::TextColored(WARNING_MESSAGE_COLOR, "%s", ICON_FA_EXCLAMATION_TRIANGLE); break; default: break; @@ -461,6 +519,15 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, ImVec2 node_rect_max = node_rect_min + node->Size; ImVec2 node_rect_title = node_rect_min + ImVec2(node->Size.x, 24); + if (node_rect_min.x > 20 + 2 * NODE_WINDOW_PADDING.x + state.leftPaneSize + graphSize.x) { + ImGui::PopID(); + continue; + } + if (node_rect_min.y > 20 + 2 * NODE_WINDOW_PADDING.y + toolbarSize.y + graphSize.y) { + ImGui::PopID(); + continue; + } + // Display node box draw_list->ChannelsSetCurrent(backgroundLayer); // Background ImGui::SetCursorScreenPos(node_rect_min); @@ -494,23 +561,23 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, draw_list->AddRectFilled(node_rect_min + ImVec2(3.f, 3.f), node_rect_max + ImVec2(3.f, 3.f), ImColor(0, 0, 0, 70), 4.0f); draw_list->AddRectFilled(node_rect_min, node_rect_max, node_bg_color, 4.0f); draw_list->AddRectFilled(node_rect_min, node_rect_title, node_title_color, 4.0f); - draw_list->AddRect(node_rect_min, node_rect_max, ImColor(100, 100, 100), 4.0f); + draw_list->AddRect(node_rect_min, node_rect_max, NODE_BORDER_COLOR, NODE_BORDER_THICKNESS); for (int slot_idx = 0; slot_idx < node->InputsCount; slot_idx++) { - auto color = ImColor(200, 200, 100); ImVec2 p1(-3 * NODE_SLOT_RADIUS, NODE_SLOT_RADIUS), p2(-3 * NODE_SLOT_RADIUS, -NODE_SLOT_RADIUS), p3(0, 0); auto pp1 = p1 + offset + NodePos::GetInputSlotPos(nodes, positions, node_idx, slot_idx); auto pp2 = p2 + offset + NodePos::GetInputSlotPos(nodes, positions, node_idx, slot_idx); auto pp3 = p3 + offset + NodePos::GetInputSlotPos(nodes, positions, node_idx, slot_idx); - draw_list->AddTriangleFilled(pp1, pp2, pp3, color); - draw_list->AddCircleFilled(offset + NodePos::GetInputSlotPos(nodes, positions, node_idx, slot_idx), NODE_SLOT_RADIUS, ImColor(150, 150, 150, 150)); + draw_list->AddTriangleFilled(pp1, pp2, pp3, ARROW_COLOR); + draw_list->AddCircleFilled(offset + NodePos::GetInputSlotPos(nodes, positions, node_idx, slot_idx), NODE_SLOT_RADIUS, INPUT_SLOT_COLOR); } for (int slot_idx = 0; slot_idx < node->OutputsCount; slot_idx++) { - draw_list->AddCircleFilled(offset + NodePos::GetOutputSlotPos(nodes, positions, node_idx, slot_idx), NODE_SLOT_RADIUS, ImColor(150, 150, 150, 150)); + draw_list->AddCircleFilled(offset + NodePos::GetOutputSlotPos(nodes, positions, node_idx, slot_idx), NODE_SLOT_RADIUS, OUTPUT_SLOT_COLOR); } ImGui::PopID(); } draw_list->ChannelsMerge(); + displayLegend(show_legend, offset, draw_list); // Open context menu if (!ImGui::IsAnyItemHovered() && ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) && ImGui::IsMouseClicked(1)) { @@ -565,3 +632,4 @@ void showTopologyNodeGraph(WorkspaceGUIState& state, } } // namespace o2::framework::gui +#pragma GGC diagnostic pop diff --git a/Framework/GUISupport/src/FrameworkGUIDevicesGraph.h b/Framework/GUISupport/src/FrameworkGUIDevicesGraph.h new file mode 100644 index 0000000000000..b9f3dcac9ecf0 --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIDevicesGraph.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ +#define O2_FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ + +#include "Framework/DataProcessorInfo.h" +#include "Framework/DeviceSpec.h" +#include "Framework/DeviceInfo.h" +#include "Framework/DeviceMetricsInfo.h" + +#include <vector> + +namespace o2::framework::gui +{ + +class WorkspaceGUIState; + +void showTopologyNodeGraph(WorkspaceGUIState& state, + std::vector<DeviceInfo> const& infos, + std::vector<DeviceSpec> const& specs, + std::vector<DataProcessorInfo> const& metadata, + std::vector<DeviceControl>& controls, + std::vector<DeviceMetricsInfo> const& metricsInfos); + +} // namespace o2::framework::gui + +#endif // O2_FRAMEWORK_FRAMEWORKGUIDEVICEGRAPH_H_ diff --git a/Framework/GUISupport/src/FrameworkGUIState.h b/Framework/GUISupport/src/FrameworkGUIState.h new file mode 100644 index 0000000000000..8a1cd8dd3bd1e --- /dev/null +++ b/Framework/GUISupport/src/FrameworkGUIState.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// State for the main GUI window + +#include <vector> +#include <string> + +namespace o2::framework::gui +{ + +/// State for the Device specific inspector +struct DeviceGUIState { + std::string label; +}; + +/// State for the workspace +struct WorkspaceGUIState { + int selectedMetric; + size_t metricMinRange; + size_t metricMaxRange; + std::vector<DeviceGUIState> devices; + float leftPaneSize; + float rightPaneSize; + float bottomPaneSize; + bool leftPaneVisible; + bool rightPaneVisible; + bool bottomPaneVisible; + double startTime; +}; + +} // namespace o2::framework::gui diff --git a/Framework/GUISupport/src/NoDebugGUI.h b/Framework/GUISupport/src/NoDebugGUI.h new file mode 100644 index 0000000000000..a4c770d456cec --- /dev/null +++ b/Framework/GUISupport/src/NoDebugGUI.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_NODEBUGGUI_H_ +#define O2_FRAMEWORK_NODEBUGGUI_H_ + +#include <functional> + +namespace o2::framework +{ + +// The DebugGUI has been moved to a separate package, this is a dummy header file +// included when the DebugGUI package is not found or disabled. +static inline void* initGUI(const char* name) +{ + return nullptr; +} + +static inline bool pollGUI(void* context, std::function<void(void)> guiCallback) +{ + // returns whether quit is requested, we return 'no' + return false; +} +static inline void disposeGUI() +{ +} + +static inline void getFrameJSON(void* data, std::ostream& json_data) override +{ +} + +static inline void getFrameRaw(void* data, void** raw_data, int* size) override +{ +} + +static inline bool pollGUIPreRender(void* context, float delta) override +{ + return true; +} + +static inline void* pollGUIRender(std::function<void(void)> guiCallback) override +{ + return nullptr; +} + +static inline void pollGUIPostRender(void* context, void* draw_data) override +{ +} + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_NODEBUGGUI_H_ diff --git a/Framework/GUISupport/src/PaletteHelpers.cxx b/Framework/GUISupport/src/PaletteHelpers.cxx new file mode 100644 index 0000000000000..cae43354a38c5 --- /dev/null +++ b/Framework/GUISupport/src/PaletteHelpers.cxx @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "PaletteHelpers.h" + +namespace o2 +{ +namespace framework +{ + +const ImVec4 PaletteHelpers::RED = ImVec4(0.945, 0.094, 0.298, 1); +const ImVec4 PaletteHelpers::GREEN = ImVec4(0x7e / 255., 0xc4 / 255., 0x52 / 255., 1); +const ImVec4 PaletteHelpers::BLUE = ImVec4(0x3d / 255., 0xb7 / 255., 0xe0 / 255., 1); +const ImVec4 PaletteHelpers::YELLOW = ImVec4(0.949, 0.769, 0.239, 1); +const ImVec4 PaletteHelpers::SHADED_RED = ImVec4(0xd5 / 255., 0x72 / 255., 0x73 / 255., 1); +const ImVec4 PaletteHelpers::SHADED_GREEN = ImVec4(0x98 / 255., 0xba / 255., 0x96 / 255., 1); +const ImVec4 PaletteHelpers::SHADED_BLUE = ImVec4(0x7a / 255., 0xab / 255., 0xea / 255., 1); +const ImVec4 PaletteHelpers::SHADED_YELLOW = ImVec4(0xeb / 255., 0xb9 / 255., 0x7a / 255., 1); +const ImVec4 PaletteHelpers::DARK_RED = ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); +const ImVec4 PaletteHelpers::DARK_GREEN = ImVec4(153. / 255, 61. / 255, 61. / 255, 255. / 255); +const ImVec4 PaletteHelpers::DARK_YELLOW = ImVec4(0xf1 / 255., 0x9b / 255., 0x2c / 255., 255. / 255); +const ImVec4 PaletteHelpers::WHITE = ImVec4(0xce / 255., 0xbe / 255., 0x91 / 255., 1); +const ImVec4 PaletteHelpers::BLACK = ImVec4(0x28 / 255., 0x28 / 255., 0x28 / 255., 1); +const ImVec4 PaletteHelpers::GRAY = ImVec4(60 / 255., 60 / 255., 60 / 255., 1); +const ImVec4 PaletteHelpers::LIGHT_GRAY = ImVec4(75 / 255., 75 / 255., 75 / 255., 1); + +} // namespace framework +} // namespace o2 diff --git a/Framework/GUISupport/src/PaletteHelpers.h b/Framework/GUISupport/src/PaletteHelpers.h new file mode 100644 index 0000000000000..760dd33ee9e2d --- /dev/null +++ b/Framework/GUISupport/src/PaletteHelpers.h @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_PALETTE_HELPER_H +#define FRAMEWORK_PALETTE_HELPER_H + +#include "DebugGUI/imgui.h" + +namespace o2 +{ +namespace framework +{ + +/// An helper class for colors and palettes +struct PaletteHelpers { + static const ImVec4 RED; + static const ImVec4 GREEN; + static const ImVec4 BLUE; + static const ImVec4 YELLOW; + static const ImVec4 SHADED_RED; + static const ImVec4 SHADED_GREEN; + static const ImVec4 SHADED_BLUE; + static const ImVec4 SHADED_YELLOW; + static const ImVec4 DARK_RED; + static const ImVec4 DARK_GREEN; + static const ImVec4 DARK_YELLOW; + static const ImVec4 WHITE; + static const ImVec4 BLACK; + static const ImVec4 GRAY; + static const ImVec4 LIGHT_GRAY; +}; + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Framework/GUISupport/src/Plugin.cxx b/Framework/GUISupport/src/Plugin.cxx new file mode 100644 index 0000000000000..4fe8e1068e77b --- /dev/null +++ b/Framework/GUISupport/src/Plugin.cxx @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#if __has_include(<DebugGUI/DebugGUI.h>) +#include <DebugGUI/DebugGUI.h> +#else +#pragma message "Building DPL without Debug GUI" +#include "NoDebugGUI.h" +#endif + +#include "Framework/Plugins.h" +#include "Framework/DebugGUI.h" +#include "FrameworkGUIDebugger.h" + +using namespace o2::framework; + +struct ImGUIDebugGUI : o2::framework::DebugGUI { + std::function<void(void)> getGUIDebugger(std::vector<DeviceInfo> const& infos, + std::vector<DeviceSpec> const& devices, + std::vector<DataProcessorInfo> const& metadata, + std::vector<DeviceMetricsInfo> const& metricsInfos, + DriverInfo const& driverInfo, + std::vector<DeviceControl>& controls, + DriverControl& driverControl) override + { + return o2::framework::gui::getGUIDebugger(infos, devices, metadata, metricsInfos, driverInfo, controls, driverControl); + } + + void updateMousePos(float x, float y) override + { + o2::framework::gui::updateMousePos(x, y); + } + void updateMouseButton(bool clicked) override + { + o2::framework::gui::updateMouseButton(clicked); + } + void updateMouseWheel(int direction) override + { + o2::framework::gui::updateMouseWheel(direction); + } + void updateWindowSize(int x, int y) override + { + o2::framework::gui::updateWindowSize(x, y); + } + void keyDown(char key) override + { + o2::framework::gui::keyDown(key); + } + void keyUp(char key) override + { + o2::framework::gui::keyUp(key); + } + void charIn(char key) override + { + o2::framework::gui::charIn(key); + } + + void* initGUI(char const* windowTitle) override + { + return o2::framework::initGUI(windowTitle); + } + bool pollGUI(void* context, std::function<void(void)> guiCallback) override + { + return o2::framework::pollGUI(context, guiCallback); + } + void disposeGUI() override + { + o2::framework::disposeGUI(); + } + void getFrameJSON(void* data, std::ostream& json_data) override + { + o2::framework::getFrameJSON(data, json_data); + } + void getFrameRaw(void* data, void** raw_data, int* size) override + { + o2::framework::getFrameRaw(data, raw_data, size); + } + bool pollGUIPreRender(void* context, float delta) override + { + return o2::framework::pollGUIPreRender(context, delta); + } + void* pollGUIRender(std::function<void(void)> guiCallback) override + { + return o2::framework::pollGUIRender(guiCallback); + } + void pollGUIPostRender(void* context, void* draw_data) override + { + o2::framework::pollGUIPostRender(context, draw_data); + } +}; + +DEFINE_DPL_PLUGINS_BEGIN +DEFINE_DPL_PLUGIN_INSTANCE(ImGUIDebugGUI, DebugGUIImpl); +DEFINE_DPL_PLUGINS_END diff --git a/Framework/Core/test/test_CustomGUIGL.cxx b/Framework/GUISupport/test/test_CustomGUIGL.cxx similarity index 84% rename from Framework/Core/test/test_CustomGUIGL.cxx rename to Framework/GUISupport/test/test_CustomGUIGL.cxx index 0de1fa1ab021e..caa0af1729739 100644 --- a/Framework/Core/test/test_CustomGUIGL.cxx +++ b/Framework/GUISupport/test/test_CustomGUIGL.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_CustomGUISokol.cxx b/Framework/GUISupport/test/test_CustomGUISokol.cxx similarity index 85% rename from Framework/Core/test/test_CustomGUISokol.cxx rename to Framework/GUISupport/test/test_CustomGUISokol.cxx index f21565ac735b7..7b9a9cc0f3828 100644 --- a/Framework/Core/test/test_CustomGUISokol.cxx +++ b/Framework/GUISupport/test/test_CustomGUISokol.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Core/test/test_SimpleTracksED.cxx b/Framework/GUISupport/test/test_SimpleTracksED.cxx similarity index 85% rename from Framework/Core/test/test_SimpleTracksED.cxx rename to Framework/GUISupport/test/test_SimpleTracksED.cxx index 35d113a0e85a2..2ce0fafbf5812 100644 --- a/Framework/Core/test/test_SimpleTracksED.cxx +++ b/Framework/GUISupport/test/test_SimpleTracksED.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Logger/CMakeLists.txt b/Framework/Logger/CMakeLists.txt index 1a778da9745f8..06d6a1bd21649 100644 --- a/Framework/Logger/CMakeLists.txt +++ b/Framework/Logger/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_header_only_library(FrameworkLogger INTERFACE_LINK_LIBRARIES fmt::fmt FairLogger::FairLogger) diff --git a/Framework/Logger/include/Framework/Logger.h b/Framework/Logger/include/Framework/Logger.h index cf1c7511c850d..5b3cd832d60a1 100644 --- a/Framework/Logger/include/Framework/Logger.h +++ b/Framework/Logger/include/Framework/Logger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Logger/test/unittest_Logger.cxx b/Framework/Logger/test/unittest_Logger.cxx index e04fc67ca5669..c0424edc07a64 100644 --- a/Framework/Logger/test/unittest_Logger.cxx +++ b/Framework/Logger/test/unittest_Logger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/CMakeLists.txt b/Framework/TestWorkflows/CMakeLists.txt index 7ae2e382ce8ec..7ad0b3e349cc3 100644 --- a/Framework/TestWorkflows/CMakeLists.txt +++ b/Framework/TestWorkflows/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # FIXME Is this one supposed to be a header only library (in which case the .h # to be installed should be in include/TestWorkflows) or not a library at all ? @@ -43,10 +44,6 @@ o2_add_dpl_workflow(sync-reconstruction-dummy SOURCES src/o2SyncReconstructionDummy.cxx COMPONENT_NAME TestWorkflows) -o2_add_dpl_workflow(aod-dummy-workflow - SOURCES src/o2AODDummy.cxx - COMPONENT_NAME TestWorkflows) - o2_add_dpl_workflow(d0-analysis SOURCES src/o2D0Analysis.cxx COMPONENT_NAME TestWorkflows) @@ -96,6 +93,12 @@ o2_add_dpl_workflow(tof-dummy-ccdb PUBLIC_LINK_LIBRARIES O2::TOFReconstruction COMPONENT_NAME TestWorkflows) +# Detector specific dummy workflows +o2_add_dpl_workflow(test-ccdb-fetcher + SOURCES src/test_CCDBFetcher.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF O2::Framework + COMPONENT_NAME TestWorkflows) + if(BUILD_SIMULATION) o2_add_executable( ITSClusterizers diff --git a/Framework/TestWorkflows/README b/Framework/TestWorkflows/README index 6c55ce5170819..e5d5cd1127e0d 100644 --- a/Framework/TestWorkflows/README +++ b/Framework/TestWorkflows/README @@ -34,4 +34,4 @@ follows: --readout-proxy '--channel-config "name=readout-proxy,type=pair,method=connect,transport=shmem,address=ipc:///tmp/readout-pipe-0,rateLogging=1"' -These must match appropriately the configuration of `readout.exe`. +These must match appropriately the configuration of `o2-readout-exe`. diff --git a/Framework/TestWorkflows/src/dummy.cxx b/Framework/TestWorkflows/src/dummy.cxx index ab2179b8eb11c..faff430964e73 100644 --- a/Framework/TestWorkflows/src/dummy.cxx +++ b/Framework/TestWorkflows/src/dummy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/flpQualification.cxx b/Framework/TestWorkflows/src/flpQualification.cxx index 22d6d32aab9b5..d0223bf05233f 100644 --- a/Framework/TestWorkflows/src/flpQualification.cxx +++ b/Framework/TestWorkflows/src/flpQualification.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,7 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) #include "Framework/ReadoutAdapter.h" #include "Framework/Logger.h" +#include "Headers/DataHeaderHelpers.h" #include <vector> @@ -65,9 +67,7 @@ DataProcessorSpec templateProcessor(std::string const& inputType) size_t index = parallelInfo.index1D(); const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(values); if (dh) { - LOG(INFO) << "some-processor" << index << ": " - << dh->dataOrigin.as<std::string>() << "/" << dh->dataDescription.as<std::string>() << "/" - << dh->subSpecification << " payload size " << dh->payloadSize; + LOGP(INFO, "some-processor {}: {}/{}/{} payload size {}", index, dh->dataOrigin, dh->dataDescription, dh->subSpecification, dh->payloadSize); } auto aData = outputs.make<int>(Output{"TST", "P", static_cast<o2::header::DataHeader::SubSpecificationType>(index)}, 1); diff --git a/Framework/TestWorkflows/src/o2AODDummy.cxx b/Framework/TestWorkflows/src/o2AODDummy.cxx deleted file mode 100644 index 4802fb7bc10b2..0000000000000 --- a/Framework/TestWorkflows/src/o2AODDummy.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/TableBuilder.h" -#include "Framework/runDataProcessing.h" - -#include <ROOT/RDataFrame.hxx> -#include <ROOT/RArrowDS.hxx> - -using namespace o2::framework; - -// A dummy workflow which creates a few of the tables proposed by Ruben, -// using ARROW -WorkflowSpec defineDataProcessing(ConfigContext const& specs) -{ - WorkflowSpec workflow{ - /// Minimal analysis example - DataProcessorSpec{ - "dummy-analysis", - { - // Dangling inputs of type AOD will be automatically picked up - // by DPL and an extra reader device will be instanciated to - // read them. - InputSpec{"TrackPar", "AOD", "TRACKPAR"}, - InputSpec{"TrackParCov", "AOD", "TRACKPARCOV"}, - // NOTE: Not needed right now. Uncomment if you want to use them - // InputSpec{ "TrackExtra", "AOD", "TRACKEXTRA" }, - // InputSpec{ "Calo", "AOD", "CALO" }, - // InputSpec{ "Muon", "AOD", "MUON" }, - // InputSpec{ "VZero", "AOD", "VZERO" }, - }, - {}, - AlgorithmSpec{ - [](InitContext& setup) { - return [](ProcessingContext& ctx) { - auto s = ctx.inputs().get<TableConsumer>("TrackPar"); - /// From the handle, we construct the actual arrow table - /// which is then used as a source for the RDataFrame. - /// This is probably easy to change to a: - /// - /// auto rdf = ctx.inputs().get<RDataSource>("xz"); - auto table = s->asArrowTable(); - if (table->num_rows() == 0) { - LOG(ERROR) << "Arrow table is TRACKPAR is empty" << table->num_rows(); - } - if (table->num_columns() != 8) { - LOG(ERROR) << "Wrong number of columns for the arrow table" << table->num_columns(); - } - auto source = std::make_unique<ROOT::RDF::RArrowDS>(s->asArrowTable(), std::vector<std::string>{}); - - auto s2 = ctx.inputs().get<TableConsumer>("TrackParCov"); - auto table2 = s->asArrowTable(); - auto source2 = std::make_unique<ROOT::RDF::RArrowDS>(s->asArrowTable(), std::vector<std::string>{}); - ROOT::RDataFrame rdf2(std::move(source2)); - }; - }}}}; - return workflow; -} diff --git a/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx b/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx index 9cd1e41f2b0d8..851928d02056f 100644 --- a/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx +++ b/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,8 +51,8 @@ struct ATask { int mSomeState; }; -WorkflowSpec defineDataProcessing(ConfigContext const&) +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask<ATask>("mySimpleTrackAnalysis", 0)}; + adaptAnalysisTask<ATask>(cfgc, TaskName{"mySimpleTrackAnalysis"}, 0)}; } diff --git a/Framework/TestWorkflows/src/o2D0Analysis.cxx b/Framework/TestWorkflows/src/o2D0Analysis.cxx index 728f3ca50a35a..3c3f13be34d87 100644 --- a/Framework/TestWorkflows/src/o2D0Analysis.cxx +++ b/Framework/TestWorkflows/src/o2D0Analysis.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2DataQueryWorkflow.cxx b/Framework/TestWorkflows/src/o2DataQueryWorkflow.cxx index 8f944534e2379..fcb29568f3924 100644 --- a/Framework/TestWorkflows/src/o2DataQueryWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2DataQueryWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2DiamondWorkflow.cxx b/Framework/TestWorkflows/src/o2DiamondWorkflow.cxx index eb1099cdbb7a9..3e19b806bb744 100644 --- a/Framework/TestWorkflows/src/o2DiamondWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2DiamondWorkflow.cxx @@ -1,15 +1,22 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/ConfigParamSpec.h" +#include "Framework/DataTakingContext.h" #include "Framework/CompletionPolicyHelpers.h" #include "Framework/DeviceSpec.h" +#include "Framework/RawDeviceService.h" +#include "Framework/ControlService.h" +#include "Framework/Configurable.h" +#include "Framework/RunningWorkflowInfo.h" +#include <FairMQDevice.h> #include <InfoLogger/InfoLogger.hxx> #include <chrono> @@ -19,30 +26,23 @@ using namespace o2::framework; using namespace AliceO2::InfoLogger; -void customize(std::vector<ConfigParamSpec>& options) -{ - options.push_back(ConfigParamSpec{"anInt", VariantType::Int, 1, {"an int option"}}); - options.push_back(ConfigParamSpec{"aFloat", VariantType::Float, 2.0f, {"a float option"}}); - options.push_back(ConfigParamSpec{"aDouble", VariantType::Double, 3., {"a double option"}}); - options.push_back(ConfigParamSpec{"aString", VariantType::String, "foo", {"a string option"}}); - options.push_back(ConfigParamSpec{"aBool", VariantType::Bool, true, {"a boolean option"}}); -} - -// This completion policy will only be applied to the device called `D` and -// will process an InputRecord which had any of its constituent updated. -void customize(std::vector<CompletionPolicy>& policies) -{ - policies.push_back(CompletionPolicyHelpers::defineByName("D", CompletionPolicy::CompletionOp::Process)); -} +struct WorkflowOptions { + Configurable<int> anInt{"anInt", 1, ""}; + Configurable<float> aFloat{"aFloat", 2.0f, {"a float option"}}; + Configurable<double> aDouble{"aDouble", 3., {"a double option"}}; + Configurable<std::string> aString{"aString", "foobar", {"a string option"}}; + Configurable<bool> aBool{"aBool", true, {"a boolean option"}}; +}; #include "Framework/runDataProcessing.h" AlgorithmSpec simplePipe(std::string const& what, int minDelay) { - return AlgorithmSpec{adaptStateful([what, minDelay]() { + return AlgorithmSpec{adaptStateful([what, minDelay](RunningWorkflowInfo const& runningWorkflow) { srand(getpid()); - return adaptStateless([what, minDelay](DataAllocator& outputs) { - std::this_thread::sleep_for(std::chrono::seconds((rand() % 5) + minDelay)); + LOG(INFO) << "There are " << runningWorkflow.devices.size() << " devices in the workflow"; + return adaptStateless([what, minDelay](DataAllocator& outputs, RawDeviceService& device) { + device.device()->WaitFor(std::chrono::milliseconds(minDelay)); auto& bData = outputs.make<int>(OutputRef{what}, 1); }); })}; @@ -57,8 +57,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& specs) {OutputSpec{{"a1"}, "TST", "A1"}, OutputSpec{{"a2"}, "TST", "A2"}}, AlgorithmSpec{adaptStateless( - [](DataAllocator& outputs, InfoLogger& logger) { - std::this_thread::sleep_for(std::chrono::seconds(rand() % 2)); + [](DataAllocator& outputs, InfoLogger& logger, RawDeviceService& device, DataTakingContext& context) { + device.device()->WaitFor(std::chrono::seconds(rand() % 2)); auto& aData = outputs.make<int>(OutputRef{"a1"}, 1); auto& bData = outputs.make<int>(OutputRef{"a2"}, 1); logger.log("This goes to infologger"); @@ -67,16 +67,21 @@ WorkflowSpec defineDataProcessing(ConfigContext const& specs) {"B", {InputSpec{"x", "TST", "A1", Lifetime::Timeframe, {ConfigParamSpec{"somestring", VariantType::String, "", {"Some input param"}}}}}, {OutputSpec{{"b1"}, "TST", "B1"}}, - simplePipe("b1", 0)}, + simplePipe("b1", 5000)}, {"C", Inputs{InputSpec{"x", "TST", "A2"}}, Outputs{OutputSpec{{"c1"}, "TST", "C1"}}, - simplePipe("c1", 5)}, + simplePipe("c1", 5000)}, {"D", Inputs{ + InputSpec{"a", "TST", "A1"}, InputSpec{"b", "TST", "B1"}, InputSpec{"c", "TST", "C1"}, }, Outputs{}, - AlgorithmSpec{adaptStateless([]() {})}}}; + AlgorithmSpec{adaptStateless([](InputRecord& inputs) { + auto ref = inputs.get("b"); + auto header = o2::header::get<const DataProcessingHeader*>(ref.header); + LOG(INFO) << header->startTime; + })}}}; } diff --git a/Framework/TestWorkflows/src/o2DummyWorkflow.cxx b/Framework/TestWorkflows/src/o2DummyWorkflow.cxx index ae4c86ade35f2..3dfcd95239e7c 100644 --- a/Framework/TestWorkflows/src/o2DummyWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2DummyWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -78,7 +79,7 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) {OutputSpec{{"summary"}, "TPC", "SUMMARY"}}, AlgorithmSpec{[](ProcessingContext& ctx) { auto& tpcSummary = ctx.outputs().make<Summary>(OutputRef{"summary"}, 1); - tpcSummary.at(0).inputCount = ctx.inputs().size(); + tpcSummary[0].inputCount = ctx.inputs().size(); }}, {ConfigParamSpec{"some-cut", VariantType::Float, 1.0f, {"some cut"}}}, }; @@ -91,7 +92,7 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) }, AlgorithmSpec{[](ProcessingContext& ctx) { auto& itsSummary = ctx.outputs().make<Summary>(OutputRef{"summary"}, 1); - itsSummary.at(0).inputCount = ctx.inputs().size(); + itsSummary[0].inputCount = ctx.inputs().size(); }}, {ConfigParamSpec{"some-cut", VariantType::Float, 1.0f, {"some cut"}}}, }; @@ -105,9 +106,9 @@ std::vector<DataProcessorSpec> defineDataProcessing(ConfigContext const&) AlgorithmSpec{ [](ProcessingContext& ctx) { // We verify we got inputs in the correct order - auto h0 = o2::header::get<DataHeader*>(ctx.inputs().get("clusters").header); - auto h1 = o2::header::get<DataHeader*>(ctx.inputs().get("summary").header); - auto h2 = o2::header::get<DataHeader*>(ctx.inputs().get("other_summary").header); + auto h0 = DataRefUtils::getHeader<DataHeader*>(ctx.inputs().get("clusters")); + auto h1 = DataRefUtils::getHeader<DataHeader*>(ctx.inputs().get("summary")); + auto h2 = DataRefUtils::getHeader<DataHeader*>(ctx.inputs().get("other_summary")); // This should always be the case, since the // test for an actual DataHeader should happen in the device itself. assert(h0 && h1 && h2); diff --git a/Framework/TestWorkflows/src/o2OutputWildcardWorkflow.cxx b/Framework/TestWorkflows/src/o2OutputWildcardWorkflow.cxx index 61543ea1b905a..42862a4d98dfd 100644 --- a/Framework/TestWorkflows/src/o2OutputWildcardWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2OutputWildcardWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx b/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx index df31abe2c0ee8..841f4a8f2b9bd 100644 --- a/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2SimpleSink.cxx b/Framework/TestWorkflows/src/o2SimpleSink.cxx index 4bb38666fa200..250e84582e52d 100644 --- a/Framework/TestWorkflows/src/o2SimpleSink.cxx +++ b/Framework/TestWorkflows/src/o2SimpleSink.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,10 +11,12 @@ #include "Framework/ConfigParamSpec.h" #include "Framework/CompletionPolicyHelpers.h" #include "Framework/DeviceSpec.h" +#include "Framework/RawDeviceService.h" #include <chrono> #include <thread> #include <vector> +#include <FairMQDevice.h> #include "Framework/runDataProcessing.h" using namespace o2::framework; @@ -22,8 +25,8 @@ AlgorithmSpec simplePipe(std::string const& what, int minDelay) { return AlgorithmSpec{adaptStateful([what, minDelay]() { srand(getpid()); - return adaptStateless([what, minDelay](DataAllocator& outputs) { - std::this_thread::sleep_for(std::chrono::seconds((rand() % 5) + minDelay)); + return adaptStateless([what, minDelay](DataAllocator& outputs, RawDeviceService& device) { + device.device()->WaitFor(std::chrono::seconds(minDelay)); auto& bData = outputs.make<int>(OutputRef{what}, 1); }); })}; diff --git a/Framework/TestWorkflows/src/o2SimpleSource.cxx b/Framework/TestWorkflows/src/o2SimpleSource.cxx index 91b03e4f75e38..b7bfcf65d844b 100644 --- a/Framework/TestWorkflows/src/o2SimpleSource.cxx +++ b/Framework/TestWorkflows/src/o2SimpleSource.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx index d42924ae64095..ff4ace962b935 100644 --- a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx +++ b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2SyncReconstructionDummy.cxx b/Framework/TestWorkflows/src/o2SyncReconstructionDummy.cxx index 10bde92cce22d..a2b9070f9e218 100644 --- a/Framework/TestWorkflows/src/o2SyncReconstructionDummy.cxx +++ b/Framework/TestWorkflows/src/o2SyncReconstructionDummy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2_sim_its_ALP3.cxx b/Framework/TestWorkflows/src/o2_sim_its_ALP3.cxx index dc83acd901f8c..70c67dce74355 100644 --- a/Framework/TestWorkflows/src/o2_sim_its_ALP3.cxx +++ b/Framework/TestWorkflows/src/o2_sim_its_ALP3.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,8 +29,6 @@ using namespace o2::framework; -using DataHeader = o2::header::DataHeader; - double radii2Turbo(double rMin, double rMid, double rMax, double sensW) { // compute turbo angle from radii and sensor width diff --git a/Framework/TestWorkflows/src/o2_sim_its_ALP3.h b/Framework/TestWorkflows/src/o2_sim_its_ALP3.h index bd3324115be53..f9c465fcf5717 100644 --- a/Framework/TestWorkflows/src/o2_sim_its_ALP3.h +++ b/Framework/TestWorkflows/src/o2_sim_its_ALP3.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/o2_sim_tpc.cxx b/Framework/TestWorkflows/src/o2_sim_tpc.cxx index 95018af91437a..f9265615a6c31 100644 --- a/Framework/TestWorkflows/src/o2_sim_tpc.cxx +++ b/Framework/TestWorkflows/src/o2_sim_tpc.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,8 +34,6 @@ using namespace o2::framework; -using DataHeader = o2::header::DataHeader; - #define BOX_GENERATOR 1 namespace o2 diff --git a/Framework/TestWorkflows/src/o2_sim_tpc.h b/Framework/TestWorkflows/src/o2_sim_tpc.h index 3416672994536..e567fe89e0b38 100644 --- a/Framework/TestWorkflows/src/o2_sim_tpc.h +++ b/Framework/TestWorkflows/src/o2_sim_tpc.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/test_CCDBFetchToTimeframe.cxx b/Framework/TestWorkflows/src/test_CCDBFetchToTimeframe.cxx index b86ae09e8ab9f..137f52ad7b8ab 100644 --- a/Framework/TestWorkflows/src/test_CCDBFetchToTimeframe.cxx +++ b/Framework/TestWorkflows/src/test_CCDBFetchToTimeframe.cxx @@ -1,48 +1,42 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/runDataProcessing.h" +#include "Framework/Logger.h" #include "Framework/ControlService.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/DataRefUtils.h" #include <chrono> #include <thread> using namespace o2::framework; -using namespace o2::header; // Set a start value which might correspond to a real timestamp of an object in CCDB, for example: // o2-testworkflows-ccdb-fetch-to-timeframe --condition-backend http://ccdb-test.cern.ch:8080 --start-value-enumeration 1575985965925000 WorkflowSpec defineDataProcessing(ConfigContext const&) { return WorkflowSpec{ - {"A", - {}, - {OutputSpec{"TST", "A1", 0, Lifetime::Timeframe}}, - AlgorithmSpec{ - adaptStateless([](DataAllocator& outputs, InputRecord& inputs, ControlService& control) { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - auto aData = outputs.make<int>(Output{"TST", "A1", 0}, 1); - })}}, { - "B", - {InputSpec{"somecondition", "TST", "textfile", 0, Lifetime::Condition}, - InputSpec{"somedata", "TST", "A1", 0, Lifetime::Timeframe}}, + "A", + {InputSpec{"somecondition", "TST", "textfile", 0, Lifetime::Condition, ccdbParamSpec("TOF/LHCphase")}, + InputSpec{"somedata", "TST", "A1", 0, Lifetime::Timer, {startTimeParamSpec(1638548475370)}}}, {}, AlgorithmSpec{ adaptStateless([](DataAllocator& outputs, InputRecord& inputs, ControlService& control) { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); DataRef condition = inputs.get("somecondition"); - auto* header = o2::header::get<const DataHeader*>(condition.header); - if (header->payloadSize != 1509) { - LOG(ERROR) << "Wrong size for condition payload (expected " << 1509 << ", found " << header->payloadSize; + auto payloadSize = DataRefUtils::getPayloadSize(condition); + if (payloadSize != 2048) { + LOGP(ERROR, "Wrong size for condition payload (expected {}, found {})", 2048, payloadSize); } control.readyToQuit(QuitRequest::All); })}, }}; -} \ No newline at end of file +} diff --git a/Framework/TestWorkflows/src/test_CCDBFetcher.cxx b/Framework/TestWorkflows/src/test_CCDBFetcher.cxx new file mode 100644 index 0000000000000..7ac4b1b867ffb --- /dev/null +++ b/Framework/TestWorkflows/src/test_CCDBFetcher.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/runDataProcessing.h" +#include "Framework/ServiceRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/DataRefUtils.h" +#include "DataFormatsTOF/CalibLHCphaseTOF.h" + +#include <chrono> +#include <thread> + +using namespace o2::framework; + +// This is how you can define your processing in a declarative way +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + return WorkflowSpec{ + { + "A", + {InputSpec{"somecondition", "TOF", "LHCphase", 0, Lifetime::Condition, ccdbParamSpec("TOF/LHCphase")}, + InputSpec{"sometimer", "TST", "BAR", 0, Lifetime::Timer, {startTimeParamSpec(1638548475371)}}}, + {OutputSpec{"TST", "A1", 0, Lifetime::Timeframe}}, + AlgorithmSpec{ + adaptStateless([](DataAllocator& outputs, InputRecord& inputs, ControlService& control) { + auto ref = inputs.get("somecondition"); + auto payloadSize = DataRefUtils::getPayloadSize(ref); + if (payloadSize != 2048) { + LOGP(ERROR, "Wrong size for condition payload (expected {}, found {}", 2048, payloadSize); + } + auto condition = inputs.get<o2::dataformats::CalibLHCphaseTOF*>("somecondition"); + LOG(ERROR) << "Condition size" << condition->size(); + for (size_t pi = 0; pi < condition->size(); pi++) { + LOGP(INFO, "Phase at {} for timestamp {} is {}", pi, condition->timestamp(pi), condition->LHCphase(pi)); + } + control.readyToQuit(QuitRequest::All); + })}, + Options{ + {"test-option", VariantType::String, "test", {"A test option"}}}, + }}; +} diff --git a/Framework/TestWorkflows/src/test_CompletionPolicies.cxx b/Framework/TestWorkflows/src/test_CompletionPolicies.cxx index a3723951039a0..60a380e139043 100644 --- a/Framework/TestWorkflows/src/test_CompletionPolicies.cxx +++ b/Framework/TestWorkflows/src/test_CompletionPolicies.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/test_RawDeviceInjector.cxx b/Framework/TestWorkflows/src/test_RawDeviceInjector.cxx index 7754363b03e69..f1c154df9a7a1 100644 --- a/Framework/TestWorkflows/src/test_RawDeviceInjector.cxx +++ b/Framework/TestWorkflows/src/test_RawDeviceInjector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,6 @@ using namespace o2::framework; -using DataHeader = o2::header::DataHeader; using DataOrigin = o2::header::DataOrigin; // A simple workflow which takes heartbeats from diff --git a/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx b/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx index 7cb35333a5aa7..d6d3cb1242f7c 100644 --- a/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx +++ b/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,10 +23,6 @@ using namespace o2::framework; using namespace o2::workflows; -using DataHeader = o2::header::DataHeader; -using DataOrigin = o2::header::DataOrigin; -using DataDescription = o2::header::DataDescription; - // This is how you can define your processing in a declarative way WorkflowSpec defineDataProcessing(ConfigContext const&) { diff --git a/Framework/TestWorkflows/src/test_o2RootMessageWorkflow.cxx b/Framework/TestWorkflows/src/test_o2RootMessageWorkflow.cxx index 3068e320196ca..20e578798ac0c 100644 --- a/Framework/TestWorkflows/src/test_o2RootMessageWorkflow.cxx +++ b/Framework/TestWorkflows/src/test_o2RootMessageWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx b/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx index bc49a193da53e..403ad8bc7127b 100644 --- a/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx +++ b/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/src/tof-dummy-ccdb.cxx b/Framework/TestWorkflows/src/tof-dummy-ccdb.cxx index 3c25c89385a8e..5f13208b00844 100644 --- a/Framework/TestWorkflows/src/tof-dummy-ccdb.cxx +++ b/Framework/TestWorkflows/src/tof-dummy-ccdb.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/TestWorkflows/test/test_MakeDPLObjects.cxx b/Framework/TestWorkflows/test/test_MakeDPLObjects.cxx index 285a0957178b9..86a073a22bdf7 100644 --- a/Framework/TestWorkflows/test/test_MakeDPLObjects.cxx +++ b/Framework/TestWorkflows/test/test_MakeDPLObjects.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/CMakeLists.txt b/Framework/Utils/CMakeLists.txt index f0fe2bc45ff36..55721d8963256 100644 --- a/Framework/Utils/CMakeLists.txt +++ b/Framework/Utils/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(DPLUtils SOURCES src/Utils.cxx @@ -17,6 +18,7 @@ o2_add_library(DPLUtils src/RawParser.cxx test/DPLBroadcasterMerger.cxx test/DPLOutputTest.cxx + test/RawPageTestData.cxx PUBLIC_LINK_LIBRARIES O2::Framework) o2_add_executable(raw-proxy @@ -53,12 +55,6 @@ o2_add_test(DPLOutput LABELS long dplutils COMMAND_LINE_ARGS ${DPL_WORKFLOW_TESTS_EXTRA_OPTIONS} --run) -o2_add_test(RootTreeWriter - SOURCES test/test_RootTreeWriter.cxx - PUBLIC_LINK_LIBRARIES O2::DPLUtils - COMPONENT_NAME DPLUtils - LABELS dplutils) - o2_add_test(RootTreeWriterWorkflow NO_BOOST_TEST SOURCES test/test_RootTreeWriterWorkflow.cxx @@ -75,20 +71,24 @@ o2_add_test(RootTreeReader LABELS dplutils COMMAND_LINE_ARGS ${DPL_WORKFLOW_TESTS_EXTRA_OPTIONS} --run) -o2_add_test(RawParser - SOURCES test/test_RawParser.cxx - PUBLIC_LINK_LIBRARIES O2::DPLUtils - COMPONENT_NAME DPLUtils - LABELS dplutils) -o2_add_test(DPLRawParser - SOURCES test/test_DPLRawParser.cxx - PUBLIC_LINK_LIBRARIES O2::DPLUtils - COMPONENT_NAME DPLUtils - LABELS dplutils) +foreach(t + RootTreeWriter + RawParser + DPLRawParser + DPLRawPageSequencer + ) + o2_add_test(${t} + SOURCES test/test_${t}.cxx + PUBLIC_LINK_LIBRARIES O2::DPLUtils + COMPONENT_NAME DPLUtils + LABELS dplutils) +endforeach() +if (TARGET benchmark::benchmark) foreach(b RawParser + DPLRawPageSequencer ) o2_add_test(benchmark_${b} NAME test_Framework_benchmark_${b} SOURCES test/benchmark_${b}.cxx @@ -96,3 +96,4 @@ foreach(b LABELS dplutils benchmark PUBLIC_LINK_LIBRARIES O2::DPLUtils benchmark::benchmark) endforeach() +endif() diff --git a/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h b/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h new file mode 100644 index 0000000000000..1b36cac62e75c --- /dev/null +++ b/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h @@ -0,0 +1,166 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef FRAMEWORK_UTILS_DPLRAWPAGESEQUENCER_H +#define FRAMEWORK_UTILS_DPLRAWPAGESEQUENCER_H + +/// @file DPLRawPageSequencer.h +/// @author Matthias Richter +/// @since 2021-07-09 +/// @brief A parser and sequencer utility for raw pages within DPL input + +#include "DPLUtils/RawParser.h" +#include "Framework/DataRef.h" +#include "Framework/DataRefUtils.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" +#include <utility> // std::declval + +namespace o2::framework +{ +class InputRecord; + +/// @class DPLRawPageSequencer +/// @brief This utility handles transparently the DPL inputs and triggers +/// a customizable action on sequences of consecutive raw pages following +/// similar RDH features, e.g. the same FEE ID. +/// +/// A DPL processor will receive raw pages accumulated on three levels: +/// 1) the DPL processor has one or more input route(s) +/// 2) multiple parts per input route (split payloads or multiple input +/// specs matching the same route spec +/// 3) variable number of raw pages in one payload +/// +/// The DPLRawPageSequencer loops transparently over all inputs matching +/// the optional filter, and partitions input buffers into sequences of +/// raw pages matching the provided predicate by binary search. +/// +/// Note: binary search requires that all raw pages must have a fixed +/// length, only the last page can be shorter. +/// +/// Usage: +/// auto isSameRdh = [](const char* left, const char* right) -> bool { +/// // implement the condition here +/// return left == right; +/// }; +/// std::vector<std::pair<const char*, size_t>> pages; +/// auto insertPages = [&pages](const char* ptr, size_t n) -> void { +/// // as an example, the sequences are simply stored in a vector +/// pages.emplace_back(ptr, n); +/// }; +/// DPLRawPageSequencer(inputs)(isSameRdh, insertPages); +/// +/// TODO: +/// - support configurable page length +class DPLRawPageSequencer +{ + public: + using rawparser_type = RawParser<8192>; + using buffer_type = typename rawparser_type::buffer_type; + + DPLRawPageSequencer() = delete; + DPLRawPageSequencer(InputRecord& inputs, std::vector<InputSpec> filterSpecs = {}) : mInput(inputs, filterSpecs) {} + + template <typename Predicate, typename Inserter> + void operator()(Predicate&& pred, Inserter&& inserter) + { + return binary(std::forward<Predicate>(pred), std::forward<Inserter>(inserter)); + } + + template <typename Predicate, typename Inserter> + void binary(Predicate pred, Inserter inserter) + { + for (auto const& ref : mInput) { + auto size = DataRefUtils::getPayloadSize(ref); + auto const pageSize = rawparser_type::max_size; + auto nPages = size / pageSize + (size % pageSize ? 1 : 0); + if (nPages == 0) { + continue; + } + // FIXME: automatic type from inserter/predicate? + const char* iterator = ref.payload; + + auto check = [&pred, &pageSize, payload = ref.payload](size_t left, size_t right) -> bool { + return pred(payload + left * pageSize, payload + right * pageSize); + }; + auto insert = [&inserter, &pageSize, payload = ref.payload](size_t pos, size_t n) -> void { + inserter(payload + pos * pageSize, n); + }; + // binary search the next different page based on the check predicate + auto search = [&check](size_t first, size_t n) -> size_t { + auto count = n; + auto pos = first; + while (count > 0) { + auto step = count / 2; + if (check(first, pos + step)) { + // still the same + pos += step; + count = n - (pos - first); + } else { + if (step == 1) { + pos += step; + break; + } + count = step; + } + } + return pos; + }; + + size_t p = 0; + do { + // insert the full block if the last RDH matches the position + if (check(p, nPages - 1)) { + insert(p, nPages - p); + break; + } + auto q = search(p, nPages - p); + insert(p, q - p); + p = q; + } while (p < nPages); + // if payloads are consecutive in memory we could apply this algorithm even over + // O2 message boundaries + } + } + + template <typename Predicate, typename Inserter> + void forward(Predicate check, Inserter inserter) + { + for (auto const& ref : mInput) { + auto size = DataRefUtils::getPayloadSize(ref); + o2::framework::RawParser parser(ref.payload, size); + const char* ptr = nullptr; + int count = 0; + for (auto it = parser.begin(); it != parser.end(); it++) { + const char* current = reinterpret_cast<const char*>(it.raw()); + if (ptr == nullptr) { + ptr = current; + } else if (check(ptr, current) == false) { + if (count) { + inserter(ptr, count); + } + count = 0; + ptr = current; + } + count++; + } + if (count) { + inserter(ptr, count); + } + } + } + + private: + InputRecordWalker mInput; +}; + +} // namespace o2::framework + +#endif //FRAMEWORK_UTILS_DPLRAWPAGESEQUENCER_H diff --git a/Framework/Utils/include/DPLUtils/DPLRawParser.h b/Framework/Utils/include/DPLUtils/DPLRawParser.h index a227ebaa753a9..222eb7f1d59b9 100644 --- a/Framework/Utils/include/DPLUtils/DPLRawParser.h +++ b/Framework/Utils/include/DPLUtils/DPLRawParser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include "Framework/DataRef.h" #include "Framework/DataRefUtils.h" #include "Framework/Logger.h" +#include "Framework/DataProcessingHeader.h" #include "Headers/DataHeader.h" #include <utility> // std::declval @@ -149,6 +151,15 @@ class DPLRawParser return nullptr; } + /// get DataProcessingHeader of the current input message + o2::framework::DataProcessingHeader const* o2DataProcessingHeader() const + { + if (mInputIterator != mEnd) { + return DataRefUtils::getHeader<o2::framework::DataProcessingHeader*>(*mPartIterator); + } + return nullptr; + } + /// get pointer to raw block at current position, rdh starts here buffer_type const* raw() const { diff --git a/Framework/Utils/include/DPLUtils/MakeRootTreeWriterSpec.h b/Framework/Utils/include/DPLUtils/MakeRootTreeWriterSpec.h index b580d989f9bd3..a56e75e70abcb 100644 --- a/Framework/Utils/include/DPLUtils/MakeRootTreeWriterSpec.h +++ b/Framework/Utils/include/DPLUtils/MakeRootTreeWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -62,8 +63,10 @@ namespace framework /// \par The processor spec is generated with the following options: /// /// --outfile +/// --output-dir /// --treename /// --nevents +/// --autosave /// --terminate /// /// \par @@ -73,8 +76,10 @@ namespace framework /// \par Constructor arguments: /// Default file name can be configured alone, tree name can only be specified after /// file name. The default number of events can be specified at arbitrary place between -/// process name and branch configuration. The process will signal to the DPL that it -/// is ready for termination. +/// process name and branch configuration. The number of events triggering autosaving +/// (by default - off) can be also specified in the constructor as an integer argument +/// coming after (not necessarilly immidiately) the number or events. The process will +/// signal to the DPL that it is ready for termination. /// /// \par Termination policy: /// The configurable termination policy specifies what to signal to the DPL when the event @@ -334,6 +339,8 @@ class MakeRootTreeWriterSpec std::vector<std::pair<std::string, std::string>> branchNameOptions; // number of events to be processed int nEvents = -1; + // autosave every nEventsAutoSave events + int nEventsAutoSave = -1; // starting with all inputs, every input which has been indicated 'ready' is removed std::unordered_set<std::string> activeInputs; // event counter @@ -366,12 +373,14 @@ class MakeRootTreeWriterSpec auto filename = ic.options().get<std::string>("outfile"); auto treename = ic.options().get<std::string>("treename"); auto treetitle = ic.options().get<std::string>("treetitle"); + auto outdir = ic.options().get<std::string>("output-dir"); processAttributes->nEvents = ic.options().get<int>("nevents"); if (processAttributes->nEvents > 0 && processAttributes->activeInputs.size() != processAttributes->nofBranches) { LOG(WARNING) << "the n inputs serve in total m branches with n != m, this means that there will be data for\n" << "different branches on the same input. Be aware that the --nevents option might lead to incomplete\n" << "data in the output file as the number of processed input sets is counted"; } + processAttributes->nEventsAutoSave = ic.options().get<int>("autosave"); try { processAttributes->terminationPolicy = TerminationPolicyMap.at(ic.options().get<std::string>("terminate")); } catch (std::out_of_range&) { @@ -388,12 +397,18 @@ class MakeRootTreeWriterSpec auto branchName = ic.options().get<std::string>(branchNameOptions[branchIndex].first.c_str()); processAttributes->writer->setBranchName(branchIndex, branchName.c_str()); } + if (!outdir.empty() && outdir != "none") { + if (outdir.back() != '/') { + outdir += '/'; + } + filename = outdir + filename; + } processAttributes->writer->init(filename.c_str(), treename.c_str(), treetitle.c_str()); - // the callback to be set as hook at stop of processing for the framework auto finishWriting = [processAttributes]() { processAttributes->writer->close(); }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, finishWriting); auto processingFct = [processAttributes](ProcessingContext& pc) { @@ -404,6 +419,7 @@ class MakeRootTreeWriterSpec auto& activeInputs = processAttributes->activeInputs; auto& counter = processAttributes->counter; auto& nEvents = processAttributes->nEvents; + auto& nEventsAutoSave = processAttributes->nEventsAutoSave; if (writer->isClosed()) { return; } @@ -459,6 +475,8 @@ class MakeRootTreeWriterSpec if ((nEvents >= 0 && counter == nEvents) || checkReady(pc.inputs())) { writer->close(); pc.services().get<ControlService>().readyToQuit(terminationPolicy == TerminationPolicy::Workflow ? QuitRequest::All : QuitRequest::Me); + } else if (nEventsAutoSave > 0 && counter && (counter % nEventsAutoSave) == 0) { + writer->autoSave(); } }; @@ -468,9 +486,11 @@ class MakeRootTreeWriterSpec Options options{ // default options {"outfile", VariantType::String, mDefaultFileName.c_str(), {"Name of the output file"}}, + {"output-dir", VariantType::String, mDefaultDir.c_str(), {"Output directory"}}, {"treename", VariantType::String, mDefaultTreeName.c_str(), {"Name of tree"}}, {"treetitle", VariantType::String, mDefaultTreeTitle.c_str(), {"Title of tree"}}, {"nevents", VariantType::Int, mDefaultNofEvents, {"Number of events to execute"}}, + {"autosave", VariantType::Int, mDefaultAutoSave, {"Autosave after number of events"}}, {"terminate", VariantType::String, mDefaultTerminationPolicy.c_str(), {"Terminate the 'process' or 'workflow'"}}, }; for (size_t branchIndex = 0; branchIndex < mBranchNameOptions.size(); branchIndex++) { @@ -521,8 +541,14 @@ class MakeRootTreeWriterSpec void parseConstructorArgs(int arg, Args&&... args) { static_assert(N == 0, "wrong argument order, default file and tree options must come before branch specs"); - mDefaultNofEvents = arg; - + if (mNIntArgCounter == 0) { + mDefaultNofEvents = arg; + } else if (mNIntArgCounter == 1) { + mDefaultAutoSave = arg; + } else { + throw std::logic_error("Too many integer arguments in the constructor"); + } + mNIntArgCounter++; parseConstructorArgs<N>(std::forward<Args>(args)...); } @@ -619,11 +645,14 @@ class MakeRootTreeWriterSpec std::string mDefaultFileName; std::string mDefaultTreeName; std::string mDefaultTreeTitle; + std::string mDefaultDir = "none"; int mDefaultNofEvents = -1; + int mDefaultAutoSave = -1; std::string mDefaultTerminationPolicy = "process"; TerminationCondition mTerminationCondition; Preprocessor mPreprocessor; size_t mNofBranches = 0; + int mNIntArgCounter = 0; CustomClose mCustomClose; }; } // namespace framework diff --git a/Framework/Utils/include/DPLUtils/RawParser.h b/Framework/Utils/include/DPLUtils/RawParser.h index 5a4ab783dbb9d..8d0384ba4194a 100644 --- a/Framework/Utils/include/DPLUtils/RawParser.h +++ b/Framework/Utils/include/DPLUtils/RawParser.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -352,7 +353,7 @@ class RawParser { public: using buffer_type = unsigned char; - size_t max_size = MAX_SIZE; + static size_t const max_size = MAX_SIZE; using self_type = RawParser<MAX_SIZE>; RawParser() = delete; diff --git a/Framework/Utils/include/DPLUtils/RootTreeReader.h b/Framework/Utils/include/DPLUtils/RootTreeReader.h index 20d2772d82f6e..920f091658825 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeReader.h +++ b/Framework/Utils/include/DPLUtils/RootTreeReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/include/DPLUtils/RootTreeWriter.h b/Framework/Utils/include/DPLUtils/RootTreeWriter.h index c6291a651ef7e..441d16728ad04 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeWriter.h +++ b/Framework/Utils/include/DPLUtils/RootTreeWriter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,39 @@ namespace o2 namespace framework { +/// Helper to get the corresponding std::function type for a callable object +/// the default is void +template <typename T> +struct get_function { + using type = void; +}; + +/// the matching specialization builds the function type from the return type +/// and types in the argument pack +template <typename Ret, typename Class, typename... Args> +struct get_function<Ret (Class::*)(Args...) const> { + using type = std::function<Ret(Args...)>; +}; + +/// check if a lambda can be assigned to concrete std::function +/// default is false +template <typename From, typename To, typename _ = void> +struct can_assign : public std::false_type { +}; + +/// specialize for callable types, i.e. having operator(), the 'From' type can be +/// assigned if its corresponding function type is the same as 'To' type +/// a direct comparison is not possible because lambdas are their own type +template <typename From, typename To> +struct can_assign< + From, To, + std::conditional_t< + false, + class_member_checker< + decltype(&From::operator())>, + void>> : public std::is_same<typename get_function<decltype(&From::operator())>::type, To> { +}; + /// @class RootTreeWriter /// @brief A generic writer interface for ROOT TTree objects. /// @@ -154,9 +188,9 @@ class RootTreeWriter /// number of branches controlled by this definition for the same type size_t nofBranches = 1; /// extractor function for the index for parallel branches - IndexExtractor getIndex; // = [](o2::framework::DataRef const&) {return 0;} + IndexExtractor getIndex = nullptr; /// get name of branch from base name and index - BranchNameMapper getName = [](std::string base, size_t i) { return base + "_" + std::to_string(i); }; + BranchNameMapper getName = nullptr; using Fill = std::function<void(TBranch& branch, T const&)>; using FillExt = std::function<void(TBranch& branch, T const&, DataRef const&)>; @@ -283,8 +317,9 @@ class RootTreeWriter void setBranchName(size_t index, const char* branchName) { auto& spec = mBranchSpecs.at(index); - if (spec.names.size() > 1 && spec.getName) { - // set the branch names for this group + if (spec.getName) { + // set the branch names for this group, we also amend if there is only one branch but + // the callback is configured size_t idx = 0; std::generate(spec.names.begin(), spec.names.end(), [&]() { return spec.getName(branchName, idx++); }); } else { @@ -330,6 +365,17 @@ class RootTreeWriter mFile.reset(nullptr); } + /// autosave the tree + void autoSave() + { + if (mIsClosed || !mFile) { + return; + } + mTree->SetEntries(); + LOG(INFO) << "Autosaving " << mTree->GetName() << " at entry " << mTree->GetEntries(); + mTree->AutoSave("overwrite"); + } + bool isClosed() const { return mIsClosed; @@ -347,14 +393,20 @@ class RootTreeWriter /// The function needs to be used with care. The user should ensure that "branch" is no longer used /// after a call to this function. template <typename T> - static TBranch* remapBranch(TBranch& branch, T* newdata) + static TBranch* remapBranch(TBranch& branchRef, T** newdata) { - auto name = branch.GetName(); - auto branchleaves = branch.GetListOfLeaves(); - auto tree = branch.GetTree(); - branch.DropBaskets("all"); - branch.DeleteBaskets("all"); - tree->GetListOfBranches()->Remove(&branch); + auto tree = branchRef.GetTree(); + auto name = branchRef.GetName(); + auto branch = tree->GetBranch(name); // the input branch might actually no belong to the tree but to TreeWriter cache + assert(branch); + if (branch->GetEntries()) { // if it has entries, then it was already remapped/filled at prevous event + branch->SetAddress(newdata); + return branch; + } + auto branchleaves = branch->GetListOfLeaves(); + branch->DropBaskets("all"); + branch->DeleteBaskets("all"); + tree->GetListOfBranches()->Remove(branch); for (auto entry : *branchleaves) { tree->GetListOfLeaves()->Remove(entry); } @@ -372,8 +424,8 @@ class RootTreeWriter std::vector<std::string> names; std::vector<TBranch*> branches; TClass* classinfo = nullptr; - IndexExtractor getIndex; - BranchNameMapper getName; + IndexExtractor getIndex = nullptr; + BranchNameMapper getName = nullptr; }; using InputContext = InputRecord; @@ -794,12 +846,15 @@ class RootTreeWriter // a getIndex function makes only sense if there are multiple branches assert(def.nofBranches <= 1 || def.getIndex); if (def.nofBranches > 1) { + // FIXME: should that be an exception since assert is disabled in the normal build? assert(def.getIndex && def.getName); mBranchSpecs.back().getIndex = def.getIndex; - mBranchSpecs.back().getName = def.getName; mBranchSpecs.back().names.resize(def.nofBranches); + } - // fill the branch names by calling the getName callback + // always amend the branch name(s) if the callback is configured + if (def.getName) { + mBranchSpecs.back().getName = def.getName; idx = 0; std::generate(mBranchSpecs.back().names.begin(), mBranchSpecs.back().names.end(), [&def, &idx]() { return def.getName(def.branchName, idx++); }); diff --git a/Framework/Utils/include/DPLUtils/Utils.h b/Framework/Utils/include/DPLUtils/Utils.h index 1d6129f21aa31..a4e5cd7bfe5be 100644 --- a/Framework/Utils/include/DPLUtils/Utils.h +++ b/Framework/Utils/include/DPLUtils/Utils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/src/DPLBroadcaster.cxx b/Framework/Utils/src/DPLBroadcaster.cxx index 6c4639d59e31d..4ea5e5747cd42 100644 --- a/Framework/Utils/src/DPLBroadcaster.cxx +++ b/Framework/Utils/src/DPLBroadcaster.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "DPLUtils/Utils.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataProcessingHeader.h" +#include "Framework/DataRefUtils.h" #include "Headers/DataHeader.h" namespace o2f = o2::framework; @@ -68,8 +70,8 @@ o2f::DataProcessorSpec defineBroadcaster(std::string devName, o2f::InputSpec usr o2f::DataProcessorSpec defineBroadcaster(std::string devName, o2f::InputSpec usrInput, o2f::Outputs usrOutputs) { // This lambda retrieves the message size using the API - auto funcSize = [](o2f::DataRef d) -> size_t { - return (o2::header::get<o2::header::DataHeader*>(d.header))->payloadSize; + auto funcSize = [](o2f::DataRef ref) -> size_t { + return o2::framework::DataRefUtils::getPayloadSize(ref); }; // Callling complete implementation return defineBroadcaster(devName, usrInput, usrOutputs, funcSize); diff --git a/Framework/Utils/src/DPLGatherer.cxx b/Framework/Utils/src/DPLGatherer.cxx index 14f033a40b530..039e6720980d1 100644 --- a/Framework/Utils/src/DPLGatherer.cxx +++ b/Framework/Utils/src/DPLGatherer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "DPLUtils/Utils.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/DataRefUtils.h" #include <vector> namespace o2f = o2::framework; @@ -40,7 +42,7 @@ o2f::DataProcessorSpec defineGatherer(std::string devName, o2f::Inputs usrInputs // Iterating over the Inputs to forward them on the same Output for (const auto& itInputs : ctx.inputs()) { // Retrieving message size from API - auto msgSize = (o2::header::get<o2::header::DataHeader*>(itInputs.header))->payloadSize; + auto msgSize = o2::framework::DataRefUtils::getPayloadSize(itInputs); // Allocating new chunk auto& fwdMsg = ctx.outputs().newChunk((*outputPtr), msgSize); // Moving the input to the output chunk diff --git a/Framework/Utils/src/DPLMerger.cxx b/Framework/Utils/src/DPLMerger.cxx index 75f2db8e73579..6f91df32a4cca 100644 --- a/Framework/Utils/src/DPLMerger.cxx +++ b/Framework/Utils/src/DPLMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "DPLUtils/Utils.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/DataRefUtils.h" #include <vector> namespace o2f = o2::framework; @@ -55,10 +57,10 @@ o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs, o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs, o2f::OutputSpec usrOutput) { // This lambda retrieves the payload size through the API and back-inserts it on the output buffer - auto funcMerge = [](OutputBuffer& buf, const o2f::DataRef d) { - auto msgSize = (o2::header::get<o2::header::DataHeader*>(d.header))->payloadSize; + auto funcMerge = [](OutputBuffer& buf, const o2f::DataRef ref) { + auto msgSize = o2::framework::DataRefUtils::getPayloadSize(ref); buf.resize(buf.size() + msgSize); - std::copy(&(d.payload[0]), &(d.payload[msgSize - 1]), std::back_inserter(buf)); + std::copy(&(ref.payload[0]), &(ref.payload[msgSize - 1]), std::back_inserter(buf)); }; // Callling complete implementation return defineMerger(devName, usrInputs, usrOutput, funcMerge); diff --git a/Framework/Utils/src/DPLRouter.cxx b/Framework/Utils/src/DPLRouter.cxx index 37a6a206feb87..7795cb37d4ea0 100644 --- a/Framework/Utils/src/DPLRouter.cxx +++ b/Framework/Utils/src/DPLRouter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "DPLUtils/Utils.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/DataRefUtils.h" #include <vector> namespace o2f = o2::framework; @@ -39,7 +41,7 @@ o2f::DataProcessorSpec defineRouter(std::string devName, o2f::Inputs usrInput, o // Defining the ProcessCallback as returned object of InitCallback return [outputsPtr, mappingFuncPtr](o2f::ProcessingContext& ctx) { auto inputMsg = ctx.inputs().getByPos(0); - auto msgSize = (o2::header::get<o2::header::DataHeader*>(inputMsg.header))->payloadSize; + auto msgSize = o2::framework::DataRefUtils::getPayloadSize(inputMsg); auto& outputCh = (*outputsPtr)[(*mappingFuncPtr)(inputMsg)]; auto& fwdMsg = ctx.outputs().newChunk(outputCh, msgSize); diff --git a/Framework/Utils/src/RawParser.cxx b/Framework/Utils/src/RawParser.cxx index 2145e4d97d6e1..9c0f9452932e7 100644 --- a/Framework/Utils/src/RawParser.cxx +++ b/Framework/Utils/src/RawParser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/src/Utils.cxx b/Framework/Utils/src/Utils.cxx index b7f1414ee9f43..3a52c46e074af 100644 --- a/Framework/Utils/src/Utils.cxx +++ b/Framework/Utils/src/Utils.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/src/dpl-output-proxy.cxx b/Framework/Utils/src/dpl-output-proxy.cxx index d7941cc520778..52483bfc92f25 100644 --- a/Framework/Utils/src/dpl-output-proxy.cxx +++ b/Framework/Utils/src/dpl-output-proxy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,6 +29,14 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) ConfigParamSpec{ "dataspec", VariantType::String, "dpl-output-proxy:TST/CLUSTERS;dpl-output-proxy:TST/TRACKS", {"selection string for the data to be proxied"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "output-proxy-method", VariantType::String, "bind", {"proxy socket method: bind, connect"}}); + + workflowOptions.push_back( + ConfigParamSpec{ + "output-proxy-address", VariantType::String, "0.0.0.0", {"address to connect / bind to"}}); + workflowOptions.push_back( ConfigParamSpec{ "default-transport", VariantType::String, "shmem", {"default transport: shmem, zeromq"}}); @@ -65,8 +74,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) OutputChannelSpec externalChannelSpec; externalChannelSpec.name = "downstream"; externalChannelSpec.type = ChannelType::Push; - externalChannelSpec.method = ChannelMethod::Bind; - externalChannelSpec.hostname = "localhost"; + if (config.options().get<std::string>("output-proxy-method") == "bind") { + externalChannelSpec.method = ChannelMethod::Bind; + } else if (config.options().get<std::string>("output-proxy-method") == "connect") { + externalChannelSpec.method = ChannelMethod::Connect; + } + externalChannelSpec.hostname = config.options().get<std::string>("output-proxy-address"); externalChannelSpec.port = defaultPort; externalChannelSpec.listeners = 0; // in principle, protocol and transport are two different things but fur simplicity diff --git a/Framework/Utils/src/raw-parser.cxx b/Framework/Utils/src/raw-parser.cxx index bbd7b5c1d1a06..e0d5a2da97faa 100644 --- a/Framework/Utils/src/raw-parser.cxx +++ b/Framework/Utils/src/raw-parser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "Framework/ConfigParamSpec.h" #include "DPLUtils/DPLRawParser.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include <vector> #include <sstream> @@ -66,17 +68,23 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) } // print the DataHeader information only for the first part or if we have high verbosity if (loglevel > 1 || dh->splitPayloadIndex == 0) { - rdhprintout << dh->dataOrigin.as<std::string>() << "/" - << dh->dataDescription.as<std::string>() << "/" - << dh->subSpecification << " "; + rdhprintout << fmt::format("DH: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification) << " " + << " TF " << dh->tfCounter << " Run " << dh->runNumber << " |"; + // at high verbosity print part number, otherwise only the total number of parts if (loglevel > 1) { - rdhprintout << "part " + std::to_string(dh->splitPayloadIndex) + " of " + std::to_string(dh->splitPayloadParts); + rdhprintout << " part " + std::to_string(dh->splitPayloadIndex) + " of " + std::to_string(dh->splitPayloadParts); } else { rdhprintout << " " + std::to_string(dh->splitPayloadParts) + " part(s)"; } - rdhprintout << " payload size " << dh->payloadSize - << std::endl; + rdhprintout << " payload size " << dh->payloadSize; + + const auto* dph = it.o2DataProcessingHeader(); + if (dph) { + rdhprintout << " | DPH: " + << " Start " << dph->startTime << " dT " << dph->duration << " Creation " << dph->creation; + } + rdhprintout << std::endl; } rdhprintout << DPLRawParser::RDHInfo(it) << std::endl; } diff --git a/Framework/Utils/src/raw-proxy.cxx b/Framework/Utils/src/raw-proxy.cxx index 0868436d113b8..ac75c7808796e 100644 --- a/Framework/Utils/src/raw-proxy.cxx +++ b/Framework/Utils/src/raw-proxy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/DPLBroadcasterMerger.cxx b/Framework/Utils/test/DPLBroadcasterMerger.cxx index 31a9b399e84fc..2535e1a052d90 100644 --- a/Framework/Utils/test/DPLBroadcasterMerger.cxx +++ b/Framework/Utils/test/DPLBroadcasterMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "DPLUtils/Utils.h" #include "Framework/DataProcessorSpec.h" #include "Framework/ControlService.h" +#include "Framework/DataRefUtils.h" #include "random" #include "Framework/Logger.h" #include <thread> @@ -82,7 +84,7 @@ o2f::DataProcessorSpec definePipeline(std::string devName, o2f::InputSpec usrInp // Processing context in captured from return on InitCallback return [output_sharedptr](o2f::ProcessingContext& ctx) { auto inputMsg = ctx.inputs().getByPos(0); - auto msgSize = (o2::header::get<o2::header::DataHeader*>(inputMsg.header))->payloadSize; + auto msgSize = o2::framework::DataRefUtils::getPayloadSize(inputMsg); auto& fwdMsg = ctx.outputs().newChunk((*output_sharedptr), msgSize); std::memcpy(fwdMsg.data(), inputMsg.payload, msgSize); diff --git a/Framework/Utils/test/DPLBroadcasterMerger.h b/Framework/Utils/test/DPLBroadcasterMerger.h index da3eeb2d1044a..4607d72a702b7 100644 --- a/Framework/Utils/test/DPLBroadcasterMerger.h +++ b/Framework/Utils/test/DPLBroadcasterMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/DPLOutputTest.cxx b/Framework/Utils/test/DPLOutputTest.cxx index 8286faf9eba3f..4bc75d4299285 100644 --- a/Framework/Utils/test/DPLOutputTest.cxx +++ b/Framework/Utils/test/DPLOutputTest.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/DPLOutputTest.h b/Framework/Utils/test/DPLOutputTest.h index 9d48271d18e51..ce776ffff1113 100644 --- a/Framework/Utils/test/DPLOutputTest.h +++ b/Framework/Utils/test/DPLOutputTest.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/RawPageTestData.cxx b/Framework/Utils/test/RawPageTestData.cxx new file mode 100644 index 0000000000000..7df0617ce98db --- /dev/null +++ b/Framework/Utils/test/RawPageTestData.cxx @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawPageTestData.cxx +/// @author Matthias Richter +/// @since 2021-06-21 +/// @brief Raw page test data generator + +#include "RawPageTestData.h" +#include "Headers/Stack.h" +#include <random> + +namespace o2::framework +{ +namespace test +{ + +DataSet createData(std::vector<InputSpec> const& inputspecs, std::vector<DataHeader> const& dataheaders, AmendRawDataHeader amendRdh) +{ + // Create the routes we want for the InputRecord + size_t i = 0; + auto createRoute = [&i](std::string const& source, InputSpec const& spec) { + return InputRoute{ + spec, + i++, + source}; + }; + + std::vector<InputRoute> schema; + for (auto const& spec : inputspecs) { + auto routename = spec.binding + "_source"; + schema.emplace_back(createRoute(routename, spec)); + } + + std::random_device rd; + std::uniform_int_distribution<> testvals(0, 42); + auto randval = [&rd, &testvals]() { + return testvals(rd); + }; + std::vector<int> checkValues; + DataSet::Messages messages; + + auto initRawPage = [&checkValues, &amendRdh](char* buffer, size_t size, auto value) { + char* wrtptr = buffer; + while (wrtptr < buffer + size) { + auto* header = reinterpret_cast<RAWDataHeader*>(wrtptr); + *header = RAWDataHeader(); + if (amendRdh) { + amendRdh(*header); + } + header->offsetToNext = PAGESIZE; + *reinterpret_cast<decltype(value)*>(wrtptr + header->headerSize) = value; + wrtptr += PAGESIZE; + checkValues.emplace_back(value); + ++value; + } + }; + + auto createMessage = [&messages, &initRawPage, &randval](DataHeader dh) { + DataProcessingHeader dph{0, 1}; + Stack stack{dh, dph}; + if (dh.splitPayloadParts == 0 || dh.splitPayloadIndex == 0) { + // add new message collection + messages.emplace_back(); + } + messages.back().emplace_back(std::make_unique<std::vector<char>>(stack.size())); + memcpy(messages.back().back()->data(), stack.data(), messages.back().back()->size()); + messages.back().emplace_back(std::make_unique<std::vector<char>>(dh.payloadSize)); + int value = randval(); + initRawPage(messages.back().back()->data(), messages.back().back()->size(), value); + }; + + // create messages for the provided dataheaders + for (auto header : dataheaders) { + for (DataHeader::SplitPayloadIndexType index = 0; index == 0 || index < header.splitPayloadParts; index++) { + header.splitPayloadIndex = index; + createMessage(header); + } + } + + return {std::move(schema), std::move(messages), std::move(checkValues)}; +} + +} // namespace test +} // namespace o2::framework diff --git a/Framework/Utils/test/RawPageTestData.h b/Framework/Utils/test/RawPageTestData.h new file mode 100644 index 0000000000000..71a11bad014f0 --- /dev/null +++ b/Framework/Utils/test/RawPageTestData.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file RawPageTestData.h +/// @author Matthias Richter +/// @since 2021-06-21 +/// @brief Raw page test data generator + +#ifndef FRAMEWORK_UTILS_RAWPAGETESTDATA_H +#define FRAMEWORK_UTILS_RAWPAGETESTDATA_H + +#include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" +#include "Headers/RAWDataHeader.h" +#include "Headers/DataHeader.h" +#include <vector> +#include <memory> + +using DataHeader = o2::header::DataHeader; +using Stack = o2::header::Stack; +using RAWDataHeaderV6 = o2::header::RAWDataHeaderV6; + +namespace o2::framework +{ +namespace test +{ +using RAWDataHeader = RAWDataHeaderV6; +static const size_t PAGESIZE = 8192; + +/// @class DataSet +/// @brief Simple helper struct to keep the InputRecord and ownership of messages +/// together with some test data. +struct DataSet { + // not nice with the double vector but for quick unit test ok + using Messages = std::vector<std::vector<std::unique_ptr<std::vector<char>>>>; + DataSet(std::vector<InputRoute>&& s, Messages&& m, std::vector<int>&& v) + : schema{std::move(s)}, + messages{std::move(m)}, + span{[this](size_t i, size_t part) { + auto header = static_cast<char const*>(this->messages[i].at(2 * part)->data()); + auto payload = static_cast<char const*>(this->messages[i].at(2 * part + 1)->data()); + return DataRef{nullptr, header, payload}; + }, + [this](size_t i) { return i < this->messages.size() ? messages[i].size() / 2 : 0; }, this->messages.size()}, + record{schema, span}, + values{std::move(v)} + { + } + + std::vector<InputRoute> schema; + Messages messages; + InputSpan span; + InputRecord record; + std::vector<int> values; +}; + +using AmendRawDataHeader = std::function<void(RAWDataHeader&)>; +DataSet createData(std::vector<InputSpec> const& inputspecs, std::vector<DataHeader> const& dataheaders, AmendRawDataHeader amendRdh = nullptr); + +} // namespace test +} // namespace o2::framework +#endif // FRAMEWORK_UTILS_RAWPAGETESTDATA_H diff --git a/Framework/Utils/test/benchmark_DPLRawPageSequencer.cxx b/Framework/Utils/test/benchmark_DPLRawPageSequencer.cxx new file mode 100644 index 0000000000000..72f68cacbabda --- /dev/null +++ b/Framework/Utils/test/benchmark_DPLRawPageSequencer.cxx @@ -0,0 +1,103 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file benchmark_DPLRawPageSequencer.h +/// @author Matthias Richter +/// @since 2021-07-21 +/// @brief Unit test for the DPL raw page sequencer utility + +#include <benchmark/benchmark.h> + +#include "DPLUtils/DPLRawPageSequencer.h" +#include "RawPageTestData.h" +#include <random> +#include <vector> + +using namespace o2::framework; +auto const PAGESIZE = test::PAGESIZE; + +auto createData(int nPages) +{ + const int nParts = 16; + std::vector<InputSpec> inputspecs = { + InputSpec{"tpc", "TPC", "RAWDATA", 0, Lifetime::Timeframe}}; + + std::vector<DataHeader> dataheaders; + dataheaders.emplace_back("RAWDATA", "TPC", 0, nPages * PAGESIZE, 0, nParts); + + std::random_device rd; + std::uniform_int_distribution<> lengthDist(1, nPages); + auto randlength = [&rd, &lengthDist]() { + return lengthDist(rd); + }; + + int rdhCount = 0; + // whenever a new id is created, it is done from the current counter + // position, so we also have the possibility to calculate the length + std::vector<uint16_t> fees; + auto nextlength = randlength(); + auto createFEEID = [&rdhCount, &fees, &nPages, &randlength, &nextlength]() { + if (rdhCount % nPages == 0 || rdhCount - fees.back() > nextlength) { + fees.emplace_back(rdhCount); + nextlength = randlength(); + } + return fees.back(); + }; + auto amendRdh = [&rdhCount, createFEEID](test::RAWDataHeader& rdh) { + rdh.feeId = createFEEID(); + rdhCount++; + }; + + return test::createData(inputspecs, dataheaders, amendRdh); +} + +static void BM_DPLRawPageSequencerBinary(benchmark::State& state) +{ + auto isSameRdh = [](const char* left, const char* right) -> bool { + if (left == right) { + return true; + } + + return reinterpret_cast<test::RAWDataHeader const*>(left)->feeId == reinterpret_cast<test::RAWDataHeader const*>(right)->feeId; + }; + std::vector<std::pair<const char*, size_t>> pages; + auto insertPages = [&pages](const char* ptr, size_t n) -> void { + pages.emplace_back(ptr, n); + }; + auto dataset = createData(state.range(0)); + for (auto _ : state) { + DPLRawPageSequencer(dataset.record).binary(isSameRdh, insertPages); + } +} + +static void BM_DPLRawPageSequencerForward(benchmark::State& state) +{ + auto isSameRdh = [](const char* left, const char* right) -> bool { + if (left == right) { + return true; + } + + return reinterpret_cast<test::RAWDataHeader const*>(left)->feeId == reinterpret_cast<test::RAWDataHeader const*>(right)->feeId; + }; + std::vector<std::pair<const char*, size_t>> pages; + auto insertPages = [&pages](const char* ptr, size_t n) -> void { + pages.emplace_back(ptr, n); + }; + auto dataset = createData(state.range(0)); + for (auto _ : state) { + DPLRawPageSequencer(dataset.record).forward(isSameRdh, insertPages); + } +} + +BENCHMARK(BM_DPLRawPageSequencerBinary)->Arg(64)->Arg(512)->Arg(1024); +BENCHMARK(BM_DPLRawPageSequencerForward)->Arg(64)->Arg(512)->Arg(1024); + +BENCHMARK_MAIN(); diff --git a/Framework/Utils/test/benchmark_RawParser.cxx b/Framework/Utils/test/benchmark_RawParser.cxx index 39235ab3a300e..ed93f0ed38a84 100644 --- a/Framework/Utils/test/benchmark_RawParser.cxx +++ b/Framework/Utils/test/benchmark_RawParser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/test_DPLBroadcasterMerger.cxx b/Framework/Utils/test/test_DPLBroadcasterMerger.cxx index 2cf006de6910f..6ff554e75f462 100644 --- a/Framework/Utils/test/test_DPLBroadcasterMerger.cxx +++ b/Framework/Utils/test/test_DPLBroadcasterMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/test_DPLOutputTest.cxx b/Framework/Utils/test/test_DPLOutputTest.cxx index 827c5eb24dade..e49bea3074dd1 100644 --- a/Framework/Utils/test/test_DPLOutputTest.cxx +++ b/Framework/Utils/test/test_DPLOutputTest.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/test_DPLRawPageSequencer.cxx b/Framework/Utils/test/test_DPLRawPageSequencer.cxx new file mode 100644 index 0000000000000..671efb18f5159 --- /dev/null +++ b/Framework/Utils/test/test_DPLRawPageSequencer.cxx @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file test_DPLRawPageSequencer.h +/// @author Matthias Richter +/// @since 2021-07-09 +/// @brief Unit test for the DPL raw page sequencer utility + +#define BOOST_TEST_MODULE Test Framework Utils DPLRawPageSequencer +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include "DPLUtils/DPLRawPageSequencer.h" +#include "RawPageTestData.h" +#include "Framework/InputRecord.h" +#include "Headers/DataHeader.h" +#include <vector> +#include <memory> +#include <iostream> +#include <random> + +using namespace o2::framework; +using DataHeader = o2::header::DataHeader; +auto const PAGESIZE = test::PAGESIZE; + +BOOST_AUTO_TEST_CASE(test_DPLRawPageSequencer) +{ + const int nPages = 64; + const int nParts = 16; + std::vector<InputSpec> inputspecs = { + InputSpec{"tpc", "TPC", "RAWDATA", 0, Lifetime::Timeframe}}; + + std::vector<DataHeader> dataheaders; + dataheaders.emplace_back("RAWDATA", "TPC", 0, nPages * PAGESIZE, 0, nParts); + + std::random_device rd; + std::uniform_int_distribution<> lengthDist(1, nPages); + auto randlength = [&rd, &lengthDist]() { + return lengthDist(rd); + }; + + int rdhCount = 0; + // whenever a new id is created, it is done from the current counter + // position, so we also have the possibility to calculate the length + std::vector<uint16_t> feeids; + auto nextlength = randlength(); + auto createFEEID = [&rdhCount, &feeids, &nPages, &randlength, &nextlength]() { + if (rdhCount % nPages == 0 || rdhCount - feeids.back() > nextlength) { + feeids.emplace_back(rdhCount); + nextlength = randlength(); + } + return feeids.back(); + }; + auto amendRdh = [&rdhCount, createFEEID](test::RAWDataHeader& rdh) { + rdh.feeId = createFEEID(); + rdhCount++; + }; + + auto dataset = test::createData(inputspecs, dataheaders, amendRdh); + InputRecord& inputs = dataset.record; + BOOST_REQUIRE(dataset.messages.size() > 0); + BOOST_REQUIRE(dataset.messages[0].at(0) != nullptr); + BOOST_REQUIRE(inputs.size() > 0); + BOOST_CHECK((*inputs.begin()).header == dataset.messages[0].at(0)->data()); + BOOST_REQUIRE(rdhCount == nPages * nParts); + DPLRawPageSequencer parser(inputs); + + auto isSameRdh = [](const char* left, const char* right) -> bool { + if (left == right) { + return true; + } + if (left == nullptr || right == nullptr) { + return true; + } + + return reinterpret_cast<test::RAWDataHeader const*>(left)->feeId == reinterpret_cast<test::RAWDataHeader const*>(right)->feeId; + }; + std::vector<std::pair<const char*, size_t>> pages; + auto insertPages = [&pages](const char* ptr, size_t n) -> void { + pages.emplace_back(ptr, n); + }; + parser(isSameRdh, insertPages); + + // a second parsing step based on forward search + std::vector<std::pair<const char*, size_t>> pagesByForwardSearch; + auto insertForwardPages = [&pagesByForwardSearch](const char* ptr, size_t n) -> void { + pagesByForwardSearch.emplace_back(ptr, n); + }; + DPLRawPageSequencer(inputs).forward(isSameRdh, insertForwardPages); + + LOG(INFO) << "called RDH amend: " << rdhCount; + LOG(INFO) << "created " << feeids.size() << " id(s), got " << pages.size() << " page(s)"; + BOOST_REQUIRE(pages.size() == feeids.size()); + BOOST_REQUIRE(pages.size() == pagesByForwardSearch.size()); + + feeids.emplace_back(rdhCount); + auto lastId = feeids.front(); + for (auto i = 0; i < pages.size(); i++) { + auto length = feeids[i + 1] - feeids[i]; + BOOST_CHECK_MESSAGE(pages[i].second == length, "sequence " << i << " at " << feeids[i] << " length " << length << ": got " << pages[i].second); + BOOST_CHECK_MESSAGE(pages[i].first == pagesByForwardSearch[i].first && pages[i].second == pagesByForwardSearch[i].second, + "mismatch with forward search at sequence " << i + << " [" << (void*)pages[i].first << "," << (void*)pagesByForwardSearch[i].first << "]" + << " [" << pages[i].second << "," << pagesByForwardSearch[i].second << "]"); + } +} diff --git a/Framework/Utils/test/test_DPLRawParser.cxx b/Framework/Utils/test/test_DPLRawParser.cxx index 7c657e5bdc481..befaace1c94e4 100644 --- a/Framework/Utils/test/test_DPLRawParser.cxx +++ b/Framework/Utils/test/test_DPLRawParser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,128 +14,36 @@ #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> #include "DPLUtils/DPLRawParser.h" +#include "RawPageTestData.h" #include "Framework/InputRecord.h" #include "Framework/WorkflowSpec.h" // o2::framework::select #include "Headers/DataHeader.h" -#include "Headers/Stack.h" #include <vector> #include <memory> #include <iostream> using namespace o2::framework; using DataHeader = o2::header::DataHeader; -using Stack = o2::header::Stack; -using RAWDataHeaderV4 = o2::header::RAWDataHeaderV4; - -static const size_t PAGESIZE = 8192; - -// simple helper struct to keep the InputRecord and ownership of messages -struct DataSet { - // not nice with the double vector but for quick unit test ok - using Messages = std::vector<std::vector<std::unique_ptr<std::vector<char>>>>; - DataSet(std::vector<InputRoute>&& s, Messages&& m, std::vector<int>&& v) - : schema{std::move(s)}, messages{std::move(m)}, record{schema, {[this](size_t i, size_t part) { - BOOST_REQUIRE(i < this->messages.size()); - BOOST_REQUIRE(part < this->messages[i].size() / 2); - auto header = static_cast<char const*>(this->messages[i].at(2 * part)->data()); - auto payload = static_cast<char const*>(this->messages[i].at(2 * part + 1)->data()); - return DataRef{nullptr, header, payload}; - }, - [this](size_t i) { return i < this->messages.size() ? messages[i].size() / 2 : 0; }, this->messages.size()}}, - values{std::move(v)} - { - BOOST_REQUIRE(messages.size() == schema.size()); - } - - std::vector<InputRoute> schema; - Messages messages; - InputRecord record; - std::vector<int> values; -}; +auto const PAGESIZE = test::PAGESIZE; +using DataSet = test::DataSet; DataSet createData() { - // Create the routes we want for the InputRecord std::vector<InputSpec> inputspecs = { InputSpec{"tpc0", "TPC", "RAWDATA", 0, Lifetime::Timeframe}, InputSpec{"its1", "ITS", "RAWDATA", 0, Lifetime::Timeframe}, InputSpec{"its1", "ITS", "RAWDATA", 1, Lifetime::Timeframe}}; - size_t i = 0; - auto createRoute = [&i](const char* source, InputSpec& spec) { - return InputRoute{ - spec, - i++, - source}; - }; - - std::vector<InputRoute> schema = { - createRoute("tpc_source", inputspecs[0]), - createRoute("its_source", inputspecs[1]), - createRoute("tof_source", inputspecs[2])}; - - std::vector<int> checkValues; - DataSet::Messages messages; - - auto initRawPage = [&checkValues](char* buffer, size_t size, int value) { - char* wrtptr = buffer; - while (wrtptr < buffer + size) { - auto* header = reinterpret_cast<RAWDataHeaderV4*>(wrtptr); - *header = RAWDataHeaderV4(); - header->offsetToNext = PAGESIZE; - *reinterpret_cast<decltype(value)*>(wrtptr + header->headerSize) = value; - wrtptr += PAGESIZE; - checkValues.emplace_back(value); - ++value; - } - }; - - auto createMessage = [&messages, &initRawPage](DataHeader dh, int value) { - DataProcessingHeader dph{0, 1}; - Stack stack{dh, dph}; - if (dh.splitPayloadParts == 0 || dh.splitPayloadIndex == 0) { - // add new message collection - messages.emplace_back(); - } - messages.back().emplace_back(std::make_unique<std::vector<char>>(stack.size())); - memcpy(messages.back().back()->data(), stack.data(), messages.back().back()->size()); - messages.back().emplace_back(std::make_unique<std::vector<char>>(dh.payloadSize)); - initRawPage(messages.back().back()->data(), messages.back().back()->size(), value); - }; - // we create message for the 3 input routes, the messages have different page size // and the second messages has 3 parts, each with the same page size // the test value is written as payload after the RDH and all values are cached for // later checking when parsing the data set - DataHeader dh1; - dh1.dataDescription = "RAWDATA"; - dh1.dataOrigin = "TPC"; - dh1.subSpecification = 0; - dh1.payloadSerializationMethod = o2::header::gSerializationMethodNone; - dh1.payloadSize = 5 * PAGESIZE; - DataHeader dh2; - dh2.dataDescription = "RAWDATA"; - dh2.dataOrigin = "ITS"; - dh2.subSpecification = 0; - dh2.payloadSerializationMethod = o2::header::gSerializationMethodNone; - dh2.payloadSize = 3 * PAGESIZE; - dh2.splitPayloadParts = 3; - dh2.splitPayloadIndex = 0; - DataHeader dh3; - dh3.dataDescription = "RAWDATA"; - dh3.dataOrigin = "ITS"; - dh3.subSpecification = 1; - dh3.payloadSerializationMethod = o2::header::gSerializationMethodNone; - dh3.payloadSize = 4 * PAGESIZE; - createMessage(dh1, 10); - createMessage(dh2, 20); - dh2.splitPayloadIndex++; - createMessage(dh2, 23); - dh2.splitPayloadIndex++; - createMessage(dh2, 26); - createMessage(dh3, 30); + std::vector<DataHeader> dataheaders; + dataheaders.emplace_back("RAWDATA", "TPC", 0, 5 * PAGESIZE); + dataheaders.emplace_back("RAWDATA", "ITS", 0, 3 * PAGESIZE, 0, 3); + dataheaders.emplace_back("RAWDATA", "ITS", 1, 4 * PAGESIZE); - return {std::move(schema), std::move(messages), std::move(checkValues)}; + return test::createData(inputspecs, dataheaders); } BOOST_AUTO_TEST_CASE(test_DPLRawParser) @@ -151,8 +60,8 @@ BOOST_AUTO_TEST_CASE(test_DPLRawParser) for (auto it = parser.begin(), end = parser.end(); it != end; ++it, ++count) { LOG(INFO) << "data " << count << " " << *((int*)it.data()); // now check the iterator API - // retrieving RDH v4 - auto const* rdh = it.get_if<o2::header::RAWDataHeaderV4>(); + // retrieving RDH + auto const* rdh = it.get_if<test::RAWDataHeader>(); // retrieving the raw pointer of the page auto const* raw = it.raw(); // retrieving payload pointer of the page @@ -162,10 +71,10 @@ BOOST_AUTO_TEST_CASE(test_DPLRawParser) // offset of payload in the raw page size_t offset = it.offset(); BOOST_REQUIRE(rdh != nullptr); - BOOST_REQUIRE(offset == sizeof(o2::header::RAWDataHeaderV4)); + BOOST_REQUIRE(offset == sizeof(test::RAWDataHeader)); BOOST_REQUIRE(payload == raw + offset); BOOST_REQUIRE(*reinterpret_cast<int const*>(payload) == dataset.values[count]); - BOOST_REQUIRE(payloadSize == PAGESIZE - sizeof(o2::header::RAWDataHeaderV4)); + BOOST_REQUIRE(payloadSize == PAGESIZE - sizeof(test::RAWDataHeader)); auto const* dh = it.o2DataHeader(); if (last != dh) { // this is a special wrapper to print the RDU info and table header, this will diff --git a/Framework/Utils/test/test_RawParser.cxx b/Framework/Utils/test/test_RawParser.cxx index 8f39f436b7619..8a4acf1c032e0 100644 --- a/Framework/Utils/test/test_RawParser.cxx +++ b/Framework/Utils/test/test_RawParser.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Framework/Utils/test/test_RootTreeReader.cxx b/Framework/Utils/test/test_RootTreeReader.cxx index 15a30e9030338..e723ba641f931 100644 --- a/Framework/Utils/test/test_RootTreeReader.cxx +++ b/Framework/Utils/test/test_RootTreeReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "Framework/InputSpec.h" #include "Framework/OutputSpec.h" #include "Framework/ControlService.h" +#include "Framework/DataRefUtils.h" #include "DPLUtils/RootTreeReader.h" #include "Headers/DataHeader.h" #include "Headers/NameHeader.h" @@ -31,7 +33,7 @@ using namespace o2::framework; #define ASSERT_ERROR(condition) \ if ((condition) == false) { \ - LOG(ERROR) << R"(Test condition ")" #condition R"(" failed)"; \ + LOG(FATAL) << R"(Test condition ")" #condition R"(" failed)"; \ } const int gTreeSize = 10; // elements in the test tree @@ -108,7 +110,7 @@ DataProcessorSpec getSinkSpec() static int counter = 0; using DataHeader = o2::header::DataHeader; for (auto& input : pc.inputs()) { - auto dh = o2::header::get<const DataHeader*>(input.header); + auto dh = DataRefUtils::getHeader<const DataHeader*>(input); LOG(INFO) << dh->dataOrigin.str << " " << dh->dataDescription.str << " " << dh->payloadSize; } auto data = pc.inputs().get<std::vector<o2::test::Polymorphic>>("input1"); diff --git a/Framework/Utils/test/test_RootTreeWriter.cxx b/Framework/Utils/test/test_RootTreeWriter.cxx index cd7a414c27f69..b82a7b19a65f5 100644 --- a/Framework/Utils/test/test_RootTreeWriter.cxx +++ b/Framework/Utils/test/test_RootTreeWriter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,6 +22,7 @@ #include <fairmq/FairMQTransportFactory.h> #include "Framework/DataProcessingHeader.h" #include "Framework/InputRecord.h" +#include "Framework/InputSpan.h" #include "Framework/DataRef.h" #include "Framework/DataRefUtils.h" #include "DPLUtils/RootTreeWriter.h" @@ -218,10 +220,10 @@ BOOST_AUTO_TEST_CASE(test_RootTreeWriter) auto getter = [&store](size_t i) -> DataRef { return DataRef{nullptr, static_cast<char const*>(store[2 * i]->GetData()), static_cast<char const*>(store[2 * i + 1]->GetData())}; }; - + InputSpan span{getter, store.size() / 2}; InputRecord inputs{ schema, - InputSpan{getter, store.size() / 2}}; + span}; writer(inputs); writer.close(); @@ -308,4 +310,21 @@ BOOST_AUTO_TEST_CASE(test_RootTreeWriterSpec_store_types) // pointer type used as store type static_assert(std::is_same<Trait<std::vector<Polymorphic>>::store_type, std::vector<Polymorphic>*>::value == true); } + +BOOST_AUTO_TEST_CASE(TestCanAssign) +{ + using Callback = std::function<bool(int, float)>; + auto matching = [](int, float) -> bool { + return true; + }; + auto otherReturn = [](int, float) -> int { + return 0; + }; + auto otherParam = [](int, int) -> bool { + return true; + }; + BOOST_REQUIRE((can_assign<decltype(matching), Callback>::value == true)); + BOOST_REQUIRE((can_assign<decltype(otherReturn), Callback>::value == false)); + BOOST_REQUIRE((can_assign<decltype(otherParam), Callback>::value == false)); +} } // namespace o2::test diff --git a/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx b/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx index 744497903fcb2..01e93b69eeb29 100644 --- a/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx +++ b/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "DPLUtils/RootTreeWriter.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "../../Core/test/TestClasses.h" #include "Framework/Logger.h" #include <TSystem.h> @@ -32,7 +34,7 @@ #include <stdexcept> #include <iostream> // note: std filesystem is first supported in gcc 8 -#include <boost/filesystem.hpp> +#include <filesystem> using namespace o2::framework; @@ -76,7 +78,7 @@ class StaticChecker setError(std::string("inconsistent number of branches in 'testtree' of file ") + check.fileName + " expecting " + std::to_string(check.nBranches) + " got " + std::to_string(tree->GetNbranches())); } file->Close(); - boost::filesystem::remove(check.fileName.c_str()); + std::filesystem::remove(check.fileName.c_str()); } mChecks.clear(); if (mErrorMessage.empty() == false) { @@ -163,7 +165,7 @@ template <typename T> using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>; WorkflowSpec defineDataProcessing(ConfigContext const&) { - std::string fileName = boost::filesystem::temp_directory_path().string(); + std::string fileName = std::filesystem::temp_directory_path().string(); fileName += "/test_RootTreeWriter"; std::string altFileName = fileName + "_alt.root"; fileName += ".root"; @@ -195,11 +197,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto preprocessor = [](ProcessingContext& ctx) { for (auto const& ref : InputRecordWalker(ctx.inputs())) { auto const* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref); - std::cout << "got data: " - << dh->dataOrigin.as<std::string>() << "/" - << dh->dataDescription.as<std::string>() << "/" - << dh->subSpecification << " " - << std::endl; + LOGP(INFO, "got data: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); } }; diff --git a/GPU/CMakeLists.txt b/GPU/CMakeLists.txt index e2ba9741f3508..eed1b51e61035 100644 --- a/GPU/CMakeLists.txt +++ b/GPU/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Subdirectories will be compiled with O2 / AliRoot / Standalone To simplify the # CMake, variables are defined for Sources / Headers first. Then, the actual @@ -21,6 +22,7 @@ add_subdirectory(Common) add_subdirectory(Utils) add_subdirectory(TPCFastTransformation) add_subdirectory(GPUTracking) -if(NOT ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_subdirectory(TPCSpaceChargeBase) +if(ALIGPU_BUILD_TYPE STREQUAL "O2") + add_subdirectory(GPUbenchmark) + add_subdirectory(Workflow) endif() diff --git a/GPU/Common/CMakeLists.txt b/GPU/Common/CMakeLists.txt index f3a8502796a19..5e4ce7b4c2ab0 100644 --- a/GPU/Common/CMakeLists.txt +++ b/GPU/Common/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUCommon) @@ -18,18 +19,15 @@ set(HDRS_INSTALL GPUCommonLogger.h GPUCommonMath.h GPUCommonRtypes.h + GPUCommonArray.h + GPUCommonTypeTraits.h GPUCommonTransform3D.h - GPUDef.h - GPUDefConstantsAndSettings.h - GPUDefGPUParameters.h - GPUDefOpenCL12Templates.h - GPULogging.h - GPUDefMacros.h + GPUROOTSMatrixFwd.h GPUROOTCartesianFwd.h) if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_library(${MODULE} - SOURCES GPUCommon.cxx + SOURCES ../GPUTracking/utils/EmptyFile.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::FrameworkLogger) target_include_directories(${targetName} @@ -37,7 +35,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") $<INSTALL_INTERFACE:include/GPU>) target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB - GPUCA_TPC_GEOMETRY_O2 HAVE_O2HEADERS) + GPUCA_TPC_GEOMETRY_O2 GPUCA_HAVE_O2HEADERS) # cuda test, only compile if CUDA if(CUDA_ENABLED) @@ -54,7 +52,7 @@ endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_definitions(-DGPUCA_ALIROOT_LIB) - set(SRCS ${SRCS} GPUCommon.cxx) + set(SRCS ${SRCS} ../GPUTracking/utils/EmptyFile.cxx) # Add a library to the project using the specified source files add_library_tested(Ali${MODULE} SHARED ${SRCS}) @@ -73,7 +71,3 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") install(FILES ${HDRS_INSTALL} DESTINATION include) endif() - -if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - -endif() diff --git a/GPU/Common/GPUCommon.cxx b/GPU/Common/GPUCommon.cxx deleted file mode 100644 index 555ae492214d1..0000000000000 --- a/GPU/Common/GPUCommon.cxx +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUCommon.cxx -/// \author David Rohr - -// Empty file, needed for AliRoot diff --git a/GPU/Common/GPUCommonAlgorithm.h b/GPU/Common/GPUCommonAlgorithm.h index 4893eb99a07c2..933a4f509a897 100644 --- a/GPU/Common/GPUCommonAlgorithm.h +++ b/GPU/Common/GPUCommonAlgorithm.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -114,32 +115,37 @@ GPUdi() I GPUCommonAlgorithm::MedianOf3Select(I f, I l, Cmp cmp) noexcept --l; if (cmp(*f, *m)) { - if (cmp(*m, *l)) + if (cmp(*m, *l)) { return m; - else if (cmp(*f, *l)) + } else if (cmp(*f, *l)) { return l; - else + } else { return f; - } else if (cmp(*f, *l)) + } + } else if (cmp(*f, *l)) { return f; - else if (cmp(*m, *l)) + } else if (cmp(*m, *l)) { return l; - else + } else { return m; + } } template <typename I, typename T, typename Cmp> GPUdi() I GPUCommonAlgorithm::UnguardedPartition(I f, I l, T piv, Cmp cmp) noexcept { do { - while (cmp(*f, piv)) + while (cmp(*f, piv)) { ++f; + } --l; - while (cmp(piv, *l)) + while (cmp(piv, *l)) { --l; + } - if (l <= f) + if (l <= f) { return f; + } IterSwap(f, l); ++f; } while (true); @@ -148,10 +154,9 @@ GPUdi() I GPUCommonAlgorithm::UnguardedPartition(I f, I l, T piv, Cmp cmp) noexc template <typename I, typename Cmp> GPUdi() void GPUCommonAlgorithm::QuickSort(I f, I l, Cmp cmp) noexcept { - if (f == l) - + if (f == l) { return; - + } using IndexType = unsigned short; struct pair { @@ -186,15 +191,19 @@ GPUdi() void GPUCommonAlgorithm::QuickSort(I f, I l, Cmp cmp) noexcept const auto lsz = pp - it0; const auto rsz = it1 - pp; if (lsz < rsz) { - if (rsz > cutoff) + if (rsz > cutoff) { s.emplace(pp - f, it1 - f); - if (lsz > cutoff) + } + if (lsz > cutoff) { s.emplace(it0 - f, pp - f); + } } else { - if (lsz > cutoff) + if (lsz > cutoff) { s.emplace(it0 - f, pp - f); - if (rsz > cutoff) + } + if (rsz > cutoff) { s.emplace(pp - f, it1 - f); + } } } InsertionSort(f, l, cmp); @@ -335,7 +344,7 @@ GPUdi() void GPUCommonAlgorithm::swap(T& a, T& b) #elif (defined(__CUDACC__) || defined(__HIPCC__)) // CUDA and HIP work the same way using cub, need just different header -#ifndef GPUCA_GPUCODE_GENRTC +#if !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_HOSTONLY) #if defined(__CUDACC__) #include <cub/cub.cuh> #elif defined(__HIPCC__) diff --git a/GPU/Common/GPUCommonAlgorithmThrust.h b/GPU/Common/GPUCommonAlgorithmThrust.h index b4fdfacde3d85..053c42f2fa3f8 100644 --- a/GPU/Common/GPUCommonAlgorithmThrust.h +++ b/GPU/Common/GPUCommonAlgorithmThrust.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #ifndef GPUCOMMONALGORITHMTHRUST_H #define GPUCOMMONALGORITHMTHRUST_H -#ifndef GPUCA_GPUCODE_GENRTC +#if !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_HOSTONLY) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #include <thrust/sort.h> diff --git a/GPU/Common/GPUCommonArray.h b/GPU/Common/GPUCommonArray.h new file mode 100644 index 0000000000000..f37483af0737d --- /dev/null +++ b/GPU/Common/GPUCommonArray.h @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUCommonArray.h +/// \author David Rohr + +#ifndef GPUCOMMONARRAY_H +#define GPUCOMMONARRAY_H + +#ifndef GPUCA_GPUCODE_DEVICE +#include <array> +#endif + +#include "GPUCommonDef.h" +namespace o2::gpu::gpustd +{ +#ifdef GPUCA_GPUCODE_DEVICE +template <typename T, size_t N> +struct array { + GPUd() T& operator[](size_t i) { return m_internal_V__[i]; }; + GPUd() const T& operator[](size_t i) const { return m_internal_V__[i]; }; + GPUd() T* data() { return m_internal_V__; }; + GPUd() const T* data() const { return m_internal_V__; }; + T m_internal_V__[N]; +}; +template <class T, class... E> +GPUd() array(T, E...)->array<T, 1 + sizeof...(E)>; +#else +template <typename T, size_t N> +using array = std::array<T, N>; +#endif +} // namespace o2::gpu::gpustd + +#endif diff --git a/GPU/Common/GPUCommonDef.h b/GPU/Common/GPUCommonDef.h index 73c576144faf7..592e88c8e8337 100644 --- a/GPU/Common/GPUCommonDef.h +++ b/GPU/Common/GPUCommonDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,17 +57,14 @@ #define CONSTEXPR constexpr #define CONSTEXPRRET CONSTEXPR #if defined(__cplusplus) && __cplusplus >= 201703L - #define CONSTEXPRIF if constexpr #define CONSTEXPR17 constexpr #else - #define CONSTEXPRIF if #define CONSTEXPR17 #endif #else #define CON_DELETE #define CON_DEFAULT #define CONSTEXPR const - #define CONSTEXPRIF if #define CONSTEXPR17 #define CONSTEXPRRET #endif @@ -77,7 +75,7 @@ #endif //Set AliRoot / O2 namespace -#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_ALIROOT_LIB) || defined(GPUCA_GPULIBRARY) +#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_ALIROOT_LIB) || defined(GPUCA_GPULIBRARY) || defined (GPUCA_GPUCODE) #define GPUCA_ALIGPUCODE #endif #ifdef GPUCA_ALIROOT_LIB diff --git a/GPU/Common/GPUCommonDefAPI.h b/GPU/Common/GPUCommonDefAPI.h index 576d03cd897a1..9b66447201d76 100644 --- a/GPU/Common/GPUCommonDefAPI.h +++ b/GPU/Common/GPUCommonDefAPI.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -171,7 +172,7 @@ #define GPUshared() __shared__ #define GPUglobal() #define GPUconstant() __constant__ - #define GPUconstexpr() __constant__ + #define GPUconstexpr() constexpr __constant__ #define GPUprivate() #define GPUgeneric() #define GPUbarrier() __syncthreads() @@ -228,5 +229,5 @@ #define get_group_id(dim) iBlock #endif - // clang-format on + // clang-format on #endif diff --git a/GPU/Common/GPUCommonDefSettings.h b/GPU/Common/GPUCommonDefSettings.h index ca5bc3b9030a4..931eeceabde79 100644 --- a/GPU/Common/GPUCommonDefSettings.h +++ b/GPU/Common/GPUCommonDefSettings.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/Common/GPUCommonLogger.h b/GPU/Common/GPUCommonLogger.h index 6c0c851a1c82c..8e572ae96c1ef 100644 --- a/GPU/Common/GPUCommonLogger.h +++ b/GPU/Common/GPUCommonLogger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,13 +15,29 @@ #ifndef GPUCOMMONFAIRLOGGER_H #define GPUCOMMONFAIRLOGGER_H +#include "GPUCommonDef.h" + +#if defined(GPUCA_GPUCODE_DEVICE) || defined(__HIPCC__) +namespace o2::gpu::detail +{ +struct DummyLogger { + template <typename... Args> + GPUhd() DummyLogger& operator<<(Args... args) + { + return *this; + } +}; +} // namespace o2::gpu::detail +#endif + #if defined(__OPENCL__) -#define LOG(...) +#define LOG(...) o2::gpu::detail::DummyLogger() #define LOGF(...) #define LOGP(...) -#elif defined(GPUCA_GPUCODE_DEVICE) -#define LOG(...) static_assert("LOG(...) << ... unsupported in GPU code"); +#elif defined(GPUCA_GPUCODE_DEVICE) || defined(__HIPCC__) +#define LOG(...) o2::gpu::detail::DummyLogger() +//#define LOG(...) static_assert(false, "LOG(...) << ... unsupported in GPU code"); #define LOGF(type, string, ...) \ { \ printf(string "\n", ##__VA_ARGS__); \ diff --git a/GPU/Common/GPUCommonMath.h b/GPU/Common/GPUCommonMath.h index b82e430f807a3..6e8d438cb4a1c 100644 --- a/GPU/Common/GPUCommonMath.h +++ b/GPU/Common/GPUCommonMath.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,7 @@ #include "GPUCommonDef.h" -#if defined(__CUDACC__) && !defined(__clang__) && !defined(GPUCA_GPUCODE_GENRTC) +#if defined(__CUDACC__) && !defined(__clang__) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_HOSTONLY) #include <sm_20_atomic_functions.h> #endif @@ -57,18 +58,19 @@ class GPUCommonMath template <class T> GPUhd() static T Abs(T x); GPUd() static float ASin(float x); + GPUd() static float ACos(float x); GPUd() static float ATan(float x); GPUd() static float ATan2(float y, float x); GPUd() static float Sin(float x); GPUd() static float Cos(float x); GPUhdni() static void SinCos(float x, float& s, float& c); - GPUhdni() static void SinCos(double x, double& s, double& c); + GPUhdni() static void SinCosd(double x, double& s, double& c); GPUd() static float Tan(float x); GPUhdni() static float Copysign(float x, float y); - GPUhdni() static double Copysign(double x, double y); - GPUd() static float TwoPi() { return 6.28319f; } - GPUd() static float Pi() { return 3.1415926535897f; } + GPUd() static float TwoPi() { return 6.2831853f; } + GPUd() static float Pi() { return 3.1415927f; } GPUd() static int Nint(float x); + GPUd() static float Modf(float x, float y); GPUd() static bool Finite(float x); GPUd() static unsigned int Clz(unsigned int val); GPUd() static unsigned int Popcount(unsigned int val); @@ -148,14 +150,20 @@ class GPUCommonMath GPUd() CONSTEXPR17 static T nextMultipleOf(T val); #ifdef GPUCA_NOCOMPAT + GPUdi() static float Sum2() // Needed for legacy C++, For >=17 the below if constexpr handles the case + { + return 0.f; + } + template <typename... Args> GPUdi() static float Sum2(float w, Args... args) { - if constexpr (sizeof...(Args) == 0) { + if CONSTEXPR17 (sizeof...(Args) == 0) { return w * w; } else { return w * w + Sum2(args...); } + return 0; } #endif @@ -174,6 +182,7 @@ class GPUCommonMath typedef GPUCommonMath CAMath; +// CHOICE Syntax: CHOISE(Host, CUDA&HIP, OpenCL) #if defined(GPUCA_GPUCODE_DEVICE) && (defined(__CUDACC__) || defined(__HIPCC__)) // clang-format off #define CHOICE(c1, c2, c3) (c2) // Select second option for CUDA and HIP #elif defined(GPUCA_GPUCODE_DEVICE) && defined (__OPENCL__) @@ -185,16 +194,13 @@ typedef GPUCommonMath CAMath; template <int I, class T> GPUdi() CONSTEXPR17 T GPUCommonMath::nextMultipleOf(T val) { - CONSTEXPRIF(I & (I - 1)) - { + if CONSTEXPR17 (I & (I - 1)) { T tmp = val % I; if (tmp) { val += I - tmp; } return val; - } - else - { + } else { return (val + I - 1) & ~(T)(I - 1); } return 0; // BUG: Cuda complains about missing return value with constexpr if @@ -227,6 +233,8 @@ GPUdi() int GPUCommonMath::Nint(float x) return i; } +GPUdi() float GPUCommonMath::Modf(float x, float y) { return CHOICE(fmodf(x, y), fmodf(x, y), fmod(x, y)); } + GPUdi() bool GPUCommonMath::Finite(float x) { return CHOICE(std::isfinite(x), true, true); } GPUdi() float GPUCommonMath::ATan(float x) { return CHOICE(atanf(x), atanf(x), atan(x)); } @@ -248,7 +256,7 @@ GPUhdi() void GPUCommonMath::SinCos(float x, float& s, float& c) #endif } -GPUhdi() void GPUCommonMath::SinCos(double x, double& s, double& c) +GPUhdi() void GPUCommonMath::SinCosd(double x, double& s, double& c) { #if !defined(GPUCA_GPUCODE_DEVICE) && defined(__APPLE__) __sincos(x, &s, &c); @@ -267,7 +275,7 @@ GPUdi() unsigned int GPUCommonMath::Clz(unsigned int x) return x == 0 ? 32 : CHOICE(__builtin_clz(x), __clz(x), __builtin_clz(x)); // use builtin if available #else for (int i = 31; i >= 0; i--) { - if (x & (1 << i)) { + if (x & (1u << i)) { return (31 - i); } } @@ -278,15 +286,12 @@ GPUdi() unsigned int GPUCommonMath::Clz(unsigned int x) GPUdi() unsigned int GPUCommonMath::Popcount(unsigned int x) { #if (defined(__GNUC__) || defined(__clang__) || defined(__CUDACC__) || defined(__HIPCC__)) && (!defined(__OPENCL__) /*|| defined(__OPENCLCPP__)*/) // TODO: remove OPENCLCPP workaround when reported SPIR-V bug is fixed - return CHOICE(__builtin_popcount(x), __popc(x), __builtin_popcount(x)); // use builtin if available + // use builtin if available + return CHOICE(__builtin_popcount(x), __popc(x), __builtin_popcount(x)); #else - unsigned int retVal = 0; - for (int i = 0; i < 32; i++) { - if (x & (1 << i)) { - retVal++; - } - } - return retVal; + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; #endif } @@ -382,6 +387,8 @@ GPUhdi() int GPUCommonMath::Abs<int>(int x) GPUdi() float GPUCommonMath::ASin(float x) { return CHOICE(asinf(x), asinf(x), asin(x)); } +GPUdi() float GPUCommonMath::ACos(float x) { return CHOICE(acosf(x), acosf(x), acos(x)); } + GPUdi() float GPUCommonMath::Log(float x) { return CHOICE(logf(x), logf(x), log(x)); } GPUhdi() float GPUCommonMath::Copysign(float x, float y) @@ -398,20 +405,6 @@ GPUhdi() float GPUCommonMath::Copysign(float x, float y) #endif // GPUCA_GPUCODE } -GPUhdi() double GPUCommonMath::Copysign(double x, double y) -{ -#if defined(__OPENCLCPP__) - return copysign(x, y); -#elif defined(GPUCA_GPUCODE) && !defined(__OPENCL__) - return copysignf(x, y); -#elif defined(__cplusplus) && __cplusplus >= 201103L - return std::copysign(x, y); -#else - x = GPUCommonMath::Abs(x); - return (y >= 0) ? x : -x; -#endif // GPUCA_GPUCODE -} - template <class S, class T> GPUdi() unsigned int GPUCommonMath::AtomicExchInt(S* addr, T val) { diff --git a/GPU/Common/GPUCommonRtypes.h b/GPU/Common/GPUCommonRtypes.h index e03108f3e12c6..3f82529d4d1fb 100644 --- a/GPU/Common/GPUCommonRtypes.h +++ b/GPU/Common/GPUCommonRtypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_GPULIBRARY) // clang-format off #if !defined(ROOT_Rtypes) && !defined(__CLING__) + #define GPUCOMMONRTYPES_H_ACTIVE #define ClassDef(name,id) #define ClassDefNV(name, id) #define ClassDefOverride(name, id) diff --git a/GPU/Common/GPUCommonTransform3D.h b/GPU/Common/GPUCommonTransform3D.h index 7497dc99932fd..0d64e89041dfb 100644 --- a/GPU/Common/GPUCommonTransform3D.h +++ b/GPU/Common/GPUCommonTransform3D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/Common/GPUCommonTypeTraits.h b/GPU/Common/GPUCommonTypeTraits.h new file mode 100644 index 0000000000000..4ace82a415c14 --- /dev/null +++ b/GPU/Common/GPUCommonTypeTraits.h @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUCommonTypeTraits.h +/// \author David Rohr + +#ifndef GPUCOMMONTYPETRAITS_H +#define GPUCOMMONTYPETRAITS_H + +#if !defined(GPUCA_GPUCODE_DEVICE) || defined(__CUDACC__) || defined(__HIPCC__) +#ifndef GPUCA_GPUCODE_GENRTC +#include <type_traits> +#endif +#elif !defined(__OPENCL__) || defined(__OPENCLCPP__) +// We just reimplement some type traits in std for the GPU +namespace std +{ +template <bool B, class T, class F> +struct conditional { + typedef T type; +}; +template <class T, class F> +struct conditional<false, T, F> { + typedef F type; +}; +template <bool B, class T, class F> +using contitional_t = typename conditional<B, T, F>::type; +template <class T, class U> +struct is_same { + static constexpr bool value = false; +}; +template <class T> +struct is_same<T, T> { + static constexpr bool value = true; +}; +template <class T, class U> +static constexpr bool is_same_v = is_same<T, U>::value; +template <bool B, class T = void> +struct enable_if { +}; +template <class T> +struct enable_if<true, T> { + typedef T type; +}; +template <class T> +struct remove_cv { + typedef T type; +}; +template <class T> +struct remove_cv<const T> { + typedef T type; +}; +template <class T> +struct remove_cv<volatile T> { + typedef T type; +}; +template <class T> +struct remove_cv<const volatile T> { + typedef T type; +}; +template <class T> +struct remove_const { + typedef T type; +}; +template <class T> +struct remove_const<const T> { + typedef T type; +}; +template <class T> +struct remove_volatile { + typedef T type; +}; +template <class T> +struct remove_volatile<volatile T> { + typedef T type; +}; +template <class T> +struct is_pointer_t { + static constexpr bool value = false; +}; +template <class T> +struct is_pointer_t<T*> { + static constexpr bool value = true; +}; +template <class T> +struct is_pointer : is_pointer_t<typename std::remove_cv<T>::type> { +}; +} // namespace std +#endif + +#endif diff --git a/GPU/Common/GPUROOTCartesianFwd.h b/GPU/Common/GPUROOTCartesianFwd.h index dd8b9b53bbcb8..7810bc6a33abe 100644 --- a/GPU/Common/GPUROOTCartesianFwd.h +++ b/GPU/Common/GPUROOTCartesianFwd.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,7 +59,7 @@ template <typename T, int I> struct GPUPoint3D; } // namespace detail -#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) +#if (!defined(GPUCA_STANDALONE) || !defined(DGPUCA_NO_ROOT)) && !defined(GPUCA_GPUCODE) && !defined(GPUCOMMONRTYPES_H_ACTIVE) template <typename T> using Point2D = ROOT::Math::PositionVector2D<ROOT::Math::Cartesian2D<T>, ROOT::Math::DefaultCoordinateSystemTag>; template <typename T> diff --git a/GPU/Common/GPUROOTSMatrixFwd.h b/GPU/Common/GPUROOTSMatrixFwd.h new file mode 100644 index 0000000000000..84047538cb912 --- /dev/null +++ b/GPU/Common/GPUROOTSMatrixFwd.h @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUROOTSMatrixFwd.h +/// \author Matteo Concas + +#ifndef GPUROOTSMATRIXFWD_H +#define GPUROOTSMATRIXFWD_H + +// Standalone forward declarations for Svector / SMatrix / etc. +// To be used on GPU where ROOT is not available. + +#include "GPUCommonDef.h" + +namespace ROOT +{ +namespace Math +{ +template <typename T, unsigned int N> +class SVector; +template <class T, unsigned int D1, unsigned int D2, class R> +class SMatrix; +template <class T, unsigned int D> +class MatRepSym; +template <class T, unsigned int D1, unsigned int D2> +class MatRepStd; +} // namespace Math +} // namespace ROOT + +namespace o2 +{ +namespace math_utils +{ + +namespace detail +{ +template <typename T, unsigned int N> +class SVectorGPU; +template <class T, unsigned int D> +class MatRepSymGPU; +template <class T, unsigned int D1, unsigned int D2> +class MatRepStdGPU; +template <class T, unsigned int D1, unsigned int D2, class R> +class SMatrixGPU; +} // namespace detail + +#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) +template <typename T, unsigned int N> +using SVector = ROOT::Math::SVector<T, N>; +template <class T, unsigned int D1, unsigned int D2, class R> +using SMatrix = ROOT::Math::SMatrix<T, D1, D2, R>; +template <class T, unsigned int D> +using MatRepSym = ROOT::Math::MatRepSym<T, D>; +template <class T, unsigned int D1, unsigned int D2> +using MatRepStd = ROOT::Math::MatRepStd<T, D1, D2>; +#else +template <typename T, unsigned int N> +using SVector = detail::SVectorGPU<T, N>; +template <class T, unsigned int D> +using MatRepSym = detail::MatRepSymGPU<T, D>; +template <class T, unsigned int D1, unsigned int D2 = D1> +using MatRepStd = detail::MatRepStdGPU<T, D1, D2>; +template <class T, unsigned int D1, unsigned int D2 = D1, class R = detail::MatRepStdGPU<T, D1, D2>> +using SMatrix = detail::SMatrixGPU<T, D1, D2, R>; +#endif + +} // namespace math_utils +} // namespace o2 + +#endif diff --git a/GPU/Common/test/testGPUsortCUDA.cu b/GPU/Common/test/testGPUsortCUDA.cu index e6bd5206cbec9..4ed905032c7d5 100644 --- a/GPU/Common/test/testGPUsortCUDA.cu +++ b/GPU/Common/test/testGPUsortCUDA.cu @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUConstantMem.h b/GPU/GPUTracking/Base/GPUConstantMem.h index 115e957ee08b1..4658a484327cd 100644 --- a/GPU/GPUTracking/Base/GPUConstantMem.h +++ b/GPU/GPUTracking/Base/GPUConstantMem.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,11 +43,12 @@ class GPUTRDTracker_t #endif // Dummies for stuff not suppored in legacy code, or for what requires O2 headers while not available -#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPULIBRARY) || !defined(GPUCA_ALIROOT_LIB)) && defined(HAVE_O2HEADERS) +#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPULIBRARY) || !defined(GPUCA_ALIROOT_LIB)) && defined(GPUCA_HAVE_O2HEADERS) #include "GPUTPCConvert.h" #include "GPUTPCCompression.h" #include "GPUITSFitter.h" #include "GPUTPCClusterFinder.h" +#include "GPUTrackingRefit.h" #else #include "GPUO2FakeClasses.h" #endif @@ -68,9 +70,11 @@ struct GPUConstantMem { GPUTPCConvert tpcConverter; GPUTPCCompression tpcCompressor; GPUTPCGMMerger tpcMerger; - GPUTRDTrackerGPU trdTracker; + GPUTRDTrackerGPU trdTrackerGPU; + GPUTRDTracker trdTrackerO2; GPUTPCClusterFinder tpcClusterer[GPUCA_NSLICES]; GPUITSFitter itsFitter; + GPUTrackingRefitProcessor trackingRefit; GPUTrackingInOutPointers ioPtrs; GPUCalibObjectsConst calibObjects; GPUErrors errorCodes; @@ -95,6 +99,7 @@ union GPUConstantMemCopyable { #if defined(GPUCA_GPUCODE) && defined(GPUCA_NOCOMPAT) static constexpr size_t gGPUConstantMemBufferSize = (sizeof(GPUConstantMem) + sizeof(uint4) - 1); +#ifndef GPUCA_GPUCODE_HOSTONLY #if defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) } // namespace gpu } // namespace GPUCA_NAMESPACE @@ -103,16 +108,17 @@ namespace GPUCA_NAMESPACE { namespace gpu { -#endif +#endif // GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM #ifdef GPUCA_CONSTANT_AS_ARGUMENT static GPUConstantMemCopyable gGPUConstantMemBufferHost; -#endif +#endif // GPUCA_CONSTANT_AS_ARGUMENT +#endif // !GPUCA_GPUCODE_HOSTONLY #endif // Must be placed here, to avoid circular header dependency GPUdi() GPUconstantref() const MEM_CONSTANT(GPUParam) & GPUProcessor::Param() const { -#if defined(GPUCA_GPUCODE_DEVICE) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) +#if defined(GPUCA_GPUCODE_DEVICE) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) && !defined(GPUCA_GPUCODE_HOSTONLY) return GPUCA_CONSMEM.param; #else return mConstantMem->param; @@ -121,7 +127,7 @@ GPUdi() GPUconstantref() const MEM_CONSTANT(GPUParam) & GPUProcessor::Param() co GPUdi() GPUconstantref() const MEM_CONSTANT(GPUConstantMem) * GPUProcessor::GetConstantMem() const { -#if defined(GPUCA_GPUCODE_DEVICE) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) +#if defined(GPUCA_GPUCODE_DEVICE) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) && !defined(GPUCA_GPUCODE_HOSTONLY) return &GPUCA_CONSMEM; #else return mConstantMem; @@ -133,13 +139,6 @@ GPUdi() void GPUProcessor::raiseError(unsigned int code, unsigned int param1, un GetConstantMem()->errorCodes.raiseError(code, param1, param2, param3); } -#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPULIBRARY) || !defined(GPUCA_ALIROOT_LIB)) && defined(HAVE_O2HEADERS) -GPUd() float GPUTPCClusterFinder::getGainCorrection(tpccf::Row row, tpccf::Pad pad) const -{ - return GetConstantMem()->calibObjects.tpcCalibration->getGainCorrection(mISlice, row, pad); -} -#endif - } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Base/GPUDataTypes.cxx b/GPU/GPUTracking/Base/GPUDataTypes.cxx deleted file mode 100644 index ee50e12d95207..0000000000000 --- a/GPU/GPUTracking/Base/GPUDataTypes.cxx +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDataTypes.cxx -/// \author David Rohr - -#include "GPUDataTypes.h" -#include "GPUReconstruction.h" - -using namespace GPUCA_NAMESPACE::gpu; - -constexpr const char* const GPUDataTypes::RECO_STEP_NAMES[]; -constexpr const char* const GPUDataTypes::GENERAL_STEP_NAMES[]; - -GPUDataTypes::DeviceType GPUDataTypes::GetDeviceType(const char* type) { return GPUReconstruction::GetDeviceType(type); } diff --git a/GPU/GPUTracking/Base/GPUDataTypes.h b/GPU/GPUTracking/Base/GPUDataTypes.h deleted file mode 100644 index 521e5b737880e..0000000000000 --- a/GPU/GPUTracking/Base/GPUDataTypes.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDataTypes.h -/// \author David Rohr - -#ifndef GPUDATATYPES_H -#define GPUDATATYPES_H - -#include "GPUCommonDef.h" - -// These are basic and non-comprex data types, which will also be visible on the GPU. -// Please add complex data types required on the host but not GPU to GPUHostDataTypes.h and forward-declare! -#ifndef GPUCA_GPUCODE_DEVICE -#include <cstddef> -#ifdef GPUCA_NOCOMPAT_ALLOPENCL -#include <type_traits> -#endif -#endif -#ifdef GPUCA_NOCOMPAT -#include "GPUTRDDef.h" - -class AliHLTTPCClusterMCLabel; -struct AliHLTTPCRawCluster; -namespace o2 -{ -namespace tpc -{ -struct ClusterNativeAccess; -struct CompressedClustersFlat; -class Digit; -namespace constants -{ -} // namespace constants -} // namespace tpc -} // namespace o2 -#endif - -namespace o2 -{ -class MCCompLabel; -namespace base -{ -class MatLayerCylSet; -} // namespace base -namespace trd -{ -class GeometryFlat; -} // namespace trd -namespace dataformats -{ -template <class T> -class MCTruthContainer; -template <class T> -class ConstMCTruthContainerView; -} // namespace dataformats -} // namespace o2 - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -class TPCFastTransform; -class TPCdEdxCalibrationSplines; -struct TPCCFCalibration; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -#ifdef GPUCA_NOCOMPAT_ALLOPENCL -#include "utils/bitfield.h" -#define ENUM_CLASS class -#define ENUM_UINT : unsigned int -#define GPUCA_RECO_STEP GPUDataTypes::RecoStep -#else -#define ENUM_CLASS -#define ENUM_UINT -#define GPUCA_RECO_STEP GPUDataTypes -#endif - -#if defined(__OPENCL__) && !defined(__OPENCLCPP__) -MEM_CLASS_PRE() // Macro with some template magic for OpenCL 1.2 -#endif -class GPUTPCTrack; -class GPUTPCHitId; -class GPUTPCGMMergedTrack; -struct GPUTPCGMMergedTrackHit; -struct GPUTPCGMMergedTrackHitXYZ; -class GPUTRDTrackletWord; -class GPUTPCMCInfo; -struct GPUTPCClusterData; -struct GPUTRDTrackletLabels; -struct GPUTPCDigitsMCInput; - -class GPUDataTypes -{ - public: - enum ENUM_CLASS GeometryType ENUM_UINT{RESERVED_GEOMETRY = 0, ALIROOT = 1, O2 = 2}; - enum DeviceType ENUM_UINT { INVALID_DEVICE = 0, - CPU = 1, - CUDA = 2, - HIP = 3, - OCL = 4, - OCL2 = 5 }; - enum ENUM_CLASS GeneralStep { Prepare = 1, - QA = 2 }; - - enum ENUM_CLASS RecoStep { TPCConversion = 1, - TPCSliceTracking = 2, - TPCMerging = 4, - TPCCompression = 8, - TRDTracking = 16, - ITSTracking = 32, - TPCdEdx = 64, - TPCClusterFinding = 128, - TPCDecompression = 256, - Refit = 512, - AllRecoSteps = 0x7FFFFFFF, - NoRecoStep = 0 }; - enum ENUM_CLASS InOutType { TPCClusters = 1, - TPCSectorTracks = 2, - TPCMergedTracks = 4, - TPCCompressedClusters = 8, - TRDTracklets = 16, - TRDTracks = 32, - TPCRaw = 64 }; - -#ifdef GPUCA_NOCOMPAT_ALLOPENCL - static constexpr const char* const RECO_STEP_NAMES[] = {"TPC Transformation", "TPC Sector Tracking", "TPC Track Merging and Fit", "TPC Compression", "TRD Tracking", "ITS Tracking", "TPC dEdx Computation", "TPC Cluster Finding", "TPC Decompression"}; - static constexpr const char* const GENERAL_STEP_NAMES[] = {"Prepare", "QA"}; - typedef bitfield<RecoStep, unsigned int> RecoStepField; - typedef bitfield<InOutType, unsigned int> InOutTypeField; - constexpr static int N_RECO_STEPS = sizeof(GPUDataTypes::RECO_STEP_NAMES) / sizeof(GPUDataTypes::RECO_STEP_NAMES[0]); - constexpr static int N_GENERAL_STEPS = sizeof(GPUDataTypes::GENERAL_STEP_NAMES) / sizeof(GPUDataTypes::GENERAL_STEP_NAMES[0]); -#endif -#ifdef GPUCA_NOCOMPAT - static constexpr unsigned int NSLICES = 36; -#endif - static DeviceType GetDeviceType(const char* type); -}; - -#ifdef GPUCA_NOCOMPAT_ALLOPENCL -struct GPURecoStepConfiguration { - GPUDataTypes::RecoStepField steps = 0; - GPUDataTypes::RecoStepField stepsGPUMask = GPUDataTypes::RecoStep::AllRecoSteps; - GPUDataTypes::InOutTypeField inputs = 0; - GPUDataTypes::InOutTypeField outputs = 0; -}; -#endif - -#ifdef GPUCA_NOCOMPAT - -template <class T> -struct DefaultPtr { - typedef T type; -}; -template <class T> -struct ConstPtr { - typedef const T type; -}; - -template <template <typename T> class S> -struct GPUCalibObjectsTemplate { - typename S<TPCFastTransform>::type* fastTransform = nullptr; - typename S<o2::base::MatLayerCylSet>::type* matLUT = nullptr; - typename S<o2::trd::GeometryFlat>::type* trdGeometry = nullptr; - typename S<TPCdEdxCalibrationSplines>::type* dEdxSplines = nullptr; - typename S<TPCCFCalibration>::type* tpcCalibration = nullptr; -}; -typedef GPUCalibObjectsTemplate<DefaultPtr> GPUCalibObjects; -typedef GPUCalibObjectsTemplate<ConstPtr> GPUCalibObjectsConst; - -struct GPUTrackingInOutZS { - static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; - static constexpr unsigned int NENDPOINTS = 20; - struct GPUTrackingInOutZSSlice { - const void* const* zsPtr[NENDPOINTS]; - const unsigned int* nZSPtr[NENDPOINTS]; - unsigned int count[NENDPOINTS]; - }; - struct GPUTrackingInOutZSCounts { - unsigned int count[NSLICES][NENDPOINTS] = {}; - }; - struct GPUTrackingInOutZSMeta { - void* ptr[NSLICES][NENDPOINTS]; - unsigned int n[NSLICES][NENDPOINTS]; - }; - GPUTrackingInOutZSSlice slice[NSLICES]; -}; - -struct GPUTrackingInOutDigits { - static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; - const o2::tpc::Digit* tpcDigits[NSLICES] = {nullptr}; - size_t nTPCDigits[NSLICES] = {0}; - GPUTPCDigitsMCInput* tpcDigitsMC; -}; - -struct GPUTrackingInOutPointers { - GPUTrackingInOutPointers() = default; - GPUTrackingInOutPointers(const GPUTrackingInOutPointers&) = default; - static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; - - const GPUTrackingInOutZS* tpcZS = nullptr; - const GPUTrackingInOutDigits* tpcPackedDigits = nullptr; - const GPUTPCClusterData* clusterData[NSLICES] = {nullptr}; - unsigned int nClusterData[NSLICES] = {0}; - const AliHLTTPCRawCluster* rawClusters[NSLICES] = {nullptr}; - unsigned int nRawClusters[NSLICES] = {0}; - const o2::tpc::ClusterNativeAccess* clustersNative = nullptr; - const GPUTPCTrack* sliceTracks[NSLICES] = {nullptr}; - unsigned int nSliceTracks[NSLICES] = {0}; - const GPUTPCHitId* sliceClusters[NSLICES] = {nullptr}; - unsigned int nSliceClusters[NSLICES] = {0}; - const AliHLTTPCClusterMCLabel* mcLabelsTPC = nullptr; - unsigned int nMCLabelsTPC = 0; - const GPUTPCMCInfo* mcInfosTPC = nullptr; - unsigned int nMCInfosTPC = 0; - const GPUTPCGMMergedTrack* mergedTracks = nullptr; - unsigned int nMergedTracks = 0; - const GPUTPCGMMergedTrackHit* mergedTrackHits = nullptr; - const GPUTPCGMMergedTrackHitXYZ* mergedTrackHitsXYZ = nullptr; - unsigned int nMergedTrackHits = 0; - unsigned int* mergedTrackHitAttachment = nullptr; - unsigned char* mergedTrackHitStates = nullptr; - const o2::tpc::CompressedClustersFlat* tpcCompressedClusters = nullptr; - const GPUTRDTrackletWord* trdTracklets = nullptr; - unsigned int nTRDTracklets = 0; - const GPUTRDTrackletLabels* trdTrackletsMC = nullptr; - unsigned int nTRDTrackletsMC = 0; - const GPUTRDTrackGPU* trdTracks = nullptr; - unsigned int nTRDTracks = 0; -}; -#else -struct GPUTrackingInOutPointers { -}; -struct GPUCalibObjectsConst { -}; -#endif - -#undef ENUM_CLASS -#undef ENUM_UINT -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Base/GPUGeneralKernels.cxx b/GPU/GPUTracking/Base/GPUGeneralKernels.cxx index 72386bb9c4836..519319292abd2 100644 --- a/GPU/GPUTracking/Base/GPUGeneralKernels.cxx +++ b/GPU/GPUTracking/Base/GPUGeneralKernels.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUMemClean16::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, processorType& GPUrestrict() processors, GPUglobalref() void* ptr, unsigned long size) +GPUdii() void GPUMemClean16::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, processorType& GPUrestrict() processors, GPUglobalref() void* ptr, unsigned long size) { const unsigned long stride = get_global_size(0); int4 i0; diff --git a/GPU/GPUTracking/Base/GPUGeneralKernels.h b/GPU/GPUTracking/Base/GPUGeneralKernels.h index 250a0420ad19f..b15dfe29d712b 100644 --- a/GPU/GPUTracking/Base/GPUGeneralKernels.h +++ b/GPU/GPUTracking/Base/GPUGeneralKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,20 +18,18 @@ #include "GPUDef.h" #include "GPUDataTypes.h" -#if defined(__HIPCC__) -#define GPUCA_CUB hipcub -#else -#define GPUCA_CUB cub -#endif - -#ifndef GPUCA_GPUCODE_GENRTC -#ifdef GPUCA_GPUCODE -#ifdef __CUDACC__ +#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_HOSTONLY) +#if defined(__CUDACC__) #include <cub/cub.cuh> #elif defined(__HIPCC__) #include <hipcub/hipcub.hpp> #endif #endif + +#if defined(__HIPCC__) +#define GPUCA_CUB hipcub +#else +#define GPUCA_CUB cub #endif namespace GPUCA_NAMESPACE @@ -58,7 +57,7 @@ class GPUKernelTemplate template <class T, int I> struct GPUSharedMemoryScan64 { // Provides the shared memory resources for CUB collectives -#if (defined(__CUDACC__) || defined(__HIPCC__)) && defined(GPUCA_GPUCODE) +#if (defined(__CUDACC__) || defined(__HIPCC__)) && defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_HOSTONLY) typedef GPUCA_CUB::BlockScan<T, I> BlockScan; typedef GPUCA_CUB::BlockReduce<T, I> BlockReduce; typedef GPUCA_CUB::WarpScan<T> WarpScan; diff --git a/GPU/GPUTracking/Base/GPUKernelDebugOutput.cxx b/GPU/GPUTracking/Base/GPUKernelDebugOutput.cxx index d69e7d96123c0..be4207abc75d3 100644 --- a/GPU/GPUTracking/Base/GPUKernelDebugOutput.cxx +++ b/GPU/GPUTracking/Base/GPUKernelDebugOutput.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUKernelDebugOutput.h b/GPU/GPUTracking/Base/GPUKernelDebugOutput.h index 494bf928c0893..86c66fa488fc5 100644 --- a/GPU/GPUTracking/Base/GPUKernelDebugOutput.h +++ b/GPU/GPUTracking/Base/GPUKernelDebugOutput.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUMemoryResource.cxx b/GPU/GPUTracking/Base/GPUMemoryResource.cxx index f376463a1b7cd..ccc912fe6c036 100644 --- a/GPU/GPUTracking/Base/GPUMemoryResource.cxx +++ b/GPU/GPUTracking/Base/GPUMemoryResource.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUMemoryResource.h b/GPU/GPUTracking/Base/GPUMemoryResource.h index 101710ce0afaf..0d73da0f8b5f7 100644 --- a/GPU/GPUTracking/Base/GPUMemoryResource.h +++ b/GPU/GPUTracking/Base/GPUMemoryResource.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -84,18 +85,16 @@ class GPUMemoryResource GPUMemoryResource(const GPUMemoryResource&) CON_DEFAULT; #endif -#ifndef __OPENCL__ void* SetPointers(void* ptr) { return (mProcessor->*mSetPointers)(ptr); } - void* SetDevicePointers(void* ptr) { return (mProcessor->mDeviceProcessor->*mSetPointers)(ptr); } + void* SetDevicePointers(void* ptr) { return (mProcessor->mLinkedProcessor->*mSetPointers)(ptr); } void* Ptr() { return mPtr; } void* PtrDevice() { return mPtrDevice; } size_t Size() const { return mSize; } const char* Name() const { return mName; } MemoryType Type() const { return mType; } -#endif private: GPUProcessor* mProcessor; diff --git a/GPU/GPUTracking/Base/GPUMemorySizeScalers.h b/GPU/GPUTracking/Base/GPUMemorySizeScalers.h deleted file mode 100644 index 24f7d6b97de6b..0000000000000 --- a/GPU/GPUTracking/Base/GPUMemorySizeScalers.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUMemorySizeScalers.h -/// \author David Rohr - -#ifndef O2_GPU_GPUMEMORYSIZESCALERS_H -#define O2_GPU_GPUMEMORYSIZESCALERS_H - -#include "GPUDef.h" - -namespace GPUCA_NAMESPACE::gpu -{ - -struct GPUMemorySizeScalers { - // Input sizes - size_t nTPCdigits = 0; - size_t nTPCHits = 0; - size_t nTRDTracklets = 0; - size_t nITSTracks = 0; - - // General scaling factor - double factor = 1; - - // Offset - double offset = 1000.; - double hitOffset = 20000; - - // Scaling Factors - double tpcPeaksPerDigit = 0.2; - double tpcClustersPerPeak = 0.9; - double tpcStartHitsPerHit = 0.08; - double tpcTrackletsPerStartHit = 0.8; - double tpcTrackletHitsPerHit = 5; - double tpcSectorTracksPerHit = 0.02; - double tpcSectorTrackHitsPerHit = 0.8f; - double tpcMergedTrackPerSliceTrack = 0.9; - double tpcMergedTrackHitPerSliceHit = 1.1; - - // Upper limits - size_t tpcMaxPeaks = 1000000000; - size_t tpcMaxClusters = 620000000; - size_t tpcMaxStartHits = 1250000; - size_t tpcMaxRowStartHits = 1000000000; - size_t tpcMaxTracklets = 1000000; - size_t tpcMaxTrackletHits = 66000000; - size_t tpcMaxSectorTracks = 250000; - size_t tpcMaxSectorTrackHits = 11500000; - size_t tpcMaxMergedTracks = 5800000; - size_t tpcMaxMergedTrackHits = 380000000; - - size_t NTPCPeaks(size_t tpcDigits) { return std::min<size_t>(tpcMaxPeaks, hitOffset + tpcDigits * tpcPeaksPerDigit) * factor; } - size_t NTPCClusters(size_t tpcDigits) { return std::min<size_t>(tpcMaxClusters, tpcClustersPerPeak * NTPCPeaks(tpcDigits)) * factor; } - size_t NTPCStartHits(size_t tpcHits) { return std::min<size_t>(tpcMaxStartHits, offset + tpcHits * tpcStartHitsPerHit) * factor; } - size_t NTPCRowStartHits(size_t tpcHits) { return std::min<size_t>(tpcMaxRowStartHits, offset + NTPCStartHits(tpcHits) / GPUCA_ROW_COUNT * 4.) * factor; } - size_t NTPCTracklets(size_t tpcHits) { return std::min<size_t>(tpcMaxTracklets, NTPCStartHits(tpcHits) * tpcTrackletsPerStartHit) * factor; } - size_t NTPCTrackletHits(size_t tpcHits) { return std::min<size_t>(tpcMaxTrackletHits, hitOffset + tpcHits * tpcTrackletHitsPerHit) * factor; } - size_t NTPCSectorTracks(size_t tpcHits) { return std::min<size_t>(tpcMaxSectorTracks, offset + tpcHits * tpcSectorTracksPerHit) * factor; } - size_t NTPCSectorTrackHits(size_t tpcHits) { return std::min<size_t>(tpcMaxSectorTrackHits, offset + tpcHits * tpcSectorTrackHitsPerHit) * factor; } - size_t NTPCMergedTracks(size_t tpcSliceTracks) { return std::min<size_t>(tpcMaxMergedTracks, offset + tpcSliceTracks * tpcMergedTrackPerSliceTrack) * factor; } - size_t NTPCMergedTrackHits(size_t tpcSliceTrackHitss) { return std::min<size_t>(tpcMaxMergedTrackHits, offset + tpcSliceTrackHitss * tpcMergedTrackHitPerSliceHit) * factor; } -}; - -} // namespace GPUCA_NAMESPACE::gpu - -#endif diff --git a/GPU/GPUTracking/Base/GPUO2DataTypes.h b/GPU/GPUTracking/Base/GPUO2DataTypes.h deleted file mode 100644 index 8d359abf4b1d3..0000000000000 --- a/GPU/GPUTracking/Base/GPUO2DataTypes.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUO2DataTypes.h -/// \author David Rohr - -#ifndef O2_GPU_GPUO2DATATYPES_H -#define O2_GPU_GPUO2DATATYPES_H - -// Pull in several O2 headers with basic data types, or load a header with empty fake classes if O2 headers not available - -#if defined(HAVE_O2HEADERS) && (!defined(__OPENCL__) || defined(__OPENCLCPP__)) -#include "DataFormatsTPC/ClusterNative.h" -#include "DetectorsBase/MatLayerCylSet.h" -#include "TRDBase/GeometryFlat.h" -#else -#include "GPUO2FakeClasses.h" -#endif - -#if !defined(__OPENCL__) || defined(__OPENCLCPP__) -#include "GPUdEdxInfo.h" -#endif - -#endif diff --git a/GPU/GPUTracking/Base/GPUOutputControl.h b/GPU/GPUTracking/Base/GPUOutputControl.h deleted file mode 100644 index f9ff427fcf3e4..0000000000000 --- a/GPU/GPUTracking/Base/GPUOutputControl.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUOutputControl.h -/// \author David Rohr - -#ifndef GPUOUTPUTCONTROL_H -#define GPUOUTPUTCONTROL_H - -#include "GPUCommonDef.h" -#include <cstddef> -#include <functional> -#include <new> - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -struct GPUOutputControl { - enum OutputTypeStruct { AllocateInternal = 0, - UseExternalBuffer = 1 }; - GPUOutputControl() = default; - void set(void* ptr, size_t size) - { - new (this) GPUOutputControl; - OutputType = GPUOutputControl::UseExternalBuffer; - OutputBase = OutputPtr = (char*)ptr; - OutputMaxSize = size; - } - void set(const std::function<void*(size_t)>& allocator) - { - new (this) GPUOutputControl; - OutputType = GPUOutputControl::UseExternalBuffer; - OutputAllocator = allocator; - } - void reset() - { - new (this) GPUOutputControl; - } - - void* OutputBase = nullptr; // Base ptr to memory pool, occupied size is OutputPtr - OutputBase - void* OutputPtr = nullptr; // Pointer to Output Space - size_t OutputMaxSize = 0; // Max Size of Output Data if Pointer to output space is given - std::function<void*(size_t)> OutputAllocator = nullptr; // Allocator callback - OutputTypeStruct OutputType = AllocateInternal; // How to perform the output - char EndOfSpace = 0; // end of space flag -}; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index a338bc8202a6b..9b3196170043e 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "GPUCommonMath.h" #include "GPUTPCGMPolynomialFieldManager.h" #include "GPUDataTypes.h" +#include "GPUConstantMem.h" using namespace GPUCA_NAMESPACE::gpu; @@ -27,6 +29,9 @@ using namespace GPUCA_NAMESPACE::gpu; #endif #include <cstring> #include <tuple> +#ifdef GPUCA_HAVE_O2HEADERS +#include "DetectorsBase/Propagator.h" +#endif #include "utils/qconfigrtc.h" @@ -75,10 +80,10 @@ void GPUParam::SetDefaults(float solenoidBz) } } - par.DAlpha = 0.349066f; - par.BzkG = solenoidBz; + par.dAlpha = 0.349066f; + par.bzkG = solenoidBz; constexpr double kCLight = 0.000299792458f; - par.ConstBz = solenoidBz * kCLight; + par.constBz = solenoidBz * kCLight; par.dodEdx = 0; constexpr float plusZmin = 0.0529937; @@ -96,59 +101,59 @@ void GPUParam::SetDefaults(float solenoidBz) if (tmp >= GPUCA_NSLICES / 4) { tmp -= GPUCA_NSLICES / 2; } - SliceParam[i].Alpha = 0.174533 + par.DAlpha * tmp; + SliceParam[i].Alpha = 0.174533 + par.dAlpha * tmp; SliceParam[i].CosAlpha = CAMath::Cos(SliceParam[i].Alpha); SliceParam[i].SinAlpha = CAMath::Sin(SliceParam[i].Alpha); - SliceParam[i].AngleMin = SliceParam[i].Alpha - par.DAlpha / 2.f; - SliceParam[i].AngleMax = SliceParam[i].Alpha + par.DAlpha / 2.f; + SliceParam[i].AngleMin = SliceParam[i].Alpha - par.dAlpha / 2.f; + SliceParam[i].AngleMax = SliceParam[i].Alpha + par.dAlpha / 2.f; } - par.AssumeConstantBz = false; - par.ToyMCEventsFlag = false; - par.ContinuousTracking = false; + par.assumeConstantBz = false; + par.toyMCEventsFlag = false; + par.continuousTracking = false; par.continuousMaxTimeBin = 0; par.debugLevel = 0; par.resetTimers = false; par.earlyTpcTransform = false; polynomialField.Reset(); // set very wrong initial value in order to see if the field was not properly initialised - GPUTPCGMPolynomialFieldManager::GetPolynomialField(par.BzkG, polynomialField); + GPUTPCGMPolynomialFieldManager::GetPolynomialField(par.bzkG, polynomialField); } -void GPUParam::UpdateEventSettings(const GPUSettingsEvent* e, const GPUSettingsProcessing* p) +void GPUParam::UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) { - if (e) { - par.AssumeConstantBz = e->constBz; - par.ToyMCEventsFlag = e->homemadeEvents; - par.ContinuousTracking = e->continuousMaxTimeBin != 0; - par.continuousMaxTimeBin = e->continuousMaxTimeBin == -1 ? GPUSettings::TPC_MAX_TF_TIME_BIN : e->continuousMaxTimeBin; + if (g) { + par.assumeConstantBz = g->constBz; + par.toyMCEventsFlag = g->homemadeEvents; + par.continuousTracking = g->continuousMaxTimeBin != 0; + par.continuousMaxTimeBin = g->continuousMaxTimeBin == -1 ? GPUSettings::TPC_MAX_TF_TIME_BIN : g->continuousMaxTimeBin; polynomialField.Reset(); - if (par.AssumeConstantBz) { - GPUTPCGMPolynomialFieldManager::GetPolynomialField(GPUTPCGMPolynomialFieldManager::kUniform, par.BzkG, polynomialField); + if (par.assumeConstantBz) { + GPUTPCGMPolynomialFieldManager::GetPolynomialField(GPUTPCGMPolynomialFieldManager::kUniform, par.bzkG, polynomialField); } else { - GPUTPCGMPolynomialFieldManager::GetPolynomialField(par.BzkG, polynomialField); + GPUTPCGMPolynomialFieldManager::GetPolynomialField(par.bzkG, polynomialField); } } if (p) { par.debugLevel = p->debugLevel; par.resetTimers = p->resetTimers; } - par.earlyTpcTransform = rec.ForceEarlyTPCTransform == -1 ? (!par.ContinuousTracking) : rec.ForceEarlyTPCTransform; + par.earlyTpcTransform = rec.tpc.forceEarlyTransform == -1 ? (!par.continuousTracking) : rec.tpc.forceEarlyTransform; } -void GPUParam::SetDefaults(const GPUSettingsEvent* e, const GPUSettingsRec* r, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) +void GPUParam::SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) { - SetDefaults(e->solenoidBz); + SetDefaults(g->solenoidBz); if (w) { par.dodEdx = w->steps.isSet(GPUDataTypes::RecoStep::TPCdEdx); } if (r) { rec = *r; if (rec.fitPropagateBzOnly == -1) { - rec.fitPropagateBzOnly = rec.NWays - 1; + rec.fitPropagateBzOnly = rec.tpc.nWays - 1; } } - UpdateEventSettings(e, p); + UpdateGRPSettings(g, p); } #ifndef GPUCA_ALIROOT_LIB @@ -231,16 +236,34 @@ void GPUParam::LoadClusterErrors(bool Print) void GPUParamRTC::setFrom(const GPUParam& param) { - memcpy((char*)this + sizeof(gpu_rtc::GPUSettingsRec) + sizeof(gpu_rtc::GPUSettingsParam), (char*)¶m + sizeof(GPUSettingsRec) + sizeof(GPUSettingsParam), sizeof(param) - sizeof(GPUSettingsRec) - sizeof(GPUSettingsParam)); - qConfigConvertRtc(this->rec, param.rec); - qConfigConvertRtc(this->par, param.par); + memcpy((char*)this, (char*)¶m, sizeof(param)); } std::string GPUParamRTC::generateRTCCode(const GPUParam& param, bool useConstexpr) { - return "namespace o2::gpu { class GPUDisplayBackend; }\n" + qConfigPrintRtc(std::make_tuple(¶m.rec, ¶m.par), useConstexpr); + return "#ifndef GPUCA_GPUCODE_DEVICE\n" + "#include <string>\n" + "#endif\n" + "namespace o2::gpu { class GPUDisplayBackend; }\n" + + qConfigPrintRtc(std::make_tuple(¶m.rec.tpc, ¶m.rec.trd, ¶m.rec, ¶m.par), useConstexpr); } -static_assert(alignof(GPUCA_NAMESPACE::gpu::GPUParam) == alignof(GPUCA_NAMESPACE::gpu::GPUSettingsRec)); -static_assert(alignof(GPUCA_NAMESPACE::gpu::GPUParam) == alignof(GPUCA_NAMESPACE::gpu::GPUSettingsParam)); -static_assert(sizeof(GPUCA_NAMESPACE::gpu::GPUParam) - sizeof(GPUCA_NAMESPACE::gpu::GPUParamRTC) == sizeof(GPUCA_NAMESPACE::gpu::GPUSettingsRec) + sizeof(GPUCA_NAMESPACE::gpu::GPUSettingsParam) - sizeof(GPUCA_NAMESPACE::gpu::gpu_rtc::GPUSettingsRec) - sizeof(GPUCA_NAMESPACE::gpu::gpu_rtc::GPUSettingsParam)); +static_assert(sizeof(GPUCA_NAMESPACE::gpu::GPUParam) == sizeof(GPUCA_NAMESPACE::gpu::GPUParamRTC), "RTC param size mismatch"); + +o2::base::Propagator* GPUParam::GetDefaultO2Propagator(bool useGPUField) const +{ + o2::base::Propagator* prop = nullptr; +#ifdef GPUCA_HAVE_O2HEADERS + if (useGPUField == false) { + throw std::runtime_error("o2 propagator withouzt gpu field unsupported"); + } + prop = o2::base::Propagator::Instance(useGPUField); + if (useGPUField) { + prop->setGPUField(&polynomialField); + prop->setBz(polynomialField.GetNominalBz()); + } +#else + throw std::runtime_error("o2 propagator unsupported"); +#endif + return prop; +} diff --git a/GPU/GPUTracking/Base/GPUParam.h b/GPU/GPUTracking/Base/GPUParam.h index 3c92e1d09f7a2..c72b672aaaed9 100644 --- a/GPU/GPUTracking/Base/GPUParam.h +++ b/GPU/GPUTracking/Base/GPUParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,12 +22,21 @@ #include "GPUTPCGeometry.h" #include "GPUTPCGMPolynomialField.h" +#if !defined(GPUCA_GPUCODE) && defined(GPUCA_NOCOMPAT) +namespace o2::base +{ +template <typename> +class PropagatorImpl; +using Propagator = PropagatorImpl<float>; +} // namespace o2::base +#endif + namespace GPUCA_NAMESPACE { namespace gpu { struct GPUSettingsRec; -struct GPUSettingsEvent; +struct GPUSettingsGTP; struct GPURecoStepConfiguration; struct GPUParamSlice { @@ -54,14 +64,16 @@ struct GPUParam_t { }; } // namespace internal +#if !(defined(__CINT__) || defined(__ROOTCINT__)) || defined(__CLING__) // Hide from ROOT 5 CINT MEM_CLASS_PRE() struct GPUParam : public internal::GPUParam_t<GPUSettingsRec, GPUSettingsParam> { #ifndef GPUCA_GPUCODE void SetDefaults(float solenoidBz); - void SetDefaults(const GPUSettingsEvent* e, const GPUSettingsRec* r = nullptr, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); - void UpdateEventSettings(const GPUSettingsEvent* e, const GPUSettingsProcessing* p = nullptr); + void SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r = nullptr, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); + void UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); void LoadClusterErrors(bool Print = 0); + o2::base::Propagator* GetDefaultO2Propagator(bool useGPUField = false) const; #endif GPUd() float Alpha(int iSlice) const @@ -72,7 +84,7 @@ struct GPUParam : public internal::GPUParam_t<GPUSettingsRec, GPUSettingsParam> if (iSlice >= GPUCA_NSLICES / 4) { iSlice -= GPUCA_NSLICES / 2; } - return 0.174533f + par.DAlpha * iSlice; + return 0.174533f + par.dAlpha * iSlice; } GPUd() float GetClusterRMS(int yz, int type, float z, float angle2) const; GPUd() void GetClusterRMS2(int row, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const; @@ -84,6 +96,7 @@ struct GPUParam : public internal::GPUParam_t<GPUSettingsRec, GPUSettingsParam> GPUd() void Slice2Global(int iSlice, float x, float y, float z, float* X, float* Y, float* Z) const; GPUd() void Global2Slice(int iSlice, float x, float y, float z, float* X, float* Y, float* Z) const; }; +#endif } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index d269adea60bb0..cfcf224966051 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,8 +12,8 @@ /// \file GPUParam.inc /// \author David Rohr, Sergey Gorbunov -#ifndef GPUPARAM_INC -#define GPUPARAM_INC +#ifndef GPU_GPUPARAM_INC_H +#define GPU_GPUPARAM_INC_H #include "GPUParam.h" #include "GPUTPCGMMergedTrackHit.h" @@ -84,7 +85,7 @@ GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float z, floa if (v < 0.0001f) { v = 0.0001f; } - v *= yz ? rec.ClusterError2CorrectionZ : rec.ClusterError2CorrectionY; + v *= yz ? rec.tpc.clusterError2CorrectionZ : rec.tpc.clusterError2CorrectionY; return v; } diff --git a/GPU/GPUTracking/Base/GPUParamRTC.h b/GPU/GPUTracking/Base/GPUParamRTC.h index 2647d7152dbea..d7959a294854c 100644 --- a/GPU/GPUTracking/Base/GPUParamRTC.h +++ b/GPU/GPUTracking/Base/GPUParamRTC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUProcessor.cxx b/GPU/GPUTracking/Base/GPUProcessor.cxx index c6408f1d04530..46f065d3fceb6 100644 --- a/GPU/GPUTracking/Base/GPUProcessor.cxx +++ b/GPU/GPUTracking/Base/GPUProcessor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ using namespace GPUCA_NAMESPACE::gpu; -GPUProcessor::GPUProcessor() : mRec(nullptr), mGPUProcessorType(PROCESSOR_TYPE_CPU), mDeviceProcessor(nullptr), mConstantMem(nullptr), mAllocateAndInitializeLate(false) {} +GPUProcessor::GPUProcessor() : mRec(nullptr), mGPUProcessorType(PROCESSOR_TYPE_CPU), mLinkedProcessor(nullptr), mConstantMem(nullptr), mAllocateAndInitializeLate(false) {} GPUProcessor::~GPUProcessor() { @@ -31,7 +32,8 @@ void GPUProcessor::InitGPUProcessor(GPUReconstruction* rec, GPUProcessor::Proces mRec = rec; mGPUProcessorType = type; if (slaveProcessor) { - slaveProcessor->mDeviceProcessor = this; + slaveProcessor->mLinkedProcessor = this; + mLinkedProcessor = slaveProcessor; } rec->ConstructGPUProcessor(this); } diff --git a/GPU/GPUTracking/Base/GPUProcessor.h b/GPU/GPUTracking/Base/GPUProcessor.h index 4c45639cea051..0024ccd6febe6 100644 --- a/GPU/GPUTracking/Base/GPUProcessor.h +++ b/GPU/GPUTracking/Base/GPUProcessor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -59,6 +60,11 @@ class GPUProcessor #ifndef __OPENCL__ void InitGPUProcessor(GPUReconstruction* rec, ProcessorType type = PROCESSOR_TYPE_CPU, GPUProcessor* slaveProcessor = nullptr); void Clear(); + template <class T> + T& HostProcessor(T*) + { + return *(T*)(mGPUProcessorType == PROCESSOR_TYPE_DEVICE ? mLinkedProcessor : this); + } template <size_t alignment = GPUCA_BUFFER_ALIGNMENT> static inline size_t getAlignmentMod(size_t addr) @@ -138,7 +144,7 @@ class GPUProcessor GPUReconstruction* mRec; ProcessorType mGPUProcessorType; - GPUProcessor* mDeviceProcessor; + GPUProcessor* mLinkedProcessor; GPUconstantref() const MEM_CONSTANT(GPUConstantMem) * mConstantMem; private: diff --git a/GPU/GPUTracking/Base/GPURawData.h b/GPU/GPUTracking/Base/GPURawData.h deleted file mode 100644 index 76e559c1e63ad..0000000000000 --- a/GPU/GPUTracking/Base/GPURawData.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPURawData.h -/// \author David Rohr - -#ifndef O2_GPU_RAW_DATA_H -#define O2_GPU_RAW_DATA_H - -// Raw data parser is not accessible from GPU, therefore we use this header to wrap direct access to the current RDH -// Since OpenCL currently doesn't support bit fields, we have to access the members directly - -#include "GPUCommonDef.h" -#ifndef __OPENCL__ -#include "Headers/RAWDataHeader.h" -#include "DetectorsRaw/RDHUtils.h" -#else -namespace o2 -{ -namespace header -{ -struct RAWDataHeader { - union { - unsigned int words[8]; - }; -}; -} // namespace header -} // namespace o2 -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -typedef o2::header::RAWDataHeader RAWDataHeaderGPU; - -class GPURawDataUtils -{ - public: - static GPUd() unsigned int getOrbit(const RAWDataHeaderGPU* rdh); - static GPUd() unsigned int getBC(const RAWDataHeaderGPU* rdh); - static GPUd() unsigned int getSize(const RAWDataHeaderGPU* rdh); -}; - -GPUdi() unsigned int GPURawDataUtils::getOrbit(const RAWDataHeaderGPU* rdh) -{ -#ifndef __OPENCL__ - return o2::raw::RDHUtils::getHeartBeatOrbit(*rdh); -#else - return (rdh->words[2] >> 32); // TODO: Ad-hoc implementation for OpenCL, RDHV4, to be moved to RDHUtils -#endif -} - -GPUdi() unsigned int GPURawDataUtils::getBC(const RAWDataHeaderGPU* rdh) -{ -#ifndef __OPENCL__ - return o2::raw::RDHUtils::getHeartBeatBC(*rdh); -#else - return (rdh->words[2] & 0xFFF); // TODO: Ad-hoc implementation for OpenCL, RDHV4, to be moved to RDHUtils -#endif -} - -GPUdi() unsigned int GPURawDataUtils::getSize(const RAWDataHeaderGPU* rdh) -{ -#ifndef __OPENCL__ - return o2::raw::RDHUtils::getMemorySize(*rdh); -#else - return ((rdh->words[1] >> 16) & 0xFFFF); // TODO: Ad-hoc implementation for OpenCL, RDHV4, to be moved to RDHUtils -#endif -} - -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index b4bb8be7dd81c..4956885656d97 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,11 +38,13 @@ #include "GPUReconstruction.h" #include "GPUReconstructionIncludes.h" +#include "GPUROOTDumpCore.h" #include "GPUMemoryResource.h" #include "GPUChain.h" #include "GPUMemorySizeScalers.h" +#include "utils/strtag.h" #define GPUCA_LOGGING_PRINTF #include "GPULogging.h" @@ -93,15 +96,16 @@ GPUReconstruction::GPUReconstruction(const GPUSettingsDeviceBackend& cfg) : mHos cfg.master->mSlaves.emplace_back(this); } new (&mProcessingSettings) GPUSettingsProcessing; - new (&mEventSettings) GPUSettingsEvent; - param().SetDefaults(&mEventSettings); + new (&mGRPSettings) GPUSettingsGRP; + param().SetDefaults(&mGRPSettings); mMemoryScalers.reset(new GPUMemorySizeScalers); for (unsigned int i = 0; i < NSLICES; i++) { processors()->tpcTrackers[i].SetSlice(i); // TODO: Move to a better place -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS processors()->tpcClusterer[i].mISlice = i; #endif } + mROOTDump = GPUROOTDumpCore::getAndCreate(); } GPUReconstruction::~GPUReconstruction() @@ -121,6 +125,19 @@ void GPUReconstruction::GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* tr } } +int GPUReconstruction::SetNOMPThreads(int n) +{ +#ifdef WITH_OPENMP + omp_set_num_threads(mProcessingSettings.ompThreads = std::max(1, n < 0 ? mMaxOMPThreads : std::min(n, mMaxOMPThreads))); + if (mProcessingSettings.debugLevel >= 3) { + GPUInfo("Set number of OpenMP threads to %d (%d requested)", mProcessingSettings.ompThreads, n); + } + return n > mMaxOMPThreads; +#else + return 1; +#endif +} + int GPUReconstruction::Init() { if (mMaster) { @@ -170,6 +187,7 @@ int GPUReconstruction::Init() if (retVal) { return retVal; } + ClearAllocatedMemory(); for (unsigned int i = 0; i < mSlaves.size(); i++) { mSlaves[i]->mDeviceMemoryPermanent = mDeviceMemoryPermanent; mSlaves[i]->mHostMemoryPermanent = mHostMemoryPermanent; @@ -178,18 +196,20 @@ int GPUReconstruction::Init() GPUError("Error initialization slave (after device init)"); return retVal; } + mSlaves[i]->ClearAllocatedMemory(); } return 0; } int GPUReconstruction::InitPhaseBeforeDevice() { -#ifndef HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS mRecoSteps.setBits(RecoStep::ITSTracking, false); mRecoSteps.setBits(RecoStep::TRDTracking, false); mRecoSteps.setBits(RecoStep::TPCConversion, false); mRecoSteps.setBits(RecoStep::TPCCompression, false); mRecoSteps.setBits(RecoStep::TPCdEdx, false); + mProcessingSettings.createO2Output = false; #endif mRecoStepsGPU &= mRecoSteps; mRecoStepsGPU &= AvailableRecoSteps(); @@ -233,6 +253,12 @@ int GPUReconstruction::InitPhaseBeforeDevice() mProcessingSettings.trackletSelectorSlices = 1; } } + if (mProcessingSettings.createO2Output > 1 && mProcessingSettings.runQA) { + mProcessingSettings.createO2Output = 1; + } + if (!mProcessingSettings.createO2Output || !IsGPU()) { + mProcessingSettings.clearO2OutputFromGPU = false; + } if (!(mRecoStepsGPU & GPUDataTypes::RecoStep::TPCMerging)) { mProcessingSettings.mergerSortTracks = false; } @@ -241,39 +267,51 @@ int GPUReconstruction::InitPhaseBeforeDevice() mProcessingSettings.nTPCClustererLanes = 1; } - if (param().rec.NonConsecutiveIDs) { - param().rec.DisableRefitAttachment = 0xFF; + if (param().rec.nonConsecutiveIDs) { + param().rec.tpc.disableRefitAttachment = 0xFF; } - if (!(mRecoStepsGPU & RecoStep::TPCMerging) || !param().rec.mergerReadFromTrackerDirectly) { + if (!(mRecoStepsGPU & RecoStep::TPCMerging) || !param().rec.tpc.mergerReadFromTrackerDirectly) { mProcessingSettings.fullMergerOnGPU = false; } if (mProcessingSettings.debugLevel || !mProcessingSettings.fullMergerOnGPU) { mProcessingSettings.delayedOutput = false; } + if (!mProcessingSettings.fullMergerOnGPU && GetRecoStepsGPU() & RecoStep::TPCMerging) { + param().rec.tpc.loopInterpolationInExtraPass = 0; + if (param().rec.tpc.retryRefit == 1) { + param().rec.tpc.retryRefit = 2; + } + } UpdateSettings(); GPUCA_GPUReconstructionUpdateDefailts(); if (!mProcessingSettings.trackletConstructorInPipeline) { mProcessingSettings.trackletSelectorInPipeline = false; } - if (!mProcessingSettings.enableRTC) { - mProcessingSettings.rtcConstexpr = false; + if (!mProcessingSettings.rtc.enable) { + mProcessingSettings.rtc.optConstexpr = false; } mMemoryScalers->factor = mProcessingSettings.memoryScalingFactor; + mMemoryScalers->returnMaxVal = mProcessingSettings.forceMaxMemScalers != 0; + if (mProcessingSettings.forceMaxMemScalers > 1) { + mMemoryScalers->rescaleMaxMem(mProcessingSettings.forceMaxMemScalers); + } #ifdef WITH_OPENMP if (mProcessingSettings.ompThreads <= 0) { mProcessingSettings.ompThreads = omp_get_max_threads(); } else { + mProcessingSettings.ompAutoNThreads = false; omp_set_num_threads(mProcessingSettings.ompThreads); } #else mProcessingSettings.ompThreads = 1; #endif + mMaxOMPThreads = mProcessingSettings.ompThreads; mMaxThreads = std::max(mMaxThreads, mProcessingSettings.ompThreads); if (IsGPU()) { - mNStreams = std::max(mProcessingSettings.nStreams, 3); + mNStreams = std::max<int>(mProcessingSettings.nStreams, 3); } if (mProcessingSettings.doublePipeline && (mChains.size() != 1 || mChains[0]->SupportsDoublePipeline() == false || !IsGPU() || mProcessingSettings.memoryAllocationStrategy != GPUMemoryResource::ALLOCATION_GLOBAL)) { @@ -290,7 +328,7 @@ int GPUReconstruction::InitPhaseBeforeDevice() mChains[i]->RegisterPermanentMemoryAndProcessors(); size_t memPrimary, memPageLocked; mChains[i]->MemorySize(memPrimary, memPageLocked); - if (!IsGPU() || mOutputControl.OutputType == GPUOutputControl::AllocateInternal) { + if (!IsGPU() || mOutputControl.useInternal()) { memPageLocked = memPrimary; } mDeviceMemorySize += memPrimary; @@ -300,7 +338,7 @@ int GPUReconstruction::InitPhaseBeforeDevice() mDeviceMemorySize = mProcessingSettings.forceMemoryPoolSize; } else if (mProcessingSettings.forceMemoryPoolSize > 2) { mDeviceMemorySize = mProcessingSettings.forceMemoryPoolSize; - if (!IsGPU() || mOutputControl.OutputType == GPUOutputControl::AllocateInternal) { + if (!IsGPU() || mOutputControl.useInternal()) { mHostMemorySize = mDeviceMemorySize; } } @@ -328,6 +366,9 @@ int GPUReconstruction::InitPhasePermanentMemory() int GPUReconstruction::InitPhaseAfterDevice() { + if (mProcessingSettings.forceMaxMemScalers <= 1 && mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_GLOBAL) { + mMemoryScalers->rescaleMaxMem(IsGPU() ? mDeviceMemorySize : mHostMemorySize); + } for (unsigned int i = 0; i < mChains.size(); i++) { if (mChains[i]->Init()) { return 1; @@ -447,7 +488,7 @@ size_t GPUReconstruction::AllocateRegisteredPermanentMemory() return total; } -size_t GPUReconstruction::AllocateRegisteredMemoryHelper(GPUMemoryResource* res, void*& ptr, void*& memorypool, void* memorybase, size_t memorysize, void* (GPUMemoryResource::*setPtr)(void*), void*& memorypoolend) +size_t GPUReconstruction::AllocateRegisteredMemoryHelper(GPUMemoryResource* res, void*& ptr, void*& memorypool, void* memorybase, size_t memorysize, void* (GPUMemoryResource::*setPtr)(void*), void*& memorypoolend, const char* device) { if (res->mReuse >= 0) { ptr = (&ptr == &res->mPtrDevice) ? mMemoryResources[res->mReuse].mPtrDevice : mMemoryResources[res->mReuse].mPtr; @@ -457,11 +498,11 @@ size_t GPUReconstruction::AllocateRegisteredMemoryHelper(GPUMemoryResource* res, } size_t retVal = (char*)((res->*setPtr)(ptr)) - (char*)(ptr); if (retVal > mMemoryResources[res->mReuse].mSize) { - GPUError("Insufficient reuse memory %lu < %lu (%s)", mMemoryResources[res->mReuse].mSize, retVal, res->mName); + GPUError("Insufficient reuse memory %lu < %lu (%s) (%s)", mMemoryResources[res->mReuse].mSize, retVal, res->mName, device); throw std::bad_alloc(); } if (mProcessingSettings.allocDebugLevel >= 2) { - std::cout << "Reused " << res->mName << ": " << retVal << "\n"; + std::cout << "Reused (" << device << ") " << res->mName << ": " << retVal << "\n"; } return retVal; } @@ -491,18 +532,18 @@ size_t GPUReconstruction::AllocateRegisteredMemoryHelper(GPUMemoryResource* res, memorypool = (void*)((char*)memorypool + GPUProcessor::getAlignment<GPUCA_MEMALIGN>(memorypool)); } if (memorypoolend ? (memorypool > memorypoolend) : ((size_t)((char*)memorypool - (char*)memorybase) > memorysize)) { - std::cout << "Memory pool size exceeded (" << res->mName << ": " << (memorypoolend ? (memorysize + ((char*)memorypool - (char*)memorypoolend)) : (char*)memorypool - (char*)memorybase) << " < " << memorysize << "\n"; + std::cout << "Memory pool size exceeded (" << device << ") (" << res->mName << ": " << (memorypoolend ? (memorysize + ((char*)memorypool - (char*)memorypoolend)) : (char*)memorypool - (char*)memorybase) << " < " << memorysize << "\n"; throw std::bad_alloc(); } if (mProcessingSettings.allocDebugLevel >= 2) { - std::cout << "Allocated " << res->mName << ": " << retVal << " - available: " << (memorypoolend ? ((char*)memorypoolend - (char*)memorypool) : (memorysize - ((char*)memorypool - (char*)memorybase))) << "\n"; + std::cout << "Allocated (" << device << ") " << res->mName << ": " << retVal << " - available: " << (memorypoolend ? ((char*)memorypoolend - (char*)memorypool) : (memorysize - ((char*)memorypool - (char*)memorybase))) << "\n"; } return retVal; } void GPUReconstruction::AllocateRegisteredMemoryInternal(GPUMemoryResource* res, GPUOutputControl* control, GPUReconstruction* recPool) { - if (mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL && (control == nullptr || control->OutputType == GPUOutputControl::AllocateInternal)) { + if (mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL && (control == nullptr || control->useInternal())) { if (!(res->mType & GPUMemoryResource::MEMORY_EXTERNAL)) { if (res->mPtrDevice && res->mReuse < 0) { operator delete(res->mPtrDevice GPUCA_OPERATOR_NEW_ALIGNMENT); @@ -525,6 +566,10 @@ void GPUReconstruction::AllocateRegisteredMemoryInternal(GPUMemoryResource* res, if (res->mType & GPUMemoryResource::MEMORY_STACK) { mNonPersistentIndividualAllocations.emplace_back(res); } + if ((size_t)res->mPtr % GPUCA_BUFFER_ALIGNMENT) { + GPUError("Got buffer with insufficient alignment"); + throw std::bad_alloc(); + } } } else { if (res->mPtr != nullptr) { @@ -535,25 +580,32 @@ void GPUReconstruction::AllocateRegisteredMemoryInternal(GPUMemoryResource* res, res->mOverrideSize = GPUCA_BUFFER_ALIGNMENT; } if ((!IsGPU() || (res->mType & GPUMemoryResource::MEMORY_HOST) || mProcessingSettings.keepDisplayMemory) && !(res->mType & GPUMemoryResource::MEMORY_EXTERNAL)) { // keepAllMemory --> keepDisplayMemory - if (control && control->OutputType == GPUOutputControl::UseExternalBuffer) { - if (control->OutputAllocator) { + if (control && control->useExternal()) { + if (control->allocator) { res->mSize = std::max((size_t)res->SetPointers((void*)1) - 1, res->mOverrideSize); - res->mPtr = control->OutputAllocator(res->mSize); + res->mPtr = control->allocator(CAMath::nextMultipleOf<GPUCA_BUFFER_ALIGNMENT>(res->mSize)); res->mSize = std::max<size_t>((char*)res->SetPointers(res->mPtr) - (char*)res->mPtr, res->mOverrideSize); + if (mProcessingSettings.allocDebugLevel >= 2) { + std::cout << "Allocated (from callback) " << res->mName << ": " << res->mSize << "\n"; + } } else { void* dummy = nullptr; - res->mSize = AllocateRegisteredMemoryHelper(res, res->mPtr, control->OutputPtr, control->OutputBase, control->OutputMaxSize, &GPUMemoryResource::SetPointers, dummy); + res->mSize = AllocateRegisteredMemoryHelper(res, res->mPtr, control->ptrCurrent, control->ptrBase, control->size, &GPUMemoryResource::SetPointers, dummy, "host"); } } else { - res->mSize = AllocateRegisteredMemoryHelper(res, res->mPtr, recPool->mHostMemoryPool, recPool->mHostMemoryBase, recPool->mHostMemorySize, &GPUMemoryResource::SetPointers, recPool->mHostMemoryPoolEnd); + res->mSize = AllocateRegisteredMemoryHelper(res, res->mPtr, recPool->mHostMemoryPool, recPool->mHostMemoryBase, recPool->mHostMemorySize, &GPUMemoryResource::SetPointers, recPool->mHostMemoryPoolEnd, "host"); + } + if ((size_t)res->mPtr % GPUCA_BUFFER_ALIGNMENT) { + GPUError("Got buffer with insufficient alignment"); + throw std::bad_alloc(); } } if (IsGPU() && (res->mType & GPUMemoryResource::MEMORY_GPU)) { - if (res->mProcessor->mDeviceProcessor == nullptr) { + if (res->mProcessor->mLinkedProcessor == nullptr) { GPUError("Device Processor not set (%s)", res->mName); throw std::bad_alloc(); } - size_t size = AllocateRegisteredMemoryHelper(res, res->mPtrDevice, recPool->mDeviceMemoryPool, recPool->mDeviceMemoryBase, recPool->mDeviceMemorySize, &GPUMemoryResource::SetDevicePointers, recPool->mDeviceMemoryPoolEnd); + size_t size = AllocateRegisteredMemoryHelper(res, res->mPtrDevice, recPool->mDeviceMemoryPool, recPool->mDeviceMemoryBase, recPool->mDeviceMemorySize, &GPUMemoryResource::SetDevicePointers, recPool->mDeviceMemoryPoolEnd, " gpu"); if (!(res->mType & GPUMemoryResource::MEMORY_HOST) || (res->mType & GPUMemoryResource::MEMORY_EXTERNAL)) { res->mSize = size; @@ -561,6 +613,10 @@ void GPUReconstruction::AllocateRegisteredMemoryInternal(GPUMemoryResource* res, GPUError("Inconsistent device memory allocation (%s: device %lu vs %lu)", res->mName, size, res->mSize); throw std::bad_alloc(); } + if ((size_t)res->mPtrDevice % GPUCA_BUFFER_ALIGNMENT) { + GPUError("Got buffer with insufficient alignment"); + throw std::bad_alloc(); + } } UpdateMaxMemoryUsed(); } @@ -585,7 +641,7 @@ size_t GPUReconstruction::AllocateRegisteredMemory(short ires, GPUOutputControl* void* GPUReconstruction::AllocateUnmanagedMemory(size_t size, int type) { if (type != GPUMemoryResource::MEMORY_HOST && (!IsGPU() || type != GPUMemoryResource::MEMORY_GPU)) { - throw std::bad_alloc(); + throw std::runtime_error("Requested invalid memory typo for unmanaged allocation"); } if (mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { mUnmanagedChunks.emplace_back(new char[size + GPUCA_BUFFER_ALIGNMENT]); @@ -596,9 +652,13 @@ void* GPUReconstruction::AllocateUnmanagedMemory(size_t size, int type) char* retVal; GPUProcessor::computePointerWithAlignment(pool, retVal, size); if (pool > poolend) { + GPUError("Insufficient unmanaged memory: missing %lu", (size_t)((char*)pool - (char*)poolend)); throw std::bad_alloc(); } UpdateMaxMemoryUsed(); + if (mProcessingSettings.allocDebugLevel >= 2) { + std::cout << "Allocated (unmanaged " << (type == GPUMemoryResource::MEMORY_GPU ? "gpu" : "host") << "): " << size << " - available: " << ((char*)poolend - (char*)pool) << "\n"; + } return retVal; } } @@ -614,9 +674,14 @@ void* GPUReconstruction::AllocateVolatileDeviceMemory(size_t size) char* retVal; GPUProcessor::computePointerWithAlignment(mDeviceMemoryPool, retVal, size); if (mDeviceMemoryPool > mDeviceMemoryPoolEnd) { + GPUError("Insufficient volatile device memory: missing %lu", (size_t)((char*)mDeviceMemoryPool - (char*)mDeviceMemoryPoolEnd)); throw std::bad_alloc(); } UpdateMaxMemoryUsed(); + if (mProcessingSettings.allocDebugLevel >= 2) { + std::cout << "Allocated (volatile GPU): " << size << " - available: " << ((char*)mDeviceMemoryPoolEnd - (char*)mDeviceMemoryPool) << "\n"; + } + return retVal; } @@ -680,23 +745,34 @@ void GPUReconstruction::ReturnVolatileDeviceMemory() mDeviceMemoryPool = mVolatileMemoryStart; mVolatileMemoryStart = nullptr; } + if (mProcessingSettings.allocDebugLevel >= 2) { + std::cout << "Freed (volatile GPU) - available: " << ((char*)mDeviceMemoryPoolEnd - (char*)mDeviceMemoryPool) << "\n"; + } } -void GPUReconstruction::PushNonPersistentMemory() +void GPUReconstruction::PushNonPersistentMemory(unsigned long tag) { - mNonPersistentMemoryStack.emplace_back(mHostMemoryPoolEnd, mDeviceMemoryPoolEnd, mNonPersistentIndividualAllocations.size()); + mNonPersistentMemoryStack.emplace_back(mHostMemoryPoolEnd, mDeviceMemoryPoolEnd, mNonPersistentIndividualAllocations.size(), tag); } -void GPUReconstruction::PopNonPersistentMemory(RecoStep step) +void GPUReconstruction::PopNonPersistentMemory(RecoStep step, unsigned long tag) { + if (mProcessingSettings.keepDisplayMemory || mProcessingSettings.disableMemoryReuse) { + return; + } + if (mNonPersistentMemoryStack.size() == 0) { + GPUFatal("Trying to pop memory state from empty stack"); + } + if (tag != 0 && std::get<3>(mNonPersistentMemoryStack.back()) != tag) { + GPUFatal("Tag mismatch when poping non persistent memory from stack : pop %s vs on stack %s", qTag2Str(tag).c_str(), qTag2Str(std::get<3>(mNonPersistentMemoryStack.back())).c_str()); + } if ((mProcessingSettings.debugLevel >= 3 || mProcessingSettings.allocDebugLevel) && (IsGPU() || mProcessingSettings.forceHostMemoryPoolSize)) { if (IsGPU()) { - printf("Allocated Device memory after %30s: %'13lld (non temporary %'13lld, blocked %'13lld)\n", GPUDataTypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], ptrDiff(mDeviceMemoryPool, mDeviceMemoryBase) + ptrDiff((char*)mDeviceMemoryBase + mDeviceMemorySize, mDeviceMemoryPoolEnd), ptrDiff(mDeviceMemoryPool, mDeviceMemoryBase), mDeviceMemoryPoolBlocked == nullptr ? 0ll : ptrDiff((char*)mDeviceMemoryBase + mDeviceMemorySize, mDeviceMemoryPoolBlocked)); + printf("Allocated Device memory after %30s (%8s): %'13lld (non temporary %'13lld, blocked %'13lld)\n", GPUDataTypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], qTag2Str(std::get<3>(mNonPersistentMemoryStack.back())).c_str(), ptrDiff(mDeviceMemoryPool, mDeviceMemoryBase) + ptrDiff((char*)mDeviceMemoryBase + mDeviceMemorySize, mDeviceMemoryPoolEnd), ptrDiff(mDeviceMemoryPool, mDeviceMemoryBase), mDeviceMemoryPoolBlocked == nullptr ? 0ll : ptrDiff((char*)mDeviceMemoryBase + mDeviceMemorySize, mDeviceMemoryPoolBlocked)); } - printf("Allocated Host memory after %30s: %'13lld (non temporary %'13lld, blocked %'13lld)\n", GPUDataTypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], ptrDiff(mHostMemoryPool, mHostMemoryBase) + ptrDiff((char*)mHostMemoryBase + mHostMemorySize, mHostMemoryPoolEnd), ptrDiff(mHostMemoryPool, mHostMemoryBase), mHostMemoryPoolBlocked == nullptr ? 0ll : ptrDiff((char*)mHostMemoryBase + mHostMemorySize, mHostMemoryPoolBlocked)); - } - if (mProcessingSettings.keepDisplayMemory || mProcessingSettings.disableMemoryReuse) { - return; + printf("Allocated Host memory after %30s (%8s): %'13lld (non temporary %'13lld, blocked %'13lld)\n", GPUDataTypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], qTag2Str(std::get<3>(mNonPersistentMemoryStack.back())).c_str(), ptrDiff(mHostMemoryPool, mHostMemoryBase) + ptrDiff((char*)mHostMemoryBase + mHostMemorySize, mHostMemoryPoolEnd), ptrDiff(mHostMemoryPool, mHostMemoryBase), mHostMemoryPoolBlocked == nullptr ? 0ll : ptrDiff((char*)mHostMemoryBase + mHostMemorySize, mHostMemoryPoolBlocked)); + printf("%16s", ""); + PrintMemoryMax(); } mHostMemoryPoolEnd = std::get<0>(mNonPersistentMemoryStack.back()); mDeviceMemoryPoolEnd = std::get<1>(mNonPersistentMemoryStack.back()); @@ -795,7 +871,7 @@ void GPUReconstruction::PrintMemoryStatistics() } printf("%59s CPU / %9s GPU\n", "", ""); for (auto it = sizes.begin(); it != sizes.end(); it++) { - printf("Allocation %30s %s: Size %'13lld / %'13lld\n", it->first.c_str(), it->second[2] ? "P" : " ", (long long int)it->second[0], (long long int)it->second[1]); + printf("Allocation %30s %s: Size %'14lld / %'14lld\n", it->first.c_str(), it->second[2] ? "P" : " ", (long long int)it->second[0], (long long int)it->second[1]); } PrintMemoryOverview(); for (unsigned int i = 0; i < mChains.size(); i++) { @@ -902,8 +978,8 @@ void GPUReconstruction::PrepareEvent() // TODO: Clean this up, this should not b continue; } (mProcessors[i].proc->*(mProcessors[i].SetMaxData))(mHostConstantMem->ioPtrs); - if (mProcessors[i].proc->mDeviceProcessor) { - (mProcessors[i].proc->mDeviceProcessor->*(mProcessors[i].SetMaxData))(mHostConstantMem->ioPtrs); + if (mProcessors[i].proc->mGPUProcessorType != GPUProcessor::PROCESSOR_TYPE_DEVICE && mProcessors[i].proc->mLinkedProcessor) { + (mProcessors[i].proc->mLinkedProcessor->*(mProcessors[i].SetMaxData))(mHostConstantMem->ioPtrs); } } ComputeReuseMax(nullptr); @@ -926,15 +1002,15 @@ void GPUReconstruction::DumpSettings(const char* dir) std::string f; f = dir; f += "settings.dump"; - DumpStructToFile(&mEventSettings, f.c_str()); + DumpStructToFile(&mGRPSettings, f.c_str()); for (unsigned int i = 0; i < mChains.size(); i++) { mChains[i]->DumpSettings(dir); } } -void GPUReconstruction::UpdateEventSettings(const GPUSettingsEvent* e, const GPUSettingsProcessing* p) +void GPUReconstruction::UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) { - param().UpdateEventSettings(e, p); + param().UpdateGRPSettings(g, p); if (mInitialized) { WriteConstantParams(); } @@ -945,11 +1021,11 @@ int GPUReconstruction::ReadSettings(const char* dir) std::string f; f = dir; f += "settings.dump"; - new (&mEventSettings) GPUSettingsEvent; - if (ReadStructFromFile(f.c_str(), &mEventSettings)) { + new (&mGRPSettings) GPUSettingsGRP; + if (ReadStructFromFile(f.c_str(), &mGRPSettings)) { return 1; } - param().UpdateEventSettings(&mEventSettings); + param().UpdateGRPSettings(&mGRPSettings); for (unsigned int i = 0; i < mChains.size(); i++) { mChains[i]->ReadSettings(dir); } @@ -960,25 +1036,25 @@ void GPUReconstruction::SetSettings(float solenoidBz, const GPURecoStepConfigura { #ifdef GPUCA_O2_LIB GPUO2InterfaceConfiguration config; - config.ReadConfigurableParam(); - if (config.configEvent.solenoidBz <= -1e6f) { - config.configEvent.solenoidBz = solenoidBz; + config.ReadConfigurableParam_internal(); + if (config.configGRP.solenoidBz <= -1e6f) { + config.configGRP.solenoidBz = solenoidBz; } - SetSettings(&config.configEvent, &config.configReconstruction, &config.configProcessing, workflow); + SetSettings(&config.configGRP, &config.configReconstruction, &config.configProcessing, workflow); #else - GPUSettingsEvent ev; - ev.solenoidBz = solenoidBz; - SetSettings(&ev, nullptr, nullptr, workflow); + GPUSettingsGRP grp; + grp.solenoidBz = solenoidBz; + SetSettings(&grp, nullptr, nullptr, workflow); #endif } -void GPUReconstruction::SetSettings(const GPUSettingsEvent* settings, const GPUSettingsRec* rec, const GPUSettingsProcessing* proc, const GPURecoStepConfiguration* workflow) +void GPUReconstruction::SetSettings(const GPUSettingsGRP* grp, const GPUSettingsRec* rec, const GPUSettingsProcessing* proc, const GPURecoStepConfiguration* workflow) { if (mInitialized) { GPUError("Cannot update settings while initialized"); throw std::runtime_error("Settings updated while initialized"); } - mEventSettings = *settings; + mGRPSettings = *grp; if (proc) { mProcessingSettings = *proc; } @@ -988,7 +1064,7 @@ void GPUReconstruction::SetSettings(const GPUSettingsEvent* settings, const GPUS mRecoStepsInputs = workflow->inputs; mRecoStepsOutputs = workflow->outputs; } - param().SetDefaults(&mEventSettings, rec, proc, workflow); + param().SetDefaults(&mGRPSettings, rec, proc, workflow); } void GPUReconstruction::SetOutputControl(void* ptr, size_t size) @@ -1003,6 +1079,9 @@ void GPUReconstruction::SetInputControl(void* ptr, size_t size) mInputControl.set(ptr, size); } +GPUReconstruction::GPUThreadContext::GPUThreadContext() = default; +GPUReconstruction::GPUThreadContext::~GPUThreadContext() = default; + std::unique_ptr<GPUReconstruction::GPUThreadContext> GPUReconstruction::GetThreadContext() { return std::unique_ptr<GPUReconstruction::GPUThreadContext>(new GPUThreadContext); } GPUReconstruction* GPUReconstruction::CreateInstance(DeviceType type, bool forceType, GPUReconstruction* master) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.h b/GPU/GPUTracking/Base/GPUReconstruction.h index 5bb4f7aa61e6a..4311d29d297ed 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.h +++ b/GPU/GPUTracking/Base/GPUReconstruction.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,7 +31,6 @@ #include "GPUMemoryResource.h" #include "GPUConstantMem.h" #include "GPUTPCSliceOutput.h" -#include "GPUDataTypes.h" #include "GPULogging.h" namespace o2 @@ -47,8 +47,9 @@ namespace GPUCA_NAMESPACE namespace gpu { class GPUChain; -class GPUMemorySizeScalers; +struct GPUMemorySizeScalers; struct GPUReconstructionPipelineContext; +class GPUROOTDumpCore; class GPUReconstruction { @@ -99,10 +100,16 @@ class GPUReconstruction TRD_TRACKLET_MC = 11, TPC_COMPRESSED_CL = 12, TPC_DIGIT = 13, - TPC_ZS = 14 }; - static constexpr const char* const IOTYPENAMES[] = {"TPC Clusters", "TPC Slice Tracks", "TPC Slice Track Clusters", "TPC Cluster MC Labels", "TPC Track MC Informations", "TPC Tracks", "TPC Track Clusters", "TRD Tracks", "TRD Tracklets", - "Raw Clusters", "ClusterNative", "TRD Tracklet MC Labels", "TPC Compressed Clusters", "TPC Digit", "TPC ZS Page"}; - static unsigned int getNIOTypeMultiplicity(InOutPointerType type) { return (type == CLUSTER_DATA || type == SLICE_OUT_TRACK || type == SLICE_OUT_CLUSTER || type == RAW_CLUSTERS || type == TPC_DIGIT) ? NSLICES : 1; } + TPC_ZS = 14, + CLUSTER_NATIVE_MC = 15, + TPC_DIGIT_MC = 16, + TRD_SPACEPOINT = 17, + TRD_TRIGGERRECORDS = 18, + TF_SETTINGS = 19 }; + static constexpr const char* const IOTYPENAMES[] = {"TPC HLT Clusters", "TPC Slice Tracks", "TPC Slice Track Clusters", "TPC Cluster MC Labels", "TPC Track MC Informations", "TPC Tracks", "TPC Track Clusters", "TRD Tracks", "TRD Tracklets", + "TPC Raw Clusters", "TPC Native Clusters", "TRD Tracklet MC Labels", "TPC Compressed Clusters", "TPC Digit", "TPC ZS Page", "TPC Native Clusters MC Labels", "TPC Digit MC Labeels", + "TRD Spacepoints", "TRD Triggerrecords", "TF Settings"}; + static unsigned int getNIOTypeMultiplicity(InOutPointerType type) { return (type == CLUSTER_DATA || type == SLICE_OUT_TRACK || type == SLICE_OUT_CLUSTER || type == RAW_CLUSTERS || type == TPC_DIGIT || type == TPC_DIGIT_MC) ? NSLICES : 1; } // Functionality to create an instance of GPUReconstruction for the desired device static GPUReconstruction* CreateInstance(const GPUSettingsDeviceBackend& cfg); @@ -200,8 +207,8 @@ class GPUReconstruction void FreeRegisteredMemory(short res); void ClearAllocatedMemory(bool clearOutputs = true); void ReturnVolatileDeviceMemory(); - void PushNonPersistentMemory(); - void PopNonPersistentMemory(RecoStep step); + void PushNonPersistentMemory(unsigned long tag); + void PopNonPersistentMemory(RecoStep step, unsigned long tag); void BlockStackedMemory(GPUReconstruction* rec); void UnblockStackedMemory(); void ResetRegisteredMemoryPointers(GPUProcessor* proc); @@ -222,20 +229,21 @@ class GPUReconstruction bool IsGPU() const { return GetDeviceType() != DeviceType::INVALID_DEVICE && GetDeviceType() != DeviceType::CPU; } const GPUParam& GetParam() const { return mHostConstantMem->param; } const GPUConstantMem& GetConstantMem() const { return *mHostConstantMem; } - const GPUSettingsEvent& GetEventSettings() const { return mEventSettings; } + const GPUSettingsGRP& GetGRPSettings() const { return mGRPSettings; } const GPUSettingsDeviceBackend& GetDeviceBackendSettings() { return mDeviceBackendSettings; } const GPUSettingsProcessing& GetProcessingSettings() const { return mProcessingSettings; } bool IsInitialized() const { return mInitialized; } void SetSettings(float solenoidBz, const GPURecoStepConfiguration* workflow = nullptr); - void SetSettings(const GPUSettingsEvent* settings, const GPUSettingsRec* rec = nullptr, const GPUSettingsProcessing* proc = nullptr, const GPURecoStepConfiguration* workflow = nullptr); + void SetSettings(const GPUSettingsGRP* grp, const GPUSettingsRec* rec = nullptr, const GPUSettingsProcessing* proc = nullptr, const GPURecoStepConfiguration* workflow = nullptr); void SetResetTimers(bool reset) { mProcessingSettings.resetTimers = reset; } // May update also after Init() void SetDebugLevelTmp(int level) { mProcessingSettings.debugLevel = level; } // Temporarily, before calling SetSettings() - void UpdateEventSettings(const GPUSettingsEvent* e, const GPUSettingsProcessing* p = nullptr); + void UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); void SetOutputControl(const GPUOutputControl& v) { mOutputControl = v; } void SetOutputControl(void* ptr, size_t size); void SetInputControl(void* ptr, size_t size); GPUOutputControl& OutputControl() { return mOutputControl; } int GetMaxThreads() const { return mMaxThreads; } + int SetNOMPThreads(int n); int NStreams() const { return mNStreams; } const void* DeviceMemoryBase() const { return mDeviceMemoryBase; } @@ -279,18 +287,18 @@ class GPUReconstruction class GPUThreadContext { public: - GPUThreadContext() = default; - virtual ~GPUThreadContext() = default; + GPUThreadContext(); + virtual ~GPUThreadContext(); }; virtual std::unique_ptr<GPUThreadContext> GetThreadContext(); // Private helper functions for memory management - size_t AllocateRegisteredMemoryHelper(GPUMemoryResource* res, void*& ptr, void*& memorypool, void* memorybase, size_t memorysize, void* (GPUMemoryResource::*SetPointers)(void*), void*& memorypoolend); + size_t AllocateRegisteredMemoryHelper(GPUMemoryResource* res, void*& ptr, void*& memorypool, void* memorybase, size_t memorysize, void* (GPUMemoryResource::*SetPointers)(void*), void*& memorypoolend, const char* device); size_t AllocateRegisteredPermanentMemory(); // Private helper functions for reading / writing / allocating IO buffer from/to file template <class T, class S> - void DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type); + unsigned int DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type); template <class T, class S> size_t ReadData(FILE* fp, const T** entries, S* num, std::unique_ptr<T[]>* mem, InOutPointerType type, T** nonConstPtrs = nullptr); template <class T> @@ -320,12 +328,12 @@ class GPUReconstruction GPUConstantMem* mDeviceConstantMem = nullptr; // Settings - GPUSettingsEvent mEventSettings; // Event Parameters - GPUSettingsDeviceBackend mDeviceBackendSettings; // Processing Parameters (at constructor level) - GPUSettingsProcessing mProcessingSettings; // Processing Parameters (at init level) - GPUOutputControl mOutputControl; // Controls the output of the individual components - GPUOutputControl mInputControl; // Prefefined input memory location for reading standalone dumps - std::unique_ptr<GPUMemorySizeScalers> mMemoryScalers; // Scalers how much memory will be needed + GPUSettingsGRP mGRPSettings; // Global Run Parameters + GPUSettingsDeviceBackend mDeviceBackendSettings; // Processing Parameters (at constructor level) + GPUSettingsProcessing mProcessingSettings; // Processing Parameters (at init level) + GPUOutputControl mOutputControl; // Controls the output of the individual components + GPUOutputControl mInputControl; // Prefefined input memory location for reading standalone dumps + std::unique_ptr<GPUMemorySizeScalers> mMemoryScalers; // Scalers how much memory will be needed RecoStepField mRecoSteps = RecoStep::AllRecoSteps; RecoStepField mRecoStepsGPU = RecoStep::AllRecoSteps; @@ -360,11 +368,13 @@ class GPUReconstruction unsigned int mNEventsProcessed = 0; double mStatKernelTime = 0.; double mStatWallTime = 0.; + std::shared_ptr<GPUROOTDumpCore> mROOTDump; - int mMaxThreads = 0; // Maximum number of threads that may be running, on CPU or GPU - int mThreadId = -1; // Thread ID that is valid for the local CUDA context - int mGPUStuck = 0; // Marks that the GPU is stuck, skip future events - int mNStreams = 1; // Number of parallel GPU streams + int mMaxThreads = 0; // Maximum number of threads that may be running, on CPU or GPU + int mThreadId = -1; // Thread ID that is valid for the local CUDA context + int mGPUStuck = 0; // Marks that the GPU is stuck, skip future events + int mNStreams = 1; // Number of parallel GPU streams + int mMaxOMPThreads = 0; // Maximum number of OMP threads // Management for GPUProcessors struct ProcessorData { @@ -382,7 +392,7 @@ class GPUReconstruction std::vector<unsigned short> res; }; std::unordered_map<GPUMemoryReuse::ID, MemoryReuseMeta> mMemoryReuse1to1; - std::vector<std::tuple<void*, void*, size_t>> mNonPersistentMemoryStack; + std::vector<std::tuple<void*, void*, size_t, unsigned long>> mNonPersistentMemoryStack; std::vector<GPUMemoryResource*> mNonPersistentIndividualAllocations; std::unique_ptr<GPUReconstructionPipelineContext> mPipelineContext; @@ -420,10 +430,11 @@ inline T* GPUReconstruction::AllocateIOMemoryHelper(size_t n, const T*& ptr, std return nullptr; } T* retVal; - if (mInputControl.OutputType == GPUOutputControl::UseExternalBuffer) { + if (mInputControl.useExternal()) { u.reset(nullptr); - GPUProcessor::computePointerWithAlignment(mInputControl.OutputPtr, retVal, n); - if ((size_t)((char*)mInputControl.OutputPtr - (char*)mInputControl.OutputBase) > mInputControl.OutputMaxSize) { + mInputControl.checkCurrent(); + GPUProcessor::computePointerWithAlignment(mInputControl.ptrCurrent, retVal, n); + if ((size_t)((char*)mInputControl.ptrCurrent - (char*)mInputControl.ptrBase) > mInputControl.size) { throw std::bad_alloc(); } } else { @@ -492,9 +503,9 @@ inline void GPUReconstruction::SetupGPUProcessor(T* proc, bool allocate) if (allocate) { proc->SetMaxData(mHostConstantMem->ioPtrs); } - if (proc->mDeviceProcessor) { - std::memcpy((void*)proc->mDeviceProcessor, (const void*)proc, sizeof(*proc)); - proc->mDeviceProcessor->InitGPUProcessor((GPUReconstruction*)this, GPUProcessor::PROCESSOR_TYPE_DEVICE); + if (proc->mGPUProcessorType != GPUProcessor::PROCESSOR_TYPE_DEVICE && proc->mLinkedProcessor) { + std::memcpy((void*)proc->mLinkedProcessor, (const void*)proc, sizeof(*proc)); + proc->mLinkedProcessor->InitGPUProcessor((GPUReconstruction*)this, GPUProcessor::PROCESSOR_TYPE_DEVICE, proc); } if (allocate) { AllocateRegisteredMemory(proc, true); @@ -504,7 +515,7 @@ inline void GPUReconstruction::SetupGPUProcessor(T* proc, bool allocate) } template <class T, class S> -inline void GPUReconstruction::DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type) +inline unsigned int GPUReconstruction::DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type) { int count = getNIOTypeMultiplicity(type); unsigned int numTotal = 0; @@ -512,7 +523,7 @@ inline void GPUReconstruction::DumpData(FILE* fp, const T* const* entries, const numTotal += num[i]; } if (numTotal == 0) { - return; + return 0; } fwrite(&type, sizeof(type), 1, fp); for (int i = 0; i < count; i++) { @@ -521,6 +532,10 @@ inline void GPUReconstruction::DumpData(FILE* fp, const T* const* entries, const fwrite(entries[i], sizeof(*entries[i]), num[i], fp); } } + if (mProcessingSettings.debugLevel >= 2) { + GPUInfo("Dumped %lld %s", (long long int)numTotal, IOTYPENAMES[type]); + } + return numTotal; } template <class T, class S> diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx index 4e1b6fc41a7fd..ea0e24a2fe63b 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,7 @@ #include "GPUTRDTrackletLabels.h" #include "GPUMemoryResource.h" #include "GPUConstantMem.h" +#include "GPUMemorySizeScalers.h" #include <atomic> #define GPUCA_LOGGING_PRINTF @@ -71,8 +73,12 @@ int GPUReconstructionCPUBackend::runKernelBackend(krnlSetup& _xyz, const Args&.. } unsigned int num = y.num == 0 || y.num == -1 ? 1 : y.num; for (unsigned int k = 0; k < num; k++) { - if (mProcessingSettings.ompKernels) { - GPUCA_OPENMP(parallel for num_threads(mProcessingSettings.ompThreads)) + int ompThreads = mProcessingSettings.ompKernels ? (mProcessingSettings.ompKernels == 2 ? ((mProcessingSettings.ompThreads + mNestedLoopOmpFactor - 1) / mNestedLoopOmpFactor) : mProcessingSettings.ompThreads) : 1; + if (ompThreads > 1) { + if (mProcessingSettings.debugLevel >= 5) { + printf("Running %d ompThreads\n", ompThreads); + } + GPUCA_OPENMP(parallel for num_threads(ompThreads)) for (unsigned int iB = 0; iB < x.nBlocks; iB++) { typename T::GPUSharedMemory smem; T::template Thread<I>(x.nBlocks, 1, iB, 0, smem, T::Processor(*mHostConstantMem)[y.start + k], args...); @@ -108,7 +114,7 @@ size_t GPUReconstructionCPU::GPUMemCpyAlways(bool onGpu, void* dst, const void* return 0; } size_t GPUReconstructionCPU::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) { return 0; } -int GPUReconstructionCPU::GPUDebug(const char* state, int stream) { return 0; } +int GPUReconstructionCPU::GPUDebug(const char* state, int stream, bool force) { return 0; } size_t GPUReconstructionCPU::TransferMemoryResourcesHelper(GPUProcessor* proc, int stream, bool all, bool toGPU) { int inc = toGPU ? GPUMemoryResource::MEMORY_INPUT_FLAG : GPUMemoryResource::MEMORY_OUTPUT_FLAG; @@ -152,11 +158,11 @@ int GPUReconstructionCPU::GetThread() int GPUReconstructionCPU::InitDevice() { if (mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_GLOBAL) { - if (mDeviceMemorySize > mHostMemorySize) { - mHostMemorySize = mDeviceMemorySize; - } if (mMaster == nullptr) { - mHostMemoryBase = operator new(mHostMemorySize); + if (mDeviceMemorySize > mHostMemorySize) { + mHostMemorySize = mDeviceMemorySize; + } + mHostMemoryBase = operator new(mHostMemorySize GPUCA_OPERATOR_NEW_ALIGNMENT); } mHostMemoryPermanent = mHostMemoryBase; ClearAllocatedMemory(); @@ -173,7 +179,7 @@ int GPUReconstructionCPU::ExitDevice() { if (mProcessingSettings.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_GLOBAL) { if (mMaster == nullptr) { - operator delete(mHostMemoryBase); + operator delete(mHostMemoryBase GPUCA_OPERATOR_NEW_ALIGNMENT); } mHostMemoryPool = mHostMemoryBase = mHostMemoryPoolEnd = mHostMemoryPermanent = nullptr; mHostMemorySize = 0; @@ -183,6 +189,7 @@ int GPUReconstructionCPU::ExitDevice() int GPUReconstructionCPU::RunChains() { + mMemoryScalers->temporaryFactor = 1.; mStatNEvents++; mNEventsProcessed++; @@ -288,8 +295,8 @@ int GPUReconstructionCPU::RunChains() void GPUReconstructionCPU::ResetDeviceProcessorTypes() { for (unsigned int i = 0; i < mProcessors.size(); i++) { - if (mProcessors[i].proc->mDeviceProcessor) { - mProcessors[i].proc->mDeviceProcessor->InitGPUProcessor(this, GPUProcessor::PROCESSOR_TYPE_DEVICE); + if (mProcessors[i].proc->mGPUProcessorType != GPUProcessor::PROCESSOR_TYPE_DEVICE && mProcessors[i].proc->mLinkedProcessor) { + mProcessors[i].proc->mLinkedProcessor->InitGPUProcessor(this, GPUProcessor::PROCESSOR_TYPE_DEVICE); } } } @@ -304,7 +311,7 @@ int GPUReconstructionCPU::getOMPMaxThreads() return omp_get_max_threads(); } -static std::atomic_flag timerFlag; // TODO: Should be a class member not global, but cannot be moved to header due to ROOT limitation +static std::atomic_flag timerFlag = ATOMIC_FLAG_INIT; // TODO: Should be a class member not global, but cannot be moved to header due to ROOT limitation GPUReconstructionCPU::timerMeta* GPUReconstructionCPU::insertTimer(unsigned int id, std::string&& name, int J, int num, int type, RecoStep step) { @@ -319,6 +326,8 @@ GPUReconstructionCPU::timerMeta* GPUReconstructionCPU::insertTimer(unsigned int name += std::to_string(J); } mTimers[id].reset(new timerMeta{std::unique_ptr<HighResTimer[]>{new HighResTimer[num]}, name, num, type, 1u, step, (size_t)0}); + } else { + mTimers[id]->count++; } timerMeta* retVal = mTimers[id].get(); timerFlag.clear(); @@ -344,3 +353,16 @@ unsigned int GPUReconstructionCPU::getNextTimerId() static std::atomic<unsigned int> id{0}; return id.fetch_add(1); } + +unsigned int GPUReconstructionCPU::SetAndGetNestedLoopOmpFactor(bool condition, unsigned int max) +{ + if (condition && mProcessingSettings.ompKernels != 1) { + mNestedLoopOmpFactor = mProcessingSettings.ompKernels == 2 ? std::min<unsigned int>(max, mProcessingSettings.ompThreads) : mProcessingSettings.ompThreads; + } else { + mNestedLoopOmpFactor = 1; + } + if (mProcessingSettings.debugLevel >= 5) { + printf("Running %d OMP threads in outer loop\n", mNestedLoopOmpFactor); + } + return mNestedLoopOmpFactor; +} diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.h b/GPU/GPUTracking/Base/GPUReconstructionCPU.h index 8b0bc183d70a1..59ff53d0cd025 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.h +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,11 +35,13 @@ #ifdef GPUCA_NOCOMPAT #include "GPUTPCGMMergerGPU.h" #endif -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "GPUITSFitterKernels.h" #include "GPUTPCConvertKernel.h" #include "GPUTPCCompressionKernels.h" #include "GPUTPCClusterFinderKernels.h" +#include "GPUTrackingRefitKernel.h" +#include "GPUTPCGMO2Output.h" #endif namespace GPUCA_NAMESPACE @@ -56,6 +59,7 @@ class GPUReconstructionCPUBackend : public GPUReconstruction int runKernelBackend(krnlSetup& _xyz, const Args&... args); template <class T, int I> krnlProperties getKernelPropertiesBackend(); + unsigned int mNestedLoopOmpFactor = 1; }; template <class T> @@ -83,7 +87,7 @@ class GPUReconstructionKernels : public T }; #ifndef GPUCA_GPURECONSTRUCTIONCPU_IMPLEMENTATION -// Hide the body for all files but GPUReconstructionCPU.cxx, otherwise we get weird symbol clashes when the compiler inlines +// Hide the function bodies for all files but GPUReconstructionCPU.cxx, otherwise we get symbol clashes when the compiler inlines template <> class GPUReconstructionKernels<GPUReconstructionCPUBackend> : public GPUReconstructionCPUBackend { @@ -134,7 +138,7 @@ class GPUReconstructionCPU : public GPUReconstructionKernels<GPUReconstructionCP template <class T, int I> constexpr static const char* GetKernelName(); - virtual int GPUDebug(const char* state = "UNKNOWN", int stream = -1); + virtual int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false); int registerMemoryForGPU(const void* ptr, size_t size) override { return 0; } int unregisterMemoryForGPU(const void* ptr) override { return 0; } int GPUStuck() { return mGPUStuck; } @@ -147,6 +151,9 @@ class GPUReconstructionCPU : public GPUReconstructionKernels<GPUReconstructionCP HighResTimer& getRecoStepTimer(RecoStep step) { return mTimersRecoSteps[getRecoStepNum(step)].timerTotal; } HighResTimer& getGeneralStepTimer(GeneralStep step) { return mTimersGeneralSteps[getGeneralStepNum(step)]; } + void SetNestedLoopOmpFactor(unsigned int f) { mNestedLoopOmpFactor = f; } + unsigned int SetAndGetNestedLoopOmpFactor(bool condition, unsigned int max); + protected: struct GPUProcessorProcessors : public GPUProcessor { GPUConstantMem* mProcessorsProc = nullptr; @@ -275,7 +282,7 @@ inline int GPUReconstructionCPU::runKernel(const krnlExec& x, const krnlRunRange } if (mProcessingSettings.debugLevel >= 1) { t = &getKernelTimer<S, I, J>(myStep, !IsGPU() || cpuFallback ? getOMPThreadNum() : x.stream); - if (!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback) { + if ((!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback) && (mNestedLoopOmpFactor < 2 || getOMPThreadNum() == 0)) { t->Start(); } } @@ -294,10 +301,10 @@ inline int GPUReconstructionCPU::runKernel(const krnlExec& x, const krnlRunRange } if (mProcessingSettings.debugLevel >= 1) { if (t) { - if (!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback) { - t->Stop(); - } else { + if (!(!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback)) { t->AddTime(setup.t); + } else if (mNestedLoopOmpFactor < 2 || getOMPThreadNum() == 0) { + t->Stop(); } } if (CheckErrorCodes(cpuFallback)) { @@ -346,7 +353,7 @@ HighResTimer& GPUReconstructionCPU::getTimer(const char* name, int num) static int id = getNextTimerId(); timerMeta* timer = getTimerById(id); if (timer == nullptr) { - int max = std::max({getOMPMaxThreads(), mProcessingSettings.nDeviceHelperThreads + 1, mProcessingSettings.nStreams}); + int max = std::max<int>({getOMPMaxThreads(), mProcessingSettings.nDeviceHelperThreads + 1, mProcessingSettings.nStreams}); timer = insertTimer(id, name, J, max, 1, RecoStep::NoRecoStep); } if (num == -1) { diff --git a/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx b/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx index 8bbb555ad4afa..ff404204f163c 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,7 +13,6 @@ /// \author David Rohr #ifdef GPUCA_O2_LIB -#include "DetectorsRaw/HBFUtils.h" #include "DetectorsRaw/RawFileWriter.h" #include "TPCBase/Sector.h" #include "DataFormatsTPC/Digit.h" @@ -28,14 +28,14 @@ #include <algorithm> #include <vector> -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "clusterFinderDefs.h" #include "DataFormatsTPC/ZeroSuppression.h" #include "DataFormatsTPC/Constants.h" -#include "GPURawData.h" #include "CommonConstants/LHCConstants.h" #include "DataFormatsTPC/Digit.h" #include "TPCBase/RDHUtils.h" +#include "DetectorsRaw/RDHUtils.h" #endif using namespace GPUCA_NAMESPACE::gpu; @@ -44,7 +44,7 @@ using namespace o2::tpc::constants; void GPUReconstructionConvert::ConvertNativeToClusterData(o2::tpc::ClusterNativeAccess* native, std::unique_ptr<GPUTPCClusterData[]>* clusters, unsigned int* nClusters, const TPCFastTransform* transform, int continuousMaxTimeBin) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS memset(nClusters, 0, NSLICES * sizeof(nClusters[0])); unsigned int offset = 0; for (unsigned int i = 0; i < NSLICES; i++) { @@ -83,7 +83,7 @@ void GPUReconstructionConvert::ConvertNativeToClusterData(o2::tpc::ClusterNative void GPUReconstructionConvert::ConvertRun2RawToNative(o2::tpc::ClusterNativeAccess& native, std::unique_ptr<ClusterNative[]>& nativeBuffer, const AliHLTTPCRawCluster** rawClusters, unsigned int* nRawClusters) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS memset((void*)&native, 0, sizeof(native)); for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int j = 0; j < nRawClusters[i]; j++) { @@ -115,7 +115,7 @@ void GPUReconstructionConvert::ConvertRun2RawToNative(o2::tpc::ClusterNativeAcce int GPUReconstructionConvert::GetMaxTimeBin(const ClusterNativeAccess& native) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS float retVal = 0; for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { @@ -134,7 +134,7 @@ int GPUReconstructionConvert::GetMaxTimeBin(const ClusterNativeAccess& native) int GPUReconstructionConvert::GetMaxTimeBin(const GPUTrackingInOutDigits& digits) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS float retVal = 0; for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int k = 0; k < digits.nTPCDigits[i]; k++) { @@ -151,16 +151,16 @@ int GPUReconstructionConvert::GetMaxTimeBin(const GPUTrackingInOutDigits& digits int GPUReconstructionConvert::GetMaxTimeBin(const GPUTrackingInOutZS& zspages) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS float retVal = 0; for (unsigned int i = 0; i < NSLICES; i++) { - int firstHBF = zspages.slice[i].count[0] ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const RAWDataHeaderGPU*)zspages.slice[i].zsPtr[0][0]) : 0; + int firstHBF = zspages.slice[i].count[0] ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)zspages.slice[i].zsPtr[0][0]) : 0; for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { for (unsigned int k = 0; k < zspages.slice[i].count[j]; k++) { const char* page = (const char*)zspages.slice[i].zsPtr[j][k]; for (unsigned int l = 0; l < zspages.slice[i].nZSPtr[j][k]; l++) { - RAWDataHeaderGPU* rdh = (RAWDataHeaderGPU*)(page + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); - TPCZSHDR* hdr = (TPCZSHDR*)(page + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(RAWDataHeaderGPU)); + o2::header::RAWDataHeader* rdh = (o2::header::RAWDataHeader*)(page + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); + TPCZSHDR* hdr = (TPCZSHDR*)(page + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(o2::header::RAWDataHeader)); unsigned int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN + hdr->nTimeBins; if (timeBin > retVal) { retVal = timeBin; @@ -194,14 +194,14 @@ void GPUReconstructionConvert::ZSstreamOut(unsigned short* bufIn, unsigned int& lenIn = 0; } -#ifdef HAVE_O2HEADERS -void GPUReconstructionConvert::ZSfillEmpty(void* ptr, int shift, unsigned int feeId) +#ifdef GPUCA_HAVE_O2HEADERS +void GPUReconstructionConvert::ZSfillEmpty(void* ptr, int shift, unsigned int feeId, int orbit) { - RAWDataHeaderGPU* rdh = (RAWDataHeaderGPU*)ptr; - o2::raw::RDHUtils::setHeartBeatOrbit(*rdh, 0); + o2::header::RAWDataHeader* rdh = (o2::header::RAWDataHeader*)ptr; + o2::raw::RDHUtils::setHeartBeatOrbit(*rdh, orbit); o2::raw::RDHUtils::setHeartBeatBC(*rdh, shift); - o2::raw::RDHUtils::setMemorySize(*rdh, sizeof(RAWDataHeaderGPU)); - o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>()); + o2::raw::RDHUtils::setMemorySize(*rdh, sizeof(o2::header::RAWDataHeader)); + o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>()); o2::raw::RDHUtils::setFEEID(*rdh, feeId); } @@ -223,7 +223,7 @@ static inline auto ZSEncoderGetCharge(const o2::tpc::Digit a) { return a.getChar template <class T, class S> void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigned long long int[]>* outBuffer, unsigned int* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, const GPUParam& param, bool zs12bit, bool verify, float threshold, bool padding) { - // Pass in either outBuffer / outSizes, to fill standalone output buffers, or raw / ir to use RawFileWriter + // Pass in either outBuffer / outSizes, to fill standalone output buffers, or raw to use RawFileWriter // ir is the interaction record for time bin 0 if (((outBuffer == nullptr) ^ (outSizes == nullptr)) || ((raw != nullptr) && (ir == nullptr)) || !((outBuffer == nullptr) ^ (raw == nullptr)) || (raw && verify) || (threshold > 0.f && verify)) { throw std::runtime_error("Invalid parameters"); @@ -241,11 +241,11 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne std::array<long long int, TPCZSHDR::TPC_ZS_PAGE_SIZE / sizeof(long long int)> singleBuffer; #ifdef GPUCA_O2_LIB int rawlnk = rdh_utils::UserLogicLinkID; - int bcShiftInFirstHBF = ir ? ir->bc : 0; #else int rawlnk = 15; - int bcShiftInFirstHBF = 0; #endif + int bcShiftInFirstHBF = ir ? ir->bc : 0; + int orbitShift = ir ? ir->orbit : 0; int rawcru = 0; int rawendpoint = 0; (void)(rawcru + rawendpoint); // avoid compiler warning @@ -276,7 +276,7 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne } return ZSEncoderGetPad(a) < ZSEncoderGetPad(b); }); - int lastEndpoint = -1, lastRow = GPUCA_ROW_COUNT, lastTime = -1; + int lastEndpoint = -2, lastRow = GPUCA_ROW_COUNT, lastTime = -1; long hbf = -1, nexthbf = 0; std::array<long long int, TPCZSHDR::TPC_ZS_PAGE_SIZE / sizeof(long long int)>* page = nullptr; TPCZSHDR* hdr = nullptr; @@ -310,6 +310,9 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne } if (ZSEncoderGetTime(tmpBuffer[k]) != lastTime) { nexthbf = ((long)ZSEncoderGetTime(tmpBuffer[k]) * LHCBCPERTIMEBIN + bcShiftInFirstHBF) / o2::constants::lhc::LHCMaxBunches; + if (nexthbf < 0) { + throw std::runtime_error("Received digit before the defined first orbit"); + } if (hbf != nexthbf) { lastEndpoint = -2; } @@ -331,6 +334,8 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne // sizeChk += (seqLen * encodeBits + streamSizeChkBits + 7) / 8; // printf("Endpoint %d (%d), Pos %d, Chk %d, Len %d, rows %d, StreamSize %d %d, time %d (%d), row %d (%d), pad %d\n", endpoint, lastEndpoint, (int) (pagePtr - reinterpret_cast<unsigned char*>(page)), sizeChk, seqLen, nRowsInTB, streamSize8, streamSize, (int) ZSEncoderGetTime(tmpBuffer[k]), lastTime, (int) ZSEncoderGetRow(tmpBuffer[k]), lastRow, ZSEncoderGetPad(tmpBuffer[k])); } + } else { + nexthbf = -1; } if (k >= tmpBuffer.size() || endpoint != lastEndpoint || ZSEncoderGetTime(tmpBuffer[k]) != lastTime) { if (pagePtr != reinterpret_cast<unsigned char*>(page)) { @@ -347,19 +352,19 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne } if (page && (k >= tmpBuffer.size() || endpoint != lastEndpoint)) { const rdh_utils::FEEIDType rawfeeid = rdh_utils::getFEEID(rawcru, rawendpoint, rawlnk); + size_t size = (padding || lastEndpoint == -1 || hbf == nexthbf) ? TPCZSHDR::TPC_ZS_PAGE_SIZE : (pagePtr - (unsigned char*)page); + size = CAMath::nextMultipleOf<o2::raw::RDHUtils::GBTWord>(size); #ifdef GPUCA_O2_LIB if (raw) { - size_t size = (padding || lastEndpoint == -1) ? TPCZSHDR::TPC_ZS_PAGE_SIZE : (pagePtr - (unsigned char*)page); - size = CAMath::nextMultipleOf<o2::raw::RDHUtils::GBTWord>(size); - raw->addData(rawfeeid, rawcru, rawlnk, rawendpoint, *ir + hbf * o2::constants::lhc::LHCMaxBunches, gsl::span<char>((char*)page + sizeof(RAWDataHeaderGPU), (char*)page + size), true); + raw->addData(rawfeeid, rawcru, rawlnk, rawendpoint, *ir + (hbf - orbitShift) * o2::constants::lhc::LHCMaxBunches, gsl::span<char>((char*)page + sizeof(o2::header::RAWDataHeader), (char*)page + size), true); } else #endif { - RAWDataHeaderGPU* rdh = (RAWDataHeaderGPU*)page; - o2::raw::RDHUtils::setHeartBeatOrbit(*rdh, hbf); + o2::header::RAWDataHeader* rdh = (o2::header::RAWDataHeader*)page; + o2::raw::RDHUtils::setHeartBeatOrbit(*rdh, hbf + orbitShift); o2::raw::RDHUtils::setHeartBeatBC(*rdh, bcShiftInFirstHBF); - o2::raw::RDHUtils::setMemorySize(*rdh, TPCZSHDR::TPC_ZS_PAGE_SIZE); - o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>()); + o2::raw::RDHUtils::setMemorySize(*rdh, size); + o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>()); o2::raw::RDHUtils::setFEEID(*rdh, rawfeeid); } } @@ -371,10 +376,10 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne if (raw) { page = &singleBuffer; } else { - if (buffer[i][endpoint].size() == 0 && nexthbf != 0) { - // Emplace empty page with RDH containing beginning of TFgpuDigitsMap + if (buffer[i][endpoint].size() == 0 && nexthbf > orbitShift) { + // Emplace empty page with RDH containing beginning of TF buffer[i][endpoint].emplace_back(); - ZSfillEmpty(&buffer[i][endpoint].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(i * 10 + endpoint / 2, endpoint & 1, rawlnk)); + ZSfillEmpty(&buffer[i][endpoint].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(i * 10 + endpoint / 2, endpoint & 1, rawlnk), orbitShift); totalPages++; } buffer[i][endpoint].emplace_back(); @@ -383,14 +388,14 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne hbf = nexthbf; pagePtr = reinterpret_cast<unsigned char*>(page); std::fill(page->begin(), page->end(), 0); - pagePtr += sizeof(RAWDataHeaderGPU); + pagePtr += sizeof(o2::header::RAWDataHeader); hdr = reinterpret_cast<TPCZSHDR*>(pagePtr); pagePtr += sizeof(*hdr); hdr->version = zs12bit ? 2 : 1; hdr->cruID = i * 10 + region; rawcru = i * 10 + region; rawendpoint = endpoint & 1; - hdr->timeOffset = ZSEncoderGetTime(tmpBuffer[k]) * LHCBCPERTIMEBIN - (hbf - 0) * o2::constants::lhc::LHCMaxBunches; + hdr->timeOffset = (long)ZSEncoderGetTime(tmpBuffer[k]) * LHCBCPERTIMEBIN - (long)hbf * o2::constants::lhc::LHCMaxBunches; lastTime = -1; tbHdr = nullptr; lastEndpoint = endpoint; @@ -435,7 +440,7 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { if (buffer[i][j].size() == 0) { buffer[i][j].emplace_back(); - ZSfillEmpty(&buffer[i][j].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(i * 10 + j / 2, j & 1, rawlnk)); + ZSfillEmpty(&buffer[i][j].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(i * 10 + j / 2, j & 1, rawlnk), orbitShift); totalPages++; } } @@ -446,15 +451,15 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne std::vector<o2::tpc::Digit> compareBuffer; compareBuffer.reserve(tmpBuffer.size()); for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - unsigned int firstOrbit = o2::raw::RDHUtils::getHeartBeatOrbit(*(const RAWDataHeaderGPU*)buffer[i][j].data()); + unsigned int firstOrbit = o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)buffer[i][j].data()); for (unsigned int k = 0; k < buffer[i][j].size(); k++) { page = &buffer[i][j][k]; pagePtr = reinterpret_cast<unsigned char*>(page); - const RAWDataHeaderGPU* rdh = (const RAWDataHeaderGPU*)pagePtr; - if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(RAWDataHeaderGPU)) { + const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)pagePtr; + if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) { continue; } - pagePtr += sizeof(RAWDataHeaderGPU); + pagePtr += sizeof(o2::header::RAWDataHeader); hdr = reinterpret_cast<TPCZSHDR*>(pagePtr); pagePtr += sizeof(*hdr); if (hdr->version != 1 && hdr->version != 2) { @@ -475,7 +480,7 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne } int nRowsRegion = param.tpcGeometry.GetRegionRows(region); - int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; + int timeBin = (hdr->timeOffset + (unsigned long)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; for (int l = 0; l < hdr->nTimeBins; l++) { if ((pagePtr - reinterpret_cast<unsigned char*>(page)) & 1) { pagePtr++; @@ -569,7 +574,7 @@ void GPUReconstructionConvert::RunZSEncoderCreateMeta(const unsigned long long i void GPUReconstructionConvert::RunZSFilter(std::unique_ptr<o2::tpc::Digit[]>* buffers, const o2::tpc::Digit* const* ptrs, size_t* nsb, const size_t* ns, const GPUParam& param, bool zs12bit, float threshold) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS for (unsigned int i = 0; i < NSLICES; i++) { if (buffers[i].get() != ptrs[i] || nsb != ns) { throw std::runtime_error("Not owning digits"); diff --git a/GPU/GPUTracking/Base/GPUReconstructionConvert.h b/GPU/GPUTracking/Base/GPUReconstructionConvert.h index 56799c160da23..dc4dbcb91860d 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionConvert.h +++ b/GPU/GPUTracking/Base/GPUReconstructionConvert.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,14 +33,14 @@ class RawFileWriter; } // namespace raw } // namespace o2 -class AliHLTTPCRawCluster; +struct AliHLTTPCRawCluster; namespace GPUCA_NAMESPACE { namespace gpu { -class GPUParam; -class GPUTPCClusterData; +struct GPUParam; +struct GPUTPCClusterData; class TPCFastTransform; struct GPUTrackingInOutDigits; struct GPUTrackingInOutZS; @@ -51,7 +52,7 @@ class GPUReconstructionConvert static void ConvertNativeToClusterData(o2::tpc::ClusterNativeAccess* native, std::unique_ptr<GPUTPCClusterData[]>* clusters, unsigned int* nClusters, const TPCFastTransform* transform, int continuousMaxTimeBin = 0); static void ConvertRun2RawToNative(o2::tpc::ClusterNativeAccess& native, std::unique_ptr<o2::tpc::ClusterNative[]>& nativeBuffer, const AliHLTTPCRawCluster** rawClusters, unsigned int* nRawClusters); template <class T, class S> - static void RunZSEncoder(const S& in, std::unique_ptr<unsigned long long int[]>* outBuffer, unsigned int* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, const GPUParam& param, bool zs12bit, bool verify, float threshold = 0.f, bool padding = true); + static void RunZSEncoder(const S& in, std::unique_ptr<unsigned long long int[]>* outBuffer, unsigned int* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, const GPUParam& param, bool zs12bit, bool verify, float threshold = 0.f, bool padding = false); static void RunZSEncoderCreateMeta(const unsigned long long int* buffer, const unsigned int* sizes, void** ptrs, GPUTrackingInOutZS* out); static void RunZSFilter(std::unique_ptr<o2::tpc::Digit[]>* buffers, const o2::tpc::Digit* const* ptrs, size_t* nsb, const size_t* ns, const GPUParam& param, bool zs12bit, float threshold); static int GetMaxTimeBin(const o2::tpc::ClusterNativeAccess& native); @@ -60,7 +61,7 @@ class GPUReconstructionConvert private: static void ZSstreamOut(unsigned short* bufIn, unsigned int& lenIn, unsigned char* bufOut, unsigned int& lenOut, unsigned int nBits); - static void ZSfillEmpty(void* ptr, int shift, unsigned int feeId); + static void ZSfillEmpty(void* ptr, int shift, unsigned int feeId, int orbit); }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.cxx b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.cxx index 9b71edde5659c..3a834c202091e 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h index 7e81e7b59151a..21c939bf8923a 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h +++ b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,7 +47,7 @@ class GPUReconstructionDeviceBase : public GPUReconstructionCPU virtual const GPUTPCTracker* CPUTracker(int iSlice) { return &processors()->tpcTrackers[iSlice]; } - int GPUDebug(const char* state = "UNKNOWN", int stream = -1) override = 0; + int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override = 0; size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override = 0; size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override = 0; size_t GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; diff --git a/GPU/GPUTracking/Base/GPUReconstructionHelpers.h b/GPU/GPUTracking/Base/GPUReconstructionHelpers.h index 1816dde572b81..a9be3d4c8d1c0 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionHelpers.h +++ b/GPU/GPUTracking/Base/GPUReconstructionHelpers.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h index 0a7a34e089ad2..6cbb80cc71dc9 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,6 +24,7 @@ #include "GPUDef.h" #include "GPULogging.h" +#include "GPUDataTypes.h" #include <iostream> #include <fstream> @@ -37,30 +39,30 @@ #define RANDOM_ERROR //#define RANDOM_ERROR || rand() % 500 == 1 -#define GPUCA_GPUReconstructionUpdateDefailts() \ - if (mProcessingSettings.trackletConstructorInPipeline < 0) { \ - mProcessingSettings.trackletConstructorInPipeline = GPUCA_CONSTRUCTOR_IN_PIPELINE; \ - } \ - if (mProcessingSettings.trackletSelectorInPipeline < 0) { \ - mProcessingSettings.trackletSelectorInPipeline = GPUCA_SELECTOR_IN_PIPELINE; \ - } \ - if (mProcessingSettings.trackletSelectorSlices < 0) { \ - mProcessingSettings.trackletSelectorSlices = GPUCA_TRACKLET_SELECTOR_SLICE_COUNT; \ - } \ - if (mProcessingSettings.alternateBorderSort < 0) { \ - mProcessingSettings.alternateBorderSort = GPUCA_ALTERNATE_BORDER_SORT; \ - } \ - if (mProcessingSettings.mergerSortTracks < 0) { \ - mProcessingSettings.mergerSortTracks = GPUCA_SORT_BEFORE_FIT; \ - } \ - if (param().rec.loopInterpolationInExtraPass < 0) { \ - param().rec.loopInterpolationInExtraPass = GPUCA_MERGER_SPLIT_LOOP_INTERPOLATION; \ - } \ - if (mProcessingSettings.tpcCompressionGatherModeKernel < 0) { \ - mProcessingSettings.tpcCompressionGatherModeKernel = GPUCA_COMP_GATHER_KERNEL; \ - } \ - if (mProcessingSettings.tpcCompressionGatherMode < 0) { \ - mProcessingSettings.tpcCompressionGatherMode = GPUCA_COMP_GATHER_MODE; \ +#define GPUCA_GPUReconstructionUpdateDefailts() \ + if (mProcessingSettings.trackletConstructorInPipeline < 0) { \ + mProcessingSettings.trackletConstructorInPipeline = GPUCA_CONSTRUCTOR_IN_PIPELINE; \ + } \ + if (mProcessingSettings.trackletSelectorInPipeline < 0) { \ + mProcessingSettings.trackletSelectorInPipeline = GPUCA_SELECTOR_IN_PIPELINE; \ + } \ + if (mProcessingSettings.trackletSelectorSlices < 0) { \ + mProcessingSettings.trackletSelectorSlices = GPUCA_TRACKLET_SELECTOR_SLICE_COUNT; \ + } \ + if (mProcessingSettings.alternateBorderSort < 0) { \ + mProcessingSettings.alternateBorderSort = GPUCA_ALTERNATE_BORDER_SORT; \ + } \ + if (mProcessingSettings.mergerSortTracks < 0) { \ + mProcessingSettings.mergerSortTracks = GPUCA_SORT_BEFORE_FIT; \ + } \ + if (param().rec.tpc.loopInterpolationInExtraPass < 0) { \ + param().rec.tpc.loopInterpolationInExtraPass = GPUCA_MERGER_SPLIT_LOOP_INTERPOLATION; \ + } \ + if (mProcessingSettings.tpcCompressionGatherModeKernel < 0) { \ + mProcessingSettings.tpcCompressionGatherModeKernel = GPUCA_COMP_GATHER_KERNEL; \ + } \ + if (mProcessingSettings.tpcCompressionGatherMode < 0) { \ + mProcessingSettings.tpcCompressionGatherMode = GPUCA_COMP_GATHER_MODE; \ } #endif diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludesDevice.h b/GPU/GPUTracking/Base/GPUReconstructionIncludesDevice.h index a6aa6d19e8245..5a410f3fc12ab 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludesDevice.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludesDevice.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,12 +53,18 @@ using namespace GPUCA_NAMESPACE::gpu; #include "GPUTPCSliceData.cxx" #include "GPUTPCCreateSliceData.cxx" -#if defined(HAVE_O2HEADERS) +#if defined(GPUCA_HAVE_O2HEADERS) // Files for propagation with material #include "MatLayerCylSet.cxx" #include "MatLayerCyl.cxx" #include "Ray.cxx" +// O2 track model +#include "TrackParametrization.cxx" +#include "TrackParametrizationWithError.cxx" +#include "Propagator.cxx" +#include "TrackLTIntegral.cxx" + // Files for GPU dEdx #include "GPUdEdx.cxx" @@ -77,9 +84,13 @@ using namespace GPUCA_NAMESPACE::gpu; #include "GPUTPCCFClusterizer.cxx" #include "GPUTPCCFDeconvolution.cxx" #include "GPUTPCCFMCLabelFlattener.cxx" +#include "GPUTPCCFCheckPadBaseline.cxx" #include "GPUTPCCFDecodeZS.cxx" #include "GPUTPCCFGather.cxx" +// Files for output into O2 format +#include "GPUTPCGMO2Output.cxx" + // Files for TRD Tracking #include "GPUTRDTrackerKernels.cxx" #include "GPUTRDTrack.cxx" @@ -90,13 +101,17 @@ using namespace GPUCA_NAMESPACE::gpu; // Files for ITS Track Fit #include "GPUITSFitterKernels.cxx" -#if !defined(GPUCA_O2_LIB) && defined(__HIPCC__) && !defined(GPUCA_NO_ITS_TRAITS) +// Files for Refit +#include "GPUTrackingRefit.cxx" +#include "GPUTrackingRefitKernel.cxx" + +#if !defined(GPUCA_O2_LIB) && defined(__HIPCC__) && !defined(GPUCA_NO_ITS_TRAITS) && !defined(GPUCA_GPUCODE_GENRTC) #include "VertexerTraitsHIP.hip.cxx" #include "ContextHIP.hip.cxx" #include "DeviceStoreVertexerHIP.hip.cxx" #include "ClusterLinesHIP.hip.cxx" #include "UtilsHIP.hip.cxx" -#elif !defined(GPUCA_O2_LIB) && defined(__CUDACC__) && !defined(GPUCA_NO_ITS_TRAITS) +#elif !defined(GPUCA_O2_LIB) && defined(__CUDACC__) && !defined(GPUCA_NO_ITS_TRAITS) && !defined(GPUCA_GPUCODE_GENRTC) #include "TrackerTraitsNV.cu" #include "VertexerTraitsGPU.cu" #include "Context.cu" @@ -107,7 +122,7 @@ using namespace GPUCA_NAMESPACE::gpu; #include "Utils.cu" #endif // !defined(GPUCA_O2_LIB) && defined(__CUDACC__) && !defined(GPUCA_NO_ITS_TRAITS) -#endif // HAVE_O2HEADERS +#endif // GPUCA_HAVE_O2HEADERS #endif // (!defined(__OPENCL__) || defined(__OPENCLCPP__)) && !defined(GPUCA_ALIROOT_LIB) #endif // GPURECONSTRUCTIONINCLUDESDEVICE_H diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h b/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h index e9a8df719f06a..def282556eec0 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #ifndef GPURECONSTRUCTIONINCLDUESITS_H #define GPURECONSTRUCTIONINCLDUESITS_H -#if defined(HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) +#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) #include "ITStracking/TrackerTraitsCPU.h" #include "ITStracking/VertexerTraits.h" #else @@ -33,7 +34,7 @@ class VertexerTraits }; } // namespace its } // namespace o2 -#if defined(HAVE_O2HEADERS) +#if defined(GPUCA_HAVE_O2HEADERS) #include "ITStracking/Road.h" #include "ITStracking/Cluster.h" #endif diff --git a/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h b/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h index d02229280d3c9..e4a691ed10737 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h +++ b/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUReconstructionKernels.h b/GPU/GPUTracking/Base/GPUReconstructionKernels.h index 5f8bca44375db..ee3ba28d2c5b7 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionKernels.h +++ b/GPU/GPUTracking/Base/GPUReconstructionKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,8 +49,8 @@ GPUCA_KRNL(( GPUTPCGMMergerMergeBorders, variant ), (simple), (, GPUP GPUCA_KRNL_LB((GPUTPCGMMergerMergeCE ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerLinkGlobalTracks ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerCollect ), (simple), (), ()) -GPUCA_KRNL_LB((GPUTPCGMMergerSortTracks ), (simple), (), ()) -GPUCA_KRNL_LB((GPUTPCGMMergerSortTracksQPt ), (simple), (), ()) +GPUCA_KRNL(( GPUTPCGMMergerSortTracks ), (simple), (), ()) +GPUCA_KRNL(( GPUTPCGMMergerSortTracksQPt ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerSortTracksPrepare ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerPrepareClusters, step0 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerPrepareClusters, step1 ), (simple), (), ()) @@ -57,8 +58,14 @@ GPUCA_KRNL_LB((GPUTPCGMMergerPrepareClusters, step2 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerFinalize, step0 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerFinalize, step1 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCGMMergerFinalize, step2 ), (simple), (), ()) -GPUCA_KRNL_LB((GPUTPCGMMergerMergeLoopers ), (simple), (), ()) -#ifdef HAVE_O2HEADERS +GPUCA_KRNL_LB((GPUTPCGMMergerMergeLoopers, step0 ), (simple), (), ()) +GPUCA_KRNL_LB((GPUTPCGMMergerMergeLoopers, step1 ), (simple), (), ()) +GPUCA_KRNL_LB((GPUTPCGMMergerMergeLoopers, step2 ), (simple), (), ()) +#ifdef GPUCA_HAVE_O2HEADERS +GPUCA_KRNL_LB((GPUTPCGMO2Output, prepare ), (simple), (), ()) +GPUCA_KRNL(( GPUTPCGMO2Output, sort ), (simple), (), ()) +GPUCA_KRNL_LB((GPUTPCGMO2Output, output ), (simple), (), ()) +GPUCA_KRNL(( GPUTPCGMO2Output, mc ), (simple), (), ()) GPUCA_KRNL_LB((GPUTRDTrackerKernels ), (simple), (), ()) GPUCA_KRNL_LB((GPUITSFitterKernel ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCConvertKernel ), (simple), (), ()) @@ -69,24 +76,26 @@ GPUCA_KRNL_LB((GPUTPCCompressionGatherKernels, buffered32 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCCompressionGatherKernels, buffered64 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCCompressionGatherKernels, buffered128 ), (simple), (), ()) GPUCA_KRNL_LB((GPUTPCCompressionGatherKernels, multiBlock ), (simple), (), ()) - -GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, fillIndexMap ), (single), (), ()) -GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, fillFromDigits ), (single), (), ()) -GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, findFragmentStart ), (single), (, char setPositions), (, setPositions)) +GPUCA_KRNL_LB((GPUTPCCFCheckPadBaseline ), (single), (), ()) +GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, fillIndexMap ), (single), (), ()) +GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, fillFromDigits ), (single), (), ()) +GPUCA_KRNL_LB((GPUTPCCFChargeMapFiller, findFragmentStart ), (single), (, char setPositions), (, setPositions)) GPUCA_KRNL_LB((GPUTPCCFPeakFinder ), (single), (), ()) -GPUCA_KRNL_LB((GPUTPCCFNoiseSuppression, noiseSuppression ), (single), (), ()) -GPUCA_KRNL_LB((GPUTPCCFNoiseSuppression, updatePeaks ), (single), (), ()) +GPUCA_KRNL_LB((GPUTPCCFNoiseSuppression, noiseSuppression ), (single), (), ()) +GPUCA_KRNL_LB((GPUTPCCFNoiseSuppression, updatePeaks ), (single), (), ()) GPUCA_KRNL_LB((GPUTPCCFDeconvolution ), (single), (), ()) GPUCA_KRNL_LB((GPUTPCCFClusterizer ), (single), (, char onlyMC), (, onlyMC)) -GPUCA_KRNL(( GPUTPCCFMCLabelFlattener, setRowOffsets ), (single), (), ()) -GPUCA_KRNL(( GPUTPCCFMCLabelFlattener, flatten ), (single), (, GPUPtr1(GPUTPCLinearLabels*, out)), (, GPUPtr2(GPUTPCLinearLabels*, out))) -GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanStart ), (single), (, int iBuf, int stage), (, iBuf, stage)) -GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanUp ), (single), (, int iBuf, int nElems), (, iBuf, nElems)) -GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanTop ), (single), (, int iBuf, int nElems), (, iBuf, nElems)) -GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanDown ), (single), (, int iBuf, unsigned int offset, int nElems), (, iBuf, offset, nElems)) -GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, compactDigits ), (single), (, int iBuf, int stage, GPUPtr1(ChargePos*, in), GPUPtr1(ChargePos*, out)), (, iBuf, stage, GPUPtr2(ChargePos*, in), GPUPtr2(ChargePos*, out))) +GPUCA_KRNL(( GPUTPCCFMCLabelFlattener, setRowOffsets ), (single), (), ()) +GPUCA_KRNL(( GPUTPCCFMCLabelFlattener, flatten ), (single), (, GPUPtr1(GPUTPCLinearLabels*, out)), (, GPUPtr2(GPUTPCLinearLabels*, out))) +GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanStart ), (single), (, int iBuf, int stage), (, iBuf, stage)) +GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanUp ), (single), (, int iBuf, int nElems), (, iBuf, nElems)) +GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanTop ), (single), (, int iBuf, int nElems), (, iBuf, nElems)) +GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, scanDown ), (single), (, int iBuf, unsigned int offset, int nElems), (, iBuf, offset, nElems)) +GPUCA_KRNL_LB((GPUTPCCFStreamCompaction, compactDigits ), (single), (, int iBuf, int stage, GPUPtr1(ChargePos*, in), GPUPtr1(ChargePos*, out)), (, iBuf, stage, GPUPtr2(ChargePos*, in), GPUPtr2(ChargePos*, out))) GPUCA_KRNL_LB((GPUTPCCFDecodeZS ), (single), (, int firstHBF), (, firstHBF)) GPUCA_KRNL_LB((GPUTPCCFGather ), (single), (, GPUPtr1(o2::tpc::ClusterNative*, dest)), (, GPUPtr2(o2::tpc::ClusterNative*, dest))) +GPUCA_KRNL_LB((GPUTrackingRefitKernel, mode0asGPU ), (simple), (), ()) +GPUCA_KRNL_LB((GPUTrackingRefitKernel, mode1asTrackParCov ), (simple), (), ()) #endif #endif // clang-format on diff --git a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.cxx b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.cxx index a7cd332069943..40fa8445b9690 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -157,6 +158,7 @@ void GPUReconstructionTimeframe::MergeShiftedEvents() } mChain->mIOPtrs.nMCLabelsTPC += ptr.nMCLabelsTPC; mChain->mIOPtrs.nMCInfosTPC += ptr.nMCInfosTPC; + mChain->mIOPtrs.nMCInfosTPCCol += ptr.nMCInfosTPCCol; SetDisplayInformation(i); } unsigned int nClustersTotal = 0; @@ -179,6 +181,7 @@ void GPUReconstructionTimeframe::MergeShiftedEvents() mChain->mIOPtrs.clustersNative = nullptr; unsigned int nTrackOffset = 0; + unsigned int nColOffset = 0; unsigned int nClustersEventOffset[NSLICES] = {0}; for (unsigned int i = 0; i < mShiftedEvents.size(); i++) { auto& ptr = std::get<0>(mShiftedEvents[i]); @@ -208,7 +211,12 @@ void GPUReconstructionTimeframe::MergeShiftedEvents() } memcpy((void*)&mChain->mIOMem.mcInfosTPC[nTrackOffset], (void*)ptr.mcInfosTPC, ptr.nMCInfosTPC * sizeof(ptr.mcInfosTPC[0])); + for (unsigned int j = 0; j < ptr.nMCInfosTPCCol; j++) { + mChain->mIOMem.mcInfosTPCCol[nColOffset + j] = ptr.mcInfosTPCCol[j]; + mChain->mIOMem.mcInfosTPCCol[nColOffset + j].first += nTrackOffset; + } nTrackOffset += ptr.nMCInfosTPC; + nColOffset += ptr.nMCInfosTPCCol; } GPUInfo("Merged %d events, %u clusters total", (int)mShiftedEvents.size(), nClustersTotal); diff --git a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h index c0f21f7b94f23..244da705c3fcf 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h +++ b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/GPUSettings.cxx b/GPU/GPUTracking/Base/GPUSettings.cxx deleted file mode 100644 index f7156a1fad96d..0000000000000 --- a/GPU/GPUTracking/Base/GPUSettings.cxx +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUSettings.cxx -/// \author David Rohr - -#include "GPUSettings.h" -#include "GPUDef.h" -#include "GPUDataTypes.h" -#include <cstring> - -using namespace GPUCA_NAMESPACE::gpu; - -GPUSettingsDeviceBackend::GPUSettingsDeviceBackend() -{ - deviceType = GPUDataTypes::DeviceType::CPU; - forceDeviceType = true; - master = nullptr; -} - -GPUSettingsEvent::GPUSettingsEvent() -{ - solenoidBz = -5.00668; - constBz = 0; - homemadeEvents = 0; - continuousMaxTimeBin = 0; - needsClusterer = 0; -} diff --git a/GPU/GPUTracking/Base/GPUSettings.h b/GPU/GPUTracking/Base/GPUSettings.h deleted file mode 100644 index 5b7bda9d647ca..0000000000000 --- a/GPU/GPUTracking/Base/GPUSettings.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUSettings.h -/// \author David Rohr - -#ifndef GPUSETTINGS_H -#define GPUSETTINGS_H - -#include "GPUCommonDef.h" -#ifndef GPUCA_GPUCODE_DEVICE -#include <vector> -#include <string> -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -class GPUDisplayBackend; -class GPUReconstruction; - -class GPUSettings -{ - public: - enum CompressionModes { CompressionTruncate = 1, - CompressionDifferences = 2, - CompressionTrackModel = 4, - CompressionFull = 7 }; - enum CompressionSort { SortTime = 0, - SortPad = 1, - SortZTimePad = 2, - SortZPadTime = 3, - SortNoSort = 4 }; - enum CompressionRejection { RejectionNone = 0, - RejectionStrategyA = 1, - RejectionStrategyB = 2 }; - -#if !defined(__OPENCL__) || defined(__OPENCLCPP__) - static CONSTEXPR unsigned int TPC_MAX_TF_TIME_BIN = ((256 * 3564 + 2 * 8 - 2) / 8); -#endif -}; - -// Settings describing the events / time frames -struct GPUSettingsEvent { - // All new members must be sizeof(int) resp. sizeof(float) for alignment reasons! - GPUSettingsEvent(); - float solenoidBz; // solenoid field strength - int constBz; // for test-MC events with constant Bz - int homemadeEvents; // Toy-MC events - int continuousMaxTimeBin; // 0 for triggered events, -1 for default of 23ms - int needsClusterer; // Set to true if the data requires the clusterizer -}; - -// Settings defining the setup of the GPUReconstruction processing (basically selecting the device / class instance) -struct GPUSettingsDeviceBackend { - GPUSettingsDeviceBackend(); - unsigned int deviceType; // Device type, shall use GPUDataTypes::DEVICE_TYPE constants, e.g. CPU / CUDA - char forceDeviceType; // Fail if device initialization fails, otherwise falls back to CPU - GPUReconstruction* master; // GPUReconstruction master object -}; - -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#ifdef GPUCA_GPUCODE_DEVICE -#define QCONFIG_GPU -#endif -// See GPUSettingsList.h for a list of all available settings of GPU Reconstruction -#ifndef GPUCA_GPUCODE_GENRTC -#include "utils/qconfig.h" -#endif - -#endif diff --git a/GPU/GPUTracking/Base/GPUSettingsList.h b/GPU/GPUTracking/Base/GPUSettingsList.h deleted file mode 100644 index 75a7da4f77154..0000000000000 --- a/GPU/GPUTracking/Base/GPUSettingsList.h +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUSettingsList.h -/// \author David Rohr - -// This file contains macros to generate all settings for the GPU Reconstruction. -// Macros are used in the following places: -// Create ConfigurableParam object for workflow. -// Configure standalone benchmark. -// Create plain-C struct for GPU code. -// Create static constexpr with default values for GPU run time compilation - -#include "GPUDefConstantsAndSettings.h" -#ifndef GPUSETTINGS_H -#error Please include GPUSettings.h! -#endif - -// clang-format off - -#ifdef QCONFIG_INSTANCE -using namespace GPUCA_NAMESPACE::gpu; -#endif -#ifdef BeginNamespace // File should not be included without defining the macros, but rootcling will do for dictionary generation -BeginNamespace(GPUCA_NAMESPACE) -BeginNamespace(gpu) - -// Settings concerning the reconstruction -// There must be no bool in here, use char, as sizeof(bool) is compiler dependent and fails on GPUs!!!!!! -BeginSubConfig(GPUSettingsRec, rec, configStandalone, "REC", 0, "Reconstruction settings") -AddOptionRTC(tpcRejectQPt, float, 1.f / 0.05f, "", 0, "QPt threshold to reject clusters of TPC tracks (Inverse Pt!!!)") -AddOptionRTC(HitPickUpFactor, float, 2., "", 0, "multiplier for the chi2 window for hit pick up procedure") -AddOptionRTC(NeighboursSearchArea, float, 3., "", 0, "area in cm for the search of neighbours") -AddOptionRTC(ClusterError2CorrectionY, float, 1., "", 0, "correction for the squared cluster error during tracking") -AddOptionRTC(ClusterError2CorrectionZ, float, 1., "", 0, "correction for the squared cluster error during tracking") -AddOptionRTC(MinNTrackClusters, int, -1, "", 0, "required min number of clusters on the track") -AddOptionRTC(MaxTrackQPt, float, 1.f / GPUCA_MIN_TRACK_PT_DEFAULT, "", 0, "required max Q/Pt (==min Pt) of tracks") -AddOptionRTC(SearchWindowDZDR, float, 2.5, "", 0, "Use DZDR window for seeding instead of vertex window") -AddOptionRTC(TrackReferenceX, float, 1000.f, "", 0, "Transport all tracks to this X after tracking (disabled if > 500, auto = 1000)") -AddOptionRTC(tpcZSthreshold, float, 2.0f, "", 0, "Zero-Suppression threshold") -AddOptionRTC(tpcTubeChi2, float, 5.f * 5.f, "", 0, "Max chi2 to mark cluster adjacent to track") -AddOptionRTC(tpcTubeMaxSize2, float, 2.5f * 2.5f, "", 0, "Square of max tube size (normally derrived from tpcTubeChi2)") -AddOptionRTC(trdMinTrackPt, float, .5f, "", 0, "Min Pt for tracks to be propagated through the TRD") -AddOptionRTC(trdMaxChi2, float, 15.f, "", 0, "Max chi2 for TRD tracklets to be matched to a track") -AddOptionRTC(trdPenaltyChi2, float, 12.f, "", 0, "Chi2 penalty for no available TRD tracklet (effective chi2 cut value)") -AddOptionRTC(tpcCFqmaxCutoff, unsigned char, 3, "", 0, "Cluster Finder rejects cluster with qmax below this threshold") -AddOptionRTC(tpcCFqtotCutoff, unsigned char, 0, "", 0, "Cluster Finder rejects cluster with qtot below this threshold") -AddOptionRTC(tpcCFinnerThreshold, unsigned char, 0, "", 0, "Cluster Finder extends cluster if inner charge above this threshold") -AddOptionRTC(tpcCFminSplitNum, unsigned char, 1, "", 0, "Minimum number of split charges in a cluster for the cluster to be marked as split") -AddOptionRTC(tpcCFnoiseSuppressionEpsilon, unsigned char, 10, "", 0, "Cluster Finder: Difference between peak and charge for the charge to count as a minima during noise suppression") -AddOptionRTC(NWays, char, 3, "", 0, "Do N fit passes in final fit of merger") -AddOptionRTC(NWaysOuter, char, 0, "", 0, "Store outer param") -AddOptionRTC(RejectMode, char, 5, "", 0, "0: no limit on rejection or missed hits, >0: break after n rejected hits, <0: reject at max -n hits") -AddOptionRTC(NonConsecutiveIDs, char, false, "", 0, "Non-consecutive cluster IDs as in HLT, disables features that need access to slice data in TPC merger") -AddOptionRTC(dEdxTruncLow, unsigned char, 2, "", 0, "Low truncation threshold, fraction of 128") -AddOptionRTC(dEdxTruncHigh, unsigned char, 77, "", 0, "High truncation threshold, fraction of 128") -AddOptionRTC(GlobalTracking, char, 1, "", 0, "Enable Global Tracking (prolong tracks to adjacent sectors to find short segments)") -AddOptionRTC(DisableRefitAttachment, unsigned char, 0, "", 0, "Bitmask to disable certain attachment steps during refit (1: attachment, 2: propagation, 4: loop following, 8: mirroring)") -AddOptionRTC(tpcRejectionMode, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression (0 = no, 1 = strategy A, 2 = strategy B)") -AddOptionRTC(tpcMergeLoopersAfterburner, unsigned char, 0, "", 0, "Run afterburner for additional looper merging") -AddOptionRTC(tpcCompressionModes, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits (1=truncate charge/width LSB, 2=differences, 4=track-model)") -AddOptionRTC(tpcCompressionSortOrder, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression (0 = time, 1 = pad, 2 = Z-time-pad, 3 = Z-pad-time, 4 = no sorting (use incoming order))") -AddOptionRTC(tpcSigBitsCharge, unsigned char, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") -AddOptionRTC(tpcSigBitsWidth, unsigned char, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") -AddOptionRTC(ForceEarlyTPCTransform, char, -1, "", 0, "Force early TPC transformation also for continuous data (-1 = auto)") -AddOptionRTC(fwdTPCDigitsAsClusters, unsigned char, 0, "", 0, "Forward TPC digits as clusters (if they pass the ZS threshold)") -AddOptionRTC(bz0Pt, unsigned char, 60, "", 0, "Nominal Pt to set when bz = 0 (in 10 MeV)") -AddOptionRTC(dropLoopers, unsigned char, 0, "", 0, "Drop looping tracks starting from second loop") -AddOptionRTC(mergerCovSource, unsigned char, 2, "", 0, "Method to obtain covariance in track merger: 0 = simple filterErrors method, 1 = use cov from track following, 2 = refit") -AddOptionRTC(mergerInterpolateErrors, unsigned char, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") -AddOptionRTC(fitInProjections, char, -1, "", 0, "Fit in projection, -1 to enable for all but passes but the first one") -AddOptionRTC(fitPropagateBzOnly, char, -1, "", 0, "Propagate using Bz only for n passes") -AddOptionRTC(retryRefit, char, 1, "", 0, "Retry refit when fit fails") -AddOptionRTC(loopInterpolationInExtraPass, char, -1, "", 0, "Perform loop interpolation in an extra pass") -AddOptionRTC(mergerReadFromTrackerDirectly, char, 1, "", 0, "Forward data directly from tracker to merger on GPU") -AddOptionRTC(useMatLUT, char, 0, "", 0, "Use material lookup table for TPC refit") -AddOptionRTC(trdStopTrkAfterNMissLy, unsigned char, 6, "", 0, "Abandon track following after N layers without a TRD match") -AddCustomCPP(void SetMinTrackPt(float v) { MaxTrackQPt = v > 0.001 ? (1. / v) : (1. / 0.001); }) -AddVariable(dummyRTC, float, 0.f) // Ensure non empty struct and proper alignment even if all normal members are constexpr -AddHelp("help", 'h') -EndConfig() - -// Settings steering the processing once the device was selected -BeginSubConfig(GPUSettingsProcessing, proc, configStandalone, "PROC", 0, "Processing settings") -AddOption(platformNum, int, -1, "", 0, "Platform to use, in case the backend provides multiple platforms (-1 = auto-select)") -AddOption(trdNCandidates, int, 1, "", 0, "Number of branching track candidates for single input track during propagation") -AddOption(trdNMaxCollisions, int, 1000, "", 0, "Maximum number of collisions per TF which the TRD tracker can handle") -AddOption(gpuDeviceOnly, bool, false, "", 0, "Use only GPU as device (i.e. no CPU for OpenCL)") -AddOption(debugMask, int, -1, "", 0, "Mask for debug output dumps to file") -AddOption(comparableDebutOutput, bool, true, "", 0, "Make CPU and GPU debug output comparable (sort / skip concurrent parts)") -AddOption(resetTimers, int, 1, "", 0, "Reset timers every event") -AddOption(stuckProtection, int, 0, "", 0, "Timeout in us, When AMD GPU is stuck, just continue processing and skip tracking, do not crash or stall the chain") -AddOption(keepAllMemory, bool, false, "", 0, "Allocate all memory on both device and host, and do not reuse") -AddOption(keepDisplayMemory, bool, false, "", 0, "Like keepAllMemory, but only for memory required for event display") -AddOption(trackletSelectorSlices, char, -1, "", 0, "Number of slices to processes in parallel at max") -AddOption(nTPCClustererLanes, int, 3, "", 0, "Number of TPC clusterers that can run in parallel") -AddOption(disableMemoryReuse, bool, false, "", 0, "Disable memory reusage (for debugging only)") -AddOption(fullMergerOnGPU, bool, true, "", 0, "Perform full TPC track merging on GPU instead of only refit") -AddOption(delayedOutput, bool, true, "", 0, "Delay output to be parallel to track fit") -AddOption(tpccfGatherKernel, bool, true, "", 0, "Use a kernel instead of the DMA engine to gather the clusters") -AddOption(doublePipelineClusterizer, bool, true, "", 0, "Include the input data of the clusterizer in the double-pipeline") -AddOption(deviceNum, int, -1, "gpuDevice", 0, "Set GPU device to use (-1: automatic, -2: for round-robin usage in timeslice-pipeline)") -AddOption(globalInitMutex, bool, false, "", 0, "Use global mutex to synchronize initialization of multiple GPU instances") -AddOption(ompThreads, int, -1, "omp", 't', "Number of OMP threads to run (-1: all)", min(-1), message("Using %d OMP threads")) -AddOption(nDeviceHelperThreads, int, 1, "", 0, "Number of CPU helper threads for CPU processing") -AddOption(nStreams, int, 8, "", 0, "Number of GPU streams / command queues") -AddOption(trackletConstructorInPipeline, int, -1, "", 0, "Run tracklet constructor in the pipeline") -AddOption(trackletSelectorInPipeline, int, -1, "", 0, "Run tracklet selector in the pipeline") -AddOption(mergerSortTracks, int, -1, "", 0, "Sort track indizes for GPU track fit") -AddOption(tpcCompressionGatherMode, int, -1, "", 0, "TPC Compressed Clusters Gather Mode (0: DMA transfer gather gpu to host, 1: serial DMA to host and gather by copy on CPU, 2. gather via GPU kernal DMA access, 3. gather on GPU via kernel, dma afterwards") -AddOption(tpcCompressionGatherModeKernel, int, -1, "", 0, "TPC Compressed Clusters Gather Mode Kernel (0: unbufferd, 1-3: buffered, 4: multi-block)") -AddOption(runMC, bool, false, "", 0, "Process MC labels") -AddOption(ompKernels, bool, true, "", 0, "Parallelize with OMP inside kernels instead of over slices") -AddOption(doublePipeline, bool, false, "", 0, "Double pipeline mode") -AddOption(prefetchTPCpageScan, int, 0, "", 0, "Prefetch Data for TPC page scan in CPU cache") -AddOption(debugLevel, int, -1, "debug", 'd', "Set debug level (-1 = silend)") -AddOption(allocDebugLevel, int, 0, "allocDebug", 0, "Some debug output for memory allocations (without messing with normal debug level)") -AddOption(runQA, bool, false, "qa", 'q', "Enable tracking QA", message("Running QA: %s")) -AddOption(runCompressionStatistics, bool, false, "compressionStat", 0, "Run statistics and verification for cluster compression") -AddOption(forceMemoryPoolSize, unsigned long, 1, "memSize", 0, "Force size of allocated GPU / page locked host memory", min(0ul)) -AddOption(forceHostMemoryPoolSize, unsigned long, 0, "hostMemSize", 0, "Force size of allocated host page locked host memory (overriding memSize)", min(0ul)) -AddOption(memoryAllocationStrategy, int, 0, "", 0, "Memory Allocation Stragegy (0 = auto, 1 = individual allocations, 2 = single global allocation)") -AddOption(deviceTimers, bool, true, "", 0, "Use device timers instead of host-based time measurement") -AddOption(registerStandaloneInputMemory, bool, false, "registerInputMemory", 0, "Automatically register input memory buffers for the GPU") -AddOption(memoryScalingFactor, float, 1.f, "", 0, "Factor to apply to all memory scalers") -AddOption(alternateBorderSort, int, -1, "", 0, "Alternative implementation for sorting of border tracks") -AddOption(enableRTC, bool, false, "", 0, "Use RTC to optimize GPU code") -AddOption(rtcConstexpr, bool, true, "", 0, "Replace constant variables by static constexpr expressions") -AddOption(showOutputStat, bool, false, "", 0, "Print some track output statistics") -AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayBackend*, nullptr) -AddHelp("help", 'h') -EndConfig() - -#ifndef GPUCA_GPUCODE_DEVICE -// Settings concerning the event display -BeginSubConfig(GPUSettingsDisplay, GL, configStandalone, "GL", 'g', "OpenGL display settings") -AddOption(clustersOnly, bool, false, "", 0, "Visualize clusters only") -AddHelp("help", 'h') -EndConfig() - -// Settings concerning the standalone QA -BeginSubConfig(GPUSettingsQA, QA, configStandalone, "QA", 'q', "QA settings") -AddOptionVec(compareInputs, const char*, "QAinput", 0, "Read histogram from these input files and include them in the output plots") -AddOptionVec(compareInputNames, const char*, "QAinputName", 0, "Legend entries for data from comparison histogram files") -AddOption(name, std::string, "", "", 0, "Legend entry for new data from current processing") -AddOption(output, std::string, "", "", 0, "Store histograms in output root file", def(std::string("histograms.root"))) -AddOption(inputHistogramsOnly, bool, false, "", 0, "Do not run tracking, but just create PDFs from input root files") -AddOption(strict, bool, true, "", 0, "Strict QA mode: Only consider resolution of tracks where the fit ended within 5 cm of the reference, and remove outliers.") -AddOption(qpt, float, 10.f, "", 0, "Set cut for Q/Pt", def(2.f)) -AddOption(recThreshold, float, 0.9f, "", 0, "Compute the efficiency including impure tracks with fake contamination") -AddOption(csvDump, bool, false, "", 0, "Dump all clusters and Pt information into csv file") -AddOption(maxResX, float, 1e6f, "", 0, "Maxmimum X (~radius) for reconstructed track position to take into accound for resolution QA in cm") -AddOption(resPrimaries, int, 0, "", 0, "0: Resolution for all tracks, 1: only for primary tracks, 2: only for non-primaries", def(1)) -AddOption(nativeFitResolutions, bool, false, "", 0, "Create resolution histograms in the native fit units (sin(phi), tan(lambda), Q/Pt)") -AddOption(filterCharge, int, 0, "", 0, "Filter for positive (+1) or negative (-1) charge") -AddOption(filterPID, int, -1, "", 0, "Filter for Particle Type (0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton)") -AddOption(writeMCLabels, bool, false, "", 0, "Store mc labels to file for later matching") -AddOptionVec(matchMCLabels, const char*, "", 0, "Read labels from files and match them, only process tracks where labels differ") -AddOption(matchDisplayMinPt, float, 0, "", 0, "Minimum Pt of a matched track to be displayed") -AddOption(writeRootFiles, bool, false, "", 0, "Create ROOT canvas files") -AddOption(noMC, bool, false, "", 0, "Force running QA without MC labels even if present") -AddOption(shipToQC, bool, false, "", 0, "Do not write output files but ship histograms for QC") -AddOption(shipToQCAsCanvas, bool, false, "", 0, "Send TCanvases with full layout to QC instead of individual histograms") -AddShortcut("compare", 0, "--QAinput", "Compare QA histograms", "--qa", "--QAinputHistogramsOnly") -AddHelp("help", 'h') -EndConfig() - -#ifdef GPUCA_STANDALONE -// Settings concerning the standlone timeframe from run 2 events assembly tool -BeginSubConfig(GPUSettingsTF, TF, configStandalone, "TF", 't', "Timeframe settings") -AddOption(nMerge, int, 0, "", 0, "Merge n events in a timeframe", min(0)) -AddOption(averageDistance, float, 50., "", 0, "Average distance in cm of events merged into timeframe", min(0.f)) -AddOption(randomizeDistance, bool, true, "", 0, "Randomize distance around average distance of merged events") -AddOption(shiftFirstEvent, bool, true, "", 0, "Also shift the first event in z when merging events to a timeframe") -AddOption(bunchSim, int, 0, "", 0, "Simulate correct bunch interactions instead of placing only the average number of events. A value [n] > 1 sets TFlen for [n] collisions in average. (Incompatible to TFmerge)") -AddOption(bunchCount, int, 12, "", 0, "Number of bunches per trainsort") -AddOption(bunchSpacing, int, 50, "", 0, "Spacing between benches in ns") -AddOption(bunchTrainCount, int, 48, "", 0, "Number of bunch trains") -AddOption(abortGapTime, int, (3000), "", 0, "Length of abort gap in ns") -AddOption(interactionRate, int, 50000, "", 0, "Instantaneous interaction rate") -AddOption(timeFrameLen, long, (1000000000 / 44), "", 'l', "Timeframe len in ns") -AddOption(noBorder, bool, false, "", 0, "Do not simulate border effects (partial events)") -AddOption(noEventRepeat, int, 0, "", 0, "0: Place random events, 1: Place events in timeframe one after another, 2: Place random events but do not repat", def(1)) -AddOption(nTotalEventsInTF, int, 0, "", 0, "Total number of collisions to be placed in the interior of all time frames (excluding borders)") -AddOption(eventStride, int, 0, "", 0, "Do not select random event, but walk over array of events in stride steps") -AddOption(overlayRaw, bool, false, "", 0, "Overlay raw TPC data instead of spatial clusters") -AddHelp("help", 'h') -EndConfig() - -// Settings concerning standalone toy event generator -BeginSubConfig(GPUSettingsEG, EG, configStandalone, "EG", 0, "Event generator settings") -AddOption(numberOfTracks, int, 1, "", 0, "Number of tracks per generated event") -AddHelp("help", 'h') -EndConfig() - -// Settings for the standalone benchmark -BeginConfig(GPUSettingsStandalone, configStandalone) -#if defined(CUDA_ENABLED) || defined(OPENCL1_ENABLED) || defined(OPENCL2_ENABLED) || defined(HIP_ENABLED) -AddOption(runGPU, bool, true, "", 'g', "Use GPU for processing", message("GPU processing: %s")) -#else -AddOption(runGPU, bool, false, "", 'g', "Use GPU for processing", message("GPU processing: %s")) -#endif -AddOptionSet(runGPU, bool, false, "", 'c', "Use CPU for processing", message("CPU enabled")) -#if defined(CUDA_ENABLED) -AddOption(gpuType, const char*, "CUDA", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") -#elif defined(OPENCL2_ENABLED) -AddOption(gpuType, const char*, "OCL2", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") -#elif defined(OPENCL1_ENABLED) -AddOption(gpuType, const char*, "OCL", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") -#elif defined(HIP_ENABLED) -AddOption(gpuType, const char*, "HIP", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") -#else -AddOption(gpuType, const char*, "", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") -#endif -AddOption(runGPUforce, bool, true, "", 0, "Force usage of the specified GPU device type, no CPU fallback") -AddOption(noprompt, bool, true, "", 0, "Do prompt for keypress before exiting") -AddOption(continueOnError, bool, false, "", 0, "Continue processing after an error") -AddOption(seed, int, -1, "", 0, "Set srand seed (-1: random)") -AddOption(StartEvent, int, 0, "", 's', "First event to process", min(0)) -AddOption(NEvents, int, -1, "", 'n', "Number of events to process (-1; all)", min(0)) -AddOption(runs, int, 1, "runs", 'r', "Number of iterations to perform (repeat each event)", min(0)) -AddOption(runs2, int, 1, "runsExternal", 0, "Number of iterations to perform (repeat full processing)", min(1)) -AddOption(runsInit, int, 1, "", 0, "Number of initial iterations excluded from average", min(0)) -AddOption(EventsDir, const char*, "pp", "events", 'e', "Directory with events to process", message("Reading events from Directory events/%s")) -AddOption(eventDisplay, int, 0, "display", 'd', "Show standalone event display", def(1)) //1: default display (Windows / X11), 2: glut, 3: glfw -AddOption(eventGenerator, bool, false, "", 0, "Run event generator") -AddOption(cont, bool, false, "", 0, "Process continuous timeframe data") -AddOption(outputcontrolmem, unsigned long, 0, "outputMemory", 0, "Use predefined output buffer of this size", min(0ul), message("Using %lld bytes as output memory")) -AddOption(inputcontrolmem, unsigned long, 0, "inputMemory", 0, "Use predefined input buffer of this size", min(0ul), message("Using %lld bytes as input memory")) -AddOption(cpuAffinity, int, -1, "", 0, "Pin CPU affinity to this CPU core", min(-1)) -AddOption(fifoScheduler, bool, false, "", 0, "Use FIFO realtime scheduler", message("Setting FIFO scheduler: %s")) -AddOption(fpe, bool, true, "", 0, "Trap on floating point exceptions") -AddOption(flushDenormals, bool, true, "", 0, "Enable FTZ and DAZ (Flush all denormals to zero)") -AddOption(solenoidBz, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") -AddOption(constBz, bool, false, "", 0, "Force constand Bz") -AddOption(overrideMaxTimebin, bool, false, "", 0, "Override max time bin setting for continuous data with max time bin in time frame") -AddOption(encodeZS, int, -1, "", 0, "Zero-Suppress TPC data", def(1)) -AddOption(zsFilter, int, -1, "", 0, "Apply Zero-Suppression when loading digits and remove those below threshold", def(1)) -AddOption(zs12bit, bool, true, "", 0, "Perform 12 bit zero-suppression encoding / filter") -AddOption(dumpEvents, bool, false, "", 0, "Dump events (after transformation such as encodeZS") -AddOption(stripDumpedEvents, bool, false, "", 0, "Remove redundant inputs (e.g. digits and ZS) before dumping") -AddOption(printSettings, bool, false, "", 0, "Print all settings") -AddOption(memoryStat, bool, false, "", 0, "Print memory statistics") -AddOption(testSyncAsync, bool, false, "syncAsync", 0, "Test first synchronous and then asynchronous processing") -AddOption(testSync, bool, false, "sync", 0, "Test settings for synchronous phase") -AddOption(timeFrameTime, bool, false, "tfTime", 0, "Print some debug information about time frame processing time") -AddOption(controlProfiler, bool, false, "", 0, "Issues GPU profiler stop and start commands to profile only the relevant processing part") -AddOption(preloadEvents, bool, false, "", 0, "Preload events into host memory before start processing") -AddOption(recoSteps, int, -1, "", 0, "Bitmask for RecoSteps") -AddOption(recoStepsGPU, int, -1, "", 0, "Bitmask for RecoSteps") -AddOption(runMerger, int, 1, "", 0, "Run track merging / refit", min(0), max(1)) -AddOption(runTRD, int, -1, "", 0, "Enable TRD processing") -AddOption(rundEdx, int, -1, "", 0, "Enable dEdx processing") -AddOption(runCompression, int, 1, "", 0, "Enable TPC Compression") -AddOption(runTransformation, int, 1, "", 0, "Enable TPC Transformation") -AddOption(runRefit, bool, false, "", 0, "Enable final track refit") -AddHelp("help", 'h') -AddHelpAll("helpall", 'H') -AddSubConfig(GPUSettingsRec, rec) -AddSubConfig(GPUSettingsProcessing, proc) -AddSubConfig(GPUSettingsTF, TF) -AddSubConfig(GPUSettingsQA, QA) -AddSubConfig(GPUSettingsDisplay, GL) -AddSubConfig(GPUSettingsEG, EG) -EndConfig() -#elif defined(GPUCA_O2_LIB) || defined(GPUCA_O2_INTERFACE) // GPUCA_STANDALONE -BeginSubConfig(GPUSettingsO2, global, configStandalone, "O2", 0, "O2 workflow settings") -AddOption(solenoidBz, float, -1e6f, "", 0, "solenoid field strength") -AddOption(constBz, bool, false, "", 0, "force constant Bz for tests") -AddOption(continuousMaxTimeBin, int, 0, "", 0, "maximum time bin of continuous data, 0 for triggered events, -1 for default of 23ms") -AddOption(deviceType, std::string, "CPU", "", 0, "Device type, CPU | CUDA | HIP | OCL1 | OCL2") -AddOption(forceDeviceType, bool, true, "", 0, "force device type, otherwise allows fall-back to CPU") -AddOption(dump, int, 0, "", 0, "Dump events for standalone benchmark: 1 = dump events, 2 = dump events and skip processing in workflow") -AddOption(runDisplay, bool, false, "", 0, "Run event visualization after processing") -AddOption(dEdxFile, std::string, "", "", 0, "File name of dEdx Splines file") -AddOption(transformationFile, std::string, "", "", 0, "File name of TPC fast transformation map") -AddOption(matLUTFile, std::string, "", "", 0, "File name of material LUT file") -AddOption(gainCalibFile, std::string, "", "", 0, "File name of TPC pad gain calibration") -AddOption(allocateOutputOnTheFly, bool, true, "", 0, "Allocate shm output buffers on the fly, instead of using preallocated buffer with upper bound size") -AddOption(outputBufferSize, unsigned long, 200000000ul, "", 0, "Size of the output buffers to be allocated") -AddOption(synchronousProcessing, bool, false, "", 0, "Apply performance shortcuts for synchronous processing, disable unneeded steps") -AddOption(mutexMemReg, bool, false, "", 0, "Global mutex to serialize GPU memory registration") -AddOption(display, bool, false, "", 0, "Enable standalone gpu tracking visualizaion") -AddOption(dropSecondaryLegs, bool, true, "", 0, "Do not store secondary legs of looping track in TrackTPC") -AddOption(memoryBufferScaleFactor, float, 1.f, "", 0, "Factor to scale buffer size estimations") -EndConfig() -#endif // GPUCA_O2_LIB -#endif // !GPUCA_GPUCODE_DEVICE - -// Derrived parameters used in GPUParam -BeginHiddenConfig(GPUSettingsParam, param) -AddVariableRTC(DAlpha, float, 0.f) // angular size -AddVariableRTC(BzkG, float, 0.f) // constant magnetic field value in kG -AddVariableRTC(ConstBz, float, 0.f) // constant magnetic field value in kG*clight -AddVariableRTC(AssumeConstantBz, char, 0) // Assume a constant magnetic field -AddVariableRTC(ToyMCEventsFlag, char, 0) // events were build with home-made event generator -AddVariableRTC(ContinuousTracking, char, 0) // Continuous tracking, estimate bz and errors for abs(z) = 125cm during seeding -AddVariableRTC(resetTimers, char, 0) // Reset benchmark timers before event processing -AddVariableRTC(dodEdx, char, 0) // Do dEdx computation -AddVariableRTC(earlyTpcTransform, char, 0) // do Early TPC transformation -AddVariableRTC(debugLevel, char, 0) // Debug level -AddVariableRTC(continuousMaxTimeBin, int, 0) // Max time bin for continuous tracking -AddVariable(dummyRTC, float, 0.f) // Ensure non empty struct and proper alignment even if all normal members are constexpr -EndConfig() - -EndNamespace() // gpu -EndNamespace() // GPUCA_NAMESPACE -#endif // #ifdef BeginNamespace - // clang-format on diff --git a/GPU/GPUTracking/Base/GPUTPCGPURootDump.h b/GPU/GPUTracking/Base/GPUTPCGPURootDump.h deleted file mode 100644 index 8fab790f4245f..0000000000000 --- a/GPU/GPUTracking/Base/GPUTPCGPURootDump.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTPCGPURootDump.h -/// \author David Rohr - -#ifndef GPUTPCGPUROOTDUMP_H -#define GPUTPCGPUROOTDUMP_H - -#if (!defined(GPUCA_STANDALONE) || defined(GPUCA_BUILD_QA)) && !defined(GPUCA_GPUCODE) -#include <TTree.h> -#include <TFile.h> -#include <TNtuple.h> - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -namespace -{ -template <class S> -struct internal_Branch { - template <typename... Args> - static void Branch(S* p, Args... args) - { - } -}; -template <> -struct internal_Branch<TTree> { - template <typename... Args> - static void Branch(TTree* p, Args... args) - { - p->Branch(args...); - } -}; -} // namespace - -template <class T> -class GPUTPCGPURootDump -{ - public: - GPUTPCGPURootDump() = delete; - GPUTPCGPURootDump(const GPUTPCGPURootDump<T>&) = delete; - GPUTPCGPURootDump<T> operator=(const GPUTPCGPURootDump<T>&) = delete; - template <typename... Args> - GPUTPCGPURootDump(const char* filename, Args... args) - { - fFile = new TFile(filename, "recreate"); - fTree = new T(args...); - } - - ~GPUTPCGPURootDump() - { - fTree->Write(); - fFile->Write(); - fFile->Close(); - delete fFile; - } - - template <typename... Args> - void Fill(Args... args) - { - fTree->Fill(args...); - } - template <typename... Args> - void Branch(Args... args) - { - internal_Branch<T>::Branch(fTree, args...); - } - - private: - TFile* fFile = nullptr; - T* fTree = nullptr; -}; -#else -template <class T> -class GPUTPCGPURootDump -{ - public: - GPUTPCGPURootDump() = delete; - template <typename... Args> - GPUTPCGPURootDump(const char* filename, Args... args) - { - } - template <typename... Args> - void Fill(Args... args) - { - } - template <typename... Args> - void Branch(Args... args) - { - } - - private: - void *a, *b; -}; -} -} -#endif - -#endif diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index dae17401295c2..a1bf6540d00ea 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTrackingCUDA) @@ -15,11 +16,12 @@ if(DEFINED CUDA_COMPUTETARGET) endif() message(STATUS "Building GPUTracking with CUDA support ${TMP_TARGET}") -set(SRCS GPUReconstructionCUDA.cu) -set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDAIncludes.h) +set(SRCS GPUReconstructionCUDA.cu GPUReconstructionCUDAKernels.cu GPUReconstructionCUDAGenRTC.cu) +set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDAIncludes.h CUDAThrustHelpers.h) # -------------------------------- Prepare RTC ------------------------------------------------------- if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") + enable_language(ASM) if(ALIGPU_BUILD_TYPE STREQUAL "O2") set(defineIncludeSrc "O2::${MODULE}") else() @@ -28,12 +30,12 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(CURTC_DEFINES "-D$<JOIN:$<TARGET_PROPERTY:${defineIncludeSrc},COMPILE_DEFINITIONS>,$<SEMICOLON>-D>" -DGPUCA_GPUCODE_GENRTC ) - set(CURTC_INCLUDES "-I$<JOIN:$<TARGET_PROPERTY:${defineIncludeSrc},INCLUDE_DIRECTORIES>,$<SEMICOLON>-I>" + set(CURTC_INCLUDES "-I$<JOIN:$<FILTER:$<TARGET_PROPERTY:${defineIncludeSrc},INCLUDE_DIRECTORIES>,EXCLUDE,^/usr/include/?>,$<SEMICOLON>-I>" -I${CMAKE_SOURCE_DIR}/Detectors/Base/src -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src ) if(ALIGPU_BUILD_TYPE STREQUAL "O2") - set(CURTC_INCLUDES ${CURTC_INCLUDES} "-I$<JOIN:$<TARGET_PROPERTY:O2::ITStrackingCUDA,INCLUDE_DIRECTORIES>,$<SEMICOLON>-I>") + set(CURTC_INCLUDES ${CURTC_INCLUDES} "-I$<JOIN:$<FILTER:$<TARGET_PROPERTY:O2::ITStrackingCUDA,INCLUDE_DIRECTORIES>,EXCLUDE,^/usr/include/?>,$<SEMICOLON>-I>") endif() #set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -keep") @@ -67,8 +69,8 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_custom_command( OUTPUT ${CURTC_BIN}.src.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_src/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.src,g" > ${CURTC_BIN}.src.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_src/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.src,g" > ${CURTC_BIN}.src.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S ) add_custom_command( @@ -80,8 +82,8 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_custom_command( OUTPUT ${CURTC_BIN}.command.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_command/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.command,g" > ${CURTC_BIN}.command.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_command/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.command,g" > ${CURTC_BIN}.command.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S DEPENDS ${CURTC_BIN}.command ) # cmake-format: on @@ -92,15 +94,15 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") ${CURTC_BIN}.src.S PROPERTIES LANGUAGE - CXX + ASM OBJECT_DEPENDS - "${CURTC_BIN}.src;${GPUDIR}/Standalone/makefiles/include.S") + "${CURTC_BIN}.src;${GPUDIR}/utils/include.S") set_source_files_properties( ${CURTC_BIN}.command.S PROPERTIES LANGUAGE - CXX + ASM ) set(SRCS ${SRCS} ${CURTC_BIN}.src.S ${CURTC_BIN}.command.S) @@ -114,7 +116,8 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/Detectors/Base/src ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src - PUBLIC_LINK_LIBRARIES O2::GPUTracking O2::ITStrackingCUDA + ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src + PUBLIC_LINK_LIBRARIES O2::GPUTracking O2::ITStrackingCUDA O2::FrameworkFoundation3rdparty TARGETVARNAME targetName) target_compile_definitions( @@ -168,3 +171,10 @@ target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_TURING) else() target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_AMPERE) endif() + +if(OpenMP_CXX_FOUND) + # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) + set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler -fopenmp") +endif() diff --git a/GPU/GPUTracking/Base/cuda/CUDAThrustHelpers.h b/GPU/GPUTracking/Base/cuda/CUDAThrustHelpers.h new file mode 100644 index 0000000000000..d9e99a8ca0bc4 --- /dev/null +++ b/GPU/GPUTracking/Base/cuda/CUDAThrustHelpers.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CUDAThrustHelpers.h +/// \author David Rohr + +#ifndef GPU_CUDATHRUSTHELPERS_H +#define GPU_CUDATHRUSTHELPERS_H + +#include "GPULogging.h" +#include <vector> +#include <memory> + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +class ThrustVolatileAsyncAllocator +{ + public: + typedef char value_type; + + ThrustVolatileAsyncAllocator(GPUReconstruction* r) : mRec(r) {} + char* allocate(std::ptrdiff_t n) { return (char*)mRec->AllocateVolatileDeviceMemory(n); } + + void deallocate(char* ptr, size_t) {} + + private: + GPUReconstruction* mRec; +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +// Override synchronize call at end of thrust algorithm running on stream, just don't run cudaStreamSynchronize +namespace thrust +{ +namespace cuda_cub +{ + +typedef thrust::cuda_cub::execution_policy<typeof(thrust::cuda::par(*(GPUCA_NAMESPACE::gpu::ThrustVolatileAsyncAllocator*)nullptr).on(*(cudaStream_t*)nullptr))> thrustStreamPolicy; +template <> +__host__ __device__ inline cudaError_t synchronize<thrustStreamPolicy>(thrustStreamPolicy& policy) +{ +#ifndef GPUCA_GPUCODE_DEVICE + // Do not synchronize! + return cudaSuccess; +#else + return synchronize_stream(derived_cast(policy)); +#endif +} + +} // namespace cuda_cub +} // namespace thrust + +#endif diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index addaf5fa869ad..beacfc7e06b97 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,14 +12,15 @@ /// \file GPUReconstructionCUDA.cu /// \author David Rohr +#define GPUCA_GPUCODE_HOSTONLY #include "GPUReconstructionCUDADef.h" #include "GPUReconstructionCUDAIncludes.h" #include <cuda_profiler_api.h> -#include <unistd.h> #include "GPUReconstructionCUDA.h" #include "GPUReconstructionCUDAInternals.h" +#include "CUDAThrustHelpers.h" #include "GPUReconstructionIncludes.h" #include "GPUParamRTC.h" @@ -30,18 +32,13 @@ static constexpr size_t RESERVE_EXTRA_MEM_OFFSET = 1L * 512 * 1024 * 1024; using namespace GPUCA_NAMESPACE::gpu; -#ifdef GPUCA_USE_TEXTURES -texture<cahit2, cudaTextureType1D, cudaReadModeElementType> gAliTexRefu2; -texture<calink, cudaTextureType1D, cudaReadModeElementType> gAliTexRefu; -#endif - __global__ void dummyInitKernel(void*) { } -#if defined(HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) -#include "ITStrackingCUDA/TrackerTraitsNV.h" -#include "ITStrackingCUDA/VertexerTraitsGPU.h" +#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) +#include "ITStrackingGPU/TrackerTraitsGPU.h" +#include "ITStrackingGPU/VertexerTraitsGPU.h" #else namespace o2::its { @@ -54,161 +51,36 @@ class VertexerTraitsGPU : public VertexerTraits } // namespace o2::its #endif -class GPUDebugTiming -{ - public: - GPUDebugTiming(bool d, void** t, cudaStream_t* s, GPUReconstruction::krnlSetup& x, GPUReconstructionCUDABackend* r = nullptr) : mDeviceTimers(t), mStreams(s), mXYZ(x), mRec(r), mDo(d) - { - if (mDo) { - if (mDeviceTimers) { - GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[0], mStreams[mXYZ.x.stream])); - } else { - mTimer.ResetStart(); - } - } - } - ~GPUDebugTiming() - { - if (mDo) { - if (mDeviceTimers) { - GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[1], mStreams[mXYZ.x.stream])); - GPUFailedMsg(cudaEventSynchronize((cudaEvent_t)mDeviceTimers[1])); - float v; - GPUFailedMsg(cudaEventElapsedTime(&v, (cudaEvent_t)mDeviceTimers[0], (cudaEvent_t)mDeviceTimers[1])); - mXYZ.t = v * 1.e-3; - } else { - GPUFailedMsg(cudaStreamSynchronize(mStreams[mXYZ.x.stream])); - mXYZ.t = mTimer.GetCurrentElapsedTime(); - } - } - } - - private: - void** mDeviceTimers; - cudaStream_t* mStreams; - GPUReconstruction::krnlSetup& mXYZ; - GPUReconstructionCUDABackend* mRec; - HighResTimer mTimer; - bool mDo; -}; - -#include "GPUReconstructionIncludesDevice.h" - -#ifndef GPUCA_ALIROOT_LIB -extern "C" char _curtc_GPUReconstructionCUDArtc_cu_src[]; -extern "C" unsigned int _curtc_GPUReconstructionCUDArtc_cu_src_size; -extern "C" char _curtc_GPUReconstructionCUDArtc_cu_command[]; -#endif - -/* -// Not using templated kernel any more, since nvidia profiler does not resolve template names -template <class T, int I, typename... Args> -GPUg() void runKernelCUDA(GPUCA_CONSMEM_PTR int iSlice_internal, Args... args) -{ - GPUshared() typename T::GPUSharedMemory smem; - T::template Thread<I>(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, T::Processor(GPUCA_CONSMEM)[iSlice_internal], args...); -} -*/ - -#undef GPUCA_KRNL_REG -#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PROP(x_class, x_attributes) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))<<<x.nBlocks, x.nThreads, 0, me->mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, args...); -#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)<<<x.nBlocks, x.nThreads, 0, me->mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, y.num, args...); - -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL - -template <bool multi, class T, int I> -int GPUReconstructionCUDAInternals::getRTCkernelNum(int k) -{ - static int num = k; - if (num < 0) { - throw std::runtime_error("Invalid kernel"); - } - return num; -} - -template <> -void GPUReconstructionCUDABackend::runKernelBackendInternal<GPUMemClean16, 0>(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) -{ - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); - GPUFailedMsg(cudaMemsetAsync(ptr, 0, size, mInternals->Streams[_xyz.x.stream])); -} - -static void getArgPtrs(const void** pArgs) {} -template <typename T, typename... Args> -static void getArgPtrs(const void** pArgs, const T& arg, const Args&... args) -{ - *pArgs = &arg; - getArgPtrs(pArgs + 1, args...); -} - -template <class T, int I, typename... Args> -void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, const Args&... args) +GPUReconstructionCUDABackend::GPUReconstructionCUDABackend(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionDeviceBase(cfg, sizeof(GPUReconstructionDeviceBase)) { - GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (void**)mDebugEvents, mInternals->Streams, _xyz); - if (mProcessingSettings.enableRTC) { - auto& x = _xyz.x; - auto& y = _xyz.y; - if (y.num <= 1) { - const void* pArgs[sizeof...(Args) + 1]; - pArgs[0] = &y.start; - getArgPtrs(&pArgs[1], args...); - GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum<false, T, I>()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); - } else { - const void* pArgs[sizeof...(Args) + 2]; - pArgs[0] = &y.start; - pArgs[1] = &y.num; - getArgPtrs(&pArgs[2], args...); - GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum<true, T, I>()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); - } - } else { - backendInternal<T, I>::runKernelBackendMacro(_xyz, this, args...); + if (mMaster == nullptr) { + mInternals = new GPUReconstructionCUDAInternals; } } -template <class T, int I, typename... Args> -int GPUReconstructionCUDABackend::runKernelBackend(krnlSetup& _xyz, const Args&... args) +GPUReconstructionCUDABackend::~GPUReconstructionCUDABackend() { - auto& x = _xyz.x; - auto& z = _xyz.z; - if (z.evList) { - for (int k = 0; k < z.nEvents; k++) { - GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[x.stream], ((cudaEvent_t*)z.evList)[k], 0)); + if (mMaster == nullptr) { + for (unsigned int i = 0; i < mInternals->rtcModules.size(); i++) { + cuModuleUnload(*mInternals->rtcModules[i]); } + delete mInternals; } - runKernelBackendInternal<T, I>(_xyz, args...); - GPUFailedMsg(cudaGetLastError()); - if (z.ev) { - GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)z.ev, mInternals->Streams[x.stream])); - } - return 0; } -GPUReconstructionCUDABackend::GPUReconstructionCUDABackend(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionDeviceBase(cfg, sizeof(GPUReconstructionDeviceBase)) +GPUReconstructionCUDA::GPUReconstructionCUDA(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionKernels(cfg) { - if (mMaster == nullptr) { - mInternals = new GPUReconstructionCUDAInternals; - } mDeviceBackendSettings.deviceType = DeviceType::CUDA; } -GPUReconstructionCUDABackend::~GPUReconstructionCUDABackend() +GPUReconstructionCUDA::~GPUReconstructionCUDA() { Exit(); // Make sure we destroy everything (in particular the ITS tracker) before we exit CUDA - if (mMaster == nullptr) { - delete mInternals; - } } GPUReconstruction* GPUReconstruction_Create_CUDA(const GPUSettingsDeviceBackend& cfg) { return new GPUReconstructionCUDA(cfg); } -void GPUReconstructionCUDABackend::GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* trackerTraits, std::unique_ptr<o2::its::VertexerTraits>* vertexerTraits) +void GPUReconstructionCUDA::GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* trackerTraits, std::unique_ptr<o2::its::VertexerTraits>* vertexerTraits) { if (trackerTraits) { trackerTraits->reset(new o2::its::TrackerTraitsNV); @@ -218,12 +90,12 @@ void GPUReconstructionCUDABackend::GetITSTraits(std::unique_ptr<o2::its::Tracker } } -void GPUReconstructionCUDABackend::UpdateSettings() +void GPUReconstructionCUDA::UpdateSettings() { GPUCA_GPUReconstructionUpdateDefailts(); } -int GPUReconstructionCUDABackend::InitDevice_Runtime() +int GPUReconstructionCUDA::InitDevice_Runtime() { if (mMaster == nullptr) { cudaDeviceProp cudaDeviceProp; @@ -442,81 +314,40 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); #ifndef GPUCA_ALIROOT_LIB - if (mProcessingSettings.enableRTC) { - if (mProcessingSettings.debugLevel >= 0) { - GPUInfo("Starting CUDA RTC Compilation"); - } - HighResTimer rtcTimer; - rtcTimer.ResetStart(); - std::string filename = "/tmp/o2cagpu_rtc_"; - filename += std::to_string(getpid()); - filename += "_"; - filename += std::to_string(rand()); - if (mProcessingSettings.debugLevel >= 3) { - printf("Writing to %s\n", filename.c_str()); - } - FILE* fp = fopen((filename + ".cu").c_str(), "w+b"); - if (fp == nullptr) { - throw std::runtime_error("Error opening file"); - } - std::string rtcparam = GPUParamRTC::generateRTCCode(param(), mProcessingSettings.rtcConstexpr); - if (fwrite(rtcparam.c_str(), 1, rtcparam.size(), fp) != rtcparam.size()) { - throw std::runtime_error("Error writing file"); - } - if (fwrite(_curtc_GPUReconstructionCUDArtc_cu_src, 1, _curtc_GPUReconstructionCUDArtc_cu_src_size, fp) != _curtc_GPUReconstructionCUDArtc_cu_src_size) { - throw std::runtime_error("Error writing file"); - } - fclose(fp); - std::string command = _curtc_GPUReconstructionCUDArtc_cu_command; - command += " -cubin -c " + filename + ".cu -o " + filename + ".o"; - if (mProcessingSettings.debugLevel >= 3) { - printf("Running command %s\n", command.c_str()); - } - if (system(command.c_str())) { + if (mProcessingSettings.rtc.enable) { + if (genRTC()) { throw std::runtime_error("Runtime compilation failed"); } - GPUFailedMsg(cuModuleLoad(&mInternals->rtcModule, (filename + ".o").c_str())); - -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - mInternals->getRTCkernelNum<false, GPUCA_M_KRNL_TEMPLATE(x_class)>(mInternals->rtcFunctions.size()); \ - mInternals->rtcFunctions.emplace_back(new CUfunction); \ - GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), mInternals->rtcModule, GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))))); -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ - mInternals->getRTCkernelNum<true, GPUCA_M_KRNL_TEMPLATE(x_class)>(mInternals->rtcFunctions.size()); \ - mInternals->rtcFunctions.emplace_back(new CUfunction); \ - GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), mInternals->rtcModule, GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)))); -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -#undef GPUCA_KRNL_LOAD_single -#undef GPUCA_KRNL_LOAD_multi - - remove((filename + ".cu").c_str()); - remove((filename + ".o").c_str()); - if (mProcessingSettings.debugLevel >= 0) { - GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); - } } #endif void* devPtrConstantMem; + if (mProcessingSettings.rtc.enable) { + mDeviceConstantMemRTC.resize(mInternals->rtcModules.size()); + } #ifndef GPUCA_NO_CONSTANT_MEMORY - if (mProcessingSettings.enableRTC) { - GPUFailedMsg(cuModuleGetGlobal((CUdeviceptr*)&devPtrConstantMem, nullptr, mInternals->rtcModule, "gGPUConstantMemBuffer")); - } else { - GPUFailedMsg(cudaGetSymbolAddress(&devPtrConstantMem, gGPUConstantMemBuffer)); + devPtrConstantMem = GetBackendConstSymbolAddress(); + if (mProcessingSettings.rtc.enable) { + for (unsigned int i = 0; i < mDeviceConstantMemRTC.size(); i++) { + GPUFailedMsg(cuModuleGetGlobal((CUdeviceptr*)&mDeviceConstantMemRTC[i], nullptr, *mInternals->rtcModules[i], "gGPUConstantMemBuffer")); + } } #else GPUFailedMsg(cudaMalloc(&devPtrConstantMem, gGPUConstantMemBufferSize)); + for (unsigned int i = 0; i < mDeviceConstantMemRTC.size(); i++) { + mDeviceConstantMemRTC[i] = devPtrConstantMem; + } #endif mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; } else { - GPUReconstructionCUDABackend* master = dynamic_cast<GPUReconstructionCUDABackend*>(mMaster); + GPUReconstructionCUDA* master = dynamic_cast<GPUReconstructionCUDA*>(mMaster); mDeviceId = master->mDeviceId; mBlockCount = master->mBlockCount; mWarpSize = master->mWarpSize; mMaxThreads = master->mMaxThreads; mDeviceName = master->mDeviceName; mDeviceConstantMem = master->mDeviceConstantMem; + mDeviceConstantMemRTC.resize(master->mDeviceConstantMemRTC.size()); + std::copy(master->mDeviceConstantMemRTC.begin(), master->mDeviceConstantMemRTC.end(), mDeviceConstantMemRTC.begin()); mInternals = master->mInternals; GPUFailedMsgI(cuCtxPushCurrent(mInternals->CudaContext)); } @@ -542,7 +373,7 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() return (0); } -int GPUReconstructionCUDABackend::ExitDevice_Runtime() +int GPUReconstructionCUDA::ExitDevice_Runtime() { // Uninitialize CUDA GPUFailedMsgI(cuCtxPushCurrent(mInternals->CudaContext)); @@ -582,7 +413,7 @@ int GPUReconstructionCUDABackend::ExitDevice_Runtime() return (0); } -size_t GPUReconstructionCUDABackend::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) +size_t GPUReconstructionCUDA::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { if (mProcessingSettings.debugLevel >= 3) { stream = -1; @@ -605,7 +436,7 @@ size_t GPUReconstructionCUDABackend::GPUMemCpy(void* dst, const void* src, size_ return size; } -size_t GPUReconstructionCUDABackend::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) +size_t GPUReconstructionCUDA::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) { if (!(res->Type() & GPUMemoryResource::MEMORY_GPU)) { if (mProcessingSettings.debugLevel >= 4) { @@ -613,41 +444,24 @@ size_t GPUReconstructionCUDABackend::TransferMemoryInternal(GPUMemoryResource* r } return 0; } - if (mProcessingSettings.debugLevel >= 3) { + if (mProcessingSettings.debugLevel >= 3 && (strcmp(res->Name(), "ErrorCodes") || mProcessingSettings.debugLevel >= 4)) { GPUInfo("Copying to %s: %s - %lld bytes", toGPU ? "GPU" : "Host", res->Name(), (long long int)res->Size()); } return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); } -size_t GPUReconstructionCUDABackend::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) +size_t GPUReconstructionCUDA::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) { -#ifndef GPUCA_NO_CONSTANT_MEMORY - if (stream == -1) { - GPUFailedMsg(cudaMemcpyToSymbol(gGPUConstantMemBuffer, src, size, offset, cudaMemcpyHostToDevice)); - } else { - GPUFailedMsg(cudaMemcpyToSymbolAsync(gGPUConstantMemBuffer, src, size, offset, cudaMemcpyHostToDevice, mInternals->Streams[stream])); - } - if (mProcessingSettings.enableRTC) -#endif - { - std::unique_ptr<GPUParamRTC> tmpParam; - if (mProcessingSettings.rtcConstexpr) { - if (offset < sizeof(GPUParam) && (offset != 0 || size > sizeof(GPUParam))) { - throw std::runtime_error("Invalid write to constant memory, crossing GPUParam border"); - } - if (offset == 0) { - tmpParam.reset(new GPUParamRTC); - tmpParam->setFrom(*(GPUParam*)src); - src = tmpParam.get(); - size = sizeof(*tmpParam); - } else { - offset = offset - sizeof(GPUParam) + sizeof(GPUParamRTC); - } + std::unique_ptr<GPUParamRTC> tmpParam; + for (unsigned int i = 0; i < 1 + mDeviceConstantMemRTC.size(); i++) { + void* basePtr = i ? mDeviceConstantMemRTC[i - 1] : mDeviceConstantMem; + if (i && basePtr == (void*)mDeviceConstantMem) { + continue; } if (stream == -1) { - GPUFailedMsg(cudaMemcpy(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice)); + GPUFailedMsg(cudaMemcpy(((char*)basePtr) + offset, src, size, cudaMemcpyHostToDevice)); } else { - GPUFailedMsg(cudaMemcpyAsync(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice, mInternals->Streams[stream])); + GPUFailedMsg(cudaMemcpyAsync(((char*)basePtr) + offset, src, size, cudaMemcpyHostToDevice, mInternals->Streams[stream])); } } if (ev && stream != -1) { @@ -656,41 +470,41 @@ size_t GPUReconstructionCUDABackend::WriteToConstantMemory(size_t offset, const return size; } -void GPUReconstructionCUDABackend::ReleaseEvent(deviceEvent* ev) {} -void GPUReconstructionCUDABackend::RecordMarker(deviceEvent* ev, int stream) { GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream])); } +void GPUReconstructionCUDA::ReleaseEvent(deviceEvent* ev) {} +void GPUReconstructionCUDA::RecordMarker(deviceEvent* ev, int stream) { GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream])); } -GPUReconstructionCUDABackend::GPUThreadContextCUDA::GPUThreadContextCUDA(GPUReconstructionCUDAInternals* context) : GPUThreadContext(), mContext(context) +GPUReconstructionCUDA::GPUThreadContextCUDA::GPUThreadContextCUDA(GPUReconstructionCUDAInternals* context) : GPUThreadContext(), mContext(context) { if (mContext->cudaContextObtained++ == 0) { cuCtxPushCurrent(mContext->CudaContext); } } -GPUReconstructionCUDABackend::GPUThreadContextCUDA::~GPUThreadContextCUDA() +GPUReconstructionCUDA::GPUThreadContextCUDA::~GPUThreadContextCUDA() { if (--mContext->cudaContextObtained == 0) { cuCtxPopCurrent(&mContext->CudaContext); } } -std::unique_ptr<GPUReconstruction::GPUThreadContext> GPUReconstructionCUDABackend::GetThreadContext() { return std::unique_ptr<GPUThreadContext>(new GPUThreadContextCUDA(mInternals)); } +std::unique_ptr<GPUReconstruction::GPUThreadContext> GPUReconstructionCUDA::GetThreadContext() { return std::unique_ptr<GPUThreadContext>(new GPUThreadContextCUDA(mInternals)); } -void GPUReconstructionCUDABackend::SynchronizeGPU() { GPUFailedMsg(cudaDeviceSynchronize()); } -void GPUReconstructionCUDABackend::SynchronizeStream(int stream) { GPUFailedMsg(cudaStreamSynchronize(mInternals->Streams[stream])); } +void GPUReconstructionCUDA::SynchronizeGPU() { GPUFailedMsg(cudaDeviceSynchronize()); } +void GPUReconstructionCUDA::SynchronizeStream(int stream) { GPUFailedMsg(cudaStreamSynchronize(mInternals->Streams[stream])); } -void GPUReconstructionCUDABackend::SynchronizeEvents(deviceEvent* evList, int nEvents) +void GPUReconstructionCUDA::SynchronizeEvents(deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { GPUFailedMsg(cudaEventSynchronize(((cudaEvent_t*)evList)[i])); } } -void GPUReconstructionCUDABackend::StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents) +void GPUReconstructionCUDA::StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[stream], ((cudaEvent_t*)evList)[i], 0)); } } -bool GPUReconstructionCUDABackend::IsEventDone(deviceEvent* evList, int nEvents) +bool GPUReconstructionCUDA::IsEventDone(deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { cudaError_t retVal = cudaEventSynchronize(((cudaEvent_t*)evList)[i]); @@ -702,7 +516,7 @@ bool GPUReconstructionCUDABackend::IsEventDone(deviceEvent* evList, int nEvents) return (true); } -int GPUReconstructionCUDABackend::GPUDebug(const char* state, int stream) +int GPUReconstructionCUDA::GPUDebug(const char* state, int stream, bool force) { // Wait for CUDA-Kernel to finish and check for CUDA errors afterwards, in case of debugmode cudaError cuErr; @@ -711,10 +525,10 @@ int GPUReconstructionCUDABackend::GPUDebug(const char* state, int stream) GPUError("Cuda Error %s while running kernel (%s) (Stream %d)", cudaGetErrorString(cuErr), state, stream); return (1); } - if (mProcessingSettings.debugLevel <= 0) { + if (force == false && mProcessingSettings.debugLevel <= 0) { return (0); } - if (GPUFailedMsgI(cudaDeviceSynchronize())) { + if (GPUFailedMsgI(stream == -1 ? cudaDeviceSynchronize() : cudaStreamSynchronize(mInternals->Streams[stream]))) { GPUError("CUDA Error while synchronizing (%s) (Stream %d)", state, stream); return (1); } @@ -724,7 +538,7 @@ int GPUReconstructionCUDABackend::GPUDebug(const char* state, int stream) return (0); } -int GPUReconstructionCUDABackend::PrepareTextures() +int GPUReconstructionCUDA::PrepareTextures() { #ifdef GPUCA_USE_TEXTURES cudaChannelFormatDesc channelDescu2 = cudaCreateChannelDesc<cahit2>(); @@ -736,45 +550,22 @@ int GPUReconstructionCUDABackend::PrepareTextures() return (0); } -int GPUReconstructionCUDABackend::registerMemoryForGPU(const void* ptr, size_t size) -{ - return GPUFailedMsgI(cudaHostRegister((void*)ptr, size, cudaHostRegisterDefault)); -} - -int GPUReconstructionCUDABackend::unregisterMemoryForGPU(const void* ptr) +int GPUReconstructionCUDA::registerMemoryForGPU(const void* ptr, size_t size) { - return GPUFailedMsgI(cudaHostUnregister((void*)ptr)); + return mProcessingSettings.noGPUMemoryRegistration ? 0 : GPUFailedMsgI(cudaHostRegister((void*)ptr, size, cudaHostRegisterDefault)); } -void GPUReconstructionCUDABackend::PrintKernelOccupancies() +int GPUReconstructionCUDA::unregisterMemoryForGPU(const void* ptr) { - int maxBlocks, threads, suggestedBlocks; - cudaFuncAttributes attr; - GPUFailedMsg(cuCtxPushCurrent(mInternals->CudaContext)); -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - GPUFailedMsg(cudaOccupancyMaxPotentialBlockSize(&suggestedBlocks, &threads, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ - GPUFailedMsg(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxBlocks, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)), threads, 0)); \ - GPUFailedMsg(cudaFuncGetAttributes(&attr, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ - GPUInfo("Kernel: %50s Block size: %4d, Maximum active blocks: %3d, Suggested blocks: %3d, Regs: %3d, smem: %3d", GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), threads, maxBlocks, suggestedBlocks, attr.numRegs, (int)attr.sharedSizeBytes); -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ - GPUFailedMsg(cudaOccupancyMaxPotentialBlockSize(&suggestedBlocks, &threads, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ - GPUFailedMsg(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxBlocks, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi), threads, 0)); \ - GPUFailedMsg(cudaFuncGetAttributes(&attr, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ - GPUInfo("Kernel: %50s Block size: %4d, Maximum active blocks: %3d, Suggested blocks: %3d, Regs: %3d, smem: %3d", GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), threads, maxBlocks, suggestedBlocks, attr.numRegs, (int)attr.sharedSizeBytes); -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -#undef GPUCA_KRNL_LOAD_single -#undef GPUCA_KRNL_LOAD_multi - GPUFailedMsg(cuCtxPopCurrent(&mInternals->CudaContext)); + return mProcessingSettings.noGPUMemoryRegistration ? 0 : GPUFailedMsgI(cudaHostUnregister((void*)ptr)); } -void GPUReconstructionCUDABackend::startGPUProfiling() +void GPUReconstructionCUDA::startGPUProfiling() { GPUFailedMsg(cudaProfilerStart()); } -void GPUReconstructionCUDABackend::endGPUProfiling() +void GPUReconstructionCUDA::endGPUProfiling() { GPUFailedMsg(cudaProfilerStop()); } diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h index 5997a88d8c224..18a382e81b131 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,6 +37,28 @@ class GPUReconstructionCUDABackend : public GPUReconstructionDeviceBase protected: GPUReconstructionCUDABackend(const GPUSettingsDeviceBackend& cfg); + void* GetBackendConstSymbolAddress(); + void PrintKernelOccupancies() override; + + template <class T, int I = 0, typename... Args> + int runKernelBackend(krnlSetup& _xyz, Args... args); + template <class T, int I = 0, typename... Args> + void runKernelBackendInternal(krnlSetup& _xyz, const Args&... args); + template <class T, int I = 0> + const krnlProperties getKernelPropertiesBackend(); + template <class T, int I> + class backendInternal; + + GPUReconstructionCUDAInternals* mInternals; +}; + +class GPUReconstructionCUDA : public GPUReconstructionKernels<GPUReconstructionCUDABackend> +{ + public: + ~GPUReconstructionCUDA() override; + GPUReconstructionCUDA(const GPUSettingsDeviceBackend& cfg); + + protected: int InitDevice_Runtime() override; int ExitDevice_Runtime() override; void UpdateSettings() override; @@ -44,7 +67,7 @@ class GPUReconstructionCUDABackend : public GPUReconstructionDeviceBase { public: GPUThreadContextCUDA(GPUReconstructionCUDAInternals* context); - virtual ~GPUThreadContextCUDA(); + ~GPUThreadContextCUDA() override; private: GPUReconstructionCUDAInternals* mContext = nullptr; @@ -53,7 +76,7 @@ class GPUReconstructionCUDABackend : public GPUReconstructionDeviceBase std::unique_ptr<GPUThreadContext> GetThreadContext() override; bool CanQueryMaxMemory() override { return true; } void SynchronizeGPU() override; - int GPUDebug(const char* state = "UNKNOWN", int stream = -1) override; + int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; void SynchronizeStream(int stream) override; void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; @@ -73,22 +96,11 @@ class GPUReconstructionCUDABackend : public GPUReconstructionDeviceBase void GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* trackerTraits, std::unique_ptr<o2::its::VertexerTraits>* vertexerTraits) override; - void PrintKernelOccupancies() override; - - template <class T, int I = 0, typename... Args> - int runKernelBackend(krnlSetup& _xyz, const Args&... args); - template <class T, int I = 0, typename... Args> - void runKernelBackendInternal(krnlSetup& _xyz, const Args&... args); - template <class T, int I = 0> - const krnlProperties getKernelPropertiesBackend(); - template <class T, int I> - class backendInternal; - private: - GPUReconstructionCUDAInternals* mInternals; + std::vector<void*> mDeviceConstantMemRTC; + int genRTC(); }; -using GPUReconstructionCUDA = GPUReconstructionKernels<GPUReconstructionCUDABackend>; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h index 9ef1ce9a820e6..cf1934637b4b8 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu new file mode 100644 index 0000000000000..5329643163130 --- /dev/null +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu @@ -0,0 +1,245 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionCUDAGenRTC.cu +/// \author David Rohr + +#define GPUCA_GPUCODE_HOSTONLY +#include <omp.h> +#include <cuda.h> +#include <cuda_fp16.h> +#include "GPUReconstructionCUDADef.h" +#include "GPUReconstructionCUDA.h" +#include "GPUReconstructionCUDAInternals.h" +#include "GPUParamRTC.h" +#include "GPUDefMacros.h" +#include <unistd.h> +#ifdef GPUCA_HAVE_O2HEADERS +#include "Framework/SHA1.h" +#endif + +using namespace GPUCA_NAMESPACE::gpu; + +#ifndef GPUCA_ALIROOT_LIB +extern "C" char _curtc_GPUReconstructionCUDArtc_cu_src[]; +extern "C" unsigned int _curtc_GPUReconstructionCUDArtc_cu_src_size; +extern "C" char _curtc_GPUReconstructionCUDArtc_cu_command[]; +#endif + +int GPUReconstructionCUDA::genRTC() +{ +#ifndef GPUCA_ALIROOT_LIB + std::string rtcparam = GPUParamRTC::generateRTCCode(param(), mProcessingSettings.rtc.optConstexpr); + std::string filename = "/tmp/o2cagpu_rtc_"; + filename += std::to_string(getpid()); + filename += "_"; + filename += std::to_string(rand()); + + std::vector<std::string> kernels; + std::string kernelsall; +#undef GPUCA_KRNL_REG +#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward))); +#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward))); +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL +#undef GPUCA_KRNL_LOAD_single +#undef GPUCA_KRNL_LOAD_multi + for (unsigned int i = 0; i < kernels.size(); i++) { + kernelsall += kernels[i]; + } + +#ifdef GPUCA_HAVE_O2HEADERS + char shasource[21], shaparam[21], shacmd[21], shakernels[21]; + if (mProcessingSettings.rtc.cacheOutput) { + o2::framework::internal::SHA1(shasource, _curtc_GPUReconstructionCUDArtc_cu_src, _curtc_GPUReconstructionCUDArtc_cu_src_size); + o2::framework::internal::SHA1(shaparam, rtcparam.c_str(), rtcparam.size()); + o2::framework::internal::SHA1(shacmd, _curtc_GPUReconstructionCUDArtc_cu_command, strlen(_curtc_GPUReconstructionCUDArtc_cu_command)); + o2::framework::internal::SHA1(shakernels, kernelsall.c_str(), kernelsall.size()); + } +#endif + + unsigned int nCompile = mProcessingSettings.rtc.compilePerKernel ? kernels.size() : 1; + bool cacheLoaded = false; + if (mProcessingSettings.rtc.cacheOutput) { +#ifndef GPUCA_HAVE_O2HEADERS + throw std::runtime_error("Cannot use RTC cache without O2 headers"); +#else + FILE* fp = fopen("rtc.cuda.cache", "rb"); + char sharead[20]; + if (fp) { + size_t len; + while (true) { + if (fread(sharead, 1, 20, fp) != 20) { + throw std::runtime_error("Cache file corrupt"); + } + if (memcmp(sharead, shasource, 20)) { + GPUInfo("Cache file content outdated (source)"); + break; + } + if (fread(sharead, 1, 20, fp) != 20) { + throw std::runtime_error("Cache file corrupt"); + } + if (memcmp(sharead, shaparam, 20)) { + GPUInfo("Cache file content outdated (param)"); + break; + } + if (fread(sharead, 1, 20, fp) != 20) { + throw std::runtime_error("Cache file corrupt"); + } + if (memcmp(sharead, shacmd, 20)) { + GPUInfo("Cache file content outdated (commandline)"); + break; + } + if (fread(sharead, 1, 20, fp) != 20) { + throw std::runtime_error("Cache file corrupt"); + } + if (memcmp(sharead, shakernels, 20)) { + GPUInfo("Cache file content outdated (kernel definitions)"); + break; + } + GPUSettingsProcessingRTC cachedSettings; + if (fread(&cachedSettings, sizeof(cachedSettings), 1, fp) != 1) { + throw std::runtime_error("Cache file corrupt"); + } + if (memcmp(&cachedSettings, &mProcessingSettings.rtc, sizeof(cachedSettings))) { + GPUInfo("Cache file content outdated (rtc parameters)"); + break; + } + std::vector<char> buffer; + for (unsigned int i = 0; i < nCompile; i++) { + if (fread(&len, sizeof(len), 1, fp) != 1) { + throw std::runtime_error("Cache file corrupt"); + } + buffer.resize(len); + if (fread(buffer.data(), 1, len, fp) != len) { + throw std::runtime_error("Cache file corrupt"); + } + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + ".o").c_str(), "w+b"); + if (fp2 == nullptr) { + throw std::runtime_error("Cannot open tmp file"); + } + if (fwrite(buffer.data(), 1, len, fp2) != len) { + throw std::runtime_error("Error writing file"); + } + fclose(fp2); + } + GPUInfo("Using RTC cache file"); + cacheLoaded = true; + break; + }; + fclose(fp); + } +#endif + } + if (!cacheLoaded) { + if (mProcessingSettings.debugLevel >= 0) { + GPUInfo("Starting CUDA RTC Compilation"); + } + HighResTimer rtcTimer; + rtcTimer.ResetStart(); +#pragma omp parallel for + for (unsigned int i = 0; i < nCompile; i++) { + if (mProcessingSettings.debugLevel >= 3) { + printf("Compiling %s\n", (filename + "_" + std::to_string(i) + ".cu").c_str()); + } + FILE* fp = fopen((filename + "_" + std::to_string(i) + ".cu").c_str(), "w+b"); + if (fp == nullptr) { + throw std::runtime_error("Error opening file"); + } + + std::string kernel = "extern \"C\" {"; + kernel += mProcessingSettings.rtc.compilePerKernel ? kernels[i] : kernelsall; + kernel += "}"; + + if (fwrite(rtcparam.c_str(), 1, rtcparam.size(), fp) != rtcparam.size() || + fwrite(_curtc_GPUReconstructionCUDArtc_cu_src, 1, _curtc_GPUReconstructionCUDArtc_cu_src_size, fp) != _curtc_GPUReconstructionCUDArtc_cu_src_size || + fwrite(kernel.c_str(), 1, kernel.size(), fp) != kernel.size()) { + throw std::runtime_error("Error writing file"); + } + fclose(fp); + std::string command = _curtc_GPUReconstructionCUDArtc_cu_command; + command += " -cubin -c " + filename + "_" + std::to_string(i) + ".cu -o " + filename + "_" + std::to_string(i) + ".o"; + if (mProcessingSettings.debugLevel >= 3) { + printf("Running command %s\n", command.c_str()); + } + if (system(command.c_str())) { + throw std::runtime_error("Error during CUDA compilation"); + } + } + if (mProcessingSettings.debugLevel >= 0) { + GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); + } + if (mProcessingSettings.rtc.cacheOutput) { + FILE* fp = fopen("rtc.cuda.cache", "w+b"); + if (fp == nullptr) { + throw std::runtime_error("Cannot open cache file for writing"); + } + GPUInfo("Storing RTC compilation result in cache file"); + + if (fwrite(shasource, 1, 20, fp) != 20 || + fwrite(shaparam, 1, 20, fp) != 20 || + fwrite(shacmd, 1, 20, fp) != 20 || + fwrite(shakernels, 1, 20, fp) != 20 || + fwrite(&mProcessingSettings.rtc, sizeof(mProcessingSettings.rtc), 1, fp) != 1) { + throw std::runtime_error("Error writing cache file"); + } + + std::vector<char> buffer; + for (unsigned int i = 0; i < nCompile; i++) { + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + ".o").c_str(), "rb"); + if (fp2 == nullptr) { + throw std::runtime_error("Cannot open cuda module file"); + } + fseek(fp2, 0, SEEK_END); + size_t size = ftell(fp2); + buffer.resize(size); + fseek(fp2, 0, SEEK_SET); + if (fread(buffer.data(), 1, size, fp2) != size) { + throw std::runtime_error("Error reading cuda module file"); + } + fclose(fp2); + + if (fwrite(&size, sizeof(size), 1, fp) != 1 || + fwrite(buffer.data(), 1, size, fp) != size) { + throw std::runtime_error("Error writing cache file"); + } + } + fclose(fp); + } + } + + for (unsigned int i = 0; i < nCompile; i++) { + mInternals->rtcModules.emplace_back(std::make_unique<CUmodule>()); + GPUFailedMsg(cuModuleLoad(mInternals->rtcModules.back().get(), (filename + "_" + std::to_string(i) + ".o").c_str())); + remove((filename + "_" + std::to_string(i) + ".cu").c_str()); + remove((filename + "_" + std::to_string(i) + ".o").c_str()); + } + + int j = 0; +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ + mInternals->getRTCkernelNum<false, GPUCA_M_KRNL_TEMPLATE(x_class)>(mInternals->rtcFunctions.size()); \ + mInternals->rtcFunctions.emplace_back(new CUfunction); \ + GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), *mInternals->rtcModules[mProcessingSettings.rtc.compilePerKernel ? j++ : 0], GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))))); +#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ + mInternals->getRTCkernelNum<true, GPUCA_M_KRNL_TEMPLATE(x_class)>(mInternals->rtcFunctions.size()); \ + mInternals->rtcFunctions.emplace_back(new CUfunction); \ + GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), *mInternals->rtcModules[mProcessingSettings.rtc.compilePerKernel ? j++ : 0], GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)))); +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL +#undef GPUCA_KRNL_LOAD_single +#undef GPUCA_KRNL_LOAD_multi + +#endif + return 0; +} diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h index 449a4d889585f..6d0e2bf1e86e6 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #ifndef O2_GPU_GPURECONSTRUCTIONCUDAINCLUDES_H #define O2_GPU_GPURECONSTRUCTIONCUDAINCLUDES_H -#include <stdint.h> +#include <cstdint> #include <cuda_runtime.h> #include <cuda.h> #include <cooperative_groups.h> @@ -27,5 +28,8 @@ #include <thrust/device_ptr.h> #pragma GCC diagnostic pop #include <sm_20_atomic_functions.h> +#include <cuda_fp16.h> +#include <type_traits> +#include <string> #endif diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h index 11a41fdb4fba7..e57cae04dd25a 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #ifndef GPURECONSTRUCTIONCUDAINTERNALS_H #define GPURECONSTRUCTIONCUDAINTERNALS_H +#include <cuda.h> #include "GPULogging.h" #include <vector> #include <memory> @@ -26,7 +28,7 @@ namespace gpu { struct GPUReconstructionCUDAInternals { CUcontext CudaContext; // CUDA context - CUmodule rtcModule; // module for RTC compilation + std::vector<std::unique_ptr<CUmodule>> rtcModules; // module for RTC compilation std::vector<std::unique_ptr<CUfunction>> rtcFunctions; // vector of ptrs to RTC kernels unsigned int cudaContextObtained = 0; // If multiple instances of GPUThreadContextCUDA are obtained, we count them and return the context only after all are destroyed cudaStream_t Streams[GPUCA_MAX_STREAMS]; // Pointer to array of CUDA Streams @@ -57,42 +59,7 @@ static void GPUFailedMsgA(const long long int error, const char* file, int line) static_assert(std::is_convertible<cudaEvent_t, void*>::value, "CUDA event type incompatible to deviceEvent"); -class ThrustVolatileAsyncAllocator -{ - public: - typedef char value_type; - - ThrustVolatileAsyncAllocator(GPUReconstruction* r) : mRec(r) {} - char* allocate(std::ptrdiff_t n) { return (char*)mRec->AllocateVolatileDeviceMemory(n); } - - void deallocate(char* ptr, size_t) {} - - private: - GPUReconstruction* mRec; -}; - } // namespace gpu } // namespace GPUCA_NAMESPACE -// Override synchronize call at end of thrust algorithm running on stream, just don't run cudaStreamSynchronize -namespace thrust -{ -namespace cuda_cub -{ - -typedef thrust::cuda_cub::execution_policy<typeof(thrust::cuda::par(*(GPUCA_NAMESPACE::gpu::ThrustVolatileAsyncAllocator*)nullptr).on(*(cudaStream_t*)nullptr))> thrustStreamPolicy; -template <> -__host__ __device__ inline cudaError_t synchronize<thrustStreamPolicy>(thrustStreamPolicy& policy) -{ -#ifndef GPUCA_GPUCODE_DEVICE - // Do not synchronize! - return cudaSuccess; -#else - return synchronize_stream(derived_cast(policy)); -#endif -} - -} // namespace cuda_cub -} // namespace thrust - #endif diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu new file mode 100644 index 0000000000000..034dffbbe69bc --- /dev/null +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu @@ -0,0 +1,205 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionCUDAKernels.cu +/// \author David Rohr + +#include "GPUReconstructionCUDADef.h" +#include "GPUReconstructionCUDAIncludes.h" + +#include "GPUReconstructionCUDA.h" +#include "GPUReconstructionCUDAInternals.h" +#include "CUDAThrustHelpers.h" + +using namespace GPUCA_NAMESPACE::gpu; + +#ifdef GPUCA_USE_TEXTURES +texture<cahit2, cudaTextureType1D, cudaReadModeElementType> gAliTexRefu2; +texture<calink, cudaTextureType1D, cudaReadModeElementType> gAliTexRefu; +#endif + +class GPUDebugTiming +{ + public: + GPUDebugTiming(bool d, void** t, cudaStream_t* s, GPUReconstruction::krnlSetup& x, GPUReconstructionCUDABackend* r = nullptr) : mDeviceTimers(t), mStreams(s), mXYZ(x), mRec(r), mDo(d) + { + if (mDo) { + if (mDeviceTimers) { + GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[0], mStreams[mXYZ.x.stream])); + } else { + mTimer.ResetStart(); + } + } + } + ~GPUDebugTiming() + { + if (mDo) { + if (mDeviceTimers) { + GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[1], mStreams[mXYZ.x.stream])); + GPUFailedMsg(cudaEventSynchronize((cudaEvent_t)mDeviceTimers[1])); + float v; + GPUFailedMsg(cudaEventElapsedTime(&v, (cudaEvent_t)mDeviceTimers[0], (cudaEvent_t)mDeviceTimers[1])); + mXYZ.t = v * 1.e-3; + } else { + GPUFailedMsg(cudaStreamSynchronize(mStreams[mXYZ.x.stream])); + mXYZ.t = mTimer.GetCurrentElapsedTime(); + } + } + } + + private: + void** mDeviceTimers; + cudaStream_t* mStreams; + GPUReconstruction::krnlSetup& mXYZ; + GPUReconstructionCUDABackend* mRec; + HighResTimer mTimer; + bool mDo; +}; + +#include "GPUReconstructionIncludesDevice.h" + +/* +// Not using templated kernel any more, since nvidia profiler does not resolve template names +template <class T, int I, typename... Args> +GPUg() void runKernelCUDA(GPUCA_CONSMEM_PTR int iSlice_internal, Args... args) +{ + GPUshared() typename T::GPUSharedMemory smem; + T::template Thread<I>(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, T::Processor(GPUCA_CONSMEM)[iSlice_internal], args...); +} +*/ + +#undef GPUCA_KRNL_REG +#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_KRNL_PROP(x_class, x_attributes) \ + GPUCA_KRNL_WRAP(GPUCA_KRNL_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))<<<x.nBlocks, x.nThreads, 0, me->mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, args...); +#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)<<<x.nBlocks, x.nThreads, 0, me->mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, y.num, args...); + +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL + +template <bool multi, class T, int I> +int GPUReconstructionCUDAInternals::getRTCkernelNum(int k) +{ + static int num = k; + if (num < 0) { + throw std::runtime_error("Invalid kernel"); + } + return num; +} + +template <> +void GPUReconstructionCUDABackend::runKernelBackendInternal<GPUMemClean16, 0>(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) +{ + GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); + GPUFailedMsg(cudaMemsetAsync(ptr, 0, size, mInternals->Streams[_xyz.x.stream])); +} + +static void getArgPtrs(const void** pArgs) {} +template <typename T, typename... Args> +static void getArgPtrs(const void** pArgs, const T& arg, const Args&... args) +{ + *pArgs = &arg; + getArgPtrs(pArgs + 1, args...); +} + +template <class T, int I, typename... Args> +void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, const Args&... args) +{ + GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (void**)mDebugEvents, mInternals->Streams, _xyz); + if (mProcessingSettings.rtc.enable) { + auto& x = _xyz.x; + auto& y = _xyz.y; + const void* pArgs[sizeof...(Args) + 3]; // 3 is max: cons mem + y.start + y.num + int arg_offset = 0; +#ifdef GPUCA_NO_CONSTANT_MEMORY + arg_offset = 1; + pArgs[0] = &mDeviceConstantMemRTC[0]; +#endif + pArgs[arg_offset] = &y.start; + getArgPtrs(&pArgs[arg_offset + 1 + (y.num > 1)], args...); + if (y.num <= 1) { + GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum<false, T, I>()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); + } else { + pArgs[arg_offset + 1] = &y.num; + GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum<true, T, I>()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); + } + } else { + backendInternal<T, I>::runKernelBackendMacro(_xyz, this, args...); + } + if (mProcessingSettings.checkKernelFailures) { + if (GPUDebug(GetKernelName<T, I>(), _xyz.x.stream, true)) { + throw std::runtime_error("Kernel Failure"); + } + } +} + +template <class T, int I, typename... Args> +int GPUReconstructionCUDABackend::runKernelBackend(krnlSetup& _xyz, Args... args) +{ + auto& x = _xyz.x; + auto& z = _xyz.z; + if (z.evList) { + for (int k = 0; k < z.nEvents; k++) { + GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[x.stream], ((cudaEvent_t*)z.evList)[k], 0)); + } + } + runKernelBackendInternal<T, I>(_xyz, args...); + GPUFailedMsg(cudaGetLastError()); + if (z.ev) { + GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)z.ev, mInternals->Streams[x.stream])); + } + return 0; +} + +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ + template int GPUReconstructionCUDABackend::runKernelBackend<GPUCA_M_KRNL_TEMPLATE(x_class)>(krnlSetup & _xyz GPUCA_M_STRIP(x_arguments)); \ + template int GPUReconstructionCUDAInternals::getRTCkernelNum<false, GPUCA_M_KRNL_TEMPLATE(x_class)>(int k); \ + template int GPUReconstructionCUDAInternals::getRTCkernelNum<true, GPUCA_M_KRNL_TEMPLATE(x_class)>(int k); +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL + +void* GPUReconstructionCUDABackend::GetBackendConstSymbolAddress() +{ + void* retVal = nullptr; +#ifndef GPUCA_NO_CONSTANT_MEMORY + GPUFailedMsg(cudaGetSymbolAddress(&retVal, gGPUConstantMemBuffer)); +#endif + return retVal; +} + +void GPUReconstructionCUDABackend::PrintKernelOccupancies() +{ + int maxBlocks, threads, suggestedBlocks; + cudaFuncAttributes attr; + GPUFailedMsg(cuCtxPushCurrent(mInternals->CudaContext)); +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ + GPUFailedMsg(cudaOccupancyMaxPotentialBlockSize(&suggestedBlocks, &threads, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ + GPUFailedMsg(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxBlocks, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)), threads, 0)); \ + GPUFailedMsg(cudaFuncGetAttributes(&attr, GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ + GPUInfo("Kernel: %50s Block size: %4d, Maximum active blocks: %3d, Suggested blocks: %3d, Regs: %3d, smem: %3d", GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), threads, maxBlocks, suggestedBlocks, attr.numRegs, (int)attr.sharedSizeBytes); +#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ + GPUFailedMsg(cudaOccupancyMaxPotentialBlockSize(&suggestedBlocks, &threads, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ + GPUFailedMsg(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxBlocks, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi), threads, 0)); \ + GPUFailedMsg(cudaFuncGetAttributes(&attr, GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ + GPUInfo("Kernel: %50s Block size: %4d, Maximum active blocks: %3d, Suggested blocks: %3d, Regs: %3d, smem: %3d", GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), threads, maxBlocks, suggestedBlocks, attr.numRegs, (int)attr.sharedSizeBytes); +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL +#undef GPUCA_KRNL_LOAD_single +#undef GPUCA_KRNL_LOAD_multi + GPUFailedMsg(cuCtxPopCurrent(&mInternals->CudaContext)); +} + +template class GPUReconstructionKernels<GPUReconstructionCUDABackend>; diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu index 194093439f34b..9a3d1cf4cef6b 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,16 +18,3 @@ #ifndef GPUCA_GPUCODE_DEVICE #error RTC Preprocessing must run on device code #endif -#ifdef GPUCA_NO_CONSTANT_MEMORY -#error CUDA RTC does not support processing without constant memory -#endif - -extern "C" { -#undef GPUCA_KRNL_REG -#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -} diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index 62a171ef7cf28..9dda3711d040c 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTrackingHIP) @@ -22,7 +23,7 @@ endif() message(STATUS "Building GPUTracking with HIP support ${TMP_TARGET}") set(SRCS GPUReconstructionHIP.hip.cxx) -set(HDRS GPUReconstructionHIP.h GPUReconstructionHIPInternals.h) +set(HDRS GPUReconstructionHIP.h GPUReconstructionHIPInternals.h GPUReconstructionHIPIncludes.h HIPThrustHelpers.h) if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_library( @@ -31,6 +32,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") PUBLIC_LINK_LIBRARIES O2::GPUTracking O2::ITStrackingHIP hip::host hip::device hip::hipcub roc::rocthrust PUBLIC_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src ${CMAKE_SOURCE_DIR}/Detectors/Base/src + ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src TARGETVARNAME targetName) target_compile_definitions( @@ -39,11 +41,11 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") install(FILES ${HDRS} DESTINATION include/GPU) - o2_add_test(GPUsortHIP NAME test_GPUsortHIP - SOURCES test/testGPUsortHIP.hip.cxx - PUBLIC_LINK_LIBRARIES O2::GPUCommon hip::host hip::device hip::hipcub roc::rocthrust - COMPONENT_NAME GPU - LABELS gpu) +# o2_add_test(GPUsortHIP NAME test_GPUsortHIP +# SOURCES test/testGPUsortHIP.hip.cxx +# PUBLIC_LINK_LIBRARIES O2::GPUCommon hip::host hip::device hip::hipcub roc::rocthrust +# COMPONENT_NAME GPU +# LABELS gpu) endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h index 9f36d0db0fb78..28fdb5b02f558 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,7 +42,7 @@ class GPUReconstructionHIPBackend : public GPUReconstructionDeviceBase void UpdateSettings() override; void SynchronizeGPU() override; - int GPUDebug(const char* state = "UNKNOWN", int stream = -1) override; + int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; void SynchronizeStream(int stream) override; void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx index 98b8882d6b81f..5bdbffc6fa13d 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,12 +17,7 @@ #define GPUCA_UNROLL(CUDA, HIP) GPUCA_M_UNROLL_##HIP #define GPUdic(CUDA, HIP) GPUCA_GPUdic_select_##HIP() -#include <hip/hip_runtime.h> -#ifdef __CUDACC__ -#define hipExtLaunchKernelGGL(...) -#else -#include <hip/hip_ext.h> -#endif +#include "GPUReconstructionHIPIncludes.h" #include "GPUDef.h" @@ -46,6 +42,7 @@ #include "GPUReconstructionHIP.h" #include "GPUReconstructionHIPInternals.h" +#include "HIPThrustHelpers.h" #include "GPUReconstructionIncludes.h" #ifdef GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM @@ -56,12 +53,12 @@ using namespace GPUCA_NAMESPACE::gpu; __global__ void dummyInitKernel(void*) {} -#if defined(HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) -#include "ITStrackingHIP/VertexerTraitsHIP.h" +#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_NO_ITS_TRAITS) +#include "ITStrackingGPU/VertexerTraitsGPU.h" #else namespace o2::its { -class VertexerTraitsHIP : public VertexerTraits +class VertexerTraitsGPU : public VertexerTraits { }; class TrackerTraitsHIP : public TrackerTraits @@ -213,7 +210,7 @@ void GPUReconstructionHIPBackend::GetITSTraits(std::unique_ptr<o2::its::TrackerT // trackerTraits->reset(new o2::its::TrackerTraitsNV); // } if (vertexerTraits) { - vertexerTraits->reset(new o2::its::VertexerTraitsHIP); + vertexerTraits->reset(new o2::its::VertexerTraitsGPU); } } @@ -306,6 +303,9 @@ int GPUReconstructionHIPBackend::InitDevice_Runtime() GPUInfo("\tmultiProcessorCount = %d", hipDeviceProp.multiProcessorCount); GPUInfo(" "); } + if (hipDeviceProp.warpSize != GPUCA_WARP_SIZE) { + throw std::runtime_error("Invalid warp size on GPU"); + } mBlockCount = hipDeviceProp.multiProcessorCount; mMaxThreads = std::max<int>(mMaxThreads, hipDeviceProp.maxThreadsPerBlock * mBlockCount); mWarpSize = 64; @@ -478,7 +478,7 @@ size_t GPUReconstructionHIPBackend::TransferMemoryInternal(GPUMemoryResource* re } return 0; } - if (mProcessingSettings.debugLevel >= 3) { + if (mProcessingSettings.debugLevel >= 3 && (strcmp(res->Name(), "ErrorCodes") || mProcessingSettings.debugLevel >= 4)) { GPUInfo("Copying to %s: %s - %lld bytes", toGPU ? "GPU" : "Host", res->Name(), (long long int)res->Size()); } return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); @@ -542,7 +542,7 @@ bool GPUReconstructionHIPBackend::IsEventDone(deviceEvent* evList, int nEvents) return (true); } -int GPUReconstructionHIPBackend::GPUDebug(const char* state, int stream) +int GPUReconstructionHIPBackend::GPUDebug(const char* state, int stream, bool force) { // Wait for HIP-Kernel to finish and check for HIP errors afterwards, in case of debugmode hipError_t cuErr; @@ -551,7 +551,7 @@ int GPUReconstructionHIPBackend::GPUDebug(const char* state, int stream) GPUError("HIP Error %s while running kernel (%s) (Stream %d)", hipGetErrorString(cuErr), state, stream); return (1); } - if (mProcessingSettings.debugLevel <= 0) { + if (!force && mProcessingSettings.debugLevel <= 0) { return (0); } if (GPUFailedMsgI(hipDeviceSynchronize())) { @@ -566,12 +566,12 @@ int GPUReconstructionHIPBackend::GPUDebug(const char* state, int stream) int GPUReconstructionHIPBackend::registerMemoryForGPU(const void* ptr, size_t size) { - return GPUFailedMsgI(hipHostRegister((void*)ptr, size, hipHostRegisterDefault)); + return mProcessingSettings.noGPUMemoryRegistration ? 0 : GPUFailedMsgI(hipHostRegister((void*)ptr, size, hipHostRegisterDefault)); } int GPUReconstructionHIPBackend::unregisterMemoryForGPU(const void* ptr) { - return GPUFailedMsgI(hipHostUnregister((void*)ptr)); + return mProcessingSettings.noGPUMemoryRegistration ? 0 : GPUFailedMsgI(hipHostUnregister((void*)ptr)); } void* GPUReconstructionHIPBackend::getGPUPointer(void* ptr) diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPIncludes.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPIncludes.h new file mode 100644 index 0000000000000..6a93c5d724cc0 --- /dev/null +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPIncludes.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionHIPInclude.h +/// \author David Rohr + +#ifndef O2_GPU_RECONSTRUCTIONHIPINCLUDES_H +#define O2_GPU_RECONSTRUCTIONHIPINCLUDES_H + +#include <hip/hip_runtime.h> +#ifdef __CUDACC__ +#define hipExtLaunchKernelGGL(...) +#else +#include <hip/hip_ext.h> +#endif +#include <hipcub/hipcub.hpp> +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include <thrust/sort.h> +#include <thrust/execution_policy.h> +#include <thrust/device_ptr.h> +#pragma GCC diagnostic pop + +#endif diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h index 9f2cea00f7e14..6ae4ced135e8b 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #ifndef GPURECONSTRUCTIONHIPINTERNALS_H #define GPURECONSTRUCTIONHIPINTERNALS_H +#include <hip/hip_runtime.h> #include "GPULogging.h" namespace GPUCA_NAMESPACE @@ -47,20 +49,6 @@ static void GPUFailedMsgA(const long long int error, const char* file, int line) static_assert(std::is_convertible<hipEvent_t, void*>::value, "HIP event type incompatible to deviceEvent"); -class ThrustVolatileAsyncAllocator -{ - public: - typedef char value_type; - - ThrustVolatileAsyncAllocator(GPUReconstruction* r) : mRec(r) {} - char* allocate(std::ptrdiff_t n) { return (char*)mRec->AllocateVolatileDeviceMemory(n); } - - void deallocate(char* ptr, size_t) {} - - private: - GPUReconstruction* mRec; -}; - } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h b/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h new file mode 100644 index 0000000000000..fbe52ed23e4bd --- /dev/null +++ b/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file HIPThrustHelpers.h +/// \author David Rohr + +#ifndef GPU_HIPTHRUSTHELPERS_H +#define GPU_HIPTHRUSTHELPERS_H + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +class ThrustVolatileAsyncAllocator +{ + public: + typedef char value_type; + + ThrustVolatileAsyncAllocator(GPUReconstruction* r) : mRec(r) {} + char* allocate(std::ptrdiff_t n) { return (char*)mRec->AllocateVolatileDeviceMemory(n); } + + void deallocate(char* ptr, size_t) {} + + private: + GPUReconstruction* mRec; +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx b/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx index a12e1dabd4d13..c7c4d9456ca7d 100644 --- a/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx +++ b/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt b/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt index f2f39ae5f040e..deaa94265d1b0 100644 --- a/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTrackingOpenCLCommon) diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl index 91c6b7f2a2bb7..7c3e1bf48856e 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,13 @@ #ifdef GPUCA_OPENCLCPP_NO_CONSTANT_MEMORY #define GPUCA_NO_CONSTANT_MEMORY #endif - #pragma OPENCL EXTENSION cl_khr_fp64 : enable + #pragma OPENCL EXTENSION cl_khr_fp64 : enable // Allow double precision variables + #pragma OPENCL EXTENSION cl_khr_fp16 : enable // Allow half precision #ifdef __clang__ - #pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + #pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable // + #pragma OPENCL EXTENSION __cl_clang_function_pointers : enable // Allow function pointers + #pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable // Allow pointers to non-standard types as kernel arguments + #pragma OPENCL EXTENSION __cl_clang_bitfields : enable // Allow usage of bitfields #define global __global #define local __local #define constant __constant @@ -55,9 +60,14 @@ #define nullptr NULL #define NULL (0x0) #endif +#define uint64_t unsigned long #define uint32_t unsigned int #define uint16_t unsigned short #define uint8_t unsigned char +#define int64_t long +#define int32_t int +#define int16_t short +#define int8_t char // Disable assertions since they produce errors in GPU Code #ifdef assert diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx index 15b6076b4b4e8..8c93a75471257 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -252,11 +253,14 @@ int GPUReconstructionOCL::InitDevice_Runtime() for (int i = 0; i < mNStreams; i++) { #ifdef CL_VERSION_2_0 - cl_queue_properties prop = 0; - if (mProcessingSettings.deviceTimers) { - prop |= CL_QUEUE_PROFILING_ENABLE; - } + cl_queue_properties prop = mProcessingSettings.deviceTimers ? CL_QUEUE_PROFILING_ENABLE : 0; mInternals->command_queue[i] = clCreateCommandQueueWithProperties(mInternals->context, mInternals->device, &prop, &ocl_error); + if (mProcessingSettings.deviceTimers && ocl_error == CL_INVALID_QUEUE_PROPERTIES) { + GPUError("GPU device timers not supported by OpenCL platform, disabling"); + mProcessingSettings.deviceTimers = 0; + prop = 0; + mInternals->command_queue[i] = clCreateCommandQueueWithProperties(mInternals->context, mInternals->device, &prop, &ocl_error); + } #else mInternals->command_queue[i] = clCreateCommandQueue(mInternals->context, mInternals->device, 0, &ocl_error); #endif @@ -392,7 +396,7 @@ size_t GPUReconstructionOCL::TransferMemoryInternal(GPUMemoryResource* res, int } return 0; } - if (mProcessingSettings.debugLevel >= 3) { + if (mProcessingSettings.debugLevel >= 3 && (strcmp(res->Name(), "ErrorCodes") || mProcessingSettings.debugLevel >= 4)) { GPUInfo("Copying to %s: %s - %lld bytes", toGPU ? "GPU" : "Host", res->Name(), (long long int)res->Size()); } return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); @@ -462,10 +466,10 @@ bool GPUReconstructionOCL::IsEventDone(deviceEvent* evList, int nEvents) return true; } -int GPUReconstructionOCL::GPUDebug(const char* state, int stream) +int GPUReconstructionOCL::GPUDebug(const char* state, int stream, bool force) { // Wait for OPENCL-Kernel to finish and check for OPENCL errors afterwards, in case of debugmode - if (mProcessingSettings.debugLevel <= 0) { + if (!force && mProcessingSettings.debugLevel <= 0) { return (0); } for (int i = 0; i < mNStreams; i++) { diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h index 46e50e8547357..c3055f4ef4356 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ class GPUReconstructionOCL : public GPUReconstructionDeviceBase void SynchronizeGPU() override; int DoStuckProtection(int stream, void* event) override; - int GPUDebug(const char* state = "UNKNOWN", int stream = -1) override; + int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; void SynchronizeStream(int stream) override; void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h index 10d397ed9fe0a..7e57155d0419d 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl/CMakeLists.txt b/GPU/GPUTracking/Base/opencl/CMakeLists.txt index 85cfa1577f15f..c984f4e8eb32c 100644 --- a/GPU/GPUTracking/Base/opencl/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl/CMakeLists.txt @@ -1,14 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTrackingOCL) +enable_language(ASM) # AMD APP SDK required for OpenCL tracker as it's using specific extensions # (currently) not provided by other vendors @@ -36,10 +38,16 @@ set(CL_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL1Code.bin) # * checks the correct vendor implementation (AMD) # * builds binary code (blob) for the found platform(s) add_executable(opencl_compiler - ${GPUDIR}/Standalone/makefiles/makefile_opencl_compiler.cxx) + ${GPUDIR}/utils/makefile_opencl_compiler.cxx) target_link_libraries(opencl_compiler PUBLIC OpenCL::OpenCL) set_property(TARGET opencl_compiler PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + set(OPENCL_HEADER_FILTER "${CMAKE_SOURCE_DIR}") +else() + set(OPENCL_HEADER_FILTER "${CMAKE_SOURCE_DIR}/GPU") +endif() # executes OpenCL compiler wrapper to build binary object add_custom_command( @@ -51,13 +59,7 @@ add_custom_command( ${CL_SRC} -- "-D$<JOIN:$<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>,$<SEMICOLON>-D>" - -I${GPUDIR}/../Common - -I${GPUDIR}/Base - -I${GPUDIR}/Merger - -I${GPUDIR}/Global - -I${GPUDIR}/SliceTracker - -I${GPUDIR}/TRDTracking - -I${GPUDIR}/Standalone + "-I$<JOIN:$<FILTER:$<FILTER:$<TARGET_PROPERTY:O2::GPUTracking,INCLUDE_DIRECTORIES>,EXCLUDE,^/usr>,INCLUDE,^${OPENCL_HEADER_FILTER}>,$<SEMICOLON>-I>" -DGPUCA_GPULIBRARY=OCL1 -x clc++ MAIN_DEPENDENCY ${CL_SRC} @@ -67,8 +69,8 @@ add_custom_command( # cmake-format: off add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_common_GPUReconstructionOCL_cl/g" | sed "s/FILENAMENORMAL/GPUReconstructionOCL1Code.bin/g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_common_GPUReconstructionOCL_cl/g" | sed "s,FILENAMENORMAL,${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL1Code.bin,g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S ) # cmake-format: on @@ -78,9 +80,9 @@ set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.S PROPERTIES LANGUAGE - CXX + ASM OBJECT_DEPENDS - "${CL_BIN};${GPUDIR}/Standalone/makefiles/include.S") + "${CL_BIN};${GPUDIR}/utils/include.S") set(SRCS GPUReconstructionOCL1.cxx ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.S) diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx index 051bdcfeeb7da..3a670002fcd7d 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,7 +26,7 @@ using namespace GPUCA_NAMESPACE::gpu; #include <typeinfo> #include <cstdlib> -#include "../makefiles/opencl_obtain_program.h" +#include "utils/opencl_obtain_program.h" extern "C" char _makefile_opencl_program_Base_opencl_common_GPUReconstructionOCL_cl[]; GPUReconstruction* GPUReconstruction_Create_OCL(const GPUSettingsDeviceBackend& cfg) { return new GPUReconstructionOCL1(cfg); } diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h index 28131147f8463..00727ffd74a6b 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1Internals.h b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1Internals.h index 5b49fcfd81f27..997a108ac26d0 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1Internals.h +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1Internals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt index df3dc5eb959d4..f48fe4c14979a 100644 --- a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt @@ -1,14 +1,16 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTrackingOCL2) +enable_language(ASM) if(DEFINED OCL2_GPUTARGET) set(TMP_TARGET "(AMDGPU Target ${OCL2_GPUTARGET})") @@ -24,11 +26,12 @@ endif() set(CL_SRC ${GPUDIR}/Base/opencl-common/GPUReconstructionOCL.cl) set(CL_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL2Code) -set(OCL_FLAGS -cl-denorms-are-zero -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Xclang -finclude-default-header -Dcl_clang_storage_class_specifiers -Wno-invalid-constexpr -Wno-unused-command-line-argument -cl-std=clc++) +set(OCL_FLAGS -Xclang -fdenormal-fp-math-f32=ieee -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Dcl_clang_storage_class_specifiers -Wno-invalid-constexpr -Wno-unused-command-line-argument -cl-std=clc++) set(OCL_DEFINECL "-D$<JOIN:$<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>,$<SEMICOLON>-D>" - "-I$<JOIN:$<TARGET_PROPERTY:O2::GPUTracking,INCLUDE_DIRECTORIES>,$<SEMICOLON>-I>" + "-I$<JOIN:$<FILTER:$<TARGET_PROPERTY:O2::GPUTracking,INCLUDE_DIRECTORIES>,EXCLUDE,^/usr/include/?>,$<SEMICOLON>-I>" -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src -I${CMAKE_SOURCE_DIR}/Detectors/Base/src + -I${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src -I${CMAKE_SOURCE_DIR}/Detectors/ITSMFT/ITS/tracking/cuda/include -DGPUCA_GPULIBRARY=OCL2 -D__OPENCLCPP__ @@ -46,6 +49,7 @@ if(OPENCL2_ENABLED_AMD) # BUILD OpenCL2 binaries for AMD target add_custom_command( OUTPUT ${CL_BIN}.amd COMMAND ${CLANG_OCL} + -O3 ${OCL_FLAGS} ${OCL_DEFINECL} -mcpu=${OCL2_GPUTARGET} @@ -57,8 +61,8 @@ if(OPENCL2_ENABLED_AMD) # BUILD OpenCL2 binaries for AMD target # cmake-format: off add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.amd.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_amd/g" | sed "s/FILENAMENORMAL/GPUReconstructionOCL2Code.amd/g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.amd.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_amd/g" | sed "s,FILENAMENORMAL,${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL2Code.amd,g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.amd.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S ) # cmake-format: on @@ -68,9 +72,9 @@ if(OPENCL2_ENABLED_AMD) # BUILD OpenCL2 binaries for AMD target ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.amd.S PROPERTIES LANGUAGE - CXX + ASM OBJECT_DEPENDS - "${CL_BIN}.amd;${GPUDIR}/Standalone/makefiles/include.S") + "${CL_BIN}.amd;${GPUDIR}/utils/include.S") set(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.amd.S) endif() @@ -80,6 +84,7 @@ if(OPENCL2_ENABLED_SPIRV) # BUILD OpenCL2 intermediate code for SPIR-V target add_custom_command( OUTPUT ${CL_BIN}.bc COMMAND clang + -O0 -emit-llvm --target=spir64-unknown-unknown ${OCL_FLAGS} ${OCL_DEFINECL} @@ -97,8 +102,8 @@ if(OPENCL2_ENABLED_SPIRV) # BUILD OpenCL2 intermediate code for SPIR-V target # cmake-format: off add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.spirv.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_spirv/g" | sed "s/FILENAMENORMAL/GPUReconstructionOCL2Code.spirv/g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.spirv.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_spirv/g" | sed "s,FILENAMENORMAL,${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL2Code.spirv,g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.spirv.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S ) # cmake-format: on @@ -108,9 +113,9 @@ if(OPENCL2_ENABLED_SPIRV) # BUILD OpenCL2 intermediate code for SPIR-V target ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.spirv.S PROPERTIES LANGUAGE - CXX + ASM OBJECT_DEPENDS - "${CL_BIN}.spirv;${GPUDIR}/Standalone/makefiles/include.S") + "${CL_BIN}.spirv;${GPUDIR}/utils/include.S") set(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.spirv.S) endif() @@ -120,7 +125,7 @@ if(OPENCL2_ENABLED) # BUILD OpenCL2 source code for runtime compilation target add_custom_command( OUTPUT ${CL_BIN}.src COMMAND clang - ${OCL_DEFINECL} + ${OCL_DEFINECL} -cl-no-stdinc -E ${CL_SRC} > ${CL_BIN}.src MAIN_DEPENDENCY ${CL_SRC} IMPLICIT_DEPENDS CXX ${CL_SRC} @@ -129,8 +134,8 @@ if(OPENCL2_ENABLED) # BUILD OpenCL2 source code for runtime compilation target # cmake-format: off add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_src/g" | sed "s/FILENAMENORMAL/GPUReconstructionOCL2Code.src/g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.S - MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + COMMAND cat ${GPUDIR}/utils/include.S | sed "s/FILENAMEMOD/_makefile_opencl_program_Base_opencl_GPUReconstructionOCL2_cl_src/g" | sed "s,FILENAMENORMAL,${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL2Code.src,g" > ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.S + MAIN_DEPENDENCY ${GPUDIR}/utils/include.S ) # cmake-format: on @@ -140,9 +145,9 @@ if(OPENCL2_ENABLED) # BUILD OpenCL2 source code for runtime compilation target ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.S PROPERTIES LANGUAGE - CXX + ASM OBJECT_DEPENDS - "${CL_BIN}.src;${GPUDIR}/Standalone/makefiles/include.S") + "${CL_BIN}.src;${GPUDIR}/utils/include.S") set(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.S) endif() diff --git a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx index 700dfd9e3942a..d0c776ad5a207 100644 --- a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx +++ b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h index dbaa05f290d6e..c9d31f20c8b3b 100644 --- a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h +++ b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2Internals.h b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2Internals.h index 71902a9ac3175..8debdc47be8e8 100644 --- a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2Internals.h +++ b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2Internals.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Benchmark/CMakeLists.txt b/GPU/GPUTracking/Benchmark/CMakeLists.txt new file mode 100644 index 0000000000000..51ff4f6b8aaa9 --- /dev/null +++ b/GPU/GPUTracking/Benchmark/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +message(STATUS "Building GPU Standalone Benchmark") + +set(SRCS + standalone.cxx + ../utils/qconfig.cxx + ../Base/GPUReconstructionTimeframe.cxx) + +if(GPUCA_EVENT_DISPLAY) + set(SRCS ${SRCS} + ../display/GPUDisplayBackendX11.cxx + ../display/GPUDisplayBackendGlut.cxx) +endif() + +if(ALIGPU_BUILD_TYPE STREQUAL "O2") + o2_add_executable(standalone-benchmark + COMPONENT_NAME gpu + TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::GPUO2Interface O2::GPUTracking + SOURCES ${SRCS}) + + target_compile_definitions(${targetName} PUBLIC $<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>) +endif() + +if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + add_executable(ca ${SRCS}) + set(targetName ca) +endif() + +if(ROOT_FOUND) + target_sources(${targetName} PRIVATE ../qa/genEvents.cxx) +endif() + +if(GPUCA_EVENT_DISPLAY) + target_link_libraries(${targetName} PUBLIC X11::X11 glut) +endif() diff --git a/GPU/GPUTracking/Standalone/standalone.cxx b/GPU/GPUTracking/Benchmark/standalone.cxx similarity index 83% rename from GPU/GPUTracking/Standalone/standalone.cxx rename to GPU/GPUTracking/Benchmark/standalone.cxx index d589ab09a803c..f8c176e1019be 100644 --- a/GPU/GPUTracking/Standalone/standalone.cxx +++ b/GPU/GPUTracking/Benchmark/standalone.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,18 +32,15 @@ #include <thread> #include <future> #include <atomic> -#ifdef WITH_OPENMP -#include <omp.h> -#endif #ifndef _WIN32 #include <unistd.h> #include <sched.h> -#include <signal.h> +#include <csignal> #include <sys/types.h> #include <sys/wait.h> #include <sys/select.h> -#include <fenv.h> +#include <cfenv> #include <clocale> #include <sys/stat.h> #endif @@ -57,7 +55,7 @@ #include <xmmintrin.h> #include "GPUO2DataTypes.h" -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "GPUChainITS.h" #endif @@ -82,10 +80,14 @@ extern GPUSettingsStandalone configStandalone; GPUReconstruction *rec, *recAsync, *recPipeline; GPUChainTracking *chainTracking, *chainTrackingAsync, *chainTrackingPipeline; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS GPUChainITS *chainITS, *chainITSAsync, *chainITSPipeline; #endif -std::unique_ptr<char[]> outputmemory, outputmemoryPipeline, inputmemory; +void unique_ptr_aligned_delete(char* v) +{ + operator delete(v GPUCA_OPERATOR_NEW_ALIGNMENT); +} +std::unique_ptr<char, void (*)(char*)> outputmemory(nullptr, unique_ptr_aligned_delete), outputmemoryPipeline(nullptr, unique_ptr_aligned_delete), inputmemory(nullptr, unique_ptr_aligned_delete); std::unique_ptr<GPUDisplayBackend> eventDisplay; std::unique_ptr<GPUReconstructionTimeframe> tf; int nEventsInDirectory = 0; @@ -118,7 +120,7 @@ int ReadConfiguration(int argc, char** argv) } return 1; } - if (configStandalone.printSettings) { + if (configStandalone.printSettings > 1) { qConfigPrint(); } if (configStandalone.proc.debugLevel < 0) { @@ -169,14 +171,15 @@ int ReadConfiguration(int argc, char** argv) return 1; } #endif -#ifndef HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS configStandalone.runTRD = configStandalone.rundEdx = configStandalone.runCompression = configStandalone.runTransformation = configStandalone.testSyncAsync = configStandalone.testSync = 0; configStandalone.rec.ForceEarlyTPCTransform = 1; configStandalone.runRefit = false; #endif #ifndef GPUCA_TPC_GEOMETRY_O2 - configStandalone.rec.mergerReadFromTrackerDirectly = 0; + configStandalone.rec.tpc.mergerReadFromTrackerDirectly = 0; configStandalone.proc.ompKernels = false; + configStandalone.proc.createO2Output = 0; if (configStandalone.rundEdx == -1) { configStandalone.rundEdx = 0; } @@ -234,26 +237,30 @@ int ReadConfiguration(int argc, char** argv) if (configStandalone.eventDisplay) { configStandalone.noprompt = 1; } - if (configStandalone.proc.debugLevel >= 4 && !configStandalone.proc.ompKernels) { - configStandalone.proc.ompThreads = 1; + if (configStandalone.proc.debugLevel >= 4) { + if (configStandalone.proc.ompKernels) { + configStandalone.proc.ompKernels = 1; + } else { + configStandalone.proc.ompThreads = 1; + } } if (configStandalone.outputcontrolmem) { bool forceEmptyMemory = getenv("LD_PRELOAD") && strstr(getenv("LD_PRELOAD"), "valgrind") != nullptr; - outputmemory.reset(new char[configStandalone.outputcontrolmem]); + outputmemory.reset((char*)operator new(configStandalone.outputcontrolmem GPUCA_OPERATOR_NEW_ALIGNMENT)); if (forceEmptyMemory) { printf("Valgrind detected, emptying GPU output memory to avoid false positive undefined reads"); memset(outputmemory.get(), 0, configStandalone.outputcontrolmem); } if (configStandalone.proc.doublePipeline) { - outputmemoryPipeline.reset(new char[configStandalone.outputcontrolmem]); + outputmemoryPipeline.reset((char*)operator new(configStandalone.outputcontrolmem GPUCA_OPERATOR_NEW_ALIGNMENT)); if (forceEmptyMemory) { memset(outputmemoryPipeline.get(), 0, configStandalone.outputcontrolmem); } } } if (configStandalone.inputcontrolmem) { - inputmemory.reset(new char[configStandalone.inputcontrolmem]); + inputmemory.reset((char*)operator new(configStandalone.inputcontrolmem GPUCA_OPERATOR_NEW_ALIGNMENT)); } #if !(defined(CUDA_ENABLED) || defined(OPENCL1_ENABLED) || defined(HIP_ENABLED)) @@ -266,6 +273,11 @@ int ReadConfiguration(int argc, char** argv) #endif configStandalone.proc.showOutputStat = true; + + if (configStandalone.printSettings) { + qConfigPrint(); + } + return (0); } @@ -273,12 +285,12 @@ int SetupReconstruction() { if (!configStandalone.eventGenerator) { char filename[256]; - snprintf(filename, 256, "events/%s/", configStandalone.EventsDir); + snprintf(filename, 256, "events/%s/", configStandalone.eventsDir); if (rec->ReadSettings(filename)) { printf("Error reading event config file\n"); return 1; } - printf("Read event settings from dir %s (solenoidBz: %f, home-made events %d, constBz %d, maxTimeBin %d)\n", filename, rec->GetEventSettings().solenoidBz, (int)rec->GetEventSettings().homemadeEvents, (int)rec->GetEventSettings().constBz, rec->GetEventSettings().continuousMaxTimeBin); + printf("Read event settings from dir %s (solenoidBz: %f, home-made events %d, constBz %d, maxTimeBin %d)\n", filename, rec->GetGRPSettings().solenoidBz, (int)rec->GetGRPSettings().homemadeEvents, (int)rec->GetGRPSettings().constBz, rec->GetGRPSettings().continuousMaxTimeBin); if (configStandalone.testSyncAsync) { recAsync->ReadSettings(filename); } @@ -287,7 +299,10 @@ int SetupReconstruction() } } - GPUSettingsEvent ev = rec->GetEventSettings(); + chainTracking->mConfigQA = &configStandalone.QA; + chainTracking->mConfigDisplay = &configStandalone.display; + + GPUSettingsGRP grp = rec->GetGRPSettings(); GPUSettingsRec recSet; GPUSettingsProcessing devProc; memcpy((void*)&recSet, (void*)&configStandalone.rec, sizeof(GPUSettingsRec)); @@ -295,16 +310,16 @@ int SetupReconstruction() GPURecoStepConfiguration steps; if (configStandalone.eventGenerator) { - ev.homemadeEvents = true; + grp.homemadeEvents = true; } if (configStandalone.solenoidBz != -1e6f) { - ev.solenoidBz = configStandalone.solenoidBz; + grp.solenoidBz = configStandalone.solenoidBz; } if (configStandalone.constBz) { - ev.constBz = true; + grp.constBz = true; } if (configStandalone.TF.nMerge || configStandalone.TF.bunchSim) { - if (ev.continuousMaxTimeBin) { + if (grp.continuousMaxTimeBin) { printf("ERROR: requested to overlay continuous data - not supported\n"); return 1; } @@ -313,11 +328,11 @@ int SetupReconstruction() configStandalone.cont = true; } if (chainTracking->GetTPCTransform()) { - ev.continuousMaxTimeBin = configStandalone.TF.timeFrameLen * ((double)GPUReconstructionTimeframe::TPCZ / (double)GPUReconstructionTimeframe::DRIFT_TIME) / chainTracking->GetTPCTransform()->getVDrift(); + grp.continuousMaxTimeBin = configStandalone.TF.timeFrameLen * ((double)GPUReconstructionTimeframe::TPCZ / (double)GPUReconstructionTimeframe::DRIFT_TIME) / chainTracking->GetTPCTransform()->getVDrift(); } } - if (configStandalone.cont && ev.continuousMaxTimeBin == 0) { - ev.continuousMaxTimeBin = -1; + if (configStandalone.cont && grp.continuousMaxTimeBin == 0) { + grp.continuousMaxTimeBin = -1; } if (rec->GetDeviceType() == GPUReconstruction::DeviceType::CPU) { printf("Standalone Test Framework for CA Tracker - Using CPU\n"); @@ -353,6 +368,9 @@ int SetupReconstruction() #endif devProc.eventDisplay = eventDisplay.get(); } + if (devProc.runQA) { + devProc.runMC = true; + } steps.steps = GPUDataTypes::RecoStep::AllRecoSteps; if (configStandalone.runTRD != -1) { @@ -382,7 +400,7 @@ int SetupReconstruction() steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, false); } steps.inputs.set(GPUDataTypes::InOutType::TPCClusters, GPUDataTypes::InOutType::TRDTracklets); - if (ev.needsClusterer) { + if (grp.needsClusterer) { steps.inputs.setBits(GPUDataTypes::InOutType::TPCRaw, true); steps.inputs.setBits(GPUDataTypes::InOutType::TPCClusters, false); } else { @@ -397,7 +415,7 @@ int SetupReconstruction() } steps.outputs.clear(); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCSectorTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TPCSliceTracking) && !recSet.mergerReadFromTrackerDirectly); + steps.outputs.setBits(GPUDataTypes::InOutType::TPCSectorTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TPCSliceTracking) && !recSet.tpc.mergerReadFromTrackerDirectly); steps.outputs.setBits(GPUDataTypes::InOutType::TPCMergedTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TPCMerging)); steps.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, steps.steps.isSet(GPUDataTypes::RecoStep::TPCCompression)); steps.outputs.setBits(GPUDataTypes::InOutType::TRDTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TRDTracking)); @@ -413,9 +431,10 @@ int SetupReconstruction() devProc.eventDisplay = nullptr; } } - rec->SetSettings(&ev, &recSet, &devProc, &steps); + + rec->SetSettings(&grp, &recSet, &devProc, &steps); if (configStandalone.proc.doublePipeline) { - recPipeline->SetSettings(&ev, &recSet, &devProc, &steps); + recPipeline->SetSettings(&grp, &recSet, &devProc, &steps); } if (configStandalone.testSyncAsync) { // Set settings for asynchronous @@ -431,11 +450,11 @@ int SetupReconstruction() devProc.runQA = false; devProc.eventDisplay = eventDisplay.get(); devProc.runCompressionStatistics = 0; - recSet.DisableRefitAttachment = 0xFF; - recSet.loopInterpolationInExtraPass = 0; - recSet.MaxTrackQPt = CAMath::Min(recSet.MaxTrackQPt, recSet.tpcRejectQPt); + recSet.tpc.disableRefitAttachment = 0xFF; + recSet.tpc.loopInterpolationInExtraPass = 0; + recSet.maxTrackQPt = CAMath::Min(recSet.maxTrackQPt, recSet.tpc.rejectQPt); recSet.useMatLUT = true; - recAsync->SetSettings(&ev, &recSet, &devProc, &steps); + recAsync->SetSettings(&grp, &recSet, &devProc, &steps); } if (configStandalone.outputcontrolmem) { @@ -445,6 +464,16 @@ int SetupReconstruction() } } +#ifdef GPUCA_HAVE_O2HEADERS + chainTracking->SetDefaultO2PropagatorForGPU(); + if (configStandalone.testSyncAsync) { + chainTrackingAsync->SetDefaultO2PropagatorForGPU(); + } + if (configStandalone.proc.doublePipeline) { + chainTrackingPipeline->SetDefaultO2PropagatorForGPU(); + } +#endif + if (rec->Init()) { printf("Error initializing GPUReconstruction!\n"); return 1; @@ -470,7 +499,7 @@ int SetupReconstruction() int ReadEvent(int n) { char filename[256]; - snprintf(filename, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.EventsDir, n); + snprintf(filename, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.eventsDir, n); if (configStandalone.inputcontrolmem && !configStandalone.preloadEvents) { rec->SetInputControl(inputmemory.get(), configStandalone.inputcontrolmem); } @@ -478,6 +507,18 @@ int ReadEvent(int n) if (r) { return r; } +#if defined(GPUCA_TPC_GEOMETRY_O2) && defined(GPUCA_BUILD_QA) && !defined(GPUCA_O2_LIB) + if ((configStandalone.proc.runQA || configStandalone.eventDisplay) && !configStandalone.QA.noMC) { + chainTracking->ForceInitQA(); + snprintf(filename, 256, "events/%s/mc.%d.dump", configStandalone.eventsDir, n); + if (chainTracking->GetQA()->ReadO2MCData(filename)) { + snprintf(filename, 256, "events/%s/mc.%d.dump", configStandalone.eventsDir, 0); + if (chainTracking->GetQA()->ReadO2MCData(filename) && configStandalone.proc.runQA) { + throw std::runtime_error("Error reading O2 MC dump"); + } + } + } +#endif if (chainTracking->mIOPtrs.clustersNative && (configStandalone.TF.bunchSim || configStandalone.TF.nMerge || !configStandalone.runTransformation)) { if (configStandalone.proc.debugLevel >= 2) { printf("Converting Native to Legacy ClusterData for overlaying - WARNING: No raw clusters produced - Compression etc will not run!!!\n"); @@ -503,7 +544,7 @@ int LoadEvent(int iEvent, int x) } } bool encodeZS = configStandalone.encodeZS == -1 ? (chainTracking->mIOPtrs.tpcPackedDigits && !chainTracking->mIOPtrs.tpcZS) : (bool)configStandalone.encodeZS; - bool zsFilter = configStandalone.zsFilter == -1 ? (!encodeZS && chainTracking->mIOPtrs.tpcPackedDigits) : (bool)configStandalone.zsFilter; + bool zsFilter = configStandalone.zsFilter == -1 ? (!encodeZS && chainTracking->mIOPtrs.tpcPackedDigits && !chainTracking->mIOPtrs.tpcZS) : (bool)configStandalone.zsFilter; if (encodeZS || zsFilter) { if (!chainTracking->mIOPtrs.tpcPackedDigits) { printf("Need digit input to run ZS\n"); @@ -543,15 +584,20 @@ int LoadEvent(int iEvent, int x) ioPtrEvents[x] = chainTracking->mIOPtrs; ioMemEvents[x] = std::move(chainTracking->mIOMem); + chainTracking->mIOMem = decltype(chainTracking->mIOMem)(); return 0; } void OutputStat(GPUChainTracking* t, long long int* nTracksTotal = nullptr, long long int* nClustersTotal = nullptr) { int nTracks = 0; - for (unsigned int k = 0; k < t->mIOPtrs.nMergedTracks; k++) { - if (t->mIOPtrs.mergedTracks[k].OK()) { - nTracks++; + if (t->GetProcessingSettings().createO2Output) { + nTracks += t->mIOPtrs.nOutputTracksTPCO2; + } else { + for (unsigned int k = 0; k < t->mIOPtrs.nMergedTracks; k++) { + if (t->mIOPtrs.mergedTracks[k].OK()) { + nTracks++; + } } } if (nTracksTotal && nClustersTotal) { @@ -605,7 +651,7 @@ int RunBenchmark(GPUReconstruction* recUse, GPUChainTracking* chainTrackingUse, } } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (tmpRetVal == 0 && configStandalone.testSyncAsync) { if (configStandalone.testSyncAsync) { printf("Running asynchronous phase\n"); @@ -620,6 +666,8 @@ int RunBenchmark(GPUReconstruction* recUse, GPUChainTracking* chainTrackingUse, chainTrackingAsync->mIOPtrs.tpcPackedDigits = nullptr; chainTrackingAsync->mIOPtrs.mcInfosTPC = nullptr; chainTrackingAsync->mIOPtrs.nMCInfosTPC = 0; + chainTrackingAsync->mIOPtrs.mcInfosTPCCol = nullptr; + chainTrackingAsync->mIOPtrs.nMCInfosTPCCol = 0; chainTrackingAsync->mIOPtrs.mcLabelsTPC = nullptr; chainTrackingAsync->mIOPtrs.nMCLabelsTPC = 0; for (int i = 0; i < chainTracking->NSLICES; i++) { @@ -648,7 +696,9 @@ int RunBenchmark(GPUReconstruction* recUse, GPUChainTracking* chainTrackingUse, configStandalone.continueOnError = 0; // Forced exit from event display loop configStandalone.noprompt = 1; } - if (tmpRetVal && !configStandalone.continueOnError) { + if (tmpRetVal == 3 && configStandalone.proc.ignoreNonFatalGPUErrors) { + printf("Non-FATAL GPU error occured, ignoring\n"); + } else if (tmpRetVal && !configStandalone.continueOnError) { if (tmpRetVal != 2) { printf("Error occured\n"); } @@ -673,14 +723,14 @@ int main(int argc, char** argv) return 1; } - recUnique.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce)); + recUnique.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType.c_str() : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce)); rec = recUnique.get(); if (configStandalone.testSyncAsync) { - recUniqueAsync.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce, rec)); + recUniqueAsync.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType.c_str() : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce, rec)); recAsync = recUniqueAsync.get(); } if (configStandalone.proc.doublePipeline) { - recUniquePipeline.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce, rec)); + recUniquePipeline.reset(GPUReconstruction::CreateInstance(configStandalone.runGPU ? configStandalone.gpuType.c_str() : GPUReconstruction::DEVICE_TYPE_NAMES[GPUReconstruction::DeviceType::CPU], configStandalone.runGPUforce, rec)); recPipeline = recUniquePipeline.get(); } if (rec == nullptr || (configStandalone.testSyncAsync && recAsync == nullptr)) { @@ -701,7 +751,7 @@ int main(int argc, char** argv) } chainTrackingPipeline = recPipeline->AddChain<GPUChainTracking>(); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (!configStandalone.proc.doublePipeline) { chainITS = rec->AddChain<GPUChainITS>(0); if (configStandalone.testSyncAsync) { @@ -730,7 +780,7 @@ int main(int argc, char** argv) for (nEventsInDirectory = 0; true; nEventsInDirectory++) { std::ifstream in; char filename[256]; - snprintf(filename, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.EventsDir, nEventsInDirectory); + snprintf(filename, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.eventsDir, nEventsInDirectory); in.open(filename, std::ifstream::binary); if (in.fail()) { break; @@ -747,13 +797,13 @@ int main(int argc, char** argv) return 0; } - int nEvents = configStandalone.NEvents; + int nEvents = configStandalone.nEvents; if (configStandalone.TF.bunchSim) { - nEvents = configStandalone.NEvents > 0 ? configStandalone.NEvents : 1; + nEvents = configStandalone.nEvents > 0 ? configStandalone.nEvents : 1; } else { if (nEvents == -1 || nEvents > nEventsInDirectory) { if (nEvents >= 0) { - printf("Only %d events available in directors %s (%d events requested)\n", nEventsInDirectory, configStandalone.EventsDir, nEvents); + printf("Only %d events available in directors %s (%d events requested)\n", nEventsInDirectory, configStandalone.eventsDir, nEvents); } nEvents = nEventsInDirectory; } @@ -765,11 +815,15 @@ int main(int argc, char** argv) ioPtrEvents.resize(configStandalone.preloadEvents ? (nEvents - configStandalone.StartEvent) : 1); ioMemEvents.resize(configStandalone.preloadEvents ? (nEvents - configStandalone.StartEvent) : 1); if (configStandalone.preloadEvents) { - printf("Preloading events"); + printf("Preloading events%s", configStandalone.proc.debugLevel >= 2 ? "\n" : ""); fflush(stdout); for (int i = 0; i < nEvents - configStandalone.StartEvent; i++) { LoadEvent(configStandalone.StartEvent + i, i); - printf(" %d", i); + if (configStandalone.proc.debugLevel >= 2) { + printf("Loading event %d\n", i); + } else { + printf(" %d", i); + } fflush(stdout); } printf("\n"); @@ -807,18 +861,18 @@ int main(int argc, char** argv) } if (configStandalone.overrideMaxTimebin && (chainTracking->mIOPtrs.clustersNative || chainTracking->mIOPtrs.tpcPackedDigits || chainTracking->mIOPtrs.tpcZS)) { - GPUSettingsEvent ev = rec->GetEventSettings(); - if (ev.continuousMaxTimeBin == 0) { + GPUSettingsGRP grp = rec->GetGRPSettings(); + if (grp.continuousMaxTimeBin == 0) { printf("Cannot override max time bin for non-continuous data!\n"); } else { - ev.continuousMaxTimeBin = chainTracking->mIOPtrs.tpcZS ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcZS) : chainTracking->mIOPtrs.tpcPackedDigits ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcPackedDigits) : GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.clustersNative); - printf("Max time bin set to %d\n", (int)ev.continuousMaxTimeBin); - rec->UpdateEventSettings(&ev); + grp.continuousMaxTimeBin = chainTracking->mIOPtrs.tpcZS ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcZS) : chainTracking->mIOPtrs.tpcPackedDigits ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcPackedDigits) : GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.clustersNative); + printf("Max time bin set to %d\n", (int)grp.continuousMaxTimeBin); + rec->UpdateGRPSettings(&grp); if (recAsync) { - recAsync->UpdateEventSettings(&ev); + recAsync->UpdateGRPSettings(&grp); } if (recPipeline) { - recPipeline->UpdateEventSettings(&ev); + recPipeline->UpdateGRPSettings(&grp); } } } diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index eecf72ce1c48b..2dfc8f94ca8bd 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUTracking) @@ -55,17 +56,20 @@ set(SRCS Merger/GPUTPCGMPhysicalTrackModel.cxx Merger/GPUTPCGMPolynomialField.cxx Merger/GPUTPCGMPolynomialFieldManager.cxx - TRDTracking/GPUTRDTrack.cxx + DataTypes/GPUTRDTrack.cxx TRDTracking/GPUTRDTracker.cxx TRDTracking/GPUTRDTrackletWord.cxx TRDTracking/GPUTRDTrackerKernels.cxx Base/GPUParam.cxx) +set(SRCS_O2_DATATYPES + DataTypes/GPUTRDTrackO2.cxx) + set(SRCS_NO_CINT - Base/GPUDataTypes.cxx + DataTypes/GPUDataTypes.cxx + DataTypes/GPUMemorySizeScalers.cxx Base/GPUReconstruction.cxx Base/GPUReconstructionCPU.cxx - Base/GPUSettings.cxx Base/GPUProcessor.cxx Base/GPUMemoryResource.cxx Base/GPUGeneralKernels.cxx @@ -77,10 +81,18 @@ set(SRCS_NO_CINT Global/GPUTrackingInputProvider.cxx Global/GPUErrors.cxx Merger/GPUTPCGMMergerGPU.cxx - Standalone/utils/timer.cxx) + Debug/GPUROOTDumpCore.cxx + utils/timer.cxx) set(SRCS_NO_H SliceTracker/GPUTPCTrackerDump.cxx Merger/GPUTPCGMMergerDump.cxx + Global/GPUChainTrackingClusterizer.cxx + Global/GPUChainTrackingTransformation.cxx + Global/GPUChainTrackingTRD.cxx + Global/GPUChainTrackingRefit.cxx + Global/GPUChainTrackingSliceTracker.cxx + Global/GPUChainTrackingMerger.cxx + Global/GPUChainTrackingCompression.cxx Global/GPUChainTrackingDebugAndProfiling.cxx Global/GPUChainTrackingIO.cxx) @@ -97,9 +109,10 @@ set(HDRS_INSTALL Merger/GPUTPCGMOfflineStatisticalErrors.h Merger/GPUTPCGMMergedTrack.h Merger/GPUTPCGMMergedTrackHit.h - TRDTracking/GPUTRDDef.h + DataTypes/GPUTRDDef.h + DataTypes/GPUSettings.h TRDTracking/GPUTRDTrackPoint.h - TRDTracking/GPUTRDTrack.h + TRDTracking/GPUTRDSpacePoint.h TRDTracking/GPUTRDTrackData.h TRDTracking/GPUTRDTrackPoint.h TRDTracking/GPUTRDTrackletLabels.h @@ -114,36 +127,42 @@ set(HDRS_INSTALL Base/GPUReconstructionKernels.h Base/GPUReconstructionIncludesITS.h Base/GPUReconstructionHelpers.h - Base/GPUOutputControl.h - Base/GPUOutputControl.h - Base/GPUO2DataTypes.h - Base/GPUHostDataTypes.h - Base/GPUMemorySizeScalers.h - Base/GPURawData.h - dEdx/GPUdEdxInfo.h - dEdx/TPCdEdxCalibrationSplines.h TPCConvert/GPUTPCConvertImpl.h Base/GPUReconstructionKernelMacros.h - Base/GPUO2FakeClasses.h + DataTypes/GPUO2FakeClasses.h + Definitions/GPUSettingsList.h + DataTypes/GPUOutputControl.h + DataTypes/GPUO2DataTypes.h + DataTypes/GPUHostDataTypes.h + DataTypes/GPUdEdxInfo.h + DataTypes/GPUTRDInterfaceO2Track.h Base/GPUParam.inc Merger/GPUTPCGMMergerTypes.h Global/GPUErrorCodes.h - Standalone/qconfigoptions.h - Standalone/qa/GPUQAHelper.h - Base/GPUSettingsList.h + Global/GPUChainTrackingDefs.h + qconfigoptions.h + qa/GPUQAHelper.h DataCompression/GPUTPCClusterRejection.h + Refit/GPUTrackParamConvert.h + Definitions/GPUDef.h + Definitions/GPUDefConstantsAndSettings.h + Definitions/GPUDefGPUParameters.h + Definitions/GPUDefOpenCL12Templates.h + Definitions/GPULogging.h + Definitions/GPUDefMacros.h + Debug/GPUROOTDump.h ) # Sources only for O2 if(ALIGPU_BUILD_TYPE STREQUAL "O2") - set(SRCS ${SRCS} Interface/GPUO2Interface.cxx Interface/GPUO2InterfaceRefit.cxx Interface/GPUO2InterfaceQA.cxx Interface/GPUO2InterfaceConfigurableParam.cxx) - set(HDRS_CINT_O2 ${HDRS_CINT_O2} Interface/GPUO2Interface.h Interface/GPUO2InterfaceRefit.h Interface/GPUO2InterfaceQA.h Interface/GPUO2InterfaceConfigurableParam.h dEdx/TPCdEdxCalibrationSplines.h) - set(HDRS_CINT_O2_ADDITIONAL Base/GPUSettings.h Base/GPUSettingsList.h TRDTracking/GPUTRDTrack.h) # Manual dependencies for ROOT dictionary generation + set(SRCS ${SRCS} Interface/GPUO2InterfaceConfigurableParam.cxx) + set(HDRS_CINT_O2 ${HDRS_CINT_O2} DataTypes/TPCdEdxCalibrationSplines.h Interface/GPUO2InterfaceConfigurableParam.h) + set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypes.h DataTypes/GPUTRDTrack.h Merger/GPUTPCGMMergedTrack.h) # Manual dependencies for ROOT dictionary generation endif() # Sources for O2 and for Standalone if requested in config file if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR ALIGPU_BUILD_TYPE STREQUAL "Standalone") - set(SRCS_NO_CINT ${SRCS_NO_CINT} Standalone/display/GPUDisplayBackend.cxx) + set(SRCS_NO_CINT ${SRCS_NO_CINT} display/GPUDisplayBackend.cxx) endif() if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) set(SRCS_NO_CINT @@ -152,7 +171,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) ITS/GPUITSFitter.cxx ITS/GPUITSFitterKernels.cxx dEdx/GPUdEdx.cxx - dEdx/TPCdEdxCalibrationSplines.cxx + DataTypes/TPCdEdxCalibrationSplines.cxx TPCConvert/GPUTPCConvert.cxx TPCConvert/GPUTPCConvertKernel.cxx DataCompression/GPUTPCCompression.cxx @@ -163,6 +182,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) TPCClusterFinder/GPUTPCClusterFinder.cxx TPCClusterFinder/ClusterAccumulator.cxx TPCClusterFinder/MCLabelAccumulator.cxx + TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx TPCClusterFinder/GPUTPCCFStreamCompaction.cxx TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx TPCClusterFinder/GPUTPCCFPeakFinder.cxx @@ -172,22 +192,22 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) TPCClusterFinder/GPUTPCCFMCLabelFlattener.cxx TPCClusterFinder/GPUTPCCFDecodeZS.cxx TPCClusterFinder/GPUTPCCFGather.cxx - TPCClusterFinder/TPCCFCalibration.cxx - dEdx/TPCdEdxCalibrationSplines.cxx - Refit/GPUTrackingRefit.cxx) + DataTypes/TPCPadGainCalib.cxx + Refit/GPUTrackingRefit.cxx + Refit/GPUTrackingRefitKernel.cxx + Merger/GPUTPCGMO2Output.cxx) set(SRCS_NO_H ${SRCS_NO_H} TPCClusterFinder/GPUTPCClusterFinderDump.cxx) set(HDRS_INSTALL ${HDRS_INSTALL} - Interface/GPUO2InterfaceConfiguration.h ITS/GPUITSTrack.h TPCClusterFinder/Array2D.h TPCClusterFinder/CfConsts.h TPCClusterFinder/CfFragment.h TPCClusterFinder/CfUtils.h TPCClusterFinder/ChargePos.h - TPCClusterFinder/clusterFinderDefs.h + Definitions/clusterFinderDefs.h TPCClusterFinder/GPUTPCClusterFinderKernels.h TPCClusterFinder/PackedCharge.h TPCClusterFinder/GPUTPCCFChainContext.h) @@ -216,23 +236,30 @@ endif() # Optional sources depending on optional dependencies if(GPUCA_EVENT_DISPLAY) - set(SRCS_NO_CINT ${SRCS_NO_CINT} Standalone/utils/qsem.cxx - Standalone/display/GPUDisplay.cxx - Standalone/display/GPUDisplayBackendGlfw.cxx) - set(SRCS_NO_H ${SRCS_NO_H} Standalone/display/GPUDisplayQuaternion.cxx - Standalone/display/GPUDisplayInterpolation.cxx - Standalone/display/GPUDisplayKeys.cxx) + set(SRCS_NO_CINT ${SRCS_NO_CINT} utils/qsem.cxx + display/GPUDisplay.cxx + display/GPUDisplayBackendGlfw.cxx) + set(SRCS_NO_H ${SRCS_NO_H} display/GPUDisplayQuaternion.cxx + display/GPUDisplayInterpolation.cxx + display/GPUDisplayKeys.cxx + display/GPUDisplayROOT.cxx) set(HDRS_INSTALL ${HDRS_INSTALL} - Standalone/display/GPUDisplayExt.h - Standalone/display/GPUDisplayShaders.h) + display/GPUDisplayExt.h + display/GPUDisplayShaders.h) + if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + install(DIRECTORY display/filterMacros/ DESTINATION displayTrackFilter FILES_MATCHING PATTERN "*.C") + get_property(GPU_DISPLAY_INCLUDE_PATH DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) + configure_file(display/filterMacros/setinclude.sh.in setinclude.sh @ONLY) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setinclude.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE DESTINATION displayTrackFilter) + endif() else() - set(HDRS_INSTALL ${HDRS_INSTALL} Standalone/display/GPUDisplay.h) + set(HDRS_INSTALL ${HDRS_INSTALL} display/GPUDisplay.h) endif() if(GPUCA_QA) - set(SRCS_NO_CINT ${SRCS_NO_CINT} Standalone/qa/GPUQA.cxx) + set(SRCS_NO_CINT ${SRCS_NO_CINT} qa/GPUQA.cxx) else() - set(HDRS_INSTALL ${HDRS_INSTALL} Standalone/qa/GPUQA.h) + set(HDRS_INSTALL ${HDRS_INSTALL} qa/GPUQA.h) endif() # Update HDR variables with files derrived from SRC variables @@ -248,31 +275,52 @@ if (TARGET AliceO2::DebugGUI) endif() # Main CMake part for O2 if(ALIGPU_BUILD_TYPE STREQUAL "O2") + o2_add_library(GPUDataTypeHeaders + TARGETVARNAME targetName + PUBLIC_INCLUDE_DIRECTORIES . + Definitions + DataTypes + PUBLIC_LINK_LIBRARIES O2::GPUCommon + O2::ReconstructionDataFormats + PRIVATE_LINK_LIBRARIES O2::DataFormatsTPC + SOURCES ${SRCS_O2_DATATYPES}) +target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB + GPUCA_TPC_GEOMETRY_O2 GPUCA_HAVE_O2HEADERS) + + o2_add_library(${MODULE} TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::GPUCommon O2::GPUUtils + O2::GPUDataTypeHeaders O2::DataFormatsTPC + O2::DataFormatsTOF O2::TPCBase O2::TRDBase + O2::TOFBase + O2::ITSBase O2::ITStracking O2::TPCFastTransformation O2::DetectorsRaw ${DEBUGGUI_TARGET} - PUBLIC_INCLUDE_DIRECTORIES SliceTracker + O2::Steer + PUBLIC_INCLUDE_DIRECTORIES . + Definitions + DataTypes Base + SliceTracker TPCConvert dEdx ITS TRDTracking - Standalone - Standalone/qa - Standalone/display + qa + display Global HLTHeaders Interface Merger Refit + Debug DataCompression TPCClusterFinder TARGETVARNAME targetName @@ -287,11 +335,11 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") LINKDEF GPUTrackingLinkDef_O2.h) target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB - GPUCA_TPC_GEOMETRY_O2 HAVE_O2HEADERS) + GPUCA_TPC_GEOMETRY_O2 GPUCA_HAVE_O2HEADERS) install(FILES ${HDRS_CINT_ALIROOT} ${HDRS_CINT_O2} ${HDRS_INSTALL} DESTINATION include/GPU) - install(DIRECTORY Standalone/utils + install(DIRECTORY utils DESTINATION include/GPU FILES_MATCHING PATTERN *.h) @@ -301,14 +349,16 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_test_root_macro(Standalone/tools/createLUT.C PUBLIC_LINK_LIBRARIES O2::GPUTracking LABELS its COMPILE_ONLY) + + add_subdirectory(Interface) endif() # Main CMake part for AliRoot if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(HDRS_CINT_ALIROOT ${HDRS_CINT_ALIROOT} - Base/GPUO2DataTypes.h) + DataTypes/GPUO2DataTypes.h) add_definitions(-DGPUCA_ALIROOT_LIB) - include_directories(Standalone/display Standalone/qa) + include_directories(display qa) include_directories(SYSTEM ${ROOT_INCLUDE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/HLT/BASE ${CMAKE_SOURCE_DIR}/HLT/BASE/util @@ -327,7 +377,9 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") ${CMAKE_SOURCE_DIR}/GPU/Common ${CMAKE_SOURCE_DIR}/GPU/Utils ${CMAKE_SOURCE_DIR}/GPU/GPUTracking - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Standalone + ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Debug + ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions + ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/DataTypes ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/SliceTracker ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Merger @@ -335,7 +387,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/TPCConvert ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/dEdx ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/TRDTracking - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Standalone + ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/utils ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base/cuda ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base/hip ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base/opencl-common @@ -388,7 +440,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") install(TARGETS Ali${MODULE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) install(FILES ${HDRS_CINT_ALIROOT} ${HDRS_INSTALL} DESTINATION include) - install(DIRECTORY Standalone/utils + install(DIRECTORY utils DESTINATION include FILES_MATCHING PATTERN *.h) @@ -462,3 +514,9 @@ if(CUDA_ENABLED OR OPENCL1_ENABLED OR OPENCL2_ENABLED OR HIP_ENABLED) endif() endif() endif() + +if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR ALIGPU_BUILD_TYPE STREQUAL "Standalone") + if(NOT ${CMAKE_SYSTEM} MATCHES Darwin AND (NOT GPUCA_EVENT_DISPLAY OR (GLUT_FOUND AND GLEW_FOUND AND X11_FOUND))) + add_subdirectory(Benchmark) + endif() +endif() diff --git a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx index 238f620a371e6..330a87d3bfb21 100644 --- a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx +++ b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.h b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.h index 9142d1ebd49ea..126c37eba1b05 100644 --- a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.h +++ b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataCompression/GPUTPCClusterRejection.h b/GPU/GPUTracking/DataCompression/GPUTPCClusterRejection.h index 890e15b7df61d..2599f305c3541 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCClusterRejection.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCClusterRejection.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.cxx b/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.cxx index e2b85cd4e1dfd..04e57426c1927 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -111,7 +112,7 @@ void GPUTPCClusterStatistics::RunStatistics(const o2::tpc::ClusterNativeAccess* auto allocator = [&clusterBuffer](size_t size) {clusterBuffer.resize(size); return clusterBuffer.data(); }; mDecoder.decompress(clustersCompressed, clustersNativeDecoded, allocator, param); std::vector<o2::tpc::ClusterNative> tmpClusters; - if (param.rec.tpcRejectionMode == GPUSettings::RejectionNone) { // verification does not make sense if we reject clusters during compression + if (param.rec.tpc.rejectionStrategy == GPUSettings::RejectionNone) { // verification does not make sense if we reject clusters during compression for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { if (clustersNative->nClusters[i][j] != clustersNativeDecoded.nClusters[i][j]) { @@ -122,7 +123,7 @@ void GPUTPCClusterStatistics::RunStatistics(const o2::tpc::ClusterNativeAccess* tmpClusters.resize(clustersNative->nClusters[i][j]); for (unsigned int k = 0; k < clustersNative->nClusters[i][j]; k++) { tmpClusters[k] = clustersNative->clusters[i][j][k]; - if (param.rec.tpcCompressionModes & GPUSettings::CompressionTruncate) { + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionTruncate) { GPUTPCCompression::truncateSignificantBitsChargeMax(tmpClusters[k].qMax, param); GPUTPCCompression::truncateSignificantBitsCharge(tmpClusters[k].qTot, param); GPUTPCCompression::truncateSignificantBitsWidth(tmpClusters[k].sigmaPadPacked, param); diff --git a/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.h b/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.h index 1c1279d529b3c..7e14f4704a635 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCClusterStatistics.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ namespace GPUCA_NAMESPACE::gpu class GPUTPCClusterStatistics { public: -#ifndef HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS void RunStatistics(const o2::tpc::ClusterNativeAccess* clustersNative, const o2::tpc::CompressedClusters* clustersCompressed, const GPUParam& param){}; void Finish(){}; #else diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx index 02f141fe7baee..938076376e1d5 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "GPUTPCCompression.h" #include "GPUReconstruction.h" #include "GPUO2DataTypes.h" +#include "GPUMemorySizeScalers.h" using namespace GPUCA_NAMESPACE::gpu; @@ -39,7 +41,7 @@ void* GPUTPCCompression::SetPointersScratch(void* mem) computePointerWithAlignment(mem, mAttachedClusterFirstIndex, mMaxTracks); } if (mRec->GetProcessingSettings().tpcCompressionGatherMode != 1) { - SetPointersCompressedClusters(mem, mPtrs, mMaxTrackClusters, mMaxTracks, mMaxClusters, false); + SetPointersCompressedClusters(mem, mPtrs, mMaxTrackClusters, mMaxTracks, mMaxClustersInCache, false); } return mem; } @@ -48,7 +50,7 @@ void* GPUTPCCompression::SetPointersOutput(void* mem) { computePointerWithAlignment(mem, mAttachedClusterFirstIndex, mMaxTrackClusters); if (mRec->GetProcessingSettings().tpcCompressionGatherMode == 1) { - SetPointersCompressedClusters(mem, mPtrs, mMaxTrackClusters, mMaxTracks, mMaxClusters, false); + SetPointersCompressedClusters(mem, mPtrs, mMaxTrackClusters, mMaxTracks, mMaxClustersInCache, false); } return mem; } @@ -67,7 +69,7 @@ void GPUTPCCompression::SetPointersCompressedClusters(void*& mem, T& c, unsigned unsigned int nClAreduced = reducedClA ? nClA - nTr : nClA; - if (!(mRec->GetParam().rec.tpcCompressionModes & GPUSettings::CompressionTrackModel)) { + if (!(mRec->GetParam().rec.tpc.compressionTypeMask & GPUSettings::CompressionTrackModel)) { return; // Track model disabled, do not allocate memory } computePointerWithAlignment(mem, c.qTotA, nClA); @@ -115,6 +117,8 @@ void GPUTPCCompression::RegisterMemoryAllocation() void GPUTPCCompression::SetMaxData(const GPUTrackingInOutPointers& io) { mMaxClusters = io.clustersNative->nClustersTotal; + mMaxClusterFactorBase1024 = mMaxClusters > 100000000 ? mRec->MemoryScalers()->tpcCompressedUnattachedHitsBase1024[mRec->GetParam().rec.tpc.rejectionStrategy] : 1024; + mMaxClustersInCache = mMaxClusters * mMaxClusterFactorBase1024 / 1024; mMaxTrackClusters = mRec->GetConstantMem().tpcMerger.NOutputTrackClusters(); mMaxTracks = mRec->GetConstantMem().tpcMerger.NOutputTracks(); if (mMaxClusters % 16) { diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompression.h b/GPU/GPUTracking/DataCompression/GPUTPCCompression.h index b0f449bd81edb..04dc218921729 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompression.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompression.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include "GPUCommonMath.h" #include "GPUParam.h" -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "DataFormatsTPC/CompressedClusters.h" #else namespace o2::tpc @@ -65,9 +66,9 @@ class GPUTPCCompression : public GPUProcessor static constexpr unsigned int P_MAX_FLAGS = 1 << 8; static constexpr unsigned int P_MAX_QPT = 1 << 8; - GPUd() static void truncateSignificantBitsCharge(unsigned short& charge, const GPUParam& param) { truncateSignificantBits(charge, param.rec.tpcSigBitsCharge, P_MAX_QTOT); } - GPUd() static void truncateSignificantBitsChargeMax(unsigned short& charge, const GPUParam& param) { truncateSignificantBits(charge, param.rec.tpcSigBitsCharge, P_MAX_QMAX); } - GPUd() static void truncateSignificantBitsWidth(unsigned char& width, const GPUParam& param) { truncateSignificantBits(width, param.rec.tpcSigBitsWidth, P_MAX_SIGMA); } + GPUd() static void truncateSignificantBitsCharge(unsigned short& charge, const GPUParam& param) { truncateSignificantBits(charge, param.rec.tpc.sigBitsCharge, P_MAX_QTOT); } + GPUd() static void truncateSignificantBitsChargeMax(unsigned short& charge, const GPUParam& param) { truncateSignificantBits(charge, param.rec.tpc.sigBitsCharge, P_MAX_QMAX); } + GPUd() static void truncateSignificantBitsWidth(unsigned char& width, const GPUParam& param) { truncateSignificantBits(width, param.rec.tpc.sigBitsWidth, P_MAX_SIGMA); } protected: struct memory { @@ -90,7 +91,8 @@ class GPUTPCCompression : public GPUProcessor unsigned int mMaxTracks = 0; unsigned int mMaxClusters = 0; unsigned int mMaxTrackClusters = 0; - unsigned int mNMaxClusterSliceRow = 0; + unsigned int mMaxClustersInCache = 0; + size_t mMaxClusterFactorBase1024 = 0; template <class T> void SetPointersCompressedClusters(void*& mem, T& c, unsigned int nClA, unsigned int nTr, unsigned int nClU, bool reducedClA); diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx index 63e7087e5ad2e..6d5e4c9e52f89 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,6 @@ #include "GPUTPCCompressionKernels.h" #include "GPUConstantMem.h" #include "GPUO2DataTypes.h" -#include "GPUTPCGMMerger.h" #include "GPUParam.h" #include "GPUCommonAlgorithm.h" #include "GPUTPCCompressionTrackModel.h" @@ -27,43 +27,43 @@ using namespace o2::tpc; template <> GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step0attached>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors) { - const GPUTPCGMMerger& GPUrestrict() merger = processors.tpcMerger; - const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = processors.ioPtrs.clustersNative; + const GPUTrackingInOutPointers& GPUrestrict() ioPtrs = processors.ioPtrs; + const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = ioPtrs.clustersNative; GPUTPCCompression& GPUrestrict() compressor = processors.tpcCompressor; const GPUParam& GPUrestrict() param = processors.param; char lastLeg = 0; int myTrack = 0; - for (unsigned int i = get_global_id(0); i < (unsigned int)merger.NOutputTracks(); i += get_global_size(0)) { + for (unsigned int i = get_global_id(0); i < ioPtrs.nMergedTracks; i += get_global_size(0)) { GPUbarrierWarp(); - const GPUTPCGMMergedTrack& GPUrestrict() trk = merger.OutputTracks()[i]; + const GPUTPCGMMergedTrack& GPUrestrict() trk = ioPtrs.mergedTracks[i]; if (!trk.OK()) { continue; } - bool rejectTrk = CAMath::Abs(trk.GetParam().GetQPt()) > processors.param.rec.tpcRejectQPt || trk.MergedLooper(); + bool rejectTrk = CAMath::Abs(trk.GetParam().GetQPt()) > processors.param.rec.tpc.rejectQPt || trk.MergedLooper(); unsigned int nClustersStored = 0; CompressedClustersPtrs& GPUrestrict() c = compressor.mPtrs; unsigned int lastRow = 0, lastSlice = 0; // BUG: These should be unsigned char, but then CUDA breaks GPUTPCCompressionTrackModel track; float zOffset = 0; for (int k = trk.NClusters() - 1; k >= 0; k--) { - const GPUTPCGMMergedTrackHit& GPUrestrict() hit = merger.Clusters()[trk.FirstClusterRef() + k]; + const GPUTPCGMMergedTrackHit& GPUrestrict() hit = ioPtrs.mergedTrackHits[trk.FirstClusterRef() + k]; if (hit.state & GPUTPCGMMergedTrackHit::flagReject) { continue; } int hitId = hit.num; - int attach = merger.ClusterAttachment()[hitId]; + int attach = ioPtrs.mergedTrackHitAttachment[hitId]; if ((attach & gputpcgmmergertypes::attachTrackMask) != i) { continue; // Main attachment to different track } - bool rejectCluster = processors.param.rec.tpcRejectionMode && (rejectTrk || GPUTPCClusterRejection::GetIsRejected(attach)); + bool rejectCluster = processors.param.rec.tpc.trackFitRejectMode && (rejectTrk || GPUTPCClusterRejection::GetIsRejected(attach)); if (rejectCluster) { compressor.mClusterStatus[hitId] = 1; // Cluster rejected, do not store continue; } - if (!(param.rec.tpcCompressionModes & GPUSettings::CompressionTrackModel)) { + if (!(param.rec.tpc.compressionTypeMask & GPUSettings::CompressionTrackModel)) { continue; // No track model compression } const ClusterNative& GPUrestrict() orgCl = clusters->clusters[hit.slice][hit.row][hit.num - clusters->clusterOffset[hit.slice][hit.row]]; @@ -102,7 +102,7 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step0at unsigned int row = hit.row; unsigned int slice = hit.slice; - if (param.rec.tpcCompressionModes & GPUSettings::CompressionDifferences) { + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionDifferences) { if (lastRow > row) { row += GPUCA_ROW_COUNT; } @@ -122,7 +122,7 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step0at } unsigned short qtot = orgCl.qTot, qmax = orgCl.qMax; unsigned char sigmapad = orgCl.sigmaPadPacked, sigmatime = orgCl.sigmaTimePacked; - if (param.rec.tpcCompressionModes & GPUSettings::CompressionTruncate) { + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionTruncate) { compressor.truncateSignificantBitsChargeMax(qmax, param); compressor.truncateSignificantBitsCharge(qtot, param); compressor.truncateSignificantBitsWidth(sigmapad, param); @@ -177,10 +177,10 @@ GPUd() bool GPUTPCCompressionKernels::GPUTPCCompressionKernels_Compare<3>::opera } template <> -GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1unattached>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1unattached>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { - const GPUTPCGMMerger& GPUrestrict() merger = processors.tpcMerger; - const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = processors.ioPtrs.clustersNative; + const GPUTrackingInOutPointers& GPUrestrict() ioPtrs = processors.ioPtrs; + const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = ioPtrs.clustersNative; GPUTPCCompression& GPUrestrict() compressor = processors.tpcCompressor; GPUParam& GPUrestrict() param = processors.param; unsigned int* sortBuffer = smem.sortBuffer; @@ -188,6 +188,8 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1un const int iSlice = iSliceRow / GPUCA_ROW_COUNT; const int iRow = iSliceRow % GPUCA_ROW_COUNT; const int idOffset = clusters->clusterOffset[iSlice][iRow]; + const int idOffsetOut = clusters->clusterOffset[iSlice][iRow] * compressor.mMaxClusterFactorBase1024 / 1024; + const int idOffsetOutMax = ((const unsigned int*)clusters->clusterOffset[iSlice])[iRow + 1] * compressor.mMaxClusterFactorBase1024 / 1024; // Array out of bounds access is ok, since it goes to the correct nClustersTotal if (iThread == nThreads - 1) { smem.nCount = 0; } @@ -207,20 +209,20 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1un if (compressor.mClusterStatus[idx]) { break; } - int attach = merger.ClusterAttachment()[idx]; + int attach = ioPtrs.mergedTrackHitAttachment[idx]; bool unattached = attach == 0; if (unattached) { - if (processors.param.rec.tpcRejectionMode >= GPUSettings::RejectionStrategyB) { + if (processors.param.rec.tpc.rejectionStrategy >= GPUSettings::RejectionStrategyB) { break; } - } else if (processors.param.rec.tpcRejectionMode >= GPUSettings::RejectionStrategyA) { + } else if (processors.param.rec.tpc.rejectionStrategy >= GPUSettings::RejectionStrategyA) { if (GPUTPCClusterRejection::GetIsRejected(attach)) { break; } int id = attach & gputpcgmmergertypes::attachTrackMask; - auto& trk = merger.OutputTracks()[id]; - if (CAMath::Abs(trk.GetParam().GetQPt()) > processors.param.rec.tpcRejectQPt || trk.MergedLooper()) { + auto& trk = ioPtrs.mergedTracks[id]; + if (CAMath::Abs(trk.GetParam().GetQPt()) > processors.param.rec.tpc.rejectQPt || trk.MergedLooper()) { break; } } @@ -247,26 +249,31 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1un continue; } - const unsigned int count = CAMath::Min(smem.nCount, (unsigned int)GPUCA_TPC_COMP_CHUNK_SIZE); - if (param.rec.tpcCompressionModes & GPUSettings::CompressionDifferences) { - if (param.rec.tpcCompressionSortOrder == GPUSettings::SortZPadTime) { + unsigned int count = CAMath::Min(smem.nCount, (unsigned int)GPUCA_TPC_COMP_CHUNK_SIZE); + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionDifferences) { + if (param.rec.tpc.compressionSortOrder == GPUSettings::SortZPadTime) { CAAlgo::sortInBlock(sortBuffer, sortBuffer + count, GPUTPCCompressionKernels_Compare<GPUSettings::SortZPadTime>(clusters->clusters[iSlice][iRow])); - } else if (param.rec.tpcCompressionSortOrder == GPUSettings::SortZTimePad) { + } else if (param.rec.tpc.compressionSortOrder == GPUSettings::SortZTimePad) { CAAlgo::sortInBlock(sortBuffer, sortBuffer + count, GPUTPCCompressionKernels_Compare<GPUSettings::SortZTimePad>(clusters->clusters[iSlice][iRow])); - } else if (param.rec.tpcCompressionSortOrder == GPUSettings::SortPad) { + } else if (param.rec.tpc.compressionSortOrder == GPUSettings::SortPad) { CAAlgo::sortInBlock(sortBuffer, sortBuffer + count, GPUTPCCompressionKernels_Compare<GPUSettings::SortPad>(clusters->clusters[iSlice][iRow])); - } else if (param.rec.tpcCompressionSortOrder == GPUSettings::SortTime) { + } else if (param.rec.tpc.compressionSortOrder == GPUSettings::SortTime) { CAAlgo::sortInBlock(sortBuffer, sortBuffer + count, GPUTPCCompressionKernels_Compare<GPUSettings::SortTime>(clusters->clusters[iSlice][iRow])); } GPUbarrier(); } for (unsigned int j = get_local_id(0); j < count; j += get_local_size(0)) { - int outidx = idOffset + totalCount + j; + int outidx = idOffsetOut + totalCount + j; + if (outidx >= idOffsetOutMax) { + compressor.raiseError(GPUErrors::ERROR_COMPRESSION_ROW_HIT_OVERFLOW, outidx, idOffsetOutMax); + count = 0; + break; + } const ClusterNative& GPUrestrict() orgCl = clusters->clusters[iSlice][iRow][sortBuffer[j]]; unsigned int lastTime = 0; unsigned int lastPad = 0; - if (param.rec.tpcCompressionModes & GPUSettings::CompressionDifferences) { + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionDifferences) { if (j != 0) { const ClusterNative& GPUrestrict() orgClPre = clusters->clusters[iSlice][iRow][sortBuffer[j - 1]]; lastPad = orgClPre.padPacked; @@ -286,7 +293,7 @@ GPUdii() void GPUTPCCompressionKernels::Thread<GPUTPCCompressionKernels::step1un unsigned short qtot = orgCl.qTot, qmax = orgCl.qMax; unsigned char sigmapad = orgCl.sigmaPadPacked, sigmatime = orgCl.sigmaTimePacked; - if (param.rec.tpcCompressionModes & GPUSettings::CompressionTruncate) { + if (param.rec.tpc.compressionTypeMask & GPUSettings::CompressionTruncate) { compressor.truncateSignificantBitsChargeMax(qmax, param); compressor.truncateSignificantBitsCharge(qtot, param); compressor.truncateSignificantBitsWidth(sigmapad, param); @@ -339,13 +346,10 @@ GPUdi() GPUTPCCompressionGatherKernels::Vec128* GPUTPCCompressionGatherKernels:: template <typename T, typename S> GPUdi() bool GPUTPCCompressionGatherKernels::isAlignedTo(const S* ptr) { - CONSTEXPRIF(alignof(S) >= alignof(T)) - { + if CONSTEXPR17 (alignof(S) >= alignof(T)) { static_cast<void>(ptr); return true; - } - else - { + } else { return reinterpret_cast<size_t>(ptr) % alignof(T) == 0; } return false; // BUG: Cuda complains about missing return value with constexpr if @@ -450,7 +454,7 @@ GPUdi() void GPUTPCCompressionGatherKernels::compressorMemcpyBasic(T* GPUrestric } template <typename V, typename T, typename S> -GPUdi() void GPUTPCCompressionGatherKernels::compressorMemcpyBuffered(V* buf, T* GPUrestrict() dst, const T* GPUrestrict() src, const S* GPUrestrict() nums, const unsigned int* GPUrestrict() srcOffsets, unsigned int nTracks, int nLanes, int iLane, int diff) +GPUdi() void GPUTPCCompressionGatherKernels::compressorMemcpyBuffered(V* buf, T* GPUrestrict() dst, const T* GPUrestrict() src, const S* GPUrestrict() nums, const unsigned int* GPUrestrict() srcOffsets, unsigned int nEntries, int nLanes, int iLane, int diff, size_t scaleBase1024) { int shmPos = 0; unsigned int dstOffset = 0; @@ -460,9 +464,9 @@ GPUdi() void GPUTPCCompressionGatherKernels::compressorMemcpyBuffered(V* buf, T* CONSTEXPR int bufSize = GPUCA_WARP_SIZE; CONSTEXPR int bufTSize = bufSize * sizeof(V) / sizeof(T); - for (unsigned int i = 0; i < nTracks; i++) { + for (unsigned int i = 0; i < nEntries; i++) { unsigned int srcPos = 0; - unsigned int srcOffset = srcOffsets[i] + diff; + unsigned int srcOffset = (srcOffsets[i] * scaleBase1024 / 1024) + diff; unsigned int srcSize = nums[i] - diff; if (dstAligned == nullptr) { @@ -485,16 +489,19 @@ GPUdi() void GPUTPCCompressionGatherKernels::compressorMemcpyBuffered(V* buf, T* compressorMemcpyBasic(bufT + shmPos, src + srcOffset + srcPos, size, nLanes, iLane); srcPos += size; shmPos += size; + GPUbarrierWarp(); if (shmPos >= bufTSize) { compressorMemcpyBasic(dstAligned + dstOffset, buf, bufSize, nLanes, iLane); dstOffset += bufSize; shmPos = 0; + GPUbarrierWarp(); } } } compressorMemcpyBasic(reinterpret_cast<T*>(dstAligned + dstOffset), bufT, shmPos, nLanes, iLane); + GPUbarrierWarp(); } template <typename T> @@ -525,7 +532,7 @@ GPUdi() unsigned int GPUTPCCompressionGatherKernels::calculateWarpOffsets(GPUSha } template <> -GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::unbuffered>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::unbuffered>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { GPUTPCCompression& GPUrestrict() compressor = processors.tpcCompressor; const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = processors.ioPtrs.clustersNative; @@ -566,13 +573,14 @@ GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKern for (unsigned int i = sliceStart; i <= sliceEnd && i < compressor.NSLICES; i++) { for (unsigned int j = ((i == sliceStart) ? sliceRowStart : 0); j < ((i == sliceEnd) ? sliceRowEnd : GPUCA_ROW_COUNT); j++) { unsigned int nClusters = compressor.mPtrs.nSliceRowClusters[i * GPUCA_ROW_COUNT + j]; - compressorMemcpy(compressor.mOutput->qTotU + rowsOffset, compressor.mPtrs.qTotU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->qMaxU + rowsOffset, compressor.mPtrs.qMaxU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->flagsU + rowsOffset, compressor.mPtrs.flagsU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->padDiffU + rowsOffset, compressor.mPtrs.padDiffU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->timeDiffU + rowsOffset, compressor.mPtrs.timeDiffU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->sigmaPadU + rowsOffset, compressor.mPtrs.sigmaPadU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); - compressorMemcpy(compressor.mOutput->sigmaTimeU + rowsOffset, compressor.mPtrs.sigmaTimeU + clusters->clusterOffset[i][j], nClusters, nLanes, iLane); + unsigned int clusterOffsetInCache = clusters->clusterOffset[i][j] * compressor.mMaxClusterFactorBase1024 / 1024; + compressorMemcpy(compressor.mOutput->qTotU + rowsOffset, compressor.mPtrs.qTotU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->qMaxU + rowsOffset, compressor.mPtrs.qMaxU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->flagsU + rowsOffset, compressor.mPtrs.flagsU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->padDiffU + rowsOffset, compressor.mPtrs.padDiffU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->timeDiffU + rowsOffset, compressor.mPtrs.timeDiffU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->sigmaPadU + rowsOffset, compressor.mPtrs.sigmaPadU + clusterOffsetInCache, nClusters, nLanes, iLane); + compressorMemcpy(compressor.mOutput->sigmaTimeU + rowsOffset, compressor.mPtrs.sigmaTimeU + clusterOffsetInCache, nClusters, nLanes, iLane); rowsOffset += nClusters; } } @@ -625,7 +633,7 @@ GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKern } template <typename V> -GPUdii() void GPUTPCCompressionGatherKernels::gatherBuffered(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::gatherBuffered(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { GPUTPCCompression& GPUrestrict() compressor = processors.tpcCompressor; @@ -677,18 +685,18 @@ GPUdii() void GPUTPCCompressionGatherKernels::gatherBuffered(int nBlocks, int nT compressorMemcpyBasic(output->padA, input.padA, compressor.mMemory->nStoredTracks, nThreads, iThread); } - const unsigned int* clusterOffsets = reinterpret_cast<const unsigned int*>(clusters->clusterOffset) + rowStart; + const unsigned int* clusterOffsets = &clusters->clusterOffset[0][0] + rowStart; const unsigned int* nSliceRowClusters = input.nSliceRowClusters + rowStart; auto* buf = smem.getBuffer<V>(iWarp); - compressorMemcpyBuffered(buf, output->qTotU + rowsOffset, input.qTotU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->qMaxU + rowsOffset, input.qMaxU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->flagsU + rowsOffset, input.flagsU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->padDiffU + rowsOffset, input.padDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->timeDiffU + rowsOffset, input.timeDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->sigmaPadU + rowsOffset, input.sigmaPadU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->sigmaTimeU + rowsOffset, input.sigmaTimeU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); + compressorMemcpyBuffered(buf, output->qTotU + rowsOffset, input.qTotU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->qMaxU + rowsOffset, input.qMaxU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->flagsU + rowsOffset, input.flagsU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->padDiffU + rowsOffset, input.padDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->timeDiffU + rowsOffset, input.timeDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->sigmaPadU + rowsOffset, input.sigmaPadU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->sigmaTimeU + rowsOffset, input.sigmaTimeU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); const unsigned short* nTrackClustersPtr = input.nTrackClusters + trackStart; const unsigned int* aClsFstIdx = compressor.mAttachedClusterFirstIndex + trackStart; @@ -707,7 +715,7 @@ GPUdii() void GPUTPCCompressionGatherKernels::gatherBuffered(int nBlocks, int nT compressorMemcpyBuffered(buf, output->timeResA + tracksOffsetDiff, input.timeResA, nTrackClustersPtr, aClsFstIdx, tracksPerWarp, nLanes, iLane, 1); } -GPUdii() void GPUTPCCompressionGatherKernels::gatherMulti(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::gatherMulti(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { GPUTPCCompression& GPUrestrict() compressor = processors.tpcCompressor; const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = processors.ioPtrs.clustersNative; @@ -743,16 +751,16 @@ GPUdii() void GPUTPCCompressionGatherKernels::gatherMulti(int nBlocks, int nThre rowsPerWarp = rowEnd - rowStart; const unsigned int rowsOffset = calculateWarpOffsets(smem, input.nSliceRowClusters, rowStart, rowEnd, nWarps, iWarp, nLanes, iLane); - const unsigned int* clusterOffsets = reinterpret_cast<const unsigned int*>(clusters->clusterOffset) + rowStart; + const unsigned int* clusterOffsets = &clusters->clusterOffset[0][0] + rowStart; const unsigned int* nSliceRowClusters = input.nSliceRowClusters + rowStart; - compressorMemcpyBuffered(buf, output->qTotU + rowsOffset, input.qTotU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->qMaxU + rowsOffset, input.qMaxU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->flagsU + rowsOffset, input.flagsU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->padDiffU + rowsOffset, input.padDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->timeDiffU + rowsOffset, input.timeDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->sigmaPadU + rowsOffset, input.sigmaPadU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); - compressorMemcpyBuffered(buf, output->sigmaTimeU + rowsOffset, input.sigmaTimeU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0); + compressorMemcpyBuffered(buf, output->qTotU + rowsOffset, input.qTotU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->qMaxU + rowsOffset, input.qMaxU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->flagsU + rowsOffset, input.flagsU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->padDiffU + rowsOffset, input.padDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->timeDiffU + rowsOffset, input.timeDiffU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->sigmaPadU + rowsOffset, input.sigmaPadU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); + compressorMemcpyBuffered(buf, output->sigmaTimeU + rowsOffset, input.sigmaTimeU, nSliceRowClusters, clusterOffsets, rowsPerWarp, nLanes, iLane, 0, compressor.mMaxClusterFactorBase1024); } else { const unsigned int nGlobalWarps = nWarps * (nBlocks - 1) / 2; const unsigned int iGlobalWarp = nWarps * (iBlock / 2 - 1) + iWarp; @@ -787,25 +795,25 @@ GPUdii() void GPUTPCCompressionGatherKernels::gatherMulti(int nBlocks, int nThre } template <> -GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered32>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered32>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { gatherBuffered<Vec32>(nBlocks, nThreads, iBlock, iThread, smem, processors); } template <> -GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered64>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered64>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { gatherBuffered<Vec64>(nBlocks, nThreads, iBlock, iThread, smem, processors); } template <> -GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered128>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::buffered128>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { gatherBuffered<Vec128>(nBlocks, nThreads, iBlock, iThread, smem, processors); } template <> -GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::multiBlock>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCCompressionGatherKernels::Thread<GPUTPCCompressionGatherKernels::multiBlock>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { gatherMulti(nBlocks, nThreads, iBlock, iThread, smem, processors); } diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h index bcee016899094..b3d6212418c50 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,7 +41,7 @@ class GPUTPCCompressionKernels : public GPUKernelTemplate }; template <int iKernel = defaultKernel> - GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors); + GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); template <int I> class GPUTPCCompressionKernels_Compare @@ -97,7 +98,7 @@ class GPUTPCCompressionGatherKernels : public GPUKernelTemplate }; template <int iKernel = defaultKernel> - GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors); + GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); template <typename T, typename S> GPUdi() static bool isAlignedTo(const S* ptr); @@ -112,15 +113,15 @@ class GPUTPCCompressionGatherKernels : public GPUKernelTemplate GPUdi() static void compressorMemcpyBasic(T* dst, const T* src, unsigned int size, int nThreads, int iThread, int nBlocks = 1, int iBlock = 0); template <typename V, typename T, typename S> - GPUdi() static void compressorMemcpyBuffered(V* buf, T* dst, const T* src, const S* nums, const unsigned int* srcOffets, unsigned int nTracks, int nLanes, int iLane, int diff = 0); + GPUdi() static void compressorMemcpyBuffered(V* buf, T* dst, const T* src, const S* nums, const unsigned int* srcOffets, unsigned int nEntries, int nLanes, int iLane, int diff = 0, size_t scaleBase1024 = 1024); template <typename T> GPUdi() static unsigned int calculateWarpOffsets(GPUSharedMemory& smem, T* nums, unsigned int start, unsigned int end, int nWarps, int iWarp, int nLanes, int iLane); template <typename V> - GPUdii() static void gatherBuffered(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors); + GPUdii() static void gatherBuffered(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); - GPUdii() static void gatherMulti(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors); + GPUdii() static void gatherMulti(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); }; } // namespace GPUCA_NAMESPACE::gpu diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx index 1434885468d2c..a0e2e80078eab 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -90,7 +91,7 @@ GPUd() int GPUTPCCompressionTrackModel::Propagate(float x, float alpha) if (alpha != mAlpha && !mTrk.Rotate(alpha, t0, GPUCA_MAX_SIN_PHI)) { return 2; } - int retVal = !mTrk.TransportToX(x, t0, mParam->par.ConstBz, GPUCA_MAX_SIN_PHI); + int retVal = !mTrk.TransportToX(x, t0, mParam->par.constBz, GPUCA_MAX_SIN_PHI); // GPUInfo("Propagated to: x %f y %f z %f alpha %f qPt %f", x, mTrk.Y(), mTrk.Z(), alpha, mTrk.QPt()); return retVal; } @@ -126,7 +127,7 @@ GPUd() void GPUTPCCompressionTrackModel::Init(float x, float y, float z, float a mP[4] = (qPt - 127.f) * (20.f / 127.f); resetCovariance(); mNDF = -5; - mBz = param.par.ConstBz; + mBz = param.par.constBz; float pti = CAMath::Abs(mP[4]); if (pti < 1.e-4f) { pti = 1.e-4f; // set 10.000 GeV momentum for straight track diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h index 7f13e434bea45..22c2e08f1caa6 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -102,7 +103,6 @@ class GPUTPCCompressionTrackModel #endif protected: - #ifdef GPUCA_COMPRESSION_TRACK_MODEL_MERGER GPUTPCGMPropagator mProp; GPUTPCGMTrackParam mTrk; diff --git a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx index 51df22a39a175..d5eb975e259a1 100644 --- a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx +++ b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,7 @@ #include "GPUTPCCompressionTrackModel.h" #include <algorithm> #include <cstring> +#include <atomic> using namespace GPUCA_NAMESPACE::gpu; using namespace o2::tpc; @@ -37,13 +39,23 @@ int TPCClusterDecompressor::decompress(const CompressedClustersFlat* clustersCom int TPCClusterDecompressor::decompress(const CompressedClusters* clustersCompressed, o2::tpc::ClusterNativeAccess& clustersNative, std::function<o2::tpc::ClusterNative*(size_t)> allocator, const GPUParam& param) { std::vector<ClusterNative> clusters[NSLICES][GPUCA_ROW_COUNT]; - unsigned int offset = 0; - float zOffset = 0; + std::atomic_flag locks[NSLICES][GPUCA_ROW_COUNT]; + for (unsigned int i = 0; i < NSLICES * GPUCA_ROW_COUNT; i++) { + (&locks[0][0])[i].clear(); + } + unsigned int offset = 0, lasti = 0; + GPUCA_OPENMP(parallel for firstprivate(offset, lasti)) for (unsigned int i = 0; i < clustersCompressed->nTracks; i++) { + while (lasti < i) { + offset += clustersCompressed->nTrackClusters[lasti++]; + } + lasti++; + float zOffset = 0; unsigned int slice = clustersCompressed->sliceA[i]; unsigned int row = clustersCompressed->rowA[i]; GPUTPCCompressionTrackModel track; - for (unsigned int j = 0; j < clustersCompressed->nTrackClusters[i]; j++) { + unsigned int j; + for (j = 0; j < clustersCompressed->nTrackClusters[i]; j++) { unsigned int pad = 0, time = 0; if (j) { unsigned char tmpSlice = clustersCompressed->sliceLegDiffA[offset - i - 1]; @@ -65,11 +77,9 @@ int TPCClusterDecompressor::decompress(const CompressedClusters* clustersCompres row = clustersCompressed->rowDiffA[offset - i - 1]; } if (changeLeg && track.Mirror()) { - offset += clustersCompressed->nTrackClusters[i] - j; break; } if (track.Propagate(param.tpcGeometry.Row2X(row), param.SliceParam[slice].Alpha)) { - offset += clustersCompressed->nTrackClusters[i] - j; break; } unsigned int timeTmp = clustersCompressed->timeResA[offset - i - 1]; @@ -84,19 +94,24 @@ int TPCClusterDecompressor::decompress(const CompressedClusters* clustersCompres pad = clustersCompressed->padA[i]; } std::vector<ClusterNative>& clusterVector = clusters[slice][row]; + auto& lock = locks[slice][row]; + while (lock.test_and_set(std::memory_order_acquire)) { + } clusterVector.emplace_back(time, clustersCompressed->flagsA[offset], pad, clustersCompressed->sigmaTimeA[offset], clustersCompressed->sigmaPadA[offset], clustersCompressed->qMaxA[offset], clustersCompressed->qTotA[offset]); - float y = param.tpcGeometry.LinearPad2Y(slice, row, clusterVector.back().getPad()); - float z = param.tpcGeometry.LinearTime2Z(slice, clusterVector.back().getTime()); + auto& cluster = clusterVector.back(); + float y = param.tpcGeometry.LinearPad2Y(slice, row, cluster.getPad()); + float z = param.tpcGeometry.LinearTime2Z(slice, cluster.getTime()); + lock.clear(std::memory_order_release); if (j == 0) { zOffset = z; track.Init(param.tpcGeometry.Row2X(row), y, z - zOffset, param.SliceParam[slice].Alpha, clustersCompressed->qPtA[i], param); } if (j + 1 < clustersCompressed->nTrackClusters[i] && track.Filter(y, z - zOffset, row)) { - offset += clustersCompressed->nTrackClusters[i] - j; break; } offset++; } + offset += clustersCompressed->nTrackClusters[i] - j; } ClusterNative* clusterBuffer = allocator(clustersCompressed->nAttachedClusters + clustersCompressed->nUnattachedClusters); unsigned int offsets[NSLICES][GPUCA_ROW_COUNT]; diff --git a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.h b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.h index 991151bade1e9..9b4314a7af721 100644 --- a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.h +++ b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataCompression/standalone-cluster-dump-entropy-analysed.cxx b/GPU/GPUTracking/DataCompression/standalone-cluster-dump-entropy-analysed.cxx index 129edc0a63c63..0996781533f02 100644 --- a/GPU/GPUTracking/DataCompression/standalone-cluster-dump-entropy-analysed.cxx +++ b/GPU/GPUTracking/DataCompression/standalone-cluster-dump-entropy-analysed.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypes.cxx b/GPU/GPUTracking/DataTypes/GPUDataTypes.cxx new file mode 100644 index 0000000000000..fcf8f89560c7f --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUDataTypes.cxx @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDataTypes.cxx +/// \author David Rohr + +#include "GPUDataTypes.h" +#include "GPUReconstruction.h" + +using namespace GPUCA_NAMESPACE::gpu; + +constexpr const char* const GPUDataTypes::RECO_STEP_NAMES[]; +constexpr const char* const GPUDataTypes::GENERAL_STEP_NAMES[]; + +GPUDataTypes::DeviceType GPUDataTypes::GetDeviceType(const char* type) { return GPUReconstruction::GetDeviceType(type); } diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypes.h b/GPU/GPUTracking/DataTypes/GPUDataTypes.h new file mode 100644 index 0000000000000..bba07920391d7 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUDataTypes.h @@ -0,0 +1,350 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDataTypes.h +/// \author David Rohr + +#ifndef GPUDATATYPES_H +#define GPUDATATYPES_H + +#include "GPUCommonDef.h" + +// These are basic and non-comprex data types, which will also be visible on the GPU. +// Please add complex data types required on the host but not GPU to GPUHostDataTypes.h and forward-declare! +#ifndef GPUCA_GPUCODE_DEVICE +#include <cstddef> +#ifdef GPUCA_NOCOMPAT_ALLOPENCL +#include <type_traits> +#endif +#endif +#ifdef GPUCA_NOCOMPAT +#include "GPUTRDDef.h" + +struct AliHLTTPCClusterMCLabel; +struct AliHLTTPCRawCluster; +namespace o2 +{ +namespace tpc +{ +struct ClusterNativeAccess; +struct CompressedClustersFlat; +class Digit; +class TrackTPC; +namespace constants +{ +} // namespace constants +} // namespace tpc +} // namespace o2 +#endif + +namespace o2 +{ +class MCCompLabel; +template <typename T> +class BaseCluster; +namespace base +{ +template <typename T> +class PropagatorImpl; +class MatLayerCylSet; +} // namespace base +namespace track +{ +#ifdef GPUCA_NOCOMPAT +template <typename value_T> +class TrackParametrizationWithError; +using TrackParCov = TrackParametrizationWithError<float>; +#else +class TrackParCov; +#endif +} // namespace track +namespace trd +{ +class GeometryFlat; +} // namespace trd +namespace dataformats +{ +class TrackTPCITS; +class MatchInfoTOF; +template <class T> +class MCTruthContainer; +template <class T> +class ConstMCTruthContainerView; +} // namespace dataformats +namespace itsmft +{ +class CompClusterExt; +class ROFRecord; +class TopologyDictionary; +} // namespace itsmft +namespace its +{ +class TrackITS; +} // namespace its +namespace tof +{ +class Cluster; +} // namespace tof +} // namespace o2 + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +class TPCFastTransform; +class TPCdEdxCalibrationSplines; +struct TPCPadGainCalib; +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +#ifdef GPUCA_NOCOMPAT_ALLOPENCL +#include "utils/bitfield.h" +#define ENUM_CLASS class +#define ENUM_UINT : unsigned int +#define GPUCA_RECO_STEP GPUDataTypes::RecoStep +#else +#define ENUM_CLASS +#define ENUM_UINT +#define GPUCA_RECO_STEP GPUDataTypes +#endif + +#if defined(__OPENCL__) && !defined(__OPENCLCPP__) +MEM_CLASS_PRE() // Macro with some template magic for OpenCL 1.2 +#endif +class GPUTPCTrack; +class GPUTPCHitId; +class GPUTPCGMMergedTrack; +struct GPUTPCGMMergedTrackHit; +struct GPUTPCGMMergedTrackHitXYZ; +class GPUTRDTrackletWord; +class GPUTRDSpacePoint; +struct GPUTPCMCInfo; +struct GPUTPCMCInfoCol; +struct GPUTPCClusterData; +struct GPUTRDTrackletLabels; +struct GPUTPCDigitsMCInput; +struct GPUSettingsTF; + +class GPUDataTypes +{ + public: + enum ENUM_CLASS GeometryType ENUM_UINT{RESERVED_GEOMETRY = 0, ALIROOT = 1, O2 = 2}; + enum DeviceType ENUM_UINT { INVALID_DEVICE = 0, + CPU = 1, + CUDA = 2, + HIP = 3, + OCL = 4, + OCL2 = 5 }; + enum ENUM_CLASS GeneralStep { Prepare = 1, + QA = 2 }; + + enum ENUM_CLASS RecoStep { TPCConversion = 1, + TPCSliceTracking = 2, + TPCMerging = 4, + TPCCompression = 8, + TRDTracking = 16, + ITSTracking = 32, + TPCdEdx = 64, + TPCClusterFinding = 128, + TPCDecompression = 256, + Refit = 512, + AllRecoSteps = 0x7FFFFFFF, + NoRecoStep = 0 }; + enum ENUM_CLASS InOutType { TPCClusters = 1, + TPCSectorTracks = 2, + TPCMergedTracks = 4, + TPCCompressedClusters = 8, + TRDTracklets = 16, + TRDTracks = 32, + TPCRaw = 64 }; + +#ifdef GPUCA_NOCOMPAT_ALLOPENCL + static constexpr const char* const RECO_STEP_NAMES[] = {"TPC Transformation", "TPC Sector Tracking", "TPC Track Merging and Fit", "TPC Compression", "TRD Tracking", "ITS Tracking", "TPC dEdx Computation", "TPC Cluster Finding", "TPC Decompression", "Global Refit"}; + static constexpr const char* const GENERAL_STEP_NAMES[] = {"Prepare", "QA"}; + typedef bitfield<RecoStep, unsigned int> RecoStepField; + typedef bitfield<InOutType, unsigned int> InOutTypeField; + constexpr static int N_RECO_STEPS = sizeof(GPUDataTypes::RECO_STEP_NAMES) / sizeof(GPUDataTypes::RECO_STEP_NAMES[0]); + constexpr static int N_GENERAL_STEPS = sizeof(GPUDataTypes::GENERAL_STEP_NAMES) / sizeof(GPUDataTypes::GENERAL_STEP_NAMES[0]); +#endif +#ifdef GPUCA_NOCOMPAT + static constexpr unsigned int NSLICES = 36; +#endif + static DeviceType GetDeviceType(const char* type); +}; + +#ifdef GPUCA_NOCOMPAT_ALLOPENCL +struct GPURecoStepConfiguration { + GPUDataTypes::RecoStepField steps = 0; + GPUDataTypes::RecoStepField stepsGPUMask = GPUDataTypes::RecoStep::AllRecoSteps; + GPUDataTypes::InOutTypeField inputs = 0; + GPUDataTypes::InOutTypeField outputs = 0; +}; +#endif + +#ifdef GPUCA_NOCOMPAT + +template <class T> +struct DefaultPtr { + typedef T type; +}; +template <class T> +struct ConstPtr { + typedef const T type; +}; + +template <template <typename T> class S> +struct GPUCalibObjectsTemplate { + typename S<TPCFastTransform>::type* fastTransform = nullptr; + typename S<o2::base::MatLayerCylSet>::type* matLUT = nullptr; + typename S<o2::trd::GeometryFlat>::type* trdGeometry = nullptr; + typename S<TPCdEdxCalibrationSplines>::type* dEdxSplines = nullptr; + typename S<TPCPadGainCalib>::type* tpcPadGain = nullptr; + typename S<o2::base::PropagatorImpl<float>>::type* o2Propagator = nullptr; + typename S<o2::itsmft::TopologyDictionary>::type* itsPatternDict = nullptr; +}; +typedef GPUCalibObjectsTemplate<DefaultPtr> GPUCalibObjects; // NOTE: These 2 must have identical layout since they are memcopied +typedef GPUCalibObjectsTemplate<ConstPtr> GPUCalibObjectsConst; + +struct GPUTrackingInOutZS { + static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; + static constexpr unsigned int NENDPOINTS = 20; + struct GPUTrackingInOutZSSlice { + const void* const* zsPtr[NENDPOINTS]; + const unsigned int* nZSPtr[NENDPOINTS]; + unsigned int count[NENDPOINTS]; + }; + struct GPUTrackingInOutZSCounts { + unsigned int count[NSLICES][NENDPOINTS] = {}; + }; + struct GPUTrackingInOutZSMeta { + void* ptr[NSLICES][NENDPOINTS]; + unsigned int n[NSLICES][NENDPOINTS]; + }; + GPUTrackingInOutZSSlice slice[NSLICES]; +}; + +struct GPUTrackingInOutDigits { + static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; + const o2::tpc::Digit* tpcDigits[NSLICES] = {nullptr}; + size_t nTPCDigits[NSLICES] = {0}; + const GPUTPCDigitsMCInput* tpcDigitsMC = nullptr; +}; + +struct GPUTrackingInOutPointers { + GPUTrackingInOutPointers() = default; + GPUTrackingInOutPointers(const GPUTrackingInOutPointers&) = default; + + // TPC + static constexpr unsigned int NSLICES = GPUDataTypes::NSLICES; + const GPUTrackingInOutZS* tpcZS = nullptr; + const GPUTrackingInOutDigits* tpcPackedDigits = nullptr; + const GPUTPCClusterData* clusterData[NSLICES] = {nullptr}; + unsigned int nClusterData[NSLICES] = {0}; + const AliHLTTPCRawCluster* rawClusters[NSLICES] = {nullptr}; + unsigned int nRawClusters[NSLICES] = {0}; + const o2::tpc::ClusterNativeAccess* clustersNative = nullptr; + const GPUTPCTrack* sliceTracks[NSLICES] = {nullptr}; + unsigned int nSliceTracks[NSLICES] = {0}; + const GPUTPCHitId* sliceClusters[NSLICES] = {nullptr}; + unsigned int nSliceClusters[NSLICES] = {0}; + const AliHLTTPCClusterMCLabel* mcLabelsTPC = nullptr; + unsigned int nMCLabelsTPC = 0; + const GPUTPCMCInfo* mcInfosTPC = nullptr; + unsigned int nMCInfosTPC = 0; + const GPUTPCMCInfoCol* mcInfosTPCCol = nullptr; + unsigned int nMCInfosTPCCol = 0; + const GPUTPCGMMergedTrack* mergedTracks = nullptr; + unsigned int nMergedTracks = 0; + const GPUTPCGMMergedTrackHit* mergedTrackHits = nullptr; + const GPUTPCGMMergedTrackHitXYZ* mergedTrackHitsXYZ = nullptr; + unsigned int nMergedTrackHits = 0; + const unsigned int* mergedTrackHitAttachment = nullptr; + const unsigned char* mergedTrackHitStates = nullptr; + const o2::tpc::TrackTPC* outputTracksTPCO2 = nullptr; + unsigned int nOutputTracksTPCO2 = 0; + const unsigned int* outputClusRefsTPCO2 = nullptr; + unsigned int nOutputClusRefsTPCO2 = 0; + const o2::MCCompLabel* outputTracksTPCO2MC = nullptr; + const o2::tpc::CompressedClustersFlat* tpcCompressedClusters = nullptr; + + // TPC links + int* tpcLinkITS = nullptr; + int* tpcLinkTRD = nullptr; + int* tpcLinkTOF = nullptr; + const o2::track::TrackParCov** globalTracks = nullptr; + float* globalTrackTimes = nullptr; + unsigned int nGlobalTracks = 0; + + // TRD + const GPUTRDTrackletWord* trdTracklets = nullptr; + const GPUTRDSpacePoint* trdSpacePoints = nullptr; + unsigned int nTRDTracklets = 0; + const GPUTRDTrackGPU* trdTracks = nullptr; + unsigned int nTRDTracks = 0; + const float* trdTriggerTimes = nullptr; + const int* trdTrackletIdxFirst = nullptr; + const char* trdTrigRecMask = nullptr; + unsigned int nTRDTriggerRecords = 0; + const GPUTRDTrack* trdTracksITSTPCTRD = nullptr; + unsigned int nTRDTracksITSTPCTRD = 0; + const GPUTRDTrack* trdTracksTPCTRD = nullptr; + unsigned int nTRDTracksTPCTRD = 0; + + // TOF + const o2::tof::Cluster* tofClusters = nullptr; + unsigned int nTOFClusters = 0; + const o2::dataformats::MatchInfoTOF* itstpctofMatches = nullptr; + unsigned int nITSTPCTOFMatches = 0; + const o2::dataformats::MatchInfoTOF* itstpctrdtofMatches = nullptr; + unsigned int nITSTPCTRDTOFMatches = 0; + const o2::dataformats::MatchInfoTOF* tpctrdtofMatches = nullptr; + unsigned int nTPCTRDTOFMatches = 0; + const o2::dataformats::MatchInfoTOF* tpctofMatches = nullptr; + unsigned int nTPCTOFMatches = 0; + + // ITS + const o2::itsmft::CompClusterExt* itsCompClusters = nullptr; + const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* itsClusterMC = nullptr; + const o2::BaseCluster<float>* itsClusters = nullptr; + unsigned int nItsClusters = 0; + const o2::itsmft::ROFRecord* itsClusterROF = nullptr; + unsigned int nItsClusterROF = 0; + const o2::its::TrackITS* itsTracks = nullptr; + const o2::MCCompLabel* itsTrackMC = nullptr; + unsigned int nItsTracks = 0; + const int* itsTrackClusIdx = nullptr; + const o2::itsmft::ROFRecord* itsTrackROF = nullptr; + unsigned int nItsTrackROF = 0; + + // TPC-ITS + const o2::dataformats::TrackTPCITS* tracksTPCITSO2 = nullptr; + unsigned int nTracksTPCITSO2 = 0; + + // Common + const GPUSettingsTF* settingsTF = nullptr; +}; +#else +struct GPUTrackingInOutPointers { +}; +struct GPUCalibObjectsConst { +}; +#endif + +#undef ENUM_CLASS +#undef ENUM_UINT +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Base/GPUHostDataTypes.h b/GPU/GPUTracking/DataTypes/GPUHostDataTypes.h similarity index 79% rename from GPU/GPUTracking/Base/GPUHostDataTypes.h rename to GPU/GPUTracking/DataTypes/GPUHostDataTypes.h index d46826d283768..b84c05dad7d14 100644 --- a/GPU/GPUTracking/Base/GPUHostDataTypes.h +++ b/GPU/GPUTracking/DataTypes/GPUHostDataTypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.cxx b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.cxx new file mode 100644 index 0000000000000..436ae6c738dc0 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.cxx @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUMemorySizeScalers.cxx +/// \author David Rohr + +#include "GPUMemorySizeScalers.h" +#include "GPULogging.h" + +using namespace GPUCA_NAMESPACE::gpu; + +void GPUMemorySizeScalers::rescaleMaxMem(size_t newAvailableMemory) +{ + GPUMemorySizeScalers tmp; + double scaleFactor = (double)newAvailableMemory / tmp.availableMemory; + GPUInfo("Rescaling buffer size limits from %lu to %lu bytes of memory (factor %f)", tmp.availableMemory, newAvailableMemory, scaleFactor); + tpcMaxPeaks = (double)tmp.tpcMaxPeaks * scaleFactor; + tpcMaxClusters = (double)tmp.tpcMaxClusters * scaleFactor; + tpcMaxStartHits = (double)tmp.tpcMaxStartHits * scaleFactor; + tpcMaxRowStartHits = (double)tmp.tpcMaxRowStartHits * scaleFactor; + tpcMaxTracklets = (double)tmp.tpcMaxTracklets * scaleFactor; + tpcMaxTrackletHits = (double)tmp.tpcMaxTrackletHits * scaleFactor; + tpcMaxSectorTracks = (double)tmp.tpcMaxSectorTracks * scaleFactor; + tpcMaxSectorTrackHits = (double)tmp.tpcMaxSectorTrackHits * scaleFactor; + tpcMaxMergedTracks = (double)tmp.tpcMaxMergedTracks * scaleFactor; + tpcMaxMergedTrackHits = (double)tmp.tpcMaxMergedTrackHits * scaleFactor; + availableMemory = newAvailableMemory; +} diff --git a/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h new file mode 100644 index 0000000000000..e60ec412e0949 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h @@ -0,0 +1,85 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUMemorySizeScalers.h +/// \author David Rohr + +#ifndef O2_GPU_GPUMEMORYSIZESCALERS_H +#define O2_GPU_GPUMEMORYSIZESCALERS_H + +#include "GPUDef.h" + +namespace GPUCA_NAMESPACE::gpu +{ + +struct GPUMemorySizeScalers { + // Input sizes + size_t nTPCdigits = 0; + size_t nTPCHits = 0; + size_t nTRDTracklets = 0; + size_t nITSTracks = 0; + + // General scaling factor + double factor = 1; + double temporaryFactor = 1; + + // Offset + double offset = 1000.; + double hitOffset = 20000; + + // Scaling Factors + double tpcPeaksPerDigit = 0.2; + double tpcClustersPerPeak = 0.9; + double tpcStartHitsPerHit = 0.08; + double tpcTrackletsPerStartHit = 0.8; + double tpcTrackletHitsPerHit = 5; + double tpcSectorTracksPerHit = 0.02; + double tpcSectorTrackHitsPerHit = 0.8f; + double tpcMergedTrackPerSliceTrack = 0.9; + double tpcMergedTrackHitPerSliceHit = 1.1; + size_t tpcCompressedUnattachedHitsBase1024[3] = {900, 900, 500}; // No ratio, but integer fraction of 1024 for exact computation + + // Upper limits + size_t tpcMaxPeaks = 20000000; + size_t tpcMaxClusters = 320000000; + size_t tpcMaxSectorClusters = 30000000; + size_t tpcMaxStartHits = 650000; + size_t tpcMaxRowStartHits = 100000; + size_t tpcMaxTracklets = 520000; + size_t tpcMaxTrackletHits = 35000000; + size_t tpcMaxSectorTracks = 130000; + size_t tpcMaxSectorTrackHits = 5900000; + size_t tpcMaxMergedTracks = 3000000; + size_t tpcMaxMergedTrackHits = 200000000; + size_t availableMemory = 20500000000; + bool returnMaxVal = false; + + void rescaleMaxMem(size_t newAvailableMemory); + inline size_t getValue(size_t maxVal, size_t val) + { + return returnMaxVal ? maxVal : (std::min<size_t>(maxVal, offset + val) * factor * temporaryFactor); + } + + inline size_t NTPCPeaks(size_t tpcDigits, bool perSector = false) { return getValue(perSector ? tpcMaxPeaks : (GPUCA_NSLICES * tpcMaxPeaks), hitOffset + tpcDigits * tpcPeaksPerDigit); } + inline size_t NTPCClusters(size_t tpcDigits, bool perSector = false) { return getValue(perSector ? tpcMaxSectorClusters : tpcMaxClusters, tpcClustersPerPeak * NTPCPeaks(tpcDigits, perSector)); } + inline size_t NTPCStartHits(size_t tpcHits) { return getValue(tpcMaxStartHits, tpcHits * tpcStartHitsPerHit); } + inline size_t NTPCRowStartHits(size_t tpcHits) { return getValue(tpcMaxRowStartHits, NTPCStartHits(tpcHits) * 4 / GPUCA_ROW_COUNT); } + inline size_t NTPCTracklets(size_t tpcHits) { return getValue(tpcMaxTracklets, NTPCStartHits(tpcHits) * tpcTrackletsPerStartHit); } + inline size_t NTPCTrackletHits(size_t tpcHits) { return getValue(tpcMaxTrackletHits, hitOffset + tpcHits * tpcTrackletHitsPerHit); } + inline size_t NTPCSectorTracks(size_t tpcHits) { return getValue(tpcMaxSectorTracks, tpcHits * tpcSectorTracksPerHit); } + inline size_t NTPCSectorTrackHits(size_t tpcHits) { return getValue(tpcMaxSectorTrackHits, tpcHits * tpcSectorTrackHitsPerHit); } + inline size_t NTPCMergedTracks(size_t tpcSliceTracks) { return getValue(tpcMaxMergedTracks, tpcSliceTracks * tpcMergedTrackPerSliceTrack); } + inline size_t NTPCMergedTrackHits(size_t tpcSliceTrackHitss) { return getValue(tpcMaxMergedTrackHits, tpcSliceTrackHitss * tpcMergedTrackHitPerSliceHit); } +}; + +} // namespace GPUCA_NAMESPACE::gpu + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUO2DataTypes.h b/GPU/GPUTracking/DataTypes/GPUO2DataTypes.h new file mode 100644 index 0000000000000..3ffdd42b9cf81 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUO2DataTypes.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2DataTypes.h +/// \author David Rohr + +#ifndef O2_GPU_GPUO2DATATYPES_H +#define O2_GPU_GPUO2DATATYPES_H + +// Pull in several O2 headers with basic data types, or load a header with empty fake classes if O2 headers not available + +#if defined(GPUCA_HAVE_O2HEADERS) && (!defined(__OPENCL__) || defined(__OPENCLCPP__)) +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/Digit.h" +#include "DetectorsBase/MatLayerCylSet.h" +#include "DetectorsBase/Propagator.h" +#include "TRDBase/GeometryFlat.h" +#else +#include "GPUO2FakeClasses.h" +#endif + +#if !defined(__OPENCL__) || defined(__OPENCLCPP__) +#include "GPUdEdxInfo.h" +#endif + +#endif diff --git a/GPU/GPUTracking/Base/GPUO2FakeClasses.h b/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h similarity index 77% rename from GPU/GPUTracking/Base/GPUO2FakeClasses.h rename to GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h index 68c592366fd76..6f9a1e25cdee4 100644 --- a/GPU/GPUTracking/Base/GPUO2FakeClasses.h +++ b/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,18 +22,20 @@ namespace o2 { +class MCCompLabel +{ +}; namespace gpu { } // namespace gpu -} // namespace o2 - -namespace o2 -{ namespace tpc { class Digit { }; +class TrackTPC +{ +}; struct ClusterNative { GPUd() static float getTime() { return 0.f; } GPUd() static float getPad() { return 0.f; } @@ -73,6 +76,17 @@ class GeometryFlat { }; } // namespace trd +namespace dataformats +{ +template <class T> +class ConstMCTruthContainerView +{ +}; +template <class T> +class ConstMCTruthContainer +{ +}; +} // namespace dataformats } // namespace o2 namespace GPUCA_NAMESPACE @@ -102,8 +116,15 @@ class GPUTPCCompression class GPUTPCClusterFinder { }; +class GPUTrackingRefitProcessor +{ +}; struct GPUTPCCFChainContext { }; +struct GPUTPCDigitsMCInput { +}; +struct TPCPadGainCalib { +}; #ifndef __OPENCL__ struct GPUParam; class GPUTPCClusterStatistics diff --git a/GPU/GPUTracking/DataTypes/GPUOutputControl.h b/GPU/GPUTracking/DataTypes/GPUOutputControl.h new file mode 100644 index 0000000000000..9d7374f819ca3 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUOutputControl.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUOutputControl.h +/// \author David Rohr + +#ifndef GPUOUTPUTCONTROL_H +#define GPUOUTPUTCONTROL_H + +#include "GPUCommonDef.h" +#include <cstddef> +#include <functional> +#include <new> + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +// This defines an output region. ptrBase points to a memory buffer, which should have a proper alignment. +// Since DPL does not respect the alignment of data types, we do not impose anything specic but just use void*, but it should be >= 64 bytes ideally. +// The size defines the maximum possible buffer size when GPUReconstruction is called, and returns the number of filled bytes when it returns. +// If the buffer size is exceeded, size is set to 1 +// ptrCurrent must equal ptr if set (or nullptr), and can be incremented by GPUReconstruction step by step if multiple buffers are used. +// If ptr == nullptr, there is no region defined and GPUReconstruction will write its output to an internal buffer. +// If allocator is set, it is called as a callback to provide a ptr to the memory. + +struct GPUOutputControl { + GPUOutputControl() = default; + void set(void* p, size_t s) + { + reset(); + ptrBase = ptrCurrent = p; + size = s; + } + void set(const std::function<void*(size_t)>& a) + { + reset(); + allocator = a; + } + void reset() + { + new (this) GPUOutputControl; + } + bool useExternal() { return size || allocator; } + bool useInternal() { return !useExternal(); } + void checkCurrent() + { + if (ptrBase && ptrCurrent == nullptr) { + ptrCurrent = ptrBase; + } + } + + void* ptrBase = nullptr; // Base ptr to memory pool, occupied size is ptrCurrent - ptr + void* ptrCurrent = nullptr; // Pointer to free Output Space + size_t size = 0; // Max Size of Output Data if Pointer to output space is given + std::function<void*(size_t)> allocator = nullptr; // Allocator callback +}; + +struct GPUTrackingOutputs { + GPUOutputControl compressedClusters; + GPUOutputControl clustersNative; + GPUOutputControl tpcTracks; + GPUOutputControl clusterLabels; + GPUOutputControl sharedClusterMap; + GPUOutputControl tpcTracksO2; + GPUOutputControl tpcTracksO2ClusRefs; + GPUOutputControl tpcTracksO2Labels; + + static constexpr size_t count() { return sizeof(GPUTrackingOutputs) / sizeof(GPUOutputControl); } + GPUOutputControl* asArray() { return (GPUOutputControl*)this; } + size_t getIndex(const GPUOutputControl& v) { return &v - (const GPUOutputControl*)this; } + static int getIndex(GPUOutputControl GPUTrackingOutputs::*v) { return &(((GPUTrackingOutputs*)(nullptr))->*v) - (GPUOutputControl*)(nullptr); } +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUSettings.h b/GPU/GPUTracking/DataTypes/GPUSettings.h new file mode 100644 index 0000000000000..0579dd53674dc --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUSettings.h @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUSettings.h +/// \author David Rohr + +#ifndef GPUSETTINGS_H +#define GPUSETTINGS_H + +#include "GPUCommonDef.h" +#include "GPUDataTypes.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include <vector> +#include <string> +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +class GPUDisplayBackend; +class GPUReconstruction; + +class GPUSettings +{ + public: + enum CompressionModes { CompressionTruncate = 1, + CompressionDifferences = 2, + CompressionTrackModel = 4, + CompressionFull = 7 }; + enum CompressionSort { SortTime = 0, + SortPad = 1, + SortZTimePad = 2, + SortZPadTime = 3, + SortNoSort = 4 }; + enum CompressionRejection { RejectionNone = 0, + RejectionStrategyA = 1, + RejectionStrategyB = 2 }; + +#if !defined(__OPENCL__) || defined(__OPENCLCPP__) + static CONSTEXPR unsigned int TPC_MAX_TF_TIME_BIN = ((256 * 3564 + 2 * 8 - 2) / 8); +#endif +}; + +#ifdef GPUCA_NOCOMPAT +// Settings describing the global run parameters +struct GPUSettingsGRP { + // All new members must be sizeof(int) resp. sizeof(float) for alignment reasons! + float solenoidBz = -5.00668; // solenoid field strength + int constBz = 0; // for test-MC events with constant Bz + int homemadeEvents = 0; // Toy-MC events + int continuousMaxTimeBin = 0; // 0 for triggered events, -1 for default of 23ms + int needsClusterer = 0; // Set to true if the data requires the clusterizer +}; + +// Parameters of the current time frame +struct GPUSettingsTF { + int hasTfStartOrbit = 0; + int tfStartOrbit = 0; + int hasRunStartOrbit = 0; + int runStartOrbit = 0; + int hasSimStartOrbit = 0; + int simStartOrbit = 0; + int hasNHBFPerTF = 0; + int nHBFPerTF = 0; +}; + +// Settings defining the setup of the GPUReconstruction processing (basically selecting the device / class instance) +struct GPUSettingsDeviceBackend { + unsigned int deviceType = GPUDataTypes::DeviceType::CPU; // Device type, shall use GPUDataTypes::DEVICE_TYPE constants, e.g. CPU / CUDA + char forceDeviceType = true; // Fail if device initialization fails, otherwise falls back to CPU + GPUReconstruction* master = nullptr; // GPUReconstruction master object +}; +#endif + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#ifdef GPUCA_GPUCODE_DEVICE +#define QCONFIG_GPU +#endif +// See GPUSettingsList.h for a list of all available settings of GPU Reconstruction +#ifndef GPUCA_GPUCODE_GENRTC +#include "utils/qconfig.h" +#endif + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUTRDDef.h b/GPU/GPUTracking/DataTypes/GPUTRDDef.h new file mode 100644 index 0000000000000..75eb1f813780e --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDDef.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDDef.h +/// \author David Rohr + +#ifndef GPUTRDDEF_H +#define GPUTRDDEF_H + +#include "GPUCommonDef.h" + +#ifdef GPUCA_ALIROOT_LIB +#define TRD_TRACK_TYPE_ALIROOT +#else +#define TRD_TRACK_TYPE_O2 +#endif + +#ifdef GPUCA_ALIROOT_LIB +class AliExternalTrackParam; +class AliTrackerBase; +#else +namespace o2 +{ +namespace track +{ +template <typename> +class TrackParametrizationWithError; +} // namespace track +namespace base +{ +template <typename> +class PropagatorImpl; +} // namespace base +} // namespace o2 +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +#ifdef GPUCA_ALIROOT_LIB +typedef double My_Float; +#else +typedef float My_Float; +#endif + +#if defined(TRD_TRACK_TYPE_ALIROOT) +typedef AliExternalTrackParam TRDBaseTrack; +class GPUTPCGMTrackParam; +typedef GPUTPCGMTrackParam TRDBaseTrackGPU; +#elif defined(TRD_TRACK_TYPE_O2) +typedef o2::track::TrackParametrizationWithError<float> TRDBaseTrack; +class GPUTPCGMTrackParam; +typedef GPUTPCGMTrackParam TRDBaseTrackGPU; +#endif + +#ifdef GPUCA_ALIROOT_LIB +typedef AliTrackerBase TRDBasePropagator; +class GPUTPCGMPropagator; +typedef GPUTPCGMPropagator TRDBasePropagatorGPU; +#else +typedef o2::base::PropagatorImpl<float> TRDBasePropagator; +class GPUTPCGMPropagator; +typedef GPUTPCGMPropagator TRDBasePropagatorGPU; +#endif + +template <class T> +class trackInterface; +template <class T> +class propagatorInterface; +template <class T> +class GPUTRDTrack_t; +// clang-format off +typedef GPUTRDTrack_t<trackInterface<TRDBaseTrack> > GPUTRDTrack; // Need pre-c++11 compliant formatting +typedef GPUTRDTrack_t<trackInterface<TRDBaseTrackGPU> > GPUTRDTrackGPU; +// clang-foramt on +typedef propagatorInterface<TRDBasePropagator> GPUTRDPropagator; +typedef propagatorInterface<TRDBasePropagatorGPU> GPUTRDPropagatorGPU; + +template <class T, class P> +class GPUTRDTracker_t; +typedef GPUTRDTracker_t<GPUTRDTrack, GPUTRDPropagator> GPUTRDTracker; +typedef GPUTRDTracker_t<GPUTRDTrackGPU, GPUTRDPropagatorGPU> GPUTRDTrackerGPU; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif // GPUTRDDEF_H diff --git a/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h b/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h new file mode 100644 index 0000000000000..c271002d71651 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDInterfaceO2Track.h +/// \author Ole Schmidt + +#ifndef GPUTRDINTERFACEO2TRACK_H +#define GPUTRDINTERFACEO2TRACK_H + +// This is the interface for the GPUTRDTrack based on the O2 track type +#include "GPUCommonDef.h" +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +template <typename T> +class trackInterface; +class GPUTPCGMMergedTrack; +namespace gputpcgmmergertypes +{ +struct GPUTPCOuterParam; +} // namespace gputpcgmmergertypes +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/TrackLTIntegral.h" + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +template <> +class trackInterface<o2::track::TrackParCov> : public o2::track::TrackParCov +{ + public: + GPUdDefault() trackInterface<o2::track::TrackParCov>() = default; + trackInterface<o2::track::TrackParCov>(const o2::track::TrackParCov& param) = delete; + GPUd() trackInterface<o2::track::TrackParCov>(const o2::dataformats::TrackTPCITS& trkItsTpc) : o2::track::TrackParCov(trkItsTpc.getParamOut()) {} + GPUd() trackInterface<o2::track::TrackParCov>(const o2::tpc::TrackTPC& trkTpc) : o2::track::TrackParCov(trkTpc.getParamOut()) {} + + GPUd() void set(float x, float alpha, const float* param, const float* cov) + { + setX(x); + setAlpha(alpha); + for (int i = 0; i < 5; i++) { + setParam(param[i], i); + } + for (int i = 0; i < 15; i++) { + setCov(cov[i], i); + } + } + GPUd() trackInterface<o2::track::TrackParCov>(const GPUTPCGMMergedTrack& trk); + GPUd() trackInterface<o2::track::TrackParCov>(const gputpcgmmergertypes::GPUTPCOuterParam& param); + GPUd() void updateCovZ2(float addZerror) { updateCov(addZerror, o2::track::CovLabels::kSigZ2); } + GPUd() o2::track::TrackLTIntegral& getLTIntegralOut() { return mLTOut; } + GPUd() const o2::track::TrackLTIntegral& getLTIntegralOut() const { return mLTOut; } + GPUd() o2::track::TrackParCov& getOuterParam() { return mParamOut; } + GPUd() const o2::track::TrackParCov& getOuterParam() const { return mParamOut; } + + GPUdi() const float* getPar() const { return getParams(); } + + GPUdi() bool CheckNumericalQuality() const { return true; } + + typedef o2::track::TrackParCov baseClass; + + private: + o2::track::TrackLTIntegral mLTOut; + o2::track::TrackParCov mParamOut; + + ClassDefNV(trackInterface, 1); +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUTRDTrack.cxx b/GPU/GPUTracking/DataTypes/GPUTRDTrack.cxx new file mode 100644 index 0000000000000..27a6cfde3a138 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDTrack.cxx @@ -0,0 +1,201 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDTrack.cxx +/// \author Ole Schmidt, Sergey Gorbunov + +#include "GPUTRDTrack.h" +#if !defined(GPU_TRD_TRACK_O2) +#include "GPUTRDInterfaces.h" +#endif + +using namespace GPUCA_NAMESPACE::gpu; + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t() +{ + // default constructor + initialize(); +} + +template <typename T> +GPUd() void GPUTRDTrack_t<T>::initialize() +{ + // set all members to their default values (needed since in-class initialization not possible with AliRoot) + mChi2 = 0.f; + mRefGlobalTrackId = 0; + mCollisionId = -1; + mFlags = 0; + for (int i = 0; i < kNLayers; ++i) { + mAttachedTracklets[i] = -1; + } +} + +#ifdef GPUCA_ALIROOT_LIB +#include "AliHLTExternalTrackParam.h" +#include "GPUTRDTrackData.h" + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const AliHLTExternalTrackParam& t) : T(t) +{ + initialize(); +} + +template <typename T> +GPUd() void GPUTRDTrack_t<T>::ConvertTo(GPUTRDTrackDataRecord& t) const +{ + //------------------------------------------------------------------ + // convert to GPU structure + //------------------------------------------------------------------ + t.mAlpha = T::getAlpha(); + t.fX = T::getX(); + t.fY = T::getY(); + t.fZ = T::getZ(); + t.fq1Pt = T::getQ2Pt(); + t.mSinPhi = T::getSnp(); + t.fTgl = T::getTgl(); + for (int i = 0; i < 15; i++) { + t.fC[i] = T::getCov()[i]; + } + t.fTPCTrackID = getRefGlobalTrackIdRaw(); + for (int i = 0; i < kNLayers; i++) { + t.fAttachedTracklets[i] = getTrackletIndex(i); + } +} + +template <typename T> +GPUd() void GPUTRDTrack_t<T>::ConvertFrom(const GPUTRDTrackDataRecord& t) +{ + //------------------------------------------------------------------ + // convert from GPU structure + //------------------------------------------------------------------ + T::set(t.fX, t.mAlpha, &(t.fY), t.fC); + setRefGlobalTrackIdRaw(t.fTPCTrackID); + mChi2 = 0.f; + mFlags = 0; + mCollisionId = -1; + for (int iLayer = 0; iLayer < kNLayers; iLayer++) { + mAttachedTracklets[iLayer] = t.fAttachedTracklets[iLayer]; + } +} + +#endif + +#if defined(GPUCA_O2_LIB) && !defined(GPUCA_GPUCODE) +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "DataFormatsTPC/TrackTPC.h" + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const o2::dataformats::TrackTPCITS& t) : T(t) +{ + initialize(); +} + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const o2::tpc::TrackTPC& t) : T(t) +{ + initialize(); +} + +#endif + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const GPUTRDTrack_t<T>& t) + : T(t), mChi2(t.mChi2), mRefGlobalTrackId(t.mRefGlobalTrackId), mCollisionId(t.mCollisionId), mFlags(t.mFlags) +{ + // copy constructor + for (int i = 0; i < kNLayers; ++i) { + mAttachedTracklets[i] = t.mAttachedTracklets[i]; + } +} + +template <typename T> +GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const T& t) : T(t) +{ + // copy constructor from anything + initialize(); +} + +template <typename T> +GPUd() GPUTRDTrack_t<T>& GPUTRDTrack_t<T>::operator=(const GPUTRDTrack_t<T>& t) +{ + // assignment operator + if (&t == this) { + return *this; + } + *(T*)this = t; + mChi2 = t.mChi2; + mRefGlobalTrackId = t.mRefGlobalTrackId; + mCollisionId = t.mCollisionId; + mFlags = t.mFlags; + for (int i = 0; i < kNLayers; ++i) { + mAttachedTracklets[i] = t.mAttachedTracklets[i]; + } + return *this; +} + +template <typename T> +GPUd() int GPUTRDTrack_t<T>::getNlayersFindable() const +{ + // returns number of layers in which the track is in active area of TRD + int retVal = 0; + for (int iLy = 0; iLy < kNLayers; iLy++) { + if ((mFlags >> iLy) & 0x1) { + ++retVal; + } + } + return retVal; +} + +template <typename T> +GPUd() int GPUTRDTrack_t<T>::getNtracklets() const +{ + // returns number of tracklets attached to this track + int retVal = 0; + for (int iLy = 0; iLy < kNLayers; ++iLy) { + if (mAttachedTracklets[iLy] >= 0) { + ++retVal; + } + } + return retVal; +} + +template <typename T> +GPUd() int GPUTRDTrack_t<T>::getNmissingConsecLayers(int iLayer) const +{ + // returns number of consecutive layers in which the track was + // inside the deadzone up to (and including) the given layer + int retVal = 0; + while (!getIsFindable(iLayer)) { + ++retVal; + --iLayer; + if (iLayer < 0) { + break; + } + } + return retVal; +} + +#if !defined(GPUCA_GPUCODE) && !defined(GPU_TRD_TRACK_O2) +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +#ifdef GPUCA_ALIROOT_LIB // Instantiate AliRoot track version +template class GPUTRDTrack_t<trackInterface<AliExternalTrackParam>>; +#endif +#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_O2_LIB) // Instantiate O2 track version, for O2 this happens in GPUTRDTrackO2.cxx +template class GPUTRDTrack_t<trackInterface<o2::track::TrackParCov>>; +#endif +template class GPUTRDTrack_t<trackInterface<GPUTPCGMTrackParam>>; // Always instatiate GM track version +} // namespace gpu +} // namespace GPUCA_NAMESPACE +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUTRDTrack.h b/GPU/GPUTracking/DataTypes/GPUTRDTrack.h new file mode 100644 index 0000000000000..508176b1161a9 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDTrack.h @@ -0,0 +1,135 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDTrack.h +/// \author Ole Schmidt + +#ifndef GPUTRDTRACK_H +#define GPUTRDTRACK_H + +#include "GPUTRDDef.h" +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" + +struct GPUTRDTrackDataRecord; +class AliHLTExternalTrackParam; + +namespace o2 +{ +namespace tpc +{ +class TrackTPC; +} // namespace tpc +namespace dataformats +{ +class TrackTPCITS; +class GlobalTrackID; +} // namespace dataformats +} // namespace o2 + +//_____________________________________________________________________________ +#if (defined(__CINT__) || defined(__ROOTCINT__)) && !defined(__CLING__) +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +template <typename T> +class GPUTRDTrack_t; +} // namespace gpu +} // namespace GPUCA_NAMESPACE +#else +#if (!defined(GPUCA_STANDALONE) && !defined(GPUCA_ALIROOT_LIB)) || defined(GPUCA_HAVE_O2HEADERS) +#include "GPUTRDInterfaceO2Track.h" +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +template <typename T> +class GPUTRDTrack_t : public T +{ + public: + enum EGPUTRDTrack { + kNLayers = 6, + kAmbiguousFlag = 6, + kStopFlag = 7 + }; + + GPUd() GPUTRDTrack_t(); + GPUTRDTrack_t(const typename T::baseClass& t) = delete; + GPUd() GPUTRDTrack_t(const GPUTRDTrack_t& t); + GPUd() GPUTRDTrack_t(const AliHLTExternalTrackParam& t); +#ifndef GPUCA_GPUCODE + GPUd() GPUTRDTrack_t(const o2::dataformats::TrackTPCITS& t); + GPUd() GPUTRDTrack_t(const o2::tpc::TrackTPC& t); +#endif + GPUd() GPUTRDTrack_t(const T& t); + GPUd() GPUTRDTrack_t& operator=(const GPUTRDTrack_t& t); + + // attach a tracklet to this track; this overwrites the mFlags flag to true for this layer + GPUd() void addTracklet(int iLayer, int idx) { mAttachedTracklets[iLayer] = idx; } + + // getters + GPUd() int getNlayersFindable() const; + GPUd() int getTrackletIndex(int iLayer) const { return mAttachedTracklets[iLayer]; } + GPUd() unsigned int getRefGlobalTrackIdRaw() const { return mRefGlobalTrackId; } + // This method is only defined in TrackTRD.h and is intended to be used only with that TRD track type + GPUd() o2::dataformats::GlobalTrackID getRefGlobalTrackId() const; + GPUd() short getCollisionId() const { return mCollisionId; } + GPUd() int getNtracklets() const; + GPUd() float getChi2() const { return mChi2; } + GPUd() float getReducedChi2() const { return getNlayersFindable() == 0 ? mChi2 : mChi2 / getNlayersFindable(); } + GPUd() bool getIsStopped() const { return (mFlags >> kStopFlag) & 0x1; } + GPUd() bool getIsAmbiguous() const { return (mFlags >> kAmbiguousFlag) & 0x1; } + GPUd() bool getIsFindable(int iLayer) const { return (mFlags >> iLayer) & 0x1; } + GPUd() int getNmissingConsecLayers(int iLayer) const; + GPUd() int getIsPenaltyAdded(int iLayer) const { return getIsFindable(iLayer) && getTrackletIndex(iLayer) < 0; } + // for AliRoot compatibility. To be removed once HLT/global/AliHLTGlobalEsdConverterComponent.cxx does not require them anymore + GPUd() int GetTPCtrackId() const { return mRefGlobalTrackId; } + GPUd() bool GetIsStopped() const { return getIsStopped(); } + GPUd() int GetNtracklets() const { return getNtracklets(); } + + // setters + GPUd() void setRefGlobalTrackIdRaw(unsigned int id) { mRefGlobalTrackId = id; } + // This method is only defined in TrackTRD.h and is intended to be used only with that TRD track type + GPUd() void setRefGlobalTrackId(o2::dataformats::GlobalTrackID id); + GPUd() void setCollisionId(short id) { mCollisionId = id; } + GPUd() void setIsFindable(int iLayer) { mFlags |= (1U << iLayer); } + GPUd() void setIsStopped() { mFlags |= (1U << kStopFlag); } + GPUd() void setIsAmbiguous() { mFlags |= (1U << kAmbiguousFlag); } + GPUd() void setChi2(float chi2) { mChi2 = chi2; } + + // conversion to / from HLT track structure (only for AliRoot) + GPUd() void ConvertTo(GPUTRDTrackDataRecord& t) const; + GPUd() void ConvertFrom(const GPUTRDTrackDataRecord& t); + + protected: + float mChi2; // total chi2. + unsigned int mRefGlobalTrackId; // raw GlobalTrackID of the seeding track (either ITS-TPC or TPC) + int mAttachedTracklets[kNLayers]; // indices of the tracklets attached to this track; -1 means no tracklet in that layer + short mCollisionId; // the collision ID of the tracklets attached to this track; is used to retrieve the BC information for this track after the tracking is done + unsigned char mFlags; // bits 0 to 5 indicate whether track is findable in layer 0 to 5, bit 6 indicates an ambiguous track and bit 7 flags if the track is stopped in the TRD + + private: + GPUd() void initialize(); +#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_ALIROOT_LIB) + ClassDefNV(GPUTRDTrack_t, 2); +#endif +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif // !((defined(__CINT__) || defined(__ROOTCINT__)) && !defined(__CLING__)) + +#endif // GPUTRDTRACK_H diff --git a/GPU/GPUTracking/DataTypes/GPUTRDTrackO2.cxx b/GPU/GPUTracking/DataTypes/GPUTRDTrackO2.cxx new file mode 100644 index 0000000000000..6141a8bd9d958 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDTrackO2.cxx @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDTrackO2.cxx +/// \author David Rohr + +#define GPU_TRD_TRACK_O2 +#include "GPUTRDTrack.cxx" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2::gpu +{ +template class GPUTRDTrack_t<trackInterface<o2::track::TrackParCov>>; +} // namespace o2::gpu diff --git a/GPU/GPUTracking/DataTypes/GPUdEdxInfo.h b/GPU/GPUTracking/DataTypes/GPUdEdxInfo.h new file mode 100644 index 0000000000000..c5635b7c5d488 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUdEdxInfo.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUdEdxInfo.h +/// \author David Rohr + +#ifndef GPUDEDXINFO_H +#define GPUDEDXINFO_H + +#ifdef GPUCA_HAVE_O2HEADERS +#include "DataFormatsTPC/dEdxInfo.h" +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +#ifdef GPUCA_HAVE_O2HEADERS +using GPUdEdxInfo = o2::tpc::dEdxInfo; +#else +struct GPUdEdxInfo { +}; +#endif +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/DataTypes/TPCPadGainCalib.cxx b/GPU/GPUTracking/DataTypes/TPCPadGainCalib.cxx new file mode 100644 index 0000000000000..d3eff4254f3c0 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/TPCPadGainCalib.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCPadGainCalib.cxx +/// \author Felix Weiglhofer + +#include "TPCPadGainCalib.h" + +#include "GPUTPCGeometry.h" +#include "DataFormatsTPC/Constants.h" +#include "TPCBase/CalDet.h" + +using namespace GPUCA_NAMESPACE::gpu; + +TPCPadGainCalib::TPCPadGainCalib() +{ + GPUTPCGeometry geo{}; + int offset = 0; + for (int r = 0; r < GPUCA_ROW_COUNT; r++) { + mPadOffsetPerRow[r] = offset; + offset += geo.NPads(r); + } +} + +TPCPadGainCalib::TPCPadGainCalib(const o2::tpc::CalDet<float>& gainMap) : TPCPadGainCalib() +{ + for (int sector = 0; sector < o2::tpc::constants::MAXSECTOR; sector++) { + for (int p = 0; p < TPC_PADS_IN_SECTOR; p++) { + const float gainVal = gainMap.getValue(sector, p); + mGainCorrection[sector].set(p, (gainVal > 1.e-5f) ? 1.f / gainVal : 1.f); + } + } +} diff --git a/GPU/GPUTracking/DataTypes/TPCPadGainCalib.h b/GPU/GPUTracking/DataTypes/TPCPadGainCalib.h new file mode 100644 index 0000000000000..5912e042c6c9d --- /dev/null +++ b/GPU/GPUTracking/DataTypes/TPCPadGainCalib.h @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCPadGainCalib.h +/// \author Felix Weiglhofer + +#ifndef O2_GPU_TPC_PAD_GAIN_CALIB_H +#define O2_GPU_TPC_PAD_GAIN_CALIB_H + +#include "clusterFinderDefs.h" +#include "GPUCommonMath.h" + +namespace o2::tpc +{ +template <class T> +class CalDet; +} // namespace o2::tpc + +namespace GPUCA_NAMESPACE::gpu +{ + +template <typename T> +struct TPCPadGainCorrectionStepNum { +}; + +template <> +struct TPCPadGainCorrectionStepNum<unsigned char> { + static constexpr int value = 254; +}; + +template <> +struct TPCPadGainCorrectionStepNum<unsigned short> { + static constexpr int value = 65534; +}; + +struct TPCPadGainCalib { + public: +#ifndef GPUCA_GPUCODE + TPCPadGainCalib(); + TPCPadGainCalib(const o2::tpc::CalDet<float>&); +#endif + + // Deal with pad gain correction from here on + GPUdi() void setGainCorrection(int sector, tpccf::Row row, tpccf::Pad pad, float c) + { + mGainCorrection[sector].set(globalPad(row, pad), c); + } + + GPUdi() float getGainCorrection(int sector, tpccf::Row row, tpccf::Pad pad) const + { + return mGainCorrection[sector].get(globalPad(row, pad)); + } + + GPUdi() unsigned short globalPad(tpccf::Row row, tpccf::Pad pad) const + { + return mPadOffsetPerRow[row] + pad; + } + + private: + template <typename T = unsigned short> + class SectorPadGainCorrection + { + + public: + constexpr static float MinCorrectionFactor = 0.f; + constexpr static float MaxCorrectionFactor = 2.f; + constexpr static int NumOfSteps = TPCPadGainCorrectionStepNum<T>::value; + + GPUdi() SectorPadGainCorrection() + { + reset(); + } + + GPUdi() void set(unsigned short globalPad, float c) + { + at(globalPad) = pack(c); + } + + GPUdi() float get(unsigned short globalPad) const + { + return unpack(at(globalPad)); + } + + GPUd() void reset() + { + for (unsigned short p = 0; p < TPC_PADS_IN_SECTOR; p++) { + set(p, 1.0f); + } + } + + private: + GPUd() static T pack(float f) + { + f = CAMath::Clamp(f, MinCorrectionFactor, MaxCorrectionFactor); + f -= MinCorrectionFactor; + f *= float(NumOfSteps); + f /= (MaxCorrectionFactor - MinCorrectionFactor); + return CAMath::Nint(f); + } + + GPUd() static float unpack(T c) + { + return MinCorrectionFactor + (MaxCorrectionFactor - MinCorrectionFactor) * float(c) / float(NumOfSteps); + } + + T mGainCorrection[TPC_PADS_IN_SECTOR]; + + GPUdi() T& at(unsigned short globalPad) + { + return mGainCorrection[globalPad]; + } + + GPUdi() const T& at(unsigned short globalPad) const + { + return mGainCorrection[globalPad]; + } + }; + + unsigned short mPadOffsetPerRow[GPUCA_ROW_COUNT]; + SectorPadGainCorrection<unsigned short> mGainCorrection[GPUCA_NSLICES]; +}; + +} // namespace GPUCA_NAMESPACE::gpu + +#endif diff --git a/GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.cxx b/GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.cxx similarity index 95% rename from GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.cxx rename to GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.cxx index 7cf0d7b3608a7..091f7e0efaf23 100644 --- a/GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.cxx +++ b/GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.h b/GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.h similarity index 95% rename from GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.h rename to GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.h index cffd3f7cadccf..f378b6d2dd347 100644 --- a/GPU/GPUTracking/dEdx/TPCdEdxCalibrationSplines.h +++ b/GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Debug/GPUROOTDump.h b/GPU/GPUTracking/Debug/GPUROOTDump.h new file mode 100644 index 0000000000000..d7f765788578a --- /dev/null +++ b/GPU/GPUTracking/Debug/GPUROOTDump.h @@ -0,0 +1,133 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUROOTDump.h +/// \author David Rohr + +#ifndef GPUROOTDUMP_H +#define GPUROOTDUMP_H + +#include "GPUCommonDef.h" +#if !defined(GPUCA_NO_ROOT) && !defined(GPUCA_GPUCODE) +#include "GPUROOTDumpCore.h" +#include <TTree.h> +#include <TNtuple.h> +#include <memory> +#include <stdexcept> +#else +class TNtuple; +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +#if !defined(GPUCA_NO_ROOT) && !defined(GPUCA_GPUCODE) +namespace +{ +template <class S> +struct internal_Branch { + template <typename... Args> + static void Branch(S* p, Args... args) + { + } +}; +template <> +struct internal_Branch<TTree> { + template <typename... Args> + static void Branch(TTree* p, Args... args) + { + p->Branch(args...); + } +}; +} // namespace + +template <class T> +class GPUROOTDump : public GPUROOTDumpBase +{ + public: + static GPUROOTDump<T>& get(const char* name) // return always the same instance, identified by template + { + static GPUROOTDump<T> instance(name); + return instance; + } + static GPUROOTDump<T> getNew(const char* name) // return new individual instance + { + return GPUROOTDump<T>(name); + } + + void write() override { mTree->Write(); } + + void Fill(const T& o) + { + mObj = o; + mTree->Fill(); + } + + private: + GPUROOTDump(const char* name) + { + mTree = new TTree(name, name); + mTree->Branch(name, &mObj); + } + TTree* mTree = nullptr; + T mObj; +}; + +template <> +class GPUROOTDump<TNtuple> : public GPUROOTDumpBase +{ + public: + static GPUROOTDump<TNtuple>& get(const char* name, const char* options) + { + static GPUROOTDump<TNtuple> instance(name, options); + return instance; + } + static GPUROOTDump<TNtuple> getNew(const char* name, const char* options) + { + return GPUROOTDump<TNtuple>(name, options); + } + + void write() override { mNTuple->Write(); } + + template <typename... Args> + void Fill(Args... args) + { + mNTuple->Fill(args...); + } + + private: + GPUROOTDump(const char* name, const char* options) + { + mNTuple = new TNtuple(name, name, options); + } + TNtuple* mNTuple; +}; +#else +template <class T> +class GPUROOTDump +{ + public: + template <typename... Args> + GPUd() void Fill(Args... args) const + { + } + template <typename... Args> + GPUd() static GPUROOTDump<T>& get(Args... args) + { + return *(GPUROOTDump<T>*)(size_t)(1024); // Will never be used, return just some reference + } +}; +#endif +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Debug/GPUROOTDumpCore.cxx b/GPU/GPUTracking/Debug/GPUROOTDumpCore.cxx new file mode 100644 index 0000000000000..1f2117efbdad5 --- /dev/null +++ b/GPU/GPUTracking/Debug/GPUROOTDumpCore.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUROOTDumpCore.cxx +/// \author David Rohr + +#include "GPUROOTDumpCore.h" + +#if (!defined(GPUCA_STANDALONE) || defined(GPUCA_BUILD_QA)) && !defined(GPUCA_GPUCODE) +#include <atomic> +#include <memory> +#include <TFile.h> + +using namespace GPUCA_NAMESPACE::gpu; + +std::weak_ptr<GPUROOTDumpCore> GPUROOTDumpCore::sInstance; + +GPUROOTDumpCore::GPUROOTDumpCore(GPUROOTDumpCore::GPUROOTDumpCorePrivate) +{ +} + +GPUROOTDumpCore::~GPUROOTDumpCore() +{ + if (mFile) { + for (unsigned int i = 0; i < mBranches.size(); i++) { + mBranches[i]->write(); + } + mFile->Close(); + } +} + +std::shared_ptr<GPUROOTDumpCore> GPUROOTDumpCore::getAndCreate() +{ + static std::atomic_flag lock = ATOMIC_FLAG_INIT; + while (lock.test_and_set(std::memory_order_acquire)) { + } + std::shared_ptr<GPUROOTDumpCore> retVal = sInstance.lock(); + if (!retVal) { + retVal = std::make_shared<GPUROOTDumpCore>(GPUROOTDumpCorePrivate()); + sInstance = retVal; + } + lock.clear(std::memory_order_release); + return retVal; +} + +GPUROOTDumpBase::GPUROOTDumpBase() +{ + std::shared_ptr<GPUROOTDumpCore> p = GPUROOTDumpCore::get().lock(); + if (!p) { + throw std::runtime_error("No instance of GPUROOTDumpCore exists"); + } + p->mBranches.emplace_back(this); + if (!p->mFile) { + p->mFile.reset(new TFile("gpudebug.root", "recreate")); + } + p->mFile->cd(); +} + +#endif diff --git a/GPU/GPUTracking/Debug/GPUROOTDumpCore.h b/GPU/GPUTracking/Debug/GPUROOTDumpCore.h new file mode 100644 index 0000000000000..73a76ddba1706 --- /dev/null +++ b/GPU/GPUTracking/Debug/GPUROOTDumpCore.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUROOTDumpCore.h +/// \author David Rohr + +#ifndef GPUROOTDUMPCORE_H +#define GPUROOTDUMPCORE_H + +#include "GPUCommonDef.h" +#include <memory> +#include <vector> + +class TFile; + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +class GPUROOTDumpCore; + +class GPUROOTDumpBase +{ + public: + virtual void write() = 0; + + protected: + GPUROOTDumpBase(); + std::weak_ptr<GPUROOTDumpCore> mCore; +}; + +class GPUROOTDumpCore +{ +#if !defined(GPUCA_NO_ROOT) && !defined(GPUCA_GPUCODE) + friend class GPUReconstruction; + friend class GPUROOTDumpBase; + + private: + struct GPUROOTDumpCorePrivate { + }; + + public: + GPUROOTDumpCore(const GPUROOTDumpCore&) = delete; + GPUROOTDumpCore operator=(const GPUROOTDumpCore&) = delete; + GPUROOTDumpCore(GPUROOTDumpCorePrivate); // Cannot be declared private directly since used with new + ~GPUROOTDumpCore(); + + private: + static std::shared_ptr<GPUROOTDumpCore> getAndCreate(); + static std::weak_ptr<GPUROOTDumpCore> get() { return sInstance; } + static std::weak_ptr<GPUROOTDumpCore> sInstance; + std::unique_ptr<TFile> mFile; + std::vector<GPUROOTDumpBase*> mBranches; +#endif +}; +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/Common/GPUDef.h b/GPU/GPUTracking/Definitions/GPUDef.h similarity index 89% rename from GPU/Common/GPUDef.h rename to GPU/GPUTracking/Definitions/GPUDef.h index 164378f1c23d8..c7d9cb00d367c 100644 --- a/GPU/Common/GPUDef.h +++ b/GPU/GPUTracking/Definitions/GPUDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/Common/GPUDefConstantsAndSettings.h b/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h similarity index 84% rename from GPU/Common/GPUDefConstantsAndSettings.h rename to GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h index e298cb51e8631..0d8ffcf2f19a1 100644 --- a/GPU/Common/GPUDefConstantsAndSettings.h +++ b/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -58,12 +59,15 @@ #define GPUCA_TPC_COMP_CHUNK_SIZE 1024 // Chunk size of sorted unattached TPC cluster in compression -#if defined(HAVE_O2HEADERS) && (!defined(__OPENCL__) || defined(__OPENCLCPP__)) && !(defined(ROOT_VERSION_CODE) && ROOT_VERSION_CODE < 393216) - //Use definitions from the O2 headers if available for nicer code and type safety - #include "DataFormatsTPC/Constants.h" - #define GPUCA_NSLICES o2::tpc::constants::MAXSECTOR - #define GPUCA_ROW_COUNT o2::tpc::constants::MAXGLOBALPADROW -#else +#if defined(GPUCA_HAVE_O2HEADERS) && (!defined(__OPENCL__) || defined(__OPENCLCPP__)) && !(defined(ROOT_VERSION_CODE) && ROOT_VERSION_CODE < 393216) && defined(__has_include) + #if __has_include("DataFormatsTPC/Constants.h") + //Use definitions from the O2 headers if available for nicer code and type safety + #include "DataFormatsTPC/Constants.h" + #define GPUCA_NSLICES o2::tpc::constants::MAXSECTOR + #define GPUCA_ROW_COUNT o2::tpc::constants::MAXGLOBALPADROW + #endif +#endif +#ifndef GPUCA_NSLICES //Define it manually, if O2 headers not available, ROOT5, and OpenCL 1.2, which do not know C++11. #define GPUCA_NSLICES 36 #ifdef GPUCA_TPC_GEOMETRY_O2 diff --git a/GPU/Common/GPUDefGPUParameters.h b/GPU/GPUTracking/Definitions/GPUDefGPUParameters.h similarity index 84% rename from GPU/Common/GPUDefGPUParameters.h rename to GPU/GPUTracking/Definitions/GPUDefGPUParameters.h index 265932ec114aa..9902be1d7cc44 100644 --- a/GPU/Common/GPUDefGPUParameters.h +++ b/GPU/GPUTracking/Definitions/GPUDefGPUParameters.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,7 +35,7 @@ #define GPUCA_LB_GPUTPCCreateSliceData 128 #define GPUCA_LB_GPUTPCStartHitsSorter 1024, 2 #define GPUCA_LB_GPUTPCStartHitsFinder 1024 - #define GPUCA_LB_GPUTPCTrackletConstructor 512, 1 + #define GPUCA_LB_GPUTPCTrackletConstructor 256, 2 #define GPUCA_LB_GPUTPCTrackletSelector 256, 8 #define GPUCA_LB_GPUTPCNeighboursFinder 1024, 1 #define GPUCA_LB_GPUTPCNeighboursCleaner 896 @@ -42,7 +43,7 @@ #define GPUCA_LB_GPUTPCCFDecodeZS 64, 4 #define GPUCA_LB_GPUTPCCFGather 1024, 1 #define GPUCA_LB_GPUTPCGMMergerTrackFit 64, 1 - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 256, 1, 200 + #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 256, 4, 200 #define GPUCA_LB_GPUTPCGMMergerSliceRefit 256 #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 @@ -59,8 +60,6 @@ #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 #define GPUCA_LB_GPUTPCGMMergerLinkGlobalTracks 256 #define GPUCA_LB_GPUTPCGMMergerCollect 512 - #define GPUCA_LB_GPUTPCGMMergerSortTracks 256 - #define GPUCA_LB_GPUTPCGMMergerSortTracksQPt 256 #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step0 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step1 256 @@ -68,10 +67,17 @@ #define GPUCA_LB_GPUTPCGMMergerFinalize_0 256 #define GPUCA_LB_GPUTPCGMMergerFinalize_1 256 #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512 + #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 192, 2 + #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 + #define GPUCA_LB_GPUTPCCFPeakFinder 512 + #define GPUCA_LB_GPUTPCCFNoiseSuppression 512 + #define GPUCA_LB_GPUTPCCFDeconvolution 512 + #define GPUCA_LB_GPUTPCCFClusterizer 512 #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_LB_CLUSTER_FINDER 512 #define GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP 5 #define GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE 20 #define GPUCA_CONSTRUCTOR_IN_PIPELINE 1 @@ -81,7 +87,10 @@ #define GPUCA_MERGER_SPLIT_LOOP_INTERPOLATION 1 #define GPUCA_TRACKLET_SELECTOR_SLICE_COUNT 1 #define GPUCA_NO_ATOMIC_PRECHECK 1 - #define GPUCA_COMP_GATHER_KERNEL 3 + #define GPUCA_DEDX_STORAGE_TYPE unsigned short + #define GPUCA_MERGER_INTERPOLATION_ERROR_TYPE half + #define GPUCA_COMP_GATHER_KERNEL 4 + #define GPUCA_COMP_GATHER_MODE 3 #elif defined(GPUCA_GPUTYPE_AMPERE) #define GPUCA_WARP_SIZE 32 #define GPUCA_THREAD_COUNT 512 @@ -113,8 +122,6 @@ #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 #define GPUCA_LB_GPUTPCGMMergerLinkGlobalTracks 256 #define GPUCA_LB_GPUTPCGMMergerCollect 256, 2 - #define GPUCA_LB_GPUTPCGMMergerSortTracks 256 - #define GPUCA_LB_GPUTPCGMMergerSortTracksQPt 256 #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step0 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step1 256 @@ -124,8 +131,15 @@ #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 64, 2 #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 3 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64,8 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 448 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 448 + #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 448 + #define GPUCA_LB_GPUTPCCFPeakFinder 128 + #define GPUCA_LB_GPUTPCCFNoiseSuppression 448 + #define GPUCA_LB_GPUTPCCFDeconvolution 384 + #define GPUCA_LB_GPUTPCCFClusterizer 448 #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_LB_CLUSTER_FINDER 448 #define GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP 4 #define GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE 20 #define GPUCA_CONSTRUCTOR_IN_PIPELINE 1 @@ -170,8 +184,6 @@ #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 #define GPUCA_LB_GPUTPCGMMergerLinkGlobalTracks 256 #define GPUCA_LB_GPUTPCGMMergerCollect 128, 2 - #define GPUCA_LB_GPUTPCGMMergerSortTracks 256 - #define GPUCA_LB_GPUTPCGMMergerSortTracksQPt 256 #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step0 256 #define GPUCA_LB_GPUTPCGMMergerPrepareClusters_step1 256 @@ -182,7 +194,6 @@ #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 128 #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_LB_CLUSTER_FINDER 512 #define GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP 4 #define GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE 20 #define GPUCA_CONSTRUCTOR_IN_PIPELINE 1 @@ -192,7 +203,8 @@ #define GPUCA_MERGER_SPLIT_LOOP_INTERPOLATION 1 #define GPUCA_TRACKLET_SELECTOR_SLICE_COUNT 1 #define GPUCA_NO_ATOMIC_PRECHECK 1 - #define GPUCA_COMP_GATHER_KERNEL 0 + #define GPUCA_COMP_GATHER_KERNEL 4 + #define GPUCA_COMP_GATHER_MODE 3 #define GPUCA_DEDX_STORAGE_TYPE unsigned short #define GPUCA_MERGER_INTERPOLATION_ERROR_TYPE half // #define GPUCA_USE_TEXTURES @@ -246,9 +258,6 @@ #ifndef GPUCA_LB_COMPRESSION_GATHER #define GPUCA_LB_COMPRESSION_GATHER 1024 #endif - #ifndef GPUCA_LB_CLUSTER_FINDER - #define GPUCA_LB_CLUSTER_FINDER 128 - #endif #ifndef GPUCA_LB_GPUTPCGMMergerTrackFit #define GPUCA_LB_GPUTPCGMMergerTrackFit 256 #endif @@ -303,12 +312,6 @@ #ifndef GPUCA_LB_GPUTPCGMMergerCollect #define GPUCA_LB_GPUTPCGMMergerCollect 256 #endif - #ifndef GPUCA_LB_GPUTPCGMMergerSortTracks - #define GPUCA_LB_GPUTPCGMMergerSortTracks 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerSortTracksQPt - #define GPUCA_LB_GPUTPCGMMergerSortTracksQPt 256 - #endif #ifndef GPUCA_LB_GPUTPCGMMergerSortTracksPrepare #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 #endif @@ -330,8 +333,20 @@ #ifndef GPUCA_LB_GPUTPCGMMergerFinalize_step2 #define GPUCA_LB_GPUTPCGMMergerFinalize_step2 256 #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers - #define GPUCA_LB_GPUTPCGMMergerMergeLoopers 256 + #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step0 + #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step0 256 + #endif + #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step1 + #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step1 256 + #endif + #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step2 + #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step2 256 + #endif + #ifndef GPUCA_LB_GPUTPCGMO2Output_prepare + #define GPUCA_LB_GPUTPCGMO2Output_prepare 256 + #endif + #ifndef GPUCA_LB_GPUTPCGMO2Output_output + #define GPUCA_LB_GPUTPCGMO2Output_output 256 #endif #ifndef GPUCA_LB_GPUITSFitterKernel #define GPUCA_LB_GPUITSFitterKernel 256 @@ -342,6 +357,36 @@ #ifndef GPUCA_LB_GPUTPCStartHitsSorter #define GPUCA_LB_GPUTPCStartHitsSorter 256 #endif + #ifndef GPUCA_LB_GPUTPCCFCheckPadBaseline + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64 + #endif + #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits + #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart + #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFPeakFinder + #define GPUCA_LB_GPUTPCCFPeakFinder 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFNoiseSuppression + #define GPUCA_LB_GPUTPCCFNoiseSuppression 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFDeconvolution + #define GPUCA_LB_GPUTPCCFDeconvolution 512 + #endif + #ifndef GPUCA_LB_GPUTPCCFClusterizer + #define GPUCA_LB_GPUTPCCFClusterizer 512 + #endif + #ifndef GPUCA_LB_GPUTrackingRefitKernel_mode0asGPU + #define GPUCA_LB_GPUTrackingRefitKernel_mode0asGPU 256 + #endif + #ifndef GPUCA_LB_GPUTrackingRefitKernel_mode1asTrackParCov + #define GPUCA_LB_GPUTrackingRefitKernel_mode1asTrackParCov 256 + #endif #define GPUCA_GET_THREAD_COUNT(...) GPUCA_M_FIRST(__VA_ARGS__) #else // The following defaults are needed to compile the host code @@ -352,14 +397,8 @@ #define GPUCA_THREAD_COUNT_SCAN 512 // TODO: WARNING!!! Must not be GPUTYPE-dependent right now! // TODO: Fix! -#define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFPeakFinder GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFNoiseSuppression_noiseSuppression GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFNoiseSuppression_updatePeaks GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFDeconvolution GPUCA_LB_CLUSTER_FINDER -#define GPUCA_LB_GPUTPCCFClusterizer GPUCA_LB_CLUSTER_FINDER +#define GPUCA_LB_GPUTPCCFNoiseSuppression_noiseSuppression GPUCA_LB_GPUTPCCFNoiseSuppression +#define GPUCA_LB_GPUTPCCFNoiseSuppression_updatePeaks GPUCA_LB_GPUTPCCFNoiseSuppression #define GPUCA_LB_GPUTPCCFStreamCompaction_scanStart GPUCA_THREAD_COUNT_SCAN #define GPUCA_LB_GPUTPCCFStreamCompaction_scanUp GPUCA_THREAD_COUNT_SCAN #define GPUCA_LB_GPUTPCCFStreamCompaction_scanTop GPUCA_THREAD_COUNT_SCAN @@ -373,6 +412,10 @@ #define GPUCA_LB_GPUTPCCompressionGatherKernels_buffered128 GPUCA_LB_COMPRESSION_GATHER #define GPUCA_LB_GPUTPCCompressionGatherKernels_multiBlock GPUCA_LB_COMPRESSION_GATHER +#if defined(__CUDACC__) || defined(__HIPCC__) +#define GPUCA_SPECIALIZE_THRUST_SORTS +#endif + #ifndef GPUCA_NEIGHBORSFINDER_REGS #define GPUCA_NEIGHBORSFINDER_REGS NONE, 0 #endif diff --git a/GPU/Common/GPUDefMacros.h b/GPU/GPUTracking/Definitions/GPUDefMacros.h similarity index 85% rename from GPU/Common/GPUDefMacros.h rename to GPU/GPUTracking/Definitions/GPUDefMacros.h index 81b350ecd0329..b47401c9f05aa 100644 --- a/GPU/Common/GPUDefMacros.h +++ b/GPU/GPUTracking/Definitions/GPUDefMacros.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/Common/GPUDefOpenCL12Templates.h b/GPU/GPUTracking/Definitions/GPUDefOpenCL12Templates.h similarity index 91% rename from GPU/Common/GPUDefOpenCL12Templates.h rename to GPU/GPUTracking/Definitions/GPUDefOpenCL12Templates.h index 22fab3362db4c..f8b9d7f3c2d9b 100644 --- a/GPU/Common/GPUDefOpenCL12Templates.h +++ b/GPU/GPUTracking/Definitions/GPUDefOpenCL12Templates.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -88,4 +89,4 @@ enum LocalOrGlobal { Mem_Local, Mem_Global, Mem_Constant, Mem_Plain }; #endif #endif //GPUDEFOPENCL12TEMPLATES_H - // clang-format on +// clang-format on diff --git a/GPU/Common/GPULogging.h b/GPU/GPUTracking/Definitions/GPULogging.h similarity index 92% rename from GPU/Common/GPULogging.h rename to GPU/GPUTracking/Definitions/GPULogging.h index c78e21dce9941..1d020180401d4 100644 --- a/GPU/Common/GPULogging.h +++ b/GPU/GPUTracking/Definitions/GPULogging.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h new file mode 100644 index 0000000000000..34f3108077968 --- /dev/null +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -0,0 +1,432 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUSettingsList.h +/// \author David Rohr + +// This file contains macros to generate all settings for the GPU Reconstruction. +// Macros are used in the following places: +// Create ConfigurableParam object for workflow. +// Configure standalone benchmark. +// Create plain-C struct for GPU code. +// Create static constexpr with default values for GPU run time compilation + +#include "GPUDefConstantsAndSettings.h" +#ifndef GPUSETTINGS_H +#error Please include GPUSettings.h! +#endif + +// clang-format off + +#ifdef QCONFIG_INSTANCE +using namespace GPUCA_NAMESPACE::gpu; +#endif +#ifdef BeginNamespace // File should not be included without defining the macros, but rootcling will do for dictionary generation +BeginNamespace(GPUCA_NAMESPACE) +BeginNamespace(gpu) + +// Settings concerning the reconstruction +// There must be no bool in here, use char, as sizeof(bool) is compiler dependent and fails on GPUs!!!!!! +BeginSubConfig(GPUSettingsRecTPC, tpc, configStandalone.rec, "RECTPC", 0, "Reconstruction settings", rec_tpc) +AddOptionRTC(rejectQPt, float, 1.f / 0.05f, "", 0, "QPt threshold to reject clusters of TPC tracks (Inverse Pt!!!)") +AddOptionRTC(hitPickUpFactor, float, 2., "", 0, "multiplier for the chi2 window for hit pick up procedure") +AddOptionRTC(neighboursSearchArea, float, 3., "", 0, "area in cm for the search of neighbours") +AddOptionRTC(clusterError2CorrectionY, float, 1., "", 0, "correction for the squared cluster error during tracking") +AddOptionRTC(clusterError2CorrectionZ, float, 1., "", 0, "correction for the squared cluster error during tracking") +AddOptionRTC(minNTrackClusters, int, -1, "", 0, "required min number of clusters on the track") +AddOptionRTC(searchWindowDZDR, float, 2.5, "", 0, "Use DZDR window for seeding instead of vertex window") +AddOptionRTC(trackReferenceX, float, 1000.f, "", 0, "Transport all tracks to this X after tracking (disabled if > 500, auto = 1000)") +AddOptionRTC(zsThreshold, float, 2.0f, "", 0, "Zero-Suppression threshold") +AddOptionRTC(tubeChi2, float, 5.f * 5.f, "", 0, "Max chi2 to mark cluster adjacent to track") +AddOptionRTC(tubeMaxSize2, float, 2.5f * 2.5f, "", 0, "Square of max tube size (normally derrived from tpcTubeChi2)") +AddOptionRTC(noisyPadsQuickCheck, unsigned char, 1, "", 0, "Only check first fragment for noisy pads instead of all fragments (when test is enabled).") +AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, unsigned short, 500, "", 0, "Except pad from cluster finding if total number of charges in a fragment is above this baseline (disable = 0)") +AddOptionRTC(maxConsecTimeBinAboveThreshold, unsigned short, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)") +AddOptionRTC(cfQMaxCutoff, unsigned char, 3, "", 0, "Cluster Finder rejects cluster with qmax below this threshold") +AddOptionRTC(cfQTotCutoff, unsigned char, 0, "", 0, "Cluster Finder rejects cluster with qtot below this threshold") +AddOptionRTC(cfInnerThreshold, unsigned char, 0, "", 0, "Cluster Finder extends cluster if inner charge above this threshold") +AddOptionRTC(cfMinSplitNum, unsigned char, 1, "", 0, "Minimum number of split charges in a cluster for the cluster to be marked as split") +AddOptionRTC(cfNoiseSuppressionEpsilon, unsigned char, 10, "", 0, "Cluster Finder: Difference between peak and charge for the charge to count as a minima during noise suppression") +AddOptionRTC(nWays, char, 3, "", 0, "Do N fit passes in final fit of merger") +AddOptionRTC(nWaysOuter, char, 0, "", 0, "Store outer param") +AddOptionRTC(trackFitRejectMode, char, 5, "", 0, "0: no limit on rejection or missed hits, >0: break after n rejected hits, <0: reject at max -n hits") +AddOptionRTC(dEdxTruncLow, unsigned char, 2, "", 0, "Low truncation threshold, fraction of 128") +AddOptionRTC(dEdxTruncHigh, unsigned char, 77, "", 0, "High truncation threshold, fraction of 128") +AddOptionRTC(globalTracking, char, 1, "", 0, "Enable Global Tracking (prolong tracks to adjacent sectors to find short segments)") +AddOptionRTC(disableRefitAttachment, unsigned char, 0, "", 0, "Bitmask to disable certain attachment steps during refit (1: attachment, 2: propagation, 4: loop following, 8: mirroring)") +AddOptionRTC(rejectionStrategy, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression (0 = no, 1 = strategy A, 2 = strategy B)") +AddOptionRTC(mergeLoopersAfterburner, unsigned char, 1, "", 0, "Run afterburner for additional looper merging") +AddOptionRTC(compressionTypeMask, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits (1=truncate charge/width LSB, 2=differences, 4=track-model)") +AddOptionRTC(compressionSortOrder, unsigned char, GPUCA_NAMESPACE::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression (0 = time, 1 = pad, 2 = Z-time-pad, 3 = Z-pad-time, 4 = no sorting (use incoming order))") +AddOptionRTC(sigBitsCharge, unsigned char, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") +AddOptionRTC(sigBitsWidth, unsigned char, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") +AddOptionRTC(forceEarlyTransform, char, -1, "", 0, "Force early TPC transformation also for continuous data (-1 = auto)") +AddOptionRTC(dropLoopers, unsigned char, 0, "", 0, "Drop looping tracks starting from second loop") +AddOptionRTC(mergerCovSource, unsigned char, 2, "", 0, "Method to obtain covariance in track merger: 0 = simple filterErrors method, 1 = use cov from track following, 2 = refit") +AddOptionRTC(mergerInterpolateErrors, unsigned char, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") +AddOptionRTC(retryRefit, char, 1, "", 0, "Retry refit when fit fails") +AddOptionRTC(loopInterpolationInExtraPass, char, -1, "", 0, "Perform loop interpolation in an extra pass") +AddOptionRTC(mergerReadFromTrackerDirectly, char, 1, "", 0, "Forward data directly from tracker to merger on GPU") +AddOptionRTC(dropSecondaryLegsInOutput, char, 1, "", 0, "Do not store secondary legs of looping track in TrackTPC") +AddHelp("help", 'h') +EndConfig() + +BeginSubConfig(GPUSettingsRecTRD, trd, configStandalone.rec, "RECTRD", 0, "Reconstruction settings", rec_trd) +AddOptionRTC(minTrackPt, float, .5f, "", 0, "Min Pt for tracks to be propagated through the TRD") +AddOptionRTC(maxChi2, float, 15.f, "", 0, "Max chi2 for TRD tracklets to be matched to a track") +AddOptionRTC(penaltyChi2, float, 13.f, "", 0, "Chi2 penalty for no available TRD tracklet (effective chi2 cut value)") +AddOptionRTC(chi2StrictCut, float, 10.f, "", 0, "Chi2 cut for strict matching mode") +AddOptionRTC(chi2SeparationCut, float, 2.5f, "", 0, "Minimum difference between chi2 of winner match and chi2 of second best match") +AddOptionRTC(nSigmaTerrITSTPC, float, 4.f, "", 0, "Number of sigmas for ITS-TPC track time error estimate") +AddOptionRTC(stopTrkAfterNMissLy, unsigned char, 6, "", 0, "Abandon track following after N layers without a TRD match") +AddHelp("help", 'h') +EndConfig() + +BeginSubConfig(GPUSettingsRec, rec, configStandalone, "REC", 0, "Reconstruction settings", rec) +AddOptionRTC(maxTrackQPt, float, 1.f / GPUCA_MIN_TRACK_PT_DEFAULT, "", 0, "required max Q/Pt (==min Pt) of tracks") +AddOptionRTC(nonConsecutiveIDs, char, false, "", 0, "Non-consecutive cluster IDs as in HLT, disables features that need access to slice data in TPC merger") +AddOptionRTC(fwdTPCDigitsAsClusters, unsigned char, 0, "", 0, "Forward TPC digits as clusters (if they pass the ZS threshold)") +AddOptionRTC(bz0Pt, unsigned char, 60, "", 0, "Nominal Pt to set when bz = 0 (in 10 MeV)") +AddOptionRTC(fitInProjections, char, -1, "", 0, "Fit in projection, -1 to enable for all but passes but the first one") +AddOptionRTC(fitPropagateBzOnly, char, -1, "", 0, "Propagate using Bz only for n passes") +AddOptionRTC(useMatLUT, char, 0, "", 0, "Use material lookup table for TPC refit") +AddOptionRTC(trackingRefitGPUModel, char, 1, "", 0, "Use GPU track model for the Global Track Refit") +AddCustomCPP(void SetMinTrackPt(float v) { maxTrackQPt = v > 0.001 ? (1. / v) : (1. / 0.001); }) +AddSubConfig(GPUSettingsRecTPC, tpc) +AddSubConfig(GPUSettingsRecTRD, trd) +AddHelp("help", 'h') +EndConfig() + +// Settings steering the processing once the device was selected +BeginSubConfig(GPUSettingsProcessingRTC, rtc, configStandalone.proc, "RTC", 0, "Processing settings", proc_rtc) +AddOption(cacheOutput, bool, false, "", 0, "Cache RTC compilation results") +AddOption(optConstexpr, bool, true, "", 0, "Replace constant variables by static constexpr expressions") +AddOption(compilePerKernel, bool, true, "", 0, "Run one RTC compilation per kernel") +AddOption(enable, bool, false, "", 0, "Use RTC to optimize GPU code") +AddHelp("help", 'h') +EndConfig() + +BeginSubConfig(GPUSettingsProcessing, proc, configStandalone, "PROC", 0, "Processing settings", proc) +AddOption(platformNum, int, -1, "", 0, "Platform to use, in case the backend provides multiple platforms (-1 = auto-select)") +AddOption(deviceNum, int, -1, "gpuDevice", 0, "Set GPU device to use (-1: automatic, -2: for round-robin usage in timeslice-pipeline)") +AddOption(gpuDeviceOnly, bool, false, "", 0, "Use only GPU as device (i.e. no CPU for OpenCL)") +AddOption(globalInitMutex, bool, false, "", 0, "Use global mutex to synchronize initialization of multiple GPU instances") +AddOption(stuckProtection, int, 0, "", 0, "Timeout in us, When AMD GPU is stuck, just continue processing and skip tracking, do not crash or stall the chain") +AddOption(trdNCandidates, int, 3, "", 0, "Number of branching track candidates for single input track during propagation") +AddOption(debugLevel, int, -1, "debug", 'd', "Set debug level (-1 = silend)") +AddOption(allocDebugLevel, int, 0, "allocDebug", 0, "Some debug output for memory allocations (without messing with normal debug level)") +AddOption(debugMask, int, -1, "", 0, "Mask for debug output dumps to file") +AddOption(checkKernelFailures, bool, false, "", 0, "Synchronize after each kernel call and identify failing kernels") +AddOption(comparableDebutOutput, bool, true, "", 0, "Make CPU and GPU debug output comparable (sort / skip concurrent parts)") +AddOption(showOutputStat, bool, false, "", 0, "Print some track output statistics") +AddOption(runCompressionStatistics, bool, false, "compressionStat", 0, "Run statistics and verification for cluster compression") +AddOption(resetTimers, char, 1, "", 0, "Reset timers every event") +AddOption(deviceTimers, bool, true, "", 0, "Use device timers instead of host-based time measurement") +AddOption(keepAllMemory, bool, false, "", 0, "Allocate all memory on both device and host, and do not reuse") +AddOption(keepDisplayMemory, bool, false, "", 0, "Like keepAllMemory, but only for memory required for event display") +AddOption(disableMemoryReuse, bool, false, "", 0, "Disable memory reusage (for debugging only)") +AddOption(memoryAllocationStrategy, char, 0, "", 0, "Memory Allocation Stragegy (0 = auto, 1 = individual allocations, 2 = single global allocation)") +AddOption(forceMemoryPoolSize, unsigned long, 1, "memSize", 0, "Force size of allocated GPU / page locked host memory", min(0ul)) +AddOption(forceHostMemoryPoolSize, unsigned long, 0, "hostMemSize", 0, "Force size of allocated host page locked host memory (overriding memSize)", min(0ul)) +AddOption(memoryScalingFactor, float, 1.f, "", 0, "Factor to apply to all memory scalers") +AddOption(forceMaxMemScalers, unsigned long, 0, "", 0, "Force using the maximum values for all buffers, Set a value n > 1 to rescale all maximums to a memory size of n") +AddOption(registerStandaloneInputMemory, bool, false, "registerInputMemory", 0, "Automatically register input memory buffers for the GPU") +AddOption(ompThreads, int, -1, "omp", 't', "Number of OMP threads to run (-1: all)", min(-1), message("Using %s OMP threads")) +AddOption(ompKernels, unsigned char, 2, "", 0, "Parallelize with OMP inside kernels instead of over slices, 2 for nested parallelization over TPC sectors and inside kernels") +AddOption(ompAutoNThreads, bool, true, "", 0, "Auto-adjust number of OMP threads, decreasing the number for small input data") +AddOption(nDeviceHelperThreads, int, 1, "", 0, "Number of CPU helper threads for CPU processing") +AddOption(nStreams, char, 8, "", 0, "Number of GPU streams / command queues") +AddOption(nTPCClustererLanes, char, 3, "", 0, "Number of TPC clusterers that can run in parallel") +AddOption(trackletSelectorSlices, char, -1, "", 0, "Number of slices to processes in parallel at max") +AddOption(trackletConstructorInPipeline, char, -1, "", 0, "Run tracklet constructor in the pipeline") +AddOption(trackletSelectorInPipeline, char, -1, "", 0, "Run tracklet selector in the pipeline") +AddOption(fullMergerOnGPU, bool, true, "", 0, "Perform full TPC track merging on GPU instead of only refit") +AddOption(delayedOutput, bool, true, "", 0, "Delay output to be parallel to track fit") +AddOption(mergerSortTracks, char, -1, "", 0, "Sort track indizes for GPU track fit") +AddOption(alternateBorderSort, char, -1, "", 0, "Alternative implementation for sorting of border tracks") +AddOption(tpcCompressionGatherMode, char, -1, "", 0, "TPC Compressed Clusters Gather Mode (0: DMA transfer gather gpu to host, 1: serial DMA to host and gather by copy on CPU, 2. gather via GPU kernal DMA access, 3. gather on GPU via kernel, dma afterwards") +AddOption(tpcCompressionGatherModeKernel, char, -1, "", 0, "TPC Compressed Clusters Gather Mode Kernel (0: unbufferd, 1-3: buffered, 4: multi-block)") +AddOption(tpccfGatherKernel, bool, true, "", 0, "Use a kernel instead of the DMA engine to gather the clusters") +AddOption(doublePipeline, bool, false, "", 0, "Double pipeline mode") +AddOption(doublePipelineClusterizer, bool, true, "", 0, "Include the input data of the clusterizer in the double-pipeline") +AddOption(prefetchTPCpageScan, char, 0, "", 0, "Prefetch Data for TPC page scan in CPU cache") +AddOption(runMC, bool, false, "", 0, "Process MC labels") +AddOption(runQA, int, 0, "qa", 'q', "Enable tracking QA (negative number to provide bitmask for QA tasks)", message("Running QA: %s"), def(1)) +AddOption(outputSharedClusterMap, bool, false, "", 0, "Ship optional shared cluster map as output for further use") +AddOption(disableTPCNoisyPadFilter, bool, false, "", 0, "Disables all TPC noisy pad filters (Not the normal noise filter!)") +AddOption(createO2Output, char, 2, "", 0, "Create Track output in O2 format (2 = skip non-O2 output in GPU track format (reverts to =1 if QA is requested))") +AddOption(clearO2OutputFromGPU, bool, false, "", 0, "Free the GPU memory used for O2 output after copying to host, prevents further O2 processing on the GPU") +AddOption(ignoreNonFatalGPUErrors, bool, false, "", 0, "Continue running after having received non fatal GPU errors, e.g. abort due to overflow") +AddOption(tpcIncreasedMinClustersPerRow, unsigned int, 0, "", 0, "Impose a minimum buffer size for the clustersPerRow during TPC clusterization") +AddOption(noGPUMemoryRegistration, bool, false, "", 0, "Do not register input / output memory for GPU dma transfer") +AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayBackend*, nullptr) +AddSubConfig(GPUSettingsProcessingRTC, rtc) +AddHelp("help", 'h') +EndConfig() + +#ifndef GPUCA_GPUCODE_DEVICE +// Light settings concerning the event display (can be changed without rebuilding vertices) +BeginSubConfig(GPUSettingsDisplayLight, light, configStandalone.display, "GLL", 'g', "Light OpenGL display settings", display_light) +AddOption(animationMode, int, 0, "", 0, "") +AddOption(smoothPoints, bool, true, "", 0, "Apply smoothing to points") +AddOption(smoothLines, bool, false, "", 0, "Apply smoothing to lines") +AddOption(depthBuffer, bool, false, "", 0, "Enable Z-buffer") +AddOption(drawClusters, bool, true, "", 0, "Highlight clusters") +AddOption(drawLinks, bool, false, "", 0, "Highlight links") +AddOption(drawInitLinks, bool, false, "", 0, "Highlight cleaned-up links") +AddOption(drawSeeds, bool, false, "", 0, "Highlight seeds") +AddOption(drawTracklets, bool, false, "", 0, "Highlight tracklets") +AddOption(drawTracks, bool, false, "", 0, "Highlight sector tracks") +AddOption(drawGlobalTracks, bool, false, "", 0, "Highlight global sector tracks prolonged into adjacent sector") +AddOption(drawFinal, bool, false, "", 0, "Highlight final tracks") +AddOption(excludeClusters, int, 0, "", 0, "Exclude clusters from selected draw objects from display") +AddOption(drawSlice, int, -1, "", 0, "Show individual slice") +AddOption(drawRelatedSlices, int, 0, "", 0, "Show related slices (if drawSlice != -1)") +AddOption(drawGrid, int, 0, "", 0, "Highlight grid") +AddOption(propagateTracks, int, 0, "", 0, "Propagate final tracks further (inward / outward / show MC tracks)") +AddOption(showCollision, int, -1, "", 0, "Show only individual collision") +AddOption(colorCollisions, int, 0, "", 0, "Distinguish collisions in timeframe by color") +AddOption(colorClusters, int, 1, "", 0, "Color clusters belonging to track objects") +AddOption(pointSize, float, 2.0f, "", 0, "Set point size") +AddOption(lineWidth, float, 1.4f, "", 0, "Set line width") +AddOption(drawTPC, bool, true, "", 0, "Enable drawing TPC data") +AddOption(drawTRD, bool, true, "", 0, "Enabale drawing TRD data") +AddOption(drawTOF, bool, true, "", 0, "Enabale drawing TOF data") +AddOption(drawITS, bool, true, "", 0, "Enabale drawing ITS data") +AddOption(invertColors, bool, false, "", 0, "Invert colors") +AddHelp("help", 'h') +EndConfig() + +// Heavy settings concerning the event display (can be changed only with rebuilding vertices) +BeginSubConfig(GPUSettingsDisplayHeavy, heavy, configStandalone.display, "GLH", 0, "Heavy OpenGL display settings", display_heavy) +AddOption(drawTPCTracks, bool, true, "", 0, "Show tracks with TPC contribution") +AddOption(drawITSTracks, bool, true, "", 0, "Show tracks with ITS contribution") +AddOption(drawTRDTracks, bool, true, "", 0, "Show tracks with TRD contribution") +AddOption(drawTOFTracks, bool, true, "", 0, "Show tracks with TOF contribution") +AddOption(drawTracksAndFilter, bool, false, "", 0, "Use AND filter instead of OR filter for selecting tracks") +AddOption(propagateLoopers, bool, false, "", 0, "Enabale propagation of loopers") +AddOption(clustersOnly, bool, false, "", 0, "Visualize clusters only") +AddOption(clustersOnNominalRow, bool, false, "", 0, "Show clusters at nominal x of pad row for early-transformed data") +AddOption(separateGlobalTracks, bool, false, "", 0, "Separate global tracks") +AddOption(markClusters, int, 0, "", 0, "Mark clusters") +AddOption(markFakeClusters, int, 0, "", 0, "Mark fake clusters") +AddOption(markAdjacentClusters, int, 0, "", 0, "Mark adjacent clusters") +AddOption(hideRejectedClusters, int, 1, "", 0, "Hide rejected clusters") +AddOption(hideRejectedTracks, int, 1, "", 0, "Hide rejected tracks") +AddOption(hideUnmatchedClusters, int, 0, "", 0, "Hide unmatched clusters") +AddOption(trackFilter, int, 0, "", 0, "Apply filter on tracks to be displayed") +AddOption(projectXY, int, 0, "", 0, "Project everything on the XY-plane") +AddOption(xAdd, float, 0, "", 0, "Separate sectors, increase X coordinate") +AddOption(zAdd, float, 0, "", 0, "Separate sides, increase Z coordinate") +AddHelp("help", 'h') +EndConfig() + +// Camera, window, and renderer settings for the event display +BeginSubConfig(GPUSettingsDisplayRenderer, renderer, configStandalone.display, "GLR", 'g', "Camera / window / renderer OpenGL display settings", display_camera) +AddOption(camLookOrigin, bool, false, "", 0, "Make the camera look at the origin") +AddOption(camYUp, bool, false, "", 0, "Orient the camera such that the y-axis is always upwards") +AddOption(cameraMode, int, 0, "", 0, "Camera mode") +AddOption(fullScreen, bool, false, "", 0, "Full Screen") +AddOption(maximized, bool, false, "", 0, "Full Screen") +AddOption(openGLCore, bool, false, "", 0, "Use renderer path for OpenGL core profile") +AddOption(drawQualityMSAA, int, 0, "", 0, "MultiSample Anti Aliasing") +AddOption(drawQualityDownsampleFSAA, int, 0, "", 0, "Downsampling Anti Aliasing") +AddOption(drawQualityVSync, bool, false, "", 0, "Enable Vertical Sync") +AddOption(maxFPSRate, int, 0, "", 0, "Do not limit FPS but run at maximum possible rate") +AddOption(useGLIndirectDraw, bool, true, "", 0, "Use OpenGL indirect draws to reduce number of draw calls") +AddOption(screenshotScaleFactor, int, 1, "", 0, "Resolution scale factor when taking screenshots") +AddOption(fov, int, 45, "", 0, "Display FOV") +AddHelp("help", 'h') +EndConfig() + +// Settings concerning the event display (fixed settings, cannot be changed) +BeginSubConfig(GPUSettingsDisplay, display, configStandalone, "GL", 'g', "OpenGL display settings", display) +AddOption(showTPCTracksFromO2Format, bool, false, "", 0, "Use TPC tracks in O2 output format instead of GPU format") +AddOptionVec(filterMacros, std::string, "", 0, "ROOT macros used as track filter") +AddSubConfig(GPUSettingsDisplayLight, light) +AddSubConfig(GPUSettingsDisplayHeavy, heavy) +AddSubConfig(GPUSettingsDisplayRenderer, renderer) +AddHelp("help", 'h') +EndConfig() + +// Settings concerning the standalone QA +BeginSubConfig(GPUSettingsQA, QA, configStandalone, "QA", 'q', "QA settings", QA) +AddOptionVec(compareInputs, std::string, "QAinput", 0, "Read histogram from these input files and include them in the output plots") +AddOptionVec(compareInputNames, std::string, "QAinputName", 0, "Legend entries for data from comparison histogram files") +AddOption(name, std::string, "", "", 0, "Legend entry for new data from current processing") +AddOption(output, std::string, "", "", 0, "Store histograms in output root file", def(std::string("histograms.root"))) +AddOption(inputHistogramsOnly, bool, false, "", 0, "Do not run tracking, but just create PDFs from input root files") +AddOption(strict, bool, true, "", 0, "Strict QA mode: Only consider resolution of tracks where the fit ended within 5 cm of the reference, and remove outliers.") +AddOption(qpt, float, 10.f, "", 0, "Set cut for Q/Pt", def(2.f)) +AddOption(maxResX, float, 1e6f, "", 0, "Maxmimum X (~radius) for reconstructed track position to take into accound for resolution QA in cm") +AddOption(recThreshold, float, 0.9f, "", 0, "Compute the efficiency including impure tracks with fake contamination") +AddOption(resPrimaries, int, 0, "", 0, "0: Resolution for all tracks, 1: only for primary tracks, 2: only for non-primaries", def(1)) +AddOption(filterCharge, int, 0, "", 0, "Filter for positive (+1) or negative (-1) charge") +AddOption(filterPID, int, -1, "", 0, "Filter for Particle Type (0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton)") +AddOption(nativeFitResolutions, bool, false, "", 0, "Create resolution histograms in the native fit units (sin(phi), tan(lambda), Q/Pt)") +AddOption(enableLocalOutput, bool, true, "", 0, "Enable normal output to local PDF files / console") +AddOption(csvDump, bool, false, "", 0, "Dump all clusters and Pt information into csv file") +AddOption(writeMCLabels, bool, false, "", 0, "Store mc labels to file for later matching") +AddOption(writeRootFiles, bool, false, "", 0, "Create ROOT canvas files") +AddOptionVec(matchMCLabels, std::string, "", 0, "Read labels from files and match them, only process tracks where labels differ") +AddOption(matchDisplayMinPt, float, 0, "", 0, "Minimum Pt of a matched track to be displayed") +AddOption(noMC, bool, false, "", 0, "Force running QA without MC labels even if present") +AddOption(shipToQC, bool, false, "", 0, "Do not write output files but ship histograms for QC") +AddOption(shipToQCAsCanvas, bool, false, "", 0, "Send TCanvases with full layout to QC instead of individual histograms") +AddOption(clusterRejectionHistograms, bool, false, "", 0, "Fill histograms with cluster rejection statistics") +AddOption(histMaxNClusters, unsigned int, 500000000, "", 0, "Maximum number of clusters in rejection histograms") +AddShortcut("compare", 0, "--QAinput", "Compare QA histograms", "--qa", "--QAinputHistogramsOnly") +AddHelp("help", 'h') +EndConfig() + +#ifdef BeginConfig +// Settings concerning the standlone timeframe from run 2 events assembly tool +BeginSubConfig(GPUSettingsTFSim, TF, configStandalone, "TF", 't', "Timeframe settings") +AddOption(nMerge, int, 0, "", 0, "Merge n events in a timeframe", min(0)) +AddOption(averageDistance, float, 50., "", 0, "Average distance in cm of events merged into timeframe", min(0.f)) +AddOption(randomizeDistance, bool, true, "", 0, "Randomize distance around average distance of merged events") +AddOption(shiftFirstEvent, bool, true, "", 0, "Also shift the first event in z when merging events to a timeframe") +AddOption(bunchSim, int, 0, "", 0, "Simulate correct bunch interactions instead of placing only the average number of events. A value [n] > 1 sets TFlen for [n] collisions in average. (Incompatible to TFmerge)") +AddOption(bunchCount, int, 12, "", 0, "Number of bunches per trainsort") +AddOption(bunchSpacing, int, 50, "", 0, "Spacing between benches in ns") +AddOption(bunchTrainCount, int, 48, "", 0, "Number of bunch trains") +AddOption(abortGapTime, int, (3000), "", 0, "Length of abort gap in ns") +AddOption(interactionRate, int, 50000, "", 0, "Instantaneous interaction rate") +AddOption(timeFrameLen, long, (1000000000 / 44), "", 'l', "Timeframe len in ns") +AddOption(noBorder, bool, false, "", 0, "Do not simulate border effects (partial events)") +AddOption(noEventRepeat, int, 0, "", 0, "0: Place random events, 1: Place events in timeframe one after another, 2: Place random events but do not repat", def(1)) +AddOption(nTotalEventsInTF, int, 0, "", 0, "Total number of collisions to be placed in the interior of all time frames (excluding borders)") +AddOption(eventStride, int, 0, "", 0, "Do not select random event, but walk over array of events in stride steps") +AddOption(overlayRaw, bool, false, "", 0, "Overlay raw TPC data instead of spatial clusters") +AddHelp("help", 'h') +EndConfig() + +// Settings concerning standalone toy event generator +BeginSubConfig(GPUSettingsEG, EG, configStandalone, "EG", 0, "Event generator settings") +AddOption(numberOfTracks, int, 1, "", 0, "Number of tracks per generated event") +AddHelp("help", 'h') +EndConfig() + +// Settings for the standalone benchmark +BeginConfig(GPUSettingsStandalone, configStandalone) +#if defined(CUDA_ENABLED) || defined(OPENCL1_ENABLED) || defined(OPENCL2_ENABLED) || defined(HIP_ENABLED) +AddOption(runGPU, bool, true, "", 'g', "Use GPU for processing", message("GPU processing: %s")) +#else +AddOption(runGPU, bool, false, "", 'g', "Use GPU for processing", message("GPU processing: %s")) +#endif +AddOptionSet(runGPU, bool, false, "", 'c', "Use CPU for processing", message("CPU enabled")) +#if defined(CUDA_ENABLED) +AddOption(gpuType, std::string, "CUDA", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") +#elif defined(OPENCL2_ENABLED) +AddOption(gpuType, std::string, "OCL2", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") +#elif defined(OPENCL1_ENABLED) +AddOption(gpuType, std::string, "OCL", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") +#elif defined(HIP_ENABLED) +AddOption(gpuType, std::string, "HIP", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") +#else +AddOption(gpuType, std::string, "", "", 0, "GPU type (CUDA / HIP / OCL / OCL2)") +#endif +AddOption(runGPUforce, bool, true, "", 0, "Force usage of the specified GPU device type, no CPU fallback") +AddOption(noprompt, bool, true, "", 0, "Do prompt for keypress before exiting") +AddOption(continueOnError, bool, false, "", 0, "Continue processing after an error") +AddOption(seed, int, -1, "", 0, "Set srand seed (-1: random)") +AddOption(StartEvent, int, 0, "", 's', "First event to process", min(0)) +AddOption(nEvents, int, -1, "", 'n', "Number of events to process (-1; all)", min(0)) +AddOption(runs, int, 1, "runs", 'r', "Number of iterations to perform (repeat each event)", min(0)) +AddOption(runs2, int, 1, "runsExternal", 0, "Number of iterations to perform (repeat full processing)", min(1)) +AddOption(runsInit, int, 1, "", 0, "Number of initial iterations excluded from average", min(0)) +AddOption(eventsDir, const char*, "pp", "events", 'e', "Directory with events to process", message("Reading events from Directory events/%s")) +AddOption(eventDisplay, int, 0, "display", 'd', "Show standalone event display", def(1)) //1: default display (Windows / X11), 2: glut, 3: glfw +AddOption(eventGenerator, bool, false, "", 0, "Run event generator") +AddOption(cont, bool, false, "", 0, "Process continuous timeframe data") +AddOption(outputcontrolmem, unsigned long, 0, "outputMemory", 0, "Use predefined output buffer of this size", min(0ul), message("Using %s bytes as output memory")) +AddOption(inputcontrolmem, unsigned long, 0, "inputMemory", 0, "Use predefined input buffer of this size", min(0ul), message("Using %s bytes as input memory")) +AddOption(cpuAffinity, int, -1, "", 0, "Pin CPU affinity to this CPU core", min(-1)) +AddOption(fifoScheduler, bool, false, "", 0, "Use FIFO realtime scheduler", message("Setting FIFO scheduler: %s")) +AddOption(fpe, bool, true, "", 0, "Trap on floating point exceptions") +AddOption(flushDenormals, bool, true, "", 0, "Enable FTZ and DAZ (Flush all denormals to zero)") +AddOption(solenoidBz, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") +AddOption(constBz, bool, false, "", 0, "Force constand Bz") +AddOption(overrideMaxTimebin, bool, false, "", 0, "Override max time bin setting for continuous data with max time bin in time frame") +AddOption(encodeZS, int, -1, "", 0, "Zero-Suppress TPC data", def(1)) +AddOption(zsFilter, int, -1, "", 0, "Apply Zero-Suppression when loading digits and remove those below threshold", def(1)) +AddOption(zs12bit, bool, true, "", 0, "Perform 12 bit zero-suppression encoding / filter") +AddOption(dumpEvents, bool, false, "", 0, "Dump events (after transformation such as encodeZS") +AddOption(stripDumpedEvents, bool, false, "", 0, "Remove redundant inputs (e.g. digits and ZS) before dumping") +AddOption(printSettings, int, 0, "", 0, "Print all settings", def(1)) +AddOption(memoryStat, bool, false, "", 0, "Print memory statistics") +AddOption(testSyncAsync, bool, false, "syncAsync", 0, "Test first synchronous and then asynchronous processing") +AddOption(testSync, bool, false, "sync", 0, "Test settings for synchronous phase") +AddOption(timeFrameTime, bool, false, "tfTime", 0, "Print some debug information about time frame processing time") +AddOption(controlProfiler, bool, false, "", 0, "Issues GPU profiler stop and start commands to profile only the relevant processing part") +AddOption(preloadEvents, bool, false, "", 0, "Preload events into host memory before start processing") +AddOption(recoSteps, int, -1, "", 0, "Bitmask for RecoSteps") +AddOption(recoStepsGPU, int, -1, "", 0, "Bitmask for RecoSteps") +AddOption(runMerger, int, 1, "", 0, "Run track merging / refit", min(0), max(1)) +AddOption(runTRD, int, -1, "", 0, "Enable TRD processing") +AddOption(rundEdx, int, -1, "", 0, "Enable dEdx processing") +AddOption(runCompression, int, 1, "", 0, "Enable TPC Compression") +AddOption(runTransformation, int, 1, "", 0, "Enable TPC Transformation") +AddOption(runRefit, bool, false, "", 0, "Enable final track refit") +AddHelp("help", 'h') +AddHelpAll("helpall", 'H') +AddSubConfig(GPUSettingsRec, rec) +AddSubConfig(GPUSettingsProcessing, proc) +AddSubConfig(GPUSettingsTFSim, TF) +AddSubConfig(GPUSettingsQA, QA) +AddSubConfig(GPUSettingsDisplay, display) +AddSubConfig(GPUSettingsEG, EG) +EndConfig() +#endif // BeginConfig + +//Settings for the O2 workfllow +#if !defined(QCONFIG_PARSER_CXX) && (defined(GPUCA_O2_LIB) || defined(GPUCA_O2_INTERFACE)) +BeginSubConfig(GPUSettingsO2, global, configStandalone, "O2", 0, "O2 workflow settings", global) +AddOption(solenoidBz, float, -1e6f, "", 0, "solenoid field strength") +AddOption(constBz, bool, false, "", 0, "force constant Bz for tests") +AddOption(continuousMaxTimeBin, int, 0, "", 0, "maximum time bin of continuous data, 0 for triggered events, -1 for default of 23ms") +AddOption(deviceType, std::string, "CPU", "", 0, "Device type, CPU | CUDA | HIP | OCL1 | OCL2") +AddOption(forceDeviceType, bool, true, "", 0, "force device type, otherwise allows fall-back to CPU") +AddOption(synchronousProcessing, bool, false, "", 0, "Apply performance shortcuts for synchronous processing, disable unneeded steps") +AddOption(dump, int, 0, "", 0, "Dump events for standalone benchmark: 1 = dump events, 2 = dump events and skip processing in workflow") +AddOption(display, bool, false, "", 0, "Enable standalone gpu tracking visualizaion") +AddOption(dEdxFile, std::string, "", "", 0, "File name of dEdx Splines file") +AddOption(transformationFile, std::string, "", "", 0, "File name of TPC fast transformation map") +AddOption(matLUTFile, std::string, "", "", 0, "File name of material LUT file") +AddOption(gainCalibFile, std::string, "", "", 0, "File name of TPC pad gain calibration") +AddOption(allocateOutputOnTheFly, bool, true, "", 0, "Allocate shm output buffers on the fly, instead of using preallocated buffer with upper bound size") +AddOption(outputBufferSize, unsigned long, 200000000ul, "", 0, "Size of the output buffers to be allocated") +AddOption(mutexMemReg, bool, false, "", 0, "Global mutex to serialize GPU memory registration") +AddOption(printSettings, int, 0, "", 0, "Print all settings", def(1)) +AddOption(gpuDisplayfilterMacro, std::string, "", "", 0, "File name of ROOT macro for GPU display filter") +EndConfig() +#endif // GPUCA_O2_LIB +#endif // !GPUCA_GPUCODE_DEVICE + +// Derrived parameters used in GPUParam +BeginHiddenConfig(GPUSettingsParam, param) +AddVariableRTC(dAlpha, float, 0.f) // angular size +AddVariableRTC(bzkG, float, 0.f) // constant magnetic field value in kG +AddVariableRTC(constBz, float, 0.f) // constant magnetic field value in kG*clight +AddVariableRTC(assumeConstantBz, char, 0) // Assume a constant magnetic field +AddVariableRTC(toyMCEventsFlag, char, 0) // events were build with home-made event generator +AddVariableRTC(continuousTracking, char, 0) // Continuous tracking, estimate bz and errors for abs(z) = 125cm during seeding +AddVariableRTC(resetTimers, char, 0) // Reset benchmark timers before event processing +AddVariableRTC(dodEdx, char, 0) // Do dEdx computation +AddVariableRTC(earlyTpcTransform, char, 0) // do Early TPC transformation +AddVariableRTC(debugLevel, char, 0) // Debug level +AddVariableRTC(continuousMaxTimeBin, int, 0) // Max time bin for continuous tracking +EndConfig() + +EndNamespace() // gpu +EndNamespace() // GPUCA_NAMESPACE +#endif // #ifdef BeginNamespace + // clang-format on diff --git a/GPU/GPUTracking/Definitions/clusterFinderDefs.h b/GPU/GPUTracking/Definitions/clusterFinderDefs.h new file mode 100644 index 0000000000000..3cfd58983a0c5 --- /dev/null +++ b/GPU/GPUTracking/Definitions/clusterFinderDefs.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file clusterFinderDefs.h +/// \author David Rohr + +#ifndef O2_GPU_CLUSTERFINDERDEFS_H +#define O2_GPU_CLUSTERFINDERDEFS_H + +#include "GPUDef.h" + +#ifndef __OPENCL__ +using uchar = unsigned char; +#endif +#ifdef __APPLE__ +using ulong = unsigned long; +#endif + +/* #define CHARGEMAP_TIME_MAJOR_LAYOUT */ +#define CHARGEMAP_TILING_LAYOUT + +#define SCRATCH_PAD_SEARCH_N 8 +#define SCRATCH_PAD_COUNT_N 16 +#if defined(GPUCA_GPUCODE) +#define SCRATCH_PAD_BUILD_N 8 +#define SCRATCH_PAD_NOISE_N 8 +#else +// Double shared memory on cpu as we can't reuse the memory from other threads +#define SCRATCH_PAD_BUILD_N 16 +#define SCRATCH_PAD_NOISE_N 16 +#endif + +// Padding of 2 and 3 respectively would be enough. But this ensures that +// rows are always aligned along cache lines. Likewise for TPC_PADS_PER_ROW. +#define PADDING_PAD 8 +#define PADDING_TIME 4 +#define TPC_PADS_PER_ROW 144 + +#define TPC_ROWS_PER_CRU 18 +#define TPC_PADS_PER_ROW_PADDED (TPC_PADS_PER_ROW + PADDING_PAD) +#define TPC_NUM_OF_PADS (GPUCA_ROW_COUNT * TPC_PADS_PER_ROW_PADDED + PADDING_PAD) +#define TPC_PADS_IN_SECTOR 14560 +#define TPC_MAX_FRAGMENT_LEN 4000 +#define TPC_MAX_FRAGMENT_LEN_PADDED (TPC_MAX_FRAGMENT_LEN + 2 * PADDING_TIME) +#define TPC_MAX_TIME_BIN_TRIGGERED 600 + +#if 0 +#define DBG_PRINT(msg, ...) printf(msg "\n", __VA_ARGS__) +#else +#define DBG_PRINT(msg, ...) static_cast<void>(0) +#endif + +#ifdef GPUCA_GPUCODE +#define CPU_ONLY(x) static_cast<void>(0) +#define CPU_PTR(x) nullptr +#else +#define CPU_ONLY(x) x +#define CPU_PTR(x) x +#endif + +namespace GPUCA_NAMESPACE::gpu::tpccf +{ + +using SizeT = size_t; +using TPCTime = int; +using TPCFragmentTime = short; +using Pad = unsigned char; +using GlobalPad = short; +using Row = unsigned char; +using Cru = unsigned char; + +using Charge = float; + +using Delta = short; +using Delta2 = short2; + +using local_id = short2; + +} // namespace GPUCA_NAMESPACE::gpu::tpccf + +#endif diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_AliRoot.h b/GPU/GPUTracking/GPUTrackingLinkDef_AliRoot.h index 33bb72f6a5408..266228dd79ff6 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_AliRoot.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_AliRoot.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h index df62b623abb44..faf8b870902b2 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,17 +18,21 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::gpu::GPUTPCO2Interface + ; -#pragma link C++ class o2::gpu::GPUTPCO2InterfaceRefit + ; -#pragma link C++ class o2::gpu::GPUO2InterfaceQA + ; #pragma link C++ class o2::gpu::TPCdEdxCalibrationSplines + ; +#pragma link C++ class o2::gpu::GPUTPCGMMergedTrack + ; +#pragma link C++ class o2::gpu::trackInterface < o2::track::TrackParCov> + ; +#pragma link C++ class o2::gpu::GPUTRDTrack_t < o2::gpu::trackInterface < o2::track::TrackParCov>> + ; +#pragma link C++ class std::vector < o2::gpu::GPUTRDTrack_t < o2::gpu::trackInterface < o2::track::TrackParCov>>> + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsO2 + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRec + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRecTPC + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRecTRD + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsProcessing + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsProcessingRTC + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplay + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplayLight + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplayHeavy + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplayRenderer + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsQA + ; -#pragma link C++ class o2::gpu::trackInterface < o2::dataformats::TrackTPCITS> + ; -#pragma link C++ class o2::gpu::GPUTRDTrack_t < o2::gpu::trackInterface < o2::dataformats::TrackTPCITS>> + ; -#pragma link C++ class std::vector < o2::gpu::GPUTRDTrack_t < o2::gpu::trackInterface < o2::dataformats::TrackTPCITS>>> + ; #endif diff --git a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx index d88ae53768a2a..ad7d481177caa 100644 --- a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx +++ b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -175,10 +176,8 @@ int AliHLTGPUDumpComponent::DoEvent(const AliHLTComponentEventData& evtData, con const AliHLTTPCClusterXYZData* clustersXYZ[NSLICES][NPATCHES] = {nullptr}; const AliHLTTPCRawClusterData* clustersRaw[NSLICES][NPATCHES] = {nullptr}; bool labelsPresent = false; - GPUTRDTrackletWord* TRDtracklets = nullptr; - GPUTRDTrackletLabels* TRDtrackletsMC = nullptr; + const GPUTRDTrackletWord* TRDtracklets = nullptr; int nTRDTrackletsTotal = 0; - int nTRDTrackletsMCTotal = 0; for (unsigned long ndx = 0; ndx < evtData.fBlockCnt; ndx++) { const AliHLTComponentBlockData& pBlock = blocks[ndx]; @@ -192,11 +191,8 @@ int AliHLTGPUDumpComponent::DoEvent(const AliHLTComponentEventData& evtData, con clusterLabels[slice][patch] = (const AliHLTTPCClusterMCData*)pBlock.fPtr; labelsPresent = true; } else if (pBlock.fDataType == AliHLTTRDDefinitions::fgkTRDTrackletDataType) { - TRDtracklets = reinterpret_cast<GPUTRDTrackletWord*>(pBlock.fPtr); + TRDtracklets = reinterpret_cast<const GPUTRDTrackletWord*>(pBlock.fPtr); nTRDTrackletsTotal = pBlock.fSize / sizeof(GPUTRDTrackletWord); - } else if (pBlock.fDataType == (AliHLTTRDDefinitions::fgkTRDMCTrackletDataType)) { - TRDtrackletsMC = reinterpret_cast<GPUTRDTrackletLabels*>(pBlock.fPtr); - nTRDTrackletsMCTotal = pBlock.fSize / sizeof(GPUTRDTrackletLabels); } } @@ -440,6 +436,9 @@ int AliHLTGPUDumpComponent::DoEvent(const AliHLTComponentEventData& evtData, con fChain->mIOPtrs.nMCInfosTPC = mcInfo.size(); fChain->mIOPtrs.mcInfosTPC = mcInfo.data(); + static const GPUTPCMCInfoCol mcColInfo = {0, (unsigned int)mcInfo.size()}; + fChain->mIOPtrs.mcInfosTPCCol = &mcColInfo; + fChain->mIOPtrs.nMCInfosTPCCol = 1; HLTDebug("Number of MC infos: %d", (int)mcInfo.size()); } unsigned int clusterNum = 0; @@ -450,9 +449,19 @@ int AliHLTGPUDumpComponent::DoEvent(const AliHLTComponentEventData& evtData, con } fChain->mIOPtrs.nTRDTracklets = nTRDTrackletsTotal; - fChain->mIOPtrs.trdTracklets = TRDtracklets; - fChain->mIOPtrs.nTRDTrackletsMC = nTRDTrackletsMCTotal; - fChain->mIOPtrs.trdTrackletsMC = TRDtrackletsMC; + std::vector<GPUTRDTrackletWord> tracklets(nTRDTrackletsTotal); + for (int i = 0; i < nTRDTrackletsTotal; i++) { + tracklets[i] = TRDtracklets[i]; + } + std::sort(tracklets.data(), tracklets.data() + nTRDTrackletsTotal); + fChain->mIOPtrs.trdTracklets = tracklets.data(); + + fChain->mIOPtrs.nTRDTriggerRecords = 1; + static float t = 0.f; + static int o = 0; + fChain->mIOPtrs.trdTriggerTimes = &t; + fChain->mIOPtrs.trdTrackletIdxFirst = &o; + HLTDebug("Number of TRD tracklets: %d", (int)nTRDTrackletsTotal); static int nEvent = 0; diff --git a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.h b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.h index c30d31de544b4..46d991bd481bd 100644 --- a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.h +++ b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Global/GPUChain.cxx b/GPU/GPUTracking/Global/GPUChain.cxx index 3a5f3b1523c45..b94e48d1e551c 100644 --- a/GPU/GPUTracking/Global/GPUChain.cxx +++ b/GPU/GPUTracking/Global/GPUChain.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Global/GPUChain.h b/GPU/GPUTracking/Global/GPUChain.h index 255672c880fa1..e5e9a8a4355d2 100644 --- a/GPU/GPUTracking/Global/GPUChain.h +++ b/GPU/GPUTracking/Global/GPUChain.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,11 +57,13 @@ class GPUChain virtual void ReadSettings(const char* dir = "") {} const GPUParam& GetParam() const { return mRec->mHostConstantMem->param; } - const GPUSettingsEvent& GetEventSettings() const { return mRec->mEventSettings; } + const GPUSettingsGRP& GetGRPSettings() const { return mRec->mGRPSettings; } const GPUSettingsDeviceBackend& GetDeviceBackendSettings() const { return mRec->mDeviceBackendSettings; } const GPUSettingsProcessing& GetProcessingSettings() const { return mRec->mProcessingSettings; } + const GPUCalibObjectsConst& calib() const { return processors()->calibObjects; } GPUReconstruction* rec() { return mRec; } const GPUReconstruction* rec() const { return mRec; } + inline const GPUConstantMem* GetProcessors() { return mRec->processors(); } GPUReconstruction::RecoStepField GetRecoSteps() const { return mRec->GetRecoSteps(); } GPUReconstruction::RecoStepField GetRecoStepsGPU() const { return mRec->GetRecoStepsGPU(); } @@ -82,6 +85,13 @@ class GPUChain inline GPUSettingsProcessing& ProcessingSettings() { return mRec->mProcessingSettings; } inline void SynchronizeStream(int stream) { mRec->SynchronizeStream(stream); } inline void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) { mRec->SynchronizeEvents(evList, nEvents); } + inline void SynchronizeEventAndRelease(deviceEvent* ev, bool doGPU = true) + { + if (doGPU) { + SynchronizeEvents(ev); + ReleaseEvent(ev); + } + } template <class T> inline void CondWaitEvent(T& cond, deviceEvent* ev) { @@ -94,7 +104,12 @@ class GPUChain inline void RecordMarker(deviceEvent* ev, int stream) { mRec->RecordMarker(ev, stream); } virtual inline std::unique_ptr<GPUReconstruction::GPUThreadContext> GetThreadContext() { return mRec->GetThreadContext(); } inline void SynchronizeGPU() { mRec->SynchronizeGPU(); } - inline void ReleaseEvent(deviceEvent* ev) { mRec->ReleaseEvent(ev); } + inline void ReleaseEvent(deviceEvent* ev, bool doGPU = true) + { + if (doGPU) { + mRec->ReleaseEvent(ev); + } + } inline void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) { mRec->StreamWaitForEvents(stream, evList, nEvents); } template <class T> void RunHelperThreads(T function, GPUReconstructionHelpers::helperDelegateBase* functionCls, int count); @@ -127,9 +142,9 @@ class GPUChain mRec->AllocateIOMemoryHelper<T>(n, ptr, u); } template <class T, class S> - inline void DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type) + inline unsigned int DumpData(FILE* fp, const T* const* entries, const S* num, InOutPointerType type) { - mRec->DumpData<T>(fp, entries, num, type); + return mRec->DumpData<T>(fp, entries, num, type); } template <class T, class S> inline size_t ReadData(FILE* fp, const T** entries, S* num, std::unique_ptr<T[]>* mem, InOutPointerType type, T** nonConstPtrs = nullptr) diff --git a/GPU/GPUTracking/Global/GPUChainITS.cxx b/GPU/GPUTracking/Global/GPUChainITS.cxx index c828884b69328..c1818df0335ce 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.cxx +++ b/GPU/GPUTracking/Global/GPUChainITS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -70,13 +71,13 @@ int GPUChainITS::Finalize() { return 0; } int GPUChainITS::RunChain() { return 0; } -int GPUChainITS::PrepareAndRunITSTrackFit(std::vector<Road>& roads, std::array<const Cluster*, 7> clusters, std::array<const Cell*, 5> cells, const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) +int GPUChainITS::PrepareAndRunITSTrackFit(std::vector<o2::its::Road>& roads, std::vector<const o2::its::Cluster*>& clusters, std::vector<const o2::its::Cell*>& cells, const std::vector<std::vector<o2::its::TrackingFrameInfo>>& tf, std::vector<o2::its::TrackITSExt>& tracks) { mRec->PrepareEvent(); return RunITSTrackFit(roads, clusters, cells, tf, tracks); } -int GPUChainITS::RunITSTrackFit(std::vector<Road>& roads, std::array<const Cluster*, 7> clusters, std::array<const Cell*, 5> cells, const std::array<std::vector<TrackingFrameInfo>, 7>& tf, std::vector<TrackITSExt>& tracks) +int GPUChainITS::RunITSTrackFit(std::vector<o2::its::Road>& roads, std::vector<const o2::its::Cluster*>& clusters, std::vector<const o2::its::Cell*>& cells, const std::vector<std::vector<o2::its::TrackingFrameInfo>>& tf, std::vector<o2::its::TrackITSExt>& tracks) { auto threadContext = GetThreadContext(); bool doGPU = GetRecoStepsGPU() & RecoStep::ITSTracking; @@ -85,7 +86,7 @@ int GPUChainITS::RunITSTrackFit(std::vector<Road>& roads, std::array<const Clust Fitter.clearMemory(); Fitter.SetNumberOfRoads(roads.size()); - for (int i = 0; i < 7; i++) { + for (unsigned int i = 0; i < clusters.size(); i++) { Fitter.SetNumberTF(i, tf[i].size()); } Fitter.SetMaxData(processors()->ioPtrs); @@ -93,7 +94,7 @@ int GPUChainITS::RunITSTrackFit(std::vector<Road>& roads, std::array<const Clust std::copy(cells.begin(), cells.end(), Fitter.cells()); SetupGPUProcessor(&Fitter, true); std::copy(roads.begin(), roads.end(), Fitter.roads()); - for (int i = 0; i < 7; i++) { + for (unsigned int i = 0; i < clusters.size(); i++) { std::copy(tf[i].begin(), tf[i].end(), Fitter.trackingFrame()[i]); } diff --git a/GPU/GPUTracking/Global/GPUChainITS.h b/GPU/GPUTracking/Global/GPUChainITS.h index f9583aee00042..63478f8c80ddf 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.h +++ b/GPU/GPUTracking/Global/GPUChainITS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,10 +18,10 @@ #include "GPUChain.h" namespace o2::its { -class Cluster; +struct Cluster; class Road; class Cell; -class TrackingFrameInfo; +struct TrackingFrameInfo; class TrackITSExt; } // namespace o2::its @@ -40,8 +41,8 @@ class GPUChainITS : public GPUChain int RunChain() override; void MemorySize(size_t& gpuMem, size_t& pageLockedHostMem) override; - int PrepareAndRunITSTrackFit(std::vector<o2::its::Road>& roads, std::array<const o2::its::Cluster*, 7> clusters, std::array<const o2::its::Cell*, 5> cells, const std::array<std::vector<o2::its::TrackingFrameInfo>, 7>& tf, std::vector<o2::its::TrackITSExt>& tracks); - int RunITSTrackFit(std::vector<o2::its::Road>& roads, std::array<const o2::its::Cluster*, 7> clusters, std::array<const o2::its::Cell*, 5> cells, const std::array<std::vector<o2::its::TrackingFrameInfo>, 7>& tf, std::vector<o2::its::TrackITSExt>& tracks); + int PrepareAndRunITSTrackFit(std::vector<o2::its::Road>& roads, std::vector<const o2::its::Cluster*>& clusters, std::vector<const o2::its::Cell*>& cells, const std::vector<std::vector<o2::its::TrackingFrameInfo>>& tf, std::vector<o2::its::TrackITSExt>& tracks); + int RunITSTrackFit(std::vector<o2::its::Road>& roads, std::vector<const o2::its::Cluster*>& clusters, std::vector<const o2::its::Cell*>& cells, const std::vector<std::vector<o2::its::TrackingFrameInfo>>& tf, std::vector<o2::its::TrackITSExt>& tracks); o2::its::TrackerTraits* GetITSTrackerTraits(); o2::its::VertexerTraits* GetITSVertexerTraits(); diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 96839d6841f54..205171b11ea6e 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,21 +12,14 @@ /// \file GPUChainTracking.cxx /// \author David Rohr -#ifdef GPUCA_O2_LIB -#include "CommonDataFormat/InteractionRecord.h" -#endif -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" #endif -#ifndef GPUCA_NO_VC -#include <Vc/Vc> -#endif #include <fstream> -#include <mutex> -#include <condition_variable> #include "GPUChainTracking.h" +#include "GPUChainTrackingDefs.h" #include "GPUTPCClusterData.h" #include "GPUTPCSliceOutput.h" #include "GPUTPCSliceOutCluster.h" @@ -43,19 +37,13 @@ #include "GPUDisplay.h" #include "GPUQA.h" #include "GPULogging.h" -#include "GPUReconstructionConvert.h" #include "GPUMemorySizeScalers.h" #include "GPUTrackingInputProvider.h" -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "GPUTPCClusterStatistics.h" -#include "DataFormatsTPC/ZeroSuppression.h" -#include "GPURawData.h" -#include "DetectorsRaw/RDHUtils.h" #include "GPUHostDataTypes.h" -#include "DataFormatsTPC/Digit.h" #include "TPCdEdxCalibrationSplines.h" -#include "TPCClusterDecompressor.h" #include "GPUTPCCFChainContext.h" #include "GPUTrackingRefit.h" #else @@ -65,26 +53,13 @@ #include "TPCFastTransform.h" #include "utils/linux_helpers.h" +#include "utils/strtag.h" using namespace GPUCA_NAMESPACE::gpu; #include "GPUO2DataTypes.h" using namespace o2::tpc; using namespace o2::trd; -using namespace o2::tpc::constants; - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -struct GPUChainTrackingFinalContext { - GPUReconstruction* rec = nullptr; - std::mutex mutex; - std::condition_variable cond; - bool ready = false; -}; -} // namespace gpu -} // namespace GPUCA_NAMESPACE GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, unsigned int maxTPCHits, unsigned int maxTRDTracklets) : GPUChain(rec), mIOPtrs(processors()->ioPtrs), mInputsHost(new GPUTrackingInputProvider), mInputsShadow(new GPUTrackingInputProvider), mClusterNativeAccess(new ClusterNativeAccess), mMaxTPCHits(maxTPCHits), mMaxTRDTracklets(maxTRDTracklets), mDebugFile(new std::ofstream) { @@ -111,9 +86,10 @@ void GPUChainTracking::RegisterPermanentMemoryAndProcessors() mRec->RegisterGPUProcessor(&processors()->tpcMerger, GetRecoStepsGPU() & RecoStep::TPCMerging); } if (GetRecoSteps() & RecoStep::TRDTracking) { - mRec->RegisterGPUProcessor(&processors()->trdTracker, GetRecoStepsGPU() & RecoStep::TRDTracking); + mRec->RegisterGPUProcessor(&processors()->trdTrackerGPU, GetRecoStepsGPU() & RecoStep::TRDTracking); + mRec->RegisterGPUProcessor(&processors()->trdTrackerO2, GetRecoStepsGPU() & RecoStep::TRDTracking); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (GetRecoSteps() & RecoStep::TPCConversion) { mRec->RegisterGPUProcessor(&processors()->tpcConverter, GetRecoStepsGPU() & RecoStep::TPCConversion); } @@ -125,6 +101,9 @@ void GPUChainTracking::RegisterPermanentMemoryAndProcessors() mRec->RegisterGPUProcessor(&processors()->tpcClusterer[i], GetRecoStepsGPU() & RecoStep::TPCClusterFinding); } } + if (GetRecoSteps() & RecoStep::Refit) { + mRec->RegisterGPUProcessor(&processors()->trackingRefit, GetRecoStepsGPU() & RecoStep::Refit); + } #endif #ifdef GPUCA_KERNEL_DEBUGGER_OUTPUT mRec->RegisterGPUProcessor(&processors()->debugOutput, true); @@ -137,7 +116,8 @@ void GPUChainTracking::RegisterGPUProcessors() if (mRec->IsGPU()) { mRec->RegisterGPUDeviceProcessor(mInputsShadow.get(), mInputsHost.get()); } - memcpy((void*)&processorsShadow()->trdTracker, (const void*)&processors()->trdTracker, sizeof(processors()->trdTracker)); + memcpy((void*)&processorsShadow()->trdTrackerGPU, (const void*)&processors()->trdTrackerGPU, sizeof(processors()->trdTrackerGPU)); + memcpy((void*)&processorsShadow()->trdTrackerO2, (const void*)&processors()->trdTrackerO2, sizeof(processors()->trdTrackerO2)); if (GetRecoStepsGPU() & RecoStep::TPCSliceTracking) { for (unsigned int i = 0; i < NSLICES; i++) { mRec->RegisterGPUDeviceProcessor(&processorsShadow()->tpcTrackers[i], &processors()->tpcTrackers[i]); @@ -147,10 +127,11 @@ void GPUChainTracking::RegisterGPUProcessors() mRec->RegisterGPUDeviceProcessor(&processorsShadow()->tpcMerger, &processors()->tpcMerger); } if (GetRecoStepsGPU() & RecoStep::TRDTracking) { - mRec->RegisterGPUDeviceProcessor(&processorsShadow()->trdTracker, &processors()->trdTracker); + mRec->RegisterGPUDeviceProcessor(&processorsShadow()->trdTrackerGPU, &processors()->trdTrackerGPU); + mRec->RegisterGPUDeviceProcessor(&processorsShadow()->trdTrackerO2, &processors()->trdTrackerO2); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (GetRecoStepsGPU() & RecoStep::TPCConversion) { mRec->RegisterGPUDeviceProcessor(&processorsShadow()->tpcConverter, &processors()->tpcConverter); } @@ -162,6 +143,9 @@ void GPUChainTracking::RegisterGPUProcessors() mRec->RegisterGPUDeviceProcessor(&processorsShadow()->tpcClusterer[i], &processors()->tpcClusterer[i]); } } + if (GetRecoStepsGPU() & RecoStep::Refit) { + mRec->RegisterGPUDeviceProcessor(&processorsShadow()->trackingRefit, &processors()->trackingRefit); + } #endif #ifdef GPUCA_KERNEL_DEBUGGER_OUTPUT mRec->RegisterGPUDeviceProcessor(&processorsShadow()->debugOutput, &processors()->debugOutput); @@ -189,19 +173,19 @@ bool GPUChainTracking::ValidateSteps() GPUError("Invalid Reconstruction Step Setting: Tracking without early transform requires TPC Conversion to be active"); return false; } - if (((GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) || (GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging)) && !(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion)) { - GPUError("Invalid GPU Reconstruction Step Setting: Tracking without early transform requires TPC Conversion to be active"); - return false; - } } if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && !(GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCRaw)) { GPUError("Invalid input, TPC Clusterizer needs TPC raw input"); return false; } - if (param().rec.mergerReadFromTrackerDirectly && (GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && ((GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCConversion))) { + if (param().rec.tpc.mergerReadFromTrackerDirectly && (GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && ((GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCConversion))) { GPUError("Invalid input / output / step, mergerReadFromTrackerDirectly cannot read/store sectors tracks and needs TPC conversion"); return false; } + if (!GetProcessingSettings().fullMergerOnGPU && (param().rec.tpc.mergerReadFromTrackerDirectly || GetProcessingSettings().createO2Output) && (GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging)) { + GPUError("createO2Output and mergerReadFromTrackerDirectly works only in combination with fullMergerOnGPU if the merger is to run on GPU"); + return false; + } bool tpcClustersAvail = (GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCClusters) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCDecompression); #ifndef GPUCA_ALIROOT_LIB if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && !tpcClustersAvail) { @@ -255,28 +239,32 @@ bool GPUChainTracking::ValidateSteps() GPUError("Cannot run dE/dx without calibration splines"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcCalibration == nullptr) { + if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcPadGain == nullptr) { GPUError("Cannot run gain calibration without calibration object"); return false; } + if ((GetRecoSteps() & GPUDataTypes::RecoStep::Refit) && !param().rec.trackingRefitGPUModel && (processors()->calibObjects.o2Propagator == nullptr || processors()->calibObjects.matLUT == nullptr)) { + GPUError("Cannot run refit with o2 track model without o2 propagator"); + return false; + } return true; } bool GPUChainTracking::ValidateSettings() { - if ((param().rec.NWays & 1) == 0) { + if ((param().rec.tpc.nWays & 1) == 0) { GPUError("nWay setting musst be odd number!"); return false; } - if (param().rec.mergerInterpolateErrors && param().rec.NWays == 1) { + if (param().rec.tpc.mergerInterpolateErrors && param().rec.tpc.nWays == 1) { GPUError("Cannot do error interpolation with NWays = 1!"); return false; } - if ((param().rec.mergerReadFromTrackerDirectly || !param().par.earlyTpcTransform) && param().rec.NonConsecutiveIDs) { + if ((param().rec.tpc.mergerReadFromTrackerDirectly || !param().par.earlyTpcTransform) && param().rec.nonConsecutiveIDs) { GPUError("incompatible settings for non consecutive ids"); return false; } - if (!param().rec.mergerReadFromTrackerDirectly && GetProcessingSettings().ompKernels) { + if (!param().rec.tpc.mergerReadFromTrackerDirectly && GetProcessingSettings().ompKernels) { GPUError("OMP Kernels require mergerReadFromTrackerDirectly"); return false; } @@ -288,12 +276,19 @@ bool GPUChainTracking::ValidateSettings() GPUError("NStreams must be > nTPCClustererLanes"); return false; } + if (GetProcessingSettings().noGPUMemoryRegistration && GetProcessingSettings().tpcCompressionGatherMode != 3) { + GPUError("noGPUMemoryRegistration only possible with gather mode 3"); + return false; + } if (GetProcessingSettings().doublePipeline) { if (!GetRecoStepsOutputs().isOnlySet(GPUDataTypes::InOutType::TPCMergedTracks, GPUDataTypes::InOutType::TPCCompressedClusters, GPUDataTypes::InOutType::TPCClusters)) { GPUError("Invalid outputs for double pipeline mode 0x%x", (unsigned int)GetRecoStepsOutputs()); return false; } - if (((GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCCompressedClusters) && mOutputCompressedClusters == nullptr) || (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCClusters) && mOutputClustersNative == nullptr) || (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCMergedTracks) && mOutputTPCTracks == nullptr))) { + if (((GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCCompressedClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)] == nullptr) || + (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)] == nullptr) || + (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCMergedTracks) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)] == nullptr) || + (GetProcessingSettings().outputSharedClusterMap && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::sharedClusterMap)] == nullptr))) { GPUError("Must use external output for double pipeline mode"); return false; } @@ -306,7 +301,7 @@ bool GPUChainTracking::ValidateSettings() return false; } } - if (!(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && (ProcessingSettings().tpcCompressionGatherMode == 1 || ProcessingSettings().tpcCompressionGatherMode == 3)) { + if ((GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && !(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && (ProcessingSettings().tpcCompressionGatherMode == 1 || ProcessingSettings().tpcCompressionGatherMode == 3)) { GPUError("Invalid tpcCompressionGatherMode for compression on CPU"); return false; } @@ -332,14 +327,10 @@ int GPUChainTracking::Init() return 1; } - if (mOutputCompressedClusters == nullptr) { - mOutputCompressedClusters = &mRec->OutputControl(); - } - if (mOutputClustersNative == nullptr) { - mOutputClustersNative = &mRec->OutputControl(); - } - if (mOutputTPCTracks == nullptr) { - mOutputTPCTracks = &mRec->OutputControl(); + for (unsigned int i = 0; i < mSubOutputControls.size(); i++) { + if (mSubOutputControls[i] == nullptr) { + mSubOutputControls[i] = &mRec->OutputControl(); + } } if (!ValidateSettings()) { @@ -364,7 +355,7 @@ int GPUChainTracking::Init() mFlatObjectsShadow.mCalibObjects.fastTransform->setActualBufferAddress(mFlatObjectsShadow.mTpcTransformBuffer); mFlatObjectsShadow.mCalibObjects.fastTransform->setFutureBufferAddress(mFlatObjectsDevice.mTpcTransformBuffer); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (processors()->calibObjects.dEdxSplines) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.dEdxSplines, (const void*)processors()->calibObjects.dEdxSplines, sizeof(*processors()->calibObjects.dEdxSplines)); memcpy((void*)mFlatObjectsShadow.mdEdxSplinesBuffer, (const void*)processors()->calibObjects.dEdxSplines->getFlatBufferPtr(), processors()->calibObjects.dEdxSplines->getFlatBufferSize()); @@ -383,11 +374,18 @@ int GPUChainTracking::Init() memcpy((void*)mFlatObjectsShadow.mCalibObjects.trdGeometry, (const void*)processors()->calibObjects.trdGeometry, sizeof(*processors()->calibObjects.trdGeometry)); mFlatObjectsShadow.mCalibObjects.trdGeometry->clearInternalBufferPtr(); } - if (processors()->calibObjects.tpcCalibration) { - memcpy((void*)mFlatObjectsShadow.mCalibObjects.tpcCalibration, (const void*)processors()->calibObjects.tpcCalibration, sizeof(*processors()->calibObjects.tpcCalibration)); + if (processors()->calibObjects.tpcPadGain) { + memcpy((void*)mFlatObjectsShadow.mCalibObjects.tpcPadGain, (const void*)processors()->calibObjects.tpcPadGain, sizeof(*processors()->calibObjects.tpcPadGain)); + } + if (processors()->calibObjects.o2Propagator) { + memcpy((void*)mFlatObjectsShadow.mCalibObjects.o2Propagator, (const void*)processors()->calibObjects.o2Propagator, sizeof(*processors()->calibObjects.o2Propagator)); + mFlatObjectsShadow.mCalibObjects.o2Propagator->setGPUField(&processorsDevice()->param.polynomialField); + mFlatObjectsShadow.mCalibObjects.o2Propagator->setBz(param().polynomialField.GetNominalBz()); + mFlatObjectsShadow.mCalibObjects.o2Propagator->setMatLUT(mFlatObjectsShadow.mCalibObjects.matLUT); } #endif TransferMemoryResourceLinkToGPU(RecoStep::NoRecoStep, mFlatObjectsShadow.mMemoryResFlat); + memcpy((void*)&processorsShadow()->calibObjects, (void*)&mFlatObjectsDevice.mCalibObjects, sizeof(mFlatObjectsDevice.mCalibObjects)); WriteToConstantMemory(RecoStep::NoRecoStep, (char*)&processors()->calibObjects - (char*)processors(), &mFlatObjectsDevice.mCalibObjects, sizeof(mFlatObjectsDevice.mCalibObjects), -1); // First initialization, for users not using RunChain processorsShadow()->errorCodes.setMemory(mInputsShadow->mErrorCodes); WriteToConstantMemory(RecoStep::NoRecoStep, (char*)&processors()->errorCodes - (char*)processors(), &processorsShadow()->errorCodes, sizeof(processorsShadow()->errorCodes), -1); @@ -416,7 +414,13 @@ int GPUChainTracking::PrepareEvent() int GPUChainTracking::ForceInitQA() { - return mQA->InitQA(); + if (!mQA) { + mQA.reset(new GPUQA(this)); + } + if (!mQA->IsInitialized()) { + return mQA->InitQA(); + } + return 0; } int GPUChainTracking::Finalize() @@ -439,10 +443,10 @@ void* GPUChainTracking::GPUTrackingFlatObjects::SetPointersFlatObjects(void* mem computePointerWithAlignment(mem, mCalibObjects.fastTransform, 1); computePointerWithAlignment(mem, mTpcTransformBuffer, mChainTracking->GetTPCTransform()->getFlatBufferSize()); } - if (mChainTracking->GetTPCCalibration()) { - computePointerWithAlignment(mem, mCalibObjects.tpcCalibration, 1); + if (mChainTracking->GetTPCPadGainCalib()) { + computePointerWithAlignment(mem, mCalibObjects.tpcPadGain, 1); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (mChainTracking->GetdEdxSplines()) { computePointerWithAlignment(mem, mCalibObjects.dEdxSplines, 1); computePointerWithAlignment(mem, mdEdxSplinesBuffer, mChainTracking->GetdEdxSplines()->getFlatBufferSize()); @@ -454,7 +458,9 @@ void* GPUChainTracking::GPUTrackingFlatObjects::SetPointersFlatObjects(void* mem if (mChainTracking->GetTRDGeometry()) { computePointerWithAlignment(mem, mCalibObjects.trdGeometry, 1); } - + if (mChainTracking->GetO2Propagator()) { + computePointerWithAlignment(mem, mCalibObjects.o2Propagator, 1); + } #endif return mem; } @@ -480,125 +486,16 @@ void GPUChainTracking::AllocateIOMemory() mIOPtrs.clustersNative = mIOMem.clusterNativeAccess->nClustersTotal ? mIOMem.clusterNativeAccess.get() : nullptr; AllocateIOMemoryHelper(mIOPtrs.nMCLabelsTPC, mIOPtrs.mcLabelsTPC, mIOMem.mcLabelsTPC); AllocateIOMemoryHelper(mIOPtrs.nMCInfosTPC, mIOPtrs.mcInfosTPC, mIOMem.mcInfosTPC); + AllocateIOMemoryHelper(mIOPtrs.nMCInfosTPCCol, mIOPtrs.mcInfosTPCCol, mIOMem.mcInfosTPCCol); AllocateIOMemoryHelper(mIOPtrs.nMergedTracks, mIOPtrs.mergedTracks, mIOMem.mergedTracks); AllocateIOMemoryHelper(mIOPtrs.nMergedTrackHits, mIOPtrs.mergedTrackHits, mIOMem.mergedTrackHits); AllocateIOMemoryHelper(mIOPtrs.nMergedTrackHits, mIOPtrs.mergedTrackHitsXYZ, mIOMem.mergedTrackHitsXYZ); AllocateIOMemoryHelper(mIOPtrs.nTRDTracks, mIOPtrs.trdTracks, mIOMem.trdTracks); AllocateIOMemoryHelper(mIOPtrs.nTRDTracklets, mIOPtrs.trdTracklets, mIOMem.trdTracklets); - AllocateIOMemoryHelper(mIOPtrs.nTRDTrackletsMC, mIOPtrs.trdTrackletsMC, mIOMem.trdTrackletsMC); -} - -int GPUChainTracking::ConvertNativeToClusterData() -{ -#ifdef HAVE_O2HEADERS - mRec->PushNonPersistentMemory(); - const auto& threadContext = GetThreadContext(); - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCConversion; - GPUTPCConvert& convert = processors()->tpcConverter; - GPUTPCConvert& convertShadow = doGPU ? processorsShadow()->tpcConverter : convert; - - SetupGPUProcessor(&convert, true); - if (doGPU) { - if (!(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { - mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mIOPtrs.clustersNative->nClustersTotal; - AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); - processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; - WriteToConstantMemory(RecoStep::TPCConversion, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); - *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; - mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; - mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); - GPUMemCpy(RecoStep::TPCConversion, mInputsShadow->mPclusterNativeBuffer, mIOPtrs.clustersNative->clustersLinear, sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * mIOPtrs.clustersNative->nClustersTotal, 0, true); - TransferMemoryResourceLinkToGPU(RecoStep::TPCConversion, mInputsHost->mResourceClusterNativeAccess, 0); - } - } - if (!param().par.earlyTpcTransform) { - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Early transform inactive, skipping TPC Early transformation kernel, transformed on the fly during slice data creation / refit"); - } - return 0; - } - for (unsigned int i = 0; i < NSLICES; i++) { - convert.mMemory->clusters[i] = convertShadow.mClusters + mIOPtrs.clustersNative->clusterOffset[i][0]; - } - - WriteToConstantMemory(RecoStep::TPCConversion, (char*)&processors()->tpcConverter - (char*)processors(), &convertShadow, sizeof(convertShadow), 0); - TransferMemoryResourcesToGPU(RecoStep::TPCConversion, &convert, 0); - runKernel<GPUTPCConvertKernel>(GetGridBlk(NSLICES * GPUCA_ROW_COUNT, 0), krnlRunRangeNone, krnlEventNone); - TransferMemoryResourcesToHost(RecoStep::TPCConversion, &convert, 0); - SynchronizeStream(0); - - for (unsigned int i = 0; i < NSLICES; i++) { - mIOPtrs.nClusterData[i] = (i == NSLICES - 1 ? mIOPtrs.clustersNative->nClustersTotal : mIOPtrs.clustersNative->clusterOffset[i + 1][0]) - mIOPtrs.clustersNative->clusterOffset[i][0]; - mIOPtrs.clusterData[i] = convert.mClusters + mIOPtrs.clustersNative->clusterOffset[i][0]; - } - mRec->PopNonPersistentMemory(RecoStep::TPCConversion); -#endif - return 0; -} - -void GPUChainTracking::ConvertNativeToClusterDataLegacy() -{ - ClusterNativeAccess* tmp = mIOMem.clusterNativeAccess.get(); - if (tmp != mIOPtrs.clustersNative) { - *tmp = *mIOPtrs.clustersNative; - } - GPUReconstructionConvert::ConvertNativeToClusterData(mIOMem.clusterNativeAccess.get(), mIOMem.clusterData, mIOPtrs.nClusterData, processors()->calibObjects.fastTransform, param().par.continuousMaxTimeBin); - for (unsigned int i = 0; i < NSLICES; i++) { - mIOPtrs.clusterData[i] = mIOMem.clusterData[i].get(); - if (GetProcessingSettings().registerStandaloneInputMemory) { - if (mRec->registerMemoryForGPU(mIOMem.clusterData[i].get(), mIOPtrs.nClusterData[i] * sizeof(*mIOPtrs.clusterData[i]))) { - throw std::runtime_error("Error registering memory for GPU"); - } - } - } - mIOPtrs.clustersNative = nullptr; - mIOMem.clustersNative.reset(nullptr); -} - -void GPUChainTracking::ConvertRun2RawToNative() -{ - GPUReconstructionConvert::ConvertRun2RawToNative(*mIOMem.clusterNativeAccess, mIOMem.clustersNative, mIOPtrs.rawClusters, mIOPtrs.nRawClusters); - for (unsigned int i = 0; i < NSLICES; i++) { - mIOPtrs.rawClusters[i] = nullptr; - mIOPtrs.nRawClusters[i] = 0; - mIOMem.rawClusters[i].reset(nullptr); - mIOPtrs.clusterData[i] = nullptr; - mIOPtrs.nClusterData[i] = 0; - mIOMem.clusterData[i].reset(nullptr); - } - mIOPtrs.clustersNative = mIOMem.clusterNativeAccess.get(); - if (GetProcessingSettings().registerStandaloneInputMemory) { - if (mRec->registerMemoryForGPU(mIOMem.clustersNative.get(), mIOMem.clusterNativeAccess->nClustersTotal * sizeof(*mIOMem.clusterNativeAccess->clustersLinear))) { - throw std::runtime_error("Error registering memory for GPU"); - } - } -} - -void GPUChainTracking::ConvertZSEncoder(bool zs12bit) -{ -#ifdef HAVE_O2HEADERS - mIOMem.tpcZSmeta2.reset(new GPUTrackingInOutZS::GPUTrackingInOutZSMeta); - mIOMem.tpcZSmeta.reset(new GPUTrackingInOutZS); - GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit>(*mIOPtrs.tpcPackedDigits, &mIOMem.tpcZSpages, &mIOMem.tpcZSmeta2->n[0][0], nullptr, nullptr, param(), zs12bit, true); - GPUReconstructionConvert::RunZSEncoderCreateMeta(mIOMem.tpcZSpages.get(), &mIOMem.tpcZSmeta2->n[0][0], &mIOMem.tpcZSmeta2->ptr[0][0], mIOMem.tpcZSmeta.get()); - mIOPtrs.tpcZS = mIOMem.tpcZSmeta.get(); - if (GetProcessingSettings().registerStandaloneInputMemory) { - for (unsigned int i = 0; i < NSLICES; i++) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[i].count[j]; k++) { - if (mRec->registerMemoryForGPU(mIOPtrs.tpcZS->slice[i].zsPtr[j][k], mIOPtrs.tpcZS->slice[i].nZSPtr[j][k] * TPCZSHDR::TPC_ZS_PAGE_SIZE)) { - throw std::runtime_error("Error registering memory for GPU"); - } - } - } - } - } -#endif -} - -void GPUChainTracking::ConvertZSFilter(bool zs12bit) -{ - GPUReconstructionConvert::RunZSFilter(mIOMem.tpcDigits, mIOPtrs.tpcPackedDigits->tpcDigits, mIOMem.digitMap->nTPCDigits, mIOPtrs.tpcPackedDigits->nTPCDigits, param(), zs12bit, param().rec.tpcZSthreshold); + AllocateIOMemoryHelper(mIOPtrs.nTRDTracklets, mIOPtrs.trdSpacePoints, mIOMem.trdSpacePoints); + AllocateIOMemoryHelper(mIOPtrs.nTRDTriggerRecords, mIOPtrs.trdTrigRecMask, mIOMem.trdTrigRecMask); + AllocateIOMemoryHelper(mIOPtrs.nTRDTriggerRecords, mIOPtrs.trdTriggerTimes, mIOMem.trdTriggerTimes); + AllocateIOMemoryHelper(mIOPtrs.nTRDTriggerRecords, mIOPtrs.trdTrackletIdxFirst, mIOMem.trdTrackletIdxFirst); } void GPUChainTracking::LoadClusterErrors() { param().LoadClusterErrors(); } @@ -627,1953 +524,199 @@ void GPUChainTracking::SetTRDGeometry(std::unique_ptr<o2::trd::GeometryFlat>&& g processors()->calibObjects.trdGeometry = mTRDGeometryU.get(); } -int GPUChainTracking::ReadEvent(unsigned int iSlice, int threadId) +int GPUChainTracking::RunChain() { - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("Running ReadEvent for slice %d on thread %d\n", iSlice, threadId); + if (GetProcessingSettings().ompAutoNThreads && !mRec->IsGPU()) { + mRec->SetNOMPThreads(-1); } - runKernel<GPUTPCCreateSliceData>({GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU)}, {iSlice}); - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("Finished ReadEvent for slice %d on thread %d\n", iSlice, threadId); - } - return (0); -} - -void GPUChainTracking::WriteOutput(int iSlice, int threadId) -{ - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("Running WriteOutput for slice %d on thread %d\n", iSlice, threadId); + const auto threadContext = GetThreadContext(); + if (GetProcessingSettings().runCompressionStatistics && mCompressionStatistics == nullptr) { + mCompressionStatistics.reset(new GPUTPCClusterStatistics); } - if (GetProcessingSettings().nDeviceHelperThreads) { - while (mLockAtomic.test_and_set(std::memory_order_acquire)) { - ; + const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && (mIOPtrs.nMCInfosTPC || GetProcessingSettings().runMC))); + if (needQA && mQA->IsInitialized() == false) { + if (mQA->InitQA(GetProcessingSettings().runQA ? -GetProcessingSettings().runQA : -1)) { + return 1; } } - processors()->tpcTrackers[iSlice].WriteOutputPrepare(); - if (GetProcessingSettings().nDeviceHelperThreads) { - mLockAtomic.clear(); + if (GetProcessingSettings().debugLevel >= 6) { + *mDebugFile << "\n\nProcessing event " << mRec->getNEventsProcessed() << std::endl; } - processors()->tpcTrackers[iSlice].WriteOutput(); - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("Finished WriteOutput for slice %d on thread %d\n", iSlice, threadId); + if (mRec->slavesExist() && mRec->IsGPU()) { + WriteToConstantMemory(RecoStep::NoRecoStep, (char*)&processors()->calibObjects - (char*)processors(), &mFlatObjectsDevice.mCalibObjects, sizeof(mFlatObjectsDevice.mCalibObjects), 0); // Reinitialize } -} -int GPUChainTracking::ForwardTPCDigits() -{ -#ifdef HAVE_O2HEADERS - if (GetRecoStepsGPU() & RecoStep::TPCClusterFinding) { - throw std::runtime_error("Cannot forward TPC digits with Clusterizer on GPU"); - } - std::vector<ClusterNative> tmp[NSLICES][GPUCA_ROW_COUNT]; - unsigned int nTotal = 0; - const float zsThreshold = param().rec.tpcZSthreshold; - for (int i = 0; i < NSLICES; i++) { - for (unsigned int j = 0; j < mIOPtrs.tpcPackedDigits->nTPCDigits[i]; j++) { - const auto& d = mIOPtrs.tpcPackedDigits->tpcDigits[i][j]; - if (d.getChargeFloat() >= zsThreshold) { - ClusterNative c; - c.setTimeFlags(d.getTimeStamp(), 0); - c.setPad(d.getPad()); - c.setSigmaTime(1); - c.setSigmaPad(1); - c.qTot = c.qMax = d.getChargeFloat(); - tmp[i][d.getRow()].emplace_back(c); - nTotal++; - } - } + mRec->getGeneralStepTimer(GeneralStep::Prepare).Start(); + try { + mRec->PrepareEvent(); + } catch (const std::bad_alloc& e) { + GPUError("Memory Allocation Error"); + return (1); } - mIOMem.clustersNative.reset(new ClusterNative[nTotal]); - nTotal = 0; - mClusterNativeAccess->clustersLinear = mIOMem.clustersNative.get(); - for (int i = 0; i < NSLICES; i++) { - for (int j = 0; j < GPUCA_ROW_COUNT; j++) { - mClusterNativeAccess->nClusters[i][j] = tmp[i][j].size(); - memcpy(&mIOMem.clustersNative[nTotal], tmp[i][j].data(), tmp[i][j].size() * sizeof(*mClusterNativeAccess->clustersLinear)); - nTotal += tmp[i][j].size(); + mRec->getGeneralStepTimer(GeneralStep::Prepare).Stop(); + + PrepareDebugOutput(); + + SynchronizeStream(0); // Synchronize all init copies that might be ongoing + + if (mIOPtrs.tpcCompressedClusters) { + if (runRecoStep(RecoStep::TPCDecompression, &GPUChainTracking::RunTPCDecompression)) { + return 1; + } + } else if (mIOPtrs.tpcPackedDigits || mIOPtrs.tpcZS) { + if (runRecoStep(RecoStep::TPCClusterFinding, &GPUChainTracking::RunTPCClusterizer, false)) { + return 1; } } - mClusterNativeAccess->setOffsetPtrs(); - mIOPtrs.tpcPackedDigits = nullptr; - mIOPtrs.clustersNative = mClusterNativeAccess.get(); - GPUInfo("Forwarded %u TPC clusters", nTotal); - mRec->MemoryScalers()->nTPCHits = nTotal; -#endif - return 0; -} -int GPUChainTracking::GlobalTracking(unsigned int iSlice, int threadId, bool synchronizeOutput) -{ - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("GPU Tracker running Global Tracking for slice %u on thread %d\n", iSlice, threadId); + if (GetProcessingSettings().ompAutoNThreads && !mRec->IsGPU() && mIOPtrs.clustersNative) { + mRec->SetNOMPThreads(mIOPtrs.clustersNative->nClustersTotal / 5000); } - GPUReconstruction::krnlDeviceType deviceType = GetProcessingSettings().fullMergerOnGPU ? GPUReconstruction::krnlDeviceType::Auto : GPUReconstruction::krnlDeviceType::CPU; - runKernel<GPUTPCGlobalTracking>(GetGridBlk(256, iSlice % mRec->NStreams(), deviceType), {iSlice}); - if (GetProcessingSettings().fullMergerOnGPU) { - TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[iSlice].MemoryResCommon(), iSlice % mRec->NStreams()); + if (mIOPtrs.clustersNative && runRecoStep(RecoStep::TPCConversion, &GPUChainTracking::ConvertNativeToClusterData)) { + return 1; } - if (synchronizeOutput) { - SynchronizeStream(iSlice % mRec->NStreams()); + + mRec->PushNonPersistentMemory(qStr2Tag("TPCSLCD1")); // 1st stack level for TPC tracking slice data + mTPCSliceScratchOnStack = true; + if (runRecoStep(RecoStep::TPCSliceTracking, &GPUChainTracking::RunTPCTrackingSlices)) { + return 1; } - if (GetProcessingSettings().debugLevel >= 5) { - GPUInfo("GPU Tracker finished Global Tracking for slice %u on thread %d\n", iSlice, threadId); + for (unsigned int i = 0; i < NSLICES; i++) { + // GPUInfo("slice %d clusters %d tracks %d", i, mClusterData[i].NumberOfClusters(), processors()->tpcTrackers[i].Output()->NTracks()); + processors()->tpcMerger.SetSliceData(i, param().rec.tpc.mergerReadFromTrackerDirectly ? nullptr : processors()->tpcTrackers[i].Output()); + } + if (runRecoStep(RecoStep::TPCMerging, &GPUChainTracking::RunTPCTrackingMerger, false)) { + return 1; + } + if (mTPCSliceScratchOnStack) { + mRec->PopNonPersistentMemory(RecoStep::TPCSliceTracking, qStr2Tag("TPCSLCD1")); // Release 1st stack level, TPC slice data not needed after merger + mTPCSliceScratchOnStack = false; } - return (0); -} -#ifdef GPUCA_TPC_GEOMETRY_O2 -std::pair<unsigned int, unsigned int> GPUChainTracking::TPCClusterizerDecodeZSCountUpdate(unsigned int iSlice, const CfFragment& fragment) -{ - bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder::ZSOffset* o = processors()->tpcClusterer[iSlice].mPzsOffsets; - unsigned int digits = 0; - unsigned short pages = 0; - for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - unsigned short posInEndpoint = 0; - unsigned short pagesEndpoint = 0; - clusterer.mMinMaxCN[j] = mCFContext->fragmentData[fragment.index].minMaxCN[iSlice][j]; - if (doGPU) { - for (unsigned int k = clusterer.mMinMaxCN[j].minC; k < clusterer.mMinMaxCN[j].maxC; k++) { - const unsigned int minL = (k == clusterer.mMinMaxCN[j].minC) ? clusterer.mMinMaxCN[j].minN : 0; - const unsigned int maxL = (k + 1 == clusterer.mMinMaxCN[j].maxC) ? clusterer.mMinMaxCN[j].maxN : mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; - for (unsigned int l = minL; l < maxL; l++) { - unsigned short pageDigits = mCFContext->fragmentData[fragment.index].pageDigits[iSlice][j][posInEndpoint++]; - if (pageDigits) { - *(o++) = GPUTPCClusterFinder::ZSOffset{digits, j, pagesEndpoint}; - digits += pageDigits; - } - pagesEndpoint++; + if (mIOPtrs.clustersNative) { + if (GetProcessingSettings().doublePipeline) { + GPUChainTracking* foreignChain = (GPUChainTracking*)GetNextChainInQueue(); + if (foreignChain && foreignChain->mIOPtrs.tpcZS) { + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Preempting tpcZS input of foreign chain"); } + mPipelineFinalizationCtx.reset(new GPUChainTrackingFinalContext); + mPipelineFinalizationCtx->rec = this->mRec; + foreignChain->mPipelineNotifyCtx = mPipelineFinalizationCtx.get(); } - pages += pagesEndpoint; - } else { - clusterer.mPzsOffsets[j] = GPUTPCClusterFinder::ZSOffset{digits, j, 0}; - digits += mCFContext->fragmentData[fragment.index].nDigits[iSlice][j]; - pages += mCFContext->fragmentData[fragment.index].nPages[iSlice][j]; } - } - - return {digits, pages}; -} - -std::pair<unsigned int, unsigned int> GPUChainTracking::TPCClusterizerDecodeZSCount(unsigned int iSlice, const CfFragment& fragment) -{ - mRec->getGeneralStepTimer(GeneralStep::Prepare).Start(); - unsigned int nDigits = 0; - unsigned int nPages = 0; - bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; - int firstHBF = o2::raw::RDHUtils::getHeartBeatOrbit(*(const RAWDataHeaderGPU*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]); - - for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - for (unsigned int k = 0; k < mCFContext->nFragments; k++) { - mCFContext->fragmentData[k].minMaxCN[iSlice][j].maxC = mIOPtrs.tpcZS->slice[iSlice].count[j]; - mCFContext->fragmentData[k].minMaxCN[iSlice][j].minC = mCFContext->fragmentData[k].minMaxCN[iSlice][j].maxC; - mCFContext->fragmentData[k].minMaxCN[iSlice][j].maxN = mIOPtrs.tpcZS->slice[iSlice].count[j] ? mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][mIOPtrs.tpcZS->slice[iSlice].count[j] - 1] : 0; - mCFContext->fragmentData[k].minMaxCN[iSlice][j].minN = mCFContext->fragmentData[k].minMaxCN[iSlice][j].maxN; + if (runRecoStep(RecoStep::TPCCompression, &GPUChainTracking::RunTPCCompression)) { + return 1; } + } -#ifndef GPUCA_NO_VC - if (GetProcessingSettings().prefetchTPCpageScan >= 3 && j < GPUTrackingInOutZS::NENDPOINTS - 1) { - for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j + 1]; k++) { - for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j + 1][k]; l++) { - Vc::Common::prefetchMid(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j + 1][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); - Vc::Common::prefetchMid(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j + 1][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(RAWDataHeaderGPU)); - } - } - } -#endif + if (runRecoStep(RecoStep::TRDTracking, &GPUChainTracking::RunTRDTracking)) { + return 1; + } - bool firstNextFound = false; - CfFragment f = fragment; - CfFragment fNext = f.next(); - bool firstSegment = true; + if (runRecoStep(RecoStep::Refit, &GPUChainTracking::RunRefit)) { + return 1; + } - for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j]; k++) { - for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; l++) { - if (f.isEnd()) { - GPUError("Time bin passed last fragment"); - return {0, 0}; - } -#ifndef GPUCA_NO_VC - if (GetProcessingSettings().prefetchTPCpageScan >= 2 && l + 1 < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]) { - Vc::Common::prefetchForOneRead(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + (l + 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE); - Vc::Common::prefetchForOneRead(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + (l + 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(RAWDataHeaderGPU)); - } -#endif - const unsigned char* const page = ((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE; - const RAWDataHeaderGPU* rdh = (const RAWDataHeaderGPU*)page; - if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(RAWDataHeaderGPU)) { - nPages++; - if (mCFContext->fragmentData[f.index].nPages[iSlice][j]) { - mCFContext->fragmentData[f.index].nPages[iSlice][j]++; - mCFContext->fragmentData[f.index].pageDigits[iSlice][j].emplace_back(0); - } - continue; - } - const TPCZSHDR* const hdr = (const TPCZSHDR*)(page + sizeof(RAWDataHeaderGPU)); - unsigned int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; - for (unsigned int m = 0; m < 2; m++) { - CfFragment& fm = m ? fNext : f; - if (timeBin + hdr->nTimeBins >= (unsigned int)fm.first() && timeBin < (unsigned int)fm.last() && !fm.isEnd()) { - mCFContext->fragmentData[fm.index].nPages[iSlice][j]++; - mCFContext->fragmentData[fm.index].nDigits[iSlice][j] += hdr->nADCsamples; - if (doGPU) { - mCFContext->fragmentData[fm.index].pageDigits[iSlice][j].emplace_back(hdr->nADCsamples); - } - } - } - if (firstSegment && timeBin + hdr->nTimeBins >= (unsigned int)f.first()) { - mCFContext->fragmentData[f.index].minMaxCN[iSlice][j].minC = k; - mCFContext->fragmentData[f.index].minMaxCN[iSlice][j].minN = l; - firstSegment = false; - } - if (!firstNextFound && timeBin + hdr->nTimeBins >= (unsigned int)fNext.first() && !fNext.isEnd()) { - mCFContext->fragmentData[fNext.index].minMaxCN[iSlice][j].minC = k; - mCFContext->fragmentData[fNext.index].minMaxCN[iSlice][j].minN = l; - firstNextFound = true; - } - while (!f.isEnd() && timeBin >= (unsigned int)f.last()) { - if (!firstNextFound && !fNext.isEnd()) { - mCFContext->fragmentData[fNext.index].minMaxCN[iSlice][j].minC = k; - mCFContext->fragmentData[fNext.index].minMaxCN[iSlice][j].minN = l; - } - mCFContext->fragmentData[f.index].minMaxCN[iSlice][j].maxC = k + 1; - mCFContext->fragmentData[f.index].minMaxCN[iSlice][j].maxN = l; - f = fNext; - fNext = f.next(); - firstNextFound = false; - } - if (timeBin + hdr->nTimeBins > mCFContext->tpcMaxTimeBin) { - mCFContext->tpcMaxTimeBin = timeBin + hdr->nTimeBins; - } + if (!GetProcessingSettings().doublePipeline) { // Synchronize with output copies running asynchronously + SynchronizeStream(mRec->NStreams() - 2); + } - nPages++; - nDigits += hdr->nADCsamples; - } - } + if (GetProcessingSettings().ompAutoNThreads && !mRec->IsGPU()) { + mRec->SetNOMPThreads(-1); } - mCFContext->nPagesTotal += nPages; - mCFContext->nPagesSector[iSlice] = nPages; - mCFContext->nPagesSectorMax = std::max(mCFContext->nPagesSectorMax, nPages); - - unsigned int digitsFragment = 0; - for (unsigned int i = 0; i < mCFContext->nFragments; i++) { - unsigned int pages = 0; - unsigned int digits = 0; - for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - pages += mCFContext->fragmentData[i].nPages[iSlice][j]; - digits += mCFContext->fragmentData[i].nDigits[iSlice][j]; - } - mCFContext->nPagesFragmentMax = std::max(mCFContext->nPagesSectorMax, pages); - digitsFragment = std::max(digitsFragment, digits); + + if (CheckErrorCodes()) { + return 3; } - mRec->getGeneralStepTimer(GeneralStep::Prepare).Stop(); - return {nDigits, digitsFragment}; + + return GetProcessingSettings().doublePipeline ? 0 : RunChainFinalize(); } -void GPUChainTracking::RunTPCClusterizer_compactPeaks(GPUTPCClusterFinder& clusterer, GPUTPCClusterFinder& clustererShadow, int stage, bool doGPU, int lane) +int GPUChainTracking::RunChainFinalize() { - auto& in = stage ? clustererShadow.mPpeakPositions : clustererShadow.mPpositions; - auto& out = stage ? clustererShadow.mPfilteredPeakPositions : clustererShadow.mPpeakPositions; - if (doGPU) { - const unsigned int iSlice = clusterer.mISlice; - auto& count = stage ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; - - std::vector<size_t> counts; - - unsigned int nSteps = clusterer.getNSteps(count); - if (nSteps > clusterer.mNBufs) { - GPUError("Clusterer buffers exceeded (%u > %u)", nSteps, (int)clusterer.mNBufs); - exit(1); - } +#ifdef GPUCA_HAVE_O2HEADERS + if (mIOPtrs.clustersNative && (GetRecoSteps() & RecoStep::TPCCompression) && GetProcessingSettings().runCompressionStatistics) { + CompressedClusters c = *mIOPtrs.tpcCompressedClusters; + mCompressionStatistics->RunStatistics(mIOPtrs.clustersNative, &c, param()); + } +#endif - size_t tmpCount = count; - if (nSteps > 1) { - for (unsigned int i = 1; i < nSteps; i++) { - counts.push_back(tmpCount); - if (i == 1) { - runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanStart>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, stage); - } else { - runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanUp>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, tmpCount); - } - tmpCount = (tmpCount + clusterer.mScanWorkGroupSize - 1) / clusterer.mScanWorkGroupSize; - } + const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && mIOPtrs.nMCInfosTPC)); + if (needQA) { + mRec->getGeneralStepTimer(GeneralStep::QA).Start(); + mQA->RunQA(!GetProcessingSettings().runQA); + mRec->getGeneralStepTimer(GeneralStep::QA).Stop(); + } - runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanTop>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, nSteps, tmpCount); + if (GetProcessingSettings().showOutputStat) { + PrintOutputStat(); + } + + PrintDebugOutput(); + + //PrintMemoryRelations(); - for (unsigned int i = nSteps - 1; i > 1; i--) { - tmpCount = counts[i - 1]; - runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanDown>(GetGrid(tmpCount - clusterer.mScanWorkGroupSize, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, clusterer.mScanWorkGroupSize, tmpCount); + if (GetProcessingSettings().eventDisplay) { + if (!mDisplayRunning) { + if (mEventDisplay->StartDisplay()) { + return (1); } + mDisplayRunning = true; + } else { + mEventDisplay->ShowNextEvent(); } - runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::compactDigits>(GetGrid(count, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, 1, stage, in, out); - } else { - auto& nOut = stage ? clusterer.mPmemory->counters.nClusters : clusterer.mPmemory->counters.nPeaks; - auto& nIn = stage ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; - size_t count = 0; - for (size_t i = 0; i < nIn; i++) { - if (clusterer.mPisPeak[i]) { - out[count++] = in[i]; + if (GetProcessingSettings().eventDisplay->EnableSendKey()) { + while (kbhit()) { + getch(); } + GPUInfo("Press key for next event!"); } - nOut = count; - } -} -std::pair<unsigned int, unsigned int> GPUChainTracking::RunTPCClusterizer_transferZS(int iSlice, const CfFragment& fragment, int lane) -{ - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCClusterFinding; - const auto& retVal = TPCClusterizerDecodeZSCountUpdate(iSlice, fragment); - if (doGPU) { - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - unsigned int nPagesSector = 0; - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - unsigned int nPages = 0; - mInputsHost->mPzsMeta->slice[iSlice].zsPtr[j] = &mInputsShadow->mPzsPtrs[iSlice * GPUTrackingInOutZS::NENDPOINTS + j]; - mInputsHost->mPzsPtrs[iSlice * GPUTrackingInOutZS::NENDPOINTS + j] = clustererShadow.mPzs + (nPagesSector + nPages) * TPCZSHDR::TPC_ZS_PAGE_SIZE; - for (unsigned int k = clusterer.mMinMaxCN[j].minC; k < clusterer.mMinMaxCN[j].maxC; k++) { - const unsigned int min = (k == clusterer.mMinMaxCN[j].minC) ? clusterer.mMinMaxCN[j].minN : 0; - const unsigned int max = (k + 1 == clusterer.mMinMaxCN[j].maxC) ? clusterer.mMinMaxCN[j].maxN : mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; - if (max > min) { - char* src = (char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k] + min * TPCZSHDR::TPC_ZS_PAGE_SIZE; - size_t size = o2::raw::RDHUtils::getMemorySize(*(const RAWDataHeaderGPU*)src); - size = (max - min - 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE + (size ? TPCZSHDR::TPC_ZS_PAGE_SIZE : size); - GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPzs + (nPagesSector + nPages) * TPCZSHDR::TPC_ZS_PAGE_SIZE, src, size, lane, true); + int iKey; + do { + Sleep(10); + if (GetProcessingSettings().eventDisplay->EnableSendKey()) { + iKey = kbhit() ? getch() : 0; + if (iKey == 'q') { + GetProcessingSettings().eventDisplay->mDisplayControl = 2; + } else if (iKey == 'n') { + break; + } else if (iKey) { + while (GetProcessingSettings().eventDisplay->mSendKey != 0) { + Sleep(1); + } + GetProcessingSettings().eventDisplay->mSendKey = iKey; } - nPages += max - min; } - mInputsHost->mPzsMeta->slice[iSlice].nZSPtr[j] = &mInputsShadow->mPzsSizes[iSlice * GPUTrackingInOutZS::NENDPOINTS + j]; - mInputsHost->mPzsSizes[iSlice * GPUTrackingInOutZS::NENDPOINTS + j] = nPages; - mInputsHost->mPzsMeta->slice[iSlice].count[j] = 1; - nPagesSector += nPages; + } while (GetProcessingSettings().eventDisplay->mDisplayControl == 0); + if (GetProcessingSettings().eventDisplay->mDisplayControl == 2) { + mDisplayRunning = false; + GetProcessingSettings().eventDisplay->DisplayExit(); + ProcessingSettings().eventDisplay = nullptr; + return (2); } - GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPzsOffsets, clusterer.mPzsOffsets, clusterer.mNMaxPages * sizeof(*clusterer.mPzsOffsets), lane, true); + GetProcessingSettings().eventDisplay->mDisplayControl = 0; + GPUInfo("Loading next event"); + + mEventDisplay->WaitForNextEvent(); } - return retVal; + + return 0; } -int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) +int GPUChainTracking::FinalizePipelinedProcessing() { - if (restorePointers) { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - processors()->tpcClusterer[iSlice].mPzsOffsets = mCFContext->ptrSave[iSlice].zsOffsetHost; - processorsShadow()->tpcClusterer[iSlice].mPzsOffsets = mCFContext->ptrSave[iSlice].zsOffsetDevice; - processorsShadow()->tpcClusterer[iSlice].mPzs = mCFContext->ptrSave[iSlice].zsDevice; + if (mPipelineFinalizationCtx) { + { + std::unique_lock<std::mutex> lock(mPipelineFinalizationCtx->mutex); + auto* ctx = mPipelineFinalizationCtx.get(); + mPipelineFinalizationCtx->cond.wait(lock, [ctx]() { return ctx->ready; }); } - processorsShadow()->ioPtrs.clustersNative = mCFContext->ptrClusterNativeSave; - return 0; - } - const auto& threadContext = GetThreadContext(); - mRec->MemoryScalers()->nTPCdigits = 0; - if (mCFContext == nullptr) { - mCFContext.reset(new GPUTPCCFChainContext); - } - mCFContext->tpcMaxTimeBin = std::max<int>(param().par.continuousMaxTimeBin, TPC_MAX_FRAGMENT_LEN); - const CfFragment fragmentMax{(tpccf::TPCTime)mCFContext->tpcMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN}; - mCFContext->prepare(mIOPtrs.tpcZS, fragmentMax); - if (mIOPtrs.tpcZS) { - unsigned int nDigitsFragment[NSLICES]; - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (mIOPtrs.tpcZS->slice[iSlice].count[0] == 0) { - GPUError("No ZS data present, must contain at least empty HBF"); - return 1; - } - const void* rdh = mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]; - if (o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>() != o2::raw::RDHUtils::getVersion(rdh)) { - GPUError("Data has invalid RDH version %d, %d required\n", o2::raw::RDHUtils::getVersion(rdh), o2::raw::RDHUtils::getVersion<o2::gpu::RAWDataHeaderGPU>()); - return 1; - } -#ifndef GPUCA_NO_VC - if (GetProcessingSettings().prefetchTPCpageScan >= 1 && iSlice < NSLICES - 1) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j]; k++) { - for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; l++) { - Vc::Common::prefetchFar(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice + 1].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); - Vc::Common::prefetchFar(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice + 1].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(RAWDataHeaderGPU)); - } - } - } - } -#endif - const auto& x = TPCClusterizerDecodeZSCount(iSlice, fragmentMax); - nDigitsFragment[iSlice] = x.second; - processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits = x.first; - mRec->MemoryScalers()->nTPCdigits += x.first; - } - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - processors()->tpcClusterer[iSlice].SetNMaxDigits(processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits, mCFContext->nPagesFragmentMax, nDigitsFragment[iSlice]); - if (mRec->IsGPU()) { - processorsShadow()->tpcClusterer[iSlice].SetNMaxDigits(processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits, mCFContext->nPagesFragmentMax, nDigitsFragment[iSlice]); - } - if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { - mPipelineNotifyCtx->rec->AllocateRegisteredForeignMemory(processors()->tpcClusterer[iSlice].mZSOffsetId, mRec); - mPipelineNotifyCtx->rec->AllocateRegisteredForeignMemory(processors()->tpcClusterer[iSlice].mZSId, mRec); - } else { - AllocateRegisteredMemory(processors()->tpcClusterer[iSlice].mZSOffsetId); - AllocateRegisteredMemory(processors()->tpcClusterer[iSlice].mZSId); - } - } - } else { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - unsigned int nDigits = mIOPtrs.tpcPackedDigits->nTPCDigits[iSlice]; - mRec->MemoryScalers()->nTPCdigits += nDigits; - processors()->tpcClusterer[iSlice].SetNMaxDigits(nDigits, mCFContext->nPagesFragmentMax, nDigits); - } - } - if (mIOPtrs.tpcZS) { - GPUInfo("Event has %u 8kb TPC ZS pages, %lld digits", mCFContext->nPagesTotal, (long long int)mRec->MemoryScalers()->nTPCdigits); - } else { - GPUInfo("Event has %lld TPC Digits", (long long int)mRec->MemoryScalers()->nTPCdigits); - } - mCFContext->fragmentFirst = CfFragment{std::max<int>(mCFContext->tpcMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN), TPC_MAX_FRAGMENT_LEN}; - for (int iSlice = 0; iSlice < GetProcessingSettings().nTPCClustererLanes && iSlice < NSLICES; iSlice++) { - if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { - mCFContext->nextPos[iSlice] = RunTPCClusterizer_transferZS(iSlice, mCFContext->fragmentFirst, GetProcessingSettings().nTPCClustererLanes + iSlice); - } - } - - if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - mCFContext->ptrSave[iSlice].zsOffsetHost = processors()->tpcClusterer[iSlice].mPzsOffsets; - mCFContext->ptrSave[iSlice].zsOffsetDevice = processorsShadow()->tpcClusterer[iSlice].mPzsOffsets; - mCFContext->ptrSave[iSlice].zsDevice = processorsShadow()->tpcClusterer[iSlice].mPzs; - } - } - return 0; -} -#endif - -int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) -{ - if (param().rec.fwdTPCDigitsAsClusters) { - return ForwardTPCDigits(); - } -#ifdef GPUCA_TPC_GEOMETRY_O2 - mRec->PushNonPersistentMemory(); - const auto& threadContext = GetThreadContext(); - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCClusterFinding; - if (RunTPCClusterizer_prepare(mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer)) { - return 1; - } - - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - processors()->tpcClusterer[iSlice].SetMaxData(mIOPtrs); // First iteration to set data sizes - } - mRec->ComputeReuseMax(nullptr); // Resolve maximums for shared buffers - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - SetupGPUProcessor(&processors()->tpcClusterer[iSlice], true); // Now we allocate - } - if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { - RunTPCClusterizer_prepare(true); // Restore some pointers, allocated by the other pipeline, and set to 0 by SetupGPUProcessor (since not allocated in this pipeline) - } - - if (doGPU && mIOPtrs.tpcZS) { - processorsShadow()->ioPtrs.tpcZS = mInputsShadow->mPzsMeta; - WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), mRec->NStreams() - 1); - } - if (doGPU) { - WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)processors()->tpcClusterer - (char*)processors(), processorsShadow()->tpcClusterer, sizeof(GPUTPCClusterFinder) * NSLICES, mRec->NStreams() - 1, &mEvents->init); - } - - size_t nClsTotal = 0; - ClusterNativeAccess* tmpNative = mClusterNativeAccess.get(); - - // setup MC Labels - bool propagateMCLabels = GetProcessingSettings().runMC && processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC != nullptr; - - auto* digitsMC = propagateMCLabels ? processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC : nullptr; - - if (param().par.continuousMaxTimeBin > 0 && mCFContext->tpcMaxTimeBin >= (unsigned int)std::max(param().par.continuousMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN)) { - GPUError("Input data has invalid time bin\n"); - return 1; - } - bool buildNativeGPU = (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression); - bool buildNativeHost = mRec->GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCClusters; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output - mRec->MemoryScalers()->nTPCHits = mRec->MemoryScalers()->NTPCClusters(mRec->MemoryScalers()->nTPCdigits); - mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mRec->MemoryScalers()->nTPCHits; - if (buildNativeGPU) { - AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); - } - if (buildNativeHost && !(buildNativeGPU && GetProcessingSettings().delayedOutput)) { - AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mOutputClustersNative); - } - - GPUTPCLinearLabels mcLinearLabels; - if (propagateMCLabels) { - // No need to overallocate here, nTPCHits is anyway an upper bound used for the GPU cluster buffer, and we can always enlarge the buffer anyway - mcLinearLabels.header.reserve(mRec->MemoryScalers()->nTPCHits / 2); - mcLinearLabels.data.reserve(mRec->MemoryScalers()->nTPCHits); - } - - char transferRunning[NSLICES] = {0}; - unsigned int outputQueueStart = mOutputQueue.size(); - - for (unsigned int iSliceBase = 0; iSliceBase < NSLICES; iSliceBase += GetProcessingSettings().nTPCClustererLanes) { - std::vector<bool> laneHasData(GetProcessingSettings().nTPCClustererLanes, false); - for (CfFragment fragment = mCFContext->fragmentFirst; !fragment.isEnd(); fragment = fragment.next()) { - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Processing time bins [%d, %d) for sectors %d to %d", fragment.start, fragment.last(), iSliceBase, iSliceBase + GetProcessingSettings().nTPCClustererLanes - 1); - } - for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { - if (fragment.index != 0) { - SynchronizeStream(lane); // Don't overwrite charge map from previous iteration until cluster computation is finished - } - - unsigned int iSlice = iSliceBase + lane; - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - clusterer.mPmemory->counters.nPeaks = clusterer.mPmemory->counters.nClusters = 0; - clusterer.mPmemory->fragment = fragment; - - if (propagateMCLabels && fragment.index == 0) { - clusterer.PrepareMC(); - clusterer.mPinputLabels = digitsMC->v[iSlice]; - // TODO: Why is the number of header entries in truth container - // sometimes larger than the number of digits? - assert(clusterer.mPinputLabels->getIndexedSize() >= mIOPtrs.tpcPackedDigits->nTPCDigits[iSlice]); - } - - if (mIOPtrs.tpcPackedDigits) { - bool setDigitsOnGPU = doGPU && not mIOPtrs.tpcZS; - bool setDigitsOnHost = (not doGPU && not mIOPtrs.tpcZS) || propagateMCLabels; - auto* inDigits = mIOPtrs.tpcPackedDigits; - size_t numDigits = inDigits->nTPCDigits[iSlice]; - if (setDigitsOnGPU) { - GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPdigits, inDigits->tpcDigits[iSlice], sizeof(clustererShadow.mPdigits[0]) * numDigits, lane, true); - clusterer.mPmemory->counters.nDigits = numDigits; - } else if (setDigitsOnHost) { - clusterer.mPdigits = const_cast<o2::tpc::Digit*>(inDigits->tpcDigits[iSlice]); // TODO: Needs fixing (invalid const cast) - clusterer.mPmemory->counters.nDigits = numDigits; - } - } - - if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { - clusterer.mPmemory->counters.nPositions = mCFContext->nextPos[iSlice].first; - clusterer.mPmemory->counters.nPagesSubslice = mCFContext->nextPos[iSlice].second; - } - TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - - using ChargeMapType = decltype(*clustererShadow.mPchargeMap); - using PeakMapType = decltype(*clustererShadow.mPpeakMap); - runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPchargeMap, TPCMapMemoryLayout<ChargeMapType>::items() * sizeof(ChargeMapType)); - runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPpeakMap, TPCMapMemoryLayout<PeakMapType>::items() * sizeof(PeakMapType)); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Zeroed Charges"); - - if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { - TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, mInputsHost->mResourceZS, lane); - SynchronizeStream(GetProcessingSettings().nTPCClustererLanes + lane); - } - - SynchronizeStream(mRec->NStreams() - 1); // Wait for copying to constant memory - - if (mIOPtrs.tpcZS && !mCFContext->nPagesSector[iSlice]) { - continue; - } - - if (not mIOPtrs.tpcZS) { - runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::findFragmentStart>(GetGrid(1, lane), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); - TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - } else if (propagateMCLabels) { - runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::findFragmentStart>(GetGrid(1, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); - TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - } - - if (mIOPtrs.tpcZS) { - int firstHBF = o2::raw::RDHUtils::getHeartBeatOrbit(*(const RAWDataHeaderGPU*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]); - runKernel<GPUTPCCFDecodeZS, GPUTPCCFDecodeZS::decodeZS>(GetGridBlk(doGPU ? clusterer.mPmemory->counters.nPagesSubslice : GPUTrackingInOutZS::NENDPOINTS, lane), {iSlice}, {}, firstHBF); - TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - } - } - for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { - unsigned int iSlice = iSliceBase + lane; - SynchronizeStream(lane); - if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { - CfFragment f = fragment.next(); - int nextSlice = iSlice; - if (f.isEnd()) { - nextSlice += GetProcessingSettings().nTPCClustererLanes; - f = mCFContext->fragmentFirst; - } - if (nextSlice < NSLICES && mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { - mCFContext->nextPos[nextSlice] = RunTPCClusterizer_transferZS(nextSlice, f, GetProcessingSettings().nTPCClustererLanes + lane); - } - } - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - if (propagateMCLabels || not mIOPtrs.tpcZS) { - if (clusterer.mPmemory->counters.nPositions == 0) { - continue; - } - } - if (!mIOPtrs.tpcZS) { - runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::fillFromDigits>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); - } - if (DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpDigits, *mDebugFile)) { - clusterer.DumpChargeMap(*mDebugFile, "Charges"); - } - - if (propagateMCLabels) { - runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::fillIndexMap>(GetGrid(clusterer.mPmemory->counters.nDigitsInFragment, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); - } - - runKernel<GPUTPCCFPeakFinder>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpPeaks, *mDebugFile); - - RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 0, doGPU, lane); - TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpPeaksCompacted, *mDebugFile); - } - for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { - unsigned int iSlice = iSliceBase + lane; - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - SynchronizeStream(lane); - if (clusterer.mPmemory->counters.nPeaks == 0) { - continue; - } - runKernel<GPUTPCCFNoiseSuppression, GPUTPCCFNoiseSuppression::noiseSuppression>(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); - runKernel<GPUTPCCFNoiseSuppression, GPUTPCCFNoiseSuppression::updatePeaks>(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaks, *mDebugFile); - - RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 1, doGPU, lane); - TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaksCompacted, *mDebugFile); - } - for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { - unsigned int iSlice = iSliceBase + lane; - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - SynchronizeStream(lane); - - if (fragment.index == 0) { - runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {nullptr, transferRunning[lane] == 1 ? &mEvents->stream[lane] : nullptr}, clustererShadow.mPclusterInRow, GPUCA_ROW_COUNT * sizeof(*clustererShadow.mPclusterInRow)); - transferRunning[lane] = 2; - } - - if (clusterer.mPmemory->counters.nClusters == 0) { - continue; - } - - runKernel<GPUTPCCFDeconvolution>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Split Charges"); - - runKernel<GPUTPCCFClusterizer>(GetGrid(clusterer.mPmemory->counters.nClusters, lane), {iSlice}, {}, 0); - if (doGPU && propagateMCLabels) { - TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mScratchId, lane); - SynchronizeStream(lane); - runKernel<GPUTPCCFClusterizer>(GetGrid(clusterer.mPmemory->counters.nClusters, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, 1); - } - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Lane %d: Found clusters: digits %u peaks %u clusters %u", lane, (int)clusterer.mPmemory->counters.nPositions, (int)clusterer.mPmemory->counters.nPeaks, (int)clusterer.mPmemory->counters.nClusters); - } - - TransferMemoryResourcesToHost(RecoStep::TPCClusterFinding, &clusterer, lane); - laneHasData[lane] = true; - if (DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpCountedPeaks, *mDebugFile)) { - clusterer.DumpClusters(*mDebugFile); - } - } - } - size_t nClsFirst = nClsTotal; - bool anyLaneHasData = false; - for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { - unsigned int iSlice = iSliceBase + lane; - std::fill(&tmpNative->nClusters[iSlice][0], &tmpNative->nClusters[iSlice][0] + MAXGLOBALPADROW, 0); - SynchronizeStream(lane); - GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; - GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; - if (laneHasData[lane]) { - anyLaneHasData = true; - if (buildNativeGPU && GetProcessingSettings().tpccfGatherKernel) { - runKernel<GPUTPCCFGather>(GetGridBlk(GPUCA_ROW_COUNT, mRec->NStreams() - 1), {iSlice}, {}, &mInputsShadow->mPclusterNativeBuffer[nClsTotal]); - } - for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { - if (buildNativeGPU) { - if (!GetProcessingSettings().tpccfGatherKernel) { - GPUMemCpyAlways(RecoStep::TPCClusterFinding, (void*)&mInputsShadow->mPclusterNativeBuffer[nClsTotal], (const void*)&clustererShadow.mPclusterByRow[j * clusterer.mNMaxClusterPerRow], sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * clusterer.mPclusterInRow[j], mRec->NStreams() - 1, -2); - } - } else if (buildNativeHost) { - GPUMemCpyAlways(RecoStep::TPCClusterFinding, (void*)&mInputsHost->mPclusterNativeOutput[nClsTotal], (const void*)&clustererShadow.mPclusterByRow[j * clusterer.mNMaxClusterPerRow], sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * clusterer.mPclusterInRow[j], mRec->NStreams() - 1, false); - } - tmpNative->nClusters[iSlice][j] += clusterer.mPclusterInRow[j]; - nClsTotal += clusterer.mPclusterInRow[j]; - } - if (transferRunning[lane]) { - ReleaseEvent(&mEvents->stream[lane]); - } - RecordMarker(&mEvents->stream[lane], mRec->NStreams() - 1); - transferRunning[lane] = 1; - } - - if (not propagateMCLabels) { - continue; - } - - runKernel<GPUTPCCFMCLabelFlattener, GPUTPCCFMCLabelFlattener::setRowOffsets>(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); - GPUTPCCFMCLabelFlattener::setGlobalOffsetsAndAllocate(clusterer, mcLinearLabels); - runKernel<GPUTPCCFMCLabelFlattener, GPUTPCCFMCLabelFlattener::flatten>(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, &mcLinearLabels); - clusterer.clearMCMemory(); - } - if (buildNativeHost && buildNativeGPU && anyLaneHasData) { - if (GetProcessingSettings().delayedOutput) { - mOutputQueue.emplace_back(outputQueueEntry{(void*)((char*)&mInputsHost->mPclusterNativeOutput[nClsFirst] - (char*)&mInputsHost->mPclusterNativeOutput[0]), &mInputsShadow->mPclusterNativeBuffer[nClsFirst], (nClsTotal - nClsFirst) * sizeof(mInputsHost->mPclusterNativeOutput[nClsFirst]), RecoStep::TPCClusterFinding}); - } else { - GPUMemCpy(RecoStep::TPCClusterFinding, (void*)&mInputsHost->mPclusterNativeOutput[nClsFirst], (void*)&mInputsShadow->mPclusterNativeBuffer[nClsFirst], (nClsTotal - nClsFirst) * sizeof(mInputsHost->mPclusterNativeOutput[nClsFirst]), mRec->NStreams() - 1, false); - } - } - } - for (int i = 0; i < GetProcessingSettings().nTPCClustererLanes; i++) { - if (transferRunning[i]) { - ReleaseEvent(&mEvents->stream[i]); - } - } - - ClusterNativeAccess::ConstMCLabelContainerView* mcLabelsConstView = nullptr; - if (propagateMCLabels) { - // TODO: write to buffer directly - o2::dataformats::MCTruthContainer<o2::MCCompLabel> mcLabels; - if (mOutputClusterLabels == nullptr || !mOutputClusterLabels->OutputAllocator) { - throw std::runtime_error("Cluster MC Label buffer missing"); - } - ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer* container = reinterpret_cast<ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer*>(mOutputClusterLabels->OutputAllocator(0)); - - assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); - assert(propagateMCLabels ? mcLinearLabels.data.size() >= nClsTotal : true); - - mcLabels.setFrom(mcLinearLabels.header, mcLinearLabels.data); - mcLabels.flatten_to(container->first); - container->second = container->first; - mcLabelsConstView = &container->second; - } - - if (buildNativeHost && buildNativeGPU && GetProcessingSettings().delayedOutput) { - mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = nClsTotal; - AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mOutputClustersNative); - for (unsigned int i = outputQueueStart; i < mOutputQueue.size(); i++) { - mOutputQueue[i].dst = (char*)mInputsHost->mPclusterNativeOutput + (size_t)mOutputQueue[i].dst; - } - } - - if (buildNativeHost) { - tmpNative->clustersLinear = mInputsHost->mPclusterNativeOutput; - tmpNative->clustersMCTruth = mcLabelsConstView; - tmpNative->setOffsetPtrs(); - mIOPtrs.clustersNative = tmpNative; - } - - if (mPipelineNotifyCtx) { - SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory - std::lock_guard<std::mutex> lock(mPipelineNotifyCtx->mutex); - mPipelineNotifyCtx->ready = true; - mPipelineNotifyCtx->cond.notify_one(); - } - - if (buildNativeGPU) { - processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; - WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); - *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; - mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; - mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); - TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, mInputsHost->mResourceClusterNativeAccess, 0); - } - if (synchronizeOutput) { - SynchronizeStream(mRec->NStreams() - 1); - } - if (buildNativeHost && GetProcessingSettings().debugLevel >= 4) { - for (unsigned int i = 0; i < NSLICES; i++) { - for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { - std::sort(&mInputsHost->mPclusterNativeOutput[tmpNative->clusterOffset[i][j]], &mInputsHost->mPclusterNativeOutput[tmpNative->clusterOffset[i][j] + tmpNative->nClusters[i][j]]); - } - } - } - mRec->MemoryScalers()->nTPCHits = nClsTotal; - mRec->PopNonPersistentMemory(RecoStep::TPCClusterFinding); - if (mPipelineNotifyCtx) { - mRec->UnblockStackedMemory(); - mPipelineNotifyCtx = nullptr; - } - -#endif - return 0; -} - -int GPUChainTracking::RunTPCTrackingSlices() -{ - if (mRec->GPUStuck()) { - GPUWarning("This GPU is stuck, processing of tracking for this event is skipped!"); - return (1); - } - - const auto& threadContext = GetThreadContext(); - - int retVal = RunTPCTrackingSlices_internal(); - if (retVal) { - SynchronizeGPU(); - } - if (retVal >= 2) { - ResetHelperThreads(retVal >= 3); - } - return (retVal != 0); -} - -int GPUChainTracking::RunTPCTrackingSlices_internal() -{ - if (GetProcessingSettings().debugLevel >= 2) { - GPUInfo("Running TPC Slice Tracker"); - } - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCSliceTracking; - bool doSliceDataOnGPU = processors()->tpcTrackers[0].SliceDataOnGPU(); - if (!param().par.earlyTpcTransform) { - for (unsigned int i = 0; i < NSLICES; i++) { - processors()->tpcTrackers[i].Data().SetClusterData(nullptr, mIOPtrs.clustersNative->nClustersSector[i], mIOPtrs.clustersNative->clusterOffset[i][0]); - if (doGPU) { - processorsShadow()->tpcTrackers[i].Data().SetClusterData(nullptr, mIOPtrs.clustersNative->nClustersSector[i], mIOPtrs.clustersNative->clusterOffset[i][0]); // TODO: not needed I think, anyway copied in SetupGPUProcessor - } - } - mRec->MemoryScalers()->nTPCHits = mIOPtrs.clustersNative->nClustersTotal; - } else { - int offset = 0; - for (unsigned int i = 0; i < NSLICES; i++) { - processors()->tpcTrackers[i].Data().SetClusterData(mIOPtrs.clusterData[i], mIOPtrs.nClusterData[i], offset); -#ifdef HAVE_O2HEADERS - if (doGPU && GetRecoSteps().isSet(RecoStep::TPCConversion)) { - processorsShadow()->tpcTrackers[i].Data().SetClusterData(processorsShadow()->tpcConverter.mClusters + processors()->tpcTrackers[i].Data().ClusterIdOffset(), processors()->tpcTrackers[i].NHitsTotal(), processors()->tpcTrackers[i].Data().ClusterIdOffset()); - } -#endif - offset += mIOPtrs.nClusterData[i]; - } - mRec->MemoryScalers()->nTPCHits = offset; - } - GPUInfo("Event has %u TPC Clusters, %d TRD Tracklets", (unsigned int)mRec->MemoryScalers()->nTPCHits, mIOPtrs.nTRDTracklets); - - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - processors()->tpcTrackers[iSlice].SetMaxData(mIOPtrs); // First iteration to set data sizes - } - mRec->ComputeReuseMax(nullptr); // Resolve maximums for shared buffers - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - SetupGPUProcessor(&processors()->tpcTrackers[iSlice], false); // Prepare custom allocation for 1st stack level - mRec->AllocateRegisteredMemory(processors()->tpcTrackers[iSlice].MemoryResSliceScratch()); - mRec->AllocateRegisteredMemory(processors()->tpcTrackers[iSlice].MemoryResSliceInput()); - } - mRec->PushNonPersistentMemory(); - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - SetupGPUProcessor(&processors()->tpcTrackers[iSlice], true); // Now we allocate - mRec->ResetRegisteredMemoryPointers(&processors()->tpcTrackers[iSlice]); // TODO: The above call breaks the GPU ptrs to already allocated memory. This fixes them. Should actually be cleaned up at the source. - processors()->tpcTrackers[iSlice].SetupCommonMemory(); - } - - bool streamInit[GPUCA_MAX_STREAMS] = {false}; - if (doGPU) { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - processorsShadow()->tpcTrackers[iSlice].GPUParametersConst()->gpumem = (char*)mRec->DeviceMemoryBase(); - // Initialize Startup Constants - processors()->tpcTrackers[iSlice].GPUParameters()->nextStartHit = (((getKernelProperties<GPUTPCTrackletConstructor, GPUTPCTrackletConstructor::allSlices>().minBlocks * BlockCount()) + NSLICES - 1 - iSlice) / NSLICES) * getKernelProperties<GPUTPCTrackletConstructor, GPUTPCTrackletConstructor::allSlices>().nThreads; - processorsShadow()->tpcTrackers[iSlice].SetGPUTextureBase(mRec->DeviceMemoryBase()); - } - - if (!doSliceDataOnGPU) { - RunHelperThreads(&GPUChainTracking::HelperReadEvent, this, NSLICES); - } - if (PrepareTextures()) { - return (2); - } - - // Copy Tracker Object to GPU Memory - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Copying Tracker objects to GPU"); - } - if (PrepareProfile()) { - return 2; - } - - WriteToConstantMemory(RecoStep::TPCSliceTracking, (char*)processors()->tpcTrackers - (char*)processors(), processorsShadow()->tpcTrackers, sizeof(GPUTPCTracker) * NSLICES, mRec->NStreams() - 1, &mEvents->init); - - for (int i = 0; i < mRec->NStreams() - 1; i++) { - streamInit[i] = false; - } - streamInit[mRec->NStreams() - 1] = true; - } - if (GPUDebug("Initialization (1)", 0)) { - return (2); - } - - int streamMap[NSLICES]; - - bool error = false; - GPUCA_OPENMP(parallel for if(!(doGPU || GetProcessingSettings().ompKernels)) num_threads(GetProcessingSettings().ompThreads)) - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (mRec->GetDeviceType() == GPUReconstruction::DeviceType::HIP) { - SynchronizeGPU(); // BUG: Workaround for probable bug in AMD runtime, crashes randomly if not synchronized here - } - GPUTPCTracker& trk = processors()->tpcTrackers[iSlice]; - GPUTPCTracker& trkShadow = doGPU ? processorsShadow()->tpcTrackers[iSlice] : trk; - int useStream = (iSlice % mRec->NStreams()); - - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Creating Slice Data (Slice %d)", iSlice); - } - if (doSliceDataOnGPU) { - TransferMemoryResourcesToGPU(RecoStep::TPCSliceTracking, &trk, useStream); - runKernel<GPUTPCCreateSliceData>(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); - streamInit[useStream] = true; - } else if (!doGPU || iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) == 0) { - if (ReadEvent(iSlice, 0)) { - GPUError("Error reading event"); - error = 1; - continue; - } - } else { - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Waiting for helper thread %d", iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1); - } - while (HelperDone(iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1) < (int)iSlice) { - ; - } - if (HelperError(iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1)) { - error = 1; - continue; - } - } - if (!doGPU && trk.CheckEmptySlice() && GetProcessingSettings().debugLevel == 0) { - continue; - } - - if (GetProcessingSettings().debugLevel >= 6) { - *mDebugFile << "\n\nReconstruction: Slice " << iSlice << "/" << NSLICES << std::endl; - if (GetProcessingSettings().debugMask & 1) { - if (doSliceDataOnGPU) { - TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &trk, -1, true); - } - trk.DumpSliceData(*mDebugFile); - } - } - - // Initialize temporary memory where needed - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Copying Slice Data to GPU and initializing temporary memory"); - } - if (GetProcessingSettings().keepDisplayMemory && !doSliceDataOnGPU) { - memset((void*)trk.Data().HitWeights(), 0, trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); - } else { - runKernel<GPUMemClean16>(GetGridAutoStep(useStream, RecoStep::TPCSliceTracking), krnlRunRangeNone, {}, trkShadow.Data().HitWeights(), trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); - } - - // Copy Data to GPU Global Memory - if (!doSliceDataOnGPU) { - TransferMemoryResourcesToGPU(RecoStep::TPCSliceTracking, &trk, useStream); - } - if (GPUDebug("Initialization (3)", useStream)) { - throw std::runtime_error("memcpy failure"); - } - - runKernel<GPUTPCNeighboursFinder>(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); - streamInit[useStream] = true; - - if (GetProcessingSettings().keepDisplayMemory) { - TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &trk, -1, true); - memcpy(trk.LinkTmpMemory(), mRec->Res(trk.MemoryResLinks()).Ptr(), mRec->Res(trk.MemoryResLinks()).Size()); - if (GetProcessingSettings().debugMask & 2) { - trk.DumpLinks(*mDebugFile); - } - } - - runKernel<GPUTPCNeighboursCleaner>(GetGridBlk(GPUCA_ROW_COUNT - 2, useStream), {iSlice}); - DoDebugAndDump(RecoStep::TPCSliceTracking, 4, trk, &GPUTPCTracker::DumpLinks, *mDebugFile); - - runKernel<GPUTPCStartHitsFinder>(GetGridBlk(GPUCA_ROW_COUNT - 6, useStream), {iSlice}); -#ifdef GPUCA_SORT_STARTHITS_GPU - if (doGPU) { - runKernel<GPUTPCStartHitsSorter>(GetGridAuto(useStream), {iSlice}); - } -#endif - DoDebugAndDump(RecoStep::TPCSliceTracking, 32, trk, &GPUTPCTracker::DumpStartHits, *mDebugFile); - - if (GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { - trk.UpdateMaxData(); - AllocateRegisteredMemory(trk.MemoryResTracklets()); - AllocateRegisteredMemory(trk.MemoryResOutput()); - } - - if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletConstructorInPipeline) { - runKernel<GPUTPCTrackletConstructor>(GetGridAuto(useStream), {iSlice}); - DoDebugAndDump(RecoStep::TPCSliceTracking, 128, trk, &GPUTPCTracker::DumpTrackletHits, *mDebugFile); - if (GetProcessingSettings().debugMask & 256 && !GetProcessingSettings().comparableDebutOutput) { - trk.DumpHitWeights(*mDebugFile); - } - } - - if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletSelectorInPipeline) { - runKernel<GPUTPCTrackletSelector>(GetGridAuto(useStream), {iSlice}); - runKernel<GPUTPCGlobalTrackingCopyNumbers>({1, -ThreadCount(), useStream}, {iSlice}, {}, 1); - TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, trk.MemoryResCommon(), useStream, &mEvents->slice[iSlice]); - streamMap[iSlice] = useStream; - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Slice %u, Number of tracks: %d", iSlice, *trk.NTracks()); - } - DoDebugAndDump(RecoStep::TPCSliceTracking, 512, trk, &GPUTPCTracker::DumpTrackHits, *mDebugFile); - } - } - if (error) { - return (3); - } - - if (doGPU || GetProcessingSettings().debugLevel >= 1) { - ReleaseEvent(&mEvents->init); - if (!doSliceDataOnGPU) { - WaitForHelperThreads(); - } - - if (!GetProcessingSettings().trackletSelectorInPipeline) { - if (GetProcessingSettings().trackletConstructorInPipeline) { - SynchronizeGPU(); - } else { - for (int i = 0; i < mRec->NStreams(); i++) { - RecordMarker(&mEvents->stream[i], i); - } - runKernel<GPUTPCTrackletConstructor, 1>(GetGridAuto(0), krnlRunRangeNone, {&mEvents->single, mEvents->stream, mRec->NStreams()}); - for (int i = 0; i < mRec->NStreams(); i++) { - ReleaseEvent(&mEvents->stream[i]); - } - SynchronizeEvents(&mEvents->single); - ReleaseEvent(&mEvents->single); - } - - if (GetProcessingSettings().debugLevel >= 4) { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - DoDebugAndDump(RecoStep::TPCSliceTracking, 128, processors()->tpcTrackers[iSlice], &GPUTPCTracker::DumpTrackletHits, *mDebugFile); - } - } - - int runSlices = 0; - int useStream = 0; - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice += runSlices) { - if (runSlices < GetProcessingSettings().trackletSelectorSlices) { - runSlices++; - } - runSlices = CAMath::Min<int>(runSlices, NSLICES - iSlice); - if (getKernelProperties<GPUTPCTrackletSelector>().minBlocks * BlockCount() < (unsigned int)runSlices) { - runSlices = getKernelProperties<GPUTPCTrackletSelector>().minBlocks * BlockCount(); - } - - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Running TPC Tracklet selector (Stream %d, Slice %d to %d)", useStream, iSlice, iSlice + runSlices); - } - runKernel<GPUTPCTrackletSelector>(GetGridAuto(useStream), {iSlice, runSlices}); - runKernel<GPUTPCGlobalTrackingCopyNumbers>({1, -ThreadCount(), useStream}, {iSlice}, {}, runSlices); - for (unsigned int k = iSlice; k < iSlice + runSlices; k++) { - TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[k].MemoryResCommon(), useStream, &mEvents->slice[k]); - streamMap[k] = useStream; - } - useStream++; - if (useStream >= mRec->NStreams()) { - useStream = 0; - } - } - } - - mSliceSelectorReady = 0; - - std::array<bool, NSLICES> transferRunning; - transferRunning.fill(true); - if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (doGPU && !(GetRecoStepsGPU() & RecoStep::TPCMerging))) { - if (param().rec.GlobalTracking) { - mWriteOutputDone.fill(0); - } - RunHelperThreads(&GPUChainTracking::HelperOutput, this, NSLICES); - - unsigned int tmpSlice = 0; - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Transfering Tracks from GPU to Host"); - } - - if (tmpSlice == iSlice) { - SynchronizeEvents(&mEvents->slice[iSlice]); - } - while (tmpSlice < NSLICES && (tmpSlice == iSlice || IsEventDone(&mEvents->slice[tmpSlice]))) { - ReleaseEvent(&mEvents->slice[tmpSlice]); - if (*processors()->tpcTrackers[tmpSlice].NTracks() > 0) { - TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[tmpSlice].MemoryResOutput(), streamMap[tmpSlice], &mEvents->slice[tmpSlice]); - } else { - transferRunning[tmpSlice] = false; - } - tmpSlice++; - } - - if (GetProcessingSettings().keepAllMemory) { - TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &processors()->tpcTrackers[iSlice], -1, true); - if (!GetProcessingSettings().trackletConstructorInPipeline) { - if (GetProcessingSettings().debugMask & 256 && !GetProcessingSettings().comparableDebutOutput) { - processors()->tpcTrackers[iSlice].DumpHitWeights(*mDebugFile); - } - } - if (!GetProcessingSettings().trackletSelectorInPipeline) { - if (GetProcessingSettings().debugMask & 512) { - processors()->tpcTrackers[iSlice].DumpTrackHits(*mDebugFile); - } - } - } - - if (transferRunning[iSlice]) { - SynchronizeEvents(&mEvents->slice[iSlice]); - } - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Tracks Transfered: %d / %d", *processors()->tpcTrackers[iSlice].NTracks(), *processors()->tpcTrackers[iSlice].NTrackHits()); - } - - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Data ready for slice %d, helper thread %d", iSlice, iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1)); - } - mSliceSelectorReady = iSlice; - - if (param().rec.GlobalTracking) { - for (unsigned int tmpSlice2a = 0; tmpSlice2a <= iSlice; tmpSlice2a += GetProcessingSettings().nDeviceHelperThreads + 1) { - unsigned int tmpSlice2 = GPUTPCGlobalTracking::GlobalTrackingSliceOrder(tmpSlice2a); - unsigned int sliceLeft, sliceRight; - GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(tmpSlice2, sliceLeft, sliceRight); - - if (tmpSlice2 <= iSlice && sliceLeft <= iSlice && sliceRight <= iSlice && mWriteOutputDone[tmpSlice2] == 0) { - GlobalTracking(tmpSlice2, 0); - WriteOutput(tmpSlice2, 0); - mWriteOutputDone[tmpSlice2] = 1; - } - } - } else { - if (iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) == 0) { - WriteOutput(iSlice, 0); - } - } - } - WaitForHelperThreads(); - } - if (!(GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) && param().rec.GlobalTracking) { - std::vector<bool> blocking(NSLICES * mRec->NStreams()); - for (int i = 0; i < NSLICES; i++) { - for (int j = 0; j < mRec->NStreams(); j++) { - blocking[i * mRec->NStreams() + j] = i % mRec->NStreams() == j; - } - } - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - unsigned int tmpSlice = GPUTPCGlobalTracking::GlobalTrackingSliceOrder(iSlice); - if (!((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (doGPU && !(GetRecoStepsGPU() & RecoStep::TPCMerging)))) { - unsigned int sliceLeft, sliceRight; - GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(tmpSlice, sliceLeft, sliceRight); - if (!blocking[tmpSlice * mRec->NStreams() + sliceLeft % mRec->NStreams()]) { - StreamWaitForEvents(tmpSlice % mRec->NStreams(), &mEvents->slice[sliceLeft]); - blocking[tmpSlice * mRec->NStreams() + sliceLeft % mRec->NStreams()] = true; - } - if (!blocking[tmpSlice * mRec->NStreams() + sliceRight % mRec->NStreams()]) { - StreamWaitForEvents(tmpSlice % mRec->NStreams(), &mEvents->slice[sliceRight]); - blocking[tmpSlice * mRec->NStreams() + sliceRight % mRec->NStreams()] = true; - } - } - GlobalTracking(tmpSlice, 0, !GetProcessingSettings().fullMergerOnGPU); - } - } - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (transferRunning[iSlice]) { - ReleaseEvent(&mEvents->slice[iSlice]); - } - } - } else { - mSliceSelectorReady = NSLICES; - GPUCA_OPENMP(parallel for if(!(doGPU || GetProcessingSettings().ompKernels)) num_threads(GetProcessingSettings().ompThreads)) - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (param().rec.GlobalTracking) { - GlobalTracking(iSlice, 0); - } - if (GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) { - WriteOutput(iSlice, 0); - } - } - } - - if (param().rec.GlobalTracking && GetProcessingSettings().debugLevel >= 3) { - for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { - GPUInfo("Slice %d - Tracks: Local %d Global %d - Hits: Local %d Global %d", iSlice, - processors()->tpcTrackers[iSlice].CommonMemory()->nLocalTracks, processors()->tpcTrackers[iSlice].CommonMemory()->nTracks, processors()->tpcTrackers[iSlice].CommonMemory()->nLocalTrackHits, processors()->tpcTrackers[iSlice].CommonMemory()->nTrackHits); - } - } - - if (GetProcessingSettings().debugMask & 1024 && !GetProcessingSettings().comparableDebutOutput) { - for (unsigned int i = 0; i < NSLICES; i++) { - processors()->tpcTrackers[i].DumpOutput(*mDebugFile); - } - } - - if (DoProfile()) { - return (1); - } - for (unsigned int i = 0; i < NSLICES; i++) { - mIOPtrs.nSliceTracks[i] = *processors()->tpcTrackers[i].NTracks(); - mIOPtrs.sliceTracks[i] = processors()->tpcTrackers[i].Tracks(); - mIOPtrs.nSliceClusters[i] = *processors()->tpcTrackers[i].NTrackHits(); - mIOPtrs.sliceClusters[i] = processors()->tpcTrackers[i].TrackHits(); - if (GetProcessingSettings().keepDisplayMemory && !GetProcessingSettings().keepAllMemory) { - TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &processors()->tpcTrackers[i], -1, true); - } - } - if (GetProcessingSettings().debugLevel >= 2) { - GPUInfo("TPC Slice Tracker finished"); - } - mRec->PopNonPersistentMemory(RecoStep::TPCSliceTracking); - return 0; -} - -void GPUChainTracking::RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, char mergeMode, GPUReconstruction::krnlDeviceType deviceType) -{ - unsigned int n = withinSlice == -1 ? NSLICES / 2 : NSLICES; - bool doGPUall = GetRecoStepsGPU() & RecoStep::TPCMerging && GetProcessingSettings().fullMergerOnGPU; - if (GetProcessingSettings().alternateBorderSort && (!mRec->IsGPU() || doGPUall)) { - GPUTPCGMMerger& Merger = processors()->tpcMerger; - GPUTPCGMMerger& MergerShadow = doGPUall ? processorsShadow()->tpcMerger : Merger; - TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->init); - RecordMarker(&mEvents->single, 0); - for (unsigned int i = 0; i < n; i++) { - int stream = i % mRec->NStreams(); - runKernel<GPUTPCGMMergerMergeBorders, 0>(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, stream && i < (unsigned int)mRec->NStreams() ? &mEvents->single : nullptr}, i, withinSlice, mergeMode); - } - ReleaseEvent(&mEvents->single); - SynchronizeEvents(&mEvents->init); - ReleaseEvent(&mEvents->init); - for (unsigned int i = 0; i < n; i++) { - int stream = i % mRec->NStreams(); - int n1, n2; - GPUTPCGMBorderTrack *b1, *b2; - int jSlice; - Merger.MergeBorderTracksSetup(n1, n2, b1, b2, jSlice, i, withinSlice, mergeMode); - gputpcgmmergertypes::GPUTPCGMBorderRange* range1 = MergerShadow.BorderRange(i); - gputpcgmmergertypes::GPUTPCGMBorderRange* range2 = MergerShadow.BorderRange(jSlice) + *processors()->tpcTrackers[jSlice].NTracks(); - runKernel<GPUTPCGMMergerMergeBorders, 3>({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range1, n1, 0); - runKernel<GPUTPCGMMergerMergeBorders, 3>({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range2, n2, 1); - deviceEvent** e = nullptr; - int ne = 0; - if (i == n - 1) { // Synchronize all execution on stream 0 with the last kernel - ne = std::min<int>(n, mRec->NStreams()); - for (int j = 1; j < ne; j++) { - RecordMarker(&mEvents->slice[j], j); - } - e = &mEvents->slice[1]; - ne--; - stream = 0; - } - runKernel<GPUTPCGMMergerMergeBorders, 2>(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, e, ne}, i, withinSlice, mergeMode); - } - } else { - for (unsigned int i = 0; i < n; i++) { - runKernel<GPUTPCGMMergerMergeBorders, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); - } - runKernel<GPUTPCGMMergerMergeBorders, 1>({2 * n, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 0, withinSlice, mergeMode); - for (unsigned int i = 0; i < n; i++) { - runKernel<GPUTPCGMMergerMergeBorders, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); - } - } - mRec->ReturnVolatileDeviceMemory(); -} - -void GPUChainTracking::RunTPCTrackingMerger_Resolve(char useOrigTrackParam, char mergeAll, GPUReconstruction::krnlDeviceType deviceType) -{ - runKernel<GPUTPCGMMergerResolve, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerResolve, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerResolve, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerResolve, 3>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerResolve, 4>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, useOrigTrackParam, mergeAll); -} - -int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) -{ - if (GetProcessingSettings().debugLevel >= 6 && GetProcessingSettings().comparableDebutOutput && param().rec.mergerReadFromTrackerDirectly) { - for (unsigned int i = 0; i < NSLICES; i++) { - GPUTPCTracker& trk = processors()->tpcTrackers[i]; - TransferMemoryResourcesToHost(RecoStep::NoRecoStep, &trk); - auto sorter = [&trk](GPUTPCTrack& trk1, GPUTPCTrack& trk2) { - if (trk1.NHits() == trk2.NHits()) { - return trk1.Param().Y() > trk2.Param().Y(); - } - return trk1.NHits() > trk2.NHits(); - }; - std::sort(trk.Tracks(), trk.Tracks() + trk.CommonMemory()->nLocalTracks, sorter); - std::sort(trk.Tracks() + trk.CommonMemory()->nLocalTracks, trk.Tracks() + *trk.NTracks(), sorter); - TransferMemoryResourcesToGPU(RecoStep::NoRecoStep, &trk, 0); - } - } - mRec->PushNonPersistentMemory(); - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCMerging; - bool doGPUall = doGPU && GetProcessingSettings().fullMergerOnGPU; - GPUReconstruction::krnlDeviceType deviceType = doGPUall ? GPUReconstruction::krnlDeviceType::Auto : GPUReconstruction::krnlDeviceType::CPU; - unsigned int numBlocks = (!mRec->IsGPU() || doGPUall) ? BlockCount() : 1; - GPUTPCGMMerger& Merger = processors()->tpcMerger; - GPUTPCGMMerger& MergerShadow = doGPU ? processorsShadow()->tpcMerger : Merger; - GPUTPCGMMerger& MergerShadowAll = doGPUall ? processorsShadow()->tpcMerger : Merger; - if (GetProcessingSettings().debugLevel >= 2) { - GPUInfo("Running TPC Merger"); - } - const auto& threadContext = GetThreadContext(); - - SynchronizeGPU(); // Need to know the full number of slice tracks - SetupGPUProcessor(&Merger, true); - AllocateRegisteredMemory(Merger.MemoryResOutput(), mOutputTPCTracks); - - if (Merger.CheckSlices()) { - return 1; - } - - memset(Merger.Memory(), 0, sizeof(*Merger.Memory())); - WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); - if (doGPUall) { - TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); - } - - for (unsigned int i = 0; i < NSLICES; i++) { - runKernel<GPUTPCGMMergerUnpackResetIds>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); - runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, i); - runKernel<GPUTPCGMMergerSliceRefit>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); - } - for (unsigned int i = 0; i < NSLICES; i++) { - runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, NSLICES + i); - runKernel<GPUTPCGMMergerUnpackGlobal>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); - } - runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 2 * NSLICES); - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpSliceTracks, *mDebugFile); - - runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 0); - runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel<GPUTPCGMMergerMergeWithinPrepare>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - RunTPCTrackingMerger_MergeBorderTracks(1, 0, deviceType); - RunTPCTrackingMerger_Resolve(0, 1, deviceType); - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedWithinSlices, *mDebugFile); - - runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 0); - runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 2, 3, 0); - RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); - RunTPCTrackingMerger_Resolve(0, 1, deviceType); - runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 0); - RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); - RunTPCTrackingMerger_Resolve(0, 1, deviceType); - runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 1); - RunTPCTrackingMerger_MergeBorderTracks(0, -1, deviceType); - RunTPCTrackingMerger_Resolve(0, 1, deviceType); - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedBetweenSlices, *mDebugFile); - - runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - - runKernel<GPUTPCGMMergerLinkGlobalTracks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerCollect>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpCollected, *mDebugFile); - - runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 1); - RunTPCTrackingMerger_MergeBorderTracks(-1, 1, deviceType); - RunTPCTrackingMerger_MergeBorderTracks(-1, 2, deviceType); - runKernel<GPUTPCGMMergerMergeCE>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergeCE, *mDebugFile); - int waitForTransfer = 0; - if (doGPUall) { - TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->single); - waitForTransfer = 1; - } - - if (GetProcessingSettings().mergerSortTracks) { - runKernel<GPUTPCGMMergerSortTracksPrepare>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - CondWaitEvent(waitForTransfer, &mEvents->single); - runKernel<GPUTPCGMMergerSortTracks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - } - - unsigned int maxId = param().rec.NonConsecutiveIDs ? Merger.Memory()->nOutputTrackClusters : Merger.NMaxClusters(); - if (maxId > Merger.NMaxClusters()) { - throw std::runtime_error("mNMaxClusters too small"); - } - if (!param().rec.NonConsecutiveIDs) { - unsigned int* sharedCount = (unsigned int*)MergerShadowAll.TmpMem() + CAMath::nextMultipleOf<4>(Merger.Memory()->nOutputTracks); - runKernel<GPUMemClean16>({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, sharedCount, maxId * sizeof(*sharedCount)); - runKernel<GPUMemClean16>({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.ClusterAttachment(), maxId * sizeof(*MergerShadowAll.ClusterAttachment())); - runKernel<GPUTPCGMMergerPrepareClusters, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - CondWaitEvent(waitForTransfer, &mEvents->single); - runKernel<GPUTPCGMMergerSortTracksQPt>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerPrepareClusters, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerPrepareClusters, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - } - - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpFitPrepare, *mDebugFile); - - if (doGPUall) { - CondWaitEvent(waitForTransfer, &mEvents->single); - if (waitForTransfer) { - ReleaseEvent(&mEvents->single); - } - } else if (doGPU) { - TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); - } - - if (GetProcessingSettings().delayedOutput) { - for (unsigned int i = 0; i < mOutputQueue.size(); i++) { - GPUMemCpy(mOutputQueue[i].step, mOutputQueue[i].dst, mOutputQueue[i].src, mOutputQueue[i].size, mRec->NStreams() - 2, false); - } - mOutputQueue.clear(); - } - - runKernel<GPUTPCGMMergerTrackFit>(doGPU ? GetGrid(Merger.NOutputTracks(), 0) : GetGridAuto(0), krnlRunRangeNone, krnlEventNone, GetProcessingSettings().mergerSortTracks ? 1 : 0); - if (param().rec.retryRefit == 1) { - runKernel<GPUTPCGMMergerTrackFit>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone, -1); - } - if (param().rec.loopInterpolationInExtraPass) { - runKernel<GPUTPCGMMergerFollowLoopers>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); - } - if (doGPU && !doGPUall) { - TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, 0); - SynchronizeStream(0); - } - - DoDebugAndDump(RecoStep::TPCMerging, 0, Merger, &GPUTPCGMMerger::DumpRefit, *mDebugFile); - runKernel<GPUTPCGMMergerFinalize, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - if (!param().rec.NonConsecutiveIDs) { - runKernel<GPUTPCGMMergerFinalize, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCGMMergerFinalize, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - } - if (param().rec.tpcMergeLoopersAfterburner) { - runKernel<GPUTPCGMMergerMergeLoopers>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - } - DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpFinal, *mDebugFile); - - if (doGPUall) { - RecordMarker(&mEvents->single, 0); - if (!GetProcessingSettings().fullMergerOnGPU) { - TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutput(), mRec->NStreams() - 2, nullptr, &mEvents->single); - } else { - GPUMemCpy(RecoStep::TPCMerging, Merger.OutputTracks(), MergerShadowAll.OutputTracks(), Merger.NOutputTracks() * sizeof(*Merger.OutputTracks()), mRec->NStreams() - 2, 0, nullptr, &mEvents->single); - GPUMemCpy(RecoStep::TPCMerging, Merger.Clusters(), MergerShadowAll.Clusters(), Merger.NOutputTrackClusters() * sizeof(*Merger.Clusters()), mRec->NStreams() - 2, 0); - if (param().par.earlyTpcTransform) { - GPUMemCpy(RecoStep::TPCMerging, Merger.ClustersXYZ(), MergerShadowAll.ClustersXYZ(), Merger.NOutputTrackClusters() * sizeof(*Merger.ClustersXYZ()), mRec->NStreams() - 2, 0); - } - GPUMemCpy(RecoStep::TPCMerging, Merger.ClusterAttachment(), MergerShadowAll.ClusterAttachment(), Merger.NMaxClusters() * sizeof(*Merger.ClusterAttachment()), mRec->NStreams() - 2, 0); - } - ReleaseEvent(&mEvents->single); - if (synchronizeOutput) { - SynchronizeStream(mRec->NStreams() - 2); - } - } else { - TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); - } - if (GetProcessingSettings().keepDisplayMemory && !GetProcessingSettings().keepAllMemory) { - TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, -1, true); - } - mRec->ReturnVolatileDeviceMemory(); - - mIOPtrs.mergedTracks = Merger.OutputTracks(); - mIOPtrs.nMergedTracks = Merger.NOutputTracks(); - mIOPtrs.mergedTrackHits = Merger.Clusters(); - mIOPtrs.nMergedTrackHits = Merger.NOutputTrackClusters(); - mIOPtrs.mergedTrackHitAttachment = Merger.ClusterAttachment(); - mIOPtrs.mergedTrackHitStates = Merger.ClusterStateExt(); - - if (GetProcessingSettings().debugLevel >= 2) { - GPUInfo("TPC Merger Finished (output clusters %d / input clusters %d)", Merger.NOutputTrackClusters(), Merger.NClusters()); - } - mRec->PopNonPersistentMemory(RecoStep::TPCMerging); - return 0; -} - -int GPUChainTracking::RunTPCCompression() -{ -#ifdef HAVE_O2HEADERS - mRec->PushNonPersistentMemory(); - RecoStep myStep = RecoStep::TPCCompression; - bool doGPU = GetRecoStepsGPU() & RecoStep::TPCCompression; - GPUTPCCompression& Compressor = processors()->tpcCompressor; - GPUTPCCompression& CompressorShadow = doGPU ? processorsShadow()->tpcCompressor : Compressor; - const auto& threadContext = GetThreadContext(); - if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { - RecordMarker(&mEvents->single, 0); - } - Compressor.mNMaxClusterSliceRow = 0; - for (unsigned int i = 0; i < NSLICES; i++) { - for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { - if (mIOPtrs.clustersNative->nClusters[i][j] > Compressor.mNMaxClusterSliceRow) { - Compressor.mNMaxClusterSliceRow = mIOPtrs.clustersNative->nClusters[i][j]; - } - } - } - - if (ProcessingSettings().tpcCompressionGatherMode == 3) { - mRec->AllocateVolatileDeviceMemory(0); // make future device memory allocation volatile - } - SetupGPUProcessor(&Compressor, true); - new (Compressor.mMemory) GPUTPCCompression::memory; - - WriteToConstantMemory(myStep, (char*)&processors()->tpcCompressor - (char*)processors(), &CompressorShadow, sizeof(CompressorShadow), 0); - TransferMemoryResourcesToGPU(myStep, &Compressor, 0); - runKernel<GPUMemClean16>(GetGridAutoStep(0, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone, CompressorShadow.mClusterStatus, Compressor.mMaxClusters * sizeof(CompressorShadow.mClusterStatus[0])); - runKernel<GPUTPCCompressionKernels, GPUTPCCompressionKernels::step0attached>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); - runKernel<GPUTPCCompressionKernels, GPUTPCCompressionKernels::step1unattached>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); - TransferMemoryResourcesToHost(myStep, &Compressor, 0); -#ifdef GPUCA_TPC_GEOMETRY_O2 - if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { - SynchronizeEvents(&mEvents->single); - ReleaseEvent(&mEvents->single); - ((GPUChainTracking*)GetNextChainInQueue())->RunTPCClusterizer_prepare(false); - ((GPUChainTracking*)GetNextChainInQueue())->mCFContext->ptrClusterNativeSave = processorsShadow()->ioPtrs.clustersNative; - } -#endif - SynchronizeStream(0); - o2::tpc::CompressedClusters* O = Compressor.mOutput; - memset((void*)O, 0, sizeof(*O)); - O->nTracks = Compressor.mMemory->nStoredTracks; - O->nAttachedClusters = Compressor.mMemory->nStoredAttachedClusters; - O->nUnattachedClusters = Compressor.mMemory->nStoredUnattachedClusters; - O->nAttachedClustersReduced = O->nAttachedClusters - O->nTracks; - O->nSliceRows = NSLICES * GPUCA_ROW_COUNT; - O->nComppressionModes = param().rec.tpcCompressionModes; - size_t outputSize = AllocateRegisteredMemory(Compressor.mMemoryResOutputHost, mOutputCompressedClusters); - Compressor.mOutputFlat->set(outputSize, *Compressor.mOutput); - char* hostFlatPtr = (char*)Compressor.mOutput->qTotU; // First array as allocated in GPUTPCCompression::SetPointersCompressedClusters - size_t copySize = 0; - if (ProcessingSettings().tpcCompressionGatherMode == 3) { - CompressorShadow.mOutputA = Compressor.mOutput; - copySize = AllocateRegisteredMemory(Compressor.mMemoryResOutputGPU); // We overwrite Compressor.mOutput with the allocated output pointers on the GPU - } - const o2::tpc::CompressedClustersPtrs* P = nullptr; - HighResTimer* gatherTimer = nullptr; - int outputStream = 0; - if (ProcessingSettings().doublePipeline) { - SynchronizeStream(mRec->NStreams() - 2); // Synchronize output copies running in parallel from memory that might be released, only the following async copy from stacked memory is safe after the chain finishes. - outputStream = mRec->NStreams() - 2; - } - - if (ProcessingSettings().tpcCompressionGatherMode >= 2) { - if (ProcessingSettings().tpcCompressionGatherMode == 2) { - void* devicePtr = mRec->getGPUPointer(Compressor.mOutputFlat); - if (devicePtr != Compressor.mOutputFlat) { - CompressedClustersPtrs& ptrs = *Compressor.mOutput; // We need to update the ptrs with the gpu-mapped version of the host address space - for (unsigned int i = 0; i < sizeof(ptrs) / sizeof(void*); i++) { - reinterpret_cast<char**>(&ptrs)[i] = reinterpret_cast<char**>(&ptrs)[i] + (reinterpret_cast<char*>(devicePtr) - reinterpret_cast<char*>(Compressor.mOutputFlat)); - } - } - } - TransferMemoryResourcesToGPU(myStep, &Compressor, outputStream); - constexpr unsigned int nBlocksDefault = 2; - constexpr unsigned int nBlocksMulti = 1 + 2 * 200; - switch (ProcessingSettings().tpcCompressionGatherModeKernel) { - case 0: - runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::unbuffered>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); - getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::unbuffered>(RecoStep::TPCCompression, 0, outputSize); - break; - case 1: - runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered32>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); - getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered32>(RecoStep::TPCCompression, 0, outputSize); - break; - case 2: - runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered64>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); - getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered64>(RecoStep::TPCCompression, 0, outputSize); - break; - case 3: - runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered128>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); - getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered128>(RecoStep::TPCCompression, 0, outputSize); - break; - case 4: - - static_assert((nBlocksMulti & 1) && nBlocksMulti >= 3); - runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::multiBlock>(GetGridBlkStep(nBlocksMulti, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); - getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::multiBlock>(RecoStep::TPCCompression, 0, outputSize); - break; - default: - GPUError("Invalid compression kernel selected."); - return 1; - } - if (ProcessingSettings().tpcCompressionGatherMode == 3) { - RecordMarker(&mEvents->stream[outputStream], outputStream); - char* deviceFlatPts = (char*)Compressor.mOutput->qTotU; - if (GetProcessingSettings().doublePipeline) { - const size_t blockSize = CAMath::nextMultipleOf<1024>(copySize / 30); - const unsigned int n = (copySize + blockSize - 1) / blockSize; - for (unsigned int i = 0; i < n; i++) { - GPUMemCpy(myStep, hostFlatPtr + i * blockSize, deviceFlatPts + i * blockSize, CAMath::Min(blockSize, copySize - i * blockSize), outputStream, false); - } - } else { - GPUMemCpy(myStep, hostFlatPtr, deviceFlatPts, copySize, outputStream, false); - } - } - } else { - char direction = 0; - if (ProcessingSettings().tpcCompressionGatherMode == 0) { - P = &CompressorShadow.mPtrs; - } else if (ProcessingSettings().tpcCompressionGatherMode == 1) { - P = &Compressor.mPtrs; - direction = -1; - gatherTimer = &getTimer<GPUTPCCompressionKernels>("GPUTPCCompression_GatherOnCPU", 0); - gatherTimer->Start(); - } - GPUMemCpyAlways(myStep, O->nSliceRowClusters, P->nSliceRowClusters, NSLICES * GPUCA_ROW_COUNT * sizeof(O->nSliceRowClusters[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->nTrackClusters, P->nTrackClusters, O->nTracks * sizeof(O->nTrackClusters[0]), outputStream, direction); - SynchronizeStream(outputStream); - unsigned int offset = 0; - for (unsigned int i = 0; i < NSLICES; i++) { - for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { - GPUMemCpyAlways(myStep, O->qTotU + offset, P->qTotU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->qTotU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->qMaxU + offset, P->qMaxU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->qMaxU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->flagsU + offset, P->flagsU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->flagsU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->padDiffU + offset, P->padDiffU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->padDiffU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->timeDiffU + offset, P->timeDiffU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->timeDiffU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sigmaPadU + offset, P->sigmaPadU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->sigmaPadU[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sigmaTimeU + offset, P->sigmaTimeU + mIOPtrs.clustersNative->clusterOffset[i][j], O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->sigmaTimeU[0]), outputStream, direction); - offset += O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j]; - } - } - offset = 0; - for (unsigned int i = 0; i < O->nTracks; i++) { - GPUMemCpyAlways(myStep, O->qTotA + offset, P->qTotA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->qTotA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->qMaxA + offset, P->qMaxA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->qMaxA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->flagsA + offset, P->flagsA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->flagsA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sigmaPadA + offset, P->sigmaPadA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->sigmaPadA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sigmaTimeA + offset, P->sigmaTimeA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->sigmaTimeA[0]), outputStream, direction); - - // First index stored with track - GPUMemCpyAlways(myStep, O->rowDiffA + offset - i, P->rowDiffA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->rowDiffA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sliceLegDiffA + offset - i, P->sliceLegDiffA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->sliceLegDiffA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->padResA + offset - i, P->padResA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->padResA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->timeResA + offset - i, P->timeResA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->timeResA[0]), outputStream, direction); - offset += O->nTrackClusters[i]; - } - GPUMemCpyAlways(myStep, O->qPtA, P->qPtA, O->nTracks * sizeof(O->qPtA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->rowA, P->rowA, O->nTracks * sizeof(O->rowA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->sliceA, P->sliceA, O->nTracks * sizeof(O->sliceA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->timeA, P->timeA, O->nTracks * sizeof(O->timeA[0]), outputStream, direction); - GPUMemCpyAlways(myStep, O->padA, P->padA, O->nTracks * sizeof(O->padA[0]), outputStream, direction); - } - if (ProcessingSettings().tpcCompressionGatherMode == 1) { - gatherTimer->Stop(); - } - mIOPtrs.tpcCompressedClusters = Compressor.mOutputFlat; - if (ProcessingSettings().tpcCompressionGatherMode == 3) { - SynchronizeEvents(&mEvents->stream[outputStream]); - ReleaseEvent(&mEvents->stream[outputStream]); - mRec->ReturnVolatileDeviceMemory(); - } - - if (mPipelineFinalizationCtx == nullptr) { - SynchronizeStream(outputStream); - } else { - ((GPUChainTracking*)GetNextChainInQueue())->mRec->BlockStackedMemory(mRec); - } - mRec->PopNonPersistentMemory(RecoStep::TPCCompression); -#endif - return 0; -} - -int GPUChainTracking::RunTPCDecompression() -{ -#ifdef HAVE_O2HEADERS - const auto& threadContext = GetThreadContext(); - TPCClusterDecompressor decomp; - auto allocator = [this](size_t size) { - this->mInputsHost->mNClusterNative = this->mInputsShadow->mNClusterNative = size; - this->AllocateRegisteredMemory(this->mInputsHost->mResourceClusterNativeOutput, this->mOutputClustersNative); - return this->mInputsHost->mPclusterNativeOutput; - }; - auto& gatherTimer = getTimer<TPCClusterDecompressor>("TPCDecompression", 0); - gatherTimer.Start(); - if (decomp.decompress(mIOPtrs.tpcCompressedClusters, *mClusterNativeAccess, allocator, param())) { - GPUError("Error decompressing clusters"); - return 1; - } - gatherTimer.Stop(); - mIOPtrs.clustersNative = mClusterNativeAccess.get(); - if (mRec->IsGPU()) { - AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); - processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; - WriteToConstantMemory(RecoStep::TPCDecompression, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); - *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; - mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; - mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); - GPUMemCpy(RecoStep::TPCDecompression, mInputsShadow->mPclusterNativeBuffer, mIOPtrs.clustersNative->clustersLinear, sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * mIOPtrs.clustersNative->nClustersTotal, 0, true); - TransferMemoryResourceLinkToGPU(RecoStep::TPCDecompression, mInputsHost->mResourceClusterNativeAccess, 0); - SynchronizeStream(0); - } -#endif - return 0; -} - -int GPUChainTracking::RunTRDTracking() -{ - if (!processors()->trdTracker.IsInitialized()) { - return 1; - } - - GPUTRDTrackerGPU& Tracker = processors()->trdTracker; - Tracker.Reset(); - if (mIOPtrs.nTRDTracklets == 0) { - return 0; - } - - mRec->PushNonPersistentMemory(); - SetupGPUProcessor(&Tracker, true); - - for (unsigned int iTracklet = 0; iTracklet < mIOPtrs.nTRDTracklets; ++iTracklet) { - if (Tracker.LoadTracklet(mIOPtrs.trdTracklets[iTracklet], mIOPtrs.trdTrackletsMC ? mIOPtrs.trdTrackletsMC[iTracklet].mLabel : nullptr)) { - return 1; - } - } - - for (unsigned int i = 0; i < mIOPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack& trk = mIOPtrs.mergedTracks[i]; - if (!Tracker.PreCheckTrackTRDCandidate(trk)) { - continue; - } - const GPUTRDTrackGPU& trktrd = param().rec.NWaysOuter ? (GPUTRDTrackGPU)trk.OuterParam() : (GPUTRDTrackGPU)trk; - if (!Tracker.CheckTrackTRDCandidate(trktrd)) { - continue; - } - - if (Tracker.LoadTrack(trktrd, -1, nullptr, -1, i, false)) { - return 1; - } - } - - Tracker.DoTracking(this); - - mIOPtrs.nTRDTracks = Tracker.NTracks(); - mIOPtrs.trdTracks = Tracker.Tracks(); - mRec->PopNonPersistentMemory(RecoStep::TRDTracking); - - return 0; -} - -int GPUChainTracking::DoTRDGPUTracking() -{ -#ifdef HAVE_O2HEADERS - bool doGPU = GetRecoStepsGPU() & RecoStep::TRDTracking; - GPUTRDTrackerGPU& Tracker = processors()->trdTracker; - GPUTRDTrackerGPU& TrackerShadow = doGPU ? processorsShadow()->trdTracker : Tracker; - - const auto& threadContext = GetThreadContext(); - SetupGPUProcessor(&Tracker, false); - TrackerShadow.OverrideGPUGeometry(reinterpret_cast<GPUTRDGeometry*>(mFlatObjectsDevice.mCalibObjects.trdGeometry)); - - WriteToConstantMemory(RecoStep::TRDTracking, (char*)&processors()->trdTracker - (char*)processors(), &TrackerShadow, sizeof(TrackerShadow), 0); - TransferMemoryResourcesToGPU(RecoStep::TRDTracking, &Tracker, 0); - - runKernel<GPUTRDTrackerKernels>(GetGridAuto(0), krnlRunRangeNone); - TransferMemoryResourcesToHost(RecoStep::TRDTracking, &Tracker, 0); - SynchronizeStream(0); - - if (GetProcessingSettings().debugLevel >= 2) { - GPUInfo("GPU TRD tracker Finished"); - } -#endif - return (0); -} - -int GPUChainTracking::RunRefit() -{ -#ifdef HAVE_O2HEADERS - GPUTrackingRefit re; - re.SetPtrsFromGPUConstantMem(processorsShadow()); - re.SetPropagatorDefault(); - for (unsigned int i = 0; i < mIOPtrs.nMergedTracks; i++) { - if (mIOPtrs.mergedTracks[i].OK()) { - printf("\nRefitting track %d\n", i); - GPUTPCGMMergedTrack t = mIOPtrs.mergedTracks[i]; - int retval = re.RefitTrackAsGPU(t, false, true); - printf("Refit error code: %d\n", retval); - - printf("\nRefitting track TrackParCov %d\n", i); - t = mIOPtrs.mergedTracks[i]; - retval = re.RefitTrackAsTrackParCov(t, false, true); - printf("Refit error code: %d\n", retval); - } - } -#endif - return 0; -} - -int GPUChainTracking::RunChain() -{ - const auto threadContext = GetThreadContext(); - if (GetProcessingSettings().runCompressionStatistics && mCompressionStatistics == nullptr) { - mCompressionStatistics.reset(new GPUTPCClusterStatistics); - } - const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && mIOPtrs.nMCInfosTPC)); - if (needQA && mQA->IsInitialized() == false) { - if (mQA->InitQA()) { - return 1; - } - } - if (GetProcessingSettings().debugLevel >= 6) { - *mDebugFile << "\n\nProcessing event " << mRec->getNEventsProcessed() << std::endl; - } - if (mRec->slavesExist() && mRec->IsGPU()) { - WriteToConstantMemory(RecoStep::NoRecoStep, (char*)&processors()->calibObjects - (char*)processors(), &mFlatObjectsDevice.mCalibObjects, sizeof(mFlatObjectsDevice.mCalibObjects), 0); // Reinitialize - } - - mRec->getGeneralStepTimer(GeneralStep::Prepare).Start(); -#ifdef GPUCA_STANDALONE - mRec->PrepareEvent(); -#else - try { - mRec->PrepareEvent(); - } catch (const std::bad_alloc& e) { - GPUError("Memory Allocation Error"); - return (1); - } -#endif - mRec->getGeneralStepTimer(GeneralStep::Prepare).Stop(); - - PrepareDebugOutput(); - - SynchronizeStream(0); // Synchronize all init copies that might be ongoing - - if (mIOPtrs.tpcCompressedClusters) { - if (runRecoStep(RecoStep::TPCDecompression, &GPUChainTracking::RunTPCDecompression)) { - return 1; - } - } else if (mIOPtrs.tpcPackedDigits || mIOPtrs.tpcZS) { - if (runRecoStep(RecoStep::TPCClusterFinding, &GPUChainTracking::RunTPCClusterizer, false)) { - return 1; - } - } - - if (mIOPtrs.clustersNative && runRecoStep(RecoStep::TPCConversion, &GPUChainTracking::ConvertNativeToClusterData)) { - return 1; - } - - mRec->PushNonPersistentMemory(); // 1st stack level for TPC tracking slice data - if (runRecoStep(RecoStep::TPCSliceTracking, &GPUChainTracking::RunTPCTrackingSlices)) { - return 1; - } - - for (unsigned int i = 0; i < NSLICES; i++) { - // GPUInfo("slice %d clusters %d tracks %d", i, mClusterData[i].NumberOfClusters(), processors()->tpcTrackers[i].Output()->NTracks()); - processors()->tpcMerger.SetSliceData(i, param().rec.mergerReadFromTrackerDirectly ? nullptr : processors()->tpcTrackers[i].Output()); - } - if (runRecoStep(RecoStep::TPCMerging, &GPUChainTracking::RunTPCTrackingMerger, false)) { - return 1; - } - mRec->PopNonPersistentMemory(RecoStep::TPCSliceTracking); // Release 1st stack level, TPC slice data not needed after merger - - if (mIOPtrs.clustersNative) { - if (GetProcessingSettings().doublePipeline) { - GPUChainTracking* foreignChain = (GPUChainTracking*)GetNextChainInQueue(); - if (foreignChain && foreignChain->mIOPtrs.tpcZS) { - if (GetProcessingSettings().debugLevel >= 3) { - GPUInfo("Preempting tpcZS input of foreign chain"); - } - mPipelineFinalizationCtx.reset(new GPUChainTrackingFinalContext); - mPipelineFinalizationCtx->rec = this->mRec; - foreignChain->mPipelineNotifyCtx = mPipelineFinalizationCtx.get(); - } - } - if (runRecoStep(RecoStep::TPCCompression, &GPUChainTracking::RunTPCCompression)) { - return 1; - } - } - - if (runRecoStep(RecoStep::TRDTracking, &GPUChainTracking::RunTRDTracking)) { - return 1; - } - - if (runRecoStep(RecoStep::Refit, &GPUChainTracking::RunRefit)) { - return 1; - } - - if (!GetProcessingSettings().doublePipeline) { // Synchronize with output copies running asynchronously - SynchronizeStream(mRec->NStreams() - 2); - } - - if (CheckErrorCodes()) { - return 1; - } - - return GetProcessingSettings().doublePipeline ? 0 : RunChainFinalize(); -} - -int GPUChainTracking::RunChainFinalize() -{ -#ifdef HAVE_O2HEADERS - if (mIOPtrs.clustersNative && (GetRecoSteps() & RecoStep::TPCCompression) && GetProcessingSettings().runCompressionStatistics) { - CompressedClusters c = *mIOPtrs.tpcCompressedClusters; - mCompressionStatistics->RunStatistics(mIOPtrs.clustersNative, &c, param()); - } -#endif - - const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && mIOPtrs.nMCInfosTPC)); - if (needQA) { - mRec->getGeneralStepTimer(GeneralStep::QA).Start(); - mQA->RunQA(!GetProcessingSettings().runQA); - mRec->getGeneralStepTimer(GeneralStep::QA).Stop(); - } - - if (GetProcessingSettings().showOutputStat) { - PrintOutputStat(); - } - - PrintDebugOutput(); - - //PrintMemoryRelations(); - - if (GetProcessingSettings().eventDisplay) { - if (!mDisplayRunning) { - if (mEventDisplay->StartDisplay()) { - return (1); - } - mDisplayRunning = true; - } else { - mEventDisplay->ShowNextEvent(); - } - - if (GetProcessingSettings().eventDisplay->EnableSendKey()) { - while (kbhit()) { - getch(); - } - GPUInfo("Press key for next event!"); - } - - int iKey; - do { - Sleep(10); - if (GetProcessingSettings().eventDisplay->EnableSendKey()) { - iKey = kbhit() ? getch() : 0; - if (iKey == 'q') { - GetProcessingSettings().eventDisplay->mDisplayControl = 2; - } else if (iKey == 'n') { - break; - } else if (iKey) { - while (GetProcessingSettings().eventDisplay->mSendKey != 0) { - Sleep(1); - } - GetProcessingSettings().eventDisplay->mSendKey = iKey; - } - } - } while (GetProcessingSettings().eventDisplay->mDisplayControl == 0); - if (GetProcessingSettings().eventDisplay->mDisplayControl == 2) { - mDisplayRunning = false; - GetProcessingSettings().eventDisplay->DisplayExit(); - ProcessingSettings().eventDisplay = nullptr; - return (2); - } - GetProcessingSettings().eventDisplay->mDisplayControl = 0; - GPUInfo("Loading next event"); - - mEventDisplay->WaitForNextEvent(); - } - - return 0; -} - -int GPUChainTracking::FinalizePipelinedProcessing() -{ - if (mPipelineFinalizationCtx) { - { - std::unique_lock<std::mutex> lock(mPipelineFinalizationCtx->mutex); - auto* ctx = mPipelineFinalizationCtx.get(); - mPipelineFinalizationCtx->cond.wait(lock, [ctx]() { return ctx->ready; }); - } - mPipelineFinalizationCtx.reset(); + mPipelineFinalizationCtx.reset(); } return RunChainFinalize(); } @@ -2582,7 +725,7 @@ int GPUChainTracking::HelperReadEvent(int iSlice, int threadId, GPUReconstructio int GPUChainTracking::HelperOutput(int iSlice, int threadId, GPUReconstructionHelpers::helperParam* par) { - if (param().rec.GlobalTracking) { + if (param().rec.tpc.globalTracking) { unsigned int tmpSlice = GPUTPCGlobalTracking::GlobalTrackingSliceOrder(iSlice); unsigned int sliceLeft, sliceRight; GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(tmpSlice, sliceLeft, sliceRight); @@ -2636,3 +779,12 @@ void GPUChainTracking::ClearErrorCodes() } TransferMemoryResourceLinkToGPU(RecoStep::NoRecoStep, mInputsHost->mResourceErrorCodes, 0); } + +void GPUChainTracking::SetDefaultO2PropagatorForGPU() +{ +#ifdef GPUCA_HAVE_O2HEADERS + o2::base::Propagator* prop = param().GetDefaultO2Propagator(true); + prop->setMatLUT(processors()->calibObjects.matLUT); + SetO2Propagator(prop); +#endif +} diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index f9cb5022e9830..8c8d73645d909 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,7 @@ #include "GPUDataTypes.h" #include <atomic> #include <array> +#include <vector> #include <utility> namespace o2 @@ -59,7 +61,7 @@ class GPUTRDGeometry; class TPCFastTransform; class TPCdEdxCalibrationSplines; class GPUTrackingInputProvider; -class GPUChainTrackingFinalContext; +struct GPUChainTrackingFinalContext; struct GPUTPCCFChainContext; class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelegateBase @@ -103,12 +105,23 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega std::unique_ptr<GPUTPCHitId[]> sliceClusters[NSLICES]; std::unique_ptr<AliHLTTPCClusterMCLabel[]> mcLabelsTPC; std::unique_ptr<GPUTPCMCInfo[]> mcInfosTPC; + std::unique_ptr<GPUTPCMCInfoCol[]> mcInfosTPCCol; std::unique_ptr<GPUTPCGMMergedTrack[]> mergedTracks; std::unique_ptr<GPUTPCGMMergedTrackHit[]> mergedTrackHits; std::unique_ptr<GPUTPCGMMergedTrackHitXYZ[]> mergedTrackHitsXYZ; std::unique_ptr<GPUTRDTrackletWord[]> trdTracklets; - std::unique_ptr<GPUTRDTrackletLabels[]> trdTrackletsMC; + std::unique_ptr<GPUTRDSpacePoint[]> trdSpacePoints; + std::unique_ptr<char[]> trdTrigRecMask; + std::unique_ptr<float[]> trdTriggerTimes; + std::unique_ptr<int[]> trdTrackletIdxFirst; std::unique_ptr<GPUTRDTrackGPU[]> trdTracks; + std::unique_ptr<char[]> clusterNativeMC; + std::unique_ptr<o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>> clusterNativeMCView; + std::unique_ptr<char[]> tpcDigitsMC[NSLICES]; + std::unique_ptr<o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>[]> tpcDigitMCView; + std::unique_ptr<GPUTPCDigitsMCInput> tpcDigitMCMap; + std::unique_ptr<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>> clusterNativeMCBuffer; + std::unique_ptr<GPUSettingsTF[]> settingsTF; } mIOMem; // Read / Dump / Clear Data @@ -129,7 +142,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void ConvertZSFilter(bool zs12bit); // Getters for external usage of tracker classes - GPUTRDTrackerGPU* GetTRDTracker() { return &processors()->trdTracker; } + GPUTRDTrackerGPU* GetTRDTrackerGPU() { return &processors()->trdTrackerGPU; } GPUTPCTracker* GetTPCSliceTrackers() { return processors()->tpcTrackers; } const GPUTPCTracker* GetTPCSliceTrackers() const { return processors()->tpcTrackers; } const GPUTPCGMMerger& GetTPCMerger() const { return processors()->tpcMerger; } @@ -152,24 +165,31 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega // Getters / setters for parameters const TPCFastTransform* GetTPCTransform() const { return processors()->calibObjects.fastTransform; } - const TPCCFCalibration* GetTPCCalibration() const { return processors()->calibObjects.tpcCalibration; } + const TPCPadGainCalib* GetTPCPadGainCalib() const { return processors()->calibObjects.tpcPadGain; } const TPCdEdxCalibrationSplines* GetdEdxSplines() const { return processors()->calibObjects.dEdxSplines; } const o2::base::MatLayerCylSet* GetMatLUT() const { return processors()->calibObjects.matLUT; } const GPUTRDGeometry* GetTRDGeometry() const { return (GPUTRDGeometry*)processors()->calibObjects.trdGeometry; } + const o2::base::Propagator* GetO2Propagator() const { return processors()->calibObjects.o2Propagator; } void SetTPCFastTransform(std::unique_ptr<TPCFastTransform>&& tpcFastTransform); void SetdEdxSplines(std::unique_ptr<TPCdEdxCalibrationSplines>&& dEdxSplines); void SetMatLUT(std::unique_ptr<o2::base::MatLayerCylSet>&& lut); void SetTRDGeometry(std::unique_ptr<o2::trd::GeometryFlat>&& geo); void SetTPCFastTransform(const TPCFastTransform* tpcFastTransform) { processors()->calibObjects.fastTransform = tpcFastTransform; } - void SetTPCCFCalibration(const TPCCFCalibration* tpcCalibration) { processors()->calibObjects.tpcCalibration = tpcCalibration; } + void SetTPCPadGainCalib(const TPCPadGainCalib* tpcPadGainCalib) { processors()->calibObjects.tpcPadGain = tpcPadGainCalib; } void SetdEdxSplines(const TPCdEdxCalibrationSplines* dEdxSplines) { processors()->calibObjects.dEdxSplines = dEdxSplines; } void SetMatLUT(const o2::base::MatLayerCylSet* lut) { processors()->calibObjects.matLUT = lut; } void SetTRDGeometry(const o2::trd::GeometryFlat* geo) { processors()->calibObjects.trdGeometry = geo; } + void SetO2Propagator(const o2::base::Propagator* prop) { processors()->calibObjects.o2Propagator = prop; } + void SetCalibObjects(const GPUCalibObjectsConst& obj) { processors()->calibObjects = obj; } + void SetCalibObjects(const GPUCalibObjects& obj) { memcpy((void*)&processors()->calibObjects, (const void*)&obj, sizeof(obj)); } + void SetDefaultO2PropagatorForGPU(); void LoadClusterErrors(); - void SetOutputControlCompressedClusters(GPUOutputControl* v) { mOutputCompressedClusters = v; } - void SetOutputControlClustersNative(GPUOutputControl* v) { mOutputClustersNative = v; } - void SetOutputControlTPCTracks(GPUOutputControl* v) { mOutputTPCTracks = v; } - void SetOutputControlClusterLabels(GPUOutputControl* v) { mOutputClusterLabels = v; } + void SetOutputControlCompressedClusters(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)] = v; } + void SetOutputControlClustersNative(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)] = v; } + void SetOutputControlTPCTracks(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)] = v; } + void SetOutputControlClusterLabels(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)] = v; } + void SetOutputControlSharedClusterMap(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::sharedClusterMap)] = v; } + void SetSubOutputControl(int i, GPUOutputControl* v) { mSubOutputControls[i] = v; } const GPUSettingsDisplay* mConfigDisplay = nullptr; // Abstract pointer to Standalone Display Configuration Structure const GPUSettingsQA* mConfigQA = nullptr; // Abstract pointer to Standalone QA Configuration Structure @@ -230,20 +250,19 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega std::unique_ptr<GPUTPCClusterStatistics> mCompressionStatistics; // Ptr to detector / calibration objects - std::unique_ptr<TPCFastTransform> mTPCFastTransformU; // Global TPC fast transformation object - std::unique_ptr<TPCCFCalibration> mTPCCalibrationU; // TPC gain calibration and cluster finder parameters - std::unique_ptr<TPCdEdxCalibrationSplines> mdEdxSplinesU; // TPC dEdx calibration splines - std::unique_ptr<o2::base::MatLayerCylSet> mMatLUTU; // Material Lookup Table - std::unique_ptr<o2::trd::GeometryFlat> mTRDGeometryU; // TRD Geometry + std::unique_ptr<TPCFastTransform> mTPCFastTransformU; // Global TPC fast transformation object + std::unique_ptr<TPCPadGainCalib> mTPCPadGainCalibU; // TPC gain calibration and cluster finder parameters + std::unique_ptr<TPCdEdxCalibrationSplines> mdEdxSplinesU; // TPC dEdx calibration splines + std::unique_ptr<o2::base::MatLayerCylSet> mMatLUTU; // Material Lookup Table + std::unique_ptr<o2::trd::GeometryFlat> mTRDGeometryU; // TRD Geometry + // Ptrs to internal buffers std::unique_ptr<o2::tpc::ClusterNativeAccess> mClusterNativeAccess; + std::array<GPUOutputControl*, GPUTrackingOutputs::count()> mSubOutputControls = {nullptr}; - GPUOutputControl* mOutputCompressedClusters = nullptr; - GPUOutputControl* mOutputClustersNative = nullptr; - GPUOutputControl* mOutputTPCTracks = nullptr; - GPUOutputControl* mOutputClusterLabels = nullptr; - + // (Ptrs to) configuration objects std::unique_ptr<GPUTPCCFChainContext> mCFContext; + bool mTPCSliceScratchOnStack = false; // Upper bounds for memory allocation unsigned int mMaxTPCHits = 0; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx new file mode 100644 index 0000000000000..500719ea264e4 --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -0,0 +1,763 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingClusterizer.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPUChainTrackingDefs.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "GPUMemorySizeScalers.h" +#include "GPUTrackingInputProvider.h" +#include <fstream> + +#ifdef GPUCA_O2_LIB +#include "CommonDataFormat/InteractionRecord.h" +#endif +#ifdef GPUCA_HAVE_O2HEADERS +#include "GPUHostDataTypes.h" +#include "GPUTPCCFChainContext.h" +#include "DataFormatsTPC/ZeroSuppression.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DataFormatsTPC/Digit.h" +#include "DataFormatsTPC/Constants.h" +#else +#include "GPUO2FakeClasses.h" +#endif + +#include "utils/strtag.h" + +#ifndef GPUCA_NO_VC +#include <Vc/Vc> +#endif + +using namespace GPUCA_NAMESPACE::gpu; +using namespace o2::tpc; +using namespace o2::tpc::constants; +using namespace o2::dataformats; + +#ifdef GPUCA_TPC_GEOMETRY_O2 +std::pair<unsigned int, unsigned int> GPUChainTracking::TPCClusterizerDecodeZSCountUpdate(unsigned int iSlice, const CfFragment& fragment) +{ + bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder::ZSOffset* o = processors()->tpcClusterer[iSlice].mPzsOffsets; + unsigned int digits = 0; + unsigned int pages = 0; + for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + clusterer.mMinMaxCN[j] = mCFContext->fragmentData[fragment.index].minMaxCN[iSlice][j]; + if (doGPU) { + unsigned short posInEndpoint = 0; + unsigned short pagesEndpoint = 0; + for (unsigned int k = clusterer.mMinMaxCN[j].minC; k < clusterer.mMinMaxCN[j].maxC; k++) { + const unsigned int minL = (k == clusterer.mMinMaxCN[j].minC) ? clusterer.mMinMaxCN[j].minN : 0; + const unsigned int maxL = (k + 1 == clusterer.mMinMaxCN[j].maxC) ? clusterer.mMinMaxCN[j].maxN : mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; + for (unsigned int l = minL; l < maxL; l++) { + unsigned short pageDigits = mCFContext->fragmentData[fragment.index].pageDigits[iSlice][j][posInEndpoint++]; + if (pageDigits) { + *(o++) = GPUTPCClusterFinder::ZSOffset{digits, j, pagesEndpoint}; + digits += pageDigits; + } + pagesEndpoint++; + } + } + if (pagesEndpoint != mCFContext->fragmentData[fragment.index].pageDigits[iSlice][j].size()) { + GPUFatal("TPC raw page count mismatch in TPCClusterizerDecodeZSCountUpdate: expected %d / buffered %lu", pagesEndpoint, mCFContext->fragmentData[fragment.index].pageDigits[iSlice][j].size()); + } + } else { + clusterer.mPzsOffsets[j] = GPUTPCClusterFinder::ZSOffset{digits, j, 0}; + digits += mCFContext->fragmentData[fragment.index].nDigits[iSlice][j]; + pages += mCFContext->fragmentData[fragment.index].nPages[iSlice][j]; + } + } + if (doGPU) { + pages = o - processors()->tpcClusterer[iSlice].mPzsOffsets; + } + return {digits, pages}; +} + +std::pair<unsigned int, unsigned int> GPUChainTracking::TPCClusterizerDecodeZSCount(unsigned int iSlice, const CfFragment& fragment) +{ + mRec->getGeneralStepTimer(GeneralStep::Prepare).Start(); + unsigned int nDigits = 0; + unsigned int nPages = 0; + bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; + int firstHBF = (mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasTfStartOrbit) ? mIOPtrs.settingsTF->tfStartOrbit : (mIOPtrs.tpcZS->slice[iSlice].count[0] && mIOPtrs.tpcZS->slice[iSlice].nZSPtr[0][0]) ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]) : 0; + + for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { +#ifndef GPUCA_NO_VC + if (GetProcessingSettings().prefetchTPCpageScan >= 3 && j < GPUTrackingInOutZS::NENDPOINTS - 1) { + for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j + 1]; k++) { + for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j + 1][k]; l++) { + Vc::Common::prefetchMid(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j + 1][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); + Vc::Common::prefetchMid(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j + 1][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(o2::header::RAWDataHeader)); + } + } + } +#endif + + std::vector<std::pair<CfFragment, std::array<int, 5>>> fragments; + fragments.reserve(mCFContext->nFragments); + fragments.emplace_back(std::pair<CfFragment, std::array<int, 5>>{fragment, {0, 0, 0, 0, 0}}); + for (unsigned int i = 1; i < mCFContext->nFragments; i++) { + fragments.emplace_back(std::pair<CfFragment, std::array<int, 5>>{fragments.back().first.next(), {0, 0, 0, 0, 0}}); + } + + unsigned int emptyPages = 0; + unsigned int firstPossibleFragment = 0; + for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j]; k++) { + nPages += mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; + for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; l++) { +#ifndef GPUCA_NO_VC + if (GetProcessingSettings().prefetchTPCpageScan >= 2 && l + 1 < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]) { + Vc::Common::prefetchForOneRead(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + (l + 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE); + Vc::Common::prefetchForOneRead(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + (l + 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(o2::header::RAWDataHeader)); + } +#endif + const unsigned char* const page = ((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE; + const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)page; + if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) { + emptyPages++; + continue; + } + const TPCZSHDR* const hdr = (const TPCZSHDR*)(page + sizeof(o2::header::RAWDataHeader)); + nDigits += hdr->nADCsamples; + unsigned int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; + if (timeBin + hdr->nTimeBins > mCFContext->tpcMaxTimeBin) { + mCFContext->tpcMaxTimeBin = timeBin + hdr->nTimeBins; + } + for (unsigned int f = firstPossibleFragment; f < mCFContext->nFragments; f++) { + if (timeBin < (unsigned int)fragments[f].first.last()) { + if ((unsigned int)fragments[f].first.first() <= timeBin + hdr->nTimeBins) { + fragments[f].second[2] = k + 1; + fragments[f].second[3] = l + 1; + if (!fragments[f].second[4]) { + fragments[f].second[4] = 1; + fragments[f].second[0] = k; + fragments[f].second[1] = l; + } else if (emptyPages) { + mCFContext->fragmentData[f].nPages[iSlice][j] += emptyPages; + for (unsigned int m = 0; m < emptyPages; m++) { + mCFContext->fragmentData[f].pageDigits[iSlice][j].emplace_back(0); + } + } + mCFContext->fragmentData[f].nPages[iSlice][j]++; + mCFContext->fragmentData[f].nDigits[iSlice][j] += hdr->nADCsamples; + if (doGPU) { + mCFContext->fragmentData[f].pageDigits[iSlice][j].emplace_back(hdr->nADCsamples); + } + } + } else { + firstPossibleFragment = f + 1; + } + } + emptyPages = 0; + } + } + for (unsigned int f = 0; f < mCFContext->nFragments; f++) { + mCFContext->fragmentData[f].minMaxCN[iSlice][j].maxC = fragments[f].second[2]; + mCFContext->fragmentData[f].minMaxCN[iSlice][j].minC = fragments[f].second[0]; + mCFContext->fragmentData[f].minMaxCN[iSlice][j].maxN = fragments[f].second[3]; + mCFContext->fragmentData[f].minMaxCN[iSlice][j].minN = fragments[f].second[1]; + } + } + mCFContext->nPagesTotal += nPages; + mCFContext->nPagesSector[iSlice] = nPages; + mCFContext->nPagesSectorMax = std::max(mCFContext->nPagesSectorMax, nPages); + + unsigned int digitsFragment = 0; + for (unsigned int i = 0; i < mCFContext->nFragments; i++) { + unsigned int pages = 0; + unsigned int digits = 0; + for (unsigned short j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + pages += mCFContext->fragmentData[i].nPages[iSlice][j]; + digits += mCFContext->fragmentData[i].nDigits[iSlice][j]; + } + mCFContext->nPagesFragmentMax = std::max(mCFContext->nPagesSectorMax, pages); + digitsFragment = std::max(digitsFragment, digits); + } + mRec->getGeneralStepTimer(GeneralStep::Prepare).Stop(); + return {nDigits, digitsFragment}; +} + +void GPUChainTracking::RunTPCClusterizer_compactPeaks(GPUTPCClusterFinder& clusterer, GPUTPCClusterFinder& clustererShadow, int stage, bool doGPU, int lane) +{ + auto& in = stage ? clustererShadow.mPpeakPositions : clustererShadow.mPpositions; + auto& out = stage ? clustererShadow.mPfilteredPeakPositions : clustererShadow.mPpeakPositions; + if (doGPU) { + const unsigned int iSlice = clusterer.mISlice; + auto& count = stage ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; + + std::vector<size_t> counts; + + unsigned int nSteps = clusterer.getNSteps(count); + if (nSteps > clusterer.mNBufs) { + GPUError("Clusterer buffers exceeded (%u > %u)", nSteps, (int)clusterer.mNBufs); + exit(1); + } + + size_t tmpCount = count; + if (nSteps > 1) { + for (unsigned int i = 1; i < nSteps; i++) { + counts.push_back(tmpCount); + if (i == 1) { + runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanStart>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, stage); + } else { + runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanUp>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, tmpCount); + } + tmpCount = (tmpCount + clusterer.mScanWorkGroupSize - 1) / clusterer.mScanWorkGroupSize; + } + + runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanTop>(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, nSteps, tmpCount); + + for (unsigned int i = nSteps - 1; i > 1; i--) { + tmpCount = counts[i - 1]; + runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::scanDown>(GetGrid(tmpCount - clusterer.mScanWorkGroupSize, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, clusterer.mScanWorkGroupSize, tmpCount); + } + } + + runKernel<GPUTPCCFStreamCompaction, GPUTPCCFStreamCompaction::compactDigits>(GetGrid(count, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, 1, stage, in, out); + } else { + auto& nOut = stage ? clusterer.mPmemory->counters.nClusters : clusterer.mPmemory->counters.nPeaks; + auto& nIn = stage ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; + size_t count = 0; + for (size_t i = 0; i < nIn; i++) { + if (clusterer.mPisPeak[i]) { + out[count++] = in[i]; + } + } + nOut = count; + } +} + +std::pair<unsigned int, unsigned int> GPUChainTracking::RunTPCClusterizer_transferZS(int iSlice, const CfFragment& fragment, int lane) +{ + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCClusterFinding; + const auto& retVal = TPCClusterizerDecodeZSCountUpdate(iSlice, fragment); + if (doGPU) { + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + unsigned int nPagesSector = 0; + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + unsigned int nPages = 0; + mInputsHost->mPzsMeta->slice[iSlice].zsPtr[j] = &mInputsShadow->mPzsPtrs[iSlice * GPUTrackingInOutZS::NENDPOINTS + j]; + mInputsHost->mPzsPtrs[iSlice * GPUTrackingInOutZS::NENDPOINTS + j] = clustererShadow.mPzs + (nPagesSector + nPages) * TPCZSHDR::TPC_ZS_PAGE_SIZE; + for (unsigned int k = clusterer.mMinMaxCN[j].minC; k < clusterer.mMinMaxCN[j].maxC; k++) { + const unsigned int min = (k == clusterer.mMinMaxCN[j].minC) ? clusterer.mMinMaxCN[j].minN : 0; + const unsigned int max = (k + 1 == clusterer.mMinMaxCN[j].maxC) ? clusterer.mMinMaxCN[j].maxN : mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; + if (max > min) { + char* src = (char*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[j][k] + min * TPCZSHDR::TPC_ZS_PAGE_SIZE; + size_t size = o2::raw::RDHUtils::getMemorySize(*(const o2::header::RAWDataHeader*)src); + size = (max - min - 1) * TPCZSHDR::TPC_ZS_PAGE_SIZE + (size ? TPCZSHDR::TPC_ZS_PAGE_SIZE : size); + GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPzs + (nPagesSector + nPages) * TPCZSHDR::TPC_ZS_PAGE_SIZE, src, size, lane, true); + } + nPages += max - min; + } + mInputsHost->mPzsMeta->slice[iSlice].nZSPtr[j] = &mInputsShadow->mPzsSizes[iSlice * GPUTrackingInOutZS::NENDPOINTS + j]; + mInputsHost->mPzsSizes[iSlice * GPUTrackingInOutZS::NENDPOINTS + j] = nPages; + mInputsHost->mPzsMeta->slice[iSlice].count[j] = 1; + nPagesSector += nPages; + } + GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPzsOffsets, clusterer.mPzsOffsets, clusterer.mNMaxPages * sizeof(*clusterer.mPzsOffsets), lane, true); + } + return retVal; +} + +int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) +{ + if (restorePointers) { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + processors()->tpcClusterer[iSlice].mPzsOffsets = mCFContext->ptrSave[iSlice].zsOffsetHost; + processorsShadow()->tpcClusterer[iSlice].mPzsOffsets = mCFContext->ptrSave[iSlice].zsOffsetDevice; + processorsShadow()->tpcClusterer[iSlice].mPzs = mCFContext->ptrSave[iSlice].zsDevice; + } + processorsShadow()->ioPtrs.clustersNative = mCFContext->ptrClusterNativeSave; + return 0; + } + const auto& threadContext = GetThreadContext(); + mRec->MemoryScalers()->nTPCdigits = 0; + if (mCFContext == nullptr) { + mCFContext.reset(new GPUTPCCFChainContext); + } + mCFContext->tpcMaxTimeBin = param().par.continuousTracking ? std::max<int>(param().par.continuousMaxTimeBin, TPC_MAX_FRAGMENT_LEN) : TPC_MAX_TIME_BIN_TRIGGERED; + const CfFragment fragmentMax{(tpccf::TPCTime)mCFContext->tpcMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN}; + mCFContext->prepare(mIOPtrs.tpcZS, fragmentMax); + if (mIOPtrs.tpcZS) { + unsigned int nDigitsFragment[NSLICES]; + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + if (mIOPtrs.tpcZS->slice[iSlice].count[0]) { + const void* rdh = mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]; + if (rdh && o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>() != o2::raw::RDHUtils::getVersion(rdh)) { + GPUError("Data has invalid RDH version %d, %d required\n", o2::raw::RDHUtils::getVersion(rdh), o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>()); + return 1; + } + } +#ifndef GPUCA_NO_VC + if (GetProcessingSettings().prefetchTPCpageScan >= 1 && iSlice < NSLICES - 1) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j]; k++) { + for (unsigned int l = 0; l < mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; l++) { + Vc::Common::prefetchFar(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice + 1].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE); + Vc::Common::prefetchFar(((const unsigned char*)mIOPtrs.tpcZS->slice[iSlice + 1].zsPtr[j][k]) + l * TPCZSHDR::TPC_ZS_PAGE_SIZE + sizeof(o2::header::RAWDataHeader)); + } + } + } + } +#endif + const auto& x = TPCClusterizerDecodeZSCount(iSlice, fragmentMax); + nDigitsFragment[iSlice] = x.second; + processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits = x.first; + mRec->MemoryScalers()->nTPCdigits += x.first; + } + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + processors()->tpcClusterer[iSlice].SetNMaxDigits(processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits, mCFContext->nPagesFragmentMax, nDigitsFragment[iSlice]); + if (mRec->IsGPU()) { + processorsShadow()->tpcClusterer[iSlice].SetNMaxDigits(processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits, mCFContext->nPagesFragmentMax, nDigitsFragment[iSlice]); + } + if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { + mPipelineNotifyCtx->rec->AllocateRegisteredForeignMemory(processors()->tpcClusterer[iSlice].mZSOffsetId, mRec); + mPipelineNotifyCtx->rec->AllocateRegisteredForeignMemory(processors()->tpcClusterer[iSlice].mZSId, mRec); + } else { + AllocateRegisteredMemory(processors()->tpcClusterer[iSlice].mZSOffsetId); + AllocateRegisteredMemory(processors()->tpcClusterer[iSlice].mZSId); + } + } + } else { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + unsigned int nDigits = mIOPtrs.tpcPackedDigits->nTPCDigits[iSlice]; + mRec->MemoryScalers()->nTPCdigits += nDigits; + processors()->tpcClusterer[iSlice].SetNMaxDigits(nDigits, mCFContext->nPagesFragmentMax, nDigits); + } + } + if (mIOPtrs.tpcZS) { + GPUInfo("Event has %u 8kb TPC ZS pages, %lld digits", mCFContext->nPagesTotal, (long long int)mRec->MemoryScalers()->nTPCdigits); + } else { + GPUInfo("Event has %lld TPC Digits", (long long int)mRec->MemoryScalers()->nTPCdigits); + } + mCFContext->fragmentFirst = CfFragment{std::max<int>(mCFContext->tpcMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN), TPC_MAX_FRAGMENT_LEN}; + for (int iSlice = 0; iSlice < GetProcessingSettings().nTPCClustererLanes && iSlice < NSLICES; iSlice++) { + if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { + mCFContext->nextPos[iSlice] = RunTPCClusterizer_transferZS(iSlice, mCFContext->fragmentFirst, GetProcessingSettings().nTPCClustererLanes + iSlice); + } + } + + if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + mCFContext->ptrSave[iSlice].zsOffsetHost = processors()->tpcClusterer[iSlice].mPzsOffsets; + mCFContext->ptrSave[iSlice].zsOffsetDevice = processorsShadow()->tpcClusterer[iSlice].mPzsOffsets; + mCFContext->ptrSave[iSlice].zsDevice = processorsShadow()->tpcClusterer[iSlice].mPzs; + } + } + return 0; +} +#endif + +// TODO: Clusterizer not working with OCL1 (Clusterizer on CPU, Tracking on GPU) +int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) +{ + if (param().rec.fwdTPCDigitsAsClusters) { + return ForwardTPCDigits(); + } +#ifdef GPUCA_TPC_GEOMETRY_O2 + mRec->PushNonPersistentMemory(qStr2Tag("TPCCLUST")); + const auto& threadContext = GetThreadContext(); + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCClusterFinding; + if (RunTPCClusterizer_prepare(mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer)) { + return 1; + } + if (GetProcessingSettings().ompAutoNThreads && !mRec->IsGPU()) { + mRec->SetNOMPThreads(mRec->MemoryScalers()->nTPCdigits / 20000); + } + + mRec->MemoryScalers()->nTPCHits = mRec->MemoryScalers()->NTPCClusters(mRec->MemoryScalers()->nTPCdigits); + float tpcHitLowOccupancyScalingFactor = 1.f; + if (mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasNHBFPerTF) { + unsigned int nHitsBase = mRec->MemoryScalers()->nTPCHits; + unsigned int threshold = 30000000 / 256 * mIOPtrs.settingsTF->nHBFPerTF; + mRec->MemoryScalers()->nTPCHits = std::max<unsigned int>(nHitsBase, std::min<unsigned int>(threshold, nHitsBase * 3)); // Increase the buffer size for low occupancy data to compensate for noisy pads creating exceiive clusters + if (nHitsBase < threshold) { + float maxFactor = mRec->MemoryScalers()->nTPCHits < threshold ? 2.25 : 1.75; + mRec->MemoryScalers()->temporaryFactor *= std::min(maxFactor, (float)threshold / nHitsBase); + tpcHitLowOccupancyScalingFactor = std::min(3.f, (float)threshold / nHitsBase); + } + } + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + processors()->tpcClusterer[iSlice].SetMaxData(mIOPtrs); // First iteration to set data sizes + } + mRec->ComputeReuseMax(nullptr); // Resolve maximums for shared buffers + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + SetupGPUProcessor(&processors()->tpcClusterer[iSlice], true); // Now we allocate + } + if (mPipelineNotifyCtx && GetProcessingSettings().doublePipelineClusterizer) { + RunTPCClusterizer_prepare(true); // Restore some pointers, allocated by the other pipeline, and set to 0 by SetupGPUProcessor (since not allocated in this pipeline) + } + + if (doGPU && mIOPtrs.tpcZS) { + processorsShadow()->ioPtrs.tpcZS = mInputsShadow->mPzsMeta; + WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), mRec->NStreams() - 1); + } + if (doGPU) { + WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)processors()->tpcClusterer - (char*)processors(), processorsShadow()->tpcClusterer, sizeof(GPUTPCClusterFinder) * NSLICES, mRec->NStreams() - 1, &mEvents->init); + } + + size_t nClsTotal = 0; + ClusterNativeAccess* tmpNative = mClusterNativeAccess.get(); + + // setup MC Labels + bool propagateMCLabels = GetProcessingSettings().runMC && processors()->ioPtrs.tpcPackedDigits && processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC; + + auto* digitsMC = propagateMCLabels ? processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC : nullptr; + + if (param().par.continuousMaxTimeBin > 0 && mCFContext->tpcMaxTimeBin >= (unsigned int)std::max(param().par.continuousMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN)) { + GPUError("Input data has invalid time bin %u > %d\n", mCFContext->tpcMaxTimeBin, std::max(param().par.continuousMaxTimeBin + 1, TPC_MAX_FRAGMENT_LEN)); + return 1; + } + bool buildNativeGPU = (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression); + bool buildNativeHost = mRec->GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCClusters; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output + + mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mRec->MemoryScalers()->nTPCHits * tpcHitLowOccupancyScalingFactor; + if (buildNativeGPU) { + AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); + } + if (buildNativeHost && !(buildNativeGPU && GetProcessingSettings().delayedOutput)) { + AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)]); + } + + GPUTPCLinearLabels mcLinearLabels; + if (propagateMCLabels) { + // No need to overallocate here, nTPCHits is anyway an upper bound used for the GPU cluster buffer, and we can always enlarge the buffer anyway + mcLinearLabels.header.reserve(mRec->MemoryScalers()->nTPCHits / 2); + mcLinearLabels.data.reserve(mRec->MemoryScalers()->nTPCHits); + } + + char transferRunning[NSLICES] = {0}; + unsigned int outputQueueStart = mOutputQueue.size(); + + for (unsigned int iSliceBase = 0; iSliceBase < NSLICES; iSliceBase += GetProcessingSettings().nTPCClustererLanes) { + std::vector<bool> laneHasData(GetProcessingSettings().nTPCClustererLanes, false); + for (CfFragment fragment = mCFContext->fragmentFirst; !fragment.isEnd(); fragment = fragment.next()) { + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Processing time bins [%d, %d) for sectors %d to %d", fragment.start, fragment.last(), iSliceBase, iSliceBase + GetProcessingSettings().nTPCClustererLanes - 1); + } + for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { + if (fragment.index != 0) { + SynchronizeStream(lane); // Don't overwrite charge map from previous iteration until cluster computation is finished + } + + unsigned int iSlice = iSliceBase + lane; + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + clusterer.mPmemory->counters.nPeaks = clusterer.mPmemory->counters.nClusters = 0; + clusterer.mPmemory->fragment = fragment; + + if (propagateMCLabels && fragment.index == 0) { + clusterer.PrepareMC(); + clusterer.mPinputLabels = digitsMC->v[iSlice]; + // TODO: Why is the number of header entries in truth container + // sometimes larger than the number of digits? + assert(clusterer.mPinputLabels->getIndexedSize() >= mIOPtrs.tpcPackedDigits->nTPCDigits[iSlice]); + } + + if (mIOPtrs.tpcPackedDigits) { + bool setDigitsOnGPU = doGPU && not mIOPtrs.tpcZS; + bool setDigitsOnHost = (not doGPU && not mIOPtrs.tpcZS) || propagateMCLabels; + auto* inDigits = mIOPtrs.tpcPackedDigits; + size_t numDigits = inDigits->nTPCDigits[iSlice]; + if (setDigitsOnGPU) { + GPUMemCpy(RecoStep::TPCClusterFinding, clustererShadow.mPdigits, inDigits->tpcDigits[iSlice], sizeof(clustererShadow.mPdigits[0]) * numDigits, lane, true); + clusterer.mPmemory->counters.nDigits = numDigits; + } else if (setDigitsOnHost) { + clusterer.mPdigits = const_cast<o2::tpc::Digit*>(inDigits->tpcDigits[iSlice]); // TODO: Needs fixing (invalid const cast) + clusterer.mPmemory->counters.nDigits = numDigits; + } + } + + if (mIOPtrs.tpcZS) { + if (mCFContext->nPagesSector[iSlice]) { + clusterer.mPmemory->counters.nPositions = mCFContext->nextPos[iSlice].first; + clusterer.mPmemory->counters.nPagesSubslice = mCFContext->nextPos[iSlice].second; + } else { + clusterer.mPmemory->counters.nPositions = clusterer.mPmemory->counters.nPagesSubslice = 0; + } + } + TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + + using ChargeMapType = decltype(*clustererShadow.mPchargeMap); + using PeakMapType = decltype(*clustererShadow.mPpeakMap); + runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPchargeMap, TPCMapMemoryLayout<ChargeMapType>::items() * sizeof(ChargeMapType)); + runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPpeakMap, TPCMapMemoryLayout<PeakMapType>::items() * sizeof(PeakMapType)); + if (fragment.index == 0) { + runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPpadIsNoisy, TPC_PADS_IN_SECTOR * sizeof(*clustererShadow.mPpadIsNoisy)); + } + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Zeroed Charges"); + + if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice]) { + TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, mInputsHost->mResourceZS, lane); + SynchronizeStream(GetProcessingSettings().nTPCClustererLanes + lane); + } + + SynchronizeStream(mRec->NStreams() - 1); // Wait for copying to constant memory + + if (mIOPtrs.tpcZS && !mCFContext->nPagesSector[iSlice]) { + continue; + } + + if (not mIOPtrs.tpcZS) { + runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::findFragmentStart>(GetGrid(1, lane), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); + TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + } else if (propagateMCLabels) { + runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::findFragmentStart>(GetGrid(1, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); + TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + } + + if (mIOPtrs.tpcZS) { + int firstHBF = (mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasTfStartOrbit) ? mIOPtrs.settingsTF->tfStartOrbit : (mIOPtrs.tpcZS->slice[iSlice].count[0] && mIOPtrs.tpcZS->slice[iSlice].nZSPtr[0][0]) ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]) : 0; + runKernel<GPUTPCCFDecodeZS, GPUTPCCFDecodeZS::decodeZS>(GetGridBlk(doGPU ? clusterer.mPmemory->counters.nPagesSubslice : GPUTrackingInOutZS::NENDPOINTS, lane), {iSlice}, {}, firstHBF); + TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + } + } + for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { + unsigned int iSlice = iSliceBase + lane; + SynchronizeStream(lane); + if (mIOPtrs.tpcZS) { + CfFragment f = fragment.next(); + int nextSlice = iSlice; + if (f.isEnd()) { + nextSlice += GetProcessingSettings().nTPCClustererLanes; + f = mCFContext->fragmentFirst; + } + if (nextSlice < NSLICES && mIOPtrs.tpcZS && mCFContext->nPagesSector[nextSlice]) { + mCFContext->nextPos[nextSlice] = RunTPCClusterizer_transferZS(nextSlice, f, GetProcessingSettings().nTPCClustererLanes + lane); + } + } + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + if (clusterer.mPmemory->counters.nPositions == 0) { + continue; + } + if (!mIOPtrs.tpcZS) { + runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::fillFromDigits>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); + } + if (DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpDigits, *mDebugFile)) { + clusterer.DumpChargeMap(*mDebugFile, "Charges"); + } + + if (propagateMCLabels) { + runKernel<GPUTPCCFChargeMapFiller, GPUTPCCFChargeMapFiller::fillIndexMap>(GetGrid(clusterer.mPmemory->counters.nDigitsInFragment, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); + } + + bool checkForNoisyPads = (rec()->GetParam().rec.tpc.maxTimeBinAboveThresholdIn1000Bin > 0) || (rec()->GetParam().rec.tpc.maxConsecTimeBinAboveThreshold > 0); + checkForNoisyPads &= (rec()->GetParam().rec.tpc.noisyPadsQuickCheck ? fragment.index == 0 : true); + checkForNoisyPads &= !GetProcessingSettings().disableTPCNoisyPadFilter; + + if (checkForNoisyPads) { + int nBlocks = TPC_PADS_IN_SECTOR / GPUTPCCFCheckPadBaseline::PadsPerCacheline; + runKernel<GPUTPCCFCheckPadBaseline>(GetGridBlk(nBlocks, lane), {iSlice}, {}); + } + + runKernel<GPUTPCCFPeakFinder>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpPeaks, *mDebugFile); + + RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 0, doGPU, lane); + TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpPeaksCompacted, *mDebugFile); + } + for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { + unsigned int iSlice = iSliceBase + lane; + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + SynchronizeStream(lane); + if (clusterer.mPmemory->counters.nPeaks == 0) { + continue; + } + runKernel<GPUTPCCFNoiseSuppression, GPUTPCCFNoiseSuppression::noiseSuppression>(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); + runKernel<GPUTPCCFNoiseSuppression, GPUTPCCFNoiseSuppression::updatePeaks>(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaks, *mDebugFile); + + RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 1, doGPU, lane); + TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaksCompacted, *mDebugFile); + } + for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { + unsigned int iSlice = iSliceBase + lane; + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + SynchronizeStream(lane); + + if (fragment.index == 0) { + runKernel<GPUMemClean16>(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {nullptr, transferRunning[lane] == 1 ? &mEvents->stream[lane] : nullptr}, clustererShadow.mPclusterInRow, GPUCA_ROW_COUNT * sizeof(*clustererShadow.mPclusterInRow)); + transferRunning[lane] = 2; + } + + if (clusterer.mPmemory->counters.nClusters == 0) { + continue; + } + + runKernel<GPUTPCCFDeconvolution>(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); + DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Split Charges"); + + runKernel<GPUTPCCFClusterizer>(GetGrid(clusterer.mPmemory->counters.nClusters, lane), {iSlice}, {}, 0); + if (doGPU && propagateMCLabels) { + TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mScratchId, lane); + SynchronizeStream(lane); + runKernel<GPUTPCCFClusterizer>(GetGrid(clusterer.mPmemory->counters.nClusters, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, 1); + } + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Sector %02d Fragment %02d Lane %d: Found clusters: digits %u peaks %u clusters %u", iSlice, fragment.index, lane, (int)clusterer.mPmemory->counters.nPositions, (int)clusterer.mPmemory->counters.nPeaks, (int)clusterer.mPmemory->counters.nClusters); + } + + TransferMemoryResourcesToHost(RecoStep::TPCClusterFinding, &clusterer, lane); + laneHasData[lane] = true; + if (DoDebugAndDump(RecoStep::TPCClusterFinding, 0, clusterer, &GPUTPCClusterFinder::DumpCountedPeaks, *mDebugFile)) { + clusterer.DumpClusters(*mDebugFile); + } + } + } + size_t nClsFirst = nClsTotal; + bool anyLaneHasData = false; + for (int lane = 0; lane < GetProcessingSettings().nTPCClustererLanes && iSliceBase + lane < NSLICES; lane++) { + unsigned int iSlice = iSliceBase + lane; + std::fill(&tmpNative->nClusters[iSlice][0], &tmpNative->nClusters[iSlice][0] + MAXGLOBALPADROW, 0); + SynchronizeStream(lane); + GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSlice]; + GPUTPCClusterFinder& clustererShadow = doGPU ? processorsShadow()->tpcClusterer[iSlice] : clusterer; + + if (laneHasData[lane]) { + anyLaneHasData = true; + if (buildNativeGPU && GetProcessingSettings().tpccfGatherKernel) { + runKernel<GPUTPCCFGather>(GetGridBlk(GPUCA_ROW_COUNT, mRec->NStreams() - 1), {iSlice}, {}, &mInputsShadow->mPclusterNativeBuffer[nClsTotal]); + } + for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { + if (nClsTotal + clusterer.mPclusterInRow[j] > mInputsHost->mNClusterNative) { + clusterer.raiseError(GPUErrors::ERROR_CF_GLOBAL_CLUSTER_OVERFLOW, nClsTotal + clusterer.mPclusterInRow[j], mInputsHost->mNClusterNative); + tmpNative->nClusters[iSlice][j] = 0; + continue; + } + if (buildNativeGPU) { + if (!GetProcessingSettings().tpccfGatherKernel) { + GPUMemCpyAlways(RecoStep::TPCClusterFinding, (void*)&mInputsShadow->mPclusterNativeBuffer[nClsTotal], (const void*)&clustererShadow.mPclusterByRow[j * clusterer.mNMaxClusterPerRow], sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * clusterer.mPclusterInRow[j], mRec->NStreams() - 1, -2); + } + } else if (buildNativeHost) { + GPUMemCpyAlways(RecoStep::TPCClusterFinding, (void*)&mInputsHost->mPclusterNativeOutput[nClsTotal], (const void*)&clustererShadow.mPclusterByRow[j * clusterer.mNMaxClusterPerRow], sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * clusterer.mPclusterInRow[j], mRec->NStreams() - 1, false); + } + tmpNative->nClusters[iSlice][j] += clusterer.mPclusterInRow[j]; + nClsTotal += clusterer.mPclusterInRow[j]; + } + if (transferRunning[lane]) { + ReleaseEvent(&mEvents->stream[lane], doGPU); + } + RecordMarker(&mEvents->stream[lane], mRec->NStreams() - 1); + transferRunning[lane] = 1; + } + + if (not propagateMCLabels || not laneHasData[lane]) { + assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); + continue; + } + + runKernel<GPUTPCCFMCLabelFlattener, GPUTPCCFMCLabelFlattener::setRowOffsets>(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); + GPUTPCCFMCLabelFlattener::setGlobalOffsetsAndAllocate(clusterer, mcLinearLabels); + runKernel<GPUTPCCFMCLabelFlattener, GPUTPCCFMCLabelFlattener::flatten>(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, &mcLinearLabels); + clusterer.clearMCMemory(); + assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); + } + if (buildNativeHost && buildNativeGPU && anyLaneHasData) { + if (GetProcessingSettings().delayedOutput) { + mOutputQueue.emplace_back(outputQueueEntry{(void*)((char*)&mInputsHost->mPclusterNativeOutput[nClsFirst] - (char*)&mInputsHost->mPclusterNativeOutput[0]), &mInputsShadow->mPclusterNativeBuffer[nClsFirst], (nClsTotal - nClsFirst) * sizeof(mInputsHost->mPclusterNativeOutput[nClsFirst]), RecoStep::TPCClusterFinding}); + } else { + GPUMemCpy(RecoStep::TPCClusterFinding, (void*)&mInputsHost->mPclusterNativeOutput[nClsFirst], (void*)&mInputsShadow->mPclusterNativeBuffer[nClsFirst], (nClsTotal - nClsFirst) * sizeof(mInputsHost->mPclusterNativeOutput[nClsFirst]), mRec->NStreams() - 1, false); + } + } + } + for (int i = 0; i < GetProcessingSettings().nTPCClustererLanes; i++) { + if (transferRunning[i]) { + ReleaseEvent(&mEvents->stream[i], doGPU); + } + } + + ClusterNativeAccess::ConstMCLabelContainerView* mcLabelsConstView = nullptr; + if (propagateMCLabels) { + // TODO: write to buffer directly + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mcLabels; + std::pair<ConstMCLabelContainer*, ConstMCLabelContainerView*> buffer; + if (mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)] && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->useExternal()) { + if (!mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->allocator) { + throw std::runtime_error("Cluster MC Label buffer missing"); + } + ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer* container = reinterpret_cast<ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer*>(mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->allocator(0)); + buffer = {&container->first, &container->second}; + } else { + mIOMem.clusterNativeMCView = std::make_unique<ConstMCLabelContainerView>(); + mIOMem.clusterNativeMCBuffer = std::make_unique<ConstMCLabelContainer>(); + buffer.first = mIOMem.clusterNativeMCBuffer.get(); + buffer.second = mIOMem.clusterNativeMCView.get(); + } + + assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); + assert(propagateMCLabels ? mcLinearLabels.data.size() >= nClsTotal : true); + + mcLabels.setFrom(mcLinearLabels.header, mcLinearLabels.data); + mcLabels.flatten_to(*buffer.first); + *buffer.second = *buffer.first; + mcLabelsConstView = buffer.second; + } + + if (buildNativeHost && buildNativeGPU && GetProcessingSettings().delayedOutput) { + mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = nClsTotal; + AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)]); + for (unsigned int i = outputQueueStart; i < mOutputQueue.size(); i++) { + mOutputQueue[i].dst = (char*)mInputsHost->mPclusterNativeOutput + (size_t)mOutputQueue[i].dst; + } + } + + if (buildNativeHost) { + tmpNative->clustersLinear = mInputsHost->mPclusterNativeOutput; + tmpNative->clustersMCTruth = mcLabelsConstView; + tmpNative->setOffsetPtrs(); + mIOPtrs.clustersNative = tmpNative; + } + + if (mPipelineNotifyCtx) { + SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory + std::lock_guard<std::mutex> lock(mPipelineNotifyCtx->mutex); + mPipelineNotifyCtx->ready = true; + mPipelineNotifyCtx->cond.notify_one(); + } + + if (buildNativeGPU) { + processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; + WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); + *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; + mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; + mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); + TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, mInputsHost->mResourceClusterNativeAccess, 0); + } + if (synchronizeOutput) { + SynchronizeStream(mRec->NStreams() - 1); + } + if (buildNativeHost && GetProcessingSettings().debugLevel >= 4) { + for (unsigned int i = 0; i < NSLICES; i++) { + for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { + std::sort(&mInputsHost->mPclusterNativeOutput[tmpNative->clusterOffset[i][j]], &mInputsHost->mPclusterNativeOutput[tmpNative->clusterOffset[i][j] + tmpNative->nClusters[i][j]]); + } + } + } + mRec->MemoryScalers()->nTPCHits = nClsTotal; + mRec->PopNonPersistentMemory(RecoStep::TPCClusterFinding, qStr2Tag("TPCCLUST")); + if (mPipelineNotifyCtx) { + mRec->UnblockStackedMemory(); + mPipelineNotifyCtx = nullptr; + } + +#endif + return 0; +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx new file mode 100644 index 0000000000000..d04cd31ec851e --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx @@ -0,0 +1,237 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingCompression.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "GPUTrackingInputProvider.h" + +#ifdef GPUCA_HAVE_O2HEADERS +#include "GPUTPCCFChainContext.h" +#include "TPCClusterDecompressor.h" +#endif +#include "utils/strtag.h" + +using namespace GPUCA_NAMESPACE::gpu; +using namespace o2::tpc; + +int GPUChainTracking::RunTPCCompression() +{ +#ifdef GPUCA_HAVE_O2HEADERS + mRec->PushNonPersistentMemory(qStr2Tag("TPCCOMPR")); + RecoStep myStep = RecoStep::TPCCompression; + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCCompression; + GPUTPCCompression& Compressor = processors()->tpcCompressor; + GPUTPCCompression& CompressorShadow = doGPU ? processorsShadow()->tpcCompressor : Compressor; + const auto& threadContext = GetThreadContext(); + if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { + RecordMarker(&mEvents->single, 0); + } + + if (ProcessingSettings().tpcCompressionGatherMode == 3) { + mRec->AllocateVolatileDeviceMemory(0); // make future device memory allocation volatile + } + SetupGPUProcessor(&Compressor, true); + new (Compressor.mMemory) GPUTPCCompression::memory; + + WriteToConstantMemory(myStep, (char*)&processors()->tpcCompressor - (char*)processors(), &CompressorShadow, sizeof(CompressorShadow), 0); + TransferMemoryResourcesToGPU(myStep, &Compressor, 0); + runKernel<GPUMemClean16>(GetGridAutoStep(0, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone, CompressorShadow.mClusterStatus, Compressor.mMaxClusters * sizeof(CompressorShadow.mClusterStatus[0])); + runKernel<GPUTPCCompressionKernels, GPUTPCCompressionKernels::step0attached>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCCompressionKernels, GPUTPCCompressionKernels::step1unattached>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); + TransferMemoryResourcesToHost(myStep, &Compressor, 0); +#ifdef GPUCA_TPC_GEOMETRY_O2 + if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { + SynchronizeEventAndRelease(&mEvents->single); + ((GPUChainTracking*)GetNextChainInQueue())->RunTPCClusterizer_prepare(false); + ((GPUChainTracking*)GetNextChainInQueue())->mCFContext->ptrClusterNativeSave = processorsShadow()->ioPtrs.clustersNative; + } +#endif + SynchronizeStream(0); + o2::tpc::CompressedClusters* O = Compressor.mOutput; + memset((void*)O, 0, sizeof(*O)); + O->nTracks = Compressor.mMemory->nStoredTracks; + O->nAttachedClusters = Compressor.mMemory->nStoredAttachedClusters; + O->nUnattachedClusters = Compressor.mMemory->nStoredUnattachedClusters; + O->nAttachedClustersReduced = O->nAttachedClusters - O->nTracks; + O->nSliceRows = NSLICES * GPUCA_ROW_COUNT; + O->nComppressionModes = param().rec.tpc.compressionTypeMask; + size_t outputSize = AllocateRegisteredMemory(Compressor.mMemoryResOutputHost, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)]); + Compressor.mOutputFlat->set(outputSize, *Compressor.mOutput); + char* hostFlatPtr = (char*)Compressor.mOutput->qTotU; // First array as allocated in GPUTPCCompression::SetPointersCompressedClusters + size_t copySize = 0; + if (ProcessingSettings().tpcCompressionGatherMode == 3) { + CompressorShadow.mOutputA = Compressor.mOutput; + copySize = AllocateRegisteredMemory(Compressor.mMemoryResOutputGPU); // We overwrite Compressor.mOutput with the allocated output pointers on the GPU + } + const o2::tpc::CompressedClustersPtrs* P = nullptr; + HighResTimer* gatherTimer = nullptr; + int outputStream = 0; + if (ProcessingSettings().doublePipeline) { + SynchronizeStream(mRec->NStreams() - 2); // Synchronize output copies running in parallel from memory that might be released, only the following async copy from stacked memory is safe after the chain finishes. + outputStream = mRec->NStreams() - 2; + } + + if (ProcessingSettings().tpcCompressionGatherMode >= 2) { + if (ProcessingSettings().tpcCompressionGatherMode == 2) { + void* devicePtr = mRec->getGPUPointer(Compressor.mOutputFlat); + if (devicePtr != Compressor.mOutputFlat) { + CompressedClustersPtrs& ptrs = *Compressor.mOutput; // We need to update the ptrs with the gpu-mapped version of the host address space + for (unsigned int i = 0; i < sizeof(ptrs) / sizeof(void*); i++) { + reinterpret_cast<char**>(&ptrs)[i] = reinterpret_cast<char**>(&ptrs)[i] + (reinterpret_cast<char*>(devicePtr) - reinterpret_cast<char*>(Compressor.mOutputFlat)); + } + } + } + TransferMemoryResourcesToGPU(myStep, &Compressor, outputStream); + constexpr unsigned int nBlocksDefault = 2; + constexpr unsigned int nBlocksMulti = 1 + 2 * 200; + switch (ProcessingSettings().tpcCompressionGatherModeKernel) { + case 0: + runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::unbuffered>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::unbuffered>(RecoStep::TPCCompression, 0, outputSize); + break; + case 1: + runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered32>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered32>(RecoStep::TPCCompression, 0, outputSize); + break; + case 2: + runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered64>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered64>(RecoStep::TPCCompression, 0, outputSize); + break; + case 3: + runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered128>(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::buffered128>(RecoStep::TPCCompression, 0, outputSize); + break; + case 4: + + static_assert((nBlocksMulti & 1) && nBlocksMulti >= 3); + runKernel<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::multiBlock>(GetGridBlkStep(nBlocksMulti, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + getKernelTimer<GPUTPCCompressionGatherKernels, GPUTPCCompressionGatherKernels::multiBlock>(RecoStep::TPCCompression, 0, outputSize); + break; + default: + GPUError("Invalid compression kernel selected."); + return 1; + } + if (ProcessingSettings().tpcCompressionGatherMode == 3) { + RecordMarker(&mEvents->stream[outputStream], outputStream); + char* deviceFlatPts = (char*)Compressor.mOutput->qTotU; + if (GetProcessingSettings().doublePipeline) { + const size_t blockSize = CAMath::nextMultipleOf<1024>(copySize / 30); + const unsigned int n = (copySize + blockSize - 1) / blockSize; + for (unsigned int i = 0; i < n; i++) { + GPUMemCpy(myStep, hostFlatPtr + i * blockSize, deviceFlatPts + i * blockSize, CAMath::Min(blockSize, copySize - i * blockSize), outputStream, false); + } + } else { + GPUMemCpy(myStep, hostFlatPtr, deviceFlatPts, copySize, outputStream, false); + } + } + } else { + char direction = 0; + if (ProcessingSettings().tpcCompressionGatherMode == 0) { + P = &CompressorShadow.mPtrs; + } else if (ProcessingSettings().tpcCompressionGatherMode == 1) { + P = &Compressor.mPtrs; + direction = -1; + gatherTimer = &getTimer<GPUTPCCompressionKernels>("GPUTPCCompression_GatherOnCPU", 0); + gatherTimer->Start(); + } + GPUMemCpyAlways(myStep, O->nSliceRowClusters, P->nSliceRowClusters, NSLICES * GPUCA_ROW_COUNT * sizeof(O->nSliceRowClusters[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->nTrackClusters, P->nTrackClusters, O->nTracks * sizeof(O->nTrackClusters[0]), outputStream, direction); + SynchronizeStream(outputStream); + unsigned int offset = 0; + for (unsigned int i = 0; i < NSLICES; i++) { + for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { + unsigned int srcOffset = mIOPtrs.clustersNative->clusterOffset[i][j] * Compressor.mMaxClusterFactorBase1024 / 1024; + GPUMemCpyAlways(myStep, O->qTotU + offset, P->qTotU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->qTotU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->qMaxU + offset, P->qMaxU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->qMaxU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->flagsU + offset, P->flagsU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->flagsU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->padDiffU + offset, P->padDiffU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->padDiffU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->timeDiffU + offset, P->timeDiffU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->timeDiffU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sigmaPadU + offset, P->sigmaPadU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->sigmaPadU[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sigmaTimeU + offset, P->sigmaTimeU + srcOffset, O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j] * sizeof(O->sigmaTimeU[0]), outputStream, direction); + offset += O->nSliceRowClusters[i * GPUCA_ROW_COUNT + j]; + } + } + offset = 0; + for (unsigned int i = 0; i < O->nTracks; i++) { + GPUMemCpyAlways(myStep, O->qTotA + offset, P->qTotA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->qTotA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->qMaxA + offset, P->qMaxA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->qMaxA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->flagsA + offset, P->flagsA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->flagsA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sigmaPadA + offset, P->sigmaPadA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->sigmaPadA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sigmaTimeA + offset, P->sigmaTimeA + Compressor.mAttachedClusterFirstIndex[i], O->nTrackClusters[i] * sizeof(O->sigmaTimeA[0]), outputStream, direction); + + // First index stored with track + GPUMemCpyAlways(myStep, O->rowDiffA + offset - i, P->rowDiffA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->rowDiffA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sliceLegDiffA + offset - i, P->sliceLegDiffA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->sliceLegDiffA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->padResA + offset - i, P->padResA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->padResA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->timeResA + offset - i, P->timeResA + Compressor.mAttachedClusterFirstIndex[i] + 1, (O->nTrackClusters[i] - 1) * sizeof(O->timeResA[0]), outputStream, direction); + offset += O->nTrackClusters[i]; + } + GPUMemCpyAlways(myStep, O->qPtA, P->qPtA, O->nTracks * sizeof(O->qPtA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->rowA, P->rowA, O->nTracks * sizeof(O->rowA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->sliceA, P->sliceA, O->nTracks * sizeof(O->sliceA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->timeA, P->timeA, O->nTracks * sizeof(O->timeA[0]), outputStream, direction); + GPUMemCpyAlways(myStep, O->padA, P->padA, O->nTracks * sizeof(O->padA[0]), outputStream, direction); + } + if (ProcessingSettings().tpcCompressionGatherMode == 1) { + gatherTimer->Stop(); + } + mIOPtrs.tpcCompressedClusters = Compressor.mOutputFlat; + if (ProcessingSettings().tpcCompressionGatherMode == 3) { + SynchronizeEventAndRelease(&mEvents->stream[outputStream]); + mRec->ReturnVolatileDeviceMemory(); + } + + if (mPipelineFinalizationCtx == nullptr) { + SynchronizeStream(outputStream); + } else { + ((GPUChainTracking*)GetNextChainInQueue())->mRec->BlockStackedMemory(mRec); + } + mRec->PopNonPersistentMemory(RecoStep::TPCCompression, qStr2Tag("TPCCOMPR")); +#endif + return 0; +} + +int GPUChainTracking::RunTPCDecompression() +{ +#ifdef GPUCA_HAVE_O2HEADERS + const auto& threadContext = GetThreadContext(); + TPCClusterDecompressor decomp; + auto allocator = [this](size_t size) { + this->mInputsHost->mNClusterNative = this->mInputsShadow->mNClusterNative = size; + this->AllocateRegisteredMemory(this->mInputsHost->mResourceClusterNativeOutput, this->mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)]); + return this->mInputsHost->mPclusterNativeOutput; + }; + auto& gatherTimer = getTimer<TPCClusterDecompressor>("TPCDecompression", 0); + gatherTimer.Start(); + if (decomp.decompress(mIOPtrs.tpcCompressedClusters, *mClusterNativeAccess, allocator, param())) { + GPUError("Error decompressing clusters"); + return 1; + } + gatherTimer.Stop(); + mIOPtrs.clustersNative = mClusterNativeAccess.get(); + if (mRec->IsGPU()) { + AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); + processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; + WriteToConstantMemory(RecoStep::TPCDecompression, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); + *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; + mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; + mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); + GPUMemCpy(RecoStep::TPCDecompression, mInputsShadow->mPclusterNativeBuffer, mIOPtrs.clustersNative->clustersLinear, sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * mIOPtrs.clustersNative->nClustersTotal, 0, true); + TransferMemoryResourceLinkToGPU(RecoStep::TPCDecompression, mInputsHost->mResourceClusterNativeAccess, 0); + SynchronizeStream(0); + } +#endif + return 0; +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx index 9cd4e25155ee7..ed24e2a505cca 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "GPUChainTracking.h" #include "GPUTrackingInputProvider.h" +#include "GPUMemorySizeScalers.h" #include <map> #include <memory> #include <string> @@ -139,18 +141,29 @@ void GPUChainTracking::PrintMemoryStatistics() addToMap("TPC Clusterer Sector Peaks", usageMap, processors()->tpcClusterer[i].mPmemory->counters.nPeaks, processors()->tpcClusterer[i].mNMaxPeaks); addToMap("TPC Clusterer Sector Clusters", usageMap, processors()->tpcClusterer[i].mPmemory->counters.nClusters, processors()->tpcClusterer[i].mNMaxClusters); #endif - addToMap("TPC Start Hits", usageMap, *processors()->tpcTrackers[i].NStartHits(), processors()->tpcTrackers[i].NMaxStartHits()); - addToMap("TPC Tracklets", usageMap, *processors()->tpcTrackers[i].NTracklets(), processors()->tpcTrackers[i].NMaxTracklets()); - addToMap("TPC TrackletHits", usageMap, *processors()->tpcTrackers[i].NRowHits(), processors()->tpcTrackers[i].NMaxRowHits()); + addToMap("TPC Sector Start Hits", usageMap, *processors()->tpcTrackers[i].NStartHits(), processors()->tpcTrackers[i].NMaxStartHits()); + addToMap("TPC Sector Tracklets", usageMap, *processors()->tpcTrackers[i].NTracklets(), processors()->tpcTrackers[i].NMaxTracklets()); + addToMap("TPC Sector TrackletHits", usageMap, *processors()->tpcTrackers[i].NRowHits(), processors()->tpcTrackers[i].NMaxRowHits()); addToMap("TPC Sector Tracks", usageMap, *processors()->tpcTrackers[i].NTracks(), processors()->tpcTrackers[i].NMaxTracks()); addToMap("TPC Sector TrackHits", usageMap, *processors()->tpcTrackers[i].NTrackHits(), processors()->tpcTrackers[i].NMaxTrackHits()); } - addToMap("TPC Clusters", usageMap, mIOPtrs.clustersNative->nClustersTotal, mInputsHost->mNClusterNative); + addToMap("TPC Clusterer Clusters", usageMap, mRec->MemoryScalers()->nTPCHits, mRec->MemoryScalers()->NTPCClusters(mRec->MemoryScalers()->nTPCdigits)); addToMap("TPC Tracks", usageMap, processors()->tpcMerger.NOutputTracks(), processors()->tpcMerger.NMaxTracks()); addToMap("TPC TrackHits", usageMap, processors()->tpcMerger.NOutputTrackClusters(), processors()->tpcMerger.NMaxOutputTrackClusters()); + if (mRec->GetProcessingSettings().createO2Output) { + addToMap("TPC O2 Tracks", usageMap, processors()->tpcMerger.NOutputTracksTPCO2(), processors()->tpcMerger.NOutputTracksTPCO2()); + addToMap("TPC O2 ClusRefs", usageMap, processors()->tpcMerger.NOutputClusRefsTPCO2(), processors()->tpcMerger.NOutputClusRefsTPCO2()); + } + +#ifdef GPUCA_TPC_GEOMETRY_O2 + addToMap("TPC ComprCache HitsAttached", usageMap, processors()->tpcCompressor.mOutput->nAttachedClusters, processors()->tpcCompressor.mMaxTrackClusters); + addToMap("TPC ComprCache HitsUnattached", usageMap, processors()->tpcCompressor.mOutput->nUnattachedClusters, processors()->tpcCompressor.mMaxClustersInCache); + addToMap("TPC ComprCache Tracks", usageMap, processors()->tpcCompressor.mOutput->nTracks, processors()->tpcCompressor.mMaxTracks); +#endif + for (auto& elem : usageMap) { - GPUInfo("Mem Usage %-30s : %9lu / %9lu (%3.0f%% / %3.0f%% / count %3u / max %9lu)", elem.first.c_str(), elem.second.nSum, elem.second.nBoundSum, 100. * elem.second.nSum / std::max(1lu, elem.second.nBoundSum), 100. * elem.second.maxUse, elem.second.count, elem.second.nMax); + printf("Mem Usage %-30s : %'14lu / %'14lu (%3.0f%% / %3.0f%% / count %3u / max %'14lu)\n", elem.first.c_str(), elem.second.nSum, elem.second.nBoundSum, 100. * elem.second.nSum / std::max(1lu, elem.second.nBoundSum), 100. * elem.second.maxUse, elem.second.count, elem.second.nMax); } } @@ -192,18 +205,23 @@ void GPUChainTracking::PrintDebugOutput() void GPUChainTracking::PrintOutputStat() { int nTracks = 0, nAttachedClusters = 0, nAttachedClustersFitted = 0, nAdjacentClusters = 0; - for (unsigned int k = 0; k < mIOPtrs.nMergedTracks; k++) { - if (mIOPtrs.mergedTracks[k].OK()) { - nTracks++; - nAttachedClusters += mIOPtrs.mergedTracks[k].NClusters(); - nAttachedClustersFitted += mIOPtrs.mergedTracks[k].NClustersFitted(); - } - } unsigned int nCls = GetProcessingSettings().doublePipeline ? mIOPtrs.clustersNative->nClustersTotal : GetTPCMerger().NMaxClusters(); - for (unsigned int k = 0; k < nCls; k++) { - int attach = mIOPtrs.mergedTrackHitAttachment[k]; - if (attach & gputpcgmmergertypes::attachFlagMask) { - nAdjacentClusters++; + if (ProcessingSettings().createO2Output > 1) { + nTracks = mIOPtrs.nOutputTracksTPCO2; + nAttachedClusters = mIOPtrs.nMergedTrackHits; + } else { + for (unsigned int k = 0; k < mIOPtrs.nMergedTracks; k++) { + if (mIOPtrs.mergedTracks[k].OK()) { + nTracks++; + nAttachedClusters += mIOPtrs.mergedTracks[k].NClusters(); + nAttachedClustersFitted += mIOPtrs.mergedTracks[k].NClustersFitted(); + } + } + for (unsigned int k = 0; k < nCls; k++) { + int attach = mIOPtrs.mergedTrackHitAttachment[k]; + if (attach & gputpcgmmergertypes::attachFlagMask) { + nAdjacentClusters++; + } } } @@ -213,8 +231,8 @@ void GPUChainTracking::PrintOutputStat() int nTRDTracklets = 0; for (unsigned int k = 0; k < mIOPtrs.nTRDTracks; k++) { auto& trk = mIOPtrs.trdTracks[k]; - nTRDTracklets += trk.GetNtracklets(); - nTRDTracks += trk.GetNtracklets() != 0; + nTRDTracklets += trk.getNtracklets(); + nTRDTracks += trk.getNtracklets() != 0; } snprintf(trdText, 1024, " - TRD Tracker reconstructed %d tracks (%d tracklets)", nTRDTracks, nTRDTracklets); } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingDefs.h b/GPU/GPUTracking/Global/GPUChainTrackingDefs.h new file mode 100644 index 0000000000000..52e8fda8666b6 --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingDefs.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTracking.h +/// \author David Rohr + +#ifndef GPUCHAINTRACKINGDEFS_H +#define GPUCHAINTRACKINGDEFS_H + +#include <mutex> +#include <condition_variable> + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +struct GPUChainTrackingFinalContext { + GPUReconstruction* rec = nullptr; + std::mutex mutex; + std::condition_variable cond; + bool ready = false; +}; +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx index e5127f94654b5..63d2bf95a8067 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,11 +12,6 @@ /// \file GPUChainTrackingIO.cxx /// \author David Rohr -#ifdef HAVE_O2HEADERS -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#endif - #include "GPUChainTracking.h" #include "GPUTPCClusterData.h" #include "GPUTPCSliceOutput.h" @@ -38,7 +34,9 @@ #include "GPUMemorySizeScalers.h" #include "GPUTrackingInputProvider.h" -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" #include "GPUTPCClusterStatistics.h" #include "DataFormatsTPC/ZeroSuppression.h" #include "GPUHostDataTypes.h" @@ -58,6 +56,7 @@ using namespace GPUCA_NAMESPACE::gpu; using namespace o2::tpc; using namespace o2::trd; +using namespace o2::dataformats; static constexpr unsigned int DUMP_HEADER_SIZE = 4; static constexpr char DUMP_HEADER[DUMP_HEADER_SIZE + 1] = "CAv1"; @@ -65,7 +64,7 @@ static constexpr char DUMP_HEADER[DUMP_HEADER_SIZE + 1] = "CAv1"; GPUChainTracking::InOutMemory::InOutMemory() = default; GPUChainTracking::InOutMemory::~InOutMemory() = default; GPUChainTracking::InOutMemory::InOutMemory(GPUChainTracking::InOutMemory&&) = default; -GPUChainTracking::InOutMemory& GPUChainTracking::InOutMemory::operator=(GPUChainTracking::InOutMemory&&) = default; +GPUChainTracking::InOutMemory& GPUChainTracking::InOutMemory::operator=(GPUChainTracking::InOutMemory&&) = default; // NOLINT: False positive in clang-tidy void GPUChainTracking::DumpData(const char* filename) { @@ -77,12 +76,28 @@ void GPUChainTracking::DumpData(const char* filename) fwrite(&GPUReconstruction::geometryType, sizeof(GPUReconstruction::geometryType), 1, fp); DumpData(fp, mIOPtrs.clusterData, mIOPtrs.nClusterData, InOutPointerType::CLUSTER_DATA); DumpData(fp, mIOPtrs.rawClusters, mIOPtrs.nRawClusters, InOutPointerType::RAW_CLUSTERS); +#ifdef GPUCA_HAVE_O2HEADERS if (mIOPtrs.clustersNative) { - DumpData(fp, &mIOPtrs.clustersNative->clustersLinear, &mIOPtrs.clustersNative->nClustersTotal, InOutPointerType::CLUSTERS_NATIVE); - fwrite(&mIOPtrs.clustersNative->nClusters[0][0], sizeof(mIOPtrs.clustersNative->nClusters[0][0]), NSLICES * GPUCA_ROW_COUNT, fp); + if (DumpData(fp, &mIOPtrs.clustersNative->clustersLinear, &mIOPtrs.clustersNative->nClustersTotal, InOutPointerType::CLUSTERS_NATIVE)) { + fwrite(&mIOPtrs.clustersNative->nClusters[0][0], sizeof(mIOPtrs.clustersNative->nClusters[0][0]), NSLICES * GPUCA_ROW_COUNT, fp); + if (mIOPtrs.clustersNative->clustersMCTruth) { + const auto& buffer = mIOPtrs.clustersNative->clustersMCTruth->getBuffer(); + std::pair<const char*, size_t> tmp = {buffer.data(), buffer.size()}; + DumpData(fp, &tmp.first, &tmp.second, InOutPointerType::CLUSTER_NATIVE_MC); + } + } } if (mIOPtrs.tpcPackedDigits) { - DumpData(fp, mIOPtrs.tpcPackedDigits->tpcDigits, mIOPtrs.tpcPackedDigits->nTPCDigits, InOutPointerType::TPC_DIGIT); + if (DumpData(fp, mIOPtrs.tpcPackedDigits->tpcDigits, mIOPtrs.tpcPackedDigits->nTPCDigits, InOutPointerType::TPC_DIGIT) && mIOPtrs.tpcPackedDigits->tpcDigitsMC) { + const char* ptrs[NSLICES]; + size_t sizes[NSLICES]; + for (unsigned int i = 0; i < NSLICES; i++) { + const auto& buffer = mIOPtrs.tpcPackedDigits->tpcDigitsMC->v[i]->getBuffer(); + ptrs[i] = buffer.data(); + sizes[i] = buffer.size(); + } + DumpData(fp, ptrs, sizes, InOutPointerType::TPC_DIGIT_MC); + } } if (mIOPtrs.tpcZS) { size_t total = 0; @@ -107,18 +122,29 @@ void GPUChainTracking::DumpData(const char* filename) } } total *= TPCZSHDR::TPC_ZS_PAGE_SIZE; - DumpData(fp, &ptr, &total, InOutPointerType::TPC_ZS); - fwrite(&counts, sizeof(counts), 1, fp); + if (DumpData(fp, &ptr, &total, InOutPointerType::TPC_ZS)) { + fwrite(&counts, sizeof(counts), 1, fp); + } + } + if (mIOPtrs.settingsTF) { + unsigned int n = 1; + DumpData(fp, &mIOPtrs.settingsTF, &n, InOutPointerType::TF_SETTINGS); } +#endif DumpData(fp, mIOPtrs.sliceTracks, mIOPtrs.nSliceTracks, InOutPointerType::SLICE_OUT_TRACK); DumpData(fp, mIOPtrs.sliceClusters, mIOPtrs.nSliceClusters, InOutPointerType::SLICE_OUT_CLUSTER); DumpData(fp, &mIOPtrs.mcLabelsTPC, &mIOPtrs.nMCLabelsTPC, InOutPointerType::MC_LABEL_TPC); DumpData(fp, &mIOPtrs.mcInfosTPC, &mIOPtrs.nMCInfosTPC, InOutPointerType::MC_INFO_TPC); + DumpData(fp, &mIOPtrs.mcInfosTPCCol, &mIOPtrs.nMCInfosTPCCol, InOutPointerType::MC_INFO_TPC); DumpData(fp, &mIOPtrs.mergedTracks, &mIOPtrs.nMergedTracks, InOutPointerType::MERGED_TRACK); DumpData(fp, &mIOPtrs.mergedTrackHits, &mIOPtrs.nMergedTrackHits, InOutPointerType::MERGED_TRACK_HIT); DumpData(fp, &mIOPtrs.trdTracks, &mIOPtrs.nTRDTracks, InOutPointerType::TRD_TRACK); DumpData(fp, &mIOPtrs.trdTracklets, &mIOPtrs.nTRDTracklets, InOutPointerType::TRD_TRACKLET); - DumpData(fp, &mIOPtrs.trdTrackletsMC, &mIOPtrs.nTRDTrackletsMC, InOutPointerType::TRD_TRACKLET_MC); + if (mIOPtrs.trdSpacePoints) { + DumpData(fp, &mIOPtrs.trdSpacePoints, &mIOPtrs.nTRDTracklets, InOutPointerType::TRD_SPACEPOINT); + } + DumpData(fp, &mIOPtrs.trdTriggerTimes, &mIOPtrs.nTRDTriggerRecords, InOutPointerType::TRD_TRIGGERRECORDS); + DumpData(fp, &mIOPtrs.trdTrackletIdxFirst, &mIOPtrs.nTRDTriggerRecords, InOutPointerType::TRD_TRIGGERRECORDS); fclose(fp); } @@ -149,16 +175,32 @@ int GPUChainTracking::ReadData(const char* filename) AliHLTTPCRawCluster* ptrRawClusters[NSLICES]; ReadData(fp, mIOPtrs.rawClusters, mIOPtrs.nRawClusters, mIOMem.rawClusters, InOutPointerType::RAW_CLUSTERS, ptrRawClusters); int nClustersTotal = 0; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS mIOMem.clusterNativeAccess.reset(new ClusterNativeAccess); if (ReadData<ClusterNative>(fp, &mIOMem.clusterNativeAccess->clustersLinear, &mIOMem.clusterNativeAccess->nClustersTotal, &mIOMem.clustersNative, InOutPointerType::CLUSTERS_NATIVE)) { r = fread(&mIOMem.clusterNativeAccess->nClusters[0][0], sizeof(mIOMem.clusterNativeAccess->nClusters[0][0]), NSLICES * GPUCA_ROW_COUNT, fp); mIOMem.clusterNativeAccess->setOffsetPtrs(); mIOPtrs.clustersNative = mIOMem.clusterNativeAccess.get(); + std::pair<const char*, size_t> tmp = {nullptr, 0}; + if (ReadData(fp, &tmp.first, &tmp.second, &mIOMem.clusterNativeMC, InOutPointerType::CLUSTER_NATIVE_MC)) { + mIOMem.clusterNativeMCView = std::make_unique<ConstMCLabelContainerView>(gsl::span<const char>(tmp.first, tmp.first + tmp.second)); + mIOMem.clusterNativeAccess->clustersMCTruth = mIOMem.clusterNativeMCView.get(); + } } mIOMem.digitMap.reset(new GPUTrackingInOutDigits); if (ReadData(fp, mIOMem.digitMap->tpcDigits, mIOMem.digitMap->nTPCDigits, mIOMem.tpcDigits, InOutPointerType::TPC_DIGIT)) { mIOPtrs.tpcPackedDigits = mIOMem.digitMap.get(); + const char* ptrs[NSLICES]; + size_t sizes[NSLICES]; + if (ReadData(fp, ptrs, sizes, mIOMem.tpcDigitsMC, InOutPointerType::TPC_DIGIT_MC)) { + mIOMem.tpcDigitMCMap = std::make_unique<GPUTPCDigitsMCInput>(); + mIOMem.tpcDigitMCView.reset(new ConstMCLabelContainerView[NSLICES]); + for (unsigned int i = 0; i < NSLICES; i++) { + mIOMem.tpcDigitMCView.get()[i] = gsl::span<const char>(ptrs[i], ptrs[i] + sizes[i]); + mIOMem.tpcDigitMCMap->v[i] = mIOMem.tpcDigitMCView.get() + i; + } + mIOMem.digitMap->tpcDigitsMC = mIOMem.tpcDigitMCMap.get(); + } } const char* ptr; size_t total; @@ -181,17 +223,31 @@ int GPUChainTracking::ReadData(const char* filename) } mIOPtrs.tpcZS = mIOMem.tpcZSmeta.get(); } + unsigned int n; + ReadData(fp, &mIOPtrs.settingsTF, &n, &mIOMem.settingsTF, InOutPointerType::TF_SETTINGS); #endif ReadData(fp, mIOPtrs.sliceTracks, mIOPtrs.nSliceTracks, mIOMem.sliceTracks, InOutPointerType::SLICE_OUT_TRACK); ReadData(fp, mIOPtrs.sliceClusters, mIOPtrs.nSliceClusters, mIOMem.sliceClusters, InOutPointerType::SLICE_OUT_CLUSTER); ReadData(fp, &mIOPtrs.mcLabelsTPC, &mIOPtrs.nMCLabelsTPC, &mIOMem.mcLabelsTPC, InOutPointerType::MC_LABEL_TPC); ReadData(fp, &mIOPtrs.mcInfosTPC, &mIOPtrs.nMCInfosTPC, &mIOMem.mcInfosTPC, InOutPointerType::MC_INFO_TPC); + ReadData(fp, &mIOPtrs.mcInfosTPCCol, &mIOPtrs.nMCInfosTPCCol, &mIOMem.mcInfosTPCCol, InOutPointerType::MC_INFO_TPC); ReadData(fp, &mIOPtrs.mergedTracks, &mIOPtrs.nMergedTracks, &mIOMem.mergedTracks, InOutPointerType::MERGED_TRACK); ReadData(fp, &mIOPtrs.mergedTrackHits, &mIOPtrs.nMergedTrackHits, &mIOMem.mergedTrackHits, InOutPointerType::MERGED_TRACK_HIT); ReadData(fp, &mIOPtrs.trdTracks, &mIOPtrs.nTRDTracks, &mIOMem.trdTracks, InOutPointerType::TRD_TRACK); ReadData(fp, &mIOPtrs.trdTracklets, &mIOPtrs.nTRDTracklets, &mIOMem.trdTracklets, InOutPointerType::TRD_TRACKLET); - ReadData(fp, &mIOPtrs.trdTrackletsMC, &mIOPtrs.nTRDTrackletsMC, &mIOMem.trdTrackletsMC, InOutPointerType::TRD_TRACKLET_MC); + unsigned int dummy = 0; + ReadData(fp, &mIOPtrs.trdSpacePoints, &dummy, &mIOMem.trdSpacePoints, InOutPointerType::TRD_SPACEPOINT); + ReadData(fp, &mIOPtrs.trdTriggerTimes, &mIOPtrs.nTRDTriggerRecords, &mIOMem.trdTriggerTimes, InOutPointerType::TRD_TRIGGERRECORDS); + ReadData(fp, &mIOPtrs.trdTrackletIdxFirst, &mIOPtrs.nTRDTriggerRecords, &mIOMem.trdTrackletIdxFirst, InOutPointerType::TRD_TRIGGERRECORDS); + + size_t fptr = ftell(fp); + fseek(fp, 0, SEEK_END); + size_t fend = ftell(fp); fclose(fp); + if (fptr != fend) { + GPUError("Error reading data file, reading incomplete"); + return 1; + } (void)r; for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int j = 0; j < mIOPtrs.nClusterData[i]; j++) { @@ -224,12 +280,12 @@ void GPUChainTracking::DumpSettings(const char* dir) f += "tpctransform.dump"; DumpFlatObjectToFile(processors()->calibObjects.fastTransform, f.c_str()); } - if (processors()->calibObjects.tpcCalibration != nullptr) { + if (processors()->calibObjects.tpcPadGain != nullptr) { f = dir; - f += "tpccalibration.dump"; - DumpStructToFile(processors()->calibObjects.tpcCalibration, f.c_str()); + f += "tpcpadgaincalib.dump"; + DumpStructToFile(processors()->calibObjects.tpcPadGain, f.c_str()); } -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS if (processors()->calibObjects.dEdxSplines != nullptr) { f = dir; f += "dedxsplines.dump"; @@ -257,10 +313,10 @@ void GPUChainTracking::ReadSettings(const char* dir) mTPCFastTransformU = ReadFlatObjectFromFile<TPCFastTransform>(f.c_str()); processors()->calibObjects.fastTransform = mTPCFastTransformU.get(); f = dir; - f += "tpccalibration.dump"; - mTPCCalibrationU = ReadStructFromFile<TPCCFCalibration>(f.c_str()); - processors()->calibObjects.tpcCalibration = mTPCCalibrationU.get(); -#ifdef HAVE_O2HEADERS + f += "tpcpadgaincalib.dump"; + mTPCPadGainCalibU = ReadStructFromFile<TPCPadGainCalib>(f.c_str()); + processors()->calibObjects.tpcPadGain = mTPCPadGainCalibU.get(); +#ifdef GPUCA_HAVE_O2HEADERS f = dir; f += "dedxsplines.dump"; mdEdxSplinesU = ReadFlatObjectFromFile<TPCdEdxCalibrationSplines>(f.c_str()); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx new file mode 100644 index 0000000000000..bf34addbe215a --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx @@ -0,0 +1,346 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingMerger.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "utils/strtag.h" +#include <fstream> + +using namespace GPUCA_NAMESPACE::gpu; + +void GPUChainTracking::RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, char mergeMode, GPUReconstruction::krnlDeviceType deviceType) +{ + unsigned int n = withinSlice == -1 ? NSLICES / 2 : NSLICES; + bool doGPUall = GetRecoStepsGPU() & RecoStep::TPCMerging && GetProcessingSettings().fullMergerOnGPU; + if (GetProcessingSettings().alternateBorderSort && (!mRec->IsGPU() || doGPUall)) { + GPUTPCGMMerger& Merger = processors()->tpcMerger; + GPUTPCGMMerger& MergerShadow = doGPUall ? processorsShadow()->tpcMerger : Merger; + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->init); + RecordMarker(&mEvents->single, 0); + for (unsigned int i = 0; i < n; i++) { + int stream = i % mRec->NStreams(); + runKernel<GPUTPCGMMergerMergeBorders, 0>(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, stream && i < (unsigned int)mRec->NStreams() ? &mEvents->single : nullptr}, i, withinSlice, mergeMode); + } + ReleaseEvent(&mEvents->single); + SynchronizeEventAndRelease(&mEvents->init); + for (unsigned int i = 0; i < n; i++) { + int stream = i % mRec->NStreams(); + int n1, n2; + GPUTPCGMBorderTrack *b1, *b2; + int jSlice; + Merger.MergeBorderTracksSetup(n1, n2, b1, b2, jSlice, i, withinSlice, mergeMode); + gputpcgmmergertypes::GPUTPCGMBorderRange* range1 = MergerShadow.BorderRange(i); + gputpcgmmergertypes::GPUTPCGMBorderRange* range2 = MergerShadow.BorderRange(jSlice) + *processors()->tpcTrackers[jSlice].NTracks(); + runKernel<GPUTPCGMMergerMergeBorders, 3>({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range1, n1, 0); + runKernel<GPUTPCGMMergerMergeBorders, 3>({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range2, n2, 1); + deviceEvent** e = nullptr; + int ne = 0; + if (i == n - 1) { // Synchronize all execution on stream 0 with the last kernel + ne = std::min<int>(n, mRec->NStreams()); + for (int j = 1; j < ne; j++) { + RecordMarker(&mEvents->slice[j], j); + } + e = &mEvents->slice[1]; + ne--; + stream = 0; + } + runKernel<GPUTPCGMMergerMergeBorders, 2>(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, e, ne}, i, withinSlice, mergeMode); + } + } else { + for (unsigned int i = 0; i < n; i++) { + runKernel<GPUTPCGMMergerMergeBorders, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); + } + runKernel<GPUTPCGMMergerMergeBorders, 1>({2 * n, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 0, withinSlice, mergeMode); + for (unsigned int i = 0; i < n; i++) { + runKernel<GPUTPCGMMergerMergeBorders, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); + } + } + mRec->ReturnVolatileDeviceMemory(); +} + +void GPUChainTracking::RunTPCTrackingMerger_Resolve(char useOrigTrackParam, char mergeAll, GPUReconstruction::krnlDeviceType deviceType) +{ + runKernel<GPUTPCGMMergerResolve, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerResolve, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerResolve, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerResolve, 3>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerResolve, 4>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, useOrigTrackParam, mergeAll); +} + +int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) +{ + if (GetProcessingSettings().debugLevel >= 6 && GetProcessingSettings().comparableDebutOutput && param().rec.tpc.mergerReadFromTrackerDirectly) { + for (unsigned int i = 0; i < NSLICES; i++) { + GPUTPCTracker& trk = processors()->tpcTrackers[i]; + TransferMemoryResourcesToHost(RecoStep::NoRecoStep, &trk); + auto sorter = [](GPUTPCTrack& trk1, GPUTPCTrack& trk2) { + if (trk1.NHits() == trk2.NHits()) { + return trk1.Param().Y() > trk2.Param().Y(); + } + return trk1.NHits() > trk2.NHits(); + }; + std::sort(trk.Tracks(), trk.Tracks() + trk.CommonMemory()->nLocalTracks, sorter); + std::sort(trk.Tracks() + trk.CommonMemory()->nLocalTracks, trk.Tracks() + *trk.NTracks(), sorter); + TransferMemoryResourcesToGPU(RecoStep::NoRecoStep, &trk, 0); + } + } + mRec->PushNonPersistentMemory(qStr2Tag("TPCMERGE")); + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCMerging; + bool doGPUall = doGPU && GetProcessingSettings().fullMergerOnGPU; + GPUReconstruction::krnlDeviceType deviceType = doGPUall ? GPUReconstruction::krnlDeviceType::Auto : GPUReconstruction::krnlDeviceType::CPU; + unsigned int numBlocks = (!mRec->IsGPU() || doGPUall) ? BlockCount() : 1; + GPUTPCGMMerger& Merger = processors()->tpcMerger; + GPUTPCGMMerger& MergerShadow = doGPU ? processorsShadow()->tpcMerger : Merger; + GPUTPCGMMerger& MergerShadowAll = doGPUall ? processorsShadow()->tpcMerger : Merger; + const int outputStream = mRec->NStreams() - 2; + if (GetProcessingSettings().debugLevel >= 2) { + GPUInfo("Running TPC Merger"); + } + const auto& threadContext = GetThreadContext(); + + SynchronizeGPU(); // Need to know the full number of slice tracks + SetupGPUProcessor(&Merger, true); + AllocateRegisteredMemory(Merger.MemoryResOutput(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)]); + AllocateRegisteredMemory(Merger.MemoryResOutputState(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::sharedClusterMap)]); + + if (Merger.CheckSlices()) { + return 1; + } + + memset(Merger.Memory(), 0, sizeof(*Merger.Memory())); + WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); + if (doGPUall) { + TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); + } + + for (unsigned int i = 0; i < NSLICES; i++) { + runKernel<GPUTPCGMMergerUnpackResetIds>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); + runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, i); + runKernel<GPUTPCGMMergerSliceRefit>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); + } + for (unsigned int i = 0; i < NSLICES; i++) { + runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, NSLICES + i); + runKernel<GPUTPCGMMergerUnpackGlobal>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); + } + runKernel<GPUTPCGMMergerUnpackSaveNumber>({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 2 * NSLICES); + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpSliceTracks, *mDebugFile); + + runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 0); + runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel<GPUTPCGMMergerMergeWithinPrepare>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + RunTPCTrackingMerger_MergeBorderTracks(1, 0, deviceType); + RunTPCTrackingMerger_Resolve(0, 1, deviceType); + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedWithinSlices, *mDebugFile); + + runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 0); + runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 2, 3, 0); + RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); + RunTPCTrackingMerger_Resolve(0, 1, deviceType); + runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 0); + RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); + RunTPCTrackingMerger_Resolve(0, 1, deviceType); + runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel<GPUTPCGMMergerMergeSlicesPrepare>(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 1); + RunTPCTrackingMerger_MergeBorderTracks(0, -1, deviceType); + RunTPCTrackingMerger_Resolve(0, 1, deviceType); + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedBetweenSlices, *mDebugFile); + + runKernel<GPUMemClean16>({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + + runKernel<GPUTPCGMMergerLinkGlobalTracks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerCollect>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpCollected, *mDebugFile); + + runKernel<GPUTPCGMMergerClearLinks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 1); + RunTPCTrackingMerger_MergeBorderTracks(-1, 1, deviceType); + RunTPCTrackingMerger_MergeBorderTracks(-1, 2, deviceType); + runKernel<GPUTPCGMMergerMergeCE>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpMergeCE, *mDebugFile); + int waitForTransfer = 0; + if (doGPUall) { + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->single); + waitForTransfer = 1; + } + + if (GetProcessingSettings().mergerSortTracks) { + runKernel<GPUTPCGMMergerSortTracksPrepare>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + CondWaitEvent(waitForTransfer, &mEvents->single); + runKernel<GPUTPCGMMergerSortTracks>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + } + + unsigned int maxId = param().rec.nonConsecutiveIDs ? Merger.Memory()->nOutputTrackClusters : Merger.NMaxClusters(); + if (maxId > Merger.NMaxClusters()) { + throw std::runtime_error("mNMaxClusters too small"); + } + if (!param().rec.nonConsecutiveIDs) { + runKernel<GPUMemClean16>({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.SharedCount(), maxId * sizeof(*MergerShadowAll.SharedCount())); + runKernel<GPUMemClean16>({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.ClusterAttachment(), maxId * sizeof(*MergerShadowAll.ClusterAttachment())); + runKernel<GPUTPCGMMergerPrepareClusters, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + CondWaitEvent(waitForTransfer, &mEvents->single); + runKernel<GPUTPCGMMergerSortTracksQPt>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerPrepareClusters, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerPrepareClusters, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + } + + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpFitPrepare, *mDebugFile); + + if (doGPUall) { + CondWaitEvent(waitForTransfer, &mEvents->single); + if (waitForTransfer) { + ReleaseEvent(&mEvents->single); + } + } else if (doGPU) { + TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); + } + + if (GetProcessingSettings().delayedOutput) { + for (unsigned int i = 0; i < mOutputQueue.size(); i++) { + GPUMemCpy(mOutputQueue[i].step, mOutputQueue[i].dst, mOutputQueue[i].src, mOutputQueue[i].size, outputStream, false); + } + mOutputQueue.clear(); + } + + runKernel<GPUTPCGMMergerTrackFit>(doGPU ? GetGrid(Merger.NOutputTracks(), 0) : GetGridAuto(0), krnlRunRangeNone, krnlEventNone, GetProcessingSettings().mergerSortTracks ? 1 : 0); + if (param().rec.tpc.retryRefit == 1) { + runKernel<GPUTPCGMMergerTrackFit>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone, -1); + } + if (param().rec.tpc.loopInterpolationInExtraPass) { + runKernel<GPUTPCGMMergerFollowLoopers>(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); + } + if (doGPU && !doGPUall) { + TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, 0); + SynchronizeStream(0); + } + + DoDebugAndDump(RecoStep::TPCMerging, 0, Merger, &GPUTPCGMMerger::DumpRefit, *mDebugFile); + runKernel<GPUTPCGMMergerFinalize, 0>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + if (!param().rec.nonConsecutiveIDs) { + runKernel<GPUTPCGMMergerFinalize, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerFinalize, 2>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + } + if (param().rec.tpc.mergeLoopersAfterburner) { + runKernel<GPUTPCGMMergerMergeLoopers, 0>(doGPUall ? GetGrid(Merger.NOutputTracks(), 0, deviceType) : GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0); + SynchronizeStream(0); + runKernel<GPUTPCGMMergerMergeLoopers, 1>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel<GPUTPCGMMergerMergeLoopers, 2>(doGPUall ? GetGrid(Merger.Memory()->nLooperMatchCandidates, 0, deviceType) : GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + } + DoDebugAndDump(RecoStep::TPCMerging, 0, doGPUall, Merger, &GPUTPCGMMerger::DumpFinal, *mDebugFile); + + if (doGPUall) { + RecordMarker(&mEvents->single, 0); + if (!GetProcessingSettings().fullMergerOnGPU) { + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutput(), outputStream, nullptr, &mEvents->single); + } else if (GetProcessingSettings().keepDisplayMemory || GetProcessingSettings().createO2Output <= 1) { + GPUMemCpy(RecoStep::TPCMerging, Merger.OutputTracks(), MergerShadowAll.OutputTracks(), Merger.NOutputTracks() * sizeof(*Merger.OutputTracks()), outputStream, 0, nullptr, &mEvents->single); + if (param().par.dodEdx) { + GPUMemCpy(RecoStep::TPCMerging, Merger.OutputTracksdEdx(), MergerShadowAll.OutputTracksdEdx(), Merger.NOutputTracks() * sizeof(*Merger.OutputTracksdEdx()), outputStream, 0, nullptr, &mEvents->single); + } + GPUMemCpy(RecoStep::TPCMerging, Merger.Clusters(), MergerShadowAll.Clusters(), Merger.NOutputTrackClusters() * sizeof(*Merger.Clusters()), outputStream, 0); + if (param().par.earlyTpcTransform) { + GPUMemCpy(RecoStep::TPCMerging, Merger.ClustersXYZ(), MergerShadowAll.ClustersXYZ(), Merger.NOutputTrackClusters() * sizeof(*Merger.ClustersXYZ()), outputStream, 0); + } + GPUMemCpy(RecoStep::TPCMerging, Merger.ClusterAttachment(), MergerShadowAll.ClusterAttachment(), Merger.NMaxClusters() * sizeof(*Merger.ClusterAttachment()), outputStream, 0); + } + ReleaseEvent(&mEvents->single); + } else { + TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); + } + if (GetProcessingSettings().keepDisplayMemory && !GetProcessingSettings().keepAllMemory) { + TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, -1, true); + } + + mRec->ReturnVolatileDeviceMemory(); + mRec->PopNonPersistentMemory(RecoStep::TPCMerging, qStr2Tag("TPCMERGE")); + +#ifdef GPUCA_TPC_GEOMETRY_O2 + if (GetProcessingSettings().createO2Output) { + if (mTPCSliceScratchOnStack) { + mRec->PopNonPersistentMemory(RecoStep::TPCSliceTracking, qStr2Tag("TPCSLCD1")); // Return the slice data memory early + mTPCSliceScratchOnStack = false; + } + + mRec->PushNonPersistentMemory(qStr2Tag("TPCMERG2")); + AllocateRegisteredMemory(Merger.MemoryResOutputO2Scratch()); + WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); + runKernel<GPUTPCGMO2Output, GPUTPCGMO2Output::prepare>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->single); + runKernel<GPUTPCGMO2Output, GPUTPCGMO2Output::sort>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + mRec->ReturnVolatileDeviceMemory(); + SynchronizeEventAndRelease(&mEvents->single, doGPUall); + + if (GetProcessingSettings().clearO2OutputFromGPU) { + mRec->AllocateVolatileDeviceMemory(0); // make future device memory allocation volatile + } + AllocateRegisteredMemory(Merger.MemoryResOutputO2(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2)]); + AllocateRegisteredMemory(Merger.MemoryResOutputO2Clus(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2ClusRefs)]); + WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); + runKernel<GPUTPCGMO2Output, GPUTPCGMO2Output::output>(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + + if (GetProcessingSettings().runMC && mIOPtrs.clustersNative && mIOPtrs.clustersNative->clustersMCTruth) { + AllocateRegisteredMemory(Merger.MemoryResOutputO2MC(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2Labels)]); + TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, -1, true); + runKernel<GPUTPCGMO2Output, GPUTPCGMO2Output::mc>(GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU), krnlRunRangeNone, krnlEventNone); + } else if (doGPUall) { + RecordMarker(&mEvents->single, 0); + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutputO2(), outputStream, nullptr, &mEvents->single); + TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutputO2Clus(), outputStream); + ReleaseEvent(&mEvents->single); + } + mRec->PopNonPersistentMemory(RecoStep::TPCMerging, qStr2Tag("TPCMERG2")); + } +#endif + if (synchronizeOutput || GetProcessingSettings().clearO2OutputFromGPU) { + SynchronizeStream(outputStream); + } + if (GetProcessingSettings().clearO2OutputFromGPU) { + mRec->ReturnVolatileDeviceMemory(); + } + + mIOPtrs.mergedTracks = Merger.OutputTracks(); + mIOPtrs.nMergedTracks = Merger.NOutputTracks(); + mIOPtrs.mergedTrackHits = Merger.Clusters(); + mIOPtrs.mergedTrackHitsXYZ = Merger.ClustersXYZ(); + mIOPtrs.nMergedTrackHits = Merger.NOutputTrackClusters(); + mIOPtrs.mergedTrackHitAttachment = Merger.ClusterAttachment(); + mIOPtrs.mergedTrackHitStates = Merger.ClusterStateExt(); + mIOPtrs.outputTracksTPCO2 = Merger.OutputTracksTPCO2(); + mIOPtrs.nOutputTracksTPCO2 = Merger.NOutputTracksTPCO2(); + mIOPtrs.outputClusRefsTPCO2 = Merger.OutputClusRefsTPCO2(); + mIOPtrs.nOutputClusRefsTPCO2 = Merger.NOutputClusRefsTPCO2(); + mIOPtrs.outputTracksTPCO2MC = Merger.OutputTracksTPCO2MC(); + + if (doGPU) { + processorsShadow()->ioPtrs.mergedTracks = MergerShadow.OutputTracks(); + processorsShadow()->ioPtrs.nMergedTracks = Merger.NOutputTracks(); + processorsShadow()->ioPtrs.mergedTrackHits = MergerShadow.Clusters(); + processorsShadow()->ioPtrs.mergedTrackHitsXYZ = MergerShadow.ClustersXYZ(); + processorsShadow()->ioPtrs.nMergedTrackHits = Merger.NOutputTrackClusters(); + processorsShadow()->ioPtrs.mergedTrackHitAttachment = MergerShadow.ClusterAttachment(); + processorsShadow()->ioPtrs.mergedTrackHitStates = MergerShadow.ClusterStateExt(); + processorsShadow()->ioPtrs.outputTracksTPCO2 = MergerShadow.OutputTracksTPCO2(); + processorsShadow()->ioPtrs.nOutputTracksTPCO2 = Merger.NOutputTracksTPCO2(); + processorsShadow()->ioPtrs.outputClusRefsTPCO2 = MergerShadow.OutputClusRefsTPCO2(); + processorsShadow()->ioPtrs.nOutputClusRefsTPCO2 = Merger.NOutputClusRefsTPCO2(); + WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); + } + + if (GetProcessingSettings().debugLevel >= 2) { + GPUInfo("TPC Merger Finished (output clusters %d / input clusters %d)", Merger.NOutputTrackClusters(), Merger.NClusters()); + } + return 0; +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx b/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx new file mode 100644 index 0000000000000..2aaa4fded4969 --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingRefit.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" + +using namespace GPUCA_NAMESPACE::gpu; + +int GPUChainTracking::RunRefit() +{ +#ifdef GPUCA_HAVE_O2HEADERS + bool doGPU = GetRecoStepsGPU() & RecoStep::Refit; + GPUTrackingRefitProcessor& Refit = processors()->trackingRefit; + GPUTrackingRefitProcessor& RefitShadow = doGPU ? processorsShadow()->trackingRefit : Refit; + + const auto& threadContext = GetThreadContext(); + SetupGPUProcessor(&Refit, false); + RefitShadow.SetPtrsFromGPUConstantMem(processorsShadow(), doGPU ? &processorsDevice()->param : nullptr); + RefitShadow.SetPropagator(doGPU ? processorsShadow()->calibObjects.o2Propagator : GetO2Propagator()); + RefitShadow.mPTracks = (doGPU ? processorsShadow() : processors())->tpcMerger.OutputTracks(); + WriteToConstantMemory(RecoStep::Refit, (char*)&processors()->trackingRefit - (char*)processors(), &RefitShadow, sizeof(RefitShadow), 0); + //TransferMemoryResourcesToGPU(RecoStep::Refit, &Refit, 0); + if (param().rec.trackingRefitGPUModel) { + runKernel<GPUTrackingRefitKernel, GPUTrackingRefitKernel::mode0asGPU>(GetGrid(mIOPtrs.nMergedTracks, 0), krnlRunRangeNone); + } else { + runKernel<GPUTrackingRefitKernel, GPUTrackingRefitKernel::mode1asTrackParCov>(GetGrid(mIOPtrs.nMergedTracks, 0), krnlRunRangeNone); + } + //TransferMemoryResourcesToHost(RecoStep::Refit, &Refit, 0); + SynchronizeStream(0); +#endif + return 0; +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx new file mode 100644 index 0000000000000..c976af9738b59 --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx @@ -0,0 +1,497 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingSliceTracker.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "GPUMemorySizeScalers.h" +#include "GPUTPCClusterData.h" +#include "utils/strtag.h" +#include <fstream> + +using namespace GPUCA_NAMESPACE::gpu; + +int GPUChainTracking::GlobalTracking(unsigned int iSlice, int threadId, bool synchronizeOutput) +{ + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("GPU Tracker running Global Tracking for slice %u on thread %d\n", iSlice, threadId); + } + + GPUReconstruction::krnlDeviceType deviceType = GetProcessingSettings().fullMergerOnGPU ? GPUReconstruction::krnlDeviceType::Auto : GPUReconstruction::krnlDeviceType::CPU; + runKernel<GPUTPCGlobalTracking>(GetGridBlk(256, iSlice % mRec->NStreams(), deviceType), {iSlice}); + if (GetProcessingSettings().fullMergerOnGPU) { + TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[iSlice].MemoryResCommon(), iSlice % mRec->NStreams()); + } + if (synchronizeOutput) { + SynchronizeStream(iSlice % mRec->NStreams()); + } + + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("GPU Tracker finished Global Tracking for slice %u on thread %d\n", iSlice, threadId); + } + return (0); +} + +int GPUChainTracking::RunTPCTrackingSlices() +{ + if (mRec->GPUStuck()) { + GPUWarning("This GPU is stuck, processing of tracking for this event is skipped!"); + return (1); + } + + const auto& threadContext = GetThreadContext(); + + int retVal = RunTPCTrackingSlices_internal(); + if (retVal) { + SynchronizeGPU(); + } + if (retVal >= 2) { + ResetHelperThreads(retVal >= 3); + } + return (retVal != 0); +} + +int GPUChainTracking::RunTPCTrackingSlices_internal() +{ + if (GetProcessingSettings().debugLevel >= 2) { + GPUInfo("Running TPC Slice Tracker"); + } + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCSliceTracking; + bool doSliceDataOnGPU = processors()->tpcTrackers[0].SliceDataOnGPU(); + if (!param().par.earlyTpcTransform) { + for (unsigned int i = 0; i < NSLICES; i++) { + processors()->tpcTrackers[i].Data().SetClusterData(nullptr, mIOPtrs.clustersNative->nClustersSector[i], mIOPtrs.clustersNative->clusterOffset[i][0]); + if (doGPU) { + processorsShadow()->tpcTrackers[i].Data().SetClusterData(nullptr, mIOPtrs.clustersNative->nClustersSector[i], mIOPtrs.clustersNative->clusterOffset[i][0]); // TODO: not needed I think, anyway copied in SetupGPUProcessor + } + } + mRec->MemoryScalers()->nTPCHits = mIOPtrs.clustersNative->nClustersTotal; + } else { + int offset = 0; + for (unsigned int i = 0; i < NSLICES; i++) { + processors()->tpcTrackers[i].Data().SetClusterData(mIOPtrs.clusterData[i], mIOPtrs.nClusterData[i], offset); +#ifdef GPUCA_HAVE_O2HEADERS + if (doGPU && GetRecoSteps().isSet(RecoStep::TPCConversion)) { + processorsShadow()->tpcTrackers[i].Data().SetClusterData(processorsShadow()->tpcConverter.mClusters + processors()->tpcTrackers[i].Data().ClusterIdOffset(), processors()->tpcTrackers[i].NHitsTotal(), processors()->tpcTrackers[i].Data().ClusterIdOffset()); + } +#endif + offset += mIOPtrs.nClusterData[i]; + } + mRec->MemoryScalers()->nTPCHits = offset; + } + GPUInfo("Event has %u TPC Clusters, %d TRD Tracklets", (unsigned int)mRec->MemoryScalers()->nTPCHits, mIOPtrs.nTRDTracklets); + + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + processors()->tpcTrackers[iSlice].SetMaxData(mIOPtrs); // First iteration to set data sizes + } + mRec->ComputeReuseMax(nullptr); // Resolve maximums for shared buffers + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + SetupGPUProcessor(&processors()->tpcTrackers[iSlice], false); // Prepare custom allocation for 1st stack level + mRec->AllocateRegisteredMemory(processors()->tpcTrackers[iSlice].MemoryResSliceScratch()); + mRec->AllocateRegisteredMemory(processors()->tpcTrackers[iSlice].MemoryResSliceInput()); + } + mRec->PushNonPersistentMemory(qStr2Tag("TPCSLTRK")); + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + SetupGPUProcessor(&processors()->tpcTrackers[iSlice], true); // Now we allocate + mRec->ResetRegisteredMemoryPointers(&processors()->tpcTrackers[iSlice]); // TODO: The above call breaks the GPU ptrs to already allocated memory. This fixes them. Should actually be cleaned up at the source. + processors()->tpcTrackers[iSlice].SetupCommonMemory(); + } + + bool streamInit[GPUCA_MAX_STREAMS] = {false}; + if (doGPU) { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + processorsShadow()->tpcTrackers[iSlice].GPUParametersConst()->gpumem = (char*)mRec->DeviceMemoryBase(); + // Initialize Startup Constants + processors()->tpcTrackers[iSlice].GPUParameters()->nextStartHit = (((getKernelProperties<GPUTPCTrackletConstructor, GPUTPCTrackletConstructor::allSlices>().minBlocks * BlockCount()) + NSLICES - 1 - iSlice) / NSLICES) * getKernelProperties<GPUTPCTrackletConstructor, GPUTPCTrackletConstructor::allSlices>().nThreads; + processorsShadow()->tpcTrackers[iSlice].SetGPUTextureBase(mRec->DeviceMemoryBase()); + } + + if (!doSliceDataOnGPU) { + RunHelperThreads(&GPUChainTracking::HelperReadEvent, this, NSLICES); + } + if (PrepareTextures()) { + return (2); + } + + // Copy Tracker Object to GPU Memory + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Copying Tracker objects to GPU"); + } + if (PrepareProfile()) { + return 2; + } + + WriteToConstantMemory(RecoStep::TPCSliceTracking, (char*)processors()->tpcTrackers - (char*)processors(), processorsShadow()->tpcTrackers, sizeof(GPUTPCTracker) * NSLICES, mRec->NStreams() - 1, &mEvents->init); + + for (int i = 0; i < mRec->NStreams() - 1; i++) { + streamInit[i] = false; + } + streamInit[mRec->NStreams() - 1] = true; + } + if (GPUDebug("Initialization (1)", 0)) { + return (2); + } + + int streamMap[NSLICES]; + + bool error = false; + GPUCA_OPENMP(parallel for if(!doGPU && GetProcessingSettings().ompKernels != 1) num_threads(mRec->SetAndGetNestedLoopOmpFactor(!doGPU, NSLICES))) + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + GPUTPCTracker& trk = processors()->tpcTrackers[iSlice]; + GPUTPCTracker& trkShadow = doGPU ? processorsShadow()->tpcTrackers[iSlice] : trk; + int useStream = (iSlice % mRec->NStreams()); + + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Creating Slice Data (Slice %d)", iSlice); + } + if (doSliceDataOnGPU) { + TransferMemoryResourcesToGPU(RecoStep::TPCSliceTracking, &trk, useStream); + runKernel<GPUTPCCreateSliceData>(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); + streamInit[useStream] = true; + } else if (!doGPU || iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) == 0) { + if (ReadEvent(iSlice, 0)) { + GPUError("Error reading event"); + error = 1; + continue; + } + } else { + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Waiting for helper thread %d", iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1); + } + while (HelperDone(iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1) < (int)iSlice) { + ; + } + if (HelperError(iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) - 1)) { + error = 1; + continue; + } + } + if (!doGPU && trk.CheckEmptySlice() && GetProcessingSettings().debugLevel == 0) { + continue; + } + + if (GetProcessingSettings().debugLevel >= 6) { + *mDebugFile << "\n\nReconstruction: Slice " << iSlice << "/" << NSLICES << std::endl; + if (GetProcessingSettings().debugMask & 1) { + if (doSliceDataOnGPU) { + TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &trk, -1, true); + } + trk.DumpSliceData(*mDebugFile); + } + } + + // Initialize temporary memory where needed + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Copying Slice Data to GPU and initializing temporary memory"); + } + if (GetProcessingSettings().keepDisplayMemory && !doSliceDataOnGPU) { + memset((void*)trk.Data().HitWeights(), 0, trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); + } else { + runKernel<GPUMemClean16>(GetGridAutoStep(useStream, RecoStep::TPCSliceTracking), krnlRunRangeNone, {}, trkShadow.Data().HitWeights(), trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); + } + + // Copy Data to GPU Global Memory + if (!doSliceDataOnGPU) { + TransferMemoryResourcesToGPU(RecoStep::TPCSliceTracking, &trk, useStream); + } + if (GPUDebug("Initialization (3)", useStream)) { + throw std::runtime_error("memcpy failure"); + } + + runKernel<GPUTPCNeighboursFinder>(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); + streamInit[useStream] = true; + + if (GetProcessingSettings().keepDisplayMemory) { + TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &trk, -1, true); + memcpy(trk.LinkTmpMemory(), mRec->Res(trk.MemoryResLinks()).Ptr(), mRec->Res(trk.MemoryResLinks()).Size()); + if (GetProcessingSettings().debugMask & 2) { + trk.DumpLinks(*mDebugFile, 0); + } + } + + runKernel<GPUTPCNeighboursCleaner>(GetGridBlk(GPUCA_ROW_COUNT - 2, useStream), {iSlice}); + DoDebugAndDump(RecoStep::TPCSliceTracking, 4, trk, &GPUTPCTracker::DumpLinks, *mDebugFile, 1); + + runKernel<GPUTPCStartHitsFinder>(GetGridBlk(GPUCA_ROW_COUNT - 6, useStream), {iSlice}); +#ifdef GPUCA_SORT_STARTHITS_GPU + if (doGPU) { + runKernel<GPUTPCStartHitsSorter>(GetGridAuto(useStream), {iSlice}); + } +#endif + DoDebugAndDump(RecoStep::TPCSliceTracking, 32, trk, &GPUTPCTracker::DumpStartHits, *mDebugFile); + + if (GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { + trk.UpdateMaxData(); + AllocateRegisteredMemory(trk.MemoryResTracklets()); + AllocateRegisteredMemory(trk.MemoryResOutput()); + } + + if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletConstructorInPipeline) { + runKernel<GPUTPCTrackletConstructor>(GetGridAuto(useStream), {iSlice}); + DoDebugAndDump(RecoStep::TPCSliceTracking, 128, trk, &GPUTPCTracker::DumpTrackletHits, *mDebugFile); + if (GetProcessingSettings().debugMask & 256 && !GetProcessingSettings().comparableDebutOutput) { + trk.DumpHitWeights(*mDebugFile); + } + } + + if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletSelectorInPipeline) { + runKernel<GPUTPCTrackletSelector>(GetGridAuto(useStream), {iSlice}); + runKernel<GPUTPCGlobalTrackingCopyNumbers>({1, -ThreadCount(), useStream}, {iSlice}, {}, 1); + TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, trk.MemoryResCommon(), useStream, &mEvents->slice[iSlice]); + streamMap[iSlice] = useStream; + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Slice %u, Number of tracks: %d", iSlice, *trk.NTracks()); + } + DoDebugAndDump(RecoStep::TPCSliceTracking, 512, trk, &GPUTPCTracker::DumpTrackHits, *mDebugFile); + } + } + mRec->SetNestedLoopOmpFactor(1); + if (error) { + return (3); + } + + if (doGPU || GetProcessingSettings().debugLevel >= 1) { + ReleaseEvent(&mEvents->init); + if (!doSliceDataOnGPU) { + WaitForHelperThreads(); + } + + if (!GetProcessingSettings().trackletSelectorInPipeline) { + if (GetProcessingSettings().trackletConstructorInPipeline) { + SynchronizeGPU(); + } else { + for (int i = 0; i < mRec->NStreams(); i++) { + RecordMarker(&mEvents->stream[i], i); + } + runKernel<GPUTPCTrackletConstructor, 1>(GetGridAuto(0), krnlRunRangeNone, {&mEvents->single, mEvents->stream, mRec->NStreams()}); + for (int i = 0; i < mRec->NStreams(); i++) { + ReleaseEvent(&mEvents->stream[i]); + } + SynchronizeEventAndRelease(&mEvents->single); + } + + if (GetProcessingSettings().debugLevel >= 4) { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + DoDebugAndDump(RecoStep::TPCSliceTracking, 128, processors()->tpcTrackers[iSlice], &GPUTPCTracker::DumpTrackletHits, *mDebugFile); + } + } + + int runSlices = 0; + int useStream = 0; + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice += runSlices) { + if (runSlices < GetProcessingSettings().trackletSelectorSlices) { + runSlices++; + } + runSlices = CAMath::Min<int>(runSlices, NSLICES - iSlice); + if (getKernelProperties<GPUTPCTrackletSelector>().minBlocks * BlockCount() < (unsigned int)runSlices) { + runSlices = getKernelProperties<GPUTPCTrackletSelector>().minBlocks * BlockCount(); + } + + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Running TPC Tracklet selector (Stream %d, Slice %d to %d)", useStream, iSlice, iSlice + runSlices); + } + runKernel<GPUTPCTrackletSelector>(GetGridAuto(useStream), {iSlice, runSlices}); + runKernel<GPUTPCGlobalTrackingCopyNumbers>({1, -ThreadCount(), useStream}, {iSlice}, {}, runSlices); + for (unsigned int k = iSlice; k < iSlice + runSlices; k++) { + TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[k].MemoryResCommon(), useStream, &mEvents->slice[k]); + streamMap[k] = useStream; + } + useStream++; + if (useStream >= mRec->NStreams()) { + useStream = 0; + } + } + } + + mSliceSelectorReady = 0; + + std::array<bool, NSLICES> transferRunning; + transferRunning.fill(true); + if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (doGPU && !(GetRecoStepsGPU() & RecoStep::TPCMerging))) { + if (param().rec.tpc.globalTracking) { + mWriteOutputDone.fill(0); + } + RunHelperThreads(&GPUChainTracking::HelperOutput, this, NSLICES); + + unsigned int tmpSlice = 0; + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Transfering Tracks from GPU to Host"); + } + + if (tmpSlice == iSlice) { + SynchronizeEvents(&mEvents->slice[iSlice]); + } + while (tmpSlice < NSLICES && (tmpSlice == iSlice || IsEventDone(&mEvents->slice[tmpSlice]))) { + ReleaseEvent(&mEvents->slice[tmpSlice]); + if (*processors()->tpcTrackers[tmpSlice].NTracks() > 0) { + TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[tmpSlice].MemoryResOutput(), streamMap[tmpSlice], &mEvents->slice[tmpSlice]); + } else { + transferRunning[tmpSlice] = false; + } + tmpSlice++; + } + + if (GetProcessingSettings().keepAllMemory) { + TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &processors()->tpcTrackers[iSlice], -1, true); + if (!GetProcessingSettings().trackletConstructorInPipeline) { + if (GetProcessingSettings().debugMask & 256 && !GetProcessingSettings().comparableDebutOutput) { + processors()->tpcTrackers[iSlice].DumpHitWeights(*mDebugFile); + } + } + if (!GetProcessingSettings().trackletSelectorInPipeline) { + if (GetProcessingSettings().debugMask & 512) { + processors()->tpcTrackers[iSlice].DumpTrackHits(*mDebugFile); + } + } + } + + if (transferRunning[iSlice]) { + SynchronizeEvents(&mEvents->slice[iSlice]); + } + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Tracks Transfered: %d / %d", *processors()->tpcTrackers[iSlice].NTracks(), *processors()->tpcTrackers[iSlice].NTrackHits()); + } + + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Data ready for slice %d, helper thread %d", iSlice, iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1)); + } + mSliceSelectorReady = iSlice; + + if (param().rec.tpc.globalTracking) { + for (unsigned int tmpSlice2a = 0; tmpSlice2a <= iSlice; tmpSlice2a += GetProcessingSettings().nDeviceHelperThreads + 1) { + unsigned int tmpSlice2 = GPUTPCGlobalTracking::GlobalTrackingSliceOrder(tmpSlice2a); + unsigned int sliceLeft, sliceRight; + GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(tmpSlice2, sliceLeft, sliceRight); + + if (tmpSlice2 <= iSlice && sliceLeft <= iSlice && sliceRight <= iSlice && mWriteOutputDone[tmpSlice2] == 0) { + GlobalTracking(tmpSlice2, 0); + WriteOutput(tmpSlice2, 0); + mWriteOutputDone[tmpSlice2] = 1; + } + } + } else { + if (iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) == 0) { + WriteOutput(iSlice, 0); + } + } + } + WaitForHelperThreads(); + } + if (!(GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) && param().rec.tpc.globalTracking) { + std::vector<bool> blocking(NSLICES * mRec->NStreams()); + for (int i = 0; i < NSLICES; i++) { + for (int j = 0; j < mRec->NStreams(); j++) { + blocking[i * mRec->NStreams() + j] = i % mRec->NStreams() == j; + } + } + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + unsigned int tmpSlice = GPUTPCGlobalTracking::GlobalTrackingSliceOrder(iSlice); + if (!((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) || (doGPU && !(GetRecoStepsGPU() & RecoStep::TPCMerging)))) { + unsigned int sliceLeft, sliceRight; + GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(tmpSlice, sliceLeft, sliceRight); + if (!blocking[tmpSlice * mRec->NStreams() + sliceLeft % mRec->NStreams()]) { + StreamWaitForEvents(tmpSlice % mRec->NStreams(), &mEvents->slice[sliceLeft]); + blocking[tmpSlice * mRec->NStreams() + sliceLeft % mRec->NStreams()] = true; + } + if (!blocking[tmpSlice * mRec->NStreams() + sliceRight % mRec->NStreams()]) { + StreamWaitForEvents(tmpSlice % mRec->NStreams(), &mEvents->slice[sliceRight]); + blocking[tmpSlice * mRec->NStreams() + sliceRight % mRec->NStreams()] = true; + } + } + GlobalTracking(tmpSlice, 0, !GetProcessingSettings().fullMergerOnGPU); + } + } + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + if (transferRunning[iSlice]) { + ReleaseEvent(&mEvents->slice[iSlice]); + } + } + } else { + mSliceSelectorReady = NSLICES; + GPUCA_OPENMP(parallel for if(!doGPU && GetProcessingSettings().ompKernels != 1) num_threads(mRec->SetAndGetNestedLoopOmpFactor(!doGPU, NSLICES))) + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + if (param().rec.tpc.globalTracking) { + GlobalTracking(iSlice, 0); + } + if (GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCSectorTracks) { + WriteOutput(iSlice, 0); + } + } + mRec->SetNestedLoopOmpFactor(1); + } + + if (param().rec.tpc.globalTracking && GetProcessingSettings().debugLevel >= 3) { + for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { + GPUInfo("Slice %d - Tracks: Local %d Global %d - Hits: Local %d Global %d", iSlice, + processors()->tpcTrackers[iSlice].CommonMemory()->nLocalTracks, processors()->tpcTrackers[iSlice].CommonMemory()->nTracks, processors()->tpcTrackers[iSlice].CommonMemory()->nLocalTrackHits, processors()->tpcTrackers[iSlice].CommonMemory()->nTrackHits); + } + } + + if (GetProcessingSettings().debugMask & 1024 && !GetProcessingSettings().comparableDebutOutput) { + for (unsigned int i = 0; i < NSLICES; i++) { + processors()->tpcTrackers[i].DumpOutput(*mDebugFile); + } + } + + if (DoProfile()) { + return (1); + } + for (unsigned int i = 0; i < NSLICES; i++) { + mIOPtrs.nSliceTracks[i] = *processors()->tpcTrackers[i].NTracks(); + mIOPtrs.sliceTracks[i] = processors()->tpcTrackers[i].Tracks(); + mIOPtrs.nSliceClusters[i] = *processors()->tpcTrackers[i].NTrackHits(); + mIOPtrs.sliceClusters[i] = processors()->tpcTrackers[i].TrackHits(); + if (GetProcessingSettings().keepDisplayMemory && !GetProcessingSettings().keepAllMemory) { + TransferMemoryResourcesToHost(RecoStep::TPCSliceTracking, &processors()->tpcTrackers[i], -1, true); + } + } + if (GetProcessingSettings().debugLevel >= 2) { + GPUInfo("TPC Slice Tracker finished"); + } + mRec->PopNonPersistentMemory(RecoStep::TPCSliceTracking, qStr2Tag("TPCSLTRK")); + return 0; +} + +int GPUChainTracking::ReadEvent(unsigned int iSlice, int threadId) +{ + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("Running ReadEvent for slice %d on thread %d\n", iSlice, threadId); + } + runKernel<GPUTPCCreateSliceData>({GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU)}, {iSlice}); + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("Finished ReadEvent for slice %d on thread %d\n", iSlice, threadId); + } + return (0); +} + +void GPUChainTracking::WriteOutput(int iSlice, int threadId) +{ + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("Running WriteOutput for slice %d on thread %d\n", iSlice, threadId); + } + if (GetProcessingSettings().nDeviceHelperThreads) { + while (mLockAtomic.test_and_set(std::memory_order_acquire)) { + ; + } + } + processors()->tpcTrackers[iSlice].WriteOutputPrepare(); + if (GetProcessingSettings().nDeviceHelperThreads) { + mLockAtomic.clear(); + } + processors()->tpcTrackers[iSlice].WriteOutput(); + if (GetProcessingSettings().debugLevel >= 5) { + GPUInfo("Finished WriteOutput for slice %d on thread %d\n", iSlice, threadId); + } +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx b/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx new file mode 100644 index 0000000000000..ebb82f1aeba1d --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingTRD.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "GPUTRDTrackletWord.h" +#include "GPUTRDTrackletLabels.h" +#include "GPUTRDTrack.h" +#include "GPUTRDTracker.h" +#include "utils/strtag.h" + +using namespace GPUCA_NAMESPACE::gpu; +using namespace o2::trd; + +int GPUChainTracking::RunTRDTracking() +{ + if (!processors()->trdTrackerGPU.IsInitialized()) { + return 1; + } + + GPUTRDTrackerGPU& Tracker = processors()->trdTrackerGPU; + Tracker.Reset(); + if (mIOPtrs.nTRDTracklets == 0) { + return 0; + } + Tracker.SetGenerateSpacePoints(mIOPtrs.trdSpacePoints == nullptr); + + mRec->PushNonPersistentMemory(qStr2Tag("TRDTRACK")); + SetupGPUProcessor(&Tracker, true); + + for (unsigned int i = 0; i < mIOPtrs.nMergedTracks; i++) { + const GPUTPCGMMergedTrack& trk = mIOPtrs.mergedTracks[i]; + if (!Tracker.PreCheckTrackTRDCandidate(trk)) { + continue; + } + const GPUTRDTrackGPU& trktrd = param().rec.tpc.nWaysOuter ? (GPUTRDTrackGPU)trk.OuterParam() : (GPUTRDTrackGPU)trk; + if (!Tracker.CheckTrackTRDCandidate(trktrd)) { + continue; + } + + if (Tracker.LoadTrack(trktrd, i, false)) { + return 1; + } + } + + Tracker.DoTracking(this); + + mIOPtrs.nTRDTracks = Tracker.NTracks(); + mIOPtrs.trdTracks = Tracker.Tracks(); + mRec->PopNonPersistentMemory(RecoStep::TRDTracking, qStr2Tag("TRDTRACK")); + + return 0; +} + +int GPUChainTracking::DoTRDGPUTracking() +{ +#ifdef GPUCA_HAVE_O2HEADERS + bool doGPU = GetRecoStepsGPU() & RecoStep::TRDTracking; + GPUTRDTrackerGPU& Tracker = processors()->trdTrackerGPU; + GPUTRDTrackerGPU& TrackerShadow = doGPU ? processorsShadow()->trdTrackerGPU : Tracker; + + const auto& threadContext = GetThreadContext(); + SetupGPUProcessor(&Tracker, false); + TrackerShadow.OverrideGPUGeometry(reinterpret_cast<GPUTRDGeometry*>(mFlatObjectsDevice.mCalibObjects.trdGeometry)); + + WriteToConstantMemory(RecoStep::TRDTracking, (char*)&processors()->trdTrackerGPU - (char*)processors(), &TrackerShadow, sizeof(TrackerShadow), 0); + TransferMemoryResourcesToGPU(RecoStep::TRDTracking, &Tracker, 0); + + runKernel<GPUTRDTrackerKernels>(GetGridAuto(0), krnlRunRangeNone); + TransferMemoryResourcesToHost(RecoStep::TRDTracking, &Tracker, 0); + SynchronizeStream(0); + + if (GetProcessingSettings().debugLevel >= 2) { + GPUInfo("GPU TRD tracker Finished"); + } +#endif + return (0); +} diff --git a/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx new file mode 100644 index 0000000000000..94d4d8252b7f5 --- /dev/null +++ b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx @@ -0,0 +1,195 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUChainTrackingTransformation.cxx +/// \author David Rohr + +#include "GPUChainTracking.h" +#include "GPULogging.h" +#include "GPUO2DataTypes.h" +#include "GPUTrackingInputProvider.h" +#include "GPUTPCClusterData.h" +#include "GPUReconstructionConvert.h" +#include "GPUMemorySizeScalers.h" +#include "AliHLTTPCRawCluster.h" + +#ifdef GPUCA_HAVE_O2HEADERS +#include "DataFormatsTPC/ClusterNative.h" +#include "CommonDataFormat/InteractionRecord.h" +#else +#include "GPUO2FakeClasses.h" +#endif +#include "utils/strtag.h" + +using namespace GPUCA_NAMESPACE::gpu; +using namespace o2::tpc; + +int GPUChainTracking::ConvertNativeToClusterData() +{ +#ifdef GPUCA_HAVE_O2HEADERS + mRec->PushNonPersistentMemory(qStr2Tag("TPCTRANS")); + const auto& threadContext = GetThreadContext(); + bool doGPU = GetRecoStepsGPU() & RecoStep::TPCConversion; + GPUTPCConvert& convert = processors()->tpcConverter; + GPUTPCConvert& convertShadow = doGPU ? processorsShadow()->tpcConverter : convert; + + bool transferClusters = false; + if (doGPU) { + if (!(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { + mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mIOPtrs.clustersNative->nClustersTotal; + AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); + processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; + WriteToConstantMemory(RecoStep::TPCConversion, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); + *mInputsHost->mPclusterNativeAccess = *mIOPtrs.clustersNative; + mInputsHost->mPclusterNativeAccess->clustersLinear = mInputsShadow->mPclusterNativeBuffer; + mInputsHost->mPclusterNativeAccess->setOffsetPtrs(); + GPUMemCpy(RecoStep::TPCConversion, mInputsShadow->mPclusterNativeBuffer, mIOPtrs.clustersNative->clustersLinear, sizeof(mIOPtrs.clustersNative->clustersLinear[0]) * mIOPtrs.clustersNative->nClustersTotal, 0, true); + TransferMemoryResourceLinkToGPU(RecoStep::TPCConversion, mInputsHost->mResourceClusterNativeAccess, 0); + transferClusters = true; + } + } + if (!param().par.earlyTpcTransform) { + if (GetProcessingSettings().debugLevel >= 3) { + GPUInfo("Early transform inactive, skipping TPC Early transformation kernel, transformed on the fly during slice data creation / refit"); + } + if (transferClusters) { + SynchronizeStream(0); // TODO: Synchronize implicitly with next step + } + return 0; + } + SetupGPUProcessor(&convert, true); + for (unsigned int i = 0; i < NSLICES; i++) { + convert.mMemory->clusters[i] = convertShadow.mClusters + mIOPtrs.clustersNative->clusterOffset[i][0]; + } + + WriteToConstantMemory(RecoStep::TPCConversion, (char*)&processors()->tpcConverter - (char*)processors(), &convertShadow, sizeof(convertShadow), 0); + TransferMemoryResourcesToGPU(RecoStep::TPCConversion, &convert, 0); + runKernel<GPUTPCConvertKernel>(GetGridBlk(NSLICES * GPUCA_ROW_COUNT, 0), krnlRunRangeNone, krnlEventNone); + TransferMemoryResourcesToHost(RecoStep::TPCConversion, &convert, 0); + SynchronizeStream(0); + + for (unsigned int i = 0; i < NSLICES; i++) { + mIOPtrs.nClusterData[i] = (i == NSLICES - 1 ? mIOPtrs.clustersNative->nClustersTotal : mIOPtrs.clustersNative->clusterOffset[i + 1][0]) - mIOPtrs.clustersNative->clusterOffset[i][0]; + mIOPtrs.clusterData[i] = convert.mClusters + mIOPtrs.clustersNative->clusterOffset[i][0]; + } + mRec->PopNonPersistentMemory(RecoStep::TPCConversion, qStr2Tag("TPCTRANS")); +#endif + return 0; +} + +void GPUChainTracking::ConvertNativeToClusterDataLegacy() +{ + ClusterNativeAccess* tmp = mIOMem.clusterNativeAccess.get(); + if (tmp != mIOPtrs.clustersNative) { + *tmp = *mIOPtrs.clustersNative; + } + GPUReconstructionConvert::ConvertNativeToClusterData(mIOMem.clusterNativeAccess.get(), mIOMem.clusterData, mIOPtrs.nClusterData, processors()->calibObjects.fastTransform, param().par.continuousMaxTimeBin); + for (unsigned int i = 0; i < NSLICES; i++) { + mIOPtrs.clusterData[i] = mIOMem.clusterData[i].get(); + if (GetProcessingSettings().registerStandaloneInputMemory) { + if (mRec->registerMemoryForGPU(mIOMem.clusterData[i].get(), mIOPtrs.nClusterData[i] * sizeof(*mIOPtrs.clusterData[i]))) { + throw std::runtime_error("Error registering memory for GPU"); + } + } + } + mIOPtrs.clustersNative = nullptr; + mIOMem.clustersNative.reset(nullptr); +} + +void GPUChainTracking::ConvertRun2RawToNative() +{ + GPUReconstructionConvert::ConvertRun2RawToNative(*mIOMem.clusterNativeAccess, mIOMem.clustersNative, mIOPtrs.rawClusters, mIOPtrs.nRawClusters); + for (unsigned int i = 0; i < NSLICES; i++) { + mIOPtrs.rawClusters[i] = nullptr; + mIOPtrs.nRawClusters[i] = 0; + mIOMem.rawClusters[i].reset(nullptr); + mIOPtrs.clusterData[i] = nullptr; + mIOPtrs.nClusterData[i] = 0; + mIOMem.clusterData[i].reset(nullptr); + } + mIOPtrs.clustersNative = mIOMem.clusterNativeAccess.get(); + if (GetProcessingSettings().registerStandaloneInputMemory) { + if (mRec->registerMemoryForGPU(mIOMem.clustersNative.get(), mIOMem.clusterNativeAccess->nClustersTotal * sizeof(*mIOMem.clusterNativeAccess->clustersLinear))) { + throw std::runtime_error("Error registering memory for GPU"); + } + } +} + +void GPUChainTracking::ConvertZSEncoder(bool zs12bit) +{ +#ifdef GPUCA_HAVE_O2HEADERS + mIOMem.tpcZSmeta2.reset(new GPUTrackingInOutZS::GPUTrackingInOutZSMeta); + mIOMem.tpcZSmeta.reset(new GPUTrackingInOutZS); + o2::InteractionRecord ir{0, mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasTfStartOrbit ? mIOPtrs.settingsTF->tfStartOrbit : 0u}; + GPUReconstructionConvert::RunZSEncoder<o2::tpc::Digit>(*mIOPtrs.tpcPackedDigits, &mIOMem.tpcZSpages, &mIOMem.tpcZSmeta2->n[0][0], nullptr, &ir, param(), zs12bit, true); + GPUReconstructionConvert::RunZSEncoderCreateMeta(mIOMem.tpcZSpages.get(), &mIOMem.tpcZSmeta2->n[0][0], &mIOMem.tpcZSmeta2->ptr[0][0], mIOMem.tpcZSmeta.get()); + mIOPtrs.tpcZS = mIOMem.tpcZSmeta.get(); + if (GetProcessingSettings().registerStandaloneInputMemory) { + for (unsigned int i = 0; i < NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[i].count[j]; k++) { + if (mRec->registerMemoryForGPU(mIOPtrs.tpcZS->slice[i].zsPtr[j][k], mIOPtrs.tpcZS->slice[i].nZSPtr[j][k] * TPCZSHDR::TPC_ZS_PAGE_SIZE)) { + throw std::runtime_error("Error registering memory for GPU"); + } + } + } + } + } +#endif +} + +void GPUChainTracking::ConvertZSFilter(bool zs12bit) +{ + GPUReconstructionConvert::RunZSFilter(mIOMem.tpcDigits, mIOPtrs.tpcPackedDigits->tpcDigits, mIOMem.digitMap->nTPCDigits, mIOPtrs.tpcPackedDigits->nTPCDigits, param(), zs12bit, param().rec.tpc.zsThreshold); +} + +int GPUChainTracking::ForwardTPCDigits() +{ +#ifdef GPUCA_HAVE_O2HEADERS + if (GetRecoStepsGPU() & RecoStep::TPCClusterFinding) { + throw std::runtime_error("Cannot forward TPC digits with Clusterizer on GPU"); + } + std::vector<ClusterNative> tmp[NSLICES][GPUCA_ROW_COUNT]; + unsigned int nTotal = 0; + const float zsThreshold = param().rec.tpc.zsThreshold; + for (int i = 0; i < NSLICES; i++) { + for (unsigned int j = 0; j < mIOPtrs.tpcPackedDigits->nTPCDigits[i]; j++) { + const auto& d = mIOPtrs.tpcPackedDigits->tpcDigits[i][j]; + if (d.getChargeFloat() >= zsThreshold) { + ClusterNative c; + c.setTimeFlags(d.getTimeStamp(), 0); + c.setPad(d.getPad()); + c.setSigmaTime(1); + c.setSigmaPad(1); + c.qTot = c.qMax = d.getChargeFloat(); + tmp[i][d.getRow()].emplace_back(c); + nTotal++; + } + } + } + mIOMem.clustersNative.reset(new ClusterNative[nTotal]); + nTotal = 0; + mClusterNativeAccess->clustersLinear = mIOMem.clustersNative.get(); + for (int i = 0; i < NSLICES; i++) { + for (int j = 0; j < GPUCA_ROW_COUNT; j++) { + mClusterNativeAccess->nClusters[i][j] = tmp[i][j].size(); + memcpy(&mIOMem.clustersNative[nTotal], tmp[i][j].data(), tmp[i][j].size() * sizeof(*mClusterNativeAccess->clustersLinear)); + nTotal += tmp[i][j].size(); + } + } + mClusterNativeAccess->setOffsetPtrs(); + mIOPtrs.tpcPackedDigits = nullptr; + mIOPtrs.clustersNative = mClusterNativeAccess.get(); + GPUInfo("Forwarded %u TPC clusters", nTotal); + mRec->MemoryScalers()->nTPCHits = nTotal; +#endif + return 0; +} diff --git a/GPU/GPUTracking/Global/GPUErrorCodes.h b/GPU/GPUTracking/Global/GPUErrorCodes.h index b7b6df0938d88..2c94844f04986 100644 --- a/GPU/GPUTracking/Global/GPUErrorCodes.h +++ b/GPU/GPUTracking/Global/GPUErrorCodes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,3 +29,12 @@ GPUCA_ERROR_CODE(12, ERROR_SLICEDATA_FIRSTHITINBIN_OVERFLOW) GPUCA_ERROR_CODE(13, ERROR_SLICEDATA_HITINROW_OVERFLOW) GPUCA_ERROR_CODE(14, ERROR_SLICEDATA_BIN_OVERFLOW) GPUCA_ERROR_CODE(15, ERROR_SLICEDATA_Z_OVERFLOW) +GPUCA_ERROR_CODE(16, ERROR_MERGER_HIT_OVERFLOW) +GPUCA_ERROR_CODE(17, ERROR_MERGER_TRACK_OVERFLOW) +GPUCA_ERROR_CODE(18, ERROR_COMPRESSION_ROW_HIT_OVERFLOW) +GPUCA_ERROR_CODE(19, ERROR_LOOPER_MATCH_OVERFLOW) +GPUCA_ERROR_CODE(20, ERROR_CF_PEAK_OVERFLOW) +GPUCA_ERROR_CODE(21, ERROR_CF_CLUSTER_OVERFLOW) +GPUCA_ERROR_CODE(22, ERROR_CF_ROW_CLUSTER_OVERFLOW) +GPUCA_ERROR_CODE(23, ERROR_CF_GLOBAL_CLUSTER_OVERFLOW) +GPUCA_ERROR_CODE(24, MAX_OVERFLOW_ERROR_NUMBER) // Overflow errors are detected as errno <= MAX_OVERFLOW_ERROR_NUMBER diff --git a/GPU/GPUTracking/Global/GPUErrors.cxx b/GPU/GPUTracking/Global/GPUErrors.cxx index ba750d6cfc3c9..2a2ac96760919 100644 --- a/GPU/GPUTracking/Global/GPUErrors.cxx +++ b/GPU/GPUTracking/Global/GPUErrors.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,9 +57,10 @@ static std::unordered_map<unsigned int, const char*> errorNames = { void GPUErrors::printErrors() { for (unsigned int i = 0; i < std::min(*mErrors, GPUCA_MAX_ERRORS); i++) { - const auto& it = errorNames.find(mErrors[4 * i + 1]); + unsigned int errorCode = mErrors[4 * i + 1]; + const auto& it = errorNames.find(errorCode); const char* errorName = it == errorNames.end() ? "INVALID ERROR CODE" : it->second; - GPUError("GPU Error Code (%u:%u) %s : %u / %u / %u", i, mErrors[4 * i + 1], errorName, mErrors[4 * i + 2], mErrors[4 * i + 3], mErrors[4 * i + 4]); + GPUError("GPU Error Code (%u:%u) %s : %u / %u / %u", i, errorCode, errorName, mErrors[4 * i + 2], mErrors[4 * i + 3], mErrors[4 * i + 4]); } if (*mErrors > GPUCA_MAX_ERRORS) { GPUError("Additional errors occured (codes not stored)"); diff --git a/GPU/GPUTracking/Global/GPUErrors.h b/GPU/GPUTracking/Global/GPUErrors.h index 83773321bdbf9..2eb1c02bb7922 100644 --- a/GPU/GPUTracking/Global/GPUErrors.h +++ b/GPU/GPUTracking/Global/GPUErrors.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx index 18f5bacbbdc70..5f29d28f5766a 100644 --- a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx +++ b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Global/GPUTrackingInputProvider.h b/GPU/GPUTracking/Global/GPUTrackingInputProvider.h index 247250c08ff8d..85526b158b959 100644 --- a/GPU/GPUTracking/Global/GPUTrackingInputProvider.h +++ b/GPU/GPUTracking/Global/GPUTrackingInputProvider.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,7 @@ namespace GPUCA_NAMESPACE namespace gpu { -class GPUTrackingInOutZS; +struct GPUTrackingInOutZS; class GPUTrackingInputProvider : public GPUProcessor { diff --git a/GPU/GPUTracking/HLTHeaders/AliHLTTPCClusterMCData.h b/GPU/GPUTracking/HLTHeaders/AliHLTTPCClusterMCData.h index 2506a5f61a723..70144139de1cb 100644 --- a/GPU/GPUTracking/HLTHeaders/AliHLTTPCClusterMCData.h +++ b/GPU/GPUTracking/HLTHeaders/AliHLTTPCClusterMCData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/HLTHeaders/AliHLTTPCRawCluster.h b/GPU/GPUTracking/HLTHeaders/AliHLTTPCRawCluster.h index c7a43d0702927..4cd8c5cdc332a 100644 --- a/GPU/GPUTracking/HLTHeaders/AliHLTTPCRawCluster.h +++ b/GPU/GPUTracking/HLTHeaders/AliHLTTPCRawCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/ITS/GPUITSFitter.cxx b/GPU/GPUTracking/ITS/GPUITSFitter.cxx index 554ef783740bc..fa9482020cbda 100644 --- a/GPU/GPUTracking/ITS/GPUITSFitter.cxx +++ b/GPU/GPUTracking/ITS/GPUITSFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/ITS/GPUITSFitter.h b/GPU/GPUTracking/ITS/GPUITSFitter.h index c45efa0048adf..2f7f77938f8bc 100644 --- a/GPU/GPUTracking/ITS/GPUITSFitter.h +++ b/GPU/GPUTracking/ITS/GPUITSFitter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -56,6 +57,8 @@ class GPUITSFitter : public GPUProcessor { return mMemory->mNumberOfTracks; } + GPUd() void SetNumberOfLayers(int i) { mNumberOfLayers = i; } + GPUd() int NumberOfLayers() { return mNumberOfLayers; } GPUd() void SetNumberTF(int i, int v) { mNTF[i] = v; } GPUd() o2::its::TrackingFrameInfo** trackingFrame() { @@ -77,16 +80,17 @@ class GPUITSFitter : public GPUProcessor }; protected: + int mNumberOfLayers; int mNumberOfRoads = 0; int mNMaxTracks = 0; - int mNTF[7] = {}; + int* mNTF = nullptr; Memory* mMemory = nullptr; o2::its::Road* mRoads = nullptr; - o2::its::TrackingFrameInfo* mTF[7] = {}; + o2::its::TrackingFrameInfo** mTF = {nullptr}; GPUITSTrack* mTracks = nullptr; - const o2::its::Cluster* mClusterPtrs[7]; - const o2::its::Cell* mCellPtrs[5]; + const o2::its::Cluster** mClusterPtrs; + const o2::its::Cell** mCellPtrs; short mMemoryResInput = -1; short mMemoryResTracks = -1; diff --git a/GPU/GPUTracking/ITS/GPUITSFitterKernels.cxx b/GPU/GPUTracking/ITS/GPUITSFitterKernels.cxx index 0e3fba8649e41..39cb24aff9be0 100644 --- a/GPU/GPUTracking/ITS/GPUITSFitterKernels.cxx +++ b/GPU/GPUTracking/ITS/GPUITSFitterKernels.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -55,7 +56,7 @@ GPUdii() bool GPUITSFitterKernel::fitTrack(GPUITSFitter& GPUrestrict() Fitter, G } template <> -GPUdii() void GPUITSFitterKernel::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUITSFitterKernel::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { GPUITSFitter& Fitter = processors.itsFitter; @@ -78,7 +79,7 @@ GPUdii() void GPUITSFitterKernel::Thread<0>(int nBlocks, int nThreads, int iBloc int lastCellLevel = o2::its::constants::its::UnusedIndex; CA_DEBUGGER(int nClusters = 2); - for (int iCell{0}; iCell < o2::its::constants::its::CellsPerRoad; ++iCell) { + for (int iCell{0}; iCell < Fitter.NumberOfLayers() - 2; ++iCell) { const int cellIndex = road[iCell]; if (cellIndex == o2::its::constants::its::UnusedIndex) { continue; @@ -164,13 +165,13 @@ GPUdii() void GPUITSFitterKernel::Thread<0>(int nBlocks, int nThreads, int iBloc for (size_t iC = 0; iC < 7; ++iC) { temporaryTrack.mClusters[iC] = clusters[iC]; } - bool fitSuccess = fitTrack(Fitter, prop, temporaryTrack, o2::its::constants::its::LayersNumber - 4, -1, -1); + bool fitSuccess = fitTrack(Fitter, prop, temporaryTrack, Fitter.NumberOfLayers() - 4, -1, -1); if (!fitSuccess) { continue; } CA_DEBUGGER(fitCounters[nClusters - 4]++); temporaryTrack.ResetCovariance(); - fitSuccess = fitTrack(Fitter, prop, temporaryTrack, 0, o2::its::constants::its::LayersNumber, 1); + fitSuccess = fitTrack(Fitter, prop, temporaryTrack, 0, Fitter.NumberOfLayers(), 1); if (!fitSuccess) { continue; } @@ -184,7 +185,7 @@ GPUdii() void GPUITSFitterKernel::Thread<0>(int nBlocks, int nThreads, int iBloc temporaryTrack.mOuterParam.X = temporaryTrack.X(); temporaryTrack.mOuterParam.alpha = prop.GetAlpha(); temporaryTrack.ResetCovariance(); - fitSuccess = fitTrack(Fitter, prop, temporaryTrack, o2::its::constants::its::LayersNumber - 1, -1, -1); + fitSuccess = fitTrack(Fitter, prop, temporaryTrack, Fitter.NumberOfLayers() - 1, -1, -1); if (!fitSuccess) { continue; } diff --git a/GPU/GPUTracking/ITS/GPUITSFitterKernels.h b/GPU/GPUTracking/ITS/GPUITSFitterKernels.h index 59ff83030f546..ceb31e267d31f 100644 --- a/GPU/GPUTracking/ITS/GPUITSFitterKernels.h +++ b/GPU/GPUTracking/ITS/GPUITSFitterKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/ITS/GPUITSTrack.h b/GPU/GPUTracking/ITS/GPUITSTrack.h index 3ced243587ba5..ad4d2edc6d552 100644 --- a/GPU/GPUTracking/ITS/GPUITSTrack.h +++ b/GPU/GPUTracking/ITS/GPUITSTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #ifndef GPUITSTRACK_H #define GPUITSTRACK_H +#include "GPUTPCGMMergerTypes.h" #include "GPUTPCGMTrackParam.h" namespace GPUCA_NAMESPACE::gpu @@ -21,7 +23,7 @@ namespace GPUCA_NAMESPACE::gpu class GPUITSTrack : public GPUTPCGMTrackParam { public: - GPUTPCGMTrackParam::GPUTPCOuterParam mOuterParam; + gputpcgmmergertypes::GPUTPCOuterParam mOuterParam; float mAlpha; int mClusters[7]; }; diff --git a/GPU/GPUTracking/Interface/CMakeLists.txt b/GPU/GPUTracking/Interface/CMakeLists.txt new file mode 100644 index 0000000000000..340d08a74d797 --- /dev/null +++ b/GPU/GPUTracking/Interface/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +set(MODULE GPUO2Interface) + +set(SRCS GPUO2Interface.cxx GPUO2InterfaceRefit.cxx GPUO2InterfaceQA.cxx GPUO2InterfaceConfiguration.cxx) + +if(OPENGL_FOUND + AND GLFW_FOUND + AND TARGET AliceO2::DebugGUI + AND OPENGL_GLU_FOUND + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin" +) + set(SRCS ${SRCS} GPUO2InterfaceDisplay.cxx) +endif() + +string(REPLACE ".cxx" ".h" HDRS_TMP "${SRCS}") +set(HDRS ${HDRS_TMP}) + +o2_add_library(${MODULE} + SOURCES ${SRCS} + TARGETVARNAME targetName + PRIVATE_LINK_LIBRARIES O2::GPUTracking + PUBLIC_LINK_LIBRARIES O2::GPUCommon + PUBLIC_INCLUDE_DIRECTORIES ../Definitions + ../DataTypes + ../Interface + ../) + +o2_target_root_dictionary(${MODULE} + HEADERS ${HDRS} + LINKDEF GPUO2InterfaceLinkDef.h) + +target_include_directories(${targetName} + PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}> + $<INSTALL_INTERFACE:include/GPU>) + +target_compile_definitions(${targetName} PRIVATE $<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>) + + +install(FILES ${HDRS} DESTINATION include/GPU) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 2c63a5528ed93..0394583d78bf5 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,27 +20,27 @@ #include "GPUO2InterfaceConfiguration.h" #include "GPUParam.inc" #include "GPUQA.h" +#include "GPUOutputControl.h" +#include "TPCPadGainCalib.h" +#include "TPCdEdxCalibrationSplines.h" #include <iostream> #include <fstream> -#ifdef WITH_OPENMP -#include <omp.h> -#endif using namespace o2::gpu; #include "DataFormatsTPC/ClusterNative.h" -GPUTPCO2Interface::GPUTPCO2Interface() = default; +GPUO2Interface::GPUO2Interface() = default; -GPUTPCO2Interface::~GPUTPCO2Interface() { Deinitialize(); } +GPUO2Interface::~GPUO2Interface() { Deinitialize(); } -int GPUTPCO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) +int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) { if (mInitialized) { return (1); } mConfig.reset(new GPUO2InterfaceConfiguration(config)); - mContinuous = mConfig->configEvent.continuousMaxTimeBin != 0; + mContinuous = mConfig->configGRP.continuousMaxTimeBin != 0; mRec.reset(GPUReconstruction::CreateInstance(mConfig->configDeviceBackend)); if (mRec == nullptr) { GPUError("Error obtaining instance of GPUReconstruction"); @@ -49,42 +50,31 @@ int GPUTPCO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) mChain->mConfigDisplay = &mConfig->configDisplay; mChain->mConfigQA = &mConfig->configQA; if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCRaw)) { - mConfig->configEvent.needsClusterer = 1; + mConfig->configGRP.needsClusterer = 1; } - mRec->SetSettings(&mConfig->configEvent, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); - mChain->SetTPCFastTransform(mConfig->configCalib.fastTransform); - mChain->SetTPCCFCalibration(mConfig->configCalib.tpcCalibration); - mChain->SetdEdxSplines(mConfig->configCalib.dEdxSplines); - mChain->SetMatLUT(mConfig->configCalib.matLUT); - mChain->SetTRDGeometry(mConfig->configCalib.trdGeometry); + mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); + mChain->SetCalibObjects(mConfig->configCalib); + mOutputRegions.reset(new GPUTrackingOutputs); if (mConfig->configInterface.outputToExternalBuffers) { - mOutputCompressedClusters.reset(new GPUOutputControl); - mChain->SetOutputControlCompressedClusters(mOutputCompressedClusters.get()); - mOutputClustersNative.reset(new GPUOutputControl); - mChain->SetOutputControlClustersNative(mOutputClustersNative.get()); - mOutputTPCTracks.reset(new GPUOutputControl); - mChain->SetOutputControlTPCTracks(mOutputTPCTracks.get()); + for (unsigned int i = 0; i < mOutputRegions->count(); i++) { + mChain->SetSubOutputControl(i, &mOutputRegions->asArray()[i]); + } GPUOutputControl dummy; dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; }); mRec->SetOutputControl(dummy); } - if (mConfig->configProcessing.runMC) { - mOutputTPCClusterLabels.reset(new GPUOutputControl); - mChain->SetOutputControlClusterLabels(mOutputTPCClusterLabels.get()); - } if (mRec->Init()) { return (1); } - if (!mRec->IsGPU() && mConfig->configProcessing.memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { + if (!mRec->IsGPU() && mRec->GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { mRec->MemoryScalers()->factor *= 2; } - mRec->MemoryScalers()->factor *= mConfig->configInterface.memoryBufferScaleFactor; mInitialized = true; return (0); } -void GPUTPCO2Interface::Deinitialize() +void GPUO2Interface::Deinitialize() { if (mInitialized) { mRec->Finalize(); @@ -93,24 +83,30 @@ void GPUTPCO2Interface::Deinitialize() mInitialized = false; } -int GPUTPCO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs) +int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs) { if (!mInitialized) { return (1); } - static int nEvent = 0; if (mConfig->configInterface.dumpEvents) { + static int nEvent = 0; mChain->ClearIOPointers(); - mChain->mIOPtrs.clustersNative = data->clustersNative; - mChain->mIOPtrs.tpcPackedDigits = data->tpcPackedDigits; - mChain->mIOPtrs.tpcZS = data->tpcZS; + mChain->mIOPtrs = *data; char fname[1024]; sprintf(fname, "event.%d.dump", nEvent); mChain->DumpData(fname); if (nEvent == 0) { mRec->DumpSettings(); +#ifdef GPUCA_BUILD_QA + if (mConfig->configProcessing.runMC) { + mChain->ForceInitQA(); + sprintf(fname, "mc.%d.dump", nEvent); + mChain->GetQA()->DumpO2MCData(fname); + } +#endif } + nEvent++; if (mConfig->configInterface.dumpEvents >= 2) { return 0; } @@ -118,35 +114,17 @@ int GPUTPCO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceO mChain->mIOPtrs = *data; if (mConfig->configInterface.outputToExternalBuffers) { - if (outputs->compressedClusters.allocator) { - mOutputCompressedClusters->set(outputs->compressedClusters.allocator); - } else if (outputs->compressedClusters.ptr) { - mOutputCompressedClusters->set(outputs->compressedClusters.ptr, outputs->compressedClusters.size); - } else { - mOutputCompressedClusters->reset(); - } - if (outputs->clustersNative.allocator) { - mOutputClustersNative->set(outputs->clustersNative.allocator); - } else if (outputs->clustersNative.ptr) { - mOutputClustersNative->set(outputs->clustersNative.ptr, outputs->clustersNative.size); - } else { - mOutputClustersNative->reset(); - } - if (outputs->tpcTracks.allocator) { - mOutputTPCTracks->set(outputs->tpcTracks.allocator); - } else if (outputs->tpcTracks.ptr) { - mOutputTPCTracks->set(outputs->tpcTracks.ptr, outputs->tpcTracks.size); - } else { - mOutputTPCTracks->reset(); - } - } - if (mConfig->configProcessing.runMC) { - if (outputs->clusterLabels.allocator) { - mOutputTPCClusterLabels->set(outputs->clusterLabels.allocator); - } else { - mOutputTPCClusterLabels->reset(); + for (unsigned int i = 0; i < mOutputRegions->count(); i++) { + if (outputs->asArray()[i].allocator) { + mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator); + } else if (outputs->asArray()[i].ptrBase) { + mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size); + } else { + mOutputRegions->asArray()[i].reset(); + } } } + int retVal = mRec->RunChains(); if (retVal == 2) { retVal = 0; // 2 signals end of event display, ignore @@ -155,11 +133,6 @@ int GPUTPCO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceO mRec->ClearAllocatedMemory(); return retVal; } - if (mConfig->configInterface.outputToExternalBuffers) { - outputs->compressedClusters.size = mOutputCompressedClusters->EndOfSpace ? 0 : mChain->mIOPtrs.tpcCompressedClusters->totalDataSize; - outputs->clustersNative.size = mOutputClustersNative->EndOfSpace ? 0 : (mChain->mIOPtrs.clustersNative->nClustersTotal * sizeof(*mChain->mIOPtrs.clustersNative->clustersLinear)); - outputs->tpcTracks.size = mOutputCompressedClusters->EndOfSpace ? 0 : (size_t)((char*)mOutputCompressedClusters->OutputPtr - (char*)mOutputCompressedClusters->OutputBase); - } if (mConfig->configQA.shipToQC) { outputs->qa.hist1 = &mChain->GetQA()->getHistograms1D(); outputs->qa.hist2 = &mChain->GetQA()->getHistograms2D(); @@ -167,24 +140,43 @@ int GPUTPCO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceO } *data = mChain->mIOPtrs; - nEvent++; return 0; } -void GPUTPCO2Interface::Clear(bool clearOutputs) { mRec->ClearAllocatedMemory(clearOutputs); } +void GPUO2Interface::Clear(bool clearOutputs) { mRec->ClearAllocatedMemory(clearOutputs); } -void GPUTPCO2Interface::GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const +void GPUO2Interface::GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const { mRec->GetParam().GetClusterErrors2(row, z, sinPhi, DzDs, ErrY2, ErrZ2); mRec->GetParam().UpdateClusterError2ByState(clusterState, ErrY2, ErrZ2); } -int GPUTPCO2Interface::registerMemoryForGPU(const void* ptr, size_t size) +int GPUO2Interface::registerMemoryForGPU(const void* ptr, size_t size) { return mRec->registerMemoryForGPU(ptr, size); } -int GPUTPCO2Interface::unregisterMemoryForGPU(const void* ptr) +int GPUO2Interface::unregisterMemoryForGPU(const void* ptr) { return mRec->unregisterMemoryForGPU(ptr); } + +std::unique_ptr<TPCPadGainCalib> GPUO2Interface::getPadGainCalibDefault() +{ + return std::make_unique<TPCPadGainCalib>(); +} + +std::unique_ptr<TPCPadGainCalib> GPUO2Interface::getPadGainCalib(const o2::tpc::CalDet<float>& in) +{ + return std::make_unique<TPCPadGainCalib>(in); +} + +std::unique_ptr<TPCdEdxCalibrationSplines> GPUO2Interface::getdEdxCalibrationSplinesDefault() +{ + return std::make_unique<TPCdEdxCalibrationSplines>(); +} + +int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib) +{ + return 1; +} diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index 6fdf163d9b84c..22fc8f9659097 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,8 +16,8 @@ #define GPUO2INTERFACE_H // Some defines denoting that we are compiling for O2 -#ifndef HAVE_O2HEADERS -#define HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS #endif #ifndef GPUCA_TPC_GEOMETRY_O2 #define GPUCA_TPC_GEOMETRY_O2 @@ -26,12 +27,15 @@ #endif #include <memory> +#include <vector> #include "GPUCommonDef.h" #include "GPUDataTypes.h" namespace o2::tpc { struct ClusterNativeAccess; struct ClusterNative; +template <class T> +class CalDet; } // namespace o2::tpc namespace o2::gpu @@ -40,13 +44,14 @@ class GPUReconstruction; class GPUChainTracking; struct GPUO2InterfaceConfiguration; struct GPUInterfaceOutputs; -struct GPUOutputControl; +struct GPUTrackingOutputs; +struct GPUConstantMem; -class GPUTPCO2Interface +class GPUO2Interface { public: - GPUTPCO2Interface(); - ~GPUTPCO2Interface(); + GPUO2Interface(); + ~GPUO2Interface(); int Initialize(const GPUO2InterfaceConfiguration& config); void Deinitialize(); @@ -54,28 +59,32 @@ class GPUTPCO2Interface int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr); void Clear(bool clearOutputs); + // Updates all calibration objects that are != nullptr in newCalib + int UpdateCalibration(const GPUCalibObjectsConst& newCalib); + bool GetParamContinuous() { return (mContinuous); } void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const; + static std::unique_ptr<TPCPadGainCalib> getPadGainCalibDefault(); + static std::unique_ptr<TPCPadGainCalib> getPadGainCalib(const o2::tpc::CalDet<float>& in); + static std::unique_ptr<TPCdEdxCalibrationSplines> getdEdxCalibrationSplinesDefault(); + int registerMemoryForGPU(const void* ptr, size_t size); int unregisterMemoryForGPU(const void* ptr); const GPUO2InterfaceConfiguration& getConfig() const { return *mConfig; } private: - GPUTPCO2Interface(const GPUTPCO2Interface&); - GPUTPCO2Interface& operator=(const GPUTPCO2Interface&); + GPUO2Interface(const GPUO2Interface&); + GPUO2Interface& operator=(const GPUO2Interface&); bool mInitialized = false; bool mContinuous = false; - std::unique_ptr<GPUReconstruction> mRec; - GPUChainTracking* mChain = nullptr; - std::unique_ptr<GPUO2InterfaceConfiguration> mConfig; - std::unique_ptr<GPUOutputControl> mOutputCompressedClusters; - std::unique_ptr<GPUOutputControl> mOutputClustersNative; - std::unique_ptr<GPUOutputControl> mOutputTPCTracks; - std::unique_ptr<GPUOutputControl> mOutputTPCClusterLabels; + std::unique_ptr<GPUReconstruction> mRec; //! + GPUChainTracking* mChain = nullptr; //! + std::unique_ptr<GPUO2InterfaceConfiguration> mConfig; //! + std::unique_ptr<GPUTrackingOutputs> mOutputRegions; //! }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx index 55f754a88b4e5..e0428587f1669 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,7 +27,7 @@ using namespace o2::gpu; #define AddOptionVec(name, type, optname, optnameshort, help, ...) #define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) #define AddSubConfig(name, instance) -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) O2ParamImpl(GPUCA_M_CAT(GPUConfigurableParam, name)) +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) O2ParamImpl(GPUCA_M_CAT(GPUConfigurableParam, name)) #define BeginHiddenConfig(...) #define EndConfig() #define AddCustomCPP(...) @@ -50,7 +51,7 @@ using namespace o2::gpu; #undef AddHelp #undef AddShortcut -GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam() +GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam_internal() { #define BeginNamespace(name) #define EndNamespace() @@ -64,11 +65,11 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam() for (int i = 0; i < count; i++) { \ dst.name[i] = src.name[i]; \ } -#define AddSubConfig(name, instance) -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) \ - name instance; \ - { \ - auto& src = GPUCA_M_CAT(GPUConfigurableParam, name)::Instance(); \ +#define AddSubConfig(name, instance) dst.instance = instance; +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) \ + name instance; \ + { \ + auto& src = GPUCA_M_CAT(GPUConfigurableParam, name)::Instance(); \ name& dst = instance; #define BeginHiddenConfig(name, instance) { #define EndConfig() } @@ -95,21 +96,41 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam() configProcessing = proc; configReconstruction = rec; - configDisplay = GL; + configDisplay = display; configQA = QA; if (global.continuousMaxTimeBin) { - configEvent.continuousMaxTimeBin = global.continuousMaxTimeBin; + configGRP.continuousMaxTimeBin = global.continuousMaxTimeBin; } if (global.solenoidBz > -1e6f) { - configEvent.solenoidBz = global.solenoidBz; + configGRP.solenoidBz = global.solenoidBz; } if (global.constBz) { - configEvent.constBz = global.constBz; + configGRP.constBz = global.constBz; + } + if (global.gpuDisplayfilterMacro != "") { + configDisplay.filterMacros.emplace_back(global.gpuDisplayfilterMacro); } - if (configReconstruction.TrackReferenceX == 1000.f) { - configReconstruction.TrackReferenceX = 83.f; + if (configReconstruction.tpc.trackReferenceX == 1000.f) { + configReconstruction.tpc.trackReferenceX = 83.f; } configDeviceBackend.deviceType = GPUDataTypes::GetDeviceType(global.deviceType.c_str()); configDeviceBackend.forceDeviceType = global.forceDeviceType; return global; } + +#include "utils/qconfig_helpers.h" + +namespace +{ +GPUSettingsStandalone configStandalone; +std::vector<std::function<void()>> qprint_global; +#define QCONFIG_PRINT +#include "utils/qconfig.h" +#undef QCONFIG_PRINT +} // namepsace + +void GPUO2InterfaceConfiguration::PrintParam_internal() +{ + qConfigPrint(configProcessing, "proc."); + qConfigPrint(configReconstruction, "rec."); +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h index 0f55a60f17874..a296567ecb269 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,8 +23,8 @@ #define GPUO2INTERFACECONFIGURABLEPARAM_H // Some defines denoting that we are compiling for O2 -#ifndef HAVE_O2HEADERS -#define HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS #endif #ifndef GPUCA_TPC_GEOMETRY_O2 #define GPUCA_TPC_GEOMETRY_O2 @@ -50,9 +51,9 @@ #define AddOptionVec(name, type, optname, optnameshort, help, ...) #define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) type name[count] = {default}; #define AddSubConfig(name, instance) -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) \ +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) \ struct GPUCA_M_CAT(GPUConfigurableParam, name) : public o2::conf::ConfigurableParamHelper<GPUCA_M_CAT(GPUConfigurableParam, name)> { \ - O2ParamDef(GPUCA_M_CAT(GPUConfigurableParam, name), GPUCA_M_STR(GPUCA_M_CAT(GPU_, instance))) public: + O2ParamDef(GPUCA_M_CAT(GPUConfigurableParam, name), GPUCA_M_STR(GPUCA_M_CAT(GPU_, o2prefix))) public: #define BeginHiddenConfig(name, instance) struct GPUCA_M_CAT(GPUConfigurableParam, name) { #define EndConfig() \ } \ diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx new file mode 100644 index 0000000000000..10535c9b1283f --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceConfiguration.cxx +/// \author David Rohr + +#include "GPUO2InterfaceConfiguration.h" +#include "GPUDataTypes.h" + +using namespace o2::gpu; + +GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam() +{ + return ReadConfigurableParam_internal(); +} + +void GPUO2InterfaceConfiguration::PrintParam() +{ + PrintParam_internal(); +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h index b3ca1cabe5ab0..8df8883a9a304 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,8 +15,8 @@ #ifndef GPUO2INTERFACECONFIGURATION_H #define GPUO2INTERFACECONFIGURATION_H -#ifndef HAVE_O2HEADERS -#define HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS #endif #ifndef GPUCA_TPC_GEOMETRY_O2 #define GPUCA_TPC_GEOMETRY_O2 @@ -32,6 +33,7 @@ #include "GPUSettings.h" #include "GPUDataTypes.h" #include "GPUHostDataTypes.h" +#include "GPUOutputControl.h" #include "DataFormatsTPC/Constants.h" class TH1F; @@ -44,34 +46,20 @@ namespace tpc { class TrackTPC; class Digit; -} +} // namespace tpc namespace gpu { class TPCFastTransform; +class GPUReconstruction; struct GPUSettingsO2; -// This defines an output region. Ptr points to a memory buffer, which should have a proper alignment. -// Since DPL does not respect the alignment of data types, we do not impose anything specic but just use a char data type, but it should be >= 64 bytes ideally. -// The size defines the maximum possible buffer size when GPUReconstruction is called, and returns the number of filled bytes when it returns. -// If ptr == nullptr, there is no region defined and GPUReconstruction will write its output to an internal buffer. -// If allocator is set, it is called as a callback to provide a ptr to the memory. -struct GPUInterfaceOutputRegion { - void* ptr = nullptr; - size_t size = 0; - std::function<void*(size_t)> allocator = nullptr; -}; - struct GPUInterfaceQAOutputs { - const std::vector<TH1F>* hist1; - const std::vector<TH2F>* hist2; - const std::vector<TH1D>* hist3; + const std::vector<TH1F>* hist1 = nullptr; + const std::vector<TH2F>* hist2 = nullptr; + const std::vector<TH1D>* hist3 = nullptr; }; -struct GPUInterfaceOutputs { - GPUInterfaceOutputRegion compressedClusters; - GPUInterfaceOutputRegion clustersNative; - GPUInterfaceOutputRegion tpcTracks; - GPUInterfaceOutputRegion clusterLabels; +struct GPUInterfaceOutputs : public GPUTrackingOutputs { GPUInterfaceQAOutputs qa; }; @@ -85,8 +73,6 @@ struct GPUO2InterfaceConfiguration { struct GPUInterfaceSettings { int dumpEvents = 0; bool outputToExternalBuffers = false; - bool dropSecondaryLegs = true; - float memoryBufferScaleFactor = 1.f; // These constants affect GPU memory allocation only and do not limit the CPU processing unsigned long maxTPCZS = 8192ul * 1024 * 1024; unsigned int maxTPCHits = 1024 * 1024 * 1024; @@ -96,50 +82,23 @@ struct GPUO2InterfaceConfiguration { GPUSettingsDeviceBackend configDeviceBackend; GPUSettingsProcessing configProcessing; - GPUSettingsEvent configEvent; + GPUSettingsGRP configGRP; GPUSettingsRec configReconstruction; GPUSettingsDisplay configDisplay; GPUSettingsQA configQA; GPUInterfaceSettings configInterface; GPURecoStepConfiguration configWorkflow; - GPUCalibObjects configCalib; + GPUCalibObjectsConst configCalib; GPUSettingsO2 ReadConfigurableParam(); -}; - -// Structure with pointers to actual data for input and output -// Which ptr is used for input and which for output is defined in GPUO2InterfaceConfiguration::configWorkflow -// Inputs and outputs are mutually exclusive. -// Inputs which are nullptr are considered empty, and will not throw an error. -// Outputs, which point to std::[container] / MCTruthContainer, will be filled and no output -// is written if the ptr is a nullptr. -// Outputs, which point to other structures are set by GPUCATracking to the location of the output. The previous -// value of the pointer is overridden. GPUCATracking will try to place the output in the "void* outputBuffer" -// location if it is not a nullptr. -struct GPUO2InterfaceIOPtrs { - // Input: TPC clusters in cluster native format, or digits, or list of ZS pages - const as it can only be input - const o2::tpc::ClusterNativeAccess* clusters = nullptr; - const std::array<gsl::span<const o2::tpc::Digit>, o2::tpc::constants::MAXSECTOR>* o2Digits = nullptr; - std::array<const o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>*, o2::tpc::constants::MAXSECTOR>* o2DigitsMC = nullptr; - const o2::gpu::GPUTrackingInOutZS* tpcZS = nullptr; + void PrintParam(); - // Input / Output for Merged TPC tracks, two ptrs, for the tracks themselves, and for the MC labels. - std::vector<o2::tpc::TrackTPC>* outputTracks = nullptr; - std::vector<uint32_t>* outputClusRefs = nullptr; - std::vector<o2::MCCompLabel>* outputTracksMCTruth = nullptr; - - // Output for entropy-reduced clusters of TPC compression - const o2::tpc::CompressedClustersFlat* compressedClusters = nullptr; - - // Hint for GPUCATracking to place its output in this buffer if possible. - // This enables to create the output directly in a shared memory segment of the framework. - // This allows further processing with zero-copy. - // So far this is only a hint, GPUCATracking will not always follow. - // If outputBuffer = nullptr, GPUCATracking will allocate the output internally and own the memory. - // TODO: Make this mandatory if outputBuffer != nullptr, and throw an error if outputBufferSize is too small. - void* outputBuffer = nullptr; - size_t outputBufferSize = 0; + private: + friend class GPUReconstruction; + GPUSettingsO2 ReadConfigurableParam_internal(); + void PrintParam_internal(); }; + } // namespace gpu } // namespace o2 diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx new file mode 100644 index 0000000000000..6a1deef5bec99 --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx @@ -0,0 +1,75 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceDisplay.cxx +/// \author David Rohr + +#include "GPUParam.h" +#include "GPUDisplay.h" +#include "GPUQA.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceDisplay.h" +#include "GPUDisplayBackend.h" +#include "GPUDisplayBackendGlfw.h" +#include <unistd.h> + +using namespace o2::gpu; +using namespace o2::tpc; + +GPUO2InterfaceDisplay::GPUO2InterfaceDisplay(const GPUO2InterfaceConfiguration* config) +{ + mConfig.reset(new GPUO2InterfaceConfiguration(*config)); + mBackend.reset(new GPUDisplayBackendGlfw); + mConfig->configProcessing.eventDisplay = mBackend.get(); + mConfig->configDisplay.showTPCTracksFromO2Format = true; + mParam.reset(new GPUParam); + mParam->SetDefaults(&config->configGRP, &config->configReconstruction, &config->configProcessing, nullptr); + mParam->par.earlyTpcTransform = 0; + if (mConfig->configProcessing.runMC) { + mQA.reset(new GPUQA(nullptr, &config->configQA, mParam.get())); + mQA->InitO2MCData(); + } + mDisplay.reset(new GPUDisplay(mBackend.get(), nullptr, nullptr, mParam.get(), &mConfig->configCalib, &mConfig->configDisplay)); +} + +GPUO2InterfaceDisplay::~GPUO2InterfaceDisplay() = default; + +int GPUO2InterfaceDisplay::startDisplay() +{ + int retVal = mDisplay->StartDisplay(); + if (retVal) { + return retVal; + } + mDisplay->WaitForNextEvent(); + return 0; +} + +int GPUO2InterfaceDisplay::show(const GPUTrackingInOutPointers* ptrs) +{ + std::unique_ptr<GPUTrackingInOutPointers> tmpPtr; + if (mConfig->configProcessing.runMC) { + tmpPtr = std::make_unique<GPUTrackingInOutPointers>(*ptrs); + mQA->InitO2MCData(tmpPtr.get()); + ptrs = tmpPtr.get(); + } + mDisplay->ShowNextEvent(ptrs); + do { + usleep(10000); + } while (mBackend->mDisplayControl == 0); + mDisplay->WaitForNextEvent(); + return 0; +} + +int GPUO2InterfaceDisplay::endDisplay() +{ + mBackend->DisplayExit(); + return 0; +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h new file mode 100644 index 0000000000000..2d0151df22153 --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceDisplay.h +/// \author David Rohr + +#ifndef GPUO2INTERFACEDisplay_H +#define GPUO2INTERFACEDisplay_H + +// Some defines denoting that we are compiling for O2 +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS +#endif +#ifndef GPUCA_TPC_GEOMETRY_O2 +#define GPUCA_TPC_GEOMETRY_O2 +#endif +#ifndef GPUCA_O2_INTERFACE +#define GPUCA_O2_INTERFACE +#endif + +#include <memory> +#include <vector> + +namespace o2::gpu +{ +class GPUDisplay; +class GPUQA; +struct GPUParam; +struct GPUTrackingInOutPointers; +struct GPUO2InterfaceConfiguration; +class GPUDisplayBackend; +class GPUO2InterfaceDisplay +{ + public: + GPUO2InterfaceDisplay(const GPUO2InterfaceConfiguration* config = nullptr); + ~GPUO2InterfaceDisplay(); + + int startDisplay(); + int show(const GPUTrackingInOutPointers* ptrs); + int endDisplay(); + + private: + std::unique_ptr<GPUDisplay> mDisplay; + std::unique_ptr<GPUQA> mQA; + std::unique_ptr<GPUParam> mParam; + std::unique_ptr<GPUDisplayBackend> mBackend; + std::unique_ptr<GPUO2InterfaceConfiguration> mConfig; +}; +} // namespace o2::gpu + +#endif diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceLinkDef.h b/GPU/GPUTracking/Interface/GPUO2InterfaceLinkDef.h new file mode 100644 index 0000000000000..21ed9f04af8d7 --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceLinkDef.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceLinkDef.h +/// \author David Rohr + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::gpu::GPUO2Interface + ; +#pragma link C++ class o2::gpu::GPUO2InterfaceRefit + ; +#pragma link C++ class o2::gpu::GPUO2InterfaceQA + ; + +#endif diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx index 31bc68d340edb..c945bbbac9f82 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,21 +12,40 @@ /// \file GPUO2InterfaceQA.cxx /// \author David Rohr +#include "GPUParam.h" #include "GPUQA.h" +#include "GPUO2InterfaceConfiguration.h" #include "GPUO2InterfaceQA.h" using namespace o2::gpu; using namespace o2::tpc; -GPUO2InterfaceQA::GPUO2InterfaceQA(const GPUSettingsQA* config) : mQA(new GPUQA(nullptr, config)) +GPUO2InterfaceQA::GPUO2InterfaceQA(const GPUO2InterfaceConfiguration* config) { + mParam.reset(new GPUParam); + mParam->SetDefaults(&config->configGRP, &config->configReconstruction, &config->configProcessing, nullptr); + mQA.reset(new GPUQA(nullptr, &config->configQA, mParam.get())); } GPUO2InterfaceQA::~GPUO2InterfaceQA() = default; -int GPUO2InterfaceQA::postprocess(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out) +int GPUO2InterfaceQA::initializeForProcessing(int tasks) { - if (mQA->loadHistograms(in1, in2, in3)) { + return mQA->InitQA(tasks); +} + +void GPUO2InterfaceQA::runQA(const std::vector<o2::tpc::TrackTPC>* tracksExternal, const std::vector<o2::MCCompLabel>* tracksExtMC, const o2::tpc::ClusterNativeAccess* clNative) +{ + mQA->RunQA(false, tracksExternal, tracksExtMC, clNative); +} +int GPUO2InterfaceQA::postprocess(TObjArray& out) +{ + return mQA->DrawQAHistograms(&out); +} + +int GPUO2InterfaceQA::postprocessExternal(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out, int tasks) +{ + if (mQA->loadHistograms(in1, in2, in3, tasks)) { return 1; } return mQA->DrawQAHistograms(&out); @@ -35,3 +55,15 @@ void GPUO2InterfaceQA::cleanup() { mQA->DrawQAHistogramsCleanup(); } + +void GPUO2InterfaceQA::getHists(const std::vector<TH1F>*& h1, const std::vector<TH2F>*& h2, const std::vector<TH1D>*& h3) +{ + h1 = &mQA->getHistograms1D(); + h2 = &mQA->getHistograms2D(); + h3 = &mQA->getHistograms1Dd(); +} + +void GPUO2InterfaceQA::resetHists() +{ + mQA->resetHists(); +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h index 6d75cdb645967..fb1324a97e3be 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,8 +16,8 @@ #define GPUO2INTERFACEQA_H // Some defines denoting that we are compiling for O2 -#ifndef HAVE_O2HEADERS -#define HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS #endif #ifndef GPUCA_TPC_GEOMETRY_O2 #define GPUCA_TPC_GEOMETRY_O2 @@ -33,22 +34,42 @@ class TH1D; class TH2F; class TObjArray; +namespace o2 +{ +class MCCompLabel; +namespace tpc +{ +class TrackTPC; +struct ClusterNativeAccess; +} // namespace tpc +} // namespace o2 + namespace o2::gpu { class GPUQA; -class GPUSettingsQA; +struct GPUParam; +struct GPUO2InterfaceConfiguration; class GPUO2InterfaceQA { public: - GPUO2InterfaceQA(const GPUSettingsQA* config = nullptr); + GPUO2InterfaceQA(const GPUO2InterfaceConfiguration* config = nullptr); ~GPUO2InterfaceQA(); + int initializeForProcessing(int tasks); // only needed for processing, not for postprocessing + + void runQA(const std::vector<o2::tpc::TrackTPC>* tracksExternal, const std::vector<o2::MCCompLabel>* tracksExtMC, const o2::tpc::ClusterNativeAccess* clNative); + int postprocess(TObjArray& out); + // Input might be modified, so we assume non-const. If it is const, a copy should be created before. - int postprocess(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out); + int postprocessExternal(std::vector<TH1F>& in1, std::vector<TH2F>& in2, std::vector<TH1D>& in3, TObjArray& out, int tasks); + + void getHists(const std::vector<TH1F>*& h1, const std::vector<TH2F>*& h2, const std::vector<TH1D>*& h3); + void resetHists(); void cleanup(); private: std::unique_ptr<GPUQA> mQA; + std::unique_ptr<GPUParam> mParam; }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx index e406532c81719..f23f2f943b54d 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,11 +17,29 @@ #include "DataFormatsTPC/TrackTPC.h" #include "GPUParam.h" #include "GPUTPCGMMergedTrackHit.h" +#include "GPUTrackingRefit.h" using namespace o2::gpu; using namespace o2::tpc; -GPUTPCO2InterfaceRefit::GPUTPCO2InterfaceRefit(const o2::tpc::ClusterNativeAccess* cl, const TPCFastTransform* trans, float bz, const TPCClRefElem* trackRef, const unsigned char* sharedmap, std::vector<o2::tpc::TrackTPC>* trks, o2::base::Propagator* p) : mRefit(), mParam(new GPUParam) +void GPUO2InterfaceRefit::fillSharedClustersMap(const ClusterNativeAccess* cl, const gsl::span<const TrackTPC> trks, const TPCClRefElem* trackRef, unsigned char* shmap) +{ + if (!cl || !shmap) { + throw std::runtime_error("Must provide clusters access and preallocated recepient for shared map"); + } + memset(shmap, 0, sizeof(char) * cl->nClustersTotal); + for (unsigned int i = 0; i < trks.size(); i++) { + for (unsigned int j = 0; j < trks[i].getNClusterReferences(); j++) { + size_t idx = &trks[i].getCluster(trackRef, j, *cl) - cl->clustersLinear; + shmap[idx] = shmap[idx] ? 2 : 1; + } + } + for (unsigned int i = 0; i < cl->nClustersTotal; i++) { + shmap[i] = (shmap[i] > 1 ? GPUTPCGMMergedTrackHit::flagShared : 0) | cl->clustersLinear[i].getFlags(); + } +} + +GPUO2InterfaceRefit::GPUO2InterfaceRefit(const ClusterNativeAccess* cl, const TPCFastTransform* trans, float bz, const TPCClRefElem* trackRef, const unsigned char* sharedmap, const std::vector<TrackTPC>* trks, o2::base::Propagator* p) : mParam(new GPUParam) { if (sharedmap == nullptr && trks == nullptr) { throw std::runtime_error("Must provide either shared cluster map or vector of tpc tracks to build the map"); @@ -28,28 +47,25 @@ GPUTPCO2InterfaceRefit::GPUTPCO2InterfaceRefit(const o2::tpc::ClusterNativeAcces if (sharedmap == nullptr) { mSharedMap.resize(cl->nClustersTotal); sharedmap = mSharedMap.data(); - std::fill(mSharedMap.begin(), mSharedMap.end(), 0); - for (unsigned int i = 0; i < (*trks).size(); i++) { - for (unsigned int j = 0; j < (*trks)[i].getNClusterReferences(); j++) { - size_t idx = &(*trks)[i].getCluster(trackRef, j, *cl) - cl->clustersLinear; - mSharedMap[idx] = mSharedMap[idx] ? 2 : 1; - } - } - for (unsigned int i = 0; i < cl->nClustersTotal; i++) { - mSharedMap[i] = (mSharedMap[i] > 1 ? GPUTPCGMMergedTrackHit::flagShared : 0) | cl->clustersLinear[i].getFlags(); - } + fillSharedClustersMap(cl, *trks, trackRef, mSharedMap.data()); } + mRefit = std::make_unique<GPUTrackingRefit>(); mParam->SetDefaults(bz); - mRefit.SetGPUParam(mParam.get()); - mRefit.SetClusterStateArray(sharedmap); - mRefit.SetPropagator(p); - mRefit.SetClusterNative(cl); - mRefit.SetTrackHitReferences(trackRef); - mRefit.SetFastTransform(trans); + mRefit->SetGPUParam(mParam.get()); + mRefit->SetClusterStateArray(sharedmap); + mRefit->SetPropagator(p); + mRefit->SetClusterNative(cl); + mRefit->SetTrackHitReferences(trackRef); + mRefit->SetFastTransform(trans); } -void GPUTPCO2InterfaceRefit::setGPUTrackFitInProjections(bool v) { mParam->rec.fitInProjections = v; } -void GPUTPCO2InterfaceRefit::setTrackReferenceX(float v) { mParam->rec.TrackReferenceX = v; } +int GPUO2InterfaceRefit::RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward, bool resetCov) { return mRefit->RefitTrackAsGPU(trk, outward, resetCov); } +int GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward, bool resetCov) { return mRefit->RefitTrackAsTrackParCov(trk, outward, resetCov); } +int GPUO2InterfaceRefit::RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsGPU(trk, clusRef, time0, chi2, outward, resetCov); } +int GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsTrackParCov(trk, clusRef, time0, chi2, outward, resetCov); } +void GPUO2InterfaceRefit::setIgnoreErrorsAtTrackEnds(bool v) { mRefit->mIgnoreErrorsOnTrackEnds = v; } +void GPUO2InterfaceRefit::setGPUTrackFitInProjections(bool v) { mParam->rec.fitInProjections = v; } +void GPUO2InterfaceRefit::setTrackReferenceX(float v) { mParam->rec.tpc.trackReferenceX = v; } -GPUTPCO2InterfaceRefit::~GPUTPCO2InterfaceRefit() = default; +GPUO2InterfaceRefit::~GPUO2InterfaceRefit() = default; diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h index 8126290e198b2..1abd34d6fb412 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,8 +16,8 @@ #define GPUO2INTERFACEREFIT_H // Some defines denoting that we are compiling for O2 -#ifndef HAVE_O2HEADERS -#define HAVE_O2HEADERS +#ifndef GPUCA_HAVE_O2HEADERS +#define GPUCA_HAVE_O2HEADERS #endif #ifndef GPUCA_TPC_GEOMETRY_O2 #define GPUCA_TPC_GEOMETRY_O2 @@ -25,19 +26,42 @@ #define GPUCA_O2_INTERFACE #endif -#include "GPUTrackingRefit.h" #include <memory> #include <vector> +#include <gsl/span> +namespace o2::base +{ +template <typename value_T> +class PropagatorImpl; +using Propagator = PropagatorImpl<float>; +} // namespace o2::base +namespace o2::dataformats +{ +template <typename FirstEntry, typename NElem> +class RangeReference; +} namespace o2::tpc { using TPCClRefElem = uint32_t; -} +using TrackTPCClusRef = o2::dataformats::RangeReference<uint32_t, uint16_t>; +class TrackTPC; +struct ClusterNativeAccess; +} // namespace o2::tpc +namespace o2::track +{ +template <typename value_T> +class TrackParametrizationWithError; +using TrackParCovF = TrackParametrizationWithError<float>; +using TrackParCov = TrackParCovF; +} // namespace o2::track namespace o2::gpu { class GPUParam; -class GPUTPCO2InterfaceRefit +class GPUTrackingRefit; +class TPCFastTransform; +class GPUO2InterfaceRefit { public: // Must initialize with: @@ -45,19 +69,21 @@ class GPUTPCO2InterfaceRefit // - Either the shared cluster map (sharedmap) or the vector of tpc tracks (trks) to build the shared cluster map internally // - o2::base::Propagator (p) in case RefitTrackAsTrackParCov is to be used - GPUTPCO2InterfaceRefit(const o2::tpc::ClusterNativeAccess* cl, const TPCFastTransform* trans, float bz, const o2::tpc::TPCClRefElem* trackRef, const unsigned char* sharedmap = nullptr, std::vector<o2::tpc::TrackTPC>* trks = nullptr, o2::base::Propagator* p = nullptr); - ~GPUTPCO2InterfaceRefit(); + GPUO2InterfaceRefit(const o2::tpc::ClusterNativeAccess* cl, const TPCFastTransform* trans, float bz, const o2::tpc::TPCClRefElem* trackRef, const unsigned char* sharedmap = nullptr, const std::vector<o2::tpc::TrackTPC>* trks = nullptr, o2::base::Propagator* p = nullptr); + ~GPUO2InterfaceRefit(); - int RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false) { return mRefit.RefitTrackAsGPU(trk, outward, resetCov); } - int RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false) { return mRefit.RefitTrackAsTrackParCov(trk, outward, resetCov); } - int RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false) { return mRefit.RefitTrackAsGPU(trk, clusRef, time0, chi2, outward, resetCov); } - int RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false) { return mRefit.RefitTrackAsTrackParCov(trk, clusRef, time0, chi2, outward, resetCov); } + int RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false); + int RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false); + int RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false); + int RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false); void setGPUTrackFitInProjections(bool v = true); void setTrackReferenceX(float v); - void setIgnoreErrorsAtTrackEnds(bool v) { mRefit.mIgnoreErrorsOnTrackEnds = v; } + void setIgnoreErrorsAtTrackEnds(bool v); + + static void fillSharedClustersMap(const o2::tpc::ClusterNativeAccess* cl, const gsl::span<const o2::tpc::TrackTPC> trks, const o2::tpc::TPCClRefElem* trackRef, unsigned char* shmap); private: - GPUTrackingRefit mRefit; + std::unique_ptr<GPUTrackingRefit> mRefit; std::unique_ptr<GPUParam> mParam; std::vector<unsigned char> mSharedMap; }; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h index 0d6c96e10610a..285166006db2e 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergedTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMMergedTrack.h index 1a4479fc74d38..1bf22616306a5 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergedTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergedTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,6 @@ #include "GPUTPCGMTrackParam.h" #include "GPUTPCGMMergedTrackHit.h" -#include "GPUdEdxInfo.h" namespace GPUCA_NAMESPACE { @@ -104,21 +104,12 @@ class GPUTPCGMMergedTrack GPUd() void SetLegs(unsigned char v) { mLegs = v; } GPUd() unsigned char Legs() const { return mLegs; } - GPUd() const GPUTPCGMTrackParam::GPUTPCOuterParam& OuterParam() const { return mOuterParam; } - GPUd() GPUTPCGMTrackParam::GPUTPCOuterParam& OuterParam() - { - return mOuterParam; - } - GPUd() const GPUdEdxInfo& dEdxInfo() const { return mdEdxInfo; } - GPUd() GPUdEdxInfo& dEdxInfo() - { - return mdEdxInfo; - } + GPUd() const gputpcgmmergertypes::GPUTPCOuterParam& OuterParam() const { return mOuterParam; } + GPUd() gputpcgmmergertypes::GPUTPCOuterParam& OuterParam() { return mOuterParam; } private: GPUTPCGMTrackParam mParam; //* fitted track parameters - GPUTPCGMTrackParam::GPUTPCOuterParam mOuterParam; //* outer param - GPUdEdxInfo mdEdxInfo; //* dEdx information + gputpcgmmergertypes::GPUTPCOuterParam mOuterParam; //* outer param float mAlpha; //* alpha angle float mLastX; //* outer X @@ -129,6 +120,8 @@ class GPUTPCGMMergedTrack unsigned int mNClustersFitted; //* number of clusters used in fit unsigned char mFlags; unsigned char mLegs; + + ClassDefNV(GPUTPCGMMergedTrack, 0); }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergedTrackHit.h b/GPU/GPUTracking/Merger/GPUTPCGMMergedTrackHit.h index 50cc8ac2e9412..3505759e49701 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergedTrackHit.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergedTrackHit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 6bb95ab55d02d..3633aa0bfbffb 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,13 @@ #define GPUCA_CADEBUG 0 #define GPUCA_MERGE_LOOPER_MC 0 +#include "GPUCommonDef.h" + +#if !defined(GPUCA_GPUCODE) && (defined(GPUCA_MERGER_BY_MC_LABEL) || defined(GPUCA_CADEBUG_ENABLED) || GPUCA_MERGE_LOOPER_MC) +#include "AliHLTTPCClusterMCData.h" +#include "GPUROOTDump.h" +#endif + #ifndef GPUCA_GPUCODE_DEVICE #include <cstdio> #include <cstring> @@ -42,13 +50,15 @@ #include "GPUTPCGMSliceTrack.h" #include "GPUTPCGMBorderTrack.h" -#if !defined(GPUCA_GPUCODE) && (defined(GPUCA_MERGER_BY_MC_LABEL) || defined(GPUCA_CADEBUG_ENABLED) || GPUCA_MERGE_LOOPER_MC) -#include "AliHLTTPCClusterMCData.h" -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS #include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/TrackTPC.h" +#ifndef GPUCA_GPUCODE #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #endif +#else +#include "GPUO2FakeClasses.h" #endif using namespace GPUCA_NAMESPACE::gpu; @@ -64,13 +74,23 @@ static constexpr int kMaxClusters = GPUCA_MERGER_MAX_TRACK_CLUSTERS; #undef OFFLINE_FITTER #endif +namespace GPUCA_NAMESPACE::gpu +{ +struct MergeLooperParam { + float refz; + float x; + float y; + unsigned int id; +}; +} // namespace GPUCA_NAMESPACE::gpu + #ifndef GPUCA_GPUCODE #include "GPUQA.h" #include "GPUMemorySizeScalers.h" GPUTPCGMMerger::GPUTPCGMMerger() - : mTrackLinks(nullptr), mNMaxSliceTracks(0), mNMaxTracks(0), mNMaxSingleSliceTracks(0), mNMaxOutputTrackClusters(0), mNMaxClusters(0), mMemoryResMemory(-1), mNClusters(0), mOutputTracks(nullptr), mSliceTrackInfos(nullptr), mSliceTrackInfoIndex(nullptr), mClusters(nullptr), mClustersXYZ(nullptr), mGlobalClusterIDs(nullptr), mClusterAttachment(nullptr), mTrackOrderAttach(nullptr), mTrackOrderProcess(nullptr), mTmpMem(nullptr), mBorderMemory(nullptr), mBorderRangeMemory(nullptr), mMemory(nullptr), mRetryRefitIds(nullptr), mLoopData(nullptr) + : mTrackLinks(nullptr), mNMaxSliceTracks(0), mNMaxTracks(0), mNMaxSingleSliceTracks(0), mNMaxOutputTrackClusters(0), mNMaxClusters(0), mMemoryResMemory(-1), mNClusters(0), mOutputTracks(nullptr), mSliceTrackInfos(nullptr), mSliceTrackInfoIndex(nullptr), mClusters(nullptr), mClustersXYZ(nullptr), mGlobalClusterIDs(nullptr), mClusterAttachment(nullptr), mOutputTracksTPCO2(nullptr), mOutputClusRefsTPCO2(nullptr), mOutputTracksTPCO2MC(nullptr), mTrackOrderAttach(nullptr), mTrackOrderProcess(nullptr), mBorderMemory(nullptr), mBorderRangeMemory(nullptr), mMemory(nullptr), mRetryRefitIds(nullptr), mLoopData(nullptr) { //* constructor @@ -169,7 +189,7 @@ long int GPUTPCGMMerger::GetTrackLabelA(const S& trk) for (int i = 0; i < nClusters; i++) { int id; if constexpr (std::is_same<S, GPUTPCGMBorderTrack&>::value) { - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { const GPUTPCTracker& tracker = GetConstantMem()->tpcTrackers[sliceTrack->Slice()]; const GPUTPCHitId& ic = tracker.TrackHits()[sliceTrack->OrigTrack()->FirstHitID() + i]; id = tracker.Data().ClusterDataIndex(tracker.Data().Row(ic.RowIndex()), ic.HitIndex()) + GetConstantMem()->ioPtrs.clustersNative->clusterOffset[sliceTrack->Slice()][0]; @@ -240,25 +260,39 @@ void* GPUTPCGMMerger::SetPointersMerger(void* mem) { computePointerWithAlignment(mem, mSliceTrackInfos, mNMaxSliceTracks); computePointerWithAlignment(mem, mSliceTrackInfoIndex, NSLICES * 2 + 1); - if (mRec->GetParam().rec.NonConsecutiveIDs) { + if (mRec->GetParam().rec.nonConsecutiveIDs) { computePointerWithAlignment(mem, mGlobalClusterIDs, mNMaxOutputTrackClusters); } - computePointerWithAlignment(mem, mBorderMemory, 2 * mNMaxSliceTracks); - computePointerWithAlignment(mem, mBorderRangeMemory, 2 * mNMaxSliceTracks); - computePointerWithAlignment(mem, mTrackLinks, mNMaxSliceTracks); - computePointerWithAlignment(mem, mTrackCCRoots, mNMaxSliceTracks); - size_t tmpSize = CAMath::Max(CAMath::Max<unsigned int>(mNMaxSingleSliceTracks, 1) * NSLICES * sizeof(int), CAMath::nextMultipleOf<4>(mNMaxTracks) * sizeof(int) + mNMaxClusters * sizeof(unsigned int)); - computePointerWithAlignment(mem, mTmpMem, (tmpSize + sizeof(*mTmpMem) - 1) / sizeof(*mTmpMem)); + void* memBase = mem; + computePointerWithAlignment(mem, mBorderMemory, 2 * mNMaxSliceTracks); // MergeBorders & Resolve + computePointerWithAlignment(mem, mBorderRangeMemory, 2 * mNMaxSliceTracks); int nTracks = 0; for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - const int n = mRec->GetParam().rec.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTracks() : mkSlices[iSlice]->NTracks(); + const int n = mRec->GetParam().rec.tpc.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTracks() : mkSlices[iSlice]->NTracks(); mBorder[iSlice] = mBorderMemory + 2 * nTracks; mBorder[NSLICES + iSlice] = mBorderMemory + 2 * nTracks + n; mBorderRange[iSlice] = mBorderRangeMemory + 2 * nTracks; nTracks += n; } - return mem; + computePointerWithAlignment(mem, mTrackLinks, mNMaxSliceTracks); + computePointerWithAlignment(mem, mTrackCCRoots, mNMaxSliceTracks); + void* memMax = mem; + mem = memBase; + computePointerWithAlignment(mem, mTrackIDs, mNMaxTracks); // UnpackResetIds - RefitSliceTracks - UnpackSliceGlobal + memMax = (void*)std::max((size_t)mem, (size_t)memMax); + mem = memBase; + computePointerWithAlignment(mem, mTrackSort, mNMaxTracks); // PrepareClustersForFit0 - SortTracksQPt - PrepareClustersForFit1 - PrepareClustersForFit1 / Finalize0 - Finalize2 + computePointerWithAlignment(mem, mSharedCount, mNMaxClusters); + memMax = (void*)std::max((size_t)mem, (size_t)memMax); + mem = memBase; + computePointerWithAlignment(mem, mLoopData, mNMaxTracks); // GPUTPCGMMergerTrackFit - GPUTPCGMMergerFollowLoopers + computePointerWithAlignment(mem, mRetryRefitIds, mNMaxTracks); // Reducing mNMaxTracks for mLoopData / mRetryRefitIds does not save memory, since the other parts are larger anyway + memMax = (void*)std::max((size_t)mem, (size_t)memMax); + mem = memBase; + computePointerWithAlignment(mem, mLooperCandidates, mNMaxLooperMatches); // MergeLoopers 1-3 + memMax = (void*)std::max((size_t)mem, (size_t)memMax); + return memMax; } void* GPUTPCGMMerger::SetPointersMemory(void* mem) @@ -269,8 +303,6 @@ void* GPUTPCGMMerger::SetPointersMemory(void* mem) void* GPUTPCGMMerger::SetPointersRefitScratch(void* mem) { - computePointerWithAlignment(mem, mRetryRefitIds, mNMaxTracks); - computePointerWithAlignment(mem, mLoopData, mNMaxTracks); if (mRec->GetProcessingSettings().fullMergerOnGPU) { mem = SetPointersRefitScratch2(mem); } @@ -289,6 +321,9 @@ void* GPUTPCGMMerger::SetPointersRefitScratch2(void* mem) void* GPUTPCGMMerger::SetPointersOutput(void* mem) { computePointerWithAlignment(mem, mOutputTracks, mNMaxTracks); + if (mRec->GetParam().par.dodEdx) { + computePointerWithAlignment(mem, mOutputTracksdEdx, mNMaxTracks); + } computePointerWithAlignment(mem, mClusters, mNMaxOutputTrackClusters); if (mRec->GetParam().par.earlyTpcTransform) { computePointerWithAlignment(mem, mClustersXYZ, mNMaxOutputTrackClusters); @@ -297,12 +332,41 @@ void* GPUTPCGMMerger::SetPointersOutput(void* mem) if (!mRec->GetProcessingSettings().fullMergerOnGPU) { mem = SetPointersRefitScratch2(mem); } - if (mRec->GetRecoSteps() & GPUDataTypes::RecoStep::Refit) { + return mem; +} + +void* GPUTPCGMMerger::SetPointersOutputState(void* mem) +{ + if ((mRec->GetRecoSteps() & GPUDataTypes::RecoStep::Refit) || mRec->GetProcessingSettings().outputSharedClusterMap) { computePointerWithAlignment(mem, mClusterStateExt, mNMaxClusters); } else { mClusterStateExt = nullptr; } + return mem; +} + +void* GPUTPCGMMerger::SetPointersOutputO2(void* mem) +{ + computePointerWithAlignment(mem, mOutputTracksTPCO2, HostProcessor(this).NOutputTracksTPCO2()); + return mem; +} + +void* GPUTPCGMMerger::SetPointersOutputO2Clus(void* mem) +{ + computePointerWithAlignment(mem, mOutputClusRefsTPCO2, HostProcessor(this).NOutputClusRefsTPCO2()); + return mem; +} +void* GPUTPCGMMerger::SetPointersOutputO2MC(void* mem) +{ + computePointerWithAlignment(mem, mOutputTracksTPCO2MC, HostProcessor(this).NOutputTracksTPCO2()); + return mem; +} + +void* GPUTPCGMMerger::SetPointersOutputO2Scratch(void* mem) +{ + computePointerWithAlignment(mem, mTrackSortO2, mNMaxTracks); + computePointerWithAlignment(mem, mClusRefTmp, mNMaxTracks); return mem; } @@ -311,7 +375,16 @@ void GPUTPCGMMerger::RegisterMemoryAllocation() AllocateAndInitializeLate(); mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersMerger, (mRec->GetProcessingSettings().fullMergerOnGPU ? 0 : GPUMemoryResource::MEMORY_HOST) | GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_STACK, "TPCMerger"); mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersRefitScratch, GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_STACK, "TPCMergerRefitScratch"); - mMemoryResOutput = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutput, (mRec->GetProcessingSettings().fullMergerOnGPU ? GPUMemoryResource::MEMORY_OUTPUT : GPUMemoryResource::MEMORY_INOUT) | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutput"); + mMemoryResOutput = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutput, (mRec->GetProcessingSettings().fullMergerOnGPU ? (mRec->GetProcessingSettings().createO2Output > 1 ? GPUMemoryResource::MEMORY_SCRATCH : GPUMemoryResource::MEMORY_OUTPUT) : GPUMemoryResource::MEMORY_INOUT) | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutput"); + mMemoryResOutputState = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutputState, (mRec->GetProcessingSettings().fullMergerOnGPU ? GPUMemoryResource::MEMORY_OUTPUT : GPUMemoryResource::MEMORY_HOST) | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutputState"); + if (mRec->GetProcessingSettings().createO2Output) { + mMemoryResOutputO2Scratch = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutputO2Scratch, GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_STACK | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutputO2Scratch"); + mMemoryResOutputO2 = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutputO2, GPUMemoryResource::MEMORY_OUTPUT | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutputO2"); + mMemoryResOutputO2Clus = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutputO2Clus, GPUMemoryResource::MEMORY_OUTPUT | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutputO2Clus"); + if (mRec->GetProcessingSettings().runMC) { + mMemoryResOutputO2MC = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersOutputO2MC, GPUMemoryResource::MEMORY_OUTPUT_FLAG | GPUMemoryResource::MEMORY_HOST | GPUMemoryResource::MEMORY_CUSTOM, "TPCMergerOutputO2MC"); + } + } mMemoryResMemory = mRec->RegisterMemoryAllocation(this, &GPUTPCGMMerger::SetPointersMemory, GPUMemoryResource::MEMORY_PERMANENT, "TPCMergerMemory"); } @@ -321,9 +394,9 @@ void GPUTPCGMMerger::SetMaxData(const GPUTrackingInOutPointers& io) mNClusters = 0; mNMaxSingleSliceTracks = 0; for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - unsigned int ntrk = mRec->GetParam().rec.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTracks() : mkSlices[iSlice]->NTracks(); + unsigned int ntrk = mRec->GetParam().rec.tpc.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTracks() : mkSlices[iSlice]->NTracks(); mNMaxSliceTracks += ntrk; - mNClusters += mRec->GetParam().rec.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTrackHits() : mkSlices[iSlice]->NTrackClusters(); + mNClusters += mRec->GetParam().rec.tpc.mergerReadFromTrackerDirectly ? *mRec->GetConstantMem().tpcTrackers[iSlice].NTrackHits() : mkSlices[iSlice]->NTrackClusters(); if (mNMaxSingleSliceTracks < ntrk) { mNMaxSingleSliceTracks = ntrk; } @@ -340,17 +413,18 @@ void GPUTPCGMMerger::SetMaxData(const GPUTrackingInOutPointers& io) } else { mNMaxClusters = mNClusters; } + mNMaxLooperMatches = mNMaxClusters / 4; // We have that much scratch memory anyway } int GPUTPCGMMerger::CheckSlices() { for (int i = 0; i < NSLICES; i++) { - if ((Param().rec.mergerReadFromTrackerDirectly ? mRec->GetConstantMem().tpcTrackers[i].CommonMemory()->nLocalTracks : mkSlices[i]->NLocalTracks()) > mNMaxSingleSliceTracks) { + if ((Param().rec.tpc.mergerReadFromTrackerDirectly ? mRec->GetConstantMem().tpcTrackers[i].CommonMemory()->nLocalTracks : mkSlices[i]->NLocalTracks()) > mNMaxSingleSliceTracks) { throw std::runtime_error("mNMaxSingleSliceTracks too small"); } } - if (!(mRec->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSliceTracking) && (!Param().rec.NonConsecutiveIDs || Param().rec.mergerReadFromTrackerDirectly)) { - throw std::runtime_error("Must run also slice tracking if NonConsecutiveIDs = false or mergerReadFromTrackerDirectly"); + if (!(mRec->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSliceTracking) && (!Param().rec.nonConsecutiveIDs || Param().rec.tpc.mergerReadFromTrackerDirectly)) { + throw std::runtime_error("Must run also slice tracking if nonConsecutiveIDs = false or mergerReadFromTrackerDirectly"); } return 0; } @@ -383,6 +457,7 @@ GPUd() int GPUTPCGMMerger::RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const trk.QPt() = inTrack->Param().GetQPt(); trk.TZOffset() = Param().par.earlyTpcTransform ? inTrack->Param().GetZOffset() : GetConstantMem()->calibObjects.fastTransform->convZOffsetToVertexTime(slice, inTrack->Param().GetZOffset(), Param().par.continuousMaxTimeBin); trk.ShiftZ(this, slice, sliceTrack.ClusterZT0(), sliceTrack.ClusterZTN()); + sliceTrack.SetX2(0.f); for (int way = 0; way < 2; way++) { if (way) { prop.SetFitInProjections(true); @@ -396,7 +471,7 @@ GPUd() int GPUTPCGMMerger::RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const for (int i = start; i != end; i += incr) { float x, y, z; int row, flags; - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { const GPUTPCTracker& tracker = GetConstantMem()->tpcTrackers[slice]; const GPUTPCHitId& ic = tracker.TrackHits()[inTrack->FirstHitID() + i]; int clusterIndex = tracker.Data().ClusterDataIndex(tracker.Data().Row(ic.RowIndex()), ic.HitIndex()); @@ -436,7 +511,6 @@ GPUd() int GPUTPCGMMerger::RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const sliceTrack.SetParam2(trk); } else { sliceTrack.Set(trk, inTrack, alpha, slice); - sliceTrack.SetX2(0.f); } } return 0; @@ -444,7 +518,7 @@ GPUd() int GPUTPCGMMerger::RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const GPUd() void GPUTPCGMMerger::SetTrackClusterZT(GPUTPCGMSliceTrack& track, int iSlice, const GPUTPCTrack* sliceTr) { - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { const GPUTPCTracker& trk = GetConstantMem()->tpcTrackers[iSlice]; const GPUTPCHitId& ic1 = trk.TrackHits()[sliceTr->FirstHitID()]; const GPUTPCHitId& ic2 = trk.TrackHits()[sliceTr->FirstHitID() + sliceTr->NHits() - 1]; @@ -473,19 +547,18 @@ GPUd() void GPUTPCGMMerger::UnpackSaveNumber(int id) GPUd() void GPUTPCGMMerger::UnpackSliceGlobal(int nBlocks, int nThreads, int iBlock, int iThread, int iSlice) { - int* TrackIds = (int*)mTmpMem; const GPUTPCTracker& trk = GetConstantMem()->tpcTrackers[iSlice]; float alpha = Param().Alpha(iSlice); const GPUTPCTrack* sliceTr = mMemory->firstGlobalTracks[iSlice]; - unsigned int nLocalTracks = Param().rec.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); - unsigned int nTracks = Param().rec.mergerReadFromTrackerDirectly ? *trk.NTracks() : mkSlices[iSlice]->NTracks(); + unsigned int nLocalTracks = Param().rec.tpc.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); + unsigned int nTracks = Param().rec.tpc.mergerReadFromTrackerDirectly ? *trk.NTracks() : mkSlices[iSlice]->NTracks(); for (unsigned int itr = nLocalTracks + iBlock * nThreads + iThread; itr < nTracks; itr += nBlocks * nThreads) { - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { sliceTr = &trk.Tracks()[itr]; } else if (itr > nLocalTracks) { sliceTr = sliceTr->GetNextTrack(); } - int localId = TrackIds[(sliceTr->LocalTrackId() >> 24) * mNMaxSingleSliceTracks + (sliceTr->LocalTrackId() & 0xFFFFFF)]; + int localId = mTrackIDs[(sliceTr->LocalTrackId() >> 24) * mNMaxSingleSliceTracks + (sliceTr->LocalTrackId() & 0xFFFFFF)]; if (localId == -1) { continue; } @@ -504,40 +577,38 @@ GPUd() void GPUTPCGMMerger::UnpackSliceGlobal(int nBlocks, int nThreads, int iBl GPUd() void GPUTPCGMMerger::UnpackResetIds(int nBlocks, int nThreads, int iBlock, int iThread, int iSlice) { - int* TrackIds = (int*)mTmpMem; const GPUTPCTracker& trk = GetConstantMem()->tpcTrackers[iSlice]; - unsigned int nLocalTracks = Param().rec.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); + unsigned int nLocalTracks = Param().rec.tpc.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); for (unsigned int i = iBlock * nThreads + iThread; i < nLocalTracks; i += nBlocks * nThreads) { - TrackIds[iSlice * mNMaxSingleSliceTracks + i] = -1; + mTrackIDs[iSlice * mNMaxSingleSliceTracks + i] = -1; } } GPUd() void GPUTPCGMMerger::RefitSliceTracks(int nBlocks, int nThreads, int iBlock, int iThread, int iSlice) { - int* TrackIds = (int*)mTmpMem; const GPUTPCTracker& trk = GetConstantMem()->tpcTrackers[iSlice]; - unsigned int nLocalTracks = Param().rec.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); + unsigned int nLocalTracks = Param().rec.tpc.mergerReadFromTrackerDirectly ? trk.CommonMemory()->nLocalTracks : mkSlices[iSlice]->NLocalTracks(); float alpha = Param().Alpha(iSlice); - const GPUTPCTrack* sliceTr = Param().rec.mergerReadFromTrackerDirectly ? nullptr : mkSlices[iSlice]->GetFirstTrack(); + const GPUTPCTrack* sliceTr = Param().rec.tpc.mergerReadFromTrackerDirectly ? nullptr : mkSlices[iSlice]->GetFirstTrack(); for (unsigned int itr = iBlock * nThreads + iThread; itr < nLocalTracks; itr += nBlocks * nThreads) { - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { sliceTr = &trk.Tracks()[itr]; } else if (itr) { sliceTr = sliceTr->GetNextTrack(); } GPUTPCGMSliceTrack track; SetTrackClusterZT(track, iSlice, sliceTr); - if (Param().rec.mergerCovSource == 0) { + if (Param().rec.tpc.mergerCovSource == 0) { track.Set(this, sliceTr, alpha, iSlice); if (!track.FilterErrors(this, iSlice, GPUCA_MAX_SIN_PHI, 0.1f)) { continue; } - } else if (Param().rec.mergerCovSource == 1) { + } else if (Param().rec.tpc.mergerCovSource == 1) { track.Set(this, sliceTr, alpha, iSlice); track.CopyBaseTrackCov(); - } else if (Param().rec.mergerCovSource == 2) { + } else if (Param().rec.tpc.mergerCovSource == 2) { if (RefitSliceTrack(track, sliceTr, alpha, iSlice)) { track.Set(this, sliceTr, alpha, iSlice); // TODO: Why does the refit fail, it shouldn't, this workaround should be removed if (!track.FilterErrors(this, iSlice, GPUCA_MAX_SIN_PHI, 0.1f)) { @@ -554,10 +625,10 @@ GPUd() void GPUTPCGMMerger::RefitSliceTracks(int nBlocks, int nThreads, int iBlo track.SetGlobalTrackId(0, -1); track.SetGlobalTrackId(1, -1); unsigned int myTrack = CAMath::AtomicAdd(&mMemory->nUnpackedTracks, 1u); - TrackIds[iSlice * mNMaxSingleSliceTracks + sliceTr->LocalTrackId()] = myTrack; + mTrackIDs[iSlice * mNMaxSingleSliceTracks + sliceTr->LocalTrackId()] = myTrack; mSliceTrackInfos[myTrack] = track; } - if (!Param().rec.mergerReadFromTrackerDirectly) { + if (!Param().rec.tpc.mergerReadFromTrackerDirectly) { mMemory->firstGlobalTracks[iSlice] = nLocalTracks ? sliceTr->GetNextTrack() : mkSlices[iSlice]->GetFirstTrack(); } } @@ -576,9 +647,9 @@ GPUd() void GPUTPCGMMerger::MakeBorderTracks(int nBlocks, int nThreads, int iBlo //* prepare slice tracks for merging with next/previous/same sector //* each track transported to the border line - float fieldBz = Param().par.ConstBz; + float fieldBz = Param().par.constBz; - float dAlpha = Param().par.DAlpha / 2; + float dAlpha = Param().par.dAlpha / 2; float x0 = 0; if (iBorder == 0) { // transport to the left edge of the sector and rotate horizontally @@ -620,7 +691,7 @@ GPUd() void GPUTPCGMMerger::MakeBorderTracks(int nBlocks, int nThreads, int iBlo } trackTmp = *trackMin; track = &trackTmp; - if (Param().rec.mergerCovSource == 2 && trackTmp.X2() != 0.f) { + if (Param().rec.tpc.mergerCovSource == 2 && trackTmp.X2() != 0.f) { trackTmp.UseParam2(); } else { trackTmp.Set(this, trackMin->OrigTrack(), trackMin->Alpha(), trackMin->Slice()); @@ -659,7 +730,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int nBlocks, int nThreads, int { CADEBUG(GPUInfo("\nMERGING Slices %d %d NTracks %d %d CROSS %d", iSlice1, iSlice2, N1, N2, mergeMode)); GPUTPCGMBorderRange* range1 = mBorderRange[iSlice1]; - GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); + GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.tpc.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); bool sameSlice = (iSlice1 == iSlice2); for (int itr = iBlock * nThreads + iThread; itr < N1; itr += nThreads * nBlocks) { GPUTPCGMBorderTrack& b = B1[itr]; @@ -703,8 +774,9 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int nBlocks, int nThreads, int template <> GPUd() void GPUTPCGMMerger::MergeBorderTracks<1>(int nBlocks, int nThreads, int iBlock, int iThread, int iSlice1, GPUTPCGMBorderTrack* B1, int N1, int iSlice2, GPUTPCGMBorderTrack* B2, int N2, int mergeMode) { +#if !defined(GPUCA_GPUCODE_GENRTC) GPUTPCGMBorderRange* range1 = mBorderRange[iSlice1]; - GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); + GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.tpc.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); if (iThread == 0) { if (iBlock == 0) { @@ -713,9 +785,12 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<1>(int nBlocks, int nThreads, int GPUCommonAlgorithm::sortDeviceDynamic(range2, range2 + N2, [](const GPUTPCGMBorderRange& a, const GPUTPCGMBorderRange& b) { return a.fMax < b.fMax; }); } } +#else + printf("This sorting variant is disabled for RTC"); +#endif } -#if (defined(__CUDACC__) || defined(__HIPCC__)) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize MergeBorderTracks<3> +#if defined(GPUCA_SPECIALIZE_THRUST_SORTS) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize MergeBorderTracks<3> struct MergeBorderTracks_compMax { GPUd() bool operator()(const GPUTPCGMBorderRange& a, const GPUTPCGMBorderRange& b) { @@ -741,11 +816,12 @@ void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal<GPUTPCGMMergerMergeBorde thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), p, p + N, MergeBorderTracks_compMin()); } } -#endif // __CUDACC__ || __HIPCC__ - MergeBorderTracks<3> +#endif // GPUCA_SPECIALIZE_THRUST_SORTS - Specialize MergeBorderTracks<3> template <> GPUd() void GPUTPCGMMerger::MergeBorderTracks<3>(int nBlocks, int nThreads, int iBlock, int iThread, GPUTPCGMBorderRange* range, int N, int cmpMax) { +#ifndef GPUCA_SPECIALIZE_THRUST_SORTS if (iThread == 0) { if (cmpMax) { GPUCommonAlgorithm::sortDeviceDynamic(range, range + N, [](const GPUTPCGMBorderRange& a, const GPUTPCGMBorderRange& b) { return a.fMax < b.fMax; }); @@ -753,6 +829,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<3>(int nBlocks, int nThreads, int GPUCommonAlgorithm::sortDeviceDynamic(range, range + N, [](const GPUTPCGMBorderRange& a, const GPUTPCGMBorderRange& b) { return a.fMin < b.fMin; }); } } +#endif } template <> @@ -773,7 +850,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int bool sameSlice = (iSlice1 == iSlice2); GPUTPCGMBorderRange* range1 = mBorderRange[iSlice1]; - GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); + GPUTPCGMBorderRange* range2 = mBorderRange[iSlice2] + (Param().rec.tpc.mergerReadFromTrackerDirectly ? *GetConstantMem()->tpcTrackers[iSlice2].NTracks() : mkSlices[iSlice2]->NTracks()); int i2 = 0; for (int i1 = iBlock * nThreads + iThread; i1 < N1; i1 += nThreads * nBlocks) { @@ -913,7 +990,7 @@ GPUd() void GPUTPCGMMerger::MergeWithinSlicesPrepare(int nBlocks, int nThreads, int iSlice = track.Slice(); GPUTPCGMBorderTrack b; ; - if (track.TransportToX(this, x0, Param().par.ConstBz, b, maxSin)) { + if (track.TransportToX(this, x0, Param().par.constBz, b, maxSin)) { b.SetTrackID(itr); CADEBUG( printf("WITHIN SLICE %d Track %d - ", iSlice, itr); for (int i = 0; i < 5; i++) { printf("%8.3f ", b.Par()[i]); } printf(" - "); for (int i = 0; i < 5; i++) { printf("%8.3f ", b.Cov()[i]); } printf("\n")); @@ -1228,7 +1305,7 @@ GPUd() void GPUTPCGMMerger::ResolveMergeSlices(GPUResolveSharedMemory& smem, int GPUd() void GPUTPCGMMerger::MergeCEFill(const GPUTPCGMSliceTrack* track, const GPUTPCGMMergedTrackHit& cls, const GPUTPCGMMergedTrackHitXYZ* clsXYZ, int itr) { - if (Param().rec.NonConsecutiveIDs) { + if (Param().rec.nonConsecutiveIDs) { return; } @@ -1247,14 +1324,14 @@ GPUd() void GPUTPCGMMerger::MergeCEFill(const GPUTPCGMSliceTrack* track, const G GPUTPCConvertImpl::convert(*mConstantMem, cls.slice, cls.row, cln.getPad(), cln.getTime(), x, y, z); } - if (!Param().par.ContinuousTracking && CAMath::Abs(z) > 10) { + if (!Param().par.continuousTracking && CAMath::Abs(z) > 10) { return; } int slice = track->Slice(); for (int attempt = 0; attempt < 2; attempt++) { GPUTPCGMBorderTrack b; const float x0 = Param().tpcGeometry.Row2X(attempt == 0 ? 63 : cls.row); - if (track->TransportToX(this, x0, Param().par.ConstBz, b, GPUCA_MAX_SIN_PHI_LOW)) { + if (track->TransportToX(this, x0, Param().par.constBz, b, GPUCA_MAX_SIN_PHI_LOW)) { b.SetTrackID(itr); b.SetNClusters(mOutputTracks[itr].NClusters()); if (CAMath::Abs(b.Cov()[4]) >= 0.5) { @@ -1335,7 +1412,7 @@ GPUd() void GPUTPCGMMerger::MergeCE(int nBlocks, int nThreads, int iBlock, int i } } - if (Param().par.ContinuousTracking) { + if (Param().par.continuousTracking) { if (Param().par.earlyTpcTransform) { const float z0 = trk[0]->CSide() ? CAMath::Max(mClustersXYZ[trk[0]->FirstClusterRef()].z, mClustersXYZ[trk[0]->FirstClusterRef() + trk[0]->NClusters() - 1].z) : CAMath::Min(mClustersXYZ[trk[0]->FirstClusterRef()].z, mClustersXYZ[trk[0]->FirstClusterRef() + trk[0]->NClusters() - 1].z); const float z1 = trk[1]->CSide() ? CAMath::Max(mClustersXYZ[trk[1]->FirstClusterRef()].z, mClustersXYZ[trk[1]->FirstClusterRef() + trk[1]->NClusters() - 1].z) : CAMath::Min(mClustersXYZ[trk[1]->FirstClusterRef()].z, mClustersXYZ[trk[1]->FirstClusterRef() + trk[1]->NClusters() - 1].z); @@ -1500,7 +1577,7 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i GPUCommonAlgorithm::sort(trackParts, trackParts + nParts, [](const GPUTPCGMSliceTrack* a, const GPUTPCGMSliceTrack* b) { return (a->X() > b->X()); }); } - if (Param().rec.dropLoopers && leg > 0) { + if (Param().rec.tpc.dropLoopers && leg > 0) { nParts = 1; leg = 0; } @@ -1513,14 +1590,14 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i int nTrackHits = t->NClusters(); trackCluster* c2 = trackClusters + nHits + nTrackHits - 1; for (int i = 0; i < nTrackHits; i++, c2--) { - if (Param().rec.mergerReadFromTrackerDirectly) { + if (Param().rec.tpc.mergerReadFromTrackerDirectly) { const GPUTPCTracker& trk = GetConstantMem()->tpcTrackers[t->Slice()]; const GPUTPCHitId& ic = trk.TrackHits()[t->OrigTrack()->FirstHitID() + i]; unsigned int id = trk.Data().ClusterDataIndex(trk.Data().Row(ic.RowIndex()), ic.HitIndex()) + GetConstantMem()->ioPtrs.clustersNative->clusterOffset[t->Slice()][0]; *c2 = trackCluster{id, (unsigned char)ic.RowIndex(), t->Slice(), t->Leg()}; } else { const GPUTPCSliceOutCluster& c = t->OrigTrack()->OutTrackClusters()[i]; - unsigned int id = Param().rec.NonConsecutiveIDs ? ((unsigned int)((unsigned int*)&c - (unsigned int*)mkSlices[t->Slice()]->GetFirstTrack())) : c.GetId(); + unsigned int id = Param().rec.nonConsecutiveIDs ? ((unsigned int)((unsigned int*)&c - (unsigned int*)mkSlices[t->Slice()]->GetFirstTrack())) : c.GetId(); *c2 = trackCluster{id, c.GetRow(), t->Slice(), t->Leg()}; } } @@ -1626,14 +1703,19 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i nHits = nFilteredHits; } - int iOutTrackFirstCluster = CAMath::AtomicAdd(&mMemory->nOutputTrackClusters, (unsigned int)nHits); + unsigned int iOutTrackFirstCluster = CAMath::AtomicAdd(&mMemory->nOutputTrackClusters, (unsigned int)nHits); + if (iOutTrackFirstCluster >= mNMaxOutputTrackClusters) { + raiseError(GPUErrors::ERROR_MERGER_HIT_OVERFLOW, iOutTrackFirstCluster, mNMaxOutputTrackClusters); + CAMath::AtomicExch(&mMemory->nOutputTrackClusters, 0u); + continue; + } GPUTPCGMMergedTrackHit* cl = mClusters + iOutTrackFirstCluster; GPUTPCGMMergedTrackHitXYZ* clXYZ = mClustersXYZ + iOutTrackFirstCluster; for (int i = 0; i < nHits; i++) { unsigned char state; - if (Param().rec.NonConsecutiveIDs) { + if (Param().rec.nonConsecutiveIDs) { const GPUTPCSliceOutCluster* c = (const GPUTPCSliceOutCluster*)((const int*)mkSlices[trackClusters[i].slice]->GetFirstTrack() + trackClusters[i].id); clXYZ[i].x = c->GetX(); clXYZ[i].y = c->GetY(); @@ -1668,7 +1750,7 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i #endif cl[i].state = state & GPUTPCGMMergedTrackHit::clustererAndSharedFlags; // Only allow edge, deconvoluted, and shared flags cl[i].row = trackClusters[i].row; - if (!Param().rec.NonConsecutiveIDs) // We already have global consecutive numbers from the slice tracker, and we need to keep them for late cluster attachment + if (!Param().rec.nonConsecutiveIDs) // We already have global consecutive numbers from the slice tracker, and we need to keep them for late cluster attachment { cl[i].num = trackClusters[i].id; } else { // Produce consecutive numbers for shared cluster flagging @@ -1679,7 +1761,12 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i cl[i].leg = trackClusters[i].leg; } // nHits - int iOutputTrack = CAMath::AtomicAdd(&mMemory->nOutputTracks, 1u); + unsigned int iOutputTrack = CAMath::AtomicAdd(&mMemory->nOutputTracks, 1u); + if (iOutputTrack >= mNMaxTracks) { + raiseError(GPUErrors::ERROR_MERGER_TRACK_OVERFLOW, iOutputTrack, mNMaxTracks); + CAMath::AtomicExch(&mMemory->nOutputTracks, 0u); + continue; + } GPUTPCGMMergedTrack& mergedTrack = mOutputTracks[iOutputTrack]; @@ -1695,7 +1782,7 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i GPUTPCGMBorderTrack b; const float toX = Param().par.earlyTpcTransform ? clXYZ[0].x : Param().tpcGeometry.Row2X(cl[0].row); - if (p2.TransportToX(this, toX, Param().par.ConstBz, b, GPUCA_MAX_SIN_PHI, false)) { + if (p2.TransportToX(this, toX, Param().par.constBz, b, GPUCA_MAX_SIN_PHI, false)) { p1.X() = toX; p1.Y() = b.Par()[0]; p1.Z() = b.Par()[1]; @@ -1745,13 +1832,12 @@ GPUd() void GPUTPCGMMerger::SortTracksPrepare(int nBlocks, int nThreads, int iBl GPUd() void GPUTPCGMMerger::PrepareClustersForFit0(int nBlocks, int nThreads, int iBlock, int iThread) { - unsigned int* trackSort = (unsigned int*)mTmpMem; for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTracks; i += nBlocks * nThreads) { - trackSort[i] = i; + mTrackSort[i] = i; } } -#if (defined(__CUDACC__) || defined(__HIPCC__)) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt +#if defined(GPUCA_SPECIALIZE_THRUST_SORTS) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt struct GPUTPCGMMergerSortTracks_comp { const GPUTPCGMMergedTrack* const mCmp; GPUhd() GPUTPCGMMergerSortTracks_comp(GPUTPCGMMergedTrack* cmp) : mCmp(cmp) {} @@ -1793,14 +1879,18 @@ template <> void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal<GPUTPCGMMergerSortTracksQPt, 0>(krnlSetup& _xyz) { GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); - thrust::device_ptr<unsigned int> trackSort((unsigned int*)mProcessorsShadow->tpcMerger.TmpMem()); + thrust::device_ptr<unsigned int> trackSort((unsigned int*)mProcessorsShadow->tpcMerger.TrackSort()); ThrustVolatileAsyncAllocator alloc(this); thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), trackSort, trackSort + processors()->tpcMerger.NOutputTracks(), GPUTPCGMMergerSortTracksQPt_comp(mProcessorsShadow->tpcMerger.OutputTracks())); } -#endif // __CUDACC__ || __HIPCC__ - Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt +#endif // GPUCA_SPECIALIZE_THRUST_SORTS - Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt GPUd() void GPUTPCGMMerger::SortTracks(int nBlocks, int nThreads, int iBlock, int iThread) { +#ifndef GPUCA_SPECIALIZE_THRUST_SORTS + if (iThread || iBlock) { + return; + } // Have to duplicate sort comparison: Thrust cannot use the Lambda but OpenCL cannot use the object auto comp = [cmp = mOutputTracks](const int aa, const int bb) { const GPUTPCGMMergedTrack& GPUrestrict() a = cmp[aa]; @@ -1815,11 +1905,15 @@ GPUd() void GPUTPCGMMerger::SortTracks(int nBlocks, int nThreads, int iBlock, in }; GPUCommonAlgorithm::sortDeviceDynamic(mTrackOrderProcess, mTrackOrderProcess + mMemory->nOutputTracks, comp); +#endif } GPUd() void GPUTPCGMMerger::SortTracksQPt(int nBlocks, int nThreads, int iBlock, int iThread) { - unsigned int* trackSort = (unsigned int*)mTmpMem; +#ifndef GPUCA_SPECIALIZE_THRUST_SORTS + if (iThread || iBlock) { + return; + } // Have to duplicate sort comparison: Thrust cannot use the Lambda but OpenCL cannot use the object auto comp = [cmp = mOutputTracks](const int aa, const int bb) { const GPUTPCGMMergedTrack& GPUrestrict() a = cmp[aa]; @@ -1827,20 +1921,19 @@ GPUd() void GPUTPCGMMerger::SortTracksQPt(int nBlocks, int nThreads, int iBlock, return (CAMath::Abs(a.GetParam().GetQPt()) > CAMath::Abs(b.GetParam().GetQPt())); }; - GPUCommonAlgorithm::sortDeviceDynamic(trackSort, trackSort + mMemory->nOutputTracks, comp); + GPUCommonAlgorithm::sortDeviceDynamic(mTrackSort, mTrackSort + mMemory->nOutputTracks, comp); +#endif } GPUd() void GPUTPCGMMerger::PrepareClustersForFit1(int nBlocks, int nThreads, int iBlock, int iThread) { - unsigned int* trackSort = (unsigned int*)mTmpMem; - GPUAtomic(unsigned int)* sharedCount = (GPUAtomic(unsigned int)*)(trackSort + CAMath::nextMultipleOf<4>(mMemory->nOutputTracks)); for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTracks; i += nBlocks * nThreads) { - mTrackOrderAttach[trackSort[i]] = i; + mTrackOrderAttach[mTrackSort[i]] = i; const GPUTPCGMMergedTrack& trk = mOutputTracks[i]; if (trk.OK()) { for (unsigned int j = 0; j < trk.NClusters(); j++) { mClusterAttachment[mClusters[trk.FirstClusterRef() + j].num] = attachAttached | attachGood; - CAMath::AtomicAdd(&sharedCount[mClusters[trk.FirstClusterRef() + j].num], 1u); + CAMath::AtomicAdd(&mSharedCount[mClusters[trk.FirstClusterRef() + j].num], 1u); } } } @@ -1848,16 +1941,15 @@ GPUd() void GPUTPCGMMerger::PrepareClustersForFit1(int nBlocks, int nThreads, in GPUd() void GPUTPCGMMerger::PrepareClustersForFit2(int nBlocks, int nThreads, int iBlock, int iThread) { - unsigned int* sharedCount = (unsigned int*)mTmpMem + CAMath::nextMultipleOf<4>(mMemory->nOutputTracks); for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTrackClusters; i += nBlocks * nThreads) { - if (sharedCount[mClusters[i].num] > 1) { + if (mSharedCount[mClusters[i].num] > 1) { mClusters[i].state |= GPUTPCGMMergedTrackHit::flagShared; } } if (mClusterStateExt) { for (unsigned int i = iBlock * nThreads + iThread; i < mNMaxClusters; i += nBlocks * nThreads) { unsigned char state = GetConstantMem()->ioPtrs.clustersNative->clustersLinear[i].getFlags(); - if (sharedCount[i] > 1) { + if (mSharedCount[i] > 1) { state |= GPUTPCGMMergedTrackHit::flagShared; } mClusterStateExt[i] = state; @@ -1867,14 +1959,13 @@ GPUd() void GPUTPCGMMerger::PrepareClustersForFit2(int nBlocks, int nThreads, in GPUd() void GPUTPCGMMerger::Finalize0(int nBlocks, int nThreads, int iBlock, int iThread) { - if (Param().rec.NonConsecutiveIDs) { + if (Param().rec.nonConsecutiveIDs) { for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTrackClusters; i += nThreads * nBlocks) { mClusters[i].num = mGlobalClusterIDs[i]; } } else { - int* trkOrderReverse = (int*)mTmpMem; for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTracks; i += nThreads * nBlocks) { - trkOrderReverse[mTrackOrderAttach[i]] = i; + mTrackSort[mTrackOrderAttach[i]] = i; } for (unsigned int i = iBlock * nThreads + iThread; i < mMemory->nOutputTrackClusters; i += nThreads * nBlocks) { mClusterAttachment[mClusters[i].num] = 0; // Reset adjacent attachment for attached clusters, set correctly below @@ -1909,38 +2000,23 @@ GPUd() void GPUTPCGMMerger::Finalize1(int nBlocks, int nThreads, int iBlock, int GPUd() void GPUTPCGMMerger::Finalize2(int nBlocks, int nThreads, int iBlock, int iThread) { - int* trkOrderReverse = (int*)mTmpMem; for (unsigned int i = iBlock * nThreads + iThread; i < mNMaxClusters; i += nThreads * nBlocks) { if (mClusterAttachment[i] != 0) { - mClusterAttachment[i] = (mClusterAttachment[i] & attachFlagMask) | trkOrderReverse[mClusterAttachment[i] & attachTrackMask]; + mClusterAttachment[i] = (mClusterAttachment[i] & attachFlagMask) | mTrackSort[mClusterAttachment[i] & attachTrackMask]; } } } -struct MergeLooperParam { - float absz; - float tgl; - float qpt; - float x; - float y; - unsigned int id; -}; - -GPUd() void GPUTPCGMMerger::MergeLoopers(int nBlocks, int nThreads, int iBlock, int iThread) +GPUd() void GPUTPCGMMerger::MergeLoopersInit(int nBlocks, int nThreads, int iBlock, int iThread) { - if (iThread || iBlock) { - return; - } -#ifndef GPUCA_GPUCODE - std::vector<MergeLooperParam> params; - const float lowPtThresh = Param().rec.tpcRejectQPt * 1.1f; // Might need to merge tracks above the threshold with parts below the threshold - for (unsigned int i = 0; i < mMemory->nOutputTracks; i++) { + const float lowPtThresh = Param().rec.tpc.rejectQPt * 1.1f; // Might need to merge tracks above the threshold with parts below the threshold + for (unsigned int i = get_global_id(0); i < mMemory->nOutputTracks; i += get_global_size(0)) { const auto& trk = mOutputTracks[i]; const auto& p = trk.GetParam(); const float qptabs = CAMath::Abs(p.GetQPt()); if (trk.NClusters() && qptabs > 5.f && qptabs <= lowPtThresh) { const int slice = mClusters[trk.FirstClusterRef() + trk.NClusters() - 1].slice; - const float z = p.GetZ() + (Param().par.earlyTpcTransform ? p.GetTZOffset() : GetConstantMem()->calibObjects.fastTransform->convVertexTimeToZOffset(slice, p.GetTZOffset(), Param().par.continuousMaxTimeBin)); + const float refz = p.GetZ() + (Param().par.earlyTpcTransform ? p.GetTZOffset() : GetConstantMem()->calibObjects.fastTransform->convVertexTimeToZOffset(slice, p.GetTZOffset(), Param().par.continuousMaxTimeBin)) + (trk.CSide() ? -100 : 100); float sinA, cosA; CAMath::SinCos(trk.GetAlpha(), sinA, cosA); float gx = cosA * p.GetX() - sinA * p.GetY(); @@ -1952,9 +2028,15 @@ GPUd() void GPUTPCGMMerger::MergeLoopers(int nBlocks, int nThreads, int iBlock, const float my = p.GetY() - r * CAMath::Sqrt(1 - p.GetSinPhi() * p.GetSinPhi()); const float gmx = cosA * mx - sinA * my; const float gmy = cosA * my + sinA * mx; - params.emplace_back(MergeLooperParam{CAMath::Abs(z), CAMath::Abs(p.GetDzDs()), p.GetDzDs() > 0 ? p.GetQPt() : -p.GetQPt(), gmx, gmy, i}); + unsigned int myId = CAMath::AtomicAdd(&mMemory->nLooperMatchCandidates, 1u); + if (myId >= mNMaxLooperMatches) { + raiseError(GPUErrors::ERROR_LOOPER_MATCH_OVERFLOW, myId, mNMaxLooperMatches); + CAMath::AtomicExch(&mMemory->nLooperMatchCandidates, 0u); + return; + } + mLooperCandidates[myId] = MergeLooperParam{refz, gmx, gmy, i}; - /*printf("Track %d Sanity qpt %f snp %f bz %f\n", (int)params.size(), p.GetQPt(), p.GetSinPhi(), bz); + /*printf("Track %u Sanity qpt %f snp %f bz %f\n", mMemory->nLooperMatchCandidates, p.GetQPt(), p.GetSinPhi(), bz); for (unsigned int k = 0;k < trk.NClusters();k++) { float xx, yy, zz; if (Param().par.earlyTpcTransform) { @@ -1975,35 +2057,113 @@ GPUd() void GPUTPCGMMerger::MergeLoopers(int nBlocks, int nThreads, int iBlock, }*/ } } - std::sort(params.begin(), params.end(), [](const MergeLooperParam& a, const MergeLooperParam& b) { return a.absz < b.absz; }); -#if GPUCA_MERGE_LOOPER_MC - std::vector<long int> paramLabels(params.size()); - for (unsigned int i = 0; i < params.size(); i++) { +} + +GPUd() void GPUTPCGMMerger::MergeLoopersSort(int nBlocks, int nThreads, int iBlock, int iThread) +{ +#ifndef GPUCA_SPECIALIZE_THRUST_SORTS + if (iThread || iBlock) { + return; + } + auto comp = [](const MergeLooperParam& a, const MergeLooperParam& b) { return CAMath::Abs(a.refz) < CAMath::Abs(b.refz); }; + GPUCommonAlgorithm::sortDeviceDynamic(mLooperCandidates, mLooperCandidates + mMemory->nLooperMatchCandidates, comp); +#endif +} + +#if defined(GPUCA_SPECIALIZE_THRUST_SORTS) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt +struct GPUTPCGMMergerMergeLoopers_comp { + GPUd() bool operator()(const MergeLooperParam& a, const MergeLooperParam& b) + { + return CAMath::Abs(a.refz) < CAMath::Abs(b.refz); + } +}; + +template <> +void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal<GPUTPCGMMergerMergeLoopers, 1>(krnlSetup& _xyz) +{ + GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); + thrust::device_ptr<MergeLooperParam> params(mProcessorsShadow->tpcMerger.LooperCandidates()); + ThrustVolatileAsyncAllocator alloc(this); + thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), params, params + processors()->tpcMerger.Memory()->nLooperMatchCandidates, GPUTPCGMMergerMergeLoopers_comp()); +} +#endif // GPUCA_SPECIALIZE_THRUST_SORTS - Specialize GPUTPCGMMergerSortTracks and GPUTPCGMMergerSortTracksQPt + +GPUd() void GPUTPCGMMerger::MergeLoopersMain(int nBlocks, int nThreads, int iBlock, int iThread) +{ + const MergeLooperParam* params = mLooperCandidates; + +#if GPUCA_MERGE_LOOPER_MC && !defined(GPUCA_GPUCODE) + std::vector<long int> paramLabels(mMemory->nLooperMatchCandidates); + for (unsigned int i = 0; i < mMemory->nLooperMatchCandidates; i++) { paramLabels[i] = GetTrackLabel(mOutputTracks[params[i].id]); } - std::vector<bool> dropped(params.size()); - std::vector<bool> droppedMC(params.size()); + /*std::vector<bool> dropped(mMemory->nLooperMatchCandidates); + std::vector<bool> droppedMC(mMemory->nLooperMatchCandidates); std::vector<int> histMatch(101); - std::vector<int> histFail(101); + std::vector<int> histFail(101);*/ + if (!mRec->GetProcessingSettings().runQA) { + throw std::runtime_error("Need QA enabled for the Merge Loopers MC QA"); + } #endif - for (unsigned int i = 0; i < params.size(); i++) { - for (unsigned int j = i + 1; j < params.size(); j++) { - if (params[j].absz > params[i].absz + 100.f) { + for (unsigned int i = get_global_id(0); i < mMemory->nLooperMatchCandidates; i += get_global_size(0)) { + for (unsigned int j = i + 1; j < mMemory->nLooperMatchCandidates; j++) { + //int bs = 0; + if (CAMath::Abs(params[j].refz) > CAMath::Abs(params[i].refz) + 100.f) { break; } - float dqpt = CAMath::Min(CAMath::Abs(params[i].tgl), CAMath::Abs(params[j].tgl)) < 0.05f ? (CAMath::Abs(params[i].qpt) - CAMath::Abs(params[i].qpt)) : (params[i].qpt - params[j].qpt); - float d = CAMath::Sum2((params[i].x - params[j].x) * (1.f / 5.f), (params[i].y - params[j].y) * (1.f / 5.f), (params[i].tgl - params[j].tgl) * (1.f / 0.15f), dqpt / CAMath::Min(params[i].qpt, params[j].qpt) * (1.f / 0.15f)); - //bool EQ = CAMath::Abs(params[i].x - params[j].x) < 10.f && CAMath::Abs(params[i].y - params[j].y) < 10.f && CAMath::Abs(params[i].tgl - params[j].tgl) < 0.15f && CAMath::Abs((params[i].qpt - params[j].qpt) / CAMath::Min(params[i].qpt, params[j].qpt)) < 0.15f; - bool EQ = d < 1.5f; -#if GPUCA_MERGE_LOOPER_MC + const float d2xy = CAMath::Sum2(params[i].x - params[j].x, params[i].y - params[j].y); + if (d2xy > 15.f) { + //bs |= 1; + continue; + } + const auto& trk1 = mOutputTracks[params[i].id]; + const auto& trk2 = mOutputTracks[params[j].id]; + const auto& param1 = trk1.GetParam(); + const auto& param2 = trk2.GetParam(); + if (CAMath::Abs(param1.GetDzDs()) > 0.03f && CAMath::Abs(param2.GetDzDs()) > 0.03f && param1.GetDzDs() * param2.GetDzDs() * param1.GetQPt() * param2.GetQPt() < 0) { + //bs |= 2; + continue; + } + + const float dznormalized = (CAMath::Abs(params[j].refz) - CAMath::Abs(params[i].refz)) / (CAMath::TwoPi() * 0.5f * (CAMath::Abs(param1.GetDzDs()) + CAMath::Abs(param2.GetDzDs())) * 1.f / (0.5f * (CAMath::Abs(param1.GetQPt()) + CAMath::Abs(param2.GetQPt())) * CAMath::Abs(Param().polynomialField.GetNominalBz()))); + const float phasecorr = CAMath::Modf((CAMath::ASin(param1.GetSinPhi()) + trk1.GetAlpha() - CAMath::ASin(param2.GetSinPhi()) - trk2.GetAlpha()) / CAMath::TwoPi() + 5.5f, 1.f) - 0.5f; + const float phasecorrdirection = (params[j].refz * param1.GetQPt() * param1.GetDzDs()) > 0 ? 1 : -1; + const float dzcorr = dznormalized + phasecorr * phasecorrdirection; + const bool sameside = !(trk1.CSide() ^ trk2.CSide()); + const float dzcorrlimit[4] = {sameside ? 0.018f : 0.012f, sameside ? 0.12f : 0.025f, 0.14f, 0.15f}; + const int dzcorrcount = sameside ? 4 : 2; + bool dzcorrok = false; + float dznorm = 0.f; + for (int k = 0; k < dzcorrcount; k++) { + const float d = CAMath::Abs(dzcorr - 0.5f * k); + if (d <= dzcorrlimit[k]) { + dzcorrok = true; + dznorm = d / dzcorrlimit[k]; + break; + } + } + if (!dzcorrok) { + //bs |= 4; + continue; + } + + const float dtgl = param1.GetDzDs() - (param1.GetQPt() * param2.GetQPt() > 0 ? param2.GetDzDs() : -param2.GetDzDs()); + const float dqpt = (CAMath::Abs(param1.GetQPt()) - CAMath::Abs(param2.GetQPt())) / CAMath::Min(param1.GetQPt(), param2.GetQPt()); + float d = CAMath::Sum2(dtgl * (1.f / 0.03f), dqpt * (1.f / 0.04f)) + d2xy * (1.f / 4.f) + dznorm * (1.f / 0.3f); + bool EQ = d < 6.f; +#if GPUCA_MERGE_LOOPER_MC && !defined(GPUCA_GPUCODE) const long int label1 = paramLabels[i]; const long int label2 = paramLabels[j]; bool labelEQ = label1 != -1 && label1 == label2; - if (EQ || labelEQ) { - printf("Matching track %d/%d %u-%u (%ld/%ld): dist %f side %d %d, tgl %f %f, qpt %f %f, x %f %f, y %f %f\n", (int)EQ, (int)labelEQ, i, j, label1, label2, d, (int)mOutputTracks[params[i].id].CSide(), (int)mOutputTracks[params[j].id].CSide(), params[i].tgl, params[j].tgl, params[i].qpt, params[j].qpt, params[i].x, params[j].x, params[i].y, params[j].y); + if (1 || EQ || labelEQ) { + //printf("Matching track %d/%d %u-%u (%ld/%ld): dist %f side %d %d, tgl %f %f, qpt %f %f, x %f %f, y %f %f\n", (int)EQ, (int)labelEQ, i, j, label1, label2, d, (int)mOutputTracks[params[i].id].CSide(), (int)mOutputTracks[params[j].id].CSide(), params[i].tgl, params[j].tgl, params[i].qpt, params[j].qpt, params[i].x, params[j].x, params[i].y, params[j].y); + static auto& tup = GPUROOTDump<TNtuple>::get("mergeloopers", "labeleq:sides:d2xy:tgl1:tgl2:qpt1:qpt2:dz:dzcorr:dtgl:dqpt:dznorm:bs"); + tup.Fill((float)labelEQ, (trk1.CSide() ? 1 : 0) | (trk2.CSide() ? 2 : 0), d2xy, param1.GetDzDs(), param2.GetDzDs(), param1.GetQPt(), param2.GetQPt(), CAMath::Abs(params[j].refz) - CAMath::Abs(params[i].refz), dzcorr, dtgl, dqpt, dznorm, bs); + static auto tup2 = GPUROOTDump<TNtuple>::getNew("mergeloopers2", "labeleq:refz1:refz2:tgl1:tgl2:qpt1:qpt2:snp1:snp2:a1:a2:dzn:phasecor:phasedir:dzcorr"); + tup2.Fill((float)labelEQ, params[i].refz, params[j].refz, param1.GetDzDs(), param2.GetDzDs(), param1.GetQPt(), param2.GetQPt(), param1.GetSinPhi(), param2.GetSinPhi(), trk1.GetAlpha(), trk2.GetAlpha(), dznormalized, phasecorr, phasecorrdirection, dzcorr); } - if (EQ) { + /*if (EQ) { dropped[j] = true; } if (labelEQ) { @@ -2012,19 +2172,19 @@ GPUd() void GPUTPCGMMerger::MergeLoopers(int nBlocks, int nThreads, int iBlock, } if (d < 10.f && !labelEQ) { histFail[CAMath::Min<int>(100, d * 10.f)]++; - } + }*/ #endif if (EQ) { mOutputTracks[params[j].id].SetMergedLooper(true); - if (CAMath::Abs(params[j].qpt) >= Param().rec.tpcRejectQPt) { + if (CAMath::Abs(param2.GetQPt()) >= Param().rec.tpc.rejectQPt) { mOutputTracks[params[i].id].SetMergedLooper(true); } } } } -#if GPUCA_MERGE_LOOPER_MC + /*#if GPUCA_MERGE_LOOPER_MC && !defined(GPUCA_GPUCODE) int total = 0, totalmc = 0, good = 0, missed = 0, fake = 0; - for (unsigned int i = 0; i < params.size(); i++) { + for (unsigned int i = 0; i < mMemory->nLooperMatchCandidates; i++) { total += dropped[i]; totalmc += droppedMC[i]; good += dropped[i] && droppedMC[i]; @@ -2046,6 +2206,5 @@ GPUd() void GPUTPCGMMerger::MergeLoopers(int nBlocks, int nThreads, int iBlock, for (unsigned int i = 0; i < histFail.size(); i++) { printf("%8.3f: %3d\n", i / 10.f + 0.05f, histFail[i]); } -#endif -#endif +#endif*/ } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h index c5e0da4c571d8..765e50a96220d 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,6 +49,7 @@ class GPUTPCTracker; class GPUChainTracking; class GPUTPCGMPolynomialField; struct GPUTPCGMLoopData; +struct MergeLooperParam; /** * @class GPUTPCGMMerger @@ -68,8 +70,11 @@ class GPUTPCGMMerger : public GPUProcessor GPUAtomic(unsigned int) nUnpackedTracks; GPUAtomic(unsigned int) nOutputTracks; GPUAtomic(unsigned int) nOutputTrackClusters; + GPUAtomic(unsigned int) nO2Tracks; + GPUAtomic(unsigned int) nO2ClusRefs; const GPUTPCTrack* firstGlobalTracks[NSLICES]; GPUAtomic(unsigned int) tmpCounter[2 * NSLICES]; + GPUAtomic(unsigned int) nLooperMatchCandidates; }; struct trackCluster { @@ -79,6 +84,11 @@ class GPUTPCGMMerger : public GPUProcessor unsigned char leg; }; + struct tmpSort { + unsigned int x; + float y; + }; + void InitializeProcessor(); void RegisterMemoryAllocation(); void SetMaxData(const GPUTrackingInOutPointers& io); @@ -86,26 +96,29 @@ class GPUTPCGMMerger : public GPUProcessor void* SetPointersRefitScratch(void* mem); void* SetPointersRefitScratch2(void* mem); void* SetPointersOutput(void* mem); + void* SetPointersOutputO2(void* mem); + void* SetPointersOutputO2Clus(void* mem); + void* SetPointersOutputO2MC(void* mem); + void* SetPointersOutputO2Scratch(void* mem); + void* SetPointersOutputState(void* mem); void* SetPointersMemory(void* mem); void SetSliceData(int index, const GPUTPCSliceOutput* sliceData) { mkSlices[index] = sliceData; } - GPUhd() int NOutputTracks() const { return mMemory->nOutputTracks; } - GPUhd() const GPUTPCGMMergedTrack* OutputTracks() const { return mOutputTracks; } - GPUhd() GPUTPCGMMergedTrack* OutputTracks() - { - return mOutputTracks; - } - - GPUhd() unsigned int NClusters() const { return mNClusters; } - GPUhd() unsigned int NMaxClusters() const { return mNMaxClusters; } - GPUhd() unsigned int NMaxTracks() const { return mNMaxTracks; } - GPUhd() unsigned int NMaxOutputTrackClusters() const { return mNMaxOutputTrackClusters; } - GPUhd() unsigned int NOutputTrackClusters() const { return mMemory->nOutputTrackClusters; } - GPUhd() const GPUTPCGMMergedTrackHit* Clusters() const { return mClusters; } - GPUhd() GPUTPCGMMergedTrackHit* Clusters() { return (mClusters); } - GPUhd() const GPUTPCGMMergedTrackHitXYZ* ClustersXYZ() const { return mClustersXYZ; } - GPUhd() GPUTPCGMMergedTrackHitXYZ* ClustersXYZ() { return (mClustersXYZ); } + GPUhdi() int NOutputTracks() const { return mMemory->nOutputTracks; } + GPUhdi() const GPUTPCGMMergedTrack* OutputTracks() const { return mOutputTracks; } + GPUhdi() GPUTPCGMMergedTrack* OutputTracks() { return mOutputTracks; } + GPUhdi() const GPUdEdxInfo* OutputTracksdEdx() const { return mOutputTracksdEdx; } + GPUhdi() GPUdEdxInfo* OutputTracksdEdx() { return mOutputTracksdEdx; } + GPUhdi() unsigned int NClusters() const { return mNClusters; } + GPUhdi() unsigned int NMaxClusters() const { return mNMaxClusters; } + GPUhdi() unsigned int NMaxTracks() const { return mNMaxTracks; } + GPUhdi() unsigned int NMaxOutputTrackClusters() const { return mNMaxOutputTrackClusters; } + GPUhdi() unsigned int NOutputTrackClusters() const { return mMemory->nOutputTrackClusters; } + GPUhdi() const GPUTPCGMMergedTrackHit* Clusters() const { return mClusters; } + GPUhdi() GPUTPCGMMergedTrackHit* Clusters() { return (mClusters); } + GPUhdi() const GPUTPCGMMergedTrackHitXYZ* ClustersXYZ() const { return mClustersXYZ; } + GPUhdi() GPUTPCGMMergedTrackHitXYZ* ClustersXYZ() { return (mClustersXYZ); } GPUhdi() GPUAtomic(unsigned int) * ClusterAttachment() const { return mClusterAttachment; } GPUhdi() unsigned int* TrackOrderAttach() const { return mTrackOrderAttach; } GPUhdi() unsigned int* TrackOrderProcess() const { return mTrackOrderProcess; } @@ -114,11 +127,25 @@ class GPUTPCGMMerger : public GPUProcessor GPUhdi() GPUTPCGMLoopData* LoopData() const { return mLoopData; } GPUhdi() memory* Memory() const { return mMemory; } GPUhdi() GPUAtomic(unsigned int) * TmpCounter() { return mMemory->tmpCounter; } - GPUhdi() uint4* TmpMem() { return mTmpMem; } + GPUhdi() uint2* ClusRefTmp() { return mClusRefTmp; } + GPUhdi() unsigned int* TrackSort() { return mTrackSort; } + GPUhdi() tmpSort* TrackSortO2() { return mTrackSortO2; } + GPUhdi() MergeLooperParam* LooperCandidates() { return mLooperCandidates; } + GPUhdi() GPUAtomic(unsigned int) * SharedCount() { return mSharedCount; } GPUhdi() gputpcgmmergertypes::GPUTPCGMBorderRange* BorderRange(int i) { return mBorderRange[i]; } + GPUhdi() o2::tpc::TrackTPC* OutputTracksTPCO2() { return mOutputTracksTPCO2; } + GPUhdi() unsigned int* OutputClusRefsTPCO2() { return mOutputClusRefsTPCO2; } + GPUhdi() o2::MCCompLabel* OutputTracksTPCO2MC() { return mOutputTracksTPCO2MC; } + GPUhdi() unsigned int NOutputTracksTPCO2() const { return mMemory->nO2Tracks; } + GPUhdi() unsigned int NOutputClusRefsTPCO2() const { return mMemory->nO2ClusRefs; } GPUd() unsigned short MemoryResMemory() { return mMemoryResMemory; } GPUd() unsigned short MemoryResOutput() const { return mMemoryResOutput; } + GPUd() unsigned short MemoryResOutputState() const { return mMemoryResOutputState; } + GPUd() unsigned short MemoryResOutputO2() const { return mMemoryResOutputO2; } + GPUd() unsigned short MemoryResOutputO2Clus() const { return mMemoryResOutputO2Clus; } + GPUd() unsigned short MemoryResOutputO2MC() const { return mMemoryResOutputO2MC; } + GPUd() unsigned short MemoryResOutputO2Scratch() const { return mMemoryResOutputO2Scratch; } GPUd() int RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const GPUTPCTrack* inTrack, float alpha, int slice); GPUd() void SetTrackClusterZT(GPUTPCGMSliceTrack& track, int iSlice, const GPUTPCTrack* sliceTr); @@ -153,7 +180,9 @@ class GPUTPCGMMerger : public GPUProcessor GPUd() void ResolveFindConnectedComponentsHookLinks(int nBlocks, int nThreads, int iBlock, int iThread); GPUd() void ResolveFindConnectedComponentsMultiJump(int nBlocks, int nThreads, int iBlock, int iThread); GPUd() void ResolveMergeSlices(gputpcgmmergertypes::GPUResolveSharedMemory& smem, int nBlocks, int nThreads, int iBlock, int iThread, char useOrigTrackParam, char mergeAll); - GPUd() void MergeLoopers(int nBlocks, int nThreads, int iBlock, int iThread); + GPUd() void MergeLoopersInit(int nBlocks, int nThreads, int iBlock, int iThread); + GPUd() void MergeLoopersSort(int nBlocks, int nThreads, int iBlock, int iThread); + GPUd() void MergeLoopersMain(int nBlocks, int nThreads, int iBlock, int iThread); #ifndef GPUCA_GPUCODE void DumpSliceTracks(std::ostream& out); @@ -208,23 +237,38 @@ class GPUTPCGMMerger : public GPUProcessor unsigned int mNMaxSingleSliceTracks; // max N tracks in one slice unsigned int mNMaxOutputTrackClusters; // max number of clusters in output tracks (double-counting shared clusters) unsigned int mNMaxClusters; // max total unique clusters (in event) + unsigned int mNMaxLooperMatches; // Maximum number of candidate pairs for looper matching unsigned short mMemoryResMemory; unsigned short mMemoryResOutput; + unsigned short mMemoryResOutputState; + unsigned short mMemoryResOutputO2; + unsigned short mMemoryResOutputO2Clus; + unsigned short mMemoryResOutputO2MC; + unsigned short mMemoryResOutputO2Scratch; - int mNClusters; // Total number of incoming clusters (from slice tracks) - GPUTPCGMMergedTrack* mOutputTracks; //* array of output merged tracks - + int mNClusters; // Total number of incoming clusters (from slice tracks) + GPUTPCGMMergedTrack* mOutputTracks; //* array of output merged tracks + GPUdEdxInfo* mOutputTracksdEdx; //* dEdx information GPUTPCGMSliceTrack* mSliceTrackInfos; //* additional information for slice tracks int* mSliceTrackInfoIndex; GPUTPCGMMergedTrackHit* mClusters; GPUTPCGMMergedTrackHitXYZ* mClustersXYZ; int* mGlobalClusterIDs; GPUAtomic(unsigned int) * mClusterAttachment; + o2::tpc::TrackTPC* mOutputTracksTPCO2; + unsigned int* mOutputClusRefsTPCO2; + o2::MCCompLabel* mOutputTracksTPCO2MC; + MergeLooperParam* mLooperCandidates; + unsigned int* mTrackOrderAttach; unsigned int* mTrackOrderProcess; unsigned char* mClusterStateExt; - uint4* mTmpMem; + uint2* mClusRefTmp; + int* mTrackIDs; + unsigned int* mTrackSort; + tmpSort* mTrackSortO2; + GPUAtomic(unsigned int) * mSharedCount; // Must be unsigned int unfortunately for atomic support GPUTPCGMBorderTrack* mBorderMemory; // memory for border tracks GPUTPCGMBorderTrack* mBorder[2 * NSLICES]; gputpcgmmergertypes::GPUTPCGMBorderRange* mBorderRangeMemory; // memory for border tracks diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx index d9c9e0c5cec23..74cb152ca680c 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -141,7 +142,7 @@ void GPUTPCGMMerger::DumpFitPrepare(std::ostream& out) out << " Cluster state " << j << "/" << (i - trk.FirstClusterRef()) << ": " << (int)mClusters[i].state << "\n"; } } - unsigned int maxId = mRec->GetParam().rec.NonConsecutiveIDs ? mMemory->nOutputTrackClusters : mNMaxClusters; + unsigned int maxId = mRec->GetParam().rec.nonConsecutiveIDs ? mMemory->nOutputTrackClusters : mNMaxClusters; for (unsigned int i = 0; i < maxId; i++) { out << " Cluster attachment " << i << ": " << getTrackOrderReverse(mClusterAttachment[i] & attachTrackMask) << " / " << (mClusterAttachment[i] & attachFlagMask) << "\n"; } @@ -154,11 +155,12 @@ void GPUTPCGMMerger::DumpRefit(std::ostream& out) out << "\nTPC Merger Refit\n"; for (unsigned int i = 0; i < mMemory->nOutputTracks; i++) { const auto& trk = mOutputTracks[trackOrder[i]]; + const auto& trkdEdx = mOutputTracksdEdx[trackOrder[i]]; const auto& p = trk.GetParam(); const auto& po = trk.OuterParam(); out << " Track " << i << ": OK " << trk.OK() << " Alpha " << trk.GetAlpha() << " X " << p.GetX() << " Y " << p.GetY() << " Z " << p.GetZ() << " SPhi " << p.GetSinPhi() << " Tgl " << p.GetDzDs() << " QPt " << p.GetQPt() << " NCl " << trk.NClusters() << " / " << trk.NClustersFitted() << " Cov " << p.GetErr2Y() << "/" << p.GetErr2Z() -#ifdef HAVE_O2HEADERS - << " dEdx " << trk.dEdxInfo().dEdxTotTPC << "/" << trk.dEdxInfo().dEdxMaxTPC +#ifdef GPUCA_HAVE_O2HEADERS + << " dEdx " << trkdEdx.dEdxTotTPC << "/" << trkdEdx.dEdxMaxTPC #endif << " Outer " << po.P[0] << "/" << po.P[1] << "/" << po.P[2] << "/" << po.P[3] << "/" << po.P[4] << "\n"; } @@ -174,7 +176,7 @@ void GPUTPCGMMerger::DumpFinal(std::ostream& out) out << " Cluster state " << j << "/" << (i - trk.FirstClusterRef()) << ": " << (int)mClusters[i].state << "\n"; } } - unsigned int maxId = mRec->GetParam().rec.NonConsecutiveIDs ? mMemory->nOutputTrackClusters : mNMaxClusters; + unsigned int maxId = mRec->GetParam().rec.nonConsecutiveIDs ? mMemory->nOutputTrackClusters : mNMaxClusters; for (unsigned int i = 0; i < maxId; i++) { out << " Cluster attachment " << i << ": " << getTrackOrderReverse(mClusterAttachment[i] & attachTrackMask) << " / " << (mClusterAttachment[i] & attachFlagMask) << "\n"; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx index 8068955daaac6..67875b4d20ef5 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCGMMergerTrackFit::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int mode) +GPUdii() void GPUTPCGMMergerTrackFit::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int mode) { const int iEnd = mode == -1 ? merger.Memory()->nRetryRefit : merger.NOutputTracks(); GPUCA_OPENMP(parallel for if(!merger.GetRec().GetProcessingSettings().ompKernels) num_threads(merger.GetRec().GetProcessingSettings().ompThreads)) @@ -31,7 +32,7 @@ GPUdii() void GPUTPCGMMergerTrackFit::Thread<0>(int nBlocks, int nThreads, int i } template <> -GPUdii() void GPUTPCGMMergerFollowLoopers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerFollowLoopers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { GPUCA_OPENMP(parallel for if(!merger.GetRec().GetProcessingSettings().ompKernels) num_threads(merger.GetRec().GetProcessingSettings().ompThreads)) for (unsigned int i = get_global_id(0); i < merger.Memory()->nLoopData; i += get_global_size(0)) { @@ -40,25 +41,25 @@ GPUdii() void GPUTPCGMMergerFollowLoopers::Thread<0>(int nBlocks, int nThreads, } template <> -GPUdii() void GPUTPCGMMergerUnpackResetIds::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice) +GPUdii() void GPUTPCGMMergerUnpackResetIds::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice) { merger.UnpackResetIds(nBlocks, nThreads, iBlock, iThread, iSlice); } template <> -GPUdii() void GPUTPCGMMergerSliceRefit::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice) +GPUdii() void GPUTPCGMMergerSliceRefit::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice) { merger.RefitSliceTracks(nBlocks, nThreads, iBlock, iThread, iSlice); } template <> -GPUdii() void GPUTPCGMMergerUnpackGlobal::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice) +GPUdii() void GPUTPCGMMergerUnpackGlobal::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice) { merger.UnpackSliceGlobal(nBlocks, nThreads, iBlock, iThread, iSlice); } template <> -GPUdii() void GPUTPCGMMergerUnpackSaveNumber::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int id) +GPUdii() void GPUTPCGMMergerUnpackSaveNumber::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int id) { if (iThread == 0 && iBlock == 0) { merger.UnpackSaveNumber(id); @@ -66,147 +67,153 @@ GPUdii() void GPUTPCGMMergerUnpackSaveNumber::Thread<0>(int nBlocks, int nThread } template <> -GPUdii() void GPUTPCGMMergerResolve::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerResolve::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.ResolveFindConnectedComponentsSetup(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerResolve::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerResolve::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.ResolveFindConnectedComponentsHookLinks(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerResolve::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerResolve::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.ResolveFindConnectedComponentsHookNeighbors(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerResolve::Thread<3>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerResolve::Thread<3>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.ResolveFindConnectedComponentsMultiJump(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerResolve::Thread<4>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, char useOrigTrackParam, char mergeAll) +GPUdii() void GPUTPCGMMergerResolve::Thread<4>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, char useOrigTrackParam, char mergeAll) { merger.ResolveMergeSlices(smem, nBlocks, nThreads, iBlock, iThread, useOrigTrackParam, mergeAll); } template <> -GPUdii() void GPUTPCGMMergerClearLinks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, char nOutput) +GPUdii() void GPUTPCGMMergerClearLinks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, char nOutput) { merger.ClearTrackLinks(nBlocks, nThreads, iBlock, iThread, nOutput); } template <> -GPUdii() void GPUTPCGMMergerMergeWithinPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerMergeWithinPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.MergeWithinSlicesPrepare(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerMergeSlicesPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int border0, int border1, char useOrigTrackParam) +GPUdii() void GPUTPCGMMergerMergeSlicesPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int border0, int border1, char useOrigTrackParam) { merger.MergeSlicesPrepare(nBlocks, nThreads, iBlock, iThread, border0, border1, useOrigTrackParam); } template <int I, typename... Args> -GPUdii() void GPUTPCGMMergerMergeBorders::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, Args... args) +GPUdii() void GPUTPCGMMergerMergeBorders::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, Args... args) { merger.MergeBorderTracks<I>(nBlocks, nThreads, iBlock, iThread, args...); } -template GPUd() void GPUTPCGMMergerMergeBorders::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode); -template GPUd() void GPUTPCGMMergerMergeBorders::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode); -template GPUd() void GPUTPCGMMergerMergeBorders::Thread<3>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, gputpcgmmergertypes::GPUTPCGMBorderRange* range, int N, int cmpMax); +template GPUd() void GPUTPCGMMergerMergeBorders::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode); +template GPUd() void GPUTPCGMMergerMergeBorders::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode); +template GPUd() void GPUTPCGMMergerMergeBorders::Thread<3>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, gputpcgmmergertypes::GPUTPCGMBorderRange* range, int N, int cmpMax); template <> -GPUdii() void GPUTPCGMMergerMergeBorders::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode) +GPUdii() void GPUTPCGMMergerMergeBorders::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger, int iSlice, char withinSlice, char mergeMode) { merger.MergeBorderTracks<1>(2, nThreads, iBlock & 1, iThread, iBlock / 2, withinSlice, mergeMode); } template <> -GPUdii() void GPUTPCGMMergerMergeCE::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerMergeCE::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.MergeCE(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerLinkGlobalTracks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerLinkGlobalTracks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.LinkGlobalTracks(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerCollect::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerCollect::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.CollectMergedTracks(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerSortTracks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerSortTracks::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { - if (iThread || iBlock) { - return; - } merger.SortTracks(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerSortTracksQPt::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerSortTracksQPt::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { - if (iThread || iBlock) { - return; - } merger.SortTracksQPt(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerSortTracksPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerSortTracksPrepare::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.SortTracksPrepare(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.PrepareClustersForFit0(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.PrepareClustersForFit1(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerPrepareClusters::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.PrepareClustersForFit2(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerFinalize::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerFinalize::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.Finalize0(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerFinalize::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerFinalize::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.Finalize1(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerFinalize::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerFinalize::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { merger.Finalize2(nBlocks, nThreads, iBlock, iThread); } template <> -GPUdii() void GPUTPCGMMergerMergeLoopers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() merger) +GPUdii() void GPUTPCGMMergerMergeLoopers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ + merger.MergeLoopersInit(nBlocks, nThreads, iBlock, iThread); +} + +template <> +GPUdii() void GPUTPCGMMergerMergeLoopers::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ + merger.MergeLoopersSort(nBlocks, nThreads, iBlock, iThread); +} + +template <> +GPUdii() void GPUTPCGMMergerMergeLoopers::Thread<2>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) { - merger.MergeLoopers(nBlocks, nThreads, iBlock, iThread); + merger.MergeLoopersMain(nBlocks, nThreads, iBlock, iThread); } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h index ee6a50d56f9ed..d1865144e4ecc 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerTypes.h b/GPU/GPUTracking/Merger/GPUTPCGMMergerTypes.h index 4911313921c8e..c9b8e15d43925 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerTypes.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerTypes.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,7 +31,8 @@ enum attachTypes { attachAttached = 0x40000000, attachTube = 0x08000000, attachHighIncl = 0x04000000, attachTrackMask = 0x03FFFFFF, - attachFlagMask = 0xFC000000 }; + attachFlagMask = 0xFC000000, + attachZero = 0 }; struct InterpolationErrorHit { float posY, posZ; @@ -51,6 +53,12 @@ struct GPUTPCGMBorderRange { float fMin, fMax; }; +struct GPUTPCOuterParam { + float X, alpha; + float P[5]; + float C[15]; +}; + } // namespace gputpcgmmergertypes } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx new file mode 100644 index 0000000000000..661cd0cae468f --- /dev/null +++ b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx @@ -0,0 +1,239 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTPCGMO2Output.cxx +/// \author David Rohr + +#include "GPUTPCDef.h" +#include "GPUTPCGMO2Output.h" +#include "GPUCommonAlgorithm.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/Constants.h" +#include "TPCFastTransform.h" + +#ifndef GPUCA_GPUCODE +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "GPUQAHelper.h" +#endif + +using namespace o2::gpu; +using namespace o2::tpc; +using namespace o2::tpc::constants; + +GPUdi() static constexpr unsigned char getFlagsReject() { return GPUTPCGMMergedTrackHit::flagReject | GPUTPCGMMergedTrackHit::flagNotFit; } +GPUdi() static unsigned int getFlagsRequired(const GPUSettingsRec& rec) { return rec.tpc.dropSecondaryLegsInOutput ? gputpcgmmergertypes::attachGoodLeg : gputpcgmmergertypes::attachZero; } + +template <> +GPUdii() void GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::prepare>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ + const GPUTPCGMMergedTrack* tracks = merger.OutputTracks(); + const unsigned int nTracks = merger.NOutputTracks(); + const GPUTPCGMMergedTrackHit* trackClusters = merger.Clusters(); + constexpr unsigned char flagsReject = getFlagsReject(); + const unsigned int flagsRequired = getFlagsRequired(merger.Param().rec); + + GPUTPCGMMerger::tmpSort* GPUrestrict() trackSort = merger.TrackSortO2(); + uint2* GPUrestrict() tmpData = merger.ClusRefTmp(); + for (unsigned int i = get_global_id(0); i < nTracks; i += get_global_size(0)) { + unsigned int nCl = 0; + for (unsigned int j = 0; j < tracks[i].NClusters(); j++) { + if (!((trackClusters[tracks[i].FirstClusterRef() + j].state & flagsReject) || (merger.ClusterAttachment()[trackClusters[tracks[i].FirstClusterRef() + j].num] & flagsRequired) != flagsRequired)) { + nCl++; + } + } + if (nCl == 0) { + continue; + } + if (merger.Param().rec.tpc.dropSecondaryLegsInOutput && nCl + 2 < GPUCA_TRACKLET_SELECTOR_MIN_HITS(tracks[i].GetParam().GetQPt())) { // Give 2 hits tolerance in the primary leg, compared to the full fit of the looper + continue; + } + unsigned int myId = CAMath::AtomicAdd(&merger.Memory()->nO2Tracks, 1u); + tmpData[i] = {nCl, CAMath::AtomicAdd(&merger.Memory()->nO2ClusRefs, nCl + (nCl + 1) / 2)}; + trackSort[myId] = {i, (merger.Param().par.earlyTpcTransform || tracks[i].CSide()) ? tracks[i].GetParam().GetTZOffset() : -tracks[i].GetParam().GetTZOffset()}; + } +} + +template <> +GPUdii() void GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::sort>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ +#ifndef GPUCA_SPECIALIZE_THRUST_SORTS + if (iThread || iBlock) { + return; + } + GPUTPCGMMerger::tmpSort* GPUrestrict() trackSort = merger.TrackSortO2(); + auto comp = [](const auto& a, const auto& b) { return (a.y > b.y); }; + GPUCommonAlgorithm::sortDeviceDynamic(trackSort, trackSort + merger.Memory()->nO2Tracks, comp); +#endif +} + +#if defined(GPUCA_SPECIALIZE_THRUST_SORTS) && !defined(GPUCA_GPUCODE_GENRTC) // Specialize GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::sort> +struct GPUTPCGMO2OutputSort_comp { + GPUd() bool operator()(const GPUTPCGMMerger::tmpSort& a, const GPUTPCGMMerger::tmpSort& b) + { + return (a.y > b.y); + } +}; + +template <> +void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal<GPUTPCGMO2Output, GPUTPCGMO2Output::sort>(krnlSetup& _xyz) +{ + GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); + thrust::device_ptr<GPUTPCGMMerger::tmpSort> trackSort(mProcessorsShadow->tpcMerger.TrackSortO2()); + ThrustVolatileAsyncAllocator alloc(this); + thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), trackSort, trackSort + processors()->tpcMerger.NOutputTracksTPCO2(), GPUTPCGMO2OutputSort_comp()); +} +#endif // GPUCA_SPECIALIZE_THRUST_SORTS - Specialize GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::sort> + +template <> +GPUdii() void GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::output>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ + constexpr float MinDelta = 0.1; + const GPUTPCGMMergedTrack* tracks = merger.OutputTracks(); + GPUdEdxInfo* tracksdEdx = merger.OutputTracksdEdx(); + const int nTracks = merger.NOutputTracksTPCO2(); + const GPUTPCGMMergedTrackHit* trackClusters = merger.Clusters(); + constexpr unsigned char flagsReject = getFlagsReject(); + const unsigned int flagsRequired = getFlagsRequired(merger.Param().rec); + TrackTPC* outputTracks = merger.OutputTracksTPCO2(); + unsigned int* clusRefs = merger.OutputClusRefsTPCO2(); + + GPUTPCGMMerger::tmpSort* GPUrestrict() trackSort = merger.TrackSortO2(); + uint2* GPUrestrict() tmpData = merger.ClusRefTmp(); + + for (int iTmp = get_global_id(0); iTmp < nTracks; iTmp += get_global_size(0)) { + TrackTPC oTrack; + const int i = trackSort[iTmp].x; + + oTrack.set(tracks[i].GetParam().GetX(), tracks[i].GetAlpha(), + {tracks[i].GetParam().GetY(), tracks[i].GetParam().GetZ(), tracks[i].GetParam().GetSinPhi(), tracks[i].GetParam().GetDzDs(), tracks[i].GetParam().GetQPt()}, + {tracks[i].GetParam().GetCov(0), + tracks[i].GetParam().GetCov(1), tracks[i].GetParam().GetCov(2), + tracks[i].GetParam().GetCov(3), tracks[i].GetParam().GetCov(4), tracks[i].GetParam().GetCov(5), + tracks[i].GetParam().GetCov(6), tracks[i].GetParam().GetCov(7), tracks[i].GetParam().GetCov(8), tracks[i].GetParam().GetCov(9), + tracks[i].GetParam().GetCov(10), tracks[i].GetParam().GetCov(11), tracks[i].GetParam().GetCov(12), tracks[i].GetParam().GetCov(13), tracks[i].GetParam().GetCov(14)}); + + oTrack.setChi2(tracks[i].GetParam().GetChi2()); + auto& outerPar = tracks[i].OuterParam(); + if (merger.Param().par.dodEdx) { + oTrack.setdEdx(tracksdEdx[i]); + } + oTrack.setOuterParam(o2::track::TrackParCov( + outerPar.X, outerPar.alpha, + {outerPar.P[0], outerPar.P[1], outerPar.P[2], outerPar.P[3], outerPar.P[4]}, + {outerPar.C[0], outerPar.C[1], outerPar.C[2], outerPar.C[3], outerPar.C[4], outerPar.C[5], + outerPar.C[6], outerPar.C[7], outerPar.C[8], outerPar.C[9], outerPar.C[10], outerPar.C[11], + outerPar.C[12], outerPar.C[13], outerPar.C[14]})); + unsigned int nOutCl = tmpData[i].x; + unsigned int clBuff = tmpData[i].y; + oTrack.setClusterRef(clBuff, nOutCl); + unsigned int* clIndArr = &clusRefs[clBuff]; + unsigned char* sectorIndexArr = reinterpret_cast<unsigned char*>(clIndArr + nOutCl); + unsigned char* rowIndexArr = sectorIndexArr + nOutCl; + + unsigned int nOutCl2 = 0; + float t1 = 0, t2 = 0; + int sector1 = 0, sector2 = 0; + const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = merger.GetConstantMem()->ioPtrs.clustersNative; + for (unsigned int j = 0; j < tracks[i].NClusters(); j++) { + if ((trackClusters[tracks[i].FirstClusterRef() + j].state & flagsReject) || (merger.ClusterAttachment()[trackClusters[tracks[i].FirstClusterRef() + j].num] & flagsRequired) != flagsRequired) { + continue; + } + int clusterIdGlobal = trackClusters[tracks[i].FirstClusterRef() + j].num; + int sector = trackClusters[tracks[i].FirstClusterRef() + j].slice; + int globalRow = trackClusters[tracks[i].FirstClusterRef() + j].row; + int clusterIdInRow = clusterIdGlobal - clusters->clusterOffset[sector][globalRow]; + clIndArr[nOutCl2] = clusterIdInRow; + sectorIndexArr[nOutCl2] = sector; + rowIndexArr[nOutCl2] = globalRow; + if (nOutCl2 == 0) { + t1 = clusters->clustersLinear[clusterIdGlobal].getTime(); + sector1 = sector; + } + nOutCl2++; + if (nOutCl2 == nOutCl) { + t2 = clusters->clustersLinear[clusterIdGlobal].getTime(); + sector2 = sector; + } + } + + bool cce = tracks[i].CCE() && ((sector1 < MAXSECTOR / 2) ^ (sector2 < MAXSECTOR / 2)); + float time0 = 0.f, tFwd = 0.f, tBwd = 0.f; + if (merger.Param().par.continuousTracking) { + time0 = tracks[i].GetParam().GetTZOffset(); + if (cce) { + bool lastSide = trackClusters[tracks[i].FirstClusterRef()].slice < MAXSECTOR / 2; + float delta = 0.f; + for (unsigned int iCl = 1; iCl < tracks[i].NClusters(); iCl++) { + if (lastSide ^ (trackClusters[tracks[i].FirstClusterRef() + iCl].slice < MAXSECTOR / 2)) { + auto& cacl1 = trackClusters[tracks[i].FirstClusterRef() + iCl]; + auto& cacl2 = trackClusters[tracks[i].FirstClusterRef() + iCl - 1]; + auto& cl1 = clusters->clustersLinear[cacl1.num]; + auto& cl2 = clusters->clustersLinear[cacl2.num]; + delta = fabs(cl1.getTime() - cl2.getTime()) * 0.5f; + if (delta < MinDelta) { + delta = MinDelta; + } + break; + } + } + tFwd = tBwd = delta; + } else { + // estimate max/min time increments which still keep track in the physical limits of the TPC + float tmin = CAMath::Min(t1, t2); + float tmax = CAMath::Max(t1, t2); + tFwd = tmin - time0; + tBwd = time0 - tmax + merger.GetConstantMem()->calibObjects.fastTransform->getMaxDriftTime(t1 > t2 ? sector1 : sector2); + } + } + oTrack.setTime0(time0); + oTrack.setDeltaTBwd(tBwd); + oTrack.setDeltaTFwd(tFwd); + if (cce) { + oTrack.setHasCSideClusters(); + oTrack.setHasASideClusters(); + } else if (tracks[i].CSide()) { + oTrack.setHasCSideClusters(); + } else { + oTrack.setHasASideClusters(); + } + outputTracks[iTmp] = oTrack; + } +} + +template <> +GPUdii() void GPUTPCGMO2Output::Thread<GPUTPCGMO2Output::mc>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() merger) +{ +#ifndef GPUCA_GPUCODE + const o2::tpc::ClusterNativeAccess* GPUrestrict() clusters = merger.GetConstantMem()->ioPtrs.clustersNative; + if (clusters == nullptr || clusters->clustersMCTruth == nullptr) { + return; + } + if (merger.OutputTracksTPCO2MC() == nullptr) { + return; + } + + auto labelAssigner = GPUTPCTrkLbl(clusters->clustersMCTruth, 0.1f); + unsigned int* clusRefs = merger.OutputClusRefsTPCO2(); + for (unsigned int i = get_global_id(0); i < merger.NOutputTracksTPCO2(); i += get_global_size(0)) { + labelAssigner.reset(); + const auto& trk = merger.OutputTracksTPCO2()[i]; + for (int j = 0; j < trk.getNClusters(); j++) { + uint8_t sectorIndex, rowIndex; + uint32_t clusterIndex; + trk.getClusterReference(clusRefs, j, sectorIndex, rowIndex, clusterIndex); + unsigned int clusterIdGlobal = clusters->clusterOffset[sectorIndex][rowIndex] + clusterIndex; + labelAssigner.addLabel(clusterIdGlobal); + } + merger.OutputTracksTPCO2MC()[i] = labelAssigner.computeLabel(); + } +#endif +} diff --git a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.h b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.h new file mode 100644 index 0000000000000..42a7f2197f0cd --- /dev/null +++ b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTPCGMO2Output.h +/// \author David Rohr + +#ifndef GPUTPCGMO2OUTPUT_H +#define GPUTPCGMO2OUTPUT_H + +#include "GPUTPCDef.h" +#include "GPUTPCGMMergerGPU.h" + +namespace o2 +{ +namespace gpu +{ + +class GPUTPCGMO2Output : public GPUTPCGMMergerGeneral +{ + public: + enum K { prepare = 0, + sort = 1, + output = 2, + mc = 3 }; + template <int iKernel = defaultKernel> + GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& merger); +}; + +} // namespace gpu +} // namespace o2 + +#endif diff --git a/GPU/GPUTracking/Merger/GPUTPCGMOfflineStatisticalErrors.h b/GPU/GPUTracking/Merger/GPUTPCGMOfflineStatisticalErrors.h index fec22db5cc5c2..1ec69ac19e5b8 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMOfflineStatisticalErrors.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMOfflineStatisticalErrors.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.cxx index 3a4cdd6041fff..21fb07098d432 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.h b/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.h index 01c780c093ae9..1643d488112db 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPhysicalTrackModel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.cxx index a4838a5cbcaf8..14904e1fb86c3 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.h b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.h index 674bd8092a789..b8484c9b9aff7 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialField.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #ifndef GPUTPCGMPOLYNOMIALFIELD_H #define GPUTPCGMPOLYNOMIALFIELD_H -#include "GPUTPCDef.h" +#include "GPUCommonDef.h" namespace GPUCA_NAMESPACE { @@ -44,13 +45,13 @@ class GPUTPCGMPolynomialField GPUdi() float GetNominalBz() const { return mNominalBz; } - GPUd() void GetField(float x, float y, float z, float B[3]) const; + GPUd() void GetField(float x, float y, float z, float* B) const; GPUd() float GetFieldBz(float x, float y, float z) const; - GPUd() void GetFieldTrd(float x, float y, float z, float B[3]) const; + GPUd() void GetFieldTrd(float x, float y, float z, float* B) const; GPUd() float GetFieldTrdBz(float x, float y, float z) const; - GPUd() void GetFieldIts(float x, float y, float z, float B[3]) const; + GPUd() void GetFieldIts(float x, float y, float z, float* B) const; GPUd() float GetFieldItsBz(float x, float y, float z) const; void Print() const; @@ -164,7 +165,7 @@ GPUdi() void GPUTPCGMPolynomialField::GetPolynomsTpc(float x, float y, float z, f[9] = z * z; } -GPUdi() void GPUTPCGMPolynomialField::GetField(float x, float y, float z, float B[3]) const +GPUdi() void GPUTPCGMPolynomialField::GetField(float x, float y, float z, float* B) const { const float* fBxS = &mTpcBx[1]; const float* fByS = &mTpcBy[1]; @@ -220,7 +221,7 @@ GPUdi() void GPUTPCGMPolynomialField::GetPolynomsTrd(float x, float y, float z, f[19] = z * zz; } -GPUdi() void GPUTPCGMPolynomialField::GetFieldTrd(float x, float y, float z, float B[3]) const +GPUdi() void GPUTPCGMPolynomialField::GetFieldTrd(float x, float y, float z, float* B) const { float f[NTRDM]; GetPolynomsTrd(x, y, z, f); @@ -266,7 +267,7 @@ GPUdi() void GPUTPCGMPolynomialField::GetPolynomsIts(float x, float y, float z, */ } -GPUdi() void GPUTPCGMPolynomialField::GetFieldIts(float x, float y, float z, float B[3]) const +GPUdi() void GPUTPCGMPolynomialField::GetFieldIts(float x, float y, float z, float* B) const { const float* fBxS = &mItsBx[1]; const float* fByS = &mItsBy[1]; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.cxx index 2ac5192273426..09f4791b4434a 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.h b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.h index fcca6fdad3ddc..38651d8dfdee3 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPolynomialFieldManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx index ea7659578305f..f2e2686b57e4a 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -121,7 +122,7 @@ GPUd() int GPUTPCGMPropagator::RotateToAlpha(float newAlpha) CAMath::SinCos(newAlpha, newSinAlpha, newCosAlpha); float cc = newCosAlpha * mCosAlpha + newSinAlpha * mSinAlpha; // cos(newAlpha - mAlpha); - float ss = newSinAlpha * mCosAlpha - newCosAlpha * mSinAlpha; //sin(newAlpha - mAlpha); + float ss = newSinAlpha * mCosAlpha - newCosAlpha * mSinAlpha; // sin(newAlpha - mAlpha); GPUTPCGMPhysicalTrackModel t0 = mT0; @@ -940,12 +941,12 @@ GPUd() void GPUTPCGMPropagator::Rotate180() mT->QPt() = -mT->QPt(); mT->DzDs() = -mT->DzDs(); - mAlpha = mAlpha + M_PI; - while (mAlpha >= M_PI) { - mAlpha -= 2 * M_PI; + mAlpha = mAlpha + CAMath::Pi(); + while (mAlpha >= CAMath::Pi()) { + mAlpha -= CAMath::TwoPi(); } - while (mAlpha < -M_PI) { - mAlpha += 2 * M_PI; + while (mAlpha < -CAMath::Pi()) { + mAlpha += CAMath::TwoPi(); } mCosAlpha = -mCosAlpha; mSinAlpha = -mSinAlpha; @@ -1064,7 +1065,7 @@ GPUd() void GPUTPCGMPropagator::Mirror(bool inFlyDirection) GPUd() o2::base::MatBudget GPUTPCGMPropagator::getMatBudget(const float* p1, const float* p2) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS return mMatLUT->getMatBudget(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]); #else return o2::base::MatBudget(); @@ -1073,7 +1074,7 @@ GPUd() o2::base::MatBudget GPUTPCGMPropagator::getMatBudget(const float* p1, con GPUdic(0, 1) void GPUTPCGMPropagator::UpdateMaterial(const GPUTPCGMPhysicalTrackModel& GPUrestrict() t0e) { -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS float xyz1[3] = {getGlobalX(mT0.GetX(), mT0.GetY()), getGlobalY(mT0.GetX(), mT0.GetY()), mT0.GetZ()}; float xyz2[3] = {getGlobalX(t0e.GetX(), t0e.GetY()), getGlobalY(t0e.GetX(), t0e.GetY()), t0e.GetZ()}; o2::base::MatBudget mat = getMatBudget(xyz1, xyz2); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h index 5e42cc1be2993..18e789dae4ed8 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx index 1627d5bdcbe67..d9197d6d80e76 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -94,14 +95,14 @@ GPUd() void GPUTPCGMSliceTrack::SetParam2(const GPUTPCGMTrackParam& trk) GPUd() bool GPUTPCGMSliceTrack::FilterErrors(const GPUTPCGMMerger* merger, int iSlice, float maxSinPhi, float sinPhiMargin) { float lastX; - if (merger->Param().par.earlyTpcTransform && !merger->Param().rec.mergerReadFromTrackerDirectly) { + if (merger->Param().par.earlyTpcTransform && !merger->Param().rec.tpc.mergerReadFromTrackerDirectly) { lastX = mOrigTrack->OutTrackCluster(mOrigTrack->NHits() - 1).GetX(); // TODO: Why is this needed, Row2X should work, but looses some tracks } else { //float lastX = merger->Param().tpcGeometry.Row2X(mOrigTrack->Cluster(mOrigTrack->NClusters() - 1).GetRow()); // TODO: again, why does this reduce efficiency? float y, z; const GPUTPCSliceOutCluster* clo; int row, index; - if (merger->Param().rec.mergerReadFromTrackerDirectly) { + if (merger->Param().rec.tpc.mergerReadFromTrackerDirectly) { const GPUTPCTracker& trk = merger->GetConstantMem()->tpcTrackers[iSlice]; const GPUTPCHitId& ic = trk.TrackHits()[mOrigTrack->FirstHitID() + mOrigTrack->NHits() - 1]; index = trk.Data().ClusterDataIndex(trk.Data().Row(ic.RowIndex()), ic.HitIndex()) + merger->GetConstantMem()->ioPtrs.clustersNative->clusterOffset[iSlice][0]; @@ -117,7 +118,7 @@ GPUd() bool GPUTPCGMSliceTrack::FilterErrors(const GPUTPCGMMerger* merger, int i const int N = 3; - float bz = -merger->Param().par.ConstBz; + float bz = -merger->Param().par.constBz; float k = mParam.mQPt * bz; float dx = (1.f / N) * (lastX - mParam.mX); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h index 7f7d0a989f3fc..30e4307a4e51f 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index b81abd9b52cf6..8e846f9f75421 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,11 @@ #define GPUCA_CADEBUG 0 #define DEBUG_SINGLE_TRACK -1 +#define EXTRACT_RESIDUALS 0 + +#if EXTRACT_RESIDUALS == 1 +#include "GPUROOTDump.h" +#endif #include "GPUTPCDef.h" #include "GPUTPCGMTrackParam.h" @@ -26,7 +32,6 @@ #include "GPUTPCClusterData.h" #include "GPUdEdx.h" #include "GPUParam.h" -#include "GPUTPCClusterErrorStat.h" #include "GPUO2DataTypes.h" #include "GPUConstantMem.h" #include "TPCFastTransform.h" @@ -54,29 +59,27 @@ using namespace o2::tpc; static constexpr float kDeg2Rad = M_PI / 180.f; static constexpr float kSectAngle = 2 * M_PI / 18.f; -GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, int iTrk, GPUTPCGMMergedTrackHit* GPUrestrict() clusters, GPUTPCGMMergedTrackHitXYZ* GPUrestrict() clustersXYZ, int& GPUrestrict() N, int& GPUrestrict() NTolerated, float& GPUrestrict() Alpha, int attempt, float maxSinPhi, GPUTPCOuterParam* GPUrestrict() outerParam, GPUdEdxInfo* GPUrestrict() dEdxOut) +GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iTrk, GPUTPCGMMergedTrackHit* GPUrestrict() clusters, GPUTPCGMMergedTrackHitXYZ* GPUrestrict() clustersXYZ, int& GPUrestrict() N, int& GPUrestrict() NTolerated, float& GPUrestrict() Alpha, int attempt, float maxSinPhi, gputpcgmmergertypes::GPUTPCOuterParam* GPUrestrict() outerParam) { const GPUParam& GPUrestrict() param = merger->Param(); - GPUTPCClusterErrorStat errorStat(N); - GPUdEdx dEdx; GPUTPCGMPropagator prop; gputpcgmmergertypes::InterpolationErrors interpolation; prop.SetMaterialTPC(); prop.SetPolynomialField(&merger->Param().polynomialField); prop.SetMaxSinPhi(maxSinPhi); - prop.SetToyMCEventsFlag(param.par.ToyMCEventsFlag); + prop.SetToyMCEventsFlag(param.par.toyMCEventsFlag); if ((clusters[0].slice < 18) == (clusters[N - 1].slice < 18)) { ShiftZ2(clusters, clustersXYZ, merger, N); } - if (param.rec.mergerInterpolateErrors) { + if (param.rec.tpc.mergerInterpolateErrors) { for (int i = 0; i < N; i++) { interpolation.hit[i].errorY = -1; } } - int nWays = param.rec.NWays; + int nWays = param.rec.tpc.nWays; int maxN = N; int ihitStart = 0; float covYYUpd = 0.f; @@ -86,7 +89,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, for (int iWay = 0; iWay < nWays; iWay++) { int nMissed = 0, nMissed2 = 0; - if (iWay && param.rec.NWaysOuter && iWay == nWays - 1 && outerParam) { + if (iWay && param.rec.tpc.nWaysOuter && iWay == nWays - 1 && outerParam) { for (int i = 0; i < 5; i++) { outerParam->P[i] = mP[i]; } @@ -130,7 +133,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, unsigned char clusterState = clusters[ihit].state; const float clAlpha = param.Alpha(clusters[ihit].slice); - if ((param.rec.RejectMode > 0 && nMissed >= param.rec.RejectMode) || nMissed2 >= GPUCA_MERGER_MAXN_MISSED_HARD || clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject) { + if ((param.rec.tpc.trackFitRejectMode > 0 && nMissed >= param.rec.tpc.trackFitRejectMode) || nMissed2 >= GPUCA_MERGER_MAXN_MISSED_HARD || clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject) { CADEBUG(printf("\tSkipping hit, %d hits rejected, flag %X\n", nMissed, (int)clusters[ihit].state)); if (iWay + 2 >= nWays && !(clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject)) { clusters[ihit].state |= GPUTPCGMMergedTrackHit::flagRejectErr; @@ -196,7 +199,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, continue; } } else if (allowModification && lastRow != 255 && CAMath::Abs(clusters[ihit].row - lastRow) > 1) { - if (dEdxOut && iWay == nWays - 1 && clusters[ihit].row == lastRow - 2 && clusters[ihit].leg == clusters[maxN - 1].leg) { + if (merger->Param().par.dodEdx && iWay == nWays - 1 && clusters[ihit].row == lastRow - 2 && clusters[ihit].leg == clusters[maxN - 1].leg) { dEdx.fillSubThreshold(lastRow - 1, param); } AttachClustersPropagate(merger, clusters[ihit].slice, lastRow, clusters[ihit].row, iTrk, clusters[ihit].leg == clusters[maxN - 1].leg, prop, inFlyDirection); @@ -213,7 +216,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, err = prop.PropagateToXAlpha(xx, clAlpha, inFlyDirection); } } - if (lastRow == 255 || CAMath::Abs((int)lastRow - (int)clusters[ihit].row) > 5 || lastSlice != clusters[ihit].slice || (param.rec.RejectMode < 0 && -nMissed <= param.rec.RejectMode)) { + if (lastRow == 255 || CAMath::Abs((int)lastRow - (int)clusters[ihit].row) > 5 || lastSlice != clusters[ihit].slice || (param.rec.tpc.trackFitRejectMode < 0 && -nMissed <= param.rec.tpc.trackFitRejectMode)) { goodRows = 0; } else { goodRows++; @@ -228,7 +231,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, if (err == 0 && changeDirection) { const float mirrordY = prop.GetMirroredYTrack(); - CADEBUG(printf(" -- MiroredY: %f --> %f", mP[0], mirrordY)); + CADEBUG(printf(" -- MirroredY: %f --> %f", mP[0], mirrordY)); if (CAMath::Abs(yy - mP[0]) > CAMath::Abs(yy - mirrordY)) { CADEBUG(printf(" - Mirroring!!!")); if (allowModification) { @@ -266,14 +269,32 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, continue; } CADEBUG(printf("\n")); - errorStat.Fill(xx, yy, zz, prop.GetAlpha(), mX, mP, mC, ihit, iWay); int retVal; float threshold = 3.f + (lastUpdateX >= 0 ? (CAMath::Abs(mX - lastUpdateX) / 2) : 0.f); if (mNDF > 5 && (CAMath::Abs(yy - mP[0]) > threshold || CAMath::Abs(zz - mP[1]) > threshold)) { retVal = 2; } else { - char rejectChi2 = attempt ? 0 : ((param.rec.mergerInterpolateErrors && CAMath::Abs(ihit - ihitMergeFirst) <= 1) ? (refit ? (2 + ((nWays - iWay) & 1)) : 0) : (allowModification && goodRows > 5)); + char rejectChi2 = attempt ? 0 : ((param.rec.tpc.mergerInterpolateErrors && CAMath::Abs(ihit - ihitMergeFirst) <= 1) ? (refit ? (2 + ((nWays - iWay) & 1)) : 0) : (allowModification && goodRows > 5)); +#if EXTRACT_RESIDUALS == 1 + if (iWay == nWays - 1 && interpolation.hit[ihit].errorY > (GPUCA_MERGER_INTERPOLATION_ERROR_TYPE)0) { + const float Iz0 = interpolation.hit[ihit].posY - mP[0]; + const float Iz1 = interpolation.hit[ihit].posZ - mP[1]; + float Iw0 = mC[2] + (float)interpolation.hit[ihit].errorZ; + float Iw2 = mC[0] + (float)interpolation.hit[ihit].errorY; + float Idet1 = 1.f / CAMath::Max(1e-10f, Iw0 * Iw2 - mC[1] * mC[1]); + const float Ik00 = (mC[0] * Iw0 + mC[1] * mC[1]) * Idet1; + const float Ik01 = (mC[0] * mC[1] + mC[1] * Iw2) * Idet1; + const float Ik10 = (mC[1] * Iw0 + mC[2] * mC[1]) * Idet1; + const float Ik11 = (mC[1] * mC[1] + mC[2] * Iw2) * Idet1; + const float ImP0 = mP[0] + Ik00 * Iz0 + Ik01 * Iz1; + const float ImP1 = mP[1] + Ik10 * Iz0 + Ik11 * Iz1; + const float ImC0 = mC[0] - Ik00 * mC[0] + Ik01 * mC[1]; + const float ImC2 = mC[2] - Ik10 * mC[1] + Ik11 * mC[2]; + auto& tup = GPUROOTDump<TNtuple>::get("clusterres", "row:clX:clY:clZ:angle:trkX:trkY:trkZ:trkSinPhi:trkDzDs:trkQPt:trkSigmaY2:trkSigmaZ2trkSigmaQPt2"); + tup.Fill((float)clusters[ihit].row, xx, yy, zz, clAlpha, mX, ImP0, ImP1, mP[2], mP[3], mP[4], ImC0, ImC2, mC[14]); + } +#endif retVal = prop.Update(yy, zz, clusters[ihit].row, param, clusterState, rejectChi2, &interpolation.hit[ihit], refit); } // clang-format off @@ -296,7 +317,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, CADEBUG(printf("Reinit linearization\n")); prop.SetTrack(this, prop.GetAlpha()); } - if (dEdxOut && iWay == nWays - 1 && clusters[ihit].leg == clusters[maxN - 1].leg) { + if (merger->Param().par.dodEdx && iWay == nWays - 1 && clusters[ihit].leg == clusters[maxN - 1].leg) { float qtot, qmax; if (merger->GetConstantMem()->ioPtrs.clustersNative == nullptr) { qtot = clustersXYZ[ihit].amp; @@ -329,9 +350,10 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, if (!(N + NTolerated >= GPUCA_TRACKLET_SELECTOR_MIN_HITS(mP[4]) && 2 * NTolerated <= CAMath::Max(10, N) && CheckNumericalQuality(covYYUpd))) { return (false); // TODO: NTolerated should never become that large, check what is going wrong! } + // TODO: we have looping tracks here with 0 accepted clusters in the primary leg. In that case we should refit the track using only the primary leg. - if (dEdxOut) { - dEdx.computedEdx(*dEdxOut, param); + if (merger->Param().par.dodEdx) { + dEdx.computedEdx(merger->OutputTracksdEdx()[iTrk], param); } Alpha = prop.GetAlpha(); MoveToReference(prop, param, Alpha); @@ -340,25 +362,26 @@ GPUd() bool GPUTPCGMTrackParam::Fit(const GPUTPCGMMerger* GPUrestrict() merger, return (true); } -GPUd() void GPUTPCGMTrackParam::MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& Alpha) +GPUdni() void GPUTPCGMTrackParam::MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& Alpha) { - if (param.rec.TrackReferenceX <= 500) { - for (int k = 0; k < 3; k++) // max 3 attempts - { - int err = prop.PropagateToXAlpha(param.rec.TrackReferenceX, Alpha, 0); - ConstrainSinPhi(); - if (CAMath::Abs(mP[0]) <= mX * CAMath::Tan(kSectAngle / 2.f)) { - break; - } + if (param.rec.tpc.trackReferenceX <= 500) { + GPUTPCGMTrackParam save = *this; + float saveAlpha = Alpha; + for (int attempt = 0; attempt < 3; attempt++) { float dAngle = floor(CAMath::ATan2(mP[0], mX) / kDeg2Rad / 20.f + 0.5f) * kSectAngle; Alpha += dAngle; - if (err || k == 2) { - Rotate(dAngle); - ConstrainSinPhi(); + if (prop.PropagateToXAlpha(param.rec.tpc.trackReferenceX, Alpha, 0)) { break; } + ConstrainSinPhi(); + if (CAMath::Abs(mP[0]) <= mX * CAMath::Tan(kSectAngle / 2.f)) { + return; + } } - } else if (CAMath::Abs(mP[0]) > mX * CAMath::Tan(kSectAngle / 2.f)) { + *this = save; + Alpha = saveAlpha; + } + if (CAMath::Abs(mP[0]) > mX * CAMath::Tan(kSectAngle / 2.f)) { float dAngle = floor(CAMath::ATan2(mP[0], mX) / kDeg2Rad / 20.f + 0.5f) * kSectAngle; Rotate(dAngle); ConstrainSinPhi(); @@ -475,7 +498,7 @@ GPUd() void GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict GPUd() void GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int iRow, int iTrack, bool goodLeg, float Y, float Z) { - if (Merger->Param().rec.DisableRefitAttachment & 1) { + if (Merger->Param().rec.tpc.disableRefitAttachment & 1) { return; } const GPUTPCTracker& GPUrestrict() tracker = *(Merger->GetConstantMem()->tpcTrackers + slice); @@ -497,8 +520,8 @@ GPUd() void GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict float err2Y, err2Z; Merger->Param().GetClusterErrors2(iRow, Z, mP[2], mP[3], err2Y, err2Z); - const float sy2 = CAMath::Min(Merger->Param().rec.tpcTubeMaxSize2, Merger->Param().rec.tpcTubeChi2 * (err2Y + CAMath::Abs(mC[0]))); // Cov can be bogus when following circle - const float sz2 = CAMath::Min(Merger->Param().rec.tpcTubeMaxSize2, Merger->Param().rec.tpcTubeChi2 * (err2Z + CAMath::Abs(mC[2]))); // In that case we should provide the track error externally + const float sy2 = CAMath::Min(Merger->Param().rec.tpc.tubeMaxSize2, Merger->Param().rec.tpc.tubeChi2 * (err2Y + CAMath::Abs(mC[0]))); // Cov can be bogus when following circle + const float sz2 = CAMath::Min(Merger->Param().rec.tpc.tubeMaxSize2, Merger->Param().rec.tpc.tubeChi2 * (err2Z + CAMath::Abs(mC[2]))); // In that case we should provide the track error externally const float tubeY = CAMath::Sqrt(sy2); const float tubeZ = CAMath::Sqrt(sz2); const float sy21 = 1.f / sy2; @@ -526,8 +549,7 @@ GPUd() void GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict const unsigned int hitLst = CA_TEXTURE_FETCH(calink, gAliTexRefu, firsthit, mybin + ny + 1); for (unsigned int ih = hitFst; ih < hitLst; ih++) { int id = idOffset + ids[ih]; - GPUAtomic(unsigned int) * GPUrestrict() const weight = weights + id; - ; + GPUAtomic(unsigned int)* const weight = weights + id; #if !defined(GPUCA_NO_ATOMIC_PRECHECK) && GPUCA_NO_ATOMIC_PRECHECK < 1 if (myWeight <= *weight) { continue; @@ -548,7 +570,10 @@ GPUd() void GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict GPUd() void GPUTPCGMTrackParam::AttachClustersPropagate(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int lastRow, int toRow, int iTrack, bool goodLeg, GPUTPCGMPropagator& GPUrestrict() prop, bool inFlyDirection, float maxSinPhi) { - if (Merger->Param().rec.DisableRefitAttachment & 2) { + if (Merger->Param().rec.tpc.disableRefitAttachment & 2) { + return; + } + if (CAMath::Abs(lastRow - toRow) < 2) { return; } int step = toRow > lastRow ? 1 : -1; @@ -605,7 +630,7 @@ GPUdii() void GPUTPCGMTrackParam::RefitLoop(const GPUTPCGMMerger* GPUrestrict() prop.SetMaterialTPC(); prop.SetPolynomialField(&Merger->Param().polynomialField); prop.SetMaxSinPhi(GPUCA_MAX_SIN_PHI); - prop.SetToyMCEventsFlag(Merger->Param().par.ToyMCEventsFlag); + prop.SetToyMCEventsFlag(Merger->Param().par.toyMCEventsFlag); prop.SetMatLUT(Merger->Param().rec.useMatLUT ? Merger->GetConstantMem()->calibObjects.matLUT : nullptr); prop.SetSeedingErrors(false); prop.SetFitInProjections(true); @@ -613,20 +638,20 @@ GPUdii() void GPUTPCGMTrackParam::RefitLoop(const GPUTPCGMMerger* GPUrestrict() GPUTPCGMLoopData& data = Merger->LoopData()[loopIdx]; prop.SetTrack(&data.param, data.alpha); - if (data.toRow == 0) { + if (data.toSlice == -1) { data.param.AttachClustersMirror<1>(Merger, data.slice, data.row, data.track, data.toY, prop, true); } else { - data.param.FollowCircle<1>(Merger, prop, data.slice, data.row, data.track, data.toAlpha, data.toY, data.toX, data.toSlice, data.toRow, data.inFlyDirection, true); + data.param.FollowCircle<1>(Merger, prop, data.slice, data.row, data.track, data.toAlpha, data.toX, data.toY, data.toSlice, data.toRow, data.inFlyDirection, true); } } template <int I> GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestrict() Merger, GPUTPCGMPropagator& GPUrestrict() prop, int slice, int iRow, int iTrack, float toAlpha, float toX, float toY, int toSlice, int toRow, bool inFlyDirection, bool phase2) { - if (Merger->Param().rec.DisableRefitAttachment & 4) { + if (Merger->Param().rec.tpc.disableRefitAttachment & 4) { return 1; } - if (Merger->Param().rec.loopInterpolationInExtraPass && phase2 == false) { + if (Merger->Param().rec.tpc.loopInterpolationInExtraPass && phase2 == false) { StoreAttachMirror(Merger, slice, iRow, iTrack, toAlpha, toY, toX, toSlice, toRow, inFlyDirection, prop.GetAlpha()); return 1; } @@ -634,33 +659,32 @@ GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestr bool right; float dAlpha = toAlpha - prop.GetAlpha(); if (CAMath::Abs(dAlpha) > 0.001f) { - right = CAMath::Abs(dAlpha) < M_PI ? (dAlpha > 0) : (dAlpha < 0); + right = CAMath::Abs(dAlpha) < CAMath::Pi() ? (dAlpha > 0) : (dAlpha < 0); } else { right = toY > mP[0]; } bool up = (mP[2] < 0) ^ right; int targetRow = up ? (GPUCA_ROW_COUNT - 1) : 0; - float lrFactor = mP[2] > 0 ? 1.f : -1.f; // right ^ down + float lrFactor = mP[2] < 0 ? -1.f : 1.f; // !(right ^ down) // TODO: shouldn't it be "right ? 1.f : -1.f", but that gives worse results... // clang-format off CADEBUG(printf("CIRCLE Track %d: Slice %d Alpha %f X %f Y %f Z %f SinPhi %f DzDs %f - Next hit: Slice %d Alpha %f X %f Y %f - Right %d Up %d dAlpha %f lrFactor %f\n", iTrack, slice, prop.GetAlpha(), mX, mP[0], mP[1], mP[2], mP[3], toSlice, toAlpha, toX, toY, (int)right, (int)up, dAlpha, lrFactor)); // clang-format on AttachClustersPropagate(Merger, slice, iRow, targetRow, iTrack, false, prop, inFlyDirection, 0.7f); - if (prop.RotateToAlpha(prop.GetAlpha() + (M_PI / 2.f) * lrFactor)) { + if (prop.RotateToAlpha(prop.GetAlpha() + (CAMath::Pi() / 2.f) * lrFactor)) { return 1; } - CADEBUG(printf("Rotated: X %f Y %f Z %f SinPhi %f (Alpha %f / %f)\n", mP[0], mX, mP[1], mP[2], prop.GetAlpha(), prop.GetAlpha() + M_PI / 2.f)); + CADEBUG(printf("Rotated: X %f Y %f Z %f SinPhi %f (Alpha %f / %f)\n", mP[0], mX, mP[1], mP[2], prop.GetAlpha(), prop.GetAlpha() + CAMath::Pi() / 2.f)); while (slice != toSlice || FollowCircleChk(lrFactor, toY, toX, up, right)) { while ((slice != toSlice) ? (CAMath::Abs(mX) <= CAMath::Abs(mP[0]) * CAMath::Tan(kSectAngle / 2.f)) : FollowCircleChk(lrFactor, toY, toX, up, right)) { int err = prop.PropagateToXAlpha(mX + 1.f, prop.GetAlpha(), inFlyDirection); if (err) { CADEBUG(printf("propagation error (%d)\n", err)); - prop.RotateToAlpha(prop.GetAlpha() - (M_PI / 2.f) * lrFactor); + prop.RotateToAlpha(prop.GetAlpha() - (CAMath::Pi() / 2.f) * lrFactor); return 1; } CADEBUG(printf("Propagated to y = %f: X %f Z %f SinPhi %f\n", mX, mP[0], mP[1], mP[2])); - int found = 0; - for (int j = 0; j < GPUCA_ROW_COUNT && found < 3; j++) { + for (int j = 0; j < GPUCA_ROW_COUNT; j++) { float rowX = Merger->Param().tpcGeometry.Row2X(j); if (CAMath::Abs(rowX - (-mP[0] * lrFactor)) < 1.5f) { CADEBUG(printf("Attempt row %d (Y %f Z %f)\n", j, mX * lrFactor, mP[1])); @@ -681,9 +705,9 @@ GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestr } } CADEBUG(printf("Rotating to slice %d\n", slice)); - if (prop.RotateToAlpha(param.Alpha(slice) + (M_PI / 2.f) * lrFactor)) { + if (prop.RotateToAlpha(param.Alpha(slice) + (CAMath::Pi() / 2.f) * lrFactor)) { CADEBUG(printf("rotation error\n")); - prop.RotateToAlpha(prop.GetAlpha() - (M_PI / 2.f) * lrFactor); + prop.RotateToAlpha(prop.GetAlpha() - (CAMath::Pi() / 2.f) * lrFactor); return 1; } CADEBUG(printf("After Rotatin Alpha %f Position X %f Y %f Z %f SinPhi %f\n", prop.GetAlpha(), mP[0], mX, mP[1], mP[2])); @@ -691,7 +715,7 @@ GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestr } CADEBUG(printf("Rotating back\n")); for (int i = 0; i < 2; i++) { - if (prop.RotateToAlpha(prop.GetAlpha() + (M_PI / 2.f) * lrFactor) == 0) { + if (prop.RotateToAlpha(prop.GetAlpha() + (CAMath::Pi() / 2.f) * lrFactor) == 0) { break; } if (i) { @@ -728,11 +752,11 @@ GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestr template <int I> GPUdni() void GPUTPCGMTrackParam::AttachClustersMirror(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int iRow, int iTrack, float toY, GPUTPCGMPropagator& GPUrestrict() prop, bool phase2) { - if (Merger->Param().rec.DisableRefitAttachment & 8) { + if (Merger->Param().rec.tpc.disableRefitAttachment & 8) { return; } - if (Merger->Param().rec.loopInterpolationInExtraPass && phase2 == false) { - StoreAttachMirror(Merger, slice, iRow, iTrack, 0, toY, 0, 0, 0, 0, prop.GetAlpha()); + if (Merger->Param().rec.tpc.loopInterpolationInExtraPass && phase2 == false) { + StoreAttachMirror(Merger, slice, iRow, iTrack, 0, toY, 0, -1, 0, 0, prop.GetAlpha()); return; } float X = mP[2] > 0 ? mP[0] : -mP[0]; @@ -795,6 +819,9 @@ GPUdni() void GPUTPCGMTrackParam::AttachClustersMirror(const GPUTPCGMMerger* GPU GPUd() void GPUTPCGMTrackParam::ShiftZ2(const GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, const GPUTPCGMMerger* merger, int N) { float tzInner, tzOuter; + if (N == 0) { + N = 1; + } if (merger->Param().par.earlyTpcTransform) { tzInner = clustersXYZ[N - 1].z; tzOuter = clustersXYZ[0].z; @@ -808,7 +835,7 @@ GPUd() void GPUTPCGMTrackParam::ShiftZ2(const GPUTPCGMMergedTrackHit* clusters, GPUd() void GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMerger* GPUrestrict() merger, int slice, float tz1, float tz2) { - if (!merger->Param().par.ContinuousTracking) { + if (!merger->Param().par.continuousTracking) { return; } const float cosPhi = CAMath::Abs(mP[2]) < 1.f ? CAMath::Sqrt(1 - mP[2] * mP[2]) : 0.f; @@ -828,7 +855,7 @@ GPUd() void GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMerger* GPUrestrict() merge // printf("Tan %f %f (%f %f)\n", atana, atanb, mX - xp, mP[0] - yp); const float dS = (xp > 0 ? (atana + atanb) : (atanb - atana)) * r; float z0 = dS * mP[3]; - // printf("Track Z %f (Offset %f), z0 %f, V %f (dS %f, dZds %f, qPt %f) - Z span %f to %f: diff %f\n", mP[1], mTZOffset, z0, mP[1] - z0, dS, mP[3], mP[4], tz2, tz1, tz2 - tz1); + // printf("Track Z %f (Offset %f), z0 %f, V %f (dS %f, dZds %f, qPt %f) - TZ span %f to %f: diff %f\n", mP[1], mTZOffset, z0, mP[1] - z0, dS, mP[3], mP[4], tz2, tz1, tz2 - tz1); if (CAMath::Abs(z0) > 250.f) { z0 = z0 > 0 ? 250.f : -250.f; } @@ -839,6 +866,7 @@ GPUd() void GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMerger* GPUrestrict() merge deltaZ = 0; float zMax = CAMath::Max(tz1, tz2); float zMin = CAMath::Min(tz1, tz2); + // printf("Z Check: Clusters %f %f, min %f max %f vtx %f\n", tz1, tz2, zMin, zMax, mTZOffset); if (zMin < 0 && zMin - mTZOffset < -250) { deltaZ = zMin - mTZOffset + 250; } else if (zMax > 0 && zMax - mTZOffset > 250) { @@ -849,25 +877,26 @@ GPUd() void GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMerger* GPUrestrict() merge } else if (zMax > 0 && zMin - mTZOffset < 0) { deltaZ = zMin - mTZOffset; } - // if (deltaZ != 0) printf("Moving clusters to TPC Range: Side %f, Shift %f: %f to %f --> %f to %f\n", tz2, deltaZ, tz2 - mTZOffset, tz1 - mTZOffset, tz2 - mTZOffset - deltaZ, tz1 - mTZOffset - deltaZ); + // if (deltaZ != 0) printf("Moving clusters to TPC Range: Shift %f in Z: %f to %f --> %f to %f in Z\n", deltaZ, tz2 - mTZOffset, tz1 - mTZOffset, tz2 - mTZOffset - deltaZ, tz1 - mTZOffset - deltaZ); mTZOffset += deltaZ; mP[1] -= deltaZ; } else { float deltaT = merger->GetConstantMem()->calibObjects.fastTransform->convDeltaZtoDeltaTimeInTimeFrame(slice, deltaZ); mTZOffset += deltaT; mP[1] -= deltaZ; - const float minT = CAMath::Min(tz1, tz2); - const float maxT = CAMath::Max(CAMath::Max(tz1, tz2) - merger->GetConstantMem()->calibObjects.fastTransform->getMaxDriftTime(slice), 0.f); - // printf("T Check: max %f min %f (min2 %f) vtx %f\n", maxT, minT, CAMath::Min(tzinner, tz2), mTZOffset); + const float maxT = CAMath::Min(tz1, tz2); + const float minT = CAMath::Max(tz1, tz2) - merger->GetConstantMem()->calibObjects.fastTransform->getMaxDriftTime(slice); + // printf("T Check: Clusters %f %f, min %f max %f vtx %f\n", tz1, tz2, minT, maxT, mTZOffset); deltaT = 0.f; - if (mTZOffset < maxT) { - deltaT = maxT - mTZOffset; - } - if (mTZOffset > minT) { + if (mTZOffset < minT) { deltaT = minT - mTZOffset; } + if (mTZOffset > maxT) { + deltaT = maxT - mTZOffset; + } if (deltaT != 0.f) { deltaZ = merger->GetConstantMem()->calibObjects.fastTransform->convDeltaTimeToDeltaZinTimeFrame(slice, deltaT); + // printf("Moving clusters to TPC Range: Shift %f in Z: %f to %f --> %f to %f in T\n", deltaZ, tz2 - mTZOffset, tz1 - mTZOffset, tz2 - mTZOffset - deltaT, tz1 - mTZOffset - deltaT); mTZOffset += deltaT; mP[1] -= deltaZ; } @@ -888,7 +917,7 @@ GPUd() bool GPUTPCGMTrackParam::CheckNumericalQuality(float overrideCovYY) const //* Check that the track parameters and covariance matrix are reasonable bool ok = CAMath::Finite(mX) && CAMath::Finite(mChi2); CADEBUG( - printf("OK %d - ", (int)ok); for (int i = 0; i < 5; i++) { printf("%f ", mP[i]); } printf(" - "); for (int i = 0; i < 15; i++) { printf("%f ", mC[i]); } printf("\n")); + printf("OK %d - %f - ", (int)ok, mX); for (int i = 0; i < 5; i++) { printf("%f ", mP[i]); } printf(" - "); for (int i = 0; i < 15; i++) { printf("%f ", mC[i]); } printf("\n")); const float* c = mC; for (int i = 0; i < 15; i++) { ok = ok && CAMath::Finite(c[i]); @@ -981,21 +1010,21 @@ GPUd() void GPUTPCGMTrackParam::RefitTrack(GPUTPCGMMergedTrack& GPUrestrict() tr GPUTPCGMTrackParam t = track.Param(); float Alpha = track.Alpha(); CADEBUG(int nTrackHitsOld = nTrackHits; float ptOld = t.QPt()); - bool ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), merger->ClustersXYZ() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, attempt, GPUCA_MAX_SIN_PHI, &track.OuterParam(), merger->Param().par.dodEdx ? &track.dEdxInfo() : nullptr); + bool ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), merger->ClustersXYZ() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, attempt, GPUCA_MAX_SIN_PHI, &track.OuterParam()); CADEBUG(printf("Finished Fit Track %d\n", iTrk)); CADEBUG(printf("OUTPUT hits %d -> %d+%d = %d, QPt %f -> %f, SP %f, ok %d chi2 %f chi2ndf %f\n", nTrackHitsOld, nTrackHits, NTolerated, nTrackHits + NTolerated, ptOld, t.QPt(), t.SinPhi(), (int)ok, t.Chi2(), t.Chi2() / CAMath::Max(1, nTrackHits))); - if (!ok && attempt == 0 && merger->Param().rec.retryRefit) { + if (!ok && attempt == 0 && merger->Param().rec.tpc.retryRefit) { for (unsigned int i = 0; i < track.NClusters(); i++) { merger->Clusters()[track.FirstClusterRef() + i].state &= GPUTPCGMMergedTrackHit::clustererAndSharedFlags; } CADEBUG(printf("Track rejected, marking for retry\n")); - if (merger->Param().rec.retryRefit == 2) { + if (merger->Param().rec.tpc.retryRefit == 2) { nTrackHits = track.NClusters(); NTolerated = 0; // Clusters not fit but tollerated for track length cut t = track.Param(); Alpha = track.Alpha(); - ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), merger->ClustersXYZ() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, 1, GPUCA_MAX_SIN_PHI, &track.OuterParam(), merger->Param().par.dodEdx ? &track.dEdxInfo() : nullptr); + ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), merger->ClustersXYZ() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, 1, GPUCA_MAX_SIN_PHI, &track.OuterParam()); } else { unsigned int nRefit = CAMath::AtomicAdd(&merger->Memory()->nRetryRefit, 1u); merger->RetryRefitIds()[nRefit] = iTrk; @@ -1006,6 +1035,8 @@ GPUd() void GPUTPCGMTrackParam::RefitTrack(GPUTPCGMMergedTrack& GPUrestrict() tr t.QPt() = 1.e-4f; } + CADEBUG(if (t.GetX() > 250) { printf("ERROR, Track %d at impossible X %f, Pt %f, Looper %d\n", iTrk, t.GetX(), CAMath::Abs(1.f / t.QPt()), (int)merger->OutputTracks()[iTrk].Looper()); }); + track.SetOK(ok); track.SetNClustersFitted(nTrackHits); track.Param() = t; @@ -1032,7 +1063,7 @@ GPUd() void GPUTPCGMTrackParam::RefitTrack(GPUTPCGMMergedTrack& GPUrestrict() tr } } -GPUd() bool GPUTPCGMTrackParam::Rotate(float alpha) +GPUd() void GPUTPCGMTrackParam::Rotate(float alpha) { float cA, sA; CAMath::SinCos(alpha, sA, cA); @@ -1067,5 +1098,4 @@ GPUd() bool GPUTPCGMTrackParam::Rotate(float alpha) mC[10] = -mC[10]; mC[11] = -mC[11]; } - return true; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h index dd7706547f8fd..3e409f11f028c 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include "GPUTPCDef.h" #include "GPUTPCGMMergedTrackHit.h" +#include "GPUTPCGMMergerTypes.h" #include "GPUCommonMath.h" #include "GPUdEdxInfo.h" @@ -47,12 +49,6 @@ class GPUTPCGMPropagator; class GPUTPCGMTrackParam { public: - struct GPUTPCOuterParam { - float X, alpha; - float P[5]; - float C[15]; - }; - GPUd() float& X() { return mX; @@ -147,7 +143,7 @@ class GPUTPCGMTrackParam GPUd() bool CheckNumericalQuality(float overrideCovYY = -1.f) const; GPUd() bool CheckCov() const; - GPUd() bool Fit(const GPUTPCGMMerger* merger, int iTrk, GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, int& N, int& NTolerated, float& Alpha, int attempt = 0, float maxSinPhi = GPUCA_MAX_SIN_PHI, GPUTPCOuterParam* outerParam = nullptr, GPUdEdxInfo* dEdxOut = nullptr); + GPUd() bool Fit(GPUTPCGMMerger* merger, int iTrk, GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, int& N, int& NTolerated, float& Alpha, int attempt = 0, float maxSinPhi = GPUCA_MAX_SIN_PHI, gputpcgmmergertypes::GPUTPCOuterParam* outerParam = nullptr); GPUd() void MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& alpha); GPUd() void MirrorTo(GPUTPCGMPropagator& prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, unsigned char row, unsigned char clusterState, bool mirrorParameters); GPUd() int MergeDoubleRowClusters(int& ihit, int wayDirection, GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, const GPUTPCGMMerger* merger, GPUTPCGMPropagator& prop, float& xx, float& yy, float& zz, int maxN, float clAlpha, unsigned char& clusterState, bool rejectChi2); @@ -181,14 +177,14 @@ class GPUTPCGMTrackParam } GPUdi() static void NormalizeAlpha(float& alpha) { - if (alpha > M_PI) { - alpha -= 2 * M_PI; - } else if (alpha <= -M_PI) { - alpha += 2 * M_PI; + if (alpha > CAMath::Pi()) { + alpha -= CAMath::TwoPi(); + } else if (alpha <= -CAMath::Pi()) { + alpha += CAMath::TwoPi(); } } - GPUd() bool Rotate(float alpha); + GPUd() void Rotate(float alpha); GPUd() void ShiftZ(const GPUTPCGMMerger* merger, int slice, float tzInner, float tzOuter); GPUd() void ShiftZ2(const GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, const GPUTPCGMMerger* merger, int N); @@ -244,7 +240,7 @@ struct GPUTPCGMLoopData { float toAlpha; unsigned char slice; unsigned char row; - unsigned char toSlice; + char toSlice; unsigned char toRow; unsigned char inFlyDirection; }; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.cxx index 472edf9719d77..7b33df8ecd787 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "GPUTPCGMTracksToTPCSeeds.h" #include "GPUTPCGlobalMergerComponent.h" +#include "GPUTPCGMMergerTypes.h" #include "GPUTPCGMMerger.h" #include "GPULogging.h" #include "AliTPCtracker.h" @@ -120,7 +122,7 @@ void GPUTPCGMTracksToTPCSeeds::UpdateParamsOuter(TObjArray* seeds) return; } AliTPCseed* seed = (AliTPCseed*)seeds->UncheckedAt(index++); - const GPUTPCGMTrackParam::GPUTPCGMTrackParam::GPUTPCOuterParam& param = track.OuterParam(); + const gputpcgmmergertypes::GPUTPCOuterParam& param = track.OuterParam(); seed->Set(param.X, param.alpha, param.P, param.C); } } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.h b/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.h index ff6771c04828b..029cb108d4119 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMTracksToTPCSeeds.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx index 773f66f3dd20b..c586abf5f68b7 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -290,21 +291,21 @@ int GPUTPCGlobalMergerComponent::Configure(const char* cdbEntry, const char* cha // Initialize the merger - GPUSettingsEvent ev; + GPUSettingsGRP grp; GPUSettingsRec rec; GPUSettingsProcessing devProc; - ev.solenoidBz = fSolenoidBz; + grp.solenoidBz = fSolenoidBz; if (fClusterErrorCorrectionY > 1.e-4) { - rec.ClusterError2CorrectionY = fClusterErrorCorrectionY * fClusterErrorCorrectionY; + rec.tpc.clusterError2CorrectionY = fClusterErrorCorrectionY * fClusterErrorCorrectionY; } if (fClusterErrorCorrectionZ > 1.e-4) { - rec.ClusterError2CorrectionZ = fClusterErrorCorrectionZ * fClusterErrorCorrectionZ; + rec.tpc.clusterError2CorrectionZ = fClusterErrorCorrectionZ * fClusterErrorCorrectionZ; } - rec.NWays = fNWays; - rec.NWaysOuter = fNWaysOuter; - rec.mergerInterpolateErrors = false; - rec.NonConsecutiveIDs = true; - rec.mergerReadFromTrackerDirectly = false; + rec.tpc.nWays = fNWays; + rec.tpc.nWaysOuter = fNWaysOuter; + rec.tpc.mergerInterpolateErrors = false; + rec.nonConsecutiveIDs = true; + rec.tpc.mergerReadFromTrackerDirectly = false; devProc.ompThreads = 1; devProc.ompKernels = false; @@ -313,7 +314,7 @@ int GPUTPCGlobalMergerComponent::Configure(const char* cdbEntry, const char* cha steps.inputs.set(GPUDataTypes::InOutType::TPCSectorTracks); steps.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); - fRec->SetSettings(&ev, &rec, &devProc, &steps); + fRec->SetSettings(&grp, &rec, &devProc, &steps); fChain->LoadClusterErrors(); if (fRec->Init()) { return -EINVAL; diff --git a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.h b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.h index 8603f72adb64d..414a23fbc2c9a 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.h +++ b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Merger/macros/checkPropagation.C b/GPU/GPUTracking/Merger/macros/checkPropagation.C index c4c60b472a58a..7c4315e8a04d6 100644 --- a/GPU/GPUTracking/Merger/macros/checkPropagation.C +++ b/GPU/GPUTracking/Merger/macros/checkPropagation.C @@ -58,7 +58,7 @@ int RecalculateSlice(GPUTPCGMPhysicalTrackModel& t, AliExternalTrackParam& t0, i int checkPropagation() { - // gSystem->Load("libAliHLTTPC.so"); + // gSystem->Load("libAliHLTTPC"); TH1F* hDiff[3] = {0, 0, 0}; diff --git a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldIts.C b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldIts.C index 4b42316c9ab41..a61004ce6f828 100644 --- a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldIts.C +++ b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldIts.C @@ -1,6 +1,6 @@ int fitPolynomialFieldIts() { - gSystem->Load("libAliHLTTPC.so"); + gSystem->Load("libAliHLTTPC"); GPUTPCGMPolynomialField polyField; AliMagF* fld = new AliMagF("Fit", "Fit", 1., 1., AliMagF::k5kG); GPUTPCGMPolynomialFieldManager::FitFieldIts(fld, polyField, 1.); diff --git a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTpc.C b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTpc.C index 74e2824215659..7b1424163a6c6 100644 --- a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTpc.C +++ b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTpc.C @@ -1,6 +1,6 @@ int fitPolynomialFieldTpc() { - gSystem->Load("libAliHLTTPC.so"); + gSystem->Load("libAliHLTTPC"); GPUTPCGMPolynomialField polyField; AliMagF* fld = new AliMagF("Fit", "Fit", 1., 1., AliMagF::k5kG); GPUTPCGMPolynomialFieldManager::FitFieldTpc(fld, polyField, 10); diff --git a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTrd.C b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTrd.C index 03ca5caf05f22..debfba0c34cf0 100644 --- a/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTrd.C +++ b/GPU/GPUTracking/Merger/macros/fitPolynomialFieldTrd.C @@ -1,6 +1,6 @@ int fitPolynomialFieldTrd() { - gSystem->Load("libAliHLTTPC.so"); + gSystem->Load("libAliHLTTPC"); GPUTPCGMPolynomialField polyField; AliMagF* fld = new AliMagF("Fit", "Fit", 1., 1., AliMagF::k5kG); GPUTPCGMPolynomialFieldManager::FitFieldTrd(fld, polyField, 2); diff --git a/GPU/GPUTracking/Refit/GPUTrackParamConvert.h b/GPU/GPUTracking/Refit/GPUTrackParamConvert.h new file mode 100644 index 0000000000000..846037ddf0039 --- /dev/null +++ b/GPU/GPUTracking/Refit/GPUTrackParamConvert.h @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTrackParamConvert.h +/// \author David Rohr + +#ifndef O2_GPU_TRACKPARAMCONVERT_H +#define O2_GPU_TRACKPARAMCONVERT_H + +#include "GPUO2DataTypes.h" +#include "GPUTPCGMTrackParam.h" +#include "GPUTPCGMMergedTrack.h" +#include "GPUTPCGMPropagator.h" +#include "ReconstructionDataFormats/Track.h" +#include "DetectorsBase/Propagator.h" +#include "DataFormatsTPC/TrackTPC.h" + +namespace o2::gpu +{ + +GPUdi() static void convertTrackParam(GPUTPCGMTrackParam& trk, const o2::track::TrackParCov& trkX) +{ + for (int i = 0; i < 5; i++) { + trk.Par()[i] = trkX.getParams()[i]; + } + for (int i = 0; i < 15; i++) { + trk.Cov()[i] = trkX.getCov()[i]; + } + trk.X() = trkX.getX(); +} +GPUdi() static void convertTrackParam(o2::track::TrackParCov& trk, const GPUTPCGMTrackParam& trkX) +{ + for (int i = 0; i < 5; i++) { + trk.setParam(trkX.GetPar()[i], i); + } + for (int i = 0; i < 15; i++) { + trk.setCov(trkX.GetCov()[i], i); + } + trk.setX(trkX.GetX()); +} + +} // namespace o2::gpu + +#endif diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx index 0612463158b30..20f715d06f46c 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,14 +25,16 @@ #include "DetectorsBase/Propagator.h" #include "DataFormatsTPC/TrackTPC.h" #include "GPUParam.inc" +#include "GPUCommonArray.h" +#include "GPUParam.h" +#include "GPUTrackParamConvert.h" +#include "GPUCommonTypeTraits.h" using namespace GPUCA_NAMESPACE::gpu; using namespace o2::track; using namespace o2::base; using namespace o2::tpc; -static constexpr float kDeg2Rad = M_PI / 180.f; -static constexpr float kSectAngle = 2 * M_PI / 18.f; static constexpr int kIGNORE_ENDS = 3; #define IgnoreErrors(SNP) \ @@ -45,7 +48,10 @@ static constexpr int kIGNORE_ENDS = 3; } // End IgnoreErrors -void GPUTrackingRefitProcessor::InitializeProcessor() {} +#ifndef GPUCA_GPUCODE +void GPUTrackingRefitProcessor::InitializeProcessor() +{ +} void GPUTrackingRefitProcessor::RegisterMemoryAllocation() { @@ -55,6 +61,7 @@ void GPUTrackingRefitProcessor::RegisterMemoryAllocation() void GPUTrackingRefitProcessor::SetMaxData(const GPUTrackingInOutPointers& io) { } +#endif namespace { @@ -71,7 +78,7 @@ struct refitTrackTypes<TrackParCov> { } // anonymous namespace template <> -void GPUTrackingRefit::initProp<GPUTPCGMPropagator>(GPUTPCGMPropagator& prop) +GPUd() void GPUTrackingRefit::initProp<GPUTPCGMPropagator>(GPUTPCGMPropagator& prop) { prop.SetMaterialTPC(); prop.SetMaxSinPhi(GPUCA_MAX_SIN_PHI); @@ -80,55 +87,37 @@ void GPUTrackingRefit::initProp<GPUTPCGMPropagator>(GPUTPCGMPropagator& prop) prop.SetFitInProjections(mPparam->rec.fitInProjections != 0); prop.SetPropagateBzOnly(false); prop.SetPolynomialField(&mPparam->polynomialField); + prop.SetMatLUT(mPmatLUT); } template <> -void GPUTrackingRefit::initProp<const Propagator*>(const Propagator*& prop) +GPUd() void GPUTrackingRefit::initProp<const Propagator*>(const Propagator*& prop) { prop = mPpropagator; } template <class T, class S, class U> -void GPUTrackingRefit::convertTrack(T& trk, const S& trkX, U& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack(T& trk, const S& trkX, U& prop, float* chi2) { trk = trkX; } -static void convertTrackParam(GPUTPCGMTrackParam& trk, const TrackParCov& trkX) -{ - for (int i = 0; i < 5; i++) { - trk.Par()[i] = trkX.getParams()[i]; - } - for (int i = 0; i < 15; i++) { - trk.Cov()[i] = trkX.getCov()[i]; - } - trk.X() = trkX.getX(); -} -static void convertTrackParam(TrackParCov& trk, const GPUTPCGMTrackParam& trkX) -{ - for (int i = 0; i < 5; i++) { - trk.setParam(trkX.GetPar()[i], i); - } - for (int i = 0; i < 15; i++) { - trk.setCov(trkX.GetCov()[i], i); - } - trk.setX(trkX.GetX()); -} + // Generic template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, TrackParCov, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const TrackParCov& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, TrackParCov, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const TrackParCov& trkX, GPUTPCGMPropagator& prop, float* chi2) { convertTrackParam(trk, trkX); prop.SetTrack(&trk, trkX.getAlpha()); } template <> -void GPUTrackingRefit::convertTrack<TrackParCov, GPUTPCGMTrackParam, GPUTPCGMPropagator>(TrackParCov& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackParCov, GPUTPCGMTrackParam, GPUTPCGMPropagator>(TrackParCov& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) { convertTrackParam(trk, trkX); trk.setAlpha(prop.GetAlpha()); } // GPUTPCGMMergedTrack input template <> -void GPUTrackingRefit::convertTrack<TrackParCov, GPUTPCGMMergedTrack, const Propagator*>(TrackParCov& trk, const GPUTPCGMMergedTrack& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackParCov, GPUTPCGMMergedTrack, const Propagator*>(TrackParCov& trk, const GPUTPCGMMergedTrack& trkX, const Propagator*& prop, float* chi2) { initProp(prop); convertTrackParam(trk, trkX.GetParam()); @@ -136,62 +125,62 @@ void GPUTrackingRefit::convertTrack<TrackParCov, GPUTPCGMMergedTrack, const Prop *chi2 = trkX.GetParam().GetChi2(); } template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMMergedTrack, TrackParCov, const Propagator*>(GPUTPCGMMergedTrack& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMMergedTrack, TrackParCov, const Propagator*>(GPUTPCGMMergedTrack& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) { convertTrackParam(trk.Param(), trkX); trk.SetAlpha(trkX.getAlpha()); trk.Param().SetChi2(*chi2); } template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, GPUTPCGMMergedTrack, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const GPUTPCGMMergedTrack& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, GPUTPCGMMergedTrack, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const GPUTPCGMMergedTrack& trkX, GPUTPCGMPropagator& prop, float* chi2) { initProp(prop); trk = trkX.GetParam(); prop.SetTrack(&trk, trkX.GetAlpha()); } template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMMergedTrack, GPUTPCGMTrackParam, GPUTPCGMPropagator>(GPUTPCGMMergedTrack& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMMergedTrack, GPUTPCGMTrackParam, GPUTPCGMPropagator>(GPUTPCGMMergedTrack& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) { trk.SetParam(trkX); trk.SetAlpha(prop.GetAlpha()); } // TrackTPC input template <> -void GPUTrackingRefit::convertTrack<TrackParCov, TrackTPC, const Propagator*>(TrackParCov& trk, const TrackTPC& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackParCov, TrackTPC, const Propagator*>(TrackParCov& trk, const TrackTPC& trkX, const Propagator*& prop, float* chi2) { initProp(prop); convertTrack<TrackParCov, TrackParCov, const Propagator*>(trk, trkX, prop, nullptr); *chi2 = trkX.getChi2(); } template <> -void GPUTrackingRefit::convertTrack<TrackTPC, TrackParCov, const Propagator*>(TrackTPC& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackTPC, TrackParCov, const Propagator*>(TrackTPC& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) { convertTrack<TrackParCov, TrackParCov, const Propagator*>(trk, trkX, prop, nullptr); trk.setChi2(*chi2); } template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, TrackTPC, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const TrackTPC& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, TrackTPC, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const TrackTPC& trkX, GPUTPCGMPropagator& prop, float* chi2) { initProp(prop); convertTrack<GPUTPCGMTrackParam, TrackParCov, GPUTPCGMPropagator>(trk, trkX, prop, nullptr); trk.SetChi2(trkX.getChi2()); } template <> -void GPUTrackingRefit::convertTrack<TrackTPC, GPUTPCGMTrackParam, GPUTPCGMPropagator>(TrackTPC& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackTPC, GPUTPCGMTrackParam, GPUTPCGMPropagator>(TrackTPC& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) { convertTrack<TrackParCov, GPUTPCGMTrackParam, GPUTPCGMPropagator>(trk, trkX, prop, nullptr); trk.setChi2(trkX.GetChi2()); } // TrackParCovWithArgs input template <> -void GPUTrackingRefit::convertTrack<TrackParCov, GPUTrackingRefit::TrackParCovWithArgs, const Propagator*>(TrackParCov& trk, const GPUTrackingRefit::TrackParCovWithArgs& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<TrackParCov, GPUTrackingRefit::TrackParCovWithArgs, const Propagator*>(TrackParCov& trk, const GPUTrackingRefit::TrackParCovWithArgs& trkX, const Propagator*& prop, float* chi2) { initProp(prop); convertTrack<TrackParCov, TrackParCov, const Propagator*>(trk, trkX.trk, prop, nullptr); *chi2 = trkX.chi2 ? *trkX.chi2 : 0.f; } template <> -void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, TrackParCov, const Propagator*>(GPUTrackingRefit::TrackParCovWithArgs& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, TrackParCov, const Propagator*>(GPUTrackingRefit::TrackParCovWithArgs& trk, const TrackParCov& trkX, const Propagator*& prop, float* chi2) { convertTrack<TrackParCov, TrackParCov, const Propagator*>(trk.trk, trkX, prop, nullptr); if (trk.chi2) { @@ -199,14 +188,14 @@ void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, Track } } template <> -void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, GPUTrackingRefit::TrackParCovWithArgs, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const GPUTrackingRefit::TrackParCovWithArgs& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTPCGMTrackParam, GPUTrackingRefit::TrackParCovWithArgs, GPUTPCGMPropagator>(GPUTPCGMTrackParam& trk, const GPUTrackingRefit::TrackParCovWithArgs& trkX, GPUTPCGMPropagator& prop, float* chi2) { initProp(prop); convertTrack<GPUTPCGMTrackParam, TrackParCov, GPUTPCGMPropagator>(trk, trkX.trk, prop, nullptr); trk.SetChi2(trkX.chi2 ? *trkX.chi2 : 0.f); } template <> -void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, GPUTPCGMTrackParam, GPUTPCGMPropagator>(GPUTrackingRefit::TrackParCovWithArgs& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) +GPUd() void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, GPUTPCGMTrackParam, GPUTPCGMPropagator>(GPUTrackingRefit::TrackParCovWithArgs& trk, const GPUTPCGMTrackParam& trkX, GPUTPCGMPropagator& prop, float* chi2) { convertTrack<TrackParCov, GPUTPCGMTrackParam, GPUTPCGMPropagator>(trk.trk, trkX, prop, chi2); if (trk.chi2) { @@ -214,8 +203,8 @@ void GPUTrackingRefit::convertTrack<GPUTrackingRefit::TrackParCovWithArgs, GPUTP } } -static const float* getPar(const GPUTPCGMTrackParam& trk) { return trk.GetPar(); } -static const float* getPar(const TrackParCov& trk) { return trk.getParams(); } +GPUd() static const float* getPar(const GPUTPCGMTrackParam& trk) { return trk.GetPar(); } +GPUd() static const float* getPar(const TrackParCov& trk) { return trk.getParams(); } template <class T, class S> GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) @@ -224,10 +213,10 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) typename refitTrackTypes<S>::propagator prop; S trk; float TrackParCovChi2 = 0.f; - convertTrack(trk, trkX, prop, &TrackParCovChi2); + convertTrack<S, T, typename refitTrackTypes<S>::propagator>(trk, trkX, prop, &TrackParCovChi2); int begin = 0, count; float tOffset; - if constexpr (std::is_same<T, GPUTPCGMMergedTrack>::value) { + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { count = trkX.NClusters(); if (trkX.Looper()) { int leg = mPtrackHits[trkX.FirstClusterRef() + trkX.NClusters() - 1].leg; @@ -239,10 +228,10 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) } } tOffset = trkX.GetParam().GetTZOffset(); - } else if constexpr (std::is_same<T, TrackTPC>::value) { + } else if constexpr (std::is_same_v<T, TrackTPC>) { count = trkX.getNClusters(); tOffset = trkX.getTime0(); - } else if constexpr (std::is_same<T, TrackParCovWithArgs>::value) { + } else if constexpr (std::is_same_v<T, TrackParCovWithArgs>) { count = trkX.clusRef.getEntries(); tOffset = trkX.time0; } else { @@ -261,7 +250,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) while (true) { if (!cl) { CADEBUG(ii = i); - if constexpr (std::is_same<T, GPUTPCGMMergedTrack>::value) { + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { const auto& hit = mPtrackHits[trkX.FirstClusterRef() + i]; cl = &mPclusterNative->clustersLinear[hit.num]; if (hit.state & (GPUTPCGMMergedTrackHit::flagReject | GPUTPCGMMergedTrackHit::flagNotFit)) { @@ -275,10 +264,10 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) row = hit.row; sector = hit.slice; nextState = mPclusterState[hit.num]; - } else if constexpr (std::is_same<T, TrackTPC>::value) { + } else if constexpr (std::is_same_v<T, TrackTPC>) { cl = &trkX.getCluster(mPtrackHitReferences, i, *mPclusterNative, sector, row); nextState = mPclusterState[cl - mPclusterNative->clustersLinear]; - } else if constexpr (std::is_same<T, TrackParCovWithArgs>::value) { + } else if constexpr (std::is_same_v<T, TrackParCovWithArgs>) { cl = &TrackTPC::getCluster(mPtrackHitReferences, i, *mPclusterNative, sector, row, trkX.clusRef); nextState = mPclusterState[cl - mPclusterNative->clustersLinear]; } else { @@ -326,7 +315,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) CADEBUG(printf("\tMerged Hit Row %3d: Cluster Alpha %8.3f %3d, X %8.3f - Y %8.3f, Z %8.3f\n", row, mPparam->Alpha(sector), (int)sector, x, y, z)); } - if constexpr (std::is_same<S, GPUTPCGMTrackParam>::value) { + if constexpr (std::is_same_v<S, GPUTPCGMTrackParam>) { if (prop.PropagateToXAlpha(x, mPparam->Alpha(currentSector), !outward)) { IgnoreErrors(trk.GetSinPhi()); return -2; @@ -340,12 +329,12 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) return -3; } CADEBUG(printf("\t%21sFit Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f), DzDs %5.2f %16s --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", prop.GetAlpha(), x, trk.Par()[0], trk.Par()[1], trk.Par()[4], prop.GetQPt0(), trk.Par()[2], prop.GetSinPhi0(), trk.Par()[3], "", sqrtf(trk.Cov()[0]), sqrtf(trk.Cov()[2]), sqrtf(trk.Cov()[5]), sqrtf(trk.Cov()[14]), trk.Cov()[10])); - } else if constexpr (std::is_same<S, TrackParCov>::value) { + } else if constexpr (std::is_same_v<S, TrackParCov>) { if (!trk.rotate(mPparam->Alpha(currentSector))) { IgnoreErrors(trk.getSnp()); return -1; } - if (!prop->PropagateToXBxByBz(trk, x, o2::constants::physics::MassPionCharged, GPUCA_MAX_SIN_PHI_LOW)) { + if (!prop->PropagateToXBxByBz(trk, x, GPUCA_MAX_SIN_PHI_LOW)) { IgnoreErrors(trk.getSnp()); return -2; } @@ -354,8 +343,8 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) TrackParCovChi2 = 0.f; } CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", trk.getAlpha(), x, trk.getParams()[0], trk.getParams()[1], trk.getParams()[4], trk.getParams()[4], trk.getParams()[2], trk.getParams()[2], trk.getParams()[0] - y, trk.getParams()[1] - z, sqrtf(trk.getCov()[0]), sqrtf(trk.getCov()[2]), sqrtf(trk.getCov()[5]), sqrtf(trk.getCov()[14]), trk.getCov()[10])); - std::array<float, 2> p = {y, z}; - std::array<float, 3> c = {0, 0, 0}; + gpu::gpustd::array<float, 2> p = {y, z}; + gpu::gpustd::array<float, 3> c = {0, 0, 0}; mPparam->GetClusterErrors2(currentRow, z, getPar(trk)[2], getPar(trk)[3], c[0], c[2]); mPparam->UpdateClusterError2ByState(clusterState, c[0], c[2]); TrackParCovChi2 += trk.getPredictedChi2(p, c); @@ -370,18 +359,20 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) resetCov = false; nFitted++; } - if constexpr (std::is_same<S, GPUTPCGMTrackParam>::value) { + if constexpr (std::is_same_v<S, GPUTPCGMTrackParam>) { float alpha = prop.GetAlpha(); trk.MoveToReference(prop, *mPparam, alpha); trk.NormalizeAlpha(alpha); prop.SetAlpha(alpha); - } else if constexpr (std::is_same<S, TrackParCov>::value) { - if (mPparam->rec.TrackReferenceX <= 500) { - if (prop->PropagateToXBxByBz(trk, mPparam->rec.TrackReferenceX)) { + } else if constexpr (std::is_same_v<S, TrackParCov>) { + static constexpr float kDeg2Rad = M_PI / 180.f; + static constexpr float kSectAngle = 2 * M_PI / 18.f; + if (mPparam->rec.tpc.trackReferenceX <= 500) { + if (prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX)) { if (CAMath::Abs(trk.getY()) > trk.getX() * CAMath::Tan(kSectAngle / 2.f)) { float newAlpha = trk.getAlpha() + floor(CAMath::ATan2(trk.getY(), trk.getX()) / kDeg2Rad / 20.f + 0.5f) * kSectAngle; GPUTPCGMTrackParam::NormalizeAlpha(newAlpha); - trk.rotate(newAlpha) && prop->PropagateToXBxByBz(trk, mPparam->rec.TrackReferenceX); + trk.rotate(newAlpha) && prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX); } } } @@ -389,7 +380,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) static_assert("Invalid template"); } - convertTrack(trkX, trk, prop, &TrackParCovChi2); + convertTrack<T, S, typename refitTrackTypes<S>::propagator>(trkX, trk, prop, &TrackParCovChi2); return nFitted; } @@ -400,20 +391,19 @@ template GPUd() int GPUTrackingRefit::RefitTrack<TrackTPC, GPUTPCGMTrackParam>(T template GPUd() int GPUTrackingRefit::RefitTrack<GPUTrackingRefit::TrackParCovWithArgs, TrackParCov>(GPUTrackingRefit::TrackParCovWithArgs& trk, bool outward, bool resetCov); template GPUd() int GPUTrackingRefit::RefitTrack<GPUTrackingRefit::TrackParCovWithArgs, GPUTPCGMTrackParam>(GPUTrackingRefit::TrackParCovWithArgs& trk, bool outward, bool resetCov); -void GPUTrackingRefit::SetPtrsFromGPUConstantMem(const GPUConstantMem* v) +#ifndef GPUCA_GPUCODE +void GPUTrackingRefit::SetPtrsFromGPUConstantMem(const GPUConstantMem* v, MEM_CONSTANT(GPUParam) * p) { mPclusterState = v->ioPtrs.mergedTrackHitStates; mPclusterNative = v->ioPtrs.clustersNative; mPtrackHits = v->ioPtrs.mergedTrackHits; mPfastTransform = v->calibObjects.fastTransform; - mPparam = &v->param; + mPmatLUT = v->calibObjects.matLUT; + mPparam = p ? p : &v->param; } void GPUTrackingRefit::SetPropagatorDefault() { -#ifndef GPUCA_STANDALONE - mPpropagator = Propagator::Instance(); -#else - throw std::runtime_error("unsupported"); -#endif + mPpropagator = mPparam->GetDefaultO2Propagator(false); } +#endif diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.h b/GPU/GPUTracking/Refit/GPUTrackingRefit.h index 7dbc710beeecc..9d0457d165fb0 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.h +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,6 @@ #include "GPUDef.h" #include "GPUProcessor.h" -#include <tuple> namespace o2::dataformats { @@ -31,7 +31,10 @@ using TrackParCov = TrackParametrizationWithError<float>; } // namespace o2::track namespace o2::base { -class Propagator; +template <typename> +class PropagatorImpl; +using Propagator = PropagatorImpl<float>; +class MatLayerCylSet; } // namespace o2::base namespace o2::tpc { @@ -55,7 +58,7 @@ class GPUTrackingRefit { public: void SetClusterStateArray(const unsigned char* v) { mPclusterState = v; } - void SetPtrsFromGPUConstantMem(const GPUConstantMem* v); + void SetPtrsFromGPUConstantMem(const GPUConstantMem* v, MEM_CONSTANT(GPUParam) * p = nullptr); void SetPropagator(const o2::base::Propagator* v) { mPpropagator = v; } void SetPropagatorDefault(); void SetClusterNative(const o2::tpc::ClusterNativeAccess* v) { mPclusterNative = v; } @@ -90,6 +93,7 @@ class GPUTrackingRefit private: const unsigned char* mPclusterState = nullptr; // Ptr to shared cluster state const o2::base::Propagator* mPpropagator = nullptr; // Ptr to propagator for TrackParCov track model + const o2::base::MatLayerCylSet* mPmatLUT = nullptr; // Ptr to material LUT const o2::tpc::ClusterNativeAccess* mPclusterNative = nullptr; // Ptr to cluster native access structure const GPUTPCGMMergedTrackHit* mPtrackHits = nullptr; // Ptr to hits for GPUTPCGMMergedTrack tracks const unsigned int* mPtrackHitReferences = nullptr; // Ptr to hits for TrackTPC tracks @@ -98,9 +102,9 @@ class GPUTrackingRefit template <class T, class S> GPUd() int RefitTrack(T& trk, bool outward, bool resetCov); template <class T, class S, class U> - void convertTrack(T& trk, const S& trkX, U& prop, float* chi2); + GPUd() void convertTrack(T& trk, const S& trkX, U& prop, float* chi2); template <class U> - void initProp(U& prop); + GPUd() void initProp(U& prop); }; class GPUTrackingRefitProcessor : public GPUTrackingRefit, public GPUProcessor @@ -111,6 +115,7 @@ class GPUTrackingRefitProcessor : public GPUTrackingRefit, public GPUProcessor void RegisterMemoryAllocation(); void SetMaxData(const GPUTrackingInOutPointers& io); #endif + GPUTPCGMMergedTrack* mPTracks = nullptr; }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.cxx new file mode 100644 index 0000000000000..dfbf52b7a354a --- /dev/null +++ b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTrackingRefitKernel.cxx +/// \author David Rohr + +#include "GPUTrackingRefitKernel.h" +#include "GPUTrackingRefit.h" + +using namespace GPUCA_NAMESPACE::gpu; + +template <int I> +GPUdii() void GPUTrackingRefitKernel::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) +{ + auto& refit = processors.trackingRefit; + for (unsigned int i = get_global_id(0); i < processors.ioPtrs.nMergedTracks; i += get_global_size(0)) { + if (refit.mPTracks[i].OK()) { + GPUTPCGMMergedTrack trk = refit.mPTracks[i]; + int retval; + if constexpr (I == mode0asGPU) { + retval = refit.RefitTrackAsGPU(trk, false, true); + } else if constexpr (I == mode1asTrackParCov) { + retval = refit.RefitTrackAsTrackParCov(trk, false, true); + } + if (retval > 0) { + refit.mPTracks[i] = trk; + } else { + refit.mPTracks[i].SetOK(false); + } + } + } +} +template GPUd() void GPUTrackingRefitKernel::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); +template GPUd() void GPUTrackingRefitKernel::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h new file mode 100644 index 0000000000000..e0d85ef85156c --- /dev/null +++ b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTrackingRefitKernel.h +/// \author David Rohr + +#ifndef GPUTRACKINGREFITKERNEL_H +#define GPUTRACKINGREFITKERNEL_H + +#include "GPUGeneralKernels.h" +#include "GPUConstantMem.h" + +namespace o2::gpu +{ + +class GPUTrackingRefitKernel : public GPUKernelTemplate +{ + public: + GPUhdi() CONSTEXPR static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCCompression; } + + enum K : int { + mode0asGPU = 0, + mode1asTrackParCov = 1, + }; + + template <int iKernel = defaultKernel> + GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors); +}; + +} // namespace o2::gpu + +#endif diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCBaseTrackParam.h b/GPU/GPUTracking/SliceTracker/GPUTPCBaseTrackParam.h index e4db3fe383268..28390eb50e3d0 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCBaseTrackParam.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCBaseTrackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCClusterData.h b/GPU/GPUTracking/SliceTracker/GPUTPCClusterData.h index a94d562a8ba05..c84e3de708346 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCClusterData.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCClusterData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCClusterErrorStat.h b/GPU/GPUTracking/SliceTracker/GPUTPCClusterErrorStat.h deleted file mode 100644 index 89d3af5ce4c7c..0000000000000 --- a/GPU/GPUTracking/SliceTracker/GPUTPCClusterErrorStat.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTPCClusterErrorStat.h -/// \author David Rohr - -#ifndef GPUTPCCLUSTERERRORSTAT_H -#define GPUTPCCLUSTERERRORSTAT_H - -//#define EXTRACT_RESIDUALS - -#if (defined(GPUCA_ALIROOT_LIB) || defined(GPUCA_BUILD_QA)) && !defined(GPUCA_GPUCODE) && defined(EXTRACT_RESIDUALS) -#include "cagpu/GPUTPCGPURootDump.h" - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -struct GPUTPCClusterErrorStat { - GPUTPCClusterErrorStat(int maxN) : fTupBuf(maxN) {} - - static GPUTPCGPURootDump<TNtuple> fTup; - static long long int fCount; - - std::vector<std::array<float, 10>> fTupBuf; - - void Fill(float x, float y, float z, float alpha, float trkX, float* fP, float* fC, int ihit, int iWay) - { - if (iWay == 1) { - fTupBuf[ihit] = {fP[0], fP[1], fP[2], fP[3], fP[4], fC[0], fC[2], fC[5], fC[9], fC[14]}; - } else if (iWay == 2) { - fTup.Fill(x, y, z, alpha, trkX, (fP[0] * fTupBuf[ihit][5] + fTupBuf[ihit][0] * fC[0]) / (fTupBuf[ihit][5] + fC[0]), (fP[1] * fTupBuf[ihit][6] + fTupBuf[ihit][1] * fC[2]) / (fTupBuf[ihit][6] + fC[2]), (fP[2] * fTupBuf[ihit][7] + fTupBuf[ihit][2] * fC[5]) / (fTupBuf[ihit][7] + fC[5]), - (fP[3] * fTupBuf[ihit][8] + fTupBuf[ihit][3] * fC[9]) / (fTupBuf[ihit][8] + fC[9]), (fP[4] * fTupBuf[ihit][9] + fTupBuf[ihit][4] * fC[14]) / (fTupBuf[ihit][9] + fC[14]), fC[0] * fTupBuf[ihit][5] / (fC[0] + fTupBuf[ihit][5]), - fC[2] * fTupBuf[ihit][6] / (fC[2] + fTupBuf[ihit][6]), fC[5] * fTupBuf[ihit][7] / (fC[5] + fTupBuf[ihit][7]), fC[9] * fTupBuf[ihit][8] / (fC[9] + fTupBuf[ihit][8]), fC[14] * fTupBuf[ihit][9] / (fC[14] + fTupBuf[ihit][9])); - if (++fCount == 2000000) { - GPUInfo("Reached %lld clusters in error stat, exiting", fCount); - fTup.~GPUTPCGPURootDump<TNtuple>(); - exit(0); - } - } - } -}; - -GPUTPCGPURootDump<TNtuple> GPUTPCClusterErrorStat::fTup("clusterres.root", "clusterres", "clusterres", "clX:clY:clZ:angle:trkX:trkY:trkZ:trkSinPhi:trkDzDs:trkQPt:trkSigmaY2:trkSigmaZ2:trkSigmaSinPhi2:trkSigmaDzDs2:trkSigmaQPt2"); -long long int GPUTPCClusterErrorStat::fCount = 0; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#else - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -struct GPUTPCClusterErrorStat { - GPUd() GPUTPCClusterErrorStat(int /*maxN*/) {} - GPUd() void Fill(float /*x*/, float /*y*/, float /*z*/, float /*alpha*/, float /*trkX*/, float* /*fP*/, float* /*fC*/, int /*ihit*/, int /*iWay*/) {} -}; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif - -#endif diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.cxx index c884f685a23b9..6990626fa0ecb 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCCreateSliceData::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCCreateSliceData::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { tracker.Data().InitFromClusterData(nBlocks, nThreads, iBlock, iThread, tracker.GetConstantMem(), tracker.ISlice(), s.tmp); } diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.h b/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.h index 13704097f3b41..adba1b95e4f28 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCCreateSliceData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCDef.h b/GPU/GPUTracking/SliceTracker/GPUTPCDef.h index 08bc40344b0c4..941150b05b428 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCDef.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCDefinitions.h b/GPU/GPUTracking/SliceTracker/GPUTPCDefinitions.h index 6275ccbe27120..7d9d607b9b88d 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCDefinitions.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCDefinitions.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h b/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h index 0eaa0516d6049..549dcdc95888c 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx index 0498d0a44c9b6..00090e80e78ae 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -23,7 +24,7 @@ using namespace GPUCA_NAMESPACE::gpu; #if !defined(__OPENCL__) || defined(__OPENCLCPP__) -GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, const GPUTPCTracker& GPUrestrict() sliceSource, int iTrack, int rowIndex, float angle, int direction) +GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, const GPUTPCTracker& GPUrestrict() sliceSource, int iTrack, int rowIndex, float angle, int direction) { /*for (int j = 0;j < Tracks()[j].NHits();j++) { @@ -50,7 +51,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker GPUTPCTrackLinearisation t0(tParam); do { rowIndex += direction; - if (!tParam.TransportToX(tracker.Row(rowIndex).X(), t0, tracker.Param().par.ConstBz, GPUCA_MAX_SIN_PHI)) { + if (!tParam.TransportToX(tracker.Row(rowIndex).X(), t0, tracker.Param().par.constBz, GPUCA_MAX_SIN_PHI)) { return (0); // Reuse t0 linearization until we are in the next sector } // GPUInfo("Transported X %f Y %f Z %f SinPhi %f DzDs %f QPt %f SignCosPhi %f (MaxY %f)", tParam.X(), tParam.Y(), tParam.Z(), tParam.SinPhi(), tParam.DzDs(), tParam.QPt(), tParam.SignCosPhi(), Row(rowIndex).MaxY()); @@ -86,7 +87,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker if (rowHit != CALINK_INVAL) { // GPUInfo("New track: entry %d, row %d, hitindex %d", i, rowIndex, mTrackletRowHits[rowIndex * tracker.CommonMemory()->nTracklets]); tracker.TrackHits()[hitId + i].Set(rowIndex, rowHit); - // if (i == 0) tParam.TransportToX(Row(rowIndex).X(), Param().par.ConstBz(), GPUCA_MAX_SIN_PHI); //Use transport with new linearisation, we have changed the track in between - NOT needed, fitting will always start at outer end of global track! + // if (i == 0) tParam.TransportToX(Row(rowIndex).X(), Param().par.constBz(), GPUCA_MAX_SIN_PHI); //Use transport with new linearisation, we have changed the track in between - NOT needed, fitting will always start at outer end of global track! i++; } rowIndex++; @@ -113,7 +114,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker return (nHits >= GPUCA_GLOBAL_TRACKING_MIN_HITS); } -GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThreads, int iBlock, int iThread, const GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, GPUTPCTracker& GPUrestrict() sliceTarget, bool right) +GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThreads, int iBlock, int iThread, const GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, GPUTPCTracker& GPUrestrict() sliceTarget, bool right) { for (int i = iBlock * nThreads + iThread; i < tracker.CommonMemory()->nLocalTracks; i += nThreads * nBlocks) { { @@ -128,11 +129,11 @@ GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThread } if (!right && Y < -row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_LOWER) { // GPUInfo("Track %d, lower row %d, left border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, -row.MaxY()); - PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.DAlpha, -1); + PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.dAlpha, -1); } if (right && Y > row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_LOWER) { // GPUInfo("Track %d, lower row %d, right border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, row.MaxY()); - PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.DAlpha, -1); + PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.dAlpha, -1); } } } @@ -149,11 +150,11 @@ GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThread } if (!right && Y < -row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_UPPER) { // GPUInfo("Track %d, upper row %d, left border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, -row.MaxY()); - PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.DAlpha, 1); + PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.dAlpha, 1); } if (right && Y > row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_UPPER) { // GPUInfo("Track %d, upper row %d, right border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, row.MaxY()); - PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.DAlpha, 1); + PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.dAlpha, 1); } } } @@ -161,7 +162,7 @@ GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThread } template <> -GPUdii() void GPUTPCGlobalTracking::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCGlobalTracking::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, processorType& GPUrestrict() tracker) { CA_SHARED_CACHE(&smem.mRows[0], tracker.SliceDataRows(), GPUCA_ROW_COUNT * sizeof(MEM_PLAIN(GPUTPCRow))); GPUbarrier(); @@ -204,7 +205,7 @@ GPUd() void GPUTPCGlobalTracking::GlobalTrackingSliceLeftRight(unsigned int iSli #endif // !__OPENCL__ || __OPENCLCPP__ template <> -GPUdii() void GPUTPCGlobalTrackingCopyNumbers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, processorType& GPUrestrict() tracker, int n) +GPUdii() void GPUTPCGlobalTrackingCopyNumbers::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, processorType& GPUrestrict() tracker, int n) { for (int i = get_global_id(0); i < n; i += get_global_size(0)) { GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() trk = (&tracker)[i]; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.h b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.h index d981be3ba5423..510bbd884339e 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,8 +46,8 @@ class GPUTPCGlobalTracking : public GPUKernelTemplate GPUd() static void GlobalTrackingSliceLeftRight(unsigned int iSlice, unsigned int& left, unsigned int& right); private: - GPUd() static int PerformGlobalTrackingRun(GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, const GPUTPCTracker& sliceSource, int iTrack, int rowIndex, float angle, int direction); - GPUd() static void PerformGlobalTracking(int nBlocks, int nThreads, int iBlock, int iThread, const GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() smem, GPUTPCTracker& sliceTarget, bool right); + GPUd() static int PerformGlobalTrackingRun(GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, const GPUTPCTracker& sliceSource, int iTrack, int rowIndex, float angle, int direction); + GPUd() static void PerformGlobalTracking(int nBlocks, int nThreads, int iBlock, int iThread, const GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, GPUTPCTracker& sliceTarget, bool right); }; #endif diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx index 310f77dcb5230..67055b85dec04 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.h b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.h index fe23185a39bf6..06b248c92cf06 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCHit.h b/GPU/GPUTracking/SliceTracker/GPUTPCHit.h index 376b34c0a8fd7..0fe86f8ef21a3 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCHit.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCHit.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCHitId.h b/GPU/GPUTracking/SliceTracker/GPUTPCHitId.h index 6e4c54b682b21..7d1c97650385b 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCHitId.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCHitId.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCMCInfo.h b/GPU/GPUTracking/SliceTracker/GPUTPCMCInfo.h index 810ce33f67422..6b20f8a680940 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCMCInfo.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCMCInfo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,13 @@ struct GPUTPCMCInfo { float pY; float pZ; float genRadius; +#ifdef GPUCA_TPC_GEOMETRY_O2 + float t0; +#endif +}; +struct GPUTPCMCInfoCol { + unsigned int first; + unsigned int num; }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.cxx index 79a53293d6f97..83a9225afd86d 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.h b/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.h index 1e6a5743ba354..b860714d5ca18 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCMCPoint.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.cxx index dfbecc149a034..2a5736ec6f7cc 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.h b/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.h index f4a00fc6498f1..7cd39b242de40 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCMCTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.cxx index 35a60ef7f0696..3c03f894d6e12 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCNeighboursCleaner::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCNeighboursCleaner::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { // * // * kill link to the neighbour if the neighbour is not pointed to the cluster diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.h b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.h index 105da4917cf8b..5f86ad2788df2 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursCleaner.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.cxx index 5ff7915bb2e3d..b3f942eb3d196 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCNeighboursFinder::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCNeighboursFinder::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { //* find neighbours @@ -109,8 +110,8 @@ GPUdii() void GPUTPCNeighboursFinder::Thread<0>(int /*nBlocks*/, int nThreads, i const float stepYDn = rowDn.mHstepY; const float stepZDn = rowDn.mHstepZ; - const float kAngularMultiplier = tracker.mConstantMem->param.rec.SearchWindowDZDR; - const float kAreaSizeY = tracker.mConstantMem->param.rec.NeighboursSearchArea; + const float kAngularMultiplier = tracker.mConstantMem->param.rec.tpc.searchWindowDZDR; + const float kAreaSizeY = tracker.mConstantMem->param.rec.tpc.neighboursSearchArea; const float kAreaSizeZUp = kAngularMultiplier != 0.f ? (s.mUpDx * kAngularMultiplier) : kAreaSizeY; const float kAreaSizeZDn = kAngularMultiplier != 0.f ? (-s.mDnDx * kAngularMultiplier) : kAreaSizeY; const float kAreaSlopeZUp = kAngularMultiplier != 0.f ? 1.f : s.mUpTx; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h index 7b0d2a41b03d8..8017abb1483a1 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,14 +36,14 @@ class GPUTPCNeighboursFinder : public GPUKernelTemplate public: MEM_CLASS_PRE() struct GPUSharedMemory { - int mNHits; // n hits - float mUpDx; // x distance to the next row - float mDnDx; // x distance to the previous row - float mUpTx; // normalized x distance to the next row - float mDnTx; // normalized x distance to the previous row - int mIRow; // row number - int mIRowUp; // next row number - int mIRowDn; // previous row number + int mNHits; // n hits + float mUpDx; // x distance to the next row + float mDnDx; // x distance to the previous row + float mUpTx; // normalized x distance to the next row + float mDnTx; // normalized x distance to the previous row + int mIRow; // row number + int mIRowUp; // next row number + int mIRowDn; // previous row number #if GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP > 0 float mA1[GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP][GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCNeighboursFinder)]; float mA2[GPUCA_NEIGHBOURS_FINDER_MAX_NNEIGHUP][GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCNeighboursFinder)]; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCRow.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCRow.cxx index 71ae58aa3fd62..8ee5e2cbddd62 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCRow.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCRow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCRow.h b/GPU/GPUTracking/SliceTracker/GPUTPCRow.h index 8303248168ffd..369ceabf4ee96 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCRow.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCRow.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,9 +61,9 @@ class GPUTPCRow friend class GPUTPCNeighboursFinder; friend class GPUTPCStartHitsFinder; - int mNHits; // number of hits - float mX; // X coordinate of the row - float mMaxY; // maximal Y coordinate of the row + int mNHits; // number of hits + float mX; // X coordinate of the row + float mMaxY; // maximal Y coordinate of the row MEM_LG(GPUTPCGrid) mGrid; // grid of hits diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx index 22bb02f75a61f..1c98977282e60 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,7 +40,7 @@ void GPUTPCSliceData::InitializeRows(const MEM_CONSTANT(GPUParam) & p) } for (int i = 0; i < GPUCA_ROW_COUNT; ++i) { mRows[i].mX = p.tpcGeometry.Row2X(i); - mRows[i].mMaxY = CAMath::Tan(p.par.DAlpha / 2.) * mRows[i].mX; + mRows[i].mMaxY = CAMath::Tan(p.par.dAlpha / 2.) * mRows[i].mX; } } @@ -310,7 +311,7 @@ GPUdii() int GPUTPCSliceData::InitFromClusterData(int nBlocks, int nThreads, int GPUbarrier(); const GPUTPCGrid& grid = row.mGrid; const int numberOfBins = grid.N(); - CONSTEXPR int maxBins = sizeof(calink) < 4 ? (1 << (sizeof(calink) * 8)) : 0x7FFFFFFF; // NOLINT: false warning + CONSTEXPR int maxBins = sizeof(calink) < 4 ? (int)(1ul << (sizeof(calink) * 8)) : 0x7FFFFFFF; // NOLINT: false warning if (sizeof(calink) < 4 && numberOfBins >= maxBins) { if (iThread == 0) { mem->errorCodes.raiseError(GPUErrors::ERROR_SLICEDATA_BIN_OVERFLOW, rowIndex, numberOfBins, maxBins); @@ -393,7 +394,7 @@ GPUdii() int GPUTPCSliceData::InitFromClusterData(int nBlocks, int nThreads, int if (iThread == 0) { const float maxAbsZ = CAMath::Max(CAMath::Abs(tmpMinMax[2]), CAMath::Abs(tmpMinMax[3])); - if (maxAbsZ > 300 && !mem->param.par.ContinuousTracking) { + if (maxAbsZ > 300 && !mem->param.par.continuousTracking) { mem->errorCodes.raiseError(GPUErrors::ERROR_SLICEDATA_Z_OVERFLOW, (unsigned int)maxAbsZ); return 1; } diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.h b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.h index b9ad19dcb34e7..6562d0b55e4ad 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ #include "GPUTPCRow.h" #include "GPUCommonMath.h" #include "GPUParam.h" -#include "GPUMemoryResource.h" +#include "GPUProcessor.h" namespace GPUCA_NAMESPACE { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutCluster.h b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutCluster.h index 30bfae193b63f..a1cda9e491c6e 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutCluster.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutCluster.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.cxx index 02fbb2c215609..d54c3140083e5 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,18 +31,19 @@ void GPUTPCSliceOutput::Allocate(GPUTPCSliceOutput*& ptrOutput, int nTracks, int // Allocate All memory needed for slice output const size_t memsize = EstimateSize(nTracks, nTrackHits); - if (outputControl && outputControl->OutputType != GPUOutputControl::AllocateInternal) { + if (outputControl && outputControl->useExternal()) { static std::atomic_flag lock = ATOMIC_FLAG_INIT; while (lock.test_and_set(std::memory_order_acquire)) { } - if (outputControl->OutputMaxSize - ((char*)outputControl->OutputPtr - (char*)outputControl->OutputBase) < memsize) { - outputControl->EndOfSpace = 1; + outputControl->checkCurrent(); + if (outputControl->size - ((char*)outputControl->ptrCurrent - (char*)outputControl->ptrBase) < memsize) { + outputControl->size = 1; ptrOutput = nullptr; lock.clear(std::memory_order_release); return; } - ptrOutput = reinterpret_cast<GPUTPCSliceOutput*>(outputControl->OutputPtr); - outputControl->OutputPtr = (char*)outputControl->OutputPtr + memsize; + ptrOutput = reinterpret_cast<GPUTPCSliceOutput*>(outputControl->ptrCurrent); + outputControl->ptrCurrent = (char*)outputControl->ptrCurrent + memsize; lock.clear(std::memory_order_release); } else { if (internalMemory) { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.h b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.h index 1124902cc7d3e..7ade263cf208f 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.cxx index 92e64b6493de6..a5dea8884a4a4 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCStartHitsFinder::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCStartHitsFinder::Thread<0>(int /*nBlocks*/, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { // find start hits for tracklets if (iThread == 0) { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.h b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.h index 2e72a5b92781f..e93597376a6f2 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.cxx index c65032872546c..cfd3f66d536c4 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCStartHitsSorter::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCStartHitsSorter::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { // Sorts the Start Hits by Row Index if (iThread == 0) { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.h b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.h index 3e84adf100360..69ed979261a31 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCStartHitsSorter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrack.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrack.cxx index 39dc2d09b6d7a..573c1f6f9c8ba 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrack.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrack.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrack.h index 9b416edab332b..0e13c46f3b19f 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrack.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrack.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackLinearisation.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrackLinearisation.h index 4f94100797446..5b94992b0d708 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackLinearisation.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackLinearisation.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.cxx index 603fd0f8a3cf0..10d366dc2bcb4 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.h index 9010b54ed8279..bab996b175d2e 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.cxx index 5db4985b15cc4..741f22daaac01 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -66,7 +67,7 @@ void GPUTPCTracker::InitializeProcessor() bool GPUTPCTracker::SliceDataOnGPU() { - return (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion) && mRec->GetParam().rec.mergerReadFromTrackerDirectly && (mRec->GetConstantMem().ioPtrs.clustersNative || mRec->GetConstantMem().ioPtrs.tpcZS || mRec->GetConstantMem().ioPtrs.tpcPackedDigits); + return (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion) && mRec->GetParam().rec.tpc.mergerReadFromTrackerDirectly && (mRec->GetConstantMem().ioPtrs.clustersNative || mRec->GetConstantMem().ioPtrs.tpcZS || mRec->GetConstantMem().ioPtrs.tpcPackedDigits); } void* GPUTPCTracker::SetPointersDataInput(void* mem) { return mData.SetPointersInput(mem, mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging, SliceDataOnGPU()); } @@ -106,7 +107,7 @@ void* GPUTPCTracker::SetPointersCommon(void* mem) void GPUTPCTracker::RegisterMemoryAllocation() { AllocateAndInitializeLate(); - bool reuseCondition = !mRec->GetProcessingSettings().keepDisplayMemory && mRec->GetProcessingSettings().trackletSelectorInPipeline && ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) || mRec->GetProcessingSettings().ompKernels || mRec->GetProcessingSettings().ompThreads == 1); + bool reuseCondition = !mRec->GetProcessingSettings().keepDisplayMemory && mRec->GetProcessingSettings().trackletSelectorInPipeline && ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSliceTracking) || mRec->GetProcessingSettings().ompKernels == 1 || mRec->GetProcessingSettings().ompThreads == 1); GPUMemoryReuse reLinks{reuseCondition, GPUMemoryReuse::REUSE_1TO1, GPUMemoryReuse::TrackerDataLinks, (unsigned short)(mISlice % mRec->GetProcessingSettings().nStreams)}; mMemoryResLinks = mRec->RegisterMemoryAllocation(this, &GPUTPCTracker::SetPointersDataLinks, GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_STACK, "TPCSliceLinks", reLinks); mMemoryResSliceScratch = mRec->RegisterMemoryAllocation(this, &GPUTPCTracker::SetPointersDataScratch, GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_STACK | GPUMemoryResource::MEMORY_CUSTOM, "TPCSliceScratch"); @@ -177,9 +178,11 @@ GPUh() int GPUTPCTracker::CheckEmptySlice() // Check if the Slice is empty, if so set the output apropriate and tell the reconstuct procesdure to terminate if (NHitsTotal() < 1) { mCommonMem->nTracks = mCommonMem->nTrackHits = 0; - WriteOutputPrepare(); - mOutput->SetNTracks(0); - mOutput->SetNTrackClusters(0); + if (mOutput) { + WriteOutputPrepare(); + mOutput->SetNTracks(0); + mOutput->SetNTrackClusters(0); + } return 1; } return 0; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h index 6f70b47a96464..b4618f7ad1b28 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -63,13 +64,13 @@ class GPUTPCTracker : public GPUProcessor void WriteOutput(); // Debugging Stuff - void DumpSliceData(std::ostream& out); // Dump Input Slice Data - void DumpLinks(std::ostream& out); // Dump all links to file (for comparison after NeighboursFinder/Cleaner) - void DumpStartHits(std::ostream& out); // Same for Start Hits - void DumpHitWeights(std::ostream& out); //.... - void DumpTrackHits(std::ostream& out); // Same for Track Hits - void DumpTrackletHits(std::ostream& out); // Same for Track Hits - void DumpOutput(std::ostream& out); // Similar for output + void DumpSliceData(std::ostream& out); // Dump Input Slice Data + void DumpLinks(std::ostream& out, int phase); // Dump all links to file (for comparison after NeighboursFinder/Cleaner) + void DumpStartHits(std::ostream& out); // Same for Start Hits + void DumpHitWeights(std::ostream& out); //.... + void DumpTrackHits(std::ostream& out); // Same for Track Hits + void DumpTrackletHits(std::ostream& out); // Same for Track Hits + void DumpOutput(std::ostream& out); // Similar for output #endif struct StructGPUParameters { @@ -93,7 +94,6 @@ class GPUTPCTracker : public GPUProcessor StructGPUParameters gpuParameters; // GPU parameters }; - #if !defined(__OPENCL__) || defined(__OPENCLCPP__) GPUhdi() GPUglobalref() const GPUTPCClusterData* ClusterData() const { @@ -111,19 +111,19 @@ class GPUTPCTracker : public GPUProcessor GPUdi() static void GetErrors2Seeding(const MEM_CONSTANT(GPUParam) & param, int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float& ErrY2, float& ErrZ2) { // param.GetClusterErrors2( iRow, param.GetContinuousTracking() != 0. ? 125. : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2 ); - param.GetClusterRMS2(iRow, param.par.ContinuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2); + param.GetClusterRMS2(iRow, param.par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2); } MEM_CLASS_PRE2() GPUdi() void GetErrors2Seeding(int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float& ErrY2, float& ErrZ2) const { // Param().GetClusterErrors2( iRow, Param().GetContinuousTracking() != 0. ? 125. : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2 ); - Param().GetClusterRMS2(iRow, Param().par.ContinuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2); + Param().GetClusterRMS2(iRow, Param().par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), ErrY2, ErrZ2); } GPUdi() void GetErrors2Seeding(int iRow, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const { // Param().GetClusterErrors2( iRow, Param().GetContinuousTracking() != 0. ? 125. : z, sinPhi, DzDs, ErrY2, ErrZ2 ); - Param().GetClusterRMS2(iRow, Param().par.ContinuousTracking != 0.f ? 125.f : z, sinPhi, DzDs, ErrY2, ErrZ2); + Param().GetClusterRMS2(iRow, Param().par.continuousTracking != 0.f ? 125.f : z, sinPhi, DzDs, ErrY2, ErrZ2); } void SetupCommonMemory(); diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx index 58039886112ce..edbfc5263826e 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -369,28 +370,28 @@ int GPUTPCTrackerComponent::ConfigureSlices() { // Initialize the tracker slices GPUSettingsRec rec; - GPUSettingsEvent ev; + GPUSettingsGRP grp; GPUSettingsProcessing devProc; - ev.solenoidBz = fSolenoidBz; - ev.continuousMaxTimeBin = 0; // triggered events + grp.solenoidBz = fSolenoidBz; + grp.continuousMaxTimeBin = 0; // triggered events if (mNeighboursSearchArea > 0) { - rec.NeighboursSearchArea = mNeighboursSearchArea; + rec.tpc.neighboursSearchArea = mNeighboursSearchArea; } if (fClusterErrorCorrectionY > 1.e-4) { - rec.ClusterError2CorrectionY = fClusterErrorCorrectionY * fClusterErrorCorrectionY; + rec.tpc.clusterError2CorrectionY = fClusterErrorCorrectionY * fClusterErrorCorrectionY; } if (fClusterErrorCorrectionZ > 1.e-4) { - rec.ClusterError2CorrectionZ = fClusterErrorCorrectionZ * fClusterErrorCorrectionZ; + rec.tpc.clusterError2CorrectionZ = fClusterErrorCorrectionZ * fClusterErrorCorrectionZ; } - rec.MinNTrackClusters = fMinNTrackClusters; + rec.tpc.minNTrackClusters = fMinNTrackClusters; rec.SetMinTrackPt(fMinTrackPt); - rec.SearchWindowDZDR = fSearchWindowDZDR; + rec.tpc.searchWindowDZDR = fSearchWindowDZDR; devProc.nDeviceHelperThreads = fGPUHelperThreads; - rec.GlobalTracking = fGlobalTracking; + rec.tpc.globalTracking = fGlobalTracking; devProc.stuckProtection = fGPUStuckProtection; - rec.NonConsecutiveIDs = true; - rec.mergerReadFromTrackerDirectly = false; + rec.nonConsecutiveIDs = true; + rec.tpc.mergerReadFromTrackerDirectly = false; devProc.ompThreads = 1; devProc.ompKernels = false; @@ -399,7 +400,7 @@ int GPUTPCTrackerComponent::ConfigureSlices() steps.inputs.set(GPUDataTypes::InOutType::TPCClusters); steps.outputs.set(GPUDataTypes::InOutType::TPCSectorTracks); - fRec->SetSettings(&ev, &rec, &devProc, &steps); + fRec->SetSettings(&grp, &rec, &devProc, &steps); fChain->LoadClusterErrors(); return fRec->Init(); } @@ -670,7 +671,7 @@ void* GPUTPCTrackerComponent::TrackerDoEvent(void* par) int ret = 0; size = 0; - if (fRec->OutputControl().EndOfSpace) { + if (fRec->OutputControl().size == 1) { HLTWarning("Output buffer size exceeded buffer size %d, tracks are not stored", maxBufferSize); ret = -ENOSPC; } else { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.h index 61f42957b0fac..b9dc408f3780d 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerDump.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerDump.cxx index 1b9f6a0af18f7..c5d50779dfd49 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerDump.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerDump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,7 +29,7 @@ using namespace GPUCA_NAMESPACE::gpu; void GPUTPCTracker::DumpOutput(std::ostream& out) { if (Param().par.earlyTpcTransform) { - out << "Slice " << mISlice << "\n"; + out << "\nSlice " << mISlice << "\n"; const GPUTPCTrack* track = (Output())->GetFirstTrack(); for (unsigned int j = 0; j < (Output())->NTracks(); j++) { out << "Track " << j << " (" << track->NHits() << "): "; @@ -44,7 +45,7 @@ void GPUTPCTracker::DumpOutput(std::ostream& out) void GPUTPCTracker::DumpSliceData(std::ostream& out) { // Dump Slice Input Data to File - out << "Slice Data (Slice" << mISlice << "):" << std::endl; + out << "\nSlice Data (Slice" << mISlice << "):" << std::endl; for (int i = 0; i < GPUCA_ROW_COUNT; i++) { if (Row(i).NHits() == 0) { continue; @@ -60,10 +61,10 @@ void GPUTPCTracker::DumpSliceData(std::ostream& out) } } -void GPUTPCTracker::DumpLinks(std::ostream& out) +void GPUTPCTracker::DumpLinks(std::ostream& out, int phase) { // Dump Links (after Neighbours Finder / Cleaner) to file - out << "Hit Links(Slice" << mISlice << "):" << std::endl; + out << "\nHit Links (Phase " << phase << ", Slice" << mISlice << "):" << std::endl; for (int i = 0; i < GPUCA_ROW_COUNT; i++) { if (Row(i).NHits() == 0) { continue; @@ -82,7 +83,7 @@ void GPUTPCTracker::DumpLinks(std::ostream& out) void GPUTPCTracker::DumpHitWeights(std::ostream& out) { // dump hit weights to file - out << "Hit Weights(Slice" << mISlice << "):" << std::endl; + out << "\nHit Weights(Slice" << mISlice << "):" << std::endl; for (int i = 0; i < GPUCA_ROW_COUNT; i++) { if (Row(i).NHits() == 0) { continue; @@ -113,7 +114,7 @@ int GPUTPCTracker::StarthitSortComparison(const void* a, const void* b) void GPUTPCTracker::DumpStartHits(std::ostream& out) { // sort start hits and dump to file - out << "Start Hits: (Slice" << mISlice << ") (" << *NStartHits() << ")" << std::endl; + out << "\nStart Hits: (Slice" << mISlice << ") (" << *NStartHits() << ")" << std::endl; if (mRec->GetProcessingSettings().comparableDebutOutput) { qsort(TrackletStartHits(), *NStartHits(), sizeof(GPUTPCHitId), StarthitSortComparison); } @@ -126,7 +127,7 @@ void GPUTPCTracker::DumpStartHits(std::ostream& out) void GPUTPCTracker::DumpTrackHits(std::ostream& out) { // dump tracks to file - out << "Tracks: (Slice" << mISlice << ") (" << *NTracks() << ")" << std::endl; + out << "\nTracks: (Slice" << mISlice << ") (" << *NTracks() << ")" << std::endl; for (int k = 0; k < GPUCA_ROW_COUNT; k++) { for (int l = 0; l < Row(k).NHits(); l++) { for (unsigned int j = 0; j < *NTracks(); j++) { @@ -154,7 +155,7 @@ void GPUTPCTracker::DumpTrackletHits(std::ostream& out) if (nTracklets < 0) { nTracklets = 0; } - out << "Tracklets: (Slice" << mISlice << ") (" << nTracklets << ")" << std::endl; + out << "\nTracklets: (Slice" << mISlice << ") (" << nTracklets << ")" << std::endl; std::vector<int> Ids(nTracklets); std::iota(Ids.begin(), Ids.end(), 0); if (mRec->GetProcessingSettings().comparableDebutOutput) { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTracklet.h b/GPU/GPUTracking/SliceTracker/GPUTPCTracklet.h index bde7f4b286089..7ba895324cfbf 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTracklet.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTracklet.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx index 42590e8f64849..a7d41c83e5ffa 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,10 +55,10 @@ GPUd() bool GPUTPCTrackletConstructor::CheckCov(MEM_LG2(GPUTPCTrackParam) & GPUr } MEM_CLASS_PRE23() -GPUd() void GPUTPCTrackletConstructor::StoreTracklet(int /*nBlocks*/, int /*nThreads*/, int /*iBlock*/, int /*iThread*/, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, GPUTPCThreadMemory& GPUrestrict() r, GPUconstantref() MEM_LG2(GPUTPCTracker) & GPUrestrict() tracker, MEM_LG3(GPUTPCTrackParam) & GPUrestrict() tParam, calink* rowHits) +GPUd() void GPUTPCTrackletConstructor::StoreTracklet(int /*nBlocks*/, int /*nThreads*/, int /*iBlock*/, int /*iThread*/, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, GPUTPCThreadMemory& GPUrestrict() r, GPUconstantref() MEM_LG2(GPUTPCTracker) & GPUrestrict() tracker, MEM_LG3(GPUTPCTrackParam) & GPUrestrict() tParam, calink* rowHits) { // reconstruction of tracklets, tracklet store step - if (r.mNHits == 0 || (r.mNHits < GPUCA_TRACKLET_SELECTOR_MIN_HITS(tParam.QPt()) || !CheckCov(tParam) || CAMath::Abs(tParam.GetQPt()) > tracker.Param().rec.MaxTrackQPt)) { + if (r.mNHits == 0 || (r.mNHits < GPUCA_TRACKLET_SELECTOR_MIN_HITS(tParam.QPt()) || !CheckCov(tParam) || CAMath::Abs(tParam.GetQPt()) > tracker.Param().rec.maxTrackQPt)) { return; } @@ -107,7 +108,7 @@ GPUd() void GPUTPCTrackletConstructor::StoreTracklet(int /*nBlocks*/, int /*nThr } MEM_CLASS_PRE2_TEMPLATE(class T) -GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int /*nThreads*/, int /*iBlock*/, int /*iThread*/, GPUsharedref() T& GPUrestrict() s, GPUTPCThreadMemory& GPUrestrict() r, GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, MEM_LG2(GPUTPCTrackParam) & GPUrestrict() tParam, int iRow, calink& rowHit) +GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int /*nThreads*/, int /*iBlock*/, int /*iThread*/, GPUsharedref() T& s, GPUTPCThreadMemory& GPUrestrict() r, GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, MEM_LG2(GPUTPCTrackParam) & GPUrestrict() tParam, int iRow, calink& rowHit) { // reconstruction of tracklets, tracklets update step CA_MAKE_SHARED_REF(GPUTPCRow, row, tracker.Row(iRow), s.mRows[iRow]); @@ -140,7 +141,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int tParam.SetX(x); tParam.SetY(y); r.mLastY = y; - if (tracker.Param().par.ContinuousTracking) { + if (tracker.Param().par.continuousTracking) { tParam.SetZ(0.f); r.mLastZ = 0.f; tParam.SetZOffset(z); @@ -186,7 +187,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int } CADEBUG( printf("%14s: FIT TRACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); - if (!tParam.TransportToX(x, sinPhi, cosPhi, tracker.Param().par.ConstBz, GPUCA_MAX_SIN_PHI)) { + if (!tParam.TransportToX(x, sinPhi, cosPhi, tracker.Param().par.constBz, GPUCA_MAX_SIN_PHI)) { rowHit = CALINK_INVAL; break; } @@ -195,7 +196,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int tracker.GetErrors2Seeding(iRow, tParam.GetZ(), sinPhi, tParam.GetDzDs(), err2Y, err2Z); if (r.mNHits >= 10) { - const float kFactor = tracker.Param().rec.HitPickUpFactor * tracker.Param().rec.HitPickUpFactor * 3.5f * 3.5f; + const float kFactor = tracker.Param().rec.tpc.hitPickUpFactor * tracker.Param().rec.tpc.hitPickUpFactor * 3.5f * 3.5f; float sy2 = kFactor * (tParam.Err2Y() + err2Y); float sz2 = kFactor * (tParam.Err2Z() + err2Z); if (sy2 > 2.f) { @@ -257,7 +258,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int float err2Y, err2Z; CADEBUG( printf("%14s: SEA TRACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); - if (!tParam.TransportToX(x, tParam.SinPhi(), tParam.GetCosPhi(), tracker.Param().par.ConstBz, GPUCA_MAX_SIN_PHI_LOW)) { + if (!tParam.TransportToX(x, tParam.SinPhi(), tParam.GetCosPhi(), tracker.Param().par.constBz, GPUCA_MAX_SIN_PHI_LOW)) { r.mGo = 0; rowHit = CALINK_INVAL; break; @@ -279,7 +280,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int { // search for the closest hit tracker.GetErrors2Seeding(iRow, *((MEM_LG2(GPUTPCTrackParam)*)&tParam), err2Y, err2Z); - const float kFactor = tracker.Param().rec.HitPickUpFactor * tracker.Param().rec.HitPickUpFactor * 3.5f * 3.5f; + const float kFactor = tracker.Param().rec.tpc.hitPickUpFactor * tracker.Param().rec.tpc.hitPickUpFactor * 3.5f * 3.5f; float sy2 = kFactor * (tParam.Err2Y() + err2Y); float sz2 = kFactor * (tParam.Err2Z() + err2Z); if (sy2 > 2.f) { @@ -353,7 +354,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int } } -GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, GPUsharedref() GPUTPCTrackletConstructor::MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, GPUTPCThreadMemory& GPUrestrict() r) +GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, GPUsharedref() GPUTPCTrackletConstructor::MEM_LOCAL(GPUSharedMemory) & s, GPUTPCThreadMemory& GPUrestrict() r) { int iRow = 0, iRowEnd = GPUCA_ROW_COUNT; MEM_PLAIN(GPUTPCTrackParam) @@ -391,7 +392,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLO StoreTracklet(0, 0, 0, 0, s, r, tracker, tParam, rowHits); } else { r.mNMissed = 0; - if ((r.mGo = (tParam.TransportToX(tracker.Row(r.mEndRow).X(), tracker.Param().par.ConstBz, GPUCA_MAX_SIN_PHI) && tParam.Filter(r.mLastY, r.mLastZ, tParam.Err2Y() * 0.5f, tParam.Err2Z() * 0.5f, GPUCA_MAX_SIN_PHI_LOW, true)))) { + if ((r.mGo = (tParam.TransportToX(tracker.Row(r.mEndRow).X(), tracker.Param().par.constBz, GPUCA_MAX_SIN_PHI) && tParam.Filter(r.mLastY, r.mLastZ, tParam.Err2Y() * 0.5f, tParam.Err2Z() * 0.5f, GPUCA_MAX_SIN_PHI_LOW, true)))) { CADEBUG( printf("%14s: SEA BACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); float err2Y, err2Z; @@ -414,7 +415,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLO } template <> -GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::singleSlice>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() sMem, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::singleSlice>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & sMem, processorType& GPUrestrict() tracker) { if (get_local_id(0) == 0) { sMem.mNStartHits = *tracker.NStartHits(); @@ -430,7 +431,7 @@ GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::singl } template <> -GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::allSlices>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() sMem, processorType& GPUrestrict() tracker0) +GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::allSlices>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & sMem, processorType& GPUrestrict() tracker0) { GPUconstantref() MEM_GLOBAL(GPUTPCTracker) * GPUrestrict() pTracker = &tracker0; #ifdef GPUCA_GPUCODE @@ -480,7 +481,7 @@ GPUdii() void GPUTPCTrackletConstructor::Thread<GPUTPCTrackletConstructor::allSl #ifdef GPUCA_GPUCODE -GPUd() int GPUTPCTrackletConstructor::FetchTracklet(GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() sMem) +GPUd() int GPUTPCTrackletConstructor::FetchTracklet(GPUconstantref() MEM_GLOBAL(GPUTPCTracker) & GPUrestrict() tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & sMem) { const unsigned int nStartHit = *tracker.NStartHits(); GPUbarrier(); diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.h index e083f6ae879fd..06b5a82e7ac57 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.cxx index 8c4d3a56687ca..cfc67e5d391b0 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCTrackletSelector::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & GPUrestrict() s, processorType& GPUrestrict() tracker) +GPUdii() void GPUTPCTrackletSelector::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & s, processorType& GPUrestrict() tracker) { // select best tracklets and kill clones @@ -57,7 +58,7 @@ GPUdii() void GPUTPCTrackletSelector::Thread<0>(int nBlocks, int nThreads, int i int gap = 0; int nShared = 0; int nHits = 0; - const int minHits = tracker.Param().rec.MinNTrackClusters == -1 ? GPUCA_TRACKLET_SELECTOR_MIN_HITS(tracklet.Param().QPt()) : tracker.Param().rec.MinNTrackClusters; + const int minHits = tracker.Param().rec.tpc.minNTrackClusters == -1 ? GPUCA_TRACKLET_SELECTOR_MIN_HITS(tracklet.Param().QPt()) : tracker.Param().rec.tpc.minNTrackClusters; GPUCA_UNROLL(, U(1)) for (irow = firstRow; irow <= lastRow && lastRow - irow + nHits >= minHits; irow++) { diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.h b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.h index f8909508b524e..70733ace6408c 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,6 +39,7 @@ class GPUTPCTrackletSelector : public GPUKernelTemplate int mItr0; // index of the first track in the block int mNThreadsTotal; // total n threads int mNTracklets; // n of tracklets + int mReserved; // for alignment reasons #if GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE != 0 GPUTPCHitId mHits[GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE][GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCTrackletSelector)]; #endif // GPUCA_TRACKLET_SELECTOR_HITS_REG_SIZE != 0 diff --git a/GPU/GPUTracking/Standalone/Base b/GPU/GPUTracking/Standalone/Base deleted file mode 120000 index e87748e1ef7fc..0000000000000 --- a/GPU/GPUTracking/Standalone/Base +++ /dev/null @@ -1 +0,0 @@ -../Base \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/CMakeLists.txt b/GPU/GPUTracking/Standalone/CMakeLists.txt index 0168de0e5c4ad..159bce697669a 100644 --- a/GPU/GPUTracking/Standalone/CMakeLists.txt +++ b/GPU/GPUTracking/Standalone/CMakeLists.txt @@ -1,28 +1,45 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Some general CMake settings -cmake_minimum_required(VERSION 3.18 FATAL_ERROR) +cmake_minimum_required(VERSION 3.19 FATAL_ERROR) project(GPUTrackingStandalone) include(FeatureSummary) set(CMAKE_INSTALL_BINDIR "${CMAKE_INSTALL_PREFIX}") set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}") -set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/dependencies ${CMAKE_MODULE_PATH}) +set(GPU_DIR "${CMAKE_SOURCE_DIR}/../../") +set(GPUTRACKING_DIR "${GPU_DIR}/GPUTracking") +set(O2_DIR "${CMAKE_SOURCE_DIR}/../../../") + +set(CMAKE_MODULE_PATH ${O2_DIR}/dependencies ${CMAKE_MODULE_PATH}) # Copy and include Config File if(NOT EXISTS "${CMAKE_BINARY_DIR}/config.cmake") file(COPY "${CMAKE_SOURCE_DIR}/cmake/config.cmake" DESTINATION "${CMAKE_BINARY_DIR}") endif() include("${CMAKE_BINARY_DIR}/config.cmake") +if(DEFINED CONFIG_COMPILER) + if(CONFIG_COMPILER STREQUAL "clang") + set(CMAKE_C_COMPILER "clang") + set(CMAKE_CXX_COMPILER "clang++") + elseif(CONFIG_COMPILER STREQUAL "gcc") + set(CMAKE_C_COMPILER "gcc") + set(CMAKE_CXX_COMPILER "c++") + else() + set(CMAKE_C_COMPILER "${CONFIG_COMPILER}") + set(CMAKE_CXX_COMPILER "${CONFIG_COMPILER}") + endif() +endif() # Set Build and Compiler settings set(ALIGPU_BUILD_TYPE "Standalone") @@ -35,7 +52,10 @@ if(BUILD_DEBUG) set(CMAKE_CXX_FLAGS "-O0 -ggdb") set(CMAKE_BUILD_TYPE DEBUG) else() - set(CMAKE_CXX_FLAGS "-O3 -march=native -ggdb -minline-all-stringops -ftracer -funroll-loops -fprefetch-loop-arrays -ffast-math -fno-stack-protector") + set(CMAKE_CXX_FLAGS "-O3 -march=native -ggdb -minline-all-stringops -funroll-loops -ffast-math -fno-stack-protector") + if (NOT CMAKE_CXX_COMPILER STREQUAL "clang++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftracer -fprefetch-loop-arrays") + endif() set(CMAKE_RELEASE_TYPE RELEASE) add_definitions(-DNDEBUG) endif() @@ -73,13 +93,12 @@ endif() if(CONFIG_ROOT) find_package(ROOT CONFIG REQUIRED) +else() + add_definitions(-DGPUCA_NO_ROOT) endif() if(CONFIG_O2_EXTENSIONS) - add_definitions(-DHAVE_O2HEADERS) - if(NOT DEFINED MS_GSL_INCLUDE_DIR AND DEFINED ENV{MS_GSL_ROOT}) - set(MS_GSL_INCLUDE_DIR $ENV{MS_GSL_ROOT}/include) - endif() - find_package(ms_gsl REQUIRED) + add_definitions(-DGPUCA_HAVE_O2HEADERS) + find_package(Microsoft.GSL REQUIRED HINTS "$ENV{MS_GSL_ROOT}/share/cmake") if(CONFIG_O2_ITS_TRAITS) if(NOT CONFIG_ROOT) message(FATAL_ERROR "Can not build ITS traits without ROOT") @@ -91,7 +110,7 @@ if(CONFIG_O2_EXTENSIONS) endif() if(CONFIG_FMT) - find_package(fmt REQUIRED) + find_package(fmt REQUIRED HINTS $ENV{FMT_ROOT}) else() add_definitions(-DGPUCA_NO_FMT) endif() @@ -100,57 +119,66 @@ endif() find_package(O2GPU) # Global include directories -include_directories(${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/Base - ${CMAKE_SOURCE_DIR}/Base/opencl-common - ${CMAKE_SOURCE_DIR}/Common - ${CMAKE_SOURCE_DIR}/GPUUtils - ${CMAKE_SOURCE_DIR}/dEdx - ${CMAKE_SOURCE_DIR}/TPCConvert - ${CMAKE_SOURCE_DIR}/TPCFastTransformation - ${CMAKE_SOURCE_DIR}/display - ${CMAKE_SOURCE_DIR}/Global - ${CMAKE_SOURCE_DIR}/HLTHeaders - ${CMAKE_SOURCE_DIR}/Merger - ${CMAKE_SOURCE_DIR}/Refit - ${CMAKE_SOURCE_DIR}/qa - ${CMAKE_SOURCE_DIR}/SliceTracker - ${CMAKE_SOURCE_DIR}/DataCompression - ${CMAKE_SOURCE_DIR}/TRDTracking) +include_directories(${GPU_DIR}/Common + ${GPU_DIR}/Utils + ${GPU_DIR}/TPCFastTransformation + ${GPUTRACKING_DIR} + ${GPUTRACKING_DIR}/Debug + ${GPUTRACKING_DIR}/Definitions + ${GPUTRACKING_DIR}/DataTypes + ${GPUTRACKING_DIR}/Base + ${GPUTRACKING_DIR}/Base/opencl-common + ${GPUTRACKING_DIR}/dEdx + ${GPUTRACKING_DIR}/TPCConvert + ${GPUTRACKING_DIR}/display + ${GPUTRACKING_DIR}/Global + ${GPUTRACKING_DIR}/HLTHeaders + ${GPUTRACKING_DIR}/Merger + ${GPUTRACKING_DIR}/Refit + ${GPUTRACKING_DIR}/qa + ${GPUTRACKING_DIR}/SliceTracker + ${GPUTRACKING_DIR}/DataCompression + ${GPUTRACKING_DIR}/TRDTracking) if(CONFIG_O2_EXTENSIONS) -include_directories(${CMAKE_SOURCE_DIR}/TPCClusterFinder - ${CMAKE_SOURCE_DIR}/ITS - ${CMAKE_SOURCE_DIR}/../../../Common/Field/include - ${CMAKE_SOURCE_DIR}/../../../Common/Constants/include - ${CMAKE_SOURCE_DIR}/../../../Common/MathUtils/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/common/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Detectors/Common/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Detectors/ITSMFT/ITS/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Detectors/TPC/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Detectors/TRD/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Headers/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/MemoryResources/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/Reconstruction/include - ${CMAKE_SOURCE_DIR}/../../../DataFormats/simulation/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/Base/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/Base/src - ${CMAKE_SOURCE_DIR}/../../../Detectors/ITSMFT/ITS/tracking/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/ITSMFT/ITS/tracking/cuda/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/ITSMFT/ITS/tracking/cuda/src - ${CMAKE_SOURCE_DIR}/../../../Detectors/ITSMFT/ITS/tracking/hip/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/ITSMFT/ITS/tracking/hip/src - ${CMAKE_SOURCE_DIR}/../../../Detectors/Raw/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/TPC/base/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/TRD/base/include - ${CMAKE_SOURCE_DIR}/../../../Detectors/TRD/base/src) +include_directories(${GPUTRACKING_DIR}/TPCClusterFinder + ${GPUTRACKING_DIR}/ITS + ${GPUTRACKING_DIR}/Interface + ${O2_DIR}/Common/Field/include + ${O2_DIR}/Common/Constants/include + ${O2_DIR}/Common/MathUtils/include + ${O2_DIR}/DataFormats/common/include + ${O2_DIR}/DataFormats/Detectors/Common/include + ${O2_DIR}/DataFormats/Detectors/ITSMFT/common/include + ${O2_DIR}/DataFormats/Detectors/ITSMFT/ITS/include + ${O2_DIR}/DataFormats/Detectors/TOF/include + ${O2_DIR}/DataFormats/Detectors/TPC/include + ${O2_DIR}/DataFormats/Detectors/TRD/include + ${O2_DIR}/DataFormats/Headers/include + ${O2_DIR}/DataFormats/MemoryResources/include + ${O2_DIR}/DataFormats/Reconstruction/include + ${O2_DIR}/DataFormats/Reconstruction/src + ${O2_DIR}/DataFormats/simulation/include + ${O2_DIR}/Detectors/Base/include + ${O2_DIR}/Detectors/Base/src + ${O2_DIR}/Detectors/ITSMFT/common/base/include + ${O2_DIR}/Detectors/ITSMFT/ITS/base/include + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/include + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/cuda/include + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/cuda/src + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/hip/include + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/hip/src + ${O2_DIR}/Detectors/Raw/include + ${O2_DIR}/Detectors/TOF/base/include + ${O2_DIR}/Detectors/TPC/base/include + ${O2_DIR}/Detectors/TRD/base/include + ${O2_DIR}/Detectors/TRD/base/src + ${O2_DIR}/Framework/Foundation/3rdparty/include) endif() # Create main targets -add_executable(ca standalone.cxx - Base/GPUReconstructionTimeframe.cxx) add_subdirectory(../../ GPU) -add_library(standalone_support SHARED utils/qconfig.cxx) +add_library(standalone_support SHARED ${GPUTRACKING_DIR}/utils/EmptyFile.cxx) target_link_libraries(GPUTracking PUBLIC TPCFastTransformation standalone_support dl) target_link_libraries(ca PUBLIC GPUTracking) @@ -161,33 +189,32 @@ target_compile_definitions(standalone_support PUBLIC $<TARGET_PROPERTY:O2::GPUTr # Add all sources and dependencies to to support based on Config File if(CONFIG_O2_EXTENSIONS) target_sources(standalone_support PRIVATE - ../../../Common/Field/src/MagFieldFast.cxx - ../../../DataFormats/Detectors/TPC/src/CompressedClusters.cxx - ../../../DataFormats/simulation/src/MCCompLabel.cxx - ../../../DataFormats/Reconstruction/src/TrackParametrization.cxx - ../../../DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx - ../../../DataFormats/Reconstruction/src/Vertex.cxx - ../../../DataFormats/Reconstruction/src/TrackLTIntegral.cxx - ../../../Detectors/TRD/base/src/GeometryBase.cxx - ../../../Detectors/Base/src/MatLayerCylSet.cxx - ../../../Detectors/Base/src/MatLayerCyl.cxx - ../../../Detectors/Base/src/Ray.cxx - ../../../Detectors/Base/src/Propagator.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/Road.cxx) + ${O2_DIR}/Common/Field/src/MagFieldFast.cxx + ${O2_DIR}/DataFormats/Detectors/TPC/src/CompressedClusters.cxx + ${O2_DIR}/DataFormats/simulation/src/MCCompLabel.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/TrackParametrization.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/Vertex.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/TrackLTIntegral.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/TrackParametrization.cxx + ${O2_DIR}/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx + ${O2_DIR}/Detectors/TRD/base/src/GeometryBase.cxx + ${O2_DIR}/Detectors/Base/src/MatLayerCylSet.cxx + ${O2_DIR}/Detectors/Base/src/MatLayerCyl.cxx + ${O2_DIR}/Detectors/Base/src/Ray.cxx + ${O2_DIR}/Detectors/Base/src/Propagator.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/Road.cxx) if(CONFIG_O2_ITS_TRAITS) target_sources(standalone_support PRIVATE - ../../../Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx - ../../../Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx) + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/Cluster.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx + ${O2_DIR}/Detectors/ITSMFT/ITS/tracking/src/ROframe.cxx) target_link_libraries(standalone_support PUBLIC Boost::boost) endif() endif() -if(CONFIG_ROOT) - target_sources(ca PRIVATE qa/genEvents.cxx) -endif() if(CONFIG_FMT) target_link_libraries(standalone_support PUBLIC fmt::fmt) @@ -198,18 +225,13 @@ if(CONFIG_VC) endif() if(BUILD_EVENT_DISPLAY) - target_link_libraries(standalone_support PUBLIC - X11::X11 - glfw - glut) - target_sources(GPUTracking PRIVATE display/GPUDisplayBackendX11.cxx - display/GPUDisplayBackendGlut.cxx) + target_link_libraries(standalone_support PUBLIC glfw) if(CONFIG_GL3W) - target_sources(GPUTracking PRIVATE display/3rdparty/gl3w.c) + target_sources(GPUTracking PRIVATE ${GPUTRACKING_DIR}/display/3rdparty/gl3w.c) target_compile_definitions(GPUTracking PUBLIC GPUCA_DISPLAY_GL3W) endif() - target_sources(GPUTracking PRIVATE display/3rdparty/HandMadeMathImpl.cxx) - target_include_directories(GPUTracking SYSTEM PUBLIC display/3rdparty) + target_sources(GPUTracking PRIVATE ${GPUTRACKING_DIR}/display/3rdparty/HandMadeMath/HandMadeMathImpl.cxx) + target_include_directories(GPUTracking SYSTEM PUBLIC ${GPUTRACKING_DIR}/display/3rdparty) endif() if(CONFIG_ROOT) @@ -217,10 +239,11 @@ if(CONFIG_ROOT) ROOT::Core ROOT::RIO ROOT::Hist - ROOT::Gui) + ROOT::Gui + ROOT::Tree) endif() if(CONFIG_O2_EXTENSIONS) - target_link_libraries(standalone_support PUBLIC ms_gsl::ms_gsl) + target_link_libraries(standalone_support PUBLIC Microsoft.GSL::GSL) endif() if(CONFIG_VC) @@ -229,10 +252,14 @@ endif() if(OpenMP_CXX_FOUND) target_link_libraries(ca PUBLIC OpenMP::OpenMP_CXX) + if (CMAKE_CXX_COMPILER STREQUAL "clang++") + target_link_libraries(ca PUBLIC -fopenmp) + target_link_libraries(GPUTracking PUBLIC -fopenmp) + endif() endif() # Installation install(TARGETS ca GPUTracking TPCFastTransformation standalone_support) install(FILES "cmake/makefile" DESTINATION "${CMAKE_INSTALL_PREFIX}") -install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR} ${CMAKE_INSTALL_PREFIX}/src)") +install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${O2_DIR} ${CMAKE_INSTALL_PREFIX}/src)") install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/config.cmake ${CMAKE_INSTALL_PREFIX}/config.cmake)") diff --git a/GPU/GPUTracking/Standalone/Common b/GPU/GPUTracking/Standalone/Common deleted file mode 120000 index a66ad39d9318c..0000000000000 --- a/GPU/GPUTracking/Standalone/Common +++ /dev/null @@ -1 +0,0 @@ -../../Common/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/DataCompression b/GPU/GPUTracking/Standalone/DataCompression deleted file mode 120000 index e336e72d378ab..0000000000000 --- a/GPU/GPUTracking/Standalone/DataCompression +++ /dev/null @@ -1 +0,0 @@ -../DataCompression \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/GPUUtils b/GPU/GPUTracking/Standalone/GPUUtils deleted file mode 120000 index 7c350897e8fd3..0000000000000 --- a/GPU/GPUTracking/Standalone/GPUUtils +++ /dev/null @@ -1 +0,0 @@ -../../Utils/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/Global b/GPU/GPUTracking/Standalone/Global deleted file mode 120000 index 7bfca6e01147e..0000000000000 --- a/GPU/GPUTracking/Standalone/Global +++ /dev/null @@ -1 +0,0 @@ -../Global/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/HLTHeaders b/GPU/GPUTracking/Standalone/HLTHeaders deleted file mode 120000 index 3f271033d8eeb..0000000000000 --- a/GPU/GPUTracking/Standalone/HLTHeaders +++ /dev/null @@ -1 +0,0 @@ -../HLTHeaders/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/ITS b/GPU/GPUTracking/Standalone/ITS deleted file mode 120000 index 3ed25d6858b1e..0000000000000 --- a/GPU/GPUTracking/Standalone/ITS +++ /dev/null @@ -1 +0,0 @@ -../ITS/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/Merger b/GPU/GPUTracking/Standalone/Merger deleted file mode 120000 index ddb7c2e13a8d9..0000000000000 --- a/GPU/GPUTracking/Standalone/Merger +++ /dev/null @@ -1 +0,0 @@ -../Merger/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/Refit b/GPU/GPUTracking/Standalone/Refit deleted file mode 120000 index 2cdf319240e0d..0000000000000 --- a/GPU/GPUTracking/Standalone/Refit +++ /dev/null @@ -1 +0,0 @@ -../Refit/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/SliceTracker b/GPU/GPUTracking/Standalone/SliceTracker deleted file mode 120000 index b2ff0a64ab1a7..0000000000000 --- a/GPU/GPUTracking/Standalone/SliceTracker +++ /dev/null @@ -1 +0,0 @@ -../SliceTracker/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/TPCClusterFinder b/GPU/GPUTracking/Standalone/TPCClusterFinder deleted file mode 120000 index ac295c7721aea..0000000000000 --- a/GPU/GPUTracking/Standalone/TPCClusterFinder +++ /dev/null @@ -1 +0,0 @@ -../TPCClusterFinder \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/TPCConvert b/GPU/GPUTracking/Standalone/TPCConvert deleted file mode 120000 index b67175d07b594..0000000000000 --- a/GPU/GPUTracking/Standalone/TPCConvert +++ /dev/null @@ -1 +0,0 @@ -../TPCConvert \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/TPCFastTransformation b/GPU/GPUTracking/Standalone/TPCFastTransformation deleted file mode 120000 index a8c5e0a2ebd0c..0000000000000 --- a/GPU/GPUTracking/Standalone/TPCFastTransformation +++ /dev/null @@ -1 +0,0 @@ -../../TPCFastTransformation/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/TRDTracking b/GPU/GPUTracking/Standalone/TRDTracking deleted file mode 120000 index db0ce36effe8b..0000000000000 --- a/GPU/GPUTracking/Standalone/TRDTracking +++ /dev/null @@ -1 +0,0 @@ -../TRDTracking/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/cmake/makefile b/GPU/GPUTracking/Standalone/cmake/makefile index d640ad8fa4552..87de4d66bb8c8 100644 --- a/GPU/GPUTracking/Standalone/cmake/makefile +++ b/GPU/GPUTracking/Standalone/cmake/makefile @@ -1,4 +1,5 @@ all: + #+$(MAKE) -C build depend +$(MAKE) -C build install clean: diff --git a/GPU/GPUTracking/Standalone/dEdx b/GPU/GPUTracking/Standalone/dEdx deleted file mode 120000 index 7318f8a5d1f11..0000000000000 --- a/GPU/GPUTracking/Standalone/dEdx +++ /dev/null @@ -1 +0,0 @@ -../dEdx \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/dependencies b/GPU/GPUTracking/Standalone/dependencies deleted file mode 120000 index 90273dd71ef60..0000000000000 --- a/GPU/GPUTracking/Standalone/dependencies +++ /dev/null @@ -1 +0,0 @@ -../../../dependencies/ \ No newline at end of file diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx deleted file mode 100644 index 36c881082954a..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx +++ /dev/null @@ -1,2245 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplay.cxx -/// \author David Rohr - -#include "GPUDisplay.h" - -#ifdef GPUCA_BUILD_EVENT_DISPLAY -#include "GPUTPCDef.h" - -#include <GL/glu.h> -#include <vector> -#include <array> -#include <tuple> -#include <memory> -#include <cstring> -#include <stdexcept> - -#ifndef _WIN32 -#include "bitmapfile.h" -#include "../utils/linux_helpers.h" -#endif -#ifdef WITH_OPENMP -#include <omp.h> -#endif - -#include "GPUTPCMCInfo.h" -#include "GPUChainTracking.h" -#include "GPUQA.h" -#include "GPUTPCSliceData.h" -#include "GPUChainTracking.h" -#include "GPUTPCTrack.h" -#include "GPUTPCTracker.h" -#include "GPUTRDTracker.h" -#include "GPUTPCGMMergedTrack.h" -#include "GPUTPCGMPropagator.h" -#include "GPUTPCClusterData.h" -#include "GPUTRDTrackletWord.h" -#include "GPUTRDGeometry.h" -#include "GPUO2DataTypes.h" -#include "GPUParam.inc" -#include "GPUTPCConvertImpl.h" -#include "utils/qconfig.h" - -#ifdef GPUCA_DISPLAY_OPENGL_CORE -#include "GPUDisplayShaders.h" -#endif - -constexpr hmm_mat4 MY_HMM_IDENTITY = {{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; -constexpr hmm_mat4 MY_HMM_FROM(float (&v)[16]) { return {{{v[0], v[1], v[2], v[3]}, {v[4], v[5], v[6], v[7]}, {v[8], v[9], v[10], v[11]}, {v[12], v[13], v[14], v[15]}}}; } - -using namespace GPUCA_NAMESPACE::gpu; - -//#define CHKERR(cmd) {cmd;} -#define CHKERR(cmd) \ - do { \ - (cmd); \ - GLenum err = glGetError(); \ - while (err != GL_NO_ERROR) { \ - GPUError("OpenGL Error %d: %s (%s: %d)", err, gluErrorString(err), __FILE__, __LINE__); \ - throw std::runtime_error("OpenGL Failure"); \ - } \ - } while (false) - -#define OPENGL_EMULATE_MULTI_DRAW 0 - -#define GL_SCALE_FACTOR 100.f - -#define SEPERATE_GLOBAL_TRACKS_LIMIT (mSeparateGlobalTracks ? tGLOBALTRACK : TRACK_TYPE_ID_LIMIT) - -#define GET_CID(slice, i) (tracker.Param().par.earlyTpcTransform ? tracker.ClusterData()[i].id : (tracker.GetConstantMem()->ioPtrs.clustersNative->clusterOffset[slice][0] + i)) - -#ifdef GPUCA_STANDALONE -namespace GPUCA_NAMESPACE::gpu -{ -extern GPUSettingsStandalone configStandalone; -} -#endif -static const GPUSettingsDisplay& GPUDisplay_GetConfig(GPUChainTracking* chain) -{ -#if !defined(GPUCA_STANDALONE) - static GPUSettingsDisplay defaultConfig; - if (chain->mConfigDisplay) { - return *chain->mConfigDisplay; - } else { - return defaultConfig; - } - -#else - return configStandalone.GL; -#endif -} - -GPUDisplay::GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa) : mBackend(backend), mChain(chain), mConfig(GPUDisplay_GetConfig(chain)), mQA(qa), mMerger(chain->GetTPCMerger()) { backend->mDisplay = this; } - -const GPUParam& GPUDisplay::param() { return mChain->GetParam(); } -const GPUTPCTracker& GPUDisplay::sliceTracker(int iSlice) { return mChain->GetTPCSliceTrackers()[iSlice]; } -const GPUTRDTrackerGPU& GPUDisplay::trdTracker() { return *mChain->GetTRDTracker(); } -const GPUTrackingInOutPointers GPUDisplay::ioptrs() { return mChain->mIOPtrs; } - -inline void GPUDisplay::drawVertices(const vboList& v, const GLenum t) -{ - auto first = std::get<0>(v); - auto count = std::get<1>(v); - auto iSlice = std::get<2>(v); - if (count == 0) { - return; - } - mNDrawCalls += count; - - if (mUseMultiVBO) { -#ifdef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glBindVertexArray(mVertexArray)); -#endif - CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[iSlice])); -#ifndef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glVertexPointer(3, GL_FLOAT, 0, nullptr)); -#else - CHKERR(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr)); - glEnableVertexAttribArray(0); -#endif - } - - if (mUseGLIndirectDraw) { - CHKERR(glMultiDrawArraysIndirect(t, (void*)(size_t)((mIndirectSliceOffset[iSlice] + first) * sizeof(DrawArraysIndirectCommand)), count, 0)); - } else if (OPENGL_EMULATE_MULTI_DRAW) { - for (int k = 0; k < count; k++) { - CHKERR(glDrawArrays(t, mVertexBufferStart[iSlice][first + k], mVertexBufferCount[iSlice][first + k])); - } - } else { - CHKERR(glMultiDrawArrays(t, mVertexBufferStart[iSlice].data() + first, mVertexBufferCount[iSlice].data() + first, count)); - } -} -inline void GPUDisplay::insertVertexList(std::pair<vecpod<GLint>*, vecpod<GLsizei>*>& vBuf, size_t first, size_t last) -{ - if (first == last) { - return; - } - vBuf.first->emplace_back(first); - vBuf.second->emplace_back(last - first); -} -inline void GPUDisplay::insertVertexList(int iSlice, size_t first, size_t last) -{ - std::pair<vecpod<GLint>*, vecpod<GLsizei>*> vBuf(mVertexBufferStart + iSlice, mVertexBufferCount + iSlice); - insertVertexList(vBuf, first, last); -} - -void GPUDisplay::calcXYZ(const float* matrix) -{ - mXYZ[0] = -(matrix[0] * matrix[12] + matrix[1] * matrix[13] + matrix[2] * matrix[14]); - mXYZ[1] = -(matrix[4] * matrix[12] + matrix[5] * matrix[13] + matrix[6] * matrix[14]); - mXYZ[2] = -(matrix[8] * matrix[12] + matrix[9] * matrix[13] + matrix[10] * matrix[14]); - - mAngle[0] = -asinf(matrix[6]); // Invert rotY*rotX*rotZ - float A = cosf(mAngle[0]); - if (fabsf(A) > 0.005) { - mAngle[1] = atan2f(-matrix[2] / A, matrix[10] / A); - mAngle[2] = atan2f(matrix[4] / A, matrix[5] / A); - } else { - mAngle[1] = 0; - mAngle[2] = atan2f(-matrix[1], -matrix[0]); - } - - mRPhiTheta[0] = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[1] * mXYZ[1] + mXYZ[2] * mXYZ[2]); - mRPhiTheta[1] = atan2f(mXYZ[0], mXYZ[2]); - mRPhiTheta[2] = atan2f(mXYZ[1], sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[2] * mXYZ[2])); - - createQuaternionFromMatrix(mQuat, matrix); - - /*float mAngle[1] = -asinf(matrix[2]); //Calculate Y-axis angle - for rotX*rotY*rotZ - float C = cosf( angle_y ); - if (fabsf(C) > 0.005) //Gimball lock? - { - mAngle[0] = atan2f(-matrix[6] / C, matrix[10] / C); - mAngle[2] = atan2f(-matrix[1] / C, matrix[0] / C); - } - else - { - mAngle[0] = 0; //set x-angle - mAngle[2] = atan2f(matrix[4], matrix[5]); - }*/ -} - -void GPUDisplay::SetCollisionFirstCluster(unsigned int collision, int slice, int cluster) -{ - mNCollissions = collision + 1; - mCollisionClusters.resize(mNCollissions); - mCollisionClusters[collision][slice] = cluster; -} - -void GPUDisplay::mAnimationCloseAngle(float& newangle, float lastAngle) -{ - const float delta = lastAngle > newangle ? (2 * M_PI) : (-2 * M_PI); - while (fabsf(newangle + delta - lastAngle) < fabsf(newangle - lastAngle)) { - newangle += delta; - } -} -void GPUDisplay::mAnimateCloseQuaternion(float* v, float lastx, float lasty, float lastz, float lastw) -{ - float distPos2 = (lastx - v[0]) * (lastx - v[0]) + (lasty - v[1]) * (lasty - v[1]) + (lastz - v[2]) * (lastz - v[2]) + (lastw - v[3]) * (lastw - v[3]); - float distNeg2 = (lastx + v[0]) * (lastx + v[0]) + (lasty + v[1]) * (lasty + v[1]) + (lastz + v[2]) * (lastz + v[2]) + (lastw + v[3]) * (lastw + v[3]); - if (distPos2 > distNeg2) { - for (int i = 0; i < 4; i++) { - v[i] = -v[i]; - } - } -} -void GPUDisplay::setAnimationPoint() -{ - if (mCfg.animationMode & 4) // Spherical - { - float rxy = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[2] * mXYZ[2]); - float anglePhi = atan2f(mXYZ[0], mXYZ[2]); - float angleTheta = atan2f(mXYZ[1], rxy); - if (mAnimateVectors[0].size()) { - mAnimationCloseAngle(anglePhi, mAnimateVectors[2].back()); - } - if (mAnimateVectors[0].size()) { - mAnimationCloseAngle(angleTheta, mAnimateVectors[3].back()); - } - mAnimateVectors[1].emplace_back(0); - mAnimateVectors[2].emplace_back(anglePhi); - mAnimateVectors[3].emplace_back(angleTheta); - } else { - for (int i = 0; i < 3; i++) { - mAnimateVectors[i + 1].emplace_back(mXYZ[i]); - } - // Cartesian - } - float r = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[1] * mXYZ[1] + mXYZ[2] * mXYZ[2]); - mAnimateVectors[4].emplace_back(r); - if (mCfg.animationMode & 1) // Euler-angles - { - for (int i = 0; i < 3; i++) { - float newangle = mAngle[i]; - if (mAnimateVectors[0].size()) { - mAnimationCloseAngle(newangle, mAnimateVectors[i + 5].back()); - } - mAnimateVectors[i + 5].emplace_back(newangle); - } - mAnimateVectors[8].emplace_back(0); - } else { // Quaternions - float v[4]; - createQuaternionFromMatrix(v, mViewMatrixP); - if (mAnimateVectors[0].size()) { - mAnimateCloseQuaternion(v, mAnimateVectors[5].back(), mAnimateVectors[6].back(), mAnimateVectors[7].back(), mAnimateVectors[8].back()); - } - for (int i = 0; i < 4; i++) { - mAnimateVectors[i + 5].emplace_back(v[i]); - } - } - float delay = 0.f; - if (mAnimateVectors[0].size()) { - delay = mAnimateVectors[0].back() + ((int)(mAnimationDelay * 20)) / 20.f; - } - mAnimateVectors[0].emplace_back(delay); - mAnimateConfig.emplace_back(mCfg); -} -void GPUDisplay::resetAnimation() -{ - for (int i = 0; i < 9; i++) { - mAnimateVectors[i].clear(); - } - mAnimateConfig.clear(); - mAnimate = 0; -} -void GPUDisplay::removeAnimationPoint() -{ - if (mAnimateVectors[0].size() == 0) { - return; - } - for (int i = 0; i < 9; i++) { - mAnimateVectors[i].pop_back(); - } - mAnimateConfig.pop_back(); -} -void GPUDisplay::startAnimation() -{ - for (int i = 0; i < 8; i++) { - mAnimationSplines[i].create(mAnimateVectors[0], mAnimateVectors[i + 1]); - } - mAnimationTimer.ResetStart(); - mAnimationFrame = 0; - mAnimate = 1; - mAnimationLastBase = 0; -} - -inline void GPUDisplay::ActivateColor() -{ -#ifndef GPUCA_DISPLAY_OPENGL_CORE - glColor3f(mDrawColor[0], mDrawColor[1], mDrawColor[2]); -#else - glUniform3fv(mColorId, 1, &mDrawColor[0]); -#endif -} - -inline void GPUDisplay::SetColorClusters() -{ - if (mCfg.colorCollisions) { - return; - } - if (mInvertColors) { - mDrawColor = {0, 0.3, 0.7}; - } else { - mDrawColor = {0, 0.7, 1.0}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorTRD() -{ - if (mCfg.colorCollisions) { - return; - } - if (mInvertColors) { - mDrawColor = {0.7, 0.3, 0}; - } else { - mDrawColor = {1.0, 0.7, 0}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorInitLinks() -{ - if (mInvertColors) { - mDrawColor = {0.42, 0.4, 0.1}; - } else { - mDrawColor = {0.42, 0.4, 0.1}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorLinks() -{ - if (mInvertColors) { - mDrawColor = {0.6, 0.1, 0.1}; - } else { - mDrawColor = {0.8, 0.2, 0.2}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorSeeds() -{ - if (mInvertColors) { - mDrawColor = {0.6, 0.0, 0.65}; - } else { - mDrawColor = {0.8, 0.1, 0.85}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorTracklets() -{ - if (mInvertColors) { - mDrawColor = {0, 0, 0}; - } else { - mDrawColor = {1, 1, 1}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorTracks() -{ - if (mInvertColors) { - mDrawColor = {0.6, 0, 0.1}; - } else { - mDrawColor = {0.8, 1., 0.15}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorGlobalTracks() -{ - if (mInvertColors) { - mDrawColor = {0.8, 0.2, 0}; - } else { - mDrawColor = {1.0, 0.4, 0}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorFinal() -{ - if (mCfg.colorCollisions) { - return; - } - if (mInvertColors) { - mDrawColor = {0, 0.6, 0.1}; - } else { - mDrawColor = {0, 0.7, 0.2}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorGrid() -{ - if (mInvertColors) { - mDrawColor = {0.5, 0.5, 0.0}; - } else { - mDrawColor = {0.7, 0.7, 0.0}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorGridTRD() -{ - if (mInvertColors) { - mDrawColor = {0.5, 0.5, 0.5}; - } else { - mDrawColor = {0.7, 0.7, 0.5}; - } - ActivateColor(); -} -inline void GPUDisplay::SetColorMarked() -{ - if (mInvertColors) { - mDrawColor = {0.8, 0, 0}; - } else { - mDrawColor = {1.0, 0.0, 0.0}; - } - ActivateColor(); -} -inline void GPUDisplay::SetCollisionColor(int col) -{ - int red = (col * 2) % 5; - int blue = (2 + col * 3) % 7; - int green = (4 + col * 5) % 6; - if (mInvertColors && red == 4 && blue == 5 && green == 6) { - red = 0; - } - if (!mInvertColors && red == 0 && blue == 0 && green == 0) { - red = 4; - } - mDrawColor = {red / 4.f, green / 5.f, blue / 6.f}; - ActivateColor(); -} - -void GPUDisplay::setQuality() -{ - // Doesn't seem to make a difference in this applicattion - if (mDrawQualityMSAA > 1) { - CHKERR(glEnable(GL_MULTISAMPLE)); - } else { - CHKERR(glDisable(GL_MULTISAMPLE)); - } -} - -void GPUDisplay::setDepthBuffer() -{ - if (mCfg.depthBuffer) { - CHKERR(glEnable(GL_DEPTH_TEST)); // Enables Depth Testing - CHKERR(glDepthFunc(GL_LEQUAL)); // The Type Of Depth Testing To Do - } else { - CHKERR(glDisable(GL_DEPTH_TEST)); - } -} - -void GPUDisplay::createFB_texture(GLuint& id, bool msaa, GLenum storage, GLenum attachment) -{ - GLenum textureType = msaa ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; - CHKERR(glGenTextures(1, &id)); - CHKERR(glBindTexture(textureType, id)); - if (msaa) { - CHKERR(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, mDrawQualityMSAA, storage, mRenderwidth, mRenderheight, false)); - } else { - CHKERR(glTexImage2D(GL_TEXTURE_2D, 0, storage, mRenderwidth, mRenderheight, 0, storage, GL_UNSIGNED_BYTE, nullptr)); - CHKERR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - CHKERR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - } - CHKERR(glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textureType, id, 0)); -} - -void GPUDisplay::createFB_renderbuffer(GLuint& id, bool msaa, GLenum storage, GLenum attachment) -{ - CHKERR(glGenRenderbuffers(1, &id)); - CHKERR(glBindRenderbuffer(GL_RENDERBUFFER, id)); - if (msaa) { - CHKERR(glRenderbufferStorageMultisample(GL_RENDERBUFFER, mDrawQualityMSAA, storage, mRenderwidth, mRenderheight)); - } else { - CHKERR(glRenderbufferStorage(GL_RENDERBUFFER, storage, mRenderwidth, mRenderheight)); - } - CHKERR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, id)); -} - -void GPUDisplay::createFB(GLfb& fb, bool tex, bool withDepth, bool msaa) -{ - fb.tex = tex; - fb.depth = withDepth; - fb.msaa = msaa; - GLint drawFboId = 0, readFboId = 0; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId); - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId); - CHKERR(glGenFramebuffers(1, &fb.fb_id)); - CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, fb.fb_id)); - - if (tex) { - createFB_texture(fb.fbCol_id, fb.msaa, GL_RGBA, GL_COLOR_ATTACHMENT0); - } else { - createFB_renderbuffer(fb.fbCol_id, fb.msaa, GL_RGBA, GL_COLOR_ATTACHMENT0); - } - - if (withDepth) { - if (tex && fb.msaa) { - createFB_texture(fb.fbDepth_id, fb.msaa, GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); - } else { - createFB_renderbuffer(fb.fbDepth_id, fb.msaa, GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); - } - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - GPUError("Error creating framebuffer (tex %d) - incomplete (%d)", (int)tex, status); - exit(1); - } - CHKERR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFboId)); - CHKERR(glBindFramebuffer(GL_READ_FRAMEBUFFER, readFboId)); - fb.created = true; -} - -void GPUDisplay::deleteFB(GLfb& fb) -{ - if (fb.tex) { - CHKERR(glDeleteTextures(1, &fb.fbCol_id)); - } else { - CHKERR(glDeleteRenderbuffers(1, &fb.fbCol_id)); - } - if (fb.depth) { - if (fb.tex && fb.msaa) { - CHKERR(glDeleteTextures(1, &fb.fbDepth_id)); - } else { - CHKERR(glDeleteRenderbuffers(1, &fb.fbDepth_id)); - } - } - CHKERR(glDeleteFramebuffers(1, &fb.fb_id)); - fb.created = false; -} - -void GPUDisplay::setFrameBuffer(int updateCurrent, GLuint newID) -{ - if (updateCurrent == 1) { - mMainBufferStack.push_back(newID); - } else if (updateCurrent == 2) { - mMainBufferStack.back() = newID; - } else if (updateCurrent == -2) { - newID = mMainBufferStack.back(); - } else if (updateCurrent == -1) { - mMainBufferStack.pop_back(); - newID = mMainBufferStack.back(); - } - if (newID == 0) { - CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); - glDrawBuffer(GL_BACK); - } else { - CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, newID)); - GLenum drawBuffer = GL_COLOR_ATTACHMENT0; - glDrawBuffers(1, &drawBuffer); - } -} - -void GPUDisplay::UpdateOffscreenBuffers(bool clean) -{ - if (mMixBuffer.created) { - deleteFB(mMixBuffer); - } - if (mOffscreenBuffer.created) { - deleteFB(mOffscreenBuffer); - } - if (mOffscreenBufferNoMSAA.created) { - deleteFB(mOffscreenBufferNoMSAA); - } - if (clean) { - return; - } - - if (mDrawQualityDownsampleFSAA > 1) { - mRenderwidth = mScreenwidth * mDrawQualityDownsampleFSAA; - mRenderheight = mScreenheight * mDrawQualityDownsampleFSAA; - } else { - mRenderwidth = mScreenwidth; - mRenderheight = mScreenheight; - } - if (mDrawQualityMSAA > 1 || mDrawQualityDownsampleFSAA > 1) { - createFB(mOffscreenBuffer, false, true, mDrawQualityMSAA > 1); - if (mDrawQualityMSAA > 1 && mDrawQualityDownsampleFSAA > 1) { - createFB(mOffscreenBufferNoMSAA, false, true, false); - } - } - createFB(mMixBuffer, true, true, false); - glViewport(0, 0, mRenderwidth, mRenderheight); - setQuality(); -} - -void GPUDisplay::ReSizeGLScene(int width, int height, bool init) -{ - if (height == 0) { // Prevent A Divide By Zero By - height = 1; // Making Height Equal One - } - mScreenwidth = width; - mScreenheight = height; - UpdateOffscreenBuffers(); - - if (init) { - mResetScene = 1; - mViewMatrix = MY_HMM_IDENTITY; - } -} - -void GPUDisplay::updateConfig() -{ - setQuality(); - setDepthBuffer(); -} - -int GPUDisplay::InitGL(bool initFailure) -{ - int retVal = initFailure; - try { - if (!initFailure) { - retVal = InitGL_internal(); - } - } catch (const std::runtime_error& e) { - retVal = 1; - } - mInitResult = retVal == 0 ? 1 : -1; - return (retVal); -} - -int GPUDisplay::InitGL_internal() -{ - int glVersion[2] = {0, 0}; - glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); - glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); - if (glVersion[0] < GPUDisplayBackend::GL_MIN_VERSION_MAJOR || (glVersion[0] == GPUDisplayBackend::GL_MIN_VERSION_MAJOR && glVersion[1] < GPUDisplayBackend::GL_MIN_VERSION_MINOR)) { - GPUError("Unsupported OpenGL runtime %d.%d < %d.%d", glVersion[0], glVersion[1], GPUDisplayBackend::GL_MIN_VERSION_MAJOR, GPUDisplayBackend::GL_MIN_VERSION_MINOR); - return (1); - } - - CHKERR(glCreateBuffers(GPUChainTracking::NSLICES, mVBOId)); - CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0])); - CHKERR(glGenBuffers(1, &mIndirectId)); - CHKERR(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectId)); -#ifndef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glShadeModel(GL_SMOOTH)); // Enable Smooth Shading -#endif - setDepthBuffer(); - setQuality(); - ReSizeGLScene(GPUDisplayBackend::INIT_WIDTH, GPUDisplayBackend::INIT_HEIGHT, true); - mThreadBuffers.resize(mChain->GetProcessingSettings().ompThreads); - mThreadTracks.resize(mChain->GetProcessingSettings().ompThreads); -#ifdef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(mVertexShader = glCreateShader(GL_VERTEX_SHADER)); - CHKERR(glShaderSource(mVertexShader, 1, &GPUDisplayShaders::vertexShader, nullptr)); - CHKERR(glCompileShader(mVertexShader)); - CHKERR(mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER)); - CHKERR(glShaderSource(mFragmentShader, 1, &GPUDisplayShaders::fragmentShader, nullptr)); - CHKERR(glCompileShader(mFragmentShader)); - CHKERR(mShaderProgram = glCreateProgram()); - CHKERR(glAttachShader(mShaderProgram, mVertexShader)); - CHKERR(glAttachShader(mShaderProgram, mFragmentShader)); - CHKERR(glLinkProgram(mShaderProgram)); - CHKERR(glGenVertexArrays(1, &mVertexArray)); - CHKERR(mModelViewProjId = glGetUniformLocation(mShaderProgram, "ModelViewProj")); - CHKERR(mColorId = glGetUniformLocation(mShaderProgram, "color")); -#endif - return (0); // Initialization Went OK -} - -void GPUDisplay::ExitGL() -{ - UpdateOffscreenBuffers(true); - CHKERR(glDeleteBuffers(GPUChainTracking::NSLICES, mVBOId)); - CHKERR(glDeleteBuffers(1, &mIndirectId)); -#ifdef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glDeleteProgram(mShaderProgram)); - CHKERR(glDeleteShader(mVertexShader)); - CHKERR(glDeleteShader(mFragmentShader)); -#endif -} - -inline void GPUDisplay::drawPointLinestrip(int iSlice, int cid, int id, int id_limit) -{ - mVertexBuffer[iSlice].emplace_back(mGlobalPos[cid].x, mGlobalPos[cid].y, mProjectXY ? 0 : mGlobalPos[cid].z); - if (mGlobalPos[cid].w < id_limit) { - mGlobalPos[cid].w = id; - } -} - -GPUDisplay::vboList GPUDisplay::DrawSpacePointsTRD(int iSlice, int select, int iCol) -{ - size_t startCount = mVertexBufferStart[iSlice].size(); - size_t startCountInner = mVertexBuffer[iSlice].size(); - - if (iCol == 0) { - for (int i = 0; i < trdTracker().NTracklets(); i++) { - int iSec = mChain->GetTRDGeometry()->GetSector(trdTracker().Tracklets()[i].GetDetector()); - bool draw = iSlice == iSec && mGlobalPosTRD[i].w == select; - if (draw) { - mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD[i].x, mGlobalPosTRD[i].y, mProjectXY ? 0 : mGlobalPosTRD[i].z); - mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD2[i].x, mGlobalPosTRD2[i].y, mProjectXY ? 0 : mGlobalPosTRD2[i].z); - } - } - } - - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawClusters(const GPUTPCTracker& tracker, int select, int iCol) -{ - int iSlice = tracker.ISlice(); - size_t startCount = mVertexBufferStart[iSlice].size(); - size_t startCountInner = mVertexBuffer[iSlice].size(); - const int firstCluster = (mNCollissions > 1 && iCol > 0) ? mCollisionClusters[iCol - 1][iSlice] : 0; - const int lastCluster = (mNCollissions > 1 && iCol + 1 < mNCollissions) ? mCollisionClusters[iCol][iSlice] : tracker.Data().NumberOfHits(); - for (int cidInSlice = firstCluster; cidInSlice < lastCluster; cidInSlice++) { - const int cid = GET_CID(iSlice, cidInSlice); - if (mHideUnmatchedClusters && mQA && mQA->SuppressHit(cid)) { - continue; - } - bool draw = mGlobalPos[cid].w == select; - - if (mMarkAdjacentClusters) { - const int attach = tracker.GetConstantMem()->ioPtrs.mergedTrackHitAttachment[cid]; - if (attach) { - if (mMarkAdjacentClusters >= 32) { - if (mQA && mQA->clusterRemovable(attach, mMarkAdjacentClusters == 33)) { - draw = select == tMARKED; - } - } else if ((mMarkAdjacentClusters & 2) && (attach & gputpcgmmergertypes::attachTube)) { - draw = select == tMARKED; - } else if ((mMarkAdjacentClusters & 1) && (attach & (gputpcgmmergertypes::attachGood | gputpcgmmergertypes::attachTube)) == 0) { - draw = select == tMARKED; - } else if ((mMarkAdjacentClusters & 4) && (attach & gputpcgmmergertypes::attachGoodLeg) == 0) { - draw = select == tMARKED; - } else if ((mMarkAdjacentClusters & 16) && (attach & gputpcgmmergertypes::attachHighIncl)) { - draw = select == tMARKED; - } else if (mMarkAdjacentClusters & 8) { - if (fabsf(tracker.GetConstantMem()->ioPtrs.mergedTracks[attach & gputpcgmmergertypes::attachTrackMask].GetParam().GetQPt()) > 20.f) { - draw = select == tMARKED; - } - } - } - } else if (mMarkClusters) { - short flags; - if (tracker.Param().par.earlyTpcTransform) { - flags = tracker.ClusterData()[cidInSlice].flags; - } else { - flags = tracker.GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cid].getFlags(); - } - const bool match = flags & mMarkClusters; - draw = (select == tMARKED) ? (match) : (draw && !match); - } else if (mMarkFakeClusters) { - const bool fake = (mQA && mQA->HitAttachStatus(cid)); - draw = (select == tMARKED) ? (fake) : (draw && !fake); - } - if (draw) { - mVertexBuffer[iSlice].emplace_back(mGlobalPos[cid].x, mGlobalPos[cid].y, mProjectXY ? 0 : mGlobalPos[cid].z); - } - } - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawLinks(const GPUTPCTracker& tracker, int id, bool dodown) -{ - int iSlice = tracker.ISlice(); - if (mConfig.clustersOnly) { - return (vboList(0, 0, iSlice)); - } - size_t startCount = mVertexBufferStart[iSlice].size(); - size_t startCountInner = mVertexBuffer[iSlice].size(); - for (int i = 0; i < GPUCA_ROW_COUNT; i++) { - const GPUTPCRow& row = tracker.Data().Row(i); - - if (i < GPUCA_ROW_COUNT - 2) { - const GPUTPCRow& rowUp = tracker.Data().Row(i + 2); - for (int j = 0; j < row.NHits(); j++) { - if (tracker.Data().HitLinkUpData(row, j) != CALINK_INVAL) { - const int cid1 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, j)); - const int cid2 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(rowUp, tracker.Data().HitLinkUpData(row, j))); - drawPointLinestrip(iSlice, cid1, id); - drawPointLinestrip(iSlice, cid2, id); - } - } - } - - if (dodown && i >= 2) { - const GPUTPCRow& rowDown = tracker.Data().Row(i - 2); - for (int j = 0; j < row.NHits(); j++) { - if (tracker.Data().HitLinkDownData(row, j) != CALINK_INVAL) { - const int cid1 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, j)); - const int cid2 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(rowDown, tracker.Data().HitLinkDownData(row, j))); - drawPointLinestrip(iSlice, cid1, id); - drawPointLinestrip(iSlice, cid2, id); - } - } - } - } - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawSeeds(const GPUTPCTracker& tracker) -{ - int iSlice = tracker.ISlice(); - if (mConfig.clustersOnly) { - return (vboList(0, 0, iSlice)); - } - size_t startCount = mVertexBufferStart[iSlice].size(); - for (unsigned int i = 0; i < *tracker.NStartHits(); i++) { - const GPUTPCHitId& hit = tracker.TrackletStartHit(i); - size_t startCountInner = mVertexBuffer[iSlice].size(); - int ir = hit.RowIndex(); - calink ih = hit.HitIndex(); - do { - const GPUTPCRow& row = tracker.Data().Row(ir); - const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, ih)); - drawPointLinestrip(iSlice, cid, tSEED); - ir += 2; - ih = tracker.Data().HitLinkUpData(row, ih); - } while (ih != CALINK_INVAL); - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - } - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawTracklets(const GPUTPCTracker& tracker) -{ - int iSlice = tracker.ISlice(); - if (mConfig.clustersOnly) { - return (vboList(0, 0, iSlice)); - } - size_t startCount = mVertexBufferStart[iSlice].size(); - for (unsigned int i = 0; i < *tracker.NTracklets(); i++) { - const GPUTPCTracklet& tracklet = tracker.Tracklet(i); - if (tracklet.NHits() == 0) { - continue; - } - size_t startCountInner = mVertexBuffer[iSlice].size(); - float4 oldpos; - for (int j = tracklet.FirstRow(); j <= tracklet.LastRow(); j++) { - const calink rowHit = tracker.TrackletRowHits()[tracklet.FirstHit() + (j - tracklet.FirstRow())]; - if (rowHit != CALINK_INVAL) { - const GPUTPCRow& row = tracker.Data().Row(j); - const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, rowHit)); - oldpos = mGlobalPos[cid]; - drawPointLinestrip(iSlice, cid, tTRACKLET); - } - } - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - } - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawTracks(const GPUTPCTracker& tracker, int global) -{ - int iSlice = tracker.ISlice(); - if (mConfig.clustersOnly) { - return (vboList(0, 0, iSlice)); - } - size_t startCount = mVertexBufferStart[iSlice].size(); - for (unsigned int i = (global ? tracker.CommonMemory()->nLocalTracks : 0); i < (global ? *tracker.NTracks() : tracker.CommonMemory()->nLocalTracks); i++) { - GPUTPCTrack& track = tracker.Tracks()[i]; - size_t startCountInner = mVertexBuffer[iSlice].size(); - for (int j = 0; j < track.NHits(); j++) { - const GPUTPCHitId& hit = tracker.TrackHits()[track.FirstHitID() + j]; - const GPUTPCRow& row = tracker.Data().Row(hit.RowIndex()); - const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, hit.HitIndex())); - drawPointLinestrip(iSlice, cid, tSLICETRACK + global); - } - insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); - } - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -void GPUDisplay::DrawFinal(int iSlice, int /*iCol*/, GPUTPCGMPropagator* prop, std::array<vecpod<int>, 2>& trackList, threadVertexBuffer& threadBuffer) -{ - auto& vBuf = threadBuffer.vBuf; - auto& buffer = threadBuffer.buffer; - unsigned int nTracks = std::max(trackList[0].size(), trackList[1].size()); - if (mConfig.clustersOnly) { - nTracks = 0; - } - for (unsigned int ii = 0; ii < nTracks; ii++) { - int i = 0; - const GPUTPCGMMergedTrack* track = nullptr; - int lastCluster = -1; - while (true) { - if (ii >= trackList[0].size()) { - break; - } - i = trackList[0][ii]; - track = &mMerger.GetConstantMem()->ioPtrs.mergedTracks[i]; - - size_t startCountInner = mVertexBuffer[iSlice].size(); - bool drawing = false; - - if (mTrackFilter) { - if (mTrackFilter == 2 && (!trdTracker().PreCheckTrackTRDCandidate(*track) || !trdTracker().CheckTrackTRDCandidate((GPUTRDTrackGPU)*track))) { - break; - } - if (mTrackFilter == 1 && mTRDTrackIds[i] == -1) { - break; - } - } - - if (mTRDTrackIds[i] != -1) { - auto& trk = trdTracker().Tracks()[mTRDTrackIds[i]]; - for (int k = 5; k >= 0; k--) { - int cid = trk.GetTrackletIndex(k); - if (cid < 0) { - continue; - } - drawing = true; - mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD2[cid].x, mGlobalPosTRD2[cid].y, mProjectXY ? 0 : mGlobalPosTRD2[cid].z); - mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD[cid].x, mGlobalPosTRD[cid].y, mProjectXY ? 0 : mGlobalPosTRD[cid].z); - mGlobalPosTRD[cid].w = tTRDATTACHED; - } - } - for (unsigned int k = 0; k < track->NClusters(); k++) { - if (mHideRejectedClusters && (mMerger.GetConstantMem()->ioPtrs.mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject)) { - continue; - } - int cid = mMerger.GetConstantMem()->ioPtrs.mergedTrackHits[track->FirstClusterRef() + k].num; - int w = mGlobalPos[cid].w; - if (drawing) { - drawPointLinestrip(iSlice, cid, tFINALTRACK, SEPERATE_GLOBAL_TRACKS_LIMIT); - } - if (w == SEPERATE_GLOBAL_TRACKS_LIMIT) { - if (drawing) { - insertVertexList(vBuf[0], startCountInner, mVertexBuffer[iSlice].size()); - } - drawing = false; - } else { - if (!drawing) { - startCountInner = mVertexBuffer[iSlice].size(); - } - if (!drawing) { - drawPointLinestrip(iSlice, cid, tFINALTRACK, SEPERATE_GLOBAL_TRACKS_LIMIT); - } - if (!drawing && lastCluster != -1) { - drawPointLinestrip(iSlice, mMerger.GetConstantMem()->ioPtrs.mergedTrackHits[track->FirstClusterRef() + lastCluster].num, 7, SEPERATE_GLOBAL_TRACKS_LIMIT); - } - drawing = true; - } - lastCluster = k; - } - insertVertexList(vBuf[0], startCountInner, mVertexBuffer[iSlice].size()); - break; - } - - for (int iMC = 0; iMC < 2; iMC++) { - if (iMC) { - if (ii >= trackList[1].size()) { - continue; - } - i = trackList[1][ii]; - } else { - if (track == nullptr) { - continue; - } - if (lastCluster == -1) { - continue; - } - } - - size_t startCountInner = mVertexBuffer[iSlice].size(); - for (int inFlyDirection = 0; inFlyDirection < 2; inFlyDirection++) { - GPUTPCGMPhysicalTrackModel trkParam; - float ZOffset = 0; - float x = 0; - int slice = iSlice; - float alpha = param().Alpha(slice); - if (iMC == 0) { - trkParam.Set(track->GetParam()); - if (mMerger.Param().par.earlyTpcTransform) { - auto cl = mMerger.ClustersXYZ()[track->FirstClusterRef() + lastCluster]; // Todo: Remove direct usage of merger - x = cl.x; - ZOffset = track->GetParam().GetTZOffset(); - } else { - auto cl = mMerger.GetConstantMem()->ioPtrs.mergedTrackHits[track->FirstClusterRef() + lastCluster]; - const auto& cln = mMerger.GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cl.num]; - float y, z; - GPUTPCConvertImpl::convert(*mMerger.GetConstantMem(), cl.slice, cl.row, cln.getPad(), cln.getTime(), x, y, z); - ZOffset = mMerger.GetConstantMem()->calibObjects.fastTransform->convTimeToZinTimeFrame(slice, track->GetParam().GetTZOffset(), mMerger.Param().par.continuousMaxTimeBin); - } - } else { - const GPUTPCMCInfo& mc = ioptrs().mcInfosTPC[i]; - if (mc.charge == 0.f) { - break; - } - if (mc.pid < 0) { - break; - } - - float c = cosf(alpha); - float s = sinf(alpha); - float mclocal[4]; - x = mc.x; - float y = mc.y; - mclocal[0] = x * c + y * s; - mclocal[1] = -x * s + y * c; - float px = mc.pX; - float py = mc.pY; - mclocal[2] = px * c + py * s; - mclocal[3] = -px * s + py * c; - float charge = mc.charge > 0 ? 1.f : -1.f; - - x = mclocal[0]; - if (fabsf(mc.z) > 250) { - ZOffset = mc.z > 0 ? (mc.z - 250) : (mc.z + 250); - } - trkParam.Set(mclocal[0], mclocal[1], mc.z - ZOffset, mclocal[2], mclocal[3], mc.pZ, charge); - } - trkParam.X() += mXadd; - x += mXadd; - float z0 = trkParam.Z(); - if (iMC && inFlyDirection == 0) { - buffer.clear(); - } - if (x < 1) { - break; - } - if (fabsf(trkParam.SinPhi()) > 1) { - break; - } - alpha = param().Alpha(slice); - vecpod<GLvertex>& useBuffer = iMC && inFlyDirection == 0 ? buffer : mVertexBuffer[iSlice]; - int nPoints = 0; - - while (nPoints++ < 5000) { - if ((inFlyDirection == 0 && x < 0) || (inFlyDirection && x * x + trkParam.Y() * trkParam.Y() > (iMC ? (450 * 450) : (300 * 300)))) { - break; - } - if (fabsf(trkParam.Z() + ZOffset) > mMaxClusterZ + (iMC ? 0 : 0)) { - break; - } - if (fabsf(trkParam.Z() - z0) > (iMC ? 250 : 250)) { - break; - } - if (inFlyDirection) { - if (fabsf(trkParam.SinPhi()) > 0.4) { - float dalpha = asinf(trkParam.SinPhi()); - trkParam.Rotate(dalpha); - alpha += dalpha; - } - x = trkParam.X() + 1.f; - if (!mPropagateLoopers) { - float diff = fabsf(alpha - param().Alpha(slice)) / (2. * M_PI); - diff -= floor(diff); - if (diff > 0.25 && diff < 0.75) { - break; - } - } - } - float B[3]; - prop->GetBxByBz(alpha, trkParam.GetX(), trkParam.GetY(), trkParam.GetZ(), B); - float dLp = 0; - if (trkParam.PropagateToXBxByBz(x, B[0], B[1], B[2], dLp)) { - break; - } - if (fabsf(trkParam.SinPhi()) > 0.9) { - break; - } - float sa = sinf(alpha), ca = cosf(alpha); - useBuffer.emplace_back((ca * trkParam.X() - sa * trkParam.Y()) / GL_SCALE_FACTOR, (ca * trkParam.Y() + sa * trkParam.X()) / GL_SCALE_FACTOR, mProjectXY ? 0 : (trkParam.Z() + ZOffset) / GL_SCALE_FACTOR); - x += inFlyDirection ? 1 : -1; - } - - if (inFlyDirection == 0) { - if (iMC) { - for (int k = (int)buffer.size() - 1; k >= 0; k--) { - mVertexBuffer[iSlice].emplace_back(buffer[k]); - } - } else { - insertVertexList(vBuf[1], startCountInner, mVertexBuffer[iSlice].size()); - startCountInner = mVertexBuffer[iSlice].size(); - } - } - } - insertVertexList(vBuf[iMC ? 3 : 2], startCountInner, mVertexBuffer[iSlice].size()); - } - } -} - -GPUDisplay::vboList GPUDisplay::DrawGrid(const GPUTPCTracker& tracker) -{ - int iSlice = tracker.ISlice(); - size_t startCount = mVertexBufferStart[iSlice].size(); - size_t startCountInner = mVertexBuffer[iSlice].size(); - for (int i = 0; i < GPUCA_ROW_COUNT; i++) { - const GPUTPCRow& row = tracker.Data().Row(i); - for (int j = 0; j <= (signed)row.Grid().Ny(); j++) { - float z1 = row.Grid().ZMin(); - float z2 = row.Grid().ZMax(); - float x = row.X() + mXadd; - float y = row.Grid().YMin() + (float)j / row.Grid().StepYInv(); - float zz1, zz2, yy1, yy2, xx1, xx2; - tracker.Param().Slice2Global(tracker.ISlice(), x, y, z1, &xx1, &yy1, &zz1); - tracker.Param().Slice2Global(tracker.ISlice(), x, y, z2, &xx2, &yy2, &zz2); - if (iSlice < 18) { - zz1 += mZadd; - zz2 += mZadd; - } else { - zz1 -= mZadd; - zz2 -= mZadd; - } - mVertexBuffer[iSlice].emplace_back(xx1 / GL_SCALE_FACTOR, yy1 / GL_SCALE_FACTOR, zz1 / GL_SCALE_FACTOR); - mVertexBuffer[iSlice].emplace_back(xx2 / GL_SCALE_FACTOR, yy2 / GL_SCALE_FACTOR, zz2 / GL_SCALE_FACTOR); - } - for (int j = 0; j <= (signed)row.Grid().Nz(); j++) { - float y1 = row.Grid().YMin(); - float y2 = row.Grid().YMax(); - float x = row.X() + mXadd; - float z = row.Grid().ZMin() + (float)j / row.Grid().StepZInv(); - float zz1, zz2, yy1, yy2, xx1, xx2; - tracker.Param().Slice2Global(tracker.ISlice(), x, y1, z, &xx1, &yy1, &zz1); - tracker.Param().Slice2Global(tracker.ISlice(), x, y2, z, &xx2, &yy2, &zz2); - if (iSlice < 18) { - zz1 += mZadd; - zz2 += mZadd; - } else { - zz1 -= mZadd; - zz2 -= mZadd; - } - mVertexBuffer[iSlice].emplace_back(xx1 / GL_SCALE_FACTOR, yy1 / GL_SCALE_FACTOR, zz1 / GL_SCALE_FACTOR); - mVertexBuffer[iSlice].emplace_back(xx2 / GL_SCALE_FACTOR, yy2 / GL_SCALE_FACTOR, zz2 / GL_SCALE_FACTOR); - } - } - insertVertexList(tracker.ISlice(), startCountInner, mVertexBuffer[iSlice].size()); - return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); -} - -GPUDisplay::vboList GPUDisplay::DrawGridTRD(int sector) -{ - // TODO: tilted pads ignored at the moment - size_t startCount = mVertexBufferStart[sector].size(); - size_t startCountInner = mVertexBuffer[sector].size(); -#ifdef HAVE_O2HEADERS - auto* geo = mChain->GetTRDGeometry(); - if (geo) { - int trdsector = NSLICES / 2 - 1 - sector; - float alpha = geo->GetAlpha() / 2.f + geo->GetAlpha() * trdsector; - if (trdsector >= 9) { - alpha -= 2 * M_PI; - } - for (int iLy = 0; iLy < GPUTRDTracker::EGPUTRDTracker::kNLayers; ++iLy) { - for (int iStack = 0; iStack < GPUTRDTracker::EGPUTRDTracker::kNStacks; ++iStack) { - int iDet = geo->GetDetector(iLy, iStack, trdsector); - auto matrix = geo->GetClusterMatrix(iDet); - if (!matrix) { - continue; - } - auto pp = geo->GetPadPlane(iDet); - for (int i = 0; i < pp->GetNrows(); ++i) { - float xyzLoc1[3]; - float xyzLoc2[3]; - float xyzGlb1[3]; - float xyzGlb2[3]; - xyzLoc1[0] = xyzLoc2[0] = geo->AnodePos(); - xyzLoc1[1] = pp->GetCol0(); - xyzLoc2[1] = pp->GetColEnd(); - xyzLoc1[2] = xyzLoc2[2] = pp->GetRowPos(i) - pp->GetRowPos(pp->GetNrows() / 2); - matrix->LocalToMaster(xyzLoc1, xyzGlb1); - matrix->LocalToMaster(xyzLoc2, xyzGlb2); - float x1Tmp = xyzGlb1[0]; - xyzGlb1[0] = xyzGlb1[0] * cosf(alpha) + xyzGlb1[1] * sinf(alpha); - xyzGlb1[1] = -x1Tmp * sinf(alpha) + xyzGlb1[1] * cosf(alpha); - float x2Tmp = xyzGlb2[0]; - xyzGlb2[0] = xyzGlb2[0] * cosf(alpha) + xyzGlb2[1] * sinf(alpha); - xyzGlb2[1] = -x2Tmp * sinf(alpha) + xyzGlb2[1] * cosf(alpha); - mVertexBuffer[sector].emplace_back(xyzGlb1[0] / GL_SCALE_FACTOR, xyzGlb1[1] / GL_SCALE_FACTOR, xyzGlb1[2] / GL_SCALE_FACTOR); - mVertexBuffer[sector].emplace_back(xyzGlb2[0] / GL_SCALE_FACTOR, xyzGlb2[1] / GL_SCALE_FACTOR, xyzGlb2[2] / GL_SCALE_FACTOR); - } - for (int j = 0; j < pp->GetNcols(); ++j) { - float xyzLoc1[3]; - float xyzLoc2[3]; - float xyzGlb1[3]; - float xyzGlb2[3]; - xyzLoc1[0] = xyzLoc2[0] = geo->AnodePos(); - xyzLoc1[1] = xyzLoc2[1] = pp->GetColPos(j) + pp->GetColSize(j) / 2.f; - xyzLoc1[2] = pp->GetRow0() - pp->GetRowPos(pp->GetNrows() / 2); - xyzLoc2[2] = pp->GetRowEnd() - pp->GetRowPos(pp->GetNrows() / 2); - matrix->LocalToMaster(xyzLoc1, xyzGlb1); - matrix->LocalToMaster(xyzLoc2, xyzGlb2); - float x1Tmp = xyzGlb1[0]; - xyzGlb1[0] = xyzGlb1[0] * cosf(alpha) + xyzGlb1[1] * sinf(alpha); - xyzGlb1[1] = -x1Tmp * sinf(alpha) + xyzGlb1[1] * cosf(alpha); - float x2Tmp = xyzGlb2[0]; - xyzGlb2[0] = xyzGlb2[0] * cosf(alpha) + xyzGlb2[1] * sinf(alpha); - xyzGlb2[1] = -x2Tmp * sinf(alpha) + xyzGlb2[1] * cosf(alpha); - mVertexBuffer[sector].emplace_back(xyzGlb1[0] / GL_SCALE_FACTOR, xyzGlb1[1] / GL_SCALE_FACTOR, xyzGlb1[2] / GL_SCALE_FACTOR); - mVertexBuffer[sector].emplace_back(xyzGlb2[0] / GL_SCALE_FACTOR, xyzGlb2[1] / GL_SCALE_FACTOR, xyzGlb2[2] / GL_SCALE_FACTOR); - } - } - } - } -#endif - insertVertexList(sector, startCountInner, mVertexBuffer[sector].size()); - return (vboList(startCount, mVertexBufferStart[sector].size() - startCount, sector)); -} - -int GPUDisplay::DrawGLScene(bool mixAnimation, float mAnimateTime) -{ - try { - if (DrawGLScene_internal(mixAnimation, mAnimateTime)) { - return (1); - } - } catch (const std::runtime_error& e) { - return (1); - } - return (0); -} - -int GPUDisplay::DrawGLScene_internal(bool mixAnimation, float mAnimateTime) -{ - bool showTimer = false; - - // Make sure event gets not overwritten during display - if (mAnimateTime < 0) { - mSemLockDisplay.Lock(); - } - - // Extract global cluster information - if (!mixAnimation && (mUpdateDLList || mResetScene)) { - showTimer = true; - mTimerDraw.ResetStart(); - mCurrentClusters = 0; - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - mCurrentClusters += sliceTracker(iSlice).NHitsTotal(); - } - if (mNMaxClusters < mCurrentClusters) { - mNMaxClusters = mCurrentClusters; - mGlobalPosPtr.reset(new float4[mNMaxClusters]); - mGlobalPos = mGlobalPosPtr.get(); - } - - mCurrentSpacePointsTRD = trdTracker().NTracklets(); - if (mCurrentSpacePointsTRD > mNMaxSpacePointsTRD) { - mNMaxSpacePointsTRD = mCurrentSpacePointsTRD; - mGlobalPosPtrTRD.reset(new float4[mNMaxSpacePointsTRD]); - mGlobalPosPtrTRD2.reset(new float4[mNMaxSpacePointsTRD]); - mGlobalPosTRD = mGlobalPosPtrTRD.get(); - mGlobalPosTRD2 = mGlobalPosPtrTRD2.get(); - } - if ((size_t)mMerger.GetConstantMem()->ioPtrs.nMergedTracks > mTRDTrackIds.size()) { - mTRDTrackIds.resize(mMerger.GetConstantMem()->ioPtrs.nMergedTracks); - } - for (unsigned int i = 0; i < mMerger.GetConstantMem()->ioPtrs.nMergedTracks; i++) { - mTRDTrackIds[i] = -1; - } - for (int i = 0; i < trdTracker().NTracks(); i++) { - if (trdTracker().Tracks()[i].GetNtracklets()) { - mTRDTrackIds[trdTracker().Tracks()[i].GetTPCtrackId()] = i; - } - } - - mMaxClusterZ = 0; - bool error = false; - GPUCA_OPENMP(parallel for num_threads(mChain->GetProcessingSettings().ompThreads) reduction(max : mMaxClusterZ)) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - if (error) { - continue; - } - int row = 0; - unsigned int nCls = mMerger.Param().par.earlyTpcTransform ? ioptrs().nClusterData[iSlice] : ioptrs().clustersNative->nClustersSector[iSlice]; - for (unsigned int i = 0; i < nCls; i++) { - int cid; - if (mMerger.Param().par.earlyTpcTransform) { - const auto& cl = ioptrs().clusterData[iSlice][i]; - cid = cl.id; - } else { - cid = ioptrs().clustersNative->clusterOffset[iSlice][0] + i; - while (row < GPUCA_ROW_COUNT && ioptrs().clustersNative->clusterOffset[iSlice][row + 1] <= (unsigned int)cid) { - row++; - } - } - if (cid >= mNMaxClusters) { - GPUError("Cluster Buffer Size exceeded (id %d max %d)", cid, mNMaxClusters); - error = true; - break; - } - float4* ptr = &mGlobalPos[cid]; - if (mMerger.Param().par.earlyTpcTransform) { - const auto& cl = ioptrs().clusterData[iSlice][i]; - mChain->GetParam().Slice2Global(iSlice, cl.x + mXadd, cl.y, cl.z, &ptr->x, &ptr->y, &ptr->z); - } else { - float x, y, z; - const auto& cln = ioptrs().clustersNative->clusters[iSlice][0][i]; - GPUTPCConvertImpl::convert(*mMerger.GetConstantMem(), iSlice, row, cln.getPad(), cln.getTime(), x, y, z); - mChain->GetParam().Slice2Global(iSlice, x + mXadd, y, z, &ptr->x, &ptr->y, &ptr->z); - } - - if (fabsf(ptr->z) > mMaxClusterZ) { - mMaxClusterZ = fabsf(ptr->z); - } - if (iSlice < 18) { - ptr->z += mZadd; - ptr->z += mZadd; - } else { - ptr->z -= mZadd; - ptr->z -= mZadd; - } - - ptr->x /= GL_SCALE_FACTOR; - ptr->y /= GL_SCALE_FACTOR; - ptr->z /= GL_SCALE_FACTOR; - ptr->w = tCLUSTER; - } - } - if (error) { - return (1); - } - - GPUCA_OPENMP(parallel for num_threads(mChain->GetProcessingSettings().ompThreads) reduction(max : mMaxClusterZ)) - for (int i = 0; i < mCurrentSpacePointsTRD; i++) { - const auto& sp = trdTracker().SpacePoints()[i]; - int iSec = mChain->GetTRDGeometry()->GetSector(trdTracker().Tracklets()[i].GetDetector()); - float4* ptr = &mGlobalPosTRD[i]; - mChain->GetParam().Slice2Global(iSec, sp.mR + mXadd, sp.mX[0], sp.mX[1], &ptr->x, &ptr->y, &ptr->z); - ptr->x /= GL_SCALE_FACTOR; - ptr->y /= GL_SCALE_FACTOR; - ptr->z /= GL_SCALE_FACTOR; - if (fabsf(ptr->z) > mMaxClusterZ) { - mMaxClusterZ = fabsf(ptr->z); - } - ptr->w = tTRDCLUSTER; - ptr = &mGlobalPosTRD2[i]; - mChain->GetParam().Slice2Global(iSec, sp.mR + mXadd + 4.5f, sp.mX[0] + 1.5f * sp.mDy, sp.mX[1], &ptr->x, &ptr->y, &ptr->z); - ptr->x /= GL_SCALE_FACTOR; - ptr->y /= GL_SCALE_FACTOR; - ptr->z /= GL_SCALE_FACTOR; - if (fabsf(ptr->z) > mMaxClusterZ) { - mMaxClusterZ = fabsf(ptr->z); - } - ptr->w = tTRDCLUSTER; - } - - mTimerFPS.ResetStart(); - mFramesDoneFPS = 0; - mFPSScaleadjust = 0; - mGlDLrecent = 0; - mUpdateDLList = 0; - } - - if (!mixAnimation && mOffscreenBuffer.created) { - setFrameBuffer(1, mOffscreenBuffer.fb_id); - } - // Initialize - if (!mixAnimation) { - if (mInvertColors) { - CHKERR(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); - } else { - CHKERR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); - } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer - } - - hmm_mat4 nextViewMatrix = MY_HMM_IDENTITY; - int mMouseWheelTmp = mBackend->mMouseWheel; - mBackend->mMouseWheel = 0; - bool lookOrigin = mCamLookOrigin ^ mBackend->mKeys[mBackend->KEY_ALT]; - bool yUp = mCamYUp ^ mBackend->mKeys[mBackend->KEY_CTRL] ^ lookOrigin; - - // Calculate rotation / translation scaling factors - float scalefactor = mBackend->mKeys[mBackend->KEY_SHIFT] ? 0.2 : 1.0; - float rotatescalefactor = scalefactor * 0.25f; - if (mCfg.drawSlice != -1) { - scalefactor *= 0.2f; - } - float sqrdist = sqrtf(sqrtf(mViewMatrixP[12] * mViewMatrixP[12] + mViewMatrixP[13] * mViewMatrixP[13] + mViewMatrixP[14] * mViewMatrixP[14]) / GL_SCALE_FACTOR) * 0.8; - if (sqrdist < 0.2) { - sqrdist = 0.2; - } - if (sqrdist > 5) { - sqrdist = 5; - } - scalefactor *= sqrdist; - - float mixSlaveImage = 0.f; - float time = mAnimateTime; - if (mAnimate && time < 0) { - if (mAnimateScreenshot) { - time = mAnimationFrame / 30.f; - } else { - time = mAnimationTimer.GetCurrentElapsedTime(); - } - - float maxTime = mAnimateVectors[0].back(); - mAnimationFrame++; - if (time >= maxTime) { - time = maxTime; - mAnimate = 0; - SetInfo("Animation finished. (%1.2f seconds, %d frames)", time, mAnimationFrame); - } else { - SetInfo("Running mAnimation: time %1.2f/%1.2f, frames %d", time, maxTime, mAnimationFrame); - } - } - // Perform new rotation / translation - if (mAnimate) { - float vals[8]; - for (int i = 0; i < 8; i++) { - vals[i] = mAnimationSplines[i].evaluate(time); - } - if (mAnimationChangeConfig && mixAnimation == false) { - int base = 0; - int k = mAnimateVectors[0].size() - 1; - while (base < k && time > mAnimateVectors[0][base]) { - base++; - } - if (base > mAnimationLastBase + 1) { - mAnimationLastBase = base - 1; - } - - if (base != mAnimationLastBase && mAnimateVectors[0][mAnimationLastBase] != mAnimateVectors[0][base] && memcmp(&mAnimateConfig[base], &mAnimateConfig[mAnimationLastBase], sizeof(mAnimateConfig[base]))) { - mCfg = mAnimateConfig[mAnimationLastBase]; - updateConfig(); - if (mDrawQualityRenderToTexture) { - setFrameBuffer(1, mMixBuffer.fb_id); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer - DrawGLScene_internal(true, time); - setFrameBuffer(); - } else { - DrawGLScene_internal(true, time); - CHKERR(glBlitNamedFramebuffer(mMainBufferStack.back(), mMixBuffer.fb_id, 0, 0, mRenderwidth, mRenderheight, 0, 0, mRenderwidth, mRenderheight, GL_COLOR_BUFFER_BIT, GL_NEAREST)); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer - } - mixSlaveImage = 1.f - (time - mAnimateVectors[0][mAnimationLastBase]) / (mAnimateVectors[0][base] - mAnimateVectors[0][mAnimationLastBase]); - } - - if (memcmp(&mAnimateConfig[base], &mCfg, sizeof(mCfg))) { - mCfg = mAnimateConfig[base]; - updateConfig(); - } - } - - if (mCfg.animationMode != 6) { - if (mCfg.animationMode & 1) // Rotation from euler angles - { - nextViewMatrix = nextViewMatrix * HMM_Rotate(-vals[4] * 180.f / M_PI, {1, 0, 0}) * HMM_Rotate(vals[5] * 180.f / M_PI, {0, 1, 0}) * HMM_Rotate(-vals[6] * 180.f / M_PI, {0, 0, 1}); - } else { // Rotation from quaternion - const float mag = sqrtf(vals[4] * vals[4] + vals[5] * vals[5] + vals[6] * vals[6] + vals[7] * vals[7]); - if (mag < 0.0001) { - vals[7] = 1; - } else { - for (int i = 0; i < 4; i++) { - vals[4 + i] /= mag; - } - } - - float xx = vals[4] * vals[4], xy = vals[4] * vals[5], xz = vals[4] * vals[6], xw = vals[4] * vals[7], yy = vals[5] * vals[5], yz = vals[5] * vals[6], yw = vals[5] * vals[7], zz = vals[6] * vals[6], zw = vals[6] * vals[7]; - float mat[16] = {1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, 0, 0, 0, 1}; - nextViewMatrix = nextViewMatrix * MY_HMM_FROM(mat); - } - } - if (mCfg.animationMode & 4) // Compute cartesian translation from sperical coordinates (euler angles) - { - const float r = vals[3], phi = vals[1], theta = vals[2]; - vals[2] = r * cosf(phi) * cosf(theta); - vals[0] = r * sinf(phi) * cosf(theta); - vals[1] = r * sinf(theta); - } else if (mCfg.animationMode & 2) { // Scale cartesion translation to interpolated radius - float r = sqrtf(vals[0] * vals[0] + vals[1] * vals[1] + vals[2] * vals[2]); - if (fabsf(r) < 0.0001) { - r = 1; - } - r = vals[3] / r; - for (int i = 0; i < 3; i++) { - vals[i] *= r; - } - } - if (mCfg.animationMode == 6) { - nextViewMatrix = HMM_LookAt({vals[0], vals[1], vals[2]}, {0, 0, 0}, {0, 1, 0}); - } else { - nextViewMatrix = nextViewMatrix * HMM_Translate({-vals[0], -vals[1], -vals[2]}); - } - } else if (mResetScene) { - nextViewMatrix = nextViewMatrix * HMM_Translate({0, 0, param().par.ContinuousTracking ? (-mMaxClusterZ / GL_SCALE_FACTOR - 8) : -8}); - - mCfg.pointSize = 2.0; - mCfg.drawSlice = -1; - mXadd = mZadd = 0; - mCamLookOrigin = mCamYUp = false; - mAngleRollOrigin = -1e9; - - mResetScene = 0; - } else { - float moveZ = scalefactor * ((float)mMouseWheelTmp / 150 + (float)(mBackend->mKeys['W'] - mBackend->mKeys['S']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]) * 0.2 * mFPSScale); - float moveY = scalefactor * ((float)(mBackend->mKeys[mBackend->KEY_PAGEDOWN] - mBackend->mKeys[mBackend->KEY_PAGEUP]) * 0.2 * mFPSScale); - float moveX = scalefactor * ((float)(mBackend->mKeys['A'] - mBackend->mKeys['D']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]) * 0.2 * mFPSScale); - float rotRoll = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys['E'] - mBackend->mKeys['F']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]); - float rotYaw = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys[mBackend->KEY_RIGHT] - mBackend->mKeys[mBackend->KEY_LEFT]); - float rotPitch = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys[mBackend->KEY_DOWN] - mBackend->mKeys[mBackend->KEY_UP]); - - if (mBackend->mMouseDnR && mBackend->mMouseDn) { - moveZ += -scalefactor * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY) / 4; - rotRoll += rotatescalefactor * ((float)mBackend->mouseMvX - (float)mBackend->mMouseDnX); - } else if (mBackend->mMouseDnR) { - moveX += -scalefactor * 0.5 * ((float)mBackend->mMouseDnX - (float)mBackend->mouseMvX) / 4; - moveY += -scalefactor * 0.5 * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY) / 4; - } else if (mBackend->mMouseDn) { - rotYaw += rotatescalefactor * ((float)mBackend->mouseMvX - (float)mBackend->mMouseDnX); - rotPitch += rotatescalefactor * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY); - } - - if (mBackend->mKeys['<'] && !mBackend->mKeysShift['<']) { - mAnimationDelay += moveX; - if (mAnimationDelay < 0.05) { - mAnimationDelay = 0.05; - } - moveX = 0.f; - moveY = 0.f; - SetInfo("Animation delay set to %1.2f", mAnimationDelay); - } - - if (yUp) { - mAngleRollOrigin = 0; - } else if (!lookOrigin) { - mAngleRollOrigin = -1e6; - } - if (lookOrigin) { - if (!yUp) { - if (mAngleRollOrigin < -1e6) { - mAngleRollOrigin = yUp ? 0. : -mAngle[2]; - } - mAngleRollOrigin += rotRoll; - nextViewMatrix = nextViewMatrix * HMM_Rotate(mAngleRollOrigin, {0, 0, 1}); - float tmpX = moveX, tmpY = moveY; - moveX = tmpX * cosf(mAngle[2]) - tmpY * sinf(mAngle[2]); - moveY = tmpX * sinf(mAngle[2]) + tmpY * cosf(mAngle[2]); - } - - const float x = mXYZ[0], y = mXYZ[1], z = mXYZ[2]; - float r = sqrtf(x * x + +y * y + z * z); - float r2 = sqrtf(x * x + z * z); - float phi = atan2f(z, x); - phi += moveX * 0.1f; - float theta = atan2f(mXYZ[1], r2); - theta -= moveY * 0.1f; - const float max_theta = M_PI / 2 - 0.01; - if (theta >= max_theta) { - theta = max_theta; - } else if (theta <= -max_theta) { - theta = -max_theta; - } - if (moveZ >= r - 0.1) { - moveZ = r - 0.1; - } - r -= moveZ; - r2 = r * cosf(theta); - mXYZ[0] = r2 * cosf(phi); - mXYZ[2] = r2 * sinf(phi); - mXYZ[1] = r * sinf(theta); - - nextViewMatrix = HMM_LookAt({mXYZ[0], mXYZ[1], mXYZ[2]}, {0, 0, 0}, {0, 1, 0}); - } else { - nextViewMatrix = nextViewMatrix * HMM_Translate({moveX, moveY, moveZ}); - if (rotYaw != 0.f) { - nextViewMatrix = nextViewMatrix * HMM_Rotate(rotYaw, {0, 1, 0}); - } - if (rotPitch != 0.f) { - nextViewMatrix = nextViewMatrix * HMM_Rotate(rotPitch, {1, 0, 0}); - } - if (!yUp && rotRoll != 0.f) { - nextViewMatrix = nextViewMatrix * HMM_Rotate(rotRoll, {0, 0, 1}); - } - - nextViewMatrix = nextViewMatrix * mViewMatrix; // Apply previous translation / rotation - - if (yUp) { - calcXYZ(&nextViewMatrix.Elements[0][0]); - nextViewMatrix = HMM_Rotate(mAngle[2] * 180.f / M_PI, {0, 0, 1}) * nextViewMatrix; - } - } - - // Graphichs Options - float minSize = 0.4 / (mDrawQualityDownsampleFSAA > 1 ? mDrawQualityDownsampleFSAA : 1); - int deltaLine = mBackend->mKeys['+'] * mBackend->mKeysShift['+'] - mBackend->mKeys['-'] * mBackend->mKeysShift['-']; - mCfg.lineWidth += (float)deltaLine * mFPSScale * 0.02 * mCfg.lineWidth; - if (mCfg.lineWidth < minSize) { - mCfg.lineWidth = minSize; - } - if (deltaLine) { - SetInfo("%s line width: %f", deltaLine > 0 ? "Increasing" : "Decreasing", mCfg.lineWidth); - } - minSize *= 2; - int deltaPoint = mBackend->mKeys['+'] * (!mBackend->mKeysShift['+']) - mBackend->mKeys['-'] * (!mBackend->mKeysShift['-']); - mCfg.pointSize += (float)deltaPoint * mFPSScale * 0.02 * mCfg.pointSize; - if (mCfg.pointSize < minSize) { - mCfg.pointSize = minSize; - } - if (deltaPoint) { - SetInfo("%s point size: %f", deltaPoint > 0 ? "Increasing" : "Decreasing", mCfg.pointSize); - } - } - - // Store position - if (mAnimateTime < 0) { - mViewMatrix = nextViewMatrix; - calcXYZ(mViewMatrixP); - } - - if (mBackend->mMouseDn || mBackend->mMouseDnR) { - mBackend->mMouseDnX = mBackend->mouseMvX; - mBackend->mMouseDnY = mBackend->mouseMvY; - } -#ifndef GPUCA_DISPLAY_OPENGL_CORE - if (mCfg.smoothPoints) { - CHKERR(glEnable(GL_POINT_SMOOTH)); - } else { - CHKERR(glDisable(GL_POINT_SMOOTH)); - } - if (mCfg.smoothLines) { - CHKERR(glEnable(GL_LINE_SMOOTH)); - } else { - CHKERR(glDisable(GL_LINE_SMOOTH)); - } -#endif - CHKERR(glEnable(GL_BLEND)); - CHKERR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - CHKERR(glPointSize(mCfg.pointSize * (mDrawQualityDownsampleFSAA > 1 ? mDrawQualityDownsampleFSAA : 1))); - CHKERR(glLineWidth(mCfg.lineWidth * (mDrawQualityDownsampleFSAA > 1 ? mDrawQualityDownsampleFSAA : 1))); - - // Prepare Event - if (!mGlDLrecent) { - for (int i = 0; i < NSLICES; i++) { - mVertexBuffer[i].clear(); - mVertexBufferStart[i].clear(); - mVertexBufferCount[i].clear(); - } - - for (int i = 0; i < mCurrentClusters; i++) { - mGlobalPos[i].w = tCLUSTER; - } - for (int i = 0; i < mCurrentSpacePointsTRD; i++) { - mGlobalPosTRD[i].w = tTRDCLUSTER; - } - - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - for (int i = 0; i < N_POINTS_TYPE; i++) { - mGlDLPoints[iSlice][i].resize(mNCollissions); - } - for (int i = 0; i < N_FINAL_TYPE; i++) { - mGlDLFinal[iSlice].resize(mNCollissions); - } - } - GPUCA_OPENMP(parallel num_threads(mChain->GetProcessingSettings().ompThreads)) - { -#ifdef WITH_OPENMP - int numThread = omp_get_thread_num(); - int numThreads = omp_get_num_threads(); -#else - int numThread = 0, numThreads = 1; -#endif - GPUCA_OPENMP(for) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - GPUTPCTracker& tracker = (GPUTPCTracker&)sliceTracker(iSlice); - tracker.SetPointersDataLinks(tracker.LinkTmpMemory()); - mGlDLLines[iSlice][tINITLINK] = DrawLinks(tracker, tINITLINK, true); - tracker.SetPointersDataLinks(mChain->rec()->Res(tracker.MemoryResLinks()).Ptr()); - } - GPUTPCGMPropagator prop; - prop.SetMaxSinPhi(.999); - prop.SetMaterialTPC(); - prop.SetPolynomialField(&mMerger.Param().polynomialField); - prop.SetToyMCEventsFlag(mMerger.Param().par.ToyMCEventsFlag); - - GPUCA_OPENMP(barrier) - GPUCA_OPENMP(for) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - const GPUTPCTracker& tracker = sliceTracker(iSlice); - - mGlDLLines[iSlice][tLINK] = DrawLinks(tracker, tLINK); - mGlDLLines[iSlice][tSEED] = DrawSeeds(tracker); - mGlDLLines[iSlice][tTRACKLET] = DrawTracklets(tracker); - mGlDLLines[iSlice][tSLICETRACK] = DrawTracks(tracker, 0); - mGlDLGrid[iSlice] = DrawGrid(tracker); - if (iSlice < NSLICES / 2) { - mGlDLGridTRD[iSlice] = DrawGridTRD(iSlice); - } - } - - GPUCA_OPENMP(barrier) - GPUCA_OPENMP(for) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - const GPUTPCTracker& tracker = sliceTracker(iSlice); - mGlDLLines[iSlice][tGLOBALTRACK] = DrawTracks(tracker, 1); - } - - GPUCA_OPENMP(barrier) - mThreadTracks[numThread].resize(mNCollissions); - for (int i = 0; i < mNCollissions; i++) { - for (int j = 0; j < NSLICES; j++) { - for (int k = 0; k < 2; k++) { - mThreadTracks[numThread][i][j][k].clear(); - } - } - } - GPUCA_OPENMP(for) - for (unsigned int i = 0; i < mMerger.GetConstantMem()->ioPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack* track = &mMerger.GetConstantMem()->ioPtrs.mergedTracks[i]; - if (track->NClusters() == 0) { - continue; - } - if (mHideRejectedTracks && !track->OK()) { - continue; - } - int slice = mMerger.GetConstantMem()->ioPtrs.mergedTrackHits[track->FirstClusterRef() + track->NClusters() - 1].slice; - unsigned int col = 0; - if (mNCollissions > 1) { - int label = mQA ? mQA->GetMCTrackLabel(i) : -1; - while (col < mCollisionClusters.size() && mCollisionClusters[col][NSLICES] < label) { - col++; - } - } - mThreadTracks[numThread][col][slice][0].emplace_back(i); - } - GPUCA_OPENMP(for) - for (unsigned int i = 0; i < ioptrs().nMCInfosTPC; i++) { - const GPUTPCMCInfo& mc = ioptrs().mcInfosTPC[i]; - if (mc.charge == 0.f) { - continue; - } - if (mc.pid < 0) { - continue; - } - - float alpha = atan2f(mc.y, mc.x); - if (alpha < 0) { - alpha += 2 * M_PI; - } - int slice = alpha / (2 * M_PI) * 18; - if (mc.z < 0) { - slice += 18; - } - unsigned int col = 0; - if (mNCollissions > 1) { - while (col < mCollisionClusters.size() && mCollisionClusters[col][NSLICES] < (int)i) { - col++; - } - } - mThreadTracks[numThread][col][slice][1].emplace_back(i); - } - GPUCA_OPENMP(barrier) - GPUCA_OPENMP(for) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - for (int iCol = 0; iCol < mNCollissions; iCol++) { - mThreadBuffers[numThread].clear(); - for (int iSet = 0; iSet < numThreads; iSet++) { - DrawFinal(iSlice, iCol, &prop, mThreadTracks[iSet][iCol][iSlice], mThreadBuffers[numThread]); - } - vboList* list = &mGlDLFinal[iSlice][iCol][0]; - for (int i = 0; i < N_FINAL_TYPE; i++) { - size_t startCount = mVertexBufferStart[iSlice].size(); - for (unsigned int j = 0; j < mThreadBuffers[numThread].start[i].size(); j++) { - mVertexBufferStart[iSlice].emplace_back(mThreadBuffers[numThread].start[i][j]); - mVertexBufferCount[iSlice].emplace_back(mThreadBuffers[numThread].count[i][j]); - } - list[i] = vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice); - } - } - } - - GPUCA_OPENMP(barrier) - GPUCA_OPENMP(for) - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - const GPUTPCTracker& tracker = sliceTracker(iSlice); - for (int i = 0; i < N_POINTS_TYPE_TPC; i++) { - for (int iCol = 0; iCol < mNCollissions; iCol++) { - mGlDLPoints[iSlice][i][iCol] = DrawClusters(tracker, i, iCol); - } - } - } - } - // End omp parallel - - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - for (int i = N_POINTS_TYPE_TPC; i < N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD; i++) { - for (int iCol = 0; iCol < mNCollissions; iCol++) { - mGlDLPoints[iSlice][i][iCol] = DrawSpacePointsTRD(iSlice, i, iCol); - } - } - } - - mGlDLrecent = 1; - size_t totalVertizes = 0; - for (int i = 0; i < NSLICES; i++) { - totalVertizes += mVertexBuffer[i].size(); - } - - // TODO: Check if this can be parallelized - mUseMultiVBO = (totalVertizes * sizeof(mVertexBuffer[0][0]) >= 0x100000000ll); - if (mUseMultiVBO) { - for (int i = 0; i < NSLICES; i++) { - CHKERR(glNamedBufferData(mVBOId[i], mVertexBuffer[i].size() * sizeof(mVertexBuffer[i][0]), mVertexBuffer[i].data(), GL_STATIC_DRAW)); - mVertexBuffer[i].clear(); - } - } else { - size_t totalYet = mVertexBuffer[0].size(); - mVertexBuffer[0].resize(totalVertizes); - for (int i = 1; i < NSLICES; i++) { - for (unsigned int j = 0; j < mVertexBufferStart[i].size(); j++) { - mVertexBufferStart[i][j] += totalYet; - } - memcpy(&mVertexBuffer[0][totalYet], &mVertexBuffer[i][0], mVertexBuffer[i].size() * sizeof(mVertexBuffer[i][0])); - totalYet += mVertexBuffer[i].size(); - mVertexBuffer[i].clear(); - } - CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0])); // Bind ahead of time, since it is not going to change - CHKERR(glNamedBufferData(mVBOId[0], totalVertizes * sizeof(mVertexBuffer[0][0]), mVertexBuffer[0].data(), GL_STATIC_DRAW)); - mVertexBuffer[0].clear(); - } - - if (mUseGLIndirectDraw) { - mCmdBuffer.clear(); - for (int iSlice = 0; iSlice < NSLICES; iSlice++) { - mIndirectSliceOffset[iSlice] = mCmdBuffer.size(); - for (unsigned int k = 0; k < mVertexBufferStart[iSlice].size(); k++) { - mCmdBuffer.emplace_back(mVertexBufferCount[iSlice][k], 1, mVertexBufferStart[iSlice][k], 0); - } - } - CHKERR(glBufferData(GL_DRAW_INDIRECT_BUFFER, mCmdBuffer.size() * sizeof(mCmdBuffer[0]), mCmdBuffer.data(), GL_STATIC_DRAW)); - } - - if (showTimer) { - printf("Event visualization time: %'d us (vertices %'lld / %'lld bytes)\n", (int)(mTimerDraw.GetCurrentElapsedTime() * 1000000.), (long long int)totalVertizes, (long long int)(totalVertizes * sizeof(mVertexBuffer[0][0]))); - } - } - - // Draw Event - mNDrawCalls = 0; -#ifndef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glEnableClientState(GL_VERTEX_ARRAY)); - CHKERR(glVertexPointer(3, GL_FLOAT, 0, nullptr)); -#else - CHKERR(glBindVertexArray(mVertexArray)); - CHKERR(glUseProgram(mShaderProgram)); - CHKERR(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr)); - CHKERR(glEnableVertexAttribArray(0)); -#endif - - { - const hmm_mat4 proj = HMM_Perspective(45.0f, (GLfloat)mScreenwidth / (GLfloat)mScreenheight, 0.1f, 1000.0f); -#ifndef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glMatrixMode(GL_PROJECTION)); - CHKERR(glLoadMatrixf(&proj.Elements[0][0])); - CHKERR(glMatrixMode(GL_MODELVIEW)); - CHKERR(glLoadMatrixf(&nextViewMatrix.Elements[0][0])); -#else - const hmm_mat4 modelViewProj = proj * nextViewMatrix; - CHKERR(glUniformMatrix4fv(mModelViewProjId, 1, GL_FALSE, &modelViewProj.Elements[0][0])); -#endif - } - -#define LOOP_SLICE for (int iSlice = (mCfg.drawSlice == -1 ? 0 : mCfg.drawRelatedSlices ? (mCfg.drawSlice % (NSLICES / 4)) : mCfg.drawSlice); iSlice < NSLICES; iSlice += (mCfg.drawSlice == -1 ? 1 : mCfg.drawRelatedSlices ? (NSLICES / 4) : NSLICES)) -#define LOOP_SLICE2 for (int iSlice = (mCfg.drawSlice == -1 ? 0 : mCfg.drawRelatedSlices ? (mCfg.drawSlice % (NSLICES / 4)) : mCfg.drawSlice) % (NSLICES / 2); iSlice < NSLICES / 2; iSlice += (mCfg.drawSlice == -1 ? 1 : mCfg.drawRelatedSlices ? (NSLICES / 4) : NSLICES)) -#define LOOP_COLLISION for (int iCol = (mCfg.showCollision == -1 ? 0 : mCfg.showCollision); iCol < mNCollissions; iCol += (mCfg.showCollision == -1 ? 1 : mNCollissions)) -#define LOOP_COLLISION_COL(cmd) \ - LOOP_COLLISION \ - { \ - if (mCfg.colorCollisions) { \ - SetCollisionColor(iCol); \ - } \ - cmd; \ - } - - if (mCfg.drawGrid) { - if (mCfg.drawTPC) { - SetColorGrid(); - LOOP_SLICE drawVertices(mGlDLGrid[iSlice], GL_LINES); - } - if (mCfg.drawTRD) { - SetColorGridTRD(); - LOOP_SLICE2 drawVertices(mGlDLGridTRD[iSlice], GL_LINES); - } - } - if (mCfg.drawClusters) { - if (mCfg.drawTRD) { - SetColorTRD(); - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRDCLUSTER][iCol], GL_LINES)); - if (mCfg.drawFinal) { - if (mCfg.colorClusters) { - SetColorFinal(); - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRDATTACHED][iCol], GL_POINTS)); - } else { - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRDATTACHED][iCol], GL_LINES)); - } - } - if (mCfg.drawTPC) { - SetColorClusters(); - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tCLUSTER][iCol], GL_POINTS)); - - if (mCfg.drawInitLinks) { - if (mCfg.excludeClusters) { - goto skip1; - } - if (mCfg.colorClusters) { - SetColorInitLinks(); - } - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tINITLINK][iCol], GL_POINTS)); - - if (mCfg.drawLinks) { - if (mCfg.excludeClusters) { - goto skip1; - } - if (mCfg.colorClusters) { - SetColorLinks(); - } - } else { - SetColorClusters(); - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tLINK][iCol], GL_POINTS)); - - if (mCfg.drawSeeds) { - if (mCfg.excludeClusters) { - goto skip1; - } - if (mCfg.colorClusters) { - SetColorSeeds(); - } - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tSEED][iCol], GL_POINTS)); - - skip1: - SetColorClusters(); - if (mCfg.drawTracklets) { - if (mCfg.excludeClusters) { - goto skip2; - } - if (mCfg.colorClusters) { - SetColorTracklets(); - } - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRACKLET][iCol], GL_POINTS)); - - if (mCfg.drawTracks) { - if (mCfg.excludeClusters) { - goto skip2; - } - if (mCfg.colorClusters) { - SetColorTracks(); - } - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tSLICETRACK][iCol], GL_POINTS)); - - skip2:; - if (mCfg.drawGlobalTracks) { - if (mCfg.excludeClusters) { - goto skip3; - } - if (mCfg.colorClusters) { - SetColorGlobalTracks(); - } - } else { - SetColorClusters(); - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tGLOBALTRACK][iCol], GL_POINTS)); - SetColorClusters(); - - if (mCfg.drawFinal && mCfg.propagateTracks < 2) { - if (mCfg.excludeClusters) { - goto skip3; - } - if (mCfg.colorClusters) { - SetColorFinal(); - } - } - LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tFINALTRACK][iCol], GL_POINTS)); - skip3:; - } - } - - if (!mConfig.clustersOnly && !mCfg.excludeClusters) { - if (mCfg.drawTPC) { - if (mCfg.drawInitLinks) { - SetColorInitLinks(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tINITLINK], GL_LINES); - } - if (mCfg.drawLinks) { - SetColorLinks(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tLINK], GL_LINES); - } - if (mCfg.drawSeeds) { - SetColorSeeds(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tSEED], GL_LINE_STRIP); - } - if (mCfg.drawTracklets) { - SetColorTracklets(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tTRACKLET], GL_LINE_STRIP); - } - if (mCfg.drawTracks) { - SetColorTracks(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tSLICETRACK], GL_LINE_STRIP); - } - if (mCfg.drawGlobalTracks) { - SetColorGlobalTracks(); - LOOP_SLICE drawVertices(mGlDLLines[iSlice][tGLOBALTRACK], GL_LINE_STRIP); - } - } - if (mCfg.drawFinal) { - SetColorFinal(); - LOOP_SLICE LOOP_COLLISION - { - if (mCfg.colorCollisions) { - SetCollisionColor(iCol); - } - if (mCfg.propagateTracks < 2) { - drawVertices(mGlDLFinal[iSlice][iCol][0], GL_LINE_STRIP); - } - if (mCfg.propagateTracks > 0 && mCfg.propagateTracks < 3) { - drawVertices(mGlDLFinal[iSlice][iCol][1], GL_LINE_STRIP); - } - if (mCfg.propagateTracks == 2) { - drawVertices(mGlDLFinal[iSlice][iCol][2], GL_LINE_STRIP); - } - if (mCfg.propagateTracks == 3) { - drawVertices(mGlDLFinal[iSlice][iCol][3], GL_LINE_STRIP); - } - } - } - if (mMarkClusters || mMarkAdjacentClusters || mMarkFakeClusters) { - if (mMarkFakeClusters) { - CHKERR(glPointSize(mCfg.pointSize * (mDrawQualityDownsampleFSAA > 1 ? mDrawQualityDownsampleFSAA : 1) * 3)); - } - SetColorMarked(); - LOOP_SLICE LOOP_COLLISION drawVertices(mGlDLPoints[iSlice][tMARKED][iCol], GL_POINTS); - } - } -#ifndef GPUCA_DISPLAY_OPENGL_CORE - CHKERR(glDisableClientState(GL_VERTEX_ARRAY)); -#else - CHKERR(glDisableVertexAttribArray(0)); - CHKERR(glUseProgram(0)); -#endif - - if (mixSlaveImage > 0) { -#ifndef GPUCA_DISPLAY_OPENGL_CORE - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - hmm_mat4 proj = HMM_Orthographic(0.f, mRenderwidth, 0.f, mRenderheight, -1.f, 1.f); - glLoadMatrixf(&proj.Elements[0][0]); - CHKERR(glEnable(GL_TEXTURE_2D)); - glDisable(GL_DEPTH_TEST); - CHKERR(glBindTexture(GL_TEXTURE_2D, mMixBuffer.fbCol_id)); - glColor4f(1, 1, 1, mixSlaveImage); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex3f(0, 0, 0); - glTexCoord2f(0, 1); - glVertex3f(0, mRenderheight, 0); - glTexCoord2f(1, 1); - glVertex3f(mRenderwidth, mRenderheight, 0); - glTexCoord2f(1, 0); - glVertex3f(mRenderwidth, 0, 0); - glEnd(); - glColor4f(1, 1, 1, 0); - CHKERR(glDisable(GL_TEXTURE_2D)); - setDepthBuffer(); -#endif - } - - if (mixAnimation) { - glColorMask(false, false, false, true); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(true, true, true, true); - } else if (mOffscreenBuffer.created) { - setFrameBuffer(); - GLuint srcid = mOffscreenBuffer.fb_id; - if (mDrawQualityMSAA > 1 && mDrawQualityDownsampleFSAA > 1) { - CHKERR(glBlitNamedFramebuffer(srcid, mOffscreenBufferNoMSAA.fb_id, 0, 0, mRenderwidth, mRenderheight, 0, 0, mRenderwidth, mRenderheight, GL_COLOR_BUFFER_BIT, GL_LINEAR)); - srcid = mOffscreenBufferNoMSAA.fb_id; - } - CHKERR(glBlitNamedFramebuffer(srcid, mMainBufferStack.back(), 0, 0, mRenderwidth, mRenderheight, 0, 0, mScreenwidth, mScreenheight, GL_COLOR_BUFFER_BIT, GL_LINEAR)); - } - - if (mAnimate && mAnimateScreenshot && mAnimateTime < 0) { - char mAnimateScreenshotFile[48]; - sprintf(mAnimateScreenshotFile, "mAnimation%d_%05d.bmp", mAnimationExport, mAnimationFrame); - DoScreenshot(mAnimateScreenshotFile, time); - } - - if (mAnimateTime < 0) { - mFramesDone++; - mFramesDoneFPS++; - double fpstime = mTimerFPS.GetCurrentElapsedTime(); - char info[1024]; - float fps = (double)mFramesDoneFPS / fpstime; - sprintf(info, - "FPS: %6.2f (Slice: %d, 1:Clusters %d, 2:Prelinks %d, 3:Links %d, 4:Seeds %d, 5:Tracklets %d, 6:Tracks %d, 7:GTracks %d, 8:Merger %d) (%d frames, %d draw calls) " - "(X %1.2f Y %1.2f Z %1.2f / R %1.2f Phi %1.1f Theta %1.1f) / Yaw %1.1f Pitch %1.1f Roll %1.1f)", - fps, mCfg.drawSlice, mCfg.drawClusters, mCfg.drawInitLinks, mCfg.drawLinks, mCfg.drawSeeds, mCfg.drawTracklets, mCfg.drawTracks, mCfg.drawGlobalTracks, mCfg.drawFinal, mFramesDone, mNDrawCalls, mXYZ[0], mXYZ[1], mXYZ[2], mRPhiTheta[0], mRPhiTheta[1] * 180 / M_PI, - mRPhiTheta[2] * 180 / M_PI, mAngle[1] * 180 / M_PI, mAngle[0] * 180 / M_PI, mAngle[2] * 180 / M_PI); - if (fpstime > 1.) { - if (mPrintInfoText & 2) { - GPUInfo("%s", info); - } - if (mFPSScaleadjust++) { - mFPSScale = 60 / fps; - } - mTimerFPS.ResetStart(); - mFramesDoneFPS = 0; - } - - if (mPrintInfoText & 1) { - setFrameBuffer(0, 0); - showInfo(info); - setFrameBuffer(-2); - } - } - - if (mAnimateTime < 0) { - mSemLockDisplay.Unlock(); - } - - return (0); -} - -void GPUDisplay::DoScreenshot(char* filename, float mAnimateTime) -{ - int SCALE_Y = screenshot_scale, SCALE_X = screenshot_scale; - - float tmpPointSize = mCfg.pointSize; - float tmpLineWidth = mCfg.lineWidth; - mCfg.pointSize *= (float)(SCALE_X + SCALE_Y) / 2.; - mCfg.lineWidth *= (float)(SCALE_X + SCALE_Y) / 2.; - - int oldWidth = mScreenwidth, oldHeight = mScreenheight; - GLfb screenshotBuffer; - - bool needBuffer = SCALE_X != 1 || SCALE_Y != 1; - - if (needBuffer) { - deleteFB(mMixBuffer); - mScreenwidth *= SCALE_X; - mScreenheight *= SCALE_Y; - mRenderwidth = mScreenwidth; - mRenderheight = mScreenheight; - createFB(screenshotBuffer, 0, 1, false); // Create screenshotBuffer of size mScreenwidth * SCALE, mRenderwidth * SCALE - UpdateOffscreenBuffers(); // Create other buffers of size mScreenwidth * SCALE * downscale, ... - setFrameBuffer(1, screenshotBuffer.fb_id); - glViewport(0, 0, mRenderwidth, mRenderheight); - DrawGLScene(false, mAnimateTime); - } - size_t size = 4 * mScreenwidth * mScreenheight; - unsigned char* pixels = new unsigned char[size]; - CHKERR(glPixelStorei(GL_PACK_ALIGNMENT, 1)); - CHKERR(glReadBuffer(needBuffer ? GL_COLOR_ATTACHMENT0 : GL_BACK)); - CHKERR(glReadPixels(0, 0, mScreenwidth, mScreenheight, GL_BGRA, GL_UNSIGNED_BYTE, pixels)); - - if (filename) { - FILE* fp = fopen(filename, "w+b"); - - BITMAPFILEHEADER bmpFH; - BITMAPINFOHEADER bmpIH; - memset(&bmpFH, 0, sizeof(bmpFH)); - memset(&bmpIH, 0, sizeof(bmpIH)); - - bmpFH.bfType = 19778; //"BM" - bmpFH.bfSize = sizeof(bmpFH) + sizeof(bmpIH) + size; - bmpFH.bfOffBits = sizeof(bmpFH) + sizeof(bmpIH); - - bmpIH.biSize = sizeof(bmpIH); - bmpIH.biWidth = mScreenwidth; - bmpIH.biHeight = mScreenheight; - bmpIH.biPlanes = 1; - bmpIH.biBitCount = 32; - bmpIH.biCompression = BI_RGB; - bmpIH.biSizeImage = size; - bmpIH.biXPelsPerMeter = 5670; - bmpIH.biYPelsPerMeter = 5670; - - fwrite(&bmpFH, 1, sizeof(bmpFH), fp); - fwrite(&bmpIH, 1, sizeof(bmpIH), fp); - fwrite(pixels, 1, size, fp); - fclose(fp); - } - delete[] pixels; - - mCfg.pointSize = tmpPointSize; - mCfg.lineWidth = tmpLineWidth; - if (needBuffer) { - setFrameBuffer(); - deleteFB(screenshotBuffer); - mScreenwidth = oldWidth; - mScreenheight = oldHeight; - UpdateOffscreenBuffers(); - glViewport(0, 0, mRenderwidth, mRenderheight); - DrawGLScene(false, mAnimateTime); - } -} - -void GPUDisplay::showInfo(const char* info) -{ -#ifndef GPUCA_DISPLAY_OPENGL_CORE - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - hmm_mat4 proj = HMM_Orthographic(0.f, mScreenwidth, 0.f, mScreenheight, -1, 1); - glLoadMatrixf(&proj.Elements[0][0]); - glViewport(0, 0, mScreenwidth, mScreenheight); -#endif - float colorValue = mInvertColors ? 0.f : 1.f; - mBackend->OpenGLPrint(info, 40.f, 40.f, colorValue, colorValue, colorValue, 1); - if (mInfoText2Timer.IsRunning()) { - if (mInfoText2Timer.GetCurrentElapsedTime() >= 6) { - mInfoText2Timer.Reset(); - } else { - mBackend->OpenGLPrint(mInfoText2, 40.f, 20.f, colorValue, colorValue, colorValue, 6 - mInfoText2Timer.GetCurrentElapsedTime()); - } - } - if (mInfoHelpTimer.IsRunning()) { - if (mInfoHelpTimer.GetCurrentElapsedTime() >= 6) { - mInfoHelpTimer.Reset(); - } else { - PrintGLHelpText(colorValue); - } - } -#ifndef GPUCA_DISPLAY_OPENGL_CORE - glViewport(0, 0, mRenderwidth, mRenderheight); -#endif -} - -void GPUDisplay::ShowNextEvent() -{ - mSemLockDisplay.Unlock(); - mBackend->mNeedUpdate = 1; - mUpdateDLList = true; -} - -void GPUDisplay::WaitForNextEvent() { mSemLockDisplay.Lock(); } - -int GPUDisplay::StartDisplay() -{ - if (mBackend->StartDisplay()) { - return (1); - } - while (mInitResult == 0) { - Sleep(10); - } - return (mInitResult != 1); -} - -#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackend.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplayBackend.cxx deleted file mode 100644 index ca3d8a3ee7f02..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackend.cxx +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayBackend.cxx -/// \author David Rohr - -#include "GPUDisplayBackend.h" -#include "GPUDisplay.h" - -using namespace GPUCA_NAMESPACE::gpu; - -void* GPUDisplayBackend::OpenGLWrapper(void* ptr) -{ - GPUDisplayBackend* me = reinterpret_cast<GPUDisplayBackend*>(ptr); - int retVal = me->OpenGLMain(); - if (retVal == -1) { - me->InitGL(true); - } - return ((void*)(size_t)retVal); -} - -void GPUDisplayBackend::HandleSendKey() -{ - if (mSendKey) { - mDisplay->HandleSendKey(mSendKey); - mSendKey = 0; - } -} - -void GPUDisplayBackend::HandleKeyRelease(unsigned char key) { mDisplay->HandleKeyRelease(key); } -int GPUDisplayBackend::DrawGLScene(bool mixAnimation, float animateTime) { return mDisplay->DrawGLScene(mixAnimation, animateTime); } -void GPUDisplayBackend::ReSizeGLScene(int width, int height) -{ - mDisplayHeight = height; - mDisplayWidth = width; - mDisplay->ReSizeGLScene(width, height); -} -int GPUDisplayBackend::InitGL(bool initFailure) { return mDisplay->InitGL(initFailure); } -void GPUDisplayBackend::ExitGL() { return mDisplay->ExitGL(); } -bool GPUDisplayBackend::EnableSendKey() { return true; } diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.cxx deleted file mode 100644 index fa576318a1071..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayBackendNone.cxx -/// \author David Rohr - -#include "GPUDisplayBackendNone.h" -using namespace GPUCA_NAMESPACE::gpu; diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.h b/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.h deleted file mode 100644 index 7e47e3c26cfe8..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendNone.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayBackendNone.h -/// \author David Rohr - -#ifndef GPUDISPLAYBACKENDNONE_H -#define GPUDISPLAYBACKENDNONE_H - -#include "GPUDisplayBackend.h" - -namespace GPUCA_NAMESPACE::gpu -{ -class GPUDisplayBackendNone : public GPUDisplayBackend -{ - GPUDisplayBackendNone() = default; - ~GPUDisplayBackendNone() override = default; - - int StartDisplay() override { return 1; } - void DisplayExit() override {} - void SwitchFullscreen(bool set) override {} - void ToggleMaximized(bool set) override {} - void SetVSync(bool enable) override {} - void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override {} -}; -} // namespace GPUCA_NAMESPACE::gpu - -#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.h b/GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.h deleted file mode 100644 index 591c36472c311..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayBackendWindows.h -/// \author David Rohr - -#ifndef GPUDISPLAYBACKENDWINDOWS_H -#define GPUDISPLAYBACKENDWINDOWS_H - -#include "GPUDisplayBackend.h" - -namespace GPUCA_NAMESPACE::gpu -{ -class GPUDisplayBackendWindows : public GPUDisplayBackend -{ - public: - GPUDisplayBackendWindows() = default; - ~GPUDisplayBackendWindows() override = default; - - int StartDisplay() override; - void DisplayExit() override; - void SwitchFullscreen(bool set) override; - void ToggleMaximized(bool set) override; - void SetVSync(bool enable) override; - void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override; - - private: - int OpenGLMain() override; -}; -} // namespace GPUCA_NAMESPACE::gpu - -#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayExt.h b/GPU/GPUTracking/Standalone/display/GPUDisplayExt.h deleted file mode 100644 index d314d1e202b05..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayExt.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayExt.h -/// \author David Rohr - -#ifndef GPUDISPLAYEXT_H -#define GPUDISPLAYEXT_H -#ifdef GPUCA_BUILD_EVENT_DISPLAY - -#include "GPUCommonDef.h" - -#if defined(GPUCA_DISPLAY_GL3W) && !defined(GPUCA_DISPLAY_OPENGL_CORE) -#define GPUCA_DISPLAY_OPENGL_CORE -#endif - -#ifdef GPUCA_DISPLAY_GL3W -#include "GL/gl3w.h" -#else -#include <GL/glew.h> -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -#ifdef GPUCA_DISPLAY_GL3W -static int GPUDisplayExtInit() -{ - return gl3wInit(); -} -#else -static int GPUDisplayExtInit() -{ - return glewInit(); -} -#endif -#ifdef GPUCA_DISPLAY_OPENGL_CORE -static constexpr bool GPUCA_DISPLAY_OPENGL_CORE_FLAGS = true; -#else -static constexpr bool GPUCA_DISPLAY_OPENGL_CORE_FLAGS = false; -#endif -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif -#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx deleted file mode 100644 index 6d453b0af8e69..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayKeys.cxx -/// \author David Rohr - -#include "GPUDisplay.h" -#ifdef GPUCA_BUILD_EVENT_DISPLAY - -using namespace GPUCA_NAMESPACE::gpu; - -const char* HelpText[] = { - "[n] / [SPACE] Next event", - "[q] / [Q] / [ESC] Quit", - "[r] Reset Display Settings", - "[l] / [k] / [J] Draw single slice (next / previous slice), draw related slices (same plane in phi)", - "[;] / [:] Show splitting of TPC in slices by extruding volume, [:] resets", - "[#] Invert colors", - "[y] / [Y] / ['] / [X] / [M] Start Animation, Add / remove Animation point, Reset Points, Cycle animation camera mode (resets)", - "[>] / [<] Toggle config interpolation during Animation / change Animation interval (via movement)", - "[g] Draw Grid", - "[i] Project onto XY-plane", - "[x] Exclude Clusters used in the tracking steps enabled for visualization ([1]-[8])", - "[.] Exclude rejected tracks", - "[c] Mark flagged clusters (splitPad = 0x1, splitTime = 0x2, edge = 0x4, singlePad = 0x8, rejectDistance = 0x10, rejectErr = 0x20", - "[z] Mark fake attached clusters", - "[B] Mark clusters attached as adjacent", - "[L] / [K] Draw single collisions (next / previous)", - "[C] Colorcode clusters of different collisions", - "[v] Hide rejected clusters from tracks", - "[j] Show global tracks as additional segments of final tracks", - "[u] Cycle through track filter", - "[E] / [G] Extrapolate tracks / loopers", - "[t] / [T] Take Screenshot / Record Animation to pictures", - "[Z] Change screenshot resolution (scaling factor)", - "[S] / [A] / [D] Enable or disable smoothing of points / smoothing of lines / depth buffer", - "[W] / [U] / [V] Toggle anti-aliasing (MSAA at raster level / change downsampling FSAA facot / toggle VSync", - "[F] / [_] / [R] Switch mFullScreen / Maximized window / FPS rate limiter", - "[I] Enable / disable GL indirect draw", - "[o] / [p] / [O] / [P] Save / restore current camera position / Animation path", - "[h] Print Help", - "[H] Show info texts", - "[w] / [s] / [a] / [d] Zoom / Strafe Left and Right", - "[pgup] / [pgdn] Strafe Up and Down", - "[e] / [f] Rotate", - "[+] / [-] Make points thicker / fainter (Hold SHIFT for lines)", - "[MOUSE 1] Look around", - "[MOUSE 2] Shift camera", - "[MOUSE 1+2] Zoom / Rotate", - "[SHIFT] Slow Zoom / Move / Rotate", - "[ALT] / [CTRL] / [m] Focus camera on origin / orient y-axis upwards (combine with [SHIFT] to lock) / Cycle through modes", - "[1] ... [8] / [N] Enable display of clusters, preseeds, seeds, starthits, tracklets, tracks, global tracks, merged tracks / Show assigned clusters in colors" - "[F1] / [F2] Enable / disable drawing of TPC / TRD" - // FREE: b - // Test setting: # --> mHideUnmatchedClusters -}; - -void GPUDisplay::PrintHelp() -{ - mInfoHelpTimer.ResetStart(); - for (unsigned int i = 0; i < sizeof(HelpText) / sizeof(HelpText[0]); i++) { - GPUInfo("%s", HelpText[i]); - } -} - -void GPUDisplay::HandleKeyRelease(unsigned char key) -{ - if (key == mBackend->KEY_ENTER || key == 'n') { - mBackend->mDisplayControl = 1; - SetInfo("Showing next event", 1); - } else if (key == 27 || key == 'q' || key == 'Q' || key == mBackend->KEY_ESCAPE) { - mBackend->mDisplayControl = 2; - SetInfo("Exiting", 1); - } else if (key == 'r') { - mResetScene = 1; - SetInfo("View reset", 1); - } else if (key == mBackend->KEY_ALT && mBackend->mKeysShift[mBackend->KEY_ALT]) { - mCamLookOrigin ^= 1; - mCameraMode = mCamLookOrigin + 2 * mCamYUp; - SetInfo("Camera locked on origin: %s", mCamLookOrigin ? "enabled" : "disabled"); - } else if (key == mBackend->KEY_CTRL && mBackend->mKeysShift[mBackend->KEY_CTRL]) { - mCamYUp ^= 1; - mCameraMode = mCamLookOrigin + 2 * mCamYUp; - SetInfo("Camera locked on y-axis facing upwards: %s", mCamYUp ? "enabled" : "disabled"); - } else if (key == 'm') { - mCameraMode++; - if (mCameraMode == 4) { - mCameraMode = 0; - } - mCamLookOrigin = mCameraMode & 1; - mCamYUp = mCameraMode & 2; - const char* modeText[] = {"Descent (free movement)", "Focus locked on origin (y-axis forced upwards)", "Spectator (y-axis forced upwards)", "Focus locked on origin (with free rotation)"}; - SetInfo("Camera mode %d: %s", mCameraMode, modeText[mCameraMode]); - } else if (key == mBackend->KEY_ALT) { - mBackend->mKeys[mBackend->KEY_CTRL] = false; // Release CTRL with alt, to avoid orienting along y automatically! - } else if (key == 'l') { - if (mCfg.drawSlice >= (mCfg.drawRelatedSlices ? (NSLICES / 4 - 1) : (NSLICES - 1))) { - mCfg.drawSlice = -1; - SetInfo("Showing all slices", 1); - } else { - mCfg.drawSlice++; - SetInfo("Showing slice %d", mCfg.drawSlice); - } - } else if (key == 'k') { - if (mCfg.drawSlice <= -1) { - mCfg.drawSlice = mCfg.drawRelatedSlices ? (NSLICES / 4 - 1) : (NSLICES - 1); - } else { - mCfg.drawSlice--; - } - if (mCfg.drawSlice == -1) { - SetInfo("Showing all slices", 1); - } else { - SetInfo("Showing slice %d", mCfg.drawSlice); - } - } else if (key == 'J') { - mCfg.drawRelatedSlices ^= 1; - SetInfo("Drawing of related slices %s", mCfg.drawRelatedSlices ? "enabled" : "disabled"); - } else if (key == 'L') { - if (mCfg.showCollision >= mNCollissions - 1) { - mCfg.showCollision = -1; - SetInfo("Showing all collisions", 1); - } else { - mCfg.showCollision++; - SetInfo("Showing collision %d", mCfg.showCollision); - } - } else if (key == 'K') { - if (mCfg.showCollision <= -1) { - mCfg.showCollision = mNCollissions - 1; - } else { - mCfg.showCollision--; - } - if (mCfg.showCollision == -1) { - SetInfo("Showing all collisions", 1); - } else { - SetInfo("Showing collision %d", mCfg.showCollision); - } - } else if (key == 'F') { - mFullScreen ^= 1; - mBackend->SwitchFullscreen(mFullScreen); - SetInfo("Toggling full screen (%d)", (int)mFullScreen); - } else if (key == '_') { - mMaximized ^= 1; - mBackend->ToggleMaximized(mMaximized); - SetInfo("Toggling mMaximized window (%d)", (int)mMaximized); - } else if (key == 'R') { - mBackend->mMaxFPSRate ^= 1; - SetInfo("FPS rate %s", mBackend->mMaxFPSRate ? "not limited" : "limited"); - } else if (key == 'H') { - mPrintInfoText += 1; - mPrintInfoText &= 3; - SetInfo("Info text display - console: %s, onscreen %s", (mPrintInfoText & 2) ? "enabled" : "disabled", (mPrintInfoText & 1) ? "enabled" : "disabled"); - } else if (key == 'j') { - mSeparateGlobalTracks ^= 1; - SetInfo("Seperated display of global tracks %s", mSeparateGlobalTracks ? "enabled" : "disabled"); - mUpdateDLList = true; - } else if (key == 'c') { - if (mMarkClusters == 0) { - mMarkClusters = 1; - } else if (mMarkClusters >= 0x20) { - mMarkClusters = 0; - } else { - mMarkClusters <<= 1; - } - SetInfo("Cluster flag highlight mask set to %d (%s)", mMarkClusters, - mMarkClusters == 0 ? "off" : mMarkClusters == 1 ? "split pad" : mMarkClusters == 2 ? "split time" : mMarkClusters == 4 ? "edge" : mMarkClusters == 8 ? "singlePad" : mMarkClusters == 0x10 ? "reject distance" : "reject error"); - mUpdateDLList = true; - } else if (key == 'z') { - mMarkFakeClusters ^= 1; - SetInfo("Marking fake clusters: %s", mMarkFakeClusters ? "on" : "off"); - mUpdateDLList = true; - } else if (key == 'B') { - mMarkAdjacentClusters++; - if (mMarkAdjacentClusters == 5) { - mMarkAdjacentClusters = 7; - } - if (mMarkAdjacentClusters == 9) { - mMarkAdjacentClusters = 15; - } - if (mMarkAdjacentClusters == 17) { - mMarkAdjacentClusters = 31; - } - if (mMarkAdjacentClusters == 34) { - mMarkAdjacentClusters = 0; - } - if (mMarkAdjacentClusters == 33) { - SetInfo("Marking protected clusters (%d)", mMarkAdjacentClusters); - } else if (mMarkAdjacentClusters == 32) { - SetInfo("Marking removable clusters (%d)", mMarkAdjacentClusters); - } else { - SetInfo("Marking adjacent clusters (%d): rejected %s, tube %s, looper leg %s, low Pt %s, high incl %s", mMarkAdjacentClusters, (mMarkAdjacentClusters & 1) ? "yes" : " no", (mMarkAdjacentClusters & 2) ? "yes" : " no", (mMarkAdjacentClusters & 4) ? "yes" : " no", (mMarkAdjacentClusters & 8) ? "yes" : " no", (mMarkAdjacentClusters & 16) ? "yes" : " no"); - } - mUpdateDLList = true; - } else if (key == 'C') { - mCfg.colorCollisions ^= 1; - SetInfo("Color coding of collisions %s", mCfg.colorCollisions ? "enabled" : "disabled"); - } else if (key == 'N') { - mCfg.colorClusters ^= 1; - SetInfo("Color coding for seed / trrack attachmend %s", mCfg.colorClusters ? "enabled" : "disabled"); - } else if (key == 'E') { - mCfg.propagateTracks += 1; - if (mCfg.propagateTracks == 4) { - mCfg.propagateTracks = 0; - } - const char* infoText[] = {"Hits connected", "Hits connected and propagated to vertex", "Reconstructed track propagated inwards and outwards", "Monte Carlo track"}; - SetInfo("Display of propagated tracks: %s", infoText[mCfg.propagateTracks]); - } else if (key == 'G') { - mPropagateLoopers ^= 1; - SetInfo("Propagation of loopers %s", mPropagateLoopers ? "enabled" : "disabled"); - mUpdateDLList = true; - } else if (key == 'v') { - mHideRejectedClusters ^= 1; - SetInfo("Rejected clusters are %s", mHideRejectedClusters ? "hidden" : "shown"); - mUpdateDLList = true; - } else if (key == 'i') { - mProjectXY ^= 1; - SetInfo("Projection onto xy plane %s", mProjectXY ? "enabled" : "disabled"); - mUpdateDLList = true; - } else if (key == 'S') { - mCfg.smoothPoints ^= true; - SetInfo("Smoothing of points %s", mCfg.smoothPoints ? "enabled" : "disabled"); - } else if (key == 'A') { - mCfg.smoothLines ^= true; - SetInfo("Smoothing of lines %s", mCfg.smoothLines ? "enabled" : "disabled"); - } else if (key == 'D') { - mCfg.depthBuffer ^= true; - GLint depthBits = 0; -#ifndef GPUCA_DISPLAY_OPENGL_CORE - glGetIntegerv(GL_DEPTH_BITS, &depthBits); -#endif - SetInfo("Depth buffer (z-buffer, %d bits) %s", depthBits, mCfg.depthBuffer ? "enabled" : "disabled"); - setDepthBuffer(); - } else if (key == 'W') { - mDrawQualityMSAA *= 2; - if (mDrawQualityMSAA < 2) { - mDrawQualityMSAA = 2; - } - if (mDrawQualityMSAA > 16) { - mDrawQualityMSAA = 0; - } - UpdateOffscreenBuffers(); - SetInfo("Multisampling anti-aliasing factor set to %d", mDrawQualityMSAA); - } else if (key == 'U') { - mDrawQualityDownsampleFSAA++; - if (mDrawQualityDownsampleFSAA == 1) { - mDrawQualityDownsampleFSAA = 2; - } - if (mDrawQualityDownsampleFSAA == 5) { - mDrawQualityDownsampleFSAA = 0; - } - UpdateOffscreenBuffers(); - SetInfo("Downsampling anti-aliasing factor set to %d", mDrawQualityDownsampleFSAA); - } else if (key == 'V') { - mDrawQualityVSync ^= true; - mBackend->SetVSync(mDrawQualityVSync); - SetInfo("VSync: %s", mDrawQualityVSync ? "enabled" : "disabled"); - } else if (key == 'I') { - mUseGLIndirectDraw ^= true; - SetInfo("OpenGL Indirect Draw %s", mUseGLIndirectDraw ? "enabled" : "disabled"); - mUpdateDLList = true; - } else if (key == ';') { - mUpdateDLList = true; - mXadd += 60; - mZadd += 60; - SetInfo("TPC sector separation: %f %f", mXadd, mZadd); - } else if (key == ':') { - mUpdateDLList = true; - mXadd -= 60; - mZadd -= 60; - if (mZadd < 0 || mXadd < 0) { - mZadd = mXadd = 0; - } - SetInfo("TPC sector separation: %f %f", mXadd, mZadd); - } else if (key == '#') { - mInvertColors ^= 1; - } else if (key == 'g') { - mCfg.drawGrid ^= 1; - SetInfo("Fast Cluster Search Grid %s", mCfg.drawGrid ? "shown" : "hidden"); - } else if (key == 'x') { - mCfg.excludeClusters ^= 1; - SetInfo(mCfg.excludeClusters ? "Clusters of selected category are excluded from display" : "Clusters are shown", 1); - } else if (key == '.') { - mHideRejectedTracks ^= 1; - SetInfo("Rejected tracks are %s", mHideRejectedTracks ? "hidden" : "shown"); - mUpdateDLList = true; - } else if (key == '1') { - mCfg.drawClusters ^= 1; - } else if (key == '2') { - mCfg.drawInitLinks ^= 1; - } else if (key == '3') { - mCfg.drawLinks ^= 1; - } else if (key == '4') { - mCfg.drawSeeds ^= 1; - } else if (key == '5') { - mCfg.drawTracklets ^= 1; - } else if (key == '6') { - mCfg.drawTracks ^= 1; - } else if (key == '7') { - mCfg.drawGlobalTracks ^= 1; - } else if (key == '8') { - mCfg.drawFinal ^= 1; - } else if (key == mBackend->KEY_F1) { - mCfg.drawTPC ^= 1; - } else if (key == mBackend->KEY_F2) { - mCfg.drawTRD ^= 1; - } else if (key == 't') { - GPUInfo("Taking screenshot"); - static int nScreenshot = 1; - char fname[32]; - sprintf(fname, "screenshot%d.bmp", nScreenshot++); - DoScreenshot(fname); - SetInfo("Taking screenshot (%s)", fname); - } else if (key == 'Z') { - screenshot_scale += 1; - if (screenshot_scale == 5) { - screenshot_scale = 1; - } - SetInfo("Screenshot scaling factor set to %d", screenshot_scale); - } else if (key == 'y' || key == 'T') { - if ((mAnimateScreenshot = (key == 'T'))) { - mAnimationExport++; - } - if (mAnimateVectors[0].size() > 1) { - startAnimation(); - SetInfo("Starting Animation", 1); - } else { - SetInfo("Insufficient Animation points to start Animation", 1); - } - } else if (key == '>') { - mAnimationChangeConfig ^= 1; - SetInfo("Interpolating visualization settings during Animation %s", mAnimationChangeConfig ? "enabled" : "disabled"); - } else if (key == 'Y') { - setAnimationPoint(); - SetInfo("Added Animation point (%d points, %6.2f seconds)", (int)mAnimateVectors[0].size(), mAnimateVectors[0].back()); - } else if (key == 'X') { - resetAnimation(); - SetInfo("Reset Animation points", 1); - } else if (key == '\'') { - removeAnimationPoint(); - SetInfo("Removed Animation point", 1); - } else if (key == 'M') { - mCfg.animationMode++; - if (mCfg.animationMode == 7) { - mCfg.animationMode = 0; - } - resetAnimation(); - if (mCfg.animationMode == 6) { - SetInfo("Animation mode %d - Centered on origin", mCfg.animationMode); - } else { - SetInfo("Animation mode %d - Position: %s, Direction: %s", mCfg.animationMode, (mCfg.animationMode & 2) ? "Spherical (spherical rotation)" : (mCfg.animationMode & 4) ? "Spherical (Euler angles)" : "Cartesian", (mCfg.animationMode & 1) ? "Euler angles" : "Quaternion"); - } - } else if (key == 'u') { - mTrackFilter = (mTrackFilter + 1) % 3; - mUpdateDLList = true; - SetInfo("Track filter: %s", mTrackFilter == 2 ? "TRD Track candidates" : mTrackFilter ? "TRD Tracks only" : "None"); - } else if (key == 'o') { - FILE* ftmp = fopen("glpos.tmp", "w+b"); - if (ftmp) { - int retval = fwrite(&mViewMatrix, sizeof(mViewMatrix), 1, ftmp); - if (retval != 1) { - GPUError("Error writing position to file"); - } else { - GPUInfo("Position stored to file"); - } - fclose(ftmp); - } else { - GPUError("Error opening file"); - } - SetInfo("Camera position stored to file", 1); - } else if (key == 'p') { - FILE* ftmp = fopen("glpos.tmp", "rb"); - if (ftmp) { - int retval = fread(&mViewMatrix, 1, sizeof(mViewMatrix), ftmp); - if (retval == sizeof(mViewMatrix)) { - GPUInfo("Position read from file"); - } else { - GPUError("Error reading position from file"); - } - fclose(ftmp); - } else { - GPUError("Error opening file"); - } - SetInfo("Camera position loaded from file", 1); - } else if (key == 'O') { - FILE* ftmp = fopen("glanimation.tmp", "w+b"); - if (ftmp) { - fwrite(&mCfg, sizeof(mCfg), 1, ftmp); - int size = mAnimateVectors[0].size(); - fwrite(&size, sizeof(size), 1, ftmp); - for (int i = 0; i < 9; i++) { - fwrite(mAnimateVectors[i].data(), sizeof(mAnimateVectors[i][0]), size, ftmp); - } - fwrite(mAnimateConfig.data(), sizeof(mAnimateConfig[0]), size, ftmp); - fclose(ftmp); - } else { - GPUError("Error opening file"); - } - SetInfo("Animation path stored to file %s", "glanimation.tmp"); - } else if (key == 'P') { - FILE* ftmp = fopen("glanimation.tmp", "rb"); - if (ftmp) { - int retval = fread(&mCfg, sizeof(mCfg), 1, ftmp); - int size; - retval += fread(&size, sizeof(size), 1, ftmp); - for (int i = 0; i < 9; i++) { - mAnimateVectors[i].resize(size); - retval += fread(mAnimateVectors[i].data(), sizeof(mAnimateVectors[i][0]), size, ftmp); - } - mAnimateConfig.resize(size); - retval += fread(mAnimateConfig.data(), sizeof(mAnimateConfig[0]), size, ftmp); - (void)retval; // disable unused warning - fclose(ftmp); - updateConfig(); - } else { - GPUError("Error opening file"); - } - SetInfo("Animation path loaded from file %s", "glanimation.tmp"); - } else if (key == 'h') { - PrintHelp(); - SetInfo("Showing help text", 1); - } - /* - else if (key == '#') - { - mTestSetting++; - SetInfo("Debug test variable set to %d", mTestSetting); - // mHideUnmatchedClusters ^= 1; - mUpdateDLList = true; - } - */ -} - -void GPUDisplay::HandleSendKey(int key) -{ - // GPUError("key %d '%c'", key, (char) key); - - bool shifted = key >= 'A' && key <= 'Z'; - int press = key; - if (press >= 'a' && press <= 'z') { - press += 'A' - 'a'; - } - bool oldShift = mBackend->mKeysShift[press]; - mBackend->mKeysShift[press] = shifted; - HandleKeyRelease(key); - mBackend->mKeysShift[press] = oldShift; -} - -void GPUDisplay::PrintGLHelpText(float colorValue) -{ - for (unsigned int i = 0; i < sizeof(HelpText) / sizeof(HelpText[0]); i++) { - mBackend->OpenGLPrint(HelpText[i], 40.f, 35 + 20 * (1 + i), colorValue, colorValue, colorValue, mInfoHelpTimer.GetCurrentElapsedTime() >= 5 ? (6 - mInfoHelpTimer.GetCurrentElapsedTime()) : 1, false); - } -} - -#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayShaders.h b/GPU/GPUTracking/Standalone/display/GPUDisplayShaders.h deleted file mode 100644 index 81b2948f1666c..0000000000000 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayShaders.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDisplayShaders.h -/// \author David Rohr - -#ifndef GPUDISPLAYSHADERS_H -#define GPUDISPLAYSHADERS_H - -#include "GPUCommonDef.h" -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ - -struct GPUDisplayShaders { - static constexpr const char* vertexShader = R"( -#version 450 core -layout (location = 0) in vec3 pos; -uniform mat4 ModelViewProj; - -void main() -{ - gl_Position = ModelViewProj * vec4(pos.x, pos.y, pos.z, 1.0); -} -)"; - - static constexpr const char* fragmentShader = R"( -#version 450 core -out vec4 fragColor; -uniform vec3 color; - -void main() -{ - fragColor = vec4(color.x, color.y, color.z, 1.f); -} -)"; -}; - -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Standalone/makefiles/.gitignore b/GPU/GPUTracking/Standalone/makefiles/.gitignore deleted file mode 100644 index b60cfbd4d33f6..0000000000000 --- a/GPU/GPUTracking/Standalone/makefiles/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.svn -as -callvc.bat diff --git a/GPU/GPUTracking/Standalone/makefiles/opencl_compiler_structs.h b/GPU/GPUTracking/Standalone/makefiles/opencl_compiler_structs.h deleted file mode 100644 index 1bf1c2afb91a4..0000000000000 --- a/GPU/GPUTracking/Standalone/makefiles/opencl_compiler_structs.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file opencl_compiler_structs.h -/// \author David Rohr - -struct _makefiles_opencl_platform_info { - char platform_profile[64]; - char platform_version[64]; - char platform_name[64]; - char platform_vendor[64]; - cl_uint count; -}; - -struct _makefiles_opencl_device_info { - char device_name[64]; - char device_vendor[64]; - cl_uint nbits; - size_t binary_size; -}; diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx deleted file mode 100644 index 3907142102bac..0000000000000 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx +++ /dev/null @@ -1,2472 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUQA.cxx -/// \author David Rohr - -#define QA_DEBUG 0 -#define QA_TIMING 0 - -#include "Rtypes.h" - -#include "TH1F.h" -#include "TH2F.h" -#include "TH1D.h" -#include "TCanvas.h" -#include "TPad.h" -#include "TLegend.h" -#include "TColor.h" -#include "TPaveText.h" -#include "TF1.h" -#include "TFile.h" -#include "TTree.h" -#include "TStyle.h" -#include "TLatex.h" -#include "TObjArray.h" -#include <sys/stat.h> - -#include "GPUQA.h" -#include "GPUTPCDef.h" -#include "GPUTPCSliceData.h" -#include "GPUChainTracking.h" -#include "GPUTPCTrack.h" -#include "GPUTPCTracker.h" -#include "GPUTPCGMMergedTrack.h" -#include "GPUTPCGMPropagator.h" -#include "AliHLTTPCClusterMCData.h" -#include "GPUTPCMCInfo.h" -#include "GPUTPCClusterData.h" -#include "GPUO2DataTypes.h" -#include "GPUParam.inc" -#include "GPUTPCClusterRejection.h" -#ifdef HAVE_O2HEADERS -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#endif -#ifdef GPUCA_O2_LIB -#include "SimulationDataFormat/MCTrack.h" -#include "SimulationDataFormat/TrackReference.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "DetectorsCommonDataFormats/NameConf.h" -#include "TPDGCode.h" -#include "TParticlePDG.h" -#include "TDatabasePDG.h" -#endif -#include "GPUQAHelper.h" -#include <algorithm> -#include <cstdio> - -#include "utils/qconfig.h" -#include "utils/timer.h" - -using namespace GPUCA_NAMESPACE::gpu; - -#ifdef GPUCA_MERGER_BY_MC_LABEL -#define CHECK_CLUSTER_STATE_INIT_LEG_BY_MC() \ - if (!unattached && mTrackMCLabels[id].isValid()) { \ - int mcLabel = mTrackMCLabels[id].getTrackID(); \ - int mcEvent = mTrackMCLabels[id].getEventID(); \ - if (mTrackMCLabelsReverse[mcEvent][mcLabel] != id) { \ - attach &= (~gputpcgmmergertypes::attachGoodLeg); \ - } \ - } -#else -#define CHECK_CLUSTER_STATE_INIT_LEG_BY_MC() -#endif - -#define CHECK_CLUSTER_STATE_INIT() \ - bool unattached = attach == 0; \ - float qpt = 0; \ - bool lowPt = false; \ - bool mev200 = false; \ - bool mergedLooper = false; \ - int id = attach & gputpcgmmergertypes::attachTrackMask; \ - if (!unattached) { \ - qpt = fabsf(mTracking->mIOPtrs.mergedTracks[id].GetParam().GetQPt()); \ - lowPt = qpt > mTracking->GetParam().rec.tpcRejectQPt; \ - mev200 = qpt > 5; \ - mergedLooper = mTracking->mIOPtrs.mergedTracks[id].MergedLooper(); \ - } \ - bool physics = false, protect = false; \ - CHECK_CLUSTER_STATE_INIT_LEG_BY_MC(); - -#define CHECK_CLUSTER_STATE() \ - CHECK_CLUSTER_STATE_INIT() \ - if (mev200) { \ - mClusterCounts.n200MeV++; \ - } \ - if (lowPt) { \ - mClusterCounts.nLowPt++; \ - } else if (mergedLooper) { \ - mClusterCounts.nMergedLooper++; \ - } else { \ - GPUTPCClusterRejection::GetProtectionStatus<true>(attach, physics, protect, &mClusterCounts, &mev200); \ - } - -#define CHECK_CLUSTER_STATE_NOCOUNT() \ - CHECK_CLUSTER_STATE_INIT() \ - (void)mev200; /* silence unused variable warning*/ \ - if (!lowPt && !mergedLooper) { \ - GPUTPCClusterRejection::GetProtectionStatus<false>(attach, physics, protect); \ - } - -#ifdef GPUCA_STANDALONE -namespace GPUCA_NAMESPACE::gpu -{ -extern GPUSettingsStandalone configStandalone; -} -#endif -static const GPUSettingsQA& GPUQA_GetConfig(GPUChainTracking* chain) -{ -#if !defined(GPUCA_STANDALONE) - static GPUSettingsQA defaultConfig; - if (chain && chain->mConfigQA) { - return *chain->mConfigQA; - } else { - return defaultConfig; - } - -#else - return configStandalone.QA; -#endif -} - -static const constexpr bool PLOT_ROOT = 0; -static const constexpr bool FIX_SCALES = 0; -static const constexpr bool PERF_FIGURE = 0; -static const constexpr float FIXED_SCALES_MIN[5] = {-0.05, -0.05, -0.2, -0.2, -0.5}; -static const constexpr float FIXED_SCALES_MAX[5] = {0.4, 0.7, 5, 3, 6.5}; -static const constexpr float LOG_PT_MIN = -1.; - -static constexpr float Y_MAX = 40; -static constexpr float Z_MAX = 100; -static constexpr float PT_MIN = GPUCA_MIN_TRACK_PT_DEFAULT; -static constexpr float PT_MIN2 = 0.1; -static constexpr float PT_MIN_PRIM = 0.1; -static constexpr float PT_MIN_CLUST = GPUCA_MIN_TRACK_PT_DEFAULT; -static constexpr float PT_MAX = 20; -static constexpr float ETA_MAX = 1.5; -static constexpr float ETA_MAX2 = 0.9; - -static constexpr float MIN_WEIGHT_CLS = 40; -static constexpr float FINDABLE_WEIGHT_CLS = 70; - -static constexpr bool CLUST_HIST_INT_SUM = false; - -static constexpr const int COLORCOUNT = 12; - -static const constexpr char* EFF_TYPES[4] = {"Rec", "Clone", "Fake", "All"}; -static const constexpr char* FINDABLE_NAMES[2] = {"", "Findable"}; -static const constexpr char* PRIM_NAMES[2] = {"Prim", "Sec"}; -static const constexpr char* PARAMETER_NAMES[5] = {"Y", "Z", "#Phi", "#lambda", "Relative #it{p}_{T}"}; -static const constexpr char* PARAMETER_NAMES_NATIVE[5] = {"Y", "Z", "sin(#Phi)", "tan(#lambda)", "q/#it{p}_{T} (curvature)"}; -static const constexpr char* VSPARAMETER_NAMES[6] = {"Y", "Z", "Phi", "Eta", "Pt", "Pt_log"}; -static const constexpr char* EFF_NAMES[3] = {"Efficiency", "Clone Rate", "Fake Rate"}; -static const constexpr char* EFFICIENCY_TITLES[4] = {"Efficiency (Primary Tracks, Findable)", "Efficiency (Secondary Tracks, Findable)", "Efficiency (Primary Tracks)", "Efficiency (Secondary Tracks)"}; -static const constexpr double SCALE[5] = {10., 10., 1000., 1000., 100.}; -static const constexpr double SCALE_NATIVE[5] = {10., 10., 1000., 1000., 1.}; -static const constexpr char* XAXIS_TITLES[5] = {"#it{y}_{mc} (cm)", "#it{z}_{mc} (cm)", "#Phi_{mc} (rad)", "#eta_{mc}", "#it{p}_{Tmc} (GeV/#it{c})"}; -static const constexpr char* AXIS_TITLES[5] = {"#it{y}-#it{y}_{mc} (mm) (Resolution)", "#it{z}-#it{z}_{mc} (mm) (Resolution)", "#phi-#phi_{mc} (mrad) (Resolution)", "#lambda-#lambda_{mc} (mrad) (Resolution)", "(#it{p}_{T} - #it{p}_{Tmc}) / #it{p}_{Tmc} (%) (Resolution)"}; -static const constexpr char* AXIS_TITLES_NATIVE[5] = {"#it{y}-#it{y}_{mc} (mm) (Resolution)", "#it{z}-#it{z}_{mc} (mm) (Resolution)", "sin(#phi)-sin(#phi_{mc}) (Resolution)", "tan(#lambda)-tan(#lambda_{mc}) (Resolution)", "q*(q/#it{p}_{T} - q/#it{p}_{Tmc}) (Resolution)"}; -static const constexpr char* AXIS_TITLES_PULL[5] = {"#it{y}-#it{y}_{mc}/#sigma_{y} (Pull)", "#it{z}-#it{z}_{mc}/#sigma_{z} (Pull)", "sin(#phi)-sin(#phi_{mc})/#sigma_{sin(#phi)} (Pull)", "tan(#lambda)-tan(#lambda_{mc})/#sigma_{tan(#lambda)} (Pull)", - "q*(q/#it{p}_{T} - q/#it{p}_{Tmc})/#sigma_{q/#it{p}_{T}} (Pull)"}; -static const constexpr char* CLUSTER_NAMES[GPUQA::N_CLS_HIST] = {"Correctly attached clusters", "Fake attached clusters", "Attached + adjacent clusters", "Fake adjacent clusters", "Clusters of reconstructed tracks", "Used in Physics", "Protected", "All clusters"}; -static const constexpr char* CLUSTER_TITLES[GPUQA::N_CLS_TYPE] = {"Clusters Pt Distribution / Attachment", "Clusters Pt Distribution / Attachment (relative to all clusters)", "Clusters Pt Distribution / Attachment (integrated)"}; -static const constexpr char* CLUSTER_NAMES_SHORT[GPUQA::N_CLS_HIST] = {"Attached", "Fake", "AttachAdjacent", "FakeAdjacent", "FoundTracks", "Physics", "Protected", "All"}; -static const constexpr char* CLUSTER_TYPES[GPUQA::N_CLS_TYPE] = {"", "Ratio", "Integral"}; -static const constexpr int COLORS_HEX[COLORCOUNT] = {0xB03030, 0x00A000, 0x0000C0, 0x9400D3, 0x19BBBF, 0xF25900, 0x7F7F7F, 0xFFD700, 0x07F707, 0x07F7F7, 0xF08080, 0x000000}; - -static const constexpr int CONFIG_DASHED_MARKERS = 0; - -static const constexpr float AXES_MIN[5] = {-Y_MAX, -Z_MAX, 0.f, -ETA_MAX, PT_MIN}; -static const constexpr float AXES_MAX[5] = {Y_MAX, Z_MAX, 2.f * M_PI, ETA_MAX, PT_MAX}; -static const constexpr int AXIS_BINS[5] = {51, 51, 144, 31, 50}; -static const constexpr int RES_AXIS_BINS[] = {1017, 113}; // Consecutive bin sizes, histograms are binned down until the maximum entry is 50, each bin size should evenly divide its predecessor. -static const constexpr float RES_AXES[5] = {1., 1., 0.03, 0.03, 1.0}; -static const constexpr float RES_AXES_NATIVE[5] = {1., 1., 0.1, 0.1, 5.0}; -static const constexpr float PULL_AXIS = 10.f; - -std::vector<TColor*> GPUQA::mColors; -int GPUQA::initColors() -{ - mColors.reserve(COLORCOUNT); - for (int i = 0; i < COLORCOUNT; i++) { - float f1 = (float)((COLORS_HEX[i] >> 16) & 0xFF) / (float)0xFF; - float f2 = (float)((COLORS_HEX[i] >> 8) & 0xFF) / (float)0xFF; - float f3 = (float)((COLORS_HEX[i] >> 0) & 0xFF) / (float)0xFF; - mColors.emplace_back(new TColor(10000 + i, f1, f2, f3)); - } - return 0; -} -static constexpr Color_t defaultColorNUms[COLORCOUNT] = {kRed, kBlue, kGreen, kMagenta, kOrange, kAzure, kBlack, kYellow, kGray, kTeal, kSpring, kPink}; - -#ifdef GPUCA_TPC_GEOMETRY_O2 -inline unsigned int GPUQA::GetNMCCollissions() -{ - return mNColTracks.size(); -} -inline unsigned int GPUQA::GetNMCTracks(int iCol) { return mNColTracks[iCol]; } -inline unsigned int GPUQA::GetNMCLabels() { return mTracking->mIOPtrs.clustersNative->clustersMCTruth ? mTracking->mIOPtrs.clustersNative->clustersMCTruth->getIndexedSize() : 0; } -inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(unsigned int iTrk, unsigned int iCol) { return mMCInfos[iCol][iTrk]; } -inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabel_t& label) { return mMCInfos[label.getEventID()][label.getTrackID()]; } -inline GPUQA::mcLabels_t GPUQA::GetMCLabel(unsigned int i) { return mTracking->mIOPtrs.clustersNative->clustersMCTruth->getLabels(i); } -inline int GPUQA::GetMCLabelNID(const mcLabels_t& label) { return label.size(); } -inline int GPUQA::GetMCLabelNID(unsigned int i) { return mTracking->mIOPtrs.clustersNative->clustersMCTruth->getLabels(i).size(); } -inline GPUQA::mcLabel_t GPUQA::GetMCLabel(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.clustersNative->clustersMCTruth->getLabels(i)[j]; } -inline int GPUQA::GetMCLabelID(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.clustersNative->clustersMCTruth->getLabels(i)[j].getTrackID(); } -inline int GPUQA::GetMCLabelID(const mcLabels_t& label, unsigned int j) { return label[j].getTrackID(); } -inline int GPUQA::GetMCLabelID(const mcLabel_t& label) { return label.getTrackID(); } -inline int GPUQA::GetMCLabelCol(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.clustersNative->clustersMCTruth->getLabels(i)[j].getEventID(); } -inline const auto& GPUQA::GetClusterLabels() { return mTracking->mIOPtrs.clustersNative->clustersMCTruth; } -inline float GPUQA::GetMCLabelWeight(unsigned int i, unsigned int j) { return 1; } -inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { return 1; } -inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return 1; } -inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && mTracking->mIOPtrs.clustersNative->clustersMCTruth && mNColTracks.size(); } -#define TRACK_EXPECTED_REFERENCE_X 78 -#else -inline GPUQA::mcLabelI_t::mcLabelI_t(const GPUQA::mcLabel_t& l) : track(l.fMCID) -{ -} -inline bool GPUQA::mcLabelI_t::operator==(const GPUQA::mcLabel_t& l) { return AbsLabelID(track) == l.fMCID; } -inline unsigned int GPUQA::GetNMCCollissions() { return 1; } -inline unsigned int GPUQA::GetNMCTracks(int iCol) { return mTracking->mIOPtrs.nMCInfosTPC; } -inline unsigned int GPUQA::GetNMCLabels() { return mTracking->mIOPtrs.nMCLabelsTPC; } -inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(unsigned int iTrk, unsigned int iCol) { return mTracking->mIOPtrs.mcInfosTPC[AbsLabelID(iTrk)]; } -inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabel_t& label) { return GetMCTrack(label.fMCID, 0); } -inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabelI_t& label) { return GetMCTrack(label.track, 0); } -inline const GPUQA::mcLabels_t& GPUQA::GetMCLabel(unsigned int i) { return mTracking->mIOPtrs.mcLabelsTPC[i]; } -inline const GPUQA::mcLabel_t& GPUQA::GetMCLabel(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j]; } -inline int GPUQA::GetMCLabelNID(const mcLabels_t& label) { return 3; } -inline int GPUQA::GetMCLabelNID(unsigned int i) { return 3; } -inline int GPUQA::GetMCLabelID(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j].fMCID; } -inline int GPUQA::GetMCLabelID(const mcLabels_t& label, unsigned int j) { return label.fClusterID[j].fMCID; } -inline int GPUQA::GetMCLabelID(const mcLabel_t& label) { return label.fMCID; } -inline int GPUQA::GetMCLabelCol(unsigned int i, unsigned int j) { return 0; } -inline const auto& GPUQA::GetClusterLabels() { return mTracking->mIOPtrs.mcLabelsTPC; } -inline float GPUQA::GetMCLabelWeight(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j].fWeight; } -inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { return label.fClusterID[j].fWeight; } -inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return label.fWeight; } -inline int GPUQA::FakeLabelID(int id) { return id < 0 ? id : (-2 - id); } -inline int GPUQA::AbsLabelID(int id) { return id >= 0 ? id : (-id - 2); } -inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && GetNMCLabels() && GetNMCTracks(0); } -#define TRACK_EXPECTED_REFERENCE_X 81 -#endif -template <class T> -inline auto& GPUQA::GetMCTrackObj(T& obj, const GPUQA::mcLabelI_t& l) -{ - return obj[l.getEventID()][l.getTrackID()]; -} - -template <> -auto GPUQA::getHistArray<TH1F>() -{ - return std::make_pair(mHist1D, &mHist1D_pos); -} -template <> -auto GPUQA::getHistArray<TH2F>() -{ - return std::make_pair(mHist2D, &mHist2D_pos); -} -template <> -auto GPUQA::getHistArray<TH1D>() -{ - return std::make_pair(mHist1Dd, &mHist1Dd_pos); -} -template <class T, typename... Args> -void GPUQA::createHist(T*& h, const char* name, Args... args) -{ - const auto& p = getHistArray<T>(); - if (mHaveExternalHists) { - if (p.first->size() <= p.second->size()) { - throw std::runtime_error("Incoming histogram array incomplete"); - } - if (strcmp((*p.first)[p.second->size()].GetName(), name)) { - throw std::runtime_error("Incoming histogram has incorrect name"); - } - } else { - p.first->emplace_back(name, args...); - } - p.second->emplace_back(&h); - h = &p.first->back(); -} - -namespace GPUCA_NAMESPACE::gpu -{ -struct GPUQAGarbageCollection { - std::tuple<std::vector<std::unique_ptr<TCanvas>>, std::vector<std::unique_ptr<TLegend>>, std::vector<std::unique_ptr<TPad>>, std::vector<std::unique_ptr<TLatex>>, std::vector<std::unique_ptr<TH1D>>> v; -}; -} // namespace GPUCA_NAMESPACE::gpu - -template <class T, typename... Args> -T* GPUQA::createGarbageCollected(Args... args) -{ - auto& v = std::get<std::vector<std::unique_ptr<T>>>(mGarbageCollector->v); - v.emplace_back(std::make_unique<T>(args...)); - return v.back().get(); -} -void GPUQA::clearGarbagageCollector() -{ - std::get<std::vector<std::unique_ptr<TPad>>>(mGarbageCollector->v).clear(); // Make sure to depete TPad first due to ROOT ownership (std::tuple has no defined order in its destructor) - std::apply([](auto&&... args) { ((args.clear()), ...); }, mGarbageCollector->v); -} - -GPUQA::GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config) : mTracking(chain), mConfig(config ? *config : GPUQA_GetConfig(chain)), mGarbageCollector(std::make_unique<GPUQAGarbageCollection>()) -{ - static int initColorsInitialized = initColors(); - (void)initColorsInitialized; - mRunForQC = chain == nullptr || mConfig.shipToQC; -} - -GPUQA::~GPUQA() -{ - if (mQAInitialized && !mHaveExternalHists) { - delete mHist1D; - delete mHist2D; - delete mHist1Dd; - } - clearGarbagageCollector(); // Needed to guarantee correct order for ROOT ownership -} - -inline bool GPUQA::MCComp(const mcLabel_t& a, const mcLabel_t& b) { return (GPUQA::GetMCLabelID(a) > GPUQA::GetMCLabelID(b)); } - -bool GPUQA::clusterRemovable(int attach, bool prot) const -{ - CHECK_CLUSTER_STATE_NOCOUNT(); - if (prot) { - return protect || physics; - } - return (!unattached && !physics && !protect); -} - -void GPUQA::SetAxisSize(TH1F* e) -{ - e->GetYaxis()->SetTitleOffset(1.0); - e->GetYaxis()->SetTitleSize(0.045); - e->GetYaxis()->SetLabelSize(0.045); - e->GetXaxis()->SetTitleOffset(1.03); - e->GetXaxis()->SetTitleSize(0.045); - e->GetXaxis()->SetLabelOffset(-0.005); - e->GetXaxis()->SetLabelSize(0.045); -} - -void GPUQA::SetLegend(TLegend* l) -{ - l->SetTextFont(72); - l->SetTextSize(0.016); - l->SetFillColor(0); -} - -double* GPUQA::CreateLogAxis(int nbins, float xmin, float xmax) -{ - float logxmin = std::log10(xmin); - float logxmax = std::log10(xmax); - float binwidth = (logxmax - logxmin) / nbins; - - double* xbins = new double[nbins + 1]; - - xbins[0] = xmin; - for (int i = 1; i <= nbins; i++) { - xbins[i] = std::pow(10, logxmin + i * binwidth); - } - return xbins; -} - -void GPUQA::ChangePadTitleSize(TPad* p, float size) -{ - p->Update(); - TPaveText* pt = (TPaveText*)(p->GetPrimitive("title")); - if (pt == nullptr) { - GPUError("Error changing title"); - } else { - pt->SetTextSize(size); - p->Modified(); - } -} - -void GPUQA::DrawHisto(TH1* histo, char* filename, char* options) -{ - TCanvas tmp; - tmp.cd(); - histo->Draw(options); - tmp.Print(filename); -} - -void GPUQA::doPerfFigure(float x, float y, float size) -{ - if (!PERF_FIGURE) { - return; - } - TLatex* t = createGarbageCollected<TLatex>(); - t->SetNDC(kTRUE); - t->SetTextColor(1); - t->SetTextSize(size); - t->DrawLatex(x, y, str_perf_figure_1); - t->DrawLatex(x, y - 0.01 - size, str_perf_figure_2); -} - -void GPUQA::SetMCTrackRange(int min, int max) -{ - mMCTrackMin = min; - mMCTrackMax = max; -} - -int GPUQA::GetMCTrackLabel(unsigned int trackId) const { return (trackId >= mTrackMCLabels.size() ? MC_LABEL_INVALID : mTrackMCLabels[trackId].getTrackID()); } - -int GPUQA::InitQACreateHistograms() -{ - char name[2048], fname[1024]; - // Create Efficiency Histograms - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - for (int l = 0; l < 5; l++) { - for (int m = 0; m < 2; m++) { - sprintf(name, "%s%s%s%sVs%s", m ? "eff" : "tracks", EFF_TYPES[i], FINDABLE_NAMES[j], PRIM_NAMES[k], VSPARAMETER_NAMES[l]); - if (l == 4) { - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], k == 0 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; - createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], binsPt.get()); - } else { - createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], AXES_MIN[l], AXES_MAX[l]); - } - if (!mHaveExternalHists) { - mEff[i][j][k][l][m]->Sumw2(); - } - } - } - } - } - } - - // Create Resolution Histograms - for (int i = 0; i < 5; i++) { - for (int j = 0; j < 5; j++) { - sprintf(name, "rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - sprintf(fname, "mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - if (j == 4) { - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; - createHist(mRes[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); - createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); - } else { - createHist(mRes[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - } - sprintf(name, "res_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - const float* axis = mConfig.nativeFitResolutions ? RES_AXES_NATIVE : RES_AXES; - const int nbins = i == 4 && mConfig.nativeFitResolutions ? (10 * RES_AXIS_BINS[0]) : RES_AXIS_BINS[0]; - if (j == 4) { - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; - createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], binsPt.get()); - } else { - createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - } - } - } - - // Create Pull Histograms - for (int i = 0; i < 5; i++) { - for (int j = 0; j < 5; j++) { - sprintf(name, "pull_rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - sprintf(fname, "pull_mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - if (j == 4) { - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; - createHist(mPull[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); - createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); - } else { - createHist(mPull[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - } - sprintf(name, "pull_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); - if (j == 4) { - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; - createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], binsPt.get()); - } else { - createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - } - } - } - - // Create Cluster Histograms - for (int i = 0; i < N_CLS_TYPE * N_CLS_HIST - 1; i++) { - int ioffset = i >= (2 * N_CLS_HIST - 1) ? (2 * N_CLS_HIST - 1) : i >= N_CLS_HIST ? N_CLS_HIST : 0; - int itype = i >= (2 * N_CLS_HIST - 1) ? 2 : i >= N_CLS_HIST ? 1 : 0; - sprintf(name, "clusters%s%s", CLUSTER_NAMES_SHORT[i - ioffset], CLUSTER_TYPES[itype]); - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; - createHist(mClusters[i], name, name, AXIS_BINS[4], binsPt.get()); - } - { - sprintf(name, "nclusters"); - createHist(mNCl, name, name, 160, 0, 159); - } - - // Create Tracks Histograms - { - sprintf(name, "tracks"); - std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; - createHist(mTracks, name, name, AXIS_BINS[4], binsPt.get()); - } - - for (unsigned int i = 0; i < mHist1D->size(); i++) { - *mHist1D_pos[i] = &(*mHist1D)[i]; - } - for (unsigned int i = 0; i < mHist2D->size(); i++) { - *mHist2D_pos[i] = &(*mHist2D)[i]; - } - for (unsigned int i = 0; i < mHist1Dd->size(); i++) { - *mHist1Dd_pos[i] = &(*mHist1Dd)[i]; - } - - return 0; -} - -int GPUQA::loadHistograms(std::vector<TH1F>& i1, std::vector<TH2F>& i2, std::vector<TH1D>& i3) -{ - if (mQAInitialized) { - return 1; - } - mHist1D = &i1; - mHist2D = &i2; - mHist1Dd = &i3; - mHist1D_pos.clear(); - mHist2D_pos.clear(); - mHist1Dd_pos.clear(); - mHaveExternalHists = true; - if (InitQACreateHistograms()) { - return 1; - } - mQAInitialized = true; - return 0; -} - -int GPUQA::InitQA() -{ - if (mQAInitialized) { - return 1; - } - - mHist1D = new std::vector<TH1F>; - mHist2D = new std::vector<TH2F>; - mHist1Dd = new std::vector<TH1D>; - - if (InitQACreateHistograms()) { - return 1; - } - - if (!mRunForQC) { - mkdir("plots", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - } - -#ifdef GPUCA_O2_LIB - TFile fileSim(o2::base::NameConf::getMCKinematicsFileName("o2sim").c_str()); - TTree* treeSim = (TTree*)fileSim.Get("o2sim"); - std::vector<o2::MCTrack>* tracksX; - std::vector<o2::TrackReference>* trackRefsX; - if (treeSim == nullptr) { - throw std::runtime_error("Error reading o2sim tree"); - } - treeSim->SetBranchAddress("MCTrack", &tracksX); - treeSim->SetBranchAddress("TrackRefs", &trackRefsX); - - int nSimEvents = treeSim->GetEntries(); - mTrackMCLabelsReverse.resize(nSimEvents); - mRecTracks.resize(nSimEvents); - mFakeTracks.resize(nSimEvents); - mMCParam.resize(nSimEvents); - mMCInfos.resize(nSimEvents); - mNColTracks.resize(nSimEvents); - std::vector<int> refId; - for (int i = 0; i < nSimEvents; i++) { - treeSim->GetEntry(i); - const std::vector<o2::MCTrack>& tracks = *tracksX; - const std::vector<o2::TrackReference>& trackRefs = *trackRefsX; - - refId.resize(tracks.size()); - std::fill(refId.begin(), refId.end(), -1); - for (unsigned int j = 0; j < trackRefs.size(); j++) { - if (trackRefs[j].getDetectorId() == o2::detectors::DetID::TPC) { - int trkId = trackRefs[j].getTrackID(); - if (refId[trkId] == -1) { - refId[trkId] = j; - } - } - } - mNColTracks[i] = tracks.size(); - mMCInfos[i].resize(tracks.size()); - for (unsigned int j = 0; j < tracks.size(); j++) { - auto& info = mMCInfos[i][j]; - const auto& trk = tracks[j]; - TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(trk.GetPdgCode()); - Int_t pid = -1; - if (abs(trk.GetPdgCode()) == kElectron) { - pid = 0; - } - if (abs(trk.GetPdgCode()) == kMuonMinus) { - pid = 1; - } - if (abs(trk.GetPdgCode()) == kPiPlus) { - pid = 2; - } - if (abs(trk.GetPdgCode()) == kKPlus) { - pid = 3; - } - if (abs(trk.GetPdgCode()) == kProton) { - pid = 4; - } - - info.charge = particle ? particle->Charge() : 0; - info.prim = 1; - info.primDaughters = 0; - info.pid = pid; - if (refId[j] >= 0) { - const auto& trkRef = trackRefs[refId[j]]; - info.x = trkRef.X(); - info.y = trkRef.Y(); - info.z = trkRef.Z(); - info.pX = trkRef.Px(); - info.pY = trkRef.Py(); - info.pZ = trkRef.Pz(); - info.genRadius = std::sqrt(trk.GetStartVertexCoordinatesX() * trk.GetStartVertexCoordinatesX() + trk.GetStartVertexCoordinatesY() * trk.GetStartVertexCoordinatesY() + trk.GetStartVertexCoordinatesZ() * trk.GetStartVertexCoordinatesZ()); - } else { - info.x = info.y = info.z = info.pX = info.pY = info.pZ = 0; - info.genRadius = 0; - } - } - } - - fileSim.Close(); -#endif - - if (mConfig.matchMCLabels.size()) { - unsigned int nFiles = mConfig.matchMCLabels.size(); - std::vector<std::unique_ptr<TFile>> files; - std::vector<std::vector<std::vector<int>>*> labelsBuffer(nFiles); - std::vector<std::vector<std::vector<int>>*> effBuffer(nFiles); - for (unsigned int i = 0; i < nFiles; i++) { - files.emplace_back(std::make_unique<TFile>(mConfig.matchMCLabels[i])); - labelsBuffer[i] = (std::vector<std::vector<int>>*)files[i]->Get("mcLabelBuffer"); - effBuffer[i] = (std::vector<std::vector<int>>*)files[i]->Get("mcEffBuffer"); - if (labelsBuffer[i] == nullptr || effBuffer[i] == nullptr) { - GPUError("Error opening / reading from labels file %u/%s: %p %p", i, mConfig.matchMCLabels[i], (void*)labelsBuffer[i], (void*)effBuffer[i]); - exit(1); - } - } - - mGoodTracks.resize(labelsBuffer[0]->size()); - mGoodHits.resize(labelsBuffer[0]->size()); - for (unsigned int iEvent = 0; iEvent < labelsBuffer[0]->size(); iEvent++) { - std::vector<bool> labelsOK((*effBuffer[0])[iEvent].size()); - for (unsigned int k = 0; k < (*effBuffer[0])[iEvent].size(); k++) { - labelsOK[k] = false; - for (unsigned int l = 0; l < nFiles; l++) { - if ((*effBuffer[0])[iEvent][k] != (*effBuffer[l])[iEvent][k]) { - labelsOK[k] = true; - break; - } - } - } - mGoodTracks[iEvent].resize((*labelsBuffer[0])[iEvent].size()); - for (unsigned int k = 0; k < (*labelsBuffer[0])[iEvent].size(); k++) { - if ((*labelsBuffer[0])[iEvent][k] == MC_LABEL_INVALID) { - continue; - } - mGoodTracks[iEvent][k] = labelsOK[abs((*labelsBuffer[0])[iEvent][k])]; - } - } - } - mQAInitialized = true; - return 0; -} - -void GPUQA::RunQA(bool matchOnly) -{ - if (!mQAInitialized) { - return; - } - - // Initialize Arrays - mTrackMCLabels.resize(mTracking->mIOPtrs.nMergedTracks); - for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { - mTrackMCLabelsReverse[iCol].resize(GetNMCTracks(iCol)); - mRecTracks[iCol].resize(GetNMCTracks(iCol)); - mFakeTracks[iCol].resize(GetNMCTracks(iCol)); - mMCParam[iCol].resize(GetNMCTracks(iCol)); - memset(mRecTracks[iCol].data(), 0, mRecTracks[iCol].size() * sizeof(mRecTracks[iCol][0])); - memset(mFakeTracks[iCol].data(), 0, mFakeTracks[iCol].size() * sizeof(mFakeTracks[iCol][0])); - for (size_t i = 0; i < mTrackMCLabelsReverse[iCol].size(); i++) { - mTrackMCLabelsReverse[iCol][i] = -1; - } - } - mClusterParam.resize(GetNMCLabels()); - memset(mClusterParam.data(), 0, mClusterParam.size() * sizeof(mClusterParam[0])); - HighResTimer timer; - - mNEvents++; - if (mConfig.writeMCLabels) { - mcEffBuffer.resize(mNEvents); - mcLabelBuffer.resize(mNEvents); - mcEffBuffer[mNEvents - 1].resize(GetNMCTracks(0)); - mcLabelBuffer[mNEvents - 1].resize(mTracking->mIOPtrs.nMergedTracks); - } - - bool mcAvail = mcPresent(); - - if (mcAvail && mTracking->GetParam().rec.NonConsecutiveIDs) { - GPUError("QA incompatible to non-consecutive MC labels"); - return; - } - - if (mcAvail) { - // Assign Track MC Labels - timer.Start(); - auto acc = GPUTPCTrkLbl<true, mcLabelI_t>(GetClusterLabels(), 1.f - mConfig.recThreshold); -#if QA_DEBUG == 0 - GPUCA_OPENMP(parallel for firstprivate(acc)) -#endif - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - acc.reset(); - int nClusters = 0; - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - std::vector<mcLabel_t> labels; - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - nClusters++; - unsigned int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; - if (hitId >= GetNMCLabels()) { - GPUError("Invalid hit id %u > %d", hitId, GetNMCLabels()); - throw std::runtime_error("qa error"); - } - acc.addLabel(hitId); - for (int j = 0; j < GetMCLabelNID(hitId); j++) { - if (GetMCLabelID(hitId, j) >= (int)GetNMCTracks(GetMCLabelCol(hitId, j))) { - GPUError("Invalid label %d > %d (hit %d, label %d, col %d)", GetMCLabelID(hitId, j), GetNMCTracks(GetMCLabelCol(hitId, j)), hitId, j, (int)GetMCLabelCol(hitId, j)); - throw std::runtime_error("qa error"); - } - if (GetMCLabelID(hitId, j) >= 0) { - if (QA_DEBUG >= 3 && track.OK()) { - GPUInfo("Track %d Cluster %u Label %d: %d (%f)", i, k, j, GetMCLabelID(hitId, j), GetMCLabelWeight(hitId, j)); - } - } - } - } - - float maxweight, sumweight; - int maxcount; - auto maxLabel = acc.computeLabel(&maxweight, &sumweight, &maxcount); - mTrackMCLabels[i] = maxLabel; - if (QA_DEBUG && track.OK() && GetNMCTracks(maxLabel.getEventID()) > maxLabel.getTrackID()) { - const mcInfo_t& mc = GetMCTrack(maxLabel); - GPUInfo("Track %d label %d (fake %d) weight %f clusters %d (fitted %d) (%f%% %f%%) Pt %f", i, maxLabel.getTrackID(), (int)(maxLabel.isFake()), maxweight, nClusters, track.NClustersFitted(), 100.f * maxweight / sumweight, 100.f * (float)maxcount / (float)nClusters, - std::sqrt(mc.pX * mc.pX + mc.pY * mc.pY)); - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // fill cluster attachment status - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - if (!track.OK()) { - continue; - } - if (!mTrackMCLabels[i].isValid()) { - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - mClusterParam[mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num].fakeAttached++; - } - continue; - } - mcLabelI_t label = mTrackMCLabels[i]; - if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; - bool correct = false; - for (int j = 0; j < GetMCLabelNID(hitId); j++) { - if (label == GetMCLabel(hitId, j)) { - correct = true; - break; - } - } - if (correct) { - mClusterParam[hitId].attached++; - } else { - mClusterParam[hitId].fakeAttached++; - } - } - } - if (mTrackMCLabels[i].isFake()) { - (GetMCTrackObj(mFakeTracks, label))++; - } else if (!track.MergedLooper()) { - GetMCTrackObj(mRecTracks, label)++; - if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { - int& revLabel = GetMCTrackObj(mTrackMCLabelsReverse, label); - if (revLabel == -1 || !mTracking->mIOPtrs.mergedTracks[revLabel].OK() || (mTracking->mIOPtrs.mergedTracks[i].OK() && fabsf(mTracking->mIOPtrs.mergedTracks[i].GetParam().GetZ()) < fabsf(mTracking->mIOPtrs.mergedTracks[revLabel].GetParam().GetZ()))) { - revLabel = i; - } - } - } - } - // fill cluster adjacent status - for (unsigned int i = 0; i < GetNMCLabels(); i++) { - if (mClusterParam[i].attached == 0 && mClusterParam[i].fakeAttached == 0) { - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; - if (attach & gputpcgmmergertypes::attachFlagMask) { - int track = attach & gputpcgmmergertypes::attachTrackMask; - mcLabelI_t trackL = mTrackMCLabels[track]; - bool fake = true; - for (int j = 0; j < GetMCLabelNID(i); j++) { - // GPUInfo("Attach %x Track %d / %d:%d", attach, track, j, GetMCLabelID(i, j)); - if (trackL == GetMCLabel(i, j)) { - fake = false; - break; - } - } - if (fake) { - mClusterParam[i].fakeAdjacent++; - } else { - mClusterParam[i].adjacent++; - } - } - } - } - if (mConfig.matchMCLabels.size()) { - mGoodHits[mNEvents - 1].resize(GetNMCLabels()); - std::vector<bool> allowMCLabels(GetNMCTracks(0)); - for (unsigned int k = 0; k < GetNMCTracks(0); k++) { - allowMCLabels[k] = false; - } - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - if (!mGoodTracks[mNEvents - 1][i]) { - continue; - } - if (mConfig.matchDisplayMinPt > 0) { - if (!mTrackMCLabels[i].isValid()) { - continue; - } - const mcInfo_t& info = GetMCTrack(mTrackMCLabels[i]); - if (info.pX * info.pX + info.pY * info.pY < mConfig.matchDisplayMinPt * mConfig.matchDisplayMinPt) { - continue; - } - } - - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - for (unsigned int j = 0; j < track.NClusters(); j++) { - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + j].num; - if (GetMCLabelNID(hitId)) { - int mcID = GetMCLabelID(hitId, 0); - if (mcID >= 0) { - allowMCLabels[mcID] = true; - } - } - } - } - for (unsigned int i = 0; i < GetNMCLabels(); i++) { - for (int j = 0; j < GetMCLabelNID(i); j++) { - int mcID = GetMCLabelID(i, j); - if (mcID >= 0 && allowMCLabels[mcID]) { - mGoodHits[mNEvents - 1][i] = true; - } - } - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Cluster attach status:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - if (matchOnly) { - return; - } - - // Recompute fNWeightCls (might have changed after merging events into timeframes) - for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { - for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { - mMCParam[iCol][i].nWeightCls = 0.; - } - } - for (unsigned int i = 0; i < GetNMCLabels(); i++) { - float weightTotal = 0.f; - for (int j = 0; j < GetMCLabelNID(i); j++) { - if (GetMCLabelID(i, j) >= 0) { - weightTotal += GetMCLabelWeight(i, j); - } - } - for (int j = 0; j < GetMCLabelNID(i); j++) { - if (GetMCLabelID(i, j) >= 0) { - GetMCTrackObj(mMCParam, GetMCLabel(i, j)).nWeightCls += GetMCLabelWeight(i, j) / weightTotal; - } - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Compute cluster label weights:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // Compute MC Track Parameters for MC Tracks - GPUCA_OPENMP(parallel for) - for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { - for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { - const mcInfo_t& info = GetMCTrack(i, iCol); - additionalMCParameters& mc2 = mMCParam[iCol][i]; - mc2.pt = std::sqrt(info.pX * info.pX + info.pY * info.pY); - mc2.phi = M_PI + std::atan2(-info.pY, -info.pX); - float p = info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ; - if (p < 1e-18) { - mc2.theta = mc2.eta = 0.f; - } else { - mc2.theta = info.pZ == 0 ? (M_PI / 2) : (std::acos(info.pZ / std::sqrt(p))); - mc2.eta = -std::log(std::tan(0.5 * mc2.theta)); - } - if (mConfig.writeMCLabels) { - std::vector<int>& effBuffer = mcEffBuffer[mNEvents - 1]; - effBuffer[i] = mRecTracks[iCol][i] * 1000 + mFakeTracks[iCol][i]; - } - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Compute track mc parameters:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // Fill Efficiency Histograms - for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { - for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { - if ((mMCTrackMin != -1 && (int)i < mMCTrackMin) || (mMCTrackMax != -1 && (int)i >= mMCTrackMax)) { - continue; - } - const mcInfo_t& info = GetMCTrack(i, iCol); - const additionalMCParameters& mc2 = mMCParam[iCol][i]; - if (mc2.nWeightCls == 0.f) { - continue; - } - const float& mcpt = mc2.pt; - const float& mcphi = mc2.phi; - const float& mceta = mc2.eta; - - if (info.prim && info.primDaughters) { - continue; - } - if (mc2.nWeightCls < MIN_WEIGHT_CLS) { - continue; - } - int findable = mc2.nWeightCls >= FINDABLE_WEIGHT_CLS; - if (info.pid < 0) { - continue; - } - if (info.charge == 0.f) { - continue; - } - if (mConfig.filterCharge && info.charge * mConfig.filterCharge < 0) { - continue; - } - if (mConfig.filterPID >= 0 && info.pid != mConfig.filterPID) { - continue; - } - - if (fabsf(mceta) > ETA_MAX || mcpt < PT_MIN || mcpt > PT_MAX) { - continue; - } - - float alpha = std::atan2(info.y, info.x); - alpha /= M_PI / 9.f; - alpha = std::floor(alpha); - alpha *= M_PI / 9.f; - alpha += M_PI / 18.f; - - float c = std::cos(alpha); - float s = std::sin(alpha); - float localY = -info.x * s + info.y * c; - - for (int j = 0; j < 4; j++) { - for (int k = 0; k < 2; k++) { - if (k == 0 && findable == 0) { - continue; - } - - int val = (j == 0) ? (mRecTracks[iCol][i] ? 1 : 0) : (j == 1) ? (mRecTracks[iCol][i] ? mRecTracks[iCol][i] - 1 : 0) : (j == 2) ? mFakeTracks[iCol][i] : 1; - - for (int l = 0; l < 5; l++) { - if (info.prim && mcpt < PT_MIN_PRIM) { - continue; - } - if (l != 3 && fabsf(mceta) > ETA_MAX2) { - continue; - } - if (l < 4 && mcpt < 1.f / mConfig.qpt) { - continue; - } - - float pos = l == 0 ? localY : l == 1 ? info.z : l == 2 ? mcphi : l == 3 ? mceta : mcpt; - - mEff[j][k][!info.prim][l][0]->Fill(pos, val); - } - } - } - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Fill efficiency histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // Fill Resolution Histograms - GPUTPCGMPropagator prop; - prop.SetMaxSinPhi(.999); - prop.SetMaterialTPC(); - prop.SetPolynomialField(&mTracking->GetParam().polynomialField); - prop.SetToyMCEventsFlag(mTracking->GetParam().par.ToyMCEventsFlag); - - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - if (mConfig.writeMCLabels) { - std::vector<int>& labelBuffer = mcLabelBuffer[mNEvents - 1]; - labelBuffer[i] = mTrackMCLabels[i].getTrackID(); - } - if (mTrackMCLabels[i].isFake()) { - continue; - } - const mcInfo_t& mc1 = GetMCTrack(mTrackMCLabels[i]); - const additionalMCParameters& mc2 = GetMCTrackObj(mMCParam, mTrackMCLabels[i]); - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - - if ((mMCTrackMin != -1 && mTrackMCLabels[i].getTrackID() < mMCTrackMin) || (mMCTrackMax != -1 && mTrackMCLabels[i].getTrackID() >= mMCTrackMax)) { - continue; - } - - if (!track.OK()) { - continue; - } - if (track.MergedLooper()) { - continue; - } - if (fabsf(mc2.eta) > ETA_MAX || mc2.pt < PT_MIN || mc2.pt > PT_MAX) { - continue; - } - if (mc1.charge == 0.f) { - continue; - } - if (mc1.pid < 0) { - continue; - } - if (mConfig.filterCharge && mc1.charge * mConfig.filterCharge < 0) { - continue; - } - if (mConfig.filterPID >= 0 && mc1.pid != mConfig.filterPID) { - continue; - } - if (mc2.nWeightCls < MIN_WEIGHT_CLS) { - continue; - } - if (mConfig.resPrimaries == 1 && (!mc1.prim || mc1.primDaughters)) { - continue; - } else if (mConfig.resPrimaries == 2 && (mc1.prim || mc1.primDaughters)) { - continue; - } - if (GetMCTrackObj(mTrackMCLabelsReverse, mTrackMCLabels[i]) != (int)i) { - continue; - } - - float mclocal[4]; // Rotated x,y,Px,Py mc-coordinates - the MC data should be rotated since the track is propagated best along x - float c = std::cos(track.GetAlpha()); - float s = std::sin(track.GetAlpha()); - float x = mc1.x; - float y = mc1.y; - mclocal[0] = x * c + y * s; - mclocal[1] = -x * s + y * c; - float px = mc1.pX; - float py = mc1.pY; - mclocal[2] = px * c + py * s; - mclocal[3] = -px * s + py * c; - - GPUTPCGMTrackParam param = track.GetParam(); - - if (mclocal[0] < TRACK_EXPECTED_REFERENCE_X - 3) { - continue; - } - if (mclocal[0] > param.GetX() + 20) { - continue; - } - if (param.GetX() > mConfig.maxResX) { - continue; - } - - float alpha = track.GetAlpha(); - prop.SetTrack(¶m, alpha); - bool inFlyDirection = 0; -#ifdef GPUCA_TPC_GEOMETRY_O2 // ignore z here, larger difference in X due to shifted reference - if (mConfig.strict && (param.X() - mclocal[0]) * (param.X() - mclocal[0]) + (param.Y() - mclocal[1]) * (param.Y() - mclocal[1]) + (mTracking->GetParam().par.continuousMaxTimeBin ? 0 : ((param.Z() - mc1.z) * (param.Z() - mc1.z))) > (5 + abs(81 - TRACK_EXPECTED_REFERENCE_X)) * (5 + abs(81 - TRACK_EXPECTED_REFERENCE_X))) { -#else // Consider Z offset (pseudo-tf mc tracks have shifted z) - if (mConfig.strict && (param.X() - mclocal[0]) * (param.X() - mclocal[0]) + (param.Y() - mclocal[1]) * (param.Y() - mclocal[1]) + (param.Z() + param.TZOffset() - mc1.z) * (param.Z() + param.TZOffset() - mc1.z) > 25) { // TODO: fix TZOffset -#endif - continue; - } - - if (prop.PropagateToXAlpha(mclocal[0], alpha, inFlyDirection)) { - continue; - } -#ifdef GPUCA_TPC_GEOMETRY_O2 // ignore z here, larger difference in X due to shifted reference - if (fabsf(param.Y() - mclocal[1]) > (mConfig.strict ? 1.f : 4.f) || (mTracking->GetParam().par.continuousMaxTimeBin == 0 && fabsf(param.Z() + param.TZOffset() - mc1.z) > (mConfig.strict ? 1.f : 4.f))) { // TODO: fix TZOffset here -#else - if (fabsf(param.Y() - mclocal[1]) > (mConfig.strict ? 1.f : 4.f) || fabsf(param.Z() + param.TZOffset() - mc1.z) > (mConfig.strict ? 1.f : 4.f)) { // TODO: fix TZOffset here -#endif - continue; - } - - float charge = mc1.charge > 0 ? 1.f : -1.f; - - float deltaY = param.GetY() - mclocal[1]; - float deltaZ = param.GetZ() + param.TZOffset() - mc1.z; // TODO: fix TZOffset here - float deltaPhiNative = param.GetSinPhi() - mclocal[3] / mc2.pt; - float deltaPhi = std::asin(param.GetSinPhi()) - std::atan2(mclocal[3], mclocal[2]); - float deltaLambdaNative = param.GetDzDs() - mc1.pZ / mc2.pt; - float deltaLambda = std::atan(param.GetDzDs()) - std::atan2(mc1.pZ, mc2.pt); - float deltaPtNative = (param.GetQPt() - charge / mc2.pt) * charge; - float deltaPt = (fabsf(1.f / param.GetQPt()) - mc2.pt) / mc2.pt; - - float paramval[5] = {mclocal[1], mc1.z, mc2.phi, mc2.eta, mc2.pt}; - float resval[5] = {deltaY, deltaZ, mConfig.nativeFitResolutions ? deltaPhiNative : deltaPhi, mConfig.nativeFitResolutions ? deltaLambdaNative : deltaLambda, mConfig.nativeFitResolutions ? deltaPtNative : deltaPt}; - float pullval[5] = {deltaY / std::sqrt(param.GetErr2Y()), deltaZ / std::sqrt(param.GetErr2Z()), deltaPhiNative / std::sqrt(param.GetErr2SinPhi()), deltaLambdaNative / std::sqrt(param.GetErr2DzDs()), deltaPtNative / std::sqrt(param.GetErr2QPt())}; - - for (int j = 0; j < 5; j++) { - for (int k = 0; k < 5; k++) { - if (k != 3 && fabsf(mc2.eta) > ETA_MAX2) { - continue; - } - if (k < 4 && mc2.pt < 1.f / mConfig.qpt) { - continue; - } - mRes2[j][k]->Fill(resval[j], paramval[k]); - mPull2[j][k]->Fill(pullval[j], paramval[k]); - } - } - } - if (QA_TIMING) { - GPUInfo("QA Time: Fill resolution histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // Fill cluster histograms - for (unsigned int iTrk = 0; iTrk < mTracking->mIOPtrs.nMergedTracks; iTrk++) { - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[iTrk]; - if (!track.OK()) { - continue; - } - if (!mTrackMCLabels[iTrk].isValid()) { - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; - float totalWeight = 0.; - for (int j = 0; j < GetMCLabelNID(hitId); j++) { - if (GetMCLabelID(hitId, j) >= 0 && GetMCTrackObj(mMCParam, GetMCLabel(hitId, j)).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - totalWeight += GetMCLabelWeight(hitId, j); - } - } - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId]; - CHECK_CLUSTER_STATE_NOCOUNT(); - if (totalWeight > 0) { - float weight = 1.f / (totalWeight * (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached)); - for (int j = 0; j < GetMCLabelNID(hitId); j++) { - mcLabelI_t label = GetMCLabel(hitId, j); - if (!label.isFake() && GetMCTrackObj(mMCParam, label).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - float pt = GetMCTrackObj(mMCParam, label).pt; - if (pt < PT_MIN_CLUST) { - pt = PT_MIN_CLUST; - } - mClusters[CL_fake]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - if (GetMCTrackObj(mRecTracks, label)) { - mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - } - mClusters[CL_all]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - if (protect || physics) { - mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - } - if (physics) { - mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); - } - } - } - } else { - float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached); - mClusters[CL_fake]->Fill(0.f, weight); - mClusters[CL_att_adj]->Fill(0.f, weight); - mClusters[CL_all]->Fill(0.f, weight); - mClusterCounts.nUnaccessible += weight; - if (protect || physics) { - mClusters[CL_prot]->Fill(0.f, weight); - } - if (physics) { - mClusters[CL_physics]->Fill(0.f, weight); - } - } - } - continue; - } - mcLabelI_t label = mTrackMCLabels[iTrk]; - if (mMCTrackMin != -1 && (label.getTrackID() < mMCTrackMin || label.getTrackID() >= mMCTrackMax)) { - continue; - } - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; - float pt = GetMCTrackObj(mMCParam, label).pt; - if (pt < PT_MIN_CLUST) { - pt = PT_MIN_CLUST; - } - float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached); - bool correct = false; - for (int j = 0; j < GetMCLabelNID(hitId); j++) { - if (label == GetMCLabel(hitId, j)) { - correct = true; - break; - } - } - if (correct) { - mClusters[CL_attached]->Fill(pt, weight); - mClusters[CL_tracks]->Fill(pt, weight); - } else { - mClusters[CL_fake]->Fill(pt, weight); - } - mClusters[CL_att_adj]->Fill(pt, weight); - mClusters[CL_all]->Fill(pt, weight); - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId]; - CHECK_CLUSTER_STATE_NOCOUNT(); - if (protect || physics) { - mClusters[CL_prot]->Fill(pt, weight); - } - if (physics) { - mClusters[CL_physics]->Fill(pt, weight); - } - } - } - for (unsigned int i = 0; i < GetNMCLabels(); i++) { - if ((mMCTrackMin != -1 && GetMCLabelID(i, 0) < mMCTrackMin) || (mMCTrackMax != -1 && GetMCLabelID(i, 0) >= mMCTrackMax)) { - continue; - } - if (mClusterParam[i].attached || mClusterParam[i].fakeAttached) { - continue; - } - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; - CHECK_CLUSTER_STATE_NOCOUNT(); - if (mClusterParam[i].adjacent) { - int label = mTracking->mIOPtrs.mergedTrackHitAttachment[i] & gputpcgmmergertypes::attachTrackMask; - if (!mTrackMCLabels[label].isValid()) { - float totalWeight = 0.; - for (int j = 0; j < GetMCLabelNID(i); j++) { - mcLabelI_t labelT = GetMCLabel(i, j); - if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - totalWeight += GetMCLabelWeight(i, j); - } - } - float weight = 1.f / totalWeight; - if (totalWeight > 0) { - for (int j = 0; j < GetMCLabelNID(i); j++) { - mcLabelI_t labelT = GetMCLabel(i, j); - if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - float pt = GetMCTrackObj(mMCParam, labelT).pt; - if (pt < PT_MIN_CLUST) { - pt = PT_MIN_CLUST; - } - if (GetMCTrackObj(mRecTracks, labelT)) { - mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(i, j) * weight); - } - mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(i, j) * weight); - mClusters[CL_fakeAdj]->Fill(pt, GetMCLabelWeight(i, j) * weight); - mClusters[CL_all]->Fill(pt, GetMCLabelWeight(i, j) * weight); - if (protect || physics) { - mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(i, j) * weight); - } - if (physics) { - mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(i, j) * weight); - } - } - } - } else { - mClusters[CL_att_adj]->Fill(0.f, 1.f); - mClusters[CL_fakeAdj]->Fill(0.f, 1.f); - mClusters[CL_all]->Fill(0.f, 1.f); - mClusterCounts.nUnaccessible++; - if (protect || physics) { - mClusters[CL_prot]->Fill(0.f, 1.f); - } - if (physics) { - mClusters[CL_physics]->Fill(0.f, 1.f); - } - } - } else { - float pt = GetMCTrackObj(mMCParam, mTrackMCLabels[label]).pt; - if (pt < PT_MIN_CLUST) { - pt = PT_MIN_CLUST; - } - mClusters[CL_att_adj]->Fill(pt, 1.f); - mClusters[CL_tracks]->Fill(pt, 1.f); - mClusters[CL_all]->Fill(pt, 1.f); - if (protect || physics) { - mClusters[CL_prot]->Fill(pt, 1.f); - } - if (physics) { - mClusters[CL_physics]->Fill(pt, 1.f); - } - } - } else { - float totalWeight = 0.; - for (int j = 0; j < GetMCLabelNID(i); j++) { - mcLabelI_t labelT = GetMCLabel(i, j); - if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - totalWeight += GetMCLabelWeight(i, j); - } - } - if (totalWeight > 0) { - for (int j = 0; j < GetMCLabelNID(i); j++) { - mcLabelI_t label = GetMCLabel(i, j); - if (!label.isFake() && GetMCTrackObj(mMCParam, label).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { - float pt = GetMCTrackObj(mMCParam, label).pt; - if (pt < PT_MIN_CLUST) { - pt = PT_MIN_CLUST; - } - float weight = GetMCLabelWeight(i, j) / totalWeight; - if (mClusterParam[i].fakeAdjacent) { - mClusters[CL_fakeAdj]->Fill(pt, weight); - } - if (mClusterParam[i].fakeAdjacent) { - mClusters[CL_att_adj]->Fill(pt, weight); - } - if (GetMCTrackObj(mRecTracks, label)) { - mClusters[CL_tracks]->Fill(pt, weight); - } - mClusters[CL_all]->Fill(pt, weight); - if (protect || physics) { - mClusters[CL_prot]->Fill(pt, weight); - } - if (physics) { - mClusters[CL_physics]->Fill(pt, weight); - } - } - } - } else { - if (mClusterParam[i].fakeAdjacent) { - mClusters[CL_fakeAdj]->Fill(0.f, 1.f); - } - if (mClusterParam[i].fakeAdjacent) { - mClusters[CL_att_adj]->Fill(0.f, 1.f); - } - mClusters[CL_all]->Fill(0.f, 1.f); - mClusterCounts.nUnaccessible++; - if (protect || physics) { - mClusters[CL_prot]->Fill(0.f, 1.f); - } - if (physics) { - mClusters[CL_physics]->Fill(0.f, 1.f); - } - } - } - } - - if (QA_TIMING) { - GPUInfo("QA Time: Fill cluster histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - } else if (!mConfig.inputHistogramsOnly) { - GPUWarning("No MC information available, only running partial TPC QA!"); - } - - // Fill track statistic histograms - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - if (!track.OK()) { - continue; - } - mTracks->Fill(1.f / fabsf(track.GetParam().GetQPt())); - mNCl->Fill(track.NClustersFitted()); - } - - unsigned int nCl = mTracking->mIOPtrs.clustersNative ? mTracking->mIOPtrs.clustersNative->nClustersTotal : mTracking->GetTPCMerger().NMaxClusters(); - for (unsigned int i = 0; i < nCl; i++) { - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; - CHECK_CLUSTER_STATE(); - - if (mcAvail) { - float totalWeight = 0, weight400 = 0, weight40 = 0; - for (int j = 0; j < GetMCLabelNID(i); j++) { - const auto& label = GetMCLabel(i, j); - if (GetMCLabelID(label) >= 0) { - totalWeight += GetMCLabelWeight(label); - if (GetMCTrackObj(mMCParam, label).pt >= 0.4) { - weight400 += GetMCLabelWeight(label); - } - if (GetMCTrackObj(mMCParam, label).pt <= 0.04) { - weight40 += GetMCLabelWeight(label); - } - } - } - if (totalWeight > 0 && 10.f * weight400 >= totalWeight) { - if (!unattached && !protect && !physics) { - mClusterCounts.nFakeRemove400++; - int totalFake = weight400 < 0.9f * totalWeight; - if (totalFake) { - mClusterCounts.nFullFakeRemove400++; - } - /*printf("Fake removal (%d): Hit %7d, attached %d lowPt %d looper %d tube200 %d highIncl %d tube %d bad %d recPt %7.2f recLabel %6d", totalFake, i, (int) (mClusterParam[i].attached || mClusterParam[i].fakeAttached), - (int) lowPt, (int) ((attach & gputpcgmmergertypes::attachGoodLeg) == 0), (int) ((attach & gputpcgmmergertypes::attachTube) && mev200), - (int) ((attach & gputpcgmmergertypes::attachHighIncl) != 0), (int) ((attach & gputpcgmmergertypes::attachTube) != 0), (int) ((attach & gputpcgmmergertypes::attachGood) == 0), - fabsf(qpt) > 0 ? 1.f / qpt : 0.f, id); - for (int j = 0;j < GetMCLabelNID(i);j++) - { - //if (GetMCLabelID(i, j) < 0) break; - printf(" - label%d %6d weight %5d", j, GetMCLabelID(i, j), (int) GetMCLabelWeight(i, j)); - if (GetMCLabelID(i, j) >= 0) printf(" - pt %7.2f", mMCParam[GetMCLabelID(i, j)].pt); - else printf(" "); - } - printf("\n");*/ - } - mClusterCounts.nAbove400++; - } - if (totalWeight > 0 && weight40 >= 0.9 * totalWeight) { - mClusterCounts.nBelow40++; - if (protect || physics) { - mClusterCounts.nFakeProtect40++; - } - } - } else { - mClusterCounts.nTotal++; - if (physics) { - mClusterCounts.nPhysics++; - } - if (physics || protect) { - mClusterCounts.nProt++; - } - if (unattached) { - mClusterCounts.nUnattached++; - } - } - } - - if (QA_TIMING) { - GPUInfo("QA Time: Others:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); - } - - // Create CSV DumpTrackHits - if (mConfig.csvDump) { - if (!mTracking->GetParam().par.earlyTpcTransform) { - GPUError("Unsupported settings for csv dump\n"); - return; - } - int totalNCls = GetNMCLabels(); - if (totalNCls == 0) { - for (unsigned int iSlice = 0; iSlice < GPUChainTracking::NSLICES; iSlice++) { - totalNCls += mTracking->mIOPtrs.nClusterData[iSlice]; - } - } - - std::vector<float> clusterInfo(totalNCls); - memset(clusterInfo.data(), 0, clusterInfo.size() * sizeof(clusterInfo[0])); - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - if (!track.OK()) { - continue; - } - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { - continue; - } - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; - float pt = fabsf(1.f / track.GetParam().GetQPt()); - if (pt > clusterInfo[hitId]) { - clusterInfo[hitId] = pt; - } - } - } - static int csvNum = 0; - char fname[256]; - sprintf(fname, "dump.%d.csv", csvNum); - FILE* fp = fopen(fname, "w+"); - fprintf(fp, "x;y;z;reconstructedPt;individualMomentum;individualTransverseMomentum;trackLabel1;trackLabel2;trackLabel3;removed\n\n"); - int dumpClTot = 0, dumpClLeft = 0, dumpClRem = 0; - for (unsigned int iSlice = 0; iSlice < GPUChainTracking::NSLICES; iSlice++) { - for (unsigned int i = 0; i < mTracking->mIOPtrs.nClusterData[iSlice]; i++) { - const auto& cl = mTracking->mIOPtrs.clusterData[iSlice][i]; - float x, y, z; - const int cid = cl.id; - mTracking->GetParam().Slice2Global(iSlice, cl.x, cl.y, cl.z, &x, &y, &z); - - float totalWeight = 0.f; - if (mcPresent()) { - for (int j = 0; j < GetMCLabelNID(cid); j++) { - if (GetMCLabelID(cid, j) >= 0) { - totalWeight += GetMCLabelWeight(cid, j); - } - } - } - - float maxPt = 0.; - float p = 0.; - - if (totalWeight > 0) { - for (int j = 0; j < GetMCLabelNID(cid); j++) { - const mcLabelI_t label = GetMCLabel(cid, j); - if (!label.isFake() && GetMCLabelWeight(cid, j) > 0.3 * totalWeight) { - const mcInfo_t& info = GetMCTrack(label); - const additionalMCParameters& mc2 = GetMCTrackObj(mMCParam, label); - const float pt = fabsf(mc2.pt); - if (pt > maxPt) { - maxPt = pt; - p = std::sqrt(info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ); - } - } - } - } - int labels[3] = {}; - if (mcPresent()) { - for (int j = 0; j < GetMCLabelNID(cid); j++) { - labels[j] = GetMCLabelID(cid, j); - } - } - - dumpClTot++; - int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[cid]; - CHECK_CLUSTER_STATE(); - if (protect || physics) { - continue; - } - if (attach && qpt < 50) { - continue; - } - dumpClLeft++; - if (attach) { - dumpClRem++; - } - - fprintf(fp, "%f;%f;%f;%f;%f;%f;%d;%d;%d;%d\n", x, y, z, attach ? 1.f / qpt : 0.f, p, maxPt, labels[0], labels[1], labels[2], attach ? 1 : 0); - } - } - fclose(fp); - if (mcPresent()) { - sprintf(fname, "dump_event.%d.csv", csvNum++); - fp = fopen(fname, "w+"); - fprintf(fp, "trackLabel;trackMomentum;trackMomentumTransverse;trackMomentumZ\n\n"); - for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { - for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { - const mcInfo_t& info = GetMCTrack(i, iCol); - additionalMCParameters& mc2 = mMCParam[iCol][i]; - if (mc2.nWeightCls > 0) { - fprintf(fp, "%u;%f;%f;%f\n", i, std::sqrt(info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ), mc2.pt, info.pZ); - } - } - } - fclose(fp); - } - GPUInfo("Wrote %s,%d clusters in total, %d left, %d to be removed", fname, dumpClTot, dumpClLeft, dumpClRem); - } -} - -void GPUQA::GetName(char* fname, int k) -{ - const int nNewInput = mConfig.inputHistogramsOnly ? 0 : 1; - if (k || mConfig.inputHistogramsOnly || mConfig.name.size()) { - if (!(mConfig.inputHistogramsOnly || k)) { - snprintf(fname, 1024, "%s - ", mConfig.name.c_str()); - } else if (mConfig.compareInputNames.size() > (unsigned)(k - nNewInput)) { - snprintf(fname, 1024, "%s - ", mConfig.compareInputNames[k - nNewInput]); - } else { - strcpy(fname, mConfig.compareInputs[k - nNewInput]); - if (strlen(fname) > 5 && strcmp(fname + strlen(fname) - 5, ".root") == 0) { - fname[strlen(fname) - 5] = 0; - } - strcat(fname, " - "); - } - } else { - fname[0] = 0; - } -} - -template <class T> -T* GPUQA::GetHist(T*& ee, std::vector<std::unique_ptr<TFile>>& tin, int k, int nNewInput) -{ - T* e = ee; - if ((mConfig.inputHistogramsOnly || k) && (e = dynamic_cast<T*>(tin[k - nNewInput]->Get(e->GetName()))) == nullptr) { - GPUWarning("Missing histogram in input %s: %s", mConfig.compareInputs[k - nNewInput], ee->GetName()); - return (nullptr); - } - ee = e; - return (e); -} - -void GPUQA::DrawQAHistogramsCleanup() -{ - clearGarbagageCollector(); -} - -int GPUQA::DrawQAHistograms(TObjArray* qcout) -{ - if (!mQAInitialized) { - return 1; - } - - std::vector<Color_t> colorNums(COLORCOUNT); - for (int i = 0; i < COLORCOUNT; i++) { - colorNums[i] = qcout ? defaultColorNUms[i] : mColors[i]->GetNumber(); - } - - bool mcAvail = mcPresent(); - char name[2048], fname[1024]; - - const int nNewInput = mConfig.inputHistogramsOnly ? 0 : 1; - const int ConfigNumInputs = nNewInput + mConfig.compareInputs.size(); - - std::vector<std::unique_ptr<TFile>> tin; - for (unsigned int i = 0; i < mConfig.compareInputs.size(); i++) { - tin.emplace_back(std::make_unique<TFile>(mConfig.compareInputs[i])); - } - std::unique_ptr<TFile> tout = nullptr; - if (mConfig.output.size()) { - tout = std::make_unique<TFile>(mConfig.output.c_str(), "RECREATE"); - } - - if (!mRunForQC || mConfig.shipToQCAsCanvas) { - float legendSpacingString = 0.025; - for (int i = 0; i < ConfigNumInputs; i++) { - GetName(fname, i); - if (strlen(fname) * 0.006 > legendSpacingString) { - legendSpacingString = strlen(fname) * 0.006; - } - } - - // Create Canvas / Pads for Efficiency Histograms - for (int ii = 0; ii < 6; ii++) { - int i = ii == 5 ? 4 : ii; - sprintf(fname, "eff_vs_%s_layout", VSPARAMETER_NAMES[ii]); - sprintf(name, "Efficiency versus %s", VSPARAMETER_NAMES[i]); - mCEff[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCEff[ii]->cd(); - float dy = 1. / 2.; - mPEff[ii][0] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPEff[ii][0]->Draw(); - mPEff[ii][0]->SetRightMargin(0.04); - mPEff[ii][1] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPEff[ii][1]->Draw(); - mPEff[ii][1]->SetRightMargin(0.04); - mPEff[ii][2] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 0.5, dy * 2 - .001); - mPEff[ii][2]->Draw(); - mPEff[ii][2]->SetRightMargin(0.04); - mPEff[ii][3] = createGarbageCollected<TPad>("p3", "", 0.5, dy * 1, 1.0, dy * 2 - .001); - mPEff[ii][3]->Draw(); - mPEff[ii][3]->SetRightMargin(0.04); - mLEff[ii] = createGarbageCollected<TLegend>(0.92 - legendSpacingString * 1.45, 0.83 - (0.93 - 0.82) / 2. * (float)ConfigNumInputs, 0.98, 0.849); - SetLegend(mLEff[ii]); - } - - // Create Canvas / Pads for Resolution Histograms - for (int ii = 0; ii < 7; ii++) { - int i = ii == 5 ? 4 : ii; - if (ii == 6) { - sprintf(fname, "res_integral_layout"); - sprintf(name, "Integral Resolution"); - } else { - sprintf(fname, "res_vs_%s_layout", VSPARAMETER_NAMES[ii]); - sprintf(name, "Resolution versus %s", VSPARAMETER_NAMES[i]); - } - mCRes[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCRes[ii]->cd(); - gStyle->SetOptFit(1); - - float dy = 1. / 2.; - mPRes[ii][3] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPRes[ii][3]->Draw(); - mPRes[ii][3]->SetRightMargin(0.04); - mPRes[ii][4] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPRes[ii][4]->Draw(); - mPRes[ii][4]->SetRightMargin(0.04); - mPRes[ii][0] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); - mPRes[ii][0]->Draw(); - mPRes[ii][0]->SetRightMargin(0.04); - mPRes[ii][0]->SetLeftMargin(0.15); - mPRes[ii][1] = createGarbageCollected<TPad>("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); - mPRes[ii][1]->Draw(); - mPRes[ii][1]->SetRightMargin(0.04); - mPRes[ii][1]->SetLeftMargin(0.135); - mPRes[ii][2] = createGarbageCollected<TPad>("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); - mPRes[ii][2]->Draw(); - mPRes[ii][2]->SetRightMargin(0.06); - mPRes[ii][2]->SetLeftMargin(0.135); - if (ii < 6) { - mLRes[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLRes[ii]); - } - } - - // Create Canvas / Pads for Pull Histograms - for (int ii = 0; ii < 7; ii++) { - int i = ii == 5 ? 4 : ii; - - if (ii == 6) { - sprintf(fname, "pull_integral_layout"); - sprintf(name, "Integral Pull"); - } else { - sprintf(fname, "pull_vs_%s_layout", VSPARAMETER_NAMES[ii]); - sprintf(name, "Pull versus %s", VSPARAMETER_NAMES[i]); - } - mCPull[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCPull[ii]->cd(); - gStyle->SetOptFit(1); - - float dy = 1. / 2.; - mPPull[ii][3] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPPull[ii][3]->Draw(); - mPPull[ii][3]->SetRightMargin(0.04); - mPPull[ii][4] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPPull[ii][4]->Draw(); - mPPull[ii][4]->SetRightMargin(0.04); - mPPull[ii][0] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); - mPPull[ii][0]->Draw(); - mPPull[ii][0]->SetRightMargin(0.04); - mPPull[ii][0]->SetLeftMargin(0.15); - mPPull[ii][1] = createGarbageCollected<TPad>("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); - mPPull[ii][1]->Draw(); - mPPull[ii][1]->SetRightMargin(0.04); - mPPull[ii][1]->SetLeftMargin(0.135); - mPPull[ii][2] = createGarbageCollected<TPad>("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); - mPPull[ii][2]->Draw(); - mPPull[ii][2]->SetRightMargin(0.06); - mPPull[ii][2]->SetLeftMargin(0.135); - if (ii < 6) { - mLPull[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLPull[ii]); - } - } - - // Create Canvas for Cluster Histos - for (int i = 0; i < 3; i++) { - sprintf(fname, "clusters_%s_layout", CLUSTER_TYPES[i]); - mCClust[i] = createGarbageCollected<TCanvas>(fname, CLUSTER_TITLES[i], 0, 0, 700, 700. * 2. / 3.); - mCClust[i]->cd(); - mPClust[i] = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); - mPClust[i]->Draw(); - float y1 = i != 1 ? 0.77 : 0.27, y2 = i != 1 ? 0.9 : 0.42; - mLClust[i] = createGarbageCollected<TLegend>(i == 2 ? 0.1 : (0.65 - legendSpacingString * 1.45), y2 - (y2 - y1) * (ConfigNumInputs + (i != 1) / 2.) + 0.005, i == 2 ? (0.3 + legendSpacingString * 1.45) : 0.9, y2); - SetLegend(mLClust[i]); - } - - // Create Canvas for track statistic histos - if (!mRunForQC) { - mCTracks = createGarbageCollected<TCanvas>("ctracks", "Track Pt", 0, 0, 700, 700. * 2. / 3.); - mCTracks->cd(); - mPTracks = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); - mPTracks->Draw(); - mLTracks = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLTracks); - - mCNCl = createGarbageCollected<TCanvas>("cncl", "Number of clusters per track", 0, 0, 700, 700. * 2. / 3.); - mCNCl->cd(); - mPNCl = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); - mPNCl->Draw(); - mLNCl = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLNCl); - } - } - - if (!mRunForQC && !mConfig.inputHistogramsOnly) { - GPUInfo("QA Stats: Eff: Tracks Prim %d (Eta %d, Pt %d) %f%% (%f%%) Sec %d (Eta %d, Pt %d) %f%% (%f%%) - Res: Tracks %d (Eta %d, Pt %d)", (int)mEff[3][1][0][0][0]->GetEntries(), (int)mEff[3][1][0][3][0]->GetEntries(), (int)mEff[3][1][0][4][0]->GetEntries(), - mEff[0][0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0][0]->GetSumOfWeights()), (int)mEff[3][1][1][0][0]->GetEntries(), (int)mEff[3][1][1][3][0]->GetEntries(), - (int)mEff[3][1][1][4][0]->GetEntries(), mEff[0][0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0][0]->GetSumOfWeights()), mEff[0][1][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0][0]->GetSumOfWeights()), (int)mRes2[0][0]->GetEntries(), - (int)mRes2[0][3]->GetEntries(), (int)mRes2[0][4]->GetEntries()); - } - - int flagShowVsPtLog = (mRunForQC && !mConfig.shipToQCAsCanvas) ? 0 : 1; - - // Process / Draw Efficiency Histograms - for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { - int i = ii == 5 ? 4 : ii; - for (int k = 0; k < ConfigNumInputs; k++) { - for (int j = 0; j < 4; j++) { - if (!mRunForQC || mConfig.shipToQCAsCanvas) { - mPEff[ii][j]->cd(); - } - for (int l = 0; l < 3; l++) { - if (k == 0 && mConfig.inputHistogramsOnly == 0 && ii != 5) { - if (l == 0) { - // Divide eff, compute all for fake/clone - mEff[0][j / 2][j % 2][i][1]->Divide(mEff[l][j / 2][j % 2][i][0], mEff[3][j / 2][j % 2][i][0], 1, 1, "B"); - mEff[3][j / 2][j % 2][i][1]->Reset(); // Sum up rec + clone + fake for clone/fake rate - mEff[3][j / 2][j % 2][i][1]->Add(mEff[0][j / 2][j % 2][i][0]); - mEff[3][j / 2][j % 2][i][1]->Add(mEff[1][j / 2][j % 2][i][0]); - mEff[3][j / 2][j % 2][i][1]->Add(mEff[2][j / 2][j % 2][i][0]); - } else { - // Divide fake/clone - mEff[l][j / 2][j % 2][i][1]->Divide(mEff[l][j / 2][j % 2][i][0], mEff[3][j / 2][j % 2][i][1], 1, 1, "B"); - } - } - - TH1F* e = mEff[l][j / 2][j % 2][i][1]; - - e->SetStats(kFALSE); - e->SetMaximum(1.02); - e->SetMinimum(-0.02); - if (!mConfig.inputHistogramsOnly && k == 0) { - if (tout) { - mEff[l][j / 2][j % 2][i][0]->Write(); - e->Write(); - if (l == 2) { - mEff[3][j / 2][j % 2][i][0]->Write(); // Store also all histogram! - } - } - } else if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetTitle(EFFICIENCY_TITLES[j]); - e->GetYaxis()->SetTitle("(Efficiency)"); - e->GetXaxis()->SetTitle(XAXIS_TITLES[i]); - - e->SetLineWidth(1); - e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); - SetAxisSize(e); - if (qcout && !mConfig.shipToQCAsCanvas) { - qcout->Add(e); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - e->SetMarkerColor(kBlack); - e->SetLineColor(colorNums[(l == 2 ? (ConfigNumInputs * 2 + k) : (k * 2 + l)) % COLORCOUNT]); - e->Draw(k || l ? "same" : ""); - if (j == 0) { - GetName(fname, k); - sprintf(name, "%s%s", fname, EFF_NAMES[l]); - mLEff[ii]->AddEntry(e, name, "l"); - } - if (ii == 5) { - mPEff[ii][j]->SetLogx(); - } - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - mCEff[ii]->cd(); - ChangePadTitleSize(mPEff[ii][j], 0.056); - } - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - mLEff[ii]->Draw(); - - if (mRunForQC) { - if (qcout) { - qcout->Add(mCEff[ii]); - } - continue; - } - doPerfFigure(0.2, 0.295, 0.025); - mCEff[ii]->Print(Form("plots/eff_vs_%s.pdf", VSPARAMETER_NAMES[ii])); - if (mConfig.writeRootFiles) { - mCEff[ii]->Print(Form("plots/eff_vs_%s.root", VSPARAMETER_NAMES[ii])); - } - } - - // Process / Draw Resolution Histograms - TH1D *resIntegral[5] = {}, *pullIntegral[5] = {}; - TCanvas* cfit = nullptr; - std::unique_ptr<TF1> customGaus = std::make_unique<TF1>("G", "[0]*exp(-(x-[1])*(x-[1])/(2.*[2]*[2]))"); - for (int p = 0; p < 2; p++) { - for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { - TCanvas* can = p ? mCPull[ii] : mCRes[ii]; - TLegend* leg = p ? mLPull[ii] : mLRes[ii]; - int i = ii == 5 ? 4 : ii; - for (int j = 0; j < 5; j++) { - TH2F* src = p ? mPull2[j][i] : mRes2[j][i]; - TH1F** dst = p ? mPull[j][i] : mRes[j][i]; - TH1D*& dstIntegral = p ? pullIntegral[j] : resIntegral[j]; - TPad* pad = p ? mPPull[ii][j] : mPRes[ii][j]; - - if (!mConfig.inputHistogramsOnly && ii != 5) { - if (cfit == nullptr) { - cfit = createGarbageCollected<TCanvas>(); - } - cfit->cd(); - - TAxis* axis = src->GetYaxis(); - int nBins = axis->GetNbins(); - int integ = 1; - for (int bin = 1; bin <= nBins; bin++) { - int bin0 = std::max(bin - integ, 0); - int bin1 = std::min(bin + integ, nBins); - std::unique_ptr<TH1D> proj{src->ProjectionX("proj", bin0, bin1)}; - proj->ClearUnderflowAndOverflow(); - if (proj->GetEntries()) { - unsigned int rebin = 1; - while (proj->GetMaximum() < 50 && rebin < sizeof(RES_AXIS_BINS) / sizeof(RES_AXIS_BINS[0])) { - proj->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]); - rebin++; - } - - if (proj->GetEntries() < 20 || proj->GetRMS() < 0.00001) { - dst[0]->SetBinContent(bin, proj->GetRMS()); - dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS())); - dst[1]->SetBinContent(bin, proj->GetMean()); - dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS())); - } else { - proj->GetXaxis()->SetRangeUser(proj->GetMean() - 6. * proj->GetRMS(), proj->GetMean() + 6. * proj->GetRMS()); - proj->GetXaxis()->SetRangeUser(proj->GetMean() - 3. * proj->GetRMS(), proj->GetMean() + 3. * proj->GetRMS()); - bool forceLogLike = proj->GetMaximum() < 20; - for (int k = forceLogLike ? 2 : 0; k < 3; k++) { - proj->Fit("gaus", forceLogLike || k == 2 ? "sQl" : k ? "sQww" : "sQ"); - TF1* fitFunc = proj->GetFunction("gaus"); - - if (k && !forceLogLike) { - customGaus->SetParameters(fitFunc->GetParameter(0), fitFunc->GetParameter(1), fitFunc->GetParameter(2)); - proj->Fit(customGaus.get(), "sQ"); - fitFunc = customGaus.get(); - } - - const float sigma = fabs(fitFunc->GetParameter(2)); - dst[0]->SetBinContent(bin, sigma); - dst[1]->SetBinContent(bin, fitFunc->GetParameter(1)); - dst[0]->SetBinError(bin, fitFunc->GetParError(2)); - dst[1]->SetBinError(bin, fitFunc->GetParError(1)); - - const bool fail1 = sigma <= 0.f; - const bool fail2 = fabs(proj->GetMean() - dst[1]->GetBinContent(bin)) > std::min<float>(p ? PULL_AXIS : mConfig.nativeFitResolutions ? RES_AXES_NATIVE[j] : RES_AXES[j], 3.f * proj->GetRMS()); - const bool fail3 = dst[0]->GetBinContent(bin) > 3.f * proj->GetRMS() || dst[0]->GetBinError(bin) > 1 || dst[1]->GetBinError(bin) > 1; - const bool fail4 = fitFunc->GetParameter(0) < proj->GetMaximum() / 5.; - const bool fail = fail1 || fail2 || fail3 || fail4; - // if (p == 0 && ii == 4 && j == 2) DrawHisto(proj, Form("Hist_bin_%d-%d_vs_%d____%d_%d___%f-%f___%f-%f___%d.pdf", p, j, ii, bin, k, dst[0]->GetBinContent(bin), proj->GetRMS(), dst[1]->GetBinContent(bin), proj->GetMean(), (int) fail), ""); - - if (!fail) { - break; - } else if (k >= 2) { - dst[0]->SetBinContent(bin, proj->GetRMS()); - dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS())); - dst[1]->SetBinContent(bin, proj->GetMean()); - dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS())); - } - } - } - } else { - dst[0]->SetBinContent(bin, 0.f); - dst[0]->SetBinError(bin, 0.f); - dst[1]->SetBinContent(bin, 0.f); - dst[1]->SetBinError(bin, 0.f); - } - } - if (ii == 0) { - dstIntegral = src->ProjectionX(mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j], 0, nBins + 1); - unsigned int rebin = 1; - while (dstIntegral->GetMaximum() < 50 && rebin < sizeof(RES_AXIS_BINS) / sizeof(RES_AXIS_BINS[0])) { - dstIntegral->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]); - rebin++; - } - } - } - if (ii == 0) { - if (mConfig.inputHistogramsOnly) { - dstIntegral = createGarbageCollected<TH1D>(); - } - sprintf(fname, p ? "IntPull%s" : "IntRes%s", VSPARAMETER_NAMES[j]); - sprintf(name, p ? "%s Pull" : "%s Resolution", p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j]); - dstIntegral->SetName(fname); - dstIntegral->SetTitle(name); - } - if (!mRunForQC || mConfig.shipToQCAsCanvas) { - pad->cd(); - } - int numColor = 0; - float tmpMax = -1000.; - float tmpMin = 1000.; - - for (int l = 0; l < 2; l++) { - for (int k = 0; k < ConfigNumInputs; k++) { - TH1F* e = dst[l]; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - if (nNewInput && k == 0 && ii != 5) { - if (p == 0) { - e->Scale(mConfig.nativeFitResolutions ? SCALE_NATIVE[j] : SCALE[j]); - } - } - if (ii == 4) { - e->GetXaxis()->SetRangeUser(0.2, PT_MAX); - } else if (LOG_PT_MIN > 0 && ii == 5) { - e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX); - } else if (ii == 5) { - e->GetXaxis()->SetRange(1, 0); - } - e->SetMinimum(-1111); - e->SetMaximum(-1111); - - if (e->GetMaximum() > tmpMax) { - tmpMax = e->GetMaximum(); - } - if (e->GetMinimum() < tmpMin) { - tmpMin = e->GetMinimum(); - } - } - } - - float tmpSpan; - tmpSpan = tmpMax - tmpMin; - tmpMax += tmpSpan * .02; - tmpMin -= tmpSpan * .02; - if (j == 2 && i < 3) { - tmpMax += tmpSpan * 0.13 * ConfigNumInputs; - } - - for (int k = 0; k < ConfigNumInputs; k++) { - for (int l = 0; l < 2; l++) { - TH1F* e = dst[l]; - if (!mConfig.inputHistogramsOnly && k == 0) { - sprintf(name, p ? "%s Pull" : "%s Resolution", p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j]); - e->SetTitle(name); - e->SetStats(kFALSE); - if (tout) { - if (l == 0) { - mRes2[j][i]->SetOption("colz"); - mRes2[j][i]->Write(); - } - e->Write(); - } - } else if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(tmpMax); - e->SetMinimum(tmpMin); - e->SetLineWidth(1); - e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); - SetAxisSize(e); - e->GetYaxis()->SetTitle(p ? AXIS_TITLES_PULL[j] : mConfig.nativeFitResolutions ? AXIS_TITLES_NATIVE[j] : AXIS_TITLES[j]); - e->GetXaxis()->SetTitle(XAXIS_TITLES[i]); - if (LOG_PT_MIN > 0 && ii == 5) { - e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX); - } - - if (j == 0) { - e->GetYaxis()->SetTitleOffset(1.5); - } else if (j < 3) { - e->GetYaxis()->SetTitleOffset(1.4); - } - if (qcout && !mConfig.shipToQCAsCanvas) { - qcout->Add(e); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - e->SetMarkerColor(kBlack); - e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); - e->Draw(k || l ? "same" : ""); - if (j == 0) { - GetName(fname, k); - if (p) { - sprintf(name, "%s%s", fname, l ? "Mean" : "Pull"); - } else { - sprintf(name, "%s%s", fname, l ? "Mean" : "Resolution"); - } - leg->AddEntry(e, name, "l"); - } - } - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - if (ii == 5) { - pad->SetLogx(); - } - can->cd(); - if (j == 4) { - ChangePadTitleSize(pad, 0.056); - } - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - leg->Draw(); - - if (mRunForQC) { - if (qcout) { - qcout->Add(can); - } - continue; - } - doPerfFigure(0.2, 0.295, 0.025); - can->Print(Form(p ? "plots/pull_vs_%s.pdf" : "plots/res_vs_%s.pdf", VSPARAMETER_NAMES[ii])); - if (mConfig.writeRootFiles) { - can->Print(Form(p ? "plots/pull_vs_%s.root" : "plots/res_vs_%s.root", VSPARAMETER_NAMES[ii])); - } - } - } - - // Process Integral Resolution Histogreams - for (int p = 0; p < 2; p++) { - TCanvas* can = p ? mCPull[6] : mCRes[6]; - for (int i = 0; i < 5; i++) { - TPad* pad = p ? mPPull[6][i] : mPRes[6][i]; - TH1D* hist = p ? pullIntegral[i] : resIntegral[i]; - int numColor = 0; - if (!mRunForQC || mConfig.shipToQCAsCanvas) { - pad->cd(); - } - if (!mConfig.inputHistogramsOnly && mcAvail) { - TH1D* e = hist; - e->GetEntries(); - e->Fit("gaus", "sQ"); - } - - float tmpMax = 0; - for (int k = 0; k < ConfigNumInputs; k++) { - TH1D* e = hist; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(-1111); - if (e->GetMaximum() > tmpMax) { - tmpMax = e->GetMaximum(); - } - } - - for (int k = 0; k < ConfigNumInputs; k++) { - TH1D* e = hist; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(tmpMax * 1.02); - e->SetMinimum(tmpMax * -0.02); - if (tout && !mConfig.inputHistogramsOnly && k == 0) { - e->Write(); - } - if (qcout && !mConfig.shipToQCAsCanvas) { - qcout->Add(e); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); - e->Draw(k == 0 ? "" : "same"); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - can->cd(); - } - if (mRunForQC) { - if (qcout) { - qcout->Add(can); - } - continue; - } - - can->Print(p ? "plots/pull_integral.pdf" : "plots/res_integral.pdf"); - if (mConfig.writeRootFiles) { - can->Print(p ? "plots/pull_integral.root" : "plots/res_integral.root"); - } - } - - // Process Cluster Histograms - { - if (mConfig.inputHistogramsOnly == 0) { - for (int i = N_CLS_HIST; i < N_CLS_TYPE * N_CLS_HIST - 1; i++) { - mClusters[i]->Sumw2(true); - } - double totalVal = 0; - if (!CLUST_HIST_INT_SUM) { - for (int j = 0; j < mClusters[N_CLS_HIST - 1]->GetXaxis()->GetNbins() + 2; j++) { - totalVal += mClusters[N_CLS_HIST - 1]->GetBinContent(j); - } - } - if (totalVal == 0.) { - totalVal = 1.; - } - unsigned long long int counts[N_CLS_HIST]; - for (int i = 0; i < N_CLS_HIST; i++) { - double val = 0; - for (int j = 0; j < mClusters[i]->GetXaxis()->GetNbins() + 2; j++) { - val += mClusters[i]->GetBinContent(j); - mClusters[2 * N_CLS_HIST - 1 + i]->SetBinContent(j, val / totalVal); - } - counts[i] = val; - } - mClusterCounts.nRejected += mClusterCounts.nHighIncl; - if (!mcAvail) { - counts[N_CLS_HIST - 1] = mClusterCounts.nTotal; - } - if (counts[N_CLS_HIST - 1] && !mRunForQC) { - if (mcAvail) { - for (int i = 0; i < N_CLS_HIST; i++) { - printf("\t%35s: %'12llu (%6.2f%%)\n", CLUSTER_NAMES[i], counts[i], 100.f * counts[i] / counts[N_CLS_HIST - 1]); - } - printf("\t%35s: %'12llu (%6.2f%%)\n", "Unattached", counts[N_CLS_HIST - 1] - counts[CL_att_adj], 100.f * (counts[N_CLS_HIST - 1] - counts[CL_att_adj]) / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Removed", counts[CL_att_adj] - counts[CL_prot], 100.f * (counts[CL_att_adj] - counts[CL_prot]) / counts[N_CLS_HIST - 1]); // Attached + Adjacent (also fake) - protected - printf("\t%35s: %'12llu (%6.2f%%)\n", "Unaccessible", (unsigned long long int)mClusterCounts.nUnaccessible, 100.f * mClusterCounts.nUnaccessible / counts[N_CLS_HIST - 1]); // No contribution from track >= 10 MeV, unattached or fake-attached/adjacent - } else { - printf("\t%35s: %'12llu (%6.2f%%)\n", "All Clusters", counts[N_CLS_HIST - 1], 100.f); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Used in Physics", mClusterCounts.nPhysics, 100.f * mClusterCounts.nPhysics / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Protected", mClusterCounts.nProt, 100.f * mClusterCounts.nProt / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Unattached", mClusterCounts.nUnattached, 100.f * mClusterCounts.nUnattached / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Removed", mClusterCounts.nTotal - mClusterCounts.nUnattached - mClusterCounts.nProt, 100.f * (mClusterCounts.nTotal - mClusterCounts.nUnattached - mClusterCounts.nProt) / counts[N_CLS_HIST - 1]); - } - - printf("\t%35s: %'12llu (%6.2f%%)\n", "Merged Loopers (Afterburner)", mClusterCounts.nMergedLooper, 100.f * mClusterCounts.nMergedLooper / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "High Inclination Angle", mClusterCounts.nHighIncl, 100.f * mClusterCounts.nHighIncl / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Rejected", mClusterCounts.nRejected, 100.f * mClusterCounts.nRejected / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Tube (> 200 MeV)", mClusterCounts.nTube, 100.f * mClusterCounts.nTube / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Tube (< 200 MeV)", mClusterCounts.nTube200, 100.f * mClusterCounts.nTube200 / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Looping Legs", mClusterCounts.nLoopers, 100.f * mClusterCounts.nLoopers / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Low Pt < 50 MeV", mClusterCounts.nLowPt, 100.f * mClusterCounts.nLowPt / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Low Pt < 200 MeV", mClusterCounts.n200MeV, 100.f * mClusterCounts.n200MeV / counts[N_CLS_HIST - 1]); - - if (mcAvail) { - printf("\t%35s: %'12llu (%6.2f%%)\n", "Tracks > 400 MeV", mClusterCounts.nAbove400, 100.f * mClusterCounts.nAbove400 / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Fake Removed (> 400 MeV)", mClusterCounts.nFakeRemove400, 100.f * mClusterCounts.nFakeRemove400 / std::max(mClusterCounts.nAbove400, 1ll)); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Full Fake Removed (> 400 MeV)", mClusterCounts.nFullFakeRemove400, 100.f * mClusterCounts.nFullFakeRemove400 / std::max(mClusterCounts.nAbove400, 1ll)); - - printf("\t%35s: %'12llu (%6.2f%%)\n", "Tracks < 40 MeV", mClusterCounts.nBelow40, 100.f * mClusterCounts.nBelow40 / counts[N_CLS_HIST - 1]); - printf("\t%35s: %'12llu (%6.2f%%)\n", "Fake Protect (< 40 MeV)", mClusterCounts.nFakeProtect40, 100.f * mClusterCounts.nFakeProtect40 / std::max(mClusterCounts.nBelow40, 1ll)); - } - } - - if (!CLUST_HIST_INT_SUM) { - for (int i = 0; i < N_CLS_HIST; i++) { - mClusters[2 * N_CLS_HIST - 1 + i]->SetMaximum(1.02); - mClusters[2 * N_CLS_HIST - 1 + i]->SetMinimum(-0.02); - } - } - - for (int i = 0; i < N_CLS_HIST - 1; i++) { - mClusters[N_CLS_HIST + i]->Divide(mClusters[i], mClusters[N_CLS_HIST - 1], 1, 1, "B"); - mClusters[N_CLS_HIST + i]->SetMinimum(-0.02); - mClusters[N_CLS_HIST + i]->SetMaximum(1.02); - } - } - - float tmpMax[2] = {0, 0}, tmpMin[2] = {0, 0}; - for (int l = 0; l <= CLUST_HIST_INT_SUM; l++) { - for (int k = 0; k < ConfigNumInputs; k++) { - TH1* e = mClusters[l ? (N_CLS_TYPE * N_CLS_HIST - 2) : (N_CLS_HIST - 1)]; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMinimum(-1111); - e->SetMaximum(-1111); - if (l == 0) { - e->GetXaxis()->SetRange(2, AXIS_BINS[4]); - } - if (e->GetMaximum() > tmpMax[l]) { - tmpMax[l] = e->GetMaximum(); - } - if (e->GetMinimum() < tmpMin[l]) { - tmpMin[l] = e->GetMinimum(); - } - } - for (int k = 0; k < ConfigNumInputs; k++) { - for (int i = 0; i < N_CLS_HIST; i++) { - TH1* e = mClusters[l ? (2 * N_CLS_HIST - 1 + i) : i]; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(tmpMax[l] * 1.02); - e->SetMinimum(tmpMax[l] * -0.02); - } - } - } - - for (int i = 0; i < N_CLS_TYPE; i++) { - if (!mRunForQC || mConfig.shipToQCAsCanvas) { - mPClust[i]->cd(); - mPClust[i]->SetLogx(); - } - int begin = i == 2 ? (2 * N_CLS_HIST - 1) : i == 1 ? N_CLS_HIST : 0; - int end = i == 2 ? (3 * N_CLS_HIST - 1) : i == 1 ? (2 * N_CLS_HIST - 1) : N_CLS_HIST; - int numColor = 0; - for (int k = 0; k < ConfigNumInputs; k++) { - for (int j = end - 1; j >= begin; j--) { - TH1* e = mClusters[j]; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - - e->SetTitle(CLUSTER_TITLES[i]); - e->GetYaxis()->SetTitle(i == 0 ? "Number of TPC clusters" : i == 1 ? "Fraction of TPC clusters" : CLUST_HIST_INT_SUM ? "Total TPC clusters (integrated)" : "Fraction of TPC clusters (integrated)"); - e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); - e->GetXaxis()->SetTitleOffset(1.1); - e->GetXaxis()->SetLabelOffset(-0.005); - if (tout && !mConfig.inputHistogramsOnly && k == 0) { - e->Write(); - } - e->SetStats(kFALSE); - e->SetLineWidth(1); - e->SetLineStyle(CONFIG_DASHED_MARKERS ? j + 1 : 1); - if (i == 0) { - e->GetXaxis()->SetRange(2, AXIS_BINS[4]); - } - if (qcout && !mConfig.shipToQCAsCanvas) { - qcout->Add(e); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - e->SetMarkerColor(kBlack); - e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); - e->Draw(j == end - 1 && k == 0 ? "" : "same"); - GetName(fname, k); - sprintf(name, "%s%s", fname, CLUSTER_NAMES[j - begin]); - mLClust[i]->AddEntry(e, name, "l"); - } - } - if (ConfigNumInputs == 1) { - TH1* e = reinterpret_cast<TH1F*>(mClusters[begin + CL_att_adj]->Clone()); - e->Add(mClusters[begin + CL_prot], -1); - if (qcout && !mConfig.shipToQCAsCanvas) { - qcout->Add(e); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); - e->Draw("same"); - mLClust[i]->AddEntry(e, "Removed", "l"); - } - if (mRunForQC && !mConfig.shipToQCAsCanvas) { - continue; - } - - mLClust[i]->Draw(); - - if (mRunForQC) { - if (qcout) { - qcout->Add(mCClust[i]); - } - continue; - } - doPerfFigure(i != 2 ? 0.37 : 0.6, 0.295, 0.030); - mCClust[i]->cd(); - mCClust[i]->Print(i == 2 ? "plots/clusters_integral.pdf" : i == 1 ? "plots/clusters_relative.pdf" : "plots/clusters.pdf"); - if (mConfig.writeRootFiles) { - mCClust[i]->Print(i == 2 ? "plots/clusters_integral.root" : i == 1 ? "plots/clusters_relative.root" : "plots/clusters.root"); - } - } - } - - // Process track statistic histograms - if (!mRunForQC) { - float tmpMax = 0.; - for (int k = 0; k < ConfigNumInputs; k++) { - TH1F* e = mTracks; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(-1111); - if (e->GetMaximum() > tmpMax) { - tmpMax = e->GetMaximum(); - } - } - mPTracks->cd(); - mPTracks->SetLogx(); - for (int k = 0; k < ConfigNumInputs; k++) { - TH1F* e = mTracks; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - if (tout && !mConfig.inputHistogramsOnly && k == 0) { - e->Write(); - } - e->SetMaximum(tmpMax * 1.02); - e->SetMinimum(tmpMax * -0.02); - e->SetStats(kFALSE); - e->SetLineWidth(1); - e->GetYaxis()->SetTitle("a.u."); - e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); - if (qcout) { - qcout->Add(e); - } - e->SetMarkerColor(kBlack); - e->SetLineColor(colorNums[k % COLORCOUNT]); - e->Draw(k == 0 ? "" : "same"); - GetName(fname, k); - sprintf(name, "%sTrack Pt", fname); - mLTracks->AddEntry(e, name, "l"); - } - mLTracks->Draw(); - mCTracks->cd(); - mCTracks->Print("plots/tracks.pdf"); - if (mConfig.writeRootFiles) { - mCTracks->Print("plots/tracks.root"); - } - tmpMax = 0.; - for (int k = 0; k < ConfigNumInputs; k++) { - TH1F* e = mNCl; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->SetMaximum(-1111); - if (e->GetMaximum() > tmpMax) { - tmpMax = e->GetMaximum(); - } - } - mPNCl->cd(); - for (int k = 0; k < ConfigNumInputs; k++) { - TH1F* e = mNCl; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - if (tout && !mConfig.inputHistogramsOnly && k == 0) { - e->Write(); - } - e->SetMaximum(tmpMax * 1.02); - e->SetMinimum(tmpMax * -0.02); - e->SetStats(kFALSE); - e->SetLineWidth(1); - e->GetYaxis()->SetTitle("a.u."); - e->GetXaxis()->SetTitle("NClusters"); - if (qcout) { - qcout->Add(e); - } - e->SetMarkerColor(kBlack); - e->SetLineColor(colorNums[k % COLORCOUNT]); - e->Draw(k == 0 ? "" : "same"); - GetName(fname, k); - sprintf(name, "%sNClusters", fname); - mLNCl->AddEntry(e, name, "l"); - } - mLNCl->Draw(); - mCNCl->cd(); - mCNCl->Print("plots/nClusters.pdf"); - if (mConfig.writeRootFiles) { - mCNCl->Print("plots/nClusters.root"); - } - } - - if (tout && !mConfig.inputHistogramsOnly && mConfig.writeMCLabels) { - gInterpreter->GenerateDictionary("vector<vector<int>>", ""); - tout->WriteObject(&mcEffBuffer, "mcEffBuffer"); - tout->WriteObject(&mcLabelBuffer, "mcLabelBuffer"); - remove("AutoDict_vector_vector_int__.cxx"); - remove("AutoDict_vector_vector_int___cxx_ACLiC_dict_rdict.pcm"); - remove("AutoDict_vector_vector_int___cxx.d"); - remove("AutoDict_vector_vector_int___cxx.so"); - } - - if (tout) { - tout->Close(); - } - for (unsigned int i = 0; i < mConfig.compareInputs.size(); i++) { - tin[i]->Close(); - } - if (!qcout) { - clearGarbagageCollector(); - } - return (0); -} diff --git a/GPU/GPUTracking/Standalone/qconfigoptions.h b/GPU/GPUTracking/Standalone/qconfigoptions.h deleted file mode 100644 index 5c44f007ffd47..0000000000000 --- a/GPU/GPUTracking/Standalone/qconfigoptions.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file qconfigoptions.h -/// \author David Rohr - -#include "GPUSettings.h" // Usually we are included from GPUSettings.h, so this doesn't do anything. - // But ROOT or qconfig.cpp will include us directly, so load the settings first. -#include "GPUSettingsList.h" diff --git a/GPU/GPUTracking/Standalone/tools/.gitignore b/GPU/GPUTracking/Standalone/tools/.gitignore index 313c07d6e8ca4..6ddce7f156a23 100644 --- a/GPU/GPUTracking/Standalone/tools/.gitignore +++ b/GPU/GPUTracking/Standalone/tools/.gitignore @@ -2,3 +2,4 @@ *.bc *.cl *.spv +*.spirv diff --git a/GPU/GPUTracking/Standalone/tools/createGeo.C b/GPU/GPUTracking/Standalone/tools/createGeo.C index 81e6ed7e3cbd6..b0837ff2604b4 100644 --- a/GPU/GPUTracking/Standalone/tools/createGeo.C +++ b/GPU/GPUTracking/Standalone/tools/createGeo.C @@ -17,7 +17,7 @@ void createGeo() gm->createClusterMatrixArray(); o2::trd::GeometryFlat gf(*gm); //if (!gf.readMatricesFromFile()) return; // uncomment this line when the matrices dumped from AliRoot should be used - gSystem->Load("libO2GPUTracking.so"); + gSystem->Load("libO2GPUTracking"); GPUReconstruction* rec = GPUReconstruction::CreateInstance(GPUReconstruction::DeviceType::CPU); GPUChainTracking* chain = rec->AddChain<GPUChainTracking>(); chain->SetTRDGeometry(&gf); diff --git a/GPU/GPUTracking/Standalone/tools/createLUT.C b/GPU/GPUTracking/Standalone/tools/createLUT.C index 53534273277c2..ae146c92e4608 100644 --- a/GPU/GPUTracking/Standalone/tools/createLUT.C +++ b/GPU/GPUTracking/Standalone/tools/createLUT.C @@ -10,7 +10,7 @@ using namespace GPUCA_NAMESPACE::gpu; void createLUT() { o2::base::MatLayerCylSet* lut = o2::base::MatLayerCylSet::loadFromFile("matbud.root", "MatBud"); - gSystem->Load("libO2GPUTracking.so"); + gSystem->Load("libO2GPUTracking"); GPUReconstruction* rec = GPUReconstruction::CreateInstance(GPUReconstruction::DeviceType::CPU); GPUChainTracking* chain = rec->AddChain<GPUChainTracking>(); chain->SetMatLUT(lut); diff --git a/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh b/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh index 6eeb456d272c1..302e3847c4219 100755 --- a/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh +++ b/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh @@ -9,7 +9,7 @@ nvcc -std=c++17 -gencode arch=compute_75,code=sm_75 -E \ -I$HOME/alice/O2/DataFormats/Detectors/TPC/include -I$HOME/alice/O2/Detectors/Base/include -I$HOME/alice/O2/Detectors/Base/src -I$HOME/alice/O2/Common/MathUtils/include -I$HOME/alice/O2/DataFormats/Headers/include \ -I$HOME/alice/O2/Detectors/TRD/base/include -I$HOME/alice/O2/Detectors/TRD/base/src -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/include -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/cuda/include -I$HOME/alice/O2/Common/Constants/include \ -I$HOME/alice/O2/DataFormats/common/include -I$HOME/alice/O2/DataFormats/Detectors/TRD/include -I$HOME/alice/O2/Detectors/Raw/include \ - -DHAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2 -DGPUCA_STANDALONE -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPUCODE_GENRTC \ + -DGPUCA_HAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2 -DGPUCA_STANDALONE -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPUCODE_GENRTC \ ~/alice/O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu \ | sed '1,/^# 1 ".*GPUReconstructionCUDArtcPre.h" 1$/d' \ >> source.cu diff --git a/GPU/GPUTracking/Standalone/tools/showLooperMergingStat.txt b/GPU/GPUTracking/Standalone/tools/showLooperMergingStat.txt new file mode 100644 index 0000000000000..6fb88b2851352 --- /dev/null +++ b/GPU/GPUTracking/Standalone/tools/showLooperMergingStat.txt @@ -0,0 +1,27 @@ +new TCanvas("qpttglsign") +mergeloopers->Draw("tgl2:tgl1>>qpttglsign(100,-0.2,0.2,100,-0.2,0.2)", "labeleq>0.5 && qpt1 * tgl1 * qpt2 * tgl2 < 0 && fabsf(tgl1) < 0.2 && fabsf(tgl2) < 0.2", "colz") +new TCanvas("okxy") +mergeloopers->Draw("(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) >> okxy(100,0,40)", "labeleq > 0.5") +new TCanvas("okxy2") +mergeloopers->Draw("x1-x2:y1-y2 >> okxy(100,-10,10,100,-10,10)", "labeleq > 0.5") +new TCanvas("failxy") +mergeloopers->Draw("(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) >> failxy(100,0,40)", "labeleq < 0.5") +new TCanvas("oktgl") +mergeloopers->Draw("tgl1-tgl2 >> oktgl(100,0,40)", "labeleq > 0.5") +new TCanvas("failtgl") +mergeloopers->Draw("tgl1-tgl2 >> failtgl(100,0,40)", "labeleq < 0.5") +new TCanvas("okqpt") +mergeloopers->Draw("qpt1-qpt2 >> okqpt(100,0,40)", "labeleq > 0.5") +new TCanvas("failqpt") +mergeloopers->Draw("qpt1-qpt2 >> failqpt(100,0,40)", "labeleq < 0.5") + +mergeloopers->Draw("2 * 3.1415 * 0.5*(fabs(tgl1) + fabs(tgl2)) * 1./(0.5*(fabsf(qpt1)+fabsf(qpt2))*0.001501)/(fabsf(refz2)-fabsf(refz1))>>test3(1000,0,5)", "labeleq > 0.5 && sameside==1", "colz") + +mergeloopers->Draw("(fabsf(absz2)-fabsf(absz1))/(2 * 3.1415 * 0.5*(fabs(tgl1) + fabs(tgl2)) * 1./(0.5*(fabsf(qpt1)+fabsf(qpt2))*0.001501)):fmodf((asinf(snp1)+a1-asinf(snp2)-a2)/(2*3.1415)+5.5,1.)-0.5>>foo(300,-0.5,0.5,300,0,5)", "labeleq > 0.5 && sameside==1 && qpt1 * qpt2 > 0 && snp1 * snp2 > 0", "colz") + +positive correction, 1 side, 2d: +mergeloopers2->Draw("(fabsf(refz2)-fabsf(refz1))/(2 * 3.1415 * 0.5*(fabs(tgl1) + fabs(tgl2)) * 1./(0.5*(fabsf(qpt1)+fabsf(qpt2))*0.001501)):(fmodf((asinf(snp1)+a1-asinf(snp2)-a2)/(2*3.1415)+5.5,1.)-0.5)>>foo(300,-0.5,0.5,300,0,5)", "labeleq > 0.5 && refz1*refz2>0 && refz1 * qpt1 * tgl1 > 0", "colz") +positive correction, 1 side, 1d: +mergeloopers2->Draw("(fabsf(refz2)-fabsf(refz1))/(2 * 3.1415 * 0.5*(fabs(tgl1) + fabs(tgl2)) * 1./(0.5*(fabsf(qpt1)+fabsf(qpt2))*0.001501))+(fmodf((asinf(snp1)+a1-asinf(snp2)-a2)/(2*3.1415)+5.5,1.)-0.5)>>hh(300,-1,5)", "labeleq > 0.5 && refz1*refz2>0 && refz1 * qpt1 * tgl1 > 0", "colz") +negative correction, 1 side, 2d: +mergeloopers2->Draw("(fabsf(refz2)-fabsf(refz1))/(2 * 3.1415 * 0.5*(fabs(tgl1) + fabs(tgl2)) * 1./(0.5*(fabsf(qpt1)+fabsf(qpt2))*0.001501)):(fmodf((asinf(snp1)+a1-asinf(snp2)-a2)/(2*3.1415)+5.5,1.)-0.5)>>foo(300,-0.5,0.5,300,0,5)", "labeleq > 0.5 && refz1*refz2>0 && refz1 * qpt1 * tgl1 < 0", "colz") diff --git a/GPU/GPUTracking/Standalone/tools/switchToAliRootLicense.sh b/GPU/GPUTracking/Standalone/tools/switchToAliRootLicense.sh index ed3273e7e7698..94545950805a0 100755 --- a/GPU/GPUTracking/Standalone/tools/switchToAliRootLicense.sh +++ b/GPU/GPUTracking/Standalone/tools/switchToAliRootLicense.sh @@ -5,10 +5,10 @@ if [ $(ls | grep GPU | wc -l) != "1" ]; then exit 1 fi -git grep -l "^// Copyright CERN and copyright holders of ALICE O2. This software is" | \ +git grep -l "^// Copyright 2019-2020 CERN and copyright holders of ALICE O2." | \ grep "^GPU/Common/\|^GPU/GPUTracking/\|^GPU/TPCFastTransformation|^GPU/TPCSpaceChargeBase\|^cmake" | \ xargs -r -n 1 \ - sed -i -e '/Copyright CERN and copyright holders of ALICE O2. This software is/,/or submit itself to any jurisdiction/c\ + sed -i -e '/Copyright 2019-2020 CERN and copyright holders of ALICE O2./,/or submit itself to any jurisdiction/c\ //**************************************************************************\ //* This file is property of and copyright by the ALICE Project *\ //* ALICE Experiment at CERN, All rights reserved. *\ diff --git a/GPU/GPUTracking/Standalone/tools/testCL.sh b/GPU/GPUTracking/Standalone/tools/testCL.sh index a980531bbe8d1..923070503437f 100755 --- a/GPU/GPUTracking/Standalone/tools/testCL.sh +++ b/GPU/GPUTracking/Standalone/tools/testCL.sh @@ -3,46 +3,53 @@ COMPILER=clang++ LLVM_SPIRV=llvm-spirv +echo "Testing using clang `which clang++`, spirv `which llvm-spirv`" + #COMPILER=/usr/lib/llvm/roc-2.1.0/bin/clang++ #COMPILER=/usr/lib/llvm/9/bin/clang++ -#COMPILER=/home/qon/clang-build/install/bin/clang++ -#LLVM_SPIRV=/home/qon/clang-build/SPIRV-LLVM-Translator/build/tools/llvm-spirv/llvm-spirv +#COMPILER=/home/qon/alice/llvm-project/build/bin/clang++ +#LLVM_SPIRV=/home/qon/alice/llvm-project/build/bin/llvm-spirv + +O2_DIR=${HOME}/alice/O2 +GPU_DIR=${HOME}/alice/O2/GPU/GPUTracking -INCLUDES="-I../. -I../Base -I../SliceTracker -I../Common -I../Merger -I../TRDTracking -I../ITS -I../dEdx -I../TPCConvert -I../TPCFastTransformation -I../DataCompression -I../TPCClusterFinder -I../Global -I ../GPUUtils \ - -I$HOME/alice/O2/DataFormats/Detectors/TPC/include -I$HOME/alice/O2/Detectors/Base/include -I$HOME/alice/O2/Detectors/Base/src -I$HOME/alice/O2/Common/MathUtils/include -I$HOME/alice/O2/DataFormats/Headers/include \ - -I$HOME/alice/O2/Detectors/TRD/base/include -I$HOME/alice/O2/Detectors/TRD/base/src -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/include -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/cuda/include -I$HOME/alice/O2/Common/Constants/include \ - -I$HOME/alice/O2/DataFormats/common/include -I$HOME/alice/O2/DataFormats/Detectors/TRD/include" -DEFINES="-DGPUCA_STANDALONE -DGPUCA_GPULIBRARY=OCL -DNDEBUG -D__OPENCLCPP__ -DHAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2" -FLAGS="-O3 -cl-denorms-are-zero -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Xclang -finclude-default-header -Dcl_clang_storage_class_specifiers" +INCLUDES="-I${GPU_DIR}/. -I${GPU_DIR}/DataTypes -I${GPU_DIR}/Definitions -I${GPU_DIR}/Base -I${GPU_DIR}/SliceTracker -I${O2_DIR}/GPU/Common -I${GPU_DIR}/Merger -I${GPU_DIR}/Refit -I${GPU_DIR}/TRDTracking -I${GPU_DIR}/ITS -I${GPU_DIR}/dEdx \ + -I${GPU_DIR}/TPCConvert -I${O2_DIR}/GPU/TPCFastTransformation -I${GPU_DIR}/DataCompression -I${GPU_DIR}/TPCClusterFinder -I${GPU_DIR}/Global -I ${O2_DIR}/GPU/Utils \ + -I${O2_DIR}/DataFormats/Detectors/TPC/include -I${O2_DIR}/Detectors/Base/include -I${O2_DIR}/Detectors/Base/src -I${O2_DIR}/Common/MathUtils/include -I${O2_DIR}/DataFormats/Headers/include \ + -I${O2_DIR}/Detectors/TRD/base/include -I${O2_DIR}/Detectors/TRD/base/src -I${O2_DIR}/Detectors/ITSMFT/ITS/tracking/include -I${O2_DIR}/Detectors/ITSMFT/ITS/tracking/cuda/include -I${O2_DIR}/Common/Constants/include \ + -I${O2_DIR}/DataFormats/common/include -I${O2_DIR}/DataFormats/Detectors/Common/include -I${O2_DIR}/DataFormats/Detectors/TRD/include -I${O2_DIR}/DataFormats/Reconstruction/include -I${O2_DIR}/DataFormats/Reconstruction/src \ + -I${O2_DIR}/Detectors/Raw/include" +DEFINES="-DGPUCA_STANDALONE -DGPUCA_GPULIBRARY=OCL -DNDEBUG -D__OPENCLCPP__ -DGPUCA_HAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2" +FLAGS="-Xclang -fdenormal-fp-math-f32=ieee -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Dcl_clang_storage_class_specifiers" echo Test1 - Preprocess -echo $COMPILER -cl-std=clc++ -x cl $INCLUDES $DEFINES -Dcl_clang_storage_class_specifiers -E ../Base/opencl-common/GPUReconstructionOCL.cl > test.cl - $COMPILER -cl-std=clc++ -x cl $INCLUDES $DEFINES -Dcl_clang_storage_class_specifiers -E ../Base/opencl-common/GPUReconstructionOCL.cl > test.cl +echo $COMPILER -cl-std=clc++ -x cl $INCLUDES $DEFINES -Dcl_clang_storage_class_specifiers -cl-no-stdinc -E ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl > test.cl + $COMPILER -cl-std=clc++ -x cl $INCLUDES $DEFINES -Dcl_clang_storage_class_specifiers -cl-no-stdinc -E ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl > test.cl if [ $? != 0 ]; then exit 1; fi -#Test 1A - Compile Preprocessed -#echo $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS -c test.cl -o test.bc -# $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS -c test.cl -o test.bc -#exit +echo Test 1A - Compile Preprocessed +echo $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS -c test.cl -o test.bc + $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS -c test.cl -o test.bc echo -echo Test2 - Clang OCL -echo clang-ocl -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test-clang-ocl.o ../Base/opencl-common/GPUReconstructionOCL.cl - clang-ocl -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test-clang-ocl.o ../Base/opencl-common/GPUReconstructionOCL.cl -rm -f test-clang-ocl.o.* +echo Test2 - SPIR-V +echo $COMPILER -O0 -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS $INCLUDES $DEFINES -c ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl -o test.bc + $COMPILER -O0 -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS $INCLUDES $DEFINES -c ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl -o test.bc +if [ $? != 0 ]; then exit 1; fi +echo $LLVM_SPIRV test.bc -o test.spirv + $LLVM_SPIRV test.bc -o test.spirv if [ $? != 0 ]; then exit 1; fi echo -echo Test3 - SPIR-V -echo $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS $INCLUDES $DEFINES -c ../Base/opencl-common/GPUReconstructionOCL.cl -o test.bc - $COMPILER -cl-std=clc++ -x cl -emit-llvm --target=spir64-unknown-unknown $FLAGS $INCLUDES $DEFINES -c ../Base/opencl-common/GPUReconstructionOCL.cl -o test.bc -if [ $? != 0 ]; then exit 1; fi -echo $LLVM_SPIRV test.bc - $LLVM_SPIRV test.bc +echo Test3 - amdgcn +echo $COMPILER -O3 -cl-std=clc++ -x cl --target=amdgcn-amd-amdhsa -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -c ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl -o test.o + $COMPILER -O3 -cl-std=clc++ -x cl --target=amdgcn-amd-amdhsa -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -c ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl -o test.o if [ $? != 0 ]; then exit 1; fi echo -echo Test4 - amdgcn -echo $COMPILER -cl-std=clc++ -x cl --target=amdgcn-amd-amdhsa -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -c ../Base/opencl-common/GPUReconstructionOCL.cl -o test.o - $COMPILER -cl-std=clc++ -x cl --target=amdgcn-amd-amdhsa -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -c ../Base/opencl-common/GPUReconstructionOCL.cl -o test.o +echo Test4 - Clang OCL +echo clang-ocl -O3 -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test-clang-ocl.o ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl + clang-ocl -O3 -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test-clang-ocl.o ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl +rm -f test-clang-ocl.o.* if [ $? != 0 ]; then exit 1; fi + diff --git a/GPU/GPUTracking/Standalone/utils/.gitignore b/GPU/GPUTracking/Standalone/utils/.gitignore deleted file mode 100644 index 27d037d6f72f7..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -/get_private_profile.h -/os_low_level_helper.h -/affinity.cxx -/affinity.h -/qmath.h -/qmultialloc.* -/qmalloc.* -/sched_affinity_win32_wrapper.h -/switchtemplate.h -/util_adl.cxx -/util_adl.h -/vecpodtest.cxx -/*.cpp -/*.sh diff --git a/GPU/GPUTracking/Standalone/utils/linux_helpers.h b/GPU/GPUTracking/Standalone/utils/linux_helpers.h deleted file mode 100644 index 21fb3e49d3914..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/linux_helpers.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file linux_helpers.h -/// \author David Rohr - -#ifndef LINUX_HELPERS_H -#define LINUX_HELPERS_H - -#include <termios.h> -#include <unistd.h> -#include <sys/ioctl.h> - -static inline int getch() -{ - static struct termios oldt, newt; - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - int retVal = getchar(); - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - return (retVal); -} - -static inline int kbhit() -{ - termios term; - tcgetattr(0, &term); - termios term2 = term; - term2.c_lflag &= ~ICANON; - tcsetattr(0, TCSANOW, &term2); - int byteswaiting; - ioctl(0, FIONREAD, &byteswaiting); - tcsetattr(0, TCSANOW, &term); - return byteswaiting > 0; -} - -static void inline Sleep(int msecs) { usleep(msecs * 1000); } - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/qconfig_helpers.h b/GPU/GPUTracking/Standalone/utils/qconfig_helpers.h deleted file mode 100644 index d230dcbf419b1..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/qconfig_helpers.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file qconfig_helpers.h -/// \author David Rohr - -#ifndef QCONFIG_HELPERS_H -#define QCONFIG_HELPERS_H - -#include <string> -#include <sstream> - -namespace qConfig -{ -template <class T> -std::string print_type(T val) -{ - std::ostringstream s; - s << val; - return s.str(); -}; -template <> -std::string print_type<char>(char val) -{ - return std::to_string(val); -}; -template <> -std::string print_type<unsigned char>(unsigned char val) -{ - return std::to_string(val); -}; -template <> -std::string print_type<bool>(bool val) -{ - return val ? "true" : "false"; -}; -} // namespace qConfig - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/qconfigrtc.h b/GPU/GPUTracking/Standalone/utils/qconfigrtc.h deleted file mode 100644 index 0420d4cc66cf4..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/qconfigrtc.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file qconfigrtc.h -/// \author David Rohr - -#ifndef QCONFIG_RTC_H -#define QCONFIG_RTC_H - -#include "qconfig.h" -#include "qconfig_helpers.h" - -#ifndef qon_mxstr -#define qon_mstr(a) #a -#define qon_mxstr(a) qon_mstr(a) -#endif - -template <class T> -static std::string qConfigPrintRtc(const T& tSrc, bool useConstexpr) -{ - std::stringstream out; -#define QCONFIG_PRINT_RTC -#include "qconfig.h" -#undef QCONFIG_PRINT_RTC - return out.str(); -} - -#define QCONFIG_CONVERT_RTC -#include "qconfig.h" -#undef QCONFIG_CONVERT_RTC - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/qmaths_helpers.h b/GPU/GPUTracking/Standalone/utils/qmaths_helpers.h deleted file mode 100644 index e593f7fd777aa..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/qmaths_helpers.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file qmaths_helpers.h -/// \author David Rohr - -#ifndef QMATH_HELPERS_H -#define QMATH_HELPERS_H - -#if defined __has_include -#if __has_include(<xmmintrin.h>) && __has_include(<pmmintrin.h>) -#include <xmmintrin.h> -#include <pmmintrin.h> -#if defined(_MM_FLUSH_ZERO_OFF) && defined(_MM_DENORMALS_ZERO_ON) -static void disable_denormals() -{ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); -} -#define XMM_HAS_DENORMAL_DEACTIVATE -#endif -#endif -#endif -#ifdef XMM_HAS_DENORMAL_DEACTIVATE -#undef XMM_HAS_DENORMAL_DEACTIVATE -#else -static void disable_denormals() {} -#endif - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/qsem.h b/GPU/GPUTracking/Standalone/utils/qsem.h deleted file mode 100644 index 75c5e52ccdb35..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/qsem.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file qsem.h -/// \author David Rohr - -#ifndef QSEM_H -#define QSEM_H - -#ifdef _WIN32 -#include "pthread_mutex_win32_wrapper.h" -#else -#include <semaphore.h> -#endif - -class qSem -{ - public: - qSem(int num = 1); - ~qSem(); - - int Lock(); - int Unlock(); - int Trylock(); - int Query(); - - private: - int max; - sem_t sem; -}; - -class qSignal -{ - private: - qSem sem; - - public: - qSignal() : sem(0) {} - void Wait() { sem.Lock(); } - void Signal() { sem.Unlock(); } -}; - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/threadserver.cxx b/GPU/GPUTracking/Standalone/utils/threadserver.cxx deleted file mode 100644 index 2791c1b979c59..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/threadserver.cxx +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file threadserver.cxx -/// \author David Rohr - -#include <cstdio> - -#ifndef STD_OUT -#define STD_OUT stdout -#endif - -#include "threadserver.h" diff --git a/GPU/GPUTracking/Standalone/utils/timer.h b/GPU/GPUTracking/Standalone/utils/timer.h deleted file mode 100644 index fe9524393e660..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/timer.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file timer.h -/// \author David Rohr - -#ifndef QONMODULE_TIMER_H -#define QONMODULE_TIMER_H - -class HighResTimer -{ - public: - HighResTimer() = default; - ~HighResTimer() = default; - void Start(); - void Stop(); - void Reset(); - void ResetStart(); - double GetElapsedTime(); - double GetCurrentElapsedTime(bool reset = false); - void StopAndStart(HighResTimer& startTimer); - int IsRunning() { return running; } - void AddTime(double t); - - private: - double ElapsedTime = 0.; - double StartTime = 0.; - int running = 0; - - static double GetFrequency(); - static double GetTime(); -#ifndef GPUCODE - static double Frequency; -#endif -}; - -#endif diff --git a/GPU/GPUTracking/Standalone/utils/vecpod.h b/GPU/GPUTracking/Standalone/utils/vecpod.h deleted file mode 100644 index 1f49430c7d5f2..0000000000000 --- a/GPU/GPUTracking/Standalone/utils/vecpod.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file vecpod.h -/// \author David Rohr - -#include <vector> - -template <class T> -struct vecpod_allocator { - typedef T value_type; - vecpod_allocator() noexcept : stdalloc() {} - T* allocate(std::size_t n) { return stdalloc.allocate(n); } - void deallocate(T* p, std::size_t n) { stdalloc.deallocate(p, n); } - static void construct(T*) {} - std::allocator<T> stdalloc; -}; - -template <class T> -using vecpod = typename std::vector<T, vecpod_allocator<T>>; -// template <class T> using vecpod = typename std::vector<T>; diff --git a/GPU/GPUTracking/TPCClusterFinder/Array2D.h b/GPU/GPUTracking/TPCClusterFinder/Array2D.h index 07964d4031c63..73057ba2f5e3d 100644 --- a/GPU/GPUTracking/TPCClusterFinder/Array2D.h +++ b/GPU/GPUTracking/TPCClusterFinder/Array2D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -96,7 +97,7 @@ struct GridSize<1> { template <> struct GridSize<2> { enum { - Width = 4, + Width = 8, Height = 4, }; }; diff --git a/GPU/GPUTracking/TPCClusterFinder/CfConsts.h b/GPU/GPUTracking/TPCClusterFinder/CfConsts.h index 62a53afa45efb..31ad34e9d6dc9 100644 --- a/GPU/GPUTracking/TPCClusterFinder/CfConsts.h +++ b/GPU/GPUTracking/TPCClusterFinder/CfConsts.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/CfFragment.h b/GPU/GPUTracking/TPCClusterFinder/CfFragment.h index 2d1574a98ad34..93d8eb8354fae 100644 --- a/GPU/GPUTracking/TPCClusterFinder/CfFragment.h +++ b/GPU/GPUTracking/TPCClusterFinder/CfFragment.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -51,6 +52,11 @@ struct CfFragment { return CfFragment{index + 1, hasFuture, tpccf::TPCTime(start + length - (hasFuture ? 2 * OverlapTimebins : 0)), totalSliceLength, maxSubSliceLength}; } + GPUdi() unsigned int count() const + { + return (totalSliceLength + maxSubSliceLength - 4 * OverlapTimebins - 1) / (maxSubSliceLength - 2 * OverlapTimebins); + } + GPUdi() tpccf::TPCTime first() const { return start; @@ -72,6 +78,21 @@ struct CfFragment { return (hasBacklog ? t < OverlapTimebins : false) || (hasFuture ? t >= (length - OverlapTimebins) : false); } + GPUdi() tpccf::TPCFragmentTime lengthWithoutOverlap() const + { + return length - (hasBacklog ? OverlapTimebins : 0) - (hasFuture ? OverlapTimebins : 0); + } + + GPUdi() tpccf::TPCFragmentTime firstNonOverlapTimeBin() const + { + return (hasBacklog ? OverlapTimebins : 0); + } + + GPUdi() tpccf::TPCFragmentTime lastNonOverlapTimeBin() const + { + return length - (hasFuture ? OverlapTimebins : 0); + } + GPUdi() tpccf::TPCFragmentTime toLocal(tpccf::TPCTime t) const { return t - first(); diff --git a/GPU/GPUTracking/TPCClusterFinder/CfUtils.h b/GPU/GPUTracking/TPCClusterFinder/CfUtils.h index e16353acf6cc3..a9fd3a71d742a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/CfUtils.h +++ b/GPU/GPUTracking/TPCClusterFinder/CfUtils.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -46,7 +47,7 @@ class CfUtils static GPUdi() bool isAboveThreshold(uchar peak) { return peak >> 1; } - template <typename SharedMemory> + template <size_t SCRATCH_PAD_WORK_GROUP_SIZE, typename SharedMemory> static GPUdi() ushort partition(SharedMemory& smem, ushort ll, bool pred, ushort partSize, ushort* newPartSize) { bool participates = ll < partSize; diff --git a/GPU/GPUTracking/TPCClusterFinder/ChargePos.h b/GPU/GPUTracking/TPCClusterFinder/ChargePos.h index 25c245de25f6c..e5033a1f37d95 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ChargePos.h +++ b/GPU/GPUTracking/TPCClusterFinder/ChargePos.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx index 547301ae80a0c..9448e528775d3 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h index d39a4ed10496e..c75575821bacd 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h index 7a01918708164..b52a67e2dee6a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -63,11 +64,7 @@ struct GPUTPCCFChainContext { if (tpcZS) { tpcMaxTimeBin = 0; - CfFragment f = fragmentMax; - while (!f.isEnd()) { - f = f.next(); - } - nFragments = f.index; + nFragments = fragmentMax.count(); if (fragmentData.size() < nFragments) { fragmentData.resize(nFragments); } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx index 8af28459db03c..f2976fff842cc 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -45,10 +46,10 @@ template <> GPUdii() void GPUTPCCFChargeMapFiller::Thread<GPUTPCCFChargeMapFiller::fillFromDigits>(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer) { Array2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap)); - fillFromDigitsImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), clusterer.mPmemory->fragment, clusterer.mPmemory->counters.nPositions, clusterer.mPdigits, clusterer.mPpositions, chargeMap); + fillFromDigitsImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), clusterer, clusterer.mPmemory->fragment, clusterer.mPmemory->counters.nPositions, clusterer.mPdigits, clusterer.mPpositions, chargeMap); } -GPUd() void GPUTPCCFChargeMapFiller::fillFromDigitsImpl(int nBlocks, int nThreads, int iBlock, int iThread, const CfFragment& fragment, size_t digitNum, +GPUd() void GPUTPCCFChargeMapFiller::fillFromDigitsImpl(int nBlocks, int nThreads, int iBlock, int iThread, processorType& clusterer, const CfFragment& fragment, size_t digitNum, const tpc::Digit* digits, ChargePos* positions, Array2D<PackedCharge>& chargeMap) @@ -61,13 +62,15 @@ GPUd() void GPUTPCCFChargeMapFiller::fillFromDigitsImpl(int nBlocks, int nThread ChargePos pos(digit.getRow(), digit.getPad(), fragment.toLocal(digit.getTimeStamp())); positions[idx] = pos; - chargeMap[pos] = PackedCharge(digit.getChargeFloat()); + float q = digit.getChargeFloat(); + q *= clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(clusterer.mISlice, digit.getRow(), digit.getPad()); + chargeMap[pos] = PackedCharge(q); } template <> GPUdii() void GPUTPCCFChargeMapFiller::Thread<GPUTPCCFChargeMapFiller::findFragmentStart>(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, char setPositions) { - if (iThread != 0) { + if (iThread != 0 || iBlock != 0) { return; } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h index 40432943fa362..888665b52f225 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,7 +41,7 @@ class GPUTPCCFChargeMapFiller : public GPUKernelTemplate findFragmentStart, }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { @@ -58,7 +59,7 @@ class GPUTPCCFChargeMapFiller : public GPUKernelTemplate static GPUd() void fillIndexMapImpl(int, int, int, int, const CfFragment&, const tpc::Digit*, Array2D<uint>&, size_t); - static GPUd() void fillFromDigitsImpl(int, int, int, int, const CfFragment&, size_t, const tpc::Digit*, ChargePos*, Array2D<PackedCharge>&); + static GPUd() void fillFromDigitsImpl(int, int, int, int, processorType&, const CfFragment&, size_t, const tpc::Digit*, ChargePos*, Array2D<PackedCharge>&); private: static GPUd() size_t findTransition(int, const tpc::Digit*, size_t, size_t); diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx new file mode 100644 index 0000000000000..181b62c602443 --- /dev/null +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTPCCFCheckPadBaseline.h +/// \author Felix Weiglhofer + +#include "GPUTPCCFCheckPadBaseline.h" +#include "Array2D.h" +#include "PackedCharge.h" +#include "clusterFinderDefs.h" + +#ifndef GPUCA_GPUCODE +#ifndef GPUCA_NO_VC +#include <Vc/Vc> +#else +#include <array> +#endif +#endif + +using namespace GPUCA_NAMESPACE::gpu; +using namespace GPUCA_NAMESPACE::gpu::tpccf; + +template <> +GPUd() void GPUTPCCFCheckPadBaseline::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer) +{ + const CfFragment& fragment = clusterer.mPmemory->fragment; + Array2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap)); + + int basePad = iBlock * PadsPerCacheline; + ChargePos basePos = padToChargePos(basePad, clusterer); + + if (not basePos.valid()) { + return; + } + +#ifdef GPUCA_GPUCODE + static_assert(TPC_MAX_FRAGMENT_LEN % NumOfCachedTimebins == 0); + + int totalCharges = 0; + int consecCharges = 0; + int maxConsecCharges = 0; + + short localPadId = iThread / NumOfCachedTimebins; + short localTimeBin = iThread % NumOfCachedTimebins; + bool handlePad = localTimeBin == 0; + + for (tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin(); t < fragment.lastNonOverlapTimeBin(); t += NumOfCachedTimebins) { + ChargePos pos = basePos.delta({localPadId, short(t + localTimeBin)}); + smem.charges[localPadId][localTimeBin] = (pos.valid()) ? chargeMap[pos].unpack() : 0; + GPUbarrier(); + if (handlePad) { + for (int i = 0; i < NumOfCachedTimebins; i++) { + Charge q = smem.charges[localPadId][i]; + totalCharges += (q > 0); + consecCharges = (q > 0) ? consecCharges + 1 : 0; + maxConsecCharges = CAMath::Max(consecCharges, maxConsecCharges); + } + } + GPUbarrier(); + } + + GPUbarrier(); + + if (handlePad) { + updatePadBaseline(basePad + localPadId, clusterer, totalCharges, maxConsecCharges); + } + +#else // CPU CODE + + constexpr size_t ElemsInTileRow = TilingLayout<GridSize<2>>::WidthInTiles * TimebinsPerCacheline * PadsPerCacheline; + +#ifndef GPUCA_NO_VC + using UShort8 = Vc::fixed_size_simd<unsigned short, PadsPerCacheline>; + + UShort8 totalCharges{Vc::Zero}; + UShort8 consecCharges{Vc::Zero}; + UShort8 maxConsecCharges{Vc::Zero}; +#else + std::array<unsigned short, PadsPerCacheline> totalCharges{0}; + std::array<unsigned short, PadsPerCacheline> consecCharges{0}; + std::array<unsigned short, PadsPerCacheline> maxConsecCharges{0}; +#endif + + tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin(); + const unsigned short* charge = reinterpret_cast<unsigned short*>(&chargeMap[basePos.delta({0, t})]); + + for (; t < fragment.lastNonOverlapTimeBin(); t += TimebinsPerCacheline) { + for (tpccf::TPCFragmentTime localtime = 0; localtime < TimebinsPerCacheline; localtime++) { +#ifndef GPUCA_NO_VC + UShort8 charges{charge + PadsPerCacheline * localtime, Vc::Aligned}; + + UShort8::mask_type isCharge = charges != 0; + + if (isCharge.isNotEmpty()) { + totalCharges(isCharge)++; + consecCharges += 1; + consecCharges(not isCharge) = 0; + maxConsecCharges = Vc::max(consecCharges, maxConsecCharges); + } else { + consecCharges = 0; + } +#else // Vc not available + for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) { + bool isCharge = charge[PadsPerCacheline * localtime + localpad] != 0; + if (isCharge) { + totalCharges[localpad]++; + consecCharges[localpad]++; + maxConsecCharges[localpad] = CAMath::Max(maxConsecCharges[localpad], consecCharges[localpad]); + } else { + consecCharges[localpad] = 0; + } + } +#endif + } + + charge += ElemsInTileRow; + } + + for (tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) { + updatePadBaseline(basePad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad]); + } +#endif +} + +GPUd() ChargePos GPUTPCCFCheckPadBaseline::padToChargePos(int& pad, const GPUTPCClusterFinder& clusterer) +{ + const GPUTPCGeometry& geo = clusterer.Param().tpcGeometry; + + int padOffset = 0; + for (Row r = 0; r < GPUCA_ROW_COUNT; r++) { + int npads = geo.NPads(r); + int padInRow = pad - padOffset; + if (0 <= padInRow && padInRow < CAMath::nextMultipleOf<PadsPerCacheline, int>(npads)) { + int cachelineOffset = padInRow % PadsPerCacheline; + pad -= cachelineOffset; + return ChargePos{r, Pad(padInRow - cachelineOffset), 0}; + } + padOffset += npads; + } + + return ChargePos{0, 0, INVALID_TIME_BIN}; +} + +GPUd() void GPUTPCCFCheckPadBaseline::updatePadBaseline(int pad, const GPUTPCClusterFinder& clusterer, int totalCharges, int consecCharges) +{ + const CfFragment& fragment = clusterer.mPmemory->fragment; + int totalChargesBaseline = clusterer.Param().rec.tpc.maxTimeBinAboveThresholdIn1000Bin * fragment.lengthWithoutOverlap() / 1000; + int consecChargesBaseline = clusterer.Param().rec.tpc.maxConsecTimeBinAboveThreshold; + bool isNoisy = (totalChargesBaseline > 0 && totalCharges >= totalChargesBaseline) || (consecChargesBaseline > 0 && consecCharges >= consecChargesBaseline); + if (isNoisy) { + clusterer.mPpadIsNoisy[pad] = true; + } +} diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h new file mode 100644 index 0000000000000..d654e509eaa20 --- /dev/null +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h @@ -0,0 +1,63 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTPCCFCheckPadBaseline.h +/// \author Felix Weiglhofer + +#ifndef O2_GPU_GPU_TPC_CF_CHECK_PAD_BASELINE_H +#define O2_GPU_GPU_TPC_CF_CHECK_PAD_BASELINE_H + +#include "GPUGeneralKernels.h" +#include "GPUConstantMem.h" + +#include "clusterFinderDefs.h" + +namespace GPUCA_NAMESPACE::gpu +{ + +class GPUTPCCFCheckPadBaseline : public GPUKernelTemplate +{ + + public: + enum { + PadsPerCacheline = 8, + TimebinsPerCacheline = 4, + NumOfCachedTimebins = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFCheckPadBaseline) / PadsPerCacheline, + }; + + struct GPUSharedMemory { + tpccf::Charge charges[PadsPerCacheline][NumOfCachedTimebins]; + }; + +#ifdef GPUCA_HAVE_O2HEADERS + typedef GPUTPCClusterFinder processorType; + GPUhdi() static processorType* Processor(GPUConstantMem& processors) + { + return processors.tpcClusterer; + } +#endif + + GPUhdi() CONSTEXPR static GPUDataTypes::RecoStep GetRecoStep() + { + return GPUDataTypes::RecoStep::TPCClusterFinding; + } + + template <int iKernel = defaultKernel> + GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer); + + private: + GPUd() static ChargePos padToChargePos(int& pad, const GPUTPCClusterFinder&); + GPUd() static void updatePadBaseline(int pad, const GPUTPCClusterFinder&, int totalCharges, int consecCharges); +}; + +} // namespace GPUCA_NAMESPACE::gpu + +#endif diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx index 36f0e1f0d6c92..7d246546ff11d 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -33,10 +34,11 @@ GPUdii() void GPUTPCCFClusterizer::Thread<0>(int nBlocks, int nThreads, int iBlo tpc::ClusterNative* clusterOut = (onlyMC) ? nullptr : clusterer.mPclusterByRow; - GPUTPCCFClusterizer::computeClustersImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), clusterer.mPmemory->fragment, smem, chargeMap, clusterer.mPfilteredPeakPositions, clusterer.Param().rec, CPU_PTR(&labelAcc), clusterer.mPmemory->counters.nClusters, clusterer.mNMaxClusterPerRow, clusterer.mPclusterInRow, clusterOut, clusterer.mPclusterPosInRow); + GPUTPCCFClusterizer::computeClustersImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), clusterer, clusterer.mPmemory->fragment, smem, chargeMap, clusterer.mPfilteredPeakPositions, clusterer.Param().rec, CPU_PTR(&labelAcc), clusterer.mPmemory->counters.nClusters, clusterer.mNMaxClusterPerRow, clusterer.mPclusterInRow, clusterOut, clusterer.mPclusterPosInRow); } GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int nBlocks, int nThreads, int iBlock, int iThread, + processorType& clusterer, const CfFragment& fragment, GPUSharedMemory& smem, const Array2D<PackedCharge>& chargeMap, @@ -76,18 +78,19 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int nBlocks, int nThreads pc.finalize(pos, charge, fragment.start); tpc::ClusterNative myCluster; - pc.toNative(pos, charge, calib.tpcCFminSplitNum, myCluster); + pc.toNative(pos, charge, calib.tpc.cfMinSplitNum, myCluster); - bool aboveQTotCutoff = (myCluster.qTot > calib.tpcCFqtotCutoff); + bool aboveQTotCutoff = (myCluster.qTot > calib.tpc.cfQTotCutoff); - if (!aboveQTotCutoff) { + if (clusterPosInRow && !aboveQTotCutoff) { clusterPosInRow[idx] = maxClusterPerRow; return; } - uint rowIndex; + uint rowIndex = 0; if (clusterByRow != nullptr) { rowIndex = sortIntoBuckets( + clusterer, myCluster, pos.row(), maxClusterPerRow, @@ -96,7 +99,7 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int nBlocks, int nThreads if (clusterPosInRow != nullptr) { clusterPosInRow[idx] = rowIndex; } - } else { + } else if (clusterPosInRow) { rowIndex = clusterPosInRow[idx]; } @@ -126,7 +129,7 @@ GPUdii() void GPUTPCCFClusterizer::updateClusterInner( CPU_ONLY( labelAcc->collect(pos.delta(d), q)); - aboveThreshold |= (uchar(q > calib.tpcCFinnerThreshold) << i); + aboveThreshold |= (uchar(q > calib.tpc.cfInnerThreshold) << i); } innerAboveThreshold[lid] = aboveThreshold; @@ -249,11 +252,14 @@ GPUdii() void GPUTPCCFClusterizer::buildCluster( #endif } -GPUd() uint GPUTPCCFClusterizer::sortIntoBuckets(const tpc::ClusterNative& cluster, uint row, uint maxElemsPerBucket, uint* elemsInBucket, tpc::ClusterNative* buckets) +GPUd() uint GPUTPCCFClusterizer::sortIntoBuckets(processorType& clusterer, const tpc::ClusterNative& cluster, uint row, uint maxElemsPerBucket, uint* elemsInBucket, tpc::ClusterNative* buckets) { uint index = CAMath::AtomicAdd(&elemsInBucket[row], 1u); if (index < maxElemsPerBucket) { buckets[maxElemsPerBucket * row + index] = cluster; + } else { + clusterer.raiseError(GPUErrors::ERROR_CF_ROW_CLUSTER_OVERFLOW, index, maxElemsPerBucket); + CAMath::AtomicExch(&elemsInBucket[row], maxElemsPerBucket); } return index; } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h index fab830119aa0a..a3b8d9567e45a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,15 +35,15 @@ class MCLabelAccumulator; class GPUTPCCFClusterizer : public GPUKernelTemplate { - public: + static constexpr size_t SCRATCH_PAD_WORK_GROUP_SIZE = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFClusterizer); struct GPUSharedMemory { ChargePos posBcast[SCRATCH_PAD_WORK_GROUP_SIZE]; PackedCharge buf[SCRATCH_PAD_WORK_GROUP_SIZE * SCRATCH_PAD_BUILD_N]; uchar innerAboveThreshold[SCRATCH_PAD_WORK_GROUP_SIZE]; }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { @@ -58,7 +59,7 @@ class GPUTPCCFClusterizer : public GPUKernelTemplate template <int iKernel = defaultKernel> GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, char); - static GPUd() void computeClustersImpl(int, int, int, int, const CfFragment&, GPUSharedMemory&, const Array2D<PackedCharge>&, const ChargePos*, const GPUSettingsRec&, MCLabelAccumulator*, uint, uint, uint*, tpc::ClusterNative*, uint*); + static GPUd() void computeClustersImpl(int, int, int, int, processorType&, const CfFragment&, GPUSharedMemory&, const Array2D<PackedCharge>&, const ChargePos*, const GPUSettingsRec&, MCLabelAccumulator*, uint, uint, uint*, tpc::ClusterNative*, uint*); private: static GPUd() void updateClusterInner(const GPUSettingsRec&, ushort, ushort, const PackedCharge*, const ChargePos&, ClusterAccumulator*, MCLabelAccumulator*, uchar*); @@ -67,7 +68,7 @@ class GPUTPCCFClusterizer : public GPUKernelTemplate static GPUd() void buildCluster(const GPUSettingsRec&, const Array2D<PackedCharge>&, ChargePos, ChargePos*, PackedCharge*, uchar*, ClusterAccumulator*, MCLabelAccumulator*); - static GPUd() uint sortIntoBuckets(const tpc::ClusterNative&, uint, uint, uint*, tpc::ClusterNative*); + static GPUd() uint sortIntoBuckets(processorType&, const tpc::ClusterNative&, uint, uint, uint*, tpc::ClusterNative*); }; } // namespace GPUCA_NAMESPACE::gpu diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx index 1b17d0a8d0ffa..ecb853b460642 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,8 +19,8 @@ #include "PackedCharge.h" #include "DataFormatsTPC/ZeroSuppression.h" #include "CommonConstants/LHCConstants.h" -#include "GPURawData.h" #include "GPUCommonAlgorithm.h" +#include "DetectorsRaw/RDHUtils.h" using namespace GPUCA_NAMESPACE::gpu; using namespace GPUCA_NAMESPACE::gpu::tpccf; @@ -73,27 +74,27 @@ GPUdii() void GPUTPCCFDecodeZS::decode(GPUTPCClusterFinder& clusterer, GPUShared CA_SHARED_CACHE_REF(&s.ZSPage[0], pageSrc, TPCZSHDR::TPC_ZS_PAGE_SIZE, unsigned int, pageCache); GPUbarrier(); const unsigned char* page = (const unsigned char*)pageCache; - const RAWDataHeaderGPU* rdh = (const RAWDataHeaderGPU*)page; - if (GPURawDataUtils::getSize(rdh) == sizeof(RAWDataHeaderGPU)) { + const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)page; + if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) { #ifdef GPUCA_GPUCODE return; #else continue; #endif } - const unsigned char* pagePtr = page + sizeof(RAWDataHeaderGPU); + const unsigned char* pagePtr = page + sizeof(o2::header::RAWDataHeader); const TPCZSHDR* hdr = reinterpret_cast<const TPCZSHDR*>(pagePtr); pagePtr += sizeof(*hdr); const bool decode12bit = hdr->version == 2; const unsigned int decodeBits = decode12bit ? TPCZSHDR::TPC_ZS_NBITS_V2 : TPCZSHDR::TPC_ZS_NBITS_V1; const float decodeBitsFactor = 1.f / (1 << (decodeBits - 10)); unsigned int mask = (1 << decodeBits) - 1; - int timeBin = (hdr->timeOffset + (GPURawDataUtils::getOrbit(rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; + int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; const int rowOffset = s.regionStartRow + ((endpoint & 1) ? (s.nRowsRegion / 2) : 0); const int nRows = (endpoint & 1) ? (s.nRowsRegion - s.nRowsRegion / 2) : (s.nRowsRegion / 2); for (int l = 0; l < hdr->nTimeBins; l++) { // TODO: Parallelize over time bins - pagePtr += (pagePtr - page) & 1; //Ensure 16 bit alignment + pagePtr += (pagePtr - page) & 1; //Ensure 16 bit alignment const TPCZSTBHDR* tbHdr = reinterpret_cast<const TPCZSTBHDR*>(pagePtr); if ((tbHdr->rowMask & 0x7FFF) == 0) { pagePtr += 2; @@ -170,7 +171,7 @@ GPUdii() void GPUTPCCFDecodeZS::decode(GPUTPCClusterFinder& clusterer, GPUShared positions[nDigitsTmp++] = pos; if (inFragment) { float q = float(byte & mask) * decodeBitsFactor; - q *= clusterer.getGainCorrection(row, pad); + q *= clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(slice, row, pad); chargeMap[pos] = PackedCharge(q); } pad++; @@ -185,8 +186,8 @@ GPUdii() void GPUTPCCFDecodeZS::decode(GPUTPCClusterFinder& clusterer, GPUShared if (nRowsUsed > 1) { pagePtr = page + tbHdr->rowAddr1()[nRowsUsed - 2]; } - pagePtr += 2 * *pagePtr; // Go to entry for last sequence length - pagePtr += 1 + (*pagePtr * decodeBits + 7) / 8; // Go to beginning of next time bin + pagePtr += 2 * *pagePtr; // Go to entry for last sequence length + pagePtr += 1 + (*pagePtr * decodeBits + 7) / 8; // Go to beginning of next time bin } } } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h index 602515675f7a0..01adb28ff83ab 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ class GPUTPCCFDecodeZS : public GPUKernelTemplate static GPUd() void decode(GPUTPCClusterFinder& clusterer, GPUSharedMemory& s, int nBlocks, int nThreads, int iBlock, int iThread, int firstHBF); -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx index 26f4dceeb96f6..3fa5b2ac265eb 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -49,7 +50,7 @@ GPUdii() void GPUTPCCFDeconvolution::deconvolutionImpl(int nBlocks, int nThreads ushort partId = ll; ushort in3x3 = 0; - partId = CfUtils::partition(smem, ll, iamPeak, SCRATCH_PAD_WORK_GROUP_SIZE, &in3x3); + partId = CfUtils::partition<SCRATCH_PAD_WORK_GROUP_SIZE>(smem, ll, iamPeak, SCRATCH_PAD_WORK_GROUP_SIZE, &in3x3); if (partId < in3x3) { smem.posBcast1[partId] = pos; @@ -73,7 +74,7 @@ GPUdii() void GPUTPCCFDeconvolution::deconvolutionImpl(int nBlocks, int nThreads } ushort in5x5 = 0; - partId = CfUtils::partition(smem, partId, peakCount > 0 && !iamPeak, in3x3, &in5x5); + partId = CfUtils::partition<SCRATCH_PAD_WORK_GROUP_SIZE>(smem, partId, peakCount > 0 && !iamPeak, in3x3, &in5x5); if (partId < in5x5) { smem.posBcast1[partId] = pos; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h index d2af024ef221e..f3715d141f09f 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,16 +27,15 @@ namespace GPUCA_NAMESPACE::gpu class GPUTPCCFDeconvolution : public GPUKernelTemplate { - public: - struct GPUSharedMemory : public GPUKernelTemplate::GPUSharedMemoryScan64<short, GPUCA_GET_THREAD_COUNT(GPUCA_LB_CLUSTER_FINDER)> { + static constexpr size_t SCRATCH_PAD_WORK_GROUP_SIZE = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFDeconvolution); + struct GPUSharedMemory : public GPUKernelTemplate::GPUSharedMemoryScan64<short, GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFDeconvolution)> { ChargePos posBcast1[SCRATCH_PAD_WORK_GROUP_SIZE]; uchar aboveThresholdBcast[SCRATCH_PAD_WORK_GROUP_SIZE]; uchar buf[SCRATCH_PAD_WORK_GROUP_SIZE * SCRATCH_PAD_COUNT_N]; }; - -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.cxx index 02810aa965bae..41174f8622bbc 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h index 37dcb4eda0833..0917409e01a40 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,7 +26,7 @@ class GPUTPCClusterFinder; class GPUTPCCFGather : public GPUKernelTemplate { public: -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.cxx index cbeb7fe2edef2..e0cff28aaa2c3 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h index 23c4717af237a..0fa1810cd6ea3 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,7 +38,7 @@ class GPUTPCCFMCLabelFlattener : public GPUKernelTemplate flatten, }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.cxx index b80258e8d2de2..7651ddc527583 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -207,7 +208,7 @@ GPUd() void GPUTPCCFNoiseSuppression::findMinimaAndPeaks( 2, 16, q, - calibration.tpcCFnoiseSuppressionEpsilon, + calibration.tpc.cfNoiseSuppressionEpsilon, minimas, bigger); @@ -229,7 +230,7 @@ GPUd() void GPUTPCCFNoiseSuppression::findMinimaAndPeaks( 16, 0, q, - calibration.tpcCFnoiseSuppressionEpsilon, + calibration.tpc.cfNoiseSuppressionEpsilon, minimas, bigger); } @@ -252,7 +253,7 @@ GPUd() void GPUTPCCFNoiseSuppression::findMinimaAndPeaks( 16, 18, q, - calibration.tpcCFnoiseSuppressionEpsilon, + calibration.tpc.cfNoiseSuppressionEpsilon, minimas, bigger); } @@ -276,7 +277,7 @@ GPUd() void GPUTPCCFNoiseSuppression::findMinimaAndPeaks( 16, 0, q, - calibration.tpcCFnoiseSuppressionEpsilon, + calibration.tpc.cfNoiseSuppressionEpsilon, minimas, bigger); } @@ -299,7 +300,7 @@ GPUd() void GPUTPCCFNoiseSuppression::findMinimaAndPeaks( 16, 18, q, - calibration.tpcCFnoiseSuppressionEpsilon, + calibration.tpc.cfNoiseSuppressionEpsilon, minimas, bigger); } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h index 4cb04bacb4a90..2615976943f7e 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,19 +29,18 @@ struct ChargePos; class GPUTPCCFNoiseSuppression : public GPUKernelTemplate { - public: enum K : int { noiseSuppression = 0, updatePeaks = 1, }; - + static constexpr size_t SCRATCH_PAD_WORK_GROUP_SIZE = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFNoiseSuppression); struct GPUSharedMemory { ChargePos posBcast[SCRATCH_PAD_WORK_GROUP_SIZE]; PackedCharge buf[SCRATCH_PAD_WORK_GROUP_SIZE * SCRATCH_PAD_NOISE_N]; }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx index 0f22cd47aca72..fc8a2fcf20d4e 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,7 @@ #include "Array2D.h" #include "CfUtils.h" #include "PackedCharge.h" -#include "TPCCFCalibration.h" +#include "TPCPadGainCalib.h" using namespace GPUCA_NAMESPACE::gpu; using namespace GPUCA_NAMESPACE::gpu::tpccf; @@ -26,7 +27,7 @@ GPUdii() void GPUTPCCFPeakFinder::Thread<0>(int nBlocks, int nThreads, int iBloc { Array2D<PackedCharge> chargeMap(reinterpret_cast<PackedCharge*>(clusterer.mPchargeMap)); Array2D<uchar> isPeakMap(clusterer.mPpeakMap); - findPeaksImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, chargeMap, clusterer.mPpositions, clusterer.mPmemory->counters.nPositions, clusterer.Param().rec, clusterer.mPisPeak, isPeakMap); + findPeaksImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, chargeMap, clusterer.mPpadIsNoisy, clusterer.mPpositions, clusterer.mPmemory->counters.nPositions, clusterer.Param().rec, *clusterer.GetConstantMem()->calibObjects.tpcPadGain, clusterer.mPisPeak, isPeakMap); } GPUdii() bool GPUTPCCFPeakFinder::isPeak( @@ -41,10 +42,10 @@ GPUdii() bool GPUTPCCFPeakFinder::isPeak( { ushort ll = get_local_id(0); - bool belowThreshold = (q <= calib.tpcCFqmaxCutoff); + bool belowThreshold = (q <= calib.tpc.cfQMaxCutoff); ushort lookForPeaks; - ushort partId = CfUtils::partition( + ushort partId = CfUtils::partition<SCRATCH_PAD_WORK_GROUP_SIZE>( smem, ll, belowThreshold, @@ -91,9 +92,11 @@ GPUdii() bool GPUTPCCFPeakFinder::isPeak( GPUd() void GPUTPCCFPeakFinder::findPeaksImpl(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, const Array2D<PackedCharge>& chargeMap, + const uchar* padHasLostBaseline, const ChargePos* positions, SizeT digitnum, const GPUSettingsRec& calib, + const TPCPadGainCalib& gainCorrection, // Only used for globalPad() function uchar* isPeakPredicate, Array2D<uchar>& peakMap) { @@ -105,8 +108,10 @@ GPUd() void GPUTPCCFPeakFinder::findPeaksImpl(int nBlocks, int nThreads, int iBl ChargePos pos = positions[CAMath::Min(idx, (SizeT)(digitnum - 1))]; Charge charge = pos.valid() ? chargeMap[pos].unpack() : Charge(0); - uchar peak; - peak = isPeak(smem, charge, pos, SCRATCH_PAD_SEARCH_N, chargeMap, calib, smem.posBcast, smem.buf); + bool hasLostBaseline = padHasLostBaseline[gainCorrection.globalPad(pos.row(), pos.pad())]; + charge = (hasLostBaseline) ? 0.f : charge; + + uchar peak = isPeak(smem, charge, pos, SCRATCH_PAD_SEARCH_N, chargeMap, calib, smem.posBcast, smem.buf); // Exit early if dummy. See comment above. bool iamDummy = (idx >= digitnum); @@ -116,5 +121,5 @@ GPUd() void GPUTPCCFPeakFinder::findPeaksImpl(int nBlocks, int nThreads, int iBl isPeakPredicate[idx] = peak; - peakMap[pos] = (uchar(charge > calib.tpcCFinnerThreshold) << 1) | peak; + peakMap[pos] = (uchar(charge > calib.tpc.cfInnerThreshold) << 1) | peak; } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h index 54d878d012562..92e92c2886869 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,14 +29,14 @@ struct ChargePos; class GPUTPCCFPeakFinder : public GPUKernelTemplate { - public: - struct GPUSharedMemory : public GPUKernelTemplate::GPUSharedMemoryScan64<short, GPUCA_GET_THREAD_COUNT(GPUCA_LB_CLUSTER_FINDER)> { + static constexpr size_t SCRATCH_PAD_WORK_GROUP_SIZE = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFPeakFinder); + struct GPUSharedMemory : public GPUKernelTemplate::GPUSharedMemoryScan64<short, GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFPeakFinder)> { ChargePos posBcast[SCRATCH_PAD_WORK_GROUP_SIZE]; PackedCharge buf[SCRATCH_PAD_WORK_GROUP_SIZE * SCRATCH_PAD_SEARCH_N]; }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { @@ -52,7 +53,7 @@ class GPUTPCCFPeakFinder : public GPUKernelTemplate GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, Args... args); private: - static GPUd() void findPeaksImpl(int, int, int, int, GPUSharedMemory&, const Array2D<PackedCharge>&, const ChargePos*, tpccf::SizeT, const GPUSettingsRec&, uchar*, Array2D<uchar>&); + static GPUd() void findPeaksImpl(int, int, int, int, GPUSharedMemory&, const Array2D<PackedCharge>&, const uchar*, const ChargePos*, tpccf::SizeT, const GPUSettingsRec&, const TPCPadGainCalib&, uchar*, Array2D<uchar>&); static GPUd() bool isPeak(GPUSharedMemory&, tpccf::Charge, const ChargePos&, ushort, const Array2D<PackedCharge>&, const GPUSettingsRec&, ChargePos*, PackedCharge*); }; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx index 3c47a31e08585..acff321f88bff 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -124,10 +125,15 @@ GPUdii() void GPUTPCCFStreamCompaction::Thread<GPUTPCCFStreamCompaction::compact compactImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, in, out, clusterer.mPisPeak, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, clusterer.mPbuf + iBuf * clusterer.mBufSize, nElems, bufferSize); unsigned int lastId = get_global_size(0) - 1; if ((unsigned int)get_global_id(0) == lastId) { + SizeT nFinal = clusterer.mPbuf[lastId]; + if (nFinal > bufferSize) { + clusterer.raiseError(stage ? GPUErrors::ERROR_CF_CLUSTER_OVERFLOW : GPUErrors::ERROR_CF_PEAK_OVERFLOW, nFinal, bufferSize); + nFinal = bufferSize; + } if (stage) { - clusterer.mPmemory->counters.nClusters = clusterer.mPbuf[lastId]; + clusterer.mPmemory->counters.nClusters = nFinal; } else { - clusterer.mPmemory->counters.nPeaks = clusterer.mPbuf[lastId]; + clusterer.mPmemory->counters.nPeaks = nFinal; } } } @@ -162,7 +168,7 @@ GPUdii() void GPUTPCCFStreamCompaction::compactImpl(int nBlocks, int nThreads, i } if (idx == lastItem) { - newIdx[idx] = CAMath::Min(compIdx, bufferSize); // TODO: Eventually, we can just return the last value, no need to store to memory + newIdx[idx] = compIdx; // TODO: Eventually, we can just return the last value, no need to store to memory } } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h index 2090b7835dab0..8a2d3034db95c 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,7 +38,7 @@ class GPUTPCCFStreamCompaction : public GPUKernelTemplate struct GPUSharedMemory : public GPUKernelTemplate::GPUSharedMemoryScan64<int, GPUCA_THREAD_COUNT_SCAN> { }; -#ifdef HAVE_O2HEADERS +#ifdef GPUCA_HAVE_O2HEADERS typedef GPUTPCClusterFinder processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx index bab748e6f44b6..1f5d290348782 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -75,11 +76,14 @@ void* GPUTPCClusterFinder::SetPointersOutput(void* mem) void* GPUTPCClusterFinder::SetPointersScratch(void* mem) { + computePointerWithAlignment(mem, mPpadIsNoisy, TPC_PADS_IN_SECTOR); computePointerWithAlignment(mem, mPpositions, mNMaxDigitsFragment); computePointerWithAlignment(mem, mPpeakPositions, mNMaxPeaks); computePointerWithAlignment(mem, mPfilteredPeakPositions, mNMaxClusters); if (mRec->GetProcessingSettings().runMC) { computePointerWithAlignment(mem, mPclusterPosInRow, mNMaxClusters); + } else { + mPclusterPosInRow = nullptr; } computePointerWithAlignment(mem, mPisPeak, mNMaxDigitsFragment); computePointerWithAlignment(mem, mPchargeMap, TPCMapMemoryLayout<decltype(*mPchargeMap)>::items()); @@ -109,8 +113,17 @@ void GPUTPCClusterFinder::RegisterMemoryAllocation() void GPUTPCClusterFinder::SetMaxData(const GPUTrackingInOutPointers& io) { mNMaxPeaks = mRec->MemoryScalers()->NTPCPeaks(mNMaxDigitsFragment); - mNMaxClusters = mRec->MemoryScalers()->NTPCClusters(mNMaxDigitsFragment); - mNMaxClusterPerRow = 0.01f * mRec->MemoryScalers()->NTPCClusters(mNMaxDigits); // TODO: Can save some memory hery by using mNMaxClusters, and copying the computed clusters out after every fragment + mNMaxClusters = mRec->MemoryScalers()->NTPCClusters(mNMaxDigitsFragment, true); + mNMaxClusterPerRow = 0.01f * mRec->MemoryScalers()->NTPCClusters(mNMaxDigits, true); // TODO: Can save some memory hery by using mNMaxClusters, and copying the computed clusters out after every fragment + if (io.settingsTF && io.settingsTF->hasNHBFPerTF) { + unsigned int threshold = 300000 * io.settingsTF->nHBFPerTF / 128; // TODO: Probably one would need to do this on a row-basis for a better estimate, but currently not supported + mNMaxClusterPerRow = std::max<unsigned int>(mNMaxClusterPerRow, std::min<unsigned int>(threshold, mNMaxClusterPerRow * 10)); // Relative increased value up until a threshold, for noisy pads + mNMaxClusterPerRow = std::max<unsigned int>(mNMaxClusterPerRow, io.settingsTF->nHBFPerTF * 20000 / 256); // Absolute increased value, to have a minimum for noisy pads + } + if (mRec->GetProcessingSettings().tpcIncreasedMinClustersPerRow) { + mNMaxClusterPerRow = std::max<unsigned int>(mNMaxClusterPerRow, mRec->GetProcessingSettings().tpcIncreasedMinClustersPerRow); + } + mBufSize = nextMultipleOf<std::max<int>(GPUCA_MEMALIGN, mScanWorkGroupSize)>(mNMaxDigitsFragment); mNBufs = getNSteps(mBufSize); } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h index abec35440f3a5..aeb0544f5a191 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,7 +19,7 @@ #include "GPUProcessor.h" #include "GPUDataTypes.h" #include "CfFragment.h" -#include "TPCCFCalibration.h" +#include "TPCPadGainCalib.h" namespace o2 { @@ -44,10 +45,12 @@ class Digit; namespace GPUCA_NAMESPACE::gpu { struct GPUTPCClusterMCInterim; -struct TPCCFCalibration; +struct TPCPadGainCalib; struct ChargePos; +class GPUTPCGeometry; + class GPUTPCClusterFinder : public GPUProcessor { public: @@ -96,6 +99,7 @@ class GPUTPCClusterFinder : public GPUProcessor unsigned char* mPzs = nullptr; ZSOffset* mPzsOffsets = nullptr; MinMaxCN* mMinMaxCN = nullptr; + unsigned char* mPpadIsNoisy = nullptr; tpc::Digit* mPdigits = nullptr; // input digits, only set if ZS is skipped ChargePos* mPpositions = nullptr; ChargePos* mPpeakPositions = nullptr; @@ -135,7 +139,7 @@ class GPUTPCClusterFinder : public GPUProcessor short mZSOffsetId = -1; short mOutputId = -1; - GPUdi() float getGainCorrection(tpccf::Row, tpccf::Pad) const; + GPUdi() const GPUTPCGeometry* getGeometry() const; #ifndef GPUCA_GPUCODE void DumpDigits(std::ostream& out); diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx index 79fedfe8b1deb..8185fd61fd19f 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ using namespace GPUCA_NAMESPACE::gpu::tpccf; void GPUTPCClusterFinder::DumpDigits(std::ostream& out) { - out << "Clusterer - Digits - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPositions << "\n"; + out << "\nClusterer - Digits - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPositions << "\n"; for (size_t i = 0; i < mPmemory->counters.nPositions; i++) { out << i << ": " << mPpositions[i].time() << ", " << (int)mPpositions[i].pad() << ", " << (int)mPpositions[i].row() << "\n"; } @@ -29,7 +30,7 @@ void GPUTPCClusterFinder::DumpDigits(std::ostream& out) void GPUTPCClusterFinder::DumpChargeMap(std::ostream& out, std::string_view title) { - out << "Clusterer - " << title << " - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; + out << "\nClusterer - " << title << " - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; Array2D<ushort> map(mPchargeMap); for (TPCFragmentTime i = 0; i < TPC_MAX_FRAGMENT_LEN_PADDED; i++) { @@ -56,7 +57,7 @@ void GPUTPCClusterFinder::DumpChargeMap(std::ostream& out, std::string_view titl void GPUTPCClusterFinder::DumpPeaks(std::ostream& out) { - out << "Clusterer - Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; + out << "\nClusterer - Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; for (unsigned int i = 0; i < mPmemory->counters.nPositions; i++) { out << (int)mPisPeak[i] << " "; if ((i + 1) % 100 == 0) { @@ -68,7 +69,7 @@ void GPUTPCClusterFinder::DumpPeaks(std::ostream& out) void GPUTPCClusterFinder::DumpPeaksCompacted(std::ostream& out) { - out << "Clusterer - Compacted Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPeaks << "\n"; + out << "\nClusterer - Compacted Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPeaks << "\n"; for (size_t i = 0; i < mPmemory->counters.nPeaks; i++) { out << i << ": " << mPpeakPositions[i].time() << ", " << (int)mPpeakPositions[i].pad() << ", " << (int)mPpeakPositions[i].row() << "\n"; } @@ -76,7 +77,7 @@ void GPUTPCClusterFinder::DumpPeaksCompacted(std::ostream& out) void GPUTPCClusterFinder::DumpSuppressedPeaks(std::ostream& out) { - out << "Clusterer - NoiseSuppression - Slice " + out << "\nClusterer - NoiseSuppression - Slice " << " - Fragment " << mPmemory->fragment.index << mISlice << "\n"; for (unsigned int i = 0; i < mPmemory->counters.nPeaks; i++) { out << (int)mPisPeak[i] << " "; @@ -89,7 +90,7 @@ void GPUTPCClusterFinder::DumpSuppressedPeaks(std::ostream& out) void GPUTPCClusterFinder::DumpSuppressedPeaksCompacted(std::ostream& out) { - out << "Clusterer - Noise Suppression Peaks Compacted - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nClusters << "\n"; + out << "\nClusterer - Noise Suppression Peaks Compacted - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nClusters << "\n"; for (size_t i = 0; i < mPmemory->counters.nClusters; i++) { out << i << ": " << mPfilteredPeakPositions[i].time() << ", " << (int)mPfilteredPeakPositions[i].pad() << ", " << (int)mPfilteredPeakPositions[i].row() << "\n"; } @@ -97,7 +98,7 @@ void GPUTPCClusterFinder::DumpSuppressedPeaksCompacted(std::ostream& out) void GPUTPCClusterFinder::DumpCountedPeaks(std::ostream& out) { - out << "Clusterer - Peak Counts - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; + out << "\nClusterer - Peak Counts - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; for (int i = 0; i < GPUCA_ROW_COUNT; i++) { out << i << ": " << mPclusterInRow[i] << "\n"; } @@ -105,7 +106,7 @@ void GPUTPCClusterFinder::DumpCountedPeaks(std::ostream& out) void GPUTPCClusterFinder::DumpClusters(std::ostream& out) { - out << "Clusterer - Clusters - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; + out << "\nClusterer - Clusters - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; for (int i = 0; i < GPUCA_ROW_COUNT; i++) { size_t N = mPclusterInRow[i]; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderKernels.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderKernels.h index e2298ad4e683a..76509714b7353 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderKernels.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,6 +23,7 @@ #include "GPUTPCCFStreamCompaction.h" #include "GPUTPCCFClusterizer.h" #include "GPUTPCCFMCLabelFlattener.h" +#include "GPUTPCCFCheckPadBaseline.h" #include "GPUTPCCFDecodeZS.h" #include "GPUTPCCFGather.h" diff --git a/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.cxx b/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.cxx index 96300ad3883a3..28018e5fce5e1 100644 --- a/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.h b/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.h index f839402ba310b..63338388b488d 100644 --- a/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.h +++ b/GPU/GPUTracking/TPCClusterFinder/MCLabelAccumulator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCClusterFinder/PackedCharge.h b/GPU/GPUTracking/TPCClusterFinder/PackedCharge.h index e610508b1864b..34a11b85a43bd 100644 --- a/GPU/GPUTracking/TPCClusterFinder/PackedCharge.h +++ b/GPU/GPUTracking/TPCClusterFinder/PackedCharge.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,6 +51,7 @@ class PackedCharge GPUdi() tpccf::Charge unpack() const { return tpccf::Charge(mVal & ChargeMask) / tpccf::Charge(1 << DecimalBits); } GPUdi() bool has3x3Peak() const { return mVal & Has3x3PeakMask; } GPUdi() bool isSplit() const { return mVal & IsSplitMask; } + GPUdi() bool isZero() const { return mVal == 0; } private: BasicType mVal; diff --git a/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.cxx b/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.cxx deleted file mode 100644 index 0f260cb76ee5b..0000000000000 --- a/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.cxx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TPCCFCalibration.cxx -/// \author Felix Weiglhofer - -#include "TPCCFCalibration.h" - -#include "GPUTPCGeometry.h" -#include "DataFormatsTPC/Constants.h" -#include "TPCBase/CalDet.h" - -using namespace GPUCA_NAMESPACE::gpu; - -TPCCFCalibration::TPCCFCalibration() -{ - GPUTPCGeometry geo{}; - int offset = 0; - for (int r = 0; r < TPC_NUM_OF_ROWS; r++) { - mPadOffsetPerRow[r] = offset; - offset += geo.NPads(r); - } -} - -TPCCFCalibration::TPCCFCalibration(const o2::tpc::CalDet<float>& gainMap) : TPCCFCalibration() -{ - for (int sector = 0; sector < o2::tpc::constants::MAXSECTOR; sector++) { - for (int p = 0; p < TPC_PADS_IN_SECTOR; p++) { - mGainCorrection[sector].set(p, gainMap.getValue(sector, p)); - } - } -} diff --git a/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.h b/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.h deleted file mode 100644 index 71ffd48e93f27..0000000000000 --- a/GPU/GPUTracking/TPCClusterFinder/TPCCFCalibration.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TPCCFCalibration.h -/// \author Felix Weiglhofer - -#ifndef O2_GPU_TPC_CF_CALIBRATION_H -#define O2_GPU_TPC_CF_CALIBRATION_H - -#include "clusterFinderDefs.h" -#include "GPUCommonMath.h" - -namespace o2::tpc -{ -template <class T> -class CalDet; -} // namespace o2::tpc - -namespace GPUCA_NAMESPACE::gpu -{ - -template <typename T> -struct TPCPadGainCorrectionStepNum { -}; - -template <> -struct TPCPadGainCorrectionStepNum<unsigned char> { - static constexpr int value = 254; -}; - -template <> -struct TPCPadGainCorrectionStepNum<unsigned short> { - static constexpr int value = 65534; -}; - -struct TPCCFCalibration { - public: -#ifndef GPUCA_GPUCODE - TPCCFCalibration(); - TPCCFCalibration(const o2::tpc::CalDet<float>&); -#endif - - // Deal with pad gain correction from here on - GPUdi() void setGainCorrection(int sector, tpccf::Row row, tpccf::Pad pad, float c) - { - mGainCorrection[sector].set(globalPad(row, pad), c); - } - - GPUdi() float getGainCorrection(int sector, tpccf::Row row, tpccf::Pad pad) const - { - return mGainCorrection[sector].get(globalPad(row, pad)); - } - - private: - template <typename T = unsigned short> - class PadGainCorrection - { - - public: - constexpr static float MinCorrectionFactor = 0.f; - constexpr static float MaxCorrectionFactor = 2.f; - constexpr static int NumOfSteps = TPCPadGainCorrectionStepNum<T>::value; - - GPUdi() PadGainCorrection() - { - reset(); - } - - GPUdi() void set(unsigned short globalPad, float c) - { - at(globalPad) = pack(c); - } - - GPUdi() float get(unsigned short globalPad) const - { - return unpack(at(globalPad)); - } - - GPUd() void reset() - { - for (unsigned short p = 0; p < TPC_PADS_IN_SECTOR; p++) { - set(p, 1.0f); - } - } - - private: - GPUd() static T pack(float f) - { - f = CAMath::Clamp(f, MinCorrectionFactor, MaxCorrectionFactor); - f -= MinCorrectionFactor; - f *= float(NumOfSteps); - f /= (MaxCorrectionFactor - MinCorrectionFactor); - return CAMath::Nint(f); - } - - GPUd() static float unpack(T c) - { - return MinCorrectionFactor + (MaxCorrectionFactor - MinCorrectionFactor) * float(c) / float(NumOfSteps); - } - - T mGainCorrection[TPC_PADS_IN_SECTOR]; - - GPUdi() T& at(unsigned short globalPad) - { - return mGainCorrection[globalPad]; - } - - GPUdi() const T& at(unsigned short globalPad) const - { - return mGainCorrection[globalPad]; - } - }; - - unsigned short mPadOffsetPerRow[TPC_NUM_OF_ROWS]; - PadGainCorrection<unsigned short> mGainCorrection[TPC_SECTORS]; - - GPUdi() unsigned short globalPad(tpccf::Row row, tpccf::Pad pad) const - { - return mPadOffsetPerRow[row] + pad; - } -}; - -} // namespace GPUCA_NAMESPACE::gpu - -#endif diff --git a/GPU/GPUTracking/TPCClusterFinder/clusterFinderDefs.h b/GPU/GPUTracking/TPCClusterFinder/clusterFinderDefs.h deleted file mode 100644 index 8ace539cd7e8c..0000000000000 --- a/GPU/GPUTracking/TPCClusterFinder/clusterFinderDefs.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file clusterFinderDefs.h -/// \author David Rohr - -#ifndef O2_GPU_CLUSTERFINDERDEFS_H -#define O2_GPU_CLUSTERFINDERDEFS_H - -#include "GPUDef.h" - -#ifndef __OPENCL__ -using uchar = unsigned char; -#endif -#ifdef __APPLE__ -using ulong = unsigned long; -#endif - -#define SCRATCH_PAD_WORK_GROUP_SIZE GPUCA_GET_THREAD_COUNT(GPUCA_LB_CLUSTER_FINDER) - -/* #define CHARGEMAP_TIME_MAJOR_LAYOUT */ -#define CHARGEMAP_TILING_LAYOUT - -#define SCRATCH_PAD_SEARCH_N 8 -#define SCRATCH_PAD_COUNT_N 16 -#if defined(GPUCA_GPUCODE) -#define SCRATCH_PAD_BUILD_N 8 -#define SCRATCH_PAD_NOISE_N 8 -#else -// Double shared memory on cpu as we can't reuse the memory from other threads -#define SCRATCH_PAD_BUILD_N 16 -#define SCRATCH_PAD_NOISE_N 16 -#endif - -#define PADDING_PAD 2 -#define PADDING_TIME 3 -#define TPC_SECTORS 36 -#define TPC_ROWS_PER_CRU 18 -#define TPC_NUM_OF_ROWS 152 -#define TPC_PADS_PER_ROW 138 -#define TPC_PADS_PER_ROW_PADDED (TPC_PADS_PER_ROW + PADDING_PAD) -#define TPC_NUM_OF_PADS (TPC_NUM_OF_ROWS * TPC_PADS_PER_ROW_PADDED + PADDING_PAD) -#define TPC_PADS_IN_SECTOR 14560 -#define TPC_MAX_FRAGMENT_LEN 4000 -#define TPC_MAX_FRAGMENT_LEN_PADDED (TPC_MAX_FRAGMENT_LEN + 2 * PADDING_TIME) - -#if 0 -#define DBG_PRINT(msg, ...) printf(msg "\n", __VA_ARGS__) -#else -#define DBG_PRINT(msg, ...) static_cast<void>(0) -#endif - -#ifdef GPUCA_GPUCODE -#define CPU_ONLY(x) static_cast<void>(0) -#define CPU_PTR(x) nullptr -#else -#define CPU_ONLY(x) x -#define CPU_PTR(x) x -#endif - -namespace GPUCA_NAMESPACE::gpu::tpccf -{ - -using SizeT = size_t; -using TPCTime = int; -using TPCFragmentTime = short; -using Pad = unsigned char; -using GlobalPad = short; -using Row = unsigned char; -using Cru = unsigned char; - -using Charge = float; - -using Delta = short; -using Delta2 = short2; - -using local_id = short2; - -} // namespace GPUCA_NAMESPACE::gpu::tpccf - -#endif diff --git a/GPU/GPUTracking/TPCConvert/GPUTPCConvert.cxx b/GPU/GPUTracking/TPCConvert/GPUTPCConvert.cxx index 47edc6bd72727..0f3f50bb17a58 100644 --- a/GPU/GPUTracking/TPCConvert/GPUTPCConvert.cxx +++ b/GPU/GPUTracking/TPCConvert/GPUTPCConvert.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCConvert/GPUTPCConvert.h b/GPU/GPUTracking/TPCConvert/GPUTPCConvert.h index ba3bbeed2145a..3e6c7bb61cae5 100644 --- a/GPU/GPUTracking/TPCConvert/GPUTPCConvert.h +++ b/GPU/GPUTracking/TPCConvert/GPUTPCConvert.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TPCConvert/GPUTPCConvertImpl.h b/GPU/GPUTracking/TPCConvert/GPUTPCConvertImpl.h index 3bd58e336ca50..edea3dccfd690 100644 --- a/GPU/GPUTracking/TPCConvert/GPUTPCConvertImpl.h +++ b/GPU/GPUTracking/TPCConvert/GPUTPCConvertImpl.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,12 +29,20 @@ class GPUTPCConvertImpl public: GPUd() static void convert(const GPUConstantMem& GPUrestrict() cm, int slice, int row, float pad, float time, float& GPUrestrict() x, float& GPUrestrict() y, float& GPUrestrict() z) { - if (cm.param.par.ContinuousTracking) { + if (cm.param.par.continuousTracking) { cm.calibObjects.fastTransform->TransformInTimeFrame(slice, row, pad, time, x, y, z, cm.param.par.continuousMaxTimeBin); } else { cm.calibObjects.fastTransform->Transform(slice, row, pad, time, x, y, z); } } + GPUd() static void convert(const TPCFastTransform& GPUrestrict() transform, const GPUParam& GPUrestrict() param, int slice, int row, float pad, float time, float& GPUrestrict() x, float& GPUrestrict() y, float& GPUrestrict() z) + { + if (param.par.continuousTracking) { + transform.TransformInTimeFrame(slice, row, pad, time, x, y, z, param.par.continuousMaxTimeBin); + } else { + transform.Transform(slice, row, pad, time, x, y, z); + } + } }; } // namespace gpu diff --git a/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.cxx b/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.cxx index c51f85e678f02..139b0906f2690 100644 --- a/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.cxx +++ b/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ using namespace GPUCA_NAMESPACE::gpu; template <> -GPUdii() void GPUTPCConvertKernel::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& GPUrestrict() smem, processorType& GPUrestrict() processors) +GPUdii() void GPUTPCConvertKernel::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& GPUrestrict() processors) { const int iSlice = iBlock / GPUCA_ROW_COUNT; const int iRow = iBlock % GPUCA_ROW_COUNT; diff --git a/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.h b/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.h index ce3dc35d6288b..f7b0eb201806c 100644 --- a/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.h +++ b/GPU/GPUTracking/TPCConvert/GPUTPCConvertKernel.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDDef.h b/GPU/GPUTracking/TRDTracking/GPUTRDDef.h deleted file mode 100644 index 54f2f7110e581..0000000000000 --- a/GPU/GPUTracking/TRDTracking/GPUTRDDef.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTRDDef.h -/// \author David Rohr - -#ifndef GPUTRDDEF_H -#define GPUTRDDEF_H - -#include "GPUCommonDef.h" - -#ifdef GPUCA_ALIROOT_LIB -#define TRD_TRACK_TYPE_ALIROOT -#else -#define TRD_TRACK_TYPE_O2 -#endif - -#ifdef GPUCA_ALIROOT_LIB -class AliExternalTrackParam; -class AliTrackerBase; -#else -namespace o2 -{ -namespace dataformats -{ -class TrackTPCITS; -} // namespace dataformats -namespace base -{ -class Propagator; -} // namespace base -} // namespace o2 -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ - -#ifdef GPUCA_ALIROOT_LIB -typedef double My_Float; -#else -typedef float My_Float; -#endif - -#if defined(TRD_TRACK_TYPE_ALIROOT) -typedef AliExternalTrackParam TRDBaseTrack; -class GPUTPCGMTrackParam; -typedef GPUTPCGMTrackParam TRDBaseTrackGPU; -#elif defined(TRD_TRACK_TYPE_O2) -typedef o2::dataformats::TrackTPCITS TRDBaseTrack; -class GPUTPCGMTrackParam; -typedef GPUTPCGMTrackParam TRDBaseTrackGPU; -#endif - -#ifdef GPUCA_ALIROOT_LIB -typedef AliTrackerBase TRDBasePropagator; -class GPUTPCGMPropagator; -typedef GPUTPCGMPropagator TRDBasePropagatorGPU; -#else -typedef o2::base::Propagator TRDBasePropagator; -class GPUTPCGMPropagator; -typedef GPUTPCGMPropagator TRDBasePropagatorGPU; -#endif - -template <class T> -class trackInterface; -template <class T> -class propagatorInterface; -template <class T> -class GPUTRDTrack_t; -// clang-format off -typedef GPUTRDTrack_t<trackInterface<TRDBaseTrack> > GPUTRDTrack; // Need pre-c++11 compliant formatting -typedef GPUTRDTrack_t<trackInterface<TRDBaseTrackGPU> > GPUTRDTrackGPU; -// clang-foramt on -typedef propagatorInterface<TRDBasePropagator> GPUTRDPropagator; -typedef propagatorInterface<TRDBasePropagatorGPU> GPUTRDPropagatorGPU; - -template <class T, class P> -class GPUTRDTracker_t; -typedef GPUTRDTracker_t<GPUTRDTrack, GPUTRDPropagator> GPUTRDTracker; -typedef GPUTRDTracker_t<GPUTRDTrackGPU, GPUTRDPropagatorGPU> GPUTRDTrackerGPU; - -#if defined(GPUCA_ALIGPUCODE) && !defined(GPUCA_ALIROOT_LIB) && !defined(__CLING__) && !defined(__ROOTCLING__) && !defined(G__ROOT) -#define Error(...) -#define Warning(...) -#define Info(...) -#endif -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif // GPUTRDDEF_H diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h b/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h index 92dd33af49a02..dde4e6232a85e 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,7 +44,7 @@ class GPUTRDGeometry : public AliTRDgeometry } // namespace gpu } // namespace GPUCA_NAMESPACE -#elif defined(HAVE_O2HEADERS) //&& defined(GPUCA_GPUCODE) +#elif defined(GPUCA_HAVE_O2HEADERS) //&& defined(GPUCA_GPUCODE) class TObjArray; #include "GPUDef.h" @@ -174,6 +175,6 @@ class GPUTRDGeometry } // namespace gpu } // namespace GPUCA_NAMESPACE -#endif // !GPUCA_ALIROOT_LIB && !defined(HAVE_O2HEADERS) +#endif // !GPUCA_ALIROOT_LIB && !defined(GPUCA_HAVE_O2HEADERS) #endif // GPUTRDGEOMETRY_H diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h index 0f40cd142d060..3d897378f089e 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,7 +61,7 @@ class trackInterface<AliExternalTrackParam> : public AliExternalTrackParam { Set(trk.GetParam().GetX(), trk.GetAlpha(), trk.GetParam().GetPar(), trk.GetParam().GetCov()); } - trackInterface<AliExternalTrackParam>(const GPUTPCGMTrackParam::GPUTPCOuterParam& param) : AliExternalTrackParam() + trackInterface<AliExternalTrackParam>(const gputpcgmmergertypes::GPUTPCOuterParam& param) : AliExternalTrackParam() { Set(param.X, param.alpha, param.P, param.C); } @@ -80,7 +81,8 @@ class trackInterface<AliExternalTrackParam> : public AliExternalTrackParam const My_Float* getPar() const { return GetParameter(); } const My_Float* getCov() const { return GetCovariance(); } - float getTime() const { return -1.f; } + void resetCovariance(float s) { ResetCovariance(10.); } + void updateCovZ2(float) {} bool CheckNumericalQuality() const { return true; } // parameter manipulation @@ -98,7 +100,8 @@ class propagatorInterface<AliTrackerBase> : public AliTrackerBase { public: - propagatorInterface<AliTrackerBase>(const void* = nullptr) : AliTrackerBase(), mParam(nullptr){}; + typedef void propagatorParam; + propagatorInterface<AliTrackerBase>(const propagatorParam* = nullptr) : AliTrackerBase(), mParam(nullptr){}; propagatorInterface<AliTrackerBase>(const propagatorInterface<AliTrackerBase>&) CON_DELETE; propagatorInterface<AliTrackerBase>& operator=(const propagatorInterface<AliTrackerBase>&) CON_DELETE; @@ -127,120 +130,72 @@ class propagatorInterface<AliTrackerBase> : public AliTrackerBase #endif // GPUCA_ALIROOT_LIB -#if (defined(GPUCA_O2_LIB) || defined(GPUCA_O2_INTERFACE)) && !defined(GPUCA_GPUCODE) // Interface for O2, build only with O2 +#if defined(GPUCA_HAVE_O2HEADERS) // Interface for O2, build only with O2 -#include "ReconstructionDataFormats/TrackTPCITS.h" #include "DetectorsBase/Propagator.h" namespace GPUCA_NAMESPACE { - namespace gpu { -template <> -class trackInterface<o2::dataformats::TrackTPCITS> : public o2::dataformats::TrackTPCITS -{ - public: - trackInterface<o2::dataformats::TrackTPCITS>() = default; - trackInterface<o2::dataformats::TrackTPCITS>(const trackInterface<o2::dataformats::TrackTPCITS>& param) = default; - trackInterface<o2::dataformats::TrackTPCITS>(const o2::dataformats::TrackTPCITS& param) = delete; - trackInterface<o2::dataformats::TrackTPCITS>(const GPUTPCGMMergedTrack& trk) - { - setX(trk.OuterParam().X); - setAlpha(trk.OuterParam().alpha); - for (int i = 0; i < 5; i++) { - setParam(trk.OuterParam().P[i], i); - } - for (int i = 0; i < 15; i++) { - setCov(trk.OuterParam().C[i], i); - } - } - trackInterface<o2::dataformats::TrackTPCITS>(const GPUTPCGMTrackParam::GPUTPCOuterParam& param) - { - setX(param.X); - setAlpha(param.alpha); - for (int i = 0; i < 5; i++) { - setParam(param.P[i], i); - } - for (int i = 0; i < 15; i++) { - setCov(param.C[i], i); - } - }; - - void set(float x, float alpha, const float param[5], const float cov[15]) - { - setX(x); - setAlpha(alpha); - for (int i = 0; i < 5; i++) { - setParam(param[i], i); - } - for (int i = 0; i < 15; i++) { - setCov(cov[i], i); - } - } - - const float* getPar() const { return getParams(); } - float getTime() const { return mTime; } - void setTime(float t) { mTime = t; } - - bool CheckNumericalQuality() const { return true; } - - typedef o2::dataformats::TrackTPCITS baseClass; - - private: - float mTime; -}; +GPUdi() trackInterface<o2::track::TrackParCov>::trackInterface(const GPUTPCGMMergedTrack& trk) { set(trk.OuterParam().X, trk.OuterParam().alpha, trk.OuterParam().P, trk.OuterParam().C); } +GPUdi() trackInterface<o2::track::TrackParCov>::trackInterface(const gputpcgmmergertypes::GPUTPCOuterParam& param) { set(param.X, param.alpha, param.P, param.C); } template <> class propagatorInterface<o2::base::Propagator> { public: - propagatorInterface<o2::base::Propagator>(const void* = nullptr){}; - propagatorInterface<o2::base::Propagator>(const propagatorInterface<o2::base::Propagator>&) = delete; - propagatorInterface<o2::base::Propagator>& operator=(const propagatorInterface<o2::base::Propagator>&) = delete; + typedef o2::base::Propagator propagatorParam; + GPUd() propagatorInterface<o2::base::Propagator>(const propagatorParam* prop) : mProp(prop){}; + GPUd() propagatorInterface<o2::base::Propagator>(const propagatorInterface<o2::base::Propagator>&) = delete; + GPUd() propagatorInterface<o2::base::Propagator>& operator=(const propagatorInterface<o2::base::Propagator>&) = delete; - bool propagateToX(float x, float maxSnp, float maxStep) { return mProp->PropagateToXBxByBz(*mParam, x, 0.13957, maxSnp, maxStep); } - int getPropagatedYZ(float x, float& projY, float& projZ) { return static_cast<int>(mParam->getYZAt(x, mProp->getNominalBz(), projY, projZ)); } + GPUdi() bool propagateToX(float x, float maxSnp, float maxStep) { return mProp->PropagateToXBxByBz(*mParam, x, maxSnp, maxStep); } + GPUdi() int getPropagatedYZ(float x, float& projY, float& projZ) { return static_cast<int>(mParam->getYZAt(x, mProp->getNominalBz(), projY, projZ)); } - void setTrack(trackInterface<o2::dataformats::TrackTPCITS>* trk) { mParam = trk; } - void setFitInProjections(bool flag) {} + GPUdi() void setTrack(trackInterface<o2::track::TrackParCov>* trk) { mParam = trk; } + GPUdi() void setFitInProjections(bool flag) {} - float getAlpha() { return (mParam) ? mParam->getAlpha() : 99999.f; } - bool update(const My_Float p[2], const My_Float cov[3]) + GPUdi() float getAlpha() { return (mParam) ? mParam->getAlpha() : 99999.f; } + GPUdi() bool update(const My_Float p[2], const My_Float cov[3]) { if (mParam) { - std::array<float, 2> pTmp = {p[0], p[1]}; - std::array<float, 3> covTmp = {cov[0], cov[1], cov[3]}; + gpustd::array<float, 2> pTmp = {p[0], p[1]}; + gpustd::array<float, 3> covTmp = {cov[0], cov[1], cov[2]}; return mParam->update(pTmp, covTmp); } else { return false; } } - float getPredictedChi2(const My_Float p[2], const My_Float cov[3]) + GPUdi() float getPredictedChi2(const My_Float p[2], const My_Float cov[3]) { if (mParam) { - std::array<float, 2> pTmp = {p[0], p[1]}; - std::array<float, 3> covTmp = {cov[0], cov[1], cov[3]}; + gpustd::array<float, 2> pTmp = {p[0], p[1]}; + gpustd::array<float, 3> covTmp = {cov[0], cov[1], cov[2]}; return mParam->getPredictedChi2(pTmp, covTmp); } else { return 99999.f; } } - bool rotate(float alpha) { return (mParam) ? mParam->rotate(alpha) : false; } + GPUdi() bool rotate(float alpha) { return (mParam) ? mParam->rotate(alpha) : false; } - trackInterface<o2::dataformats::TrackTPCITS>* mParam{nullptr}; - o2::base::Propagator* mProp{o2::base::Propagator::Instance()}; + trackInterface<o2::track::TrackParCov>* mParam{nullptr}; + const o2::base::Propagator* mProp; }; } // namespace gpu } // namespace GPUCA_NAMESPACE -#endif // GPUCA_O2_LIB || GPUCA_O2_INTERFACE +#endif // GPUCA_HAVE_O2HEADERS #include "GPUTPCGMPropagator.h" #include "GPUParam.h" #include "GPUDef.h" +#ifdef GPUCA_O2_LIB +#include "DataFormatsTPC/TrackTPC.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#endif namespace GPUCA_NAMESPACE { @@ -254,7 +209,7 @@ class trackInterface<GPUTPCGMTrackParam> : public GPUTPCGMTrackParam GPUdDefault() trackInterface<GPUTPCGMTrackParam>() = default; GPUd() trackInterface<GPUTPCGMTrackParam>(const GPUTPCGMTrackParam& param) CON_DELETE; GPUd() trackInterface<GPUTPCGMTrackParam>(const GPUTPCGMMergedTrack& trk) : GPUTPCGMTrackParam(trk.GetParam()), mAlpha(trk.GetAlpha()) {} - GPUd() trackInterface<GPUTPCGMTrackParam>(const GPUTPCGMTrackParam::GPUTPCOuterParam& param) : GPUTPCGMTrackParam(), mAlpha(param.alpha) + GPUd() trackInterface<GPUTPCGMTrackParam>(const gputpcgmmergertypes::GPUTPCOuterParam& param) : GPUTPCGMTrackParam(), mAlpha(param.alpha) { SetX(param.X); for (int i = 0; i < 5; i++) { @@ -282,6 +237,32 @@ class trackInterface<GPUTPCGMTrackParam> : public GPUTPCGMTrackParam } }; #endif +#if defined(GPUCA_O2_LIB) && !defined(GPUCA_GPUCODE) + trackInterface<GPUTPCGMTrackParam>(const o2::dataformats::TrackTPCITS& param) : GPUTPCGMTrackParam(), mAlpha(param.getParamOut().getAlpha()) + { + SetX(param.getParamOut().getX()); + SetPar(0, param.getParamOut().getY()); + SetPar(1, param.getParamOut().getZ()); + SetPar(2, param.getParamOut().getSnp()); + SetPar(3, param.getParamOut().getTgl()); + SetPar(4, param.getParamOut().getQ2Pt()); + for (int i = 0; i < 15; i++) { + SetCov(i, param.getParamOut().getCov()[i]); + } + } + trackInterface<GPUTPCGMTrackParam>(const o2::tpc::TrackTPC& param) : GPUTPCGMTrackParam(), mAlpha(param.getParamOut().getAlpha()) + { + SetX(param.getParamOut().getX()); + SetPar(0, param.getParamOut().getY()); + SetPar(1, param.getParamOut().getZ()); + SetPar(2, param.getParamOut().getSnp()); + SetPar(3, param.getParamOut().getTgl()); + SetPar(4, param.getParamOut().getQ2Pt()); + for (int i = 0; i < 15; i++) { + SetCov(i, param.getParamOut().getCov()[i]); + } + } +#endif GPUd() float getX() const { @@ -300,8 +281,8 @@ class trackInterface<GPUTPCGMTrackParam> : public GPUTPCGMTrackParam GPUd() const float* getPar() const { return GetPar(); } GPUd() const float* getCov() const { return GetCov(); } - GPUd() float getTime() const { return -1.f; } - + GPUd() void resetCovariance(float s) { ResetCovariance(); } + GPUd() void updateCovZ2(float addZerror) { SetCov(2, GetErr2Z() + addZerror); } GPUd() void setAlpha(float alpha) { mAlpha = alpha; } GPUd() void set(float x, float alpha, const float param[5], const float cov[15]) { @@ -318,14 +299,15 @@ class trackInterface<GPUTPCGMTrackParam> : public GPUTPCGMTrackParam typedef GPUTPCGMTrackParam baseClass; private: - float mAlpha = 0.f; + float mAlpha = 0.f; // rotation along phi wrt global coordinate system }; template <> class propagatorInterface<GPUTPCGMPropagator> : public GPUTPCGMPropagator { public: - GPUd() propagatorInterface<GPUTPCGMPropagator>(const GPUTPCGMPolynomialField* pField) : GPUTPCGMPropagator(), mTrack(nullptr) + typedef GPUTPCGMPolynomialField propagatorParam; + GPUd() propagatorInterface<GPUTPCGMPropagator>(const propagatorParam* pField) : GPUTPCGMPropagator(), mTrack(nullptr) { this->SetMaterialTPC(); this->SetPolynomialField(pField); diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDSpacePoint.h b/GPU/GPUTracking/TRDTracking/GPUTRDSpacePoint.h new file mode 100644 index 0000000000000..1af4812e5b23f --- /dev/null +++ b/GPU/GPUTracking/TRDTracking/GPUTRDSpacePoint.h @@ -0,0 +1,72 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTRDSpacePoint.h +/// \author Ole Schmidt, ole.schmidt@cern.ch +/// \brief Struct to hold the position/direction information of the tracklets transformed in sector coordinates + +#ifndef GPUTRDSPACEPOINT_H +#define GPUTRDSPACEPOINT_H + +#ifndef GPUCA_TPC_GEOMETRY_O2 // compatibility to Run 2 data types + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +// class to hold the information on the space points +class GPUTRDSpacePoint +{ + public: + GPUd() GPUTRDSpacePoint(float x = 0, float y = 0, float z = 0, float dy = 0) : mX(x), mY(y), mZ(z), mDy(dy) {} + GPUd() float getX() const { return mX; } + GPUd() float getY() const { return mY; } + GPUd() float getZ() const { return mZ; } + GPUd() float getDy() const { return mDy; } + GPUd() void setX(float x) { mX = x; } + GPUd() void setY(float y) { mY = y; } + GPUd() void setZ(float z) { mZ = z; } + GPUd() void setDy(float dy) { mDy = dy; } + + private: + float mX; // x position (3.5 mm above anode wires) - radial offset due to t0 mis-calibration, measured -1 mm for run 245353 + float mY; // y position (sector coordinates) + float mZ; // z position (sector coordinates) + float mDy; // deflection over drift length +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#else // compatibility with Run 3 data types + +#include "DataFormatsTRD/CalibratedTracklet.h" + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +class GPUTRDSpacePoint : public o2::trd::CalibratedTracklet +{ +}; + +#ifdef GPUCA_NOCOMPAT +static_assert(sizeof(GPUTRDSpacePoint) == sizeof(o2::trd::CalibratedTracklet), "Incorrect memory layout"); +#endif + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif // GPUCA_TPC_GEOMETRY_O2 + +#endif // GPUTRDSPACEPOINT_H diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrack.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrack.cxx deleted file mode 100644 index df0201333d450..0000000000000 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrack.cxx +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTRDTrack.cxx -/// \author Ole Schmidt, Sergey Gorbunov - -#include "GPUTRDTrack.h" -#include "GPUTRDTrackData.h" - -using namespace GPUCA_NAMESPACE::gpu; - -#ifdef GPUCA_ALIROOT_LIB -#include "AliHLTExternalTrackParam.h" - -template <typename T> -GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const AliHLTExternalTrackParam& t) : T(t), mChi2(0.f), mMass(0.f), mLabel(-1), mTPCTrackId(0), mNTracklets(0), mNMissingConsecLayers(0), mLabelOffline(-1), mIsStopped(false) -{ - //------------------------------------------------------------------ - // copy constructor from AliHLTExternalTrackParam struct - //------------------------------------------------------------------ - for (int i = 0; i < kNLayers; ++i) { - mAttachedTracklets[i] = -1; - mIsFindable[i] = 0; - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = 0; - } -} -#endif - -template <typename T> -GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t() : mChi2(0.f), mMass(0.f), mLabel(-1), mTPCTrackId(0), mNTracklets(0), mNMissingConsecLayers(0), mLabelOffline(-1), mIsStopped(false) -{ - //------------------------------------------------------------------ - // default constructor - //------------------------------------------------------------------ - for (int i = 0; i < kNLayers; ++i) { - mAttachedTracklets[i] = -1; - mIsFindable[i] = 0; - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = 0; - } -} - -template <typename T> -GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const GPUTRDTrack_t<T>& t) - : T(t), mChi2(t.mChi2), mMass(t.mMass), mLabel(t.mLabel), mTPCTrackId(t.mTPCTrackId), mNTracklets(t.mNTracklets), mNMissingConsecLayers(t.mNMissingConsecLayers), mLabelOffline(t.mLabelOffline), mIsStopped(t.mIsStopped) -{ - //------------------------------------------------------------------ - // copy constructor - //------------------------------------------------------------------ - for (int i = 0; i < kNLayers; ++i) { - mAttachedTracklets[i] = t.mAttachedTracklets[i]; - mIsFindable[i] = t.mIsFindable[i]; - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = t.mNTrackletsOffline[j]; - } -} - -template <typename T> -GPUd() GPUTRDTrack_t<T>::GPUTRDTrack_t(const T& t) : T(t), mChi2(0.f), mMass(0.f), mLabel(-1), mTPCTrackId(0), mNTracklets(0), mNMissingConsecLayers(0), mLabelOffline(-1), mIsStopped(false) -{ - //------------------------------------------------------------------ - // copy constructor from anything - //------------------------------------------------------------------ - for (int i = 0; i < kNLayers; ++i) { - mAttachedTracklets[i] = -1; - mIsFindable[i] = 0; - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = 0; - } -} - -template <typename T> -GPUd() GPUTRDTrack_t<T>& GPUTRDTrack_t<T>::operator=(const GPUTRDTrack_t<T>& t) -{ - //------------------------------------------------------------------ - // assignment operator - //------------------------------------------------------------------ - if (&t == this) { - return *this; - } - *(T*)this = t; - mChi2 = t.mChi2; - mMass = t.mMass; - mLabel = t.mLabel; - mTPCTrackId = t.mTPCTrackId; - mNTracklets = t.mNTracklets; - mNMissingConsecLayers = t.mNMissingConsecLayers; - mLabelOffline = t.mLabelOffline; - mIsStopped = t.mIsStopped; - for (int i = 0; i < kNLayers; ++i) { - mAttachedTracklets[i] = t.mAttachedTracklets[i]; - mIsFindable[i] = t.mIsFindable[i]; - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = t.mNTrackletsOffline[j]; - } - return *this; -} - -template <typename T> -GPUd() int GPUTRDTrack_t<T>::GetNlayers() const -{ - //------------------------------------------------------------------ - // returns number of layers in which the track is in active area of TRD - //------------------------------------------------------------------ - int res = 0; - for (int iLy = 0; iLy < kNLayers; iLy++) { - if (mIsFindable[iLy]) { - ++res; - } - } - return res; -} - -template <typename T> -GPUd() int GPUTRDTrack_t<T>::GetTracklet(int iLayer) const -{ - //------------------------------------------------------------------ - // returns index of attached tracklet in given layer - //------------------------------------------------------------------ - if (iLayer < 0 || iLayer >= kNLayers) { - return -1; - } - return mAttachedTracklets[iLayer]; -} - -template <typename T> -GPUd() int GPUTRDTrack_t<T>::GetNmissingConsecLayers(int iLayer) const -{ - //------------------------------------------------------------------ - // returns number of consecutive layers in which the track was - // inside the deadzone up to (and including) the given layer - //------------------------------------------------------------------ - int res = 0; - while (!mIsFindable[iLayer]) { - ++res; - --iLayer; - if (iLayer < 0) { - break; - } - } - return res; -} - -template <typename T> -GPUd() void GPUTRDTrack_t<T>::ConvertTo(GPUTRDTrackDataRecord& t) const -{ - //------------------------------------------------------------------ - // convert to GPU structure - //------------------------------------------------------------------ - t.mAlpha = T::getAlpha(); - t.fX = T::getX(); - t.fY = T::getY(); - t.fZ = T::getZ(); - t.fq1Pt = T::getQ2Pt(); - t.mSinPhi = T::getSnp(); - t.fTgl = T::getTgl(); - for (int i = 0; i < 15; i++) { - t.fC[i] = T::getCov()[i]; - } - t.fTPCTrackID = GetTPCtrackId(); - for (int i = 0; i < kNLayers; i++) { - t.fAttachedTracklets[i] = GetTracklet(i); - } -} - -template <typename T> -GPUd() void GPUTRDTrack_t<T>::ConvertFrom(const GPUTRDTrackDataRecord& t) -{ - //------------------------------------------------------------------ - // convert from GPU structure - //------------------------------------------------------------------ - T::set(t.fX, t.mAlpha, &(t.fY), t.fC); - SetTPCtrackId(t.fTPCTrackID); - mChi2 = 0.f; - mMass = 0.13957f; - mLabel = -1; - mNTracklets = 0; - mNMissingConsecLayers = 0; - mLabelOffline = -1; - mIsStopped = false; - for (int iLayer = 0; iLayer < kNLayers; iLayer++) { - mAttachedTracklets[iLayer] = t.fAttachedTracklets[iLayer]; - mIsFindable[iLayer] = 0; - if (mAttachedTracklets[iLayer] >= 0) { - mNTracklets++; - } - } - for (int j = 0; j < 4; ++j) { - mNTrackletsOffline[j] = 0; - } -} - -#ifndef GPUCA_GPUCODE -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -#ifndef GPUCA_GPUCODE -#ifdef GPUCA_ALIROOT_LIB // Instantiate AliRoot track version -template class GPUTRDTrack_t<trackInterface<AliExternalTrackParam>>; -#endif -#ifdef GPUCA_O2_LIB // Instantiate O2 track version -template class GPUTRDTrack_t<trackInterface<o2::dataformats::TrackTPCITS>>; -#endif -#endif -template class GPUTRDTrack_t<trackInterface<GPUTPCGMTrackParam>>; // Always instatiate GM track version -} // namespace gpu -} // namespace GPUCA_NAMESPACE -#endif diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrack.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrack.h deleted file mode 100644 index 515927fac8452..0000000000000 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrack.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTRDTrack.h -/// \author Ole Schmidt - -#ifndef GPUTRDTRACK_H -#define GPUTRDTRACK_H - -#include "GPUTRDDef.h" -#include "GPUDef.h" - -struct GPUTRDTrackDataRecord; -class AliHLTExternalTrackParam; - -//_____________________________________________________________________________ -#if (defined(__CINT__) || defined(__ROOTCINT__)) && !defined(__CLING__) -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -template <typename T> -class GPUTRDTrack_t; -} -} // namespace GPUCA_NAMESPACE -#else -#include "GPUTRDInterfaces.h" - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ - -template <typename T> -class GPUTRDTrack_t : public T -{ - public: - enum EGPUTRDTrack { kNLayers = 6 }; - - GPUd() GPUTRDTrack_t(); - GPUTRDTrack_t(const typename T::baseClass& t) = delete; - GPUd() GPUTRDTrack_t(const GPUTRDTrack_t& t); - GPUd() GPUTRDTrack_t(const AliHLTExternalTrackParam& t); - GPUd() GPUTRDTrack_t(const T& t); - GPUd() GPUTRDTrack_t& operator=(const GPUTRDTrack_t& t); - - GPUd() int GetNlayers() const; - GPUd() int GetTracklet(int iLayer) const; - GPUd() int GetTPCtrackId() const { return mTPCTrackId; } - GPUd() int GetNtracklets() const { return mNTracklets; } - GPUd() int GetNtrackletsOffline(int type) const { return mNTrackletsOffline[type]; } - GPUd() int GetLabelOffline() const { return mLabelOffline; } - GPUd() int GetLabel() const { return mLabel; } - GPUd() float GetChi2() const { return mChi2; } - GPUd() float GetReducedChi2() const { return GetNlayers() == 0 ? mChi2 : mChi2 / GetNlayers(); } - GPUd() float GetMass() const { return mMass; } - GPUd() bool GetIsStopped() const { return mIsStopped; } - GPUd() bool GetIsFindable(int iLayer) const { return mIsFindable[iLayer]; } - GPUd() int GetTrackletIndex(int iLayer) const { return GetTracklet(iLayer); } - GPUd() int GetNmissingConsecLayers(int iLayer) const; - - GPUd() void AddTracklet(int iLayer, int idx) - { - mAttachedTracklets[iLayer] = idx; - mNTracklets++; - } - GPUd() void SetTPCtrackId(int v) { mTPCTrackId = v; } - GPUd() void SetNtracklets(int nTrklts) { mNTracklets = nTrklts; } - GPUd() void SetIsFindable(int iLayer) { mIsFindable[iLayer] = true; } - GPUd() void SetNtrackletsOffline(int type, int nTrklts) { mNTrackletsOffline[type] = nTrklts; } - GPUd() void SetLabelOffline(int lab) { mLabelOffline = lab; } - GPUd() void SetIsStopped() { mIsStopped = true; } - - GPUd() void SetChi2(float chi2) { mChi2 = chi2; } - GPUd() void SetMass(float mass) { mMass = mass; } - GPUd() void SetLabel(int label) { mLabel = label; } - - // conversion to / from HLT track structure - - GPUd() void ConvertTo(GPUTRDTrackDataRecord& t) const; - GPUd() void ConvertFrom(const GPUTRDTrackDataRecord& t); - - protected: - float mChi2; // total chi2 - float mMass; // mass hypothesis - int mLabel; // MC label - int mTPCTrackId; // corresponding TPC track - int mNTracklets; // number of attached TRD tracklets - int mNMissingConsecLayers; // number of missing consecutive layers - int mNTrackletsOffline[4]; // for debugging: attached offline TRD tracklets (0: total, 1: match, 2: related, 3: fake) - int mLabelOffline; // offline TRD MC label of this track - int mAttachedTracklets[kNLayers]; // IDs for attached tracklets sorted by layer - bool mIsFindable[kNLayers]; // number of layers where tracklet should exist - bool mIsStopped; // track ends in TRD -}; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif // !((defined(__CINT__) || defined(__ROOTCINT__)) && !defined(__CLING__)) - -#endif // GPUTRDTRACK_H diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackData.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackData.h index ea03e3b2a09de..eca3c199329f4 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackData.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackData.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackPoint.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackPoint.h index bb356209fe96a..a8c95b74fa8d4 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackPoint.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackPoint.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx index ef8b167b85f16..0c24558f731e8 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,6 @@ #include "GPUTRDTrackletWord.h" #include "GPUTRDGeometry.h" #include "GPUTRDTrackerDebug.h" -#include "GPUMemoryResource.h" #include "GPUCommonMath.h" #include "GPUCommonAlgorithm.h" @@ -31,31 +31,27 @@ using namespace GPUCA_NAMESPACE::gpu; class GPUTPCGMPolynomialField; #ifndef GPUCA_GPUCODE - -#ifndef GPUCA_GPUCODE_DEVICE +#include "GPUMemoryResource.h" #include "GPUReconstruction.h" #ifdef WITH_OPENMP #include <omp.h> -#endif +#endif // WITH_OPENMP #include <chrono> #include <vector> -#endif #ifdef GPUCA_ALIROOT_LIB #include "TDatabasePDG.h" #include "AliMCParticle.h" #include "AliMCEvent.h" -static const float piMass = TDatabasePDG::Instance()->GetParticle(211)->Mass(); -#else -static const float piMass = 0.139f; -#endif +#endif // GPUCA_ALIROOT_LIB #include "GPUChainTracking.h" template <class TRDTRK, class PROP> void GPUTRDTracker_t<TRDTRK, PROP>::SetMaxData(const GPUTrackingInOutPointers& io) { - mNMaxTracks = io.nMergedTracks; + mNMaxTracks = std::max(std::max(io.nOutputTracksTPCO2, io.nTracksTPCITSO2), io.nMergedTracks); mNMaxSpacePoints = io.nTRDTracklets; + mNMaxCollisions = io.nTRDTriggerRecords; } template <class TRDTRK, class PROP> @@ -75,7 +71,6 @@ void* GPUTRDTracker_t<TRDTRK, PROP>::SetPointersBase(void* base) //-------------------------------------------------------------------- mMaxThreads = mRec->GetMaxThreads(); computePointerWithAlignment(base, mR, kNChambers); - computePointerWithAlignment(base, mTrackletIndexArray, (kNChambers + 1) * mNMaxCollisions); computePointerWithAlignment(base, mHypothesis, mNCandidates * mMaxThreads); computePointerWithAlignment(base, mCandidates, mNCandidates * 2 * mMaxThreads); return base; @@ -88,9 +83,10 @@ void* GPUTRDTracker_t<TRDTRK, PROP>::SetPointersTracklets(void* base) // Allocate memory for tracklets and space points // (size might change for different events) //-------------------------------------------------------------------- - computePointerWithAlignment(base, mTracklets, mNMaxSpacePoints * mNMaxCollisions); - computePointerWithAlignment(base, mSpacePoints, mNMaxSpacePoints * mNMaxCollisions); - computePointerWithAlignment(base, mTrackletLabels, 3 * mNMaxSpacePoints * mNMaxCollisions); + if (mGenerateSpacePoints) { + computePointerWithAlignment(base, mSpacePoints, mNMaxSpacePoints); + } + computePointerWithAlignment(base, mTrackletIndexArray, (kNChambers + 1) * mNMaxCollisions); return base; } @@ -101,11 +97,12 @@ void* GPUTRDTracker_t<TRDTRK, PROP>::SetPointersTracks(void* base) // Allocate memory for tracks (this is done once per event) //-------------------------------------------------------------------- computePointerWithAlignment(base, mTracks, mNMaxTracks); + computePointerWithAlignment(base, mTrackAttribs, mNMaxTracks); return base; } template <class TRDTRK, class PROP> -GPUTRDTracker_t<TRDTRK, PROP>::GPUTRDTracker_t() : mR(nullptr), mIsInitialized(false), mProcessPerTimeFrame(false), mMemoryPermanent(-1), mMemoryTracklets(-1), mMemoryTracks(-1), mNMaxCollisions(1), mNMaxTracks(0), mNMaxSpacePoints(0), mTracks(nullptr), mNCandidates(1), mNCollisions(1), mNTracks(0), mNEvents(0), mTriggerRecordIndices(nullptr), mTriggerRecordTimes(nullptr), mTracklets(nullptr), mMaxThreads(100), mNTracklets(0), mTrackletIndexArray(nullptr), mHypothesis(nullptr), mCandidates(nullptr), mSpacePoints(nullptr), mTrackletLabels(nullptr), mGeo(nullptr), mRPhiA2(0), mRPhiB(0), mRPhiC2(0), mDyA2(0), mDyB(0), mDyC2(0), mAngleToDyA(0), mAngleToDyB(0), mAngleToDyC(0), mDebugOutput(false), mTimeWindow(.1f), mRadialOffset(-0.1), mMaxEta(0.84f), mExtraRoadY(2.f), mRoadZ(18.f), mZCorrCoefNRC(1.4f), mMCEvent(nullptr), mDebug(new GPUTRDTrackerDebug<TRDTRK>()) +GPUTRDTracker_t<TRDTRK, PROP>::GPUTRDTracker_t() : mR(nullptr), mIsInitialized(false), mGenerateSpacePoints(false), mProcessPerTimeFrame(false), mNAngleHistogramBins(25), mAngleHistogramRange(50), mMemoryPermanent(-1), mMemoryTracklets(-1), mMemoryTracks(-1), mNMaxCollisions(0), mNMaxTracks(0), mNMaxSpacePoints(0), mTracks(nullptr), mTrackAttribs(nullptr), mNCandidates(1), mNTracks(0), mNEvents(0), mMaxThreads(100), mTrackletIndexArray(nullptr), mHypothesis(nullptr), mCandidates(nullptr), mSpacePoints(nullptr), mGeo(nullptr), mRPhiA2(0), mRPhiB(0), mRPhiC2(0), mDyA2(0), mDyB(0), mDyC2(0), mAngleToDyA(0), mAngleToDyB(0), mAngleToDyC(0), mDebugOutput(false), mMaxEta(0.84f), mExtraRoadY(2.f), mRoadZ(18.f), mZCorrCoefNRC(1.4f), mTPCVdrift(2.58f), mDebug(new GPUTRDTrackerDebug<TRDTRK>()) { //-------------------------------------------------------------------- // Default constructor @@ -129,12 +126,12 @@ void GPUTRDTracker_t<TRDTRK, PROP>::InitializeProcessor() //-------------------------------------------------------------------- mGeo = (TRD_GEOMETRY_CONST GPUTRDGeometry*)GetConstantMem()->calibObjects.trdGeometry; if (!mGeo) { - Error("Init", "TRD geometry must be provided externally"); + GPUError("TRD geometry must be provided externally"); } - float Bz = Param().par.BzkG; + float Bz = Param().par.bzkG; GPUInfo("Initializing with B-field: %f kG", Bz); - if (abs(abs(Bz) - 2) < 0.1) { + if (CAMath::Abs(CAMath::Abs(Bz) - 2) < 0.1) { // magnetic field +-0.2 T if (Bz > 0) { GPUInfo("Loading error parameterization for Bz = +2 kG"); @@ -147,7 +144,7 @@ void GPUTRDTracker_t<TRDTRK, PROP>::InitializeProcessor() mDyA2 = 1.225e-3f, mDyB = 9.8e-3f, mDyC2 = 3.88e-2f; mAngleToDyA = 0.1f, mAngleToDyB = 1.89f, mAngleToDyC = 0.4f; } - } else if (abs(abs(Bz) - 5) < 0.1) { + } else if (CAMath::Abs(CAMath::Abs(Bz) - 5) < 0.1) { // magnetic field +-0.5 T if (Bz > 0) { GPUInfo("Loading error parameterization for Bz = +5 kG"); @@ -196,28 +193,31 @@ void GPUTRDTracker_t<TRDTRK, PROP>::Reset() //-------------------------------------------------------------------- // Reset tracker //-------------------------------------------------------------------- - mNTracklets = 0; mNTracks = 0; } template <class TRDTRK, class PROP> -void GPUTRDTracker_t<TRDTRK, PROP>::DoTracking(GPUChainTracking* chainTracking) +void GPUTRDTracker_t<TRDTRK, PROP>::PrepareTracking(GPUChainTracking* chainTracking) { //-------------------------------------------------------------------- - // Steering function for the tracking + // Prepare tracklet index array and if requested calculate space points + // in part duplicated from DoTracking() method to allow for calling + // this function on the host prior to GPU processing //-------------------------------------------------------------------- - - // sort tracklets and fill index array - for (int iColl = 0; iColl < mNCollisions; ++iColl) { + for (unsigned int iColl = 0; iColl < GetConstantMem()->ioPtrs.nTRDTriggerRecords; ++iColl) { + if (GetConstantMem()->ioPtrs.trdTrigRecMask[iColl] == 0) { + // this trigger is masked as there is no ITS information available for it + continue; + } int nTrklts = 0; + int idxOffset = 0; if (mProcessPerTimeFrame) { - // FIXME maybe two nested if statements are not so good in terms of performance? - nTrklts = (iColl < mNCollisions - 1) ? mTriggerRecordIndices[iColl + 1] - mTriggerRecordIndices[iColl] : mNTracklets - mTriggerRecordIndices[iColl]; + idxOffset = GetConstantMem()->ioPtrs.trdTrackletIdxFirst[iColl]; + nTrklts = (iColl < GetConstantMem()->ioPtrs.nTRDTriggerRecords - 1) ? GetConstantMem()->ioPtrs.trdTrackletIdxFirst[iColl + 1] - GetConstantMem()->ioPtrs.trdTrackletIdxFirst[iColl] : GetConstantMem()->ioPtrs.nTRDTracklets - GetConstantMem()->ioPtrs.trdTrackletIdxFirst[iColl]; } else { - nTrklts = mNTracklets; + nTrklts = GetConstantMem()->ioPtrs.nTRDTracklets; } - GPUTRDTrackletWord* tracklets = (mProcessPerTimeFrame) ? &(mTracklets[mTriggerRecordIndices[iColl]]) : mTracklets; - CAAlgo::sort(tracklets, tracklets + nTrklts); // tracklets are sorted by HCId + const GPUTRDTrackletWord* tracklets = &((GetConstantMem()->ioPtrs.trdTracklets)[idxOffset]); int* trkltIndexArray = &mTrackletIndexArray[iColl * (kNChambers + 1) + 1]; trkltIndexArray[-1] = 0; int currDet = 0; @@ -236,12 +236,26 @@ void GPUTRDTracker_t<TRDTRK, PROP>::DoTracking(GPUChainTracking* chainTracking) for (int iDet = currDet; iDet <= kNChambers; ++iDet) { trkltIndexArray[iDet] = trkltCounter; } - - if (!CalculateSpacePoints(iColl)) { - GPUError("Space points for at least one chamber could not be calculated (for interaction %i)", iColl); - break; + if (mGenerateSpacePoints) { + if (!CalculateSpacePoints(iColl)) { + GPUError("Space points for at least one chamber could not be calculated (for interaction %i)", iColl); + break; + } } } + if (mGenerateSpacePoints) { + chainTracking->mIOPtrs.trdSpacePoints = mSpacePoints; + } +} + +template <class TRDTRK, class PROP> +void GPUTRDTracker_t<TRDTRK, PROP>::DoTracking(GPUChainTracking* chainTracking) +{ + //-------------------------------------------------------------------- + // Steering function for the tracking + //-------------------------------------------------------------------- + + PrepareTracking(chainTracking); auto timeStart = std::chrono::high_resolution_clock::now(); @@ -249,7 +263,7 @@ void GPUTRDTracker_t<TRDTRK, PROP>::DoTracking(GPUChainTracking* chainTracking) chainTracking->DoTRDGPUTracking(); } else { #ifdef WITH_OPENMP -#pragma omp parallel for +#pragma omp parallel for num_threads(mRec->GetProcessingSettings().ompThreads) for (int iTrk = 0; iTrk < mNTracks; ++iTrk) { if (omp_get_num_threads() > mMaxThreads) { GPUError("Number of parallel threads too high, aborting tracking"); @@ -267,11 +281,12 @@ void GPUTRDTracker_t<TRDTRK, PROP>::DoTracking(GPUChainTracking* chainTracking) } auto duration = std::chrono::high_resolution_clock::now() - timeStart; + (void)duration; // suppress warning about unused variable /* std::cout << "---> -----> -------> ---------> "; std::cout << "Time for event " << mNEvents << ": " << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() << " us "; std::cout << "nTracks: " << mNTracks; - std::cout << " nTracklets: " << mNTracklets; + std::cout << " nTracklets: " << GetConstantMem()->ioPtrs.nTRDTracklets; std::cout << std::endl; */ //DumpTracks(); @@ -287,7 +302,7 @@ void GPUTRDTracker_t<TRDTRK, PROP>::SetNCandidates(int n) if (!mIsInitialized) { mNCandidates = n; } else { - Error("SetNCandidates", "Cannot change mNCandidates after initialization"); + GPUError("Cannot change mNCandidates after initialization"); } } @@ -299,8 +314,8 @@ void GPUTRDTracker_t<TRDTRK, PROP>::PrintSettings() const //-------------------------------------------------------------------- GPUInfo("##############################################################"); GPUInfo("Current settings for GPU TRD tracker:"); - GPUInfo(" maxChi2(%.2f), chi2Penalty(%.2f), nCandidates(%i), maxMissingLayers(%i)", Param().rec.trdMaxChi2, Param().rec.trdPenaltyChi2, mNCandidates, Param().rec.trdStopTrkAfterNMissLy); - GPUInfo(" ptCut = %.2f GeV, abs(eta) < %.2f", Param().rec.trdMinTrackPt, mMaxEta); + GPUInfo(" maxChi2(%.2f), chi2Penalty(%.2f), nCandidates(%i), maxMissingLayers(%i)", Param().rec.trd.maxChi2, Param().rec.trd.penaltyChi2, mNCandidates, Param().rec.trd.stopTrkAfterNMissLy); + GPUInfo(" ptCut = %.2f GeV, abs(eta) < %.2f", Param().rec.trd.minTrackPt, mMaxEta); GPUInfo("##############################################################"); } @@ -310,121 +325,27 @@ void GPUTRDTracker_t<TRDTRK, PROP>::StartDebugging() mDebug->CreateStreamer(); } -template <class TRDTRK, class PROP> -void GPUTRDTracker_t<TRDTRK, PROP>::CountMatches(const int trackID, std::vector<int>* matches) const + + +#endif //! GPUCA_GPUCODE + +template <> +GPUdi() const GPUTRDPropagatorGPU::propagatorParam* GPUTRDTracker_t<GPUTRDTrackGPU, GPUTRDPropagatorGPU>::getPropagatorParam() { -//-------------------------------------------------------------------- -// search in all TRD chambers for matching tracklets -// including all tracklets created by the track and its daughters -// important: tracklets far away / pointing in different direction of -// the track should be rejected (or this has to be done afterwards in analysis) -//-------------------------------------------------------------------- -#ifndef GPUCA_GPUCODE -#ifdef ENABLE_GPUMC - for (int k = 0; k < kNChambers; k++) { - int layer = mGeo->GetLayer(k); - for (int trkltIdx = mTrackletIndexArray[k]; trkltIdx < mTrackletIndexArray[k + 1]; trkltIdx++) { - bool trkltStored = false; - for (int il = 0; il < 3; il++) { - int lb = mSpacePoints[trkltIdx].mLabel[il]; - if (lb < 0) { - // no more valid labels - break; - } - if (lb == CAMath::Abs(trackID)) { - matches[layer].push_back(trkltIdx); - break; - } - if (!mMCEvent) { - continue; - } - //continue; //FIXME uncomment to count only exact matches - AliMCParticle* mcPart = (AliMCParticle*)mMCEvent->GetTrack(lb); - while (mcPart) { - lb = mcPart->GetMother(); - if (lb == CAMath::Abs(trackID)) { - matches[layer].push_back(trkltIdx); - trkltStored = true; - break; - } - mcPart = lb >= 0 ? (AliMCParticle*)mMCEvent->GetTrack(lb) : 0; - } - if (trkltStored) { - break; - } - } - } - } -#endif -#endif + return &Param().polynomialField; } template <class TRDTRK, class PROP> -GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::CheckTrackRefs(const int trackID, bool* findableMC) const +GPUdi() const typename PROP::propagatorParam* GPUTRDTracker_t<TRDTRK, PROP>::getPropagatorParam() { -#ifdef ENABLE_GPUMC - //-------------------------------------------------------------------- - // loop over all track references for the input trackID and set - // findableMC to true for each layer in which a track hit both - // entering and exiting the TRD chamber exists - // (in debug mode) - //-------------------------------------------------------------------- - TParticle* particle; - TClonesArray* trackRefs; - - int nHits = mMCEvent->GetParticleAndTR(trackID, particle, trackRefs); - if (nHits < 1) { - return; - } - bool isFindable[2 * kNLayers] = {false}; - int nHitsTrd = 0; - for (int iHit = 0; iHit < nHits; ++iHit) { - AliTrackReference* trackReference = static_cast<AliTrackReference*>(trackRefs->UncheckedAt(iHit)); - if (trackReference->DetectorId() != AliTrackReference::kTRD) { - continue; - } - nHitsTrd++; - float xLoc = trackReference->LocalX(); - if (!((trackReference->TestBits(0x1 << 18)) || (trackReference->TestBits(0x1 << 17)))) { - //if (!trackReference->TestBits(0x1 << 18)) { - // bit 17 - entering; bit 18 - exiting - continue; - } - int layer = -1; - if (xLoc < 304.f) { - layer = 0; - } else if (xLoc < 317.f) { - layer = 1; - } else if (xLoc < 330.f) { - layer = 2; - } else if (xLoc < 343.f) { - layer = 3; - } else if (xLoc < 356.f) { - layer = 4; - } else if (xLoc < 369.f) { - layer = 5; - } - if (layer < 0) { - GPUError("No layer can be determined for x=%f, y=%f, z=%f, layer=%i", xLoc, trackReference->LocalY(), trackReference->Z(), layer); - continue; - } - if (trackReference->TestBits(0x1 << 18)) { - isFindable[layer * 2] = true; - } - if (trackReference->TestBits(0x1 << 17)) { - isFindable[layer * 2 + 1] = true; - } - } - for (int iLayer = 0; iLayer < kNLayers; ++iLayer) { - if (isFindable[iLayer * 2] && isFindable[iLayer * 2 + 1]) { - findableMC[iLayer] = true; - } else { - findableMC[iLayer] = false; - } - } +#ifdef GPUCA_GPUCODE + return GetConstantMem()->calibObjects.o2Propagator; +#elif defined GPUCA_ALIROOT_LIB + return nullptr; +#else + return o2::base::Propagator::Instance(); #endif } -#endif //! GPUCA_GPUCODE template <class TRDTRK, class PROP> GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::CheckTrackTRDCandidate(const TRDTRK& trk) const @@ -435,14 +356,14 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::CheckTrackTRDCandidate(const TRDTRK& if (CAMath::Abs(trk.getEta()) > mMaxEta) { return false; } - if (trk.getPt() < Param().rec.trdMinTrackPt) { + if (trk.getPt() < Param().rec.trd.minTrackPt) { return false; } return true; } template <class TRDTRK, class PROP> -GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::LoadTrack(const TRDTRK& trk, const int label, const int* nTrkltsOffline, const int labelOffline, int tpcTrackId, bool checkTrack) +GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::LoadTrack(const TRDTRK& trk, unsigned int tpcTrackId, bool checkTrack, HelperTrackAttributes* attribs) { if (mNTracks >= mNMaxTracks) { #ifndef GPUCA_GPUCODE @@ -458,38 +379,14 @@ GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::LoadTrack(const TRDTRK& trk, const int #else mTracks[mNTracks] = trk; #endif - mTracks[mNTracks].SetTPCtrackId(tpcTrackId >= 0 ? tpcTrackId : mNTracks); - if (label >= 0) { - mTracks[mNTracks].SetLabel(label); + mTracks[mNTracks].setRefGlobalTrackIdRaw(tpcTrackId); + if (attribs) { + mTrackAttribs[mNTracks] = *attribs; } - if (nTrkltsOffline) { - for (int i = 0; i < 4; ++i) { - mTracks[mNTracks].SetNtrackletsOffline(i, nTrkltsOffline[i]); // see GPUTRDTrack.h for information on the index - } - } - mTracks[mNTracks].SetLabelOffline(labelOffline); mNTracks++; return (0); } -template <class TRDTRK, class PROP> -GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::LoadTracklet(const GPUTRDTrackletWord& tracklet, const int* labels) -{ - //-------------------------------------------------------------------- - // Add single tracklet to tracker - //-------------------------------------------------------------------- - if (mNTracklets >= mNMaxSpacePoints * mNMaxCollisions) { - Error("LoadTracklet", "Running out of memory for tracklets, skipping tracklet(s). This should actually never happen."); - return 1; - } - if (labels) { - for (int i = 0; i < 3; ++i) { - mTrackletLabels[3 * mNTracklets + i] = labels[i]; - } - } - mTracklets[mNTracklets++] = tracklet; - return 0; -} template <class TRDTRK, class PROP> GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::DumpTracks() @@ -497,25 +394,38 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::DumpTracks() //-------------------------------------------------------------------- // helper function (only for debugging purposes) //-------------------------------------------------------------------- - GPUInfo("There are %i tracks loaded. mNMaxTracks(%i)\n", mNTracks, mNMaxTracks); + GPUInfo("There are in total %i tracklets loaded", GetConstantMem()->ioPtrs.nTRDTracklets); + GPUInfo("There are %i tracks loaded. mNMaxTracks(%i)", mNTracks, mNMaxTracks); for (int i = 0; i < mNTracks; ++i) { auto* trk = &(mTracks[i]); - GPUInfo("track %i: x=%f, alpha=%f, nTracklets=%i, pt=%f", i, trk->getX(), trk->getAlpha(), trk->GetNtracklets(), trk->getPt()); + GPUInfo("track %i: x=%f, alpha=%f, nTracklets=%i, pt=%f, time=%f", i, trk->getX(), trk->getAlpha(), trk->getNtracklets(), trk->getPt(), mTrackAttribs[i].mTime); } } template <class TRDTRK, class PROP> -GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::GetCollisionID(float trkTime) const +GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::GetCollisionIDs(int iTrk, int* collisionIds) const { - for (int iColl = 0; iColl < mNCollisions; ++iColl) { - if (CAMath::Abs(trkTime - mTriggerRecordTimes[iColl]) < mTimeWindow) { - if (ENABLE_INFO) { - GPUInfo("TRD info found from interaction %i at %f for track with time %f", iColl, mTriggerRecordTimes[iColl], trkTime); + //-------------------------------------------------------------------- + // Check which TRD trigger times possibly match given input track. + // If ITS-TPC matches or CE-crossing TPC tracks the time is precisely + // known and max 1 trigger time can be assigned. + // For TPC-only tracks the collision IDs are stored in collisionIds array + // and the number of valid entries in the array is returned + //-------------------------------------------------------------------- + int nColls = 0; + for (unsigned int iColl = 0; iColl < GetConstantMem()->ioPtrs.nTRDTriggerRecords; ++iColl) { + if (GetConstantMem()->ioPtrs.trdTrigRecMask[iColl] == 0) { + continue; + } + if (GetConstantMem()->ioPtrs.trdTriggerTimes[iColl] > mTrackAttribs[iTrk].GetTimeMin() && GetConstantMem()->ioPtrs.trdTriggerTimes[iColl] < mTrackAttribs[iTrk].GetTimeMax()) { + if (nColls == 20) { + GPUError("Found too many collision candidates for track with tMin(%f) and tMax(%f)", mTrackAttribs[iTrk].GetTimeMin(), mTrackAttribs[iTrk].GetTimeMax()); + return nColls; } - return iColl; + collisionIds[nColls++] = iColl; } } - return -1; + return nColls; } template <class TRDTRK, class PROP> @@ -524,25 +434,67 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::DoTrackingThread(int iTrk, int thread //-------------------------------------------------------------------- // perform the tracking for one track (must be threadsafe) //-------------------------------------------------------------------- - int collisionId = 0; + int collisionIds[20] = {0}; // due to the dead time there will never exist more possible TRD triggers for a single track + int nCollisionIds = 1; // initialize with 1 for AliRoot compatibility if (mProcessPerTimeFrame) { - collisionId = GetCollisionID(mTracks[iTrk].getTime()); - if (collisionId < 0) { + nCollisionIds = GetCollisionIDs(iTrk, collisionIds); + if (nCollisionIds == 0) { if (ENABLE_INFO) { - GPUInfo("Did not find TRD data for track with t=%f", mTracks[iTrk].getTime()); + GPUInfo("Did not find TRD data for track %i with t=%f. tMin(%f), tMax(%f)", iTrk, mTrackAttribs[iTrk].mTime, mTrackAttribs[iTrk].GetTimeMin(), mTrackAttribs[iTrk].GetTimeMax()); } // no TRD data available for the bunch crossing this track originates from return; } } - PROP prop(&Param().polynomialField); - auto trkCopy = mTracks[iTrk]; - prop.setTrack(&trkCopy); - prop.setFitInProjections(true); - FollowProlongation(&prop, &trkCopy, threadId, collisionId); - mTracks[iTrk] = trkCopy; // copy back the resulting track + PROP prop(getPropagatorParam()); + mTracks[iTrk].setChi2(Param().rec.trd.penaltyChi2); // TODO check if this should not be higher + auto trkStart = mTracks[iTrk]; + for (int iColl = 0; iColl < nCollisionIds; ++iColl) { + // do track following for each collision candidate and keep best track + auto trkCopy = trkStart; + prop.setTrack(&trkCopy); + prop.setFitInProjections(true); + if (!FollowProlongation(&prop, &trkCopy, iTrk, threadId, collisionIds[iColl])) { + // track following failed + continue; + } + if (trkCopy.getReducedChi2() < mTracks[iTrk].getReducedChi2()) { + mTracks[iTrk] = trkCopy; // copy back the resulting track + } + } } +#ifndef GPUCA_ALIROOT_LIB // AliRoot TRD geometry functions are non-const, and cannot work with a const geometry +template <class TRDTRK, class PROP> +GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::ConvertTrkltToSpacePoint(const GPUTRDGeometry& geo, GPUTRDTrackletWord& trklt, GPUTRDSpacePoint& sp) +{ + // converts a single GPUTRDTrackletWord into GPUTRDSpacePoint + // returns true if successfull + int det = trklt.GetDetector(); + if (!geo.ChamberInGeometry(det)) { + return false; + } + auto* matrix = geo.GetClusterMatrix(det); + if (!matrix) { + return false; + } + const GPUTRDpadPlane* pp = geo.GetPadPlane(det); + int trkltZbin = trklt.GetZbin(); + My_Float xTrkltDet[3] = {0.f}; // trklt position in chamber coordinates + My_Float xTrkltSec[3] = {0.f}; // trklt position in sector coordinates + xTrkltDet[0] = geo.AnodePos() - sRadialOffset; + xTrkltDet[1] = trklt.GetY(); + xTrkltDet[2] = pp->GetRowPos(trkltZbin) - pp->GetRowSize(trkltZbin) / 2.f - pp->GetRowPos(pp->GetNrows() / 2); + matrix->LocalToMaster(xTrkltDet, xTrkltSec); + sp.setX(xTrkltSec[0]); + sp.setY(xTrkltSec[1]); + sp.setZ(xTrkltSec[2]); + sp.setDy(trklt.GetdY()); + + return true; +} +#endif + template <class TRDTRK, class PROP> GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::CalculateSpacePoints(int iCollision) { @@ -552,11 +504,15 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::CalculateSpacePoints(int iCollision) //-------------------------------------------------------------------- bool result = true; - int idxOffset = iCollision * (kNChambers + 1); + int idxOffset = iCollision * (kNChambers + 1); // offset for accessing mTrackletIndexArray for collision iCollision + + const GPUTRDTrackletWord* tracklets = GetConstantMem()->ioPtrs.trdTracklets; for (int iDet = 0; iDet < kNChambers; ++iDet) { - int nTracklets = mTrackletIndexArray[idxOffset + iDet + 1] - mTrackletIndexArray[idxOffset + iDet]; - if (nTracklets == 0) { + int iFirstTrackletInDet = mTrackletIndexArray[idxOffset + iDet]; + int iFirstTrackletInNextDet = mTrackletIndexArray[idxOffset + iDet + 1]; + int nTrackletsInDet = iFirstTrackletInNextDet - iFirstTrackletInDet; + if (nTrackletsInDet == 0) { continue; } if (!mGeo->ChamberInGeometry(iDet)) { @@ -570,44 +526,31 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::CalculateSpacePoints(int iCollision) continue; } const GPUTRDpadPlane* pp = mGeo->GetPadPlane(iDet); - float tilt = CAMath::Tan(M_PI / 180.f * pp->GetTiltingAngle()); - float t2 = tilt * tilt; // tan^2 (tilt) - float c2 = 1.f / (1.f + t2); // cos^2 (tilt) - float sy2 = 0.1f * 0.1f; // sigma_rphi^2, currently assume sigma_rphi = 1 mm - - for (int trkltIdx = mTrackletIndexArray[idxOffset + iDet]; trkltIdx < mTrackletIndexArray[idxOffset + iDet + 1]; ++trkltIdx) { - int trkltZbin = mTracklets[trkltIdx].GetZbin(); - float sz2 = pp->GetRowSize(trkltZbin) * pp->GetRowSize(trkltZbin) / 12.f; // sigma_z = l_pad/sqrt(12) TODO try a larger z error + + int trkltIdxOffset = (mProcessPerTimeFrame) ? GetConstantMem()->ioPtrs.trdTrackletIdxFirst[iCollision] : 0; // global index of first tracklet in iCollision + int trkltIdxStart = trkltIdxOffset + iFirstTrackletInDet; + for (int trkltIdx = trkltIdxStart; trkltIdx < trkltIdxStart + nTrackletsInDet; ++trkltIdx) { + int trkltZbin = tracklets[trkltIdx].GetZbin(); My_Float xTrkltDet[3] = {0.f}; // trklt position in chamber coordinates My_Float xTrkltSec[3] = {0.f}; // trklt position in sector coordinates - xTrkltDet[0] = mGeo->AnodePos() + mRadialOffset; - xTrkltDet[1] = mTracklets[trkltIdx].GetY(); + xTrkltDet[0] = mGeo->AnodePos() + sRadialOffset; + xTrkltDet[1] = tracklets[trkltIdx].GetY(); xTrkltDet[2] = pp->GetRowPos(trkltZbin) - pp->GetRowSize(trkltZbin) / 2.f - pp->GetRowPos(pp->GetNrows() / 2); //GPUInfo("Space point local %i: x=%f, y=%f, z=%f", trkltIdx, xTrkltDet[0], xTrkltDet[1], xTrkltDet[2]); matrix->LocalToMaster(xTrkltDet, xTrkltSec); - mSpacePoints[trkltIdx].mR = xTrkltSec[0]; - mSpacePoints[trkltIdx].mX[0] = xTrkltSec[1]; - mSpacePoints[trkltIdx].mX[1] = xTrkltSec[2]; - mSpacePoints[trkltIdx].mId = mTracklets[trkltIdx].GetId(); - for (int i = 0; i < 3; i++) { - mSpacePoints[trkltIdx].mLabel[i] = mTrackletLabels[3 * mTracklets[trkltIdx].GetId() + i]; - } - mSpacePoints[trkltIdx].mCov[0] = c2 * (sy2 + t2 * sz2); - mSpacePoints[trkltIdx].mCov[1] = c2 * tilt * (sz2 - sy2); - mSpacePoints[trkltIdx].mCov[2] = c2 * (t2 * sy2 + sz2); - mSpacePoints[trkltIdx].mDy = 0.014f * mTracklets[trkltIdx].GetdY(); - - int modId = mGeo->GetSector(iDet) * GPUTRDGeometry::kNstack + mGeo->GetStack(iDet); // global TRD stack number - unsigned short volId = mGeo->GetGeomManagerVolUID(iDet, modId); - mSpacePoints[trkltIdx].mVolumeId = volId; - //GPUInfo("Space point global %i: x=%f, y=%f, z=%f", trkltIdx, mSpacePoints[trkltIdx].mR, mSpacePoints[trkltIdx].mX[0], mSpacePoints[trkltIdx].mX[1]); + mSpacePoints[trkltIdx].setX(xTrkltSec[0]); + mSpacePoints[trkltIdx].setY(xTrkltSec[1]); + mSpacePoints[trkltIdx].setZ(xTrkltSec[2]); + mSpacePoints[trkltIdx].setDy(tracklets[trkltIdx].GetdY()); + + //GPUInfo("Space point global %i: x=%f, y=%f, z=%f", trkltIdx, mSpacePoints[trkltIdx].getX(), mSpacePoints[trkltIdx].getY(), mSpacePoints[trkltIdx].getZ()); } } return result; } template <class TRDTRK, class PROP> -GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK* t, int threadId, int collisionId) +GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK* t, int iTrk, int threadId, int collisionId) { //-------------------------------------------------------------------- // Propagate TPC track layerwise through TRD and pick up closest @@ -615,32 +558,29 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK // -> returns false if prolongation could not be executed fully // or track does not fullfill threshold conditions //-------------------------------------------------------------------- - //GPUInfo("Start track following for track %i at x=%f with pt=%f", t->GetTPCtrackId(), t->getX(), t->getPt()); + //GPUInfo("Start track following for track %i at x=%f with pt=%f", t->getRefGlobalTrackIdRaw(), t->getX(), t->getPt()); mDebug->Reset(); - int iTrack = t->GetTPCtrackId(); - t->SetChi2(0.f); + t->setChi2(0.f); + float zShiftTrk = 0.f; + if (mProcessPerTimeFrame) { + zShiftTrk = (mTrackAttribs[iTrk].mTime - GetConstantMem()->ioPtrs.trdTriggerTimes[collisionId]) * mTPCVdrift * mTrackAttribs[iTrk].mSide; + //float addZerr = (mTrackAttribs[iTrk].mTimeAddMax + mTrackAttribs[iTrk].mTimeSubMax) * .5f * mTPCVdrift; + // increase Z error based on time window + // -> this is here since it was done before, but the efficiency seems to be better if the covariance is not updated (more tracklets are attached) + //t->updateCovZ2(addZerr * addZerr); // TODO check again once detailed performance study tools are available, maybe this can be tuned + } const GPUTRDpadPlane* pad = nullptr; + const GPUTRDTrackletWord* tracklets = GetConstantMem()->ioPtrs.trdTracklets; + const GPUTRDSpacePoint* spacePoints = GetConstantMem()->ioPtrs.trdSpacePoints; #ifdef ENABLE_GPUTRDDEBUG TRDTRK trackNoUp(*t); #endif - // look for matching tracklets via MC label - int trackID = t->GetLabel(); - -#ifdef ENABLE_GPUMC - std::vector<int> matchAvailableAll[kNLayers]; // all available MC tracklet matches for this track - if (mDebugOutput && trackID > 0 && mMCEvent) { - CountMatches(trackID, matchAvailableAll); - bool findableMC[kNLayers] = {false}; - CheckTrackRefs(trackID, findableMC); - mDebug->SetFindableMC(findableMC); - } -#endif - int candidateIdxOffset = threadId * 2 * mNCandidates; int hypothesisIdxOffset = threadId * mNCandidates; - int trkltIdxOffset = collisionId * (kNChambers + 1); + int trkltIdxOffset = collisionId * (kNChambers + 1); // offset for accessing mTrackletIndexArray for given collision + int glbTrkltIdxOffset = (mProcessPerTimeFrame) ? GetConstantMem()->ioPtrs.trdTrackletIdxFirst[collisionId] : 0; // offset of first tracklet in given collision in global tracklet array auto trkWork = t; if (mNCandidates > 1) { @@ -648,22 +588,23 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK mCandidates[candidateIdxOffset] = *t; } - int nCandidates = 1; + int nCandidates = 1; // we always start with one candidate + int nCurrHypothesis = 0; // the number of track hypothesis in given iLayer // search window float roadY = 0.f; float roadZ = 0.f; const int nMaxChambersToSearch = 4; - mDebug->SetGeneralInfo(mNEvents, mNTracks, iTrack, trackID, t->getPt()); + mDebug->SetGeneralInfo(mNEvents, mNTracks, iTrk, t->getPt()); for (int iLayer = 0; iLayer < kNLayers; ++iLayer) { - int nCurrHypothesis = 0; + nCurrHypothesis = 0; bool isOK = false; // if at least one candidate could be propagated or the track was stopped this becomes true int currIdx = candidateIdxOffset + iLayer % 2; int nextIdx = candidateIdxOffset + (iLayer + 1) % 2; pad = mGeo->GetPadPlane(iLayer, 0); - float tilt = CAMath::Tan(M_PI / 180.f * pad->GetTiltingAngle()); // tilt is signed! + float tilt = CAMath::Tan(CAMath::Pi() / 180.f * pad->GetTiltingAngle()); // tilt is signed! const float zMaxTRD = pad->GetRow0(); // -------------------------------------------------------------------------------- @@ -680,8 +621,8 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK prop->setTrack(trkWork); } - if (trkWork->GetIsStopped()) { - Hypothesis hypo(trkWork->GetNlayers(), iCandidate, -1, trkWork->GetChi2()); + if (trkWork->getIsStopped()) { + Hypothesis hypo(trkWork->getNlayersFindable(), iCandidate, -1, trkWork->getChi2()); InsertHypothesis(hypo, nCurrHypothesis, hypothesisIdxOffset); isOK = true; continue; @@ -690,7 +631,7 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK // propagate track to average radius of TRD layer iLayer (sector 0, stack 2 is chosen as a reference) if (!prop->propagateToX(mR[2 * kNLayers + iLayer], .8f, 2.f)) { if (ENABLE_INFO) { - GPUInfo("Track propagation failed for track %i candidate %i in layer %i (pt=%f, x=%f, mR[layer]=%f)", iTrack, iCandidate, iLayer, trkWork->getPt(), trkWork->getX(), mR[2 * kNLayers + iLayer]); + GPUInfo("Track propagation failed for track %i candidate %i in layer %i (pt=%f, x=%f, mR[layer]=%f)", iTrk, iCandidate, iLayer, trkWork->getPt(), trkWork->getX(), mR[2 * kNLayers + iLayer]); } continue; } @@ -698,14 +639,14 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK // rotate track in new sector in case of sector crossing if (!AdjustSector(prop, trkWork)) { if (ENABLE_INFO) { - GPUInfo("FollowProlongation: Adjusting sector failed for track %i candidate %i in layer %i", iTrack, iCandidate, iLayer); + GPUInfo("Adjusting sector failed for track %i candidate %i in layer %i", iTrk, iCandidate, iLayer); } continue; } // check if track is findable - if (IsGeoFindable(trkWork, iLayer, prop->getAlpha())) { - trkWork->SetIsFindable(iLayer); + if (IsGeoFindable(trkWork, iLayer, prop->getAlpha(), zShiftTrk)) { + trkWork->setIsFindable(iLayer); } // define search window @@ -713,15 +654,15 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK // roadZ = 7.f * CAMath::Sqrt(trkWork->getSigmaZ2() + 9.f * 9.f / 12.f); // take longest pad length roadZ = mRoadZ; // simply twice the longest pad length -> efficiency 99.996% // - if (CAMath::Abs(trkWork->getZ()) - roadZ >= zMaxTRD) { + if (CAMath::Abs(trkWork->getZ() + zShiftTrk) - roadZ >= zMaxTRD) { if (ENABLE_INFO) { - GPUInfo("FollowProlongation: Track out of TRD acceptance with z=%f in layer %i (eta=%f)", trkWork->getZ(), iLayer, trkWork->getEta()); + GPUInfo("Track out of TRD acceptance with z=%f in layer %i (eta=%f)", trkWork->getZ() + zShiftTrk, iLayer, trkWork->getEta()); } continue; } // determine chamber(s) to be searched for tracklets - FindChambersInRoad(trkWork, roadY, roadZ, iLayer, det, zMaxTRD, prop->getAlpha()); + FindChambersInRoad(trkWork, roadY, roadZ, iLayer, det, zMaxTRD, prop->getAlpha(), zShiftTrk); // track debug information to be stored in case no matching tracklet can be found mDebug->SetTrackParameter(*trkWork, iLayer); @@ -732,99 +673,69 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK if (currDet == -1) { continue; } + pad = mGeo->GetPadPlane(currDet); int currSec = mGeo->GetSector(currDet); if (currSec != GetSector(prop->getAlpha())) { if (!prop->rotate(GetAlphaOfSector(currSec))) { if (ENABLE_WARNING) { - Warning("FollowProlongation", "Track could not be rotated in tracklet coordinate system"); + GPUWarning("Track could not be rotated in tracklet coordinate system"); } break; } } if (currSec != GetSector(prop->getAlpha())) { - Error("FollowProlongation", "Track is in sector %i and sector %i is searched for tracklets", GetSector(prop->getAlpha()), currSec); + GPUError("Track is in sector %i and sector %i is searched for tracklets", GetSector(prop->getAlpha()), currSec); continue; } // propagate track to radius of chamber if (!prop->propagateToX(mR[currDet], .8f, .2f)) { if (ENABLE_WARNING) { - Warning("FollowProlongation", "Track parameter for track %i, x=%f at chamber %i x=%f in layer %i cannot be retrieved", iTrack, trkWork->getX(), currDet, mR[currDet], iLayer); + GPUWarning("Track parameter for track %i, x=%f at chamber %i x=%f in layer %i cannot be retrieved", iTrk, trkWork->getX(), currDet, mR[currDet], iLayer); } } // first propagate track to x of tracklet - for (int trkltIdx = mTrackletIndexArray[trkltIdxOffset + currDet]; trkltIdx < mTrackletIndexArray[trkltIdxOffset + currDet + 1]; ++trkltIdx) { - if (CAMath::Abs(trkWork->getY() - mSpacePoints[trkltIdx].mX[0]) > roadY || CAMath::Abs(trkWork->getZ() - mSpacePoints[trkltIdx].mX[1]) > roadZ) { + for (int trkltIdx = glbTrkltIdxOffset + mTrackletIndexArray[trkltIdxOffset + currDet]; trkltIdx < glbTrkltIdxOffset + mTrackletIndexArray[trkltIdxOffset + currDet + 1]; ++trkltIdx) { + if (CAMath::Abs(trkWork->getY() - spacePoints[trkltIdx].getY()) > roadY || CAMath::Abs(trkWork->getZ() + zShiftTrk - spacePoints[trkltIdx].getZ()) > roadZ) { // skip tracklets which are too far away // although the radii of space points and tracks may differ by ~ few mm the roads are large enough to allow no efficiency loss by this cut continue; } float projY, projZ; - prop->getPropagatedYZ(mSpacePoints[trkltIdx].mR, projY, projZ); - // correction for tilted pads (only applied if deltaZ < l_pad && track z err << l_pad) - float tiltCorr = tilt * (mSpacePoints[trkltIdx].mX[1] - projZ); - float l_pad = pad->GetRowSize(mTracklets[trkltIdx].GetZbin()); - if (!((CAMath::Abs(mSpacePoints[trkltIdx].mX[1] - projZ) < l_pad) && (trkWork->getSigmaZ2() < (l_pad * l_pad / 12.f)))) { - tiltCorr = 0.f; + prop->getPropagatedYZ(spacePoints[trkltIdx].getX(), projY, projZ); + // correction for tilted pads (only applied if deltaZ < lPad && track z err << lPad) + float tiltCorr = tilt * (spacePoints[trkltIdx].getZ() - projZ); + float lPad = pad->GetRowSize(tracklets[trkltIdx].GetZbin()); + if (!((CAMath::Abs(spacePoints[trkltIdx].getZ() - projZ) < lPad) && (trkWork->getSigmaZ2() < (lPad * lPad / 12.f)))) { + tiltCorr = 0.f; // will be zero also for TPC tracks which are shifted in z } // correction for mean z position of tracklet (is not the center of the pad if track eta != 0) - float zPosCorr = mSpacePoints[trkltIdx].mX[1] + mZCorrCoefNRC * trkWork->getTgl(); - float yPosCorr = mSpacePoints[trkltIdx].mX[0] - tiltCorr; + float zPosCorr = spacePoints[trkltIdx].getZ() + mZCorrCoefNRC * trkWork->getTgl(); + float yPosCorr = spacePoints[trkltIdx].getY() - tiltCorr; + zPosCorr -= zShiftTrk; // shift tracklet instead of track in order to avoid having to do a re-fit for each collision float deltaY = yPosCorr - projY; float deltaZ = zPosCorr - projZ; My_Float trkltPosTmpYZ[2] = {yPosCorr, zPosCorr}; My_Float trkltCovTmp[3] = {0.f}; if ((CAMath::Abs(deltaY) < roadY) && (CAMath::Abs(deltaZ) < roadZ)) { // TODO: check if this is still necessary after the cut before propagation of track // tracklet is in windwow: get predicted chi2 for update and store tracklet index if best guess - RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(mTracklets[trkltIdx].GetZbin()), trkltCovTmp); + RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(tracklets[trkltIdx].GetZbin()), trkltCovTmp); float chi2 = prop->getPredictedChi2(trkltPosTmpYZ, trkltCovTmp); - // GPUInfo("layer %i: chi2 = %f", iLayer, chi2); - if (chi2 < Param().rec.trdMaxChi2 && CAMath::Abs(GetAngularPull(mSpacePoints[trkltIdx].mDy, trkWork->getSnp())) < 4) { - Hypothesis hypo(trkWork->GetNlayers(), iCandidate, trkltIdx, trkWork->GetChi2() + chi2); + // TODO cut on angular pull should be made stricter when proper v-drift calibration for the TRD tracklets is implemented + if (chi2 < Param().rec.trd.maxChi2 && CAMath::Abs(GetAngularPull(spacePoints[trkltIdx].getDy(), trkWork->getSnp())) < 4) { + Hypothesis hypo(trkWork->getNlayersFindable(), iCandidate, trkltIdx, trkWork->getChi2() + chi2); InsertHypothesis(hypo, nCurrHypothesis, hypothesisIdxOffset); - } // end tracklet chi2 < Param().rec.trdMaxChi2 + } // end tracklet chi2 < Param().rec.trd.maxChi2 } // end tracklet in window } // tracklet loop } // chamber loop // add no update to hypothesis list - Hypothesis hypoNoUpdate(trkWork->GetNlayers(), iCandidate, -1, trkWork->GetChi2() + Param().rec.trdPenaltyChi2); + Hypothesis hypoNoUpdate(trkWork->getNlayersFindable(), iCandidate, -1, trkWork->getChi2() + Param().rec.trd.penaltyChi2); InsertHypothesis(hypoNoUpdate, nCurrHypothesis, hypothesisIdxOffset); isOK = true; } // end candidate loop -#ifdef ENABLE_GPUMC - // in case matching tracklet exists in this layer -> store position information for debugging FIXME: does not yet work for time frames in o2, but here we anyway do not yet have MC labels... - if (matchAvailableAll[iLayer].size() > 0 && mDebugOutput) { - mDebug->SetNmatchAvail(matchAvailableAll[iLayer].size(), iLayer); - int realTrkltId = matchAvailableAll[iLayer].at(0); - int realTrkltDet = mTracklets[realTrkltId].GetDetector(); - prop->rotate(GetAlphaOfSector(mGeo->GetSector(realTrkltDet))); - if (!prop->propagateToX(mSpacePoints[realTrkltId].mR, .8f, 2.f) || GetSector(prop->getAlpha()) != mGeo->GetSector(realTrkltDet)) { - if (ENABLE_WARNING) { - Warning("FollowProlongation", "Track parameter at x=%f for track %i at real tracklet x=%f in layer %i cannot be retrieved (pt=%f)", trkWork->getX(), iTrack, mSpacePoints[realTrkltId].mR, iLayer, trkWork->getPt()); - } - } else { - // track could be propagated, rotated and is in the same sector as the MC matching tracklet - mDebug->SetTrackParameterReal(*trkWork, iLayer); - float zPosCorrReal = mSpacePoints[realTrkltId].mX[1] + mZCorrCoefNRC * trkWork->getTgl(); - float deltaZReal = zPosCorrReal - trkWork->getZ(); - float tiltCorrReal = tilt * (mSpacePoints[realTrkltId].mX[1] - trkWork->getZ()); - float l_padReal = pad->GetRowSize(mTracklets[realTrkltId].GetZbin()); - if ((trkWork->getSigmaZ2() >= (l_padReal * l_padReal / 12.f)) || (CAMath::Abs(mSpacePoints[realTrkltId].mX[1] - trkWork->getZ()) >= l_padReal)) { - tiltCorrReal = 0; - } - My_Float yzPosReal[2] = {mSpacePoints[realTrkltId].mX[0] - tiltCorrReal, zPosCorrReal}; - My_Float covReal[3] = {0.}; - RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(mTracklets[realTrkltId].GetZbin()), covReal); - mDebug->SetChi2Real(prop->getPredictedChi2(yzPosReal, covReal), iLayer); - mDebug->SetRawTrackletPositionReal(mSpacePoints[realTrkltId].mR, mSpacePoints[realTrkltId].mX, iLayer); - mDebug->SetCorrectedTrackletPositionReal(yzPosReal, iLayer); - mDebug->SetTrackletPropertiesReal(mTracklets[realTrkltId].GetDetector(), iLayer); - } - } -#endif - // - mDebug->SetChi2Update(mHypothesis[0 + hypothesisIdxOffset].mChi2 - t->GetChi2(), iLayer); // only meaningful for ONE candidate!!! + mDebug->SetChi2Update(mHypothesis[0 + hypothesisIdxOffset].mChi2 - t->getChi2(), iLayer); // only meaningful for ONE candidate!!! mDebug->SetRoad(roadY, roadZ, iLayer); // only meaningful for ONE candidate bool wasTrackStored = false; // -------------------------------------------------------------------------------- @@ -838,12 +749,9 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK if (mHypothesis[iUpdate + hypothesisIdxOffset].mCandidateId == -1) { // no more candidates if (iUpdate == 0) { - if (ENABLE_WARNING) { - Warning("FollowProlongation", "No valid candidates for track %i in layer %i", iTrack, iLayer); - } - nCandidates = 0; + return false; // no valid candidates for this track (probably propagation failed) } - break; + break; // go to next layer } nCandidates = iUpdate + 1; if (mNCandidates > 1) { @@ -852,11 +760,11 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK } if (mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId == -1) { // no matching tracklet found - if (trkWork->GetIsFindable(iLayer)) { - if (trkWork->GetNmissingConsecLayers(iLayer) > Param().rec.trdStopTrkAfterNMissLy) { - trkWork->SetIsStopped(); + if (trkWork->getIsFindable(iLayer)) { + if (trkWork->getNmissingConsecLayers(iLayer) > Param().rec.trd.stopTrkAfterNMissLy) { + trkWork->setIsStopped(); } - trkWork->SetChi2(trkWork->GetChi2() + Param().rec.trdPenaltyChi2); + trkWork->setChi2(trkWork->getChi2() + Param().rec.trd.penaltyChi2); } if (iUpdate == 0 && mNCandidates > 1) { // TODO: is thie really necessary????? CHECK! *t = mCandidates[2 * iUpdate + nextIdx]; @@ -867,19 +775,19 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK if (mNCandidates > 1) { prop->setTrack(trkWork); } - int trkltSec = mGeo->GetSector(mTracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()); + int trkltSec = mGeo->GetSector(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()); if (trkltSec != GetSector(prop->getAlpha())) { // if after a matching tracklet was found another sector was searched for tracklets the track needs to be rotated back prop->rotate(GetAlphaOfSector(trkltSec)); } - if (!prop->propagateToX(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mR, .8f, 2.f)) { + if (!prop->propagateToX(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getX(), .8f, 2.f)) { if (ENABLE_WARNING) { - Warning("FollowProlongation", "Final track propagation for track %i update %i in layer %i failed", iTrack, iUpdate, iLayer); + GPUWarning("Final track propagation for track %i update %i in layer %i failed", iTrk, iUpdate, iLayer); } - trkWork->SetChi2(trkWork->GetChi2() + Param().rec.trdPenaltyChi2); - if (trkWork->GetIsFindable(iLayer)) { - if (trkWork->GetNmissingConsecLayers(iLayer) >= Param().rec.trdStopTrkAfterNMissLy) { - trkWork->SetIsStopped(); + trkWork->setChi2(trkWork->getChi2() + Param().rec.trd.penaltyChi2); + if (trkWork->getIsFindable(iLayer)) { + if (trkWork->getNmissingConsecLayers(iLayer) >= Param().rec.trd.stopTrkAfterNMissLy) { + trkWork->setIsStopped(); } } if (iUpdate == 0 && mNCandidates > 1) { @@ -888,21 +796,23 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK continue; } - float tiltCorrUp = tilt * (mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mX[1] - trkWork->getZ()); - float zPosCorrUp = mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mX[1] + mZCorrCoefNRC * trkWork->getTgl(); - float l_padTrklt = pad->GetRowSize(mTracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()); - if (!((trkWork->getSigmaZ2() < (l_padTrklt * l_padTrklt / 12.f)) && (CAMath::Abs(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mX[1] - trkWork->getZ()) < l_padTrklt))) { + pad = mGeo->GetPadPlane(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()); + float tiltCorrUp = tilt * (spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ() - trkWork->getZ()); + float zPosCorrUp = spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ() + mZCorrCoefNRC * trkWork->getTgl(); + zPosCorrUp -= zShiftTrk; + float padLength = pad->GetRowSize(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()); + if (!((trkWork->getSigmaZ2() < (padLength * padLength / 12.f)) && (CAMath::Abs(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ() - trkWork->getZ()) < padLength))) { tiltCorrUp = 0.f; } - My_Float trkltPosUp[2] = {mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mX[0] - tiltCorrUp, zPosCorrUp}; + My_Float trkltPosUp[2] = {spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getY() - tiltCorrUp, zPosCorrUp}; My_Float trkltCovUp[3] = {0.f}; - RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(mTracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()), trkltCovUp); + RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()), trkltCovUp); #ifdef ENABLE_GPUTRDDEBUG prop->setTrack(&trackNoUp); prop->rotate(GetAlphaOfSector(trkltSec)); - //prop->propagateToX(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mR, .8f, 2.f); - prop->propagateToX(mR[mTracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()], .8f, 2.f); + //prop->propagateToX(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getX(), .8f, 2.f); + prop->propagateToX(mR[tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()], .8f, 2.f); prop->setTrack(trkWork); #endif @@ -911,21 +821,21 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK mDebug->SetTrackParameterNoUp(trackNoUp, iLayer); #endif mDebug->SetTrackParameter(*trkWork, iLayer); - mDebug->SetRawTrackletPosition(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mR, mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mX, iLayer); + mDebug->SetRawTrackletPosition(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getX(), spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getY(), spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ(), iLayer); mDebug->SetCorrectedTrackletPosition(trkltPosUp, iLayer); - mDebug->SetTrackletCovariance(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mCov, iLayer); - mDebug->SetTrackletProperties(mSpacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].mDy, mTracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector(), iLayer); + mDebug->SetTrackletCovariance(trkltCovUp, iLayer); + mDebug->SetTrackletProperties(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getDy(), tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector(), iLayer); wasTrackStored = true; } if (!prop->update(trkltPosUp, trkltCovUp)) { if (ENABLE_WARNING) { - Warning("FollowProlongation", "Failed to update track %i with space point in layer %i", iTrack, iLayer); + GPUWarning("Failed to update track %i with space point in layer %i", iTrk, iLayer); } - trkWork->SetChi2(trkWork->GetChi2() + Param().rec.trdPenaltyChi2); - if (trkWork->GetIsFindable(iLayer)) { - if (trkWork->GetNmissingConsecLayers(iLayer) >= Param().rec.trdStopTrkAfterNMissLy) { - trkWork->SetIsStopped(); + trkWork->setChi2(trkWork->getChi2() + Param().rec.trd.penaltyChi2); + if (trkWork->getIsFindable(iLayer)) { + if (trkWork->getNmissingConsecLayers(iLayer) >= Param().rec.trd.stopTrkAfterNMissLy) { + trkWork->setIsStopped(); } } if (iUpdate == 0 && mNCandidates > 1) { @@ -935,13 +845,14 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK } if (!trkWork->CheckNumericalQuality()) { if (ENABLE_INFO) { - GPUInfo("FollowProlongation: Track %i has invalid covariance matrix. Aborting track following\n", iTrack); + GPUInfo("Track %i has invalid covariance matrix. Aborting track following\n", iTrk); } return false; } - trkWork->AddTracklet(iLayer, mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId); - trkWork->SetChi2(mHypothesis[iUpdate + hypothesisIdxOffset].mChi2); - trkWork->SetIsFindable(iLayer); + trkWork->addTracklet(iLayer, mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId); + trkWork->setChi2(mHypothesis[iUpdate + hypothesisIdxOffset].mChi2); + trkWork->setIsFindable(iLayer); + trkWork->setCollisionId(collisionId); if (iUpdate == 0 && mNCandidates > 1) { *t = mCandidates[2 * iUpdate + nextIdx]; } @@ -949,7 +860,7 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK if (!isOK) { if (ENABLE_INFO) { - GPUInfo("FollowProlongation: Track %i cannot be followed. Stopped in layer %i", iTrack, iLayer); + GPUInfo("Track %i cannot be followed. Stopped in layer %i", iTrk, iLayer); } return false; } @@ -960,82 +871,20 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::FollowProlongation(PROP* prop, TRDTRK // and store full track information // -------------------------------------------------------------------------------- if (mDebugOutput) { - int update[6] = {0}; - if (!mMCEvent) { - for (int iLy = 0; iLy < kNLayers; iLy++) { - if (t->GetTracklet(iLy) != -1) { - update[iLy] = 1; - } - } - } else { - // for MC: check attached tracklets (match, related, fake) - int nRelated = 0; - int nMatching = 0; - int nFake = 0; - for (int iLy = 0; iLy < kNLayers; iLy++) { - if (t->GetTracklet(iLy) != -1) { - int lbTracklet; - for (int il = 0; il < 3; il++) { - if ((lbTracklet = mSpacePoints[t->GetTracklet(iLy)].mLabel[il]) < 0) { - // no more valid labels - continue; - } - if (lbTracklet == CAMath::Abs(trackID)) { - update[iLy] = 1 + il; - nMatching++; - break; - } - } -#ifdef ENABLE_GPUMC - if (update[iLy] < 1 && mMCEvent) { - // no exact match, check in related labels - bool isRelated = false; - for (int il = 0; il < 3; il++) { - if (isRelated) { - break; - } - if ((lbTracklet = mSpacePoints[t->GetTracklet(iLy)].mLabel[il]) < 0) { - // no more valid labels - continue; - } - AliMCParticle* mcPart = (AliMCParticle*)mMCEvent->GetTrack(lbTracklet); - while (mcPart) { - int motherPart = mcPart->GetMother(); - if (motherPart == CAMath::Abs(trackID)) { - update[iLy] = 4 + il; - nRelated++; - isRelated = true; - break; - } - mcPart = motherPart >= 0 ? (AliMCParticle*)mMCEvent->GetTrack(motherPart) : 0; - } - } - } -#endif - if (update[iLy] < 1) { - update[iLy] = 9; - nFake++; - } - } - } - mDebug->SetTrackProperties(nMatching, nFake, nRelated); -#ifdef ENABLE_GPUMC - AliMCParticle* mcPartDbg = (AliMCParticle*)mMCEvent->GetTrack(trackID); - if (mcPartDbg) { - mDebug->SetMCinfo(mcPartDbg->Xv(), mcPartDbg->Yv(), mcPartDbg->Zv(), mcPartDbg->PdgCode()); - } -#endif - } mDebug->SetTrack(*t); - mDebug->SetUpdates(update); mDebug->Output(); } - //GPUInfo("Ended track following for track %i at x=%f with pt=%f", t->GetTPCtrackId(), t->getX(), t->getPt()); - //GPUInfo("Attached %i tracklets", t->GetNtracklets()); + if (ENABLE_INFO) { + GPUInfo("Ended track following for track %i at x=%f with pt=%f. Attached %i tracklets", t->getRefGlobalTrackIdRaw(), t->getX(), t->getPt(), t->getNtracklets()); + } + if (nCurrHypothesis > 1) { + if (CAMath::Abs(mHypothesis[hypothesisIdxOffset + 1].GetReducedChi2() - mHypothesis[hypothesisIdxOffset].GetReducedChi2()) < Param().rec.trd.chi2SeparationCut) { + t->setIsAmbiguous(); + } + } return true; } - template <class TRDTRK, class PROP> GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::InsertHypothesis(Hypothesis hypo, int& nCurrHypothesis, int idxOffset) { @@ -1112,7 +961,7 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::AdjustSector(PROP* prop, TRDTRK* t) c if (CAMath::Abs(y) > 2.f * yMax) { if (ENABLE_INFO) { - Info("AdjustSector", "Track %i with pT = %f crossing two sector boundaries at x = %f", t->GetTPCtrackId(), t->getPt(), t->getX()); + GPUInfo("AdjustSector: Track %i with pT = %f crossing two sector boundaries at x = %f", t->getRefGlobalTrackIdRaw(), t->getPt(), t->getX()); } return false; } @@ -1124,10 +973,10 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::AdjustSector(PROP* prop, TRDTRK* t) c } int sign = (y > 0) ? 1 : -1; float alphaNew = alphaCurr + alpha * sign; - if (alphaNew > M_PI) { - alphaNew -= 2 * M_PI; - } else if (alphaNew < -M_PI) { - alphaNew += 2 * M_PI; + if (alphaNew > CAMath::Pi()) { + alphaNew -= 2 * CAMath::Pi(); + } else if (alphaNew < -CAMath::Pi()) { + alphaNew += 2 * CAMath::Pi(); } if (!prop->rotate(alphaNew)) { return false; @@ -1148,11 +997,11 @@ GPUd() int GPUTRDTracker_t<TRDTRK, PROP>::GetSector(float alpha) const // TRD sector number for reference system alpha //-------------------------------------------------------------------- if (alpha < 0) { - alpha += 2.f * M_PI; - } else if (alpha >= 2.f * M_PI) { - alpha -= 2.f * M_PI; + alpha += 2.f * CAMath::Pi(); + } else if (alpha >= 2.f * CAMath::Pi()) { + alpha -= 2.f * CAMath::Pi(); } - return (int)(alpha * kNSectors / (2.f * M_PI)); + return (int)(alpha * kNSectors / (2.f * CAMath::Pi())); } template <class TRDTRK, class PROP> @@ -1161,9 +1010,9 @@ GPUd() float GPUTRDTracker_t<TRDTRK, PROP>::GetAlphaOfSector(const int sec) cons //-------------------------------------------------------------------- // rotation angle for TRD sector sec //-------------------------------------------------------------------- - float alpha = 2.0f * M_PI / (float)kNSectors * ((float)sec + 0.5f); - if (alpha > M_PI) { - alpha -= 2 * M_PI; + float alpha = 2.0f * CAMath::Pi() / (float)kNSectors * ((float)sec + 0.5f); + if (alpha > CAMath::Pi()) { + alpha -= 2 * CAMath::Pi(); } return alpha; } @@ -1196,7 +1045,7 @@ GPUd() float GPUTRDTracker_t<TRDTRK, PROP>::GetAngularPull(float dYtracklet, flo } template <class TRDTRK, class PROP> -GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, const float roadY, const float roadZ, const int iLayer, int* det, const float zMax, const float alpha) const +GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, const float roadY, const float roadZ, const int iLayer, int* det, const float zMax, const float alpha, const float zShiftTrk) const { //-------------------------------------------------------------------- // determine initial chamber where the track ends up @@ -1205,13 +1054,15 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, c //-------------------------------------------------------------------- const float yMax = CAMath::Abs(mGeo->GetCol0(iLayer)); + float zTrk = t->getZ() + zShiftTrk; - int currStack = mGeo->GetStack(t->getZ(), iLayer); + int currStack = mGeo->GetStack(zTrk, iLayer); int currSec = GetSector(alpha); int currDet; int nDets = 0; + if (currStack > -1) { // chamber unambiguous currDet = mGeo->GetDetector(iLayer, currStack, currSec); @@ -1219,16 +1070,16 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, c const GPUTRDpadPlane* pp = mGeo->GetPadPlane(iLayer, currStack); int lastPadRow = mGeo->GetRowMax(iLayer, currStack, 0); float zCenter = pp->GetRowPos(lastPadRow / 2); - if ((t->getZ() + roadZ) > pp->GetRow0() || (t->getZ() - roadZ) < pp->GetRowEnd()) { - int addStack = t->getZ() > zCenter ? currStack - 1 : currStack + 1; + if ((zTrk + roadZ) > pp->GetRow0() || (zTrk - roadZ) < pp->GetRowEnd()) { + int addStack = zTrk > zCenter ? currStack - 1 : currStack + 1; if (addStack < kNStacks && addStack > -1) { det[nDets++] = mGeo->GetDetector(iLayer, addStack, currSec); } } } else { - if (CAMath::Abs(t->getZ()) > zMax) { + if (CAMath::Abs(zTrk) > zMax) { // shift track in z so it is in the TRD acceptance - if (t->getZ() > 0) { + if (zTrk > 0) { currDet = mGeo->GetDetector(iLayer, 0, currSec); } else { currDet = mGeo->GetDetector(iLayer, kNStacks - 1, currSec); @@ -1238,11 +1089,11 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, c } else { // track in between two stacks, add both surrounding chambers // gap between two stacks is 4 cm wide - currDet = GetDetectorNumber(t->getZ() + 4.0f, alpha, iLayer); + currDet = GetDetectorNumber(zTrk + 4.0f, alpha, iLayer); if (currDet != -1) { det[nDets++] = currDet; } - currDet = GetDetectorNumber(t->getZ() - 4.0f, alpha, iLayer); + currDet = GetDetectorNumber(zTrk - 4.0f, alpha, iLayer); if (currDet != -1) { det[nDets++] = currDet; } @@ -1271,14 +1122,16 @@ GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::FindChambersInRoad(const TRDTRK* t, c } template <class TRDTRK, class PROP> -GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::IsGeoFindable(const TRDTRK* t, const int layer, const float alpha) const +GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::IsGeoFindable(const TRDTRK* t, const int layer, const float alpha, const float zShiftTrk) const { //-------------------------------------------------------------------- // returns true if track position inside active area of the TRD // and not too close to the boundaries //-------------------------------------------------------------------- - int det = GetDetectorNumber(t->getZ(), alpha, layer); + float zTrk = t->getZ() + zShiftTrk; + + int det = GetDetectorNumber(zTrk, alpha, layer); // reject tracks between stacks if (det < 0) { @@ -1303,36 +1156,22 @@ GPUd() bool GPUTRDTracker_t<TRDTRK, PROP>::IsGeoFindable(const TRDTRK* t, const return false; } // reject tracks closer than epsZ cm to stack boundary - if (!((t->getZ() > zMin + epsZ) && (t->getZ() < zMax - epsZ))) { + if (!((zTrk > zMin + epsZ) && (zTrk < zMax - epsZ))) { return false; } return true; } -template <class TRDTRK, class PROP> -GPUd() void GPUTRDTracker_t<TRDTRK, PROP>::SetNCollisions(int nColl) -{ - // Set the number of collisions for a given time frame. - // The number is taken from the TRD trigger records - if (nColl < mNMaxCollisions) { - mNCollisions = nColl; - } else { - GPUError("Cannot process more than %i collisions. The last %i collisions will be dropped", mNMaxCollisions, nColl - mNMaxCollisions); - mNCollisions = mNMaxCollisions; - } -} #ifndef GPUCA_GPUCODE namespace GPUCA_NAMESPACE { namespace gpu { -#if !defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE) -// instantiate version for non-GPU data types +// instantiate version for AliExternalTrackParam / o2::TrackParCov data types template class GPUTRDTracker_t<GPUTRDTrack, GPUTRDPropagator>; -#endif -// always instantiate version for GPU data types +// always instantiate version for GPU Track Model template class GPUTRDTracker_t<GPUTRDTrackGPU, GPUTRDPropagatorGPU>; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h index 02739fbdad80b..a7237dd71c2a2 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,21 +17,19 @@ #ifndef GPUTRDTRACKER_H #define GPUTRDTRACKER_H - #include "GPUCommonDef.h" #include "GPUProcessor.h" #include "GPUTRDDef.h" #include "GPUDef.h" #include "GPUTRDTrack.h" +#include "GPUTRDSpacePoint.h" #include "GPULogging.h" +#include "GPUTRDInterfaces.h" #ifndef GPUCA_GPUCODE_DEVICE #include <vector> #endif -class AliExternalTrackParam; -class AliMCEvent; - namespace GPUCA_NAMESPACE { namespace gpu @@ -66,7 +65,7 @@ class GPUTRDTracker_t : public GPUProcessor void* SetPointersTracklets(void* base); void* SetPointersTracks(void* base); - void CountMatches(const int trackID, std::vector<int>* matches) const; + void PrepareTracking(GPUChainTracking* chainTracking); void DoTracking(GPUChainTracking* chainTracking); void SetNCandidates(int n); void PrintSettings() const; @@ -79,21 +78,21 @@ class GPUTRDTracker_t : public GPUProcessor kNSectors = 18, kNChambers = 540 }; - // struct to hold the information on the space points - struct GPUTRDSpacePointInternal { - float mR; // x position (3.5 mm above anode wires) - radial offset due to t0 mis-calibration, measured -1 mm for run 245353 - float mX[2]; // y and z position (sector coordinates) - My_Float mCov[3]; // sigma_y^2, sigma_yz, sigma_z^2 - float mDy; // deflection over drift length - int mId; // index - int mLabel[3]; // MC labels - unsigned short mVolumeId; // basically derived from TRD chamber number + struct HelperTrackAttributes { + // additional TRD track attributes which are transient + float mTime; // time estimate for seeding track in us + float mTimeAddMax; // max. time that can be added to this track seed in us + float mTimeSubMax; // max. time that can be subtracted to this track seed in us + short mSide; // -1 : A-side, +1 : C-side (relevant only for TPC-only tracks) + GPUd() float GetTimeMin() const { return mTime - mTimeSubMax; } + GPUd() float GetTimeMax() const { return mTime + mTimeAddMax; } + GPUd() HelperTrackAttributes() : mTime(-1.f), mTimeAddMax(0.f), mTimeSubMax(0.f), mSide(0) {} }; struct Hypothesis { int mLayers; // number of layers with TRD space point int mCandidateId; // to which track candidate the hypothesis belongs - int mTrackletId; // tracklet index to be used for update + int mTrackletId; // tracklet index to be used for update (global index within tracklet array) float mChi2; // predicted chi2 for given space point GPUd() float GetReducedChi2() { return mLayers > 0 ? mChi2 / mLayers : mChi2; } @@ -107,7 +106,6 @@ class GPUTRDTracker_t : public GPUProcessor GPUhd() void OverrideGPUGeometry(TRD_GEOMETRY_CONST GPUTRDGeometry* geo) { mGeo = geo; } void Reset(); - GPUd() int LoadTracklet(const GPUTRDTrackletWord& tracklet, const int* labels = nullptr); template <class T> GPUd() bool PreCheckTrackTRDCandidate(const T& trk) const { @@ -115,12 +113,13 @@ class GPUTRDTracker_t : public GPUProcessor } GPUd() bool PreCheckTrackTRDCandidate(const GPUTPCGMMergedTrack& trk) const { return trk.OK() && !trk.Looper(); } GPUd() bool CheckTrackTRDCandidate(const TRDTRK& trk) const; - GPUd() int LoadTrack(const TRDTRK& trk, const int label = -1, const int* nTrkltsOffline = nullptr, const int labelOffline = -1, int tpcTrackId = -1, bool checkTrack = true); + GPUd() int LoadTrack(const TRDTRK& trk, unsigned int tpcTrackId, bool checkTrack = true, HelperTrackAttributes* attribs = nullptr); - GPUd() int GetCollisionID(float trkTime) const; + GPUd() int GetCollisionIDs(int iTrk, int* collisionIds) const; GPUd() void DoTrackingThread(int iTrk, int threadId = 0); + static GPUd() bool ConvertTrkltToSpacePoint(const GPUTRDGeometry& geo, GPUTRDTrackletWord& trklt, GPUTRDSpacePoint& sp); GPUd() bool CalculateSpacePoints(int iCollision = 0); - GPUd() bool FollowProlongation(PROP* prop, TRDTRK* t, int threadId, int collisionId); + GPUd() bool FollowProlongation(PROP* prop, TRDTRK* t, int iTrk, int threadId, int collisionId); GPUd() int GetDetectorNumber(const float zPos, const float alpha, const int layer) const; GPUd() bool AdjustSector(PROP* prop, TRDTRK* t) const; GPUd() int GetSector(float alpha) const; @@ -130,29 +129,20 @@ class GPUTRDTracker_t : public GPUProcessor GPUd() float ConvertAngleToDy(float snp) const { return mAngleToDyA + mAngleToDyB * snp + mAngleToDyC * snp * snp; } // a + b*snp + c*snp^2 is more accurate than sin(phi) = (dy / xDrift) / sqrt(1+(dy/xDrift)^2) GPUd() float GetAngularPull(float dYtracklet, float snp) const; GPUd() void RecalcTrkltCov(const float tilt, const float snp, const float rowSize, My_Float (&cov)[3]); - GPUd() void CheckTrackRefs(const int trackID, bool* findableMC) const; - GPUd() void FindChambersInRoad(const TRDTRK* t, const float roadY, const float roadZ, const int iLayer, int* det, const float zMax, const float alpha) const; - GPUd() bool IsGeoFindable(const TRDTRK* t, const int layer, const float alpha) const; - GPUd() void SwapTracklets(const int left, const int right); - GPUd() int PartitionTracklets(const int left, const int right); - GPUd() void Quicksort(const int left, const int right, const int size); + GPUd() void FindChambersInRoad(const TRDTRK* t, const float roadY, const float roadZ, const int iLayer, int* det, const float zMax, const float alpha, const float zShiftTrk) const; + GPUd() bool IsGeoFindable(const TRDTRK* t, const int layer, const float alpha, const float zShiftTrk) const; GPUd() void InsertHypothesis(Hypothesis hypo, int& nCurrHypothesis, int idxOffset); - // input from TRD trigger record - GPUd() void SetNMaxCollisions(int nColl) { mNMaxCollisions = nColl; } // can this be fixed to a sufficiently large value? - GPUd() void SetNCollisions(int nColl); - GPUd() void SetTriggerRecordIndices(int* indices) { mTriggerRecordIndices = indices; } - GPUd() void SetTriggerRecordTimes(float* times) { mTriggerRecordTimes = times; } // settings - GPUd() void SetProcessPerTimeFrame() { mProcessPerTimeFrame = true; } - GPUd() void SetMCEvent(AliMCEvent* mc) { mMCEvent = mc; } + GPUd() void SetGenerateSpacePoints(bool flag) { mGenerateSpacePoints = flag; } + GPUd() void SetProcessPerTimeFrame(bool flag) { mProcessPerTimeFrame = flag; } GPUd() void EnableDebugOutput() { mDebugOutput = true; } GPUd() void SetMaxEta(float maxEta) { mMaxEta = maxEta; } GPUd() void SetExtraRoadY(float extraRoadY) { mExtraRoadY = extraRoadY; } GPUd() void SetRoadZ(float roadZ) { mRoadZ = roadZ; } + GPUd() void SetTPCVdrift(float vDrift) { mTPCVdrift = vDrift; } - GPUd() AliMCEvent* GetMCEvent() const { return mMCEvent; } GPUd() bool GetIsDebugOutputOn() const { return mDebugOutput; } GPUd() float GetMaxEta() const { return mMaxEta; } GPUd() int GetNCandidates() const { return mNCandidates; } @@ -161,16 +151,20 @@ class GPUTRDTracker_t : public GPUProcessor // output GPUd() int NTracks() const { return mNTracks; } + GPUd() GPUTRDSpacePoint* SpacePoints() const { return mSpacePoints; } GPUd() TRDTRK* Tracks() const { return mTracks; } - GPUd() int NTracklets() const { return mNTracklets; } - GPUd() GPUTRDSpacePointInternal* SpacePoints() const { return mSpacePoints; } - GPUd() GPUTRDTrackletWord* Tracklets() const { return mTracklets; } GPUd() void DumpTracks(); + // utility + GPUd() const typename PROP::propagatorParam* getPropagatorParam(); + protected: float* mR; // radial position of each TRD chamber, alignment taken into account, radial spread within chambers < 7mm bool mIsInitialized; // flag is set upon initialization - bool mProcessPerTimeFrame; // if true, tracking is done per time frame instead of on a single events basis //FIXME is this needed?? + bool mGenerateSpacePoints; // if true, only tracklets are provided as input and they will be converted into space points by the tracker + bool mProcessPerTimeFrame; // if true, tracking is done per time frame instead of on a single events basis + short mNAngleHistogramBins; // number of bins per chamber for the angular difference histograms + float mAngleHistogramRange; // range of impact angles covered by each histogram short mMemoryPermanent; // size of permanent memory for the tracker short mMemoryTracklets; // size of memory for TRD tracklets short mMemoryTracks; // size of memory for tracks (used for i/o) @@ -178,20 +172,18 @@ class GPUTRDTracker_t : public GPUProcessor int mNMaxTracks; // max number of tracks the tracker can handle (per event) int mNMaxSpacePoints; // max number of space points hold by the tracker (per event) TRDTRK* mTracks; // array of trd-updated tracks + HelperTrackAttributes* mTrackAttribs; // array with additional (transient) track attributes int mNCandidates; // max. track hypothesis per layer - int mNCollisions; // number of collisions with TRD tracklet data int mNTracks; // number of TPC tracks to be matched int mNEvents; // number of processed events - int* mTriggerRecordIndices; // index of first tracklet for each collision - float* mTriggerRecordTimes; // time in us for each collision - GPUTRDTrackletWord* mTracklets; // array of all tracklets, later sorted by HCId int mMaxThreads; // maximum number of supported threads - int mNTracklets; // total number of tracklets in event - int* mTrackletIndexArray; // index of first tracklet for each chamber, last entry is the total amount of tracklets + // index of first tracklet for each chamber within tracklets array, last entry is total number of tracklets for given collision + // the array has (kNChambers + 1) * numberOfCollisions entries + // note, that for collision iColl one has to add an offset corresponding to the index of the first tracklet of iColl to the index stored in mTrackletIndexArray + int* mTrackletIndexArray; Hypothesis* mHypothesis; // array with multiple track hypothesis TRDTRK* mCandidates; // array of tracks for multiple hypothesis tracking - GPUTRDSpacePointInternal* mSpacePoints; // array with tracklet coordinates in global tracking frame - int* mTrackletLabels; // array with MC tracklet labels + GPUTRDSpacePoint* mSpacePoints; // array with tracklet coordinates in global tracking frame TRD_GEOMETRY_CONST GPUTRDGeometry* mGeo; // TRD geometry /// ---- error parametrization depending on magnetic field ---- float mRPhiA2; // parameterization for tracklet position resolution @@ -204,15 +196,14 @@ class GPUTRDTracker_t : public GPUProcessor float mAngleToDyB; // parameterization for conversion track angle -> tracklet deflection float mAngleToDyC; // parameterization for conversion track angle -> tracklet deflection /// ---- end error parametrization ---- - bool mDebugOutput; // store debug output - float mTimeWindow; // max. deviation of the ITS-TPC track time w.r.t. TRD trigger record time stamp (in us, default is 100 ns) - float mRadialOffset; // due to mis-calibration of t0 - float mMaxEta; // TPC tracks with higher eta are ignored - float mExtraRoadY; // addition to search road in r-phi to account for not exact radial match of tracklets and tracks in first iteration - float mRoadZ; // in z, a constant search road is used - float mZCorrCoefNRC; // tracklet z-position depends linearly on track dip angle - AliMCEvent* mMCEvent; //! externaly supplied optional MC event - GPUTRDTrackerDebug<TRDTRK>* mDebug; // debug output + bool mDebugOutput; // store debug output + static CONSTEXPR float sRadialOffset GPUCA_CPP11_INIT(= -0.1f); // due to (possible) mis-calibration of t0 -> will become obsolete when tracklet conversion is done outside of the tracker + float mMaxEta; // TPC tracks with higher eta are ignored + float mExtraRoadY; // addition to search road in r-phi to account for not exact radial match of tracklets and tracks in first iteration + float mRoadZ; // in z, a constant search road is used + float mZCorrCoefNRC; // tracklet z-position depends linearly on track dip angle + float mTPCVdrift; // TPC drift velocity used for shifting TPC tracks along Z + GPUTRDTrackerDebug<TRDTRK>* mDebug; // debug output }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx index fcfdb62b13969..63cdf5ccb2886 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,6 +26,7 @@ #include "GPUTRDTracker.h" #include "GPUTRDTrack.h" #include "GPUTRDTrackerComponent.h" +#include "GPUTRDSpacePoint.h" #include "GPUTRDTrackletWord.h" #include "GPUTRDTrackletLabels.h" #include "AliHLTTRDDefinitions.h" @@ -182,8 +184,8 @@ int GPUTRDTrackerComponent::DoInit(int argc, const char** argv) iResult = ReadConfigurationString(arguments.Data()); - GPUSettingsEvent cfgEvent; - cfgEvent.solenoidBz = GetBz(); + GPUSettingsGRP cfgGRP; + cfgGRP.solenoidBz = GetBz(); GPUSettingsRec cfgRec; GPUSettingsProcessing cfgDeviceProcessing; GPURecoStepConfiguration cfgRecoStep; @@ -191,7 +193,7 @@ int GPUTRDTrackerComponent::DoInit(int argc, const char** argv) cfgRecoStep.inputs.clear(); cfgRecoStep.outputs.clear(); fRec = GPUReconstruction::CreateInstance("CPU", true); - fRec->SetSettings(&cfgEvent, &cfgRec, &cfgDeviceProcessing, &cfgRecoStep); + fRec->SetSettings(&cfgGRP, &cfgRec, &cfgDeviceProcessing, &cfgRecoStep); fChain = fRec->AddChain<GPUChainTracking>(); fGeo = new GPUTRDGeometry(); @@ -257,38 +259,37 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con int nBlocks = evtData.fBlockCnt; - AliHLTTracksData* tpcData = nullptr; - AliHLTTracksData* itsData = nullptr; - AliHLTTrackMCData* tpcDataMC = nullptr; + const AliHLTTracksData* tpcData = nullptr; + const AliHLTTracksData* itsData = nullptr; + const AliHLTTrackMCData* tpcDataMC = nullptr; std::vector<GPUTRDTrackGPU> tracksTPC; - std::vector<int> tracksTPCLab; std::vector<int> tracksTPCId; bool hasMCtracklets = false; int nTrackletsTotal = 0; int nTrackletsTotalMC = 0; - GPUTRDTrackletWord* tracklets = nullptr; - GPUTRDTrackletLabels* trackletsMC = nullptr; + const GPUTRDTrackletWord* tracklets = nullptr; + const GPUTRDTrackletLabels* trackletsMC = nullptr; for (int iBlock = 0; iBlock < nBlocks; iBlock++) { if (blocks[iBlock].fDataType == (kAliHLTDataTypeTrack | kAliHLTDataOriginITS) && fRequireITStrack) { - itsData = (AliHLTTracksData*)blocks[iBlock].fPtr; + itsData = (const AliHLTTracksData*)blocks[iBlock].fPtr; fBenchmark.AddInput(blocks[iBlock].fSize); } else if (blocks[iBlock].fDataType == (AliHLTTPCDefinitions::TracksOuterDataType() | kAliHLTDataOriginTPC)) { - tpcData = (AliHLTTracksData*)blocks[iBlock].fPtr; + tpcData = (const AliHLTTracksData*)blocks[iBlock].fPtr; fBenchmark.AddInput(blocks[iBlock].fSize); } else if (blocks[iBlock].fDataType == (kAliHLTDataTypeTrackMC | kAliHLTDataOriginTPC)) { - tpcDataMC = (AliHLTTrackMCData*)blocks[iBlock].fPtr; + tpcDataMC = (const AliHLTTrackMCData*)blocks[iBlock].fPtr; fBenchmark.AddInput(blocks[iBlock].fSize); } else if (blocks[iBlock].fDataType == (AliHLTTRDDefinitions::fgkTRDTrackletDataType)) { - tracklets = reinterpret_cast<GPUTRDTrackletWord*>(blocks[iBlock].fPtr); + tracklets = reinterpret_cast<const GPUTRDTrackletWord*>(blocks[iBlock].fPtr); nTrackletsTotal = blocks[iBlock].fSize / sizeof(GPUTRDTrackletWord); fBenchmark.AddInput(blocks[iBlock].fSize); } else if (blocks[iBlock].fDataType == (AliHLTTRDDefinitions::fgkTRDMCTrackletDataType)) { hasMCtracklets = true; - trackletsMC = reinterpret_cast<GPUTRDTrackletLabels*>(blocks[iBlock].fPtr); + trackletsMC = reinterpret_cast<const GPUTRDTrackletLabels*>(blocks[iBlock].fPtr); nTrackletsTotalMC = blocks[iBlock].fSize / sizeof(GPUTRDTrackletLabels); fBenchmark.AddInput(blocks[iBlock].fSize); } @@ -309,12 +310,18 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con return -EINVAL; } + // copy tracklets into temporary vector to allow for sorting them (the input array is const) + std::vector<GPUTRDTrackletWord> trackletsTmp(nTrackletsTotal); + for (int iTrklt = 0; iTrklt < nTrackletsTotal; ++iTrklt) { + trackletsTmp[iTrklt] = tracklets[iTrklt]; + } + int nTPCtracks = tpcData->fCount; std::vector<bool> itsAvail(nTPCtracks, false); if (itsData) { // look for ITS tracks with >= 2 hits int nITStracks = itsData->fCount; - AliHLTExternalTrackParam* currITStrack = itsData->fTracklets; + const AliHLTExternalTrackParam* currITStrack = itsData->fTracklets; for (int iTrkITS = 0; iTrkITS < nITStracks; iTrkITS++) { if (currITStrack->fNPoints >= 2) { itsAvail.at(currITStrack->fTrackID) = true; @@ -328,11 +335,11 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con // look for TPC track MC labels int nMCtracks = tpcDataMC->fCount; for (int iMC = 0; iMC < nMCtracks; iMC++) { - AliHLTTrackMCLabel& lab = tpcDataMC->fLabels[iMC]; + const AliHLTTrackMCLabel& lab = tpcDataMC->fLabels[iMC]; mcLabels[lab.fTrackID] = lab.fMCLabel; } } - AliHLTExternalTrackParam* currOutTrackTPC = tpcData->fTracklets; + const AliHLTExternalTrackParam* currOutTrackTPC = tpcData->fTracklets; for (int iTrk = 0; iTrk < nTPCtracks; iTrk++) { // store TPC tracks (if required only the ones with >=2 ITS hits) if (itsData != nullptr && !itsAvail.at(currOutTrackTPC->fTrackID)) { @@ -347,7 +354,6 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con } tracksTPC.push_back(t); tracksTPCId.push_back(currOutTrackTPC->fTrackID); - tracksTPCLab.push_back(mcLabel); unsigned int dSize = sizeof(AliHLTExternalTrackParam) + currOutTrackTPC->fNPoints * sizeof(unsigned int); currOutTrackTPC = (AliHLTExternalTrackParam*)+(((Byte_t*)currOutTrackTPC) + dSize); } @@ -356,37 +362,31 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con HLTInfo("TRDTrackerComponent received %i tracklets\n", nTrackletsTotal); } + fTracker->SetGenerateSpacePoints(true); fTracker->Reset(); fChain->mIOPtrs.nMergedTracks = tracksTPC.size(); fChain->mIOPtrs.nTRDTracklets = nTrackletsTotal; - fChain->AllocateIOMemory(); + fChain->mIOPtrs.nTRDTriggerRecords = 1; + char trigRecMaskDummy[1] = {1}; + fChain->mIOPtrs.trdTrigRecMask = &(trigRecMaskDummy[0]); fRec->PrepareEvent(); fRec->SetupGPUProcessor(fTracker, true); - // loop over all tracklets - for (int iTracklet = 0; iTracklet < nTrackletsTotal; ++iTracklet) { - if (!hasMCtracklets) { - if (fTracker->LoadTracklet(tracklets[iTracklet])) { - return -EINVAL; - } - } else { - if (fTracker->LoadTracklet(tracklets[iTracklet], trackletsMC[iTracklet].mLabel)) { - return -EINVAL; - } - } - } + std::sort(trackletsTmp.begin(), trackletsTmp.end()); + fChain->mIOPtrs.trdTracklets = &(trackletsTmp[0]); + // loop over all tracks for (unsigned int iTrack = 0; iTrack < tracksTPC.size(); ++iTrack) { - fTracker->LoadTrack(tracksTPC[iTrack], tracksTPCLab[iTrack]); + fTracker->LoadTrack(tracksTPC[iTrack], tracksTPCId[iTrack]); } fBenchmark.Start(1); - fTracker->DoTracking(NULL); + fTracker->DoTracking(fChain); fBenchmark.Stop(1); GPUTRDTrackGPU* trackArray = fTracker->Tracks(); int nTracks = fTracker->NTracks(); - GPUTRDTrackerGPU::GPUTRDSpacePointInternal* spacePoints = fTracker->SpacePoints(); + GPUTRDSpacePoint* spacePoints = fTracker->SpacePoints(); // TODO delete fTrackList since it only works for TObjects (or use compiler flag after tests with GPU track type) // for (int iTrack=0; iTrack<nTracks; ++iTrack) { @@ -412,10 +412,10 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con for (int iTrk = 0; iTrk < nTracks; ++iTrk) { GPUTRDTrackGPU& t = trackArray[iTrk]; - if (t.GetNtracklets() == 0) { + if (t.getNtracklets() == 0) { continue; } - assignedTracklets += t.GetNtracklets(); + assignedTracklets += t.getNtracklets(); GPUTRDTrackDataRecord& currOutTrack = outTracks->fTracks[outTracks->fCount]; t.ConvertTo(currOutTrack); outTracks->fCount++; @@ -458,16 +458,16 @@ int GPUTRDTrackerComponent::DoEvent(const AliHLTComponentEventData& evtData, con } for (int i = 0; i < nTrackletsTotal; ++i) { - const GPUTRDTrackerGPU::GPUTRDSpacePointInternal& sp = spacePoints[i]; - int id = sp.mId; - if (id < 0 || id >= nTrackletsTotal) { - HLTError("Internal error: wrong space point index %d", id); - } - GPUTRDTrackPoint* currOutPoint = &outTrackPoints->fPoints[id]; - currOutPoint->fX[0] = sp.mR; // x in sector coordinates - currOutPoint->fX[1] = sp.mX[0]; // y in sector coordinates - currOutPoint->fX[2] = sp.mX[1]; // z in sector coordinates - currOutPoint->fVolumeId = sp.mVolumeId; + const GPUTRDSpacePoint& sp = spacePoints[i]; + GPUTRDTrackPoint* currOutPoint = &outTrackPoints->fPoints[i]; + currOutPoint->fX[0] = sp.getX(); // x in sector coordinates + currOutPoint->fX[1] = sp.getY(); // y in sector coordinates + currOutPoint->fX[2] = sp.getZ(); // z in sector coordinates + int detId = trackletsTmp[i].GetDetector(); + int layer = detId % 6; // TRD layer number for given detector + int modId = (detId / 18) * 5 + ((detId % 30) / 6); // global TRD stack number [0..89] + int volId = (UShort_t(9 + layer) << 11) | UShort_t(modId); // taken from AliGeomManager::LayerToVolUID(). AliGeomManager::ELayerID(AliGeomManager::kTRD1) == 9 + currOutPoint->fVolumeId = volId; } AliHLTComponentBlockData resultDataSP; FillBlockData(resultDataSP); diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h index 6adc8704e7e79..28267c1ae5d71 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -132,9 +133,9 @@ class GPUTRDTrackerComponent : public AliHLTProcessor * --------------------------------------------------------------------------------- */ GPUCA_NAMESPACE::gpu::GPUTRDTrackerGPU* fTracker; // the tracker itself - GPUCA_NAMESPACE::gpu::GPUTRDGeometry* fGeo; // TRD geometry needed by the tracker - GPUCA_NAMESPACE::gpu::GPUReconstruction* fRec; // GPU Reconstruction object - GPUCA_NAMESPACE::gpu::GPUChainTracking* fChain; // Tracking Chain Object + GPUCA_NAMESPACE::gpu::GPUTRDGeometry* fGeo; // TRD geometry needed by the tracker + GPUCA_NAMESPACE::gpu::GPUReconstruction* fRec; // GPU Reconstruction object + GPUCA_NAMESPACE::gpu::GPUChainTracking* fChain; // Tracking Chain Object TList* fTrackList; bool fDebugTrackOutput; // output GPUTRDTracks instead AliHLTExternalTrackParam diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerDebug.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerDebug.h index 08b453d4f2345..855b4cebf2009 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerDebug.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerDebug.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -83,24 +84,8 @@ class GPUTRDTrackerDebug fTrackletDet.ResizeTo(6); fRoadY.ResizeTo(6); fRoadZ.ResizeTo(6); - fTrackletXReal.ResizeTo(6); - fTrackletYReal.ResizeTo(6); - fTrackletZReal.ResizeTo(6); - ; - fTrackletYcorrReal.ResizeTo(6); - fTrackletZcorrReal.ResizeTo(6); - fTrackletSecReal.ResizeTo(6); - fTrackletDetReal.ResizeTo(6); - fTrackXReal.ResizeTo(6); - fTrackYReal.ResizeTo(6); - fTrackZReal.ResizeTo(6); - fTrackSecReal.ResizeTo(6); fChi2Update.ResizeTo(6); - fChi2Real.ResizeTo(6); - fNmatchesAvail.ResizeTo(6); fFindable.ResizeTo(6); - fFindableMC.ResizeTo(6); - fUpdates.ResizeTo(6); } void Reset() @@ -137,61 +122,25 @@ class GPUTRDTrackerDebug fTrackletDet.Zero(); fRoadY.Zero(); fRoadZ.Zero(); - fTrackletXReal.Zero(); - fTrackletYReal.Zero(); - fTrackletZReal.Zero(); - ; - fTrackletYcorrReal.Zero(); - fTrackletZcorrReal.Zero(); - fTrackletSecReal.Zero(); - fTrackletDetReal.Zero(); - fTrackXReal.Zero(); - fTrackYReal.Zero(); - fTrackZReal.Zero(); - fTrackSecReal.Zero(); fChi2Update.Zero(); - fChi2Real.Zero(); - fNmatchesAvail.Zero(); fFindable.Zero(); - fFindableMC.Zero(); - fUpdates.Zero(); fEv = 0; fNTPCtracks = 0; fTrk = 0; - mTrackId = 0; fPtTPC = 0.f; fNtrklts = 0; - fNtrkltsRef = 0; - fNtrkltsRefMatch = 0; - fNtrkltsRefRelated = 0; - fNtrkltsRefFake = 0; - fTrackIDref = -1; fNlayers = 0; fChi2 = 0.f; - fNmatch = 0; - fNfake = 0; - fNrelated = 0; - fXvMC = 0; - fYvMC = 0; - fZvMC = 0; - fPdgCode = 0; } // general information - void SetGeneralInfo(int iEv, int nTPCtracks, int iTrk, int trackId, float pt) + void SetGeneralInfo(int iEv, int nTPCtracks, int iTrk, float pt) { fEv = iEv; fNTPCtracks = nTPCtracks; fTrk = iTrk; - mTrackId = trackId; fPtTPC = pt; } - void SetTrackProperties(int nMatch = 0, int nFake = 0, int nRelated = 0) - { - fNmatch = nMatch; - fNfake = nFake; - fNrelated = nRelated; - } // track parameters void SetTrackParameter(const T& trk, int ly) @@ -219,36 +168,24 @@ class GPUTRDTrackerDebug fTrackNoUpYerr(ly) = trk.getSigmaY2(); fTrackNoUpZerr(ly) = trk.getSigmaZ2(); } - void SetTrackParameterReal(const T& trk, int ly) - { - fTrackXReal(ly) = trk.getX(); - fTrackYReal(ly) = trk.getY(); - fTrackZReal(ly) = trk.getZ(); - fTrackSecReal(ly) = GetSector(trk.getAlpha()); - } void SetTrack(const T& trk) { - fChi2 = trk.GetChi2(); - fNlayers = trk.GetNlayers(); - fNtrklts = trk.GetNtracklets(); - fNtrkltsRef = trk.GetNtrackletsOffline(0); - fNtrkltsRefMatch = trk.GetNtrackletsOffline(1); - fNtrkltsRefRelated = trk.GetNtrackletsOffline(2); - fNtrkltsRefFake = trk.GetNtrackletsOffline(3); - fTrackIDref = trk.GetLabelOffline(); + fChi2 = trk.getChi2(); + fNlayers = trk.getNlayers(); + fNtrklts = trk.getNtracklets(); for (int iLy = 0; iLy < 6; iLy++) { - if (trk.GetIsFindable(iLy)) { + if (trk.getIsFindable(iLy)) { fFindable(iLy) = 1; } } } // tracklet parameters - void SetRawTrackletPosition(const float fX, const float* fYZ, int ly) + void SetRawTrackletPosition(const float fX, const float fY, const float fZ, int ly) { fTrackletX(ly) = fX; - fTrackletY(ly) = fYZ[0]; - fTrackletZ(ly) = fYZ[1]; + fTrackletY(ly) = fY; + fTrackletZ(ly) = fZ; } void SetCorrectedTrackletPosition(const My_Float* fYZ, int ly) { @@ -266,26 +203,9 @@ class GPUTRDTrackerDebug fTrackletDy(ly) = dy; fTrackletDet(ly) = det; } - void SetRawTrackletPositionReal(float fX, float* fYZ, int ly) - { - fTrackletXReal(ly) = fX; - fTrackletYReal(ly) = fYZ[0]; - fTrackletZReal(ly) = fYZ[1]; - } - void SetCorrectedTrackletPositionReal(My_Float* fYZ, int ly) - { - fTrackletYcorrReal(ly) = fYZ[0]; - fTrackletZcorrReal(ly) = fYZ[1]; - } - void SetTrackletPropertiesReal(const int det, int ly) - { - fTrackletSecReal(ly) = det / 30; - fTrackletDetReal(ly) = det; - } // update information void SetChi2Update(float chi2, int ly) { fChi2Update(ly) = chi2; } - void SetChi2Real(float chi2, int ly) { fChi2Real(ly) = chi2; } // other infos void SetRoad(float roadY, float roadZ, int ly) @@ -293,26 +213,6 @@ class GPUTRDTrackerDebug fRoadY(ly) = roadY; fRoadZ(ly) = roadZ; } - void SetUpdates(int* up) - { - for (int iLy = 0; iLy < 6; iLy++) { - fUpdates(iLy) = up[iLy]; - } - } - void SetNmatchAvail(size_t i, int ly) { fNmatchesAvail(ly) = (int)i; }; - void SetFindableMC(bool* findableMC) - { - for (int iLy = 0; iLy < 6; iLy++) { - fFindableMC(iLy) = findableMC[iLy]; - } - } - void SetMCinfo(float xv, float yv, float zv, int pdg) - { - fXvMC = xv; - fYvMC = yv; - fZvMC = zv; - fPdgCode = pdg; - } void Output() { @@ -320,7 +220,6 @@ class GPUTRDTrackerDebug << "event=" << fEv << // event number "nTPCtracks=" << fNTPCtracks << // total number of TPC tracks for this event "iTrack=" << fTrk << // track index in event - "trackID=" << mTrackId << // TPC MC track label "trackPtTPC=" << fPtTPC << // track pT before any propagation "trackX.=" << &fTrackX << // x-pos of track (layerwise) "trackY.=" << &fTrackY << // y-pos of track (layerwise) @@ -351,40 +250,13 @@ class GPUTRDTrackerDebug "trackletZerr.=" << &fTrackletZ2err << // sigma_z^2 for tracklet "trackletDy.=" << &fTrackletDy << // deflection for tracklet "trackletDet.=" << &fTrackletDet << // TRD chamber of tracklet - "trackXReal.=" << &fTrackXReal << // x-pos for track at first found tracklet radius w/ matching MC label - "trackYReal.=" << &fTrackYReal << // y-pos for track at first found tracklet radius w/ matching MC label - "trackZReal.=" << &fTrackZReal << // z-pos for track at first found tracklet radius w/ matching MC label - "trackSecReal.=" << &fTrackSecReal << // TRD sector for track at first found tracklet w/ matching MC label - "trackletXReal.=" << &fTrackletXReal << // x position (sector coords) for matching or related tracklet if available, otherwise 0 - "trackletYReal.=" << &fTrackletYcorrReal << // y position (sector coords, tilt correctet position) for matching or related tracklet if available, otherwise 0 - "trackletZReal.=" << &fTrackletZcorrReal << // z position (sector coords, tilt correctet position) for matching or related tracklet if available, otherwise 0 - "trackletYRawReal.=" << &fTrackletYReal << // y position (sector coords) for matching or related tracklet if available, otherwise 0 - "trackletZRawReal.=" << &fTrackletZReal << // z position (sector coords) for matching or related tracklet if available, otherwise 0 - "trackletSecReal.=" << &fTrackletSecReal << // sector number for matching or related tracklet if available, otherwise -1 - "trackletDetReal.=" << &fTrackletDetReal << // detector number for matching or related tracklet if available, otherwise -1 "chi2Update.=" << &fChi2Update << // chi2 for update - "chi2Real.=" << &fChi2Real << // chi2 for first tracklet w/ matching MC label "chi2Total=" << fChi2 << // total chi2 for track "nLayers=" << fNlayers << // number of layers in which track was findable "nTracklets=" << fNtrklts << // number of attached tracklets - "nTrackletsOffline=" << fNtrkltsRef << // number of attached offline tracklets - "nTrackletsOfflineMatch=" << fNtrkltsRefMatch << // number of attached offline tracklets - "nTrackletsOfflineRelated=" << fNtrkltsRefRelated << // number of attached offline tracklets - "nTrackletsOfflineFake=" << fNtrkltsRefFake << // number of attached offline tracklets - "labelRef=" << fTrackIDref << // TRD MC track label from offline, if provided "roadY.=" << &fRoadY << // search road width in Y "roadZ.=" << &fRoadZ << // search road width in Z "findable.=" << &fFindable << // whether or not track was in active TRD volume (layerwise) - "findableMC.=" << &fFindableMC << // whether or not a MC hit existed inside the TRD for the track (layerwise) - "update.=" << &fUpdates << // layerwise tracklet attachment (0 - no tracklet, [1-3] matching tracklet, [4-6] related tracklet, 9 fake tracklet) - "nRelated=" << fNrelated << // number of attached related tracklets - "nMatching=" << fNmatch << // number of attached matching tracklets - "nFake=" << fNfake << // number of attached fake tracklets - "nMatchingTracklets.=" << &fNmatchesAvail << // number of matching + related tracklets for this track in each layer - "XvMC=" << fXvMC << // MC production vertex x - "YvMC=" << fYvMC << // MC production vertex y - "ZvMC=" << fZvMC << // MC production vertex z - "pdgCode=" << fPdgCode << // MC PID "\n"; } @@ -392,20 +264,9 @@ class GPUTRDTrackerDebug int fEv; int fNTPCtracks; int fTrk; - int mTrackId; float fPtTPC; - int fNtrklts; - int fNtrkltsRef; - int fNtrkltsRefMatch; - int fNtrkltsRefRelated; - int fNtrkltsRefFake; - int fTrackIDref; int fNlayers; float fChi2; - int fNmatch; - int fNfake; - int fNrelated; - TVectorF fNmatchesAvail; TVectorF fTrackX; TVectorF fTrackY; TVectorF fTrackZ; @@ -435,28 +296,10 @@ class GPUTRDTrackerDebug TVectorF fTrackletZ2err; TVectorF fTrackletDy; TVectorF fTrackletDet; - TVectorF fTrackXReal; - TVectorF fTrackYReal; - TVectorF fTrackZReal; - TVectorF fTrackSecReal; - TVectorF fTrackletXReal; - TVectorF fTrackletYReal; - TVectorF fTrackletZReal; - TVectorF fTrackletYcorrReal; - TVectorF fTrackletZcorrReal; - TVectorF fTrackletSecReal; - TVectorF fTrackletDetReal; TVectorF fChi2Update; - TVectorF fChi2Real; TVectorF fRoadY; TVectorF fRoadZ; TVectorF fFindable; - TVectorF fFindableMC; - TVectorF fUpdates; - float fXvMC; - float fYvMC; - float fZvMC; - int fPdgCode; TTreeSRedirector* fStreamer; }; @@ -480,36 +323,26 @@ class GPUTRDTrackerDebug GPUd() void Reset() {} // general information - GPUd() void SetGeneralInfo(int iEv, int nTPCtracks, int iTrk, int trackId, float pt) {} - GPUd() void SetTrackProperties(int nMatch = 0, int nFake = 0, int nRelated = 0) {} + GPUd() void SetGeneralInfo(int iEv, int nTPCtracks, int iTrk, float pt) {} // track parameters GPUd() void SetTrackParameter(const T& trk, int ly) {} GPUd() void SetTrackParameterNoUp(const T& trk, int ly) {} - GPUd() void SetTrackParameterReal(const T& trk, int ly) {} GPUd() void SetTrack(const T& trk) {} // tracklet parameters - GPUd() void SetRawTrackletPosition(const float fX, const float* fYZ, int ly) {} + GPUd() void SetRawTrackletPosition(const float fX, const float fY, const float fZ, int ly) {} GPUd() void SetCorrectedTrackletPosition(const My_Float* fYZ, int ly) {} GPUd() void SetTrackletCovariance(const My_Float* fCov, int ly) {} GPUd() void SetTrackletProperties(const float dy, const int det, int ly) {} - GPUd() void SetRawTrackletPositionReal(float fX, float* fYZ, int ly) {} - GPUd() void SetCorrectedTrackletPositionReal(My_Float* fYZ, int ly) {} - GPUd() void SetTrackletPropertiesReal(const int det, int ly) {} // update information GPUd() void SetChi2Update(float chi2, int ly) {} - GPUd() void SetChi2Real(float chi2, int ly) {} GPUd() void SetChi2YZPhiUpdate(float chi2, int ly) {} // other infos GPUd() void SetRoad(float roadY, float roadZ, int ly) {} - GPUd() void SetUpdates(int* up) {} - GPUd() void SetNmatchAvail(size_t i, int ly) {} GPUd() void SetFindable(bool* findable) {} - GPUd() void SetFindableMC(bool* findableMC) {} - GPUd() void SetMCinfo(float xv, float yv, float zv, int pdg) {} GPUd() void Output() {} }; #ifndef GPUCA_ALIROOT_LIB diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.cxx index 296407ed2af00..dbb58a71f9b45 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,11 +21,38 @@ using namespace GPUCA_NAMESPACE::gpu; +#ifdef GPUCA_HAVE_O2HEADERS +template <int I> +GPUd() auto& getTracker(GPUTRDTrackerKernels::processorType& processors); template <> -GPUdii() void GPUTRDTrackerKernels::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors) +GPUdi() auto& getTracker<0>(GPUTRDTrackerKernels::processorType& processors) { - GPUCA_OPENMP(parallel for if(!processors.trdTracker.GetRec().GetProcessingSettings().ompKernels) num_threads(processors.trdTracker.GetRec().GetProcessingSettings().ompThreads)) - for (int i = get_global_id(0); i < processors.trdTracker.NTracks(); i += get_global_size(0)) { - processors.trdTracker.DoTrackingThread(i, get_global_id(0)); + return processors.trdTrackerGPU; +} +template <> +GPUdi() auto& getTracker<1>(GPUTRDTrackerKernels::processorType& processors) +{ + return processors.trdTrackerO2; +} +#else +template <int I> +GPUdi() GPUTRDTrackerGPU& getTracker(GPUTRDTrackerKernels::processorType& processors) +{ + return processors.trdTrackerGPU; +} +#endif + +template <int I> +GPUdii() void GPUTRDTrackerKernels::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors) +{ + auto& trdTracker = getTracker<I>(processors); + GPUCA_OPENMP(parallel for if(!trdTracker.GetRec().GetProcessingSettings().ompKernels) num_threads(trdTracker.GetRec().GetProcessingSettings().ompThreads)) + for (int i = get_global_id(0); i < trdTracker.NTracks(); i += get_global_size(0)) { + trdTracker.DoTrackingThread(i, get_global_id(0)); } } + +template GPUd() void GPUTRDTrackerKernels::Thread<0>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors); +#ifdef GPUCA_HAVE_O2HEADERS +template GPUd() void GPUTRDTrackerKernels::Thread<1>(int nBlocks, int nThreads, int iBlock, int iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors); +#endif diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h index 9f19823865ee9..39f93ddaa307c 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletLabels.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletLabels.h index 8a6317d312a0d..5e0e1ee71ddc2 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletLabels.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletLabels.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx index ff78dba37b8e4..101f07155f95f 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -63,7 +64,7 @@ ClassImp(GPUTRDTrackletReaderComponent); } \ } - GPUTRDTrackletReaderComponent::GPUTRDTrackletReaderComponent() +GPUTRDTrackletReaderComponent::GPUTRDTrackletReaderComponent() : AliHLTProcessor(), fDebugLevel(0), fEventId(fgkInvalidEventId), fTrackletArray(nullptr), fRawReaderMem(nullptr), fRawReaderTrd(nullptr) { // constructor @@ -305,7 +306,6 @@ int GPUTRDTrackletReaderComponent::DoEvent(const AliHLTComponentEventData& hltEv HLTInfo("There are %i tracklets in this event\n", nTracklets); for (int iTracklet = 0; iTracklet < nTracklets; ++iTracklet) { GPUTRDTrackletWord trkl = *((AliTRDtrackletWord*)fTrackletArray->At(iTracklet)); - trkl.SetId(iTracklet); outputTrkls.push_back(trkl); } LogDebug("pushing data for sectors: 0x%05x", sourceSectors); @@ -373,7 +373,6 @@ int GPUTRDTrackletReaderComponent::DoEvent(const AliHLTComponentEventData& hltEv continue; } GPUTRDTrackletWord hltTrkl = *trkl; - hltTrkl.SetId(iTracklet); outputTrkls.push_back(hltTrkl); GPUTRDTrackletLabels trklMC; trklMC.mLabel[0] = trkl->GetLabel(0); diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.h index f2f9816a43017..983c93148ba70 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx index f12833a6ddb9f..00bb31a0794aa 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,26 +14,22 @@ #include "GPUTRDTrackletWord.h" using namespace GPUCA_NAMESPACE::gpu; -#ifndef GPUCA_GPUCODE_DEVICE -#include <new> -#endif -GPUd() GPUTRDTrackletWord::GPUTRDTrackletWord(unsigned int trackletWord) : mId(-1), mHCId(-1), mTrackletWord(trackletWord) +#ifndef GPUCA_TPC_GEOMETRY_O2 + +GPUd() GPUTRDTrackletWord::GPUTRDTrackletWord(unsigned int trackletWord) : mHCId(-1), mTrackletWord(trackletWord) { } +GPUd() GPUTRDTrackletWord::GPUTRDTrackletWord(unsigned int trackletWord, int hcid) : mHCId(hcid), mTrackletWord(trackletWord) {} -GPUd() GPUTRDTrackletWord::GPUTRDTrackletWord(unsigned int trackletWord, int hcid, int id) : mId(id), mHCId(hcid), mTrackletWord(trackletWord) {} - -#ifndef GPUCA_GPUCODE_DEVICE #ifdef GPUCA_ALIROOT_LIB #include "AliTRDtrackletWord.h" #include "AliTRDtrackletMCM.h" -GPUTRDTrackletWord::GPUTRDTrackletWord(const AliTRDtrackletWord& rhs) : mId(-1), mHCId(rhs.GetHCId()), mTrackletWord(rhs.GetTrackletWord()) +GPUTRDTrackletWord::GPUTRDTrackletWord(const AliTRDtrackletWord& rhs) : mHCId(rhs.GetHCId()), mTrackletWord(rhs.GetTrackletWord()) { } - -GPUTRDTrackletWord::GPUTRDTrackletWord(const AliTRDtrackletMCM& rhs) : mId(-1), mHCId(rhs.GetHCId()), mTrackletWord(rhs.GetTrackletWord()) {} +GPUTRDTrackletWord::GPUTRDTrackletWord(const AliTRDtrackletMCM& rhs) : mHCId(rhs.GetHCId()), mTrackletWord(rhs.GetTrackletWord()) {} GPUTRDTrackletWord& GPUTRDTrackletWord::operator=(const AliTRDtrackletMCM& rhs) { @@ -42,7 +39,6 @@ GPUTRDTrackletWord& GPUTRDTrackletWord::operator=(const AliTRDtrackletMCM& rhs) } #endif // GPUCA_ALIROOT_LIB -#endif // GPUCA_GPUCODE_DEVICE GPUd() int GPUTRDTrackletWord::GetYbin() const { @@ -54,7 +50,7 @@ GPUd() int GPUTRDTrackletWord::GetYbin() const } } -GPUd() int GPUTRDTrackletWord::GetdY() const +GPUd() int GPUTRDTrackletWord::GetdYbin() const { // returns (signed) value of the deflection length if (mTrackletWord & (1 << 19)) { @@ -63,3 +59,5 @@ GPUd() int GPUTRDTrackletWord::GetdY() const return ((mTrackletWord >> 13) & 0x7f); } } + +#endif // !GPUCA_TPC_GEOMETRY_O2 diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.h index 56f50f2bf6b5f..89c8296c71a91 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,8 @@ #include "GPUDef.h" +#ifndef GPUCA_TPC_GEOMETRY_O2 // compatibility to Run 2 data types + class AliTRDtrackletWord; class AliTRDtrackletMCM; @@ -30,7 +33,7 @@ class GPUTRDTrackletWord { public: GPUd() GPUTRDTrackletWord(unsigned int trackletWord = 0); - GPUd() GPUTRDTrackletWord(unsigned int trackletWord, int hcid, int id); + GPUd() GPUTRDTrackletWord(unsigned int trackletWord, int hcid); GPUdDefault() GPUTRDTrackletWord(const GPUTRDTrackletWord& rhs) CON_DEFAULT; GPUdDefault() GPUTRDTrackletWord& operator=(const GPUTRDTrackletWord& rhs) CON_DEFAULT; GPUdDefault() ~GPUTRDTrackletWord() CON_DEFAULT; @@ -47,27 +50,24 @@ class GPUTRDTrackletWord // ----- Getters for contents of tracklet word ----- GPUd() int GetYbin() const; - GPUd() int GetdY() const; + GPUd() int GetdYbin() const; GPUd() int GetZbin() const { return ((mTrackletWord >> 20) & 0xf); } GPUd() int GetPID() const { return ((mTrackletWord >> 24) & 0xff); } - GPUd() int GetId() const { return mId; } - // ----- Getters for offline corresponding values ----- GPUd() double GetPID(int /* is */) const { return (double)GetPID() / 256.f; } GPUd() int GetDetector() const { return mHCId / 2; } GPUd() int GetHCId() const { return mHCId; } - GPUd() float GetdYdX() const { return (GetdY() * 140e-4f / 3.f); } + GPUd() float GetdYdX() const { return (GetdYbin() * 140e-4f / 3.f); } + GPUd() float GetdY() const { return GetdYbin() * 140e-4f; } GPUd() float GetY() const { return (GetYbin() * 160e-4f); } GPUd() unsigned int GetTrackletWord() const { return mTrackletWord; } GPUd() void SetTrackletWord(unsigned int trackletWord) { mTrackletWord = trackletWord; } GPUd() void SetDetector(int id) { mHCId = 2 * id + (GetYbin() < 0 ? 0 : 1); } - GPUd() void SetId(int id) { mId = id; } GPUd() void SetHCId(int id) { mHCId = id; } protected: - int mId; // index in tracklet array int mHCId; // half-chamber ID unsigned int mTrackletWord; // tracklet word: PID | Z | deflection length | Y // bits: 8 4 7 13 @@ -75,4 +75,44 @@ class GPUTRDTrackletWord } // namespace gpu } // namespace GPUCA_NAMESPACE +#else // compatibility with Run 3 data types + +#include "DataFormatsTRD/Tracklet64.h" + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +class GPUTRDTrackletWord : private o2::trd::Tracklet64 +{ + public: + GPUd() GPUTRDTrackletWord(uint64_t trackletWord = 0) : o2::trd::Tracklet64(trackletWord){}; + GPUdDefault() GPUTRDTrackletWord(const GPUTRDTrackletWord& rhs) CON_DEFAULT; + GPUdDefault() GPUTRDTrackletWord& operator=(const GPUTRDTrackletWord& rhs) CON_DEFAULT; + GPUdDefault() ~GPUTRDTrackletWord() CON_DEFAULT; + + // ----- Override operators < and > to enable tracklet sorting by HCId ----- + GPUd() bool operator<(const GPUTRDTrackletWord& t) const { return (getHCID() < t.getHCID()); } + GPUd() bool operator>(const GPUTRDTrackletWord& t) const { return (getHCID() > t.getHCID()); } + GPUd() bool operator<=(const GPUTRDTrackletWord& t) const { return (getHCID() < t.getHCID()) || (getHCID() == t.getHCID()); } + + GPUd() int GetZbin() const { return getPadRow(); } + GPUd() float GetY() const { return getUncalibratedY(); } + GPUd() float GetdY() const { return getUncalibratedDy(); } + GPUd() int GetDetector() const { return getDetector(); } + GPUd() int GetHCId() const { return getHCID(); } + + // IMPORTANT: Do not add members, this class must keep the same memory layout as o2::trd::Tracklet64 +}; + +#ifdef GPUCA_NOCOMPAT +static_assert(sizeof(GPUTRDTrackletWord) == sizeof(o2::trd::Tracklet64), "Incorrect memory layout"); +#endif + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif // GPUCA_TPC_GEOMETRY_O2 + #endif // GPUTRDTRACKLETWORD_H diff --git a/GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C b/GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C index 7e0175905c7bf..23d444a72435f 100644 --- a/GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C +++ b/GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -852,8 +853,6 @@ void TwoTrackletEfficiency(Int_t nEntries = -1) fOut = 0x0; } - - void PlotTRDEfficiency(Int_t nEntries = -1, Bool_t writeToFile = kTRUE) { // plot fraction of tracks with at least 4/5/6 online/offline tracklets diff --git a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C index d53118770e0d6..7a1fe6dc98686 100644 --- a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C +++ b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C @@ -23,20 +23,13 @@ #include "ReconstructionDataFormats/TrackTPCITS.h" #include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsTRD/TriggerRecord.h" +#include "TPCBase/ParameterElectronics.h" +#include "TPCBase/ParameterGas.h" #endif using namespace GPUCA_NAMESPACE::gpu; -unsigned int convertTrkltWordToRun2Format(uint64_t trkltWordRun3) -{ - // FIXME: this is currently a dummy function - // need proper functionality to convert the new tracklet data format to - // something compatible with the TRD tracker, but this macro is probably - // not the right place for this - unsigned int trkltWord = 0; - return trkltWord; -} void run_trd_tracker(std::string path = "./", std::string inputTracks = "o2match_itstpc.root", @@ -48,7 +41,7 @@ void run_trd_tracker(std::string path = "./", //-------- init geometry and field --------// o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP(o2::base::NameConf::getGRPFileName()); + o2::base::Propagator::initFieldFromGRP(); auto geo = o2::trd::Geometry::instance(); geo->createPadPlaneArray(); @@ -56,23 +49,28 @@ void run_trd_tracker(std::string path = "./", const o2::trd::GeometryFlat geoFlat(*geo); //-------- init GPU reconstruction --------// - GPUSettingsEvent cfgEvent; // defaults should be ok - GPUSettingsRec cfgRec; // don't care for now, NWaysOuter is set in here for instance - GPUSettingsProcessing cfgDeviceProcessing; // also keep defaults here, or adjust debug level + // different settings are defined in GPUSettingsList.h + GPUSettingsGRP cfgGRP; // defaults should be ok + GPUSettingsRec cfgRec; // settings concerning reconstruction + cfgRec.trd.minTrackPt = .5f; + cfgRec.trd.maxChi2 = 15.f; + cfgRec.trd.penaltyChi2 = 12.f; + cfgRec.trd.stopTrkAfterNMissLy = 6; + GPUSettingsProcessing cfgDeviceProcessing; // also keep defaults here, or adjust debug level cfgDeviceProcessing.debugLevel = 5; GPURecoStepConfiguration cfgRecoStep; cfgRecoStep.steps = GPUDataTypes::RecoStep::NoRecoStep; cfgRecoStep.inputs.clear(); cfgRecoStep.outputs.clear(); auto rec = GPUReconstruction::CreateInstance("CPU", true); - rec->SetSettings(&cfgEvent, &cfgRec, &cfgDeviceProcessing, &cfgRecoStep); + rec->SetSettings(&cfgGRP, &cfgRec, &cfgDeviceProcessing, &cfgRecoStep); auto chainTracking = rec->AddChain<GPUChainTracking>(); auto tracker = new GPUTRDTracker(); tracker->SetNCandidates(1); // must be set before initialization - tracker->SetProcessPerTimeFrame(); - tracker->SetNMaxCollisions(100); + tracker->SetProcessPerTimeFrame(true); + tracker->SetGenerateSpacePoints(true); rec->RegisterGPUProcessor(tracker, false); chainTracking->SetTRDGeometry(&geoFlat); @@ -80,13 +78,15 @@ void run_trd_tracker(std::string path = "./", printf("ERROR: GPUReconstruction not initialized\n"); } + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + auto& gasParam = o2::tpc::ParameterGas::Instance(); + auto tpcTBinMUS = elParam.ZbinWidth; + auto tpcVdrift = gasParam.DriftV; + tracker->SetTPCVdrift(tpcVdrift); + // configure the tracker //tracker->EnableDebugOutput(); //tracker->StartDebugging(); - tracker->SetPtThreshold(0.5); - tracker->SetChi2Threshold(15); - tracker->SetChi2Penalty(12); - tracker->SetStopTrkFollowingAfterNMissingLayers(6); tracker->PrintSettings(); // load input tracks @@ -98,8 +98,8 @@ void run_trd_tracker(std::string path = "./", printf("Attached ITS-TPC tracks branch with %lli entries\n", (tracksItsTpc.GetBranch("TPCITS"))->GetEntries()); tracksItsTpc.GetEntry(0); - int nTracks = tracksInArrayPtr->size(); - printf("There are %i tracks in total\n", nTracks); + unsigned int nTracks = tracksInArrayPtr->size(); + printf("There are %u tracks in total\n", nTracks); // and load input tracklets TChain trdTracklets("o2sim"); @@ -116,8 +116,8 @@ void run_trd_tracker(std::string path = "./", for (int iEv = 0; iEv < nCollisions; ++iEv) { o2::trd::TriggerRecord& trg = triggerRecordsInArrayPtr->at(iEv); - int nTrackletsCurrent = trg.getNumberOfObjects(); - int iFirstTracklet = trg.getFirstEntry(); + int nTrackletsCurrent = trg.getNumberOfTracklets(); + int iFirstTracklet = trg.getFirstTracklet(); int64_t evTime = trg.getBCData().toLong() * o2::constants::lhc::LHCBunchSpacingNS; // event time in ns trdTriggerTimes.push_back(evTime / 1000.); trdTriggerIndices.push_back(iFirstTracklet); @@ -128,43 +128,26 @@ void run_trd_tracker(std::string path = "./", chainTracking->mIOPtrs.nMergedTracks = nTracks; chainTracking->mIOPtrs.nTRDTracklets = nTracklets; - chainTracking->AllocateIOMemory(); + chainTracking->mIOPtrs.trdTriggerTimes = &(trdTriggerTimes[0]); + chainTracking->mIOPtrs.trdTrackletIdxFirst = &(trdTriggerIndices[0]); + chainTracking->mIOPtrs.nTRDTriggerRecords = nCollisions; + chainTracking->mIOPtrs.trdTracklets = reinterpret_cast<const o2::gpu::GPUTRDTrackletWord*>(trackletsInArrayPtr->data()); + rec->PrepareEvent(); rec->SetupGPUProcessor(tracker, true); - printf("Start loading input into TRD tracker\n"); + printf("Start loading input tracks into TRD tracker\n"); // load everything into the tracker - for (int iTrk = 0; iTrk < nTracks; ++iTrk) { - const auto& match = (*tracksInArrayPtr)[iTrk]; - const auto& trk = match.getParamOut(); - GPUTRDTrack trkLoad; - trkLoad.setX(trk.getX()); - trkLoad.setAlpha(trk.getAlpha()); - for (int i = 0; i < 5; ++i) { - trkLoad.setParam(trk.getParam(i), i); - } - for (int i = 0; i < 15; ++i) { - trkLoad.setCov(trk.getCov()[i], i); - } - trkLoad.setTime(match.getTimeMUS().getTimeStamp()); - tracker->LoadTrack(trkLoad); - printf("Loaded track %i with time %f\n", iTrk, trkLoad.getTime()); + for (unsigned int iTrk = 0; iTrk < nTracks; ++iTrk) { + const auto& trkITSTPC = tracksInArrayPtr->at(iTrk); + GPUTRDTracker::HelperTrackAttributes trkAttribs; + trkAttribs.mTime = trkITSTPC.getTimeMUS().getTimeStamp(); + trkAttribs.mTimeAddMax = trkITSTPC.getTimeMUS().getTimeStampError(); + trkAttribs.mTimeSubMax = trkITSTPC.getTimeMUS().getTimeStampError(); + GPUTRDTrack trkLoad(trkITSTPC); + tracker->LoadTrack(trkLoad, iTrk, true, &trkAttribs); } - for (int iTrklt = 0; iTrklt < nTracklets; ++iTrklt) { - auto trklt = trackletsInArrayPtr->at(iTrklt); - unsigned int trkltWord = convertTrkltWordToRun2Format(trklt.getTrackletWord()); - GPUTRDTrackletWord trkltLoad; - trkltLoad.SetId(iTrklt); - trkltLoad.SetHCId(trklt.getHCID()); - trkltLoad.SetTrackletWord(trkltWord); - if (tracker->LoadTracklet(trkltLoad) > 0) { - printf("Could not load tracklet %i\n", iTrklt); - } - } - tracker->SetTriggerRecordTimes(&(trdTriggerTimes[0])); - tracker->SetTriggerRecordIndices(&(trdTriggerIndices[0])); - tracker->SetNCollisions(nCollisions); tracker->DumpTracks(); tracker->DoTracking(chainTracking); tracker->DumpTracks(); diff --git a/GPU/GPUTracking/dEdx/GPUdEdx.cxx b/GPU/GPUTracking/dEdx/GPUdEdx.cxx index 2fe03a6e20cb3..5699b6e38e42a 100644 --- a/GPU/GPUTracking/dEdx/GPUdEdx.cxx +++ b/GPU/GPUTracking/dEdx/GPUdEdx.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,14 +21,17 @@ using namespace GPUCA_NAMESPACE::gpu; #ifndef GPUCA_GPUCODE_DEVICE -GPUd() void GPUdEdx::clear() { new (this) GPUdEdx; } +GPUd() void GPUdEdx::clear() +{ + new (this) GPUdEdx; +} #endif GPUd() void GPUdEdx::computedEdx(GPUdEdxInfo& GPUrestrict() output, const GPUParam& GPUrestrict() param) { checkSubThresh(255); - const int truncLow = param.rec.dEdxTruncLow; - const int truncHigh = param.rec.dEdxTruncHigh; + const int truncLow = param.rec.tpc.dEdxTruncLow; + const int truncHigh = param.rec.tpc.dEdxTruncHigh; const int countIROC = mNClsROC[0]; const int countOROC1 = mNClsROC[1]; const int countOROC2 = mNClsROC[2]; diff --git a/GPU/GPUTracking/dEdx/GPUdEdx.h b/GPU/GPUTracking/dEdx/GPUdEdx.h index b3d2406171984..4e98d621d861b 100644 --- a/GPU/GPUTracking/dEdx/GPUdEdx.h +++ b/GPU/GPUTracking/dEdx/GPUdEdx.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include "GPUCommonMath.h" #include "GPUParam.h" #include "GPUdEdxInfo.h" -#ifdef HAVE_O2HEADERS +#if defined(GPUCA_HAVE_O2HEADERS) && !defined(GPUCA_OPENCL1) #include "TPCdEdxCalibrationSplines.h" #endif @@ -27,7 +28,7 @@ namespace GPUCA_NAMESPACE { namespace gpu { -#ifndef HAVE_O2HEADERS +#if !defined(GPUCA_HAVE_O2HEADERS) || defined(GPUCA_OPENCL1) class GPUdEdx { @@ -156,7 +157,7 @@ GPUdi() void GPUdEdx::fillSubThreshold(int padRow, const GPUParam& GPUrestrict() mNSubThresh++; } -#endif // !HAVE_O2HEADERS +#endif // !GPUCA_HAVE_O2HEADERS || __OPENCL1__ } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/dEdx/GPUdEdxInfo.h b/GPU/GPUTracking/dEdx/GPUdEdxInfo.h deleted file mode 100644 index cbf2d254ec180..0000000000000 --- a/GPU/GPUTracking/dEdx/GPUdEdxInfo.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUdEdxInfo.h -/// \author David Rohr - -#ifndef GPUDEDXINFO_H -#define GPUDEDXINFO_H - -#ifdef HAVE_O2HEADERS -#include "DataFormatsTPC/dEdxInfo.h" -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -#ifdef HAVE_O2HEADERS -using GPUdEdxInfo = o2::tpc::dEdxInfo; -#else -struct GPUdEdxInfo { -}; -#endif -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/GL/gl3w.h b/GPU/GPUTracking/display/3rdparty/GL/gl3w.h similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/GL/gl3w.h rename to GPU/GPUTracking/display/3rdparty/GL/gl3w.h diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/GL/glcorearb.h b/GPU/GPUTracking/display/3rdparty/GL/glcorearb.h similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/GL/glcorearb.h rename to GPU/GPUTracking/display/3rdparty/GL/glcorearb.h diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/HandMadeMath.h b/GPU/GPUTracking/display/3rdparty/HandMadeMath.h similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/HandMadeMath.h rename to GPU/GPUTracking/display/3rdparty/HandMadeMath.h diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/HandMadeMathImpl.cxx b/GPU/GPUTracking/display/3rdparty/HandMadeMath/HandMadeMathImpl.cxx similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/HandMadeMathImpl.cxx rename to GPU/GPUTracking/display/3rdparty/HandMadeMath/HandMadeMathImpl.cxx diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/KHR/khrplatform.h b/GPU/GPUTracking/display/3rdparty/KHR/khrplatform.h similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/KHR/khrplatform.h rename to GPU/GPUTracking/display/3rdparty/KHR/khrplatform.h diff --git a/GPU/GPUTracking/Standalone/display/3rdparty/gl3w.c b/GPU/GPUTracking/display/3rdparty/gl3w.c similarity index 100% rename from GPU/GPUTracking/Standalone/display/3rdparty/gl3w.c rename to GPU/GPUTracking/display/3rdparty/gl3w.c diff --git a/GPU/GPUTracking/display/GPUDisplay.cxx b/GPU/GPUTracking/display/GPUDisplay.cxx new file mode 100644 index 0000000000000..3e7c9a8395e44 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplay.cxx @@ -0,0 +1,2689 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplay.cxx +/// \author David Rohr + +#ifndef GPUCA_NO_ROOT +#include "Rtypes.h" // Include ROOT header first, to use ROOT and disable replacements +#endif + +#include "GPUDisplay.h" + +#ifdef GPUCA_BUILD_EVENT_DISPLAY +#include "GPUTPCDef.h" + +#include <GL/glu.h> +#include <vector> +#include <array> +#include <tuple> +#include <memory> +#include <cstring> +#include <stdexcept> +#include <type_traits> + +#ifndef _WIN32 +#include "bitmapfile.h" +#include "../utils/linux_helpers.h" +#endif +#ifdef WITH_OPENMP +#include <omp.h> +#endif + +#include "GPUTPCMCInfo.h" +#include "GPUChainTracking.h" +#include "GPUQA.h" +#include "GPUTPCSliceData.h" +#include "GPUChainTracking.h" +#include "GPUTPCTrack.h" +#include "GPUTPCTracker.h" +#include "GPUTRDTracker.h" +#include "GPUTPCGMMergedTrack.h" +#include "GPUTPCGMPropagator.h" +#include "GPUTPCClusterData.h" +#include "GPUTRDTrackletWord.h" +#include "GPUTRDGeometry.h" +#include "GPUTrackParamConvert.h" +#include "GPUO2DataTypes.h" +#include "GPUParam.inc" +#include "GPUTPCConvertImpl.h" +#include "utils/qconfig.h" + +#ifdef GPUCA_HAVE_O2HEADERS +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTOF/Cluster.h" +#include "TOFBase/Geo.h" +#include "ITSBase/GeometryTGeo.h" +#endif +#ifdef GPUCA_O2_LIB +#include "ITSMFTBase/DPLAlpideParam.h" +#endif + +#include "GPUDisplayShaders.h" + +constexpr hmm_mat4 MY_HMM_IDENTITY = {{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; +constexpr hmm_mat4 MY_HMM_FROM(float (&v)[16]) { return {{{v[0], v[1], v[2], v[3]}, {v[4], v[5], v[6], v[7]}, {v[8], v[9], v[10], v[11]}, {v[12], v[13], v[14], v[15]}}}; } + +using namespace GPUCA_NAMESPACE::gpu; + +//#define CHKERR(cmd) {cmd;} +#define CHKERR(cmd) \ + do { \ + (cmd); \ + GLenum err = glGetError(); \ + while (err != GL_NO_ERROR) { \ + GPUError("OpenGL Error %d: %s (%s: %d)", err, gluErrorString(err), __FILE__, __LINE__); \ + throw std::runtime_error("OpenGL Failure"); \ + } \ + } while (false) + +#define OPENGL_EMULATE_MULTI_DRAW 0 + +#define GL_SCALE_FACTOR 100.f + +#define SEPERATE_GLOBAL_TRACKS_LIMIT (mCfgH.separateGlobalTracks ? tGLOBALTRACK : TRACK_TYPE_ID_LIMIT) + +#define GET_CID(slice, i) (mParam->par.earlyTpcTransform ? mIOPtrs->clusterData[slice][i].id : (mIOPtrs->clustersNative->clusterOffset[slice][0] + i)) + +static const GPUSettingsDisplay& GPUDisplay_GetConfig(GPUChainTracking* chain) +{ + static GPUSettingsDisplay defaultConfig; + if (chain && chain->mConfigDisplay) { + return *chain->mConfigDisplay; + } else { + return defaultConfig; + } +} + +GPUDisplay::GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa, const GPUParam* param, const GPUCalibObjectsConst* calib, const GPUSettingsDisplay* config) : mBackend(backend), mChain(chain), mConfig(config ? *config : GPUDisplay_GetConfig(chain)), mQA(qa) +{ + backend->mDisplay = this; + mCfgR.openGLCore = GPUCA_DISPLAY_OPENGL_CORE_FLAGS; + mParam = param ? param : &mChain->GetParam(); + mCalib = calib; + mCfgL = mConfig.light; + mCfgH = mConfig.heavy; + mCfgR = mConfig.renderer; +} + +inline const GPUTRDGeometry& GPUDisplay::trdGeometry() { return *(GPUTRDGeometry*)mCalib->trdGeometry; } +const GPUTPCTracker& GPUDisplay::sliceTracker(int iSlice) { return mChain->GetTPCSliceTrackers()[iSlice]; } +const GPUTRDTrackerGPU& GPUDisplay::trdTracker() { return *mChain->GetTRDTrackerGPU(); } +inline int GPUDisplay::getNumThreads() +{ + if (mChain) { + return mChain->GetProcessingSettings().ompThreads; + } else { +#ifdef WITH_OPENMP + return omp_get_max_threads(); +#else + return 1; +#endif + } +} + +void GPUDisplay::disableUnsupportedOptions() +{ + if (!mIOPtrs->mergedTrackHitAttachment) { + mCfgH.markAdjacentClusters = 0; + } + if (!mQA) { + mCfgH.markFakeClusters = 0; + } + if (!mChain) { + mCfgL.excludeClusters = mCfgL.drawInitLinks = mCfgL.drawLinks = mCfgL.drawSeeds = mCfgL.drawTracklets = mCfgL.drawTracks = mCfgL.drawGlobalTracks = 0; + } + if (mConfig.showTPCTracksFromO2Format && mParam->par.earlyTpcTransform) { + throw std::runtime_error("Cannot run GPU display with early Transform when input is O2 tracks"); + } +} + +inline void GPUDisplay::drawVertices(const vboList& v, const GLenum t) +{ + auto first = std::get<0>(v); + auto count = std::get<1>(v); + auto iSlice = std::get<2>(v); + if (count == 0) { + return; + } + mNDrawCalls += count; + + if (mUseMultiVBO) { + if (mCfgR.openGLCore) { + CHKERR(glBindVertexArray(mVertexArray)); + } + CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[iSlice])); +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + CHKERR(glVertexPointer(3, GL_FLOAT, 0, nullptr)); + } else +#endif + { + CHKERR(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr)); + glEnableVertexAttribArray(0); + } + } + + if (mCfgR.useGLIndirectDraw) { + CHKERR(glMultiDrawArraysIndirect(t, (void*)(size_t)((mIndirectSliceOffset[iSlice] + first) * sizeof(DrawArraysIndirectCommand)), count, 0)); + } else if (OPENGL_EMULATE_MULTI_DRAW) { + for (int k = 0; k < count; k++) { + CHKERR(glDrawArrays(t, mVertexBufferStart[iSlice][first + k], mVertexBufferCount[iSlice][first + k])); + } + } else { + CHKERR(glMultiDrawArrays(t, mVertexBufferStart[iSlice].data() + first, mVertexBufferCount[iSlice].data() + first, count)); + } +} +inline void GPUDisplay::insertVertexList(std::pair<vecpod<GLint>*, vecpod<GLsizei>*>& vBuf, size_t first, size_t last) +{ + if (first == last) { + return; + } + vBuf.first->emplace_back(first); + vBuf.second->emplace_back(last - first); +} +inline void GPUDisplay::insertVertexList(int iSlice, size_t first, size_t last) +{ + std::pair<vecpod<GLint>*, vecpod<GLsizei>*> vBuf(mVertexBufferStart + iSlice, mVertexBufferCount + iSlice); + insertVertexList(vBuf, first, last); +} + +void GPUDisplay::calcXYZ(const float* matrix) +{ + mXYZ[0] = -(matrix[0] * matrix[12] + matrix[1] * matrix[13] + matrix[2] * matrix[14]); + mXYZ[1] = -(matrix[4] * matrix[12] + matrix[5] * matrix[13] + matrix[6] * matrix[14]); + mXYZ[2] = -(matrix[8] * matrix[12] + matrix[9] * matrix[13] + matrix[10] * matrix[14]); + + mAngle[0] = -asinf(matrix[6]); // Invert rotY*rotX*rotZ + float A = cosf(mAngle[0]); + if (fabsf(A) > 0.005) { + mAngle[1] = atan2f(-matrix[2] / A, matrix[10] / A); + mAngle[2] = atan2f(matrix[4] / A, matrix[5] / A); + } else { + mAngle[1] = 0; + mAngle[2] = atan2f(-matrix[1], -matrix[0]); + } + + mRPhiTheta[0] = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[1] * mXYZ[1] + mXYZ[2] * mXYZ[2]); + mRPhiTheta[1] = atan2f(mXYZ[0], mXYZ[2]); + mRPhiTheta[2] = atan2f(mXYZ[1], sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[2] * mXYZ[2])); + + createQuaternionFromMatrix(mQuat, matrix); + + /*float mAngle[1] = -asinf(matrix[2]); //Calculate Y-axis angle - for rotX*rotY*rotZ + float C = cosf( angle_y ); + if (fabsf(C) > 0.005) //Gimball lock? + { + mAngle[0] = atan2f(-matrix[6] / C, matrix[10] / C); + mAngle[2] = atan2f(-matrix[1] / C, matrix[0] / C); + } + else + { + mAngle[0] = 0; //set x-angle + mAngle[2] = atan2f(matrix[4], matrix[5]); + }*/ +} + +void GPUDisplay::SetCollisionFirstCluster(unsigned int collision, int slice, int cluster) +{ + mNCollissions = std::max<unsigned int>(mNCollissions, collision + 1); + mCollisionClusters.resize(mNCollissions); + mCollisionClusters[collision][slice] = cluster; +} + +void GPUDisplay::mAnimationCloseAngle(float& newangle, float lastAngle) +{ + const float delta = lastAngle > newangle ? (2 * CAMath::Pi()) : (-2 * CAMath::Pi()); + while (fabsf(newangle + delta - lastAngle) < fabsf(newangle - lastAngle)) { + newangle += delta; + } +} +void GPUDisplay::mAnimateCloseQuaternion(float* v, float lastx, float lasty, float lastz, float lastw) +{ + float distPos2 = (lastx - v[0]) * (lastx - v[0]) + (lasty - v[1]) * (lasty - v[1]) + (lastz - v[2]) * (lastz - v[2]) + (lastw - v[3]) * (lastw - v[3]); + float distNeg2 = (lastx + v[0]) * (lastx + v[0]) + (lasty + v[1]) * (lasty + v[1]) + (lastz + v[2]) * (lastz + v[2]) + (lastw + v[3]) * (lastw + v[3]); + if (distPos2 > distNeg2) { + for (int i = 0; i < 4; i++) { + v[i] = -v[i]; + } + } +} +void GPUDisplay::setAnimationPoint() +{ + if (mCfgL.animationMode & 4) // Spherical + { + float rxy = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[2] * mXYZ[2]); + float anglePhi = atan2f(mXYZ[0], mXYZ[2]); + float angleTheta = atan2f(mXYZ[1], rxy); + if (mAnimateVectors[0].size()) { + mAnimationCloseAngle(anglePhi, mAnimateVectors[2].back()); + } + if (mAnimateVectors[0].size()) { + mAnimationCloseAngle(angleTheta, mAnimateVectors[3].back()); + } + mAnimateVectors[1].emplace_back(0); + mAnimateVectors[2].emplace_back(anglePhi); + mAnimateVectors[3].emplace_back(angleTheta); + } else { + for (int i = 0; i < 3; i++) { + mAnimateVectors[i + 1].emplace_back(mXYZ[i]); + } + // Cartesian + } + float r = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[1] * mXYZ[1] + mXYZ[2] * mXYZ[2]); + mAnimateVectors[4].emplace_back(r); + if (mCfgL.animationMode & 1) // Euler-angles + { + for (int i = 0; i < 3; i++) { + float newangle = mAngle[i]; + if (mAnimateVectors[0].size()) { + mAnimationCloseAngle(newangle, mAnimateVectors[i + 5].back()); + } + mAnimateVectors[i + 5].emplace_back(newangle); + } + mAnimateVectors[8].emplace_back(0); + } else { // Quaternions + float v[4]; + createQuaternionFromMatrix(v, mViewMatrixP); + if (mAnimateVectors[0].size()) { + mAnimateCloseQuaternion(v, mAnimateVectors[5].back(), mAnimateVectors[6].back(), mAnimateVectors[7].back(), mAnimateVectors[8].back()); + } + for (int i = 0; i < 4; i++) { + mAnimateVectors[i + 5].emplace_back(v[i]); + } + } + float delay = 0.f; + if (mAnimateVectors[0].size()) { + delay = mAnimateVectors[0].back() + ((int)(mAnimationDelay * 20)) / 20.f; + } + mAnimateVectors[0].emplace_back(delay); + mAnimateConfig.emplace_back(mCfgL); +} +void GPUDisplay::resetAnimation() +{ + for (int i = 0; i < 9; i++) { + mAnimateVectors[i].clear(); + } + mAnimateConfig.clear(); + mAnimate = 0; +} +void GPUDisplay::removeAnimationPoint() +{ + if (mAnimateVectors[0].size() == 0) { + return; + } + for (int i = 0; i < 9; i++) { + mAnimateVectors[i].pop_back(); + } + mAnimateConfig.pop_back(); +} +void GPUDisplay::startAnimation() +{ + for (int i = 0; i < 8; i++) { + mAnimationSplines[i].create(mAnimateVectors[0], mAnimateVectors[i + 1]); + } + mAnimationTimer.ResetStart(); + mAnimationFrame = 0; + mAnimate = 1; + mAnimationLastBase = 0; +} + +inline void GPUDisplay::ActivateColor() +{ +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + glColor3f(mDrawColor[0], mDrawColor[1], mDrawColor[2]); + } else +#endif + { + glUniform3fv(mColorId, 1, &mDrawColor[0]); + } +} + +inline void GPUDisplay::SetColorClusters() +{ + if (mCfgL.colorCollisions) { + return; + } + if (mCfgL.invertColors) { + mDrawColor = {0, 0.3, 0.7}; + } else { + mDrawColor = {0, 0.7, 1.0}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorTRD() +{ + if (mCfgL.colorCollisions) { + return; + } + if (mCfgL.invertColors) { + mDrawColor = {0.7, 0.3, 0}; + } else { + mDrawColor = {1.0, 0.7, 0}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorITS() +{ + if (mCfgL.colorCollisions) { + return; + } + if (mCfgL.invertColors) { + mDrawColor = {1.00, 0.1, 0.1}; + } else { + mDrawColor = {1.00, 0.3, 0.3}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorTOF() +{ + if (mCfgL.colorCollisions) { + return; + } + if (mCfgL.invertColors) { + mDrawColor = {0.1, 1.0, 0.1}; + } else { + mDrawColor = {0.5, 1.0, 0.5}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorInitLinks() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.42, 0.4, 0.1}; + } else { + mDrawColor = {0.42, 0.4, 0.1}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorLinks() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.6, 0.1, 0.1}; + } else { + mDrawColor = {0.8, 0.2, 0.2}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorSeeds() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.6, 0.0, 0.65}; + } else { + mDrawColor = {0.8, 0.1, 0.85}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorTracklets() +{ + if (mCfgL.invertColors) { + mDrawColor = {0, 0, 0}; + } else { + mDrawColor = {1, 1, 1}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorTracks() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.6, 0, 0.1}; + } else { + mDrawColor = {0.8, 1., 0.15}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorGlobalTracks() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.8, 0.2, 0}; + } else { + mDrawColor = {1.0, 0.4, 0}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorFinal() +{ + if (mCfgL.colorCollisions) { + return; + } + if (mCfgL.invertColors) { + mDrawColor = {0, 0.6, 0.1}; + } else { + mDrawColor = {0, 0.7, 0.2}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorGrid() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.5, 0.5, 0.0}; + } else { + mDrawColor = {0.7, 0.7, 0.0}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorGridTRD() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.5, 0.5, 0.5}; + } else { + mDrawColor = {0.7, 0.7, 0.5}; + } + ActivateColor(); +} +inline void GPUDisplay::SetColorMarked() +{ + if (mCfgL.invertColors) { + mDrawColor = {0.8, 0, 0}; + } else { + mDrawColor = {1.0, 0.0, 0.0}; + } + ActivateColor(); +} +inline void GPUDisplay::SetCollisionColor(int col) +{ + int red = (col * 2) % 5; + int blue = (2 + col * 3) % 7; + int green = (4 + col * 5) % 6; + if (mCfgL.invertColors && red == 4 && blue == 5 && green == 6) { + red = 0; + } + if (!mCfgL.invertColors && red == 0 && blue == 0 && green == 0) { + red = 4; + } + mDrawColor = {red / 4.f, green / 5.f, blue / 6.f}; + ActivateColor(); +} + +void GPUDisplay::setQuality() +{ + // Doesn't seem to make a difference in this applicattion + if (mCfgR.drawQualityMSAA > 1) { + CHKERR(glEnable(GL_MULTISAMPLE)); + } else { + CHKERR(glDisable(GL_MULTISAMPLE)); + } +} + +void GPUDisplay::setDepthBuffer() +{ + if (mCfgL.depthBuffer) { + CHKERR(glEnable(GL_DEPTH_TEST)); // Enables Depth Testing + CHKERR(glDepthFunc(GL_LEQUAL)); // The Type Of Depth Testing To Do + } else { + CHKERR(glDisable(GL_DEPTH_TEST)); + } +} + +void GPUDisplay::createFB_texture(GLuint& id, bool msaa, GLenum storage, GLenum attachment) +{ + GLenum textureType = msaa ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + CHKERR(glGenTextures(1, &id)); + CHKERR(glBindTexture(textureType, id)); + if (msaa) { + CHKERR(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, mCfgR.drawQualityMSAA, storage, mRenderwidth, mRenderheight, false)); + } else { + CHKERR(glTexImage2D(GL_TEXTURE_2D, 0, storage, mRenderwidth, mRenderheight, 0, storage, GL_UNSIGNED_BYTE, nullptr)); + CHKERR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + CHKERR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + } + CHKERR(glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textureType, id, 0)); +} + +void GPUDisplay::createFB_renderbuffer(GLuint& id, bool msaa, GLenum storage, GLenum attachment) +{ + CHKERR(glGenRenderbuffers(1, &id)); + CHKERR(glBindRenderbuffer(GL_RENDERBUFFER, id)); + if (msaa) { + CHKERR(glRenderbufferStorageMultisample(GL_RENDERBUFFER, mCfgR.drawQualityMSAA, storage, mRenderwidth, mRenderheight)); + } else { + CHKERR(glRenderbufferStorage(GL_RENDERBUFFER, storage, mRenderwidth, mRenderheight)); + } + CHKERR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, id)); +} + +void GPUDisplay::createFB(GLfb& fb, bool tex, bool withDepth, bool msaa) +{ + fb.tex = tex; + fb.depth = withDepth; + fb.msaa = msaa; + GLint drawFboId = 0, readFboId = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId); + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId); + CHKERR(glGenFramebuffers(1, &fb.fb_id)); + CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, fb.fb_id)); + + if (tex) { + createFB_texture(fb.fbCol_id, fb.msaa, GL_RGBA, GL_COLOR_ATTACHMENT0); + } else { + createFB_renderbuffer(fb.fbCol_id, fb.msaa, GL_RGBA, GL_COLOR_ATTACHMENT0); + } + + if (withDepth) { + if (tex && fb.msaa) { + createFB_texture(fb.fbDepth_id, fb.msaa, GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); + } else { + createFB_renderbuffer(fb.fbDepth_id, fb.msaa, GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); + } + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + GPUError("Error creating framebuffer (tex %d) - incomplete (%d)", (int)tex, status); + exit(1); + } + CHKERR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFboId)); + CHKERR(glBindFramebuffer(GL_READ_FRAMEBUFFER, readFboId)); + fb.created = true; +} + +void GPUDisplay::deleteFB(GLfb& fb) +{ + if (fb.tex) { + CHKERR(glDeleteTextures(1, &fb.fbCol_id)); + } else { + CHKERR(glDeleteRenderbuffers(1, &fb.fbCol_id)); + } + if (fb.depth) { + if (fb.tex && fb.msaa) { + CHKERR(glDeleteTextures(1, &fb.fbDepth_id)); + } else { + CHKERR(glDeleteRenderbuffers(1, &fb.fbDepth_id)); + } + } + CHKERR(glDeleteFramebuffers(1, &fb.fb_id)); + fb.created = false; +} + +void GPUDisplay::setFrameBuffer(int updateCurrent, GLuint newID) +{ + if (updateCurrent == 1) { + mMainBufferStack.push_back(newID); + } else if (updateCurrent == 2) { + mMainBufferStack.back() = newID; + } else if (updateCurrent == -2) { + newID = mMainBufferStack.back(); + } else if (updateCurrent == -1) { + mMainBufferStack.pop_back(); + newID = mMainBufferStack.back(); + } + if (newID == 0) { + CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); + glDrawBuffer(GL_BACK); + } else { + CHKERR(glBindFramebuffer(GL_FRAMEBUFFER, newID)); + GLenum drawBuffer = GL_COLOR_ATTACHMENT0; + glDrawBuffers(1, &drawBuffer); + } +} + +void GPUDisplay::UpdateOffscreenBuffers(bool clean) +{ + if (mMixBuffer.created) { + deleteFB(mMixBuffer); + } + if (mOffscreenBuffer.created) { + deleteFB(mOffscreenBuffer); + } + if (mOffscreenBufferNoMSAA.created) { + deleteFB(mOffscreenBufferNoMSAA); + } + if (clean) { + return; + } + + if (mCfgR.drawQualityDownsampleFSAA > 1) { + mRenderwidth = mScreenwidth * mCfgR.drawQualityDownsampleFSAA; + mRenderheight = mScreenheight * mCfgR.drawQualityDownsampleFSAA; + } else { + mRenderwidth = mScreenwidth; + mRenderheight = mScreenheight; + } + if (mCfgR.drawQualityMSAA > 1 || mCfgR.drawQualityDownsampleFSAA > 1) { + createFB(mOffscreenBuffer, false, true, mCfgR.drawQualityMSAA > 1); + if (mCfgR.drawQualityMSAA > 1 && mCfgR.drawQualityDownsampleFSAA > 1) { + createFB(mOffscreenBufferNoMSAA, false, true, false); + } + } + createFB(mMixBuffer, true, true, false); + glViewport(0, 0, mRenderwidth, mRenderheight); + setQuality(); +} + +void GPUDisplay::ReSizeGLScene(int width, int height, bool init) +{ + if (height == 0) { // Prevent A Divide By Zero By + height = 1; // Making Height Equal One + } + mScreenwidth = width; + mScreenheight = height; + UpdateOffscreenBuffers(); + + if (init) { + mResetScene = 1; + mViewMatrix = MY_HMM_IDENTITY; + mModelMatrix = MY_HMM_IDENTITY; + } +} + +void GPUDisplay::updateConfig() +{ + setQuality(); + setDepthBuffer(); +} + +int GPUDisplay::InitGL(bool initFailure) +{ + int retVal = initFailure; + try { + if (!initFailure) { + retVal = InitGL_internal(); + } + } catch (const std::runtime_error& e) { + retVal = 1; + } + mInitResult = retVal == 0 ? 1 : -1; + return (retVal); +} + +int GPUDisplay::InitGL_internal() +{ + int glVersion[2] = {0, 0}; + glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); + glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); + if (glVersion[0] < GPUDisplayBackend::GL_MIN_VERSION_MAJOR || (glVersion[0] == GPUDisplayBackend::GL_MIN_VERSION_MAJOR && glVersion[1] < GPUDisplayBackend::GL_MIN_VERSION_MINOR)) { + GPUError("Unsupported OpenGL runtime %d.%d < %d.%d", glVersion[0], glVersion[1], GPUDisplayBackend::GL_MIN_VERSION_MAJOR, GPUDisplayBackend::GL_MIN_VERSION_MINOR); + return (1); + } + + CHKERR(glCreateBuffers(GPUChainTracking::NSLICES, mVBOId)); + CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0])); + CHKERR(glGenBuffers(1, &mIndirectId)); + CHKERR(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectId)); +#ifndef GPUCA_DISPLAY_OPENGL_CORE + CHKERR(glShadeModel(GL_SMOOTH)); // Enable Smooth Shading +#endif + setDepthBuffer(); + setQuality(); + ReSizeGLScene(GPUDisplayBackend::INIT_WIDTH, GPUDisplayBackend::INIT_HEIGHT, true); + mThreadBuffers.resize(getNumThreads()); + mThreadTracks.resize(getNumThreads()); + CHKERR(mVertexShader = glCreateShader(GL_VERTEX_SHADER)); + CHKERR(glShaderSource(mVertexShader, 1, &GPUDisplayShaders::vertexShader, nullptr)); + CHKERR(glCompileShader(mVertexShader)); + CHKERR(mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER)); + CHKERR(glShaderSource(mFragmentShader, 1, &GPUDisplayShaders::fragmentShader, nullptr)); + CHKERR(glCompileShader(mFragmentShader)); + CHKERR(mShaderProgram = glCreateProgram()); + CHKERR(glAttachShader(mShaderProgram, mVertexShader)); + CHKERR(glAttachShader(mShaderProgram, mFragmentShader)); + CHKERR(glLinkProgram(mShaderProgram)); + CHKERR(glGenVertexArrays(1, &mVertexArray)); + CHKERR(mModelViewProjId = glGetUniformLocation(mShaderProgram, "ModelViewProj")); + CHKERR(mColorId = glGetUniformLocation(mShaderProgram, "color")); + return (0); // Initialization Went OK +} + +void GPUDisplay::ExitGL() +{ + UpdateOffscreenBuffers(true); + CHKERR(glDeleteBuffers(GPUChainTracking::NSLICES, mVBOId)); + CHKERR(glDeleteBuffers(1, &mIndirectId)); + CHKERR(glDeleteProgram(mShaderProgram)); + CHKERR(glDeleteShader(mVertexShader)); + CHKERR(glDeleteShader(mFragmentShader)); +} + +inline void GPUDisplay::drawPointLinestrip(int iSlice, int cid, int id, int id_limit) +{ + mVertexBuffer[iSlice].emplace_back(mGlobalPos[cid].x, mGlobalPos[cid].y, mCfgH.projectXY ? 0 : mGlobalPos[cid].z); + if (mGlobalPos[cid].w < id_limit) { + mGlobalPos[cid].w = id; + } +} + +GPUDisplay::vboList GPUDisplay::DrawSpacePointsTRD(int iSlice, int select, int iCol) +{ + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + + if (iCol == 0) { + for (unsigned int i = 0; i < mIOPtrs->nTRDTracklets; i++) { + int iSec = trdGeometry().GetSector(mIOPtrs->trdTracklets[i].GetDetector()); + bool draw = iSlice == iSec && mGlobalPosTRD[i].w == select; + if (draw) { + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD[i].x, mGlobalPosTRD[i].y, mCfgH.projectXY ? 0 : mGlobalPosTRD[i].z); + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD2[i].x, mGlobalPosTRD2[i].y, mCfgH.projectXY ? 0 : mGlobalPosTRD2[i].z); + } + } + } + + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawSpacePointsTOF(int iSlice, int select, int iCol) +{ + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + + if (iCol == 0 && iSlice == 0) { + for (unsigned int i = 0; i < mIOPtrs->nTOFClusters; i++) { + mVertexBuffer[iSlice].emplace_back(mGlobalPosTOF[i].x, mGlobalPosTOF[i].y, mCfgH.projectXY ? 0 : mGlobalPosTOF[i].z); + } + } + + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawSpacePointsITS(int iSlice, int select, int iCol) +{ + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + + if (iCol == 0 && iSlice == 0 && mIOPtrs->itsClusters) { + for (unsigned int i = 0; i < mIOPtrs->nItsClusters; i++) { + mVertexBuffer[iSlice].emplace_back(mGlobalPosITS[i].x, mGlobalPosITS[i].y, mCfgH.projectXY ? 0 : mGlobalPosITS[i].z); + } + } + + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawClusters(int iSlice, int select, unsigned int iCol) +{ + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + if (mCollisionClusters.size() > 0 || iCol == 0) { + const int firstCluster = (mCollisionClusters.size() > 1 && iCol > 0) ? mCollisionClusters[iCol - 1][iSlice] : 0; + const int lastCluster = (mCollisionClusters.size() > 1 && iCol + 1 < mCollisionClusters.size()) ? mCollisionClusters[iCol][iSlice] : (mParam->par.earlyTpcTransform ? mIOPtrs->nClusterData[iSlice] : mIOPtrs->clustersNative ? mIOPtrs->clustersNative->nClustersSector[iSlice] : 0); + for (int cidInSlice = firstCluster; cidInSlice < lastCluster; cidInSlice++) { + const int cid = GET_CID(iSlice, cidInSlice); + if (mCfgH.hideUnmatchedClusters && mQA && mQA->SuppressHit(cid)) { + continue; + } + bool draw = mGlobalPos[cid].w == select; + + if (mCfgH.markAdjacentClusters) { + const int attach = mIOPtrs->mergedTrackHitAttachment[cid]; + if (attach) { + if (mCfgH.markAdjacentClusters >= 32) { + if (mQA && mQA->clusterRemovable(attach, mCfgH.markAdjacentClusters == 33)) { + draw = select == tMARKED; + } + } else if ((mCfgH.markAdjacentClusters & 2) && (attach & gputpcgmmergertypes::attachTube)) { + draw = select == tMARKED; + } else if ((mCfgH.markAdjacentClusters & 1) && (attach & (gputpcgmmergertypes::attachGood | gputpcgmmergertypes::attachTube)) == 0) { + draw = select == tMARKED; + } else if ((mCfgH.markAdjacentClusters & 4) && (attach & gputpcgmmergertypes::attachGoodLeg) == 0) { + draw = select == tMARKED; + } else if ((mCfgH.markAdjacentClusters & 16) && (attach & gputpcgmmergertypes::attachHighIncl)) { + draw = select == tMARKED; + } else if (mCfgH.markAdjacentClusters & 8) { + if (fabsf(mIOPtrs->mergedTracks[attach & gputpcgmmergertypes::attachTrackMask].GetParam().GetQPt()) > 20.f) { + draw = select == tMARKED; + } + } + } + } else if (mCfgH.markClusters) { + short flags; + if (mParam->par.earlyTpcTransform) { + flags = mIOPtrs->clusterData[iSlice][cidInSlice].flags; + } else { + flags = mIOPtrs->clustersNative->clustersLinear[cid].getFlags(); + } + const bool match = flags & mCfgH.markClusters; + draw = (select == tMARKED) ? (match) : (draw && !match); + } else if (mCfgH.markFakeClusters) { + const bool fake = (mQA->HitAttachStatus(cid)); + draw = (select == tMARKED) ? (fake) : (draw && !fake); + } + if (draw) { + mVertexBuffer[iSlice].emplace_back(mGlobalPos[cid].x, mGlobalPos[cid].y, mCfgH.projectXY ? 0 : mGlobalPos[cid].z); + } + } + } + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawLinks(const GPUTPCTracker& tracker, int id, bool dodown) +{ + int iSlice = tracker.ISlice(); + if (mCfgH.clustersOnly) { + return (vboList(0, 0, iSlice)); + } + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + for (int i = 0; i < GPUCA_ROW_COUNT; i++) { + const GPUTPCRow& row = tracker.Data().Row(i); + + if (i < GPUCA_ROW_COUNT - 2) { + const GPUTPCRow& rowUp = tracker.Data().Row(i + 2); + for (int j = 0; j < row.NHits(); j++) { + if (tracker.Data().HitLinkUpData(row, j) != CALINK_INVAL) { + const int cid1 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, j)); + const int cid2 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(rowUp, tracker.Data().HitLinkUpData(row, j))); + drawPointLinestrip(iSlice, cid1, id); + drawPointLinestrip(iSlice, cid2, id); + } + } + } + + if (dodown && i >= 2) { + const GPUTPCRow& rowDown = tracker.Data().Row(i - 2); + for (int j = 0; j < row.NHits(); j++) { + if (tracker.Data().HitLinkDownData(row, j) != CALINK_INVAL) { + const int cid1 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, j)); + const int cid2 = GET_CID(iSlice, tracker.Data().ClusterDataIndex(rowDown, tracker.Data().HitLinkDownData(row, j))); + drawPointLinestrip(iSlice, cid1, id); + drawPointLinestrip(iSlice, cid2, id); + } + } + } + } + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawSeeds(const GPUTPCTracker& tracker) +{ + int iSlice = tracker.ISlice(); + if (mCfgH.clustersOnly) { + return (vboList(0, 0, iSlice)); + } + size_t startCount = mVertexBufferStart[iSlice].size(); + for (unsigned int i = 0; i < *tracker.NStartHits(); i++) { + const GPUTPCHitId& hit = tracker.TrackletStartHit(i); + size_t startCountInner = mVertexBuffer[iSlice].size(); + int ir = hit.RowIndex(); + calink ih = hit.HitIndex(); + do { + const GPUTPCRow& row = tracker.Data().Row(ir); + const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, ih)); + drawPointLinestrip(iSlice, cid, tSEED); + ir += 2; + ih = tracker.Data().HitLinkUpData(row, ih); + } while (ih != CALINK_INVAL); + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + } + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawTracklets(const GPUTPCTracker& tracker) +{ + int iSlice = tracker.ISlice(); + if (mCfgH.clustersOnly) { + return (vboList(0, 0, iSlice)); + } + size_t startCount = mVertexBufferStart[iSlice].size(); + for (unsigned int i = 0; i < *tracker.NTracklets(); i++) { + const GPUTPCTracklet& tracklet = tracker.Tracklet(i); + if (tracklet.NHits() == 0) { + continue; + } + size_t startCountInner = mVertexBuffer[iSlice].size(); + float4 oldpos; + for (int j = tracklet.FirstRow(); j <= tracklet.LastRow(); j++) { + const calink rowHit = tracker.TrackletRowHits()[tracklet.FirstHit() + (j - tracklet.FirstRow())]; + if (rowHit != CALINK_INVAL) { + const GPUTPCRow& row = tracker.Data().Row(j); + const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, rowHit)); + oldpos = mGlobalPos[cid]; + drawPointLinestrip(iSlice, cid, tTRACKLET); + } + } + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + } + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawTracks(const GPUTPCTracker& tracker, int global) +{ + int iSlice = tracker.ISlice(); + if (mCfgH.clustersOnly) { + return (vboList(0, 0, iSlice)); + } + size_t startCount = mVertexBufferStart[iSlice].size(); + for (unsigned int i = (global ? tracker.CommonMemory()->nLocalTracks : 0); i < (global ? *tracker.NTracks() : tracker.CommonMemory()->nLocalTracks); i++) { + GPUTPCTrack& track = tracker.Tracks()[i]; + size_t startCountInner = mVertexBuffer[iSlice].size(); + for (int j = 0; j < track.NHits(); j++) { + const GPUTPCHitId& hit = tracker.TrackHits()[track.FirstHitID() + j]; + const GPUTPCRow& row = tracker.Data().Row(hit.RowIndex()); + const int cid = GET_CID(iSlice, tracker.Data().ClusterDataIndex(row, hit.HitIndex())); + drawPointLinestrip(iSlice, cid, tSLICETRACK + global); + } + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + } + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +void GPUDisplay::DrawTrackITS(int trackId, int iSlice) +{ + const auto& trk = mIOPtrs->itsTracks[trackId]; + for (int k = 0; k < trk.getNClusters(); k++) { + int cid = mIOPtrs->itsTrackClusIdx[trk.getFirstClusterEntry() + k]; + mVertexBuffer[iSlice].emplace_back(mGlobalPosITS[cid].x, mGlobalPosITS[cid].y, mCfgH.projectXY ? 0 : mGlobalPosITS[cid].z); + mGlobalPosITS[cid].w = tITSATTACHED; + } +} + +GPUDisplay::vboList GPUDisplay::DrawFinalITS() +{ + const int iSlice = 0; + size_t startCount = mVertexBufferStart[iSlice].size(); + for (unsigned int i = 0; i < mIOPtrs->nItsTracks; i++) { + if (mITSStandaloneTracks[i]) { + size_t startCountInner = mVertexBuffer[iSlice].size(); + DrawTrackITS(i, iSlice); + insertVertexList(iSlice, startCountInner, mVertexBuffer[iSlice].size()); + } + } + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +template <class T> +void GPUDisplay::DrawFinal(int iSlice, int /*iCol*/, GPUTPCGMPropagator* prop, std::array<vecpod<int>, 2>& trackList, threadVertexBuffer& threadBuffer) +{ + auto& vBuf = threadBuffer.vBuf; + auto& buffer = threadBuffer.buffer; + unsigned int nTracks = std::max(trackList[0].size(), trackList[1].size()); + if (mCfgH.clustersOnly) { + nTracks = 0; + } + for (unsigned int ii = 0; ii < nTracks; ii++) { + int i = 0; + const T* track = nullptr; + int lastCluster = -1; + while (true) { + if (ii >= trackList[0].size()) { + break; + } + i = trackList[0][ii]; + int nClusters; + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + track = &mIOPtrs->mergedTracks[i]; + nClusters = track->NClusters(); + } else if constexpr (std::is_same_v<T, o2::tpc::TrackTPC>) { + track = &mIOPtrs->outputTracksTPCO2[i]; + nClusters = track->getNClusters(); + if (!mIOPtrs->clustersNative) { + break; + } + } else { + throw std::runtime_error("invalid type"); + } + + size_t startCountInner = mVertexBuffer[iSlice].size(); + bool drawing = false; + + if constexpr (std::is_same_v<T, o2::tpc::TrackTPC>) { + if (!mCfgH.drawTracksAndFilter && !(mCfgH.drawTPCTracks || (mCfgH.drawITSTracks && mIOPtrs->tpcLinkITS && mIOPtrs->tpcLinkITS[i] != -1) || (mCfgH.drawTRDTracks && mIOPtrs->tpcLinkTRD && mIOPtrs->tpcLinkTRD[i] != -1) || (mCfgH.drawTOFTracks && mIOPtrs->tpcLinkTOF && mIOPtrs->tpcLinkTOF[i] != -1))) { + break; + } + if (mCfgH.drawTracksAndFilter && ((mCfgH.drawITSTracks && !(mIOPtrs->tpcLinkITS && mIOPtrs->tpcLinkITS[i] != -1)) || (mCfgH.drawTRDTracks && !(mIOPtrs->tpcLinkTRD && mIOPtrs->tpcLinkTRD[i] != -1)) || (mCfgH.drawTOFTracks && !(mIOPtrs->tpcLinkTOF && mIOPtrs->tpcLinkTOF[i] != -1)))) { + break; + } + } + + if (mCfgH.trackFilter && !mTrackFilter[i]) { + break; + } + + // Print TOF part of track + if constexpr (std::is_same_v<T, o2::tpc::TrackTPC>) { + if (mIOPtrs->tpcLinkTOF && mIOPtrs->tpcLinkTOF[i] != -1 && mIOPtrs->nTOFClusters) { + int cid = mIOPtrs->tpcLinkTOF[i]; + drawing = true; + mVertexBuffer[iSlice].emplace_back(mGlobalPosTOF[cid].x, mGlobalPosTOF[cid].y, mCfgH.projectXY ? 0 : mGlobalPosTOF[cid].z); + mGlobalPosTOF[cid].w = tTOFATTACHED; + } + } + + // Print TRD part of track + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + if (mTRDTrackIds[i] != -1 && mIOPtrs->nTRDTracklets) { + auto& trk = mIOPtrs->trdTracks[mTRDTrackIds[i]]; + for (int k = 5; k >= 0; k--) { + int cid = trk.getTrackletIndex(k); + if (cid < 0) { + continue; + } + drawing = true; + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD2[cid].x, mGlobalPosTRD2[cid].y, mCfgH.projectXY ? 0 : mGlobalPosTRD2[cid].z); + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD[cid].x, mGlobalPosTRD[cid].y, mCfgH.projectXY ? 0 : mGlobalPosTRD[cid].z); + mGlobalPosTRD[cid].w = tTRDATTACHED; + } + } + } else if constexpr (std::is_same_v<T, o2::tpc::TrackTPC>) { + if (mIOPtrs->tpcLinkTRD && mIOPtrs->tpcLinkTRD[i] != -1 && mIOPtrs->nTRDTracklets) { + if ((mIOPtrs->tpcLinkTRD[i] & 0x40000000) ? mIOPtrs->nTRDTracksITSTPCTRD : mIOPtrs->nTRDTracksTPCTRD) { + const auto* container = (mIOPtrs->tpcLinkTRD[i] & 0x40000000) ? mIOPtrs->trdTracksITSTPCTRD : mIOPtrs->trdTracksTPCTRD; + const auto& trk = container[mIOPtrs->tpcLinkTRD[i] & 0x3FFFFFFF]; + for (int k = 5; k >= 0; k--) { + int cid = trk.getTrackletIndex(k); + if (cid < 0) { + continue; + } + drawing = true; + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD2[cid].x, mGlobalPosTRD2[cid].y, mCfgH.projectXY ? 0 : mGlobalPosTRD2[cid].z); + mVertexBuffer[iSlice].emplace_back(mGlobalPosTRD[cid].x, mGlobalPosTRD[cid].y, mCfgH.projectXY ? 0 : mGlobalPosTRD[cid].z); + mGlobalPosTRD[cid].w = tTRDATTACHED; + } + } + } + } + + // Print TPC part of track + for (int k = 0; k < nClusters; k++) { + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + if (mCfgH.hideRejectedClusters && (mIOPtrs->mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject)) { + continue; + } + } + int cid; + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + cid = mIOPtrs->mergedTrackHits[track->FirstClusterRef() + k].num; + } else { + cid = &track->getCluster(mIOPtrs->outputClusRefsTPCO2, k, *mIOPtrs->clustersNative) - mIOPtrs->clustersNative->clustersLinear; + } + int w = mGlobalPos[cid].w; + if (drawing) { + drawPointLinestrip(iSlice, cid, tFINALTRACK, SEPERATE_GLOBAL_TRACKS_LIMIT); + } + if (w == SEPERATE_GLOBAL_TRACKS_LIMIT) { + if (drawing) { + insertVertexList(vBuf[0], startCountInner, mVertexBuffer[iSlice].size()); + } + drawing = false; + } else { + if (!drawing) { + startCountInner = mVertexBuffer[iSlice].size(); + } + if (!drawing) { + drawPointLinestrip(iSlice, cid, tFINALTRACK, SEPERATE_GLOBAL_TRACKS_LIMIT); + } + if (!drawing && lastCluster != -1) { + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + cid = mIOPtrs->mergedTrackHits[track->FirstClusterRef() + lastCluster].num; + } else { + cid = &track->getCluster(mIOPtrs->outputClusRefsTPCO2, lastCluster, *mIOPtrs->clustersNative) - mIOPtrs->clustersNative->clustersLinear; + } + drawPointLinestrip(iSlice, cid, 7, SEPERATE_GLOBAL_TRACKS_LIMIT); + } + drawing = true; + } + lastCluster = k; + } + + // Print ITS part of track + if constexpr (std::is_same_v<T, o2::tpc::TrackTPC>) { + if (mIOPtrs->tpcLinkITS && mIOPtrs->tpcLinkITS[i] != -1 && mIOPtrs->nItsTracks && mIOPtrs->nItsClusters) { + DrawTrackITS(mIOPtrs->tpcLinkITS[i], iSlice); + } + } + insertVertexList(vBuf[0], startCountInner, mVertexBuffer[iSlice].size()); + break; + } + + if (!mIOPtrs->clustersNative) { + continue; + } + + // Propagate track paramters / plot MC tracks + for (int iMC = 0; iMC < 2; iMC++) { + if (iMC) { + if (ii >= trackList[1].size()) { + continue; + } + i = trackList[1][ii]; + } else { + if (track == nullptr) { + continue; + } + if (lastCluster == -1) { + continue; + } + } + + size_t startCountInner = mVertexBuffer[iSlice].size(); + for (int inFlyDirection = 0; inFlyDirection < 2; inFlyDirection++) { + GPUTPCGMPhysicalTrackModel trkParam; + float ZOffset = 0; + float x = 0; + float alphaOrg = 0; + if (iMC == 0) { + if (!inFlyDirection && mIOPtrs->tpcLinkITS && mIOPtrs->tpcLinkITS[i] != -1) { + continue; + } + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + trkParam.Set(track->GetParam()); + alphaOrg = mParam->Alpha(iSlice); + } else { + GPUTPCGMTrackParam t; + convertTrackParam(t, *track); + alphaOrg = track->getAlpha(); + trkParam.Set(t); + } + + if (mParam->par.earlyTpcTransform) { + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + x = mIOPtrs->mergedTrackHitsXYZ[track->FirstClusterRef() + lastCluster].x; + ZOffset = track->GetParam().GetTZOffset(); + } + } else { + float y, z; + if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) { + auto cl = mIOPtrs->mergedTrackHits[track->FirstClusterRef() + lastCluster]; + const auto& cln = mIOPtrs->clustersNative->clustersLinear[cl.num]; + GPUTPCConvertImpl::convert(*mCalib->fastTransform, *mParam, cl.slice, cl.row, cln.getPad(), cln.getTime(), x, y, z); + ZOffset = mCalib->fastTransform->convVertexTimeToZOffset(iSlice, track->GetParam().GetTZOffset(), mParam->par.continuousMaxTimeBin); + } else { + uint8_t sector, row; + auto cln = track->getCluster(mIOPtrs->outputClusRefsTPCO2, lastCluster, *mIOPtrs->clustersNative, sector, row); + GPUTPCConvertImpl::convert(*mCalib->fastTransform, *mParam, sector, row, cln.getPad(), cln.getTime(), x, y, z); + ZOffset = mCalib->fastTransform->convVertexTimeToZOffset(sector, track->getTime0(), mParam->par.continuousMaxTimeBin); + } + } + } else { + const GPUTPCMCInfo& mc = mIOPtrs->mcInfosTPC[i]; + if (mc.charge == 0.f) { + break; + } + if (mc.pid < 0) { + break; + } + + alphaOrg = mParam->Alpha(iSlice); + float c = cosf(alphaOrg); + float s = sinf(alphaOrg); + float mclocal[4]; + x = mc.x; + float y = mc.y; + mclocal[0] = x * c + y * s; + mclocal[1] = -x * s + y * c; + float px = mc.pX; + float py = mc.pY; + mclocal[2] = px * c + py * s; + mclocal[3] = -px * s + py * c; + float charge = mc.charge > 0 ? 1.f : -1.f; + + x = mclocal[0]; +#ifdef GPUCA_TPC_GEOMETRY_O2 + trkParam.Set(mclocal[0], mclocal[1], mc.z, mclocal[2], mclocal[3], mc.pZ, charge); + if (mParam->par.continuousTracking) { + ZOffset = fabsf(mCalib->fastTransform->convVertexTimeToZOffset(0, mc.t0, mParam->par.continuousMaxTimeBin)) * (mc.z < 0 ? -1 : 1); + } +#else + if (fabsf(mc.z) > 250) { + ZOffset = mc.z > 0 ? (mc.z - 250) : (mc.z + 250); + } + trkParam.Set(mclocal[0], mclocal[1], mc.z - ZOffset, mclocal[2], mclocal[3], mc.pZ, charge); +#endif + } + trkParam.X() += mCfgH.xAdd; + x += mCfgH.xAdd; + float z0 = trkParam.Z(); + if (iMC && inFlyDirection == 0) { + buffer.clear(); + } + if (x < 1) { + break; + } + if (fabsf(trkParam.SinPhi()) > 1) { + break; + } + float alpha = alphaOrg; + vecpod<GLvertex>& useBuffer = iMC && inFlyDirection == 0 ? buffer : mVertexBuffer[iSlice]; + int nPoints = 0; + + while (nPoints++ < 5000) { + if ((inFlyDirection == 0 && x < 0) || (inFlyDirection && x * x + trkParam.Y() * trkParam.Y() > (iMC ? (450 * 450) : (300 * 300)))) { + break; + } + if (fabsf(trkParam.Z() + ZOffset) > mMaxClusterZ + (iMC ? 0 : 0)) { + break; + } + if (fabsf(trkParam.Z() - z0) > (iMC ? 250 : 250)) { + break; + } + if (inFlyDirection) { + if (fabsf(trkParam.SinPhi()) > 0.4) { + float dalpha = asinf(trkParam.SinPhi()); + trkParam.Rotate(dalpha); + alpha += dalpha; + } + x = trkParam.X() + 1.f; + if (!mCfgH.propagateLoopers) { + float diff = fabsf(alpha - alphaOrg) / (2. * CAMath::Pi()); + diff -= floor(diff); + if (diff > 0.25 && diff < 0.75) { + break; + } + } + } + float B[3]; + prop->GetBxByBz(alpha, trkParam.GetX(), trkParam.GetY(), trkParam.GetZ(), B); + float dLp = 0; + if (trkParam.PropagateToXBxByBz(x, B[0], B[1], B[2], dLp)) { + break; + } + if (fabsf(trkParam.SinPhi()) > 0.9) { + break; + } + float sa = sinf(alpha), ca = cosf(alpha); + useBuffer.emplace_back((ca * trkParam.X() - sa * trkParam.Y()) / GL_SCALE_FACTOR, (ca * trkParam.Y() + sa * trkParam.X()) / GL_SCALE_FACTOR, mCfgH.projectXY ? 0 : (trkParam.Z() + ZOffset) / GL_SCALE_FACTOR); + x += inFlyDirection ? 1 : -1; + } + + if (inFlyDirection == 0) { + if (iMC) { + for (int k = (int)buffer.size() - 1; k >= 0; k--) { + mVertexBuffer[iSlice].emplace_back(buffer[k]); + } + } else { + insertVertexList(vBuf[1], startCountInner, mVertexBuffer[iSlice].size()); + startCountInner = mVertexBuffer[iSlice].size(); + } + } + } + insertVertexList(vBuf[iMC ? 3 : 2], startCountInner, mVertexBuffer[iSlice].size()); + } + } +} + +GPUDisplay::vboList GPUDisplay::DrawGrid(const GPUTPCTracker& tracker) +{ + int iSlice = tracker.ISlice(); + size_t startCount = mVertexBufferStart[iSlice].size(); + size_t startCountInner = mVertexBuffer[iSlice].size(); + for (int i = 0; i < GPUCA_ROW_COUNT; i++) { + const GPUTPCRow& row = tracker.Data().Row(i); + for (int j = 0; j <= (signed)row.Grid().Ny(); j++) { + float z1 = row.Grid().ZMin(); + float z2 = row.Grid().ZMax(); + float x = row.X() + mCfgH.xAdd; + float y = row.Grid().YMin() + (float)j / row.Grid().StepYInv(); + float zz1, zz2, yy1, yy2, xx1, xx2; + mParam->Slice2Global(tracker.ISlice(), x, y, z1, &xx1, &yy1, &zz1); + mParam->Slice2Global(tracker.ISlice(), x, y, z2, &xx2, &yy2, &zz2); + if (iSlice < 18) { + zz1 += mCfgH.zAdd; + zz2 += mCfgH.zAdd; + } else { + zz1 -= mCfgH.zAdd; + zz2 -= mCfgH.zAdd; + } + mVertexBuffer[iSlice].emplace_back(xx1 / GL_SCALE_FACTOR, yy1 / GL_SCALE_FACTOR, zz1 / GL_SCALE_FACTOR); + mVertexBuffer[iSlice].emplace_back(xx2 / GL_SCALE_FACTOR, yy2 / GL_SCALE_FACTOR, zz2 / GL_SCALE_FACTOR); + } + for (int j = 0; j <= (signed)row.Grid().Nz(); j++) { + float y1 = row.Grid().YMin(); + float y2 = row.Grid().YMax(); + float x = row.X() + mCfgH.xAdd; + float z = row.Grid().ZMin() + (float)j / row.Grid().StepZInv(); + float zz1, zz2, yy1, yy2, xx1, xx2; + mParam->Slice2Global(tracker.ISlice(), x, y1, z, &xx1, &yy1, &zz1); + mParam->Slice2Global(tracker.ISlice(), x, y2, z, &xx2, &yy2, &zz2); + if (iSlice < 18) { + zz1 += mCfgH.zAdd; + zz2 += mCfgH.zAdd; + } else { + zz1 -= mCfgH.zAdd; + zz2 -= mCfgH.zAdd; + } + mVertexBuffer[iSlice].emplace_back(xx1 / GL_SCALE_FACTOR, yy1 / GL_SCALE_FACTOR, zz1 / GL_SCALE_FACTOR); + mVertexBuffer[iSlice].emplace_back(xx2 / GL_SCALE_FACTOR, yy2 / GL_SCALE_FACTOR, zz2 / GL_SCALE_FACTOR); + } + } + insertVertexList(tracker.ISlice(), startCountInner, mVertexBuffer[iSlice].size()); + return (vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice)); +} + +GPUDisplay::vboList GPUDisplay::DrawGridTRD(int sector) +{ + // TODO: tilted pads ignored at the moment + size_t startCount = mVertexBufferStart[sector].size(); + size_t startCountInner = mVertexBuffer[sector].size(); +#ifdef GPUCA_HAVE_O2HEADERS + auto* geo = &trdGeometry(); + if (geo) { + int trdsector = NSLICES / 2 - 1 - sector; + float alpha = geo->GetAlpha() / 2.f + geo->GetAlpha() * trdsector; + if (trdsector >= 9) { + alpha -= 2 * CAMath::Pi(); + } + for (int iLy = 0; iLy < GPUTRDTracker::EGPUTRDTracker::kNLayers; ++iLy) { + for (int iStack = 0; iStack < GPUTRDTracker::EGPUTRDTracker::kNStacks; ++iStack) { + int iDet = geo->GetDetector(iLy, iStack, trdsector); + auto matrix = geo->GetClusterMatrix(iDet); + if (!matrix) { + continue; + } + auto pp = geo->GetPadPlane(iDet); + for (int i = 0; i < pp->GetNrows(); ++i) { + float xyzLoc1[3]; + float xyzLoc2[3]; + float xyzGlb1[3]; + float xyzGlb2[3]; + xyzLoc1[0] = xyzLoc2[0] = geo->AnodePos(); + xyzLoc1[1] = pp->GetCol0(); + xyzLoc2[1] = pp->GetColEnd(); + xyzLoc1[2] = xyzLoc2[2] = pp->GetRowPos(i) - pp->GetRowPos(pp->GetNrows() / 2); + matrix->LocalToMaster(xyzLoc1, xyzGlb1); + matrix->LocalToMaster(xyzLoc2, xyzGlb2); + float x1Tmp = xyzGlb1[0]; + xyzGlb1[0] = xyzGlb1[0] * cosf(alpha) + xyzGlb1[1] * sinf(alpha); + xyzGlb1[1] = -x1Tmp * sinf(alpha) + xyzGlb1[1] * cosf(alpha); + float x2Tmp = xyzGlb2[0]; + xyzGlb2[0] = xyzGlb2[0] * cosf(alpha) + xyzGlb2[1] * sinf(alpha); + xyzGlb2[1] = -x2Tmp * sinf(alpha) + xyzGlb2[1] * cosf(alpha); + mVertexBuffer[sector].emplace_back(xyzGlb1[0] / GL_SCALE_FACTOR, xyzGlb1[1] / GL_SCALE_FACTOR, xyzGlb1[2] / GL_SCALE_FACTOR); + mVertexBuffer[sector].emplace_back(xyzGlb2[0] / GL_SCALE_FACTOR, xyzGlb2[1] / GL_SCALE_FACTOR, xyzGlb2[2] / GL_SCALE_FACTOR); + } + for (int j = 0; j < pp->GetNcols(); ++j) { + float xyzLoc1[3]; + float xyzLoc2[3]; + float xyzGlb1[3]; + float xyzGlb2[3]; + xyzLoc1[0] = xyzLoc2[0] = geo->AnodePos(); + xyzLoc1[1] = xyzLoc2[1] = pp->GetColPos(j) + pp->GetColSize(j) / 2.f; + xyzLoc1[2] = pp->GetRow0() - pp->GetRowPos(pp->GetNrows() / 2); + xyzLoc2[2] = pp->GetRowEnd() - pp->GetRowPos(pp->GetNrows() / 2); + matrix->LocalToMaster(xyzLoc1, xyzGlb1); + matrix->LocalToMaster(xyzLoc2, xyzGlb2); + float x1Tmp = xyzGlb1[0]; + xyzGlb1[0] = xyzGlb1[0] * cosf(alpha) + xyzGlb1[1] * sinf(alpha); + xyzGlb1[1] = -x1Tmp * sinf(alpha) + xyzGlb1[1] * cosf(alpha); + float x2Tmp = xyzGlb2[0]; + xyzGlb2[0] = xyzGlb2[0] * cosf(alpha) + xyzGlb2[1] * sinf(alpha); + xyzGlb2[1] = -x2Tmp * sinf(alpha) + xyzGlb2[1] * cosf(alpha); + mVertexBuffer[sector].emplace_back(xyzGlb1[0] / GL_SCALE_FACTOR, xyzGlb1[1] / GL_SCALE_FACTOR, xyzGlb1[2] / GL_SCALE_FACTOR); + mVertexBuffer[sector].emplace_back(xyzGlb2[0] / GL_SCALE_FACTOR, xyzGlb2[1] / GL_SCALE_FACTOR, xyzGlb2[2] / GL_SCALE_FACTOR); + } + } + } + } +#endif + insertVertexList(sector, startCountInner, mVertexBuffer[sector].size()); + return (vboList(startCount, mVertexBufferStart[sector].size() - startCount, sector)); +} + +int GPUDisplay::DrawGLScene(bool mixAnimation, float mAnimateTime) +{ + if (mChain) { + mIOPtrs = &mChain->mIOPtrs; + mCalib = &mChain->calib(); + } + try { + if (DrawGLScene_internal(mixAnimation, mAnimateTime)) { + return (1); + } + } catch (const std::runtime_error& e) { + return (1); + } + return (0); +} + +int GPUDisplay::DrawGLScene_internal(bool mixAnimation, float mAnimateTime) +{ + bool showTimer = false; + + // Make sure event gets not overwritten during display + if (mAnimateTime < 0) { + mSemLockDisplay.Lock(); + } + + if (!mIOPtrs) { + mNCollissions = 0; + } else if (!mCollisionClusters.size()) { + mNCollissions = std::max(1u, mIOPtrs->nMCInfosTPCCol); + } + + if (!mixAnimation && (mUpdateDLList || mResetScene || !mGlDLrecent) && mIOPtrs) { + disableUnsupportedOptions(); + } + + // Extract global cluster information + if (!mixAnimation && (mUpdateDLList || mResetScene) && mIOPtrs) { + showTimer = true; + mTimerDraw.ResetStart(); + if (mIOPtrs->clustersNative) { + mCurrentClusters = mIOPtrs->clustersNative->nClustersTotal; + } else { + mCurrentClusters = 0; + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + mCurrentClusters += mIOPtrs->nClusterData[iSlice]; + } + } + if (mNMaxClusters < mCurrentClusters) { + mNMaxClusters = mCurrentClusters; + mGlobalPosPtr.reset(new float4[mNMaxClusters]); + mGlobalPos = mGlobalPosPtr.get(); + } + + mCurrentSpacePointsTRD = mIOPtrs->nTRDTracklets; + if (mCurrentSpacePointsTRD > mNMaxSpacePointsTRD) { + mNMaxSpacePointsTRD = mCurrentSpacePointsTRD; + mGlobalPosPtrTRD.reset(new float4[mNMaxSpacePointsTRD]); + mGlobalPosPtrTRD2.reset(new float4[mNMaxSpacePointsTRD]); + mGlobalPosTRD = mGlobalPosPtrTRD.get(); + mGlobalPosTRD2 = mGlobalPosPtrTRD2.get(); + } + + mCurrentClustersITS = mIOPtrs->itsClusters ? mIOPtrs->nItsClusters : 0; + if (mNMaxClustersITS < mCurrentClustersITS) { + mNMaxClustersITS = mCurrentClustersITS; + mGlobalPosPtrITS.reset(new float4[mNMaxClustersITS]); + mGlobalPosITS = mGlobalPosPtrITS.get(); + } + + mCurrentClustersTOF = mIOPtrs->nTOFClusters; + if (mNMaxClustersTOF < mCurrentClustersTOF) { + mNMaxClustersTOF = mCurrentClustersTOF; + mGlobalPosPtrTOF.reset(new float4[mNMaxClustersTOF]); + mGlobalPosTOF = mGlobalPosPtrTOF.get(); + } + + unsigned int nTpcMergedTracks = mConfig.showTPCTracksFromO2Format ? mIOPtrs->nOutputTracksTPCO2 : mIOPtrs->nMergedTracks; + if ((size_t)nTpcMergedTracks > mTRDTrackIds.size()) { + mTRDTrackIds.resize(nTpcMergedTracks); + } + if (mIOPtrs->nItsTracks > mITSStandaloneTracks.size()) { + mITSStandaloneTracks.resize(mIOPtrs->nItsTracks); + } + for (unsigned int i = 0; i < nTpcMergedTracks; i++) { + mTRDTrackIds[i] = -1; + } + for (unsigned int i = 0; i < mIOPtrs->nTRDTracks; i++) { + if (mIOPtrs->trdTracks[i].getNtracklets()) { + mTRDTrackIds[mIOPtrs->trdTracks[i].getRefGlobalTrackIdRaw()] = i; + } + } + if (mIOPtrs->nItsTracks) { + std::fill(mITSStandaloneTracks.begin(), mITSStandaloneTracks.end(), true); + if (mIOPtrs->tpcLinkITS) { + for (unsigned int i = 0; i < nTpcMergedTracks; i++) { + if (mIOPtrs->tpcLinkITS[i] != -1) { + mITSStandaloneTracks[mIOPtrs->tpcLinkITS[i]] = false; + } + } + } + } + + if (mCfgH.trackFilter) { + unsigned int nTracks = mConfig.showTPCTracksFromO2Format ? mIOPtrs->nOutputTracksTPCO2 : mIOPtrs->nMergedTracks; + mTrackFilter.resize(nTracks); + std::fill(mTrackFilter.begin(), mTrackFilter.end(), true); + if (buildTrackFilter()) { + SetInfo("Error running track filter from %s", mConfig.filterMacros[mCfgH.trackFilter - 1].c_str()); + } else { + unsigned int nFiltered = 0; + for (unsigned int i = 0; i < mTrackFilter.size(); i++) { + nFiltered += !mTrackFilter[i]; + } + if (mUpdateTrackFilter) { + SetInfo("Applied track filter %s - filtered %u / %u", mConfig.filterMacros[mCfgH.trackFilter - 1].c_str(), nFiltered, (unsigned int)mTrackFilter.size()); + } + } + } + mUpdateTrackFilter = false; + + mMaxClusterZ = 0; + GPUCA_OPENMP(parallel for num_threads(getNumThreads()) reduction(max : mMaxClusterZ)) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + int row = 0; + unsigned int nCls = mParam->par.earlyTpcTransform ? mIOPtrs->nClusterData[iSlice] : mIOPtrs->clustersNative ? mIOPtrs->clustersNative->nClustersSector[iSlice] : 0; + for (unsigned int i = 0; i < nCls; i++) { + int cid; + if (mParam->par.earlyTpcTransform) { + const auto& cl = mIOPtrs->clusterData[iSlice][i]; + cid = cl.id; + row = cl.row; + } else { + cid = mIOPtrs->clustersNative->clusterOffset[iSlice][0] + i; + while (row < GPUCA_ROW_COUNT && mIOPtrs->clustersNative->clusterOffset[iSlice][row + 1] <= (unsigned int)cid) { + row++; + } + } + if (cid >= mNMaxClusters) { + throw std::runtime_error("Cluster Buffer Size exceeded"); + } + float4* ptr = &mGlobalPos[cid]; + if (mParam->par.earlyTpcTransform) { + const auto& cl = mIOPtrs->clusterData[iSlice][i]; + mParam->Slice2Global(iSlice, (mCfgH.clustersOnNominalRow ? mParam->tpcGeometry.Row2X(row) : cl.x) + mCfgH.xAdd, cl.y, cl.z, &ptr->x, &ptr->y, &ptr->z); + } else { + float x, y, z; + const auto& cln = mIOPtrs->clustersNative->clusters[iSlice][0][i]; + GPUTPCConvertImpl::convert(*mCalib->fastTransform, *mParam, iSlice, row, cln.getPad(), cln.getTime(), x, y, z); + if (mCfgH.clustersOnNominalRow) { + x = mParam->tpcGeometry.Row2X(row); + } + mParam->Slice2Global(iSlice, x + mCfgH.xAdd, y, z, &ptr->x, &ptr->y, &ptr->z); + } + + if (fabsf(ptr->z) > mMaxClusterZ) { + mMaxClusterZ = fabsf(ptr->z); + } + ptr->z += iSlice < 18 ? mCfgH.zAdd : -mCfgH.zAdd; + ptr->x /= GL_SCALE_FACTOR; + ptr->y /= GL_SCALE_FACTOR; + ptr->z /= GL_SCALE_FACTOR; + ptr->w = tCLUSTER; + } + } + + int trdTriggerRecord = -1; + float trdZoffset = 0; + GPUCA_OPENMP(parallel for num_threads(getNumThreads()) reduction(max : mMaxClusterZ) firstprivate(trdTriggerRecord, trdZoffset)) + for (int i = 0; i < mCurrentSpacePointsTRD; i++) { + while (mParam->par.continuousTracking && trdTriggerRecord < (int)mIOPtrs->nTRDTriggerRecords - 1 && mIOPtrs->trdTrackletIdxFirst[trdTriggerRecord + 1] <= i) { + trdTriggerRecord++; + float trdTime = mIOPtrs->trdTriggerTimes[trdTriggerRecord] * 1e3 / o2::constants::lhc::LHCBunchSpacingNS / o2::tpc::constants::LHCBCPERTIMEBIN; + trdZoffset = fabsf(mCalib->fastTransform->convVertexTimeToZOffset(0, trdTime, mParam->par.continuousMaxTimeBin)); + } + const auto& sp = mIOPtrs->trdSpacePoints[i]; + int iSec = trdGeometry().GetSector(mIOPtrs->trdTracklets[i].GetDetector()); + float4* ptr = &mGlobalPosTRD[i]; + mParam->Slice2Global(iSec, sp.getX() + mCfgH.xAdd, sp.getY(), sp.getZ(), &ptr->x, &ptr->y, &ptr->z); + ptr->z += ptr->z > 0 ? trdZoffset : -trdZoffset; + if (fabsf(ptr->z) > mMaxClusterZ) { + mMaxClusterZ = fabsf(ptr->z); + } + ptr->x /= GL_SCALE_FACTOR; + ptr->y /= GL_SCALE_FACTOR; + ptr->z /= GL_SCALE_FACTOR; + ptr->w = tTRDCLUSTER; + ptr = &mGlobalPosTRD2[i]; + mParam->Slice2Global(iSec, sp.getX() + mCfgH.xAdd + 4.5f, sp.getY() + 1.5f * sp.getDy(), sp.getZ(), &ptr->x, &ptr->y, &ptr->z); + ptr->z += ptr->z > 0 ? trdZoffset : -trdZoffset; + if (fabsf(ptr->z) > mMaxClusterZ) { + mMaxClusterZ = fabsf(ptr->z); + } + ptr->x /= GL_SCALE_FACTOR; + ptr->y /= GL_SCALE_FACTOR; + ptr->z /= GL_SCALE_FACTOR; + ptr->w = tTRDCLUSTER; + } + + GPUCA_OPENMP(parallel for num_threads(getNumThreads()) reduction(max : mMaxClusterZ)) + for (int i = 0; i < mCurrentClustersTOF; i++) { +#ifdef GPUCA_HAVE_O2HEADERS + float4* ptr = &mGlobalPosTOF[i]; + mParam->Slice2Global(mIOPtrs->tofClusters[i].getSector(), mIOPtrs->tofClusters[i].getX() + mCfgH.xAdd, mIOPtrs->tofClusters[i].getY(), mIOPtrs->tofClusters[i].getZ(), &ptr->x, &ptr->y, &ptr->z); + float ZOffset = 0; + if (mParam->par.continuousTracking) { + float tofTime = mIOPtrs->tofClusters[i].getTime() * 1e-3 / o2::constants::lhc::LHCBunchSpacingNS / o2::tpc::constants::LHCBCPERTIMEBIN; + ZOffset = fabsf(mCalib->fastTransform->convVertexTimeToZOffset(0, tofTime, mParam->par.continuousMaxTimeBin)); + ptr->z += ptr->z > 0 ? ZOffset : -ZOffset; + } + if (fabsf(ptr->z) > mMaxClusterZ) { + mMaxClusterZ = fabsf(ptr->z); + } + ptr->x /= GL_SCALE_FACTOR; + ptr->y /= GL_SCALE_FACTOR; + ptr->z /= GL_SCALE_FACTOR; + ptr->w = tTOFCLUSTER; +#endif + } + + if (mCurrentClustersITS) { +#ifdef GPUCA_HAVE_O2HEADERS + float itsROFhalfLen = 0; +#ifdef GPUCA_O2_LIB // Not available in standalone benchmark + if (mParam->par.continuousTracking) { + const auto& alpParams = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); + itsROFhalfLen = alpParams.roFrameLengthInBC / (float)o2::tpc::constants::LHCBCPERTIMEBIN / 2; + } +#endif + int i = 0; + for (unsigned int j = 0; j < mIOPtrs->nItsClusterROF; j++) { + float ZOffset = 0; + if (mParam->par.continuousTracking) { + o2::InteractionRecord startIR = o2::InteractionRecord(0, mIOPtrs->settingsTF && mIOPtrs->settingsTF->hasTfStartOrbit ? mIOPtrs->settingsTF->tfStartOrbit : 0); + float itsROFtime = mIOPtrs->itsClusterROF[j].getBCData().differenceInBC(startIR) / (float)o2::tpc::constants::LHCBCPERTIMEBIN; + ZOffset = fabsf(mCalib->fastTransform->convVertexTimeToZOffset(0, itsROFtime + itsROFhalfLen, mParam->par.continuousMaxTimeBin)); + } + if (i != mIOPtrs->itsClusterROF[j].getFirstEntry()) { + throw std::runtime_error("Inconsistent ITS data, number of clusters does not match ROF content"); + } + for (int k = 0; k < mIOPtrs->itsClusterROF[j].getNEntries(); k++) { + float4* ptr = &mGlobalPosITS[i]; + const auto& cl = mIOPtrs->itsClusters[i]; + auto* itsGeo = o2::its::GeometryTGeo::Instance(); + auto p = cl.getXYZGlo(*itsGeo); + ptr->x = p.X(); + ptr->y = p.Y(); + ptr->z = p.Z(); + ptr->z += ptr->z > 0 ? ZOffset : -ZOffset; + if (fabsf(ptr->z) > mMaxClusterZ) { + mMaxClusterZ = fabsf(ptr->z); + } + ptr->x /= GL_SCALE_FACTOR; + ptr->y /= GL_SCALE_FACTOR; + ptr->z /= GL_SCALE_FACTOR; + ptr->w = tITSCLUSTER; + i++; + } + } +#endif + } + + mTimerFPS.ResetStart(); + mFramesDoneFPS = 0; + mFPSScaleadjust = 0; + mGlDLrecent = 0; + mUpdateDLList = 0; + } + + if (!mixAnimation && mOffscreenBuffer.created) { + setFrameBuffer(1, mOffscreenBuffer.fb_id); + } + // Initialize + if (!mixAnimation) { + if (mCfgL.invertColors) { + CHKERR(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); + } else { + CHKERR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer + } + + hmm_mat4 nextViewMatrix = MY_HMM_IDENTITY; + int mMouseWheelTmp = mBackend->mMouseWheel; + mBackend->mMouseWheel = 0; + bool lookOrigin = mCfgR.camLookOrigin ^ mBackend->mKeys[mBackend->KEY_ALT]; + bool yUp = mCfgR.camYUp ^ mBackend->mKeys[mBackend->KEY_CTRL] ^ lookOrigin; + bool rotateModel = mBackend->mKeys[mBackend->KEY_RCTRL] || mBackend->mKeys[mBackend->KEY_RALT]; + bool rotateModelTPC = mBackend->mKeys[mBackend->KEY_RALT]; + + // Calculate rotation / translation scaling factors + float scalefactor = mBackend->mKeys[mBackend->KEY_SHIFT] ? 0.2 : 1.0; + float rotatescalefactor = scalefactor * 0.25f; + if (mCfgL.drawSlice != -1) { + scalefactor *= 0.2f; + } + float sqrdist = sqrtf(sqrtf(mViewMatrixP[12] * mViewMatrixP[12] + mViewMatrixP[13] * mViewMatrixP[13] + mViewMatrixP[14] * mViewMatrixP[14]) / GL_SCALE_FACTOR) * 0.8; + if (sqrdist < 0.2) { + sqrdist = 0.2; + } + if (sqrdist > 5) { + sqrdist = 5; + } + scalefactor *= sqrdist; + + float mixSlaveImage = 0.f; + float time = mAnimateTime; + if (mAnimate && time < 0) { + if (mAnimateScreenshot) { + time = mAnimationFrame / 30.f; + } else { + time = mAnimationTimer.GetCurrentElapsedTime(); + } + + float maxTime = mAnimateVectors[0].back(); + mAnimationFrame++; + if (time >= maxTime) { + time = maxTime; + mAnimate = 0; + SetInfo("Animation finished. (%1.2f seconds, %d frames)", time, mAnimationFrame); + } else { + SetInfo("Running mAnimation: time %1.2f/%1.2f, frames %d", time, maxTime, mAnimationFrame); + } + } + // Perform new rotation / translation + if (mAnimate) { + float vals[8]; + for (int i = 0; i < 8; i++) { + vals[i] = mAnimationSplines[i].evaluate(time); + } + if (mAnimationChangeConfig && mixAnimation == false) { + int base = 0; + int k = mAnimateVectors[0].size() - 1; + while (base < k && time > mAnimateVectors[0][base]) { + base++; + } + if (base > mAnimationLastBase + 1) { + mAnimationLastBase = base - 1; + } + + if (base != mAnimationLastBase && mAnimateVectors[0][mAnimationLastBase] != mAnimateVectors[0][base] && memcmp(&mAnimateConfig[base], &mAnimateConfig[mAnimationLastBase], sizeof(mAnimateConfig[base]))) { + mCfgL = mAnimateConfig[mAnimationLastBase]; + updateConfig(); + setFrameBuffer(1, mMixBuffer.fb_id); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer + DrawGLScene_internal(true, time); + setFrameBuffer(); + mixSlaveImage = 1.f - (time - mAnimateVectors[0][mAnimationLastBase]) / (mAnimateVectors[0][base] - mAnimateVectors[0][mAnimationLastBase]); + } + + if (memcmp(&mAnimateConfig[base], &mCfgL, sizeof(mCfgL))) { + mCfgL = mAnimateConfig[base]; + updateConfig(); + } + } + + if (mCfgL.animationMode != 6) { + if (mCfgL.animationMode & 1) // Rotation from euler angles + { + nextViewMatrix = nextViewMatrix * HMM_Rotate(-vals[4] * 180.f / CAMath::Pi(), {1, 0, 0}) * HMM_Rotate(vals[5] * 180.f / CAMath::Pi(), {0, 1, 0}) * HMM_Rotate(-vals[6] * 180.f / CAMath::Pi(), {0, 0, 1}); + } else { // Rotation from quaternion + const float mag = sqrtf(vals[4] * vals[4] + vals[5] * vals[5] + vals[6] * vals[6] + vals[7] * vals[7]); + if (mag < 0.0001) { + vals[7] = 1; + } else { + for (int i = 0; i < 4; i++) { + vals[4 + i] /= mag; + } + } + + float xx = vals[4] * vals[4], xy = vals[4] * vals[5], xz = vals[4] * vals[6], xw = vals[4] * vals[7], yy = vals[5] * vals[5], yz = vals[5] * vals[6], yw = vals[5] * vals[7], zz = vals[6] * vals[6], zw = vals[6] * vals[7]; + float mat[16] = {1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, 0, 0, 0, 1}; + nextViewMatrix = nextViewMatrix * MY_HMM_FROM(mat); + } + } + if (mCfgL.animationMode & 4) // Compute cartesian translation from sperical coordinates (euler angles) + { + const float r = vals[3], phi = vals[1], theta = vals[2]; + vals[2] = r * cosf(phi) * cosf(theta); + vals[0] = r * sinf(phi) * cosf(theta); + vals[1] = r * sinf(theta); + } else if (mCfgL.animationMode & 2) { // Scale cartesion translation to interpolated radius + float r = sqrtf(vals[0] * vals[0] + vals[1] * vals[1] + vals[2] * vals[2]); + if (fabsf(r) < 0.0001) { + r = 1; + } + r = vals[3] / r; + for (int i = 0; i < 3; i++) { + vals[i] *= r; + } + } + if (mCfgL.animationMode == 6) { + nextViewMatrix = HMM_LookAt({vals[0], vals[1], vals[2]}, {0, 0, 0}, {0, 1, 0}); + } else { + nextViewMatrix = nextViewMatrix * HMM_Translate({-vals[0], -vals[1], -vals[2]}); + } + } else if (mResetScene) { + nextViewMatrix = nextViewMatrix * HMM_Translate({0, 0, mParam->par.continuousTracking ? (-mMaxClusterZ / GL_SCALE_FACTOR - 8) : -8}); + mViewMatrix = MY_HMM_IDENTITY; + mModelMatrix = MY_HMM_IDENTITY; + + mCfgL.pointSize = 2.0; + mCfgL.drawSlice = -1; + mCfgH.xAdd = mCfgH.zAdd = 0; + mCfgR.camLookOrigin = mCfgR.camYUp = false; + mAngleRollOrigin = -1e9; + mCfgR.fov = 45.f; + + mResetScene = 0; + } else { + float moveZ = scalefactor * ((float)mMouseWheelTmp / 150 + (float)(mBackend->mKeys['W'] - mBackend->mKeys['S']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]) * 0.2 * mFPSScale); + float moveY = scalefactor * ((float)(mBackend->mKeys[mBackend->KEY_PAGEDOWN] - mBackend->mKeys[mBackend->KEY_PAGEUP]) * 0.2 * mFPSScale); + float moveX = scalefactor * ((float)(mBackend->mKeys['A'] - mBackend->mKeys['D']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]) * 0.2 * mFPSScale); + float rotRoll = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys['E'] - mBackend->mKeys['F']) * (!mBackend->mKeys[mBackend->KEY_SHIFT]); + float rotYaw = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys[mBackend->KEY_RIGHT] - mBackend->mKeys[mBackend->KEY_LEFT]); + float rotPitch = rotatescalefactor * mFPSScale * 2 * (mBackend->mKeys[mBackend->KEY_DOWN] - mBackend->mKeys[mBackend->KEY_UP]); + + if (mBackend->mMouseDnR && mBackend->mMouseDn) { + moveZ += -scalefactor * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY) / 4; + rotRoll += rotatescalefactor * ((float)mBackend->mouseMvX - (float)mBackend->mMouseDnX); + } else if (mBackend->mMouseDnR) { + moveX += -scalefactor * 0.5 * ((float)mBackend->mMouseDnX - (float)mBackend->mouseMvX) / 4; + moveY += -scalefactor * 0.5 * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY) / 4; + } else if (mBackend->mMouseDn) { + rotYaw += rotatescalefactor * ((float)mBackend->mouseMvX - (float)mBackend->mMouseDnX); + rotPitch += rotatescalefactor * ((float)mBackend->mouseMvY - (float)mBackend->mMouseDnY); + } + + if (mBackend->mKeys['<'] && !mBackend->mKeysShift['<']) { + mAnimationDelay += moveX; + if (mAnimationDelay < 0.05) { + mAnimationDelay = 0.05; + } + moveX = 0.f; + moveY = 0.f; + SetInfo("Animation delay set to %1.2f", mAnimationDelay); + } + + if (yUp) { + mAngleRollOrigin = 0; + } else if (!lookOrigin) { + mAngleRollOrigin = -1e6; + } + if (lookOrigin) { + if (!yUp) { + if (mAngleRollOrigin < -1e6) { + mAngleRollOrigin = yUp ? 0. : -mAngle[2]; + } + mAngleRollOrigin += rotRoll; + nextViewMatrix = nextViewMatrix * HMM_Rotate(mAngleRollOrigin, {0, 0, 1}); + float tmpX = moveX, tmpY = moveY; + moveX = tmpX * cosf(mAngle[2]) - tmpY * sinf(mAngle[2]); + moveY = tmpX * sinf(mAngle[2]) + tmpY * cosf(mAngle[2]); + } + + const float x = mXYZ[0], y = mXYZ[1], z = mXYZ[2]; + float r = sqrtf(x * x + +y * y + z * z); + float r2 = sqrtf(x * x + z * z); + float phi = atan2f(z, x); + phi += moveX * 0.1f; + float theta = atan2f(mXYZ[1], r2); + theta -= moveY * 0.1f; + const float max_theta = CAMath::Pi() / 2 - 0.01; + if (theta >= max_theta) { + theta = max_theta; + } else if (theta <= -max_theta) { + theta = -max_theta; + } + if (moveZ >= r - 0.1) { + moveZ = r - 0.1; + } + r -= moveZ; + r2 = r * cosf(theta); + mXYZ[0] = r2 * cosf(phi); + mXYZ[2] = r2 * sinf(phi); + mXYZ[1] = r * sinf(theta); + + if (yUp) { + nextViewMatrix = MY_HMM_IDENTITY; + } + nextViewMatrix = nextViewMatrix * HMM_LookAt({mXYZ[0], mXYZ[1], mXYZ[2]}, {0, 0, 0}, {0, 1, 0}); + } else { + nextViewMatrix = nextViewMatrix * HMM_Translate({moveX, moveY, moveZ}); + if (!rotateModel) { + if (rotYaw != 0.f) { + nextViewMatrix = nextViewMatrix * HMM_Rotate(rotYaw, {0, 1, 0}); + } + if (rotPitch != 0.f) { + nextViewMatrix = nextViewMatrix * HMM_Rotate(rotPitch, {1, 0, 0}); + } + if (!yUp && rotRoll != 0.f) { + nextViewMatrix = nextViewMatrix * HMM_Rotate(rotRoll, {0, 0, 1}); + } + } + nextViewMatrix = nextViewMatrix * mViewMatrix; // Apply previous translation / rotation + if (yUp) { + calcXYZ(&nextViewMatrix.Elements[0][0]); + nextViewMatrix = HMM_Rotate(mAngle[2] * 180.f / CAMath::Pi(), {0, 0, 1}) * nextViewMatrix; + } + if (rotateModel) { + if (rotYaw != 0.f) { + mModelMatrix = HMM_Rotate(rotYaw, {nextViewMatrix.Elements[0][1], nextViewMatrix.Elements[1][1], nextViewMatrix.Elements[2][1]}) * mModelMatrix; + } + if (rotPitch != 0.f) { + mModelMatrix = HMM_Rotate(rotPitch, {nextViewMatrix.Elements[0][0], nextViewMatrix.Elements[1][0], nextViewMatrix.Elements[2][0]}) * mModelMatrix; + } + if (rotRoll != 0.f) { + if (rotateModelTPC) { + mModelMatrix = HMM_Rotate(-rotRoll, {0, 0, 1}) * mModelMatrix; + } else { + mModelMatrix = HMM_Rotate(-rotRoll, {nextViewMatrix.Elements[0][2], nextViewMatrix.Elements[1][2], nextViewMatrix.Elements[2][2]}) * mModelMatrix; + } + } + } + } + + // Graphichs Options + float minSize = 0.4 / (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1); + int deltaLine = mBackend->mKeys['+'] * mBackend->mKeysShift['+'] - mBackend->mKeys['-'] * mBackend->mKeysShift['-']; + mCfgL.lineWidth += (float)deltaLine * mFPSScale * 0.02 * mCfgL.lineWidth; + if (mCfgL.lineWidth < minSize) { + mCfgL.lineWidth = minSize; + } + if (deltaLine) { + SetInfo("%s line width: %f", deltaLine > 0 ? "Increasing" : "Decreasing", mCfgL.lineWidth); + } + minSize *= 2; + int deltaPoint = mBackend->mKeys['+'] * (!mBackend->mKeysShift['+']) - mBackend->mKeys['-'] * (!mBackend->mKeysShift['-']); + mCfgL.pointSize += (float)deltaPoint * mFPSScale * 0.02 * mCfgL.pointSize; + if (mCfgL.pointSize < minSize) { + mCfgL.pointSize = minSize; + } + if (deltaPoint) { + SetInfo("%s point size: %f", deltaPoint > 0 ? "Increasing" : "Decreasing", mCfgL.pointSize); + } + } + + // Store position + if (mAnimateTime < 0) { + mViewMatrix = nextViewMatrix; + calcXYZ(mViewMatrixP); + } + + if (mBackend->mMouseDn || mBackend->mMouseDnR) { + mBackend->mMouseDnX = mBackend->mouseMvX; + mBackend->mMouseDnY = mBackend->mouseMvY; + } +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (mCfgL.smoothPoints && !mCfgR.openGLCore) { + CHKERR(glEnable(GL_POINT_SMOOTH)); + } else { + CHKERR(glDisable(GL_POINT_SMOOTH)); + } + if (mCfgL.smoothLines && !mCfgR.openGLCore) { + CHKERR(glEnable(GL_LINE_SMOOTH)); + } else { + CHKERR(glDisable(GL_LINE_SMOOTH)); + } +#endif + CHKERR(glEnable(GL_BLEND)); + CHKERR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + CHKERR(glPointSize(mCfgL.pointSize * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1))); + CHKERR(glLineWidth(mCfgL.lineWidth * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1))); + + // Prepare Event + if (!mGlDLrecent && mIOPtrs) { + for (int i = 0; i < NSLICES; i++) { + mVertexBuffer[i].clear(); + mVertexBufferStart[i].clear(); + mVertexBufferCount[i].clear(); + } + + for (int i = 0; i < mCurrentClusters; i++) { + mGlobalPos[i].w = tCLUSTER; + } + for (int i = 0; i < mCurrentSpacePointsTRD; i++) { + mGlobalPosTRD[i].w = tTRDCLUSTER; + } + + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int i = 0; i < N_POINTS_TYPE; i++) { + mGlDLPoints[iSlice][i].resize(mNCollissions); + } + for (int i = 0; i < N_FINAL_TYPE; i++) { + mGlDLFinal[iSlice].resize(mNCollissions); + } + } + GPUCA_OPENMP(parallel num_threads(getNumThreads())) + { +#ifdef WITH_OPENMP + int numThread = omp_get_thread_num(); + int numThreads = omp_get_num_threads(); +#else + int numThread = 0, numThreads = 1; +#endif + if (mChain && (mChain->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSliceTracking)) { + GPUCA_OPENMP(for) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + GPUTPCTracker& tracker = (GPUTPCTracker&)sliceTracker(iSlice); + tracker.SetPointersDataLinks(tracker.LinkTmpMemory()); + mGlDLLines[iSlice][tINITLINK] = DrawLinks(tracker, tINITLINK, true); + tracker.SetPointersDataLinks(mChain->rec()->Res(tracker.MemoryResLinks()).Ptr()); + } + GPUCA_OPENMP(barrier) + + GPUCA_OPENMP(for) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + const GPUTPCTracker& tracker = sliceTracker(iSlice); + + mGlDLLines[iSlice][tLINK] = DrawLinks(tracker, tLINK); + mGlDLLines[iSlice][tSEED] = DrawSeeds(tracker); + mGlDLLines[iSlice][tTRACKLET] = DrawTracklets(tracker); + mGlDLLines[iSlice][tSLICETRACK] = DrawTracks(tracker, 0); + mGlDLGrid[iSlice] = DrawGrid(tracker); + if (iSlice < NSLICES / 2) { + mGlDLGridTRD[iSlice] = DrawGridTRD(iSlice); + } + } + GPUCA_OPENMP(barrier) + + GPUCA_OPENMP(for) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + const GPUTPCTracker& tracker = sliceTracker(iSlice); + mGlDLLines[iSlice][tGLOBALTRACK] = DrawTracks(tracker, 1); + } + GPUCA_OPENMP(barrier) + } + mThreadTracks[numThread].resize(mNCollissions); + for (int i = 0; i < mNCollissions; i++) { + for (int j = 0; j < NSLICES; j++) { + for (int k = 0; k < 2; k++) { + mThreadTracks[numThread][i][j][k].clear(); + } + } + } + if (mConfig.showTPCTracksFromO2Format) { + unsigned int col = 0; + GPUCA_OPENMP(for) + for (unsigned int i = 0; i < mIOPtrs->nOutputTracksTPCO2; i++) { + uint8_t sector, row; + if (mIOPtrs->clustersNative) { + mIOPtrs->outputTracksTPCO2[i].getCluster(mIOPtrs->outputClusRefsTPCO2, 0, *mIOPtrs->clustersNative, sector, row); + } else { + sector = 0; + } + mThreadTracks[numThread][col][sector][0].emplace_back(i); + } + } else { + GPUCA_OPENMP(for) + for (unsigned int i = 0; i < mIOPtrs->nMergedTracks; i++) { + const GPUTPCGMMergedTrack* track = &mIOPtrs->mergedTracks[i]; + if (track->NClusters() == 0) { + continue; + } + if (mCfgH.hideRejectedTracks && !track->OK()) { + continue; + } + int slice = mIOPtrs->mergedTrackHits[track->FirstClusterRef() + track->NClusters() - 1].slice; + unsigned int col = 0; + if (mCollisionClusters.size() > 1) { + int label = mQA ? mQA->GetMCTrackLabel(i) : -1; + while (col < mCollisionClusters.size() && mCollisionClusters[col][NSLICES] < label) { + col++; + } + } + mThreadTracks[numThread][col][slice][0].emplace_back(i); + } + } + for (unsigned int col = 0; col < mIOPtrs->nMCInfosTPCCol; col++) { + GPUCA_OPENMP(for) + for (unsigned int i = mIOPtrs->mcInfosTPCCol[col].first; i < mIOPtrs->mcInfosTPCCol[col].first + mIOPtrs->mcInfosTPCCol[col].num; i++) { + const GPUTPCMCInfo& mc = mIOPtrs->mcInfosTPC[i]; + if (mc.charge == 0.f) { + continue; + } + if (mc.pid < 0) { + continue; + } + + float alpha = atan2f(mc.y, mc.x); + if (alpha < 0) { + alpha += 2 * CAMath::Pi(); + } + int slice = alpha / (2 * CAMath::Pi()) * 18; + if (mc.z < 0) { + slice += 18; + } + mThreadTracks[numThread][col][slice][1].emplace_back(i); + } + } + GPUCA_OPENMP(barrier) + + GPUTPCGMPropagator prop; + prop.SetMaxSinPhi(.999); + prop.SetMaterialTPC(); + prop.SetPolynomialField(&mParam->polynomialField); + + GPUCA_OPENMP(for) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int iCol = 0; iCol < mNCollissions; iCol++) { + mThreadBuffers[numThread].clear(); + for (int iSet = 0; iSet < numThreads; iSet++) { +#ifdef GPUCA_HAVE_O2HEADERS + if (mConfig.showTPCTracksFromO2Format) { + DrawFinal<o2::tpc::TrackTPC>(iSlice, iCol, &prop, mThreadTracks[iSet][iCol][iSlice], mThreadBuffers[numThread]); + } else +#endif + { + DrawFinal<GPUTPCGMMergedTrack>(iSlice, iCol, &prop, mThreadTracks[iSet][iCol][iSlice], mThreadBuffers[numThread]); + } + } + vboList* list = &mGlDLFinal[iSlice][iCol][0]; + for (int i = 0; i < N_FINAL_TYPE; i++) { + size_t startCount = mVertexBufferStart[iSlice].size(); + for (unsigned int j = 0; j < mThreadBuffers[numThread].start[i].size(); j++) { + mVertexBufferStart[iSlice].emplace_back(mThreadBuffers[numThread].start[i][j]); + mVertexBufferCount[iSlice].emplace_back(mThreadBuffers[numThread].count[i][j]); + } + list[i] = vboList(startCount, mVertexBufferStart[iSlice].size() - startCount, iSlice); + } + } + } + + GPUCA_OPENMP(barrier) + GPUCA_OPENMP(for) + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int i = 0; i < N_POINTS_TYPE_TPC; i++) { + for (int iCol = 0; iCol < mNCollissions; iCol++) { + mGlDLPoints[iSlice][i][iCol] = DrawClusters(iSlice, i, iCol); + } + } + } + } + // End omp parallel + + mGlDLFinalITS = DrawFinalITS(); + + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int i = N_POINTS_TYPE_TPC; i < N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD; i++) { + for (int iCol = 0; iCol < mNCollissions; iCol++) { + mGlDLPoints[iSlice][i][iCol] = DrawSpacePointsTRD(iSlice, i, iCol); + } + } + } + + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int i = N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD; i < N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD + N_POINTS_TYPE_TOF; i++) { + for (int iCol = 0; iCol < mNCollissions; iCol++) { + mGlDLPoints[iSlice][i][iCol] = DrawSpacePointsTOF(iSlice, i, iCol); + } + } + break; // TODO: Only slice 0 filled for now + } + + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + for (int i = N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD + N_POINTS_TYPE_TOF; i < N_POINTS_TYPE_TPC + N_POINTS_TYPE_TRD + N_POINTS_TYPE_TOF + N_POINTS_TYPE_ITS; i++) { + for (int iCol = 0; iCol < mNCollissions; iCol++) { + mGlDLPoints[iSlice][i][iCol] = DrawSpacePointsITS(iSlice, i, iCol); + } + } + break; // TODO: Only slice 0 filled for now + } + + mGlDLrecent = 1; + size_t totalVertizes = 0; + for (int i = 0; i < NSLICES; i++) { + totalVertizes += mVertexBuffer[i].size(); + } + + // TODO: Check if this can be parallelized + mUseMultiVBO = (totalVertizes * sizeof(mVertexBuffer[0][0]) >= 0x100000000ll); + if (mUseMultiVBO) { + for (int i = 0; i < NSLICES; i++) { + CHKERR(glNamedBufferData(mVBOId[i], mVertexBuffer[i].size() * sizeof(mVertexBuffer[i][0]), mVertexBuffer[i].data(), GL_STATIC_DRAW)); + mVertexBuffer[i].clear(); + } + } else { + size_t totalYet = mVertexBuffer[0].size(); + mVertexBuffer[0].resize(totalVertizes); + for (int i = 1; i < NSLICES; i++) { + for (unsigned int j = 0; j < mVertexBufferStart[i].size(); j++) { + mVertexBufferStart[i][j] += totalYet; + } + memcpy(&mVertexBuffer[0][totalYet], &mVertexBuffer[i][0], mVertexBuffer[i].size() * sizeof(mVertexBuffer[i][0])); + totalYet += mVertexBuffer[i].size(); + mVertexBuffer[i].clear(); + } + CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0])); // Bind ahead of time, since it is not going to change + CHKERR(glNamedBufferData(mVBOId[0], totalVertizes * sizeof(mVertexBuffer[0][0]), mVertexBuffer[0].data(), GL_STATIC_DRAW)); + mVertexBuffer[0].clear(); + } + + if (mCfgR.useGLIndirectDraw) { + mCmdBuffer.clear(); + for (int iSlice = 0; iSlice < NSLICES; iSlice++) { + mIndirectSliceOffset[iSlice] = mCmdBuffer.size(); + for (unsigned int k = 0; k < mVertexBufferStart[iSlice].size(); k++) { + mCmdBuffer.emplace_back(mVertexBufferCount[iSlice][k], 1, mVertexBufferStart[iSlice][k], 0); + } + } + CHKERR(glBufferData(GL_DRAW_INDIRECT_BUFFER, mCmdBuffer.size() * sizeof(mCmdBuffer[0]), mCmdBuffer.data(), GL_STATIC_DRAW)); + } + + if (showTimer) { + printf("Event visualization time: %'d us (vertices %'lld / %'lld bytes)\n", (int)(mTimerDraw.GetCurrentElapsedTime() * 1000000.), (long long int)totalVertizes, (long long int)(totalVertizes * sizeof(mVertexBuffer[0][0]))); + } + } + + // Draw Event + mNDrawCalls = 0; +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + CHKERR(glEnableClientState(GL_VERTEX_ARRAY)); + CHKERR(glVertexPointer(3, GL_FLOAT, 0, nullptr)); + } else +#endif + { + CHKERR(glBindVertexArray(mVertexArray)); + CHKERR(glUseProgram(mShaderProgram)); + CHKERR(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr)); + CHKERR(glEnableVertexAttribArray(0)); + } + + { + const float zFar = ((mParam->par.continuousTracking ? (mMaxClusterZ / GL_SCALE_FACTOR) : 8.f) + 50.f) * 2.f; + const hmm_mat4 proj = HMM_Perspective(mCfgR.fov, (GLfloat)mScreenwidth / (GLfloat)mScreenheight, 0.1f, zFar); + nextViewMatrix = nextViewMatrix * mModelMatrix; +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + CHKERR(glMatrixMode(GL_PROJECTION)); + CHKERR(glLoadMatrixf(&proj.Elements[0][0])); + CHKERR(glMatrixMode(GL_MODELVIEW)); + CHKERR(glLoadMatrixf(&nextViewMatrix.Elements[0][0])); + } else +#endif + { + const hmm_mat4 modelViewProj = proj * nextViewMatrix; + CHKERR(glUniformMatrix4fv(mModelViewProjId, 1, GL_FALSE, &modelViewProj.Elements[0][0])); + } + } + +#define LOOP_SLICE for (int iSlice = (mCfgL.drawSlice == -1 ? 0 : mCfgL.drawRelatedSlices ? (mCfgL.drawSlice % (NSLICES / 4)) : mCfgL.drawSlice); iSlice < NSLICES; iSlice += (mCfgL.drawSlice == -1 ? 1 : mCfgL.drawRelatedSlices ? (NSLICES / 4) : NSLICES)) +#define LOOP_SLICE2 for (int iSlice = (mCfgL.drawSlice == -1 ? 0 : mCfgL.drawRelatedSlices ? (mCfgL.drawSlice % (NSLICES / 4)) : mCfgL.drawSlice) % (NSLICES / 2); iSlice < NSLICES / 2; iSlice += (mCfgL.drawSlice == -1 ? 1 : mCfgL.drawRelatedSlices ? (NSLICES / 4) : NSLICES)) +#define LOOP_COLLISION for (int iCol = (mCfgL.showCollision == -1 ? 0 : mCfgL.showCollision); iCol < mNCollissions; iCol += (mCfgL.showCollision == -1 ? 1 : mNCollissions)) +#define LOOP_COLLISION_COL(cmd) \ + LOOP_COLLISION \ + { \ + if (mCfgL.colorCollisions) { \ + SetCollisionColor(iCol); \ + } \ + cmd; \ + } + + if (mCfgL.drawGrid) { + if (mCfgL.drawTPC) { + SetColorGrid(); + LOOP_SLICE drawVertices(mGlDLGrid[iSlice], GL_LINES); + } + if (mCfgL.drawTRD) { + SetColorGridTRD(); + LOOP_SLICE2 drawVertices(mGlDLGridTRD[iSlice], GL_LINES); + } + } + if (mCfgL.drawClusters) { + if (mCfgL.drawTRD) { + SetColorTRD(); + CHKERR(glLineWidth(mCfgL.lineWidth * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1) * 2)); + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRDCLUSTER][iCol], GL_LINES)); + if (mCfgL.drawFinal && mCfgL.colorClusters) { + SetColorFinal(); + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRDATTACHED][iCol], GL_LINES)); + CHKERR(glLineWidth(mCfgL.lineWidth * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1))); + } + if (mCfgL.drawTOF) { + SetColorTOF(); + CHKERR(glPointSize(mCfgL.pointSize * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1) * 2)); + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[0][tTOFCLUSTER][0], GL_POINTS)); + CHKERR(glPointSize(mCfgL.pointSize * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1))); + } + if (mCfgL.drawITS) { + SetColorITS(); + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[0][tITSCLUSTER][0], GL_POINTS)); + } + if (mCfgL.drawTPC) { + SetColorClusters(); + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tCLUSTER][iCol], GL_POINTS)); + + if (mCfgL.drawInitLinks) { + if (mCfgL.excludeClusters) { + goto skip1; + } + if (mCfgL.colorClusters) { + SetColorInitLinks(); + } + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tINITLINK][iCol], GL_POINTS)); + + if (mCfgL.drawLinks) { + if (mCfgL.excludeClusters) { + goto skip1; + } + if (mCfgL.colorClusters) { + SetColorLinks(); + } + } else { + SetColorClusters(); + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tLINK][iCol], GL_POINTS)); + + if (mCfgL.drawSeeds) { + if (mCfgL.excludeClusters) { + goto skip1; + } + if (mCfgL.colorClusters) { + SetColorSeeds(); + } + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tSEED][iCol], GL_POINTS)); + + skip1: + SetColorClusters(); + if (mCfgL.drawTracklets) { + if (mCfgL.excludeClusters) { + goto skip2; + } + if (mCfgL.colorClusters) { + SetColorTracklets(); + } + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tTRACKLET][iCol], GL_POINTS)); + + if (mCfgL.drawTracks) { + if (mCfgL.excludeClusters) { + goto skip2; + } + if (mCfgL.colorClusters) { + SetColorTracks(); + } + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tSLICETRACK][iCol], GL_POINTS)); + + skip2:; + if (mCfgL.drawGlobalTracks) { + if (mCfgL.excludeClusters) { + goto skip3; + } + if (mCfgL.colorClusters) { + SetColorGlobalTracks(); + } + } else { + SetColorClusters(); + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tGLOBALTRACK][iCol], GL_POINTS)); + SetColorClusters(); + + if (mCfgL.drawFinal && mCfgL.propagateTracks < 2) { + if (mCfgL.excludeClusters) { + goto skip3; + } + if (mCfgL.colorClusters) { + SetColorFinal(); + } + } + LOOP_SLICE LOOP_COLLISION_COL(drawVertices(mGlDLPoints[iSlice][tFINALTRACK][iCol], GL_POINTS)); + skip3:; + } + } + + if (!mCfgH.clustersOnly && !mCfgL.excludeClusters) { + if (mCfgL.drawTPC) { + if (mCfgL.drawInitLinks) { + SetColorInitLinks(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tINITLINK], GL_LINES); + } + if (mCfgL.drawLinks) { + SetColorLinks(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tLINK], GL_LINES); + } + if (mCfgL.drawSeeds) { + SetColorSeeds(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tSEED], GL_LINE_STRIP); + } + if (mCfgL.drawTracklets) { + SetColorTracklets(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tTRACKLET], GL_LINE_STRIP); + } + if (mCfgL.drawTracks) { + SetColorTracks(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tSLICETRACK], GL_LINE_STRIP); + } + if (mCfgL.drawGlobalTracks) { + SetColorGlobalTracks(); + LOOP_SLICE drawVertices(mGlDLLines[iSlice][tGLOBALTRACK], GL_LINE_STRIP); + } + } + if (mCfgL.drawFinal) { + SetColorFinal(); + LOOP_SLICE LOOP_COLLISION + { + if (mCfgL.colorCollisions) { + SetCollisionColor(iCol); + } + if (mCfgL.propagateTracks < 2) { + drawVertices(mGlDLFinal[iSlice][iCol][0], GL_LINE_STRIP); + } + if (mCfgL.propagateTracks > 0 && mCfgL.propagateTracks < 3) { + drawVertices(mGlDLFinal[iSlice][iCol][1], GL_LINE_STRIP); + } + if (mCfgL.propagateTracks == 2) { + drawVertices(mGlDLFinal[iSlice][iCol][2], GL_LINE_STRIP); + } + if (mCfgL.propagateTracks == 3) { + drawVertices(mGlDLFinal[iSlice][iCol][3], GL_LINE_STRIP); + } + } + if (mCfgH.drawTracksAndFilter ? (mCfgH.drawTPCTracks || mCfgH.drawTRDTracks || mCfgH.drawTOFTracks) : mCfgH.drawITSTracks) { + drawVertices(mGlDLFinalITS, GL_LINE_STRIP); + } + } + if (mCfgH.markClusters || mCfgH.markAdjacentClusters || mCfgH.markFakeClusters) { + if (mCfgH.markFakeClusters) { + CHKERR(glPointSize(mCfgL.pointSize * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1) * 3)); + } + SetColorMarked(); + LOOP_SLICE LOOP_COLLISION drawVertices(mGlDLPoints[iSlice][tMARKED][iCol], GL_POINTS); + if (mCfgH.markFakeClusters) { + CHKERR(glPointSize(mCfgL.pointSize * (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1))); + } + } + } +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + CHKERR(glDisableClientState(GL_VERTEX_ARRAY)); + } else +#endif + { + CHKERR(glDisableVertexAttribArray(0)); + CHKERR(glUseProgram(0)); + } + + if (mixSlaveImage > 0) { +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + hmm_mat4 proj = HMM_Orthographic(0.f, mRenderwidth, 0.f, mRenderheight, -1.f, 1.f); + glLoadMatrixf(&proj.Elements[0][0]); + CHKERR(glEnable(GL_TEXTURE_2D)); + glDisable(GL_DEPTH_TEST); + CHKERR(glBindTexture(GL_TEXTURE_2D, mMixBuffer.fbCol_id)); + glColor4f(1, 1, 1, mixSlaveImage); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex3f(0, 0, 0); + glTexCoord2f(0, 1); + glVertex3f(0, mRenderheight, 0); + glTexCoord2f(1, 1); + glVertex3f(mRenderwidth, mRenderheight, 0); + glTexCoord2f(1, 0); + glVertex3f(mRenderwidth, 0, 0); + glEnd(); + glColor4f(1, 1, 1, 0); + CHKERR(glDisable(GL_TEXTURE_2D)); + setDepthBuffer(); + } else +#endif + { + GPUWarning("Image mixing unsupported in OpenGL CORE profile"); + } + } + + if (mixAnimation) { + glColorMask(false, false, false, true); + glClear(GL_COLOR_BUFFER_BIT); + glColorMask(true, true, true, true); + } else if (mOffscreenBuffer.created) { + setFrameBuffer(); + GLuint srcid = mOffscreenBuffer.fb_id; + if (mCfgR.drawQualityMSAA > 1 && mCfgR.drawQualityDownsampleFSAA > 1) { + CHKERR(glBlitNamedFramebuffer(srcid, mOffscreenBufferNoMSAA.fb_id, 0, 0, mRenderwidth, mRenderheight, 0, 0, mRenderwidth, mRenderheight, GL_COLOR_BUFFER_BIT, GL_LINEAR)); + srcid = mOffscreenBufferNoMSAA.fb_id; + } + CHKERR(glBlitNamedFramebuffer(srcid, mMainBufferStack.back(), 0, 0, mRenderwidth, mRenderheight, 0, 0, mScreenwidth, mScreenheight, GL_COLOR_BUFFER_BIT, GL_LINEAR)); + } + + if (mAnimate && mAnimateScreenshot && mAnimateTime < 0) { + char mAnimateScreenshotFile[48]; + sprintf(mAnimateScreenshotFile, "mAnimation%d_%05d.bmp", mAnimationExport, mAnimationFrame); + DoScreenshot(mAnimateScreenshotFile, time); + } + + if (mAnimateTime < 0) { + mFramesDone++; + mFramesDoneFPS++; + double fpstime = mTimerFPS.GetCurrentElapsedTime(); + char info[1024]; + float fps = (double)mFramesDoneFPS / fpstime; + sprintf(info, + "FPS: %6.2f (Slice: %d, 1:Clusters %d, 2:Prelinks %d, 3:Links %d, 4:Seeds %d, 5:Tracklets %d, 6:Tracks %d, 7:GTracks %d, 8:Merger %d) (%d frames, %d draw calls) " + "(X %1.2f Y %1.2f Z %1.2f / R %1.2f Phi %1.1f Theta %1.1f) / Yaw %1.1f Pitch %1.1f Roll %1.1f)", + fps, mCfgL.drawSlice, mCfgL.drawClusters, mCfgL.drawInitLinks, mCfgL.drawLinks, mCfgL.drawSeeds, mCfgL.drawTracklets, mCfgL.drawTracks, mCfgL.drawGlobalTracks, mCfgL.drawFinal, mFramesDone, mNDrawCalls, mXYZ[0], mXYZ[1], mXYZ[2], mRPhiTheta[0], mRPhiTheta[1] * 180 / CAMath::Pi(), + mRPhiTheta[2] * 180 / CAMath::Pi(), mAngle[1] * 180 / CAMath::Pi(), mAngle[0] * 180 / CAMath::Pi(), mAngle[2] * 180 / CAMath::Pi()); + if (fpstime > 1.) { + if (mPrintInfoText & 2) { + GPUInfo("%s", info); + } + if (mFPSScaleadjust++) { + mFPSScale = 60 / fps; + } + mTimerFPS.ResetStart(); + mFramesDoneFPS = 0; + } + + if (mPrintInfoText & 1) { + setFrameBuffer(0, 0); + showInfo(info); + setFrameBuffer(-2); + } + } + + if (mAnimateTime < 0) { + mSemLockDisplay.Unlock(); + } + + return (0); +} + +void GPUDisplay::DoScreenshot(char* filename, float mAnimateTime) +{ + int SCALE_Y = mCfgR.screenshotScaleFactor, SCALE_X = mCfgR.screenshotScaleFactor; + + float tmpPointSize = mCfgL.pointSize; + float tmpLineWidth = mCfgL.lineWidth; + mCfgL.pointSize *= (float)(SCALE_X + SCALE_Y) / 2.; + mCfgL.lineWidth *= (float)(SCALE_X + SCALE_Y) / 2.; + + int oldWidth = mScreenwidth, oldHeight = mScreenheight; + GLfb screenshotBuffer; + + bool needBuffer = SCALE_X != 1 || SCALE_Y != 1; + + if (needBuffer) { + deleteFB(mMixBuffer); + mScreenwidth *= SCALE_X; + mScreenheight *= SCALE_Y; + mRenderwidth = mScreenwidth; + mRenderheight = mScreenheight; + createFB(screenshotBuffer, 0, 1, false); // Create screenshotBuffer of size mScreenwidth * SCALE, mRenderwidth * SCALE + UpdateOffscreenBuffers(); // Create other buffers of size mScreenwidth * SCALE * downscale, ... + setFrameBuffer(1, screenshotBuffer.fb_id); + glViewport(0, 0, mRenderwidth, mRenderheight); + DrawGLScene(false, mAnimateTime); + } + size_t size = 4 * mScreenwidth * mScreenheight; + unsigned char* pixels = new unsigned char[size]; + CHKERR(glPixelStorei(GL_PACK_ALIGNMENT, 1)); + CHKERR(glReadBuffer(needBuffer ? GL_COLOR_ATTACHMENT0 : GL_BACK)); + CHKERR(glReadPixels(0, 0, mScreenwidth, mScreenheight, GL_BGRA, GL_UNSIGNED_BYTE, pixels)); + + if (filename) { + FILE* fp = fopen(filename, "w+b"); + + BITMAPFILEHEADER bmpFH; + BITMAPINFOHEADER bmpIH; + memset(&bmpFH, 0, sizeof(bmpFH)); + memset(&bmpIH, 0, sizeof(bmpIH)); + + bmpFH.bfType = 19778; //"BM" + bmpFH.bfSize = sizeof(bmpFH) + sizeof(bmpIH) + size; + bmpFH.bfOffBits = sizeof(bmpFH) + sizeof(bmpIH); + + bmpIH.biSize = sizeof(bmpIH); + bmpIH.biWidth = mScreenwidth; + bmpIH.biHeight = mScreenheight; + bmpIH.biPlanes = 1; + bmpIH.biBitCount = 32; + bmpIH.biCompression = BI_RGB; + bmpIH.biSizeImage = size; + bmpIH.biXPelsPerMeter = 5670; + bmpIH.biYPelsPerMeter = 5670; + + fwrite(&bmpFH, 1, sizeof(bmpFH), fp); + fwrite(&bmpIH, 1, sizeof(bmpIH), fp); + fwrite(pixels, 1, size, fp); + fclose(fp); + } + delete[] pixels; + + mCfgL.pointSize = tmpPointSize; + mCfgL.lineWidth = tmpLineWidth; + if (needBuffer) { + setFrameBuffer(); + deleteFB(screenshotBuffer); + mScreenwidth = oldWidth; + mScreenheight = oldHeight; + UpdateOffscreenBuffers(); + glViewport(0, 0, mRenderwidth, mRenderheight); + DrawGLScene(false, mAnimateTime); + } +} + +void GPUDisplay::showInfo(const char* info) +{ +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + hmm_mat4 proj = HMM_Orthographic(0.f, mScreenwidth, 0.f, mScreenheight, -1, 1); + glLoadMatrixf(&proj.Elements[0][0]); + glViewport(0, 0, mScreenwidth, mScreenheight); + } +#endif + float colorValue = mCfgL.invertColors ? 0.f : 1.f; + mBackend->OpenGLPrint(info, 40.f, 40.f, colorValue, colorValue, colorValue, 1); + if (mInfoText2Timer.IsRunning()) { + if (mInfoText2Timer.GetCurrentElapsedTime() >= 6) { + mInfoText2Timer.Reset(); + } else { + mBackend->OpenGLPrint(mInfoText2, 40.f, 20.f, colorValue, colorValue, colorValue, 6 - mInfoText2Timer.GetCurrentElapsedTime()); + } + } + if (mInfoHelpTimer.IsRunning()) { + if (mInfoHelpTimer.GetCurrentElapsedTime() >= 6) { + mInfoHelpTimer.Reset(); + } else { + PrintGLHelpText(colorValue); + } + } +#ifndef GPUCA_DISPLAY_OPENGL_CORE + if (!mCfgR.openGLCore) { + glViewport(0, 0, mRenderwidth, mRenderheight); + } +#endif +} + +void GPUDisplay::ShowNextEvent(const GPUTrackingInOutPointers* ptrs) +{ + if (ptrs) { + mIOPtrs = ptrs; + } + if (mMaxClusterZ <= 0) { + mResetScene = true; + } + mSemLockDisplay.Unlock(); + mBackend->mNeedUpdate = 1; + mUpdateDLList = true; +} + +void GPUDisplay::WaitForNextEvent() { mSemLockDisplay.Lock(); } + +int GPUDisplay::StartDisplay() +{ + if (mBackend->StartDisplay()) { + return (1); + } + while (mInitResult == 0) { + Sleep(10); + } + return (mInitResult != 1); +} + +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplay.h b/GPU/GPUTracking/display/GPUDisplay.h similarity index 79% rename from GPU/GPUTracking/Standalone/display/GPUDisplay.h rename to GPU/GPUTracking/display/GPUDisplay.h index 565b3af52c2e8..904aaa5ece6ee 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplay.h +++ b/GPU/GPUTracking/display/GPUDisplay.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,15 +36,6 @@ #include "GPUSettings.h" #include "GPUDisplayBackend.h" -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -class GPUChainTracking; -class GPUQA; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - #ifndef GPUCA_BUILD_EVENT_DISPLAY namespace GPUCA_NAMESPACE @@ -53,16 +45,16 @@ namespace gpu class GPUDisplay { public: - GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa) {} + GPUDisplay(void* backend, void* chain, void* qa, const void* param = nullptr, const void* calib = nullptr, const void* config = nullptr) {} ~GPUDisplay() = default; GPUDisplay(const GPUDisplay&) = delete; int StartDisplay() { return 1; } - void ShowNextEvent() {} + void ShowNextEvent(const GPUTrackingInOutPointers* ptrs = nullptr) {} void WaitForNextEvent() {} void SetCollisionFirstCluster(unsigned int collision, int slice, int cluster) {} - void HandleKeyRelease(unsigned char key) {} + void HandleKey(unsigned char key) {} int DrawGLScene(bool mixAnimation = false, float mAnimateTime = -1.f) { return 1; } void HandleSendKey(int key) {} int InitGL(bool initFailure = false) { return 1; } @@ -90,20 +82,21 @@ namespace gpu { class GPUTPCTracker; struct GPUParam; +class GPUQA; class GPUDisplay { public: - GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa); + GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa, const GPUParam* param = nullptr, const GPUCalibObjectsConst* calib = nullptr, const GPUSettingsDisplay* config = nullptr); ~GPUDisplay() = default; GPUDisplay(const GPUDisplay&) = delete; int StartDisplay(); - void ShowNextEvent(); + void ShowNextEvent(const GPUTrackingInOutPointers* ptrs = nullptr); void WaitForNextEvent(); void SetCollisionFirstCluster(unsigned int collision, int slice, int cluster); - void HandleKeyRelease(unsigned char key); + void HandleKey(unsigned char key); int DrawGLScene(bool mixAnimation = false, float mAnimateTime = -1.f); void HandleSendKey(int key); int InitGL(bool initFailure = false); @@ -113,9 +106,11 @@ class GPUDisplay private: static constexpr int NSLICES = GPUChainTracking::NSLICES; - static constexpr const int N_POINTS_TYPE = 11; + static constexpr const int N_POINTS_TYPE = 15; static constexpr const int N_POINTS_TYPE_TPC = 9; static constexpr const int N_POINTS_TYPE_TRD = 2; + static constexpr const int N_POINTS_TYPE_TOF = 2; + static constexpr const int N_POINTS_TYPE_ITS = 2; static constexpr const int N_LINES_TYPE = 7; static constexpr const int N_FINAL_TYPE = 4; static constexpr int TRACK_TYPE_ID_LIMIT = 100; @@ -129,7 +124,11 @@ class GPUDisplay tFINALTRACK = 7, tMARKED = 8, tTRDCLUSTER = 9, - tTRDATTACHED = 10 }; + tTRDATTACHED = 10, + tTOFCLUSTER = 11, + tTOFATTACHED = 12, + tITSCLUSTER = 13, + tITSATTACHED = 14 }; enum LineTypes { RESERVED = 0 /*1 -- 6 = INITLINK to GLOBALTRACK*/ }; typedef std::tuple<GLsizei, GLsizei, int> vboList; @@ -138,38 +137,6 @@ class GPUDisplay GLvertex(GLfloat a, GLfloat b, GLfloat c) : x(a), y(b), z(c) {} }; - struct OpenGLConfig { - int animationMode = 0; - - bool smoothPoints = true; - bool smoothLines = false; - bool depthBuffer = false; - - bool drawClusters = true; - bool drawLinks = false; - bool drawSeeds = false; - bool drawInitLinks = false; - bool drawTracklets = false; - bool drawTracks = false; - bool drawGlobalTracks = false; - bool drawFinal = false; - int excludeClusters = 0; - int propagateTracks = 0; - - int colorClusters = 1; - int drawSlice = -1; - int drawRelatedSlices = 0; - int drawGrid = 0; - int colorCollisions = 0; - int showCollision = -1; - - float pointSize = 2.0; - float lineWidth = 1.4; - - bool drawTPC = true; - bool drawTRD = true; - }; - struct DrawArraysIndirectCommand { DrawArraysIndirectCommand(unsigned int a = 0, unsigned int b = 0, unsigned int c = 0, unsigned int d = 0) : count(a), instanceCount(b), first(c), baseInstance(d) {} unsigned int count; @@ -223,10 +190,13 @@ class GPUDisplay int DrawGLScene_internal(bool mixAnimation, float mAnimateTime); int InitGL_internal(); - const GPUParam& param(); + int getNumThreads(); + void disableUnsupportedOptions(); + int buildTrackFilter(); const GPUTPCTracker& sliceTracker(int iSlice); const GPUTRDTrackerGPU& trdTracker(); - const GPUTrackingInOutPointers ioptrs(); + const GPUTRDGeometry& trdGeometry(); + const GPUTrackingInOutPointers* mIOPtrs = nullptr; void drawVertices(const vboList& v, const GLenum t); void insertVertexList(std::pair<vecpod<GLint>*, vecpod<GLsizei>*>& vBuf, size_t first, size_t last); void insertVertexList(int iSlice, size_t first, size_t last); @@ -248,6 +218,8 @@ class GPUDisplay void showInfo(const char* info); void ActivateColor(); void SetColorTRD(); + void SetColorTOF(); + void SetColorITS(); void SetColorClusters(); void SetColorInitLinks(); void SetColorLinks(); @@ -270,13 +242,17 @@ class GPUDisplay void UpdateOffscreenBuffers(bool clean = false); void updateConfig(); void drawPointLinestrip(int iSlice, int cid, int id, int id_limit = TRACK_TYPE_ID_LIMIT); - vboList DrawClusters(const GPUTPCTracker& tracker, int select, int iCol); + vboList DrawClusters(int iSlice, int select, unsigned int iCol); vboList DrawSpacePointsTRD(int iSlice, int select, int iCol); - vboList DrawSpacePointsTRD(const GPUTPCTracker& tracker, int select, int iCol); + vboList DrawSpacePointsTOF(int iSlice, int select, int iCol); + vboList DrawSpacePointsITS(int iSlice, int select, int iCol); vboList DrawLinks(const GPUTPCTracker& tracker, int id, bool dodown = false); vboList DrawSeeds(const GPUTPCTracker& tracker); vboList DrawTracklets(const GPUTPCTracker& tracker); vboList DrawTracks(const GPUTPCTracker& tracker, int global); + void DrawTrackITS(int trackId, int iSlice); + GPUDisplay::vboList DrawFinalITS(); + template <class T> void DrawFinal(int iSlice, int /*iCol*/, GPUTPCGMPropagator* prop, std::array<vecpod<int>, 2>& trackList, threadVertexBuffer& threadBuffer); vboList DrawGrid(const GPUTPCTracker& tracker); vboList DrawGridTRD(int sector); @@ -293,10 +269,13 @@ class GPUDisplay GPUDisplayBackend* mBackend; GPUChainTracking* mChain; + const GPUParam* mParam; + const GPUCalibObjectsConst* mCalib; const GPUSettingsDisplay& mConfig; - OpenGLConfig mCfg; + GPUSettingsDisplayLight mCfgL; + GPUSettingsDisplayHeavy mCfgH; + GPUSettingsDisplayRenderer mCfgR; GPUQA* mQA; - const GPUTPCGMMerger& mMerger; qSem mSemLockDisplay; GLfb mMixBuffer; @@ -309,72 +288,55 @@ class GPUDisplay vecpod<GLuint> mMainBufferStack{0}; int mNDrawCalls = 0; - bool mUseGLIndirectDraw = true; + bool mUseMultiVBO = false; std::array<float, 3> mDrawColor = {}; - bool mInvertColors = false; - const int mDrawQualityRenderToTexture = 1; - int mDrawQualityMSAA = 0; - int mDrawQualityDownsampleFSAA = 0; - bool mDrawQualityVSync = false; - bool mMaximized = true; - bool mFullScreen = false; int mTestSetting = 0; - bool mCamLookOrigin = false; - bool mCamYUp = false; - int mCameraMode = 0; - float mAngleRollOrigin = -1e9; - float mMaxClusterZ = 0; - - int screenshot_scale = 1; + float mMaxClusterZ = -1; int mScreenwidth = GPUDisplayBackend::INIT_WIDTH, mScreenheight = GPUDisplayBackend::INIT_HEIGHT; int mRenderwidth = GPUDisplayBackend::INIT_WIDTH, mRenderheight = GPUDisplayBackend::INIT_HEIGHT; - bool mSeparateGlobalTracks = 0; - bool mPropagateLoopers = 0; - - hmm_mat4 mViewMatrix; + hmm_mat4 mViewMatrix, mModelMatrix; float* const mViewMatrixP = &mViewMatrix.Elements[0][0]; float mXYZ[3]; float mAngle[3]; float mRPhiTheta[3]; float mQuat[4]; - int mProjectXY = 0; - - int mMarkClusters = 0; - int mHideRejectedClusters = 1; - int mHideUnmatchedClusters = 0; - int mHideRejectedTracks = 1; - int mMarkAdjacentClusters = 0; - int mMarkFakeClusters = 0; - int mTrackFilter = 0; - vecpod<std::array<int, 37>> mCollisionClusters; int mNCollissions = 1; - float mXadd = 0; - float mZadd = 0; - std::unique_ptr<float4[]> mGlobalPosPtr; std::unique_ptr<float4[]> mGlobalPosPtrTRD; std::unique_ptr<float4[]> mGlobalPosPtrTRD2; + std::unique_ptr<float4[]> mGlobalPosPtrITS; + std::unique_ptr<float4[]> mGlobalPosPtrTOF; float4* mGlobalPos; float4* mGlobalPosTRD; float4* mGlobalPosTRD2; + float4* mGlobalPosITS; + float4* mGlobalPosTOF; int mNMaxClusters = 0; int mNMaxSpacePointsTRD = 0; + int mNMaxClustersITS = 0; + int mNMaxClustersTOF = 0; int mCurrentClusters = 0; int mCurrentSpacePointsTRD = 0; - std::vector<int> mTRDTrackIds; + int mCurrentClustersITS = 0; + int mCurrentClustersTOF = 0; + vecpod<int> mTRDTrackIds; + vecpod<bool> mITSStandaloneTracks; + std::vector<bool> mTrackFilter; + bool mUpdateTrackFilter = false; int mGlDLrecent = 0; - int mUpdateDLList = 0; + volatile int mUpdateDLList = 0; + volatile int mResetScene = 0; int mAnimate = 0; HighResTimer mAnimationTimer; @@ -385,11 +347,9 @@ class GPUDisplay bool mAnimationChangeConfig = true; float mAnimationDelay = 2.f; vecpod<float> mAnimateVectors[9]; - vecpod<OpenGLConfig> mAnimateConfig; + vecpod<GPUSettingsDisplayLight> mAnimateConfig; opengl_spline mAnimationSplines[8]; - volatile int mResetScene = 0; - int mPrintInfoText = 1; char mInfoText2[1024]; HighResTimer mInfoText2Timer, mInfoHelpTimer; @@ -404,6 +364,7 @@ class GPUDisplay HighResTimer mTimerFPS, mTimerDisplay, mTimerDraw; vboList mGlDLLines[NSLICES][N_LINES_TYPE]; vecpod<std::array<vboList, N_FINAL_TYPE>> mGlDLFinal[NSLICES]; + vboList mGlDLFinalITS; vecpod<vboList> mGlDLPoints[NSLICES][N_POINTS_TYPE]; vboList mGlDLGrid[NSLICES]; vboList mGlDLGridTRD[NSLICES / 2]; diff --git a/GPU/GPUTracking/display/GPUDisplayBackend.cxx b/GPU/GPUTracking/display/GPUDisplayBackend.cxx new file mode 100644 index 0000000000000..cc75abd015233 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayBackend.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayBackend.cxx +/// \author David Rohr + +#include "GPUDisplayBackend.h" +#include "GPUDisplay.h" + +using namespace GPUCA_NAMESPACE::gpu; + +void* GPUDisplayBackend::OpenGLWrapper(void* ptr) +{ + GPUDisplayBackend* me = reinterpret_cast<GPUDisplayBackend*>(ptr); + int retVal = me->OpenGLMain(); + if (retVal == -1) { + me->InitGL(true); + } + return ((void*)(size_t)retVal); +} + +void GPUDisplayBackend::HandleSendKey() +{ + if (mSendKey) { + mDisplay->HandleSendKey(mSendKey); + mSendKey = 0; + } +} + +void GPUDisplayBackend::HandleKey(unsigned char key) { mDisplay->HandleKey(key); } +int GPUDisplayBackend::DrawGLScene(bool mixAnimation, float animateTime) { return mDisplay->DrawGLScene(mixAnimation, animateTime); } +void GPUDisplayBackend::ReSizeGLScene(int width, int height) +{ + mDisplayHeight = height; + mDisplayWidth = width; + mDisplay->ReSizeGLScene(width, height); +} +int GPUDisplayBackend::InitGL(bool initFailure) { return mDisplay->InitGL(initFailure); } +void GPUDisplayBackend::ExitGL() { return mDisplay->ExitGL(); } +bool GPUDisplayBackend::EnableSendKey() { return true; } diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackend.h b/GPU/GPUTracking/display/GPUDisplayBackend.h similarity index 79% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackend.h rename to GPU/GPUTracking/display/GPUDisplayBackend.h index 48917ec5c4fcd..d6362595bfc59 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackend.h +++ b/GPU/GPUTracking/display/GPUDisplayBackend.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -61,27 +62,29 @@ class GPUDisplayBackend static constexpr int KEY_RIGHT = 4; static constexpr int KEY_PAGEUP = 5; static constexpr int KEY_PAGEDOWN = 6; - static constexpr int KEY_SPACE = 7; static constexpr int KEY_SHIFT = 8; static constexpr int KEY_ALT = 9; - static constexpr int KEY_CTRL = 10; - static constexpr int KEY_F1 = 11; - static constexpr int KEY_F2 = 12; + static constexpr int KEY_RALT = 10; + static constexpr int KEY_CTRL = 11; + static constexpr int KEY_RCTRL = 12; + static constexpr int KEY_ENTER = 13; // fixed at 13 + static constexpr int KEY_F1 = 14; + static constexpr int KEY_F2 = 15; static constexpr int KEY_F3 = 26; - static constexpr int KEY_F4 = 14; - static constexpr int KEY_F5 = 15; - static constexpr int KEY_F6 = 16; - static constexpr int KEY_F7 = 17; - static constexpr int KEY_F8 = 18; - static constexpr int KEY_F9 = 19; - static constexpr int KEY_F10 = 20; - static constexpr int KEY_F11 = 21; - static constexpr int KEY_F12 = 22; - static constexpr int KEY_HOME = 23; - static constexpr int KEY_END = 24; - static constexpr int KEY_INSERT = 25; - static constexpr int KEY_ESCAPE = 27; - static constexpr int KEY_ENTER = 13; + static constexpr int KEY_F4 = 17; + static constexpr int KEY_F5 = 18; + static constexpr int KEY_F6 = 19; + static constexpr int KEY_F7 = 20; + static constexpr int KEY_F8 = 21; + static constexpr int KEY_F9 = 22; + static constexpr int KEY_F10 = 23; + static constexpr int KEY_F11 = 24; + static constexpr int KEY_F12 = 25; + static constexpr int KEY_INSERT = 26; + static constexpr int KEY_ESCAPE = 27; // fixed at 27 + static constexpr int KEY_HOME = 28; + static constexpr int KEY_END = 29; + static constexpr int KEY_SPACE = 32; // fixed at 32 // Keyboard / Mouse actions bool mMouseDn = false; // Mouse button down @@ -98,7 +101,7 @@ class GPUDisplayBackend GPUDisplay* mDisplay; // Ptr to display, not owning, set by display when it connects to backend - void HandleKeyRelease(unsigned char key); // Callback for handling key presses + void HandleKey(unsigned char key); // Callback for handling key presses int DrawGLScene(bool mixAnimation = false, float animateTime = -1.f); // Callback to draw the GL scene void HandleSendKey(); // Optional callback to handle key press from external source (e.g. stdin by default) void ReSizeGLScene(int width, int height); // Callback when GL window is resized diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.cxx b/GPU/GPUTracking/display/GPUDisplayBackendGlfw.cxx similarity index 83% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.cxx rename to GPU/GPUTracking/display/GPUDisplayBackendGlfw.cxx index adf7f93e70afa..d49e834e30510 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.cxx +++ b/GPU/GPUTracking/display/GPUDisplayBackendGlfw.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,12 +55,18 @@ int GPUDisplayBackendGlfw::GetKey(int key) if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) { return (KEY_SHIFT); } - if (key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) { + if (key == GLFW_KEY_LEFT_ALT) { return (KEY_ALT); } - if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL) { + if (key == GLFW_KEY_RIGHT_ALT) { + return (KEY_RALT); + } + if (key == GLFW_KEY_LEFT_CONTROL) { return (KEY_CTRL); } + if (key == GLFW_KEY_RIGHT_CONTROL) { + return (KEY_RCTRL); + } if (key == GLFW_KEY_UP) { return (KEY_UP); } @@ -143,7 +150,7 @@ void GPUDisplayBackendGlfw::GetKey(int key, int scancode, int mods, int& keyOut, if ((mods & GLFW_MOD_SHIFT) && localeKey >= 'a' && localeKey <= 'z') { localeKey += 'A' - 'a'; } - // GPUInfo("Key: key %d (%c) -> %d (%c) special %d (%c)", key, (char) key, (int) localeKey, localeKey, specialKey, (char) specialKey); + // GPUInfo("Key: key %d (%c) scancode %d -> %d (%c) special %d (%c)", key, (char)key, scancode, (int)localeKey, localeKey, specialKey, (char)specialKey); if (specialKey) { keyOut = keyPressOut = specialKey; @@ -161,18 +168,39 @@ void GPUDisplayBackendGlfw::key_callback(GLFWwindow* window, int key, int scanco { int handleKey = 0, keyPress = 0; GetKey(key, scancode, mods, handleKey, keyPress); - if (action == GLFW_PRESS) { - me->mKeys[keyPress] = true; - me->mKeysShift[keyPress] = mods & GLFW_MOD_SHIFT; - } else if (action == GLFW_RELEASE) { - if (me->mKeys[keyPress]) { - me->HandleKeyRelease(handleKey); + if (handleKey < 32) { + if (action == GLFW_PRESS) { + me->mKeys[keyPress] = true; + me->mKeysShift[keyPress] = mods & GLFW_MOD_SHIFT; + me->HandleKey(handleKey); + } else if (action == GLFW_RELEASE) { + me->mKeys[keyPress] = false; + me->mKeysShift[keyPress] = false; + } + } else if (handleKey < 256) { + if (action == GLFW_PRESS) { + me->mLastKeyDown = handleKey; + } else if (action == GLFW_RELEASE) { + keyPress = me->mKeyDownMap[handleKey]; + me->mKeys[keyPress] = false; + me->mKeysShift[keyPress] = false; } - me->mKeys[keyPress] = false; - me->mKeysShift[keyPress] = false; } } +void GPUDisplayBackendGlfw::char_callback(GLFWwindow* window, unsigned int codepoint) +{ + // GPUInfo("Key (char callback): %d %c - key: %d", codepoint, (char)codepoint, (int)me->mLastKeyDown); + int keyPress = codepoint; + if (keyPress >= 'a' && keyPress <= 'z') { + keyPress += 'A' - 'a'; + } + me->mKeyDownMap[me->mLastKeyDown] = keyPress; + me->mKeys[keyPress] = true; + me->mKeysShift[keyPress] = me->mKeys[KEY_SHIFT]; + me->HandleKey(codepoint); +} + void GPUDisplayBackendGlfw::mouseButton_callback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS) { @@ -240,6 +268,7 @@ int GPUDisplayBackendGlfw::OpenGLMain() glfwMakeContextCurrent(mWindow); glfwSetKeyCallback(mWindow, key_callback); + glfwSetCharCallback(mWindow, char_callback); glfwSetMouseButtonCallback(mWindow, mouseButton_callback); glfwSetScrollCallback(mWindow, scroll_callback); glfwSetCursorPosCallback(mWindow, cursorPos_callback); @@ -268,9 +297,6 @@ int GPUDisplayBackendGlfw::OpenGLMain() #ifdef GPUCA_O2_LIB ImGui_ImplGlfwGL3_Init(mWindow, false); -#endif - -#ifdef GPUCA_O2_LIB while (o2::framework::pollGUI(mWindow, DisplayLoop)) { } #else diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.h b/GPU/GPUTracking/display/GPUDisplayBackendGlfw.h similarity index 79% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.h rename to GPU/GPUTracking/display/GPUDisplayBackendGlfw.h index 6b0949390cbc8..0fd4e4da76806 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlfw.h +++ b/GPU/GPUTracking/display/GPUDisplayBackendGlfw.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,6 +42,7 @@ class GPUDisplayBackendGlfw : public GPUDisplayBackend static void error_callback(int error, const char* description); static void key_callback(GLFWwindow* mWindow, int key, int scancode, int action, int mods); + static void char_callback(GLFWwindow* window, unsigned int codepoint); static void mouseButton_callback(GLFWwindow* mWindow, int button, int action, int mods); static void scroll_callback(GLFWwindow* mWindow, double x, double y); static void cursorPos_callback(GLFWwindow* mWindow, double x, double y); @@ -56,6 +58,8 @@ class GPUDisplayBackendGlfw : public GPUDisplayBackend int mWindowY = 0; int mWindowWidth = INIT_WIDTH; int mWindowHeight = INIT_HEIGHT; + char mKeyDownMap[256] = {0}; + unsigned char mLastKeyDown = 0; }; } // namespace GPUCA_NAMESPACE::gpu diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.cxx b/GPU/GPUTracking/display/GPUDisplayBackendGlut.cxx similarity index 93% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.cxx rename to GPU/GPUTracking/display/GPUDisplayBackendGlut.cxx index 0698c15fc0253..691d8fe898f9d 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.cxx +++ b/GPU/GPUTracking/display/GPUDisplayBackendGlut.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -26,13 +27,13 @@ using namespace GPUCA_NAMESPACE::gpu; static GPUDisplayBackendGlut* me = nullptr; -void GPUDisplayBackendGlut::displayFunc(void) +void GPUDisplayBackendGlut::displayFunc() { me->DrawGLScene(); glutSwapBuffers(); } -void GPUDisplayBackendGlut::glutLoopFunc(void) +void GPUDisplayBackendGlut::glutLoopFunc() { me->HandleSendKey(); displayFunc(); @@ -127,15 +128,13 @@ void GPUDisplayBackendGlut::keyboardDownFunc(unsigned char key, int x, int y) GetKey(key, handleKey, keyPress, false); me->mKeysShift[keyPress] = glutGetModifiers() & GLUT_ACTIVE_SHIFT; me->mKeys[keyPress] = true; + me->HandleKey(handleKey); } void GPUDisplayBackendGlut::keyboardUpFunc(unsigned char key, int x, int y) { int handleKey = 0, keyPress = 0; GetKey(key, handleKey, keyPress, false); - if (me->mKeys[keyPress]) { - me->HandleKeyRelease(handleKey); - } me->mKeys[keyPress] = false; me->mKeysShift[keyPress] = false; } @@ -146,15 +145,13 @@ void GPUDisplayBackendGlut::specialDownFunc(int key, int x, int y) GetKey(key, handleKey, keyPress, true); me->mKeysShift[keyPress] = glutGetModifiers() & GLUT_ACTIVE_SHIFT; me->mKeys[keyPress] = true; + me->HandleKey(handleKey); } void GPUDisplayBackendGlut::specialUpFunc(int key, int x, int y) { int handleKey = 0, keyPress = 0; GetKey(key, handleKey, keyPress, true); - if (me->mKeys[keyPress]) { - me->HandleKeyRelease(handleKey); - } me->mKeys[keyPress] = false; me->mKeysShift[keyPress] = false; } diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.h b/GPU/GPUTracking/display/GPUDisplayBackendGlut.h similarity index 81% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.h rename to GPU/GPUTracking/display/GPUDisplayBackendGlut.h index 77426ebcac656..17f82d9827e7a 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendGlut.h +++ b/GPU/GPUTracking/display/GPUDisplayBackendGlut.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,8 +36,8 @@ class GPUDisplayBackendGlut : public GPUDisplayBackend private: int OpenGLMain() override; - static void displayFunc(void); - static void glutLoopFunc(void); + static void displayFunc(); + static void glutLoopFunc(); static void keyboardUpFunc(unsigned char key, int x, int y); static void keyboardDownFunc(unsigned char key, int x, int y); static void specialUpFunc(int key, int x, int y); diff --git a/GPU/GPUTracking/display/GPUDisplayBackendNone.cxx b/GPU/GPUTracking/display/GPUDisplayBackendNone.cxx new file mode 100644 index 0000000000000..214e6249f93b4 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayBackendNone.cxx @@ -0,0 +1,16 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayBackendNone.cxx +/// \author David Rohr + +#include "GPUDisplayBackendNone.h" +using namespace GPUCA_NAMESPACE::gpu; diff --git a/GPU/GPUTracking/display/GPUDisplayBackendNone.h b/GPU/GPUTracking/display/GPUDisplayBackendNone.h new file mode 100644 index 0000000000000..7a1cd69264496 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayBackendNone.h @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayBackendNone.h +/// \author David Rohr + +#ifndef GPUDISPLAYBACKENDNONE_H +#define GPUDISPLAYBACKENDNONE_H + +#include "GPUDisplayBackend.h" + +namespace GPUCA_NAMESPACE::gpu +{ +class GPUDisplayBackendNone : public GPUDisplayBackend +{ + GPUDisplayBackendNone() = default; + ~GPUDisplayBackendNone() override = default; + + int StartDisplay() override { return 1; } + void DisplayExit() override {} + void SwitchFullscreen(bool set) override {} + void ToggleMaximized(bool set) override {} + void SetVSync(bool enable) override {} + void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override {} +}; +} // namespace GPUCA_NAMESPACE::gpu + +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.cxx b/GPU/GPUTracking/display/GPUDisplayBackendWindows.cxx similarity index 96% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.cxx rename to GPU/GPUTracking/display/GPUDisplayBackendWindows.cxx index 00a20190e1e9f..d70fdf6c9b1c3 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendWindows.cxx +++ b/GPU/GPUTracking/display/GPUDisplayBackendWindows.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -261,13 +262,13 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) wParam = GetKey(wParam); mKeys[wParam] = TRUE; mKeysShift[wParam] = mKeys[KEY_SHIFT]; + HandleKey(wParam); return 0; case WM_KEYUP: wParam = GetKey(wParam); - HandleKeyRelease(wParam); mKeysShift[wParam] = false; - + mKeys[wParam] = false; GPUInfo("Key: %d", wParam); return 0; diff --git a/GPU/GPUTracking/display/GPUDisplayBackendWindows.h b/GPU/GPUTracking/display/GPUDisplayBackendWindows.h new file mode 100644 index 0000000000000..9b605c9b3564b --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayBackendWindows.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayBackendWindows.h +/// \author David Rohr + +#ifndef GPUDISPLAYBACKENDWINDOWS_H +#define GPUDISPLAYBACKENDWINDOWS_H + +#include "GPUDisplayBackend.h" + +namespace GPUCA_NAMESPACE::gpu +{ +class GPUDisplayBackendWindows : public GPUDisplayBackend +{ + public: + GPUDisplayBackendWindows() = default; + ~GPUDisplayBackendWindows() override = default; + + int StartDisplay() override; + void DisplayExit() override; + void SwitchFullscreen(bool set) override; + void ToggleMaximized(bool set) override; + void SetVSync(bool enable) override; + void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override; + + private: + int OpenGLMain() override; +}; +} // namespace GPUCA_NAMESPACE::gpu + +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.cxx b/GPU/GPUTracking/display/GPUDisplayBackendX11.cxx similarity index 94% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.cxx rename to GPU/GPUTracking/display/GPUDisplayBackendX11.cxx index 50f4f78a14621..4451a3bc0ab98 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.cxx +++ b/GPU/GPUTracking/display/GPUDisplayBackendX11.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,12 +37,18 @@ int GPUDisplayBackendX11::GetKey(int key) if (key == 65505 || key == 65506) { return (KEY_SHIFT); } - if (key == 65513 || key == 65027) { + if (key == 65513 || key == 65511) { return (KEY_ALT); } - if (key == 65507 || key == 65508) { + if (key == 65027) { + return (KEY_RALT); + } + if (key == 65507) { return (KEY_CTRL); } + if (key == 65508) { + return (KEY_RCTRL); + } if (key == 65362) { return (KEY_UP); } @@ -129,7 +136,7 @@ void GPUDisplayBackendX11::GetKey(XEvent& event, int& keyOut, int& keyPressOut) } int specialKey = GetKey(sym); int localeKey = tmpString[0]; - // GPUInfo("Key: keycode %d -> sym %d (%c) key %d (%c) special %d (%c)", event.xkey.keycode, (int) sym, (char) sym, (int) localeKey, localeKey, specialKey, (char) specialKey); + // GPUInfo("Key: keycode %d -> sym %d (%c) key %d (%c) special %d (%c)", (int)event.xkey.keycode, (int)sym, (char)sym, (int)localeKey, (char)localeKey, (int)specialKey, (char)specialKey); if (specialKey) { keyOut = keyPressOut = specialKey; @@ -199,7 +206,7 @@ int GPUDisplayBackendX11::OpenGLMain() // GLX_SAMPLES , MSAA_SAMPLES, None}; - GLXFBConfig fbconfig = 0; + GLXFBConfig fbconfig = nullptr; int fbcount; GLXFBConfig* fbc = glXChooseFBConfig(mDisplay, DefaultScreen(mDisplay), attribs, &fbcount); if (fbc == nullptr || fbcount == 0) { @@ -368,15 +375,13 @@ int GPUDisplayBackendX11::OpenGLMain() GetKey(event, handleKey, keyPress); mKeysShift[keyPress] = mKeys[KEY_SHIFT]; mKeys[keyPress] = true; + HandleKey(handleKey); break; } case KeyRelease: { int handleKey = 0, keyPress = 0; GetKey(event, handleKey, keyPress); - if (mKeys[keyPress]) { - HandleKeyRelease(handleKey); - } mKeys[keyPress] = false; mKeysShift[keyPress] = false; break; diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.h b/GPU/GPUTracking/display/GPUDisplayBackendX11.h similarity index 80% rename from GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.h rename to GPU/GPUTracking/display/GPUDisplayBackendX11.h index 7b7bf91dd4a13..782566f5c369f 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayBackendX11.h +++ b/GPU/GPUTracking/display/GPUDisplayBackendX11.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/display/GPUDisplayExt.h b/GPU/GPUTracking/display/GPUDisplayExt.h new file mode 100644 index 0000000000000..365c1cb9dabce --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayExt.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayExt.h +/// \author David Rohr + +#ifndef GPUDISPLAYEXT_H +#define GPUDISPLAYEXT_H +#ifdef GPUCA_BUILD_EVENT_DISPLAY + +#include "GPUCommonDef.h" + +#if defined(GPUCA_DISPLAY_GL3W) && !defined(GPUCA_DISPLAY_OPENGL_CORE) +#define GPUCA_DISPLAY_OPENGL_CORE +#endif + +#ifdef GPUCA_DISPLAY_GL3W +#include "GL/gl3w.h" +#else +#include <GL/glew.h> +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ +#ifdef GPUCA_DISPLAY_GL3W +static int GPUDisplayExtInit() +{ + return gl3wInit(); +} +#else +static int GPUDisplayExtInit() +{ + return glewInit(); +} +#endif +#ifdef GPUCA_DISPLAY_OPENGL_CORE +static constexpr bool GPUCA_DISPLAY_OPENGL_CORE_FLAGS = true; +#else +static constexpr bool GPUCA_DISPLAY_OPENGL_CORE_FLAGS = false; +#endif +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayInterpolation.cxx b/GPU/GPUTracking/display/GPUDisplayInterpolation.cxx similarity index 86% rename from GPU/GPUTracking/Standalone/display/GPUDisplayInterpolation.cxx rename to GPU/GPUTracking/display/GPUDisplayInterpolation.cxx index db72319db6d73..dc95606301ce0 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayInterpolation.cxx +++ b/GPU/GPUTracking/display/GPUDisplayInterpolation.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/display/GPUDisplayKeys.cxx b/GPU/GPUTracking/display/GPUDisplayKeys.cxx new file mode 100644 index 0000000000000..05c311d809998 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayKeys.cxx @@ -0,0 +1,516 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayKeys.cxx +/// \author David Rohr + +#include "GPUDisplay.h" +#ifdef GPUCA_BUILD_EVENT_DISPLAY + +using namespace GPUCA_NAMESPACE::gpu; + +const char* HelpText[] = { + "[ESC] Quit", + "[n] Next event", + "[r] Reset Display Settings", + "[l] / [k] / [J] Draw single slice (next / previous slice), draw related slices (same plane in phi)", + "[;] / [:] Show splitting of TPC in slices by extruding volume, [:] resets", + "[#] Invert colors", + "[y] / [Y] / ['] / [X] / [M] Start Animation, Add / remove Animation point, Reset Points, Cycle animation camera mode (resets)", + "[>] / [<] Toggle config interpolation during Animation / change Animation interval (via movement)", + "[g] Draw Grid", + "[i] Project onto XY-plane", + "[x] Exclude Clusters used in the tracking steps enabled for visualization ([1]-[8])", + "[.] Exclude rejected tracks", + "[c] Mark flagged clusters (splitPad = 0x1, splitTime = 0x2, edge = 0x4, singlePad = 0x8, rejectDistance = 0x10, rejectErr = 0x20", + "[z] Mark fake attached clusters", + "[B] Mark clusters attached as adjacent", + "[L] / [K] Draw single collisions (next / previous)", + "[C] Colorcode clusters of different collisions", + "[v] Hide rejected clusters from tracks", + "[j] Show global tracks as additional segments of final tracks", + "[u] Cycle through track filter", + "[E] / [G] Extrapolate tracks / loopers", + "[t] / [T] Take Screenshot / Record Animation to pictures", + "[Z] Change screenshot resolution (scaling factor)", + "[S] / [A] / [D] Enable or disable smoothing of points / smoothing of lines / depth buffer", + "[W] / [U] / [V] Toggle anti-aliasing (MSAA at raster level / change downsampling FSAA factor) / toggle VSync", + "[F] / [_] / [R] Switch mFullScreen / Maximized window / FPS rate limiter", + "[I] Enable / disable GL indirect draw", + "[o] / [p] / [O] / [P] Save / restore current camera position / Animation path", + "[h] Print Help", + "[H] Show info texts", + "[w] / [s] / [a] / [d] Zoom / Strafe Left and Right", + "[pgup] / [pgdn] Strafe up / down", + "[e] / [f] Rotate left / right", + "[+] / [-] Increase / decrease point size (Hold SHIFT for lines)", + "[b] Change FOV (field of view)", + "['] Switch between OpenGL core / compat code path", + "[MOUSE 1] Look around", + "[MOUSE 2] Strafe camera", + "[MOUSE 1+2] Zoom / Rotate", + "[SHIFT] Slow Zoom / Move / Rotate", + "[ALT] / [CTRL] / [ENTER] Focus camera on origin / orient y-axis upwards (combine with [SHIFT] to lock) / Cycle through modes", + "[RCTRL] / [RALT] Rotate model instead of camera / rotate TPC around beamline", + "[1] ... [8] / [N] Enable display of clusters, preseeds, seeds, starthits, tracklets, tracks, global tracks, merged tracks / Show assigned clusters in colors", + "[F1] / [F2] / [F3] / [F4] Enable / disable drawing of TPC / TRD / TOF / ITS", + "[SHIFT] + [F1] to [F4] Enable / disable track detector filter", + "[SHIFT] + [F12] Switch track detector filter between AND and OR mode" + // FREE: [m] [SPACE] [q] [Q] + // Test setting: ^ +}; + +void GPUDisplay::PrintHelp() +{ + mInfoHelpTimer.ResetStart(); + for (unsigned int i = 0; i < sizeof(HelpText) / sizeof(HelpText[0]); i++) { + GPUInfo("%s", HelpText[i]); + } +} + +void GPUDisplay::HandleKey(unsigned char key) +{ + GPUSettingsDisplayHeavy oldCfgH = mCfgH; + GPUSettingsDisplayRenderer oldCfgR = mCfgR; + if (key == 'n') { + mBackend->mDisplayControl = 1; + SetInfo("Showing next event", 1); + } else if (key == 27 || key == mBackend->KEY_ESCAPE) { + mBackend->mDisplayControl = 2; + SetInfo("Exiting", 1); + } else if (key == 'r') { + mResetScene = 1; + SetInfo("View reset", 1); + } else if (key == mBackend->KEY_ALT && mBackend->mKeysShift[mBackend->KEY_ALT]) { + mCfgR.camLookOrigin ^= 1; + mCfgR.cameraMode = mCfgR.camLookOrigin + 2 * mCfgR.camYUp; + SetInfo("Camera locked on origin: %s", mCfgR.camLookOrigin ? "enabled" : "disabled"); + } else if (key == mBackend->KEY_CTRL && mBackend->mKeysShift[mBackend->KEY_CTRL]) { + mCfgR.camYUp ^= 1; + mCfgR.cameraMode = mCfgR.camLookOrigin + 2 * mCfgR.camYUp; + SetInfo("Camera locked on y-axis facing upwards: %s", mCfgR.camYUp ? "enabled" : "disabled"); + } else if (key == mBackend->KEY_ENTER) { + mCfgR.cameraMode++; + if (mCfgR.cameraMode == 4) { + mCfgR.cameraMode = 0; + } + mCfgR.camLookOrigin = mCfgR.cameraMode & 1; + mCfgR.camYUp = mCfgR.cameraMode & 2; + const char* modeText[] = {"Descent (free movement)", "Focus locked on origin (y-axis forced upwards)", "Spectator (y-axis forced upwards)", "Focus locked on origin (with free rotation)"}; + SetInfo("Camera mode %d: %s", mCfgR.cameraMode, modeText[mCfgR.cameraMode]); + } else if (key == mBackend->KEY_ALT) { + mBackend->mKeys[mBackend->KEY_CTRL] = false; // Release CTRL with alt, to avoid orienting along y automatically! + } else if (key == 'l') { + if (mCfgL.drawSlice >= (mCfgL.drawRelatedSlices ? (NSLICES / 4 - 1) : (NSLICES - 1))) { + mCfgL.drawSlice = -1; + SetInfo("Showing all slices", 1); + } else { + mCfgL.drawSlice++; + SetInfo("Showing slice %d", mCfgL.drawSlice); + } + } else if (key == 'k') { + if (mCfgL.drawSlice <= -1) { + mCfgL.drawSlice = mCfgL.drawRelatedSlices ? (NSLICES / 4 - 1) : (NSLICES - 1); + } else { + mCfgL.drawSlice--; + } + if (mCfgL.drawSlice == -1) { + SetInfo("Showing all slices", 1); + } else { + SetInfo("Showing slice %d", mCfgL.drawSlice); + } + } else if (key == 'J') { + mCfgL.drawRelatedSlices ^= 1; + SetInfo("Drawing of related slices %s", mCfgL.drawRelatedSlices ? "enabled" : "disabled"); + } else if (key == 'L') { + if (mCfgL.showCollision >= mNCollissions - 1) { + mCfgL.showCollision = -1; + SetInfo("Showing all collisions", 1); + } else { + mCfgL.showCollision++; + SetInfo("Showing collision %d / %d", mCfgL.showCollision, mNCollissions); + } + } else if (key == 'K') { + if (mCfgL.showCollision <= -1) { + mCfgL.showCollision = mNCollissions - 1; + } else { + mCfgL.showCollision--; + } + if (mCfgL.showCollision == -1) { + SetInfo("Showing all collisions", 1); + } else { + SetInfo("Showing collision %d", mCfgL.showCollision); + } + } else if (key == 'F') { + mCfgR.fullScreen ^= 1; + SetInfo("Toggling full screen (%d)", (int)mCfgR.fullScreen); + } else if (key == '_') { + mCfgR.maximized ^= 1; + SetInfo("Toggling Maximized window (%d)", (int)mCfgR.maximized); + } else if (key == 'R') { + mCfgR.maxFPSRate ^= 1; + SetInfo("FPS rate %s", mCfgR.maxFPSRate ? "not limited" : "limited"); + } else if (key == 'H') { + mPrintInfoText += 1; + mPrintInfoText &= 3; + SetInfo("Info text display - console: %s, onscreen %s", (mPrintInfoText & 2) ? "enabled" : "disabled", (mPrintInfoText & 1) ? "enabled" : "disabled"); + } else if (key == 'j') { + mCfgH.separateGlobalTracks ^= 1; + SetInfo("Seperated display of global tracks %s", mCfgH.separateGlobalTracks ? "enabled" : "disabled"); + } else if (key == 'c') { + if (mCfgH.markClusters == 0) { + mCfgH.markClusters = 1; + } else if (mCfgH.markClusters >= 0x20) { + mCfgH.markClusters = 0; + } else { + mCfgH.markClusters <<= 1; + } + SetInfo("Cluster flag highlight mask set to %d (%s)", mCfgH.markClusters, + mCfgH.markClusters == 0 ? "off" : mCfgH.markClusters == 1 ? "split pad" : mCfgH.markClusters == 2 ? "split time" : mCfgH.markClusters == 4 ? "edge" : mCfgH.markClusters == 8 ? "singlePad" : mCfgH.markClusters == 0x10 ? "reject distance" : "reject error"); + } else if (key == 'z') { + mCfgH.markFakeClusters ^= 1; + SetInfo("Marking fake clusters: %s", mCfgH.markFakeClusters ? "on" : "off"); + } else if (key == 'b') { + if ((mCfgR.fov += 5) > 175) { + mCfgR.fov = 5; + } + SetInfo("Set FOV to %f", mCfgR.fov); + } else if (key == 39) { // character = "'" +#ifdef GPUCA_DISPLAY_OPENGL_CORE + SetInfo("OpenGL compat profile not available, using core profile", 1); +#else + mCfgR.openGLCore ^= 1; + SetInfo("Using renderer path for OpenGL %s profile", mCfgR.openGLCore ? "core" : "compat"); +#endif + } else if (key == 'B') { + mCfgH.markAdjacentClusters++; + if (mCfgH.markAdjacentClusters == 5) { + mCfgH.markAdjacentClusters = 7; + } + if (mCfgH.markAdjacentClusters == 9) { + mCfgH.markAdjacentClusters = 15; + } + if (mCfgH.markAdjacentClusters == 17) { + mCfgH.markAdjacentClusters = 31; + } + if (mCfgH.markAdjacentClusters == 34) { + mCfgH.markAdjacentClusters = 0; + } + if (mCfgH.markAdjacentClusters == 33) { + SetInfo("Marking protected clusters (%d)", mCfgH.markAdjacentClusters); + } else if (mCfgH.markAdjacentClusters == 32) { + SetInfo("Marking removable clusters (%d)", mCfgH.markAdjacentClusters); + } else { + SetInfo("Marking adjacent clusters (%d): rejected %s, tube %s, looper leg %s, low Pt %s, high incl %s", mCfgH.markAdjacentClusters, (mCfgH.markAdjacentClusters & 1) ? "yes" : " no", (mCfgH.markAdjacentClusters & 2) ? "yes" : " no", (mCfgH.markAdjacentClusters & 4) ? "yes" : " no", (mCfgH.markAdjacentClusters & 8) ? "yes" : " no", (mCfgH.markAdjacentClusters & 16) ? "yes" : " no"); + } + } else if (key == 'C') { + mCfgL.colorCollisions ^= 1; + SetInfo("Color coding of collisions %s", mCfgL.colorCollisions ? "enabled" : "disabled"); + } else if (key == 'N') { + mCfgL.colorClusters ^= 1; + SetInfo("Color coding for seed / trrack attachmend %s", mCfgL.colorClusters ? "enabled" : "disabled"); + } else if (key == 'E') { + mCfgL.propagateTracks += 1; + if (mCfgL.propagateTracks == 4) { + mCfgL.propagateTracks = 0; + } + const char* infoText[] = {"Hits connected", "Hits connected and propagated to vertex", "Reconstructed track propagated inwards and outwards", "Monte Carlo track"}; + SetInfo("Display of propagated tracks: %s", infoText[mCfgL.propagateTracks]); + } else if (key == 'G') { + mCfgH.propagateLoopers ^= 1; + SetInfo("Propagation of loopers %s", mCfgH.propagateLoopers ? "enabled" : "disabled"); + } else if (key == 'v') { + mCfgH.hideRejectedClusters ^= 1; + SetInfo("Rejected clusters are %s", mCfgH.hideRejectedClusters ? "hidden" : "shown"); + } else if (key == 'i') { + mCfgH.projectXY ^= 1; + SetInfo("Projection onto xy plane %s", mCfgH.projectXY ? "enabled" : "disabled"); + } else if (key == 'S') { + mCfgL.smoothPoints ^= true; + SetInfo("Smoothing of points %s", mCfgL.smoothPoints ? "enabled" : "disabled"); + } else if (key == 'A') { + mCfgL.smoothLines ^= true; + SetInfo("Smoothing of lines %s", mCfgL.smoothLines ? "enabled" : "disabled"); + } else if (key == 'D') { + mCfgL.depthBuffer ^= true; + GLint depthBits = 0; +#ifndef GPUCA_DISPLAY_OPENGL_CORE + glGetIntegerv(GL_DEPTH_BITS, &depthBits); +#endif + SetInfo("Depth buffer (z-buffer, %d bits) %s", depthBits, mCfgL.depthBuffer ? "enabled" : "disabled"); + setDepthBuffer(); + } else if (key == 'W') { + mCfgR.drawQualityMSAA *= 2; + if (mCfgR.drawQualityMSAA < 2) { + mCfgR.drawQualityMSAA = 2; + } + if (mCfgR.drawQualityMSAA > 16) { + mCfgR.drawQualityMSAA = 0; + } + SetInfo("Multisampling anti-aliasing factor set to %d", mCfgR.drawQualityMSAA); + } else if (key == 'U') { + mCfgR.drawQualityDownsampleFSAA++; + if (mCfgR.drawQualityDownsampleFSAA == 1) { + mCfgR.drawQualityDownsampleFSAA = 2; + } + if (mCfgR.drawQualityDownsampleFSAA == 5) { + mCfgR.drawQualityDownsampleFSAA = 0; + } + SetInfo("Downsampling anti-aliasing factor set to %d", mCfgR.drawQualityDownsampleFSAA); + } else if (key == 'V') { + mCfgR.drawQualityVSync ^= true; + SetInfo("VSync: %s", mCfgR.drawQualityVSync ? "enabled" : "disabled"); + } else if (key == 'I') { + mCfgR.useGLIndirectDraw ^= true; + SetInfo("OpenGL Indirect Draw %s", mCfgR.useGLIndirectDraw ? "enabled" : "disabled"); + } else if (key == ';') { + mCfgH.xAdd += 60; + mCfgH.zAdd += 60; + SetInfo("TPC sector separation: %f %f", mCfgH.xAdd, mCfgH.zAdd); + } else if (key == ':') { + mCfgH.xAdd -= 60; + mCfgH.zAdd -= 60; + if (mCfgH.zAdd < 0 || mCfgH.xAdd < 0) { + mCfgH.zAdd = mCfgH.xAdd = 0; + } + SetInfo("TPC sector separation: %f %f", mCfgH.xAdd, mCfgH.zAdd); + } else if (key == '#') { + mCfgL.invertColors ^= 1; + } else if (key == 'g') { + mCfgL.drawGrid ^= 1; + SetInfo("Fast Cluster Search Grid %s", mCfgL.drawGrid ? "shown" : "hidden"); + } else if (key == 'x') { + mCfgL.excludeClusters ^= 1; + SetInfo(mCfgL.excludeClusters ? "Clusters of selected category are excluded from display" : "Clusters are shown", 1); + } else if (key == '.') { + mCfgH.hideRejectedTracks ^= 1; + SetInfo("Rejected tracks are %s", mCfgH.hideRejectedTracks ? "hidden" : "shown"); + } else if (key == '1') { + mCfgL.drawClusters ^= 1; + } else if (key == '2') { + mCfgL.drawInitLinks ^= 1; + } else if (key == '3') { + mCfgL.drawLinks ^= 1; + } else if (key == '4') { + mCfgL.drawSeeds ^= 1; + } else if (key == '5') { + mCfgL.drawTracklets ^= 1; + } else if (key == '6') { + mCfgL.drawTracks ^= 1; + } else if (key == '7') { + mCfgL.drawGlobalTracks ^= 1; + } else if (key == '8') { + mCfgL.drawFinal ^= 1; + } else if (key == mBackend->KEY_F1) { + if (mBackend->mKeysShift[mBackend->KEY_F1]) { + mCfgH.drawTPCTracks ^= 1; + SetInfo("Track Filter Mask: TPC:%d TRD:%d TOF:%d ITS:%d", (int)mCfgH.drawTPCTracks, (int)mCfgH.drawTRDTracks, (int)mCfgH.drawTOFTracks, (int)mCfgH.drawITSTracks); + } else { + mCfgL.drawTPC ^= 1; + SetInfo("Showing TPC Clusters: %d", (int)mCfgL.drawTPC); + } + } else if (key == mBackend->KEY_F2) { + if (mBackend->mKeysShift[mBackend->KEY_F2]) { + mCfgH.drawTRDTracks ^= 1; + SetInfo("Track Filter Mask: TPC:%d TRD:%d TOF:%d ITS:%d", (int)mCfgH.drawTPCTracks, (int)mCfgH.drawTRDTracks, (int)mCfgH.drawTOFTracks, (int)mCfgH.drawITSTracks); + } else { + mCfgL.drawTRD ^= 1; + SetInfo("Showing TRD Tracklets: %d", (int)mCfgL.drawTRD); + } + } else if (key == mBackend->KEY_F3) { + if (mBackend->mKeysShift[mBackend->KEY_F3]) { + mCfgH.drawTOFTracks ^= 1; + SetInfo("Track Filter Mask: TPC:%d TRD:%d TOF:%d ITS:%d", (int)mCfgH.drawTPCTracks, (int)mCfgH.drawTRDTracks, (int)mCfgH.drawTOFTracks, (int)mCfgH.drawITSTracks); + } else { + mCfgL.drawTOF ^= 1; + SetInfo("Showing TOF Hits: %d", (int)mCfgL.drawTOF); + } + } else if (key == mBackend->KEY_F4) { + if (mBackend->mKeysShift[mBackend->KEY_F4]) { + mCfgH.drawITSTracks ^= 1; + SetInfo("Track Filter Mask: TPC:%d TRD:%d TOF:%d ITS:%d", (int)mCfgH.drawTPCTracks, (int)mCfgH.drawTRDTracks, (int)mCfgH.drawTOFTracks, (int)mCfgH.drawITSTracks); + } else { + mCfgL.drawITS ^= 1; + SetInfo("Showing ITS Clusters: %d", (int)mCfgL.drawITS); + } + } else if (key == mBackend->KEY_F12 && mBackend->mKeysShift[mBackend->KEY_F12]) { + mCfgH.drawTracksAndFilter ^= 1; + SetInfo("Track filter: %s", mCfgH.drawTracksAndFilter ? "AND" : "OR"); + } else if (key == 't') { + GPUInfo("Taking screenshot"); + static int nScreenshot = 1; + char fname[32]; + sprintf(fname, "screenshot%d.bmp", nScreenshot++); + DoScreenshot(fname); + SetInfo("Taking screenshot (%s)", fname); + } else if (key == 'Z') { + mCfgR.screenshotScaleFactor += 1; + if (mCfgR.screenshotScaleFactor == 5) { + mCfgR.screenshotScaleFactor = 1; + } + SetInfo("Screenshot scaling factor set to %d", mCfgR.screenshotScaleFactor); + } else if (key == 'y' || key == 'T') { + if ((mAnimateScreenshot = (key == 'T'))) { + mAnimationExport++; + } + if (mAnimateVectors[0].size() > 1) { + startAnimation(); + SetInfo("Starting Animation", 1); + } else { + SetInfo("Insufficient Animation points to start Animation", 1); + } + } else if (key == '>') { + mAnimationChangeConfig ^= 1; + SetInfo("Interpolating visualization settings during Animation %s", mAnimationChangeConfig ? "enabled" : "disabled"); + } else if (key == 'Y') { + setAnimationPoint(); + SetInfo("Added Animation point (%d points, %6.2f seconds)", (int)mAnimateVectors[0].size(), mAnimateVectors[0].back()); + } else if (key == 'X') { + resetAnimation(); + SetInfo("Reset Animation points", 1); + } else if (key == '\'') { + removeAnimationPoint(); + SetInfo("Removed Animation point", 1); + } else if (key == 'M') { + mCfgL.animationMode++; + if (mCfgL.animationMode == 7) { + mCfgL.animationMode = 0; + } + resetAnimation(); + if (mCfgL.animationMode == 6) { + SetInfo("Animation mode %d - Centered on origin", mCfgL.animationMode); + } else { + SetInfo("Animation mode %d - Position: %s, Direction: %s", mCfgL.animationMode, (mCfgL.animationMode & 2) ? "Spherical (spherical rotation)" : (mCfgL.animationMode & 4) ? "Spherical (Euler angles)" : "Cartesian", (mCfgL.animationMode & 1) ? "Euler angles" : "Quaternion"); + } + } else if (key == 'u') { + mCfgH.trackFilter = (mCfgH.trackFilter + 1) % (mConfig.filterMacros.size() + 1); + mUpdateTrackFilter = true; + SetInfo("Track filter: %s", mCfgH.trackFilter == 0 ? "None" : mConfig.filterMacros[mCfgH.trackFilter - 1].c_str()); + } else if (key == 'o') { + FILE* ftmp = fopen("glpos.tmp", "w+b"); + if (ftmp) { + int retval = fwrite(&mViewMatrix, sizeof(mViewMatrix), 1, ftmp); + if (retval != 1) { + GPUError("Error writing position to file"); + } else { + GPUInfo("Position stored to file"); + } + fclose(ftmp); + } else { + GPUError("Error opening file"); + } + SetInfo("Camera position stored to file", 1); + } else if (key == 'p') { + FILE* ftmp = fopen("glpos.tmp", "rb"); + if (ftmp) { + int retval = fread(&mViewMatrix, 1, sizeof(mViewMatrix), ftmp); + if (retval == sizeof(mViewMatrix)) { + GPUInfo("Position read from file"); + } else { + GPUError("Error reading position from file"); + } + fclose(ftmp); + } else { + GPUError("Error opening file"); + } + SetInfo("Camera position loaded from file", 1); + } else if (key == 'O') { + FILE* ftmp = fopen("glanimation.tmp", "w+b"); + if (ftmp) { + fwrite(&mCfgL, sizeof(mCfgL), 1, ftmp); + int size = mAnimateVectors[0].size(); + fwrite(&size, sizeof(size), 1, ftmp); + for (int i = 0; i < 9; i++) { + fwrite(mAnimateVectors[i].data(), sizeof(mAnimateVectors[i][0]), size, ftmp); + } + fwrite(mAnimateConfig.data(), sizeof(mAnimateConfig[0]), size, ftmp); + fclose(ftmp); + } else { + GPUError("Error opening file"); + } + SetInfo("Animation path stored to file %s", "glanimation.tmp"); + } else if (key == 'P') { + FILE* ftmp = fopen("glanimation.tmp", "rb"); + if (ftmp) { + int retval = fread(&mCfgL, sizeof(mCfgL), 1, ftmp); + int size; + retval += fread(&size, sizeof(size), 1, ftmp); + for (int i = 0; i < 9; i++) { + mAnimateVectors[i].resize(size); + retval += fread(mAnimateVectors[i].data(), sizeof(mAnimateVectors[i][0]), size, ftmp); + } + mAnimateConfig.resize(size); + retval += fread(mAnimateConfig.data(), sizeof(mAnimateConfig[0]), size, ftmp); + (void)retval; // disable unused warning + fclose(ftmp); + updateConfig(); + } else { + GPUError("Error opening file"); + } + SetInfo("Animation path loaded from file %s", "glanimation.tmp"); + } else if (key == 'h') { + PrintHelp(); + SetInfo("Showing help text", 1); + } + /* + else if (key == '^') + { + mTestSetting++; + SetInfo("Debug test variable set to %d", mTestSetting); + } + */ + + if (memcmp((void*)&oldCfgH, (void*)&mCfgH, sizeof(mCfgH)) != 0) { + mUpdateDLList = true; + } + if (oldCfgR.drawQualityMSAA != mCfgR.drawQualityMSAA || oldCfgR.drawQualityDownsampleFSAA != mCfgR.drawQualityDownsampleFSAA) { + UpdateOffscreenBuffers(); + } + if (oldCfgR.drawQualityVSync != mCfgR.drawQualityVSync) { + mBackend->SetVSync(mCfgR.drawQualityVSync); + } + if (oldCfgR.fullScreen != mCfgR.fullScreen) { + mBackend->SwitchFullscreen(mCfgR.fullScreen); + } + if (oldCfgR.maximized != mCfgR.maximized) { + mBackend->ToggleMaximized(mCfgR.maximized); + } + if (oldCfgR.maxFPSRate != mCfgR.maxFPSRate) { + mBackend->mMaxFPSRate = mCfgR.maxFPSRate; + } + if (oldCfgR.useGLIndirectDraw != mCfgR.useGLIndirectDraw) { + mUpdateDLList = true; + } +} + +void GPUDisplay::HandleSendKey(int key) +{ + // GPUError("key %d '%c'", key, (char) key); + + bool shifted = key >= 'A' && key <= 'Z'; + int press = key; + if (press >= 'a' && press <= 'z') { + press += 'A' - 'a'; + } + bool oldShift = mBackend->mKeysShift[press]; + mBackend->mKeysShift[press] = shifted; + HandleKey(key); + mBackend->mKeysShift[press] = oldShift; +} + +void GPUDisplay::PrintGLHelpText(float colorValue) +{ + for (unsigned int i = 0; i < sizeof(HelpText) / sizeof(HelpText[0]); i++) { + mBackend->OpenGLPrint(HelpText[i], 40.f, 35 + 20 * (1 + i), colorValue, colorValue, colorValue, mInfoHelpTimer.GetCurrentElapsedTime() >= 5 ? (6 - mInfoHelpTimer.GetCurrentElapsedTime()) : 1, false); + } +} + +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayQuaternion.cxx b/GPU/GPUTracking/display/GPUDisplayQuaternion.cxx similarity index 79% rename from GPU/GPUTracking/Standalone/display/GPUDisplayQuaternion.cxx rename to GPU/GPUTracking/display/GPUDisplayQuaternion.cxx index 48fe05c1c834d..4de2d2804ba4f 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayQuaternion.cxx +++ b/GPU/GPUTracking/display/GPUDisplayQuaternion.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/display/GPUDisplayROOT.cxx b/GPU/GPUTracking/display/GPUDisplayROOT.cxx new file mode 100644 index 0000000000000..2040a7297d6a3 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayROOT.cxx @@ -0,0 +1,60 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayROOT.cxx +/// \author David Rohr + +#ifdef GPUCA_BUILD_EVENT_DISPLAY + +#include "GPUDisplay.h" +using namespace GPUCA_NAMESPACE::gpu; + +#ifndef GPUCA_NO_ROOT +#include "Rtypes.h" // Include ROOT header first, to use ROOT and disable replacements +#include "TROOT.h" +#include "TSystem.h" +#include "TMethodCall.h" + +int GPUDisplay::buildTrackFilter() +{ + if (!mCfgH.trackFilter) { + return 0; + } + if (mUpdateTrackFilter) { + std::string name = "displayTrackFilter/"; + name += mConfig.filterMacros[mCfgH.trackFilter - 1]; + gROOT->Reset(); + if (gROOT->LoadMacro(name.c_str())) { + GPUError("Error loading trackFilter macro %s", name.c_str()); + return 1; + } + } + TMethodCall call; + call.InitWithPrototype("gpuDisplayTrackFilter", "std::vector<bool>*, const o2::gpu::GPUTrackingInOutPointers*, const o2::gpu::GPUConstantMem*"); + const void* args[3]; + std::vector<bool>* arg0 = &mTrackFilter; + args[0] = &arg0; + args[1] = &mIOPtrs; + const GPUConstantMem* arg2 = mChain ? mChain->GetProcessors() : nullptr; + args[2] = &arg2; + + call.Execute(nullptr, args, sizeof(args) / sizeof(args[0]), nullptr); + return 0; +} + +#else + +int GPUDisplay::buildTrackFilter() +{ +} + +#endif +#endif diff --git a/GPU/GPUTracking/display/GPUDisplayShaders.h b/GPU/GPUTracking/display/GPUDisplayShaders.h new file mode 100644 index 0000000000000..6d40a57abd7a9 --- /dev/null +++ b/GPU/GPUTracking/display/GPUDisplayShaders.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayShaders.h +/// \author David Rohr + +#ifndef GPUDISPLAYSHADERS_H +#define GPUDISPLAYSHADERS_H + +#include "GPUCommonDef.h" +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +struct GPUDisplayShaders { + static constexpr const char* vertexShader = R"( +#version 450 core +layout (location = 0) in vec3 pos; +uniform mat4 ModelViewProj; + +void main() +{ + gl_Position = ModelViewProj * vec4(pos.x, pos.y, pos.z, 1.0); +} +)"; + + static constexpr const char* fragmentShader = R"( +#version 450 core +out vec4 fragColor; +uniform vec3 color; + +void main() +{ + fragColor = vec4(color.x, color.y, color.z, 1.f); +} +)"; +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Standalone/display/bitmapfile.h b/GPU/GPUTracking/display/bitmapfile.h similarity index 76% rename from GPU/GPUTracking/Standalone/display/bitmapfile.h rename to GPU/GPUTracking/display/bitmapfile.h index 1576f24113f60..274993633e36e 100644 --- a/GPU/GPUTracking/Standalone/display/bitmapfile.h +++ b/GPU/GPUTracking/display/bitmapfile.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/display/filterMacros/README.md b/GPU/GPUTracking/display/filterMacros/README.md new file mode 100644 index 0000000000000..a13417de805e0 --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/README.md @@ -0,0 +1,26 @@ +# Filtering tracks in the GPU event display using ROOT macros + +The event display can filter tracks using ROOT macros. +For the standalone version, you can provide a list of filter macros with the `--GLfilterMacros` option. +In the DPL version, you can set a single filter macro via `--configKeyValues "GPU_global.gpuDisplayfilterMacro=[MACRO]"`. +By pressing the `u` key in the event display, you can cycle through the loaded filters (and filter disabled). +You can use the ROOT `+` and `++` syntax for compiled macros. +All macro files must be placed in the folder `displayTrackFilter` in the working directory. +The macros should include `#include "GPUO2Interface.h"` + +The filter macro must implement a function with the following prototype: +``` +void gpuDisplayTrackFilter(std::vector<bool>* filter, const GPUTrackingInOutPointers* ioPtrs, const GPUConstantMem* processors) +``` +This function is called once when the event display loads the data for an event / time frame. +Here, `filter` is a vector of booleans indicating whether the track is shown or not. Default is all entries are `true` and no track is filtered. +The current filter applies only to TPC tracks, and will filter matched ITS, TOF, and TRD tracks as well. +It is not yet possible to filter ITS standalone tracks. +Access to the track data goes via the `ioPtrs` structure. +Note that when the input to the event display is GPU tracks, use `ioPtrs->mergedTracks` while when the input are final TPC tracks, `ioPtrs->outputTracksTPCO2` must be used. + +Note that since most GPU classes have no ROOT dictionary, it might be required to use the macro in compiled mode. + +If the event display runs with the tracking (i.e. not via the separate DPL device but in the same executable as the tracking), the filter has access to all internal data structures of the tracker via the `processors` parameter. + +Some example filter macros are placed in O2 in `GPU/GPUTracking/display/filterMacros`. diff --git a/GPU/GPUTracking/display/filterMacros/TRDCandidate.C b/GPU/GPUTracking/display/filterMacros/TRDCandidate.C new file mode 100644 index 0000000000000..a58558b0b52a0 --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/TRDCandidate.C @@ -0,0 +1,10 @@ +#include "GPUO2Interface.h" +#include "GPUConstantMem.h" +using namespace o2::gpu; + +void gpuDisplayTrackFilter(std::vector<bool>* filter, const GPUTrackingInOutPointers* ioPtrs, const GPUConstantMem* processors) +{ + for (unsigned int i = 0; i < filter->size(); i++) { + (*filter)[i] = processors->trdTrackerGPU.PreCheckTrackTRDCandidate(ioPtrs->mergedTracks[i]) && processors->trdTrackerGPU.CheckTrackTRDCandidate((GPUTRDTrackGPU)ioPtrs->mergedTracks[i]); + } +} diff --git a/GPU/GPUTracking/display/filterMacros/filterGPUTrack.C b/GPU/GPUTracking/display/filterMacros/filterGPUTrack.C new file mode 100644 index 0000000000000..1c70fbd7768fa --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/filterGPUTrack.C @@ -0,0 +1,17 @@ +#include "GPUO2Interface.h" +#include "GPUTPCGMMergedTrack.h" + +namespace o2::gpu +{ +struct GPUConstantMem; +}; + +using namespace o2::gpu; + +void gpuDisplayTrackFilter(std::vector<bool>* filter, const GPUTrackingInOutPointers* ioPtrs, const GPUConstantMem* processors) +{ + for (unsigned int i = 0; i < filter->size(); i++) { + auto& trk = ioPtrs->mergedTracks[i]; + (*filter)[i] = fabsf(trk.GetParam().GetQPt()) < 1.0f; + } +} diff --git a/GPU/GPUTracking/display/filterMacros/filterTPCTrack.C b/GPU/GPUTracking/display/filterMacros/filterTPCTrack.C new file mode 100644 index 0000000000000..b2d161d967f2f --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/filterTPCTrack.C @@ -0,0 +1,19 @@ +#include "GPUO2Interface.h" +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "DataFormatsTPC/TrackTPC.h" +#endif + +namespace o2::gpu +{ +struct GPUConstantMem; +}; + +using namespace o2::gpu; + +void gpuDisplayTrackFilter(std::vector<bool>* filter, const GPUTrackingInOutPointers* ioPtrs, const GPUConstantMem* processors) +{ + for (unsigned int i = 0; i < filter->size(); i++) { + auto& trk = ioPtrs->outputTracksTPCO2[i]; + (*filter)[i] = fabsf(trk.getQ2Pt()) < 1.0f; + } +} diff --git a/GPU/GPUTracking/display/filterMacros/hasTRD.C b/GPU/GPUTracking/display/filterMacros/hasTRD.C new file mode 100644 index 0000000000000..355fd213c57fd --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/hasTRD.C @@ -0,0 +1,12 @@ +#include "GPUO2Interface.h" +using namespace o2::gpu; + +void gpuDisplayTrackFilter(std::vector<bool>* filter, const GPUTrackingInOutPointers* ioPtrs, const GPUConstantMem* processors) +{ + if (!ioPtrs->tpcLinkTRD) { + return; + } + for (unsigned int i = 0; i < filter->size(); i++) { + (*filter)[i] = ioPtrs->tpcLinkTRD[i] != -1; + } +} diff --git a/GPU/GPUTracking/display/filterMacros/setinclude.sh.in b/GPU/GPUTracking/display/filterMacros/setinclude.sh.in new file mode 100755 index 0000000000000..c588923db4b43 --- /dev/null +++ b/GPU/GPUTracking/display/filterMacros/setinclude.sh.in @@ -0,0 +1,2 @@ +#!/bin/bash +export ROOC_INCLUDE_PATH="@GPU_DISPLAY_INCLUDE_PATH@" diff --git a/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.cxx b/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.cxx index ad81f5c45f50a..05e8d4af0b187 100644 --- a/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.cxx +++ b/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.h b/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.h index ed01970095cd1..f9cc54f95a2e8 100644 --- a/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.h +++ b/GPU/GPUTracking/oldFiles/AliHLT3DTrackParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.cxx b/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.cxx index fe8598ec8dfc0..c06c70b144269 100644 --- a/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.cxx +++ b/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.h b/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.h index ef0e473904b74..b6e5056a24389 100644 --- a/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.h +++ b/GPU/GPUTracking/oldFiles/GPUTPCGMOfflineFitter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx new file mode 100644 index 0000000000000..647579389ac36 --- /dev/null +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -0,0 +1,2770 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUQA.cxx +/// \author David Rohr + +#define QA_DEBUG 0 +#define QA_TIMING 0 + +#include "Rtypes.h" // Include ROOT header first, to use ROOT and disable replacements + +#include "TH1F.h" +#include "TH2F.h" +#include "TH1D.h" +#include "TCanvas.h" +#include "TPad.h" +#include "TLegend.h" +#include "TColor.h" +#include "TPaveText.h" +#include "TF1.h" +#include "TFile.h" +#include "TTree.h" +#include "TStyle.h" +#include "TLatex.h" +#include "TObjArray.h" +#include <sys/stat.h> + +#include "GPUQA.h" +#include "GPUTPCDef.h" +#include "GPUTPCSliceData.h" +#include "GPUChainTracking.h" +#include "GPUTPCTrack.h" +#include "GPUTPCTracker.h" +#include "GPUTPCGMMergedTrack.h" +#include "GPUTPCGMPropagator.h" +#include "AliHLTTPCClusterMCData.h" +#include "GPUTPCMCInfo.h" +#include "GPUTPCClusterData.h" +#include "GPUO2DataTypes.h" +#include "GPUParam.inc" +#include "GPUTPCClusterRejection.h" +#include "TPCFastTransform.h" +#ifdef GPUCA_HAVE_O2HEADERS +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#endif +#ifdef GPUCA_O2_LIB +#include "DetectorsRaw/HBFUtils.h" +#include "DataFormatsTPC/TrackTPC.h" +#include "DataFormatsTPC/Constants.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/TrackReference.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "Steer/MCKinematicsReader.h" +#include "TPDGCode.h" +#include "TParticlePDG.h" +#include "TDatabasePDG.h" +#endif +#include "GPUQAHelper.h" +#include <algorithm> +#include <cstdio> + +#include "utils/qconfig.h" +#include "utils/timer.h" + +using namespace GPUCA_NAMESPACE::gpu; + +#ifdef GPUCA_MERGER_BY_MC_LABEL +#define CHECK_CLUSTER_STATE_INIT_LEG_BY_MC() \ + if (!unattached && mTrackMCLabels[id].isValid()) { \ + int mcLabel = mTrackMCLabels[id].getTrackID(); \ + int mcEvent = mTrackMCLabels[id].getEventID(); \ + if (mTrackMCLabelsReverse[mcEvent][mcLabel] != id) { \ + attach &= (~gputpcgmmergertypes::attachGoodLeg); \ + } \ + } +#else +#define CHECK_CLUSTER_STATE_INIT_LEG_BY_MC() +#endif + +#define CHECK_CLUSTER_STATE_INIT() \ + bool unattached = attach == 0; \ + float qpt = 0; \ + bool lowPt = false; \ + bool mev200 = false; \ + bool mergedLooper = false; \ + int id = attach & gputpcgmmergertypes::attachTrackMask; \ + if (!unattached) { \ + qpt = fabsf(mTracking->mIOPtrs.mergedTracks[id].GetParam().GetQPt()); \ + lowPt = qpt > mTracking->GetParam().rec.tpc.rejectQPt; \ + mev200 = qpt > 5; \ + mergedLooper = mTracking->mIOPtrs.mergedTracks[id].MergedLooper(); \ + } \ + bool physics = false, protect = false; \ + CHECK_CLUSTER_STATE_INIT_LEG_BY_MC(); + +#define CHECK_CLUSTER_STATE() \ + CHECK_CLUSTER_STATE_INIT() \ + if (mev200) { \ + mClusterCounts.n200MeV++; \ + } \ + if (lowPt) { \ + mClusterCounts.nLowPt++; \ + } else if (mergedLooper) { \ + mClusterCounts.nMergedLooper++; \ + } else { \ + GPUTPCClusterRejection::GetProtectionStatus<true>(attach, physics, protect, &mClusterCounts, &mev200); \ + } + +#define CHECK_CLUSTER_STATE_NOCOUNT() \ + CHECK_CLUSTER_STATE_INIT() \ + (void)mev200; /* silence unused variable warning*/ \ + if (!lowPt && !mergedLooper) { \ + GPUTPCClusterRejection::GetProtectionStatus<false>(attach, physics, protect); \ + } + +static const GPUSettingsQA& GPUQA_GetConfig(GPUChainTracking* chain) +{ + static GPUSettingsQA defaultConfig; + if (chain && chain->mConfigQA) { + return *chain->mConfigQA; + } else { + return defaultConfig; + } +} + +static const constexpr bool PLOT_ROOT = 0; +static const constexpr bool FIX_SCALES = 0; +static const constexpr bool PERF_FIGURE = 0; +static const constexpr float FIXED_SCALES_MIN[5] = {-0.05, -0.05, -0.2, -0.2, -0.5}; +static const constexpr float FIXED_SCALES_MAX[5] = {0.4, 0.7, 5, 3, 6.5}; +static const constexpr float LOG_PT_MIN = -1.; + +static constexpr float Y_MAX = 40; +static constexpr float Z_MAX = 100; +static constexpr float PT_MIN = GPUCA_MIN_TRACK_PT_DEFAULT; +static constexpr float PT_MIN2 = 0.1; +static constexpr float PT_MIN_PRIM = 0.1; +static constexpr float PT_MIN_CLUST = GPUCA_MIN_TRACK_PT_DEFAULT; +static constexpr float PT_MAX = 20; +static constexpr float ETA_MAX = 1.5; +static constexpr float ETA_MAX2 = 0.9; + +static constexpr float MIN_WEIGHT_CLS = 40; +static constexpr float FINDABLE_WEIGHT_CLS = 70; + +static constexpr bool CLUST_HIST_INT_SUM = false; + +static constexpr const int COLORCOUNT = 12; + +static const constexpr char* EFF_TYPES[4] = {"Rec", "Clone", "Fake", "All"}; +static const constexpr char* FINDABLE_NAMES[2] = {"", "Findable"}; +static const constexpr char* PRIM_NAMES[2] = {"Prim", "Sec"}; +static const constexpr char* PARAMETER_NAMES[5] = {"Y", "Z", "#Phi", "#lambda", "Relative #it{p}_{T}"}; +static const constexpr char* PARAMETER_NAMES_NATIVE[5] = {"Y", "Z", "sin(#Phi)", "tan(#lambda)", "q/#it{p}_{T} (curvature)"}; +static const constexpr char* VSPARAMETER_NAMES[6] = {"Y", "Z", "Phi", "Eta", "Pt", "Pt_log"}; +static const constexpr char* EFF_NAMES[3] = {"Efficiency", "Clone Rate", "Fake Rate"}; +static const constexpr char* EFFICIENCY_TITLES[4] = {"Efficiency (Primary Tracks, Findable)", "Efficiency (Secondary Tracks, Findable)", "Efficiency (Primary Tracks)", "Efficiency (Secondary Tracks)"}; +static const constexpr double SCALE[5] = {10., 10., 1000., 1000., 100.}; +static const constexpr double SCALE_NATIVE[5] = {10., 10., 1000., 1000., 1.}; +static const constexpr char* XAXIS_TITLES[5] = {"#it{y}_{mc} (cm)", "#it{z}_{mc} (cm)", "#Phi_{mc} (rad)", "#eta_{mc}", "#it{p}_{Tmc} (GeV/#it{c})"}; +static const constexpr char* AXIS_TITLES[5] = {"#it{y}-#it{y}_{mc} (mm) (Resolution)", "#it{z}-#it{z}_{mc} (mm) (Resolution)", "#phi-#phi_{mc} (mrad) (Resolution)", "#lambda-#lambda_{mc} (mrad) (Resolution)", "(#it{p}_{T} - #it{p}_{Tmc}) / #it{p}_{Tmc} (%) (Resolution)"}; +static const constexpr char* AXIS_TITLES_NATIVE[5] = {"#it{y}-#it{y}_{mc} (mm) (Resolution)", "#it{z}-#it{z}_{mc} (mm) (Resolution)", "sin(#phi)-sin(#phi_{mc}) (Resolution)", "tan(#lambda)-tan(#lambda_{mc}) (Resolution)", "q*(q/#it{p}_{T} - q/#it{p}_{Tmc}) (Resolution)"}; +static const constexpr char* AXIS_TITLES_PULL[5] = {"#it{y}-#it{y}_{mc}/#sigma_{y} (Pull)", "#it{z}-#it{z}_{mc}/#sigma_{z} (Pull)", "sin(#phi)-sin(#phi_{mc})/#sigma_{sin(#phi)} (Pull)", "tan(#lambda)-tan(#lambda_{mc})/#sigma_{tan(#lambda)} (Pull)", + "q*(q/#it{p}_{T} - q/#it{p}_{Tmc})/#sigma_{q/#it{p}_{T}} (Pull)"}; +static const constexpr char* CLUSTER_NAMES[GPUQA::N_CLS_HIST] = {"Correctly attached clusters", "Fake attached clusters", "Attached + adjacent clusters", "Fake adjacent clusters", "Clusters of reconstructed tracks", "Used in Physics", "Protected", "All clusters"}; +static const constexpr char* CLUSTER_TITLES[GPUQA::N_CLS_TYPE] = {"Clusters Pt Distribution / Attachment", "Clusters Pt Distribution / Attachment (relative to all clusters)", "Clusters Pt Distribution / Attachment (integrated)"}; +static const constexpr char* CLUSTER_NAMES_SHORT[GPUQA::N_CLS_HIST] = {"Attached", "Fake", "AttachAdjacent", "FakeAdjacent", "FoundTracks", "Physics", "Protected", "All"}; +static const constexpr char* CLUSTER_TYPES[GPUQA::N_CLS_TYPE] = {"", "Ratio", "Integral"}; +static const constexpr int COLORS_HEX[COLORCOUNT] = {0xB03030, 0x00A000, 0x0000C0, 0x9400D3, 0x19BBBF, 0xF25900, 0x7F7F7F, 0xFFD700, 0x07F707, 0x07F7F7, 0xF08080, 0x000000}; + +static const constexpr int CONFIG_DASHED_MARKERS = 0; + +static const constexpr float AXES_MIN[5] = {-Y_MAX, -Z_MAX, 0.f, -ETA_MAX, PT_MIN}; +static const constexpr float AXES_MAX[5] = {Y_MAX, Z_MAX, 2.f * M_PI, ETA_MAX, PT_MAX}; +static const constexpr int AXIS_BINS[5] = {51, 51, 144, 31, 50}; +static const constexpr int RES_AXIS_BINS[] = {1017, 113}; // Consecutive bin sizes, histograms are binned down until the maximum entry is 50, each bin size should evenly divide its predecessor. +static const constexpr float RES_AXES[5] = {1., 1., 0.03, 0.03, 1.0}; +static const constexpr float RES_AXES_NATIVE[5] = {1., 1., 0.1, 0.1, 5.0}; +static const constexpr float PULL_AXIS = 10.f; + +std::vector<TColor*> GPUQA::mColors; +int GPUQA::initColors() +{ + mColors.reserve(COLORCOUNT); + for (int i = 0; i < COLORCOUNT; i++) { + float f1 = (float)((COLORS_HEX[i] >> 16) & 0xFF) / (float)0xFF; + float f2 = (float)((COLORS_HEX[i] >> 8) & 0xFF) / (float)0xFF; + float f3 = (float)((COLORS_HEX[i] >> 0) & 0xFF) / (float)0xFF; + mColors.emplace_back(new TColor(10000 + i, f1, f2, f3)); + } + return 0; +} +static constexpr Color_t defaultColorNUms[COLORCOUNT] = {kRed, kBlue, kGreen, kMagenta, kOrange, kAzure, kBlack, kYellow, kGray, kTeal, kSpring, kPink}; + +#define TRACK_EXPECTED_REFERENCE_X_DEFAULT 81 +#ifdef GPUCA_TPC_GEOMETRY_O2 +inline unsigned int GPUQA::GetNMCCollissions() const +{ + return mMCInfosCol.size(); +} +inline unsigned int GPUQA::GetNMCTracks(int iCol) const { return mMCInfosCol[iCol].num; } +inline unsigned int GPUQA::GetNMCLabels() const { return mClNative->clustersMCTruth ? mClNative->clustersMCTruth->getIndexedSize() : 0; } +inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(unsigned int iTrk, unsigned int iCol) { return mMCInfos[mMCInfosCol[iCol].first + iTrk]; } +inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabel_t& label) { return mMCInfos[mMCInfosCol[label.getEventID()].first + label.getTrackID()]; } +inline GPUQA::mcLabels_t GPUQA::GetMCLabel(unsigned int i) { return mClNative->clustersMCTruth->getLabels(i); } +inline int GPUQA::GetMCLabelNID(const mcLabels_t& label) { return label.size(); } +inline int GPUQA::GetMCLabelNID(unsigned int i) { return mClNative->clustersMCTruth->getLabels(i).size(); } +inline GPUQA::mcLabel_t GPUQA::GetMCLabel(unsigned int i, unsigned int j) { return mClNative->clustersMCTruth->getLabels(i)[j]; } +inline int GPUQA::GetMCLabelID(unsigned int i, unsigned int j) { return mClNative->clustersMCTruth->getLabels(i)[j].getTrackID(); } +inline int GPUQA::GetMCLabelID(const mcLabels_t& label, unsigned int j) { return label[j].getTrackID(); } +inline int GPUQA::GetMCLabelID(const mcLabel_t& label) { return label.getTrackID(); } +inline int GPUQA::GetMCLabelCol(unsigned int i, unsigned int j) { return mClNative->clustersMCTruth->getLabels(i)[j].getEventID(); } +inline const auto& GPUQA::GetClusterLabels() { return mClNative->clustersMCTruth; } +inline float GPUQA::GetMCLabelWeight(unsigned int i, unsigned int j) { return 1; } +inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { return 1; } +inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return 1; } +inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && mClNative->clustersMCTruth && mMCInfos.size(); } +#define TRACK_EXPECTED_REFERENCE_X 78 +#else +inline GPUQA::mcLabelI_t::mcLabelI_t(const GPUQA::mcLabel_t& l) : track(l.fMCID) +{ +} +inline bool GPUQA::mcLabelI_t::operator==(const GPUQA::mcLabel_t& l) { return AbsLabelID(track) == l.fMCID; } +inline unsigned int GPUQA::GetNMCCollissions() const { return 1; } +inline unsigned int GPUQA::GetNMCTracks(int iCol) const { return mTracking->mIOPtrs.nMCInfosTPC; } +inline unsigned int GPUQA::GetNMCLabels() const { return mTracking->mIOPtrs.nMCLabelsTPC; } +inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(unsigned int iTrk, unsigned int iCol) { return mTracking->mIOPtrs.mcInfosTPC[AbsLabelID(iTrk)]; } +inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabel_t& label) { return GetMCTrack(label.fMCID, 0); } +inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(const mcLabelI_t& label) { return GetMCTrack(label.track, 0); } +inline const GPUQA::mcLabels_t& GPUQA::GetMCLabel(unsigned int i) { return mTracking->mIOPtrs.mcLabelsTPC[i]; } +inline const GPUQA::mcLabel_t& GPUQA::GetMCLabel(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j]; } +inline int GPUQA::GetMCLabelNID(const mcLabels_t& label) { return 3; } +inline int GPUQA::GetMCLabelNID(unsigned int i) { return 3; } +inline int GPUQA::GetMCLabelID(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j].fMCID; } +inline int GPUQA::GetMCLabelID(const mcLabels_t& label, unsigned int j) { return label.fClusterID[j].fMCID; } +inline int GPUQA::GetMCLabelID(const mcLabel_t& label) { return label.fMCID; } +inline int GPUQA::GetMCLabelCol(unsigned int i, unsigned int j) { return 0; } +inline const auto& GPUQA::GetClusterLabels() { return mTracking->mIOPtrs.mcLabelsTPC; } +inline float GPUQA::GetMCLabelWeight(unsigned int i, unsigned int j) { return mTracking->mIOPtrs.mcLabelsTPC[i].fClusterID[j].fWeight; } +inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { return label.fClusterID[j].fWeight; } +inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return label.fWeight; } +inline int GPUQA::FakeLabelID(int id) { return id < 0 ? id : (-2 - id); } +inline int GPUQA::AbsLabelID(int id) { return id >= 0 ? id : (-id - 2); } +inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && GetNMCLabels() && GetNMCTracks(0); } +#define TRACK_EXPECTED_REFERENCE_X TRACK_EXPECTED_REFERENCE_X_DEFAULT +#endif +template <class T> +inline auto& GPUQA::GetMCTrackObj(T& obj, const GPUQA::mcLabelI_t& l) +{ + return obj[l.getEventID()][l.getTrackID()]; +} + +template <> +auto GPUQA::getHistArray<TH1F>() +{ + return std::make_pair(mHist1D, &mHist1D_pos); +} +template <> +auto GPUQA::getHistArray<TH2F>() +{ + return std::make_pair(mHist2D, &mHist2D_pos); +} +template <> +auto GPUQA::getHistArray<TH1D>() +{ + return std::make_pair(mHist1Dd, &mHist1Dd_pos); +} +template <class T, typename... Args> +void GPUQA::createHist(T*& h, const char* name, Args... args) +{ + const auto& p = getHistArray<T>(); + if (mHaveExternalHists) { + if (p.first->size() <= p.second->size()) { + throw std::runtime_error("Incoming histogram array incomplete"); + } + if (strcmp((*p.first)[p.second->size()].GetName(), name)) { + throw std::runtime_error("Incoming histogram has incorrect name"); + } + } else { + p.first->emplace_back(name, args...); + } + p.second->emplace_back(&h); + h = &p.first->back(); +} + +namespace GPUCA_NAMESPACE::gpu +{ +struct GPUQAGarbageCollection { + std::tuple<std::vector<std::unique_ptr<TCanvas>>, std::vector<std::unique_ptr<TLegend>>, std::vector<std::unique_ptr<TPad>>, std::vector<std::unique_ptr<TLatex>>, std::vector<std::unique_ptr<TH1D>>> v; +}; +} // namespace GPUCA_NAMESPACE::gpu + +template <class T, typename... Args> +T* GPUQA::createGarbageCollected(Args... args) +{ + auto& v = std::get<std::vector<std::unique_ptr<T>>>(mGarbageCollector->v); + v.emplace_back(std::make_unique<T>(args...)); + return v.back().get(); +} +void GPUQA::clearGarbagageCollector() +{ + std::get<std::vector<std::unique_ptr<TPad>>>(mGarbageCollector->v).clear(); // Make sure to depete TPad first due to ROOT ownership (std::tuple has no defined order in its destructor) + std::apply([](auto&&... args) { ((args.clear()), ...); }, mGarbageCollector->v); +} + +GPUQA::GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config, const GPUParam* param) : mTracking(chain), mConfig(config ? *config : GPUQA_GetConfig(chain)), mParam(param ? *param : chain->GetParam()), mGarbageCollector(std::make_unique<GPUQAGarbageCollection>()) +{ + static int initColorsInitialized = initColors(); + (void)initColorsInitialized; +} + +GPUQA::~GPUQA() +{ + if (mQAInitialized && !mHaveExternalHists) { + delete mHist1D; + delete mHist2D; + delete mHist1Dd; + } + clearGarbagageCollector(); // Needed to guarantee correct order for ROOT ownership +} + +inline bool GPUQA::MCComp(const mcLabel_t& a, const mcLabel_t& b) { return (GPUQA::GetMCLabelID(a) > GPUQA::GetMCLabelID(b)); } + +bool GPUQA::clusterRemovable(int attach, bool prot) const +{ + CHECK_CLUSTER_STATE_NOCOUNT(); + if (prot) { + return protect || physics; + } + return (!unattached && !physics && !protect); +} + +void GPUQA::SetAxisSize(TH1F* e) +{ + e->GetYaxis()->SetTitleOffset(1.0); + e->GetYaxis()->SetTitleSize(0.045); + e->GetYaxis()->SetLabelSize(0.045); + e->GetXaxis()->SetTitleOffset(1.03); + e->GetXaxis()->SetTitleSize(0.045); + e->GetXaxis()->SetLabelOffset(-0.005); + e->GetXaxis()->SetLabelSize(0.045); +} + +void GPUQA::SetLegend(TLegend* l) +{ + l->SetTextFont(72); + l->SetTextSize(0.016); + l->SetFillColor(0); +} + +double* GPUQA::CreateLogAxis(int nbins, float xmin, float xmax) +{ + float logxmin = std::log10(xmin); + float logxmax = std::log10(xmax); + float binwidth = (logxmax - logxmin) / nbins; + + double* xbins = new double[nbins + 1]; + + xbins[0] = xmin; + for (int i = 1; i <= nbins; i++) { + xbins[i] = std::pow(10, logxmin + i * binwidth); + } + return xbins; +} + +void GPUQA::ChangePadTitleSize(TPad* p, float size) +{ + p->Update(); + TPaveText* pt = (TPaveText*)(p->GetPrimitive("title")); + if (pt == nullptr) { + GPUError("Error changing title"); + } else { + pt->SetTextSize(size); + p->Modified(); + } +} + +void GPUQA::DrawHisto(TH1* histo, char* filename, char* options) +{ + TCanvas tmp; + tmp.cd(); + histo->Draw(options); + tmp.Print(filename); +} + +void GPUQA::doPerfFigure(float x, float y, float size) +{ + if (!PERF_FIGURE) { + return; + } + TLatex* t = createGarbageCollected<TLatex>(); + t->SetNDC(kTRUE); + t->SetTextColor(1); + t->SetTextSize(size); + t->DrawLatex(x, y, str_perf_figure_1); + t->DrawLatex(x, y - 0.01 - size, str_perf_figure_2); +} + +void GPUQA::SetMCTrackRange(int min, int max) +{ + mMCTrackMin = min; + mMCTrackMax = max; +} + +int GPUQA::GetMCTrackLabel(unsigned int trackId) const { return (trackId >= mTrackMCLabels.size() ? MC_LABEL_INVALID : mTrackMCLabels[trackId].getTrackID()); } + +int GPUQA::InitQACreateHistograms() +{ + char name[2048], fname[1024]; + if (mQATasks & taskTrackingEff) { + // Create Efficiency Histograms + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + for (int l = 0; l < 5; l++) { + for (int m = 0; m < 2; m++) { + sprintf(name, "%s%s%s%sVs%s", m ? "eff" : "tracks", EFF_TYPES[i], FINDABLE_NAMES[j], PRIM_NAMES[k], VSPARAMETER_NAMES[l]); + if (l == 4) { + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], k == 0 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], binsPt.get()); + } else { + createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], AXES_MIN[l], AXES_MAX[l]); + } + if (!mHaveExternalHists) { + mEff[i][j][k][l][m]->Sumw2(); + } + } + } + } + } + } + } + + // Create Resolution Histograms + if (mQATasks & taskTrackingRes) { + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + sprintf(name, "rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + sprintf(fname, "mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + if (j == 4) { + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mRes[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); + createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); + } else { + createHist(mRes[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + } + sprintf(name, "res_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + const float* axis = mConfig.nativeFitResolutions ? RES_AXES_NATIVE : RES_AXES; + const int nbins = i == 4 && mConfig.nativeFitResolutions ? (10 * RES_AXIS_BINS[0]) : RES_AXIS_BINS[0]; + if (j == 4) { + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], binsPt.get()); + } else { + createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + } + } + } + } + + // Create Pull Histograms + if (mQATasks & taskTrackingResPull) { + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + sprintf(name, "pull_rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + sprintf(fname, "pull_mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + if (j == 4) { + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; + createHist(mPull[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); + createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); + } else { + createHist(mPull[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + } + sprintf(name, "pull_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); + if (j == 4) { + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; + createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], binsPt.get()); + } else { + createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + } + } + } + } + + // Create Cluster Histograms + if (mQATasks & taskClusterAttach) { + for (int i = 0; i < N_CLS_TYPE * N_CLS_HIST - 1; i++) { + int ioffset = i >= (2 * N_CLS_HIST - 1) ? (2 * N_CLS_HIST - 1) : i >= N_CLS_HIST ? N_CLS_HIST : 0; + int itype = i >= (2 * N_CLS_HIST - 1) ? 2 : i >= N_CLS_HIST ? 1 : 0; + sprintf(name, "clusters%s%s", CLUSTER_NAMES_SHORT[i - ioffset], CLUSTER_TYPES[itype]); + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; + createHist(mClusters[i], name, name, AXIS_BINS[4], binsPt.get()); + } + } + + if (mQATasks & taskTrackStatistics) { + // Create Tracks Histograms + sprintf(name, "nclusters"); + createHist(mNCl, name, name, 160, 0, 159); + sprintf(name, "tracks"); + std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; + createHist(mTracks, name, name, AXIS_BINS[4], binsPt.get()); + } + + if ((mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) { + int num = DoClusterCounts(nullptr, 2); + mHistClusterCount.resize(num); + DoClusterCounts(nullptr, 1); + } + + for (unsigned int i = 0; i < mHist1D->size(); i++) { + *mHist1D_pos[i] = &(*mHist1D)[i]; + } + for (unsigned int i = 0; i < mHist2D->size(); i++) { + *mHist2D_pos[i] = &(*mHist2D)[i]; + } + for (unsigned int i = 0; i < mHist1Dd->size(); i++) { + *mHist1Dd_pos[i] = &(*mHist1Dd)[i]; + } + + return 0; +} + +int GPUQA::loadHistograms(std::vector<TH1F>& i1, std::vector<TH2F>& i2, std::vector<TH1D>& i3, int tasks) +{ + if (tasks == -1) { + tasks = taskDefaultPostprocess; + } + if (mQAInitialized && (!mHaveExternalHists || tasks != mQATasks)) { + throw std::runtime_error("QA not initialized or initialized with different task array"); + } + mHist1D = &i1; + mHist2D = &i2; + mHist1Dd = &i3; + mHist1D_pos.clear(); + mHist2D_pos.clear(); + mHist1Dd_pos.clear(); + mHaveExternalHists = true; + mQATasks = tasks; + if (InitQACreateHistograms()) { + return 1; + } + mQAInitialized = true; + return 0; +} + +void GPUQA::DumpO2MCData(const char* filename) const +{ + FILE* fp = fopen(filename, "w+b"); + if (fp == nullptr) { + return; + } + unsigned int n = mMCInfos.size(); + fwrite(&n, sizeof(n), 1, fp); + fwrite(mMCInfos.data(), sizeof(mMCInfos[0]), n, fp); + n = mMCInfosCol.size(); + fwrite(&n, sizeof(n), 1, fp); + fwrite(mMCInfosCol.data(), sizeof(mMCInfosCol[0]), n, fp); + fclose(fp); +} + +int GPUQA::ReadO2MCData(const char* filename) +{ + FILE* fp = fopen(filename, "rb"); + if (fp == nullptr) { + return 1; + } + unsigned int n; + unsigned int x; + if ((x = fread(&n, sizeof(n), 1, fp)) != 1) { + fclose(fp); + return 1; + } + mMCInfos.resize(n); + if (fread(mMCInfos.data(), sizeof(mMCInfos[0]), n, fp) != n) { + fclose(fp); + return 1; + } + if ((x = fread(&n, sizeof(n), 1, fp)) != 1) { + fclose(fp); + return 1; + } + mMCInfosCol.resize(n); + if (fread(mMCInfosCol.data(), sizeof(mMCInfosCol[0]), n, fp) != n) { + fclose(fp); + return 1; + } + fclose(fp); + if (mTracking) { + CopyO2MCtoIOPtr(&mTracking->mIOPtrs); + } + return 0; +} + +void GPUQA::CopyO2MCtoIOPtr(GPUTrackingInOutPointers* ptr) +{ + ptr->mcInfosTPC = mMCInfos.data(); + ptr->nMCInfosTPC = mMCInfos.size(); + ptr->mcInfosTPCCol = mMCInfosCol.data(); + ptr->nMCInfosTPCCol = mMCInfosCol.size(); +} + +void GPUQA::InitO2MCData(GPUTrackingInOutPointers* updateIOPtr) +{ +#ifdef GPUCA_O2_LIB + if (!mO2MCDataLoaded) { + HighResTimer timer; + if (mTracking && mTracking->GetProcessingSettings().debugLevel) { + GPUInfo("Start reading O2 Track MC information"); + timer.Start(); + } + static constexpr float PRIM_MAX_T = 0.01f; + + o2::steer::MCKinematicsReader mcReader("collisioncontext.root"); + int nSimEvents = mcReader.getNEvents(0); + mMCInfos.resize(nSimEvents); + std::vector<int> refId; + + auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + auto evrec = dc->getEventRecords(); + + mMCInfosCol.resize(nSimEvents); + for (int i = 0; i < nSimEvents; i++) { + auto ir = evrec[i]; + auto ir0 = o2::raw::HBFUtils::Instance().getFirstIRofTF(ir); + float timebin = (float)ir.differenceInBC(ir0) / o2::tpc::constants::LHCBCPERTIMEBIN; + + const std::vector<o2::MCTrack>& tracks = mcReader.getTracks(0, i); + const std::vector<o2::TrackReference>& trackRefs = mcReader.getTrackRefsByEvent(0, i); + + refId.resize(tracks.size()); + std::fill(refId.begin(), refId.end(), -1); + for (unsigned int j = 0; j < trackRefs.size(); j++) { + if (trackRefs[j].getDetectorId() == o2::detectors::DetID::TPC) { + int trkId = trackRefs[j].getTrackID(); + if (refId[trkId] == -1) { + refId[trkId] = j; + } + } + } + mMCInfosCol[i].first = mMCInfos.size(); + mMCInfosCol[i].num = tracks.size(); + mMCInfos.resize(mMCInfos.size() + tracks.size()); + for (unsigned int j = 0; j < tracks.size(); j++) { + auto& info = mMCInfos[mMCInfosCol[i].first + j]; + const auto& trk = tracks[j]; + TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(trk.GetPdgCode()); + Int_t pid = -1; + if (abs(trk.GetPdgCode()) == kElectron) { + pid = 0; + } + if (abs(trk.GetPdgCode()) == kMuonMinus) { + pid = 1; + } + if (abs(trk.GetPdgCode()) == kPiPlus) { + pid = 2; + } + if (abs(trk.GetPdgCode()) == kKPlus) { + pid = 3; + } + if (abs(trk.GetPdgCode()) == kProton) { + pid = 4; + } + + info.charge = particle ? particle->Charge() : 0; + info.prim = trk.T() < PRIM_MAX_T; + info.primDaughters = 0; + if (trk.getFirstDaughterTrackId() != -1) { + for (int k = trk.getFirstDaughterTrackId(); k <= trk.getLastDaughterTrackId(); k++) { + if (tracks[k].T() < PRIM_MAX_T) { + info.primDaughters = 1; + break; + } + } + } + info.pid = pid; + info.t0 = timebin; + if (refId[j] >= 0) { + const auto& trkRef = trackRefs[refId[j]]; + info.x = trkRef.X(); + info.y = trkRef.Y(); + info.z = trkRef.Z(); + info.pX = trkRef.Px(); + info.pY = trkRef.Py(); + info.pZ = trkRef.Pz(); + info.genRadius = std::sqrt(trk.GetStartVertexCoordinatesX() * trk.GetStartVertexCoordinatesX() + trk.GetStartVertexCoordinatesY() * trk.GetStartVertexCoordinatesY() + trk.GetStartVertexCoordinatesZ() * trk.GetStartVertexCoordinatesZ()); + } else { + info.x = info.y = info.z = info.pX = info.pY = info.pZ = 0; + info.genRadius = 0; + } + } + } + if (mTracking && mTracking->GetProcessingSettings().debugLevel) { + GPUInfo("Finished reading O2 Track MC information (%f seconds)", timer.GetCurrentElapsedTime()); + } + mO2MCDataLoaded = true; + } + if (updateIOPtr) { + CopyO2MCtoIOPtr(updateIOPtr); + } +#endif +} + +int GPUQA::InitQA(int tasks) +{ + if (mQAInitialized) { + throw std::runtime_error("QA already initialized"); + } + if (tasks == -1) { + tasks = taskDefault; + } + + mHist1D = new std::vector<TH1F>; + mHist2D = new std::vector<TH2F>; + mHist1Dd = new std::vector<TH1D>; + mQATasks = tasks; + + if (mTracking) { + mClNative = mTracking->mIOPtrs.clustersNative; + } + + if (InitQACreateHistograms()) { + return 1; + } + + if (mConfig.enableLocalOutput) { + mkdir("plots", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + } + +#ifdef GPUCA_O2_LIB + if (!mConfig.noMC) { + InitO2MCData(mTracking ? &mTracking->mIOPtrs : nullptr); + } +#endif + + if (mConfig.matchMCLabels.size()) { + unsigned int nFiles = mConfig.matchMCLabels.size(); + std::vector<std::unique_ptr<TFile>> files; + std::vector<std::vector<std::vector<int>>*> labelsBuffer(nFiles); + std::vector<std::vector<std::vector<int>>*> effBuffer(nFiles); + for (unsigned int i = 0; i < nFiles; i++) { + files.emplace_back(std::make_unique<TFile>(mConfig.matchMCLabels[i].c_str())); + labelsBuffer[i] = (std::vector<std::vector<int>>*)files[i]->Get("mcLabelBuffer"); + effBuffer[i] = (std::vector<std::vector<int>>*)files[i]->Get("mcEffBuffer"); + if (labelsBuffer[i] == nullptr || effBuffer[i] == nullptr) { + GPUError("Error opening / reading from labels file %u/%s: %p %p", i, mConfig.matchMCLabels[i], (void*)labelsBuffer[i], (void*)effBuffer[i]); + exit(1); + } + } + + mGoodTracks.resize(labelsBuffer[0]->size()); + mGoodHits.resize(labelsBuffer[0]->size()); + for (unsigned int iEvent = 0; iEvent < labelsBuffer[0]->size(); iEvent++) { + std::vector<bool> labelsOK((*effBuffer[0])[iEvent].size()); + for (unsigned int k = 0; k < (*effBuffer[0])[iEvent].size(); k++) { + labelsOK[k] = false; + for (unsigned int l = 0; l < nFiles; l++) { + if ((*effBuffer[0])[iEvent][k] != (*effBuffer[l])[iEvent][k]) { + labelsOK[k] = true; + break; + } + } + } + mGoodTracks[iEvent].resize((*labelsBuffer[0])[iEvent].size()); + for (unsigned int k = 0; k < (*labelsBuffer[0])[iEvent].size(); k++) { + if ((*labelsBuffer[0])[iEvent][k] == MC_LABEL_INVALID) { + continue; + } + mGoodTracks[iEvent][k] = labelsOK[abs((*labelsBuffer[0])[iEvent][k])]; + } + } + } + mQAInitialized = true; + return 0; +} + +void GPUQA::RunQA(bool matchOnly, const std::vector<o2::tpc::TrackTPC>* tracksExternal, const std::vector<o2::MCCompLabel>* tracksExtMC, const o2::tpc::ClusterNativeAccess* clNative) +{ + if (!mQAInitialized) { + throw std::runtime_error("QA not initialized"); + } + if (!clNative && mTracking) { + clNative = mTracking->mIOPtrs.clustersNative; + } + mClNative = clNative; + +#ifdef GPUCA_TPC_GEOMETRY_O2 + unsigned int nSimEvents = GetNMCCollissions(); + if (mTrackMCLabelsReverse.size() < nSimEvents) { + mTrackMCLabelsReverse.resize(nSimEvents); + } + if (mRecTracks.size() < nSimEvents) { + mRecTracks.resize(nSimEvents); + } + if (mFakeTracks.size() < nSimEvents) { + mFakeTracks.resize(nSimEvents); + } + if (mMCParam.size() < nSimEvents) { + mMCParam.resize(nSimEvents); + } +#endif + + // Initialize Arrays + unsigned int nReconstructedTracks = 0; + if (tracksExternal) { +#ifdef GPUCA_O2_LIB + nReconstructedTracks = tracksExternal->size(); +#endif + } else { + nReconstructedTracks = mTracking->mIOPtrs.nMergedTracks; + } + mTrackMCLabels.resize(nReconstructedTracks); + for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { + mTrackMCLabelsReverse[iCol].resize(GetNMCTracks(iCol)); + mRecTracks[iCol].resize(GetNMCTracks(iCol)); + mFakeTracks[iCol].resize(GetNMCTracks(iCol)); + mMCParam[iCol].resize(GetNMCTracks(iCol)); + memset(mRecTracks[iCol].data(), 0, mRecTracks[iCol].size() * sizeof(mRecTracks[iCol][0])); + memset(mFakeTracks[iCol].data(), 0, mFakeTracks[iCol].size() * sizeof(mFakeTracks[iCol][0])); + for (size_t i = 0; i < mTrackMCLabelsReverse[iCol].size(); i++) { + mTrackMCLabelsReverse[iCol][i] = -1; + } + } + if (mQATasks & taskClusterAttach) { + mClusterParam.resize(GetNMCLabels()); + memset(mClusterParam.data(), 0, mClusterParam.size() * sizeof(mClusterParam[0])); + } + HighResTimer timer; + + mNEvents++; + if (mConfig.writeMCLabels) { + mcEffBuffer.resize(mNEvents); + mcLabelBuffer.resize(mNEvents); + mcEffBuffer[mNEvents - 1].resize(GetNMCTracks(0)); + mcLabelBuffer[mNEvents - 1].resize(nReconstructedTracks); + } + + bool mcAvail = mcPresent() || tracksExtMC; + + if (mcAvail && !tracksExtMC && mTracking->GetParam().rec.nonConsecutiveIDs) { + GPUError("QA incompatible to non-consecutive MC labels"); + return; + } + + if (mcAvail) { + // Assign Track MC Labels + timer.Start(); + if (tracksExternal) { +#ifdef GPUCA_O2_LIB + for (unsigned int i = 0; i < tracksExternal->size(); i++) { + mTrackMCLabels[i] = (*tracksExtMC)[i]; + } +#endif + } else { + auto acc = GPUTPCTrkLbl<true, mcLabelI_t>(GetClusterLabels(), 1.f - mConfig.recThreshold); +#if QA_DEBUG == 0 + GPUCA_OPENMP(parallel for firstprivate(acc)) +#endif + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + acc.reset(); + int nClusters = 0; + const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; + std::vector<mcLabel_t> labels; + for (unsigned int k = 0; k < track.NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + nClusters++; + unsigned int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; + if (hitId >= GetNMCLabels()) { + GPUError("Invalid hit id %u > %d (nClusters %d)", hitId, GetNMCLabels(), mTracking->mIOPtrs.clustersNative ? mTracking->mIOPtrs.clustersNative->nClustersTotal : 0); + throw std::runtime_error("qa error"); + } + acc.addLabel(hitId); + for (int j = 0; j < GetMCLabelNID(hitId); j++) { + if (GetMCLabelID(hitId, j) >= (int)GetNMCTracks(GetMCLabelCol(hitId, j))) { + GPUError("Invalid label %d > %d (hit %d, label %d, col %d)", GetMCLabelID(hitId, j), GetNMCTracks(GetMCLabelCol(hitId, j)), hitId, j, (int)GetMCLabelCol(hitId, j)); + throw std::runtime_error("qa error"); + } + if (GetMCLabelID(hitId, j) >= 0) { + if (QA_DEBUG >= 3 && track.OK()) { + GPUInfo("Track %d Cluster %u Label %d: %d (%f)", i, k, j, GetMCLabelID(hitId, j), GetMCLabelWeight(hitId, j)); + } + } + } + } + + float maxweight, sumweight; + int maxcount; + auto maxLabel = acc.computeLabel(&maxweight, &sumweight, &maxcount); + mTrackMCLabels[i] = maxLabel; + if (QA_DEBUG && track.OK() && GetNMCTracks(maxLabel.getEventID()) > (unsigned int)maxLabel.getTrackID()) { + const mcInfo_t& mc = GetMCTrack(maxLabel); + GPUInfo("Track %d label %d (fake %d) weight %f clusters %d (fitted %d) (%f%% %f%%) Pt %f", i, maxLabel.getTrackID(), (int)(maxLabel.isFake()), maxweight, nClusters, track.NClustersFitted(), 100.f * maxweight / sumweight, 100.f * (float)maxcount / (float)nClusters, + std::sqrt(mc.pX * mc.pX + mc.pY * mc.pY)); + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + const GPUTPCGMMergedTrack* track = mTracking ? &mTracking->mIOPtrs.mergedTracks[i] : nullptr; + mcLabelI_t label = mTrackMCLabels[i]; + if (mQATasks & taskClusterAttach) { + // fill cluster attachment status + if (!track->OK()) { + continue; + } + if (!mTrackMCLabels[i].isValid()) { + for (unsigned int k = 0; k < track->NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + mClusterParam[mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].num].fakeAttached++; + } + continue; + } + if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { + for (unsigned int k = 0; k < track->NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + int hitId = mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].num; + bool correct = false; + for (int j = 0; j < GetMCLabelNID(hitId); j++) { + if (label == GetMCLabel(hitId, j)) { + correct = true; + break; + } + } + if (correct) { + mClusterParam[hitId].attached++; + } else { + mClusterParam[hitId].fakeAttached++; + } + } + } + } + + if (mTrackMCLabels[i].isFake()) { + (GetMCTrackObj(mFakeTracks, label))++; + } else if (tracksExternal || !track->MergedLooper()) { + GetMCTrackObj(mRecTracks, label)++; + if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { + int& revLabel = GetMCTrackObj(mTrackMCLabelsReverse, label); + if (tracksExternal) { +#ifdef GPUCA_O2_LIB + if (revLabel == -1 || fabsf((*tracksExternal)[i].getZ()) < fabsf((*tracksExternal)[revLabel].getZ())) { + revLabel = i; + } +#endif + } else { + const auto* trks = mTracking->mIOPtrs.mergedTracks; + bool comp; + if (revLabel == -1) { + comp = true; + } else if (mTracking->GetParam().par.earlyTpcTransform) { + comp = fabsf(trks[i].GetParam().GetZ() + trks[i].GetParam().GetTZOffset()) < fabsf(trks[revLabel].GetParam().GetZ() + trks[revLabel].GetParam().GetTZOffset()); + } else { + float shift1 = mTracking->GetTPCTransform()->convDeltaTimeToDeltaZinTimeFrame(trks[i].CSide() * GPUChainTracking::NSLICES / 2, trks[i].GetParam().GetTZOffset()); + float shift2 = mTracking->GetTPCTransform()->convDeltaTimeToDeltaZinTimeFrame(trks[revLabel].CSide() * GPUChainTracking::NSLICES / 2, trks[revLabel].GetParam().GetTZOffset()); + comp = fabsf(trks[i].GetParam().GetZ() + shift1) < fabsf(trks[revLabel].GetParam().GetZ() + shift2); + } + if (revLabel == -1 || !trks[revLabel].OK() || (trks[i].OK() && comp)) { + revLabel = i; + } + } + } + } + } + if ((mQATasks & taskClusterAttach) && mTracking->mIOPtrs.mergedTrackHitAttachment) { + // fill cluster adjacent status + for (unsigned int i = 0; i < GetNMCLabels(); i++) { + if (mClusterParam[i].attached == 0 && mClusterParam[i].fakeAttached == 0) { + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; + if (attach & gputpcgmmergertypes::attachFlagMask) { + int track = attach & gputpcgmmergertypes::attachTrackMask; + mcLabelI_t trackL = mTrackMCLabels[track]; + bool fake = true; + for (int j = 0; j < GetMCLabelNID(i); j++) { + // GPUInfo("Attach %x Track %d / %d:%d", attach, track, j, GetMCLabelID(i, j)); + if (trackL == GetMCLabel(i, j)) { + fake = false; + break; + } + } + if (fake) { + mClusterParam[i].fakeAdjacent++; + } else { + mClusterParam[i].adjacent++; + } + } + } + } + } + + if (mConfig.matchMCLabels.size()) { + mGoodHits[mNEvents - 1].resize(GetNMCLabels()); + std::vector<bool> allowMCLabels(GetNMCTracks(0)); + for (unsigned int k = 0; k < GetNMCTracks(0); k++) { + allowMCLabels[k] = false; + } + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + if (!mGoodTracks[mNEvents - 1][i]) { + continue; + } + if (mConfig.matchDisplayMinPt > 0) { + if (!mTrackMCLabels[i].isValid()) { + continue; + } + const mcInfo_t& info = GetMCTrack(mTrackMCLabels[i]); + if (info.pX * info.pX + info.pY * info.pY < mConfig.matchDisplayMinPt * mConfig.matchDisplayMinPt) { + continue; + } + } + + const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; + for (unsigned int j = 0; j < track.NClusters(); j++) { + int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + j].num; + if (GetMCLabelNID(hitId)) { + int mcID = GetMCLabelID(hitId, 0); + if (mcID >= 0) { + allowMCLabels[mcID] = true; + } + } + } + } + for (unsigned int i = 0; i < GetNMCLabels(); i++) { + for (int j = 0; j < GetMCLabelNID(i); j++) { + int mcID = GetMCLabelID(i, j); + if (mcID >= 0 && allowMCLabels[mcID]) { + mGoodHits[mNEvents - 1][i] = true; + } + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Cluster attach status:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + if (matchOnly) { + return; + } + + // Recompute fNWeightCls (might have changed after merging events into timeframes) + for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { + for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { + mMCParam[iCol][i].nWeightCls = 0.; + } + } + for (unsigned int i = 0; i < GetNMCLabels(); i++) { + float weightTotal = 0.f; + for (int j = 0; j < GetMCLabelNID(i); j++) { + if (GetMCLabelID(i, j) >= 0) { + weightTotal += GetMCLabelWeight(i, j); + } + } + for (int j = 0; j < GetMCLabelNID(i); j++) { + if (GetMCLabelID(i, j) >= 0) { + GetMCTrackObj(mMCParam, GetMCLabel(i, j)).nWeightCls += GetMCLabelWeight(i, j) / weightTotal; + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Compute cluster label weights:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + // Compute MC Track Parameters for MC Tracks + GPUCA_OPENMP(parallel for) + for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { + for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { + const mcInfo_t& info = GetMCTrack(i, iCol); + additionalMCParameters& mc2 = mMCParam[iCol][i]; + mc2.pt = std::sqrt(info.pX * info.pX + info.pY * info.pY); + mc2.phi = M_PI + std::atan2(-info.pY, -info.pX); + float p = info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ; + if (p < 1e-18) { + mc2.theta = mc2.eta = 0.f; + } else { + mc2.theta = info.pZ == 0 ? (M_PI / 2) : (std::acos(info.pZ / std::sqrt(p))); + mc2.eta = -std::log(std::tan(0.5 * mc2.theta)); + } + if (mConfig.writeMCLabels) { + std::vector<int>& effBuffer = mcEffBuffer[mNEvents - 1]; + effBuffer[i] = mRecTracks[iCol][i] * 1000 + mFakeTracks[iCol][i]; + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Compute track mc parameters:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + // Fill Efficiency Histograms + if (mQATasks & taskTrackingEff) { + for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { + for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { + if ((mMCTrackMin != -1 && (int)i < mMCTrackMin) || (mMCTrackMax != -1 && (int)i >= mMCTrackMax)) { + continue; + } + const mcInfo_t& info = GetMCTrack(i, iCol); + const additionalMCParameters& mc2 = mMCParam[iCol][i]; + if (mc2.nWeightCls == 0.f) { + continue; + } + const float& mcpt = mc2.pt; + const float& mcphi = mc2.phi; + const float& mceta = mc2.eta; + + if (info.primDaughters) { + continue; + } + if (mc2.nWeightCls < MIN_WEIGHT_CLS) { + continue; + } + int findable = mc2.nWeightCls >= FINDABLE_WEIGHT_CLS; + if (info.pid < 0) { + continue; + } + if (info.charge == 0.f) { + continue; + } + if (mConfig.filterCharge && info.charge * mConfig.filterCharge < 0) { + continue; + } + if (mConfig.filterPID >= 0 && info.pid != mConfig.filterPID) { + continue; + } + + if (fabsf(mceta) > ETA_MAX || mcpt < PT_MIN || mcpt > PT_MAX) { + continue; + } + + float alpha = std::atan2(info.y, info.x); + alpha /= M_PI / 9.f; + alpha = std::floor(alpha); + alpha *= M_PI / 9.f; + alpha += M_PI / 18.f; + + float c = std::cos(alpha); + float s = std::sin(alpha); + float localY = -info.x * s + info.y * c; + + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 2; k++) { + if (k == 0 && findable == 0) { + continue; + } + + int val = (j == 0) ? (mRecTracks[iCol][i] ? 1 : 0) : (j == 1) ? (mRecTracks[iCol][i] ? mRecTracks[iCol][i] - 1 : 0) : (j == 2) ? mFakeTracks[iCol][i] : 1; + if (val == 0) { + continue; + } + + for (int l = 0; l < 5; l++) { + if (info.prim && mcpt < PT_MIN_PRIM) { + continue; + } + if (l != 3 && fabsf(mceta) > ETA_MAX2) { + continue; + } + if (l < 4 && mcpt < 1.f / mConfig.qpt) { + continue; + } + + float pos = l == 0 ? localY : l == 1 ? info.z : l == 2 ? mcphi : l == 3 ? mceta : mcpt; + + mEff[j][k][!info.prim][l][0]->Fill(pos, val); + } + } + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Fill efficiency histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + } + + // Fill Resolution Histograms + if (mQATasks & (taskTrackingRes | taskTrackingResPull)) { + GPUTPCGMPropagator prop; + prop.SetMaxSinPhi(.999); + prop.SetMaterialTPC(); + prop.SetPolynomialField(&mParam.polynomialField); + + for (unsigned int i = 0; i < mTrackMCLabels.size(); i++) { + if (mConfig.writeMCLabels) { + std::vector<int>& labelBuffer = mcLabelBuffer[mNEvents - 1]; + labelBuffer[i] = mTrackMCLabels[i].getTrackID(); + } + if (mTrackMCLabels[i].isFake()) { + continue; + } + const mcInfo_t& mc1 = GetMCTrack(mTrackMCLabels[i]); + const additionalMCParameters& mc2 = GetMCTrackObj(mMCParam, mTrackMCLabels[i]); + + if (mc1.primDaughters) { + continue; + } + if (!tracksExternal) { + if (!mTracking->mIOPtrs.mergedTracks[i].OK()) { + continue; + } + if (mTracking->mIOPtrs.mergedTracks[i].MergedLooper()) { + continue; + } + } + if ((mMCTrackMin != -1 && mTrackMCLabels[i].getTrackID() < mMCTrackMin) || (mMCTrackMax != -1 && mTrackMCLabels[i].getTrackID() >= mMCTrackMax)) { + continue; + } + if (fabsf(mc2.eta) > ETA_MAX || mc2.pt < PT_MIN || mc2.pt > PT_MAX) { + continue; + } + if (mc1.charge == 0.f) { + continue; + } + if (mc1.pid < 0) { + continue; + } + if (mConfig.filterCharge && mc1.charge * mConfig.filterCharge < 0) { + continue; + } + if (mConfig.filterPID >= 0 && mc1.pid != mConfig.filterPID) { + continue; + } + if (mc2.nWeightCls < MIN_WEIGHT_CLS) { + continue; + } + if (mConfig.resPrimaries == 1 && !mc1.prim) { + continue; + } else if (mConfig.resPrimaries == 2 && mc1.prim) { + continue; + } + if (GetMCTrackObj(mTrackMCLabelsReverse, mTrackMCLabels[i]) != (int)i) { + continue; + } + + GPUTPCGMTrackParam param; + float alpha = 0.f; + int side; + if (tracksExternal) { +#ifdef GPUCA_O2_LIB + for (int k = 0; k < 5; k++) { + param.Par()[k] = (*tracksExternal)[i].getParams()[k]; + } + for (int k = 0; k < 15; k++) { + param.Cov()[k] = (*tracksExternal)[i].getCov()[k]; + } + param.X() = (*tracksExternal)[i].getX(); + param.TZOffset() = (*tracksExternal)[i].getTime0(); + alpha = (*tracksExternal)[i].getAlpha(); + side = (*tracksExternal)[i].hasBothSidesClusters() ? 2 : ((*tracksExternal)[i].hasCSideClusters() ? 1 : 0); +#endif + } else { + param = mTracking->mIOPtrs.mergedTracks[i].GetParam(); + alpha = mTracking->mIOPtrs.mergedTracks[i].GetAlpha(); + side = mTracking->mIOPtrs.mergedTracks[i].CCE() ? 2 : (mTracking->mIOPtrs.mergedTracks[i].CSide() ? 1 : 0); + } + + float mclocal[4]; // Rotated x,y,Px,Py mc-coordinates - the MC data should be rotated since the track is propagated best along x + float c = std::cos(alpha); + float s = std::sin(alpha); + float x = mc1.x; + float y = mc1.y; + mclocal[0] = x * c + y * s; + mclocal[1] = -x * s + y * c; + float px = mc1.pX; + float py = mc1.pY; + mclocal[2] = px * c + py * s; + mclocal[3] = -px * s + py * c; + + if (mclocal[0] < TRACK_EXPECTED_REFERENCE_X - 3) { + continue; + } + if (mclocal[0] > param.GetX() + 20) { + continue; + } + if (param.GetX() > mConfig.maxResX) { + continue; + } + + auto getdz = [this, ¶m, &mc1, &side, tracksExternal]() { + if (tracksExternal) { + return param.GetZ(); + } + if (!mParam.par.continuousMaxTimeBin) { + return param.GetZ() - mc1.z; + } +#ifdef GPUCA_TPC_GEOMETRY_O2 + if (!mParam.par.earlyTpcTransform) { + float shift = side == 2 ? 0 : mTracking->GetTPCTransform()->convDeltaTimeToDeltaZinTimeFrame(side * GPUChainTracking::NSLICES / 2, param.GetTZOffset() - mc1.t0); + return param.GetZ() + shift - mc1.z; + } +#endif + return param.Z() + param.TZOffset() - mc1.z; + }; + + prop.SetTrack(¶m, alpha); + bool inFlyDirection = 0; + if (mConfig.strict) { + const float dx = param.X() - std::max<float>(mclocal[0], TRACK_EXPECTED_REFERENCE_X_DEFAULT); // Limit distance check if the O2 MC position is farther inside than the AliRoot MC position. + const float dy = param.Y() - mclocal[1]; + const float dz = getdz(); + if (dx * dx + dy * dy + dz * dz > 5.f * 5.f) { + continue; + } + } + + if (prop.PropagateToXAlpha(mclocal[0], alpha, inFlyDirection)) { + continue; + } + if (fabsf(param.Y() - mclocal[1]) > (mConfig.strict ? 1.f : 4.f) || fabsf(getdz()) > (mConfig.strict ? 1.f : 4.f)) { + continue; + } + float charge = mc1.charge > 0 ? 1.f : -1.f; + + float deltaY = param.GetY() - mclocal[1]; + float deltaZ = getdz(); + float deltaPhiNative = param.GetSinPhi() - mclocal[3] / mc2.pt; + float deltaPhi = std::asin(param.GetSinPhi()) - std::atan2(mclocal[3], mclocal[2]); + float deltaLambdaNative = param.GetDzDs() - mc1.pZ / mc2.pt; + float deltaLambda = std::atan(param.GetDzDs()) - std::atan2(mc1.pZ, mc2.pt); + float deltaPtNative = (param.GetQPt() - charge / mc2.pt) * charge; + float deltaPt = (fabsf(1.f / param.GetQPt()) - mc2.pt) / mc2.pt; + + float paramval[5] = {mclocal[1], mc1.z, mc2.phi, mc2.eta, mc2.pt}; + float resval[5] = {deltaY, deltaZ, mConfig.nativeFitResolutions ? deltaPhiNative : deltaPhi, mConfig.nativeFitResolutions ? deltaLambdaNative : deltaLambda, mConfig.nativeFitResolutions ? deltaPtNative : deltaPt}; + float pullval[5] = {deltaY / std::sqrt(param.GetErr2Y()), deltaZ / std::sqrt(param.GetErr2Z()), deltaPhiNative / std::sqrt(param.GetErr2SinPhi()), deltaLambdaNative / std::sqrt(param.GetErr2DzDs()), deltaPtNative / std::sqrt(param.GetErr2QPt())}; + + for (int j = 0; j < 5; j++) { + for (int k = 0; k < 5; k++) { + if (k != 3 && fabsf(mc2.eta) > ETA_MAX2) { + continue; + } + if (k < 4 && mc2.pt < 1.f / mConfig.qpt) { + continue; + } + if (mQATasks & taskTrackingRes) { + mRes2[j][k]->Fill(resval[j], paramval[k]); + } + if (mQATasks & taskTrackingResPull) { + mPull2[j][k]->Fill(pullval[j], paramval[k]); + } + } + } + } + if (QA_TIMING) { + GPUInfo("QA Time: Fill resolution histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + } + + if (mQATasks & taskClusterAttach) { + // Fill cluster histograms + for (unsigned int iTrk = 0; iTrk < nReconstructedTracks; iTrk++) { + const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[iTrk]; + if (!track.OK()) { + continue; + } + if (!mTrackMCLabels[iTrk].isValid()) { + for (unsigned int k = 0; k < track.NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; + float totalWeight = 0.; + for (int j = 0; j < GetMCLabelNID(hitId); j++) { + if (GetMCLabelID(hitId, j) >= 0 && GetMCTrackObj(mMCParam, GetMCLabel(hitId, j)).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + totalWeight += GetMCLabelWeight(hitId, j); + } + } + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId]; + CHECK_CLUSTER_STATE_NOCOUNT(); + if (totalWeight > 0) { + float weight = 1.f / (totalWeight * (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached)); + for (int j = 0; j < GetMCLabelNID(hitId); j++) { + mcLabelI_t label = GetMCLabel(hitId, j); + if (!label.isFake() && GetMCTrackObj(mMCParam, label).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + float pt = GetMCTrackObj(mMCParam, label).pt; + if (pt < PT_MIN_CLUST) { + pt = PT_MIN_CLUST; + } + mClusters[CL_fake]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + if (GetMCTrackObj(mRecTracks, label)) { + mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + } + mClusters[CL_all]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + if (protect || physics) { + mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + } + if (physics) { + mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(hitId, j) * weight); + } + } + } + } else { + float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached); + mClusters[CL_fake]->Fill(0.f, weight); + mClusters[CL_att_adj]->Fill(0.f, weight); + mClusters[CL_all]->Fill(0.f, weight); + mClusterCounts.nUnaccessible += weight; + if (protect || physics) { + mClusters[CL_prot]->Fill(0.f, weight); + } + if (physics) { + mClusters[CL_physics]->Fill(0.f, weight); + } + } + } + continue; + } + mcLabelI_t label = mTrackMCLabels[iTrk]; + if (mMCTrackMin != -1 && (label.getTrackID() < mMCTrackMin || label.getTrackID() >= mMCTrackMax)) { + continue; + } + for (unsigned int k = 0; k < track.NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; + float pt = GetMCTrackObj(mMCParam, label).pt; + if (pt < PT_MIN_CLUST) { + pt = PT_MIN_CLUST; + } + float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached); + bool correct = false; + for (int j = 0; j < GetMCLabelNID(hitId); j++) { + if (label == GetMCLabel(hitId, j)) { + correct = true; + break; + } + } + if (correct) { + mClusters[CL_attached]->Fill(pt, weight); + mClusters[CL_tracks]->Fill(pt, weight); + } else { + mClusters[CL_fake]->Fill(pt, weight); + } + mClusters[CL_att_adj]->Fill(pt, weight); + mClusters[CL_all]->Fill(pt, weight); + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId]; + CHECK_CLUSTER_STATE_NOCOUNT(); + if (protect || physics) { + mClusters[CL_prot]->Fill(pt, weight); + } + if (physics) { + mClusters[CL_physics]->Fill(pt, weight); + } + } + } + for (unsigned int i = 0; i < GetNMCLabels(); i++) { + if ((mMCTrackMin != -1 && GetMCLabelID(i, 0) < mMCTrackMin) || (mMCTrackMax != -1 && GetMCLabelID(i, 0) >= mMCTrackMax)) { + continue; + } + if (mClusterParam[i].attached || mClusterParam[i].fakeAttached) { + continue; + } + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; + CHECK_CLUSTER_STATE_NOCOUNT(); + if (mClusterParam[i].adjacent) { + int label = mTracking->mIOPtrs.mergedTrackHitAttachment[i] & gputpcgmmergertypes::attachTrackMask; + if (!mTrackMCLabels[label].isValid()) { + float totalWeight = 0.; + for (int j = 0; j < GetMCLabelNID(i); j++) { + mcLabelI_t labelT = GetMCLabel(i, j); + if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + totalWeight += GetMCLabelWeight(i, j); + } + } + float weight = 1.f / totalWeight; + if (totalWeight > 0) { + for (int j = 0; j < GetMCLabelNID(i); j++) { + mcLabelI_t labelT = GetMCLabel(i, j); + if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + float pt = GetMCTrackObj(mMCParam, labelT).pt; + if (pt < PT_MIN_CLUST) { + pt = PT_MIN_CLUST; + } + if (GetMCTrackObj(mRecTracks, labelT)) { + mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(i, j) * weight); + } + mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(i, j) * weight); + mClusters[CL_fakeAdj]->Fill(pt, GetMCLabelWeight(i, j) * weight); + mClusters[CL_all]->Fill(pt, GetMCLabelWeight(i, j) * weight); + if (protect || physics) { + mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(i, j) * weight); + } + if (physics) { + mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(i, j) * weight); + } + } + } + } else { + mClusters[CL_att_adj]->Fill(0.f, 1.f); + mClusters[CL_fakeAdj]->Fill(0.f, 1.f); + mClusters[CL_all]->Fill(0.f, 1.f); + mClusterCounts.nUnaccessible++; + if (protect || physics) { + mClusters[CL_prot]->Fill(0.f, 1.f); + } + if (physics) { + mClusters[CL_physics]->Fill(0.f, 1.f); + } + } + } else { + float pt = GetMCTrackObj(mMCParam, mTrackMCLabels[label]).pt; + if (pt < PT_MIN_CLUST) { + pt = PT_MIN_CLUST; + } + mClusters[CL_att_adj]->Fill(pt, 1.f); + mClusters[CL_tracks]->Fill(pt, 1.f); + mClusters[CL_all]->Fill(pt, 1.f); + if (protect || physics) { + mClusters[CL_prot]->Fill(pt, 1.f); + } + if (physics) { + mClusters[CL_physics]->Fill(pt, 1.f); + } + } + } else { + float totalWeight = 0.; + for (int j = 0; j < GetMCLabelNID(i); j++) { + mcLabelI_t labelT = GetMCLabel(i, j); + if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + totalWeight += GetMCLabelWeight(i, j); + } + } + if (totalWeight > 0) { + for (int j = 0; j < GetMCLabelNID(i); j++) { + mcLabelI_t label = GetMCLabel(i, j); + if (!label.isFake() && GetMCTrackObj(mMCParam, label).pt > GPUCA_MIN_TRACK_PT_DEFAULT) { + float pt = GetMCTrackObj(mMCParam, label).pt; + if (pt < PT_MIN_CLUST) { + pt = PT_MIN_CLUST; + } + float weight = GetMCLabelWeight(i, j) / totalWeight; + if (mClusterParam[i].fakeAdjacent) { + mClusters[CL_fakeAdj]->Fill(pt, weight); + } + if (mClusterParam[i].fakeAdjacent) { + mClusters[CL_att_adj]->Fill(pt, weight); + } + if (GetMCTrackObj(mRecTracks, label)) { + mClusters[CL_tracks]->Fill(pt, weight); + } + mClusters[CL_all]->Fill(pt, weight); + if (protect || physics) { + mClusters[CL_prot]->Fill(pt, weight); + } + if (physics) { + mClusters[CL_physics]->Fill(pt, weight); + } + } + } + } else { + if (mClusterParam[i].fakeAdjacent) { + mClusters[CL_fakeAdj]->Fill(0.f, 1.f); + } + if (mClusterParam[i].fakeAdjacent) { + mClusters[CL_att_adj]->Fill(0.f, 1.f); + } + mClusters[CL_all]->Fill(0.f, 1.f); + mClusterCounts.nUnaccessible++; + if (protect || physics) { + mClusters[CL_prot]->Fill(0.f, 1.f); + } + if (physics) { + mClusters[CL_physics]->Fill(0.f, 1.f); + } + } + } + } + + if (QA_TIMING) { + GPUInfo("QA Time: Fill cluster histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + } + } else if (!mConfig.inputHistogramsOnly && !mConfig.noMC && (mQATasks & (taskTrackingEff | taskTrackingRes | taskTrackingResPull | taskClusterAttach))) { + GPUWarning("No MC information available, only running partial TPC QA!"); + } + + if (mQATasks & taskTrackStatistics) { + // Fill track statistic histograms + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; + if (!track.OK()) { + continue; + } + mTracks->Fill(1.f / fabsf(track.GetParam().GetQPt())); + mNCl->Fill(track.NClustersFitted()); + } + + if (QA_TIMING) { + GPUInfo("QA Time: Fill track statistics:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + } + + unsigned int nCl = clNative ? clNative->nClustersTotal : mTracking->GetTPCMerger().NMaxClusters(); + mClusterCounts.nTotal += nCl; + if (mQATasks & taskClusterCounts) { + for (unsigned int i = 0; i < nCl; i++) { + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; + CHECK_CLUSTER_STATE(); + + if (mcAvail) { + float totalWeight = 0, weight400 = 0, weight40 = 0; + for (int j = 0; j < GetMCLabelNID(i); j++) { + const auto& label = GetMCLabel(i, j); + if (GetMCLabelID(label) >= 0) { + totalWeight += GetMCLabelWeight(label); + if (GetMCTrackObj(mMCParam, label).pt >= 0.4) { + weight400 += GetMCLabelWeight(label); + } + if (GetMCTrackObj(mMCParam, label).pt <= 0.04) { + weight40 += GetMCLabelWeight(label); + } + } + } + if (totalWeight > 0 && 10.f * weight400 >= totalWeight) { + if (!unattached && !protect && !physics) { + mClusterCounts.nFakeRemove400++; + int totalFake = weight400 < 0.9f * totalWeight; + if (totalFake) { + mClusterCounts.nFullFakeRemove400++; + } + /*printf("Fake removal (%d): Hit %7d, attached %d lowPt %d looper %d tube200 %d highIncl %d tube %d bad %d recPt %7.2f recLabel %6d", totalFake, i, (int) (mClusterParam[i].attached || mClusterParam[i].fakeAttached), + (int) lowPt, (int) ((attach & gputpcgmmergertypes::attachGoodLeg) == 0), (int) ((attach & gputpcgmmergertypes::attachTube) && mev200), + (int) ((attach & gputpcgmmergertypes::attachHighIncl) != 0), (int) ((attach & gputpcgmmergertypes::attachTube) != 0), (int) ((attach & gputpcgmmergertypes::attachGood) == 0), + fabsf(qpt) > 0 ? 1.f / qpt : 0.f, id); + for (int j = 0;j < GetMCLabelNID(i);j++) + { + //if (GetMCLabelID(i, j) < 0) break; + printf(" - label%d %6d weight %5d", j, GetMCLabelID(i, j), (int) GetMCLabelWeight(i, j)); + if (GetMCLabelID(i, j) >= 0) printf(" - pt %7.2f", mMCParam[GetMCLabelID(i, j)].pt); + else printf(" "); + } + printf("\n");*/ + } + mClusterCounts.nAbove400++; + } + if (totalWeight > 0 && weight40 >= 0.9 * totalWeight) { + mClusterCounts.nBelow40++; + if (protect || physics) { + mClusterCounts.nFakeProtect40++; + } + } + } + if (physics) { + mClusterCounts.nPhysics++; + } + if (physics || protect) { + mClusterCounts.nProt++; + } + if (unattached) { + mClusterCounts.nUnattached++; + } + } + } + + // Process cluster count statistics + if ((mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) { + DoClusterCounts(nullptr); + mClusterCounts = counts_t(); + } + + if (QA_TIMING) { + GPUInfo("QA Time: Cluster Counts:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + // Create CSV DumpTrackHits + if (mConfig.csvDump) { + if (!mTracking->GetParam().par.earlyTpcTransform) { + GPUError("Unsupported settings for csv dump\n"); + return; + } + int totalNCls = GetNMCLabels(); + if (totalNCls == 0) { + for (unsigned int iSlice = 0; iSlice < GPUChainTracking::NSLICES; iSlice++) { + totalNCls += mTracking->mIOPtrs.nClusterData[iSlice]; + } + } + + std::vector<float> clusterInfo(totalNCls); + memset(clusterInfo.data(), 0, clusterInfo.size() * sizeof(clusterInfo[0])); + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; + if (!track.OK()) { + continue; + } + for (unsigned int k = 0; k < track.NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + continue; + } + int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; + float pt = fabsf(1.f / track.GetParam().GetQPt()); + if (pt > clusterInfo[hitId]) { + clusterInfo[hitId] = pt; + } + } + } + static int csvNum = 0; + char fname[256]; + sprintf(fname, "dump.%d.csv", csvNum); + FILE* fp = fopen(fname, "w+"); + fprintf(fp, "x;y;z;reconstructedPt;individualMomentum;individualTransverseMomentum;trackLabel1;trackLabel2;trackLabel3;removed\n\n"); + int dumpClTot = 0, dumpClLeft = 0, dumpClRem = 0; + for (unsigned int iSlice = 0; iSlice < GPUChainTracking::NSLICES; iSlice++) { + for (unsigned int i = 0; i < mTracking->mIOPtrs.nClusterData[iSlice]; i++) { + const auto& cl = mTracking->mIOPtrs.clusterData[iSlice][i]; + float x, y, z; + const int cid = cl.id; + mTracking->GetParam().Slice2Global(iSlice, cl.x, cl.y, cl.z, &x, &y, &z); + + float totalWeight = 0.f; + if (mcPresent()) { + for (int j = 0; j < GetMCLabelNID(cid); j++) { + if (GetMCLabelID(cid, j) >= 0) { + totalWeight += GetMCLabelWeight(cid, j); + } + } + } + + float maxPt = 0.; + float p = 0.; + + if (totalWeight > 0) { + for (int j = 0; j < GetMCLabelNID(cid); j++) { + const mcLabelI_t label = GetMCLabel(cid, j); + if (!label.isFake() && GetMCLabelWeight(cid, j) > 0.3 * totalWeight) { + const mcInfo_t& info = GetMCTrack(label); + const additionalMCParameters& mc2 = GetMCTrackObj(mMCParam, label); + const float pt = fabsf(mc2.pt); + if (pt > maxPt) { + maxPt = pt; + p = std::sqrt(info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ); + } + } + } + } + int labels[3] = {}; + if (mcPresent()) { + for (int j = 0; j < GetMCLabelNID(cid); j++) { + labels[j] = GetMCLabelID(cid, j); + } + } + + dumpClTot++; + int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[cid]; + CHECK_CLUSTER_STATE(); + if (protect || physics) { + continue; + } + if (attach && qpt < 50) { + continue; + } + dumpClLeft++; + if (attach) { + dumpClRem++; + } + + fprintf(fp, "%f;%f;%f;%f;%f;%f;%d;%d;%d;%d\n", x, y, z, attach ? 1.f / qpt : 0.f, p, maxPt, labels[0], labels[1], labels[2], attach ? 1 : 0); + } + } + fclose(fp); + if (mcPresent()) { + sprintf(fname, "dump_event.%d.csv", csvNum++); + fp = fopen(fname, "w+"); + fprintf(fp, "trackLabel;trackMomentum;trackMomentumTransverse;trackMomentumZ\n\n"); + for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { + for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { + const mcInfo_t& info = GetMCTrack(i, iCol); + additionalMCParameters& mc2 = mMCParam[iCol][i]; + if (mc2.nWeightCls > 0) { + fprintf(fp, "%u;%f;%f;%f\n", i, std::sqrt(info.pX * info.pX + info.pY * info.pY + info.pZ * info.pZ), mc2.pt, info.pZ); + } + } + } + fclose(fp); + } + GPUInfo("Wrote %s,%d clusters in total, %d left, %d to be removed", fname, dumpClTot, dumpClLeft, dumpClRem); + } +} + +void GPUQA::GetName(char* fname, int k) +{ + const int nNewInput = mConfig.inputHistogramsOnly ? 0 : 1; + if (k || mConfig.inputHistogramsOnly || mConfig.name.size()) { + if (!(mConfig.inputHistogramsOnly || k)) { + snprintf(fname, 1024, "%s - ", mConfig.name.c_str()); + } else if (mConfig.compareInputNames.size() > (unsigned)(k - nNewInput)) { + snprintf(fname, 1024, "%s - ", mConfig.compareInputNames[k - nNewInput].c_str()); + } else { + strcpy(fname, mConfig.compareInputs[k - nNewInput].c_str()); + if (strlen(fname) > 5 && strcmp(fname + strlen(fname) - 5, ".root") == 0) { + fname[strlen(fname) - 5] = 0; + } + strcat(fname, " - "); + } + } else { + fname[0] = 0; + } +} + +template <class T> +T* GPUQA::GetHist(T*& ee, std::vector<std::unique_ptr<TFile>>& tin, int k, int nNewInput) +{ + T* e = ee; + if ((mConfig.inputHistogramsOnly || k) && (e = dynamic_cast<T*>(tin[k - nNewInput]->Get(e->GetName()))) == nullptr) { + GPUWarning("Missing histogram in input %s: %s", mConfig.compareInputs[k - nNewInput], ee->GetName()); + return (nullptr); + } + ee = e; + return (e); +} + +void GPUQA::DrawQAHistogramsCleanup() +{ + clearGarbagageCollector(); +} + +void GPUQA::resetHists() +{ + if (!mQAInitialized) { + throw std::runtime_error("QA not initialized"); + } + if (mHaveExternalHists) { + throw std::runtime_error("Cannot reset external hists"); + } + for (auto& h : *mHist1D) { + h.Reset(); + } + for (auto& h : *mHist2D) { + h.Reset(); + } + for (auto& h : *mHist1Dd) { + h.Reset(); + } + mClusterCounts = counts_t(); +} + +int GPUQA::DrawQAHistograms(TObjArray* qcout) +{ + if (!mQAInitialized) { + throw std::runtime_error("QA not initialized"); + } + + std::vector<Color_t> colorNums(COLORCOUNT); + for (int i = 0; i < COLORCOUNT; i++) { + colorNums[i] = qcout ? defaultColorNUms[i] : mColors[i]->GetNumber(); + } + + bool mcAvail = mcPresent(); + char name[2048], fname[1024]; + + const int nNewInput = mConfig.inputHistogramsOnly ? 0 : 1; + const int ConfigNumInputs = nNewInput + mConfig.compareInputs.size(); + + std::vector<std::unique_ptr<TFile>> tin; + for (unsigned int i = 0; i < mConfig.compareInputs.size(); i++) { + tin.emplace_back(std::make_unique<TFile>(mConfig.compareInputs[i].c_str())); + } + std::unique_ptr<TFile> tout = nullptr; + if (mConfig.output.size()) { + tout = std::make_unique<TFile>(mConfig.output.c_str(), "RECREATE"); + } + + if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) { + float legendSpacingString = 0.025; + for (int i = 0; i < ConfigNumInputs; i++) { + GetName(fname, i); + if (strlen(fname) * 0.006 > legendSpacingString) { + legendSpacingString = strlen(fname) * 0.006; + } + } + + // Create Canvas / Pads for Efficiency Histograms + if (mQATasks & taskTrackingEff) { + for (int ii = 0; ii < 6; ii++) { + int i = ii == 5 ? 4 : ii; + sprintf(fname, "eff_vs_%s_layout", VSPARAMETER_NAMES[ii]); + sprintf(name, "Efficiency versus %s", VSPARAMETER_NAMES[i]); + mCEff[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCEff[ii]->cd(); + float dy = 1. / 2.; + mPEff[ii][0] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPEff[ii][0]->Draw(); + mPEff[ii][0]->SetRightMargin(0.04); + mPEff[ii][1] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPEff[ii][1]->Draw(); + mPEff[ii][1]->SetRightMargin(0.04); + mPEff[ii][2] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 0.5, dy * 2 - .001); + mPEff[ii][2]->Draw(); + mPEff[ii][2]->SetRightMargin(0.04); + mPEff[ii][3] = createGarbageCollected<TPad>("p3", "", 0.5, dy * 1, 1.0, dy * 2 - .001); + mPEff[ii][3]->Draw(); + mPEff[ii][3]->SetRightMargin(0.04); + mLEff[ii] = createGarbageCollected<TLegend>(0.92 - legendSpacingString * 1.45, 0.83 - (0.93 - 0.82) / 2. * (float)ConfigNumInputs, 0.98, 0.849); + SetLegend(mLEff[ii]); + } + } + + // Create Canvas / Pads for Resolution Histograms + if (mQATasks & taskTrackingRes) { + for (int ii = 0; ii < 7; ii++) { + int i = ii == 5 ? 4 : ii; + if (ii == 6) { + sprintf(fname, "res_integral_layout"); + sprintf(name, "Integral Resolution"); + } else { + sprintf(fname, "res_vs_%s_layout", VSPARAMETER_NAMES[ii]); + sprintf(name, "Resolution versus %s", VSPARAMETER_NAMES[i]); + } + mCRes[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCRes[ii]->cd(); + gStyle->SetOptFit(1); + + float dy = 1. / 2.; + mPRes[ii][3] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPRes[ii][3]->Draw(); + mPRes[ii][3]->SetRightMargin(0.04); + mPRes[ii][4] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPRes[ii][4]->Draw(); + mPRes[ii][4]->SetRightMargin(0.04); + mPRes[ii][0] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); + mPRes[ii][0]->Draw(); + mPRes[ii][0]->SetRightMargin(0.04); + mPRes[ii][0]->SetLeftMargin(0.15); + mPRes[ii][1] = createGarbageCollected<TPad>("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); + mPRes[ii][1]->Draw(); + mPRes[ii][1]->SetRightMargin(0.04); + mPRes[ii][1]->SetLeftMargin(0.135); + mPRes[ii][2] = createGarbageCollected<TPad>("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); + mPRes[ii][2]->Draw(); + mPRes[ii][2]->SetRightMargin(0.06); + mPRes[ii][2]->SetLeftMargin(0.135); + if (ii < 6) { + mLRes[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLRes[ii]); + } + } + } + + // Create Canvas / Pads for Pull Histograms + if (mQATasks & taskTrackingResPull) { + for (int ii = 0; ii < 7; ii++) { + int i = ii == 5 ? 4 : ii; + + if (ii == 6) { + sprintf(fname, "pull_integral_layout"); + sprintf(name, "Integral Pull"); + } else { + sprintf(fname, "pull_vs_%s_layout", VSPARAMETER_NAMES[ii]); + sprintf(name, "Pull versus %s", VSPARAMETER_NAMES[i]); + } + mCPull[ii] = createGarbageCollected<TCanvas>(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCPull[ii]->cd(); + gStyle->SetOptFit(1); + + float dy = 1. / 2.; + mPPull[ii][3] = createGarbageCollected<TPad>("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPPull[ii][3]->Draw(); + mPPull[ii][3]->SetRightMargin(0.04); + mPPull[ii][4] = createGarbageCollected<TPad>("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPPull[ii][4]->Draw(); + mPPull[ii][4]->SetRightMargin(0.04); + mPPull[ii][0] = createGarbageCollected<TPad>("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); + mPPull[ii][0]->Draw(); + mPPull[ii][0]->SetRightMargin(0.04); + mPPull[ii][0]->SetLeftMargin(0.15); + mPPull[ii][1] = createGarbageCollected<TPad>("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); + mPPull[ii][1]->Draw(); + mPPull[ii][1]->SetRightMargin(0.04); + mPPull[ii][1]->SetLeftMargin(0.135); + mPPull[ii][2] = createGarbageCollected<TPad>("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); + mPPull[ii][2]->Draw(); + mPPull[ii][2]->SetRightMargin(0.06); + mPPull[ii][2]->SetLeftMargin(0.135); + if (ii < 6) { + mLPull[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLPull[ii]); + } + } + } + + // Create Canvas for Cluster Histos + if (mQATasks & taskClusterAttach) { + for (int i = 0; i < 3; i++) { + sprintf(fname, "clusters_%s_layout", CLUSTER_TYPES[i]); + mCClust[i] = createGarbageCollected<TCanvas>(fname, CLUSTER_TITLES[i], 0, 0, 700, 700. * 2. / 3.); + mCClust[i]->cd(); + mPClust[i] = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); + mPClust[i]->Draw(); + float y1 = i != 1 ? 0.77 : 0.27, y2 = i != 1 ? 0.9 : 0.42; + mLClust[i] = createGarbageCollected<TLegend>(i == 2 ? 0.1 : (0.65 - legendSpacingString * 1.45), y2 - (y2 - y1) * (ConfigNumInputs + (i != 1) / 2.) + 0.005, i == 2 ? (0.3 + legendSpacingString * 1.45) : 0.9, y2); + SetLegend(mLClust[i]); + } + } + + // Create Canvas for track statistic histos + if (mQATasks & taskTrackStatistics) { + mCTracks = createGarbageCollected<TCanvas>("ctracks", "Track Pt", 0, 0, 700, 700. * 2. / 3.); + mCTracks->cd(); + mPTracks = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); + mPTracks->Draw(); + mLTracks = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLTracks); + + mCNCl = createGarbageCollected<TCanvas>("cncl", "Number of clusters per track", 0, 0, 700, 700. * 2. / 3.); + mCNCl->cd(); + mPNCl = createGarbageCollected<TPad>("p0", "", 0.0, 0.0, 1.0, 1.0); + mPNCl->Draw(); + mLNCl = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLNCl); + } + } + + if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && (mQATasks & taskTrackingEff)) { + GPUInfo("QA Stats: Eff: Tracks Prim %d (Eta %d, Pt %d) %f%% (%f%%) Sec %d (Eta %d, Pt %d) %f%% (%f%%) - Res: Tracks %d (Eta %d, Pt %d)", (int)mEff[3][1][0][0][0]->GetEntries(), (int)mEff[3][1][0][3][0]->GetEntries(), (int)mEff[3][1][0][4][0]->GetEntries(), + mEff[0][0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0][0]->GetSumOfWeights()), (int)mEff[3][1][1][0][0]->GetEntries(), (int)mEff[3][1][1][3][0]->GetEntries(), + (int)mEff[3][1][1][4][0]->GetEntries(), mEff[0][0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0][0]->GetSumOfWeights()), mEff[0][1][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0][0]->GetSumOfWeights()), (int)mRes2[0][0]->GetEntries(), + (int)mRes2[0][3]->GetEntries(), (int)mRes2[0][4]->GetEntries()); + } + + int flagShowVsPtLog = (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) ? 1 : 0; + + if (mQATasks & taskTrackingEff) { + // Process / Draw Efficiency Histograms + for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { + int i = ii == 5 ? 4 : ii; + for (int k = 0; k < ConfigNumInputs; k++) { + for (int j = 0; j < 4; j++) { + if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) { + mPEff[ii][j]->cd(); + } + for (int l = 0; l < 3; l++) { + if (k == 0 && mConfig.inputHistogramsOnly == 0 && ii != 5) { + if (l == 0) { + // Divide eff, compute all for fake/clone + mEff[0][j / 2][j % 2][i][1]->Divide(mEff[l][j / 2][j % 2][i][0], mEff[3][j / 2][j % 2][i][0], 1, 1, "B"); + mEff[3][j / 2][j % 2][i][1]->Reset(); // Sum up rec + clone + fake for clone/fake rate + mEff[3][j / 2][j % 2][i][1]->Add(mEff[0][j / 2][j % 2][i][0]); + mEff[3][j / 2][j % 2][i][1]->Add(mEff[1][j / 2][j % 2][i][0]); + mEff[3][j / 2][j % 2][i][1]->Add(mEff[2][j / 2][j % 2][i][0]); + } else { + // Divide fake/clone + mEff[l][j / 2][j % 2][i][1]->Divide(mEff[l][j / 2][j % 2][i][0], mEff[3][j / 2][j % 2][i][1], 1, 1, "B"); + } + } + + TH1F* e = mEff[l][j / 2][j % 2][i][1]; + + e->SetStats(kFALSE); + e->SetMaximum(1.02); + e->SetMinimum(-0.02); + if (!mConfig.inputHistogramsOnly && k == 0) { + if (tout) { + mEff[l][j / 2][j % 2][i][0]->Write(); + e->Write(); + if (l == 2) { + mEff[3][j / 2][j % 2][i][0]->Write(); // Store also all histogram! + } + } + } else if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetTitle(EFFICIENCY_TITLES[j]); + e->GetYaxis()->SetTitle("(Efficiency)"); + e->GetXaxis()->SetTitle(XAXIS_TITLES[i]); + + e->SetLineWidth(1); + e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); + SetAxisSize(e); + if (qcout && !mConfig.shipToQCAsCanvas) { + qcout->Add(e); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + e->SetMarkerColor(kBlack); + e->SetLineColor(colorNums[(l == 2 ? (ConfigNumInputs * 2 + k) : (k * 2 + l)) % COLORCOUNT]); + e->Draw(k || l ? "same" : ""); + if (j == 0) { + GetName(fname, k); + sprintf(name, "%s%s", fname, EFF_NAMES[l]); + mLEff[ii]->AddEntry(e, name, "l"); + } + if (ii == 5) { + mPEff[ii][j]->SetLogx(); + } + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + mCEff[ii]->cd(); + ChangePadTitleSize(mPEff[ii][j], 0.056); + } + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + mLEff[ii]->Draw(); + + if (qcout) { + qcout->Add(mCEff[ii]); + } + if (!mConfig.enableLocalOutput) { + continue; + } + doPerfFigure(0.2, 0.295, 0.025); + mCEff[ii]->Print(Form("plots/eff_vs_%s.pdf", VSPARAMETER_NAMES[ii])); + if (mConfig.writeRootFiles) { + mCEff[ii]->Print(Form("plots/eff_vs_%s.root", VSPARAMETER_NAMES[ii])); + } + } + } + + if (mQATasks & (taskTrackingRes | taskTrackingResPull)) { + // Process / Draw Resolution Histograms + TH1D *resIntegral[5] = {}, *pullIntegral[5] = {}; + TCanvas* cfit = nullptr; + std::unique_ptr<TF1> customGaus = std::make_unique<TF1>("G", "[0]*exp(-(x-[1])*(x-[1])/(2.*[2]*[2]))"); + for (int p = 0; p < 2; p++) { + if ((p == 0 && (mQATasks & taskTrackingRes) == 0) || (p == 1 && (mQATasks & taskTrackingResPull) == 0)) { + continue; + } + for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { + TCanvas* can = p ? mCPull[ii] : mCRes[ii]; + TLegend* leg = p ? mLPull[ii] : mLRes[ii]; + int i = ii == 5 ? 4 : ii; + for (int j = 0; j < 5; j++) { + TH2F* src = p ? mPull2[j][i] : mRes2[j][i]; + TH1F** dst = p ? mPull[j][i] : mRes[j][i]; + TH1D*& dstIntegral = p ? pullIntegral[j] : resIntegral[j]; + TPad* pad = p ? mPPull[ii][j] : mPRes[ii][j]; + + if (!mConfig.inputHistogramsOnly && ii != 5) { + if (cfit == nullptr) { + cfit = createGarbageCollected<TCanvas>(); + } + cfit->cd(); + + TAxis* axis = src->GetYaxis(); + int nBins = axis->GetNbins(); + int integ = 1; + for (int bin = 1; bin <= nBins; bin++) { + int bin0 = std::max(bin - integ, 0); + int bin1 = std::min(bin + integ, nBins); + std::unique_ptr<TH1D> proj{src->ProjectionX("proj", bin0, bin1)}; + proj->ClearUnderflowAndOverflow(); + if (proj->GetEntries()) { + unsigned int rebin = 1; + while (proj->GetMaximum() < 50 && rebin < sizeof(RES_AXIS_BINS) / sizeof(RES_AXIS_BINS[0])) { + proj->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]); + rebin++; + } + + if (proj->GetEntries() < 20 || proj->GetRMS() < 0.00001) { + dst[0]->SetBinContent(bin, proj->GetRMS()); + dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS())); + dst[1]->SetBinContent(bin, proj->GetMean()); + dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS())); + } else { + proj->GetXaxis()->SetRangeUser(proj->GetMean() - 6. * proj->GetRMS(), proj->GetMean() + 6. * proj->GetRMS()); + proj->GetXaxis()->SetRangeUser(proj->GetMean() - 3. * proj->GetRMS(), proj->GetMean() + 3. * proj->GetRMS()); + bool forceLogLike = proj->GetMaximum() < 20; + for (int k = forceLogLike ? 2 : 0; k < 3; k++) { + proj->Fit("gaus", forceLogLike || k == 2 ? "sQl" : k ? "sQww" : "sQ"); + TF1* fitFunc = proj->GetFunction("gaus"); + + if (k && !forceLogLike) { + customGaus->SetParameters(fitFunc->GetParameter(0), fitFunc->GetParameter(1), fitFunc->GetParameter(2)); + proj->Fit(customGaus.get(), "sQ"); + fitFunc = customGaus.get(); + } + + const float sigma = fabs(fitFunc->GetParameter(2)); + dst[0]->SetBinContent(bin, sigma); + dst[1]->SetBinContent(bin, fitFunc->GetParameter(1)); + dst[0]->SetBinError(bin, fitFunc->GetParError(2)); + dst[1]->SetBinError(bin, fitFunc->GetParError(1)); + + const bool fail1 = sigma <= 0.f; + const bool fail2 = fabs(proj->GetMean() - dst[1]->GetBinContent(bin)) > std::min<float>(p ? PULL_AXIS : mConfig.nativeFitResolutions ? RES_AXES_NATIVE[j] : RES_AXES[j], 3.f * proj->GetRMS()); + const bool fail3 = dst[0]->GetBinContent(bin) > 3.f * proj->GetRMS() || dst[0]->GetBinError(bin) > 1 || dst[1]->GetBinError(bin) > 1; + const bool fail4 = fitFunc->GetParameter(0) < proj->GetMaximum() / 5.; + const bool fail = fail1 || fail2 || fail3 || fail4; + // if (p == 0 && ii == 4 && j == 2) DrawHisto(proj, Form("Hist_bin_%d-%d_vs_%d____%d_%d___%f-%f___%f-%f___%d.pdf", p, j, ii, bin, k, dst[0]->GetBinContent(bin), proj->GetRMS(), dst[1]->GetBinContent(bin), proj->GetMean(), (int) fail), ""); + + if (!fail) { + break; + } else if (k >= 2) { + dst[0]->SetBinContent(bin, proj->GetRMS()); + dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS())); + dst[1]->SetBinContent(bin, proj->GetMean()); + dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS())); + } + } + } + } else { + dst[0]->SetBinContent(bin, 0.f); + dst[0]->SetBinError(bin, 0.f); + dst[1]->SetBinContent(bin, 0.f); + dst[1]->SetBinError(bin, 0.f); + } + } + if (ii == 0) { + dstIntegral = src->ProjectionX(mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j], 0, nBins + 1); + unsigned int rebin = 1; + while (dstIntegral->GetMaximum() < 50 && rebin < sizeof(RES_AXIS_BINS) / sizeof(RES_AXIS_BINS[0])) { + dstIntegral->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]); + rebin++; + } + } + } + if (ii == 0) { + if (mConfig.inputHistogramsOnly) { + dstIntegral = createGarbageCollected<TH1D>(); + } + sprintf(fname, p ? "IntPull%s" : "IntRes%s", VSPARAMETER_NAMES[j]); + sprintf(name, p ? "%s Pull" : "%s Resolution", p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j]); + dstIntegral->SetName(fname); + dstIntegral->SetTitle(name); + } + if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) { + pad->cd(); + } + int numColor = 0; + float tmpMax = -1000.; + float tmpMin = 1000.; + + for (int l = 0; l < 2; l++) { + for (int k = 0; k < ConfigNumInputs; k++) { + TH1F* e = dst[l]; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + if (nNewInput && k == 0 && ii != 5) { + if (p == 0) { + e->Scale(mConfig.nativeFitResolutions ? SCALE_NATIVE[j] : SCALE[j]); + } + } + if (ii == 4) { + e->GetXaxis()->SetRangeUser(0.2, PT_MAX); + } else if (LOG_PT_MIN > 0 && ii == 5) { + e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX); + } else if (ii == 5) { + e->GetXaxis()->SetRange(1, 0); + } + e->SetMinimum(-1111); + e->SetMaximum(-1111); + + if (e->GetMaximum() > tmpMax) { + tmpMax = e->GetMaximum(); + } + if (e->GetMinimum() < tmpMin) { + tmpMin = e->GetMinimum(); + } + } + } + + float tmpSpan; + tmpSpan = tmpMax - tmpMin; + tmpMax += tmpSpan * .02; + tmpMin -= tmpSpan * .02; + if (j == 2 && i < 3) { + tmpMax += tmpSpan * 0.13 * ConfigNumInputs; + } + + for (int k = 0; k < ConfigNumInputs; k++) { + for (int l = 0; l < 2; l++) { + TH1F* e = dst[l]; + if (!mConfig.inputHistogramsOnly && k == 0) { + sprintf(name, p ? "%s Pull" : "%s Resolution", p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[j] : PARAMETER_NAMES[j]); + e->SetTitle(name); + e->SetStats(kFALSE); + if (tout) { + if (l == 0) { + mRes2[j][i]->SetOption("colz"); + mRes2[j][i]->Write(); + } + e->Write(); + } + } else if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(tmpMax); + e->SetMinimum(tmpMin); + e->SetLineWidth(1); + e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); + SetAxisSize(e); + e->GetYaxis()->SetTitle(p ? AXIS_TITLES_PULL[j] : mConfig.nativeFitResolutions ? AXIS_TITLES_NATIVE[j] : AXIS_TITLES[j]); + e->GetXaxis()->SetTitle(XAXIS_TITLES[i]); + if (LOG_PT_MIN > 0 && ii == 5) { + e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX); + } + + if (j == 0) { + e->GetYaxis()->SetTitleOffset(1.5); + } else if (j < 3) { + e->GetYaxis()->SetTitleOffset(1.4); + } + if (qcout && !mConfig.shipToQCAsCanvas) { + qcout->Add(e); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + e->SetMarkerColor(kBlack); + e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); + e->Draw(k || l ? "same" : ""); + if (j == 0) { + GetName(fname, k); + if (p) { + sprintf(name, "%s%s", fname, l ? "Mean" : "Pull"); + } else { + sprintf(name, "%s%s", fname, l ? "Mean" : "Resolution"); + } + leg->AddEntry(e, name, "l"); + } + } + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + if (ii == 5) { + pad->SetLogx(); + } + can->cd(); + if (j == 4) { + ChangePadTitleSize(pad, 0.056); + } + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + leg->Draw(); + + if (qcout) { + qcout->Add(can); + } + if (!mConfig.enableLocalOutput) { + continue; + } + doPerfFigure(0.2, 0.295, 0.025); + can->Print(Form(p ? "plots/pull_vs_%s.pdf" : "plots/res_vs_%s.pdf", VSPARAMETER_NAMES[ii])); + if (mConfig.writeRootFiles) { + can->Print(Form(p ? "plots/pull_vs_%s.root" : "plots/res_vs_%s.root", VSPARAMETER_NAMES[ii])); + } + } + } + + // Process Integral Resolution Histogreams + for (int p = 0; p < 2; p++) { + if ((p == 0 && (mQATasks & taskTrackingRes) == 0) || (p == 1 && (mQATasks & taskTrackingResPull) == 0)) { + continue; + } + TCanvas* can = p ? mCPull[6] : mCRes[6]; + for (int i = 0; i < 5; i++) { + TPad* pad = p ? mPPull[6][i] : mPRes[6][i]; + TH1D* hist = p ? pullIntegral[i] : resIntegral[i]; + int numColor = 0; + if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) { + pad->cd(); + } + if (!mConfig.inputHistogramsOnly && mcAvail) { + TH1D* e = hist; + if (e && e->GetEntries()) { + e->Fit("gaus", "sQ"); + } + } + + float tmpMax = 0; + for (int k = 0; k < ConfigNumInputs; k++) { + TH1D* e = hist; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(-1111); + if (e->GetMaximum() > tmpMax) { + tmpMax = e->GetMaximum(); + } + } + + for (int k = 0; k < ConfigNumInputs; k++) { + TH1D* e = hist; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(tmpMax * 1.02); + e->SetMinimum(tmpMax * -0.02); + if (tout && !mConfig.inputHistogramsOnly && k == 0) { + e->Write(); + } + if (qcout && !mConfig.shipToQCAsCanvas) { + qcout->Add(e); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); + e->Draw(k == 0 ? "" : "same"); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + can->cd(); + } + if (qcout) { + qcout->Add(can); + } + if (!mConfig.enableLocalOutput) { + continue; + } + + can->Print(p ? "plots/pull_integral.pdf" : "plots/res_integral.pdf"); + if (mConfig.writeRootFiles) { + can->Print(p ? "plots/pull_integral.root" : "plots/res_integral.root"); + } + } + } + + unsigned long long int attachClusterCounts[N_CLS_HIST]; + if (mQATasks & taskClusterAttach) { + // Process Cluster Attachment Histograms + if (mConfig.inputHistogramsOnly == 0) { + for (int i = N_CLS_HIST; i < N_CLS_TYPE * N_CLS_HIST - 1; i++) { + mClusters[i]->Sumw2(true); + } + double totalVal = 0; + if (!CLUST_HIST_INT_SUM) { + for (int j = 0; j < mClusters[N_CLS_HIST - 1]->GetXaxis()->GetNbins() + 2; j++) { + totalVal += mClusters[N_CLS_HIST - 1]->GetBinContent(j); + } + } + if (totalVal == 0.) { + totalVal = 1.; + } + for (int i = 0; i < N_CLS_HIST; i++) { + double val = 0; + for (int j = 0; j < mClusters[i]->GetXaxis()->GetNbins() + 2; j++) { + val += mClusters[i]->GetBinContent(j); + mClusters[2 * N_CLS_HIST - 1 + i]->SetBinContent(j, val / totalVal); + } + attachClusterCounts[i] = val; + } + + if (!CLUST_HIST_INT_SUM) { + for (int i = 0; i < N_CLS_HIST; i++) { + mClusters[2 * N_CLS_HIST - 1 + i]->SetMaximum(1.02); + mClusters[2 * N_CLS_HIST - 1 + i]->SetMinimum(-0.02); + } + } + + for (int i = 0; i < N_CLS_HIST - 1; i++) { + mClusters[N_CLS_HIST + i]->Divide(mClusters[i], mClusters[N_CLS_HIST - 1], 1, 1, "B"); + mClusters[N_CLS_HIST + i]->SetMinimum(-0.02); + mClusters[N_CLS_HIST + i]->SetMaximum(1.02); + } + } + + float tmpMax[2] = {0, 0}, tmpMin[2] = {0, 0}; + for (int l = 0; l <= CLUST_HIST_INT_SUM; l++) { + for (int k = 0; k < ConfigNumInputs; k++) { + TH1* e = mClusters[l ? (N_CLS_TYPE * N_CLS_HIST - 2) : (N_CLS_HIST - 1)]; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMinimum(-1111); + e->SetMaximum(-1111); + if (l == 0) { + e->GetXaxis()->SetRange(2, AXIS_BINS[4]); + } + if (e->GetMaximum() > tmpMax[l]) { + tmpMax[l] = e->GetMaximum(); + } + if (e->GetMinimum() < tmpMin[l]) { + tmpMin[l] = e->GetMinimum(); + } + } + for (int k = 0; k < ConfigNumInputs; k++) { + for (int i = 0; i < N_CLS_HIST; i++) { + TH1* e = mClusters[l ? (2 * N_CLS_HIST - 1 + i) : i]; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(tmpMax[l] * 1.02); + e->SetMinimum(tmpMax[l] * -0.02); + } + } + } + + for (int i = 0; i < N_CLS_TYPE; i++) { + if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) { + mPClust[i]->cd(); + mPClust[i]->SetLogx(); + } + int begin = i == 2 ? (2 * N_CLS_HIST - 1) : i == 1 ? N_CLS_HIST : 0; + int end = i == 2 ? (3 * N_CLS_HIST - 1) : i == 1 ? (2 * N_CLS_HIST - 1) : N_CLS_HIST; + int numColor = 0; + for (int k = 0; k < ConfigNumInputs; k++) { + for (int j = end - 1; j >= begin; j--) { + TH1* e = mClusters[j]; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + + e->SetTitle(CLUSTER_TITLES[i]); + e->GetYaxis()->SetTitle(i == 0 ? "Number of TPC clusters" : i == 1 ? "Fraction of TPC clusters" : CLUST_HIST_INT_SUM ? "Total TPC clusters (integrated)" : "Fraction of TPC clusters (integrated)"); + e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); + e->GetXaxis()->SetTitleOffset(1.1); + e->GetXaxis()->SetLabelOffset(-0.005); + if (tout && !mConfig.inputHistogramsOnly && k == 0) { + e->Write(); + } + e->SetStats(kFALSE); + e->SetLineWidth(1); + e->SetLineStyle(CONFIG_DASHED_MARKERS ? j + 1 : 1); + if (i == 0) { + e->GetXaxis()->SetRange(2, AXIS_BINS[4]); + } + if (qcout && !mConfig.shipToQCAsCanvas) { + qcout->Add(e); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + e->SetMarkerColor(kBlack); + e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); + e->Draw(j == end - 1 && k == 0 ? "" : "same"); + GetName(fname, k); + sprintf(name, "%s%s", fname, CLUSTER_NAMES[j - begin]); + mLClust[i]->AddEntry(e, name, "l"); + } + } + if (ConfigNumInputs == 1) { + TH1* e = reinterpret_cast<TH1F*>(mClusters[begin + CL_att_adj]->Clone()); + e->Add(mClusters[begin + CL_prot], -1); + if (qcout && !mConfig.shipToQCAsCanvas) { + qcout->Add(e); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + e->SetLineColor(colorNums[numColor++ % COLORCOUNT]); + e->Draw("same"); + mLClust[i]->AddEntry(e, "Removed (Strategy A)", "l"); + } + if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) { + continue; + } + + mLClust[i]->Draw(); + + if (qcout) { + qcout->Add(mCClust[i]); + } + if (!mConfig.enableLocalOutput) { + continue; + } + doPerfFigure(i != 2 ? 0.37 : 0.6, 0.295, 0.030); + mCClust[i]->cd(); + mCClust[i]->Print(i == 2 ? "plots/clusters_integral.pdf" : i == 1 ? "plots/clusters_relative.pdf" : "plots/clusters.pdf"); + if (mConfig.writeRootFiles) { + mCClust[i]->Print(i == 2 ? "plots/clusters_integral.root" : i == 1 ? "plots/clusters_relative.root" : "plots/clusters.root"); + } + } + } + + // Process cluster count statistics + if ((mQATasks & taskClusterCounts) && !mHaveExternalHists && !mConfig.clusterRejectionHistograms && !mConfig.inputHistogramsOnly) { + DoClusterCounts(attachClusterCounts); + } + if ((qcout || tout) && (mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) { + for (unsigned int i = 0; i < mHistClusterCount.size(); i++) { + if (tout) { + mHistClusterCount[i]->Write(); + } + if (qcout) { + qcout->Add(mHistClusterCount[i]); + } + } + } + + if (mQATasks & taskTrackStatistics) { + // Process track statistic histograms + float tmpMax = 0.; + for (int k = 0; k < ConfigNumInputs; k++) { + TH1F* e = mTracks; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(-1111); + if (e->GetMaximum() > tmpMax) { + tmpMax = e->GetMaximum(); + } + } + mPTracks->cd(); + mPTracks->SetLogx(); + for (int k = 0; k < ConfigNumInputs; k++) { + TH1F* e = mTracks; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + if (tout && !mConfig.inputHistogramsOnly && k == 0) { + e->Write(); + } + e->SetMaximum(tmpMax * 1.02); + e->SetMinimum(tmpMax * -0.02); + e->SetStats(kFALSE); + e->SetLineWidth(1); + e->GetYaxis()->SetTitle("a.u."); + e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); + if (qcout) { + qcout->Add(e); + } + e->SetMarkerColor(kBlack); + e->SetLineColor(colorNums[k % COLORCOUNT]); + e->Draw(k == 0 ? "" : "same"); + GetName(fname, k); + sprintf(name, "%sTrack Pt", fname); + mLTracks->AddEntry(e, name, "l"); + } + mLTracks->Draw(); + mCTracks->cd(); + mCTracks->Print("plots/tracks.pdf"); + if (mConfig.writeRootFiles) { + mCTracks->Print("plots/tracks.root"); + } + tmpMax = 0.; + for (int k = 0; k < ConfigNumInputs; k++) { + TH1F* e = mNCl; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + e->SetMaximum(-1111); + if (e->GetMaximum() > tmpMax) { + tmpMax = e->GetMaximum(); + } + } + mPNCl->cd(); + for (int k = 0; k < ConfigNumInputs; k++) { + TH1F* e = mNCl; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; + } + if (tout && !mConfig.inputHistogramsOnly && k == 0) { + e->Write(); + } + e->SetMaximum(tmpMax * 1.02); + e->SetMinimum(tmpMax * -0.02); + e->SetStats(kFALSE); + e->SetLineWidth(1); + e->GetYaxis()->SetTitle("a.u."); + e->GetXaxis()->SetTitle("NClusters"); + if (qcout) { + qcout->Add(e); + } + e->SetMarkerColor(kBlack); + e->SetLineColor(colorNums[k % COLORCOUNT]); + e->Draw(k == 0 ? "" : "same"); + GetName(fname, k); + sprintf(name, "%sNClusters", fname); + mLNCl->AddEntry(e, name, "l"); + } + mLNCl->Draw(); + mCNCl->cd(); + mCNCl->Print("plots/nClusters.pdf"); + if (mConfig.writeRootFiles) { + mCNCl->Print("plots/nClusters.root"); + } + } + + if (tout && !mConfig.inputHistogramsOnly && mConfig.writeMCLabels) { + gInterpreter->GenerateDictionary("vector<vector<int>>", ""); + tout->WriteObject(&mcEffBuffer, "mcEffBuffer"); + tout->WriteObject(&mcLabelBuffer, "mcLabelBuffer"); + remove("AutoDict_vector_vector_int__.cxx"); + remove("AutoDict_vector_vector_int___cxx_ACLiC_dict_rdict.pcm"); + remove("AutoDict_vector_vector_int___cxx.d"); + remove("AutoDict_vector_vector_int___cxx.so"); + } + + if (tout) { + tout->Close(); + } + for (unsigned int i = 0; i < mConfig.compareInputs.size(); i++) { + tin[i]->Close(); + } + if (!qcout) { + clearGarbagageCollector(); + } + return (0); +} + +void GPUQA::PrintClusterCount(int mode, int& num, const char* name, unsigned long long int n, unsigned long long int normalization) +{ + if (mode == 2) { + // do nothing, just count num + } else if (mode == 1) { + char name2[128]; + sprintf(name2, "clusterCount%d", num); + createHist(mHistClusterCount[num], name2, name, 1000, 0, mConfig.histMaxNClusters, 1000, 0, 100); + } else if (mode == 0) { + if (normalization && mConfig.enableLocalOutput) { + printf("\t%35s: %'12llu (%6.2f%%)\n", name, n, 100.f * n / normalization); + } + if (mConfig.clusterRejectionHistograms) { + float ratio = 100.f * n / std::max(normalization, 1llu); + mHistClusterCount[num]->Fill(n, ratio, 1); + } + } + num++; +} + +int GPUQA::DoClusterCounts(unsigned long long int* attachClusterCounts, int mode) +{ + int num = 0; + if (mcPresent() && (mQATasks & taskClusterAttach) && attachClusterCounts) { + for (int i = 0; i < N_CLS_HIST; i++) { + PrintClusterCount(mode, num, CLUSTER_NAMES[i], attachClusterCounts[i], mClusterCounts.nTotal); + } + PrintClusterCount(mode, num, "Unattached", attachClusterCounts[N_CLS_HIST - 1] - attachClusterCounts[CL_att_adj], mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Removed (Strategy A)", attachClusterCounts[CL_att_adj] - attachClusterCounts[CL_prot], mClusterCounts.nTotal); // Attached + Adjacent (also fake) - protected + PrintClusterCount(mode, num, "Unaccessible", mClusterCounts.nUnaccessible, mClusterCounts.nTotal); // No contribution from track >= 10 MeV, unattached or fake-attached/adjacent + } else { + PrintClusterCount(mode, num, "All Clusters", mClusterCounts.nTotal, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Used in Physics", mClusterCounts.nPhysics, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Protected", mClusterCounts.nProt, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Unattached", mClusterCounts.nUnattached, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Removed (Strategy A)", mClusterCounts.nTotal - mClusterCounts.nUnattached - mClusterCounts.nProt, mClusterCounts.nTotal); + } + + PrintClusterCount(mode, num, "Merged Loopers (Afterburner)", mClusterCounts.nMergedLooper, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "High Inclination Angle", mClusterCounts.nHighIncl, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Rejected", mClusterCounts.nRejected, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Tube (> 200 MeV)", mClusterCounts.nTube, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Tube (< 200 MeV)", mClusterCounts.nTube200, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Looping Legs", mClusterCounts.nLoopers, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Low Pt < 50 MeV", mClusterCounts.nLowPt, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Low Pt < 200 MeV", mClusterCounts.n200MeV, mClusterCounts.nTotal); + + if (mcPresent() && (mQATasks & taskClusterAttach)) { + PrintClusterCount(mode, num, "Tracks > 400 MeV", mClusterCounts.nAbove400, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Fake Removed (> 400 MeV)", mClusterCounts.nFakeRemove400, mClusterCounts.nAbove400); + PrintClusterCount(mode, num, "Full Fake Removed (> 400 MeV)", mClusterCounts.nFullFakeRemove400, mClusterCounts.nAbove400); + PrintClusterCount(mode, num, "Tracks < 40 MeV", mClusterCounts.nBelow40, mClusterCounts.nTotal); + PrintClusterCount(mode, num, "Fake Protect (< 40 MeV)", mClusterCounts.nFakeProtect40, mClusterCounts.nBelow40); + } + return num; +} diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h similarity index 81% rename from GPU/GPUTracking/Standalone/qa/GPUQA.h rename to GPU/GPUTracking/qa/GPUQA.h index 7aca651aecf5a..081a56efb628e 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,15 +36,13 @@ namespace GPUCA_NAMESPACE { namespace gpu { -class GPUChainTracking; - class GPUQA { public: - GPUQA(GPUChainTracking* chain) {} + GPUQA(void* chain) {} ~GPUQA() = default; - int InitQA() { return 1; } + int InitQA(int tasks = 0) { return 1; } void RunQA(bool matchOnly = false) {} int DrawQAHistograms() { return 1; } void SetMCTrackRange(int min, int max) {} @@ -52,6 +51,8 @@ class GPUQA int HitAttachStatus(int iHit) const { return false; } int GetMCTrackLabel(unsigned int trackId) const { return -1; } bool clusterRemovable(int attach, bool prot) const { return false; } + void DumpO2MCData(const char* filename) const {} + int ReadO2MCData(const char* filename) { return 1; } static bool QAAvailable() { return false; } static bool IsInitialized() { return false; } }; @@ -71,25 +72,31 @@ class GPUQA namespace o2 { class MCCompLabel; -} +namespace tpc +{ +class TrackTPC; +struct ClusterNativeAccess; +} // namespace tpc +} // namespace o2 -class AliHLTTPCClusterMCLabel; +struct AliHLTTPCClusterMCLabel; namespace GPUCA_NAMESPACE::gpu { class GPUChainTracking; -class GPUTPCMCInfo; +class GPUParam; +struct GPUTPCMCInfo; struct GPUQAGarbageCollection; class GPUQA { public: GPUQA(); - GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config = nullptr); + GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config = nullptr, const GPUParam* param = nullptr); ~GPUQA(); - int InitQA(); - void RunQA(bool matchOnly = false); + int InitQA(int tasks = -1); + void RunQA(bool matchOnly = false, const std::vector<o2::tpc::TrackTPC>* tracksExternal = nullptr, const std::vector<o2::MCCompLabel>* tracksExtMC = nullptr, const o2::tpc::ClusterNativeAccess* clNative = nullptr); int DrawQAHistograms(TObjArray* qcout = nullptr); void DrawQAHistogramsCleanup(); // Needed after call to DrawQAHistograms with qcout != nullptr when GPUSettingsQA.shipToQCAsCanvas = true to clean up the Canvases etc. void SetMCTrackRange(int min, int max); @@ -98,19 +105,34 @@ class GPUQA int HitAttachStatus(int iHit) const; int GetMCTrackLabel(unsigned int trackId) const; bool clusterRemovable(int attach, bool prot) const; + void InitO2MCData(GPUTrackingInOutPointers* updateIOPtr = nullptr); + void DumpO2MCData(const char* filename) const; + int ReadO2MCData(const char* filename); static bool QAAvailable() { return true; } bool IsInitialized() { return mQAInitialized; } const std::vector<TH1F>& getHistograms1D() const { return *mHist1D; } const std::vector<TH2F>& getHistograms2D() const { return *mHist2D; } const std::vector<TH1D>& getHistograms1Dd() const { return *mHist1Dd; } - int loadHistograms(std::vector<TH1F>& i1, std::vector<TH2F>& i2, std::vector<TH1D>& i3); + void resetHists(); + int loadHistograms(std::vector<TH1F>& i1, std::vector<TH2F>& i2, std::vector<TH1D>& i3, int tasks = -1); static constexpr int N_CLS_HIST = 8; static constexpr int N_CLS_TYPE = 3; static constexpr int MC_LABEL_INVALID = -1e9; + enum QA_TASKS { + taskTrackingEff = 1, + taskTrackingRes = 2, + taskTrackingResPull = 4, + taskClusterAttach = 8, + taskTrackStatistics = 16, + taskClusterCounts = 32, + taskDefault = 63, + taskDefaultPostprocess = 31 + }; + private: struct additionalMCParameters { float pt, phi, theta, eta, nWeightCls; @@ -122,7 +144,9 @@ class GPUQA }; int InitQACreateHistograms(); - + int DoClusterCounts(unsigned long long int* attachClusterCounts, int mode = 0); + void PrintClusterCount(int mode, int& num, const char* name, unsigned long long int n, unsigned long long int normalization); + void CopyO2MCtoIOPtr(GPUTrackingInOutPointers* ptr); void SetAxisSize(TH1F* e); void SetLegend(TLegend* l); double* CreateLogAxis(int nbins, float xmin, float xmax); @@ -133,11 +157,12 @@ class GPUQA template <class T> T* GetHist(T*& ee, std::vector<std::unique_ptr<TFile>>& tin, int k, int nNewInput); + using mcInfo_t = GPUTPCMCInfo; #ifdef GPUCA_TPC_GEOMETRY_O2 using mcLabels_t = gsl::span<const o2::MCCompLabel>; using mcLabel_t = o2::MCCompLabel; using mcLabelI_t = mcLabel_t; - using mcInfo_t = GPUTPCMCInfo; + mcLabels_t GetMCLabel(unsigned int i); mcLabel_t GetMCLabel(unsigned int i, unsigned int j); #else @@ -158,7 +183,6 @@ class GPUQA mcLabelI_t(const mcLabel_t& l); int track = MC_LABEL_INVALID; }; - using mcInfo_t = GPUTPCMCInfo; const mcLabels_t& GetMCLabel(unsigned int i); const mcLabel_t& GetMCLabel(unsigned int i, unsigned int j); const mcInfo_t& GetMCTrack(const mcLabelI_t& label); @@ -168,9 +192,9 @@ class GPUQA template <class T> static auto& GetMCTrackObj(T& obj, const mcLabelI_t& l); - unsigned int GetNMCCollissions(); - unsigned int GetNMCTracks(int iCol); - unsigned int GetNMCLabels(); + unsigned int GetNMCCollissions() const; + unsigned int GetNMCTracks(int iCol) const; + unsigned int GetNMCLabels() const; const mcInfo_t& GetMCTrack(unsigned int iTrk, unsigned int iCol); const mcInfo_t& GetMCTrack(const mcLabel_t& label); int GetMCLabelNID(const mcLabels_t& label); @@ -189,7 +213,7 @@ class GPUQA GPUChainTracking* mTracking; const GPUSettingsQA& mConfig; - bool mRunForQC; + const GPUParam& mParam; const char* str_perf_figure_1 = "ALICE Performance 2018/03/20"; // const char* str_perf_figure_2 = "2015, MC pp, #sqrt{s} = 5.02 TeV"; @@ -202,14 +226,14 @@ class GPUQA std::vector<std::vector<int>> mRecTracks; std::vector<std::vector<int>> mFakeTracks; std::vector<std::vector<additionalMCParameters>> mMCParam; - std::vector<std::vector<mcInfo_t>> mMCInfos; - std::vector<int> mNColTracks; #else std::vector<int> mTrackMCLabelsReverse[1]; std::vector<int> mRecTracks[1]; std::vector<int> mFakeTracks[1]; std::vector<additionalMCParameters> mMCParam[1]; #endif + std::vector<mcInfo_t> mMCInfos; + std::vector<GPUTPCMCInfoCol> mMCInfosCol; std::vector<additionalClusterParameters> mClusterParam; int mNTotalFakes = 0; @@ -258,6 +282,8 @@ class GPUQA TPad* mPNCl; TLegend* mLNCl; + std::vector<TH2F*> mHistClusterCount; + std::vector<TH1F>* mHist1D = nullptr; std::vector<TH2F>* mHist2D = nullptr; std::vector<TH1D>* mHist1Dd = nullptr; @@ -277,6 +303,8 @@ class GPUQA int mNEvents = 0; bool mQAInitialized = false; + bool mO2MCDataLoaded = false; + int mQATasks = 0; std::vector<std::vector<int>> mcEffBuffer; std::vector<std::vector<int>> mcLabelBuffer; std::vector<std::vector<bool>> mGoodTracks; @@ -286,6 +314,8 @@ class GPUQA static int initColors(); int mMCTrackMin = -1, mMCTrackMax = -1; + + const o2::tpc::ClusterNativeAccess* mClNative = nullptr; }; inline bool GPUQA::SuppressTrack(int iTrack) const { return (mConfig.matchMCLabels.size() && !mGoodTracks[mNEvents][iTrack]); } diff --git a/GPU/GPUTracking/Standalone/qa/GPUQAHelper.h b/GPU/GPUTracking/qa/GPUQAHelper.h similarity index 91% rename from GPU/GPUTracking/Standalone/qa/GPUQAHelper.h rename to GPU/GPUTracking/qa/GPUQAHelper.h index 18499cec90a74..ee2f8890ecc90 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQAHelper.h +++ b/GPU/GPUTracking/qa/GPUQAHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,10 @@ #include <vector> #include <type_traits> +#ifdef GPUCA_STANDALONE +#include "AliHLTTPCClusterMCData.h" +#endif + struct AliHLTTPCClusterMCWeight; struct AliHLTTPCClusterMCLabel; diff --git a/GPU/GPUTracking/Standalone/qa/genEvents.cxx b/GPU/GPUTracking/qa/genEvents.cxx similarity index 92% rename from GPU/GPUTracking/Standalone/qa/genEvents.cxx rename to GPU/GPUTracking/qa/genEvents.cxx index 914adcef3a8e8..2facc76d8c1ca 100644 --- a/GPU/GPUTracking/Standalone/qa/genEvents.cxx +++ b/GPU/GPUTracking/qa/genEvents.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,7 +14,7 @@ #include <iostream> #include <fstream> -#include <string.h> +#include <cstring> #include <sys/stat.h> #include "Rtypes.h" @@ -91,7 +92,7 @@ double genEvents::GetGaus(double sigma) double x = 0; do { x = gRandom->Gaus(0., sigma); - if (fabsf(x) <= 3.5 * sigma) { + if (fabs(x) <= 3.5 * sigma) { break; } } while (1); @@ -345,6 +346,9 @@ int genEvents::GenerateEvent(const GPUParam& param, char* filename) mRec->mIOPtrs.nMCInfosTPC = mcInfo.size(); mRec->mIOPtrs.mcInfosTPC = mcInfo.data(); + static const GPUTPCMCInfoCol mcColInfo = {0, (unsigned int)mcInfo.size()}; + mRec->mIOPtrs.mcInfosTPCCol = &mcColInfo; + mRec->mIOPtrs.nMCInfosTPCCol = 1; mRec->DumpData(filename); labels.clear(); @@ -356,15 +360,15 @@ void genEvents::RunEventGenerator(GPUChainTracking* rec) { std::unique_ptr<genEvents> gen(new genEvents(rec)); char dirname[256]; - snprintf(dirname, 256, "events/%s/", configStandalone.EventsDir); + snprintf(dirname, 256, "events/%s/", configStandalone.eventsDir); mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); rec->DumpSettings(dirname); gen->InitEventGenerator(); - for (int i = 0; i < (configStandalone.NEvents == -1 ? 10 : configStandalone.NEvents); i++) { - GPUInfo("Generating event %d/%d", i, configStandalone.NEvents == -1 ? 10 : configStandalone.NEvents); - snprintf(dirname, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.EventsDir, i); + for (int i = 0; i < (configStandalone.nEvents == -1 ? 10 : configStandalone.nEvents); i++) { + GPUInfo("Generating event %d/%d", i, configStandalone.nEvents == -1 ? 10 : configStandalone.nEvents); + snprintf(dirname, 256, "events/%s/" GPUCA_EVDUMP_FILE ".%d.dump", configStandalone.eventsDir, i); gen->GenerateEvent(rec->GetParam(), dirname); } gen->FinishEventGenerator(); diff --git a/GPU/GPUTracking/Standalone/qa/genEvents.h b/GPU/GPUTracking/qa/genEvents.h similarity index 78% rename from GPU/GPUTracking/Standalone/qa/genEvents.h rename to GPU/GPUTracking/qa/genEvents.h index fe3c6f4e10cb6..b2ed2426ea439 100644 --- a/GPU/GPUTracking/Standalone/qa/genEvents.h +++ b/GPU/GPUTracking/qa/genEvents.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,7 +55,7 @@ class genEvents int RecalculateSlice(GPUTPCGMPhysicalTrackModel& t, int& iSlice); double GetGaus(double sigma); - TH1F* mClusterError[3][2] = {{0, 0}, {0, 0}, {0, 0}}; + TH1F* mClusterError[3][2] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; struct GenCluster { int sector; diff --git a/GPU/GPUTracking/qconfigoptions.h b/GPU/GPUTracking/qconfigoptions.h new file mode 100644 index 0000000000000..2a43c3f59cc3f --- /dev/null +++ b/GPU/GPUTracking/qconfigoptions.h @@ -0,0 +1,17 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfigoptions.h +/// \author David Rohr + +#include "GPUSettings.h" // Usually we are included from GPUSettings.h, so this doesn't do anything. + // But ROOT or qconfig.cpp will include us directly, so load the settings first. +#include "GPUSettingsList.h" diff --git a/GPU/GPUTracking/Standalone/makefiles/.gitattributes b/GPU/GPUTracking/utils/.gitattributes similarity index 100% rename from GPU/GPUTracking/Standalone/makefiles/.gitattributes rename to GPU/GPUTracking/utils/.gitattributes diff --git a/GPU/GPUTracking/utils/.gitignore b/GPU/GPUTracking/utils/.gitignore new file mode 100644 index 0000000000000..ff145e23751f6 --- /dev/null +++ b/GPU/GPUTracking/utils/.gitignore @@ -0,0 +1,17 @@ +/get_private_profile.h +/os_low_level_helper.h +/affinity.cxx +/affinity.h +/qmath.h +/qmultialloc.* +/qmalloc.* +/sched_affinity_win32_wrapper.h +/switchtemplate.h +/util_adl.cxx +/util_adl.h +/vecpodtest.cxx +/*.cpp +/*.sh +/.svn +/as +/callvc.bat diff --git a/GPU/GPUTracking/utils/EmptyFile.cxx b/GPU/GPUTracking/utils/EmptyFile.cxx new file mode 100644 index 0000000000000..74268d78ed5d5 --- /dev/null +++ b/GPU/GPUTracking/utils/EmptyFile.cxx @@ -0,0 +1,15 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EmptyFile.cxx +/// \author David Rohr + +// Empty file, needed for header only libraries diff --git a/GPU/GPUTracking/Standalone/utils/bitfield.h b/GPU/GPUTracking/utils/bitfield.h similarity index 88% rename from GPU/GPUTracking/Standalone/utils/bitfield.h rename to GPU/GPUTracking/utils/bitfield.h index bf102cee5e343..92cc412f08aba 100644 --- a/GPU/GPUTracking/Standalone/utils/bitfield.h +++ b/GPU/GPUTracking/utils/bitfield.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Standalone/makefiles/include.S b/GPU/GPUTracking/utils/include.S similarity index 100% rename from GPU/GPUTracking/Standalone/makefiles/include.S rename to GPU/GPUTracking/utils/include.S diff --git a/GPU/GPUTracking/utils/linux_helpers.h b/GPU/GPUTracking/utils/linux_helpers.h new file mode 100644 index 0000000000000..b9b17a3ab3be6 --- /dev/null +++ b/GPU/GPUTracking/utils/linux_helpers.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file linux_helpers.h +/// \author David Rohr + +#ifndef LINUX_HELPERS_H +#define LINUX_HELPERS_H + +#include <termios.h> +#include <unistd.h> +#include <sys/ioctl.h> + +static inline int getch() +{ + static struct termios oldt, newt; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + int retVal = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return (retVal); +} + +static inline int kbhit() +{ + termios term; + tcgetattr(0, &term); + termios term2 = term; + term2.c_lflag &= ~ICANON; + tcsetattr(0, TCSANOW, &term2); + int byteswaiting; + ioctl(0, FIONREAD, &byteswaiting); + tcsetattr(0, TCSANOW, &term); + return byteswaiting > 0; +} + +static void inline Sleep(int msecs) { usleep(msecs * 1000); } + +#endif diff --git a/GPU/GPUTracking/Standalone/makefiles/makefile_opencl_compiler.cxx b/GPU/GPUTracking/utils/makefile_opencl_compiler.cxx similarity index 96% rename from GPU/GPUTracking/Standalone/makefiles/makefile_opencl_compiler.cxx rename to GPU/GPUTracking/utils/makefile_opencl_compiler.cxx index 58918fe988539..a94509cf94db0 100644 --- a/GPU/GPUTracking/Standalone/makefiles/makefile_opencl_compiler.cxx +++ b/GPU/GPUTracking/utils/makefile_opencl_compiler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/utils/opencl_compiler_structs.h b/GPU/GPUTracking/utils/opencl_compiler_structs.h new file mode 100644 index 0000000000000..68e0a4f184480 --- /dev/null +++ b/GPU/GPUTracking/utils/opencl_compiler_structs.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file opencl_compiler_structs.h +/// \author David Rohr + +struct _makefiles_opencl_platform_info { + char platform_profile[64]; + char platform_version[64]; + char platform_name[64]; + char platform_vendor[64]; + cl_uint count; +}; + +struct _makefiles_opencl_device_info { + char device_name[64]; + char device_vendor[64]; + cl_uint nbits; + size_t binary_size; +}; diff --git a/GPU/GPUTracking/Standalone/makefiles/opencl_obtain_program.h b/GPU/GPUTracking/utils/opencl_obtain_program.h similarity index 90% rename from GPU/GPUTracking/Standalone/makefiles/opencl_obtain_program.h rename to GPU/GPUTracking/utils/opencl_obtain_program.h index 9dfa9b04bd2d5..3678bb3fe04f2 100644 --- a/GPU/GPUTracking/Standalone/makefiles/opencl_obtain_program.h +++ b/GPU/GPUTracking/utils/opencl_obtain_program.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Standalone/utils/pthread_mutex_win32_wrapper.h b/GPU/GPUTracking/utils/pthread_mutex_win32_wrapper.h similarity index 90% rename from GPU/GPUTracking/Standalone/utils/pthread_mutex_win32_wrapper.h rename to GPU/GPUTracking/utils/pthread_mutex_win32_wrapper.h index edb9856fefb2e..e61b1fd69d0cd 100644 --- a/GPU/GPUTracking/Standalone/utils/pthread_mutex_win32_wrapper.h +++ b/GPU/GPUTracking/utils/pthread_mutex_win32_wrapper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Standalone/utils/qconfig.cxx b/GPU/GPUTracking/utils/qconfig.cxx similarity index 93% rename from GPU/GPUTracking/Standalone/utils/qconfig.cxx rename to GPU/GPUTracking/utils/qconfig.cxx index bc943254a8b6f..f8a869ddb5987 100644 --- a/GPU/GPUTracking/Standalone/utils/qconfig.cxx +++ b/GPU/GPUTracking/utils/qconfig.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,18 +25,13 @@ #include "qconfig_helpers.h" // Create config instances +#define QCONFIG_PARSER_CXX #define QCONFIG_INSTANCE #include "qconfig.h" #undef QCONFIG_INSTANCE namespace qConfig { -#define qon_mcat(a, b) a##b -#define qon_mxcat(a, b) qon_mcat(a, b) -#define qon_mcat3(a, b, c) a##b##c -#define qon_mxcat3(a, b, c) qon_mcat3(a, b, c) -#define qon_mstr(a) #a -#define qon_mxstr(a) qon_mstr(a) #define QCONFIG_SETTING(name, type) \ struct qon_mxcat3(q, name, _t) \ { \ @@ -374,6 +370,24 @@ inline int qAddOptionType<unsigned int>(qConfigSettings<unsigned int>& settings, settings.doDefault); } template <> +inline int qAddOptionType<short>(qConfigSettings<short>& settings, short& ref, int& i, const char** argv, const int argc, short /*def*/) +{ + return qAddOptionGeneric<short>( + settings, ref, i, argv, argc, settings.set, [](const char* a) -> short { + return atoi(a); + }, + settings.doDefault); +} +template <> +inline int qAddOptionType<unsigned short>(qConfigSettings<unsigned short>& settings, unsigned short& ref, int& i, const char** argv, const int argc, unsigned short /*def*/) +{ + return qAddOptionGeneric<unsigned short>( + settings, ref, i, argv, argc, settings.set, [](const char* a) -> unsigned short { + return strtoul(a, nullptr, 0); + }, + settings.doDefault); +} +template <> inline int qAddOptionType<long>(qConfigSettings<long>& settings, long& ref, int& i, const char** argv, const int argc, long /*def*/) { return qAddOptionGeneric<long>( @@ -452,16 +466,9 @@ template <typename T> inline void qAddOptionMessage(qConfigSettings<T>& settings, T& ref) { if (settings.message) { - printf(settings.message, ref); - printf("\n"); - } -} -template <> -inline void qAddOptionMessage<bool>(qConfigSettings<bool>& settings, bool& ref) -{ - if (settings.message) { - printf(settings.message, ref ? "ON" : "OFF"); - printf("\n"); + std::string tmp = print_type(ref); + std::string msg = std::string(settings.message) + "\n"; + printf(msg.c_str(), tmp.c_str()); } } @@ -494,6 +501,11 @@ static inline int qConfigParse(int argc, const char** argv, const char* /*filena } return (0); } + +std::vector<std::function<void()>> qprint_global; +#define QCONFIG_PRINT +#include "qconfig.h" +#undef QCONFIG_PRINT } // end namespace qConfig // Main parse function called from outside @@ -501,8 +513,7 @@ int qConfigParse(int argc, const char** argv, const char* filename) { return (qC void qConfigPrint() { - std::string blockName; -#define QCONFIG_PRINT -#include "qconfig.h" -#undef QCONFIG_PRINT + for (auto& f : qConfig::qprint_global) { + f(); + } } diff --git a/GPU/GPUTracking/Standalone/utils/qconfig.h b/GPU/GPUTracking/utils/qconfig.h similarity index 85% rename from GPU/GPUTracking/Standalone/utils/qconfig.h rename to GPU/GPUTracking/utils/qconfig.h index 80cad5f540275..3834b0ff7eba8 100644 --- a/GPU/GPUTracking/Standalone/utils/qconfig.h +++ b/GPU/GPUTracking/utils/qconfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -90,16 +91,16 @@ enum qConfigRetVal { qcrOK = 0, if (found) { \ } -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) \ - { \ - constexpr const char* preopt = preoptname; \ - (void)preopt; \ - constexpr const char preoptshort = preoptnameshort; \ - (void)preoptshort; \ - name& tmp = parent.instance; \ - (void)tmp; \ - bool tmpfound = true; \ - if (found) { \ +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ + { \ + constexpr const char* preopt = preoptname; \ + (void)preopt; \ + constexpr const char preoptshort = preoptnameshort; \ + (void)preoptshort; \ + name& tmp = parent.instance; \ + (void)tmp; \ + bool tmpfound = true; \ + if (found) { \ } #define BeginHiddenConfig(name, instance) \ @@ -165,7 +166,7 @@ enum qConfigRetVal { qcrOK = 0, constexpr const char* preopt = ""; \ constexpr const char preoptshort = 0; \ printf("\n"); -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) \ +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ const char* qon_mxcat(qConfig_subconfig_, name) = preoptnameshort == 0 ? (qon_mxstr(name) ": --" preoptname "\n\t\t" descr) : (qon_mxstr(name) ": -" qon_mxstr('a') " (--" preoptname ")\n\t\t" descr); \ (void)qon_mxcat(qConfig_subconfig_, name); \ if (subConfig == nullptr || strcmp(subConfig, followSub == 2 ? qon_mxstr(name) : preoptname) == 0) { \ @@ -185,42 +186,42 @@ enum qConfigRetVal { qcrOK = 0, // End QCONFIG_HELP #elif defined(QCONFIG_PRINT) -#define AddOption(name, type, default, optname, optnameshort, ...) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(tmp.name) << "\n"; -#define AddVariable(name, type, default) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(tmp.name) << "\n"; +#define AddOption(name, type, default, optname, optnameshort, ...) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(qconfig_tmp_object.name) << "\n"; +#define AddVariable(name, type, default) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(qconfig_tmp_object.name) << "\n"; #define AddOptionSet(name, type, value, optname, optnameshort, ...) -#define AddOptionVec(name, type, optname, optnameshort, ...) \ - { \ - std::cout << "\t" << blockName << qon_mxstr(name) << "[]: "; \ - for (unsigned int i = 0; i < tmp.name.size(); i++) { \ - if (i) { \ - std::cout << ", "; \ - } \ - std::cout << qConfig::print_type(tmp.name[i]); \ - } \ - std::cout << "\n"; \ +#define AddOptionVec(name, type, optname, optnameshort, ...) \ + { \ + std::cout << "\t" << blockName << qon_mxstr(name) << "[]: "; \ + for (unsigned int i = 0; i < qconfig_tmp_object.name.size(); i++) { \ + if (i) { \ + std::cout << ", "; \ + } \ + std::cout << qConfig::print_type(qconfig_tmp_object.name[i]); \ + } \ + std::cout << "\n"; \ } -#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ - { \ - std::cout << "\t" << blockName << qon_mxstr(name) << "[" << count << "]: " << qConfig::print_type(tmp.name[0]); \ - for (int i = 1; i < count; i++) { \ - std::cout << ", " << qConfig::print_type(tmp.name[i]); \ - } \ - std::cout << "\n"; \ +#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ + { \ + std::cout << "\t" << blockName << qon_mxstr(name) << "[" << count << "]: " << qConfig::print_type(qconfig_tmp_object.name[0]); \ + for (int i = 1; i < count; i++) { \ + std::cout << ", " << qConfig::print_type(qconfig_tmp_object.name[i]); \ + } \ + std::cout << "\n"; \ } -#define AddSubConfig(name, instance) +#define AddSubConfig(name, instance) qConfigPrint(qconfig_tmp_object.instance, blockName + qon_mxstr(instance.)); #define AddHelpText(text) printf(" " text ":\n"); -#define BeginConfig(name, instance) \ - { \ - name& tmp = instance; \ - blockName = ""; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) \ - { \ - name& tmp = parent.instance; \ - blockName = std::string("\t") + qon_mxstr(name) + "."; \ - std::cout << "\t" << qon_mxstr(name) << "\n"; -#define BeginHiddenConfig(name, instance) \ - if (0) { \ - name tmp; +#define BeginConfig(name, instance) \ + void qConfigPrint(const name& qconfig_tmp_object); \ + bool qon_mxcat(qprint_global_, instance) = []() { qprint_global.emplace_back([]() { qConfigPrint(instance); }); return true; }(); \ + void qConfigPrint(const name& qconfig_tmp_object) \ + { \ + std::string blockName = ""; +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ + void qConfigPrint(const name& qconfig_tmp_object, std::string blockName = "") \ + { \ + std::cout << "\n\t" << qon_mxstr(name) << ":\n"; +#define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, x, x, x, x) + #define EndConfig() } // End QCONFIG_PRINT @@ -236,7 +237,7 @@ enum qConfigRetVal { qcrOK = 0, #define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) #define AddSubConfig(name, instance) #define BeginConfig(name, instance) name instance; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) #define EndConfig() // End QCONFIG_INSTANCE @@ -248,6 +249,7 @@ enum qConfigRetVal { qcrOK = 0, #define AddVariableRTC(name, type, default) \ if (useConstexpr) { \ out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << " = " << qConfig::print_type(std::get<const qConfigCurrentType*>(tSrc)->name) << ";\n"; \ + out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ } else { \ AddOption(name, type, default, optname, optnameshort, help); \ } @@ -256,37 +258,16 @@ enum qConfigRetVal { qcrOK = 0, { \ using qConfigCurrentType = name; \ out << "struct " << qon_mxstr(name) << " {\n"; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) BeginConfig(name, instance) +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) BeginConfig(name, instance) #define EndConfig() \ out << "};"; \ } #define BeginNamespace(name) out << "namespace " << qon_mxstr(name) << " {\n"; #define EndNamespace() out << "}\n"; -#define AddSubConfig(name, instance) +#define AddSubConfig(name, instance) out << qon_mxstr(name) << " " << qon_mxstr(instance) << ";"; #define AddOptionSet(...) // End QCONFIG_PRINT_RTC -#elif defined(QCONFIG_CONVERT_RTC) -#define AddOption(name, type, default, optname, optnameshort, help, ...) out.name = in.name; -#define AddVariable(name, type, default) out.name = in.name; -#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) \ - for (unsigned int i = 0; i < count; i++) \ - out.name[i] = in.name[i]; -#define AddOptionVec(name, type, optname, optnameshort, help, ...) \ - for (unsigned int i = 0; i < in.name.size(); i++) \ - out.name[i] = in.name[i]; -#define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) -#define AddVariableRTC(name, type, default) -#define BeginConfig(name, instance) \ - template <class T> \ - void qConfigConvertRtc(T& out, const name& in) \ - { -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) BeginConfig(name, instance) -#define EndConfig() } -#define AddSubConfig(name, instance) -#define AddOptionSet(...) - -// End QCONFIG_CONVERT_RTC #else // Define structures #if defined(QCONFIG_HEADER_GUARD) && !defined(QCONFIG_GENRTC) #define QCONFIG_HEADER_GUARD_NO_INCLUDE @@ -311,15 +292,17 @@ enum qConfigRetVal { qcrOK = 0, #define AddOptionVec(name, type, optname, optnameshort, help, ...) void* name[sizeof(std::vector<type>) / sizeof(void*)]; #endif #ifdef QCONFIG_GENRTC -#define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) static constexpr type name = default; -#define AddVariableRTC(name, type, default) static constexpr type name = default; +#define AddVariableRTC(name, type, default) \ + static constexpr type name = default; \ + type _dummy_##name = default; +#define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) AddVariableRTC(name, type, default) #else #define AddCustomCPP(...) __VA_ARGS__ #endif #define AddOptionSet(name, type, value, optname, optnameshort, help, ...) #define AddSubConfig(name, instance) name instance; #define BeginConfig(name, instance) struct name { -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr) struct name { +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) struct name { #define EndConfig() \ } \ ; diff --git a/GPU/GPUTracking/utils/qconfig_helpers.h b/GPU/GPUTracking/utils/qconfig_helpers.h new file mode 100644 index 0000000000000..5ca2c8a693f61 --- /dev/null +++ b/GPU/GPUTracking/utils/qconfig_helpers.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfig_helpers.h +/// \author David Rohr + +#ifndef QCONFIG_HELPERS_H +#define QCONFIG_HELPERS_H + +#include <string> +#include <sstream> + +#define qon_mcat(a, b) a##b +#define qon_mxcat(a, b) qon_mcat(a, b) +#define qon_mcat3(a, b, c) a##b##c +#define qon_mxcat3(a, b, c) qon_mcat3(a, b, c) +#define qon_mstr(a) #a +#define qon_mxstr(a) qon_mstr(a) + +namespace qConfig +{ +template <class T> +inline std::string print_type(T val) +{ + std::ostringstream s; + s << val; + return s.str(); +}; +template <> +inline std::string print_type<char>(char val) +{ + return std::to_string(val); +}; +template <> +inline std::string print_type<unsigned char>(unsigned char val) +{ + return std::to_string(val); +}; +template <> +inline std::string print_type<bool>(bool val) +{ + return val ? "true" : "false"; +}; +} // namespace qConfig + +#endif diff --git a/GPU/GPUTracking/utils/qconfigrtc.h b/GPU/GPUTracking/utils/qconfigrtc.h new file mode 100644 index 0000000000000..54114cb3846f7 --- /dev/null +++ b/GPU/GPUTracking/utils/qconfigrtc.h @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfigrtc.h +/// \author David Rohr + +#ifndef QCONFIG_RTC_H +#define QCONFIG_RTC_H + +#include "qconfig.h" +#include "qconfig_helpers.h" + +#ifndef qon_mxstr +#define qon_mstr(a) #a +#define qon_mxstr(a) qon_mstr(a) +#endif +#ifndef qon_mxcat +#define qon_mcat(a, b) a##b +#define qon_mxcat(a, b) qon_mcat(a, b) +#endif + +template <class T> +static std::string qConfigPrintRtc(const T& tSrc, bool useConstexpr) +{ +#if defined(__cplusplus) && __cplusplus >= 201703L + std::stringstream out; +#define QCONFIG_PRINT_RTC +#include "qconfig.h" +#undef QCONFIG_PRINT_RTC + return out.str(); +#else + throw std::runtime_error("not supported"); +#endif +} + +#define QCONFIG_CONVERT_RTC +#include "qconfig.h" +#undef QCONFIG_CONVERT_RTC + +#endif diff --git a/GPU/GPUTracking/utils/qmaths_helpers.h b/GPU/GPUTracking/utils/qmaths_helpers.h new file mode 100644 index 0000000000000..9c5f704180aaa --- /dev/null +++ b/GPU/GPUTracking/utils/qmaths_helpers.h @@ -0,0 +1,38 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qmaths_helpers.h +/// \author David Rohr + +#ifndef QMATH_HELPERS_H +#define QMATH_HELPERS_H + +#if defined __has_include +#if __has_include(<xmmintrin.h>) && __has_include(<pmmintrin.h>) +#include <xmmintrin.h> +#include <pmmintrin.h> +#if defined(_MM_FLUSH_ZERO_OFF) && defined(_MM_DENORMALS_ZERO_ON) +static void disable_denormals() +{ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); +} +#define XMM_HAS_DENORMAL_DEACTIVATE +#endif +#endif +#endif +#ifdef XMM_HAS_DENORMAL_DEACTIVATE +#undef XMM_HAS_DENORMAL_DEACTIVATE +#else +static void disable_denormals() {} +#endif + +#endif diff --git a/GPU/GPUTracking/Standalone/utils/qsem.cxx b/GPU/GPUTracking/utils/qsem.cxx similarity index 77% rename from GPU/GPUTracking/Standalone/utils/qsem.cxx rename to GPU/GPUTracking/utils/qsem.cxx index 949b384f52f28..3109a6c2608f0 100644 --- a/GPU/GPUTracking/Standalone/utils/qsem.cxx +++ b/GPU/GPUTracking/utils/qsem.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/utils/qsem.h b/GPU/GPUTracking/utils/qsem.h new file mode 100644 index 0000000000000..08d3bcfeaa50f --- /dev/null +++ b/GPU/GPUTracking/utils/qsem.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qsem.h +/// \author David Rohr + +#ifndef QSEM_H +#define QSEM_H + +#ifdef _WIN32 +#include "pthread_mutex_win32_wrapper.h" +#else +#include <semaphore.h> +#endif + +class qSem +{ + public: + qSem(int num = 1); + ~qSem(); + + int Lock(); + int Unlock(); + int Trylock(); + int Query(); + + private: + int max; + sem_t sem; +}; + +class qSignal +{ + private: + qSem sem; + + public: + qSignal() : sem(0) {} + void Wait() { sem.Lock(); } + void Signal() { sem.Unlock(); } +}; + +#endif diff --git a/GPU/GPUTracking/utils/strtag.h b/GPU/GPUTracking/utils/strtag.h new file mode 100644 index 0000000000000..00a84fc680d33 --- /dev/null +++ b/GPU/GPUTracking/utils/strtag.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file strtag.h +/// \author David Rohr + +#ifndef STRTAG_H +#define STRTAG_H + +#include <stdexcept> +#include <string> + +template <class T = unsigned long> +#if defined(__cplusplus) && __cplusplus >= 201402L +constexpr +#endif +T qStr2Tag(const char* str) +{ + if (strlen(str) != sizeof(T)) { + throw std::runtime_error("Invalid tag length"); + } + T tmp; + for (unsigned int i = 0; i < sizeof(T); i++) { + ((char*)&tmp)[i] = str[i]; + } + return tmp; +} + +template <class T> +std::string qTag2Str(const T tag) +{ + T str[2]; + str[0] = tag; + str[1] = 0; + return std::string((const char*)str); +} + +#endif diff --git a/GPU/GPUTracking/utils/threadserver.cxx b/GPU/GPUTracking/utils/threadserver.cxx new file mode 100644 index 0000000000000..cedd7af6fa428 --- /dev/null +++ b/GPU/GPUTracking/utils/threadserver.cxx @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file threadserver.cxx +/// \author David Rohr + +#include <cstdio> + +#ifndef STD_OUT +#define STD_OUT stdout +#endif + +#include "threadserver.h" diff --git a/GPU/GPUTracking/Standalone/utils/threadserver.h b/GPU/GPUTracking/utils/threadserver.h similarity index 92% rename from GPU/GPUTracking/Standalone/utils/threadserver.h rename to GPU/GPUTracking/utils/threadserver.h index 298e4425f31a3..0e3204993a484 100644 --- a/GPU/GPUTracking/Standalone/utils/threadserver.h +++ b/GPU/GPUTracking/utils/threadserver.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/Standalone/utils/timer.cxx b/GPU/GPUTracking/utils/timer.cxx similarity index 87% rename from GPU/GPUTracking/Standalone/utils/timer.cxx rename to GPU/GPUTracking/utils/timer.cxx index 12c924cfd80fe..7f0330ba03287 100644 --- a/GPU/GPUTracking/Standalone/utils/timer.cxx +++ b/GPU/GPUTracking/utils/timer.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/GPUTracking/utils/timer.h b/GPU/GPUTracking/utils/timer.h new file mode 100644 index 0000000000000..f7738bf64e365 --- /dev/null +++ b/GPU/GPUTracking/utils/timer.h @@ -0,0 +1,45 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file timer.h +/// \author David Rohr + +#ifndef QONMODULE_TIMER_H +#define QONMODULE_TIMER_H + +class HighResTimer +{ + public: + HighResTimer() = default; + ~HighResTimer() = default; + void Start(); + void Stop(); + void Reset(); + void ResetStart(); + double GetElapsedTime(); + double GetCurrentElapsedTime(bool reset = false); + void StopAndStart(HighResTimer& startTimer); + int IsRunning() { return running; } + void AddTime(double t); + + private: + double ElapsedTime = 0.; + double StartTime = 0.; + int running = 0; + + static double GetFrequency(); + static double GetTime(); +#ifndef GPUCODE + static double Frequency; +#endif +}; + +#endif diff --git a/GPU/GPUTracking/utils/vecpod.h b/GPU/GPUTracking/utils/vecpod.h new file mode 100644 index 0000000000000..47ba4d1535d8e --- /dev/null +++ b/GPU/GPUTracking/utils/vecpod.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file vecpod.h +/// \author David Rohr + +#include <vector> + +template <class T> +struct vecpod_allocator { + typedef T value_type; + vecpod_allocator() noexcept : stdalloc() {} + T* allocate(std::size_t n) { return stdalloc.allocate(n); } + void deallocate(T* p, std::size_t n) { stdalloc.deallocate(p, n); } + static void construct(T*) {} + std::allocator<T> stdalloc; +}; + +template <class T> +using vecpod = typename std::vector<T, vecpod_allocator<T>>; +// template <class T> using vecpod = typename std::vector<T>; diff --git a/GPU/GPUbenchmark/CMakeLists.txt b/GPU/GPUbenchmark/CMakeLists.txt new file mode 100644 index 0000000000000..3aaf90dd19a92 --- /dev/null +++ b/GPU/GPUbenchmark/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +set(HDRS_INSTALL ../Shared/Kernels.h) + +if(CUDA_ENABLED) + o2_add_executable(gpu-memory-benchmark-cuda + SOURCES benchmark.cxx + cuda/Kernels.cu + PUBLIC_LINK_LIBRARIES Boost::program_options + ROOT::Tree + TARGETVARNAME targetName) +endif() + +if(HIP_ENABLED) + # Hipify-perl + set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") + + set(HIP_KERNEL "Kernels.hip.cxx") + set(CU_KERNEL ${CMAKE_CURRENT_SOURCE_DIR}/cuda/Kernels.cu) + set(HIP_KERNEL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/hip/${HIP_KERNEL}") + + if(EXISTS ${HIPIFY_EXECUTABLE}) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CU_KERNEL}) + add_custom_command( + OUTPUT ${HIP_KERNEL_PATH} + COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${CU_KERNEL} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${HIP_KERNEL_PATH} + ) + set(CMAKE_CXX_COMPILER ${HIP_HIPCC_EXECUTABLE}) + set(CMAKE_CXX_LINKER ${HIP_HIPCC_EXECUTABLE}) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") + + o2_add_executable(gpu-memory-benchmark-hip + SOURCES benchmark.cxx + hip/Kernels.hip.cxx + PUBLIC_LINK_LIBRARIES hip::host + Boost::program_options + ROOT::Tree + TARGETVARNAME targetName) + + if(HIP_AMDGPUTARGET) + # Need to add gpu target also to link flags due to gpu-rdc option + target_link_options(${targetName} PUBLIC --amdgpu-target=${HIP_AMDGPUTARGET}) + endif() + endif() +endif() + +o2_add_test_root_macro(macro/showBenchmarks.C) diff --git a/GPU/GPUbenchmark/Shared/Kernels.h b/GPU/GPUbenchmark/Shared/Kernels.h new file mode 100644 index 0000000000000..06e6cbb9839fa --- /dev/null +++ b/GPU/GPUbenchmark/Shared/Kernels.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Kernels.h +/// \author: mconcas@cern.ch + +#ifndef GPU_BENCHMARK_KERNELS_H +#define GPU_BENCHMARK_KERNELS_H + +#include "Utils.h" +#include <vector> +#include <iostream> +#include <iomanip> +#include <memory> +#include <chrono> + +namespace o2 +{ +namespace benchmark +{ + +template <class chunk_type> +class GPUbenchmark final +{ + public: + GPUbenchmark() = delete; // need for a configuration + GPUbenchmark(benchmarkOpts& opts, std::shared_ptr<ResultWriter> rWriter) : mResultWriter{rWriter}, mOptions{opts} + { + } + virtual ~GPUbenchmark() = default; + template <typename... T> + float measure(void (GPUbenchmark::*)(T...), const char*, T&&... args); + + // Single stream synchronous (sequential kernels) execution + template <typename... T> + float benchmarkSync(void (*kernel)(T...), + int nLaunches, int blocks, int threads, T&... args); + + // Multi-streams asynchronous executions on whole memory + template <typename... T> + std::vector<float> benchmarkAsync(void (*kernel)(int, T...), + int nStreams, int nLaunches, int blocks, int threads, T&... args); + + // Main interface + void globalInit(); // Allocate scratch buffers and compute runtime parameters + void run(); // Execute all specified callbacks + void globalFinalize(); // Cleanup + void printDevices(); // Dump info + + // Initializations/Finalizations of tests. Not to be measured, in principle used for report + void readInit(); + void readFinalize(); + + void writeInit(); + void writeFinalize(); + + void copyInit(); + void copyFinalize(); + + // Kernel calling wrappers + void readSequential(SplitLevel sl); + void readConcurrent(SplitLevel sl, int nRegions = 2); + + void writeSequential(SplitLevel sl); + void writeConcurrent(SplitLevel sl, int nRegions = 2); + + void copySequential(SplitLevel sl); + void copyConcurrent(SplitLevel sl, int nRegions = 2); + + private: + gpuState<chunk_type> mState; + std::shared_ptr<ResultWriter> mResultWriter; + benchmarkOpts mOptions; +}; + +} // namespace benchmark +} // namespace o2 +#endif \ No newline at end of file diff --git a/GPU/GPUbenchmark/Shared/Utils.h b/GPU/GPUbenchmark/Shared/Utils.h new file mode 100644 index 0000000000000..fc52a623d5639 --- /dev/null +++ b/GPU/GPUbenchmark/Shared/Utils.h @@ -0,0 +1,186 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Common.h +/// \author: mconcas@cern.ch + +#ifndef GPU_BENCHMARK_UTILS_H +#define GPU_BENCHMARK_UTILS_H + +#include <iostream> +#include <iomanip> +#include <typeinfo> +#include <boost/program_options.hpp> +#include <vector> +#include <TTree.h> +#include <TFile.h> + +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +#define GB (1024 * 1024 * 1024) + +enum class Test { + Read, + Write, + Copy +}; + +enum class Mode { + Sequential, + Concurrent +}; + +enum class SplitLevel { + Blocks, + Threads +}; + +namespace o2 +{ +namespace benchmark +{ + +struct benchmarkOpts { + benchmarkOpts() = default; + + int deviceId = 0; + std::vector<Test> tests = {Test::Read, Test::Write, Test::Copy}; + std::vector<Mode> modes = {Mode::Sequential, Mode::Concurrent}; + std::vector<SplitLevel> pools = {SplitLevel::Blocks, SplitLevel::Threads}; + float chunkReservedGB = 1.f; + int nRegions = 2; + float freeMemoryFractionToAllocate = 0.95f; + int kernelLaunches = 1; + int nTests = 1; +}; + +template <class T> +struct gpuState { + int getMaxChunks() + { + return (double)scratchSize / (chunkReservedGB * GB); + } + + void computeScratchPtrs() + { + partAddrOnHost.resize(getMaxChunks()); + for (size_t iBuffAddress{0}; iBuffAddress < getMaxChunks(); ++iBuffAddress) { + partAddrOnHost[iBuffAddress] = reinterpret_cast<T*>(reinterpret_cast<char*>(scratchPtr) + static_cast<size_t>(GB * chunkReservedGB) * iBuffAddress); + } + } + + size_t getPartitionCapacity() + { + return static_cast<size_t>(GB * chunkReservedGB / sizeof(T)); + } + + std::vector<T*> getScratchPtrs() + { + return partAddrOnHost; + } + + std::vector<std::vector<T>>& getHostBuffers() + { + return gpuBuffersHost; + } + + int getNKernelLaunches() { return iterations; } + + // Configuration + size_t nMaxThreadsPerDimension; + int iterations; + + float chunkReservedGB; // Size of each partition (GB) + + // General containers and state + T* scratchPtr; // Pointer to scratch buffer + size_t scratchSize; // Size of scratch area (B) + std::vector<T*> partAddrOnHost; // Pointers to scratch partitions on host vector + std::vector<std::vector<T>> gpuBuffersHost; // Host-based vector-ized data + T* deviceReadResultsPtr; // Results of the read test (single variable) on GPU + std::vector<T> hostReadResultsVector; // Results of the read test (single variable) on host + T* deviceWriteResultsPtr; // Results of the write test (single variable) on GPU + std::vector<T> hostWriteResultsVector; // Results of the write test (single variable) on host + T* deviceCopyInputsPtr; // Inputs of the copy test (single variable) on GPU + std::vector<T> hostCopyInputsVector; // Inputs of the copy test (single variable) on host + + // Static info + size_t totalMemory; + size_t nMultiprocessors; + size_t nMaxThreadsPerBlock; +}; + +// Interface class to stream results to root file +class ResultWriter +{ + public: + explicit ResultWriter(const std::string resultsTreeFilename = "benchmark_results.root"); + ~ResultWriter() = default; + void storeBenchmarkEntry(int chunk, float entry); + void addBenchmarkEntry(const std::string bName, const std::string type, const int nChunks); + void snapshotBenchmark(); + void saveToFile(); + + private: + std::vector<float> mBenchmarkResults; + std::vector<TTree*> mBenchmarkTrees; + TFile* mOutfile; +}; + +inline ResultWriter::ResultWriter(const std::string resultsTreeFilename) +{ + mOutfile = TFile::Open(resultsTreeFilename.data(), "recreate"); +} + +inline void ResultWriter::addBenchmarkEntry(const std::string bName, const std::string type, const int nChunks) +{ + mBenchmarkTrees.emplace_back(new TTree((bName + "_" + type).data(), (bName + "_" + type).data())); + mBenchmarkResults.clear(); + mBenchmarkResults.resize(nChunks); + mBenchmarkTrees.back()->Branch("elapsed", &mBenchmarkResults); +} + +inline void ResultWriter::storeBenchmarkEntry(int chunk, float entry) +{ + mBenchmarkResults[chunk] = entry; +} + +inline void ResultWriter::snapshotBenchmark() +{ + mBenchmarkTrees.back()->Fill(); +} + +inline void ResultWriter::saveToFile() +{ + mOutfile->cd(); + for (auto t : mBenchmarkTrees) { + t->Write(); + } + mOutfile->Close(); +} + +} // namespace benchmark +} // namespace o2 + +#define failed(...) \ + printf("%serror: ", KRED); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + printf("error: TEST FAILED\n%s", KNRM); \ + exit(EXIT_FAILURE); +#endif \ No newline at end of file diff --git a/GPU/GPUbenchmark/benchmark.cxx b/GPU/GPUbenchmark/benchmark.cxx new file mode 100644 index 0000000000000..85f7654927c8f --- /dev/null +++ b/GPU/GPUbenchmark/benchmark.cxx @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file benchmark.cxx +/// \author mconcas@cern.ch +/// \brief configuration widely inspired/copied by SimConfig +#include "Shared/Kernels.h" + +bool parseArgs(o2::benchmark::benchmarkOpts& conf, int argc, const char* argv[]) +{ + namespace bpo = boost::program_options; + bpo::variables_map vm; + bpo::options_description options("Benchmark options"); + options.add_options()( + "help,h", "Print help message.")( + "device,d", bpo::value<int>()->default_value(0), "Id of the device to run test on, EPN targeted.")( + "test,t", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>{"read", "write", "copy"}, "read, write, copy"), "Tests to be performed.")( + "mode,m", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>{"seq", "con"}, "seq, con"), "Mode: sequential or concurrent.")( + "pool,p", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>{"sb, mb"}, "sb, mb"), "Pool strategy: single or multi blocks.")( + "chunkSize,c", bpo::value<float>()->default_value(1.f), "Size of scratch partitions (GB).")( + "freeMemFraction,f", bpo::value<float>()->default_value(0.95f), "Fraction of free memory to be allocated (min: 0.f, max: 1.f).")( + "launches,l", bpo::value<int>()->default_value(10), "Number of iterations in reading kernels.")( + "nruns,n", bpo::value<int>()->default_value(1), "Number of times each test is run."); + try { + bpo::store(parse_command_line(argc, argv, options), vm); + if (vm.count("help")) { + std::cout << options << std::endl; + return false; + } + + bpo::notify(vm); + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing command line arguments. Available options:\n"; + + std::cerr << options << std::endl; + return false; + } + + conf.deviceId = vm["device"].as<int>(); + conf.freeMemoryFractionToAllocate = vm["freeMemFraction"].as<float>(); + conf.chunkReservedGB = vm["chunkSize"].as<float>(); + conf.nRegions = vm["regions"].as<int>(); + conf.kernelLaunches = vm["launches"].as<int>(); + conf.nTests = vm["nruns"].as<int>(); + + conf.tests.clear(); + for (auto& test : vm["test"].as<std::vector<std::string>>()) { + if (test == "read") { + conf.tests.push_back(Test::Read); + } else if (test == "write") { + conf.tests.push_back(Test::Write); + } else if (test == "copy") { + conf.tests.push_back(Test::Copy); + } else { + std::cerr << "Unkonwn test: " << test << std::endl; + exit(1); + } + } + + conf.modes.clear(); + for (auto& mode : vm["mode"].as<std::vector<std::string>>()) { + if (mode == "seq") { + conf.modes.push_back(Mode::Sequential); + } else if (mode == "con") { + conf.modes.push_back(Mode::Concurrent); + } else { + std::cerr << "Unkonwn mode: " << mode << std::endl; + exit(1); + } + } + + conf.pools.clear(); + for (auto& pool : vm["pool"].as<std::vector<std::string>>()) { + if (pool == "sb") { + conf.pools.push_back(SplitLevel::Blocks); + } else if (pool == "mb") { + conf.pools.push_back(SplitLevel::Threads); + } else { + std::cerr << "Unkonwn pool: " << pool << std::endl; + exit(1); + } + } + + return true; +} + +using o2::benchmark::ResultWriter; + +int main(int argc, const char* argv[]) +{ + + o2::benchmark::benchmarkOpts opts; + + if (!parseArgs(opts, argc, argv)) { + return -1; + } + + std::shared_ptr<ResultWriter> writer = std::make_shared<ResultWriter>(std::to_string(opts.deviceId) + "_benchmark_results.root"); + + o2::benchmark::GPUbenchmark<char> bm_char{opts, writer}; + bm_char.run(); + o2::benchmark::GPUbenchmark<int> bm_int{opts, writer}; + bm_int.run(); + o2::benchmark::GPUbenchmark<size_t> bm_size_t{opts, writer}; + bm_size_t.run(); + + // save results + writer.get()->saveToFile(); + + return 0; +} diff --git a/GPU/GPUbenchmark/cuda/Kernels.cu b/GPU/GPUbenchmark/cuda/Kernels.cu new file mode 100644 index 0000000000000..4e26a655e9b5a --- /dev/null +++ b/GPU/GPUbenchmark/cuda/Kernels.cu @@ -0,0 +1,875 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file Kernels.{cu, hip.cxx} +/// \author: mconcas@cern.ch + +#include "../Shared/Kernels.h" +#if defined(__HIPCC__) +#include "hip/hip_runtime.h" +#endif +#include <cstdio> + +// Memory partitioning legend +// +// |----------------------region 0-----------------|----------------------region 1-----------------| regions -> deafult: 2, to test lower and upper RAM +// |--chunk 0--|--chunk 1--|--chunk 2--| *** |--chunk n--| chunks -> default size: 1GB (sing block pins) +// |__________________________________________scratch______________________________________________| scratch -> default size: 95% free GPU RAM + +#define GPUCHECK(error) \ + if (error != cudaSuccess) { \ + printf("%serror: '%s'(%d) at %s:%d%s\n", KRED, cudaGetErrorString(error), error, __FILE__, \ + __LINE__, KNRM); \ + failed("API returned error code."); \ + } + +double bytesToKB(size_t s) { return (double)s / (1024.0); } +double bytesToGB(size_t s) { return (double)s / GB; } + +int getCorrespondingRegionId(int Id, int nChunks, int nRegions = 1) +{ + return Id * nRegions / nChunks; +} + +template <class T> +std::string getType() +{ + if (typeid(T).name() == typeid(char).name()) { + return std::string{"char"}; + } + if (typeid(T).name() == typeid(size_t).name()) { + return std::string{"unsigned_long"}; + } + if (typeid(T).name() == typeid(int).name()) { + return std::string{"int"}; + } + if (typeid(T).name() == typeid(int4).name()) { + return std::string{"int4"}; + } + return std::string{"unknown"}; +} + +namespace o2 +{ +namespace benchmark +{ +namespace gpu +{ + +/////////////////////////// +// Device functions go here +template <class chunk_type> +__host__ __device__ inline chunk_type* getPartPtrOnScratch(chunk_type* scratchPtr, float chunkReservedGB, size_t partNumber) +{ + return reinterpret_cast<chunk_type*>(reinterpret_cast<char*>(scratchPtr) + static_cast<size_t>(GB * chunkReservedGB) * partNumber); +} + +////////////////// +// Kernels go here +// Reading +template <class chunk_type> +__global__ void readChunkSBKernel( + int chunkId, + chunk_type* results, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + if (chunkId == blockIdx.x) { // runs only if blockIdx.x is allowed in given split + chunk_type sink{0}; + chunk_type* ptr = getPartPtrOnScratch(scratch, chunkReservedGB, chunkId); + for (size_t i = threadIdx.x; i < chunkSize; i += blockDim.x) { + sink += ptr[i]; + } + if (sink == static_cast<chunk_type>(1)) { + results[chunkId] = sink; + } + } +} + +template <class chunk_type> +__global__ void readChunkMBKernel( + int chunkId, + chunk_type* results, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < chunkSize; i += blockDim.x * gridDim.x) { + if (getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i] == static_cast<chunk_type>(1)) { // actual read operation is performed here + results[chunkId] += getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i]; // this case should never happen and waves should be always in sync + } + } +} + +// Writing +template <class chunk_type> +__global__ void writeChunkSBKernel( + int chunkId, + chunk_type* results, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + if (chunkId == blockIdx.x) { // runs only if blockIdx.x is allowed in given split + for (size_t i = threadIdx.x; i < chunkSize; i += blockDim.x) { + getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i] = 1; + } + } +} + +template <class chunk_type> +__global__ void writeChunkMBKernel( + int chunkId, + chunk_type* results, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < chunkSize; i += blockDim.x * gridDim.x) { + getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i] = 1; + } +} + +// Copying +template <class chunk_type> +__global__ void copyChunkSBKernel( + int chunkId, + chunk_type* inputs, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + if (chunkId == blockIdx.x) { // runs only if blockIdx.x is allowed in given split + for (size_t i = threadIdx.x; i < chunkSize; i += blockDim.x) { + getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i] = inputs[chunkId]; + } + } +} + +template <class chunk_type> +__global__ void copyChunkMBKernel( + int chunkId, + chunk_type* inputs, + chunk_type* scratch, + size_t chunkSize, + float chunkReservedGB = 1.f) +{ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < chunkSize; i += blockDim.x * gridDim.x) { + getPartPtrOnScratch(scratch, chunkReservedGB, chunkId)[i] = inputs[chunkId]; + } +} + +} // namespace gpu + +void printDeviceProp(int deviceId) +{ + const int w1 = 34; + std::cout << std::left; + std::cout << std::setw(w1) + << "--------------------------------------------------------------------------------" + << std::endl; + std::cout << std::setw(w1) << "device#" << deviceId << std::endl; + + cudaDeviceProp props; + GPUCHECK(cudaGetDeviceProperties(&props, deviceId)); + + std::cout << std::setw(w1) << "Name: " << props.name << std::endl; + std::cout << std::setw(w1) << "pciBusID: " << props.pciBusID << std::endl; + std::cout << std::setw(w1) << "pciDeviceID: " << props.pciDeviceID << std::endl; + std::cout << std::setw(w1) << "pciDomainID: " << props.pciDomainID << std::endl; + std::cout << std::setw(w1) << "multiProcessorCount: " << props.multiProcessorCount << std::endl; + std::cout << std::setw(w1) << "maxThreadsPerMultiProcessor: " << props.maxThreadsPerMultiProcessor + << std::endl; + std::cout << std::setw(w1) << "isMultiGpuBoard: " << props.isMultiGpuBoard << std::endl; + std::cout << std::setw(w1) << "clockRate: " << (float)props.clockRate / 1000.0 << " Mhz" << std::endl; + std::cout << std::setw(w1) << "memoryClockRate: " << (float)props.memoryClockRate / 1000.0 << " Mhz" + << std::endl; + std::cout << std::setw(w1) << "memoryBusWidth: " << props.memoryBusWidth << std::endl; + std::cout << std::setw(w1) << "clockInstructionRate: " << (float)props.clockRate / 1000.0 + << " Mhz" << std::endl; + std::cout << std::setw(w1) << "totalGlobalMem: " << std::fixed << std::setprecision(2) + << bytesToGB(props.totalGlobalMem) << " GB" << std::endl; +#if !defined(__CUDACC__) + std::cout << std::setw(w1) << "maxSharedMemoryPerMultiProcessor: " << std::fixed << std::setprecision(2) + << bytesToKB(props.sharedMemPerMultiprocessor) << " KB" << std::endl; +#endif +#if defined(__HIPCC__) + std::cout << std::setw(w1) << "maxSharedMemoryPerMultiProcessor: " << std::fixed << std::setprecision(2) + << bytesToKB(props.maxSharedMemoryPerMultiProcessor) << " KB" << std::endl; +#endif + std::cout << std::setw(w1) << "totalConstMem: " << props.totalConstMem << std::endl; + std::cout << std::setw(w1) << "sharedMemPerBlock: " << (float)props.sharedMemPerBlock / 1024.0 << " KB" + << std::endl; + std::cout << std::setw(w1) << "canMapHostMemory: " << props.canMapHostMemory << std::endl; + std::cout << std::setw(w1) << "regsPerBlock: " << props.regsPerBlock << std::endl; + std::cout << std::setw(w1) << "warpSize: " << props.warpSize << std::endl; + std::cout << std::setw(w1) << "l2CacheSize: " << props.l2CacheSize << std::endl; + std::cout << std::setw(w1) << "computeMode: " << props.computeMode << std::endl; + std::cout << std::setw(w1) << "maxThreadsPerBlock: " << props.maxThreadsPerBlock << std::endl; + std::cout << std::setw(w1) << "maxThreadsDim.x: " << props.maxThreadsDim[0] << std::endl; + std::cout << std::setw(w1) << "maxThreadsDim.y: " << props.maxThreadsDim[1] << std::endl; + std::cout << std::setw(w1) << "maxThreadsDim.z: " << props.maxThreadsDim[2] << std::endl; + std::cout << std::setw(w1) << "maxGridSize.x: " << props.maxGridSize[0] << std::endl; + std::cout << std::setw(w1) << "maxGridSize.y: " << props.maxGridSize[1] << std::endl; + std::cout << std::setw(w1) << "maxGridSize.z: " << props.maxGridSize[2] << std::endl; + std::cout << std::setw(w1) << "major: " << props.major << std::endl; + std::cout << std::setw(w1) << "minor: " << props.minor << std::endl; + std::cout << std::setw(w1) << "concurrentKernels: " << props.concurrentKernels << std::endl; + std::cout << std::setw(w1) << "cooperativeLaunch: " << props.cooperativeLaunch << std::endl; + std::cout << std::setw(w1) << "cooperativeMultiDeviceLaunch: " << props.cooperativeMultiDeviceLaunch << std::endl; +#if defined(__HIPCC__) + std::cout << std::setw(w1) << "arch.hasGlobalInt32Atomics: " << props.arch.hasGlobalInt32Atomics << std::endl; + std::cout << std::setw(w1) << "arch.hasGlobalFloatAtomicExch: " << props.arch.hasGlobalFloatAtomicExch + << std::endl; + std::cout << std::setw(w1) << "arch.hasSharedInt32Atomics: " << props.arch.hasSharedInt32Atomics << std::endl; + std::cout << std::setw(w1) << "arch.hasSharedFloatAtomicExch: " << props.arch.hasSharedFloatAtomicExch + << std::endl; + std::cout << std::setw(w1) << "arch.hasFloatAtomicAdd: " << props.arch.hasFloatAtomicAdd << std::endl; + std::cout << std::setw(w1) << "arch.hasGlobalInt64Atomics: " << props.arch.hasGlobalInt64Atomics << std::endl; + std::cout << std::setw(w1) << "arch.hasSharedInt64Atomics: " << props.arch.hasSharedInt64Atomics << std::endl; + std::cout << std::setw(w1) << "arch.hasDoubles: " << props.arch.hasDoubles << std::endl; + std::cout << std::setw(w1) << "arch.hasWarpVote: " << props.arch.hasWarpVote << std::endl; + std::cout << std::setw(w1) << "arch.hasWarpBallot: " << props.arch.hasWarpBallot << std::endl; + std::cout << std::setw(w1) << "arch.hasWarpShuffle: " << props.arch.hasWarpShuffle << std::endl; + std::cout << std::setw(w1) << "arch.hasFunnelShift: " << props.arch.hasFunnelShift << std::endl; + std::cout << std::setw(w1) << "arch.hasThreadFenceSystem: " << props.arch.hasThreadFenceSystem << std::endl; + std::cout << std::setw(w1) << "arch.hasSyncThreadsExt: " << props.arch.hasSyncThreadsExt << std::endl; + std::cout << std::setw(w1) << "arch.hasSurfaceFuncs: " << props.arch.hasSurfaceFuncs << std::endl; + std::cout << std::setw(w1) << "arch.has3dGrid: " << props.arch.has3dGrid << std::endl; + std::cout << std::setw(w1) << "arch.hasDynamicParallelism: " << props.arch.hasDynamicParallelism << std::endl; + std::cout << std::setw(w1) << "gcnArchName: " << props.gcnArchName << std::endl; +#endif + std::cout << std::setw(w1) << "isIntegrated: " << props.integrated << std::endl; + std::cout << std::setw(w1) << "maxTexture1D: " << props.maxTexture1D << std::endl; + std::cout << std::setw(w1) << "maxTexture2D.width: " << props.maxTexture2D[0] << std::endl; + std::cout << std::setw(w1) << "maxTexture2D.height: " << props.maxTexture2D[1] << std::endl; + std::cout << std::setw(w1) << "maxTexture3D.width: " << props.maxTexture3D[0] << std::endl; + std::cout << std::setw(w1) << "maxTexture3D.height: " << props.maxTexture3D[1] << std::endl; + std::cout << std::setw(w1) << "maxTexture3D.depth: " << props.maxTexture3D[2] << std::endl; +#if defined(__HIPCC__) + std::cout << std::setw(w1) << "isLargeBar: " << props.isLargeBar << std::endl; + std::cout << std::setw(w1) << "asicRevision: " << props.asicRevision << std::endl; +#endif + + int deviceCnt; + GPUCHECK(cudaGetDeviceCount(&deviceCnt)); + std::cout << std::setw(w1) << "peers: "; + for (int i = 0; i < deviceCnt; i++) { + int isPeer; + GPUCHECK(cudaDeviceCanAccessPeer(&isPeer, i, deviceId)); + if (isPeer) { + std::cout << "device#" << i << " "; + } + } + std::cout << std::endl; + std::cout << std::setw(w1) << "non-peers: "; + for (int i = 0; i < deviceCnt; i++) { + int isPeer; + GPUCHECK(cudaDeviceCanAccessPeer(&isPeer, i, deviceId)); + if (!isPeer) { + std::cout << "device#" << i << " "; + } + } + std::cout << std::endl; + + size_t free, total; + GPUCHECK(cudaMemGetInfo(&free, &total)); + + std::cout << std::fixed << std::setprecision(2); + std::cout << std::setw(w1) << "memInfo.total: " << bytesToGB(total) << " GB" << std::endl; + std::cout << std::setw(w1) << "memInfo.free: " << bytesToGB(free) << " GB (" << std::setprecision(0) + << (float)free / total * 100.0 << "%)" << std::endl; +} + +template <class chunk_type> +template <typename... T> +float GPUbenchmark<chunk_type>::benchmarkSync(void (*kernel)(T...), + int nLaunches, int blocks, int threads, T&... args) // run for each chunk (id is passed in variadic args) +{ + cudaEvent_t start, stop; + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaEventCreate(&start)); + GPUCHECK(cudaEventCreate(&stop)); + + GPUCHECK(cudaEventRecord(start)); + for (auto iLaunch{0}; iLaunch < nLaunches; ++iLaunch) { // Schedule all the requested kernel launches + (*kernel)<<<blocks, threads, 0, 0>>>(args...); // NOLINT: clang-tidy false-positive + } + GPUCHECK(cudaEventRecord(stop)); // record checkpoint + + GPUCHECK(cudaEventSynchronize(stop)); // synchronize executions + float milliseconds{0.f}; + GPUCHECK(cudaEventElapsedTime(&milliseconds, start, stop)); + GPUCHECK(cudaEventDestroy(start)); + GPUCHECK(cudaEventDestroy(stop)); + + return milliseconds; +} + +template <class chunk_type> +template <typename... T> +std::vector<float> GPUbenchmark<chunk_type>::benchmarkAsync(void (*kernel)(int, T...), + int nStreams, int nLaunches, int blocks, int threads, T&... args) +{ + std::vector<cudaEvent_t> starts(nStreams), stops(nStreams); + std::vector<cudaStream_t> streams(nStreams); + std::vector<float> results(nStreams); + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + for (auto iStream{0}; iStream < nStreams; ++iStream) { // one stream per chunk + GPUCHECK(cudaStreamCreate(&(streams.at(iStream)))); + GPUCHECK(cudaEventCreate(&(starts[iStream]))); + GPUCHECK(cudaEventCreate(&(stops[iStream]))); + } + + for (auto iStream{0}; iStream < nStreams; ++iStream) { + GPUCHECK(cudaEventRecord(starts[iStream], streams[iStream])); + + for (auto iLaunch{0}; iLaunch < 10 * nLaunches; ++iLaunch) { // 10x consecutive launches on the same stream + (*kernel)<<<blocks, threads, 0, streams[iStream]>>>(iStream, args...); + } + GPUCHECK(cudaEventRecord(stops[iStream], streams[iStream])); + } + + for (auto iStream{0}; iStream < nStreams; ++iStream) { + GPUCHECK(cudaEventSynchronize(stops[iStream])); + GPUCHECK(cudaEventElapsedTime(&(results.at(iStream)), starts[iStream], stops[iStream])); + GPUCHECK(cudaEventDestroy(starts[iStream])); + GPUCHECK(cudaEventDestroy(stops[iStream])); + GPUCHECK(cudaStreamDestroy(streams[iStream])); + } + + return results; +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::printDevices() +{ + int deviceCnt; + GPUCHECK(cudaGetDeviceCount(&deviceCnt)); + + for (int i = 0; i < deviceCnt; i++) { + GPUCHECK(cudaSetDevice(i)); + printDeviceProp(i); + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::globalInit() +{ + cudaDeviceProp props; + size_t free; + + // Fetch and store features + GPUCHECK(cudaGetDeviceProperties(&props, mOptions.deviceId)); + GPUCHECK(cudaMemGetInfo(&free, &mState.totalMemory)); + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + + mState.chunkReservedGB = mOptions.chunkReservedGB; + mState.iterations = mOptions.kernelLaunches; + mState.nMultiprocessors = props.multiProcessorCount; + mState.nMaxThreadsPerBlock = props.maxThreadsPerMultiProcessor; + mState.nMaxThreadsPerDimension = props.maxThreadsDim[0]; + mState.scratchSize = static_cast<long int>(mOptions.freeMemoryFractionToAllocate * free); + std::cout << ">>> Running on: \033[1;31m" << props.name << "\e[0m" << std::endl; + + // Allocate scratch on GPU + GPUCHECK(cudaMalloc(reinterpret_cast<void**>(&mState.scratchPtr), mState.scratchSize)); + + mState.computeScratchPtrs(); + GPUCHECK(cudaMemset(mState.scratchPtr, 0, mState.scratchSize)) + + std::cout << " ├ Buffer type: \e[1m" << getType<chunk_type>() << "\e[0m" << std::endl + << " ├ Allocated: " << std::setprecision(2) << bytesToGB(mState.scratchSize) << "/" << std::setprecision(2) << bytesToGB(mState.totalMemory) + << "(GB) [" << std::setprecision(3) << (100.f) * (mState.scratchSize / (float)mState.totalMemory) << "%]\n" + << " ├ Number of scratch chunks: " << mState.getMaxChunks() << " of " << mOptions.chunkReservedGB << "GB each\n" + << " └ Each chunk can store up to: " << mState.getPartitionCapacity() << " elements" << std::endl + << std::endl; +} + +/// Read +template <class chunk_type> +void GPUbenchmark<chunk_type>::readInit() +{ + std::cout << ">>> Initializing read benchmarks with \e[1m" << mOptions.nTests << "\e[0m runs and \e[1m" << mOptions.kernelLaunches << "\e[0m kernel launches" << std::endl; + mState.hostReadResultsVector.resize(mState.getMaxChunks()); + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaMalloc(reinterpret_cast<void**>(&(mState.deviceReadResultsPtr)), mState.getMaxChunks() * sizeof(chunk_type))); +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::readSequential(SplitLevel sl) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("seq_read_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq read, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::readChunkSBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceReadResultsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("seq_read_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq read, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::readChunkMBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceReadResultsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::readConcurrent(SplitLevel sl, int nRegions) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("conc_read_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc read, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::readChunkSBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceReadResultsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("conc_read_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc read, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::readChunkMBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceReadResultsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::readFinalize() +{ + GPUCHECK(cudaMemcpy(mState.hostReadResultsVector.data(), mState.deviceReadResultsPtr, mState.getMaxChunks() * sizeof(chunk_type), cudaMemcpyDeviceToHost)); + GPUCHECK(cudaFree(mState.deviceReadResultsPtr)); + std::cout << " └ done." << std::endl; +} + +/// Write +template <class chunk_type> +void GPUbenchmark<chunk_type>::writeInit() +{ + std::cout << ">>> Initializing write benchmarks with \e[1m" << mOptions.nTests << "\e[0m runs and \e[1m" << mOptions.kernelLaunches << "\e[0m kernel launches" << std::endl; + mState.hostWriteResultsVector.resize(mState.getMaxChunks()); + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaMalloc(reinterpret_cast<void**>(&(mState.deviceWriteResultsPtr)), mState.getMaxChunks() * sizeof(chunk_type))); +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::writeSequential(SplitLevel sl) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("seq_write_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq write, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::writeChunkSBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceWriteResultsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("seq_write_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq write, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::writeChunkMBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceWriteResultsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::writeConcurrent(SplitLevel sl, int nRegions) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("conc_write_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc write, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::writeChunkSBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceWriteResultsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("conc_write_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc write, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::writeChunkMBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceWriteResultsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::writeFinalize() +{ + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaMemcpy(mState.hostWriteResultsVector.data(), mState.deviceWriteResultsPtr, mState.getMaxChunks() * sizeof(chunk_type), cudaMemcpyDeviceToHost)); + GPUCHECK(cudaFree(mState.deviceWriteResultsPtr)); + std::cout << " └ done." << std::endl; +} + +/// Copy +template <class chunk_type> +void GPUbenchmark<chunk_type>::copyInit() +{ + std::cout << ">>> Initializing copy benchmarks with \e[1m" << mOptions.nTests << "\e[0m runs and \e[1m" << mOptions.kernelLaunches << "\e[0m kernel launches" << std::endl; + mState.hostCopyInputsVector.resize(mState.getMaxChunks()); + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaMalloc(reinterpret_cast<void**>(&(mState.deviceCopyInputsPtr)), mState.getMaxChunks() * sizeof(chunk_type))); + GPUCHECK(cudaMemset(mState.deviceCopyInputsPtr, 1, mState.getMaxChunks() * sizeof(chunk_type))); +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::copySequential(SplitLevel sl) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("seq_copy_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq copy, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::copyChunkSBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceCopyInputsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("seq_copy_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { // loop on the number of times we perform same measurement + std::cout << std::setw(2) << " ├ (" << getType<chunk_type>() << ") Seq copy, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + for (auto iChunk{0}; iChunk < mState.getMaxChunks(); ++iChunk) { // loop over single chunks separately + auto result = benchmarkSync(&gpu::copyChunkMBKernel<chunk_type>, + mState.getNKernelLaunches(), + nBlocks, + nThreads, + iChunk, + mState.deviceCopyInputsPtr, + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + mResultWriter.get()->storeBenchmarkEntry(iChunk, result); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::copyConcurrent(SplitLevel sl, int nRegions) +{ + switch (sl) { + case SplitLevel::Blocks: { + mResultWriter.get()->addBenchmarkEntry("conc_copy_SB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc copy, sing block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::copyChunkSBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceCopyInputsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + case SplitLevel::Threads: { + mResultWriter.get()->addBenchmarkEntry("conc_copy_MB", getType<chunk_type>(), mState.getMaxChunks()); + auto nBlocks{mState.nMultiprocessors}; + auto nThreads{std::min(mState.nMaxThreadsPerDimension, mState.nMaxThreadsPerBlock)}; + auto chunks{mState.getMaxChunks()}; + auto capacity{mState.getPartitionCapacity()}; + + for (auto measurement{0}; measurement < mOptions.nTests; ++measurement) { + std::cout << " ├ (" << getType<chunk_type>() << ") Conc copy, mult block (" << measurement + 1 << "/" << mOptions.nTests << "):"; + auto results = benchmarkAsync(&gpu::copyChunkMBKernel<chunk_type>, + mState.getMaxChunks(), // nStreams + mState.getNKernelLaunches(), + nBlocks, + nThreads, + mState.deviceCopyInputsPtr, // kernel arguments (chunkId is passed by wrapper) + mState.scratchPtr, + capacity, + mState.chunkReservedGB); + for (auto iResult{0}; iResult < results.size(); ++iResult) { + auto region = getCorrespondingRegionId(iResult, nBlocks, nRegions); + mResultWriter.get()->storeBenchmarkEntry(iResult, results[iResult]); + } + mResultWriter.get()->snapshotBenchmark(); + std::cout << "\033[1;32m complete\033[0m" << std::endl; + } + break; + } + } +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::copyFinalize() +{ + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaMemcpy(mState.hostCopyInputsVector.data(), mState.deviceCopyInputsPtr, mState.getMaxChunks() * sizeof(chunk_type), cudaMemcpyDeviceToHost)); + GPUCHECK(cudaFree(mState.deviceCopyInputsPtr)); + std::cout << " └ done." << std::endl; +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::globalFinalize() +{ + GPUCHECK(cudaSetDevice(mOptions.deviceId)); + GPUCHECK(cudaFree(mState.scratchPtr)); +} + +template <class chunk_type> +void GPUbenchmark<chunk_type>::run() +{ + globalInit(); + + for (auto& sl : mOptions.pools) { + for (auto& test : mOptions.tests) { + switch (test) { + case Test::Read: { + readInit(); + + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Sequential) != mOptions.modes.end()) { + readSequential(sl); + } + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Concurrent) != mOptions.modes.end()) { + readConcurrent(sl); + } + + readFinalize(); + + break; + } + case Test::Write: { + writeInit(); + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Sequential) != mOptions.modes.end()) { + writeSequential(sl); + } + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Concurrent) != mOptions.modes.end()) { + writeConcurrent(sl); + } + + writeFinalize(); + + break; + } + case Test::Copy: { + copyInit(); + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Sequential) != mOptions.modes.end()) { + copySequential(sl); + } + if (std::find(mOptions.modes.begin(), mOptions.modes.end(), Mode::Concurrent) != mOptions.modes.end()) { + copyConcurrent(sl); + } + + copyFinalize(); + + break; + } + } + } + } + + globalFinalize(); +} + +template class GPUbenchmark<char>; +template class GPUbenchmark<size_t>; +template class GPUbenchmark<int>; +// template class GPUbenchmark<uint4>; + +} // namespace benchmark +} // namespace o2 diff --git a/GPU/GPUbenchmark/hip/.gitignore b/GPU/GPUbenchmark/hip/.gitignore new file mode 100644 index 0000000000000..14f27f00c53c2 --- /dev/null +++ b/GPU/GPUbenchmark/hip/.gitignore @@ -0,0 +1 @@ +*.hip.cxx \ No newline at end of file diff --git a/GPU/GPUbenchmark/macro/showBenchmarks.C b/GPU/GPUbenchmark/macro/showBenchmarks.C new file mode 100644 index 0000000000000..281fc17b6d28d --- /dev/null +++ b/GPU/GPUbenchmark/macro/showBenchmarks.C @@ -0,0 +1,86 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include <TString.h> +#include <TFile.h> +#include <TH1F.h> +#include <TTree.h> +#include <TBranch.h> +#include <TCanvas.h> +#include <TGraphErrors.h> +#include <vector> +#include <unordered_map> +#include <iostream> +#endif + +int nBins{500}; +float minHist{0.f}, maxHist{1e4}; +void showBenchmarks(const TString fileName = "0_benchmark_results.root") +{ + auto f = TFile::Open(fileName.Data(), "read"); + std::unordered_map<std::string, TTree*> um_trees; + std::vector<std::vector<TH1F*>> histograms; + std::vector<TGraphErrors*> results; + std::vector<std::string> tests = {"read", "write", "copy"}; + std::vector<std::string> types = {"char", "int", "unsigned_long"}; + std::vector<std::string> modes = {"seq", "conc"}; + std::vector<std::string> patterns = {"SB", "MB"}; + + for (auto&& keyAsObj : *f->GetListOfKeys()) { + auto tName = ((TKey*)keyAsObj)->GetName(); + um_trees[tName] = (TTree*)f->Get(tName); + } + std::cout << "Found " << um_trees.size() << " trees.\n"; + + // Main loop + for (auto& keyPair : um_trees) { + for (auto& test : tests) { + if (keyPair.first.find(test) != std::string::npos) { + for (auto& mode : modes) { + if (keyPair.first.find(mode) != std::string::npos) { + for (auto& type : types) { + if (keyPair.first.find(type) != std::string::npos) { + for (auto& pattern : patterns) { + if (keyPair.first.find(pattern) != std::string::npos) { + // Single Tree entry, we know test, type, mode, pattern + std::vector<float>* measures = 0; + TBranch* elapsed; + keyPair.second->SetBranchAddress("elapsed", &measures, &elapsed); + elapsed->GetEntry(keyPair.second->LoadTree(0)); + auto nChunk = measures->size(); + histograms.emplace_back(nChunk); + for (int iHist{0}; iHist < (int)nChunk; ++iHist) { + histograms.back()[iHist] = new TH1F(Form("Chunk_%d_%s", iHist, keyPair.first.c_str()), Form("Chunk_%d_%s;ms", iHist, keyPair.first.c_str()), 500, 0, 1e4); + } + for (size_t iEntry(0); iEntry < (size_t)keyPair.second->GetEntriesFast(); ++iEntry) { + auto tentry = keyPair.second->LoadTree(iEntry); + elapsed->GetEntry(tentry); + for (int iHist{0}; iHist < (int)nChunk; ++iHist) { + histograms.back()[iHist]->Fill((*measures)[iHist]); + } + } + + std::vector<float> xCoord(nChunk), exCoord(nChunk), yCoord(nChunk), eyCoord(nChunk); + + for (size_t i{0}; i < nChunk; ++i) { + xCoord[i] = (float)i; + yCoord[i] = histograms.back()[i]->GetMean(); + eyCoord[i] = histograms.back()[i]->GetRMS(); + exCoord[i] = 0.f; + } + TCanvas* c = new TCanvas(Form("c%s", keyPair.first.c_str()), Form("%s", keyPair.first.c_str())); + c->cd(); + TGraphErrors* g = new TGraphErrors(nChunk, xCoord.data(), yCoord.data(), exCoord.data(), eyCoord.data()); + g->GetYaxis()->SetRangeUser(0, 5000); + g->GetXaxis()->SetRangeUser(-2.f, nChunk); + g->SetTitle(Form("%s, N_{test}=%d;chunk_id;elapsed (ms)", keyPair.first.c_str(), (int)keyPair.second->GetEntriesFast())); + g->SetFillColor(40); + g->Draw("AB"); + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/GPU/TPCFastTransformation/CMakeLists.txt b/GPU/TPCFastTransformation/CMakeLists.txt index 1b91851677d6e..0ff6d8f39640a 100644 --- a/GPU/TPCFastTransformation/CMakeLists.txt +++ b/GPU/TPCFastTransformation/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE TPCFastTransformation) @@ -68,7 +69,7 @@ if(${ALIGPU_BUILD_TYPE} STREQUAL "O2") O2::TPCReconstruction PUBLIC_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/stage/include - LABELS gpu tpc) + LABELS gpu tpc COMPILE_ONLY) endforeach() foreach(m IrregularSpline1DTest.C diff --git a/GPU/TPCFastTransformation/ChebyshevFit1D.cxx b/GPU/TPCFastTransformation/ChebyshevFit1D.cxx index af4cfe779e9ec..eeeeb344800f9 100644 --- a/GPU/TPCFastTransformation/ChebyshevFit1D.cxx +++ b/GPU/TPCFastTransformation/ChebyshevFit1D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/ChebyshevFit1D.h b/GPU/TPCFastTransformation/ChebyshevFit1D.h index 3b7ab15df9a61..ec2cfe0a4bc95 100644 --- a/GPU/TPCFastTransformation/ChebyshevFit1D.h +++ b/GPU/TPCFastTransformation/ChebyshevFit1D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline.cxx b/GPU/TPCFastTransformation/Spline.cxx index cdebd17ad68f1..01cb96bc28482 100644 --- a/GPU/TPCFastTransformation/Spline.cxx +++ b/GPU/TPCFastTransformation/Spline.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline.h b/GPU/TPCFastTransformation/Spline.h index ef06f560c76e9..b7c14b3c12cb9 100644 --- a/GPU/TPCFastTransformation/Spline.h +++ b/GPU/TPCFastTransformation/Spline.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline1D.cxx b/GPU/TPCFastTransformation/Spline1D.cxx index e5bf074ca410f..c1ef8a45346ef 100644 --- a/GPU/TPCFastTransformation/Spline1D.cxx +++ b/GPU/TPCFastTransformation/Spline1D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline1D.h b/GPU/TPCFastTransformation/Spline1D.h index 772231386d112..eb0c06b63a0f2 100644 --- a/GPU/TPCFastTransformation/Spline1D.h +++ b/GPU/TPCFastTransformation/Spline1D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline1DHelper.cxx b/GPU/TPCFastTransformation/Spline1DHelper.cxx index ac0998fe9529c..26e75584c6892 100644 --- a/GPU/TPCFastTransformation/Spline1DHelper.cxx +++ b/GPU/TPCFastTransformation/Spline1DHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -501,7 +502,7 @@ int Spline1DHelper<DataT>::test(const bool draw, const bool drawDataPoints) double cosx[Fdegree + 1], sinx[Fdegree + 1]; double xi = 0; for (int i = 0; i <= Fdegree; i++, xi += x) { - GPUCommonMath::SinCos(xi, sinx[i], cosx[i]); + GPUCommonMath::SinCosd(xi, sinx[i], cosx[i]); } for (int dim = 0; dim < Ndim; dim++) { f[dim] = 0; // Fcoeff[0]/2; diff --git a/GPU/TPCFastTransformation/Spline1DHelper.h b/GPU/TPCFastTransformation/Spline1DHelper.h index 07dcc8827597e..f980ebbbd2167 100644 --- a/GPU/TPCFastTransformation/Spline1DHelper.h +++ b/GPU/TPCFastTransformation/Spline1DHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline1DSpec.cxx b/GPU/TPCFastTransformation/Spline1DSpec.cxx index 002e9cd173940..9e995552d6122 100644 --- a/GPU/TPCFastTransformation/Spline1DSpec.cxx +++ b/GPU/TPCFastTransformation/Spline1DSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline1DSpec.h b/GPU/TPCFastTransformation/Spline1DSpec.h index 9b7a3357fd0e6..47e4806515651 100644 --- a/GPU/TPCFastTransformation/Spline1DSpec.h +++ b/GPU/TPCFastTransformation/Spline1DSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline2D.cxx b/GPU/TPCFastTransformation/Spline2D.cxx index 08f832b408a55..3055bcaccbbc1 100644 --- a/GPU/TPCFastTransformation/Spline2D.cxx +++ b/GPU/TPCFastTransformation/Spline2D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline2D.h b/GPU/TPCFastTransformation/Spline2D.h index f4dfe34c7b2fc..2fb25bc29df54 100644 --- a/GPU/TPCFastTransformation/Spline2D.h +++ b/GPU/TPCFastTransformation/Spline2D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline2DHelper.cxx b/GPU/TPCFastTransformation/Spline2DHelper.cxx index 0833b9e0a3be9..6145507a7eeb2 100644 --- a/GPU/TPCFastTransformation/Spline2DHelper.cxx +++ b/GPU/TPCFastTransformation/Spline2DHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -245,8 +246,8 @@ int Spline2DHelper<DataT>::test(const bool draw, const bool drawDataPoints) double cosu[Fdegree + 1], sinu[Fdegree + 1], cosv[Fdegree + 1], sinv[Fdegree + 1]; double ui = 0, vi = 0; for (int i = 0; i <= Fdegree; i++, ui += uu, vi += vv) { - GPUCommonMath::SinCos(ui, sinu[i], cosu[i]); - GPUCommonMath::SinCos(vi, sinv[i], cosv[i]); + GPUCommonMath::SinCosd(ui, sinu[i], cosu[i]); + GPUCommonMath::SinCosd(vi, sinv[i], cosv[i]); } for (int dim = 0; dim < Ndim; dim++) { double f = 0; // Fcoeff[dim][0]/2; diff --git a/GPU/TPCFastTransformation/Spline2DHelper.h b/GPU/TPCFastTransformation/Spline2DHelper.h index 76f11bf8cc709..d612dc36dce2a 100644 --- a/GPU/TPCFastTransformation/Spline2DHelper.h +++ b/GPU/TPCFastTransformation/Spline2DHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline2DSpec.cxx b/GPU/TPCFastTransformation/Spline2DSpec.cxx index 7e96f73e6b254..5671e6cb2c5ae 100644 --- a/GPU/TPCFastTransformation/Spline2DSpec.cxx +++ b/GPU/TPCFastTransformation/Spline2DSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/Spline2DSpec.h b/GPU/TPCFastTransformation/Spline2DSpec.h index 68c8518dc81b6..80881bb3c907e 100644 --- a/GPU/TPCFastTransformation/Spline2DSpec.h +++ b/GPU/TPCFastTransformation/Spline2DSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/SplineHelper.cxx b/GPU/TPCFastTransformation/SplineHelper.cxx index 2cba30b391468..2398c781f6433 100644 --- a/GPU/TPCFastTransformation/SplineHelper.cxx +++ b/GPU/TPCFastTransformation/SplineHelper.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -135,7 +136,7 @@ void SplineHelper<DataT>::approximateFunction( //std::vector<DataT> dataPointF(getNumberOfDataPoints() * mFdimensions); //DUMYY VERSION Commented out /* for (int i = 0; i < getNumberOfDataPoints() * mFdimensions; i++) { - dataPointF[i] = 1.; + dataPointF[i] = 1.; } */ /* double scaleX1 = (x1Max - x1Min) / ((double)mHelperU1.getSpline().getUmax()); @@ -155,20 +156,60 @@ void SplineHelper<DataT>::approximateFunction( template <typename DataT> void SplineHelper<DataT>::approximateFunctionBatch( DataT* Fparameters, const double xMin[], const double xMax[], - std::function<void(const std::vector<double> x[], std::vector<double> f[/*mFdimensions*/])> F, + std::function<void(const std::vector<double> x[], double f[/*mFdimensions*/])> F, unsigned int batchsize) const { /// Create best-fit spline parameters for a given input function F. /// F calculates values for a batch of points. /// output in Fparameters - // TODO: implement later + double scaleX[mXdimensions]; + for (int i = 0; i < mXdimensions; i++) { + scaleX[i] = (xMax[i] - xMin[i]) / ((double)(mHelpers[i].getSpline().getUmax())); + } + + const int nrOfAllPoints = getNumberOfDataPoints(); + std::vector<double> dataPointF(nrOfAllPoints * mFdimensions); + + int nrOfPoints[mXdimensions]; + for (int i = 0; i < mXdimensions; i++) { + nrOfPoints[i] = mHelpers[i].getNumberOfDataPoints(); + } - std::vector<double> dataPointF(getNumberOfDataPoints() * mFdimensions); - for (int i = 0; i < getNumberOfDataPoints() * mFdimensions; i++) { - dataPointF[i] = 0.; + std::vector<double> x[mXdimensions]; + for (unsigned int iDim = 0; iDim < mXdimensions; ++iDim) { + x[iDim].reserve(batchsize); } + int ibatch = 0; + int index = 0; + for (int d = 0; d < nrOfAllPoints; d++) { // for all DataPoints + int indices[mXdimensions]; + int modoperand = 1; + int divisor = 1; + + // get the DataPoint index + for (int i = 0; i < mXdimensions; i++) { + modoperand *= nrOfPoints[i]; + indices[i] = (int)((d % modoperand) / divisor); + divisor *= nrOfPoints[i]; + // get the respecting u-values: + x[i].emplace_back(xMin[i] + mHelpers[i].getDataPoint(indices[i]).u * scaleX[i]); + } + ++ibatch; + + if (ibatch == batchsize || d == nrOfAllPoints - 1) { + ibatch = 0; + + F(x, &dataPointF[index]); + index = (d + 1) * mFdimensions; + + for (unsigned int iDim = 0; iDim < mXdimensions; ++iDim) { + x[iDim].clear(); + } + } + } // end for all DataPoints d + approximateFunction(Fparameters, dataPointF.data()); } @@ -351,8 +392,9 @@ void SplineHelper<DataT>::approximateFunction( } // get the knotindexvalue for FParameters: int knotind = pointstoarray(knotindices, numberOfKnots, mXdimensions); - for (int f = 0; f < mFdimensions; f++) + for (int f = 0; f < mFdimensions; f++) { Fparameters[knotind * numberOfParameterTypes * mFdimensions + p * mFdimensions + f] = par[dimension][2 * i * mFdimensions + mFdimensions + f]; ///write derivatives in FParameters + } } } // end for all fknots (for redistribution) @@ -481,11 +523,9 @@ int SplineHelper<DataT>::test(const bool draw, const bool drawDataPoints) Spline<float, nDimX, nDimY> spline(nKnots, knotsU); Spline2D<float, nDimY> spline2D(nKnots[0], knotsU[0], nKnots[1], knotsU[1]); - cout << "mark 1" << std::endl; spline.approximateFunction(xMin, xMax, F, nAxiliaryDatapoints); spline2D.approximateFunction(xMin[0], xMax[0], xMin[1], xMax[1], F2D, nAxiliaryDatapoints[0], nAxiliaryDatapoints[0]); - cout << "mark 2" << std::endl; long double statDf = 0; long double statDf2D = 0; diff --git a/GPU/TPCFastTransformation/SplineHelper.h b/GPU/TPCFastTransformation/SplineHelper.h index fce2ef1aa12e9..9d93df5a153e0 100644 --- a/GPU/TPCFastTransformation/SplineHelper.h +++ b/GPU/TPCFastTransformation/SplineHelper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -74,7 +75,7 @@ class SplineHelper /// approximate std::function, output in Fparameters. F calculates values for a batch of points. void approximateFunctionBatch( DataT* Fparameters, const double xMin[/* mXdimensions */], const double xMax[/* mXdimensions */], - std::function<void(const std::vector<double> x[/* mXdimensions */], std::vector<double> f[/*mFdimensions*/])> F, + std::function<void(const std::vector<double> x[/* mXdimensions */], double f[/*mFdimensions*/])> F, unsigned int batchsize) const; /// approximate a function given as an array of values at data points diff --git a/GPU/TPCFastTransformation/SplineSpec.cxx b/GPU/TPCFastTransformation/SplineSpec.cxx index 35beb0d3c8417..85239788526b9 100644 --- a/GPU/TPCFastTransformation/SplineSpec.cxx +++ b/GPU/TPCFastTransformation/SplineSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/SplineSpec.h b/GPU/TPCFastTransformation/SplineSpec.h index 6217415dd7c74..b81e2ba4f5191 100644 --- a/GPU/TPCFastTransformation/SplineSpec.h +++ b/GPU/TPCFastTransformation/SplineSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -327,31 +328,28 @@ class SplineSpec<DataT, XdimT, YdimT, 0> : public SplineContainer<DataT> DataT S1[maxInterpolations]; DataT D1[maxInterpolations]; - int nrofInterpolations = (1 << (2 * nXdim - 2)) * nYdim; - int nrofKnots = 1 << (nXdim); + int nInterpolations = (1 << (2 * nXdim - 2)) * nYdim; + int nKnots = 1 << (nXdim); for (int d = 0; d < nXdim; d++) { //for every dimension DataT* pointer[4] = {S0, D0, S1, D1}; // pointers for interpolation arrays S0, D0, S1, D1 point to Arraystart - for (int i = 0; i < nrofKnots; i++) { //for every knot - for (int j = 0; j < nrofKnots; j++) { // for every parametertype + for (int i = 0; i < nKnots; i++) { //for every knot + for (int j = 0; j < nKnots; j++) { // for every parametertype int pointernr = 2 * (i % 2) + (j % 2); //to which array should it be delivered for (int k = 0; k < nYdim; k++) { - pointer[pointernr][0] = iParameters[(i * nrofKnots + j) * nYdim + k]; + pointer[pointernr][0] = iParameters[(i * nKnots + j) * nYdim + k]; pointer[pointernr]++; } } // end for j (every parametertype) } // end for i (every knot) const typename Spline1D<DataT>::Knot& knotL = mGrid[d].getKnot(indices[d]); - int Ydim = nrofInterpolations; DataT coordinate = u[d]; - - typedef Spline1DSpec<DataT, YdimT, 0> TGridX; + typedef Spline1DSpec<DataT, 0, 0> TGridX; const TGridX& gridX = *((const TGridX*)&(mGrid[d])); - gridX.interpolateU(Ydim, knotL, S0, D0, S1, D1, coordinate, iParameters); - - nrofInterpolations = nrofInterpolations / 4; - nrofKnots = nrofKnots / 2; + gridX.interpolateU(nInterpolations, knotL, S0, D0, S1, D1, coordinate, iParameters); + nInterpolations /= 4; + nKnots /= 2; } //end d (every dimension) for (int i = 0; i < nYdim; i++) { diff --git a/GPU/TPCFastTransformation/SplineUtil.h b/GPU/TPCFastTransformation/SplineUtil.h index 0ca3d738f46c7..c4c695c2b3636 100644 --- a/GPU/TPCFastTransformation/SplineUtil.h +++ b/GPU/TPCFastTransformation/SplineUtil.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,6 +39,9 @@ class SplineUtil // 2 - at least one of the dimensions must be set during runtime // 3 - specialization where nYdim==1 (a small add-on on top of the other specs) + // calculate it as one return statement to make the AliRoot compiler happy + return (nYdim == 1) ? 3 : ((nXdim > 0 && nYdim > 0) ? 1 : 2); + /* if (nYdim == 1) { return 3; } @@ -46,6 +50,7 @@ class SplineUtil } else { return 2; } + */ } /// Spline1D & Spline2D specialization number depending on nYdim diff --git a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx index aed967c972429..e806e3888d4c6 100644 --- a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx +++ b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h index b78e5f233c703..351046a104009 100644 --- a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h +++ b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransform.cxx b/GPU/TPCFastTransformation/TPCFastTransform.cxx index 67466abe5b93f..58422a171c91c 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransform.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index 26df87075060e..536698cc2c579 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx b/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx index d8fdf6b73aa0f..93cab6bd6e045 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformGeo.h b/GPU/TPCFastTransformation/TPCFastTransformGeo.h index c8676c61751b1..1eef097175cb2 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformGeo.h +++ b/GPU/TPCFastTransformation/TPCFastTransformGeo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformManager.cxx b/GPU/TPCFastTransformation/TPCFastTransformManager.cxx index 4fbc08c2e8ba1..e5a858f1497f9 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformManager.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransformManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformManager.h b/GPU/TPCFastTransformation/TPCFastTransformManager.h index e3b4c5ac03297..e13ca67b9a05e 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformManager.h +++ b/GPU/TPCFastTransformation/TPCFastTransformManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformQA.cxx b/GPU/TPCFastTransformation/TPCFastTransformQA.cxx index dd52015c19aaa..3616ff83e036d 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformQA.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransformQA.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformQA.h b/GPU/TPCFastTransformation/TPCFastTransformQA.h index a792c6ea22d48..d1938b8fa587e 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformQA.h +++ b/GPU/TPCFastTransformation/TPCFastTransformQA.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_AliRoot.h b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_AliRoot.h index d64a7fc0f8fd7..8fc2d6bfb88d7 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_AliRoot.h +++ b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_AliRoot.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h index 4db934adfbfad..c072a5201ad56 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h +++ b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/alirootMacro/generateTPCDistortionNTupleAliRoot.C b/GPU/TPCFastTransformation/alirootMacro/generateTPCDistortionNTupleAliRoot.C index fead77bfb4e48..91bb546e7d57e 100644 --- a/GPU/TPCFastTransformation/alirootMacro/generateTPCDistortionNTupleAliRoot.C +++ b/GPU/TPCFastTransformation/alirootMacro/generateTPCDistortionNTupleAliRoot.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline1D.cxx b/GPU/TPCFastTransformation/devtools/IrregularSpline1D.cxx index 7c4deefd01f3f..84156b53c8f78 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline1D.cxx +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline1D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline1D.h b/GPU/TPCFastTransformation/devtools/IrregularSpline1D.h index 5b2c1e37872ba..9c1b30110238f 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline1D.h +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline1D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.cxx b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.cxx index af9162be207ce..d7d9530c7b41f 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.cxx +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.h b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.h index 7fc312bfc7bcd..9ecfec886753c 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.h +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.cxx b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.cxx index a21b7119c95e1..9d7756a971d7f 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.cxx +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.h b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.h index ee63e719c63a4..5dfceceb2df99 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.h +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibrator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibratorTest.C b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibratorTest.C index 94d70dbc9ee41..a46c3522b9d86 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibratorTest.C +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DCalibratorTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DTest.C b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DTest.C index c2e002bd4a7b2..04906797c1b7f 100644 --- a/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DTest.C +++ b/GPU/TPCFastTransformation/devtools/IrregularSpline2D3DTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/RegularSpline1D.h b/GPU/TPCFastTransformation/devtools/RegularSpline1D.h index 8d2fa51440b1d..10540b84bdabc 100644 --- a/GPU/TPCFastTransformation/devtools/RegularSpline1D.h +++ b/GPU/TPCFastTransformation/devtools/RegularSpline1D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/RegularSpline1DTest.C b/GPU/TPCFastTransformation/devtools/RegularSpline1DTest.C index ad772dba8086e..fb96b4e2f5dca 100644 --- a/GPU/TPCFastTransformation/devtools/RegularSpline1DTest.C +++ b/GPU/TPCFastTransformation/devtools/RegularSpline1DTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.cxx b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.cxx index ff87f28b9bd26..5abd6c4beedaf 100644 --- a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.cxx +++ b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.h b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.h index be03655206c6b..f2e0f4b3fe80e 100644 --- a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.h +++ b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3D.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -287,7 +288,6 @@ inline void SemiregularSpline2D3D::correctEdges(T* data) const } { // ==== high edge of V ==== - const RegularSpline1D& gridU = getGridU(nv - 4); int nu = getGridU(nv - 1).getNumberOfKnots(); for (int iu = 0; iu < nu; iu++) { diff --git a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3DTest.C b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3DTest.C index 423c9658746f7..a84198859bc15 100644 --- a/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3DTest.C +++ b/GPU/TPCFastTransformation/devtools/SemiregularSpline2D3DTest.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C b/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C index 9dfd2a4d271fe..214235217d652 100644 --- a/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C +++ b/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,17 +25,22 @@ #include "TH3.h" #include "DataFormatsTPC/Defs.h" -#include "TPCSimulation/SpaceCharge.h" #include "GPU/TPCFastTransform.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "TPCSpaceCharge/SpaceCharge.h" #endif -o2::tpc::SpaceCharge* sc = 0; +// define number of bins in r, rphi, z for the lookup tables +// o2::tpc::SpaceCharge<double, nZ, nR, nPhi> +// for valid values see the definitions in TPCSpacechargeLinkDef.h +using SC = o2::tpc::SpaceCharge<double>; +SC* sc = nullptr; + using namespace o2::tpc; using namespace o2::gpu; -void generateTPCCorrectionNTuple() +void generateTPCCorrectionNTuple(const char* path = "InputSCDensityHistograms.root", const char* histoName = "inputSCDensity3D8") { // open file with space-charge density histograms // location: alien:///alice/cern.ch/user/e/ehellbar/TPCSpaceCharge/RUN3/ SCDensityHistograms/InputSCDensityHistograms.root @@ -43,35 +49,30 @@ void generateTPCCorrectionNTuple() // - nPileUpEvents = 0,2,4,6,8,10,12 // - number of events (in units of 1000) contributing to the ion density. 0 = 130000 events, 2 = 2000 events, 4 = 4000 events, etc. // - expected default map with 8000 pileup events: inputSCDensity3D8 - auto mFileSCDensity = std::unique_ptr<TFile>(TFile::Open("InputSCDensityHistograms.root")); + auto mFileSCDensity = std::unique_ptr<TFile>(TFile::Open(path)); if (!mFileSCDensity || !mFileSCDensity->IsOpen()) { std::cout << " input file does not exist!" << std::endl; return; } // get the histogram with the sc density - std::unique_ptr<TH3> mHisSCDensity3D = std::unique_ptr<TH3>((TH3*)mFileSCDensity->Get("inputSCDensity3D8")); + std::unique_ptr<TH3> mHisSCDensity3D = std::unique_ptr<TH3>((TH3*)mFileSCDensity->Get(histoName)); if (!mHisSCDensity3D) { - std::cout << "inputSCDensity3D8 histogramm does not exist!" << std::endl; + std::cout << Form("%s histogramm does not exist!", histoName) << std::endl; return; } - // define number of bins in r, rphi, z for the lookup tables - // nR annd nZ have to be 2^n + 1, nPhi is arbitrary - // expected default for desired precision: 129, 129, 144 (takes a lot of time, you can also us 65 in r and z) - int mNRRows = 129; - int mNZCols = 129; - int mNPhiSlices = 180; - // create space-charge object - sc = new o2::tpc::SpaceCharge(mNRRows, mNPhiSlices, mNZCols); - sc->setInitialSpaceChargeDensity((TH3*)mHisSCDensity3D.get()); + sc = new SC; + sc->setGlobalDistType(SC::GlobalDistType::None); + sc->fillChargeDensityFromHisto(*mHisSCDensity3D.get()); // select constant distortions (over time), realistic distortions changing in time not yet pushed to official code - sc->setSCDistortionType(o2::tpc::SpaceCharge::SCDistortionType::SCDistortionsConstant); + sc->setSCDistortionType(SC::SCDistortionType::SCDistortionsConstant); // gas parameters nor Ne-CO2-N2 90-10-5 sc->setOmegaTauT1T2(0.32, 1, 1); // start calculation of lookup tables (takes some time) - sc->calculateLookupTables(); + sc->calculateDistortionsCorrections(Side::A); + sc->calculateDistortionsCorrections(Side::C); // create TPC transformation to get the TPC geometry diff --git a/GPU/TPCFastTransformation/test/testSplines.cxx b/GPU/TPCFastTransformation/test/testSplines.cxx index 306cfc1099542..ab15cd4594551 100644 --- a/GPU/TPCFastTransformation/test/testSplines.cxx +++ b/GPU/TPCFastTransformation/test/testSplines.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.cxx b/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.cxx deleted file mode 100644 index 9fbfa42db6491..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.cxx +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPC3DCylindricalInterpolator.cxx -/// \brief Interpolator for cylindrical coordinate -/// this class provides: cubic spline, quadratic and linear interpolation -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Jan 5, 2016 - -#include "TMath.h" -#include "AliTPC3DCylindricalInterpolator.h" - -/// \cond CLASSIMP -ClassImp(AliTPC3DCylindricalInterpolator); -/// \endcond - -/// constructor -/// -AliTPC3DCylindricalInterpolator::AliTPC3DCylindricalInterpolator() -{ - fOrder = 1; - fIsAllocatingLookUp = kFALSE; - fIsInitCubic = kFALSE; -} - -/// destructor -/// -AliTPC3DCylindricalInterpolator::~AliTPC3DCylindricalInterpolator() -{ - delete fValue; - delete fRList; - delete fPhiList; - delete fZList; - if (fIsInitCubic) { - delete fSecondDerZ; - } -} - -/// Get interpolation value on a point in a cylindrical volume -/// -/// \param r position r -/// \param phi position $\phi$ -/// \param z position z -/// -/// \return interpolation value -Double_t AliTPC3DCylindricalInterpolator::GetValue(Double_t r, Double_t phi, Double_t z) const -{ - return InterpolateCylindrical(r, z, phi); -} - -/// Get interpolation value on a point in a cylindrical volume -/// -/// \param r Double_t position r -/// \param phi Double_t position $\phi$ -/// \param z Double_t position z -/// -/// \return interpolation value -Double_t AliTPC3DCylindricalInterpolator::InterpolateCylindrical(Double_t r, Double_t z, Double_t phi) const -{ - Int_t iLow = 0, jLow = 0, m = 0; - Int_t kLow = 0; - Int_t index; - - // tri cubic points - Double_t saveArray[fOrder + 1]; - Double_t savedArray[fOrder + 1]; - Double_t zListM1[fOrder + 1]; - Double_t valueM1[fOrder + 1]; - - Bool_t neg = kFALSE; - - // check phi - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - // search lowest index related to r,z and phi - Search(fNR, fRList, r, iLow); - Search(fNZ, fZList, z, jLow); - Search(fNPhi, fPhiList, phi, kLow); - - // order >= 3 - kLow -= (fOrder / 2); - iLow -= (fOrder / 2); - jLow -= (fOrder / 2); - - // check if out of range - if (iLow < 0) { - iLow = 0; - } - if (jLow < 0) { - jLow = 0; - } - if (kLow < 0) { - kLow = fNPhi + kLow; - } - // check if out of range - if (iLow + fOrder >= fNR - 1) { - iLow = fNR - 1 - fOrder; - } - if (jLow + fOrder >= fNZ - 1) { - jLow = fNZ - 1 - fOrder; - } - - // do for each - for (Int_t k = 0; k < fOrder + 1; k++) { - m = (kLow + k) % fNPhi; - // interpolate - for (Int_t i = iLow; i < iLow + fOrder + 1; i++) { - if (fOrder < 3) { - if (jLow >= 0) { - index = m * (fNZ * fNR) + i * (fNZ) + jLow; - saveArray[i - iLow] = Interpolate(&fZList[jLow], &fValue[index], z); - } else { - index = m * (fNZ * fNR) + i * (fNZ); - zListM1[0] = fZList[0] - (fZList[1] - fZList[0]); - zListM1[1] = fZList[0]; - zListM1[2] = fZList[1]; - valueM1[0] = fValue[index] - (fValue[index + 1] - fValue[index]); - valueM1[1] = fValue[index]; - valueM1[2] = fValue[index + 1]; - saveArray[i - iLow] = Interpolate(&zListM1[0], &valueM1[0], z); - } - - } else { - index = m * (fNZ * fNR) + i * (fNZ); - saveArray[i - iLow] = InterpolateCubicSpline(fZList, &fValue[index], &fSecondDerZ[index], fNZ, fNZ, fNZ, - z, 1); - } - } - savedArray[k] = Interpolate(&fRList[iLow], saveArray, r); - } - return (InterpolatePhi(&fPhiList[0], kLow, fNPhi, savedArray, phi)); -} - -/// Get interpolation for 1 dimension non cyclic -/// -/// \param xArray Double_t[] known position x -/// \param yArray Double_t[] known y = f(x) -/// \param x unknown position -/// -/// \return interpolation value f(x) -Double_t AliTPC3DCylindricalInterpolator::Interpolate(Double_t xArray[], Double_t yArray[], Double_t x) const -{ - Double_t y; - - // if cubic spline - if (fOrder > 2) { - Double_t y2Array[fOrder + 1]; - InitCubicSpline(xArray, yArray, fOrder + 1, y2Array, 1); - y = InterpolateCubicSpline(xArray, yArray, y2Array, fOrder + 1, fOrder + 1, fOrder + 1, x, 1); - } else if (fOrder == 2) { - // Quadratic Interpolation = 2 - y = (x - xArray[1]) * (x - xArray[2]) * yArray[0] / ((xArray[0] - xArray[1]) * (xArray[0] - xArray[2])); - y += (x - xArray[2]) * (x - xArray[0]) * yArray[1] / ((xArray[1] - xArray[2]) * (xArray[1] - xArray[0])); - y += (x - xArray[0]) * (x - xArray[1]) * yArray[2] / ((xArray[2] - xArray[0]) * (xArray[2] - xArray[1])); - } else { - // Linear Interpolation = 1 - y = yArray[0] + (yArray[1] - yArray[0]) * (x - xArray[0]) / (xArray[1] - xArray[0]); - } - return (y); -} - -/// Get interpolation for 1 dimension cyclic -/// -/// \param xArray Double_t[] known position x -/// \param yArray Double_t[] known y = f(x) -/// \param x unknown position -/// -/// \return interpolation value f(x) -Double_t AliTPC3DCylindricalInterpolator::InterpolatePhi( - Double_t xArray[], const Int_t iLow, const Int_t lenX, Double_t yArray[], Double_t x) const -{ - Int_t i0 = iLow; - Double_t xi0 = xArray[iLow]; - Int_t i1 = (iLow + 1) % lenX; - Double_t xi1 = xArray[i1]; - Int_t i2 = (iLow + 2) % lenX; - Double_t xi2 = xArray[i2]; - - if (fOrder <= 2) { - if (xi1 < xi0) { - xi1 = TMath::TwoPi() + xi1; - } - if (xi2 < xi1) { - xi2 = TMath::TwoPi() + xi2; - } - if (x < xi0) { - x = TMath::TwoPi() + x; - } - } - - Double_t y; - if (fOrder > 2) { - Double_t y2Array[fOrder + 1]; - Double_t xArrayTemp[fOrder + 1]; - Double_t dPhi = xArray[1] - xArray[0]; - // make list phi ascending order - for (Int_t i = 0; i < fOrder + 1; i++) { - xArrayTemp[i] = xArray[iLow] + (dPhi * i); - } - if (x < xArrayTemp[0]) { - x = TMath::TwoPi() + x; - } - if (x < xArrayTemp[0] || x > xArrayTemp[fOrder]) { - printf("x (%f) is outside of interpolation box (%f,%f)\n", x, xArrayTemp[0], xArrayTemp[fOrder]); - } - - InitCubicSpline(xArrayTemp, yArray, fOrder + 1, y2Array, 1); - y = InterpolateCubicSpline(xArrayTemp, yArray, y2Array, fOrder + 1, fOrder + 1, fOrder + 1, x, 1); - } else if (fOrder == 2) { // Quadratic Interpolation = 2 - y = (x - xi1) * (x - xi2) * yArray[0] / ((xi0 - xi1) * (xi0 - xi2)); - y += (x - xi2) * (x - xi0) * yArray[1] / ((xi1 - xi2) * (xi1 - xi0)); - y += (x - xi0) * (x - xi1) * yArray[2] / ((xi2 - xi0) * (xi2 - xi1)); - } else { // Li2near Interpolation = 1 - y = yArray[0] + (yArray[1] - yArray[0]) * (x - xi0) / (xi1 - xi0); - } - return (y); -} - -/// Solving cubic splines for system of splines -/// -/// \param xArray Double_t[] known position x -/// \param yArray Double_t[] known y = f(x) -/// \param n Int_t length of splines -/// \param y2Array Double_t[] calculated $d^2Y$ spline (output) -/// \param skip memory offset for xArray -/// -void AliTPC3DCylindricalInterpolator::InitCubicSpline(Double_t* xArray, Double_t* yArray, const Int_t n, Double_t* y2Array, - const Int_t skip) const -{ - Double_t u[n]; - Double_t sig, p, qn, un; - - y2Array[0] = 0.0; - u[0] = 0.0; //natural condition - - for (Int_t i = 1; i <= n - 2; i++) { - sig = (xArray[i] - xArray[i - 1]) / (xArray[i + 1] - xArray[i - 1]); - p = sig * y2Array[(i - 1) * skip] + 2.0; - y2Array[i * skip] = (sig - 1.0) / p; - u[i] = (yArray[(i + 1) * skip] - yArray[i * skip]) / (xArray[i + 1] - xArray[i]) - - (yArray[i * skip] - yArray[(i - 1) * skip]) / (xArray[i] - xArray[i - 1]); - u[i] = (6.0 * u[i] / (xArray[i + 1] - xArray[i - 1]) - sig * u[i - 1]) / p; - } - - qn = un = 0.0; - - y2Array[(n - 1) * skip] = (un - qn * u[n - 2]) / (qn * y2Array[(n - 2) * skip] + 1.0); - for (Int_t k = n - 2; k >= 0; k--) { - y2Array[k * skip] = y2Array[k * skip] * y2Array[(k + 1) * skip] + u[k]; - } -} - -/// Solving cubic splines for system of splines -/// -/// \param xArray Double_t[] known position x -/// \param yArray Double_t[] known y = f(x) -/// \param n Int_t length of splines -/// \param y2Array Double_t[] calculated $d^2Y$ spline (output) -/// \param skip memory offset for xArray -/// -void AliTPC3DCylindricalInterpolator::InitCubicSpline(Double_t* xArray, Double_t* yArray, const Int_t n, Double_t* y2Array, - const Int_t skip, Double_t yp0, Double_t ypn1) const -{ - Double_t u[n]; - Double_t sig, p, qn, un; - - y2Array[0] = 0.0; - u[0] = 0.0; //natural condition - - for (Int_t i = 1; i <= n - 2; i++) { - sig = (xArray[i] - xArray[i - 1]) / (xArray[i + 1] - xArray[i - 1]); - p = sig * y2Array[(i - 1) * skip] + 2.0; - y2Array[i * skip] = (sig - 1.0) / p; - u[i] = (yArray[(i + 1) * skip] - yArray[i * skip]) / (xArray[i + 1] - xArray[i]) - - (yArray[i * skip] - yArray[(i - 1) * skip]) / (xArray[i] - xArray[i - 1]); - u[i] = (6.0 * u[i] / (xArray[i + 1] - xArray[i - 1]) - sig * u[i - 1]) / p; - } - - qn = un = 0.0; - y2Array[(n - 1) * skip] = (un - qn * u[n - 2]) / (qn * y2Array[(n - 2) * skip] + 1.0); - for (Int_t k = n - 2; k >= 0; k--) { - y2Array[k * skip] = y2Array[k * skip] * y2Array[(k + 1) * skip] + u[k]; - } -} - -/// Interpolate initialized cubic spline -/// -/// \param xArray -/// \param yArray -/// \param y2Array -/// \param nxArray -/// \param nyArray -/// \param ny2Array -/// \param x -/// \param skip -/// \return -Double_t AliTPC3DCylindricalInterpolator::InterpolateCubicSpline(Double_t* xArray, Double_t* yArray, Double_t* y2Array, - const Int_t nxArray, const Int_t nyArray, - const Int_t ny2Array, Double_t x, Int_t skip) const -{ - Int_t klo, khi, k; - Float_t h, b, a; - klo = 0; - khi = nxArray - 1; - - while (khi - klo > 1) { - k = (khi + klo) >> 1; - if (xArray[k] > x) { - khi = k; - } else { - klo = k; - } - } - - h = xArray[khi] - xArray[klo]; - - if (TMath::Abs(h) < 1e-10) { - return 0.0; - } - - a = (xArray[khi] - x) / h; - b = (x - xArray[klo]) / h; - - Double_t y = a * yArray[klo] + b * yArray[khi] + - ((a * a * a - a) * y2Array[klo * skip] + (b * b * b - b) * y2Array[khi * skip]) * (h * h) / 6.0; - - return y; -} - -/// init cubic spline for all -/// -void AliTPC3DCylindricalInterpolator::InitCubicSpline() -{ - - Double_t yp0, ypn1; - if (fIsInitCubic != kTRUE) { - fSecondDerZ = new Double_t[fNR * fNZ * fNPhi]; - - // Init at Z direction - for (Int_t m = 0; m < fNPhi; m++) { - for (Int_t i = 0; i < fNR; i++) { - yp0 = (-(11.0 / 6.0) * fValue[(m * (fNZ * fNR) + i * fNZ)] + - (3.0 * fValue[(m * (fNZ * fNR) + i * fNZ) + 1]) - - (1.5 * fValue[(m * (fNZ * fNR) + i * fNZ) + 2]) + - ((1.0 / 3.0) * fValue[(m * (fNZ * fNR) + i * fNZ) + 4])) / - (fZList[1] - fZList[0]); - ypn1 = (-(11.0 / 6.0) * fValue[(m * (fNZ * fNR) + i * fNZ) + (fNZ - 1)] + - (3.0 * fValue[(m * (fNZ * fNR) + i * fNZ) + (fNZ - 2)]) - - (1.5 * fValue[(m * (fNZ * fNR) + i * fNZ) + (fNZ - 3)]) + - ((1.0 / 3.0) * fValue[(m * (fNZ * fNR) + i * fNZ) + (fNZ - 4)])) / - (fZList[0] - fZList[1]); - InitCubicSpline(fZList, &fValue[m * (fNZ * fNR) + i * fNZ], fNZ, - &fSecondDerZ[m * (fNZ * fNR) + i * fNZ], 1); - } - } - - fIsInitCubic = kTRUE; - } -} - -/// Search the nearest grid index position to a Point -/// -/// \param n -/// \param xArray -/// \param x -/// \param low -void AliTPC3DCylindricalInterpolator::Search(Int_t n, const Double_t xArray[], Double_t x, Int_t& low) const -{ - /// Search an ordered table by starting at the most recently used point - - Long_t middle, high; - Int_t ascend = 0, increment = 1; - - if (xArray[n - 1] > xArray[0]) { - ascend = 1; // Ascending ordered table if true - } - if (low < 0 || low > n - 1) { - low = -1; - high = n; - } else { // Ordered Search phase - if ((Int_t)(x > xArray[low]) == ascend) { - if (low == n - 1) { - return; - } - high = low + 1; - while ((Int_t)(x > xArray[high]) == ascend) { - low = high; - increment *= 2; - high = low + increment; - if (high > n - 1) { - high = n; - break; - } - } - } else { - if (low == 0) { - low = -1; - return; - } - high = low - 1; - while ((Int_t)(x < xArray[low]) == ascend) { - high = low; - increment *= 2; - if (increment >= high) { - low = -1; - break; - } else { - low = high - increment; - } - } - } - } - - while ((high - low) != 1) { // Binary Search Phase - middle = (high + low) / 2; - if ((Int_t)(x > xArray[middle]) == ascend) { - low = middle; - } else { - high = middle; - } - } - - if (x > xArray[n - 1]) { - low = n; - } - if (x < xArray[0]) { - low = -1; - } -} - -/// Set the value as interpolation point -/// -/// \param matricesVal TMatrixD** reference value for each point -void AliTPC3DCylindricalInterpolator::SetValue(TMatrixD** matricesVal) -{ - Int_t indexVal1D; - Int_t index1D; - if (!fIsAllocatingLookUp) { - fValue = new Double_t[fNPhi * fNR * fNZ]; - fIsAllocatingLookUp = kTRUE; - } - for (Int_t m = 0; m < fNPhi; m++) { - indexVal1D = m * fNR * fNZ; - TMatrixD* mat = matricesVal[m]; - for (Int_t i = 0; i < fNR; i++) { - index1D = indexVal1D + i * fNZ; - for (Int_t j = 0; j < fNZ; j++) { - fValue[index1D + j] = (*mat)(i, j); - } - } - } -} - -/// Set the value as interpolation point -/// -/// \param matricesVal TMatrixD** reference value for each point -void AliTPC3DCylindricalInterpolator::SetValue(TMatrixD** matricesVal, Int_t iZ) -{ - Int_t indexVal1D; - Int_t index1D; - if (!fIsAllocatingLookUp) { - fValue = new Double_t[fNPhi * fNR * fNZ]; - fIsAllocatingLookUp = kTRUE; - } - for (Int_t m = 0; m < fNPhi; m++) { - indexVal1D = m * fNR * fNZ; - TMatrixD* mat = matricesVal[m]; - for (Int_t i = 0; i < fNR; i++) { - index1D = indexVal1D + i * fNZ; - fValue[index1D + iZ] = (*mat)(i, iZ); - } - } -} - -/// set the position of R -/// -/// \param rList -void AliTPC3DCylindricalInterpolator::SetRList(Double_t* rList) -{ - fRList = new Double_t[fNR]; - for (Int_t i = 0; i < fNR; i++) { - fRList[i] = rList[i]; - } -} - -/// set the position of phi -/// -/// \param phiList -void AliTPC3DCylindricalInterpolator::SetPhiList(Double_t* phiList) -{ - fPhiList = new Double_t[fNPhi]; - for (Int_t i = 0; i < fNPhi; i++) { - fPhiList[i] = phiList[i]; - } -} - -/// Setting z position -/// -/// \param zList -void AliTPC3DCylindricalInterpolator::SetZList(Double_t* zList) -{ - fZList = new Double_t[fNZ]; - for (Int_t i = 0; i < fNZ; i++) { - fZList[i] = zList[i]; - } -} - -/// Setting values from 1D -/// -/// \param valueList -void AliTPC3DCylindricalInterpolator::SetValue(Double_t* valueList) { fValue = valueList; } - -/// Set number of total grid points -void AliTPC3DCylindricalInterpolator::SetNGridPoints() -{ - if (fNR == 0 || fNPhi == 0 || fNZ == 0) { - Error("AliTPC3DCylindricalInterpolator::SetNGridPoints", "Error in calculating total number of grid points! Either nR, nPhi or nZ are zero!"); - } - fNGridPoints = fNR * fNPhi * fNZ; -} \ No newline at end of file diff --git a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.h b/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.h deleted file mode 100644 index 67e01e640dbd4..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolator.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPC3DCylindricalInterpolator.h -/// \brief Interpolator for cylindrical coordinate -/// this class provides: cubic spline, quadratic and linear interpolation -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Jan 5, 2016 - -#ifndef AliTPC3DCylindricalInterpolator_H -#define AliTPC3DCylindricalInterpolator_H - -#include <TMatrixD.h> - -class AliTPC3DCylindricalInterpolator -{ - public: - AliTPC3DCylindricalInterpolator(); - ~AliTPC3DCylindricalInterpolator(); - Double_t GetValue(Double_t r, Double_t phi, Double_t z) const; - void InitCubicSpline(); - void SetOrder(Int_t order) { fOrder = order; } - void SetNR(Int_t nR) { fNR = nR; } - void SetNPhi(Int_t nPhi) { fNPhi = nPhi; } - void SetNZ(Int_t nZ) { fNZ = nZ; } - void SetNGridPoints(); - void SetRList(Double_t* rList); - void SetPhiList(Double_t* phiList); - void SetZList(Double_t* zList); - void SetValue(Double_t* vList); - void SetValue(TMatrixD** vList); - void SetValue(TMatrixD** vList, Int_t iZ); - - Int_t GetNR() { return fNR; } - Int_t GetNPhi() { return fNPhi; } - Int_t GetNZ() { return fNZ; } - Int_t GetOrder() { return fOrder; } - - Double_t* GetSecondDerZ() { return fSecondDerZ; } - - private: - Int_t fOrder; ///< Order of interpolation, 1 - linear, 2 - quadratic, 3 >= - cubic, - Int_t fNR; ///< Grid size in direction of R - Int_t fNPhi; ///< Grid size in direction of Phi - Int_t fNZ; ///< Grid size in direction of Z - Int_t fNGridPoints; ///< Total number of grid points (needed for streamer) - - Double_t* fValue = nullptr; //[fNGridPoints] Description 3D for storing known values interpolation should be in size fNR*fNPhi*fNZ - Double_t* fRList = nullptr; //[fNR] coordinate in R (cm) (should be increasing) - Double_t* fPhiList = nullptr; //[fNPhi] coordinate in phiList (rad) (should be increasing) 0 <= < 2 pi (cyclic) - Double_t* fZList = nullptr; //[fNZ] coordinate in z list (cm) (should be increasing) - Double_t* fSecondDerZ = nullptr; //[fNGridPoints] store second derivative of cubic interpolation in z direction - - Bool_t fIsAllocatingLookUp; ///< is allocating memory - Bool_t fIsInitCubic; ///< is cubic second derivative already been initialized - - Double_t InterpolatePhi(Double_t xArray[], const Int_t iLow, const Int_t lenX, Double_t yArray[], Double_t x) const; - Double_t InterpolateCylindrical(Double_t r, Double_t z, Double_t phi) const; - Double_t Interpolate(Double_t xArray[], Double_t yArray[], Double_t x) const; - Double_t InterpolateCubicSpline(Double_t* xArray, Double_t* yArray, Double_t* y2Array, const Int_t nxArray, - const Int_t nyArray, const Int_t ny2Array, Double_t x, const Int_t skip) const; - void Search(Int_t n, const Double_t xArray[], Double_t x, Int_t& low) const; - void InitCubicSpline(Double_t* xArray, Double_t* yArray, const Int_t n, Double_t* y2Array, const Int_t skip) const; - void InitCubicSpline(Double_t* xArray, Double_t* yArray, const Int_t n, Double_t* y2Array, const Int_t skip, - Double_t yp0, Double_t ypn1) const; - - /// \cond CLASSIMP - ClassDefNV(AliTPC3DCylindricalInterpolator, 1); - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.cxx b/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.cxx deleted file mode 100644 index b4d395ceadbaa..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.cxx +++ /dev/null @@ -1,1514 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPC3DCylindricalInterpolatorIrregular.cxx -/// \brief Irregular grid interpolator for cylindrical coordinate with r,phi,z different coordinates -/// RBF-based interpolation -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Jan 5, 2016 - -#include "TMath.h" -#include "TVector.h" -#include "TVectorD.h" -#include "TMatrix.h" -#include "TMatrixD.h" -#include "TDecompSVD.h" -#include "AliTPCPoissonSolver.h" -#include "AliTPC3DCylindricalInterpolatorIrregular.h" -#include <cstdlib> - -/// \cond CLASSIMP3 -ClassImp(AliTPC3DCylindricalInterpolatorIrregular); -/// \endcond - -/// constructor -/// -/// \param nRRow -/// \param nZColumn -/// \param nPhiSlice -/// \param rStep -/// \param zStep -/// \param phiStep -/// \param type -AliTPC3DCylindricalInterpolatorIrregular::AliTPC3DCylindricalInterpolatorIrregular( - Int_t nRRow, Int_t nZColumn, Int_t nPhiSlice, Int_t rStep, Int_t zStep, Int_t phiStep, Int_t type) -{ - fOrder = 1; - fIsAllocatingLookUp = kFALSE; - fMinZIndex = 0; - fNR = nRRow; - fNZ = nZColumn; - fNPhi = nPhiSlice; - fNGridPoints = nRRow * nZColumn * nPhiSlice; - - fRBFWeightLookUp = new Int_t[nRRow * nZColumn * nPhiSlice]; - - Int_t nd = rStep * zStep * phiStep; - fStepR = rStep; - fStepZ = zStep; - fStepPhi = phiStep; - fNRBFpoints = nRRow * nZColumn * nPhiSlice * nd; - - fType = type; - fRBFWeight = new Double_t[nRRow * nZColumn * nPhiSlice * nd]; - for (Int_t i = 0; i < nRRow * nZColumn * nPhiSlice; i++) { - fRBFWeightLookUp[i] = 0; - } - - SetKernelType(kRBFInverseMultiQuadratic); -} - -/// constructor -/// -AliTPC3DCylindricalInterpolatorIrregular::AliTPC3DCylindricalInterpolatorIrregular() -{ - fOrder = 1; - fIsAllocatingLookUp = kFALSE; - - fMinZIndex = 0; -} - -/// destructor -/// -AliTPC3DCylindricalInterpolatorIrregular::~AliTPC3DCylindricalInterpolatorIrregular() -{ - - delete fValue; - delete fRList; - delete fPhiList; - delete fZList; - - if (fKDTreeIrregularPoints) { - delete[] fKDTreeIrregularPoints; - delete fKDTreeIrregularRoot; - } - delete[] fRBFWeightLookUp; - delete[] fRBFWeight; -} - -/// irregular grid interpolation with IDW (inverse distance weight) -/// -/// \param r -/// \param z -/// \param phi -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \return -Double_t - AliTPC3DCylindricalInterpolatorIrregular::Interpolate3DTableCylIDW( - Double_t r, Double_t z, Double_t phi, Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, - Int_t zStep) -{ - Double_t r0, z0, phi0, d; - Double_t MIN_DIST = 1e-3; - Double_t val = 0.0; - Int_t startPhi = phiIndex - phiStep / 2; - Int_t indexPhi; - Int_t startR = rIndex - rStep / 2; - Int_t startZ = zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - Int_t index; - Double_t sum_w = 0.0; - Double_t sum_d = 0.0; - Double_t shortest_d = 10000.0; - Int_t new_rIndex = 0; - Int_t new_zIndex = 0; - Int_t new_phiIndex = 0; - - for (Int_t iPhi = startPhi; iPhi < startPhi + phiStep; iPhi++) { - indexPhi = iPhi % fNPhi; - for (Int_t index_r = startR; index_r < startR + rStep; index_r++) { - for (Int_t index_z = startZ; index_z < startZ + zStep; index_z++) { - // check for the closest poInt_t - index = indexPhi * (fNZ * fNR) + index_r * fNZ + index_z; - - r0 = fRList[index]; - z0 = fZList[index]; - phi0 = fPhiList[index]; - - d = Distance(r0, phi0, z0, r, phi, z); - if (d < shortest_d) { - shortest_d = d; - new_rIndex = index_r; - new_phiIndex = indexPhi; - new_zIndex = index_z; - } - } - } - } - - phiStep = 3; - rStep = 3; - startPhi = new_phiIndex - phiStep / 2; - startR = new_rIndex - rStep / 2; - startZ = new_zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - for (Int_t iPhi = startPhi; iPhi < startPhi + phiStep; iPhi++) { - indexPhi = iPhi % fNPhi; - for (Int_t index_r = startR; index_r < startR + rStep; index_r++) { - for (Int_t index_z = startZ; index_z < startZ + zStep; index_z++) { - // check for the closest poInt_t - index = indexPhi * (fNZ * fNR) + index_r * fNZ + index_z; - - r0 = fRList[indexPhi * (fNR * fNZ) + index_r * fNZ + index_z]; - z0 = fZList[indexPhi * (fNR * fNZ) + index_r * fNZ + index_z]; - phi0 = fPhiList[indexPhi * (fNR * fNZ) + index_r * fNZ + index_z]; - d = Distance(r0, phi0, z0, r, phi, z); - if (d < MIN_DIST) { - return fValue[index]; - } - d = 1.0 / d; - sum_w += (fValue[index] * d * d * d * d); - sum_d += d * d * d * d; - } - } - } - return (sum_w / sum_d); -} - -/// distance in Cyl coordinate -/// -/// \param r0 -/// \param phi0 -/// \param z0 -/// \param r -/// \param phi -/// \param z -/// \return -Double_t - AliTPC3DCylindricalInterpolatorIrregular::Distance(Double_t r0, Double_t phi0, Double_t z0, Double_t r, Double_t phi, - Double_t z) -{ - if (phi < 0) { - phi = TMath::TwoPi() + phi; - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - if (phi0 < 0) { - phi0 = TMath::TwoPi() + phi0; - } - if (phi0 > TMath::TwoPi()) { - phi0 = phi0 - TMath::TwoPi(); - } - - Double_t dPhi = phi - phi0; - if (dPhi > TMath::Pi()) { - dPhi = TMath::TwoPi() - dPhi; - } - if (dPhi < -TMath::Pi()) { - dPhi = TMath::TwoPi() + dPhi; - } - - Double_t ret = r * r + r0 * r0 - 2 * r0 * r * TMath::Cos(dPhi) + (z - z0) * (z - z0); - - return TMath::Sqrt(ret); -} - -/// main operation -/// interpolation by RBF -/// -/// \param r -/// \param z -/// \param phi -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radiusRBF0 -/// \return -Double_t - AliTPC3DCylindricalInterpolatorIrregular::Interpolate3DTableCylRBF( - Double_t r, Double_t z, Double_t phi, Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, - Int_t zStep, Double_t radiusRBF0) -{ - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNR - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZ - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhi; - Double_t r0, z0, phi0, d; - Double_t MIN_DIST = 1e-3; - Double_t val = 0.0; - Int_t startPhi = phiIndex - phiStep / 2; - Int_t indexPhi; - Int_t startR = rIndex - rStep / 2; - Int_t startZ = zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - Int_t index; - Double_t sum_w = 0.0; - Double_t sum_d = 0.0; - Double_t shortest_d = 10000.0; - Int_t new_rIndex = 0; - Int_t new_zIndex = 0; - Int_t new_phiIndex = 0; - - for (Int_t iPhi = startPhi; iPhi < startPhi + phiStep; iPhi++) { - indexPhi = iPhi % fNPhi; - for (Int_t index_r = startR; index_r < startR + rStep; index_r++) { - for (Int_t index_z = startZ; index_z < startZ + zStep; index_z++) { - // check for the closest poInt_t - index = indexPhi * (fNZ * fNR) + index_r * fNZ + index_z; - - r0 = fRList[index]; - z0 = fZList[index]; - phi0 = fPhiList[index]; - - d = Distance(r0, phi0, z0, r, phi, z); - if (d < shortest_d) { - shortest_d = d; - new_rIndex = index_r; - new_phiIndex = indexPhi; - new_zIndex = index_z; - } - } - } - } - - index = new_phiIndex * (fNZ * fNR) + new_rIndex * fNZ + new_zIndex; - phiStep = fStepPhi; - rStep = fStepR; - zStep = fStepZ; - startPhi = new_phiIndex - phiStep / 2; - - startR = new_rIndex - rStep / 2; - startZ = new_zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - Double_t* w; - - //Int_t nd = (phiStep-1) + (rStep-1) + (zStep-1) + 1; - Int_t nd = phiStep * rStep * zStep; - - w = new Double_t[nd]; - - Float_t minTemp, minTemp2; - - radiusRBF0 = GetRadius0RBF(new_rIndex, new_phiIndex, new_zIndex); - - if (fType == 1) { - - for (Int_t i = 0; i < nd; i++) { - w[i] = 0.0; - } - GetRBFWeight(new_rIndex, new_zIndex, new_phiIndex, rStep, phiStep, zStep, radiusRBF0, 0, w); - val = InterpRBF(r, phi, z, startR, startPhi, startZ, rStep, phiStep, zStep, radiusRBF0, 0, w); - } else { - GetRBFWeightHalf(new_rIndex, new_zIndex, new_phiIndex, rStep, phiStep, zStep, radiusRBF0, 0, w); - val = InterpRBFHalf(r, phi, z, startR, startPhi, startZ, rStep, phiStep, zStep, radiusRBF0, 0, w); - } - delete[] w; - return val; -} - -/// Search nearest point at grid -/// \param n -/// \param xArray -/// \param offset -/// \param x -/// \param low -void AliTPC3DCylindricalInterpolatorIrregular::Search(Int_t n, Double_t* xArray, Int_t offset, Double_t x, Int_t& low) -{ - /// Search an ordered table by starting at the most recently used poInt_t - - Long_t middle, high; - Int_t ascend = 0, increment = 1; - - if (xArray[(n - 1) * offset] >= xArray[0 * offset]) { - ascend = 1; // Ascending ordered table if true - } - if (low < 0 || low > n - 1) { - low = -1; - high = n; - } else { // Ordered Search phase - if ((Int_t)(x >= xArray[low * offset]) == ascend) { - if (low == n - 1) { - return; - } - high = low + 1; - while ((Int_t)(x >= xArray[high * offset]) == ascend) { - low = high; - increment *= 2; - high = low + increment; - if (high > n - 1) { - high = n; - break; - } - } - } else { - if (low == 0) { - low = -1; - return; - } - high = low - 1; - while ((Int_t)(x < xArray[low * offset]) == ascend) { - high = low; - increment *= 2; - if (increment >= high) { - low = -1; - break; - } else { - low = high - increment; - } - } - } - } - - while ((high - low) != 1) { // Binary Search Phase - middle = (high + low) / 2; - if ((Int_t)(x >= xArray[middle * offset]) == ascend) { - low = middle; - } else { - high = middle; - } - } - - if (x > xArray[n - 1]) { - low = n; - } - if (x < xArray[0]) { - low = -1; - } -} - -/// get value, interpolation with RBF -/// -/// \param r -/// \param phi -/// \param z -/// \param rIndex -/// \param phiIndex -/// \param zIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \return -Double_t AliTPC3DCylindricalInterpolatorIrregular::GetValue( - Double_t r, Double_t phi, Double_t z, Int_t rIndex, Int_t phiIndex, Int_t zIndex, Int_t rStep, Int_t phiStep, - Int_t zStep) -{ - - fMinZIndex = 0; - return Interpolate3DTableCylRBF(r, z, phi, rIndex, zIndex, phiIndex, rStep, phiStep, zStep, 0.0); -} - -/// get value -/// -/// \param r -/// \param phi -/// \param z -/// \param rIndex -/// \param phiIndex -/// \param zIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param minZColumnIndex -/// \return -Double_t AliTPC3DCylindricalInterpolatorIrregular::GetValue( - Double_t r, Double_t phi, Double_t z, Int_t rIndex, Int_t phiIndex, Int_t zIndex, Int_t rStep, Int_t phiStep, - Int_t zStep, Int_t minZColumnIndex) -{ - fMinZIndex = minZColumnIndex; - return Interpolate3DTableCylRBF(r, z, phi, rIndex, zIndex, phiIndex, rStep, phiStep, zStep, 0.0); -} - -// GetValue using searching at KDTree -Double_t AliTPC3DCylindricalInterpolatorIrregular::GetValue( - Double_t r, Double_t phi, Double_t z) -{ - - KDTreeNode n; - n.pR = &r; - n.pPhi = φ - n.pZ = &z; - KDTreeNode* nearest; - Double_t dist; - dist = 100000000.0; - Int_t startIndex = 0; // Z - Int_t dim = 3; // dimenstion - KDTreeNearest(fKDTreeIrregularRoot, &n, startIndex, dim, &nearest, &dist); - return Interpolate3DTableCylRBF(r, z, phi, nearest); -} -/// Set value and distorted point for irregular grid interpolation -/// -/// \param matrixRicesValue -/// \param matrixRicesRPoint -/// \param matrixRicesPhiPoint -/// \param matrixRicesZPoint -void AliTPC3DCylindricalInterpolatorIrregular::SetValue( - TMatrixD** matrixRicesValue, TMatrixD** matrixRicesRPoint, TMatrixD** matrixRicesPhiPoint, - TMatrixD** matrixRicesZPoint) -{ - Int_t indexInner; - Int_t index; - - if (!fIsAllocatingLookUp) { - fValue = new Double_t[fNPhi * fNR * fNZ]; - fRList = new Double_t[fNPhi * fNR * fNZ]; - fPhiList = new Double_t[fNPhi * fNR * fNZ]; - fZList = new Double_t[fNPhi * fNR * fNZ]; - fIsAllocatingLookUp = kTRUE; - } - - for (Int_t m = 0; m < fNPhi; m++) { - indexInner = m * fNR * fNZ; - TMatrixD* mat = matrixRicesValue[m]; - TMatrixD* matrixR = matrixRicesRPoint[m]; - TMatrixD* matrixPhi = matrixRicesPhiPoint[m]; - TMatrixD* matrixZ = matrixRicesZPoint[m]; - - for (Int_t i = 0; i < fNR; i++) { - index = indexInner + i * fNZ; - for (Int_t j = 0; j < fNZ; j++) { - fValue[index + j] = (*mat)(i, j); - - fRList[index + j] = (*matrixR)(i, j); - fPhiList[index + j] = (*matrixPhi)(i, j); - fZList[index + j] = (*matrixZ)(i, j); - } - } - } - // KD Tree is used for look-up a point to irregular grid to find - // closest neughboor point - InitKDTree(); - InitRBFWeight(); -} - -/// init RBF Weights assume value already been set -/// -void AliTPC3DCylindricalInterpolatorIrregular::InitRBFWeight() -{ - - Int_t indexInner; - Int_t rIndex; - Int_t index; - Int_t startR; - Int_t nd; - - const Double_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNR - 1); - const Double_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZ - 1); - const Double_t gridSizePhi = TMath::TwoPi() / fNPhi; - - Float_t r0; - Double_t radiusRBF0, minTemp, minTemp2; - - nd = fStepR * fStepPhi * fStepZ; - for (Int_t m = 0; m < fNPhi; m++) { - indexInner = m * fNR * fNZ; - for (Int_t i = 0; i < fNR; i++) { - rIndex = indexInner + i * fNZ; - - startR = i - fStepR / 2; - - if (startR < 0) { - startR = 0; - } - if (startR + fStepR >= fNR) { - startR = fNR - fStepR; - } - - for (Int_t j = 0; j < fNZ; j++) { - index = rIndex + j; - - radiusRBF0 = GetRadius0RBF(i, j, m); - - RBFWeight( - i, - j, - m, - fStepR, - fStepPhi, - fStepZ, - radiusRBF0, - fKernelType, - &fRBFWeight[index * nd]); - fRBFWeightLookUp[index] = 1; - } - } - } -} - -/// Set value and distorted Point -/// -/// \param matrixRicesValue -/// \param matrixRicesRPoint -/// \param matrixRicesPhiPoint -/// \param matrixRicesZPoint -/// \param jy -void AliTPC3DCylindricalInterpolatorIrregular::SetValue( - TMatrixD** matrixRicesValue, TMatrixD** matrixRicesRPoint, TMatrixD** matrixRicesPhiPoint, - TMatrixD** matrixRicesZPoint, - Int_t jy) -{ - Int_t indexInner; - Int_t index; - - if (!fIsAllocatingLookUp) { - fValue = new Double_t[fNPhi * fNR * fNZ]; - fRList = new Double_t[fNPhi * fNR * fNZ]; - fPhiList = new Double_t[fNPhi * fNR * fNZ]; - fZList = new Double_t[fNPhi * fNR * fNZ]; - - fIsAllocatingLookUp = kTRUE; - } - - for (Int_t m = 0; m < fNPhi; m++) { - indexInner = m * fNR * fNZ; - TMatrixD* mat = matrixRicesValue[m]; - TMatrixD* matrixR = matrixRicesRPoint[m]; - TMatrixD* matrixPhi = matrixRicesPhiPoint[m]; - TMatrixD* matrixZ = matrixRicesZPoint[m]; - - for (Int_t i = 0; i < fNR; i++) { - index = indexInner + i * fNZ; - fValue[index + jy] = (*mat)(i, jy); - fRList[index + jy] = (*matrixR)(i, jy); - fPhiList[index + jy] = (*matrixPhi)(i, jy); - fZList[index + jy] = (*matrixZ)(i, jy); - } - } -} - -/// calculate -/// RBFWeight for all points in the interpolation -/// -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param w -void AliTPC3DCylindricalInterpolatorIrregular::RBFWeight( - Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, Int_t zStep, Double_t radius0, - Int_t kernelType, Double_t* w) -{ - - Double_t* a; - Int_t i; - Int_t j; - Int_t k; - Int_t ii; - Int_t jj; - Int_t kk; - - Int_t index0, index1; - Int_t indexCyl0, indexCyl1; - Double_t* r; - Double_t* v; - - Double_t phi0; - Double_t z0; - Double_t r0; - - Double_t phi1; - Double_t z1; - Double_t r1; - - Int_t nd = rStep * phiStep * zStep; - - a = new Double_t[nd * nd]; - r = new Double_t[nd]; - v = new Double_t[nd]; - - Int_t startPhi = phiIndex - phiStep / 2; - Int_t indexPhi; - Int_t indexPhi1; - - Int_t startR = rIndex - rStep / 2; - Int_t startZ = zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - index0 = 0; - - for (i = startPhi; i < startPhi + phiStep; i++) { - indexPhi = i % fNPhi; - - for (j = startR; j < startR + rStep; j++) { - for (k = startZ; k < startZ + zStep; k++) { - indexCyl0 = indexPhi * fNR * fNZ + j * fNZ + k; - - r0 = fRList[indexCyl0]; - z0 = fZList[indexCyl0]; - phi0 = fPhiList[indexCyl0]; - - index1 = 0; - for (ii = startPhi; ii < startPhi + phiStep; ii++) { - indexPhi1 = ii % fNPhi; - for (jj = startR; jj < startR + rStep; jj++) { - for (kk = startZ; kk < startZ + zStep; kk++) { - indexCyl1 = indexPhi1 * fNR * fNZ + jj * fNZ + kk; - r1 = fRList[indexCyl1]; - z1 = fZList[indexCyl1]; - phi1 = fPhiList[indexCyl1]; - r[index1] = Distance(r0, phi0, z0, r1, phi1, z1); - - index1++; - } - } - } - - Phi(nd, r, radius0, v); - - index1 = 0; - for (ii = startPhi; ii < startPhi + phiStep; ii++) { - indexPhi1 = ii % fNPhi; - for (jj = startR; jj < startR + rStep; jj++) { - for (kk = startZ; kk < startZ + zStep; kk++) { - a[index0 * nd + index1] = v[index1]; - index1++; - } - } - } - w[index0] = fValue[indexCyl0]; - index0++; - } - } - } - - TMatrixD mat_a; - mat_a.Use(nd, nd, a); - TVectorD vec_w; - vec_w.Use(nd, w); - TDecompSVD svd(mat_a); - - svd.Solve(vec_w); - - delete[] a; - delete[] r; - delete[] v; -} - -/// rbf1 -/// \param n -/// \param r -/// \param r0 -/// \param v -void AliTPC3DCylindricalInterpolatorIrregular::rbf1(Int_t n, Double_t r[], Double_t r0, Double_t v[]) -{ - Int_t i; - - for (i = 0; i < n; i++) { - v[i] = sqrt(1 + (r[i] * r[i] + r0 * r0)); - } - return; -} - -/// rbf2 -/// \param n -/// \param r -/// \param r0 -/// \param v - -void AliTPC3DCylindricalInterpolatorIrregular::rbf2(Int_t n, Double_t r[], Double_t r0, Double_t v[]) -{ - Int_t i; - - for (i = 0; i < n; i++) { - v[i] = 1.0 / sqrt(1 + (r[i] * r[i] + r0 * r0)); - } - return; -} - -/// rbf3 -/// \param n -/// \param r -/// \param r0 -/// \param v -void AliTPC3DCylindricalInterpolatorIrregular::rbf3(Int_t n, Double_t r[], Double_t r0, Double_t v[]) -{ - Int_t i; - - for (i = 0; i < n; i++) { - if (r[i] <= 0.0) { - v[i] = 0.0; - } else { - v[i] = r[i] * r[i] * log(r[i] / r0); - } - } - return; -} - -/// rbf4 -/// \param n -/// \param r -/// \param r0 -/// \param v -void AliTPC3DCylindricalInterpolatorIrregular::rbf4(Int_t n, Double_t r[], Double_t r0, Double_t v[]) -{ - Int_t i; - - for (i = 0; i < n; i++) { - v[i] = TMath::Exp(-0.5 * r[i] * r[i] / (r0 * r0)); - } - return; -} - -// RBF based interpolation -// return interpolated value -/// -/// \param r -/// \param phi -/// \param z -/// \param startR -/// \param startPhi -/// \param startZ -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param weight -/// \return -Double_t AliTPC3DCylindricalInterpolatorIrregular::InterpRBF( - Double_t r, Double_t phi, Double_t z, Int_t startR, Int_t startPhi, Int_t startZ, Int_t rStep, Int_t phiStep, - Int_t zStep, Double_t radius0, Int_t kernelType, Double_t* weight) -{ - Double_t interpVal = 0.0; - Double_t r0, z0, phi0; - Double_t* dList; - Double_t* v; - - Int_t indexCyl0, index0, indexPhi; - - Int_t nd = rStep * phiStep * zStep; - - dList = new Double_t[nd]; - v = new Double_t[nd]; - - index0 = 0; - for (Int_t i = startPhi; i < startPhi + phiStep; i++) { - indexPhi = i % fNPhi; - - for (Int_t j = startR; j < startR + rStep; j++) { - for (Int_t k = startZ; k < startZ + zStep; k++) { - - indexCyl0 = indexPhi * fNR * fNZ + j * fNZ + k; - - r0 = fRList[indexCyl0]; - z0 = fZList[indexCyl0]; - phi0 = fPhiList[indexCyl0]; - - dList[index0] = Distance(r, phi, z, r0, phi0, z0); - index0++; - } - } - } - - Phi(nd, dList, radius0, v); - - TVectorD vec_v; - vec_v.Use(nd, v); - - TVectorD vec_w; - vec_w.Use(nd, weight); - - interpVal = vec_v * vec_w; - delete[] v; - delete[] dList; - return interpVal; -} - -// calculate -// RBFWeight for all points in the interpolation -/// -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param w -void AliTPC3DCylindricalInterpolatorIrregular::GetRBFWeight( - Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, Int_t zStep, Double_t radius0, - Int_t kernelType, Double_t* w) -{ - - Int_t index = phiIndex * fNR * fNZ + rIndex * fNZ + zIndex; - if (fRBFWeightLookUp[index] == 0) { - RBFWeight(rIndex, zIndex, phiIndex, rStep, phiStep, zStep, radius0, kernelType, w); - - fRBFWeightLookUp[index] = 1; - Int_t nd = rStep * zStep * phiStep; - - for (Int_t i = 0; i < nd; i++) { - fRBFWeight[index * nd + i] = w[i]; - } - } else { - - Int_t ndw = rStep * zStep * phiStep; - - Int_t nd = fStepR * fStepZ * fStepPhi; - Int_t indexWeight = phiIndex * fNR * fNZ * nd + rIndex * fNZ * nd + zIndex * nd; - - for (Int_t i = 0; i < nd; i++) { - w[i] = fRBFWeight[indexWeight + i]; - } - } -} - -// calculate -// RBFWeight for all points in the interpolation -/// -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param w -void AliTPC3DCylindricalInterpolatorIrregular::GetRBFWeightHalf( - Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, Int_t zStep, Double_t radius0, - Int_t kernelType, Double_t* w) -{ - - Int_t index = phiIndex * fNR * fNZ + rIndex * fNZ + zIndex; - - if (fRBFWeightLookUp[index] == 0) { - RBFWeightHalf(rIndex, zIndex, phiIndex, rStep, phiStep, zStep, radius0, kernelType, w); - - if ((rStep == fStepR) && (zStep == fStepZ) && (phiStep == fStepPhi) && (zIndex > fMinZIndex + fStepZ)) { - fRBFWeightLookUp[index] = 1; - // copy to lookup - Int_t nd = rStep + zStep + phiStep - 2; - - for (Int_t i = 0; i < nd; i++) { - fRBFWeight[index * nd + i] = w[i]; - } - } - } else { - - //Int_t ndw = rStep*zStep*phiStep; - Int_t nd = rStep + zStep + phiStep - 2; - Int_t indexWeight = phiIndex * fNR * fNZ * nd + rIndex * fNZ * nd + zIndex * nd; - - for (Int_t i = 0; i < nd; i++) { - w[i] = fRBFWeight[indexWeight + i]; - } - } -} - -// calculate -// RBFWeight for all points in the interpolation -// half cubes (not included -/// -/// \param rIndex -/// \param zIndex -/// \param phiIndex -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param w -void AliTPC3DCylindricalInterpolatorIrregular::RBFWeightHalf( - Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t rStep, Int_t phiStep, Int_t zStep, Double_t radius0, - Int_t kernelType, Double_t* w) -{ - Double_t* a; - Int_t i; - Int_t j; - Int_t k; - Int_t ii; - Int_t jj; - Int_t kk; - - Int_t index0, index1; - Int_t indexCyl0, indexCyl1; - Double_t* r; - Double_t* v; - - Double_t phi0; - Double_t z0; - Double_t r0; - - Double_t phi1; - Double_t z1; - Double_t r1; - - Int_t nd = (rStep - 1) + (phiStep - 1) + (zStep - 1) + 1; - - a = new Double_t[nd * nd]; - r = new Double_t[nd]; - v = new Double_t[nd]; - - Int_t startPhi = phiIndex - phiStep / 2; - Int_t indexPhi; - Int_t indexPhi1; - - Int_t startR = rIndex - rStep / 2; - Int_t startZ = zIndex - zStep / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - - if (startR < 0) { - startR = 0; - } - if (startR + rStep >= fNR) { - startR = fNR - rStep; - } - - if (startZ < fMinZIndex) { - startZ = fMinZIndex; - } - if (startZ + zStep >= fNZ) { - startZ = fNZ - zStep; - } - - index0 = 0; - - for (i = startPhi; i < startPhi + phiStep; i++) { - indexPhi = i % fNPhi; - - for (j = startR; j < startR + rStep; j++) { - for (k = startZ; k < startZ + zStep; k++) { - - if ( - (i == (startPhi + phiStep / 2) && j == (startR + rStep / 2)) || - (i == (startPhi + phiStep / 2) && k == (startZ + zStep / 2)) || - (j == (startR + rStep / 2) && k == (startZ + zStep / 2))) { - indexCyl0 = indexPhi * fNR * fNZ + j * fNZ + k; - - r0 = fRList[indexCyl0]; - z0 = fZList[indexCyl0]; - phi0 = fPhiList[indexCyl0]; - - index1 = 0; - for (ii = startPhi; ii < startPhi + phiStep; ii++) { - indexPhi1 = ii % fNPhi; - for (jj = startR; jj < startR + rStep; jj++) { - for (kk = startZ; kk < startZ + zStep; kk++) { - if ( - (ii == (startPhi + phiStep / 2) && jj == (startR + rStep / 2)) || - (ii == (startPhi + phiStep / 2) && kk == (startZ + zStep / 2)) || - (jj == (startR + rStep / 2) && kk == (startZ + zStep / 2))) { - - indexCyl1 = indexPhi1 * fNR * fNZ + jj * fNZ + kk; - r1 = fRList[indexCyl1]; - z1 = fZList[indexCyl1]; - phi1 = fPhiList[indexCyl1]; - - r[index1] = Distance(r0, phi0, z0, r1, phi1, z1); - index1++; - } - } - } - } - - Phi(nd, r, radius0, v); - - index1 = 0; - for (ii = startPhi; ii < startPhi + phiStep; ii++) { - indexPhi1 = ii % fNPhi; - for (jj = startR; jj < startR + rStep; jj++) { - for (kk = startZ; kk < startZ + zStep; kk++) { - if ( - (ii == (startPhi + phiStep / 2) && jj == (startR + rStep / 2)) || - (ii == (startPhi + phiStep / 2) && kk == (startZ + zStep / 2)) || - (jj == (startR + rStep / 2) && kk == (startZ + zStep / 2))) { - a[index0 * nd + index1] = v[index1]; - index1++; - } - } - } - } - - w[index0] = fValue[indexCyl0]; - index0++; - } - } - } - } - - TMatrixD mat_a; - mat_a.Use(nd, nd, a); - TVectorD vec_w; - - vec_w.Use(nd, w); - TDecompSVD svd(mat_a); - - svd.Solve(vec_w); - - delete[] a; - delete[] r; - delete[] v; -} - -// RBF based interpolation -// return interpolated value -// half points -/// -/// \param r -/// \param phi -/// \param z -/// \param startR -/// \param startPhi -/// \param startZ -/// \param rStep -/// \param phiStep -/// \param zStep -/// \param radius0 -/// \param kernelType -/// \param weight -/// \return -Double_t AliTPC3DCylindricalInterpolatorIrregular::InterpRBFHalf( - Double_t r, Double_t phi, Double_t z, Int_t startR, Int_t startPhi, Int_t startZ, Int_t rStep, Int_t phiStep, - Int_t zStep, Double_t radius0, Int_t kernelType, Double_t* weight) -{ - Double_t interpVal = 0.0; - Double_t r0, z0, phi0; - Double_t* dList; - Double_t* v; - - Int_t indexCyl0, index0, indexPhi; - - // Int_t nd = rStep * phiStep * zStep; - Int_t nd = (rStep - 1) + (phiStep - 1) + (zStep - 1) + 1; - - dList = new Double_t[nd]; - v = new Double_t[nd]; - - index0 = 0; - for (Int_t i = startPhi; i < startPhi + phiStep; i++) { - indexPhi = i % fNPhi; - - for (Int_t j = startR; j < startR + rStep; j++) { - for (Int_t k = startZ; k < startZ + zStep; k++) { - if ( - (i == (startPhi + phiStep / 2) && j == (startR + rStep / 2)) || - (i == (startPhi + phiStep / 2) && k == (startZ + zStep / 2)) || - (j == (startR + rStep / 2) && k == (startZ + zStep / 2))) { - - indexCyl0 = indexPhi * fNR * fNZ + j * fNZ + k; - - r0 = fRList[indexCyl0]; - z0 = fZList[indexCyl0]; - phi0 = fPhiList[indexCyl0]; - - dList[index0] = Distance(r, phi, z, r0, phi0, z0); - index0++; - } - } - } - } - - Phi(nd, dList, radius0, v); - - TVectorD vec_v; - vec_v.Use(nd, v); - - TVectorD vec_w; - vec_w.Use(nd, weight); - - interpVal = vec_v * vec_w; - delete[] v; - delete[] dList; - return interpVal; -} - -// set Radius0 -/// -/// \param n -/// \param r -/// \param r0 -/// \param v -void AliTPC3DCylindricalInterpolatorIrregular::Phi(Int_t n, Double_t r[], Double_t r0, Double_t v[]) -{ - - switch (fKernelType) { - case kRBFMultiQuadratic: - rbf1(n, r, r0, v); - break; - case kRBFInverseMultiQuadratic: - rbf2(n, r, r0, v); - break; - case kRBFThinPlateSpline: - rbf3(n, r, r0, v); - break; - case kRBFGaussian: - rbf4(n, r, r0, v); - break; - - default: - rbf1(n, r, r0, v); - break; - } -} - -// -Double_t - AliTPC3DCylindricalInterpolatorIrregular::GetRadius0RBF(const Int_t rIndex, const Int_t phiIndex, const Int_t zIndex) -{ - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNR - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZ - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhi; - Int_t startPhi = phiIndex - fStepPhi / 2; - - Int_t startR = rIndex - fStepR / 2; - Int_t startZ = zIndex - fStepZ / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - - if (startR < 0) { - startR = 0; - } - if (startR + fStepR >= fNR) { - startR = fNR - fStepR; - } - - if (startZ < 0) { - startZ = 0; - } - if (startZ + fStepZ >= fNZ) { - startZ = fNZ - fStepZ; - } - - Double_t r0 = AliTPCPoissonSolver::fgkIFCRadius + (startR * gridSizeR); - Double_t phi0 = startPhi * gridSizePhi; - Double_t z0 = startZ * gridSizeZ; - - Double_t r1 = AliTPCPoissonSolver::fgkIFCRadius + (startR * gridSizeR); - Double_t phi1 = (startPhi + 1) * gridSizePhi; - Double_t z1 = (startZ + 1) * gridSizeZ; - - if (fKernelType == kRBFThinPlateSpline) { - r0 = AliTPCPoissonSolver::fgkIFCRadius + ((startR - 1) * gridSizeR); - } else { - r0 = AliTPCPoissonSolver::fgkIFCRadius + (startR * gridSizeR); - } - - return Distance(r0, 0.0, 0.0, r0 + gridSizeR, gridSizePhi, gridSizeR); -} - -// make kdtree for irregular look-up -void AliTPC3DCylindricalInterpolatorIrregular::InitKDTree() -{ - Int_t count = fNR * fNZ * fNPhi; - - fKDTreeIrregularPoints = new KDTreeNode[count]; - - for (Int_t i = 0; i < count; i++) { - fKDTreeIrregularPoints[i].pR = &fRList[i]; - fKDTreeIrregularPoints[i].pZ = &fZList[i]; - fKDTreeIrregularPoints[i].pPhi = &fPhiList[i]; - fKDTreeIrregularPoints[i].index = i; - } - - fKDTreeIrregularRoot = MakeKDTree(fKDTreeIrregularPoints, count, 0, 3); -} - -// create KDTree -AliTPC3DCylindricalInterpolatorIrregular::KDTreeNode* AliTPC3DCylindricalInterpolatorIrregular::MakeKDTree(KDTreeNode* t, Int_t count, Int_t index, Int_t dim) -{ - KDTreeNode* n; - - if (!count) { - return nullptr; - } - if ((n = FindMedian(t, t + count, index))) { - index = (index + 1) % dim; - n->left = MakeKDTree(t, (n - t), index, dim); - n->right = MakeKDTree(n + 1, (t + count) - (n + 1), index, dim); - } - return n; -} - -// find median -AliTPC3DCylindricalInterpolatorIrregular::KDTreeNode* AliTPC3DCylindricalInterpolatorIrregular::FindMedian(KDTreeNode* start, KDTreeNode* end, Int_t index) -{ - if (end <= start) { - return nullptr; - } - if (end == start + 1) { - return start; - } - - KDTreeNode *p, *store, *md = start + (end - start) / 2; - Double_t pivot; - - while (1) { - if (index == 0) { - pivot = *(md->pZ); - } else if (index == 1) { - pivot = *(md->pR); - } else { - pivot = *(md->pPhi); - } - - Swap(md, end - 1); - - for (store = p = start; p < end; p++) { - - if (((index == 0) && (*(p->pZ) < pivot)) || - ((index == 1) && (*(p->pR) < pivot)) || - ((index == 2) && (*(p->pPhi) < pivot))) - - { - if (p != store) { - Swap(p, store); - } - store++; - } - } - Swap(store, end - 1); - - if ((index == 0) && (*(store->pZ) == *(md->pZ))) { - return md; - } - if ((index == 1) && (*(store->pR) == *(md->pR))) { - return md; - } - if ((index == 2) && (*(store->pPhi) == *(md->pPhi))) { - return md; - } - - // if (md->index == store->index) return md; - - if (store > md) { - end = store; - } else { - start = store; - } - } -} - -//swap -void AliTPC3DCylindricalInterpolatorIrregular::Swap(KDTreeNode* x, KDTreeNode* y) -{ - KDTreeNode* tmp = new KDTreeNode; - tmp->pR = x->pR; - tmp->pZ = x->pZ; - tmp->pPhi = x->pPhi; - tmp->index = x->index; - - x->pR = y->pR; - x->pZ = y->pZ; - x->pPhi = y->pPhi; - x->index = y->index; - - y->pR = tmp->pR; - y->pZ = tmp->pZ; - y->pPhi = tmp->pPhi; - y->index = tmp->index; - - delete tmp; -} - -// look for nearest point -void AliTPC3DCylindricalInterpolatorIrregular::KDTreeNearest(KDTreeNode* root, KDTreeNode* nd, Int_t index, Int_t dim, - KDTreeNode** best, Double_t* best_dist) -{ - Double_t d, dx2, dx; - - if (!root) { - return; - } - d = Distance(*(root->pR), *(root->pPhi), *(root->pZ), *(nd->pR), *(nd->pPhi), *(nd->pZ)); - if (index == 0) { - dx = *(root->pZ) - *(nd->pZ); - dx2 = Distance(*(nd->pR), *(nd->pPhi), *(root->pZ), *(nd->pR), *(nd->pPhi), *(nd->pZ)); - } else if (index == 1) { - dx = *(root->pR) - *(nd->pR); - dx2 = Distance(*(root->pR), *(nd->pPhi), *(nd->pZ), *(nd->pR), *(nd->pPhi), *(nd->pZ)); - } else { - dx = *(root->pPhi) - *(nd->pPhi); - dx2 = Distance(*(nd->pR), *(root->pPhi), *(nd->pZ), *(nd->pR), *(nd->pPhi), *(nd->pZ)); - } - - if (!*best || (d < *best_dist)) { - *best_dist = d; - *best = root; - } - - if (!*best_dist) { - return; - } - - if (++index >= dim) { - index = 0; - } - - KDTreeNearest(dx > 0 ? root->left : root->right, nd, index, dim, best, best_dist); - if (dx2 >= *best_dist) { - return; - } - KDTreeNearest(dx > 0 ? root->right : root->left, nd, index, dim, best, best_dist); -} - -// interpolate on the nearest neighbor of irregular grid -Double_t - AliTPC3DCylindricalInterpolatorIrregular::Interpolate3DTableCylRBF( - Double_t r, Double_t z, Double_t phi, KDTreeNode* nearestNode) -{ - Double_t val = 0.0; - Int_t startPhi, startR, startZ; - Int_t phiIndex, rIndex, zIndex; - - phiIndex = nearestNode->index / (fNR * fNZ); - rIndex = (nearestNode->index - (phiIndex * (fNR * fNZ))) / fNZ; - zIndex = nearestNode->index - (phiIndex * (fNR * fNZ) + rIndex * fNZ); - - startPhi = phiIndex - fStepPhi / 2; - startR = rIndex - fStepR / 2; - startZ = zIndex - fStepZ / 2; - - if (startPhi < 0) { - startPhi = fNPhi + startPhi; - } - - if (startR < 0) { - startR = 0; - } - if (startR + fStepR >= fNR) { - startR = fNR - fStepR; - } - - if (startZ < 0) { - startZ = 0; - } - if (startZ + fStepZ >= fNZ) { - startZ = fNZ - fStepZ; - } - Int_t indexPhi; - - Int_t index; - Double_t r0, z0, phi0; - - Int_t rStep = fStepR; - Int_t zStep = fStepZ; - Int_t phiStep = fStepPhi; - - Double_t* w; - - //Int_t nd = (phiStep-1) + (rStep-1) + (zStep-1) + 1; - Int_t nd = fStepPhi * fStepR * fStepZ; - - w = new Double_t[nd]; - - Float_t minTemp, minTemp2; - - Double_t radiusRBF0 = GetRadius0RBF(rIndex, phiIndex, zIndex); - - if (fType == 1) { - - for (Int_t i = 0; i < nd; i++) { - w[i] = 0.0; - } - GetRBFWeight(rIndex, zIndex, phiIndex, rStep, phiStep, zStep, radiusRBF0, 0, w); - val = InterpRBF(r, phi, z, startR, startPhi, startZ, rStep, phiStep, zStep, radiusRBF0, 0, w); - } else { - GetRBFWeightHalf(rIndex, zIndex, phiIndex, rStep, phiStep, zStep, radiusRBF0, 0, w); - val = InterpRBFHalf(r, phi, z, startR, startPhi, startZ, rStep, phiStep, zStep, radiusRBF0, 0, w); - } - delete[] w; - return val; -} diff --git a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.h b/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.h deleted file mode 100644 index 952114b174cd2..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPC3DCylindricalInterpolatorIrregular.h +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPC3DCylindricalInterpolatorIrregular.h -/// \brief Irregular grid interpolator for cylindrical coordinate with r,phi,z different coordinates -/// RBF-based interpolation -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Jan 5, 2016 - -#ifndef AliTPC3DCylindricalInterpolatorIrregular_H -#define AliTPC3DCylindricalInterpolatorIrregular_H - -#include "TMatrixD.h" - -class AliTPC3DCylindricalInterpolatorIrregular -{ - public: - AliTPC3DCylindricalInterpolatorIrregular(Int_t nRRow, Int_t nZColumn, Int_t nPhiSlice, Int_t rStep, Int_t zStep, - Int_t phiStep, Int_t intType); - AliTPC3DCylindricalInterpolatorIrregular(); - ~AliTPC3DCylindricalInterpolatorIrregular(); - - Double_t - GetValue(Double_t r, Double_t phi, Double_t z, Int_t rIndex, Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, - Int_t stepZ); - Double_t - GetValue(Double_t r, Double_t phi, Double_t z, Int_t rIndex, Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, - Int_t stepZ, Int_t minZColumnIndex); - Double_t GetValue(Double_t r, Double_t phi, Double_t z); - void SetOrder(Int_t order) { fOrder = order; } - - void InitRBFWeight(); - void SetIrregularGridSize(Int_t size) { fIrregularGridSize = size; } - Int_t GetIrregularGridSize() { return fIrregularGridSize; } - void SetKernelType(Int_t kernelType) { fKernelType = kernelType; } - Int_t GetKernelType() { return fKernelType; } - - ///< Enumeration of Poisson Solver Strategy Type - enum RBFKernelType { - kRBFMultiQuadratic = 0, - kRBFInverseMultiQuadratic = 1, - kRBFThinPlateSpline = 2, - kRBFGaussian = 3 - }; - - void SetNR(Int_t nRRow) { fNR = nRRow; } - void SetNPhi(Int_t nPhiSlice) { fNPhi = nPhiSlice; } - void SetNZ(Int_t nZColumn) { fNZ = nZColumn; } - - Int_t GetNR() { return fNR; } - Int_t GetNPhi() { return fNPhi; } - Int_t GetNZ() { return fNZ; } - - void SetRList(Double_t* rList) { fRList = rList; } - void SetPhiList(Double_t* phiList) { fPhiList = phiList; } - void SetZList(Double_t* zList) { fZList = zList; } - - void SetValue(Double_t* value) { fValue = value; } - void - SetValue(TMatrixD** matricesValue, TMatrixD** matricesRPoint, TMatrixD** matricesPhiPoint, TMatrixD** matricesZPoint); - void - SetValue(TMatrixD** matricesValue, TMatrixD** matricesRPoint, TMatrixD** matricesPhiPoint, TMatrixD** matricesZPoint, - Int_t jy); - - struct KDTreeNode { - Double_t* pR; //!<! TODO: fix for streamers - Double_t* pZ; //!<! - Double_t* pPhi; //!<! - Int_t index; - struct KDTreeNode *left, *right; - }; - - private: - Int_t fOrder; ///< Order of interpolation, 1 - linear, 2 - quadratic, 3 - cubic - Int_t fType; ///< 0 INVERSE WEIGHT, 1 RBF FULL, 2 RBF Half - Int_t fKernelType; ///< type kernel RBF 1--5 - Int_t fIrregularGridSize; ///< size when interpolating for irregular grid - Int_t fNR; ///< Grid size in direction of R - Int_t fNPhi; ///< Grid size in direction of Phi - Int_t fNZ; ///< Grid size in direction of Z - Int_t fNGridPoints; ///< Total number of grid points (needed for streamer) - Int_t fNRBFpoints; ///< Total number of points for RBF weights - Int_t fMinZIndex; ///<index z minimal as lower bound - Int_t fStepR; ///< step in R direction for irregular grid - Int_t fStepZ; ///< step in Z direction for irregular grid - Int_t fStepPhi; ///< step in Phi direction for irregular grid - Int_t* fRBFWeightLookUp = nullptr; //[fNGridPoints] weighted look up - - Double_t fRadiusRBF0; ///< Radius RBF0 - Double_t* fValue = nullptr; //[fNGridPoints] 3D for storing known values interpolation should be in size fNR*fNPhi*fNZ - Double_t* fRList = nullptr; //[fNGridPoints] coordinate in R (cm) (should be increasing) in 3D - Double_t* fPhiList = nullptr; //[fNGridPoints] coordinate in phiList (rad) (should be increasing) 0 <= < 2 pi (cyclic) in 3D - Double_t* fZList = nullptr; //[fNGridPoints] coordinate in z list (cm) (should be increasing) in 3D - Double_t* fRBFWeight = nullptr; //[fNRBFpoints] weight for RBF - Bool_t fIsAllocatingLookUp; ///< is allocating memory? - - Double_t Interpolate3DTableCylIDW(Double_t r, Double_t z, Double_t phi, Int_t rIndex, Int_t zIndex, Int_t phiIndex, - Int_t stepR, Int_t stepZ, Int_t stepPhi); - Double_t Interpolate3DTableCylRBF(Double_t r, Double_t z, Double_t phi, Int_t rIndex, Int_t zIndex, Int_t phiIndex, - Int_t stepR, Int_t stepZ, Int_t stepPhi, Double_t radiusRBF0); - Double_t Interpolate3DTableCylRBF(Double_t r, Double_t z, Double_t phi, KDTreeNode* nearestNode); - - void Search(Int_t n, const Double_t xArray[], Double_t x, Int_t& low); - void Search(Int_t n, Double_t* xArray, Int_t offset, Double_t x, Int_t& low); - Double_t Distance(Double_t r0, Double_t phi0, Double_t z0, Double_t r, Double_t phi, Double_t z); - void RBFWeight(Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, Double_t radius0, - Int_t kernelType, Double_t* weight); - void - GetRBFWeight(Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, Double_t radius0, - Int_t kernelType, Double_t* weight); - void Phi(Int_t n, Double_t r[], Double_t r0, Double_t v[]); - void rbf1(Int_t n, Double_t r[], Double_t r0, Double_t v[]); - void rbf2(Int_t n, Double_t r[], Double_t r0, Double_t v[]); - void rbf3(Int_t n, Double_t r[], Double_t r0, Double_t v[]); - void rbf4(Int_t n, Double_t r[], Double_t r0, Double_t v[]); - Double_t InterpRBF(Double_t r, Double_t phi, Double_t z, Int_t startR, Int_t startPhi, Int_t startZ, Int_t stepR, - Int_t stepPhi, Int_t stepZ, Double_t radius0, Int_t kernelType, Double_t* weight); - void - RBFWeightHalf(Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, Double_t radius0, - Int_t kernelType, Double_t* weight); - Double_t InterpRBFHalf(Double_t r, Double_t phi, Double_t z, Int_t startR, Int_t startPhi, Int_t startZ, Int_t stepR, - Int_t stepPhi, Int_t stepZ, Double_t radius0, Int_t kernelType, Double_t* weight); - void GetRBFWeightHalf(Int_t rIndex, Int_t zIndex, Int_t phiIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, - Double_t radius0, Int_t kernelType, Double_t* weight); - Double_t GetRadius0RBF(const Int_t rIndex, const Int_t phiIndex, const Int_t zIndex); - - KDTreeNode* fKDTreeIrregularPoints = nullptr; //!<![fNGridPoints] to save tree as list - KDTreeNode* fKDTreeIrregularRoot = nullptr; //!<! kdtree root TODO: make this streamable - - void InitKDTree(); - KDTreeNode* MakeKDTree(KDTreeNode* tree, Int_t count, Int_t index, Int_t dimention); - - KDTreeNode* FindMedian(KDTreeNode* startTree, KDTreeNode* endTree, Int_t index); - void Swap(KDTreeNode* x, KDTreeNode* y); - - void KDTreeNearest(KDTreeNode* root, KDTreeNode* nd, Int_t index, Int_t dim, - KDTreeNode** best, Double_t* best_dist); - /// \cond CLASSIMP - ClassDefNV(AliTPC3DCylindricalInterpolatorIrregular, 1); - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.cxx b/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.cxx deleted file mode 100644 index 10e0837b95699..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.cxx +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCLookUpTable3DInterpolatorD.cxx -/// \brief Wrap up look-up table for correction/distortion integral or derivative (electric field) -/// assume 3 components: r-component, phi-component and z-component -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Mar 4, 2015 - -#include "AliTPCLookUpTable3DInterpolatorD.h" - -/// \cond CLASSIMP3 -ClassImp(AliTPCLookUpTable3DInterpolatorD); -/// \endcond - -/// constructor -AliTPCLookUpTable3DInterpolatorD::AliTPCLookUpTable3DInterpolatorD() -{ - fOrder = 1; - fIsAllocatingLookUp = kFALSE; -} - -/// constructor -/// -/// \param nRRow Int_t size of grid in R direction -/// \param rMin Double_t minimal value of R -/// \param rMax Double_t maximal value of R -/// \param nPhiSlice Int_t size of grid Phi direction -/// \param phiMin Double_t minimal value of Phi -/// \param phiMax Double_t maximal value of Phi -/// \param nZColumn Int_t size of grid Z direction -/// \param zMin Double_t minimal value of Z -/// \param zMax Double_t maximal value of Z - -/** - AliTPCLookUpTable3DInterpolatorD::AliTPCLookUpTable3DInterpolatorD(Int_t nRRow, Double_t rMin, Double_t rMax, - Int_t nPhiSlice, - Double_t phiMin, Double_t phiMax, Int_t nZColumn, - Double_t zMin, Double_t zMax) { - fOrder = 1; - fIsAllocatingLookUp = kTRUE; - - fNR = nRRow; - fNPhi = nPhiSlice; - fNZ = nZColumn; - - fLookUpR = new TMatrixD *[fNPhi]; - fLookUpPhi = new TMatrixD *[fNPhi]; - fLookUpZ = new TMatrixD *[fNPhi]; - - for (Int_t m = 0; m < fNPhi; m++) { - fLookUpR[m] = new TMatrixD(fNR, fNZ); - fLookUpPhi[m] = new TMatrixD(fNR, fNZ); - fLookUpZ[m] = new TMatrixD(fNR, fNZ); - } - - fRList = new Double_t[fNR]; - fPhiList = new Double_t[fNPhi]; - fZList = new Double_t[fNZ]; - - Double_t dR = (rMax - rMin) / fNR; - Double_t dPhi = (phiMax - phiMin) / fNPhi; - Double_t dZ = (zMax - zMin) / fNPhi; - - for (Int_t m = 0; m < fNPhi; m++) fPhiList[m] = phiMin + dPhi * m; - for (Int_t m = 0; m < fNR; m++) fRList[m] = rMin + dR * m; - for (Int_t m = 0; m < fNZ; m++) fZList[m] = zMin + dZ * m; - } - **/ - -/// Constructor -/// -/// \param nRRow Int_t size of grid in R direction -/// \param matricesRValue TMatrixD** values of component R -/// \param rList Double_t* list of position R -/// \param nPhiSlice Int_t size of grid in Phi direction -/// \param matricesPhiValue TMatrixD** values of component Phi -/// \param phiList Double_t* list of position Phi -/// \param nZColumn Int_t size of grid in Z direction -/// \param matricesZValue TMatrixD** values of component Z -/// \param zList Double_t* list of position Z -/// \param order Int_t order of interpolation -AliTPCLookUpTable3DInterpolatorD::AliTPCLookUpTable3DInterpolatorD( - Int_t nRRow, TMatrixD** matricesRValue, Double_t* rList, - Int_t nPhiSlice, TMatrixD** matricesPhiValue, Double_t* phiList, - Int_t nZColumn, TMatrixD** matricesZValue, Double_t* zList, Int_t order) -{ - fIsAllocatingLookUp = kFALSE; - - SetNR(nRRow); - SetLookUpR(matricesRValue); - SetRList(rList); - SetNPhi(nPhiSlice); - SetLookUpPhi(matricesPhiValue); - SetPhiList(phiList); - SetNZ(nZColumn); - SetLookUpZ(matricesZValue); - SetZList(zList); - - fInterpolatorR = new AliTPC3DCylindricalInterpolator(); - fInterpolatorZ = new AliTPC3DCylindricalInterpolator(); - fInterpolatorPhi = new AliTPC3DCylindricalInterpolator(); - - SetOrder(order); - fInterpolatorR->SetNR(nRRow); - fInterpolatorR->SetNZ(nZColumn); - fInterpolatorR->SetNPhi(nPhiSlice); - fInterpolatorR->SetNGridPoints(); - fInterpolatorR->SetRList(rList); - fInterpolatorR->SetZList(zList); - fInterpolatorR->SetPhiList(phiList); - fInterpolatorR->SetOrder(order); - - fInterpolatorZ->SetNR(nRRow); - fInterpolatorZ->SetNZ(nZColumn); - fInterpolatorZ->SetNPhi(nPhiSlice); - fInterpolatorZ->SetNGridPoints(); - fInterpolatorZ->SetRList(rList); - fInterpolatorZ->SetZList(zList); - fInterpolatorZ->SetPhiList(phiList); - fInterpolatorZ->SetOrder(order); - - fInterpolatorPhi->SetNR(nRRow); - fInterpolatorPhi->SetNZ(nZColumn); - fInterpolatorPhi->SetNPhi(nPhiSlice); - fInterpolatorPhi->SetNGridPoints(); - fInterpolatorPhi->SetRList(rList); - fInterpolatorPhi->SetZList(zList); - fInterpolatorPhi->SetPhiList(phiList); - fInterpolatorPhi->SetOrder(order); -} - -/// destructor -AliTPCLookUpTable3DInterpolatorD::~AliTPCLookUpTable3DInterpolatorD() -{ - delete fInterpolatorR; - delete fInterpolatorZ; - delete fInterpolatorPhi; -} - -/// copy from matrices to 1D array for interpolation algorithm -void AliTPCLookUpTable3DInterpolatorD::CopyFromMatricesToInterpolator() -{ - fInterpolatorR->SetValue(fLookUpR); - fInterpolatorZ->SetValue(fLookUpZ); - fInterpolatorPhi->SetValue(fLookUpPhi); - - if (fOrder > 2) { - fInterpolatorR->InitCubicSpline(); - fInterpolatorZ->InitCubicSpline(); - fInterpolatorPhi->InitCubicSpline(); - } -} - -/// copy from matrices to 1D array for interpolation algorithm -void AliTPCLookUpTable3DInterpolatorD::CopyFromMatricesToInterpolator(Int_t iZ) -{ - fInterpolatorR->SetValue(fLookUpR, iZ); - fInterpolatorZ->SetValue(fLookUpZ, iZ); - fInterpolatorPhi->SetValue(fLookUpPhi, iZ); - - // no implementation for cubic spline interpolation -} - -/// get value of 3-components at a P(r,phi,z) -/// -/// \param r Double_t r position -/// \param phi Double_t phi position -/// \param z Double_t z position -/// \param rValue Double_t value of r-component -/// \param phiValue Double_t value of phi-component -/// \param zValue Double_t value of z-component -void AliTPCLookUpTable3DInterpolatorD::GetValue( - Double_t r, Double_t phi, Double_t z, - Double_t& rValue, Double_t& phiValue, Double_t& zValue) const -{ - rValue = fInterpolatorR->GetValue(r, phi, z); - phiValue = fInterpolatorPhi->GetValue(r, phi, z); - zValue = fInterpolatorZ->GetValue(r, phi, z); -} - -/// get value for return value is a Float_t -/// -/// \param r Double_t r position -/// \param phi Double_t phi position -/// \param z Double_t z position -/// \param rValue Float_t value of r-component -/// \param phiValue Float_t value of phi-component -/// \param zValue Float_t value of z-component -void AliTPCLookUpTable3DInterpolatorD::GetValue( - Double_t r, Double_t phi, Double_t z, - Float_t& rValue, Float_t& phiValue, Float_t& zValue) const -{ - rValue = fInterpolatorR->GetValue(r, phi, z); - phiValue = fInterpolatorPhi->GetValue(r, phi, z); - zValue = fInterpolatorZ->GetValue(r, phi, z); -} - -// Set Order of interpolation -// -void AliTPCLookUpTable3DInterpolatorD::SetOrder(Int_t order) -{ - fOrder = order; - fInterpolatorR->SetOrder(order); - fInterpolatorZ->SetOrder(order); - fInterpolatorPhi->SetOrder(order); -} diff --git a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.h b/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.h deleted file mode 100644 index 470a84577a69e..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorD.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCLookUpTable3DInterpolatorD.h -/// \brief Wrap up look-up table for correction/distortion integral or derivative (electric field) -/// assume 3 components: r-component, phi-component and z-component -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Mar 4, 2015 - -#ifndef AliTPCLookUpTable3DInterpolatorD_H -#define AliTPCLookUpTable3DInterpolatorD_H - -#include "TMatrixD.h" -#include "AliTPC3DCylindricalInterpolator.h" - -class AliTPCLookUpTable3DInterpolatorD -{ - public: - AliTPCLookUpTable3DInterpolatorD(); - //AliTPCLookUpTable3DInterpolatorD(Int_t nRRow, Double_t rMin, Double_t rMax, Int_t nPhiSlice, Double_t phiMin, Double_t phiMax, Int_t nZColumn , Double_t zMin, Double_t zMax ); - AliTPCLookUpTable3DInterpolatorD(Int_t nRRow, TMatrixD** matricesRValue, Double_t* rList, Int_t nPhiSlice, TMatrixD** matricesPhiValue, Double_t* phiList, Int_t nZColumn, TMatrixD** matricesZValue, Double_t* zList, Int_t order); - ~AliTPCLookUpTable3DInterpolatorD(); - - void SetNR(Int_t nRRow) { fNR = nRRow; } - void SetNPhi(Int_t nPhiSlice) { fNPhi = nPhiSlice; } - void SetNZ(Int_t nZColumn) { fNZ = nZColumn; } - Int_t GetNR() { return fNR; } - Int_t GetNPhi() { return fNPhi; } - Int_t GetNZ() { return fNZ; } - - void SetRList(Double_t* rList) { fRList = rList; } - void SetPhiList(Double_t* phiList) { fPhiList = phiList; } - void SetZList(Double_t* zList) { fZList = zList; } - void SetLookUpR(TMatrixD** matricesRValue) { fLookUpR = matricesRValue; } - void SetLookUpPhi(TMatrixD** matricesPhiValue) { fLookUpPhi = matricesPhiValue; } - void SetLookUpZ(TMatrixD** matricesZValue) { fLookUpZ = matricesZValue; } - void SetOrder(Int_t order); - void GetValue(Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue) const; - void GetValue(Double_t r, Double_t phi, Double_t z, Float_t& rValue, Float_t& phiValue, Float_t& zValue) const; - void CopyFromMatricesToInterpolator(); - void CopyFromMatricesToInterpolator(Int_t iZ); // copy only iZ - - TMatrixD** GetLookUpR() { return fLookUpR; } - TMatrixD** GetLookUpPhi() { return fLookUpPhi; } - TMatrixD** GetLookUpZ() { return fLookUpZ; } - Double_t* GetRList() { return fRList; } - Double_t* GetPhiList() { return fPhiList; } - Double_t* GetZList() { return fZList; } - - AliTPC3DCylindricalInterpolator* GetInterpolatorR() { return fInterpolatorR; } - AliTPC3DCylindricalInterpolator* GetInterpolatorPhi() { return fInterpolatorPhi; } - AliTPC3DCylindricalInterpolator* GetInterpolatorZ() { return fInterpolatorZ; } - - private: - Int_t fOrder; ///< order of interpolation - Int_t fNR; ///< number of grid in R - Int_t fNPhi; ///< number of grid in Phi - Int_t fNZ; ///< number of grid in Z - - TMatrixD** fLookUpR = nullptr; //!<! Array to store distortion following the drift - TMatrixD** fLookUpPhi = nullptr; //!<! to store distortion following the drift - TMatrixD** fLookUpZ = nullptr; //!<! Array to store distortion following the drift - - AliTPC3DCylindricalInterpolator* fInterpolatorR = nullptr; //-> Interpolator for R component - AliTPC3DCylindricalInterpolator* fInterpolatorPhi = nullptr; //-> Interpolator for Phi component - AliTPC3DCylindricalInterpolator* fInterpolatorZ = nullptr; //-> Interpolator for Z component - - Double_t* fRList = nullptr; //!<! List of R coordinate (regular grid) - Double_t* fPhiList = nullptr; //!<! List of Phi coordinate (regular grid) - Double_t* fZList = nullptr; //!<! List of Z coordinate (regular grid) - - Bool_t fIsAllocatingLookUp; ///< flag for initialization of cubic spline - - /// \cond CLASSIMP - ClassDefNV(AliTPCLookUpTable3DInterpolatorD, 1); - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.cxx b/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.cxx deleted file mode 100644 index b12c36566941a..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.cxx +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCLookUpTable3DInterpolatorIrregularD.cxx -/// \brief Wrap up look-up table with irregular grid -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Mar 4, 2015 - -#include "AliTPCLookUpTable3DInterpolatorIrregularD.h" - -/// \cond CLASSIMP3 -ClassImp(AliTPCLookUpTable3DInterpolatorIrregularD); -/// \endcond - -/// constructor -AliTPCLookUpTable3DInterpolatorIrregularD::AliTPCLookUpTable3DInterpolatorIrregularD() -{ - fOrder = 1; - fIsAllocatingLookUp = kFALSE; -} - -/// constructor -/// -/// \param nRRow -/// \param matricesRValue -/// \param matricesRPoint -/// \param nPhiSlice -/// \param matricesPhiValue -/// \param matricesPhiPoint -/// \param nZColumn -/// \param matricesZValue -/// \param matricesZPoint -/// \param order -/// \param stepR -/// \param stepZ -/// \param stepPhi -/// \param type -AliTPCLookUpTable3DInterpolatorIrregularD::AliTPCLookUpTable3DInterpolatorIrregularD( - Int_t nRRow, TMatrixD** matricesRValue, TMatrixD** matricesRPoint, Int_t nPhiSlice, TMatrixD** matricesPhiValue, - TMatrixD** matricesPhiPoint, Int_t nZColumn, - TMatrixD** matricesZValue, TMatrixD** matricesZPoint, Int_t order, Int_t stepR, Int_t stepZ, Int_t stepPhi, - Int_t type) -{ - fIsAllocatingLookUp = kFALSE; - - SetNR(nRRow); - SetLookUpR(matricesRValue); - SetRList(matricesRPoint); - SetNPhi(nPhiSlice); - SetLookUpPhi(matricesPhiValue); - SetPhiList(matricesPhiPoint); - SetNZ(nZColumn); - SetLookUpZ(matricesZValue); - SetZList(matricesZPoint); - SetOrder(order); - - fInterpolatorR = new AliTPC3DCylindricalInterpolatorIrregular( - nRRow, nZColumn, nPhiSlice, stepR, stepZ, stepPhi, type); - fInterpolatorZ = new AliTPC3DCylindricalInterpolatorIrregular( - nRRow, nZColumn, nPhiSlice, stepR, stepZ, stepPhi, type); - fInterpolatorPhi = new AliTPC3DCylindricalInterpolatorIrregular( - nRRow, nZColumn, nPhiSlice, stepR, stepZ, stepPhi, type); - - fInterpolatorR->SetNR(nRRow); - fInterpolatorR->SetNZ(nZColumn); - fInterpolatorR->SetNPhi(nPhiSlice); - - fInterpolatorR->SetOrder(order); - fInterpolatorZ->SetNR(nRRow); - fInterpolatorZ->SetNZ(nZColumn); - fInterpolatorZ->SetNPhi(nPhiSlice); - fInterpolatorZ->SetOrder(order); - fInterpolatorPhi->SetNR(nRRow); - fInterpolatorPhi->SetNZ(nZColumn); - fInterpolatorPhi->SetNPhi(nPhiSlice); - fInterpolatorPhi->SetOrder(order); -} - -/// destructor -AliTPCLookUpTable3DInterpolatorIrregularD::~AliTPCLookUpTable3DInterpolatorIrregularD() -{ - delete fInterpolatorR; - delete fInterpolatorZ; - delete fInterpolatorPhi; -} - -/// copy from matrices to the interpolator -void AliTPCLookUpTable3DInterpolatorIrregularD::CopyFromMatricesToInterpolator() -{ - - fInterpolatorR->SetValue(fMatricesRValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint); - fInterpolatorZ->SetValue(fMatricesZValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint); - fInterpolatorPhi->SetValue(fMatricesPhiValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint); -} - -/// -/// \param j -void AliTPCLookUpTable3DInterpolatorIrregularD::CopyFromMatricesToInterpolator(Int_t j) -{ - fInterpolatorR->SetValue(fMatricesRValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint, j); - fInterpolatorZ->SetValue(fMatricesZValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint, j); - fInterpolatorPhi->SetValue(fMatricesPhiValue, fMatricesRPoint, fMatricesPhiPoint, fMatricesZPoint, j); -} - -/// Get interpolation -/// \param r -/// \param phi -/// \param z -/// \param rValue -/// \param phiValue -/// \param zValue -/// \param rIndex -/// \param phiIndex -/// \param zIndex -/// \param stepR -/// \param stepPhi -/// \param stepZ -void AliTPCLookUpTable3DInterpolatorIrregularD::GetValue( - Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue, - Int_t rIndex, Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ) -{ - rValue = fInterpolatorR->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ); - phiValue = fInterpolatorPhi->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ); - zValue = fInterpolatorZ->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ); -} - -/// Interpolation for a point (r,phi,z) -/// -/// \param r -/// \param phi -/// \param z -/// \param rValue -/// \param phiValue -/// \param zValue -/// \param rIndex -/// \param phiIndex -/// \param zIndex -/// \param stepR -/// \param stepPhi -/// \param stepZ -/// \param minZColumnIndex -void AliTPCLookUpTable3DInterpolatorIrregularD::GetValue( - Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue, Int_t rIndex, - Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, Int_t minZColumnIndex) -{ - rValue = fInterpolatorR->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ, minZColumnIndex); - phiValue = fInterpolatorPhi->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ, minZColumnIndex); - zValue = fInterpolatorZ->GetValue(r, phi, z, rIndex, phiIndex, zIndex, stepR, stepPhi, stepZ, minZColumnIndex); -} - -/// Get interpolation -/// \param r -/// \param phi -/// \param z -/// \param rValue -/// \param phiValue -/// \param zValue -/// \param rIndex -/// \param phiIndex -/// \param zIndex -/// \param startR -/// \param startPhi -/// \param startZ -void AliTPCLookUpTable3DInterpolatorIrregularD::GetValue( - Double_t r, Double_t phi, Double_t z, Float_t& rValue, Float_t& phiValue, Float_t& zValue, Int_t rIndex, - Int_t phiIndex, Int_t zIndex, Int_t startR, Int_t startPhi, Int_t startZ) -{ - rValue = fInterpolatorR->GetValue(r, phi, z, rIndex, phiIndex, zIndex, startR, startPhi, startZ); - phiValue = fInterpolatorPhi->GetValue(r, phi, z, rIndex, phiIndex, zIndex, startR, startPhi, startZ); - zValue = fInterpolatorZ->GetValue(r, phi, z, rIndex, phiIndex, zIndex, startR, startPhi, startZ); -} - -// using kdtree -void AliTPCLookUpTable3DInterpolatorIrregularD::GetValue( - Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue) -{ - rValue = fInterpolatorR->GetValue(r, phi, z); - phiValue = fInterpolatorPhi->GetValue(r, phi, z); - zValue = fInterpolatorZ->GetValue(r, phi, z); -} diff --git a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.h b/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.h deleted file mode 100644 index f7466360f3f85..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCLookUpTable3DInterpolatorIrregularD.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCLookUpTable3DInterpolatorIrregularD.h -/// \brief Wrap up look-up table with irregular grid -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Mar 4, 2015 - -#ifndef AliTPCLookUpTable3DInterpolatorIrregularD_H -#define AliTPCLookUpTable3DInterpolatorIrregularD_H - -#include "TMatrixD.h" -#include "AliTPC3DCylindricalInterpolatorIrregular.h" - -class AliTPCLookUpTable3DInterpolatorIrregularD -{ - public: - void SetNR(Int_t nRRow) { fNR = nRRow; } - void SetNPhi(Int_t nPhiSlice) { fNPhi = nPhiSlice; } - void SetNZ(Int_t nZColumn) { fNZ = nZColumn; } - - Int_t GetNR() { return fNR; } - Int_t GetNPhi() { return fNPhi; } - Int_t GetNZ() { return fNZ; } - - void SetRList(TMatrixD** matricesRPoint) { fMatricesRPoint = matricesRPoint; } - void SetPhiList(TMatrixD** matricesPhiPoint) { fMatricesPhiPoint = matricesPhiPoint; } - void SetZList(TMatrixD** matricesZPoint) { fMatricesZPoint = matricesZPoint; } - - void SetLookUpR(TMatrixD** matricesRValue) { fMatricesRValue = matricesRValue; } - void SetLookUpPhi(TMatrixD** matricesPhiValue) { fMatricesPhiValue = matricesPhiValue; } - void SetLookUpZ(TMatrixD** matricesZValue) { fMatricesZValue = matricesZValue; } - - AliTPCLookUpTable3DInterpolatorIrregularD(); - AliTPCLookUpTable3DInterpolatorIrregularD(Int_t nRRow, TMatrixD** matricesRValue, TMatrixD** r, Int_t nPhiSlice, - TMatrixD** matricesPhiValue, TMatrixD** matricesPhiPoint, Int_t nZColumn, - TMatrixD** matricesZValue, TMatrixD** matricesZPoint, Int_t order, - Int_t stepR, Int_t stepZ, Int_t stepPhi, Int_t type); - - ~AliTPCLookUpTable3DInterpolatorIrregularD(); - - void GetValue(Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue, Int_t rIndex, - Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ); - void GetValue(Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue, Int_t rIndex, - Int_t phiIndex, Int_t zIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ, Int_t minZColumnIndex); - void GetValue(Double_t r, Double_t phi, Double_t z, Float_t& rValue, Float_t& phiValue, Float_t& zValue, Int_t rIndex, Int_t phiIndex, - Int_t zIndex, Int_t stepR, Int_t stepPhi, Int_t stepZ); - void GetValue(Double_t r, Double_t phi, Double_t z, Double_t& rValue, Double_t& phiValue, Double_t& zValue); - void SetOrder(Int_t order) { fOrder = order; } - void CopyFromMatricesToInterpolator(); - void CopyFromMatricesToInterpolator(Int_t j); - - Int_t GetIrregularGridSize() { return fInterpolatorR->GetIrregularGridSize(); } - void SetIrregularGridSize(Int_t size) - { - fInterpolatorR->SetIrregularGridSize(size); - fInterpolatorPhi->SetIrregularGridSize(size); - fInterpolatorZ->SetIrregularGridSize(size); - } - void SetKernelType(Int_t kernelType) - { - fInterpolatorR->SetKernelType(kernelType); - fInterpolatorPhi->SetKernelType(kernelType); - fInterpolatorZ->SetKernelType(kernelType); - } - Int_t GetKernelType() { return fInterpolatorR->GetKernelType(); } - - private: - Int_t fOrder; ///< Order of interpolation - Int_t fIrregularGridSize; ///< Size of irregular interpolation neighborhood - Int_t fNR; ///< Number of grid in R - Int_t fNPhi; ///< Number of grid in Phi - Int_t fNZ; ///< Number of grid in Z - - TMatrixD** fMatricesRValue = nullptr; //!<! Matrices to store r-component - TMatrixD** fMatricesPhiValue = nullptr; //!<! Matrices to store phi-component - TMatrixD** fMatricesZValue = nullptr; //!<! Matrices to store z-component - - AliTPC3DCylindricalInterpolatorIrregular* fInterpolatorR = nullptr; //-> Irregular interpolator for R-component - AliTPC3DCylindricalInterpolatorIrregular* fInterpolatorPhi = nullptr; //-> Irregular interpolator for Phi-component - AliTPC3DCylindricalInterpolatorIrregular* fInterpolatorZ = nullptr; //-> Irregular interpolator for Z-component - - TMatrixD** fMatricesRPoint = nullptr; //!<! Matrices to store distorted point (r component) - TMatrixD** fMatricesPhiPoint = nullptr; //!<! Matrices to store distorted point (phi component) - TMatrixD** fMatricesZPoint = nullptr; //!<! Matrices to store distorted point (z component) - - Bool_t fIsAllocatingLookUp; - - /// \cond CLASSIMP - ClassDefNV(AliTPCLookUpTable3DInterpolatorIrregularD, 1); - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.cxx b/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.cxx deleted file mode 100644 index bf789cedfcb68..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.cxx +++ /dev/null @@ -1,3031 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCPoissonSolver.cxx -/// \brief This class provides implementation of Poisson Eq -/// solver by MultiGrid Method -/// -/// -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Nov 20, 2017 - -#include <TMath.h> -#include "AliTPCPoissonSolver.h" - -/// \cond CLASSIMP -ClassImp(AliTPCPoissonSolver); -/// \endcond - -const Double_t AliTPCPoissonSolver::fgkTPCZ0 = 249.7; ///< nominal gating grid position -const Double_t AliTPCPoissonSolver::fgkIFCRadius = 83.5; ///< radius which renders the "18 rod manifold" best -> compare calc. of Jim Thomas -const Double_t AliTPCPoissonSolver::fgkOFCRadius = 254.5; ///< Mean Radius of the Outer Field Cage (252.55 min, 256.45 max) (cm) -const Double_t AliTPCPoissonSolver::fgkZOffSet = 0.2; ///< Offset from CE: calculate all distortions closer to CE as if at this point -const Double_t AliTPCPoissonSolver::fgkCathodeV = -100000.0; ///< Cathode Voltage (volts) -const Double_t AliTPCPoissonSolver::fgkGG = -70.0; ///< Gating Grid voltage (volts) -const Double_t AliTPCPoissonSolver::fgkdvdE = 0.0024; ///< [cm/V] drift velocity dependency on the E field (from Magboltz for NeCO2N2 at standard environment) -const Double_t AliTPCPoissonSolver::fgkEM = -1.602176487e-19 / 9.10938215e-31; ///< charge/mass in [C/kg] -const Double_t AliTPCPoissonSolver::fgke0 = 8.854187817e-12; ///< vacuum permittivity [A·s/(V·m)] - -Double_t AliTPCPoissonSolver::fgExactErr = 1e-4; -Double_t AliTPCPoissonSolver::fgConvergenceError = 1e-3; - -/// constructor -/// -AliTPCPoissonSolver::AliTPCPoissonSolver() - : TNamed("poisson solver", "solver"), - fErrorConvergenceNorm2{new TVectorD(fMgParameters.nMGCycle)}, - fErrorConvergenceNormInf{new TVectorD(fMgParameters.nMGCycle)}, - fError{new TVectorD(fMgParameters.nMGCycle)} - -{ - // default strategy -} - -/// Constructor -/// \param name name of the object -/// \param title title of the object -AliTPCPoissonSolver::AliTPCPoissonSolver(const char* name, const char* title) - : TNamed(name, title), - fErrorConvergenceNorm2{new TVectorD(fMgParameters.nMGCycle)}, - fErrorConvergenceNormInf{new TVectorD(fMgParameters.nMGCycle)}, - fError{new TVectorD(fMgParameters.nMGCycle)} -{ - /// constructor -} - -/// destructor -AliTPCPoissonSolver::~AliTPCPoissonSolver() -{ - /// virtual destructor - delete[] fExactSolution; - delete fErrorConvergenceNorm2; - delete fErrorConvergenceNormInf; - delete fError; -} - -/// Provides poisson solver in 2D -/// -/// Based on the strategy (relaxation, multi grid or FFT) -/// -/// \param matrixV TMatrixD& potential in matrix -/// \param matrixCharge TMatrixD& charge density in matrix (side effect -/// \param nRRow Int_t number of nRRow in the grid -/// \param nZColumn Int_t number of nZColumn in the grid -/// \param maxIteration Int_t maximum iteration for relaxation method -/// -/// \return A fixed number that has nothing to do with what the function does -void AliTPCPoissonSolver::PoissonSolver2D(TMatrixD& matrixV, TMatrixD& matrixCharge, Int_t nRRow, Int_t nZColumn, - Int_t maxIteration) -{ - switch (fStrategy) { - case kMultiGrid: - PoissonMultiGrid2D(matrixV, matrixCharge, nRRow, nZColumn); - break; - default: - PoissonRelaxation2D(matrixV, matrixCharge, nRRow, nZColumn, maxIteration); - } -} - -/// Provides poisson solver in Cylindrical 3D (TPC geometry) -/// -/// Strategy based on parameter settings (fStrategy and fMgParameters)provided -/// * Cascaded multi grid with S.O.R -/// * Geometric MultiGrid -/// * Cycles: V, W, Full -/// * Relaxation: Jacobi, Weighted-Jacobi, Gauss-Seidel -/// * Grid transfer operators: Full, Half -/// * Spectral Methods (TODO) -/// -/// \param matricesV TMatrixD** potential in 3D matrix -/// \param matricesCharge TMatrixD** charge density in 3D matrix (side effect) -/// \param nRRow Int_t number of nRRow in the r direction of TPC -/// \param nZColumn Int_t number of nZColumn in z direction of TPC -/// \param phiSlice Int_t number of phiSlice in phi direction of T{C -/// \param maxIteration Int_t maximum iteration for relaxation method -/// \param symmetry Int_t symmetry or not -/// -/// \pre Charge density distribution in **matricesCharge** is known and boundary values for **matricesV** are set -/// \post Numerical solution for potential distribution is calculated and stored in each rod at **matricesV** -void AliTPCPoissonSolver::PoissonSolver3D(TMatrixD** matricesV, TMatrixD** matricesCharge, - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, - Int_t symmetry) -{ - switch (fStrategy) { - case kMultiGrid: - if (fMgParameters.isFull3D) { - PoissonMultiGrid3D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, symmetry); - } else { - PoissonMultiGrid3D2D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, symmetry); - } - break; - default: - PoissonRelaxation3D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, maxIteration, symmetry); - } -} - -/// Solve Poisson's Equation by Relaxation Technique in 2D (assuming cylindrical symmetry) -/// -/// Solve Poisson's equation in a cylindrical coordinate system. The matrixV matrix must be filled with the -/// boundary conditions on the first and last nRRow, and the first and last nZColumn. The remainder of the -/// array can be blank or contain a preliminary guess at the solution. The Charge density matrix contains -/// the enclosed spacecharge density at each point. The charge density matrix can be full of zero's if -/// you wish to solve Laplace equation however it should not contain random numbers or you will get -/// random numbers back as a solution. -/// Poisson's equation is solved by iteratively relaxing the matrix to the final solution. In order to -/// speed up the convergence to the best solution, this algorithm does a binary expansion of the solution -/// space. First it solves the problem on a very sparse grid by skipping nRRow and nZColumn in the original -/// matrix. Then it doubles the number of points and solves the problem again. Then it doubles the -/// number of points and solves the problem again. This happens several times until the maximum number -/// of points has been included in the array. -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// So nRRow == 2**M + 1 and nZColumn == 2**N + 1. The number of nRRow and nZColumn can be different. -/// -/// Method for relaxation: S.O.R Weighted Jacobi -/// -/// \param matrixV TMatrixD& potential in matrix -/// \param matrixCharge TMatrixD& charge density in matrix (side effect -/// \param nRRow Int_t number of nRRow in the grid -/// \param nZColumn Int_t number of nZColumn in the grid -/// \param maxIteration Int_t maximum iteration for relaxation method -/// -/// \return A fixed number that has nothing to do with what the function does -/// -/// -/// Original code by Jim Thomas (STAR TPC Collaboration) -void AliTPCPoissonSolver::PoissonRelaxation2D(TMatrixD& matrixV, TMatrixD& matrixCharge, Int_t nRRow, Int_t nZColumn, - Int_t maxIteration) -{ - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t ratio = gridSizeR * gridSizeR / (gridSizeZ * gridSizeZ); - - TMatrixD arrayEr(nRRow, nZColumn); - TMatrixD arrayEz(nRRow, nZColumn); - - //Check that number of nRRow and nZColumn is suitable for a binary expansion - - if (!IsPowerOfTwo(nRRow - 1)) { - Error("PoissonRelaxation2D", "PoissonRelaxation - Error in the number of nRRow. Must be 2**M - 1"); - return; - } - - if (!IsPowerOfTwo(nZColumn - 1)) { - Error("PoissonRelaxation2D", "PoissonRelaxation - Error in the number of nZColumn. Must be 2**N - 1"); - return; - } - - // Solve Poisson's equation in cylindrical coordinates by relaxation technique - // Allow for different size grid spacing in R and Z directions - // Use a binary expansion of the size of the matrix to speed up the solution of the problem - - Int_t iOne = (nRRow - 1) / 4; - Int_t jOne = (nZColumn - 1) / 4; - - // Coarse until nLoop - Int_t nLoop = 1 + (int)(0.5 + TMath::Log2((double)TMath::Max(iOne, jOne))); - - // Loop while the matrix expands & the resolution increases. - for (Int_t count = 0; count < nLoop; count++) { - - Float_t tempGridSizeR = gridSizeR * iOne; - Float_t tempRatio = ratio * iOne * iOne / (jOne * jOne); - Float_t tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - - // Do this the standard C++ way to avoid gcc extensions for Float_t coefficient1[nRRow] - std::vector<float> coefficient1(nRRow); - std::vector<float> coefficient2(nRRow); - - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - Float_t radius = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - coefficient1[i] = 1.0 + tempGridSizeR / (2 * radius); - coefficient2[i] = 1.0 - tempGridSizeR / (2 * radius); - } - - TMatrixD sumChargeDensity(nRRow, nZColumn); - - // average charge at the coarse point - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - Float_t radius = AliTPCPoissonSolver::fgkIFCRadius + iOne * gridSizeR; - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - if (iOne == 1 && jOne == 1) { - sumChargeDensity(i, j) = matrixCharge(i, j); - } else { - // Add up all enclosed charge density contributions within 1/2 unit in all directions - Float_t weight = 0.0; - Float_t sum = 0.0; - sumChargeDensity(i, j) = 0.0; - for (Int_t ii = i - iOne / 2; ii <= i + iOne / 2; ii++) { - for (Int_t jj = j - jOne / 2; jj <= j + jOne / 2; jj++) { - if (ii == i - iOne / 2 || ii == i + iOne / 2 || jj == j - jOne / 2 || jj == j + jOne / 2) { - weight = 0.5; - } else { - weight = 1.0; - } - sumChargeDensity(i, j) += matrixCharge(ii, jj) * weight * radius; - sum += weight * radius; - } - } - sumChargeDensity(i, j) /= sum; - } - sumChargeDensity(i, j) *= tempGridSizeR * tempGridSizeR; // just saving a step later on - } - } - - // Iterate on the current level - for (Int_t k = 1; k <= maxIteration; k++) { - // Solve Poisson's Equation - // Over-relaxation index, must be >= 1 but < 2. Arrange for it to evolve from 2 => 1 - // as iteration increase. - Float_t overRelax = 1.0 + TMath::Sqrt(TMath::Cos((k * TMath::PiOver2()) / maxIteration)); - Float_t overRelaxM1 = overRelax - 1.0; - Float_t overRelaxTemp4, overRelaxCoefficient5; - overRelaxTemp4 = overRelax * tempFourth; - overRelaxCoefficient5 = overRelaxM1 / overRelaxTemp4; - - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - // S.O.R - // - matrixV(i, j) = (coefficient2[i] * matrixV(i - iOne, j) + tempRatio * (matrixV(i, j - jOne) + matrixV(i, j + jOne)) - overRelaxCoefficient5 * matrixV(i, j) + coefficient1[i] * matrixV(i + iOne, j) + sumChargeDensity(i, j)) * overRelaxTemp4; - } - } - - // if already at maxIteration - // TODO: stop when it converged - if (k == maxIteration) { - - // After full solution is achieved, copy low resolution solution into higher res array - // Interpolate solution - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - if (iOne > 1) { - matrixV(i + iOne / 2, j) = (matrixV(i + iOne, j) + matrixV(i, j)) / 2; - if (i == iOne) { - matrixV(i - iOne / 2, j) = (matrixV(0, j) + matrixV(iOne, j)) / 2; - } - } - if (jOne > 1) { - matrixV(i, j + jOne / 2) = (matrixV(i, j + jOne) + matrixV(i, j)) / 2; - if (j == jOne) { - matrixV(i, j - jOne / 2) = (matrixV(i, 0) + matrixV(i, jOne)) / 2; - } - } - if (iOne > 1 && jOne > 1) { - matrixV(i + iOne / 2, j + jOne / 2) = (matrixV(i + iOne, j + jOne) + matrixV(i, j)) / 2; - if (i == iOne) { - matrixV(i - iOne / 2, j - jOne / 2) = (matrixV(0, j - jOne) + matrixV(iOne, j)) / 2; - } - if (j == jOne) { - matrixV(i - iOne / 2, j - jOne / 2) = (matrixV(i - iOne, 0) + matrixV(i, jOne)) / 2; - } - // Note that this leaves a point at the upper left and lower right corners uninitialized. - // -> Not a big deal. - } - } - } - } - } - - iOne = iOne / 2; - if (iOne < 1) { - iOne = 1; - } - jOne = jOne / 2; - if (jOne < 1) { - jOne = 1; - } - sumChargeDensity.Clear(); - } -} - -/// Solve Poisson's Equation by MultiGrid Technique in 2D (assuming cylindrical symmetry) -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// So nRRow == 2**M + 1 and nZColumn == 2**N + 1. The number of nRRow and nZColumn can be different. -/// -/// \param matrixV TMatrixD& potential in matrix -/// \param matrixCharge TMatrixD& charge density in matrix (side effect -/// \param nRRow Int_t number of nRRow -/// \param nZColumn Int_t number of nZColumn -/// \param maxIteration Int_t maximum iteration for relaxation method -/// -/// \return A fixed number that has nothing to do with what the function does -void AliTPCPoissonSolver::PoissonMultiGrid2D(TMatrixD& matrixV, TMatrixD& matrixCharge, Int_t nRRow, Int_t nZColumn) -{ - /// Geometry of TPC -- should be use AliTPCParams instead - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t ratio = gridSizeR * gridSizeR / (gridSizeZ * gridSizeZ); - - Int_t nGridRow = 0; // number grid - Int_t nGridCol = 0; // number grid - Int_t nnRow; - Int_t nnCol; - - nnRow = nRRow; - while (nnRow >>= 1) { - nGridRow++; - } - - nnCol = nZColumn; - while (nnCol >>= 1) { - nGridCol++; - } - - //Check that number of nRRow and nZColumn is suitable for multi grid - if (!IsPowerOfTwo(nRRow - 1)) { - Error("PoissonMultiGrid2D", "PoissonMultiGrid - Error in the number of nRRow. Must be 2**M - 1"); - return; - } - if (!IsPowerOfTwo(nZColumn - 1)) { - Error("PoissonMultiGrid2D", "PoissonMultiGrid - Error in the number of nZColumn. Must be 2**N - 1"); - return; - } - - Int_t nLoop = TMath::Max(nGridRow, nGridCol); // Calculate the number of nLoop for the binary expansion - - Info("PoissonMultiGrid2D", "%s", Form("nGridRow=%d, nGridCol=%d, nLoop=%d, nMGCycle=%d", nGridRow, nGridCol, nLoop, fMgParameters.nMGCycle)); - - Float_t h, h2, radius; - Int_t iOne = 1; // in/dex - Int_t jOne = 1; // index - Int_t tnRRow = nRRow, tnZColumn = nZColumn; - Int_t count; - Float_t tempRatio, tempFourth; - - // Vector for storing multi grid array - std::vector<TMatrixD*> tvChargeFMG(nLoop); - std::vector<TMatrixD*> tvArrayV(nLoop); - std::vector<TMatrixD*> tvCharge(nLoop); - std::vector<TMatrixD*> tvResidue(nLoop); - - // Allocate memory for temporary grid - for (count = 1; count <= nLoop; count++) { - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - // if one just address to matrixV - tvResidue[count - 1] = new TMatrixD(tnRRow, tnZColumn); - if (count == 1) { - tvChargeFMG[count - 1] = &matrixCharge; - tvArrayV[count - 1] = &matrixV; - tvCharge[count - 1] = &matrixCharge; - } else { - tvArrayV[count - 1] = new TMatrixD(tnRRow, tnZColumn); - tvCharge[count - 1] = new TMatrixD(tnRRow, tnZColumn); - tvChargeFMG[count - 1] = new TMatrixD(tnRRow, tnZColumn); - Restrict2D(*tvChargeFMG[count - 1], *tvChargeFMG[count - 2], tnRRow, tnZColumn); - } - iOne = 2 * iOne; - jOne = 2 * jOne; - } - - /// full multi grid - if (fMgParameters.cycleType == kFCycle) { - - Info("PoissonMultiGrid2D", "Do full cycle"); - // FMG - // 1) Relax on the coarsest grid - iOne = iOne / 2; - jOne = jOne / 2; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - h = gridSizeR * count; - h2 = h * h; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - - std::vector<float> coefficient1(tnRRow); - std::vector<float> coefficient2(tnRRow); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - - Relax2D(*tvArrayV[nLoop - 1], *tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - - // Do VCycle from nLoop H to h - for (count = nLoop - 2; count >= 0; count--) { - - iOne = iOne / 2; - jOne = jOne / 2; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - Interp2D(*tvArrayV[count], *tvArrayV[count + 1], tnRRow, tnZColumn); - // Copy the relax charge to the tvCharge - *tvCharge[count] = *tvChargeFMG[count]; //copy - //tvCharge[count]->Print(); - // Do V cycle - - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - - VCycle2D(nRRow, nZColumn, count + 1, nLoop, fMgParameters.nPre, fMgParameters.nPost, gridSizeR, ratio, tvArrayV, - tvCharge, tvResidue); - } - } - } else if (fMgParameters.cycleType == kVCycle) { - // 2. VCycle - Info("PoissonMultiGrid2D", "Do V cycle"); - - Int_t gridFrom = 1; - Int_t gridTo = nLoop; - - // Do MGCycle - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - VCycle2D(nRRow, nZColumn, gridFrom, gridTo, fMgParameters.nPre, fMgParameters.nPost, gridSizeR, ratio, tvArrayV, - tvCharge, tvResidue); - } - } else if (fMgParameters.cycleType == kWCycle) { - - // 3. W Cycle (TODO:) - - Int_t gridFrom = 1; - - //nLoop = nLoop >= 4 ? 4 : nLoop; - - Int_t gridTo = nLoop; - //Int_t gamma = 1; - - // Do MGCycle - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - WCycle2D(nRRow, nZColumn, gridFrom, gridTo, fMgParameters.gamma, fMgParameters.nPre, fMgParameters.nPost, - gridSizeR, ratio, tvArrayV, tvCharge, tvResidue); - } - } - - // Deallocate memory - for (count = nLoop; count >= 1; count--) { - // if one just address to matrixV - if (count > 1) { - delete tvArrayV[count - 1]; - delete tvCharge[count - 1]; - delete tvChargeFMG[count - 1]; - } - delete tvResidue[count - 1]; - } -} - -/// 3D - Solve Poisson's Equation in 3D by Relaxation Technique -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slice == Arbitrary but greater than 3 -/// -/// DeltaPhi in Radians -/// -/// SYMMETRY = 0 if no phi symmetries, and no phi boundary conditions -/// = 1 if we have reflection symmetry at the boundaries (eg. sector symmetry or half sector symmetries). -/// -/// \param matricesV TMatrixD** potential in 3D matrix -/// \param matricesCharge TMatrixD** charge density in 3D matrix (side effect) -/// \param nRRow Int_t number of nRRow in the r direction of TPC -/// \param nZColumn Int_t number of nZColumn in z direction of TPC -/// \param phiSlice Int_t number of phiSlice in phi direction of T{C -/// \param maxIteration Int_t maximum iteration for relaxation method -/// \param symmetry Int_t symmetry or not -/// -void AliTPCPoissonSolver::PoissonRelaxation3D(TMatrixD** matricesV, TMatrixD** matricesCharge, - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, - Int_t symmetry) -{ - - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t ratioPhi = gridSizeR * gridSizeR / (gridSizePhi * gridSizePhi); - const Float_t ratioZ = gridSizeR * gridSizeR / (gridSizeZ * gridSizeZ); - - Info("PoissonRelaxation3D", "%s", Form("in Poisson Solver 3D relaxation nRRow=%d, cols=%d, phiSlice=%d \n", nRRow, nZColumn, phiSlice)); - // Check that the number of nRRow and nZColumn is suitable for a binary expansion - if (!IsPowerOfTwo((nRRow - 1))) { - Error("PoissonRelaxation3D", "Poisson3DRelaxation - Error in the number of nRRow. Must be 2**M - 1"); - return; - } - if (!IsPowerOfTwo((nZColumn - 1))) { - Error("PoissonRelaxation3D", "Poisson3DRelaxation - Error in the number of nZColumn. Must be 2**N - 1"); - return; - } - if (phiSlice <= 3) { - Error("PoissonRelaxation3D", "Poisson3DRelaxation - Error in the number of phiSlice. Must be larger than 3"); - return; - } - if (phiSlice > 1000) { - Error("PoissonRelaxation3D", "Poisson3D phiSlice > 1000 is not allowed (nor wise) "); - return; - } - - // Solve Poisson's equation in cylindrical coordinates by relaxation technique - // Allow for different size grid spacing in R and Z directions - // Use a binary expansion of the matrix to speed up the solution of the problem - - Int_t nLoop, mPlus, mMinus, signPlus, signMinus; - Int_t iOne = (nRRow - 1) / 4; - Int_t jOne = (nZColumn - 1) / 4; - nLoop = TMath::Max(iOne, jOne); // Calculate the number of nLoop for the binary expansion - nLoop = 1 + (int)(0.5 + TMath::Log2((double)nLoop)); // Solve for N in 2**N - - TMatrixD* matricesSumChargeDensity[1000]; // Create temporary arrays to store low resolution charge arrays - - std::vector<float> coefficient1( - nRRow); // Do this the standard C++ way to avoid gcc extensions for Float_t coefficient1[nRRow] - std::vector<float> coefficient2( - nRRow); // Do this the standard C++ way to avoid gcc extensions for Float_t coefficient1[nRRow] - std::vector<float> coefficient3( - nRRow); // Do this the standard C++ way to avoid gcc extensions for Float_t coefficient1[nRRow] - std::vector<float> coefficient4( - nRRow); // Do this the standard C++ way to avoid gcc extensions for Float_t coefficient1[nRRow] - std::vector<float> overRelaxCoefficient4(nRRow); // Do this the standard C++ way to avoid gcc extensions - std::vector<float> overRelaxCoefficient5(nRRow); // Do this the standard C++ way to avoid gcc extensions - for (Int_t i = 0; i < phiSlice; i++) { - matricesSumChargeDensity[i] = new TMatrixD(nRRow, nZColumn); - } - - ///// Test of Convergence - TMatrixD* prevArrayV[phiSlice]; - - for (Int_t m = 0; m < phiSlice; m++) { - prevArrayV[m] = new TMatrixD(nRRow, nZColumn); - } - ///// - - // START the master loop and do the binary expansion - for (Int_t count = 0; count < nLoop; count++) { - Float_t tempGridSizeR = gridSizeR * iOne; - Float_t tempRatioPhi = ratioPhi * iOne * iOne; - Float_t tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - Float_t radius = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - coefficient1[i] = 1.0 + tempGridSizeR / (2 * radius); - coefficient2[i] = 1.0 - tempGridSizeR / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - for (Int_t m = 0; m < phiSlice; m++) { - TMatrixD& matrixCharge = *matricesCharge[m]; - TMatrixD& sumChargeDensity = *matricesSumChargeDensity[m]; - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - Float_t radius = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - if (iOne == 1 && jOne == 1) { - sumChargeDensity(i, j) = matrixCharge(i, j); - } else { // Add up all enclosed charge density contributions within 1/2 unit in all directions - Float_t weight = 0.0; - Float_t sum = 0.0; - sumChargeDensity(i, j) = 0.0; - for (Int_t ii = i - iOne / 2; ii <= i + iOne / 2; ii++) { - for (Int_t jj = j - jOne / 2; jj <= j + jOne / 2; jj++) { - if (ii == i - iOne / 2 || ii == i + iOne / 2 || jj == j - jOne / 2 || jj == j + jOne / 2) { - weight = 0.5; - } else { - weight = 1.0; - } - sumChargeDensity(i, j) += matrixCharge(ii, jj) * weight * radius; - sum += weight * radius; - } - } - sumChargeDensity(i, j) /= sum; - } - sumChargeDensity(i, j) *= tempGridSizeR * tempGridSizeR; // just saving a step later on - } - } - } - - for (Int_t k = 1; k <= maxIteration; k++) { - if (count == nLoop - 1) { - //// Test of Convergence - for (Int_t m = 0; m < phiSlice; m++) { - (*prevArrayV[m]) = (*matricesV[m]); - } - //// - } - - Float_t overRelax = 1.0 + TMath::Sqrt(TMath::Cos((k * TMath::PiOver2()) / maxIteration)); - Float_t overRelaxM1 = overRelax - 1.0; - - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - overRelaxCoefficient4[i] = overRelax * coefficient4[i]; - overRelaxCoefficient5[i] = overRelaxM1 / overRelaxCoefficient4[i]; - } - - for (Int_t m = 0; m < phiSlice; m++) { - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - if (symmetry == 1) { // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } else if (symmetry == -1) { // Anti-symmetry in phi - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - } - - TMatrixD& matrixV = *matricesV[m]; - TMatrixD& matrixVP = *matricesV[mPlus]; - TMatrixD& matrixVM = *matricesV[mMinus]; - TMatrixD& sumChargeDensity = *matricesSumChargeDensity[m]; - Double_t* matrixVFast = matrixV.GetMatrixArray(); - Double_t* matrixVPFast = matrixVP.GetMatrixArray(); - Double_t* matrixVMFast = matrixVM.GetMatrixArray(); - Double_t* sumChargeDensityFast = sumChargeDensity.GetMatrixArray(); - - if (fStrategy == kRelaxation) { - // slow implementation - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - - matrixV(i, j) = (coefficient2[i] * matrixV(i - iOne, j) + tempRatioZ * (matrixV(i, j - jOne) + matrixV(i, j + jOne)) - overRelaxCoefficient5[i] * matrixV(i, j) + coefficient1[i] * matrixV(i + iOne, j) + coefficient3[i] * (signPlus * matrixVP(i, j) + signMinus * matrixVM(i, j)) + sumChargeDensity(i, j)) * overRelaxCoefficient4[i]; - // Note: over-relax the solution at each step. This speeds up the convergence. - } - } - } else { - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - Double_t* matrixVFastI = &(matrixVFast[i * nZColumn]); - Double_t* matrixVPFastI = &(matrixVPFast[i * nZColumn]); - Double_t* matrixVMFastI = &(matrixVMFast[i * nZColumn]); - Double_t* sumChargeDensityFastI = &(sumChargeDensityFast[i * nZColumn]); - - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - Double_t /*resSlow*/ resFast; - - resFast = (coefficient2[i] * matrixVFastI[j - nZColumn * iOne] + tempRatioZ * (matrixVFastI[j - jOne] + matrixVFastI[j + jOne]) - overRelaxCoefficient5[i] * matrixVFastI[j] + coefficient1[i] * matrixVFastI[j + nZColumn * iOne] + coefficient3[i] * (signPlus * matrixVPFastI[j] + signMinus * matrixVMFastI[j]) + sumChargeDensityFastI[j]) * overRelaxCoefficient4[i]; - matrixVFastI[j] = resFast; - // Note: over-relax the solution at each step. This speeds up the convergence. - } // end j - } //end i - } // end phi - - // After full solution is achieved, copy low resolution solution into higher res array - if (k == maxIteration) { - for (Int_t i = iOne; i < nRRow - 1; i += iOne) { - for (Int_t j = jOne; j < nZColumn - 1; j += jOne) { - - if (iOne > 1) { - matrixV(i + iOne / 2, j) = (matrixV(i + iOne, j) + matrixV(i, j)) / 2; - if (i == iOne) { - matrixV(i - iOne / 2, j) = (matrixV(0, j) + matrixV(iOne, j)) / 2; - } - } - if (jOne > 1) { - matrixV(i, j + jOne / 2) = (matrixV(i, j + jOne) + matrixV(i, j)) / 2; - if (j == jOne) { - matrixV(i, j - jOne / 2) = (matrixV(i, 0) + matrixV(i, jOne)) / 2; - } - } - if (iOne > 1 && jOne > 1) { - matrixV(i + iOne / 2, j + jOne / 2) = (matrixV(i + iOne, j + jOne) + matrixV(i, j)) / 2; - if (i == iOne) { - matrixV(i - iOne / 2, j - jOne / 2) = (matrixV(0, j - jOne) + matrixV(iOne, j)) / 2; - } - if (j == jOne) { - matrixV(i - iOne / 2, j - jOne / 2) = (matrixV(i - iOne, 0) + matrixV(i, jOne)) / 2; - } - // Note that this leaves a point at the upper left and lower right corners uninitialized. Not a big deal. - } - } - } - } - } - - if (count == nLoop - 1) { - - (*fErrorConvergenceNormInf)(k - 1) = GetConvergenceError(matricesV, prevArrayV, phiSlice); - (*fError)(k - 1) = GetExactError(matricesV, prevArrayV, phiSlice); - - // if error already achieved then stop mg iteration - fIterations = k - 1; - if ((*fErrorConvergenceNormInf)(k - 1) <= fgConvergenceError) { - Info("PoissonRelaxation3D", "%s", Form("Exact Err: %f, Iteration : %d", (*fError)(k - 1), k - 1)); - break; - } - if (k == maxIteration) { - Info("PoissonRelaxation3D", "%s", Form("Exact Err: %f, Iteration : %d", (*fError)(k - 1), k - 1)); - } - } - } - - iOne = iOne / 2; - if (iOne < 1) { - iOne = 1; - } - jOne = jOne / 2; - if (jOne < 1) { - jOne = 1; - } - } - - for (Int_t k = 0; k < phiSlice; k++) { - matricesSumChargeDensity[k]->Delete(); - } - - for (Int_t m = 0; m < phiSlice; m++) { - delete prevArrayV[m]; - } -} - -/// 3D - Solve Poisson's Equation in 3D by MultiGrid with constant phi slices -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slice == Arbitrary but greater than 3 -/// -/// Solving: \f$ \nabla^{2}V(r,\phi,z) = - f(r,\phi,z) \f$ -/// -/// Algorithm for MultiGrid Full Cycle (FMG) -/// - Relax on the coarsest grid -/// - Do from coarsest to finest -/// - Interpolate potential from coarse -> fine -/// - Do V-Cycle to the current coarse level to the coarsest -/// - Stop if converged -/// -/// DeltaPhi in Radians -/// \param matricesV TMatrixD** potential in 3D matrix \f$ V(r,\phi,z) \f$ -/// \param matricesCharge TMatrixD** charge density in 3D matrix (side effect) \f$ - f(r,\phi,z) \f$ -/// \param nRRow Int_t number of nRRow in the r direction of TPC -/// \param nZColumn Int_t number of nZColumn in z direction of TPC -/// \param phiSlice Int_t number of phiSlice in phi direction of T{C -/// \param maxIteration Int_t maximum iteration for relaxation method (NOT USED) -/// \param symmetry Int_t symmetry (TODO for symmetry = 1) -// -/// SYMMETRY = 0 if no phi symmetries, and no phi boundary condition -/// = 1 if we have reflection symmetry at the boundaries (eg. sector symmetry or half sector symmetries). -/// -void AliTPCPoissonSolver::PoissonMultiGrid3D2D(TMatrixD** matricesV, TMatrixD** matricesCharge, Int_t nRRow, - Int_t nZColumn, Int_t phiSlice, Int_t symmetry) -{ - - const Float_t gridSizeR = - (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); // h_{r} - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; // h_{phi} - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); // h_{z} - const Float_t ratioPhi = - gridSizeR * gridSizeR / (gridSizePhi * gridSizePhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} - const Float_t ratioZ = gridSizeR * gridSizeR / (gridSizeZ * gridSizeZ); // ratio_{Z} = gridSize_{r} / gridSize_{z} - - // error tolerate - //const Float_t ERR = 1e-8; - Double_t convergenceError; - - Info("PoissonMultiGrid3D2D", "%s", Form("in Poisson Solver 3D multiGrid semi coarsening nRRow=%d, cols=%d, phiSlice=%d \n", nRRow, nZColumn, phiSlice)); - - // Check that the number of nRRow and nZColumn is suitable for a binary expansion - if (!IsPowerOfTwo((nRRow - 1))) { - Error("PoissonMultiGrid3D2D", "Poisson3DMultiGrid - Error in the number of nRRow. Must be 2**M + 1"); - return; - } - if (!IsPowerOfTwo((nZColumn - 1))) { - Error("PoissonMultiGrid3D2D", "Poisson3DMultiGrid - Error in the number of nZColumn. Must be 2**N - 1"); - return; - } - if (phiSlice <= 3) { - Error("PoissonMultiGrid3D2D", "Poisson3DMultiGrid - Error in the number of phiSlice. Must be larger than 3"); - return; - } - if (phiSlice > 1000) { - Error("PoissonMultiGrid3D2D", "Poisson3D phiSlice > 1000 is not allowed (nor wise) "); - return; - } - - // Solve Poisson's equation in cylindrical coordinates by multiGrid technique - // Allow for different size grid spacing in R and Z directions - - Int_t nGridRow = 0; // number grid - Int_t nGridCol = 0; // number grid - Int_t nnRow; - Int_t nnCol; - - nnRow = nRRow; - while (nnRow >>= 1) { - nGridRow++; - } - nnCol = nZColumn; - while (nnCol >>= 1) { - nGridCol++; - } - - Int_t nLoop = TMath::Max(nGridRow, nGridCol); // Calculate the number of nLoop for the binary expansion - nLoop = (nLoop > fMgParameters.maxLoop) ? fMgParameters.maxLoop : nLoop; - Int_t count; - Int_t iOne = 1; // index i in gridSize r (original) - Int_t jOne = 1; // index j in gridSize z (original) - Int_t tnRRow = nRRow, tnZColumn = nZColumn; - std::vector<TMatrixD**> tvChargeFMG(nLoop); // charge is restricted in full multiGrid - std::vector<TMatrixD**> tvArrayV(nLoop); // potential <--> error - std::vector<TMatrixD**> tvCharge(nLoop); // charge <--> residue - std::vector<TMatrixD**> tvResidue(nLoop); // residue calculation - std::vector<TMatrixD**> tvPrevArrayV(nLoop); // error calculation - - for (count = 1; count <= nLoop; count++) { - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tvResidue[count - 1] = new TMatrixD*[phiSlice]; - tvPrevArrayV[count - 1] = new TMatrixD*[phiSlice]; - for (Int_t k = 0; k < phiSlice; k++) { - tvResidue[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvPrevArrayV[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - } - - // memory for the finest grid is from parameters - if (count == 1) { - tvChargeFMG[count - 1] = matricesCharge; - tvArrayV[count - 1] = matricesV; - tvCharge[count - 1] = matricesCharge; - } else { - // allocate for coarser grid - tvChargeFMG[count - 1] = new TMatrixD*[phiSlice]; - tvArrayV[count - 1] = new TMatrixD*[phiSlice]; - tvCharge[count - 1] = new TMatrixD*[phiSlice]; - for (Int_t k = 0; k < phiSlice; k++) { - tvArrayV[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvCharge[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvChargeFMG[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - } - Restrict3D(tvChargeFMG[count - 1], tvChargeFMG[count - 2], tnRRow, tnZColumn, phiSlice, phiSlice); - RestrictBoundary3D(tvArrayV[count - 1], tvArrayV[count - 2], tnRRow, tnZColumn, phiSlice, phiSlice); - } - iOne = 2 * iOne; // doubling - jOne = 2 * jOne; // doubling - } - Float_t h, h2, radius; - Float_t tempRatioPhi, tempRatioZ; - std::vector<float> coefficient1( - nRRow); // coefficient1(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - std::vector<float> coefficient2( - nRRow); // coefficient2(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - std::vector<float> coefficient3( - nRRow); // coefficient3(nRRow) for storing (1/r_{i}^2) from central differences in phi direction - std::vector<float> coefficient4(nRRow); // coefficient4(nRRow) for storing 1/2 - std::vector<float> inverseCoefficient4(nRRow); // inverse of coefficient4(nRRow) - - // Case full multi grid (FMG) - if (fMgParameters.cycleType == kFCycle) { - - // 1) Relax on the coarsest grid - iOne = iOne / 2; - jOne = jOne / 2; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - h = gridSizeR * iOne; - h2 = h * h; - - tempRatioPhi = ratioPhi * iOne * iOne; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - // relax on the coarsest level - Relax3D(tvArrayV[nLoop - 1], tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, - coefficient1, - coefficient2, coefficient3, coefficient4); - // 2) Do multiGrid v-cycle from coarsest to finest - for (count = nLoop - 2; count >= 0; count--) { - // move to finer grid - iOne = iOne / 2; - jOne = jOne / 2; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - // 2) a) Interpolate potential for h -> 2h (coarse -> fine) - Interp3D(tvArrayV[count], tvArrayV[count + 1], tnRRow, tnZColumn, phiSlice, phiSlice); - // 2) c) Copy the restricted charge to charge for calculation - for (Int_t m = 0; m < phiSlice; m++) { - *tvCharge[count][m] = *tvChargeFMG[count][m]; //copy - } - // 2) c) Do V cycle fMgParameters.nMGCycle times at most - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - // Copy the potential to temp array for convergence calculation - for (Int_t m = 0; m < phiSlice; m++) { - *tvPrevArrayV[count][m] = *tvArrayV[count][m]; //copy - } - // 2) c) i) Call V cycle from grid count+1 (current fine level) to nLoop (coarsest) - VCycle3D2D(nRRow, nZColumn, phiSlice, symmetry, count + 1, nLoop, fMgParameters.nPre, fMgParameters.nPost, - gridSizeR, ratioZ, ratioPhi, tvArrayV, tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, - coefficient4, inverseCoefficient4); - - convergenceError = GetConvergenceError(tvArrayV[count], tvPrevArrayV[count], phiSlice); - - if (count == 0) { - (*fErrorConvergenceNormInf)(mgCycle) = convergenceError; - (*fError)(mgCycle) = GetExactError(matricesV, tvPrevArrayV[count], phiSlice); - } - /// if already converge just break move to finer grid - if (convergenceError <= fgConvergenceError) { - fIterations = mgCycle + 1; - break; - } - } - } - } // Case V multi grid (VMG) - else if (fMgParameters.cycleType == kVCycle) { - Int_t gridFrom = 1; - Int_t gridTo = nLoop; - // do v cycle fMgParameters.nMGCycle from the coarsest to finest - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - // copy to store previous potential - for (Int_t m = 0; m < phiSlice; m++) { - *tvPrevArrayV[0][m] = *tvArrayV[0][m]; //copy - } - // Do V Cycle for constant phiSlice - VCycle3D2D(nRRow, nZColumn, phiSlice, symmetry, gridFrom, gridTo, fMgParameters.nPre, fMgParameters.nPost, - gridSizeR, ratioZ, ratioPhi, tvArrayV, tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, - coefficient4, inverseCoefficient4); - - // convergence error - convergenceError = GetConvergenceError(tvArrayV[0], tvPrevArrayV[0], phiSlice); - (*fErrorConvergenceNormInf)(mgCycle) = convergenceError; - (*fError)(mgCycle) = GetExactError(matricesV, tvPrevArrayV[0], phiSlice); - - // if error already achieved then stop mg iteration - if (convergenceError <= fgConvergenceError) { - fIterations = mgCycle + 1; - break; - } - } - } - // Deallocate memory - for (count = 1; count <= nLoop; count++) { - delete[] tvResidue[count - 1]; - delete[] tvPrevArrayV[count - 1]; - - if (count > 1) { - delete[] tvChargeFMG[count - 1]; - delete[] tvArrayV[count - 1]; - delete[] tvCharge[count - 1]; - } - } -} - -/// 3D - Solve Poisson's Equation in 3D in all direction by MultiGrid -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slices == Arbitrary but greater than 3 -/// -/// Solving: \f$ \nabla^{2}V(r,\phi,z) = - f(r,\phi,z) \f$ -/// -/// Algorithm for MultiGrid Full Cycle (FMG) -/// - Relax on the coarsest grid -/// - Do from coarsest to finest -/// - Interpolate potential from coarse -> fine -/// - Do V-Cycle to the current coarse level to the coarsest -/// - Stop if converged -/// -/// DeltaPhi in Radians -/// \param matricesV TMatrixD** potential in 3D matrix -/// \param matricesCharge TMatrixD** charge density in 3D matrix (side effect) -/// \param nRRow Int_t number of nRRow in the r direction of TPC -/// \param nZColumn Int_t number of nZColumn in z direction of TPC -/// \param phiSlice Int_t number of phiSlice in phi direction of T{C -/// \param maxIteration Int_t maximum iteration for relaxation method -/// \param symmetry Int_t symmetry or not -// -/// SYMMETRY = 0 if no phi symmetries, and no phi boundary condition -/// = 1 if we have reflection symmetry at the boundaries (eg. sector symmetry or half sector symmetries). -/// -void AliTPCPoissonSolver::PoissonMultiGrid3D(TMatrixD** matricesV, TMatrixD** matricesCharge, - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t symmetry) -{ - - const Float_t gridSizeR = - (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); // h_{r} - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); // h_{z} - const Float_t ratioZ = gridSizeR * gridSizeR / (gridSizeZ * gridSizeZ); // ratio_{Z} = gridSize_{r} / gridSize_{z} - - Float_t gridSizePhi = TMath::TwoPi() / phiSlice; // h_{phi} - Float_t h, h2, radius; - Float_t tempRatioPhi, tempRatioZ; - - Float_t convergenceError; // Convergence error - - Info("PoissonMultiGrid3D", "%s", Form("in Poisson Solver 3D multi grid full coarsening nRRow=%d, cols=%d, phiSlice=%d \n", nRRow, nZColumn, phiSlice)); - - // Check that the number of nRRow and nZColumn is suitable for a binary expansion - if (!IsPowerOfTwo((nRRow - 1))) { - Error("PoissonMultiGrid3D", "Poisson3DMultiGrid - Error in the number of nRRow. Must be 2**M + 1"); - return; - } - if (!IsPowerOfTwo((nZColumn - 1))) { - Error("PoissonMultiGrid3D", "Poisson3DMultiGrid - Error in the number of nZColumn. Must be 2**N - 1"); - return; - } - if (phiSlice <= 3) { - Error("PoissonMultiGrid3D", "Poisson3DMultiGrid - Error in the number of phiSlice. Must be larger than 3"); - return; - } - if (phiSlice > 1000) { - Error("PoissonMultiGrid3D", "Poisson3D phiSlice > 1000 is not allowed (nor wise) "); - return; - } - - // Solve Poisson's equation in cylindrical coordinates by multi grid technique - // Allow for different size grid spacing in R and Z directions - - Int_t nGridRow = 0; // number grid - Int_t nGridCol = 0; // number grid - Int_t nGridPhi = 0; - - Int_t nnRow; - Int_t nnCol; - Int_t nnPhi; - - nnRow = nRRow; - while (nnRow >>= 1) { - nGridRow++; - } - - nnCol = nZColumn; - while (nnCol >>= 1) { - nGridCol++; - } - - nnPhi = phiSlice; - - while (nnPhi % 2 == 0) { - nGridPhi++; - nnPhi /= 2; - } - - Info("PoissonMultiGrid3D", "%s", Form("nGridRow=%d, nGridCol=%d, nGridPhi=%d", nGridRow, nGridCol, nGridPhi)); - Int_t nLoop = TMath::Max(nGridRow, nGridCol); // Calculate the number of nLoop for the binary expansion - nLoop = TMath::Max(nLoop, nGridPhi); - - // Vector for storing multi grid array - Int_t iOne = 1; // index i in gridSize r (original) - Int_t jOne = 1; // index j in gridSize z (original) - Int_t kOne = 1; // index k in gridSize phi - Int_t tnRRow = nRRow, tnZColumn = nZColumn, tPhiSlice = phiSlice, otPhiSlice; - - // 1) Memory allocation for multi grid - std::vector<TMatrixD**> tvChargeFMG(nLoop); // charge is restricted in full multiGrid - std::vector<TMatrixD**> tvArrayV(nLoop); // potential <--> error - std::vector<TMatrixD**> tvCharge(nLoop); // charge <--> residue - std::vector<TMatrixD**> tvResidue(nLoop); // residue calculation - std::vector<TMatrixD**> tvPrevArrayV(nLoop); // error calculation - - // these vectors for storing the coefficients in smoother - std::vector<float> coefficient1( - nRRow); // coefficient1(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - std::vector<float> coefficient2( - nRRow); // coefficient2(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - std::vector<float> coefficient3( - nRRow); // coefficient3(nRRow) for storing (1/r_{i}^2) from central differences in phi direction - std::vector<float> coefficient4(nRRow); // coefficient4(nRRow) for storing 1/2 - std::vector<float> inverseCoefficient4(nRRow); // inverse of coefficient4(nRRow) - - for (Int_t count = 1; count <= nLoop; count++) { - - // tnRRow,tnZColumn in new grid - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - - // allocate memory for residue - tvResidue[count - 1] = new TMatrixD*[tPhiSlice]; - tvPrevArrayV[count - 1] = new TMatrixD*[tPhiSlice]; - for (Int_t k = 0; k < tPhiSlice; k++) { - tvResidue[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvPrevArrayV[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - } - - // memory for the finest grid is from parameters - if (count == 1) { - tvChargeFMG[count - 1] = matricesCharge; - tvArrayV[count - 1] = matricesV; - tvCharge[count - 1] = matricesCharge; - } else { - // allocate for coarser grid - tvChargeFMG[count - 1] = new TMatrixD*[tPhiSlice]; - tvArrayV[count - 1] = new TMatrixD*[tPhiSlice]; - tvCharge[count - 1] = new TMatrixD*[tPhiSlice]; - for (Int_t k = 0; k < tPhiSlice; k++) { - tvArrayV[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvCharge[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - tvChargeFMG[count - 1][k] = new TMatrixD(tnRRow, tnZColumn); - } - } - iOne = 2 * iOne; // doubling - jOne = 2 * jOne; // doubling - kOne = 2 * kOne; - } - - // Case full multi grid (FMG) - - if (fMgParameters.cycleType == kFCycle) { - // Restrict the charge to coarser grid - iOne = 2; - jOne = 2; - kOne = 2; - otPhiSlice = phiSlice; - - // 1) Restrict Charge and Boundary to coarser grid - for (Int_t count = 2; count <= nLoop; count++) { - // tnRRow,tnZColumn in new grid - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - - Info("PoissonMultiGrid3D", "%s", Form("Restrict3D, tnRRow=%d, tnZColumn=%d, newPhiSlice=%d, oldPhiSlice=%d\n", tnRRow, tnZColumn, tPhiSlice, otPhiSlice)); - Restrict3D(tvChargeFMG[count - 1], tvChargeFMG[count - 2], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); - // copy boundary values of V - RestrictBoundary3D(tvArrayV[count - 1], tvArrayV[count - 2], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); - otPhiSlice = tPhiSlice; - - iOne = 2 * iOne; // doubling - jOne = 2 * jOne; // doubling - kOne = 2 * kOne; - } - - // Relax on the coarsest grid - // FMG - // 2) Relax on the coarsest grid - - // move to the coarsest + 1 - iOne = iOne / 2; - jOne = jOne / 2; - kOne = kOne / 2; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - otPhiSlice = tPhiSlice; - - h = gridSizeR * iOne; - h2 = h * h; - gridSizePhi = TMath::TwoPi() / tPhiSlice; // h_{phi} - tempRatioPhi = h * h / (gridSizePhi * gridSizePhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - // 3) Relax on the coarsest grid - Relax3D(tvArrayV[nLoop - 1], tvChargeFMG[nLoop - 1], tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, - coefficient1, - coefficient2, coefficient3, coefficient4); - - // 4) V Cycle from coarsest to finest - for (Int_t count = nLoop - 2; count >= 0; count--) { - // move to finer grid - coefficient1.clear(); - coefficient2.clear(); - coefficient3.clear(); - coefficient4.clear(); - inverseCoefficient4.clear(); - - iOne = iOne / 2; - jOne = jOne / 2; - kOne = kOne / 2; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - // 4) a) interpolate from 2h --> h grid - Interp3D(tvArrayV[count], tvArrayV[count + 1], tnRRow, tnZColumn, tPhiSlice, otPhiSlice); - - // Copy the relax charge to the tvCharge - if (count > 0) { - for (Int_t m = 0; m < tPhiSlice; m++) { - *tvCharge[count][m] = *tvChargeFMG[count][m]; //copy - } - } - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - // copy to store previous potential - for (Int_t m = 0; m < tPhiSlice; m++) { - *tvPrevArrayV[count][m] = *tvArrayV[count][m]; //copy - } - - VCycle3D(nRRow, nZColumn, phiSlice, symmetry, count + 1, nLoop, fMgParameters.nPre, fMgParameters.nPost, - gridSizeR, ratioZ, tvArrayV, - tvCharge, tvResidue, coefficient1, coefficient2, coefficient3, coefficient4, inverseCoefficient4); - - /// converge error - convergenceError = GetConvergenceError(tvArrayV[count], tvPrevArrayV[count], tPhiSlice); - //// error counting ///// - if (count == 0) { - (*fErrorConvergenceNormInf)(mgCycle) = convergenceError; - (*fError)(mgCycle) = GetExactError(matricesV, tvPrevArrayV[count], phiSlice); - } - /// if already converge just break move to finer grid - if (convergenceError <= fgConvergenceError) { - fIterations = mgCycle + 1; - break; - } - } - // keep old slice information - otPhiSlice = tPhiSlice; - } - - } else if (fMgParameters.cycleType == kVCycle) { - // V-cycle - Int_t gridFrom = 1; - Int_t gridTo = nLoop; - - for (Int_t mgCycle = 0; mgCycle < fMgParameters.nMGCycle; mgCycle++) { - // copy to store previous potential - for (Int_t m = 0; m < phiSlice; m++) { - *tvPrevArrayV[0][m] = *tvArrayV[0][m]; //copy - } - // Do V Cycle from the coarsest to finest grid - VCycle3D(nRRow, nZColumn, phiSlice, symmetry, gridFrom, gridTo, fMgParameters.nPre, fMgParameters.nPost, - gridSizeR, ratioZ, tvArrayV, tvCharge, tvResidue, - coefficient1, coefficient2, coefficient3, coefficient4, inverseCoefficient4); - // convergence error - convergenceError = GetConvergenceError(tvArrayV[0], tvPrevArrayV[0], phiSlice); - (*fErrorConvergenceNormInf)(mgCycle) = convergenceError; - (*fError)(mgCycle) = GetExactError(matricesV, tvPrevArrayV[0], phiSlice); - // if error already achieved then stop mg iteration - if (convergenceError <= fgConvergenceError) { - //Info("PoissonMultiGrid3D",Form("Exact Err: %f, MG Iteration : %d", (*fError)(mgCycle), mgCycle)); - fIterations = mgCycle + 1; - break; - } - } - } - // deallocate memory for multiGrid - for (Int_t count = 1; count <= nLoop; count++) { - delete[] tvResidue[count - 1]; - delete[] tvPrevArrayV[count - 1]; - if (count > 1) { - delete[] tvChargeFMG[count - 1]; - delete[] tvArrayV[count - 1]; - delete[] tvCharge[count - 1]; - } - } -} - -/// Helper function to check if the integer is equal to a power of two -/// \param i Int_t the number -/// \return 1 if it is a power of two, else 0 -Int_t AliTPCPoissonSolver::IsPowerOfTwo(Int_t i) const -{ - Int_t j = 0; - while (i > 0) { - j += (i & 1); - i = (i >> 1); - } - if (j == 1) { - return (1); // True - } - return (0); // False -} - -/// Relax3D -/// -/// Relaxation operation for multiGrid -/// relaxation used 7 stencil in cylindrical coordinate -/// -/// Using the following equations -/// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ -/// -/// \param matricesCurrentV TMatrixD** potential in 3D (matrices of matrix) -/// \param matricesCurrentCharge TMatrixD** charge in 3D -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// \param phiSlice const Int_t number of phiSlice in phi direction of TPC -/// \param symmetry const Int_t is the cylinder has symmetry -/// \param h2 const Float_t \f$ h_{r}^{2} \f$ -/// \param tempRatioZ const Float_t ration between grid size in z-direction and r-direction -/// \param coefficient1 std::vector<float> coefficient for \f$ V_{x+1,y,z} \f$ -/// \param coefficient2 std::vector<float> coefficient for \f$ V_{x-1,y,z} \f$ -/// \param coefficient3 std::vector<float> coefficient for z -/// \param coefficient4 std::vector<float> coefficient for f(r,\phi,z) -/// -void AliTPCPoissonSolver::Relax3D(TMatrixD** matricesCurrentV, TMatrixD** matricesCurrentCharge, const Int_t tnRRow, - const Int_t tnZColumn, - const Int_t phiSlice, const Int_t symmetry, const Float_t h2, - const Float_t tempRatioZ, std::vector<float>& coefficient1, - std::vector<float>& coefficient2, - std::vector<float>& coefficient3, std::vector<float>& coefficient4) -{ - - Int_t mPlus, mMinus, signPlus, signMinus; - TMatrixD* matrixV; - TMatrixD* matrixVP; - TMatrixD* matrixVM; - TMatrixD* arrayCharge; - - // Gauss-Seidel (Read Black} - if (fMgParameters.relaxType == kGaussSeidel) { - // for each slice - Int_t isw, jsw, msw; - msw = 1; - for (Int_t iPass = 1; iPass <= 2; iPass++, msw = 3 - msw) { - jsw = msw; - for (Int_t m = 0; m < phiSlice; m++, jsw = 3 - jsw) { - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (symmetry == 1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } - // Anti-symmetry in phi - else if (symmetry == -1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - } - matrixV = matricesCurrentV[m]; - matrixVP = matricesCurrentV[mPlus]; // slice - matrixVM = matricesCurrentV[mMinus]; // slice - arrayCharge = matricesCurrentCharge[m]; - - isw = jsw; - for (Int_t j = 1; j < tnZColumn - 1; j++, isw = 3 - isw) { - for (Int_t i = isw; i < tnRRow - 1; i += 2) { - //Info("Relax3D",Form("Doing slice %d, z=%d, r=%d", m,j,i)); - (*matrixV)(i, j) = (coefficient2[i] * (*matrixV)(i - 1, j) + tempRatioZ * ((*matrixV)(i, j - 1) + (*matrixV)(i, j + 1)) + coefficient1[i] * (*matrixV)(i + 1, j) + coefficient3[i] * (signPlus * (*matrixVP)(i, j) + signMinus * (*matrixVM)(i, j)) + (h2 * (*arrayCharge)(i, j))) * coefficient4[i]; - } // end cols - } // end nRRow - } // end phi - } // end sweep - } else if (fMgParameters.relaxType == kJacobi) { - // for each slice - for (Int_t m = 0; m < phiSlice; m++) { - - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - - // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (symmetry == 1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } - // Anti-symmetry in phi - else if (symmetry == -1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - } - - matrixV = matricesCurrentV[m]; - matrixVP = matricesCurrentV[mPlus]; // slice - matrixVM = matricesCurrentV[mMinus]; // slice - arrayCharge = matricesCurrentCharge[m]; - - // Jacobian - for (Int_t j = 1; j < tnZColumn - 1; j++) { - for (Int_t i = 1; i < tnRRow - 1; i++) { - (*matrixV)(i, j) = (coefficient2[i] * (*matrixV)(i - 1, j) + tempRatioZ * ((*matrixV)(i, j - 1) + (*matrixV)(i, j + 1)) + coefficient1[i] * (*matrixV)(i + 1, j) + coefficient3[i] * (signPlus * (*matrixVP)(i, j) + signMinus * (*matrixVM)(i, j)) + (h2 * (*arrayCharge)(i, j))) * coefficient4[i]; - - } // end cols - } // end nRRow - - } // end phi - - } else { - // Case weighted Jacobi - // TODO - } -} - -/// Relax2D -/// -/// Relaxation operation for multiGrid -/// relaxation used 5 stencil in cylindrical coordinate -/// -/// Using the following equations -/// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ -/// -/// \param matricesCurrentV TMatrixD& potential in 3D (matrices of matrix) -/// \param matricesCurrentCharge TMatrixD& charge in 3D -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// \param phiSlice const Int_t number of phiSlice in phi direction of TPC -/// \param symmetry const Int_t is the cylinder has symmetry -/// \param h2 const Float_t \f$ h_{r}^{2} \f$ -/// \param tempFourth const Float_t coefficient for h -/// \param tempRatio const Float_t ratio between grid size in z-direction and r-direction -/// \param coefficient1 std::vector<float> coefficient for \f$ V_{x+1,y,z} \f$ -/// \param coefficient2 std::vector<float> coefficient for \f$ V_{x-1,y,z} \f$ -/// -void AliTPCPoissonSolver::Relax2D(TMatrixD& matricesCurrentV, TMatrixD& matricesCurrentCharge, const Int_t tnRRow, - const Int_t tnZColumn, - const Float_t h2, const Float_t tempFourth, const Float_t tempRatio, - std::vector<float>& coefficient1, std::vector<float>& coefficient2) -{ - - // Gauss-Seidel - if (fMgParameters.relaxType == kGaussSeidel) { - - Int_t isw, jsw = 1; - for (Int_t iPass = 1; iPass <= 2; iPass++, jsw = 3 - jsw) { - isw = jsw; - for (Int_t j = 1; j < tnZColumn - 1; j++, isw = 3 - isw) { - for (Int_t i = isw; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j) + - coefficient2[i] * matricesCurrentV(i - 1, j) + - tempRatio * (matricesCurrentV(i, j + 1) + matricesCurrentV(i, j - 1)) + - (h2 * matricesCurrentCharge(i, j))); - } // end cols - } // end nRRow - } // end pass red-black - } else if (fMgParameters.relaxType == kJacobi) { - for (Int_t j = 1; j < tnZColumn - 1; j++) { - for (Int_t i = 1; i < tnRRow - 1; i++) { - matricesCurrentV(i, j) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j) + - coefficient2[i] * matricesCurrentV(i - 1, j) + tempRatio * (matricesCurrentV(i, j + 1) + matricesCurrentV(i, j - 1)) + - (h2 * matricesCurrentCharge(i, j))); - } // end cols - } // end nRRow - } else if (fMgParameters.relaxType == kWeightedJacobi) { - // Weighted Jacobi - // TODO - } -} - -/// Residue3D -/// -/// Compute residue from V(.) where V(.) is numerical potential and f(.). -/// residue used 7 stencil in cylindrical coordinate -/// -/// Using the following equations -/// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ -/// -/// \param residue TMatrixD** residue in 3D (matrices of matrix) -/// \param matricesCurrentV TMatrixD** potential in 3D (matrices of matrix) -/// \param matricesCurrentCharge TMatrixD** charge in 3D -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// \param phiSlice const Int_t number of phiSlice in phi direction of TPC -/// \param symmetry const Int_t is the cylinder has symmetry -/// \param ih2 const Float_t \f$ 1/ h_{r}^{2} \f$ -/// \param tempRatioZ const Float_t ration between grid size in z-direction and r-direction -/// \param coefficient1 std::vector<float> coefficient for \f$ V_{x+1,y,z} \f$ -/// \param coefficient2 std::vector<float> coefficient for \f$ V_{x-1,y,z} \f$ -/// \param coefficient3 std::vector<float> coefficient for z -/// \param inverseCoefficient4 std::vector<float> inverse coefficient for f(r,\phi,z) -/// -void AliTPCPoissonSolver::Residue3D(TMatrixD** residue, TMatrixD** matricesCurrentV, TMatrixD** matricesCurrentCharge, - const Int_t tnRRow, - const Int_t tnZColumn, const Int_t phiSlice, const Int_t symmetry, - const Float_t ih2, - const Float_t tempRatioZ, std::vector<float>& coefficient1, - std::vector<float>& coefficient2, - std::vector<float>& coefficient3, std::vector<float>& inverseCoefficient4) -{ - Int_t mPlus, mMinus, signPlus, signMinus; - for (Int_t m = 0; m < phiSlice; m++) { - - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - - // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (symmetry == 1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } - // Anti-symmetry in phi - else if (symmetry == -1) { - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculation is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - } - - TMatrixD& arrayResidue = *residue[m]; - TMatrixD& matrixV = *matricesCurrentV[m]; - TMatrixD& matrixVP = *matricesCurrentV[mPlus]; // slice - TMatrixD& matrixVM = *matricesCurrentV[mMinus]; // slice - TMatrixD& arrayCharge = *matricesCurrentCharge[m]; - - for (Int_t j = 1; j < tnZColumn - 1; j++) { - for (Int_t i = 1; i < tnRRow - 1; i++) { - - arrayResidue(i, j) = - ih2 * (coefficient2[i] * matrixV(i - 1, j) + tempRatioZ * (matrixV(i, j - 1) + matrixV(i, j + 1)) + coefficient1[i] * matrixV(i + 1, j) + - coefficient3[i] * (signPlus * matrixVP(i, j) + signMinus * matrixVM(i, j)) - - inverseCoefficient4[i] * matrixV(i, j)) + - arrayCharge(i, j); - - } // end cols - } // end nRRow - - //arrayResidue.Print(); - } -} - -/// Residue2D -/// -/// Compute residue from V(.) where V(.) is numerical potential and f(.). -/// residue used 5 stencil in cylindrical coordinate -/// -/// Using the following equations -/// \f$ U_{i,j,k} = (1 + \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} + (1 - \frac{1}{r_{i}h_{r}}) U_{i+1,j,k} \f$ -/// -/// \param residue TMatrixD& potential in 2D -/// \param matricesCurrentV TMatrixD& potential in 2D -/// \param matricesCurrentCharge TMatrixD& charge in 2D -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// \param phiSlice const Int_t number of phiSlice in phi direction of TPC -/// \param symmetry const Int_t is the cylinder has symmetry -/// \param h2 const Float_t \f$ h_{r}^{2} \f$ -/// \param tempFourth const Float_t coefficient for h -/// \param tempRatio const Float_t ratio between grid size in z-direction and r-direction -/// \param coefficient1 std::vector<float> coefficient for \f$ V_{x+1,y,z} \f$ -/// \param coefficient2 std::vector<float> coefficient for \f$ V_{x-1,y,z} \f$ -/// -void AliTPCPoissonSolver::Residue2D(TMatrixD& residue, TMatrixD& matricesCurrentV, TMatrixD& matricesCurrentCharge, - const Int_t tnRRow, - const Int_t tnZColumn, const Float_t ih2, const Float_t inverseTempFourth, - const Float_t tempRatio, std::vector<float>& coefficient1, - std::vector<float>& coefficient2) -{ - for (Int_t i = 1; i < tnRRow - 1; i++) { - for (Int_t j = 1; j < tnZColumn - 1; j++) { - residue(i, j) = ih2 * (coefficient1[i] * matricesCurrentV(i + 1, j) + coefficient2[i] * matricesCurrentV(i - 1, j) + tempRatio * (matricesCurrentV(i, j + 1) + matricesCurrentV(i, j - 1)) - - inverseTempFourth * matricesCurrentV(i, j)) + - matricesCurrentCharge(i, j); - - } // end cols - } // end nRRow - - //Boundary points. - for (Int_t i = 0; i < tnRRow; i++) { - residue(i, 0) = residue(i, tnZColumn - 1) = 0.0; - } - - for (Int_t j = 0; j < tnZColumn; j++) { - residue(0, j) = residue(tnRRow - 1, j) = 0.0; - } -} - -/// Restrict2D -/// -/// Grid transfer operator, restrict from fine -> coarse grid -/// provide full-half weighting -/// -/// \[ \frac{1}{16}\left( \begin{array}{ccc} -/// 1 & 2 & 1 \\ -/// 2 & 4 & 2 \\ -/// 1 & 2 & 1 \end{array} \right) \] -/// -/// \param matricesCurrentCharge TMatrixD& coarse grid (2h) -/// \param residue TMatrixD& fine grid (h) -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// -void AliTPCPoissonSolver::Restrict2D(TMatrixD& matricesCurrentCharge, TMatrixD& residue, const Int_t tnRRow, - const Int_t tnZColumn) -{ - - for (Int_t i = 1, ii = 2; i < tnRRow - 1; i++, ii += 2) { - for (Int_t j = 1, jj = 2; j < tnZColumn - 1; j++, jj += 2) { - if (fMgParameters.gtType == kHalf) { - // half - matricesCurrentCharge(i, j) = 0.5 * residue(ii, jj) + - 0.125 * - (residue(ii + 1, jj) + residue(ii - 1, jj) + residue(ii, jj + 1) + - residue(ii, jj - 1)); - - } else - // full - if (fMgParameters.gtType == kFull) { - matricesCurrentCharge(i, j) = 0.25 * residue(ii, jj) + - 0.125 * - (residue(ii + 1, jj) + residue(ii - 1, jj) + residue(ii, jj + 1) + - residue(ii, jj - 1)) + - 0.0625 * - (residue(ii + 1, jj + 1) + residue(ii - 1, jj + 1) + residue(ii + 1, jj - 1) + - residue(ii - 1, jj - 1)); - } - - } // end cols - } // end nRRow - - // boundary - // for boundary - for (Int_t j = 0, jj = 0; j < tnZColumn; j++, jj += 2) { - matricesCurrentCharge(0, j) = residue(0, jj); - matricesCurrentCharge(tnRRow - 1, j) = residue((tnRRow - 1) * 2, jj); - } - - // for boundary - for (Int_t i = 0, ii = 0; i < tnRRow; i++, ii += 2) { - matricesCurrentCharge(i, 0) = residue(ii, 0); - matricesCurrentCharge(i, tnZColumn - 1) = residue(ii, (tnZColumn - 1) * 2); - } -} - -/// RestrictBoundary2D -/// -/// Boundary transfer restrict from fine -> coarse grid -/// -/// \param matricesCurrentCharge TMatrixD& coarse grid (2h) -/// \param residue TMatrixD& fine grid (h) -/// \param nRRow const Int_t number of nRRow in the r direction of TPC -/// \param nZColumn const Int_t number of nZColumn in z direction of TPC -/// -void AliTPCPoissonSolver::RestrictBoundary2D(TMatrixD& matricesCurrentCharge, TMatrixD& residue, const Int_t tnRRow, - const Int_t tnZColumn) -{ - // for boundary - for (Int_t j = 0, jj = 0; j < tnZColumn; j++, jj += 2) { - matricesCurrentCharge(0, j) = residue(0, jj); - matricesCurrentCharge(tnRRow - 1, j) = residue((tnRRow - 1) * 2, jj); - } - - // for boundary - for (Int_t i = 0, ii = 0; i < tnRRow; i++, ii += 2) { - matricesCurrentCharge(i, 0) = residue(ii, 0); - matricesCurrentCharge(i, tnZColumn - 1) = residue(ii, (tnZColumn - 1) * 2); - } -} - -/// Restriction in 3D -/// -/// Restriction is a map from fine grid (h) to coarse grid (2h) -/// -/// In case of 3D -/// Full weighting: -/// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] -/// -/// -/// Restriction in all direction r-phi-z -/// restriction in phi only if oldPhi == 2*newPhi -/// \param matricesCurrentCharge TMatrixD** coarser grid 2h -/// \param residue TMatrixD ** fine grid h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param newPhiSlice Int_t number of phiSlice (in phi-direction) for coarser grid -/// \param oldPhiSlice Int_t number of phiSlice (in phi-direction) for finer grid -/// -void AliTPCPoissonSolver::Restrict3D(TMatrixD** matricesCurrentCharge, TMatrixD** residue, const Int_t tnRRow, - const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice) -{ - - Double_t s1, s2, s3; - - if (2 * newPhiSlice == oldPhiSlice) { - - Int_t mPlus, mMinus; - Int_t mm = 0; - - for (Int_t m = 0; m < newPhiSlice; m++, mm += 2) { - - // assuming no symmetry - mPlus = mm + 1; - mMinus = mm - 1; - - if (mPlus > (oldPhiSlice)-1) { - mPlus = mm + 1 - (oldPhiSlice); - } - if (mMinus < 0) { - mMinus = mm - 1 + (oldPhiSlice); - } - - TMatrixD& arrayResidue = *residue[mm]; - TMatrixD& arrayResidueP = *residue[mPlus]; - TMatrixD& arrayResidueM = *residue[mMinus]; // slice - TMatrixD& arrayCharge = *matricesCurrentCharge[m]; - - for (Int_t i = 1, ii = 2; i < tnRRow - 1; i++, ii += 2) { - for (Int_t j = 1, jj = 2; j < tnZColumn - 1; j++, jj += 2) { - - // at the same plane - s1 = arrayResidue(ii + 1, jj) + arrayResidue(ii - 1, jj) + arrayResidue(ii, jj + 1) + - arrayResidue(ii, jj - 1) + arrayResidueP(ii, jj) + arrayResidueM(ii, jj); - s2 = (arrayResidue(ii + 1, jj + 1) + arrayResidue(ii + 1, jj - 1) + arrayResidueP(ii + 1, jj) + - arrayResidueM(ii + 1, jj)) + - (arrayResidue(ii - 1, jj - 1) + arrayResidue(ii - 1, jj + 1) + arrayResidueP(ii - 1, jj) + - arrayResidueM(ii - 1, jj)) + - arrayResidueP(ii, jj - 1) + arrayResidueM(ii, jj + 1) + arrayResidueM(ii, jj - 1) + - arrayResidueP(ii, jj + 1); - - s3 = (arrayResidueP(ii + 1, jj + 1) + arrayResidueP(ii + 1, jj - 1) + arrayResidueM(ii + 1, jj + 1) + - arrayResidueM(ii + 1, jj - 1)) + - (arrayResidueM(ii - 1, jj - 1) + arrayResidueM(ii - 1, jj + 1) + arrayResidueP(ii - 1, jj - 1) + - arrayResidueP(ii - 1, jj + 1)); - - arrayCharge(i, j) = 0.125 * arrayResidue(ii, jj) + 0.0625 * s1 + 0.03125 * s2 + 0.015625 * s3; - } // end cols - } // end nRRow - - // for boundary - for (Int_t j = 0, jj = 0; j < tnZColumn; j++, jj += 2) { - arrayCharge(0, j) = arrayResidue(0, jj); - arrayCharge(tnRRow - 1, j) = arrayResidue((tnRRow - 1) * 2, jj); - } - - // for boundary - for (Int_t i = 0, ii = 0; i < tnRRow; i++, ii += 2) { - arrayCharge(i, 0) = arrayResidue(ii, 0); - arrayCharge(i, tnZColumn - 1) = arrayResidue(ii, (tnZColumn - 1) * 2); - } - } // end phis - - } else { - for (int m = 0; m < newPhiSlice; m++) { - Restrict2D(*matricesCurrentCharge[m], *residue[m], tnRRow, tnZColumn); - } - } -} - -/// Restrict Boundary in 3D -/// -/// Pass boundary information to coarse grid -/// -/// \param matricesCurrentCharge TMatrixD** coarser grid 2h -/// \param residue TMatrixD ** fine grid h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param newPhiSlice Int_t number of phiSlice (in phi-direction) for coarser grid -/// \param oldPhiSlice Int_t number of phiSlice (in phi-direction) for finer grid -/// -void AliTPCPoissonSolver::RestrictBoundary3D(TMatrixD** matricesCurrentCharge, TMatrixD** residue, const Int_t tnRRow, - const Int_t tnZColumn, const Int_t newPhiSlice, const Int_t oldPhiSlice) -{ - - // in case of full 3d and the phiSlice is also coarsening - - if (2 * newPhiSlice == oldPhiSlice) { - - for (Int_t m = 0, mm = 0; m < newPhiSlice; m++, mm += 2) { - - TMatrixD& arrayResidue = *residue[mm]; - TMatrixD& arrayCharge = *matricesCurrentCharge[m]; - // for boundary - for (Int_t j = 0, jj = 0; j < tnZColumn; j++, jj += 2) { - arrayCharge(0, j) = arrayResidue(0, jj); - arrayCharge(tnRRow - 1, j) = arrayResidue((tnRRow - 1) * 2, jj); - } - - // for boundary - for (Int_t i = 0, ii = 0; i < tnRRow; i++, ii += 2) { - arrayCharge(i, 0) = arrayResidue(ii, 0); - arrayCharge(i, tnZColumn - 1) = arrayResidue(ii, (tnZColumn - 1) * 2); - } - } // end phis - } else { - for (int m = 0; m < newPhiSlice; m++) { - RestrictBoundary2D(*matricesCurrentCharge[m], *residue[m], tnRRow, tnZColumn); - } - } -} - -/// Prolongation with Addition for 2D -/// -/// Interpolation with addition from coarse level (2h) --> fine level (h) -/// -/// Interpolation in all direction r-phi-z -/// \param matricesCurrentV TMatrixD& fine grid h -/// \param matricesCurrentVC TMatrixD& coarse grid 2h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1a -/// -void AliTPCPoissonSolver::AddInterp2D(TMatrixD& matricesCurrentV, TMatrixD& matricesCurrentVC, const Int_t tnRRow, - const Int_t tnZColumn) -{ - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = matricesCurrentV(i, j) + matricesCurrentVC(i / 2, j / 2); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = - matricesCurrentV(i, j) + 0.5 * (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2, j / 2 + 1)); - } - } - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = - matricesCurrentV(i, j) + 0.5 * (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2 + 1, j / 2)); - } - } - - // only if full - if (fMgParameters.gtType == kFull) { - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = - matricesCurrentV(i, j) + 0.25 * (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2, j / 2 + 1) + matricesCurrentVC(i / 2 + 1, j / 2) + matricesCurrentVC(i / 2 + 1, j / 2 + 1)); - } - } - } -} - -/// Prolongation with Addition for 3D -/// -/// Interpolation with addition from coarse level (2h) --> fine level (h) -/// -/// Interpolation in all direction r-phi-z -/// Interpolation in phi only if oldPhi == 2*newPhi -/// \param matricesCurrentV TMatrixD& fine grid h -/// \param matricesCurrentVC TMatrixD& coarse grid 2h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1a -/// \param newPhiSlice Int_t number of phiSlice (in phi-direction) for coarser grid -/// \param oldPhiSlice Int_t number of phiSlice (in phi-direction) for finer grid -/// -void AliTPCPoissonSolver::AddInterp3D(TMatrixD** matricesCurrentV, TMatrixD** matricesCurrentVC, const Int_t tnRRow, - const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice) -{ - // Do restrict 2 D for each slice - - //const Float_t h = (AliTPCPoissonSolver::fgkOFCRadius-AliTPCPoissonSolver::fgkIFCRadius) / ((tnRRow-1)/2); // h_{r} - //Float_t radius,ratio; - //std::vector<float> coefficient1((tnRRow-1) / 2 ); // coefficient1(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - //std::vector<float> coefficient2((tnRRow-1) / 2); // coefficient2(nRRow) for storing (1 + h_{r}/2r_{i}) from central differences in r direction - - if (newPhiSlice == 2 * oldPhiSlice) { - Int_t mPlus, mmPlus; - Int_t mm = 0; - - for (Int_t m = 0; m < newPhiSlice; m += 2) { - - // assuming no symmetry - mm = m / 2; - mmPlus = mm + 1; - mPlus = m + 1; - - // round - if (mmPlus > (oldPhiSlice)-1) { - mmPlus = mm + 1 - (oldPhiSlice); - } - if (mPlus > (newPhiSlice)-1) { - mPlus = m + 1 - (newPhiSlice); - } - - TMatrixD& fineV = *matricesCurrentV[m]; - TMatrixD& fineVP = *matricesCurrentV[mPlus]; - TMatrixD& coarseV = *matricesCurrentVC[mm]; - TMatrixD& coarseVP = *matricesCurrentVC[mmPlus]; - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - fineV(i, j) += coarseV(i / 2, j / 2); - // point on corner lines at phi direction - fineVP(i, j) += 0.5 * (coarseV(i / 2, j / 2) + coarseVP(i / 2, j / 2)); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - fineV(i, j) += 0.5 * (coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1)); - // point on corner lines at phi direction - fineVP(i, j) += 0.25 * (coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1) + coarseVP(i / 2, j / 2) + - coarseVP(i / 2, j / 2 + 1)); - } - } - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - fineV(i, j) += 0.5 * (coarseV(i / 2, j / 2) + coarseV(i / 2 + 1, j / 2)); - - // point on line at phi direction - fineVP(i, j) += 0.25 * ((coarseV(i / 2, j / 2) + coarseVP(i / 2, j / 2)) + - (coarseVP(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2))); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - fineV(i, j) += 0.25 * ((coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1)) + - (coarseV(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2 + 1))); - - // point at the center at phi direction - fineVP(i, j) += 0.125 * ((coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1) + coarseVP(i / 2, j / 2) + - coarseVP(i / 2, j / 2 + 1)) + - (coarseV(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2 + 1) + - coarseVP(i / 2 + 1, j / 2) + coarseVP(i / 2 + 1, j / 2 + 1))); - } - } - } - - } else { - for (int m = 0; m < newPhiSlice; m++) { - AddInterp2D(*matricesCurrentV[m], *matricesCurrentVC[m], tnRRow, tnZColumn); - } - } -} - -/// Interpolation/Prolongation in 3D -/// -/// Interpolation is a map from coarse grid (h) to fine grid (2h) -/// -/// In case of 3D -/// Full weighting: -/// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] -/// -/// -/// Restriction in all direction r-phi-z -/// restriction in phi only if oldPhi == 2*newPhi -/// \param matricesCurrentV TMatrixD** finer grid h -/// \param curArrayCV TMatrixD ** coarse grid 2h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param newPhiSlice Int_t number of phiSlice (in phi-direction) for coarser grid -/// \param oldPhiSlice Int_t number of phiSlice (in phi-direction) for finer grid -/// -void AliTPCPoissonSolver::Interp3D(TMatrixD** matricesCurrentV, TMatrixD** matricesCurrentVC, const Int_t tnRRow, - const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice) -{ - - // Do restrict 2 D for each slice - if (newPhiSlice == 2 * oldPhiSlice) { - Int_t mPlus, mmPlus; - Int_t mm = 0; - - for (Int_t m = 0; m < newPhiSlice; m += 2) { - - // assuming no symmetry - mm = m / 2; - mmPlus = mm + 1; - mPlus = m + 1; - - // round - if (mmPlus > (oldPhiSlice)-1) { - mmPlus = mm + 1 - (oldPhiSlice); - } - if (mPlus > (newPhiSlice)-1) { - mPlus = m + 1 - (newPhiSlice); - } - - TMatrixD& fineV = *matricesCurrentV[m]; - TMatrixD& fineVP = *matricesCurrentV[mPlus]; - TMatrixD& coarseV = *matricesCurrentVC[mm]; - TMatrixD& coarseVP = *matricesCurrentVC[mmPlus]; - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - fineV(i, j) = coarseV(i / 2, j / 2); - - // point on corner lines at phi direction - fineVP(i, j) = 0.5 * (coarseV(i / 2, j / 2) + coarseVP(i / 2, j / 2)); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - fineV(i, j) = 0.5 * (coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1)); - - // point on corner lines at phi direction - fineVP(i, j) = 0.25 * (coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1) + coarseVP(i / 2, j / 2) + - coarseVP(i / 2, j / 2 + 1)); - } - } - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - fineV(i, j) = 0.5 * (coarseV(i / 2, j / 2) + coarseV(i / 2 + 1, j / 2)); - - // point on line at phi direction - fineVP(i, j) = 0.25 * ((coarseV(i / 2, j / 2) + coarseVP(i / 2, j / 2)) + - (coarseVP(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2))); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - fineV(i, j) = 0.25 * ((coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1)) + - (coarseV(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2 + 1))); - - // point at the center at phi direction - fineVP(i, j) = 0.125 * ((coarseV(i / 2, j / 2) + coarseV(i / 2, j / 2 + 1) + coarseVP(i / 2, j / 2) + - coarseVP(i / 2, j / 2 + 1)) + - (coarseV(i / 2 + 1, j / 2) + coarseV(i / 2 + 1, j / 2 + 1) + - coarseVP(i / 2 + 1, j / 2) + coarseVP(i / 2 + 1, j / 2 + 1))); - } - } - } - - } else { - for (int m = 0; m < newPhiSlice; m++) { - Interp2D(*matricesCurrentV[m], *matricesCurrentVC[m], tnRRow, tnZColumn); - } - } -} - -/// Interpolation/Prolongation in 2D -/// -/// Interpolation is a map from coarse grid (h) to fine grid (2h) -/// -/// In case of 2D -/// Full weighting: -/// \f[ (R u)_{i,j,k} = \frac{1}{2} u_{2i,2j,2k} + \frac{1}{4} S_{1} + \frac{1}{8} S_{2} + \frac{1}{16} S_{3}\f] -/// -/// -/// Restriction in all direction r-phi-z -/// \param matricesCurrentV TMatrixD** finer grid h -/// \param curArrayCV TMatrixD ** coarse grid 2h -/// \param tnRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param tnZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// -void AliTPCPoissonSolver::Interp2D(TMatrixD& matricesCurrentV, TMatrixD& matricesCurrentVC, const Int_t tnRRow, - const Int_t tnZColumn) -{ - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = matricesCurrentVC(i / 2, j / 2); - } - } - - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 2; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = 0.5 * (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2, j / 2 + 1)); - } - } - - for (Int_t j = 2; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = 0.5 * (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2 + 1, j / 2)); - } - } - - // only if full - if (fMgParameters.gtType == kFull) { - for (Int_t j = 1; j < tnZColumn - 1; j += 2) { - for (Int_t i = 1; i < tnRRow - 1; i += 2) { - matricesCurrentV(i, j) = 0.25 * - (matricesCurrentVC(i / 2, j / 2) + matricesCurrentVC(i / 2, j / 2 + 1) + - matricesCurrentVC(i / 2 + 1, j / 2) + - matricesCurrentVC(i / 2 + 1, j / 2 + 1)); - } - } - } -} - -/// V-Cycle 2D -/// -/// Implementation non-recursive V-cycle for 2D -/// -/// Algorithms: -/// -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param gridFrom const Int_t finest level of grid -/// \param gridTo const Int_t coarsest level of grid -/// \param nPre const Int_t number of smoothing before coarsening -/// \param nPost const Int_t number of smoothing after coarsening -/// \param gridSizeR const Float_t grid size in r direction (OPTION, recalculate) -/// \param ratio const Float_t ratio between square of grid r and grid z (OPTION, recalculate) -/// \param tvArrayV vector<TMatrixD *> vector of V potential in different grids -/// \param tvCharge vector<TMatrixD *> vector of charge distribution in different grids -/// \param tvResidue vector<TMatrixD *> vector of residue calculation in different grids -/// -void AliTPCPoissonSolver::VCycle2D(const Int_t nRRow, const Int_t nZColumn, const Int_t gridFrom, const Int_t gridTo, - const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, const Float_t ratio, - std::vector<TMatrixD*>& tvArrayV, - std::vector<TMatrixD*>& tvCharge, std::vector<TMatrixD*>& tvResidue) -{ - - Float_t h, h2, ih2, tempRatio, tempFourth, inverseTempFourth, radius; - TMatrixD *matricesCurrentV, *matricesCurrentVC; - TMatrixD* matricesCurrentCharge; - TMatrixD* residue; - Int_t iOne, jOne, tnRRow, tnZColumn, count; - iOne = 1 << (gridFrom - 1); - jOne = 1 << (gridFrom - 1); - - matricesCurrentV = nullptr; - matricesCurrentVC = nullptr; - matricesCurrentCharge = nullptr; - residue = nullptr; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - std::vector<float> coefficient1(nRRow); - std::vector<float> coefficient2(nZColumn); - - // 1) Go to coarsest level - for (count = gridFrom; count <= gridTo - 1; count++) { - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - inverseTempFourth = 1.0 / tempFourth; - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentCharge = tvCharge[count - 1]; - residue = tvResidue[count - 1]; - - // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi - for (Int_t jPre = 1; jPre <= nPre; jPre++) { - Relax2D(*matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - } - - // 2) Residue calculation - Residue2D(*residue, *matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, ih2, inverseTempFourth, tempRatio, - coefficient1, - coefficient2); - - iOne = 2 * iOne; - jOne = 2 * jOne; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - matricesCurrentCharge = tvCharge[count]; - matricesCurrentV = tvArrayV[count]; - - //3) Restriction - Restrict2D(*matricesCurrentCharge, *residue, tnRRow, tnZColumn); - - //4) Zeroing coarser V - matricesCurrentV->Zero(); - } - - // 5) coarsest grid - h = gridSizeR * iOne; - h2 = h * h; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - - Relax2D(*matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - - // Go to finest grid - for (count = gridTo - 1; count >= gridFrom; count--) { - - iOne = iOne / 2; - jOne = jOne / 2; - - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - inverseTempFourth = 1.0 / tempFourth; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - matricesCurrentCharge = tvCharge[count - 1]; - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentVC = tvArrayV[count]; - - // 6) Interpolation/Prolongation - AddInterp2D(*matricesCurrentV, *matricesCurrentVC, tnRRow, tnZColumn); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - - // 7) Post-Smoothing: Gauss-Seidel Relaxation - for (Int_t jPost = 1; jPost <= nPost; jPost++) { - Relax2D(*matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - } // end post smoothing - - //// DEBUG //// - //Info("VCycle2D",Form("Count %d", count)); - //Info("VCycle2D",Form("Exact Err: %f, MG Iteration : %d", (*fError)(mgCycle), mgCycle)); - //matricesCurrentV->Print(); - //matricesCurrentCharge->Print(); - } -} - -/// W-Cycle 2D -/// -/// Implementation non-recursive W-cycle for 2D -/// -/// Algorithms: -/// -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param gridFrom const Int_t finest level of grid -/// \param gridTo const Int_t coarsest level of grid -/// \param gamma const Int_t number of iterations at coarsest level -/// \param nPre const Int_t number of smoothing before coarsening -/// \param nPost const Int_t number of smoothing after coarsening -/// \param gridSizeR const Float_t grid size in r direction (OPTION, recalculate) -/// \param ratio const Float_t ratio between square of grid r and grid z (OPTION, recalculate) -/// \param tvArrayV vector<TMatrixD *> vector of V potential in different grids -/// \param tvCharge vector<TMatrixD *> vector of charge distribution in different grids -/// \param tvResidue vector<TMatrixD *> vector of residue calculation in different grids -/// -void AliTPCPoissonSolver::WCycle2D(const Int_t nRRow, const Int_t nZColumn, const Int_t gridFrom, const Int_t gridTo, - const int gamma, - const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, const Float_t ratio, - std::vector<TMatrixD*>& tvArrayV, - std::vector<TMatrixD*>& tvCharge, std::vector<TMatrixD*>& tvResidue) -{ - - Float_t h, h2, ih2, tempRatio, tempFourth, inverseTempFourth, radius; - TMatrixD *matricesCurrentV, *matricesCurrentVC; - TMatrixD* matricesCurrentCharge; - TMatrixD* residue; - Int_t iOne, jOne, tnRRow, tnZColumn, count; - iOne = 1 << (gridFrom - 1); - jOne = 1 << (gridFrom - 1); - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - std::vector<float> coefficient1(nRRow); - std::vector<float> coefficient2(nZColumn); - - // 1) Go to coarsest level - for (count = gridFrom; count <= gridTo - 2; count++) { - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - inverseTempFourth = 1.0 / tempFourth; - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentCharge = tvCharge[count - 1]; - residue = tvResidue[count - 1]; - - // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi - for (Int_t jPre = 1; jPre <= nPre; jPre++) { - Relax2D(*matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - } - - // 2) Residue calculation - Residue2D(*residue, *matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, ih2, inverseTempFourth, tempRatio, - coefficient1, - coefficient2); - - iOne = 2 * iOne; - jOne = 2 * jOne; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - matricesCurrentCharge = tvCharge[count]; - matricesCurrentV = tvArrayV[count]; - - //3) Restriction - Restrict2D(*matricesCurrentCharge, *residue, tnRRow, tnZColumn); - - //4) Zeroing coarser V - matricesCurrentV->Zero(); - } - - // Do V cycle from: gridTo-1 to gridTo gamma times - for (Int_t iGamma = 0; iGamma < gamma; iGamma++) { - VCycle2D(nRRow, nZColumn, gridTo - 1, gridTo, - nPre, nPost, gridSizeR, ratio, tvArrayV, - tvCharge, tvResidue); - } - - // Go to finest grid - for (count = gridTo - 2; count >= gridFrom; count--) { - - iOne = iOne / 2; - jOne = jOne / 2; - - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - tempRatio = ratio * iOne * iOne / (jOne * jOne); - tempFourth = 1.0 / (2.0 + 2.0 * tempRatio); - inverseTempFourth = 1.0 / tempFourth; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - matricesCurrentCharge = tvCharge[count - 1]; - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentVC = tvArrayV[count]; - - // 6) Interpolation/Prolongation - AddInterp2D(*matricesCurrentV, *matricesCurrentVC, tnRRow, tnZColumn); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - } - - // 7) Post-Smoothing: Gauss-Seidel Relaxation - for (Int_t jPost = 1; jPost <= nPost; jPost++) { - Relax2D(*matricesCurrentV, *matricesCurrentCharge, tnRRow, tnZColumn, h2, tempFourth, tempRatio, coefficient1, - coefficient2); - } // end post smoothing - } -} - -/// VCycle 3D2D, V Cycle 3D in multiGrid with constant phiSlice -/// fine-->coarsest-->fine, propagating the residue to correct initial guess of V -/// -/// Algorithm: -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slice == Arbitrary but greater than 3 -/// -/// DeltaPhi in Radians -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param gridFrom const Int_t finest level of grid -/// \param gridTo const Int_t coarsest level of grid -/// \param nPre const Int_t number of smoothing before coarsening -/// \param nPost const Int_t number of smoothing after coarsening -/// \param gridSizeR const Float_t grid size in r direction (OPTION, recalculate) -/// \param ratio const Float_t ratio between square of grid r and grid z (OPTION, recalculate) -/// \param tvArrayV vector<TMatrixD *> vector of V potential in different grids -/// \param tvCharge vector<TMatrixD *> vector of charge distribution in different grids -/// \param tvResidue vector<TMatrixD *> vector of residue calculation in different grids -/// \param coefficient1 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient2 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient3 std::vector<float>& coefficient for relaxation (ratio r/z) -/// \param coefficient4 std::vector<float>& coefficient for relaxation (ratio for grid_r) -/// \param inverseCoefficient4 std::vector<float>& coefficient for relaxation (inverse coefficient4) -/// -void AliTPCPoissonSolver::VCycle3D2D(const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, - const Int_t gridFrom, const Int_t gridTo, const Int_t nPre, const Int_t nPost, - const Float_t gridSizeR, const Float_t ratioZ, const Float_t ratioPhi, - std::vector<TMatrixD**>& tvArrayV, std::vector<TMatrixD**>& tvCharge, - std::vector<TMatrixD**>& tvResidue, std::vector<float>& coefficient1, - std::vector<float>& coefficient2, std::vector<float>& coefficient3, - std::vector<float>& coefficient4, - std::vector<float>& inverseCoefficient4) -{ - - Float_t h, h2, ih2, tempRatioZ, tempRatioPhi, radius; - TMatrixD **matricesCurrentV, **matricesCurrentVC; - TMatrixD** matricesCurrentCharge; - TMatrixD** residue; - Int_t iOne, jOne, tnRRow, tnZColumn, count; - - matricesCurrentV = nullptr; - matricesCurrentVC = nullptr; - matricesCurrentCharge = nullptr; - residue = nullptr; - - iOne = 1 << (gridFrom - 1); - jOne = 1 << (gridFrom - 1); - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - for (count = gridFrom; count <= gridTo - 1; count++) { - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - - tempRatioPhi = ratioPhi * iOne * iOne; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - inverseCoefficient4[i] = 1.0 / coefficient4[i]; - } - - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentCharge = tvCharge[count - 1]; - residue = tvResidue[count - 1]; - - //Info("VCycle3D2D","Before Pre-smoothing"); - //matricesCurrentV->Print(); - - // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi - for (Int_t jPre = 1; jPre <= nPre; jPre++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, - coefficient3, coefficient4); - } // end pre smoothing - - // 2) Residue calculation - Residue3D(residue, matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, ih2, tempRatioZ, - coefficient1, - coefficient2, - coefficient3, inverseCoefficient4); - - iOne = 2 * iOne; - jOne = 2 * jOne; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - matricesCurrentCharge = tvCharge[count]; - matricesCurrentV = tvArrayV[count]; - - //3) Restriction - //Restrict2D(*matricesCurrentCharge,*residue,tnRRow,tnZColumn); - Restrict3D(matricesCurrentCharge, residue, tnRRow, tnZColumn, phiSlice, phiSlice); - - //4) Zeroing coarser V - for (Int_t m = 0; m < phiSlice; m++) { - matricesCurrentV[m]->Zero(); - } - } - - // coarsest grid - h = gridSizeR * iOne; - h2 = h * h; - - tempRatioPhi = ratioPhi * iOne * iOne; - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 3) Relax on the coarsest grid - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, coefficient1, - coefficient2, - coefficient3, coefficient4); - - // back to fine - for (count = gridTo - 1; count >= gridFrom; count--) { - iOne = iOne / 2; - jOne = jOne / 2; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - h = gridSizeR * iOne; - h2 = h * h; - - tempRatioPhi = ratioPhi * iOne * iOne; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - matricesCurrentCharge = tvCharge[count - 1]; - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentVC = tvArrayV[count]; - - // 4) Interpolation/Prolongation - AddInterp3D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, phiSlice, phiSlice); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 5) Post-Smoothing: Gauss-Seidel Relaxation - for (Int_t jPost = 1; jPost <= nPost; jPost++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, - coefficient3, coefficient4); - } // end post smoothing - } -} - -/// VCycle 3D, V Cycle in multiGrid, fine-->coarsest-->fine, propagating the residue to correct initial guess of V -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slice == Arbitrary but greater than 3 -/// -/// DeltaPhi in Radians -/// -/// \param nRRow Int_t number of nRRow in the r direction of TPC -/// \param nZColumn Int_t number of nZColumn in z direction of TPC -/// \param phiSlice Int_t number of phiSlice in phi direction of T{C -/// \param symmetry Int_t symmetry or not -/// \param gridFrom const Int_t finest level of grid -/// \param gridTo const Int_t coarsest level of grid -/// \param nPre const Int_t number of smoothing before coarsening -/// \param nPost const Int_t number of smoothing after coarsening -/// \param gridSizeR const Float_t grid size in r direction (OPTION, recalculate) -/// \param ratioz const Float_t ratio between square of grid r and grid z (OPTION, recalculate) -/// \param tvArrayV vector<TMatrixD *> vector of V potential in different grids -/// \param tvCharge vector<TMatrixD *> vector of charge distribution in different grids -/// \param tvResidue vector<TMatrixD *> vector of residue calculation in different grids -/// \param coefficient1 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient2 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient3 std::vector<float>& coefficient for relaxation (ratio r/z) -/// \param coefficient4 std::vector<float>& coefficient for relaxation (ratio for grid_r) -/// \param inverseCoefficient4 std::vector<float>& coefficient for relaxation (inverse coefficient4) -/// -void AliTPCPoissonSolver::VCycle3D(const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, - const Int_t gridFrom, const Int_t gridTo, - const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, const Float_t ratioZ, - std::vector<TMatrixD**>& tvArrayV, std::vector<TMatrixD**>& tvCharge, - std::vector<TMatrixD**>& tvResidue, - std::vector<float>& coefficient1, std::vector<float>& coefficient2, - std::vector<float>& coefficient3, - std::vector<float>& coefficient4, std::vector<float>& inverseCoefficient4) -{ - - Float_t h, h2, ih2, tempRatioZ, tempRatioPhi, radius, tempGridSizePhi; - TMatrixD **matricesCurrentV, **matricesCurrentVC; - TMatrixD** matricesCurrentCharge; - TMatrixD** residue; - Int_t iOne, jOne, kOne, tnRRow, tnZColumn, tPhiSlice, otPhiSlice, count, nnPhi; - - matricesCurrentV = nullptr; - matricesCurrentVC = nullptr; - matricesCurrentCharge = nullptr; - residue = nullptr; - - iOne = 1 << (gridFrom - 1); - jOne = 1 << (gridFrom - 1); - kOne = 1 << (gridFrom - 1); - - nnPhi = phiSlice; - - while (nnPhi % 2 == 0) { - nnPhi /= 2; - } - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - - //Info("VCycle3D",Form("Grid information: tnRRow=%d, tcols=%d, tPhiSlice=%d\n", tnRRow,tnZColumn,tPhiSlice)); - - for (count = gridFrom; count <= gridTo - 1; count++) { - otPhiSlice = tPhiSlice; - - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - tempGridSizePhi = TMath::TwoPi() / tPhiSlice; // phi now is multiGrid - - tempRatioPhi = h * h / (tempGridSizePhi * tempGridSizePhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} - - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - inverseCoefficient4[i] = 1.0 / coefficient4[i]; - } - - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentCharge = tvCharge[count - 1]; - residue = tvResidue[count - 1]; - - //Info("VCycle3D","Before Pre-smoothing"); - //matricesCurrentV->Print(); - - // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi - for (Int_t jPre = 1; jPre <= nPre; jPre++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, coefficient3, coefficient4); - } // end pre smoothing - - // 2) Residue calculation - - Residue3D(residue, matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, tPhiSlice, symmetry, ih2, tempRatioZ, - coefficient1, coefficient2, coefficient3, inverseCoefficient4); - - iOne = 2 * iOne; - jOne = 2 * jOne; - kOne = 2 * kOne; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - - matricesCurrentCharge = tvCharge[count]; - matricesCurrentV = tvArrayV[count]; - //3) Restriction - Restrict3D(matricesCurrentCharge, residue, tnRRow, tnZColumn, tPhiSlice, otPhiSlice); - - //4) Zeroing coarser V - for (Int_t m = 0; m < tPhiSlice; m++) { - matricesCurrentV[m]->Zero(); - } - } - - // coarsest grid - h = gridSizeR * iOne; - h2 = h * h; - tempGridSizePhi = TMath::TwoPi() / tPhiSlice; // phi now is multiGrid - - tempRatioPhi = h * h / (tempGridSizePhi * tempGridSizePhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 3) Relax on the coarsest grid - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, coefficient1, - coefficient2, coefficient3, coefficient4); - - // back to fine - for (count = gridTo - 1; count >= gridFrom; count--) { - otPhiSlice = tPhiSlice; - - iOne = iOne / 2; - jOne = jOne / 2; - kOne = kOne / 2; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - tPhiSlice = kOne == 1 ? phiSlice : phiSlice / kOne; - tPhiSlice = tPhiSlice < nnPhi ? nnPhi : tPhiSlice; - - h = gridSizeR * iOne; - h2 = h * h; - tempGridSizePhi = TMath::TwoPi() / tPhiSlice; // phi now is multiGrid - - tempRatioPhi = h * h / (tempGridSizePhi * tempGridSizePhi); // ratio_{phi} = gridSize_{r} / gridSize_{phi} - - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - matricesCurrentCharge = tvCharge[count - 1]; - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentVC = tvArrayV[count]; - - // 4) Interpolation/Prolongation - - AddInterp3D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, tPhiSlice, otPhiSlice); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 5) Post-Smoothing: Gauss-Seidel Relaxation - for (Int_t jPost = 1; jPost <= nPost; jPost++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, tPhiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, - coefficient3, coefficient4); - } - } -} - -/// -/// Set matrix exact solution for relative error calculation -/// -/// \param exactSolution TMatrixD** pointer to exact solution (potential) in 3D -/// \param fPhiSlices const Int_t number of phi slices -/// -void AliTPCPoissonSolver::SetExactSolution(TMatrixD** exactSolution, const Int_t fPhiSlices) -{ - Double_t maxAbs; - fExactSolution = exactSolution; - fExactPresent = kTRUE; - fMaxExact = 0.0; - for (Int_t m = 0; m < fPhiSlices; m++) { - maxAbs = TMath::Max(TMath::Abs((*fExactSolution[m]).Max()), TMath::Abs((*fExactSolution[m]).Min())); - if (maxAbs > fMaxExact) { - fMaxExact = maxAbs; - } - } -} - -/// -/// Relative error calculation: comparison with exact solution -/// -/// \param matricesCurrentV TMatrixD** current potential (numerical solution) -/// \param tempArrayV TMatrixD** temporary matrix for calculating error -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param phiSlice const Int_t phi slices -/// -Double_t AliTPCPoissonSolver::GetExactError(TMatrixD** matricesCurrentV, TMatrixD** tempArrayV, const Int_t phiSlice) -{ - Double_t error = 0.0; - - if (fExactPresent == kTRUE) { - for (Int_t m = 0; m < phiSlice; m++) { - (*tempArrayV[m]) = (*fExactSolution[m]) - (*matricesCurrentV[m]); - (*tempArrayV[m]) *= 1.0 / GetMaxExact(); - if (tempArrayV[m]->E2Norm() > error) { - error = tempArrayV[m]->E2Norm(); - } - //printf("%f\n",tempArrayV[m]->E2Norm(); - } - } - return error; -} - -/// -/// Relative error calculation: comparison with exact solution -/// -/// \param matricesCurrentV TMatrixD** current potential (numerical solution) -/// \param tempArrayV TMatrixD** temporary matrix for calculating error -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param phiSlice const Int_t phi slices -/// -Double_t - AliTPCPoissonSolver::GetConvergenceError(TMatrixD** matricesCurrentV, TMatrixD** prevArrayV, const Int_t phiSlice) -{ - Double_t error = 0.0; - - for (Int_t m = 0; m < phiSlice; m++) { - - // absolute - (*prevArrayV[m]) = (*prevArrayV[m]) - (*matricesCurrentV[m]); - - if (prevArrayV[m]->E2Norm() > error) { - error = prevArrayV[m]->E2Norm(); - } - } - return error; -} - -///////////////////// interface for GPU /////////////////// - -/// VCycle 3D2D, V Cycle 3D in multiGrid with constant phiSlice -/// fine-->coarsest-->fine, propagating the residue to correct initial guess of V -/// -/// Algorithm: -/// -/// NOTE: In order for this algorithm to work, the number of nRRow and nZColumn must be a power of 2 plus one. -/// The number of nRRow and Z Column can be different. -/// -/// R Row == 2**M + 1 -/// Z Column == 2**N + 1 -/// Phi Slice == Arbitrary but greater than 3 -/// -/// DeltaPhi in Radians -/// \param nRRow Int_t number of grid in nRRow (in r-direction) for coarser grid should be 2^N + 1, finer grid in 2^{N+1} + 1 -/// \param nZColumn Int_t number of grid in nZColumn (in z-direction) for coarser grid should be 2^M + 1, finer grid in 2^{M+1} + 1 -/// \param gridFrom const Int_t finest level of grid -/// \param gridTo const Int_t coarsest level of grid -/// \param nPre const Int_t number of smoothing before coarsening -/// \param nPost const Int_t number of smoothing after coarsening -/// \param gridSizeR const Float_t grid size in r direction (OPTION, recalculate) -/// \param ratio const Float_t ratio between square of grid r and grid z (OPTION, recalculate) -/// \param tvArrayV vector<TMatrixD *> vector of V potential in different grids -/// \param tvCharge vector<TMatrixD *> vector of charge distribution in different grids -/// \param tvResidue vector<TMatrixD *> vector of residue calculation in different grids -/// \param coefficient1 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient2 std::vector<float>& coefficient for relaxation (r direction) -/// \param coefficient3 std::vector<float>& coefficient for relaxation (ratio r/z) -/// \param coefficient4 std::vector<float>& coefficient for relaxation (ratio for grid_r) -/// \param inverseCoefficient4 std::vector<float>& coefficient for relaxation (inverse coefficient4) -/// -void AliTPCPoissonSolver::VCycle3D2DGPU( - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, - const Int_t gridFrom, const Int_t gridTo, const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, - const Float_t ratioZ, const Float_t ratioPhi, std::vector<TMatrixD**>& tvArrayV, - std::vector<TMatrixD**>& tvCharge, std::vector<TMatrixD**>& tvResidue, std::vector<float>& coefficient1, - std::vector<float>& coefficient2, std::vector<float>& coefficient3, std::vector<float>& coefficient4, - std::vector<float>& inverseCoefficient4) -{ - Float_t h, h2, ih2, tempRatioZ, tempRatioPhi, radius; - TMatrixD **matricesCurrentV, **matricesCurrentVC; - TMatrixD** matricesCurrentCharge; - TMatrixD** residue; - Int_t iOne, jOne, tnRRow, tnZColumn, count; - - matricesCurrentV = nullptr; - matricesCurrentVC = nullptr; - matricesCurrentCharge = nullptr; - residue = nullptr; - - iOne = 1 << (gridFrom - 1); - jOne = 1 << (gridFrom - 1); - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - for (count = gridFrom; count <= gridTo - 1; count++) { - h = gridSizeR * iOne; - h2 = h * h; - ih2 = 1.0 / h2; - - tempRatioPhi = ratioPhi * iOne * iOne; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - inverseCoefficient4[i] = 1.0 / coefficient4[i]; - } - - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentCharge = tvCharge[count - 1]; - residue = tvResidue[count - 1]; - - //Info("VCycle3D2DGPU","Before Pre-smoothing"); - //matricesCurrentV->Print(); - - // 1) Pre-Smoothing: Gauss-Seidel Relaxation or Jacobi - for (Int_t jPre = 1; jPre <= nPre; jPre++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, - coefficient3, coefficient4); - } // end pre smoothing - - // 2) Residue calculation - Residue3D(residue, matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, ih2, tempRatioZ, - coefficient1, - coefficient2, - coefficient3, inverseCoefficient4); - - iOne = 2 * iOne; - jOne = 2 * jOne; - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - matricesCurrentCharge = tvCharge[count]; - matricesCurrentV = tvArrayV[count]; - - //3) Restriction - //Restrict2D(*matricesCurrentCharge,*residue,tnRRow,tnZColumn); - Restrict3D(matricesCurrentCharge, residue, tnRRow, tnZColumn, phiSlice, phiSlice); - - //4) Zeroing coarser V - for (Int_t m = 0; m < phiSlice; m++) { - matricesCurrentV[m]->Zero(); - } - } - - // coarsest grid - h = gridSizeR * iOne; - h2 = h * h; - - tempRatioPhi = ratioPhi * iOne * iOne; - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 3) Relax on the coarsest grid - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, coefficient1, - coefficient2, - coefficient3, coefficient4); - - // back to fine - for (count = gridTo - 1; count >= gridFrom; count--) { - iOne = iOne / 2; - jOne = jOne / 2; - - tnRRow = iOne == 1 ? nRRow : nRRow / iOne + 1; - tnZColumn = jOne == 1 ? nZColumn : nZColumn / jOne + 1; - - h = gridSizeR * iOne; - h2 = h * h; - - tempRatioPhi = ratioPhi * iOne * iOne; // Used tobe divided by ( m_one * m_one ) when m_one was != 1 - tempRatioZ = ratioZ * iOne * iOne / (jOne * jOne); - - matricesCurrentCharge = tvCharge[count - 1]; - matricesCurrentV = tvArrayV[count - 1]; - matricesCurrentVC = tvArrayV[count]; - - // 4) Interpolation/Prolongation - AddInterp3D(matricesCurrentV, matricesCurrentVC, tnRRow, tnZColumn, phiSlice, phiSlice); - - for (Int_t i = 1; i < tnRRow - 1; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * h; - coefficient1[i] = 1.0 + h / (2 * radius); - coefficient2[i] = 1.0 - h / (2 * radius); - coefficient3[i] = tempRatioPhi / (radius * radius); - coefficient4[i] = 0.5 / (1.0 + tempRatioZ + coefficient3[i]); - } - - // 5) Post-Smoothing: Gauss-Seidel Relaxation - for (Int_t jPost = 1; jPost <= nPost; jPost++) { - Relax3D(matricesCurrentV, matricesCurrentCharge, tnRRow, tnZColumn, phiSlice, symmetry, h2, tempRatioZ, - coefficient1, coefficient2, - coefficient3, coefficient4); - } // end post smoothing - } -} diff --git a/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.h b/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.h deleted file mode 100644 index 5aead1e7b555c..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCPoissonSolver.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCPoissonSolver.h -/// \brief This class provides implementation of Poisson Eq -/// solver by MultiGrid Method -/// -/// -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Nov 20, 2017 - -#ifndef ALITPCPOISSONSOLVER_H -#define ALITPCPOISSONSOLVER_H - -#include <TNamed.h> -#include "TMatrixD.h" -#include "TVectorD.h" - -class AliTPCPoissonSolver : public TNamed -{ - public: - ///< Enumeration of Poisson Solver Strategy Type - enum StrategyType { - kRelaxation = 0, ///< S.O.R Cascaded MultiGrid - kMultiGrid = 1, ///< Geometric MG - kFastRelaxation = 2 ///< Spectral (TODO) - }; - - ///< Enumeration of Cycles Type - enum CycleType { - kVCycle = 0, ///< V Cycle - kWCycle = 1, ///< W Cycle (TODO) - kFCycle = 2 ///< Full Cycle - }; - - ///< Fine -> Coarse Grid transfer operator types - enum GridTransferType { - kHalf = 0, ///< Half weighting - kFull = 1, ///< Full weighting - }; - - ///< Smoothing (Relax) operator types - enum RelaxType { - kJacobi = 0, ///< Jacobi (5 Stencil 2D, 7 Stencil 3D_ - kWeightedJacobi = 1, ///< (TODO) - kGaussSeidel = 2 ///< Gauss Seidel 2D (2 Color, 5 Stencil), 3D (7 Stencil) - }; - - ///< Coarse -> fine operator types (TODO: Interp and Restrict in one packet, just one enumeration) - enum InterpType { - kHalfInterp = 0, ///< Half bi linear interpolation - kFullInterp = 1 ///< Full bi linear interpolation - }; - - ///< Parameters choice for MultiGrid algorithm - struct MGParameters { - Bool_t isFull3D; ///< TRUE: full coarsening, FALSE: semi coarsening - CycleType cycleType; ///< cycleType follow CycleType - GridTransferType gtType; ///< gtType grid transfer type follow GridTransferType - RelaxType relaxType; ///< relaxType follow RelaxType - Int_t gamma; ///< number of iteration at coarsest level - Int_t nPre; ///< number of iteration for pre smoothing - Int_t nPost; ///< number of iteration for post smoothing - Int_t nMGCycle; ///< number of multi grid cycle (V type) - Int_t maxLoop; ///< the number of tree-deep of multi grid - - // default values - MGParameters() - { - isFull3D = kFALSE; - cycleType = kFCycle; - gtType = kFull; // default full - relaxType = kGaussSeidel; // default relaxation method - nPre = 2; - nPost = 2; - nMGCycle = 200; - maxLoop = 6; - } - }; - - AliTPCPoissonSolver(); - AliTPCPoissonSolver(const char* name, const char* title); -#if (defined(__CINT__) || defined(__ROOTCINT__)) && !defined(__CLING__) - ~AliTPCPoissonSolver(); -#else - ~AliTPCPoissonSolver() override; -#endif - void PoissonSolver2D(TMatrixD& matrixV, TMatrixD& chargeDensity, Int_t nRRow, Int_t nZColumn, Int_t maxIterations); - void PoissonSolver3D(TMatrixD** matricesV, TMatrixD** matricesChargeDensities, Int_t nRRow, Int_t nZColumn, - Int_t phiSlice, Int_t maxIterations, Int_t symmetry); - - void SetStrategy(StrategyType strategy) { fStrategy = strategy; } - StrategyType GetStrategy() { return fStrategy; } - - static const Double_t fgkTPCZ0; ///< nominal gating grid position - static const Double_t fgkIFCRadius; ///< Mean Radius of the Inner Field Cage ( 82.43 min, 83.70 max) (cm) - static const Double_t fgkOFCRadius; ///< Mean Radius of the Outer Field Cage (252.55 min, 256.45 max) (cm) - static const Double_t fgkZOffSet; ///< Offset from CE: calculate all distortions closer to CE as if at this point - static const Double_t fgkCathodeV; ///< Cathode Voltage (volts) - static const Double_t fgkGG; ///< Gating Grid voltage (volts) - static const Double_t fgkdvdE; ///< [cm/V] drift velocity dependency on the E field (from Magboltz for NeCO2N2 at standard environment) - static const Double_t fgkEM; ///< charge/mass in [C/kg] - static const Double_t fgke0; ///< vacuum permittivity [A·s/(V·m)] - - static Double_t fgExactErr; ///< Error tolerated - static Double_t fgConvergenceError; ///< Error tolerated - Int_t fIterations; ///< number of maximum iteration - MGParameters fMgParameters; ///< parameters multi grid - - void SetExactSolution(TMatrixD** exactSolution, const Int_t fPhiSlices); - void SetCycleType(AliTPCPoissonSolver::CycleType cycleType) { fMgParameters.cycleType = cycleType; } - - private: - AliTPCPoissonSolver(const AliTPCPoissonSolver&); // not implemented - AliTPCPoissonSolver& operator=(const AliTPCPoissonSolver&); // not implemented - StrategyType fStrategy = kMultiGrid; ///< strategy used default multiGrid - TMatrixD** fExactSolution = nullptr; //!<! Pointer to exact solution - /// TODO: remove pointers? - TVectorD* fErrorConvergenceNorm2; ///< for storing convergence error norm2 - TVectorD* fErrorConvergenceNormInf; ///< for storing convergence error normInf - TVectorD* fError; ///< for storing error - Double_t GetMaxExact() { return fMaxExact; }; - - void PoissonRelaxation2D(TMatrixD& matrixV, TMatrixD& chargeDensity, Int_t nRRow, Int_t nZColumn, - Int_t maxIterations); - void PoissonRelaxation3D(TMatrixD** matricesV, TMatrixD** matricesChargeDensities, Int_t nRRow, - Int_t nZColumn, Int_t phiSlice, Int_t maxIterations, Int_t symmetry); - void PoissonMultiGrid2D(TMatrixD& matrixV, TMatrixD& chargeDensity, Int_t nRRow, Int_t nZColumn); - void PoissonMultiGrid3D2D(TMatrixD** matricesV, TMatrixD** matricesChargeDensities, Int_t nRRow, - Int_t nZColumn, Int_t phiSlice, Int_t symmetry); - void PoissonMultiGrid3D(TMatrixD** matricesV, TMatrixD** matricesChargeDensities, Int_t nRRow, - Int_t nZColumn, Int_t phiSlice, Int_t symmetry); - Int_t IsPowerOfTwo(Int_t i) const; - void Relax2D(TMatrixD& matrixV, TMatrixD& matrixCharge, const Int_t tnRRow, const Int_t tnZColumn, - const Float_t h2, const Float_t tempFourth, const Float_t tempRatio, - std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2); - void Relax3D(TMatrixD** currentMatricesV, TMatrixD** matricesCharge, const Int_t tnRRow, const Int_t tnZColumn, - const Int_t phiSlice, const Int_t symmetry, const Float_t h2, const Float_t tempRatioZ, - std::vector<float>& vectorCoefficient1, std::vector<float>& vectorCoefficient2, - std::vector<float>& vectorCoefficient3, - std::vector<float>& vectorCoefficient4); - void Residue2D(TMatrixD& residue, TMatrixD& matrixV, TMatrixD& matrixCharge, - const Int_t tnRRow, const Int_t tnZColumn, const Float_t ih2, const Float_t iTempFourth, - const Float_t tempRatio, std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2); - void Residue3D(TMatrixD** residue, TMatrixD** currentMatricesV, TMatrixD** matricesCharge, const Int_t tnRRow, - const Int_t tnZColumn, const Int_t phiSlice, const Int_t symmetry, const Float_t ih2, - const Float_t tempRatio, std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2, - std::vector<float>& vectorCoefficient3, std::vector<float>& vectorInverseCoefficient4); - void Restrict2D(TMatrixD& matrixCharge, TMatrixD& residue, const Int_t tnRRow, const Int_t tnZColumn); - void Restrict3D(TMatrixD** matricesCharge, TMatrixD** residue, const Int_t tnRRow, const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice); - void RestrictBoundary2D(TMatrixD& matrixCharge, TMatrixD& residue, const Int_t tnRRow, const Int_t tnZColumn); - void RestrictBoundary3D(TMatrixD** matricesCharge, TMatrixD** residue, const Int_t tnRRow, const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice); - - void AddInterp2D(TMatrixD& matrixV, TMatrixD& matrixVC, const Int_t tnRRow, const Int_t tnZColumn); - void AddInterp3D(TMatrixD** currentMatricesV, TMatrixD** currentMatricesVC, const Int_t tnRRow, const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice); - void Interp2D(TMatrixD& matrixV, TMatrixD& matrixVC, const Int_t tnRRow, const Int_t tnZColumn); - - void Interp3D(TMatrixD** currentMatricesV, TMatrixD** currentMatricesVC, const Int_t tnRRow, const Int_t tnZColumn, - const Int_t newPhiSlice, const Int_t oldPhiSlice); - void VCycle2D(const Int_t nRRow, const Int_t nZColumn, const Int_t gridFrom, const Int_t gridTo, const Int_t nPre, - const Int_t nPost, const Float_t gridSizeR, const Float_t ratio, std::vector<TMatrixD*>& tvArrayV, - std::vector<TMatrixD*>& tvCharge, std::vector<TMatrixD*>& tvResidue); - void WCycle2D(const Int_t nRRow, const Int_t nZColumn, const Int_t gridFrom, const Int_t gridTo, const Int_t gamma, - const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, const Float_t ratio, - std::vector<TMatrixD*>& tvArrayV, - std::vector<TMatrixD*>& tvCharge, std::vector<TMatrixD*>& tvResidue); - void - VCycle3D(const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, const Int_t gridFrom, - const Int_t gridTo, const Int_t nPre, const Int_t nPost, const Float_t gridSizeR, const Float_t ratioZ, - std::vector<TMatrixD**>& tvArrayV, std::vector<TMatrixD**>& tvCharge, - std::vector<TMatrixD**>& tvResidue, std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2, - std::vector<float>& vectorCoefficient3, std::vector<float>& vectorCoefficient4, - std::vector<float>& vectorInverseCoefficient4); - void VCycle3D2D(const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, - const Int_t gridFrom, const Int_t gridTo, const Int_t nPre, const Int_t nPost, - const Float_t gridSizeR, - const Float_t ratioZ, const Float_t ratioPhi, std::vector<TMatrixD**>& tvArrayV, - std::vector<TMatrixD**>& tvCharge, std::vector<TMatrixD**>& tvResidue, - std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2, std::vector<float>& vectorCoefficient3, - std::vector<float>& vectorCoefficient4, - std::vector<float>& vectorInverseCoefficient4); - void VCycle3D2DGPU(const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t symmetry, - const Int_t gridFrom, const Int_t gridTo, const Int_t nPre, - const Int_t nPost, const Float_t gridSizeR, const Float_t ratioZ, const Float_t ratioPhi, - std::vector<TMatrixD**>& tvArrayV, std::vector<TMatrixD**>& tvCharge, - std::vector<TMatrixD**>& tvResidue, std::vector<float>& vectorCoefficient1, - std::vector<float>& vectorCoefficient2, - std::vector<float>& vectorCoefficient3, std::vector<float>& vectorCoefficient4, - std::vector<float>& vectorInverseCoefficient4); - Double_t GetExactError(TMatrixD** currentMatricesV, TMatrixD** tempArrayV, const Int_t phiSlice); - Double_t GetConvergenceError(TMatrixD** currentMatricesV, TMatrixD** prevArrayV, const Int_t phiSlice); - Double_t fMaxExact; - Bool_t fExactPresent = kFALSE; - /// \cond CLASSIMP -#if defined(ROOT_VERSION_CODE) && ROOT_VERSION_CODE >= ROOT_VERSION(6, 0, 0) - ClassDefOverride(AliTPCPoissonSolver, 5); -#else - ClassDefNV(AliTPCPoissonSolver, 5); -#endif - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.cxx b/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.cxx deleted file mode 100644 index 14dea14dbc555..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.cxx +++ /dev/null @@ -1,5315 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCSpaceCharge3DCalc.cxx -/// \brief This class provides distortion and correction map with integration following electron drift -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Nov 20, 2017 - -#include "TStopwatch.h" -#include "TMath.h" -#include "AliTPCSpaceCharge3DCalc.h" - -/// \cond CLASSIMP -ClassImp(AliTPCSpaceCharge3DCalc); -/// \endcond - -/// Construction for AliTPCSpaceCharge3DCalc class -/// Default values -/// ~~~ -/// fInterpolationOrder = 5; // interpolation cubic spline with 5 points -/// fNRRows = 129; -/// fNPhiSlices = 180; // the maximum of phi-slices so far = (8 per sector) -/// fNZColumns = 129; // the maximum on column-slices so ~ 2cm slicing -/// ~~~ -AliTPCSpaceCharge3DCalc::AliTPCSpaceCharge3DCalc() -{ - InitAllocateMemory(); -} - -/// Member values from params -/// -/// \param nRRow Int_t number of grid in r direction -/// \param nZColumn Int_t number of grid in z direction -/// \param nPhiSlice Int_t number of grid in \f$ \phi \f$ direction -/// -AliTPCSpaceCharge3DCalc::AliTPCSpaceCharge3DCalc(Int_t nRRow, - Int_t nZColumn, Int_t nPhiSlice) - : fNRRows(nRRow), - fNPhiSlices(nPhiSlice), - fNZColumns(nZColumn) -{ - InitAllocateMemory(); -} - -/// Construction for AliTPCSpaceCharge3DCalc class -/// Member values from params -/// -/// \param nRRow Int_t number of grid in r direction -/// \param nZColumn Int_t number of grid in z direction -/// \param nPhiSlice Int_t number of grid in \f$ \phi \f$ direction -/// \param interpolationOrder Int_t order of interpolation -/// \param strategy Int_t strategy for global distortion -/// \param rbfKernelType Int_t strategy for global distortion -/// -AliTPCSpaceCharge3DCalc::AliTPCSpaceCharge3DCalc( - Int_t nRRow, Int_t nZColumn, Int_t nPhiSlice, Int_t interpolationOrder, - Int_t irregularGridSize, Int_t rbfKernelType) - : fNRRows(nRRow), - fNPhiSlices(nPhiSlice), - fNZColumns(nZColumn), - fInterpolationOrder(interpolationOrder), - fIrregularGridSize(irregularGridSize), - fRBFKernelType(rbfKernelType) -{ - InitAllocateMemory(); -} - -/// Memory allocation for working/output memory -/// -void AliTPCSpaceCharge3DCalc::InitAllocateMemory() -{ - fPoissonSolver = new AliTPCPoissonSolver(); - - fListR = new Double_t[fNRRows]; - fListPhi = new Double_t[fNPhiSlices]; - fListZ = new Double_t[fNZColumns]; - fListZA = new Double_t[fNZColumns]; - fListZC = new Double_t[fNZColumns]; - - // allocate for boundary - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // Int_t len = 2 * fNPhiSlices * (fNZColumns + fNRRows) - (4 * fNPhiSlices); - // fListPotentialBoundaryA = new Double_t[len]; - // fListPotentialBoundaryC = new Double_t[len]; - - Int_t phiSlicesPerSector = fNPhiSlices / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNRRows - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZColumns - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhiSlices; - - for (Int_t k = 0; k < fNPhiSlices; k++) { - fListPhi[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < fNRRows; i++) { - fListR[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < fNZColumns; j++) { - fListZ[j] = (j * gridSizeZ); - fListZA[j] = (j * gridSizeZ); - fListZC[j] = (j * gridSizeZ); - } - - fMatrixIntDistDrEzA = new TMatrixD*[fNPhiSlices]; - fMatrixIntDistDPhiREzA = new TMatrixD*[fNPhiSlices]; - fMatrixIntDistDzA = new TMatrixD*[fNPhiSlices]; - - fMatrixIntDistDrEzC = new TMatrixD*[fNPhiSlices]; - fMatrixIntDistDPhiREzC = new TMatrixD*[fNPhiSlices]; - fMatrixIntDistDzC = new TMatrixD*[fNPhiSlices]; - - fMatrixErOverEzA = new TMatrixD*[fNPhiSlices]; - fMatrixEPhiOverEzA = new TMatrixD*[fNPhiSlices]; - fMatrixDeltaEzA = new TMatrixD*[fNPhiSlices]; - - fMatrixErOverEzC = new TMatrixD*[fNPhiSlices]; - fMatrixEPhiOverEzC = new TMatrixD*[fNPhiSlices]; - fMatrixDeltaEzC = new TMatrixD*[fNPhiSlices]; - - fMatrixIntCorrDrEzA = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDPhiREzA = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDzA = new TMatrixD*[fNPhiSlices]; - - fMatrixIntCorrDrEzC = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDPhiREzC = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDzC = new TMatrixD*[fNPhiSlices]; - - fMatrixIntCorrDrEzIrregularA = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDPhiREzIrregularA = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDzIrregularA = new TMatrixD*[fNPhiSlices]; - fMatrixRListIrregularA = new TMatrixD*[fNPhiSlices]; - fMatrixPhiListIrregularA = new TMatrixD*[fNPhiSlices]; - fMatrixZListIrregularA = new TMatrixD*[fNPhiSlices]; - - fMatrixIntCorrDrEzIrregularC = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDPhiREzIrregularC = new TMatrixD*[fNPhiSlices]; - fMatrixIntCorrDzIrregularC = new TMatrixD*[fNPhiSlices]; - fMatrixRListIrregularC = new TMatrixD*[fNPhiSlices]; - fMatrixPhiListIrregularC = new TMatrixD*[fNPhiSlices]; - fMatrixZListIrregularC = new TMatrixD*[fNPhiSlices]; - - fMatrixChargeA = new TMatrixD*[fNPhiSlices]; - fMatrixChargeC = new TMatrixD*[fNPhiSlices]; - fMatrixChargeInverseA = new TMatrixD*[fNPhiSlices]; - fMatrixChargeInverseC = new TMatrixD*[fNPhiSlices]; - fMatrixPotentialA = new TMatrixD*[fNPhiSlices]; - fMatrixPotentialC = new TMatrixD*[fNPhiSlices]; - - for (Int_t k = 0; k < fNPhiSlices; k++) { - - fMatrixIntDistDrEzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntDistDPhiREzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntDistDzA[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixIntDistDrEzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntDistDPhiREzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntDistDzC[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixIntCorrDrEzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDPhiREzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDzA[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixIntCorrDrEzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDPhiREzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDzC[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixErOverEzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixEPhiOverEzA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixDeltaEzA[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixErOverEzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixEPhiOverEzC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixDeltaEzC[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixIntCorrDrEzIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDPhiREzIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDzIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixRListIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixPhiListIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixZListIrregularA[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixIntCorrDrEzIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDPhiREzIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixIntCorrDzIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixRListIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixPhiListIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixZListIrregularC[k] = new TMatrixD(fNRRows, fNZColumns); - - fMatrixChargeA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixChargeC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixChargeInverseA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixChargeInverseC[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixPotentialA[k] = new TMatrixD(fNRRows, fNZColumns); - fMatrixPotentialC[k] = new TMatrixD(fNRRows, fNZColumns); - } - - fLookupIntDistA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixIntDistDrEzA, fListR, fNPhiSlices, fMatrixIntDistDPhiREzA, fListPhi, - fNZColumns, fMatrixIntDistDzA, fListZA, fInterpolationOrder); - fLookupIntDistC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixIntDistDrEzC, fListR, fNPhiSlices, fMatrixIntDistDPhiREzC, fListPhi, - fNZColumns, fMatrixIntDistDzC, fListZC, fInterpolationOrder); - fLookupIntCorrA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixIntCorrDrEzA, fListR, fNPhiSlices, fMatrixIntCorrDPhiREzA, fListPhi, - fNZColumns, fMatrixIntCorrDzA, fListZA, fInterpolationOrder); - fLookupIntCorrC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixIntCorrDrEzC, fListR, fNPhiSlices, fMatrixIntCorrDPhiREzC, fListPhi, - fNZColumns, fMatrixIntCorrDzC, fListZC, fInterpolationOrder); - - fLookupIntENoDriftA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixErOverEzA, fListR, fNPhiSlices, fMatrixEPhiOverEzA, fListPhi, - fNZColumns, fMatrixDeltaEzA, fListZA, fInterpolationOrder); - fLookupIntENoDriftC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, fMatrixErOverEzC, fListR, fNPhiSlices, fMatrixEPhiOverEzC, fListPhi, - fNZColumns, fMatrixDeltaEzC, fListZC, fInterpolationOrder); - fLookupIntCorrIrregularA = - new AliTPCLookUpTable3DInterpolatorIrregularD( - fNRRows, fMatrixIntCorrDrEzIrregularA, fMatrixRListIrregularA, fNPhiSlices, - fMatrixIntCorrDPhiREzIrregularA, fMatrixPhiListIrregularA, fNZColumns, - fMatrixIntCorrDzIrregularA, fMatrixZListIrregularA, 2, GetIrregularGridSize(), - GetIrregularGridSize(), GetIrregularGridSize(), 1); - - fLookupIntCorrIrregularC = - new AliTPCLookUpTable3DInterpolatorIrregularD( - fNRRows, fMatrixIntCorrDrEzIrregularC, fMatrixRListIrregularC, fNPhiSlices, - fMatrixIntCorrDPhiREzIrregularC, fMatrixPhiListIrregularC, fNZColumns, - fMatrixIntCorrDzIrregularC, fMatrixZListIrregularC, 2, GetIrregularGridSize(), - GetIrregularGridSize(), GetIrregularGridSize(), 1); - - fInterpolatorChargeA = new AliTPC3DCylindricalInterpolator(); - fInterpolatorChargeC = new AliTPC3DCylindricalInterpolator(); - fInterpolatorPotentialA = new AliTPC3DCylindricalInterpolator(); - fInterpolatorPotentialC = new AliTPC3DCylindricalInterpolator(); - fInterpolatorInverseChargeA = new AliTPC3DCylindricalInterpolator(); - fInterpolatorInverseChargeC = new AliTPC3DCylindricalInterpolator(); - - fInterpolatorChargeA->SetNR(fNRRows); - fInterpolatorChargeA->SetNZ(fNZColumns); - fInterpolatorChargeA->SetNPhi(fNPhiSlices); - fInterpolatorChargeA->SetNGridPoints(); - fInterpolatorChargeA->SetRList(fListR); - fInterpolatorChargeA->SetZList(fListZA); - fInterpolatorChargeA->SetPhiList(fListPhi); - fInterpolatorChargeA->SetOrder(fInterpolationOrder); - - fInterpolatorChargeC->SetNR(fNRRows); - fInterpolatorChargeC->SetNZ(fNZColumns); - fInterpolatorChargeC->SetNPhi(fNPhiSlices); - fInterpolatorChargeC->SetNGridPoints(); - fInterpolatorChargeC->SetRList(fListR); - fInterpolatorChargeC->SetZList(fListZC); - fInterpolatorChargeC->SetPhiList(fListPhi); - fInterpolatorChargeC->SetOrder(fInterpolationOrder); - - fInterpolatorPotentialA->SetNR(fNRRows); - fInterpolatorPotentialA->SetNZ(fNZColumns); - fInterpolatorPotentialA->SetNPhi(fNPhiSlices); - fInterpolatorPotentialA->SetNGridPoints(); - fInterpolatorPotentialA->SetRList(fListR); - fInterpolatorPotentialA->SetZList(fListZA); - fInterpolatorPotentialA->SetPhiList(fListPhi); - fInterpolatorPotentialA->SetOrder(fInterpolationOrder); - - fInterpolatorPotentialC->SetNR(fNRRows); - fInterpolatorPotentialC->SetNZ(fNZColumns); - fInterpolatorPotentialC->SetNPhi(fNPhiSlices); - fInterpolatorPotentialC->SetNGridPoints(); - fInterpolatorPotentialC->SetRList(fListR); - fInterpolatorPotentialC->SetZList(fListZA); - fInterpolatorPotentialC->SetPhiList(fListPhi); - fInterpolatorPotentialC->SetOrder(fInterpolationOrder); - - fInterpolatorInverseChargeA->SetNR(fNRRows); - fInterpolatorInverseChargeA->SetNZ(fNZColumns); - fInterpolatorInverseChargeA->SetNPhi(fNPhiSlices); - fInterpolatorInverseChargeA->SetNGridPoints(); - fInterpolatorInverseChargeA->SetRList(fListR); - fInterpolatorInverseChargeA->SetZList(fListZA); - fInterpolatorInverseChargeA->SetPhiList(fListPhi); - fInterpolatorInverseChargeA->SetOrder(fInterpolationOrder); - - fInterpolatorInverseChargeC->SetNR(fNRRows); - fInterpolatorInverseChargeC->SetNZ(fNZColumns); - fInterpolatorInverseChargeC->SetNPhi(fNPhiSlices); - fInterpolatorInverseChargeC->SetNGridPoints(); - fInterpolatorInverseChargeC->SetRList(fListR); - fInterpolatorInverseChargeC->SetZList(fListZC); - fInterpolatorInverseChargeC->SetPhiList(fListPhi); - fInterpolatorInverseChargeC->SetOrder(fInterpolationOrder); - - fLookupDistA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupDistC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupCorrA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupCorrC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupInverseDistA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupInverseDistC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupElectricFieldA = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupElectricFieldC = - new AliTPCLookUpTable3DInterpolatorD( - fNRRows, nullptr, fListR, fNPhiSlices, nullptr, fListPhi, fNZColumns, nullptr, fListZA, - fInterpolationOrder); - - fLookupIntCorrIrregularA->SetKernelType(fRBFKernelType); - fLookupIntCorrIrregularC->SetKernelType(fRBFKernelType); -} -/// Destruction for AliTPCSpaceCharge3DCalc -/// Deallocate memory for lookup table and charge distribution -/// -AliTPCSpaceCharge3DCalc::~AliTPCSpaceCharge3DCalc() -{ - - if (fPoissonSolver != nullptr) { - delete fPoissonSolver; - } - - for (Int_t k = 0; k < fNPhiSlices; k++) { - delete fMatrixIntDistDrEzA[k]; - delete fMatrixIntDistDPhiREzA[k]; - delete fMatrixIntDistDzA[k]; - delete fMatrixIntDistDrEzC[k]; - delete fMatrixIntDistDPhiREzC[k]; - delete fMatrixIntDistDzC[k]; - delete fMatrixIntCorrDrEzA[k]; - delete fMatrixIntCorrDPhiREzA[k]; - delete fMatrixIntCorrDzA[k]; - delete fMatrixIntCorrDrEzC[k]; - delete fMatrixIntCorrDPhiREzC[k]; - delete fMatrixIntCorrDzC[k]; - delete fMatrixErOverEzA[k]; - delete fMatrixEPhiOverEzA[k]; - delete fMatrixDeltaEzA[k]; - delete fMatrixErOverEzC[k]; - delete fMatrixEPhiOverEzC[k]; - delete fMatrixDeltaEzC[k]; - delete fMatrixIntCorrDrEzIrregularA[k]; - delete fMatrixIntCorrDPhiREzIrregularA[k]; - delete fMatrixIntCorrDzIrregularA[k]; - delete fMatrixRListIrregularA[k]; - delete fMatrixPhiListIrregularA[k]; - delete fMatrixZListIrregularA[k]; - delete fMatrixIntCorrDrEzIrregularC[k]; - delete fMatrixIntCorrDPhiREzIrregularC[k]; - delete fMatrixIntCorrDzIrregularC[k]; - delete fMatrixRListIrregularC[k]; - delete fMatrixPhiListIrregularC[k]; - delete fMatrixZListIrregularC[k]; - delete fMatrixChargeA[k]; - delete fMatrixChargeC[k]; - delete fMatrixChargeInverseA[k]; - delete fMatrixChargeInverseC[k]; - - delete fMatrixPotentialA[k]; - delete fMatrixPotentialC[k]; - } - delete[] fListR; - delete[] fListPhi; - delete[] fListZ; - delete[] fListZA; - delete[] fListZC; - - delete fLookupIntDistA; - delete fLookupIntDistC; - delete fLookupIntENoDriftA; - delete fLookupIntENoDriftC; - delete fLookupIntCorrA; - delete fLookupIntCorrC; - delete fLookupIntCorrIrregularA; - delete fLookupIntCorrIrregularC; - delete fLookupDistA; - delete fLookupDistC; - delete fLookupInverseDistA; - delete fLookupInverseDistC; - delete fLookupElectricFieldA; - delete fLookupElectricFieldC; - delete fInterpolatorChargeA; - delete fInterpolatorPotentialA; - delete fInterpolatorChargeC; - delete fInterpolatorPotentialC; - delete fInterpolatorInverseChargeA; - delete fInterpolatorInverseChargeC; - - delete fHistogram3DSpaceCharge; - delete fHistogram3DSpaceChargeA; - delete fHistogram3DSpaceChargeC; - - delete fFormulaBoundaryIFCA; - delete fFormulaBoundaryIFCC; - delete fFormulaBoundaryOFCA; - delete fFormulaBoundaryOFCC; - delete fFormulaBoundaryROCA; - delete fFormulaBoundaryROCC; - delete fFormulaBoundaryCE; - - delete fFormulaPotentialV; - delete fFormulaChargeRho; - - delete fFormulaEPhi; - delete fFormulaEr; - delete fFormulaEz; - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // delete[] fListPotentialBoundaryA; - // delete[] fListPotentialBoundaryC; -} - -/// Creating look-up tables of Correction/Distortion by integration following -/// drift line, input from space charge 3d histogram (fSpaceCharge3D) and boundary values are filled with zeroes -/// -/// TODO: provide an interface for setting boundary values -/// -/// The algorithm and implementations of this function is the following: -/// -/// Do for each side A,C -/// -/// 1) Solving \f$ \nabla^2 \Phi(r,\phi,z) = - \rho(r,\phi,z)\f$ -/// ~~~ Calling poisson solver -/// fPoissonSolver->PoissonSolver3D( matricesV, matricesCharge, nRRow, nZColumn, phiSlice, maxIteration, symmetry ) ; -/// ~~~ -/// -/// 2) Get the electric field \f$ \vec{E} = - \nabla \Phi(r,\phi,z) \f$ -/// ~~~ -/// ElectricField( matricesV, matricesEr, matricesEPhi, matricesEz, nRRow, nZColumn, phiSlice, -/// gridSizeR, gridSizePhi ,gridSizeZ,symmetry, AliTPCPoissonSolver::fgkIFCRadius); -/// ~~~ -/// -/// 3) Calculate local distortion and correction, using Langevin formula -/// ~~~ cxx -/// LocalDistCorrDz (matricesEr, matricesEPhi, matricesEz, -/// matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, -/// matricesCorrDrDz, matricesCorrDPhiRDz, matricesCorrDz, -/// nRRow, nZColumn, phiSlice, gridSizeZ, ezField); -/// ~~~ -/// -/// 4) Integrate distortion by following the drift line -/// -/// 5) Fill look up table for Integral distortion -/// -/// 6) Fill look up table for Integral correction -/// -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slice in \f$ phi \f$ direction -/// \param maxIteration Int_t Maximum iteration for poisson solver -/// \param stoppingConvergence Convergence error stopping condition for poisson solver -/// -/// \post Lookup tables for distortion: -/// ~~~ -/// fLookUpIntDistDrEz,fLookUpIntDistDPhiREz,fLookUpIntDistDz -/// ~~~ -/// and correction: -/// ~~~ -/// fLookUpIntCorrDrEz,fLookUpIntCorrDPhiREz,fLookUpIntCorrDz -/// ~~~ -/// are initialized -/// -void AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz( - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stoppingConvergence) -{ - Int_t phiSlicesPerSector = phiSlice / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - - // local variables - Float_t radius0, phi0, z0; - - // memory allocation for temporary matrices: - // potential (boundary values), charge distribution - TMatrixD **matricesV, *matricesCharge[phiSlice]; - TMatrixD *matricesEr[phiSlice], *matricesEPhi[phiSlice], *matricesEz[phiSlice]; - TMatrixD *matricesDistDrDz[phiSlice], *matricesDistDPhiRDz[phiSlice], *matricesDistDz[phiSlice]; - TMatrixD *matricesCorrDrDz[phiSlice], *matricesCorrDPhiRDz[phiSlice], *matricesCorrDz[phiSlice]; - TMatrixD *matricesGDistDrDz[phiSlice], *matricesGDistDPhiRDz[phiSlice], *matricesGDistDz[phiSlice]; - TMatrixD *matricesGCorrDrDz[phiSlice], *matricesGCorrDPhiRDz[phiSlice], *matricesGCorrDz[phiSlice]; - - for (Int_t k = 0; k < phiSlice; k++) { - //matricesV[k] = new TMatrixD(nRRow, nZColumn); - matricesCharge[k] = new TMatrixD(nRRow, nZColumn); - matricesEr[k] = new TMatrixD(nRRow, nZColumn); - matricesEPhi[k] = new TMatrixD(nRRow, nZColumn); - matricesEz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDz[k] = new TMatrixD(nRRow, nZColumn); - } - - // list of point as used in the poisson relaxation and the interpolation (for interpolation) - Double_t rList[nRRow], zList[nZColumn], phiList[phiSlice]; - - // pointer to current TF1 for potential boundary values - TF1* f1BoundaryIFC = nullptr; - TF1* f1BoundaryOFC = nullptr; - TF1* f1BoundaryROC = nullptr; - TStopwatch w; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = j * gridSizeZ; - } - - // allocate look up local distortion - AliTPCLookUpTable3DInterpolatorD* lookupLocalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesDistDrDz, rList, phiSlice, matricesDistDPhiRDz, phiList, nZColumn, matricesDistDz, - zList, fInterpolationOrder); - - // allocate look up local correction - AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesCorrDrDz, rList, phiSlice, matricesCorrDPhiRDz, phiList, nZColumn, matricesCorrDz, - zList, fInterpolationOrder); - - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGDistDrDz, rList, phiSlice, matricesGDistDPhiRDz, phiList, nZColumn, matricesGDistDz, - zList, fInterpolationOrder); - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGCorrDrDz, rList, phiSlice, matricesGCorrDPhiRDz, phiList, nZColumn, matricesGCorrDz, - zList, fInterpolationOrder); - - // should be set, in another place - const Int_t symmetry = 0; // fSymmetry - - // for irregular - TMatrixD** matricesIrregularDrDz = nullptr; - TMatrixD** matricesIrregularDPhiRDz = nullptr; - TMatrixD** matricesIrregularDz = nullptr; - TMatrixD** matricesPhiIrregular = nullptr; - TMatrixD** matricesRIrregular = nullptr; - TMatrixD** matricesZIrregular = nullptr; - - // for charge - TMatrixD** matricesLookUpCharge = nullptr; - AliTPC3DCylindricalInterpolator* chargeInterpolator = nullptr; - AliTPC3DCylindricalInterpolator* potentialInterpolator = nullptr; - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // Double_t* potentialBoundary = nullptr; - TMatrixD* matrixV; - TMatrixD* matrixCharge; - // for potential - TMatrixD** matricesVPotential; - - Int_t pIndex = 0; - - // do if look up table haven't be initialized - if (!fInitLookUp) { - // initialize for working memory - for (Int_t side = 0; side < 2; side++) { - // zeroing global distortion/correction - for (Int_t k = 0; k < phiSlice; k++) { - matricesDistDrDz[k]->Zero(); - matricesDistDPhiRDz[k]->Zero(); - matricesDistDz[k]->Zero(); - matricesCorrDrDz[k]->Zero(); - matricesCorrDPhiRDz[k]->Zero(); - matricesCorrDz[k]->Zero(); - - matricesGDistDrDz[k]->Zero(); - matricesGDistDPhiRDz[k]->Zero(); - matricesGDistDz[k]->Zero(); - matricesGCorrDrDz[k]->Zero(); - matricesGCorrDPhiRDz[k]->Zero(); - matricesGCorrDz[k]->Zero(); - } - if (side == 0) { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularA; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularA; - matricesIrregularDz = fMatrixIntCorrDzIrregularA; - - matricesPhiIrregular = fMatrixPhiListIrregularA; - matricesRIrregular = fMatrixRListIrregularA; - matricesZIrregular = fMatrixZListIrregularA; - matricesLookUpCharge = fMatrixChargeA; - - matricesV = fMatrixPotentialA; - chargeInterpolator = fInterpolatorChargeA; - potentialInterpolator = fInterpolatorPotentialA; - fLookupDistA->SetLookUpR(matricesDistDrDz); - fLookupDistA->SetLookUpPhi(matricesDistDPhiRDz); - fLookupDistA->SetLookUpZ(matricesDistDz); - fLookupCorrA->SetLookUpR(matricesCorrDrDz); - fLookupCorrA->SetLookUpPhi(matricesCorrDPhiRDz); - fLookupCorrA->SetLookUpZ(matricesCorrDz); - - fLookupElectricFieldA->SetLookUpR(matricesEr); - fLookupElectricFieldA->SetLookUpPhi(matricesEPhi); - fLookupElectricFieldA->SetLookUpZ(matricesEz); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryA; - f1BoundaryIFC = fFormulaBoundaryIFCA; - f1BoundaryOFC = fFormulaBoundaryOFCA; - f1BoundaryROC = fFormulaBoundaryROCA; - } else { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularC; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularC; - matricesIrregularDz = fMatrixIntCorrDzIrregularC; - matricesPhiIrregular = fMatrixPhiListIrregularC; - matricesRIrregular = fMatrixRListIrregularC; - matricesZIrregular = fMatrixZListIrregularC; - matricesLookUpCharge = fMatrixChargeC; - matricesV = fMatrixPotentialC; - chargeInterpolator = fInterpolatorChargeC; - potentialInterpolator = fInterpolatorPotentialC; - fLookupDistC->SetLookUpR(matricesDistDrDz); - fLookupDistC->SetLookUpPhi(matricesDistDPhiRDz); - fLookupDistC->SetLookUpZ(matricesDistDz); - fLookupCorrC->SetLookUpR(matricesCorrDrDz); - fLookupCorrC->SetLookUpPhi(matricesCorrDPhiRDz); - fLookupCorrC->SetLookUpZ(matricesCorrDz); - fLookupElectricFieldC->SetLookUpR(matricesEr); - fLookupElectricFieldC->SetLookUpPhi(matricesEPhi); - fLookupElectricFieldC->SetLookUpZ(matricesEz); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryC; - f1BoundaryIFC = fFormulaBoundaryIFCC; - f1BoundaryOFC = fFormulaBoundaryOFCC; - f1BoundaryROC = fFormulaBoundaryROCC; - } - - // fill the potential boundary - // guess the initial potential - // fill also charge - //pIndex = 0; - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step = 0: Fill Boundary and Charge Densities")); - for (Int_t k = 0; k < phiSlice; k++) { - phi0 = k * gridSizePhi; - matrixV = matricesV[k]; - matrixCharge = matricesCharge[k]; - for (Int_t i = 0; i < nRRow; i++) { - radius0 = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - for (Int_t j = 0; j < nZColumn; j++) { - z0 = j * gridSizeZ; - (*matrixCharge)(i, j) = chargeInterpolator->GetValue(rList[i], phiList[k], zList[j]); - (*matrixV)(i, j) = 0.0; // fill zeros - - if (fFormulaPotentialV == nullptr) { - // boundary IFC - if (i == 0) { - if (f1BoundaryIFC != nullptr) { - if (TF2* f2BoundaryIFC = dynamic_cast<TF2*>(f1BoundaryIFC)) { - (*matrixV)(i, j) = f2BoundaryIFC->Eval(z0, phi0); - } else { - (*matrixV)(i, j) = f1BoundaryIFC->Eval(z0); - } - } - } - if (i == (nRRow - 1)) { - if (f1BoundaryOFC != nullptr) { - if (TF2* f2BoundaryOFC = dynamic_cast<TF2*>(f1BoundaryOFC)) { - (*matrixV)(i, j) = f2BoundaryOFC->Eval(z0, phi0); - } else { - (*matrixV)(i, j) = f1BoundaryOFC->Eval(z0); - } - } - } - if (j == 0) { - if (fFormulaBoundaryCE) { - if (TF2* f2FormulaBoundaryCE = dynamic_cast<TF2*>(fFormulaBoundaryCE)) { - (*matrixV)(i, j) = f2FormulaBoundaryCE->Eval(radius0, phi0); - } else { - (*matrixV)(i, j) = fFormulaBoundaryCE->Eval(radius0); - } - } - } - if (j == (nZColumn - 1)) { - if (f1BoundaryROC != nullptr) { - if (TF2* f2BoundaryROC = dynamic_cast<TF2*>(f1BoundaryROC)) { - (*matrixV)(i, j) = f2BoundaryROC->Eval(radius0, phi0); - } else { - (*matrixV)(i, j) = f1BoundaryROC->Eval(radius0); - } - } - } - } else { - if ((i == 0) || (i == (nRRow - 1)) || (j == 0) || (j == (nZColumn - 1))) { - (*matrixV)(i, j) = fFormulaPotentialV->Eval(radius0, phi0, z0); - } - } - } - } - } - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 0: Preparing Charge interpolator: %f\n", w.CpuTime())); - AliTPCPoissonSolver::fgConvergenceError = stoppingConvergence; - - //fPoissonSolver->SetStrategy(AliTPCPoissonSolver::kMultiGrid); - //(fPoissonSolver->fMgParameters).cycleType = AliTPCPoissonSolver::kFCycle; - //(fPoissonSolver->fMgParameters).isFull3D = kFALSE; - //(fPoissonSolver->fMgParameters).nMGCycle = maxIteration; - //(fPoissonSolver->fMgParameters).maxLoop = 6; - - w.Start(); - fPoissonSolver->PoissonSolver3D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, maxIteration, symmetry); - w.Stop(); - - potentialInterpolator->SetValue(matricesV); - potentialInterpolator->InitCubicSpline(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 1: Poisson solver: %f\n", w.CpuTime())); - if (side == 0) { - myProfile.poissonSolverTime = w.CpuTime(); - } - if (side == 0) { - myProfile.iteration = fPoissonSolver->fIterations; - } - - w.Start(); - ElectricField(matricesV, - matricesEr, matricesEPhi, matricesEz, nRRow, nZColumn, phiSlice, - gridSizeR, gridSizePhi, gridSizeZ, symmetry, AliTPCPoissonSolver::fgkIFCRadius); - w.Stop(); - - myProfile.electricFieldTime = w.CpuTime(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 2: Electric Field Calculation: %f\n", w.CpuTime())); - w.Start(); - LocalDistCorrDz(matricesEr, matricesEPhi, matricesEz, - matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, - matricesCorrDrDz, matricesCorrDPhiRDz, matricesCorrDz, - nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - w.Stop(); - myProfile.localDistortionTime = w.CpuTime(); - - // copy to interpolator - if (side == 0) { - lookupLocalDist->CopyFromMatricesToInterpolator(); - lookupLocalCorr->CopyFromMatricesToInterpolator(); - fLookupDistA->CopyFromMatricesToInterpolator(); - fLookupCorrA->CopyFromMatricesToInterpolator(); - fLookupElectricFieldA->CopyFromMatricesToInterpolator(); - } else { - lookupLocalDist->CopyFromMatricesToInterpolator(); - lookupLocalCorr->CopyFromMatricesToInterpolator(); - fLookupDistC->CopyFromMatricesToInterpolator(); - fLookupCorrC->CopyFromMatricesToInterpolator(); - fLookupElectricFieldC->CopyFromMatricesToInterpolator(); - } - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 3: Local distortion and correction: %f\n", w.CpuTime())); - w.Start(); - if (fIntegrationStrategy == kNaive) { - IntegrateDistCorrDriftLineDz( - lookupLocalDist, - matricesGDistDrDz, matricesGDistDPhiRDz, matricesGDistDz, - lookupLocalCorr, - matricesGCorrDrDz, matricesGCorrDPhiRDz, matricesGCorrDz, - matricesIrregularDrDz, matricesIrregularDPhiRDz, matricesIrregularDz, - matricesRIrregular, matricesPhiIrregular, matricesZIrregular, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } else { - IntegrateDistCorrDriftLineDzWithLookUp( - lookupLocalDist, - matricesGDistDrDz, matricesGDistDPhiRDz, matricesGDistDz, - lookupLocalCorr, - matricesGCorrDrDz, matricesGCorrDPhiRDz, matricesGCorrDz, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 4: Global correction/distortion: %f\n", w.CpuTime())); - myProfile.globalDistortionTime = w.CpuTime(); - - //// copy to 1D interpolator ///// - lookupGlobalDist->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - lookupGlobalCorr->CopyFromMatricesToInterpolator(); - } - //// - - w.Stop(); - - if (side == 0) { - - w.Start(); - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzA, fMatrixIntDistDPhiREzA, fMatrixIntDistDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - if (fCorrectionType == 0) { - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzA, fMatrixIntCorrDPhiREzA, fMatrixIntCorrDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } - - fLookupIntDistA->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrA->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularA->CopyFromMatricesToInterpolator(); - } - - w.Stop(); - myProfile.interpolationInitTime = w.CpuTime(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 5: Filling up the look up: %f\n", w.CpuTime())); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " A side done"); - } - if (side == 1) { - w.Start(); - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzC, fMatrixIntDistDPhiREzC, fMatrixIntDistDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - if (fCorrectionType == 0) { - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzC, fMatrixIntCorrDPhiREzC, fMatrixIntCorrDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } - - fLookupIntDistC->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrC->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularC->CopyFromMatricesToInterpolator(); - } - w.Stop(); - myProfile.interpolationInitTime = w.CpuTime(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " C side done"); - } - } - - fInitLookUp = kTRUE; - } - - // memory de-allocation for temporary matrices - for (Int_t k = 0; k < phiSlice; k++) { - //delete matricesV[k]; - delete matricesCharge[k]; - delete matricesEr[k]; - delete matricesEPhi[k]; - delete matricesEz[k]; - delete matricesDistDrDz[k]; - delete matricesDistDPhiRDz[k]; - delete matricesDistDz[k]; - - delete matricesCorrDrDz[k]; - delete matricesCorrDPhiRDz[k]; - delete matricesCorrDz[k]; - delete matricesGDistDrDz[k]; - delete matricesGDistDPhiRDz[k]; - delete matricesGDistDz[k]; - - delete matricesGCorrDrDz[k]; - delete matricesGCorrDPhiRDz[k]; - delete matricesGCorrDz[k]; - } - delete lookupLocalDist; - delete lookupLocalCorr; - delete lookupGlobalDist; - delete lookupGlobalCorr; -} - -// outdated, to be removed once modifications in aliroot are pushed -/// Creating look-up tables of Correction/Distortion by integration following -/// drift line with known distributions for potential and space charge. -/// -/// -/// \param nRRow Int_t number of grid in row direction -/// \param nZColumn Int_t number of grid in z direction -/// \param phiSlice Int_t number of slices in phi direction -/// \param maxIteration Int_t max iteration for convergence -/// \param stopConvergence Double_t stopping criteria for convergence -/// \param matricesDistDrDzA TMatrixD** local r distortion (output) A side -/// \param matricesDistDPhiRDzA TMatrixD** local r phi distortion (output) A side -/// \param matricesDistDzA TMatrixD** local z distortion (output) A side -/// \param matricesCorrDrDzA TMatrixD** local r correction (output) A side -/// \param matricesCorrDPhiRDzA TMatrixD** local r phi correction (output) A side -/// \param matricesCorrDzA TMatrixD** local z correction (output) A side -/// \param matricesDistDrDzC TMatrixD** local r distortion (output) C side -/// \param matricesDistDPhiRDzC TMatrixD** local r phi distortion (output) C side -/// \param matricesDistDzC TMatrixD** local z distortion (output) C side -/// \param matricesCorrDrDzC TMatrixD** local r phi correction (output) C side -/// \param matricesCorrDPhiRDzC TMatrixD** local r phi correction (output) C side -/// \param matricesCorrDzC TMatrixD** local z correction (output) C side -/// -/// \post Lookup tables for distortion: -/// ~~~ -/// fLookUpIntDistDrEz,fLookUpIntDistDPhiREz,fLookUpIntDistDz -/// ~~~ -/// and correction: -/// ~~~ -/// fLookUpIntCorrDrEz,fLookUpIntCorrDPhiREz,fLookUpIntCorrDz -/// ~~~ -/// are initialized -/// -void AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz( - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stopConvergence, - TMatrixD** matricesErA, TMatrixD** matricesEPhiA, TMatrixD** matricesEzA, - TMatrixD** matricesErC, TMatrixD** matricesEPhiC, TMatrixD** matricesEzC, - TMatrixD** matricesDistDrDzA, TMatrixD** matricesDistDPhiRDzA, TMatrixD** matricesDistDzA, - TMatrixD** matricesCorrDrDzA, TMatrixD** matricesCorrDPhiRDzA, TMatrixD** matricesCorrDzA, - TMatrixD** matricesDistDrDzC, TMatrixD** matricesDistDPhiRDzC, TMatrixD** matricesDistDzC, - TMatrixD** matricesCorrDrDzC, TMatrixD** matricesCorrDPhiRDzC, TMatrixD** matricesCorrDzC, - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction) -{ - Int_t phiSlicesPerSector = phiSlice / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - - // local variables - Float_t radius0, phi0, z0; - - // memory allocation for temporary matrices: - // potential (boundary values), charge distribution - TMatrixD *matricesV[phiSlice], *matricesCharge[phiSlice]; - TMatrixD *matricesEr[phiSlice], *matricesEPhi[phiSlice], *matricesEz[phiSlice]; - TMatrixD *matricesDistDrDz[phiSlice], *matricesDistDPhiRDz[phiSlice], *matricesDistDz[phiSlice]; - TMatrixD *matricesCorrDrDz[phiSlice], *matricesCorrDPhiRDz[phiSlice], *matricesCorrDz[phiSlice]; - TMatrixD *matricesGDistDrDz[phiSlice], *matricesGDistDPhiRDz[phiSlice], *matricesGDistDz[phiSlice]; - TMatrixD *matricesGCorrDrDz[phiSlice], *matricesGCorrDPhiRDz[phiSlice], *matricesGCorrDz[phiSlice]; - - for (Int_t k = 0; k < phiSlice; k++) { - matricesV[k] = new TMatrixD(nRRow, nZColumn); - matricesCharge[k] = new TMatrixD(nRRow, nZColumn); - matricesEr[k] = new TMatrixD(nRRow, nZColumn); - matricesEPhi[k] = new TMatrixD(nRRow, nZColumn); - matricesEz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDz[k] = new TMatrixD(nRRow, nZColumn); - } - - // list of point as used in the poisson relaxation and the interpolation (for interpolation) - Double_t rList[nRRow], zList[nZColumn], phiList[phiSlice]; - - // pointer to current TF1 for potential boundary values - TF1* f1BoundaryIFC = nullptr; - TF1* f1BoundaryOFC = nullptr; - TF1* f1BoundaryROC = nullptr; - TStopwatch w; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = j * gridSizeZ; - } - - // allocate look up local distortion - AliTPCLookUpTable3DInterpolatorD* lookupLocalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesDistDrDz, rList, phiSlice, matricesDistDPhiRDz, phiList, nZColumn, matricesDistDz, - zList, fInterpolationOrder); - - // allocate look up local correction - AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesCorrDrDz, rList, phiSlice, matricesCorrDPhiRDz, phiList, nZColumn, matricesCorrDz, - zList, fInterpolationOrder); - - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGDistDrDz, rList, phiSlice, matricesGDistDPhiRDz, phiList, nZColumn, matricesGDistDz, - zList, fInterpolationOrder); - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGCorrDrDz, rList, phiSlice, matricesGCorrDPhiRDz, phiList, nZColumn, matricesGCorrDz, - zList, fInterpolationOrder); - - // should be set, in another place - const Int_t symmetry = 0; // fSymmetry - - // for irregular - TMatrixD** matricesIrregularDrDz = nullptr; - TMatrixD** matricesIrregularDPhiRDz = nullptr; - TMatrixD** matricesIrregularDz = nullptr; - TMatrixD** matricesPhiIrregular = nullptr; - TMatrixD** matricesRIrregular = nullptr; - TMatrixD** matricesZIrregular = nullptr; - - // for charge - TMatrixD** matricesLookUpCharge = nullptr; - AliTPC3DCylindricalInterpolator* chargeInterpolator = nullptr; - AliTPC3DCylindricalInterpolator* potentialInterpolator = nullptr; - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // Double_t* potentialBoundary = nullptr; - TMatrixD* matrixV; - TMatrixD* matrixCharge; - Int_t pIndex = 0; - - // do if look up table haven't be initialized - if (!fInitLookUp) { - // initialize for working memory - for (Int_t side = 0; side < 2; side++) { - // zeroing global distortion/correction - for (Int_t k = 0; k < phiSlice; k++) { - matricesDistDrDz[k]->Zero(); - matricesDistDPhiRDz[k]->Zero(); - matricesDistDz[k]->Zero(); - matricesCorrDrDz[k]->Zero(); - matricesCorrDPhiRDz[k]->Zero(); - matricesCorrDz[k]->Zero(); - - matricesGDistDrDz[k]->Zero(); - matricesGDistDPhiRDz[k]->Zero(); - matricesGDistDz[k]->Zero(); - matricesGCorrDrDz[k]->Zero(); - matricesGCorrDPhiRDz[k]->Zero(); - matricesGCorrDz[k]->Zero(); - } - if (side == 0) { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularA; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularA; - matricesIrregularDz = fMatrixIntCorrDzIrregularA; - - matricesPhiIrregular = fMatrixPhiListIrregularA; - matricesRIrregular = fMatrixRListIrregularA; - matricesZIrregular = fMatrixZListIrregularA; - matricesLookUpCharge = fMatrixChargeA; - chargeInterpolator = fInterpolatorChargeA; - potentialInterpolator = fInterpolatorPotentialA; - fLookupDistA->SetLookUpR(matricesDistDrDzA); - fLookupDistA->SetLookUpPhi(matricesDistDPhiRDzA); - fLookupDistA->SetLookUpZ(matricesDistDzA); - lookupLocalDist->SetLookUpR(matricesDistDrDzA); - lookupLocalDist->SetLookUpPhi(matricesDistDPhiRDzA); - lookupLocalDist->SetLookUpZ(matricesDistDzA); - - lookupLocalCorr->SetLookUpR(matricesCorrDrDzA); - lookupLocalCorr->SetLookUpPhi(matricesCorrDPhiRDzA); - lookupLocalCorr->SetLookUpZ(matricesCorrDzA); - - fLookupElectricFieldA->SetLookUpR(matricesErA); - fLookupElectricFieldA->SetLookUpPhi(matricesEPhiA); - fLookupElectricFieldA->SetLookUpZ(matricesEzA); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryA; - f1BoundaryIFC = fFormulaBoundaryIFCA; - f1BoundaryOFC = fFormulaBoundaryOFCA; - f1BoundaryROC = fFormulaBoundaryROCA; - } else { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularC; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularC; - matricesIrregularDz = fMatrixIntCorrDzIrregularC; - matricesPhiIrregular = fMatrixPhiListIrregularC; - matricesRIrregular = fMatrixRListIrregularC; - matricesZIrregular = fMatrixZListIrregularC; - matricesLookUpCharge = fMatrixChargeC; - chargeInterpolator = fInterpolatorChargeC; - potentialInterpolator = fInterpolatorPotentialC; - fLookupDistC->SetLookUpR(matricesDistDrDzC); - fLookupDistC->SetLookUpPhi(matricesDistDPhiRDzC); - fLookupDistC->SetLookUpZ(matricesDistDzC); - fLookupElectricFieldC->SetLookUpR(matricesErC); - fLookupElectricFieldC->SetLookUpPhi(matricesEPhiC); - fLookupElectricFieldC->SetLookUpZ(matricesEzC); - - lookupLocalDist->SetLookUpR(matricesDistDrDzC); - lookupLocalDist->SetLookUpPhi(matricesDistDPhiRDzC); - lookupLocalDist->SetLookUpZ(matricesDistDzC); - - lookupLocalCorr->SetLookUpR(matricesCorrDrDzC); - lookupLocalCorr->SetLookUpPhi(matricesCorrDPhiRDzC); - lookupLocalCorr->SetLookUpZ(matricesCorrDzC); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryC; - f1BoundaryIFC = fFormulaBoundaryIFCC; - f1BoundaryOFC = fFormulaBoundaryOFCC; - f1BoundaryROC = fFormulaBoundaryROCC; - } - - // fill the potential boundary - // guess the initial potential - // fill also charge - //pIndex = 0; - - //Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz","%s",Form("Step = 0: Fill Boundary and Charge Densities")); - for (Int_t k = 0; k < phiSlice; k++) { - phi0 = k * gridSizePhi; - matrixV = matricesV[k]; - matrixCharge = matricesCharge[k]; - for (Int_t i = 0; i < nRRow; i++) { - radius0 = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - for (Int_t j = 0; j < nZColumn; j++) { - z0 = j * gridSizeZ; - (*matrixCharge)(i, j) = chargeInterpolator->GetValue(rList[i], phiList[k], zList[j]); - (*matrixV)(i, j) = fFormulaPotentialV->Eval(radius0, phi0, z0); - } - } - } - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 0: Preparing Charge interpolator: %f\n", w.CpuTime())); - //AliTPCPoissonSolver::fgConvergenceError = stoppingConvergence; - - //fPoissonSolver->SetStrategy(AliTPCPoissonSolver::kMultiGrid); - //(fPoissonSolver->fMgParameters).cycleType = AliTPCPoissonSolver::kFCycle; - //(fPoissonSolver->fMgParameters).isFull3D = kFALSE; - //(fPoissonSolver->fMgParameters).nMGCycle = maxIteration; - //(fPoissonSolver->fMgParameters).maxLoop = 6; - - w.Start(); - //fPoissonSolver->PoissonSolver3D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, maxIteration, - // symmetry); - w.Stop(); - - potentialInterpolator->SetValue(matricesV); - potentialInterpolator->InitCubicSpline(); - - // copy to interpolator - if (side == 0) { - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 1: Poisson solver: %f\n", w.CpuTime())); - w.Start(); - ElectricField(matricesV, - matricesErA, matricesEPhiA, matricesEzA, nRRow, nZColumn, phiSlice, - gridSizeR, gridSizePhi, gridSizeZ, symmetry, AliTPCPoissonSolver::fgkIFCRadius); - w.Stop(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 2: Electric Field Calculation: %f\n", w.CpuTime())); - w.Start(); - LocalDistCorrDz(matricesErA, matricesEPhiA, matricesEzA, - matricesDistDrDzA, matricesDistDPhiRDzA, matricesDistDzA, - matricesCorrDrDzA, matricesCorrDPhiRDzA, matricesCorrDzA, - nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - //LocalDistCorrDz(intErDzTestFunction, intEPhiRDzTestFunction, intDzTestFunction, - // GetEzFormula(), rList, phiList, zList, - // matricesDistDrDzA, matricesDistDPhiRDzA, matricesDistDzA, - // matricesCorrDrDzA, matricesCorrDPhiRDzA, matricesCorrDzA, - // nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 3: Local distortion and correction: %f\n", w.CpuTime())); - - lookupLocalDist->CopyFromMatricesToInterpolator(); - lookupLocalCorr->CopyFromMatricesToInterpolator(); - fLookupDistA->CopyFromMatricesToInterpolator(); - fLookupElectricFieldA->CopyFromMatricesToInterpolator(); - } else { - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 1: Poisson solver: %f\n", w.CpuTime())); - w.Start(); - ElectricField(matricesV, - matricesErC, matricesEPhiC, matricesEzC, nRRow, nZColumn, phiSlice, - gridSizeR, gridSizePhi, gridSizeZ, symmetry, AliTPCPoissonSolver::fgkIFCRadius); - w.Stop(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 2: Electric Field Calculation: %f\n", w.CpuTime())); - w.Start(); - LocalDistCorrDz(matricesErC, matricesEPhiC, matricesEzC, - matricesDistDrDzC, matricesDistDPhiRDzC, matricesDistDzC, - matricesCorrDrDzC, matricesCorrDPhiRDzC, matricesCorrDzC, - nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - //LocalDistCorrDz(intErDzTestFunction, intEPhiRDzTestFunction, intDzTestFunction, - // GetEzFormula(), rList, phiList, zList, - // matricesDistDrDzC, matricesDistDPhiRDzC, matricesDistDzC, - // matricesCorrDrDzC, matricesCorrDPhiRDzC, matricesCorrDzC, - // nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 3: Local distortion and correction: %f\n", w.CpuTime())); - lookupLocalDist->CopyFromMatricesToInterpolator(); - lookupLocalCorr->CopyFromMatricesToInterpolator(); - fLookupDistC->CopyFromMatricesToInterpolator(); - fLookupElectricFieldC->CopyFromMatricesToInterpolator(); - } - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 3: Local distortion and correction: %f\n", w.CpuTime())); - w.Start(); - if (fIntegrationStrategy == kNaive) { - IntegrateDistCorrDriftLineDz( - lookupLocalDist, - matricesGDistDrDz, matricesGDistDPhiRDz, matricesGDistDz, - lookupLocalCorr, - matricesGCorrDrDz, matricesGCorrDPhiRDz, matricesGCorrDz, - matricesIrregularDrDz, matricesIrregularDPhiRDz, matricesIrregularDz, - matricesRIrregular, matricesPhiIrregular, matricesZIrregular, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } else { - IntegrateDistCorrDriftLineDzWithLookUp( - lookupLocalDist, - matricesGDistDrDz, matricesGDistDPhiRDz, matricesGDistDz, - lookupLocalCorr, - matricesGCorrDrDz, matricesGCorrDPhiRDz, matricesGCorrDz, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - } - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 4: Global correction/distortion: %f\n", w.CpuTime())); - - //// copy to 1D interpolator ///// - lookupGlobalDist->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - lookupGlobalCorr->CopyFromMatricesToInterpolator(); - } - //// - - w.Start(); - //// copy to 1D interpolator ///// - lookupGlobalDist->CopyFromMatricesToInterpolator(); - lookupGlobalCorr->CopyFromMatricesToInterpolator(); - //// - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 5: Filling up the look up: %f\n", w.CpuTime())); - - if (side == 0) { - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzA, fMatrixIntDistDPhiREzA, fMatrixIntDistDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzA, fMatrixIntCorrDPhiREzA, fMatrixIntCorrDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - fLookupIntDistA->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrA->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularA->CopyFromMatricesToInterpolator(); - } - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " A side done"); - } - if (side == 1) { - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzC, fMatrixIntDistDPhiREzC, fMatrixIntDistDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzC, fMatrixIntCorrDPhiREzC, fMatrixIntCorrDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - fLookupIntDistC->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrC->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularC->CopyFromMatricesToInterpolator(); - } - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " C side done"); - } - } - - fInitLookUp = kTRUE; - } - - // memory de-allocation for temporary matrices - for (Int_t k = 0; k < phiSlice; k++) { - delete matricesV[k]; - delete matricesCharge[k]; - delete matricesEr[k]; - delete matricesEPhi[k]; - delete matricesEz[k]; - delete matricesDistDrDz[k]; - delete matricesDistDPhiRDz[k]; - delete matricesDistDz[k]; - - delete matricesCorrDrDz[k]; - delete matricesCorrDPhiRDz[k]; - delete matricesCorrDz[k]; - delete matricesGDistDrDz[k]; - delete matricesGDistDPhiRDz[k]; - delete matricesGDistDz[k]; - - delete matricesGCorrDrDz[k]; - delete matricesGCorrDPhiRDz[k]; - delete matricesGCorrDz[k]; - } - delete lookupLocalDist; - delete lookupLocalCorr; - delete lookupGlobalDist; - delete lookupGlobalCorr; -} - -/// Creating look-up tables of Correction/Distortion by integration following -/// drift line with known distributions for potential and space charge. -/// -/// -/// \param nRRow Int_t number of grid in row direction -/// \param nZColumn Int_t number of grid in z direction -/// \param phiSlice Int_t number of slices in phi direction -/// \param maxIteration Int_t max iteration for convergence -/// \param stopConvergence Double_t stopping criteria for convergence -/// \param matricesCorrDzC TMatrixD** local z correction (output) C side -/// \param intErDzTestFunction TFormula* analytic function for closed integration of Er in z direction -/// \param intEPhiRDzTestFunction TFormula* analytic function for closed integration of EPhi in z direction -/// \param intDzTestFunction TFormula* analytic function for closed integration of Ez in z direction -/// -/// \post Lookup tables for distortion: -/// ~~~ -/// fLookUpIntDistDrEz,fLookUpIntDistDPhiREz,fLookUpIntDistDz -/// ~~~ -/// and correction: -/// ~~~ -/// fLookUpIntCorrDrEz,fLookUpIntCorrDPhiREz,fLookUpIntCorrDz -/// ~~~ -/// are initialized -/// -void AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz( - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stopConvergence, - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction) -{ - Int_t phiSlicesPerSector = phiSlice / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - - // local variables - Float_t radius0, phi0, z0; - - // memory allocation for temporary matrices: - // potential (boundary values), charge distribution - TMatrixD *matricesV[phiSlice], *matricesCharge[phiSlice]; - TMatrixD *matricesEr[phiSlice], *matricesEPhi[phiSlice], *matricesEz[phiSlice]; - TMatrixD *matricesDistDrDz[phiSlice], *matricesDistDPhiRDz[phiSlice], *matricesDistDz[phiSlice]; - TMatrixD *matricesCorrDrDz[phiSlice], *matricesCorrDPhiRDz[phiSlice], *matricesCorrDz[phiSlice]; - TMatrixD *matricesGDistDrDz[phiSlice], *matricesGDistDPhiRDz[phiSlice], *matricesGDistDz[phiSlice]; - TMatrixD *matricesGCorrDrDz[phiSlice], *matricesGCorrDPhiRDz[phiSlice], *matricesGCorrDz[phiSlice]; - - for (Int_t k = 0; k < phiSlice; k++) { - matricesV[k] = new TMatrixD(nRRow, nZColumn); - matricesCharge[k] = new TMatrixD(nRRow, nZColumn); - matricesEr[k] = new TMatrixD(nRRow, nZColumn); - matricesEPhi[k] = new TMatrixD(nRRow, nZColumn); - matricesEz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesCorrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGDistDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDrDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDPhiRDz[k] = new TMatrixD(nRRow, nZColumn); - matricesGCorrDz[k] = new TMatrixD(nRRow, nZColumn); - } - - // list of point as used in the poisson relaxation and the interpolation (for interpolation) - Double_t rList[nRRow], zList[nZColumn], phiList[phiSlice]; - - // pointer to current TF1 for potential boundary values - TF1* f1BoundaryIFC = nullptr; - TF1* f1BoundaryOFC = nullptr; - TF1* f1BoundaryROC = nullptr; - TStopwatch w; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = j * gridSizeZ; - } - - // allocate look up local distortion - AliTPCLookUpTable3DInterpolatorD* lookupLocalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesDistDrDz, rList, phiSlice, matricesDistDPhiRDz, phiList, nZColumn, matricesDistDz, - zList, fInterpolationOrder); - - // allocate look up local correction - AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesCorrDrDz, rList, phiSlice, matricesCorrDPhiRDz, phiList, nZColumn, matricesCorrDz, - zList, fInterpolationOrder); - - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalDist = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGDistDrDz, rList, phiSlice, matricesGDistDPhiRDz, phiList, nZColumn, matricesGDistDz, - zList, fInterpolationOrder); - // allocate look up for global distortion - AliTPCLookUpTable3DInterpolatorD* lookupGlobalCorr = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGCorrDrDz, rList, phiSlice, matricesGCorrDPhiRDz, phiList, nZColumn, matricesGCorrDz, - zList, fInterpolationOrder); - - // should be set, in another place - const Int_t symmetry = 0; // fSymmetry - - // for irregular - TMatrixD** matricesIrregularDrDz = nullptr; - TMatrixD** matricesIrregularDPhiRDz = nullptr; - TMatrixD** matricesIrregularDz = nullptr; - TMatrixD** matricesPhiIrregular = nullptr; - TMatrixD** matricesRIrregular = nullptr; - TMatrixD** matricesZIrregular = nullptr; - - // for charge - TMatrixD** matricesLookUpCharge = nullptr; - AliTPC3DCylindricalInterpolator* chargeInterpolator = nullptr; - AliTPC3DCylindricalInterpolator* potentialInterpolator = nullptr; - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // Double_t* potentialBoundary = nullptr; - TMatrixD* matrixV; - TMatrixD* matrixCharge; - - // do if look up table haven't be initialized - if (!fInitLookUp) { - // initialize for working memory - for (Int_t side = 0; side < 2; side++) { - // zeroing global distortion/correction - for (Int_t k = 0; k < phiSlice; k++) { - matricesDistDrDz[k]->Zero(); - matricesDistDPhiRDz[k]->Zero(); - matricesDistDz[k]->Zero(); - matricesCorrDrDz[k]->Zero(); - matricesCorrDPhiRDz[k]->Zero(); - matricesCorrDz[k]->Zero(); - - matricesGDistDrDz[k]->Zero(); - matricesGDistDPhiRDz[k]->Zero(); - matricesGDistDz[k]->Zero(); - matricesGCorrDrDz[k]->Zero(); - matricesGCorrDPhiRDz[k]->Zero(); - matricesGCorrDz[k]->Zero(); - } - - if (side == 0) { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularA; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularA; - matricesIrregularDz = fMatrixIntCorrDzIrregularA; - - matricesPhiIrregular = fMatrixPhiListIrregularA; - matricesRIrregular = fMatrixRListIrregularA; - matricesZIrregular = fMatrixZListIrregularA; - matricesLookUpCharge = fMatrixChargeA; - - chargeInterpolator = fInterpolatorChargeA; - potentialInterpolator = fInterpolatorPotentialA; - fLookupDistA->SetLookUpR(matricesDistDrDz); - fLookupDistA->SetLookUpPhi(matricesDistDPhiRDz); - fLookupDistA->SetLookUpZ(matricesDistDz); - - fLookupElectricFieldA->SetLookUpR(matricesEr); - fLookupElectricFieldA->SetLookUpPhi(matricesEPhi); - fLookupElectricFieldA->SetLookUpZ(matricesEz); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryA; - f1BoundaryIFC = fFormulaBoundaryIFCA; - f1BoundaryOFC = fFormulaBoundaryOFCA; - f1BoundaryROC = fFormulaBoundaryROCA; - } else { - matricesIrregularDrDz = fMatrixIntCorrDrEzIrregularC; - matricesIrregularDPhiRDz = fMatrixIntCorrDPhiREzIrregularC; - matricesIrregularDz = fMatrixIntCorrDzIrregularC; - matricesPhiIrregular = fMatrixPhiListIrregularC; - matricesRIrregular = fMatrixRListIrregularC; - matricesZIrregular = fMatrixZListIrregularC; - matricesLookUpCharge = fMatrixChargeC; - - chargeInterpolator = fInterpolatorChargeC; - potentialInterpolator = fInterpolatorPotentialC; - fLookupDistC->SetLookUpR(matricesDistDrDz); - fLookupDistC->SetLookUpPhi(matricesDistDPhiRDz); - fLookupDistC->SetLookUpZ(matricesDistDz); - fLookupElectricFieldC->SetLookUpR(matricesEr); - fLookupElectricFieldC->SetLookUpPhi(matricesEPhi); - fLookupElectricFieldC->SetLookUpZ(matricesEz); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // potentialBoundary = fListPotentialBoundaryC; - f1BoundaryIFC = fFormulaBoundaryIFCC; - f1BoundaryOFC = fFormulaBoundaryOFCC; - f1BoundaryROC = fFormulaBoundaryROCC; - } - // fill the potential boundary - // guess the initial potential - // fill also charge - //pIndex = 0; - - //Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz","%s",Form("Step = 0: Fill Boundary and Charge Densities")); - for (Int_t k = 0; k < phiSlice; k++) { - phi0 = k * gridSizePhi; - matrixV = matricesV[k]; - matrixCharge = matricesCharge[k]; - for (Int_t i = 0; i < nRRow; i++) { - radius0 = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - for (Int_t j = 0; j < nZColumn; j++) { - z0 = j * gridSizeZ; - (*matrixCharge)(i, j) = chargeInterpolator->GetValue(rList[i], phiList[k], zList[j]); - (*matrixV)(i, j) = fFormulaPotentialV->Eval(radius0, phi0, z0); - } - } - } - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 0: Preparing Charge interpolator: %f\n", w.CpuTime())); - - potentialInterpolator->SetValue(matricesV); - potentialInterpolator->InitCubicSpline(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 1: Poisson solver: %f\n", w.CpuTime())); - w.Start(); - w.Stop(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 2: Electric Field Calculation: %f\n", w.CpuTime())); - w.Start(); - w.Stop(); - - // copy to interpolator - LocalDistCorrDz(intErDzTestFunction, intEPhiRDzTestFunction, intDzTestFunction, - GetEzFormula(), rList, phiList, zList, - matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, - matricesCorrDrDz, matricesCorrDPhiRDz, matricesCorrDz, - nRRow, nZColumn, phiSlice, gridSizeZ, ezField); - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 3: Local distortion and correction: %f\n", w.CpuTime())); - lookupLocalDist->CopyFromMatricesToInterpolator(); - lookupLocalCorr->CopyFromMatricesToInterpolator(); - if (side == 0) { - fLookupDistA->CopyFromMatricesToInterpolator(); - fLookupElectricFieldA->CopyFromMatricesToInterpolator(); - } else { - fLookupDistC->CopyFromMatricesToInterpolator(); - fLookupElectricFieldC->CopyFromMatricesToInterpolator(); - } - - w.Start(); - - IntegrateDistCorrDriftLineDz(intErDzTestFunction, intEPhiRDzTestFunction, intDzTestFunction, GetEzFormula(), ezField, - matricesGDistDrDz, matricesGDistDPhiRDz, matricesGDistDz, - matricesGCorrDrDz, matricesGCorrDPhiRDz, matricesGCorrDz, - matricesIrregularDrDz, matricesIrregularDPhiRDz, matricesIrregularDz, - matricesRIrregular, matricesPhiIrregular, matricesZIrregular, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 4: Global correction/distortion: %f\n", w.CpuTime())); - w.Start(); - - //// copy to 1D interpolator ///// - lookupGlobalDist->CopyFromMatricesToInterpolator(); - lookupGlobalCorr->CopyFromMatricesToInterpolator(); - //// - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Step 5: Filling up the look up: %f\n", w.CpuTime())); - - if (side == 0) { - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzA, fMatrixIntDistDPhiREzA, fMatrixIntDistDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzA, fMatrixIntCorrDPhiREzA, fMatrixIntCorrDzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - fLookupIntDistA->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrA->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularA->CopyFromMatricesToInterpolator(); - } - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " A side done"); - } - if (side == 1) { - FillLookUpTable(lookupGlobalDist, - fMatrixIntDistDrEzC, fMatrixIntDistDPhiREzC, fMatrixIntDistDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - FillLookUpTable(lookupGlobalCorr, - fMatrixIntCorrDrEzC, fMatrixIntCorrDPhiREzC, fMatrixIntCorrDzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - - fLookupIntDistC->CopyFromMatricesToInterpolator(); - if (fCorrectionType == 0) { - fLookupIntCorrC->CopyFromMatricesToInterpolator(); - } else { - fLookupIntCorrIrregularC->CopyFromMatricesToInterpolator(); - } - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " C side done"); - } - } - - fInitLookUp = kTRUE; - } - - // memory de-allocation for temporary matrices - for (Int_t k = 0; k < phiSlice; k++) { - delete matricesV[k]; - delete matricesCharge[k]; - delete matricesEr[k]; - delete matricesEPhi[k]; - delete matricesEz[k]; - delete matricesDistDrDz[k]; - delete matricesDistDPhiRDz[k]; - delete matricesDistDz[k]; - - delete matricesCorrDrDz[k]; - delete matricesCorrDPhiRDz[k]; - delete matricesCorrDz[k]; - delete matricesGDistDrDz[k]; - delete matricesGDistDPhiRDz[k]; - delete matricesGDistDz[k]; - - delete matricesGCorrDrDz[k]; - delete matricesGCorrDPhiRDz[k]; - delete matricesGCorrDz[k]; - } - delete lookupLocalDist; - delete lookupLocalCorr; - delete lookupGlobalDist; - delete lookupGlobalCorr; -} -/// Creating look-up tables of Correction/Distortion by linear integration -/// on z line -/// -/// \param nRRow Int_t number of grid in row direction -/// \param nZColumn Int_t number of grid in z direction -/// \param phiSlice Int_t number of slices in phi direction -/// \param maxIteration Int_t max iteration for convergence -/// \param stoppingConvergence Double_t stopping criteria for convergence -/// \post Lookup tables for distortion: -/// ~~~ -/// fLookUpIntDistDrEz,fLookUpIntDistDPhiREz,fLookUpIntDistDz -/// ~~~ fo -/// and correction: -/// ~~~ -/// fLookUpIntCorrDrEz,fLookUpIntCorrDPhiREz,fLookUpIntCorrDz -/// ~~~ -/// are initialized -/// -void AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoisson(Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, - Double_t stoppingConvergence) -{ - // Compute grid size for all direction - Int_t phiSlicesPerSector = phiSlice / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - - // local variables - Float_t radius0, phi0, z0; - - // memory allocation for temporary matrices: - // potential (boundary values), charge distribution - - TMatrixD *matricesV[phiSlice], *matricesCharge[phiSlice]; - TMatrixD *matricesEr[phiSlice], *matricesEPhi[phiSlice], *matricesEz[phiSlice]; - - for (Int_t k = 0; k < phiSlice; k++) { - matricesEr[k] = new TMatrixD(nRRow, nZColumn); - matricesEPhi[k] = new TMatrixD(nRRow, nZColumn); - matricesEz[k] = new TMatrixD(nRRow, nZColumn); - matricesV[k] = new TMatrixD(nRRow, nZColumn); - matricesCharge[k] = new TMatrixD(nRRow, nZColumn); - } - - // list of point as used in the poisson relaxation and the interpolation (for interpolation) - Double_t rList[nRRow], zList[nZColumn], phiList[phiSlice]; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = j * gridSizeZ; - } - // should be set, in another place - const Int_t symmetry = 0; - // do if look up table haven't be initialized - if (!fInitLookUp) { - for (Int_t side = 0; side < 2; side++) { - for (Int_t k = 0; k < phiSlice; k++) { - TMatrixD* mV = matricesV[k]; - TMatrixD* mCharge = matricesCharge[k]; - phi0 = phiList[k]; - for (Int_t i = 0; i < nRRow; i++) { - radius0 = rList[i]; - for (Int_t j = 0; j < nZColumn; j++) { - z0 = zList[j]; - if (side == 1) { - z0 = -TMath::Abs(zList[j]); - } - if (fHistogram3DSpaceCharge != nullptr) { - // * Boundary values and charge distribution setup - (*mV)(i, j) = 0.0; - (*mCharge)(i, j) = -1 * InterpolatePhi(fHistogram3DSpaceCharge, phi0, radius0, z0); - } - } - } - } - AliTPCLookUpTable3DInterpolatorD* lookupEField = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, - matricesEr, - rList, phiSlice, - matricesEPhi, - phiList, nZColumn, - matricesEz, - zList, - fInterpolationOrder); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "Step 1: Solving poisson solver"); - fPoissonSolver->PoissonSolver3D(matricesV, matricesCharge, nRRow, nZColumn, phiSlice, maxIteration, symmetry); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "Step 2: Calculate electric field"); - CalculateEField( - matricesV, - matricesEr, - matricesEPhi, - matricesEz, - nRRow, - nZColumn, - phiSlice, - maxIteration, - symmetry); - lookupEField->CopyFromMatricesToInterpolator(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "Step 3: Fill the look up table"); - - if (side == 0) { - FillLookUpTable(lookupEField, - fMatrixErOverEzA, fMatrixEPhiOverEzA, fMatrixDeltaEzA, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - fLookupIntENoDriftA->CopyFromMatricesToInterpolator(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " A side done"); - } - if (side == 1) { - FillLookUpTable(lookupEField, - fMatrixErOverEzC, fMatrixEPhiOverEzC, fMatrixDeltaEzC, - nRRow, nZColumn, phiSlice, rList, phiList, zList); - fLookupIntENoDriftC->CopyFromMatricesToInterpolator(); - - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", " C side done"); - } - delete lookupEField; - } - fInitLookUp = kTRUE; - } - - for (Int_t k = 0; k < phiSlice; k++) { - delete matricesV[k]; - delete matricesCharge[k]; - delete matricesEr[k]; - delete matricesEPhi[k]; - delete matricesEz[k]; - } -} -/// Force creating look-up table of Correction/Distortion by integration following -/// drift line. -/// -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slices in \f$ phi \f$ direction -/// \param maxIteration Int_t Maximum iteration for poisson solver -/// \param stoppingConvergence Convergence error stopping condition for poisson solver -/// -void AliTPCSpaceCharge3DCalc::ForceInitSpaceCharge3DPoissonIntegralDz(Int_t nRRow, Int_t nZColumn, Int_t phiSlice, - Int_t maxIteration, Double_t stoppingConvergence) -{ - fInitLookUp = kFALSE; - InitSpaceCharge3DPoissonIntegralDz(nRRow, nZColumn, phiSlice, maxIteration, stoppingConvergence); -} -/// Electric field Calculation: -/// -/// -/// \param matricesV -/// \param matricesEr -/// \param matricesEPhi -/// \param matricesEz -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -/// \param gridSizeR -/// \param gridSizePhi -/// \param gridSizeZ -/// \param symmetry -/// \param innerRadius -/// -/// \pre Matrix matricesV is assumed had been calculated by Poisson solver -/// \post Results of E-fields are calculated by measuring gradient at potential distribution -/// -/// -/// * Differentiate potential on all direction (r,z and phi) -/// * Non-boundary -> Central difference (3 stencil) TODO: 5 Stencil -/// -/// \f$ \nabla_{r} V(r_{i},\phi_{j},z_{k}) \approx -( V_{i+1,j,k} - V_{i-1,j,k}) / (2* h_{r}) \f$ -/// -/// \f$ -\nabla_{\phi} V(r_{i},\phi_{j},z_{k}) \approx -( V_{i,j-1,k} - V_{i,j+1,k}) / (2* r_{j} * h_{\phi}) \f$ -/// -/// \f$ -\nabla_{z} V(r_{i},\phi_{j},z_{k}) \approx -( V_{i,j,k+1} - V_{i,j,k-1}) / (2* h_{z}) \f$ -/// -/// ~~~ cxx -/// matrixEr(i,j) = -1 * ( arrayV(i+1,j) - arrayV(i-1,j) ) / (2*gridSizeR); // r direction -/// matrixEz(i,j) = -1 * ( arrayV(i,j+1) - arrayV(i,j-1) ) / (2*gridSizeZ) ; // z direction -/// matrixEPhi(i,j) = -1 * (signPlus * arrayVP(i,j) - signMinus * arrayVM(i,j) ) / (2*radius*gridSizePhi) -/// ~~~ -/// -/// * Boundary -> Forward/Backward difference (3 stencil) TODO: 5 Stencil -/// -/// \f$ -\nabla_{r} V(r_{0},\phi_{j},z_{k}) \approx -( -0.5 V_{2,j,k} + 2 V_{1,j,k} - 1.5 * V_{0,j,k}) / h_{r} \f$ -/// -/// \f$ -\nabla_{r} V(r_{nRRow - 1},\phi_{j},z_{k}) \approx -( 1.5 V_{nRRow-1,j,k} - 2.0 V_{nRRow-2,j,k} + 0.5 V_{nRRow -3,j,k}) / h_{\phi} \f$ -/// -void AliTPCSpaceCharge3DCalc::ElectricField(TMatrixD** matricesV, TMatrixD** matricesEr, TMatrixD** matricesEPhi, - TMatrixD** matricesEz, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, - const Float_t gridSizeR, const Float_t gridSizePhi, - const Float_t gridSizeZ, - const Int_t symmetry, const Float_t innerRadius) -{ - Float_t radius; - Int_t mPlus, mMinus, signPlus, signMinus; - for (Int_t m = 0; m < phiSlice; m++) { - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - if (symmetry == 1) { // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } else if (symmetry == -1) { // Anti-symmetry in phi - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculations is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - } - - TMatrixD& arrayVP = *matricesV[mPlus]; - TMatrixD& arrayVM = *matricesV[mMinus]; - TMatrixD& arrayV = *matricesV[m]; - TMatrixD& matrixEr = *matricesEr[m]; - TMatrixD& matrixEz = *matricesEz[m]; - TMatrixD& matrixEPhi = *matricesEPhi[m]; - - // for non-boundary V - for (Int_t i = 1; i < nRRow - 1; i++) { - radius = innerRadius + i * gridSizeR; - for (Int_t j = 1; j < nZColumn - 1; j++) { - matrixEr(i, j) = -1 * (arrayV(i + 1, j) - arrayV(i - 1, j)) / (2 * gridSizeR); // r direction - matrixEz(i, j) = -1 * (arrayV(i, j + 1) - arrayV(i, j - 1)) / (2 * gridSizeZ); // z direction - matrixEPhi(i, j) = -1 * (signPlus * arrayVP(i, j) - signMinus * arrayVM(i, j)) / - (2 * radius * gridSizePhi); // phi direction - } - } - - // for boundary-r - for (Int_t j = 0; j < nZColumn; j++) { - matrixEr(0, j) = -1 * (-0.5 * arrayV(2, j) + 2.0 * arrayV(1, j) - 1.5 * arrayV(0, j)) / - gridSizeR; // forward difference - matrixEr(nRRow - 1, j) = - -1 * (1.5 * arrayV(nRRow - 1, j) - 2.0 * arrayV(nRRow - 2, j) + 0.5 * arrayV(nRRow - 3, j)) / - gridSizeR; // backward difference - } - - for (Int_t i = 0; i < nRRow; i += nRRow - 1) { - radius = innerRadius + i * gridSizeR; - for (Int_t j = 1; j < nZColumn - 1; j++) { - matrixEz(i, j) = -1 * (arrayV(i, j + 1) - arrayV(i, j - 1)) / (2 * gridSizeZ); // z direction - matrixEPhi(i, j) = -1 * (signPlus * arrayVP(i, j) - signMinus * arrayVM(i, j)) / - (2 * radius * gridSizePhi); // phi direction - } - } - - // for boundary-z - for (Int_t i = 0; i < nRRow; i++) { - matrixEz(i, 0) = -1 * (-0.5 * arrayV(i, 2) + 2.0 * arrayV(i, 1) - 1.5 * arrayV(i, 0)) / gridSizeZ; - matrixEz(i, nZColumn - 1) = - -1 * - (1.5 * arrayV(i, nZColumn - 1) - 2.0 * arrayV(i, nZColumn - 2) + 0.5 * arrayV(i, nZColumn - 3)) / - gridSizeZ; - } - - for (Int_t i = 1; i < nRRow - 1; i++) { - radius = innerRadius + i * gridSizeR; - for (Int_t j = 0; j < nZColumn; j += nZColumn - 1) { - matrixEr(i, j) = -1 * (arrayV(i + 1, j) - arrayV(i - 1, j)) / (2 * gridSizeR); // r direction - matrixEPhi(i, j) = -1 * (signPlus * arrayVP(i, j) - signMinus * arrayVM(i, j)) / - (2 * radius * gridSizePhi); // phi direction - } - } - - // corner points for EPhi - for (Int_t i = 0; i < nRRow; i += nRRow - 1) { - radius = innerRadius + i * gridSizeR; - for (Int_t j = 0; j < nZColumn; j += nZColumn - 1) { - matrixEPhi(i, j) = -1 * (signPlus * arrayVP(i, j) - signMinus * arrayVM(i, j)) / - (2 * radius * gridSizePhi); // phi direction - } - } - } -} -/// -/// Local distortion and correction, calculate local distortion/correction -/// based on simplified langevin equation, see internal note ALICE-INT-2010-016. -/// -/// <b> Local Distortion </b> -/// -/// Local distortion is calculated based on formulation in ALICE-INT-2010-016, this function assume that -/// electric field \f$\vec{E}(r_{i},z_{j},\phi_{m})\f$ is provided. -/// -/// First, we calculate integration of the Electric field in z-direction for all direction. -/// Assumption: \f$ z_{0} \f$ is location of CE (Central Electrode) and \f$ z_{nZColumn - 1} \f$ is location of End Plate. -/// -/// This integration is in \f$z\f$ direction we can only use trapezoidal rule. -/// -/// Let suppose we want to calculate local distortion at \f$(r_{i},z_{j},\phi_{m})\f$. -/// Assume \f$\vec{E}(r_{i},z_{j+1},\phi_{m}) \f$ and \f$\vec{E}(r_{i},z_{j},\phi_{m}) \f$ are known, see Figure \ref fig1 (a), -/// -/// \anchor fig1 -/// ![Local Distortion](localdist.png) -/// -/// Than we can calculate definite integrations for each directions in respect of $z$ from \f$ z_{j} \f$ to \f$ z_{j + 1} \f$ as follows: -/// -/// \f$ \int^{z_{j+1}}_{z_{j}} \frac{E_{r}}{E_{z}}(r_{i},z_{j},\phi_{m}) dzDist \approx \frac{-1}{\mathrm{ezField}} \frac{h_{z}}{2.0} \left( E_{r}(r_{i},z_{j},\phi_{m}) + E_{r}(r_{i},z_{j+1},\phi_{m}) \right)\f$ -/// -/// \f$ \int^{z_{j+1}}_{z_{j}} \frac{E_{\phi}}{E_{z}}(r_{i},z_{j},\phi_{m}) dzDist \approx \frac{-1}{\mathrm{ezField}} \frac{h_{z}}{2.0} \left( E_{\phi}(r_{i},z_{j},\phi_{m}) + E_{\phi}(r_{i},z_{j+1},\phi_{m}) \right)\f$ -/// -/// \f$ \int^{z_{j+1}}_{z_{j}} E_{z}(r_{i},z_{j},\phi_{m}) dzDist \approx \frac{h_{z}}{2.0} \left( E_{z}(r_{i},z_{j},\phi_{m}) + E_{z}(r_{i},z_{j+1},\phi_{m}) \right) \f$ -/// -/// Code sample at \ref impllocaldist is an implementation of the local integration of electric field. -/// -/// \anchor impllocaldist -/// ~~~ -/// Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV-AliTPCPoissonSolver::fgkGG)/AliTPCPoissonSolver::fgkTPCZ0; // = Electric Field (V/cm) Magnitude ~ -400 V/cm; -/// -/// localIntErOverEz = (gridSizeZ/2.0)*((*eR)(i,j)+(*eR)(i,j+1))/(ezField + (*eZ)(i,j)) ; -/// localIntEPhiOverEz = (gridSizeZ/2.0)*((*ePhi)(i,j)+(*ePhi)(i,j+1))/(ezField + (*eZ)(i,j)) ; -/// localIntDeltaEz = (gridSizeZ/2.0)*((*eZ)(i,j)+(*eZ)(i,j+1)) ; -/// ~~~ -/// -/// -/// After we have local integrations for electric fields in each direction, -/// local distortion \f$\hat{\delta}(r_{i},z_{j},\phi_{m})\f$ is calculated by simplified Langevin equation (see Figure \ref1 (b) for illustration): -/// -/// \f$ \hat{\delta}_{rE}(r_{i},z_{j},\phi_{m}) = c_{0} \int^{z_{j+1}}_{z_{j}} \frac{E_{r}}{E_{z}} dzDist + c_{1} \int^{z_{j+1}}_{z_{j}} \frac{E_{\phi}}{E_{z}} dzDist \f$ -/// -/// ~~~ -/// (*distDrDz)(i,j) = fC0*localIntErOverEz + fC1*localIntEPhiOverEz; -/// ~~~ -/// -/// \f$ r\hat{\delta}_{\phi E}(r_{i},z_{j},\phi_{m}) = - c_{1} \int^{z_{j+1}}_{z_{j}} \frac{E_{j}}{E_{j}} dzDist + c_{0} \int^{z_{j+1}}_{j_{j}} \frac{E_{\phi}}{E_{z}} dzDist \f$ -/// -/// ~~~ -/// (*distDPhiRDz)(i,j) = fC0*localIntEPhiOverEz - fC1*localIntErOverEz ; -/// ~~~ -/// -/// \f$ \hat{\delta}_{z}(r_{i},z_{j},\phi_{m}) = \int_{z_{j}}^{z_{j+1}} \frac{v^{\prime}(E)}{v_{0}} (E - E_{0}) dzDist\f$ -/// -/// ~~~ -/// (*distDz)(i,j) = localIntDeltaEz*-1*AliTPCPoissonSolver::fgkdvdE; -/// ~~~ -/// -/// Where \f$c_{0}\f$ and \f$c_{1}\f$ are constants (see the ALICE-INT-2010-016 for further details). -/// -/// <b> Local correction </b> -/// -/// Local correction is computed as local distortion where the electric fields are in opposite direction (see Figure \ref fig2 (a)). -/// -/// \anchor fig2 -/// ![Local Correction](localcorr.png) -/// -/// Let suppose we want to calculate local correction at \f$(r_{i},\mathbf{z_{j+1}},\phi_{m})\f$. -/// Assume \f$\vec{E}(r_{i},z_{j+1},\phi_{m}) \f$ and \f$\vec{E}(r_{i},z_{j},\phi_{m}) \f$ are known. -/// -/// Than we can calculate definite integrations for each directions in respect of \f$z\f$ from \f$ z_{j+1} \f$ to \f$ z_{j} \f$ as follows: -/// -/// \f$ \int^{z_{j}}_{z_{j+1}} \frac{E_{r}}{E_{z}}(r_{i},z_{j},\phi_{m}) dzDist \approx -1 * \frac{-1}{\mathrm{ezField}} \frac{h_{z}}{2.0} \left( E_{r}(r_{i},z_{j},\phi_{m}) + E_{r}(r_{i},z_{j+1},\phi_{m}) \right)\f$ -/// -/// \f$ \int^{z_{j}}_{z_{j+1}} \frac{E_{\phi}}{E_{z}}(r_{i},z_{j},\phi_{m}) dzDist \approx -1 * \frac{-1}{\mathrm{ezField}} \frac{h_{z}}{2.0} \left( E_{\phi}(r_{i},z_{j},\phi_{m}) + E_{\phi}(r_{i},z_{j+1},\phi_{m}) \right)\f$ -/// -/// \f$ \int^{z_{j}}_{z_{j+1}} E_{z}(r_{i},z_{j},\phi_{m}) dzDist \approx -1 * \frac{h_{z}}{2.0} \left( E_{z}(r_{i},z_{j},\phi_{m}) + E_{z}(r_{i},z_{j+1},\phi_{m}) \right) \f$ -/// -/// Local correction at \f$\hat{\delta'}(r_{i},\mathbf{z_{j+1}},\phi_{m})\f$ is calculated by simplified Langevin equation (see Figure \ref fig2 (b) for illustration): -/// -/// \f$ \hat{\delta'}_{rE}(r_{i},z_{j+1},\phi_{m}) = c_{0} \int^{z_{j}}_{z_{j+1}} \frac{E_{r}}{E_{z}} dzDist + c_{1} \int^{z_{j-1}}_{z_{j}} \frac{E_{\phi}}{E_{z}} dzDist \f$ -/// -/// \f$ r\hat{\delta'}_{\phi E}(r_{i},z_{j+1},\phi_{m}) = - c_{1} \int^{z_{j}}_{z_{j+1}} \frac{E_{j}}{E_{j}} dzDist + c_{0} \int^{z_{j-1}}_{j_{k}} \frac{E_{\phi}}{E_{z}} dzDist \f$ -/// -/// \f$ \hat{\delta'}_{z}(r_{i},z_{j+1},\phi_{m}) = \int_{z_{j}}^{z_{j+1}} \frac{v^{\prime}(E)}{v_{0}} (E - E_{0}) dzDist\f$ -/// -/// For implementation, we use the fact that -/// -/// \f$ \hat{\delta'}_{rE}(r_{i},z_{j+1},\phi_{m}) = -1 * \hat{\delta}_{rE}(r_{i},z_{j},\phi_{m}) \f$ -/// -/// \f$ r\hat{\delta'}_{\phi E}(r_{i},z_{j+1},\phi_{m}) = -1 * r\hat{\delta}_{\phi E}(r_{i},z_{j},\phi_{m}) \f$ -/// -/// \f$ \hat{\delta'}_{z}(r_{i},z_{j+1},\phi_{m}) = -1 * \hat{\delta}_{z}(r_{i},z_{j},\phi_{m}) \f$ -/// -/// ~~~ -/// (*corrDrDz)(i,j+1) = -1* (*distDrDz)(i,j) ; -/// (*corrDPhiRDz)(i,j+1) = -1* (*distDPhiRDz)(i,j); -/// (*corrDz)(i,j+1) = -1* (*distDz)(i,j); -/// ~~~ -/// -/// \param matricesEr TMatrixD** electric field for \f$r\f$ component -/// \param matricesEPhi TMatrixD** electric field for \f$\phi\f$ component -/// \param matricesEz TMatrixD** electric field for \f$z\f$ component -/// \param matricesDistDrDz TMatrixD** local distortion \f$\hat{\delta}_{r}\f$ -/// \param matricesDistDPhiRDz TMatrixD** local distortion \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesDistDz TMatrixD** local distortion \f$ \hat{\delta}_{z}\f$ -/// \param matricesCorrDrDz TMatrixD** local correction \f$\hat{\delta}_{r}\f$ -/// \param matricesCorrDPhiRDz TMatrixD** local correction \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesCorrDz TMatrixD** local correction \f$ \hat{\delta}_{z}\f$ -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slices in \f$ phi \f$ direction -/// \param gridSizeZ const Float_t grid size in z direction -/// \param ezField const Double_t ezField calculated from the invoking operation -/// -/// \pre matricesEr, matricesEPhi, matrices Ez assume already been calculated -/// \post Local distortion and correction are computed according simplified Langevin equation -/// ~~~ -/// matricesDistDrDz,matricesDistDPhiRDz,matricesDistDz -/// ~~~ -/// and correction: -/// ~~~ -/// matricesCorrDrDz,matricesCorrDPhiRDz,matricesCorrDz -/// ~~~ -/// -void AliTPCSpaceCharge3DCalc::LocalDistCorrDz(TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, - TMatrixD** matricesDistDz, - TMatrixD** matricesCorrDrDz, TMatrixD** matricesCorrDPhiRDz, - TMatrixD** matricesCorrDz, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Float_t gridSizeZ, - const Double_t ezField) -{ - Float_t localIntErOverEz = 0.0; - Float_t localIntEPhiOverEz = 0.0; - Float_t localIntDeltaEz = 0.0; - TMatrixD* eR; - TMatrixD* ePhi; - TMatrixD* eZ; - TMatrixD* distDrDz; - TMatrixD* distDPhiRDz; - TMatrixD* distDz; - TMatrixD* corrDrDz; - TMatrixD* corrDPhiRDz; - TMatrixD* corrDz; - - // Initialization for j == column-1 integration is 0.0 - for (Int_t m = 0; m < phiSlice; m++) { - distDrDz = matricesDistDrDz[m]; - distDPhiRDz = matricesDistDPhiRDz[m]; - distDz = matricesDistDz[m]; - - corrDrDz = matricesCorrDrDz[m]; - corrDPhiRDz = matricesCorrDPhiRDz[m]; - corrDz = matricesCorrDz[m]; - - for (Int_t i = 0; i < nRRow; i++) { - (*distDrDz)(i, nZColumn - 1) = 0.0; - (*distDPhiRDz)(i, nZColumn - 1) = 0.0; - (*distDz)(i, nZColumn - 1) = 0.0; - - (*corrDrDz)(i, 0) = 0.0; - (*corrDPhiRDz)(i, 0) = 0.0; - (*corrDz)(i, 0) = 0.0; - } - } - - // for this case - // use trapezoidal rule assume no ROC displacement - for (Int_t m = 0; m < phiSlice; m++) { - eR = matricesEr[m]; - ePhi = matricesEPhi[m]; - eZ = matricesEz[m]; - distDrDz = matricesDistDrDz[m]; - distDPhiRDz = matricesDistDPhiRDz[m]; - distDz = matricesDistDz[m]; - - corrDrDz = matricesCorrDrDz[m]; - corrDPhiRDz = matricesCorrDPhiRDz[m]; - corrDz = matricesCorrDz[m]; - - for (Int_t j = 0; j < nZColumn - 1; j++) { - for (Int_t i = 0; i < nRRow; i++) { - double eZ0 = ezField + (*eZ)(i, j); - double eZ1 = ezField + (*eZ)(i, j + 1); - localIntErOverEz = (gridSizeZ * 0.5) * ((*eR)(i, j) / eZ0 + (*eR)(i, j + 1) / eZ1); - localIntEPhiOverEz = (gridSizeZ * 0.5) * ((*ePhi)(i, j) / eZ0 + (*ePhi)(i, j + 1) / eZ1); - localIntDeltaEz = (gridSizeZ * 0.5) * ((*eZ)(i, j) + (*eZ)(i, j + 1)); - - (*distDrDz)(i, j) = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - (*distDPhiRDz)(i, j) = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - (*distDz)(i, j) = localIntDeltaEz * -1 * AliTPCPoissonSolver::fgkdvdE; - - (*corrDrDz)(i, j + 1) = -1 * (*distDrDz)(i, j); - (*corrDPhiRDz)(i, j + 1) = -1 * (*distDPhiRDz)(i, j); - (*corrDz)(i, j + 1) = -1 * (*distDz)(i, j); - } - } - } -} -/// -/// Local distortion and correction, calculate local distortion/correction for known analitics functions -/// based on simplified langevin equation, see internal note ALICE-INT-2010-016. -/// -/// \param matricesEPhi TMatrixD** electric field for \f$\phi\f$ component -/// \param matricesEz TMatrixD** electric field for \f$z\f$ component -/// \param matricesDistDrDz TMatrixD** local distortion \f$\hat{\delta}_{r}\f$ -/// \param matricesDistDPhiRDz TMatrixD** local distortion \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesDistDz TMatrixD** local distortion \f$ \hat{\delta}_{z}\f$ -/// \param matricesCorrDrDz TMatrixD** local correction \f$\hat{\delta}_{r}\f$ -/// \param matricesCorrDPhiRDz TMatrixD** local correction \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesCorrDz TMatrixD** local correction \f$ \hat{\delta}_{z}\f$ -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slices in \f$ phi \f$ direction -/// \param gridSizeZ const Float_t grid size in z direction -/// \param ezField const Double_t ezField calculated from the invoking operation -/// -/// \pre matricesEr, matricesEPhi, matrices Ez assume already been calculated -/// \post Local distortion and correction are computed according simplified Langevin equation -/// ~~~ -/// matricesDistDrDz,matricesDistDPhiRDz,matricesDistDz -/// ~~~ -/// and correction: -/// ~~~ -/// matricesCorrDrDz,matricesCorrDPhiRDz,matricesCorrDz -/// ~~~ -/// -void AliTPCSpaceCharge3DCalc::LocalDistCorrDz(TFormula* intErDzFunction, TFormula* intEPhiRDzFunction, TFormula* intDzFunction, - TFormula* ezFunction, Double_t* rList, Double_t* phiList, Double_t* zList, TMatrixD** matricesDistDrDz, - TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, TMatrixD** matricesCorrDrDz, - TMatrixD** matricesCorrDPhiRDz, TMatrixD** matricesCorrDz, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Float_t gridSizeZ, const Double_t ezField) -{ - Float_t localIntErOverEz = 0.0; - Float_t localIntEPhiOverEz = 0.0; - Float_t localIntDeltaEz = 0.0; - TMatrixD* distDrDz; - TMatrixD* distDPhiRDz; - TMatrixD* distDz; - TMatrixD* corrDrDz; - TMatrixD* corrDPhiRDz; - TMatrixD* corrDz; - - Double_t radius, phi, z0, z1; - - // Initialization for j == column-1 integration is 0.0 - for (Int_t m = 0; m < phiSlice; m++) { - distDrDz = matricesDistDrDz[m]; - distDPhiRDz = matricesDistDPhiRDz[m]; - distDz = matricesDistDz[m]; - - corrDrDz = matricesCorrDrDz[m]; - corrDPhiRDz = matricesCorrDPhiRDz[m]; - corrDz = matricesCorrDz[m]; - - for (Int_t i = 0; i < nRRow; i++) { - (*distDrDz)(i, nZColumn - 1) = 0.0; - (*distDPhiRDz)(i, nZColumn - 1) = 0.0; - (*distDz)(i, nZColumn - 1) = 0.0; - - (*corrDrDz)(i, 0) = 0.0; - (*corrDPhiRDz)(i, 0) = 0.0; - (*corrDz)(i, 0) = 0.0; - } - } - - // for this case - // use trapezoidal rule assume no ROC displacement - for (Int_t m = 0; m < phiSlice; m++) { - phi = phiList[m]; - distDrDz = matricesDistDrDz[m]; - distDPhiRDz = matricesDistDPhiRDz[m]; - distDz = matricesDistDz[m]; - - corrDrDz = matricesCorrDrDz[m]; - corrDPhiRDz = matricesCorrDPhiRDz[m]; - corrDz = matricesCorrDz[m]; - - for (Int_t i = 0; i < nRRow; i++) { - radius = rList[i]; - - for (Int_t j = 0; j < nZColumn - 1; j++) { - z0 = zList[j]; - z1 = zList[j + 1]; - - localIntErOverEz = (intErDzFunction->Eval(radius, phi, z1) - intErDzFunction->Eval(radius, phi, z0)) / (ezField + ezFunction->Eval(radius, phi, z0)); - localIntEPhiOverEz = (intEPhiRDzFunction->Eval(radius, phi, z1) - intEPhiRDzFunction->Eval(radius, phi, z0)) / (ezField + ezFunction->Eval(radius, phi, z0)); - localIntDeltaEz = intDzFunction->Eval(radius, phi, z1) - intDzFunction->Eval(radius, phi, z0); - - (*distDrDz)(i, j) = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - (*distDPhiRDz)(i, j) = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - (*distDz)(i, j) = localIntDeltaEz * -1 * AliTPCPoissonSolver::fgkdvdE; - - (*corrDrDz)(i, j + 1) = -1 * (*distDrDz)(i, j); - (*corrDPhiRDz)(i, j + 1) = -1 * (*distDPhiRDz)(i, j); - (*corrDz)(i, j + 1) = -1 * (*distDz)(i, j); - } - } - } -} - -/// IntegrateDistCorrDriftLineDz, integration of local distortion by following electron drift -/// See explanation at LocalDistCorrDz -/// -/// -/// \param matricesEr TMatrixD** electric field for \f$r\f$ component -/// \param matricesEPhi TMatrixD** electric field for \f$\phi\f$ component -/// \param matricesEz TMatrixD** electric field for \f$z\f$ component -/// \param matricesCorrDrDz TMatrixD** local correction \f$\hat{\delta}_{r}\f$ -/// \param matricesCorrDPhiRDz TMatrixD** local correction \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesCorrDz TMatrixD** local correction \f$ \hat{\delta}_{z}\f$ -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slices in \f$ phi \f$ direction -/// \param gridSizeZ const Float_t grid size in z direction -/// \param ezField const Double_t ezField calculate from the invoking operation -/// -/// \pre matricesEr, matricesEPhi, matrices Ez are provided -/// \post Local correction are computed according simplified Langevin equation -/// ~~~ -/// matricesCorrDz,matricesCorrDPhiRDz,matricesDistDz -/// ~~~ -/// -void AliTPCSpaceCharge3DCalc::IntegrateDistCorrDriftLineDz( - AliTPCLookUpTable3DInterpolatorD* lookupLocalDist, - TMatrixD** matricesGDistDrDz, - TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, - AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr, - TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, - TMatrixD** matricesGCorrIrregularDz, - TMatrixD** matricesRIrregular, TMatrixD** matricesPhiIrregular, TMatrixD** matricesZIrregular, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Double_t* rList, const Double_t* phiList, const Double_t* zList) -{ - - Float_t drDist, dPhi, dzDist, ddR, ddRPhi, ddZ; - Float_t radius0, phi0, z0, radius, phi, z, radiusCorrection; - radiusCorrection = 0.0; - radius = 0.0; - TMatrixD* mDistDrDz; - TMatrixD* mDistDPhiRDz; - TMatrixD* mDistDz; - TMatrixD* mCorrDrDz; - TMatrixD* mCorrDPhiRDz; - TMatrixD* mCorrDz; - TMatrixD* mCorrIrregularDrDz; - TMatrixD* mCorrIrregularDPhiRDz; - TMatrixD* mCorrIrregularDz; - TMatrixD* mRIrregular; - TMatrixD* mPhiIrregular; - TMatrixD* mZIrregular; - Int_t j = nZColumn - 1; - z0 = zList[j]; - - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // do from j to 0 - // follow the drift - radius0 = rList[i]; - phi = phi0; - - /// - (*mDistDrDz)(i, j) = 0.; - (*mDistDPhiRDz)(i, j) = 0.; - (*mDistDz)(i, j) = 0.; - - (*mCorrDrDz)(i, j) = 0.; - (*mCorrDPhiRDz)(i, j) = 0.; - (*mCorrDz)(i, j) = 0.; - - //////////////// use irregular grid look up table for correction - if (fCorrectionType == kIrregularInterpolator) { - (*mCorrIrregularDrDz)(i, j) = 0.0; - (*mCorrIrregularDPhiRDz)(i, j) = 0.0; - (*mCorrIrregularDz)(i, j) = -0.0; - - // distorted point - (*mRIrregular)(i, j) = radius0; - (*mPhiIrregular)(i, j) = phi0; - (*mZIrregular)(i, j) = z0; - } - /////////////// - } - } - - // from j one column near end cap - for (j = nZColumn - 2; j >= 0; j--) { - - z0 = zList[j]; - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // do from j to 0 - // follow the drift - radius0 = rList[i]; - phi = phi0; - radius = radius0; - - drDist = 0.0; - dPhi = 0.0; - dzDist = 0.0; - - // follow the drift line from z=j --> nZColumn - 1 - for (Int_t jj = j; jj < nZColumn; jj++) { - // interpolation the local distortion for current position - // phi += ddRPhi / radius; - phi = phi0 + dPhi; - radius = radius0 + drDist; - z = zList[jj] + dzDist; - - // regulate phi - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - lookupLocalDist->GetValue(radius, phi, z, ddR, ddRPhi, ddZ); - - // add local distortion - drDist += ddR; - dPhi += (ddRPhi / radius); - dzDist += ddZ; - } - // set the global distortion after following the electron drift - (*mDistDrDz)(i, j) = drDist; - (*mDistDPhiRDz)(i, j) = dPhi * radius0; - (*mDistDz)(i, j) = dzDist; - /////////////// use irregular grid look up table for correction - // set - if (fCorrectionType == kIrregularInterpolator) { - // values should be negative of distortions - (*mCorrIrregularDrDz)(i, j) = -drDist; - (*mCorrIrregularDPhiRDz)(i, j) = -1 * dPhi * (radius0 + drDist); - (*mCorrIrregularDz)(i, j) = -dzDist; - - // distorted point - (*mRIrregular)(i, j) = radius0 + drDist; - (*mPhiIrregular)(i, j) = phi0 + dPhi; - (*mZIrregular)(i, j) = z0 + dzDist; - } - /////////////// - - // put the radius to the original value - if (fCorrectionType == kRegularInterpolator) { - if (j == nZColumn - 2) { - radiusCorrection = radius0; - } - - // get global correction from j+1 - drDist = (*mCorrDrDz)(i, j + 1); - dPhi = (*mCorrDPhiRDz)(i, j + 1) / radius0; - dzDist = (*mCorrDz)(i, j + 1); - - radiusCorrection = radius0 + drDist; - phi = phi0 + dPhi; - z = zList[j + 1] + dzDist; - - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - lookupLocalCorr->GetValue(radiusCorrection, phi, z, ddR, ddRPhi, ddZ); - - drDist += ddR; - dzDist += ddZ; - dPhi += ddRPhi / radiusCorrection; - - (*mCorrDrDz)(i, j) = drDist; - (*mCorrDPhiRDz)(i, j) = dPhi * radius0; - (*mCorrDz)(i, j) = dzDist; - } - } - } - } -} - -// oudated, to be removed once changes in aliroot are pushed -/// follow the drift for exact function -/// -/// \param intDrDzF -/// \param intDPhiDzF -/// \param intDzDzF -/// \param ezField -/// \param matricesGDistDrDz -/// \param matricesGDistDPhiRDz -/// \param matricesGDistDz -/// \param matricesGCorrDrDz -/// \param matricesGCorrDPhiRDz -/// \param matricesGCorrDz -/// \param matricesGCorrIrregularDrDz -/// \param matricesGCorrIrregularDPhiRDz -/// \param matricesGCorrIrregularDz -/// \param matricesRIrregular -/// \param matricesPhiIrregular -/// \param matricesZIrregular -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -/// \param rList -/// \param phiList -/// \param zList -void AliTPCSpaceCharge3DCalc::IntegrateDistCorrDriftLineDz( - TFormula* intDrDzF, TFormula* intDPhiDzF, TFormula* intDzDzF, const Double_t ezField, - TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, - TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, TMatrixD** matricesGCorrIrregularDz, TMatrixD** matricesRIrregular, - TMatrixD** matricesPhiIrregular, TMatrixD** matricesZIrregular, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Double_t* rList, const Double_t* phiList, const Double_t* zList) -{ - Float_t drDist, dPhi, dzDist, ddR, ddRPhi, ddZ; - Float_t radius0, phi0, z0, radius, phi, z, radiusCorrection, z1; - - Float_t localIntErOverEz = 0.0; - Float_t localIntEPhiOverEz = 0.0; - Float_t localIntDeltaEz = 0.0; - // set parameters for function - // hard coded, will be modified after pull at AliRoot - - TFormula* ezF = GetEzFormula(); - radiusCorrection = 0.0; - radius = 0.0; - TMatrixD* mDistDrDz; - TMatrixD* mDistDPhiRDz; - TMatrixD* mDistDz; - TMatrixD* mCorrDrDz; - TMatrixD* mCorrDPhiRDz; - TMatrixD* mCorrDz; - TMatrixD* mCorrIrregularDrDz; - TMatrixD* mCorrIrregularDPhiRDz; - TMatrixD* mCorrIrregularDz; - TMatrixD* mRIrregular; - TMatrixD* mPhiIrregular; - TMatrixD* mZIrregular; - Int_t j = nZColumn - 1; - z0 = zList[j]; - - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // follow the drift - radius0 = rList[i]; - phi = phi0; - radius = radius0; - /// - (*mDistDrDz)(i, j) = 0.0; - (*mDistDPhiRDz)(i, j) = 0.0; - (*mDistDz)(i, j) = 0.0; - - //////////////// use irregular grid look up table for correction - // set - (*mCorrIrregularDrDz)(i, j) = 0.0; - (*mCorrIrregularDPhiRDz)(i, j) = 0.0; - (*mCorrIrregularDz)(i, j) = 0.0; - - // distorted point - (*mRIrregular)(i, j) = radius0; - (*mPhiIrregular)(i, j) = phi0; - (*mZIrregular)(i, j) = z0; - /////////////// - } - } - - // from j one column near end cap - for (j = nZColumn - 2; j >= 0; j--) { - - z0 = zList[j]; - - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // do from j to 0 - // follow the drift - radius0 = rList[i]; - phi = phi0; - radius = radius0; - - drDist = 0.0; - dPhi = 0.0; - dzDist = 0.0; - ddRPhi = 0.0; - - // follow the drift line from z=j --> nZColumn - 1 - for (Int_t jj = j; jj < nZColumn; jj++) { - // interpolation the local distortion for current position - phi = phi0 + dPhi; - radius = radius0 + drDist; - z = zList[jj] + dzDist; - z1 = z + (zList[j + 1] - zList[j]); - // regulate phi - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - //lookupLocalDist->GetValue(radius, phi, z, ddR, ddRPhi, ddZ); - localIntErOverEz = (intDrDzF->Eval(radius, phi, z1) - intDrDzF->Eval(radius, phi, z)) / (ezField + ezF->Eval(radius, phi, z)); - localIntEPhiOverEz = (intDPhiDzF->Eval(radius, phi, z1) - intDPhiDzF->Eval(radius, phi, z)) / (ezField + ezF->Eval(radius, phi, z)); - localIntDeltaEz = intDzDzF->Eval(radius, phi, z1) - intDzDzF->Eval(radius, phi, z); - - ddR = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - ddRPhi = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - ddZ = -1 * localIntDeltaEz * AliTPCPoissonSolver::fgkdvdE; - - drDist += ddR; - dPhi += (ddRPhi / radius); - dzDist += ddZ; - - // add local distortion - } - // set the global distortion after following the electron drift - (*mDistDrDz)(i, j) = drDist; - (*mDistDPhiRDz)(i, j) = dPhi * radius0; - (*mDistDz)(i, j) = dzDist; - /////////////// use irregular grid look up table for correction - // use oppsite directions of distortion - (*mCorrIrregularDrDz)(i, j) = -drDist; - (*mCorrIrregularDPhiRDz)(i, j) = -dPhi * (radius0 + drDist); - (*mCorrIrregularDz)(i, j) = -dzDist; - - // distorted point - (*mRIrregular)(i, j) = radius0 + drDist; - (*mPhiIrregular)(i, j) = phi0 + dPhi; - (*mZIrregular)(i, j) = z0 + dzDist; - /////////////// - - // put the radius to the original value - if (j == nZColumn - 2) { - radiusCorrection = radius0; - } - - // get global correction from j+1 - drDist = (*mCorrDrDz)(i, j + 1); - dzDist = (*mCorrDz)(i, j + 1); - - radiusCorrection = radius0 + drDist; - dPhi = (*mCorrDPhiRDz)(i, j + 1) / radius0; - //dPhi = (*mCorrDPhiRDz)(i, j + 1) /radiusCorrection; - phi = phi0 + dPhi; - z = zList[j + 1] + dzDist; - z1 = z - (zList[j + 1] - zList[j]); - - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - //lookupLocalCorr->GetValue(radiusCorrection, phi, z, ddR, ddRPhi, ddZ); - localIntErOverEz = (intDrDzF->Eval(radiusCorrection, phi, z1) - intDrDzF->Eval(radiusCorrection, phi, z)) / (ezField + intDzDzF->Eval(radiusCorrection, phi, z)); - localIntEPhiOverEz = (intDPhiDzF->Eval(radiusCorrection, phi, z1) - intDPhiDzF->Eval(radiusCorrection, phi, z)) / (ezField + intDzDzF->Eval(radiusCorrection, phi, z)); - localIntDeltaEz = intDzDzF->Eval(radiusCorrection, phi, z1) - intDzDzF->Eval(radiusCorrection, phi, z); - - ddR = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - ddRPhi = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - ddZ = -1 * localIntDeltaEz * AliTPCPoissonSolver::fgkdvdE; - - drDist += ddR; - dzDist += ddZ; - dPhi += ddRPhi / radiusCorrection; - - (*mCorrDrDz)(i, j) = drDist; - (*mCorrDPhiRDz)(i, j) = dPhi * radius0; - (*mCorrDz)(i, j) = dzDist; - } - } - } -} - -/// follow the drift for exact function -/// -/// \param intDrDzF -/// \param intDPhiDzF -/// \param intDzDzF -/// \param ezField -/// \param matricesGDistDrDz -/// \param matricesGDistDPhiRDz -/// \param matricesGDistDz -/// \param matricesGCorrDrDz -/// \param matricesGCorrDPhiRDz -/// \param matricesGCorrDz -/// \param matricesGCorrIrregularDrDz -/// \param matricesGCorrIrregularDPhiRDz -/// \param matricesGCorrIrregularDz -/// \param matricesRIrregular -/// \param matricesPhiIrregular -/// \param matricesZIrregular -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -/// \param rList -/// \param phiList -/// \param zList -void AliTPCSpaceCharge3DCalc::IntegrateDistCorrDriftLineDz( - TFormula* intDrDzF, TFormula* intDPhiDzF, TFormula* intDzDzF, TFormula* ezF, const Double_t ezField, - TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, - TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, TMatrixD** matricesGCorrIrregularDz, TMatrixD** matricesRIrregular, - TMatrixD** matricesPhiIrregular, TMatrixD** matricesZIrregular, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Double_t* rList, const Double_t* phiList, const Double_t* zList) -{ - - Float_t drDist, dPhi, dzDist, ddR, ddRPhi, ddZ; - Float_t radius0, phi0, z0, radius, phi, z, radiusCorrection, z1; - - Float_t localIntErOverEz = 0.0; - Float_t localIntEPhiOverEz = 0.0; - Float_t localIntDeltaEz = 0.0; - - radiusCorrection = 0.0; - radius = 0.0; - TMatrixD* mDistDrDz; - TMatrixD* mDistDPhiRDz; - TMatrixD* mDistDz; - TMatrixD* mCorrDrDz; - TMatrixD* mCorrDPhiRDz; - TMatrixD* mCorrDz; - TMatrixD* mCorrIrregularDrDz; - TMatrixD* mCorrIrregularDPhiRDz; - TMatrixD* mCorrIrregularDz; - TMatrixD* mRIrregular; - TMatrixD* mPhiIrregular; - TMatrixD* mZIrregular; - Int_t j = nZColumn - 1; - z0 = zList[j]; - - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // follow the drift - radius0 = rList[i]; - phi = phi0; - radius = radius0; - /// - (*mDistDrDz)(i, j) = 0.0; - (*mDistDPhiRDz)(i, j) = 0.0; - (*mDistDz)(i, j) = 0.0; - - //////////////// use irregular grid look up table for correction - // set - (*mCorrIrregularDrDz)(i, j) = 0.0; - (*mCorrIrregularDPhiRDz)(i, j) = 0.0; - (*mCorrIrregularDz)(i, j) = 0.0; - - // distorted point - (*mRIrregular)(i, j) = radius0; - (*mPhiIrregular)(i, j) = phi0; - (*mZIrregular)(i, j) = z0; - /////////////// - } - } - - // from j one column near end cap - for (j = nZColumn - 2; j >= 0; j--) { - - z0 = zList[j]; - - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - mCorrIrregularDrDz = matricesGCorrIrregularDrDz[m]; - mCorrIrregularDPhiRDz = matricesGCorrIrregularDPhiRDz[m]; - mCorrIrregularDz = matricesGCorrIrregularDz[m]; - - mRIrregular = matricesRIrregular[m]; - mPhiIrregular = matricesPhiIrregular[m]; - mZIrregular = matricesZIrregular[m]; - - for (Int_t i = 0; i < nRRow; i++) { - // do from j to 0 - // follow the drift - radius0 = rList[i]; - phi = phi0; - radius = radius0; - - drDist = 0.0; - dPhi = 0.0; - dzDist = 0.0; - ddRPhi = 0.0; - - // follow the drift line from z=j --> nZColumn - 1 - for (Int_t jj = j; jj < nZColumn; jj++) { - // interpolation the local distortion for current position - phi = phi0 + dPhi; - radius = radius0 + drDist; - z = zList[jj] + dzDist; - z1 = z + (zList[j + 1] - zList[j]); - // regulate phi - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - //lookupLocalDist->GetValue(radius, phi, z, ddR, ddRPhi, ddZ); - localIntErOverEz = (intDrDzF->Eval(radius, phi, z1) - intDrDzF->Eval(radius, phi, z)) / (ezField + ezF->Eval(radius, phi, z)); - localIntEPhiOverEz = (intDPhiDzF->Eval(radius, phi, z1) - intDPhiDzF->Eval(radius, phi, z)) / (ezField + ezF->Eval(radius, phi, z)); - localIntDeltaEz = intDzDzF->Eval(radius, phi, z1) - intDzDzF->Eval(radius, phi, z); - - ddR = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - ddRPhi = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - ddZ = -1 * localIntDeltaEz * AliTPCPoissonSolver::fgkdvdE; - - drDist += ddR; - dPhi += (ddRPhi / radius); - dzDist += ddZ; - - // add local distortion - } - // set the global distortion after following the electron drift - (*mDistDrDz)(i, j) = drDist; - (*mDistDPhiRDz)(i, j) = dPhi * radius0; - (*mDistDz)(i, j) = dzDist; - /////////////// use irregular grid look up table for correction - // use oppsite directions of distortion - (*mCorrIrregularDrDz)(i, j) = -drDist; - (*mCorrIrregularDPhiRDz)(i, j) = -dPhi * (radius0 + drDist); - (*mCorrIrregularDz)(i, j) = -dzDist; - - // distorted point - (*mRIrregular)(i, j) = radius0 + drDist; - (*mPhiIrregular)(i, j) = phi0 + dPhi; - (*mZIrregular)(i, j) = z0 + dzDist; - /////////////// - - // put the radius to the original value - if (j == nZColumn - 2) { - radiusCorrection = radius0; - } - - // get global correction from j+1 - drDist = (*mCorrDrDz)(i, j + 1); - dzDist = (*mCorrDz)(i, j + 1); - - radiusCorrection = radius0 + drDist; - dPhi = (*mCorrDPhiRDz)(i, j + 1) / radius0; - //dPhi = (*mCorrDPhiRDz)(i, j + 1) /radiusCorrection; - phi = phi0 + dPhi; - z = zList[j + 1] + dzDist; - z1 = z - (zList[j + 1] - zList[j]); - - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - //lookupLocalCorr->GetValue(radiusCorrection, phi, z, ddR, ddRPhi, ddZ); - localIntErOverEz = (intDrDzF->Eval(radiusCorrection, phi, z1) - intDrDzF->Eval(radiusCorrection, phi, z)) / (ezField + intDzDzF->Eval(radiusCorrection, phi, z)); - localIntEPhiOverEz = (intDPhiDzF->Eval(radiusCorrection, phi, z1) - intDPhiDzF->Eval(radiusCorrection, phi, z)) / (ezField + intDzDzF->Eval(radiusCorrection, phi, z)); - localIntDeltaEz = intDzDzF->Eval(radiusCorrection, phi, z1) - intDzDzF->Eval(radiusCorrection, phi, z); - - ddR = fC0 * localIntErOverEz + fC1 * localIntEPhiOverEz; - ddRPhi = fC0 * localIntEPhiOverEz - fC1 * localIntErOverEz; - ddZ = -1 * localIntDeltaEz * AliTPCPoissonSolver::fgkdvdE; // two times? - - drDist += ddR; - dzDist += ddZ; - dPhi += ddRPhi / radiusCorrection; - - (*mCorrDrDz)(i, j) = drDist; - (*mCorrDPhiRDz)(i, j) = dPhi * radius0; - (*mCorrDz)(i, j) = dzDist; - } - } - } -} - -/// See explanation at LocalDistCorrDz -/// -/// -/// \param matricesEr TMatrixD** electric field for \f$r\f$ component -/// \param matricesEPhi TMatrixD** electric field for \f$\phi\f$ component -/// \param matricesEz TMatrixD** electric field for \f$z\f$ component -/// \param matricesCorrDrDz TMatrixD** local correction \f$\hat{\delta}_{r}\f$ -/// \param matricesCorrDPhiRDz TMatrixD** local correction \f$r \hat{\delta}_{\phi}\f$ -/// \param matricesCorrDz TMatrixD** local correction \f$ \hat{\delta}_{z}\f$ -/// \param nRRow Int_t Number of nRRow in r-direction -/// \param nZColumn Int_t Number of nZColumn in z-direction -/// \param phiSlice Int_t Number of phi slices in \f$ phi \f$ direction -/// \param gridSizeZ const Float_t grid size in z direction -/// \param ezField const Double_t ezField calculate from the invoking operation -/// -/// \pre matricesEr, matricesEPhi, matrices Ez are provided -/// \post Local correction are computed according simplified Langevin equation -/// ~~~ -/// matricesCorrDz,matricesCorrDPhiRDz,matricesDistDz -/// ~~~ -void AliTPCSpaceCharge3DCalc::IntegrateDistCorrDriftLineDzWithLookUp(AliTPCLookUpTable3DInterpolatorD* lookupLocalDist, TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr, TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, Double_t* rList, Double_t* phiList, Double_t* zList) -{ - - Float_t drDist, dRPhi, dPhi, dzDist, ddR, ddRPhi, ddPhi, ddZ; - Float_t radius0, phi0, z0, radius, phi, z, radiusCorrection; - TMatrixD* mDistDrDz; - TMatrixD* mDistDPhiRDz; - TMatrixD* mDistDz; - TMatrixD* mCorrDrDz; - TMatrixD* mCorrDPhiRDz; - TMatrixD* mCorrDz; - - // allocate look up for temporal - AliTPCLookUpTable3DInterpolatorD* lookupGlobalDistTemp = - new AliTPCLookUpTable3DInterpolatorD( - nRRow, matricesGDistDrDz, rList, phiSlice, matricesGDistDPhiRDz, phiList, nZColumn, matricesGDistDz, - zList, 1); - - Int_t j = nZColumn - 1; - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - for (Int_t i = 0; i < nRRow; i++) { - /// - (*mDistDrDz)(i, j) = 0.0; - (*mDistDPhiRDz)(i, j) = 0.0; - (*mDistDz)(i, j) = 0.0; - - (*mCorrDrDz)(i, j) = 0.0; - (*mCorrDPhiRDz)(i, j) = 0.0; - (*mCorrDz)(i, j) = 0.0; - } - } - - drDist = 0.0; - dRPhi = 0.0; - dPhi = 0.0; - dzDist = 0.0; - // from j one column near end cap - for (j = nZColumn - 2; j >= 0; j--) { - - z0 = zList[j]; - for (Int_t m = 0; m < phiSlice; m++) { - phi0 = phiList[m]; - - mDistDrDz = matricesGDistDrDz[m]; - mDistDPhiRDz = matricesGDistDPhiRDz[m]; - mDistDz = matricesGDistDz[m]; - - // - mCorrDrDz = matricesGCorrDrDz[m]; - mCorrDPhiRDz = matricesGCorrDPhiRDz[m]; - mCorrDz = matricesGCorrDz[m]; - - for (Int_t i = 0; i < nRRow; i++) { - - // do from j to 0 - // follow the drift - radius0 = rList[i]; - - lookupLocalDist->GetValue(radius0, phi0, z0, ddR, ddRPhi, ddZ); - ddPhi = ddRPhi / radius0; - - if (j < nZColumn - 2) { - phi = phi0 + ddPhi; - radius = radius0 + ddR; - z = zList[j + 1] + ddZ; - - lookupGlobalDistTemp->GetValue(radius, phi, z, drDist, dRPhi, dzDist); - dPhi = dRPhi / radius; - } - - (*mDistDrDz)(i, j) = drDist + ddR; - (*mDistDPhiRDz)(i, j) = (dPhi + ddPhi) * radius0; - (*mDistDz)(i, j) = dzDist + ddZ; - - // copy to 1D for being able to interpolate at next step - if (j > 0) { - (*mDistDrDz)(i, j - 1) = drDist + ddR; - (*mDistDPhiRDz)(i, j - 1) = (dPhi + ddPhi) * radius0; - (*mDistDz)(i, j - 1) = dzDist + ddZ; - } - - // get global correction from j+1 - drDist = (*mCorrDrDz)(i, j + 1); - dPhi = (*mCorrDPhiRDz)(i, j + 1) / radius0; - dzDist = (*mCorrDz)(i, j + 1); - - radiusCorrection = radius0 + drDist; - phi = phi0 + dPhi; - z = zList[j + 1] + dzDist; - - while (phi < 0.0) { - phi = TMath::TwoPi() + phi; - } - while (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); - } - - lookupLocalCorr->GetValue(radiusCorrection, phi, z, ddR, ddRPhi, ddZ); - - drDist += ddR; - dzDist += ddZ; - dPhi += (ddRPhi / radiusCorrection); - - (*mCorrDrDz)(i, j) = drDist; - (*mCorrDPhiRDz)(i, j) = dPhi * radius0; - (*mCorrDz)(i, j) = dzDist; - } - } - - lookupGlobalDistTemp->CopyFromMatricesToInterpolator(j); - if (j > 0) { - lookupGlobalDistTemp->CopyFromMatricesToInterpolator(j - 1); - } - } - delete lookupGlobalDistTemp; -} - -/// -/// \param lookupGlobal -/// \param lookupRDz -/// \param lookupPhiRDz -/// \param lookupDz -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -/// \param rList -/// \param phiList -/// \param zList -void AliTPCSpaceCharge3DCalc::FillLookUpTable(AliTPCLookUpTable3DInterpolatorD* lookupGlobal, TMatrixD** lookupRDz, - TMatrixD** lookupPhiRDz, TMatrixD** lookupDz, const Int_t nRRow, - const Int_t nZColumn, const Int_t phiSlice, const Double_t* rList, - const Double_t* phiList, const Double_t* zList) -{ - Double_t r, phi, z; - TMatrixD* mR; - TMatrixD* mPhiR; - TMatrixD* mDz; - - /// * Interpolate basicLookup tables; once for each rod, then sum the results - for (Int_t k = 0; k < fNPhiSlices; k++) { - phi = fListPhi[k]; - - mR = lookupRDz[k]; - mPhiR = lookupPhiRDz[k]; - mDz = lookupDz[k]; - for (Int_t j = 0; j < fNZColumns; j++) { - z = fListZ[j]; // Symmetric solution in Z that depends only on ABS(Z) - - for (Int_t i = 0; i < fNRRows; i++) { - r = fListR[i]; - - lookupGlobal->GetValue(r, phi, z, (*mR)(i, j), (*mPhiR)(i, j), (*mDz)(i, j)); - } - } - } -} -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - GetDistortionCylAC(x, roc, dx); -} -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetDistortionCylAC(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::GetDistortionCylAC", "Lookup table was not initialized! Please run AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz(nRRows, nZColumns, nPhiSlices) to perform the initialization. Returning distortion vector (0, 0, 0)."); - for (int i = 0; i < 3; ++i) { - dx[i] = 0.; - } - return; - } - - Float_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::GetDistortionCylAC", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupIntDistA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupIntDistC->GetValue(r, phi, -1 * z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} -/// Get Correction from irregular table -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrectionCylACIrregular(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::GetCorrectionCylACIrregular", "Lookup table was not initialized! Please run AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz(nRRows, nZColumns, nPhiSlices) to perform the initialization. Returning correction vector (0, 0, 0)."); - for (int i = 0; i < 3; ++i) { - dx[i] = 0.; - } - return; - } - - Double_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNRRows - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZColumns - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhiSlices; - - r = x[0]; - phi = x[1]; - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceChargeCalc3D::GetCorrectionCylACIrregular", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - // get distortion from irregular table - - if (z > 0) { - fLookupIntCorrIrregularA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupIntCorrIrregularC->GetValue(r, phi, -z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} - -/// Get Correction from irregular table -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrectionCylACIrregular(const Float_t x[], Short_t roc, Float_t dx[], const Int_t side) const -{ - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::GetCorrectionCylACIrregular", "Lookup table was not initialized! Please run AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz(nRRows, nZColumns, nPhiSlices) to perform the initialization. Returning correction vector (0, 0, 0)."); - for (int i = 0; i < 3; ++i) { - dx[i] = 0.; - } - return; - } - - Double_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNRRows - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZColumns - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhiSlices; - - r = x[0]; - phi = x[1]; - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceChargeCalc3D::GetCorrectionCylACIrregular", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - // get distortion from irregular table - - if (side == 0) { - fLookupIntCorrIrregularA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupIntCorrIrregularC->GetValue(r, phi, -z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} - -/// Get correction regular grid by following electron -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrectionCylAC(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::GetDistortionCylAC", "Lookup table was not initialized! Please run AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz(nRRows, nZColumns, nPhiSlices) to perform the initialization. Returning correction vector (0, 0, 0)."); - for (int i = 0; i < 3; ++i) { - dx[i] = 0.; - } - return; - } - - Float_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceChargeCalc3D::GetCorrectionCylAC", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupIntCorrA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupIntCorrC->GetValue(r, phi, -z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} -void AliTPCSpaceCharge3DCalc::GetDistortion(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - Float_t pCyl[3]; // a point in cylindrical coordinate - Float_t dCyl[3]; // distortion - - pCyl[0] = TMath::Sqrt(x[0] * x[0] + x[1] * x[1]); - pCyl[1] = TMath::ATan2(x[1], x[0]); - - // normalize phi - while (pCyl[1] > TMath::Pi()) { - pCyl[1] -= TMath::TwoPi(); - } - while (pCyl[1] < -TMath::Pi()) { - pCyl[1] += TMath::TwoPi(); - } - - pCyl[2] = x[2]; // Create temporary copy of x[2] - - GetDistortionCylAC(pCyl, roc, dCyl); - - // Calculate distorted position - if (pCyl[0] > 0.0) { - //pCyl[0] = pCyl[0] + fCorrectionFactor * dCyl[0]; - pCyl[1] = pCyl[1] + fCorrectionFactor * dCyl[1] / pCyl[0]; - pCyl[0] = pCyl[0] + fCorrectionFactor * dCyl[0]; - } - - dCyl[2] = fCorrectionFactor * dCyl[2]; - - // distortion in x,y and z - dx[0] = (pCyl[0] * TMath::Cos(pCyl[1]) - x[0]); - dx[1] = (pCyl[0] * TMath::Sin(pCyl[1]) - x[1]); - dx[2] = dCyl[2]; -} -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrectionCyl(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - if (fCorrectionType == kRegularInterpolator) { - GetCorrectionCylAC(x, roc, dx); - } else { - GetCorrectionCylACIrregular(x, roc, dx); - } -} -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrection(const Float_t x[], Short_t roc, Float_t dx[]) const -{ - Float_t pCyl[3]; // a point in cylindrical coordinate - Float_t dCyl[3]; // distortion - - pCyl[0] = TMath::Sqrt(x[0] * x[0] + x[1] * x[1]); - pCyl[1] = TMath::ATan2(x[1], x[0]); - pCyl[2] = x[2]; // Create temporary copy of x[2] - - if (fCorrectionType == kRegularInterpolator) { - while (pCyl[1] > TMath::Pi()) { - pCyl[1] -= TMath::TwoPi(); - } - while (pCyl[1] < -TMath::Pi()) { - pCyl[1] += TMath::TwoPi(); - } - - GetCorrectionCylAC(pCyl, roc, dCyl); - } else { - GetCorrectionCylACIrregular(pCyl, roc, dCyl); - } - - // Calculate distorted position - if (pCyl[0] > 0.0) { - //pCyl[0] = pCyl[0] + fCorrectionFactor * dCyl[0]; - pCyl[1] = pCyl[1] + fCorrectionFactor * dCyl[1] / pCyl[0]; - pCyl[0] = pCyl[0] + fCorrectionFactor * dCyl[0]; - } - - dCyl[2] = fCorrectionFactor * dCyl[2]; - - // distortion in x,y and z - dx[0] = (pCyl[0] * TMath::Cos(pCyl[1]) - x[0]); - dx[1] = (pCyl[0] * TMath::Sin(pCyl[1]) - x[1]); - dx[2] = dCyl[2]; -} - -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrection(const Float_t x[], Short_t roc, Float_t dx[], const Int_t side) const -{ - Float_t pCyl[3]; // a point in cylindrical coordinate - Float_t dCyl[3]; // distortion - - pCyl[0] = TMath::Sqrt(x[0] * x[0] + x[1] * x[1]); - pCyl[1] = TMath::ATan2(x[1], x[0]); - pCyl[2] = x[2]; // Create temporary copy of x[2] - - if (fCorrectionType == kRegularInterpolator) { - while (pCyl[1] > TMath::Pi()) { - pCyl[1] -= TMath::TwoPi(); - } - while (pCyl[1] < -TMath::Pi()) { - pCyl[1] += TMath::TwoPi(); - } - - GetCorrectionCylAC(pCyl, roc, dCyl); - } else { - GetCorrectionCylACIrregular(pCyl, roc, dCyl, side); - } - - // Calculate distorted position - if (pCyl[0] > 0.0) { - pCyl[0] = pCyl[0] + fCorrectionFactor * dCyl[0]; - pCyl[1] = pCyl[1] + fCorrectionFactor * dCyl[1] / pCyl[0]; - } - - dCyl[2] = fCorrectionFactor * dCyl[2]; - - // distortion in x,y and z - dx[0] = (pCyl[0] * TMath::Cos(pCyl[1]) - x[0]); - dx[1] = (pCyl[0] * TMath::Sin(pCyl[1]) - x[1]); - dx[2] = dCyl[2]; -} - -/// Use 3D space charge map as an optional input -/// The layout of the input histogram is assumed to be: (phi,r,z) -/// Density histogram is expected to bin in C/m^3 -/// -/// Standard histogram interpolation is used in order to use the density at center of bin -/// -/// \param hisSpaceCharge3D -/// \param norm -void AliTPCSpaceCharge3DCalc::SetInputSpaceCharge(TH3* hisSpaceCharge3D, Double_t norm) -{ - fHistogram3DSpaceCharge = hisSpaceCharge3D; - fInitLookUp = kFALSE; - - Info("AliTPCSpaceCharge3DCalc:SetInputSpaceCharge", "Set Input Space Charge by 3D"); - - Double_t radius0, z0, phi0; - TMatrixD* charge; - for (Int_t iSide = 0; iSide < 2; iSide++) { - for (Int_t k = 0; k < fNPhiSlices; k++) { - if (iSide == 0) { - charge = fMatrixChargeA[k]; - } else { - charge = fMatrixChargeC[k]; - } - - phi0 = fListPhi[k]; - - for (Int_t i = 0; i < fNRRows; i++) { - radius0 = fListR[i]; - - for (Int_t j = 0; j < fNZColumns; j++) { - if (iSide == 0) { - z0 = fListZ[j]; - } else { - z0 = -fListZ[j]; - } - - (*charge)(i, j) = norm * InterpolatePhi(hisSpaceCharge3D, phi0, radius0, z0); - - } // end j - } // end i - } // end phi - } - - fInterpolatorChargeA->SetValue(fMatrixChargeA); - if (fInterpolationOrder > 2) { - fInterpolatorChargeA->InitCubicSpline(); - } - fInterpolatorChargeC->SetValue(fMatrixChargeC); - if (fInterpolationOrder > 2) { - fInterpolatorChargeC->InitCubicSpline(); - } -} - -/// SetInputCharge -/// -/// \param hisSpaceCharge3D TH3* histogram for space charge -/// \param norm Double_t norm/weight -/// \param side Int_t side = 0 => side A, side = 1 => side C -/// -/// side effects: create Charge interpolator -void AliTPCSpaceCharge3DCalc::SetInputSpaceCharge(TH3* hisSpaceCharge3D, Double_t norm, Int_t side) -{ - if (side == 0) { - fHistogram3DSpaceChargeA = hisSpaceCharge3D; - } else { - fHistogram3DSpaceChargeC = hisSpaceCharge3D; - } - - Double_t rMin = hisSpaceCharge3D->GetYaxis()->GetBinCenter(0); - Double_t rMax = hisSpaceCharge3D->GetYaxis()->GetBinUpEdge(hisSpaceCharge3D->GetYaxis()->GetNbins()); - Double_t zMin = hisSpaceCharge3D->GetZaxis()->GetBinCenter(0); - Double_t zMax = hisSpaceCharge3D->GetZaxis()->GetBinCenter(hisSpaceCharge3D->GetZaxis()->GetNbins()); - Double_t radius0, z0, phi0; - TMatrixD* charge; - - for (Int_t k = 0; k < fNPhiSlices; k++) { - if (side == 0) { - charge = fMatrixChargeA[k]; - } else { - charge = fMatrixChargeC[k]; - } - - phi0 = fListPhi[k]; - for (Int_t i = 0; i < fNRRows; i++) { - radius0 = fListR[i]; - for (Int_t j = 0; j < fNZColumns; j++) { - z0 = fListZ[j]; - - if (radius0 > rMin && radius0 < rMax && z0 > zMin && z0 < zMax) { - (*charge)(i, j) = norm * InterpolatePhi(hisSpaceCharge3D, phi0, radius0, z0); - } - } // end j - } // end i - } // end phi - - if (side == 0) { - fInterpolatorChargeA->SetValue(fMatrixChargeA); - fInterpolatorChargeA->InitCubicSpline(); - } else { - fInterpolatorChargeC->SetValue(fMatrixChargeC); - fInterpolatorChargeC->InitCubicSpline(); - } - - fInitLookUp = kFALSE; -} - -/// InterpolationPhi is only used for reading from TH3F (since it is not cylindrical) -/// -/// \param r -/// \param z -/// \return -Double_t AliTPCSpaceCharge3DCalc::InterpolatePhi(const TH3* h3, const Double_t phi, const Double_t r, const Double_t z) -{ - - Int_t ubx = h3->GetXaxis()->FindBin(phi); - if (phi < h3->GetXaxis()->GetBinCenter(ubx)) { - ubx -= 1; - } - Int_t obx = ubx + 1; - Int_t uby = h3->GetYaxis()->FindBin(r); - if (r < h3->GetYaxis()->GetBinCenter(uby)) { - uby -= 1; - } - Int_t oby = uby + 1; - Int_t ubz = h3->GetZaxis()->FindBin(z); - if (z < h3->GetZaxis()->GetBinCenter(ubz)) { - ubz -= 1; - } - Int_t obz = ubz + 1; - - if (uby <= 0 || ubz <= 0 || - oby > h3->GetYaxis()->GetNbins() || obz > h3->GetZaxis()->GetNbins()) { - return 0; - } - - if (ubx <= 0) { - ubx = h3->GetXaxis()->GetNbins(); - } - - if (obx > h3->GetXaxis()->GetNbins()) { - obx = 1; - } - - Double_t xw = h3->GetXaxis()->GetBinCenter(obx) - h3->GetXaxis()->GetBinCenter(ubx); - Double_t yw = h3->GetYaxis()->GetBinCenter(oby) - h3->GetYaxis()->GetBinCenter(uby); - Double_t zw = h3->GetZaxis()->GetBinCenter(obz) - h3->GetZaxis()->GetBinCenter(ubz); - Double_t xd = (phi - h3->GetXaxis()->GetBinCenter(ubx)) / xw; - Double_t yd = (r - h3->GetYaxis()->GetBinCenter(uby)) / yw; - Double_t zd = (z - h3->GetZaxis()->GetBinCenter(ubz)) / zw; - Double_t v[] = {h3->GetBinContent(ubx, uby, ubz), h3->GetBinContent(ubx, uby, obz), - h3->GetBinContent(ubx, oby, ubz), h3->GetBinContent(ubx, oby, obz), - h3->GetBinContent(obx, uby, ubz), h3->GetBinContent(obx, uby, obz), - h3->GetBinContent(obx, oby, ubz), h3->GetBinContent(obx, oby, obz)}; - Double_t i1 = v[0] * (1 - zd) + v[1] * zd; - Double_t i2 = v[2] * (1 - zd) + v[3] * zd; - Double_t j1 = v[4] * (1 - zd) + v[5] * zd; - Double_t j2 = v[6] * (1 - zd) + v[7] * zd; - Double_t w1 = i1 * (1 - yd) + i2 * yd; - Double_t w2 = j1 * (1 - yd) + j2 * yd; - Double_t result = w1 * (1 - xd) + w2 * xd; - return result; -} -/// returns the (input) space charge density at a given point according -/// Note: input in [cm], output in [C/m^3/e0] !! -Float_t AliTPCSpaceCharge3DCalc::GetSpaceChargeDensity(Float_t r, Float_t phi, Float_t z) -{ - while (phi < 0) { - phi += TMath::TwoPi(); - } - while (phi > TMath::TwoPi()) { - phi -= TMath::TwoPi(); - } - - const Int_t order = 1; // - - const Float_t x[] = {r, phi, z}; - Float_t sc = 0; - if (z > -1e-16) { - sc = GetChargeCylAC(x, 0); - } else { - sc = GetChargeCylAC(x, 18); - } - - return sc; -} -/// returns the (input) space charge density at a given point according -/// Note: input in [cm], output in [C/m^3/e0] !! -Float_t AliTPCSpaceCharge3DCalc::GetPotential(Float_t r, Float_t phi, Float_t z) -{ - while (phi < 0) { - phi += TMath::TwoPi(); - } - while (phi > TMath::TwoPi()) { - phi -= TMath::TwoPi(); - } - - const Int_t order = 1; // - - const Float_t x[] = {r, phi, z}; - Float_t v = 0; - if (z > -1e-16) { - v = GetPotentialCylAC(x, 0); - } else { - v = GetPotentialCylAC(x, 18); - } - - return v; -} -/// -/// -/// \param matricesDistDrDz TMatrixD ** matrix of global distortion drDist (r direction) -/// \param matricesDistDPhiRDz TMatrixD ** matrix of global distortion dRPhi (phi r direction) -/// \param matricesDistDz TMatrixD ** matrix of global distortion dzDist (z direction) -/// \param rList Double_t * points of r in the grid (ascending mode) -/// \param zList Double_t * points of z in the grid (ascending mode) -/// \param phiList Double_t * points of phi in the grid (ascending mode) -/// \param nRRow Int_t number of grid in r direction -/// \param nZColumn Int_t number of grid in z direction -/// \param phiSlice Int_t number of grid in phi direction -/// \param nStep Int_t number of step to calculate local dist -/// -void AliTPCSpaceCharge3DCalc::InverseGlobalToLocalDistortionGlobalInvTable( - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, Double_t* rList, - Double_t* zList, Double_t* phiList, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Int_t nStep, const Bool_t useCylAC, Int_t stepR, Int_t stepZ, Int_t stepPhi, Int_t type) -{ - Double_t z, phi, r, zAfter, zPrevious, ddR, ddRPhi, ddZ, zl, drDist, dRPhi, dzDist, ddPhi, dPhi, deltaZ, r0, z0, phi0; - Float_t x[3], dx[3], pdx[3]; - Int_t roc; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - TMatrixD* distDrDz; - TMatrixD* distDPhiRDz; - TMatrixD* distDz; - - // correction build up for inverse flow - TMatrixD* corrDrDz; - TMatrixD* corrDPhiRDz; - TMatrixD* corrDz; - TMatrixD* listR; - TMatrixD* listPhi; - TMatrixD* listZ; - TMatrixD* matricesCorrDrDz[phiSlice]; - TMatrixD* matricesCorrDPhiRDz[phiSlice]; - TMatrixD* matricesCorrDz[phiSlice]; - TMatrixD* matricesRList[phiSlice]; - TMatrixD* matricesPhiList[phiSlice]; - TMatrixD* matricesZList[phiSlice]; - - for (Int_t m = 0; m < phiSlice; m++) { - matricesCorrDrDz[m] = new TMatrixD(nRRow, nZColumn); - matricesCorrDPhiRDz[m] = new TMatrixD(nRRow, nZColumn); - matricesCorrDz[m] = new TMatrixD(nRRow, nZColumn); - - matricesRList[m] = new TMatrixD(nRRow, nZColumn); - matricesPhiList[m] = new TMatrixD(nRRow, nZColumn); - matricesZList[m] = new TMatrixD(nRRow, nZColumn); - } - - AliTPCLookUpTable3DInterpolatorIrregularD* lookupInverseCorr = new AliTPCLookUpTable3DInterpolatorIrregularD( - nRRow, matricesCorrDrDz, matricesRList, phiSlice, matricesCorrDPhiRDz, - matricesPhiList, nZColumn, matricesCorrDz, matricesZList, 2, - stepR, stepZ, stepPhi, type); - - lookupInverseCorr->SetKernelType(GetRBFKernelType()); - - for (Int_t k = 0; k < phiSlice; k++) { - distDrDz = matricesDistDrDz[k]; - distDPhiRDz = matricesDistDPhiRDz[k]; - distDz = matricesDistDz[k]; - - listR = matricesRList[k]; - listPhi = matricesPhiList[k]; - listZ = matricesZList[k]; - - for (Int_t i = 0; i < nRRow; i++) { - (*distDrDz)(i, nZColumn - 1) = 0.0; - (*distDPhiRDz)(i, nZColumn - 1) = 0.0; - (*distDz)(i, nZColumn - 1) = 0.0; - - for (Int_t j = 0; j < nZColumn; j++) { - (*listR)(i, j) = rList[i]; - (*listPhi)(i, j) = phiList[k]; - (*listZ)(i, j) = zList[j]; - } - } - } - - // 1) create global correction - deltaZ = (zList[1] - zList[0]); - Int_t iAnchor, kAnchor, zAnchor; - - for (Int_t j = nZColumn - 2; j >= 0; j--) { - - roc = 0; // FIXME - for (Int_t k = 0; k < phiSlice; k++) { - - corrDrDz = matricesCorrDrDz[k]; - corrDPhiRDz = matricesCorrDPhiRDz[k]; - corrDz = matricesCorrDz[k]; - - listR = matricesRList[k]; - listPhi = matricesPhiList[k]; - listZ = matricesZList[k]; - - for (Int_t i = 0; i < nRRow; i++) { - // get global distortion - - r = rList[i]; - phi = phiList[k]; - z = zList[j]; - - drDist = 0.0; - dzDist = 0.0; - dRPhi = 0.0; - - x[0] = r; - x[1] = phi; - x[2] = z; - - if (useCylAC == kTRUE) { - GetDistortionCylAC(x, roc, dx); - } else { - GetDistortionCyl(x, roc, dx); - } - - drDist = dx[0]; - dzDist = dx[2]; - dRPhi = dx[1]; - - r = rList[i]; - phi = phiList[k]; - z = zList[j]; - - (*corrDrDz)(i, j + 1) = -drDist; - (*corrDz)(i, j + 1) = -dzDist; - (*corrDPhiRDz)(i, j + 1) = -dRPhi; - - (*listR)(i, j + 1) = r + drDist; - (*listPhi)(i, j + 1) = phi + dRPhi / r; - (*listZ)(i, j + 1) = z + dzDist; - } - } - lookupInverseCorr->CopyFromMatricesToInterpolator(j + 1); - } - // 2) calculate local distortion - for (Int_t j = nZColumn - 2; j >= 0; j--) { - roc = 0; // FIXME - for (Int_t k = 0; k < phiSlice; k++) { - distDrDz = matricesDistDrDz[k]; - distDPhiRDz = matricesDistDPhiRDz[k]; - distDz = matricesDistDz[k]; - for (Int_t i = 0; i < nRRow; i++) { - // get global distortion - r = rList[i]; - phi = phiList[k]; - z = zList[j]; - drDist = 0.0; - dzDist = 0.0; - dRPhi = 0.0; - - if (j < nZColumn - 2) { - // get global distortion of this point - x[0] = r; - x[1] = phi; - x[2] = z; - if (useCylAC == kTRUE) { - GetDistortionCylAC(x, roc, dx); - } else { - GetDistortionCyl(x, roc, dx); - } - - r0 = r + dx[0]; - z0 = zList[j + 1] + dx[2]; - phi0 = phi + (dx[1] / r); - iAnchor = TMath::FloorNint((r0 - AliTPCPoissonSolver::fgkIFCRadius) / gridSizeR); - kAnchor = TMath::FloorNint(phi0 / gridSizePhi); - zAnchor = TMath::FloorNint(z0 / gridSizeZ); - - if (j > nZColumn - (GetIrregularGridSize() + 2)) { - lookupInverseCorr->GetValue(r0, phi0, z0, drDist, dRPhi, dzDist, iAnchor, kAnchor, zAnchor, - nRRow / 4 + 1, phiSlice / 4 + 1, 1, 0); - } else { - lookupInverseCorr->GetValue(r0, phi0, z0, drDist, dRPhi, dzDist, iAnchor, kAnchor, zAnchor, - nRRow / 4 + 1, phiSlice / 4 + 1, GetIrregularGridSize(), 0); - } - - phi0 = phi0 + ((dRPhi) / r0); - r0 = r0 + (drDist); - z0 += dzDist; - - x[0] = r0; - x[1] = phi0; - x[2] = z0; - - if (phi0 < 0) { - phi0 = TMath::TwoPi() + phi0; - } - if (phi0 > TMath::TwoPi()) { - phi0 = phi0 - TMath::TwoPi(); - } - - if (useCylAC == kTRUE) { - GetDistortionCylAC(x, roc, pdx); - } else { - GetDistortionCyl(x, roc, pdx); - } - - drDist = (dx[0] - pdx[0]); - dzDist = (dx[2] - pdx[2]); - dRPhi = (dx[1] - pdx[1]); - - } else if (j == (nZColumn - 2)) { - - x[0] = r; - x[1] = phi; - x[2] = zList[j]; - if (useCylAC == kTRUE) { - GetDistortionCylAC(x, roc, dx); - } else { - GetDistortionCyl(x, roc, dx); - } - - x[2] = zList[j + 1]; - if (useCylAC == kTRUE) { - GetDistortionCylAC(x, roc, pdx); - } else { - GetDistortionCyl(x, roc, pdx); - } - drDist = (dx[0] - pdx[0]); - dzDist = (dx[2] - pdx[2]); - dRPhi = (dx[1] - pdx[1]); - } - - (*distDrDz)(i, j) = drDist; - (*distDz)(i, j) = dzDist; - (*distDPhiRDz)(i, j) = dRPhi; - } - } - } - - for (Int_t m = 0; m < phiSlice; m++) { - delete matricesCorrDrDz[m]; - delete matricesCorrDPhiRDz[m]; - delete matricesCorrDz[m]; - delete matricesRList[m]; - delete matricesPhiList[m]; - delete matricesZList[m]; - } - delete lookupInverseCorr; -} -/// -/// \param matricesEr -/// \param matricesEPhi -/// \param matricesEz -/// \param matricesInvLocalIntErDz -/// \param matricesInvLocalIntEPhiDz -/// \param matricesInvLocalIntEz -/// \param matricesDistDrDz -/// \param matricesDistDPhiRDz -/// \param matricesDistDz -/// \param rList -/// \param zList -/// \param phiList -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -void AliTPCSpaceCharge3DCalc::InverseLocalDistortionToElectricField( - TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - TMatrixD** matricesInvLocalIntErDz, TMatrixD** matricesInvLocalIntEPhiDz, - TMatrixD** matricesInvLocalIntEz, TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, - TMatrixD** matricesDistDz, Double_t* rList, Double_t* zList, Double_t* phiList, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice) -{ - // calculate integral - Float_t localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, z2; - Double_t r; - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - - TMatrixD* distDrDz; - TMatrixD* distDz; - TMatrixD* distDPhiRDz; - TMatrixD* tDistDz; - TMatrixD* tDistDPhiRDz; - TMatrixD* tDistDrDz; - Float_t c02c12 = fC0 * fC0 + fC1 * fC1; - - // solve local integration - for (Int_t j = 0; j < nZColumn; j++) { - for (Int_t k = 0; k < phiSlice; k++) { - distDrDz = matricesDistDrDz[k]; - distDz = matricesDistDz[k]; - distDPhiRDz = matricesDistDPhiRDz[k]; - - tDistDrDz = matricesInvLocalIntErDz[k]; - tDistDz = matricesInvLocalIntEz[k]; - tDistDPhiRDz = matricesInvLocalIntEPhiDz[k]; - for (Int_t i = 0; i < nRRow; i++) { - localIntErOverEz = fC0 * (*distDrDz)(i, j) - fC1 * (*distDPhiRDz)(i, j); - localIntErOverEz = localIntErOverEz / (fC0 * fC0 + fC1 * fC1); - localIntEPhiOverEz = ((*distDrDz)(i, j) - (fC0 * localIntErOverEz)) / fC1; - localIntDeltaEz = -1 * (*distDz)(i, j) / AliTPCPoissonSolver::fgkdvdE; // two times? - (*tDistDrDz)(i, j) = localIntErOverEz; - (*tDistDPhiRDz)(i, j) = localIntEPhiOverEz; - (*tDistDz)(i, j) = localIntDeltaEz; - } - } - } - TMatrixD* mEPhi; - TMatrixD* mEr; - TMatrixD* mEz; - - // use central-backward-forward difference for calculating Electric field component - for (Int_t m = 0; m < phiSlice; m++) { - mEPhi = matricesEPhi[m]; - mEr = matricesEr[m]; - mEz = matricesEz[m]; - distDrDz = matricesInvLocalIntErDz[m]; - distDPhiRDz = matricesInvLocalIntEPhiDz[m]; - distDz = matricesInvLocalIntEz[m]; - for (Int_t i = 0; i < nRRow; i++) { - (*mEr)(i, 0) = ((*distDrDz)(i, 0) / gridSizeZ) * -1 * ezField; - (*mEPhi)(i, 0) = ((*distDPhiRDz)(i, 0) / gridSizeZ) * -1 * ezField; - (*mEz)(i, 0) = ((*distDz)(i, 0) / gridSizeZ); - (*mEr)(i, nZColumn - 1) = - ((-0.5 * (*distDrDz)(i, nZColumn - 3) + 1.5 * (*distDrDz)(i, nZColumn - 2)) / gridSizeZ) * ezField; - (*mEPhi)(i, nZColumn - 1) = - ((-0.5 * (*distDPhiRDz)(i, nZColumn - 3) + 1.5 * (*distDPhiRDz)(i, nZColumn - 2)) / gridSizeZ) * - ezField; - (*mEz)(i, nZColumn - 1) = - (-0.5 * (*distDz)(i, nZColumn - 3) + 1.5 * (*distDz)(i, nZColumn - 2)) / gridSizeZ; - } - - for (Int_t i = 0; i < nRRow; i++) { - for (Int_t j = 1; j < nZColumn - 1; j++) { - (*mEr)(i, j) = (((*distDrDz)(i, j) + (*distDrDz)(i, j - 1)) / (2 * gridSizeZ)) * - ezField; // z direction - (*mEPhi)(i, j) = (((*distDPhiRDz)(i, j) + (*distDPhiRDz)(i, j - 1)) / (2 * gridSizeZ)) * - ezField; // z direction - (*mEz)(i, j) = ((*distDz)(i, j) + (*distDz)(i, j - 1)) / (2 * gridSizeZ); // z direction - } - } - } -} -/// Inverse Electric Field to Charge -/// using partial differential -/// -/// \param matricesCharge -/// \param matricesEr -/// \param matricesEPhi -/// \param matricesEz -/// \param rList -/// \param zList -/// \param phiList -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -void AliTPCSpaceCharge3DCalc::InverseElectricFieldToCharge( - TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - Double_t* rList, Double_t* zList, Double_t* phiList, const Int_t nRRow, - const Int_t nZColumn, const Int_t phiSlice) -{ - - Float_t radius; - Double_t drDist, dzDist, dPhi; - Int_t mPlus, mMinus, mPlus2, mMinus2, signPlus, signMinus; - Int_t symmetry = 0; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - - for (Int_t m = 0; m < phiSlice; m++) { - mPlus = m + 1; - signPlus = 1; - mMinus = m - 1; - signMinus = 1; - mPlus2 = m + 2; - mMinus2 = m - 2; - if (symmetry == 1) { // Reflection symmetry in phi (e.g. symmetry at sector boundaries, or half sectors, etc.) - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - } - if (mMinus < 0) { - mMinus = 1; - } - } else if (symmetry == -1) { // Anti-symmetry in phi - if (mPlus > phiSlice - 1) { - mPlus = phiSlice - 2; - signPlus = -1; - } - if (mMinus < 0) { - mMinus = 1; - signMinus = -1; - } - } else { // No Symmetries in phi, no boundaries, the calculations is continuous across all phi - if (mPlus > phiSlice - 1) { - mPlus = m + 1 - phiSlice; - } - if (mMinus < 0) { - mMinus = m - 1 + phiSlice; - } - if (mPlus2 > phiSlice - 1) { - mPlus2 = m + 2 - phiSlice; - } - if (mMinus2 < 0) { - mMinus2 = m - 2 + phiSlice; - } - } - - TMatrixD& matrixCharge = *matricesCharge[m]; - TMatrixD& matrixEr = *matricesEr[m]; - TMatrixD& matrixEz = *matricesEz[m]; - TMatrixD& matrixEPhi = *matricesEPhi[m]; - TMatrixD& matrixEPhiM = *matricesEPhi[mMinus]; - TMatrixD& matrixEPhiP = *matricesEPhi[mPlus]; - TMatrixD& matrixEPhiM2 = *matricesEPhi[mMinus2]; - TMatrixD& matrixEPhiP2 = *matricesEPhi[mPlus2]; - - // for non-boundary V - for (Int_t i = 2; i < nRRow - 2; i++) { - radius = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - for (Int_t j = 2; j < nZColumn - 2; j++) { - drDist = (-matrixEr(i + 2, j) + 8 * matrixEr(i + 1, j) - 8 * matrixEr(i - 1, j) + matrixEr(i - 2, j)) / - (12 * gridSizeR); // r direction - dzDist = (-matrixEz(i, j + 2) + 8 * matrixEz(i, j + 1) - 8 * matrixEz(i, j - 1) + matrixEz(i, j - 2)) / - (12 * gridSizeZ); // r direction - dPhi = (-matrixEPhiP2(i, j) + 8 * matrixEPhiP(i, j) - 8 * matrixEPhiM(i, j) + matrixEPhiM2(i, j)) / - (12 * gridSizePhi); // phi - - matrixCharge(i, j) = -1 * (matrixEr(i, j) / radius + drDist + dPhi / radius + dzDist); - } - } - - // for boundary in r - for (Int_t j = 2; j < nZColumn - 2; j++) { - - // r near inner radius - // for index r[0] - radius = AliTPCPoissonSolver::fgkIFCRadius; - drDist = (-(11.0 / 6.0) * matrixEr(0, j) + (3.0 * matrixEr(1, j)) - (1.5 * matrixEr(2, j)) + - ((1.0 / 3.0) * matrixEr(3, j))) / - gridSizeR; // forward difference - - // drDist = ( -(1.5)*matrixEr(0,j) + (2.0*matrixEr(1,j)) - (0.5*matrixEr(2,j)) ) / gridSizeR; - - dzDist = (-matrixEz(0, j + 2) + 8 * matrixEz(0, j + 1) - 8 * matrixEz(0, j - 1) + matrixEz(0, j - 2)) / - (12.0 * gridSizeZ); // z direction - dPhi = (-matrixEPhiP2(0, j) + 8 * matrixEPhiP(0, j) - 8 * matrixEPhiM(0, j) + matrixEPhiM2(0, j)) / - (12.0 * gridSizePhi); - - matrixCharge(0, j) = -1 * (matrixEr(0, j) / radius + drDist + dPhi / radius + dzDist); - - // index use central difference 3-point center - radius = AliTPCPoissonSolver::fgkIFCRadius + gridSizeR; - // drDist = (-matrixEr(3,j) +6.0*matrixEr(2,j) - 3.0*matrixEr(1,j) - 2*matrixEr(0,j) ) / (6.0*gridSizeR) ; // forward difference - drDist = (matrixEr(2, j) - matrixEr(0, j)) / (2.0 * gridSizeR); - - dzDist = (-matrixEz(1, j + 2) + 8 * matrixEz(1, j + 1) - 8 * matrixEz(1, j - 1) + matrixEz(1, j - 2)) / - (12 * gridSizeZ); // z direction - dPhi = (-matrixEPhiP2(1, j) + 8 * matrixEPhiP(1, j) - 8 * matrixEPhiM(1, j) + matrixEPhiM2(1, j)) / - (12 * gridSizePhi); - matrixCharge(1, j) = -1 * (matrixEr(1, j) / radius + drDist + dPhi / radius + dzDist); - - // index use central difference 3-point center - radius = AliTPCPoissonSolver::fgkIFCRadius + (nRRow - 2) * gridSizeR; - // drDist = (2.0 * matrixEr(nRRow - 1,j) + 3.0*matrixEr(nRRow - 2,j) - 6.0*matrixEr(nRRow -3,j) + matrixEr(nRRow-4,j) ) / (6.0*gridSizeR) ; - drDist = (matrixEr(nRRow - 1, j) - matrixEr(nRRow - 3, j)) / (2.0 * gridSizeR); - - dzDist = (-matrixEz(nRRow - 2, j + 2) + 8 * matrixEz(nRRow - 2, j + 1) - 8 * matrixEz(nRRow - 2, j - 1) + - matrixEz(nRRow - 2, j - 2)) / - (12 * gridSizeZ); - dPhi = (-matrixEPhiP2(nRRow - 2, j) + 8 * matrixEPhiP(nRRow - 2, j) - 8 * matrixEPhiM(nRRow - 2, j) + - matrixEPhiM2(nRRow - 2, j)) / - (12.0 * gridSizePhi); - matrixCharge(nRRow - 2, j) = -1 * (matrixEr(nRRow - 2, j) / radius + drDist + dPhi / radius + dzDist); - - // index r[nRRow -1] backward difference - radius = AliTPCPoissonSolver::fgkIFCRadius + (nRRow - 1) * gridSizeR; - //drDist = ( 1.5*matrixEr(nRRow-1,j) - 2.0*matrixEr(nRRow-2,j) + 0.5*matrixEr(nRRow-3,j) ) / gridSizeR ; // backward difference - drDist = - (-(11.0 / 6.0) * matrixEr(nRRow - 1, j) + (3.0 * matrixEr(nRRow - 2, j)) - - (1.5 * matrixEr(nRRow - 3, j)) + - ((1.0 / 3.0) * matrixEr(nRRow - 4, j))) / - (-1 * gridSizeR); - - //dzDist = ( matrixEz(nRRow-1,j+1) - matrixEz(nRRow-1,j-1) ) / (2*gridSizeZ) ; // z direction - dzDist = (-matrixEz(nRRow - 1, j + 2) + 8 * matrixEz(nRRow - 1, j + 1) - 8 * matrixEz(nRRow - 1, j - 1) + - matrixEz(nRRow - 1, j - 2)) / - (12 * gridSizeZ); - - dPhi = (-matrixEPhiP2(nRRow - 1, j) + 8 * matrixEPhiP(nRRow - 1, j) - 8 * matrixEPhiM(nRRow - 1, j) + - matrixEPhiM2(nRRow - 1, j)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 1, j) = -1 * (matrixEr(nRRow - 1, j) / radius + drDist + dPhi / radius + dzDist); - } - - // boundary z - for (Int_t i = 2; i < nRRow - 2; i++) { - // z[0] - radius = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - dzDist = (-(11.0 / 6.0) * matrixEz(i, 0) + (3.0 * matrixEz(i, 1)) - (1.5 * matrixEz(i, 2)) + - ((1.0 / 3.0) * matrixEz(i, 3))) / - (1 * gridSizeZ); // forward difference - drDist = (-matrixEr(i + 2, 0) + 8 * matrixEr(i + 1, 0) - 8 * matrixEr(i - 1, 0) + matrixEr(i - 2, 0)) / - (12 * gridSizeR); // z direction - dPhi = (-matrixEPhiP2(i, 0) + 8 * matrixEPhiP(i, 0) - 8 * matrixEPhiM(i, 0) + matrixEPhiM2(i, 0)) / - (12 * gridSizePhi); - matrixCharge(i, 0) = -1 * (matrixEr(i, 0) / radius + drDist + dPhi / radius + dzDist); - - dzDist = (matrixEz(i, 2) - matrixEz(i, 0)) / (2.0 * gridSizeZ); // forward difference - - drDist = (-matrixEr(i + 2, 1) + 8 * matrixEr(i + 1, 1) - 8 * matrixEr(i - 1, 1) + matrixEr(i - 2, 1)) / - (12 * gridSizeR); // z direction - dPhi = (-matrixEPhiP2(i, 1) + 8 * matrixEPhiP(i, 1) - 8 * matrixEPhiM(i, 1) + matrixEPhiM2(i, 1)) / - (12 * gridSizePhi); - matrixCharge(i, 1) = -1 * (matrixEr(i, 1) / radius + drDist + dPhi / radius + dzDist); - - dzDist = (matrixEz(i, nZColumn - 1) - matrixEz(i, nZColumn - 3)) / (2.0 * gridSizeZ); // forward difference - - drDist = (-matrixEr(i + 2, nZColumn - 2) + 8 * matrixEr(i + 1, nZColumn - 2) - - 8 * matrixEr(i - 1, nZColumn - 2) + - matrixEr(i - 2, nZColumn - 2)) / - (12 * gridSizeR); // z direction - dPhi = (-matrixEPhiP2(i, nZColumn - 2) + 8 * matrixEPhiP(i, nZColumn - 2) - - 8 * matrixEPhiM(i, nZColumn - 2) + - matrixEPhiM2(i, nZColumn - 2)) / - (12 * gridSizePhi); - matrixCharge(i, nZColumn - 2) = -1 * (matrixEr(i, nZColumn - 2) / radius + drDist + dPhi / radius + dzDist); - - dzDist = (-(11.0 / 6.0) * matrixEz(i, nZColumn - 1) + (3.0 * matrixEz(i, nZColumn - 2)) - - (1.5 * matrixEz(i, nZColumn - 3)) + ((1.0 / 3.0) * matrixEz(i, nZColumn - 4))) / - (-gridSizeZ); // backward difference - drDist = (-matrixEr(i + 2, nZColumn - 1) + 8 * matrixEr(i + 1, nZColumn - 1) - - 8 * matrixEr(i - 1, nZColumn - 1) + - matrixEr(i - 2, nZColumn - 1)) / - (12 * gridSizeR); // z direction - dPhi = (-matrixEPhiP2(i, nZColumn - 1) + 8 * matrixEPhiP(i, nZColumn - 1) - - 8 * matrixEPhiM(i, nZColumn - 1) + - matrixEPhiM2(i, nZColumn - 1)) / - (12 * gridSizePhi); - matrixCharge(i, nZColumn - 1) = -1 * (matrixEr(i, nZColumn - 1) / radius + drDist + dPhi / radius + dzDist); - } - // for corner points - // corner points for EPhi - radius = AliTPCPoissonSolver::fgkIFCRadius; - drDist = - (-0.5 * matrixEr(2, 0) + 2.0 * matrixEr(1, 0) - 1.5 * matrixEr(0, 0)) / gridSizeR; // forward difference - dzDist = - (-0.5 * matrixEz(0, 2) + 2.0 * matrixEz(0, 1) - 1.5 * matrixEz(0, 0)) / gridSizeZ; // forward difference - dPhi = (-matrixEPhiP2(0, 0) + 8 * matrixEPhiP(0, 0) - 8 * matrixEPhiM(0, 0) + matrixEPhiM2(0, 0)) / - (12 * gridSizePhi); - matrixCharge(0, 0) = -1 * (matrixEr(0, 0) / radius + drDist + dPhi / radius + dzDist); - drDist = - (-0.5 * matrixEr(2, 1) + 2.0 * matrixEr(1, 1) - 1.5 * matrixEr(0, 1)) / gridSizeR; // forward difference - dzDist = (matrixEz(0, 2) - matrixEz(0, 0)) / (2.0 * gridSizeZ); // forward difference - dPhi = (-matrixEPhiP2(0, 1) + 8 * matrixEPhiP(0, 1) - 8 * matrixEPhiM(0, 1) + matrixEPhiM2(0, 1)) / - (12 * gridSizePhi); - matrixCharge(0, 1) = -1 * (matrixEr(0, 1) / radius + drDist + dPhi / radius + dzDist); - drDist = - (-0.5 * matrixEr(2, nZColumn - 2) + 2.0 * matrixEr(1, nZColumn - 2) - 1.5 * matrixEr(0, nZColumn - 2)) / - gridSizeR; // forward difference - dzDist = (2.0 * matrixEz(0, nZColumn - 1) + 3.0 * matrixEz(0, nZColumn - 2) - 6.0 * matrixEz(0, nZColumn - 3) + - matrixEz(0, nZColumn - 4)) / - (6.0 * gridSizeZ); // backward difference - dPhi = (-matrixEPhiP2(0, nZColumn - 2) + 8 * matrixEPhiP(0, nZColumn - 2) - 8 * matrixEPhiM(0, nZColumn - 2) + - matrixEPhiM2(0, nZColumn - 2)) / - (12 * gridSizePhi); - matrixCharge(0, nZColumn - 2) = -1 * (matrixEr(0, nZColumn - 2) / radius + drDist + dPhi / radius + dzDist); - drDist = - (-0.5 * matrixEr(2, nZColumn - 1) + 2.0 * matrixEr(1, nZColumn - 1) - 1.5 * matrixEr(0, nZColumn - 1)) / - gridSizeR; // forward difference - dzDist = (1.5 * matrixEz(0, nZColumn - 1) - 2.0 * matrixEz(0, nZColumn - 2) + 0.5 * matrixEz(0, nZColumn - 3)) / - gridSizeZ; // backward difference - dPhi = (-matrixEPhiP2(0, nZColumn - 1) + 8 * matrixEPhiP(0, nZColumn - 1) - 8 * matrixEPhiM(0, nZColumn - 1) + - matrixEPhiM2(0, nZColumn - 1)) / - (12 * gridSizePhi); - matrixCharge(0, nZColumn - 1) = -1 * (matrixEr(0, nZColumn - 1) / radius + drDist + dPhi / radius + dzDist); - - radius = AliTPCPoissonSolver::fgkIFCRadius + gridSizeR; - drDist = (-matrixEr(3, 0) + 6.0 * matrixEr(2, 0) - 3.0 * matrixEr(1, 0) - 2 * matrixEr(0, 0)) / - (6.0 * gridSizeR); // forward difference - dzDist = - (-0.5 * matrixEz(1, 2) + 2.0 * matrixEz(1, 1) - 1.5 * matrixEz(1, 0)) / gridSizeZ; // forward difference - dPhi = (-matrixEPhiP2(1, 0) + 8 * matrixEPhiP(1, 0) - 8 * matrixEPhiM(1, 0) + matrixEPhiM2(1, 0)) / - (12 * gridSizePhi); - matrixCharge(1, 0) = -1 * (matrixEr(1, 0) / radius + drDist + dPhi / radius + dzDist); - drDist = (-matrixEr(3, 1) + 6.0 * matrixEr(2, 1) - 3.0 * matrixEr(1, 1) - 2 * matrixEr(0, 1)) / - (6.0 * gridSizeR); // forward difference - dzDist = (-matrixEz(1, 3) + 6.0 * matrixEz(1, 2) - 3.0 * matrixEz(1, 1) - 2 * matrixEz(1, 0)) / - (6.0 * gridSizeZ); // forward difference - dPhi = (-matrixEPhiP2(1, 1) + 8 * matrixEPhiP(1, 1) - 8 * matrixEPhiM(1, 1) + matrixEPhiM2(1, 1)) / - (12 * gridSizePhi); - matrixCharge(1, 1) = -1 * (matrixEr(1, 1) / radius + drDist + dPhi / radius + dzDist); - drDist = (-matrixEr(3, nZColumn - 2) + 6.0 * matrixEr(2, nZColumn - 2) - 3.0 * matrixEr(1, nZColumn - 2) - - 2 * matrixEr(0, nZColumn - 2)) / - (6.0 * gridSizeR); // forward difference - dzDist = (2.0 * matrixEz(1, nZColumn - 1) + 3.0 * matrixEz(1, nZColumn - 2) - 6.0 * matrixEz(1, nZColumn - 3) + - matrixEz(1, nZColumn - 4)) / - (6.0 * gridSizeZ); // backward difference - dPhi = (-matrixEPhiP2(1, nZColumn - 2) + 8 * matrixEPhiP(1, nZColumn - 2) - 8 * matrixEPhiM(1, nZColumn - 2) + - matrixEPhiM2(1, nZColumn - 2)) / - (12 * gridSizePhi); - matrixCharge(1, nZColumn - 2) = -1 * (matrixEr(1, nZColumn - 2) / radius + drDist + dPhi / radius + dzDist); - - drDist = (-matrixEr(3, nZColumn - 1) + 6.0 * matrixEr(2, nZColumn - 1) - 3.0 * matrixEr(1, nZColumn - 1) - - 2 * matrixEr(0, nZColumn - 1)) / - (6.0 * gridSizeR); // forward difference - dzDist = (1.5 * matrixEz(1, nZColumn - 1) - 2.0 * matrixEz(1, nZColumn - 2) + 0.5 * matrixEz(1, nZColumn - 3)) / - gridSizeZ; // backward difference - dPhi = (-matrixEPhiP2(1, nZColumn - 1) + 8 * matrixEPhiP(1, nZColumn - 1) - 8 * matrixEPhiM(1, nZColumn - 1) + - matrixEPhiM2(1, nZColumn - 1)) / - (12 * gridSizePhi); - matrixCharge(1, nZColumn - 1) = -1 * (matrixEr(1, nZColumn - 1) / radius + drDist + dPhi / radius + dzDist); - - radius = AliTPCPoissonSolver::fgkIFCRadius + (nRRow - 2) * gridSizeR; - drDist = (2.0 * matrixEr(nRRow - 1, 0) + 3.0 * matrixEr(nRRow - 2, 0) - 6.0 * matrixEr(nRRow - 3, 0) + - matrixEr(nRRow - 4, 0)) / - (6.0 * gridSizeR); // backward difference - dzDist = (-0.5 * matrixEz(nRRow - 2, 2) + 2.0 * matrixEz(nRRow - 2, 1) - 1.5 * matrixEz(nRRow - 2, 0)) / - gridSizeZ; // forward difference - dPhi = (-matrixEPhiP2(nRRow - 2, 0) + 8 * matrixEPhiP(nRRow - 2, 0) - 8 * matrixEPhiM(nRRow - 2, 0) + - matrixEPhiM2(nRRow - 2, 0)) / - (12 * gridSizePhi); - - matrixCharge(nRRow - 2, 0) = -1 * (matrixEr(nRRow - 2, 0) / radius + drDist + dPhi / radius + dzDist); - drDist = (2.0 * matrixEr(nRRow - 1, 1) + 3.0 * matrixEr(nRRow - 2, 1) - 6.0 * matrixEr(nRRow - 3, 1) + - matrixEr(nRRow - 4, 1)) / - (6.0 * gridSizeR); // backward difference - dzDist = (-matrixEz(nRRow - 2, 3) + 6.0 * matrixEz(nRRow - 2, 2) - 3.0 * matrixEz(nRRow - 2, 1) - - 2 * matrixEz(nRRow - 2, 0)) / - (6.0 * gridSizeZ); // forward difference - dPhi = (-matrixEPhiP2(nRRow - 2, 1) + 8 * matrixEPhiP(nRRow - 2, 1) - 8 * matrixEPhiM(nRRow - 2, 1) + - matrixEPhiM2(nRRow - 2, 1)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 2, 1) = -1 * (matrixEr(nRRow - 2, 1) / radius + drDist + dPhi / radius + dzDist); - drDist = (2.0 * matrixEr(nRRow - 1, nZColumn - 2) + 3.0 * matrixEr(nRRow - 2, nZColumn - 2) - - 6.0 * matrixEr(nRRow - 3, nZColumn - 2) + matrixEr(nRRow - 4, nZColumn - 2)) / - (6.0 * gridSizeR); // backward difference - dzDist = (2.0 * matrixEz(nRRow - 2, nZColumn - 1) + 3.0 * matrixEz(nRRow - 2, nZColumn - 2) - - 6.0 * matrixEz(nRRow - 2, nZColumn - 3) + matrixEz(nRRow - 2, nZColumn - 4)) / - (6.0 * gridSizeZ); // backward difference - dPhi = (-matrixEPhiP2(nRRow - 2, nZColumn - 2) + 8 * matrixEPhiP(nRRow - 2, nZColumn - 2) - - 8 * matrixEPhiM(nRRow - 2, nZColumn - 2) + matrixEPhiM2(nRRow - 2, nZColumn - 2)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 2, nZColumn - 2) = - -1 * (matrixEr(nRRow - 2, nZColumn - 2) / radius + drDist + dPhi / radius + dzDist); - drDist = (2.0 * matrixEr(nRRow - 1, nZColumn - 1) + 3.0 * matrixEr(nRRow - 2, nZColumn - 1) - - 6.0 * matrixEr(nRRow - 3, nZColumn - 1) + matrixEr(nRRow - 4, nZColumn - 1)) / - (6.0 * gridSizeR); // backward difference - dzDist = (1.5 * matrixEz(0, nZColumn - 1) - 2.0 * matrixEz(0, nZColumn - 2) + 0.5 * matrixEz(0, nZColumn - 3)) / - gridSizeZ; // backward difference - dPhi = (-matrixEPhiP2(nRRow - 2, nZColumn - 1) + 8 * matrixEPhiP(nRRow - 2, nZColumn - 1) - - 8 * matrixEPhiM(nRRow - 2, nZColumn - 1) + matrixEPhiM2(nRRow - 2, nZColumn - 1)) / - (12 * gridSizePhi); - - matrixCharge(nRRow - 2, nZColumn - 1) = - -1 * (matrixEr(nRRow - 2, nZColumn - 1) / radius + drDist + dPhi / radius + dzDist); - radius = AliTPCPoissonSolver::fgkIFCRadius + (nRRow - 1) * gridSizeR; - drDist = (1.5 * matrixEr(nRRow - 1, 0) - 2.0 * matrixEr(nRRow - 2, 0) + 0.5 * matrixEr(nRRow - 3, 0)) / - gridSizeR; // backward difference - dzDist = (-0.5 * matrixEz(nRRow - 1, 2) + 2.0 * matrixEz(nRRow - 1, 1) - 1.5 * matrixEz(nRRow - 1, 0)) / - gridSizeZ; // forward difference - dPhi = (-matrixEPhiP2(nRRow - 1, 0) + 8 * matrixEPhiP(nRRow - 1, 0) - 8 * matrixEPhiM(nRRow - 1, 0) + - matrixEPhiM2(nRRow - 1, 0)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 1, 0) = -1 * (matrixEr(nRRow - 1, 0) / radius + drDist + dPhi / radius + dzDist); - drDist = (1.5 * matrixEr(nRRow - 1, 1) - 2.0 * matrixEr(nRRow - 2, 1) + 0.5 * matrixEr(nRRow - 3, 1)) / - gridSizeR; // backward difference - dzDist = (-matrixEz(nRRow - 1, 3) + 6.0 * matrixEz(nRRow - 1, 2) - 3.0 * matrixEz(nRRow - 1, 1) - - 2 * matrixEz(nRRow - 1, 0)) / - (6.0 * gridSizeZ); // forward difference - dPhi = (-matrixEPhiP2(nRRow - 1, 1) + 8 * matrixEPhiP(nRRow - 1, 1) - 8 * matrixEPhiM(nRRow - 1, 1) + - matrixEPhiM2(nRRow - 1, 1)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 1, 1) = -1 * (matrixEr(nRRow - 1, 1) / radius + drDist + dPhi / radius + dzDist); - - drDist = (1.5 * matrixEr(nRRow - 1, nZColumn - 2) - 2.0 * matrixEr(nRRow - 2, nZColumn - 2) + - 0.5 * matrixEr(nRRow - 3, nZColumn - 2)) / - gridSizeR; // backward difference - dzDist = (2.0 * matrixEz(nRRow - 1, nZColumn - 1) + 3.0 * matrixEz(nRRow - 1, nZColumn - 2) - - 6.0 * matrixEz(nRRow - 1, nZColumn - 3) + matrixEz(nRRow - 1, nZColumn - 4)) / - (6.0 * gridSizeZ); // backward difference - dPhi = (-matrixEPhiP2(nRRow - 1, nZColumn - 2) + 8 * matrixEPhiP(nRRow - 1, nZColumn - 2) - - 8 * matrixEPhiM(nRRow - 1, nZColumn - 2) + matrixEPhiM2(nRRow - 1, nZColumn - 2)) / - (12 * gridSizePhi); - matrixCharge(nRRow - 1, nZColumn - 2) = - -1 * (matrixEr(nRRow - 1, nZColumn - 2) / radius + drDist + dPhi / radius + dzDist); - - drDist = (1.5 * matrixEr(nRRow - 1, nZColumn - 1) - 2.0 * matrixEr(nRRow - 2, nZColumn - 1) + - 0.5 * matrixEr(nRRow - 3, nZColumn - 1)) / - gridSizeR; // backward difference - dzDist = (1.5 * matrixEz(nRRow - 1, nZColumn - 1) - 2.0 * matrixEz(nRRow - 1, nZColumn - 2) + - 0.5 * matrixEz(nRRow - 1, nZColumn - 3)) / - gridSizeZ; // backward difference - - dPhi = (-matrixEPhiP2(nRRow - 1, nZColumn - 1) + 8 * matrixEPhiP(nRRow - 1, nZColumn - 1) - - 8 * matrixEPhiM(nRRow - 1, nZColumn - 1) + matrixEPhiM2(nRRow - 1, nZColumn - 1)) / - (12 * gridSizePhi); - - matrixCharge(nRRow - 1, nZColumn - 1) = - -1 * (matrixEr(nRRow - 1, nZColumn - 1) / radius + drDist + dPhi / radius + dzDist); - } -} -/// -/// \param matricesCharge -/// \param matricesEr -/// \param matricesEPhi -/// \param matricesEz -/// \param matricesInvLocalIntErDz -/// \param matricesInvLocalIntEPhiDz -/// \param matricesInvLocalEz -/// \param matricesDistDrDz -/// \param matricesDistDPhiRDz -/// \param matricesDistDz -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -/// \param nSize -/// \param useCylAC -/// \param stepR -/// \param stepZ -/// \param stepPhi -/// \param interpType -/// \param inverseType -void AliTPCSpaceCharge3DCalc::InverseDistortionMaps( - TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - TMatrixD** matricesInvLocalIntErDz, TMatrixD** matricesInvLocalIntEPhiDz, TMatrixD** matricesInvLocalEz, - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t nSize, - const Bool_t useCylAC, Int_t stepR, Int_t stepZ, Int_t stepPhi, Int_t interpType) -{ - // can inverse after lookup table for global distortion been calculated - Double_t* rList = new Double_t[nRRow]; - Double_t* zList = new Double_t[nZColumn]; - Double_t* phiList = new Double_t[phiSlice]; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = (j * gridSizeZ); - } - // memory allocation - if (fInitLookUp) { - // 1) get local distortion - InverseGlobalToLocalDistortionGlobalInvTable(matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, rList, - zList, phiList, nRRow, nZColumn, phiSlice, nSize, useCylAC, - stepR, stepZ, stepPhi, interpType); - - fLookupInverseDistA->SetLookUpR(matricesDistDrDz); - fLookupInverseDistA->SetLookUpPhi(matricesDistDPhiRDz); - fLookupInverseDistA->SetLookUpZ(matricesDistDz); - fLookupInverseDistA->CopyFromMatricesToInterpolator(); - - // 2) calculate local integral - InverseLocalDistortionToElectricField(matricesEr, matricesEPhi, matricesEz, matricesInvLocalIntErDz, - matricesInvLocalIntEPhiDz, matricesInvLocalEz, - matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, rList, zList, - phiList, nRRow, nZColumn, phiSlice); - // 3) get potential from electric field assuming zero boundaries - InverseElectricFieldToCharge(matricesCharge, matricesEr, matricesEPhi, matricesEz, rList, zList, phiList, nRRow, - nZColumn, phiSlice); - } - - // copy charge inverse here just for side A (TODO: do for side C) - for (Int_t k = 0; k < phiSlice; k++) { - *(fMatrixChargeInverseA[k]) = *(matricesCharge[k]); - } - fInterpolatorInverseChargeA->SetValue(fMatrixChargeInverseA); - fInterpolatorInverseChargeA->InitCubicSpline(); - - delete[] zList; - delete[] rList; - delete[] phiList; -} -/// CalculateEField (New Version: with reorganization of modules) -/// Calculate E field based on look-up table created by Poisson Solver -/// * Differentiate V(r) and solve for E(r) using special equations for the first and last row -/// * Integrate E(r)/E(z) from point of origin to pad plane -/// * Differentiate V(r) and solve for E(phi) -/// * Integrate E(phi)/E(z) from point of origin to pad plane -/// * Differentiate V(r) and solve for E(z) using special equations for the first and last row -/// * Integrate (E(z)-Ez(ROC)) from point of origin to pad plane -/// -/// \param matricesV TMatrixD** 3D matrix representing calculated potential -/// \param matricesErOverEz TMatrix** 3D matrix representing e-field at Er/Ez -/// \param matricesEPhiOverEz TMatrix** 3D matrix representing e-field at EPhi/Ez -/// \param matricesDeltaZ TMatrix** 3D matrix representing e-field at DeltaZ -/// \param nRRow Int_t number of nRRow (in R direction) -/// \param nZColumn Int_t number of nZColumn (in Z direction) -/// \param phiSlice Int_t number of (phi slices in phi direction) -/// \param symmetry Int_t symmetry? -/// \param rocDisplace rocDisplacement -/// -/// \pre Matrix matricesV is assumed had been calculated by Poisson solver -/// \post Results of Integration and Derivations for E-field calculation are stored in matricesErOverEz, matricesEPhiOverEz, matricesDeltaZ -/// -void AliTPCSpaceCharge3DCalc::CalculateEField( - TMatrixD** matricesV, TMatrixD** matricesErOverEz, TMatrixD** matricesEPhiOverEz, - TMatrixD** matricesDeltaEz, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Int_t symmetry, Bool_t rocDisplacement) -{ - - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - TMatrixD *matricesEr[phiSlice], *matricesEz[phiSlice], *matricesEPhi[phiSlice]; - - //Allocate memory for electric field r,z, phi direction - for (Int_t k = 0; k < phiSlice; k++) { - matricesEr[k] = new TMatrixD(nRRow, nZColumn); - matricesEz[k] = new TMatrixD(nRRow, nZColumn); - matricesEPhi[k] = new TMatrixD(nRRow, nZColumn); - } - - //Differentiate V(r) and solve for E(r) using special equations for the first and last row - TStopwatch w; - w.Start(); - - ElectricField(matricesV, matricesEr, matricesEPhi, matricesEz, nRRow, nZColumn, - phiSlice, gridSizeR, gridSizePhi, gridSizeZ, symmetry, AliTPCPoissonSolver::fgkIFCRadius); - - w.Stop(); - Info("AliTPCSpaceCharge3DCalc::InitSpaceCharge3DPoissonIntegralDz", "%s", Form("Time for calculation E-field CPU = %f s\n", w.CpuTime())); - - //Integrate E(r)/E(z) from point of origin to pad plane - - IntegrateEz(matricesErOverEz, matricesEr, nRRow, nZColumn, phiSlice, ezField); - IntegrateEz(matricesEPhiOverEz, matricesEPhi, nRRow, nZColumn, phiSlice, ezField); - IntegrateEz(matricesDeltaEz, matricesEz, nRRow, nZColumn, phiSlice, -1.0); - - // calculate z distortion from the integrated Delta Ez residuals - // and include the equivalence (Volt to cm) of the ROC shift !! - for (Int_t m = 0; m < phiSlice; m++) { - TMatrixD& arrayV = *matricesV[m]; - TMatrixD& deltaEz = *matricesDeltaEz[m]; - - for (Int_t j = 0; j < nZColumn; j++) { - for (Int_t i = 0; i < nRRow; i++) { - // Scale the Ez distortions with the drift velocity -> delivers cm - deltaEz(i, j) = deltaEz(i, j) * AliTPCPoissonSolver::fgkdvdE; - // ROC Potential in cm equivalent - Double_t dzROCShift = arrayV(i, nZColumn - 1) / ezField; - if (rocDisplacement) { - deltaEz(i, j) = deltaEz(i, j) + dzROCShift; // add the ROC mis alignment - } - } - } - } - // clear the temporary arrays lists - - for (Int_t k = 0; k < phiSlice; k++) { - delete matricesEr[k]; - delete matricesEz[k]; - delete matricesEPhi[k]; - } -} -/// -/// Integrate at z direction Ez for electron drift calculation -/// -/// -/// \param matricesExOverEz TMatrixD** 3D matrix representing ExOverEz -/// \param matricesEx TMatrix** 3D matrix representing e-field at x direction -/// \param nRRow const Int_t number of nRRow (in R direction) -/// \param nZColumn const Int_t number of nZColumn (in Z direction) -/// \param phiSlice const Int_t number of (phiSlice in phi direction) -/// \param ezField const Double_t Electric field in z direction -/// -/// \pre matricesEx is assumed already been calculated by ElectricFieldCalculation -/// \post Matrix matricesExOverEz is calculated by integration of matricesEx -/// -void AliTPCSpaceCharge3DCalc::IntegrateEz( - TMatrixD** matricesExOverEz, TMatrixD** matricesEx, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Double_t ezField) -{ - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - for (Int_t m = 0; m < phiSlice; m++) { - TMatrixD& eXoverEz = *matricesExOverEz[m]; - TMatrixD& arrayEx = *matricesEx[m]; - - for (Int_t j = nZColumn - 1; j >= 0; j--) { - for (Int_t i = 0; i < nRRow; i++) { - - /// Calculate integration from int^{0}_{j} (TODO: Split the integration) - if (j < nZColumn - 3) { - eXoverEz(i, j) = eXoverEz(i, j + 2) + - (gridSizeZ / 3.0) * (arrayEx(i, j) + 4 * arrayEx(i, j + 1) + arrayEx(i, j + 2)) / - (-1 * ezField); - } else { - if (j == nZColumn - 3) { - eXoverEz(i, j) = (gridSizeZ / 3.0) * (arrayEx(i, nZColumn - 3) + 4 * arrayEx(i, nZColumn - 2) + arrayEx(i, nZColumn - 1)) / (-1 * ezField); - } - if (j == nZColumn - 2) { - eXoverEz(i, j) = - (gridSizeZ / 3.0) * (1.5 * arrayEx(i, nZColumn - 2) + 1.5 * arrayEx(i, nZColumn - 1)) / - (-1 * ezField); - } - if (j == nZColumn - 1) { - eXoverEz(i, j) = 0.0; - } - } - } - } - } -} -/// GetCorrection from no-drift -/// -/// \param x Float_t point origin -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetCorrectionCylNoDrift(const Float_t x[], const Short_t roc, Float_t dx[]) -{ - /// Calculates the correction due the Space Charge effect within the TPC drift volume - - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::", "Lookup table was not initialized! Performing the initialization now ..."); - // InitSpaceCharge3DDistortion(); - return; - } - - Float_t intEr, intEPhi, intDEz; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi -= TMath::TwoPi(); - } - - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (sign == -1 && z < 0.0) { - printf("call C side\n"); - fLookupIntENoDriftC->GetValue(r, phi, z, intEr, intEPhi, intDEz); - } else { - fLookupIntENoDriftA->GetValue(r, phi, z, intEr, intEPhi, intDEz); - } - - // Calculate distorted position - if (r > 0.0) { - phi = phi + fCorrectionFactor * (fC0 * intEPhi - fC1 * intEr) / r; - r = r + fCorrectionFactor * (fC0 * intEr + fC1 * intEPhi); - } - Double_t dzDist = intDEz * fCorrectionFactor * AliTPCPoissonSolver::fgkdvdE; - - // Calculate correction in cartesian coordinates - dx[0] = -(r - x[0]); - dx[1] = -(phi - x[1]); - dx[2] = -dzDist; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetDistortionCylNoDrift(const Float_t x[], Short_t roc, Float_t dx[]) -{ - /// This function delivers the distortion values dx in respect to the initial coordinates x - /// roc represents the TPC read out chamber (offline numbering convention) - - GetCorrectionCylNoDrift(x, roc, dx); - for (Int_t j = 0; j < 3; ++j) { - dx[j] = -dx[j]; - } -} -/// inverse for no drift -/// inverse from global distortion to local distortion -/// -/// \param matricesDistDrDz -/// \param matricesDistDPhiRDz -/// \param matricesDistDz -/// \param rList -/// \param zList -/// \param phiList -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -void AliTPCSpaceCharge3DCalc::InverseGlobalToLocalDistortionNoDrift( - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, - Double_t* rList, Double_t* zList, Double_t* phiList, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice) -{ - - Double_t z, phi, r, zAfter, zPrevious, ddR, ddRPhi, ddZ, drDist, dRPhi, dzDist; - Float_t x[3], dx[3], pdx[3], dxp1[3], dxp2[3]; - Int_t roc; - TMatrixD* distDrDz; - TMatrixD* distDPhiRDz; - TMatrixD* distDz; - - for (Int_t k = 0; k < phiSlice; k++) { - distDrDz = matricesDistDrDz[k]; - distDPhiRDz = matricesDistDPhiRDz[k]; - distDz = matricesDistDz[k]; - for (Int_t i = 0; i < nRRow; i++) { - (*distDrDz)(i, nZColumn - 1) = 0.0; - (*distDPhiRDz)(i, nZColumn - 1) = 0.0; - (*distDz)(i, nZColumn - 1) = 0.0; - } - } - - for (Int_t j = nZColumn - 2; j >= 0; j--) { - roc = 0; // FIXME - for (Int_t k = 0; k < phiSlice; k++) { - - distDrDz = matricesDistDrDz[k]; - distDPhiRDz = matricesDistDPhiRDz[k]; - distDz = matricesDistDz[k]; - for (Int_t i = 0; i < nRRow; i++) { - // get global distortion - - r = rList[i]; - phi = phiList[k]; - z = zList[j]; - zPrevious = zList[j + 1]; - //zAfter = zList[j-1]; - - (*distDrDz)(i, j) = 0.0; - (*distDPhiRDz)(i, j) = 0.0; - (*distDz)(i, j) = 0.0; - drDist = 0.0; - dRPhi = 0.0; - dzDist = 0.0; - - r = rList[i]; - phi = phiList[k]; - z = zList[j]; - - x[0] = r; - x[1] = phi; - x[2] = z; - - GetDistortionCylNoDrift(x, roc, dx); - - //x[0] = x[0] + drDist; - //x[1] = x[1] + dRPhi/r; - x[2] = zPrevious; - - GetDistortionCylNoDrift(x, roc, pdx); - - (*distDrDz)(i, j) = (dx[0] - pdx[0]); - (*distDPhiRDz)(i, j) = (dx[1] - pdx[1]) * r; - (*distDz)(i, j) = (dx[2] - pdx[2]); - } - } - } -} -/// -/// \param matricesCharge -/// \param matricesEr -/// \param matricesEPhi -/// \param matricesEz -/// \param matricesInvLocalIntErDz -/// \param matricesInvLocalIntEPhiDz -/// \param matricesInvLocalEz -/// \param matricesDistDrDz -/// \param matricesDistDPhiRDz -/// \param matricesDistDz -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -void AliTPCSpaceCharge3DCalc::InverseDistortionMapsNoDrift( - TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - TMatrixD** matricesInvLocalIntErDz, TMatrixD** matricesInvLocalIntEPhiDz, TMatrixD** matricesInvLocalEz, - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice) -{ - // can inverse after lookup table for global distortion been calculated - Double_t* rList = new Double_t[nRRow]; - Double_t* zList = new Double_t[nZColumn]; - Double_t* phiList = new Double_t[phiSlice]; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = (j * gridSizeZ); - } - // memory allocation - if (fInitLookUp) { - // 1) get local distortion - InverseGlobalToLocalDistortionNoDrift(matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, rList, zList, - phiList, nRRow, nZColumn, phiSlice); - // 2) calculate local integral - InverseLocalDistortionToElectricField(matricesEr, matricesEPhi, matricesEz, matricesInvLocalIntErDz, - matricesInvLocalIntEPhiDz, matricesInvLocalEz, - matricesDistDrDz, matricesDistDPhiRDz, matricesDistDz, rList, zList, - phiList, nRRow, nZColumn, phiSlice); - // 3) get potential from electric field assuming zero boundaries - InverseElectricFieldToCharge(matricesCharge, matricesEr, matricesEPhi, matricesEz, rList, zList, phiList, nRRow, - nZColumn, phiSlice); - } - delete[] zList; - delete[] rList; - delete[] phiList; -} -/// -/// \param matricesChargeA -/// \param matricesChargeC -/// \param spaceChargeHistogram3D -/// \param nRRow -/// \param nZColumn -/// \param phiSlice -void AliTPCSpaceCharge3DCalc::GetChargeDensity( - TMatrixD** matricesChargeA, TMatrixD** matricesChargeC, const TH3* spaceChargeHistogram3D, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice) -{ - Int_t phiSlicesPerSector = phiSlice / kNumSector; - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (nRRow - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (nZColumn - 1); - const Float_t gridSizePhi = TMath::TwoPi() / phiSlice; - const Double_t ezField = (AliTPCPoissonSolver::fgkCathodeV - AliTPCPoissonSolver::fgkGG) / AliTPCPoissonSolver::fgkTPCZ0; // = ALICE Electric Field (V/cm) Magnitude ~ -400 V/cm; - // local variables - Float_t radius0, phi0, z0; - // list of point as used in the poisson relaxation and the interpolation (for interpolation) - Double_t rList[nRRow], zList[nZColumn], phiList[phiSlice]; - for (Int_t k = 0; k < phiSlice; k++) { - phiList[k] = gridSizePhi * k; - } - for (Int_t i = 0; i < nRRow; i++) { - rList[i] = AliTPCPoissonSolver::fgkIFCRadius + i * gridSizeR; - } - for (Int_t j = 0; j < nZColumn; j++) { - zList[j] = j * gridSizeZ; - } - - TMatrixD* mCharge; - for (Int_t side = 0; side < 2; side++) { - for (Int_t k = 0; k < phiSlice; k++) { - if (side == 0) { - mCharge = matricesChargeA[k]; - } else { - mCharge = matricesChargeC[k]; - } - - phi0 = phiList[k]; - for (Int_t i = 0; i < nRRow; i++) { - radius0 = rList[i]; - for (Int_t j = 0; j < nZColumn; j++) { - z0 = zList[j]; - if (side == 1) { - z0 = -TMath::Abs(zList[j]); - } - if (spaceChargeHistogram3D != nullptr) { - (*mCharge)(i, j) = InterpolatePhi(spaceChargeHistogram3D, phi0, radius0, z0); - //InterpolatePhi(spaceChargeHistogram3D,phi0,radius0,z0); - } - } - } - } - } -} -/// -/// \param x -/// \param roc -/// \return -Double_t AliTPCSpaceCharge3DCalc::GetChargeCylAC(const Float_t x[], Short_t roc) const -{ - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - return fInterpolatorChargeA->GetValue(r, phi, z); - } else { - return fInterpolatorChargeC->GetValue(r, phi, -z); - } -} -/// -/// \param x -/// \param roc -/// \return -Double_t AliTPCSpaceCharge3DCalc::GetPotentialCylAC(const Float_t x[], Short_t roc) const -{ - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - return fInterpolatorPotentialA->GetValue(r, phi, z); - } else { - return fInterpolatorPotentialC->GetValue(r, phi, -z); - } -} -/// chargeInverse -/// -/// \param x -/// \param roc -/// \return -Double_t AliTPCSpaceCharge3DCalc::GetInverseChargeCylAC(const Float_t x[], Short_t roc) const -{ - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < 0) || (sign == -1 && z > 0)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-6) { - return fInterpolatorInverseChargeA->GetValue(r, phi, z); - } else { - return fInterpolatorInverseChargeC->GetValue(r, phi, z); - } -} - -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetLocalDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]) -{ - Float_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupDistA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupDistC->GetValue(r, phi, -z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} - -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetLocalCorrectionCyl(const Float_t x[], Short_t roc, Float_t dx[]) -{ - Float_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupCorrA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupCorrC->GetValue(r, phi, -z, dR, dRPhi, dZ); - dZ = -1 * dZ; - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} - -/// Get Electric field from look up table -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetElectricFieldCyl(const Float_t x[], Short_t roc, Double_t dx[]) -{ - Double_t eR, ePhi, eZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupElectricFieldA->GetValue(r, phi, z, eR, ePhi, eZ); - } else { - fLookupElectricFieldC->GetValue(r, phi, -z, eR, ePhi, eZ); - eZ = -1 * eZ; - } - - dx[0] = eR; - dx[1] = ePhi; - dx[2] = eZ; -} - -/// -/// \param x -/// \param roc -/// \param dx -void AliTPCSpaceCharge3DCalc::GetInverseLocalDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]) -{ - if (!fInitLookUp) { - Info("AliTPCSpaceCharge3DCalc::", "Lookup table was not initialized! Performing the initialization now ..."); - InitSpaceCharge3DPoissonIntegralDz(129, 129, 144, 100, 1e-8); - } - - Float_t dR, dRPhi, dZ; - Double_t r, phi, z; - Int_t sign; - - r = x[0]; - phi = x[1]; - if (phi < 0) { - phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - if (phi > TMath::TwoPi()) { - phi = phi - TMath::TwoPi(); // Table uses phi from 0 to 2*Pi - } - z = x[2]; // Create temporary copy of x[2] - - if ((roc % 36) < 18) { - sign = 1; // (TPC A side) - } else { - sign = -1; // (TPC C side) - } - - if (sign == 1 && z < AliTPCPoissonSolver::fgkZOffSet) { - z = AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if (sign == -1 && z > -AliTPCPoissonSolver::fgkZOffSet) { - z = -AliTPCPoissonSolver::fgkZOffSet; // Protect against discontinuity at CE - } - if ((sign == 1 && z < -1e-16) || (sign == -1 && z > -1e-16)) { // just a consistency check - Error("AliTPCSpaceCharge3DCalc::", "ROC number does not correspond to z coordinate! Calculation of distortions is most likely wrong!"); - } - - if (z > -1e-16) { - fLookupInverseDistA->GetValue(r, phi, z, dR, dRPhi, dZ); - } else { - fLookupInverseDistC->GetValue(r, phi, -z, dR, dRPhi, dZ); - } - - dx[0] = fCorrectionFactor * dR; - dx[1] = fCorrectionFactor * dRPhi; - dx[2] = fCorrectionFactor * - dZ; // z distortion - (scaled with drift velocity dependency on the Ez field and the overall scaling factor) -} -/// Function for setting Potential Boundary Values and Charge distribution input TFormula -/// -/// \param vTestFunction -/// \param rhoTestFunction -/// -void AliTPCSpaceCharge3DCalc::SetPotentialBoundaryAndChargeFormula(TFormula* vTestFunction, TFormula* rhoTestFunction) -{ - /**** allocate memory for charge ***/ - // we allocate pointer to TMatrixD array to picture 3D (slices), this representation should be revised - // since it is easier for GPU implementation to run for 1D memory - const Float_t gridSizeR = (AliTPCPoissonSolver::fgkOFCRadius - AliTPCPoissonSolver::fgkIFCRadius) / (fNRRows - 1); - const Float_t gridSizeZ = AliTPCPoissonSolver::fgkTPCZ0 / (fNZColumns - 1); - const Float_t gridSizePhi = TMath::TwoPi() / fNPhiSlices; - - fFormulaPotentialV = vTestFunction; - fFormulaChargeRho = rhoTestFunction; - - // grid size for one side - TMatrixD* chargeA; - TMatrixD* chargeC; - Double_t radius0, z0, phi0, z0neg; - Int_t indexB = 0; - for (Int_t k = 0; k < fNPhiSlices; k++) { - chargeA = fMatrixChargeA[k]; - chargeC = fMatrixChargeC[k]; - - phi0 = k * gridSizePhi; - - /// Fill the non-boundary values - for (Int_t i = 0; i < fNRRows; i++) { - radius0 = AliTPCPoissonSolver::fgkIFCRadius + (i * gridSizeR); - for (Int_t j = 0; j < fNZColumns; j++) { - z0 = j * gridSizeZ; - z0neg = -z0; - - (*chargeA)(i, j) = -1.0 * rhoTestFunction->Eval(radius0, phi0, z0); - (*chargeC)(i, j) = -1.0 * rhoTestFunction->Eval(radius0, phi0, z0neg); - - /// TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // if ((i == 0) || (i == fNRRows - 1) || (j == 0) || (j == fNZColumns - 1)) { - // fListPotentialBoundaryA[indexB] = vTestFunction->Eval(radius0, phi0, z0); - // fListPotentialBoundaryC[indexB] = vTestFunction->Eval(radius0, phi0, z0neg); - // indexB++; - // } - - } // end j - } // end i - } // end phi - - fInterpolatorChargeA->SetValue(fMatrixChargeA); - fInterpolatorChargeA->InitCubicSpline(); - fInterpolatorChargeC->SetValue(fMatrixChargeC); - fInterpolatorChargeC->InitCubicSpline(); -} - -/// Set interpolation -void AliTPCSpaceCharge3DCalc::SetInterpolationOrder(Int_t order) -{ - fInterpolationOrder = order; - - fInterpolatorChargeA->SetOrder(fInterpolationOrder); - fInterpolatorChargeC->SetOrder(fInterpolationOrder); - fInterpolatorPotentialA->SetOrder(fInterpolationOrder); - fInterpolatorPotentialC->SetOrder(fInterpolationOrder); - fInterpolatorInverseChargeA->SetOrder(fInterpolationOrder); - fInterpolatorInverseChargeC->SetOrder(fInterpolationOrder); - - fLookupDistA->SetOrder(fInterpolationOrder); - - fLookupDistC->SetOrder(fInterpolationOrder); - - fLookupInverseDistA->SetOrder(fInterpolationOrder); - - fLookupInverseDistC->SetOrder(fInterpolationOrder); - - fLookupElectricFieldA->SetOrder(fInterpolationOrder); - fLookupElectricFieldC->SetOrder(fInterpolationOrder); - fLookupIntDistA->SetOrder(fInterpolationOrder); - fLookupIntDistC->SetOrder(fInterpolationOrder); - fLookupIntCorrA->SetOrder(fInterpolationOrder); - fLookupIntCorrC->SetOrder(fInterpolationOrder); - fLookupIntENoDriftA->SetOrder(fInterpolationOrder); - fLookupIntENoDriftC->SetOrder(fInterpolationOrder); - fLookupIntCorrIrregularA->SetOrder(fInterpolationOrder); - - fLookupIntCorrIrregularC->SetOrder(fInterpolationOrder); -} - -void AliTPCSpaceCharge3DCalc::SetDistortionLookupTables(TMatrixD** matrixIntDistDrA, TMatrixD** matrixIntDistDrphiA, TMatrixD** matrixIntDistDzA, TMatrixD** matrixIntDistDrC, TMatrixD** matrixIntDistDrphiC, TMatrixD** matrixIntDistDzC) -{ - fMatrixIntDistDrEzA = matrixIntDistDrA; - fMatrixIntDistDPhiREzA = matrixIntDistDrphiA; - fMatrixIntDistDzA = matrixIntDistDzA; - fLookupIntDistA->SetLookUpR(fMatrixIntDistDrEzA); - fLookupIntDistA->SetLookUpPhi(fMatrixIntDistDPhiREzA); - fLookupIntDistA->SetLookUpZ(fMatrixIntDistDzA); - fLookupIntDistA->CopyFromMatricesToInterpolator(); - - fMatrixIntDistDrEzC = matrixIntDistDrC; - fMatrixIntDistDPhiREzC = matrixIntDistDrphiC; - fMatrixIntDistDzC = matrixIntDistDzC; - fLookupIntDistC->SetLookUpR(fMatrixIntDistDrEzC); - fLookupIntDistC->SetLookUpPhi(fMatrixIntDistDPhiREzC); - fLookupIntDistC->SetLookUpZ(fMatrixIntDistDzC); - fLookupIntDistC->CopyFromMatricesToInterpolator(); - - fInitLookUp = kTRUE; -} \ No newline at end of file diff --git a/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.h b/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.h deleted file mode 100644 index bf686deff2b0f..0000000000000 --- a/GPU/TPCSpaceChargeBase/AliTPCSpaceCharge3DCalc.h +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file AliTPCSpaceCharge3DCalc.h -/// \brief This class provides distortion and correction map calculation with integration following electron drift -/// TODO: validate distortion z by comparing with exisiting classes -/// -/// \author Rifki Sadikin <rifki.sadikin@cern.ch>, Indonesian Institute of Sciences -/// \date Nov 20, 2017 - -#ifndef ALI_TPC_SPACECHARGE3D_CALC_H -#define ALI_TPC_SPACECHARGE3D_CALC_H - -#include "TF1.h" -#include "TF2.h" -#include "TH3F.h" -#include "TMatrixD.h" - -#include "AliTPCPoissonSolver.h" -#include "AliTPCLookUpTable3DInterpolatorD.h" -#include "AliTPC3DCylindricalInterpolator.h" -#include "AliTPCLookUpTable3DInterpolatorIrregularD.h" -#include "AliTPC3DCylindricalInterpolatorIrregular.h" - -class TFormula; - -class AliTPCSpaceCharge3DCalc -{ - public: - AliTPCSpaceCharge3DCalc(); - AliTPCSpaceCharge3DCalc(Int_t nRRow, Int_t nZColumn, Int_t nPhiSlice); - AliTPCSpaceCharge3DCalc(Int_t nRRow, Int_t nZColumn, Int_t nPhiSlice, - Int_t interpolationOrder, Int_t irregularGridSize, Int_t rbfKernelType); - ~AliTPCSpaceCharge3DCalc(); - void InitSpaceCharge3DPoissonIntegralDz(Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, - Double_t stopConvergence); - - // outdated, to be removed after modifications in aliroot are pushed - void InitSpaceCharge3DPoissonIntegralDz( - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stopConvergence, - TMatrixD** matricesErA, TMatrixD** matricesEphiA, TMatrixD** matricesEzA, - TMatrixD** matricesErC, TMatrixD** matricesEphiC, TMatrixD** matricesEzC, - TMatrixD** matricesDistDrDzA, TMatrixD** matricesDistDPhiRDzA, TMatrixD** matricesDistDzA, - TMatrixD** matricesCorrDrDzA, TMatrixD** matricesCorrDPhiRDzA, TMatrixD** matricesCorrDzA, - TMatrixD** matricesDistDrDzC, TMatrixD** matricesDistDPhiRDzC, TMatrixD** matricesDistDzC, - TMatrixD** matricesCorrDrDzC, TMatrixD** matricesCorrDPhiRDzC, TMatrixD** matricesCorrDzC, - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction); - - void InitSpaceCharge3DPoissonIntegralDz( - Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stopConvergence, - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction); - - void - InitSpaceCharge3DPoisson(Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, Double_t stopConvergence); - void ForceInitSpaceCharge3DPoissonIntegralDz(Int_t nRRow, Int_t nZColumn, Int_t phiSlice, Int_t maxIteration, - Double_t stopConvergence); - void GetDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetDistortionCylAC(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetCorrectionCyl(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetCorrectionCylAC(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetCorrectionCylACIrregular(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetCorrectionCylACIrregular(const Float_t x[], Short_t roc, Float_t dx[], const Int_t side) const; - void GetDistortion(const Float_t x[], Short_t roc, Float_t dx[]) const; - - void GetCorrection(const Float_t x[], Short_t roc, Float_t dx[]) const; - void GetCorrection(const Float_t x[], Short_t roc, Float_t dx[], const Int_t side) const; - - Double_t GetChargeCylAC(const Float_t x[], Short_t roc) const; - Double_t GetPotentialCylAC(const Float_t x[], Short_t roc) const; - - Double_t GetInverseChargeCylAC(const Float_t x[], Short_t roc) const; - - void SetCorrectionType(Int_t correctionType) { fCorrectionType = correctionType; } - - enum { - kNumSector = 18 - }; - - enum CorrectionType { - kRegularInterpolator = 0, ///< use interpolation with regular interpolator for correction look up table - kIrregularInterpolator = 1, ///< use irregular interpolator for correction look up table - }; - - enum IntegrationStrategy { - kNaive = 0, ///< use interpolation with regular interpolator for correction look up table - kOpt = 1, ///< use irregular interpolator for correction look up table - }; - void SetInputSpaceCharge(TH3* hisSpaceCharge3D, Double_t norm); - void SetInputSpaceCharge(TH3* hisSpaceCharge3D) { SetInputSpaceCharge(hisSpaceCharge3D, 1); } - void SetInputSpaceCharge(TH3* hisSpaceCharge3D, Double_t norm, Int_t side); - void SetInputSpaceCharge(TH3* hisSpaceCharge3D, Int_t side) { SetInputSpaceCharge(hisSpaceCharge3D, 1, side); } - - void SetInputSpaceChargeA(TMatrixD** matricesLookUpCharge) - { - fInterpolatorChargeA->SetValue(matricesLookUpCharge); - fInterpolatorChargeA->InitCubicSpline(); - } - - void SetInputSpaceChargeC(TMatrixD** matricesLookUpCharge) - { - fInterpolatorChargeC->SetValue(matricesLookUpCharge); - fInterpolatorChargeC->InitCubicSpline(); - } - - void SetNRRows(Int_t nRRow) { fNRRows = nRRow; } - - void SetNPhiSlices(Int_t nPhiSlice) { fNPhiSlices = nPhiSlice; } - - void SetNZColumns(Int_t nZColumn) { fNZColumns = nZColumn; } - - Int_t GetNRRows() { return fNRRows; } - - Int_t GetNPhiSlices() { return fNPhiSlices; } - - Int_t GetNZColumns() { return fNZColumns; } - - void SetPoissonSolver(AliTPCPoissonSolver* poissonSolver) - { - if (fPoissonSolver != nullptr) { - delete fPoissonSolver; - } - fPoissonSolver = poissonSolver; - } - - AliTPCPoissonSolver* GetPoissonSolver() { return fPoissonSolver; } - - void SetInterpolationOrder(Int_t order); - - Int_t GetInterpolationOrder() { return fInterpolationOrder; } - - void SetOmegaTauT1T2(Float_t omegaTau, Float_t t1, Float_t t2) - { - const Double_t wt0 = t2 * omegaTau; - fC0 = 1. / (1. + wt0 * wt0); - const Double_t wt1 = t1 * omegaTau; - fC1 = wt1 / (1. + wt1 * wt1); - }; - - void SetC0C1(Float_t c0, Float_t c1) - { - fC0 = c0; - fC1 = c1; - } - - Float_t GetC0() const { return fC0; } - - Float_t GetC1() const { return fC1; } - - void SetCorrectionFactor(Float_t correctionFactor) { fCorrectionFactor = correctionFactor; } - - Float_t GetCorrectionFactor() const { return fCorrectionFactor; } - - void InverseDistortionMaps(TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, - TMatrixD** matricesEz, TMatrixD** matricesInvLocalIntErDz, - TMatrixD**, TMatrixD** matricesInvLocalEz, - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, const Int_t nStep, - const Bool_t useCylAC, Int_t stepR, Int_t stepZ, Int_t stepPhi, Int_t interpType); - - void InverseDistortionMapsNoDrift(TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, - TMatrixD** matricesEz, TMatrixD** matricesInvLocalIntErDz, - TMatrixD** matricesInvLocalIntEPhiDz, TMatrixD** matricesInvLocalEz, - TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, - TMatrixD** matricesDistDz, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice); - - void GetCorrectionCylNoDrift(const Float_t x[], const Short_t roc, Float_t dx[]); - - void GetDistortionCylNoDrift(const Float_t x[], Short_t roc, Float_t dx[]); - - void InverseGlobalToLocalDistortionNoDrift(TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, - TMatrixD** matricesDistDz, Double_t* rList, Double_t* zList, - Double_t* phiList, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice); - - void GetChargeDensity(TMatrixD** matricesChargeA, TMatrixD** matricesChargeC, const TH3* spaceChargeHistogram3D, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice); - - void GetInverseLocalDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]); - - void GetLocalDistortionCyl(const Float_t x[], Short_t roc, Float_t dx[]); - - void GetLocalCorrectionCyl(const Float_t x[], Short_t roc, Float_t dx[]); - - void SetIrregularGridSize(Int_t size) { fIrregularGridSize = size; } - - Int_t GetIrregularGridSize() { return fIrregularGridSize; } - - Int_t GetRBFKernelType() { return fRBFKernelType; } - - void SetPotentialBoundaryAndChargeFormula(TFormula* vTestFunction, TFormula* rhoTestFunction); - TFormula* GetPotentialVFormula() const { return fFormulaPotentialV; } - TFormula* GetChargeRhoFormula() const { return fFormulaChargeRho; } - - void SetBoundaryIFCA(TF1* f1) { fFormulaBoundaryIFCA = f1; } - - void SetBoundaryIFCC(TF1* f1) { fFormulaBoundaryIFCC = f1; } - - void SetBoundaryOFCA(TF1* f1) { fFormulaBoundaryOFCA = f1; } - - void SetBoundaryOFCC(TF1* f1) { fFormulaBoundaryOFCC = f1; } - - void SetBoundaryROCA(TF1* f1) { fFormulaBoundaryROCA = f1; } - - void SetBoundaryROCC(TF1* f1) { fFormulaBoundaryROCC = f1; } - - void SetBoundaryCE(TF1* f1) { fFormulaBoundaryCE = f1; } - - void SetElectricFieldFormula(TFormula* formulaEr, TFormula* formulaEPhi, TFormula* formulaEz) - { - fFormulaEr = formulaEr; - fFormulaEPhi = formulaEPhi; - fFormulaEz = formulaEz; - } - TFormula* GetErFormula() const { return fFormulaEr; } - TFormula* GetEPhiFormula() const { return fFormulaEPhi; } - TFormula* GetEzFormula() const { return fFormulaEz; } - - Float_t GetSpaceChargeDensity(Float_t r, Float_t phi, Float_t z); - Float_t GetPotential(Float_t r, Float_t phi, Float_t z); - void GetElectricFieldCyl(const Float_t x[], Short_t roc, Double_t dx[]); - struct Profile { - Double_t poissonSolverTime; - Double_t electricFieldTime; - Double_t localDistortionTime; - Double_t globalDistortionTime; - Double_t interpolationInitTime; - Int_t iteration; - }; - - Profile GetProfile() { return myProfile; } - void SetIntegrationStrategy(Int_t integrationStrategy) { fIntegrationStrategy = integrationStrategy; } - - void SetDistortionLookupTables(TMatrixD** matrixIntDistDrA, TMatrixD** matrixIntDistDrphiA, TMatrixD** matrixIntDistDzA, TMatrixD** matrixIntDistDrC, TMatrixD** matrixIntDistDrphiC, TMatrixD** matrixIntDistDzC); - - private: - Profile myProfile; //!<! - Int_t fNRRows = 129; ///< the maximum on row-slices so far ~ 2cm slicing - Int_t fNPhiSlices = 180; ///< the maximum of phi-slices so far = (8 per sector) - Int_t fNZColumns = 129; ///< the maximum on column-slices so ~ 2cm slicing - Float_t fC0 = 0.f; ///< coefficient C0 (compare Jim Thomas's notes for definitions) - Float_t fC1 = 0.f; ///< coefficient C1 (compare Jim Thomas's notes for definitions) - Float_t fCorrectionFactor = 1.f; ///< Space Charge Correction factor in comparison to initialized - - Bool_t fInitLookUp = kFALSE; ///< flag to check if the Look Up table was created - Double_t* fListR; //[fNRRows] list of r-coordinate of grids - Double_t* fListPhi; //[fNPhiSlices] list of \f$ \phi\f$ -coordinate of grids - Double_t* fListZ; //[fNZColumns] - Double_t* fListZA; //[fNZColumns] list of z-coordinate of grids - Double_t* fListZC; //[fNZColumns] list of z-coordinate of grids - // / TODO: fListPotentialBoundary arrays are never used in the code. Remove? - // Double_t* fListPotentialBoundaryA; //[(fNRRows + fNZColumns) * 2 * fNPhiSlices] - // Double_t* fListPotentialBoundaryC; //[(fNRRows + fNZColumns) * 2 * fNPhiSlices] - - Int_t fCorrectionType = 1; ///< use regular or irregular grid method - Int_t fInterpolationOrder = 5; ///< Order of interpolation (1-> tri linear, 2->Lagrange interpolation order 2, 3> cubic spline) - Int_t fIrregularGridSize = 3; ///< Size of irregular grid cubes for interpolation (min 3) - Int_t fRBFKernelType = 0; ///< RBF kernel type - Int_t fIntegrationStrategy = 0; ///< Strategy for integration - - TMatrixD** fMatrixIntDistDrEzA; //!<! Matrices for storing Global distortion \f$ R \f$ direction for Side A - TMatrixD** fMatrixIntDistDPhiREzA; //!<! Matrices for storing Global \f$ \phi R \f$ Distortion for Side A - TMatrixD** fMatrixIntDistDzA; //!<! Matrices for storing Global \f$ z \f$ Distortion for Side A - - TMatrixD** fMatrixIntDistDrEzC; //!<! Matrices for storing Global \f$ R \f$ direction for Side C - TMatrixD** fMatrixIntDistDPhiREzC; //!<! Matrices for storing Global \f$ \phi R \f$ Distortion for Side C - TMatrixD** fMatrixIntDistDzC; //!<! Matrices for storing Global \f$ z \f$ Distortion for Side C - - TMatrixD** fMatrixErOverEzA; //!<! Matrices for storing Er Over Ez for intermediate value for side A - TMatrixD** fMatrixEPhiOverEzA; //!<! Matrices for storing EPhi Over Ez for intermediate value for side A - TMatrixD** fMatrixDeltaEzA; //!<! Matrices for storing delta Ez for intermediate value for side A - - TMatrixD** fMatrixErOverEzC; //!<! Matrices for storing Er Over Ez for intermediate value for Side C - TMatrixD** fMatrixEPhiOverEzC; //!<! Matrices for storing EPhi Over Ez for intermediate value for Side C - TMatrixD** fMatrixDeltaEzC; //!<! Matrices for storing delta Ez for intermediate value for side A - - TMatrixD** fMatrixIntCorrDrEzA; //!<! Matrices for storing Global \f$ R \f$ correction for side A - TMatrixD** fMatrixIntCorrDPhiREzA; //!<! Matrices for storing Global \f$ \phi R \f$ correction for side A - TMatrixD** fMatrixIntCorrDzA; //!<! Matrices for storing Global \f$ X \f$ correction for side A - - TMatrixD** fMatrixIntCorrDrEzC; //!<! Matrices for storing Global \f$ R \f$ correction for side C - TMatrixD** fMatrixIntCorrDPhiREzC; //!<! Matrices for storing Global \f$ \phi R \f$ correction for side C - TMatrixD** fMatrixIntCorrDzC; //!<! Matrices for storing Global \f$ X \f$ correction for side C - - TMatrixD** fMatrixIntCorrDrEzIrregularA; //!<! Matrices for storing global \f$ R \f$ correction irregular type for side A - TMatrixD** fMatrixIntCorrDPhiREzIrregularA; //!<! Matrices for storing Global \f$ \phi R \f$ correction irregular type for side A - TMatrixD** fMatrixIntCorrDzIrregularA; //!<! Matrices for storing Global \f$ z \f$ correction irregular type for side A - - TMatrixD** fMatrixRListIrregularA; //!<! Matrices for storing distorted \f$ R \f$ side A - TMatrixD** fMatrixPhiListIrregularA; //!<! Matrices for storing distorted \f$ \phi \f$ side A - TMatrixD** fMatrixZListIrregularA; //!<! Matrices for storing distorted \f$ z \f$ side A - - TMatrixD** fMatrixIntCorrDrEzIrregularC; //!<! Matrices for storing Global \f$ R \f$ correction irregular type for side C - TMatrixD** fMatrixIntCorrDPhiREzIrregularC; //!<! Matrices for storing Global \f$ \phi R \f$ correction irregular type for side C - TMatrixD** fMatrixIntCorrDzIrregularC; //!<! Matrices for storing Global \f$ z \f$ correction irregular type for side C - - TMatrixD** fMatrixRListIrregularC; //!<! Matrices for storing distorted \f$ R \f$ side C - TMatrixD** fMatrixPhiListIrregularC; //!<! Matrices for storing distorted \f$ \phi \f$ side C - TMatrixD** fMatrixZListIrregularC; //!<! Matrices for storing distorted \f$ z \f$ side C - - // look up for charge densities - TMatrixD** fMatrixChargeA; //!<! Matrices for storing input charge densities side A - TMatrixD** fMatrixChargeC; //!<! Matrices for storing input charge densities side C - TMatrixD** fMatrixChargeInverseA; //!<! Matrices for storing charge densities from backward algorithm side A - TMatrixD** fMatrixChargeInverseC; //!<! Matrices for storing charge densities from backward algorithm side C - - TMatrixD** fMatrixPotentialA; //!<! Matrices for storing potential side A - TMatrixD** fMatrixPotentialC; //!<! Matrices for storing potential side C - - AliTPC3DCylindricalInterpolator* fInterpolatorChargeA = nullptr; //!<! interpolator for charge densities side A - AliTPC3DCylindricalInterpolator* fInterpolatorChargeC = nullptr; //!<! interpolator for charge densities side C - AliTPC3DCylindricalInterpolator* fInterpolatorPotentialA = nullptr; //!<! interpolator for charge densities side A - AliTPC3DCylindricalInterpolator* fInterpolatorPotentialC = nullptr; //!<! interpolator for charge densities side C - AliTPC3DCylindricalInterpolator* fInterpolatorInverseChargeA = nullptr; //!<! interpolator for inverse charge densities side A - AliTPC3DCylindricalInterpolator* fInterpolatorInverseChargeC = nullptr; //!<! interpolator for inverse charge densities side C - - AliTPCLookUpTable3DInterpolatorD* fLookupIntDistA = nullptr; //-> look-up table for global distortion side A - AliTPCLookUpTable3DInterpolatorD* fLookupIntCorrA = nullptr; //-> look-up table for global correction side A - AliTPCLookUpTable3DInterpolatorD* fLookupIntDistC = nullptr; //-> look-up table for global distortion side C - AliTPCLookUpTable3DInterpolatorD* fLookupIntCorrC = nullptr; //-> look-up table for global correction side C - AliTPCLookUpTable3DInterpolatorIrregularD* fLookupIntCorrIrregularA = nullptr; //!<! look-up table for global correction side A (method irregular) - AliTPCLookUpTable3DInterpolatorIrregularD* fLookupIntCorrIrregularC = nullptr; //!<! look-up table for global correction side C (method irregular) - AliTPCLookUpTable3DInterpolatorD* fLookupIntENoDriftA = nullptr; //!<! look-up table for no drift integration side A - AliTPCLookUpTable3DInterpolatorD* fLookupIntENoDriftC = nullptr; //!<! look-up table for no drift integration side C - AliTPCLookUpTable3DInterpolatorD* fLookupDistA = nullptr; //!<! look-up table for local distortion side A - AliTPCLookUpTable3DInterpolatorD* fLookupDistC = nullptr; //!<! look-up table for local distortion side C - AliTPCLookUpTable3DInterpolatorD* fLookupCorrA = nullptr; //!<! look-up table for local correction side A - AliTPCLookUpTable3DInterpolatorD* fLookupCorrC = nullptr; //!<! look-up table for local correction side C - AliTPCLookUpTable3DInterpolatorD* fLookupInverseDistA = nullptr; //!<! look-up table for local distortion (from inverse) side A - AliTPCLookUpTable3DInterpolatorD* fLookupInverseDistC = nullptr; //!<! look-up table for local distortion (from inverse) side C - - AliTPCLookUpTable3DInterpolatorD* fLookupElectricFieldA = nullptr; //!<! look-up table for electric field side A - AliTPCLookUpTable3DInterpolatorD* fLookupElectricFieldC = nullptr; //!<! look-up table for electric field side C - - TH3* fHistogram3DSpaceCharge = nullptr; //!<! Histogram with the input space charge histogram - used as an optional input - TH3* fHistogram3DSpaceChargeA = nullptr; //!<! Histogram with the input space charge histogram - used as an optional input side A - TH3* fHistogram3DSpaceChargeC = nullptr; //!<! Histogram with the input space charge histogram - used as an optional input side C - TF1* fFormulaBoundaryIFCA = nullptr; //!<! function define boundary values for IFC side A V(z) assuming symmetry in phi and r. - TF1* fFormulaBoundaryIFCC = nullptr; //!<! function define boundary values for IFC side C V(z) assuming symmetry in phi and r. - TF1* fFormulaBoundaryOFCA = nullptr; //!<! function define boundary values for OFC side A V(z) assuming symmetry in phi and r. - TF1* fFormulaBoundaryOFCC = nullptr; //!<! function define boundary values for IFC side C V(z) assuming symmetry in phi and r. - TF1* fFormulaBoundaryROCA = nullptr; //!<! function define boundary values for ROC side A V(r) assuming symmetry in phi and z. - TF1* fFormulaBoundaryROCC = nullptr; //!<! function define boundary values for ROC side V V(t) assuming symmetry in phi and z. - TF1* fFormulaBoundaryCE = nullptr; //!<! function define boundary values for CE V(z) assuming symmetry in phi and z. - - TFormula* fFormulaPotentialV = nullptr; //!<! potential V(r,rho,z) function - TFormula* fFormulaChargeRho = nullptr; //!<! charge density Rho(r,rho,z) function - - // analytic formula for E - TFormula* fFormulaEPhi = nullptr; //!<! ePhi EPhi(r,rho,z) electric field (phi) function - TFormula* fFormulaEr = nullptr; //!<! er Er(r,rho,z) electric field (r) function - TFormula* fFormulaEz = nullptr; //!<! ez Ez(r,rho,z) electric field (z) function - - AliTPCPoissonSolver* fPoissonSolver = nullptr; //!<! Pointer to a poisson solver - - void ElectricField(TMatrixD** matricesV, TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlices, const Float_t gridSizeR, - const Float_t gridSizePhi, const Float_t gridSizeZ, const Int_t symmetry, - const Float_t innerRadius); - - void - LocalDistCorrDz(TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, TMatrixD** matricesDistDrDz, - TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, TMatrixD** matricesCorrDrDz, - TMatrixD** matricesCorrDPhiRDz, TMatrixD** matricesCorrDz, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Float_t gridSizeZ, const Double_t ezField); - void - LocalDistCorrDz(TFormula* intErDzFunction, TFormula* intEPhiRDzFunction, TFormula* intDzFunction, TFormula* ezFunction, - Double_t* rList, Double_t* phiList, Double_t* zList, TMatrixD** matricesDistDrDz, - TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, TMatrixD** matricesCorrDrDz, - TMatrixD** matricesCorrDPhiRDz, TMatrixD** matricesCorrDz, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Float_t gridSizeZ, const Double_t ezField); - - void IntegrateDistCorrDriftLineDz(AliTPCLookUpTable3DInterpolatorD* lookupLocalDist, TMatrixD** matricesGDistDrDz, - TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, - AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr, TMatrixD** matricesGCorrDrDz, - TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, - TMatrixD** matricesGCorrIrregularDz, - TMatrixD** matricesRIrregular, TMatrixD** matricesPhiIrregular, - TMatrixD** matricesZIrregular, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Double_t* rList, const Double_t* phiList, const Double_t* zList); - - // outdated, to be removed once modifications in aliroot are pushed - void IntegrateDistCorrDriftLineDz( - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction, - const Double_t ezField, TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, - TMatrixD** matricesGDistDz, - TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, - TMatrixD** matricesGCorrIrregularDz, TMatrixD** matricesRIrregular, TMatrixD** matricesPhiIrregular, - TMatrixD** matricesZIrregular, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Double_t* rList, - const Double_t* phiList, const Double_t* zList); - - void IntegrateDistCorrDriftLineDz( - TFormula* intErDzTestFunction, TFormula* intEPhiRDzTestFunction, TFormula* intDzTestFunction, TFormula* ezF, - const Double_t ezField, TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, - TMatrixD** matricesGDistDz, - TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, - TMatrixD** matricesGCorrIrregularDrDz, TMatrixD** matricesGCorrIrregularDPhiRDz, - TMatrixD** matricesGCorrIrregularDz, TMatrixD** matricesRIrregular, TMatrixD** matricesPhiIrregular, - TMatrixD** matricesZIrregular, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Double_t* rList, - const Double_t* phiList, const Double_t* zList); - - void IntegrateDistCorrDriftLineDzWithLookUp(AliTPCLookUpTable3DInterpolatorD* lookupLocalDist, TMatrixD** matricesGDistDrDz, TMatrixD** matricesGDistDPhiRDz, TMatrixD** matricesGDistDz, AliTPCLookUpTable3DInterpolatorD* lookupLocalCorr, TMatrixD** matricesGCorrDrDz, TMatrixD** matricesGCorrDPhiRDz, TMatrixD** matricesGCorrDz, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, Double_t* rList, Double_t* phiList, Double_t* zList); - - void FillLookUpTable(AliTPCLookUpTable3DInterpolatorD* lookupGlobal, TMatrixD** lookupRDz, TMatrixD** lookupPhiRDz, - TMatrixD** lookupDz, const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice, - const Double_t* rList, const Double_t* phiList, const Double_t* zList); - - Double_t InterpolatePhi(const TH3* h3, const Double_t phi, const Double_t r, const Double_t z); - - void InverseGlobalToLocalDistortionGlobalInvTable(TMatrixD** matricesDistDrDz, TMatrixD** matricesDistDPhiRDz, - TMatrixD** matricesDistDz, Double_t* rList, Double_t* zList, - Double_t* phiList, const Int_t nRRow, const Int_t nZColumn, - const Int_t phiSlice, const Int_t nStep, const Bool_t useCylAC, - Int_t stepR, Int_t stepZ, Int_t stepPhi, Int_t type); - - void InverseLocalDistortionToElectricField(TMatrixD** matricesEr, TMatrixD** matricesEPhi, TMatrixD** matricesEz, - TMatrixD** matricesInvLocalIntErDz, TMatrixD** matricesInvLocalIntEPhiDz, - TMatrixD** matricesInvLocalIntEz, TMatrixD** matricesDistDrDz, - TMatrixD** matricesDistDPhiRDz, TMatrixD** matricesDistDz, - Double_t* rList, Double_t* zList, Double_t* phiList, const Int_t nRRow, - const Int_t nZColumn, const Int_t phiSlice); - - void InverseElectricFieldToCharge(TMatrixD** matricesCharge, TMatrixD** matricesEr, TMatrixD** matricesEPhi, - TMatrixD** matricesEz, Double_t* rList, Double_t* zList, Double_t* phiList, - const Int_t nRRow, const Int_t nZColumn, const Int_t phiSlice); - - void CalculateEField(TMatrixD** matricesV, TMatrixD** matricesErOverEz, TMatrixD** matricesEPhiOverEz, - TMatrixD** matricesDeltaEz, const Int_t nRRow, const Int_t nZColumn, const Int_t nPhiSlice, - const Int_t symmetry, Bool_t rocDisplacement = kFALSE); - - void - IntegrateEz(TMatrixD** matricesExOverEz, TMatrixD** matricesEx, const Int_t nRRow, const Int_t nZColumn, - const Int_t nPhiSlice, const Double_t ezField); - - void InitAllocateMemory(); - - /// \cond CLASSIMP - ClassDefNV(AliTPCSpaceCharge3DCalc, 1); - /// \endcond -}; - -#endif diff --git a/GPU/TPCSpaceChargeBase/CMakeLists.txt b/GPU/TPCSpaceChargeBase/CMakeLists.txt deleted file mode 100644 index 3743bb73ff6d4..0000000000000 --- a/GPU/TPCSpaceChargeBase/CMakeLists.txt +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -set(MODULE TPCSpaceChargeBase) - -set(SRCS - AliTPC3DCylindricalInterpolator.cxx - AliTPC3DCylindricalInterpolatorIrregular.cxx - AliTPCLookUpTable3DInterpolatorD.cxx - AliTPCLookUpTable3DInterpolatorIrregularD.cxx - AliTPCPoissonSolver.cxx - AliTPCSpaceCharge3DCalc.cxx) -string(REPLACE ".cxx" ".h" HDRS_CINT "${SRCS}") - -if(${ALIGPU_BUILD_TYPE} STREQUAL "O2") - o2_add_library(TPCSpaceChargeBase - TARGETVARNAME targetName - PUBLIC_LINK_LIBRARIES ROOT::Matrix ROOT::Hist - PUBLIC_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR} - SOURCES ${SRCS}) - - o2_target_root_dictionary(TPCSpaceChargeBase - HEADERS ${HDRS_CINT} - LINKDEF TPCSpaceChargeBaseLinkDef.h) - - o2_add_test(SpaceChargeBase - SOURCES ctest/testTPCSpaceChargeBase.cxx - COMPONENT_NAME gpu - LABELS gpu - PUBLIC_LINK_LIBRARIES O2::TPCSpaceChargeBase) - - target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB) - - install(FILES ${HDRS_CINT} DESTINATION include/GPU) -endif() - -if(${ALIGPU_BUILD_TYPE} STREQUAL "ALIROOT") - add_definitions(-DGPUCA_ALIROOT_LIB) - include_directories(SYSTEM ${ROOT_INCLUDE_DIR}) - include_directories(${AliRoot_SOURCE_DIR}/GPU/TPCSpaceChargeBase) - - # Generate the dictionary - get_directory_property(incdirs INCLUDE_DIRECTORIES) - generate_dictionary("Ali${MODULE}" "TPCSpaceChargeBaseLinkDef.h" - "${HDRS_CINT}" "${incdirs}") - - set(ROOT_DEPENDENCIES Core Hist MathCore Matrix Physics) - - # Generate the ROOT map Dependecies - set(LIBDEPS ${ROOT_DEPENDENCIES}) - generate_rootmap("Ali${MODULE}" "${LIBDEPS}" - "${CMAKE_CURRENT_SOURCE_DIR}/TPCSpaceChargeBaseLinkDef.h") - - # Add a library to the project using the specified source files - add_library_tested(Ali${MODULE} SHARED ${SRCS} G__Ali${MODULE}.cxx) - target_link_libraries(Ali${MODULE} ${LIBDEPS}) - - # Additional compilation flags - set_target_properties(Ali${MODULE} PROPERTIES COMPILE_FLAGS "") - - # System dependent: Modify the way the library is build - if(${CMAKE_SYSTEM} MATCHES Darwin) - set_target_properties(Ali${MODULE} - PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") - endif(${CMAKE_SYSTEM} MATCHES Darwin) - - # Installation - install(TARGETS Ali${MODULE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) - - install(FILES ${HDRS_CINT} DESTINATION include) -endif() diff --git a/GPU/TPCSpaceChargeBase/TPCSpaceChargeBaseLinkDef.h b/GPU/TPCSpaceChargeBase/TPCSpaceChargeBaseLinkDef.h deleted file mode 100644 index 1df5061c43b3b..0000000000000 --- a/GPU/TPCSpaceChargeBase/TPCSpaceChargeBaseLinkDef.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TPCSpaceChargeBaseLinkDef.h -/// \author Ernst Hellbaer - -#if defined(__CINT__) || defined(__CLING__) - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class AliTPC3DCylindricalInterpolator + ; -#pragma link C++ class AliTPC3DCylindricalInterpolatorIrregular + ; -#pragma link C++ struct AliTPC3DCylindricalInterpolatorIrregular::KDTreeNode + ; -#pragma link C++ class AliTPCLookUpTable3DInterpolatorD + ; -#pragma link C++ class AliTPCLookUpTable3DInterpolatorIrregularD + ; -#pragma link C++ class AliTPCPoissonSolver + ; -#pragma link C++ struct AliTPCPoissonSolver::MGParameters + ; -#pragma link C++ class AliTPCSpaceCharge3DCalc + ; - -#endif diff --git a/GPU/TPCSpaceChargeBase/ctest/testTPCSpaceChargeBase.cxx b/GPU/TPCSpaceChargeBase/ctest/testTPCSpaceChargeBase.cxx deleted file mode 100644 index 8df9e76bfb543..0000000000000 --- a/GPU/TPCSpaceChargeBase/ctest/testTPCSpaceChargeBase.cxx +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file testTPCSpaceChargeBase.cxx -/// \author Ernst Hellbaer - -#define BOOST_TEST_MODULE Test TPC Space - Charge Base Class -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -#include <boost/test/unit_test.hpp> -#include "AliTPCSpaceCharge3DCalc.h" - -/// @brief Basic test if we can create the method class -BOOST_AUTO_TEST_CASE(TPCSpaceChargeBase_test1) -{ - auto spacecharge = new AliTPCSpaceCharge3DCalc; - delete spacecharge; -} diff --git a/GPU/Utils/CMakeLists.txt b/GPU/Utils/CMakeLists.txt index 7420801222ff3..c90ddb929e689 100644 --- a/GPU/Utils/CMakeLists.txt +++ b/GPU/Utils/CMakeLists.txt @@ -1,23 +1,26 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(MODULE GPUUtils) -set(HDRS_CINT FlatObject.h) +set(HDRS_CINT FlatObject.h + GPUCommonBitSet.h +) set(HDRS_INSTALL ) if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_library(${MODULE} - SOURCES GPUUtils.cxx + SOURCES ../GPUTracking/utils/EmptyFile.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::GPUCommon ROOT::RIO) target_include_directories(${targetName} @@ -29,7 +32,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") LINKDEF GPUUtilsLinkDef.h) target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB - GPUCA_TPC_GEOMETRY_O2 HAVE_O2HEADERS) + GPUCA_TPC_GEOMETRY_O2 GPUCA_HAVE_O2HEADERS) install(FILES ${HDRS_CINT} ${HDRS_INSTALL} DESTINATION include/GPU) endif() @@ -37,7 +40,7 @@ endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_definitions(-DGPUCA_ALIROOT_LIB) - set(SRCS ${SRCS} GPUCommon.cxx) + set(SRCS ${SRCS} ../GPUTracking/utils/EmptyFile.cxx) # Add a library to the project using the specified source files add_library_tested(Ali${MODULE} SHARED ${SRCS}) @@ -56,7 +59,3 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") install(FILES ${HDRS_CINT} ${HDRS_INSTALL} DESTINATION include) endif() - -if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - -endif() diff --git a/GPU/Utils/FlatObject.h b/GPU/Utils/FlatObject.h index 8077fd18b6912..e16e08bd5b9a6 100644 --- a/GPU/Utils/FlatObject.h +++ b/GPU/Utils/FlatObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/GPU/Utils/GPUCommonBitSet.h b/GPU/Utils/GPUCommonBitSet.h new file mode 100644 index 0000000000000..11ac220935c9d --- /dev/null +++ b/GPU/Utils/GPUCommonBitSet.h @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUCommonBitSet.h +/// \author David Rohr + +#ifndef GPUCOMMONBITSET_H +#define GPUCOMMONBITSET_H + +// Limited reimplementation of std::bitset for the GPU. +// Fixed to 32 bits for now. +// In contrast to the GPUCommonArray, we cannot just use std::bitset on the host. +// The layout may be implementation defined, so it is not guarantueed that we +// get correct data after copying it into a gpustd::bitset on the GPU. + +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" +#include "GPUCommonMath.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include <string> +#endif + +namespace o2::gpu::gpustd +{ +template <unsigned int N> +class bitset +{ + static_assert(N <= 32, "> 32 bits not supported"); + + public: + GPUdDefault() constexpr bitset() = default; + GPUdDefault() constexpr bitset(const bitset&) = default; +#ifdef __OPENCL__ + GPUdDefault() constexpr bitset(const __constant bitset&) = default; +#endif // __OPENCL__ + GPUd() constexpr bitset(unsigned int vv) : v(vv){}; + static constexpr unsigned int full_set = ((1ul << N) - 1ul); + + GPUd() constexpr bool all() const { return (v & full_set) == full_set; } + GPUd() constexpr bool any() const { return v & full_set; } + GPUd() constexpr bool none() const { return !any(); } + + GPUd() constexpr void set() { v = full_set; } + GPUd() constexpr void set(unsigned int i) { v |= (1u << i) & full_set; } + GPUd() constexpr void reset() { v = 0; } + GPUd() constexpr void reset(unsigned int i) { v &= ~(1u << i); } + GPUd() constexpr void flip() { v = (~v) & full_set; } + + GPUdDefault() constexpr bitset& operator=(const bitset&) = default; + GPUd() constexpr bitset operator|(const bitset b) const { return v | b.v; } + GPUd() constexpr bitset& operator|=(const bitset b) + { + v |= b.v; + return *this; + } + GPUd() constexpr bitset operator&(const bitset b) const { return v & b.v; } + GPUd() constexpr bitset& operator&=(const bitset b) + { + v &= b.v; + return *this; + } + GPUd() constexpr bitset operator^(const bitset b) const { return v ^ b.v; } + GPUd() constexpr bitset& operator^=(const bitset b) + { + v ^= b.v; + return *this; + } + GPUd() constexpr bitset operator~() const { return (~v) & full_set; } + GPUd() constexpr bool operator==(const bitset b) { return v == b.v; } + GPUd() constexpr bool operator!=(const bitset b) { return v != b.v; } + + GPUd() constexpr bool operator[](unsigned int i) const { return (v >> i) & 1u; } + + GPUd() constexpr unsigned int to_ulong() const { return v; } + + GPUd() constexpr unsigned int count() const + { + // count number of non-0 bits in 32bit word + return GPUCommonMath::Popcount(v); + } + +#ifndef GPUCA_GPUCODE_DEVICE + std::string to_string() const; +#endif + + private: + unsigned int v = 0; + + ClassDefNV(bitset, 1); +}; + +#ifndef GPUCA_GPUCODE_DEVICE +template <unsigned int N> +inline std::string bitset<N>::to_string() const +{ + std::string retVal; + for (unsigned int i = N; i--;) { + retVal += std::to_string((int)((*this)[i])); + } + return retVal; +} +template <class CharT, class Traits, unsigned int N> +std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const bitset<N>& x) +{ + os << x.to_string(); + return os; +} + +#endif +} // namespace o2::gpu::gpustd + +#endif diff --git a/GPU/Utils/GPUUtils.cxx b/GPU/Utils/GPUUtils.cxx deleted file mode 100644 index 5de5e03f34a45..0000000000000 --- a/GPU/Utils/GPUUtils.cxx +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUUtils.cxx -/// \author David Rohr - -// Empty file, needed for AliRoot diff --git a/GPU/Utils/GPUUtilsLinkDef.h b/GPU/Utils/GPUUtilsLinkDef.h index b348375c78dd3..ab235192ce4c5 100644 --- a/GPU/Utils/GPUUtilsLinkDef.h +++ b/GPU/Utils/GPUUtilsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,5 +19,37 @@ #pragma link off all functions; #pragma link C++ class o2::gpu::FlatObject + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 1> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 2> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 3> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 4> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 5> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 6> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 7> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 8> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 9> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 10> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 11> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 12> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 13> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 14> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 15> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 16> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 17> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 18> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 19> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 20> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 21> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 22> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 23> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 24> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 25> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 26> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 27> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 28> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 29> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 30> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 31> + ; +#pragma link C++ class o2::gpu::gpustd::bitset < 32> + ; #endif diff --git a/GPU/Workflow/CMakeLists.txt b/GPU/Workflow/CMakeLists.txt new file mode 100644 index 0000000000000..c1ab290d2acd1 --- /dev/null +++ b/GPU/Workflow/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(GPUWorkflow + SOURCES src/GPUWorkflowSpec.cxx + TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsTPC + O2::DPLUtils + O2::TPCReconstruction + O2::TPCCalibration + O2::TPCSimulation + O2::TPCQC + O2::DetectorsCalibration + O2::TPCReaderWorkflow + O2::DataFormatsGlobalTracking + O2::DataFormatsTRD + PRIVATE_LINK_LIBRARIES O2::GPUTracking) + +if(GPUCA_EVENT_DISPLAY OR + (OPENGL_FOUND AND GLFW_FOUND AND TARGET AliceO2::DebugGUI AND OPENGL_GLU_FOUND + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")) + target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY) +endif() + +o2_add_executable(reco-workflow + COMPONENT_NAME gpu + TARGETVARNAME targetName + SOURCES src/gpu-reco-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GPUWorkflow + O2::GlobalTrackingWorkflowHelpers) + +if(ALIGPU_BUILD_TYPE STREQUAL "O2" + AND OPENGL_FOUND + AND GLFW_FOUND + AND TARGET AliceO2::DebugGUI + AND OPENGL_GLU_FOUND + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin" +) + o2_add_executable(display + COMPONENT_NAME gpu + TARGETVARNAME targetName + SOURCES src/O2GPUDPLDisplay.cxx + PUBLIC_LINK_LIBRARIES O2::GPUO2Interface + O2::GPUWorkflowHelper + O2::DataFormatsGlobalTracking + O2::TPCFastTransformation + O2::TRDBase + O2::TOFBase + O2::TPCReconstruction + O2::GlobalTrackingWorkflowHelpers) + target_include_directories(${targetName} PUBLIC "include") +endif() + +add_subdirectory(helper) diff --git a/GPU/Workflow/helper/CMakeLists.txt b/GPU/Workflow/helper/CMakeLists.txt new file mode 100644 index 0000000000000..2902db7076fde --- /dev/null +++ b/GPU/Workflow/helper/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(GPUWorkflowHelper + SOURCES src/GPUWorkflowHelper.cxx + TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsGlobalTracking + O2::GPUDataTypeHeaders + O2::GPUO2Interface + O2::ITStracking) diff --git a/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h b/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h new file mode 100644 index 0000000000000..225b6f75b1511 --- /dev/null +++ b/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GPU_WORKFLOW_HELPER_H +#define O2_GPU_WORKFLOW_HELPER_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "GPUDataTypes.h" +#include <memory> + +namespace o2::gpu +{ + +class GPUWorkflowHelper +{ + using GID = o2::dataformats::GlobalTrackID; + + public: + struct tmpDataContainer; + static std::shared_ptr<const tmpDataContainer> fillIOPtr(GPUTrackingInOutPointers& ioPtr, const o2::globaltracking::RecoContainer& recoCont, bool useMC, const GPUCalibObjectsConst* calib = nullptr, GID::mask_t maskCl = GID::MASK_ALL, GID::mask_t maskTrk = GID::MASK_ALL, GID::mask_t maskMatch = GID::MASK_ALL); +}; + +} // namespace o2::gpu + +#endif diff --git a/GPU/Workflow/helper/src/GPUWorkflowHelper.cxx b/GPU/Workflow/helper/src/GPUWorkflowHelper.cxx new file mode 100644 index 0000000000000..2f89a8fef9496 --- /dev/null +++ b/GPU/Workflow/helper/src/GPUWorkflowHelper.cxx @@ -0,0 +1,229 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GPUWorkflowHelper/GPUWorkflowHelper.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "DataFormatsTRD/TrackTRD.h" +#include "ITStracking/IOUtils.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include <type_traits> + +using namespace o2::globaltracking; +using namespace o2::gpu; + +struct GPUWorkflowHelper::tmpDataContainer { + std::vector<o2::BaseCluster<float>> ITSClustersArray; + std::vector<int> tpcLinkITS, tpcLinkTRD, tpcLinkTOF; + std::vector<const o2::track::TrackParCov*> globalTracks; + std::vector<float> globalTrackTimes; +}; + +std::shared_ptr<const GPUWorkflowHelper::tmpDataContainer> GPUWorkflowHelper::fillIOPtr(GPUTrackingInOutPointers& ioPtr, const o2::globaltracking::RecoContainer& recoCont, bool useMC, const GPUCalibObjectsConst* calib, o2::dataformats::GlobalTrackID::mask_t maskCl, o2::dataformats::GlobalTrackID::mask_t maskTrk, o2::dataformats::GlobalTrackID::mask_t maskMatch) +{ + auto retVal = std::make_shared<tmpDataContainer>(); + + if (maskCl[GID::ITS] && ioPtr.nItsClusters == 0) { + const auto& ITSClusterROFRec = recoCont.getITSClustersROFRecords(); + const auto& clusITS = recoCont.getITSClusters(); + if (clusITS.size() && ITSClusterROFRec.size()) { + if (calib && calib->itsPatternDict) { + const auto& patterns = recoCont.getITSClustersPatterns(); + auto pattIt = patterns.begin(); + retVal->ITSClustersArray.reserve(clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, retVal->ITSClustersArray, *calib->itsPatternDict); + ioPtr.itsClusters = retVal->ITSClustersArray.data(); + } + ioPtr.nItsClusters = clusITS.size(); + ioPtr.itsCompClusters = clusITS.data(); + ioPtr.nItsClusterROF = ITSClusterROFRec.size(); + ioPtr.itsClusterROF = ITSClusterROFRec.data(); + if (useMC) { + const auto& ITSClsLabels = recoCont.mcITSClusters.get(); + ioPtr.itsClusterMC = ITSClsLabels; + } + } + //LOG(info) << "Got " << ioPtr.nItsClusters << " ITS Clusters"; + } + if (maskTrk[GID::ITS] && ioPtr.nItsTracks == 0) { + const auto& ITSTracksArray = recoCont.getITSTracks(); + const auto& ITSTrackROFRec = recoCont.getITSTracksROFRecords(); + if (ITSTracksArray.size() && ITSTrackROFRec.size()) { + const auto& ITSTrackClusIdx = recoCont.getITSTracksClusterRefs(); + ioPtr.nItsTracks = ITSTracksArray.size(); + ioPtr.itsTracks = ITSTracksArray.data(); + ioPtr.itsTrackClusIdx = ITSTrackClusIdx.data(); + ioPtr.nItsTrackROF = ITSTrackROFRec.size(); + ioPtr.itsTrackROF = ITSTrackROFRec.data(); + if (useMC) { + const auto& ITSTrkLabels = recoCont.getITSTracksMCLabels(); + ioPtr.itsTrackMC = ITSTrkLabels.data(); + } + } + //LOG(info) << "Got " << ioPtr.nItsTracks << " ITS Tracks"; + } + + if (maskTrk[GID::ITSTPC] && ioPtr.nTracksTPCITSO2 == 0) { + const auto& trkITSTPC = recoCont.getTPCITSTracks(); + if (trkITSTPC.size()) { + ioPtr.nTracksTPCITSO2 = trkITSTPC.size(); + ioPtr.tracksTPCITSO2 = trkITSTPC.data(); + } + //LOG(info) << "Got " << ioPtr.nTracksTPCITSO2 << " ITS-TPC Tracks"; + } + + if (maskCl[GID::TOF] && ioPtr.nTOFClusters == 0) { + const auto& tofClusters = recoCont.getTOFClusters(); + if (tofClusters.size()) { + ioPtr.nTOFClusters = tofClusters.size(); + ioPtr.tofClusters = tofClusters.data(); + } + //LOG(info) << "Got " << ioPtr.nTOFClusters << " TOF Clusters"; + } + + if ((maskMatch[GID::TOF] || maskMatch[GID::ITSTPCTOF]) && ioPtr.nITSTPCTOFMatches == 0) { + const auto& itstpctofMatches = recoCont.getITSTPCTOFMatches(); + if (itstpctofMatches.size()) { + ioPtr.nITSTPCTOFMatches = itstpctofMatches.size(); + ioPtr.itstpctofMatches = itstpctofMatches.data(); + } + //LOG(info) << "Got " << ioPtr.nITSTPCTOFMatches << " ITS-TPC-TOF Matches"; + } + + if ((maskMatch[GID::TOF] || maskMatch[GID::ITSTPCTRDTOF]) && ioPtr.nITSTPCTRDTOFMatches == 0) { + const auto& itstpctrdtofMatches = recoCont.getITSTPCTRDTOFMatches(); + if (itstpctrdtofMatches.size()) { + ioPtr.nITSTPCTRDTOFMatches = itstpctrdtofMatches.size(); + ioPtr.itstpctrdtofMatches = itstpctrdtofMatches.data(); + } + //LOG(info) << "Got " << ioPtr.nITSTPCTRDTOFMatches << " ITS-TPC-TRD-TOF Matches"; + } + + if ((maskMatch[GID::TOF] || maskMatch[GID::TPCTOF]) && ioPtr.nTPCTOFMatches == 0) { + const auto& tpctofMatches = recoCont.getTPCTOFMatches(); + if (tpctofMatches.size()) { + ioPtr.nTPCTOFMatches = tpctofMatches.size(); + ioPtr.tpctofMatches = tpctofMatches.data(); + } + //LOG(info) << "Got " << ioPtr.nTPCTOFMatches << " TPC-TOF Matches"; + } + + if ((maskMatch[GID::TOF] || maskMatch[GID::TPCTRDTOF]) && ioPtr.nTPCTRDTOFMatches == 0) { + const auto& tpctrdtofMatches = recoCont.getTPCTRDTOFMatches(); + if (tpctrdtofMatches.size()) { + ioPtr.nTPCTRDTOFMatches = tpctrdtofMatches.size(); + ioPtr.tpctrdtofMatches = tpctrdtofMatches.data(); + } + //LOG(info) << "Got " << ioPtr.nTPCTOFMatches << " TPC-TOF Matches"; + } + + if (maskCl[GID::TRD]) { + recoCont.inputsTRD->fillGPUIOPtr(&ioPtr); + //LOG(info) << "Got " << ioPtr.nTRDTracklets << " TRD Tracklets"; + } + + if (maskTrk[GID::ITSTPCTRD] && ioPtr.nTRDTracksITSTPCTRD == 0) { + const auto& trdTracks = recoCont.getITSTPCTRDTracks<o2::trd::TrackTRD>(); + if (trdTracks.size()) { + ioPtr.nTRDTracksITSTPCTRD = trdTracks.size(); + ioPtr.trdTracksITSTPCTRD = trdTracks.data(); + } + //LOG(info) << "Got " << ioPtr.nTRDTracksITSTPCTRD << " ITS-TPC-TRD Tracks"; + } + + if (maskTrk[GID::TPCTRD] && ioPtr.nTRDTracksTPCTRD == 0) { + const auto& trdTracks = recoCont.getTPCTRDTracks<o2::trd::TrackTRD>(); + if (trdTracks.size()) { + ioPtr.nTRDTracksTPCTRD = trdTracks.size(); + ioPtr.trdTracksTPCTRD = trdTracks.data(); + } + //LOG(info) << "Got " << ioPtr.nTRDTracksTPCTRD << " TPC-TRD Tracks"; + } + + if (maskCl[GID::TPC] && ioPtr.clustersNative == nullptr) { + ioPtr.clustersNative = &recoCont.getTPCClusters(); + //LOG(info) << "Got " << ioPtr.clustersNative->nClustersTotal << " TPC Clusters"; + } + + if (maskTrk[GID::TPC] && ioPtr.nOutputTracksTPCO2 == 0) { + const auto& tpcTracks = recoCont.getTPCTracks(); + const auto& tpcClusRefs = recoCont.getTPCTracksClusterRefs(); + ioPtr.outputTracksTPCO2 = tpcTracks.data(); + ioPtr.nOutputTracksTPCO2 = tpcTracks.size(); + ioPtr.outputClusRefsTPCO2 = tpcClusRefs.data(); + ioPtr.nOutputClusRefsTPCO2 = tpcClusRefs.size(); + if (useMC) { + const auto& tpcTracksMC = recoCont.getTPCTracksMCLabels(); + ioPtr.outputTracksTPCO2MC = tpcTracksMC.data(); + } + if (ioPtr.nTracksTPCITSO2) { + retVal->tpcLinkITS.resize(ioPtr.nOutputTracksTPCO2, -1); + ioPtr.tpcLinkITS = retVal->tpcLinkITS.data(); + } + if (ioPtr.nITSTPCTOFMatches || ioPtr.nTPCTRDTOFMatches || ioPtr.nITSTPCTRDTOFMatches || ioPtr.nTPCTOFMatches) { + retVal->tpcLinkTOF.resize(ioPtr.nOutputTracksTPCO2, -1); + ioPtr.tpcLinkTOF = retVal->tpcLinkTOF.data(); + } + if (ioPtr.nTRDTracksITSTPCTRD || ioPtr.nTRDTracksTPCTRD) { + retVal->tpcLinkTRD.resize(ioPtr.nOutputTracksTPCO2, -1); + ioPtr.tpcLinkTRD = retVal->tpcLinkTRD.data(); + } + //LOG(info) << "Got " << ioPtr.nOutputTracksTPCO2 << " TPC Tracks"; + } + + auto creator = [maskTrk, &ioPtr, &recoCont, &retVal](auto& trk, GID gid, float time, float) { + if (gid.getSource() == GID::ITSTPCTOF) { + if (maskTrk[GID::TPC] && ioPtr.nTracksTPCITSO2) { + const auto& match = recoCont.getTOFMatch(gid); + const auto& trkItsTPC = ioPtr.tracksTPCITSO2[match.getTrackIndex()]; + if (retVal->tpcLinkTOF.size()) { + retVal->tpcLinkTOF[trkItsTPC.getRefTPC().getIndex()] = match.getTOFClIndex(); + } + if (retVal->tpcLinkITS.size()) { + retVal->tpcLinkITS[trkItsTPC.getRefTPC().getIndex()] = trkItsTPC.getRefITS().getIndex(); + } + } + } else if constexpr (isTPCTrack<decltype(trk)>()) { + time = trk.getTime0(); + } else if constexpr (isTPCITSTrack<decltype(trk)>()) { + if (maskTrk[GID::TPC] && retVal->tpcLinkITS.size()) { + retVal->tpcLinkITS[trk.getRefTPC().getIndex()] = trk.getRefITS().getIndex(); + } + } else if constexpr (isTPCTOFTrack<decltype(trk)>()) { + if (maskTrk[GID::TPC] && ioPtr.nTPCTOFMatches && retVal->tpcLinkTOF.size()) { + const auto& match = ioPtr.tpctofMatches[trk.getRefMatch()]; + retVal->tpcLinkTOF[match.getTrackIndex()] = match.getTOFClIndex(); + } + } + if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(trk)>>) { + retVal->globalTracks.emplace_back(&trk); + retVal->globalTrackTimes.emplace_back(time); + return true; + } else { + return false; + } + }; + recoCont.createTracksVariadic(creator); + if (maskTrk[GID::TPC] && retVal->tpcLinkTRD.size()) { + for (unsigned int i = 0; i < ioPtr.nTRDTracksTPCTRD; i++) { // TODO: This should be handled by the createTracks logic, but so far it lacks the TRD tracks + retVal->tpcLinkTRD[ioPtr.trdTracksTPCTRD[i].getRefGlobalTrackId().getIndex()] = i; + } + if (ioPtr.nTracksTPCITSO2) { + for (unsigned int i = 0; i < ioPtr.nTRDTracksITSTPCTRD; i++) { + retVal->tpcLinkTRD[ioPtr.tracksTPCITSO2[ioPtr.trdTracksITSTPCTRD[i].getRefGlobalTrackId().getIndex()].getRefTPC().getIndex()] = i | 0x40000000; + } + } + } + ioPtr.globalTracks = retVal->globalTracks.data(); + ioPtr.globalTrackTimes = retVal->globalTrackTimes.data(); + + return std::move(retVal); +} diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h new file mode 100644 index 0000000000000..b116ed3cd5af2 --- /dev/null +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPURecoWorkflowSpec.h +/// @author Matthias Richter +/// @since 2018-04-18 +/// @brief Processor spec for running TPC CA tracking + +#ifndef O2_GPU_WORKFLOW_SPEC_H +#define O2_GPU_WORKFLOW_SPEC_H + +#include "Framework/DataProcessorSpec.h" +#include <string> +#include <vector> + +namespace o2 +{ +namespace framework +{ +struct CompletionPolicy; +} + +namespace gpu +{ +namespace gpuworkflow +{ +struct Config { + bool decompressTPC = false; + bool decompressTPCFromROOT = false; + bool caClusterer = false; + bool zsDecoder = false; + bool zsOnTheFly = false; + bool outputTracks = false; + bool outputCompClusters = false; + bool outputCompClustersFlat = false; + bool outputCAClusters = false; + bool outputQA = false; + bool outputSharedClusterMap = false; + bool processMC = false; + bool sendClustersPerSector = false; + bool askDISTSTF = true; + bool readTRDtracklets = false; +}; +using CompletionPolicyData = std::vector<framework::InputSpec>; +} // namespace gpuworkflow + +/// create a processor spec for the CATracker +/// The CA tracker is actually much more than the tracker it has evolved to a +/// general interface processor for TPC GPU algorithms. This includes currently +/// decoding of zero-suppressed raw data, ca clusterer and ca tracking. The input +/// is chosen depending on the mode. +/// +/// The input specs are created depending on the list of tpc sectors, with separate +/// routes per sector. If the processor is also runnig the clusterer and cluster +/// output is enabled, the outputs are created based on the list of TPC sectors. +/// +/// The individual operations of the CA processor can be switched using enum +/// @ca::Operations, a configuration object @a ca::Config is used to pass the +/// configuration to the processor spec. +/// +/// @param specconfig configuration options for the processor spec +/// @param tpcsectors list of sector numbers +framework::DataProcessorSpec getGPURecoWorkflowSpec(gpuworkflow::CompletionPolicyData* policyData, gpuworkflow::Config const& specconfig, std::vector<int> const& tpcsectors, unsigned long tpcSectorMask, std::string processorName); + +o2::framework::CompletionPolicy getCATrackerCompletionPolicy(); +} // end namespace gpu +} // end namespace o2 + +#endif // O2_GPU_WORKFLOW_SPEC_H diff --git a/GPU/Workflow/include/GPUWorkflow/O2GPUDPLDisplay.h b/GPU/Workflow/include/GPUWorkflow/O2GPUDPLDisplay.h new file mode 100644 index 0000000000000..763d7f2172cad --- /dev/null +++ b/GPU/Workflow/include/GPUWorkflow/O2GPUDPLDisplay.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_GPU_DPL_DISPLAY_H +#define O2_GPU_DPL_DISPLAY_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Task.h" +#include <memory> + +namespace o2::trd +{ +class GeometryFlat; +} +namespace o2::globaltracking +{ +struct DataRequest; +} +namespace o2::itsmft +{ +class TopologyDictionary; +} + +namespace o2::gpu +{ +class GPUO2InterfaceDisplay; +struct GPUO2InterfaceConfiguration; +class TPCFastTransform; + +class O2GPUDPLDisplaySpec : public o2::framework::Task +{ + public: + O2GPUDPLDisplaySpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t trkMask, o2::dataformats::GlobalTrackID::mask_t clMask, std::shared_ptr<o2::globaltracking::DataRequest> dataRequest) : mUseMC(useMC), mTrkMask(trkMask), mClMask(clMask), mDataRequest(dataRequest) {} + ~O2GPUDPLDisplaySpec() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + bool mUseMC = false; + o2::dataformats::GlobalTrackID::mask_t mTrkMask; + o2::dataformats::GlobalTrackID::mask_t mClMask; + std::unique_ptr<GPUO2InterfaceDisplay> mDisplay; + std::unique_ptr<GPUO2InterfaceConfiguration> mConfig; + std::unique_ptr<TPCFastTransform> mFastTransform; + std::unique_ptr<o2::trd::GeometryFlat> mTrdGeo; + std::unique_ptr<o2::itsmft::TopologyDictionary> mITSDict; + std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest; +}; + +} // namespace o2::gpu + +#endif diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx new file mode 100644 index 0000000000000..fbf31d780dc72 --- /dev/null +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -0,0 +1,846 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPUWorkflowSpec.cxx +/// @author Matthias Richter +/// @since 2018-04-18 +/// @brief Processor spec for running TPC CA tracking + +#include "GPUWorkflow/GPUWorkflowSpec.h" +#include "Headers/DataHeader.h" +#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs +#include "Framework/DataRefUtils.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/SerializationMethods.h" +#include "Framework/Logger.h" +#include "Framework/CallbackService.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/Helpers.h" +#include "DataFormatsTPC/ZeroSuppression.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "TPCReconstruction/TPCTrackingDigitsPreCheck.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCFastTransform.h" +#include "TPCdEdxCalibrationSplines.h" +#include "DPLUtils/DPLRawParser.h" +#include "DPLUtils/DPLRawPageSequencer.h" +#include "DetectorsBase/MatLayerCylSet.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "TPCBase/RDHUtils.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceQA.h" +#include "GPUO2Interface.h" +#include "TPCPadGainCalib.h" +#include "GPUDisplayBackend.h" +#ifdef GPUCA_BUILD_EVENT_DISPLAY +#include "GPUDisplayBackendGlfw.h" +#endif +#include "DataFormatsParameters/GRPObject.h" +#include "TPCBase/Sector.h" +#include "TPCBase/Utils.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Algorithm/Parser.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "TRDBase/Geometry.h" +#include "TRDBase/GeometryFlat.h" +#include <filesystem> +#include <memory> // for make_shared +#include <vector> +#include <iomanip> +#include <stdexcept> +#include <regex> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <chrono> +#include "GPUReconstructionConvert.h" +#include "DetectorsRaw/RDHUtils.h" +#include <TStopwatch.h> +#include <TObjArray.h> +#include <TH1F.h> +#include <TH2F.h> +#include <TH1D.h> + +using namespace o2::framework; +using namespace o2::header; +using namespace o2::gpu; +using namespace o2::base; +using namespace o2::dataformats; +using namespace o2::tpc; + +namespace o2::gpu +{ +DataProcessorSpec getGPURecoWorkflowSpec(gpuworkflow::CompletionPolicyData* policyData, gpuworkflow::Config const& specconfig, std::vector<int> const& tpcsectors, unsigned long tpcSectorMask, std::string processorName) +{ + if (specconfig.outputCAClusters && !specconfig.caClusterer && !specconfig.decompressTPC) { + throw std::runtime_error("inconsistent configuration: cluster output is only possible if CA clusterer is activated"); + } + + static TStopwatch timer; + + constexpr static size_t NSectors = Sector::MAXSECTOR; + constexpr static size_t NEndpoints = 20; //TODO: get from mapper? + using ClusterGroupParser = o2::algorithm::ForwardParser<ClusterGroupHeader>; + struct ProcessAttributes { + std::unique_ptr<ClusterGroupParser> parser; + std::unique_ptr<GPUO2Interface> tracker; + std::unique_ptr<GPUDisplayBackend> displayBackend; + std::unique_ptr<TPCFastTransform> fastTransform; + std::unique_ptr<TPCdEdxCalibrationSplines> dEdxSplines; + std::unique_ptr<TPCPadGainCalib> tpcPadGainCalib; + std::unique_ptr<o2::trd::GeometryFlat> trdGeometry; + std::unique_ptr<GPUO2InterfaceConfiguration> config; + int qaTaskMask = 0; + std::unique_ptr<GPUO2InterfaceQA> qa; + std::vector<int> clusterOutputIds; + unsigned long outputBufferSize = 0; + unsigned long tpcSectorMask = 0; + int verbosity = 0; + bool readyToQuit = false; + bool allocateOutputOnTheFly = false; + bool suppressOutput = false; + o2::gpu::GPUSettingsTF tfSettings; + }; + + auto processAttributes = std::make_shared<ProcessAttributes>(); + processAttributes->tpcSectorMask = tpcSectorMask; + + auto initFunction = [processAttributes, specconfig](InitContext& ic) { + processAttributes->config.reset(new GPUO2InterfaceConfiguration); + GPUO2InterfaceConfiguration& config = *processAttributes->config.get(); + GPUSettingsO2 confParam; + { + auto& parser = processAttributes->parser; + auto& tracker = processAttributes->tracker; + parser = std::make_unique<ClusterGroupParser>(); + tracker = std::make_unique<GPUO2Interface>(); + + // Create configuration object and fill settings + const auto grp = o2::parameters::GRPObject::loadFrom(); + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + if (!grp) { + throw std::runtime_error("Failed to initialize run parameters from GRP"); + } + config.configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + config.configGRP.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; // Number of timebins in timeframe if continuous, 0 otherwise + processAttributes->tfSettings.hasNHBFPerTF = 1; + processAttributes->tfSettings.nHBFPerTF = grp->getNHBFPerTF(); + processAttributes->tfSettings.hasRunStartOrbit = 1; + processAttributes->tfSettings.runStartOrbit = grp->getFirstOrbit(); + processAttributes->tfSettings.hasSimStartOrbit = 1; + auto& hbfu = o2::raw::HBFUtils::Instance(); + processAttributes->tfSettings.simStartOrbit = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit; + + LOG(INFO) << "Initializing run paramerers from GRP bz=" << config.configGRP.solenoidBz << " cont=" << grp->isDetContinuousReadOut(o2::detectors::DetID::TPC); + + confParam = config.ReadConfigurableParam(); + processAttributes->allocateOutputOnTheFly = confParam.allocateOutputOnTheFly; + processAttributes->outputBufferSize = confParam.outputBufferSize; + processAttributes->suppressOutput = (confParam.dump == 2); + config.configInterface.dumpEvents = confParam.dump; + if (confParam.display) { +#ifdef GPUCA_BUILD_EVENT_DISPLAY + processAttributes->displayBackend.reset(new GPUDisplayBackendGlfw); + config.configProcessing.eventDisplay = processAttributes->displayBackend.get(); + LOG(INFO) << "Event display enabled"; +#else + throw std::runtime_error("Standalone Event Display not enabled at build time!"); +#endif + } + + if (config.configGRP.continuousMaxTimeBin == -1) { + config.configGRP.continuousMaxTimeBin = (processAttributes->tfSettings.nHBFPerTF * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; + } + if (config.configProcessing.deviceNum == -2) { + int myId = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId; + int idMax = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices; + config.configProcessing.deviceNum = myId; + LOG(INFO) << "GPU device number selected from pipeline id: " << myId << " / " << idMax; + } + if (config.configProcessing.debugLevel >= 3 && processAttributes->verbosity == 0) { + processAttributes->verbosity = 1; + } + config.configProcessing.runMC = specconfig.processMC; + if (specconfig.outputQA) { + if (!specconfig.processMC && !config.configQA.clusterRejectionHistograms) { + throw std::runtime_error("Need MC information to create QA plots"); + } + if (!specconfig.processMC) { + config.configQA.noMC = true; + } + config.configQA.shipToQC = true; + if (!config.configProcessing.runQA) { + config.configQA.enableLocalOutput = false; + processAttributes->qaTaskMask = (specconfig.processMC ? 15 : 0) | (config.configQA.clusterRejectionHistograms ? 32 : 0); + config.configProcessing.runQA = -processAttributes->qaTaskMask; + } + } + config.configReconstruction.tpc.nWaysOuter = true; + config.configInterface.outputToExternalBuffers = true; + if (confParam.synchronousProcessing) { + config.configReconstruction.useMatLUT = false; + } + + // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) + if (specconfig.outputTracks || specconfig.outputCompClusters || specconfig.outputCompClustersFlat) { + config.configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, + GPUDataTypes::RecoStep::TPCSliceTracking, + GPUDataTypes::RecoStep::TPCMerging); + config.configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); + config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, !confParam.synchronousProcessing); + } + if (specconfig.outputCompClusters || specconfig.outputCompClustersFlat) { + config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true); + config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); + } + config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); + if (specconfig.caClusterer) { // Override some settings if we have raw data as input + config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw); + config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true); + config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); + } + if (specconfig.decompressTPC) { + config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); + config.configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); + config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters); + config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); + config.configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + if (processAttributes->tpcSectorMask != 0xFFFFFFFFF) { + throw std::invalid_argument("Cannot run TPC decompression with a sector mask"); + } + } + if (specconfig.outputSharedClusterMap) { + config.configProcessing.outputSharedClusterMap = true; + } + config.configProcessing.createO2Output = specconfig.outputTracks ? 2 : 0; // Skip GPU-formatted output if QA is not requested + + // Create and forward data objects for TPC transformation, material LUT, ... + if (confParam.transformationFile.size()) { + processAttributes->fastTransform = nullptr; + config.configCalib.fastTransform = TPCFastTransform::loadFromFile(confParam.transformationFile.c_str()); + } else { + processAttributes->fastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0)); + config.configCalib.fastTransform = processAttributes->fastTransform.get(); + } + if (config.configCalib.fastTransform == nullptr) { + throw std::invalid_argument("GPU workflow: initialization of the TPC transformation failed"); + } + + if (confParam.matLUTFile.size()) { + config.configCalib.matLUT = o2::base::MatLayerCylSet::loadFromFile(confParam.matLUTFile.c_str(), "MatBud"); + } + + if (confParam.dEdxFile.size()) { + processAttributes->dEdxSplines.reset(new TPCdEdxCalibrationSplines(confParam.dEdxFile.c_str())); + } else { + processAttributes->dEdxSplines.reset(new TPCdEdxCalibrationSplines); + } + config.configCalib.dEdxSplines = processAttributes->dEdxSplines.get(); + + if (std::filesystem::exists(confParam.gainCalibFile)) { + LOG(INFO) << "Loading tpc gain correction from file " << confParam.gainCalibFile; + const auto* gainMap = o2::tpc::utils::readCalPads(confParam.gainCalibFile, "GainMap")[0]; + processAttributes->tpcPadGainCalib = GPUO2Interface::getPadGainCalib(*gainMap); + } else { + if (not confParam.gainCalibFile.empty()) { + LOG(WARN) << "Couldn't find tpc gain correction file " << confParam.gainCalibFile << ". Not applying any gain correction."; + } + processAttributes->tpcPadGainCalib = GPUO2Interface::getPadGainCalibDefault(); + } + config.configCalib.tpcPadGain = processAttributes->tpcPadGainCalib.get(); + + config.configCalib.o2Propagator = Propagator::Instance(); + + if (specconfig.readTRDtracklets) { + auto gm = o2::trd::Geometry::instance(); + gm->createPadPlaneArray(); + gm->createClusterMatrixArray(); + processAttributes->trdGeometry = std::make_unique<o2::trd::GeometryFlat>(*gm); + config.configCalib.trdGeometry = processAttributes->trdGeometry.get(); + } + + if (confParam.printSettings) { + config.PrintParam(); + } + + // Configuration is prepared, initialize the tracker. + if (tracker->Initialize(config) != 0) { + throw std::invalid_argument("GPU Reconstruction initialization failed"); + } + if (specconfig.outputQA) { + processAttributes->qa = std::make_unique<GPUO2InterfaceQA>(processAttributes->config.get()); + } + timer.Stop(); + timer.Reset(); + } + + auto& callbacks = ic.services().get<CallbackService>(); + callbacks.set(CallbackService::Id::RegionInfoCallback, [&processAttributes, confParam](FairMQRegionInfo const& info) { + if (info.size) { + int fd = 0; + if (confParam.mutexMemReg) { + mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); + if (fd == -1) { + throw std::runtime_error("Error opening lock file"); + } + fchmod(fd, mask); + if (lockf(fd, F_LOCK, 0)) { + throw std::runtime_error("Error locking file"); + } + } + auto& tracker = processAttributes->tracker; + if (tracker->registerMemoryForGPU(info.ptr, info.size)) { + throw std::runtime_error("Error registering memory for GPU"); + } + if (confParam.mutexMemReg) { + if (lockf(fd, F_ULOCK, 0)) { + throw std::runtime_error("Error unlocking file"); + } + close(fd); + } + } + }); + + // the callback to be set as hook at stop of processing for the framework + auto printTiming = []() { + LOGF(INFO, "TPC CATracker total timing: Cpu: %.3e Real: %.3e s in %d slots", timer.CpuTime(), timer.RealTime(), timer.Counter() - 1); + }; + ic.services().get<CallbackService>().set(CallbackService::Id::Stop, printTiming); + + auto processingFct = [processAttributes, specconfig](ProcessingContext& pc) { + if (processAttributes->readyToQuit) { + return; + } + auto cput = timer.CpuTime(); + auto realt = timer.RealTime(); + timer.Start(false); + auto& parser = processAttributes->parser; + auto& tracker = processAttributes->tracker; + auto& verbosity = processAttributes->verbosity; + std::vector<gsl::span<const char>> inputs; + + const CompressedClustersFlat* pCompClustersFlat; + size_t compClustersFlatDummyMemory[(sizeof(CompressedClustersFlat) + sizeof(size_t) - 1) / sizeof(size_t)]; + CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast<CompressedClustersFlat&>(compClustersFlatDummyMemory); + CompressedClusters compClustersDummy; + o2::gpu::GPUTrackingInOutZS tpcZS; + std::vector<const void*> tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + std::vector<unsigned int> tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const void** tpcZSmetaPointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const unsigned int* tpcZSmetaSizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + std::array<unsigned int, NEndpoints * NSectors> tpcZSonTheFlySizes; + gsl::span<const ZeroSuppressedContainer8kb> inputZS; + + bool getWorkflowTPCInput_clusters = false, getWorkflowTPCInput_mc = false, getWorkflowTPCInput_digits = false; + + // unsigned int totalZSPages = 0; + if (specconfig.processMC) { + getWorkflowTPCInput_mc = true; + } + if (!specconfig.decompressTPC && !specconfig.caClusterer) { + getWorkflowTPCInput_clusters = true; + } + if (!specconfig.decompressTPC && specconfig.caClusterer && ((!specconfig.zsOnTheFly || specconfig.processMC) && !specconfig.zsDecoder)) { + getWorkflowTPCInput_digits = true; + } + + if (specconfig.zsOnTheFly || specconfig.zsDecoder) { + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZSmetaPointers[i][j].clear(); + tpcZSmetaSizes[i][j].clear(); + } + } + } + if (specconfig.zsOnTheFly) { + tpcZSonTheFlySizes = {0}; + // tpcZSonTheFlySizes: #zs pages per endpoint: + std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "ZSSIZES"}, Lifetime::Timeframe}}; + bool recv = false, recvsizes = false; + for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) { + if (recvsizes) { + throw std::runtime_error("Received multiple ZSSIZES data"); + } + tpcZSonTheFlySizes = pc.inputs().get<std::array<unsigned int, NEndpoints * NSectors>>(ref); + recvsizes = true; + } + // zs pages + std::vector<InputSpec> filter2 = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "TPCZS"}, Lifetime::Timeframe}}; + for (auto const& ref : InputRecordWalker(pc.inputs(), filter2)) { + if (recv) { + throw std::runtime_error("Received multiple TPCZS data"); + } + inputZS = pc.inputs().get<gsl::span<ZeroSuppressedContainer8kb>>(ref); + recv = true; + } + if (!recv || !recvsizes) { + throw std::runtime_error("TPC ZS on the fly data not received"); + } + + unsigned int offset = 0; + for (unsigned int i = 0; i < NSectors; i++) { + unsigned int pageSector = 0; + for (unsigned int j = 0; j < NEndpoints; j++) { + pageSector += tpcZSonTheFlySizes[i * NEndpoints + j]; + offset += tpcZSonTheFlySizes[i * NEndpoints + j]; + } + if (verbosity >= 1) { + LOG(INFO) << "GOT ZS on the fly pages FOR SECTOR " << i << " -> pages: " << pageSector; + } + } + } + if (specconfig.zsDecoder) { + std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; + auto isSameRdh = [](const char* left, const char* right) -> bool { + return o2::raw::RDHUtils::getFEEID(left) == o2::raw::RDHUtils::getFEEID(right); + }; + auto insertPages = [&tpcZSmetaPointers, &tpcZSmetaSizes](const char* ptr, size_t count) -> void { + int rawcru = rdh_utils::getCRU(ptr); + int rawendpoint = rdh_utils::getEndPoint(ptr); + tpcZSmetaPointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr); + tpcZSmetaSizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); + }; + // the sequencer processes all inputs matching the filter and finds sequences of consecutive + // raw pages based on the matcher predicate, and calls the inserter for each sequence + DPLRawPageSequencer(pc.inputs(), filter)(isSameRdh, insertPages); + + int totalCount = 0; + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZSmetaPointers2[i][j] = tpcZSmetaPointers[i][j].data(); + tpcZSmetaSizes2[i][j] = tpcZSmetaSizes[i][j].data(); + tpcZS.slice[i].zsPtr[j] = tpcZSmetaPointers2[i][j]; + tpcZS.slice[i].nZSPtr[j] = tpcZSmetaSizes2[i][j]; + tpcZS.slice[i].count[j] = tpcZSmetaPointers[i][j].size(); + totalCount += tpcZSmetaPointers[i][j].size(); + } + } + } else if (specconfig.decompressTPC) { + if (specconfig.decompressTPCFromROOT) { + compClustersDummy = *pc.inputs().get<CompressedClustersROOT*>("input"); + compClustersFlatDummy.setForward(&compClustersDummy); + pCompClustersFlat = &compClustersFlatDummy; + } else { + pCompClustersFlat = pc.inputs().get<CompressedClustersFlat*>("input").get(); + } + } else if (!specconfig.zsOnTheFly) { + if (verbosity) { + LOGF(INFO, "running tracking for sector(s) 0x%09x", processAttributes->tpcSectorMask); + } + } + + const auto& inputsClustersDigits = getWorkflowTPCInput(pc, verbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, processAttributes->tpcSectorMask, getWorkflowTPCInput_digits); + GPUTrackingInOutPointers ptrs; + + o2::globaltracking::RecoContainer inputTracksTRD; + decltype(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD)) trdInputContainer; + if (specconfig.readTRDtracklets) { + o2::globaltracking::DataRequest dataRequestTRD; + dataRequestTRD.requestTracks(o2::dataformats::GlobalTrackID::getSourcesMask(o2::dataformats::GlobalTrackID::NONE), false); + inputTracksTRD.collectData(pc, dataRequestTRD); + trdInputContainer = std::move(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD)); + } + + void* ptrEp[NSectors * NEndpoints] = {}; + bool doInputDigits = false, doInputDigitsMC = false; + if (specconfig.decompressTPC) { + ptrs.tpcCompressedClusters = pCompClustersFlat; + } else if (specconfig.zsOnTheFly) { + const unsigned long long int* buffer = reinterpret_cast<const unsigned long long int*>(&inputZS[0]); + o2::gpu::GPUReconstructionConvert::RunZSEncoderCreateMeta(buffer, tpcZSonTheFlySizes.data(), *&ptrEp, &tpcZS); + ptrs.tpcZS = &tpcZS; + doInputDigits = doInputDigitsMC = specconfig.processMC; + } else if (specconfig.zsDecoder) { + ptrs.tpcZS = &tpcZS; + if (specconfig.processMC) { + throw std::runtime_error("Cannot process MC information, none available"); + } + } else if (specconfig.caClusterer) { + doInputDigits = true; + doInputDigitsMC = specconfig.processMC; + } else { + ptrs.clustersNative = &inputsClustersDigits->clusterIndex; + } + + GPUTrackingInOutDigits tpcDigitsMap; + GPUTPCDigitsMCInput tpcDigitsMapMC; + if (doInputDigits) { + ptrs.tpcPackedDigits = &tpcDigitsMap; + if (doInputDigitsMC) { + tpcDigitsMap.tpcDigitsMC = &tpcDigitsMapMC; + } + for (unsigned int i = 0; i < NSectors; i++) { + tpcDigitsMap.tpcDigits[i] = inputsClustersDigits->inputDigits[i].data(); + tpcDigitsMap.nTPCDigits[i] = inputsClustersDigits->inputDigits[i].size(); + if (doInputDigitsMC) { + tpcDigitsMapMC.v[i] = inputsClustersDigits->inputDigitsMCPtrs[i]; + } + } + } + + // a byte size resizable vector object, the DataAllocator returns reference to internal object + // initialize optional pointer to the vector object + TPCSectorHeader clusterOutputSectorHeader{0}; + if (processAttributes->clusterOutputIds.size() > 0) { + clusterOutputSectorHeader.sectorBits = processAttributes->tpcSectorMask; + // subspecs [0, NSectors - 1] are used to identify sector data, we use NSectors to indicate the full TPC + clusterOutputSectorHeader.activeSectors = processAttributes->tpcSectorMask; + } + + GPUInterfaceOutputs outputRegions; + using outputDataType = char; + using outputBufferUninitializedVector = std::decay_t<decltype(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(Output{"", "", 0}))>; + using outputBufferType = std::pair<std::optional<std::reference_wrapper<outputBufferUninitializedVector>>, outputDataType*>; + std::vector<outputBufferType> outputBuffers(GPUInterfaceOutputs::count(), {std::nullopt, nullptr}); + + auto setOutputAllocator = [&specconfig, &outputBuffers, &outputRegions, &processAttributes, &pc, verbosity](const char* name, bool condition, GPUOutputControl& region, auto&& outputSpec, size_t offset = 0) { + if (condition) { + auto& buffer = outputBuffers[outputRegions.getIndex(region)]; + if (processAttributes->allocateOutputOnTheFly) { + region.allocator = [name, &buffer, &pc, outputSpec = std::move(outputSpec), verbosity, offset](size_t size) -> void* { + size += offset; + if (verbosity) { + LOG(INFO) << "ALLOCATING " << size << " bytes for " << std::get<DataOrigin>(outputSpec).template as<std::string>() << "/" << std::get<DataDescription>(outputSpec).template as<std::string>() << "/" << std::get<2>(outputSpec); + } + std::chrono::time_point<std::chrono::high_resolution_clock> start, end; + if (verbosity) { + start = std::chrono::high_resolution_clock::now(); + } + buffer.first.emplace(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(std::make_from_tuple<Output>(outputSpec), size)); + if (verbosity) { + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double> elapsed_seconds = end - start; + LOG(INFO) << "Allocation time for " << name << " (" << size << " bytes)" << ": " << elapsed_seconds.count() << "s"; + } + return (buffer.second = buffer.first->get().data()) + offset; + }; + } else { + buffer.first.emplace(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(std::make_from_tuple<Output>(outputSpec), processAttributes->outputBufferSize)); + region.ptrBase = (buffer.second = buffer.first->get().data()) + offset; + region.size = buffer.first->get().size() - offset; + } + } + }; + + auto downSizeBuffer = [](outputBufferType& buffer, size_t size) { + if (!buffer.first) { + return; + } + if (buffer.first->get().size() < size) { + throw std::runtime_error("Invalid buffer size requested"); + } + buffer.first->get().resize(size); + if (size && buffer.first->get().data() != buffer.second) { + throw std::runtime_error("Inconsistent buffer address after downsize"); + } + }; + + auto downSizeBufferByName = [&outputBuffers, &outputRegions, &downSizeBuffer](GPUOutputControl& region, size_t size) { + auto& buffer = outputBuffers[outputRegions.getIndex(region)]; + downSizeBuffer(buffer, size); + }; + + auto downSizeBufferToSpan = [&outputBuffers, &outputRegions, &downSizeBuffer](GPUOutputControl& region, auto span) { + auto& buffer = outputBuffers[outputRegions.getIndex(region)]; + if (!buffer.first) { + return; + } + if (span.size() && buffer.second != (char*)span.data()) { + throw std::runtime_error("Buffer does not match span"); + } + downSizeBuffer(buffer, span.size() * sizeof(*span.data())); + }; + + setOutputAllocator("COMPCLUSTERSFLAT", specconfig.outputCompClustersFlat, outputRegions.compressedClusters, std::make_tuple(gDataOriginTPC, (DataDescription) "COMPCLUSTERSFLAT", 0)); + setOutputAllocator("CLUSTERNATIVE", processAttributes->clusterOutputIds.size() > 0, outputRegions.clustersNative, std::make_tuple(gDataOriginTPC, specconfig.sendClustersPerSector ? (DataDescription) "CLUSTERNATIVETMP" : (DataDescription) "CLUSTERNATIVE", NSectors, Lifetime::Timeframe, clusterOutputSectorHeader), sizeof(ClusterCountIndex)); + setOutputAllocator("CLSHAREDMAP", specconfig.outputSharedClusterMap, outputRegions.sharedClusterMap, std::make_tuple(gDataOriginTPC, (DataDescription) "CLSHAREDMAP", 0)); + setOutputAllocator("TRACKS", specconfig.outputTracks, outputRegions.tpcTracksO2, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKS", 0)); + setOutputAllocator("CLUSREFS", specconfig.outputTracks, outputRegions.tpcTracksO2ClusRefs, std::make_tuple(gDataOriginTPC, (DataDescription) "CLUSREFS", 0)); + setOutputAllocator("TRACKSMCLBL", specconfig.outputTracks && specconfig.processMC, outputRegions.tpcTracksO2Labels, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKSMCLBL", 0)); + ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer clustersMCBuffer; + if (specconfig.processMC && specconfig.caClusterer) { + outputRegions.clusterLabels.allocator = [&clustersMCBuffer](size_t size) -> void* { return &clustersMCBuffer; }; + } + + const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().getFirstValid(true).header); + processAttributes->tfSettings.tfStartOrbit = dh->firstTForbit; + processAttributes->tfSettings.hasTfStartOrbit = 1; + ptrs.settingsTF = &processAttributes->tfSettings; + + if (processAttributes->tpcSectorMask != 0xFFFFFFFFF) { + // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash + for (int i = 0; i < NSectors; i++) { + if (!(processAttributes->tpcSectorMask & (1ul << i))) { + if (ptrs.tpcZS) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZS.slice[i].zsPtr[j] = nullptr; + tpcZS.slice[i].nZSPtr[j] = nullptr; + tpcZS.slice[i].count[j] = 0; + } + } + } + } + } + + if ((int)(ptrs.tpcZS != nullptr) + (int)(ptrs.tpcPackedDigits != nullptr && (ptrs.tpcZS == nullptr || ptrs.tpcPackedDigits->tpcDigitsMC == nullptr)) + (int)(ptrs.clustersNative != nullptr) + (int)(ptrs.tpcCompressedClusters != nullptr) != 1) { + throw std::runtime_error("Invalid input for gpu tracking"); + } + + const auto& holdData = TPCTrackingDigitsPreCheck::runPrecheck(&ptrs, processAttributes->config.get()); + int retVal = tracker->RunTracking(&ptrs, &outputRegions); + + tracker->Clear(false); + + if (processAttributes->suppressOutput) { + return; + } + bool createEmptyOutput = false; + if (retVal != 0) { + if (retVal == 3 && processAttributes->config->configProcessing.ignoreNonFatalGPUErrors) { + LOG(ERROR) << "GPU Reconstruction aborted with non fatal error code, ignoring"; + createEmptyOutput = true; + } else { + throw std::runtime_error("tracker returned error code " + std::to_string(retVal)); + } + } + + std::unique_ptr<ClusterNativeAccess> tmpEmptyClNative; + if (createEmptyOutput) { + memset(&ptrs, 0, sizeof(ptrs)); + for (unsigned int i = 0; i < outputRegions.count(); i++) { + if (outputBuffers[i].first) { + size_t toSize = 0; + if (i == outputRegions.getIndex(outputRegions.compressedClusters)) { + toSize = sizeof(*ptrs.tpcCompressedClusters); + } else if (i == outputRegions.getIndex(outputRegions.clustersNative)) { + toSize = sizeof(ClusterCountIndex); + } + outputBuffers[i].first->get().resize(toSize); + outputBuffers[i].second = outputBuffers[i].first->get().data(); + if (toSize) { + memset(outputBuffers[i].second, 0, toSize); + } + } + } + tmpEmptyClNative = std::make_unique<ClusterNativeAccess>(); + memset(tmpEmptyClNative.get(), 0, sizeof(*tmpEmptyClNative)); + ptrs.clustersNative = tmpEmptyClNative.get(); + if (specconfig.processMC) { + MCLabelContainer cont; + cont.flatten_to(clustersMCBuffer.first); + clustersMCBuffer.second = clustersMCBuffer.first; + tmpEmptyClNative->clustersMCTruth = &clustersMCBuffer.second; + } + } else { + gsl::span<const o2::tpc::TrackTPC> spanOutputTracks = {ptrs.outputTracksTPCO2, ptrs.nOutputTracksTPCO2}; + gsl::span<const uint32_t> spanOutputClusRefs = {ptrs.outputClusRefsTPCO2, ptrs.nOutputClusRefsTPCO2}; + gsl::span<const o2::MCCompLabel> spanOutputTracksMCTruth = {ptrs.outputTracksTPCO2MC, ptrs.outputTracksTPCO2MC ? ptrs.nOutputTracksTPCO2 : 0}; + if (!processAttributes->allocateOutputOnTheFly) { + for (unsigned int i = 0; i < outputRegions.count(); i++) { + if (outputRegions.asArray()[i].ptrBase) { + if (outputRegions.asArray()[i].size == 1) { + throw std::runtime_error("Preallocated buffer size exceeded"); + } + outputRegions.asArray()[i].checkCurrent(); + downSizeBuffer(outputBuffers[i], (char*)outputRegions.asArray()[i].ptrCurrent - (char*)outputBuffers[i].second); + } + } + } + downSizeBufferToSpan(outputRegions.tpcTracksO2, spanOutputTracks); + downSizeBufferToSpan(outputRegions.tpcTracksO2ClusRefs, spanOutputClusRefs); + downSizeBufferToSpan(outputRegions.tpcTracksO2Labels, spanOutputTracksMCTruth); + + if (processAttributes->clusterOutputIds.size() > 0 && (void*)ptrs.clustersNative->clustersLinear != (void*)(outputBuffers[outputRegions.getIndex(outputRegions.clustersNative)].second + sizeof(ClusterCountIndex))) { + throw std::runtime_error("cluster native output ptrs out of sync"); // sanity check + } + } + + LOG(INFO) << "found " << ptrs.nOutputTracksTPCO2 << " track(s)"; + + if (specconfig.outputCompClusters) { + CompressedClustersROOT compressedClusters = *ptrs.tpcCompressedClusters; + pc.outputs().snapshot(Output{gDataOriginTPC, "COMPCLUSTERS", 0}, ROOTSerialized<CompressedClustersROOT const>(compressedClusters)); + } + + if (processAttributes->clusterOutputIds.size() > 0) { + ClusterNativeAccess const& accessIndex = *ptrs.clustersNative; + if (specconfig.sendClustersPerSector) { + // Clusters are shipped by sector, we are copying into per-sector buffers (anyway only for ROOT output) + for (int i = 0; i < NSectors; i++) { + if (processAttributes->tpcSectorMask & (1ul << i)) { + DataHeader::SubSpecificationType subspec = i; + clusterOutputSectorHeader.sectorBits = (1ul << i); + char* buffer = pc.outputs().make<char>({gDataOriginTPC, "CLUSTERNATIVE", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear) + sizeof(ClusterCountIndex)).data(); + ClusterCountIndex* outIndex = reinterpret_cast<ClusterCountIndex*>(buffer); + memset(outIndex, 0, sizeof(*outIndex)); + for (int j = 0; j < o2::tpc::constants::MAXGLOBALPADROW; j++) { + outIndex->nClusters[i][j] = accessIndex.nClusters[i][j]; + } + memcpy(buffer + sizeof(*outIndex), accessIndex.clusters[i][0], accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear)); + if (specconfig.processMC && accessIndex.clustersMCTruth) { + MCLabelContainer cont; + for (int j = 0; j < accessIndex.nClustersSector[i]; j++) { + const auto& labels = accessIndex.clustersMCTruth->getLabels(accessIndex.clusterOffset[i][0] + j); + for (const auto& label : labels) { + cont.addElement(j, label); + } + } + ConstMCLabelContainer contflat; + cont.flatten_to(contflat); + pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, contflat); + } + } + } + } else { + // Clusters are shipped as single message, fill ClusterCountIndex + DataHeader::SubSpecificationType subspec = NSectors; + ClusterCountIndex* outIndex = reinterpret_cast<ClusterCountIndex*>(outputBuffers[outputRegions.getIndex(outputRegions.clustersNative)].second); + static_assert(sizeof(ClusterCountIndex) == sizeof(accessIndex.nClusters)); + memcpy(outIndex, &accessIndex.nClusters[0][0], sizeof(ClusterCountIndex)); + if (specconfig.processMC && specconfig.caClusterer && accessIndex.clustersMCTruth) { + pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {clusterOutputSectorHeader}}, clustersMCBuffer.first); + } + } + } + if (specconfig.outputQA) { + TObjArray out; + auto getoutput = [createEmptyOutput](auto ptr) { return ptr && !createEmptyOutput ? *ptr : std::decay_t<decltype(*ptr)>(); }; + std::vector<TH1F> copy1 = getoutput(outputRegions.qa.hist1); // Internally, this will also be used as output, so we need a non-const copy + std::vector<TH2F> copy2 = getoutput(outputRegions.qa.hist2); + std::vector<TH1D> copy3 = getoutput(outputRegions.qa.hist3); + processAttributes->qa->postprocessExternal(copy1, copy2, copy3, out, processAttributes->qaTaskMask ? processAttributes->qaTaskMask : -1); + pc.outputs().snapshot({gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe}, out); + processAttributes->qa->cleanup(); + } + timer.Stop(); + LOG(INFO) << "GPU Reoncstruction time for this TF " << timer.CpuTime() - cput << " s (cpu), " << timer.RealTime() - realt << " s (wall)"; + }; + + return processingFct; + }; + + // FIXME: find out how to handle merge inputs in a simple and intuitive way + // changing the binding name of the input in order to identify inputs by unique labels + // in the processing. Think about how the processing can be made agnostic of input size, + // e.g. by providing a span of inputs under a certain label + auto createInputSpecs = [&tpcsectors, &specconfig, policyData]() { + Inputs inputs; + if (specconfig.decompressTPC) { + inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, specconfig.decompressTPCFromROOT ? o2::header::DataDescription("COMPCLUSTERS") : o2::header::DataDescription("COMPCLUSTERSFLAT")}, Lifetime::Timeframe}); + } else if (specconfig.caClusterer) { + // We accept digits and MC labels also if we run on ZS Raw data, since they are needed for MC label propagation + if ((!specconfig.zsOnTheFly || specconfig.processMC) && !specconfig.zsDecoder) { + inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe}); + policyData->emplace_back(o2::framework::InputSpec{"digits", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITS"}}); + } + } else { + inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe}); + policyData->emplace_back(o2::framework::InputSpec{"clusters", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}}); + } + if (specconfig.processMC) { + if (specconfig.caClusterer) { + if (!specconfig.zsDecoder) { + inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}, Lifetime::Timeframe}); + policyData->emplace_back(o2::framework::InputSpec{"digitsmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITSMCTR"}}); + } + } else { + inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "CLNATIVEMCLBL"}, Lifetime::Timeframe}); + policyData->emplace_back(o2::framework::InputSpec{"clustersmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}}); + } + } + + if (specconfig.zsDecoder) { + // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution + // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA + inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Optional}); + if (specconfig.askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + } + if (specconfig.zsOnTheFly) { + inputs.emplace_back(InputSpec{"zsinput", ConcreteDataTypeMatcher{"TPC", "TPCZS"}, Lifetime::Timeframe}); + inputs.emplace_back(InputSpec{"zsinputsizes", ConcreteDataTypeMatcher{"TPC", "ZSSIZES"}, Lifetime::Timeframe}); + } + if (specconfig.readTRDtracklets) { + inputs.emplace_back("trdctracklets", o2::header::gDataOriginTRD, "CTRACKLETS", 0, Lifetime::Timeframe); + inputs.emplace_back("trdtracklets", o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe); + inputs.emplace_back("trdtriggerrec", o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe); + } + return inputs; + }; + + auto createOutputSpecs = [&specconfig, &tpcsectors, &processAttributes]() { + std::vector<OutputSpec> outputSpecs; + if (specconfig.outputTracks) { + outputSpecs.emplace_back(gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe); + } + if (specconfig.processMC && specconfig.outputTracks) { + outputSpecs.emplace_back(gDataOriginTPC, "TRACKSMCLBL", 0, Lifetime::Timeframe); + } + if (specconfig.outputCompClusters) { + outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERS", 0, Lifetime::Timeframe); + } + if (specconfig.outputCompClustersFlat) { + outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe); + } + if (specconfig.outputCAClusters) { + for (auto const& sector : tpcsectors) { + processAttributes->clusterOutputIds.emplace_back(sector); + } + outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", specconfig.sendClustersPerSector ? 0 : NSectors, Lifetime::Timeframe); + if (specconfig.sendClustersPerSector) { + outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVETMP", NSectors, Lifetime::Timeframe); // Dummy buffer the TPC tracker writes the inital linear clusters to + for (const auto sector : tpcsectors) { + outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", sector, Lifetime::Timeframe); + } + } else { + outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", NSectors, Lifetime::Timeframe); + } + if (specconfig.processMC) { + if (specconfig.sendClustersPerSector) { + for (const auto sector : tpcsectors) { + outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", sector, Lifetime::Timeframe); + } + } else { + outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", NSectors, Lifetime::Timeframe); + } + } + } + if (specconfig.outputSharedClusterMap) { + outputSpecs.emplace_back(gDataOriginTPC, "CLSHAREDMAP", 0, Lifetime::Timeframe); + } + if (specconfig.outputQA) { + outputSpecs.emplace_back(gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe); + } + return std::move(outputSpecs); + }; + + return DataProcessorSpec{processorName, // process id + {createInputSpecs()}, + {createOutputSpecs()}, + AlgorithmSpec(initFunction)}; +} +} // namespace o2::gpu diff --git a/GPU/Workflow/src/O2GPUDPLDisplay.cxx b/GPU/Workflow/src/O2GPUDPLDisplay.cxx new file mode 100644 index 0000000000000..efda6009f4cc3 --- /dev/null +++ b/GPU/Workflow/src/O2GPUDPLDisplay.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GPUWorkflow/O2GPUDPLDisplay.h" +#include "Framework/ConfigParamSpec.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsBase/GeometryManager.h" +#include "TRDBase/GeometryFlat.h" +#include "TRDBase/Geometry.h" +#include "TOFBase/Geo.h" +#include "ITSBase/GeometryTGeo.h" +#include "DetectorsBase/Propagator.h" +#include "GPUO2InterfaceDisplay.h" +#include "GPUO2InterfaceConfiguration.h" +#include "TPCFastTransform.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "GPUWorkflowHelper/GPUWorkflowHelper.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" + +using namespace o2::framework; +using namespace o2::dataformats; +using namespace o2::globaltracking; +using namespace o2::gpu; +using namespace o2::tpc; +using namespace o2::trd; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + std::vector<o2::framework::ConfigParamSpec> options{ + {"enable-mc", o2::framework::VariantType::Bool, false, {"enable visualization of MC data"}}, + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable visualization of MC data"}}, // for compatibility, overrides enable-mc + {"display-clusters", VariantType::String, "ITS,TPC,TRD,TOF", {"comma-separated list of clusters to display"}}, + {"display-tracks", VariantType::String, "TPC,ITS,ITS-TPC,TPC-TRD,ITS-TPC-TRD,TPC-TOF,ITS-TPC-TOF", {"comma-separated list of tracks to display"}}, + {"read-from-files", o2::framework::VariantType::Bool, false, {"comma-separated list of tracks to display"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"Disable root input overriding read-from-files"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +void O2GPUDPLDisplaySpec::init(InitContext& ic) +{ + const auto grp = o2::parameters::GRPObject::loadFrom(); + o2::base::GeometryManager::loadGeometry(); + o2::base::Propagator::initFieldFromGRP(); + mConfig.reset(new GPUO2InterfaceConfiguration); + mConfig->configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + mConfig->configGRP.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; // Number of timebins in timeframe if continuous, 0 otherwise + mConfig->ReadConfigurableParam(); + + mFastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0)); + mConfig->configCalib.fastTransform = mFastTransform.get(); + + auto gm = o2::trd::Geometry::instance(); + gm->createPadPlaneArray(); + gm->createClusterMatrixArray(); + mTrdGeo.reset(new o2::trd::GeometryFlat(*gm)); + mConfig->configCalib.trdGeometry = mTrdGeo.get(); + + mITSDict = std::make_unique<o2::itsmft::TopologyDictionary>(); + mConfig->configCalib.itsPatternDict = mITSDict.get(); + + mConfig->configProcessing.runMC = mUseMC; + + o2::tof::Geo::Init(); + + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2L)); + + mDisplay.reset(new GPUO2InterfaceDisplay(mConfig.get())); +} + +void O2GPUDPLDisplaySpec::run(ProcessingContext& pc) +{ + static bool first = false; + if (first == false) { + if (mDisplay->startDisplay()) { + throw std::runtime_error("Error starting event display"); + } + } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest); + GPUTrackingInOutPointers ptrs; + auto tmpContainer = GPUWorkflowHelper::fillIOPtr(ptrs, recoData, mUseMC, &(mConfig->configCalib), mClMask, mTrkMask, mTrkMask); + + mDisplay->show(&ptrs); +} + +void O2GPUDPLDisplaySpec::endOfStream(EndOfStreamContext& ec) +{ + mDisplay->endDisplay(); +} + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + + bool useMC = cfgc.options().get<bool>("enable-mc") && !cfgc.options().get<bool>("disable-mc"); + GlobalTrackID::mask_t srcTrk = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("display-tracks")); + GlobalTrackID::mask_t srcCl = GlobalTrackID::getSourcesMask(cfgc.options().get<std::string>("display-clusters")); + if (!srcTrk.any() && !srcCl.any()) { + throw std::runtime_error("No input configured"); + } + std::shared_ptr<DataRequest> dataRequest = std::make_shared<DataRequest>(); + dataRequest->requestTracks(srcTrk, useMC); + dataRequest->requestClusters(srcCl, useMC); + + if (cfgc.options().get<bool>("read-from-files")) { + InputHelper::addInputSpecs(cfgc, specs, srcCl, srcTrk, srcTrk, useMC); + } + + specs.emplace_back(DataProcessorSpec{ + "o2-gpu-display", + dataRequest->inputs, + {}, + AlgorithmSpec{adaptFromTask<O2GPUDPLDisplaySpec>(useMC, srcTrk, srcCl, dataRequest)}}); + + return std::move(specs); +} diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx new file mode 100644 index 0000000000000..86ecbca8e1960 --- /dev/null +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -0,0 +1,150 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file gpu-reco-workflow.cxx +/// @author David Rohr + +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/ConcreteDataMatcher.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "GPUWorkflow/GPUWorkflowSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "TPCBase/Sector.h" +#include "Algorithm/RangeTokenizer.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +#include <unordered_map> + +using namespace o2::framework; +using namespace o2::dataformats; +using CompletionPolicyData = std::vector<InputSpec>; +CompletionPolicyData gPolicyData; +static constexpr unsigned long gTpcSectorMask = 0xFFFFFFFFF; + +void customize(std::vector<ConfigParamSpec>& workflowOptions) +{ + + std::vector<ConfigParamSpec> options{ + {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, zsonthefly, clustersnative, compressed-clusters-root, compressed-clusters-ctf, trd-tracklets"}}, + {"output-type", VariantType::String, "tracks", {"clustersnative, tracks, compressed-clusters-ctf, qa, no-shared-cluster-map"}}, + {"disable-root-input", VariantType::Bool, true, {"disable root-files input reader"}}, + {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, + {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCHwClusterer.peakChargeThreshold=4;...')"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; + + o2::raw::HBFUtilsInitializer::addConfigOption(options); + + std::swap(workflowOptions, options); +} + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector<DispatchPolicy>& policies) +{ + using DispatchOp = DispatchPolicy::DispatchOp; + policies.push_back({"prompt-for-gpu-reco", [](auto const& spec) { return true; }, DispatchOp::WhenReady}); +} + +void customize(std::vector<CompletionPolicy>& policies) +{ + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("gpu-reconstruction.*", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData, &gTpcSectorMask)()); +} + +#include "Framework/runDataProcessing.h" // the main driver + +using namespace o2::framework; + +enum struct ioType { Digits, + Clusters, + ZSRaw, + ZSRawOTF, + CompClustROOT, + CompClustCTF, + Tracks, + QA, + TRDTracklets, + NoSharedMap }; + +static const std::unordered_map<std::string, ioType> InputMap{ + {"digits", ioType::Digits}, + {"clusters", ioType::Clusters}, + {"zsraw", ioType::ZSRaw}, + {"zsonthefly", ioType::ZSRawOTF}, + {"compressed-clusters-root", ioType::CompClustROOT}, + {"compressed-clusters-ctf", ioType::CompClustCTF}, + {"trd-tracklets", ioType::TRDTracklets}}; + +static const std::unordered_map<std::string, ioType> OutputMap{ + {"clusters", ioType::Clusters}, + {"tracks", ioType::Tracks}, + {"compressed-clusters-ctf", ioType::CompClustCTF}, + {"qa", ioType::QA}, + {"no-shared-cluster-map", ioType::NoSharedMap}}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + std::vector<int> tpcSectors(o2::tpc::Sector::MAXSECTOR); + std::iota(tpcSectors.begin(), tpcSectors.end(), 0); + + auto inputType = cfgc.options().get<std::string>("input-type"); + bool doMC = !cfgc.options().get<bool>("disable-mc"); + + o2::conf::ConfigurableParam::updateFromFile(cfgc.options().get<std::string>("configFile")); + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2gpurecoworkflow_configuration.ini"); + + std::vector<ioType> outputTypes, inputTypes; + try { + outputTypes = o2::RangeTokenizer::tokenize<ioType>(cfgc.options().get<std::string>("output-type"), [](std::string const& token) { return OutputMap.at(token); }); + inputTypes = o2::RangeTokenizer::tokenize<ioType>(cfgc.options().get<std::string>("input-type"), [](std::string const& token) { return InputMap.at(token); }); + } catch (std::out_of_range&) { + throw std::invalid_argument("invalid input / output type"); + } + + auto isEnabled = [](auto& list, ioType type) { + return std::find(list.begin(), list.end(), type) != list.end(); + }; + + o2::gpu::gpuworkflow::Config cfg; + cfg.decompressTPC = isEnabled(inputTypes, ioType::CompClustCTF); + cfg.decompressTPCFromROOT = isEnabled(inputTypes, ioType::CompClustROOT); + cfg.zsDecoder = isEnabled(inputTypes, ioType::ZSRaw); + cfg.zsOnTheFly = isEnabled(inputTypes, ioType::ZSRawOTF); + cfg.caClusterer = cfg.zsDecoder || cfg.zsOnTheFly || isEnabled(inputTypes, ioType::Digits); + cfg.outputTracks = isEnabled(outputTypes, ioType::Tracks); + cfg.outputCompClusters = isEnabled(outputTypes, ioType::CompClustROOT); + cfg.outputCompClustersFlat = isEnabled(outputTypes, ioType::CompClustCTF); + cfg.outputCAClusters = isEnabled(outputTypes, ioType::Clusters); + cfg.outputQA = isEnabled(outputTypes, ioType::QA); + cfg.outputSharedClusterMap = (cfg.outputCAClusters || cfg.caClusterer || isEnabled(inputTypes, ioType::Clusters)) && cfg.outputTracks && !isEnabled(outputTypes, ioType::NoSharedMap); + cfg.processMC = doMC; + cfg.sendClustersPerSector = false; + cfg.askDISTSTF = !cfgc.options().get<bool>("ignore-dist-stf"); + cfg.readTRDtracklets = isEnabled(inputTypes, ioType::TRDTracklets); + specs.emplace_back(o2::gpu::getGPURecoWorkflowSpec(&gPolicyData, cfg, tpcSectors, gTpcSectorMask, "gpu-reconstruction")); + + if (!cfgc.options().get<bool>("ignore-dist-stf")) { + GlobalTrackID::mask_t srcTrk = GlobalTrackID::getSourcesMask("none"); + GlobalTrackID::mask_t srcCl = GlobalTrackID::getSourcesMask("TPC"); + o2::globaltracking::InputHelper::addInputSpecs(cfgc, specs, srcCl, srcTrk, srcTrk, doMC); + } + + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); + + return std::move(specs); +} diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 7985ed8283501..fe8868aaa9747 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. if(pythia6_FOUND) set(pythia6Target ROOT::EGPythia6 MC::Pythia6) @@ -27,6 +28,7 @@ o2_add_library(Generators src/GeneratorTGenerator.cxx src/GeneratorExternalParam.cxx src/GeneratorFromFile.cxx + src/GeneratorFromO2KineParam.cxx src/PDG.cxx src/PrimaryGenerator.cxx src/InteractionDiamondParam.cxx @@ -68,12 +70,12 @@ set(headers include/Generators/GeneratorTGenerator.h include/Generators/GeneratorExternalParam.h include/Generators/GeneratorFromFile.h + include/Generators/GeneratorFromO2KineParam.h include/Generators/PDG.h include/Generators/PrimaryGenerator.h include/Generators/InteractionDiamondParam.h include/Generators/TriggerExternalParam.h include/Generators/TriggerParticleParam.h - include/Generators/ConfigurationMacroHelper.h include/Generators/BoxGunParam.h include/Generators/QEDGenParam.h include/Generators/GenCosmicsParam.h) diff --git a/Generators/include/Generators/BoxGunParam.h b/Generators/include/Generators/BoxGunParam.h index 1967d53d90679..ad93ebf7d760c 100644 --- a/Generators/include/Generators/BoxGunParam.h +++ b/Generators/include/Generators/BoxGunParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/DecayerPythia8.h b/Generators/include/Generators/DecayerPythia8.h index fafdccf2f7cac..c158782bedceb 100644 --- a/Generators/include/Generators/DecayerPythia8.h +++ b/Generators/include/Generators/DecayerPythia8.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/DecayerPythia8Param.h b/Generators/include/Generators/DecayerPythia8Param.h index b3f2397af94d8..f33a3075abc52 100644 --- a/Generators/include/Generators/DecayerPythia8Param.h +++ b/Generators/include/Generators/DecayerPythia8Param.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GenCosmicsParam.h b/Generators/include/Generators/GenCosmicsParam.h index 372bd9ec3b0a0..c462d6b9e927b 100644 --- a/Generators/include/Generators/GenCosmicsParam.h +++ b/Generators/include/Generators/GenCosmicsParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 9f8d3a23c1085..6f2fc8ea8502d 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,16 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" +#include <functional> #include <vector> -class FairMCEventHeader; +namespace o2 +{ +namespace dataformats +{ +class MCEventHeader; +} +} // namespace o2 namespace o2 { @@ -59,7 +67,11 @@ class Generator : public FairGenerator *@param pStack The stack *@return kTRUE if successful, kFALSE if not **/ - Bool_t ReadEvent(FairPrimaryGenerator* primGen) override; + Bool_t ReadEvent(FairPrimaryGenerator* primGen) final; + + /** methods to override **/ + virtual Bool_t generateEvent() = 0; + virtual Bool_t importParticles() = 0; /** setters **/ void setMomentumUnit(double val) { mMomentumUnit = val; }; @@ -71,8 +83,17 @@ class Generator : public FairGenerator void addTrigger(Trigger trigger) { mTriggers.push_back(trigger); }; void addDeepTrigger(DeepTrigger trigger) { mDeepTriggers.push_back(trigger); }; + /** getters **/ + const std::vector<TParticle>& getParticles() const { return mParticles; }; //! + + /** other **/ + void clearParticles() { mParticles.clear(); }; + /** notification methods **/ - virtual void notifyEmbedding(const FairMCEventHeader* mcHeader){}; + virtual void notifyEmbedding(const o2::dataformats::MCEventHeader* eventHeader){}; + + void setTriggerOkHook(std::function<void(std::vector<TParticle> const& p, int eventCount)> f) { mTriggerOkHook = f; } + void setTriggerFalseHook(std::function<void(std::vector<TParticle> const& p, int eventCount)> f) { mTriggerFalseHook = f; } protected: /** copy constructor **/ @@ -80,12 +101,8 @@ class Generator : public FairGenerator /** operator= **/ Generator& operator=(const Generator&); - /** methods to override **/ - virtual Bool_t generateEvent() = 0; - virtual Bool_t importParticles() = 0; - /** methods that can be overridded **/ - virtual void updateHeader(FairMCEventHeader* eventHeader){}; + virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader){}; /** internal methods **/ Bool_t addTracks(FairPrimaryGenerator* primGen); @@ -101,6 +118,12 @@ class Generator : public FairGenerator std::vector<Trigger> mTriggers; //! std::vector<DeepTrigger> mDeepTriggers; //! + // we allow to register callbacks so as to take specific user actions when + // a trigger was ok nor not + std::function<void(std::vector<TParticle> const& p, int eventCount)> mTriggerOkHook = [](std::vector<TParticle> const& p, int eventCount) {}; + std::function<void(std::vector<TParticle> const& p, int eventCount)> mTriggerFalseHook = [](std::vector<TParticle> const& p, int eventCount) {}; + int mReadEventCounter = 0; // counting the number of times + /** conversion data members **/ double mMomentumUnit = 1.; // [GeV/c] double mEnergyUnit = 1.; // [GeV/c] diff --git a/Generators/include/Generators/GeneratorExternalParam.h b/Generators/include/Generators/GeneratorExternalParam.h index 1fa2fa860cae1..e55d184af9dda 100644 --- a/Generators/include/Generators/GeneratorExternalParam.h +++ b/Generators/include/Generators/GeneratorExternalParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorFactory.h b/Generators/include/Generators/GeneratorFactory.h index 35deca12cf312..9f4dfb5514582 100644 --- a/Generators/include/Generators/GeneratorFactory.h +++ b/Generators/include/Generators/GeneratorFactory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorFromFile.h b/Generators/include/Generators/GeneratorFromFile.h index 42038353e5937..13b6239189a38 100644 --- a/Generators/include/Generators/GeneratorFromFile.h +++ b/Generators/include/Generators/GeneratorFromFile.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #define ALICEO2_GENERATORFROMFILE_H_ #include "FairGenerator.h" +#include "Generators/Generator.h" class TBranch; class TFile; @@ -58,6 +60,41 @@ class GeneratorFromFile : public FairGenerator ClassDefOverride(GeneratorFromFile, 1); }; +/// This class implements a generic FairGenerator which +/// reads the particles from an external O2 sim kinematics file. +class GeneratorFromO2Kine : public o2::eventgen::Generator +{ + public: + GeneratorFromO2Kine() = default; + GeneratorFromO2Kine(const char* name); + + bool Init() override; + + // the o2 Generator interface methods + bool generateEvent() override + { /* trivial - actual work in importParticles */ + return true; + } + bool importParticles() override; + + // Set from which event to start + void SetStartEvent(int start); + + void setContinueMode(bool val) { mContinueMode = val; }; + + private: + /** methods that can be overridden **/ + void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; + + TFile* mEventFile = nullptr; //! the file containing the persistent events + TBranch* mEventBranch = nullptr; //! the branch containing the persistent events + int mEventCounter = 0; + int mEventsAvailable = 0; + bool mSkipNonTrackable = true; //! whether to pass non-trackable (decayed particles) to the MC stack + bool mContinueMode = false; //! whether we want to continue simulation of previously inhibited tracks + ClassDefOverride(GeneratorFromO2Kine, 1); +}; + } // end namespace eventgen } // end namespace o2 diff --git a/Generators/include/Generators/GeneratorFromO2KineParam.h b/Generators/include/Generators/GeneratorFromO2KineParam.h new file mode 100644 index 0000000000000..56642ccdd52db --- /dev/null +++ b/Generators/include/Generators/GeneratorFromO2KineParam.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author R+Preghenella - January 2021 + +#ifndef ALICEO2_EVENTGEN_GENERATORFROMO2KINEPARAM_H_ +#define ALICEO2_EVENTGEN_GENERATORFROMO2KINEPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace eventgen +{ + +/** + ** a parameter class/struct to keep the settings of + ** the FromO2Kine event generator and + ** allow the user to modify them + **/ + +struct GeneratorFromO2KineParam : public o2::conf::ConfigurableParamHelper<GeneratorFromO2KineParam> { + bool skipNonTrackable = true; + bool continueMode = false; + O2ParamDef(GeneratorFromO2KineParam, "GeneratorFromO2Kine"); +}; + +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_GENERATORFROMO2KINEPARAM_H_ diff --git a/Generators/include/Generators/GeneratorHepMC.h b/Generators/include/Generators/GeneratorHepMC.h index cca39d7d2f02e..b3f329d2465ba 100644 --- a/Generators/include/Generators/GeneratorHepMC.h +++ b/Generators/include/Generators/GeneratorHepMC.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,6 +55,10 @@ class GeneratorHepMC : public Generator /** Initialize the generator if needed **/ Bool_t Init() override; + /** methods to override **/ + Bool_t generateEvent() override; + Bool_t importParticles() override; + /** setters **/ void setVersion(Int_t val) { mVersion = val; }; void setFileName(std::string val) { mFileName = val; }; @@ -64,10 +69,6 @@ class GeneratorHepMC : public Generator /** operator= **/ GeneratorHepMC& operator=(const GeneratorHepMC&); - /** methods to override **/ - Bool_t generateEvent() override; - Bool_t importParticles() override; - /** methods **/ #ifdef GENERATORS_WITH_HEPMC3_DEPRECATED const HepMC::FourVector getBoostedVector(const HepMC::FourVector& vector, Double_t boost); diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index 0c2826a687c85..6ef5fd97c854a 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorPythia6.h b/Generators/include/Generators/GeneratorPythia6.h index 32db581656034..335c3ad5944ca 100644 --- a/Generators/include/Generators/GeneratorPythia6.h +++ b/Generators/include/Generators/GeneratorPythia6.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorPythia6Param.h b/Generators/include/Generators/GeneratorPythia6Param.h index 8551caf334520..f2375bb2ae194 100644 --- a/Generators/include/Generators/GeneratorPythia6Param.h +++ b/Generators/include/Generators/GeneratorPythia6Param.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorPythia8.h b/Generators/include/Generators/GeneratorPythia8.h index c743c931aefc9..f54c2f439b47a 100644 --- a/Generators/include/Generators/GeneratorPythia8.h +++ b/Generators/include/Generators/GeneratorPythia8.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,6 +39,10 @@ class GeneratorPythia8 : public Generator /** Initialize the generator if needed **/ Bool_t Init() override; + /** methods to override **/ + Bool_t generateEvent() override; + Bool_t importParticles() override { return importParticles(mPythia.event); }; + /** setters **/ void setConfig(std::string val) { mConfig = val; }; void setHooksFileName(std::string val) { mHooksFileName = val; }; @@ -55,24 +60,42 @@ class GeneratorPythia8 : public Generator bool readString(std::string val) { return mPythia.readString(val, true); }; bool readFile(std::string val) { return mPythia.readFile(val, true); }; + /** utilities **/ + void getNcoll(int& nColl) + { + getNcoll(mPythia.info, nColl); + }; + void getNpart(int& nPart) + { + getNpart(mPythia.info, nPart); + }; + void getNpart(int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg) + { + getNpart(mPythia.info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); + }; + void getNremn(int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg) + { + getNremn(mPythia.event, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); + }; + protected: /** copy constructor **/ GeneratorPythia8(const GeneratorPythia8&); /** operator= **/ GeneratorPythia8& operator=(const GeneratorPythia8&); - /** methods to override **/ - Bool_t generateEvent() override; - Bool_t importParticles() override { return importParticles(mPythia.event); }; - /** methods that can be overridded **/ - void updateHeader(FairMCEventHeader* eventHeader) override; + void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; /** internal methods **/ Bool_t importParticles(Pythia8::Event& event); /** utilities **/ void selectFromAncestor(int ancestor, Pythia8::Event& inputEvent, Pythia8::Event& outputEvent); + void getNcoll(const Pythia8::Info& info, int& nColl); + void getNpart(const Pythia8::Info& info, int& nPart); + void getNpart(const Pythia8::Info& info, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg); + void getNremn(const Pythia8::Event& event, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg); /** Pythia8 **/ Pythia8::Pythia mPythia; //! diff --git a/Generators/include/Generators/GeneratorPythia8Param.h b/Generators/include/Generators/GeneratorPythia8Param.h index e9133da76e6f0..a09ec839c320d 100644 --- a/Generators/include/Generators/GeneratorPythia8Param.h +++ b/Generators/include/Generators/GeneratorPythia8Param.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/GeneratorTGenerator.h b/Generators/include/Generators/GeneratorTGenerator.h index 72dfe17a4a003..6a5298161de0c 100644 --- a/Generators/include/Generators/GeneratorTGenerator.h +++ b/Generators/include/Generators/GeneratorTGenerator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -37,6 +38,10 @@ class GeneratorTGenerator : public Generator /** destructor **/ ~GeneratorTGenerator() override; + /** methods to override **/ + Bool_t generateEvent() override; + Bool_t importParticles() override; + /** setters **/ void setTGenerator(TGenerator* val) { mTGenerator = val; }; const TGenerator* getTGenerator() const { return mTGenerator; } @@ -49,10 +54,6 @@ class GeneratorTGenerator : public Generator /** operator= **/ GeneratorTGenerator& operator=(const GeneratorTGenerator&); - /** methods to override **/ - Bool_t generateEvent() override; - Bool_t importParticles() override; - /** TGenerator interface **/ TGenerator* mTGenerator; TClonesArray* mCloneParticles; diff --git a/Generators/include/Generators/InteractionDiamondParam.h b/Generators/include/Generators/InteractionDiamondParam.h index 787117ffd272e..1a8f0504dd984 100644 --- a/Generators/include/Generators/InteractionDiamondParam.h +++ b/Generators/include/Generators/InteractionDiamondParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/PDG.h b/Generators/include/Generators/PDG.h index 5f51b335280c6..b98bf56dd75bf 100644 --- a/Generators/include/Generators/PDG.h +++ b/Generators/include/Generators/PDG.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/PrimaryGenerator.h b/Generators/include/Generators/PrimaryGenerator.h index 9c576118fcbca..ba2f7815a2fa1 100644 --- a/Generators/include/Generators/PrimaryGenerator.h +++ b/Generators/include/Generators/PrimaryGenerator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/Pythia6Generator.h b/Generators/include/Generators/Pythia6Generator.h deleted file mode 100644 index 9dd94f2ff714e..0000000000000 --- a/Generators/include/Generators/Pythia6Generator.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/******************************************************************************** - * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence version 3 (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ -// ------------------------------------------------------------------------- -// ----- M. Al-Turany June 2014 ----- -// ------------------------------------------------------------------------- - -// ------------------------------------------------------------------------- -// ----- Pythia6Generator header file ----- -// ----- Created 08/08/08 by S. Spataro ----- -// ------------------------------------------------------------------------- - -/** Pythia6Generator.h - *@author S.Spataro <spataro@to.infn.it> - * - The Pythia6Generator reads a Pythia6 input file. The file must contain - for each event a header line of the format: - - [start] -1 20 - 3 -2212 0 0 0 0 0.00000000E+00 0.00000000E+00 0.14000000E+02 0.14031406E+02 0.93827000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 2212 0 0 0 0 0.00000000E+00 0.00000000E+00 -0.13444107E-16 0.93827000E+00 0.93827000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 -2 1 0 0 0 -0.70661074E+00 -0.81156104E+00 0.49379331E+01 0.50538217E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 2 2 0 0 0 -0.79043780E+00 0.32642680E+00 0.10299757E+01 0.13387293E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 -2 3 0 0 0 -0.70661074E+00 -0.81156104E+00 0.49379331E+01 0.50538217E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 2 4 0 0 0 -0.79043780E+00 0.32642680E+00 0.10299757E+01 0.13387293E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 23 5 6 0 0 -0.14970485E+01 -0.48513424E+00 0.59679088E+01 0.63925510E+01 0.16650116E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 11 7 0 0 0 -0.16024130E+01 0.20883507E-01 0.32233123E+01 0.35997091E+01 0.51000000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 -11 7 0 0 0 0.10536443E+00 -0.50601774E+00 0.27445965E+01 0.27928419E+01 0.51000000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 23 7 0 11 13 -0.14970485E+01 -0.48513424E+00 0.59679088E+01 0.63925510E+01 0.16650116E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 -11 9 0 0 0 0.10536442E+00 -0.50601769E+00 0.27445962E+01 0.27928416E+01 0.51000000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 11 8 0 0 0 -0.16017105E+01 0.20863360E-01 0.32218964E+01 0.35981284E+01 0.51000000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 22 8 0 0 0 -0.70246172E-03 0.20096726E-04 0.14161816E-02 0.15809575E-02 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 -2103 1 0 16 16 0.70661074E+00 0.81156104E+00 0.69735272E+01 0.70980957E+01 0.77133000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 2101 2 0 16 16 0.79043780E+00 -0.32642680E+00 0.10585640E+01 0.14790292E+01 0.57933000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 92 14 15 17 18 0.14970485E+01 0.48513424E+00 0.80320912E+01 0.85771248E+01 0.25643853E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 -2214 16 0 19 20 0.81382620E+00 0.70515618E+00 0.61830559E+01 0.63829315E+01 0.11627878E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 2212 16 0 0 0 0.68322234E+00 -0.22002195E+00 0.18490353E+01 0.21941934E+01 0.93827000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 -2112 17 0 0 0 0.78494059E+00 0.52384336E+00 0.55944336E+01 0.57507411E+01 0.93957000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1 -211 17 0 0 0 0.28885610E-01 0.18131282E+00 0.58862227E+00 0.63219038E+00 0.13957000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2 25 - 3 -2212 0 0 0 0 0.00000000E+00 0.00000000E+00 0.14000000E+02 0.14031406E+02 0.93827000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3 2212 0 0 0 0 0.00000000E+00 0.00000000E+00 -0.13444107E-16 0.93827000E+00 0.93827000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 - - -... - [stop] - - where the first row has the number of event and the number of particles, and below "N" is the line - number of the event, - - Derived from FairGenerator. -**/ - -#ifndef PND_PYTHIAGENERATOR_H -#define PND_PYTHIAGENERATOR_H - -#ifdef __CLING__ -#define _DLFCN_H_ -#define _DLFCN_H -#endif - -#include <cstdio> // for FILE -#include "FairGenerator.h" // for FairGenerator -#include "Rtypes.h" // for Int_t, Pythia6Generator::Class, Bool_t, etc -class FairPrimaryGenerator; // lines 68-68 - -namespace o2 -{ -namespace eventgen -{ - -class Pythia6Generator : public FairGenerator -{ - - public: - /** Default constructor without arguments should not be used. **/ - Pythia6Generator(); - - /** Standard constructor. - ** @param fileName The input file name - **/ - Pythia6Generator(const char* fileName); - - /** Destructor. **/ - ~Pythia6Generator() override; - - /** Reads on event from the input file and pushes the tracks onto - ** the stack. Abstract method in base class. - ** @param primGen pointer to the CbmrimaryGenerator - **/ - Bool_t ReadEvent(FairPrimaryGenerator* primGen) override; - - void SetVerbose(Int_t verb) { mVerbose = verb; }; - - private: - const Char_t* mFileName; //! Input file Name - FILE* mInputFile; //! File - Int_t mVerbose; //! Verbose Level - - /** Private method CloseInput. Just for convenience. Closes the - ** input file properly. Called from destructor and from ReadEvent. **/ - void CloseInput(); - - /** PDG data base */ - - // TDatabasePDG *mPDG; //! - - ClassDefOverride(Pythia6Generator, 1); -}; - -} // namespace eventgen -} // namespace o2 -#endif diff --git a/Generators/include/Generators/Pythia8Generator.h b/Generators/include/Generators/Pythia8Generator.h deleted file mode 100644 index 9b60415dd5504..0000000000000 --- a/Generators/include/Generators/Pythia8Generator.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/******************************************************************************** - * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence version 3 (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ -// ------------------------------------------------------------------------- -// ----- M. Al-Turany June 2014 ----- -// ------------------------------------------------------------------------- - -#ifndef PNDP8GENERATOR_H -#define PNDP8GENERATOR_H 1 - -#include "FairGenerator.h" // for FairGenerator -#include "Rtypes.h" // for Double_t, Bool_t, Int_t, etc -#include <memory> - -class FairPrimaryGenerator; -namespace Pythia8 -{ -class Pythia; -class RndmEngine; -} // namespace Pythia8 -namespace o2 -{ -namespace eventgen -{ - -class Pythia8Generator : public FairGenerator -{ - public: - /** default constructor **/ - Pythia8Generator(); - - /** destructor **/ - ~Pythia8Generator() override; - - /** public method ReadEvent **/ - Bool_t ReadEvent(FairPrimaryGenerator*) override; - void SetParameters(const char*); - void Print(); //! - - Bool_t Init() override; //! - - void SetMom(Double_t mom) { mMom = mom; }; - void SetId(Double_t id) { mId = id; }; - void SetHNLId(Int_t id) { mHNL = id; }; - void UseRandom1() - { - mUseRandom1 = kTRUE; - mUseRandom3 = kFALSE; - }; - void UseRandom3() - { - mUseRandom1 = kFALSE; - mUseRandom3 = kTRUE; - }; - void GetPythiaInstance(int); - - private: - std::unique_ptr<Pythia8::Pythia> mPythia; //! - std::unique_ptr<Pythia8::RndmEngine> mRandomEngine; //! - - protected: - Double_t mMom; // proton momentum - Int_t mHNL; // HNL ID - Int_t mId; // target type - Bool_t mUseRandom1; // flag to use TRandom1 - Bool_t mUseRandom3; // flag to use TRandom3 (default) - - ClassDefOverride(Pythia8Generator, 1); -}; - -} // namespace eventgen -} // namespace o2 -#endif /* !PNDP8GENERATOR_H */ diff --git a/Generators/include/Generators/QEDGenParam.h b/Generators/include/Generators/QEDGenParam.h index 2e7347c3790bf..1c78b14cfc516 100644 --- a/Generators/include/Generators/QEDGenParam.h +++ b/Generators/include/Generators/QEDGenParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/Trigger.h b/Generators/include/Generators/Trigger.h index 57f8f3494c28b..cb17c40de7b94 100644 --- a/Generators/include/Generators/Trigger.h +++ b/Generators/include/Generators/Trigger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/TriggerExternalParam.h b/Generators/include/Generators/TriggerExternalParam.h index 2360ca16f36c7..a47348894c2e2 100644 --- a/Generators/include/Generators/TriggerExternalParam.h +++ b/Generators/include/Generators/TriggerExternalParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/TriggerParticle.h b/Generators/include/Generators/TriggerParticle.h index bab2b8d62b9b6..770a43b090967 100644 --- a/Generators/include/Generators/TriggerParticle.h +++ b/Generators/include/Generators/TriggerParticle.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/include/Generators/TriggerParticleParam.h b/Generators/include/Generators/TriggerParticleParam.h index 74d54167cb2f2..4f05bb3f5a05c 100644 --- a/Generators/include/Generators/TriggerParticleParam.h +++ b/Generators/include/Generators/TriggerParticleParam.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/share/egconfig/pythia8_hf.cfg b/Generators/share/egconfig/pythia8_hf.cfg index 123c4146c59af..273751f09d718 100644 --- a/Generators/share/egconfig/pythia8_hf.cfg +++ b/Generators/share/egconfig/pythia8_hf.cfg @@ -9,4 +9,4 @@ HardQCD:hardbbbar on # scatterings g-g / q-qbar -> b-bbar ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/Generators/share/egconfig/pythia8_hi.cfg b/Generators/share/egconfig/pythia8_hi.cfg index 2c9c8b68bdabb..85efe50fb9c5d 100644 --- a/Generators/share/egconfig/pythia8_hi.cfg +++ b/Generators/share/egconfig/pythia8_hi.cfg @@ -12,4 +12,4 @@ HeavyIon:bWidth 15. # impact parameter from 0-x [fm] ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/Generators/share/egconfig/pythia8_inel.cfg b/Generators/share/egconfig/pythia8_inel.cfg index fdea3cc091984..d5e23efd65139 100644 --- a/Generators/share/egconfig/pythia8_inel.cfg +++ b/Generators/share/egconfig/pythia8_inel.cfg @@ -8,4 +8,4 @@ SoftQCD:inelastic on # all inelastic processes ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/Generators/share/egconfig/pythia8_ppb.cfg b/Generators/share/egconfig/pythia8_ppb.cfg new file mode 100644 index 0000000000000..bce0864949a63 --- /dev/null +++ b/Generators/share/egconfig/pythia8_ppb.cfg @@ -0,0 +1,10 @@ +### beams +Beams:frameType 2 # the beams are back-to-back, but with different energies +Beams:idA 2212 # proton +Beams:idB 1000822080 # Pb +Beams:eA 7000. # The energy of the first incoming particle, moving in the +z direction +Beams:eB 2760. # The energy of the second incoming particle, moving in the -z direction + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. diff --git a/Generators/share/egconfig/pythia8_userhooks_charm.C b/Generators/share/egconfig/pythia8_userhooks_charm.C index 19004c3f4a9f2..fc6b847c985cb 100644 --- a/Generators/share/egconfig/pythia8_userhooks_charm.C +++ b/Generators/share/egconfig/pythia8_userhooks_charm.C @@ -1,6 +1,6 @@ // Pythia8 UserHooks // -// usage: o2sim -g pythia8 --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_charm.C" +// usage: o2sim -g pythia8pp --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_charm.C" // /// \author R+Preghenella - February 2020 diff --git a/Generators/share/external/GenCosmics.C b/Generators/share/external/GenCosmics.C index f8757c2b51a89..6b56237a8e1a4 100644 --- a/Generators/share/external/GenCosmics.C +++ b/Generators/share/external/GenCosmics.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,7 @@ //< Macro to run QED background generator, us it as e.g. //< o2-sim -n10000 -m PIPE ITS TPC -g extgen --configKeyValues "GeneratorExternal.fileName=$O2_ROOT/share/Generators/external/GenCosmicsLoader.C" -R__LOAD_LIBRARY(libGeneratorCosmics.so) +R__LOAD_LIBRARY(libGeneratorCosmics) using namespace o2::eventgen; diff --git a/Generators/share/external/GenCosmicsLoader.C b/Generators/share/external/GenCosmicsLoader.C index 3ed746b30ac59..e8537be0ce66e 100644 --- a/Generators/share/external/GenCosmicsLoader.C +++ b/Generators/share/external/GenCosmicsLoader.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,7 +21,7 @@ FairGenerator* fg = nullptr; FairGenerator* GenCosmicsLoader() { const TString macroName = "GenCosmics"; - gSystem->Load("libGeneratorCosmics.so"); + gSystem->Load("libGeneratorCosmics"); // the path of the macro to load depends on where it was installed, we assume that its installation // directory is the same as of the loader macro diff --git a/Generators/share/external/QEDLoader.C b/Generators/share/external/QEDLoader.C index 3ea7297490a7a..c17b5165aa3b1 100644 --- a/Generators/share/external/QEDLoader.C +++ b/Generators/share/external/QEDLoader.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ FairGenerator* fg = nullptr; FairGenerator* QEDLoader() { const TString macroName = "QEDepem"; - gSystem->Load("libTEPEMGEN.so"); + gSystem->Load("libTEPEMGEN"); // the path of the macro to load depends on where it was installed, we assume that its installation // directory is the same as of the loader macro diff --git a/Generators/share/external/QEDepem.C b/Generators/share/external/QEDepem.C index 8c218ffdeb28f..2716c8e3d8081 100644 --- a/Generators/share/external/QEDepem.C +++ b/Generators/share/external/QEDepem.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,7 +12,7 @@ //< Macro to run QED background generator, us it as e.g. //< o2-sim -n10000 -m PIPE ITS T0 MFT --noemptyevents -g external --configKeyValues "GeneratorExternal.fileName=QEDloader.C" -R__LOAD_LIBRARY(libTEPEMGEN.so) +R__LOAD_LIBRARY(libTEPEMGEN) o2::eventgen::GeneratorTGenerator* QEDepem() { diff --git a/Generators/src/BoxGunParam.cxx b/Generators/src/BoxGunParam.cxx index b3016e80ffaf3..74f18d3547a1c 100644 --- a/Generators/src/BoxGunParam.cxx +++ b/Generators/src/BoxGunParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/DecayerPythia8.cxx b/Generators/src/DecayerPythia8.cxx index 77c4c04cff7b7..3101225053e4e 100644 --- a/Generators/src/DecayerPythia8.cxx +++ b/Generators/src/DecayerPythia8.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/DecayerPythia8Param.cxx b/Generators/src/DecayerPythia8Param.cxx index 2fb28af117127..0c9195c38c41b 100644 --- a/Generators/src/DecayerPythia8Param.cxx +++ b/Generators/src/DecayerPythia8Param.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GenCosmicsParam.cxx b/Generators/src/GenCosmicsParam.cxx index 6d23cdf0747fa..aaca942b6da36 100644 --- a/Generators/src/GenCosmicsParam.cxx +++ b/Generators/src/GenCosmicsParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 21a1916a7a337..6ce82deda0ad6 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -13,6 +14,7 @@ #include "Generators/Generator.h" #include "Generators/Trigger.h" #include "Generators/PrimaryGenerator.h" +#include "SimulationDataFormat/MCEventHeader.h" #include "FairPrimaryGenerator.h" #include "FairLogger.h" #include <cmath> @@ -31,7 +33,6 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), mBoost(0.) { /** default constructor **/ - } /*****************************************************************/ @@ -40,7 +41,6 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na mBoost(0.) { /** constructor **/ - } /*****************************************************************/ @@ -63,6 +63,7 @@ Bool_t /** endless generate-and-trigger loop **/ while (true) { + mReadEventCounter++; /** clear particle vector **/ mParticles.clear(); @@ -79,7 +80,10 @@ Bool_t /** trigger event **/ if (triggerEvent()) { + mTriggerOkHook(mParticles, mReadEventCounter); break; + } else { + mTriggerFalseHook(mParticles, mReadEventCounter); } } @@ -89,7 +93,13 @@ Bool_t } /** update header **/ - updateHeader(primGen->GetEvent()); + auto header = primGen->GetEvent(); + auto o2header = dynamic_cast<o2::dataformats::MCEventHeader*>(header); + if (!header) { + LOG(FATAL) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; + return kFALSE; + } + updateHeader(o2header); /** success **/ return kTRUE; @@ -124,7 +134,8 @@ Bool_t particle.GetStatusCode() == 1, particle.Energy() * mEnergyUnit, particle.T() * mTimeUnit, - particle.GetWeight()); + particle.GetWeight(), + (TMCProcess)particle.GetUniqueID()); } /** success **/ diff --git a/Generators/src/GeneratorExternalParam.cxx b/Generators/src/GeneratorExternalParam.cxx index dbed9392540a4..d3d987295d05e 100644 --- a/Generators/src/GeneratorExternalParam.cxx +++ b/Generators/src/GeneratorExternalParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 9af65cf5a0b72..60871525bd430 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,10 +33,11 @@ #include <Generators/GeneratorHepMCParam.h> #endif #include <Generators/BoxGunParam.h> +#include <Generators/PDG.h> #include <Generators/TriggerParticle.h> #include <Generators/TriggerExternalParam.h> #include <Generators/TriggerParticleParam.h> -#include "Generators/ConfigurationMacroHelper.h" +#include "CommonUtils/ConfigurationMacroHelper.h" #include "TRandom.h" @@ -65,8 +67,10 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair #ifdef GENERATORS_WITH_PYTHIA8 auto makePythia8Gen = [](std::string& config) { auto gen = new o2::eventgen::GeneratorPythia8(); - LOG(INFO) << "Reading \'Pythia8\' base configuration: " << config << std::endl; - gen->readFile(config); + if (!config.empty()) { + LOG(INFO) << "Reading \'Pythia8\' base configuration: " << config << std::endl; + gen->readFile(config); + } auto seed = (gRandom->GetSeed() % 900000000); LOG(INFO) << "Using random seed from gRandom % 900000000: " << seed; gen->readString("Random:setSeed on"); @@ -77,6 +81,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair /** generators **/ + o2::PDG::addParticlesToPdgDataBase(); auto genconfig = conf.getGenerator(); if (genconfig.compare("boxgen") == 0) { // a simple "box" generator configurable via BoxGunparam @@ -136,6 +141,12 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair extGen->SetStartEvent(conf.getStartEvent()); primGen->AddGenerator(extGen); LOG(INFO) << "using external kinematics"; + } else if (genconfig.compare("extkinO2") == 0) { + // external kinematics from previous O2 output + auto extGen = new o2::eventgen::GeneratorFromO2Kine(conf.getExtKinematicsFileName().c_str()); + extGen->SetStartEvent(conf.getStartEvent()); + primGen->AddGenerator(extGen); + LOG(INFO) << "using external O2 kinematics"; #ifdef GENERATORS_WITH_HEPMC3 } else if (genconfig.compare("hepmc") == 0) { // external HepMC file @@ -175,6 +186,10 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair auto muon = makeBoxGen(13, 100, -2.5, -4.0, 100, 100, 0., 360); primGen->AddGenerator(muon); } else if (genconfig.compare("pythia8") == 0) { + auto py8config = std::string(); + auto py8 = makePythia8Gen(py8config); + primGen->AddGenerator(py8); + } else if (genconfig.compare("pythia8pp") == 0) { auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_inel.cfg"; auto py8 = makePythia8Gen(py8config); primGen->AddGenerator(py8); @@ -199,7 +214,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair LOG(INFO) << params; auto extgen_filename = params.fileName; auto extgen_func = params.funcName; - auto extgen = GetFromMacro<FairGenerator*>(extgen_filename, extgen_func, "FairGenerator*", "extgen"); + auto extgen = o2::conf::GetFromMacro<FairGenerator*>(extgen_filename, extgen_func, "FairGenerator*", "extgen"); if (!extgen) { LOG(FATAL) << "Failed to retrieve \'extgen\': problem with configuration "; } @@ -237,10 +252,10 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair LOG(INFO) << params; auto external_trigger_filename = params.fileName; auto external_trigger_func = params.funcName; - trigger = GetFromMacro<o2::eventgen::Trigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::Trigger", "trigger"); + trigger = o2::conf::GetFromMacro<o2::eventgen::Trigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::Trigger", "trigger"); if (!trigger) { LOG(INFO) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type" << std::endl; - deeptrigger = GetFromMacro<o2::eventgen::DeepTrigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::DeepTrigger", "deeptrigger"); + deeptrigger = o2::conf::GetFromMacro<o2::eventgen::DeepTrigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::DeepTrigger", "deeptrigger"); } if (!trigger && !deeptrigger) { LOG(FATAL) << "Failed to retrieve \'external trigger\': problem with configuration "; diff --git a/Generators/src/GeneratorFromFile.cxx b/Generators/src/GeneratorFromFile.cxx index a93a750b256f9..29e793f14ca54 100644 --- a/Generators/src/GeneratorFromFile.cxx +++ b/Generators/src/GeneratorFromFile.cxx @@ -1,19 +1,24 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Generators/GeneratorFromFile.h" +#include "Generators/GeneratorFromO2KineParam.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/MCEventHeader.h" #include <FairLogger.h> #include <FairPrimaryGenerator.h> #include <TBranch.h> #include <TClonesArray.h> #include <TFile.h> +#include <TMCProcess.h> #include <TParticle.h> #include <TTree.h> #include <sstream> @@ -110,7 +115,7 @@ Bool_t GeneratorFromFile::ReadEvent(FairPrimaryGenerator* primGen) auto isFirstTrackableDescendant = [](TParticle const& p) { const int kTransportBit = BIT(14); // The particle should have not set kDone bit and its status should not exceed 1 - if (p.GetUniqueID() > 0 || !p.TestBit(kTransportBit)) { + if ((p.GetUniqueID() > 0 && p.GetUniqueID() != kPNoProcess) || !p.TestBit(kTransportBit)) { return false; } return true; @@ -153,7 +158,125 @@ Bool_t GeneratorFromFile::ReadEvent(FairPrimaryGenerator* primGen) return kFALSE; } +// based on O2 kinematics + +GeneratorFromO2Kine::GeneratorFromO2Kine(const char* name) +{ + mEventFile = TFile::Open(name); + if (mEventFile == nullptr) { + LOG(FATAL) << "EventFile " << name << " not found"; + return; + } + // the kinematics will be stored inside a branch MCTrack + // different events are stored inside different entries + auto tree = (TTree*)mEventFile->Get("o2sim"); + if (tree) { + mEventBranch = tree->GetBranch("MCTrack"); + if (mEventBranch) { + mEventsAvailable = mEventBranch->GetEntries(); + LOG(INFO) << "Found " << mEventsAvailable << " events in this file"; + return; + } + } + LOG(ERROR) << "Problem reading events from file " << name; +} + +bool GeneratorFromO2Kine::Init() +{ + + // read and set params + auto& param = GeneratorFromO2KineParam::Instance(); + LOG(INFO) << "Init \'FromO2Kine\' generator with following parameters"; + LOG(INFO) << param; + mSkipNonTrackable = param.skipNonTrackable; + mContinueMode = param.continueMode; + + return true; +} + +void GeneratorFromO2Kine::SetStartEvent(int start) +{ + if (start < mEventsAvailable) { + mEventCounter = start; + } else { + LOG(ERROR) << "start event bigger than available events\n"; + } +} + +bool GeneratorFromO2Kine::importParticles() +{ + // NOTE: This should be usable with kinematics files without secondaries + // It might need some adjustment to make it work with secondaries or to continue + // from a kinematics snapshot + + if (mEventCounter < mEventsAvailable) { + int particlecounter = 0; + + std::vector<o2::MCTrack>* tracks = nullptr; + mEventBranch->SetAddress(&tracks); + mEventBranch->GetEntry(mEventCounter); + + for (auto& t : *tracks) { + + // in case we do not want to continue, take only primaries + if (!mContinueMode && !t.isPrimary()) { + continue; + } + + auto pdg = t.GetPdgCode(); + auto px = t.Px(); + auto py = t.Py(); + auto pz = t.Pz(); + auto vx = t.Vx(); + auto vy = t.Vy(); + auto vz = t.Vz(); + auto m1 = t.getMotherTrackId(); + auto m2 = t.getSecondMotherTrackId(); + auto d1 = t.getFirstDaughterTrackId(); + auto d2 = t.getLastDaughterTrackId(); + auto e = t.GetEnergy(); + auto vt = t.T(); + auto weight = 1.; // p.GetWeight() ?? + auto wanttracking = t.getToBeDone(); + + if (mContinueMode) { // in case we want to continue, do only inhibited tracks + wanttracking &= t.getInhibited(); + } + + LOG(DEBUG) << "Putting primary " << pdg; + + mParticles.push_back(TParticle(pdg, wanttracking, m1, m2, d1, d2, px, py, pz, e, vx, vy, vz, vt)); + mParticles.back().SetUniqueID((unsigned int)t.getProcess()); // we should propagate the process ID + + particlecounter++; + } + mEventCounter++; + + if (tracks) { + delete tracks; + } + + LOG(INFO) << "Event generator put " << particlecounter << " on stack"; + return true; + } else { + LOG(ERROR) << "GeneratorFromO2Kine: Ran out of events\n"; + } + return false; +} + +void GeneratorFromO2Kine::updateHeader(o2::dataformats::MCEventHeader* eventHeader) +{ + /** update header **/ + + // put information about input file and event number of the current event + + eventHeader->putInfo<std::string>("generator", "generatorFromO2Kine"); + eventHeader->putInfo<std::string>("inputFile", mEventFile->GetName()); + eventHeader->putInfo<int>("inputEventNumber", mEventCounter - 1); +} + } // namespace eventgen } // end namespace o2 ClassImp(o2::eventgen::GeneratorFromFile); +ClassImp(o2::eventgen::GeneratorFromO2Kine); diff --git a/Generators/src/GeneratorFromO2KineParam.cxx b/Generators/src/GeneratorFromO2KineParam.cxx new file mode 100644 index 0000000000000..7550893da8e70 --- /dev/null +++ b/Generators/src/GeneratorFromO2KineParam.cxx @@ -0,0 +1,15 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author R+Preghenella - January 2021 + +#include "Generators/GeneratorFromO2KineParam.h" +O2ParamImpl(o2::eventgen::GeneratorFromO2KineParam); diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index ac0b76c4e666c..0a67b8e936401 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorHepMCParam.cxx b/Generators/src/GeneratorHepMCParam.cxx index cf838412e3bc5..79f31ac5fbbb8 100644 --- a/Generators/src/GeneratorHepMCParam.cxx +++ b/Generators/src/GeneratorHepMCParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorPythia6.cxx b/Generators/src/GeneratorPythia6.cxx index 470d1ecb89e5b..eb9305cf87811 100644 --- a/Generators/src/GeneratorPythia6.cxx +++ b/Generators/src/GeneratorPythia6.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorPythia6Param.cxx b/Generators/src/GeneratorPythia6Param.cxx index 295a84f37abe7..52dd91d86f1da 100644 --- a/Generators/src/GeneratorPythia6Param.cxx +++ b/Generators/src/GeneratorPythia6Param.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index 0727de5083739..c901aa05d014c 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,10 +13,10 @@ #include "Generators/GeneratorPythia8.h" #include "Generators/GeneratorPythia8Param.h" -#include "Generators/ConfigurationMacroHelper.h" +#include "CommonUtils/ConfigurationMacroHelper.h" #include "FairLogger.h" #include "TParticle.h" -#include "FairMCEventHeader.h" +#include "SimulationDataFormat/MCEventHeader.h" #include "Pythia8/HIUserHooks.h" #include "TSystem.h" @@ -82,7 +83,7 @@ Bool_t GeneratorPythia8::Init() /** user hooks via configuration macro **/ if (!mHooksFileName.empty()) { LOG(INFO) << "Applying \'Pythia8\' user hooks: " << mHooksFileName << " -> " << mHooksFuncName; - auto hooks = GetFromMacro<Pythia8::UserHooks*>(mHooksFileName, mHooksFuncName, "Pythia8::UserHooks*", "pythia8_user_hooks"); + auto hooks = o2::conf::GetFromMacro<Pythia8::UserHooks*>(mHooksFileName, mHooksFuncName, "Pythia8::UserHooks*", "pythia8_user_hooks"); if (!hooks) { LOG(FATAL) << "Failed to init \'Pythia8\': problem with user hooks configuration "; return false; @@ -91,7 +92,7 @@ Bool_t GeneratorPythia8::Init() } #if PYTHIA_VERSION_INTEGER < 8300 - /** [NOTE] The issue with large particle production vertex when running + /** [NOTE] The issue with large particle production vertex when running Pythia8 heavy-ion model (Angantyr) is solved in Pythia 8.3 series. For discussions about this issue, please refer to this JIRA ticket https://alice.its.cern.ch/jira/browse/O2-1382. @@ -125,7 +126,7 @@ Bool_t } #if PYTHIA_VERSION_INTEGER < 8300 - /** [NOTE] The issue with large particle production vertex when running + /** [NOTE] The issue with large particle production vertex when running Pythia8 heavy-ion model (Angantyr) is solved in Pythia 8.3 series. For discussions about this issue, please refer to this JIRA ticket https://alice.its.cern.ch/jira/browse/O2-1382. @@ -167,7 +168,7 @@ Bool_t /* loop over particles */ // auto weight = mPythia.info.weight(); // TBD: use weights auto nParticles = event.size(); - for (Int_t iparticle = 0; iparticle < nParticles; iparticle++) { // first particle is system + for (Int_t iparticle = 1; iparticle < nParticles; iparticle++) { // first particle is system auto particle = event[iparticle]; auto pdg = particle.id(); auto st = particle.statusHepMC(); @@ -179,10 +180,10 @@ Bool_t auto vy = particle.yProd(); auto vz = particle.zProd(); auto vt = particle.tProd(); - auto m1 = particle.mother1(); - auto m2 = particle.mother2(); - auto d1 = particle.daughter1(); - auto d2 = particle.daughter2(); + auto m1 = particle.mother1() - 1; + auto m2 = particle.mother2() - 1; + auto d1 = particle.daughter1() - 1; + auto d2 = particle.daughter2() - 1; mParticles.push_back(TParticle(pdg, st, m1, m2, d1, d2, px, py, pz, et, vx, vy, vz, vt)); } @@ -192,19 +193,43 @@ Bool_t /*****************************************************************/ -void GeneratorPythia8::updateHeader(FairMCEventHeader* eventHeader) +void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { /** update header **/ + eventHeader->putInfo<std::string>("generator", "pythia8"); + eventHeader->putInfo<int>("version", PYTHIA_VERSION_INTEGER); + eventHeader->putInfo<std::string>("processName", mPythia.info.name()); + eventHeader->putInfo<int>("processCode", mPythia.info.code()); + #if PYTHIA_VERSION_INTEGER < 8300 auto hiinfo = mPythia.info.hiinfo; #else auto hiinfo = mPythia.info.hiInfo; #endif - /** set impact parameter if in heavy-ion mode **/ if (hiinfo) { + /** set impact parameter **/ eventHeader->SetB(hiinfo->b()); + eventHeader->putInfo<double>("Bimpact", hiinfo->b()); + /** set Ncoll, Npart and Nremn **/ + int nColl, nPart; + int nPartProtonProj, nPartNeutronProj, nPartProtonTarg, nPartNeutronTarg; + int nRemnProtonProj, nRemnNeutronProj, nRemnProtonTarg, nRemnNeutronTarg; + getNcoll(nColl); + getNpart(nPart); + getNpart(nPartProtonProj, nPartNeutronProj, nPartProtonTarg, nPartNeutronTarg); + getNremn(nRemnProtonProj, nRemnNeutronProj, nRemnProtonTarg, nRemnNeutronTarg); + eventHeader->putInfo<int>("Ncoll", nColl); + eventHeader->putInfo<int>("Npart", nPart); + eventHeader->putInfo<int>("Npart_proj_p", nPartProtonProj); + eventHeader->putInfo<int>("Npart_proj_n", nPartNeutronProj); + eventHeader->putInfo<int>("Npart_targ_p", nPartProtonTarg); + eventHeader->putInfo<int>("Npart_targ_n", nPartNeutronTarg); + eventHeader->putInfo<int>("Nremn_proj_p", nRemnProtonProj); + eventHeader->putInfo<int>("Nremn_proj_n", nRemnNeutronProj); + eventHeader->putInfo<int>("Nremn_targ_p", nRemnProtonTarg); + eventHeader->putInfo<int>("Nremn_targ_n", nRemnNeutronTarg); } } @@ -250,6 +275,154 @@ void GeneratorPythia8::selectFromAncestor(int ancestor, Pythia8::Event& inputEve } } +/*****************************************************************/ + +void GeneratorPythia8::getNcoll(const Pythia8::Info& info, int& nColl) +{ + + /** compute number of collisions from sub-collision information **/ + +#if PYTHIA_VERSION_INTEGER < 8300 + auto hiinfo = info.hiinfo; +#else + auto hiinfo = info.hiInfo; +#endif + + nColl = 0; + + if (!hiinfo) { + return; + } + + // loop over sub-collisions + auto scptr = hiinfo->subCollisionsPtr(); + for (auto sc : *scptr) { + + // wounded nucleon flag in projectile/target + auto pW = sc.proj->status() == Pythia8::Nucleon::ABS; // according to C.Bierlich this should be == Nucleon::ABS + auto tW = sc.targ->status() == Pythia8::Nucleon::ABS; + + // increase number of collisions if both are wounded + if (pW && tW) { + nColl++; + } + } +} + +/*****************************************************************/ + +void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nPart) +{ + + /** compute number of participants as the sum of all participants nucleons **/ + + int nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg; + getNpart(info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); + nPart = nProtonProj + nNeutronProj + nProtonTarg + nNeutronTarg; +} + +/*****************************************************************/ + +void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg) +{ + + /** compute number of participants from sub-collision information **/ + +#if PYTHIA_VERSION_INTEGER < 8300 + auto hiinfo = info.hiinfo; +#else + auto hiinfo = info.hiInfo; +#endif + + nProtonProj = nNeutronProj = nProtonTarg = nNeutronTarg = 0; + if (!hiinfo) { + return; + } + + // keep track of wounded nucleons + std::vector<Pythia8::Nucleon*> projW; + std::vector<Pythia8::Nucleon*> targW; + + // loop over sub-collisions + auto scptr = hiinfo->subCollisionsPtr(); + for (auto sc : *scptr) { + + // wounded nucleon flag in projectile/target + auto pW = sc.proj->status() == Pythia8::Nucleon::ABS || sc.proj->status() == Pythia8::Nucleon::DIFF; // according to C.Bierlich this should be == Nucleon::ABS || Nucleon::DIFF + auto tW = sc.targ->status() == Pythia8::Nucleon::ABS || sc.targ->status() == Pythia8::Nucleon::DIFF; + + // increase number of wounded projectile nucleons if not yet in the wounded vector + if (pW && std::find(projW.begin(), projW.end(), sc.proj) == projW.end()) { + projW.push_back(sc.proj); + if (sc.proj->id() == 2212) { + nProtonProj++; + } else if (sc.proj->id() == 2112) { + nNeutronProj++; + } + } + + // increase number of wounded target nucleons if not yet in the wounded vector + if (tW && std::find(targW.begin(), targW.end(), sc.targ) == targW.end()) { + targW.push_back(sc.targ); + if (sc.targ->id() == 2212) { + nProtonTarg++; + } else if (sc.targ->id() == 2112) { + nNeutronTarg++; + } + } + } +} + +/*****************************************************************/ + +void GeneratorPythia8::getNremn(const Pythia8::Event& event, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg) +{ + + /** compute number of spectators from the nuclear remnant of the beams **/ + + // reset + nProtonProj = nNeutronProj = nProtonTarg = nNeutronTarg = 0; + auto nNucRem = 0; + + // particle loop + auto nparticles = event.size(); + for (int ipa = 0; ipa < nparticles; ++ipa) { + const auto particle = event[ipa]; + auto pdg = particle.id(); + + // nuclear remnants have pdg code = ±10LZZZAAA9 + if (pdg < 1000000000) { + continue; // must be nucleus + } + if (pdg % 10 != 9) { + continue; // first digit must be 9 + } + nNucRem++; + + // extract A, Z and L from pdg code + pdg /= 10; + auto A = pdg % 1000; + pdg /= 1000; + auto Z = pdg % 1000; + pdg /= 1000; + auto L = pdg % 10; + + if (particle.pz() > 0.) { + nProtonProj = Z; + nNeutronProj = A - Z; + } + if (particle.pz() < 0.) { + nProtonTarg = Z; + nNeutronTarg = A - Z; + } + + } // end of particle loop + + if (nNucRem > 2) { + LOG(WARNING) << " GeneratorPythia8: found more than two nuclear remnants (weird)"; + } +} + /*****************************************************************/ /*****************************************************************/ diff --git a/Generators/src/GeneratorPythia8Param.cxx b/Generators/src/GeneratorPythia8Param.cxx index d109167435620..984680e46ad01 100644 --- a/Generators/src/GeneratorPythia8Param.cxx +++ b/Generators/src/GeneratorPythia8Param.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorTGenerator.cxx b/Generators/src/GeneratorTGenerator.cxx index 17b686e65a0ff..bbe6e131f9111 100644 --- a/Generators/src/GeneratorTGenerator.cxx +++ b/Generators/src/GeneratorTGenerator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 25632f549ff8d..8ef8ab3735ee7 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -28,6 +29,7 @@ #pragma link C++ class o2::eventgen::Generator + ; #pragma link C++ class o2::eventgen::GeneratorTGenerator + ; #pragma link C++ class o2::eventgen::GeneratorExternalParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorExternalParam> + ; #ifdef GENERATORS_WITH_HEPMC3 #pragma link C++ class o2::eventgen::GeneratorHepMC + ; #pragma link C++ class o2::eventgen::GeneratorHepMCParam + ; @@ -35,32 +37,35 @@ #ifdef GENERATORS_WITH_PYTHIA6 #pragma link C++ class o2::eventgen::GeneratorPythia6 + ; #pragma link C++ class o2::eventgen::GeneratorPythia6Param + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorPythia6Param > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorPythia6Param> + ; #endif #ifdef GENERATORS_WITH_PYTHIA8 #pragma link C++ class o2::eventgen::GeneratorPythia8 + ; #pragma link C++ class o2::eventgen::DecayerPythia8 + ; #pragma link C++ class o2::eventgen::GeneratorPythia8Param + ; #pragma link C++ class o2::eventgen::DecayerPythia8Param + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorPythia8Param > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorPythia8Param> + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::DecayerPythia8Param> + ; #pragma link C++ class o2::eventgen::GeneratorFactory + ; #endif #pragma link C++ class o2::eventgen::GeneratorFromFile + ; +#pragma link C++ class o2::eventgen::GeneratorFromO2Kine + ; +#pragma link C++ class o2::eventgen::GeneratorFromO2KineParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorFromO2KineParam> + ; #pragma link C++ class o2::PDG + ; #pragma link C++ class o2::eventgen::PrimaryGenerator + ; #pragma link C++ enum o2::eventgen::EVertexDistribution; #pragma link C++ class o2::eventgen::InteractionDiamondParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::InteractionDiamondParam > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::InteractionDiamondParam> + ; #pragma link C++ class o2::eventgen::TriggerExternalParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::TriggerExternalParam> + ; #pragma link C++ class o2::eventgen::TriggerParticleParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::TriggerParticleParam > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::TriggerParticleParam> + ; #pragma link C++ class o2::eventgen::BoxGunParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::BoxGunParam > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::BoxGunParam> + ; #pragma link C++ class o2::eventgen::QEDGenParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam > +; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam> + ; #pragma link C++ class o2::eventgen::GenCosmicsParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GenCosmicsParam> + ; diff --git a/Generators/src/InteractionDiamondParam.cxx b/Generators/src/InteractionDiamondParam.cxx index d83f4bc0a0fa4..36f5ae1a4cecf 100644 --- a/Generators/src/InteractionDiamondParam.cxx +++ b/Generators/src/InteractionDiamondParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/PDG.cxx b/Generators/src/PDG.cxx index 139ee12d2b685..1a5b972b33bdb 100644 --- a/Generators/src/PDG.cxx +++ b/Generators/src/PDG.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/PrimaryGenerator.cxx b/Generators/src/PrimaryGenerator.cxx index 2e76ac6d9a373..d8aaea0a93754 100644 --- a/Generators/src/PrimaryGenerator.cxx +++ b/Generators/src/PrimaryGenerator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #include "Generators/Generator.h" #include "Generators/InteractionDiamondParam.h" #include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/Stack.h" #include "FairLogger.h" #include "FairGenericStack.h" @@ -186,9 +188,14 @@ void PrimaryGenerator::AddTrack(Int_t pdgid, Double_t px, Double_t py, Double_t } /** add track to stack **/ - fStack->PushTrack(doTracking, mother1, pdgid, px, py, pz, - e, vx, vy, vz, tof, polx, poly, polz, proc, ntr, - weight, status, mother2); + auto stack = dynamic_cast<o2::data::Stack*>(fStack); + if (!stack) { + LOG(FATAL) << "Stack must be an o2::data:Stack"; + return; // must be the o2 stack + } + stack->PushTrack(doTracking, mother1, pdgid, px, py, pz, + e, vx, vy, vz, tof, polx, poly, polz, TMCProcess::kPPrimary, ntr, + weight, status, mother2, daughter1, daughter2, proc); fNTracks++; } diff --git a/Generators/src/Pythia6Generator.cxx b/Generators/src/Pythia6Generator.cxx deleted file mode 100644 index 3a84114b30c22..0000000000000 --- a/Generators/src/Pythia6Generator.cxx +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/******************************************************************************** - * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence version 3 (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ -// ------------------------------------------------------------------------- -// ----- M. Al-Turany June 2014 ----- -// ------------------------------------------------------------------------- -// ------------------------------------------------------------------------- -// ----- Pythia6Generator source file ----- -// ----- Created 08/08/08 by S. Spataro ----- -// ------------------------------------------------------------------------- -#include "Generators/Pythia6Generator.h" - -#include "FairPrimaryGenerator.h" - -#include <iostream> -#include <cstdio> - -using std::cout; -using std::endl; -using std::max; -namespace o2 -{ -namespace eventgen -{ - -// ----- Default constructor ------------------------------------------ -Pythia6Generator::Pythia6Generator() = default; -// ------------------------------------------------------------------------ - -// ----- Standard constructor ----------------------------------------- -Pythia6Generator::Pythia6Generator(const char* fileName) - : mFileName(fileName), mInputFile(nullptr), mVerbose(0) -{ - cout << "-I Pythia6Generator: Opening input file " << mFileName << endl; - if ((mInputFile = fopen(mFileName, "r")) == nullptr) { - Fatal("Pythia6Generator", "Cannot open input file."); - } - - // mPDG=TDatabasePDG::Instance(); -} -// ------------------------------------------------------------------------ - -// ----- Destructor --------------------------------------------------- -Pythia6Generator::~Pythia6Generator() -{ - CloseInput(); -} -// ------------------------------------------------------------------------ - -// ----- Public method ReadEvent -------------------------------------- -Bool_t Pythia6Generator::ReadEvent(FairPrimaryGenerator* primGen) -{ - - // Check for input file - if (!mInputFile) { - // if ( ! mInputFile->is_open() ) { - cout << "-E Pythia6Generator: Input file not open!" << endl; - return kFALSE; - } - - // Define event variable to be read from file - Int_t ntracks = 0, eventID = 0, ncols = 0; - - // Define track variables to be read from file - Int_t nLev = 0, pdgID = 0, nM1 = -1, nM2 = -1, nDF = -1, nDL = -1; - Float_t fPx = 0., fPy = 0., fPz = 0., fM = 0., fE = 0.; - Float_t fVx = 0., fVy = 0., fVz = 0., fT = 0.; - - // Read event header line from input file - - Int_t max_nr = 0; - - Text_t buffer[200]; - ncols = fscanf(mInputFile, "%d\t%d", &eventID, &ntracks); - - if (ncols && ntracks > 0) { - - if (mVerbose > 0) - cout << "Event number: " << eventID << "\tNtracks: " << ntracks << endl; - - for (Int_t ll = 0; ll < ntracks; ll++) { - ncols = fscanf(mInputFile, "%d %d %d %d %d %d %f %f %f %f %f %f %f %f %f", &nLev, &pdgID, &nM1, &nM2, &nDF, &nDL, &fPx, &fPy, &fPz, &fE, &fM, &fVx, &fVy, &fVz, &fT); - if (mVerbose > 0) - cout << nLev << "\t" << pdgID << "\t" << nM1 << "\t" << nM2 << "\t" << nDF << "\t" << nDL << "\t" << fPx << "\t" << fPy << "\t" << fPz << "\t" << fE << "\t" << fM << "\t" << fVx << "\t" << fVy << "\t" << fVz << "\t" << fT << endl; - if (nLev == 1) - primGen->AddTrack(pdgID, fPx, fPy, fPz, fVx, fVy, fVz); - } - } else { - cout << "-I Pythia6Generator: End of input file reached " << endl; - CloseInput(); - return kFALSE; - } - - // If end of input file is reached : close it and abort run - if (feof(mInputFile)) { - cout << "-I Pythia6Generator: End of input file reached " << endl; - CloseInput(); - return kFALSE; - } - - /* - cout << "-I Pythia6Generator: Event " << eventID << ", vertex = (" - << vx << "," << vy << "," << vz << ") cm, multiplicity " - << ntracks << endl; - */ - - return kTRUE; -} -// ------------------------------------------------------------------------ - -// ----- Private method CloseInput ------------------------------------ -void Pythia6Generator::CloseInput() -{ - if (mInputFile) { - //if ( mInputFile->is_open() ) { - { - cout << "-I Pythia6Generator: Closing input file " - << mFileName << endl; - // mInputFile->close(); - - fclose(mInputFile); - } - delete mInputFile; - mInputFile = nullptr; - } -} -// ------------------------------------------------------------------------ - -} // namespace eventgen -} // namespace o2 - -ClassImp(o2::eventgen::Pythia6Generator); diff --git a/Generators/src/Pythia8Generator.cxx b/Generators/src/Pythia8Generator.cxx deleted file mode 100644 index 3e6f8a59990a1..0000000000000 --- a/Generators/src/Pythia8Generator.cxx +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/******************************************************************************** - * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence version 3 (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ -// ------------------------------------------------------------------------- -// ----- M. Al-Turany June 2014 ----- -// ------------------------------------------------------------------------- - -#include <cmath> -#include "TROOT.h" -#include "Pythia8/Basics.h" // for RndmEngine -#include "Pythia8/Pythia.h" -#include "FairPrimaryGenerator.h" -#include "FairGenerator.h" -#include "TRandom.h" // for TRandom -#include "TRandom1.h" // for TRandom1 -#include "TRandom3.h" // for TRandom3, gRandom - -#include "Generators/Pythia8Generator.h" - -using namespace Pythia8; - -namespace o2 -{ -namespace eventgen -{ - -class PyTr1Rng : public RndmEngine -{ - public: - PyTr1Rng() { mRng = std::make_unique<TRandom1>(gRandom->GetSeed()); }; - ~PyTr1Rng() override = default; - - Double_t flat() override { return mRng->TRandom1::Rndm(); }; - - private: - std::unique_ptr<TRandom1> mRng; //! -}; - -class PyTr3Rng : public RndmEngine -{ - public: - PyTr3Rng() { mRng = std::make_unique<TRandom3>(gRandom->GetSeed()); }; - ~PyTr3Rng() override = default; - - Double_t flat() override { return mRng->TRandom3::Rndm(); }; - - private: - std::unique_ptr<TRandom3> mRng; //! -}; - -// ----- Default constructor ------------------------------------------- -Pythia8Generator::Pythia8Generator() -{ - mUseRandom1 = kFALSE; - mUseRandom3 = kTRUE; - mId = 2212; // proton - mMom = 400; // proton - mHNL = 0; // HNL if set to !=0, for example 9900014, only track - mPythia = std::make_unique<Pythia>(); -} -// ------------------------------------------------------------------------- - -// ----- Default constructor ------------------------------------------- -Bool_t Pythia8Generator::Init() -{ - if (mUseRandom1) { - mRandomEngine = std::make_unique<PyTr1Rng>(); - } - if (mUseRandom3) { - mRandomEngine = std::make_unique<PyTr3Rng>(); - } - mPythia->setRndmEnginePtr(mRandomEngine.get()); - - /** commenting these lines - as they would override external settings **/ - /** - cout<<"Beam Momentum "<<fMom<<endl; - // Set arguments in Settings database. - mPythia.settings.mode("Beams:idA", fId); - mPythia.settings.mode("Beams:idB", 2212); - mPythia.settings.mode("Beams:frameType", 3); - mPythia.settings.parm("Beams:pxA", 0.); - mPythia.settings.parm("Beams:pyA", 0.); - mPythia.settings.parm("Beams:pzA", fMom); - mPythia.settings.parm("Beams:pxB", 0.); - mPythia.settings.parm("Beams:pyB", 0.); - mPythia.settings.parm("Beams:pzB", 0.); - **/ - mPythia->init(); - return kTRUE; -} -// ------------------------------------------------------------------------- - -// ----- Destructor ---------------------------------------------------- -Pythia8Generator::~Pythia8Generator() = default; -// ------------------------------------------------------------------------- - -// ----- Passing the event --------------------------------------------- -Bool_t Pythia8Generator::ReadEvent(FairPrimaryGenerator* cpg) -{ - const double mm2cm = 0.1; - const double clight = 2.997924580e10; //cm/c - Int_t npart = 0; - while (npart == 0) { - mPythia->next(); - for (int i = 0; i < mPythia->event.size(); i++) { - if (mPythia->event[i].isFinal()) { - // only send HNL decay products to G4 - if (mHNL != 0) { - Int_t im = mPythia->event[i].mother1(); - if (mPythia->event[im].id() == mHNL) { - // for the moment, hardcode 110m is maximum decay length - Double_t z = mPythia->event[i].zProd(); - Double_t x = abs(mPythia->event[i].xProd()); - Double_t y = abs(mPythia->event[i].yProd()); - // cout<<"debug HNL decay pos "<<x<<" "<< y<<" "<< z <<endl; - if (z < 11000. && z > 7000. && x < 250. && y < 250.) { - npart++; - } - } - } else { - npart++; - } - }; - }; - // happens if a charm particle being produced which does decay without producing a HNL. Try another event. - // if (npart == 0){ mPythia->event.list();} - }; - // cout<<"debug p8 event 0 " << mPythia->event[0].id()<< " "<< mPythia->event[1].id()<< " " - // << mPythia->event[2].id()<< " "<< npart <<endl; - for (Int_t ii = 0; ii < mPythia->event.size(); ii++) { - Bool_t wanttracking = true; - if (!mPythia->event[ii].isFinal()) - wanttracking = false; - Double_t z = mPythia->event[ii].zProd(); - Double_t x = mPythia->event[ii].xProd(); - Double_t y = mPythia->event[ii].yProd(); - Double_t pz = mPythia->event[ii].pz(); - Double_t px = mPythia->event[ii].px(); - Double_t py = mPythia->event[ii].py(); - Double_t t = mPythia->event[ii].tProd(); - x *= mm2cm; - y *= mm2cm; - z *= mm2cm; - t *= mm2cm / clight; - Double_t e = -9e9; - // handle system entry separately - if (!wanttracking) - e = mPythia->event[ii].e(); - // - printf("AddTrack from Pythia8 %5d \n", (Int_t)mPythia->event[ii].id()); - cpg->AddTrack((Int_t)mPythia->event[ii].id(), px, py, pz, x, y, z, - (Int_t)mPythia->event[ii].mother1(), wanttracking, e, t); - } // particle lloop - - return kTRUE; -} -// ------------------------------------------------------------------------- -void Pythia8Generator::SetParameters(const char* par) -{ - // Set Parameters - mPythia->readString(par); - cout << R"(mPythia->readString(")" << par << R"("))" << endl; -} - -// ------------------------------------------------------------------------- -void Pythia8Generator::Print() -{ - mPythia->settings.listAll(); -} -// ------------------------------------------------------------------------- -void Pythia8Generator::GetPythiaInstance(int arg) -{ - mPythia->particleData.list(arg); - cout << "canDecay " << mPythia->particleData.canDecay(arg) << " " << mPythia->particleData.mayDecay(arg) << endl; -} -// ------------------------------------------------------------------------- - -} // namespace eventgen -} // namespace o2 - -ClassImp(o2::eventgen::Pythia8Generator); diff --git a/Generators/src/QEDGenParam.cxx b/Generators/src/QEDGenParam.cxx index 7bbef98746697..29a657283d7ce 100644 --- a/Generators/src/QEDGenParam.cxx +++ b/Generators/src/QEDGenParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/Trigger.cxx b/Generators/src/Trigger.cxx index b22873630972a..5e00c48bb53dc 100644 --- a/Generators/src/Trigger.cxx +++ b/Generators/src/Trigger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,4 +20,3 @@ namespace eventgen } /* namespace eventgen */ } /* namespace o2 */ - diff --git a/Generators/src/TriggerExternalParam.cxx b/Generators/src/TriggerExternalParam.cxx index 0c164bbe06c1d..36593d01f3452 100644 --- a/Generators/src/TriggerExternalParam.cxx +++ b/Generators/src/TriggerExternalParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/TriggerParticle.cxx b/Generators/src/TriggerParticle.cxx index dca26f5874a80..a34cad7fe6ddb 100644 --- a/Generators/src/TriggerParticle.cxx +++ b/Generators/src/TriggerParticle.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Generators/src/TriggerParticleParam.cxx b/Generators/src/TriggerParticleParam.cxx index 1a1e9e8f9d82f..f9a257e215e70 100644 --- a/Generators/src/TriggerParticleParam.cxx +++ b/Generators/src/TriggerParticleParam.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/README.md b/README.md index 880f581943956..b25c4f680e874 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ [![](http://ali-ci.cern.ch/repo/buildstatus/AliceO2Group/AliceO2/dev/build_O2_o2.svg)](https://ali-ci.cern.ch/repo/logs/AliceO2Group/AliceO2/dev/latest/build_O2_o2/fullLog.txt) [![](http://ali-ci.cern.ch/repo/buildstatus/AliceO2Group/AliceO2/dev/build_o2_macos.svg)](https://ali-ci.cern.ch/repo/logs/AliceO2Group/AliceO2/dev/latest/build_o2_macos/fullLog.txt) [![](http://ali-ci.cern.ch/repo/buildstatus/AliceO2Group/AliceO2/dev/build_o2checkcode_o2.svg)](https://ali-ci.cern.ch/repo/logs/AliceO2Group/AliceO2/dev/latest/build_o2checkcode_o2/fullLog.txt) -[![](http://ali-ci.cern.ch/repo/buildstatus/AliceO2Group/AliceO2/dev/build_O2_o2-dev-fairroot.svg)](https://ali-ci.cern.ch/repo/logs/AliceO2Group/AliceO2/dev/latest/build_O2_o2-dev-fairroot/fullLog.txt) <!-- /// \endcond --> diff --git a/Steer/CMakeLists.txt b/Steer/CMakeLists.txt index 6adb9c0b78548..83d2d447a0ece 100644 --- a/Steer/CMakeLists.txt +++ b/Steer/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library(Steer SOURCES src/O2MCApplication.cxx src/InteractionSampler.cxx @@ -16,6 +17,11 @@ o2_add_library(Steer O2::SimulationDataFormat O2::DetectorsCommonDataFormats) +o2_add_executable(colcontexttool + COMPONENT_NAME steer + SOURCES src/CollisionContextTool.cxx + PUBLIC_LINK_LIBRARIES Boost::program_options O2::Algorithm O2::Steer O2::SimulationDataFormat) + o2_target_root_dictionary(Steer HEADERS include/Steer/InteractionSampler.h include/Steer/HitProcessingManager.h diff --git a/Steer/DigitizerWorkflow/CMakeLists.txt b/Steer/DigitizerWorkflow/CMakeLists.txt index b210068b113d9..eab4a24e23504 100644 --- a/Steer/DigitizerWorkflow/CMakeLists.txt +++ b/Steer/DigitizerWorkflow/CMakeLists.txt @@ -1,18 +1,76 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +if (ENABLE_UPGRADES) +o2_add_executable(digitizer-workflow + COMPONENT_NAME sim + SOURCES src/CTPDigitizerSpec.cxx + src/FT0DigitizerSpec.cxx + src/FV0DigitizerSpec.cxx + src/FDDDigitizerSpec.cxx + src/GRPUpdaterSpec.cxx + src/HMPIDDigitizerSpec.cxx + src/ITSMFTDigitizerSpec.cxx + src/ITS3DigitizerSpec.cxx + src/MCHDigitizerSpec.cxx + src/MIDDigitizerSpec.cxx + src/PHOSDigitizerSpec.cxx + src/CPVDigitizerSpec.cxx + src/SimReaderSpec.cxx + src/SimpleDigitizerWorkflow.cxx + src/TPCDigitRootWriterSpec.cxx + src/TPCDigitizerSpec.cxx + src/ZDCDigitizerSpec.cxx + src/TOFDigitizerSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::Steer + O2::CommonConstants + O2::EMCALSimulation + O2::EMCALWorkflow + O2::FT0Simulation + O2::FV0Simulation + O2::FDDSimulation + O2::CTPSimulation + O2::CTPWorkflowIO + O2::FDDWorkflow + O2::HMPIDSimulation + O2::ITSMFTSimulation + O2::ITSSimulation + O2::ITSMFTWorkflow + O2::MCHSimulation + O2::MCHBase + O2::DataFormatsMCH + O2::MFTSimulation + O2::MIDSimulation + O2::PHOSSimulation + O2::CPVSimulation + O2::TOFSimulation + O2::TOFCalibration + O2::TOFReconstruction + O2::TOFWorkflowIO + O2::TPCSimulation + O2::TRDSimulation + O2::TRDWorkflow + O2::TRDWorkflowIO + O2::DataFormatsTRD + O2::ZDCSimulation + O2::ZDCWorkflow + O2::DetectorsRaw + O2::ITS3Simulation + O2::ITS3Workflow + ) +else() o2_add_executable(digitizer-workflow COMPONENT_NAME sim - SOURCES src/EMCALDigitWriterSpec.cxx - src/EMCALDigitizerSpec.cxx + SOURCES src/CTPDigitizerSpec.cxx src/FT0DigitizerSpec.cxx src/FV0DigitizerSpec.cxx src/FDDDigitizerSpec.cxx @@ -31,10 +89,15 @@ o2_add_executable(digitizer-workflow src/TOFDigitizerSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::Steer + O2::CommonConstants O2::EMCALSimulation + O2::EMCALWorkflow O2::FT0Simulation O2::FV0Simulation O2::FDDSimulation + O2::CTPSimulation + O2::CTPWorkflowIO + O2::FDDWorkflow O2::HMPIDSimulation O2::ITSMFTSimulation O2::ITSSimulation @@ -48,18 +111,22 @@ o2_add_executable(digitizer-workflow O2::TOFSimulation O2::TOFCalibration O2::TOFReconstruction - O2::TOFWorkflowUtils + O2::TOFWorkflowIO O2::TPCSimulation O2::TRDSimulation O2::TRDWorkflow O2::DataFormatsTRD - O2::ZDCSimulation) + O2::ZDCSimulation + O2::ZDCWorkflow + O2::DetectorsRaw + ) +endif() o2_add_executable(mctruth-testworkflow COMPONENT_NAME sim SOURCES src/MCTruthTestWorkflow.cxx - src/MCTruthSourceSpec.cxx - src/MCTruthWriterSpec.cxx + src/MCTruthSourceSpec.cxx + src/MCTruthWriterSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimulationDataFormat) diff --git a/Steer/DigitizerWorkflow/src/CPVDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/CPVDigitWriterSpec.h index be380fddba8b9..396b033f31f4a 100644 --- a/Steer/DigitizerWorkflow/src/CPVDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/CPVDigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.cxx index 2621c2355f512..49745e3745173 100644 --- a/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,6 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" -#include "Headers/DataHeader.h" #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" @@ -22,6 +22,7 @@ #include "CommonDataFormat/EvIndex.h" #include "DataFormatsCPV/TriggerRecord.h" #include "CPVSimulation/Digitizer.h" +#include "CPVBase/CPVSimParams.h" #include "DataFormatsParameters/GRPObject.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -41,49 +42,37 @@ void DigitizerSpec::initDigitizerTask(framework::InitContext& ic) // init digitizer mDigitizer.init(); - if (mHitsS) { - delete mHitsS; + if (mHits) { + delete mHits; } - mHitsS = new std::vector<Hit>(); - if (mHitsBg) { - delete mHitsBg; + mHits = new std::vector<Hit>(); + + auto simulatePileup = ic.options().get<int>("pileup"); + if (simulatePileup) { // set readout time and dead time parameters + mReadoutTime = o2::cpv::CPVSimParams::Instance().mReadoutTimePU; //PHOS readout time in ns + mDeadTime = o2::cpv::CPVSimParams::Instance().mDeadTimePU; //PHOS dead time (should include readout => mReadoutTime< mDeadTime) + } else { + mReadoutTime = o2::cpv::CPVSimParams::Instance().mReadoutTime; //PHOS readout time in ns + mDeadTime = o2::cpv::CPVSimParams::Instance().mDeadTime; //PHOS dead time (should include readout => mReadoutTime< mDeadTime) } - mHitsBg = new std::vector<Hit>(); - - mFinished = false; } // helper function which will be offered as a service void DigitizerSpec::retrieveHits(const char* brname, int sourceID, int entryID) { - - if (sourceID == 0) { //Bg - mHitsBg->clear(); - auto br = mSimChains[sourceID]->GetBranch(brname); - if (!br) { - LOG(ERROR) << "No branch found"; - return; - } - br->SetAddress(&mHitsBg); - br->GetEntry(entryID); - } else { //Bg - mHitsS->clear(); - auto br = mSimChains[sourceID]->GetBranch(brname); - if (!br) { - LOG(ERROR) << "No branch found"; - return; - } - br->SetAddress(&mHitsS); - br->GetEntry(entryID); + auto br = mSimChains[sourceID]->GetBranch(brname); + if (!br) { + LOG(ERROR) << "No branch found"; + return; } + mHits->clear(); + br->SetAddress(&mHits); + br->GetEntry(entryID); } void DigitizerSpec::run(framework::ProcessingContext& pc) { - if (mFinished) { - return; - } // read collision context from input auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); @@ -92,7 +81,8 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) LOG(DEBUG) << "GOT " << timesview.size() << " COLLISSION TIMES"; // if there is nothing to do ... return - if (timesview.size() == 0) { + int n = timesview.size(); + if (n == 0) { return; } @@ -101,46 +91,69 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) LOG(INFO) << " CALLING CPV DIGITIZATION "; std::vector<TriggerRecord> triggers; - static std::vector<o2::cpv::Hit> hits; - mLabels.clear(); - mDigits.clear(); - int indexStart = mDigits.size(); + int indexStart = mDigitsOut.size(); auto& eventParts = context->getEventParts(); + //if this is last stream of hits and we can write directly to final vector of digits? Otherwize use temporary vectors + bool isLastStream = true; + double eventTime = timesview[0].getTimeNS() - o2::cpv::CPVSimParams::Instance().mDeadTime; //checked above that list not empty + int eventId; // loop over all composite collisions given from context // (aka loop over all the interaction records) - for (int collID = 0; collID < timesview.size(); ++collID) { - mDigitizer.setEventTime(timesview[collID].getTimeNS()); - - // for each collision, loop over the constituents event and source IDs - // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { + for (int collID = 0; collID < n; ++collID) { - // get the hits for this event and this source - retrieveHits("CPVHit", part.sourceID, part.entryID); - mDigitizer.setCurrEvID(part.entryID); + double dt = timesview[collID].getTimeNS() - eventTime; //start new PHOS readout, continue current or dead time? + if (dt > mReadoutTime && dt < mDeadTime) { //dead time, skip event + continue; } - LOG(DEBUG) << "Found " << mHitsBg->size() << " BG hits and " << mHitsS->size() << "signal hits"; - - // call actual digitization procedure - mDigitizer.process(mHitsBg, mHitsS, mDigits, mLabels); + if (dt >= o2::cpv::CPVSimParams::Instance().mDeadTime) { // start new event + //new event + eventTime = timesview[collID].getTimeNS(); + dt = 0.; + eventId = collID; + } - // Add trigger record - triggers.emplace_back(timesview[collID], indexStart, mDigits.size() - indexStart); - indexStart = mDigits.size(); + //Check if next event has to be added to this read-out + if (collID < n - 1) { + isLastStream = (timesview[collID + 1].getTimeNS() - eventTime > mReadoutTime); + } else { + isLastStream = true; + } - LOG(DEBUG) << "Have " << mDigits.size() << " digits "; + // for each collision, loop over the constituents event and source IDs + // (background signal merging is basically taking place here) + // merge new hist to current digit list + auto part = eventParts[collID].begin(); + while (part != eventParts[collID].end()) { + // get the hits for this event and this source + int source = part->sourceID; + int entry = part->entryID; + retrieveHits("CPVHit", source, entry); + part++; + if (part == eventParts[collID].end() && isLastStream) { //last stream, copy digits directly to output vector + mDigitizer.processHits(mHits, mDigitsFinal, mDigitsOut, mLabels, collID, source, dt); + mDigitsFinal.clear(); + //finalyze previous event and clean + // Add trigger record + triggers.emplace_back(timesview[eventId], indexStart, mDigitsOut.size() - indexStart); + indexStart = mDigitsOut.size(); + mDigitsFinal.clear(); + } else { //Fill intermediate digitvector + mDigitsTmp.swap(mDigitsFinal); + mDigitizer.processHits(mHits, mDigitsTmp, mDigitsFinal, mLabels, collID, source, dt); + mDigitsTmp.clear(); + } + } } - LOG(DEBUG) << "Have " << mLabels.getNElements() << " CPV labels "; // here we have all digits and we can send them to consumer (aka snapshot it onto output) - pc.outputs().snapshot(Output{"CPV", "DIGITS", 0, Lifetime::Timeframe}, mDigits); + pc.outputs().snapshot(Output{"CPV", "DIGITS", 0, Lifetime::Timeframe}, mDigitsOut); pc.outputs().snapshot(Output{"CPV", "DIGITTRIGREC", 0, Lifetime::Timeframe}, triggers); if (pc.outputs().isAllowed({"CPV", "DIGITSMCTR", 0})) { pc.outputs().snapshot(Output{"CPV", "DIGITSMCTR", 0, Lifetime::Timeframe}, mLabels); } - // CPV is always a triggering detector + // CPV is always a triggered detector const o2::parameters::GRPObject::ROMode roMode = o2::parameters::GRPObject::TRIGGERING; LOG(DEBUG) << "CPV: Sending ROMode= " << roMode << " to GRPUpdater"; pc.outputs().snapshot(Output{"CPV", "ROMode", 0, Lifetime::Timeframe}, roMode); @@ -148,10 +161,9 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) timer.Stop(); LOG(INFO) << "Digitization took " << timer.CpuTime() << "s"; - pc.services().get<o2::framework::ControlService>().endOfStream(); + // pc.services().get<o2::framework::ControlService>().endOfStream(); // we should be only called once; tell DPL that this process is ready to exit pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - mFinished = true; } DataProcessorSpec getCPVDigitizerSpec(int channel, bool mctruth) diff --git a/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.h b/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.h index 909fea0f6a316..26ed4def6f854 100644 --- a/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/CPVDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "DataFormatsCPV/Digit.h" -#include "CPVBase/Hit.h" +#include "DataFormatsCPV/Hit.h" #include "CPVSimulation/Digitizer.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "DetectorsBase/BaseDPLDigitizer.h" @@ -61,12 +62,14 @@ class DigitizerSpec final : public o2::base::BaseDPLDigitizer int sourceID, int entryID); - Bool_t mFinished = false; ///< Flag for digitization finished + float mReadoutTime = 0.; ///< PHOS readout time + float mDeadTime = 0.; ///< PHOS dead time Digitizer mDigitizer; ///< Digitizer object - std::vector<TChain*> mSimChains; - std::vector<Hit>* mHitsBg = nullptr; ///< Vector with input hits from Bg event - std::vector<Hit>* mHitsS = nullptr; ///< Vector with input hits from Signal event - std::vector<Digit> mDigits; ///< Vector with non-accumulated digits (per collision) + std::vector<TChain*> mSimChains; ///< Chain of files for background/signal events + std::vector<Hit>* mHits = nullptr; ///< Vector with input hits from Signal event + std::vector<Digit> mDigitsTmp; ///< Vector with accumulated digits (per collision) + std::vector<Digit> mDigitsFinal; ///< Vector with accumulated digits (per collision) + std::vector<Digit> mDigitsOut; ///< Vector with accumulated digits (per collision) dataformats::MCTruthContainer<o2::MCCompLabel> mLabels; ///< List of labels }; diff --git a/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.cxx new file mode 100644 index 0000000000000..836881c8f1790 --- /dev/null +++ b/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.cxx @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CTPDigitizerSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework//Task.h" +#include "DetectorsBase/BaseDPLDigitizer.h" +#include "DataFormatsCTP/Digits.h" +#include "Steer/HitProcessingManager.h" // for DigitizationContext +#include "DetectorsCommonDataFormats/DetID.h" +#include "CTPSimulation/Digitizer.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFV0/BCData.h" + +#include <TStopwatch.h> +#include <gsl/span> + +using namespace o2::framework; +namespace o2 +{ +namespace ctp +{ +class CTPDPLDigitizerTask : public o2::base::BaseDPLDigitizer +{ + using GRP = o2::parameters::GRPObject; + + public: + CTPDPLDigitizerTask() : o2::base::BaseDPLDigitizer(), mDigitizer() {} + ~CTPDPLDigitizerTask() override = default; + void initDigitizerTask(framework::InitContext& ic) override + { + mDigitizer.init(); + } + void run(framework::ProcessingContext& pc) + { + // read collision context from input + //auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); + //const bool withQED = context->isQEDProvided(); + //auto& timesview = context->getEventRecords(withQED); + // read ctp inputs from input + auto ft0inputs = pc.inputs().get<gsl::span<o2::ft0::DetTrigInput>>("ft0"); + auto fv0inputs = pc.inputs().get<gsl::span<o2::fv0::DetTrigInput>>("fv0"); + + std::vector<o2::ctp::CTPInputDigit> finputs; + TStopwatch timer; + timer.Start(); + LOG(INFO) << "CALLING CTP DIGITIZATION"; + // Input order: T0, V0, ... but O need also poisition of inputs DETInputs + for (const auto& inp : ft0inputs) { + finputs.emplace_back(CTPInputDigit{inp.mIntRecord, inp.mInputs, o2::detectors::DetID::FT0}); + } + for (const auto& inp : fv0inputs) { + finputs.emplace_back(CTPInputDigit{inp.mIntRecord, inp.mInputs, o2::detectors::DetID::FV0}); + } + gsl::span<CTPInputDigit> ginputs(finputs); + auto digits = mDigitizer.process(ginputs); + // send out to next stage + LOG(INFO) << "CTP DIGITS being sent."; + pc.outputs().snapshot(Output{"CTP", "DIGITS", 0, Lifetime::Timeframe}, digits); + LOG(INFO) << "CTP PRESENT being sent."; + pc.outputs().snapshot(Output{"CTP", "ROMode", 0, Lifetime::Timeframe}, mROMode); + timer.Stop(); + LOG(INFO) << "CTP Digitization took " << timer.CpuTime() << "s"; + } + + protected: + o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::PRESENT; + o2::ctp::Digitizer mDigitizer; ///< Digitizer +}; +o2::framework::DataProcessorSpec getCTPDigitizerSpec(int channel, std::vector<o2::detectors::DetID>& detList, bool mctruth) +{ + std::vector<InputSpec> inputs; + std::vector<OutputSpec> output; + if (std::find(detList.begin(), detList.end(), o2::detectors::DetID::FT0) != detList.end()) { + inputs.emplace_back("ft0", "FT0", "TRIGGERINPUT", 0, Lifetime::Timeframe); + } + if (std::find(detList.begin(), detList.end(), o2::detectors::DetID::FV0) != detList.end()) { + inputs.emplace_back("fv0", "FV0", "TRIGGERINPUT", 0, Lifetime::Timeframe); + } + output.emplace_back("CTP", "DIGITS", 0, Lifetime::Timeframe); + output.emplace_back("CTP", "ROMode", 0, Lifetime::Timeframe); + return DataProcessorSpec{ + "CTPDigitizer", + inputs, + output, + AlgorithmSpec{adaptFromTask<CTPDPLDigitizerTask>()}, + Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}, + {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; +} +} // namespace ctp +} // namespace o2 diff --git a/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.h b/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.h new file mode 100644 index 0000000000000..b5cd46f27ad64 --- /dev/null +++ b/Steer/DigitizerWorkflow/src/CTPDigitizerSpec.h @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_CTPDIGITIZER_H_ +#define STEER_DIGITIZERWORKFLOW_CTPDIGITIZER_H_ + +#include "Framework/DataProcessorSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" + +namespace o2 +{ +namespace ctp +{ + +o2::framework::DataProcessorSpec getCTPDigitizerSpec(int channel, std::vector<o2::detectors::DetID>& detList, bool mctruth = true); + +} // namespace ctp +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_CTPDIGITIZER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.h deleted file mode 100644 index 29b2a9e2f5b4e..0000000000000 --- a/Steer/DigitizerWorkflow/src/EMCALDigitWriterSpec.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ -#define STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ - -#include "Framework/DataProcessorSpec.h" -namespace o2 -{ -namespace emcal -{ - -/// \brief Create new digits writer spec -/// \return digits writer spec -o2::framework::DataProcessorSpec getEMCALDigitWriterSpec(bool mctruth = true); - -} // end namespace emcal -} // end namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_EMCALDIGITWRITER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/FDDDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/FDDDigitWriterSpec.h deleted file mode 100644 index 7b4e31cbca772..0000000000000 --- a/Steer/DigitizerWorkflow/src/FDDDigitWriterSpec.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef STEER_DIGITIZERWORKFLOW_SRC_FDDDIGITWRITERSPEC_H_ -#define STEER_DIGITIZERWORKFLOW_SRC_FDDDIGITWRITERSPEC_H_ - -#include "Framework/DataProcessorSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "Framework/InputSpec.h" -#include "DataFormatsFDD/Digit.h" -#include "DataFormatsFDD/MCLabel.h" -#include "SimulationDataFormat/IOMCTruthContainerView.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace fdd -{ - -template <typename T> -using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; - -o2::framework::DataProcessorSpec getFDDDigitWriterSpec(bool mctruth = true) -{ - using InputSpec = framework::InputSpec; - using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - - // the callback to be set as hook for custom action when the writer is closed - auto finishWriting = [](TFile* outputfile, TTree* outputtree) { - const auto* brArr = outputtree->GetListOfBranches(); - int64_t nent = 0; - for (const auto* brc : *brArr) { - int64_t n = ((const TBranch*)brc)->GetEntries(); - if (nent && (nent != n)) { - LOG(ERROR) << "Branches have different number of entries"; - } - nent = n; - } - outputtree->SetEntries(nent); - outputtree->Write(); - outputfile->Close(); - }; - - // custom handler for labels: - // essentially transform the input container (as registered in the original branch definition) to the special output format for labels - auto customlabelhandler = [](TBranch& branch, std::vector<char> const& labeldata, framework::DataRef const& ref) { - o2::dataformats::ConstMCTruthContainerView<o2::fdd::MCLabel> labels(labeldata); - // make the actual output object by adopting/casting the buffer - // into a split format - o2::dataformats::IOMCTruthContainerView outputcontainer(labeldata); - auto br = framework::RootTreeWriter::remapBranch(branch, &outputcontainer); - br->Fill(); - br->ResetAddress(); - }; - - auto labelsdef = BranchDefinition<std::vector<char>>{InputSpec{"labelinput", "FDD", "DIGITLBL"}, - "FDDDigitLabels", "labels-branch-name", - // this branch definition is disabled if MC labels are not processed - (mctruth ? 1 : 0), - customlabelhandler}; - - return MakeRootTreeWriterSpec("FDDDigitWriter", - "fdddigits.root", - "o2sim", - 1, - MakeRootTreeWriterSpec::CustomClose(finishWriting), - BranchDefinition<std::vector<o2::fdd::Digit>>{InputSpec{"digitBCinput", "FDD", "DIGITSBC"}, "FDDDigit"}, - BranchDefinition<std::vector<o2::fdd::ChannelData>>{InputSpec{"digitChinput", "FDD", "DIGITSCH"}, "FDDDigitCh"}, - std::move(labelsdef))(); -} - -} // end namespace fdd -} // end namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_SRC_FDDDIGITWRITERSPEC_H_ */ diff --git a/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.cxx index 4b72eeb32dbaa..dcad22132e989 100644 --- a/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -31,7 +32,6 @@ using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; - namespace o2 { namespace fdd @@ -91,18 +91,19 @@ class FDDDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.setEventID(part.entryID); mDigitizer.setSrcID(part.sourceID); - mDigitizer.process(hits, mDigitsBC, mDigitsCh, labels); + mDigitizer.process(hits, mDigitsBC, mDigitsCh, mDigitsTrig, labels); } } o2::InteractionTimeRecord terminateIR; terminateIR.orbit = 0xffffffff; // supply IR in the infinite future to flush all cached BC mDigitizer.setInteractionRecord(terminateIR); - mDigitizer.flush(mDigitsBC, mDigitsCh, labels); + mDigitizer.flush(mDigitsBC, mDigitsCh, mDigitsTrig, labels); // send out to next stage pc.outputs().snapshot(Output{"FDD", "DIGITSBC", 0, Lifetime::Timeframe}, mDigitsBC); pc.outputs().snapshot(Output{"FDD", "DIGITSCH", 0, Lifetime::Timeframe}, mDigitsCh); + pc.outputs().snapshot(Output{"FDD", "TRIGGERINPUT", 0, Lifetime::Timeframe}, mDigitsTrig); if (pc.outputs().isAllowed({"FDD", "DIGITLBL", 0})) { auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::fdd::MCLabel>>(Output{"FDD", "DIGITLBL", 0, Lifetime::Timeframe}); labels.flatten_to(sharedlabels); @@ -123,6 +124,7 @@ class FDDDPLDigitizerTask : public o2::base::BaseDPLDigitizer std::vector<TChain*> mSimChains; std::vector<o2::fdd::ChannelData> mDigitsCh; std::vector<o2::fdd::Digit> mDigitsBC; + std::vector<o2::fdd::DetTrigInput> mDigitsTrig; // RS: at the moment using hardcoded flag for continuous readout o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::CONTINUOUS; // readout mode @@ -138,6 +140,7 @@ o2::framework::DataProcessorSpec getFDDDigitizerSpec(int channel, bool mctruth) std::vector<OutputSpec> outputs; outputs.emplace_back("FDD", "DIGITSBC", 0, Lifetime::Timeframe); outputs.emplace_back("FDD", "DIGITSCH", 0, Lifetime::Timeframe); + outputs.emplace_back("FDD", "TRIGGERINPUT", 0, Lifetime::Timeframe); if (mctruth) { outputs.emplace_back("FDD", "DIGITLBL", 0, Lifetime::Timeframe); } diff --git a/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.h b/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.h index bbb1389434b9a..2c95a942b8ba4 100644 --- a/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/FDDDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/FT0DigitWriterSpec.h b/Steer/DigitizerWorkflow/src/FT0DigitWriterSpec.h index 8ac752f065083..5436356db190a 100644 --- a/Steer/DigitizerWorkflow/src/FT0DigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/FT0DigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -39,10 +40,11 @@ o2::framework::DataProcessorSpec getFT0DigitWriterSpec(bool mctruth) 1, BranchDefinition<std::vector<o2::ft0::Digit>>{InputSpec{"digitBCinput", "FT0", "DIGITSBC"}, "FT0DIGITSBC"}, BranchDefinition<std::vector<o2::ft0::ChannelData>>{InputSpec{"digitChinput", "FT0", "DIGITSCH"}, "FT0DIGITSCH"}, + BranchDefinition<std::vector<o2::ft0::DetTrigInput>>{InputSpec{"digitTrinput", "FT0", "TRIGGERINPUT"}, "TRIGGERINPUT"}, BranchDefinition<o2::dataformats::MCTruthContainer<o2::ft0::MCLabel>>{InputSpec{"labelinput", "FT0", "DIGITSMCTR"}, "FT0DIGITSMCTR", mctruth ? 1 : 0})(); } } // namespace ft0 } // end namespace o2 -#endif /* STEER_DIGITIZERWORKFLOW_ITSMFTDIGITWRITER_H_ */ +#endif /* STEER_DIGITIZERWORKFLOW_FT0DIGITWRITER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.cxx index 7f63d80c95333..1a8ec7df159e3 100644 --- a/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,6 @@ #include "Headers/DataHeader.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "FT0Simulation/Digitizer.h" -#include "FT0Simulation/DigitizationParameters.h" #include "DataFormatsFT0/ChannelData.h" #include "DataFormatsFT0/HitType.h" #include "DataFormatsFT0/Digit.h" @@ -44,9 +44,7 @@ class FT0DPLDigitizerTask : public o2::base::BaseDPLDigitizer using GRP = o2::parameters::GRPObject; public: - FT0DPLDigitizerTask() : o2::base::BaseDPLDigitizer(), mDigitizer(DigitizationParameters{}) {} - explicit FT0DPLDigitizerTask(o2::ft0::DigitizationParameters const& parameters) - : o2::base::BaseDPLDigitizer(), mDigitizer(parameters){}; + FT0DPLDigitizerTask() : o2::base::BaseDPLDigitizer(), mDigitizer() {} ~FT0DPLDigitizerTask() override = default; void initDigitizerTask(framework::InitContext& ic) override @@ -101,15 +99,16 @@ class FT0DPLDigitizerTask : public o2::base::BaseDPLDigitizer // call actual digitization procedure mDigitizer.setEventID(part.entryID); mDigitizer.setSrcID(part.sourceID); - mDigitizer.process(&hits, mDigitsBC, mDigitsCh, labels); + mDigitizer.process(&hits, mDigitsBC, mDigitsCh, mDigitsTrig, labels); } } } - mDigitizer.flush_all(mDigitsBC, mDigitsCh, labels); + mDigitizer.flush_all(mDigitsBC, mDigitsCh, mDigitsTrig, labels); // send out to next stage pc.outputs().snapshot(Output{"FT0", "DIGITSBC", 0, Lifetime::Timeframe}, mDigitsBC); pc.outputs().snapshot(Output{"FT0", "DIGITSCH", 0, Lifetime::Timeframe}, mDigitsCh); + pc.outputs().snapshot(Output{"FT0", "TRIGGERINPUT", 0, Lifetime::Timeframe}, mDigitsTrig); if (pc.outputs().isAllowed({"FT0", "DIGITSMCTR", 0})) { pc.outputs().snapshot(Output{"FT0", "DIGITSMCTR", 0, Lifetime::Timeframe}, labels); } @@ -128,6 +127,7 @@ class FT0DPLDigitizerTask : public o2::base::BaseDPLDigitizer bool mFinished = false; std::vector<o2::ft0::ChannelData> mDigitsCh; std::vector<o2::ft0::Digit> mDigitsBC; + std::vector<o2::ft0::DetTrigInput> mDigitsTrig; Bool_t mContinuous = kFALSE; ///< flag to do continuous simulation double mFairTimeUnitInNS = 1; ///< Fair time unit in ns @@ -153,6 +153,7 @@ o2::framework::DataProcessorSpec getFT0DigitizerSpec(int channel, bool mctruth) std::vector<OutputSpec> outputs; outputs.emplace_back("FT0", "DIGITSBC", 0, Lifetime::Timeframe); outputs.emplace_back("FT0", "DIGITSCH", 0, Lifetime::Timeframe); + outputs.emplace_back("FT0", "TRIGGERINPUT", 0, Lifetime::Timeframe); if (mctruth) { outputs.emplace_back("FT0", "DIGITSMCTR", 0, Lifetime::Timeframe); } diff --git a/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.h b/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.h index f335afc772e0e..5cafe96ed609f 100644 --- a/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/FT0DigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/FV0DigitWriterSpec.h b/Steer/DigitizerWorkflow/src/FV0DigitWriterSpec.h index 842e4c947da0d..d79f6a150e8f3 100644 --- a/Steer/DigitizerWorkflow/src/FV0DigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/FV0DigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -38,10 +39,11 @@ o2::framework::DataProcessorSpec getFV0DigitWriterSpec(bool mctruth = true) 1, BranchDefinition<std::vector<o2::fv0::BCData>>{InputSpec{"digitBCinput", "FV0", "DIGITSBC"}, "FV0DigitBC"}, BranchDefinition<std::vector<o2::fv0::ChannelData>>{InputSpec{"digitChinput", "FV0", "DIGITSCH"}, "FV0DigitCh"}, + BranchDefinition<std::vector<o2::fv0::DetTrigInput>>{InputSpec{"digitTrinput", "FV0", "TRIGGERINPUT"}, "TRIGGERINPUT"}, BranchDefinition<o2::dataformats::MCTruthContainer<o2::fv0::MCLabel>>{InputSpec{"labelinput", "FV0", "DIGITLBL"}, "FV0DigitLabels", mctruth ? 1 : 0})(); } } // namespace fv0 } // end namespace o2 -#endif /* STEER_DIGITIZERWORKFLOW_ITSMFTDIGITWRITER_H_ */ +#endif /* STEER_DIGITIZERWORKFLOW_FV0DIGITWRITER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx index 7e501e6f2ed81..9e13e71fcaf31 100644 --- a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -48,8 +49,9 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer void initDigitizerTask(framework::InitContext& ic) override { - LOG(INFO) << "FV0DPLDigitizerTask:init"; + LOG(DEBUG) << "FV0DPLDigitizerTask:init"; mDigitizer.init(); + mDisableQED = ic.options().get<bool>("disable-qed"); //TODO: QED implementation to be tested } void run(framework::ProcessingContext& pc) @@ -57,16 +59,17 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer if (mFinished) { return; } - LOG(INFO) << "FV0DPLDigitizerTask:run"; + LOG(DEBUG) << "FV0DPLDigitizerTask:run"; // read collision context from input auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); context->initSimChains(o2::detectors::DetID::FV0, mSimChains); + const bool withQED = context->isQEDProvided() && !mDisableQED; //TODO: QED implementation to be tested mDigitizer.setTimeStamp(context->getGRP().getTimeStart()); - auto& irecords = context->getEventRecords(); - auto& eventParts = context->getEventParts(); + auto& irecords = context->getEventRecords(withQED); //TODO: QED implementation to be tested + auto& eventParts = context->getEventParts(withQED); //TODO: QED implementation to be tested // loop over all composite collisions given from context // (aka loop over all the interaction records) @@ -80,20 +83,20 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer for (auto& part : eventParts[collID]) { hits.clear(); context->retrieveHits(mSimChains, "FV0Hit", part.sourceID, part.entryID, &hits); - LOG(INFO) << "[FV0] For collision " << collID << " eventID " << part.entryID << " found " << hits.size() << " hits "; + LOG(DEBUG) << "[FV0] For collision " << collID << " eventID " << part.entryID << " found " << hits.size() << " hits "; // call actual digitization procedure mDigitizer.setEventId(part.entryID); mDigitizer.setSrcId(part.sourceID); - mDigitizer.process(hits, mDigitsBC, mDigitsCh, mLabels); + mDigitizer.process(hits, mDigitsBC, mDigitsCh, mDigitsTrig, mLabels); } - LOG(INFO) << "[FV0] Has " << mDigitsBC.size() << " BC elements, " << mDigitsCh.size() << " mDigitsCh elements"; + LOG(DEBUG) << "[FV0] Has " << mDigitsBC.size() << " BC elements, " << mDigitsCh.size() << " mDigitsCh elements"; } o2::InteractionTimeRecord terminateIR; terminateIR.orbit = 0xffffffff; // supply IR in the infinite future to flush all cached BC mDigitizer.setInteractionRecord(terminateIR); - mDigitizer.flush(mDigitsBC, mDigitsCh, mLabels); + mDigitizer.flush(mDigitsBC, mDigitsCh, mDigitsTrig, mLabels); // here we have all digits and we can send them to consumer (aka snapshot it onto output) LOG(INFO) << "FV0: Sending " << mDigitsBC.size() << " digitsBC and " << mDigitsCh.size() << " digitsCh."; @@ -101,6 +104,7 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer // send out to next stage pc.outputs().snapshot(Output{"FV0", "DIGITSBC", 0, Lifetime::Timeframe}, mDigitsBC); pc.outputs().snapshot(Output{"FV0", "DIGITSCH", 0, Lifetime::Timeframe}, mDigitsCh); + pc.outputs().snapshot(Output{"FV0", "TRIGGERINPUT", 0, Lifetime::Timeframe}, mDigitsTrig); if (pc.outputs().isAllowed({"FV0", "DIGITLBL", 0})) { pc.outputs().snapshot(Output{"FV0", "DIGITLBL", 0, Lifetime::Timeframe}, mLabels); } @@ -118,10 +122,12 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer std::vector<TChain*> mSimChains; std::vector<o2::fv0::ChannelData> mDigitsCh; std::vector<o2::fv0::BCData> mDigitsBC; + std::vector<o2::fv0::DetTrigInput> mDigitsTrig; o2::dataformats::MCTruthContainer<o2::fv0::MCLabel> mLabels; // labels which get filled // RS: at the moment using hardcoded flag for continuous readout o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::CONTINUOUS; // readout mode + bool mDisableQED = false; }; o2::framework::DataProcessorSpec getFV0DigitizerSpec(int channel, bool mctruth) @@ -134,6 +140,7 @@ o2::framework::DataProcessorSpec getFV0DigitizerSpec(int channel, bool mctruth) std::vector<OutputSpec> outputs; outputs.emplace_back("FV0", "DIGITSBC", 0, Lifetime::Timeframe); outputs.emplace_back("FV0", "DIGITSCH", 0, Lifetime::Timeframe); + outputs.emplace_back("FV0", "TRIGGERINPUT", 0, Lifetime::Timeframe); if (mctruth) { outputs.emplace_back("FV0", "DIGITLBL", 0, Lifetime::Timeframe); } @@ -146,8 +153,9 @@ o2::framework::DataProcessorSpec getFV0DigitizerSpec(int channel, bool mctruth) outputs, AlgorithmSpec{adaptFromTask<FV0DPLDigitizerTask>()}, - - Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; + Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}, + {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; + //Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; } } // end namespace fv0 diff --git a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.h b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.h index f5048b4a3f89d..2d5d2d440b07a 100644 --- a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.cxx b/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.cxx index 70639be2212f2..edd7dbc47c98a 100644 --- a/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.cxx +++ b/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,11 +17,17 @@ #include "Framework/Task.h" #include "Framework/Lifetime.h" #include "DataFormatsParameters/GRPObject.h" -#include "Headers/DataHeader.h" #include <TFile.h> #include <FairLogger.h> #include <memory> // for make_shared, make_unique, unique_ptr #include <string> +#include "DetectorsRaw/HBFUtils.h" + +// this is for some process synchronization, since +// we need to prevent writing concurrently to the same global GRP file +#include <boost/interprocess/sync/named_semaphore.hpp> +#include <filesystem> +#include <unordered_map> // for the hashing utility using namespace o2::framework; @@ -48,35 +55,68 @@ class GRPDPLUpdatedTask void run(framework::ProcessingContext& pc) { const std::string grpName = "GRP"; - if (mFinished) { - return; - } - TFile flGRP(mGRPFileName.c_str(), "update"); - if (flGRP.IsZombie()) { - LOG(ERROR) << "Failed to open in update mode " << mGRPFileName; - return; + // a standardized semaphore convention --> taking the current execution path should be enough + // (the user enables this via O2_USEGRP_SEMA environment) + bool use_sema = false; + boost::interprocess::named_semaphore* sem = nullptr; + std::string semhashedstring; + try { + const auto semname = std::filesystem::current_path().string() + mGRPFileName; + std::hash<std::string> hasher; + semhashedstring = "alice_grp_" + std::to_string(hasher(semname)).substr(0, 16); + sem = new boost::interprocess::named_semaphore(boost::interprocess::open_or_create_t{}, semhashedstring.c_str(), 1); + } catch (std::exception e) { + LOG(WARN) << "Could not setup GRP semaphore; Continuing without"; + sem = nullptr; } - std::unique_ptr<GRP> grp(static_cast<GRP*>(flGRP.GetObjectChecked(grpName.c_str(), GRP::Class()))); - for (auto det : sDetList) { // get readout mode data from different detectors - auto roMode = pc.inputs().get<o2::parameters::GRPObject::ROMode>(det.getName()); - if (!(roMode & o2::parameters::GRPObject::PRESENT)) { - LOG(ERROR) << "Detector " << det.getName() << " is read out while processor set ABSENT"; - continue; + try { + if (sem) { + sem->wait(); // wait until we can enter (no one else there) } - grp->setDetROMode(det, roMode); - } - LOG(INFO) << "Updated GRP in " << mGRPFileName << " for detectors RO mode"; - grp->print(); - flGRP.WriteObjectAny(grp.get(), grp->Class(), grpName.c_str()); - flGRP.Close(); - mFinished = true; + auto postSem = [sem, &semhashedstring] { + if (sem) { + sem->post(); + if (sem->try_wait()) { + // if nobody else is waiting remove the semaphore resource + sem->post(); + boost::interprocess::named_semaphore::remove(semhashedstring.c_str()); + } + delete sem; + } + }; + + TFile flGRP(mGRPFileName.c_str(), "update"); + if (flGRP.IsZombie()) { + LOG(ERROR) << "Failed to open in update mode " << mGRPFileName; + postSem(); + return; + } + std::unique_ptr<GRP> grp(static_cast<GRP*>(flGRP.GetObjectChecked(grpName.c_str(), GRP::Class()))); + for (auto det : sDetList) { // get readout mode data from different detectors + auto roMode = pc.inputs().get<o2::parameters::GRPObject::ROMode>(det.getName()); + if (!(roMode & o2::parameters::GRPObject::PRESENT)) { + LOG(ERROR) << "Detector " << det.getName() << " is read out while processor set ABSENT"; + continue; + } + grp->setDetROMode(det, roMode); + } + grp->setFirstOrbit(o2::raw::HBFUtils::Instance().orbitFirst); + grp->setNHBFPerTF(o2::raw::HBFUtils::Instance().nHBFPerTF); + LOG(INFO) << "Updated GRP in " << mGRPFileName << " for detectors RO mode and 1st orbit of the run"; + grp->print(); + flGRP.WriteObjectAny(grp.get(), grp->Class(), grpName.c_str()); + flGRP.Close(); + + postSem(); + } catch (boost::interprocess::interprocess_exception e) { + LOG(ERROR) << "Caught semaphore exception " << e.what(); + } pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); } private: - bool mFinished = false; std::string mGRPFileName = "o2sim_grp.root"; }; diff --git a/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.h b/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.h index a0cad08e906cf..719ca5fb47f22 100644 --- a/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.h +++ b/Steer/DigitizerWorkflow/src/GRPUpdaterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h index 4d66a83fddd82..38fc86285ea9c 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,8 @@ #include "Framework/DataProcessorSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" -#include "HMPIDBase/Digit.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -35,6 +37,7 @@ o2::framework::DataProcessorSpec getHMPIDDigitWriterSpec(bool mctruth = true) "o2sim", 1, BranchDefinition<std::vector<o2::hmpid::Digit>>{InputSpec{"digitinput", "HMP", "DIGITS"}, "HMPDigit"}, + BranchDefinition<std::vector<o2::hmpid::Trigger>>{InputSpec{"interactionrecods", "HMP", "INTRECORDS"}, "InteractionRecords"}, BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"labelinput", "HMP", "DIGITLBL"}, "HMPDigitLabels", mctruth ? 1 : 0})(); } diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx index 61d298248687f..1b7d0d40f55a7 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,7 +23,8 @@ #include <SimulationDataFormat/MCTruthContainer.h> #include "Framework/Task.h" #include "DataFormatsParameters/GRPObject.h" -#include "HMPIDBase/Digit.h" +#include "DataFormatsHMP/Digit.h" +#include "DataFormatsHMP/Trigger.h" #include "HMPIDSimulation/HMPIDDigitizer.h" #include "HMPIDSimulation/Detector.h" #include "DetectorsBase/BaseDPLDigitizer.h" @@ -61,7 +63,6 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer context->initSimChains(o2::detectors::DetID::HMP, mSimChains); auto& irecords = context->getEventRecords(); - for (auto& record : irecords) { LOG(INFO) << "HMPID TIME RECEIVED " << record.getTimeNS(); } @@ -69,6 +70,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer auto& eventParts = context->getEventParts(); std::vector<o2::hmpid::Digit> digitsAccum; // accumulator for digits o2::dataformats::MCTruthContainer<o2::MCCompLabel> labelAccum; // timeframe accumulator for labels + mIntRecord.clear(); auto flushDigitsAndLabels = [this, &digitsAccum, &labelAccum]() { // flush previous buffer @@ -77,20 +79,23 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.flush(mDigits); LOG(INFO) << "HMPID flushed " << mDigits.size() << " digits at this time "; LOG(INFO) << "NUMBER OF LABEL OBTAINED " << mLabels.getNElements(); + int32_t first = digitsAccum.size(); // this is the first std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum)); labelAccum.mergeAtBack(mLabels); + + // save info for the triggers accepted + LOG(INFO) << "Trigger Orbit :" << mDigitizer.getOrbit() << " BC:" << mDigitizer.getBc(); + mIntRecord.push_back(o2::hmpid::Trigger(o2::InteractionRecord(mDigitizer.getBc(), mDigitizer.getOrbit()), first, digitsAccum.size() - first)); }; // loop over all composite collisions given from context // (aka loop over all the interaction records) for (int collID = 0; collID < irecords.size(); ++collID) { - // try to start new readout cycle by setting the trigger time auto triggeraccepted = mDigitizer.setTriggerTime(irecords[collID].getTimeNS()); if (triggeraccepted) { flushDigitsAndLabels(); // flush previous readout cycle } - auto withinactivetime = mDigitizer.setEventTime(irecords[collID].getTimeNS()); if (withinactivetime) { // for each collision, loop over the constituents event and source IDs @@ -110,6 +115,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.process(hits, mDigits); } + } else { LOG(INFO) << "COLLISION " << collID << "FALLS WITHIN A DEAD TIME"; } @@ -119,6 +125,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer // send out to next stage pc.outputs().snapshot(Output{"HMP", "DIGITS", 0, Lifetime::Timeframe}, digitsAccum); + pc.outputs().snapshot(Output{"HMP", "INTRECORDS", 0, Lifetime::Timeframe}, mIntRecord); if (pc.outputs().isAllowed({"HMP", "DIGITLBL", 0})) { pc.outputs().snapshot(Output{"HMP", "DIGITLBL", 0, Lifetime::Timeframe}, labelAccum); } @@ -135,6 +142,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer std::vector<TChain*> mSimChains; std::vector<o2::hmpid::Digit> mDigits; o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels; // labels which get filled + std::vector<o2::hmpid::Trigger> mIntRecord; // RS: at the moment using hardcoded flag for continuous readout o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::CONTINUOUS; // readout mode @@ -149,6 +157,7 @@ o2::framework::DataProcessorSpec getHMPIDDigitizerSpec(int channel, bool mctruth // options that can be used for this processor (here: input file names where to take the hits) std::vector<OutputSpec> outputs; outputs.emplace_back("HMP", "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back("HMP", "INTRECORDS", 0, Lifetime::Timeframe); if (mctruth) { outputs.emplace_back("HMP", "DIGITLBL", 0, Lifetime::Timeframe); } diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.h b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.h index fd826f67f4397..c5992a26c5ff1 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx new file mode 100644 index 0000000000000..29c5b7f4169de --- /dev/null +++ b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx @@ -0,0 +1,286 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSMFTDigitizerSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataRefUtils.h" +#include "Framework/Lifetime.h" +#include "Framework/Task.h" +#include "Steer/HitProcessingManager.h" // for DigitizationContext +#include "DataFormatsITSMFT/Digit.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DetectorsBase/BaseDPLDigitizer.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/SimTraits.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITS3Simulation/Digitizer.h" +#include "ITSMFTSimulation/DPLDigitizerParam.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ITS3Base/GeometryTGeo.h" +#include <TChain.h> +#include <TStopwatch.h> +#include <string> + +using namespace o2::framework; +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +namespace +{ +std::vector<OutputSpec> makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth) +{ + std::vector<OutputSpec> outputs; + outputs.emplace_back(detOrig, "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSROF", 0, Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(detOrig, "DIGITSMC2ROF", 0, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSMCTR", 0, Lifetime::Timeframe); + } + outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe); + return outputs; +} +} // namespace + +namespace o2 +{ +namespace its3 +{ + +using namespace o2::base; +class ITS3DPLDigitizerTask : BaseDPLDigitizer +{ + public: + static constexpr o2::detectors::DetID::ID DETID = o2::detectors::DetID::IT3; + static constexpr o2::header::DataOrigin DETOR = o2::header::gDataOriginIT3; + using BaseDPLDigitizer::init; + + ITS3DPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) + { + mID = DETID; + mOrigin = DETOR; + } + + void initDigitizerTask(framework::InitContext& ic) override + { + setDigitizationOptions(); // set options provided via configKeyValues mechanism + auto& digipar = mDigitizer.getParams(); + + mROMode = digipar.isContinuous() ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::PRESENT; + LOG(INFO) << mID.getName() << " simulated in " + << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED") + << " RO mode"; + + // configure digitizer + o2::its3::GeometryTGeo* geom = o2::its3::GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); // make sure L2G matrices are loaded + mDigitizer.setGeometry(geom); + + mDisableQED = ic.options().get<bool>("disable-qed"); + + // init digitizer + mDigitizer.init(); + } + + virtual void setDigitizationOptions() + { + auto& dopt = o2::itsmft::DPLDigitizerParam<o2::detectors::DetID::ITS>::Instance(); + auto& aopt = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); + auto& digipar = mDigitizer.getParams(); + digipar.setContinuous(dopt.continuous); + if (dopt.continuous) { + auto frameNS = aopt.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS; + digipar.setROFrameLengthInBC(aopt.roFrameLengthInBC); + digipar.setROFrameLength(frameNS); // RO frame in ns + digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns + digipar.setStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); // Strobe length in ns + } else { + digipar.setROFrameLength(aopt.roFrameLengthTrig); // RO frame in ns + digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns + digipar.setStrobeLength(aopt.strobeLengthTrig); // Strobe length in ns + } + // parameters of signal time response: flat-top duration, max rise time and q @ which rise time is 0 + digipar.getSignalShape().setParameters(dopt.strobeFlatTop, dopt.strobeMaxRiseTime, dopt.strobeQRiseTime0); + digipar.setChargeThreshold(dopt.chargeThreshold); // charge threshold in electrons + digipar.setNoisePerPixel(dopt.noisePerPixel); // noise level + digipar.setTimeOffset(dopt.timeOffset); + digipar.setNSimSteps(dopt.nSimSteps); + } + + void run(framework::ProcessingContext& pc) + { + if (mFinished) { + return; + } + std::string detStr = mID.getName(); + // read collision context from input + auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); + context->initSimChains(mID, mSimChains); + const bool withQED = context->isQEDProvided() && !mDisableQED; + auto& timesview = context->getEventRecords(withQED); + LOG(INFO) << "GOT " << timesview.size() << " COLLISSION TIMES"; + LOG(INFO) << "SIMCHAINS " << mSimChains.size(); + + // if there is nothing to do ... return + if (timesview.size() == 0) { + return; + } + TStopwatch timer; + timer.Start(); + LOG(INFO) << " CALLING ITS3 DIGITIZATION "; + + mDigitizer.setDigits(&mDigits); + mDigitizer.setROFRecords(&mROFRecords); + mDigitizer.setMCLabels(&mLabels); + + // digits are directly put into DPL owned resource + auto& digitsAccum = pc.outputs().make<std::vector<itsmft::Digit>>(Output{mOrigin, "DIGITS", 0, Lifetime::Timeframe}); + + auto accumulate = [this, &digitsAccum]() { + // accumulate result of single event processing, called after processing every event supplied + // AND after the final flushing via digitizer::fillOutputContainer + if (!mDigits.size()) { + return; // no digits were flushed, nothing to accumulate + } + static int fixMC2ROF = 0; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID + auto ndigAcc = digitsAccum.size(); + std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum)); + + // fix ROFrecords references on ROF entries + auto nROFRecsOld = mROFRecordsAccum.size(); + + for (int i = 0; i < mROFRecords.size(); i++) { + auto& rof = mROFRecords[i]; + rof.setFirstEntry(ndigAcc + rof.getFirstEntry()); + rof.print(); + + if (mFixMC2ROF < mMC2ROFRecordsAccum.size()) { // fix ROFRecord entry in MC2ROF records + for (int m2rid = mFixMC2ROF; m2rid < mMC2ROFRecordsAccum.size(); m2rid++) { + // need to register the ROFRecors entry for MC event starting from this entry + auto& mc2rof = mMC2ROFRecordsAccum[m2rid]; + if (rof.getROFrame() == mc2rof.minROF) { + mFixMC2ROF++; + mc2rof.rofRecordID = nROFRecsOld + i; + mc2rof.print(); + } + } + } + } + + std::copy(mROFRecords.begin(), mROFRecords.end(), std::back_inserter(mROFRecordsAccum)); + if (mWithMCTruth) { + mLabelsAccum.mergeAtBack(mLabels); + } + LOG(INFO) << "Added " << mDigits.size() << " digits "; + // clean containers from already accumulated stuff + mLabels.clear(); + mDigits.clear(); + mROFRecords.clear(); + }; // and accumulate lambda + + auto& eventParts = context->getEventParts(withQED); + // loop over all composite collisions given from context (aka loop over all the interaction records) + for (int collID = 0; collID < timesview.size(); ++collID) { + const auto& irt = timesview[collID]; + + mDigitizer.setEventTime(irt); + mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID + // for each collision, loop over the constituents event and source IDs + // (background signal merging is basically taking place here) + for (auto& part : eventParts[collID]) { + + // get the hits for this event and this source + mHits.clear(); + context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[mID][0].c_str(), part.sourceID, part.entryID, &mHits); + + if (mHits.size() > 0) { + LOG(DEBUG) << "For collision " << collID << " eventID " << part.entryID + << " found " << mHits.size() << " hits "; + mDigitizer.process(&mHits, part.entryID, part.sourceID); // call actual digitization procedure + } + } + mMC2ROFRecordsAccum.emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax()); + accumulate(); + } + mDigitizer.fillOutputContainer(); + accumulate(); + + // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) + + pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0, Lifetime::Timeframe}, mROFRecordsAccum); + if (mWithMCTruth) { + pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0, Lifetime::Timeframe}, mMC2ROFRecordsAccum); + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", 0, Lifetime::Timeframe}); + mLabelsAccum.flatten_to(sharedlabels); + // free space of existing label containers + mLabels.clear_andfreememory(); + mLabelsAccum.clear_andfreememory(); + } + LOG(INFO) << mID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater"; + pc.outputs().snapshot(Output{mOrigin, "ROMode", 0, Lifetime::Timeframe}, mROMode); + + timer.Stop(); + LOG(INFO) << "Digitization took " << timer.CpuTime() << "s"; + + // we should be only called once; tell DPL that this process is ready to exit + pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); + + mFinished = true; + } + + protected: + bool mWithMCTruth = true; + bool mFinished = false; + bool mDisableQED = false; + o2::detectors::DetID mID; + o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + o2::its3::Digitizer mDigitizer; + std::vector<o2::itsmft::Digit> mDigits; + std::vector<o2::itsmft::ROFRecord> mROFRecords; + std::vector<o2::itsmft::ROFRecord> mROFRecordsAccum; + std::vector<o2::itsmft::Hit> mHits; + std::vector<o2::itsmft::Hit>* mHitsP = &mHits; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabelsAccum; + std::vector<o2::itsmft::MC2ROFRecord> mMC2ROFRecordsAccum; + std::vector<TChain*> mSimChains; + + int mFixMC2ROF = 0; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID + o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::PRESENT; // readout mode +}; + +constexpr o2::detectors::DetID::ID ITS3DPLDigitizerTask::DETID; +constexpr o2::header::DataOrigin ITS3DPLDigitizerTask::DETOR; + +DataProcessorSpec getITS3DigitizerSpec(int channel, bool mctruth) +{ + std::string detStr = o2::detectors::DetID::getName(ITS3DPLDigitizerTask::DETID); + auto detOrig = ITS3DPLDigitizerTask::DETOR; + std::stringstream parHelper; + parHelper << "Params as " << o2::itsmft::DPLDigitizerParam<o2::detectors::DetID::ITS>::getParamName().data() << ".<param>=value;... with" + << o2::itsmft::DPLDigitizerParam<o2::detectors::DetID::ITS>::Instance() + << "\n or " << o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::getParamName().data() << ".<param>=value;... with" + << o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance(); + + return DataProcessorSpec{(detStr + "Digitizer").c_str(), + Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", + static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}}, + makeOutChannels(detOrig, mctruth), + AlgorithmSpec{adaptFromTask<ITS3DPLDigitizerTask>(mctruth)}, + Options{ + {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}} + // { "configKeyValues", VariantType::String, "", { parHelper.str().c_str() } } + }}; +} + +} // namespace its3 +} // end namespace o2 diff --git a/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.h b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.h new file mode 100644 index 0000000000000..d5ffb5b686d3e --- /dev/null +++ b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef STEER_DIGITIZERWORKFLOW_ITS3DIGITIZER_H_ +#define STEER_DIGITIZERWORKFLOW_ITS3DIGITIZER_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace its3 +{ + +o2::framework::DataProcessorSpec getITS3DigitizerSpec(int channel, bool mctruth = true); + +} // namespace its3 +} // end namespace o2 + +#endif /* STEER_DIGITIZERWORKFLOW_ITS3DIGITIZER_H_ */ diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx index 03c5af766a837..d84f73d400991 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,6 @@ #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" -#include "Headers/DataHeader.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "DataFormatsITSMFT/Digit.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.h b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.h index e041129426713..55fd88b1e1f80 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCHDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/MCHDigitWriterSpec.h index a74a7994083a3..7d4f41efa4406 100644 --- a/Steer/DigitizerWorkflow/src/MCHDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/MCHDigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,8 @@ #include "Framework/DataProcessorSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" -#include "MCHBase/Digit.h" +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" #include <SimulationDataFormat/MCCompLabel.h> #include <SimulationDataFormat/MCTruthContainer.h> @@ -35,7 +37,8 @@ o2::framework::DataProcessorSpec getMCHDigitWriterSpec(bool mctruth) "o2sim", 1, //default number of events BranchDefinition<std::vector<o2::mch::Digit>>{InputSpec{"mchdigits", "MCH", "DIGITS"}, "MCHDigit"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"mchdigitlabels", "MCH", "DIGITSMCTR"}, "MCHMCLabels", mctruth ? 1 : 0} + BranchDefinition<std::vector<o2::mch::ROFRecord>>{InputSpec{"mchrofrecords", "MCH", "DIGITROFS"}, "MCHROFRecords"}, + BranchDefinition<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>{InputSpec{"mchdigitlabels", "MCH", "DIGITSLABELS"}, "MCHMCLabels", mctruth ? 1 : 0} // add more branch definitions (for example Monte Carlo labels here) )(); } diff --git a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx index c6c8bafc155e8..739f993290753 100644 --- a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx @@ -1,31 +1,35 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "MCHDigitizerSpec.h" + +#include "DataFormatsMCH/Digit.h" +#include "DataFormatsMCH/ROFRecord.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/BaseDPLDigitizer.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" -#include "Headers/DataHeader.h" -#include "TStopwatch.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext +#include "Framework/Task.h" +#include "MCHSimulation/Detector.h" +#include "MCHSimulation/Digitizer.h" +#include "MCHSimulation/DigitizerParam.h" +#include "SimulationDataFormat/DigitizationContext.h" #include "TChain.h" #include <SimulationDataFormat/MCCompLabel.h> #include <SimulationDataFormat/MCTruthContainer.h> -#include "Framework/Task.h" -#include "DataFormatsParameters/GRPObject.h" -#include "MCHBase/Digit.h" -#include "MCHSimulation/Digitizer.h" -#include "MCHSimulation/Detector.h" -#include "DetectorsBase/BaseDPLDigitizer.h" +#include <TGeoManager.h> +#include <map> using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; @@ -42,7 +46,24 @@ class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer void initDigitizerTask(framework::InitContext& ic) override { - // nothing specific do to + auto transformation = o2::mch::geo::transformationFromTGeoManager(*gGeoManager); + mDigitizer = std::make_unique<Digitizer>(transformation); + } + + void logStatus(gsl::span<Digit> digits, gsl::span<ROFRecord> rofs, + o2::dataformats::MCTruthContainer<o2::MCCompLabel>& labels, + std::chrono::high_resolution_clock::time_point start) + { + LOGP(info, "Number of digits : {}", digits.size()); + LOGP(info, "Number of rofs : {}", rofs.size()); + LOGP(info, "Number of labels : {} (indexed {})", labels.getNElements(), labels.getIndexedSize()); + if (labels.getIndexedSize() != digits.size()) { + LOGP(error, "Number of labels != number of digits"); + } + auto tEnd = std::chrono::high_resolution_clock::now(); + auto duration = tEnd - start; + auto d = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); + LOGP(info, "Digitizer time {} ms", d); } void run(framework::ProcessingContext& pc) @@ -51,97 +72,67 @@ class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer if (finished) { return; } - LOG(DEBUG) << "Doing MCH digitization"; - - // read collision context from input + float noiseProba = DigitizerParam::Instance().noiseProba; + auto tStart = std::chrono::high_resolution_clock::now(); auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); context->initSimChains(o2::detectors::DetID::MCH, mSimChains); - auto& irecords = context->getEventRecords(); - - for (auto& record : irecords) { - LOG(DEBUG) << "MCH TIME RECEIVED " << record.getTimeNS(); - LOG(DEBUG) << "MCH TIME RECEIVED: bc " << record.bc; - } - - auto& eventParts = context->getEventParts(); - std::vector<o2::mch::Digit> digitsAccum; // accumulator for digits - o2::dataformats::MCTruthContainer<o2::MCCompLabel> labelAccum; - - // loop over all composite collisions given from context - // (aka loop over all the interaction records) - for (int collID = 0; collID < irecords.size(); ++collID) { - // mDigitizer.setEventTime(irecords[collID].getTimeNS()); - mDigitizer.setEventTime(irecords[collID].bc); - // for each collision, loop over the constituents event and source IDs - // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { - mDigitizer.setEventID(part.entryID); - mDigitizer.setSrcID(part.sourceID); - - // get the hits for this event and this source - std::vector<o2::mch::Hit> hits; - context->retrieveHits(mSimChains, "MCHHit", part.sourceID, part.entryID, &hits); - LOG(DEBUG) << "For collision " << collID << " eventID " << part.entryID << " found MCH " << hits.size() << " hits "; - - std::vector<o2::mch::Digit> digits; // digits which get filled - o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels; - - mDigitizer.process(hits, digits, labels); - LOG(DEBUG) << "MCH obtained " << digits.size() << " digits "; - for (auto& d : digits) { - LOG(DEBUG) << "ADC " << d.getADC(); - LOG(DEBUG) << "PAD " << d.getPadID(); - LOG(DEBUG) << "TIME " << d.getTime().sampaTime; - LOG(DEBUG) << "DetID " << d.getDetID(); + const auto& eventRecords = context->getEventRecords(); + const auto& eventParts = context->getEventParts(); + std::vector<o2::mch::Digit> digits; + std::vector<o2::mch::ROFRecord> rofs; + o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels; + size_t firstIdx = 0; + auto mchRecords = groupIR(eventRecords); + for (auto mrec : mchRecords) { + auto collisionIndices = mrec.second; + const auto& mchIR = mrec.first; + mDigitizer->startCollision(mchIR); + for (auto collisionIndex : collisionIndices) { + for (const auto& part : eventParts[collisionIndex]) { + std::vector<o2::mch::Hit> hits; + context->retrieveHits(mSimChains, "MCHHit", part.sourceID, part.entryID, &hits); + mDigitizer->processHits(hits, part.entryID, part.sourceID); } - std::copy(digits.begin(), digits.end(), std::back_inserter(digitsAccum)); - labelAccum.mergeAtBack(labels); //is this ok? check inside MCtruthContainer if this is what one wants to do. - LOG(DEBUG) << "labelAccum.getIndexedSize() " << labelAccum.getIndexedSize(); - LOG(DEBUG) << "labelAccum.getNElements() " << labelAccum.getNElements(); - LOG(DEBUG) << "Have " << digits.size() << " digits "; } + mDigitizer->addNoise(noiseProba); + mDigitizer->extractDigitsAndLabels(digits, labels); + auto nEntries = digits.size() - firstIdx; + rofs.emplace_back(ROFRecord(mchIR, firstIdx, nEntries)); + firstIdx = digits.size(); } - mDigitizer.mergeDigits(digitsAccum, labelAccum); //print-out inside alos works fine - - LOG(DEBUG) << "Have " << labelAccum.getNElements() << " MCH labels "; //does not work out! - pc.outputs().snapshot(Output{"MCH", "DIGITS", 0, Lifetime::Timeframe}, digitsAccum); - if (pc.outputs().isAllowed({"MCH", "DIGITSMCTR", 0})) { - pc.outputs().snapshot(Output{"MCH", "DIGITSMCTR", 0, Lifetime::Timeframe}, labelAccum); + pc.outputs().snapshot(Output{"MCH", "DIGITS", 0, Lifetime::Timeframe}, digits); + pc.outputs().snapshot(Output{"MCH", "DIGITROFS", 0, Lifetime::Timeframe}, rofs); + if (pc.outputs().isAllowed({"MCH", "DIGITSLABELS", 0})) { + pc.outputs().snapshot(Output{"MCH", "DIGITSLABELS", 0, Lifetime::Timeframe}, labels); } - LOG(DEBUG) << "MCH: Sending ROMode= " << mROMode << " to GRPUpdater"; - //ROMode: to be understood, check EMCal etc. - pc.outputs().snapshot(Output{"MCH", "ROMode", 0, Lifetime::Timeframe}, mROMode); + pc.outputs().snapshot(Output{"MCH", "ROMode", 0, Lifetime::Timeframe}, + DigitizerParam::Instance().continuous ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::TRIGGERING); // we should be only called once; tell DPL that this process is ready to exit pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); finished = true; + + logStatus(digits, rofs, labels, tStart); } private: - Digitizer mDigitizer; + std::unique_ptr<Digitizer> mDigitizer; std::vector<TChain*> mSimChains; - // RS: at the moment using hardcoded flag for continuos readout - o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::CONTINUOUS; // readout mode }; o2::framework::DataProcessorSpec getMCHDigitizerSpec(int channel, bool mctruth) { - // create the full data processor spec using - // a name identifier - // input description - // algorithmic description (here a lambda getting called once to setup the actual processing function) - // options that can be used for this processor (here: input file names where to take the hits) std::vector<OutputSpec> outputs; outputs.emplace_back("MCH", "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back("MCH", "DIGITROFS", 0, Lifetime::Timeframe); if (mctruth) { - outputs.emplace_back("MCH", "DIGITSMCTR", 0, Lifetime::Timeframe); + outputs.emplace_back("MCH", "DIGITSLABELS", 0, Lifetime::Timeframe); } outputs.emplace_back("MCH", "ROMode", 0, Lifetime::Timeframe); return DataProcessorSpec{ "MCHDigitizer", Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}}, - outputs, AlgorithmSpec{adaptFromTask<MCHDPLDigitizerTask>()}, Options{}}; diff --git a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.h b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.h index 4d1d552e1aff4..da45073f43ec6 100644 --- a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthReaderSpec.h b/Steer/DigitizerWorkflow/src/MCTruthReaderSpec.h index eb507f4d4afe1..badb38ad97b59 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthReaderSpec.h +++ b/Steer/DigitizerWorkflow/src/MCTruthReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.cxx b/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.cxx index c80ae833cb31b..e4960b7dae6bc 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.h b/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.h index e9a23c36c260e..af7b6b21a0126 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.h +++ b/Steer/DigitizerWorkflow/src/MCTruthSourceSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthTestWorkflow.cxx b/Steer/DigitizerWorkflow/src/MCTruthTestWorkflow.cxx index 4f91872726a8a..253167f6b78e7 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthTestWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/MCTruthTestWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.cxx b/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.cxx index b35db1ad01954..edbbf2f2fdd7f 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.h b/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.h index 436077f1b0386..51afe5388fee6 100644 --- a/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/MCTruthWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MIDDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/MIDDigitWriterSpec.h index 203414cdb4c96..9ee223f13aa8d 100644 --- a/Steer/DigitizerWorkflow/src/MIDDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/MIDDigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.cxx index 62a0cb03e92fa..b4f5c184a503f 100644 --- a/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,7 +17,6 @@ #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" -#include "Headers/DataHeader.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "DetectorsBase/BaseDPLDigitizer.h" #include "SimulationDataFormat/MCTruthContainer.h" diff --git a/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.h b/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.h index 7e3cadba53f37..41b3148fd1a2a 100644 --- a/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/MIDDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h index 21055f5ef9142..5352acbcfd370 100644 --- a/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,13 +33,22 @@ o2::framework::DataProcessorSpec getPHOSDigitWriterSpec(bool mctruth) { using InputSpec = framework::InputSpec; using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - return MakeRootTreeWriterSpec("PHOSDigitWriter", - "phosdigits.root", - "o2sim", - 1, - BranchDefinition<std::vector<o2::phos::Digit>>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, - BranchDefinition<std::vector<o2::phos::TriggerRecord>>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{InputSpec{"phosdigitsmc", "PHS", "DIGITSMCTR"}, "PHOSDigitMCTruth", mctruth ? 1 : 0})(); + if (mctruth) { + return MakeRootTreeWriterSpec("PHOSDigitWriter", + "phosdigits.root", + "o2sim", + 1, + BranchDefinition<std::vector<o2::phos::Digit>>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, + BranchDefinition<std::vector<o2::phos::TriggerRecord>>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"}, + BranchDefinition<o2::dataformats::MCTruthContainer<o2::phos::MCLabel>>{InputSpec{"phosdigitsmc", "PHS", "DIGITSMCTR"}, "PHOSDigitMCTruth"})(); + } else { + return MakeRootTreeWriterSpec("PHOSDigitWriter", + "phosdigits.root", + "o2sim", + 1, + BranchDefinition<std::vector<o2::phos::Digit>>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, + BranchDefinition<std::vector<o2::phos::TriggerRecord>>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"})(); + } } } // namespace phos diff --git a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx index fde0562970a56..9f571929d1f92 100644 --- a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,14 +15,13 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" -#include "Headers/DataHeader.h" #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" - #include "CommonDataFormat/EvIndex.h" #include "DataFormatsPHOS/TriggerRecord.h" #include "PHOSSimulation/Digitizer.h" +#include "PHOSBase/PHOSSimParams.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsPHOS/MCLabel.h" #include <SimulationDataFormat/MCTruthContainer.h> @@ -36,22 +36,27 @@ namespace phos void DigitizerSpec::initDigitizerTask(framework::InitContext& ic) { - // run 3 geometry == run 2 geometry for PHOS - // create singleton geometry - o2::phos::Geometry::GetInstance("Run2"); - // init digitizer - mDigitizer.init(); - if (mHitsS) { - delete mHitsS; + auto simulatePileup = ic.options().get<int>("pileup"); + if (simulatePileup) { // set readout time and dead time parameters + mReadoutTime = o2::phos::PHOSSimParams::Instance().mReadoutTimePU; //PHOS readout time in ns + mDeadTime = o2::phos::PHOSSimParams::Instance().mDeadTimePU; //PHOS dead time (should include readout => mReadoutTime< mDeadTime) + } else { + mReadoutTime = o2::phos::PHOSSimParams::Instance().mReadoutTime; //PHOS readout time in ns + mDeadTime = o2::phos::PHOSSimParams::Instance().mDeadTime; //PHOS dead time (should include readout => mReadoutTime< mDeadTime) } - mHitsS = new std::vector<Hit>(); - if (mHitsBg) { - delete mHitsBg; + + // init digitizer + mDigitizer.init(); + auto mctruth = ic.options().get<bool>("mctruth"); + if (!mctruth) { + mDigitizer.processMC(false); } - mHitsBg = new std::vector<Hit>(); - mFinished = false; + if (mHits) { + delete mHits; + } + mHits = new std::vector<Hit>(); } // helper function which will be offered as a service void DigitizerSpec::retrieveHits(const char* brname, @@ -63,22 +68,13 @@ void DigitizerSpec::retrieveHits(const char* brname, LOG(ERROR) << "No branch found"; return; } - if (sourceID == 0) { //Bg - mHitsBg->clear(); - br->SetAddress(&mHitsBg); - } else { // Signal - mHitsS->clear(); - br->SetAddress(&mHitsS); - } + mHits->clear(); + br->SetAddress(&mHits); br->GetEntry(entryID); } void DigitizerSpec::run(framework::ProcessingContext& pc) { - if (mFinished) { - return; - } - // read collision context from input auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext"); context->initSimChains(o2::detectors::DetID::PHS, mSimChains); @@ -86,7 +82,8 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) LOG(DEBUG) << "GOT " << timesview.size() << " COLLISSION TIMES"; // if there is nothing to do ... return - if (timesview.size() == 0) { + int n = timesview.size(); + if (n == 0) { return; } @@ -95,41 +92,64 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) LOG(INFO) << " CALLING PHOS DIGITIZATION "; std::vector<TriggerRecord> triggers; - static std::vector<o2::phos::Hit> hits; - mLabels.clear(); - mDigits.clear(); - int indexStart = mDigits.size(); + int indexStart = mDigitsOut.size(); auto& eventParts = context->getEventParts(); + //if this is last stream of hits and we can write directly to final vector of digits? Otherwize use temporary vectors + mDigitsFinal.clear(); + mDigitsTmp.clear(); + bool isLastStream = true; + double eventTime = timesview[0].getTimeNS() - o2::phos::PHOSSimParams::Instance().mDeadTime; //checked above that list not empty + int eventId; // loop over all composite collisions given from context // (aka loop over all the interaction records) - for (int collID = 0; collID < timesview.size(); ++collID) { - mDigitizer.setEventTime(timesview[collID].getTimeNS()); + for (int collID = 0; collID < n; ++collID) { + double dt = timesview[collID].getTimeNS() - eventTime; //start new PHOS readout, continue current or dead time? + if (dt > mReadoutTime && dt < mDeadTime) { //dead time, skip event + continue; + } + + if (dt >= o2::phos::PHOSSimParams::Instance().mDeadTime) { // start new event + //new event + eventTime = timesview[collID].getTimeNS(); + dt = 0.; + eventId = collID; + } + + //Check if next event has to be added to this read-out + if (collID < n - 1) { + isLastStream = (timesview[collID + 1].getTimeNS() - eventTime > mReadoutTime); + } else { + isLastStream = true; + } // for each collision, loop over the constituents event and source IDs // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { - + // merge new hist to current digit list + auto part = eventParts[collID].begin(); + while (part != eventParts[collID].end()) { // get the hits for this event and this source - retrieveHits("PHSHit", part.sourceID, part.entryID); - mDigitizer.setCurrEvID(part.entryID); + int source = part->sourceID; + int entry = part->entryID; + retrieveHits("PHSHit", source, entry); + part++; + if (part == eventParts[collID].end() && isLastStream) { //last stream, copy digits directly to output vector + mDigitizer.processHits(mHits, mDigitsFinal, mDigitsOut, mLabels, entry, source, dt); + mDigitsFinal.clear(); + //finalyze previous event and clean + // Add trigger record + triggers.emplace_back(timesview[eventId], indexStart, mDigitsOut.size() - indexStart); + indexStart = mDigitsOut.size(); + } else { //Fill intermediate digitvector + mDigitsTmp.swap(mDigitsFinal); + mDigitizer.processHits(mHits, mDigitsTmp, mDigitsFinal, mLabels, entry, source, dt); + mDigitsTmp.clear(); + } } - - LOG(DEBUG) << "Found " << mHitsBg->size() << " BG hits and " << mHitsS->size() << "signal hits"; - - // call actual digitization procedure - mDigitizer.process(mHitsBg, mHitsS, mDigits, mLabels); - - // Add trigger record - triggers.emplace_back(timesview[collID], indexStart, mDigits.size() - indexStart); - indexStart = mDigits.size(); - - LOG(DEBUG) << "Have " << mDigits.size() << " digits "; } - LOG(DEBUG) << "Have " << mLabels.getNElements() << " PHOS labels "; // here we have all digits and we can send them to consumer (aka snapshot it onto output) - pc.outputs().snapshot(Output{"PHS", "DIGITS", 0, Lifetime::Timeframe}, mDigits); + pc.outputs().snapshot(Output{"PHS", "DIGITS", 0, Lifetime::Timeframe}, mDigitsOut); pc.outputs().snapshot(Output{"PHS", "DIGITTRIGREC", 0, Lifetime::Timeframe}, triggers); if (pc.outputs().isAllowed({"PHS", "DIGITSMCTR", 0})) { pc.outputs().snapshot(Output{"PHS", "DIGITSMCTR", 0, Lifetime::Timeframe}, mLabels); @@ -145,7 +165,6 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) // we should be only called once; tell DPL that this process is ready to exit pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - mFinished = true; } DataProcessorSpec getPHOSDigitizerSpec(int channel, bool mctruth) @@ -167,7 +186,8 @@ DataProcessorSpec getPHOSDigitizerSpec(int channel, bool mctruth) "PHOSDigitizer", Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<DigitizerSpec>()}, - Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; + Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}, + {"mctruth", VariantType::Bool, true, {"whether to process MC info"}}}}; } } // namespace phos } // namespace o2 diff --git a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.h b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.h index b4af953807142..0d99311d58ac4 100644 --- a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -62,12 +63,14 @@ class DigitizerSpec final : public o2::base::BaseDPLDigitizer int sourceID, int entryID); - Bool_t mFinished = false; ///< Flag for digitization finished + float mReadoutTime = 0.; ///< PHOS readout time + float mDeadTime = 0.; ///< PHOS dead time Digitizer mDigitizer; ///< Digitizer object std::vector<TChain*> mSimChains; ///< Chain of files for background/signal events - std::vector<Hit>* mHitsBg = nullptr; ///< Vector with input hits from Bg event - std::vector<Hit>* mHitsS = nullptr; ///< Vector with input hits from Signal event - std::vector<Digit> mDigits; ///< Vector with non-accumulated digits (per collision) + std::vector<Hit>* mHits = nullptr; ///< Vector with input hits from Signal event + std::vector<Digit> mDigitsTmp; ///< Vector with accumulated digits (per collision) + std::vector<Digit> mDigitsFinal; ///< Vector with accumulated digits (per collision) + std::vector<Digit> mDigitsOut; ///< Vector with accumulated digits (per collision) dataformats::MCTruthContainer<o2::phos::MCLabel> mLabels; ///< List of labels }; diff --git a/Steer/DigitizerWorkflow/src/SimReaderSpec.cxx b/Steer/DigitizerWorkflow/src/SimReaderSpec.cxx index ad8922be63902..c1c8c7e991add 100644 --- a/Steer/DigitizerWorkflow/src/SimReaderSpec.cxx +++ b/Steer/DigitizerWorkflow/src/SimReaderSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,11 +16,11 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/Lifetime.h" -#include "Headers/DataHeader.h" #include "Steer/HitProcessingManager.h" #include "Steer/InteractionSampler.h" #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsTPC/TPCSectorHeader.h" +#include "DetectorsRaw/HBFUtils.h" #include <FairMQLogger.h> #include <TMessage.h> // object serialization #include <memory> // std::unique_ptr @@ -115,13 +116,10 @@ DataProcessorSpec getSimReaderSpec(SubspecRange range, const std::vector<std::st } LOG(INFO) << "Imposing hadronic interaction rate " << intRate << "Hz"; mgr.getInteractionSampler().setInteractionRate(intRate); - - int bc0 = ctx.options().get<int>("firstBC"); - int orbit0 = ctx.options().get<int>("firstOrbit"); - if (bc0 < 0 || orbit0 < 0) { - throw std::runtime_error("negative 1st orbit or BC provided"); - } - mgr.getInteractionSampler().setFirstIR({uint16_t(bc0 % o2lhc::LHCMaxBunches), orbit0 + uint32_t(bc0 / o2lhc::LHCMaxBunches)}); + o2::raw::HBFUtils::Instance().print(); + o2::raw::HBFUtils::Instance().checkConsistency(); + mgr.getInteractionSampler().setFirstIR({0, o2::raw::HBFUtils::Instance().orbitFirstSampled}); + mgr.getDigitizationContext().setFirstOrbitForSampling(o2::raw::HBFUtils::Instance().orbitFirstSampled); auto bcPatternFile = ctx.options().get<std::string>("bcPatternFile"); if (!bcPatternFile.empty()) { @@ -146,6 +144,9 @@ DataProcessorSpec getSimReaderSpec(SubspecRange range, const std::vector<std::st auto qedprefix = ctx.options().get<std::string>("simPrefixQED"); if (qedprefix.size() > 0) { o2::steer::InteractionSampler qedInteractionSampler; + if (!bcPatternFile.empty()) { + qedInteractionSampler.setBunchFilling(bcPatternFile); + } // get first and last "hadronic" interaction records and let // QED events range from the first bunch crossing to the last bunch crossing @@ -207,8 +208,6 @@ DataProcessorSpec getSimReaderSpec(SubspecRange range, const std::vector<std::st /* OPTIONS */ Options{ {"interactionRate", VariantType::Float, 50000.0f, {"Total hadronic interaction rate (Hz)"}}, - {"firstBC", VariantType::Int, 0, {"First BC in interaction sampling, will affect 1st orbit if > LHCMaxBunches"}}, - {"firstOrbit", VariantType::Int, 1, {"First orbit in interaction sampling"}}, {"bcPatternFile", VariantType::String, "", {"Interacting BC pattern file (e.g. from CreateBCPattern.C)"}}, {"simPrefixQED", VariantType::String, "", {"Sim (QED) input prefix (example: path/o2qed). The prefix allows to find files like path/o2qed_Kine.root etc."}}, {"qed-x-section-ratio", VariantType::Float, -1.f, {"Ratio of cross sections QED/hadronic events. Determines QED interaction rate from hadronic interaction rate."}}, diff --git a/Steer/DigitizerWorkflow/src/SimReaderSpec.h b/Steer/DigitizerWorkflow/src/SimReaderSpec.h index 3cb17ff468e4c..b16cc1fc485e8 100644 --- a/Steer/DigitizerWorkflow/src/SimReaderSpec.h +++ b/Steer/DigitizerWorkflow/src/SimReaderSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx index 4bde26c686859..8695ba6083e3b 100644 --- a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,25 +36,35 @@ #include "ITSMFTDigitizerSpec.h" #include "ITSMFTWorkflow/DigitWriterSpec.h" +#ifdef ENABLE_UPGRADES +// for ITS3 +#include "ITS3DigitizerSpec.h" +#include "ITS3Workflow/DigitWriterSpec.h" +#endif + // for TOF #include "TOFDigitizerSpec.h" -#include "TOFWorkflowUtils/TOFDigitWriterSpec.h" +#include "TOFWorkflowIO/TOFDigitWriterSpec.h" // for FT0 #include "FT0DigitizerSpec.h" #include "FT0DigitWriterSpec.h" +// for CTP +#include "CTPDigitizerSpec.h" +#include "CTPWorkflowIO/DigitWriterSpec.h" + // for FV0 #include "FV0DigitizerSpec.h" #include "FV0DigitWriterSpec.h" // for FDD #include "FDDDigitizerSpec.h" -#include "FDDDigitWriterSpec.h" +#include "FDDWorkflow/DigitWriterSpec.h" // for EMCal -#include "EMCALDigitizerSpec.h" -#include "EMCALDigitWriterSpec.h" +#include "EMCALWorkflow/EMCALDigitizerSpec.h" +#include "EMCALWorkflow/EMCALDigitWriterSpec.h" // for HMPID #include "HMPIDDigitizerSpec.h" @@ -61,9 +72,9 @@ // for TRD #include "TRDWorkflow/TRDDigitizerSpec.h" -#include "TRDWorkflow/TRDDigitWriterSpec.h" +#include "TRDWorkflowIO/TRDDigitWriterSpec.h" #include "TRDWorkflow/TRDTrapSimulatorSpec.h" -#include "TRDWorkflow/TRDTrackletWriterSpec.h" +#include "TRDWorkflowIO/TRDTrackletWriterSpec.h" //for MUON MCH #include "MCHDigitizerSpec.h" @@ -83,7 +94,7 @@ // for ZDC #include "ZDCDigitizerSpec.h" -#include "ZDCDigitWriterSpec.h" +#include "ZDCWorkflow/ZDCDigitWriterDPLSpec.h" // GRP #include "DataFormatsParameters/GRPObject.h" @@ -140,11 +151,18 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) workflowOptions.push_back( ConfigParamSpec{"skipDet", VariantType::String, "none", {skiphelp}}); + std::string onlyctxhelp("Produce only the digitization context; Don't actually digitize"); + workflowOptions.push_back(ConfigParamSpec{"only-context", o2::framework::VariantType::Bool, false, {onlyctxhelp}}); + // we support only output type 'tracks' for the moment std::string tpcrthelp("deprecated option, please connect workflows on the command line by pipe"); workflowOptions.push_back( ConfigParamSpec{"tpc-reco-type", VariantType::String, "", {tpcrthelp}}); + // Option to write TPC digits internaly, without forwarding to a special writer instance. + // This is useful in GRID productions with small available memory. + workflowOptions.push_back(ConfigParamSpec{"tpc-chunked-writer", o2::framework::VariantType::Bool, false, {"Write independent TPC digit chunks as soon as they can be flushed."}}); + std::string simhelp("Comma separated list of simulation prefixes (for background, signal productions)"); workflowOptions.push_back( ConfigParamSpec{"sims", VariantType::String, "o2sim", {simhelp}}); @@ -159,11 +177,14 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions) // option to disable MC truth workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable mc-truth"}}); + // option to disable INI file writing + workflowOptions.push_back(ConfigParamSpec{"disable-write-ini", o2::framework::VariantType::Bool, false, {"disable INI config write"}}); + // option to use/not use CCDB for TOF workflowOptions.push_back(ConfigParamSpec{"use-ccdb-tof", o2::framework::VariantType::Bool, false, {"enable access to ccdb tof calibration objects"}}); // option to use or not use the Trap Simulator after digitisation (debate of digitization or reconstruction is for others) - workflowOptions.push_back(ConfigParamSpec{"enable-trd-trapsim", VariantType::Bool, false, {"enable the trap simulation of the TRD"}}); + workflowOptions.push_back(ConfigParamSpec{"disable-trd-trapsim", VariantType::Bool, false, {"disable the trap simulation of the TRD"}}); } void customize(std::vector<o2::framework::DispatchPolicy>& policies) @@ -360,16 +381,15 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // which sim productions to overlay and digitize auto simPrefixes = splitString(configcontext.options().get<std::string>("sims"), ','); - // First, read the GRP to detect which components need instantiations - auto grpfile = o2::base::NameConf::getGRPFileName(simPrefixes[0]); std::shared_ptr<o2::parameters::GRPObject const> grp(nullptr); if (!helpasked) { - grp = readGRP(grpfile.c_str()); + grp = readGRP(simPrefixes[0]); if (!grp) { return WorkflowSpec{}; } } + auto grpfile = o2::base::NameConf::getGRPFileName(simPrefixes[0]); // update the digitization configuration with the right geometry file // we take the geometry from the first simPrefix (could actually check if they are @@ -382,8 +402,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) ConfigurableParam::setValue("DigiParams", "mctruth", mctruth); // write the configuration used for the digitizer workflow + // (In the case, in which we call multiple processes to do digitization, + // only one of them should write this file ... but take the complete configKeyValue line) if (ismaster) { - o2::conf::ConfigurableParam::writeINI(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)); + if (!configcontext.options().get<bool>("disable-write-ini")) { + o2::conf::ConfigurableParam::writeINI(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)); + } } // onlyDet takes precedence on skipDet @@ -407,6 +431,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (helpasked) { return true; } + if (configcontext.options().get<bool>("only-context")) { + // no detector necessary if we are asked to produce only the digitization context + return false; + } auto accepted = accept(id); bool is_ingrp = grp->isDetReadOut(id); if (gIsMaster) { @@ -419,29 +447,30 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) std::vector<o2::detectors::DetID> detList; // list of participating detectors - // the TPC part - // we need to init this anyway since TPC is treated a bit special (for the moment) - if (!helpasked && ismaster) { - initTPC(); - } - // keeps track of which tpc sectors to process std::vector<int> tpcsectors; if (isEnabled(o2::detectors::DetID::TPC)) { + if (!helpasked && ismaster) { + initTPC(); + } + tpcsectors = o2::RangeTokenizer::tokenize<int>(configcontext.options().get<std::string>("tpc-sectors")); // only one lane for the help printout auto lanes = helpasked ? 1 : getNumTPCLanes(tpcsectors, configcontext); detList.emplace_back(o2::detectors::DetID::TPC); - WorkflowSpec tpcPipelines = o2::tpc::getTPCDigitizerSpec(lanes, tpcsectors, mctruth); + auto internalwrite = configcontext.options().get<bool>("tpc-chunked-writer"); + WorkflowSpec tpcPipelines = o2::tpc::getTPCDigitizerSpec(lanes, tpcsectors, mctruth, internalwrite); specs.insert(specs.end(), tpcPipelines.begin(), tpcPipelines.end()); if (configcontext.options().get<std::string>("tpc-reco-type").empty() == false) { throw std::runtime_error("option 'tpc-reco-type' is deprecated, please connect workflows on the command line by pipe"); } - // for writing digits to disc - specs.emplace_back(o2::tpc::getTPCDigitRootWriterSpec(tpcsectors, mctruth)); + if (!internalwrite) { + // for writing digits to disc + specs.emplace_back(o2::tpc::getTPCDigitRootWriterSpec(tpcsectors, mctruth)); + } } // first 36 channels are reserved for the TPC @@ -457,6 +486,17 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(o2::itsmft::getITSDigitWriterSpec(mctruth)); } +#ifdef ENABLE_UPGRADES + // the ITS3 part + if (isEnabled(o2::detectors::DetID::IT3)) { + detList.emplace_back(o2::detectors::DetID::IT3); + // connect the ITS digitization + specs.emplace_back(o2::its3::getITS3DigitizerSpec(fanoutsize++, mctruth)); + // // connect ITS digit writer + specs.emplace_back(o2::its3::getITS3DigitWriterSpec(mctruth)); + } +#endif + // the MFT part if (isEnabled(o2::detectors::DetID::MFT)) { detList.emplace_back(o2::detectors::DetID::MFT); @@ -518,7 +558,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // connect the ZDC digitization specs.emplace_back(o2::zdc::getZDCDigitizerSpec(fanoutsize++, mctruth)); // connect the ZDC digit writer - specs.emplace_back(o2::zdc::getZDCDigitWriterSpec(mctruth)); + specs.emplace_back(o2::zdc::getZDCDigitWriterDPLSpec(mctruth, true)); } // add TRD @@ -528,12 +568,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(o2::trd::getTRDDigitizerSpec(fanoutsize++, mctruth)); // connect the TRD digit writer specs.emplace_back(o2::trd::getTRDDigitWriterSpec(mctruth)); - auto enableTrapSim = configcontext.options().get<bool>("enable-trd-trapsim"); - if (enableTrapSim) { + auto disableTrapSim = configcontext.options().get<bool>("disable-trd-trapsim"); + if (!disableTrapSim) { // connect the TRD Trap SimulatorA - specs.emplace_back(o2::trd::getTRDTrapSimulatorSpec()); + specs.emplace_back(o2::trd::getTRDTrapSimulatorSpec(mctruth)); // connect to the device to write out the tracklets. - specs.emplace_back(o2::trd::getTRDTrackletWriterSpec()); + specs.emplace_back(o2::trd::getTRDTrackletWriterSpec(mctruth)); } } @@ -576,12 +616,19 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // the CPV part if (isEnabled(o2::detectors::DetID::CPV)) { detList.emplace_back(o2::detectors::DetID::CPV); - // connect the PHOS digitization + // connect the CPV digitization specs.emplace_back(o2::cpv::getCPVDigitizerSpec(fanoutsize++, mctruth)); // add PHOS writer specs.emplace_back(o2::cpv::getCPVDigitWriterSpec(mctruth)); } - + // the CTP part + if (isEnabled(o2::detectors::DetID::CTP)) { + detList.emplace_back(o2::detectors::DetID::CTP); + // connect the CTP digitization + specs.emplace_back(o2::ctp::getCTPDigitizerSpec(fanoutsize++, detList)); + // connect the CTP digit writer + specs.emplace_back(o2::ctp::getDigitWriterSpec(false)); + } // GRP updater: must come after all detectors since requires their list specs.emplace_back(o2::parameters::getGRPUpdaterSpec(grpfile, detList)); diff --git a/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.cxx index 743dd00bdf9f5..086a4e7a91ea7 100644 --- a/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,7 +16,6 @@ #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" -#include "Headers/DataHeader.h" #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" diff --git a/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.h b/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.h index 325f307a1dd53..df7dc030effde 100644 --- a/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/TOFDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx b/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx index 53ca18ec2a4c8..faa5568c736cb 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -203,7 +204,8 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur // first of all redefine the output format (special to labels) auto tree = branch.GetTree(); auto sector = extractSector(ref); - auto br = framework::RootTreeWriter::remapBranch(branch, &outputcontainer); + auto ptr = &outputcontainer; + auto br = framework::RootTreeWriter::remapBranch(branch, &ptr); auto const* dh = DataRefUtils::getHeader<DataHeader*>(ref); LOG(INFO) << "HAVE LABEL DATA FOR SECTOR " << sector << " ON CHANNEL " << dh->subSpecification; diff --git a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h b/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h index 52562f7644c55..bd6a2f577ee51 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx index f35c3b30856d4..8da8fbb4cdf2c 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx @@ -1,13 +1,18 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> #include "Framework/RootSerializationSupport.h" #include "TPCDigitizerSpec.h" #include "Framework/ControlService.h" @@ -16,13 +21,15 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" +#include "Framework/DeviceSpec.h" +#include "DetectorsRaw/HBFUtils.h" #include "Headers/DataHeader.h" #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" -#include "TSystem.h" #include <SimulationDataFormat/MCCompLabel.h> #include <SimulationDataFormat/ConstMCTruthContainer.h> +#include <SimulationDataFormat/IOMCTruthContainerView.h> #include "Framework/Task.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsTPC/TPCSectorHeader.h" @@ -31,19 +38,56 @@ #include "TPCSimulation/Digitizer.h" #include "TPCSimulation/Detector.h" #include "DetectorsBase/BaseDPLDigitizer.h" +#include "DetectorsBase/Detector.h" #include "CommonDataFormat/RangeReference.h" -#include "TPCSimulation/SAMPAProcessing.h" #include "SimConfig/DigiParams.h" +#include <filesystem> +#include "TH3.h" using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; using DigiGroupRef = o2::dataformats::RangeReference<int, int>; +using SC = o2::tpc::SpaceCharge<double>; namespace o2 { namespace tpc { +template <typename T> +void copyHelper(T const& origin, T& target) +{ + std::copy(origin.begin(), origin.end(), std::back_inserter(target)); +} +template <> +void copyHelper<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>(o2::dataformats::MCTruthContainer<o2::MCCompLabel> const& origin, o2::dataformats::MCTruthContainer<o2::MCCompLabel>& target) +{ + target.mergeAtBack(origin); +} + +template <typename T> +void writeToBranchHelper(TTree& tree, const char* name, T* accum) +{ + auto targetbr = o2::base::getOrMakeBranch(tree, name, accum); + targetbr->Fill(); + targetbr->ResetAddress(); + targetbr->DropBaskets("all"); +} +template <> +void writeToBranchHelper<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>(TTree& tree, + const char* name, o2::dataformats::MCTruthContainer<o2::MCCompLabel>* accum) +{ + // we convert first of all to IOMCTruthContainer + std::vector<char> buffer; + accum->flatten_to(buffer); + accum->clear_andfreememory(); + o2::dataformats::IOMCTruthContainerView view(buffer); + auto targetbr = o2::base::getOrMakeBranch(tree, name, &view); + targetbr->Fill(); + targetbr->ResetAddress(); + targetbr->DropBaskets("all"); +} + std::string getBranchNameLeft(int sector) { std::stringstream branchnamestreamleft; @@ -62,7 +106,7 @@ using namespace o2::base; class TPCDPLDigitizerTask : public BaseDPLDigitizer { public: - TPCDPLDigitizerTask() : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM) + TPCDPLDigitizerTask(bool internalwriter) : mInternalWriter(internalwriter), BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM) { } @@ -70,6 +114,8 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer { LOG(INFO) << "Initializing TPC digitization"; + mLaneId = ic.services().get<const o2::framework::DeviceSpec>().rank; + mWithMCTruth = o2::conf::DigiParams::Instance().mctruth; auto useDistortions = ic.options().get<int>("distortionType"); auto triggeredMode = ic.options().get<bool>("TPCtriggered"); @@ -89,29 +135,14 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer readSpaceCharge.push_back(substr); } if (readSpaceCharge[0].size() != 0) { // use pre-calculated space-charge object - std::unique_ptr<o2::tpc::SpaceCharge> spaceCharge; - if (!gSystem->AccessPathName(readSpaceCharge[0].data())) { - auto fileSC = std::unique_ptr<TFile>(TFile::Open(readSpaceCharge[0].data())); - if (fileSC->FindKey(readSpaceCharge[1].data())) { - spaceCharge.reset((o2::tpc::SpaceCharge*)fileSC->Get(readSpaceCharge[1].data())); - } - } - if (spaceCharge.get() != nullptr) { - LOG(INFO) << "Using pre-calculated space-charge object: " << readSpaceCharge[1].data(); - mDigitizer.setUseSCDistortions(spaceCharge.release()); + if (std::filesystem::exists(readSpaceCharge[0])) { + TFile fileSC(readSpaceCharge[0].data(), "READ"); + mDigitizer.setUseSCDistortions(fileSC); } else { LOG(ERROR) << "Space-charge object or file not found!"; } } else { // create new space-charge object either with empty TPC or an initial space-charge density provided by histogram - o2::tpc::SpaceCharge::SCDistortionType distortionType = useDistortions == 2 ? o2::tpc::SpaceCharge::SCDistortionType::SCDistortionsConstant : o2::tpc::SpaceCharge::SCDistortionType::SCDistortionsRealistic; - auto gridSizeString = ic.options().get<std::string>("gridSize"); - std::vector<int> gridSize; - std::stringstream ss(gridSizeString); - while (ss.good()) { - std::string substr; - getline(ss, substr, ','); - gridSize.push_back(std::stoi(substr)); - } + SC::SCDistortionType distortionType = useDistortions == 2 ? SC::SCDistortionType::SCDistortionsConstant : SC::SCDistortionType::SCDistortionsRealistic; auto inputHistoString = ic.options().get<std::string>("initialSpaceChargeDensity"); std::vector<std::string> inputHisto; std::stringstream ssHisto(inputHistoString); @@ -121,7 +152,7 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer inputHisto.push_back(substr); } std::unique_ptr<TH3> hisSCDensity; - if (!gSystem->AccessPathName(inputHisto[0].data())) { + if (std::filesystem::exists(inputHisto[0])) { auto fileSCInput = std::unique_ptr<TFile>(TFile::Open(inputHisto[0].data())); if (fileSCInput->FindKey(inputHisto[1].data())) { hisSCDensity.reset((TH3*)fileSCInput->Get(inputHisto[1].data())); @@ -130,9 +161,9 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer } if (hisSCDensity.get() != nullptr) { LOG(INFO) << "TPC: Providing initial space-charge density histogram: " << hisSCDensity->GetName(); - mDigitizer.setUseSCDistortions(distortionType, hisSCDensity.get(), gridSize[0], gridSize[1], gridSize[2]); + mDigitizer.setUseSCDistortions(distortionType, hisSCDensity.get()); } else { - if (distortionType == SpaceCharge::SCDistortionType::SCDistortionsConstant) { + if (distortionType == SC::SCDistortionType::SCDistortionsConstant) { LOG(ERROR) << "Input space-charge density histogram or file not found!"; } } @@ -145,6 +176,41 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer mWriteGRP = true; } + void writeToROOTFile() + { + if (!mInternalROOTFlushFile) { + std::stringstream tmp; + tmp << "tpc_driftime_digits_lane" << mLaneId << ".root"; + mInternalROOTFlushFile = new TFile(tmp.str().c_str(), "UPDATE"); + std::stringstream trname; + trname << mSector; + mInternalROOTFlushTTree = new TTree(trname.str().c_str(), "o2sim"); + } + { + std::stringstream brname; + brname << "TPCDigit_" << mSector; + auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mDigits); + br->Fill(); + br->ResetAddress(); + } + if (mWithMCTruth) { + // labels + std::stringstream brname; + brname << "TPCDigitMCTruth_" << mSector; + auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mLabels); + br->Fill(); + br->ResetAddress(); + } + { + // common + std::stringstream brname; + brname << "TPCCommonMode_" << mSector; + auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mCommonMode); + br->Fill(); + br->ResetAddress(); + } + } + void run(framework::ProcessingContext& pc) { LOG(INFO) << "Processing TPC digitization"; @@ -152,7 +218,7 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer /// For the time being use the defaults for the CDB auto& cdb = o2::tpc::CDBInterface::instance(); cdb.setUseDefaults(); - if (!gSystem->AccessPathName("GainMap.root")) { + if (std::filesystem::exists("GainMap.root")) { LOG(INFO) << "TPC: Using gain map from 'GainMap.root'"; cdb.setGainMapFromFile("GainMap.root"); } @@ -160,6 +226,17 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer for (auto it = pc.inputs().begin(), end = pc.inputs().end(); it != end; ++it) { for (auto const& inputref : it) { process(pc, inputref); + if (mInternalWriter) { + mInternalROOTFlushTTree->SetEntries(mFlushCounter); + mInternalROOTFlushFile->Write("", TObject::kOverwrite); + mInternalROOTFlushFile->Close(); + // delete mInternalROOTFlushTTree; --> automatically done by ->Close() + delete mInternalROOTFlushFile; + mInternalROOTFlushFile = nullptr; + } + //TODO: make generic reset method? + mFlushCounter = 0; + mDigitCounter = 0; } } } @@ -194,6 +271,8 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer return; } auto sector = sectorHeader->sector(); + mSector = sector; + mListOfSectors.push_back(sector); LOG(INFO) << "TPC: Processing sector " << sector; // the active sectors need to be propagated uint64_t activeSectors = 0; @@ -203,35 +282,46 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer auto makeDigitBuffer = [this, sector, &pc, activeSectors, &dh]() { o2::tpc::TPCSectorHeader header{sector}; header.activeSectors = activeSectors; - return &pc.outputs().make<std::vector<o2::tpc::Digit>>(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, - header}); + if (mInternalWriter) { + using ContainerType = std::decay_t<decltype(pc.outputs().make<std::vector<o2::tpc::Digit>>(Output{"", "", 0}))>*; + return ContainerType(nullptr); + } else { + // default case + return &pc.outputs().make<std::vector<o2::tpc::Digit>>(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, header}); + } }; // lambda that snapshots the common mode vector to be sent out; prepares and attaches header with sector information auto snapshotCommonMode = [this, sector, &pc, activeSectors, &dh](std::vector<o2::tpc::CommonMode> const& commonMode) { o2::tpc::TPCSectorHeader header{sector}; header.activeSectors = activeSectors; - // note that snapshoting only works with non-const references (to be fixed?) - pc.outputs().snapshot(Output{"TPC", "COMMONMODE", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, - header}, - const_cast<std::vector<o2::tpc::CommonMode>&>(commonMode)); + if (!mInternalWriter) { + // note that snapshoting only works with non-const references (to be fixed?) + pc.outputs().snapshot(Output{"TPC", "COMMONMODE", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, + header}, + const_cast<std::vector<o2::tpc::CommonMode>&>(commonMode)); + } }; // lambda that snapshots labels to be sent out; prepares and attaches header with sector information auto snapshotLabels = [this, §or, &pc, activeSectors, &dh](o2::dataformats::MCTruthContainer<o2::MCCompLabel> const& labels) { o2::tpc::TPCSectorHeader header{sector}; header.activeSectors = activeSectors; if (mWithMCTruth) { - auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, header}); - labels.flatten_to(sharedlabels); + if (!mInternalWriter) { + auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, header}); + labels.flatten_to(sharedlabels); + } } }; // lambda that snapshots digits grouping (triggers) to be sent out; prepares and attaches header with sector information auto snapshotEvents = [this, sector, &pc, activeSectors, &dh](const std::vector<DigiGroupRef>& events) { o2::tpc::TPCSectorHeader header{sector}; header.activeSectors = activeSectors; - LOG(INFO) << "TPC: Send TRIGGERS for sector " << sector << " channel " << dh->subSpecification << " | size " << events.size(); - pc.outputs().snapshot(Output{"TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, - header}, - const_cast<std::vector<DigiGroupRef>&>(events)); + if (!mInternalWriter) { + LOG(INFO) << "TPC: Send TRIGGERS for sector " << sector << " channel " << dh->subSpecification << " | size " << events.size(); + pc.outputs().snapshot(Output{"TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(dh->subSpecification), Lifetime::Timeframe, + header}, + const_cast<std::vector<DigiGroupRef>&>(events)); + } }; auto digitsAccum = makeDigitBuffer(); // accumulator for digits @@ -258,21 +348,34 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer auto& eventParts = context->getEventParts(); auto flushDigitsAndLabels = [this, digitsAccum, &labelAccum, &commonModeAccum](bool finalFlush = false) { + mFlushCounter++; // flush previous buffer mDigits.clear(); mLabels.clear(); mCommonMode.clear(); mDigitizer.flush(mDigits, mLabels, mCommonMode, finalFlush); LOG(INFO) << "TPC: Flushed " << mDigits.size() << " digits, " << mLabels.getNElements() << " labels and " << mCommonMode.size() << " common mode entries"; - std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(*digitsAccum)); - if (mWithMCTruth) { - labelAccum.mergeAtBack(mLabels); + + if (mInternalWriter) { + // the natural place to write out this independent datachunk immediately ... + writeToROOTFile(); + } else { + // ... or to accumulate and later forward to next DPL proc + std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(*digitsAccum)); + if (mWithMCTruth) { + labelAccum.mergeAtBack(mLabels); + } + std::copy(mCommonMode.begin(), mCommonMode.end(), std::back_inserter(commonModeAccum)); } - std::copy(mCommonMode.begin(), mCommonMode.end(), std::back_inserter(commonModeAccum)); + mDigitCounter += mDigits.size(); }; - static SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance(); - mDigitizer.setStartTime(sampaProcessing.getTimeBinFromTime(irecords[0].getTimeNS() / 1000.f)); + if (isContinuous) { + auto& hbfu = o2::raw::HBFUtils::Instance(); + double time = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).bc2ns() / 1000.; + mDigitizer.setOutputDigitTimeOffset(time); + mDigitizer.setStartTime(irecords[0].getTimeNS() / 1000.f); + } TStopwatch timer; timer.Start(); @@ -280,13 +383,13 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer // loop over all composite collisions given from context // (aka loop over all the interaction records) for (int collID = 0; collID < irecords.size(); ++collID) { - const float eventTime = irecords[collID].getTimeNS() / 1000.f; + const double eventTime = irecords[collID].getTimeNS() / 1000.f; LOG(INFO) << "TPC: Event time " << eventTime << " us"; mDigitizer.setEventTime(eventTime); if (!isContinuous) { - mDigitizer.setStartTime(sampaProcessing.getTimeBinFromTime(eventTime)); + mDigitizer.setStartTime(eventTime); } - int startSize = digitsAccum->size(); + size_t startSize = mDigitCounter; // digitsAccum->size(); // for each collision, loop over the constituents event and source IDs // (background signal merging is basically taking place here) @@ -307,7 +410,7 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer flushDigitsAndLabels(); if (!isContinuous) { - eventAccum.emplace_back(startSize, digitsAccum->size() - startSize); + eventAccum.emplace_back(startSize, mDigits.size()); } } } @@ -316,14 +419,16 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer if (isContinuous) { LOG(INFO) << "TPC: Final flush"; flushDigitsAndLabels(true); - eventAccum.emplace_back(0, digitsAccum->size()); // all digits are grouped to 1 super-event pseudo-triggered mode + eventAccum.emplace_back(0, mDigitCounter); // all digits are grouped to 1 super-event pseudo-triggered mode } - // send out to next stage - snapshotEvents(eventAccum); - // snapshotDigits(digitsAccum); --> done automatically - snapshotCommonMode(commonModeAccum); - snapshotLabels(labelAccum); + if (!mInternalWriter) { + // send out to next stage + snapshotEvents(eventAccum); + // snapshotDigits(digitsAccum); --> done automatically + snapshotCommonMode(commonModeAccum); + snapshotLabels(labelAccum); + } timer.Stop(); LOG(INFO) << "TPC: Digitization took " << timer.CpuTime() << "s"; @@ -335,11 +440,19 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer std::vector<o2::tpc::Digit> mDigits; o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels; std::vector<o2::tpc::CommonMode> mCommonMode; + std::vector<int> mListOfSectors; // a list of sectors treated by this task + TFile* mInternalROOTFlushFile = nullptr; + TTree* mInternalROOTFlushTTree = nullptr; + size_t mDigitCounter = 0; + size_t mFlushCounter = 0; + int mLaneId = 0; // the id of the current process within the parallel pipeline + int mSector = 0; bool mWriteGRP = false; bool mWithMCTruth = true; + bool mInternalWriter = false; }; -o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, bool mctruth) +o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, bool mctruth, bool internalwriter) { // create the full data processor spec using // a name identifier @@ -351,12 +464,14 @@ o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, std::vector<OutputSpec> outputs; // define channel by triple of (origin, type id of data to be sent on this channel, subspecification) - outputs.emplace_back("TPC", "DIGITS", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); - outputs.emplace_back("TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); - if (mctruth) { - outputs.emplace_back("TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); + if (!internalwriter) { + outputs.emplace_back("TPC", "DIGITS", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); + outputs.emplace_back("TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back("TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); + } + outputs.emplace_back("TPC", "COMMONMODE", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); } - outputs.emplace_back("TPC", "COMMONMODE", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe); if (writeGRP) { outputs.emplace_back("TPC", "ROMode", 0, Lifetime::Timeframe); LOG(DEBUG) << "TPC: Channel " << channel << " will supply ROMode"; @@ -366,21 +481,20 @@ o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, id.str().c_str(), Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}}, outputs, - AlgorithmSpec{adaptFromTask<TPCDPLDigitizerTask>()}, + AlgorithmSpec{adaptFromTask<TPCDPLDigitizerTask>(internalwriter)}, Options{{"distortionType", VariantType::Int, 0, {"Distortion type to be used. 0 = no distortions (default), 1 = realistic distortions (not implemented yet), 2 = constant distortions"}}, - {"gridSize", VariantType::String, "129,144,129", {"Comma separated list of number of bins in (r,phi,z) for distortion lookup tables (r and z can only be 2**N + 1, N=1,2,3,...)"}}, {"initialSpaceChargeDensity", VariantType::String, "", {"Path to root file containing TH3 with initial space-charge density and name of the TH3 (comma separated)"}}, {"readSpaceCharge", VariantType::String, "", {"Path to root file containing pre-calculated space-charge object and name of the object (comma separated)"}}, {"TPCtriggered", VariantType::Bool, false, {"Impose triggered RO mode (default: continuous)"}}}}; } -o2::framework::WorkflowSpec getTPCDigitizerSpec(int nLanes, std::vector<int> const& sectors, bool mctruth) +o2::framework::WorkflowSpec getTPCDigitizerSpec(int nLanes, std::vector<int> const& sectors, bool mctruth, bool internalwriter) { // channel parameter is deprecated in the TPCDigitizer processor, all descendants // are initialized not to publish GRP mode, but the channel will be added to the first // processor after the pipelines have been created. The processor will decide upon // the index in the ParallelContext whether to publish - WorkflowSpec pipelineTemplate{getTPCDigitizerSpec(0, false, mctruth)}; + WorkflowSpec pipelineTemplate{getTPCDigitizerSpec(0, false, mctruth, internalwriter)}; // override the predefined name, index will be added by parallelPipeline method pipelineTemplate[0].name = "TPCDigitizer"; WorkflowSpec pipelines = parallelPipeline( diff --git a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.h b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.h index 01f560c07b99f..08a28b2f7647a 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,9 +20,9 @@ namespace o2 namespace tpc { -o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, bool mctruth); +o2::framework::DataProcessorSpec getTPCDigitizerSpec(int channel, bool writeGRP, bool mctruth, bool internalwriter); -o2::framework::WorkflowSpec getTPCDigitizerSpec(int nLanes, std::vector<int> const& sectors, bool mctruth); +o2::framework::WorkflowSpec getTPCDigitizerSpec(int nLanes, std::vector<int> const& sectors, bool mctruth, bool internalwriter); } // end namespace tpc } // end namespace o2 diff --git a/Steer/DigitizerWorkflow/src/ZDCDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/ZDCDigitWriterSpec.h deleted file mode 100644 index 946d04788da1a..0000000000000 --- a/Steer/DigitizerWorkflow/src/ZDCDigitWriterSpec.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef STEER_DIGITIZERWORKFLOW_SRC_ZDCDIGITWRITERSPEC_H_ -#define STEER_DIGITIZERWORKFLOW_SRC_ZDCDIGITWRITERSPEC_H_ - -#include "Framework/DataProcessorSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "Framework/InputSpec.h" -#include "DataFormatsZDC/ChannelData.h" -#include "DataFormatsZDC/BCData.h" -#include "ZDCSimulation/MCLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" - -namespace o2 -{ -namespace zdc -{ - -template <typename T> -using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition<T>; - -o2::framework::DataProcessorSpec getZDCDigitWriterSpec(bool mctruth = true) -{ - using InputSpec = framework::InputSpec; - using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - return MakeRootTreeWriterSpec("ZDCDigitWriter", - "zdcdigits.root", - "o2sim", - 1, - BranchDefinition<std::vector<o2::zdc::BCData>>{InputSpec{"digitBCinput", "ZDC", "DIGITSBC"}, "ZDCDigitBC"}, - BranchDefinition<std::vector<o2::zdc::ChannelData>>{InputSpec{"digitChinput", "ZDC", "DIGITSCH"}, "ZDCDigitCh"}, - BranchDefinition<o2::dataformats::MCTruthContainer<o2::zdc::MCLabel>>{InputSpec{"labelinput", "ZDC", "DIGITLBL"}, "ZDCDigitLabels", mctruth ? 1 : 0})(); -} - -} // end namespace zdc -} // end namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_SRC_ZDCDIGITWRITERSPEC_H_ */ diff --git a/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.cxx index 5025e694ce8e1..ed22206a9c423 100644 --- a/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,12 +12,13 @@ #include "ZDCDigitizerSpec.h" #include "DataFormatsZDC/ChannelData.h" #include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/MCLabel.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" -#include "Headers/DataHeader.h" #include "TStopwatch.h" #include "Steer/HitProcessingManager.h" // for DigitizationContext #include "TChain.h" @@ -25,7 +27,6 @@ #include "DataFormatsParameters/GRPObject.h" #include "ZDCSimulation/Digitizer.h" #include "ZDCSimulation/Detector.h" -#include "ZDCSimulation/MCLabel.h" #include "DetectorsBase/BaseDPLDigitizer.h" #include "SimConfig/DigiParams.h" @@ -40,9 +41,10 @@ namespace zdc class ZDCDPLDigitizerTask : public o2::base::BaseDPLDigitizer { using GRP = o2::parameters::GRPObject; + bool mUseMC = true; public: - ZDCDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM) {} + ZDCDPLDigitizerTask(bool useMC) : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM), mUseMC(useMC) {} void initDigitizerTask(framework::InitContext& ic) override { @@ -51,15 +53,15 @@ class ZDCDPLDigitizerTask : public o2::base::BaseDPLDigitizer auto& dopt = o2::conf::DigiParams::Instance(); mDigitizer.setCCDBServer(dopt.ccdb); + auto enableHitInfo = ic.options().get<bool>("enable-hit-info"); + mDigitizer.setMaskTriggerBits(!enableHitInfo); + mDigitizer.setSkipMCLabels(not mUseMC); mDigitizer.init(); mROMode = mDigitizer.isContinuous() ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::PRESENT; } void run(framework::ProcessingContext& pc) { - if (mFinished) { - return; - } LOG(INFO) << "Doing ZDC digitization"; // TODO: this should eventually come from the framework and depend on the TF timestamp @@ -71,10 +73,14 @@ class ZDCDPLDigitizerTask : public o2::base::BaseDPLDigitizer const auto& grp = context->getGRP(); mDigitizer.setTimeStamp(grp.getTimeStart()); - + if (mDigitizer.getNEmptyBunches() < 0) { + mDigitizer.findEmptyBunches(context->getBunchFilling().getPattern()); + } auto& irecords = context->getEventRecords(); auto& eventParts = context->getEventParts(); - + if (irecords.empty()) { + return; + } // loop over all composite collisions given from context // (aka loop over all the interaction records) std::vector<o2::zdc::Hit> hits; @@ -101,11 +107,28 @@ class ZDCDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.setInteractionRecord(terminateIR); mDigitizer.flush(mDigitsBC, mDigitsCh, mLabels); + for (uint32_t ib = 0; ib < mDigitsBC.size(); ib++) { + mDigitizer.assignTriggerBits(ib, mDigitsBC); + } + + const auto &irFirst = irecords.front(), irLast = irecords.back(); + o2::InteractionRecord irPed(o2::constants::lhc::LHCMaxBunches - 1, irFirst.orbit); + int norbits = irLast.orbit - irFirst.orbit + 1; + mOrbitData.resize(norbits); + for (int i = 0; i < norbits; i++) { + mDigitizer.updatePedestalReference(mOrbitData[i]); + mOrbitData[i].ir = irPed; + irPed.orbit++; + } + + mDigitizer.Finalize(mDigitsBC, mOrbitData); + // send out to next stage pc.outputs().snapshot(Output{"ZDC", "DIGITSBC", 0, Lifetime::Timeframe}, mDigitsBC); pc.outputs().snapshot(Output{"ZDC", "DIGITSCH", 0, Lifetime::Timeframe}, mDigitsCh); - if (pc.outputs().isAllowed({"ZDC", "DIGITLBL", 0})) { - pc.outputs().snapshot(Output{"ZDC", "DIGITLBL", 0, Lifetime::Timeframe}, mLabels); + pc.outputs().snapshot(Output{"ZDC", "DIGITSPD", 0, Lifetime::Timeframe}, mOrbitData); + if (pc.outputs().isAllowed({"ZDC", "DIGITSLBL", 0})) { + pc.outputs().snapshot(Output{"ZDC", "DIGITSLBL", 0, Lifetime::Timeframe}, mLabels); } LOG(INFO) << "ZDC: Sending ROMode= " << mROMode << " to GRPUpdater"; @@ -113,15 +136,14 @@ class ZDCDPLDigitizerTask : public o2::base::BaseDPLDigitizer // we should be only called once; tell DPL that this process is ready to exit pc.services().get<ControlService>().readyToQuit(QuitRequest::Me); - mFinished = true; } private: - bool mFinished = false; Digitizer mDigitizer; std::vector<TChain*> mSimChains; std::vector<o2::zdc::ChannelData> mDigitsCh; std::vector<o2::zdc::BCData> mDigitsBC; + std::vector<o2::zdc::OrbitData> mOrbitData; o2::dataformats::MCTruthContainer<o2::zdc::MCLabel> mLabels; // labels which get filled // RS: at the moment using hardcoded flag for continuous readout @@ -138,19 +160,18 @@ o2::framework::DataProcessorSpec getZDCDigitizerSpec(int channel, bool mctruth) std::vector<OutputSpec> outputs; outputs.emplace_back("ZDC", "DIGITSBC", 0, Lifetime::Timeframe); outputs.emplace_back("ZDC", "DIGITSCH", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "DIGITSPD", 0, Lifetime::Timeframe); if (mctruth) { - outputs.emplace_back("ZDC", "DIGITLBL", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "DIGITSLBL", 0, Lifetime::Timeframe); } outputs.emplace_back("ZDC", "ROMode", 0, Lifetime::Timeframe); return DataProcessorSpec{ "ZDCDigitizer", Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}}, - outputs, - - AlgorithmSpec{adaptFromTask<ZDCDPLDigitizerTask>()}, - Options{}}; + AlgorithmSpec{adaptFromTask<ZDCDPLDigitizerTask>(mctruth)}, + Options{{"enable-hit-info", o2::framework::VariantType::Bool, false, {"enable hit info of unread channels"}}}}; } } // end namespace zdc diff --git a/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.h b/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.h index 25d6b8b0c5e87..9b57a8e35a7d6 100644 --- a/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.h +++ b/Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/include/Steer/HitProcessingManager.h b/Steer/include/Steer/HitProcessingManager.h index 9f85bb77e52e4..9494ba58f17d6 100644 --- a/Steer/include/Steer/HitProcessingManager.h +++ b/Steer/include/Steer/HitProcessingManager.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -42,10 +43,10 @@ class HitProcessingManager } ~HitProcessingManager() = default; - // add background file to chain + // add background file (simprefix) to chain void addInputFile(std::string_view simfilename); - // add a signal file to chain corresponding to signal index "signalindex" + // add a signal file (simprefix) to chain corresponding to signal index "signalindex" void addInputSignalFile(std::string_view signalfilename, int signalindex = 1); void setGeometryFile(std::string const& geomfile) { mGeometryFile = geomfile; } diff --git a/Steer/include/Steer/InteractionSampler.h b/Steer/include/Steer/InteractionSampler.h index f4ebf6727b283..7593393937793 100644 --- a/Steer/include/Steer/InteractionSampler.h +++ b/Steer/include/Steer/InteractionSampler.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -41,7 +42,13 @@ class InteractionSampler mMuBC = -1.; // invalidate } float getInteractionRate() const { return mIntRate; } - void setFirstIR(const o2::InteractionRecord& ir) { mFirstIR.InteractionRecord::operator=(ir); } + void setFirstIR(const o2::InteractionRecord& ir) + { + mFirstIR.InteractionRecord::operator=(ir); + if (mFirstIR.orbit == 0 && mFirstIR.bc < 4) { + mFirstIR.bc = 4; + } + } const o2::InteractionRecord& getFirstIR() const { return mFirstIR; } void setMuPerBC(float mu) @@ -68,7 +75,7 @@ class InteractionSampler o2::math_utils::RandomRing<1000> mCollTimeGenerator; // generator of number of interactions in BC o2::InteractionTimeRecord mIR{{0, 0}, 0.}; - o2::InteractionTimeRecord mFirstIR{{0, 0}, 0.}; + o2::InteractionTimeRecord mFirstIR{{4, 0}, 0.}; int mIntBCCache = 0; ///< N interactions left for current BC float mIntRate = -1.; ///< total interaction rate in Hz diff --git a/Steer/include/Steer/MCKinematicsReader.h b/Steer/include/Steer/MCKinematicsReader.h index f73497fbff6f6..92d1ede5b0404 100644 --- a/Steer/include/Steer/MCKinematicsReader.h +++ b/Steer/include/Steer/MCKinematicsReader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,8 @@ #include "SimulationDataFormat/MCTrack.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/TrackReference.h" +#include "SimulationDataFormat/MCTruthContainer.h" #include <vector> class TChain; @@ -33,6 +36,9 @@ class MCKinematicsReader /// default constructor MCKinematicsReader() = default; + /// destructor + ~MCKinematicsReader(); + /// constructor taking a name and mode (either kDigiContext or kMCKine) /// In case of "context", the name is the filename of the digitization context. /// In case of MCKine mode, the name is the "prefix" referencing a single simulation production. @@ -70,6 +76,9 @@ class MCKinematicsReader /// variant returning all tracks for source and event at once std::vector<MCTrack> const& getTracks(int source, int event) const; + /// API to ask releasing tracks (freeing memory) for source + event + void releaseTracksForSourceAndEvent(int source, int event); + /// variant returning all tracks for source and event at once std::vector<MCTrack> const& getTracks(int event) const; @@ -79,17 +88,33 @@ class MCKinematicsReader /// get all mothers/daughters of the given label + /// return all track references associated to a source/event/track + gsl::span<o2::TrackReference> getTrackRefs(int source, int event, int track) const; + /// return all track references associated to a source/event + const std::vector<o2::TrackReference>& getTrackRefsByEvent(int source, int event) const; + /// return all track references associated to a event/track (when initialized from kinematics directly) + gsl::span<o2::TrackReference> getTrackRefs(int event, int track) const; + /// retrieves the MCEventHeader for a given eventID and sourceID o2::dataformats::MCEventHeader const& getMCEventHeader(int source, int event) const; + /// Get number of sources + size_t getNSources() const; + + /// Get number of events + size_t getNEvents(int source) const; + DigitizationContext const* getDigitizationContext() const { return mDigitizationContext; } private: - void loadTracksForSource(int source) const; + void initTracksForSource(int source) const; + void loadTracksForSourceAndEvent(int source, int eventID) const; void loadHeadersForSource(int source) const; + void loadTrackRefsForSource(int source) const; + void initIndexedTrackRefs(std::vector<o2::TrackReference>& refs, o2::dataformats::MCTruthContainer<o2::TrackReference>& indexedrefs) const; DigitizationContext const* mDigitizationContext = nullptr; @@ -97,8 +122,9 @@ class MCKinematicsReader std::vector<TChain*> mInputChains; // a vector of tracks foreach source and each collision - mutable std::vector<std::vector<std::vector<o2::MCTrack>>> mTracks; // the in-memory track container - mutable std::vector<std::vector<o2::dataformats::MCEventHeader>> mHeaders; // the in-memory header container + mutable std::vector<std::vector<std::vector<o2::MCTrack>*>> mTracks; // the in-memory track container + mutable std::vector<std::vector<o2::dataformats::MCEventHeader>> mHeaders; // the in-memory header container + mutable std::vector<std::vector<o2::dataformats::MCTruthContainer<o2::TrackReference>>> mIndexedTrackRefs; // the in-memory track ref container bool mInitialized = false; // whether initialized }; @@ -113,10 +139,7 @@ inline MCTrack const* MCKinematicsReader::getTrack(o2::MCCompLabel const& label) inline MCTrack const* MCKinematicsReader::getTrack(int source, int event, int track) const { - if (mTracks[source].size() == 0) { - loadTracksForSource(source); - } - return &mTracks[source][event][track]; + return &getTracks(source, event)[track]; } inline MCTrack const* MCKinematicsReader::getTrack(int event, int track) const @@ -127,9 +150,12 @@ inline MCTrack const* MCKinematicsReader::getTrack(int event, int track) const inline std::vector<MCTrack> const& MCKinematicsReader::getTracks(int source, int event) const { if (mTracks[source].size() == 0) { - loadTracksForSource(source); + initTracksForSource(source); } - return mTracks[source][event]; + if (mTracks[source][event] == nullptr) { + loadTracksForSourceAndEvent(source, event); + } + return *mTracks[source][event]; } inline std::vector<MCTrack> const& MCKinematicsReader::getTracks(int event) const @@ -145,5 +171,39 @@ inline o2::dataformats::MCEventHeader const& MCKinematicsReader::getMCEventHeade return mHeaders.at(source)[event]; } +inline gsl::span<o2::TrackReference> MCKinematicsReader::getTrackRefs(int source, int event, int track) const +{ + if (mIndexedTrackRefs[source].size() == 0) { + loadTrackRefsForSource(source); + } + return mIndexedTrackRefs[source][event].getLabels(track); +} + +inline const std::vector<o2::TrackReference>& MCKinematicsReader::getTrackRefsByEvent(int source, int event) const +{ + if (mIndexedTrackRefs[source].size() == 0) { + loadTrackRefsForSource(source); + } + return mIndexedTrackRefs[source][event].getTruthArray(); +} + +inline gsl::span<o2::TrackReference> MCKinematicsReader::getTrackRefs(int event, int track) const +{ + return getTrackRefs(0, event, track); +} + +inline size_t MCKinematicsReader::getNSources() const +{ + return mTracks.size(); +} + +inline size_t MCKinematicsReader::getNEvents(int source) const +{ + if (mTracks[source].size() == 0) { + initTracksForSource(source); + } + return mTracks[source].size(); +} + } // namespace steer } // namespace o2 diff --git a/Steer/include/Steer/O2MCApplication.h b/Steer/include/Steer/O2MCApplication.h index 25ae7e0c1ebbd..10bf94675a3c5 100644 --- a/Steer/include/Steer/O2MCApplication.h +++ b/Steer/include/Steer/O2MCApplication.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,8 +23,7 @@ #include <FairRootManager.h> #include <FairDetector.h> -class FairMQParts; -class FairMQChannel; +#include <fairmq/FwdDecls.h> namespace o2 { @@ -75,7 +75,7 @@ class O2MCApplication : public O2MCApplicationBase void GeneratePrimaries() override { // ordinarily we would call the event generator ... - LOG(INFO) << "Generate primaries " << mPrimaries.size() << "\n"; + LOG(DEBUG) << "O2MCApplication: Init primaries from external buffer " << mPrimaries.size(); GetStack()->Reset(); // but here we init the stack from // a vector of particles that someone sets externally diff --git a/Steer/include/Steer/O2MCApplicationBase.h b/Steer/include/Steer/O2MCApplicationBase.h index d95a66615c1ef..56f42d1b65903 100644 --- a/Steer/include/Steer/O2MCApplicationBase.h +++ b/Steer/include/Steer/O2MCApplicationBase.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ #include <FairMCApplication.h> #include "Rtypes.h" // for Int_t, Bool_t, Double_t, etc #include <TVirtualMC.h> -#include "SimConfig/SimCutParams.h" +#include "SimConfig/SimParams.h" namespace o2 { diff --git a/Steer/include/Steer/O2RunSim.h b/Steer/include/Steer/O2RunSim.h index 90ea8df528542..27f175b8fb0d9 100644 --- a/Steer/include/Steer/O2RunSim.h +++ b/Steer/include/Steer/O2RunSim.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/src/CollisionContextTool.cxx b/Steer/src/CollisionContextTool.cxx new file mode 100644 index 0000000000000..710119626044d --- /dev/null +++ b/Steer/src/CollisionContextTool.cxx @@ -0,0 +1,350 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include <boost/program_options.hpp> +#include <string> +#include <iostream> +#include <Algorithm/RangeTokenizer.h> +#include <regex> +#include "Steer/InteractionSampler.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "SimulationDataFormat/DigitizationContext.h" +#include <cmath> +#include <TRandom.h> +#include <numeric> +#include <FairLogger.h> + +// +// Created by Sandro Wenzel on 13.07.21. +// + +// A utility to create/engineer (later modify/display) collision contexts + +// options struct filled from command line +struct Options { + std::vector<std::string> interactionRates; + std::string outfilename; // + double timeframelengthinMS; // timeframe length in milliseconds + long seed; // + bool printContext = false; + std::string bcpatternfile; + int tfid = 0; // tfid -> used to calculate start orbit for collisions + int orbitsPerTF = 256; // number of orbits per timeframe --> used to calculate start orbit for collisions +}; + +enum class InteractionLockMode { + NOLOCK, + EVERYN, + MINTIMEDISTANCE +}; + +struct InteractionSpec { + std::string name; // name (prefix for transport simulation); may also serve as unique identifier + float interactionRate; + std::pair<int, float> synconto; // if this interaction locks on another interaction; takes precedence over interactionRate + InteractionLockMode syncmode = InteractionLockMode::NOLOCK; + int mcnumberasked = -1; // number of MC events asked (but can be left -1) in which case it will be determined from timeframelength + int mcnumberavail = -1; // number of MC events avail (but can be left -1); if avail < asked there will be reuse of events + bool randomizeorder = false; // whether order of events will be randomized +}; + +InteractionSpec parseInteractionSpec(std::string const& specifier, std::vector<InteractionSpec> const& existingPatterns) +{ + // An interaction specification is a command-separated string + // of the following form: + // SPEC=NAMESTRING,INTERACTIONSTRING[,MCNUMBERSTRING] + // + // where + // + // NAMESTRING : a simple named specifier for the interaction; matching to a simulation prefix used by o2-sim + // + // INTERACTIONSTRING: irate | @ID:[ed]FLOATVALUE + // - either: a simple number irate specifying the interaction rate in kHz + // - or: a string such as @0:e5, saying that this interaction should match/sync + // with collisions of the 0-th interaction, but inject only every 5 collisions. + // Alternatively @0:d10000 means to inject but leaving a timedistance of at least 10000ns between signals + // + // MCNUMBERSTRING: NUMBER1:r?NUMBER2 can specify how many collisions NUMBER1 to produce, taking from a sample of NUMBER2 available collisions + // - this option is only supported on the first interaction which is supposed to be the background interaction + // - if the 'r' character is present we randomize the order of the MC events + + // tokens are separated by comma + std::vector<std::string> tokens = o2::RangeTokenizer::tokenize<std::string>(specifier); + + float rate = -1.; + std::pair<int, float> synconto(-1, 1); + + // extract name + std::string name = tokens[0]; + + // extract the MC number spec if given + int collisionsasked = -1; + int collisionsavail = -1; + bool randomizeorder = false; + if (tokens.size() > 2) { + auto mctoken = tokens[2]; + std::regex re("([0-9]*):(r?)([0-9]*)$", std::regex_constants::extended); + + std::cmatch m; + if (std::regex_match(mctoken.c_str(), m, re)) { + collisionsasked = std::atoi(m[1].str().c_str()); + if (m[2].str().compare("r") == 0) { + randomizeorder = true; + } + collisionsavail = std::atoi(m[3].str().c_str()); + } else { + LOG(ERROR) << "Could not parse " << mctoken << " as MCNUMBERSTRING"; + exit(1); + } + } + + // extract interaction rate ... or locking + auto& interactionToken = tokens[1]; + if (interactionToken[0] == '@') { + try { + // locking onto some other interaction + std::regex re("@([0-9]*):([ed])([0-9]*[.]?[0-9]?)$", std::regex_constants::extended); + + std::cmatch m; + if (std::regex_match(interactionToken.c_str(), m, re)) { + auto crossindex = std::atoi(m[1].str().c_str()); + auto mode = m[2].str(); + auto modevalue = std::atof(m[3].str().c_str()); + + if (crossindex > existingPatterns.size()) { + LOG(ERROR) << "Reference to non-existent interaction spec"; + exit(1); + } + synconto = std::pair<int, float>(crossindex, modevalue); + + InteractionLockMode lockMode; + if (mode.compare("e") == 0) { + lockMode = InteractionLockMode::EVERYN; + } + if (mode.compare("d") == 0) { + lockMode = InteractionLockMode::MINTIMEDISTANCE; + } + return InteractionSpec{name, rate, synconto, lockMode, collisionsasked, collisionsavail, randomizeorder}; + } else { + LOG(ERROR) << "Could not parse " << interactionToken << " as INTERACTIONSTRING"; + exit(1); + } + } catch (std::regex_error e) { + LOG(ERROR) << "Exception during regular expression match " << e.what(); + exit(1); + } + } else { + rate = std::atof(interactionToken.c_str()); + return InteractionSpec{name, rate, synconto, InteractionLockMode::NOLOCK, collisionsasked, collisionsavail, randomizeorder}; + } +} + +bool parseOptions(int argc, char* argv[], Options& optvalues) +{ + namespace bpo = boost::program_options; + bpo::options_description options( + "A utility to create and manipulate digitization contexts (MC collision structure within a timeframe).\n\n" + "Allowed options"); + + options.add_options()( + "interactions,i", bpo::value<std::vector<std::string>>(&optvalues.interactionRates)->multitoken(), "name,IRate|LockSpecifier")( + "outfile,o", bpo::value<std::string>(&optvalues.outfilename)->default_value("collisioncontext.root"), "Outfile of collision context")( + "tflength", bpo::value<double>(&optvalues.timeframelengthinMS)->default_value(-1.), + "Length of timeframe to generate in ms (if given). " + "Otherwise, the context will be generated by using collision numbers from the interaction specification.")( + "seed", bpo::value<long>(&optvalues.seed)->default_value(0L), "Seed for random number generator (for time sampling etc). Default 0: Random")( + "show-context", "Print generated collision context to terminal.")( + "bcPatternFile", bpo::value<std::string>(&optvalues.bcpatternfile)->default_value(""), "Interacting BC pattern file (e.g. from CreateBCPattern.C)")( + "orbitsPerTF", bpo::value<int>(&optvalues.orbitsPerTF)->default_value(256), "Orbits per timeframes")( + "timeframeID", bpo::value<int>(&optvalues.tfid)->default_value(0), "Timeframe id of this context. Allows to generate contexts for different start orbits"); + + options.add_options()("help,h", "Produce help message."); + + bpo::variables_map vm; + try { + bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm); + bpo::notify(vm); + + // help + if (vm.count("help")) { + std::cout << options << std::endl; + return false; + } + if (vm.count("show-context")) { + optvalues.printContext = true; + } + + } catch (const bpo::error& e) { + std::cerr << e.what() << "\n\n"; + std::cerr << "Error parsing options; Available options:\n"; + std::cerr << options << std::endl; + return false; + } + return true; +} + +int main(int argc, char* argv[]) +{ + Options options; + if (!parseOptions(argc, argv, options)) { + exit(1); + } + + // init random generator + gRandom->SetSeed(options.seed); + + std::vector<InteractionSpec> ispecs; + // building the interaction spec + for (auto& i : options.interactionRates) { + // this is created as output from + ispecs.push_back(parseInteractionSpec(i, ispecs)); + } + + std::vector<std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>>> collisions; + std::vector<o2::BunchFilling> bunchFillings; // vector of bunch filling objects; generated by interaction samplers + + // now we generate the collision structure (interaction type by interaction type) + bool usetimeframelength = options.timeframelengthinMS > 0; + + for (int id = 0; id < ispecs.size(); ++id) { + auto mode = ispecs[id].syncmode; + if (mode == InteractionLockMode::NOLOCK) { + o2::steer::InteractionSampler sampler; + sampler.setInteractionRate(ispecs[id].interactionRate); + if (!options.bcpatternfile.empty()) { + sampler.setBunchFilling(options.bcpatternfile); + } + sampler.setFirstIR(o2::InteractionRecord(0, options.tfid * options.orbitsPerTF)); + sampler.init(); + o2::InteractionTimeRecord record; + int count = 0; + do { + record = sampler.generateCollisionTime(); + std::vector<o2::steer::EventPart> parts; + parts.emplace_back(id, count); + + std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>> insertvalue(record, parts); + auto iter = std::lower_bound(collisions.begin(), collisions.end(), insertvalue, [](std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>> const& a, std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>> const& b) { return a.first < b.first; }); + collisions.insert(iter, insertvalue); + count++; + } while ((usetimeframelength && record.getTimeNS() < options.timeframelengthinMS * 1000 * 1000) || (ispecs[id].mcnumberasked > 0 && count < ispecs[id].mcnumberasked)); + + // we support randomization etc on non-injected/embedded interactions + // and we can apply them here + auto random_shuffle = [](auto first, auto last) { + auto n = last - first; + for (auto i = n - 1; i > 0; --i) { + using std::swap; + swap(first[i], first[(int)(gRandom->Rndm() * n)]); + } + }; + std::vector<int> eventindices(count); + std::iota(eventindices.begin(), eventindices.end(), 0); + // apply randomization of order if any + if (ispecs[id].randomizeorder) { + random_shuffle(eventindices.begin(), eventindices.end()); + } + if (ispecs[id].mcnumberavail > 0) { + // apply cutting to number of available entries + for (auto& e : eventindices) { + e = e % ispecs[id].mcnumberavail; + } + } + // make these transformations final: + for (auto& col : collisions) { + for (auto& part : col.second) { + if (part.sourceID == id) { + part.entryID = eventindices[part.entryID]; + } + } + } + + // keep bunch filling information produced by these samplers + bunchFillings.push_back(sampler.getBunchFilling()); + + } else { + // we are in some lock/sync mode and modify existing collisions + int lastcol = -1; + double lastcoltime = -1.; + auto distanceval = ispecs[id].synconto.second; + auto lockonto = ispecs[id].synconto.first; + int eventcount = 0; + + for (int colid = 0; colid < collisions.size(); ++colid) { + auto& col = collisions[colid]; + auto coltime = col.first.getTimeNS(); + + bool rightinteraction = false; + // we are locking only on collisions which have the referenced interaction present + // --> there must be an EventPart with the right sourceID + for (auto& eventPart : col.second) { + if (eventPart.sourceID == lockonto) { + rightinteraction = true; + break; + } + } + if (!rightinteraction) { + continue; + } + + bool inject = false; + // we always start with first one + if (lastcol == -1) { + inject = true; + } + if (mode == InteractionLockMode::EVERYN && (colid - lastcol) >= distanceval) { + inject = true; + } + if (mode == InteractionLockMode::MINTIMEDISTANCE && (coltime - lastcoltime) >= distanceval) { + inject = true; + } + + if (inject) { + col.second.emplace_back(id, eventcount++); + lastcol = colid; + lastcoltime = coltime; + } + } + } + } + + // create DigitizationContext + o2::steer::DigitizationContext digicontext; + // we can fill this container + auto& parts = digicontext.getEventParts(); + // we can fill this container + auto& records = digicontext.getEventRecords(); + // copy over information + size_t maxParts = 0; + for (auto& p : collisions) { + records.push_back(p.first); + parts.push_back(p.second); + maxParts = std::max(p.second.size(), maxParts); + } + digicontext.setNCollisions(collisions.size()); + digicontext.setMaxNumberParts(maxParts); + // merge bunch filling info + for (int i = 1; i < bunchFillings.size(); ++i) { + bunchFillings[0].mergeWith(bunchFillings[i]); + } + digicontext.setBunchFilling(bunchFillings[0]); + std::vector<std::string> prefixes; + for (auto& p : ispecs) { + prefixes.push_back(p.name); + } + digicontext.setSimPrefixes(prefixes); + if (options.printContext) { + digicontext.printCollisionSummary(); + } + digicontext.saveToFile(options.outfilename); + + return 0; +} diff --git a/Steer/src/HitProcessingManager.cxx b/Steer/src/HitProcessingManager.cxx index 27e86523162d5..7d98438deb4ad 100644 --- a/Steer/src/HitProcessingManager.cxx +++ b/Steer/src/HitProcessingManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -55,7 +56,7 @@ bool HitProcessingManager::setupChain() auto& c = *mSimChains[0]; c.Reset(); for (auto& filename : mBackgroundFileNames) { - c.AddFile(o2::base::NameConf::getMCKinematicsFileName(filename.data()).c_str()); + c.AddFile(o2::base::NameConf::getMCHeadersFileName(filename.data()).c_str()); } for (auto& pair : mSignalFileNames) { @@ -63,7 +64,7 @@ bool HitProcessingManager::setupChain() const auto& filenamevector = pair.second; auto& chain = *mSimChains[signalid]; for (auto& filename : filenamevector) { - chain.AddFile(o2::base::NameConf::getMCKinematicsFileName(filename.data()).c_str()); + chain.AddFile(o2::base::NameConf::getMCHeadersFileName(filename.data()).c_str()); } } @@ -124,7 +125,7 @@ void HitProcessingManager::sampleCollisionTimes() { mDigitizationContext.getEventRecords().resize(mDigitizationContext.getNCollisions()); mInteractionSampler.generateCollisionTimes(mDigitizationContext.getEventRecords()); - mDigitizationContext.getBunchFilling() = mInteractionSampler.getBunchFilling(); + mDigitizationContext.setBunchFilling(mInteractionSampler.getBunchFilling()); mDigitizationContext.setMuPerBC(mInteractionSampler.getMuPerBC()); } diff --git a/Steer/src/InteractionSampler.cxx b/Steer/src/InteractionSampler.cxx index b59cca5c1804d..d099053f0430b 100644 --- a/Steer/src/InteractionSampler.cxx +++ b/Steer/src/InteractionSampler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/src/MCKinematicsReader.cxx b/Steer/src/MCKinematicsReader.cxx index a77089db29172..4b1edafefc986 100644 --- a/Steer/src/MCKinematicsReader.cxx +++ b/Steer/src/MCKinematicsReader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -11,13 +12,55 @@ #include "DetectorsCommonDataFormats/NameConf.h" #include "Steer/MCKinematicsReader.h" #include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/TrackReference.h" #include <TChain.h> #include <vector> #include "FairLogger.h" using namespace o2::steer; -void MCKinematicsReader::loadTracksForSource(int source) const +MCKinematicsReader::~MCKinematicsReader() +{ + for (auto chain : mInputChains) { + delete chain; + } + mInputChains.clear(); + + if (mDigitizationContext) { + delete mDigitizationContext; + } +} + +void MCKinematicsReader::initIndexedTrackRefs(std::vector<o2::TrackReference>& refs, o2::dataformats::MCTruthContainer<o2::TrackReference>& indexedrefs) const +{ + // sort trackrefs according to track index then according to track length + std::sort(refs.begin(), refs.end(), [](const o2::TrackReference& a, const o2::TrackReference& b) { + if (a.getTrackID() == b.getTrackID()) { + return a.getLength() < b.getLength(); + } + return a.getTrackID() < b.getTrackID(); + }); + + // make final indexed container for track references + indexedrefs.clear(); + for (auto& ref : refs) { + if (ref.getTrackID() >= 0) { + indexedrefs.addElement(ref.getTrackID(), ref); + } + } +} + +void MCKinematicsReader::initTracksForSource(int source) const +{ + auto chain = mInputChains[source]; + if (chain) { + // todo: get name from NameConfig + auto br = chain->GetBranch("MCTrack"); + mTracks[source].resize(br->GetEntries(), nullptr); + } +} + +void MCKinematicsReader::loadTracksForSourceAndEvent(int source, int event) const { auto chain = mInputChains[source]; if (chain) { @@ -26,16 +69,22 @@ void MCKinematicsReader::loadTracksForSource(int source) const if (br) { std::vector<MCTrack>* loadtracks = nullptr; br->SetAddress(&loadtracks); - // load all kinematics - mTracks[source].resize(br->GetEntries()); - for (int event = 0; event < br->GetEntries(); ++event) { - br->GetEntry(event); - mTracks[source][event] = *loadtracks; - } + br->GetEntry(event); + mTracks[source][event] = new std::vector<o2::MCTrack>; + *mTracks[source][event] = *loadtracks; + delete loadtracks; } } } +void MCKinematicsReader::releaseTracksForSourceAndEvent(int source, int eventID) +{ + if (mTracks.at(source).at(eventID) != nullptr) { + delete mTracks[source][eventID]; + mTracks[source][eventID] = nullptr; + } +} + void MCKinematicsReader::loadHeadersForSource(int source) const { auto chain = mInputChains[source]; @@ -50,12 +99,39 @@ void MCKinematicsReader::loadHeadersForSource(int source) const br->GetEntry(event); mHeaders[source][event] = *header; } + delete header; + header = nullptr; } else { LOG(WARN) << "MCHeader branch not found"; } } } +void MCKinematicsReader::loadTrackRefsForSource(int source) const +{ + auto chain = mInputChains[source]; + if (chain) { + // todo: get name from NameConfig + auto br = chain->GetBranch("TrackRefs"); + if (br) { + std::vector<o2::TrackReference>* refs = nullptr; + br->SetAddress(&refs); + mIndexedTrackRefs[source].resize(br->GetEntries()); + for (int event = 0; event < br->GetEntries(); ++event) { + br->GetEntry(event); + if (refs) { + // we convert the original flat vector into an indexed structure + initIndexedTrackRefs(*refs, mIndexedTrackRefs[source][event]); + delete refs; + refs = nullptr; + } + } + } else { + LOG(WARN) << "TrackRefs branch not found"; + } + } +} + bool MCKinematicsReader::initFromDigitContext(std::string_view name) { if (mInitialized) { @@ -76,6 +152,7 @@ bool MCKinematicsReader::initFromDigitContext(std::string_view name) // load the kinematics information mTracks.resize(mInputChains.size()); mHeaders.resize(mInputChains.size()); + mIndexedTrackRefs.resize(mInputChains.size()); // actual loading will be done only if someone asks // the first time for a particular source ... @@ -93,6 +170,7 @@ bool MCKinematicsReader::initFromKinematics(std::string_view name) mInputChains.back()->AddFile(o2::base::NameConf::getMCKinematicsFileName(name.data()).c_str()); mTracks.resize(1); mHeaders.resize(1); + mIndexedTrackRefs.resize(1); mInitialized = true; return true; diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index 57d70317c24c3..a9cce295677ae 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include <sstream> #include <SimConfig/SimConfig.h> #include <DetectorsBase/Detector.h> +#include "DetectorsBase/Aligner.h" #include <CommonUtils/ShmManager.h> #include <cassert> #include <SimulationDataFormat/MCEventHeader.h> @@ -54,14 +56,27 @@ void O2MCApplicationBase::Stepping() // we can kill tracks here based on our // custom detector specificities + // Note that this is done in addition to the generic + // R + Z-cut mechanism at VMC level. + float x, y, z; fMC->TrackPosition(x, y, z); - if (z > mCutParams.ZmaxA) { - fMC->StopTrack(); - return; - } - if (-z > mCutParams.ZmaxC) { + // this function is implementing a basic z-dependent R cut + // can be generalized later on + auto outOfR = [x, y, this](float z) { + // for the moment for cases when we have ZDC enabled + if (std::abs(z) > mCutParams.tunnelZ) { + if ((x * x + y * y) > mCutParams.maxRTrackingZDC * mCutParams.maxRTrackingZDC) { + return true; + } + } + return false; + }; + + if (z > mCutParams.ZmaxA || + -z > mCutParams.ZmaxC || + outOfR(z)) { fMC->StopTrack(); return; } @@ -81,13 +96,18 @@ void O2MCApplicationBase::ConstructGeometry() { // fill the mapping mModIdToName.clear(); + o2::detectors::DetID::mask_t dmask{}; for (int i = 0; i < fModules->GetEntries(); ++i) { auto mod = static_cast<FairModule*>(fModules->At(i)); if (mod) { mModIdToName[mod->GetModId()] = mod->GetName(); + int did = o2::detectors::DetID::nameToID(mod->GetName()); + if (did >= 0) { + dmask |= o2::detectors::DetID::getMask(did); + } } } - + gGeoManager->SetUniqueID(dmask.to_ulong()); FairMCApplication::ConstructGeometry(); std::ofstream voltomodulefile("MCStepLoggerVolMap.dat"); @@ -123,7 +143,9 @@ bool O2MCApplicationBase::MisalignGeometry() } } - auto b = FairMCApplication::MisalignGeometry(); + // RS We want to store ideal geometry to be able to apply different alignments on the fly + // auto b = FairMCApplication::MisalignGeometry(); + // we use this moment to stream our geometry (before other // VMC engine dependent modifications are done) @@ -131,8 +153,12 @@ bool O2MCApplicationBase::MisalignGeometry() auto geomfile = o2::base::NameConf::getGeomFileName(confref.getOutPrefix()); gGeoManager->Export(geomfile.c_str()); + // apply alignment for included detectors AFTER exporting ideal geometry + auto& aligner = o2::base::Aligner::Instance(); + aligner.applyAlignment(0); + // return original return value of misalignment procedure - return b; + return true; } void O2MCApplicationBase::finishEventCommon() @@ -248,7 +274,6 @@ void O2MCApplication::SendData() attachSubEventInfo(simdataparts, *mSubEventInfo); auto tracks = attachBranch<std::vector<o2::MCTrack>>("MCTrack", *mSimDataChannel, simdataparts); attachBranch<std::vector<o2::TrackReference>>("TrackRefs", *mSimDataChannel, simdataparts); - attachBranch<o2::dataformats::MCTruthContainer<o2::TrackReference>>("IndexedTrackRefs", *mSimDataChannel, simdataparts); assert(tracks->size() == mSubEventInfo->npersistenttracks); for (auto det : listActiveDetectors) { diff --git a/Steer/src/SteerLinkDef.h b/Steer/src/SteerLinkDef.h index 66a1bde07eca6..f0b62cd482249 100644 --- a/Steer/src/SteerLinkDef.h +++ b/Steer/src/SteerLinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/test/testHitProcessingManager.cxx b/Steer/test/testHitProcessingManager.cxx index 97de4051095f2..8450e8ddd4f74 100644 --- a/Steer/test/testHitProcessingManager.cxx +++ b/Steer/test/testHitProcessingManager.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Steer/test/testInteractionSampler.cxx b/Steer/test/testInteractionSampler.cxx index 452c932a47c53..c76d9560c367d 100644 --- a/Steer/test/testInteractionSampler.cxx +++ b/Steer/test/testInteractionSampler.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt index 440514c381c6a..20a124fa58119 100644 --- a/Utilities/CMakeLists.txt +++ b/Utilities/CMakeLists.txt @@ -1,26 +1,17 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -if(ALIROOT) - # FIXME: not tested - add_subdirectory(hough) -endif(ALIROOT) - -add_subdirectory(aliceHLTwrapper) -add_subdirectory(O2MessageMonitor) -add_subdirectory(DataFlow) add_subdirectory(DataSampling) -add_subdirectory(Publishers) add_subdirectory(DataCompression) add_subdirectory(Mergers) -add_subdirectory(O2Device) add_subdirectory(PCG) add_subdirectory(rANS) add_subdirectory(Tools) diff --git a/Utilities/DataCompression/CMakeLists.txt b/Utilities/DataCompression/CMakeLists.txt index 214a4f5e85c2c..268fa6a8ae576 100644 --- a/Utilities/DataCompression/CMakeLists.txt +++ b/Utilities/DataCompression/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test(dc_primitives SOURCES test/test_dc_primitives.cxx @@ -27,7 +28,7 @@ o2_add_test(DataGenerator o2_add_test(HuffmanCodec SOURCES test/test_HuffmanCodec.cxx COMPONENT_NAME DataCompression - PUBLIC_LINK_LIBRARIES O2::CommonUtils Boost::filesystem + PUBLIC_LINK_LIBRARIES O2::CommonUtils LABELS utils) o2_add_test(DataDeflater diff --git a/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h b/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h index 0d54e019a9a94..68fcc8360df2b 100644 --- a/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h +++ b/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/include/DataCompression/DataDeflater.h b/Utilities/DataCompression/include/DataCompression/DataDeflater.h index 71ec5492b90b7..25c7dad81dcea 100644 --- a/Utilities/DataCompression/include/DataCompression/DataDeflater.h +++ b/Utilities/DataCompression/include/DataCompression/DataDeflater.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/include/DataCompression/HuffmanCodec.h b/Utilities/DataCompression/include/DataCompression/HuffmanCodec.h index 5b6cda6bac249..6cfbccf099ca8 100644 --- a/Utilities/DataCompression/include/DataCompression/HuffmanCodec.h +++ b/Utilities/DataCompression/include/DataCompression/HuffmanCodec.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/include/DataCompression/TruncatedPrecisionConverter.h b/Utilities/DataCompression/include/DataCompression/TruncatedPrecisionConverter.h index 11c0498ddee4a..dbf82781f6257 100644 --- a/Utilities/DataCompression/include/DataCompression/TruncatedPrecisionConverter.h +++ b/Utilities/DataCompression/include/DataCompression/TruncatedPrecisionConverter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/include/DataCompression/dc_primitives.h b/Utilities/DataCompression/include/DataCompression/dc_primitives.h index 8bb379d302bef..5b054caa82a93 100644 --- a/Utilities/DataCompression/include/DataCompression/dc_primitives.h +++ b/Utilities/DataCompression/include/DataCompression/dc_primitives.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/include/DataCompression/runtime_container.h b/Utilities/DataCompression/include/DataCompression/runtime_container.h index 32cf5e9bed173..363f4220e73f6 100644 --- a/Utilities/DataCompression/include/DataCompression/runtime_container.h +++ b/Utilities/DataCompression/include/DataCompression/runtime_container.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/DataGenerator.h b/Utilities/DataCompression/test/DataGenerator.h index eea927312d54a..ec3983384a5e5 100644 --- a/Utilities/DataCompression/test/DataGenerator.h +++ b/Utilities/DataCompression/test/DataGenerator.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/Fifo.h b/Utilities/DataCompression/test/Fifo.h index 56717729dc2ff..2c7a8a9939f64 100644 --- a/Utilities/DataCompression/test/Fifo.h +++ b/Utilities/DataCompression/test/Fifo.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/test_DataDeflater.cxx b/Utilities/DataCompression/test/test_DataDeflater.cxx index e42aa89dab38d..9762544a4bcbc 100644 --- a/Utilities/DataCompression/test/test_DataDeflater.cxx +++ b/Utilities/DataCompression/test/test_DataDeflater.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/test_DataGenerator.cxx b/Utilities/DataCompression/test/test_DataGenerator.cxx index de0fa72b22888..b7b830d4e150f 100644 --- a/Utilities/DataCompression/test/test_DataGenerator.cxx +++ b/Utilities/DataCompression/test/test_DataGenerator.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/test_Fifo.cxx b/Utilities/DataCompression/test/test_Fifo.cxx index 9a579fb6665df..828f8724e36a6 100644 --- a/Utilities/DataCompression/test/test_Fifo.cxx +++ b/Utilities/DataCompression/test/test_Fifo.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/test/test_HuffmanCodec.cxx b/Utilities/DataCompression/test/test_HuffmanCodec.cxx index 9c7d8cd7cd10d..bec783976985d 100644 --- a/Utilities/DataCompression/test/test_HuffmanCodec.cxx +++ b/Utilities/DataCompression/test/test_HuffmanCodec.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,7 +18,7 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include <boost/filesystem.hpp> +#include <filesystem> #include <iostream> #include <iomanip> #include <sstream> @@ -27,6 +28,7 @@ #include <stdexcept> // exeptions, runtime_error #include "../include/DataCompression/dc_primitives.h" #include "../include/DataCompression/HuffmanCodec.h" +#include "CommonUtils/StringUtils.h" #include "DataGenerator.h" #include "Fifo.h" @@ -213,14 +215,13 @@ BOOST_AUTO_TEST_CASE(test_HuffmanCodec_configuration) // check writing and reading of the huffman configuration std::stringstream filename; - filename << boost::filesystem::temp_directory_path().string() << "/" << boost::filesystem::unique_path().string() - << "_testHuffmanCodec.zlib"; + filename << o2::utils::Str::create_unique_path(std::filesystem::temp_directory_path().native()) << "_testHuffmanCodec.zlib"; auto nNodes = codec.writeConfiguration(filename.str().c_str(), "zlib"); BOOST_CHECK(nNodes > 0); auto result = codec.loadConfiguration(filename.str().c_str(), "zlib"); BOOST_CHECK(result == 0); - boost::filesystem::remove(filename.str()); + std::filesystem::remove(filename.str()); checkRandom(codec, dg); } diff --git a/Utilities/DataCompression/test/test_dc_primitives.cxx b/Utilities/DataCompression/test/test_dc_primitives.cxx index a2c78cfaa0112..c2d8d9e05770a 100644 --- a/Utilities/DataCompression/test/test_dc_primitives.cxx +++ b/Utilities/DataCompression/test/test_dc_primitives.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataCompression/tpccluster_parameter_model.h b/Utilities/DataCompression/tpccluster_parameter_model.h index e8538016321b6..e8455399f17c1 100644 --- a/Utilities/DataCompression/tpccluster_parameter_model.h +++ b/Utilities/DataCompression/tpccluster_parameter_model.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataFlow/CMakeLists.txt b/Utilities/DataFlow/CMakeLists.txt deleted file mode 100644 index 05e9e26bd0c31..0000000000000 --- a/Utilities/DataFlow/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -# the bucket contains the following dependencies - common_boost_bucket - Base - -# Headers - O2device - dl the 'dl' dependency is needed as the device -# boilerplate code in runSimpleMQStateMachine.h uses dlopen etc. Probably this -# hidden dependency can be avoided by including the to some compiled FairMQ -# library - -o2_add_library(DataFlow - SOURCES src/FakeTimeframeBuilder.cxx - src/FakeTimeframeGeneratorDevice.cxx - src/HeartbeatSampler.cxx - src/SubframeBuilderDevice.cxx - src/TimeframeParser.cxx - src/TimeframeReaderDevice.cxx - src/TimeframeValidatorDevice.cxx - src/TimeframeWriterDevice.cxx - src/EPNReceiverDevice.cxx - src/FLPSenderDevice.cxx - PUBLIC_LINK_LIBRARIES O2::Headers O2::TimeFrame FairMQ::FairMQ - O2::Device) - -o2_target_man_page(DataFlow NAME o2-timeframe-reader-device) -o2_target_man_page(DataFlow NAME o2-timeframe-writer-device) -o2_target_man_page(DataFlow NAME o2-subframebuilder-device) - -o2_add_executable(fake-timeframegenerator-device - SOURCES src/runFakeTimeframeGeneratorDevice - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(heartbeat-sampler - SOURCES src/runHeartbeatSampler - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(subframebuilder-device - SOURCES src/runSubframeBuilderDevice - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(timeframe-reader-device - SOURCES src/runTimeframeReaderDevice - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(timeframe-validator-device - SOURCES src/runTimeframeValidatorDevice - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(timeframe-writer-device - SOURCES src/runTimeframeWriterDevice - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(epn-receiver-device - SOURCES src/runEPNReceiver - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(flp-sender-device - SOURCES src/runFLPSender - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_executable(timeframe-validation-tool - SOURCES src/TimeframeValidationTool - PUBLIC_LINK_LIBRARIES O2::DataFlow) - -o2_add_test(TimeframeParser - SOURCES test/test_TimeframeParser - PUBLIC_LINK_LIBRARIES O2::DataFlow - COMPONENT_NAME dataflow - LABELS utils) - -o2_add_test(SubframeUtils01 - SOURCES test/test_SubframeUtils01 - PUBLIC_LINK_LIBRARIES O2::DataFlow - COMPONENT_NAME dataflow - LABELS utils) - -o2_add_test(PayloadMerger01 - SOURCES test/test_PayloadMerger01 - PUBLIC_LINK_LIBRARIES O2::DataFlow - COMPONENT_NAME dataflow - LABELS utils) diff --git a/Utilities/DataFlow/doc/o2-subframebuilder-device.1.in b/Utilities/DataFlow/doc/o2-subframebuilder-device.1.in deleted file mode 100644 index 653053997d842..0000000000000 --- a/Utilities/DataFlow/doc/o2-subframebuilder-device.1.in +++ /dev/null @@ -1,48 +0,0 @@ -.\" Manpage for o2-subframebuilder-device. -.TH AliceO2 1 "12 May 2017" "1.0" "o2-subframebuilder-device man page" - -.SH NAME - -o2-subframebuilder-device - aggregate HBF in input as a single STF - -.SH SYNOPSIS - -o2-subframebuilder-device [options] - -.SH DESCRIPTION - -o2-subframebuilder-device will take in input a number of HeartBeat Frames -(HBF) and merge them in a single STF, with a policy defined by the -passed options. - -.SH OPTIONS - ---self-triggered Time frame duration - -.TP 5 - ---in-chan-name [NAME] Name of the input channel - -.TP 5 - ---out-chan-name [NAME] Name of the output channel - -.TP 5 - ---detector-name [NAME] Name of detector as data source - -.TP 5 - ---flp-id arg [NAME] ID of the FLP used as data source - -.TP 5 - ---strip-hbf Strip HeartBeatHeader (HBH) & HeartBeatTrailer (HBT) from each HBF - -.SH SEE ALSO - -FLPSenderDEvice(1), o2-epn-receiver-device(1), o2-heartbeat-sampler(1), TimeframeValidator(1) - -.SH BUGS - -Lots of bugs diff --git a/Utilities/DataFlow/doc/o2-timeframe-reader-device.1.in b/Utilities/DataFlow/doc/o2-timeframe-reader-device.1.in deleted file mode 100644 index bdf460cadc976..0000000000000 --- a/Utilities/DataFlow/doc/o2-timeframe-reader-device.1.in +++ /dev/null @@ -1,29 +0,0 @@ -.\" Manpage for o2-timeframe-reader-device. -.TH man 1 "12 May 2017" "1.0" "o2-timeframe-reader-device man page" - -.SH NAME - -o2-timeframe-reader-device - read a timeframe from disk - -.SH SYNOPSIS - -o2-timeframe-reader-device --input-file [FILE] - -.SH DESCRIPTION - -o2-timeframe-reader-device will read a Timeframe from the FILE on disk and streams it -via FairMQ - -.SH OPTIONS - -.TP 5 - ---input-file [FILE] the file to be streamed - -.SH SEE ALSO - -o2-timeframe-writer-device(1) - -.SH BUGS - -Lots of bugs diff --git a/Utilities/DataFlow/doc/o2-timeframe-writer-device.1.in b/Utilities/DataFlow/doc/o2-timeframe-writer-device.1.in deleted file mode 100644 index a4828d9f12d41..0000000000000 --- a/Utilities/DataFlow/doc/o2-timeframe-writer-device.1.in +++ /dev/null @@ -1,29 +0,0 @@ -.\" Manpage for o2-timeframe-writer-device. -.TH man 1 "12 May 2017" "1.0" "o2-timeframe-writer-device man page" - -.SH NAME - -o2-timeframe-writer-device - writes a timeframe to disk - -.SH SYNOPSIS - -o2-timeframe-writer-device --input-file [FILE] - -.SH DESCRIPTION - -o2-timeframe-writer-device will receive a Timeframe from FairMQ transport and stream -it via FairMQ. - -.SH OPTIONS - -.TP 5 - ---output-file [FILE] the file where to stream results - -.SH SEE ALSO - -o2-timeframe-reader-device(1) - -.SH BUGS - -Lots of bugs diff --git a/Utilities/DataFlow/include/DataFlow/EPNReceiverDevice.h b/Utilities/DataFlow/include/DataFlow/EPNReceiverDevice.h deleted file mode 100644 index f13fc8cd88585..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/EPNReceiverDevice.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_DEVICES_EPNRECEIVER_H_ -#define ALICEO2_DEVICES_EPNRECEIVER_H_ - -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <chrono> - -#include <FairMQDevice.h> - -namespace o2 -{ -namespace devices -{ - -/// Container for (sub-)timeframes - -struct TFBuffer { - FairMQParts parts; - std::chrono::steady_clock::time_point start; - std::chrono::steady_clock::time_point end; -}; - -/// Receives sub-timeframes from the flpSenders and merges these into full timeframes. - -class EPNReceiverDevice final : public FairMQDevice -{ - public: - EPNReceiverDevice() = default; - ~EPNReceiverDevice() final = default; - void InitTask() final; - - /// Prints the contents of the timeframe container - void PrintBuffer(const std::unordered_map<uint16_t, TFBuffer>& buffer) const; - - /// Discared incomplete timeframes after \p fBufferTimeoutInMs. - void DiscardIncompleteTimeframes(); - - protected: - /// Overloads the Run() method of FairMQDevice - void Run() override; - - std::unordered_map<uint16_t, TFBuffer> mTimeframeBuffer; ///< Stores (sub-)timeframes - std::unordered_set<uint16_t> mDiscardedSet; ///< Set containing IDs of dropped timeframes - - int mNumFLPs = 0; ///< Number of flpSenders - int mBufferTimeoutInMs = 5000; ///< Time after which incomplete timeframes are dropped - int mTestMode = 0; ///< Run the device in test mode (only syncSampler+flpSender+epnReceiver) - - std::string mInChannelName = ""; - std::string mOutChannelName = ""; - std::string mAckChannelName = ""; -}; - -} // namespace devices -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/include/DataFlow/FLPSenderDevice.h b/Utilities/DataFlow/include/DataFlow/FLPSenderDevice.h deleted file mode 100644 index 08cda323677b9..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/FLPSenderDevice.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_DEVICES_FLPSENDER_H_ -#define ALICEO2_DEVICES_FLPSENDER_H_ - -#include <string> -#include <queue> -#include <unordered_map> -#include <chrono> - -#include <FairMQDevice.h> - -namespace o2 -{ -namespace devices -{ - -/// Sends sub-timframes to epnReceivers -/// -/// Sub-timeframes are received from the previous step (or generated in test-mode) -/// and are sent to epnReceivers. Target epnReceiver is determined from the timeframe ID: -/// targetEpnReceiver = timeframeId % numEPNs (numEPNs is same for every flpSender, although some may be inactive). - -class FLPSenderDevice final : public FairMQDevice -{ - public: - /// Default constructor - FLPSenderDevice() = default; - - /// Default destructor - ~FLPSenderDevice() final = default; - - protected: - /// Overloads the InitTask() method of FairMQDevice - void InitTask() final; - - /// Overloads the Run() method of FairMQDevice - void Run() final; - - private: - /// Sends the "oldest" element from the sub-timeframe container - void sendFrontData(); - - std::queue<FairMQParts> mSTFBuffer; ///< Buffer for sub-timeframes - std::queue<std::chrono::steady_clock::time_point> mArrivalTime; ///< Stores arrival times of sub-timeframes - - int mNumEPNs = 0; ///< Number of epnReceivers - unsigned int mIndex = 0; ///< Index of the flpSender among other flpSenders - unsigned int mSendOffset = 0; ///< Offset for staggering output - unsigned int mSendDelay = 8; ///< Delay for staggering output - - int mEventSize = 10000; ///< Size of the sub-timeframe body (only for test mode) - int mTestMode = false; ///< Run the device in test mode (only syncSampler+flpSender+epnReceiver) - uint16_t mTimeFrameId; - - std::string mInChannelName = ""; - std::string mOutChannelName = ""; - int mLastTimeframeId = -1; -}; - -} // namespace devices -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/include/DataFlow/FakeTimeframeBuilder.h b/Utilities/DataFlow/include/DataFlow/FakeTimeframeBuilder.h deleted file mode 100644 index 87e72cc0df998..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/FakeTimeframeBuilder.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef DATAFLOW_FAKETIMEFRAMEBUILDER_H_ -#define DATAFLOW_FAKETIMEFRAMEBUILDER_H_ - -#include "Headers/DataHeader.h" -#include <vector> -#include <memory> -#include <functional> - -namespace o2 -{ -namespace data_flow -{ - -struct FakeTimeframeSpec { - const char* origin; - const char* dataDescription; - std::function<void(char*, size_t)> bufferFiller; - size_t bufferSize; -}; - -/** Generate a timeframe from the provided specification - */ -std::unique_ptr<char[]> fakeTimeframeGenerator(std::vector<FakeTimeframeSpec>& specs, std::size_t& totalSize); - -} // namespace data_flow -} // namespace o2 -#endif /* DATAFLOW_FAKETIMEFRAMEBUILDER_H_ */ diff --git a/Utilities/DataFlow/include/DataFlow/FakeTimeframeGeneratorDevice.h b/Utilities/DataFlow/include/DataFlow/FakeTimeframeGeneratorDevice.h deleted file mode 100644 index 5c25ec45f7394..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/FakeTimeframeGeneratorDevice.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_FAKE_TIMEFRAME_GENERATOR_H_ -#define ALICEO2_FAKE_TIMEFRAME_GENERATOR_H_ - -#include "O2Device/O2Device.h" - -namespace o2 -{ -namespace data_flow -{ - -/// A device which writes to file the timeframes. -class FakeTimeframeGeneratorDevice : public base::O2Device -{ - public: - static constexpr const char* OptionKeyOutputChannelName = "output-channel-name"; - static constexpr const char* OptionKeyMaxTimeframes = "max-timeframes"; - - /// Default constructor - FakeTimeframeGeneratorDevice(); - - /// Default destructor - ~FakeTimeframeGeneratorDevice() override = default; - - void InitTask() final; - - protected: - /// Overloads the ConditionalRun() method of FairMQDevice - bool ConditionalRun() final; - - std::string mOutChannelName; - size_t mMaxTimeframes; - size_t mTimeframeCount; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/include/DataFlow/HeartbeatSampler.h b/Utilities/DataFlow/include/DataFlow/HeartbeatSampler.h deleted file mode 100644 index a6bf6dce79ff6..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/HeartbeatSampler.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef HEARTBEATSAMPLER_H -#define HEARTBEATSAMPLER_H - -// @file HeartbeatSampler.h -// @author Matthias Richter -// @since 2017-02-03 -// @brief Heartbeat sampler device - -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" -#include "O2Device/O2Device.h" -#include <string> - -namespace o2 -{ -namespace data_flow -{ - -/// @class HeartbeatSampler -/// @brief A sampler for heartbeat triggers -/// -/// The device is going to be used in an emulation of the reader -/// processes on the FLP -/// The heartbeat triggers are sent out with constant frequency, the -/// period in nano seconds can be configured by option --period -/// -/// TODO: the class can evolve to a general clock sampler device with -/// configurable period, even randomly distributed -class HeartbeatSampler final : public base::O2Device -{ - public: - typedef o2::base::O2Message O2Message; - - static constexpr const char* OptionKeyOutputChannelName = "out-chan-name"; - static constexpr const char* OptionKeyPeriod = "period"; - - HeartbeatSampler() = default; - ~HeartbeatSampler() final = default; - - protected: - /// overloading the InitTask() method of FairMQDevice - void InitTask() final; - - /// overloading ConditionalRun method of FairMQDevice - bool ConditionalRun() final; - - private: - /// publishing period (configurable) - uint32_t mPeriod = 1000000000; - /// name of the (configurable) - std::string mOutputChannelName = "output"; - /// number of elapsed periods - int mCount = 0; -}; - -} // namespace data_flow -}; // namespace o2 -#endif diff --git a/Utilities/DataFlow/include/DataFlow/PayloadMerger.h b/Utilities/DataFlow/include/DataFlow/PayloadMerger.h deleted file mode 100644 index 81c4544a5f717..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/PayloadMerger.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef PAYLOAD_MERGER_H -#define PAYLOAD_MERGER_H - -#include <map> -#include <cstdint> -#include <vector> -#include <functional> -#include <cstring> - -#include <fairmq/FairMQMessage.h> - -namespace o2 -{ -namespace dataflow -{ -/// Helper class that given a set of FairMQMessage, merges (part of) their -/// payload into a separate memory area. -/// -/// - Append multiple messages via the aggregate method -/// - Finalise buffer creation with the finalise call. -template <typename ID> -class PayloadMerger -{ - public: - using MergeableId = ID; - using MessageMap = std::multimap<MergeableId, std::unique_ptr<FairMQMessage>>; - using PayloadExtractor = std::function<size_t(char**, char*, size_t)>; - using IdExtractor = std::function<MergeableId(std::unique_ptr<FairMQMessage>&)>; - using MergeCompletionCheker = std::function<bool(MergeableId, MessageMap&)>; - - /// Helper class to merge FairMQMessages sharing a user defined class of equivalence, - /// specified by @makeId. Completeness of the class of equivalence can be asserted by - /// the @checkIfComplete policy. It's also possible to specify a user defined way of - /// extracting the parts of the payload to be merged via the extractPayload method. - PayloadMerger(IdExtractor makeId, - MergeCompletionCheker checkIfComplete, - PayloadExtractor extractPayload = fullPayloadExtractor) - : mMakeId{makeId}, - mCheckIfComplete{checkIfComplete}, - mExtractPayload{extractPayload} - { - } - - /// Aggregates @payload to all the ones with the same id. - /// @return the id extracted from the payload via the constructor - /// specified id policy (mMakeId callback). - MergeableId aggregate(std::unique_ptr<FairMQMessage>& payload) - { - auto id = mMakeId(payload); - mPartsMap.emplace(std::make_pair(id, std::move(payload))); - return id; - } - - /// This merges a set of messages sharing the same id @id to a unique buffer - /// @out, so that it can be either consumed or sent as a message itself. - /// The decision on whether the merge must happen is done by the constructor - /// specified policy mCheckIfComplete which can, for example, decide - /// to merge when a certain number of subparts are reached. - /// Merging at the moment requires an extra copy, but in principle this could - /// be easily extended to support scatter - gather. - size_t finalise(char** out, MergeableId& id) - { - *out = nullptr; - if (mCheckIfComplete(id, mPartsMap) == false) { - return 0; - } - // If we are here, it means we can send the messages that belong - // to some predefined class of equivalence, identified by the MERGEABLE_ID, - // to the receiver. This is done by the following process: - // - // - Extract what we actually want to send (this might be data embedded inside the message itself) - // - Calculate the aggregate size of all the payloads. - // - Copy all the parts into a final payload - // - Create the header part - // - Create the payload part - // - Send - std::vector<std::pair<char*, size_t>> parts; - - size_t sum = 0; - auto range = mPartsMap.equal_range(id); - for (auto hi = range.first, he = range.second; hi != he; ++hi) { - std::unique_ptr<FairMQMessage>& payload = hi->second; - std::pair<char*, size_t> part; - part.second = mExtractPayload(&part.first, reinterpret_cast<char*>(payload->GetData()), payload->GetSize()); - parts.push_back(part); - sum += part.second; - } - - auto* payload = new char[sum](); - size_t offset = 0; - for (auto& part : parts) { - // Right now this does a copy. In principle this could be done with some sort of - // vectorized I/O - memcpy(payload + offset, part.first, part.second); - offset += part.second; - } - - mPartsMap.erase(id); - *out = payload; - return sum; - } - - // Helper method which leaves the payload untouched - static int64_t fullPayloadExtractor(char** payload, - char* buffer, - size_t bufferSize) - { - *payload = buffer; - return bufferSize; - } - - private: - IdExtractor mMakeId; - MergeCompletionCheker mCheckIfComplete; - PayloadExtractor mExtractPayload; - - MessageMap mPartsMap; -}; -} // namespace dataflow -} // namespace o2 - -#endif // PAYLOAD_MERGER_H diff --git a/Utilities/DataFlow/include/DataFlow/SubframeBuilderDevice.h b/Utilities/DataFlow/include/DataFlow/SubframeBuilderDevice.h deleted file mode 100644 index 0eda40bf51d0f..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/SubframeBuilderDevice.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef SUBFRAMEBUILDERDEVICE_H -#define SUBFRAMEBUILDERDEVICE_H - -/// @file SubframeBuilderDevice.h -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-07 -/// @brief Demonstrator device for a subframe builder - -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" -#include "O2Device/O2Device.h" -#include "DataFlow/PayloadMerger.h" -#include "DataFlow/SubframeUtils.h" -#include <cstring> -#include <map> - -class FairMQParts; - -namespace o2 -{ -namespace data_flow -{ - -/// @class SubframeBuilderDevice -/// A demonstrator device for building of sub timeframes -/// -/// The scheme in the demonstrator chain assumes multiple data publishers -/// for different input chains of the CRU. The output of these publishers -/// is assembled to a sub timeframe by this device. -/// -/// The device implements the high-level API of the FairMQDevice -/// run loop. The registered method is called once per message -/// which is in itself a multipart message. It;s parts are passed -/// with a FairMQParts object. Not yet clear if this approach is -/// suited for the frame builder as it needs the data from multiple -/// channels with the same channel name. Depends on the validity of -/// the message data. Very likely the message parts are no longer -/// valid after leaving the handler method. But one could apply a -/// scheme with unique pointers and move semantics -/// -/// The duration should be with respect to a time constant, which in -/// itself needs to be configurable, now the time constant is -/// hard-coded microseconds -class SubframeBuilderDevice final : public base::O2Device -{ - public: - using O2Message = o2::base::O2Message; - using SubframeId = o2::dataflow::SubframeId; - using Merger = dataflow::PayloadMerger<SubframeId>; - - static constexpr const char* OptionKeyInputChannelName = "in-chan-name"; - static constexpr const char* OptionKeyOutputChannelName = "out-chan-name"; - static constexpr const char* OptionKeyOrbitDuration = "orbit-duration"; - static constexpr const char* OptionKeyOrbitsPerTimeframe = "orbits-per-timeframe"; - static constexpr const char* OptionKeyInDataFile = "indatafile-name"; - static constexpr const char* OptionKeyDetector = "detector-name"; - static constexpr const char* OptionKeyFLPId = "flp-id"; - static constexpr const char* OptionKeyStripHBF = "strip-hbf"; - - // TODO: this is just a first mockup, remove it - // Default start time for all the producers is 8/4/1977 - // Timeframe start time will be ((N * duration) + start time) where - // N is the incremental number of timeframes being sent out. - // TODO: replace this with a unique Heartbeat from a common device. - static constexpr uint32_t DefaultOrbitDuration = 88924; - static constexpr uint32_t DefaultOrbitsPerTimeframe = 256; - static constexpr uint64_t DefaultHeartbeatStart = 229314600000000000LL; - - /// Default constructor - SubframeBuilderDevice(); - - /// Default destructor - ~SubframeBuilderDevice() final; - - protected: - /// overloading the InitTask() method of FairMQDevice - void InitTask() final; - - /// data handling method to be registered as handler in the - /// FairMQDevice API method OnData - /// The device base class handles the state loop in the RUNNING - /// state and calls the handler when receiving a message on one channel - /// The multiple parts included in one message are provided in the - /// FairMQParts object. - bool HandleData(FairMQParts& msgParts, int /*index*/); - - /// Build the frame and send it - /// For the moment a simple mockup composing a DataHeader and adding it - /// to the multipart message together with the SubframeMetadata as payload - bool BuildAndSendFrame(FairMQParts& parts); - - private: - uint32_t mOrbitsPerTimeframe; - // FIXME: lookup the actual value - uint32_t mOrbitDuration; - std::string mInputChannelName = ""; - std::string mOutputChannelName = ""; - size_t mFLPId = 0; - bool mStripHBF = false; - std::unique_ptr<Merger> mMerger; - - uint64_t mHeartbeatStart = DefaultHeartbeatStart; - - template <typename T> - size_t fakeHBHPayloadHBT(char** buffer, std::function<void(T&, int)> filler, int numOfElements) - { - // LOG(INFO) << "SENDING TPC PAYLOAD\n"; - auto payloadSize = sizeof(header::HeartbeatHeader) + sizeof(T) * numOfElements + sizeof(header::HeartbeatTrailer); - *buffer = new char[payloadSize]; - auto* hbh = reinterpret_cast<header::HeartbeatHeader*>(*buffer); - assert(payloadSize > 0); - assert(payloadSize - sizeof(header::HeartbeatTrailer) > 0); - auto* hbt = reinterpret_cast<header::HeartbeatTrailer*>(payloadSize - sizeof(header::HeartbeatTrailer)); - - T* payload = reinterpret_cast<T*>(*buffer + sizeof(header::HeartbeatHeader)); - for (int i = 0; i < numOfElements; ++i) { - new (payload + i) T; - // put some random toy time stamp to each cluster - filler(payload[i], i); - } - return payloadSize; - } -}; - -} // namespace data_flow -}; // namespace o2 -#endif diff --git a/Utilities/DataFlow/include/DataFlow/SubframeUtils.h b/Utilities/DataFlow/include/DataFlow/SubframeUtils.h deleted file mode 100644 index 69b5f3d4a6c24..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/SubframeUtils.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef DATAFLOW_SUBFRAMEUTILS_H -#define DATAFLOW_SUBFRAMEUTILS_H - -#include <tuple> -#include <cstddef> -#include "Headers/HeartbeatFrame.h" - -namespace o2 -{ -namespace dataflow -{ - -int64_t extractDetectorPayloadStrip(char** payload, char* buffer, size_t bufferSize) -{ - *payload = buffer + sizeof(o2::header::HeartbeatHeader); - return bufferSize - sizeof(o2::header::HeartbeatHeader) - sizeof(o2::header::HeartbeatTrailer); -} - -struct SubframeId { - size_t timeframeId; - size_t socketId; - - // operator needed for the equal_range algorithm/ multimap method - bool operator<(const SubframeId& rhs) const - { - return std::tie(timeframeId, socketId) < std::tie(rhs.timeframeId, rhs.socketId); - } -}; - -SubframeId makeIdFromHeartbeatHeader(const header::HeartbeatHeader& header, size_t socketId, size_t orbitsPerTimeframe) -{ - SubframeId id = { - .timeframeId = header.orbit / orbitsPerTimeframe, - .socketId = socketId}; - return id; -} - -} /* namespace dataflow */ -} /* namespace o2 */ - -#endif // DATAFLOW_SUBFRAMEUTILS_H diff --git a/Utilities/DataFlow/include/DataFlow/TimeframeParser.h b/Utilities/DataFlow/include/DataFlow/TimeframeParser.h deleted file mode 100644 index 590982c1dfb04..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/TimeframeParser.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef TIMEFRAME_PARSER_H_ -#define TIMEFRAME_PARSER_H_ - -#include <iosfwd> -#include <functional> - -class FairMQParts; - -namespace o2 -{ -namespace data_flow -{ - -/// An helper function which takes a std::istream pointing -/// to a naively persisted timeframe and pumps its parts to -/// FairMQParts, ready to be shipped via FairMQ. -void streamTimeframe(std::istream& stream, - std::function<void(FairMQParts& parts, char* buffer, size_t size)> onAddPart, - std::function<void(FairMQParts& parts)> onSend); - -void streamTimeframe(std::ostream& stream, FairMQParts& parts); - -} // namespace data_flow -} // namespace o2 - -#endif // TIMEFRAME_PARSER_H diff --git a/Utilities/DataFlow/include/DataFlow/TimeframeReaderDevice.h b/Utilities/DataFlow/include/DataFlow/TimeframeReaderDevice.h deleted file mode 100644 index f4359b6f21142..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/TimeframeReaderDevice.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_TIMEFRAME_READER_H_ -#define ALICEO2_TIMEFRAME_READER_H_ - -#include "O2Device/O2Device.h" -#include <fstream> - -namespace o2 -{ -namespace data_flow -{ - -/// A device which writes to file the timeframes. -class TimeframeReaderDevice : public base::O2Device -{ - public: - static constexpr const char* OptionKeyOutputChannelName = "output-channel-name"; - static constexpr const char* OptionKeyInputFileName = "input-file"; - - /// Default constructor - TimeframeReaderDevice(); - - /// Default destructor - ~TimeframeReaderDevice() override = default; - - void InitTask() final; - - protected: - /// Overloads the ConditionalRun() method of FairMQDevice - bool ConditionalRun() final; - - std::string mOutChannelName; - std::string mInFileName; - std::fstream mFile; - std::vector<std::string> mSeen; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/include/DataFlow/TimeframeValidatorDevice.h b/Utilities/DataFlow/include/DataFlow/TimeframeValidatorDevice.h deleted file mode 100644 index 453b0ea669d5b..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/TimeframeValidatorDevice.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_TIMEFRAMEVALIDATOR_H_ -#define ALICEO2_TIMEFRAMEVALIDATOR_H_ - -#include "O2Device/O2Device.h" - -namespace o2 -{ -namespace data_flow -{ - -/// A validating device for time frame data (coming from EPN) -class TimeframeValidatorDevice : public base::O2Device -{ - public: - static constexpr const char* OptionKeyInputChannelName = "input-channel-name"; - - /// Default constructor - TimeframeValidatorDevice(); - - /// Default destructor - ~TimeframeValidatorDevice() override = default; - - void InitTask() final; - - protected: - /// Overloads the Run() method of FairMQDevice - void Run() final; - - std::string mInChannelName; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/include/DataFlow/TimeframeWriterDevice.h b/Utilities/DataFlow/include/DataFlow/TimeframeWriterDevice.h deleted file mode 100644 index 73fceed644d48..0000000000000 --- a/Utilities/DataFlow/include/DataFlow/TimeframeWriterDevice.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_TIMEFRAME_WRITER_DEVICE_H_ -#define ALICEO2_TIMEFRAME_WRITER_DEVICE_H_ - -#include "O2Device/O2Device.h" -#include <fstream> - -namespace o2 -{ -namespace data_flow -{ - -/// A device which writes to file the timeframes. -class TimeframeWriterDevice : public base::O2Device -{ - public: - static constexpr const char* OptionKeyInputChannelName = "input-channel-name"; - static constexpr const char* OptionKeyOutputFileName = "output-file"; - static constexpr const char* OptionKeyMaxTimeframesPerFile = "max-timeframes-per-file"; - static constexpr const char* OptionKeyMaxFileSize = "max-file-size"; - static constexpr const char* OptionKeyMaxFiles = "max-files"; - - /// Default constructor - TimeframeWriterDevice(); - - /// Default destructor - ~TimeframeWriterDevice() override = default; - - void InitTask() final; - - /// The PostRun will trigger saving the file to disk - void PostRun() final; - - protected: - /// Overloads the Run() method of FairMQDevice - void Run() final; - - std::string mInChannelName; - std::string mOutFileName; - std::fstream mFile; - size_t mMaxTimeframes; - size_t mMaxFileSize; - size_t mMaxFiles; - size_t mFileCount; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/Utilities/DataFlow/run/CreateSetup.py b/Utilities/DataFlow/run/CreateSetup.py deleted file mode 100755 index 0ebe8f8f38a82..0000000000000 --- a/Utilities/DataFlow/run/CreateSetup.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/python -# a very simple python script to -# create and scale a topology/conf + runfile for a variable list of -# HeartbeatSampler + DataPublisher + ... + FLP + EPN -# author: S. Wenzel -#FIXME: decide whether to config for xterm or tmux - -import json - -NumFLP = 2 -NumDP = NumFLP # in principle we could have different number of data publishers -NumEPN = 4 -EPNStartSocket = 6000 -HeartbeatSocket = 5000 -HeartbeatBaseName = "o2-heartbeat-sampler" -EPNBaseName = "epnReceiver" -SFBStartSocket = 5500 -FLPStartSocket = 4000 -ValidatorStartSocket = 7000 -FLPBaseName = "flpSender" -DPBaseName = "o2-datapublisher-device" -SFBBaseName = "subframeBuilder" -tcpbase = "tcp://127.0.0.1:" -detectors = ["TPC","ITS"] -datadescription = ["TPCCLUSTER", "ITSRAW"] - -configfilename = "customconfig.json" -runscriptfilename = "customrunscript.sh" - -# some potentially reusable API to construct devices -def initDevice(name): - device = {} - device["id"] = name - device["channels"] = [] # empty list for device - return device - -# creates one channel; empty sockets -def initChannel(name, type, connect): - channel = {} - channel["name"] = name - channel["type"] = type - channel["method"] = connect - channel["sockets"] = [] - return channel - -def initAddress(url): - return {"address":url} - -def addChannel(device, channel): - device["channels"].append(channel) - -def addAddress(channel, address): - channel["sockets"].append(address) - -# adds a custom key:value pair to a dictionary -def addPair(element, key, value): - element[key]=value - -# code describing our devices follows - -def writeOneDP(id): - device = initDevice(DPBaseName+str(id)) - inchannel = initChannel("input","sub","connect") - addAddress(inchannel, initAddress(tcpbase + str(HeartbeatSocket))) - outchannel = initChannel("output","pub","bind") - addAddress(outchannel, initAddress(tcpbase + str(SFBStartSocket + id))) - addPair(outchannel, "sndBufSize", "10") - addChannel(device, inchannel) - addChannel(device, outchannel) - return device - -def writeOneSFB(id): - device = initDevice(SFBBaseName + str(id)) - # the input channel - inchannel = initChannel("input", "sub", "connect") - addAddress(inchannel, initAddress(tcpbase + str(SFBStartSocket+id))) - addPair(inchannel, "sndBufSize", "10") - # the output channel - outchannel = initChannel("output", "pub", "bind") - addAddress(outchannel, initAddress(tcpbase + str(FLPStartSocket+id))) - addPair(outchannel, "sndBufSize", "10") - addChannel(device,inchannel) - addChannel(device,outchannel) - return device - -def writeHBSamplerDevice(): - device = initDevice(HeartbeatBaseName) - outchannel = initChannel("output", "pub", "bind") - addAddress(outchannel, initAddress(tcpbase + str(HeartbeatSocket))) - addChannel(device, outchannel) - return device - -# write timeframeValidator -def writeTFV(): - device = initDevice("timeframeValidator") - channel = initChannel("input", "sub", "connect") - addAddress(channel, initAddress(tcpbase + str(ValidatorStartSocket))) - addChannel(device, channel) - return device - -# write single flp device -def writeOneFLP(id): - device = initDevice(FLPBaseName + str(id)) - inchannel = initChannel("input","sub","connect") - addAddress(inchannel, initAddress(tcpbase + str(FLPStartSocket+id))) - outchannel = initChannel("output", "push", "connect") - # write all EPN addresses - for i in range(0,NumEPN): - addAddress(outchannel, initAddress(tcpbase + str(EPNStartSocket+i))) - addChannel(device, inchannel) - addChannel(device, outchannel) - return device - -def writeOneEPN(id): - # write a single EPN device - device = initDevice(EPNBaseName + str(id)) - inchannel = initChannel("input", "pull", "bind") - addAddress(inchannel, initAddress(tcpbase + str(EPNStartSocket+id))) - # the ack channel - ackchannel = initChannel("ack", "push", "connect") - addAddress(ackchannel, initAddress("tcp://127.0.0.1:5990")) - addPair(ackchannel, "ratelogging", "0") - # the output channel (time frame validator) - outchannel = initChannel("output", "pub", "bind") - addAddress(outchannel, initAddress(tcpbase + str(ValidatorStartSocket))) - addChannel(device, inchannel) - addChannel(device, ackchannel) - addChannel(device, outchannel) - return device - -def addFLPDevices(devicelist): - for i in range(0,NumFLP): - devicelist.append(writeOneDP(i)) - devicelist.append(writeOneSFB(i)) - devicelist.append(writeOneFLP(i)) - -def addEPNDevices(devicelist): - for i in range(0,NumEPN): - devicelist.append(writeOneEPN(i)) - -def getConf(): - conf = {} - conf["fairMQOptions"] = {"devices" : []} - devicelist = conf["fairMQOptions"]["devices"] - # append all the the devices to this list - addFLPDevices(devicelist) - addEPNDevices(devicelist) - devicelist.append(writeTFV()) - devicelist.append(writeHBSamplerDevice()) - return conf - -def writeJSONConf(): - print "creating JOSN config " + configfilename - with open(configfilename, 'w') as f: - f.write(json.dumps(getConf())) - -def writeRunScript(): - xtermcommand = "xterm -hold -e " - dumpstring = [] - # treat data publishers - for i in range(0, NumDP): - # we might need to give information about detector to DP as well - command = "o2-datapublisher-device --id DataPublisherDevice" + str(i) - command += " --data-description " + datadescription[i%2] - command += " --mq-config " + configfilename + " --in-chan-name input --out-chan-name output &" - dumpstring.append(xtermcommand + command) - - # treat sfbdevices - for i in range(0, NumFLP): - command = "o2-subframebuilder-device --id subframeBuilder" + str(i) - command += " --mq-config " + configfilename + " --detector " + detectors[i%2] + " &" - dumpstring.append(xtermcommand + command) - # treat flpSender - for i in range(0, NumFLP): - flpCommand = "flpSender --id flpSender" + str(i) - flpCommand += " --mq-config " + configfilename + " --in-chan-name input" - flpCommand += " --out-chan-name output --num-epns " + str(NumEPN) + " --flp-index " + str(i) - flpCommand += "&" - dumpstring.append(xtermcommand + flpCommand) - # treat EPN receiver - for i in range(0, NumEPN): - epnCommand = "epnReceiver --id epnReceiver" + str(i) - epnCommand += " --mq-config " + configfilename + " --in-chan-name input --out-chan-name output" - epnCommand += " --num-flps " + str(NumFLP) + "&" - dumpstring.append(xtermcommand + epnCommand) - # treat timeFrameValidator - command = "o2-timeframe-validator-device --id timeframeValidator --mq-config " + configfilename + " customconfig.json --input-channel-name input &" - dumpstring.append(xtermcommand + command) - - # treat heartbeatsampler - command = "o2-heartbeat-sampler --id heartbeatSampler --mq-config " + configfilename + " --out-chan-name output &" - dumpstring.append(xtermcommand + command) - - print "creating runscript " + runscriptfilename - with open(runscriptfilename, 'w') as f: - f.write('\n'.join(dumpstring)) - -if __name__ == '__main__': - writeJSONConf() - writeRunScript() diff --git a/Utilities/DataFlow/run/confBasicSetup.json b/Utilities/DataFlow/run/confBasicSetup.json deleted file mode 100644 index 4fe1a1c633d61..0000000000000 --- a/Utilities/DataFlow/run/confBasicSetup.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "fairMQOptions": - { - "devices": - [ - { - "id": "subframeBuilder", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5550" } - ], - "sndBufSize": "10" - }] - }, - - { - "id": "flpSender", - "channels": - [{ - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5550" } - ], - "rcvBufSize": "10" - }, - { - "name": "output", - "type": "push", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5570" } - ], - "sndBufSize": "10" - }] - }, - - { - "id": "epnReceiver", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5570"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, - - { - "id": "timeframeValidator", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5580"} - ], - "sndBufSize": "10" - } - ] - } - - ] - } -} diff --git a/Utilities/DataFlow/run/confComplexSetup.json b/Utilities/DataFlow/run/confComplexSetup.json deleted file mode 100644 index cbb69fb7434ce..0000000000000 --- a/Utilities/DataFlow/run/confComplexSetup.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "fairMQOptions": - { - "devices": - [ - { - "id": "subframeBuilderTPC", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5550" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "flpSenderTPC", - "channels": - [{ - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5550" } - ], - "rcvBufSize": "10" - }, - { - "name": "output", - "type": "push", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5570" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "subframeBuilderITS", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5551" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "flpSenderITS", - "channels": - [{ - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5551" } - ], - "rcvBufSize": "10" - }, - { - "name": "output", - "type": "push", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5570" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "epnReceiver", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5570"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, - { - "id": "timeframeValidator", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5580"} - ], - "sndBufSize": "10" - } - ] - } - ] - } -} diff --git a/Utilities/DataFlow/run/confComplexSetup2.json b/Utilities/DataFlow/run/confComplexSetup2.json deleted file mode 100644 index 3c527d7616713..0000000000000 --- a/Utilities/DataFlow/run/confComplexSetup2.json +++ /dev/null @@ -1,345 +0,0 @@ -{ - "fairMQOptions": - { - "devices": - [ - { - "id": "heartbeatSampler", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5450" } - ], - "sndBufSize": "10" - } - ] - }, - { - "id": "DataPublisherDeviceTPC", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets":[ - {"address": "tcp://127.0.0.1:5450"} - ] - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:6550" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "DataPublisherDeviceITS", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets":[ - {"address": "tcp://127.0.0.1:5450"} - ] - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:7550" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "subframeBuilderTPC", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets":[ - {"address": "tcp://127.0.0.1:6550"} - ] - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5550" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "flpSenderTPC", - "channels": - [ - { - "name": "input-channel-name", - "type": "sub", - "method": "connect", - "sockets":[ - {"address": "tcp://127.0.0.1:5450"} - ] - }, - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5550" } - ], - "rcvBufSize": "10" - }, - { - "name": "output", - "type": "push", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5570" }, - { "address": "tcp://127.0.0.1:5571" }, - { "address": "tcp://127.0.0.1:5572" }, - { "address": "tcp://127.0.0.1:5573" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "subframeBuilderITS", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets":[ - {"address": "tcp://127.0.0.1:7550"} - ] - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5551" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "flpSenderITS", - "channels": - [{ - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5551" } - ], - "rcvBufSize": "10" - }, - { - "name": "output", - "type": "push", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5570" }, - { "address": "tcp://127.0.0.1:5571" }, - { "address": "tcp://127.0.0.1:5572" }, - { "address": "tcp://127.0.0.1:5573" } - ], - "sndBufSize": "10" - }] - }, - { - "id": "epnReceiver1", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5570"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, -{ - "id": "epnReceiver1", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5570"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, - { - "id": "epnReceiver2", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5571"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, - { - "id": "epnReceiver3", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5572"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, -{ - "id": "epnReceiver4", - "channels": - [ - { - "name": "input", - "type": "pull", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5573"} - ], - "sndBufSize": "10" - }, - { - "name": "ack", - "type": "push", - "method": "connect", - "address": "tcp://127.0.0.1:5990", - "rateLogging": "0" - }, - { - "name": "output", - "type": "pub", - "method": "bind", - "address": "tcp://127.0.0.1:5580", - "sndBufSize": "10" - } - ] - }, - { - "id": "timeframeValidator", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5580"} - ], - "sndBufSize": "10" - } - ] - } - ] - } -} diff --git a/Utilities/DataFlow/run/confFakeTimeframe.json b/Utilities/DataFlow/run/confFakeTimeframe.json deleted file mode 100644 index ae1f686087f25..0000000000000 --- a/Utilities/DataFlow/run/confFakeTimeframe.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "fairMQOptions": - { - "devices": - [ - { - "id": "FakeTimeframeGeneratorDevice", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://*:5550" } - ], - "sndBufSize": "10" - } - ] - }, - { - "id": "TimeframeWriterDevice", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5550"} - ], - "sndBufSize": "10" - } - ] - }, - { - "id": "TimeframeReaderDevice", - "channels": - [ - { - "name": "output", - "type": "pub", - "method": "bind", - "sockets": - [ - { "address": "tcp://127.0.0.1:5551"} - ], - "sndBufSize": "10" - } - ] - }, - { - "id": "TimeframeValidatorDevice", - "channels": - [ - { - "name": "input", - "type": "sub", - "method": "connect", - "sockets": - [ - { "address": "tcp://127.0.0.1:5551"} - ], - "sndBufSize": "10" - } - ] - } - ] - } -} diff --git a/Utilities/DataFlow/run/startBasicSetup.sh b/Utilities/DataFlow/run/startBasicSetup.sh deleted file mode 100755 index e69106eab5dc5..0000000000000 --- a/Utilities/DataFlow/run/startBasicSetup.sh +++ /dev/null @@ -1,13 +0,0 @@ -# simple start script to lauch a basic setup -# Prerequisites: -# - expects the configuration file to be in the working directory -# - O2 bin and lib set n the shell environment - - -xterm -geometry 80x25+0+0 -hold -e epnReceiver --id epnReceiver --mq-config confBasicSetup.json --in-chan-name input --out-chan-name output --num-flps 1 & - -xterm -geometry 80x25+500+0 -hold -e flpSender --id flpSender --mq-config confBasicSetup.json --in-chan-name input --out-chan-name output --num-epns 1 & - -xterm -geometry 80x25+1000+0 -hold -e o2-subframebuilder-device --id subframeBuilder --mq-config confBasicSetup.json --self-triggered & - -xterm -geometry 80x25+1500+0 -hold -e o2-timeframe-validator-device --id timeframeValidator --mq-config confBasicSetup.json --input-channel-name input & diff --git a/Utilities/DataFlow/run/startComplexSetup.sh b/Utilities/DataFlow/run/startComplexSetup.sh deleted file mode 100755 index 6280269be5d16..0000000000000 --- a/Utilities/DataFlow/run/startComplexSetup.sh +++ /dev/null @@ -1,24 +0,0 @@ -# simple start script to launch a more complex setup -# with 2 data publishers (inside subframebuilder) + 2 attached flpSenders -# Prerequisites: -# - expects the configuration file to be in the working directory -# - O2 bin and lib set n the shell environment - - -# we have just one epn and 2 flps -xterm -geometry 80x25+0+0 -hold -e epnReceiver --id epnReceiver --mq-config confComplexSetup.json --in-chan-name input --out-chan-name output --num-flps 2 & - -# this is the flp for TPC -xterm -geometry 80x25+500+0 -hold -e flpSender --id flpSenderTPC --mq-config confComplexSetup.json --in-chan-name input --out-chan-name output --num-epns 1 --flp-index 0 & - -# this is the flp for ITS -xterm -geometry 80x25+800+0 -hold -e flpSender --id flpSenderITS --mq-config confComplexSetup.json --in-chan-name input --out-chan-name output --num-epns 1 --flp-index 1 & - -# this is the subtimeframe publisher for TPC -xterm -geometry 80x25+0+500 -hold -e o2-subframebuilder-device --id subframeBuilderTPC --mq-config confComplexSetup.json --self-triggered --detector TPC & - -# this is the subtimeframe publisher for ITS -xterm -geometry 80x25+500+500 -hold -e o2-subframebuilder-device --id subframeBuilderITS --mq-config confComplexSetup.json --self-triggered --detector ITS & - -# consumer and validator of the full EPN time frame -xterm -geometry 80x25+800+500 -hold -e o2-timeframe-validator-device --id timeframeValidator --mq-config confComplexSetup.json --input-channel-name input & diff --git a/Utilities/DataFlow/run/startComplexSetup2.sh b/Utilities/DataFlow/run/startComplexSetup2.sh deleted file mode 100755 index a0c343658ad8a..0000000000000 --- a/Utilities/DataFlow/run/startComplexSetup2.sh +++ /dev/null @@ -1,36 +0,0 @@ -# simple start script to launch a more complex setup -# with 2 data publishers (inside subframebuilder) + 2 attached flpSenders + 4 EPNS -# Prerequisites: -# - expects the configuration file to be in the working directory -# - O2 bin and lib set n the shell environment - -# it would be nice having a script that generates the configuration file for N FLP and M EPNS - -# Start one HBSampler device -xterm -geometry 80x25+0+0 -hold -e o2-heartbeat-sampler --id heartbeatSampler --mq-config confComplexSetup2.json --out-chan-name output & - -# Data publishers -xterm -geometry 80x25+500+0 -hold -e o2-datapublisher-device --id DataPublisherDeviceTPC --mq-config confComplexSetup2.json --in-chan-name input --out-chan-name output --data-description TPCCLUSTER & -xterm -geometry 80x25+500+400 -hold -e o2-datapublisher-device --id DataPublisherDeviceITS --mq-config confComplexSetup2.json --in-chan-name input --out-chan-name output --data-description ITSRAW & - - -# this is the subtimeframe publisher for TPC -xterm -geometry 80x25+1000+0 -hold -e o2-subframebuilder-device --id subframeBuilderTPC --mq-config confComplexSetup2.json --detector TPC & - -# this is the subtimeframe publisher for ITS -xterm -geometry 80x25+1000+400 -hold -e o2-subframebuilder-device --id subframeBuilderITS --mq-config confComplexSetup2.json --detector ITS & - -# this is the flp for TPC -xterm -geometry 80x25+1500+0 -hold -e o2-flp-sender-device --id flpSenderTPC --mq-config confComplexSetup2.json --in-chan-name input --out-chan-name output --num-epns 4 --flp-index 0 & - -# this is the flp for ITS -xterm -geometry 80x25+1500+400 -hold -e o2-flp-sender-device --id flpSenderITS --mq-config confComplexSetup2.json --in-chan-name input --out-chan-name output --num-epns 4 --flp-index 1 & - -# we have 4 epn and 2 flps -xterm -geometry 80x25+2000+0 -hold -e o2-epn-receiver-device --id epnReceiver1 --mq-config confComplexSetup2.json --buffer-timeout 10000 --in-chan-name input --out-chan-name output --num-flps 2 & -xterm -geometry 80x25+2000+400 -hold -e o2-epn-receiver-device --id epnReceiver2 --mq-config confComplexSetup2.json --buffer-timeout 10000 --in-chan-name input --out-chan-name output --num-flps 2 & -xterm -geometry 80x25+2000+800 -hold -e o2-epn-receiver-device --id epnReceiver3 --mq-config confComplexSetup2.json --buffer-timeout 10000 --in-chan-name input --out-chan-name output --num-flps 2 & -xterm -geometry 80x25+2000+1200 -hold -e o2-epn-receiver-device --id epnReceiver4 --mq-config confComplexSetup2.json --buffer-timeout 10000 --in-chan-name input --out-chan-name output --num-flps 2 & - -# consumer and validator of the full EPN time frame -xterm -geometry 80x25+2000+500 -hold -e o2-timeframe-validator-device --id timeframeValidator --mq-config confComplexSetup2.json --input-channel-name input & diff --git a/Utilities/DataFlow/run/startTimeframeExample.sh b/Utilities/DataFlow/run/startTimeframeExample.sh deleted file mode 100755 index f9c108825cc3a..0000000000000 --- a/Utilities/DataFlow/run/startTimeframeExample.sh +++ /dev/null @@ -1,4 +0,0 @@ -xterm -geometry 80x25+0+0 -hold -e FakeTimeframeGeneratorDevice --id FakeTimeframeGeneratorDevice --mq-config confFakeTimeframe.json --output-channel-name output & -xterm -geometry 80x25+0+0 -hold -e o2-timeframe-writer-device --id TimeframeWriterDevice --mq-config confFakeTimeframe.json --input-channel-name input --max-timeframes 1 --output-file data.o2tf & -#xterm -geometry 80x25+0+0 -hold -e o2-timeframe-reader-device --id TimeframeReaderDevice --mq-config confFakeTimeframe.json --input-file data.o2tf --output-channel-name output & -#xterm -geometry 80x25+0+0 -hold -e o2-timeframe-validator-device --id TimeframeValidatorDevice --mq-config confFakeTimeframe.json --input-channel-name input & diff --git a/Utilities/DataFlow/src/EPNReceiverDevice.cxx b/Utilities/DataFlow/src/EPNReceiverDevice.cxx deleted file mode 100644 index 9424bd58d9f25..0000000000000 --- a/Utilities/DataFlow/src/EPNReceiverDevice.cxx +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <cstddef> // size_t -#include <fstream> // writing to file (DEBUG) -#include <cstring> -#include <iomanip> - -#include <FairMQLogger.h> -#include <options/FairMQProgOptions.h> - -#include "DataFlow/EPNReceiverDevice.h" -#include "Headers/DataHeader.h" -#include "Headers/SubframeMetadata.h" -#include "O2Device/Compatibility.h" -#include "TimeFrame/TimeFrame.h" - -#include <iomanip> - -using namespace std; -using namespace std::chrono; -using namespace o2::devices; -using SubframeMetadata = o2::data_flow::SubframeMetadata; -using TPCTestPayload = o2::data_flow::TPCTestPayload; -using TPCTestCluster = o2::data_flow::TPCTestCluster; -using IndexElement = o2::dataformats::IndexElement; - -void EPNReceiverDevice::InitTask() -{ - mNumFLPs = GetConfig()->GetValue<int>("num-flps"); - mBufferTimeoutInMs = GetConfig()->GetValue<int>("buffer-timeout"); - mTestMode = GetConfig()->GetValue<int>("test-mode"); - mInChannelName = GetConfig()->GetValue<string>("in-chan-name"); - mOutChannelName = GetConfig()->GetValue<string>("out-chan-name"); - mAckChannelName = GetConfig()->GetValue<string>("ack-chan-name"); -} - -void EPNReceiverDevice::PrintBuffer(const unordered_map<uint16_t, TFBuffer>& buffer) const -{ - string header = "===== "; - - for (int i = 1; i <= mNumFLPs; ++i) { - stringstream out; - out << i % 10; - header += out.str(); - //i > 9 ? header += " " : header += " "; - } - LOG(INFO) << header; - - for (auto& it : buffer) { - string stars = ""; - for (unsigned int j = 1; j <= (it.second).parts.Size(); ++j) { - stars += "*"; - } - LOG(INFO) << setw(4) << it.first << ": " << stars; - } -} - -void EPNReceiverDevice::DiscardIncompleteTimeframes() -{ - auto it = mTimeframeBuffer.begin(); - - while (it != mTimeframeBuffer.end()) { - if (duration_cast<milliseconds>(steady_clock::now() - (it->second).start).count() > mBufferTimeoutInMs) { - LOG(WARN) << "Timeframe #" << it->first << " incomplete after " << mBufferTimeoutInMs << " milliseconds, discarding"; - mDiscardedSet.insert(it->first); - mTimeframeBuffer.erase(it++); - LOG(WARN) << "Number of discarded timeframes: " << mDiscardedSet.size(); - } else { - // LOG(INFO) << "Timeframe #" << it->first << " within timeout, buffering..."; - ++it; - } - } -} - -void EPNReceiverDevice::Run() -{ - uint16_t id = 0; // holds the timeframe id of the currently arrived sub-timeframe. - - FairMQChannel& ackOutChannel = fChannels.at(mAckChannelName).at(0); - - // Simple multi timeframe index - using TimeframeId = int; - using FlpId = int; - std::multimap<TimeframeId, IndexElement> index; - std::multimap<TimeframeId, FlpId> flpIds; - - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - FairMQParts subtimeframeParts; - if (Receive(subtimeframeParts, mInChannelName, 0, 100) <= 0) { - continue; - } - - assert(subtimeframeParts.Size() >= 2); - - const auto* dh = o2::header::get<header::DataHeader*>(subtimeframeParts.At(0)->GetData()); - assert(strncmp(dh->dataDescription.str, "SUBTIMEFRAMEMD", 16) == 0); - SubframeMetadata* sfm = reinterpret_cast<SubframeMetadata*>(subtimeframeParts.At(1)->GetData()); - id = o2::data_flow::timeframeIdFromTimestamp(sfm->startTime, sfm->duration); - auto flpId = sfm->flpIndex; - - if (mDiscardedSet.find(id) == mDiscardedSet.end()) { - if (mTimeframeBuffer.find(id) == mTimeframeBuffer.end()) { - // if this is the first part with this ID, save the receive time. - mTimeframeBuffer[id].start = steady_clock::now(); - } - flpIds.insert(std::make_pair(id, flpId)); - LOG(INFO) << "Timeframe ID " << id << " for startTime " << sfm->startTime << "\n"; - // If the received ID has not previously been discarded, store - // the data part in the buffer For the moment we just concatenate - // the subtimeframes and add an index for their description at - // the end. Given every second part is a data header we skip - // every two parts to populate the index. Moreover we know that - // the SubframeMetadata is always in the second part, so we can - // extract the flpId from there. - for (size_t i = 0; i < subtimeframeParts.Size(); ++i) { - if (i % 2 == 0) { - const auto* adh = o2::header::get<header::DataHeader*>(subtimeframeParts.At(i)->GetData()); - auto ie = std::make_pair(*adh, index.count(id) * 2); - index.insert(std::make_pair(id, ie)); - } - mTimeframeBuffer[id].parts.AddPart(move(subtimeframeParts.At(i))); - } - } else { - // if received ID has been previously discarded. - LOG(WARN) << "Received part from an already discarded timeframe with id " << id; - } - - if (flpIds.count(id) == mNumFLPs) { - LOG(INFO) << "Timeframe " << id << " complete. Publishing.\n"; - o2::header::DataHeader tih; - std::vector<IndexElement> flattenedIndex; - - tih.dataDescription = o2::header::DataDescription("TIMEFRAMEINDEX"); - tih.dataOrigin = o2::header::DataOrigin("EPN"); - tih.subSpecification = 0; - tih.payloadSize = index.count(id) * sizeof(flattenedIndex.front()); - void* indexData = malloc(tih.payloadSize); - auto indexRange = index.equal_range(id); - for (auto ie = indexRange.first; ie != indexRange.second; ++ie) { - flattenedIndex.push_back(ie->second); - } - memcpy(indexData, flattenedIndex.data(), tih.payloadSize); - - mTimeframeBuffer[id].parts.AddPart(NewSimpleMessage(tih)); - mTimeframeBuffer[id].parts.AddPart(NewMessage( - indexData, tih.payloadSize, - [](void* data, void* hint) { free(data); }, nullptr)); - // LOG(INFO) << "Collected all parts for timeframe #" << id; - // when all parts are collected send then to the output channel - Send(mTimeframeBuffer[id].parts, mOutChannelName); - LOG(INFO) << "Index count for " << id << " " << index.count(id) << "\n"; - index.erase(id); - LOG(INFO) << "Index count for " << id << " " << index.count(id) << "\n"; - flpIds.erase(id); - - if (mTestMode > 0) { - // Send an acknowledgement back to the sampler to measure the round trip time - unique_ptr<FairMQMessage> ack(NewMessage(sizeof(uint16_t))); - memcpy(ack->GetData(), &id, sizeof(uint16_t)); - - if (ackOutChannel.Send(ack, 0) <= 0) { - LOG(ERROR) << "Could not send acknowledgement without blocking"; - } - } - - mTimeframeBuffer.erase(id); - } - - // LOG(WARN) << "Buffer size: " << fTimeframeBuffer.size(); - - // Check if any incomplete timeframes in the buffer are older than - // timeout period, and discard them if they are - // QUESTION: is this really what we want to do? - DiscardIncompleteTimeframes(); - } -} diff --git a/Utilities/DataFlow/src/FLPSenderDevice.cxx b/Utilities/DataFlow/src/FLPSenderDevice.cxx deleted file mode 100644 index cc37be574bb6d..0000000000000 --- a/Utilities/DataFlow/src/FLPSenderDevice.cxx +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <cstdint> -#include <cassert> - -#include <FairMQLogger.h> -#include <FairMQMessage.h> -#include <options/FairMQProgOptions.h> - -#include "Headers/DataHeader.h" -#include "Headers/SubframeMetadata.h" -#include "DataFlow/FLPSenderDevice.h" -#include "O2Device/Compatibility.h" - -using namespace std; -using namespace std::chrono; -using namespace o2::devices; -using SubframeMetadata = o2::data_flow::SubframeMetadata; - -void FLPSenderDevice::InitTask() -{ - mIndex = GetConfig()->GetValue<int>("flp-index"); - mEventSize = GetConfig()->GetValue<int>("event-size"); - mNumEPNs = GetConfig()->GetValue<int>("num-epns"); - mTestMode = GetConfig()->GetValue<int>("test-mode"); - mSendOffset = GetConfig()->GetValue<int>("send-offset"); - mSendDelay = GetConfig()->GetValue<int>("send-delay"); - mInChannelName = GetConfig()->GetValue<string>("in-chan-name"); - mOutChannelName = GetConfig()->GetValue<string>("out-chan-name"); -} - -void FLPSenderDevice::Run() -{ - // base buffer, to be copied from for every timeframe body (zero-copy) - FairMQMessagePtr baseMsg(NewMessage(mEventSize)); - - // store the channel reference to avoid traversing the map on every loop iteration - //FairMQChannel& dataInChannel = fChannels.at(fInChannelName).at(0); - - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - // - Get the SubtimeframeMetadata - // - Add the current FLP id to the SubtimeframeMetadata - // - Forward to the EPN the whole subtimeframe - FairMQParts subtimeframeParts; - if (Receive(subtimeframeParts, mInChannelName, 0, 100) <= 0) { - continue; - } - - assert(subtimeframeParts.Size() != 0); - assert(subtimeframeParts.Size() >= 2); - const auto* dh = o2::header::get<header::DataHeader*>(subtimeframeParts.At(0)->GetData()); - assert(strncmp(dh->dataDescription.str, "SUBTIMEFRAMEMD", 16) == 0); - - SubframeMetadata* sfm = reinterpret_cast<SubframeMetadata*>(subtimeframeParts.At(1)->GetData()); - sfm->flpIndex = mIndex; - - mArrivalTime.push(steady_clock::now()); - mSTFBuffer.push(move(subtimeframeParts)); - - // if offset is 0 - send data out without staggering. - assert(mSTFBuffer.size() > 0); - - if (mSendOffset == 0 && mSTFBuffer.size() > 0) { - sendFrontData(); - } else if (mSTFBuffer.size() > 0) { - if (duration_cast<milliseconds>(steady_clock::now() - mArrivalTime.front()).count() >= (mSendDelay * mSendOffset)) { - sendFrontData(); - } else { - // LOG(INFO) << "buffering..."; - } - } - } -} - -inline void FLPSenderDevice::sendFrontData() -{ - SubframeMetadata* sfm = static_cast<SubframeMetadata*>(mSTFBuffer.front().At(1)->GetData()); - uint16_t currentTimeframeId = o2::data_flow::timeframeIdFromTimestamp(sfm->startTime, sfm->duration); - if (mLastTimeframeId != -1) { - if (currentTimeframeId == mLastTimeframeId) { - LOG(ERROR) << "Sent same consecutive timeframe ids\n"; - } - } - mLastTimeframeId = currentTimeframeId; - - // for which EPN is the message? - int direction = currentTimeframeId % mNumEPNs; - if (Send(mSTFBuffer.front(), mOutChannelName, direction, 0) < 0) { - LOG(ERROR) << "Failed to queue sub-timeframe #" << currentTimeframeId << " to EPN[" << direction << "]"; - } - mSTFBuffer.pop(); - mArrivalTime.pop(); -} diff --git a/Utilities/DataFlow/src/FakeTimeframeBuilder.cxx b/Utilities/DataFlow/src/FakeTimeframeBuilder.cxx deleted file mode 100644 index 66bcc4fbcea08..0000000000000 --- a/Utilities/DataFlow/src/FakeTimeframeBuilder.cxx +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFlow/FakeTimeframeBuilder.h" -#include "TimeFrame/TimeFrame.h" -#include "Headers/DataHeader.h" -#include <string> -#include <vector> -#include <functional> -#include <cstring> - -using DataHeader = o2::header::DataHeader; -using DataDescription = o2::header::DataDescription; -using DataOrigin = o2::header::DataOrigin; -using IndexElement = o2::dataformats::IndexElement; - -namespace -{ -o2::header::DataDescription lookupDataDescription(const char* key) -{ - if (strcmp(key, "RAWDATA") == 0) { - return o2::header::gDataDescriptionRawData; - } else if (strcmp(key, "CLUSTERS") == 0) { - return o2::header::gDataDescriptionClusters; - } else if (strcmp(key, "TRACKS") == 0) { - return o2::header::gDataDescriptionTracks; - } else if (strcmp(key, "CONFIG") == 0) { - return o2::header::gDataDescriptionConfig; - } else if (strcmp(key, "INFO") == 0) { - return o2::header::gDataDescriptionInfo; - } - return o2::header::gDataDescriptionInvalid; -} - -o2::header::DataOrigin lookupDataOrigin(const char* key) -{ - if (strcmp(key, "TPC") == 0) { - return o2::header::gDataOriginTPC; - } - if (strcmp(key, "TRD") == 0) { - return o2::header::gDataOriginTRD; - } - if (strcmp(key, "TOF") == 0) { - return o2::header::gDataOriginTOF; - } - if (strcmp(key, "ITS") == 0) { - return o2::header::gDataOriginITS; - } - return o2::header::gDataOriginInvalid; -} - -} // namespace - -namespace o2 -{ -namespace data_flow -{ - -std::unique_ptr<char[]> fakeTimeframeGenerator(std::vector<FakeTimeframeSpec>& specs, std::size_t& totalSize) -{ - // Calculate the total size of your timeframe. This is - // given by: - // - N*The size of the data header (this should actually depend on the - // kind of data as different dataDescriptions will probably have - // different headers). - // - Sum_N(The size of the buffer_i) - // - The size of the index header - // - N*sizeof(dataheader) - // Assuming all the data header - size_t sizeOfHeaders = specs.size() * sizeof(DataHeader); - size_t sizeOfBuffers = 0; - for (auto&& spec : specs) { - sizeOfBuffers += spec.bufferSize; - } - size_t sizeOfIndexHeader = sizeof(DataHeader); - size_t sizeOfIndex = sizeof(IndexElement) * specs.size(); - totalSize = sizeOfHeaders + sizeOfBuffers + sizeOfIndexHeader + sizeOfIndex; - - // Add the actual - data - auto buffer = std::make_unique<char[]>(totalSize); - char* bi = buffer.get(); - std::vector<IndexElement> headers; - int count = 0; - for (auto&& spec : specs) { - IndexElement el; - el.first.dataDescription = lookupDataDescription(spec.dataDescription); - el.first.dataOrigin = lookupDataOrigin(spec.origin); - el.first.payloadSize = spec.bufferSize; - el.first.headerSize = sizeof(el.first); - el.second = count++; - // Let's zero at least the header... - memset(bi, 0, sizeof(el.first)); - memcpy(bi, &el, sizeof(el.first)); - headers.push_back(el); - bi += sizeof(el.first); - spec.bufferFiller(bi, spec.bufferSize); - bi += spec.bufferSize; - } - - // Add the index - DataHeader index; - index.dataDescription = DataDescription("TIMEFRAMEINDEX"); - index.dataOrigin = DataOrigin("FKE"); - index.headerSize = sizeOfIndexHeader; - index.payloadSize = sizeOfIndex; - memcpy(bi, &index, sizeof(index)); - memcpy(bi + sizeof(index), headers.data(), headers.size() * sizeof(IndexElement)); - return std::move(buffer); -} - -} // namespace data_flow -} // namespace o2 diff --git a/Utilities/DataFlow/src/FakeTimeframeGeneratorDevice.cxx b/Utilities/DataFlow/src/FakeTimeframeGeneratorDevice.cxx deleted file mode 100644 index 81c07bcc82f5c..0000000000000 --- a/Utilities/DataFlow/src/FakeTimeframeGeneratorDevice.cxx +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <cstring> - -#include "DataFlow/FakeTimeframeGeneratorDevice.h" -#include "DataFlow/FakeTimeframeBuilder.h" -#include "DataFlow/TimeframeParser.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/DataHeader.h" -#include <options/FairMQProgOptions.h> -#include <vector> - -using DataHeader = o2::header::DataHeader; - -namespace -{ -struct OneShotReadBuf : public std::streambuf { - OneShotReadBuf(char* s, std::size_t n) - { - setg(s, s, s + n); - } -}; -} // namespace -namespace o2 -{ -namespace data_flow -{ - -FakeTimeframeGeneratorDevice::FakeTimeframeGeneratorDevice() - : O2Device{}, mOutChannelName{}, mMaxTimeframes{}, mTimeframeCount{0} -{ -} - -void FakeTimeframeGeneratorDevice::InitTask() -{ - mOutChannelName = GetConfig()->GetValue<std::string>(OptionKeyOutputChannelName); - mMaxTimeframes = GetConfig()->GetValue<size_t>(OptionKeyMaxTimeframes); -} - -bool FakeTimeframeGeneratorDevice::ConditionalRun() -{ - auto addPartFn = [this](FairMQParts& parts, char* buffer, size_t size) { - parts.AddPart(this->NewMessage( - buffer, - size, - [](void* data, void* hint) { delete[](char*) data; }, - nullptr)); - }; - auto sendFn = [this](FairMQParts& parts) { this->Send(parts, this->mOutChannelName); }; - auto zeroFiller = [](char* b, size_t s) { memset(b, 0, s); }; - - std::vector<o2::data_flow::FakeTimeframeSpec> specs = { - {.origin = "TPC", - .dataDescription = "CLUSTERS", - .bufferFiller = zeroFiller, - .bufferSize = 1000}, - {.origin = "ITS", - .dataDescription = "CLUSTERS", - .bufferFiller = zeroFiller, - .bufferSize = 500}}; - - try { - size_t totalSize; - auto buffer = fakeTimeframeGenerator(specs, totalSize); - OneShotReadBuf osrb(buffer.get(), totalSize); - std::istream s(&osrb); - - streamTimeframe(s, - addPartFn, - sendFn); - } catch (std::runtime_error& e) { - LOG(ERROR) << e.what() << "\n"; - } - - mTimeframeCount++; - - if (mTimeframeCount < mMaxTimeframes) { - return true; - } - return false; -} - -} // namespace data_flow -} // namespace o2 diff --git a/Utilities/DataFlow/src/HeartbeatSampler.cxx b/Utilities/DataFlow/src/HeartbeatSampler.cxx deleted file mode 100644 index d960a5941d9c9..0000000000000 --- a/Utilities/DataFlow/src/HeartbeatSampler.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// @file HeartbeatSampler.h -// @author Matthias Richter -// @since 2017-02-03 -// @brief Heartbeat sampler device - -#include <thread> // this_thread::sleep_for -#include <chrono> - -#include "DataFlow/HeartbeatSampler.h" -#include "Headers/HeartbeatFrame.h" -#include <options/FairMQProgOptions.h> - -void o2::data_flow::HeartbeatSampler::InitTask() -{ - mPeriod = GetConfig()->GetValue<uint32_t>(OptionKeyPeriod); - mOutputChannelName = GetConfig()->GetValue<std::string>(OptionKeyOutputChannelName); -} - -bool o2::data_flow::HeartbeatSampler::ConditionalRun() -{ - std::this_thread::sleep_for(std::chrono::nanoseconds(mPeriod)); - - o2::header::HeartbeatStatistics hbfPayload; - - o2::header::DataHeader dh; - dh.dataDescription = o2::header::gDataDescriptionHeartbeatFrame; - dh.dataOrigin = o2::header::DataOrigin("SMPL"); - dh.subSpecification = 0; - dh.payloadSize = sizeof(hbfPayload); - - // Note: the block type of both header an trailer members of the envelope - // structure are autmatically initialized to the appropriate block type - // and size '1' (i.e. only one 64bit word) - o2::header::HeartbeatFrameEnvelope specificHeader; - specificHeader.header.orbit = mCount; - specificHeader.trailer.hbAccept = 1; - - O2Message outgoing; - - // build multipart message from header and payload - o2::base::addDataBlock(outgoing, {dh, specificHeader}, NewSimpleMessage(hbfPayload)); - - // send message - Send(outgoing, mOutputChannelName.c_str()); - outgoing.fParts.clear(); - - mCount++; - return true; -} diff --git a/Utilities/DataFlow/src/SubframeBuilderDevice.cxx b/Utilities/DataFlow/src/SubframeBuilderDevice.cxx deleted file mode 100644 index adad827e04a1f..0000000000000 --- a/Utilities/DataFlow/src/SubframeBuilderDevice.cxx +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file SubframeBuilderDevice.cxx -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-07 -/// @brief Demonstrator device for a subframe builder - -#include <thread> // this_thread::sleep_for -#include <chrono> -#include <functional> - -#include "DataFlow/SubframeBuilderDevice.h" -#include "DataFlow/SubframeUtils.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/HeartbeatFrame.h" -#include "Headers/DataHeader.h" -#include <options/FairMQProgOptions.h> - -using HeartbeatHeader = o2::header::HeartbeatHeader; -using HeartbeatTrailer = o2::header::HeartbeatTrailer; -using DataHeader = o2::header::DataHeader; -using SubframeId = o2::dataflow::SubframeId; - -o2::data_flow::SubframeBuilderDevice::SubframeBuilderDevice() - : O2Device() -{ -} - -o2::data_flow::SubframeBuilderDevice::~SubframeBuilderDevice() = default; - -void o2::data_flow::SubframeBuilderDevice::InitTask() -{ - mOrbitDuration = GetConfig()->GetValue<uint32_t>(OptionKeyOrbitDuration); - mOrbitsPerTimeframe = GetConfig()->GetValue<uint32_t>(OptionKeyOrbitsPerTimeframe); - mInputChannelName = GetConfig()->GetValue<std::string>(OptionKeyInputChannelName); - mOutputChannelName = GetConfig()->GetValue<std::string>(OptionKeyOutputChannelName); - mFLPId = GetConfig()->GetValue<size_t>(OptionKeyFLPId); - mStripHBF = GetConfig()->GetValue<bool>(OptionKeyStripHBF); - - LOG(INFO) << "Obtaining data from DataPublisher\n"; - // Now that we have all the information lets create the policies to do the - // payload extraction and merging and create the actual PayloadMerger. - - // We extract the timeframeId from the number of orbits. - // FIXME: handle multiple socket ids - Merger::IdExtractor makeId = [this](std::unique_ptr<FairMQMessage>& msg) -> SubframeId { - HeartbeatHeader* hbh = reinterpret_cast<HeartbeatHeader*>(msg->GetData()); - SubframeId id = {.timeframeId = hbh->orbit / this->mOrbitsPerTimeframe, - .socketId = 0}; - return id; - }; - - // We extract the payload differently depending on wether we want to strip - // the header or not. - Merger::PayloadExtractor payloadExtractor = [this](char** out, char* in, size_t inSize) -> size_t { - if (!this->mStripHBF) { - return Merger::fullPayloadExtractor(out, in, inSize); - } - return o2::dataflow::extractDetectorPayloadStrip(out, in, inSize); - }; - - // Whether a given timeframe is complete depends on how many orbits per - // timeframe we want. - Merger::MergeCompletionCheker checkIfComplete = - [this](Merger::MergeableId id, Merger::MessageMap& map) { - return map.count(id) < this->mOrbitsPerTimeframe; - }; - - mMerger.reset(new Merger(makeId, checkIfComplete, payloadExtractor)); - OnData(mInputChannelName.c_str(), &o2::data_flow::SubframeBuilderDevice::HandleData); -} - -bool o2::data_flow::SubframeBuilderDevice::BuildAndSendFrame(FairMQParts& inParts) -{ - auto id = mMerger->aggregate(inParts.At(1)); - - char** outBuffer; - size_t outSize = mMerger->finalise(outBuffer, id); - // In this case we do not have enough subtimeframes for id, - // so we simply return. - if (outSize == 0) { - return true; - } - // If we reach here, it means we do have enough subtimeframes. - - // top level subframe header, the DataHeader is going to be used with - // description "SUBTIMEFRAMEMD" - // this should be defined in a common place, and also the origin - // the origin can probably name a detector identifier, but not sure if - // all CRUs of a FLP in all cases serve a single detector - o2::header::DataHeader dh; - dh.dataDescription = o2::header::DataDescription("SUBTIMEFRAMEMD"); - dh.dataOrigin = o2::header::DataOrigin("FLP"); - dh.subSpecification = mFLPId; - dh.payloadSize = sizeof(SubframeMetadata); - - DataHeader payloadheader(*o2::header::get<DataHeader*>((byte*)inParts.At(0)->GetData())); - - // subframe meta information as payload - SubframeMetadata md; - // id is really the first orbit in the timeframe. - md.startTime = id.timeframeId * mOrbitsPerTimeframe * static_cast<uint64_t>(mOrbitDuration); - md.duration = mOrbitDuration * mOrbitsPerTimeframe; - LOG(INFO) << "Start time for subframe (" << md.startTime << ", " - << md.duration - << ")"; - - // Add the metadata about the merged subtimeframes - // FIXME: do we really need this? - O2Message outgoing; - o2::base::addDataBlock(outgoing, dh, NewSimpleMessage(md)); - - // Add the actual merged payload. - o2::base::addDataBlock(outgoing, payloadheader, - NewMessage( - *outBuffer, outSize, - [](void* data, void* hint) { delete[] reinterpret_cast<char*>(hint); }, *outBuffer)); - // send message - Send(outgoing, mOutputChannelName.c_str()); - // FIXME: do we actually need this? outgoing should go out of scope - outgoing.fParts.clear(); - - return true; -} - -bool o2::data_flow::SubframeBuilderDevice::HandleData(FairMQParts& msgParts, int /*index*/) -{ - // loop over header payload pairs in the incoming multimessage - // for each pair - // - check timestamp - // - create new subtimeframe if none existing where the timestamp of the data fits - // - add pair to the corresponding subtimeframe - - // check for completed subtimeframes and send all completed frames - // the builder does not implement the routing to the EPN, this is done in the - // specific FLP-EPN setup - // to fit into the simple emulation of event/frame ids in the flpSender the order of - // subtimeframes needs to be preserved - BuildAndSendFrame(msgParts); - return true; -} diff --git a/Utilities/DataFlow/src/TimeframeParser.cxx b/Utilities/DataFlow/src/TimeframeParser.cxx deleted file mode 100644 index 4e3cc4f2001b8..0000000000000 --- a/Utilities/DataFlow/src/TimeframeParser.cxx +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TimeframeValidatorDevice.cxx -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-07 -/// @brief Validator device for a full time frame - -#include <thread> // this_thread::sleep_for -#include <chrono> -#include <cstring> - -#include "DataFlow/TimeframeParser.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/DataHeader.h" -#include "TimeFrame/TimeFrame.h" - -#include <options/FairMQProgOptions.h> -#include <FairMQParts.h> - -using DataHeader = o2::header::DataHeader; -using DataDescription = o2::header::DataDescription; -using IndexElement = o2::dataformats::IndexElement; - -namespace o2 -{ -namespace data_flow -{ - -// Possible states for the parsing of a timeframe -// PARSE_BEGIN_STREAM -> -enum ParsingState { - PARSE_BEGIN_STREAM = 0, - PARSE_BEGIN_TIMEFRAME, - PARSE_BEGIN_PAIR, - PARSE_DATA_HEADER, - PARSE_CONCRETE_HEADER, - PARSE_PAYLOAD, - PARSE_END_PAIR, - PARSE_END_TIMEFRAME, - PARSE_END_STREAM, - ERROR -}; - -struct StreamingState { - StreamingState() = default; - - ParsingState state = PARSE_BEGIN_STREAM; - bool hasDataHeader = false; - bool hasConcreteHeader = false; - void* payloadBuffer = nullptr; - void* headerBuffer = nullptr; - DataHeader dh; // The current DataHeader being parsed -}; - -void streamTimeframe(std::istream& stream, - std::function<void(FairMQParts& parts, char* buffer, size_t size)> onAddPart, - std::function<void(FairMQParts& parts)> onSend) -{ - FairMQParts parts; - StreamingState state; - assert(state.state == PARSE_BEGIN_STREAM); - while (true) { - switch (state.state) { - case PARSE_BEGIN_STREAM: - LOG(INFO) << "In PARSE_BEGIN_STREAM\n"; - state.state = PARSE_BEGIN_TIMEFRAME; - break; - case PARSE_BEGIN_TIMEFRAME: - LOG(INFO) << "In PARSE_BEGIN_TIMEFRAME\n"; - state.state = PARSE_BEGIN_PAIR; - break; - case PARSE_BEGIN_PAIR: - LOG(INFO) << "In PARSE_BEGIN_PAIR\n"; - state.state = PARSE_DATA_HEADER; - state.hasDataHeader = false; - state.payloadBuffer = nullptr; - state.headerBuffer = nullptr; - break; - case PARSE_DATA_HEADER: - LOG(INFO) << "In PARSE_DATA_HEADER\n"; - if (state.hasDataHeader) { - throw std::runtime_error("DataHeader already present."); - } else if (state.payloadBuffer) { - throw std::runtime_error("Unexpected payload."); - } - LOG(INFO) << "Reading dataheader of " << sizeof(state.dh) << " bytes\n"; - stream.read(reinterpret_cast<char*>(&state.dh), sizeof(state.dh)); - // If we have a TIMEFRAMEINDEX part and we find the eof, we are done. - if (stream.eof()) { - throw std::runtime_error("Premature end of stream"); - } - - // Otherwise we move to the state which is responsible for parsing the - // kind of header. - state.state = PARSE_CONCRETE_HEADER; - break; - case PARSE_CONCRETE_HEADER: - LOG(INFO) << "In PARSE_CONCRETE_HEADER\n"; - if (state.headerBuffer) { - throw std::runtime_error("File has two consecutive headers"); - } - if (state.dh.headerSize < sizeof(DataHeader)) { - std::ostringstream str; - str << "Bad header size. Should be greater then " - << sizeof(DataHeader) - << ". Found " << state.dh.headerSize << "\n"; - throw std::runtime_error(str.str()); - } - // We get the full header size and read the rest of the header - state.headerBuffer = malloc(state.dh.headerSize); - memcpy(state.headerBuffer, &state.dh, sizeof(state.dh)); - LOG(INFO) << "Reading rest of the header of " << state.dh.headerSize - sizeof(state.dh) << " bytes\n"; - stream.read(reinterpret_cast<char*>(state.headerBuffer) + sizeof(state.dh), - state.dh.headerSize - sizeof(state.dh)); - // Handle the case the file was truncated. - if (stream.eof()) { - throw std::runtime_error("Unexpected end of file"); - } - onAddPart(parts, reinterpret_cast<char*>(state.headerBuffer), state.dh.headerSize); - // Move to parse the payload - state.state = PARSE_PAYLOAD; - break; - case PARSE_PAYLOAD: - LOG(INFO) << "In PARSE_PAYLOAD\n"; - if (state.payloadBuffer) { - throw std::runtime_error("File has two consecutive payloads"); - } - state.payloadBuffer = new char[state.dh.payloadSize]; - LOG(INFO) << "Reading payload of " << state.dh.payloadSize << " bytes\n"; - stream.read(reinterpret_cast<char*>(state.payloadBuffer), state.dh.payloadSize); - if (stream.eof()) { - throw std::runtime_error("Unexpected end of file"); - } - onAddPart(parts, reinterpret_cast<char*>(state.payloadBuffer), state.dh.payloadSize); - state.state = PARSE_END_PAIR; - break; - case PARSE_END_PAIR: - LOG(INFO) << "In PARSE_END_PAIR\n"; - state.state = state.dh == DataDescription("TIMEFRAMEINDEX") ? PARSE_END_TIMEFRAME : PARSE_BEGIN_PAIR; - break; - case PARSE_END_TIMEFRAME: - LOG(INFO) << "In PARSE_END_TIMEFRAME\n"; - onSend(parts); - // Check if we have more. If not, we can declare success. - stream.peek(); - if (stream.eof()) { - state.state = PARSE_END_STREAM; - } else { - state.state = PARSE_BEGIN_TIMEFRAME; - } - break; - case PARSE_END_STREAM: - return; - break; - default: - break; - } - } -} - -void streamTimeframe(std::ostream& stream, FairMQParts& parts) -{ - if (parts.Size() < 2) { - throw std::runtime_error("Expecting at least 2 parts\n"); - } - - auto indexHeader = o2::header::get<DataHeader*>(parts.At(parts.Size() - 2)->GetData()); - // FIXME: Provide iterator pair API for the index - // Index should really be something which provides an - // iterator pair API so that we can sort / find / lower_bound - // easily. Right now we simply use it a C-style array. - auto index = reinterpret_cast<IndexElement*>(parts.At(parts.Size() - 1)->GetData()); - - LOG(INFO) << "This time frame has " << parts.Size() << " parts.\n"; - auto indexEntries = indexHeader->payloadSize / sizeof(IndexElement); - if (indexHeader->dataDescription != DataDescription("TIMEFRAMEINDEX")) { - throw std::runtime_error("Could not find a valid index header\n"); - } - LOG(INFO) << indexHeader->dataDescription.str << "\n"; - LOG(INFO) << "This time frame has " << indexEntries << "entries in the index.\n"; - if ((indexEntries * 2 + 2) != (parts.Size())) { - std::stringstream err; - err << "Mismatched index and received parts. Expected " - << (parts.Size() - 2 * 2) << " found " << indexEntries; - throw std::runtime_error(err.str()); - } - - LOG(INFO) << "Everything is fine with received timeframe\n"; - for (size_t i = 0; i < parts.Size(); ++i) { - stream.write(reinterpret_cast<const char*>(parts.At(i)->GetData()), - parts.At(i)->GetSize()); - } -} - -} // namespace data_flow -} // namespace o2 diff --git a/Utilities/DataFlow/src/TimeframeReaderDevice.cxx b/Utilities/DataFlow/src/TimeframeReaderDevice.cxx deleted file mode 100644 index 5113838bb0a5a..0000000000000 --- a/Utilities/DataFlow/src/TimeframeReaderDevice.cxx +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include <cstring> - -#include "DataFlow/TimeframeReaderDevice.h" -#include "DataFlow/TimeframeParser.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/DataHeader.h" -#include <options/FairMQProgOptions.h> - -using DataHeader = o2::header::DataHeader; - -namespace o2 -{ -namespace data_flow -{ - -TimeframeReaderDevice::TimeframeReaderDevice() - : O2Device{}, mOutChannelName{}, mFile{} -{ -} - -void TimeframeReaderDevice::InitTask() -{ - mOutChannelName = GetConfig()->GetValue<std::string>(OptionKeyOutputChannelName); - mInFileName = GetConfig()->GetValue<std::string>(OptionKeyInputFileName); - mSeen.clear(); -} - -bool TimeframeReaderDevice::ConditionalRun() -{ - auto addPartFn = [this](FairMQParts& parts, char* buffer, size_t size) { - parts.AddPart(this->NewMessage( - buffer, - size, - [](void* data, void* hint) { delete[](char*) data; }, - nullptr)); - }; - auto sendFn = [this](FairMQParts& parts) { this->Send(parts, this->mOutChannelName); }; - - // FIXME: For the moment we support a single file. This should really be a glob. We - // should also have a strategy for watching directories. - std::vector<std::string> files; - files.push_back(mInFileName); - for (auto&& fn : files) { - mFile.open(fn, std::ofstream::in | std::ofstream::binary); - try { - streamTimeframe(mFile, - addPartFn, - sendFn); - } catch (std::runtime_error& e) { - LOG(ERROR) << e.what() << "\n"; - } - mSeen.push_back(fn); - } - - return false; -} - -} // namespace data_flow -} // namespace o2 diff --git a/Utilities/DataFlow/src/TimeframeValidationTool.cxx b/Utilities/DataFlow/src/TimeframeValidationTool.cxx deleted file mode 100644 index b3f1168006fc6..0000000000000 --- a/Utilities/DataFlow/src/TimeframeValidationTool.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFlow/TimeframeParser.h" -#include "fairmq/FairMQParts.h" -#include "Framework/Logger.h" -#include <vector> -#include <string> -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <unistd.h> -#include <fstream> - -// A simple tool which verifies timeframe files -int main(int argc, char** argv) -{ - int c; - opterr = 0; - - while ((c = getopt(argc, argv, "")) != -1) { - switch (c) { - case '?': - if (isprint(optopt)) { - fprintf(stderr, "Unknown option `-%c'.\n", optopt); - } else { - fprintf(stderr, - "Unknown option character `\\x%x'.\n", - optopt); - } - return 1; - default: - abort(); - } - } - - std::vector<std::string> filenames; - for (size_t index = optind; index < argc; index++) { - filenames.emplace_back(std::string(argv[index])); - } - - for (auto&& fn : filenames) { - LOG(INFO) << "Processing file" << fn << "\n"; - std::ifstream s(fn); - FairMQParts parts; - auto onAddParts = [](FairMQParts& p, char* buffer, size_t size) { - }; - auto onSend = [](FairMQParts& p) { - }; - - try { - o2::data_flow::streamTimeframe(s, onAddParts, onSend); - } catch (std::runtime_error& e) { - LOG(ERROR) << e.what() << std::endl; - exit(1); - } - } -} diff --git a/Utilities/DataFlow/src/TimeframeValidatorDevice.cxx b/Utilities/DataFlow/src/TimeframeValidatorDevice.cxx deleted file mode 100644 index 4f62bc621ef46..0000000000000 --- a/Utilities/DataFlow/src/TimeframeValidatorDevice.cxx +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TimeframeValidatorDevice.cxx -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-07 -/// @brief Validator device for a full time frame - -#include <thread> // this_thread::sleep_for -#include <chrono> - -#include "DataFlow/TimeframeValidatorDevice.h" -#include "TimeFrame/TimeFrame.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/DataHeader.h" -#include "O2Device/Compatibility.h" - -#include <options/FairMQProgOptions.h> - -using DataHeader = o2::header::DataHeader; -using DataOrigin = o2::header::DataOrigin; -using DataDescription = o2::header::DataDescription; -using IndexElement = o2::dataformats::IndexElement; - -o2::data_flow::TimeframeValidatorDevice::TimeframeValidatorDevice() - : O2Device(), mInChannelName() -{ -} - -void o2::data_flow::TimeframeValidatorDevice::InitTask() -{ - mInChannelName = GetConfig()->GetValue<std::string>(OptionKeyInputChannelName); -} - -void o2::data_flow::TimeframeValidatorDevice::Run() -{ - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - FairMQParts timeframeParts; - if (Receive(timeframeParts, mInChannelName, 0, 100) <= 0) { - continue; - } - - if (timeframeParts.Size() < 2) { - LOG(ERROR) << "Expecting at least 2 parts\n"; - } - - auto indexHeader = o2::header::get<header::DataHeader*>(timeframeParts.At(timeframeParts.Size() - 2)->GetData()); - // FIXME: Provide iterator pair API for the index - // Index should really be something which provides an - // iterator pair API so that we can sort / find / lower_bound - // easily. Right now we simply use it a C-style array. - auto index = reinterpret_cast<IndexElement*>(timeframeParts.At(timeframeParts.Size() - 1)->GetData()); - - // TODO: fill this with checks on time frame - LOG(INFO) << "This time frame has " << timeframeParts.Size() << " parts.\n"; - auto indexEntries = indexHeader->payloadSize / sizeof(DataHeader); - if (indexHeader->dataDescription != DataDescription("TIMEFRAMEINDEX")) { - LOG(ERROR) << "Could not find a valid index header\n"; - } - LOG(INFO) << indexHeader->dataDescription.str << "\n"; - LOG(INFO) << "This time frame has " << indexEntries << "entries in the index.\n"; - if ((indexEntries * 2 + 2) != (timeframeParts.Size())) { - LOG(ERROR) << "Mismatched index and received parts\n"; - } - - // - Use the index to find out if we have TPC data - // - Get the part with the TPC data - // - Validate TPCCluster dummy data - // - Validate ITSRaw dummy data - int tpcIndex = -1; - int itsIndex = -1; - - for (int ii = 0; ii < indexEntries; ++ii) { - IndexElement& ie = index[ii]; - assert(ie.second >= 0); - LOG(DEBUG) << ie.first.dataDescription.str << " " - << ie.first.dataOrigin.str << std::endl; - if ((ie.first.dataOrigin == header::gDataOriginTPC) && (ie.first.dataDescription == header::gDataDescriptionClusters)) { - tpcIndex = ie.second; - } - if ((ie.first.dataOrigin == header::gDataOriginITS) && (ie.first.dataDescription == header::gDataDescriptionClusters)) { - itsIndex = ie.second; - } - } - - if (tpcIndex < 0) { - LOG(ERROR) << "Could not find expected TPC payload\n"; - continue; - } - if (itsIndex < 0) { - LOG(ERROR) << "Could not find expected ITS payload\n"; - continue; - } - LOG(DEBUG) << "TPC Index " << tpcIndex << "\n"; - LOG(DEBUG) << "ITS Index " << itsIndex << "\n"; - - // Data header it at position - 1 - auto tpcHeader = reinterpret_cast<DataHeader*>(timeframeParts.At(tpcIndex)->GetData()); - if ((tpcHeader->dataDescription != header::gDataDescriptionClusters) || - (tpcHeader->dataOrigin != header::gDataOriginTPC)) { - LOG(ERROR) << "Wrong data description. Expecting TPC - CLUSTERS, found " - << tpcHeader->dataOrigin.str << " - " - << tpcHeader->dataDescription.str << "\n"; - continue; - } - auto tpcPayload = reinterpret_cast<TPCTestCluster*>(timeframeParts.At(tpcIndex + 1)->GetData()); - if (tpcHeader->payloadSize % sizeof(TPCTestCluster)) { - LOG(ERROR) << "TPC - CLUSTERS Size Mismatch\n"; - } - auto numOfClusters = tpcHeader->payloadSize / sizeof(TPCTestCluster); - for (size_t ci = 0; ci < numOfClusters; ++ci) { - TPCTestCluster& cluster = tpcPayload[ci]; - if (cluster.z != 1.5) { - LOG(ERROR) << "TPC Data mismatch. Expecting z = 1.5 got " << cluster.z << "\n"; - break; - } - if (cluster.timeStamp != ci) { - LOG(ERROR) << "TPC Data mismatch. Expecting " << ci << " got " << cluster.timeStamp << "\n"; - break; - } - } - - // Data header it at position - 1 - auto itsHeader = reinterpret_cast<DataHeader*>(timeframeParts.At(itsIndex)->GetData()); - if ((itsHeader->dataDescription != header::gDataDescriptionClusters) || (itsHeader->dataOrigin != header::gDataOriginITS)) { - LOG(ERROR) << "Wrong data description. Expecting ITS - CLUSTERS, found " - << itsHeader->dataOrigin.str << " - " << itsHeader->dataDescription.str << "\n"; - continue; - } - auto itsPayload = reinterpret_cast<ITSRawData*>(timeframeParts.At(itsIndex + 1)->GetData()); - if (itsHeader->payloadSize % sizeof(ITSRawData)) { - LOG(ERROR) << "ITS - CLUSTERS Size Mismatch.\n"; - } - numOfClusters = itsHeader->payloadSize / sizeof(ITSRawData); - for (size_t ci = 0; ci < numOfClusters; ++ci) { - ITSRawData& cluster = itsPayload[ci]; - if (cluster.timeStamp != ci) { - LOG(ERROR) << "ITS Data mismatch. Expecting " << ci - << " got " << cluster.timeStamp << "\n"; - break; - } - } - LOG(INFO) << "Everything is fine with received timeframe\n"; - } -} diff --git a/Utilities/DataFlow/src/TimeframeWriterDevice.cxx b/Utilities/DataFlow/src/TimeframeWriterDevice.cxx deleted file mode 100644 index 151ac59424880..0000000000000 --- a/Utilities/DataFlow/src/TimeframeWriterDevice.cxx +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file TimeframeValidatorDevice.cxx -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-07 -/// @brief Validator device for a full time frame - -#include <thread> // this_thread::sleep_for -#include <chrono> - -#include "DataFlow/TimeframeWriterDevice.h" -#include "DataFlow/TimeframeParser.h" -#include "TimeFrame/TimeFrame.h" -#include "Headers/SubframeMetadata.h" -#include "Headers/DataHeader.h" -#include "O2Device/Compatibility.h" - -#include <options/FairMQProgOptions.h> -#include <boost/filesystem.hpp> - -using DataHeader = o2::header::DataHeader; -using IndexElement = o2::dataformats::IndexElement; - -namespace o2 -{ -namespace data_flow -{ - -TimeframeWriterDevice::TimeframeWriterDevice() - : O2Device{}, mInChannelName{}, mFile{}, mMaxTimeframes{}, mMaxFileSize{}, mMaxFiles{}, mFileCount{0} -{ -} - -void TimeframeWriterDevice::InitTask() -{ - mInChannelName = GetConfig()->GetValue<std::string>(OptionKeyInputChannelName); - mOutFileName = GetConfig()->GetValue<std::string>(OptionKeyOutputFileName); - mMaxTimeframes = GetConfig()->GetValue<size_t>(OptionKeyMaxTimeframesPerFile); - mMaxFileSize = GetConfig()->GetValue<size_t>(OptionKeyMaxFileSize); - mMaxFiles = GetConfig()->GetValue<size_t>(OptionKeyMaxFiles); -} - -void TimeframeWriterDevice::Run() -{ - boost::filesystem::path p(mOutFileName); - size_t streamedTimeframes = 0; - bool needsNewFile = true; - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this) && mFileCount < mMaxFiles) { - // In case we need to process more than one file, - // the filename is split in basename and extension - // and we call the files `<basename><count>.<extension>`. - if (needsNewFile) { - std::string filename = mOutFileName; - if (mMaxFiles > 1) { - std::string base_path(mOutFileName, 0, mOutFileName.find_last_of(".")); - std::string extension(mOutFileName, mOutFileName.find_last_of(".")); - filename = base_path + std::to_string(mFileCount) + extension; - } - LOG(INFO) << "Opening " << filename << " for output\n"; - mFile.open(filename.c_str(), std::ofstream::out | std::ofstream::binary); - needsNewFile = false; - } - - FairMQParts timeframeParts; - if (Receive(timeframeParts, mInChannelName, 0, 100) <= 0) { - continue; - } - - streamTimeframe(mFile, timeframeParts); - if ((mFile.tellp() > mMaxFileSize) || (streamedTimeframes++ > mMaxTimeframes)) { - mFile.flush(); - mFile.close(); - mFileCount++; - needsNewFile = true; - } - } -} - -void TimeframeWriterDevice::PostRun() -{ - if (mFile.is_open()) { - mFile.flush(); - mFile.close(); - } -} - -} // namespace data_flow -} // namespace o2 diff --git a/Utilities/DataFlow/src/runEPNReceiver.cxx b/Utilities/DataFlow/src/runEPNReceiver.cxx deleted file mode 100644 index b4681116052df..0000000000000 --- a/Utilities/DataFlow/src/runEPNReceiver.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/** - * runEPNReceiver.cxx - * - * @since 2013-01-21 - * @author D. Klein, A. Rybalchenko, M. Al-Turany, C. Kouzinopoulos - */ - -#include "runFairMQDevice.h" -#include "DataFlow/EPNReceiverDevice.h" - -#include <string> - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - ("buffer-timeout", bpo::value<int>()->default_value(1000), "Buffer timeout in milliseconds") - ("num-flps", bpo::value<int>()->required(), "Number of FLPs") - ("test-mode", bpo::value<int>()->default_value(0), "Run in test mode") - ("in-chan-name", bpo::value<std::string>()->default_value("stf2"), "Name of the input channel (sub-time frames)") - ("out-chan-name", bpo::value<std::string>()->default_value("tf"), "Name of the output channel (time frames)") - ("ack-chan-name", bpo::value<std::string>()->default_value("ack"), "Name of the acknowledgement channel"); - // clang-format on -} - -FairMQDevice* getDevice(const FairMQProgOptions& config) -{ - return new o2::devices::EPNReceiverDevice(); -} diff --git a/Utilities/DataFlow/src/runFLPSender.cxx b/Utilities/DataFlow/src/runFLPSender.cxx deleted file mode 100644 index ed2b94d648954..0000000000000 --- a/Utilities/DataFlow/src/runFLPSender.cxx +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/FLPSenderDevice.h" - -#include <string> - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - ("flp-index", bpo::value<int>()->default_value(0), "FLP Index (for debugging in test mode)") - ("event-size", bpo::value<int>()->default_value(1000), "Event size in bytes (test mode)") - ("num-epns", bpo::value<int>()->required(), "Number of EPNs") - ("test-mode", bpo::value<int>()->default_value(0), "Run in test mode") - ("send-offset", bpo::value<int>()->default_value(0), "Offset for staggered sending") - ("send-delay", bpo::value<int>()->default_value(8), "Delay for staggered sending") - ("in-chan-name", bpo::value<std::string>()->default_value("stf1"), "Name of the input channel (sub-time frames)") - ("out-chan-name", bpo::value<std::string>()->default_value("stf2"), "Name of the output channel (sub-time frames)"); - // clang-format on -} - -FairMQDevice* getDevice(const FairMQProgOptions& config) -{ - return new o2::devices::FLPSenderDevice(); -} diff --git a/Utilities/DataFlow/src/runFakeTimeframeGeneratorDevice.cxx b/Utilities/DataFlow/src/runFakeTimeframeGeneratorDevice.cxx deleted file mode 100644 index 755cf2b8f111f..0000000000000 --- a/Utilities/DataFlow/src/runFakeTimeframeGeneratorDevice.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/FakeTimeframeGeneratorDevice.h" -#include <vector> - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::FakeTimeframeGeneratorDevice::OptionKeyOutputChannelName, - bpo::value<std::string>()->default_value("output"), - "Name of the output channel"); - options.add_options() - (o2::data_flow::FakeTimeframeGeneratorDevice::OptionKeyMaxTimeframes, - bpo::value<std::string>()->default_value("1"), - "Number of timeframes to generate"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::FakeTimeframeGeneratorDevice(); -} diff --git a/Utilities/DataFlow/src/runHeartbeatSampler.cxx b/Utilities/DataFlow/src/runHeartbeatSampler.cxx deleted file mode 100644 index e5fcd7b12c6b2..0000000000000 --- a/Utilities/DataFlow/src/runHeartbeatSampler.cxx +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/HeartbeatSampler.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::HeartbeatSampler::OptionKeyPeriod, - bpo::value<uint32_t>()->default_value(1000000000), - "sampling period") - (o2::data_flow::HeartbeatSampler::OptionKeyOutputChannelName, - bpo::value<std::string>()->default_value("output"), - "Name of the output channel"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::HeartbeatSampler(); -} diff --git a/Utilities/DataFlow/src/runSubframeBuilderDevice.cxx b/Utilities/DataFlow/src/runSubframeBuilderDevice.cxx deleted file mode 100644 index 1c26bf66d6e5f..0000000000000 --- a/Utilities/DataFlow/src/runSubframeBuilderDevice.cxx +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/SubframeBuilderDevice.h" - -namespace bpo = boost::program_options; - -constexpr uint32_t o2::data_flow::SubframeBuilderDevice::DefaultOrbitDuration; -constexpr uint32_t o2::data_flow::SubframeBuilderDevice::DefaultOrbitsPerTimeframe; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::SubframeBuilderDevice::OptionKeyOrbitDuration, - bpo::value<uint32_t>()->default_value(o2::data_flow::SubframeBuilderDevice::DefaultOrbitDuration), - "Orbit duration") - (o2::data_flow::SubframeBuilderDevice::OptionKeyOrbitsPerTimeframe, - bpo::value<uint32_t>()->default_value(o2::data_flow::SubframeBuilderDevice::DefaultOrbitsPerTimeframe), - "Orbits per timeframe") - (o2::data_flow::SubframeBuilderDevice::OptionKeyInputChannelName, - bpo::value<std::string>()->default_value("input"), - "Name of the input channel") - (o2::data_flow::SubframeBuilderDevice::OptionKeyOutputChannelName, - bpo::value<std::string>()->default_value("output"), - "Name of the output channel") - (o2::data_flow::SubframeBuilderDevice::OptionKeyDetector, - bpo::value<std::string>()->default_value("TPC"), - "Name of detector as data source") - (o2::data_flow::SubframeBuilderDevice::OptionKeyFLPId, - bpo::value<size_t>()->default_value(0), - "ID of the FLP used as data source") - (o2::data_flow::SubframeBuilderDevice::OptionKeyStripHBF, - bpo::bool_switch()->default_value(false), - "Strip HBH & HBT from each HBF"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::SubframeBuilderDevice(); -} diff --git a/Utilities/DataFlow/src/runTimeframeReaderDevice.cxx b/Utilities/DataFlow/src/runTimeframeReaderDevice.cxx deleted file mode 100644 index 57574a0dd7811..0000000000000 --- a/Utilities/DataFlow/src/runTimeframeReaderDevice.cxx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/TimeframeReaderDevice.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::TimeframeReaderDevice::OptionKeyOutputChannelName, - bpo::value<std::string>()->default_value("output"), - "Name of the output channel"); - options.add_options() - (o2::data_flow::TimeframeReaderDevice::OptionKeyInputFileName, - bpo::value<std::string>()->default_value("data.o2tf"), - "Name of the input file"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::TimeframeReaderDevice(); -} diff --git a/Utilities/DataFlow/src/runTimeframeValidatorDevice.cxx b/Utilities/DataFlow/src/runTimeframeValidatorDevice.cxx deleted file mode 100644 index 34b5e90d46e69..0000000000000 --- a/Utilities/DataFlow/src/runTimeframeValidatorDevice.cxx +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/TimeframeValidatorDevice.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::TimeframeValidatorDevice::OptionKeyInputChannelName, - bpo::value<std::string>()->default_value("input"), - "Name of the input channel"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::TimeframeValidatorDevice(); -} diff --git a/Utilities/DataFlow/src/runTimeframeWriterDevice.cxx b/Utilities/DataFlow/src/runTimeframeWriterDevice.cxx deleted file mode 100644 index 112c0cb3f8be1..0000000000000 --- a/Utilities/DataFlow/src/runTimeframeWriterDevice.cxx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "DataFlow/TimeframeWriterDevice.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (o2::data_flow::TimeframeWriterDevice::OptionKeyInputChannelName, - bpo::value<std::string>()->default_value("input"), - "Name of the input channel"); - options.add_options() - (o2::data_flow::TimeframeWriterDevice::OptionKeyOutputFileName, - bpo::value<std::string>()->default_value("data.o2tf"), - "Name of the input channel"); - options.add_options() - (o2::data_flow::TimeframeWriterDevice::OptionKeyMaxFiles, - bpo::value<size_t>()->default_value(1), - "Maximum number of files to write"); - options.add_options() - (o2::data_flow::TimeframeWriterDevice::OptionKeyMaxTimeframesPerFile, - bpo::value<size_t>()->default_value(1), - "Maximum number of timeframes per file"); - options.add_options() - (o2::data_flow::TimeframeWriterDevice::OptionKeyMaxFileSize, - bpo::value<size_t>()->default_value(-1), - "Maximum size per file"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::data_flow::TimeframeWriterDevice(); -} diff --git a/Utilities/DataFlow/test/test_PayloadMerger01.cxx b/Utilities/DataFlow/test/test_PayloadMerger01.cxx deleted file mode 100644 index 40cc1e252a84c..0000000000000 --- a/Utilities/DataFlow/test/test_PayloadMerger01.cxx +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#define BOOST_TEST_MODULE Test Utilities DataFlowTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -#include <boost/test/unit_test.hpp> - -#include <iostream> -#include <memory> -#include "DataFlow/PayloadMerger.h" -#include "DataFlow/FakeTimeframeBuilder.h" -#include "DataFlow/TimeframeParser.h" -#include "DataFlow/SubframeUtils.h" -#include "fairmq/FairMQTransportFactory.h" -#include "fairmq/FairMQParts.h" - -using SubframeId = o2::dataflow::SubframeId; -using HeartbeatHeader = o2::header::HeartbeatHeader; -using HeartbeatTrailer = o2::header::HeartbeatTrailer; - -SubframeId fakeAddition(o2::dataflow::PayloadMerger<SubframeId>& merger, - std::shared_ptr<FairMQTransportFactory>& transport, - int64_t orbit) -{ - // Create a message - // - // We set orbit to be always the same and the actual contents to be 127 - static size_t dummyMessageSize = 1000; - auto msg = transport->CreateMessage(dummyMessageSize); - char* b = reinterpret_cast<char*>(msg->GetData()) + sizeof(HeartbeatHeader); - for (size_t i = 0; i < (dummyMessageSize - sizeof(HeartbeatHeader)); ++i) { - b[i] = orbit; - } - b[0] = 127; - HeartbeatHeader* header = reinterpret_cast<HeartbeatHeader*>(msg->GetData()); - header->orbit = orbit; - return merger.aggregate(msg); -} - -BOOST_AUTO_TEST_CASE(PayloadMergerTest) -{ - auto zmq = FairMQTransportFactory::CreateTransportFactory("zeromq"); - - // Needs three subtimeframes to merge them - auto checkIfComplete = [](SubframeId id, o2::dataflow::PayloadMerger<SubframeId>::MessageMap& m) -> bool { - return m.count(id) >= 3; - }; - - // Id is given by the orbit, 2 orbits per timeframe - auto makeId = [](std::unique_ptr<FairMQMessage>& msg) { - auto header = reinterpret_cast<o2::header::HeartbeatHeader const*>(msg->GetData()); - return o2::dataflow::makeIdFromHeartbeatHeader(*header, 0, 2); - }; - - o2::dataflow::PayloadMerger<SubframeId> merger(makeId, checkIfComplete, o2::dataflow::extractDetectorPayloadStrip); - char* finalBuf = new char[3000]; - size_t finalSize = 0; - auto id = fakeAddition(merger, zmq, 1); - finalSize = merger.finalise(&finalBuf, id); - BOOST_CHECK(finalSize == 0); // Not enough parts, not merging yet. - id = fakeAddition(merger, zmq, 1); - finalSize = merger.finalise(&finalBuf, id); - BOOST_CHECK(finalSize == 0); // Not enough parts, not merging yet. - id = fakeAddition(merger, zmq, 2); - finalSize = merger.finalise(&finalBuf, id); - BOOST_CHECK(finalSize == 0); // Different ID, not merging yet. - id = fakeAddition(merger, zmq, 1); - finalSize = merger.finalise(&finalBuf, id); - BOOST_CHECK(finalSize); // Now we merge! - size_t partSize = (1000 - sizeof(HeartbeatHeader) - sizeof(HeartbeatTrailer)); - BOOST_CHECK(finalSize == 3 * partSize); // This should be the calculated size - for (size_t i = 0; i < finalSize; ++i) { - BOOST_CHECK(finalBuf[i] == ((i % partSize) == 0 ? 127 : 1)); - } -} diff --git a/Utilities/DataFlow/test/test_SubframeUtils01.cxx b/Utilities/DataFlow/test/test_SubframeUtils01.cxx deleted file mode 100644 index 32605f9075808..0000000000000 --- a/Utilities/DataFlow/test/test_SubframeUtils01.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test Utilities DataFlowTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -#include "DataFlow/SubframeUtils.h" -#include <boost/test/unit_test.hpp> -#include <iostream> - -BOOST_AUTO_TEST_CASE(SubframeUtils01) -{ - o2::dataflow::SubframeId a; - a.timeframeId = 0; - a.socketId = 1; - o2::dataflow::SubframeId b; - b.timeframeId = 1; - b.socketId = 0; - BOOST_CHECK(a < b); - char* buf = new char[1000]; - memset(buf, 126, 1000); - for (size_t i = sizeof(o2::header::HeartbeatHeader); i < 1000 - sizeof(o2::header::HeartbeatHeader); ++i) { - buf[i] = 0; - } - BOOST_CHECK(buf[0] == 126); - BOOST_CHECK(buf[sizeof(o2::header::HeartbeatHeader)] == 0); - BOOST_CHECK(buf[sizeof(o2::header::HeartbeatHeader) - 1] == 126); - char* realPayload = nullptr; - size_t realSize = o2::dataflow::extractDetectorPayloadStrip(&realPayload, buf, 1000); - BOOST_CHECK(realPayload != nullptr); - BOOST_CHECK(realSize == 1000 - sizeof(o2::header::HeartbeatHeader) - sizeof(o2::header::HeartbeatTrailer)); - BOOST_CHECK(realPayload == buf + sizeof(o2::header::HeartbeatHeader)); - BOOST_CHECK(realPayload[0] == 0); - - o2::header::HeartbeatHeader header1; - header1.orbit = 0; - o2::header::HeartbeatHeader header2; - header2.orbit = 255; - o2::header::HeartbeatHeader header3; - header3.orbit = 256; - - auto id1 = o2::dataflow::makeIdFromHeartbeatHeader(header1, 1, 256); - auto id2 = o2::dataflow::makeIdFromHeartbeatHeader(header2, 1, 256); - auto id3 = o2::dataflow::makeIdFromHeartbeatHeader(header3, 1, 256); - BOOST_CHECK(!(id1 < id2)); // Maybe we should provide an == operator - BOOST_CHECK(!(id2 < id1)); - BOOST_CHECK(id1 < id3); - BOOST_CHECK(id2 < id3); - BOOST_CHECK(id1.timeframeId == 0); - BOOST_CHECK(id3.timeframeId == 1); -} diff --git a/Utilities/DataFlow/test/test_TimeframeParser.cxx b/Utilities/DataFlow/test/test_TimeframeParser.cxx deleted file mode 100644 index 37e6f5af09c36..0000000000000 --- a/Utilities/DataFlow/test/test_TimeframeParser.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFlow/TimeframeParser.h" -#include "DataFlow/FakeTimeframeBuilder.h" -#include "Headers/DataHeader.h" -#include "Framework/Logger.h" -#include <FairMQParts.h> -#include <istream> -#include <cstdlib> - -struct OneShotReadBuf : public std::streambuf { - OneShotReadBuf(char* s, std::size_t n) - { - setg(s, s, s + n); - } -}; - -using DataHeader = o2::header::DataHeader; - -int main(int argc, char** argv) -{ - // Construct a dummy timeframe. - // Stream it and get the parts - FairMQParts parts; - auto onAddParts = [](FairMQParts& p, char* buffer, size_t size) { - LOG(INFO) << "Adding part to those to be sent.\n"; - }; - auto onSend = [](FairMQParts& p) { - LOG(INFO) << "Everything OK. Sending parts\n"; - }; - - // Prepare a test timeframe to be streamed - auto zeroFiller = [](char* b, size_t s) { memset(b, 0, s); }; - std::vector<o2::data_flow::FakeTimeframeSpec> specs = { - {.origin = "TPC", - .dataDescription = "CLUSTERS", - .bufferFiller = zeroFiller, - .bufferSize = 1000}}; - - size_t testBufferSize; - auto testBuffer = fakeTimeframeGenerator(specs, testBufferSize); - - OneShotReadBuf osrb(testBuffer.get(), testBufferSize); - std::istream s(&osrb); - - try { - o2::data_flow::streamTimeframe(s, onAddParts, onSend); - } catch (std::runtime_error& e) { - LOG(ERROR) << e.what() << std::endl; - exit(1); - } -} diff --git a/Utilities/DataSampling/CMakeLists.txt b/Utilities/DataSampling/CMakeLists.txt index 549f87122175f..584dbce9a4235 100644 --- a/Utilities/DataSampling/CMakeLists.txt +++ b/Utilities/DataSampling/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # FIXME: the LinkDef should not be in the public area @@ -23,7 +24,7 @@ o2_add_library(DataSampling src/DataSamplingReadoutAdapter.cxx src/Dispatcher.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) + PUBLIC_LINK_LIBRARIES O2::Framework) #o2_target_root_dictionary( # Mergers @@ -61,27 +62,27 @@ endforeach() o2_data_file(COPY etc/exampleDataSamplingConfig.json DESTINATION etc) -o2_add_dpl_workflow(standalone +o2_add_executable(standalone SOURCES src/dataSamplingStandalone.cxx COMPONENT_NAME DataSampling - PUBLIC_LINK_LIBRARIES O2::DataSampling) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) -o2_add_dpl_workflow(datasampling-pod-and-root +o2_add_executable(datasampling-pod-and-root SOURCES test/dataSamplingPodAndRoot.cxx COMPONENT_NAME DataSampling - PUBLIC_LINK_LIBRARIES O2::DataSampling) +PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) -o2_add_dpl_workflow(datasampling-parallel +o2_add_executable(datasampling-parallel SOURCES test/dataSamplingParallel.cxx COMPONENT_NAME DataSampling - PUBLIC_LINK_LIBRARIES O2::DataSampling) +PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) -o2_add_dpl_workflow(datasampling-time-pipeline +o2_add_executable(datasampling-time-pipeline SOURCES test/dataSamplingTimePipeline.cxx COMPONENT_NAME DataSampling - PUBLIC_LINK_LIBRARIES O2::DataSampling) + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) -o2_add_dpl_workflow(datasampling-benchmark +o2_add_executable(datasampling-benchmark SOURCES test/dataSamplingBenchmark.cxx COMPONENT_NAME DataSampling - PUBLIC_LINK_LIBRARIES O2::DataSampling) \ No newline at end of file + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataSampling) diff --git a/Utilities/DataSampling/README.md b/Utilities/DataSampling/README.md index b417f83beee2c..88a7a6ea800e6 100644 --- a/Utilities/DataSampling/README.md +++ b/Utilities/DataSampling/README.md @@ -1,3 +1,7 @@ +<!-- doxy +\page refUtilitiesDataSampling Data Sampling +/doxy --> + ## Data Sampling Data Sampling provides a possibility to sample data in DPL workflows based on certain conditions ( 5% randomly, when a payload is greater than 4234 bytes, etc.). The job of passing the right data is done by a data processor called `Dispatcher`. A desired data stream is specified in form of Data Sampling Policies, configured by JSON structures (example below) or by using dedicated interface methods (for advanced use). @@ -68,7 +72,7 @@ The [o2-datasampling-pod-and-root](https://github.com/AliceO2Group/AliceO2/blob/ ## Data Sampling Conditions The following sampling conditions are available. When more than one is used, a positive decision is taken when all the conditions are fulfilled. -- **DataSamplingConditionRandom** - pseudo-randomly accepts specified fraction of incoming messages. +- **DataSamplingConditionRandom** - pseudo-randomly accepts specified fraction of incoming messages. Use seed "0" to have it randomly selected. ```json { "condition": "random", diff --git a/Utilities/DataSampling/include/DataSampling/DataSampling.h b/Utilities/DataSampling/include/DataSampling/DataSampling.h index 6ef4f9a0ca2d4..83503a41b4320 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSampling.h +++ b/Utilities/DataSampling/include/DataSampling/DataSampling.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,6 +21,7 @@ #include "Framework/InputSpec.h" #include <string> #include <boost/property_tree/ptree_fwd.hpp> +#include <optional> namespace o2::configuration { @@ -79,40 +81,33 @@ class DataSampling /// QC tasks. /// \param policiesSource Path to configuration file. /// \param threads Number of dispatcher threads, that will handle the data - static void GenerateInfrastructure(framework::WorkflowSpec& workflow, const std::string& policiesSource, size_t threads = 1); + /// \param host Host name. If the host or a policy machine list are empty, the policy will always be created. + static void GenerateInfrastructure(framework::WorkflowSpec& workflow, const std::string& policiesSource, size_t threads = 1, const std::string& host = ""); /// \brief Generates data sampling infrastructure. /// \param workflow DPL workflow with already declared data processors which provide data desired by /// QC tasks. /// \param policiesSource boost::property_tree::ptree with the configuration /// \param threads Number of dispatcher threads, that will handle the data - static void GenerateInfrastructure(framework::WorkflowSpec& workflow, boost::property_tree::ptree const& policies, size_t threads = 1); + /// \param host Host name. If the host or a policy machine list are empty, the policy will always be created. + static void GenerateInfrastructure(framework::WorkflowSpec& workflow, boost::property_tree::ptree const& policies, size_t threads = 1, const std::string& host = ""); /// \brief Configures dispatcher to consume any data immediately. static void CustomizeInfrastructure(std::vector<framework::CompletionPolicy>&); /// \brief Applies blocking/nonblocking data sampling configuration to the workflow. static void CustomizeInfrastructure(std::vector<framework::ChannelConfigurationPolicy>&); - /// \brief Provides InputSpecs to receive data for given DataSamplingPolicy - static std::vector<framework::InputSpec> InputSpecsForPolicy(const std::string& policiesSource, const std::string& policyName); - /// \brief Provides InputSpecs to receive data for given DataSamplingPolicy - /// @deprecated - static std::vector<framework::InputSpec> InputSpecsForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName); - /// \brief Provides InputSpecs to receive data for given DataSamplingPolicy - static std::vector<framework::InputSpec> InputSpecsForPolicy(std::shared_ptr<configuration::ConfigurationInterface> config, const std::string& policyName); - /// \brief Provides OutputSpecs of given DataSamplingPolicy - static std::vector<framework::OutputSpec> OutputSpecsForPolicy(const std::string& policiesSource, const std::string& policyName); - /// \brief Provides OutputSpecs of given DataSamplingPolicy - static std::vector<framework::OutputSpec> OutputSpecsForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName); - /// \brief Provides the port to be used for a proxy of given DataSamplingPolicy - static uint16_t PortForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName); - /// \brief Provides the port to be used for a proxy of given DataSamplingPolicy - static uint16_t PortForPolicy(const std::string& policiesSource, const std::string& policyName); - /// \brief Provides the machines where given DataSamplingPolicy is enabled - static std::vector<std::string> MachinesForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName); - /// \brief Provides the port to be used for a proxy of given DataSamplingPolicy - static std::vector<std::string> MachinesForPolicy(const std::string& policiesSource, const std::string& policyName); + /// \brief Provides InputSpecs to receive data for given DataSamplingPolicy. Expects the "dataSamplingPolicies" tree. + static std::vector<framework::InputSpec> InputSpecsForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName); + /// \brief Provides OutputSpecs of given DataSamplingPolicy. Expects the "dataSamplingPolicies" tree. + static std::vector<framework::OutputSpec> OutputSpecsForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName); + /// \brief Provides the port to be used for a proxy of given DataSamplingPolicy. Expects the "dataSamplingPolicies" tree. + static std::optional<uint16_t> PortForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName); + /// \brief Provides the machines where given DataSamplingPolicy is enabled. Expects the "dataSamplingPolicies" tree. + static std::vector<std::string> MachinesForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName); + /// \brief Says if remote part (e.g. QC server) should bind the inter-machine channel, according to the configuration. Expects the "dataSamplingPolicies" tree. + static std::string BindLocationForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName); private: - static void DoGenerateInfrastructure(Dispatcher&, framework::WorkflowSpec& workflow, boost::property_tree::ptree const& policies, size_t threads = 1); + static void DoGenerateInfrastructure(Dispatcher&, framework::WorkflowSpec& workflow, boost::property_tree::ptree const& policies, size_t threads = 1, const std::string& host = ""); // Internal functions, used by GenerateInfrastructure() static std::string createDispatcherName(); }; diff --git a/Utilities/DataSampling/include/DataSampling/DataSamplingCondition.h b/Utilities/DataSampling/include/DataSampling/DataSamplingCondition.h index 754f9049a1561..09c2f35c73580 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSamplingCondition.h +++ b/Utilities/DataSampling/include/DataSampling/DataSamplingCondition.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/include/DataSampling/DataSamplingConditionFactory.h b/Utilities/DataSampling/include/DataSampling/DataSamplingConditionFactory.h index fb62efa80e89f..32bfc5ffdd1fb 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSamplingConditionFactory.h +++ b/Utilities/DataSampling/include/DataSampling/DataSamplingConditionFactory.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/include/DataSampling/DataSamplingHeader.h b/Utilities/DataSampling/include/DataSampling/DataSamplingHeader.h index 03856ccec2348..adc2c97759f52 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSamplingHeader.h +++ b/Utilities/DataSampling/include/DataSampling/DataSamplingHeader.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/include/DataSampling/DataSamplingPolicy.h b/Utilities/DataSampling/include/DataSampling/DataSamplingPolicy.h index 3330aea33686b..1ce6807c3cee4 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSamplingPolicy.h +++ b/Utilities/DataSampling/include/DataSampling/DataSamplingPolicy.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -72,7 +73,7 @@ class DataSamplingPolicy void setFairMQOutputChannel(std::string); /// \brief Returns true if this policy requires data with given InputSpec. - bool match(const framework::ConcreteDataMatcher& input) const; + const framework::OutputSpec* match(const framework::ConcreteDataMatcher& input) const; /// \brief Returns true if user-defined conditions of sampling are fulfilled. bool decide(const o2::framework::DataRef&); /// \brief Returns Output for given InputSpec to pass data forward. diff --git a/Utilities/DataSampling/include/DataSampling/DataSamplingReadoutAdapter.h b/Utilities/DataSampling/include/DataSampling/DataSamplingReadoutAdapter.h index 74084dde0112c..4db52a98aaf2d 100644 --- a/Utilities/DataSampling/include/DataSampling/DataSamplingReadoutAdapter.h +++ b/Utilities/DataSampling/include/DataSampling/DataSamplingReadoutAdapter.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/include/DataSampling/Dispatcher.h b/Utilities/DataSampling/include/DataSampling/Dispatcher.h index b342f9478f0e1..d92876f4c6125 100644 --- a/Utilities/DataSampling/include/DataSampling/Dispatcher.h +++ b/Utilities/DataSampling/include/DataSampling/Dispatcher.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,7 +25,8 @@ #include "Framework/DeviceSpec.h" #include "Framework/Task.h" -class FairMQDevice; +#include <fairmq/FwdDecls.h> +#include "DataSampling/DataSamplingHeader.h" namespace o2::monitoring { @@ -62,14 +64,13 @@ class Dispatcher : public framework::Task framework::Options getOptions(); private: - DataSamplingHeader prepareDataSamplingHeader(const DataSamplingPolicy& policy, const framework::DeviceSpec& spec); + DataSamplingHeader prepareDataSamplingHeader(const DataSamplingPolicy& policy); header::Stack extractAdditionalHeaders(const char* inputHeaderStack) const; void reportStats(monitoring::Monitoring& monitoring) const; - void send(framework::DataAllocator& dataAllocator, const framework::DataRef& inputData, framework::Output&& output) const; - void sendFairMQ(FairMQDevice* device, const framework::DataRef& inputData, const std::string& fairMQChannel, - header::Stack&& stack) const; + void send(framework::DataAllocator& dataAllocator, const framework::DataRef& inputData, const framework::Output& output) const; std::string mName; + DataSamplingHeader::DeviceIDType mDeviceID = "invalid"; std::string mReconfigurationSource; // policies should be shared between all pipeline threads std::vector<std::shared_ptr<DataSamplingPolicy>> mPolicies; diff --git a/Utilities/DataSampling/src/DataSampling.cxx b/Utilities/DataSampling/src/DataSampling.cxx index 766dadd9e22b3..9b14fe36ff144 100644 --- a/Utilities/DataSampling/src/DataSampling.cxx +++ b/Utilities/DataSampling/src/DataSampling.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -35,7 +36,7 @@ std::string DataSampling::createDispatcherName() return std::string("Dispatcher"); //_") + getenv("HOSTNAME"); } -void DataSampling::GenerateInfrastructure(WorkflowSpec& workflow, const std::string& policiesSource, size_t threads) +void DataSampling::GenerateInfrastructure(WorkflowSpec& workflow, const std::string& policiesSource, size_t threads, const std::string& host) { std::unique_ptr<ConfigurationInterface> cfg = ConfigurationFactory::getConfiguration(policiesSource); if (cfg->getRecursive("").count("dataSamplingPolicies") == 0) { @@ -44,26 +45,33 @@ void DataSampling::GenerateInfrastructure(WorkflowSpec& workflow, const std::str } auto policiesTree = cfg->getRecursive("dataSamplingPolicies"); Dispatcher dispatcher(createDispatcherName(), policiesSource); - DataSampling::DoGenerateInfrastructure(dispatcher, workflow, policiesTree, threads); + DataSampling::DoGenerateInfrastructure(dispatcher, workflow, policiesTree, threads, host); } -void DataSampling::GenerateInfrastructure(WorkflowSpec& workflow, const boost::property_tree::ptree& policiesTree, size_t threads) +void DataSampling::GenerateInfrastructure(WorkflowSpec& workflow, const boost::property_tree::ptree& policiesTree, size_t threads, const std::string& host) { Dispatcher dispatcher(createDispatcherName(), ""); - DataSampling::DoGenerateInfrastructure(dispatcher, workflow, policiesTree, threads); + DataSampling::DoGenerateInfrastructure(dispatcher, workflow, policiesTree, threads, host); } -void DataSampling::DoGenerateInfrastructure(Dispatcher& dispatcher, WorkflowSpec& workflow, const boost::property_tree::ptree& policiesTree, size_t threads) +void DataSampling::DoGenerateInfrastructure(Dispatcher& dispatcher, WorkflowSpec& workflow, const boost::property_tree::ptree& policiesTree, size_t threads, const std::string& host) { LOG(DEBUG) << "Generating Data Sampling infrastructure..."; for (auto&& policyConfig : policiesTree) { - std::unique_ptr<DataSamplingPolicy> policy; - // We don't want the Dispatcher to exit due to one faulty Policy try { - dispatcher.registerPolicy(std::make_unique<DataSamplingPolicy>(DataSamplingPolicy::fromConfiguration(policyConfig.second))); + auto policy = DataSamplingPolicy::fromConfiguration(policyConfig.second); + std::vector<std::string> machines; + if (policyConfig.second.count("machines") > 0) { + for (const auto& machine : policyConfig.second.get_child("machines")) { + machines.emplace_back(machine.second.get<std::string>("")); + } + } + if (host.empty() || machines.empty() || std::find(machines.begin(), machines.end(), host) != machines.end()) { + dispatcher.registerPolicy(std::make_unique<DataSamplingPolicy>(std::move(policy))); + } } catch (const std::exception& ex) { LOG(WARN) << "Could not load the Data Sampling Policy '" << policyConfig.second.get_optional<std::string>("id").value_or("") << "', because: " << ex.what(); @@ -103,35 +111,9 @@ void DataSampling::CustomizeInfrastructure(std::vector<ChannelConfigurationPolic // now it cannot be done, since matching is possible only using data processors names } -std::vector<InputSpec> DataSampling::InputSpecsForPolicy(const std::string& policiesSource, const std::string& policyName) -{ - std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(policiesSource); - return InputSpecsForPolicy(config.get(), policyName); -} - -std::vector<InputSpec> DataSampling::InputSpecsForPolicy(ConfigurationInterface* const config, const std::string& policyName) -{ - std::vector<InputSpec> inputs; - auto policiesTree = config->getRecursive("dataSamplingPolicies"); - - for (auto&& policyConfig : policiesTree) { - if (policyConfig.second.get<std::string>("id") == policyName) { - auto policy = DataSamplingPolicy::fromConfiguration(policyConfig.second); - for (const auto& path : policy.getPathMap()) { - InputSpec input = DataSpecUtils::matchingInput(path.second); - inputs.push_back(input); - } - break; - } - } - return inputs; -} - -std::vector<InputSpec> DataSampling::InputSpecsForPolicy(std::shared_ptr<configuration::ConfigurationInterface> config, const std::string& policyName) +std::vector<framework::InputSpec> DataSampling::InputSpecsForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName) { std::vector<InputSpec> inputs; - auto policiesTree = config->getRecursive("dataSamplingPolicies"); - for (auto&& policyConfig : policiesTree) { if (policyConfig.second.get<std::string>("id") == policyName) { auto policy = DataSamplingPolicy::fromConfiguration(policyConfig.second); @@ -145,17 +127,9 @@ std::vector<InputSpec> DataSampling::InputSpecsForPolicy(std::shared_ptr<configu return inputs; } -std::vector<OutputSpec> DataSampling::OutputSpecsForPolicy(const std::string& policiesSource, const std::string& policyName) -{ - std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(policiesSource); - return OutputSpecsForPolicy(config.get(), policyName); -} - -std::vector<OutputSpec> DataSampling::OutputSpecsForPolicy(ConfigurationInterface* const config, const std::string& policyName) +std::vector<framework::OutputSpec> DataSampling::OutputSpecsForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName) { std::vector<OutputSpec> outputs; - auto policiesTree = config->getRecursive("dataSamplingPolicies"); - for (auto&& policyConfig : policiesTree) { if (policyConfig.second.get<std::string>("id") == policyName) { auto policy = DataSamplingPolicy::fromConfiguration(policyConfig.second); @@ -168,31 +142,26 @@ std::vector<OutputSpec> DataSampling::OutputSpecsForPolicy(ConfigurationInterfac return outputs; } -uint16_t DataSampling::PortForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName) +std::optional<uint16_t> DataSampling::PortForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName) { - auto policiesTree = config->getRecursive("dataSamplingPolicies"); for (auto&& policyConfig : policiesTree) { if (policyConfig.second.get<std::string>("id") == policyName) { - return policyConfig.second.get<uint16_t>("port"); + auto boostOptionalPort = policyConfig.second.get_optional<uint16_t>("port"); + return boostOptionalPort.has_value() ? std::optional<uint16_t>(boostOptionalPort.value()) : std::nullopt; } } throw std::runtime_error("Could not find the policy '" + policyName + "'"); } -uint16_t DataSampling::PortForPolicy(const std::string& policiesSource, const std::string& policyName) -{ - std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(policiesSource); - return PortForPolicy(config.get(), policyName); -} - -std::vector<std::string> DataSampling::MachinesForPolicy(configuration::ConfigurationInterface* const config, const std::string& policyName) +std::vector<std::string> DataSampling::MachinesForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName) { std::vector<std::string> machines; - auto policiesTree = config->getRecursive("dataSamplingPolicies"); for (auto&& policyConfig : policiesTree) { if (policyConfig.second.get<std::string>("id") == policyName) { - for (const auto& machine : policyConfig.second.get_child("machines")) { - machines.emplace_back(machine.second.get<std::string>("")); + if (policyConfig.second.count("machines") > 0) { + for (const auto& machine : policyConfig.second.get_child("machines")) { + machines.emplace_back(machine.second.get<std::string>("")); + } } return machines; } @@ -200,10 +169,14 @@ std::vector<std::string> DataSampling::MachinesForPolicy(configuration::Configur throw std::runtime_error("Could not find the policy '" + policyName + "'"); } -std::vector<std::string> DataSampling::MachinesForPolicy(const std::string& policiesSource, const std::string& policyName) +std::string DataSampling::BindLocationForPolicy(const boost::property_tree::ptree& policiesTree, const std::string& policyName) { - std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(policiesSource); - return MachinesForPolicy(config.get(), policyName); + for (auto&& policyConfig : policiesTree) { + if (policyConfig.second.get<std::string>("id") == policyName) { + return policyConfig.second.get_optional<std::string>("bindLocation").value_or("remote"); + } + } + throw std::runtime_error("Could not find the policy '" + policyName + "'"); } } // namespace o2::utilities diff --git a/Utilities/DataSampling/src/DataSamplingConditionCustom.cxx b/Utilities/DataSampling/src/DataSamplingConditionCustom.cxx index f9dca006e8b5b..9ba9368003a1a 100644 --- a/Utilities/DataSampling/src/DataSamplingConditionCustom.cxx +++ b/Utilities/DataSampling/src/DataSamplingConditionCustom.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/DataSamplingConditionFactory.cxx b/Utilities/DataSampling/src/DataSamplingConditionFactory.cxx index 94dc64bd746a4..c5211ba044b88 100644 --- a/Utilities/DataSampling/src/DataSamplingConditionFactory.cxx +++ b/Utilities/DataSampling/src/DataSamplingConditionFactory.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/DataSamplingConditionNConsecutive.cxx b/Utilities/DataSampling/src/DataSamplingConditionNConsecutive.cxx index 48f63f4c79e44..a4f33e1ea0903 100644 --- a/Utilities/DataSampling/src/DataSamplingConditionNConsecutive.cxx +++ b/Utilities/DataSampling/src/DataSamplingConditionNConsecutive.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/DataSamplingConditionPayloadSize.cxx b/Utilities/DataSampling/src/DataSamplingConditionPayloadSize.cxx index 3afa25b0d4dbd..6a3bfc4dcf20c 100644 --- a/Utilities/DataSampling/src/DataSamplingConditionPayloadSize.cxx +++ b/Utilities/DataSampling/src/DataSamplingConditionPayloadSize.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/DataSamplingConditionRandom.cxx b/Utilities/DataSampling/src/DataSamplingConditionRandom.cxx index 48b00b929a9cb..1e4f6bacd2d2f 100644 --- a/Utilities/DataSampling/src/DataSamplingConditionRandom.cxx +++ b/Utilities/DataSampling/src/DataSamplingConditionRandom.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,6 +19,7 @@ #include "Framework/DataProcessingHeader.h" #include "PCG/pcg_random.hpp" +#include <random> #include <boost/property_tree/ptree.hpp> @@ -47,7 +49,10 @@ class DataSamplingConditionRandom : public DataSamplingCondition void configure(const boost::property_tree::ptree& config) override { mThreshold = static_cast<uint32_t>(config.get<double>("fraction") * std::numeric_limits<uint32_t>::max()); - mGenerator.seed(config.get<uint64_t>("seed")); + + auto seed = config.get<uint64_t>("seed"); + mGenerator.seed((seed == 0) ? std::random_device()() : seed); + mCurrentTimesliceID = 0; mLastDecision = false; }; diff --git a/Utilities/DataSampling/src/DataSamplingHeader.cxx b/Utilities/DataSampling/src/DataSamplingHeader.cxx index 95e21088a9df7..392e37a5d9117 100644 --- a/Utilities/DataSampling/src/DataSamplingHeader.cxx +++ b/Utilities/DataSampling/src/DataSamplingHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/DataSamplingPolicy.cxx b/Utilities/DataSampling/src/DataSamplingPolicy.cxx index 452f61ab14cfd..cfd6e97683904 100644 --- a/Utilities/DataSampling/src/DataSamplingPolicy.cxx +++ b/Utilities/DataSampling/src/DataSamplingPolicy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -102,9 +103,10 @@ DataSamplingPolicy DataSamplingPolicy::fromConfiguration(const ptree& config) return policy; } -bool DataSamplingPolicy::match(const ConcreteDataMatcher& input) const +const framework::OutputSpec* DataSamplingPolicy::match(const ConcreteDataMatcher& input) const { - return mPaths.find(input) != mPaths.end(); + const auto it = mPaths.find(input); + return it != mPaths.end() ? &(it->second) : nullptr; } bool DataSamplingPolicy::decide(const o2::framework::DataRef& dataRef) diff --git a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx index 4c613af6eb6f1..c353d1e0ba5da 100644 --- a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx +++ b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/src/Dispatcher.cxx b/Utilities/DataSampling/src/Dispatcher.cxx index e4e434ff66fa8..d143419671fd3 100644 --- a/Utilities/DataSampling/src/Dispatcher.cxx +++ b/Utilities/DataSampling/src/Dispatcher.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,7 +15,6 @@ /// \author Piotr Konopka, piotr.jan.konopka@cern.ch #include "DataSampling/Dispatcher.h" -#include "Framework/RawDeviceService.h" #include "DataSampling/DataSamplingPolicy.h" #include "DataSampling/DataSamplingHeader.h" #include "Framework/DataProcessingHeader.h" @@ -22,11 +22,11 @@ #include "Framework/Logger.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/InputRecordWalker.h" - #include "Framework/Monitoring.h" +#include "Framework/DataRefUtils.h" + #include <Configuration/ConfigurationInterface.h> #include <Configuration/ConfigurationFactory.h> -#include <fairmq/FairMQDevice.h> using namespace o2::configuration; using namespace o2::monitoring; @@ -71,34 +71,52 @@ void Dispatcher::init(InitContext& ctx) << policyConfig.second.get_optional<std::string>("id").value_or("") << "'"; } } + + auto spec = ctx.services().get<const DeviceSpec>(); + mDeviceID.runtimeInit(spec.id.substr(0, DataSamplingHeader::deviceIDTypeSize).c_str()); } void Dispatcher::run(ProcessingContext& ctx) { - for (const auto& input : InputRecordWalker(ctx.inputs())) { + // todo: consider matching (and deciding) in completion policy to save some time + // it is not trivial though, we would have to share state with the customize() method, + // which is not possible atm. - const auto* inputHeader = header::get<header::DataHeader*>(input.header); - ConcreteDataMatcher inputMatcher{inputHeader->dataOrigin, inputHeader->dataDescription, inputHeader->subSpecification}; + for (auto inputIt = ctx.inputs().begin(); inputIt != ctx.inputs().end(); inputIt++) { + + const DataRef& firstPart = inputIt.getByPos(0); + if (firstPart.header == nullptr) { + continue; + } + const auto* firstInputHeader = DataRefUtils::getHeader<header::DataHeader*>(firstPart); + ConcreteDataMatcher inputMatcher{firstInputHeader->dataOrigin, firstInputHeader->dataDescription, firstInputHeader->subSpecification}; for (auto& policy : mPolicies) { - // todo: consider getting the outputSpec in match to improve performance - // todo: consider matching (and deciding) in completion policy to save some time - - if (policy->match(inputMatcher) && policy->decide(input)) { - // We copy every header which is not DataHeader or DataProcessingHeader, - // so that custom data-dependent headers are passed forward, - // and we add a DataSamplingHeader. - header::Stack headerStack{ - std::move(extractAdditionalHeaders(input.header)), - std::move(prepareDataSamplingHeader(*policy.get(), ctx.services().get<const DeviceSpec>()))}; - - if (!policy->getFairMQOutputChannel().empty()) { - sendFairMQ(ctx.services().get<RawDeviceService>().device(), input, policy->getFairMQOutputChannelName(), - std::move(headerStack)); - } else { - Output output = policy->prepareOutput(inputMatcher, input.spec->lifetime); - output.metaHeader = std::move(header::Stack{std::move(output.metaHeader), std::move(headerStack)}); - send(ctx.outputs(), input, std::move(output)); + // fixme: in principle matching could be broken by having query "TST/RAWDATA/0" and having parts with just + // the first subspec == 0, but others could be different. However, we trust that DPL does necessary checks + // during workflow validation and when passing messages (e.g. query "TST/RAWDATA/0" should not match + // a "TST/RAWDATA/*" output. + if (auto route = policy->match(inputMatcher); route != nullptr && policy->decide(firstPart)) { + auto routeAsConcreteDataType = DataSpecUtils::asConcreteDataTypeMatcher(*route); + auto dsheader = prepareDataSamplingHeader(*policy); + for (const auto& part : inputIt) { + if (part.header != nullptr) { + // We copy every header which is not DataHeader or DataProcessingHeader, + // so that custom data-dependent headers are passed forward, + // and we add a DataSamplingHeader. + header::Stack headerStack{ + std::move(extractAdditionalHeaders(part.header)), + dsheader}; + const auto* partInputHeader = DataRefUtils::getHeader<header::DataHeader*>(part); + + Output output{ + routeAsConcreteDataType.origin, + routeAsConcreteDataType.description, + partInputHeader->subSpecification, + part.spec->lifetime, + std::move(headerStack)}; + send(ctx.outputs(), part, output); + } } } } @@ -123,25 +141,22 @@ void Dispatcher::reportStats(Monitoring& monitoring) const monitoring.send({dispatcherTotalAcceptedMessages, "Dispatcher_messages_passed"}); } -DataSamplingHeader Dispatcher::prepareDataSamplingHeader(const DataSamplingPolicy& policy, const DeviceSpec& spec) +DataSamplingHeader Dispatcher::prepareDataSamplingHeader(const DataSamplingPolicy& policy) { uint64_t sampleTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count()); - DataSamplingHeader::DeviceIDType id; - id.runtimeInit(spec.id.substr(0, DataSamplingHeader::deviceIDTypeSize).c_str()); - return { sampleTime, policy.getTotalAcceptedMessages(), policy.getTotalEvaluatedMessages(), - id}; + mDeviceID}; } header::Stack Dispatcher::extractAdditionalHeaders(const char* inputHeaderStack) const { header::Stack headerStack; - const auto* first = header::BaseHeader::get(reinterpret_cast<const byte*>(inputHeaderStack)); + const auto* first = header::BaseHeader::get(reinterpret_cast<const std::byte*>(inputHeaderStack)); for (const auto* current = first; current != nullptr; current = current->next()) { if (current->description != header::DataHeader::sHeaderType && current->description != DataProcessingHeader::sHeaderType) { @@ -152,41 +167,12 @@ header::Stack Dispatcher::extractAdditionalHeaders(const char* inputHeaderStack) return headerStack; } -void Dispatcher::send(DataAllocator& dataAllocator, const DataRef& inputData, Output&& output) const +void Dispatcher::send(DataAllocator& dataAllocator, const DataRef& inputData, const Output& output) const { - const auto* inputHeader = header::get<header::DataHeader*>(inputData.header); + const auto* inputHeader = DataRefUtils::getHeader<header::DataHeader*>(inputData); dataAllocator.snapshot(output, inputData.payload, inputHeader->payloadSize, inputHeader->payloadSerializationMethod); } -// ideally this should be in a separate proxy device or use Lifetime::External -void Dispatcher::sendFairMQ(FairMQDevice* device, const DataRef& inputData, const std::string& fairMQChannel, - header::Stack&& stack) const -{ - const auto* dh = header::get<header::DataHeader*>(inputData.header); - assert(dh); - const auto* dph = header::get<DataProcessingHeader*>(inputData.header); - assert(dph); - - header::DataHeader dhout{dh->dataDescription, dh->dataOrigin, dh->subSpecification, dh->payloadSize}; - dhout.payloadSerializationMethod = dh->payloadSerializationMethod; - DataProcessingHeader dphout{dph->startTime, dph->duration}; - o2::header::Stack headerStack{dhout, dphout, stack}; - - auto channelAlloc = o2::pmr::getTransportAllocator(device->Transport()); - FairMQMessagePtr msgHeaderStack = o2::pmr::getMessage(std::move(headerStack), channelAlloc); - - char* payloadCopy = new char[dh->payloadSize]; - memcpy(payloadCopy, inputData.payload, dh->payloadSize); - auto cleanupFcn = [](void* data, void*) { delete[] reinterpret_cast<char*>(data); }; - FairMQMessagePtr msgPayload(device->NewMessage(payloadCopy, dh->payloadSize, cleanupFcn, payloadCopy)); - - FairMQParts message; - message.AddPart(move(msgHeaderStack)); - message.AddPart(move(msgPayload)); - - int64_t bytesSent = device->Send(message, fairMQChannel); -} - void Dispatcher::registerPolicy(std::unique_ptr<DataSamplingPolicy>&& policy) { mPolicies.emplace_back(std::move(policy)); @@ -245,20 +231,9 @@ Outputs Dispatcher::getOutputSpecs() } framework::Options Dispatcher::getOptions() { - o2::framework::Options options; - for (const auto& policy : mPolicies) { - if (!policy->getFairMQOutputChannel().empty()) { - if (!options.empty()) { - throw std::runtime_error("Maximum one policy with raw FairMQ channel is allowed, more have been declared."); - } - options.push_back({"channel-config", VariantType::String, policy->getFairMQOutputChannel().c_str(), {"Out-of-band channel config"}}); - LOG(DEBUG) << " - registering output FairMQ channel '" << policy->getFairMQOutputChannel() << "'"; - } - } - options.push_back({"period-timer-stats", framework::VariantType::Int, 10 * 1000000, {"Dispatcher's stats timer period"}}); - - return options; + return {{"period-timer-stats", framework::VariantType::Int, 10 * 1000000, {"Dispatcher's stats timer period"}}}; } + size_t Dispatcher::numberOfPolicies() { return mPolicies.size(); diff --git a/Utilities/DataSampling/src/dataSamplingStandalone.cxx b/Utilities/DataSampling/src/dataSamplingStandalone.cxx index e6fb96fbdbdd5..a2468a8216dcc 100644 --- a/Utilities/DataSampling/src/dataSamplingStandalone.cxx +++ b/Utilities/DataSampling/src/dataSamplingStandalone.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/test/dataSamplingBenchmark.cxx b/Utilities/DataSampling/test/dataSamplingBenchmark.cxx index 8d5773b9eeb75..09d3ce4f499b8 100644 --- a/Utilities/DataSampling/test/dataSamplingBenchmark.cxx +++ b/Utilities/DataSampling/test/dataSamplingBenchmark.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -12,6 +13,7 @@ #include "DataSampling/DataSampling.h" #include "Framework/CompletionPolicyHelpers.h" #include <vector> +#include <filesystem> using namespace o2::framework; using namespace o2::utilities; @@ -45,7 +47,6 @@ void customize(std::vector<ConfigParamSpec>& workflowOptions) #include <memory> #include <boost/algorithm/string.hpp> -#include <boost/filesystem/operations.hpp> #include <boost/interprocess/managed_shared_memory.hpp> #include <boost/functional/hash.hpp> #include <fairmq/FairMQDevice.h> @@ -154,7 +155,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) " ]\n" "}"; - if (!boost::filesystem::exists(configurationPath)) { + if (!std::filesystem::exists(configurationPath)) { std::ofstream configurationFile(configurationPath); configurationFile << configuration; configurationFile.close(); diff --git a/Utilities/DataSampling/test/dataSamplingParallel.cxx b/Utilities/DataSampling/test/dataSamplingParallel.cxx index 280f2733f2920..496697219e17a 100644 --- a/Utilities/DataSampling/test/dataSamplingParallel.cxx +++ b/Utilities/DataSampling/test/dataSamplingParallel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -29,6 +30,7 @@ void customize(std::vector<ChannelConfigurationPolicy>& policies) #include "Framework/DataSpecUtils.h" #include "Framework/ParallelContext.h" #include "Framework/runDataProcessing.h" +#include "Framework/DataRefUtils.h" #include <chrono> #include <iostream> @@ -108,7 +110,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto inputDataTpcProcessed = reinterpret_cast<const FakeCluster*>(ctx.inputs().get( "TPC_CLUSTERS_P_S").payload); - const auto* header = o2::header::get<DataHeader*>(ctx.inputs().get("TPC_CLUSTERS_S").header); + const auto* header = DataRefUtils::getHeader<DataHeader*>(ctx.inputs().get("TPC_CLUSTERS_S")); bool dataGood = true; for (int j = 0; j < header->payloadSize / sizeof(FakeCluster); ++j) { diff --git a/Utilities/DataSampling/test/dataSamplingPodAndRoot.cxx b/Utilities/DataSampling/test/dataSamplingPodAndRoot.cxx index eeb8220985119..34df12c60072d 100644 --- a/Utilities/DataSampling/test/dataSamplingPodAndRoot.cxx +++ b/Utilities/DataSampling/test/dataSamplingPodAndRoot.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -30,6 +31,7 @@ void customize(std::vector<ChannelConfigurationPolicy>& policies) #include "Framework/TMessageSerializer.h" #include "DataSampling/DataSamplingHeader.h" #include "Framework/Logger.h" +#include "Framework/DataRefUtils.h" #include <TClonesArray.h> #include <TObjString.h> #include <TH1F.h> @@ -97,8 +99,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto inputDataTpcProcessed = reinterpret_cast<const FakeCluster*>(ctx.inputs().get( "TPC_CLUSTERS_P_S").payload); - const auto* header = ctx.inputs().get("TPC_CLUSTERS_S").header; - const auto* dataHeader = o2::header::get<DataHeader*>(header); + auto ref = ctx.inputs().get("TPC_CLUSTERS_S"); + const auto* dataHeader = DataRefUtils::getHeader<DataHeader*>(ref); bool dataGood = true; for (int j = 0; j < dataHeader->payloadSize / sizeof(FakeCluster); ++j) { @@ -114,7 +116,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) LOG(INFO) << "qcTaskTPC - received data is " << (dataGood ? "correct" : "wrong"); - const auto* dsHeader = o2::header::get<DataSamplingHeader*>(header); + const auto* dsHeader = DataRefUtils::getHeader<DataSamplingHeader*>(ref); if (dsHeader) { LOG(INFO) << "Matching messages seen by Dispatcher: " << dsHeader->totalEvaluatedMessages << ", accepted: " << dsHeader->totalAcceptedMessages diff --git a/Utilities/DataSampling/test/dataSamplingTimePipeline.cxx b/Utilities/DataSampling/test/dataSamplingTimePipeline.cxx index c5cc028d14c81..ec5c9075cde44 100644 --- a/Utilities/DataSampling/test/dataSamplingTimePipeline.cxx +++ b/Utilities/DataSampling/test/dataSamplingTimePipeline.cxx @@ -1,14 +1,16 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "DataSampling/DataSampling.h" +#include "Framework/DataRefUtils.h" #include <thread> @@ -95,7 +97,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto inputDataTpcProcessed = reinterpret_cast<const FakeCluster*>(ctx.inputs().get( "TPC_CLUSTERS_P_S").payload); - const auto* header = o2::header::get<DataHeader*>(ctx.inputs().get("TPC_CLUSTERS_S").header); + const auto* header = DataRefUtils::getHeader<DataHeader*>(ctx.inputs().get("TPC_CLUSTERS_S")); bool dataGood = true; for (int j = 0; j < header->payloadSize / sizeof(FakeCluster); ++j) { diff --git a/Utilities/DataSampling/test/test_DataSampling.cxx b/Utilities/DataSampling/test/test_DataSampling.cxx index e3eff2d236310..95e4b1c5fc7a2 100644 --- a/Utilities/DataSampling/test/test_DataSampling.cxx +++ b/Utilities/DataSampling/test/test_DataSampling.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,9 +17,6 @@ #include "DataSampling/DataSampling.h" #include "DataSampling/Dispatcher.h" #include "DataSampling/DataSamplingPolicy.h" -#include "Framework/DataProcessingHeader.h" -#include "Framework/ExternalFairMQDeviceProxy.h" -#include "DataSampling/DataSamplingReadoutAdapter.h" #include "Framework/DataSpecUtils.h" #include "Headers/DataHeader.h" @@ -171,52 +169,158 @@ BOOST_AUTO_TEST_CASE(DataSamplingTimePipelineFlow) BOOST_CHECK_EQUAL(disp->maxInputTimeslices, 3); } -BOOST_AUTO_TEST_CASE(DataSamplingFairMq) +BOOST_AUTO_TEST_CASE(InputSpecsForPolicy) { - WorkflowSpec workflow{ - specifyExternalFairMQDeviceProxy( - "readout-proxy", - Outputs{{"TPC", "RAWDATA"}}, - "fake-channel-config", - dataSamplingReadoutAdapter({"TPC", "RAWDATA"}))}; - - std::string configFilePath = std::string(getenv("O2_ROOT")) + "/share/tests/test_DataSampling.json"; - DataSampling::GenerateInfrastructure(workflow, "json:/" + configFilePath); + std::string configFilePath = "json:/" + std::string(getenv("O2_ROOT")) + "/share/tests/test_DataSampling.json"; + std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(configFilePath); + auto policiesTree = config->getRecursive("dataSamplingPolicies"); - auto disp = std::find_if(workflow.begin(), workflow.end(), - [](const DataProcessorSpec& d) { - return d.name.find("Dispatcher") != std::string::npos; - }); - BOOST_REQUIRE(disp != workflow.end()); + { + std::vector<InputSpec> inputs = DataSampling::InputSpecsForPolicy(policiesTree, "tpcclusters"); - auto input = std::find_if(disp->inputs.begin(), disp->inputs.end(), - [](const InputSpec& in) { - return DataSpecUtils::match(in, ConcreteDataMatcher{DataOrigin("TPC"), DataDescription("RAWDATA"), 0}) && in.lifetime == Lifetime::Timeframe; - }); - BOOST_CHECK(input != disp->inputs.end()); + BOOST_CHECK_EQUAL(inputs.size(), 2); + BOOST_CHECK(DataSpecUtils::match(inputs[0], ConcreteDataTypeMatcher{"DS", "tpcclusters0"})); + BOOST_CHECK_EQUAL(inputs[0].binding, "clusters"); + BOOST_CHECK(DataSpecUtils::match(inputs[1], ConcreteDataTypeMatcher{"DS", "tpcclusters1"})); + BOOST_CHECK_EQUAL(inputs[1].binding, "clusters_p"); + } + { + std::vector<InputSpec> inputs = DataSampling::InputSpecsForPolicy(policiesTree, "tpcraw"); - auto channelConfig = std::find_if(disp->options.begin(), disp->options.end(), - [](const ConfigParamSpec& opt) { - return opt.name == "channel-config"; - }); - BOOST_REQUIRE(channelConfig != disp->options.end()); + BOOST_CHECK_EQUAL(inputs.size(), 1); + BOOST_CHECK(DataSpecUtils::match(inputs[0], ConcreteDataTypeMatcher{"TPC", "SMP_RAWDATA"})); + BOOST_CHECK_EQUAL(inputs[0].binding, "clusters"); + } } -BOOST_AUTO_TEST_CASE(InputSpecsForPolicy) +BOOST_AUTO_TEST_CASE(OutputSpecsForPolicy) { std::string configFilePath = "json:/" + std::string(getenv("O2_ROOT")) + "/share/tests/test_DataSampling.json"; - std::vector<InputSpec> inputs = DataSampling::InputSpecsForPolicy(configFilePath, "tpcclusters"); + std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(configFilePath); + auto policiesTree = config->getRecursive("dataSamplingPolicies"); + + { + auto outputs = DataSampling::OutputSpecsForPolicy(policiesTree, "tpcclusters"); - BOOST_CHECK_EQUAL(inputs.size(), 2); - BOOST_CHECK(DataSpecUtils::match(inputs[0], ConcreteDataTypeMatcher{"DS", "tpcclusters0"})); - BOOST_CHECK_EQUAL(inputs[0].binding, "clusters"); - BOOST_CHECK(DataSpecUtils::match(inputs[1], ConcreteDataTypeMatcher{"DS", "tpcclusters1"})); - BOOST_CHECK_EQUAL(inputs[1].binding, "clusters_p"); + BOOST_REQUIRE_EQUAL(outputs.size(), 2); + BOOST_CHECK(DataSpecUtils::match(outputs[0], ConcreteDataTypeMatcher{"DS", "tpcclusters0"})); + BOOST_CHECK_EQUAL(outputs[0].binding.value, "clusters"); + BOOST_CHECK(DataSpecUtils::match(outputs[1], ConcreteDataTypeMatcher{"DS", "tpcclusters1"})); + BOOST_CHECK_EQUAL(outputs[1].binding.value, "clusters_p"); + } + { + auto outputs = DataSampling::OutputSpecsForPolicy(policiesTree, "tpcraw"); + BOOST_REQUIRE_EQUAL(outputs.size(), 1); + BOOST_CHECK(DataSpecUtils::match(outputs[0], ConcreteDataTypeMatcher{"TPC", "SMP_RAWDATA"})); + BOOST_CHECK_EQUAL(outputs[0].binding.value, "clusters"); + } +} + +BOOST_AUTO_TEST_CASE(MultinodeUtilities) +{ + std::string configFilePath = "json:/" + std::string(getenv("O2_ROOT")) + "/share/tests/test_DataSampling.json"; std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(configFilePath); - inputs = DataSampling::InputSpecsForPolicy(config.get(), "tpcclusters"); + auto policiesTree = config->getRecursive("dataSamplingPolicies"); + + { + BOOST_CHECK_THROW(DataSampling::PortForPolicy(policiesTree, "no such policy"), std::runtime_error); + BOOST_CHECK_THROW(DataSampling::MachinesForPolicy(policiesTree, "no such policy"), std::runtime_error); + BOOST_CHECK_THROW(DataSampling::BindLocationForPolicy(policiesTree, "no such policy"), std::runtime_error); + } + { + auto port = DataSampling::PortForPolicy(policiesTree, "tpcclusters"); + BOOST_CHECK(!port.has_value()); + auto machines = DataSampling::MachinesForPolicy(policiesTree, "tpcclusters"); + BOOST_CHECK(machines.empty()); + } + { + auto port = DataSampling::PortForPolicy(policiesTree, "tpcraw"); + BOOST_REQUIRE(port.has_value()); + BOOST_CHECK_EQUAL(port.value(), 1234); + auto machines = DataSampling::MachinesForPolicy(policiesTree, "tpcraw"); + BOOST_CHECK_EQUAL(machines.size(), 2); + } + { + BOOST_CHECK_EQUAL(DataSampling::BindLocationForPolicy(policiesTree, "tpcclusters"), "local"); + BOOST_CHECK_EQUAL(DataSampling::BindLocationForPolicy(policiesTree, "tpcraw"), "remote"); + } + { + // empty host -> match any policy + WorkflowSpec workflow; + DataSampling::GenerateInfrastructure(workflow, configFilePath, 1, ""); + + auto disp = std::find_if(workflow.begin(), workflow.end(), + [](const DataProcessorSpec& d) { + return d.name.find("Dispatcher") != std::string::npos; + }); + BOOST_REQUIRE(disp != workflow.end()); + + auto input1 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input1 != disp->inputs.end()); + auto input2 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS_P"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input2 != disp->inputs.end()); + auto input3 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("RAWDATA"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input3 != disp->inputs.end()); + } + { + // mismatching host -> create only policies with empty machines list + WorkflowSpec workflow; + DataSampling::GenerateInfrastructure(workflow, configFilePath, 1, "mismatching host"); + + auto disp = std::find_if(workflow.begin(), workflow.end(), + [](const DataProcessorSpec& d) { + return d.name.find("Dispatcher") != std::string::npos; + }); + BOOST_REQUIRE(disp != workflow.end()); + + auto input1 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input1 != disp->inputs.end()); + auto input2 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS_P"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input2 != disp->inputs.end()); + } + { + // matching host -> create policies with empty machines list and the ones which match + WorkflowSpec workflow; + DataSampling::GenerateInfrastructure(workflow, configFilePath, 1, "machineA"); + + auto disp = std::find_if(workflow.begin(), workflow.end(), + [](const DataProcessorSpec& d) { + return d.name.find("Dispatcher") != std::string::npos; + }); + BOOST_REQUIRE(disp != workflow.end()); - BOOST_CHECK_EQUAL(inputs.size(), 2); + auto input1 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input1 != disp->inputs.end()); + auto input2 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("CLUSTERS_P"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input2 != disp->inputs.end()); + auto input3 = std::find_if(disp->inputs.begin(), disp->inputs.end(), + [](const InputSpec& in) { + return DataSpecUtils::match(in, DataOrigin("TPC"), DataDescription("RAWDATA"), 0) && in.lifetime == Lifetime::Timeframe; + }); + BOOST_CHECK(input3 != disp->inputs.end()); + } } BOOST_AUTO_TEST_CASE(DataSamplingEmptyConfig) @@ -300,4 +404,25 @@ BOOST_AUTO_TEST_CASE(DataSamplingOverlappingInputs) BOOST_CHECK_EQUAL(inputs[2], (InputSpec{"asdf", {"TST", "CCCC"}})); BOOST_CHECK_EQUAL(inputs[3], (InputSpec{"timer-stats", "DS", "TIMER-dispatcher", 0, Lifetime::Timer})); } + + { + // two policies with one common concrete data spec + Dispatcher dispatcher("dispatcher", ""); + auto policy1 = std::make_unique<DataSamplingPolicy>("policy1"); + policy1->registerPath({"random", "TST", "AAAA", 0}, {{"erwv"}, "DS", "XYZ", 0}); + + auto policy2 = std::make_unique<DataSamplingPolicy>("policy2"); + policy2->registerPath({"random0", "TST", "AAAA", 0}, {{"fdsf"}, "DS", "BBBB", 0}); + policy2->registerPath({"random1", "TST", "AAAA", 1}, {{"fdsf"}, "DS", "BBBB", 1}); + + dispatcher.registerPolicy(std::move(policy1)); + dispatcher.registerPolicy(std::move(policy2)); + + auto inputs = dispatcher.getInputSpecs(); + + BOOST_REQUIRE_EQUAL(inputs.size(), 3); + BOOST_CHECK_EQUAL(inputs[0], (InputSpec{"random0", "TST", "AAAA", 0})); + BOOST_CHECK_EQUAL(inputs[1], (InputSpec{"random1", "TST", "AAAA", 1})); + BOOST_CHECK_EQUAL(inputs[2], (InputSpec{"timer-stats", "DS", "TIMER-dispatcher", 0, Lifetime::Timer})); + } } diff --git a/Utilities/DataSampling/test/test_DataSampling.json b/Utilities/DataSampling/test/test_DataSampling.json index e1451a3048d54..90087fbd41a2f 100644 --- a/Utilities/DataSampling/test/test_DataSampling.json +++ b/Utilities/DataSampling/test/test_DataSampling.json @@ -1,19 +1,23 @@ { - "dataSamplingPolicies": [ + "dataSamplingPolicies" : [ { - "id": "tpcclusters", - "active": "true", - "machines": [], + "id" : "tpcclusters", + "active" : "true", "query" : "clusters:TPC/CLUSTERS;clusters_p:TPC/CLUSTERS_P", - "samplingConditions": [] + "samplingConditions" : [], + "bindLocation" : "local" }, { - "id": "tpcraw", - "active": "true", - "machines": [], - "query": "clusters:TPC/RAWDATA", - "samplingConditions": [], - "fairMQOutput": "name=data,type=push,method=bind,address=tcp://127.0.0.1:26525,rateLogging=1" + "id" : "tpcraw", + "active" : "true", + "machines" : [ + "machineA", + "machineB" + ], + "port" : "1234", + "query" : "clusters:TPC/RAWDATA", + "outputs" : "clusters:TPC/SMP_RAWDATA", + "samplingConditions" : [] } ] } diff --git a/Utilities/DataSampling/test/test_DataSamplingCondition.cxx b/Utilities/DataSampling/test/test_DataSamplingCondition.cxx index 8b77e299df5e7..44209d804c52c 100644 --- a/Utilities/DataSampling/test/test_DataSamplingCondition.cxx +++ b/Utilities/DataSampling/test/test_DataSamplingCondition.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/test/test_DataSamplingHeader.cxx b/Utilities/DataSampling/test/test_DataSamplingHeader.cxx index 44c26270572ba..48ab5ba953eec 100644 --- a/Utilities/DataSampling/test/test_DataSamplingHeader.cxx +++ b/Utilities/DataSampling/test/test_DataSamplingHeader.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/DataSampling/test/test_DataSamplingPolicy.cxx b/Utilities/DataSampling/test/test_DataSamplingPolicy.cxx index 1723dc913fe28..e1eda88c69e00 100644 --- a/Utilities/DataSampling/test/test_DataSamplingPolicy.cxx +++ b/Utilities/DataSampling/test/test_DataSamplingPolicy.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/MCStepLogger/CMakeLists.txt b/Utilities/MCStepLogger/CMakeLists.txt index f63a845c7bcdb..728861afb576c 100644 --- a/Utilities/MCStepLogger/CMakeLists.txt +++ b/Utilities/MCStepLogger/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # @author Sandro Wenzel @brief cmake setup for module Utilities/MCStepLogger diff --git a/Utilities/Mergers/CMakeLists.txt b/Utilities/Mergers/CMakeLists.txt index d28670f7c72cf..6cc026eaa38a5 100644 --- a/Utilities/Mergers/CMakeLists.txt +++ b/Utilities/Mergers/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # FIXME: the LinkDef should not be in the public area @@ -47,6 +48,7 @@ o2_add_executable(benchmark-empty-loop COMPONENT_NAME mergers PUBLIC_LINK_LIBRARIES O2::Mergers) +if (TARGET benchmark::benchmark) o2_add_executable(benchmark-miscellaneous SOURCES test/benchmark_Miscellaneous.cxx COMPONENT_NAME mergers @@ -66,6 +68,7 @@ o2_add_executable(benchmark-types SOURCES test/benchmark_Types.cxx COMPONENT_NAME mergers PUBLIC_LINK_LIBRARIES O2::Mergers benchmark::benchmark) +endif() o2_add_test(InfrastructureBuilder SOURCES test/test_InfrastructureBuilder.cxx @@ -83,4 +86,4 @@ o2_add_test(ObjectStore SOURCES test/test_ObjectStore.cxx COMPONENT_NAME mergers PUBLIC_LINK_LIBRARIES O2::Mergers - LABELS utils) \ No newline at end of file + LABELS utils) diff --git a/Utilities/Mergers/include/Mergers/CustomMergeableObject.h b/Utilities/Mergers/include/Mergers/CustomMergeableObject.h index c64035bac6e13..b88fae3195d68 100644 --- a/Utilities/Mergers/include/Mergers/CustomMergeableObject.h +++ b/Utilities/Mergers/include/Mergers/CustomMergeableObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/CustomMergeableTObject.h b/Utilities/Mergers/include/Mergers/CustomMergeableTObject.h index ef57a90daa7ca..9c621b41342dc 100644 --- a/Utilities/Mergers/include/Mergers/CustomMergeableTObject.h +++ b/Utilities/Mergers/include/Mergers/CustomMergeableTObject.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/FullHistoryMerger.h b/Utilities/Mergers/include/Mergers/FullHistoryMerger.h index fd471f22b981a..7dc9a491eaec1 100644 --- a/Utilities/Mergers/include/Mergers/FullHistoryMerger.h +++ b/Utilities/Mergers/include/Mergers/FullHistoryMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -54,6 +55,7 @@ class FullHistoryMerger : public framework::Task MergerConfig mConfig; std::unique_ptr<monitoring::Monitoring> mCollector; + int mCyclesSinceReset = 0; // stats int mTotalObjectsMerged = 0; @@ -65,6 +67,7 @@ class FullHistoryMerger : public framework::Task void updateCache(const framework::DataRef& ref); void mergeCache(); void publish(framework::DataAllocator& allocator); + void clear(); }; } // namespace o2::mergers diff --git a/Utilities/Mergers/include/Mergers/IntegratingMerger.h b/Utilities/Mergers/include/Mergers/IntegratingMerger.h index a7133fa49b56b..99113b1058d89 100644 --- a/Utilities/Mergers/include/Mergers/IntegratingMerger.h +++ b/Utilities/Mergers/include/Mergers/IntegratingMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -52,16 +53,18 @@ class IntegratingMerger : public framework::Task private: void publish(framework::DataAllocator& allocator); + void clear(); private: header::DataHeader::SubSpecificationType mSubSpec; ObjectStore mMergedObject = std::monostate{}; MergerConfig mConfig; std::unique_ptr<monitoring::Monitoring> mCollector; + int mCyclesSinceReset = 0; // stats - int mTotalObjectsMerged = 0; - int mObjectsMerged = 0; + int mTotalDeltasMerged = 0; + int mDeltasMerged = 0; }; } // namespace o2::mergers diff --git a/Utilities/Mergers/include/Mergers/LinkDef.h b/Utilities/Mergers/include/Mergers/LinkDef.h index 80e59eb8c935e..5367cf2412391 100644 --- a/Utilities/Mergers/include/Mergers/LinkDef.h +++ b/Utilities/Mergers/include/Mergers/LinkDef.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/MergeInterface.h b/Utilities/Mergers/include/Mergers/MergeInterface.h index 1b7da756f852f..5f614136a6520 100644 --- a/Utilities/Mergers/include/Mergers/MergeInterface.h +++ b/Utilities/Mergers/include/Mergers/MergeInterface.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,10 +33,13 @@ class MergeInterface // make sure that all entries are correctly deleted as well. virtual ~MergeInterface() = default; - /// \brief Custom merge function. Can return a number of merged entries/bins/etc for statistics. + /// \brief Custom merge method. virtual void merge(MergeInterface* const other) = 0; // const argument - ClassDef(MergeInterface, 0); + /// \brief Lets the child perform any routines after the object was deserialized (e.g. setting the correct ownership) + virtual void postDeserialization(){}; + + ClassDef(MergeInterface, 1); }; } // namespace o2::mergers diff --git a/Utilities/Mergers/include/Mergers/MergerAlgorithm.h b/Utilities/Mergers/include/Mergers/MergerAlgorithm.h index 89955fe6407b2..bd5453afed4b1 100644 --- a/Utilities/Mergers/include/Mergers/MergerAlgorithm.h +++ b/Utilities/Mergers/include/Mergers/MergerAlgorithm.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/MergerBuilder.h b/Utilities/Mergers/include/Mergers/MergerBuilder.h index f9ed3a264cd6c..89c5350a97f91 100644 --- a/Utilities/Mergers/include/Mergers/MergerBuilder.h +++ b/Utilities/Mergers/include/Mergers/MergerBuilder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/MergerConfig.h b/Utilities/Mergers/include/Mergers/MergerConfig.h index 2ddd24b1c2993..9e027336d20ed 100644 --- a/Utilities/Mergers/include/Mergers/MergerConfig.h +++ b/Utilities/Mergers/include/Mergers/MergerConfig.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,8 @@ /// /// \author Piotr Konopka, piotr.jan.konopka@cern.ch +#include <string> + namespace o2::mergers { @@ -32,8 +35,11 @@ enum class MergedObjectTimespan { FullHistory, // Merged object should be an sum of differences received after last publication. // Merged object is reset after published. It won't produce meaningful results - // when InputObjectsTimespan::FullHstory is set. - LastDifference + // when InputObjectsTimespan::FullHistory is set. + LastDifference, + // Generalisation of the two above. Resets all objects in Mergers after n cycles (0 - infinite). + // The the above will be removed once we switch to NCycles in QC. + NCycles }; enum class PublicationDecision { @@ -54,9 +60,10 @@ struct ConfigEntry { // \brief MergerAlgorithm configuration structure. Default configuration should work in most cases, out of the box. struct MergerConfig { ConfigEntry<InputObjectsTimespan> inputObjectTimespan = {InputObjectsTimespan::FullHistory}; - ConfigEntry<MergedObjectTimespan> mergedObjectTimespan = {MergedObjectTimespan::FullHistory}; + ConfigEntry<MergedObjectTimespan, int> mergedObjectTimespan = {MergedObjectTimespan::FullHistory}; ConfigEntry<PublicationDecision> publicationDecision = {PublicationDecision::EachNSeconds, 10}; ConfigEntry<TopologySize, int> topologySize = {TopologySize::NumberOfLayers, 1}; + std::string monitoringUrl = "infologger:///debug?qc"; }; } // namespace o2::mergers diff --git a/Utilities/Mergers/include/Mergers/MergerInfrastructureBuilder.h b/Utilities/Mergers/include/Mergers/MergerInfrastructureBuilder.h index ea9ecba60e65a..c0cf6c786a26c 100644 --- a/Utilities/Mergers/include/Mergers/MergerInfrastructureBuilder.h +++ b/Utilities/Mergers/include/Mergers/MergerInfrastructureBuilder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/include/Mergers/ObjectStore.h b/Utilities/Mergers/include/Mergers/ObjectStore.h index 3c64dd22c1d8d..7fcbe3090c46f 100644 --- a/Utilities/Mergers/include/Mergers/ObjectStore.h +++ b/Utilities/Mergers/include/Mergers/ObjectStore.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/src/FullHistoryMerger.cxx b/Utilities/Mergers/src/FullHistoryMerger.cxx index 9504e603e2246..8f88ff2aee5b8 100644 --- a/Utilities/Mergers/src/FullHistoryMerger.cxx +++ b/Utilities/Mergers/src/FullHistoryMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -34,7 +35,6 @@ FullHistoryMerger::FullHistoryMerger(const MergerConfig& config, const header::D : mConfig(config), mSubSpec(subSpec) { - mCollector = monitoring::MonitoringFactory::Get("infologger:///debug?mergers"); } FullHistoryMerger::~FullHistoryMerger() @@ -46,6 +46,9 @@ FullHistoryMerger::~FullHistoryMerger() void FullHistoryMerger::init(framework::InitContext& ictx) { + mCyclesSinceReset = 0; + mCollector = monitoring::MonitoringFactory::Get(mConfig.monitoringUrl); + mCollector->addGlobalTag(monitoring::tags::Key::Subsystem, monitoring::tags::Value::Mergers); } void FullHistoryMerger::run(framework::ProcessingContext& ctx) @@ -61,11 +64,36 @@ void FullHistoryMerger::run(framework::ProcessingContext& ctx) } if (ctx.inputs().isValid("timer-publish") && !mFirstObjectSerialized.first.empty()) { + mCyclesSinceReset++; mergeCache(); publish(ctx.outputs()); + + if (mConfig.mergedObjectTimespan.value == MergedObjectTimespan::LastDifference || + mConfig.mergedObjectTimespan.value == MergedObjectTimespan::NCycles && mConfig.mergedObjectTimespan.param == mCyclesSinceReset) { + clear(); + } } } +// I am not calling it reset(), because it does not have to be performed during the FairMQs reset. +void FullHistoryMerger::clear() +{ + mFirstObjectSerialized.first.clear(); + delete mFirstObjectSerialized.second.header; + delete mFirstObjectSerialized.second.payload; + delete mFirstObjectSerialized.second.spec; + mFirstObjectSerialized.second.header = nullptr; + mFirstObjectSerialized.second.payload = nullptr; + mFirstObjectSerialized.second.spec = nullptr; + mMergedObject = std::monostate{}; + mCache.clear(); + mCyclesSinceReset = 0; + mTotalObjectsMerged = 0; + mObjectsMerged = 0; + mTotalUpdatesReceived = 0; + mUpdatesReceived = 0; +} + void FullHistoryMerger::updateCache(const DataRef& ref) { auto* dh = get<DataHeader*>(ref.header); @@ -77,14 +105,13 @@ void FullHistoryMerger::updateCache(const DataRef& ref) // We store one object in the serialized form, so we can take it as the first object to be merged (multiple times). // If we kept it deserialized, we would need to require implementing a clone() method in MergeInterface. - // Clang-Tidy: 'if' statement is unnecessary; deleting null pointer has no effect delete mFirstObjectSerialized.second.spec; delete mFirstObjectSerialized.second.header; delete mFirstObjectSerialized.second.payload; mFirstObjectSerialized.first = sourceID; mFirstObjectSerialized.second.spec = new InputSpec(*ref.spec); - mFirstObjectSerialized.second.header = new char[Stack::headerStackSize(reinterpret_cast<o2::byte const*>(dh))]; + mFirstObjectSerialized.second.header = new char[Stack::headerStackSize(reinterpret_cast<std::byte const*>(dh))]; memcpy((void*)mFirstObjectSerialized.second.header, ref.header, dh->headerSize); mFirstObjectSerialized.second.payload = new char[dh->payloadSize]; memcpy((void*)mFirstObjectSerialized.second.payload, ref.payload, dh->payloadSize); @@ -96,7 +123,7 @@ void FullHistoryMerger::updateCache(const DataRef& ref) void FullHistoryMerger::mergeCache() { - LOG(INFO) << "Merging " << mCache.size() + 1 << " objects."; + LOG(DEBUG) << "Merging " << mCache.size() + 1 << " objects."; mMergedObject = object_store_helpers::extractObjectFrom(mFirstObjectSerialized.second); assert(!std::holds_alternative<std::monostate>(mMergedObject)); @@ -128,13 +155,17 @@ void FullHistoryMerger::publish(framework::DataAllocator& allocator) { // todo see if std::visit is faster here if (std::holds_alternative<std::monostate>(mMergedObject)) { - LOG(INFO) << "Nothing to publish yet"; + LOG(INFO) << "No objects received since start or reset, nothing to publish"; } else if (std::holds_alternative<MergeInterfacePtr>(mMergedObject)) { allocator.snapshot(framework::OutputRef{MergerBuilder::mergerOutputBinding(), mSubSpec}, *std::get<MergeInterfacePtr>(mMergedObject)); + LOG(INFO) << "Published the merged object containing " << mCache.size() + 1 << " incomplete objects. " + << mUpdatesReceived << " updates were received during the last cycle."; } else if (std::holds_alternative<TObjectPtr>(mMergedObject)) { allocator.snapshot(framework::OutputRef{MergerBuilder::mergerOutputBinding(), mSubSpec}, *std::get<TObjectPtr>(mMergedObject)); + LOG(INFO) << "Published the merged object containing " << mCache.size() + 1 << " incomplete objects. " + << mUpdatesReceived << " updates were received during the last cycle."; } else { throw std::runtime_error("mMergedObject' variant has no value."); } @@ -145,6 +176,7 @@ void FullHistoryMerger::publish(framework::DataAllocator& allocator) mCollector->send({mObjectsMerged, "objects_merged_since_last_publication"}); mCollector->send({mTotalUpdatesReceived, "total_updates_received"}, monitoring::DerivedMetricMode::RATE); mCollector->send({mUpdatesReceived, "updates_received_since_last_publication"}); + mCollector->send({mCyclesSinceReset, "cycles_since_reset"}); mObjectsMerged = 0; mUpdatesReceived = 0; } diff --git a/Utilities/Mergers/src/IntegratingMerger.cxx b/Utilities/Mergers/src/IntegratingMerger.cxx index 0607e0e78888b..b9eeea725ff0b 100644 --- a/Utilities/Mergers/src/IntegratingMerger.cxx +++ b/Utilities/Mergers/src/IntegratingMerger.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,11 +23,8 @@ #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" -//#include "Framework/DataRef.h" -//using namespace o2; using namespace o2::framework; -//using namespace std::chrono; namespace o2::mergers { @@ -35,12 +33,13 @@ IntegratingMerger::IntegratingMerger(const MergerConfig& config, const header::D : mConfig(config), mSubSpec(subSpec) { - mCollector = monitoring::MonitoringFactory::Get("infologger:///debug?qc"); - // mCollector->enableProcessMonitoring(); } void IntegratingMerger::init(framework::InitContext& ictx) { + mCyclesSinceReset = 0; + mCollector = monitoring::MonitoringFactory::Get(mConfig.monitoringUrl); + mCollector->addGlobalTag(monitoring::tags::Key::Subsystem, monitoring::tags::Value::Mergers); } void IntegratingMerger::run(framework::ProcessingContext& ctx) @@ -50,54 +49,70 @@ void IntegratingMerger::run(framework::ProcessingContext& ctx) for (const DataRef& ref : InputRecordWalker(ctx.inputs())) { if (ref.header != timerHeader) { + auto other = object_store_helpers::extractObjectFrom(ref); if (std::holds_alternative<std::monostate>(mMergedObject)) { - mMergedObject = object_store_helpers::extractObjectFrom(ref); - + mMergedObject = std::move(object_store_helpers::extractObjectFrom(ref)); } else if (std::holds_alternative<TObjectPtr>(mMergedObject)) { // We expect that if the first object was TObject, then all should. - auto other = TObjectPtr(framework::DataRefUtils::as<TObject>(ref).release(), algorithm::deleteTCollections); - auto target = std::get<TObjectPtr>(mMergedObject); - algorithm::merge(target.get(), other.get()); + auto targetAsTObject = std::get<TObjectPtr>(mMergedObject); + auto otherAsTObject = std::get<TObjectPtr>(other); + algorithm::merge(targetAsTObject.get(), otherAsTObject.get()); } else if (std::holds_alternative<MergeInterfacePtr>(mMergedObject)) { // We expect that if the first object inherited MergeInterface, then all should. - auto other = framework::DataRefUtils::as<MergeInterface>(ref); - std::get<MergeInterfacePtr>(mMergedObject)->merge(other.get()); + auto otherAsMergeInterface = std::get<MergeInterfacePtr>(other); + std::get<MergeInterfacePtr>(mMergedObject)->merge(otherAsMergeInterface.get()); } else { throw std::runtime_error("mMergedObject' variant has no value."); } - mObjectsMerged++; + mDeltasMerged++; } } if (ctx.inputs().isValid("timer-publish")) { - + mCyclesSinceReset++; publish(ctx.outputs()); - if (mConfig.mergedObjectTimespan.value == MergedObjectTimespan::LastDifference) { - mMergedObject = std::monostate{}; + if (mConfig.mergedObjectTimespan.value == MergedObjectTimespan::LastDifference || + mConfig.mergedObjectTimespan.value == MergedObjectTimespan::NCycles && mConfig.mergedObjectTimespan.param == mCyclesSinceReset) { + clear(); } } } +// I am not calling it reset(), because it does not have to be performed during the FairMQs reset. +void IntegratingMerger::clear() +{ + mMergedObject = std::monostate{}; + mCyclesSinceReset = 0; + mTotalDeltasMerged = 0; + mDeltasMerged = 0; +} + void IntegratingMerger::publish(framework::DataAllocator& allocator) { + mTotalDeltasMerged += mDeltasMerged; + if (std::holds_alternative<std::monostate>(mMergedObject)) { - LOG(INFO) << "Nothing to publish yet"; + LOG(INFO) << "No objects received since start or reset, nothing to publish"; } else if (std::holds_alternative<MergeInterfacePtr>(mMergedObject)) { allocator.snapshot(framework::OutputRef{MergerBuilder::mergerOutputBinding(), mSubSpec}, *std::get<MergeInterfacePtr>(mMergedObject)); + LOG(INFO) << "Published the merged object with " << mTotalDeltasMerged << " deltas in total," + << " including " << mDeltasMerged << " in the last cycle."; } else if (std::holds_alternative<TObjectPtr>(mMergedObject)) { allocator.snapshot(framework::OutputRef{MergerBuilder::mergerOutputBinding(), mSubSpec}, *std::get<TObjectPtr>(mMergedObject)); + LOG(INFO) << "Published the merged object with " << mTotalDeltasMerged << " deltas in total," + << " including " << mDeltasMerged << " in the last cycle."; } else { throw std::runtime_error("mMergedObject' variant has no value."); } - mTotalObjectsMerged += mObjectsMerged; - mCollector->send({mTotalObjectsMerged, "total_objects_merged"}, monitoring::DerivedMetricMode::RATE); - mCollector->send({mObjectsMerged, "objects_merged_since_last_publication"}); - mObjectsMerged = 0; + mCollector->send({mTotalDeltasMerged, "total_deltas_merged"}, monitoring::DerivedMetricMode::RATE); + mCollector->send({mDeltasMerged, "deltas_merged_since_last_publication"}); + mCollector->send({mCyclesSinceReset, "cycles_since_reset"}); + mDeltasMerged = 0; } } // namespace o2::mergers diff --git a/Utilities/Mergers/src/MergerAlgorithm.cxx b/Utilities/Mergers/src/MergerAlgorithm.cxx index 6b0d263bd46ac..e87fb3eb023ff 100644 --- a/Utilities/Mergers/src/MergerAlgorithm.cxx +++ b/Utilities/Mergers/src/MergerAlgorithm.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -24,6 +25,7 @@ #include <TTree.h> #include <THnSparse.h> #include <TObjArray.h> +#include <TGraph.h> namespace o2::mergers::algorithm { @@ -81,6 +83,8 @@ void merge(TObject* const target, TObject* const other) errorCode = reinterpret_cast<THnBase*>(target)->Merge(&otherCollection); } else if (target->InheritsFrom(TTree::Class())) { errorCode = reinterpret_cast<TTree*>(target)->Merge(&otherCollection); + } else if (target->InheritsFrom(TGraph::Class())) { + errorCode = reinterpret_cast<TGraph*>(target)->Merge(&otherCollection); } else { throw std::runtime_error("Object with type '" + std::string(target->ClassName()) + "' is not one of the mergeable types."); } diff --git a/Utilities/Mergers/src/MergerBuilder.cxx b/Utilities/Mergers/src/MergerBuilder.cxx index ce70bd14265e6..8d60532b5bd72 100644 --- a/Utilities/Mergers/src/MergerBuilder.cxx +++ b/Utilities/Mergers/src/MergerBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/src/MergerInfrastructureBuilder.cxx b/Utilities/Mergers/src/MergerInfrastructureBuilder.cxx index 17301b5b68658..121f793cd3aa7 100644 --- a/Utilities/Mergers/src/MergerInfrastructureBuilder.cxx +++ b/Utilities/Mergers/src/MergerInfrastructureBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -104,9 +105,9 @@ framework::WorkflowSpec MergerInfrastructureBuilder::generateInfrastructure() size_t inputsPerMergerRemainder = layerInputs.size() % numberOfMergers; MergerConfig layerConfig = mConfig; - if (layer > 1 && mConfig.inputObjectTimespan.value == InputObjectsTimespan::LastDifference) { - layerConfig.inputObjectTimespan = {InputObjectsTimespan::FullHistory}; // in LastDifference mode only the first layer should integrate - layerConfig.mergedObjectTimespan = {MergedObjectTimespan::LastDifference}; // and objects that are merged should not be used again + if (layer < mergersPerLayer.size() - 1) { + // in intermediate layers we should reset the results, so the same data is not added many times. + layerConfig.mergedObjectTimespan = {MergedObjectTimespan::NCycles, 1}; } mergerBuilder.setConfig(layerConfig); diff --git a/Utilities/Mergers/src/ObjectStore.cxx b/Utilities/Mergers/src/ObjectStore.cxx index 3d549fb6885b3..82645a8586487 100644 --- a/Utilities/Mergers/src/ObjectStore.cxx +++ b/Utilities/Mergers/src/ObjectStore.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -36,7 +37,7 @@ ObjectStore extractObjectFrom(const framework::DataRef& ref) const static std::string errorPrefix = "Could not extract object to be merged: "; using DataHeader = o2::header::DataHeader; - auto header = o2::header::get<const DataHeader*>(ref.header); + auto header = framework::DataRefUtils::getHeader<const DataHeader*>(ref); if (header->payloadSerializationMethod != o2::header::gSerializationMethodROOT) { throw std::runtime_error(errorPrefix + "It is not ROOT-serialized"); } @@ -64,13 +65,18 @@ ObjectStore extractObjectFrom(const framework::DataRef& ref) errorPrefix + "Failed to read object with name '" + storedClass->GetName() + "' from message using ROOT serialization."); } - if (inheritsFromTObject) { - return TObjectPtr(static_cast<TObject*>(object), algorithm::deleteTCollections); + if (inheritsFromMergeInterface) { + MergeInterface* objectAsMergeInterface = inheritsFromTObject ? dynamic_cast<MergeInterface*>(static_cast<TObject*>(object)) : static_cast<MergeInterface*>(object); + if (objectAsMergeInterface == nullptr) { + throw std::runtime_error(errorPrefix + "Could not cast '" + storedClass->GetName() + "' to MergeInterface"); + } + objectAsMergeInterface->postDeserialization(); + return MergeInterfacePtr(objectAsMergeInterface); } else { - return MergeInterfacePtr(static_cast<MergeInterface*>(object)); + return TObjectPtr(static_cast<TObject*>(object), algorithm::deleteTCollections); } } } // namespace object_store_helpers -} // namespace o2::mergers \ No newline at end of file +} // namespace o2::mergers diff --git a/Utilities/Mergers/src/mergersTopologyExample.cxx b/Utilities/Mergers/src/mergersTopologyExample.cxx index 20faf41aebe4c..b3241507acb13 100644 --- a/Utilities/Mergers/src/mergersTopologyExample.cxx +++ b/Utilities/Mergers/src/mergersTopologyExample.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/benchmark_FullVsDiff.cxx b/Utilities/Mergers/test/benchmark_FullVsDiff.cxx index b20ea506682d8..0995774bb14a7 100644 --- a/Utilities/Mergers/test/benchmark_FullVsDiff.cxx +++ b/Utilities/Mergers/test/benchmark_FullVsDiff.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/benchmark_MergingCollections.cxx b/Utilities/Mergers/test/benchmark_MergingCollections.cxx index 701c4d4d38175..3336aedb8894c 100644 --- a/Utilities/Mergers/test/benchmark_MergingCollections.cxx +++ b/Utilities/Mergers/test/benchmark_MergingCollections.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/benchmark_Miscellaneous.cxx b/Utilities/Mergers/test/benchmark_Miscellaneous.cxx index 0d5e8fa64f1c4..225fcb297e626 100644 --- a/Utilities/Mergers/test/benchmark_Miscellaneous.cxx +++ b/Utilities/Mergers/test/benchmark_Miscellaneous.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/benchmark_Types.cxx b/Utilities/Mergers/test/benchmark_Types.cxx index e1ec7fba59af1..790fd329185ea 100644 --- a/Utilities/Mergers/test/benchmark_Types.cxx +++ b/Utilities/Mergers/test/benchmark_Types.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/emptyLoopBenchmark.cxx b/Utilities/Mergers/test/emptyLoopBenchmark.cxx index 2ec37b5f8895e..248c8022cff2d 100644 --- a/Utilities/Mergers/test/emptyLoopBenchmark.cxx +++ b/Utilities/Mergers/test/emptyLoopBenchmark.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/mergersBenchmarkTopology.cxx b/Utilities/Mergers/test/mergersBenchmarkTopology.cxx index 07ce0db27731a..5c0675e45ef6b 100644 --- a/Utilities/Mergers/test/mergersBenchmarkTopology.cxx +++ b/Utilities/Mergers/test/mergersBenchmarkTopology.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/multinodeBenchmarkMergers.cxx b/Utilities/Mergers/test/multinodeBenchmarkMergers.cxx index a5fdfad3cc7e7..79137b4709e68 100644 --- a/Utilities/Mergers/test/multinodeBenchmarkMergers.cxx +++ b/Utilities/Mergers/test/multinodeBenchmarkMergers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/multinodeBenchmarkProducers.cxx b/Utilities/Mergers/test/multinodeBenchmarkProducers.cxx index 4d1ff089a9a57..4f62e1a992164 100644 --- a/Utilities/Mergers/test/multinodeBenchmarkProducers.cxx +++ b/Utilities/Mergers/test/multinodeBenchmarkProducers.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/test_Algorithm.cxx b/Utilities/Mergers/test/test_Algorithm.cxx index 0082b4e381efb..9da139bf64cf1 100644 --- a/Utilities/Mergers/test/test_Algorithm.cxx +++ b/Utilities/Mergers/test/test_Algorithm.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -32,6 +33,8 @@ #include <TTree.h> #include <THnSparse.h> #include <TF1.h> +#include <TGraph.h> +#include <TProfile.h> //using namespace o2::framework; using namespace o2::mergers; @@ -189,6 +192,38 @@ BOOST_AUTO_TEST_CASE(MergerSingularObjects) delete other; delete target; } + { + constexpr Int_t points = 5; + Double_t x1[] = {0, 1, 2, 3, 4}; + Double_t y1[] = {0, 1, 2, 3, 4}; + Double_t x2[] = {5, 6, 7, 8, 9}; + Double_t y2[] = {5, 6, 7, 8, 9}; + + TGraph* target = new TGraph(points, x1, y1); + TGraph* other = new TGraph(points, x2, y2); + + BOOST_CHECK_NO_THROW(algorithm::merge(target, other)); + BOOST_CHECK_EQUAL(target->GetN(), 2 * points); + + delete other; + delete target; + } + { + auto target = new TProfile("hprof1", "hprof1", bins, min, max, min, max); + target->Fill(2, 2, 1); + auto other = new TProfile("hprof2", "hprof2", bins, min, max, min, max); + other->Fill(5, 5, 1); + + BOOST_CHECK_NO_THROW(algorithm::merge(target, other)); + BOOST_CHECK_EQUAL(target->GetEntries(), 2); + BOOST_CHECK_EQUAL(target->GetBinContent(target->FindBin(0)), 0); + BOOST_CHECK_EQUAL(target->GetBinContent(target->FindBin(1)), 0); + BOOST_CHECK_CLOSE(target->GetBinContent(target->FindBin(2)), 2, 0.001); + BOOST_CHECK_CLOSE(target->GetBinContent(target->FindBin(5)), 5, 0.001); + + delete other; + delete target; + } { auto* target = new CustomMergeableTObject("obj1", 123); auto* other = new CustomMergeableTObject("obj2", 321); diff --git a/Utilities/Mergers/test/test_InfrastructureBuilder.cxx b/Utilities/Mergers/test/test_InfrastructureBuilder.cxx index a83507ed9906d..12001622b2338 100644 --- a/Utilities/Mergers/test/test_InfrastructureBuilder.cxx +++ b/Utilities/Mergers/test/test_InfrastructureBuilder.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/Utilities/Mergers/test/test_ObjectStore.cxx b/Utilities/Mergers/test/test_ObjectStore.cxx index 3680fdef4d241..7c3bd019ce45b 100644 --- a/Utilities/Mergers/test/test_ObjectStore.cxx +++ b/Utilities/Mergers/test/test_ObjectStore.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -50,9 +51,9 @@ BOOST_AUTO_TEST_CASE(TestObjectExtraction) DataRef ref = makeDataRef(obj); auto objStore = object_store_helpers::extractObjectFrom(ref); - BOOST_REQUIRE(std::holds_alternative<TObjectPtr>(objStore)); + BOOST_REQUIRE(std::holds_alternative<MergeInterfacePtr>(objStore)); - auto objExtractedCustom = dynamic_cast<CustomMergeableTObject*>(std::get<TObjectPtr>(objStore).get()); + auto objExtractedCustom = dynamic_cast<CustomMergeableTObject*>(std::get<MergeInterfacePtr>(objStore).get()); BOOST_REQUIRE(objExtractedCustom != nullptr); BOOST_CHECK_EQUAL(objExtractedCustom->getSecret(), 123); diff --git a/Utilities/O2Device/CMakeLists.txt b/Utilities/O2Device/CMakeLists.txt deleted file mode 100644 index 5fb7f0d44265e..0000000000000 --- a/Utilities/O2Device/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(Device - SOURCES src/O2Device.cxx - PUBLIC_LINK_LIBRARIES FairMQ::FairMQ O2::MemoryResources - O2::Headers ms_gsl::ms_gsl - AliceO2::Monitoring) -if(NOT APPLE) - o2_add_test(O2Device - SOURCES test/test_O2Device.cxx - PUBLIC_LINK_LIBRARIES O2::Device - COMPONENT_NAME Device) -endif() diff --git a/Utilities/O2Device/README.md b/Utilities/O2Device/README.md deleted file mode 100644 index 79ba57eabb003..0000000000000 --- a/Utilities/O2Device/README.md +++ /dev/null @@ -1,78 +0,0 @@ -<!-- doxy -\page refUtilitiesO2Device O2Device -/doxy --> - -# O2Device - -The O2Device is meant to build O2 specific behaviours on top of plain FairMQDevices. - -# O2Device utilities - -The header **O2Device/Utilities.h** contains utilities that enable consistent handling of -data in the O2 format and some useful definitions. - -```O2Message``` - currently alias of FairMQPArts, contains FairMQMessages in header-payload order - -### addDataBlock() -Allows to consistently create O2 compatible messages for FairMQ transport. -Appends a header::Stack-data pair to message. Sets the data size in the DataHeader inside the stack based either on the message/container size. - -``` -template <typename T> -addDataBlock(O2Message& message, o2::header::Stack&& headerStack, T data); -``` -#### arguments: -- headerStack: as the name implies. - -- data: - - ```FairMQMessagePtr``` (```std::unique_ptr<FairMQMessage>```) - - STL-like container that uses a ```pmr::polymorphic_allocator``` as allocator. Note: this is only efficient if - the memory resource used to construct the allocator is ```o2::pmr::ChannelResource```, otherwise an implicit copy occurs. - -### forEach() -Executes a function on each data block within the message. - -``` -template<typename T> -T forEach(O2Message& message, T function); -``` -#### arguments: -the function is a callable object (lambda, functor, std::function) and needs to take two arguents of type gsl::span, first one points to the header buffer, second one points to the payload buffer, e.g. ```[](span header, span payload) {}```. - - -#### basic example, inside a FairMQDevice: -```C++ -// make sure we have the allocator associated with the transport appropriate for the selected channel: -auto outputChannelAllocator = o2::pmr::getTransportAllocator(GetChannel("dataOut").Transport()); - -//the data -using namespace boost::container::pmr; -o2::pmr::vector<int> dataVector(outputChannelAllocator); -dataVector.reserve(10); -dataVector.push_back(1); -dataVector.push_back(2); - -//create the message -O2message message; -addDataBlock(message, - o2::header::Stack{outputChannelAllocator, DataHeader{<args>}}, - std::move(dataVector)); - -addDataBlock(message, - o2::header::Stack{outputChannelAllocator, DataHeader{<args>}}, - NewMessageFor("dataOut",0,"some message string")); - -Send(message,"dataOut"); - -//On the receiving end: -O2Message messageIn; -Receive(messageIn, "dataIn"); -forEach(messageIn, [](span header, span payload) { - auto dataHeader = get<DataHeader*>(header.data()); - if (dataHeader->dataDescription==gDataDescriptionMyDataType) { - MyDataType* myData = reinterpret_cast<MyDataType*>(payload.data()); - } -}); - -``` - diff --git a/Utilities/O2Device/include/O2Device/Compatibility.h b/Utilities/O2Device/include/O2Device/Compatibility.h deleted file mode 100644 index 851dc8139f04e..0000000000000 --- a/Utilities/O2Device/include/O2Device/Compatibility.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef ALICEO2_UTILITIES_O2DEVICE_COMPATIBILITY_H_ -#define ALICEO2_UTILITIES_O2DEVICE_COMPATIBILITY_H_ - -#include <type_traits> - -namespace o2 -{ -namespace compatibility -{ - -template <typename T> -class FairMQ13 -{ - private: - template <typename C> - static std::true_type test(decltype(&C::NewStatePending)); - template <typename C> - static std::false_type test(...); - - public: - static bool IsRunning(T* device) - { - if constexpr (std::is_same_v<decltype(test<T>(nullptr)), std::true_type>) { - return !device->NewStatePending(); - } else if constexpr (std::is_same_v<decltype(test<T>(nullptr)), std::false_type>) { - return device->CheckCurrentState(T::RUNNING); - } - } -}; - -} // namespace compatibility -} // namespace o2 - -#endif // ALICEO2_UTILITIES_O2DEVICE_COMPATIBILITY_H_ diff --git a/Utilities/O2Device/include/O2Device/O2Device.h b/Utilities/O2Device/include/O2Device/O2Device.h deleted file mode 100644 index 59c3b0eb6b2b5..0000000000000 --- a/Utilities/O2Device/include/O2Device/O2Device.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @headerfile O2Device.h -/// -/// @since 2014-12-10 -/// @author M. Krzewicki <mkrzewic@cern.ch> - -#ifndef O2DEVICE_H_ -#define O2DEVICE_H_ - -#include <FairMQDevice.h> -#include <options/FairMQProgOptions.h> -#include "O2Device/Utilities.h" -#include "Monitoring/MonitoringFactory.h" -#include <stdexcept> - -namespace o2 -{ -namespace base -{ - -/// just a typedef to express the fact that it is not just a FairMQParts vector, -/// it has to follow the O2 convention of header-payload-header-payload -class O2Device : public FairMQDevice -{ - public: - using FairMQDevice::FairMQDevice; - - ~O2Device() override = default; - - /// Monitoring instance - std::unique_ptr<o2::monitoring::Monitoring> monitoring; - - /// Provides monitoring instance - auto GetMonitoring() { return monitoring.get(); } - - /// Connects to a monitoring backend - void Init() override - { - FairMQDevice::Init(); - static constexpr const char* MonitoringUrlKey = "monitoring-url"; - std::string monitoringUrl = GetConfig()->GetValue<std::string>(MonitoringUrlKey); - if (!monitoringUrl.empty()) { - monitoring->addBackend(o2::monitoring::MonitoringFactory::GetBackend(monitoringUrl)); - } - } - - private: -}; -} // namespace base -} // namespace o2 -#endif /* O2DEVICE_H_ */ diff --git a/Utilities/O2Device/include/O2Device/Utilities.h b/Utilities/O2Device/include/O2Device/Utilities.h deleted file mode 100644 index 398086cc009b0..0000000000000 --- a/Utilities/O2Device/include/O2Device/Utilities.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @brief standalone tools to interact with the O2 data model -/// -/// @author Mikolaj Krzewicki, mkrzewic@cern.ch - -#ifndef ALICEO2_BASE_O2DEVICE_UTILITIES_ -#define ALICEO2_BASE_O2DEVICE_UTILITIES_ - -#include "MemoryResources/MemoryResources.h" -#include "Headers/DataHeader.h" -#include "Headers/Stack.h" - -#include <utility> -#include <gsl/gsl> - -namespace o2 -{ -namespace base -{ - -using O2Message = FairMQParts; - -//__________________________________________________________________________________________________ -// addDataBlock for generic (compatible) containers, that is contiguous containers using the pmr allocator -template <typename ContainerT, typename std::enable_if<!std::is_same<ContainerT, FairMQMessagePtr>::value, int>::type = 0> -bool addDataBlock(O2Message& parts, o2::header::Stack&& inputStack, ContainerT&& inputData, o2::pmr::FairMQMemoryResource* targetResource = nullptr) -{ - using std::forward; - using std::move; - - auto headerMessage = getMessage(move(inputStack), targetResource); - auto dataMessage = getMessage(forward<ContainerT>(inputData), targetResource); - - parts.AddPart(move(headerMessage)); - parts.AddPart(move(dataMessage)); - - return true; -} - -//__________________________________________________________________________________________________ -// addDataBlock for data already wrapped in FairMQMessagePtr -// note: since we cannot partially specialize function templates, use SFINAE here instead -template <typename ContainerT, typename std::enable_if<std::is_same<ContainerT, FairMQMessagePtr>::value, int>::type = 0> -bool addDataBlock(O2Message& parts, o2::header::Stack&& inputStack, ContainerT&& dataMessage, o2::pmr::FairMQMemoryResource* targetResource = nullptr) -{ - using std::move; - - //make sure the payload size in DataHeader corresponds to message size - using o2::header::DataHeader; - DataHeader* dataHeader = const_cast<DataHeader*>(o2::header::get<DataHeader*>(inputStack.data())); - dataHeader->payloadSize = dataMessage->GetSize(); - - auto headerMessage = getMessage(move(inputStack), targetResource); - - parts.AddPart(move(headerMessage)); - parts.AddPart(move(dataMessage)); - - return true; -} - -namespace internal -{ - -template <typename I, typename F> -auto forEach(I begin, I end, F&& function) -{ - using span = gsl::span<const o2::byte>; - using gsl::narrow_cast; - for (auto it = begin; it != end; ++it) { - o2::byte* headerBuffer{nullptr}; - span::index_type headerBufferSize{0}; - if (*it != nullptr) { - headerBuffer = reinterpret_cast<o2::byte*>((*it)->GetData()); - headerBufferSize = narrow_cast<span::index_type>((*it)->GetSize()); - } - ++it; - o2::byte* dataBuffer{nullptr}; - span::index_type dataBufferSize{0}; - if (*it != nullptr) { - dataBuffer = reinterpret_cast<o2::byte*>((*it)->GetData()); - dataBufferSize = narrow_cast<span::index_type>((*it)->GetSize()); - } - - // call the user provided function - function(span{headerBuffer, headerBufferSize}, span{dataBuffer, dataBufferSize}); - } - return std::move(function); -} -}; //namespace internal - -/// Execute user code (e.g. a lambda) on each data block (header-payload pair) -/// returns the function (same as std::for_each) -template <typename F> -auto forEach(O2Message& parts, F&& function) -{ - if ((parts.Size() % 2) != 0) { - throw std::invalid_argument( - "number of parts in message not even (n%2 != 0), cannot be considered an O2 compliant message"); - } - - return internal::forEach(parts.begin(), parts.end(), std::forward<F>(function)); -} - -} // namespace base -} // namespace o2 - -#endif diff --git a/Utilities/O2Device/src/O2Device.cxx b/Utilities/O2Device/src/O2Device.cxx deleted file mode 100644 index acf891388579a..0000000000000 --- a/Utilities/O2Device/src/O2Device.cxx +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @file O2Device.cpp -/// -/// @since 2014-12-10 -/// @author M.Krzewicki <mkrzewic@cern.ch> - -#include "O2Device/O2Device.h" diff --git a/Utilities/O2Device/test/test_O2Device.cxx b/Utilities/O2Device/test/test_O2Device.cxx deleted file mode 100644 index 2f679b850f05f..0000000000000 --- a/Utilities/O2Device/test/test_O2Device.cxx +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test O2Device -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -#include "O2Device/O2Device.h" -#include "Headers/NameHeader.h" -#include <boost/test/unit_test.hpp> -#include <iostream> -#include <vector> -#include <fairmq/Tools.h> -#include <fairmq/ProgOptions.h> - -using namespace o2::base; -using namespace o2::header; -using namespace o2::pmr; - -BOOST_AUTO_TEST_CASE(getMessage_Stack) -{ - size_t session{fair::mq::tools::UuidHash()}; - fair::mq::ProgOptions config; - config.SetProperty<std::string>("session", std::to_string(session)); - - auto factoryZMQ = FairMQTransportFactory::CreateTransportFactory("zeromq"); - auto factorySHM = FairMQTransportFactory::CreateTransportFactory("shmem"); - auto allocZMQ = getTransportAllocator(factoryZMQ.get()); - auto allocSHM = getTransportAllocator(factorySHM.get()); - { - //check that a message is constructed properly with the default new_delete_resource - Stack s1{DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}, - NameHeader<9>{"somename"}}; - - auto message = o2::pmr::getMessage(std::move(s1), allocZMQ); - - BOOST_REQUIRE(s1.data() == nullptr); - BOOST_REQUIRE(message != nullptr); - auto* h3 = get<NameHeader<0>*>(message->GetData()); - BOOST_REQUIRE(h3 != nullptr); - BOOST_CHECK(h3->getNameLength() == 9); - BOOST_CHECK(0 == std::strcmp(h3->getName(), "somename")); - BOOST_CHECK(message->GetType() == fair::mq::Transport::ZMQ); - } - { - //check that a message is constructed properly, cross resource - Stack s1{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}, - NameHeader<9>{"somename"}}; - BOOST_TEST(allocZMQ->getNumberOfMessages() == 1); - - auto message = o2::pmr::getMessage(std::move(s1), allocSHM); - - BOOST_TEST(allocZMQ->getNumberOfMessages() == 0); - BOOST_TEST(allocSHM->getNumberOfMessages() == 0); - BOOST_REQUIRE(s1.data() == nullptr); - BOOST_REQUIRE(message != nullptr); - auto* h3 = get<NameHeader<0>*>(message->GetData()); - BOOST_REQUIRE(h3 != nullptr); - BOOST_CHECK(h3->getNameLength() == 9); - BOOST_CHECK(0 == std::strcmp(h3->getName(), "somename")); - BOOST_CHECK(message->GetType() == fair::mq::Transport::SHM); - } -} - -BOOST_AUTO_TEST_CASE(addDataBlockForEach_test) -{ - size_t session{fair::mq::tools::UuidHash()}; - fair::mq::ProgOptions config; - config.SetProperty<std::string>("session", std::to_string(session)); - - auto factoryZMQ = FairMQTransportFactory::CreateTransportFactory("zeromq"); - auto allocZMQ = getTransportAllocator(factoryZMQ.get()); - - { - //simple addition of a data block from an exisiting message - O2Message message; - auto simpleMessage = factoryZMQ->CreateMessage(10); - addDataBlock(message, - Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, - std::move(simpleMessage)); - BOOST_CHECK(message.Size() == 2); - } - - { - int sizeofDataHeader = sizeof(o2::header::DataHeader); - struct elem { - int i; - int j; - }; - using namespace boost::container::pmr; - O2Message message; - std::vector<elem, polymorphic_allocator<elem>> vec(polymorphic_allocator<elem>{allocZMQ}); - vec.reserve(100); - vec.push_back({1, 2}); - vec.push_back({3, 4}); - - addDataBlock(message, - Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, - std::move(vec)); - BOOST_CHECK(message.Size() == 2); - BOOST_CHECK(vec.size() == 0); - BOOST_CHECK(message[0].GetSize() == sizeofDataHeader); - BOOST_CHECK(message[1].GetSize() == 2 * sizeof(elem)); //check the size of the buffer is set correctly - - //check contents - int sum{0}; - forEach(message, [&](auto header, auto data) { - const int* numbers = reinterpret_cast<const int*>(data.data()); - sum = numbers[0] + numbers[1] + numbers[2] + numbers[3]; - }); - BOOST_CHECK(sum == 10); - - //add one more data block and check total size using forEach; - addDataBlock(message, - Stack{allocZMQ, DataHeader{gDataDescriptionInvalid, gDataOriginInvalid, DataHeader::SubSpecificationType{0}}}, - factoryZMQ->CreateMessage(10)); - int size{0}; - forEach(message, [&](auto header, auto data) { size += header.size() + data.size(); }); - BOOST_CHECK(size == sizeofDataHeader + 2 * sizeof(elem) + sizeofDataHeader + 10); - - //check contents (headers) - int checkOK{0}; - forEach(message, [&](auto header, auto data) { - auto dh = get<DataHeader*>(header.data()); - if (dh->dataDescription == gDataDescriptionInvalid && dh->dataOrigin == gDataOriginInvalid) { - checkOK++; - }; - }); - BOOST_CHECK(checkOK == 2); - } -} diff --git a/Utilities/O2MessageMonitor/CMakeLists.txt b/Utilities/O2MessageMonitor/CMakeLists.txt deleted file mode 100644 index e705802c1028b..0000000000000 --- a/Utilities/O2MessageMonitor/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -o2_add_library(MessageMonitor - SOURCES src/O2MessageMonitor.cxx - PUBLIC_LINK_LIBRARIES FairLogger::FairLogger FairMQ::FairMQ - O2::Device) - -o2_add_executable(message-monitor - SOURCES src/runO2MessageMonitor.cxx - PUBLIC_LINK_LIBRARIES O2::MessageMonitor) - -o2_add_test(O2MessageMonitorTest - SOURCES test/O2MessageMonitorTest.cxx - PUBLIC_LINK_LIBRARIES O2::MessageMonitor - LABELS utils) diff --git a/Utilities/O2MessageMonitor/include/O2MessageMonitor/O2MessageMonitor.h b/Utilities/O2MessageMonitor/include/O2MessageMonitor/O2MessageMonitor.h deleted file mode 100644 index a54322d3e92ee..0000000000000 --- a/Utilities/O2MessageMonitor/include/O2MessageMonitor/O2MessageMonitor.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @file O2MessageMonitor.h -/// -/// @since 2014-12-10 -/// @author M. Krzewicki <mkrzewic@cern.ch> - -#ifndef O2MESSAGEMONITOR_H_ -#define O2MESSAGEMONITOR_H_ - -#include "O2Device/O2Device.h" - -/// This is a simple FairMQ monitoring class -/// assumption is the messages are O@ messages (constructed supported -/// methods in O2Device). -/// The "data" channel can be configured as any socket type, -/// it will appropriately send requests, send/receive messages or send replies. -/// All incoming traffic is dumped on screen in the form of a hex dump for both -/// the header block and payload block. -class O2MessageMonitor : public o2::base::O2Device -{ - public: - O2MessageMonitor() = default; - ~O2MessageMonitor() override = default; - - protected: - void Run() override; - void InitTask() override; - - private: - std::string mPayload{"I am the info payload"}; - std::string mName{R"(My name is "gDataDescriptionInfo")"}; - long long mDelay{1000}; - long long mIterations{10}; - long long mLimitOutputCharacters{1024}; -}; - -#endif /* O2MESSAGEMONITOR_H_ */ diff --git a/Utilities/O2MessageMonitor/src/O2MessageMonitor.cxx b/Utilities/O2MessageMonitor/src/O2MessageMonitor.cxx deleted file mode 100644 index 1d2dc6f8dfa0b..0000000000000 --- a/Utilities/O2MessageMonitor/src/O2MessageMonitor.cxx +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @file O2MessageMonitor.cxx -/// -/// @since 2014-12-10 -/// @author M. Krzewicki <mkrzewic@cern.ch> - -#include <chrono> -#include <thread> // this_thread::sleep_for - -#include <FairMQLogger.h> -#include <options/FairMQProgOptions.h> -#include "O2MessageMonitor/O2MessageMonitor.h" -#include "O2Device/Compatibility.h" - -using namespace std; -using namespace o2::header; -using namespace o2::base; -using namespace o2::compatibility; - -//__________________________________________________________________________________________________ -void O2MessageMonitor::InitTask() -{ - mDelay = GetConfig()->GetValue<int>("sleep"); - mIterations = GetConfig()->GetValue<int>("n"); - mPayload = GetConfig()->GetValue<std::string>("payload"); - std::string tmp = GetConfig()->GetValue<std::string>("name"); - if (!tmp.empty()) { - mName = tmp; - } - mLimitOutputCharacters = GetConfig()->GetValue<int>("limit"); -} - -//__________________________________________________________________________________________________ -void O2MessageMonitor::Run() -{ - // check socket type of data channel - std::string type; - std::vector<FairMQChannel>& subChannels = fChannels["data"]; - if (subChannels.size() > 0) { - type = subChannels[0].GetType(); - } - - auto dataResource = o2::pmr::getTransportAllocator(subChannels[0].Transport()); - - while (FairMQ13<FairMQDevice>::IsRunning(this) && (--mIterations) != 0) { - this_thread::sleep_for(chrono::milliseconds(mDelay)); - - O2Message message; - - // maybe send a request - if (type == "req") { - addDataBlock(message, {dataResource, DataHeader{gDataDescriptionInfo, gDataOriginAny, DataHeader::SubSpecificationType{0}}}, - NewSimpleMessageFor("data", 0, mPayload)); - Send(message, "data"); - message.fParts.clear(); - } - - // message in; - Receive(message, "data"); - LOG(INFO) << "== New message============================="; - o2::base::forEach(message, [&](auto header, auto data) { - hexDump("headerBuffer", header.data(), header.size()); - hexDump("dataBuffer", data.data(), data.size(), mLimitOutputCharacters); - }); - message.fParts.clear(); - - // maybe a reply message - if (type == "rep") { - o2::base::addDataBlock(message, - {dataResource, DataHeader{gDataDescriptionInfo, gDataOriginAny, DataHeader::SubSpecificationType{0}}}, - NewSimpleMessageFor("data", 0, "")); - Send(message, "data"); - } - } -} diff --git a/Utilities/O2MessageMonitor/src/runO2MessageMonitor.cxx b/Utilities/O2MessageMonitor/src/runO2MessageMonitor.cxx deleted file mode 100644 index 069875b28abdf..0000000000000 --- a/Utilities/O2MessageMonitor/src/runO2MessageMonitor.cxx +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @copyright -/// © Copyright 2014 Copyright Holders of the ALICE O2 collaboration. -/// See https://aliceinfo.cern.ch/AliceO2 for details on the Copyright holders. -/// This software is distributed under the terms of the -/// GNU General Public License version 3 (GPL Version 3). -/// -/// License text in a separate file. -/// -/// In applying this license, CERN does not waive the privileges and immunities -/// granted to it by virtue of its status as an Intergovernmental Organization -/// or submit itself to any jurisdiction. - -/// @file runO2MessageMonitor.h -/// -/// @since 2014-12-10 -/// @author M. Krzewicki <mkrzewic@cern.ch> - -#include "runFairMQDevice.h" -#include "O2MessageMonitor/O2MessageMonitor.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - ("n",bpo::value<int>()->default_value(-1), "How many loops"); - options.add_options() - ("sleep",bpo::value<int>()->default_value(0), "sleep between loops in milliseconds"); - options.add_options() - ("limit",bpo::value<int>()->default_value(0), "limit output of payload to n characters"); - options.add_options() - ("payload",bpo::value<std::string>()-> - default_value("I am the info payload"), "the info string in the payload"); - options.add_options() - ("name",bpo::value<std::string>()->default_value(""), "optional name in the header"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new O2MessageMonitor(); -} diff --git a/Utilities/O2MessageMonitor/test/O2MessageMonitor.json b/Utilities/O2MessageMonitor/test/O2MessageMonitor.json deleted file mode 100644 index 99f05d098e100..0000000000000 --- a/Utilities/O2MessageMonitor/test/O2MessageMonitor.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "fairMQOptions": { - "devices": [ - { - "id": "source1", - "channels": [ - { - "name": "data", - "sockets": [ - { - "type": "push", - "method": "connect", - "address": "tcp://localhost:5555", - "sndBufSize": 1000, - "rcvBufSize": 1000, - "rateLogging": 0 - } - ] - } - ] - }, - { - "id": "sink1", - "channels": [ - { - "name": "data", - "sockets": [ - { - "type": "pull", - "method": "bind", - "address": "tcp://*:5555", - "sndBufSize": 1000, - "rcvBufSize": 1000, - "rateLogging": 0 - } - ] - } - ] - } - ] - } -} diff --git a/Utilities/O2MessageMonitor/test/O2MessageMonitorTest.cxx b/Utilities/O2MessageMonitor/test/O2MessageMonitorTest.cxx deleted file mode 100644 index 03ab99004767c..0000000000000 --- a/Utilities/O2MessageMonitor/test/O2MessageMonitorTest.cxx +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -int main() -{ -} diff --git a/Utilities/O2MessageMonitor/test/runO2MessageMonitor.sh b/Utilities/O2MessageMonitor/test/runO2MessageMonitor.sh deleted file mode 100644 index 6b48661e3e484..0000000000000 --- a/Utilities/O2MessageMonitor/test/runO2MessageMonitor.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -#here's how to use it: -#o2-message-monitor --id source1 --mq-config O2MessageMonitor.json -#o2-message-monitor --id sink1 --mq-config O2MessageMonitor.json diff --git a/Utilities/PCG/CMakeLists.txt b/Utilities/PCG/CMakeLists.txt index d53bec96dff6d..5d0fdd8756b3a 100644 --- a/Utilities/PCG/CMakeLists.txt +++ b/Utilities/PCG/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # @author Piotr Konopka diff --git a/Utilities/Publishers/CMakeLists.txt b/Utilities/Publishers/CMakeLists.txt deleted file mode 100644 index 5308ec1250739..0000000000000 --- a/Utilities/Publishers/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -# FIXME: do we actually need a library here ? -o2_add_library(Publishers - SOURCES src/DataPublisherDevice.cxx - PUBLIC_LINK_LIBRARIES O2::Device) - -o2_add_executable(datapublisher-device - PUBLIC_LINK_LIBRARIES O2::Publishers - SOURCES src/runDataPublisherDevice.cxx) diff --git a/Utilities/Publishers/include/Publishers/DataPublisherDevice.h b/Utilities/Publishers/include/Publishers/DataPublisherDevice.h deleted file mode 100644 index 342acbf3dbbc6..0000000000000 --- a/Utilities/Publishers/include/Publishers/DataPublisherDevice.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef DATAPUBLISHERDEVICE_H -#define DATAPUBLISHERDEVICE_H - -/// @file DataPublisherDevice.h -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-10 -/// @brief Utility device for data publishing - -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" -#include "O2Device/O2Device.h" -#include <cstring> -#include <vector> - -class FairMQParts; - -namespace o2 -{ -namespace utilities -{ - -/// @class DataPublisherDevice -/// Utility device for data publishing -/// -/// TODO: Generalize with an input policy -class DataPublisherDevice final : public base::O2Device -{ - public: - typedef o2::base::O2Message O2Message; - /// TODO: use type alias when it has been added to DataHeader.h - typedef uint64_t SubSpecificationT; - - static constexpr const char* OptionKeyInputChannelName = "in-chan-name"; - static constexpr const char* OptionKeyOutputChannelName = "out-chan-name"; - static constexpr const char* OptionKeyDataDescription = "data-description"; - static constexpr const char* OptionKeyDataOrigin = "data-origin"; - static constexpr const char* OptionKeySubspecification = "sub-specification"; - static constexpr const char* OptionKeyFileName = "filename"; - - /// Default constructor - DataPublisherDevice(); - - /// Default destructor - ~DataPublisherDevice() final; - - protected: - /// overloading the InitTask() method of FairMQDevice - void InitTask() final; - - /// data handling method to be registered as handler in the - /// FairMQDevice API method OnData - /// The device base class handles the state loop in the RUNNING - /// state and calls the handler when receiving a message on one channel - /// The multiple parts included in one message are provided in the - /// FairMQParts object. - bool HandleData(FairMQParts& msgParts, int index); - - /// handle one logical O2 block of the input, consists of header and payload - bool HandleO2LogicalBlock(const byte* headerBuffer, size_t headerBufferSize, - const byte* dataBuffer, size_t dataBufferSize); - - /// Read file and append to the buffer - static bool AppendFile(const char* name, std::vector<o2::byte>& buffer); - - private: - /// configurable name of input channel - std::string mInputChannelName; - /// configurable name of output channel - std::string mOutputChannelName; - /// index of the previously handled data channel in HandleData - int mLastIndex; - /// the default data description - o2::header::DataDescription mDataDescription; - /// the default data description - o2::header::DataOrigin mDataOrigin; - /// the default data sub specification - SubSpecificationT mSubSpecification; - /// buffer for the file to read - /// Note the shift by sizeof(HeartbeatHeader) - std::vector<o2::byte> mFileBuffer; - std::string mFileName; -}; - -} // namespace utilities -}; // namespace o2 -#endif diff --git a/Utilities/Publishers/src/DataPublisherDevice.cxx b/Utilities/Publishers/src/DataPublisherDevice.cxx deleted file mode 100644 index 598ac8c5413e7..0000000000000 --- a/Utilities/Publishers/src/DataPublisherDevice.cxx +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DataPublisherDevice.cxx -/// @author Giulio Eulisse, Matthias Richter, Sandro Wenzel -/// @since 2017-02-10 -/// @brief Utility device for data publishing - -#include "Publishers/DataPublisherDevice.h" -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" -#include "Headers/SubframeMetadata.h" -#include <options/FairMQProgOptions.h> - -using HeartbeatHeader = o2::header::HeartbeatHeader; -using HeartbeatTrailer = o2::header::HeartbeatTrailer; -using TPCTestCluster = o2::data_flow::TPCTestCluster; -using ITSRawData = o2::data_flow::ITSRawData; - -using DataDescription = o2::header::DataDescription; -using DataOrigin = o2::header::DataOrigin; - -template <typename T> -void fakePayload(std::vector<o2::byte>& buffer, std::function<void(T&, int)> filler, int numOfElements) -{ - auto payloadSize = sizeof(T) * numOfElements; - LOG(INFO) << "Payload size " << payloadSize << "\n"; - buffer.resize(buffer.size() + payloadSize); - - T* payload = reinterpret_cast<T*>(buffer.data() + sizeof(HeartbeatHeader)); - for (int i = 0; i < numOfElements; ++i) { - new (payload + i) T(); - // put some random toy time stamp to each cluster - filler(payload[i], i); - } -} - -namespace o2 -{ -namespace utilities -{ - -DataPublisherDevice::DataPublisherDevice() - : O2Device(), mInputChannelName("input"), mOutputChannelName("output"), mLastIndex(-1), mDataDescription(), mDataOrigin(), mSubSpecification(~(SubSpecificationT)0), mFileName() -{ -} - -DataPublisherDevice::~DataPublisherDevice() = default; - -void DataPublisherDevice::InitTask() -{ - mInputChannelName = GetConfig()->GetValue<std::string>(OptionKeyInputChannelName); - mOutputChannelName = GetConfig()->GetValue<std::string>(OptionKeyOutputChannelName); - // TODO: this turned out to be a missing feature in the description fields of - // the different headers. The idea is to use a field of n bytes as an integer - // but create the integers from a char sequence. This was thought to be done - // at compile time, but here we want to have it configurable at runtime. - // - // GetConfig()->GetValue<std::string>(OptionKeyDataDescription).c_str() - // GetConfig()->GetValue<std::string>(OptionKeyDataOrigin).c_str() - // - // Still needed: - // * a registry for descriptors (probably for different descriptor types of - // even the same size) to ensure uniqueness - // * create the unsigned integer value once from the configurable string and - // check in the registry - // * constructors and assignment operators taking the integer type as argument - if (GetConfig()->GetValue<std::string>(OptionKeyDataDescription) == "TPCCLUSTER") { - mDataDescription = DataDescription("CLUSTERS"); - mDataOrigin = DataOrigin("TPC"); - } else if (GetConfig()->GetValue<std::string>(OptionKeyDataDescription) == "ITSRAW") { - mDataDescription = DataDescription("CLUSTERS"); - mDataOrigin = DataOrigin("ITS"); - } - mSubSpecification = GetConfig()->GetValue<SubSpecificationT>(OptionKeySubspecification); - mFileName = GetConfig()->GetValue<std::string>(OptionKeyFileName); - - OnData(mInputChannelName.c_str(), &DataPublisherDevice::HandleData); - - // reserve space for the HBH at the beginning - mFileBuffer.resize(sizeof(o2::header::HeartbeatHeader)); - - if (!mFileName.empty()) { - AppendFile(mFileName.c_str(), mFileBuffer); - } else if (mDataDescription == DataDescription("CLUSTERS") && mDataOrigin == DataOrigin("TPC")) { - auto f = [](TPCTestCluster& cluster, int idx) { cluster.timeStamp = idx; }; - fakePayload<TPCTestCluster>(mFileBuffer, f, 1000); - LOG(INFO) << "Payload size (after) " << mFileBuffer.size() << "\n"; - // For the moment, add the data as another part to this message - } else if (mDataDescription == DataDescription("CLUSTERS") && mDataOrigin == DataOrigin("ITS")) { - auto f = [](ITSRawData& cluster, int idx) { cluster.timeStamp = idx; }; - fakePayload<ITSRawData>(mFileBuffer, f, 500); - } - - mFileBuffer.resize(mFileBuffer.size() + sizeof(o2::header::HeartbeatTrailer)); - auto* hbhOut = reinterpret_cast<o2::header::HeartbeatHeader*>(&mFileBuffer[0]); - auto* hbtOut = reinterpret_cast<o2::header::HeartbeatTrailer*>(&mFileBuffer[mFileBuffer.size() - sizeof(o2::header::HeartbeatTrailer)]); - *hbhOut = o2::header::HeartbeatHeader(); - *hbtOut = o2::header::HeartbeatTrailer(); -} - -bool DataPublisherDevice::HandleData(FairMQParts& msgParts, int index) -{ - o2::base::forEach(msgParts, [&](auto header, auto payload) { this->HandleO2LogicalBlock(header.data(), header.size(), payload.data(), payload.size()); }); - - return true; -} - -bool DataPublisherDevice::HandleO2LogicalBlock(const byte* headerBuffer, - size_t headerBufferSize, - const byte* dataBuffer, - size_t dataBufferSize) -{ - // AliceO2::header::hexDump("data buffer", dataBuffer, dataBufferSize); - const auto* dataHeader = o2::header::get<o2::header::DataHeader*>(headerBuffer); - const auto* hbfEnvelope = o2::header::get<o2::header::HeartbeatFrameEnvelope*>(headerBuffer); - - // TODO: not sure what the return value is supposed to indicate, it's - // not handled in O2Device::ForEach at the moment - // indicate that the block has not been processed by a 'false' - if (!dataHeader || - (dataHeader->dataDescription) != o2::header::gDataDescriptionHeartbeatFrame) { - return false; - } - - if (!hbfEnvelope) { - LOG(ERROR) << "no heartbeat frame envelope header found"; - return false; - } - - // TODO: consistency checks - // hbfEnvelope->header; - // hbfEnvelope->trailer; - // - block type in both HBH and HBT - // - HBH size + payload size (specified in HBT) + HBT size == dataBufferSize - // - dynamically adjust start of the trailer (if this contains more than one - // 64 bit word - - // TODO: make tool for reading and manipulation of the HeartbeatFrame/Envelop - - // assume everything valid - // write the HBH and HBT as envelop to the buffer of the file data - auto* hbhOut = reinterpret_cast<o2::header::HeartbeatHeader*>(&mFileBuffer[0]); - auto* hbtOut = reinterpret_cast<o2::header::HeartbeatTrailer*>(&mFileBuffer[mFileBuffer.size() - sizeof(o2::header::HeartbeatTrailer)]); - - // copy HBH and HBT, but set the length explicitely to 1 - // TODO: handle all kinds of corner cases, or add an assert - *hbhOut = hbfEnvelope->header; - hbhOut->headerLength = 1; - *hbtOut = hbfEnvelope->trailer; - hbtOut->dataLength = mFileBuffer.size() - sizeof(o2::header::HeartbeatFrameEnvelope); - - // top level subframe header, the DataHeader is going to be used with - // configured description, origin and sub specification - o2::header::DataHeader dh; - dh.dataDescription = mDataDescription; - dh.dataOrigin = mDataOrigin; - dh.subSpecification = mSubSpecification; - dh.payloadSize = mFileBuffer.size(); - - O2Message outgoing; - - LOG(DEBUG) << "Sending buffer of size " << mFileBuffer.size() << "\n"; - LOG(DEBUG) << "Orbit number " << hbhOut->orbit << "\n"; - // build multipart message from header and payload - // TODO: obviously there is a lot to do here, avoid copying etc, this - // is just a proof of principle - // NewSimpleMessage(mFileBuffer) does not work with the vector - - // TODO: fix payload size in dh - auto* buffer = new char[mFileBuffer.size()]; - memcpy(buffer, mFileBuffer.data(), mFileBuffer.size()); - o2::base::addDataBlock(outgoing, dh, NewMessage( - buffer, mFileBuffer.size(), [](void* data, void* hint) { delete[] reinterpret_cast<char*>(data); }, nullptr)); - - // send message - Send(outgoing, mOutputChannelName.c_str()); - outgoing.fParts.clear(); - - return true; -} - -bool DataPublisherDevice::AppendFile(const char* name, std::vector<o2::byte>& buffer) -{ - bool result = true; - std::ifstream ifile(name, std::ifstream::binary); - if (ifile.bad()) { - return false; - } - - // get length of file: - ifile.seekg(0, ifile.end); - int length = ifile.tellg(); - ifile.seekg(0, ifile.beg); - - // allocate memory: - int position = buffer.size(); - buffer.resize(buffer.size() + length); - - // read data as a block: - ifile.read(reinterpret_cast<char*>(&buffer[position]), length); - if (!(result = ifile.good())) { - LOG(ERROR) << "failed to read " << length << " byte(s) from file " << name << std::endl; - } - - ifile.close(); - - return result; -} - -} // namespace utilities -} // namespace o2 diff --git a/Utilities/Publishers/src/runDataPublisherDevice.cxx b/Utilities/Publishers/src/runDataPublisherDevice.cxx deleted file mode 100644 index 1760ace67acb9..0000000000000 --- a/Utilities/Publishers/src/runDataPublisherDevice.cxx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "runFairMQDevice.h" -#include "Publishers/DataPublisherDevice.h" - -namespace bpo = boost::program_options; -using DataPublisherDevice = o2::utilities::DataPublisherDevice; - -void addCustomOptions(bpo::options_description& options) -{ - // clang-format off - options.add_options() - (DataPublisherDevice::OptionKeyDataDescription, - bpo::value<std::string>()->default_value("unspecified"), - "default data description") - (DataPublisherDevice::OptionKeyDataOrigin, - bpo::value<std::string>()->default_value("void"), - "default data origin") - (DataPublisherDevice::OptionKeySubspecification, - bpo::value<DataPublisherDevice::SubSpecificationT>()->default_value(~(DataPublisherDevice::SubSpecificationT)0), - "default sub specification") - (DataPublisherDevice::OptionKeyFileName, - bpo::value<std::string>()->default_value(""), - "File name") - (DataPublisherDevice::OptionKeyInputChannelName, - bpo::value<std::string>()->default_value("input"), - "Name of the input channel") - (DataPublisherDevice::OptionKeyOutputChannelName, - bpo::value<std::string>()->default_value("output"), - "Name of the output channel"); - // clang-format on -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new DataPublisherDevice(); -} diff --git a/Utilities/README.md b/Utilities/README.md index 026a778c559b1..48e1bfbb91473 100644 --- a/Utilities/README.md +++ b/Utilities/README.md @@ -11,6 +11,7 @@ This module contains the following submodules: * \subpage refUtilitiesDataCompression * \subpage refUtilitiesDataFlow +* \subpage refUtilitiesDataSampling * \subpage refUtilitiesMCStepLogger * \subpage refUtilitiesMergers * \subpage refUtilitiesO2Device diff --git a/Utilities/Tools/CMakeLists.txt b/Utilities/Tools/CMakeLists.txt index b8c1346d84d49..428d4c96466df 100644 --- a/Utilities/Tools/CMakeLists.txt +++ b/Utilities/Tools/CMakeLists.txt @@ -1,13 +1,15 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +add_subdirectory(cpulimit) install(PROGRAMS monitor-mem.sh DESTINATION share/scripts/) install(PROGRAMS jobutils.sh DESTINATION share/scripts/) diff --git a/Utilities/Tools/cpulimit/.clang-format b/Utilities/Tools/cpulimit/.clang-format new file mode 100644 index 0000000000000..a43d914ec38dd --- /dev/null +++ b/Utilities/Tools/cpulimit/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false \ No newline at end of file diff --git a/Utilities/Tools/cpulimit/CMakeLists.txt b/Utilities/Tools/cpulimit/CMakeLists.txt new file mode 100644 index 0000000000000..f1109c65fdb69 --- /dev/null +++ b/Utilities/Tools/cpulimit/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_executable(cpulimit + cpulimit.c list.c process_group.c process_iterator.c) +target_compile_definitions(cpulimit PUBLIC _GNU_SOURCE) + +install(TARGETS cpulimit DESTINATION share/scripts/) diff --git a/Utilities/Tools/cpulimit/README b/Utilities/Tools/cpulimit/README new file mode 100644 index 0000000000000..20f543f9491ee --- /dev/null +++ b/Utilities/Tools/cpulimit/README @@ -0,0 +1,2 @@ +These sources have been copied from https://github.com/opsengine/cpulimit +commit f4d2682804931e. \ No newline at end of file diff --git a/Utilities/Tools/cpulimit/cpulimit.c b/Utilities/Tools/cpulimit/cpulimit.c new file mode 100644 index 0000000000000..e7c801496ba3d --- /dev/null +++ b/Utilities/Tools/cpulimit/cpulimit.c @@ -0,0 +1,534 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ************************************************************** + * + * This is a simple program to limit the cpu usage of a process + * If you modify this code, send me a copy please + * + * Get the latest version at: http://github.com/opsengine/cpulimit + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> +#include <time.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#if defined(__APPLE__) +#include <sys/sysctl.h> +#endif +#include <sys/resource.h> +#include <sys/types.h> +#include <sys/wait.h> + +#if defined(__APPLE__) || defined(__FREEBSD__) +#include <libgen.h> +#endif + +#include "process_group.h" +#include "list.h" + +#ifdef HAVE_SYS_SYSINFO_H +#include <sys/sysinfo.h> +#endif + +#ifdef __APPLE__ +#include "memrchr.c" +#endif + +//some useful macro +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +//control time slot in microseconds +//each slot is splitted in a working slice and a sleeping slice +//TODO: make it adaptive, based on the actual system load +#define TIME_SLOT 100000 + +#define MAX_PRIORITY -10 + +/* GLOBAL VARIABLES */ + +//the "family" +struct process_group pgroup; +//pid of cpulimit +pid_t cpulimit_pid; +//name of this program (maybe cpulimit...) +char *program_name; + +//number of cpu +int NCPU; + +/* CONFIGURATION VARIABLES */ + +//verbose mode +int verbose = 0; +//lazy mode (exits if there is no process) +int lazy = 0; + +//SIGINT and SIGTERM signal handler +static void quit(int sig) +{ + //let all the processes continue if stopped + struct list_node *node = NULL; + if (pgroup.proclist != NULL) + { + for (node = pgroup.proclist->first; node != NULL; node = node->next) { + struct process *p = (struct process*)(node->data); + kill(p->pid, SIGCONT); + } + close_process_group(&pgroup); + } + //fix ^C little problem + printf("\r"); + fflush(stdout); + exit(0); +} + +//return t1-t2 in microseconds (no overflow checks, so better watch out!) +static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) +{ + return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec); +} + +static void print_usage(FILE *stream, int exit_code) +{ + fprintf(stream, "Usage: %s [OPTIONS...] TARGET\n", program_name); + fprintf(stream, " OPTIONS\n"); + fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to %d (required)\n", 100*NCPU); + fprintf(stream, " -v, --verbose show control statistics\n"); + fprintf(stream, " -z, --lazy exit if there is no target process, or if it dies\n"); + fprintf(stream, " -i, --include-children limit also the children processes\n"); + fprintf(stream, " -h, --help display this help and exit\n"); + fprintf(stream, " TARGET must be exactly one of these:\n"); + fprintf(stream, " -p, --pid=N pid of the process (implies -z)\n"); + fprintf(stream, " -e, --exe=FILE name of the executable program file or path name\n"); + fprintf(stream, " COMMAND [ARGS] run this command and limit it (implies -z)\n"); + fprintf(stream, "\nReport bugs to <marlonx80@hotmail.com>.\n"); + exit(exit_code); +} + +static void increase_priority() { + //find the best available nice value + int old_priority = getpriority(PRIO_PROCESS, 0); + int priority = old_priority; + while (setpriority(PRIO_PROCESS, 0, priority-1) == 0 && priority>MAX_PRIORITY) { + priority--; + } + if (priority != old_priority) { + if (verbose) { printf("Priority changed to %d\n", priority); } + } + else { + if (verbose) { printf("Warning: Cannot change priority. Run as root or renice for best results.\n"); } + } +} + +/* Get the number of CPUs */ +static int get_ncpu() { + int ncpu; +#ifdef _SC_NPROCESSORS_ONLN + ncpu = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined __APPLE__ + int mib[2] = {CTL_HW, HW_NCPU}; + size_t len = sizeof(ncpu); + sysctl(mib, 2, &ncpu, &len, NULL, 0); +#elif defined _GNU_SOURCE + ncpu = get_nprocs(); +#else + ncpu = -1; +#endif + return ncpu; +} + +int get_pid_max() +{ +#ifdef __linux__ + //read /proc/sys/kernel/pid_max + static char buffer[1024]; + FILE *fd = fopen("/proc/sys/kernel/pid_max", "r"); + if (fd==NULL) { return -1; } + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + return atoi(buffer); +#elif defined __FreeBSD__ + return 99998; +#elif defined __APPLE__ + return 99998; +#endif +} + +void limit_process(pid_t pid, double limit, int include_children) +{ + //slice of the slot in which the process is allowed to run + struct timespec twork; + //slice of the slot in which the process is stopped + struct timespec tsleep; + //when the last twork has started + struct timeval startwork; + //when the last twork has finished + struct timeval endwork; + //initialization + memset(&twork, 0, sizeof(struct timespec)); + memset(&tsleep, 0, sizeof(struct timespec)); + memset(&startwork, 0, sizeof(struct timeval)); + memset(&endwork, 0, sizeof(struct timeval)); + //last working time in microseconds + unsigned long workingtime = 0; + //generic list item + struct list_node *node; + //counter + int c = 0; + + //get a better priority + increase_priority(); + + //build the family + init_process_group(&pgroup, pid, include_children); + + if (verbose) { printf("Members in the process group owned by %d: %d\n", pgroup.target_pid, pgroup.proclist->count); } + + //rate at which we are keeping active the processes (range 0-1) + //1 means that the process are using all the twork slice + double workingrate = -1; + while(1) { + update_process_group(&pgroup); + + if (pgroup.proclist->count==0) { + if (verbose) { printf("No more processes.\n"); } + break; + } + + //total cpu actual usage (range 0-1) + //1 means that the processes are using 100% cpu + double pcpu = -1; + + //estimate how much the controlled processes are using the cpu in the working interval + for (node = pgroup.proclist->first; node != NULL; node = node->next) { + struct process *proc = (struct process*)(node->data); + if (proc->cpu_usage < 0) { + continue; + } + if (pcpu < 0) { pcpu = 0; } + pcpu += proc->cpu_usage; + } + + //adjust work and sleep time slices + if (pcpu < 0) { + //it's the 1st cycle, initialize workingrate + pcpu = limit; + workingrate = limit; + twork.tv_nsec = TIME_SLOT * limit * 1000; + } + else { + //adjust workingrate + workingrate = MIN(workingrate / pcpu * limit, 1); + twork.tv_nsec = TIME_SLOT * 1000 * workingrate; + } + tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec; + + if (verbose) { + if (c%200==0) { + printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n"); + } + if (c%10==0 && c>0) { + printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n", pcpu*100, twork.tv_nsec/1000, tsleep.tv_nsec/1000, workingrate*100); + } + } + + //resume processes + node = pgroup.proclist->first; + while (node != NULL) + { + struct list_node *next_node = node->next; + struct process *proc = (struct process*)(node->data); + if (kill(proc->pid,SIGCONT) != 0) { + //process is dead, remove it from family + if (verbose) { fprintf(stderr, "SIGCONT failed. Process %d dead!\n", proc->pid); } + //remove process from group + delete_node(pgroup.proclist, node); + remove_process(&pgroup, proc->pid); + } + node = next_node; + } + + //now processes are free to run (same working slice for all) + gettimeofday(&startwork, NULL); + nanosleep(&twork, NULL); + gettimeofday(&endwork, NULL); + workingtime = timediff(&endwork, &startwork); + + long delay = workingtime - twork.tv_nsec/1000; + if (c>0 && delay>10000) { + //delay is too much! signal to user? + //fprintf(stderr, "%d %ld us\n", c, delay); + } + + if (tsleep.tv_nsec>0) { + //stop processes only if tsleep>0 + node = pgroup.proclist->first; + while (node != NULL) + { + struct list_node *next_node = node->next; + struct process *proc = (struct process*)(node->data); + if (kill(proc->pid,SIGSTOP)!=0) { + //process is dead, remove it from family + if (verbose) { fprintf(stderr, "SIGSTOP failed. Process %d dead!\n", proc->pid); } + //remove process from group + delete_node(pgroup.proclist, node); + remove_process(&pgroup, proc->pid); + } + node = next_node; + } + //now the processes are sleeping + nanosleep(&tsleep,NULL); + } + c++; + } + close_process_group(&pgroup); +} + +int main(int argc, char **argv) { + //argument variables + const char *exe = NULL; + int perclimit = 0; + int exe_ok = 0; + int pid_ok = 0; + int limit_ok = 0; + pid_t pid = 0; + int include_children = 0; + + //get program name + char *p = (char*)memrchr(argv[0], (unsigned int)'/', strlen(argv[0])); + program_name = p==NULL ? argv[0] : (p+1); + //get current pid + cpulimit_pid = getpid(); + //get cpu count + NCPU = get_ncpu(); + + //parse arguments + int next_option; + int option_index = 0; + //A string listing valid short options letters + const char* short_options = "+p:e:l:vzih"; + //An array describing valid long options + const struct option long_options[] = { + { "pid", required_argument, NULL, 'p' }, + { "exe", required_argument, NULL, 'e' }, + { "limit", required_argument, NULL, 'l' }, + { "verbose", no_argument, NULL, 'v' }, + { "lazy", no_argument, NULL, 'z' }, + { "include-children", no_argument, NULL, 'i' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + do { + next_option = getopt_long(argc, argv, short_options,long_options, &option_index); + switch(next_option) { + case 'p': + pid = atoi(optarg); + pid_ok = 1; + break; + case 'e': + exe = optarg; + exe_ok = 1; + break; + case 'l': + perclimit = atoi(optarg); + limit_ok = 1; + break; + case 'v': + verbose = 1; + break; + case 'z': + lazy = 1; + break; + case 'i': + include_children = 1; + break; + case 'h': + print_usage(stdout, 1); + break; + case '?': + print_usage(stderr, 1); + break; + case -1: + break; + default: + abort(); + } + } while(next_option != -1); + + if (pid_ok && (pid <= 1 || pid >= get_pid_max())) { + fprintf(stderr,"Error: Invalid value for argument PID\n"); + print_usage(stderr, 1); + exit(1); + } + if (pid != 0) { + lazy = 1; + } + + if (!limit_ok) { + fprintf(stderr,"Error: You must specify a cpu limit percentage\n"); + print_usage(stderr, 1); + exit(1); + } + double limit = perclimit / 100.0; + if (limit<0 || limit >NCPU) { + fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU); + print_usage(stderr, 1); + exit(1); + } + + int command_mode = optind < argc; + if (exe_ok + pid_ok + command_mode == 0) { + fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n"); + print_usage(stderr, 1); + exit(1); + } + + if (exe_ok + pid_ok + command_mode > 1) { + fprintf(stderr,"Error: You must specify exactly one target process, either by name, pid, or command line\n"); + print_usage(stderr, 1); + exit(1); + } + + //all arguments are ok! + signal(SIGINT, quit); + signal(SIGTERM, quit); + + //print the number of available cpu + if (verbose) { printf("%d cpu detected\n", NCPU); } + + if (command_mode) { + int i; + //executable file + const char *cmd = argv[optind]; + //command line arguments + char **cmd_args = (char**)malloc((argc-optind + 1) * sizeof(char*)); + if (cmd_args==NULL) { exit(2); } + for (i=0; i<argc-optind; i++) { + cmd_args[i] = argv[i+optind]; + } + cmd_args[i] = NULL; + + if (verbose) { + printf("Running command: '%s", cmd); + for (i=1; i<argc-optind; i++) { + printf(" %s", cmd_args[i]); + } + printf("'\n"); + } + + int child = fork(); + if (child < 0) { + exit(EXIT_FAILURE); + } + else if (child == 0) { + //target process code + int ret = execvp(cmd, cmd_args); + //if we are here there was an error, show it + perror("Error"); + exit(ret); + } + else { + //parent code + free(cmd_args); + int limiter = fork(); + if (limiter < 0) { + exit(EXIT_FAILURE); + } + else if (limiter > 0) { + //parent + int status_process; + int status_limiter; + waitpid(child, &status_process, 0); + waitpid(limiter, &status_limiter, 0); + if (WIFEXITED(status_process)) { + if (verbose) { printf("Process %d terminated with exit status %d\n", child, (int)WEXITSTATUS(status_process)); } + exit(WEXITSTATUS(status_process)); + } + printf("Process %d terminated abnormally\n", child); + exit(status_process); + } + else { + //limiter code + if (verbose) { printf("Limiting process %d\n",child); } + limit_process(child, limit, include_children); + exit(0); + } + } + } + + while(1) { + //look for the target process..or wait for it + pid_t ret = 0; + if (pid_ok) { + //search by pid + ret = find_process_by_pid(pid); + if (ret == 0) { + printf("No process found\n"); + } + else if (ret < 0) { + printf("Process found but you aren't allowed to control it\n"); + } + } + else { + //search by file or path name + ret = find_process_by_name(exe); + if (ret == 0) { + printf("No process found\n"); + } + else if (ret < 0) { + printf("Process found but you aren't allowed to control it\n"); + } + else { + pid = ret; + } + } + if (ret > 0) { + if (ret == cpulimit_pid) { + printf("Target process %d is cpulimit itself! Aborting because it makes no sense\n", ret); + exit(1); + } + printf("Process %d found\n", pid); + //control + limit_process(pid, limit, include_children); + } + if (lazy) { break; } + sleep(2); + }; + + exit(0); +} diff --git a/Utilities/Tools/cpulimit/list.c b/Utilities/Tools/cpulimit/list.c new file mode 100644 index 0000000000000..2ac36708d4a08 --- /dev/null +++ b/Utilities/Tools/cpulimit/list.c @@ -0,0 +1,148 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdlib.h> +#include <string.h> + +#include "list.h" + +#define EMPTYLIST NULL + +void init_list(struct list *l,int keysize) { + l->first=l->last=NULL; + l->keysize=keysize; + l->count=0; +} + +struct list_node *add_elem(struct list *l,void *elem) { + struct list_node *newnode=(struct list_node*)malloc(sizeof(struct list_node)); + newnode->data=elem; + newnode->previous=l->last; + newnode->next=NULL; + if (l->count==0) { + l->first=l->last=newnode; + } + else { + l->last->next=newnode; + l->last=newnode; + } + l->count++; + return newnode; +} + +void delete_node(struct list *l,struct list_node *node) { + if (l->count==1) { + l->first=l->last=NULL; + } + else if (node==l->first) { + node->next->previous=NULL; + l->first=node->next; + } + else if (node==l->last) { + node->previous->next=NULL; + l->last=node->previous; + } + else { + node->previous->next=node->next; + node->next->previous=node->previous; + } + l->count--; + free(node); +} + +void destroy_node(struct list *l,struct list_node *node) { + free(node->data); + node->data=NULL; + delete_node(l,node); +} + +int is_empty_list(struct list *l) { + return (l->count==0?TRUE:FALSE); +} + +int get_list_count(struct list *l) { + return l->count; +} + +void *first_elem(struct list *l) { + return l->first->data; +} + +struct list_node *first_node(struct list *l) { + return l->first; +} + +void *last_elem(struct list *l) { + return l->last->data; +} + +struct list_node *last_node(struct list *l) { + return l->last; +} + +struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) { + struct list_node *tmp; + tmp=l->first; + while(tmp!=NULL) { + if(!memcmp((char*)tmp->data+offset,elem,length==0?l->keysize:length)) { return (tmp); } + tmp=tmp->next; + } + return EMPTYLIST; +} + +struct list_node *locate_node(struct list *l,void *elem) { + return(xlocate_node(l,elem,0,0)); +} + +void *xlocate_elem(struct list *l,void *elem,int offset,int length) { + struct list_node *node=xlocate_node(l,elem,offset,length); + return(node==NULL?NULL:node->data); +} + +void *locate_elem(struct list *l,void *elem) { + return(xlocate_elem(l,elem,0,0)); +} + +void clear_list(struct list *l) { + while(l->first!=EMPTYLIST) { + struct list_node *tmp; + tmp=l->first; + l->first=l->first->next; + free(tmp); + tmp=NULL; + } + l->last=EMPTYLIST; + l->count=0; +} + +void destroy_list(struct list *l) { + while(l->first!=EMPTYLIST) { + struct list_node *tmp; + tmp=l->first; + l->first=l->first->next; + free(tmp->data); + tmp->data=NULL; + free(tmp); + tmp=NULL; + } + l->last=EMPTYLIST; + l->count=0; +} diff --git a/Utilities/Tools/cpulimit/list.h b/Utilities/Tools/cpulimit/list.h new file mode 100644 index 0000000000000..0b43a2b39c0f3 --- /dev/null +++ b/Utilities/Tools/cpulimit/list.h @@ -0,0 +1,138 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __LIST__ + +#define __LIST__ + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +struct list_node { + //pointer to the content of the node + void *data; + //pointer to previous node + struct list_node *previous; + //pointer to next node + struct list_node *next; +}; + +struct list { + //first node + struct list_node *first; + //last node + struct list_node *last; + //size of the search key in bytes + int keysize; + //element count + int count; +}; + +/* + * Initialize a list, with a specified key size + */ +void init_list(struct list *l,int keysize); + +/* + * Add a new element at the end of the list + * return the pointer to the new node + */ +struct list_node *add_elem(struct list *l,void *elem); + +/* + * Delete a node + */ +void delete_node(struct list *l,struct list_node *node); + +/* + * Delete a node from the list, even the content pointed by it + * Use only when the content is a dynamically allocated pointer + */ +void destroy_node(struct list *l,struct list_node *node); + +/* + * Check whether a list is empty or not + */ +int is_empty_list(struct list *l); + +/* + * Return the element count of the list + */ +int get_list_count(struct list *l); + +/* + * Return the first element (content of the node) from the list + */ +void *first_elem(struct list *l); + +/* + * Return the first node from the list + */ +struct list_node *first_node(struct list *l); + +/* + * Return the last element (content of the node) from the list + */ +void *last_elem(struct list *l); + +/* + * Return the last node from the list + */ +struct list_node *last_node(struct list *l); + +/* + * Search an element of the list by content + * the comparison is done from the specified offset and for a specified length + * if offset=0, the comparison starts from the address pointed by data + * if length=0, default keysize is used for length + * if the element is found, return the node address + * else return NULL + */ +struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length); + +/* + * The same of xlocate_node(), but return the content of the node + */ +void *xlocate_elem(struct list *l,void *elem,int offset,int length); + +/* + * The same of calling xlocate_node() with offset=0 and length=0 + */ +struct list_node *locate_node(struct list *l,void *elem); + +/* + * The same of locate_node, but return the content of the node + */ +void *locate_elem(struct list *l,void *elem); + +/* + * Delete all the elements in the list + */ +void clear_list(struct list *l); + +/* + * Delete every element in the list, and free the memory pointed by all the node data + */ +void destroy_list(struct list *l); + +#endif diff --git a/Utilities/Tools/cpulimit/memrchr.c b/Utilities/Tools/cpulimit/memrchr.c new file mode 100644 index 0000000000000..1f3787020afad --- /dev/null +++ b/Utilities/Tools/cpulimit/memrchr.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +/* + * Reverse memchr() + * Find the last occurrence of 'c' in the buffer 's' of size 'n'. + */ +void * +memrchr(s, c, n) + const void *s; + int c; + size_t n; +{ + if (n != 0) { + const unsigned char *cp; + cp = (unsigned char *)s + n; + do { + if (*(--cp) == (unsigned char)c) + return((void *)cp); + } while (--n != 0); + } + return((void *)0); +} diff --git a/Utilities/Tools/cpulimit/process_group.c b/Utilities/Tools/cpulimit/process_group.c new file mode 100644 index 0000000000000..c5343e32bd9a1 --- /dev/null +++ b/Utilities/Tools/cpulimit/process_group.c @@ -0,0 +1,219 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#if defined(__APPLE__) || defined(__FREEBSD__) +#include <libgen.h> +#endif + +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/time.h> +#include <signal.h> + +#include <assert.h> + +#include "process_iterator.h" +#include "process_group.h" +#include "list.h" + +// look for a process by pid +// search_pid : pid of the wanted process +// return: pid of the found process, if successful +// negative pid, if the process does not exist or if the signal fails +int find_process_by_pid(pid_t pid) +{ + return (kill(pid,0)==0) ? pid : -pid; +} + +// look for a process with a given name +// process: the name of the wanted process. it can be an absolute path name to the executable file +// or just the file name +// return: pid of the found process, if it is found +// 0, if it's not found +// negative pid, if it is found but it's not possible to control it +int find_process_by_name(const char *process_name) +{ + //pid of the target process + pid_t pid = -1; + + //process iterator + struct process_iterator it; + struct process proc; + struct process_filter filter; + filter.pid = 0; + filter.include_children = 0; + init_process_iterator(&it, &filter); + while (get_next_process(&it, &proc) != -1) + { + //process found + if (strncmp(basename(proc.command), process_name, strlen(process_name))==0 && kill(pid,SIGCONT)==0) { + //process is ok! + pid = proc.pid; + break; + } + } + if (close_process_iterator(&it) != 0) { + exit(1); + } + if (pid >= 0) { + //ok, the process was found + return pid; + } + else { + //process not found + return 0; + } +} + +int init_process_group(struct process_group *pgroup, int target_pid, int include_children) +{ + //hashtable initialization + memset(&pgroup->proctable, 0, sizeof(pgroup->proctable)); + pgroup->target_pid = target_pid; + pgroup->include_children = include_children; + pgroup->proclist = (struct list*)malloc(sizeof(struct list)); + init_list(pgroup->proclist, 4); + memset(&pgroup->last_update, 0, sizeof(pgroup->last_update)); + update_process_group(pgroup); + return 0; +} + +int close_process_group(struct process_group *pgroup) +{ + int i; + int size = sizeof(pgroup->proctable) / sizeof(struct process*); + for (i=0; i<size; i++) { + if (pgroup->proctable[i] != NULL) { + //free() history for each process + destroy_list(pgroup->proctable[i]); + free(pgroup->proctable[i]); + pgroup->proctable[i] = NULL; + } + } + clear_list(pgroup->proclist); + free(pgroup->proclist); + pgroup->proclist = NULL; + return 0; +} + +void remove_terminated_processes(struct process_group *pgroup) +{ + //TODO +} + +//return t1-t2 in microseconds (no overflow checks, so better watch out!) +static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) +{ + return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec); +} + +//parameter in range 0-1 +#define ALFA 0.08 +#define MIN_DT 20 + +void update_process_group(struct process_group *pgroup) +{ + struct process_iterator it; + struct process tmp_process; + struct process_filter filter; + struct timeval now; + gettimeofday(&now, NULL); + //time elapsed from previous sample (in ms) + long dt = timediff(&now, &pgroup->last_update) / 1000; + filter.pid = pgroup->target_pid; + filter.include_children = pgroup->include_children; + init_process_iterator(&it, &filter); + clear_list(pgroup->proclist); + init_list(pgroup->proclist, 4); + + while (get_next_process(&it, &tmp_process) != -1) + { +// struct timeval t; +// gettimeofday(&t, NULL); +// printf("T=%ld.%ld PID=%d PPID=%d START=%d CPUTIME=%d\n", t.tv_sec, t.tv_usec, tmp_process.pid, tmp_process.ppid, tmp_process.starttime, tmp_process.cputime); + int hashkey = pid_hashfn(tmp_process.pid); + if (pgroup->proctable[hashkey] == NULL) + { + //empty bucket + pgroup->proctable[hashkey] = malloc(sizeof(struct list)); + struct process *new_process = malloc(sizeof(struct process)); + tmp_process.cpu_usage = -1; + memcpy(new_process, &tmp_process, sizeof(struct process)); + init_list(pgroup->proctable[hashkey], 4); + add_elem(pgroup->proctable[hashkey], new_process); + add_elem(pgroup->proclist, new_process); + } + else + { + //existing bucket + struct process *p = (struct process*)locate_elem(pgroup->proctable[hashkey], &tmp_process); + if (p == NULL) + { + //process is new. add it + struct process *new_process = malloc(sizeof(struct process)); + tmp_process.cpu_usage = -1; + memcpy(new_process, &tmp_process, sizeof(struct process)); + add_elem(pgroup->proctable[hashkey], new_process); + add_elem(pgroup->proclist, new_process); + } + else + { + assert(tmp_process.pid == p->pid); + assert(tmp_process.starttime == p->starttime); + add_elem(pgroup->proclist, p); + if (dt < MIN_DT) { + continue; + } + //process exists. update CPU usage + double sample = 1.0 * (tmp_process.cputime - p->cputime) / dt; + if (p->cpu_usage == -1) { + //initialization + p->cpu_usage = sample; + } + else { + //usage adjustment + p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample; + } + p->cputime = tmp_process.cputime; + } + } + } + close_process_iterator(&it); + if (dt < MIN_DT) { + return; + } + pgroup->last_update = now; +} + +int remove_process(struct process_group *pgroup, int pid) +{ + int hashkey = pid_hashfn(pid); + if (pgroup->proctable[hashkey] == NULL) { + return 1; //nothing to delete + } + struct list_node *node = (struct list_node*)locate_node(pgroup->proctable[hashkey], &pid); + if (node == NULL) { + return 2; + } + delete_node(pgroup->proctable[hashkey], node); + return 0; +} diff --git a/Utilities/Tools/cpulimit/process_group.h b/Utilities/Tools/cpulimit/process_group.h new file mode 100644 index 0000000000000..5a5b581554a80 --- /dev/null +++ b/Utilities/Tools/cpulimit/process_group.h @@ -0,0 +1,55 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PROCESS_GROUP_H + +#define __PROCESS_GROUP_H + +#include "process_iterator.h" + +#include "list.h" + +#define PIDHASH_SZ 1024 +#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) + +struct process_group +{ + //hashtable with all the processes (array of struct list of struct process) + struct list *proctable[PIDHASH_SZ]; + struct list *proclist; + pid_t target_pid; + int include_children; + struct timeval last_update; +}; + +int init_process_group(struct process_group *pgroup, int target_pid, int include_children); + +void update_process_group(struct process_group *pgroup); + +int close_process_group(struct process_group *pgroup); + +int find_process_by_pid(pid_t pid); + +int find_process_by_name(const char *process_name); + +int remove_process(struct process_group *pgroup, int pid); + +#endif diff --git a/Utilities/Tools/cpulimit/process_iterator.c b/Utilities/Tools/cpulimit/process_iterator.c new file mode 100644 index 0000000000000..8b4019d237f2b --- /dev/null +++ b/Utilities/Tools/cpulimit/process_iterator.c @@ -0,0 +1,49 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef __APPLE__ +#include <sys/procfs.h> +#endif +#include <time.h> +#include "process_iterator.h" + +//See this link to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 + +#ifdef __linux__ + +#include "process_iterator_linux.c" + +#elif defined __FreeBSD__ + +#include "process_iterator_freebsd.c" + +#elif defined __APPLE__ + +#include "process_iterator_apple.c" + +#else + +#error Platform not supported + +#endif diff --git a/Utilities/Tools/cpulimit/process_iterator.h b/Utilities/Tools/cpulimit/process_iterator.h new file mode 100644 index 0000000000000..70520b68a6e88 --- /dev/null +++ b/Utilities/Tools/cpulimit/process_iterator.h @@ -0,0 +1,97 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PROCESS_ITERATOR_H + +#define __PROCESS_ITERATOR_H + +#include <unistd.h> +#include <limits.h> +#include <dirent.h> + +//USER_HZ detection, from openssl code +#ifndef HZ +# if defined(_SC_CLK_TCK) \ + && (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000) +# define HZ ((double)sysconf(_SC_CLK_TCK)) +# else +# ifndef CLK_TCK +# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */ +# define HZ 100.0 +# else /* _BSD_CLK_TCK_ */ +# define HZ ((double)_BSD_CLK_TCK_) +# endif +# else /* CLK_TCK */ +# define HZ ((double)CLK_TCK) +# endif +# endif +#endif + +#ifdef __FreeBSD__ +#include <kvm.h> +#endif + +// process descriptor +struct process { + //pid of the process + pid_t pid; + //ppid of the process + pid_t ppid; + //start time (unix timestamp) + int starttime; + //cputime used by the process (in milliseconds) + int cputime; + //actual cpu usage estimation (value in range 0-1) + double cpu_usage; + //absolute path of the executable file + char command[PATH_MAX+1]; +}; + +struct process_filter { + int pid; + int include_children; + char program_name[PATH_MAX+1]; +}; + +struct process_iterator { +#ifdef __linux__ + DIR *dip; + int boot_time; +#elif defined __FreeBSD__ + kvm_t *kd; + struct kinfo_proc *procs; + int count; + int i; +#elif defined __APPLE__ + int i; + int count; + int *pidlist; +#endif + struct process_filter *filter; +}; + +int init_process_iterator(struct process_iterator *i, struct process_filter *filter); + +int get_next_process(struct process_iterator *i, struct process *p); + +int close_process_iterator(struct process_iterator *i); + +#endif diff --git a/Utilities/Tools/cpulimit/process_iterator_apple.c b/Utilities/Tools/cpulimit/process_iterator_apple.c new file mode 100644 index 0000000000000..b878ed8c9a946 --- /dev/null +++ b/Utilities/Tools/cpulimit/process_iterator_apple.c @@ -0,0 +1,148 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Author: Simon Sigurdhsson + * + */ + +#include <errno.h> +#include <stdio.h> +#include <libproc.h> + +int unique_nonzero_ints(int* arr_in, int len_in, int* arr_out) { + int* source = arr_in; + if (arr_out == NULL) return -1; + if (arr_in == arr_out) { + source = malloc(sizeof(int)*len_in); + memcpy(source, arr_in, sizeof(int)*len_in); + memset(arr_out, -1, sizeof(int)*len_in); + } + int len_out = 0; + int i, j; + for (i=0; i<len_in; i++) { + int found = 0; + if (source[i] == 0) continue; + for (j=0; !found && j<len_out; j++) { + found = (source[i] == arr_out[j]) ? 1 : 0; + } + if (!found) { + arr_out[len_out++] = source[i]; + } + } + if (arr_in == arr_out) { + free(source); + } + return len_out-1; +} + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + it->i = 0; + /* Find out how much to allocate for it->pidlist */ + if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) { + fprintf(stderr, "proc_listpids: %s\n", strerror(errno)); + return -1; + } + /* Allocate and populate it->pidlist */ + if ((it->pidlist = (int *)malloc((it->count)*sizeof(int))) == NULL) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + } + if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, it->pidlist, it->count)) <= 0) { + fprintf(stderr, "proc_listpids: %s\n", strerror(errno)); + return -1; + } + it->count = unique_nonzero_ints(it->pidlist, it->count, it->pidlist); + it->filter = filter; + return 0; +} + +static int pti2proc(struct proc_taskallinfo *ti, struct process *process) { + int bytes; + process->pid = ti->pbsd.pbi_pid; + process->ppid = ti->pbsd.pbi_ppid; + process->starttime = ti->pbsd.pbi_start_tvsec; + process->cputime = (ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system) / 1000000; + bytes = strlen(ti->pbsd.pbi_comm); + memcpy(process->command, ti->pbsd.pbi_comm, (bytes < PATH_MAX ? bytes : PATH_MAX) + 1); + return 0; +} + +static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) { + int bytes; + bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(*ti)); + if (bytes <= 0) { + if (!(errno & (EPERM | ESRCH))) { + fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno)); + } + return -1; + } else if (bytes < sizeof(ti)) { + fprintf(stderr, "proc_pidinfo: too few bytes; expected %ld, got %d\n", sizeof(ti), bytes); + return -1; + } + return 0; +} + +int get_next_process(struct process_iterator *it, struct process *p) { + if (it->i == it->count) return -1; + if (it->filter->pid != 0 && !it->filter->include_children) { + struct proc_taskallinfo ti; + if (get_process_pti(it->filter->pid, &ti) != 0) { + it->i = it->count = 0; + return -1; + } + it->i = it->count = 1; + return pti2proc(&ti, p); + } + while (it->i < it->count) { + struct proc_taskallinfo ti; + if (get_process_pti(it->pidlist[it->i], &ti) != 0) { + it->i++; + continue; + } + if (ti.pbsd.pbi_flags & PROC_FLAG_SYSTEM) { + it->i++; + continue; + } + if (it->filter->pid != 0 && it->filter->include_children) { + pti2proc(&ti, p); + it->i++; + if (p->pid != it->pidlist[it->i - 1]) // I don't know why this can happen + continue; + if (p->pid != it->filter->pid && p->ppid != it->filter->pid) + continue; + return 0; + } + else if (it->filter->pid == 0) + { + pti2proc(&ti, p); + it->i++; + return 0; + } + } + return -1; +} + +int close_process_iterator(struct process_iterator *it) { + free(it->pidlist); + it->pidlist = NULL; + it->filter = NULL; + it->count = 0; + it->i = 0; + return 0; +} diff --git a/Utilities/Tools/cpulimit/process_iterator_freebsd.c b/Utilities/Tools/cpulimit/process_iterator_freebsd.c new file mode 100644 index 0000000000000..a6381123e1251 --- /dev/null +++ b/Utilities/Tools/cpulimit/process_iterator_freebsd.c @@ -0,0 +1,119 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <sys/sysctl.h> +#include <sys/user.h> +#include <fcntl.h> +#include <paths.h> + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + char errbuf[_POSIX2_LINE_MAX]; + it->i = 0; + /* Open the kvm interface, get a descriptor */ + if ((it->kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + fprintf(stderr, "kvm_open: %s\n", errbuf); + return -1; + } + /* Get the list of processes. */ + if ((it->procs = kvm_getprocs(it->kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { + kvm_close(it->kd); +// fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd)); + return -1; + } + it->filter = filter; + return 0; +} + +static int kproc2proc(kvm_t *kd, struct kinfo_proc *kproc, struct process *proc) +{ + proc->pid = kproc->ki_pid; + proc->ppid = kproc->ki_ppid; + proc->cputime = kproc->ki_runtime / 1000; + proc->starttime = kproc->ki_start.tv_sec; + char **args = kvm_getargv(kd, kproc, sizeof(proc->command)); + if (args == NULL) return -1; + memcpy(proc->command, args[0], strlen(args[0]) + 1); + return 0; +} + +static int get_single_process(kvm_t *kd, pid_t pid, struct process *process) +{ + int count; + struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); + if (count == 0 || kproc == NULL) + { +// fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); + return -1; + } + kproc2proc(kd, kproc, process); + return 0; +} + +int get_next_process(struct process_iterator *it, struct process *p) { + if (it->i == it->count) + { + return -1; + } + if (it->filter->pid != 0 && !it->filter->include_children) + { + if (get_single_process(it->kd, it->filter->pid, p) != 0) + { + it->i = it->count = 0; + return -1; + } + it->i = it->count = 1; + return 0; + } + while (it->i < it->count) + { + struct kinfo_proc *kproc = &(it->procs[it->i]); + if (kproc->ki_flag & P_SYSTEM) + { + // skip system processes + it->i++; + continue; + } + if (it->filter->pid != 0 && it->filter->include_children) + { + kproc2proc(it->kd, kproc, p); + it->i++; + if (p->pid != it->filter->pid && p->ppid != it->filter->pid) + continue; + return 0; + } + else if (it->filter->pid == 0) + { + kproc2proc(it->kd, kproc, p); + it->i++; + return 0; + } + } + return -1; +} + +int close_process_iterator(struct process_iterator *it) { + if (kvm_close(it->kd) == -1) { + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd)); + return -1; + } + return 0; +} + diff --git a/Utilities/Tools/cpulimit/process_iterator_linux.c b/Utilities/Tools/cpulimit/process_iterator_linux.c new file mode 100644 index 0000000000000..d8d2cab3571da --- /dev/null +++ b/Utilities/Tools/cpulimit/process_iterator_linux.c @@ -0,0 +1,198 @@ +/** + * + * cpulimit - a CPU limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <sys/vfs.h> + +static int get_boot_time() +{ + int uptime = 0; + FILE *fp = fopen ("/proc/uptime", "r"); + if (fp != NULL) + { + char buf[BUFSIZ]; + char *b = fgets(buf, BUFSIZ, fp); + if (b == buf) + { + char *end_ptr; + double upsecs = strtod(buf, &end_ptr); + uptime = (int)upsecs; + } + fclose (fp); + } + time_t now = time(NULL); + return now - uptime; +} + +static int check_proc() +{ + struct statfs mnt; + if (statfs("/proc", &mnt) < 0) { + return 0; + } + if (mnt.f_type!=0x9fa0) { + return 0; + } + return 1; +} + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) +{ + if (!check_proc()) { + fprintf(stderr, "procfs is not mounted!\nAborting\n"); + exit(-2); + } + //open a directory stream to /proc directory + if ((it->dip = opendir("/proc")) == NULL) + { + perror("opendir"); + return -1; + } + it->filter = filter; + it->boot_time = get_boot_time(); + return 0; +} + +static int read_process_info(pid_t pid, struct process *p) +{ + static char buffer[1024]; + static char statfile[32]; + static char exefile[1024]; + p->pid = pid; + //read stat file + sprintf(statfile, "/proc/%d/stat", p->pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) { + return -1; + } + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) { + token = strtok(NULL, " "); + } + p->ppid = atoi(token); + for (i=0; i<10; i++) { + token = strtok(NULL, " "); + } + p->cputime = atoi(token) * 1000 / HZ; + token = strtok(NULL, " "); + p->cputime += atoi(token) * 1000 / HZ; + for (i=0; i<7; i++) { + token = strtok(NULL, " "); + } + p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); + //read command line + sprintf(exefile,"/proc/%d/cmdline", p->pid); + fd = fopen(exefile, "r"); + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + strcpy(p->command, buffer); + return 0; +} + +static pid_t getppid_of(pid_t pid) +{ + char statfile[20]; + char buffer[1024]; + sprintf(statfile, "/proc/%d/stat", pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) { + return -1; + } + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) { + token = strtok(NULL, " "); + } + return atoi(token); +} + +static int is_child_of(pid_t child_pid, pid_t parent_pid) +{ + int ppid = child_pid; + while(ppid > 1 && ppid != parent_pid) { + ppid = getppid_of(ppid); + } + return ppid == parent_pid; +} + +int get_next_process(struct process_iterator *it, struct process *p) +{ + if (it->dip == NULL) + { + //end of processes + return -1; + } + if (it->filter->pid != 0 && !it->filter->include_children) + { + int ret = read_process_info(it->filter->pid, p); + //p->starttime += it->boot_time; + closedir(it->dip); + it->dip = NULL; + if (ret != 0) { + return -1; + } + return 0; + } + struct dirent *dit = NULL; + //read in from /proc and seek for process dirs + while ((dit = readdir(it->dip)) != NULL) { + if(strtok(dit->d_name, "0123456789") != NULL) { + continue; + } + p->pid = atoi(dit->d_name); + if (it->filter->pid != 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) { + continue; + } + read_process_info(p->pid, p); + //p->starttime += it->boot_time; + break; + } + if (dit == NULL) + { + //end of processes + closedir(it->dip); + it->dip = NULL; + return -1; + } + return 0; +} + +int close_process_iterator(struct process_iterator *it) { + if (it->dip != NULL && closedir(it->dip) == -1) { + perror("closedir"); + return 1; + } + it->dip = NULL; + return 0; +} diff --git a/Utilities/Tools/jobutils.sh b/Utilities/Tools/jobutils.sh index 5905fb7dc6adc..2f73dc40464af 100644 --- a/Utilities/Tools/jobutils.sh +++ b/Utilities/Tools/jobutils.sh @@ -1,52 +1,39 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # # author: Sandro Wenzel # This file contains a couple of utility functions for reuse # in shell job scripts (such as on the GRID). # In order to use these functions in scripts, this file needs to be -# simply sourced into the target script. +# simply sourced into the target script. The script needs bash versions > 4 +# TODOs: +# -harmonize use of bc/awk for calculations +# -harmonize coding style for variables o2_cleanup_shm_files() { - # check if we have lsof (otherwise we do nothing) - which lsof &> /dev/null - if [ "$?" = "0" ]; then - # find shared memory files **CURRENTLY IN USE** by FairMQ - USEDFILES=`lsof -u $(whoami) | grep -e \"/dev/shm/.*fmq\" | sed 's/.*\/dev/\/dev/g' | sort | uniq | tr '\n' ' '` - - echo "${USEDFILES}" - if [ ! "${USEDFILES}" ]; then - # in this case we can remove everything - COMMAND="find /dev/shm/ -user $(whoami) -name \"*fmq_*\" -delete 2> /dev/null" - else - # build exclusion list - for f in ${USEDFILES}; do - LOGICALOP="" - [ "${EXCLPATTERN}" ] && LOGICALOP="-o" - EXCLPATTERN="${EXCLPATTERN} ${LOGICALOP} -wholename ${f}" - done - COMMAND="find /dev/shm/ -user $(whoami) -type f -not \( ${EXCLPATTERN} \) -delete 2> /dev/null" - fi - eval "${COMMAND}" - else - echo "Can't do shared mem cleanup: lsof not found" + if [ "${JOBUTILS_INTERNAL_DPL_SESSION}" ]; then + # echo "cleaning up session ${JOBUTILS_INTERNAL_DPL_SESSION}" + fairmq-shmmonitor -s ${JOBUTILS_INTERNAL_DPL_SESSION} -c &> /dev/null fi } # Function to find out all the (recursive) child processes starting from a parent PID. -# The output includes includes the parent -# output is saved in child_pid_list +# The output includes the parent childprocs() { local parent=$1 + if [ ! "$2" ]; then + child_pid_list="" + fi if [ "$parent" ] ; then child_pid_list="$child_pid_list $parent" for childpid in $(pgrep -P ${parent}); do @@ -59,17 +46,24 @@ childprocs() { fi } +taskwrapper_cleanup() { + MOTHERPID=$1 + SIGNAL=${2:-SIGTERM} + for p in $(childprocs ${MOTHERPID}); do + echo "killing child $p" + kill -s ${SIGNAL} $p 2> /dev/null + done + sleep 2 + # remove leftover shm files + o2_cleanup_shm_files + unset JOBUTILS_INTERNAL_DPL_SESSION +} + taskwrapper_cleanup_handler() { PID=$1 SIGNAL=$2 echo "CLEANUP HANDLER FOR PROCESS ${PID} AND SIGNAL ${SIGNAL}" - PROCS=$(childprocs ${PID}) - # make sure to bring down everything, including all kids - for p in ${PROCS}; do - echo "killing ${p}" - kill -s ${SIGNAL} ${p} 2> /dev/null - done - o2_cleanup_shm_files + taskwrapper_cleanup ${PID} ${SIGNAL} # I prefer to exit the current job completely exit 1 } @@ -78,28 +72,53 @@ taskwrapper_cleanup_handler() { # Main features provided at the moment are: # - optional recording of walltime and memory consumption (time evolution) # - optional recording of CPU utilization -# - Some job control and error detection (in particular for DPL workflows). +# - Some job control and error detection (in particular for DPL workflows). # If exceptions are found, all participating processes will be sent a termination signal. -# The rational behind this function is to be able to determine failing -# conditions early and prevent longtime hanging executables +# The rational behind this function is to be able to determine failing +# conditions early and prevent longtime hanging executables # (until DPL offers signal handling and automatic shutdown) # - possibility to provide user hooks for "start" and "failure" # - possibility to skip (jump over) job alltogether +# - possibility to define timeout +# - possibility to control/limit the CPU load taskwrapper() { + unset JOBUTILS_INTERNAL_DPL_SESSION + # nested helper to parse DPL session ID + _parse_DPL_session () + { + childpids=$(childprocs ${1}) + for p in ${childpids}; do + command=$(ps -o command ${p} | grep -v "COMMAND" | grep "session") + if [ "$?" = "0" ]; then + # echo "parsing from ${command}" + session=`echo ${command} | sed 's/.*--session//g' | awk '//{print $1}'` + if [ "${session}" ]; then + # echo "found ${session}" + break + fi + fi + done + echo "${session:-""}" + } + local logfile=$1 shift 1 local command="$*" + STARTTIME=$SECONDS + # launch the actual command in the background echo "Launching task: ${command} &> $logfile &" # the command might be a complex block: For the timing measurement below # it is better to execute this as a script SCRIPTNAME="${logfile}_tmp.sh" - echo "${command}" > ${SCRIPTNAME} + echo "export LIBC_FATAL_STDERR_=1" > ${SCRIPTNAME} # <--- needed ... otherwise the LIBC fatal messages appear on a different tty + echo "${command};" >> ${SCRIPTNAME} + echo 'RC=$?; echo "TASK-EXIT-CODE: ${RC}"; exit ${RC}' >> ${SCRIPTNAME} chmod +x ${SCRIPTNAME} # this gives some possibility to customize the wrapper - # and do some special task at the start. The hook takes 2 arguments: + # and do some special task at the start. The hook takes 2 arguments: # The original command and the logfile if [ "${JOBUTILS_JOB_STARTHOOK}" ]; then hook="${JOBUTILS_JOB_STARTHOOK} '$command' $logfile" @@ -133,7 +152,7 @@ taskwrapper() { finalcommand="TIME=\"#walltime %e\" ${O2_ROOT}/share/scripts/monitor-mem.sh ${TIMECOMMAND} './${SCRIPTNAME}'" fi echo "Running: ${finalcommand}" > ${logfile} - eval ${finalcommand} >> ${logfile} 2>&1 & + eval ${finalcommand} >> ${logfile} 2>&1 & #can't disown here since we want to retrieve exit status later on # THE NEXT PART IS THE SUPERVISION PART # get the PID @@ -143,38 +162,52 @@ taskwrapper() { trap "taskwrapper_cleanup_handler ${PID} SIGTERM" SIGTERM cpucounter=1 + inactivitycounter=0 # used to detect periods of inactivity + NLOGICALCPUS=$(getNumberOfLogicalCPUCores) + reduction_factor=1 + control_iteration=1 while [ 1 ]; do # We don't like to see critical problems in the log file. # We need to grep on multitude of things: - # - all sorts of exceptions (may need to fine-tune) + # - all sorts of exceptions (may need to fine-tune) # - segmentation violation # - there was a crash # - bus error (often occuring with shared mem) - pattern="-e \"xception\" \ - -e \"segmentation violation\" \ - -e \"error while setting up workflow\" \ - -e \"bus error\" \ - -e \"Assertion.*failed\" \ - -e \"There was a crash.\"" - - grepcommand="grep -H ${pattern} $logfile >> encountered_exceptions_list 2>/dev/null" + pattern="-e \"\<[Ee]xception\" \ + -e \"segmentation violation\" \ + -e \"error while setting up workflow\" \ + -e \"bus error\" \ + -e \"Assertion.*failed\" \ + -e \"Fatal in\" \ + -e \"libc++abi.*terminating\" \ + -e \"There was a crash.\" \ + -e \"arrow.*Check failed\" \ + -e \"terminate called after\" \ + -e \"terminate called without an active\" \ + -e \"\*\*\* Error in\"" # <--- LIBC fatal error messages + + grepcommand="grep -a -H ${pattern} $logfile ${JOBUTILS_JOB_SUPERVISEDFILES} >> encountered_exceptions_list 2>/dev/null" eval ${grepcommand} - - grepcommand="grep -h --count ${pattern} $logfile 2>/dev/null" + + grepcommand="grep -a -h --count ${pattern} $logfile ${JOBUTILS_JOB_SUPERVISEDFILES} 2>/dev/null" # using eval here since otherwise the pattern is translated to a # a weirdly quoted stringlist RC=$(eval ${grepcommand}) - + # if we see an exception we will bring down the DPL workflow # after having given it some chance to shut-down itself # basically --> send kill to all children if [ "$RC" != "" -a "$RC" != "0" ]; then echo "Detected critical problem in logfile $logfile" + if [ "${JOBUTILS_PRINT_ON_ERROR}" ]; then + grepcommand="grep -a -H -A 2 -B 2 ${pattern} $logfile ${JOBUTILS_JOB_SUPERVISEDFILES}" + eval ${grepcommand} + fi # this gives some possibility to customize the wrapper - # and do some special task at the start. The hook takes 2 arguments: + # and do some special task at the start. The hook takes 2 arguments: # The original command and the logfile if [ "${JOBUTILS_JOB_FAILUREHOOK}" ]; then hook="${JOBUTILS_JOB_FAILUREHOOK} '$command' $logfile" @@ -183,18 +216,12 @@ taskwrapper() { sleep 2 - # query processes still alive and terminate them - for p in $(childprocs ${PID}); do - echo "killing child $p" - kill -9 $p 2> /dev/null - done - sleep 2 - - # remove leftover shm files - o2_cleanup_shm_files + [ ! "${JOBUTILS_DEBUGMODE}" ] && taskwrapper_cleanup ${PID} SIGKILL RC_ACUM=$((RC_ACUM+1)) [ ! "${JOBUTILS_KEEPJOBSCRIPT}" ] && rm ${SCRIPTNAME} 2> /dev/null + [ "${JOBUTILS_PRINT_ON_ERROR}" ] && cat ${logfile} + [[ ! "${JOBUTILS_NOEXIT_ON_ERROR}" ]] && [[ ! $- == *i* ]] && exit 1 return 1 fi @@ -202,35 +229,170 @@ taskwrapper() { ps -p $PID > /dev/null [ $? == 1 ] && break - if [ "${JOBUTILS_MONITORCPU}" ]; then + if [ "${JOBUTILS_MONITORMEM}" ]; then + if [ "${JOBUTILS_INTERNAL_DPL_SESSION}" ]; then + MAX_FMQ_SHM=${MAX_FMQ_SHM:-0} + text=$(fairmq-shmmonitor -v -s ${JOBUTILS_INTERNAL_DPL_SESSION}) + line=$(echo ${text} | tr '[' '\n[' | grep "^0" | tail -n1) + CURRENT_FMQ_SHM=$(echo ${line} | sed 's/.*used://g') + # echo "current shm ${CURRENT_FMQ_SHM}" + MAX_FMQ_SHM=$(awk -v "t=${CURRENT_FMQ_SHM}" -v "s=${MAX_FMQ_SHM}" 'BEGIN { if(t>=s) { print t; } else { print s; } }') + fi + fi + + if [ "${JOBUTILS_MONITORCPU}" ] || [ "${JOBUTILS_LIMITLOAD}" ]; then + # NOTE: The following section is "a bit" compute intensive and currently not optimized + # A careful evaluation of awk vs bc or other tools might be needed -- or a move to a more + # system oriented language/tool + + for p in $limitPIDs; do + wait ${p} + done + # get some CPU usage statistics per process --> actual usage can be calculated thereafter - for p in $(childprocs ${PID}); do - total=`awk 'BEGIN{s=0}/cpu /{for (i=1;i<=NF;i++) s+=$i;} END {print s}' /proc/stat` - utime=`awk '//{print $14}' /proc/${p}/stat 2> /dev/null` - stime=`awk '//{print $15}' /proc/${p}/stat 2> /dev/null` - name=`awk '//{print $2}' /proc/${p}/stat 2> /dev/null` - echo "${cpucounter} ${p} ${total} ${utime} ${stime} ${name}" >> ${logfile}_cpuusage + total=`awk 'BEGIN{s=0}/cpu /{for (i=1;i<=NF;i++) s+=$i;} END {print s}' /proc/stat` + previous_total=${current_total} + current_total=${total} + # quickly fetch the data + childpids=$(childprocs ${PID}) + + for p in $childpids; do + while read -r name utime stime; do + echo "${cpucounter} ${p} ${total} ${utime} ${stime} ${name}" >> ${logfile}_cpuusage + previous[$p]=${current[$p]} + current[$p]=${utime} + name[$p]=${name} + done <<<$(awk '//{print $2" "$14" "$15}' /proc/${p}/stat 2>/dev/null) done + # do some calculations based on the data + totalCPU=0 # actual CPU load measured + totalCPU_unlimited=0 # extrapolated unlimited CPU load + line="" + for p in $childpids; do + C=${current[$p]} + P=${previous[$p]} + CT=${total} + PT=${previous_total} + # echo "${p} : current ${C} previous ${P} ${CT} ${PT}" + thisCPU[$p]=$(awk -v "c=${C}" -v "p=${P}" -v "ct=${CT}" -v "pt=${PT}" -v "ncpu=${NLOGICALCPUS}" 'BEGIN { print 100.*ncpu*(c-p)/(ct-pt); }') + line="${line} $p:${thisCPU[$p]}" + totalCPU=$(awk -v "t=${totalCPU}" -v "this=${thisCPU[$p]}" 'BEGIN { print (t + this); }') + previousfactor=1 + [ ${waslimited[$p]} ] && previousfactor=${reduction_factor} + totalCPU_unlimited=$(awk -v "t=${totalCPU_unlimited}" -v "this=${thisCPU[$p]}" -v f="${previousfactor}" 'BEGIN { print (t + this/f); }') + # echo "CPU last time window ${p} : ${thisCPU[$p]}" + done + + # echo "${line}" + # echo "${cpucounter} totalCPU = ${totalCPU} -- without limitation ${totalCPU_unlimited}" + # We can check if the total load is above a resource limit + # And take corrective actions if we extend by 10% + limitPIDs="" + unset waslimited + if [ ${JOBUTILS_LIMITLOAD} ]; then + if (( $(echo "${totalCPU_unlimited} > 1.1*${JOBUTILS_LIMITLOAD}" | bc -l 2>/dev/null) )); then + # we reduce each pid proportionally for the time until the next check and record the reduction factor in place + oldreduction=${reduction_factor} + reduction_factor=$(awk -v limit="${JOBUTILS_LIMITLOAD}" -v cur="${totalCPU_unlimited}" 'BEGIN{ print limit/cur;}') + echo "APPLYING REDUCTION = ${reduction_factor}" + + for p in $childpids; do + cpulim=$(awk -v a="${thisCPU[${p}]}" -v newr="${reduction_factor}" -v oldr="${oldreduction}" 'BEGIN { r=(a/oldr)*newr; print r; if(r > 0.05) {exit 0;} exit 1; }') + if [ $? = "0" ]; then + # we only apply to jobs above a certain threshold + echo "Setting CPU lim for job ${p} / ${name[$p]} to ${cpulim}"; + + timeout ${JOBUTILS_WRAPPER_SLEEP} ${O2_ROOT}/share/scripts/cpulimit -l ${cpulim} -p ${p} > /dev/null 2> /dev/null & disown + proc=$! + limitPIDs="${limitPIDs} ${proc}" + waslimited[$p]=1 + fi + done + else + # echo "RESETING REDUCTION = 1" + reduction_factor=1. + fi + fi + let cpucounter=cpucounter+1 + # our condition for inactive + if (( $(echo "${totalCPU} < 5" | bc -l 2> /dev/null) )); then + let inactivitycounter=inactivitycounter+JOBUTILS_WRAPPER_SLEEP + else + inactivitycounter=0 + fi + if [ "${JOBUTILS_JOB_KILLINACTIVE}" ]; then + $(awk -v I="${inactivitycounter}" -v T="${JOBUTILS_JOB_KILLINACTIVE}" 'BEGIN {if(I>T){exit 1;} exit 0;}') + if [ "$?" = "1" ]; then + echo "task inactivity limit reached .. killing all processes"; + taskwrapper_cleanup $PID SIGKILL + # call a more specialized hook for this?? + if [ "${JOBUTILS_JOB_FAILUREHOOK}" ]; then + hook="${JOBUTILS_JOB_FAILUREHOOK} '$command' $logfile" + eval "${hook}" + fi + [ "${JOBUTILS_PRINT_ON_ERROR}" ] && echo ----- Last log: ----- && pwd && cat ${logfile} && echo ----- End of log ----- + [[ ! "${JOBUTILS_NOEXIT_ON_ERROR}" ]] && [[ ! $- == *i* ]] && exit 1 + return 1 + fi + fi + fi + + # a good moment to check for jobs timeout (or other resources) + if [ "$JOBUTILS_JOB_TIMEOUT" ]; then + $(awk -v S="${SECONDS}" -v T="${JOBUTILS_JOB_TIMEOUT}" -v START="${STARTTIME}" 'BEGIN {if((S-START)>T){exit 1;} exit 0;}') + if [ "$?" = "1" ]; then + echo "task timeout reached .. killing all processes"; + taskwrapper_cleanup $PID SIGKILL + # call a more specialized hook for this?? + if [ "${JOBUTILS_JOB_FAILUREHOOK}" ]; then + hook="${JOBUTILS_JOB_FAILUREHOOK} '$command' $logfile" + eval "${hook}" + fi + [ "${JOBUTILS_PRINT_ON_ERROR}" ] && echo ----- Last log: ----- && pwd && cat ${logfile} && echo ----- End of log ----- + [[ ! "${JOBUTILS_NOEXIT_ON_ERROR}" ]] && [[ ! $- == *i* ]] && exit 1 + return 1 + fi fi + # Try to find out DPL session ID + # if [ -z "${JOBUTILS_INTERNAL_DPL_SESSION}" ]; then + JOBUTILS_INTERNAL_DPL_SESSION=$(_parse_DPL_session ${PID}) + # echo "got session ${JOBUTILS_INTERNAL_DPL_SESSION}" + # fi + # sleep for some time (can be customized for power user) - sleep ${JOBUTILS_WRAPPER_SLEEP:-5} + sleep ${JOBUTILS_WRAPPER_SLEEP:-1} + + # power feature: we allow to call a user hook at each i-th control + # iteration + if [ "${JOBUTILS_JOB_PERIODICCONTROLHOOK}" ]; then + if [ "${control_iteration}" = "${JOBUTILS_JOB_CONTROLITERS:-10}" ]; then + hook="${JOBUTILS_JOB_PERIODICCONTROLHOOK} '$command' $logfile" + eval "${hook}" + control_iteration=0 + fi + fi + + let control_iteration=control_iteration+1 done # wait for PID and fetch return code # ?? should directly exit here? - wait $PID - # return code - RC=$? + wait $PID || QUERY_RC_FROM_LOG="ON" + # query return code from log (seems to be safer as sometimes the wait issues "PID" not a child of this shell) + RC=$(grep -a "TASK-EXIT-CODE:" ${logfile} | awk '//{print $2}') RC_ACUM=$((RC_ACUM+RC)) if [ "${RC}" -eq "0" ]; then - # if return code 0 we mark this task as done - echo "Command \"${command}\" successfully finished." > "${logfile}"_done - echo "The presence of this file can be used to skip this command in future runs" >> "${logfile}"_done - echo "of the pipeline by setting the JOBUTILS_SKIPDONE environment variable." >> "${logfile}"_done + if [ ! "${JOBUTILS_JOB_SKIPCREATEDONE}" ]; then + # if return code 0 we mark this task as done + echo "Command \"${command}\" successfully finished." > "${logfile}"_done + echo "The presence of this file can be used to skip this command in future runs" >> "${logfile}"_done + echo "of the pipeline by setting the JOBUTILS_SKIPDONE environment variable." >> "${logfile}"_done + fi else echo "command ${command} had nonzero exit code ${RC}" + [ "${JOBUTILS_PRINT_ON_ERROR}" ] && echo ----- Last log: ----- && pwd && cat ${logfile} && echo ----- End of log ----- fi [ ! "${JOBUTILS_KEEPJOBSCRIPT}" ] && rm ${SCRIPTNAME} 2> /dev/null @@ -241,7 +403,7 @@ taskwrapper() { o2_cleanup_shm_files #--> better to register a general trap at EXIT # this gives some possibility to customize the wrapper - # and do some special task at the ordinary exit. The hook takes 3 arguments: + # and do some special task at the ordinary exit. The hook takes 3 arguments: # - The original command # - the logfile # - the return code from the execution @@ -250,13 +412,30 @@ taskwrapper() { eval "${hook}" fi + if [ ! "${RC}" -eq "0" ]; then + if [ ! "${JOBUTILS_NOEXIT_ON_ERROR}" ]; then + # in case of incorrect termination, we usually like to stop the whole outer script (== we are in non-interactive mode) + [[ ! $- == *i* ]] && exit ${RC} + fi + fi + if [ "${JOBUTILS_MONITORMEM}" ]; then + # convert bytes in MB + MAX_FMQ_SHM=${MAX_FMQ_SHM:-0} + MAX_FMQ_SHM=$(awk -v "s=${MAX_FMQ_SHM}" 'BEGIN { print s/(1024.*1024) }') + echo "PROCESS MAX FMQ_SHM = ${MAX_FMQ_SHM}" >> ${logfile} + fi + unset JOBUTILS_INTERNAL_DPL_SESSION return ${RC} } getNumberOfPhysicalCPUCores() { if [ "$(uname)" == "Darwin" ]; then CORESPERSOCKET=`system_profiler SPHardwareDataType | grep "Total Number of Cores:" | awk '{print $5}'` - SOCKETS=`system_profiler SPHardwareDataType | grep "Number of Processors:" | awk '{print $4}'` + if [ "$(uname -m)" == "arm64" ]; then + SOCKETS=1 + else + SOCKETS=`system_profiler SPHardwareDataType | grep "Number of Processors:" | awk '{print $4}'` + fi else # Do something under GNU/Linux platform CORESPERSOCKET=`lscpu | grep "Core(s) per socket" | awk '{print $4}'` @@ -266,3 +445,11 @@ getNumberOfPhysicalCPUCores() { echo "${N}" } +getNumberOfLogicalCPUCores() { + if [ "$(uname)" == "Darwin" ]; then + echo $(sysctl -n hw.logicalcpu) + else + # Do something under GNU/Linux platform + echo $(grep "processor" /proc/cpuinfo | wc -l) + fi +} diff --git a/Utilities/aliceHLTwrapper/.gitignore b/Utilities/aliceHLTwrapper/.gitignore deleted file mode 100644 index b25c15b81fae0..0000000000000 --- a/Utilities/aliceHLTwrapper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*~ diff --git a/Utilities/aliceHLTwrapper/CMakeLists.txt b/Utilities/aliceHLTwrapper/CMakeLists.txt deleted file mode 100644 index 4487ca73b1de1..0000000000000 --- a/Utilities/aliceHLTwrapper/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -# @author Matthias Richter @brief cmake setup for module -# devices/aliceHLTwrapper - -o2_add_library(aliceHLTwrapper - SOURCES src/SystemInterface.cxx - src/HOMERFactory.cxx - src/WrapperDevice.cxx - src/Component.cxx - src/MessageFormat.cxx - src/EventSampler.cxx - PUBLIC_LINK_LIBRARIES FairMQ::FairMQ O2::Headers O2::Device - Boost::thread) - -o2_target_man_page(aliceHLTwrapper NAME o2-alicehlt-wrapper-device) -o2_target_man_page(aliceHLTwrapper NAME AliceHLTComponents) - -o2_add_executable(wrapper-device - SOURCES src/aliceHLTWrapper.cxx - COMPONENT_NAME alicehlt - PUBLIC_LINK_LIBRARIES O2::aliceHLTwrapper) - -o2_add_executable(eventsampler-device - SOURCES src/aliceHLTEventSampler.cxx - COMPONENT_NAME alicehlt - PUBLIC_LINK_LIBRARIES O2::aliceHLTwrapper) - -o2_add_executable(runcomponent - SOURCES src/runComponent.cxx - COMPONENT_NAME alicehlt - PUBLIC_LINK_LIBRARIES O2::aliceHLTwrapper) - -o2_add_test(MessageFormat - COMPONENT_NAME alicehlt - SOURCES test/testMessageFormat.cxx - PUBLIC_LINK_LIBRARIES O2::aliceHLTwrapper - LABELS utils) diff --git a/Utilities/aliceHLTwrapper/README b/Utilities/aliceHLTwrapper/README deleted file mode 100644 index bd53b83d5b460..0000000000000 --- a/Utilities/aliceHLTwrapper/README +++ /dev/null @@ -1,114 +0,0 @@ -The ALICE HLT wrapper device allows to bind ALICE HLT components from AliRoot into a -FairDevice using the HLt external interface. - -1) External software packages -============================= -All necessary packages need to be installed as a prerequesite to compiling -AliceO2. See the instractions in the top directory. The ALICE HLT wrapper -device requires Root, FairRoot, Aliroot - -2) Environment -============== -AliRoot, FairRoot and external packages need to be set up, in particular -library directories need to be added to LD LIBRARY PATH, bin folder to -PATH, e.g. - - # you have to set up the environment according to the AliceO2 package - # install dir and the external package install dir - export ALICEO2_INSTALL_DIR=<path to AliceO2 install dir> - export ALICEO2_EXTERNALS=<path to external package install folder> - - export ROOTSYS=$ALICEO2_EXTERNALS - export ALICE_ROOT=$ALICEO2_EXTERNALS/AliRoot # see comment below - - export LD_LIBRARY_PATH=$ALICEO2_INSTALL_DIR/lib:$ALICEO2_EXTERNALS/lib:$ROOTSYS/lib/root:$LD_LIBRARY_PATH - export PATH=$ALICEO2_INSTALL_DIR/bin:$ALICEO2_EXTERNALS/bin:$ALICEO2_EXTERNALS/FairRoot/bin:$ALICEO2_EXTERNALS/AliRoot/bin:$ROOTSYS/bin:$PATH - -A word on the ALICE_ROOT variable - # the plan for the future is to be independent of ALICE_ROOT, for - # the moment some code still uses the variable to open data files - # shipped with the source code - export ALICE_ROOT=<path of AliRoot source code> - -Path to the OCDB copy used for running the HLT components, here is -an example, you have to use the correct OCDB for the data set. - - export ALIHLT_HCDBDIR=local://./OCDB - -3) Test Data -============ -Generate binary files of HLT TPC clusters to be used by FilePublishers of a simple processing topology, -e.g. 6 publishers (one full slice/sector of the TPC) to one tracker instance -Using: -macro example/alice/hlt/macros/hltConfigurations.C to define a custom chain -macro $ALICE_ROOT/HLT/exa/recraw-local.C to run the HLT chain embedded to AliRoot reconstruction - - ln -s $ALICE_ROOT/HLT/exa/recraw-local.C - ln -s $ALICE_ROOT/HLT/exa/EnableHLTInGRP.C - aliroot -b -q -l hltConfigurations.C recraw-local.C’("raw.root", "raw://", 0, 0, "HLT TPC", "loglevel=0x79 chains=cluster-collection", "local://./OCDB")’ - aliroot -b -q -l EnableHLTInGRP.C’(167808, "local://./OCDB", "local://./OCDB")’ - rm galice.root QA.root - aliroot -b -q -l hltConfigurations.C recraw-local.C’("raw.root", "local://OCDB", -1, -1, "HLT", "loglevel=0x79 chains=cluster-collection")’ 2>&1 | tee cluster-collection.log - -Runs HLT TPC cluster emulation, binary files stored in emulated-tpc-clusters -configuration files emulated-tpc-clusters *.txt for FilePublisher components - -Be aware that there might be crashes of the AliRoot framework after the last event has been -processed. That does not effect the generation of the test data. - -4) Running the Wrapper -====================== -The wrapper can run any ALIROOT HLT component. Components are implemented in -component libraries which are loaded at runtime into the system. Each component -is uniquely identified by the component identifier and the library. Additional -component parameters might be necessary to configure the component and control. -The processing. - -The ALICE HLT wrapper implements a FairDevice, the parameters can be categorized -in three groups: -a) device specific arguments: id and number of i/o threads - -b) flexible input and output slot configuration, multiple arguments possible - --output|--input type=<value>,size=<size>,method=<value>,address=<value> - -c) HLT component arguments: library, component id, parameters, run number - --library <library name> --component <component id> --run <no> - -NOTE: the three groups have to be in that fixed sequence!!! - -Example: - aliceHLTWrapper ClusterPublisher_00_0 1 \ - --output type=push,size=1000,method=bind,address=tcp://*:45000 \ - --library libAliHLTUtil.so --component FilePublisher --run 167808 \ - --parameter ’-datafilelist emulated-tpc-clusters_0x00000000.txt’ - -Some explanation: -This starts a device instance with a name/id 'ClusterPublisher_00_0 and 1 I/O -thread. The name of the device instance should be unique within the configuration -describing the processing hierarchy. -The actual component has the identifier 'FilePublisher' and is implemented in -'libAliHLTUtil.so'. In order to run it it needs some configuration, namely the -files to be published in the individual events. That is defined in the -configuration file 'emulated-tpc-clusters_0x00000000.txt'. - -Simple topology: -Helper script to create the commands to launch multiple processes on a single -machine. - launchSimpleChain.sh - - -4) Source code -============== -SystemInterface.cxx/.h counterpart of the ALICE HLT external interface -Component.cxx/.h all HLT component related code -WrapperDevice.cxx/.h specific implementation of FairMQ device -aliceHLTWrapper.cxx: executable of the FairMQ device -runComponent.cxx: AliRoot HLT interface test program for the Component -HOMERFactory.cxx/.h: Originally AliHLTHOMERLibManager from AliRoot - -The following headers have been copied from AliRoot, in the future they might be -taken directly from AliRoot -AliHLTDataTypes.h Common data type and function definition for the HLT code -AliHLTHOMERData.h Data structure definition for the HOMER interface -AliHLTHOMERReader.h Abstract interface for the HOMER reader -AliHLTHOMERWriter.h Abstract interface for the HOMER writer diff --git a/Utilities/aliceHLTwrapper/cluster-relay-to-tracker.sh b/Utilities/aliceHLTwrapper/cluster-relay-to-tracker.sh deleted file mode 100755 index 30f52f41459bf..0000000000000 --- a/Utilities/aliceHLTwrapper/cluster-relay-to-tracker.sh +++ /dev/null @@ -1,537 +0,0 @@ -#! /bin/bash - -#**************************************************************************** -#* This file is free software: you can redistribute it and/or modify * -#* it under the terms of the GNU General Public License as published by * -#* the Free Software Foundation, either version 3 of the License, or * -#* (at your option) any later version. * -#* * -#* Primary Authors: Matthias Richter <Matthias.Richter@scieq.net> * -#* * -#* The authors make no claims about the suitability of this software for * -#* any purpose. It is provided "as is" without express or implied warranty. * -#**************************************************************************** - -# @file cluster-relay-to-tracker.sh -# @author Matthias Richter -# @since 2014-11-26 -# @brief Launch script for ALICE HLT TPC processing topology - - -################################################################### -# global settings -runno=167808 - -# note: don't want to overdo the logic now, the lastslice should be firstslice plus multiples of slices_per_node minus 1 -# lastslice=(firstslice + n*slices_per_node) - 1 -# -# TODO: this possibly needs some more checking -firstslice=0 -lastslice=35 -slices_per_node=1 -pollingtimeout=100 -eventperiod=100000 -initialdelay=10000 # time before trigger starts -CFoptOpenFilesAtStart=" -open_files_at_start" -CFoptPublishIndividualPartitions=no #yes -#CFoptLocalConfigFile=/tmp/tpc-cluster-publisher.conf -write_tracks=yes -syncrundir=no -rundir=`pwd` - -baseport_on_flpgroup=48400 -baseport_on_epn1group=48450 -baseport_on_epn2group=48470 -baseport_on_triggergroup=48475 -triggernode=localhost -epn2node=localhost - -# uncomment the following line to print the commands instead of -# actually launching them -#printcmdtoscreen='echo' - -# uncomment the following line to bypass the FLP relays and -# send data directly to th tracker -#bypass_relays=yes - -# uncomment the following line to bypass the tracking -#bypass_tracking=yes - -################################################################### -# argument scan -# TODO: implement real argument scan and more configurable options -while [ "x$1" != "x" ]; do - if [ "x$1" == "x--print-commands" ]; then - printcmdtoscreen='echo' - elif [ "x$1" == "x--polling-timeout" ] && [ "x$2" != "x" ] ; then - pollingtimeout=$2 - shift - elif [ "x$1" == "x--eventperiod" ] && [ "x$2" != "x" ] ; then - eventperiod=$2 - shift - elif [ "x$1" == "x--initialdelay" ] && [ "x$2" != "x" ] ; then - initialdelay=$2 - shift - elif [ "x$1" == "x--first-slice" ] && [ "x$2" != "x" ] ; then - firstslice=$2 - shift - elif [ "x$1" == "x--last-slice" ] && [ "x$2" != "x" ] ; then - lastslice=$2 - shift - elif [ "x$1" == "x--sync-rundir" ]; then - syncrundir=yes - elif [ "x$1" == "x--write-tracks" ]; then - write_tracks=yes - elif [ "x$1" == "x--skip-write-tracks" ]; then - write_tracks=no - elif [ "x$1" == "x--skip-tracking" ]; then - # skip the tracking by using the dry-run option of the wrapper - # component - skiptracking="-n" - elif [ "x$1" == "x--enable-gpu" ]; then - # set the GPU parameter for the tracker - gpuparams="-allowGPU -GPUHelperThreads 4" - else - echo unknown option $1 - exit - fi - shift -done - -################################################################### -######## end of configuration area ############ -######## no changes beyond this point ############ -################################################################### - -################################################################### -# fill the list of nodes either from standard input or subsidiary -# script in the current directory -# -nodelist= - -flpinputnode= -flpinputsocket= -nflpinputs=0 -epnoutputnode= -epnoutputsocket= -nepnoutputs=0 -postponed_messages= -npostponed_messages=0 -while read line; do - flpdevice=`echo $line | sed -e '/^FLP_DEVICE_IN=/!d' -e 's|^FLP_DEVICE_IN=||'` - epndevice=`echo $line | sed -e '/^EPN_DEVICE_OUT=/!d' -e 's|^EPN_DEVICE_OUT=||'` - if [ "x$flpdevice" != "x" ]; then - echo "FLPINPUT: $flpdevice" - flpinputnode[nflpinputs]=`echo ${flpdevice} | sed -e 's/:.*//'` - flpinputsocket[nflpinputs]=`echo ${flpdevice} | sed -e 's/.*://'` - let nflpinputs++ - elif [ "x$epndevice" != "x" ]; then - echo "EPNOUTPUT $epndevice" - epnoutputnode[nepnoutputs]=`echo ${epndevice} | sed -e 's/:.*//'` - epnoutputsocket[nepnoutputs]=`echo ${epndevice} | sed -e 's/.*://'` - let nepnoutputs++ - elif [ "x${line:0:11}" == "xscheduling " ]; then - echo $line - elif [ "x$line" != "x" ]; then - postponed_messages[npostponed_messages]=" $line" - let npostponed_messages++ - else - echo - fi -done - -for node in `for n in ${flpinputnode[@]}; do echo $n; done | sort | uniq`; do - flpnodelist=(${flpnodelist[@]} $node) - nodelist=(${nodelist[@]} $node) -done -for node in `for n in ${epnoutputnode[@]}; do echo $n; done | sort | uniq`; do - epnnodelist=(${epnnodelist[@]} $node) - nodelist=(${nodelist[@]} $node) -done - -# read from subsidiary script in the current directory if nodelist not -# yet filled -nodelistfile=nodelist.sh -if [ "x$nodelist" == "x" ] && [ -e $nodelistfile ]; then - . $nodelistfile -fi - -if [ "x$nodelist" == "x" ]; then -cat <<EOF -error: can not find node definition - -Please add a script file 'nodelist.sh' in the current directory -defining the nodes to be used in this topology. - -############## example ############################## -nodelist= -nodelist=(\${nodelist[@]} localhost) -#nodelist=(\${nodelist[@]} someothernode) - -EOF -exit -1 -fi -nnodes=${#nodelist[@]} -nflpnodes=${#flpnodelist[@]} -nepnnodes=${#epnnodelist[@]} - -# the same node name can be specified for multiple FLP groups -# this map holds a count of sockets already used per node -declare -A numberOfUsedSocketsPerNode - -echo "using ${#flpinputnode[@]} FLP(s) on $nflpnodes node(s) and $nepnnodes EPN node(s) for running processing topology" -echo "FLP ${flpnodelist[@]} - EPN ${epnnodelist[@]}" - -# init the variables for the session commands -sessionnode= -sessiontitle= -sessioncmd= -nsessions=0 - - -################################################################### -# check if the output of the parent is binding or not -# and set the attributes according to that -# name=data-out <--> name=data-in -# bind <--> connect -# push <--> pull -translate_io_attributes() { - __inputattributes=$1 - __translated=`echo $1 | sed -e 'h; /name=data-out/{s|name=data-out|name=data-in|g; p}; g; /name=data-in/{s|name=data-in|name=data-out|g; p}; d'` - __node=${2:-localhost} - if [ x`echo ${__inputattributes} | sed -e 's|.*method=\(.*\)|\1|' -e 's|,.*$||'` == "xbind" ]; then - __translated=`echo ${__translated} | sed -e "s|://\*:|://${__node}:|g" -e 's|method=bind|method=connect|g'` - else - __translated=`echo ${__translated} | sed -e 's|://.*:|://*:|g' -e 's|method=connect|method=bind|g'` - fi - if [[ ${__translated} == *push* ]] || [[ ${__translated} == *pull* ]]; then - __translated=`echo ${__translated} | sed -e 'h; /type=push/{s/type=push/type=pull/g; p}; g; /type=pull/{s/type=pull/type=push/g; p}; d'` - elif [[ ${__translated} == *pub* ]] || [[ ${__translated} == *sub* ]]; then - __translated=`echo ${__translated} | sed -e 'h; /type=pub/{s/type=pub/type=sub/g; p}; g; /type=sub/{s/type=sub/type=pub/g; p}; d'` - fi - echo $__translated -} - -################################################################### -# create the trigger node group -flp_trigger_input= -create_triggergroup() { - node=$1 - basesocket=$2 - socketcount=0 - - deviceid="Trigger" - input= - output="--channel-config name=data-out,type=pub,size=5000,method=bind,address=tcp://*:$((basesocket + socketcount))" - let socketcount++ - command="o2-alicehlt-eventsampler-device --id=$deviceid $input $output --eventperiod $eventperiod --initialdelay $initialdelay --latency-log /tmp/latency.log" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - - flp_trigger_input=${output/\/\/\*:///$node:} -} - -################################################################### -# create an flp node group -epn1_input= -n_epn1_inputs=0 -create_flpgroup() { - node=$1 - basesocket=$2 - firstslice_on_node=$3 - nofslices=$4 - groupoutputsocket=$5 - socketcount=0 - cf_output= - if [ "x$CFoptPublishIndividualPartitions" == "xyes" ]; then - nofIndividualPartitions=6 - else - nofIndividualPartitions=1 - fi - for ((c=0; c<nofslices; c++)); do - for ((partition=0; partition<nofIndividualPartitions; partition++)); do - slice=$((firstslice_on_node + c)) - socket=$((basesocket + socketcount)) - let socketcount++ - if [ "$nofIndividualPartitions" -le 1 ]; then - spec=`printf %02d $slice` - specprefix="slice_" - else - spec=0x`printf %02x%02x%02x%02x $slice $slice $partition $partition` - specprefix= - fi - deviceid="ClusterPublisher_$spec" - input= - if [ "x$flp_trigger_input" != "x" ]; then - input=`translate_io_attributes "$flp_trigger_input"` - fi - output="--channel-config name=data-out,type=push,size=5000,method=bind,address=tcp://*:$socket" - if [ "x$syncrundir" == "xyes" ]; then - echo "synchronizing data $rundir on node $node" - rsync -auL --include="*CLUSTERS_"`printf 0x%02x $slice`"*" --exclude="event_*" $rundir/ $node:$rundir - fi - publisher_conf_file=data/emulated-tpc-clusters_$specprefix$spec.txt - if [ "x$CFoptLocalConfigFile" != "x" ]; then - echo "copying publisher configuration file $publisher_conf_file to $CFoptLocalConfigFile on node $node" - scp $publisher_conf_file $node:$CFoptLocalConfigFile - publisher_conf_file=$CFoptLocalConfigFile - fi - command="o2-alicehlt-wrapper-device --id=$deviceid --poll-period $pollingtimeout $input $output --library libAliHLTUtil.so --component FilePublisher --run $runno --parameter '-datafilelist $publisher_conf_file $CFoptOpenFilesAtStart'" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]=$deviceid - sessioncmd[nsessions]=$command - let nsessions++ - - cf_output="$cf_output ${output}" - done - done - - if [ "x$bypass_relays" != "xyes" ]; then - # add a relay combining CF output into one (multi)message - deviceid=Relay_`printf %02d $slice` - input=`translate_io_attributes "$cf_output"` - # output configuration is either taken from the flp/epn network - # or according to the base socket - output= - if [ "$nflpinputs" -eq 0 ]; then - output="--channel-config name=data-out,type=push,size=5000,method=bind,address=tcp://*:$((basesocket + socketcount))" - let socketcount++ - else - output="--channel-config name=data-out,type=push,size=5000,method=connect,address=tcp://${node}:${groupoutputsocket}" - fi - - command="o2-alicehlt-wrapper-device --id=$deviceid --poll-period $pollingtimeout $input $output --library libAliHLTUtil.so --component BlockFilter --run $runno --parameter ''" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - numberOfUsedSocketsPerNode[$node]=$(( numberOfUsedSocketsPerNode[$node] + socketcount )) - - epn1_input[n_epn1_inputs]=${output/\/\/\*:///$node:} - let n_epn1_inputs++ - else - # add each CF output directly to EPN input - # TODO: this is a bug, but it does not harm - # the string is broken up at blanks, so the option-parameter - # relation is lost and there are too many elements in the array, - # the array is expanded to a string, so does not matter at the moment - for output in $cf_output; do - epn1_input[n_epn1_inputs]=${output/\/\/\*:///$node:} - let n_epn1_inputs++ - done - fi -} - -################################################################### -# create an epn1 node group -epn2_input= -ntrackers=0 -globalmergerid=0 -create_epn1group() { - node=$1 - basesocket=$2 - # epn2 input commonly subscribes to output of top devices of all epn1 node groups - epn2_input=$3 - socketcount=0 - - # check if there is a FLP to EPN topology available - epnoutputonnode= - nepnoutputonnode=0 - for ((iepnoutput=0; iepnoutput<nepnoutputs; iepnoutput++)); do - if [ "${epnoutputnode[$iepnoutput]}" == "$node" ]; then - epnoutputonnode[nepnoutputonnode]="tcp://${epnoutputnode[$iepnoutput]}:${epnoutputsocket[$iepnoutput]}" - let nepnoutputonnode++ - fi - done - - ntrackersonnode=$nepnoutputonnode - [ "$nepnoutputonnode" -eq 0 ] && ntrackersonnode=1 # at least one tracker - if [ "x$bypass_tracking" != "xyes" ]; then - for ((trackerid=0; trackerid<$ntrackersonnode; trackerid++)); do - - deviceid=`printf %03d $ntrackers` - deviceid="Tracker_$deviceid" - let ntrackers++ - if [ "$nepnoutputonnode" -eq 0 ]; then - output=`echo "${epn1_input[@]}"` - input=`translate_io_attributes "$output"` - else - input="--channel-config name=data-in,type=pull,size=1000,method=connect,address=${epnoutputonnode[$trackerid]}" - fi - - output="--channel-config name=data-out,type=push,size=1000,method=connect,address=tcp://localhost:$((basesocket + socketcount))" - command="o2-alicehlt-wrapper-device --id=$deviceid ${skiptracking} --poll-period $pollingtimeout $input $output --library libAliHLTTPC.so --component TPCCATracker --run $runno --parameter '-GlobalTracking ${gpuparams} -loglevel=0x7c'" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - done - socketcount=$((trackerid + 1)) - - deviceid=GlobalMerger_`printf %02d $globalmergerid` - input=`translate_io_attributes "$output"` - output=`translate_io_attributes "$epn2_input"` - let socketcount++ - command="o2-alicehlt-wrapper-device --id=$deviceid ${skiptracking} --poll-period $pollingtimeout $input $output --library libAliHLTTPC.so --component TPCCAGlobalMerger --run $runno --parameter '-loglevel=0x7c'" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - let globalmergerid++ - fi - - # deviceid=FileWriter - # input=`translate_io_attributes "$output"` - # output= - # let socketcount++ - # command="o2-alicehlt-wrapper-device --id=$deviceid ${skiptracking} --poll-period $pollingtimeout $input $output --library libAliHLTUtil.so --component FileWriter --run $runno --parameter '-directory tracker-output -idfmt=%04d -specfmt=_%08x -blocknofmt= -loglevel=0x7c -write-all-blocks -publisher-conf tracker-output/datablocks.txt'" - - # sessionnode[nsessions]=$node - # sessiontitle[nsessions]="$deviceid" - # sessioncmd[nsessions]=$command - # let nsessions++ -} - -################################################################### -# create an epn2 node group -# collects different processing branches from epn1 -create_epn2group() { - node=$1 - basesocket=$2 - socketcount=0 - - deviceid=Collector - epn2_input="--channel-config name=data-in,type=pull,size=1000,method=bind,address=tcp://$node:$((basesocket + socketcount))" - let socketcount++ - input=$epn2_input - output="--channel-config name=data-out,type=pub,size=1000,method=bind,address=tcp://$node:$((basesocket + socketcount))" - let socketcount++ - command="o2-alicehlt-wrapper-device --id=$deviceid --poll-period $pollingtimeout $input $output --library libAliHLTUtil.so --component BlockFilter --run $runno --parameter ''" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - - if [ "x$write_tracks" == "xyes" ] ; then - deviceid=FileWriter - input=`translate_io_attributes "$output"` - output= - command="o2-alicehlt-wrapper-device --id=$deviceid --poll-period $pollingtimeout $input $output --library libAliHLTUtil.so --component FileWriter --run $runno --parameter '-directory tracker-output -subdir -idfmt=%04d -specfmt=_%08x -blocknofmt= -loglevel=0x7c -write-all-blocks -publisher-conf tracker-output/datablocks.txt'" - - sessionnode[nsessions]=$node - sessiontitle[nsessions]="$deviceid" - sessioncmd[nsessions]=$command - let nsessions++ - fi -} - -########### main script ########################################### -# -# now build the commands on the nodes -# trigger nodegroup -create_triggergroup $triggernode $baseport_on_triggergroup - -# flp nodegroups -sliceno=$firstslice -inode=0 -while [ "$sliceno" -le "$lastslice" ]; do - if [ "$inode" -ge "${#flpinputnode[@]}" ]; then - echo "error: too few nodes to create all flp node groups" - sliceno=$((lastslice + 1)) - exit -1 - fi - node=${flpinputnode[inode]} - create_flpgroup $node $(( baseport_on_flpgroup + ${numberOfUsedSocketsPerNode[$node]:=0} )) $sliceno $slices_per_node ${flpinputsocket[inode]} - sliceno=$((sliceno + slices_per_node)) - - let inode++ -done - -# epn2 nodegroup -# has one input which all epn1 outputs will connect to -create_epn2group ${epn2node} $baseport_on_epn2group - -# epn1 nodegroup -inode=0 -while [ "$inode" -lt "$nepnnodes" ]; do - create_epn1group ${epnnodelist[inode]} $baseport_on_epn1group "$epn2_input" - let inode++ -done - -# start the screen sessions and devices -sessionmap= -for ((isession=$nsessions++-1; isession>=0; isession--)); do - sessionmap[isession]=1 -done -havesessions=1 - -applications= -usednodes=`for n in ${sessionnode[@]}; do echo $n; done | sort | uniq` -if [ "x$syncrundir" == "xyes" ]; then -for node in $usednodes; do - echo "synchronizing setup $rundir on node $node" - rsync -auL --include="setup.sh" --exclude="*" $rundir/ $node:$rundir - rsync -auL $rundir/data/OCDB/ $node:$rundir/data/OCDB -done -fi - -while [ "$havesessions" -gt 0 ]; do -havesessions=0 -lastnode= - -for ((isession=$nsessions++-1; isession>=0; isession--)); do - if [ "${sessionmap[isession]}" -eq 1 ]; then - if [ "x$printcmdtoscreen" == "x" ]; then - echo "scheduling ${sessiontitle[$isession]} on ${sessionnode[$isession]}: ${sessioncmd[$isession]}" - fi - #logcmd=" 2>&1 | tee ${sessiontitle[$isession]}.log" - applications+=" "`echo ${sessioncmd[$isession]} | sed -e 's| .*$||'` - fi - - if [ "${sessionmap[isession]}" -gt 0 ]; then - #echo $isession: ${sessionmap[isession]} $lastnode - if [ "x$lastnode" == "x${sessionnode[$isession]}" ] && [ "${sessionmap[$isession]}" -lt 10 ]; then - let sessionmap[isession]++ - havesessions=1 - else - if [ "x$lastnode" == "x${sessionnode[$isession]}" ]; then - # sleep between starts, some of the screens are not started if the frequency is too high - usleep 500000 - fi - logcmd="2>&1 | tee ${sessiontitle[$isession]}.log"; - $printcmdtoscreen screen -d -m -S "${sessiontitle[$isession]} on ${sessionnode[$isession]}" ssh ${sessionnode[$isession]} "cd $rundir && source setup.sh && ${sessioncmd[$isession]} $logcmd" & - sessionmap[isession]=0 - lastnode=${sessionnode[$isession]} - fi - fi -done -done - -echo -for ((imsg=0; imsg<npostponed_messages; imsg++)); do - [ "x${postponed_messages[$imsg]:0:12}" == "xfor node in" ] && continue - echo ${postponed_messages[$imsg]} -done -if [ "x$printcmdtoscreen" == "x" ]; then -echo - -echo -echo "started processing topology in ${#sessionnode[@]} session(s) on `echo $usednodes | wc -w` node(s):" -usednodes=`echo $usednodes | sed ':a;N;$!ba;s/\n/ /g'` -echo $usednodes - -applications=`for app in $applications; do echo $app; done | sort | uniq` -echo -echo "a simple method to stop the devices:" -for app in $applications; do - echo "for node in $usednodes; do ssh \$node killall $app; done" -done -fi diff --git a/Utilities/aliceHLTwrapper/doc/AliceHLTComponents.1.in b/Utilities/aliceHLTwrapper/doc/AliceHLTComponents.1.in deleted file mode 100644 index c57a348988c58..0000000000000 --- a/Utilities/aliceHLTwrapper/doc/AliceHLTComponents.1.in +++ /dev/null @@ -1,138 +0,0 @@ -.\" Manpage for AliceHLT components. -.TH AliceO2 1 "19 May 2017" "1.0" "AliceHLT components man page" - -.SH DESCRIPTION -ALICE HLT components are part of AliRoot and can be plugged into the -O2 system via the o2-alicehlt-wrapper-device. The wrapper device takes the -shared library name and component id as parameters to instantiate the -component instance. - -.SH SELECTED COMPONENTS -.B libAliHLTUtil.so - FilePublisher - FileWriter - ROOTFilePublisher - ROOTFileWriter - -.SH COMPONENT OPTIONS -.SS FilePublisher -.TP 2 -.B -datafile -.I filename - data file to be published -.TP 2 -.B -datafilelist -.I configfile - read arguments from a configfile -.TP 2 -.B -datatype -.I datatype dataorigin - data type ID and origin, e.g. -datatype 'CLUSTERS' 'TPC ' -.TP 2 -.B -dataspec -.I specification - data specification treated as decimal number or hex number if prepended by '0x' -.TP -.B -open_files_at_start (optional) -Opens all files during component initialisation rather than as needed during event processing. Note: this feature may result in the system running out of file handles if a large number of files was specified. -.TP -.B -nextevent (optional) -indicate subsequent files to be published by the next event - -.SS FileWriter -.TP -.B -datafile -.I filename - file name base -.TP -.B -directory -.I directory - target directory -.TP -.B -subdir[=pattern] - create sub dir for each event, the format pattern can contain printfspecifiers to print the event no into the dir name, default is'event%%03lu' (-subdir w/o additional pattern). The format specifyer%%lu is automatically added if missing in the pattern. Please note thelong int type of the event id, the idfmt string is reset since the subdircontains the id -.TP -.B -idfmt[=pattern] - format specifier for the event id in the file name, default: on, default pattern: '_0x%%08x' -.TP -.B -specfmt[=pattern] -format specifier for the data specification in the file name default: off, default pattern: '_0x%%08x' -.TP -.B -blocknofmt[=pattern] -format specifier for the block no in the file name default: on, default pattern: '_0x%%02x' -.TP -.B -skip-datatype - do not consider data type when building the file name. -.TP -.B -enumerate -don't use the event number but an event counter beginning from 0 -.TP -.B -concatenate-blocks - concatenate all blocks of one event into one file, this skips the block no, and the block data type in the file name -.TP -.B -concatenate-events - concatenate all events into one file, this skips the event no, the block no, and the block data type in the file name. Currently, this implies the -concatenate-blocks option. -.TP -.B -publisher-conf -.I filename - write configuration file for FilePublisher component (AliHLTFilePublisher) one line per file: -datatype id origin -datafile filename events separated by -nextevent -.TP -.B -write-all-events - by default, the file writer ignores all steering events like thethe SOR/EOR events, with this option, all events will be consideredthe beginning. -.TP -.B -write-all-blocks - by default, the file writer ignores all blocks of origin {PRIV} (::kAliHLTDataOriginPrivate), with this option, all blocks willbe written. For SOR/EOR events, a short string will be added in the beginning. -.TP -.B -write-all - combines both -write-all-events and -write-all-blocks -.TP -.B -burst-buffer <size> - size of burst buffer, blocks are written to buffer until it is filled and written in one burst (though to different files according to conf). Note: burst write is currently only supported for mode -concatenate-events AND -concatenate-blocks (both enabled). -.TP -.B -datatype -.I id origin - data block selection by AliHLTBlockDataCollection -.TP -.B -origin -.I origin - data block selection by AliHLTBlockDataCollection -.TP -.B -typeid -.I id - data block selection by AliHLTBlockDataCollection -.TP -.B -dataspec -.I specification - data block selection by AliHLTBlockDataCollection - -.SS ROOTFilePublisher -Special implementation of the -.I FilePublisher -component. -.P -Additional options: -.TP -.B -objectname -.I objectname -Name of the object in the root file to be fetched. This is set for all events/files. If not given, all objects are fetched. - -.SS ROOTFileWriter -Special implementation of the -.I FileWriter -component. -.P -Additional options: -.TP -.B -overwrite -write objects with the TObject::kOverwrite flag and avoid multiple keys in the file - - -.SH AUTHOR -Matthias.Richter@scieq.net -All questions and suggestions welcome - -.SH "SEE ALSO" -o2-alicehlt-wrapper-device(1) - -.SH BUGS - diff --git a/Utilities/aliceHLTwrapper/doc/o2-alicehlt-wrapper-device.1.in b/Utilities/aliceHLTwrapper/doc/o2-alicehlt-wrapper-device.1.in deleted file mode 100644 index b1926d8318417..0000000000000 --- a/Utilities/aliceHLTwrapper/doc/o2-alicehlt-wrapper-device.1.in +++ /dev/null @@ -1,133 +0,0 @@ -.\" Manpage for o2-alicehlt-wrapper-device. -.TH AliceO2 1 "19 May 2017" "1.0" "o2-alicehlt-wrapper-device man page" -.SH NAME -o2-alicehlt-wrapper-device - FairRoot/ALFA device running ALICE HLT code - -.SH SYNOPSIS -.B o2-alicehlt-wrapper-device -.B --id -.I deviceid -.B --channel-config -.I config -.B --library -.I arg -.B --component -.I arg -.B --parameter -.I arg -.B --runno -.I n - -.SH DESCRIPTION - -A FairMQ device class supporting the HLT component interface -for processing. - -The device class implements the interface functions of FairMQ, and it -receives and send messages. The data of the messages are processed -using the Component class. - -.SH OPTIONS -.SS Common FairMQDevice options -.TP 2 -.B --id \fIid\fR -A unique identifier of the device -.TP 2 -.B --channel-config \fIargs\fR -channel configuration as comma separated key=\fIvalue\fR pairs -.RS -Valid Keys: -.B name -.B type -.B method -.B address -.B property -.RE - -.SS Mandatory HLT Component related options -.B Note: -Every HLT component has it's own set of (command line) options which can be passed via the \fB--parameter\fR option. -.TP 2 -.B --library \fIarg\fR -HLT library containing the component -.TP 2 -.B --component \fIarg\fR -HLT component id -.TP 2 -.B --parameter \fIarg\fR -Parameter of the component, make sure to put in quotes if the argument consists -of multiple strings -.TP 2 -.B --run \fIn\fR -Run number -.TP 2 -.B --ocdb \fIuri\fR -Set the OCDB URI and override the value of environment variable ALIHLT_HCDBDIR - -.SS Other Options -.B --poll-period \fIperiod\fR -Polling period on the input channel -.B --output-mode \fImode\fR -The output mode of the device, default is O2 format (3) -.RS 2 -.B 0 -- HOMER format -.br -.B 1 -- blocks in multiple messages -.br -.B 2 -- blocks concatenated in one message (default) -.br -.B 3 -- O2 format -.RE - -.SH FEATURES -.SS Message channels -The device supports input and output channels with the names -.IR --data-in / -.I --data-out -respectively. All input channels are treated equally and the device expects messages -from all channels before data is processed. - -If no input channel is specified the device will run in a self-triggered mode -and call the component processing repeatedly with the period specified by -.IR --poll-period . - -.SS Configuration database -HLT components need the Alice OCDB to load the configuration. The path to the OCDB -must be set in environment variable -.B ALIHLT_HCDBDIR -or via option -.BR --ocdb . - -.SS Heartbeat information -The device interprets Heartbeat frame data blocks at the input channel. If this -information is available at the input, all output blocks will be wrapped into -Haertbeat frames. - -.SH EXAMPLES -.B o2-alicehlt-wrapper-device ---id publisher \\ -.br ---channel-config \\ -.br - name=data-out,type=pub,method=bind,address=tcp://*:42424 \\ -.br ---library libAliHLTUtil.so --component FilePublisher --run 167808 \\ -.br ---parameter '-datafile some_file_to_publish' - -.SH AUTHOR -Matthias.Richter@scieq.net -All questions and suggestions welcome - -.SH SEE ALSO -AliceHLTComponents(1), FairMQDevice(1) - -.SH BUGS/ISSUES -.SS Parameter Manager -The device does not interface to the FairMQ parameter manager. The device itself -does not need any more parameters than the command line options. The HLT component -needs the ALICE OCDB location and the run number. diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTDataTypes.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTDataTypes.h deleted file mode 100644 index f618d117c388c..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTDataTypes.h +++ /dev/null @@ -1,1687 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// @(#) $Id$ - -#ifndef ALIHLTDATATYPES_H -#define ALIHLTDATATYPES_H -/* This file is property of and copyright by the ALICE HLT Project * - * ALICE Experiment at CERN, All rights reserved. * - * See cxx source for full Copyright notice */ - -/** @file AliHLTDataTypes.h - @author Matthias Richter, Timm Steinbeck, Jochen Thaeder - @date - @brief Data type declaration for the HLT module. -*/ - -////////////////////////////////////////////////////////////////////////// -// -// version no of HLT data types -// -////////////////////////////////////////////////////////////////////////// - -/* Version Description - * 1 first version until June 07; implicite, not tagged - * 2 introduced June 07, enhanced/cleaned/arranged structure - * 3 2007-11-15 RAW DDL data type added; some inconsistencies fixed - * ('void' and 'any' origins); added signed HLT basic data types - * 2007-11-23 origin defines have become variables in conjunction - * to be used with the operator| (AliHLTComponentDataType) - * 2007-11-24 added trigger structs and ESD tree data type - * 4 Component configuration and DCS update events added - * gkAliHLTDDLListSize set from 29 to 30 according to new PubSub - * specs - * 5 Data types for Run and Event summary, and for monitoring added - * 6 Common data types for TreeD and TreeR defined - * kAliHLTAllDataTypes and kAliHLTDataOriginSample added - * kAliHLTDataOriginEMCAL added - * kAliHLTDataTypeRunType added - * 7 kAliHLTDataTypeComponentStatistics, kAliHLTDataTypeComponentTable, - * and AliHLTComponentStatistics have been added for optional - * component block statistics - * 8 new wrapper interface has been introduced, old wrapper interface - * deprecated but kept for backward compatibility, the PubSub - * interface is going to be compiled independently of AliHLT, new - * interface provided by the libHLTinterface.so - * AliHLTComponentEnvironment -> AliHLTAnalysisEnvironment - * 9 added data types for arrays of AliHLTExternalTrackParam sets and - * TClonesArrays of AliExternalTrackParam objects. - * 10 Changes for information objects neededfor running with offline - * chains and analysis tasks. - * kAliHLTMCObjectDataType added - * kAliHLTDataOriginOffline added - * kAliHLTDataOriginHLT added - * 11 extended AliHLTComponentStatistics: one more member to store the - * cycle time between events per component. - * 12 added common data type id 'CLUSTERS' - * added data type 'ECSPARAM' for the full ECS parameter string to - * be sebt during SOR - * added kAliHLTDataTypeTrackMC (TRACK_MC) data type - * added data types (note: interface version stays the same - * kAliHLTDataTypeDAQRDOUT (DAQRDOUT) - * kAliHLTDataTypeTriggerDecision (TRIG_DEC) - * kAliHLTDataTypeGlobalTrigger (GLOBTRIG) - * kAliHLTDataTypeStreamerInfo (ROOTSTRI) - * 13 Changed AliHLTEventDDL to now contain 31 words. The extra word is - * for the EMCAL detector, which needs 46 DDLs after DCAL was added. - * 14 Adding new data block type for HLT global trigger counters. - * Adding data block type for ESD content - * Adding data block type for forwarded component table blocks - * Adding new event type for software triggers. - * 15 Modifying data block types for trigger counter blocks. - * 16 Adding data type for the meta data block to be forwarded by the - * TCPDumpSubscriber for the Common Data Header (CDH) and readout - * list information. - * 17 bugfix: definition of function AliHLTExtFctGetOutputSize did not - * match the implementation in AliHLTExternalInterface; the bug was - * introduced when extending the function call by one parameter and - * has never been observed in the ALICE HLT because the PubSub - * framework uses its own definition of function types - */ -#define ALIHLT_DATA_TYPES_VERSION 17 - -////////////////////////////////////////////////////////////////////////// -// -// HLT data origin variables. -// -// By converting from defines to variables, the origins can be used with -// the operator| -// -// AliHLTComponentDataType dt; -// dt = kAliHLTDataTypeDDLRaw | kAliHLTDataOriginTPC; -// -////////////////////////////////////////////////////////////////////////// - -/** field size of datat type origin - * @ingroup alihlt_component_datatypes - */ -const int kAliHLTComponentDataTypefOriginSize = 4; - -/** invalid data origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDataOriginVoid "\0\0\0" -/** old invalid data origin, kept for backward compatibility */ -#define kAliHLTVoidDataOrigin "\0\0\0" - -/** wildcard data type origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDataOriginAny "***" -/** old wildcard data type origin, kept for backward compatibility */ -#define kAliHLTAnyDataOrigin "***" - -/** Data origin HLT out - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginOut[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin HLT, used for HLT specifc data - * in offline chains. This not a bug! - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginHLT[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin Offline - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginOffline[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin HLT/PubSub private internal - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginPrivate[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin TPC - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginTPC[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin PHOS - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginPHOS[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin FMD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginFMD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin MUON - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginMUON[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin TRD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginTRD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ITS - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginITS[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ITSOut - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginITSOut[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ITS SPD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginITSSPD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ITS SDD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginITSSDD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ITS SSD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginITSSSD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin for examples - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginSample[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin EMCAL - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginEMCAL[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin TOF - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginTOF[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin HMPID - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginHMPID[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin CPV - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginCPV[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin PMD - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginPMD[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin T0 - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginT0[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin VZERO - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginVZERO[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ZDC - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginZDC[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin ACORDE - * @ingroup alihlt_component_datatypes - */ - -extern const char kAliHLTDataOriginACORDE[kAliHLTComponentDataTypefOriginSize]; - -/** Data origin TRG - * @ingroup alihlt_component_datatypes - */ -extern const char kAliHLTDataOriginTRG[kAliHLTComponentDataTypefOriginSize]; - -////////////////////////////////////////////////////////////////////////// -// -// HLT common data type defines -// -////////////////////////////////////////////////////////////////////////// - -/** field size of data type id - * @ingroup alihlt_component_datatypes - */ -const int kAliHLTComponentDataTypefIDsize = 8; - -/** invalid data type id - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTVoidDataTypeID "\0\0\0\0\0\0\0" - -/** special id for all data types: any + void - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTAllDataTypesID "ALLDATA" - -/** special id for any valid data type id - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTAnyDataTypeID "*******" - -/** DDL RAW data - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDDLRawDataTypeID \ - { \ - 'D', 'D', 'L', '_', 'R', 'A', 'W', ' ' \ - } - -/** CLUSTERS data - * Common data type for the output of cluster finders, the exact - * format depends on the origin (detector) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTClustersDataTypeID \ - { \ - 'C', 'L', 'U', 'S', 'T', 'E', 'R', 'S' \ - } - -/** calibration data for file exchange subscriber - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTFXSCalibDataTypeID \ - { \ - 'F', 'X', 'S', '_', 'C', 'A', 'L', ' ' \ - } - -/** start of run (SOR) event - * @ref AliHLTRunDesc - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTSORDataTypeID \ - { \ - 'S', 'T', 'A', 'R', 'T', 'O', 'F', 'R' \ - } - -/** end of run (EOR) event - * @ref AliHLTRunDesc - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTEORDataTypeID \ - { \ - 'E', 'N', 'D', 'O', 'F', 'R', 'U', 'N' \ - } - -/** run type data block - * string with run type as payload - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTRunTypeDataTypeID \ - { \ - 'R', 'U', 'N', 'T', 'Y', 'P', 'E', ' ' \ - } - -/** DDL list event - * @ref AliHLTEventDDL - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDDLDataTypeID \ - { \ - 'D', 'D', 'L', 'L', 'I', 'S', 'T', ' ' \ - } - -/** DAQ readout list - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDAQRDOUTDataTypeID "DAQRDOUT" - -/** HLT readout list. - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTReadoutListDataTypeID \ - { \ - 'H', 'L', 'T', 'R', 'D', 'L', 'S', 'T' \ - } - -/** EventType event - * - empty payload, specification gives eventType - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTEventDataTypeID \ - { \ - 'E', 'V', 'E', 'N', 'T', 'T', 'Y', 'P' \ - } - -/** ECS parameter event - * - sent during the SOR event by the framework - * - contains the full ECS parameter string - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTECSParamDataTypeID \ - { \ - 'E', 'C', 'S', 'P', 'A', 'R', 'A', 'M' \ - } - -/** ComponentConfiguration event - * - payload contains the CDB path as string - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTComConfDataTypeID \ - { \ - 'C', 'O', 'M', '_', 'C', 'O', 'N', 'F' \ - } - -/** DCS value update event - * - payload contains string of relevant detectors - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTUpdtDCSDataTypeID \ - { \ - 'U', 'P', 'D', 'T', '_', 'D', 'C', 'S' \ - } - -/** MC data block - * an AliMCEvent object of varying origin - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTMCObjectDataTypeID \ - { \ - 'A', 'L', 'I', 'M', 'C', '_', 'V', '0' \ - } - -/** ESDVertex data block - * an AliESDVertex object of varying origin - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTESDVertexDataTypeID \ - { \ - 'E', 'S', 'D', 'V', 'T', 'X', 'V', '0' \ - } - -/** KFVertex data block - * an AliKFVertex object of varying origin - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTKFVertexDataTypeID \ - { \ - 'A', 'L', 'I', 'K', 'F', 'V', 'V', '0' \ - } - -/** output of the GlobalVertexer data block - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDataTypeGlobalVertexerID \ - { \ - 'G', 'L', 'B', 'V', 'T', 'X', 'V', '0' \ - } - -/** output of the PrimaryFinder data block - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDataTypePrimaryFinderID \ - { \ - 'P', 'R', 'I', 'V', 'T', 'X', 'V', '0' \ - } - -/** output of the V0Finder data block - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTDataTypeV0FinderID \ - { \ - 'V', '0', 'S', 'V', 'T', 'X', 'V', '0' \ - } - -/** ESD data block - * an AliESD object of varying origin - * The 'V0' at the end allows a versioning - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTESDObjectDataTypeID \ - { \ - 'A', 'L', 'I', 'E', 'S', 'D', 'V', '0' \ - } - -/** ESD - * data blocks designated for the ESD - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTESDContentDataTypeID \ - { \ - 'E', 'S', 'D', '_', 'C', 'O', 'N', 'T' \ - } - -/** ESD tree data block - * TTree with an AliESD object of varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTESDTreeDataTypeID \ - { \ - 'E', 'S', 'D', '_', 'T', 'R', 'E', 'E' \ - } - -/** AliRoot TreeD - * - the digits tree of an AliRoot module - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTreeDDataTypeID \ - { \ - 'A', 'L', 'I', 'T', 'R', 'E', 'E', 'D' \ - } - -/** AliRoot TreeR - * - the rec points tree of an AliRoot module - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTreeRDataTypeID \ - { \ - 'A', 'L', 'I', 'T', 'R', 'E', 'E', 'R' \ - } - -/** HW Address selection data block - * - a selection list for 16 bit HW addresses - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTHwAddr16DataTypeID \ - { \ - 'H', 'W', 'A', 'D', 'D', 'R', '1', '6' \ - } - -/** Event Statistics - * - event statistics for given detectors - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTEventStatisticsDataTypeID \ - { \ - 'E', 'V', '_', 'S', 'T', 'A', 'T', 'I' \ - } - -/** Event Summary - * - event summary - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTEventSummaryDataTypeID \ - { \ - 'E', 'V', '_', 'S', 'U', 'M', 'M', 'A' \ - } - -/** Run Statistics - * - run statistics for given detectors - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTRunStatisticsDataTypeID \ - { \ - 'R', 'U', 'N', 'S', 'T', 'A', 'T', 'I' \ - } - -/** Run Summary - * - run summary - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTRunSummaryDataTypeID \ - { \ - 'R', 'U', 'N', 'S', 'U', 'M', 'M', 'A' \ - } - -/** Trigger decision - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTriggerDecisionDataTypeID \ - { \ - 'T', 'R', 'I', 'G', '_', 'D', 'E', 'C' \ - } - -/** Global trigger decision - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTGlobalTriggerDataTypeID \ - { \ - 'G', 'L', 'O', 'B', 'T', 'R', 'I', 'G' \ - } - -/** Block Statistics - * - small block statistics info added to the data stream by - * the component base class - * - origin kAliHLTDataOriginPrivate - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTComponentStatisticsDataTypeID \ - { \ - 'C', 'O', 'M', 'P', 'S', 'T', 'A', 'T' \ - } - -/** Component table - * - list of components in the chain to be percolated through the chain - * - each component adds it's chain id string and a generated 32bit id - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTComponentTableDataTypeID \ - { \ - 'C', 'O', 'M', 'P', 'T', 'A', 'B', 'L' \ - } - -/** Forwarded component table - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTComponentFwdTableDataTypeID \ - { \ - 'C', 'O', 'M', 'P', 'T', 'A', 'B', 'F' \ - } - -/** general ROOT TObject - * - a general TObject exported from the HLT analysis - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTObjectDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'T', 'O', 'B', 'J' \ - } - -/** ROOT streamer info - * - used for the transmission of streamer info for objects in the HLTOUT - * - origin kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTStreamerInfoDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'S', 'T', 'R', 'I' \ - } - -/** ROOT TObjArray - * - a TObjArray exported from the HLT analysis - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTObjArrayDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'O', 'B', 'A', 'R' \ - } - -/** ROOT TTree - * - a TTree object exported from the HLT analysis - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTTreeDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'T', 'R', 'E', 'E' \ - } - -/** ROOT histogram - * - a histogram object exported from the HLT analysis - * - class derives from TH1 (directly or indirectly) and inherits all common functionality - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTHistogramDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'H', 'I', 'S', 'T' \ - } - -/** ROOT TNtuple - * - a TNtupl object exported from the HLT analysis - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTNtupleDataTypeID \ - { \ - 'R', 'O', 'O', 'T', 'T', 'U', 'P', 'L' \ - } - -/** HLT Track - * - Struct for Tracks based on AliExternalTrackParam - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTrackDataTypeID \ - { \ - 'H', 'L', 'T', 'T', 'R', 'A', 'C', 'K' \ - } - -/** Track Monte Carlo information - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTTrackMCDataTypeID \ - { \ - 'T', 'R', 'A', 'C', 'K', '_', 'M', 'C' \ - } - -/** TClonesArray of AliExternalTrackParam - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTExternalTrackParamDataTypeID \ - { \ - 'T', 'C', 'A', 'E', 'X', 'T', 'T', 'R' \ - } - -/** HLT Jet - * - Struct for jets based on AliHLTJETJets - * - varying origin - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTJetDataTypeID \ - { \ - 'H', 'L', 'T', 'J', 'E', 'T', 'V', '0' \ - } - -/** dEdx data - * Common data type for the dEdx - * format depends on the origin (detector) - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTdEdxDataTypeID \ - { \ - 'D', 'E', 'D', 'X', ' ', ' ', ' ', ' ' \ - } - -/** dNdPt data - * Common data type for the dNdPt output object - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTdNdPtDataTypeID \ - { \ - 'D', 'N', 'D', 'P', 'T', ' ', ' ', ' ' \ - } - -/** Global input trigger counters data block type. - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTInputTriggerCountersDataTypeID \ - { \ - 'I', 'N', 'T', 'R', 'G', 'C', 'N', 'T' \ - } - -/** Global output trigger counters data block type. - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTOutputTriggerCountersDataTypeID \ - { \ - 'O', 'T', 'T', 'R', 'G', 'C', 'N', 'T' \ - } - -/** Generic meta data block type ID. - * @ingroup alihlt_component_datatypes - */ -#define kAliHLTMetaDataTypeID \ - { \ - 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A' \ - } - -extern "C" { -////////////////////////////////////////////////////////////////////////// -// -// Basic HLT data types -// -////////////////////////////////////////////////////////////////////////// - -typedef unsigned char AliHLTUInt8_t; - -typedef signed char AliHLTInt8_t; - -typedef unsigned short AliHLTUInt16_t; - -typedef signed short AliHLTInt16_t; - -typedef unsigned int AliHLTUInt32_t; - -typedef signed int AliHLTInt32_t; - -typedef unsigned long long AliHLTUInt64_t; - -typedef signed long long AliHLTInt64_t; - -typedef float AliHLTFloat32_t; - -typedef double AliHLTFloat64_t; - -typedef AliHLTUInt64_t AliHLTEventID_t; - -////////////////////////////////////////////////////////////////////////// -// -// HLT logging levels -// -////////////////////////////////////////////////////////////////////////// - -/** - * Logging severities of the HLT - */ -enum AliHLTComponentLogSeverity { - /** no logging */ - kHLTLogNone = 0, - /** benchmark messages */ - kHLTLogBenchmark = 0x1, - /** debug messages */ - kHLTLogDebug = 0x2, - /** info messages */ - kHLTLogInfo = 0x4, - /** warning messages */ - kHLTLogWarning = 0x8, - /** error messages */ - kHLTLogError = 0x10, - /** fatal error messages */ - kHLTLogFatal = 0x20, - /** few important messages not to be filtered out. - * redirected to kHLTLogInfo in AliRoot - */ - kHLTLogImportant = 0x40, - /** special value to enable all messages */ - kHLTLogAll = 0x7f, - /** the default logging filter */ - kHLTLogDefault = 0x79 -}; - -////////////////////////////////////////////////////////////////////////// -// -// HLT data structures for data exchange and external interface -// -////////////////////////////////////////////////////////////////////////// - -/** - * @struct AliHLTComponentEventData - * Event descriptor - */ -struct AliHLTComponentEventData { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTEventID_t fEventID; /// 64 bit event ID number. - AliHLTUInt32_t fEventCreation_s; /// Event creation time in seconds (Should be added to fEventCreation_us*1e6). - AliHLTUInt32_t fEventCreation_us; /// Fractional event creation time in micro seconds. - AliHLTUInt32_t fBlockCnt; /// The number of raw data blocks received by the component. -}; - -/** - * @struct AliHLTComponentShmData - * Shared memory descriptor. - * Irrelevant for analysis components. - */ -struct AliHLTComponentShmData { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fShmType; /// The type code of the shared memory. - AliHLTUInt64_t fShmID; /// The shared memory identifier. -}; - -/** - * @defgroup alihlt_component_datatypes Common Component Data Types - * The analysis framework defines a number of common data types for - * usage in the detector modules, like e.g. ::kAliHLTAnyDataType - * and ::kAliHLTDataTypeDDLRaw. Those data types always have - * origin ::kAliHLTDataOriginAny. The correct detector origin can be - * set by using operator '|' - * <pre> - * AliHLTComponentDataType dt=kAliHLTDDLRawDataTypeID|kAliHLTDataOriginTPC - * </pre> - * @ingroup alihlt_component - */ - -/** - * @struct AliHLTComponentDataType - * Data type descriptor for data blocks transferred through the processing - * chain. - * @ingroup alihlt_component_datatypes - */ -struct AliHLTComponentDataType { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - char fID[kAliHLTComponentDataTypefIDsize]; /// Data type identifier. - char fOrigin[kAliHLTComponentDataTypefOriginSize]; /// Subsystem or detector origin of the data. -}; - -/** - * @struct AliHLTComponentBlockData - * This is the decription of data blocks exchanged between components. - * \b IMPORTANT: The validity of fPtr and fOffset is different for input and - * output blocks: - * - input blocks: The \em fPtr member always points to the beginning of the data - * of size \em fSize. fOffset is ignored and should be in most - * case 0. - * - output blocks: The \em fPtr member is ignored by the framework. \em fOffset - * must specify the start of the data relative to the output - * buffer. The data block has size \em fSize. - */ -struct AliHLTComponentBlockData { - /** size and version of the struct */ - AliHLTUInt32_t fStructSize; - /** shared memory key, ignored by processing components */ - AliHLTComponentShmData fShmKey; - /** offset of output data relative to the output buffer */ - AliHLTUInt32_t fOffset; - /** start of the data for input data blocks, fOffset to be ignored*/ - void* fPtr; - /** size of the data block */ - AliHLTUInt32_t fSize; - /** data type of the data block */ - AliHLTComponentDataType fDataType; - /** data specification of the data block */ - AliHLTUInt32_t fSpecification; - - AliHLTComponentDataType GetDataType() const { return fDataType; } - AliHLTUInt32_t GetSpecification() const { return fSpecification; } -}; - -/** - * @struct AliHLTComponentEventDoneData - * - */ -struct AliHLTComponentEventDoneData { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fDataSize; /// Size of the data section (following this data member) in bytes. - void* fData; /// Start of the data section. -}; - -/** - * @struct AliHLTRunDesc - * Event descriptor. - * The struct is sent with the SOR and EOR events. - * - * @note - * The name of the member fRunType is a bit misleading. This is not - * the ALICE Run Type given by the ECS to the sub-system. The member - * is an internal HLT run type and a combination of the HLT running - * mode and the beam type. - * <pre> - * Bit 0-2: beam type identifier - * Bit 3-31: HLT mode - * </pre> - */ -struct AliHLTRunDesc { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fRunNo; /// The run number for the current active run. - AliHLTUInt32_t fRunType; /// The HLT run type. -}; - -/** - * @struct AliHLTComponentStatistics - * Small block size summary added by the AliHLTComponent base class - * if component statistics are enabled (--enable-compstat). - * - * fLevel is retrieved from incoming block statistics and incremented. - * Incoming block statistics are appended to the newly added one if - * --enable-compstat=full has been chosen. - * - * ChangeLog: - * 2009-01-14 fComponentCycleTime added - */ -struct AliHLTComponentStatistics { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fLevel; /// Indicates from which processing stage this information is from. - AliHLTUInt32_t fId; /// Unique identifier for the chain based on CRC code. - AliHLTUInt32_t fTime; /// Real wall time used to process the data (micro seconds). - AliHLTUInt32_t fCTime; /// CPU time used to process the data (micro seconds). - AliHLTUInt32_t fInputBlockCount; /// Number of input data blocks. - AliHLTUInt32_t fTotalInputSize; /// Total size in bytes of input data. - AliHLTUInt32_t fOutputBlockCount; /// Number of output data blocks. - AliHLTUInt32_t fTotalOutputSize; /// Total size in bytes of output data. - AliHLTUInt32_t fComponentCycleTime; /// Real wall time indicating the start of the data processing (micro seconds). -}; - -/** - * @struct AliHLTComponentTableEntry - * Structure to be send on SOR event through the chain. - * The 'length' of the structure is variable and depends on the length - * of the buffer at the end. - * - * ComponentTableEntries are sent with data type @ref kAliHLTDataTypeComponentTable - * and are identified by a 32bit Id specification generated by a CRC - * algorithm from the chain Id of the component. This is not a 100% unique - * id but with a high probability. This approach accounts for the fact - * that all components are separated processes. - * - * The buffer consists of an array of 32bit Ids containing the Ids of - * all direct parents taken from the specification of the data blocks. - * The number of parents is stored in fNofParents. Each component forwards the - * incoming component table entries with data type @ref kAliHLTDataTypeComponentFwdTable - * by that the direct parents can be identified. - * - * Following this array a description string contains the chain id, component args, and - * maybe more properties in the future. The current format is - * 'chain_id{component_id:component args}' e.g. TPC-CF_00_0{TPCClusterFinder32Bit:-deconvolute-time} - */ -struct AliHLTComponentTableEntry { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fLevel; /// Indicates from which processing stage this information is from. - AliHLTUInt16_t fNofParents; /// size of the array of parent ids - AliHLTUInt8_t fSizeDescription; /// size of the description string in the appended buffer - AliHLTUInt8_t fBuffer[1]; /// the strings: chain id, component args, reserved -}; - -////////////////////////////////////////////////////////////////////////// -// -// Trigger meta information -// -////////////////////////////////////////////////////////////////////////// - -/** field size of fAttribute */ -const int gkAliHLTBlockDAttributeCount = 8; - -/** field size of fCommonHeader */ -const int gkAliHLTCommonHeaderCount = 8; - -/** size of the DDL list first version */ -const int gkAliHLTDDLListSizeV0 = 30; - -/** size of the DDL list after DCAL added to EMCAL */ -const int gkAliHLTDDLListSizeV1 = 31; - -/** size of the DDL list */ -const int gkAliHLTDDLListSize = gkAliHLTDDLListSizeV1; - -/** Number of Trigger Classes of CTP in CDH */ -const int gkNCTPTriggerClasses = 50; - -/** - * @struct AliHLTEventDDLV0 - * First version of the DDL list event. - * The struct is send with the DDLLIST event. - * Used in the trigger structure for internal apperance of - * the DLLs as well as for the HLT readout list send to DAQ - * ( as DataType : kAliHLTDataTypeDDL ) - */ -struct AliHLTEventDDLV0 { - AliHLTUInt32_t fCount; /// Indicates the number of words in fList. - AliHLTUInt32_t fList[gkAliHLTDDLListSizeV0]; /// The list of DDL enable/disable bits. -}; - -/** - * @struct AliHLTEventDDLV1 - * DDL list event structure with extra word for DCAL bits. - */ -struct AliHLTEventDDLV1 { - AliHLTUInt32_t fCount; /// Indicates the number of words in fList. - AliHLTUInt32_t fList[gkAliHLTDDLListSizeV1]; /// The list of DDL enable/disable bits. -}; - -/** - * @typedef AliHLTEventDDL - * Current used default version of the AliHLTEventDDL structure. - */ -typedef AliHLTEventDDLV1 AliHLTEventDDL; - -/** - * @struct AliHLTEventTriggerData - */ -struct AliHLTEventTriggerData { - AliHLTUInt8_t fAttributes[gkAliHLTBlockDAttributeCount]; /// List of data block attibutes. - AliHLTUInt64_t fHLTStatus; /// Bit field - AliHLTUInt32_t fCommonHeaderWordCnt; /// Number of words in fCommonHeader. - AliHLTUInt32_t fCommonHeader[gkAliHLTCommonHeaderCount]; /// The common header words. - union { - AliHLTEventDDL fReadoutList; /// The default readout list structure. - AliHLTEventDDLV0 fReadoutListV0; /// Access to the old version of the readout list structure. - AliHLTEventDDLV1 fReadoutListV1; /// Access to the readout list structure with DCAL included. - }; -}; - -/** - * @struct AliHLTComponentTriggerData - * Trigger data - */ -struct AliHLTComponentTriggerData { - AliHLTUInt32_t fStructSize; /// Size of this structure in bytes. - AliHLTUInt32_t fDataSize; /// Size of the data section (following this data member) in bytes. - void* fData; /// Start of the data section. -}; - -////////////////////////////////////////////////////////////////////////// -// -// HLT Event Type Specification -// -////////////////////////////////////////////////////////////////////////// - -/** Unknown eventType specification */ -const AliHLTUInt32_t gkAliEventTypeUnknown = ~(AliHLTUInt32_t)0; -/** SOR eventType specification */ -const AliHLTUInt32_t gkAliEventTypeStartOfRun = 1; -/** Data eventType specification */ -const AliHLTUInt32_t gkAliEventTypeData = 2; -/** EOR eventType specification */ -const AliHLTUInt32_t gkAliEventTypeEndOfRun = 4; -/** Corrupt eventType specification */ -const AliHLTUInt32_t gkAliEventTypeCorruptID = 8; -/** Calibration eventType specification */ -const AliHLTUInt32_t gkAliEventTypeCalibration = 16; -/** Software eventType specification */ -const AliHLTUInt32_t gkAliEventTypeSoftware = 24; -/** DataReplay eventType specification */ -const AliHLTUInt32_t gkAliEventTypeDataReplay = 32; -/** Configuration eventType specification */ -const AliHLTUInt32_t gkAliEventTypeConfiguration = 34; -/** Update DCS eventType specification */ -const AliHLTUInt32_t gkAliEventTypeReadPreprocessor = 35; -/** Tick eventType specification */ -const AliHLTUInt32_t gkAliEventTypeTick = 64; -/** Max eventType specification */ -const AliHLTUInt32_t gkAliEventTypeMax = 64; - -////////////////////////////////////////////////////////////////////////// -// -// HLT defines and defaults -// -////////////////////////////////////////////////////////////////////////// - -/** invalid event id - * @ingroup alihlt_component_datatypes - */ -const AliHLTEventID_t kAliHLTVoidEventID = ~(AliHLTEventID_t)0; - -/** invalid data specification - * @ingroup alihlt_component_datatypes - */ -const AliHLTUInt32_t kAliHLTVoidDataSpec = ~(AliHLTUInt32_t)0; - -/** invalid run no - * @ingroup alihlt_component_datatypes - */ -const AliHLTUInt32_t kAliHLTVoidRunNo = ~(AliHLTUInt32_t)0; - -/** invalid run type - * @ingroup alihlt_component_datatypes - */ -const AliHLTUInt32_t kAliHLTVoidRunType = ~(AliHLTUInt32_t)0; - -/** invalid run descriptor - * @ingroup alihlt_component_datatypes - */ -const AliHLTRunDesc kAliHLTVoidRunDesc = {sizeof(AliHLTRunDesc), kAliHLTVoidRunNo, kAliHLTVoidRunType}; - -/** invalid shared memory type */ -const AliHLTUInt32_t gkAliHLTComponentInvalidShmType = 0; - -/** invalid shared memory id */ -const AliHLTUInt64_t gkAliHLTComponentInvalidShmID = ~(AliHLTUInt64_t)0; - -/** invalid data type - * @ingroup alihlt_component_datatypes - */ -const AliHLTComponentDataType kAliHLTVoidDataType = { - sizeof(AliHLTComponentDataType), - kAliHLTVoidDataTypeID, - kAliHLTDataOriginVoid}; - -/** all data types, means any + void data type - * @ingroup alihlt_component_datatypes - */ -const AliHLTComponentDataType kAliHLTAllDataTypes = { - sizeof(AliHLTComponentDataType), - kAliHLTAllDataTypesID, - kAliHLTDataOriginAny}; - -// there is currently a problem with rootcint if the predefined ids -// (commented below) are used. rootcint does not find the id if they -// are char arrays defined with {} and individual chars. If strings -// are used it works fine -/** any data type - * @ingroup alihlt_component_datatypes - */ -const AliHLTComponentDataType kAliHLTAnyDataType = { - sizeof(AliHLTComponentDataType), - kAliHLTAnyDataTypeID, - kAliHLTDataOriginAny}; - -/** multiple output data types - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTMultipleDataType; - -/** data to file exchange subscriber - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeFXSCalib; - -/** DDL list data type - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeDDL; - -/** DAQ readout list - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeDAQRDOUT; - -/** CLUSTERS data - * Common data type for the output of cluster finders, the exact - * format depends on the origin (detector) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeClusters; - -/** SOR data type - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeSOR; - -/** EOR data type - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeEOR; - -/** Run type data block - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeRunType; - -/** Event type specification - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeEvent; - -/** ECS parameter event - * - sent during the SOR event by the framework - * - contains the full ECS parameter string - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeECSParam; // {ECSPARAM:PRIV} - -/** Configuration event data type - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeComConf; - -/** DCS value update event - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeUpdtDCS; - -/** RAW DDL data specification, origin is 'any', data publisher origin correctly - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeDDLRaw; - -/** AliMCEvent object data specification, origin is 'OFFL' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeMCObject; - -/** ESD vertex object data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeESDVertex; - -/** KF vertex object data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeKFVertex; - -/** global vertexer data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeGlobalVertexer; - -/** primary finder data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypePrimaryFinder; - -/** primary finder data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeV0Finder; - -/** ESD object data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeESDObject; - -/** ESD content data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeESDContent; - -/** ESD Tree data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeESDTree; - -/** AliRoot TreeD data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeAliTreeD; - -/** AliRoot TreeR data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeAliTreeR; - -/** 16 bit Hardware address selection data specification, origin is 'any' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeHwAddr16; - -/** Event statistics - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeEventStatistics; - -/** Event summary - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeEventSummary; - -/** Event statistics - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeRunStatistics; - -/** Run summary - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeRunSummary; - -/** Trigger decision - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTriggerDecision; // {TRIG_DEC:HLT } - -/** Trigger decision - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeReadoutList; // {HLTRDLST:HLT } - -/** Global trigger decision - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeGlobalTrigger; // {GLOBTRIG:HLT } - -/** Component block statistics - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeComponentStatistics; - -/** Component table - * To be sent on SOR event, each component adds it's chain id string - * and a generated 32bit identifier to the table - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeComponentTable; - -/** Forwarded component table - * To be sent on SOR event, each component forwards blocks of type - * @ref kAliHLTDataTypeComponentTable was kAliHLTDataTypeComponentFwdTable - * after adding the parent ids to its own table struct. - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeComponentFwdTable; - -/** - * Data type for the Common Data Header and readout list information sent by TCPDumpSubscriber. - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTriggerMetaBlock; // {METADATA:PRIV} - -////////////////////////////////////////////////////////////////////////// -// -// Data Types for Monitoring objects -// -////////////////////////////////////////////////////////////////////////// - -/** general ROOT TObject - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTObject; // {ROOTTOBJ,"***"} - -/** ROOT streamer info - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeStreamerInfo; // {ROOTSTRI,HLT } - -/** ROOT TObjArray - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTObjArray; // {ROOTOBAR,"***"} - -/** ROOT TTree - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTTree; // {ROOTTREE,"***"} - -/** ROOT TH1 (can be used for all histograms, they derive from TH1) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeHistogram; // {ROOTHIST,"***"} - -/** ROOT TNtuple - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTNtuple; // {ROOTTUPL,"***"} - -/** Global input trigger counters. - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeInputTriggerCounters; // {INTRGCNT:HLT } - -/** Global output trigger counters. - * - origin : kAliHLTDataOriginOut ( HLT ) - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeOutputTriggerCounters; // {OTTRGCNT:HLT } - -/** General track array for the barrel tracks based on AliExternalTrackParam - * Data format defined by AliHLTTracksData - * - * We follow the naming scheme of AliESDEvent where 'Tracks' denote the - * barrel tracks and detector tracks get names 'DETTracks' - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTrack; // {HLTTRACK,"***"} - -/** Track Monte Carlo information - */ -extern const AliHLTComponentDataType kAliHLTDataTypeTrackMC; // {TRACK_MC,"***"} - -/** TClonesArray of AliExternalTrackParam - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeExternalTrackParam; // {TCAEXTTR,"***"} - -/** Container containing jets (AliHLTJETJets) - * Containing TClonesArray of AliAODJets - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeJet; // {HLTJETV0,"***"} - -/** Container of ITS tracks - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType fgkITSTracksDataType; - -/** Container of calorimeter clusters - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypeCaloCluster; - -/** Container of dEdx - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypedEdx; - -/** Container of dNdPt - * @ingroup alihlt_component_datatypes - */ -extern const AliHLTComponentDataType kAliHLTDataTypedNdPt; - -////////////////////////////////////////////////////////////////////////// -// -// FXS subscriber meta information -// -////////////////////////////////////////////////////////////////////////// - -const int gkAliHLTFXSHeaderfOriginSize = 4; -const int gkAliHLTFXSHeaderfFileIDSize = 128; -const int gkAliHLTFXSHeaderfDDLNumberSize = 64; - -/** Header in front of the data payload, in order to sent data to the FXS. */ -struct AliHLTFXSHeader { - AliHLTUInt32_t fHeaderVersion; /// HLT software version number. - AliHLTUInt32_t fRunNumber; /// The current run number. - char fOrigin[gkAliHLTFXSHeaderfOriginSize]; /// The detector from which the FXS data is received. - char fFileID[gkAliHLTFXSHeaderfFileIDSize]; /// File identifier for the stored data. - char fDDLNumber[gkAliHLTFXSHeaderfDDLNumberSize]; /// The DDL bits. -}; - -////////////////////////////////////////////////////////////////////////// -// -// Component running environment -// -////////////////////////////////////////////////////////////////////////// - -/** definition of a void fct pointer */ -typedef void (*AliHLTfctVoid)(); - -/** logging function */ -typedef int (*AliHLTfctLogging)(void* param, - AliHLTComponentLogSeverity severity, - const char* origin, - const char* keyword, - const char* message); - -/** - * @struct AliHLTAnalysisEnvironment - * Running environment for analysis components. - * The struct describes function callbacks for actions to be - * carried out by the calling framework, like memory allocation, - * property callbecks, logging, etc. - * - * @ingroup alihlt_wrapper_interface - */ -struct AliHLTAnalysisEnvironment { - /** size of the structure */ - AliHLTUInt32_t fStructSize; - - /** the component parameter given by the framework on creation */ - void* fParam; - - /** allocated memory */ - void* (*fAllocMemoryFunc)(void* param, unsigned long size); - - /** allocate an EventDoneData structure. */ - int (*fGetEventDoneDataFunc)(void* param, AliHLTEventID_t eventID, unsigned long size, AliHLTComponentEventDoneData** edd); - - /** logging callback */ - AliHLTfctLogging fLoggingFunc; -}; -#if 0 - // I just keep this as a note pad. Has to be added to the end of the structure - // future addition already foreseen/envisioned - // IMPORTANT: don not just remove the defines as this breaks the binary - // compatibility - int (*fAllocShmMemoryFunc)( void* param, unsigned long size, AliHLTComponentBlockData* blockLocation ); -#endif - -/** - * @struct AliHLTComponentEnvironment - * This was the original definition of the running environment. - * Due to a bug in the AliRootWrapperSubscriber/SimpleComponentWrapper, - * this structure can not be used any longer but is kept for backward - * compatibility. - * @note The external interface provided by the libHLTbase is now kept - * frozen but should not be used any more. Use the interface provided - * by the libHLTinterface library. - * - * @ingroup alihlt_wrapper_interface_deprecated - */ -struct AliHLTComponentEnvironment { - AliHLTUInt32_t fStructSize; - void* fParam; - void* (*fAllocMemoryFunc)(void* param, unsigned long size); - int (*fGetEventDoneDataFunc)(void* param, AliHLTEventID_t eventID, unsigned long size, AliHLTComponentEventDoneData** edd); - AliHLTfctLogging fLoggingFunc; -}; - -////////////////////////////////////////////////////////////////////////// -// -// The external interface definition -// -////////////////////////////////////////////////////////////////////////// - -/** - * The component handle. - * Used as indification in the outside world. - * @ingroup alihlt_wrapper_interface - */ -typedef void* AliHLTComponentHandle; - -/** @ingroup alihlt_wrapper_interface */ -const AliHLTComponentHandle kEmptyHLTComponentHandle = nullptr; - -/** - * Get a system call of the interface. - * @param function signature - * @return pointer to system call - * @ingroup alihlt_wrapper_interface - */ -typedef void* (*AliHLTAnalysisFctGetInterfaceCall)(const char*); - -#define ALIHLTANALYSIS_INTERFACE_LIBRARY "libHLTinterface.so" -#define ALIHLTANALYSIS_FCT_GETINTERFACECALL "AliHLTAnalysisGetInterfaceCall" - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctInitSystem)(unsigned long version, AliHLTAnalysisEnvironment* externalEnv, unsigned long runNo, const char* runType); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctDeinitSystem)(); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctLoadLibrary)(const char*); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctUnloadLibrary)(const char*); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctCreateComponent)(const char*, void*, int, const char**, AliHLTComponentHandle*, const char* description); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctDestroyComponent)(AliHLTComponentHandle); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctProcessEvent)(AliHLTComponentHandle, const AliHLTComponentEventData*, const AliHLTComponentBlockData*, - AliHLTComponentTriggerData*, AliHLTUInt8_t*, - AliHLTUInt32_t*, AliHLTUInt32_t*, - AliHLTComponentBlockData**, - AliHLTComponentEventDoneData**); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctGetOutputDataType)(AliHLTComponentHandle, AliHLTComponentDataType*); - -/** @ingroup alihlt_wrapper_interface */ -typedef int (*AliHLTExtFctGetOutputSize)(AliHLTComponentHandle, unsigned long*, unsigned long*, double*); -} - -namespace std -{ -} - -////////////////////////////////////////////////////////////////////////// -// -// Data type helper functions -// -////////////////////////////////////////////////////////////////////////// - -/** exact comparison of HLT component data types - * @ingroup alihlt_component_datatypes - */ -inline bool MatchExactly(const AliHLTComponentDataType& dt1, const AliHLTComponentDataType& dt2) -{ - for (int i = 0; i < kAliHLTComponentDataTypefIDsize; i++) { - if (dt1.fID[i] != dt2.fID[i]) { - return false; - } - } - for (int i = 0; i < kAliHLTComponentDataTypefOriginSize; i++) { - if (dt1.fOrigin[i] != dt2.fOrigin[i]) { - return false; - } - } - return true; -} - -/** Comparison operator for HLT component data types. - * The operator takes wildcards into account, i.e. the ::kAliHLTAnyDataType, - * ::kAliHLTAnyDataTypeID and ::kAliHLTDataOriginAny definitions. - * @ingroup alihlt_component_datatypes - */ -inline bool operator==(const AliHLTComponentDataType& dt1, const AliHLTComponentDataType& dt2) -{ - if (MatchExactly(dt1, kAliHLTAllDataTypes)) { - return true; - } - if (MatchExactly(dt2, kAliHLTAllDataTypes)) { - return true; - } - - bool any1 = true, any2 = true, void1 = true, void2 = true, match = true; - for (int i = 0; i < kAliHLTComponentDataTypefOriginSize; i++) { - any1 &= (dt1.fOrigin[i] == kAliHLTDataOriginAny[i]); - any2 &= (dt2.fOrigin[i] == kAliHLTDataOriginAny[i]); - void1 &= (dt1.fOrigin[i] == kAliHLTDataOriginVoid[i]); - void2 &= (dt2.fOrigin[i] == kAliHLTDataOriginVoid[i]); - match &= dt1.fOrigin[i] == dt2.fOrigin[i]; - if (!(match || (any2 && !void1) || (any1 && !void2))) { - return false; - } - } - - any1 = true, any2 = true, match = true; - for (int i = 0; i < kAliHLTComponentDataTypefIDsize; i++) { - any1 &= (dt1.fID[i] == kAliHLTAnyDataTypeID[i]); - any2 &= (dt2.fID[i] == kAliHLTAnyDataTypeID[i]); - void1 &= (dt1.fID[i] == kAliHLTVoidDataTypeID[i]); - void2 &= (dt2.fID[i] == kAliHLTVoidDataTypeID[i]); - match &= dt1.fID[i] == dt2.fID[i]; - if (!(match || (any2 && !void1) || (any1 && !void2))) { - return false; - } - } - return true; -} - -/** Comparison operator for HLT component data types - * Invers of operator== - * @ingroup alihlt_component_datatypes - */ -inline bool operator!=(const AliHLTComponentDataType& dt1, const AliHLTComponentDataType& dt2) -{ - return !(dt1 == dt2); -} - -/** merge operator for HLT component data types and origins - * @ingroup alihlt_component_datatypes - */ -inline AliHLTComponentDataType operator|(const AliHLTComponentDataType srcdt, const char origin[kAliHLTComponentDataTypefOriginSize]) -{ - AliHLTComponentDataType dt = srcdt; - for (int i = 0; i < kAliHLTComponentDataTypefOriginSize; i++) { - dt.fOrigin[i] = origin[i]; - } - return dt; -} - -/** - * Helper function to initialize a data type from an id char array and origin string. - * @return data type structure initialized with the specified id and origin - * @ingroup alihlt_component_datatypes - */ -inline AliHLTComponentDataType AliHLTComponentDataTypeInitializer(const char id[kAliHLTComponentDataTypefIDsize], const char* origin) -{ - AliHLTComponentDataType dt = kAliHLTVoidDataType; - int i = 0; - for (i = 0; i < kAliHLTComponentDataTypefIDsize && id[i] != 0; i++) { - dt.fID[i] = id[i]; - } - for (i = 0; i < kAliHLTComponentDataTypefOriginSize && origin[i] != 0; i++) { - dt.fOrigin[i] = origin[i]; - } - return dt; -} - -/** - * Helper function to initialize a data type from a default data type and - * an origin string. Basically it merges the specified origin into the data - * type. - * @return data type structure initialized with the id from specified data type - * and origin - * @ingroup alihlt_component_datatypes - */ -inline AliHLTComponentDataType AliHLTComponentDataTypeInitializer(const AliHLTComponentDataType src, const char* origin) -{ - return AliHLTComponentDataTypeInitializer(src.fID, origin); -} - -#endif diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERData.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERData.h deleted file mode 100644 index 59c0ab41f93e3..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERData.h +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// XEMacs -*-C++-*- -#ifndef ALIHLTHOMERDATA_H -#define ALIHLTHOMERDATA_H - -// @file AliHLTHOMERData.h -// @author Matthias Richter -// @since 2014-05-07 -// @brief Original AliHLTHOMERData.h of AliRoot included for HOMER -// support in the ALFA project - -//************************************************************************ -//* -//* -//* This file is property of and copyright by the Technical Computer -//* Science Group, Kirchhoff Institute for Physics, Ruprecht-Karls- -//* University, Heidelberg, Germany, 2001 -//* This file has been written by Timm Morten Steinbeck, -//* timm@kip.uni-heidelberg.de -//* -//* -//* See the file license.txt for details regarding usage, modification, -//* distribution and warranty. -//* Important: This file is provided without any warranty, including -//* fitness for any particular purpose. -//* -//* -//* Newer versions of this file's package will be made available from -//* http://web.kip.uni-heidelberg.de/Hardwinf/L3/ -//* or the corresponding page of the Heidelberg Alice Level 3 group. -//* -//************************************************************************/ - -/* -*************************************************************************** -** -** $Author$ - Initial Version by Timm Morten Steinbeck -** -** $Id$ -** -*************************************************************************** -*/ - -#ifdef USE_ROOT -#include "Rtypes.h" -#endif -#include <climits> - -// Determine the sizes of the different integer type -// homer_uint32, homer_uint64 -#if !defined(USE_ROOT) -// First homer_uint32 -#if USHRT_MAX == 4294967295 -typedef unsigned short homer_uint32; -#else // USHRT_MAX==4294967295 - -#if UINT_MAX == 4294967295 -typedef unsigned int homer_uint32; -#else // UINT_MAX==4294967295 - -#if ULONG_MAX == 4294967295l -typedef unsigned long homer_uint32; -#else // ULONG_MAX==4294967295l - -#error Could not typedef homer_uint32 - -#endif // ULONG_MAX==4294967295l - -#endif // UINT_MAX==4294967295 - -#endif // USHRT_MAX==4294967295 - -// Then homer_uint16 -#if USHRT_MAX == 65535 -typedef unsigned short homer_uint16; -#else // USHRT_MAX==65535 - -#if UINT_MAX == 65535 -typedef unsigned int homer_uint16; -#else // UINT_MAX==65535 - -#if ULONG_MAX == 65535 -typedef unsigned long homer_uint16; -#else // ULONG_MAX==65535 - -#error Could not typedef homer_uint16 - -#endif // ULONG_MAX==65535 - -#endif // UINT_MAX==65535 - -#endif // USHRT_MAX==65535 - -// Then homer_uint64 -#if ULONG_MAX == 18446744073709551615UL -typedef unsigned long homer_uint64; -#else // ULONG_MAX==18446744073709551615UL - -#if defined __GNUC__ -typedef unsigned long long homer_uint64; -#else // defined __GNUC__ - -#if defined __SUNPRO_CC -typedef unsigned long long homer_uint64; -#else // defined __SUNPRO_CC - -#error Could not typedef homer_uint64 - -#endif // defined __SUNPRO_CC -#endif // defined __GNUC__ - -#endif // ULONG_MAX==18446744073709551615UL - -typedef unsigned char homer_uint8; - -#else // !USE_ROOT - -typedef UShort_t homer_uint16; -typedef UInt_t homer_uint32; -typedef ULong64_t homer_uint64; -typedef Byte_t homer_uint8; - -#ifdef __CINT__ -typedef int key_t; -#endif - -#endif // USE_ROOT - -//typedef homer_uint64 AliEventID_t; - -#define kAttribute_8b_StartOffset 0 -#define kByteOrderAttribute_8b_Offset kAttribute_8b_StartOffset + 0 -#define kVersionAttribute_8b_Offset kAttribute_8b_StartOffset + 1 -#define kAlignment_8b_StartOffset 24 -#define kUInt64Alignment_8b_Offset kAlignment_8b_StartOffset + 0 -#define kUInt32Alignment_8b_Offset kAlignment_8b_StartOffset + 1 -#define kUInt16Alignment_8b_Offset kAlignment_8b_StartOffset + 2 -#define kUInt8Alignment_8b_Offset kAlignment_8b_StartOffset + 3 -#define kDoubleAlignment_8b_Offset kAlignment_8b_StartOffset + 4 -#define kFloatAlignment_8b_Offset kAlignment_8b_StartOffset + 5 - -#define kID_64b_Offset 1 -#define kLength_64b_Offset 2 -#define kType_64b_Offset 4 -#define kSubType1_64b_Offset 5 -#define kSubType2_64b_Offset 6 -#define kBirth_s_64b_Offset 7 -#define kBirth_us_64b_Offset 8 -#define kProducerNode_64b_Offset 9 -#define kOffset_64b_Offset 10 -#define kSize_64b_Offset 11 -#define kStatusFlags_64b_Offset 12 -#define kEnd_64b_Offset 13 -#define kCount_64b_Words kEnd_64b_Offset - -// Possible values for fAttributes[kByteOrderAttribute] -/* Keep this consistent with BCLNetworkData.hpp kLittleEndian/kBigEndian and AliHLTSubEventDataDescriptor.hpp */ -const homer_uint8 kHOMERUnknownByteOrder = 0; -const homer_uint8 kHOMERLittleEndianByteOrder = 1; -const homer_uint8 kHOMERBigEndianByteOrder = 2; -#ifdef __i386__ -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#else -#ifdef __arm__ -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#else -#ifdef __x86_64__ -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#else -#ifdef __ia64__ -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#else -#if defined(__powerpc__) -const homer_uint8 kHOMERNativeByteOrder = kHOMERBigEndianByteOrder; -#else -#ifdef __CINT__ -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#warning Assuming little endian format for __CINT__ -#else -const homer_uint8 kHOMERNativeByteOrder = kHOMERLittleEndianByteOrder; -#warning Assuming little endian format for unknown architecture -//#error Byte format (little/big endian) currently not defined for platforms other than intel i386 compatible, x86-64 (AMD64) and arm... -#endif -#endif -#endif -#endif -#endif -#endif - -//#define HOMER_BLOCK_DESCRIPTOR_TYPEID (((homer_uint64)'HOBL')<<32 | 'KDES') -#define HOMER_BLOCK_DESCRIPTOR_TYPEID ((((homer_uint64)'H') << 56) | (((homer_uint64)'O') << 48) | (((homer_uint64)'B') << 40) | (((homer_uint64)'L') << 32) | (((homer_uint64)'K') << 24) | (((homer_uint64)'D') << 16) | (((homer_uint64)'E') << 8) | (((homer_uint64)'S') << 0)) -//#define HOMER_BLOCK_DESCRIPTOR_TYPEID ( (((homer_uint64)'H')<<56)|(((homer_uint64)'O')<<48) ) -#define HOMER_HEADER_CURRENT_VERSION 2 - -class AliHLTHOMERBlockDescriptor -{ - public: - static unsigned GetHOMERBlockDescriptorSize() - { - return sizeof(homer_uint64) * kCount_64b_Words; - } - - AliHLTHOMERBlockDescriptor(void* header = nullptr) - : fHeader(header) - { - } - void UseHeader(void* header) - { - fHeader = header; - } - void Initialize() - { - if (fHeader) { - for (unsigned ii = 0; ii < kCount_64b_Words; ii++) { - ((homer_uint64*)fHeader)[ii] = (homer_uint64)0; - } - ((homer_uint64*)fHeader)[kID_64b_Offset] = HOMER_BLOCK_DESCRIPTOR_TYPEID; - ((homer_uint64*)fHeader)[kLength_64b_Offset] = GetHOMERBlockDescriptorSize(); - ((homer_uint8*)fHeader)[kByteOrderAttribute_8b_Offset] = kHOMERNativeByteOrder; - ((homer_uint8*)fHeader)[kVersionAttribute_8b_Offset] = HOMER_HEADER_CURRENT_VERSION; - } - } - - void SetByteOrder(homer_uint8 bo) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kByteOrderAttribute_8b_Offset] = bo; - } - } - homer_uint8 GetByteOrder() const - { - if (fHeader) { - return ((homer_uint8*)fHeader)[kByteOrderAttribute_8b_Offset]; - } - return 0xFF; - } - void SetVersion(homer_uint8 v) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kVersionAttribute_8b_Offset] = v; - } - } - void SetID(homer_uint64 id) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kID_64b_Offset] = id; - } - } - void SetHeaderLength(homer_uint64 l) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kLength_64b_Offset] = l; - } - } - homer_uint64 GetHeaderLength() const - { - if (fHeader) { - return ((homer_uint64*)fHeader)[kLength_64b_Offset]; - } - return 0; - } - void SetAlignment(homer_uint8 type, homer_uint8 align) const - { - if (fHeader && type < 6) { - ((homer_uint8*)fHeader)[kAlignment_8b_StartOffset + type] = align; - } - } - void SetUInt64Alignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kUInt64Alignment_8b_Offset] = align; - } - } - void SetUInt32Alignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kUInt32Alignment_8b_Offset] = align; - } - } - void SetUInt16Alignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kUInt16Alignment_8b_Offset] = align; - } - } - void SetUInt8Alignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kUInt8Alignment_8b_Offset] = align; - } - } - void SetDoubleAlignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kDoubleAlignment_8b_Offset] = align; - } - } - void SetFloatAlignment(homer_uint8 align) const - { - if (fHeader) { - ((homer_uint8*)fHeader)[kFloatAlignment_8b_Offset] = align; - } - } - void SetType(homer_uint64 t) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kType_64b_Offset] = t; - } - } - void SetSubType1(homer_uint64 st1) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kSubType1_64b_Offset] = st1; - } - } - void SetSubType2(homer_uint64 st2) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kSubType2_64b_Offset] = st2; - } - } - void SetBirth_s(homer_uint64 bs) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kBirth_s_64b_Offset] = bs; - } - } - void SetBirth_us(homer_uint64 bus) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kBirth_us_64b_Offset] = bus; - } - } - void SetProducerNode(homer_uint64 pn) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kProducerNode_64b_Offset] = pn; - } - } - void SetBlockOffset(homer_uint64 bo) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kOffset_64b_Offset] = bo; - } - } - homer_uint64 GetBlockOffset() const - { - if (fHeader) { - return ((homer_uint64*)fHeader)[kOffset_64b_Offset]; - } - return 0; - } - void SetBlockSize(homer_uint64 bs) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kSize_64b_Offset] = bs; - } - } - homer_uint64 GetBlockSize() const - { - if (fHeader) { - return ((homer_uint64*)fHeader)[kSize_64b_Offset]; - } - return 0; - } - void SetStatusFlags(homer_uint64 bs) const - { - if (fHeader) { - ((homer_uint64*)fHeader)[kStatusFlags_64b_Offset] = bs; - } - } - homer_uint64 GetStatusFlags() const - { - if (fHeader) { - return ((homer_uint64*)fHeader)[kStatusFlags_64b_Offset]; - } - return 0; - } - - void* GetHeader() const - { - return fHeader; - } - - protected: - void* fHeader; //! transient - - private: - /** copy constructor prohibited */ - AliHLTHOMERBlockDescriptor(const AliHLTHOMERBlockDescriptor&); - /** assignment operator prohibited */ - AliHLTHOMERBlockDescriptor& operator=(const AliHLTHOMERBlockDescriptor&); -}; - -// the HOMERBlockDescriptor is used in the code -typedef class AliHLTHOMERBlockDescriptor HOMERBlockDescriptor; - -/* -*************************************************************************** -** -** $Author$ - Initial Version by Timm Morten Steinbeck -** -** $Id$ -** -*************************************************************************** -*/ - -#endif // ALIHLTHOMERDATA_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERReader.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERReader.h deleted file mode 100644 index a5cdadd53b830..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERReader.h +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// XEMacs -*-C++-*- -#ifndef AliHLTHOMERREADER_H -#define AliHLTHOMERREADER_H -/* This file is property of and copyright by the ALICE HLT Project * - * ALICE Experiment at CERN, All rights reserved. * - * See cxx source for full Copyright notice */ - -/** @file AliHLTHOMERReader.h - @author Timm Steinbeck - @date Sep 14 2007 - @brief HLT Online Monitoring Environment including ROOT - Reader - @note migrated from PubSub HLT-stable-20070905.141318 (rev 2375) - 2014-05-08 included to ALFA for HOMER support -*/ - -#include <climits> -#include <sys/ipc.h> -#include <sys/shm.h> -#include "AliHLTHOMERData.h" - -/** - * @class AliHLTMonitoringReader - * The class provides a virtual interface for the HOMER reader. - * Used for dynamic generation of HOMER readers and dynamic loading of - * the libAliHLTHOMER library. - * @see AliHLTHOMERLibManager - * - * @ingroup alihlt_homer - */ -class AliHLTMonitoringReader -{ - public: - AliHLTMonitoringReader() = default; - virtual ~AliHLTMonitoringReader() = default; - - /* Return the status of the connection as established by one of the constructors. - 0 means connection is ok, non-zero specifies the type of error that occured. */ - virtual int GetConnectionStatus() const = 0; - - /* Return the index of the connection for which an error given by the above - function occured. */ - virtual unsigned int GetErrorConnectionNdx() const = 0; - - /* Read in the next available event */ - virtual int ReadNextEvent() = 0; - /* Read in the next available event, wait max. timeout microsecs. */ - virtual int ReadNextEvent(unsigned long timeout) = 0; - - /* Return the type of the current event */ - virtual homer_uint64 GetEventType() const = 0; - - /* Return the ID of the current event */ - virtual homer_uint64 GetEventID() const = 0; - - /* Return the number of data blocks in the current event */ - virtual unsigned long GetBlockCnt() const = 0; - - /* Return the size (in bytes) of the current event's data - block with the given block index (starting at 0). */ - virtual unsigned long GetBlockDataLength(unsigned long ndx) const = 0; - /* Return a pointer to the start of the current event's data - block with the given block index (starting at 0). */ - virtual const void* GetBlockData(unsigned long ndx) const = 0; - /* Return IP address or hostname of node which sent the - current event's data block with the given block index - (starting at 0). */ - virtual const char* GetBlockSendNodeID(unsigned long ndx) const = 0; - /* Return byte order of the data stored in the - current event's data block with the given block - index (starting at 0). - 0 is unknown alignment, - 1 ist little endian, - 2 is big endian. */ - virtual homer_uint8 GetBlockByteOrder(unsigned long ndx) const = 0; - /* Return the alignment (in bytes) of the given datatype - in the data stored in the current event's data block - with the given block index (starting at 0). - Possible values for the data type are - 0: homer_uint64 - 1: homer_uint32 - 2: uin16 - 3: homer_uint8 - 4: double - 5: float - */ - virtual homer_uint8 GetBlockTypeAlignment(unsigned long ndx, homer_uint8 dataType) const = 0; - - virtual homer_uint64 GetBlockStatusFlags(unsigned long ndx) const = 0; - - /* Return the type of the data in the current event's data - block with the given block index (starting at 0). */ - virtual homer_uint64 GetBlockDataType(unsigned long ndx) const = 0; - /* Return the origin of the data in the current event's data - block with the given block index (starting at 0). */ - virtual homer_uint32 GetBlockDataOrigin(unsigned long ndx) const = 0; - /* Return a specification of the data in the current event's data - block with the given block index (starting at 0). */ - virtual homer_uint32 GetBlockDataSpec(unsigned long ndx) const = 0; - - /* Find the next data block in the current event with the given - data type, origin, and specification. Returns the block's - index. */ - virtual unsigned long FindBlockNdx(homer_uint64 type, homer_uint32 origin, - homer_uint32 spec, unsigned long startNdx = 0) const = 0; - - /* Find the next data block in the current event with the given - data type, origin, and specification. Returns the block's - index. */ - virtual unsigned long FindBlockNdx(char type[8], char origin[4], - homer_uint32 spec, unsigned long startNdx = 0) const = 0; -#ifdef USE_ROOT - ClassDefOverride(AliHLTMonitoringReader, 1); -#endif -}; - -class AliHLTHOMERReader : public AliHLTMonitoringReader -{ - public: -#ifdef USE_ROOT - AliHLTHOMERReader(); -#endif - - /* Constructors & destructors, HOMER specific */ - /* For reading from a TCP port */ - AliHLTHOMERReader(const char* hostname, unsigned short port); - /* For reading from multiple TCP ports */ - AliHLTHOMERReader(unsigned int tcpCnt, const char** hostnames, const unsigned short* ports); - /* For reading from a System V shared memory segment */ - AliHLTHOMERReader(key_t shmKey, int shmSize); - /* For reading from multiple System V shared memory segments */ - AliHLTHOMERReader(unsigned int shmCnt, const key_t* shmKey, const int* shmSize); - /* For reading from multiple TCP ports and multiple System V shared memory segments */ - AliHLTHOMERReader(unsigned int tcpCnt, const char** hostnames, const unsigned short* ports, - unsigned int shmCnt, const key_t* shmKey, const int* shmSize); - /* For reading from a buffer */ - AliHLTHOMERReader(const void* pBuffer, int size); - ~AliHLTHOMERReader() override; - - /* Return the status of the connection as established by one of the constructors. - 0 means connection is ok, non-zero specifies the type of error that occured. */ - int GetConnectionStatus() const override - { - return fConnectionStatus; - } - - /* Return the index of the connection for which an error given by the above - function occured. */ - unsigned int GetErrorConnectionNdx() const override - { - return fErrorConnection; - } - - void SetEventRequestAdvanceTime(unsigned long time) - { - // advance time in us - fEventRequestAdvanceTime = time; - } - - /* Defined in AliHLTMonitoringReader */ - /** Read in the next available event */ - int ReadNextEvent() override; - /** Read in the next available event */ - int ReadNextEvent(unsigned long timeout) override; - - /** Return the type of the current event */ - homer_uint64 GetEventType() const override - { - return fCurrentEventType; - } - - /** Return the ID of the current event */ - homer_uint64 GetEventID() const override - { - return fCurrentEventID; - } - - /** Return the number of data blocks in the current event */ - unsigned long GetBlockCnt() const override - { - return fBlockCnt; - } - - /** Return a pointer to the start of the current event's data - block with the given block index (starting at 0). */ - const void* GetBlockData(unsigned long ndx) const override; - /** Return the size (in bytes) of the current event's data - block with the given block index (starting at 0). */ - unsigned long GetBlockDataLength(unsigned long ndx) const override; - /** Return IP address or hostname of node which sent the - current event's data block with the given block index - (starting at 0). - For HOMER this is the ID of the node on which the subscriber - that provided this data runs/ran. */ - const char* GetBlockSendNodeID(unsigned long ndx) const override; - /** Return byte order of the data stored in the - current event's data block with the given block - index (starting at 0). - 0 is unknown alignment, - 1 ist little endian, - 2 is big endian. */ - homer_uint8 GetBlockByteOrder(unsigned long ndx) const override; - /** Return the alignment (in bytes) of the given datatype - in the data stored in the current event's data block - with the given block index (starting at 0). - Possible values for the data type are - 0: homer_uint64 - 1: homer_uint32 - 2: uin16 - 3: homer_uint8 - 4: double - 5: float - */ - homer_uint8 GetBlockTypeAlignment(unsigned long ndx, homer_uint8 dataType) const override; - - homer_uint64 GetBlockStatusFlags(unsigned long ndx) const override; - - /* HOMER specific */ - /** Return the type of the data in the current event's data - block with the given block index (starting at 0). */ - homer_uint64 GetBlockDataType(unsigned long ndx) const override; - /** Return the origin of the data in the current event's data - block with the given block index (starting at 0). */ - homer_uint32 GetBlockDataOrigin(unsigned long ndx) const override; - /** Return a specification of the data in the current event's data - block with the given block index (starting at 0). */ - homer_uint32 GetBlockDataSpec(unsigned long ndx) const override; - - /** Return the time stamp of when the data block was created. - This is a UNIX time stamp in seconds. - \param ndx The index of the block (starting at 0). */ - homer_uint64 GetBlockBirthSeconds(unsigned long ndx) const; - - /** Return the micro seconds part of the time stamp of when the data - block was created. - \param ndx The index of the block (starting at 0). */ - homer_uint64 GetBlockBirthMicroSeconds(unsigned long ndx) const; - - /** Find the next data block in the current event with the given - data type, origin, and specification. Returns the block's - index. */ - unsigned long FindBlockNdx(homer_uint64 type, homer_uint32 origin, - homer_uint32 spec, unsigned long startNdx = 0) const override; - - /** Find the next data block in the current event with the given - data type, origin, and specification. Returns the block's - index. */ - unsigned long FindBlockNdx(char type[8], char origin[4], - homer_uint32 spec, unsigned long startNdx = 0) const override; - - /** Return the ID of the node that actually produced this data block. - This may be different from the node which sent the data to this - monitoring object as returned by GetBlockSendNodeID. */ - const char* GetBlockCreateNodeID(unsigned long ndx) const; - - protected: - enum DataSourceType { kUndef = 0, - kTCP, - kShm, - kBuf }; - struct DataSource { - DataSourceType fType; // source type (TCP or Shm) - unsigned fNdx; // This source's index - const char* fHostname; // Filled for both Shm and TCP - unsigned short fTCPPort; // port if type TCP - key_t fShmKey; // shm key if type Shm - int fShmSize; // shm size if type Shm - int fTCPConnection; // File descriptor for the TCP connection - int fShmID; // ID of the shared memory area - void* fShmPtr; // Pointer to shared memory area - void* fData; // Pointer to data read in for current event from this source - unsigned long fDataSize; // Size of data (to be) read in for current event from this source - unsigned long fDataRead; // Data actually read for current event - }; - - void Init(); - - bool AllocDataSources(unsigned int sourceCnt); - int AddDataSource(const char* hostname, unsigned short port, DataSource& source); - int AddDataSource(key_t shmKey, int shmSize, DataSource& source); - int AddDataSource(void* pBuffer, int size, DataSource& source); - void FreeDataSources(); - int FreeShmDataSource(DataSource& source); - int FreeTCPDataSource(DataSource& source); - int ReadNextEvent(bool useTimeout, unsigned long timeout); - void ReleaseCurrentEvent(); - int TriggerTCPSource(DataSource& source, bool useTimeout, unsigned long timeout); - int TriggerShmSource(DataSource& source, bool useTimeout, unsigned long timeout) const; - int ReadDataFromTCPSources(unsigned sourceCnt, DataSource* sources, bool useTimeout, unsigned long timeout); - int ReadDataFromShmSources(unsigned sourceCnt, DataSource* sources, bool useTimeout, unsigned long timeout); - int ParseSourceData(const DataSource& source); - int ReAllocBlocks(unsigned long newCnt); - homer_uint64 GetSourceEventID(const DataSource& source); - homer_uint64 GetSourceEventType(const DataSource& source); - homer_uint64 Swap(homer_uint8 destFormat, homer_uint8 sourceFormat, homer_uint64 source) const; - - homer_uint32 Swap(homer_uint8 destFormat, homer_uint8 sourceFormat, homer_uint32 source) const; - - struct DataBlock { - unsigned int fSource; // Index of originating data source - void* fData; // pointer to data - unsigned long fLength; // buffer length - homer_uint64* fMetaData; // Pointer to meta data describing data itself. - const char* fOriginatingNodeID; // node id from which the data originates - }; - - /** type of the current event */ - homer_uint64 fCurrentEventType; //!transient - /** ID of the current event */ - homer_uint64 fCurrentEventID; //!transient - /** no of blocks currently used */ - unsigned long fBlockCnt; //!transient - /** available space in the block array */ - unsigned long fMaxBlockCnt; //!transient - /** block array */ - DataBlock* fBlocks; //!transient - - /** total no of data sources */ - unsigned int fDataSourceCnt; //!transient - /** no of TCP data sources */ - unsigned int fTCPDataSourceCnt; //!transient - /** no of Shm data sources */ - unsigned int fShmDataSourceCnt; //!transient - /** available space in the sources array */ - unsigned int fDataSourceMaxCnt; //!transient - /** array of data source descriptions */ - DataSource* fDataSources; //!transient - - /** status of the connection */ - int fConnectionStatus; //!transient - /** flag an error for */ - unsigned fErrorConnection; //!transient - - /** */ - unsigned long fEventRequestAdvanceTime; //!transient - private: - /** copy constructor prohibited */ - AliHLTHOMERReader(const AliHLTHOMERReader&); - /** assignment operator prohibited */ - AliHLTHOMERReader& operator=(const AliHLTHOMERReader&); - -#ifdef USE_ROOT - ClassDefOverride(AliHLTHOMERReader, 2); -#endif -}; - -/** defined for backward compatibility */ -typedef AliHLTMonitoringReader MonitoringReader; -/** defined for backward compatibility */ -typedef AliHLTHOMERReader HOMERReader; - -// external interface of the HOMER reader -#define ALIHLTHOMERREADER_CREATE_FROM_TCPPORT "AliHLTHOMERReaderCreateFromTCPPort" -#define ALIHLTHOMERREADER_CREATE_FROM_TCPPORTS "AliHLTHOMERReaderCreateFromTCPPorts" -#define ALIHLTHOMERREADER_CREATE_FROM_BUFFER "AliHLTHOMERReaderCreateFromBuffer" -#define ALIHLTHOMERREADER_DELETE "AliHLTHOMERReaderDelete" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef AliHLTHOMERReader* (*AliHLTHOMERReaderCreateFromTCPPort_t)(const char* hostname, unsigned short port); -typedef AliHLTHOMERReader* (*AliHLTHOMERReaderCreateFromTCPPorts_t)(unsigned int tcpCnt, const char** hostnames, unsigned short* ports); -typedef AliHLTHOMERReader* (*AliHLTHOMERReaderCreateFromBuffer_t)(const void* pBuffer, int size); -typedef void (*AliHLTHOMERReaderDelete_t)(AliHLTHOMERReader* pInstance); - -/** - * Create instance of HOMER reader working on a TCP port. - */ -AliHLTHOMERReader* AliHLTHOMERReaderCreateFromTCPPort(const char* hostname, unsigned short port); - -/** - * Create instance of HOMER reader working on multiple TCP ports. - */ -AliHLTHOMERReader* AliHLTHOMERReaderCreateFromTCPPorts(unsigned int tcpCnt, const char** hostnames, unsigned short* ports); - -/** - * Create instance of HOMER reader working on buffer. - */ -AliHLTHOMERReader* AliHLTHOMERReaderCreateFromBuffer(const void* pBuffer, int size); - -/** - * Delete instance of HOMER reader. - */ -void AliHLTHOMERReaderDelete(AliHLTHOMERReader* pInstance); -#ifdef __cplusplus -} -#endif - -#endif /* AliHLTHOMERREADER_H */ diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERWriter.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERWriter.h deleted file mode 100644 index 67136528e8ed7..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/AliHLTHOMERWriter.h +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -// XEMacs -*-C++-*- -#ifndef ALIHLTHOMERWRITER_H -#define ALIHLTHOMERWRITER_H -/************************************************************************ -** -** -** This file is property of and copyright by the Technical Computer -** Science Group, Kirchhoff Institute for Physics, Ruprecht-Karls- -** University, Heidelberg, Germany, 2001 -** This file has been written by Timm Morten Steinbeck, -** timm@kip.uni-heidelberg.de -** -** -** See the file license.txt for details regarding usage, modification, -** distribution and warranty. -** Important: This file is provided without any warranty, including -** fitness for any particular purpose. -** -** -** Newer versions of this file's package will be made available from -** http://web.kip.uni-heidelberg.de/Hardwinf/L3/ -** or the corresponding page of the Heidelberg Alice Level 3 group. -** -*************************************************************************/ - -/* -*************************************************************************** -** -** $Author$ - Initial Version by Timm Morten Steinbeck -** -** $Id$ -** -*************************************************************************** -*/ - -/** @file AliHLTHOMERWriter.h - @author Timm Steinbeck - @date Sep 14 2007 - @brief HLT Online Monitoring Environment including ROOT - Writer - @note migrated from PubSub HLT-stable-20070905.141318 (rev 2375) - 2014-05-08 included to ALFA for HOMER support -*/ - -// see below for class documentation -// or -// refer to README to build package -// or -// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt - -#include "AliHLTHOMERData.h" -#include <vector> - -/** - * @class AliHLTMonitoringWriter - * A pure virtual interface definition for HLT monitoring writers. - * - * @ingroup alihlt_homer - */ -class AliHLTMonitoringWriter -{ - public: - AliHLTMonitoringWriter() = default; - virtual ~AliHLTMonitoringWriter() = default; - - virtual void Clear() = 0; - - virtual void AddBlock(const void* descriptor, const void* data) = 0; - - virtual homer_uint32 GetTotalMemorySize(bool includeData = true) = 0; - virtual void Copy(void* destination, homer_uint64 eventType, homer_uint64 eventNr, homer_uint64 statusFlags, homer_uint64 nodeID, bool includeData = true) = 0; -}; - -/** - * @class AliHLTHOMERWriter - * The HOMER writer assembles several data blocks of different properties - * into one big buffer and adds meta information to describe the data's - * alignment and byte order. - */ -class AliHLTHOMERWriter : public AliHLTMonitoringWriter -{ - public: - AliHLTHOMERWriter(); - ~AliHLTHOMERWriter() override; - - /** - * Resets the writer and clears the block list. - */ - void Clear() override; - - /** - * Add a data block to the writer. - * The HOMER header must contain all meta information including the - * size of the data. - * @param homerHeader pointer to the header describing the block - * @param data pointer to data - */ - void AddBlock(const void* homerHeader, const void* data) override; - - /** - * Add a data block to the writer. - * The function has certainly been introduced to make type - * conversion easier. In fact it makes it worse. The presence of the - * function with void* argument leads to a wrong interpretation when - * passing a non const pointer to HOMERBlockDescriptor. Then the - * other function is called directly, leading to pointer mess up. - */ - void AddBlock(const HOMERBlockDescriptor* descriptor, const void* data) - { - AddBlock(descriptor->GetHeader(), data); - } - - /** - * Add a data block to the writer. - * Function added to avoid potential pointer mismatches - */ - void AddBlock(HOMERBlockDescriptor* descriptor, const void* data) - { - AddBlock(descriptor->GetHeader(), data); - } - - /** - * Get the total buffer size required to write all data into one buffer - */ - homer_uint32 GetTotalMemorySize(bool includeData = true) override; - - /** - * Copy the data into a buffer. - * The buffer is supposed to be big enough, the capacity should be queried - * by calling @ref GetTotalMemorySize. - */ - void Copy(void* destination, homer_uint64 eventType, homer_uint64 eventNr, homer_uint64 statusFlags, homer_uint64 nodeID, bool includeData = true) override; - - /** determine alignment of 64 bit variables */ - static homer_uint8 DetermineUInt64Alignment(); - /** determine alignment of 32 bit variables */ - static homer_uint8 DetermineUInt32Alignment(); - /** determine alignment of 16 bit variables */ - static homer_uint8 DetermineUInt16Alignment(); - /** determine alignment of 8 bit variables */ - static homer_uint8 DetermineUInt8Alignment(); - /** determine alignment of double type variables */ - static homer_uint8 DetermineDoubleAlignment(); - /** determine alignment of float type bit variables */ - static homer_uint8 DetermineFloatAlignment(); - - /** test structure for the alignment determination of 64 bit variables */ - struct AliHLTHOMERWriterAlignment64TestStructure { - homer_uint64 f64Fill; // ! - homer_uint64 f64Test64; // ! - homer_uint32 f32Fill; // ! - homer_uint64 f64Test32; // ! - homer_uint16 f16Fill; // ! - homer_uint64 f64Test16; // ! - homer_uint8 f8Fill; // ! - homer_uint64 f64Test8; // ! - }; - /** test structure for the alignment determination of 32 bit variables */ - struct AliHLTHOMERWriterAlignment32TestStructure { - homer_uint64 f64Fill; // ! - homer_uint32 f32Test64; // ! - homer_uint32 f32Fill; // ! - homer_uint32 f32Test32; // ! - homer_uint16 f16Fill; // ! - homer_uint32 f32Test16; // ! - homer_uint8 f8Fill; // ! - homer_uint32 f32Test8; // ! - }; - /** test structure for the alignment determination of 16 bit variables */ - struct AliHLTHOMERWriterAlignment16TestStructure { - homer_uint64 f64Fill; // ! - homer_uint16 f16Test64; // ! - homer_uint32 f32Fill; // ! - homer_uint16 f16Test32; // ! - homer_uint16 f16Fill; // ! - homer_uint16 f16Test16; // ! - homer_uint8 f8Fill; // ! - homer_uint16 f16Test8; // ! - }; - /** test structure for the alignment determination of 8 bit variables */ - struct AliHLTHOMERWriterAlignment8TestStructure { - homer_uint64 f64Fill; // ! - homer_uint8 f8Test64; // ! - homer_uint32 f32Fill; // ! - homer_uint8 f8Test32; // ! - homer_uint16 f16Fill; // ! - homer_uint8 f8Test16; // ! - homer_uint8 f8Fill; // ! - homer_uint8 f8Test8; // ! - }; - /** test structure for the alignment determination of double type variables */ - struct AliHLTHOMERWriterAlignmentDoubleTestStructure { - homer_uint64 f64Fill; // ! - double fDoubleTest64; // ! - homer_uint32 f32Fill; // ! - double fDoubleTest32; // ! - homer_uint16 f16Fill; // ! - double fDoubleTest16; // ! - homer_uint8 f8Fill; // ! - double fDoubleTest8; // ! - }; - /** test structure for the alignment determination of float type variables */ - struct AliHLTHOMERWriterAlignmentFloatTestStructure { - homer_uint64 f64Fill; // ! - float fFloatTest64; // ! - homer_uint32 f32Fill; // ! - float fFloatTest32; // ! - homer_uint16 f16Fill; // ! - float fFloatTest16; // ! - homer_uint8 f8Fill; // ! - float fFloatTest8; // ! - }; - - protected: - /** - * Block descriptor structure. - * The descriptor contains a header for meta information and position - * and a pointer to the data. - */ - struct TBlockData { - homer_uint64 fDescriptor[kCount_64b_Words]; //!transient - const void* fData; //!transient - }; - - unsigned long fDataOffset; //!transient - - /** list of data blocks */ - std::vector<TBlockData> fBlocks; //!transient -#ifdef USE_ROOT - ClassDefOverride(AliHLTHOMERWriter, 0); -#endif -}; - -/** defined for backward compatibility */ -typedef AliHLTHOMERWriter HOMERWriter; - -// external interface of the HOMER writer -#define ALIHLTHOMERWRITER_CREATE "AliHLTHOMERWriterCreate" -#define ALIHLTHOMERWRITER_DELETE "AliHLTHOMERWriterDelete" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef AliHLTHOMERWriter* (*AliHLTHOMERWriterCreate_t)(); -typedef void (*AliHLTHOMERWriterDelete_t)(AliHLTHOMERWriter* pInstance); -/** - * Create instance of HOMER writer. - */ -AliHLTHOMERWriter* AliHLTHOMERWriterCreate(); - -/** - * Delete instance of HOMER writer. - */ -void AliHLTHOMERWriterDelete(AliHLTHOMERWriter* pInstance); -#ifdef __cplusplus -} -#endif - -/* -*************************************************************************** -** -** $Author$ - Initial Version by Timm Morten Steinbeck -** -** $Id$ -** -*************************************************************************** -*/ - -#endif // ALIHLTHOMERWRITER_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/Component.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/Component.h deleted file mode 100644 index 76ae05190ee5d..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/Component.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef COMPONENT_H -#define COMPONENT_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file Component.h -// @author Matthias Richter -// @since 2014-05-08 -// @brief A component running ALICE HLT code - -#include "AliHLTDataTypes.h" -#include "MessageFormat.h" -#include <vector> -#include <boost/signals2.hpp> -#include <boost/program_options.hpp> -//using boost::signals2::signal; -typedef boost::signals2::signal<unsigned char*(unsigned int)> cballoc_signal_t; - -namespace bpo = boost::program_options; - -namespace o2 -{ -namespace alice_hlt -{ -class SystemInterface; - -/// @class Component -/// This class handles the creation of an HLT component and data processing -/// via the SystemInterface. Each HLT component is implemented in a library -/// and identified by a "component ID". HLT components support the processing -/// interface and need to be initialized by calling function Init(). -/// -/// Mandatory arguments: -/// --library HLT component library to be loaded -/// --component component ID -/// -/// Optional arguments -/// --parameter parameters of the component -/// Each componenent is initialized from a list of arguments -/// which have impact on e.g. algorithm, cuts, data selection -/// and the type of output being produced. The arguments are -/// completely under control of component. -/// --run run no -/// Currently, all HLT components need configuration and -/// calibration data from OCDB; OCDB interface needs to -/// be initialized with run number -/// --ocdb uri of the OCDB, e.g. 'local://./OCDB' -/// --msgsize size of the output buffer in byte -/// This overrides the default behavior where output buffer -/// size is determined from the input size and properties -/// of the component -/// --output-mode mode of arranging output blocks, @see MessageFormat.h -/// 0 HOMER format -/// 1 blocks in multiple messages -/// 2 blocks concatenated in one message (default) -/// 3 O2 data format (default) -/// -class Component -{ - public: - /// default constructor - Component(); - /// destructor - ~Component(); - - /// get description of options - static bpo::options_description GetOptionsDescription(); - - // TODO: have been trying to use strongly typed enums, however - // the problem starts with the iteration over all elements (which - // doen't seem to work without specialized coding in the enum class) - // Furthermore, one would need to use a map which can not be used in - // a constexpr because of the non-trivial destructor - // Keep the solution with the simple const char array for the OptionKeys - // and live with the fact that changing the sequence causes a runtime - // error, and a compile time check is not possible - enum /*class*/ OptionKeyIds /*: int*/ { - OptionKeyLibrary = 0, - OptionKeyComponent, - OptionKeyParameter, - OptionKeyRun, - OptionKeyOCDB, - OptionKeyMsgsize, - OptionKeyOutputMode, - OptionKeyInstanceId, - OptionKeyLast - }; - - constexpr static const char* OptionKeys[] = { - "library", - "component", - "parameter", - "run", - "ocdb", - "msgsize", - "output-mode", - "instance-id", - nullptr}; - - /// Init the component - int init(int argc, char** argv); - - /// Process one event - /// Method takes a list of binary buffers which are expected to start with - /// the AliHLTComponentBlockData header immediately followed by the block - /// payload. After processing, handles to output blocks are provided in this - /// list. - int process(std::vector<o2::alice_hlt::MessageFormat::BufferDesc_t>& dataArray, - cballoc_signal_t* cbAllocate = nullptr); - - int getEventCount() const { return mEventCount; } - - protected: - private: - // copy constructor prohibited - Component(const Component&); - // assignment operator prohibited - Component& operator=(const Component&); - - /// output buffer to receive the data produced by component - std::vector<uint8_t> mOutputBuffer; - - /// instance of the system interface - SystemInterface* mpSystem; - /// handle of the processing component - AliHLTComponentHandle mProcessor; - /// container for handling the i/o buffers - o2::alice_hlt::MessageFormat mFormatHandler; - int mEventCount; -}; - -} // namespace alice_hlt -} // namespace o2 -#endif // COMPONENT_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/EventSampler.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/EventSampler.h deleted file mode 100644 index d523a806f0473..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/EventSampler.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef EVENTSAMPLER_H -#define EVENTSAMPLER_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file EventSampler.h -// @author Matthias Richter -// @since 2015-03-15 -// @brief Sampler device for Alice HLT events in FairRoot/ALFA - -#include <FairMQDevice.h> -#include <vector> -#include <boost/program_options.hpp> - -namespace bpo = boost::program_options; - -namespace o2 -{ -namespace alice_hlt -{ -class Component; - -/// @class EventSampler -/// Sampler device for Alice HLT events in FairRoot/ALFA. -/// -/// The device sends the event descriptor to downstream devices and can -/// measure latency though a feedback channel -class EventSampler : public FairMQDevice -{ - public: - /// default constructor - EventSampler(int verbosity = 0); - /// destructor - ~EventSampler() override; - - /// get description of options - static bpo::options_description GetOptionsDescription(); - - enum /*class*/ OptionKeyIds /*: int*/ { - OptionKeyEventPeriod = 0, - OptionKeyInitialDelay, - OptionKeyPollTimeout, - OptionKeyDryRun, - OptionKeyLatencyLog, - OptionKeyLast - }; - - constexpr static const char* OptionKeys[] = { - "eventperiod", - "initialdelay", - "polltimeout", - "dry-run", - "latency-log", - nullptr}; - - ///////////////////////////////////////////////////////////////// - // the FairMQDevice interface - - /// inherited from FairMQDevice - void InitTask() override; - /// inherited from FairMQDevice - void Run() override; - - /// sampler loop started in a separate thread - void samplerLoop(); - - protected: - private: - // copy constructor prohibited - EventSampler(const EventSampler&); - // assignment operator prohibited - EventSampler& operator=(const EventSampler&); - - int mEventPeriod; // event rate in us - int mInitialDelay; // initial delay in ms before sending first event - int mNEvents; // number of generated events - int mPollingTimeout; // period of polling on input sockets in ms - int mSkipProcessing; // skip component processing - int mVerbosity; // verbosity level - std::string mLatencyLogFileName; // output file for logging of latency -}; - -} // namespace alice_hlt -} // namespace o2 -#endif // EVENTSAMPLER_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/HOMERFactory.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/HOMERFactory.h deleted file mode 100644 index e6a489399a6cd..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/HOMERFactory.h +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef HOMERFACTORY_H -#define HOMERFACTORY_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//* * -//* See original copyright notice below * -//**************************************************************************** - -// @file HOMERFactory.h -// @author Matthias Richter -// @since 2014-05-07 -// @brief Original AliHLTHOMERLibManager.h of AliRoot adapted to the -// ALFA project - -/* This file is property of and copyright by the ALICE HLT Project * - * ALICE Experiment at CERN, All rights reserved. * - * See cxx source for full Copyright notice */ - -#include "AliHLTDataTypes.h" -class AliHLTHOMERReader; -class AliHLTHOMERWriter; - -namespace o2 -{ -namespace alice_hlt -{ - -/** - * @class HOMERFactory - * Dynamic manager of HOMER library. - * The class allows to generate objects of HOMER readers and writers - * dynamically and loads also the HOMER lib. In order to write HOMER library - * independent code it is important to use the AliHLTMonitoringWriter/ - * AliHLTMonitoringReader classes when ever class methods are used. Those - * classes just define a virtual interface. <br> - * - * Instead of creating a reader or writer by \em new and deleting it with - * \em delete, one has to use the Open and Delete methods of this class. - * - * <pre> - * HOMERFactory manager; - * - * // open a HOMER reader listening at port 23000 of the localhost - * AliHLTMonitoringReader* pReader=manager.OpenReader(localhost, 23000); - * - * // read next event, timeout 5s - * while (pReader && pReader->ReadNextEvent(5000000)==0) { - * unsigned long count=pReader->GetBlockCnt(); - * gSystem->Sleep(5); - * ... - * } - * - * // delete reader - * manager.DeleteReader(pReader); - * </pre> - * - * The manager does not provide methods to create a HOMER reader on - * basis of shared memory. This is most likely a depricated functionality, - * although kept for the sake of completeness. However, at some point it - * might become useful. Please notify the developers if you need that - * functionality. - * - * @ingroup alihlt_homer - */ -class HOMERFactory -{ - public: - /** standard constructor */ - HOMERFactory(); - /** destructor */ - virtual ~HOMERFactory(); - - /** - * Open a homer reader working on a TCP port. - */ - AliHLTHOMERReader* OpenReader(const char* hostname, unsigned short port); - - /** - * Open a homer reader working on multiple TCP ports. - */ - AliHLTHOMERReader* OpenReader(unsigned int tcpCnt, const char** hostnames, unsigned short* ports); - - /** - * Open a HOMER reader for reading from a System V shared memory segment. - AliHLTHOMERReader* OpenReader(key_t shmKey, int shmSize ); - */ - - /** - * Open a HOMER reader for reading from multiple System V shared memory segments - AliHLTHOMERReader* OpenReader(unsigned int shmCnt, key_t* shmKey, int* shmSize ); - */ - - /** - * Open a HOMER reader for reading from multiple TCP ports and multiple System V shared memory segments - AliHLTHOMERReader* OpenReader(unsigned int tcpCnt, const char** hostnames, unsigned short* ports, - unsigned int shmCnt, key_t* shmKey, int* shmSize ); - */ - - /** - * Open a HOMER reader. - * Load HOMER library dynamically and create object working on the provided - * buffer. - */ - AliHLTHOMERReader* OpenReaderBuffer(const AliHLTUInt8_t* pBuffer, int size); - - /** - * Delete a HOMER reader. - * Clean-up of the object is done inside the HOMER library. - */ - int DeleteReader(AliHLTHOMERReader* pReader); - - /** - * Open a HOMER writer. - * Load HOMER library dynamically and create object working on the provided - * buffer. - */ - AliHLTHOMERWriter* OpenWriter(); - - /** - * Delete a HOMER writer. - * Clean-up of the object is done inside the HOMER library. - */ - int DeleteWriter(AliHLTHOMERWriter* pWriter); - - protected: - private: - /** copy constructor prohibited */ - HOMERFactory(const HOMERFactory&); - /** assignment operator prohibited */ - HOMERFactory& operator=(const HOMERFactory&); - - /** - * Load the HOMER library. - */ - int LoadHOMERLibrary(); - - /** - * Unloads the HOMER library. - */ - int UnloadHOMERLibrary(); - - /** status of the loading of the HOMER library */ - static int sLibraryStatus; //!transient - - /** entry in the HOMER library */ - void (*mFctCreateReaderFromTCPPort)(); //!transient - - /** entry in the HOMER library */ - void (*mFctCreateReaderFromTCPPorts)(); //!transient - - /** entry in the HOMER library */ - void (*mFctCreateReaderFromBuffer)(); //!transient - - /** entry in the HOMER library */ - void (*mFctDeleteReader)(); //!transient - - /** entry in the HOMER library */ - void (*mFctCreateWriter)(); //!transient - - /** entry in the HOMER library */ - void (*mFctDeleteWriter)(); //!transient - - /** Indicates the library that was actually (and if) loaded in LoadHOMERLibrary(). */ - const char* mLoadedLib; //!transient - - /** library handle returned by dlopen */ - void* mHandle; - - static const char* sLibraries[]; /// List of libraries to try and load. - static int sLibRefCount[]; /// The library reference count to control when to unload the library. -}; -} // namespace alice_hlt -} // namespace o2 -#endif diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/MessageFormat.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/MessageFormat.h deleted file mode 100644 index 8ae419716f0c4..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/MessageFormat.h +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef MESSAGEFORMAT_H -#define MESSAGEFORMAT_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file MessageFormat.h -// @author Matthias Richter -// @since 2014-12-11 -// @brief Helper class for message format of ALICE HLT data blocks - -#include "AliHLTDataTypes.h" -#include "HOMERFactory.h" -#include <vector> -#include <cstdint> -#include <boost/signals2.hpp> -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" - -class AliHLTHOMERReader; -class AliHLTHOMERWriter; - -namespace o2 -{ -namespace alice_hlt -{ -/// @struct BlockDescriptor -/// Helper struct to provide constructors to AliHLTComponentBlockData -/// -struct BlockDescriptor : public AliHLTComponentBlockData { - BlockDescriptor(AliHLTUInt32_t offset, - void* ptr, - AliHLTUInt32_t size, - AliHLTComponentDataType datatype, - AliHLTUInt32_t specification) - { - fStructSize = sizeof(AliHLTComponentBlockData); - memset(&fShmKey, 0, sizeof(AliHLTComponentShmData)); - fOffset = offset; - fPtr = ptr; - fSize = size; - fDataType = datatype; - fSpecification = specification; - } - - BlockDescriptor(const AliHLTComponentBlockData& src) - : BlockDescriptor(src.fOffset, src.fPtr, src.fSize, src.fDataType, src.fSpecification) {} - - BlockDescriptor(void* ptr, - AliHLTUInt32_t size, - AliHLTComponentDataType datatype, - AliHLTUInt32_t specification) - : BlockDescriptor(0, ptr, size, datatype, specification) {} - - BlockDescriptor() - : BlockDescriptor(0, nullptr, 0, kAliHLTVoidDataType, kAliHLTVoidDataSpec) {} - - BlockDescriptor(void* ptr, - AliHLTUInt32_t size, - const o2::header::DataHeader& o2dh) - : BlockDescriptor(0, ptr, size, AliHLTComponentDataTypeInitializer(o2dh.dataDescription.str, o2dh.dataOrigin.str), o2dh.subSpecification) {} -}; - -/// @class MessageFormat -/// Helper class to format ALICE HLT data blocks for transport in -/// messaging system. -/// -/// Data blocks in the ALICE HLT are described by a block descriptor -/// (data type, size, specification) and the actual data somewhere in -/// memory. For transporting them in a message, block descriptors and -/// payloads are written as a sequence, every block descriptor directly -/// followed by its payload -class MessageFormat -{ - public: - /// default constructor - MessageFormat(); - /// destructor - ~MessageFormat(); - - using DataHeader = o2::header::DataHeader; - using HeartbeatFrameEnvelope = o2::header::HeartbeatFrameEnvelope; - using HeartbeatHeader = o2::header::HeartbeatHeader; - using HeartbeatTrailer = o2::header::HeartbeatTrailer; - - struct BufferDesc_t { - using PtrT = unsigned char*; - PtrT mP; - unsigned mSize; - - BufferDesc_t(unsigned char* p, unsigned size) - { - mP = p; - mSize = size; - } - }; - - enum { - // all blocks in HOMER format - kOutputModeHOMER = 0, - // each block individually as part of a multi-part output - kOutputModeMultiPart, - // all blocks as sequence of header and payload - kOutputModeSequence, - // O2 data format, header-payload pairs - kOutputModeO2, - kOutputModeLast - }; - - // cleanup internal buffers - void clear(); - - // set output mode - void setOutputMode(unsigned mode) { mOutputMode = mode; } - - // add message - // this will extract the block descriptors from the message - // the descriptors refer to data in the original message buffer - int addMessage(uint8_t* buffer, unsigned size); - - // add list of messages - // this will extract the block descriptors from the message - // the descriptors refer to data in the original message buffer - int addMessages(const std::vector<BufferDesc_t>& list); - - // add a block descriptor and its payload to the message - // planned for future extension - //int AddOutput(AliHLTComponentBlockData* db); - - std::vector<BlockDescriptor>& getBlockDescriptors() - { - return mBlockDescriptors; - } - - const std::vector<BlockDescriptor>& getBlockDescriptors() const - { - return mBlockDescriptors; - } - - // create message payloads in the internal buffer and return list - // of decriptors - std::vector<BufferDesc_t> createMessages(const AliHLTComponentBlockData* blocks, unsigned count, - unsigned totalPayloadSize, const AliHLTComponentEventData* evtData = nullptr, - boost::signals2::signal<unsigned char*(unsigned int)>* cbAllocate = nullptr); - - // read a sequence of blocks consisting of AliHLTComponentBlockData followed by payload - // from a buffer - int readBlockSequence(uint8_t* buffer, unsigned size, std::vector<BlockDescriptor>& descriptorList) const; - - // read message payload in HOMER format - int readHOMERFormat(uint8_t* buffer, unsigned size, std::vector<BlockDescriptor>& descriptorList) const; - - // read messages in O2 format - int readO2Format(const std::vector<BufferDesc_t>& list, std::vector<BlockDescriptor>& descriptorList, HeartbeatHeader& hbh, HeartbeatTrailer& hbt) const; - - // create HOMER format from the output blocks - AliHLTHOMERWriter* createHOMERFormat(const AliHLTComponentBlockData* pOutputBlocks, - uint32_t outputBlockCnt) const; - - // insert event header to list, sort by time, oldest first - int insertEvtData(const AliHLTComponentEventData& evtData); - - // get event header list - const std::vector<AliHLTComponentEventData>& getEvtDataList() const - { - return mListEvtData; - } - - uint64_t byteSwap64(uint64_t src) const; - uint32_t byteSwap32(uint32_t src) const; - - protected: - private: - // copy constructor prohibited - MessageFormat(const MessageFormat&); - // assignment operator prohibited - MessageFormat& operator=(const MessageFormat&); - - // single point to provide a target pointer, either by using a - // provided callback function or in the internal buffer, which has - // to be allocated completely in advance in order to ensure validity - // of the pointers - uint8_t* MakeTarget(unsigned size, unsigned position, boost::signals2::signal<unsigned char*(unsigned int)>* cbAllocate); - - std::vector<BlockDescriptor> mBlockDescriptors; - /// internal buffer to assemble message data - std::vector<uint8_t> mDataBuffer; - /// list of message payload descriptors - std::vector<BufferDesc_t> mMessages; - /// HOMER factory for creation and deletion of HOMER readers and writers - o2::alice_hlt::HOMERFactory* mpFactory; - /// output mode: HOMER, multi-message, sequential - int mOutputMode; - /// list of event descriptors - std::vector<AliHLTComponentEventData> mListEvtData; - - /// the current heartbeat header - HeartbeatHeader mHeartbeatHeader; - /// the current heartbeat trailer - HeartbeatTrailer mHeartbeatTrailer; -}; - -} // namespace alice_hlt -} // namespace o2 -#endif // MESSAGEFORMAT_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/SystemInterface.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/SystemInterface.h deleted file mode 100644 index 710fae94ba5e2..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/SystemInterface.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef SYSTEMINTERFACE_H -#define SYSTEMINTERFACE_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file SystemInterface.h -// @author Matthias Richter -// @since 2014-05-07 -// @brief FairRoot/ALFA interface to ALICE HLT code - -#include "AliHLTDataTypes.h" -namespace o2 -{ -namespace alice_hlt -{ - -/// @class SystemInterface -/// Tool class for the ALICE HLT external interface defined in -/// AliHLTDataTypes.h -/// -/// The class loads the interface library and loads the function -/// pointers. The individual functions of the external interface -/// can be used by calling the corresponding functions of this class. -class SystemInterface -{ - public: - /// default constructor - SystemInterface(); - /// destructor - ~SystemInterface(); - - /** initilize the system - * load external library and set up the HLT system - */ - int initSystem(unsigned long runNo); - - /** cleanup and release system - */ - int releaseSystem(); - - /** load HLT plugin library - */ - int loadLibrary(const char* libname); - - /** unload HLT plugin library - */ - int unloadLibrary(const char* libname); - - /** create/factorize component - * @param componentType - * @param environParam - * @param argc - * @param argv - * @param handle - * @param description - * @return 0 on success and valid handle - */ - int createComponent(const char* componentId, - void* environParam, - int argc, - const char** argv, - AliHLTComponentHandle* handle, - const char* description); - - /** create/factorize component - * @param handle - * @return 0 on success - */ - int destroyComponent(AliHLTComponentHandle handle); - - /** process event - */ - int processEvent(AliHLTComponentHandle handle, - const AliHLTComponentEventData* evtData, const AliHLTComponentBlockData* blocks, - AliHLTComponentTriggerData* trigData, - AliHLTUInt8_t* outputPtr, AliHLTUInt32_t* size, - AliHLTUInt32_t* outputBlockCnt, AliHLTComponentBlockData** outputBlocks, - AliHLTComponentEventDoneData** edd); - - /** get the output data type - */ - int getOutputDataType(AliHLTComponentHandle handle, AliHLTComponentDataType* dataType); - - /** get output data size - * return an estimation of the size of the produced data relative to the number of - * input blocks and input size - */ - int getOutputSize(AliHLTComponentHandle handle, unsigned long* constEventBase, - unsigned long* constBlockBase, double* inputBlockMultiplier); - - /// clear the object and reset pointer references - virtual void clear(const char* /*option*/ = ""); - - /// print info - virtual void print(const char* option = "") const; - - /// allocate memory - static void* alloc(void* param, unsigned long size); - - /// deallocate memory - static void dealloc(void* buffer, unsigned long size); - - protected: - private: - AliHLTExtFctInitSystem mpAliHLTExtFctInitSystem; - AliHLTExtFctDeinitSystem mpAliHLTExtFctDeinitSystem; - AliHLTExtFctLoadLibrary mpAliHLTExtFctLoadLibrary; - AliHLTExtFctUnloadLibrary mpAliHLTExtFctUnloadLibrary; - AliHLTExtFctCreateComponent mpAliHLTExtFctCreateComponent; - AliHLTExtFctDestroyComponent mpAliHLTExtFctDestroyComponent; - AliHLTExtFctProcessEvent mpAliHLTExtFctProcessEvent; - AliHLTExtFctGetOutputDataType mpAliHLTExtFctGetOutputDataType; - AliHLTExtFctGetOutputSize mpAliHLTExtFctGetOutputSize; - - AliHLTAnalysisEnvironment mEnvironment; -}; - -} // namespace alice_hlt -} // namespace o2 -#endif // SYSTEMINTERFACE_H diff --git a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/WrapperDevice.h b/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/WrapperDevice.h deleted file mode 100644 index 1b7c138891e2c..0000000000000 --- a/Utilities/aliceHLTwrapper/include/aliceHLTwrapper/WrapperDevice.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef WRAPPERDEVICE_H -#define WRAPPERDEVICE_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file WrapperDevice.h -// @author Matthias Richter -// @since 2014-05-08 -// @brief FairRoot/ALFA device running ALICE HLT code - -#include <FairMQDevice.h> -#include <vector> -#include <boost/program_options.hpp> - -namespace bpo = boost::program_options; - -class FairMQMessage; - -namespace o2 -{ -namespace alice_hlt -{ -class Component; - -/// @class WrapperDevice -/// A FairMQ device class supporting the HLT component interface -/// for processing. -/// -/// The device class implements the interface functions of FairMQ, and it -/// receives and send messages. The data of the messages are processed -/// using the Component class. -class WrapperDevice : public FairMQDevice -{ - public: - /// default constructor - WrapperDevice(int verbosity = 0); - /// destructor - ~WrapperDevice() override; - - /// get description of options - static bpo::options_description GetOptionsDescription(); - - enum /*class*/ OptionKeyIds /*: int*/ { - OptionKeyPollPeriod = 0, - OptionKeyDryRun, - OptionKeyLast - }; - - constexpr static const char* OptionKeys[] = { - "poll-period", - "dry-run", - nullptr}; - - ///////////////////////////////////////////////////////////////// - // the FairMQDevice interface - - /// inherited from FairMQDevice - void InitTask() override; - /// inherited from FairMQDevice - void Run() override; - - protected: - private: - // copy constructor prohibited - WrapperDevice(const WrapperDevice&); - // assignment operator prohibited - WrapperDevice& operator=(const WrapperDevice&); - - /// create a new message with data buffer of specified size - unsigned char* createMessageBuffer(unsigned size); - - Component* mComponent; // component instance - std::vector<FairMQMessagePtr> mMessages; // array of output messages - - int mPollingPeriod; // period of polling on input sockets in ms - int mSkipProcessing; // skip component processing - int mLastCalcTime; // start time of current statistic period - int mLastSampleTime; // time of last data sample - int mMinTimeBetweenSample; // min time between data samples in statistic period - int mMaxTimeBetweenSample; // max time between data samples in statistic period - int mTotalReadCycles; // tot number of read cycles in statistic period - int mMaxReadCycles; // max number of read cycles in statistic period - int mNSamples; // number of samples in statistic period - int mVerbosity; // verbosity level -}; - -} // namespace alice_hlt -} // namespace o2 -#endif // WRAPPERDEVICE_H diff --git a/Utilities/aliceHLTwrapper/launch-flp-epn.sh b/Utilities/aliceHLTwrapper/launch-flp-epn.sh deleted file mode 100755 index 3fa2bd3948530..0000000000000 --- a/Utilities/aliceHLTwrapper/launch-flp-epn.sh +++ /dev/null @@ -1,274 +0,0 @@ -#! /bin/bash - -#**************************************************************************** -#* This file is free software: you can redistribute it and/or modify * -#* it under the terms of the GNU General Public License as published by * -#* the Free Software Foundation, either version 3 of the License, or * -#* (at your option) any later version. * -#* * -#* Primary Authors: Matthias Richter <Matthias.Richter@scieq.net> * -#* * -#* The authors make no claims about the suitability of this software for * -#* any purpose. It is provided "as is" without express or implied warranty. * -#**************************************************************************** - -# @file launch-flp-epn.sh -# @author Matthias Richter -# @since 2015-01-14 -# @brief Launch script for a FLP to EPN data distribution topology - - -################################################################### -# global settings -number_of_flps=2 -flp_command_socket=48490 -epn_ack_socket=48491 -baseport_on_flpgroup=48420 -baseport_on_epngroup=48480 -number_of_epns=2 -number_of_epns_per_node=2 -rundir=`pwd` - -################################################################### -# argument scan -# TODO: implement real argument scan and more configurable options -while [ "x$1" != "x" ]; do - if [ "x$1" == "x--print-commands" ]; then - printcmdtoscreen='echo' - elif [ "x$1" == "x--non-blocking-output" ] ; then - # use method 'pub' for non-blocking EPN output - outputmethod=pub - shift - else - echo unknown option $1 - exit - fi - shift -done - -################################################################### -######## end of configuration area ############ -######## no changes beyond this point ############ -################################################################### - -################################################################### -# fill the list of nodes -# -# for every FLP group there needs to be an entry in the node list -# nodes can be specified multiple times -flpnodelist= -flpnodelist=(${flpnodelist[@]} localhost) -flpnodelist=(${flpnodelist[@]} localhost) - -epnnodelist= -epnnodelist=(${epnnodelist[@]} 127.0.0.1) - -nflpnodes=${#flpnodelist[@]} -nepnnodes=${#epnnodelist[@]} - -################################################################### -# init the variables for the session commands -flpsessionnode= -flpinputsocket= -flpsessiontitle= -flpsessioncmd= -nflpsessions=0 - -epnsessionnode= -epninputsocket= -epnoutputsocket= -epnsessiontitle= -epnsessioncmd= -nepnsessions=0 - -# the same node name can be specified for multiple FLP groups -# this map holds a count of groups per node while adding the groups -declare -A flpgroupsPerNode - -################################################################### - -################################################################### -# create an flp node group -create_flpgroup() { - node=$1 - basesocket=$2 - - deviceid="FLP_$node${3:+_${3}}" - command="flpSender" - command+=" --id $deviceid" - command+=" --control static" - command+=" --flp-index 0" - command+=" --num-epns $nepnsessions" - command+=" --send-offset $((1+3*$nflpsessions))" - command+=" " - command+=" --in-chan-name data-in" - flpinputsocket[nflpsessions]=$((basesocket + 0)) - command+=" --channel-config name=data-in,type=pull,size=5000,method=bind,address=tcp://*:${flpinputsocket[$nflpsessions]},rateLogging=1" # data input - command+=" --out-chan-name data-out" - for ((j=0; j<$nepnsessions; j++)); - do - command+=" --channel-config name=data-out,type=push,size=5000,method=connect,address=tcp://${epnsessionnode[$j]}:${epninputsocket[$j]},rateLogging=1" - done - - flpsessionnode[nflpsessions]=$node - flpsessiontitle[nflpsessions]=$deviceid - flpsessioncmd[nflpsessions]=$command - let nflpsessions++ -} - -################################################################### -# create an epn node group -create_epngroup() { - node=$1 - basesocket=$2 - - for ((nepn=0; nepn<$number_of_epns_per_node; nepn++)); do - deviceid=EPN_`printf %02d $nepnsessions` - command="epnReceiver" - command+=" --id $deviceid" - command+=" --control static" - command+=" --num-flps $number_of_flps" - epninputsocket[nepnsessions]=$((2*nepn + basesocket)) - command+=" --in-chan-name data-in" - command+=" --out-chan-name data-out" - command+=" --channel-config name=data-in,type=pull,size=5000,method=bind,address=tcp://$node:${epninputsocket[$nepnsessions]},rateLogging=1" # data input - command+=" --channel-config name=ack,type=pub,method=connect,address=tcp://localhost:$epn_ack_socket,rateLogging=1" # data input - epnoutputsocket[nepnsessions]=$((2*nepn + basesocket +1)) - command+=" --channel-config name=data-out,type=${outputmethod:=push},size=5000,method=bind,address=tcp://*:${epnoutputsocket[$nepnsessions]},rateLogging=1" # data output - - epnsessionnode[nepnsessions]=$node - epnsessiontitle[nepnsessions]="$deviceid" - epnsessioncmd[nepnsessions]=$command - let nepnsessions++ - done -} - -########### main script ########################################### -# -# build the commands on the nodes -# epn nodegroups -error=0 -inode=0 -while [ "$nepnsessions" -lt "$number_of_epns" ]; do - if [ "$inode" -ge "$nepnnodes" ]; then - echo "error: too few nodes to create all epn devices" - error=1 - break - fi - create_epngroup ${epnnodelist[$inode]} $baseport_on_epngroup - - let inode++ -done - -inode=0 -while [ "$nflpsessions" -lt "$number_of_flps" ]; do - if [ "$inode" -ge "$nflpnodes" ]; then - echo "error: too few nodes to create all flp devices" - error=1 - break - fi - key=${flpnodelist[$inode]} - # keep record of the count of FLP groups on a node in a dedicated map and - # calculate the input port based on that. There is only one input socket - # per FLP group, multiple devices can connect to the same socket - create_flpgroup ${flpnodelist[$inode]} $(( baseport_on_flpgroup + ${flpgroupsPerNode[$key]:=0} )) ${flpgroupsPerNode[$key]:=0} - flpgroupsPerNode[$key]=$(( flpgroupsPerNode[$key] + 1 )) - - let inode++ -done - -if [ "$error" -gt 0 ]; then - exit -fi - -sessionmap= -for ((isession=$nflpsessions++-1; isession>=0; isession--)); do - sessionmap[isession]=1 -done -havesessions=1 - -applications= -while [ "$havesessions" -gt 0 ]; do -havesessions=0 -lastnode= -for ((isession=$nflpsessions++-1; isession>=0; isession--)); do - if [ "${sessionmap[isession]}" -eq 1 ]; then - echo "FLP_DEVICE_IN=${flpsessionnode[$isession]}:${flpinputsocket[$isession]}" - if [ "x$printcmdtoscreen" == "x" ]; then - echo "scheduling ${flpsessiontitle[$isession]} on ${flpsessionnode[$isession]}: ${flpsessioncmd[$isession]}" - echo - fi - applications+=" "`echo ${flpsessioncmd[$isession]} | sed -e 's| .*$||'` - fi - - if [ "${sessionmap[isession]}" -gt 0 ]; then - #echo $isession: ${sessionmap[isession]} $lastnode - if [ "x$lastnode" == "x${flpsessionnode[$isession]}" ] && [ "${sessionmap[$isession]}" -lt 10 ]; then - let sessionmap[isession]++ - let havesessions++ - else - if [ "x$lastnode" == "x${flpsessionnode[$isession]}" ]; then - # sleep between starts, some of the screens are not started if the frequency is too high - usleep 500000 - fi - - logcmd=" 2>&1 | tee ${flpsessiontitle[$isession]}.log" - $printcmdtoscreen screen -d -m -S "${flpsessiontitle[$isession]} on ${flpsessionnode[$isession]}" ssh ${flpsessionnode[$isession]} "cd $rundir && source setup.sh && ${flpsessioncmd[$isession]} $logcmd" & - sessionmap[isession]=0 - lastnode=${flpsessionnode[$isession]} - fi - fi -done -done - -for ((isession=$nepnsessions++-1; isession>=0; isession--)); do - sessionmap[isession]=1 -done -havesessions=1 - -while [ "$havesessions" -gt 0 ]; do -havesessions=0 -lastnode= -for ((isession=$nepnsessions++-1; isession>=0; isession--)); do - if [ "${sessionmap[isession]}" -eq 1 ]; then - echo "EPN_DEVICE_OUT=${epnsessionnode[$isession]}:${epnoutputsocket[$isession]}" - if [ "x$printcmdtoscreen" == "x" ]; then - echo "scheduling ${epnsessiontitle[$isession]} on ${epnsessionnode[$isession]}: ${epnsessioncmd[$isession]}" - echo - fi - applications+=" "`echo ${epnsessioncmd[$isession]} | sed -e 's| .*$||'` - fi - - if [ "${sessionmap[isession]}" -gt 0 ]; then - #echo $isession: ${sessionmap[isession]} $lastnode - if [ "x$lastnode" == "x${epnsessionnode[$isession]}" ] && [ "${sessionmap[$isession]}" -lt 10 ]; then - let sessionmap[isession]++ - let havesessions++ - else - if [ "x$lastnode" == "x${epnsessionnode[$isession]}" ]; then - # sleep between starts, some of the screens are not started if the frequency is too high - usleep 500000 - fi - logcmd=" 2>&1 | tee ${epnsessiontitle[$isession]}.log" - $printcmdtoscreen screen -d -m -S "${epnsessiontitle[$isession]} on ${epnsessionnode[$isession]}" ssh ${epnsessionnode[$isession]} "cd $rundir && source setup.sh && ${epnsessioncmd[$isession]} $logcmd" & - sessionmap[isession]=0 - lastnode=${epnsessionnode[$isession]} - fi - fi -done -done - -if [ "x$printcmdtoscreen" == "x" ]; then -usednodes=`for n in ${flpsessionnode[@]} ${epnsessionnode[@]}; do echo $n; done | sort | uniq` -echo -echo "started FLP-EPN topology in $((nflpsessions + nepnsessions)) session(s) on `echo $usednodes | wc -w` node(s):" -usednodes=`echo $usednodes | sed ':a;N;$!ba;s/\n/ /g'` -echo $usednodes - -applications=`for app in $applications; do echo $app; done | sort | uniq` -echo -echo "a simple method to stop the devices:" -for app in $applications; do - echo "for node in $usednodes; do ssh \$node killall $app; done" -done -fi diff --git a/Utilities/aliceHLTwrapper/launchSimpleChain.sh b/Utilities/aliceHLTwrapper/launchSimpleChain.sh deleted file mode 100755 index 5c7c979cc2cfb..0000000000000 --- a/Utilities/aliceHLTwrapper/launchSimpleChain.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -# very simple helper script to create the commands for starting several processes -# in multiple screen sessions - -minSlice=0 -maxSlice=0 -minPart=0 -maxPart=5 -runNo=167808 -msgSize=1000 - -firstSocketNo=45000 -let socketNo=firstSocketNo -trackerInputSockets= - -exit_with_message () { - echo $1 - exit -} - -start_device () { - echo "starting $1 for specification $spec in screen \"$sessiontitle\"" - # Note: there seems to be a limit how many characters are sent to the - # screen with the -X option. Both environment and channel configuration - # are thus split into multiple commands - - # start the screen session - screen -S "$sessiontitle" -t 0 -A -d -m - # change to the directory - screen -S "$sessiontitle" -p 0 -X stuff $"cd ${PWD}\n" - # propagate the environment to the screen window - env | sed -e '/^[A-Z].*=/!d' | while read line ; do variable=${line/=*/}; screen -S "$sessiontitle" -p 0 -X stuff $"unset ${variable}\n"; unset delimiter; echo ${line/${variable}=/} | tr ':' '\n' | while read token ; do screen -S "$sessiontitle" -p 0 -X stuff $"export ${variable}${delimiter/:/+}=\"$delimiter${token}\"\n"; delimiter=':'; done; done - # start the device - echo $command $channels $parameters - screen -S "$sessiontitle" -p 0 -X stuff $"${command} " - screen -S "$sessiontitle" -p 0 -X stuff $"${channels} " - #echo $channels | tr ' ' '\n' | while read channelconfig; do screen -S "$sessiontitle" -p 0 -X stuff $"${channelconfig} "; done - screen -S "$sessiontitle" -p 0 -X stuff $"${parameters}\n" - screen -S "$sessiontitle" -p 0 -X stuff $"\n" -} - - -WrapperDeviceApplication=o2-alicehlt-wrapper-device - -# check whether the required executables are available -which screen > /dev/null 2>&1 || exit_with_message "This script requires the 'screen' command to be installed" -which $WrapperDeviceApplication > /dev/null 2>&1 || exit_with_message "Can not find the $WrapperDeviceApplication executable" - -for ((slice=minSlice; slice<=maxSlice; slice++)); do - for ((part=minPart; part<=maxPart; part++)); do - spec=`printf 0x%02x%02x%02x%02x $slice $slice $part $part` - command="$WrapperDeviceApplication --id=ClusterPublisher_$spec --channel-config name=data-out,type=push,method=bind,address=tcp://*:$socketNo --library libAliHLTUtil.so --component FilePublisher --run 167808 --parameter '-datafilelist emulated-tpc-clusters_$spec.txt'" - sessiontitle="ClusterPublisher_$spec" - start_device ClusterPublisher - trackerInputSockets+="${trackerInputSockets:+ }$socketNo" - let socketNo++ - done -done - -command="$WrapperDeviceApplication --id=Tracker" -parameters="--library libAliHLTTPC.so --component TPCCATracker --run $runNo --parameter '-GlobalTracking'" -unset channels -for socket in $trackerInputSockets; do - channels+="${channels:+ }--channel-config name=data-in,type=pull,method=connect,address=tcp://localhost:$socket" -done -spec=`printf 0x%02x%02x%02x%02x $maxSlice $minSlice $maxPart $minPart` -sessiontitle="Tracker" -start_device Tracker - -echo -screen -ls diff --git a/Utilities/aliceHLTwrapper/macros/hltConfigurations.C_backup b/Utilities/aliceHLTwrapper/macros/hltConfigurations.C_backup deleted file mode 100644 index 1e492ea4e9e84..0000000000000 --- a/Utilities/aliceHLTwrapper/macros/hltConfigurations.C_backup +++ /dev/null @@ -1,114 +0,0 @@ -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file hltConfigurations.C -// @author Matthias Richter -// @since 2014-05-20 -// @brief Various helper configurations for the ALICE HLT - -/** - * Usage: aliroot -b -q -l \ - * hltConfigurations.C \ - * recraw-local.C'("file", "cdb", minEvent, maxEvent, modules)' - * - * Macro defines the following configurations: - * - cluster-collection: emulation of TPC HLT clusters from TPC raw data - */ -void hltConfigurations() -{ - // init the HLT system - AliHLTSystem* pHLT=AliHLTPluginBase::GetInstance(); - - /////////////////////////////////////////////////////////////////////////////////////////// - // - // list of configurations - // - /////////////////////////////////////////////////////////////////////////////////////////// - int iMinSlice=0; - int iMaxSlice=35; - int iMinPart=0; - int iMaxPart=5; - - TString collectionInput; - for (int slice=iMinSlice; slice<=iMaxSlice; slice++) { - for (int part=iMinPart; part<=iMaxPart; part++) { - TString arg; - TString filterid; - filterid.Form("TPC-CLFilter_%02d_%d", slice, part); - arg.Form("-dataspec 0x%02x%02x%02x%02x", slice, slice, part, part); - AliHLTConfiguration clusterfilter(filterid.Data(), "BlockFilter","TPC-ClusterTransformation", arg.Data()); - - TString cid; - cid.Form("TPC-CLWriter_%02d_%d", slice, part); - arg=("-directory emulated-tpc-clusters -subdir -specfmt=_0x%08x -blocknofmt="); - arg+=Form(" -publisher-conf emulated-tpc-clusters_0x%02x%02x%02x%02x.txt", slice, slice, part, part); - AliHLTConfiguration clusterwriter(cid.Data(), "FileWriter", filterid.Data(), arg.Data()); - - if (collectionInput.Length()>0) collectionInput+=" "; - collectionInput+=cid; - } - } - AliHLTConfiguration clustercollection("cluster-collection", "BlockFilter", collectionInput.Data(), ""); - - TString arg; - TString publisher; - - arg.Form("-publish-raw filtered"); - AliHLTConfiguration tpcdatapublisherconf("TPC-DP", "TPCDataPublisher", NULL , arg.Data()); - - publisher.Form("TPC-DP-raw", slice, part); - arg.Form("-datatype 'DDL_RAW ' 'TPC '"); - AliHLTConfiguration tpcdatarawfilterconf(publisher.Data(), "BlockFilter", "TPC-DP" , arg.Data()); - - // Hardware CF emulator - TString hwcfemu; - hwcfemu.Form("TPC-HWCFEmu"); - arg=""; - AliHLTConfiguration tpchwcfemuconf(hwcfemu.Data(), "TPCHWClusterFinderEmulator", publisher.Data(), arg.Data()); - - TString hwcf; - hwcf.Form("TPC-HWCF"); - AliHLTConfiguration hwcfemuconf(hwcf.Data(), "TPCHWClusterTransform", hwcfemu.Data(), "-publish-raw"); - - TString hwcfDecoder = "TPC-HWCFDecoder"; - AliHLTConfiguration hwcfdecoderconf(hwcfDecoder.Data(), "TPCHWClusterDecoder",hwcfemu.Data(), ""); - - TString clusterTransformation = "TPC-ClusterTransformation"; - AliHLTConfiguration clustertransformationconf(clusterTransformation.Data(), "TPCClusterTransformation",hwcfDecoder.Data(), ""); - - AliHLTConfiguration clusterpubconf("cluster-publisher", "FilePublisher", "", "-datafilelist cluster-input.txt"); - - TString trackerID; - trackerID.Form("TPC-TR"); - TString trackerInput; - //trackerInput=clusterTransformation; - trackerInput="cluster-publisher"; - AliHLTConfiguration trackerconf(trackerID.Data(), "TPCCATracker", trackerInput.Data(), "-ExampleModule2 -allowGPU -GPUHelperThreads 4"); - - AliHLTConfiguration globalmergerconf("TPC-globalmerger","TPCCAGlobalMerger",trackerID.Data(),""); - - TString input; - input+=" "; input+=clusterTransformation; - input+=" "; input+=hwcfDecoder; - //input+=" TPC-globalmerger"; - arg="-directory clusters-from-raw -subdir -specfmt=_0x%08x -blocknofmt= -write-all-blocks -write-all-events"; - arg+=Form(" -publisher-conf emulated-tpc-clusters.txt"); - AliHLTConfiguration clustertransformwriterconf("TPC-ClusterWriter", "FileWriter", input.Data(), arg.Data()); - - arg="-directory output-tracks -subdir -specfmt=_0x%08x -blocknofmt= -write-all-blocks -write-all-events"; - arg+=Form(" -publisher-conf output-tracks.txt"); - AliHLTConfiguration trackwriterconf("TPC-TrackWriter", "FileWriter", "TPC-globalmerger", arg.Data()); - - arg.Form("-disable-component-stat -publish 0 -file ClusterRawStatistics.root"); - AliHLTConfiguration collector("collector", "StatisticsCollector", "TPC-ClusterWriter", arg.Data()); - -} diff --git a/Utilities/aliceHLTwrapper/macros/overlayClusters.C_backup b/Utilities/aliceHLTwrapper/macros/overlayClusters.C_backup deleted file mode 100644 index 05916311834ac..0000000000000 --- a/Utilities/aliceHLTwrapper/macros/overlayClusters.C_backup +++ /dev/null @@ -1,253 +0,0 @@ -/// @file overlayClusters.C -/// @author Matthias.Richter@scieq.net -/// @date 2015-03-02 -/// @brief Merge clusters from multiple events into one single data sample -/// -/// Usage: -/// (echo -o target_file_path ; ls path_to_source_files) \ -/// | root -b -q -l overlayClusters.C -/// -/// for performance reasons, the macro is compiled into a temporary library -/// and the compiled function is called. All options are read from standard -/// input. Empty lines break the argument scan. -/// -/// Options: -/// -o target_file_path path to target file -/// -v verbose mode -/// -q quiet mode -/// path_to_source_file path to source file, multiple occurrence -/// -/// All options need to be separated by newline, and can be created via -/// echo commands. Multiple input file names can be listed using ls with -/// wildcard expansion. - -// Note: when using new classes the corresponding include files need to be -// add in the include section -#if defined(__CLING__) && !defined(__MAKECLING__) -{ - gSystem->AddIncludePath("-I$ROOTSYS/include -I$ALICE_ROOT/include"); - TString macroname=gInterpreter->GetCurrentMacroName(); - macroname+="+"; - gROOT->LoadMacro(macroname); - overlayClusters(); -} -#else - -#include "AliHLTDataTypes.h" -#include "AliHLTTPCSpacePointContainer.h" -#include "AliHLTTPCClusterDataFormat.h" -#include "AliHLTTPCSpacePointData.h" - -#include <vector> -#include <cstdlib> -#include <iostream> -#include <iomanip> -#include <memory> -#include <fstream> -#include <ostream> - -typedef unsigned char byte; - -vector<std::string> inputFileNames; -std::string outputFileName=""; -float zShift=20.; -int verbosity=1; - -int scanArguments(); -bool checkConsistency(const byte* data, unsigned size); -int shiftClusters(AliHLTTPCSpacePointData* array, unsigned size, float zshift); -int readData(std::string fileName, std::vector<o2::byte>& buffer); -int writeData(std::string fileName, std::vector<o2::byte>& buffer); -int writeData(std::vector<o2::byte>& buffer, std::ostream& os=std::cout); -void printHelp(); - -void overlayClusters() -{ - // main function - scanArguments(); - if (inputFileNames.size()==0) { - printHelp(); - return; - } - unsigned addedClCount=0; - vector<o2::byte> buffer; - vector<std::string>::const_iterator fileName=inputFileNames.begin(); - if (readData(*fileName, buffer)<0) { - std::cerr << "Error: no usable data in file " << *fileName << ", aborting ..." << endl; - return; - } - if (!checkConsistency(&buffer[0], buffer.size())) { - std::cerr << "Error: inconsistent cluster data block in file " << *fileName << ", aborting ..." << endl; - return; - } - unsigned fileCount=1; - for (; ++fileName!=inputFileNames.end(); fileCount++) { - unsigned offset=buffer.size(); - if (readData(*fileName, buffer)<0) { - std::cerr << "Error: no usable data in file " << *fileName << ", aborting ..." << endl; - return; - } - if (!checkConsistency(&buffer[offset], buffer.size()-offset)) { - std::cerr << "Error: inconsistent cluster data block in file " << *fileName << ", aborting ..." << endl; - return; - } - unsigned clcount=0; - unsigned clsize=0; - { // scope for the blockheader, eventually invalid after buffer resize - AliHLTTPCClusterData* blockheader=reinterpret_cast<AliHLTTPCClusterData*>(&buffer[offset]); - clcount=blockheader->fSpacePointCnt; - clsize=clcount*sizeof(AliHLTTPCSpacePointData); - - if (verbosity>1) std::cout << "adding " << clcount << " cluster(s) of total size " << clsize << " to buffer of size " << offset << endl; - // remove the include of the current block and append its clusters to the main block - memmove(&buffer[offset], &buffer[offset+sizeof(AliHLTTPCClusterData)], clsize); - } - buffer.resize(offset+clsize); - addedClCount+=clcount; - - // shift the clusters of the current block - shiftClusters(reinterpret_cast<AliHLTTPCSpacePointData*>(&buffer[offset]), clcount, fileCount*zShift); - if (verbosity>1) std::cout << "buffer size: " << buffer.size() << endl; - } - AliHLTTPCClusterData* header=reinterpret_cast<AliHLTTPCClusterData*>(&buffer[0]); - header->fSpacePointCnt+=addedClCount; - - if (verbosity>1) std::cout << "Merged " << header->fSpacePointCnt << " cluster(s) from " << fileCount << " file(s) to " << outputFileName << endl; - writeData(outputFileName, buffer); - - return; -} - -int scanArguments() -{ - // read commands from the std input - std::string line; - char c=0; - std::cout << "Reading parameters from std input ... (terminate with empty line)" << endl; - while (cin.get(c)) { - while (c==' ' && cin.get(c)) /* nop */; - if (c=='\n') { // break on empty line - inputFileNames.clear(); - break; - } else if (c=='-') { - if (!cin.get(c) || c=='\n') { - std::cerr << "incomplete option token" << endl; - inputFileNames.clear(); - break; - } - char arg=0; - while (cin.get(arg) && arg==' ') /* nop */; - cin.putback(arg); - std::getline(std::cin, line); - if (c=='o') { - outputFileName=line; - } else if (c='v') { - verbosity=2; - } else if (c='q') { - verbosity=0; - } else { - std::cerr << "unknown option '" << c << "'" << endl; - inputFileNames.clear(); - break; - } - continue; - } - cin.putback(c); - std::getline(std::cin, line); - inputFileNames.push_back(line); - } - return inputFileNames.size(); -} - -bool checkConsistency(const byte* data, unsigned size) -{ - // check the format of the data block - // binary block contains AliHLTTPCClusterData include followed by - // array of AliHLTTPCSpacePointData - if (size<sizeof(AliHLTTPCClusterData)) return false; - const AliHLTTPCClusterData* cld=reinterpret_cast<const AliHLTTPCClusterData*>(data); - if (cld->fSpacePointCnt*sizeof(AliHLTTPCSpacePointData)+sizeof(AliHLTTPCClusterData)!=size) return false; - return true; -} - -int shiftClusters(AliHLTTPCSpacePointData* array, unsigned count, float zshift) -{ - // shift the z coordinate of all the clusters - for (AliHLTTPCSpacePointData* cl=array; cl<array+count; cl++) { - float z=cl->GetZ(); - if (z>=0) z+=zshift; - else z-=zshift; - cl->SetZ(z); - } - return count; -} - -int readData(std::string fileName, std::vector<o2::byte>& buffer) -{ - // read file content as binary block to the end of the buffer - std::ifstream inputFile(fileName.c_str(), std::ifstream::binary); - if (!inputFile) { - std::cerr << "Error: failed to open file " << fileName << endl; - return -1; - } - - inputFile.seekg(0, inputFile.end); - int len = inputFile.tellg(); - inputFile.seekg(0, inputFile.beg); - - unsigned offset=buffer.size(); - buffer.resize(offset+len); - inputFile.read((char*)&buffer[offset], len); - if (!inputFile) { - std:cerr << "Error: failed to read from file " << fileName << " - only " << inputFile.gcount() << " of " << len << std::endl; - return -1; - } - inputFile.close(); - return len; -} - -int writeData(std::string fileName, std::vector<o2::byte>& buffer) -{ - // write buffer to file - std::ifstream inputFile(fileName.c_str(), std::ifstream::binary); - if (inputFile) { - std::cerr << "Error: refusing to overwrite existing output file " << fileName << endl; - inputFile.close(); - return -1; - } - std::ofstream outputFile(fileName.c_str(), std::ifstream::binary); - if (!outputFile) { - std::cerr << "Error: failed to open output file " << fileName << endl; - return -1; - } - - int result=writeData(buffer, outputFile); - outputFile.close(); - return result; -} - -int writeData(std::vector<o2::byte>& buffer, std::ostream& os) -{ - // write buffer to stream - os.write((char*)&buffer[0], buffer.size()); - if (!os) return -1; - return buffer.size(); -} - -void printHelp() -{ - // print help instructions - std::cerr << "overlayClusters.C" << endl; - std::cerr << "Usage: " << endl; - std::cerr << " (echo -o target_file_path ; ls path_to_source_files) \\ " << endl; - std::cerr << " | root -b -q -l overlayClusters.C" << endl << endl; - std::cerr << " Options:" << endl; - std::cerr << " -o target_file_path path to target file" << endl; - std::cerr << " -v verbose mode" << endl; - std::cerr << " path_to_source_file path to source file, multiple occurrence" << endl << endl; - std::cerr << " All options need to be separated by newline, and can be created via" << endl; - std::cerr << " echo commands. Multiple input file names can be listed using ls with" << endl; - std::cerr << " wildcard expansion." << endl; -} - -#endif diff --git a/Utilities/aliceHLTwrapper/macros/overlayClusters.sh b/Utilities/aliceHLTwrapper/macros/overlayClusters.sh deleted file mode 100755 index 64bf7096a9f82..0000000000000 --- a/Utilities/aliceHLTwrapper/macros/overlayClusters.sh +++ /dev/null @@ -1,93 +0,0 @@ -#! /bin/bash - -printHelp=0 -merge_nEvents=0 -targetdir= -nOutput=0 -outputBaseName=event - -scriptname=`basename $0` -scriptdir=`dirname $0` -macroname=overlayClusters.C -macropath=$scriptdir/$macroname - -if ! test -e "$macropath" ; then -cat<<EOF - -Error can not find macro '$macropath'; has to be in the same folder as script - -EOF - printHelp=1 - -else - [ "$#" -ge 1 ] && merge_nEvents=$1 - shift - [ "$#" -ge 1 ] && targetdir=$1 - shift - [ "$#" -ge 1 ] && outputBaseName=$1 - shift - [ "$merge_nEvents" -eq 0 ] && printHelp=1 -fi - - -if [ "$printHelp" -gt 0 ]; then -cat<<EOF -$scriptname: merge TPC cluster data files with help of root macro $macroname -Usage: - ls path_to_event_folder | $scriptname count targetdir basename - - count number of files to merge - targetdir target directory [optional] - basename basename of folders for merged data samples [optional] - -The input event folders are read from standard input. - -A working aliroot setup is required in order to start root and load the required -AliRoot libraries. - -Current script/macro path: - $scriptdir -EOF -exit -fi - -c=0 -unset inputeventlist -while read inputevent; do - inputeventlist=(${inputeventlist[@]} $inputevent) - if [ "$c" -ge $(( merge_nEvents - 1 )) ]; then - outputevent=`echo $targetdir | sed -e 's|\([^/]\)$|\1/|'`$outputBaseName`printf %03d $nOutput` - echo merging ... - for f in ${inputeventlist[@]}; do echo " $f"; done - echo " -> $outputevent" - - mkdir -p $outputevent || break - # for each event to be generated loop over all slices and partitions - # and merge the files with corresponding specification - for ((slice=0; slice<36; slice++)); do - for ((part=0; part<6; part++)); do - # the data specification of HLT TPC data blocks describes ranges of - # from-to slices/partitions in the corresponding bitfields of the 32bit specification - spec=`printf 0x%02x%02x%02x%02x $slice $slice $part $part` - echo "$outputevent: processing slice $slice partition $part (data specification $spec)" - for inputpath in `ls ${inputeventlist[0]}/*$spec* | sed -e '/CLUSTERS/!d'`; do - filename=`basename $inputpath` - outputfile=$outputevent/$filename - if test -e $outputfile ; then - echo "file $outputfile existing, skipping ..." - continue - fi - echo ${inputeventlist[@]} > $outputevent/filelist.txt - (echo "-o $outputevent/$filename"; for ev in ${inputeventlist[@]}; do echo "$ev/$filename"; done) \ - | root -b -q -l $macropath - done - done - done - - let nOutput++ - c=0 - unset inputeventlist - else - let c++ - fi -done diff --git a/Utilities/aliceHLTwrapper/macros/runHLT.C_backup b/Utilities/aliceHLTwrapper/macros/runHLT.C_backup deleted file mode 100644 index b84e1b304d160..0000000000000 --- a/Utilities/aliceHLTwrapper/macros/runHLT.C_backup +++ /dev/null @@ -1,29 +0,0 @@ -const char* defaultCDBUri="local://./OCDB"; -void runHLT(const char* chain, int events=1, int runno=-1, const char* cdbURI=defaultCDBUri) -{ - // setup the OCDB access - // required to load the GRP entry in order to initialize the magnetic field - if (runno>=0) { - AliCDBManager::Instance()->SetDefaultStorage(cdbURI); - AliCDBManager::Instance()->SetRun(runno); - AliGRPManager grpman; - grpman.ReadGRPEntry(); - grpman.SetMagField(); - } - - // init the HLT system - AliHLTSystem* pHLT=AliHLTPluginBase::GetInstance(); - - /////////////////////////////////////////////////////////////////////////////////////////// - // - // list of configurations - // - /////////////////////////////////////////////////////////////////////////////////////////// - - if (chain) { - pHLT->ScanOptions("loglevel=0x7c"); - //pHLT->ScanOptions("loglevel=0x7f frameworklog=0x7f"); - pHLT->BuildTaskList(chain); - pHLT->Run(events); - } -} diff --git a/Utilities/aliceHLTwrapper/nodelist.sh b/Utilities/aliceHLTwrapper/nodelist.sh deleted file mode 100644 index bafeb3fbee487..0000000000000 --- a/Utilities/aliceHLTwrapper/nodelist.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -# this script defines the nodelist as a subsidiary to AliceO2 -# launch scripts - -############## example ############################## -nodelist= -nodelist=(${nodelist[@]} localhost) -#nodelist=(${nodelist[@]} someothernode) - diff --git a/Utilities/aliceHLTwrapper/src/Component.cxx b/Utilities/aliceHLTwrapper/src/Component.cxx deleted file mode 100644 index 115faa1b3f765..0000000000000 --- a/Utilities/aliceHLTwrapper/src/Component.cxx +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file Component.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief A component running ALICE HLT code - -#include "aliceHLTwrapper/Component.h" -#include "aliceHLTwrapper/AliHLTDataTypes.h" -#include "aliceHLTwrapper/SystemInterface.h" -#include "FairMQLogger.h" - -#include <cstdlib> -#include <cerrno> -#include <cstring> -#include <sstream> -#include <iostream> -#include <sstream> -#include <getopt.h> -#include <memory> - -using namespace o2::alice_hlt; - -using std::endl; -using std::string; -using std::unique_ptr; -using std::vector; -using std::stringstream; - -Component::Component() - : mOutputBuffer() - , mpSystem(nullptr) - , mProcessor(kEmptyHLTComponentHandle) - , mFormatHandler() - , mEventCount(-1) -{ -} - -Component::~Component() -= default; - -constexpr const char* Component::OptionKeys[]; - -bpo::options_description Component::GetOptionsDescription() -{ - // clang-format off - bpo::options_description od("HLT Component options"); - od.add_options() - ((std::string(OptionKeys[OptionKeyLibrary]) + ",l").c_str(), - bpo::value<string>()->required(), - "component library") - ((std::string(OptionKeys[OptionKeyComponent]) + ",c").c_str(), - bpo::value<string>()->required(), - "component id") - ((std::string(OptionKeys[OptionKeyParameter]) + ",p").c_str(), - bpo::value<string>()->default_value(""), - "component command line parameter") - ((std::string(OptionKeys[OptionKeyRun]) + ",r").c_str(), - bpo::value<string>()->required(), - "run number") - ((std::string(OptionKeys[OptionKeyOCDB])).c_str(), - bpo::value<string>(), - "ocdb uri") - ((std::string(OptionKeys[OptionKeyMsgsize]) + ",s").c_str(), - bpo::value<string>()->default_value("0"), - "maximum size of output buffer/msg") - ((std::string(OptionKeys[OptionKeyOutputMode]) + ",m").c_str(), - bpo::value<string>()->default_value("3"), - "output mode"); - // clang-format on - return od; -} - -int Component::init(int argc, char** argv) -{ - /// initialize: scan arguments, setup system interface and create component - - // the hidden options are not exposed to the outside - bpo::options_description od("component options"); - od.add_options() - (OptionKeys[OptionKeyInstanceId], - bpo::value<string>()->required(), - "internal instance id"); - // now add all the visible options - od.add(GetOptionsDescription()); - - // HLT components are implemented in shared libraries, the library name - // and component id are used to factorize a component - // optionally, a list of configuration parameters can be specified as - // one single string which is translated in an array of string in the - // argc/argv format - string componentParameter; - string instanceId; - - // the configuration and calibration is fixed for every run and identified - // by the run no - int runNumber = 0; - - bpo::variables_map varmap; - bpo::store(bpo::parse_command_line(argc, argv, od), varmap); - - for (int option = 0; option < OptionKeyLast; ++option) { - if (varmap.count(OptionKeys[option]) == 0) { - continue; - } - switch (option) { - case OptionKeyLibrary: break; - case OptionKeyComponent: break; - case OptionKeyParameter: - componentParameter = varmap[OptionKeys[option]].as<string>(); - break; - case OptionKeyRun: - stringstream(varmap[OptionKeys[option]].as<string>()) >> runNumber; - break; - case OptionKeyOCDB: - if (getenv("ALIHLT_HCDBDIR") != nullptr) { - LOG(WARN) << "overriding value of ALICEHLT_HCDBDIR by --ocdb command option"; - } - setenv("ALIHLT_HCDBDIR", varmap[OptionKeys[option]].as<string>().c_str(), 1); - break; - case OptionKeyMsgsize: { - unsigned size = 0; - stringstream(varmap[OptionKeys[option]].as<string>()) >> size; - mOutputBuffer.resize(size); - } break; - case OptionKeyOutputMode: { - unsigned mode; - stringstream(varmap[OptionKeys[option]].as<string>()) >> mode; - mFormatHandler.setOutputMode(mode); - } break; - case OptionKeyInstanceId: break; - instanceId = varmap[OptionKeys[option]].as<string>(); - break; - } - } - - // TODO: this can be a loop over all required options - // probably we won't come here anyhow as the parser will detect - // the absence of a required parameter, check and handle the parser - // exception - if (varmap.count(OptionKeys[OptionKeyLibrary]) == 0 || - varmap.count(OptionKeys[OptionKeyComponent]) == 0 || - runNumber < 0) { - LOG(ERROR) << "missing argument, required options: library, component,run"; - return -EINVAL; - } - - // check the OCDB URI - // the HLT code relies on ALIHLT_HCDBDIR environment variable to be set - if (!getenv("ALIHLT_HCDBDIR")) { - LOG(ERROR) << "FATAL: OCDB URI is needed, use option --ocdb or environment variable ALIHLT_HCDBDIR"; -// temporary fix to regain compilation on MacOS (which on some platforms does not define ENOKEY) -#ifndef ENOKEY -#define ENOKEY 126 -#endif - return -ENOKEY; - } - - int iResult = 0; - // TODO: make the SystemInterface a singleton - unique_ptr<o2::alice_hlt::SystemInterface> iface(new SystemInterface); - if (iface.get() == nullptr || ((iResult = iface->initSystem(runNumber))) < 0) { - // LOG(ERROR) << "failed to set up SystemInterface " << iface.get() << " (" << iResult << ")"; - return -ENOSYS; - } - - // basic initialization succeeded, make the instances persistent - mpSystem = iface.release(); - - // load the component library - if ((iResult = mpSystem->loadLibrary(varmap[OptionKeys[OptionKeyLibrary]].as<string>().c_str())) != 0) { - return iResult > 0 ? -iResult : iResult; - } - - // chop the parameter string in order to provide parameters in the argc/argv format - vector<const char*> parameters; - unsigned parameterLength = componentParameter.length(); - unique_ptr<char> parameterBuffer(new char[parameterLength + 1]); - if (parameterLength > 0 && parameterBuffer.get() != nullptr) { - strcpy(parameterBuffer.get(), componentParameter.c_str()); - char* iterator = parameterBuffer.get(); - parameters.emplace_back(iterator); - for (; *iterator != 0; iterator++) { - if (*iterator != ' ') { - continue; - } - *iterator = 0; // separate strings - if (*(iterator + 1) != ' ' && *(iterator + 1) != 0) { - parameters.emplace_back(iterator + 1); - } - } - } - - // create component - string description; - description+=" chainid=" + instanceId; - if ((iResult=mpSystem->createComponent(varmap[OptionKeys[OptionKeyComponent]].as<string>().c_str(), nullptr, parameters.size(), ¶meters[0], &mProcessor, description.c_str()))<0) { - // the ALICE HLT external interface uses the following error definition - // 0 success - // >0 error number - return iResult > 0 ? -iResult : iResult; - } - - mEventCount = 0; - - return iResult; -} - -int Component::process(vector<MessageFormat::BufferDesc_t>& dataArray, - cballoc_signal_t* cbAllocate) -{ - if (!mpSystem) { - return -ENOSYS; - } - int iResult = 0; - - unsigned outputBufferSize = 0; - - AliHLTComponentEventData evtData; - memset(&evtData, 0, sizeof(evtData)); - evtData.fStructSize = sizeof(evtData); - if (mEventCount >= 0) { - // very simple approach to provide an event ID - // TODO: adjust to the relevant format if available - evtData.fEventID = mEventCount++; - } - - AliHLTComponentTriggerData trigData; - memset(&trigData, 0, sizeof(trigData)); - trigData.fStructSize = sizeof(trigData); - - uint32_t outputBlockCnt = 0; - AliHLTComponentBlockData* pOutputBlocks = nullptr; - AliHLTComponentEventDoneData* pEventDoneData = nullptr; - - // prepare input structure for the ALICE HLT component - mFormatHandler.clear(); - mFormatHandler.addMessages(dataArray); - vector<BlockDescriptor>& inputBlocks = mFormatHandler.getBlockDescriptors(); - unsigned nofInputBlocks = inputBlocks.size(); - if (dataArray.size() > 0 && nofInputBlocks == 0 && mFormatHandler.getEvtDataList().size() == 0) { - LOG(ERROR) << "warning: none of " << dataArray.size() << " input buffer(s) recognized as valid input"; - } - dataArray.clear(); - - if (mFormatHandler.getEvtDataList().size()>0) { - // copy the oldest event header - memcpy(&evtData, &mFormatHandler.getEvtDataList().front(), sizeof(AliHLTComponentEventData)); - } - - // determine the total input size, needed later on for the calculation of the output buffer size - int totalInputSize = 0; - for (auto & ci : inputBlocks) { - totalInputSize += ci.fSize; - } - - // add event type data block - // this data block describes the type of the event, set it - // to 'data' by using specification gkAliEventTypeData - const AliHLTComponentDataType kDataTypeEvent = AliHLTComponentDataTypeInitializer("EVENTTYP", "PRIV"); - inputBlocks.emplace_back(nullptr, 0, kDataTypeEvent, gkAliEventTypeData); - - // process - evtData.fBlockCnt = inputBlocks.size(); - int nofTrials = 2; - do { - unsigned long constEventBase = 0; - unsigned long constBlockBase = 0; - double inputBlockMultiplier = 0.; - mpSystem->getOutputSize(mProcessor, &constEventBase, &constBlockBase, &inputBlockMultiplier); - outputBufferSize = constEventBase + nofInputBlocks * constBlockBase + totalInputSize * inputBlockMultiplier; - outputBufferSize+=sizeof(AliHLTComponentStatistics) + sizeof(AliHLTComponentTableEntry); - // take the full available buffer and increase if that - // is too little - mOutputBuffer.resize(mOutputBuffer.capacity()); - if (mOutputBuffer.size() < outputBufferSize) { - mOutputBuffer.resize(outputBufferSize); - } else if (nofTrials < 2) { - // component did not update the output size - break; - } - outputBufferSize = mOutputBuffer.size(); - outputBlockCnt = 0; - // TODO: check if that is working with the corresponding allocation method of the - // component environment - if (pOutputBlocks) { - delete[] pOutputBlocks; - } - pOutputBlocks = nullptr; - if (pEventDoneData) { - delete pEventDoneData; - } - pEventDoneData = nullptr; - - iResult = mpSystem->processEvent(mProcessor, &evtData, &inputBlocks[0], &trigData, - &mOutputBuffer[0], &outputBufferSize, - &outputBlockCnt, &pOutputBlocks, - &pEventDoneData); - if (outputBufferSize > 0) { - if (outputBufferSize > mOutputBuffer.size()) { - LOG(ERROR) << "FATAL: fatal error: component writing beyond buffer capacity"; - return -EFAULT; - } else if (outputBufferSize < mOutputBuffer.size()) { - mOutputBuffer.resize(outputBufferSize); - } - } else { - mOutputBuffer.clear(); - } - - } while (iResult == ENOSPC && --nofTrials > 0); - - // prepare output - { // keep this after removing condition to preserve formatting - uint8_t* pOutputBufferStart = &mOutputBuffer[0]; - uint8_t* pOutputBufferEnd = pOutputBufferStart + mOutputBuffer.size(); - // consistency check for data blocks - // 1) all specified data must be either inside the output buffer given - // to the component or in one of the input buffers - // 2) filter out special data blocks if they have been forwarded - // - // Some components set both pointer and offset in the block descriptor as data - // reference for blocks in the output buffer. Due to a misinterpretation in the - // early days of development that is only allowed if fPtr is set to the beginning - // of output buffer. The block is however fully described by offset relative to - // beginning of output buffer. - unsigned validBlocks = 0; - unsigned totalPayloadSize = 0; - AliHLTComponentBlockData* pOutputBlock = pOutputBlocks; - AliHLTComponentBlockData* pFiltered = pOutputBlocks; - for (unsigned blockIndex = 0; blockIndex < outputBlockCnt; blockIndex++, pOutputBlock++) { - // filter special data blocks - if (pOutputBlock->fDataType == kDataTypeEvent) { - continue; - } - - // block descriptors without any attached payload are propagated - bool bValid = pOutputBlock->fSize == 0; - - // calculate the data reference - uint8_t* pStart = - pOutputBlock->fPtr != nullptr ? reinterpret_cast<uint8_t*>(pOutputBlock->fPtr) : &mOutputBuffer[0]; - pStart += pOutputBlock->fOffset; - uint8_t* pEnd = pStart + pOutputBlock->fSize; - pOutputBlock->fPtr = pStart; - pOutputBlock->fOffset = 0; - - // first search in the output buffer - bValid = bValid || (pStart >= pOutputBufferStart && pEnd <= pOutputBufferEnd); - - // possibly a forwarded data block, try the input buffers - if (!bValid) { - for (auto & ci : inputBlocks) { - uint8_t* pInputBufferStart = reinterpret_cast<uint8_t*>(ci.fPtr); - uint8_t* pInputBufferEnd = pInputBufferStart + ci.fSize; - if ((bValid = (pStart >= pInputBufferStart && pEnd <= pInputBufferEnd))) { - break; - } - } - } - - if (bValid) { - totalPayloadSize += pOutputBlock->fSize; - validBlocks++; - memcpy(pFiltered, pOutputBlock, sizeof(AliHLTComponentBlockData)); - pFiltered++; - } else { - LOG(ERROR) << "Inconsistent data reference in output block " << blockIndex; - } - } - evtData.fBlockCnt=validBlocks; - - // create the messages - // TODO: for now there is an extra copy of the data, but it should be - // handled in place - vector<MessageFormat::BufferDesc_t> outputMessages = - mFormatHandler.createMessages(pOutputBlocks, validBlocks, totalPayloadSize, &evtData, cbAllocate); - dataArray.insert(dataArray.end(), outputMessages.begin(), outputMessages.end()); - } - - // cleanup - // NOTE: don't cleanup mOutputBuffer as the data is going to be used outside the class - // until released. - inputBlocks.clear(); - outputBlockCnt = 0; - if (pOutputBlocks) { - delete[] pOutputBlocks; - } - pOutputBlocks = nullptr; - if (pEventDoneData) { - delete pEventDoneData; - } - pEventDoneData = nullptr; - - return -iResult; -} diff --git a/Utilities/aliceHLTwrapper/src/EventSampler.cxx b/Utilities/aliceHLTwrapper/src/EventSampler.cxx deleted file mode 100644 index 46a4b7f601a79..0000000000000 --- a/Utilities/aliceHLTwrapper/src/EventSampler.cxx +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file EventSampler.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief Sampler device for Alice HLT events in FairRoot/ALFA - -#include "aliceHLTwrapper/EventSampler.h" -#include "O2Device/Compatibility.h" -#include <FairMQLogger.h> -#include <FairMQPoller.h> -#include "aliceHLTwrapper/AliHLTDataTypes.h" -#include <options/FairMQProgOptions.h> - -#include <boost/thread.hpp> -#include <boost/bind.hpp> -#include <cstdlib> -#include <cerrno> -#include <cstring> -#include <iostream> -#include <memory> -#include <chrono> -#include <fstream> - -using std::string; -using std::vector; -using std::unique_ptr; -using std::cerr; -using std::endl; - -// time reference for the timestamp of events is the beginning of the day -using std::chrono::system_clock; -typedef std::chrono::duration<int,std::ratio<60*60*24> > PeriodDay; -const std::chrono::time_point<system_clock, PeriodDay> dayref=std::chrono::time_point_cast<PeriodDay>(system_clock::now()); - -using namespace o2::alice_hlt; - -EventSampler::EventSampler(int verbosity) - : mEventPeriod(-1) - , mInitialDelay(-1) - , mNEvents(-1) - , mPollingTimeout(-1) - , mSkipProcessing(0) - , mVerbosity(verbosity) - , mLatencyLogFileName() -{ -} - -EventSampler::~EventSampler() -= default; - -constexpr const char* EventSampler::OptionKeys[]; - -bpo::options_description EventSampler::GetOptionsDescription() -{ - // assemble the options for the device class and component - bpo::options_description od("EventSampler options"); - // clang-format off - od.add_options() - (OptionKeys[OptionKeyEventPeriod], - bpo::value<int>()->default_value(1000), - "event period in us") - (OptionKeys[OptionKeyInitialDelay], - bpo::value<int>()->default_value(1000), - "initial delay before the first event in ms") - (OptionKeys[OptionKeyPollTimeout], - bpo::value<int>()->default_value(10), - "timeout for the input socket poller in ms") - ((std::string(OptionKeys[OptionKeyLatencyLog]) + ",l").c_str(), - bpo::value<std::string>()->default_value(""), - "output file name for logging of latency") - ((std::string(OptionKeys[OptionKeyDryRun]) + ",n").c_str(), - bpo::value<bool>()->zero_tokens()->default_value(false), - "skip component processing"); - // clang-format on - return od; -} - -void EventSampler::InitTask() -{ - /// inherited from FairMQDevice - const auto * config = GetConfig(); - if (config) { - mEventPeriod = config->GetValue<int>(OptionKeys[OptionKeyEventPeriod]); - mInitialDelay = config->GetValue<int>(OptionKeys[OptionKeyInitialDelay]); - mPollingTimeout = config->GetValue<int>(OptionKeys[OptionKeyPollTimeout]); - mSkipProcessing = config->GetValue<bool>(OptionKeys[OptionKeyDryRun]); - mLatencyLogFileName = config->GetValue<std::string>(OptionKeys[OptionKeyLatencyLog]); - } - mNEvents=0; -} - -void EventSampler::Run() -{ - /// inherited from FairMQDevice - int iResult=0; - - boost::thread samplerThread([this] { EventSampler::samplerLoop(); }); - - unique_ptr<FairMQPoller> poller(fTransportFactory->CreatePoller(fChannels["data-in"])); - - bool received = false; - - // inherited variables of FairMQDevice: - // fChannels - // fTransportFactory - int numInputs = fChannels["data-in"].size(); - int NoOfMsgParts=numInputs-1; - int errorCount=0; - const int maxError=10; - - vector<unique_ptr<FairMQMessage>> inputMessages; - vector<int> inputMessageCntPerSocket(numInputs, 0); - int nReadCycles=0; - - std::ofstream latencyLog(mLatencyLogFileName); - - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - - // read input messages - poller->Poll(mPollingTimeout); - for(int i = 0; i < numInputs; i++) { - if (poller->CheckInput(i)) { - if (fChannels.at("data-in").at(i).Receive(inputMessages)) { - inputMessageCntPerSocket[i] = inputMessages.size(); - if (mVerbosity > 3) { - LOG(INFO) << " |---- receive Msgs from socket " << i; - } - } - if (mVerbosity > 2) { - LOG(INFO) << "------ received " << inputMessageCntPerSocket[i] << " message(s) from socket " << i; - } - } - } - - system_clock::time_point timestamp = system_clock::now(); - auto seconds = std::chrono::duration_cast<std::chrono::seconds>(timestamp - dayref); - auto useconds = std::chrono::duration_cast<std::chrono::microseconds>(timestamp - dayref - seconds); - - for (vector<unique_ptr<FairMQMessage>>::iterator mit=inputMessages.begin(); - mit!=inputMessages.end(); mit++) { - AliHLTComponentEventData* evtData=reinterpret_cast<AliHLTComponentEventData*>((*mit)->GetData()); - if ((*mit)->GetSize() >= sizeof(AliHLTComponentEventData) && - evtData && evtData->fStructSize == sizeof(AliHLTComponentEventData) && - (evtData->fEventCreation_s>0 || evtData->fEventCreation_us>0)) { - unsigned latencySeconds=seconds.count() - evtData->fEventCreation_s; - unsigned latencyUSeconds=0; - if (useconds.count() < evtData->fEventCreation_us) { - latencySeconds--; - latencyUSeconds=(1000000 + useconds.count()) - evtData->fEventCreation_us; - } else { - latencyUSeconds=useconds.count() - evtData->fEventCreation_us; - } - if (mVerbosity>0) { - const char* unit=""; - unsigned value=0; - if (latencySeconds>=10) { - unit=" s"; - value=latencySeconds; - } else if (latencySeconds>0 || latencyUSeconds>10000) { - value=latencySeconds*1000 + latencyUSeconds/1000; - unit=" ms"; - } else { - value=latencyUSeconds; - unit=" us"; - } - LOG(DEBUG) << "received event " << evtData->fEventID << " at " << seconds.count() << "s " << useconds.count() << "us - latency " << value << unit; - } - latencyUSeconds+=latencySeconds*1000000; // max 4294s, should be enough for latency - if (latencyLog.is_open()) { - latencyLog << evtData->fEventID << " " << latencyUSeconds << endl; - } - } - } - inputMessages.clear(); - for (vector<int>::iterator mcit=inputMessageCntPerSocket.begin(); - mcit!=inputMessageCntPerSocket.end(); mcit++) { - *mcit=0; - } - } - - if (latencyLog.is_open()) { - latencyLog.close(); - } - - samplerThread.interrupt(); - samplerThread.join(); -} - -void EventSampler::samplerLoop() -{ - /// sampler loop - LOG(INFO) << "initializing sampler loop, then waiting for " << mInitialDelay << " ms"; - // wait until the first event is sent - // usleep expects arguments in the range [0,1000000] - unsigned initialDelayInSeconds=mInitialDelay/1000; - unsigned initialDelayInUSeconds=mInitialDelay%1000; - unsigned eventPeriodInSeconds=mEventPeriod/1000000; - if (initialDelayInSeconds > 0) { - sleep(initialDelayInSeconds); - } - usleep(initialDelayInUSeconds); - - unique_ptr<FairMQMessage> msg(fTransportFactory->CreateMessage()); - msg->Rebuild(sizeof(AliHLTComponentEventData)); - if (msg->GetSize() < sizeof(AliHLTComponentEventData)) { - // fatal error - LOG(ERROR) << "failed to allocate message of size " << sizeof(AliHLTComponentEventData) << ", aborting event generation"; - return; - } - AliHLTComponentEventData* evtData = reinterpret_cast<AliHLTComponentEventData*>(msg->GetData()); - memset(evtData, 0, sizeof(AliHLTComponentEventData)); - evtData->fStructSize = sizeof(AliHLTComponentEventData); - - int numOutputs = (fChannels.find("data-out") == fChannels.end() ? 0 : fChannels["data-out"].size()); - - LOG(INFO) << "starting sampler loop, period " << mEventPeriod << " us"; - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - msg->Rebuild(sizeof(AliHLTComponentEventData)); - evtData = reinterpret_cast<AliHLTComponentEventData*>(msg->GetData()); - memset(evtData, 0, sizeof(AliHLTComponentEventData)); - evtData->fStructSize = sizeof(AliHLTComponentEventData); - evtData->fEventID=mNEvents; - system_clock::time_point timestamp = system_clock::now(); - auto seconds = std::chrono::duration_cast<std::chrono::seconds>(timestamp - dayref); - evtData->fEventCreation_s=seconds.count(); - auto useconds = std::chrono::duration_cast<std::chrono::microseconds>(timestamp - dayref - seconds); - evtData->fEventCreation_us=useconds.count(); - if (mVerbosity>0) { - LOG(DEBUG) << "send event " << evtData->fEventID << " at " << evtData->fEventCreation_s << "s " << evtData->fEventCreation_us << "us"; - } - - for (int iOutput=0; iOutput<numOutputs; iOutput++) { - fChannels["data-out"].at(iOutput).Send(msg); - } - - mNEvents++; - if (eventPeriodInSeconds > 0) { - sleep(eventPeriodInSeconds); - } else { - usleep(mEventPeriod); - } - } -} diff --git a/Utilities/aliceHLTwrapper/src/HOMERFactory.cxx b/Utilities/aliceHLTwrapper/src/HOMERFactory.cxx deleted file mode 100644 index f9c70a1da1ad6..0000000000000 --- a/Utilities/aliceHLTwrapper/src/HOMERFactory.cxx +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//* * -//* See original copyright notice below * -//**************************************************************************** - -// @file HOMERFactory.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief Original AliHLTHOMERLibManager.h of AliRoot adapted to the -// ALFA project - -/************************************************************************** - * This file is property of and copyright by the ALICE HLT Project * - * ALICE Experiment at CERN, All rights reserved. * - * * - * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> * - * for The ALICE HLT Project. * - * * - * Permission to use, copy, modify and distribute this software and its * - * documentation strictly for non-commercial purposes is hereby granted * - * without fee, provided that the above copyright notice appears in all * - * copies and that both the copyright notice and this permission notice * - * appear in the supporting documentation. The authors make no claims * - * about the suitability of this software for any purpose. It is * - * provided "as is" without express or implied warranty. * - **************************************************************************/ - -#include <cerrno> -#include <cassert> -#include <cerrno> -#include <cstring> -#include <iostream> -#include <dlfcn.h> -#include "aliceHLTwrapper/HOMERFactory.h" -#include "aliceHLTwrapper/AliHLTHOMERReader.h" -#include "aliceHLTwrapper/AliHLTHOMERWriter.h" - -using namespace o2::alice_hlt; - -using std::cerr; -using std::cout; -using std::endl; - -// global flag of the library status -int HOMERFactory::sLibraryStatus = 0; -// This list must be NULL terminated, since we use it as a marker to identify -// the end of the list. -const char* HOMERFactory::sLibraries[] = {"libAliHLTHOMER.so", "libHOMER.so", nullptr}; -// The size of the list of reference counts must be one less than sLibraries. -int HOMERFactory::sLibRefCount[] = {0, 0}; - -HOMERFactory::HOMERFactory() - : mFctCreateReaderFromTCPPort(nullptr), mFctCreateReaderFromTCPPorts(nullptr), mFctCreateReaderFromBuffer(nullptr), mFctDeleteReader(nullptr), mFctCreateWriter(nullptr), mFctDeleteWriter(nullptr), mLoadedLib(nullptr), mHandle(nullptr) -{ - // constructor - // - // Interface to the HLT Online Monitoring Including Root (HOMER) library. - // It allows to decouple the HLT base library from this additional library - // while providing the basic functionality to the component libraries -} - -// destructor -// -// the library load strategy has been changed in March 2013 in order to -// stabilize the runtime memory layout of AliRoot in an attemp to get control -// over memory corruptions -HOMERFactory::~HOMERFactory() = default; - -AliHLTHOMERReader* HOMERFactory::OpenReader(const char* hostname, unsigned short port) -{ - // Open Reader instance for host - if (sLibraryStatus < 0) { - return nullptr; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return nullptr; - } - - AliHLTHOMERReader* pReader = nullptr; - if (mFctCreateReaderFromTCPPort != nullptr && (pReader = (((AliHLTHOMERReaderCreateFromTCPPort_t)mFctCreateReaderFromTCPPort)(hostname, port))) == nullptr) { - cout << "can not create instance of HOMER reader from ports" << endl; - } - - return pReader; -} - -AliHLTHOMERReader* HOMERFactory::OpenReader(unsigned int tcpCnt, const char** hostnames, unsigned short* ports) -{ - // Open Reader instance for a list of hosts - if (sLibraryStatus < 0) { - return nullptr; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return nullptr; - } - - AliHLTHOMERReader* pReader = nullptr; - if (mFctCreateReaderFromTCPPorts != nullptr && (pReader = (((AliHLTHOMERReaderCreateFromTCPPorts_t)mFctCreateReaderFromTCPPorts)(tcpCnt, hostnames, ports))) == nullptr) { - //HLTError("can not create instance of HOMER reader (function %p)", mFctCreateReaderFromTCPPorts); - cout << "can not create instance of HOMER reader from port" << endl; - } - - return pReader; -} - -AliHLTHOMERReader* HOMERFactory::OpenReaderBuffer(const AliHLTUInt8_t* pBuffer, int size) -{ - // Open Reader instance for a data buffer - if (sLibraryStatus < 0) { - return nullptr; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return nullptr; - } - - AliHLTHOMERReader* pReader = nullptr; - if (mFctCreateReaderFromBuffer != nullptr && (pReader = (((AliHLTHOMERReaderCreateFromBuffer_t)mFctCreateReaderFromBuffer)(pBuffer, size))) == nullptr) { - //HLTError("can not create instance of HOMER reader (function %p)", mFctCreateReaderFromBuffer); - } - - return pReader; -} - -int HOMERFactory::DeleteReader(AliHLTHOMERReader* pReader) -{ - // delete a reader - - // the actual deletion function is inside the HOMER library - if (sLibraryStatus < 0) { - return sLibraryStatus; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return sLibraryStatus; - } - - if (mFctDeleteReader != nullptr) { - ((AliHLTHOMERReaderDelete_t)mFctDeleteReader)(pReader); - } - - return 0; -} - -AliHLTHOMERWriter* HOMERFactory::OpenWriter() -{ - // open a Writer instance - if (sLibraryStatus < 0) { - return nullptr; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return nullptr; - } - - AliHLTHOMERWriter* pWriter = nullptr; - if (mFctCreateWriter != nullptr && (pWriter = (((AliHLTHOMERWriterCreate_t)mFctCreateWriter)())) == nullptr) { - // HLTError("can not create instance of HOMER writer (function %p)", mFctCreateWriter); - } - - return pWriter; -} - -int HOMERFactory::DeleteWriter(AliHLTHOMERWriter* pWriter) -{ - // see header file for class documentation - if (sLibraryStatus < 0) { - return sLibraryStatus; - } - - sLibraryStatus = LoadHOMERLibrary(); - if (sLibraryStatus <= 0) { - return sLibraryStatus; - } - - if (mFctDeleteWriter != nullptr) { - ((AliHLTHOMERWriterDelete_t)mFctDeleteWriter)(pWriter); - } - - return 0; -} - -int HOMERFactory::LoadHOMERLibrary() -{ - // delete a writer - - // the actual deletion function is inside the HOMER library - int iResult = -EBADF; - const char** library = &sLibraries[0]; - int* refcount = &sLibRefCount[0]; - do { - mHandle = dlopen(*library, RTLD_NOW); - if (mHandle) { - ++(*refcount); - mLoadedLib = *library; - iResult = 1; - break; - } - ++library; - ++refcount; - } while ((*library) != nullptr); - - if (iResult > 0 && *library != nullptr) { - // print compile info - using CompileInfo = void (*)(char*&, char*&); - - mFctCreateReaderFromTCPPort = (void (*)())dlsym(mHandle, ALIHLTHOMERREADER_CREATE_FROM_TCPPORT); - mFctCreateReaderFromTCPPorts = (void (*)())dlsym(mHandle, ALIHLTHOMERREADER_CREATE_FROM_TCPPORTS); - mFctCreateReaderFromBuffer = (void (*)())dlsym(mHandle, ALIHLTHOMERREADER_CREATE_FROM_BUFFER); - mFctDeleteReader = (void (*)())dlsym(mHandle, ALIHLTHOMERREADER_DELETE); - mFctCreateWriter = (void (*)())dlsym(mHandle, ALIHLTHOMERWRITER_CREATE); - mFctDeleteWriter = (void (*)())dlsym(mHandle, ALIHLTHOMERWRITER_DELETE); - if (mFctCreateReaderFromTCPPort == nullptr || - mFctCreateReaderFromTCPPorts == nullptr || - mFctCreateReaderFromBuffer == nullptr || - mFctDeleteReader == nullptr || - mFctCreateWriter == nullptr || - mFctDeleteWriter == nullptr) { - iResult = -ENOSYS; - } else { - } - } - if (iResult < 0 || *library == nullptr) { - mFctCreateReaderFromTCPPort = nullptr; - mFctCreateReaderFromTCPPorts = nullptr; - mFctCreateReaderFromBuffer = nullptr; - mFctDeleteReader = nullptr; - mFctCreateWriter = nullptr; - mFctDeleteWriter = nullptr; - } - - return iResult; -} - -int HOMERFactory::UnloadHOMERLibrary() -{ - // unload HOMER library - int iResult = 0; - - if (mLoadedLib != nullptr) { - // Find the corresponding reference count. - const char** library = &sLibraries[0]; - int* refcount = &sLibRefCount[0]; - while (*library != nullptr) { - if (strcmp(*library, mLoadedLib) == 0) { - break; - } - ++library; - ++refcount; - } - - // Decrease the reference count and remove the library if it is zero. - if (*refcount >= 0) { - --(*refcount); - } - if (*refcount == 0) { /* Matthias 2014-05-08 that part of the code has been disabled for the ROOT-independent - version. - TODO: dlopen is maintaining an internal reference count, which also makes the - counters here obsolete - - // Check that the library we are trying to unload is actually the last library - // in the gSystem->GetLibraries() list. If not then we must abort the removal. - // This is because of a ROOT bug/feature/limitation. If we try unload the library - // then ROOT will also wipe all libraries in the gSystem->GetLibraries() list - // following the library we want to unload. - TString libstring = gSystem->GetLibraries(); - TString token, lastlib; - Ssiz_t from = 0; - Int_t numOfLibs = 0, posOfLib = -1; - while (libstring.Tokenize(token, from, " ")) - { - ++numOfLibs; - lastlib = token; - if (token.Contains(mLoadedLib)) posOfLib = numOfLibs; - } - if (numOfLibs == posOfLib) - { - gSystem->Unload(mLoadedLib); - - // Check that the library is gone, since Unload() does not return a status code. - libstring = gSystem->GetLibraries(); - if (libstring.Contains(mLoadedLib)) iResult = -EBADF; - } - else - { - AliHLTLogging log; - log.LoggingVarargs(kHLTLogWarning, Class_Name(), FUNCTIONNAME(), __FILE__, __LINE__, - Form("ROOT limitation! Cannot properly cleanup and unload the shared" - " library '%s' since another library '%s' was loaded afterwards. Trying to" - " unload this library will remove the others and lead to serious memory faults.", - mLoadedLib, lastlib.Data() - )); - } - */ - dlclose(mHandle); - } - } - - // Clear the function pointers. - mFctCreateReaderFromTCPPort = nullptr; - mFctCreateReaderFromTCPPorts = nullptr; - mFctCreateReaderFromBuffer = nullptr; - mFctDeleteReader = nullptr; - mFctCreateWriter = nullptr; - mFctDeleteWriter = nullptr; - - return iResult; -} diff --git a/Utilities/aliceHLTwrapper/src/MessageFormat.cxx b/Utilities/aliceHLTwrapper/src/MessageFormat.cxx deleted file mode 100644 index 6d383f068ae9f..0000000000000 --- a/Utilities/aliceHLTwrapper/src/MessageFormat.cxx +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file MessageFormat.cxx -// @author Matthias Richter -// @since 2014-12-11 -// @brief Helper class for message format of ALICE HLT data blocks - -#include "aliceHLTwrapper/MessageFormat.h" -#include "aliceHLTwrapper/HOMERFactory.h" -#include "aliceHLTwrapper/AliHLTHOMERData.h" -#include "aliceHLTwrapper/AliHLTHOMERWriter.h" -#include "aliceHLTwrapper/AliHLTHOMERReader.h" -#include "Headers/Stack.h" - -#include <cstdlib> -#include <cerrno> -#include <cstring> -#include <iostream> -#include <memory> -#include <cassert> -#include <sstream> - -using namespace o2::alice_hlt; -using std::cerr; -using std::endl; -using std::unique_ptr; -using std::vector; - -// TODO: central logging to be implemented - -MessageFormat::MessageFormat() - : mBlockDescriptors(), mDataBuffer(), mMessages(), mpFactory(nullptr), mOutputMode(kOutputModeO2), mListEvtData(), mHeartbeatHeader(), mHeartbeatTrailer() -{ - // invalidate the heartbeat header and trailer - mHeartbeatHeader.headerWord = 0; - mHeartbeatTrailer.trailerWord = 0; -} - -MessageFormat::~MessageFormat() -{ - if (mpFactory) { - delete mpFactory; - } - mpFactory = nullptr; -} - -void MessageFormat::clear() -{ - mBlockDescriptors.clear(); - mDataBuffer.clear(); - mMessages.clear(); - mListEvtData.clear(); - - // invalidate the heartbeat header and trailer - mHeartbeatHeader.headerWord = 0; - mHeartbeatTrailer.trailerWord = 0; -} - -int MessageFormat::addMessage(uint8_t* buffer, unsigned size) -{ - // add message - // this will extract the block descriptors from the message - // the descriptors refer to data in the original message buffer - - unsigned count = mBlockDescriptors.size(); - // the buffer might start with an event descriptor of type AliHLTComponentEventData - // the first read attempt is assuming the descriptor and checking consistency - // - buffer size at least size of AliHLTComponentEventData struct - // - fStructSize member matches - // - number of blocks matches fBlockCnt member - unsigned position = 0; - AliHLTComponentEventData* evtData = reinterpret_cast<AliHLTComponentEventData*>(buffer + position); - if (position + sizeof(AliHLTComponentEventData) <= size && - evtData->fStructSize == sizeof(AliHLTComponentEventData)) { - position += sizeof(AliHLTComponentEventData); - } else { - // one of the criteria does not match -> no event descriptor - evtData = nullptr; - } - do { - if (evtData && evtData->fBlockCnt == 0 && size < sizeof(AliHLTComponentBlockData)) { - // special case: no block data, only event header - break; - } - if (readBlockSequence(buffer + position, size - position, mBlockDescriptors) < 0 || - (evtData != nullptr && ((mBlockDescriptors.size() - count) != evtData->fBlockCnt))) { - // not in the format of a single block, check if its a HOMER block - if (readHOMERFormat(buffer + position, size - position, mBlockDescriptors) < 0 || - (evtData != nullptr && ((mBlockDescriptors.size() - count) != evtData->fBlockCnt))) { - // not in HOMER format either - if (position > 0) { - // try once more without the assumption of event data header - position = 0; - evtData = nullptr; - continue; - } - return -ENODATA; - } - } - } while (false); - - int result = 0; - if (evtData && (result = insertEvtData(*evtData)) < 0) { - // error in the event data header, probably headers of different events - mBlockDescriptors.resize(count); - return result; - } - - return mBlockDescriptors.size() - count; -} - -int MessageFormat::addMessages(const std::vector<BufferDesc_t>& list) -{ - // add list of messages - int totalCount = 0; - int i = 0; - bool tryO2format = true; - for (auto& data : list) { - if (tryO2format) { - if (o2::header::get<o2::header::DataHeader*>(data.mP, data.mSize)) { - return readO2Format(list, mBlockDescriptors, mHeartbeatHeader, mHeartbeatTrailer); - } - tryO2format = false; - } - if (data.mSize > 0) { - unsigned nofEventHeaders = mListEvtData.size(); - int result = addMessage(data.mP, data.mSize); - if (result >= 0) { - totalCount += result; - } else { - cerr << "warning: no valid data blocks in message " << i << endl; - } - } else { - cerr << "warning: ignoring message " << i << " with payload of size 0" << endl; - } - } - return 0; -} - -int MessageFormat::readBlockSequence(uint8_t* buffer, unsigned size, - std::vector<BlockDescriptor>& descriptorList) const -{ - // read a sequence of blocks consisting of AliHLTComponentBlockData followed by payload - // from a buffer - if (buffer == nullptr) { - return 0; - } - unsigned position = 0; - std::vector<BlockDescriptor> input; - while (position + sizeof(AliHLTComponentBlockData) < size) { - AliHLTComponentBlockData* p = reinterpret_cast<AliHLTComponentBlockData*>(buffer + position); - if (p->fStructSize == 0 || // no valid header - p->fStructSize + position > size || // no space for the header - p->fStructSize + p->fSize + position > size) { // no space for the payload - // the buffer is only a valid sequence of data blocks if payload - // of the last block exacly matches the buffer boundary - // otherwize all blocks added until now are ignored - return -ENODATA; - } - // insert a new block - input.emplace_back(*p); - position += p->fStructSize; - if (p->fSize > 0) { - input.back().fPtr = buffer + position; - position += p->fSize; - } else { - // Note: also a valid block, payload is optional - input.back().fPtr = nullptr; - } - // offset always 0 for iput blocks - input.back().fOffset = 0; - } - - descriptorList.insert(descriptorList.end(), input.begin(), input.end()); - return input.size(); -} - -int MessageFormat::readHOMERFormat(uint8_t* buffer, unsigned size, - std::vector<BlockDescriptor>& descriptorList) const -{ - // read message payload in HOMER format - if (mpFactory == nullptr) { - const_cast<MessageFormat*>(this)->mpFactory = new o2::alice_hlt::HOMERFactory; - } - if (buffer == nullptr || mpFactory == nullptr) { - return -EINVAL; - } - unique_ptr<AliHLTHOMERReader> reader(mpFactory->OpenReaderBuffer(buffer, size)); - if (reader.get() == nullptr) { - return -ENOMEM; - } - - unsigned nofBlocks = 0; - if (reader->ReadNextEvent() == 0) { - nofBlocks = reader->GetBlockCnt(); - for (unsigned i = 0; i < nofBlocks; i++) { - descriptorList.emplace_back(const_cast<void*>(reader->GetBlockData(i)), reader->GetBlockDataLength(i), kAliHLTVoidDataType, reader->GetBlockDataSpec(i)); - homer_uint64 id = byteSwap64(reader->GetBlockDataType(i)); - homer_uint32 origin = byteSwap32(reader->GetBlockDataOrigin(i)); - memcpy(&descriptorList.back().fDataType.fID, &id, - sizeof(id) > kAliHLTComponentDataTypefIDsize ? kAliHLTComponentDataTypefIDsize : sizeof(id)); - memcpy(&descriptorList.back().fDataType.fOrigin, &origin, - sizeof(origin) > kAliHLTComponentDataTypefOriginSize ? kAliHLTComponentDataTypefOriginSize : sizeof(origin)); - } - } - - return nofBlocks; -} - -int MessageFormat::readO2Format(const std::vector<BufferDesc_t>& list, std::vector<BlockDescriptor>& descriptorList, HeartbeatHeader& hbh, HeartbeatTrailer& hbt) const -{ - int partNumber = 0; - const o2::header::DataHeader* dh = nullptr; - for (auto part : list) { - if (!dh) { - // new header - payload pair, read DataHeader - dh = o2::header::get<o2::header::DataHeader*>(part.mP, part.mSize); - if (!dh) { - cerr << "can not find DataHeader" << endl; - return -ENOMSG; - } - // extract the heartbeat information if available and keep it to - // envelope the data blocks in the output message - if (dh->dataDescription == o2::header::gDataDescriptionHeartbeatFrame) { - const HeartbeatFrameEnvelope* hbf = o2::header::get<HeartbeatFrameEnvelope*>(part.mP, part.mSize); - if (hbf) { - hbh = hbf->header; - hbt = hbf->trailer; - } else { - hbh.headerWord = hbt.trailerWord = 0; - } - } - } else { - if (dh->dataDescription == o2::header::gDataDescriptionHeartbeatFrame) { - // this is pure O2 information, do not forward to HLT component - dh = nullptr; - continue; - } - auto ptr = part.mP; - auto size = part.mSize; - if (hbh) { - // check if the data is enveloped in a heartbeat frame - if (size > sizeof(HeartbeatHeader) + sizeof(HeartbeatTrailer)) { - auto* datahbh = reinterpret_cast<const HeartbeatHeader*>(ptr); - auto* datahbt = reinterpret_cast<const HeartbeatTrailer*>(ptr + size - sizeof(HeartbeatTrailer)); - if ((*datahbh) && (*datahbt)) { - // valid header and trailer found, strip the block - ptr += sizeof(HeartbeatHeader); - size -= sizeof(HeartbeatHeader) + sizeof(HeartbeatTrailer); - } - } - } - descriptorList.emplace_back(ptr, size, *dh); - dh = nullptr; - } - } - if (dh) { - cerr << "missing payload to the last header" << endl; - return -ENOMSG; - } - return list.size() / 2; -} - -std::vector<MessageFormat::BufferDesc_t> MessageFormat::createMessages(const AliHLTComponentBlockData* blocks, - unsigned count, unsigned totalPayloadSize, - const AliHLTComponentEventData* evtData, - boost::signals2::signal<unsigned char*(unsigned int)>* cbAllocate) -{ - // O2 output mode does not support event info struct - // for the moment simply ignore it, not sure if this is the best - // way to go, but this function is anyhow subject to change - if (mOutputMode == kOutputModeO2 && evtData != nullptr) { - evtData = nullptr; - } - //assert(mOutputMode != kOutputModeO2 || evtData == nullptr); - - const AliHLTComponentBlockData* pOutputBlocks = blocks; - uint32_t outputBlockCnt = count; - mDataBuffer.clear(); - mMessages.clear(); - if (mOutputMode == kOutputModeHOMER) { - AliHLTHOMERWriter* pWriter = createHOMERFormat(pOutputBlocks, outputBlockCnt); - if (pWriter) { - uint32_t position = mDataBuffer.size(); - uint32_t offset = 0; - uint32_t payloadSize = pWriter->GetTotalMemorySize(); - auto msgSize = payloadSize + (evtData != nullptr ? sizeof(AliHLTComponentEventData) : 0); - if (cbAllocate == nullptr) { - // make the target in the internal buffer - mDataBuffer.resize(position + msgSize); - } - auto pTarget = MakeTarget(msgSize, position, cbAllocate); - if (evtData) { - memcpy(pTarget + offset, evtData, sizeof(AliHLTComponentEventData)); - offset += sizeof(AliHLTComponentEventData); - } - pWriter->Copy(pTarget + offset, 0, 0, 0, 0); - mpFactory->DeleteWriter(pWriter); - offset += payloadSize; - mMessages.emplace_back(pTarget, offset); - } - } else if (mOutputMode == kOutputModeMultiPart || - mOutputMode == kOutputModeSequence || - mOutputMode == kOutputModeO2) { - // the output blocks are assempled in the internal buffer, for each - // block BlockData is added as header information, directly followed - // by the block payload - // - // kOutputModeMultiPart: - // multi part mode adds one buffer descriptor per output block - // the devices decides what to do with the multiple descriptors, one - // option is to send them in a multi-part message - // - // kOutputModeSequence: - // sequence mode concatenates the output blocks in the internal - // buffer. In contrast to multi part mode, only one buffer descriptor - // for the complete sequence is handed over to device - // - // kOutputModeO2 - // the O2 data format consisting of header-payload pairs - uint32_t position = mDataBuffer.size(); - uint32_t offset = 0; - unsigned bi = 0; - const auto* pOutputBlock = pOutputBlocks; - auto maxBufferSize = totalPayloadSize; - if (mOutputMode == kOutputModeO2) { - maxBufferSize += count * sizeof(o2::header::DataHeader); - if (mHeartbeatHeader) { - // one extra header for the generated HB information - maxBufferSize += sizeof(o2::header::DataHeader) + sizeof(HeartbeatFrameEnvelope); - // the payload of the additional block - maxBufferSize += sizeof(o2::header::HeartbeatStatistics); - // one heartbeat header-trailer pair per data block - maxBufferSize += count * (sizeof(mHeartbeatHeader) + sizeof(mHeartbeatTrailer)); - } - } else { - maxBufferSize += sizeof(AliHLTComponentEventData) + count * sizeof(AliHLTComponentBlockData); - } - if (mDataBuffer.size() < position + maxBufferSize) { - // make the target in the internal buffer, for simplicity data is copied - // to a new buffer, a memmove would be possible to make room for block - // descriptors - // resize to the full size before using individual chunks of - // this buffer to ensure, that all pointers are valid at the end. - mDataBuffer.resize(position + maxBufferSize); - } - auto pTarget = &mDataBuffer[position]; - pTarget = nullptr; - if (mOutputMode == kOutputModeO2 && mHeartbeatHeader) { - // add additional heartbeat envelope block at the beginning - // data header - o2::header::DataHeader dh; - o2::header::HeartbeatStatistics hbfPayload; - dh.dataDescription = o2::header::gDataDescriptionHeartbeatFrame; - dh.dataOrigin = o2::header::gDataOriginAny; - dh.payloadSize = sizeof(hbfPayload); - dh.subSpecification = 0; - // make the stack - o2::header::Stack headerMessage(dh, HeartbeatFrameEnvelope(mHeartbeatHeader, mHeartbeatTrailer)); - - auto msgSize = headerMessage.size(); - pTarget = MakeTarget(msgSize, position, cbAllocate); - memcpy(pTarget, headerMessage.data(), msgSize); - mMessages.emplace_back(pTarget, msgSize); - if (cbAllocate == nullptr) { - position += msgSize; - } - msgSize = dh.payloadSize; - pTarget = MakeTarget(msgSize, position, cbAllocate); - memcpy(pTarget, &hbfPayload, msgSize); - mMessages.emplace_back(pTarget, msgSize); - if (cbAllocate == nullptr) { - position += msgSize; - } - } - unsigned msgSize = 0; - do { - if (bi == 0 || - mOutputMode == kOutputModeMultiPart || - mOutputMode == kOutputModeO2) { - // request a new message buffer when entering for the first time in concatanate mode - // and for every block in multi part mode - // the actual size depends on mode and block index - // - event data structure is only written at beginning of first - // message, regardsless of mode - // - concatanate mode requests one big buffer for sequential sequence of - // all blocks - msgSize = (bi == 0 && evtData != nullptr ? sizeof(AliHLTComponentEventData) : 0); // first message has event data - if (count > 0 && mOutputMode == kOutputModeMultiPart) { - msgSize += sizeof(AliHLTComponentBlockData) + pOutputBlock->fSize; - } else if (mOutputMode == kOutputModeSequence) { - msgSize += count * sizeof(AliHLTComponentBlockData) + totalPayloadSize; - } else if (mOutputMode == kOutputModeO2) { - msgSize = sizeof(o2::header::DataHeader); - } - pTarget = MakeTarget(msgSize, position, cbAllocate); - offset = 0; - } - - if (bi == 0 && evtData != nullptr) { - // event data only in the first message in order to avoid increase of required - // buffer size due to duplicated event header - memcpy(pTarget + offset, evtData, sizeof(AliHLTComponentEventData)); - if (mOutputMode == kOutputModeMultiPart && evtData->fBlockCnt > 1) { - // in multipart mode, there is only one block per part - // consequently, the number of blocks indicated in the event data header - // does not reflect the number of blocks in this data sample. But it is - // set to 1 to make the single message consistent - auto* pEvtData = reinterpret_cast<AliHLTComponentEventData*>(pTarget + offset); - pEvtData->fBlockCnt = 1; - } - offset += sizeof(AliHLTComponentEventData); - } - - if (bi < count) { - // copy BlockData and payload - uint8_t* pData = reinterpret_cast<uint8_t*>(pOutputBlock->fPtr); - pData += pOutputBlock->fOffset; - auto* bdTarget = reinterpret_cast<AliHLTComponentBlockData*>(pTarget + offset); - if (mOutputMode != kOutputModeO2) { - assert(msgSize >= offset + sizeof(AliHLTComponentBlockData) + pOutputBlock->fSize); - memcpy(bdTarget, pOutputBlock, sizeof(AliHLTComponentBlockData)); - bdTarget->fOffset = 0; - bdTarget->fPtr = nullptr; - offset += sizeof(AliHLTComponentBlockData); - memcpy(pTarget + offset, pData, pOutputBlock->fSize); - offset += pOutputBlock->fSize; - } - if (mOutputMode == kOutputModeMultiPart) { - // send one descriptor per block back to device - mMessages.emplace_back(pTarget, offset); - if (cbAllocate == nullptr) { - position += offset; - } - offset = 0; - } else if (mOutputMode == kOutputModeO2) { - o2::header::DataHeader dh; - dh.dataDescription.runtimeInit(pOutputBlock->fDataType.fID, kAliHLTComponentDataTypefIDsize); - dh.dataOrigin.runtimeInit(pOutputBlock->fDataType.fOrigin, kAliHLTComponentDataTypefOriginSize); - dh.payloadSize = pOutputBlock->fSize; - dh.subSpecification = pOutputBlock->fSpecification; - memcpy(pTarget, &dh, sizeof(o2::header::DataHeader)); - offset += sizeof(o2::header::DataHeader); - mMessages.emplace_back(pTarget, offset); - if (cbAllocate == nullptr) { - position += offset; - } - offset = 0; - if (mHeartbeatHeader.headerWord == 0) { - // no heartbeat information availalbe, send the buffer - // as it is - mMessages.emplace_back(pData, pOutputBlock->fSize); - } else { - // make the heartbeat frame - msgSize = pOutputBlock->fSize + sizeof(mHeartbeatHeader) + sizeof(mHeartbeatTrailer); - pTarget = MakeTarget(msgSize, position, cbAllocate); - memcpy(pTarget + offset, &mHeartbeatHeader, sizeof(mHeartbeatHeader)); - offset += sizeof(mHeartbeatHeader); - memcpy(pTarget + offset, pData, pOutputBlock->fSize); - offset += pOutputBlock->fSize; - memcpy(pTarget + offset, &mHeartbeatTrailer, sizeof(mHeartbeatTrailer)); - offset += sizeof(mHeartbeatTrailer); - mMessages.emplace_back(pTarget, offset); - if (cbAllocate == nullptr) { - position += offset; - } - offset = 0; - } - } - pOutputBlock++; - } - } while (++bi < count); - if (mOutputMode == kOutputModeSequence || count == 0) { - // send one single descriptor for all concatenated blocks - mMessages.emplace_back(pTarget, offset); - } - } else { - // invalid output mode - std::stringstream errorMsg; - errorMsg << "invalid output mode: " << mOutputMode; - throw std::runtime_error(errorMsg.str()); - } - return mMessages; -} - -uint8_t* MessageFormat::MakeTarget(unsigned size, unsigned position, boost::signals2::signal<unsigned char*(unsigned int)>* cbAllocate) -{ - // TODO: obviously this can be done in a better way, it's a bit of a hack - // taking account for the limited lifetime of the wrapper device code - uint8_t* pTarget = nullptr; - if (cbAllocate == nullptr) { - if (mDataBuffer.size() < position + size) { - throw std::runtime_error("complete buffer allocation must be done in the first cycle"); - } - pTarget = &mDataBuffer[position]; - } else { - // use callback to create target - pTarget = *(*cbAllocate)(size); - if (pTarget == nullptr) { - throw std::bad_alloc(); - } - } - return pTarget; -} - -AliHLTHOMERWriter* MessageFormat::createHOMERFormat(const AliHLTComponentBlockData* pOutputBlocks, - uint32_t outputBlockCnt) const -{ - // send data blocks in HOMER format in one message - int iResult = 0; - if (mpFactory == nullptr) { - const_cast<MessageFormat*>(this)->mpFactory = new o2::alice_hlt::HOMERFactory; - } - if (!mpFactory) { - return nullptr; - } - unique_ptr<AliHLTHOMERWriter> writer(mpFactory->OpenWriter()); - if (writer.get() == nullptr) { - return nullptr; - } - - homer_uint64 homerHeader[kCount_64b_Words]; - HOMERBlockDescriptor homerDescriptor(homerHeader); - - const AliHLTComponentBlockData* pOutputBlock = pOutputBlocks; - for (unsigned blockIndex = 0; blockIndex < outputBlockCnt; blockIndex++, pOutputBlock++) { - if (pOutputBlock->fPtr == nullptr && pOutputBlock->fSize > 0) { - cerr << "warning: ignoring block " << blockIndex << " because of missing data pointer" << endl; - } - memset(homerHeader, 0, sizeof(homer_uint64) * kCount_64b_Words); - homerDescriptor.Initialize(); - homer_uint64 id = 0; - homer_uint64 origin = 0; - memcpy(&id, pOutputBlock->fDataType.fID, sizeof(homer_uint64)); - memcpy(((uint8_t*)&origin) + sizeof(homer_uint32), pOutputBlock->fDataType.fOrigin, sizeof(homer_uint32)); - homerDescriptor.SetType(byteSwap64(id)); - homerDescriptor.SetSubType1(byteSwap64(origin)); - homerDescriptor.SetSubType2(pOutputBlock->fSpecification); - homerDescriptor.SetBlockSize(pOutputBlock->fSize); - writer->AddBlock(homerHeader, pOutputBlock->fPtr); - } - return writer.release(); -} - -int MessageFormat::insertEvtData(const AliHLTComponentEventData& evtData) -{ - // insert event header to list, sort by time, oldest first - if (mListEvtData.size() == 0) { - mListEvtData.emplace_back(evtData); - } else { - auto it = mListEvtData.begin(); - for (; it != mListEvtData.end(); it++) { - if ((it->fEventCreation_us * 1e3 + it->fEventCreation_us / 1e3) > - (evtData.fEventCreation_us * 1e3 + evtData.fEventCreation_us / 1e3)) { - // found a younger element - break; - } - } - // TODO: simple logic at the moment, header is not inserted - // if there is a mismatch, as the headers are inserted one by one, all - // headers in the list have the same ID - if (it != mListEvtData.end() && - evtData.fEventID != it->fEventID) { - cerr << "Error: mismatching event ID " << evtData.fEventID - << ", expected " << it->fEventID - << " for event with timestamp " - << evtData.fEventCreation_us * 1e3 + evtData.fEventCreation_us / 1e3 << " ms" - << endl; - return -1; - } - // insert before the younger element - mListEvtData.insert(it, evtData); - } - return 0; -} - -uint64_t MessageFormat::byteSwap64(uint64_t src) const -{ - // swap a 64 bit number - return ((src & 0xFFULL) << 56) | - ((src & 0xFF00ULL) << 40) | - ((src & 0xFF0000ULL) << 24) | - ((src & 0xFF000000ULL) << 8) | - ((src & 0xFF00000000ULL) >> 8) | - ((src & 0xFF0000000000ULL) >> 24) | - ((src & 0xFF000000000000ULL) >> 40) | - ((src & 0xFF00000000000000ULL) >> 56); -} - -uint32_t MessageFormat::byteSwap32(uint32_t src) const -{ - // swap a 32 bit number - return ((src & 0xFFULL) << 24) | - ((src & 0xFF00ULL) << 8) | - ((src & 0xFF0000ULL) >> 8) | - ((src & 0xFF000000ULL) >> 24); -} diff --git a/Utilities/aliceHLTwrapper/src/SystemInterface.cxx b/Utilities/aliceHLTwrapper/src/SystemInterface.cxx deleted file mode 100644 index 4026f55be909d..0000000000000 --- a/Utilities/aliceHLTwrapper/src/SystemInterface.cxx +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file SystemInterface.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief FairRoot/ALFA interface to ALICE HLT code - -#include "aliceHLTwrapper/SystemInterface.h" -#include "aliceHLTwrapper/AliHLTDataTypes.h" -#include <cstdlib> -#include <cerrno> -#include <cstring> -#include <iostream> -#include <dlfcn.h> -using namespace o2::alice_hlt; - -using std::cerr; -using std::cout; -using std::endl; -using std::string; - -SystemInterface::SystemInterface() - : mpAliHLTExtFctInitSystem(nullptr), mpAliHLTExtFctDeinitSystem(nullptr), mpAliHLTExtFctLoadLibrary(nullptr), mpAliHLTExtFctUnloadLibrary(nullptr), mpAliHLTExtFctCreateComponent(nullptr), mpAliHLTExtFctDestroyComponent(nullptr), mpAliHLTExtFctProcessEvent(nullptr), mpAliHLTExtFctGetOutputDataType(nullptr), mpAliHLTExtFctGetOutputSize(nullptr), mEnvironment() -{ - memset(&mEnvironment, 0, sizeof(mEnvironment)); - mEnvironment.fStructSize = sizeof(mEnvironment); - mEnvironment.fAllocMemoryFunc = SystemInterface::alloc; -} - -SystemInterface::~SystemInterface() = default; -/* THINK ABOUT - make SystemInterface a singleton and release the interface here if still - active - */ - -const char* gInterfaceCallSignatures[] = { - // int AliHLTAnalysisInitSystem( unsigned long version, AliHLTAnalysisEnvironment* externalEnv, unsigned long runNo, const char* runType) - "int AliHLTAnalysisInitSystem(unsigned long,AliHLTAnalysisEnvironment*,unsigned long,const char*)", - - // int AliHLTAnalysisDeinitSystem() - "int AliHLTAnalysisDeinitSystem()", - - // int AliHLTAnalysisLoadLibrary( const char* libraryPath) - "int AliHLTAnalysisLoadLibrary(const char*)", - - // int AliHLTAnalysisUnloadLibrary( const char* /*libraryPath*/) - "int AliHLTAnalysisUnloadLibrary(const char*)", - - // int AliHLTAnalysisCreateComponent( const char* componentType, void* environParam, int argc, const char** argv, AliHLTComponentHandle* handle, const char* description) - "int AliHLTAnalysisCreateComponent(const char*,void*,int,const char**,AliHLTComponentHandle*,const char*)", - - // int AliHLTAnalysisDestroyComponent( AliHLTComponentHandle handle) - "int AliHLTAnalysisDestroyComponent(AliHLTComponentHandle)", - - // int AliHLTAnalysisProcessEvent( AliHLTComponentHandle handle, const AliHLTComponentEventData* evtData, const AliHLTComponentBlockData* blocks, AliHLTComponentTriggerData* trigData, AliHLTUInt8_t* outputPtr, AliHLTUInt32_t* size, AliHLTUInt32_t* outputBlockCnt, AliHLTComponentBlockData** outputBlocks, AliHLTComponentEventDoneData** edd) - "int AliHLTAnalysisProcessEvent(AliHLTComponentHandle,const AliHLTComponentEventData*,const AliHLTComponentBlockData*,AliHLTComponentTriggerData*,AliHLTUInt8_t*,AliHLTUInt32_t*,AliHLTUInt32_t*,AliHLTComponentBlockData**,AliHLTComponentEventDoneData**)", - - // int AliHLTAnalysisGetOutputDataType( AliHLTComponentHandle handle, AliHLTComponentDataType* dataType) - "int AliHLTAnalysisGetOutputDataType(AliHLTComponentHandle,AliHLTComponentDataType*)", - - // int AliHLTAnalysisGetOutputSize( AliHLTComponentHandle handle, unsigned long* constEventBase, unsigned long* constBlockBase, double* inputBlockMultiplier) - "int AliHLTAnalysisGetOutputSize(AliHLTComponentHandle,unsigned long*,unsigned long*,double*)", - - nullptr}; - -int SystemInterface::initSystem(unsigned long runNo) -{ - /// init the system: load interface libraries and read function pointers - int iResult = 0; - - string libraryPath = ALIHLTANALYSIS_INTERFACE_LIBRARY; - - void* libHandle = dlopen(libraryPath.c_str(), RTLD_NOW); - if (!libHandle) { - cerr << "error: can not load library " << libraryPath.c_str() << endl; -#ifdef __APPLE__ - int returnvalue = -EFTYPE; -#else - int returnvalue = -ELIBACC; -#endif - - return returnvalue; - } - - AliHLTAnalysisFctGetInterfaceCall fctGetSystemCall = - (AliHLTAnalysisFctGetInterfaceCall)dlsym(libHandle, ALIHLTANALYSIS_FCT_GETINTERFACECALL); - if (!fctGetSystemCall) { - cerr << "error: can not find function '" << ALIHLTANALYSIS_FCT_GETINTERFACECALL << "' in " << libraryPath.c_str() - << endl; - return -ENOSYS; - } - - const char** arrayCalls = gInterfaceCallSignatures; - for (int i = 0; arrayCalls[i] != nullptr; i++) { - AliHLTExtFctInitSystem call = (AliHLTExtFctInitSystem)(*fctGetSystemCall)(arrayCalls[i]); - if (call == nullptr) { - cerr << "error: can not find function signature '" << arrayCalls[i] << "' in " << libraryPath.c_str() << endl; - } else { - cout << "function '" << arrayCalls[i] << "' loaded from " << libraryPath.c_str() << endl; - switch (i) { - case 0: - mpAliHLTExtFctInitSystem = (AliHLTExtFctInitSystem)call; - break; - case 1: - mpAliHLTExtFctDeinitSystem = (AliHLTExtFctDeinitSystem)call; - break; - case 2: - mpAliHLTExtFctLoadLibrary = (AliHLTExtFctLoadLibrary)call; - break; - case 3: - mpAliHLTExtFctUnloadLibrary = (AliHLTExtFctUnloadLibrary)call; - break; - case 4: - mpAliHLTExtFctCreateComponent = (AliHLTExtFctCreateComponent)call; - break; - case 5: - mpAliHLTExtFctDestroyComponent = (AliHLTExtFctDestroyComponent)call; - break; - case 6: - mpAliHLTExtFctProcessEvent = (AliHLTExtFctProcessEvent)call; - break; - case 7: - mpAliHLTExtFctGetOutputDataType = (AliHLTExtFctGetOutputDataType)call; - break; - case 8: - mpAliHLTExtFctGetOutputSize = (AliHLTExtFctGetOutputSize)call; - break; - default: - cerr << "error: number of function signatures does not match expected number of functions" << endl; - } - } - } - - if (mpAliHLTExtFctInitSystem) { - if ((iResult = (*mpAliHLTExtFctInitSystem)(ALIHLT_DATA_TYPES_VERSION, &mEnvironment, runNo, nullptr)) != 0) { - cerr << "error: AliHLTAnalysisInitSystem failed with error " << iResult << endl; - return -ENOSYS; - } - } - - return 0; -} - -int SystemInterface::releaseSystem() -{ - /// release the system interface, clean all internal structures - - /* THINK ABOUT - bookkeeping of loaded libraries and unloading them before releasing the system? - */ - int iResult = 0; - if (mpAliHLTExtFctDeinitSystem) { - iResult = (*mpAliHLTExtFctDeinitSystem)(); - } - clear(); - return iResult; -} - -int SystemInterface::loadLibrary(const char* libname) -{ - if (!mpAliHLTExtFctLoadLibrary) { - return -ENOSYS; - } - return (*mpAliHLTExtFctLoadLibrary)(libname); -} - -int SystemInterface::unloadLibrary(const char* libname) -{ - if (!mpAliHLTExtFctUnloadLibrary) { - return -ENOSYS; - } - return (*mpAliHLTExtFctUnloadLibrary)(libname); -} - -int SystemInterface::createComponent(const char* componentId, - void* environParam, - int argc, - const char** argv, - AliHLTComponentHandle* handle, - const char* description) -{ - if (!mpAliHLTExtFctCreateComponent) { - return -ENOSYS; - } - return (*mpAliHLTExtFctCreateComponent)(componentId, environParam, argc, argv, handle, description); -} - -int SystemInterface::destroyComponent(AliHLTComponentHandle handle) -{ - if (!mpAliHLTExtFctDestroyComponent) { - return -ENOSYS; - } - return (*mpAliHLTExtFctDestroyComponent)(handle); -} - -int SystemInterface::processEvent(AliHLTComponentHandle handle, - const AliHLTComponentEventData* evtData, const AliHLTComponentBlockData* blocks, - AliHLTComponentTriggerData* trigData, - AliHLTUInt8_t* outputPtr, AliHLTUInt32_t* size, - AliHLTUInt32_t* outputBlockCnt, AliHLTComponentBlockData** outputBlocks, - AliHLTComponentEventDoneData** edd) -{ - if (!mpAliHLTExtFctProcessEvent) { - return -ENOSYS; - } - return (*mpAliHLTExtFctProcessEvent)(handle, evtData, blocks, trigData, - outputPtr, size, outputBlockCnt, outputBlocks, edd); -} - -int SystemInterface::getOutputDataType(AliHLTComponentHandle handle, AliHLTComponentDataType* dataType) -{ - if (!mpAliHLTExtFctGetOutputDataType) { - return -ENOSYS; - } - return (*mpAliHLTExtFctGetOutputDataType)(handle, dataType); -} - -int SystemInterface::getOutputSize(AliHLTComponentHandle handle, unsigned long* constEventBase, - unsigned long* constBlockBase, double* inputBlockMultiplier) -{ - if (!mpAliHLTExtFctGetOutputSize) { - return -ENOSYS; - } - return (*mpAliHLTExtFctGetOutputSize)(handle, constEventBase, constEventBase, inputBlockMultiplier); -} - -void SystemInterface::clear(const char* /*option*/) -{ - /// clear the object and reset pointer references - mpAliHLTExtFctInitSystem = nullptr; - mpAliHLTExtFctDeinitSystem = nullptr; - mpAliHLTExtFctLoadLibrary = nullptr; - mpAliHLTExtFctUnloadLibrary = nullptr; - mpAliHLTExtFctCreateComponent = nullptr; - mpAliHLTExtFctDestroyComponent = nullptr; - mpAliHLTExtFctProcessEvent = nullptr; - mpAliHLTExtFctGetOutputDataType = nullptr; - mpAliHLTExtFctGetOutputSize = nullptr; -} - -void SystemInterface::print(const char* /*option*/) const -{ - /// print info -} - -void* SystemInterface::alloc(void* /*param*/, unsigned long size) -{ - // allocate memory - return malloc(size); -} - -void SystemInterface::dealloc(void* buffer, unsigned long /*size*/) -{ - // deallocate memory - if (buffer == nullptr) { - return; - } - free(buffer); -} diff --git a/Utilities/aliceHLTwrapper/src/WrapperDevice.cxx b/Utilities/aliceHLTwrapper/src/WrapperDevice.cxx deleted file mode 100644 index 7ba026f7ba714..0000000000000 --- a/Utilities/aliceHLTwrapper/src/WrapperDevice.cxx +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file WrapperDevice.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief FairRoot/ALFA device running ALICE HLT code - -#include "aliceHLTwrapper/WrapperDevice.h" -#include "aliceHLTwrapper/Component.h" -#include "O2Device/Compatibility.h" -#include <FairMQParts.h> -#include <FairMQLogger.h> -#include <FairMQPoller.h> -#include <options/FairMQProgOptions.h> - -#include <boost/thread.hpp> -#include <boost/bind.hpp> -#include <cstdlib> -#include <cerrno> -#include <cstring> -#include <iostream> -#include <memory> -#include <utility> //std::move -#include <thread> // this_thread::sleep_for - -using std::string; -using std::unique_ptr; -using std::vector; -using namespace o2::alice_hlt; - -using std::chrono::system_clock; -using TimeScale = std::chrono::milliseconds; - -WrapperDevice::WrapperDevice(int verbosity) - : mComponent(nullptr), mMessages(), mPollingPeriod(10), mSkipProcessing(0), mLastCalcTime(-1), mLastSampleTime(-1), mMinTimeBetweenSample(-1), mMaxTimeBetweenSample(-1), mTotalReadCycles(-1), mMaxReadCycles(-1), mNSamples(-1), mVerbosity(verbosity) -{ -} - -WrapperDevice::~WrapperDevice() = default; - -constexpr const char* WrapperDevice::OptionKeys[]; - -bpo::options_description WrapperDevice::GetOptionsDescription() -{ - // assemble the options for the device class and component - bpo::options_description od("WrapperDevice options"); - od.add_options()(OptionKeys[OptionKeyPollPeriod], - bpo::value<int>()->default_value(10), - "polling period")((std::string(OptionKeys[OptionKeyDryRun]) + ",n").c_str(), - bpo::value<bool>()->zero_tokens()->default_value(false), - "skip component processing"); - od.add(Component::GetOptionsDescription()); - return od; -} - -void WrapperDevice::InitTask() -{ - /// inherited from FairMQDevice - - int iResult = 0; - - std::unique_ptr<Component> component(new o2::alice_hlt::Component); - if (!component.get()) { - return /*-ENOMEM*/; - } - - // loop over program options, check if the option was used and - // add it together with the parameter to the argument vector. - // would have been easier to iterate over the individual - // option_description entires, but options_description does not - // provide such a functionality - vector<std::string> argstrings; - bpo::options_description componentOptionDescriptions = Component::GetOptionsDescription(); - const auto* config = GetConfig(); - if (config) { - const auto varmap = config->GetVarMap(); - for (const auto varit : varmap) { - // check if this key belongs to the options of the device - const auto* description = componentOptionDescriptions.find_nothrow(varit.first, false); - if (description && varmap.count(varit.first) && !varit.second.defaulted()) { - argstrings.emplace_back("--"); - argstrings.back() += varit.first; - // check the semantics of the value - auto semantic = description->semantic(); - if (semantic) { - // the value semantics allows different properties like - // multitoken, zero_token and composing - // currently only the simple case is supported - assert(semantic->min_tokens() <= 1); - assert(semantic->max_tokens() && semantic->min_tokens()); - if (semantic->min_tokens() > 0) { - // add the token - argstrings.emplace_back(varit.second.as<std::string>()); - } - } - } - } - mPollingPeriod = config->GetValue<int>(OptionKeys[OptionKeyPollPeriod]); - mSkipProcessing = config->GetValue<bool>(OptionKeys[OptionKeyDryRun]); - } - - // TODO: probably one can get rid of this option, the instance/device - // id is now specified with the --id option of FairMQProgOptions - string idkey = "--instance-id"; - string id = ""; - id = GetId(); - vector<char*> argv; - argv.emplace_back(&idkey[0]); - argv.emplace_back(&id[0]); - for (auto& argstringiter : argstrings) { - argv.emplace_back(&argstringiter[0]); - } - - if ((iResult = component->init(argv.size(), &argv[0])) < 0) { - LOG(ERROR) << "component init failed with error code " << iResult; - throw std::runtime_error("component init failed"); - return /*iResult*/; - } - - mComponent = component.release(); - mLastCalcTime = -1; - mLastSampleTime = -1; - mMinTimeBetweenSample = -1; - mMaxTimeBetweenSample = -1; - mTotalReadCycles = 0; - mMaxReadCycles = -1; - mNSamples = 0; -} - -void WrapperDevice::Run() -{ - /// inherited from FairMQDevice - int iResult = 0; - - static system_clock::time_point refTime = system_clock::now(); - - // inherited variables of FairMQDevice: - // fChannels - // fTransportFactory - int numInputs = fChannels["data-in"].size(); - unique_ptr<FairMQPoller> poller(numInputs > 0 ? fChannels["data-in"].at(0).Transport()->CreatePoller(fChannels["data-in"]) : nullptr); - - int errorCount = 0; - const int maxError = 10; - - vector<FairMQParts> socketInputs(numInputs); - int nReadCycles = 0; - while (compatibility::FairMQ13<FairMQDevice>::IsRunning(this)) { - - // read input messages - if (poller) { - poller->Poll(mPollingPeriod); - } else { - std::this_thread::sleep_for(std::chrono::milliseconds(mPollingPeriod)); - } - int inputsReceived = 0; - bool receivedAtLeastOneMessage = false; - for (int i = 0; i < numInputs; i++) { - if (socketInputs[i].Size() > 0) { - inputsReceived++; - continue; - } - if (poller->CheckInput(i)) { - if (Receive(socketInputs[i], "data-in", i)) { - receivedAtLeastOneMessage = true; - inputsReceived++; - if (mVerbosity > 3) { - LOG(INFO) << " |---- receive Msgs from socket " << i; - } - } - if (mVerbosity > 2) { - LOG(INFO) << "------ received " << socketInputs[i].Size() << " message(s) from socket " << i; - } - } - } - if (receivedAtLeastOneMessage) { - nReadCycles++; - } - if (inputsReceived < numInputs) { - continue; - } - mNSamples++; - mTotalReadCycles += nReadCycles; - if (mMaxReadCycles < 0 || mMaxReadCycles < nReadCycles) { - mMaxReadCycles = nReadCycles; - } - // if (nReadCycles>1) { - // LOG(INFO) << "------ recieved complete Msg from " << numInputs << " input(s) after " << nReadCycles << " read cycles" ; - // } - nReadCycles = 0; - - auto duration = std::chrono::duration_cast<TimeScale>(std::chrono::system_clock::now() - refTime); - - if (mLastSampleTime >= 0) { - int sampleTimeDiff = duration.count() - mLastSampleTime; - if (mMinTimeBetweenSample < 0 || sampleTimeDiff < mMinTimeBetweenSample) { - mMinTimeBetweenSample = sampleTimeDiff; - } - if (mMaxTimeBetweenSample < 0 || sampleTimeDiff > mMaxTimeBetweenSample) { - mMaxTimeBetweenSample = sampleTimeDiff; - } - } - mLastSampleTime = duration.count(); - if (duration.count() - mLastCalcTime > 1000) { - LOG(INFO) << "------ processed " << mNSamples << " sample(s) - total " - << mComponent->getEventCount() << " sample(s)"; - if (mNSamples > 0) { - LOG(INFO) << "------ min " << mMinTimeBetweenSample << "ms, max " << mMaxTimeBetweenSample << "ms avrg " - << (duration.count() - mLastCalcTime) / mNSamples << "ms "; - LOG(INFO) << "------ avrg number of read cycles " << mTotalReadCycles / mNSamples - << " max number of read cycles " << mMaxReadCycles; - } - mNSamples = 0; - mTotalReadCycles = 0; - mMinTimeBetweenSample = -1; - mMaxTimeBetweenSample = -1; - mMaxReadCycles = -1; - mLastCalcTime = duration.count(); - } - - if (!mSkipProcessing) { - // prepare input from messages - vector<o2::alice_hlt::MessageFormat::BufferDesc_t> dataArray; - for (auto& socketInput : socketInputs) { - for (auto& msg : socketInput.fParts) { - void* buffer = msg->GetData(); - dataArray.emplace_back(reinterpret_cast<unsigned char*>(buffer), msg->GetSize()); - } - } - - // create a signal with the callback to the buffer allocation, the component - // can create messages via the callback and writes data directly to buffer - cballoc_signal_t cbsignal; - cbsignal.connect([this](unsigned int size) { return this->createMessageBuffer(size); }); - mMessages.clear(); - - // call the component - if ((iResult = mComponent->process(dataArray, &cbsignal)) < 0) { - LOG(ERROR) << "component processing failed with error code " << iResult; - } - - // build messages from output data - if (dataArray.size() > 0) { - if (mVerbosity > 2) { - LOG(INFO) << "processing " << dataArray.size() << " buffer(s)"; - } - for (auto opayload : dataArray) { - FairMQMessage* omsg = nullptr; - // loop over pre-allocated messages - for (auto premsg = begin(mMessages); premsg != end(mMessages); premsg++) { - if ((*premsg)->GetData() == opayload.mP && - (*premsg)->GetSize() == opayload.mSize) { - omsg = (*premsg).get(); - if (mVerbosity > 2) { - LOG(DEBUG) << "using pre-allocated message of size " << opayload.mSize; - } - break; - } - } - if (omsg == nullptr) { - FairMQMessagePtr msg = NewMessage(opayload.mSize); - if (msg.get()) { - if (msg->GetSize() < opayload.mSize) { - iResult = -ENOSPC; - break; - } - if (mVerbosity > 2) { - LOG(DEBUG) << "scheduling message of size " << opayload.mSize; - } - uint8_t* pTarget = reinterpret_cast<uint8_t*>(msg->GetData()); - memcpy(pTarget, opayload.mP, opayload.mSize); - mMessages.emplace_back(move(msg)); - } else { - if (errorCount == maxError && errorCount++ > 0) { - LOG(ERROR) << "persistent error, suppressing further output"; - } else if (errorCount++ < maxError) { - LOG(ERROR) << "can not get output message from framework"; - } - iResult = -ENOMSG; - } - } - } - } - - if (mMessages.size() > 0) { - if (fChannels.find("data-out") != fChannels.end() && fChannels["data-out"].size() > 0) { - // TODO: request FairMQParts helper function to set vector - // of messages - FairMQParts outputParts; - for (auto& msg : mMessages) { - outputParts.AddPart(std::move(msg)); - } - Send(outputParts, "data-out", 0); - if (mVerbosity > 2) { - LOG(DEBUG) << "sending multipart message with " << mMessages.size() << " parts"; - } - } else { - if (errorCount == maxError && errorCount++ > 0) { - LOG(ERROR) << "persistent error, suppressing further output"; - } else if (errorCount++ < maxError) { - LOG(ERROR) << "no output slot available (" << (fChannels.find("data-out") == fChannels.end() ? "uninitialized" : "0 slots") - << ")"; - } - } - mMessages.clear(); - } - } - - // cleanup - for (auto& socketInput : socketInputs) { - // TODO: use method of FairMQParts to clear instead of - // accessing public member - socketInput.fParts.clear(); - } - } -} - -unsigned char* WrapperDevice::createMessageBuffer(unsigned size) -{ - /// create a new message with data buffer of specified size - FairMQMessagePtr msg = NewMessage(size); - if (!msg || msg->GetSize() < size) { - return nullptr; - } - - if (mVerbosity > 2) { - LOG(DEBUG) << "allocating message of size " << size; - } - mMessages.emplace_back(move(msg)); - return reinterpret_cast<uint8_t*>(mMessages.back()->GetData()); -} diff --git a/Utilities/aliceHLTwrapper/src/aliceHLTEventSampler.cxx b/Utilities/aliceHLTwrapper/src/aliceHLTEventSampler.cxx deleted file mode 100644 index 8ae4415743a48..0000000000000 --- a/Utilities/aliceHLTwrapper/src/aliceHLTEventSampler.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file aliceHLTEventSampler.cxx -// @author Matthias Richter -// @since 2015-03-15 -// @brief Event sampler for Alice HLT in FairMQ/ALFA - -#include "aliceHLTwrapper/EventSampler.h" -#include "runFairMQDevice.h" // FairMQDevice launcher boiler plate code -using namespace o2::alice_hlt; - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - options.add(EventSampler::GetOptionsDescription()); -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::alice_hlt::EventSampler; -} diff --git a/Utilities/aliceHLTwrapper/src/aliceHLTWrapper.cxx b/Utilities/aliceHLTwrapper/src/aliceHLTWrapper.cxx deleted file mode 100644 index e95fcbe8ff38c..0000000000000 --- a/Utilities/aliceHLTwrapper/src/aliceHLTWrapper.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file aliceHLTWrapper.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief FairRoot/ALFA device running ALICE HLT code - -#include "runFairMQDevice.h" // FairMQDevice launcher boiler plate code -#include "aliceHLTwrapper/WrapperDevice.h" - -namespace bpo = boost::program_options; - -void addCustomOptions(bpo::options_description& options) -{ - options.add(o2::alice_hlt::WrapperDevice::GetOptionsDescription()); -} - -FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) -{ - return new o2::alice_hlt::WrapperDevice; -} diff --git a/Utilities/aliceHLTwrapper/src/runComponent.cxx b/Utilities/aliceHLTwrapper/src/runComponent.cxx deleted file mode 100644 index 17d07cc37d61f..0000000000000 --- a/Utilities/aliceHLTwrapper/src/runComponent.cxx +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter <richterm@scieq.net> * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file runComponent.cxx -// @author Matthias Richter -// @since 2014-05-07 -// @brief run a component encapsulating ALICE HLT code - -// TODO: this file is intended to evolve into a unit test - -#include "aliceHLTwrapper/SystemInterface.h" -#include "aliceHLTwrapper/Component.h" -#include <iostream> -#include <fstream> -#include <vector> -#include <memory> -#include <cstring> - -using std::cerr; -using std::cout; -using std::endl; -using std::ofstream; -using std::string; -using std::stringstream; -using std::vector; - -int main(int argc, char** argv) -{ - int iResult = 0; - // parse options - const char* inputFileName = nullptr; - const char* outputFileName = nullptr; - - vector<char*> componentOptions; - for (int i = 0; i < argc; i++) { - char* arg = argv[i]; - switch (arg[0]) { - case '-': - if (arg[1] != 0 && arg[2] == 0) { // one char after the '-' - if (arg[1] == 'i' || arg[1] == 'o') { - if (i + 1 >= argc) { - cerr << "missing file name for option " << arg << endl; - } else if (arg[1] == 'i') { - inputFileName = argv[i + 1]; - } else { - outputFileName = argv[i + 1]; - } - break; - } - } - // intended fall-through - default: - componentOptions.push_back(arg); - } - } - - o2::alice_hlt::Component component; - if ((iResult = component.init(componentOptions.size(), &componentOptions[0])) < 0) { - cerr << "error: init failed with " << iResult << endl; - // the ALICE HLT external interface uses the following error definition - // 0 success - // >0 error number - return -iResult; - } - - vector<o2::alice_hlt::MessageFormat::BufferDesc_t> blockData; - char* inputBuffer = nullptr; - if (inputFileName) { - std::ifstream input(inputFileName, std::ifstream::binary); - if (input) { - // get length of file: - input.seekg(0, input.end); - int length = input.tellg(); - input.seekg(0, input.beg); - - // allocate memory: - inputBuffer = new char[length]; - input.read(inputBuffer, length); - input.close(); - blockData.emplace_back(reinterpret_cast<unsigned char*>(inputBuffer), length); - } - } - if ((iResult = component.process(blockData)) < 0) { - cerr << "error: init failed with " << iResult << endl; - } - if (inputBuffer) { - delete[] inputBuffer; - } - inputBuffer = nullptr; - if (iResult < 0) { - return -iResult; - } - - // for now, only the first buffer is written - if (blockData.size() > 0) { - if (outputFileName != nullptr) { - ofstream outputFile(outputFileName); - if (outputFile.good()) { - outputFile.write(reinterpret_cast<const char*>(blockData[0].mP), blockData[0].mSize); - outputFile.close(); - } - } else { - cerr << "WARNING: dropping " << blockData.size() - << " data block(s) produced by component, use option '-o' to specify output file" << endl; - } - } -} diff --git a/Utilities/aliceHLTwrapper/test/testMessageFormat.cxx b/Utilities/aliceHLTwrapper/test/testMessageFormat.cxx deleted file mode 100644 index 83681cbc2d117..0000000000000 --- a/Utilities/aliceHLTwrapper/test/testMessageFormat.cxx +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test Headers DataHeaderTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include <boost/test/unit_test.hpp> -#include <iostream> -#include <iomanip> -#include "aliceHLTwrapper/MessageFormat.h" -#include "Headers/DataHeader.h" -#include "Headers/HeartbeatFrame.h" -#include "Headers/Stack.h" - -namespace o2 -{ -namespace alice_hlt -{ -template <typename... Targs> -void hexDump(Targs... Fargs) -{ - //o2::header::hexDump(Fargs...); -} - -using DataHeader = o2::header::DataHeader; - -BOOST_AUTO_TEST_CASE(test_createMessagesModeMultiPart) -{ - std::cout << "Testing kOutputModeMultiPart" << std::endl; - MessageFormat handler; - handler.setOutputMode(MessageFormat::kOutputModeMultiPart); - - std::vector<std::string> dataFields = { - "data1", - "anotherDataSet"}; - - std::vector<BlockDescriptor> dataDescriptors; - for (auto& dataField : dataFields) { - dataDescriptors.emplace_back((void*)dataField.c_str(), dataField.size() + 1, AliHLTComponentDataTypeInitializer("TESTDATA", "TEST"), 0); - } - - unsigned totalPayloadSize = 0; - for (auto& desc : dataDescriptors) { - totalPayloadSize += desc.fSize; - hexDump("HLT data descriptor", &desc, sizeof(desc)); - if (!desc.fPtr) { - continue; - } - hexDump(" data payload", (char*)desc.fPtr + desc.fOffset, desc.fSize); - } - - // testing without event info - auto outputs = handler.createMessages(&dataDescriptors[0], dataDescriptors.size(), totalPayloadSize); - BOOST_REQUIRE(outputs.size() == dataDescriptors.size()); - unsigned dataidx = 0; - for (auto& output : outputs) { - hexDump("Output block (w/o event info)", output.mP, output.mSize); - const char* data = (char*)output.mP + sizeof(AliHLTComponentBlockData); - BOOST_CHECK(dataFields[dataidx++] == data); - } - - // testing with dummy event info - AliHLTComponentEventData evtData; - handler.clear(); - outputs.clear(); - outputs = handler.createMessages(&dataDescriptors[0], dataDescriptors.size(), totalPayloadSize, &evtData); - dataidx = 0; - for (auto& output : outputs) { - std::string debugMessage = "Output block (with"; - debugMessage += (dataidx == 0 ? "" : "out"); - debugMessage += " event info)"; - hexDump(debugMessage.c_str(), output.mP, output.mSize); - const char* data = (char*)output.mP + sizeof(AliHLTComponentBlockData) + (dataidx == 0 ? sizeof(AliHLTComponentEventData) : 0); - BOOST_CHECK(dataFields[dataidx++] == data); - } -} - -BOOST_AUTO_TEST_CASE(test_createMessagesModeSequence) -{ - std::cout << "Testing kOutputModeSequence" << std::endl; - MessageFormat handler; - handler.setOutputMode(MessageFormat::kOutputModeSequence); - - std::vector<std::string> dataFields = { - "data1", - "anotherDataSet"}; - - std::vector<BlockDescriptor> dataDescriptors; - for (auto& dataField : dataFields) { - dataDescriptors.emplace_back((void*)dataField.c_str(), dataField.size() + 1, AliHLTComponentDataTypeInitializer("TESTDATA", "TEST"), 0); - } - - unsigned totalPayloadSize = 0; - for (auto& desc : dataDescriptors) { - totalPayloadSize += desc.fSize; - hexDump("HLT data descriptor", &desc, sizeof(desc)); - if (!desc.fPtr) { - continue; - } - hexDump(" data payload", (char*)desc.fPtr + desc.fOffset, desc.fSize); - } - - // testing without event info - auto outputs = handler.createMessages(&dataDescriptors[0], dataDescriptors.size(), totalPayloadSize); - BOOST_REQUIRE(outputs.size() == 1); - hexDump("Sequential collection", outputs[0].mP, outputs[0].mSize); - unsigned capacity = outputs[0].mSize; - BOOST_REQUIRE(capacity >= sizeof(AliHLTComponentBlockData)); - const AliHLTComponentBlockData* desc = reinterpret_cast<const AliHLTComponentBlockData*>(outputs[0].mP); - for (auto& dataField : dataFields) { - BOOST_REQUIRE(desc->fSize + sizeof(AliHLTComponentBlockData) <= capacity); - const char* data = (const char*)desc + sizeof(AliHLTComponentBlockData); - hexDump("Output block", data, desc->fSize); - BOOST_CHECK(dataField == data); - capacity -= desc->fSize + sizeof(AliHLTComponentBlockData); - data += desc->fSize; - desc = reinterpret_cast<const AliHLTComponentBlockData*>(data); - } -} - -BOOST_AUTO_TEST_CASE(test_createMessagesModeO2) -{ - std::cout << "Testing kOutputModeO2" << std::endl; - MessageFormat handler; - handler.setOutputMode(MessageFormat::kOutputModeO2); - - std::vector<std::string> dataFields = { - "data1", - "anotherDataSet"}; - - std::vector<BlockDescriptor> dataDescriptors; - for (auto& dataField : dataFields) { - dataDescriptors.emplace_back((void*)dataField.c_str(), dataField.size() + 1, AliHLTComponentDataTypeInitializer("TESTDATA", "TEST"), 0); - } - - unsigned totalPayloadSize = 0; - for (auto& desc : dataDescriptors) { - totalPayloadSize += desc.fSize; - hexDump("HLT data descriptor", &desc, sizeof(desc)); - if (!desc.fPtr) { - continue; - } - hexDump(" data payload", (char*)desc.fPtr + desc.fOffset, desc.fSize); - } - - // testing without event info - auto outputs = handler.createMessages(&dataDescriptors[0], dataDescriptors.size(), totalPayloadSize); - BOOST_REQUIRE(outputs.size() % 2 == 0); - unsigned dataidx = 0; - for (auto& output : outputs) { - if (dataidx % 2 == 0) { - hexDump("Header block", output.mP, output.mSize); - BOOST_CHECK(output.mSize == sizeof(DataHeader)); - } else { - hexDump("Payload block", output.mP, output.mSize); - hexDump(" Data string", dataFields[dataidx / 2].c_str(), dataFields[dataidx / 2].size() + 1); - const char* data = (char*)output.mP; - BOOST_CHECK(dataFields[dataidx / 2] == data); - } - ++dataidx; - } - - std::cout << "reading O2 format" << std::endl; - MessageFormat inputHandler; - int result = inputHandler.addMessages(outputs); - BOOST_REQUIRE(result == dataFields.size()); - - const std::vector<BlockDescriptor>& descriptors = inputHandler.getBlockDescriptors(); - dataidx = 0; - for (auto& desc : descriptors) { - hexDump("Readback: HLT data descriptor", &desc, sizeof(desc)); - if (!desc.fPtr) { - continue; - } - const char* data = (char*)desc.fPtr + desc.fOffset; - hexDump(" data payload", data, desc.fSize); - BOOST_CHECK(dataFields[dataidx++] == data); - } -} - -BOOST_AUTO_TEST_CASE(test_createHeartbeatFrame) -{ - using HeartbeatFrameEnvelope = o2::header::HeartbeatFrameEnvelope; - using HeartbeatHeader = o2::header::HeartbeatHeader; - using HeartbeatTrailer = o2::header::HeartbeatTrailer; - using HeartbeatStatistics = o2::header::HeartbeatStatistics; - std::cout << "Testing HearbeatFrame propagation" << std::endl; - MessageFormat handler; - handler.setOutputMode(MessageFormat::kOutputModeO2); - - // data is wrapped into heartbeat frame if the - // HeartbeatFrameEnvelope header is found in the incoming - // header stack - HeartbeatStatistics hbfPayload; - DataHeader dh; - dh.dataDescription = o2::header::gDataDescriptionHeartbeatFrame; - dh.dataOrigin = o2::header::DataOrigin("TEST"); - dh.subSpecification = 0; - dh.payloadSize = sizeof(hbfPayload); - - // create incoming header stack - HeartbeatFrameEnvelope hbfHeader; - o2::header::Stack headerMessage(dh, hbfHeader); - - std::vector<MessageFormat::BufferDesc_t> incomingMessages; - incomingMessages.emplace_back((MessageFormat::BufferDesc_t::PtrT)headerMessage.data(), headerMessage.size()); - incomingMessages.emplace_back((MessageFormat::BufferDesc_t::PtrT)&hbfPayload, sizeof(hbfPayload)); - for (auto& imsg : incomingMessages) { - hexDump("Incoming message:", imsg.mP, imsg.mSize); - } - handler.addMessages(incomingMessages); - - std::vector<std::string> dataFields = { - "data1", - "anotherDataSet"}; - - std::vector<BlockDescriptor> dataDescriptors; - for (auto& dataField : dataFields) { - dataDescriptors.emplace_back((void*)dataField.c_str(), dataField.size() + 1, AliHLTComponentDataTypeInitializer("TESTDATA", "TEST"), 0); - } - - unsigned totalPayloadSize = 0; - for (auto& desc : dataDescriptors) { - totalPayloadSize += desc.fSize; - hexDump("HLT data descriptor", &desc, sizeof(desc)); - if (!desc.fPtr) { - continue; - } - hexDump(" data payload", (char*)desc.fPtr + desc.fOffset, desc.fSize); - } - - // testing without event info - std::cout << "... creating messages" << std::endl; - auto outputs = handler.createMessages(&dataDescriptors[0], dataDescriptors.size(), totalPayloadSize); - std::cout << "... checking messages" << std::endl; - BOOST_REQUIRE(outputs.size() % 2 == 0); - unsigned dataidx = 0; - unsigned datafieldidx = 0; - for (auto& output : outputs) { - if (dataidx % 2 == 0) { - hexDump("Header block", output.mP, output.mSize); - BOOST_CHECK(output.mSize >= sizeof(o2::header::DataHeader)); - } else { - hexDump("Payload block", output.mP, output.mSize); - hexDump(" Data string", dataFields[datafieldidx].c_str(), dataFields[datafieldidx].size() + 1); - if (dataidx >= 2) { - const HeartbeatHeader* hbh = reinterpret_cast<const HeartbeatHeader*>(output.mP); - const HeartbeatTrailer* hbt = reinterpret_cast<const HeartbeatTrailer*>(output.mP + output.mSize - sizeof(HeartbeatTrailer)); - BOOST_CHECK(hbh->blockType == 1 && hbh->headerLength == 1); - BOOST_CHECK(hbt->blockType == 5 && hbt->trailerLength == 1); - const char* data = (char*)(output.mP + sizeof(HeartbeatHeader)); - BOOST_CHECK(dataFields[datafieldidx] == data); - ++datafieldidx; - } - } - ++dataidx; - } - - std::cout << "... reading back messages" << std::endl; - MessageFormat readhandler; - readhandler.addMessages(outputs); - const auto readbackdescriptors = readhandler.getBlockDescriptors(); - BOOST_CHECK(readbackdescriptors.size() == dataFields.size()); - datafieldidx = 0; - for (auto readbackdesc : readbackdescriptors) { - auto data = reinterpret_cast<const char*>(readbackdesc.fPtr); - data += readbackdesc.fOffset; - hexDump("Payload block", data, readbackdesc.fSize); - BOOST_CHECK(dataFields[datafieldidx] == data); - ++datafieldidx; - } -} -} // namespace alice_hlt -} // namespace o2 diff --git a/Utilities/hough/CMakeLists.txt b/Utilities/hough/CMakeLists.txt deleted file mode 100644 index 12c3adcc99d92..0000000000000 --- a/Utilities/hough/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -set(MODULE_NAME "hough") - -o2_setup(NAME ${MODULE_NAME}) - -set(Exe_Names runHough) - -set(Exe_Source runHough.cxx) - -set(BUCKET_NAME hough_bucket) - -list(LENGTH Exe_Names _length) -math(EXPR _length ${_length}-1) - -foreach(_file RANGE 0 ${_length}) - list(GET Exe_Names ${_file} _name) - list(GET Exe_Source ${_file} _src) - o2_generate_executable(EXE_NAME - ${_name} - SOURCES - ${_src} - BUCKET_NAME - ${BUCKET_NAME}) -endforeach(_file RANGE 0 ${_length}) diff --git a/Utilities/hough/README.md b/Utilities/hough/README.md deleted file mode 100644 index 3d8f44e8ccb43..0000000000000 --- a/Utilities/hough/README.md +++ /dev/null @@ -1,46 +0,0 @@ -<!-- doxy -\page refUtilitieshough Hough Transform -/doxy --> - -# Hough Transform - -This is the groundwork for the Hough Transform algorithm implementation. The runHough executable takes as an argument an event number (i.e. runHough 032) and for the given event it loads all clusters from the corresponding data files. - -### Step by Step installation and execution - -1. The runHough executable depends on the AliRoot HLT libraries. For this, an optional dependency to AliRoot has been added to the AliceO2 framework. To build the executable, the path to the AliRoot installation must be given at configuration time. For example: - - cmake -DCMAKE_INSTALL_PREFIX:PATH=.. -DCMAKE_CXX_FLAGS="-std=c++11" .. -DALIROOT="/opt/alice/external/AliRoot" - -It is important that AliRoot, FairRoot and AliceO2 have been built against the same version of ROOT. To ensure that the prerequisite packages were compiled and installed correctly, the alfaconfig.sh script that is included as part of the FairSoft installation can be used. - -2. Raw data files should be retrieved from AliEn for a given run. The implementation can be tested using the raw files corresponding to run 167808: - - alien-token-init <username> - aliensh - - cd /alice/data/2011/LHC11h/000167808/raw/ - cp 11000167808000.10.root file://tmp - exit - - mv /tmp/11000167808000.10.root raw.root - -Then, the necessary scripts to perform the clusterization for the data should be coppied to the current directory: - - cp ${AliRoot}/HLT/exa/recraw-local.C . - cp ${AliRoot}/HLT/exa/EnableHLTInGRP.C . - cp ${AliceO2}devices/aliceHLTwrapper/macros/hltConfigurations.C . - -Finally, the following commands should executed: - - aliroot -b -q -l hltConfigurations.C recraw-local.C'("raw.root", "raw://", 0, 0, "HLT TPC", "loglevel=0x79 chains=cluster-collection", "local://./OCDB")' - - aliroot -b -q -l EnableHLTInGRP.C'(167808, "local://./OCDB", "local://./OCDB")' - rm galice.root QA.root - aliroot -b -q -l hltConfigurations.C recraw-local.C'("raw.root", "local://OCDB", -1, -1, "HLT", "loglevel=0x79 chains=cluster-collection")' 2>&1 | tee cluster-collection.log - -The result should be a directory, called "emulated-tpc-clusters" that will be the input of runHough. By executing - - runHough 032 - -the executable will load all the clusters from the emulated-tpc-clusters/event032 subdirectory. After the execution, a graphics file "clusters.pdf" will be created in the current directory depicting the coordinates of the loaded clusters. diff --git a/Utilities/hough/runHough.cxx b/Utilities/hough/runHough.cxx deleted file mode 100644 index 5c767e98bcf60..0000000000000 --- a/Utilities/hough/runHough.cxx +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file runHough.cxx -/// \brief Implementation of a cluster loader -/// \author Charis Kouzinopoulos - -#include "AliHLTTPCTrackGeometry.h" -#include "AliHLTTPCClusterDataFormat.h" -#include "AliHLTTPCSpacePointContainer.h" -#include "AliHLTComponent.h" -#include "AliHLTTPCDefinitions.h" - -#include "TCanvas.h" -#include "TGraph2D.h" - -#include "boost/filesystem.hpp" - -#include <sstream> - -std::unique_ptr<AliHLTTPCSpacePointContainer> spacepoints; -vector<float> clusterCoordinates; - -void drawData(int totalNumberOfClusters, std::string dataFilename) -{ - TCanvas* c1 = new TCanvas("c1", dataFilename.c_str(), 0, 0, 800, 600); - TGraph2D* dt = new TGraph2D(10000); - - for (Int_t i = 0; i < totalNumberOfClusters; i++) { - dt->SetPoint(i, clusterCoordinates[i * 4 + 1], clusterCoordinates[i * 4 + 2], clusterCoordinates[i * 4 + 3]); - } - - // Draw with colored dots - dt->SetMarkerStyle(1); - dt->Draw("pcol"); - - c1->Print("clusters.pdf"); -} - -void printData(int totalNumberOfClusters) -{ - cout << "Cluster ID" << setw(13) << "X coordinate" << setw(13) << "Y coordinate" << setw(13) << "Z coordinate" - << endl; - - for (int i = 0; i < totalNumberOfClusters; i++) { - cout << (AliHLTUInt32_t)clusterCoordinates[i * 4] << setw(13) << clusterCoordinates[i * 4 + 1] << setw(13) - << clusterCoordinates[i * 4 + 2] << setw(13) << clusterCoordinates[i * 4 + 3] << endl; - } -} - -void addDataToCoordinatesVector(AliHLTUInt32_t clusterID, float XCoordinate, float YCoordinate, float ZCoordinate) -{ - clusterCoordinates.push_back((float)clusterID); - clusterCoordinates.push_back(XCoordinate); - clusterCoordinates.push_back(YCoordinate); - clusterCoordinates.push_back(ZCoordinate); -} - -int processData(std::string dataPath, std::string dataType, std::string dataOrigin) -{ - // Open data file for reading - std::ifstream inputData(dataPath.c_str(), std::ifstream::binary); - if (!inputData) { - std::cerr << "Error, cluster data file " << dataPath << " could not be accessed" << endl; - std::exit(1); - } - - // Get length of file - inputData.seekg(0, inputData.end); - int dataLength = inputData.tellg(); - inputData.seekg(0, inputData.beg); - - // Allocate memory and read file to memory - char* inputBuffer = new char[dataLength]; - inputData.read(inputBuffer, dataLength); - inputData.close(); - - // Retrieve the TPC slice and partition from the filename - std::string currentSliceString(dataPath, dataPath.length() - 6, 2); - std::string currentPartitionString(dataPath, dataPath.length() - 2, 2); - - AliHLTUInt8_t currentSlice = std::stoul(currentSliceString, nullptr, 16); - AliHLTUInt8_t currentPartition = std::stoul(currentPartitionString, nullptr, 16); - - // Initialize a cluster point collection - spacepoints = std::unique_ptr<AliHLTTPCSpacePointContainer>(new AliHLTTPCSpacePointContainer); - if (!spacepoints.get()) { - std::cerr << "Error, could not create a space point collection" << endl; - std::exit(1); - } - - // Create an AliHLTComponentBlockData object, fill it with default values and then set its pointer to the data buffer - AliHLTComponentBlockData bd; - AliHLTComponent::FillBlockData(bd); - bd.fPtr = inputBuffer; - bd.fSize = dataLength; - // bd.fDataType=kAliHLTVoidDataType; - AliHLTComponent::SetDataType(bd.fDataType, dataType.c_str(), dataOrigin.c_str()); - bd.fSpecification = kAliHLTVoidDataSpec; - - // Set slice and partition - AliHLTTPCDefinitions::EncodeDataSpecification(currentSlice, currentSlice, currentPartition, currentPartition); - - // Add the AliHLTComponentBlockData object to AliHLTTPCSpacePointContainer - int numberOfClusters = spacepoints->AddInputBlock(&bd); - - // cout << *spacepoints << endl; - - // Retrieve the cluster information from AliHLTTPCSpacePointContainer - std::vector<AliHLTUInt32_t> clusterIDs; - spacepoints->GetClusterIDs(clusterIDs); - - // Append the cluster IDs and their X, Y and Z coordinates to the clusterCoordinates vector - for (vector<AliHLTUInt32_t>::const_iterator element = clusterIDs.begin(); element != clusterIDs.end(); element++) { - AliHLTUInt32_t clusterID = *element; - - addDataToCoordinatesVector(clusterID, spacepoints->GetX(clusterID), spacepoints->GetY(clusterID), - spacepoints->GetZ(clusterID)); - } - - // De-allocate memory space - if (inputBuffer) { - delete[] inputBuffer; - } - inputBuffer = NULL; - - return numberOfClusters; -} - -int main(int argc, char** argv) -{ - if (argc != 2) { - std::cerr << "Usage: " << argv[0] << " <event number>" << endl; - std::exit(1); - } - - // Create data path - std::string dataFilename = "emulated-tpc-clusters/event"; - dataFilename += argv[1]; - - boost::filesystem::path dataPath(dataFilename); - boost::filesystem::directory_iterator endIterator; - - typedef std::multimap<std::time_t, boost::filesystem::path> result_set_t; - result_set_t result_set; - - std::string dataType = "CLUSTERS", dataOrigin = "TPC "; - - int totalNumberOfClusters = 0, totalNumberOfDataFiles = 0; - - // Traverse the filesystem and execute processData for each cluster file found - if (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) { - for (boost::filesystem::directory_iterator directoryIterator(dataPath); directoryIterator != endIterator; - ++directoryIterator) { - if (boost::filesystem::is_regular_file(directoryIterator->status())) { - totalNumberOfClusters += processData(directoryIterator->path().string(), dataType, dataOrigin); - totalNumberOfDataFiles++; - } - } - } else { - std::cerr << "Path " << dataPath.string() << "/ could not be found or does not contain any valid data files" - << endl; - exit(1); - } - - cout << "Added " << totalNumberOfClusters << " clusters from " << totalNumberOfDataFiles << " data files" << endl; - - // printData(totalNumberOfClusters); - - drawData(totalNumberOfClusters, dataFilename); - - return 0; -} diff --git a/Utilities/rANS/CMakeLists.txt b/Utilities/rANS/CMakeLists.txt index 46e86f0cf3767..d07c577808b61 100644 --- a/Utilities/rANS/CMakeLists.txt +++ b/Utilities/rANS/CMakeLists.txt @@ -1,32 +1,69 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -o2_add_library(rANS +o2_add_library(rANS SOURCES src/SymbolStatistics.cxx src/FrequencyTable.cxx PUBLIC_LINK_LIBRARIES FairLogger::FairLogger) -o2_add_test(EncodeDecode - NAME EncodeDecode - SOURCES test/test_ransEncodeDecode.cxx +o2_add_test(Iterators + NAME Iterators + SOURCES test/test_ransIterators.cxx PUBLIC_LINK_LIBRARIES O2::rANS COMPONENT_NAME rANS LABELS utils) - + o2_add_test(FrequencyTable NAME FrequencyTable SOURCES test/test_ransFrequencyTable.cxx PUBLIC_LINK_LIBRARIES O2::rANS COMPONENT_NAME rANS LABELS utils) - + +o2_add_test(SymbolStatistics + NAME SymbolStatistics + SOURCES test/test_ransSymbolStatistics.cxx + PUBLIC_LINK_LIBRARIES O2::rANS + COMPONENT_NAME rANS + LABELS utils) + +o2_add_test(SymbolTable + NAME SymbolTable + SOURCES test/test_ransSymbolTable.cxx + PUBLIC_LINK_LIBRARIES O2::rANS + COMPONENT_NAME rANS + LABELS utils) + +o2_add_test(ReverseSymbolLookupTable + NAME ReverseSymbolLookupTable + SOURCES test/test_ransReverseSymbolLookupTable.cxx + PUBLIC_LINK_LIBRARIES O2::rANS + COMPONENT_NAME rANS + LABELS utils) + +o2_add_test(EncodeDecode + NAME EncodeDecode + SOURCES test/test_ransEncodeDecode.cxx + PUBLIC_LINK_LIBRARIES O2::rANS + COMPONENT_NAME rANS + LABELS utils) + +if (TARGET benchmark::benchmark) +o2_add_executable(CombinedIterator + SOURCES benchmarks/bench_ransCombinedIterator.cxx + COMPONENT_NAME rANS + IS_BENCHMARK + PUBLIC_LINK_LIBRARIES O2::rANS benchmark::benchmark) +endif() + o2_add_executable(rans-encode-decode-8 TARGETVARNAME targetName SOURCES run/bin-encode-decode.cxx @@ -43,4 +80,4 @@ o2_add_executable(rans-encode-decode-32 TARGETVARNAME targetName SOURCES run/bin-encode-decode.cxx PUBLIC_LINK_LIBRARIES O2::rANS Boost::program_options) -target_compile_definitions(${targetName} PRIVATE -DSOURCE_T=uint32_t) \ No newline at end of file +target_compile_definitions(${targetName} PRIVATE -DSOURCE_T=uint32_t) diff --git a/Utilities/rANS/benchmarks/bench_ransCombinedIterator.cxx b/Utilities/rANS/benchmarks/bench_ransCombinedIterator.cxx new file mode 100644 index 0000000000000..dce88855518cf --- /dev/null +++ b/Utilities/rANS/benchmarks/bench_ransCombinedIterator.cxx @@ -0,0 +1,114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file bench_ransCombinedIterator.cxx +/// @author Michael Lettrich +/// @since Nov 18, 2020 +/// @brief + +#include <vector> + +#include <benchmark/benchmark.h> + +#include "rANS/utils.h" + +static void BM_Array_Read_Copy(benchmark::State& state) +{ + std::vector<uint32_t> a(state.range(0), 0x0); + std::vector<uint32_t> b(state.range(0), 0x1); + std::vector<uint32_t> c(state.range(0), 0x0); + for (auto _ : state) { + std::vector<uint32_t> tmp(state.range(0)); + + for (size_t i = 0; i < a.size(); ++i) { + tmp[i] = b[i] + (a[i] << 16); + } + + for (size_t i = 0; i < tmp.size(); ++i) { + c[i] = tmp[i] + 1; + } + } +} + +BENCHMARK(BM_Array_Read_Copy)->RangeMultiplier(2)->Range(10e4, 2 * 10e6); + +static void BM_Array_Read_Iterator(benchmark::State& state) +{ + std::vector<uint32_t> a(state.range(0), 0x0); + std::vector<uint32_t> b(state.range(0), 0x1); + std::vector<uint32_t> c(state.range(0), 0x0); + + for (auto _ : state) { + auto readOP = [](auto iterA, auto iterB) -> uint32_t { + return *iterB + (*iterA << 16); + }; + + const o2::rans::utils::CombinedInputIterator begin(a.begin(), b.begin(), readOP); + const o2::rans::utils::CombinedInputIterator end(a.end(), b.end(), readOP); + + auto cIter = c.begin(); + + for (auto iter = begin; iter != end; ++iter) { + *cIter = *iter + 1; + ++cIter; + } + } +} + +BENCHMARK(BM_Array_Read_Iterator)->RangeMultiplier(2)->Range(10e4, 2 * 10e6); + +static void BM_Array_Write_Copy(benchmark::State& state) +{ + std::vector<uint32_t> a(state.range(0), 0x0); + std::vector<uint32_t> b(state.range(0), 0x0); + std::vector<uint32_t> c(state.range(0), 0x0001000f); + for (auto _ : state) { + std::vector<uint32_t> tmp(state.range(0)); + + for (size_t i = 0; i < c.size(); ++i) { + tmp[i] = c[i] + 1; + } + + for (size_t i = 0; i < a.size(); ++i) { + const uint32_t shift = 16; + a[i] = tmp[i] >> shift; + b[i] = tmp[i] & ((1 << shift) - 1); + } + } +} + +BENCHMARK(BM_Array_Write_Copy)->RangeMultiplier(2)->Range(10e4, 2 * 10e6); + +static void BM_Array_Write_Iterator(benchmark::State& state) +{ + std::vector<uint32_t> a(state.range(0), 0x0); + std::vector<uint32_t> b(state.range(0), 0x0); + std::vector<uint32_t> c(state.range(0), 0x0001000f); + + for (auto _ : state) { + auto writeOP = [](auto iterA, auto iterB, uint32_t value) -> void { + const uint32_t shift = 16; + *iterA = value >> shift; + *iterB = value & ((1 << shift) - 1); + }; + + auto out = o2::rans::utils::CombinedOutputIteratorFactory<uint32_t>::makeIter(a.begin(), b.begin(), writeOP); + + for (auto iter = c.begin(); iter != c.end(); ++iter) { + *out = *iter + 1; + ++out; + } + } +} + +BENCHMARK(BM_Array_Write_Iterator)->RangeMultiplier(2)->Range(10e4, 2 * 10e6); + +BENCHMARK_MAIN(); diff --git a/Utilities/rANS/include/rANS/Decoder.h b/Utilities/rANS/include/rANS/Decoder.h index b9ace6e49fc2b..fa735045dbc07 100644 --- a/Utilities/rANS/include/rANS/Decoder.h +++ b/Utilities/rANS/include/rANS/Decoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,21 +17,22 @@ #ifndef RANS_DECODER_H #define RANS_DECODER_H -#include "internal/Decoder.h" - #include <cstddef> #include <type_traits> #include <iostream> +#include <iomanip> #include <memory> #include <fairlogger/Logger.h> -#include "FrequencyTable.h" -#include "internal/DecoderSymbol.h" -#include "internal/ReverseSymbolLookupTable.h" -#include "internal/SymbolTable.h" -#include "internal/Decoder.h" -#include "internal/SymbolStatistics.h" +#include "rANS/FrequencyTable.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/ReverseSymbolLookupTable.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/internal/Decoder.h" +#include "rANS/internal/DecoderBase.h" +#include "rANS/internal/SymbolStatistics.h" +#include "rANS/internal/helper.h" namespace o2 { @@ -38,84 +40,26 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class Decoder +class Decoder : public internal::DecoderBase<coder_T, stream_T, source_T> { - - protected: - using decoderSymbolTable_t = internal::SymbolTable<internal::DecoderSymbol>; - using reverseSymbolLookupTable_t = internal::ReverseSymbolLookupTable; - using ransDecoder = internal::Decoder<coder_T, stream_T>; - public: - Decoder(const Decoder& d); - Decoder(Decoder&& d) = default; - Decoder<coder_T, stream_T, source_T>& operator=(const Decoder& d); - Decoder<coder_T, stream_T, source_T>& operator=(Decoder&& d) = default; - ~Decoder() = default; - Decoder(const FrequencyTable& stats, size_t probabilityBits); - - template <typename stream_IT, typename source_IT> - void process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength) const; - - size_t getAlphabetRangeBits() const { return mSymbolTable->getAlphabetRangeBits(); } - int getMinSymbol() const { return mSymbolTable->getMinSymbol(); } - int getMaxSymbol() const { return mSymbolTable->getMaxSymbol(); } - - using coder_t = coder_T; - using stream_t = stream_T; - using source_t = source_T; - - protected: - std::unique_ptr<decoderSymbolTable_t> mSymbolTable; - std::unique_ptr<reverseSymbolLookupTable_t> mReverseLUT; - size_t mProbabilityBits; -}; - -template <typename coder_T, typename stream_T, typename source_T> -Decoder<coder_T, stream_T, source_T>::Decoder(const Decoder& d) : mSymbolTable(nullptr), mReverseLUT(nullptr), mProbabilityBits(d.mProbabilityBits) -{ - mSymbolTable = std::make_unique<decoderSymbolTable_t>(*d.mSymbolTable); - mReverseLUT = std::make_unique<reverseSymbolLookupTable_t>(*d.mReverseLUT); -} - -template <typename coder_T, typename stream_T, typename source_T> -Decoder<coder_T, stream_T, source_T>& Decoder<coder_T, stream_T, source_T>::operator=(const Decoder& d) -{ - mSymbolTable = std::make_unique<decoderSymbolTable_t>(*d.mSymbolTable); - mReverseLUT = std::make_unique<reverseSymbolLookupTable_t>(*d.mReverseLUT); - mProbabilityBits = d.mProbabilityBits; - return *this; -} - -template <typename coder_T, typename stream_T, typename source_T> -Decoder<coder_T, stream_T, source_T>::Decoder(const FrequencyTable& frequencies, size_t probabilityBits) : mSymbolTable(nullptr), mReverseLUT(nullptr), mProbabilityBits(probabilityBits) -{ - using namespace internal; + using internal::DecoderBase<coder_T, stream_T, source_T>::DecoderBase; - SymbolStatistics stats(frequencies, mProbabilityBits); - mProbabilityBits = stats.getSymbolTablePrecision(); + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool> = true> + void process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength) const; - RANSTimer t; - t.start(); - mSymbolTable = std::make_unique<decoderSymbolTable_t>(stats); - t.stop(); - LOG(debug1) << "Decoder SymbolTable inclusive time (ms): " << t.getDurationMS(); - t.start(); - mReverseLUT = std::make_unique<reverseSymbolLookupTable_t>(mProbabilityBits, stats); - t.stop(); - LOG(debug1) << "ReverseSymbolLookupTable inclusive time (ms): " << t.getDurationMS(); + private: + using ransDecoder_t = typename internal::DecoderBase<coder_T, stream_T, source_T>::ransDecoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -void Decoder<coder_T, stream_T, source_T>::process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool>> +void Decoder<coder_T, stream_T, source_T>::process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength) const { using namespace internal; LOG(trace) << "start decoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); if (messageLength == 0) { LOG(warning) << "Empty message passed to decoder, skipping decode process"; @@ -128,24 +72,26 @@ void Decoder<coder_T, stream_T, source_T>::process(const source_IT outputBegin, // make Iter point to the last last element --inputIter; - ransDecoder rans0, rans1; + ransDecoder_t rans0{this->mSymbolTablePrecission}; + ransDecoder_t rans1{this->mSymbolTablePrecission}; + inputIter = rans0.init(inputIter); inputIter = rans1.init(inputIter); for (size_t i = 0; i < (messageLength & ~1); i += 2) { - const int64_t s0 = (*mReverseLUT)[rans0.get(mProbabilityBits)]; - const int64_t s1 = (*mReverseLUT)[rans1.get(mProbabilityBits)]; + const int64_t s0 = this->mReverseLUT[rans0.get()]; + const int64_t s1 = this->mReverseLUT[rans1.get()]; *it++ = s0; *it++ = s1; - inputIter = rans0.advanceSymbol(inputIter, (*mSymbolTable)[s0], mProbabilityBits); - inputIter = rans1.advanceSymbol(inputIter, (*mSymbolTable)[s1], mProbabilityBits); + inputIter = rans0.advanceSymbol(inputIter, this->mSymbolTable[s0]); + inputIter = rans1.advanceSymbol(inputIter, this->mSymbolTable[s1]); } // last byte, if message length was odd if (messageLength & 1) { - const int64_t s0 = (*mReverseLUT)[rans0.get(mProbabilityBits)]; + const int64_t s0 = this->mReverseLUT[rans0.get()]; *it = s0; - inputIter = rans0.advanceSymbol(inputIter, (*mSymbolTable)[s0], mProbabilityBits); + inputIter = rans0.advanceSymbol(inputIter, this->mSymbolTable[s0]); } t.stop(); LOG(debug1) << "Decoder::" << __func__ << " { DecodedSymbols: " << messageLength << "," diff --git a/Utilities/rANS/include/rANS/DedupDecoder.h b/Utilities/rANS/include/rANS/DedupDecoder.h index b9c3538b95dcf..802593f3846f0 100644 --- a/Utilities/rANS/include/rANS/DedupDecoder.h +++ b/Utilities/rANS/include/rANS/DedupDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,19 +17,19 @@ #ifndef RANS_DEDUPDECODER_H #define RANS_DEDUPDECODER_H -#include "Decoder.h" - #include <cstddef> #include <type_traits> #include <iostream> +#include <iomanip> #include <string> #include <fairlogger/Logger.h> -#include "internal/DecoderSymbol.h" -#include "internal/ReverseSymbolLookupTable.h" -#include "internal/SymbolTable.h" -#include "internal/Decoder.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/ReverseSymbolLookupTable.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/internal/Decoder.h" +#include "rANS/internal/DecoderBase.h" namespace o2 { @@ -36,29 +37,30 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class DedupDecoder : public Decoder<coder_T, stream_T, source_T> +class DedupDecoder : public internal::DecoderBase<coder_T, stream_T, source_T> { - //inherit constructors; - using Decoder<coder_T, stream_T, source_T>::Decoder; public: using duplicatesMap_t = std::map<uint32_t, uint32_t>; - template <typename stream_IT, typename source_IT> - void process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength, duplicatesMap_t& duplicates) const; + //inherit constructors; + using internal::DecoderBase<coder_T, stream_T, source_T>::DecoderBase; + + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool> = true> + void process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength, duplicatesMap_t& duplicates) const; + + private: + using ransDecoder_t = typename internal::DecoderBase<coder_T, stream_T, source_T>::ransDecoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -void DedupDecoder<coder_T, stream_T, source_T>::process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength, duplicatesMap_t& duplicates) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool>> +void DedupDecoder<coder_T, stream_T, source_T>::process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength, duplicatesMap_t& duplicates) const { using namespace internal; - using ransDecoder = internal::Decoder<coder_T, stream_T>; LOG(trace) << "start decoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); if (messageLength == 0) { LOG(warning) << "Empty message passed to decoder, skipping decode process"; @@ -71,11 +73,11 @@ void DedupDecoder<coder_T, stream_T, source_T>::process(const source_IT outputBe // make Iter point to the last last element --inputIter; - ransDecoder rans; + ransDecoder_t rans{this->mSymbolTablePrecission}; inputIter = rans.init(inputIter); for (size_t i = 0; i < (messageLength); i++) { - const auto s = (*this->mReverseLUT)[rans.get(this->mProbabilityBits)]; + const auto s = (this->mReverseLUT)[rans.get()]; // deduplication auto duplicatesIter = duplicates.find(i); @@ -87,7 +89,7 @@ void DedupDecoder<coder_T, stream_T, source_T>::process(const source_IT outputBe } } *it++ = s; - inputIter = rans.advanceSymbol(inputIter, (*this->mSymbolTable)[s], this->mProbabilityBits); + inputIter = rans.advanceSymbol(inputIter, (this->mSymbolTable)[s]); } t.stop(); diff --git a/Utilities/rANS/include/rANS/DedupEncoder.h b/Utilities/rANS/include/rANS/DedupEncoder.h index 3a4efaf2d9f74..faafddda69eba 100644 --- a/Utilities/rANS/include/rANS/DedupEncoder.h +++ b/Utilities/rANS/include/rANS/DedupEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,6 @@ #ifndef INCLUDE_RANS_DEDUPENCODER_H_ #define INCLUDE_RANS_DEDUPENCODER_H_ -#include "Encoder.h" - #include <memory> #include <algorithm> #include <iomanip> @@ -28,9 +27,10 @@ #include <fairlogger/Logger.h> #include <stdexcept> -#include "internal/EncoderSymbol.h" -#include "internal/helper.h" -#include "internal/SymbolTable.h" +#include "rANS/internal/EncoderBase.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" +#include "rANS/internal/SymbolTable.h" namespace o2 { @@ -38,53 +38,44 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class DedupEncoder : public Encoder<coder_T, stream_T, source_T> +class DedupEncoder : public internal::EncoderBase<coder_T, stream_T, source_T> { + public: //inherit constructors; - using Encoder<coder_T, stream_T, source_T>::Encoder; + using internal::EncoderBase<coder_T, stream_T, source_T>::EncoderBase; - public: using duplicatesMap_t = std::map<uint32_t, uint32_t>; - template <typename stream_IT, typename source_IT> - const stream_IT process(const stream_IT outputBegin, const stream_IT outputEnd, - const source_IT inputBegin, source_IT inputEnd, duplicatesMap_t& duplicates) const; + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool> = true> + stream_IT process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, duplicatesMap_t& duplicates) const; + + private: + using ransCoder_t = typename internal::EncoderBase<coder_T, stream_T, source_T>::ransCoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -const stream_IT DedupEncoder<coder_T, stream_T, source_T>::process(const stream_IT outputBegin, const stream_IT outputEnd, const source_IT inputBegin, const source_IT inputEnd, duplicatesMap_t& duplicates) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool>> +stream_IT DedupEncoder<coder_T, stream_T, source_T>::process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, duplicatesMap_t& duplicates) const { using namespace internal; - using ransCoder = internal::Encoder<coder_T, stream_T>; LOG(trace) << "start encoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); - if (inputBegin == inputEnd) { LOG(warning) << "passed empty message to encoder, skip encoding"; - return outputEnd; - } - - if (outputBegin == outputEnd) { - const std::string errorMessage("Unallocated encode buffer passed to encoder. Aborting"); - LOG(error) << errorMessage; - throw std::runtime_error(errorMessage); + return outputBegin; } - - ransCoder rans; + ransCoder_t rans{this->mSymbolTablePrecission}; stream_IT outputIter = outputBegin; source_IT inputIT = inputEnd; const auto inputBufferSize = std::distance(inputBegin, inputEnd); - auto encode = [&inputBegin, &duplicates, this](source_IT symbolIter, stream_IT outputIter, ransCoder& coder) { + auto encode = [&inputBegin, &duplicates, this](source_IT symbolIter, stream_IT outputIter, ransCoder_t& coder) { const source_T symbol = *symbolIter; - const auto& encoderSymbol = (*this->mSymbolTable)[symbol]; + const auto& encoderSymbol = (this->mSymbolTable)[symbol]; // dedup step: auto dedupIT = symbolIter; @@ -100,35 +91,21 @@ const stream_IT DedupEncoder<coder_T, stream_T, source_T>::process(const stream_ // if we have a duplicate treat it. if (numDuplicates > 0) { - LOG(trace) << "pos[" << std::distance(inputBegin, symbolIter) - 1 << "]: found " << numDuplicates << " duplicates of symbol " << (char)symbol; - duplicates.emplace(std::distance(inputBegin, symbolIter) - 1, numDuplicates); + const auto pos = std::distance(inputBegin, symbolIter) - 1; + LOG(trace) << "pos[" << pos << "]: found " << numDuplicates << " duplicates of symbol " << (char)symbol; + duplicates.emplace(pos, numDuplicates); } - return std::tuple(++dedupIT, coder.putSymbol(outputIter, encoderSymbol, this->mProbabilityBits)); + return std::pair(++dedupIT, coder.putSymbol(outputIter, encoderSymbol)); }; - while (inputIT > inputBegin) { // NB: working in reverse! + while (inputIT != inputBegin) { // NB: working in reverse! std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans); - assert(outputIter < outputEnd); } outputIter = rans.flush(outputIter); // first iterator past the range so that sizes, distances and iterators work correctly. ++outputIter; - assert(!(outputIter > outputEnd)); - - // deal with overflow - if (outputIter > outputEnd) { - const std::string exceptionText = [&]() { - std::stringstream ss; - ss << __func__ << " detected overflow in encode buffer: allocated:" << std::distance(outputBegin, outputEnd) << ", used:" << std::distance(outputBegin, outputIter); - return ss.str(); - }(); - - LOG(error) << exceptionText; - throw std::runtime_error(exceptionText); - } - t.stop(); LOG(debug1) << "Encoder::" << __func__ << " {ProcessedBytes: " << inputBufferSize * sizeof(source_T) << "," << " inclusiveTimeMS: " << t.getDurationMS() << "," @@ -138,16 +115,14 @@ const stream_IT DedupEncoder<coder_T, stream_T, source_T>::process(const stream_ #if !defined(NDEBUG) const auto inputBufferSizeB = inputBufferSize * sizeof(source_T); - const auto outputBufferSizeB = std::distance(outputBegin, outputIter) * sizeof(stream_T); - - LOG(debug2) << "EncoderProperties: {" - << "sourceTypeB: " << sizeof(source_T) << ", " - << "streamTypeB: " << sizeof(stream_T) << ", " - << "coderTypeB: " << sizeof(coder_T) << ", " - << "probabilityBits: " << this->mProbabilityBits << ", " - << "inputBufferSizeB: " << inputBufferSizeB << ", " - << "outputBufferSizeB: " << outputBufferSizeB << ", " - << "compressionFactor: " << std::fixed << std::setprecision(2) << static_cast<double>(inputBufferSizeB) / static_cast<double>(outputBufferSizeB) << "}"; + + LOG(debug2) + << "EncoderProperties: {" + << "sourceTypeB: " << sizeof(source_T) << ", " + << "streamTypeB: " << sizeof(stream_T) << ", " + << "coderTypeB: " << sizeof(coder_T) << ", " + << "probabilityBits: " << this->mSymbolTablePrecission << ", " + << "inputBufferSizeB: " << inputBufferSizeB << "}"; #endif LOG(trace) << "done encoding"; diff --git a/Utilities/rANS/include/rANS/Encoder.h b/Utilities/rANS/include/rANS/Encoder.h index 907302b14202c..a39e03007058d 100644 --- a/Utilities/rANS/include/rANS/Encoder.h +++ b/Utilities/rANS/include/rANS/Encoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,6 @@ #ifndef RANS_ENCODER_H #define RANS_ENCODER_H -#include "internal/Encoder.h" - #include <memory> #include <algorithm> #include <iomanip> @@ -25,10 +24,12 @@ #include <fairlogger/Logger.h> #include <stdexcept> -#include "internal/EncoderSymbol.h" -#include "internal/helper.h" -#include "internal/SymbolTable.h" -#include "FrequencyTable.h" +#include "rANS/internal/EncoderBase.h" +#include "rANS/internal/Encoder.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/FrequencyTable.h" namespace o2 { @@ -36,148 +37,62 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class Encoder +class Encoder : public internal::EncoderBase<coder_T, stream_T, source_T> { - protected: - using encoderSymbolTable_t = internal::SymbolTable<internal::EncoderSymbol<coder_T>>; public: - Encoder() = delete; - ~Encoder() = default; - Encoder(Encoder&& e) = default; - Encoder(const Encoder& e); - Encoder<coder_T, stream_T, source_T>& operator=(const Encoder& e); - Encoder<coder_T, stream_T, source_T>& operator=(Encoder&& e) = default; - - Encoder(const encoderSymbolTable_t& e, size_t probabilityBits); - Encoder(encoderSymbolTable_t&& e, size_t probabilityBits); - Encoder(const FrequencyTable& frequencies, size_t probabilityBits); - - template <typename stream_IT, typename source_IT> - const stream_IT process(const stream_IT outputBegin, const stream_IT outputEnd, - const source_IT inputBegin, const source_IT inputEnd) const; - - size_t getProbabilityBits() const { return mProbabilityBits; } - size_t getAlphabetRangeBits() const { return mSymbolTable->getAlphabetRangeBits(); } - int getMinSymbol() const { return mSymbolTable->getMinSymbol(); } - int getMaxSymbol() const { return mSymbolTable->getMaxSymbol(); } - - using coder_t = coder_T; - using stream_t = stream_T; - using source_t = source_T; - - protected: - std::unique_ptr<encoderSymbolTable_t> mSymbolTable; - size_t mProbabilityBits; - - using ransCoder = internal::Encoder<coder_T, stream_T>; -}; + //inherit constructors; + using internal::EncoderBase<coder_T, stream_T, source_T>::EncoderBase; -template <typename coder_T, typename stream_T, typename source_T> -Encoder<coder_T, stream_T, source_T>::Encoder(const Encoder& e) : mSymbolTable(nullptr), mProbabilityBits(e.mProbabilityBits) -{ - mSymbolTable = std::make_unique<encoderSymbolTable_t>(*e.mSymbolTable); -}; + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool> = true> + const stream_IT process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin) const; -template <typename coder_T, typename stream_T, typename source_T> -Encoder<coder_T, stream_T, source_T>& Encoder<coder_T, stream_T, source_T>::operator=(const Encoder& e) -{ - mProbabilityBits = e.mProbabilityBits; - mSymbolTable = std::make_unique<encoderSymbolTable_t>(*e.mSymbolTable); - return *this; + private: + using ransCoder_t = typename internal::EncoderBase<coder_T, stream_T, source_T>::ransCoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -Encoder<coder_T, stream_T, source_T>::Encoder(const encoderSymbolTable_t& e, size_t probabilityBits) : mSymbolTable(nullptr), mProbabilityBits(probabilityBits) -{ - mSymbolTable = std::make_unique<encoderSymbolTable_t>(e); -}; - -template <typename coder_T, typename stream_T, typename source_T> -Encoder<coder_T, stream_T, source_T>::Encoder(encoderSymbolTable_t&& e, size_t probabilityBits) : mSymbolTable(std::move(e.mSymbolTable)), mProbabilityBits(probabilityBits){}; - -template <typename coder_T, typename stream_T, typename source_T> -Encoder<coder_T, stream_T, source_T>::Encoder(const FrequencyTable& frequencies, - size_t probabilityBits) : mSymbolTable(nullptr), mProbabilityBits(probabilityBits) -{ - using namespace internal; - - SymbolStatistics stats(frequencies, mProbabilityBits); - mProbabilityBits = stats.getSymbolTablePrecision(); - - RANSTimer t; - t.start(); - mSymbolTable = std::make_unique<encoderSymbolTable_t>(stats); - t.stop(); - LOG(debug1) << "Encoder SymbolTable inclusive time (ms): " << t.getDurationMS(); -} - -template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -const stream_IT Encoder<coder_T, stream_T, source_T>::Encoder::process(const stream_IT outputBegin, const stream_IT outputEnd, const source_IT inputBegin, const source_IT inputEnd) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool>> +const stream_IT Encoder<coder_T, stream_T, source_T>::process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin) const { using namespace internal; LOG(trace) << "start encoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); - if (inputBegin == inputEnd) { LOG(warning) << "passed empty message to encoder, skip encoding"; - return outputEnd; - } - - if (outputBegin == outputEnd) { - const std::string errorMessage("Unallocated encode buffer passed to encoder. Aborting"); - LOG(error) << errorMessage; - throw std::runtime_error(errorMessage); + return outputBegin; } - ransCoder rans0, rans1; + ransCoder_t rans0{this->mSymbolTablePrecission}; + ransCoder_t rans1{this->mSymbolTablePrecission}; stream_IT outputIter = outputBegin; source_IT inputIT = inputEnd; const auto inputBufferSize = std::distance(inputBegin, inputEnd); - auto encode = [this](source_IT symbolIter, stream_IT outputIter, ransCoder& coder) { + auto encode = [this](source_IT symbolIter, stream_IT outputIter, ransCoder_t& coder) { const source_T symbol = *symbolIter; - const auto& encoderSymbol = (*this->mSymbolTable)[symbol]; - return std::tuple(symbolIter, coder.putSymbol(outputIter, encoderSymbol, this->mProbabilityBits)); + const auto& encoderSymbol = (this->mSymbolTable)[symbol]; + return coder.putSymbol(outputIter, encoderSymbol); }; // odd number of bytes? if (inputBufferSize & 1) { - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans0); - assert(outputIter < outputEnd); + outputIter = encode(--inputIT, outputIter, rans0); } - while (inputIT > inputBegin) { // NB: working in reverse! - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans1); - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans0); - assert(outputIter < outputEnd); + while (inputIT != inputBegin) { // NB: working in reverse! + outputIter = encode(--inputIT, outputIter, rans1); + outputIter = encode(--inputIT, outputIter, rans0); } outputIter = rans1.flush(outputIter); outputIter = rans0.flush(outputIter); // first iterator past the range so that sizes, distances and iterators work correctly. ++outputIter; - assert(!(outputIter > outputEnd)); - - // deal with overflow - if (outputIter > outputEnd) { - const std::string exceptionText = [&]() { - std::stringstream ss; - ss << __func__ << " detected overflow in encode buffer: allocated:" << std::distance(outputBegin, outputEnd) << ", used:" << std::distance(outputBegin, outputIter); - return ss.str(); - }(); - - LOG(error) << exceptionText; - throw std::runtime_error(exceptionText); - } - t.stop(); LOG(debug1) << "Encoder::" << __func__ << " {ProcessedBytes: " << inputBufferSize * sizeof(source_T) << "," << " inclusiveTimeMS: " << t.getDurationMS() << "," @@ -187,16 +102,13 @@ const stream_IT Encoder<coder_T, stream_T, source_T>::Encoder::process(const str #if !defined(NDEBUG) const auto inputBufferSizeB = inputBufferSize * sizeof(source_T); - const auto outputBufferSizeB = std::distance(outputBegin, outputIter) * sizeof(stream_T); LOG(debug2) << "EncoderProperties: {" << "sourceTypeB: " << sizeof(source_T) << ", " << "streamTypeB: " << sizeof(stream_T) << ", " << "coderTypeB: " << sizeof(coder_T) << ", " - << "probabilityBits: " << mProbabilityBits << ", " - << "inputBufferSizeB: " << inputBufferSizeB << ", " - << "outputBufferSizeB: " << outputBufferSizeB << ", " - << "compressionFactor: " << std::fixed << std::setprecision(2) << static_cast<double>(inputBufferSizeB) / static_cast<double>(outputBufferSizeB) << "}"; + << "probabilityBits: " << this->mSymbolTablePrecission << ", " + << "inputBufferSizeB: " << inputBufferSizeB << "}"; #endif LOG(trace) << "done encoding"; diff --git a/Utilities/rANS/include/rANS/FrequencyTable.h b/Utilities/rANS/include/rANS/FrequencyTable.h index 789a3ab599919..a93c0a22b50ab 100644 --- a/Utilities/rANS/include/rANS/FrequencyTable.h +++ b/Utilities/rANS/include/rANS/FrequencyTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -27,7 +28,7 @@ #include <fairlogger/Logger.h> -#include "internal/helper.h" +#include "rANS/internal/helper.h" namespace o2 { @@ -40,91 +41,101 @@ std::ostream& operator<<(std::ostream& out, const FrequencyTable& fTable); class FrequencyTable { public: - using value_t = int32_t; + using symbol_t = int32_t; + using count_t = uint32_t; + using iterator_t = count_t*; + using constIterator_t = const count_t*; + using histogram_t = std::vector<count_t>; - FrequencyTable() : mMin(0), mMax(0), mNumSamples(0), mFrequencyTable(){}; + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + FrequencyTable() noexcept {}; //NOLINT - FrequencyTable(value_t min, value_t max) : mMin(min), mMax(max), mNumSamples(0), mFrequencyTable(mMax - mMin + 1, 0) - { - assert(mMax >= mMin); - } + FrequencyTable(symbol_t min, symbol_t max) : mMin{min}, mMax{max}, mFrequencyTable(max - min + 1, 0) { assert(mMax >= mMin); }; + + template <typename Source_IT, std::enable_if_t<internal::isIntegralIter_v<Source_IT>, bool> = true> + void addSamples(Source_IT begin, Source_IT end); - FrequencyTable(size_t range) : FrequencyTable(0, internal::bitsToRange(range) - 1) - { - assert(range >= 1); - }; + template <typename Source_IT, std::enable_if_t<internal::isIntegralIter_v<Source_IT>, bool> = true> + void addSamples(Source_IT begin, Source_IT end, symbol_t min, symbol_t max); - template <typename Source_IT> - void addSamples(Source_IT begin, Source_IT end, value_t min = 0, value_t max = 0); + template <typename Freq_IT, std::enable_if_t<internal::isIntegralIter_v<Freq_IT>, bool> = true> + void addFrequencies(Freq_IT begin, Freq_IT end, symbol_t min, symbol_t max); - template <typename Freq_IT> - void addFrequencies(Freq_IT begin, Freq_IT end, value_t min, value_t max); + inline count_t operator[](symbol_t symbol) const { return getSymbol(symbol); }; - value_t operator[](value_t index) const; + count_t at(size_t index) const; - size_t size() const; + inline size_t size() const { return mFrequencyTable.size(); }; - const uint32_t* data() const; + inline const count_t* data() const noexcept { return mFrequencyTable.data(); }; - const uint32_t* cbegin() const; + inline constIterator_t cbegin() const noexcept { return data(); }; - const uint32_t* cend() const; + inline constIterator_t cend() const noexcept { return data() + size(); }; - uint32_t* begin(); + inline constIterator_t begin() const noexcept { return cbegin(); }; - uint32_t* end(); + inline constIterator_t end() const noexcept { return cend(); }; - const uint32_t* begin() const; + inline iterator_t begin() noexcept { return const_cast<iterator_t>(cbegin()); }; - const uint32_t* end() const; + inline iterator_t end() noexcept { return const_cast<iterator_t>(cend()); }; FrequencyTable& operator+(FrequencyTable& other); - value_t getMinSymbol() const; - value_t getMaxSymbol() const; + inline histogram_t&& release() && noexcept; + + inline symbol_t getMinSymbol() const noexcept { return mNumSamples == 0 ? 0 : mMin; }; + inline symbol_t getMaxSymbol() const noexcept { return mNumSamples == 0 ? 0 : mMax; }; - size_t getAlphabetRangeBits() const; + inline size_t getAlphabetRangeBits() const noexcept { return internal::numBitsForNSymbols(mFrequencyTable.size()); }; - size_t getNumSamples() const; + inline size_t getNumSamples() const noexcept { return mNumSamples; }; - size_t getUsedAlphabetSize() const; + size_t getNUsedAlphabetSymbols() const noexcept; private: - void resizeFrequencyTable(value_t min, value_t max); + void resizeFrequencyTable(symbol_t min, symbol_t max); - value_t mMin; - value_t mMax; - size_t mNumSamples; - std::vector<uint32_t> mFrequencyTable; + const count_t& getSymbol(symbol_t symbol) const; + count_t& getSymbol(symbol_t symbol); + + histogram_t mFrequencyTable{}; + symbol_t mMin{std::numeric_limits<symbol_t>::max()}; + symbol_t mMax{std::numeric_limits<symbol_t>::min()}; + size_t mNumSamples{}; }; -template <typename Source_IT> -void FrequencyTable::addSamples(Source_IT begin, Source_IT end, value_t min, value_t max) +template <typename Source_IT, std::enable_if_t<internal::isIntegralIter_v<Source_IT>, bool>> +void FrequencyTable::addSamples(Source_IT begin, Source_IT end) { - static_assert(std::is_integral<typename std::iterator_traits<Source_IT>::value_type>::value); + if (begin != end) { + const auto& [minIter, maxIter] = std::minmax_element(begin, end); + addSamples(begin, end, *minIter, *maxIter); + } else { + LOG(warning) << "Passed empty message to " << __func__; // RS this is ok for empty columns + return; + } +} +template <typename Source_IT, std::enable_if_t<internal::isIntegralIter_v<Source_IT>, bool>> +void FrequencyTable::addSamples(Source_IT begin, Source_IT end, symbol_t min, symbol_t max) +{ LOG(trace) << "start adding samples"; internal::RANSTimer t; t.start(); if (begin == end) { - LOG(debug) << "Passed empty message to " << __func__; // RS this is ok for empty columns + LOG(warning) << "Passed empty message to " << __func__; // RS this is ok for empty columns return; } - if (min == max) { - const auto& [minIter, maxIter] = std::minmax_element(begin, end); - resizeFrequencyTable(*minIter, *maxIter); + resizeFrequencyTable(min, max); - } else { - resizeFrequencyTable(min, max); - } + // add new symbols + std::for_each(begin, end, [this](symbol_t symbol) { ++this->getSymbol(symbol); }); - for (auto it = begin; it != end; ++it) { - assert((*it - mMin) < mFrequencyTable.size()); - mFrequencyTable[*it - mMin]++; - } - mNumSamples = std::distance(begin, end); + mNumSamples += std::distance(begin, end); t.stop(); LOG(debug1) << __func__ << " inclusive time (ms): " << t.getDurationMS(); @@ -135,8 +146,8 @@ void FrequencyTable::addSamples(Source_IT begin, Source_IT end, value_t min, val LOG(trace) << "done adding samples"; } -template <typename Freq_IT> -void FrequencyTable::addFrequencies(Freq_IT begin, Freq_IT end, value_t min, value_t max) +template <typename Freq_IT, std::enable_if_t<internal::isIntegralIter_v<Freq_IT>, bool>> +void FrequencyTable::addFrequencies(Freq_IT begin, Freq_IT end, symbol_t min, symbol_t max) { static_assert(std::is_integral<typename std::iterator_traits<Freq_IT>::value_type>::value); @@ -145,7 +156,7 @@ void FrequencyTable::addFrequencies(Freq_IT begin, Freq_IT end, value_t min, val t.start(); if (begin == end) { - LOG(debug) << "Passed empty FrequencyTable to " << __func__; // RS this is ok for empty columns + LOG(warning) << "Passed empty FrequencyTable to " << __func__; // RS this is ok for empty columns return; } @@ -159,7 +170,7 @@ void FrequencyTable::addFrequencies(Freq_IT begin, Freq_IT end, value_t min, val std::transform(begin, end, mFrequencyTable.begin() + offset, mFrequencyTable.begin() + offset, - [this](typename std::iterator_traits<Freq_IT>::value_type first, uint32_t second) { + [this](typename std::iterator_traits<Freq_IT>::value_type first, count_t second) { mNumSamples += first; return first + second; }); @@ -173,87 +184,45 @@ void FrequencyTable::addFrequencies(Freq_IT begin, Freq_IT end, value_t min, val LOG(trace) << "done adding frequencies"; } -inline typename FrequencyTable::value_t FrequencyTable::operator[](value_t index) const +inline auto FrequencyTable::at(size_t index) const -> count_t { - const value_t idx = index - mMin; - assert(idx >= 0); - assert(idx < mFrequencyTable.size()); + assert(index < size()); return mFrequencyTable[index]; -} - -inline size_t FrequencyTable::size() const -{ - return mFrequencyTable.size(); -} - -inline const uint32_t* FrequencyTable::data() const -{ - return mFrequencyTable.data(); -} - -inline const uint32_t* FrequencyTable::cbegin() const -{ - return mFrequencyTable.data(); -} - -inline const uint32_t* FrequencyTable::cend() const -{ - return mFrequencyTable.data() + mFrequencyTable.size(); -} - -inline uint32_t* FrequencyTable::begin() -{ - return const_cast<uint32_t*>(static_cast<const FrequencyTable*>(this)->begin()); -} - -inline uint32_t* FrequencyTable::end() -{ - return const_cast<uint32_t*>(static_cast<const FrequencyTable*>(this)->end()); -} - -inline const uint32_t* FrequencyTable::begin() const -{ - return cbegin(); -} - -inline const uint32_t* FrequencyTable::end() const -{ - return cend(); -} +}; inline FrequencyTable& FrequencyTable::operator+(FrequencyTable& other) { - addFrequencies(std::begin(other), std::end(other), other.getMinSymbol(), other.getMaxSymbol()); + addFrequencies(other.cbegin(), other.cend(), other.getMinSymbol(), other.getMaxSymbol()); return *this; } -inline typename FrequencyTable::value_t FrequencyTable::getMinSymbol() const +inline auto FrequencyTable::release() && noexcept -> histogram_t&& { - return mMin; -} + mMin = 0; + mMax = 0; + mNumSamples = 0; + return std::move(mFrequencyTable); +}; -inline typename FrequencyTable::value_t FrequencyTable::getMaxSymbol() const +inline size_t FrequencyTable::getNUsedAlphabetSymbols() const noexcept { - return mMax; + return std::count_if(cbegin(), cend(), [](count_t count) { return count > 0; }); } -inline size_t FrequencyTable::getAlphabetRangeBits() const +inline auto FrequencyTable::getSymbol(symbol_t symbol) const -> const count_t& { - if (mMax - mMin > 0) { - return std::ceil(std::log2(mMax - mMin)); - } else if (mMax - mMin == 0) { - return 1; - } else { - return 0; - } + //negative numbers cause overflow thus we get away with one comparison only + const size_t index = static_cast<size_t>(symbol - mMin); + assert(index < mFrequencyTable.size()); + return mFrequencyTable[index]; } -inline size_t FrequencyTable::getNumSamples() const +inline auto FrequencyTable::getSymbol(symbol_t symbol) -> count_t& { - return mNumSamples; + return const_cast<count_t&>(static_cast<const FrequencyTable&>(*this).getSymbol(symbol)); } -} // namespace rans -} // namespace o2 +} // namespace rans +} // namespace o2 #endif /* INCLUDE_RANS_FREQUENCYTABLE_H_ */ diff --git a/Utilities/rANS/include/rANS/LiteralDecoder.h b/Utilities/rANS/include/rANS/LiteralDecoder.h index 4e8b2716184c9..5e3921de79e3b 100644 --- a/Utilities/rANS/include/rANS/LiteralDecoder.h +++ b/Utilities/rANS/include/rANS/LiteralDecoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,14 +22,16 @@ #include <cstddef> #include <type_traits> #include <iostream> +#include <iomanip> #include <string> #include <fairlogger/Logger.h> -#include "internal/DecoderSymbol.h" -#include "internal/ReverseSymbolLookupTable.h" -#include "internal/SymbolTable.h" -#include "internal/Decoder.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/ReverseSymbolLookupTable.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/internal/Decoder.h" +#include "rANS/internal/DecoderBase.h" namespace o2 { @@ -36,27 +39,26 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class LiteralDecoder : public Decoder<coder_T, stream_T, source_T> +class LiteralDecoder : public internal::DecoderBase<coder_T, stream_T, source_T> { - //inherit constructors; - using Decoder<coder_T, stream_T, source_T>::Decoder; - public: - template <typename stream_IT, typename source_IT> - void process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength, std::vector<source_T>& literals) const; + using internal::DecoderBase<coder_T, stream_T, source_T>::DecoderBase; + + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool> = true> + void process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength, std::vector<source_T>& literals) const; + + private: + using ransDecoder_t = typename internal::DecoderBase<coder_T, stream_T, source_T>::ransDecoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -void LiteralDecoder<coder_T, stream_T, source_T>::process(const source_IT outputBegin, const stream_IT inputEnd, size_t messageLength, std::vector<source_T>& literals) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<stream_T, stream_IT>, bool>> +void LiteralDecoder<coder_T, stream_T, source_T>::process(stream_IT inputEnd, source_IT outputBegin, size_t messageLength, std::vector<source_T>& literals) const { using namespace internal; - using ransDecoder = internal::Decoder<coder_T, stream_T>; LOG(trace) << "start decoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); if (messageLength == 0) { LOG(warning) << "Empty message passed to decoder, skipping decode process"; @@ -66,22 +68,23 @@ void LiteralDecoder<coder_T, stream_T, source_T>::process(const source_IT output stream_IT inputIter = inputEnd; source_IT it = outputBegin; - auto decode = [&, this](ransDecoder& decoder) { - auto cumul = decoder.get(this->mProbabilityBits); - const auto streamSymbol = (*this->mReverseLUT)[cumul]; + auto decode = [&, this](ransDecoder_t& decoder) { + const auto cumul = decoder.get(); + const auto streamSymbol = (this->mReverseLUT)[cumul]; source_T symbol = streamSymbol; - if (this->mSymbolTable->isRareSymbol(streamSymbol)) { + if (this->mSymbolTable.isEscapeSymbol(streamSymbol)) { symbol = literals.back(); literals.pop_back(); } - return std::make_tuple(symbol, decoder.advanceSymbol(inputIter, (*this->mSymbolTable)[streamSymbol], this->mProbabilityBits)); + return std::make_tuple(symbol, decoder.advanceSymbol(inputIter, (this->mSymbolTable)[streamSymbol])); }; // make Iter point to the last last element --inputIter; - ransDecoder rans0, rans1; + ransDecoder_t rans0{this->mSymbolTablePrecission}; + ransDecoder_t rans1{this->mSymbolTablePrecission}; inputIter = rans0.init(inputIter); inputIter = rans1.init(inputIter); diff --git a/Utilities/rANS/include/rANS/LiteralEncoder.h b/Utilities/rANS/include/rANS/LiteralEncoder.h index 989ee035cb5e5..d7d6ab1095e17 100644 --- a/Utilities/rANS/include/rANS/LiteralEncoder.h +++ b/Utilities/rANS/include/rANS/LiteralEncoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,8 +17,6 @@ #ifndef RANS_LITERAL_ENCODER_H #define RANS_LITERAL_ENCODER_H -#include "Encoder.h" - #include <memory> #include <algorithm> #include <iomanip> @@ -25,9 +24,10 @@ #include <fairlogger/Logger.h> #include <stdexcept> -#include "internal/EncoderSymbol.h" -#include "internal/helper.h" -#include "internal/SymbolTable.h" +#include "rANS/internal/EncoderBase.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" +#include "rANS/internal/SymbolTable.h" namespace o2 { @@ -35,87 +35,65 @@ namespace rans { template <typename coder_T, typename stream_T, typename source_T> -class LiteralEncoder : public Encoder<coder_T, stream_T, source_T> +class LiteralEncoder : public internal::EncoderBase<coder_T, stream_T, source_T> { - //inherit constructors; - using Encoder<coder_T, stream_T, source_T>::Encoder; public: - template <typename stream_IT, typename source_IT> - const stream_IT process(const stream_IT outputBegin, const stream_IT outputEnd, - const source_IT inputBegin, source_IT inputEnd, std::vector<source_T>& literals) const; + //inherit constructors; + using internal::EncoderBase<coder_T, stream_T, source_T>::EncoderBase; + + template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool> = true> + stream_IT process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, std::vector<source_T>& literals) const; + + private: + using ransCoder_t = typename internal::EncoderBase<coder_T, stream_T, source_T>::ransCoder_t; }; template <typename coder_T, typename stream_T, typename source_T> -template <typename stream_IT, typename source_IT> -const stream_IT LiteralEncoder<coder_T, stream_T, source_T>::process(const stream_IT outputBegin, const stream_IT outputEnd, const source_IT inputBegin, const source_IT inputEnd, std::vector<source_T>& literals) const +template <typename stream_IT, typename source_IT, std::enable_if_t<internal::isCompatibleIter_v<source_T, source_IT>, bool>> +stream_IT LiteralEncoder<coder_T, stream_T, source_T>::process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, std::vector<source_T>& literals) const { using namespace internal; - using ransCoder = internal::Encoder<coder_T, stream_T>; LOG(trace) << "start encoding"; RANSTimer t; t.start(); - static_assert(std::is_same<typename std::iterator_traits<source_IT>::value_type, source_T>::value); - static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); - if (inputBegin == inputEnd) { LOG(warning) << "passed empty message to encoder, skip encoding"; - return outputEnd; + return outputBegin; } - if (outputBegin == outputEnd) { - const std::string errorMessage("Unallocated encode buffer passed to encoder. Aborting"); - LOG(error) << errorMessage; - throw std::runtime_error(errorMessage); - } - - ransCoder rans0, rans1; + ransCoder_t rans0{this->mSymbolTablePrecission}; + ransCoder_t rans1{this->mSymbolTablePrecission}; stream_IT outputIter = outputBegin; source_IT inputIT = inputEnd; const auto inputBufferSize = std::distance(inputBegin, inputEnd); - auto encode = [&literals, this](source_IT symbolIter, stream_IT outputIter, ransCoder& coder) { + auto encode = [&literals, this](source_IT symbolIter, stream_IT outputIter, ransCoder_t& coder) { const source_T symbol = *symbolIter; - const auto& encoderSymbol = (*this->mSymbolTable)[symbol]; - if (this->mSymbolTable->isRareSymbol(symbol)) { + const auto& encoderSymbol = (this->mSymbolTable)[symbol]; + if (this->mSymbolTable.isEscapeSymbol(symbol)) { literals.push_back(symbol); } - return std::tuple(symbolIter, coder.putSymbol(outputIter, encoderSymbol, this->mProbabilityBits)); + return coder.putSymbol(outputIter, encoderSymbol); }; // odd number of bytes? if (inputBufferSize & 1) { - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans0); - assert(outputIter < outputEnd); + outputIter = encode(--inputIT, outputIter, rans0); } - while (inputIT > inputBegin) { // NB: working in reverse! - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans1); - std::tie(inputIT, outputIter) = encode(--inputIT, outputIter, rans0); - assert(outputIter < outputEnd); + while (inputIT != inputBegin) { // NB: working in reverse! + outputIter = encode(--inputIT, outputIter, rans1); + outputIter = encode(--inputIT, outputIter, rans0); } outputIter = rans1.flush(outputIter); outputIter = rans0.flush(outputIter); // first iterator past the range so that sizes, distances and iterators work correctly. ++outputIter; - assert(!(outputIter > outputEnd)); - - // deal with overflow - if (outputIter > outputEnd) { - const std::string exceptionText = [&]() { - std::stringstream ss; - ss << __func__ << " detected overflow in encode buffer: allocated:" << std::distance(outputBegin, outputEnd) << ", used:" << std::distance(outputBegin, outputIter); - return ss.str(); - }(); - - LOG(error) << exceptionText; - throw std::runtime_error(exceptionText); - } - t.stop(); LOG(debug1) << "Encoder::" << __func__ << " {ProcessedBytes: " << inputBufferSize * sizeof(source_T) << "," << " inclusiveTimeMS: " << t.getDurationMS() << "," @@ -125,16 +103,13 @@ const stream_IT LiteralEncoder<coder_T, stream_T, source_T>::process(const strea #if !defined(NDEBUG) const auto inputBufferSizeB = inputBufferSize * sizeof(source_T); - const auto outputBufferSizeB = std::distance(outputBegin, outputIter) * sizeof(stream_T); LOG(debug2) << "EncoderProperties: {" << "sourceTypeB: " << sizeof(source_T) << ", " << "streamTypeB: " << sizeof(stream_T) << ", " << "coderTypeB: " << sizeof(coder_T) << ", " - << "probabilityBits: " << this->mProbabilityBits << ", " - << "inputBufferSizeB: " << inputBufferSizeB << ", " - << "outputBufferSizeB: " << outputBufferSizeB << ", " - << "compressionFactor: " << std::fixed << std::setprecision(2) << static_cast<double>(inputBufferSizeB) / static_cast<double>(outputBufferSizeB) << "}"; + << "probabilityBits: " << this->mSymbolTablePrecission << ", " + << "inputBufferSizeB: " << inputBufferSizeB << "}"; #endif LOG(trace) << "done encoding"; diff --git a/Utilities/rANS/include/rANS/internal/Decoder.h b/Utilities/rANS/include/rANS/internal/Decoder.h index d983a1f91a34d..b987960e58b7e 100644 --- a/Utilities/rANS/include/rANS/internal/Decoder.h +++ b/Utilities/rANS/include/rANS/internal/Decoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,9 +23,9 @@ #include <tuple> #include <type_traits> -#include "DecoderSymbol.h" -#include "EncoderSymbol.h" -#include "helper.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" namespace o2 { @@ -34,128 +35,128 @@ namespace internal { __extension__ typedef unsigned __int128 uint128; -template <typename State_T, typename Stream_T> +template <typename state_T, typename stream_T> class Decoder { // the Coder works either with a 64Bit state and 32 bit streaming or //a 32 Bit state and 8 Bit streaming We need to make sure it gets initialized with //the right template arguments at compile time. - static_assert((sizeof(State_T) == sizeof(uint32_t) && sizeof(Stream_T) == sizeof(uint8_t)) || - (sizeof(State_T) == sizeof(uint64_t) && sizeof(Stream_T) == sizeof(uint32_t)), + static_assert((sizeof(state_T) == sizeof(uint32_t) && sizeof(stream_T) == sizeof(uint8_t)) || + (sizeof(state_T) == sizeof(uint64_t) && sizeof(stream_T) == sizeof(uint32_t)), "Coder can either be 32Bit with 8 Bit stream type or 64 Bit Type with 32 Bit stream type"); public: - Decoder(); + explicit Decoder(size_t symbolTablePrecission) noexcept; // Initializes a rANS decoder. // Unlike the encoder, the decoder works forwards as you'd expect. - template <typename Stream_IT> - Stream_IT init(Stream_IT iter); + template <typename stream_IT> + stream_IT init(stream_IT inputIter); // Returns the current cumulative frequency (map it to a symbol yourself!) - uint32_t get(uint32_t scale_bits); + uint32_t get(); // Equivalent to Rans32DecAdvance that takes a symbol. - template <typename Stream_IT> - Stream_IT advanceSymbol(Stream_IT iter, const DecoderSymbol& sym, uint32_t scale_bits); + template <typename stream_IT> + stream_IT advanceSymbol(stream_IT inputIter, const DecoderSymbol& sym); private: - State_T mState; + state_T mState{}; + size_t mSymbolTablePrecission{}; // Renormalize. - template <typename Stream_IT> - std::tuple<State_T, Stream_IT> renorm(State_T x, Stream_IT iter); + template <typename stream_IT> + std::tuple<state_T, stream_IT> renorm(state_T x, stream_IT iter); // L ('l' in the paper) is the lower bound of our normalization interval. // Between this and our byte-aligned emission, we use 31 (not 32!) bits. // This is done intentionally because exact reciprocals for 31-bit uints // fit in 32-bit uints: this permits some optimizations during encoding. - inline static constexpr State_T LOWER_BOUND = needs64Bit<State_T>() ? (1u << 31) : (1u << 23); // lower bound of our normalization interval + inline static constexpr state_T LOWER_BOUND = needs64Bit<state_T>() ? (1u << 31) : (1u << 23); // lower bound of our normalization interval - inline static constexpr State_T STREAM_BITS = sizeof(Stream_T) * 8; // lower bound of our normalization interval + inline static constexpr state_T STREAM_BITS = sizeof(stream_T) * 8; // lower bound of our normalization interval }; -template <typename State_T, typename Stream_T> -Decoder<State_T, Stream_T>::Decoder() : mState(0){}; +template <typename state_T, typename stream_T> +Decoder<state_T, stream_T>::Decoder(size_t symbolTablePrecission) noexcept : mSymbolTablePrecission{symbolTablePrecission} {}; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -Stream_IT Decoder<State_T, Stream_T>::init(Stream_IT iter) +template <typename state_T, typename stream_T> +template <typename stream_IT> +stream_IT Decoder<state_T, stream_T>::init(stream_IT inputIter) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); - State_T x = 0; - Stream_IT streamPos = iter; + state_T newState = 0; + stream_IT streamPosition = inputIter; - if constexpr (needs64Bit<State_T>()) { - x = static_cast<State_T>(*streamPos) << 0; - --streamPos; - x |= static_cast<State_T>(*streamPos) << 32; - --streamPos; - assert(std::distance(streamPos, iter) == 2); + if constexpr (needs64Bit<state_T>()) { + newState = static_cast<state_T>(*streamPosition) << 0; + --streamPosition; + newState |= static_cast<state_T>(*streamPosition) << 32; + --streamPosition; + assert(std::distance(streamPosition, inputIter) == 2); } else { - x = static_cast<State_T>(*streamPos) << 0; - --streamPos; - x |= static_cast<State_T>(*streamPos) << 8; - --streamPos; - x |= static_cast<State_T>(*streamPos) << 16; - --streamPos; - x |= static_cast<State_T>(*streamPos) << 24; - --streamPos; - assert(std::distance(streamPos, iter) == 4); + newState = static_cast<state_T>(*streamPosition) << 0; + --streamPosition; + newState |= static_cast<state_T>(*streamPosition) << 8; + --streamPosition; + newState |= static_cast<state_T>(*streamPosition) << 16; + --streamPosition; + newState |= static_cast<state_T>(*streamPosition) << 24; + --streamPosition; + assert(std::distance(streamPosition, inputIter) == 4); } - mState = x; - return streamPos; + mState = newState; + return streamPosition; }; -template <typename State_T, typename Stream_T> -uint32_t Decoder<State_T, Stream_T>::get(uint32_t scale_bits) +template <typename state_T, typename stream_T> +uint32_t Decoder<state_T, stream_T>::get() { - return mState & ((1u << scale_bits) - 1); + return mState & ((pow2(mSymbolTablePrecission)) - 1); }; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -Stream_IT Decoder<State_T, Stream_T>::advanceSymbol(Stream_IT iter, const DecoderSymbol& sym, uint32_t scale_bits) +template <typename state_T, typename stream_T> +template <typename stream_IT> +stream_IT Decoder<state_T, stream_T>::advanceSymbol(stream_IT inputIter, const DecoderSymbol& symbol) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); + static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); - State_T mask = (1ull << scale_bits) - 1; + state_T mask = (pow2(mSymbolTablePrecission)) - 1; // s, x = D(x) - State_T x = mState; - x = sym.freq * (x >> scale_bits) + (x & mask) - sym.start; + state_T newState = mState; + newState = symbol.getFrequency() * (newState >> mSymbolTablePrecission) + (newState & mask) - symbol.getCumulative(); // renormalize - Stream_IT streamPos; - std::tie(mState, streamPos) = this->renorm(x, iter); - return streamPos; + const auto [renormedState, newStreamPosition] = this->renorm(newState, inputIter); + mState = renormedState; + return newStreamPosition; }; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -inline std::tuple<State_T, Stream_IT> Decoder<State_T, Stream_T>::renorm(State_T x, Stream_IT iter) +template <typename state_T, typename stream_T> +template <typename stream_IT> +inline std::tuple<state_T, stream_IT> Decoder<state_T, stream_T>::renorm(state_T state, stream_IT inputIter) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); + static_assert(std::is_same<typename std::iterator_traits<stream_IT>::value_type, stream_T>::value); - Stream_IT streamPos = iter; + stream_IT streamPosition = inputIter; // renormalize - if (x < LOWER_BOUND) { - if constexpr (needs64Bit<State_T>()) { - x = (x << STREAM_BITS) | *streamPos; - --streamPos; - assert(x >= LOWER_BOUND); + if (state < LOWER_BOUND) { + if constexpr (needs64Bit<state_T>()) { + state = (state << STREAM_BITS) | *streamPosition; + --streamPosition; + assert(state >= LOWER_BOUND); } else { do { - x = (x << STREAM_BITS) | *streamPos; - --streamPos; - } while (x < LOWER_BOUND); + state = (state << STREAM_BITS) | *streamPosition; + --streamPosition; + } while (state < LOWER_BOUND); } } - return std::make_tuple(x, streamPos); + return std::make_tuple(state, streamPosition); } } // namespace internal diff --git a/Utilities/rANS/include/rANS/internal/DecoderBase.h b/Utilities/rANS/include/rANS/internal/DecoderBase.h new file mode 100644 index 0000000000000..0aecd31ed3196 --- /dev/null +++ b/Utilities/rANS/include/rANS/internal/DecoderBase.h @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DecoderBase.h +/// @author michael.lettrich@cern.ch +/// @since Feb 8, 2021 +/// @brief + +#ifndef INCLUDE_RANS_INTERNAL_DECODERBASE_H_ +#define INCLUDE_RANS_INTERNAL_DECODERBASE_H_ + +#include <cstddef> +#include <type_traits> +#include <iostream> +#include <memory> + +#include <fairlogger/Logger.h> + +#include "rANS/FrequencyTable.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/ReverseSymbolLookupTable.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/internal/Decoder.h" +#include "rANS/internal/SymbolStatistics.h" +#include "rANS/internal/helper.h" + +namespace o2 +{ +namespace rans +{ +namespace internal +{ + +template <typename coder_T, typename stream_T, typename source_T> +class DecoderBase +{ + + protected: + using decoderSymbolTable_t = internal::SymbolTable<internal::DecoderSymbol>; + using reverseSymbolLookupTable_t = internal::ReverseSymbolLookupTable; + using ransDecoder_t = Decoder<coder_T, stream_T>; + + public: + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + DecoderBase() noexcept {}; //NOLINT + DecoderBase(const FrequencyTable& stats, size_t probabilityBits); + + inline size_t getAlphabetRangeBits() const noexcept { return mSymbolTable.getAlphabetRangeBits(); } + inline size_t getSymbolTablePrecision() const noexcept { return mSymbolTablePrecission; } + inline int getMinSymbol() const noexcept { return mSymbolTable.getMinSymbol(); } + inline int getMaxSymbol() const noexcept { return mSymbolTable.getMaxSymbol(); } + + using coder_t = coder_T; + using stream_t = stream_T; + using source_t = source_T; + + protected: + size_t mSymbolTablePrecission{}; + decoderSymbolTable_t mSymbolTable{}; + reverseSymbolLookupTable_t mReverseLUT{}; +}; + +template <typename coder_T, typename stream_T, typename source_T> +DecoderBase<coder_T, stream_T, source_T>::DecoderBase(const FrequencyTable& frequencies, size_t probabilityBits) : mSymbolTablePrecission{probabilityBits} +{ + using namespace internal; + + SymbolStatistics stats{frequencies, mSymbolTablePrecission}; + mSymbolTablePrecission = stats.getSymbolTablePrecision(); + + RANSTimer t; + t.start(); + mSymbolTable = decoderSymbolTable_t{stats}; + t.stop(); + LOG(debug1) << "Decoder SymbolTable inclusive time (ms): " << t.getDurationMS(); + t.start(); + mReverseLUT = reverseSymbolLookupTable_t{stats}; + t.stop(); + LOG(debug1) << "ReverseSymbolLookupTable inclusive time (ms): " << t.getDurationMS(); +}; +} // namespace internal +} // namespace rans +} // namespace o2 + +#endif /* INCLUDE_RANS_INTERNAL_DECODERBASE_H_ */ diff --git a/Utilities/rANS/include/rANS/internal/DecoderSymbol.h b/Utilities/rANS/include/rANS/internal/DecoderSymbol.h index b35a690fd8b3b..1b93c36fc96e0 100644 --- a/Utilities/rANS/include/rANS/internal/DecoderSymbol.h +++ b/Utilities/rANS/include/rANS/internal/DecoderSymbol.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -17,6 +18,8 @@ #define RANS_INTERNAL_DECODERSYMBOL_H #include <cstdint> +#include <cstring> +#include <cassert> namespace o2 { @@ -26,18 +29,27 @@ namespace internal { // Decoder symbols are straightforward. -struct DecoderSymbol { +class DecoderSymbol +{ + public: + using count_t = uint32_t; + + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + constexpr DecoderSymbol() noexcept {}; //NOLINT // Initialize a decoder symbol to start "start" and frequency "freq" - DecoderSymbol(uint32_t start, uint32_t freq, uint32_t probabilityBits) - : start(start), freq(freq) + constexpr DecoderSymbol(count_t frequency, count_t cumulative, size_t symbolTablePrecision) + : mCumulative(cumulative), mFrequency(frequency) { - (void)probabilityBits; // silence compiler warnings if assert not compiled. - assert(start <= (1 << probabilityBits)); - assert(freq <= (1 << probabilityBits) - start); + (void)symbolTablePrecision; // silence compiler warnings if assert not compiled. + assert(mCumulative <= pow2(symbolTablePrecision)); + assert(mFrequency <= pow2(symbolTablePrecision) - mCumulative); }; + inline constexpr count_t getFrequency() const noexcept { return mFrequency; }; + inline constexpr count_t getCumulative() const noexcept { return mCumulative; }; - uint32_t start; // Start of range. - uint32_t freq; // Symbol frequency. + private: + count_t mCumulative{}; // Start of range. + count_t mFrequency{}; // Symbol frequency. }; } // namespace internal } // namespace rans diff --git a/Utilities/rANS/include/rANS/internal/Encoder.h b/Utilities/rANS/include/rANS/internal/Encoder.h index c3e9c9fb04b89..8684a2104d6b4 100644 --- a/Utilities/rANS/include/rANS/internal/Encoder.h +++ b/Utilities/rANS/include/rANS/internal/Encoder.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -22,9 +23,9 @@ #include <type_traits> #include <tuple> -#include "DecoderSymbol.h" -#include "EncoderSymbol.h" -#include "helper.h" +#include "rANS/internal/DecoderSymbol.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" namespace o2 { @@ -33,159 +34,119 @@ namespace rans namespace internal { -template <typename State_T, typename Stream_T> +template <typename state_T, typename stream_T> class Encoder { - __extension__ typedef unsigned __int128 uint128; + __extension__ using uint128_t = unsigned __int128; // the Coder works either with a 64Bit state and 32 bit streaming or //a 32 Bit state and 8 Bit streaming We need to make sure it gets initialized with //the right template arguments at compile time. - static_assert((sizeof(State_T) == sizeof(uint32_t) && sizeof(Stream_T) == sizeof(uint8_t)) || - (sizeof(State_T) == sizeof(uint64_t) && sizeof(Stream_T) == sizeof(uint32_t)), + static_assert((sizeof(state_T) == sizeof(uint32_t) && sizeof(stream_T) == sizeof(uint8_t)) || + (sizeof(state_T) == sizeof(uint64_t) && sizeof(stream_T) == sizeof(uint32_t)), "Coder can either be 32Bit with 8 Bit stream type or 64 Bit Type with 32 Bit stream type"); public: - Encoder(); - - // Encodes a single symbol with range start "start" and frequency "freq". - // All frequencies are assumed to sum to "1 << scale_bits", and the - // resulting bytes get written to ptr (which is updated). - // - // NOTE: With rANS, you need to encode symbols in *reverse order*, i.e. from - // beginning to end! Likewise, the output bytestream is written *backwards*: - // ptr starts pointing at the end of the output buffer and keeps decrementing. - template <typename Stream_IT> - Stream_IT put(Stream_IT iter, uint32_t start, uint32_t freq, uint32_t scale_bits); - - // Flushes the rANS encoder. - template <typename Stream_IT> - Stream_IT flush(Stream_IT iter); - - // Encodes a given symbol. This is faster than straight RansEnc since we can do - // multiplications instead of a divide. - // - // See Rans32EncSymbolInit for a description of how this works. - template <typename Stream_IT> - Stream_IT putSymbol(Stream_IT iter, const EncoderSymbol<State_T>& sym, uint32_t scale_bits); + explicit Encoder(size_t symbolTablePrecission) noexcept; + + template <typename stream_IT> + stream_IT flush(stream_IT outputIter); + + // Encodes a given symbol. + template <typename stream_IT> + stream_IT putSymbol(stream_IT outputIter, const EncoderSymbol<state_T>& symbol); private: - State_T mState; + state_T mState{LOWER_BOUND}; + size_t mSymbolTablePrecission{}; // Renormalize the encoder. - template <typename Stream_IT> - std::tuple<State_T, Stream_IT> renorm(State_T x, Stream_IT iter, uint32_t freq, uint32_t scale_bits); + template <typename stream_IT> + std::tuple<state_T, stream_IT> renorm(state_T state, stream_IT outputIter, uint32_t frequency); // L ('l' in the paper) is the lower bound of our normalization interval. // Between this and our byte-aligned emission, we use 31 (not 32!) bits. // This is done intentionally because exact reciprocals for 31-bit uints // fit in 32-bit uints: this permits some optimizations during encoding. - inline static constexpr State_T LOWER_BOUND = needs64Bit<State_T>() ? (1u << 31) : (1u << 23); // lower bound of our normalization interval + inline static constexpr state_T LOWER_BOUND = needs64Bit<state_T>() ? (1u << 31) : (1u << 23); // lower bound of our normalization interval - inline static constexpr State_T STREAM_BITS = sizeof(Stream_T) * 8; // lower bound of our normalization interval + inline static constexpr state_T STREAM_BITS = sizeof(stream_T) * 8; // lower bound of our normalization interval }; -template <typename State_T, typename Stream_T> -Encoder<State_T, Stream_T>::Encoder() : mState(LOWER_BOUND){}; +template <typename state_T, typename stream_T> +Encoder<state_T, stream_T>::Encoder(size_t symbolTablePrecission) noexcept : mSymbolTablePrecission(symbolTablePrecission){}; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -Stream_IT Encoder<State_T, Stream_T>::put(Stream_IT iter, uint32_t start, uint32_t freq, uint32_t scale_bits) +template <typename state_T, typename stream_T> +template <typename stream_IT> +stream_IT Encoder<state_T, stream_T>::flush(stream_IT outputIter) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); - // renormalize - Stream_IT streamPos; - State_T x; - std::tie(x, streamPos) = renorm(mState, iter, freq, scale_bits); - - // x = C(s,x) - mState = ((x / freq) << scale_bits) + (x % freq) + start; - return streamPos; -}; - -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -Stream_IT Encoder<State_T, Stream_T>::flush(Stream_IT iter) -{ - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); - - Stream_IT streamPos = iter; - - if constexpr (needs64Bit<State_T>()) { - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 32); - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 0); - assert(std::distance(iter, streamPos) == 2); + stream_IT streamPosition = outputIter; + if constexpr (needs64Bit<state_T>()) { + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 32); + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 0); } else { - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 24); - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 16); - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 8); - ++streamPos; - *streamPos = static_cast<Stream_T>(mState >> 0); - assert(std::distance(iter, streamPos) == 4); + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 24); + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 16); + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 8); + ++streamPosition; + *streamPosition = static_cast<stream_T>(mState >> 0); } - mState = 0; - return streamPos; + return streamPosition; }; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -Stream_IT Encoder<State_T, Stream_T>::putSymbol(Stream_IT iter, const EncoderSymbol<State_T>& sym, uint32_t scale_bits) +template <typename state_T, typename stream_T> +template <typename stream_IT> +stream_IT Encoder<state_T, stream_T>::putSymbol(stream_IT outputIter, const EncoderSymbol<state_T>& symbol) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); - assert(sym.freq != 0); // can't encode symbol with freq=0 + assert(symbol.getFrequency() != 0); // can't encode symbol with freq=0 // renormalize - Stream_IT streamPos; - State_T x; - std::tie(x, streamPos) = renorm(mState, iter, sym.freq, scale_bits); + const auto [newState, streamPosition] = renorm(mState, outputIter, symbol.getFrequency()); // x = C(s,x) - State_T q = 0; + state_T quotient = 0; - if constexpr (needs64Bit<State_T>()) { + if constexpr (needs64Bit<state_T>()) { // This code needs support for 64-bit long multiplies with 128-bit result // (or more precisely, the top 64 bits of a 128-bit result). - q = static_cast<State_T>((static_cast<uint128>(x) * sym.rcp_freq) >> 64); + quotient = static_cast<state_T>((static_cast<uint128_t>(newState) * symbol.getReciprocalFrequency()) >> 64); } else { - q = static_cast<State_T>((static_cast<uint64_t>(x) * sym.rcp_freq) >> 32); + quotient = static_cast<state_T>((static_cast<uint64_t>(newState) * symbol.getReciprocalFrequency()) >> 32); } - q = q >> sym.rcp_shift; + quotient = quotient >> symbol.getReciprocalShift(); - mState = x + sym.bias + q * sym.cmpl_freq; - return streamPos; + mState = newState + symbol.getBias() + quotient * symbol.getFrequencyComplement(); + return streamPosition; }; -template <typename State_T, typename Stream_T> -template <typename Stream_IT> -inline std::tuple<State_T, Stream_IT> Encoder<State_T, Stream_T>::renorm(State_T x, Stream_IT iter, uint32_t freq, uint32_t scale_bits) +template <typename state_T, typename stream_T> +template <typename stream_IT> +inline std::tuple<state_T, stream_IT> Encoder<state_T, stream_T>::renorm(state_T state, stream_IT outputIter, uint32_t frequency) { - static_assert(std::is_same<typename std::iterator_traits<Stream_IT>::value_type, Stream_T>::value); - - Stream_IT streamPos = iter; - - State_T x_max = ((LOWER_BOUND >> scale_bits) << STREAM_BITS) * freq; // this turns into a shift. - if (x >= x_max) { - if constexpr (needs64Bit<State_T>()) { - ++streamPos; - *streamPos = static_cast<Stream_T>(x); - x >>= STREAM_BITS; - assert(x < x_max); + state_T maxState = ((LOWER_BOUND >> mSymbolTablePrecission) << STREAM_BITS) * frequency; // this turns into a shift. + if (state >= maxState) { + if constexpr (needs64Bit<state_T>()) { + ++outputIter; + *outputIter = static_cast<stream_T>(state); + state >>= STREAM_BITS; + assert(state < maxState); } else { do { - ++streamPos; - *streamPos = static_cast<Stream_T>(x & 0xff); - x >>= STREAM_BITS; - } while (x >= x_max); + ++outputIter; + //stream out 8 Bits + *outputIter = static_cast<stream_T>(state & 0xff); + state >>= STREAM_BITS; + } while (state >= maxState); } } - return std::make_tuple(x, streamPos); + return std::make_tuple(state, outputIter); }; } // namespace internal diff --git a/Utilities/rANS/include/rANS/internal/EncoderBase.h b/Utilities/rANS/include/rANS/internal/EncoderBase.h new file mode 100644 index 0000000000000..c3fdf9f6e5335 --- /dev/null +++ b/Utilities/rANS/include/rANS/internal/EncoderBase.h @@ -0,0 +1,91 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file EncoderBase.h +/// @author michael.lettrich@cern.ch +/// @since Feb 8, 2021 +/// @brief + +#ifndef INCLUDE_RANS_INTERNAL_ENCODERBASE_H_ +#define INCLUDE_RANS_INTERNAL_ENCODERBASE_H_ + +#include <memory> +#include <algorithm> +#include <iomanip> + +#include <fairlogger/Logger.h> +#include <stdexcept> + +#include "rANS/internal/Encoder.h" +#include "rANS/internal/EncoderSymbol.h" +#include "rANS/internal/helper.h" +#include "rANS/internal/SymbolTable.h" +#include "rANS/FrequencyTable.h" + +namespace o2 +{ +namespace rans +{ +namespace internal +{ + +template <typename coder_T, typename stream_T, typename source_T> +class EncoderBase +{ + protected: + using encoderSymbolTable_t = typename internal::SymbolTable<internal::EncoderSymbol<coder_T>>; + + public: + using symbol_t = typename FrequencyTable::symbol_t; + + using coder_t = coder_T; + using stream_t = stream_T; + using source_t = source_T; + + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + EncoderBase() noexcept {}; //NOLINT + EncoderBase(encoderSymbolTable_t&& e, size_t symbolTablePrecission) noexcept; + EncoderBase(const FrequencyTable& frequencies, size_t symbolTablePrecission); + + inline size_t getSymbolTablePrecision() const noexcept { return mSymbolTablePrecission; } + inline size_t getAlphabetRangeBits() const noexcept { return mSymbolTable.getAlphabetRangeBits(); } + inline symbol_t getMinSymbol() const noexcept { return mSymbolTable.getMinSymbol(); } + inline symbol_t getMaxSymbol() const noexcept { return mSymbolTable.getMaxSymbol(); } + + protected: + encoderSymbolTable_t mSymbolTable{}; + size_t mSymbolTablePrecission{}; + + using ransCoder_t = typename internal::Encoder<coder_T, stream_T>; +}; + +template <typename coder_T, typename stream_T, typename source_T> +EncoderBase<coder_T, stream_T, source_T>::EncoderBase(encoderSymbolTable_t&& e, size_t symbolTablePrecission) noexcept : mSymbolTable{std::move(e)}, mSymbolTablePrecission{symbolTablePrecission} {}; + +template <typename coder_T, typename stream_T, typename source_T> +EncoderBase<coder_T, stream_T, source_T>::EncoderBase(const FrequencyTable& frequencies, + size_t symbolTablePrecission) : mSymbolTablePrecission{symbolTablePrecission} +{ + SymbolStatistics stats{frequencies, mSymbolTablePrecission}; + mSymbolTablePrecission = stats.getSymbolTablePrecision(); + + RANSTimer t; + t.start(); + mSymbolTable = encoderSymbolTable_t{stats}; + t.stop(); + LOG(debug1) << "Encoder SymbolTable inclusive time (ms): " << t.getDurationMS(); +} + +} // namespace internal +} // namespace rans +} // namespace o2 + +#endif /* INCLUDE_RANS_INTERNAL_ENCODERBASE_H_ */ diff --git a/Utilities/rANS/include/rANS/internal/EncoderSymbol.h b/Utilities/rANS/include/rANS/internal/EncoderSymbol.h index 08fccf7fff284..d9e9c48b3e364 100644 --- a/Utilities/rANS/include/rANS/internal/EncoderSymbol.h +++ b/Utilities/rANS/include/rANS/internal/EncoderSymbol.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,7 +20,7 @@ #include <cstdint> #include <cassert> -#include "helper.h" +#include "rANS/internal/helper.h" namespace o2 { @@ -32,37 +33,46 @@ namespace internal // RansEncPutSymbol as cheap as possible. template <typename T> -struct EncoderSymbol { - EncoderSymbol(uint32_t start, uint32_t freq, uint32_t scale_bits) +class EncoderSymbol +{ + private: + __extension__ using uint128_t = unsigned __int128; + + public: + using count_t = uint32_t; + + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + constexpr EncoderSymbol() noexcept {}; //NOLINT + + constexpr EncoderSymbol(count_t frequency, count_t cumulative, size_t symbolTablePrecision) { - // RansAssert(scale_bits <= 16); - assert(start <= (1u << scale_bits)); - assert(freq <= (1u << scale_bits) - start); + assert(cumulative <= pow2(symbolTablePrecision)); + assert(frequency <= pow2(symbolTablePrecision) - cumulative); - // Say M := 1 << scale_bits. + // Say M := 1 << symbolTablePrecision. // // The original encoder does: - // x_new = (x/freq)*M + start + (x%freq) + // x_new = (x/frequency)*M + cumulative + (x%frequency) // // The fast encoder does (schematically): // q = mul_hi(x, rcp_freq) >> rcp_shift (division) - // r = x - q*freq (remainder) + // r = x - q*frequency (remainder) // x_new = q*M + bias + r (new x) // plugging in r into x_new yields: - // x_new = bias + x + q*(M - freq) + // x_new = bias + x + q*(M - frequency) // =: bias + x + q*cmpl_freq (*) // // and we can just precompute cmpl_freq. Now we just need to // set up our parameters such that the original encoder and // the fast encoder agree. - this->freq = freq; - this->cmpl_freq = static_cast<T>((1 << scale_bits) - freq); - if (freq < 2) { - // freq=0 symbols are never valid to encode, so it doesn't matter what + mFrequency = frequency; + mFrequencyComplement = static_cast<T>((pow2(symbolTablePrecision)) - frequency); + if (frequency < 2) { + // frequency=0 symbols are never valid to encode, so it doesn't matter what // we set our values to. // - // freq=1 is tricky, since the reciprocal of 1 is 1; unfortunately, + // frequency=1 is tricky, since the reciprocal of 1 is 1; unfortunately, // our fixed-point reciprocal approximation can only multiply by values // smaller than 1. // @@ -75,56 +85,58 @@ struct EncoderSymbol { // and we know that x>0 (x=0 is never in a valid normalization interval). // // So we now need to choose the other parameters such that - // x_new = x*M + start + // x_new = x*M + cumulative // plug it in: - // x*M + start (desired result) + // x*M + cumulative (desired result) // = bias + x + q*cmpl_freq (*) // = bias + x + (x - 1)*(M - 1) (plug in q=x-1, cmpl_freq) // = bias + 1 + (x - 1)*M // = x*M + (bias + 1 - M) // - // so we have start = bias + 1 - M, or equivalently - // bias = start + M - 1. - this->rcp_freq = static_cast<T>(~0ul); - this->rcp_shift = 0; - this->bias = start + (1 << scale_bits) - 1; + // so we have cumulative = bias + 1 - M, or equivalently + // bias = cumulative + M - 1. + mReciprocalFrequency = static_cast<T>(~0ul); + mReciprocalShift = 0; + mBias = cumulative + (pow2(symbolTablePrecision)) - 1; } else { // Alverson, "Integer Division using reciprocals" - // shift=ceil(log2(freq)) - uint32_t shift = 0; - while (freq > (1u << shift)) { - shift++; - } + const uint32_t shift = std::ceil(std::log2(frequency)); if constexpr (needs64Bit<T>()) { - uint64_t x0, x1, t0, t1; - // long divide ((uint128) (1 << (shift + 63)) + freq-1) / freq + // long divide ((uint128) (1 << (shift + 63)) + frequency-1) / frequency // by splitting it into two 64:64 bit divides (this works because // the dividend has a simple form.) - x0 = freq - 1; - x1 = 1ull << (shift + 31); + uint64_t x0 = frequency - 1; + const uint64_t x1 = 1ull << (shift + 31); - t1 = x1 / freq; - x0 += (x1 % freq) << 32; - t0 = x0 / freq; + const uint64_t t1 = x1 / frequency; + x0 += (x1 % frequency) << 32; + const uint64_t t0 = x0 / frequency; - this->rcp_freq = t0 + (t1 << 32); + mReciprocalFrequency = t0 + (t1 << 32); } else { - this->rcp_freq = static_cast<uint32_t>(((1ull << (shift + 31)) + freq - 1) / freq); + mReciprocalFrequency = static_cast<count_t>(((1ull << (shift + 31)) + frequency - 1) / frequency); } - this->rcp_shift = shift - 1; + mReciprocalShift = shift - 1; // With these values, 'q' is the correct quotient, so we - // have bias=start. - this->bias = start; + // have bias=cumulative. + mBias = cumulative; } }; - T rcp_freq; // Fixed-point reciprocal frequency - uint32_t freq; // (Exclusive) upper bound of pre-normalization interval - uint32_t bias; // Bias - uint32_t cmpl_freq; // Complement of frequency: (1 << scale_bits) - freq - uint32_t rcp_shift; // Reciprocal shift + inline constexpr T getReciprocalFrequency() const noexcept { return mReciprocalFrequency; }; + inline constexpr count_t getFrequency() const noexcept { return mFrequency; }; + inline constexpr count_t getBias() const noexcept { return mBias; }; + inline constexpr count_t getFrequencyComplement() const noexcept { return mFrequencyComplement; }; + inline constexpr count_t getReciprocalShift() const noexcept { return mReciprocalShift; }; + + private: + T mReciprocalFrequency{}; // Fixed-point reciprocal frequency + count_t mFrequency{}; // (Exclusive) upper bound of pre-normalization interval + count_t mBias{}; // Bias + count_t mFrequencyComplement{}; // Complement of frequency: (1 << symbolTablePrecision) - frequency + count_t mReciprocalShift{}; // Reciprocal shift }; } // namespace internal diff --git a/Utilities/rANS/include/rANS/internal/ReverseSymbolLookupTable.h b/Utilities/rANS/include/rANS/internal/ReverseSymbolLookupTable.h index 7b10a3a6d5fc3..2037f9a77ce07 100644 --- a/Utilities/rANS/include/rANS/internal/ReverseSymbolLookupTable.h +++ b/Utilities/rANS/include/rANS/internal/ReverseSymbolLookupTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,8 +21,8 @@ #include <type_traits> #include <fairlogger/Logger.h> -#include "helper.h" -#include "SymbolStatistics.h" +#include "rANS/internal/helper.h" +#include "rANS/internal/SymbolStatistics.h" namespace o2 { @@ -33,35 +34,26 @@ namespace internal class ReverseSymbolLookupTable { public: - ReverseSymbolLookupTable(size_t probabilityBits, - const SymbolStatistics& stats) : mLut() + using symbol_t = SymbolStatistics::symbol_t; + using count_t = SymbolStatistics::count_t; + using iterator_t = const symbol_t*; + + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + ReverseSymbolLookupTable() noexcept {}; //NOLINT + + explicit ReverseSymbolLookupTable(const SymbolStatistics& symbolStats) { LOG(trace) << "start building reverse symbol lookup table"; - if (stats.size() == 1) { - LOG(warning) << "SymbolStatistics of empty message passed to " << __func__; - return; - } - - mLut.resize(bitsToRange(probabilityBits)); + mLut.resize(pow2(symbolStats.getSymbolTablePrecision())); // go over all symbols - for (auto symbolIT = std::begin(stats); symbolIT != std::end(stats); ++symbolIT) { - auto symbol = stats.getMinSymbol() + std::distance(std::begin(stats), symbolIT); - const auto [symFrequency, symCumulated] = *symbolIT; - for (auto cumulative = symCumulated; - cumulative < symCumulated + symFrequency; cumulative++) { + for (size_t index = 0; index < symbolStats.size(); ++index) { + const symbol_t symbol = symbolStats.getMinSymbol() + index; + const auto [symFrequency, symCumulated] = symbolStats.at(index); + for (count_t cumulative = symCumulated; cumulative < symCumulated + symFrequency; cumulative++) { mLut[cumulative] = symbol; } } - -// for (int symbol = stats.getMinSymbol(); symbol <= stats.getMaxSymbol(); -// symbol++) { -// for (uint32_t cumulative = stats[symbol].second; -// cumulative < stats[symbol].second + stats[symbol].first; cumulative++) { -// mLut[cumulative] = symbol; -// } -// } - // advanced diagnostics for debug builds #if !defined(NDEBUG) LOG(debug2) << "reverseSymbolLookupTableProperties: {" @@ -69,16 +61,24 @@ class ReverseSymbolLookupTable << "sizeB: " << mLut.size() * sizeof(typename std::decay_t<decltype(mLut)>::value_type) << "}"; #endif + if (symbolStats.size() == 1) { + LOG(warning) << "SymbolStatistics of empty message passed to " << __func__; + } + LOG(trace) << "done building reverse symbol lookup table"; }; - inline int32_t operator[](size_t cummulative) const + inline size_t size() const noexcept { return mLut.size(); }; + inline symbol_t operator[](count_t cumul) const noexcept { - return mLut[cummulative]; + assert(cumul < size()); + return mLut[cumul]; }; + inline iterator_t begin() const noexcept { return mLut.data(); }; + inline iterator_t end() const noexcept { return mLut.data() + size(); }; private: - std::vector<int32_t> mLut; + std::vector<symbol_t> mLut{}; }; } // namespace internal diff --git a/Utilities/rANS/include/rANS/internal/SymbolStatistics.h b/Utilities/rANS/include/rANS/internal/SymbolStatistics.h index 18af55e313c6c..a496169a698bc 100644 --- a/Utilities/rANS/include/rANS/internal/SymbolStatistics.h +++ b/Utilities/rANS/include/rANS/internal/SymbolStatistics.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,17 +20,18 @@ #include <algorithm> #include <cassert> #include <iostream> +#include <cstdint> #include <numeric> #include <vector> #include <cmath> -#include <iterator> -#include <type_traits> #include <fairlogger/Logger.h> -#include "helper.h" +#include "rANS/internal/helper.h" #include "rANS/FrequencyTable.h" +#include "rANS/utils/iterators.h" + namespace o2 { namespace rans @@ -37,231 +39,121 @@ namespace rans namespace internal { -constexpr size_t MIN_SCALE = 16; -constexpr size_t MAX_SCALE = 27; +inline constexpr size_t MIN_SCALE = 16; +inline constexpr size_t MAX_SCALE = 27; -class SymbolStatistics +namespace detail +{ +class MergingFunctor { - public: - class Iterator + template <typename iterA_T, typename iterB_T> + auto operator()(iterA_T iterA, iterB_T iterB) const -> std::tuple<typename std::iterator_traits<iterA_T>::value_type, + typename std::iterator_traits<iterB_T>::value_type> { - public: - Iterator(size_t index, const SymbolStatistics& stats) : mIndex(index), mStats(stats){}; - - using difference_type = int64_t; - using value_type = std::tuple<uint32_t, uint32_t>; - using pointer = const std::tuple<uint32_t, uint32_t>*; - using reference = const std::tuple<uint32_t, uint32_t>&; - using iterator_category = std::random_access_iterator_tag; - - const Iterator& operator++(); - - const Iterator& operator--(); - - difference_type operator-(const Iterator& other) const; - - difference_type operator-(size_t idx) const; - - const Iterator& operator-(size_t idx); - - value_type operator*() const; - - bool operator!=(const Iterator& other) const; - - private: - size_t mIndex; - const SymbolStatistics& mStats; - }; + return {*iterA, *iterB}; + } +}; +} // namespace detail +class SymbolStatistics +{ public: - SymbolStatistics(const FrequencyTable& frequencyTable, size_t scaleBits = 0); + using count_t = FrequencyTable::count_t; + using symbol_t = FrequencyTable::symbol_t; + using pair_t = std::tuple<count_t, count_t>; + using histogram_t = std::vector<count_t>; - template <typename Source_IT> - SymbolStatistics(const Source_IT begin, const Source_IT end, int64_t min, int64_t max, size_t scaleBits, size_t nUsedAlphabetSymbols); - - std::tuple<uint32_t, uint32_t> operator[](int64_t index) const; - std::tuple<uint32_t, uint32_t> at(size_t pos) const; + SymbolStatistics(const FrequencyTable& frequencyTable, size_t scaleBits = 0); + SymbolStatistics(FrequencyTable&& frequencyTable, size_t scaleBits = 0); - Iterator begin() const; - Iterator end() const; + template <typename Source_IT, std::enable_if_t<isCompatibleIter_v<count_t, Source_IT>, bool> = true> + SymbolStatistics(Source_IT begin, + Source_IT end, + symbol_t min, + size_t scaleBits, + size_t nUsedAlphabetSymbols); - Iterator getEscapeSymbol() const; + pair_t operator[](symbol_t symbol) const; + pair_t at(size_t index) const; + inline size_t size() const noexcept { return mFrequencyTable.size(); }; - size_t size() const; + auto begin() const noexcept; + inline auto end() const noexcept; - int64_t getMinSymbol() const; - int64_t getMaxSymbol() const; + inline pair_t getEscapeSymbol() const noexcept { return {mFrequencyTable.back(), mCumulativeFrequencyTable.back()}; }; - size_t getNUsedAlphabetSymbols() const; + inline symbol_t getMinSymbol() const noexcept { return mMin; }; + inline symbol_t getMaxSymbol() const noexcept { return getMinSymbol() + size() - 1; }; - size_t getSymbolTablePrecision() const; + inline size_t getAlphabetRangeBits() const noexcept { return numBitsForNSymbols(size()); }; + inline size_t getNUsedAlphabetSymbols() const noexcept { return mNUsedAlphabetSymbols; }; + inline size_t getSymbolTablePrecision() const noexcept { return mSymbolTablePrecission; }; private: + SymbolStatistics(symbol_t min, size_t scaleBits, size_t nUsedAlphabetSymbols, histogram_t&& frequencies); + void buildCumulativeFrequencyTable(); void rescale(); - int64_t mMin; - int64_t mMax; - size_t mScaleBits; - size_t mNUsedAlphabetSymbols; - - std::vector<uint32_t> mFrequencyTable; - std::vector<uint32_t> mCumulativeFrequencyTable; + histogram_t mFrequencyTable{}; + histogram_t mCumulativeFrequencyTable{}; + symbol_t mMin{}; + size_t mSymbolTablePrecission{}; + size_t mNUsedAlphabetSymbols{}; static constexpr size_t MAX_RANGE = 26; }; -template <typename Source_IT> -SymbolStatistics::SymbolStatistics(const Source_IT begin, const Source_IT end, int64_t min, int64_t max, size_t scaleBits, size_t nUsedAlphabetSymbols) : mMin(min), mMax(max), mScaleBits(scaleBits), mFrequencyTable(), mNUsedAlphabetSymbols(nUsedAlphabetSymbols), mCumulativeFrequencyTable() +template <typename Source_IT, + std::enable_if_t<isCompatibleIter_v<typename SymbolStatistics::count_t, Source_IT>, bool>> +inline SymbolStatistics::SymbolStatistics(Source_IT begin, + Source_IT end, + symbol_t min, + size_t scaleBits, + size_t nUsedAlphabetSymbols) : SymbolStatistics{ + min, + scaleBits, + nUsedAlphabetSymbols, + histogram_t{begin, end}} { - - using namespace internal; - LOG(trace) << "start building symbol statistics"; - RANSTimer t; - t.start(); - - if (begin == end) { - LOG(debug) << "Passed empty message to " << __func__; // RS this is ok for empty columns - return; - } - - // if we did not calculate renormalization size, calculate it. - if (scaleBits == 0) { - mScaleBits = [&, this]() { - const size_t minScale = MIN_SCALE; - const size_t maxScale = MAX_SCALE; - const size_t calculated = static_cast<uint32_t>(3 * std::ceil(std::log2(getNUsedAlphabetSymbols())) / 2 + 2); - return std::max(minScale, std::min(maxScale, calculated)); - }(); - } - - //additional bit for escape symbol - mFrequencyTable.reserve(std::distance(begin, end) + 1); - - mFrequencyTable.insert(mFrequencyTable.begin(), begin, end); - //incompressible symbol - mFrequencyTable.push_back(1); - - // range check - if (mMax - mMin > 1 << (MAX_RANGE - 1)) { - const std::string errmsg = [&]() { - std::stringstream ss; - ss << "Range of source message " << std::ceil(std::log2(mMax - mMin)) << "Bits surpasses maximal allowed range of " << MAX_RANGE << "Bits."; - return ss.str(); - }(); - LOG(error) << errmsg; - throw std::runtime_error(errmsg); - } - - buildCumulativeFrequencyTable(); - rescale(); - - assert(mFrequencyTable.size() > 1); - assert(mCumulativeFrequencyTable.size() > 2); - assert(mCumulativeFrequencyTable.size() - mFrequencyTable.size() == 1); - - t.stop(); - LOG(debug1) << __func__ << " inclusive time (ms): " << t.getDurationMS(); - -// advanced diagnostics in debug builds -#if !defined(NDEBUG) - LOG(debug2) << "SymbolStatistics: {" - << "entries: " << mFrequencyTable.size() << ", " - << "frequencyTableSizeB: " << mFrequencyTable.size() * sizeof(typename std::decay_t<decltype(mFrequencyTable)>::value_type) << ", " - << "CumulativeFrequencyTableSizeB: " << mCumulativeFrequencyTable.size() * sizeof(typename std::decay_t<decltype(mCumulativeFrequencyTable)>::value_type) << "}"; -#endif - - LOG(trace) << "done building symbol statistics"; } -inline int64_t SymbolStatistics::getMinSymbol() const -{ - return mMin; -} +inline SymbolStatistics::SymbolStatistics(const FrequencyTable& frequencyTable, size_t scaleBits) : SymbolStatistics{ + frequencyTable.getMinSymbol(), + scaleBits, + frequencyTable.getNUsedAlphabetSymbols(), + histogram_t(frequencyTable.begin(), frequencyTable.end())} {}; -inline int64_t SymbolStatistics::getMaxSymbol() const -{ - return mMax; -} +inline SymbolStatistics::SymbolStatistics(FrequencyTable&& frequencyTable, size_t scaleBits) : SymbolStatistics{ + frequencyTable.getMinSymbol(), + scaleBits, + frequencyTable.getNUsedAlphabetSymbols(), + std::move(frequencyTable).release()} {}; -inline size_t SymbolStatistics::size() const +inline auto SymbolStatistics::begin() const noexcept { - return mFrequencyTable.size(); -} - -inline size_t SymbolStatistics::getSymbolTablePrecision() const + return utils::CombinedInputIterator(mFrequencyTable.begin(), mCumulativeFrequencyTable.begin(), detail::MergingFunctor{}); +}; +inline auto SymbolStatistics::end() const noexcept { - return mScaleBits; -} + return utils::CombinedInputIterator(mFrequencyTable.end(), mCumulativeFrequencyTable.end(), detail::MergingFunctor{}); +}; -inline std::tuple<uint32_t, uint32_t> SymbolStatistics::operator[](int64_t index) const +inline auto SymbolStatistics::operator[](symbol_t symbol) const -> pair_t { - assert(index - mMin < mFrequencyTable.size()); + //negative numbers cause overflow thus we get away with one comparison only + const size_t index = static_cast<size_t>(symbol - mMin); + assert(index < size()); return {mFrequencyTable[index], mCumulativeFrequencyTable[index]}; } -inline std::tuple<uint32_t, uint32_t> SymbolStatistics::at(size_t pos) const -{ - assert(pos < mFrequencyTable.size()); - return {mFrequencyTable[pos], mCumulativeFrequencyTable[pos]}; -} - -inline SymbolStatistics::Iterator SymbolStatistics::begin() const -{ - return SymbolStatistics::Iterator(0, *this); -} - -inline SymbolStatistics::Iterator SymbolStatistics::end() const -{ - return SymbolStatistics::Iterator(mFrequencyTable.size(), *this); -} - -inline SymbolStatistics::Iterator SymbolStatistics::getEscapeSymbol() const -{ - return mFrequencyTable.size() > 0 ? SymbolStatistics::Iterator(mFrequencyTable.size() - 1, *this) : end(); -} - -inline const SymbolStatistics::Iterator& SymbolStatistics::Iterator::operator++() -{ - ++mIndex; - assert(mIndex <= mStats.mFrequencyTable.size()); - return *this; -} - -inline const SymbolStatistics::Iterator& SymbolStatistics::Iterator::operator--() -{ - --mIndex; - assert(mIndex >= 0); - return *this; -} - -inline SymbolStatistics::Iterator::difference_type SymbolStatistics::Iterator::operator-(const Iterator& other) const +inline auto SymbolStatistics::at(size_t index) const -> pair_t { - return mIndex - other.mIndex; -} - -inline SymbolStatistics::Iterator::difference_type SymbolStatistics::Iterator::operator-(size_t index) const -{ - return mIndex - index; -} - -inline const SymbolStatistics::Iterator& SymbolStatistics::Iterator::operator-(size_t index) -{ - mIndex -= index; - return *this; -} - -inline typename SymbolStatistics::Iterator::value_type SymbolStatistics::Iterator::operator*() const -{ - return std::move(mStats.at(mIndex)); -} - -inline bool SymbolStatistics::Iterator::operator!=(const Iterator& other) const -{ - return this->mIndex != other.mIndex; -} + assert(index < size()); + return {mFrequencyTable.at(index), mCumulativeFrequencyTable.at(index)}; +}; } // namespace internal } // namespace rans diff --git a/Utilities/rANS/include/rANS/internal/SymbolTable.h b/Utilities/rANS/include/rANS/internal/SymbolTable.h index d13fb340853db..ff40dd634720c 100644 --- a/Utilities/rANS/include/rANS/internal/SymbolTable.h +++ b/Utilities/rANS/include/rANS/internal/SymbolTable.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -21,7 +22,7 @@ #include <cmath> #include <fairlogger/Logger.h> -#include "SymbolStatistics.h" +#include "rANS/internal/SymbolStatistics.h" namespace o2 { @@ -35,28 +36,34 @@ class SymbolTable { public: - SymbolTable(const SymbolStatistics& symbolStats); + using symbol_t = SymbolStatistics::symbol_t; - const T& operator[](int64_t index) const; + //TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 + SymbolTable() noexcept {}; //NOLINT - const T& getEscapeSymbol() const; + explicit SymbolTable(const SymbolStatistics& symbolStats); - bool isRareSymbol(int64_t index) const; + inline size_t size() const noexcept { return mIndex.size(); }; - size_t getAlphabetRangeBits() const; - int getMinSymbol() const { return mMin; } - int getMaxSymbol() const { return mMax; } + const T& operator[](symbol_t symbol) const noexcept; + inline const T& at(size_t index) const { return *mIndex[index]; }; + inline const T& getEscapeSymbol() const noexcept { return *mEscapeSymbol; }; + inline bool isEscapeSymbol(symbol_t symbol) const noexcept { return &((*this)[symbol]) == mEscapeSymbol.get(); } + + inline size_t getAlphabetRangeBits() const noexcept { return numBitsForNSymbols(size()); }; + inline size_t getNUsedAlphabetSymbols() const noexcept { return mSymbols.size() + 1; /*all normal symbols plus escape symbol*/ }; + inline symbol_t getMinSymbol() const noexcept { return mMin; }; + inline symbol_t getMaxSymbol() const noexcept { return getMinSymbol() + size() - 1; }; private: - int mMin; - int mMax; - std::vector<T*> mIndex; - std::vector<T> mSymbols; - std::unique_ptr<T> mEscapeSymbol; + std::vector<T*> mIndex{}; + std::vector<T> mSymbols{}; + std::unique_ptr<T> mEscapeSymbol{}; + int mMin{}; }; template <typename T> -SymbolTable<T>::SymbolTable(const SymbolStatistics& symbolStats) : mMin(symbolStats.getMinSymbol()), mMax(symbolStats.getMaxSymbol()), mIndex(), mSymbols(), mEscapeSymbol(nullptr) +SymbolTable<T>::SymbolTable(const SymbolStatistics& symbolStats) : mMin{symbolStats.getMinSymbol()} { LOG(trace) << "start building symbol table"; @@ -64,19 +71,14 @@ SymbolTable<T>::SymbolTable(const SymbolStatistics& symbolStats) : mMin(symbolSt mSymbols.reserve(symbolStats.getNUsedAlphabetSymbols()); mEscapeSymbol = [&]() -> std::unique_ptr<T> { - const auto it = symbolStats.getEscapeSymbol(); - if (it != symbolStats.end()) { - const auto [symFrequency, symCumulated] = *(it); - return std::make_unique<T>(symCumulated, symFrequency, symbolStats.getSymbolTablePrecision()); - } else { - return nullptr; - } + const auto [symFrequency, symCumulated] = symbolStats.getEscapeSymbol(); + return std::make_unique<T>(symFrequency, symCumulated, symbolStats.getSymbolTablePrecision()); }(); - for (auto it = symbolStats.begin(); it != symbolStats.getEscapeSymbol(); ++it) { + for (auto it = symbolStats.begin(); it != --symbolStats.end(); ++it) { const auto [symFrequency, symCumulated] = *it; if (symFrequency) { - mSymbols.emplace_back(symCumulated, symFrequency, symbolStats.getSymbolTablePrecision()); + mSymbols.emplace_back(symFrequency, symCumulated, symbolStats.getSymbolTablePrecision()); mIndex.emplace_back(&mSymbols.back()); } else { mIndex.emplace_back(mEscapeSymbol.get()); @@ -97,49 +99,17 @@ SymbolTable<T>::SymbolTable(const SymbolStatistics& symbolStats) : mMin(symbolSt } template <typename T> -inline const T& SymbolTable<T>::operator[](int64_t index) const +inline const T& SymbolTable<T>::operator[](symbol_t symbol) const noexcept { - const int64_t idx = index - mMin; + const size_t index = static_cast<size_t>(symbol - mMin); // static cast to unsigned: idx < 0 => (uint)idx > MAX_INT => idx > mIndex.size() - if (static_cast<uint64_t>(idx) < mIndex.size()) { - return *(mIndex[idx]); + if (index < mIndex.size()) { + return *(mIndex[index]); } else { return *mEscapeSymbol; } } -template <typename T> -inline bool SymbolTable<T>::isRareSymbol(int64_t index) const -{ - const int64_t idx = index - mMin; - // static cast to unsigned: idx < 0 => (uint)idx > MAX_INT => idx > mIndex.size() - if (static_cast<uint64_t>(idx) < mIndex.size()) { - assert(mEscapeSymbol != nullptr); - return mIndex[idx] == mEscapeSymbol.get(); - } else { - return true; - } -} - -template <typename T> -inline const T& SymbolTable<T>::getEscapeSymbol() const -{ - assert(mEscapeSymbol != nullptr); - return *mEscapeSymbol; -} - -template <typename T> -inline size_t SymbolTable<T>::getAlphabetRangeBits() const -{ - if (mMax - mMin > 0) { - return std::ceil(std::log2(mMax - mMin)); - } else if (mMax - mMin == 0) { - return 1; - } else { - return 0; - } -} - } // namespace internal } // namespace rans } // namespace o2 diff --git a/Utilities/rANS/include/rANS/internal/helper.h b/Utilities/rANS/include/rANS/internal/helper.h index b8c5c46283d43..5a752047ead03 100644 --- a/Utilities/rANS/include/rANS/internal/helper.h +++ b/Utilities/rANS/include/rANS/internal/helper.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -19,6 +20,8 @@ #include <cstddef> #include <cmath> #include <chrono> +#include <type_traits> +#include <iterator> namespace o2 { @@ -28,14 +31,34 @@ namespace internal { template <typename T> -inline constexpr bool needs64Bit() +inline constexpr bool needs64Bit() noexcept { return sizeof(T) > 4; } -inline constexpr size_t bitsToRange(size_t bits) +inline constexpr size_t pow2(size_t n) noexcept { - return 1 << bits; + return 1 << n; +} + +inline constexpr size_t numSymbolsWithNBits(size_t bits) noexcept +{ + return (1 << (bits + 1)) - 1; +} + +inline constexpr size_t numBitsForNSymbols(size_t nSymbols) noexcept +{ + switch (nSymbols) { + case 0: + return 0; // to represent 0 symbols we need 0 bits + break; + case 1: // to represent 1 symbol we need 1 bit + return 1; + break; + default: // general case for > 1 symbols + return std::ceil(std::log2(nSymbols)); + break; + } } class RANSTimer @@ -43,13 +66,13 @@ class RANSTimer public: void start() { mStart = std::chrono::high_resolution_clock::now(); }; void stop() { mStop = std::chrono::high_resolution_clock::now(); }; - double getDurationMS() + inline double getDurationMS() noexcept { std::chrono::duration<double, std::milli> duration = mStop - mStart; return duration.count(); } - double getDurationS() + inline double getDurationS() noexcept { std::chrono::duration<double, std::ratio<1>> duration = mStop - mStart; return duration.count(); @@ -60,6 +83,11 @@ class RANSTimer std::chrono::time_point<std::chrono::high_resolution_clock> mStop; }; +template <typename T, typename IT> +inline constexpr bool isCompatibleIter_v = std::is_convertible_v<typename std::iterator_traits<IT>::value_type, T>; +template <typename IT> +inline constexpr bool isIntegralIter_v = std::is_integral_v<typename std::iterator_traits<IT>::value_type>; + } // namespace internal } // namespace rans } // namespace o2 diff --git a/Utilities/rANS/include/rANS/rans.h b/Utilities/rANS/include/rANS/rans.h index 4353abbec8001..5dfec822ace74 100644 --- a/Utilities/rANS/include/rANS/rans.h +++ b/Utilities/rANS/include/rANS/rans.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,14 +17,14 @@ #ifndef RANS_RANS_H #define RANS_RANS_H -#include "FrequencyTable.h" -#include "Encoder.h" -#include "Decoder.h" -#include "DedupEncoder.h" -#include "DedupDecoder.h" -#include "LiteralEncoder.h" -#include "LiteralDecoder.h" -#include "internal/helper.h" +#include "rANS/FrequencyTable.h" +#include "rANS/Encoder.h" +#include "rANS/Decoder.h" +#include "rANS/DedupEncoder.h" +#include "rANS/DedupDecoder.h" +#include "rANS/LiteralEncoder.h" +#include "rANS/LiteralDecoder.h" +#include "rANS/internal/helper.h" namespace o2 { diff --git a/Utilities/rANS/include/rANS/utils.h b/Utilities/rANS/include/rANS/utils.h new file mode 100644 index 0000000000000..722f3c82e40c3 --- /dev/null +++ b/Utilities/rANS/include/rANS/utils.h @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file utils.h +/// @author Michael Lettrich +/// @since 2020-11-18 +/// @brief header for utils +#ifndef INCLUDE_RANS_UTILS__H_ +#define INCLUDE_RANS_UTILS__H_ + +#include "rANS/utils/iterators.h" + +#endif /* INCLUDE_RANS_UTILS__H_ */ \ No newline at end of file diff --git a/Utilities/rANS/include/rANS/utils/iterators.h b/Utilities/rANS/include/rANS/utils/iterators.h new file mode 100644 index 0000000000000..3561b6f13dd3d --- /dev/null +++ b/Utilities/rANS/include/rANS/utils/iterators.h @@ -0,0 +1,264 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CombinedIterator.h +/// \brief +/// \author michael.lettrich@cern.ch + +#ifndef INCLUDE_RANS_UTILS_COMBINEDITERATOR_H_ +#define INCLUDE_RANS_UTILS_COMBINEDITERATOR_H_ + +#include <cstddef> +#include <cassert> +#include <cstdint> +#include <type_traits> +#include <iostream> +#include <iterator> + +#include <fairlogger/Logger.h> + +namespace o2 +{ +namespace rans +{ +namespace utils +{ + +template <class iterA_T, class iterB_T, class F> +class CombinedInputIterator +{ + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::invoke_result_t<F, iterA_T, iterB_T>; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::bidirectional_iterator_tag; + + CombinedInputIterator() = default; + CombinedInputIterator(iterA_T iterA, iterB_T iterB, F functor); + CombinedInputIterator(const CombinedInputIterator& iter) = default; + CombinedInputIterator(CombinedInputIterator&& iter) = default; + CombinedInputIterator& operator=(const CombinedInputIterator& other); + CombinedInputIterator& operator=(CombinedInputIterator&& other) = default; + ~CombinedInputIterator() = default; + + //comparison + bool operator==(const CombinedInputIterator& other) const; + bool operator!=(const CombinedInputIterator& other) const; + + //pointer arithmetics + CombinedInputIterator& operator++(); + CombinedInputIterator operator++(int); + CombinedInputIterator& operator--(); + CombinedInputIterator operator--(int); + + // dereference + auto operator*() const; + + private: + iterA_T mIterA{}; + iterB_T mIterB{}; + F mFunctor{}; + + public: + friend std::ostream& operator<<(std::ostream& o, const CombinedInputIterator& iter) + { + o << "CombinedInputIterator{iterA: " << &(iter.mIterA) << ", iterB: " << &(iter.mIterB) << "}"; + return o; + } +}; + +template <class input_T, class iterA_T, class iterB_T, class F> +class CombinedOutputIterator +{ + + class Proxy + { + public: + Proxy(CombinedOutputIterator& iter); + + Proxy& operator=(input_T value); + + private: + CombinedOutputIterator* mIter{}; + }; + + public: + using difference_type = std::ptrdiff_t; + using value_type = input_T; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + + CombinedOutputIterator(iterA_T iterA, iterB_T iterB, F functor); + CombinedOutputIterator(const CombinedOutputIterator& iter) = default; + CombinedOutputIterator(CombinedOutputIterator&& iter) = default; + CombinedOutputIterator& operator=(const CombinedOutputIterator& other); + CombinedOutputIterator& operator=(CombinedOutputIterator&& other) = default; + ~CombinedOutputIterator() = default; + + //pointer arithmetics + CombinedOutputIterator& operator++(); + CombinedOutputIterator operator++(int); + + // dereference + Proxy& operator*(); + + private: + iterA_T mIterA{}; + iterB_T mIterB{}; + F mFunctor{}; + Proxy mProxy{*this}; + + public: + friend std::ostream& operator<<(std::ostream& o, const CombinedOutputIterator& iter) + { + o << "CombinedOutputIterator{iterA: " << &(iter.mIterA) << ", iterB: " << &(iter.mIterB) << "}"; + return o; + } +}; + +template <typename input_T> +struct CombinedOutputIteratorFactory { + + template <class iterA_T, class iterB_T, class F> + static inline auto makeIter(iterA_T iterA, iterB_T iterB, F functor) -> CombinedOutputIterator<input_T, iterA_T, iterB_T, F> + { + return {iterA, iterB, functor}; + } +}; + +template <class iterA_T, class iterB_T, class F> +CombinedInputIterator<iterA_T, iterB_T, F>::CombinedInputIterator(iterA_T iterA, iterB_T iterB, F functor) : mIterA{iterA}, mIterB{iterB}, mFunctor{functor} +{ +} + +template <class iterA_T, class iterB_T, class F> +auto CombinedInputIterator<iterA_T, iterB_T, F>::operator=(const CombinedInputIterator& other) -> CombinedInputIterator& +{ + mIterA = other.mIterA; + mIterB = other.mIterB; + return *this; +} + +template <class iterA_T, class iterB_T, class F> +inline bool CombinedInputIterator<iterA_T, iterB_T, F>::operator==(const CombinedInputIterator& other) const +{ + return (mIterA == other.mIterA) && (mIterB == other.mIterB); +} + +template <class iterA_T, class iterB_T, class F> +inline bool CombinedInputIterator<iterA_T, iterB_T, F>::operator!=(const CombinedInputIterator& other) const +{ + return !(*this == other); +} + +template <class iterA_T, class iterB_T, class F> +inline auto CombinedInputIterator<iterA_T, iterB_T, F>::operator++() -> CombinedInputIterator& +{ + ++mIterA; + ++mIterB; + return *this; +} + +template <class iterA_T, class iterB_T, class F> +inline auto CombinedInputIterator<iterA_T, iterB_T, F>::operator++(int) -> CombinedInputIterator +{ + auto res = *this; + ++(*this); + return res; +} + +template <class iterA_T, class iterB_T, class F> +inline auto CombinedInputIterator<iterA_T, iterB_T, F>::operator--() -> CombinedInputIterator& +{ + --mIterA; + --mIterB; + return *this; +} + +template <class iterA_T, class iterB_T, class F> +inline auto CombinedInputIterator<iterA_T, iterB_T, F>::operator--(int) -> CombinedInputIterator +{ + auto res = *this; + --(*this); + return res; +} + +template <class iterA_T, class iterB_T, class F> +inline auto CombinedInputIterator<iterA_T, iterB_T, F>::operator*() const +{ + return mFunctor(mIterA, mIterB); +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::CombinedOutputIterator(iterA_T iterA, iterB_T iterB, F functor) : mIterA{iterA}, mIterB{iterB}, mFunctor{functor} +{ +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +auto CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::operator=(const CombinedOutputIterator& other) -> CombinedOutputIterator& +{ + mIterA = other.mIterA; + mIterB = other.mIterB; + return *this; +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +inline auto CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::operator++() -> CombinedOutputIterator& +{ + ++mIterA; + ++mIterB; + return *this; +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +inline auto CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::operator++(int) -> CombinedOutputIterator +{ + auto res = *this; + ++(*this); + return res; +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +inline auto CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::operator*() -> Proxy& +{ + mProxy = {*this}; + return mProxy; +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::Proxy::Proxy(CombinedOutputIterator& iter) : mIter{&iter} +{ +} + +template <typename input_T, class iterA_T, class iterB_T, class F> +inline auto CombinedOutputIterator<input_T, iterA_T, iterB_T, F>::Proxy::operator=(input_T value) -> Proxy& +{ + mIter->mFunctor(mIter->mIterA, mIter->mIterB, value); + return *this; +} + +template <typename IT> +void checkBounds(IT iteratorPosition, IT upperBound) +{ + const auto diff = std::distance(iteratorPosition, upperBound); + if (diff < 0) { + throw std::runtime_error(fmt::format("Bounds of buffer violated by {} elements", std::abs(diff))); + } +} + +} // namespace utils +} // namespace rans +} // namespace o2 + +#endif /* INCLUDE_RANS_UTILS_COMBINEDITERATOR_H_ */ diff --git a/Utilities/rANS/run/bin-encode-decode.cxx b/Utilities/rANS/run/bin-encode-decode.cxx index a3af57b308e0e..04353773dd47e 100644 --- a/Utilities/rANS/run/bin-encode-decode.cxx +++ b/Utilities/rANS/run/bin-encode-decode.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ /// @brief benchmark encode/decode using rans on binary data. #include "rANS/rans.h" +#include "rANS/utils.h" #include <boost/program_options.hpp> @@ -68,8 +70,7 @@ int main(int argc, char* argv[]) ("file,f",bpo::value<std::string>(), "file to compress") ("samples,s",bpo::value<uint32_t>(), "how often to run benchmark") ("bits,b",bpo::value<uint32_t>(), "resample dictionary to N Bits") - ("range,r",bpo::value<uint32_t>()->default_value(0), "range of the source data") - ("log_severity,l",bpo::value<std::string>(), "severity of FairLogger"); + ("log_severity,l",bpo::value<std::string>(), "severity of FairLogger"); // clang-format on bpo::variables_map vm; @@ -98,14 +99,6 @@ int main(int argc, char* argv[]) } }(); - const uint32_t symbolRangeBits = [&]() { - if (vm.count("range")) { - return vm["range"].as<uint32_t>(); - } else { - return static_cast<uint32_t>(0); - } - }(); - const uint32_t repetitions = [&]() { if (vm.count("samples")) { return vm["samples"].as<uint32_t>(); @@ -125,16 +118,14 @@ int main(int argc, char* argv[]) o2::rans::FrequencyTable frequencies; frequencies.addSamples(std::begin(tokens), std::end(tokens)); - std::vector<stream_t> encoderBuffer(256 << 20, 0); - const auto encodedMessageEnd = [&]() { - const o2::rans::Encoder64<source_t> encoder{frequencies, probabilityBits}; - return encoder.process(encoderBuffer.begin(), encoderBuffer.end(), std::begin(tokens), std::end(tokens)); - }(); + std::vector<stream_t> encoderBuffer; + const o2::rans::Encoder64<source_t> encoder{frequencies, probabilityBits}; + encoder.process(std::begin(tokens), std::end(tokens), std::back_inserter(encoderBuffer)); std::vector<source_t> decoderBuffer(tokens.size()); [&]() { o2::rans::Decoder64<source_t> decoder{frequencies, probabilityBits}; - decoder.process(decoderBuffer.begin(), encodedMessageEnd, std::distance(std::begin(tokens), std::end(tokens))); + decoder.process(encoderBuffer.end(), decoderBuffer.begin(), std::distance(std::begin(tokens), std::end(tokens))); }(); if (std::memcmp(tokens.data(), decoderBuffer.data(), diff --git a/Utilities/rANS/src/FrequencyTable.cxx b/Utilities/rANS/src/FrequencyTable.cxx index 50d638941f373..ef757894cf180 100644 --- a/Utilities/rANS/src/FrequencyTable.cxx +++ b/Utilities/rANS/src/FrequencyTable.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -20,25 +21,25 @@ namespace o2 namespace rans { -void FrequencyTable::resizeFrequencyTable(value_t min, value_t max) +void FrequencyTable::resizeFrequencyTable(symbol_t min, symbol_t max) { LOG(trace) << "start resizing frequency table"; internal::RANSTimer t; t.start(); // calculate new dimensions - const value_t newMin = std::min(mMin, min); - const value_t newMax = std::max(mMax, max); + const symbol_t newMin = std::min(mMin, min); + const symbol_t newMax = std::max(mMax, max); const size_t newSize = newMax - newMin + 1; - // empty - init; - if (mMin == 0 && mMax == 0) { + // empty - init and prevent special treatment of corner cases when resizing. + if (mFrequencyTable.empty()) { mFrequencyTable.resize(newSize, 0); } // if the new size is bigger than the old one we need to resize the frequency table - if ((newSize) > mFrequencyTable.size()) { + if (newSize > mFrequencyTable.size()) { const size_t offset = newMin < mMin ? std::abs(min - mMin) : 0; - std::vector<uint32_t> tmpFrequencyTable; + std::vector<count_t> tmpFrequencyTable; tmpFrequencyTable.reserve(newSize); // insert initial offset if applicable tmpFrequencyTable.insert(std::begin(tmpFrequencyTable), offset, 0); @@ -60,18 +61,6 @@ void FrequencyTable::resizeFrequencyTable(value_t min, value_t max) LOG(trace) << "done resizing frequency table"; } -size_t FrequencyTable::getUsedAlphabetSize() const -{ - size_t nUsedAlphabetSymbols = 0; - - for (auto freq : *this) { - if (freq > 0) { - nUsedAlphabetSymbols++; - } - } - return nUsedAlphabetSymbols; -} - std::ostream& operator<<(std::ostream& out, const FrequencyTable& fTable) { double entropy = 0; @@ -85,11 +74,11 @@ std::ostream& operator<<(std::ostream& out, const FrequencyTable& fTable) out << "FrequencyTable: {" << "numSymbols: " << fTable.getNumSamples() << ", " << "alphabetRange: " << fTable.getAlphabetRangeBits() << ", " - << "alphabetSize: " << fTable.getUsedAlphabetSize() << ", " + << "alphabetSize: " << fTable.getNUsedAlphabetSymbols() << ", " << "minSymbol: " << fTable.getMinSymbol() << ", " << "maxSymbol: " << fTable.getMaxSymbol() << ", " << "sizeFrequencyTableB: " << fTable.size() << ", " - << "sizeFrequencyTableB: " << fTable.size() * sizeof(typename o2::rans::FrequencyTable::value_t) << ", " + << "sizeFrequencyTableB: " << fTable.size() * sizeof(typename o2::rans::FrequencyTable::symbol_t) << ", " << "entropy: " << entropy << "}"; return out; diff --git a/Utilities/rANS/src/SymbolStatistics.cxx b/Utilities/rANS/src/SymbolStatistics.cxx index ca9934b236443..051507744dd40 100644 --- a/Utilities/rANS/src/SymbolStatistics.cxx +++ b/Utilities/rANS/src/SymbolStatistics.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,12 +26,78 @@ namespace rans namespace internal { -SymbolStatistics::SymbolStatistics(const FrequencyTable& frequencyTable, size_t scaleBits) : SymbolStatistics(frequencyTable.begin(), frequencyTable.end(), frequencyTable.getMinSymbol(), frequencyTable.getMaxSymbol(), scaleBits, frequencyTable.getUsedAlphabetSize()){}; +SymbolStatistics::SymbolStatistics(symbol_t min, + size_t scaleBits, + size_t nUsedAlphabetSymbols, + histogram_t&& frequencies) : mFrequencyTable{std::move(frequencies)}, + mMin{min}, + mSymbolTablePrecission{scaleBits}, + mNUsedAlphabetSymbols{nUsedAlphabetSymbols} +{ + + using namespace internal; + LOG(trace) << "start building symbol statistics"; + RANSTimer t; + t.start(); + + // calculate reonormalization size. + mSymbolTablePrecission = [&, this]() { + const size_t minScale = MIN_SCALE; + const size_t maxScale = MAX_SCALE; + size_t calculated = mSymbolTablePrecission > 0 ? mSymbolTablePrecission : static_cast<size_t>(3 * numBitsForNSymbols(this->getNUsedAlphabetSymbols()) / 2 + 2); + calculated = std::max(minScale, std::min(maxScale, calculated)); + if (mSymbolTablePrecission > 0 && calculated != mSymbolTablePrecission) { + LOG(warning) << fmt::format("Normalization interval for rANS SymbolTable of {} Bits is outside of allowed range of {} - {} Bits. Setting to {} Bits", + mSymbolTablePrecission, minScale, maxScale, calculated); + } + return calculated; + }(); + + //add a special symbol for incompressible data; + [this]() { + mFrequencyTable.push_back(1); + ++mNUsedAlphabetSymbols; + }(); + + // range check + if (numBitsForNSymbols(mFrequencyTable.size()) > numSymbolsWithNBits(MAX_RANGE)) { + const std::string errmsg = fmt::format("Alphabet Range of {} Bits of the source message surpasses maximal allowed range of {} Bits.", + numBitsForNSymbols(mFrequencyTable.size()), MAX_RANGE); + LOG(error) << errmsg; + throw std::runtime_error(errmsg); + } + + buildCumulativeFrequencyTable(); + rescale(); + + assert(mFrequencyTable.size() > 0); + assert(mCumulativeFrequencyTable.size() == mFrequencyTable.size()); + + t.stop(); + LOG(debug1) << __func__ << " inclusive time (ms): " << t.getDurationMS(); + +// advanced diagnostics in debug builds +#if !defined(NDEBUG) + LOG(debug2) << "SymbolStatistics: {" + << "entries: " << mFrequencyTable.size() << ", " + << "frequencyTableSizeB: " << mFrequencyTable.size() * sizeof(typename std::decay_t<decltype(mFrequencyTable)>::value_type) << ", " + << "CumulativeFrequencyTableSizeB: " << mCumulativeFrequencyTable.size() * sizeof(typename std::decay_t<decltype(mCumulativeFrequencyTable)>::value_type) << "}"; +#endif + + if (mFrequencyTable.size() == 1) { // we do this check only after the adding the escape symbol + LOG(debug) << "Passed empty message to " << __func__; // RS this is ok for empty columns + } + + LOG(trace) << "done building symbol statistics"; +} void SymbolStatistics::rescale() { - auto getFrequency = [this](size_t i) { return mCumulativeFrequencyTable[i + 1] - mCumulativeFrequencyTable[i]; }; + // temporarily extend cumulative frequency Table to obtain total number of entries + mCumulativeFrequencyTable.push_back(mCumulativeFrequencyTable.back() + mFrequencyTable.back()); + + auto getFrequency = [this](count_t i) { return mCumulativeFrequencyTable[i + 1] - mCumulativeFrequencyTable[i]; }; using namespace internal; LOG(trace) << "start rescaling frequency table"; @@ -39,63 +106,67 @@ void SymbolStatistics::rescale() if (mFrequencyTable.empty()) { LOG(warning) << "rescaling Frequency Table for empty message"; - return; } - const size_t newCumulatedFrequency = bitsToRange(mScaleBits); - assert(newCumulatedFrequency >= this->getNUsedAlphabetSymbols() + 1); - - size_t cumulatedFrequencies = mCumulativeFrequencyTable.back(); + const auto sortIdx = [&, this]() { + std::vector<size_t> indices; + indices.reserve(getNUsedAlphabetSymbols()); - std::vector<uint32_t> sortIdx; - sortIdx.reserve(getNUsedAlphabetSymbols()); - - // resample distribution based on cumulative frequencies_ - for (size_t i = 0; i < mFrequencyTable.size(); i++) { - if (mFrequencyTable[i]) { - sortIdx.push_back(i); // we will sort only those memorize only those entries which can be used + // we will sort only those memorize only those entries which can be used + for (size_t i = 0; i < mFrequencyTable.size(); i++) { + if (mFrequencyTable[i] != 0) { + indices.push_back(i); + } } - } + std::sort(indices.begin(), indices.end(), [&](count_t i, count_t j) { return getFrequency(i) < getFrequency(j); }); + + return indices; + }(); - std::sort(sortIdx.begin(), sortIdx.end(), [&](uint32_t i, uint32_t j) { return getFrequency(i) < getFrequency(j); }); - size_t need_shift = 0; + // resample distribution based on cumulative frequencies + const count_t newCumulatedFrequency = pow2(mSymbolTablePrecission); + assert(newCumulatedFrequency >= this->getNUsedAlphabetSymbols()); + const count_t cumulatedFrequencies = mCumulativeFrequencyTable.back(); + size_t needsShift = 0; for (size_t i = 0; i < sortIdx.size(); i++) { - if (static_cast<uint64_t>(getFrequency(sortIdx[i])) * (newCumulatedFrequency - need_shift) / cumulatedFrequencies >= 1) { + if (static_cast<count_t>(getFrequency(sortIdx[i])) * (newCumulatedFrequency - needsShift) / cumulatedFrequencies >= 1) { break; } - need_shift++; + needsShift++; } size_t shift = 0; auto beforeUpdate = mCumulativeFrequencyTable[0]; for (size_t i = 0; i < mFrequencyTable.size(); i++) { - if (mFrequencyTable[i] && static_cast<uint64_t>(mCumulativeFrequencyTable[i + 1] - beforeUpdate) * (newCumulatedFrequency - need_shift) / cumulatedFrequencies < 1) { + if (mFrequencyTable[i] && static_cast<uint64_t>(mCumulativeFrequencyTable[i + 1] - beforeUpdate) * (newCumulatedFrequency - needsShift) / cumulatedFrequencies < 1) { shift++; } beforeUpdate = mCumulativeFrequencyTable[i + 1]; - mCumulativeFrequencyTable[i + 1] = (static_cast<uint64_t>(newCumulatedFrequency - need_shift) * mCumulativeFrequencyTable[i + 1]) / cumulatedFrequencies + shift; + mCumulativeFrequencyTable[i + 1] = (static_cast<uint64_t>(newCumulatedFrequency - needsShift) * mCumulativeFrequencyTable[i + 1]) / cumulatedFrequencies + shift; } - assert(shift == need_shift); + assert(shift == needsShift); - // calculate updated freqs and make sure we didn't screw anything up + //verify +#if !defined(NDEBUG) assert(mCumulativeFrequencyTable.front() == 0 && mCumulativeFrequencyTable.back() == newCumulatedFrequency); - for (size_t i = 0; i < mFrequencyTable.size(); i++) { if (mFrequencyTable[i] == 0) { assert(mCumulativeFrequencyTable[i + 1] == mCumulativeFrequencyTable[i]); } else { assert(mCumulativeFrequencyTable[i + 1] > mCumulativeFrequencyTable[i]); } + } +#endif - // calc updated freq + // calculate updated frequencies + for (size_t i = 0; i < mFrequencyTable.size(); i++) { mFrequencyTable[i] = getFrequency(i); } - // for(int i = 0; i<static_cast<int>(freqs.getNumSymbols()); i++){ - // std::cout << i << ": " << i + min_ << " " << freqs[i] << " " << - // cummulatedFrequencies_[i] << std::endl; - // } - // std::cout << cummulatedFrequencies_.back() << std::endl; + + // remove added entry to cumulative Frequency table: + mCumulativeFrequencyTable.pop_back(); + assert(mFrequencyTable.size() == mCumulativeFrequencyTable.size()); t.stop(); LOG(debug1) << __func__ << " inclusive time (ms): " << t.getDurationMS(); @@ -103,19 +174,14 @@ void SymbolStatistics::rescale() LOG(trace) << "done rescaling frequency table"; } -size_t SymbolStatistics::getNUsedAlphabetSymbols() const -{ - return mNUsedAlphabetSymbols; -} - void SymbolStatistics::buildCumulativeFrequencyTable() { LOG(trace) << "start building cumulative frequency table"; - mCumulativeFrequencyTable.resize(mFrequencyTable.size() + 1); + mCumulativeFrequencyTable.resize(mFrequencyTable.size()); mCumulativeFrequencyTable[0] = 0; - std::partial_sum(mFrequencyTable.begin(), mFrequencyTable.end(), - mCumulativeFrequencyTable.begin() + 1); + std::partial_sum(mFrequencyTable.begin(), --mFrequencyTable.end(), + ++mCumulativeFrequencyTable.begin()); LOG(trace) << "done building cumulative frequency table"; } diff --git a/Utilities/rANS/test/test_ransEncodeDecode.cxx b/Utilities/rANS/test/test_ransEncodeDecode.cxx index 83389dc06b746..e3c96bbcdf742 100644 --- a/Utilities/rANS/test/test_ransEncodeDecode.cxx +++ b/Utilities/rANS/test/test_ransEncodeDecode.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,40 +26,14 @@ #include "rANS/rans.h" -template <typename CODER_T, typename STREAM_T, uint P> -struct Fixture { - // type of the coder: 32 bit or 64 bit - using coder_t = CODER_T; - // how many bytes do we stream out during normalization: - // 1 Byte for 32Bit coders, 4Byte for 64Bit coders - using stream_t = STREAM_T; - // what is the datatype of our source symbols? - using source_t = char; - - using encoder_t = o2::rans::Encoder<coder_t, stream_t, source_t>; - using decoder_t = o2::rans::Decoder<coder_t, stream_t, source_t>; - using literalEncoder_t = o2::rans::LiteralEncoder<coder_t, stream_t, source_t>; - using literalDecoder_t = o2::rans::LiteralDecoder<coder_t, stream_t, source_t>; - using dedupEncoder_t = o2::rans::DedupEncoder<coder_t, stream_t, source_t>; - using dedupDecoder_t = o2::rans::DedupDecoder<coder_t, stream_t, source_t>; - - //TUNIG parameters - // how many bits do we resample the symbol statistics to? - // this depends on the size of the alphabet (i.e. how big source_t is). - // See poster for more details - // https://indico.cern.ch/event/773049/contributions/3474364/attachments/1936180/3208584/Layout.pdf - // As a rule of thumb we need - // 10 Bits for 8Bit alphabets, - // 22Bits for 16Bit alphabets, - // 25Bits for 25Bit alphabets - const uint probabilityBits = P; - - const std::string source; +struct EmptyTestString { + std::string data{}; }; -template <typename CODER_T, typename STREAM_T, uint P> -struct FixtureFull : public Fixture<CODER_T, STREAM_T, P> { - const std::string source = R"(Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium +struct FullTestString : public EmptyTestString { + FullTestString() + { + data = R"(Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores @@ -69,113 +44,146 @@ quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid commodi consequatur? quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?)"; + } }; -typedef boost::mpl::vector<Fixture<uint32_t, uint8_t, 14>, Fixture<uint64_t, uint32_t, 18>, FixtureFull<uint32_t, uint8_t, 14>, FixtureFull<uint64_t, uint32_t, 18>> Fixtures; +template <typename coder_T> +struct Params { +}; -BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_EncodeDecode, T, Fixtures, T) -{ - fair::Logger::SetConsoleSeverity("trace"); - // iterate over the message and create PDF and CDF for each symbol in the message - o2::rans::FrequencyTable frequencies; - frequencies.addSamples(std::begin(T::source), std::end(T::source)); - - // buffer to write the rANS coded message into - std::vector<typename T::stream_t> encoderBuffer(1 << 20, 0); - //create a stateful encoder object that builds an encoding table from the given symbol statistics - const typename T::encoder_t encoder{frequencies, T::probabilityBits}; - // encoder rANS encodes symbols from SOURCE array to encoder Buffer. Since coder and decoder - // are mathematical inverse functions on the ANS state, they operate as a stack - - // i.e. the decoder outputs the message in reverse order of the encoder. - // By convention the encoder runs backwards over the input so that the decoder can return - // the data in the expected order. The encoder will start from encoderBuffer.begin() - // and return an iterator one element past the last entry written. - // This means the encodeded message ranges from encoderBuffer.begin() to encodedMessageEnd -1, with (encodedMessageEnd -encoderBuffer.begin()) entries written. - auto encodedMessageEnd = encoder.process(encoderBuffer.begin(), encoderBuffer.end(), std::begin(T::source), std::end(T::source)); - - // The decoded message will go into the decoder buffer which will have as many symbols as the original message - std::vector<typename T::source_t> decoderBuffer(std::distance(std::begin(T::source), std::end(T::source)), 0); - // create a stateful decoder object that build a decoding table from the given symbol statistics - const typename T::decoder_t decoder{frequencies, T::probabilityBits}; - // the decoder unwinds the rANS state in the encoder buffer starting at ransBegin and decodes it into the decode buffer; - decoder.process(decoderBuffer.begin(), encodedMessageEnd, std::distance(std::begin(T::source), std::end(T::source))); - - //the decodeBuffer and the source message have to be identical afterwards. - BOOST_REQUIRE(std::memcmp(&(*T::source.begin()), decoderBuffer.data(), - decoderBuffer.size() * sizeof(typename T::source_t)) == 0); -} - -typedef boost::mpl::vector<FixtureFull<uint32_t, uint8_t, 14>, FixtureFull<uint64_t, uint32_t, 14>> LiteralFixtures; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_EncodeDecode_literals, T, LiteralFixtures, T) -{ - fair::Logger::SetConsoleSeverity("trace"); - - // iterate over the message and create PDF and CDF for each symbol in the message - o2::rans::FrequencyTable frequencies; - frequencies.addSamples(std::begin(T::source), std::end(T::source)); - - std::string adaptedSource = "\\"; - adaptedSource.append(T::source); - adaptedSource.append("&%=/*!"); - - // buffer to write the rANS coded message into - std::vector<typename T::stream_t> encoderBuffer(1 << 20, 0); - //create a stateful encoder object that builds an encoding table from the given symbol statistics - const typename T::literalEncoder_t encoder{frequencies, T::probabilityBits}; - // encoder rANS encodes symbols from SOURCE array to encoder Buffer. Since coder and decoder - // are mathematical inverse functions on the ANS state, they operate as a stack - - // i.e. the decoder outputs the message in reverse order of the encoder. - // By convention the encoder runs backwards over the input so that the decoder can return - // the data in the expected order. The encoder will start from encoderBuffer.begin() - // and return an iterator one element past the last entry written. - // This means the encodeded message ranges from encoderBuffer.begin() to encodedMessageEnd -1, with (encodedMessageEnd -encoderBuffer.begin()) entries written. - std::vector<typename T::source_t> literals; - auto encodedMessageEnd = encoder.process(encoderBuffer.begin(), encoderBuffer.end(), std::begin(adaptedSource), std::end(adaptedSource), literals); - - // The decoded message will go into the decoder buffer which will have as many symbols as the original message - std::vector<typename T::source_t> decoderBuffer(std::distance(std::begin(adaptedSource), std::end(adaptedSource)), 0); - // create a stateful decoder object that build a decoding table from the given symbol statistics - const typename T::literalDecoder_t decoder{frequencies, T::probabilityBits}; - // the decoder unwinds the rANS state in the encoder buffer starting at ransBegin and decodes it into the decode buffer; - decoder.process(decoderBuffer.begin(), encodedMessageEnd, std::distance(std::begin(adaptedSource), std::end(adaptedSource)), literals); - - //the decodeBuffer and the source message have to be identical afterwards. - BOOST_REQUIRE(std::memcmp(&(*adaptedSource.begin()), decoderBuffer.data(), - decoderBuffer.size() * sizeof(typename T::source_t)) == 0); -} - -typedef boost::mpl::vector<FixtureFull<uint32_t, uint8_t, 14>, FixtureFull<uint64_t, uint32_t, 14>> DedupFixtures; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_EncodeDecode_dedup, T, DedupFixtures, T) +template <> +struct Params<uint32_t> { + using coder_t = uint32_t; + using stream_t = uint8_t; + using source_t = char; + static constexpr size_t symbolTablePrecission = 16; +}; + +template <> +struct Params<uint64_t> { + using coder_t = uint64_t; + using stream_t = uint32_t; + using source_t = char; + static constexpr size_t symbolTablePrecission = 16; +}; + +template < + template <typename, typename, typename> class encoder_T, + template <typename, typename, typename> class decoder_T, + typename coder_T, class dictString_T, class testString_T> +struct EncodeDecodeBase { + public: + using params_t = Params<coder_T>; + + EncodeDecodeBase() + { + dictString_T source; + std::string& s = source.data; + o2::rans::FrequencyTable frequencies; + frequencies.addSamples(std::begin(s), std::end(s)); + + encoder = decltype(encoder)(frequencies, params_t::symbolTablePrecission); + decoder = decltype(decoder)(frequencies, params_t::symbolTablePrecission); + + const auto [min, max] = [&s]() { + const auto [minIter, maxIter] = std::minmax_element(s.begin(), s.end()); + const char min = minIter == s.end() ? 0 : *minIter; + const char max = maxIter == s.end() ? 0 : *maxIter + 1; + return std::make_tuple(min, max); + }(); + + const size_t alphabetRangeBits = o2::rans::internal::numBitsForNSymbols(max - min + 1 + 1); + + BOOST_CHECK_EQUAL(encoder.getSymbolTablePrecision(), params_t::symbolTablePrecission); + BOOST_CHECK_EQUAL(encoder.getAlphabetRangeBits(), alphabetRangeBits); + BOOST_CHECK_EQUAL(encoder.getMinSymbol(), min); + BOOST_CHECK_EQUAL(encoder.getMaxSymbol(), max); + + BOOST_CHECK_EQUAL(decoder.getSymbolTablePrecision(), params_t::symbolTablePrecission); + BOOST_CHECK_EQUAL(decoder.getAlphabetRangeBits(), alphabetRangeBits); + BOOST_CHECK_EQUAL(decoder.getMinSymbol(), min); + BOOST_CHECK_EQUAL(decoder.getMaxSymbol(), max); + } + + virtual void encode() = 0; + virtual void decode() = 0; + + void check() + { + testString_T testString; + BOOST_CHECK_EQUAL_COLLECTIONS(testString.data.begin(), testString.data.end(), decodeBuffer.begin(), decodeBuffer.end()); + } + + testString_T source; + encoder_T<typename params_t::coder_t, typename params_t::stream_t, typename params_t::source_t> encoder{}; + decoder_T<typename params_t::coder_t, typename params_t::stream_t, typename params_t::source_t> decoder{}; + std::vector<typename Params<coder_T>::stream_t> encodeBuffer{}; + std::vector<typename Params<coder_T>::source_t> decodeBuffer{}; +}; + +template <typename coder_T, class dictString_T, class testString_T> +struct EncodeDecode : public EncodeDecodeBase<o2::rans::Encoder, o2::rans::Decoder, coder_T, dictString_T, testString_T> { + void encode() override + { + BOOST_CHECK_NO_THROW(this->encoder.process(std::begin(this->source.data), std::end(this->source.data), std::back_inserter(this->encodeBuffer))); + }; + void decode() override + { + BOOST_CHECK_NO_THROW(this->decoder.process(this->encodeBuffer.end(), std::back_inserter(this->decodeBuffer), this->source.data.size())); + }; +}; + +template <typename coder_T, class dictString_T, class testString_T> +struct EncodeDecodeLiteral : public EncodeDecodeBase<o2::rans::LiteralEncoder, o2::rans::LiteralDecoder, coder_T, dictString_T, testString_T> { + void encode() override + { + BOOST_CHECK_NO_THROW(this->encoder.process(std::begin(this->source.data), std::end(this->source.data), std::back_inserter(this->encodeBuffer), literals)); + }; + void decode() override + { + BOOST_CHECK_NO_THROW(this->decoder.process(this->encodeBuffer.end(), std::back_inserter(this->decodeBuffer), this->source.data.size(), literals)); + BOOST_CHECK(literals.empty()); + }; + + std::vector<typename Params<coder_T>::source_t> literals; +}; + +template <typename coder_T, class dictString_T, class testString_T> +struct EncodeDecodeDedup : public EncodeDecodeBase<o2::rans::DedupEncoder, o2::rans::DedupDecoder, coder_T, dictString_T, testString_T> { + void encode() override + { + BOOST_CHECK_NO_THROW(this->encoder.process(std::begin(this->source.data), std::end(this->source.data), std::back_inserter(this->encodeBuffer), duplicates)); + }; + void decode() override + { + BOOST_CHECK_NO_THROW(this->decoder.process(this->encodeBuffer.end(), std::back_inserter(this->decodeBuffer), this->source.data.size(), duplicates)); + }; + + using params_t = Params<coder_T>; + typename o2::rans::DedupEncoder<typename params_t::coder_t, + typename params_t::stream_t, + typename params_t::source_t>::duplicatesMap_t duplicates; +}; + +using testCase_t = boost::mpl::vector<EncodeDecode<uint32_t, EmptyTestString, EmptyTestString>, + EncodeDecode<uint64_t, EmptyTestString, EmptyTestString>, + EncodeDecode<uint32_t, FullTestString, FullTestString>, + EncodeDecode<uint64_t, FullTestString, FullTestString>, + EncodeDecodeLiteral<uint32_t, EmptyTestString, EmptyTestString>, + EncodeDecodeLiteral<uint64_t, EmptyTestString, EmptyTestString>, + EncodeDecodeLiteral<uint32_t, FullTestString, FullTestString>, + EncodeDecodeLiteral<uint64_t, FullTestString, FullTestString>, + EncodeDecodeLiteral<uint32_t, EmptyTestString, FullTestString>, + EncodeDecodeLiteral<uint64_t, EmptyTestString, FullTestString>, + EncodeDecodeDedup<uint32_t, EmptyTestString, EmptyTestString>, + EncodeDecodeDedup<uint64_t, EmptyTestString, EmptyTestString>, + EncodeDecodeDedup<uint32_t, FullTestString, FullTestString>, + EncodeDecodeDedup<uint64_t, FullTestString, FullTestString>>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_encodeDecode, testCase_T, testCase_t) { - fair::Logger::SetConsoleSeverity("trace"); - // iterate over the message and create PDF and CDF for each symbol in the message - o2::rans::FrequencyTable frequencies; - frequencies.addSamples(std::begin(T::source), std::end(T::source)); - - // buffer to write the rANS coded message into - std::vector<typename T::stream_t> encoderBuffer(1 << 20, 0); - //create a stateful encoder object that builds an encoding table from the given symbol statistics - const typename T::dedupEncoder_t encoder{frequencies, T::probabilityBits}; - // encoder rANS encodes symbols from SOURCE array to encoder Buffer. Since coder and decoder - // are mathematical inverse functions on the ANS state, they operate as a stack - - // i.e. the decoder outputs the message in reverse order of the encoder. - // By convention the encoder runs backwards over the input so that the decoder can return - // the data in the expected order. The encoder will start from encoderBuffer.begin() - // and return an iterator one element past the last entry written. - // This means the encodeded message ranges from encoderBuffer.begin() to encodedMessageEnd -1, with (encodedMessageEnd -encoderBuffer.begin()) entries written. - std::map<uint32_t, uint32_t> duplicates; - auto encodedMessageEnd = encoder.process(encoderBuffer.begin(), encoderBuffer.end(), std::begin(T::source), std::end(T::source), duplicates); - - // The decoded message will go into the decoder buffer which will have as many symbols as the original message - std::vector<typename T::source_t> decoderBuffer(std::distance(std::begin(T::source), std::end(T::source)), 0); - // create a stateful decoder object that build a decoding table from the given symbol statistics - const typename T::dedupDecoder_t decoder{frequencies, T::probabilityBits}; - // the decoder unwinds the rANS state in the encoder buffer starting at ransBegin and decodes it into the decode buffer; - decoder.process(decoderBuffer.begin(), encodedMessageEnd, std::distance(std::begin(T::source), std::end(T::source)), duplicates); - - //the decodeBuffer and the source message have to be identical afterwards. - BOOST_REQUIRE(std::memcmp(&(*T::source.begin()), decoderBuffer.data(), - decoderBuffer.size() * sizeof(typename T::source_t)) == 0); -} + testCase_T testCase; + testCase.encode(); + testCase.decode(); + testCase.check(); +}; \ No newline at end of file diff --git a/Utilities/rANS/test/test_ransFrequencyTable.cxx b/Utilities/rANS/test/test_ransFrequencyTable.cxx index b67d40584201d..2808d0676b70c 100644 --- a/Utilities/rANS/test/test_ransFrequencyTable.cxx +++ b/Utilities/rANS/test/test_ransFrequencyTable.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -18,33 +19,76 @@ #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> +#include <boost/mpl/vector.hpp> #include "rANS/rans.h" -BOOST_AUTO_TEST_CASE(test_addSamples) +template <typename T> +size_t getNUniqueSymbols(const T& container) { + return std::count_if(container.begin(), container.end(), [](uint32_t value) { return value != 0; }); +}; + +BOOST_AUTO_TEST_CASE(test_empty) +{ + std::vector<int> A{}; + + o2::rans::FrequencyTable frequencyTable; + frequencyTable.addSamples(std::begin(A), std::end(A)); + + BOOST_CHECK_EQUAL(frequencyTable.getMinSymbol(), 0); + BOOST_CHECK_EQUAL(frequencyTable.getMaxSymbol(), 0); + BOOST_CHECK_EQUAL(frequencyTable.size(), 0); + BOOST_CHECK_EQUAL(frequencyTable.getAlphabetRangeBits(), 0); + BOOST_CHECK_EQUAL(frequencyTable.getNumSamples(), 0); + BOOST_CHECK_EQUAL(frequencyTable.getNUsedAlphabetSymbols(), 0); + + BOOST_CHECK_EQUAL(frequencyTable.begin(), frequencyTable.end()); +} + +struct negativeOffset { std::vector<int> A{5, 5, 6, 6, 8, 8, 8, 8, 8, -1, -5, 2, 7, 3}; std::vector<uint32_t> histA{1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5}; + std::vector<int> B{10, -10}; + std::vector<uint32_t> histAandB{1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5, 0, 1}; +}; + +struct positiveOffset { + std::vector<int> A{5, 5, 6, 6, 8, 8, 8, 8, 8, 2, 7, 3}; + std::vector<uint32_t> histA{1, 1, 0, 2, 2, 1, 5}; + std::vector<int> B{10, -10}; + std::vector<uint32_t> histAandB{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 2, 1, 5, 0, 1}; +}; + +using samples_t = boost::mpl::vector<negativeOffset, positiveOffset>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_addSamples, samples_T, samples_t) +{ + samples_T s{}; o2::rans::FrequencyTable fA; - fA.addSamples(std::begin(A), std::end(A)); + fA.addSamples(std::begin(s.A), std::end(s.A)); - BOOST_CHECK_EQUAL(fA.getMinSymbol(), -5); - BOOST_CHECK_EQUAL(fA.getMaxSymbol(), 8); - BOOST_CHECK_EQUAL(fA.size(), histA.size()); + BOOST_CHECK_EQUAL(fA.getMinSymbol(), *std::min_element(s.A.begin(), s.A.end())); + BOOST_CHECK_EQUAL(fA.getMaxSymbol(), *std::max_element(s.A.begin(), s.A.end())); + BOOST_CHECK_EQUAL(fA.size(), s.histA.size()); + BOOST_CHECK_EQUAL(fA.getAlphabetRangeBits(), std::ceil(std::log2(s.histA.size()))); + BOOST_CHECK_EQUAL(fA.getNumSamples(), s.A.size()); + BOOST_CHECK_EQUAL(fA.getNUsedAlphabetSymbols(), getNUniqueSymbols(s.histA)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(histA), std::end(histA)); + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(s.histA), std::end(s.histA)); - std::vector<int> B{10, -10}; - fA.addSamples(std::begin(B), std::end(B)); + fA.addSamples(std::begin(s.B), std::end(s.B)); - BOOST_CHECK_EQUAL(fA.getMinSymbol(), -10); - BOOST_CHECK_EQUAL(fA.getMaxSymbol(), 10); + BOOST_CHECK_EQUAL(fA.getMinSymbol(), *std::min_element(s.B.begin(), s.B.end())); + BOOST_CHECK_EQUAL(fA.getMaxSymbol(), *std::max_element(s.B.begin(), s.B.end())); - std::vector<uint32_t> histAandB{1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5, 0, 1}; - BOOST_CHECK_EQUAL(fA.size(), histAandB.size()); + BOOST_CHECK_EQUAL(fA.size(), s.histAandB.size()); + BOOST_CHECK_EQUAL(fA.getAlphabetRangeBits(), std::ceil(std::log2(s.histAandB.size()))); + BOOST_CHECK_EQUAL(fA.getNumSamples(), std::accumulate(s.histAandB.begin(), s.histAandB.end(), 0)); + BOOST_CHECK_EQUAL(fA.getNUsedAlphabetSymbols(), getNUniqueSymbols(s.histAandB)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(histAandB), std::end(histAandB)); + BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(s.histAandB), std::end(s.histAandB)); } BOOST_AUTO_TEST_CASE(test_addFrequencies) @@ -61,6 +105,9 @@ BOOST_AUTO_TEST_CASE(test_addFrequencies) BOOST_CHECK_EQUAL(fA.getMinSymbol(), -5); BOOST_CHECK_EQUAL(fA.getMaxSymbol(), 8); BOOST_CHECK_EQUAL(fA.size(), histA.size()); + BOOST_CHECK_EQUAL(fA.getAlphabetRangeBits(), std::ceil(std::log2(histA.size()))); + BOOST_CHECK_EQUAL(fA.getNumSamples(), A.size()); + BOOST_CHECK_EQUAL(fA.getNUsedAlphabetSymbols(), getNUniqueSymbols(histA)); BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(histA), std::end(histA)); @@ -75,6 +122,9 @@ BOOST_AUTO_TEST_CASE(test_addFrequencies) std::vector<uint32_t> histAandB{1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 6, 0, 1}; BOOST_CHECK_EQUAL(fA.size(), histAandB.size()); + BOOST_CHECK_EQUAL(fA.getAlphabetRangeBits(), std::ceil(std::log2(histAandB.size()))); + BOOST_CHECK_EQUAL(fA.getNumSamples(), A.size() + B.size()); + BOOST_CHECK_EQUAL(fA.getNUsedAlphabetSymbols(), getNUniqueSymbols(histAandB)); BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(fA), std::end(fA), std::begin(histAandB), std::end(histAandB)); } diff --git a/Utilities/rANS/test/test_ransIterators.cxx b/Utilities/rANS/test/test_ransIterators.cxx new file mode 100644 index 0000000000000..02dead794ccd7 --- /dev/null +++ b/Utilities/rANS/test/test_ransIterators.cxx @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file test_ransIterators.cxx +/// @author michael.lettrich@cern.ch +/// @since 2020-10-28 +/// @brief + +#define BOOST_TEST_MODULE Utility test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include "rANS/utils.h" + +class ShiftFunctor +{ + public: + ShiftFunctor(size_t shift) : mShift{shift} {}; + + template <typename iterA_T, typename iterB_T> + inline uint32_t operator()(iterA_T iterA, iterB_T iterB) const + { + return *iterB + (static_cast<uint32_t>(*iterA) << mShift); + }; + + template <typename iterA_T, typename iterB_T> + inline void operator()(iterA_T iterA, iterB_T iterB, uint32_t value) const + { + *iterA = value >> mShift; + *iterB = value & ((1 << mShift) - 1); + }; + + private: + size_t mShift; +}; + +struct test_CombninedIteratorFixture { + const std::vector<uint16_t> a{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + const std::vector<uint16_t> b{a.rbegin(), a.rend()}; + const ShiftFunctor f{16}; + const std::vector<uint32_t> aAndB{0x0001000f, 0x0002000e, 0x0003000d, 0x0004000c, 0x0005000b, + 0x0006000a, 0x00070009, 0x00080008, 0x00090007, 0x000a0006, + 0x000b0005, 0x000c0004, 0x000d0003, 0x000e0002, 0x000f0001}; +}; + +BOOST_FIXTURE_TEST_CASE(test_CombinedInputIteratorBase, test_CombninedIteratorFixture) +{ + + o2::rans::utils::CombinedInputIterator iter(a.begin(), b.begin(), f); + // test equal + const o2::rans::utils::CombinedInputIterator first(a.begin(), b.begin(), f); + BOOST_CHECK_EQUAL(iter, first); + // test not equal + const o2::rans::utils::CombinedInputIterator second(++(a.begin()), ++(b.begin()), f); + BOOST_CHECK_NE(iter, second); + // test pre-increment + ++iter; + BOOST_CHECK_EQUAL(iter, second); + //test post-increment + iter = first; + BOOST_CHECK_EQUAL(iter++, first); + BOOST_CHECK_EQUAL(iter, second); + // test pre-decrement + iter = second; + --iter; + BOOST_CHECK_EQUAL(iter, first); + // test post-decrement + iter = second; + BOOST_CHECK_EQUAL(iter--, second); + BOOST_CHECK_EQUAL(iter, first); + + //test deref + const uint32_t val = first.operator*(); + BOOST_CHECK_EQUAL(val, aAndB.front()); +} + +BOOST_FIXTURE_TEST_CASE(test_CombinedOutputIteratorBase, test_CombninedIteratorFixture) +{ + std::vector<uint16_t> aOut(2, 0x0); + std::vector<uint16_t> bOut(2, 0x0); + + o2::rans::utils::CombinedOutputIteratorFactory<uint32_t> iterFactory; + auto iter = iterFactory.makeIter(aOut.begin(), bOut.begin(), f); + + // test deref: + *iter = aAndB[0]; + BOOST_CHECK_EQUAL(aOut[0], a[0]); + BOOST_CHECK_EQUAL(bOut[0], b[0]); + aOut[0] = 0x0; + bOut[0] = 0x0; + + // test pre-increment + *(++iter) = aAndB[1]; + BOOST_CHECK_EQUAL(aOut[0], 0); + BOOST_CHECK_EQUAL(bOut[0], 0); + BOOST_CHECK_EQUAL(aOut[1], a[1]); + BOOST_CHECK_EQUAL(bOut[1], b[1]); + aOut.assign(2, 0x0); + bOut.assign(2, 0x0); + iter = iterFactory.makeIter(aOut.begin(), bOut.begin(), f); + + // test post-increment + auto preInc = iter++; + *preInc = aAndB[0]; + BOOST_CHECK_EQUAL(aOut[0], a[0]); + BOOST_CHECK_EQUAL(bOut[0], b[0]); + BOOST_CHECK_EQUAL(aOut[1], 0x0); + BOOST_CHECK_EQUAL(bOut[1], 0x0); + aOut.assign(2, 0x0); + bOut.assign(2, 0x0); + *iter = aAndB[1]; + BOOST_CHECK_EQUAL(aOut[0], 0); + BOOST_CHECK_EQUAL(bOut[0], 0); + BOOST_CHECK_EQUAL(aOut[1], a[1]); + BOOST_CHECK_EQUAL(bOut[1], b[1]); +}; + +BOOST_FIXTURE_TEST_CASE(test_CombinedInputIteratorReadArray, test_CombninedIteratorFixture) +{ + + const o2::rans::utils::CombinedInputIterator begin(a.begin(), b.begin(), f); + const o2::rans::utils::CombinedInputIterator end(a.end(), b.end(), f); + BOOST_CHECK_EQUAL_COLLECTIONS(begin, end, aAndB.begin(), aAndB.end()); +}; + +BOOST_FIXTURE_TEST_CASE(test_CombinedOutputIteratorWriteArray, test_CombninedIteratorFixture) +{ + std::vector<uint16_t> aRes(a.size(), 0); + std::vector<uint16_t> bRes(b.size(), 0); + + auto iter = o2::rans::utils::CombinedOutputIteratorFactory<uint32_t>::makeIter(aRes.begin(), bRes.begin(), f); + for (auto input : aAndB) { + *iter++ = input; + } + + BOOST_CHECK_EQUAL_COLLECTIONS(aRes.begin(), aRes.end(), a.begin(), a.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(bRes.begin(), bRes.end(), b.begin(), b.end()); +}; + +BOOST_AUTO_TEST_CASE(test_Functions) +{ + std::vector<size_t> A(2); + BOOST_CHECK_THROW(o2::rans::utils::checkBounds(std::end(A), std::begin(A)), std::runtime_error); + BOOST_CHECK_NO_THROW(o2::rans::utils::checkBounds(std::begin(A), std::end(A))); +}; \ No newline at end of file diff --git a/Utilities/rANS/test/test_ransReverseSymbolLookupTable.cxx b/Utilities/rANS/test/test_ransReverseSymbolLookupTable.cxx new file mode 100644 index 0000000000000..7f35b48a40d15 --- /dev/null +++ b/Utilities/rANS/test/test_ransReverseSymbolLookupTable.cxx @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file test_ransReverseSymbolLookupTable.cxx +/// @author Michael Lettrich +/// @since 2021-06-02 +/// @brief + +#define BOOST_TEST_MODULE Utility test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/mpl/vector.hpp> + +#include "rANS/rans.h" + +template <typename T> +size_t getNUniqueSymbols(const T& container) +{ + return std::count_if(container.begin(), container.end(), [](uint32_t value) { return value != 0; }); +}; + +BOOST_AUTO_TEST_CASE(test_empty) +{ + const std::vector<int32_t> A{}; + const o2::rans::internal::SymbolStatistics symbolStats{A.begin(), A.end(), 0, 0u, 0u}; + const o2::rans::internal::ReverseSymbolLookupTable rLut{symbolStats}; + + const auto size = 1 << o2::rans::internal::MIN_SCALE; + BOOST_CHECK_EQUAL(rLut.size(), size); + + const std::vector<int32_t> res(size, 0); + BOOST_CHECK_EQUAL_COLLECTIONS(rLut.begin(), rLut.end(), res.begin(), res.end()); +} + +BOOST_AUTO_TEST_CASE(test_buildRLUT) +{ + const std::vector<int> A{5, 5, 6, 6, 8, 8, 8, 8, 8, -1, -5, 2, 7, 3}; + const std::vector<uint32_t> histA{1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5, 1}; + const size_t scaleBits = 17; + const auto size = 1 << scaleBits; + + o2::rans::FrequencyTable ft; + ft.addSamples(A.begin(), A.end()); + const o2::rans::internal::SymbolStatistics symbolStats{std::move(ft), scaleBits}; + const o2::rans::internal::ReverseSymbolLookupTable rLut{symbolStats}; + + BOOST_CHECK_EQUAL(rLut.size(), size); + + const auto min = *std::min_element(A.begin(), A.end()); + const std::vector<uint32_t> frequencies{8738, 0, 0, 0, 8738, 0, 0, 8738, 8738, 0, 17476, 17477, 8738, 43690, 8739}; + const std::vector<uint32_t> cumulative{0, 8738, 8738, 8738, 8738, 17476, 17476, 17476, 26214, 34952, 34952, 52428, 69905, 78643, 122333}; + + for (size_t i = 0; i < frequencies.size(); ++i) { + const int symbol = min + i; + for (size_t cumul = cumulative[i]; cumul < cumulative[i] + frequencies[i]; ++cumul) { + BOOST_CHECK(cumul < rLut.size()); + BOOST_CHECK_EQUAL(rLut[cumul], symbol); + } + } +} diff --git a/Utilities/rANS/test/test_ransSymbolStatistics.cxx b/Utilities/rANS/test/test_ransSymbolStatistics.cxx new file mode 100644 index 0000000000000..474557257d8be --- /dev/null +++ b/Utilities/rANS/test/test_ransSymbolStatistics.cxx @@ -0,0 +1,115 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file test_ransSymbolStatistics.cxx +/// @author Michael Lettrich +/// @since 2021-06-02 +/// @brief + +#define BOOST_TEST_MODULE Utility test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/mpl/vector.hpp> + +#include "rANS/rans.h" + +template <typename T> +size_t getNUniqueSymbols(const T& container) +{ + return std::count_if(container.begin(), container.end(), [](uint32_t value) { return value != 0; }); +}; + +BOOST_AUTO_TEST_CASE(test_empty) +{ + const std::vector<uint32_t> A{}; + o2::rans::internal::SymbolStatistics symbolStats{A.begin(), A.end(), 0, 0u, 0u}; + + BOOST_CHECK_EQUAL(symbolStats.getMinSymbol(), 0); + BOOST_CHECK_EQUAL(symbolStats.getMaxSymbol(), 0); + BOOST_CHECK_EQUAL(symbolStats.size(), 1); + BOOST_CHECK_EQUAL(symbolStats.getAlphabetRangeBits(), 1); + BOOST_CHECK_EQUAL(symbolStats.getNUsedAlphabetSymbols(), 1); + BOOST_CHECK_EQUAL(symbolStats.getSymbolTablePrecision(), o2::rans::internal::MIN_SCALE); + + BOOST_CHECK(symbolStats.begin() != symbolStats.end()); + + const auto [freq, cumul] = symbolStats.getEscapeSymbol(); + BOOST_CHECK_EQUAL(freq, std::get<0>(symbolStats[0])); + BOOST_CHECK_EQUAL(cumul, std::get<1>(symbolStats[0])); + BOOST_CHECK_EQUAL(freq, std::get<0>(symbolStats.at(0))); + BOOST_CHECK_EQUAL(cumul, std::get<1>(symbolStats.at(0))); +} + +struct SymbolStatsFromFrequencyTable { + static auto makeStats(const std::vector<int>& samples, size_t scaleBits) + { + o2::rans::FrequencyTable f; + f.addSamples(std::begin(samples), std::end(samples)); + return o2::rans::internal::SymbolStatistics{f, scaleBits}; + }; +}; + +struct SymbolStatsFromFrequencyTableRvalue { + static auto makeStats(const std::vector<int>& samples, size_t scaleBits) + { + o2::rans::FrequencyTable f; + f.addSamples(std::begin(samples), std::end(samples)); + return o2::rans::internal::SymbolStatistics{std::move(f), scaleBits}; + }; +}; + +struct SymbolStatsFromIterator { + static auto makeStats(const std::vector<int>& samples, size_t scaleBits) + { + o2::rans::FrequencyTable f; + f.addSamples(std::begin(samples), std::end(samples)); + return o2::rans::internal::SymbolStatistics{f.begin(), + f.end(), + f.getMinSymbol(), + scaleBits, + f.getNUsedAlphabetSymbols()}; + }; +}; + +using SymbolStats_t = boost::mpl::vector<SymbolStatsFromFrequencyTable, + SymbolStatsFromFrequencyTableRvalue, + SymbolStatsFromIterator>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_buildSymbolStats, Stats_T, SymbolStats_t) +{ + const std::vector<int> A{5, 5, 6, 6, 8, 8, 8, 8, 8, -1, -5, 2, 7, 3}; + const std::vector<uint32_t> histA{1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5, 1}; + const size_t scaleBits = 17; + + auto symbolStats = Stats_T::makeStats(A, scaleBits); + + BOOST_CHECK_EQUAL(symbolStats.getMinSymbol(), *std::min_element(A.begin(), A.end())); + BOOST_CHECK_EQUAL(symbolStats.getMaxSymbol(), *std::max_element(A.begin(), A.end()) + 1); + BOOST_CHECK_EQUAL(symbolStats.size(), histA.size()); + BOOST_CHECK_EQUAL(symbolStats.getAlphabetRangeBits(), std::ceil(std::log2(histA.size()))); + BOOST_CHECK_EQUAL(symbolStats.getNUsedAlphabetSymbols(), getNUniqueSymbols(histA)); + BOOST_CHECK_EQUAL(symbolStats.getSymbolTablePrecision(), scaleBits); + + BOOST_CHECK(symbolStats.begin() != symbolStats.end()); + + const std::vector<uint32_t> frequencies{8738, 0, 0, 0, 8738, 0, 0, 8738, 8738, 0, 17476, 17477, 8738, 43690, 8739}; + const std::vector<uint32_t> cumulative{0, 8738, 8738, 8738, 8738, 17476, 17476, 17476, 26214, 34952, 34952, 52428, 69905, 78643, 122333}; + BOOST_CHECK_EQUAL(symbolStats.size(), frequencies.size()); + BOOST_CHECK_EQUAL(symbolStats.size(), cumulative.size()); + + for (size_t i = 0; i < symbolStats.size(); ++i) { + const auto [freq, cumul] = symbolStats.at(i); + BOOST_CHECK_EQUAL(freq, frequencies[i]); + BOOST_CHECK_EQUAL(cumul, cumulative[i]); + } +} diff --git a/Utilities/rANS/test/test_ransSymbolTable.cxx b/Utilities/rANS/test/test_ransSymbolTable.cxx new file mode 100644 index 0000000000000..a170601a75afd --- /dev/null +++ b/Utilities/rANS/test/test_ransSymbolTable.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file test_ransSymbolStatistics.cxx +/// @author Michael Lettrich +/// @since 2021-06-02 +/// @brief + +#define BOOST_TEST_MODULE Utility test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> +#include <boost/mpl/vector.hpp> + +#include "rANS/rans.h" + +template <typename T> +size_t getNUniqueSymbols(const T& container) +{ + return std::count_if(container.begin(), container.end(), [](uint32_t value) { return value != 0; }); +}; + +BOOST_AUTO_TEST_CASE(test_empty) +{ + using namespace o2::rans; + + const std::vector<uint32_t> A{}; + const internal::SymbolStatistics symbolStats{A.begin(), A.end(), 0, 0u, 0u}; + const internal::SymbolTable<internal::DecoderSymbol> symbolTable{symbolStats}; + + BOOST_CHECK_EQUAL(symbolTable.getMinSymbol(), 0); + BOOST_CHECK_EQUAL(symbolTable.getMaxSymbol(), 0); + BOOST_CHECK_EQUAL(symbolTable.size(), 1); + BOOST_CHECK_EQUAL(symbolTable.getAlphabetRangeBits(), 1); + BOOST_CHECK_EQUAL(symbolTable.getNUsedAlphabetSymbols(), 1); + + const auto escapeSymbol = symbolTable.getEscapeSymbol(); + BOOST_CHECK_EQUAL(escapeSymbol.getFrequency(), symbolTable[0].getFrequency()); + BOOST_CHECK_EQUAL(escapeSymbol.getCumulative(), symbolTable[0].getCumulative()); + BOOST_CHECK_EQUAL(escapeSymbol.getFrequency(), symbolTable.at(0).getFrequency()); + BOOST_CHECK_EQUAL(escapeSymbol.getCumulative(), symbolTable.at(0).getCumulative()); + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(0), true); + + // out of range checks: + const int outOfRangeSymbols[] = {-100, 100}; + for (auto symbol : outOfRangeSymbols) { + const auto outOfRange = symbolTable[symbol]; + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(symbol), true); + BOOST_CHECK_EQUAL(outOfRange.getFrequency(), escapeSymbol.getFrequency()); + BOOST_CHECK_EQUAL(outOfRange.getCumulative(), escapeSymbol.getCumulative()); + } +} + +BOOST_AUTO_TEST_CASE(test_symbolTable) +{ + using namespace o2::rans; + + const std::vector<int> A{5, 5, 6, 6, 8, 8, 8, 8, 8, -1, -5, 2, 7, 3}; + const std::vector<uint32_t> histA{1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 1, 5, 1}; + const size_t scaleBits = 17; + const int32_t min = *std::min_element(A.begin(), A.end()); + + FrequencyTable f; + f.addSamples(A.begin(), A.end()); + const internal::SymbolStatistics symbolStats{std::move(f), scaleBits}; + const internal::SymbolTable<internal::DecoderSymbol> symbolTable{symbolStats}; + + BOOST_CHECK_EQUAL(symbolTable.getMinSymbol(), min); + BOOST_CHECK_EQUAL(symbolTable.getMaxSymbol(), *std::max_element(A.begin(), A.end()) + 1); + BOOST_CHECK_EQUAL(symbolTable.size(), histA.size()); + BOOST_CHECK_EQUAL(symbolTable.getAlphabetRangeBits(), std::ceil(std::log2(histA.size()))); + BOOST_CHECK_EQUAL(symbolTable.getNUsedAlphabetSymbols(), getNUniqueSymbols(histA)); + + const auto escapeSymbol = symbolTable.getEscapeSymbol(); + const std::vector<uint32_t> frequencies{8738, 0, 0, 0, 8738, 0, 0, 8738, 8738, 0, 17476, 17477, 8738, 43690, 8739}; + const std::vector<uint32_t> cumulative{0, 8738, 8738, 8738, 8738, 17476, 17476, 17476, 26214, 34952, 34952, 52428, 69905, 78643, 122333}; + BOOST_CHECK_EQUAL(symbolTable.size(), frequencies.size()); + BOOST_CHECK_EQUAL(symbolTable.size(), cumulative.size()); + + // all but last since this is the escape symbol + for (size_t i = 0; i < frequencies.size() - 1; ++i) { + const uint32_t symbol = min + i; + + const auto decodeSymbol = symbolTable[symbol]; + const auto decodeSymbolAt = symbolTable.at(i); + BOOST_CHECK_EQUAL(decodeSymbol.getFrequency(), decodeSymbolAt.getFrequency()); + BOOST_CHECK_EQUAL(decodeSymbol.getCumulative(), decodeSymbolAt.getCumulative()); + + const auto escapeSymbol = symbolTable.getEscapeSymbol(); + + if (frequencies[i] == 0) { + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(symbol), true); + BOOST_CHECK_EQUAL(decodeSymbol.getFrequency(), escapeSymbol.getFrequency()); + BOOST_CHECK_EQUAL(decodeSymbol.getCumulative(), escapeSymbol.getCumulative()); + } else { + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(symbol), false); + BOOST_CHECK_EQUAL(decodeSymbol.getFrequency(), frequencies[i]); + BOOST_CHECK_EQUAL(decodeSymbol.getCumulative(), cumulative[i]); + } + } + //escape symbol: + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(0), true); + BOOST_CHECK_EQUAL(escapeSymbol.getFrequency(), symbolTable.at(frequencies.size() - 1).getFrequency()); + BOOST_CHECK_EQUAL(escapeSymbol.getCumulative(), symbolTable.at(frequencies.size() - 1).getCumulative()); + + // out of range checks: + const int outOfRangeSymbols[] = {-100, 100}; + for (auto symbol : outOfRangeSymbols) { + const auto escapeSymbol = symbolTable.getEscapeSymbol(); + const auto outOfRange = symbolTable[symbol]; + BOOST_CHECK_EQUAL(symbolTable.isEscapeSymbol(symbol), true); + BOOST_CHECK_EQUAL(outOfRange.getFrequency(), escapeSymbol.getFrequency()); + BOOST_CHECK_EQUAL(outOfRange.getCumulative(), escapeSymbol.getCumulative()); + } +} diff --git a/cmake/AddRootDictionary.cmake b/cmake/AddRootDictionary.cmake index 8f627247c9183..88a895c2805b7 100644 --- a/cmake/AddRootDictionary.cmake +++ b/cmake/AddRootDictionary.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2AddExecutable.cmake b/cmake/O2AddExecutable.cmake index 59b6ff3d184a7..3416347cdc5e7 100644 --- a/cmake/O2AddExecutable.cmake +++ b/cmake/O2AddExecutable.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -49,7 +50,7 @@ function(o2_add_executable baseTargetName) A "IS_TEST;NO_INSTALL;IS_BENCHMARK" "COMPONENT_NAME;TARGETVARNAME" - "SOURCES;PUBLIC_LINK_LIBRARIES") + "SOURCES;PUBLIC_LINK_LIBRARIES;JOB_POOL") if(A_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Got trailing arguments ${A_UNPARSED_ARGUMENTS}") @@ -95,6 +96,9 @@ function(o2_add_executable baseTargetName) # set the executable output name set_property(TARGET ${target} PROPERTY OUTPUT_NAME ${exeName}) + if(A_JOB_POOL) + set_property(TARGET ${target} PROPERTY JOB_POOL_COMPILE ${A_JOB_POOL}) + endif() if(A_IS_TEST) # tests go in a separate directory diff --git a/cmake/O2AddHeaderOnlyLibrary.cmake b/cmake/O2AddHeaderOnlyLibrary.cmake index a461bf8faf8a0..95e0bc5158fc1 100644 --- a/cmake/O2AddHeaderOnlyLibrary.cmake +++ b/cmake/O2AddHeaderOnlyLibrary.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2AddLibrary.cmake b/cmake/O2AddLibrary.cmake index 581936de30adb..2a0fcf8418ab4 100644 --- a/cmake/O2AddLibrary.cmake +++ b/cmake/O2AddLibrary.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2AddTest.cmake b/cmake/O2AddTest.cmake index 6f55f9007db45..d1cadcde091f8 100644 --- a/cmake/O2AddTest.cmake +++ b/cmake/O2AddTest.cmake @@ -1,32 +1,54 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() include(O2AddExecutable) -include(O2AddTestWrapper) # -# o2_add_test(testName SOURCES ...) adds a test. The test itself (in the CTest -# sense) is a wrapper around an executable. Both the test wrapper and the -# executable are setup by this function. +# o2_add_test(testName SOURCES) adds an executable that is also a test. +# +# It is a convenience function that groups the actions of cmake intrinsics +# add_executable and add_test. # # If BUILD_TESTING if not set this function does nothing at all. # # The test name is the name of the first source file in SOURCES, unless the NAME # parameter is given (see below). # -# This function accepts two sets of parameters : one for the executable and one -# for the test wrapper. +# o2_add_test accept the following parameters : +# +# required +# +# * SOURCES : same meaning as for o2_add_executable +# +# recommended/often needed : +# +# * PUBLIC_LINK_LIBRARIES : same meaning as for +# o2_add_executable +# * COMMAND_LINE_ARGS : the arguments to pass to the executable, if any +# * COMPONENT_NAME : a short name that will be used to create the +# executable name (if not provided with NAME) : o2-test-[COMPONENT_NAME]-... +# * LABELS : labels attached to the test, that can then be used to filter +# which tests are executed with the `ctest -L` command +# +# optional/less frequently used : +# +# * NAME: if given, will be used verbatim as the test name +# * ENVIRONMENT: extra environment needed by the test to run properly +# * TIMEOUT : the number of seconds allowed for the test to run. Past this time +# failure is assumed. +# * WORKING_DIRECTORY: the directory in which the test will be ran # -# Parameters of the test executable : +# rarely needed/for special cases : # # * NO_BOOST_TEST : we assume most of the tests are using the Boost::Test # framework and thus link the test with the Boost::unit_test_framework target. @@ -35,17 +57,10 @@ include(O2AddTestWrapper) # * INSTALL : by default tests are _not_ installed. If that option is present # then the test is installed (under ${CMAKE_INSTALL_PREFIX}/tests, not in # ${CMAKE_INSTALL_PREFIX}/bin like other binaries) +# * CONFIGURATIONS : the test will only be ran for those named configurations +# * TARGETVARNAME : same meaning as for o2_add_executable # -# Parameters of the test wrapper : -# -# * NAME: if given, will be used verbatim as the test name -# * MAX_ATTEMPTS : the number of time the test will be tried (upon failures) -# before it is actually considered as failed -# * TIMEOUT : the number of seconds allowed for the test to run. Past this time -# failure is assumed. -# * NON_FATAL : true if the failing of this test is not causing the CI to fail -# * ENVIRONMENT: extra environment needed by the test to run properly -# + function(o2_add_test) if(NOT BUILD_TESTING) @@ -56,14 +71,13 @@ function(o2_add_test) PARSE_ARGV 1 A - "INSTALL;NO_BOOST_TEST;NON_FATAL" - "COMPONENT_NAME;MAX_ATTEMPTS;TIMEOUT;WORKING_DIRECTORY;NAME" + "INSTALL;NO_BOOST_TEST" + "COMPONENT_NAME;TIMEOUT;WORKING_DIRECTORY;NAME" "SOURCES;PUBLIC_LINK_LIBRARIES;COMMAND_LINE_ARGS;LABELS;CONFIGURATIONS;ENVIRONMENT" ) if(A_UNPARSED_ARGUMENTS) - message( - FATAL_ERROR "Unexpected unparsed arguments: ${A_UNPARSED_ARGUMENTS}") + message(FATAL_ERROR "Unexpected unparsed arguments: ${A_UNPARSED_ARGUMENTS}") endif() set(testName ${ARGV0}) @@ -95,12 +109,7 @@ function(o2_add_test) COMPONENT_NAME ${A_COMPONENT_NAME} IS_TEST ${noInstall} TARGETVARNAME targetName) - set(nonFatal "") - if(NON_FATAL) - set(nonFatal NON_FATAL) - endif() - - # create a test with a script wrapping the executable above + # create a test for the executable above set(name "") if(A_NAME) set(name ${A_NAME}) @@ -110,14 +119,14 @@ function(o2_add_test) file(RELATIVE_PATH name ${CMAKE_SOURCE_DIR} ${src}) endif() - o2_add_test_wrapper(TARGET ${targetName} - NAME ${name} - DONT_FAIL_ON_TIMEOUT - MAX_ATTEMPTS ${A_MAX_ATTEMPTS} - TIMEOUT ${A_TIMEOUT} ${nonFatal} - WORKING_DIRECTORY ${A_WORKING_DIRECTORY} - COMMAND_LINE_ARGS ${A_COMMAND_LINE_ARGS} - LABELS ${A_LABELS} - CONFIGURATIONS ${A_CONFIGURATIONS} - ENVIRONMENT "${A_ENVIRONMENT}") + add_test(NAME ${name} + COMMAND ${targetName} ${A_COMMAND_LINE_ARGS} + WORKING_DIRECTORY ${A_WORKING_DIRECTORY} + CONFIGURATIONS ${A_CONFIGURATIONS} + ) + + set_property(TEST ${name} PROPERTY LABELS ${A_LABELS}) + set_property(TEST ${name} PROPERTY ENVIRONMENT "${A_ENVIRONMENT}") + set_property(TEST ${name} PROPERTY TIMEOUT ${A_TIMEOUT}) + endfunction() diff --git a/cmake/O2AddTestCommand.cmake b/cmake/O2AddTestCommand.cmake new file mode 100644 index 0000000000000..6e99b2bb61616 --- /dev/null +++ b/cmake/O2AddTestCommand.cmake @@ -0,0 +1,90 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization or +# submit itself to any jurisdiction. + +include_guard() + +include(O2AddExecutable) + +# +# o2_add_test_command(COMMAND) adds a test which uses a command as executable. +# +# Compared to o2_add_test, this function does _not_ add a new executable, +# but uses an already declared executable (or even a script that is +# not build by cmake at all) +# +# If BUILD_TESTING if not set this function does nothing at all. +# +# o2_add_test_command accept the following parameters : +# +# required +# +# * COMMAND : command to be executed as a test +# * NAME : name of the test +# +# recommended/often needed : +# +# * COMMAND_LINE_ARGS : the arguments to pass to the test, if any +# * COMPONENT_NAME : a short name that will be used to create the +# executable name (if not provided with NAME) : o2-test-[COMPONENT_NAME]-... +# * LABELS : labels attached to the test, that can then be used to filter +# which tests are executed with the `ctest -L` command +# +# optional/less frequently used : +# +# * ENVIRONMENT: extra environment needed by the test to run properly +# * TIMEOUT : the number of seconds allowed for the test to run. Past this time +# failure is assumed. +# * WORKING_DIRECTORY: the directory in which the test will be ran +# +# rarely needed/for special cases : +# +# * CONFIGURATIONS : the test will only be ran for those named configurations +# + +function(o2_add_test_command) + + if(NOT BUILD_TESTING) + return() + endif() + + cmake_parse_arguments( + PARSE_ARGV + 0 + A + "" + "COMMAND;COMPONENT_NAME;TIMEOUT;WORKING_DIRECTORY;NAME" + "COMMAND_LINE_ARGS;LABELS;CONFIGURATIONS;ENVIRONMENT" + ) + + if(A_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected unparsed arguments: ${A_UNPARSED_ARGUMENTS}") + endif() + + set(noInstall NO_INSTALL) + + if(NOT A_NAME) + message(FATAL_ERROR "Must give a name to the test") + endif() + + if(NOT A_COMMAND) + message(FATAL_ERROR "Must give a command for the test") + endif() + + add_test(NAME ${A_NAME} + COMMAND ${A_COMMAND} ${A_COMMAND_LINE_ARGS} + WORKING_DIRECTORY ${A_WORKING_DIRECTORY} + CONFIGURATIONS ${A_CONFIGURATIONS} + ) + + set_property(TEST ${A_NAME} PROPERTY LABELS ${A_LABELS}) + set_property(TEST ${A_NAME} PROPERTY ENVIRONMENT ${A_ENVIRONMENT}) + set_property(TEST ${A_NAME} PROPERTY TIMEOUT ${A_TIMEOUT}) + +endfunction() diff --git a/cmake/O2AddTestRootMacro.cmake b/cmake/O2AddTestRootMacro.cmake index 6f78018ff8171..3e68556538b74 100644 --- a/cmake/O2AddTestRootMacro.cmake +++ b/cmake/O2AddTestRootMacro.cmake @@ -1,27 +1,28 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() +include(O2AddTestCommand) + # # o2_add_test_root_macro generate a test for a Root macro. # -# That test is trying to load the macro within a root.exe session using +# That test is trying to load the macro within a root.exe session using # ".L macro.C" # # * arg COMPILE: if present we generate, in addition to the baseline "load # the macro test", a test to compile the library, i.e. using ".L macro.C++ # * arg COMPILE_ONLY: if present we discard the "load the macro" test and # only attempt the compilation test. It implies COMPILE -# * arg NON_FATAL: if present mark the test as non_fatal, i.e. it won't -# invalidate the build # * arg ENVIRONMENT: sets the running environment for the generated test(s). # * arg PUBLIC_LINK_LIBRARIES: the list of targets this macro is depending on. # Required to be able to specify correctly the include and library paths to @@ -44,7 +45,7 @@ function(o2_add_test_root_macro macro) PARSE_ARGV 1 A - "NON_FATAL;COMPILE;COMPILE_ONLY" + "COMPILE;COMPILE_ONLY" "" "ENVIRONMENT;PUBLIC_LINK_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;LABELS") @@ -64,10 +65,6 @@ function(o2_add_test_root_macro macro) file(RELATIVE_PATH testName ${CMAKE_SOURCE_DIR} ${macroFileName}) - if(${A_IS_NON_FATAL}) - set(nonFatal "NON_FATAL") - endif() - list(APPEND incdir $ENV{ROOT_INCLUDE_PATH}) list(APPEND incdir ${A_PUBLIC_INCLUDE_DIRECTORIES}) @@ -100,7 +97,7 @@ function(o2_add_test_root_macro macro) # baseline test is to try and load the macro if (NOT A_COMPILE_ONLY) - o2_add_test_wrapper(COMMAND ${CMAKE_BINARY_DIR}/test-root-macro.sh + o2_add_test_command(COMMAND ${CMAKE_BINARY_DIR}/test-root-macro.sh NAME ${testName} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ${nonFatal} COMMAND_LINE_ARGS ${macroFileName} 0 "${includePath}" "${libraryPath}" @@ -115,8 +112,7 @@ function(o2_add_test_root_macro macro) # if (and only if) requested, try also to compile the macro if(A_COMPILE OR A_COMPILE_ONLY) - - o2_add_test_wrapper(COMMAND ${CMAKE_BINARY_DIR}/test-root-macro.sh + o2_add_test_command(COMMAND ${CMAKE_BINARY_DIR}/test-root-macro.sh NAME ${testName}_compiled WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ${nonFatal} COMMAND_LINE_ARGS ${macroFileName} 1 "${includePath}" "${libraryPath}" diff --git a/cmake/O2AddTestWrapper.cmake b/cmake/O2AddTestWrapper.cmake deleted file mode 100644 index df37179f07fb5..0000000000000 --- a/cmake/O2AddTestWrapper.cmake +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -include_guard() - -# -# o2_add_test_wrapper -# -# Same as o2_add_test() but optionally retry up to MAX_ATTEMPTS times upon -# failure. This is achieved by using a shell script wrapper. -# -# * TARGET or COMMAND (required) is either a target name or the full path to the -# executable to be wrapped -# -# * NAME (optional): the test name. If not present it is derived from the -# target name (if TARGET was used) or from the executable name (if COMMAND was -# given) -# -# * WORKING_DIRECTORY (optional) the wrapper will cd into this directory before -# running the executable -# * DONT_FAIL_ON_TIMEOUT (optional) indicate the test will not fail on timeouts -# * MAX_ATTEMPTS (optional) the maximum number of attempts -# * TIMEOUT (optional) the test timeout (for each attempt) -# * COMMAND_LINE_ARGS (optional) extra arguments to the test executable, if -# needed -# * NON_FATAL (optional) mark the test as non criticial for the CI -# * ENVIRONMENT: extra environment needed by the test to run properly -# -function(o2_add_test_wrapper) - - if(NOT BUILD_TESTING) - return() - endif() - - cmake_parse_arguments( - PARSE_ARGV - 0 - "A" - "DONT_FAIL_ON_TIMEOUT;NON_FATAL" - "TARGET;COMMAND;WORKING_DIRECTORY;MAX_ATTEMPTS;TIMEOUT;NAME" - "COMMAND_LINE_ARGS;LABELS;CONFIGURATIONS;ENVIRONMENT") - - if(A_UNPARSED_ARGUMENTS) - message( - FATAL_ERROR "Unexpected unparsed arguments: ${A_UNPARSED_ARGUMENTS}") - endif() - - if(A_TARGET AND A_COMMAND) - message(FATAL_ERROR "Should only use one of COMMAND or TARGET") - endif() - - if(NOT A_TARGET AND NOT A_COMMAND) - message(FATAL_ERROR "Must give at least one of COMMAND or TARGET") - endif() - - if(A_TARGET) - if(NOT TARGET ${A_TARGET}) - message(FATAL_ERROR "${A_TARGET} is not a target") - endif() - set(testExe $<TARGET_FILE:${A_TARGET}>) - endif() - - if(A_COMMAND) - set(testExe ${A_COMMAND}) - endif() - - if(A_NAME) - set(testName "${A_NAME}") - else() - if(A_COMMAND) - get_filename_component(testName ${testExe} NAME_WE) - else() - set(testName ${A_TARGET}) - endif() - endif() - -# if("${A_MAX_ATTEMPTS}" GREATER 1) -# # Warn only for tests where retry has been requested -# message( -# WARNING "Test ${testName} will be retried max ${A_MAX_ATTEMPTS} times") -# endif() - if(A_NON_FATAL) - message(WARNING "Failure of test ${testName} will not be fatal") - endif() - - if(NOT A_TIMEOUT) - set(A_TIMEOUT 100) # default timeout (seconds) - endif() - if(NOT A_MAX_ATTEMPTS) - set(A_MAX_ATTEMPTS 1) # default number of attempts - endif() - if(A_DONT_FAIL_ON_TIMEOUT) - set(A_DONT_FAIL_ON_TIMEOUT "--dont-fail-on-timeout") - else() - set(A_DONT_FAIL_ON_TIMEOUT "") - endif() - if(A_NON_FATAL) - set(A_NON_FATAL "--non-fatal") - else() - set(A_NON_FATAL "") - endif() - - # For now, we enforce 3 max attempts for all tests. - # No need to ignore time out, since we have 3 attempts - set(A_MAX_ATTEMPTS 3) - set(A_DONT_FAIL_ON_TIMEOUT "") - - math(EXPR ctestTimeout "(20 + ${A_TIMEOUT}) * ${A_MAX_ATTEMPTS}") - - if(NOT A_WORKING_DIRECTORY) - if(DEFINED DEFAULT_TEST_OUTPUT_DIRECTORY) - string(REPLACE "${CMAKE_BINARY_DIR}" "" reldir "${CMAKE_CURRENT_BINARY_DIR}") - get_filename_component(wdir ${DEFAULT_TEST_OUTPUT_DIRECTORY}/${reldir} REALPATH) - file(MAKE_DIRECTORY ${wdir}) - message( - STATUS - "test ${testName} will output in ${wdir}" - ) - set(A_WORKING_DIRECTORY ${wdir}) - endif() - endif() - - add_test(NAME "${testName}" - COMMAND "${CMAKE_BINARY_DIR}/tests-wrapper.sh" - "--name" - "${testName}" - "--max-attempts" - "${A_MAX_ATTEMPTS}" - "--timeout" - "${A_TIMEOUT}" - ${A_DONT_FAIA_ON_TIMEOUT} - ${A_NON_FATAL} - "--" - ${testExe} - ${A_COMMAND_LINE_ARGS} - WORKING_DIRECTORY "${A_WORKING_DIRECTORY}" - CONFIGURATIONS "${A_CONFIGURATIONS}") - - set_tests_properties(${testName} PROPERTIES TIMEOUT ${ctestTimeout}) - if(A_LABELS) - foreach(A IN LISTS A_LABELS) - set_property(TEST ${testName} APPEND PROPERTY LABELS ${A}) - endforeach() - endif() - if(A_ENVIRONMENT) - set_tests_properties(${testName} PROPERTIES ENVIRONMENT ${A_ENVIRONMENT}) - endif() -endfunction() diff --git a/cmake/O2AddWorkflow.cmake b/cmake/O2AddWorkflow.cmake index 17a5febf0b911..50694822e8cb6 100644 --- a/cmake/O2AddWorkflow.cmake +++ b/cmake/O2AddWorkflow.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -28,7 +29,7 @@ include_guard() function(o2_add_dpl_workflow baseTargetName) cmake_parse_arguments(PARSE_ARGV 1 A "" "COMPONENT_NAME;TARGETVARNAME" - "SOURCES;PUBLIC_LINK_LIBRARIES") + "SOURCES;PUBLIC_LINK_LIBRARIES;JOB_POOL") if(A_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Got trailing arguments ${A_UNPARSED_ARGUMENTS}") @@ -44,12 +45,16 @@ function(o2_add_dpl_workflow baseTargetName) ${targetExeName} PARENT_SCOPE) endif() + if(A_JOB_POOL) + set_property(TARGET ${targetExeName} PROPERTY JOB_POOL_COMPILE ${A_JOB_POOL}) + endif() set(jsonFile $<TARGET_FILE_BASE_NAME:${targetExeName}>.json) add_custom_command( TARGET ${targetExeName} POST_BUILD - COMMAND $<TARGET_FILE:${targetExeName}> -b | cat > ${jsonFile}) + COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$$LD_LIBRARY_PATH" $<TARGET_FILE:${targetExeName}> -b --dump-workflow --dump-workflow-file ${jsonFile}) + add_dependencies(${targetExeName} O2::FrameworkAnalysisSupport) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${jsonFile} diff --git a/cmake/O2BuildSanityChecks.cmake b/cmake/O2BuildSanityChecks.cmake index 95a6afaa82d4e..887b490ecfb90 100644 --- a/cmake/O2BuildSanityChecks.cmake +++ b/cmake/O2BuildSanityChecks.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2CheckCXXFeatures.cmake b/cmake/O2CheckCXXFeatures.cmake index 532d1df9761e0..3a20c0dfc6e37 100644 --- a/cmake/O2CheckCXXFeatures.cmake +++ b/cmake/O2CheckCXXFeatures.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2DataFile.cmake b/cmake/O2DataFile.cmake index 9b7932ee2404c..45ffb2c79a56b 100644 --- a/cmake/O2DataFile.cmake +++ b/cmake/O2DataFile.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # # o2_data_file(COPY src DESTINATION dest) is a convenience function to copy and diff --git a/cmake/O2DefineOptions.cmake b/cmake/O2DefineOptions.cmake index 81191510beac2..8dc3458cbf129 100644 --- a/cmake/O2DefineOptions.cmake +++ b/cmake/O2DefineOptions.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -14,6 +15,8 @@ function(o2_define_options) option(BUILD_SHARED_LIBS "Build shared libs" ON) + option(BUILD_ANALYSIS "Build analysis parts" ON) + option(BUILD_EXAMPLES "Build examples" ON) option(BUILD_TEST_ROOT_MACROS diff --git a/cmake/O2DefineOutputPaths.cmake b/cmake/O2DefineOutputPaths.cmake index a5d7bb9563778..2744c63008e79 100644 --- a/cmake/O2DefineOutputPaths.cmake +++ b/cmake/O2DefineOutputPaths.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2DefineRPATH.cmake b/cmake/O2DefineRPATH.cmake index 372f8e6d12530..a753125c81999 100644 --- a/cmake/O2DefineRPATH.cmake +++ b/cmake/O2DefineRPATH.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2DumpTargetProperties.cmake b/cmake/O2DumpTargetProperties.cmake index 45db6c168b90f..12ab58c26018e 100644 --- a/cmake/O2DumpTargetProperties.cmake +++ b/cmake/O2DumpTargetProperties.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2GetListOfMacros.cmake b/cmake/O2GetListOfMacros.cmake index d032e24a506ad..adadbe06af6fa 100644 --- a/cmake/O2GetListOfMacros.cmake +++ b/cmake/O2GetListOfMacros.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -18,5 +19,9 @@ function(o2_get_list_of_macros dir varname) file(GLOB_RECURSE listOfMacros RELATIVE ${CMAKE_SOURCE_DIR} ${dir}/*.C) # Case sensitive filtering of .C files (to avoid .c files on Mac) list(FILTER listOfMacros INCLUDE REGEX "^.*\\.C$") + # Remove macros that were copied to the build directory, to deal with + # the (non-recommended-but-can-happen) case where the build directory + # is a subdirectory of the source dir + list(FILTER listOfMacros EXCLUDE REGEX "/stage/${CMAKE_INSTALL_DATADIR}") set(${varname} ${listOfMacros} PARENT_SCOPE) endfunction() diff --git a/cmake/O2NameTarget.cmake b/cmake/O2NameTarget.cmake index c96e6ffecf0a7..de1c836fc3826 100644 --- a/cmake/O2NameTarget.cmake +++ b/cmake/O2NameTarget.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2ReportNonTestedMacros.cmake b/cmake/O2ReportNonTestedMacros.cmake index 4a2b80d398682..b12eb67c28261 100644 --- a/cmake/O2ReportNonTestedMacros.cmake +++ b/cmake/O2ReportNonTestedMacros.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2RootMacroExclusionList.cmake b/cmake/O2RootMacroExclusionList.cmake index 933546715c67d..edd596f4f1f7c 100644 --- a/cmake/O2RootMacroExclusionList.cmake +++ b/cmake/O2RootMacroExclusionList.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -18,8 +19,8 @@ include(O2GetListOfMacros) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C # temporary exclude until fix for full Clusters elimination - Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C # temporary exclude until fix for full Clusters elimination - Detectors/MUON/MCH/Simulation/macros/rootlogon.C + Detectors/ITSMFT/ITS/macros/test/dictionary_integrity_test.C # temporary exclude until fix for full Clusters elimination + Detectors/MUON/MCH/Geometry/Test/rootlogon.C Detectors/Passive/macro/PutFrameInTop.C Detectors/TPC/reconstruction/macro/addInclude.C Detectors/TPC/reconstruction/macro/getTPCTransformationExample.C @@ -31,6 +32,10 @@ list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Detectors/TRD/macros/convertRun2ToRun3Digits.C Detectors/TRD/macros/ParseTrapRawOutput.C Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C + GPU/GPUTracking/display/filterMacros/TRDCandidate.C + GPU/GPUTracking/display/filterMacros/hasTRD.C + GPU/GPUTracking/display/filterMacros/filterGPUTrack.C + GPU/GPUTracking/display/filterMacros/filterTPCTrack.C GPU/GPUTracking/Merger/macros/checkPropagation.C # Needs AliRoot AliExternalTrackParam GPU/GPUTracking/Merger/macros/fitPolynomialFieldIts.C # Needs AliRoot AliMagF GPU/GPUTracking/Merger/macros/fitPolynomialFieldTpc.C # Needs AliRoot AliMagF @@ -44,16 +49,17 @@ list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST GPU/TPCFastTransformation/devtools/loadlibs.C # Special macro GPU/TPCFastTransformation/alirootMacro/moveTPCFastTransform.C # Relies on initTPCcalibration.C GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C # Not yet ready - Detectors/TOF/prototyping/ConvertRun2CalibrationToO2.C + Detectors/TOF/prototyping/ConvertRun2CalibrationToO2.C Generators/share/external/hijing.C - Generators/share/external/QEDepem.C - Generators/share/external/GenCosmics.C + Generators/share/external/QEDepem.C + Generators/share/external/GenCosmics.C macro/SetIncludePath.C macro/loadExtDepLib.C macro/load_all_libs.C macro/putCondition.C macro/rootlogon.C - Detectors/DCS/test/processor_dpcom_o2.C) + Detectors/FIT/FT0/calibration/macros/makeDummyFT0CalibObjectInCCDB.C) + if(NOT BUILD_SIMULATION) # some complete sub_directories are not added to the build when not building @@ -69,6 +75,12 @@ if(NOT BUILD_SIMULATION) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/external/trigger_mpi.C) endif() +if(NOT ENABLE_UPGRADES) + # exclude all the macros found under Detectors/Upgrades directory + o2_get_list_of_macros(${CMAKE_SOURCE_DIR}/Detectors/Upgrades upgradeMacros) + list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST ${upgradeMacros}) +endif() + if(NOT pythia6_FOUND) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/external/pythia6.C) endif() diff --git a/cmake/O2SetROOTPCMDependencies.cmake b/cmake/O2SetROOTPCMDependencies.cmake index 915cc7858234d..d3f266c9c0337 100644 --- a/cmake/O2SetROOTPCMDependencies.cmake +++ b/cmake/O2SetROOTPCMDependencies.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2TargetManPage.cmake b/cmake/O2TargetManPage.cmake index 0c311d41755a5..5d29447c52536 100644 --- a/cmake/O2TargetManPage.cmake +++ b/cmake/O2TargetManPage.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/O2TargetRootDictionary.cmake b/cmake/O2TargetRootDictionary.cmake index 33a31b8b6f117..f5d630dd10569 100644 --- a/cmake/O2TargetRootDictionary.cmake +++ b/cmake/O2TargetRootDictionary.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/cmake/checks/cxx14-test-aggregate-initialization.cxx b/cmake/checks/cxx14-test-aggregate-initialization.cxx index 0abaf9de561da..8dedff45a91f8 100644 --- a/cmake/checks/cxx14-test-aggregate-initialization.cxx +++ b/cmake/checks/cxx14-test-aggregate-initialization.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/cmake/checks/cxx14-test-binary-literals.cxx b/cmake/checks/cxx14-test-binary-literals.cxx index ec5f693ee55b5..8fd1f13b697e5 100644 --- a/cmake/checks/cxx14-test-binary-literals.cxx +++ b/cmake/checks/cxx14-test-binary-literals.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/cmake/checks/cxx14-test-generic-lambda.cxx b/cmake/checks/cxx14-test-generic-lambda.cxx index bfa609be69902..c80e439f3e6c0 100644 --- a/cmake/checks/cxx14-test-generic-lambda.cxx +++ b/cmake/checks/cxx14-test-generic-lambda.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/cmake/checks/cxx14-test-make_unique.cxx b/cmake/checks/cxx14-test-make_unique.cxx index b7f323f4f5239..f7cf6f256b2cd 100644 --- a/cmake/checks/cxx14-test-make_unique.cxx +++ b/cmake/checks/cxx14-test-make_unique.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/cmake/checks/cxx14-test-user-defined-literals.cxx b/cmake/checks/cxx14-test-user-defined-literals.cxx index 268c3bb2b9388..0ef6c74df0a0f 100644 --- a/cmake/checks/cxx14-test-user-defined-literals.cxx +++ b/cmake/checks/cxx14-test-user-defined-literals.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index 8c32b4e727e7a..3888ca17ce913 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -1,11 +1,12 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. install(FILES rootmanager.dat DESTINATION share/config/) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 8da6e6c6e5a70..352bd805ebdf7 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include("${CMAKE_CURRENT_LIST_DIR}/O2CompileFlags.cmake") include("${CMAKE_CURRENT_LIST_DIR}/O2Dependencies.cmake") diff --git a/dependencies/FindAliRoot.cmake b/dependencies/FindAliRoot.cmake index 7252240bd2335..7888f65abfeb3 100644 --- a/dependencies/FindAliRoot.cmake +++ b/dependencies/FindAliRoot.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(AliRoot_FOUND FALSE) diff --git a/dependencies/FindFairRoot.cmake b/dependencies/FindFairRoot.cmake index c08562ead9e56..7c09ac01392dc 100644 --- a/dependencies/FindFairRoot.cmake +++ b/dependencies/FindFairRoot.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # TODO: remove this file once FairRoot correctly exports its cmake config @@ -72,7 +73,7 @@ if(NOT TARGET FairRoot::Base) INTERFACE_LINK_DIRECTORIES ${libdir}) target_link_libraries(FairRoot::Base INTERFACE FairRoot::Tools FairRoot::ParBase - FairRoot::GeoBase ROOT::ROOTDataFrame) + FairRoot::GeoBase ROOT::ROOTDataFrame ROOT::VMC) if(TARGET arrow_shared) # FIXME: this dependency (coming from ROOTDataFrame) should be handled in # ROOT itself diff --git a/dependencies/FindFastJet.cmake b/dependencies/FindFastJet.cmake index a61abdf7e7a28..3d6c7db490bf1 100644 --- a/dependencies/FindFastJet.cmake +++ b/dependencies/FindFastJet.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Author: Jochen Klein # diff --git a/dependencies/FindFlukaVMC.cmake b/dependencies/FindFlukaVMC.cmake new file mode 100644 index 0000000000000..01304a285f234 --- /dev/null +++ b/dependencies/FindFlukaVMC.cmake @@ -0,0 +1,30 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +# use the GEANT4_VMCConfig.cmake provided by the Geant4VMC installation but +# amend the target geant4vmc with the include directories + +find_package(FlukaVMC NO_MODULE) +if(NOT FlukaVMC_FOUND) +return() +endif() + +set_target_properties(flukavmc + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${FlukaVMC_INCLUDE_DIRS}" + INTERFACE_LINK_DIRECTORIES + $<TARGET_FILE_DIR:flukavmc>) + +# Promote the imported target to global visibility +# (so we can alias it) +set_target_properties(flukavmc PROPERTIES IMPORTED_GLOBAL TRUE) + +add_library(MC::FlukaVMC ALIAS flukavmc) diff --git a/dependencies/FindGLFW.cmake b/dependencies/FindGLFW.cmake index b28d43f6a607d..e062c6f06cec6 100644 --- a/dependencies/FindGLFW.cmake +++ b/dependencies/FindGLFW.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Simply provide a namespaced alias for the existing target diff --git a/dependencies/FindGeant3.cmake b/dependencies/FindGeant3.cmake index ec0b0c30696d7..1fe8a3a80529f 100644 --- a/dependencies/FindGeant3.cmake +++ b/dependencies/FindGeant3.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the the config provided by the Geant3 installation but amend the target # geant321 with the include directories diff --git a/dependencies/FindGeant4.cmake b/dependencies/FindGeant4.cmake index df24abec4a9d4..e9ac4600670e4 100644 --- a/dependencies/FindGeant4.cmake +++ b/dependencies/FindGeant4.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the Geant4Config.cmake provided by the Geant4 installation to create a # single target geant4 with the include directories and libraries we need diff --git a/dependencies/FindGeant4VMC.cmake b/dependencies/FindGeant4VMC.cmake index 985868e4a6090..de018165f2864 100644 --- a/dependencies/FindGeant4VMC.cmake +++ b/dependencies/FindGeant4VMC.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the GEANT4_VMCConfig.cmake provided by the Geant4VMC installation but # amend the target geant4vmc with the include directories diff --git a/dependencies/FindHepMC.cmake b/dependencies/FindHepMC.cmake index 76446c486ee08..c3f0da1f3fa95 100644 --- a/dependencies/FindHepMC.cmake +++ b/dependencies/FindHepMC.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the HepMCConfig.cmake provided by the HepMC3 installation to create a # single target HepMC with the include directories and libraries we need diff --git a/dependencies/FindHepMC3.cmake b/dependencies/FindHepMC3.cmake index 3f9233814f66d..da28e21dc2411 100644 --- a/dependencies/FindHepMC3.cmake +++ b/dependencies/FindHepMC3.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the HepMCConfig.cmake provided by the HepMC3 installation to create a # single target HepMC with the include directories and libraries we need diff --git a/dependencies/FindJAliEnROOT.cmake b/dependencies/FindJAliEnROOT.cmake new file mode 100644 index 0000000000000..dd9a0eceb8905 --- /dev/null +++ b/dependencies/FindJAliEnROOT.cmake @@ -0,0 +1,34 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. +find_path(JALIEN_ROOT_INCLUDE_DIR TJAlienFile.h PATH_SUFFIXES include + PATHS + ${JALIEN_ROOT_ROOT}) + +find_library(JAliEnRoot_LIB JAliEnROOT PATHS ${JALIEN_ROOT_ROOT}/lib) + +if(NOT JALIEN_ROOT_INCLUDE_DIR) + set(JAliEnROOT_FOUND FALSE) + return() +endif() + +set(JAliEnROOT_FOUND TRUE) + +if(NOT TARGET JAliEn::JAliEn) + get_filename_component(libdir ${JAliEnRoot_LIB} DIRECTORY) + add_library(JAliEn::JAliEn INTERFACE IMPORTED) + set_target_properties(JAliEn::JAliEn PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${JALIEN_ROOT_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES ${JAliEnRoot_LIB} + INTERFACE_LINK_DIRECTORIES ${libdir} + ) +endif() + +mark_as_advanced(JALIEN_ROOT_INCLUDE_DIR) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index f552ba605c055..c84ae643c38ae 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. if(NOT DEFINED ENABLE_CUDA) set(ENABLE_CUDA "AUTO") @@ -27,7 +28,6 @@ string(TOUPPER "${ENABLE_HIP}" ENABLE_HIP) # Detect and enable CUDA if(ENABLE_CUDA) - set(CUDA_MINIMUM_VERSION "11.0") set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_STANDARD_REQUIRED TRUE) include(CheckLanguage) @@ -40,17 +40,28 @@ if(ENABLE_CUDA) endif() endif() if(CMAKE_CUDA_COMPILER) - cmake_minimum_required(VERSION 3.18 FATAL_ERROR) enable_language(CUDA) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + if (ENABLE_CUDA STREQUAL "AUTO") + set(FAILURE_SEVERITY STATUS) + else() + set(FAILURE_SEVERITY FATAL_ERROR) + endif() if(NOT CUDA IN_LIST LANGUAGES) - message(FATAL_ERROR "CUDA was found but cannot be enabled") + message(${FAILURE_SEVERITY} "CUDA was found but cannot be enabled") + set(CMAKE_CUDA_COMPILER OFF) endif() find_path(THRUST_INCLUDE_DIR thrust/version.h PATHS ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} NO_DEFAULT_PATH) if(THRUST_INCLUDE_DIR STREQUAL "THRUST_INCLUDE_DIR-NOTFOUND") - message(FATAL_ERROR "CUDA found but thrust not available") + message(${FAILURE_SEVERITY} "CUDA found but thrust not available") + set(CMAKE_CUDA_COMPILER OFF) endif() - + if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.4") + message(${FAILURE_SEVERITY} "CUDA Version too old: ${CMAKE_CUDA_COMPILER_VERSION}, 11.4 required") + set(CMAKE_CUDA_COMPILER OFF) + endif() + endif() + if(CMAKE_CUDA_COMPILER) # Forward CXX flags to CUDA C++ Host compiler (for warnings, gdb, etc.) STRING(REGEX REPLACE "\-std=[^ ]*" "" CMAKE_CXX_FLAGS_NOSTD ${CMAKE_CXX_FLAGS}) # Need to strip c++17 imposed by alidist defaults set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler \"${CMAKE_CXX_FLAGS_NOSTD}\" --expt-relaxed-constexpr --extended-lambda --allow-unsupported-compiler -Xptxas -v") @@ -62,15 +73,17 @@ if(ENABLE_CUDA) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Werror=cross-execution-space-call") endif() if(CUDA_COMPUTETARGET) - set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTETARGET}) + set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTETARGET} CACHE STRING "" FORCE) else() - set(CMAKE_CUDA_ARCHITECTURES 61-virtual) + set(CMAKE_CUDA_ARCHITECTURES 61-virtual CACHE STRING "" FORCE) endif() set(CUDA_ENABLED ON) message(STATUS "CUDA found (Version ${CMAKE_CUDA_COMPILER_VERSION})") elseif(NOT ENABLE_CUDA STREQUAL "AUTO") message(FATAL_ERROR "CUDA not found (Compiler: ${CMAKE_CUDA_COMPILER})") + else() + set(CUDA_ENABLED OFF) endif() endif() @@ -97,18 +110,20 @@ if(ENABLE_OPENCL1) message(STATUS "Found AMD OpenCL 1.2") elseif(NOT ENABLE_OPENCL1 STREQUAL "AUTO") message(FATAL_ERROR "AMD OpenCL 1.2 not available") + else() + set(OPENCL1_ENABLED OFF) endif() endif() # Detect and enable OpenCL 2.x if(ENABLE_OPENCL2) + find_package(OpenCL) find_package(LLVM) if(LLVM_FOUND) find_package(Clang) endif() - find_package(ROCM PATHS /opt/rocm) - if(NOT ROCM_DIR STREQUAL "ROCM_DIR-NOTFOUND") - get_filename_component(ROCM_ROOT "${ROCM_DIR}/../../../" ABSOLUTE) + if(DEFINED ENV{ROCM_PATH}) + get_filename_component(ROCM_ROOT "$ENV{ROCM_PATH}" ABSOLUTE) else() set(ROCM_ROOT "/opt/rocm") endif() @@ -117,7 +132,7 @@ if(ENABLE_OPENCL2) find_program(LLVM_SPIRV llvm-spirv) if(Clang_FOUND AND LLVM_FOUND - AND LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 10.0) + AND LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 13.0) set(OPENCL2_COMPATIBLE_CLANG_FOUND ON) endif() if(OpenCL_VERSION_STRING VERSION_GREATER_EQUAL 2.0 @@ -141,6 +156,8 @@ if(ENABLE_OPENCL2) ) elseif(NOT ENABLE_OPENCL2 STREQUAL "AUTO") message(FATAL_ERROR "OpenCL 2.x not available") + else() + set(OPENCL2_ENABLED OFF) endif() if (FORCE_OPENCL2_ALL AND NOT(OPENCL2_ENABLED_AMD AND OPENCL2_ENABLED_SPIRV)) message(FATAL_ERROR "Not all OpenCL2 backends available, but requested (AMD ${OPENCL2_ENABLED_AMD} SPIRV ${OPENCL2_ENABLED_SPIRV})") @@ -163,6 +180,10 @@ if(ENABLE_HIP) if(EXISTS "${HIP_PATH}") get_filename_component(hip_ROOT "${HIP_PATH}" ABSOLUTE) + if(HIP_AMDGPUTARGET) + set(AMDGPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + set(GPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + endif() find_package(hip) find_package(hipcub) find_package(rocprim) @@ -186,6 +207,8 @@ if(ENABLE_HIP) if(HIP_AMDGPUTARGET) set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} --amdgpu-target=${HIP_AMDGPUTARGET}") endif() + else() + set(HIP_ENABLED OFF) endif() endif() if(NOT HIP_ENABLED AND NOT ENABLE_HIP STREQUAL "AUTO") diff --git a/dependencies/FindO2arrow.cmake b/dependencies/FindO2arrow.cmake index c616bd9d6cf33..f5b0c7e734f7a 100644 --- a/dependencies/FindO2arrow.cmake +++ b/dependencies/FindO2arrow.cmake @@ -1,19 +1,22 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # Simply provide a namespaced alias for the existing target +set(_CMAKE_MODULE_PATH_COPY ${CMAKE_MODULE_PATH}) # Make sure CMAKE_MODULE_PATH is not reset find_package(Arrow CONFIG QUIET) + if(NOT Arrow_FOUND) - find_package(arrow CONFIG QUIET) set(Arrow_DIR ${arrow_DIR}) + find_package(arrow CONFIG PATHS ${Arrow_DIR} QUIET) endif() find_package(Gandiva CONFIG PATHS ${Arrow_DIR} QUIET) @@ -36,3 +39,5 @@ find_package_handle_standard_args(O2arrow REQUIRED_VARS arrow_TARGET gandiva_TAR unset(arrow_TARGET) unset(gandiva_TARGET) +set(CMAKE_MODULE_PATH ${_CMAKE_MODULE_PATH_COPY}) +unset(_CMAKE_MODULE_PATH_COPY) diff --git a/dependencies/FindRapidJSON.cmake b/dependencies/FindRapidJSON.cmake index a9baebbc53721..9fea87c357fa5 100644 --- a/dependencies/FindRapidJSON.cmake +++ b/dependencies/FindRapidJSON.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # # Finds the rapidjson (header-only) library using the CONFIG file provided by diff --git a/dependencies/FindVGM.cmake b/dependencies/FindVGM.cmake index b6eefc30731b0..c3d7129a6b3e5 100644 --- a/dependencies/FindVGM.cmake +++ b/dependencies/FindVGM.cmake @@ -1,13 +1,14 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # use the VGMConfig.cmake provided by the VGM installation but # amend the target VGM::XmlVGM with the include and link directories diff --git a/dependencies/FindXRootD.cmake b/dependencies/FindXRootD.cmake new file mode 100644 index 0000000000000..23167369eb781 --- /dev/null +++ b/dependencies/FindXRootD.cmake @@ -0,0 +1,236 @@ +################################################################################ +# Module for locating XRootD. +# +# XROOTD_FOUND +# Indicates whether the library has been found. +# +# XROOTD_INCLUDE_DIRS +# Specifies XRootD include directory. +# +# XROOTD_LIBRARIES +# Specifies XRootD libraries that should be passed to target_link_libararies. +# +# XROOTD_<COMPONENT>_LIBRARIES +# Specifies the libraries of a specific <COMPONENT> +# +# XROOTD_<COMPONENT>_FOUND +# Indicates whether the specified <COMPONENT> was found. +# +# List of components: CLIENT, UTILS, SERVER, POSIX, HTTP and SSI +################################################################################ + + +################################################################################ +# Set XRootD include paths +################################################################################ +FIND_PATH( XROOTD_INCLUDE_DIRS XrdVersion.hh + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES include/xrootd + PATHS /opt/xrootd +) + +IF( NOT "${XROOTD_INCLUDE_DIRS}" STREQUAL "XROOTD_INCLUDE_DIRS-NOTFOUND" ) + SET( XROOTD_FOUND TRUE ) +ENDIF() + +IF( NOT XROOTD_FOUND ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD client libs +# - libXrdCl +################################################################################ +FIND_LIBRARY( XROOTD_CLIENT_LIBRARIES XrdCl + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_CLIENT_LIBRARIES}" STREQUAL "XROOTD_CLIENT_LIBRARIES-NOTFOUND" ) + SET( XROOTD_CLIENT_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_CLIENT_LIBRARIES} ) +ENDIF() + +IF( XRootD_FIND_REQUIRED_CLIENT AND NOT XROOTD_CLIENT_FOUND ) + MESSAGE( "XRootD client required but not found!" ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_CLIENT_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD utils libs +# - libXrdUtils +################################################################################ +FIND_LIBRARY( XROOTD_UTILS_LIBRARIES XrdUtils + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_UTILS_LIBRARIES}" STREQUAL "XROOTD_UTILS_LIBRARIES-NOTFOUND" ) + SET( XROOTD_UTILS_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_UTILS_LIBRARIES} ) +ENDIF() + +IF( XRootD_FIND_REQUIRED_UTILS AND NOT XROOTD_UTILS_FOUND ) + MESSAGE( "XRootD utils required but not found!" ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_UTILS_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD server libs +# - libXrdServer +################################################################################ +FIND_LIBRARY( XROOTD_SERVER_LIBRARIES XrdServer + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_SERVER_LIBRARIES}" STREQUAL "XROOTD_SERVER_LIBRARIES-NOTFOUND" ) + SET( XROOTD_SERVER_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_SERVER_LIBRARIES} ) +ENDIF() + +IF( XRootD_FIND_REQUIRED_SERVER AND NOT XROOTD_SERVER_FOUND ) + MESSAGE( "XRootD server required but not found!" ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_SERVER_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD posix libs +# - libXrdPosix +# - libXrdPosixPreload +################################################################################ +FIND_LIBRARY( XROOTD_POSIX_LIBRARY XrdPosix + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +FIND_LIBRARY( XROOTD_POSIX_PRELOAD_LIBRARY XrdPosixPreload + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_POSIX_LIBRARY}" STREQUAL "XROOTD_POSIX_LIBRARY-NOTFOUND" ) + IF( NOT "${XROOTD_POSIX_PRELOAD_LIBRARY}" STREQUAL "XROOTD_POSIX_PRELOAD_LIBRARY-NOTFOUND" ) + SET( XROOTD_POSIX_LIBRARIES ${XROOTD_POSIX_LIBRARY} ${XROOTD_POSIX_PRELOAD_LIBRARY} ) + SET( XROOTD_POSIX_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_POSIX_LIBRARIES} ) + ENDIF() +ENDIF() + +IF( XRootD_FIND_REQUIRED_POSIX AND NOT XROOTD_POSIX_FOUND ) + MESSAGE( "XRootD posix required but not found!" ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_POSIX_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD HTTP (XrdHttp) libs +# - libXrdHtppUtils +################################################################################ +FIND_LIBRARY( XROOTD_HTTP_LIBRARIES XrdHttpUtils + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_HTTP_LIBRARIES}" STREQUAL "XROOTD_HTTP_LIBRARIES-NOTFOUND" ) + SET( XROOTD_HTTP_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_HTTP_LIBRARIES} ) +ENDIF() + +IF( XRootD_FIND_REQUIRED_HTTP AND NOT XROOTD_HTTP_FOUND ) + MESSAGE( "XRootD http required but not found!" ) + LIST( APPEND _XROOTD_MISSING_COMPONENTS XROOTD_HTTP_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# XRootD SSI libs +# - XrdSsiLib +# - XrdSsiShMap +################################################################################ +FIND_LIBRARY( XROOTD_SSI_LIBRARY XrdSsiLib + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +FIND_LIBRARY( XROOTD_SSI_SHMAP_LIBRARY XrdSsiShMap + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd + PATH_SUFFIXES lib lib64 +) + +IF( NOT "${XROOTD_SSI_LIBRARY}" STREQUAL "XROOTD_SSI_LIBRARY-NOTFOUND" ) + IF( NOT "${XROOTD_SSI_SHMAP_LIBRARY}" STREQUAL "XROOTD_SSI_SHMAP_LIBRARY-NOTFOUND" ) + SET( XROOTD_SSI_LIBRARIES ${XROOTD_SSI_LIBRARY} ${XROOTD_SSI_SHMAP_LIBRARY} ) + SET( XROOTD_SSI_FOUND TRUE ) + LIST( APPEND XROOTD_LIBRARIES ${XROOTD_SSI_LIBRARIES} ) + ENDIF() +ENDIF() + +IF( XRootD_FIND_REQUIRED_SSI AND NOT XROOTD_SSI_FOUND ) + MESSAGE( "XRootD ssi required but not found!" ) + LIST (APPEND _XROOTD_MISSING_COMPONENTS XROOTD_SSI_FOUND ) + UNSET( XROOTD_FOUND ) +ENDIF() + +################################################################################ +# Set up the XRootD find module +################################################################################ + +IF( XRootD_FIND_REQUIRED ) + INCLUDE( FindPackageHandleStandardArgs ) + FIND_PACKAGE_HANDLE_STANDARD_ARGS( XRootD + REQUIRED_VARS XROOTD_INCLUDE_DIRS ${_XROOTD_MISSING_COMPONENTS} + ) +ENDIF() + + +if (XROOTD_CLIENT_FOUND) +if(NOT TARGET XRootD::Client) + get_filename_component(libdir ${XROOTD_CLIENT_LIBRARIES} DIRECTORY) + add_library(XRootD::Client INTERFACE IMPORTED) + set_target_properties(XRootD::Client PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${XROOTD_INCLUDE_DIRS} + INTERFACE_LINK_LIBRARIES ${XROOTD_CLIENT_LIBRARIES} + INTERFACE_LINK_DIRECTORIES ${libdir} + ) +endif() +endif() diff --git a/dependencies/FindlibjalienO2.cmake b/dependencies/FindlibjalienO2.cmake new file mode 100644 index 0000000000000..492880efc2110 --- /dev/null +++ b/dependencies/FindlibjalienO2.cmake @@ -0,0 +1,41 @@ +# Find module for libjalienO2. +# Variables: +# - LIBJALIENO2_FOUND: TRUE if found +# - LIBJALIENO2_LIBPATH: library path +# - LIBJALIENO2_INCLUDE_DIR: include dir + +# Init +include(FindPackageHandleStandardArgs) + +# find includes +find_path(LIBJALIENO2_INCLUDE_DIR TJAlienSSLContext.h + PATH_SUFFIXES "include" + HINTS "${LIBJALIENO2}" +) + +mark_as_advanced(LIBJALIENO2_INCLUDE_DIR) + +# find library +find_library(LIBJALIENO2_LIBPATH "jalienO2" + PATH_SUFFIXES "lib" + HINTS "${LIBJALIENO2}" +) + +mark_as_advanced(LIBJALIENO2_LIBPATH) + +find_package_handle_standard_args(libjalienO2 DEFAULT_MSG + LIBJALIENO2_LIBPATH LIBJALIENO2_INCLUDE_DIR) + +if(LIBJALIENO2_FOUND) + set(LIBJALIENO2_LIBRARIES ${LIBJALIENO2_LIBPATH}) + set(LIBJALIENO2_INCLUDE_DIRS ${LIBJALIENO2_INCLUDE_DIR}) + + # add target + if(NOT TARGET libjalien::libjalienO2) + add_library(libjalien::libjalienO2 IMPORTED INTERFACE) + set_target_properties(libjalien::libjalienO2 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBJALIENO2_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${LIBJALIENO2_LIBPATH}" + ) + endif() +endif() diff --git a/dependencies/Findms_gsl.cmake b/dependencies/Findms_gsl.cmake deleted file mode 100644 index b3098d1468197..0000000000000 --- a/dependencies/Findms_gsl.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -find_path(MS_GSL_INCLUDE_DIR gsl/gsl PATH_SUFFIXES ms_gsl/include include - PATHS $ENV{MS_GSL_ROOT}) - -if(NOT MS_GSL_INCLUDE_DIR) - set(MS_GSL_FOUND FALSE) - message(WARNING "MS_GSL not found") - return() -endif() - -set(MS_GSL_FOUND TRUE) - -if(NOT TARGET ms_gsl::ms_gsl) - add_library(ms_gsl::ms_gsl INTERFACE IMPORTED) - set_target_properties(ms_gsl::ms_gsl - PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - ${MS_GSL_INCLUDE_DIR}) -endif() - -mark_as_advanced(MS_GSL_INCLUDE_DIR) diff --git a/dependencies/Findpythia.cmake b/dependencies/Findpythia.cmake index 2940a1fe18bbd..2191c6a2576e4 100644 --- a/dependencies/Findpythia.cmake +++ b/dependencies/Findpythia.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(PKGNAME ${CMAKE_FIND_PACKAGE_NAME}) string(TOUPPER ${PKGNAME} PKGENVNAME) diff --git a/dependencies/Findpythia6.cmake b/dependencies/Findpythia6.cmake index 2b2f65d4b4b14..c4bc0cbd76ec4 100644 --- a/dependencies/Findpythia6.cmake +++ b/dependencies/Findpythia6.cmake @@ -1,18 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. set(PKGNAME ${CMAKE_FIND_PACKAGE_NAME}) string(TOUPPER ${PKGNAME} PKGENVNAME) find_library(${PKGNAME}_LIBRARY_SHARED - NAMES libpythia6.so libpythia6.dylib + NAMES libpythia6.so libpythia6.dylib libPythia6.so libPythia6.dylib PATHS $ENV{${PKGENVNAME}_ROOT}/lib) if(${PKGNAME}_LIBRARY_SHARED) diff --git a/dependencies/O2CompileFlags.cmake b/dependencies/O2CompileFlags.cmake index 85a98847e1511..7bc9a517345e0 100644 --- a/dependencies/O2CompileFlags.cmake +++ b/dependencies/O2CompileFlags.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/dependencies/O2Dependencies.cmake b/dependencies/O2Dependencies.cmake index 93cc13d58df3e..d77550e7d4fdd 100644 --- a/dependencies/O2Dependencies.cmake +++ b/dependencies/O2Dependencies.cmake @@ -1,27 +1,20 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() -include("${CMAKE_CURRENT_LIST_DIR}/O2RecipeAdapter.cmake") include("${CMAKE_CURRENT_LIST_DIR}/O2TestsAdapter.cmake") set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH}) -if(ALIBUILD_BASEDIR) - # try autodetecting external packages from an alibuild installation zone - include(O2FindDependenciesFromAliBuild) - o2_find_dependencies_from_alibuild(${ALIBUILD_BASEDIR} LABEL ${ALIBUILD_LABEL} - QUIET) -endif() - # Required packages # # Order is not completely irrelevant. For instance arrow must come before @@ -45,6 +38,8 @@ set_package_properties(Vc PROPERTIES TYPE REQUIRED) find_package(ROOT 6.20.02) set_package_properties(ROOT PROPERTIES TYPE REQUIRED) +find_package(VMC) + find_package(fmt) set_package_properties(fmt PROPERTIES TYPE REQUIRED) @@ -73,8 +68,8 @@ set_package_properties(FairLogger PROPERTIES TYPE REQUIRED) find_package(FairRoot MODULE) set_package_properties(FairRoot PROPERTIES TYPE REQUIRED) -find_package(ms_gsl MODULE) -set_package_properties(ms_gsl +find_package(Microsoft.GSL CONFIG) +set_package_properties(Microsoft.GSL PROPERTIES TYPE REQUIRED PURPOSE "Mainly for its span") @@ -82,8 +77,8 @@ set_package_properties(ms_gsl find_package(FairMQ CONFIG) set_package_properties(FairMQ PROPERTIES TYPE REQUIRED) -find_package(protobuf CONFIG) -set_package_properties(protobuf PROPERTIES TYPE REQUIRED PURPOSE "For CCDB API") +# find_package(protobuf CONFIG) +# set_package_properties(protobuf PROPERTIES TYPE REQUIRED PURPOSE "For CCDB API") find_package(InfoLogger CONFIG NAMES InfoLogger libInfoLogger) set_package_properties(InfoLogger PROPERTIES TYPE REQUIRED) @@ -103,6 +98,15 @@ set_package_properties(RapidJSON PROPERTIES TYPE REQUIRED) find_package(CURL) set_package_properties(CURL PROPERTIES TYPE REQUIRED) +find_package(JAliEnROOT MODULE) +set_package_properties(JAliEnROOT PROPERTIES TYPE RECOMMENDED) + +find_package(XRootD MODULE) +set_package_properties(XRootD PROPERTIES TYPE RECOMMENDED) + +find_package(libjalienO2 MODULE) +set_package_properties(libjalienO2 PROPERTIES TYPE REQUIRED PURPOSE "For CCDB API") + # MC specific packages message(STATUS "Input BUILD_SIMULATION=${BUILD_SIMULATION}") include("${CMAKE_CURRENT_LIST_DIR}/O2SimulationDependencies.cmake") @@ -136,7 +140,10 @@ set_package_properties(AliRoot find_package(GLEW) set_package_properties(GLEW PROPERTIES TYPE OPTIONAL) - +find_package(X11) +set_package_properties(X11 PROPERTIES TYPE OPTIONAL) +find_package(GLUT) +set_package_properties(GLUT PROPERTIES TYPE OPTIONAL) find_package(OpenGL) set_package_properties(OpenGL PROPERTIES TYPE OPTIONAL) @@ -152,4 +159,7 @@ find_package(O2GPU) find_package(FastJet) +find_package(FFTW3f CONFIG) +set_package_properties(FFTW3f PROPERTIES TYPE REQUIRED) + feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/dependencies/O2FindDependenciesFromAliBuild.cmake b/dependencies/O2FindDependenciesFromAliBuild.cmake deleted file mode 100644 index 6cb2795804f6c..0000000000000 --- a/dependencies/O2FindDependenciesFromAliBuild.cmake +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -include_guard() -# -# o2_find_dependencies_from_alibuild(basedir ...) will locate, all our external -# dependencies from a typical alibuild installation. -# -# * basedir : the top directory of the alibuild installation, -# $HOME/alice/sw/[osname] typically -# * LABEL (`latest` by default) : the label of the installation -# -# In the example below, basedir would be ~/alice/sw/osx_x86-64 and LABEL could -# be either `label` or `label-cmake-reorg-o2` -# -# cmake-format: off -# -# ~/alice/sw -# ├── BUILD -# ├── INSTALLROOT -# ├── MIRROR -# ├── MODULES -# ├── SOURCES -# ├── SPECS -# ├── TARS -# ├── osx_x86-64 -# │   ├── FairMQ -# │   │   ├── latest -> v1.4.2-1 -# │   │   ├── latest-cmake-reorg-o2 -> v1.4.2-1 -# │   │   └── v1.4.2-1 -# │   ├── GEANT4 -# │   │   ├── latest -> v10.4.2-1 -# │   │   ├── latest-cmake-reorg-o2 -> v10.4.2-1 -# │   │   └── v10.4.2-1 -# │   ├── ROOT -# │   │   ├── latest -> v6-16-00-1 -# │   │   ├── latest-cmake-reorg-o2 -> v6-16-00-1 -# │   │   └── v6-16-00-1 -# │   ├── RapidJSON -# │   │   ├── 091de040edb3355dcf2f4a18c425aec51b906f08-1 -# │   │   ├── latest -> 091de040edb3355dcf2f4a18c425aec51b906f08-1 -# │   │   └── latest-cmake-reorg-o2 -> 091de040edb3355dcf2f4a18c425aec51b906f08-1 -# -# cmake-format: on - -function(o2_find_dependencies_from_alibuild) - - if(DEPENDENCIES_FROM_ALIBUILD_DONE) - return() - endif() - - cmake_parse_arguments(PARSE_ARGV - 1 - A - "" - "LABEL;QUIET" - "") - - set(basedir ${ARGV0}) - if(A_LABEL AND NOT "${A_LABEL}" STREQUAL "") - set(label ${A_LABEL}) - else() - set(label latest) - endif() - - macro(protected_set_root var) - if(DEFINED ${var}_ROOT) - if(NOT A_QUIET) - message(STATUS "${var}_ROOT already defined. Not autodetecting it.") - endif() - else() - if(${ARGC} LESS 2) - # if we have only one argument, use value=var - set(value ${var}) - else() - set(value ${ARGV1}) - endif() - set(dir ${basedir}/${value}/${label}) - if(IS_DIRECTORY ${dir}) - set(${var}_ROOT ${dir} CACHE STRING "top dir for ${pkg}") - if(NOT A_QUIET) - message(STATUS "Detected ${var}_ROOT=${dir}") - endif() - else() - if(NOT A_QUIET) - message( - STATUS "Could not detect ${var}_ROOT from alibuild installation") - endif() - endif() - unset(dir) - unset(value) - endif() - endmacro() - - macro(protected_set_dir var) - if(DEFINED ${var}_DIR) - if(NOT A_QUIET) - message(STATUS "${var}_DIR already defined. Not autodetecting it.") - endif() - else() - if(${ARGC} LESS 2) - # if we have only one argument, use value=var - set(value ${var}) - set(pkg ${var}) - elseif(${ARGC} LESS 3) - set(value ${ARGV1}) - set(pkg ${var}) - else() - set(value ${ARGV1}) - set(pkg ${ARGV2}) - endif() - set(dir ${basedir}/${pkg}/${label}/lib/cmake/${value}) - if(IS_DIRECTORY ${dir}) - set(${var}_DIR - ${dir} - CACHE STRING "location of cmake config for ${pkg}") - if(NOT A_QUIET) - message(STATUS "Detected ${var}_DIR=${dir}") - endif() - else() - if(NOT A_QUIET) - message( - STATUS "Could not detect ${var}_DIR from alibuild installation") - endif() - endif() - unset(dir) - endif() - endmacro() - - protected_set_root(DDS) - protected_set_root(protobuf) - protected_set_root(Common Common-O2) - protected_set_root(Configuration) - protected_set_root(Monitoring) - protected_set_root(FairMQ) - protected_set_root(FairLogger) - protected_set_root(FairRoot) - protected_set_root(InfoLogger libInfoLogger) - protected_set_root(BOOST boost) - protected_set_root(ROOT) - protected_set_root(RapidJSON) - protected_set_root(ms_gsl) - protected_set_root(ZeroMQ) - - protected_set_root(pythia) - protected_set_root(pythia6) - protected_set_root(Geant3 GEANT3) - protected_set_root(Geant4 GEANT4) - protected_set_root(Geant4VMC GEANT4_VMC) - protected_set_root(VGM vgm) - protected_set_root(HepMC HepMC3) - - protected_set_dir(arrow) - protected_set_dir(benchmark benchmark googlebenchmark) - protected_set_dir(Vc) - - protected_set_root(cub) - - find_program(brew_CMD brew) - if(brew_CMD) - execute_process(COMMAND ${brew_CMD} --PREFIX glfw - OUTPUT_VARIABLE result - OUTPUT_STRIP_TRAILING_WHITESPACE) - get_filename_component(glfw ${result}/lib/cmake ABSOLUTE) - if(EXISTS ${glfw}) - if(NOT A_QUIET) - message(STATUS "Detected GLFW_DIR=${glfw}") - endif() - set(GLFW_DIR ${glfw} PARENT_SCOPE) - endif() - endif() - - set( - DEPENDENCIES_FROM_ALIBUILD_DONE - TRUE - CACHE BOOL - "whether the dependencies where found from an alibuild installation") -endfunction() diff --git a/dependencies/O2RecipeAdapter.cmake b/dependencies/O2RecipeAdapter.cmake deleted file mode 100644 index 39d707f8a3275..0000000000000 --- a/dependencies/O2RecipeAdapter.cmake +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. - -# FIXME: this part should disappear when we merge all this new cmake stuff and -# we change the o2.sh recipe accordingly. -# -# we unset most of the -D variables that were passed to cmake so our auto- -# detection has a chance to work. Should not be needed in the long run if we use -# the correct -D set from the beginning -# - -function(o2_show_env var) - if(DEFINED ENV{${var}}) - file(TO_CMAKE_PATH $ENV{${var}} path) - message(STATUS "!!!") - message(STATUS "!!! ${var} is : ") - foreach(v IN LISTS path) - message(STATUS "!!! - ${v}") - endforeach() - endif() -endfunction() - -macro(o2_unset var) - message(STATUS "!!! Unsetting ${var}=${${var}}") - unset(${var}) -endmacro() - -if(ALICEO2_MODULAR_BUILD) - - message(STATUS "!!!") - message(STATUS "!!! Using O2RecipeAdapter - this should be only temporary") - message(STATUS "!!!") - - # - # we use the presence of ALICEO2_MODULAR_BUILD as a signal that we are using - # the old recipe and we assume Common_O2_ROOT is defined and can be used to - # retrieve the ALIBUILD_BASEDIR - # - - if(NOT Common_O2_ROOT) - message(FATAL_ERROR "Don't know how to adapt (yet) to this situation") - endif() - get_filename_component(ALIBUILD_BASEDIR ${Common_O2_ROOT}/../.. ABSOLUTE) - message( - STATUS - "!!! Used Common_O2_ROOT location to compute ALIBUILD_BASEDIR=${ALIBUILD_BASEDIR}" - ) - - message( - STATUS "!!! Unsetting most of the -D options and detecting them instead") - message(STATUS "!!!") - - set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) - - o2_unset(FairRoot_DIR) - o2_unset(ALICEO2_MODULAR_BUILD) - o2_unset(ROOTSYS) - o2_unset(Pythia6_LIBRARY_DIR) - o2_unset(Geant3_DIR) - o2_unset(Geant4_DIR) - o2_unset(VGM_DIR) - o2_unset(GEANT4_VMC_DIR) - o2_unset(FAIRROOTPATH) - o2_unset(BOOST_ROOT) - o2_unset(DDS_PATH) - o2_unset(ZMQ_DIR) - o2_unset(ZMQ_INCLUDE_DIR) - o2_unset(ALIROOT) - o2_unset(Protobuf_LIBRARY) - o2_unset(Protobuf_LITE_LIBRARY) - o2_unset(Protobuf_PROTOC_LIBRARY) - o2_unset(Protobuf_INCLUDE_DIR) - o2_unset(Protobuf_PROTOC_EXECUTABLE) - o2_unset(GSL_DIR) - o2_unset(PYTHIA8_INCLUDE_DIR) - o2_unset(HEPMC3_DIR) - o2_unset(MS_GSL_INCLUDE_DIR) - o2_unset(ALITPCCOMMON_DIR) - o2_unset(Monitoring_ROOT) - o2_unset(Configuration_ROOT) - o2_unset(InfoLogger_ROOT) - o2_unset(Common_O2_ROOT) - o2_unset(RAPIDJSON_INCLUDEDIR) - o2_unset(ARROW_HOME) - o2_unset(benchmark_DIR) - o2_unset(GLFW_LOCATION) - o2_unset(CUB_ROOT) - - o2_show_env(LD_LIBRARY_PATH) - o2_show_env(PATH) - -endif() diff --git a/dependencies/O2SimulationDependencies.cmake b/dependencies/O2SimulationDependencies.cmake index 6d69d467a024d..c50b432a111df 100644 --- a/dependencies/O2SimulationDependencies.cmake +++ b/dependencies/O2SimulationDependencies.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # # Note that the BUILD_SIMULATION option governs what to do with the simulation @@ -63,6 +64,9 @@ set_package_properties(Geant4 find_package(Geant4VMC MODULE) set_package_properties(Geant4VMC PROPERTIES TYPE ${mcPackageRequirement}) +find_package(FlukaVMC MODULE) +set_package_properties(FlukaVMC PROPERTIES TYPE OPTIONAL) + find_package(VGM MODULE) set_package_properties(VGM PROPERTIES TYPE ${mcPackageRequirement}) diff --git a/dependencies/O2TestsAdapter.cmake b/dependencies/O2TestsAdapter.cmake index d3f587006099a..f4aabd3ff45ff 100644 --- a/dependencies/O2TestsAdapter.cmake +++ b/dependencies/O2TestsAdapter.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # We patch those tests that require some environment (most notably the O2_ROOT # variable) to convert from O2_ROOT pointing to build tree to O2_ROOT pointing diff --git a/doc/CMakeInstructions.md b/doc/CMakeInstructions.md index 4d79a7e38abd3..c4f55140f611c 100644 --- a/doc/CMakeInstructions.md +++ b/doc/CMakeInstructions.md @@ -6,20 +6,20 @@ <!-- vim-markdown-toc GFM --> -- [CMake and CTest tips for AliceO2](#cmake-and-ctest-tips-for-aliceo2) - - [CMake](#cmake) - - [Instructions for contributors (aka developers' documentation)](#instructions-for-contributors-aka-developers-documentation) - - [Typical CMakeLists.txt](#typical-cmakeliststxt) - - [Examples](#examples) - - [Ex1 Adding a basic library](#ex1-adding-a-basic-library) - - [Ex2 Adding a basic library with a Root dictionary](#ex2-adding-a-basic-library-with-a-root-dictionary) - - [Ex3 Adding an executable](#ex3-adding-an-executable) - - [Ex4 Adding a couple of tests](#ex4-adding-a-couple-of-tests) - - [Ex5 Adding a man page](#ex5-adding-a-man-page) - - [CTest](#ctest) - - [Selecting/excluding by test name (-R/-E)](#selectingexcluding-by-test-name--r-e) - - [Selecting/excluding by label (-L/-LE)](#selectingexcluding-by-label--l-le) - - [Speeding up ctest execution](#speeding-up-ctest-execution) +* [CMake and CTest tips for AliceO2](#cmake-and-ctest-tips-for-aliceo2) + * [CMake](#cmake) + * [Instructions for contributors (aka developers' documentation)](#instructions-for-contributors-aka-developers-documentation) + * [Typical CMakeLists.txt](#typical-cmakeliststxt) + * [Examples](#examples) + * [Ex1 Adding a basic library](#ex1-adding-a-basic-library) + * [Ex2 Adding a basic library with a Root dictionary](#ex2-adding-a-basic-library-with-a-root-dictionary) + * [Ex3 Adding an executable](#ex3-adding-an-executable) + * [Ex4 Adding a couple of tests](#ex4-adding-a-couple-of-tests) + * [Ex5 Adding a man page](#ex5-adding-a-man-page) + * [CTest](#ctest) + * [Selecting/excluding by test name (-R/-E)](#selectingexcluding-by-test-name--r-e) + * [Selecting/excluding by label (-L/-LE)](#selectingexcluding-by-label--l-le) + * [Speeding up ctest execution](#speeding-up-ctest-execution) <!-- vim-markdown-toc --> @@ -340,6 +340,15 @@ Tests can also be _excluded_ based on label (`-LE`) or name (`-RE`). dummy = 0.07 sec*proc (1 test) fast = 0.07 sec*proc (1 test) +Note as well that some (very few) tests are ran only for some configurations +(aka build types). Those tests are _not_ ran automatically when using the bare +`ctest` command. One has to explicitely specify the build type for those, e.g. +: + +``` +ctest -C RelWithDebInfo +``` + #### [Ex5](../Examples/Ex5) Adding a man page If a module provides one or more executables, it might be of interest for the users of those executables to have access to a man page for them. Ex5 illustates that use case. diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 7ce37c657235e..58dcd585a1185 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # # Build the doxygen diff --git a/doc/DetectorSimulation.md b/doc/DetectorSimulation.md index de89e32b973e4..e72919c18fe20 100644 --- a/doc/DetectorSimulation.md +++ b/doc/DetectorSimulation.md @@ -32,7 +32,7 @@ The purpose of the `o2-sim` executable is to simulate the passage of particles e ## Usage overview * **Quick start example:** A typical (exemplary) invocation is of the form - ```o2-sim -n 10 -g pythia8 -e TGeant4 -j 2 --skipModules ZDC,PHS``` + ```o2-sim -n 10 -g pythia8pp -e TGeant4 -j 2 --skipModules ZDC,PHS``` which would launch a simulation for 10 pythia8 events on the whole ALICE detector but ZDC and PHOS, using Geant4 on 2 parallel worker processes. * **Generated output**: The simulation creates the following output files: @@ -44,9 +44,9 @@ The purpose of the `o2-sim` executable is to simulate the passage of particles e | `o2sim_grp.root` | special global run parameters (grp) such as field | | `o2sim_XXXHits.root` | hit file for each participating active detector XXX | | `o2sim_configuration.ini` | summary of parameter values with which the simulation was done | -| `serverlog` | log file produced from the particle generator server | -| `workerlog` | log file produced form the transportation processes | -| `hitmergerlog` | log file produced from the IO process | +| `o2sim_serverlog` | log file produced from the particle generator server | +| `o2sim_workerlog` | log file produced form the transportation processes | +| `o2sim_hitmergerlog` | log file produced from the IO process | * **Main command line options**: The following major options are available (incomplete): @@ -55,7 +55,7 @@ The purpose of the `o2-sim` executable is to simulate the passage of particles e | --------------------- | -------------------------------------------------------------------------------------- | | -h,--help | Prints the list of possible command line options and their default values. | | -n,--number | The number of events to simulate. | -| -g,--generator | name of a predefined generator template to use (such as pythia8, pythia8hi). Configuration of generations is explained in a dedicated section. | +| -g,--generator | name of a predefined generator template to use (such as pythia8pp, pythia8hi). Configuration of generations is explained in a dedicated section. | | -e,--engine | Select the VMC transport engine (TGeant4, TGeant3). | | -m,--modules | List of modules/geometries to include (default is ALL); example -m PIPE ITS TPC | | -j,--nworkers | Number of parallel simulation engine workers (default is half the number of hyperthread CPU cores) | @@ -86,7 +86,7 @@ Important parameters influencing the transport simulation are: | Main parameter key | Description | | --- | --- | -| G4 | Parameters influencing the Geant4 engine, such as the physics list. Example "G4.physicslist=kFTFP_BERT_optical_biasing" | +| G4 | Parameters influencing the Geant4 engine, such as the physics list. Example "G4.physicsmode=kFTFP_BERT_optical_biasing" | | Stack | Parameters influencing the particle stack. Example include whether the stack does kinematics pruning or whether it keeps secondaries at all. | | SimCutParams | Parameters allowing to set some sime geometry stepping cuts in R, Z, etc. | | Diamond | Parameter allowing to set the interaction vertex location and the spread/width. Is used in all event generators. | @@ -120,7 +120,7 @@ o2-sim -m PIPE ITS MFT -e TGeant3 -g boxgen -n 10 --configKeyValues 'BoxGun.pdg= Configures pythia8 for min.bias pp collisions at 14 TeV ``` -o2-sim -m PIPE ITS MFT -g pythia8 -n 50 +o2-sim -m PIPE ITS MFT -g pythia8pp -n 50 ``` [Describe in detail the environment variables] @@ -181,13 +181,13 @@ All event generator interfaces that comply with the `o2::eventgen::Generator` pr A basic 'particle trigger' is implemented in the `o2::eventgen` core and allows the user to define a trigger particle. The definitions of the trigger particle can be expressed via command line arguments ``` -o2-sim -g pythia8 -t particle --configKeyValues "TriggerParticle.pdg=333;TriggerParticle.ptMin=5.;TriggerParticle.yMin=-0.5;TriggerParticle.yMax=0.5" +o2-sim -g pythia8pp -t particle --configKeyValues "TriggerParticle.pdg=333;TriggerParticle.ptMin=5.;TriggerParticle.yMin=-0.5;TriggerParticle.yMax=0.5" ``` Custom triggers can also be constructed by the user to provide unlimited flexibility in the trigger needs. An external trigger function can be specified via command line arguments ``` -o2-sim -g pythia8 -t external --configKeyValues 'TriggerExternal.fileName=path_to_trigger_macro.C;TriggerExternal.funcName="the_function(some, parameters)"' +o2-sim -g pythia8pp -t external --configKeyValues 'TriggerExternal.fileName=path_to_trigger_macro.C;TriggerExternal.funcName="the_function(some, parameters)"' ``` The function must comply with a simple protocol and return a lambda function defined as follows ``` @@ -205,7 +205,7 @@ To allow users to define triggers that go beyond the particle stack generated by This allows the user to go deep into the core of the event generator, whenever this is possible. For this reason, this is called a 'DeepTrigger'. A 'DeepTrigger' is attached to the simulation in the same way as a normal trigger ``` -o2-sim -g pythia8 -t external --configKeyValues 'TriggerExternal.fileName=path_to_deep_trigger_macro.C;TriggerExternal.funcName="the_deep_function(some, parameters)"' +o2-sim -g pythia8pp -t external --configKeyValues 'TriggerExternal.fileName=path_to_deep_trigger_macro.C;TriggerExternal.funcName="the_deep_function(some, parameters)"' ``` In this case the function must comply with a similar, but different protocol than before and return a lambda function defined as follows ``` o2::eventgen::DeepTrigger the_deep_function() @@ -258,7 +258,7 @@ This functionality might be of use for users who want to be able to steer the ev An example of a configuration macro is this one ``` -// usage: o2sim -g pythia8 --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_charm.C" +// usage: o2sim -g pythia8pp --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_charm.C" #include "Generators/Trigger.h" #include "Pythia8/Pythia.h" @@ -361,13 +361,37 @@ Digitization - the transformation of hits produced in the transport simulation t | --sims | Comma separated list of simulation prefixes that should be overlaid/embedded. Example `--sims background,signal` where `background` and `signal` refer to transport simulation productions. Final collisions will be composed from both of them (in a round robin fashion). See separate section about [Embedding](#Embedding) for more details. If just one prefix is given, normal digitization without overlay will be done. | | --tpc-lanes | Number of parallel digitizers for TPC, which has a special attention due an increased data rate compared to other detectors. | | | --interactionRate | Total hadronic interaction rate (Hz). | -| --bcPatternFile | Interacting BC pattern file chaning the default bunch crossing pattern. | +| --bcPatternFile | Interacting BC pattern file chaning the default bunch crossing pattern, see `macro/CreateBCPattern.C` for details. | | --onlyDet | Comma separated list of detectors to digitize. (Default is all) | | --skipDet | Comma separed list of detectors to exclude. | | --incontext | Name of context file. Useful for reusing a context from a previous run when we split the processing detectorwise. | | --outcontext | Specify name of contextfile to produce. | | --simFileQED | Optional special QED hit file to include effect from QED effects into digitization. | +## Interaction sampling <a name="Interaction sampling"></a> + +The files produced by the `o2-sim` contain only a set of separate events, w/o any time stamp. The digitization will sample the vector of non-decreasing `{BC/orbit}` pairs according to bunch filling schema and requested interaction rate and provide it to digitizers. +The interaction sampling is steered by the `HBFUtils` configurable parameters, e.g. + +```o2-sim-digitizer-workflow --configKeyValues "HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=123;HBFUtils.orbitFirstSampled=300"``` + +The most important here is `HBFUtils.orbitFirstSampled` which tells to `InteractionSampler` the orbit from which the sampling should start. +Other parameters, `nHBFPerTF` and `orbitFirst` do not directly affect the digitization but they are stored in the `grp` object (`o2sim_grp.root` file) and the number of orbits per TF and the 1st orbit of the run. +The full content of the `HBFUtils` is stored in the `o2simdigitizerworkflow_configuration.ini` and can be used in reconstruction and MC->raw-data creation processes. +Particularly, when creating the raw data (see `...-digi2raw` group of commands in `O2/prodtests/full_system_test.sh`) the content of the `HBFUtils` settings will be loaded from this ini file +(the name can be changed via `--hbfutils-config <ini-file>` option) and `HBFUtils.orbitFirst` will be used to define the start-of-the-run (`SOX flag in the RDH`) and `HBFUtils.nHBFPerTF` will be used to chop the digitized data to TFs. +Note that for the detectors in continuous readout mode all empty HBFs will be created for all orbits w/o detector data between the `SOX` and the last orbit of the TF for which data was received. +In case you want to create raw data starting from the 1st sampled TF, you should override the `HBFUtils.orbitFirst` by the wanted orbit, i.e. for the digitization done as in the example above +one can request + +```o2-ft0-digi2raw --configKeyValues "HBFUtils.orbitFirst=251" ...``` + +to start the raw data not from the orbit 123 indicated during digitization but from the orbit 251 (i.e. the 2nd TF of the run). Additional setting `HBFUtils.maxNOrbits` can be provided +to limit the number of orbits stored (counted from the `SOX`) in the raw data (i.e. all data with `orbit > HBFUtils.orbitFirst + HBFUtils.maxNOrbits` will be ignored when creating the raw data. + +Similarly, when running the reconstruction workflow using the output of the digitization, the `HBFUtils` settings used by `o2-sim-digitizer-workflow` will be loaded (again, they can be overridden +by either providing `--hbfutils-config <ini-file>` option or by explicit `--configKeyValues "HBFUtils...` setting) and the DPL will make sure that the content of the `DataHeader.firstTForbit` correspond +to the 1st orbit of the TF containing `HBFUtils.orbitFirstSampled` (then incremented by `HBFUtils.nHBFPerTF` for the following TFs if the digits files contain multiple TF entries). ## Embedding <a name="Embedding"></a> @@ -416,7 +440,7 @@ for (auto& label : labels_for_digit) { ``` -## Accessing Monte Carlo kinematics after the digitization phase <a name="MCReader"></a> +## Accessing Monte Carlo kinematics<a name="MCReader"></a> After digitization is done, one can use the `MCKinematicsReader` class to load and access the Monte Carlo tracks. The MCKinematicsReader needs the digitization context file, generated during digitization. Once initialized it can return the tracks associated to a Monte Carlo label. @@ -441,6 +465,21 @@ for (int pos = 0; pos < alldigits.size(); ++pos) { } } ``` +Note, that one can also access kinematics directly after the transport simulation. +In this case, one needs to initialize the MCKinematicsReader in a different mode: +```c++ +// init the reader from the transport kinematics file (assuming here prefix o2sim) +o2::steer::MCKinematicsReader reader("o2sim", o2::steer::MCKinematicsReader::Mode::kMCKine); + +// loop over all events in the file +for (int event = 0; event < reader.getNEvents(0); ++event) { + // get all Monte Carlo tracks for this event + std::vector<MCTrack> const& tracks = reader.getTracks(event); + + // analyse tracks +} +``` + # Simulation tutorials/examples <a name="Examples"></a> @@ -454,7 +493,11 @@ Other helpful resources are the scripts used for regression testing in [prodtest | [AliRoot_AMPT](../run/SimExamples/AliRoot_AMPT) | Example showing how to use AMPT from AliRoot for event generation | | [Adaptive_Pythia8](../run/SimExamples/Adaptive_Pythia8) | Complex example showing **generator configuration for embedding** that cat adapt the response based on the background event | | [Signal_ImpactB](../run/SimExamples/Signal_ImpactB) | Example showing **generator configuration for embedding** that cat adapt to the impact parameter of the background event | +| [PrimaryKinematics](../run/SimExamples/JustPrimaryKinematics) | Example showing how to obtain only primary kinematics via transport configuration | | [HepMC_STARlight](../run/SimExamples/HepMC_STARlight) | Simple example showing **generator configuration** that runs a standalone `STARlight` generation that couples to the `o2` via a `HepMC` file | | [Jet_Embedding_Pythia](../run/SimExamples/Jet_Embedding_Pythia8) | Complex example showing **generator configuration**, **digitization embedding**, **MCTrack access** | +| [Selective_Transport](../run/SimExamples/Selective_Transport) | Simple example showing how to run simulation transporting only a custumisable set of particles | +| [Selective_Transport_pi0](../run/SimExamples/Selective_Transport_pi0) | Complex example showing how to run simulation within the inhibit-pause-trigger-continue approach | +| [Custom_EventInfo](../run/SimExamples/Custom_EventInfo) | Simple example showing how to add custom information to the MC event header | | [sim_challenge.sh](../prodtests/sim_challenge.sh) | Basic example doing a **simple transport, digitization, reconstruction pipeline** on the full dectector. All stages use parallelism. | | [sim_performance.sh](../prodtests/sim_performance_test.sh) | Basic example for serial transport and linearized digitization sequence (one detector after the other). Serves as standard performance candle. | diff --git a/doc/README.md b/doc/README.md index b699306179b00..68520ab356009 100644 --- a/doc/README.md +++ b/doc/README.md @@ -15,4 +15,5 @@ This module contains the documentation pages. * \subpage refdocDoxygenInstructions * \subpage refdocManPages * \subpage refdocUpgrades +* \subpage refprodtestsfull-system-test /doxy --> diff --git a/doc/data/2021-01-o2_prs.json b/doc/data/2021-01-o2_prs.json new file mode 100644 index 0000000000000..12a0ea55f0699 --- /dev/null +++ b/doc/data/2021-01-o2_prs.json @@ -0,0 +1,4603 @@ +{ + "repository": { + "pullRequests": { + "edges": [ + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T07:51:53Z", + "title": "PWGHF : syncing decays in the preselection with enums used for MC", + "number": 5223, + "author": { + "login": "nzardosh" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/HFConfigurables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T15:08:15Z", + "title": "PWGHF: Shift decay type values to allow usage in arrays and bitmaps.", + "number": 5224, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T09:18:17Z", + "title": "[EMCAL-630] Fix assignment of energy and time", + "number": 5225, + "author": { + "login": "mfasDa" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T14:04:52Z", + "title": "Bugfix: WorkflowHelper.h was not installled", + "number": 5226, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/CMakeLists.txt" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T16:07:16Z", + "title": "Check for selective primary transport also in case of parallel sim", + "number": 5227, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCTrack.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/Stack.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/src/Stack.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T13:19:49Z", + "title": "o2-sim: Make configfile prefixed with correct name", + "number": 5228, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h" + } + }, + { + "node": { + "path": "doc/DetectorSimulation.md" + } + }, + { + "node": { + "path": "macro/o2sim.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T18:31:34Z", + "title": "raw-parser logs DataHeader and DataProcessingHeader info", + "number": 5229, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Utils/include/DPLUtils/DPLRawParser.h" + } + }, + { + "node": { + "path": "Framework/Utils/src/raw-parser.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T01:21:48Z", + "title": "Pileup and calibration DA for PHOS and CPV", + "number": 5230, + "author": { + "login": "peressounko" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Cluster.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/PHOS/src/Cluster.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/base/include/CPVBase/CPVSimParams.h" + } + }, + { + "node": { + "path": "Detectors/CPV/base/include/CPVBase/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVBadMapCalibDevice.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVGainCalibDevice.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/include/CPVCalibWorkflow/CPVPedestalCalibDevice.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/CPVBadMapCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/CPVGainCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/CPVPedestalCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/cpv-calib-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/include/CPVCalib/CalibParams.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/include/CPVCalib/Pedestals.h" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/src/Pedestals.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/cpv-reco-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/base/include/PHOSBase/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/base/include/PHOSBase/PHOSSimParams.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSCalibCollector.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSHGLGRatioCalibDevice.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSCalibCollector.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSCalibWorkflowLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSHGLGRatioCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSPedestalCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/phos-calib-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/include/PHOSCalib/BadChannelMap.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/include/PHOSCalib/CalibParams.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/src/BadChannelMap.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/src/CalibParams.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/src/PHOSCalibLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/src/Pedestals.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/reconstruction/include/PHOSReconstruction/CaloRawFitter.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/reconstruction/include/PHOSReconstruction/FullCluster.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/reconstruction/src/FullCluster.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/reconstruction/src/PHOSReconstructionLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/CPVDigitizerSpec.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/CPVDigitizerSpec.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-19T19:57:45Z", + "title": "Make sure benchmark::benchmark stays optional (O2-1973)", + "number": 5231, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Utils/CMakeLists.txt" + } + }, + { + "node": { + "path": "Utilities/Mergers/CMakeLists.txt" + } + }, + { + "node": { + "path": "Utilities/rANS/CMakeLists.txt" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T08:41:11Z", + "title": "PWGHF : further restricitng HF preselection for hyperloop testing", + "number": 5232, + "author": { + "login": "nzardosh" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/HFConfigurables.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T08:43:04Z", + "title": "TPC Workflow / Tracking: Remove dead codee", + "number": 5233, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/GPUCATracking.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CATrackerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "macro/CMakeLists.txt" + } + }, + { + "node": { + "path": "macro/runCATrackingClusterNative.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T09:28:25Z", + "title": "Abstract and track aggregated containers/indices + use in vertexers", + "number": 5234, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Reconstruction/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackAccessor.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/GlobalTrackID.cxx" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/VtxTrackIndex.cxx" + } + }, + { + "node": { + "path": "DataFormats/common/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/common/include/CommonDataFormat/AbstractRefAccessor.h" + } + }, + { + "node": { + "path": "DataFormats/common/src/AbstractRefAccessor.cxx" + } + }, + { + "node": { + "path": "DataFormats/common/src/CommonDataFormatLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/common/test/testAbstractRefAccessor.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/StandaloneAODProducer.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/PVertexer.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/SVertexer.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/VertexTrackMatcher.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T17:33:09Z", + "title": "pileup check: fix type comparison", + "number": 5235, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "macro/analyzeDigitLabels.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T08:15:52Z", + "title": "DPL Analysis: consolidated Variant conversions", + "number": 5236, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ConfigParamRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantJSONHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantPropertyTreeHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantStringHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/PropertyTreeHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/RootConfigParamHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T15:02:03Z", + "title": "adding protection for float truncation", + "number": 5237, + "author": { + "login": "nzardosh" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/include/MathUtils/detail/TypeTruncation.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T15:36:16Z", + "title": "Fix missing TPC split task in CMakeFile", + "number": 5238, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T15:21:39Z", + "title": "Fix Z position of ML/OL modules to be symmetric wrt half stave center", + "number": 5239, + "author": { + "login": "mario6829" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "adapting nuclei spectra task to be ready for helium skimming", + "number": 5240, + "author": { + "login": "akalweit" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-20T19:02:18Z", + "title": "[O2-1977][CMake](fix) Filter out macros in build directory if any", + "number": 5241, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "cmake/O2GetListOfMacros.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-21T08:42:46Z", + "title": "Simplifications for TPC workflow", + "number": 5242, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/workflow/src/CATrackerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUDataTypes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUO2FakeClasses.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUOutputControl.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2Interface.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2Interface.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCSliceOutput.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "fix filtering and minor edits", + "number": 5243, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "fix filtering and minor edits", + "number": 5244, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-21T08:51:29Z", + "title": "fix filtering and minor edits", + "number": 5245, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-21T13:00:35Z", + "title": "[QC-526] Set message level to debug1 to avoid flood", + "number": 5246, + "author": { + "login": "Barthelemy" + }, + "files": { + "edges": [ + { + "node": { + "path": "CCDB/src/CcdbApi.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-21T10:11:52Z", + "title": "Fix compiler warning about signed / unsigned int", + "number": 5247, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/include/MathUtils/detail/TypeTruncation.h" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Move some internal headers from GPU/Common to GPU/GPUTracking + some CMake improvements", + "number": 5248, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/Common/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/cuda/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/opencl/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/opencl2/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDef.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefGPUParameters.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefMacros.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefOpenCL12Templates.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPULogging.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/Definitions" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T15:25:18Z", + "title": "TPCClusterFinder: Improve performance of noisy pad filter on CPU.", + "number": 5249, + "author": { + "login": "fweig" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/base/include/TPCBase/CalArray.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefGPUParameters.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/Array2D.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/PackedCharge.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/clusterFinderDefs.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T17:32:06Z", + "title": "Raw2Digits and Trigger", + "number": 5250, + "author": { + "login": "mbroz84" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/LookUpTable.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/RawEventData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/src/DataFormatsFDDLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/include/FDDRaw/DataBlockFDD.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/include/FDDRaw/DigitBlockFDD.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/include/FDDRaw/RawReaderFDDBase.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/src/DataBlockFDD.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/src/DigitBlockFDD.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/src/FDDRawLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/raw/src/RawReaderFDDBase.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/include/FDDSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawReaderFDD.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/DigitWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawReaderFDD.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/fdd-flp-workflow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/FDDDigitWriterSpec.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/FDDDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "The following changelog has been automatically generated.", + "number": 5251, + "author": { + "login": "github-actions" + }, + "files": { + "edges": [ + { + "node": { + "path": "CHANGELOG.md" + } + }, + { + "node": { + "path": "doc/data/2021-01-o2_prs.json" + } + }, + { + "node": { + "path": "doc/data/2021-01-o2_releases.json" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T08:44:35Z", + "title": "Workflow: use existing PR if creation fails", + "number": 5252, + "author": { + "login": "TimoWilken" + }, + "files": { + "edges": [ + { + "node": { + "path": ".github/workflows/reports.yml" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-21T21:15:30Z", + "title": "PID: Add single task for all tiny TPC PID information", + "number": 5253, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T13:34:37Z", + "title": "DPL: speed up single channel output proxy", + "number": 5254, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ExternalFairMQDeviceProxy.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T08:17:11Z", + "title": "adding collision selections", + "number": 5255, + "author": { + "login": "nzardosh" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCReference.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T19:09:24Z", + "title": "file reader for TPC Tracks and Clusters (+ MC info)", + "number": 5256, + "author": { + "login": "tklemenz" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/FileReaderWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/TrackReaderSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: First version of skimming for Lc --> K0s+p", + "number": 5257, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T14:30:15Z", + "title": "Analysis/Task/PWGDQ: remove unnecessary macro", + "number": 5258, + "author": { + "login": "dsekihat" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGDQ/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableMaker_pp.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T11:23:08Z", + "title": "Clean up GPU Folders / Includes; Split off GPUInterface in separate library", + "number": 5259, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUHostDataTypes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUO2DataTypes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUOutputControl.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPURawData.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUSettings.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUSettingsList.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTRDDef.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUdEdxInfo.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/TPCdEdxCalibrationSplines.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDef.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefGPUParameters.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefMacros.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefOpenCL12Templates.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPULogging.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/GPUTrackingLinkDef_O2.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingDefs.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2Interface.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2Interface.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceLinkDef.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/DataTypes" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/Definitions" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/display" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/makefiles/.gitignore" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/qa" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/qconfigoptions.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/qconfigoptions.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/utils" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/GL/gl3w.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/GL/glcorearb.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/HandMadeMath.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/HandMadeMath/HandMadeMathImpl.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/KHR/khrplatform.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/3rdparty/gl3w.c" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplay.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplay.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackend.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackend.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlfw.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlfw.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlut.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlut.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendNone.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendNone.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendWindows.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendWindows.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendX11.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendX11.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayExt.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayInterpolation.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayKeys.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayQuaternion.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayShaders.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/bitmapfile.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/GPUQA.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/GPUQA.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/GPUQAHelper.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/genEvents.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/genEvents.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qconfigoptions.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/.gitattributes" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/.gitignore" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/bitfield.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/include.S" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/linux_helpers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/makefile_opencl_compiler.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/opencl_compiler_structs.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/opencl_obtain_program.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/pthread_mutex_win32_wrapper.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qconfig.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qconfig.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qconfig_helpers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qconfigrtc.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qmaths_helpers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qsem.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qsem.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/threadserver.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/threadserver.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/timer.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/timer.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/vecpod.h" + } + }, + { + "node": { + "path": "macro/runTPCRefit.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-22T21:44:21Z", + "title": "PID: Remove exp values from tiny PID tables", + "number": 5260, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/PIDResponse.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "removing excessive copying", + "number": 5261, + "author": { + "login": "nzardosh" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCProvider.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T13:19:32Z", + "title": "adding macro to create space charge density maps from simulations", + "number": 5262, + "author": { + "login": "matthias-kleiner" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/spacecharge/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: Add a flag to the different LcpKpi decay channels", + "number": 5263, + "author": { + "login": "DelloStritto" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Fix tree creator", + "number": 5264, + "author": { + "login": "ginnocen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorD0ToKPi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorLcToPKPi.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-24T12:40:41Z", + "title": "PWGHF: Little fix of the J/ψ → e+ e- code.", + "number": 5265, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFJpsiToEECandidateSelector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T13:19:05Z", + "title": "DPL Analysis: make HistogramRegistry support StepTHn", + "number": 5266, + "author": { + "login": "mario-krueger" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tutorials/src/histogramRegistry.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/HistogramRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/StepTHn.h" + } + }, + { + "node": { + "path": "Framework/Core/src/HistogramRegistry.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/StepTHn.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HistogramRegistry.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T02:02:39Z", + "title": "Fix in indexing for Vertex-Track matching", + "number": 5267, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackRef.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/VtxTrackRef.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/VertexTrackMatcher.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T13:15:49Z", + "title": "Fix: default TPC reco output names propagated to dependent code", + "number": 5268, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/src/StandaloneAODProducer.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h" + } + }, + { + "node": { + "path": "Detectors/TOF/prototyping/findLabels.C" + } + }, + { + "node": { + "path": "Detectors/TOF/prototyping/findTOFclusterFromLabel.C" + } + }, + { + "node": { + "path": "macro/checkTOFMatching.C" + } + }, + { + "node": { + "path": "prodtests/sim_challenge.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T20:40:02Z", + "title": "Create TPC output tracks directly in O2 format on the GPU and write directly to SHM buffer", + "number": 5269, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/reconstruction/src/GPUCATracking.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/test/testGPUCATracking.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CATrackerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUMemoryResource.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUProcessor.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUProcessor.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionIncludesDevice.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionKernels.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUDataTypes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUOutputControl.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUSettingsList.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefGPUParameters.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMergerTypes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMO2Output.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/standalone.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/GPUQAHelper.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T14:44:51Z", + "title": "Revert \"Add full table writing tasks for D0 and Lc (#4910)\"", + "number": 5270, + "author": { + "login": "ginnocen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorD0ToKPi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorLcToPKPi.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-23T13:49:59Z", + "title": "Fix codechecker violations", + "number": 5271, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ZDC/raw/src/DumpRaw.cxx" + } + }, + { + "node": { + "path": "Utilities/Tools/cpulimit/process_group.c" + } + }, + { + "node": { + "path": "Utilities/Tools/cpulimit/process_iterator_linux.c" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T08:13:30Z", + "title": "Fix codechecker warnings", + "number": 5272, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/VertexerTraitsGPU.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UniquePointerHIP.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/UtilsHIP.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VectorHIP.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VertexerTraitsHIP.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/src/ContextHIP.hip.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/src/DeviceStoreVertexerHIP.hip.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/src/UtilsHIP.hip.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/src/VertexerTraitsHIP.hip.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Update NucleiSpectraTask.cxx for skimming with correct coding conventions", + "number": 5273, + "author": { + "login": "akalweit" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "adapting nuclex task to skim", + "number": 5274, + "author": { + "login": "akalweit" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T13:34:07Z", + "title": "updating nuclei task for skimming", + "number": 5275, + "author": { + "login": "akalweit" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T10:42:50Z", + "title": "Minor improvements", + "number": 5276, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/workflow/src/CATrackerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T22:12:19Z", + "title": "PWGHF: Add simple task dedicated to efficiency and one for QA", + "number": 5277, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskEfficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskSimple.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T10:48:36Z", + "title": "Cosmic tracking mode added for ITS", + "number": 5278, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx" + } + }, + { + "node": { + "path": "macro/run_trac_ca_its.C" + } + }, + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + }, + { + "node": { + "path": "prodtests/sim_challenge.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T07:16:47Z", + "title": "CPV geometry fix, run3 raw format. fix O2-1991", + "number": 5279, + "author": { + "login": "peressounko" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/CPV/base/include/CPVBase/CPVSimParams.h" + } + }, + { + "node": { + "path": "Detectors/CPV/base/include/CPVBase/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/CPV/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/CPVGainCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/calib/CPVCalibWorkflow/src/CPVPedestalCalibDevice.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/reconstruction/src/RawDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/include/CPVSimulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/GeometryParams.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/simulation/src/RawWriter.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/RawToDigitConverterSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T10:49:03Z", + "title": "Use global track indices for cross-detector matches", + "number": 5280, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCITS.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/TrackTPCITS.cxx" + } + }, + { + "node": { + "path": "DataFormats/common/include/CommonDataFormat/AbstractRef.h" + } + }, + { + "node": { + "path": "DataFormats/common/test/testAbstractRefAccessor.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTOF.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTPCITS.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/PVertexer.cxx" + } + }, + { + "node": { + "path": "macro/checkTOFMatching.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T02:51:18Z", + "title": "Fix: increment MCEventHeader class version", + "number": 5281, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T22:25:05Z", + "title": "DPL: refactor how we process control messages", + "number": 5282, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T13:44:10Z", + "title": "DPL: introduce a WebSocketHandler", + "number": 5283, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/src/Base64.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Base64.h" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/src/SHA1.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/SHA1.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Add WS DPL DriverClient.", + "number": 5284, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DeviceState.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DriverInfo.h" + } + }, + { + "node": { + "path": "Framework/Core/src/Base64.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Base64.h" + } + }, + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/src/SHA1.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/SHA1.h" + } + }, + { + "node": { + "path": "Framework/Core/src/TextDriverClient.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/TextDriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/GUISupport/src/FrameworkGUIDebugger.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2DiamondWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T16:15:35Z", + "title": "Fixes for TPC buffer alignment / 0-size buffers", + "number": 5285, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/workflow/src/CATrackerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T16:24:04Z", + "title": "Fix daughter labels when running parallel merger", + "number": 5286, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCTrack.h" + } + }, + { + "node": { + "path": "run/O2HitMerger.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T14:35:18Z", + "title": "jobutils improvements", + "number": 5287, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T10:47:27Z", + "title": "PWGHF: Update selection on Dplus flag", + "number": 5288, + "author": { + "login": "fcatalan92" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskDPlus.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T08:43:42Z", + "title": "GPU: Fix kernel call counters with OpenMP", + "number": 5289, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T22:51:15Z", + "title": "Use same detector argument for ctf-reader and ctf-writer in full system test", + "number": 5290, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T09:47:01Z", + "title": "Hide stderr output of lsof in jobutils", + "number": 5291, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-25T22:59:19Z", + "title": "Add FV0 and FDD raw generation to full system test", + "number": 5292, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T18:37:25Z", + "title": "DPL: Adds Variant JSON helpers", + "number": 5293, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/Array2D.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ConfigParamsHelper.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Variant.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantJSONHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/BoostOptionsRetriever.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ConfigParamsHelper.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/PropertyTreeHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/RootConfigParamHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Variant.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowSerializationHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_Variants.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T09:03:00Z", + "title": "DPL: use pid_t to refer to pids", + "number": 5294, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWG-HF: DONT MERGE YET- Testing CI- Add full table writing tasks for D0 and Lc", + "number": 5295, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorD0ToKPi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTreeCreatorLcToPKPi.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWG-HF: Add protection in RecoDecay before asking particle mass", + "number": 5296, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/RecoDecay.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T11:49:34Z", + "title": "Add JOBUTILS_JOB_SKIPCREATEDONE option, and do not wipe ctf_dictionar…", + "number": 5297, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + }, + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[WIP] A skeleton of ITS calibration using DPL workflows", + "number": 5298, + "author": { + "login": "iouribelikov" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/include/ITSCalibration/NoiseCalibratorSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromClusters.C" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/macros/MakeNoiseMapFromDigits.C" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/src/NoiseCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/src/NoiseCalibratorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/testWorkflow/README.md" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/testWorkflow/its-calib-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/macros/Calib/MakeNoiseMapFromClusters.C" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/its-cluster-reader-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T18:16:57Z", + "title": "removing TPerfStats", + "number": 5299, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T08:32:41Z", + "title": "Improve GPU Thread count parameters for TPC Clusterizer", + "number": 5300, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefGPUParameters.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/CfUtils.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/clusterFinderDefs.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-26T20:23:49Z", + "title": "DPL: improve WebSockets support", + "number": 5301, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T13:25:01Z", + "title": "Remove std::memcpy while processing data in compressor task", + "number": 5302, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TOF/compression/include/TOFCompression/CompressorTask.h" + } + }, + { + "node": { + "path": "Detectors/TOF/compression/src/CompressorTask.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/compression/src/tof-compressor.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "RecoDecay: getDaughters: Skip PDG check for the original particle.", + "number": 5303, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/RecoDecay.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: propaedeutic for WS based DriverClient", + "number": 5304, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLMonitoringBackend.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLMonitoringBackend.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/src/TextDriverClient.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/TextDriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Implementation of simulation inhibit-pause-trigger-continue features", + "number": 5305, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCTrack.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/Stack.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/src/Stack.cxx" + } + }, + { + "node": { + "path": "Generators/CMakeLists.txt" + } + }, + { + "node": { + "path": "Generators/include/Generators/GeneratorFromFile.h" + } + }, + { + "node": { + "path": "Generators/include/Generators/GeneratorFromO2KineParam.h" + } + }, + { + "node": { + "path": "Generators/src/Generator.cxx" + } + }, + { + "node": { + "path": "Generators/src/GeneratorFromFile.cxx" + } + }, + { + "node": { + "path": "Generators/src/GeneratorFromO2KineParam.cxx" + } + }, + { + "node": { + "path": "Generators/src/GeneratorsLinkDef.h" + } + }, + { + "node": { + "path": "Generators/src/PrimaryGenerator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T08:34:51Z", + "title": "Fix typo in full system test script", + "number": 5306, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T11:07:59Z", + "title": "GPU: Apparently one must not do find_package(ROCM)", + "number": 5307, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T08:43:18Z", + "title": "Fix typo again", + "number": 5308, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "corrected cdrum geometry, added heat strips", + "number": 5309, + "author": { + "login": "MarekKowalski1504" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T12:19:43Z", + "title": "Drop obsolete analysis example", + "number": 5310, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/TestWorkflows/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2AODDummy.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Allow copy elision when returning object", + "number": 5311, + "author": { + "login": "mpuccio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T11:38:58Z", + "title": "DPL: include what you use", + "number": 5312, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/test/test_ProcessorOptions.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_RegionInfoCallbackService.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_SimpleWildcard.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_SimpleWildcard02.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_Task.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/test_CCDBFetchToTimeframe.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T14:43:47Z", + "title": "DPL / DPL Analysis: Introduce LabeledArray as an option for Variant", + "number": 5313, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tutorials/src/configurableObjects.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Array2D.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ConfigParamRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ConfigParamSpec.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Configurable.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Variant.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantJSONHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantPropertyTreeHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/BoostOptionsRetriever.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ConfigParamsHelper.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/PropertyTreeHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Variant.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowSerializationHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_Variants.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T11:09:10Z", + "title": "Fix for alienv environment detection in full system test + minor unrelated fixes", + "number": 5314, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Standalone/tools/testCL.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/datadistribution.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/raw-reader.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Merge options on dump", + "number": 5315, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DriverInfo.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/runDataProcessing.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "fixing calculation of z-slice for hits with z<0", + "number": 5316, + "author": { + "login": "matthias-kleiner" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Fix TRD digit constructor w/o channel ID", + "number": 5317, + "author": { + "login": "martenole" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/Digit.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/Digit.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T16:35:17Z", + "title": "Update CODEOWNERS", + "number": 5318, + "author": { + "login": "martenole" + }, + "files": { + "edges": [ + { + "node": { + "path": "CODEOWNERS" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Add GPU standalone benchmark to normal O2 build", + "number": 5319, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUMemoryResource.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUSettingsList.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCSliceData.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/Benchmark/standalone.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/dummy.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplay.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlfw.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/GPUQA.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/qconfig.cxx" + } + }, + { + "node": { + "path": "dependencies/O2Dependencies.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T20:49:09Z", + "title": "Add option to create an o2 propagator instance uninitialized to be used with external matLut / gpuFieldMap", + "number": 5320, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/Propagator.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/Propagator.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUParam.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-01-27T19:11:58Z", + "title": "DPL: Fix labeled array exception", + "number": 5321, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/VariantPropertyTreeHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/PropertyTreeHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Add default file name to TPC PublisherSpec", + "number": 5322, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/MatchTPCITSWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TrackInterpolationWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCReaderWorkflow/PublisherSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/FileReaderWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/PublisherSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "prodtests/sim_challenge.sh" + } + } + ] + } + } + } + ] + } + } +} diff --git a/doc/data/2021-01-o2_releases.json b/doc/data/2021-01-o2_releases.json new file mode 100644 index 0000000000000..6549af0837998 --- /dev/null +++ b/doc/data/2021-01-o2_releases.json @@ -0,0 +1,44 @@ +{ + "repository": { + "releases": { + "edges": [ + { + "node": { + "tagName": "O2-1.0.0", + "publishedAt": "2018-11-21T13:41:46Z" + } + }, + { + "node": { + "tagName": "v1.2.0", + "publishedAt": "2020-02-25T09:10:00Z" + } + }, + { + "node": { + "tagName": "v1.3.0", + "publishedAt": "2020-09-22T07:21:04Z" + } + }, + { + "node": { + "tagName": "v20.49", + "publishedAt": "2020-12-11T16:12:56Z" + } + }, + { + "node": { + "tagName": "v21.01", + "publishedAt": "2021-01-05T16:47:05Z" + } + }, + { + "node": { + "tagName": "v21.03", + "publishedAt": "2021-01-21T13:14:28Z" + } + } + ] + } + } +} diff --git a/doc/data/2021-02-o2_prs.json b/doc/data/2021-02-o2_prs.json new file mode 100644 index 0000000000000..572e342f732a3 --- /dev/null +++ b/doc/data/2021-02-o2_prs.json @@ -0,0 +1,4877 @@ +{ + "repository": { + "pullRequests": { + "edges": [ + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-06T10:57:27Z", + "title": "[ITS vertexer] Fix compilation with ITS debug", + "number": 5383, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/common/include/CommonDataFormat/RangeReference.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreVertexerGPU.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/DeviceStoreVertexerHIP.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/src/VertexerTraitsHIP.hip.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/StandaloneDebugger.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Apply clang-format on all C++ in O2.", + "number": 5384, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h" + } + }, + { + "node": { + "path": "Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h" + } + }, + { + "node": { + "path": "Detectors/TPC/simulation/src/TPCSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/ZSSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/CalDet.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/CalPad.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/FeeParam.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/PadCalibrations.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/PadResponse.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/Tracklet.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/TRDBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/src/TRDSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/ITS3SimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/DetectorsVertexingLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/PVertexer.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/VertexTrackMatcher.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/ZDCSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/gconfig/src/GConfLinkDef.h" + } + }, + { + "node": { + "path": "EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h" + } + }, + { + "node": { + "path": "EventVisualisation/Base/src/ConfigurationManager.cxx" + } + }, + { + "node": { + "path": "EventVisualisation/View/src/EventManagerFrame.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AODReaderHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/CallbackRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/InputSpec.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/MessageContext.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantJSONHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AODReaderHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisDataModelHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLMonitoringBackend.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ResourcesMonitoringHelper.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/FrameworkCoreTestLinkDef.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/StructToTuple.h" + } + }, + { + "node": { + "path": "Framework/GUISupport/src/FrameworkGUIDevicesGraph.cxx" + } + }, + { + "node": { + "path": "GPU/Common/GPUCommonDefAPI.h" + } + }, + { + "node": { + "path": "GPU/Common/GPUCommonMath.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionConvert.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPURawData.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/GPUTrackingLinkDef_O2.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Refit/GPUTrackingRefit.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCRow.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCTrack.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/TPCPadGainCalib.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C" + } + }, + { + "node": { + "path": "GPU/GPUTracking/dEdx/GPUdEdx.cxx" + } + }, + { + "node": { + "path": "GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h" + } + }, + { + "node": { + "path": "Generators/src/Generator.cxx" + } + }, + { + "node": { + "path": "Generators/src/GeneratorsLinkDef.h" + } + }, + { + "node": { + "path": "Generators/src/Trigger.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimReaderSpec.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/HitProcessingManager.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/InteractionSampler.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/MCKinematicsReader.h" + } + }, + { + "node": { + "path": "Utilities/Mergers/include/Mergers/MergerConfig.h" + } + }, + { + "node": { + "path": "Utilities/O2MessageMonitor/src/runO2MessageMonitor.cxx" + } + }, + { + "node": { + "path": "Utilities/Publishers/src/DataPublisherDevice.cxx" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/macros/hltConfigurations.C_backup" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/macros/overlayClusters.C_backup" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/macros/runHLT.C_backup" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/src/Component.cxx" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/src/EventSampler.cxx" + } + }, + { + "node": { + "path": "Utilities/rANS/include/rANS/FrequencyTable.h" + } + }, + { + "node": { + "path": "macro/run_clus_itsSA.C" + } + }, + { + "node": { + "path": "run/O2HitMerger.h" + } + }, + { + "node": { + "path": "run/O2PrimaryServerDevice.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-05T18:31:29Z", + "title": "example macro for Milestone Week 2 - CCDB test", + "number": 5385, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/populateCCDB.C" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/populateCCDB.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-08T08:44:45Z", + "title": "Fix conversion from string to seconds", + "number": 5386, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/DCS/src/DataPointGenerator.cxx" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/testWorkflow/README.md" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-05T08:28:50Z", + "title": "DPL: improve reliability of --driver-client-backend ws://", + "number": 5387, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/ControlService.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ControlServiceHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.h" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WSDriverClient.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "DDbar devel (new branch)", + "number": 5388, + "author": { + "login": "fcolamar" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-05T14:21:22Z", + "title": "DPL: do not open a websocket for devices", + "number": 5389, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-08T08:51:25Z", + "title": "DPL: fix for sending configuration with spaces", + "number": 5390, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tutorials/src/configurableObjects.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceConfigInfo.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DeviceConfigInfo.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "jobutils: detect [ERROR] directly - disable shm-cleanup", + "number": 5391, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "DPL: allow parallel WS backed drivers", + "number": 5392, + "author": { + "login": "ktf" + }, + "files": { + "edges": [] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T22:06:11Z", + "title": "PWGHF: Change the eta cut with the Y cut in the tasks", + "number": 5393, + "author": { + "login": "DelloStritto" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskLc.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T08:31:24Z", + "title": "[MCH] Introduce DCS processor", + "number": 5394, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/DCS/src/DetectorsDCSLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/src/DCSRandomDataGeneratorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/src/dcs-check-ccdb.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/workflow/dcs-processor-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/workflow/dcs-sim-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-06T09:02:33Z", + "title": "DPL: allow parallel WS backed drivers", + "number": 5395, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_FrameworkDataFlowToDDS.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Developments for pedestal calibration in DPL", + "number": 5396, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h" + } + }, + { + "node": { + "path": "Detectors/TPC/base/src/TPCBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/drawPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/runPedestal.sh" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/runPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalibProcessingHelper.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-06T10:57:03Z", + "title": "fix: missing reset in its CompressedClusters", + "number": 5397, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/common/src/CTF.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-06T13:35:29Z", + "title": "Some improvements for running the full system test in the CI (and the first test for the full-system-test-CI)", + "number": 5398, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/setenv.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-07T12:35:15Z", + "title": "[O2-1896] Exclude related macros from checklist when not building upgrades", + "number": 5399, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "cmake/O2RootMacroExclusionList.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T08:02:07Z", + "title": "GPU: Track cut during output on primary leg hits, if secondary legs a…", + "number": 5400, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-07T09:35:41Z", + "title": "TPCClusterFinder: Fix how to determine if a sector is empty.", + "number": 5401, + "author": { + "login": "fweig" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-09T13:03:27Z", + "title": "Add FDD to QED, Extend QED Y range to FDD, auto.calculation of xQED/xPbPb in full system test", + "number": 5402, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "add (DCA,Pt,Mass) histogram to result", + "number": 5403, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "add (DCA,Pt,Mass) histogram to result", + "number": 5404, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerofinder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "More metrics cleanups", + "number": 5405, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataProcessingStats.h" + } + }, + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-09T16:34:25Z", + "title": "Executable to retrieve the CCDB entries for the Milestone Week 2", + "number": 5406, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/cdbSizeV0.txt" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/populateCCDB.cxx" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/retrieveFromCCDB.C" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/retrieveFromCCDB.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/makeCCDBEntryForDCS.C" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "modify (pre)clustering workflows to process several ROF per TF", + "number": 5407, + "author": { + "login": "pillot" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Base/include/MCHBase/ClusterBlock.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: Use labeled array for configurable cuts in D0 selector", + "number": 5408, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/HFSelectorCuts.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Array2D.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Add untested X task", + "number": 5409, + "author": { + "login": "ginnocen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskX.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T00:06:03Z", + "title": "Fixes for TOF CTF creation", + "number": 5410, + "author": { + "login": "noferini" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h" + } + }, + { + "node": { + "path": "Detectors/CTF/test/test_ctf_io_tof.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TOF/base/include/TOFBase/WindowFiller.h" + } + }, + { + "node": { + "path": "Detectors/TOF/base/src/WindowFiller.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/src/TOFFEElightConfig.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/src/CTFCoder.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/CompressedDecodingTask.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/DigitReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFDigitWriterSplitterSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/CompressedDecodingTask.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/TOFDigitWriterSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-08T19:59:43Z", + "title": "Developments for pedestal calibration in DPL + misc", + "number": 5411, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h" + } + }, + { + "node": { + "path": "Detectors/TPC/base/include/TPCBase/Painter.h" + } + }, + { + "node": { + "path": "Detectors/TPC/base/src/Painter.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/base/src/TPCBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibPedestal.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibPedestalParam.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/drawPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/runPedestal.sh" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/runPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/RawReaderCRU.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalibProcessingHelper.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-08T23:24:39Z", + "title": "DPL: handle splitted websocket header", + "number": 5412, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/HTTPParser.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/HTTPParser.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_HTTPParser.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: add wildcards when creating matchers via DataDescriptorQueryBuilder::parse", + "number": 5413, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataDescriptorQueryBuilder.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DataDescriptorMatcher.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T09:31:31Z", + "title": "Changed log message from WARNING to DEBUG.", + "number": 5414, + "author": { + "login": "pbuehler" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/CommonDataProcessors.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-09T09:02:13Z", + "title": "Update CODEOWNERS", + "number": 5415, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "CODEOWNERS" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T15:55:53Z", + "title": "[Alice 3] Update TRK readme", + "number": 5416, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/README.md" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T12:39:17Z", + "title": "DPL: unify JSON representation of arrays in Variant", + "number": 5417, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/VariantPropertyTreeHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/PropertyTreeHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T11:48:39Z", + "title": "TRD trigger records for raw data input and trigger record bug fix", + "number": 5418, + "author": { + "login": "jbarrella" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TRD/macros/convertRun2ToRun3Digits.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-09T13:33:08Z", + "title": "[TPC] fix check for number of provided canvases", + "number": 5419, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/base/src/Painter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T12:38:31Z", + "title": "Apply git clang-format to Analysis.", + "number": 5420, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableMaker.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableReader.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/dynamicColumns.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T12:37:47Z", + "title": "add (DCA,Pt,Mass) histogram to analyser - switch to histogram registry", + "number": 5421, + "author": { + "login": "aimeric-landou" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerofinder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T07:43:29Z", + "title": "jobutils/taskwrapper: use fairmq-shmmonitor", + "number": 5422, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T07:39:57Z", + "title": "Monitoring usage cleanup in DPL", + "number": 5423, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataProcessingStats.h" + } + }, + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T09:43:36Z", + "title": "[O2-2018] Changes to allow usage of either v2 or v3 of Microsoft GSL.", + "number": 5424, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNativeHelper.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/src/CompressedClusters.cxx" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCTruthContainer.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/reconstruction/src/ReadRaw.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Simulation/test/testSimulation.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx" + } + }, + { + "node": { + "path": "EventVisualisation/Detectors/src/DataInterpreterITS.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/TMessageSerializer.h" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2DummyWorkflow.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "Utilities/O2Device/include/O2Device/Utilities.h" + } + }, + { + "node": { + "path": "dependencies/Findms_gsl.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T09:34:38Z", + "title": "GPU: Add SMatrixGPU and Fwd decls", + "number": 5425, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/CMakeLists.txt" + } + }, + { + "node": { + "path": "Common/MathUtils/include/MathUtils/Cartesian.h" + } + }, + { + "node": { + "path": "Common/MathUtils/include/MathUtils/SMatrixGPU.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h" + } + }, + { + "node": { + "path": "GPU/Common/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/Common/GPUCommonArray.h" + } + }, + { + "node": { + "path": "GPU/Common/GPUROOTSMatrixFwd.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-09T22:37:19Z", + "title": "[EMCAL-614] Fixing the pileup simulation", + "number": 5426, + "author": { + "login": "hahassan7" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/simulation/include/EMCALSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/EMCALDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T08:01:11Z", + "title": "Apply git clang-format to GPU.", + "number": 5427, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/Common/GPUCommonDefAPI.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Refit/GPUTrackingRefit.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCNeighboursFinder.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCRow.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/TPCPadGainCalib.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackletReaderComponent.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/macros/checkDbgOutput.C" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C" + } + }, + { + "node": { + "path": "GPU/GPUTracking/dEdx/GPUdEdx.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T10:54:59Z", + "title": "Fix TPC digit reading macro after switch to ConstMCTruthContainer", + "number": 5428, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/simulation/macro/readMCtruth.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-10T12:20:26Z", + "title": "Apply git clang-format to Generators.", + "number": 5429, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Generators/src/Generator.cxx" + } + }, + { + "node": { + "path": "Generators/src/GeneratorsLinkDef.h" + } + }, + { + "node": { + "path": "Generators/src/Trigger.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Apply git clang-format to Detectors.", + "number": 5430, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/DCS/src/DetectorsDCSLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/base/src/EMCALBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/base/include/FT0Base/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/simulation/include/FT0Simulation/DigitizationParameters.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/base/include/FV0Base/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h" + } + }, + { + "node": { + "path": "Detectors/FIT/common/simulation/include/FITSimulation/DigitizationParameters.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTOF.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/macros/test/CheckLUtime.C" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/macros/test/run_digi2rawVarPage_its.C" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/Utils.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/cuda/src/VertexerTraitsGPU.cu" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/IOUtils.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/IOUtils.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/src/ChipMappingITS.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/MC2RawEncoder.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Simulation/src/MCHSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSCalibWorkflowLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/calib/src/PHOSCalibLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Passive/include/DetectorsPassive/HallSimParam.h" + } + }, + { + "node": { + "path": "Detectors/Passive/include/DetectorsPassive/Magnet.h" + } + }, + { + "node": { + "path": "Detectors/Passive/include/DetectorsPassive/Pipe.h" + } + }, + { + "node": { + "path": "Detectors/Passive/src/Hall.cxx" + } + }, + { + "node": { + "path": "Detectors/Passive/src/Pipe.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/HBFUtils.h" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/RDHUtils.h" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/RawFileReader.h" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/RawFileWriter.h" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/SimpleRawReader.h" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileReader.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileReaderWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileWriter.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/test/testRawReaderWriter.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/base/include/TOFBase/Digit.h" + } + }, + { + "node": { + "path": "Detectors/TOF/base/include/TOFBase/Geo.h" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/src/CalibTOF.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/include/TOFReconstruction/Encoder.h" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/src/Encoder.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/base/include/TPCBase/ParameterElectronics.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibParam.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/qc/include/TPCQC/Tracking.h" + } + }, + { + "node": { + "path": "Detectors/TPC/qc/src/TPCQCLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/ClustererTask.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/HardwareClusterDecoder.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/TPCFastTransformHelperO2.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/TPCReconstructionLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TPC/simulation/include/TPCSimulation/CommonMode.h" + } + }, + { + "node": { + "path": "Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h" + } + }, + { + "node": { + "path": "Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/ZSSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/CalDet.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/CalPad.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/FeeParam.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/PadCalibrations.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/PadResponse.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/Tracklet.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/TRDBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDWorkflowLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/PVertexer.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/VertexTrackMatcher.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/include/ZDCSimulation/ZDCSimParam.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Apply git clang-format to Framework.", + "number": 5431, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "CCDB/include/CCDB/CcdbApi.h" + } + }, + { + "node": { + "path": "CCDB/test/testCcdbApi.cxx" + } + }, + { + "node": { + "path": "Common/MathUtils/src/Chebyshev3D.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/EMCAL/src/DataFormatsEMCALLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/CTF.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FV0/src/Hit.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/MFT/src/TrackMFT.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/common/src/Cluster.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/MUON/MID/src/DataFormatsMIDLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/PHOS/src/DataFormatsPHOSLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx" + } + }, + { + "node": { + "path": "DataFormats/common/src/CommonDataFormatLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCTrack.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/src/SimulationDataLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/src/Stack.cxx" + } + }, + { + "node": { + "path": "EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h" + } + }, + { + "node": { + "path": "EventVisualisation/Base/src/ConfigurationManager.cxx" + } + }, + { + "node": { + "path": "EventVisualisation/View/src/EventManagerFrame.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AODReaderHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/CallbackRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/InputSpec.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/MessageContext.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/RCombinedDS.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/VariantJSONHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AODReaderHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisDataModelHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataRelayer.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ResourcesMonitoringHelper.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/FrameworkCoreTestLinkDef.h" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/StructToTuple.h" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/VariantHelpers.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimReaderSpec.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/HitProcessingManager.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/InteractionSampler.h" + } + }, + { + "node": { + "path": "Steer/include/Steer/MCKinematicsReader.h" + } + }, + { + "node": { + "path": "Utilities/Mergers/include/Mergers/MergerConfig.h" + } + }, + { + "node": { + "path": "Utilities/O2MessageMonitor/src/runO2MessageMonitor.cxx" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/src/Component.cxx" + } + }, + { + "node": { + "path": "Utilities/aliceHLTwrapper/src/EventSampler.cxx" + } + }, + { + "node": { + "path": "Utilities/rANS/include/rANS/FrequencyTable.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T08:46:57Z", + "title": "DPL: check for bind result as well.", + "number": 5432, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "TEST - CI Run with some jobutils debugging", + "number": 5433, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + }, + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T10:54:12Z", + "title": "Implementation of CYSS support cylinder in ITS geometry", + "number": 5434, + "author": { + "login": "mario6829" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Services.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/src/V3Services.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T15:51:55Z", + "title": "remove obsolete check", + "number": 5435, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibRawBase.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: first checked implementation of Xic->pKpi filtering", + "number": 5436, + "author": { + "login": "mfaggin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFCandidateSelectionTables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFTrackIndexSkimsCreator.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFXicCandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskXic.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[EMCAL-565]: Add the basic calibration workflow.", + "number": 5437, + "author": { + "login": "hjbossi" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/src/EMCALChannelCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/calibration/testWorkflow/emc-channel-calib-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/doxymodules.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/src/RecoWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Update QA tasks for vertexing and MC PID", + "number": 5438, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskEfficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskSimple.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOFqa.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T09:41:02Z", + "title": "Add option to fix SEED for full system test", + "number": 5439, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T08:29:12Z", + "title": "Fix mem problems related to RootSerializableKeyValStore", + "number": 5440, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h" + } + }, + { + "node": { + "path": "Common/Utils/src/CommonUtilsLinkDef.h" + } + }, + { + "node": { + "path": "Common/Utils/src/RootSerializableKeyValueStore.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T10:52:26Z", + "title": "Reintroduce Wrapper Volume 0 for IB Layers of ITS3 Upgrade", + "number": 5441, + "author": { + "login": "mario6829" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T20:31:08Z", + "title": "Fixes for thread safety of CCDB manager and MW2 CDB tests", + "number": 5442, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "CCDB/include/CCDB/BasicCCDBManager.h" + } + }, + { + "node": { + "path": "CCDB/include/CCDB/CcdbApi.h" + } + }, + { + "node": { + "path": "CCDB/src/BasicCCDBManager.cxx" + } + }, + { + "node": { + "path": "CCDB/src/CcdbApi.cxx" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/cdbSizeV0.txt" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/populateCCDB.cxx" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/retrieveFromCCDB.C" + } + }, + { + "node": { + "path": "Detectors/Calibration/testMacros/retrieveFromCCDB.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T08:00:37Z", + "title": "Added macro to read event info from a Pythia8 heavy-ion simulation header", + "number": 5443, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "run/SimExamples/Custom_EventInfo/read_event_info_pythia8hi.macro" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T15:55:10Z", + "title": "Catch ROOT 'fatal in' / simplify fairmq-shmmonitor usage", + "number": 5444, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T15:46:41Z", + "title": "Fix codechecker errors", + "number": 5445, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/ConstMCTruthContainer.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Benchmark/standalone.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlut.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/GPUDisplayBackendGlut.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/genEvents.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/qa/genEvents.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T08:45:21Z", + "title": "DPL: add helper for matcher creation", + "number": 5446, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataSpecUtils.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DataSpecUtils.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/unittest_DataSpecUtils.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T09:57:39Z", + "title": "TPConly-TOF matching improvement", + "number": 5447, + "author": { + "login": "noferini" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTOF.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T23:04:57Z", + "title": "TPC CDBInterface: enable fetching CalPad from any path in CCDB", + "number": 5448, + "author": { + "login": "tklemenz" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/base/include/TPCBase/CDBInterface.h" + } + }, + { + "node": { + "path": "Detectors/TPC/base/src/CDBInterface.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-11T21:48:37Z", + "title": "DPL: make --fairmq-ipc-prefix homogeneous", + "number": 5449, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: Adding first implementation of D0-D0bar correlation code (data/MC-reco/MC-kine)", + "number": 5450, + "author": { + "login": "fcolamar" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFDDbar_corr.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[MCH] fix bug in Segmentation::findPadPairByPosition", + "number": 5451, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationCImpl3.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationCImpl4.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/test/src/CathodeSegmentation.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/test/src/Segmentation.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T08:39:28Z", + "title": "DPL Analysis: fix for malformed slice for the last entry in grouping", + "number": 5452, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/Kernels.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_GroupSlicer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T23:46:34Z", + "title": "[EMCAL-650] Split payload per SRU link", + "number": 5453, + "author": { + "login": "hahassan7" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/simulation/src/RawWriter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Add missing class to ROOT Dictionary", + "number": 5454, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Base/src/MCHBaseLinkDef.h" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Increase pipeline depth temporarily to avoid lost messages, to be fixed later", + "number": 5455, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataRelayer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T15:53:50Z", + "title": "Initializing dcs-proxy from CCDB", + "number": 5456, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/DCS/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/README.md" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/macros/makeCCDBEntryForDCS.C" + } + }, + { + "node": { + "path": "Detectors/DCS/testWorkflow/src/dcs-proxy.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/makeTOFCCDBEntryForDCS.C" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "TEST COMMIT TO DEBUG THE CI - DO NOT MERGE", + "number": 5457, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "The following changelog has been automatically generated.", + "number": 5458, + "author": { + "login": "github-actions" + }, + "files": { + "edges": [ + { + "node": { + "path": "CHANGELOG.md" + } + }, + { + "node": { + "path": "doc/data/2021-02-o2_prs.json" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "WIP: automatically set tables for PID in analysis", + "number": 5459, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/BetheBloch.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/PIDTOF.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/PIDTPC.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/TOFReso.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/TPCReso.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/src/AnalysisDataModelLinkDef.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTOFqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PID/pidTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskEfficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_auto.cxx" + } + }, + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AODReaderHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DetectorResponse.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ParamBase.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AODReaderHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisManagers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ParamBase.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/FrameworkCoreTestLinkDef.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Full system test as a DAG pipeline", + "number": 5460, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/create_full_system_pipeline.py" + } + }, + { + "node": { + "path": "prodtests/full_system_test_pipeline.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: Add Dplus selector", + "number": 5461, + "author": { + "login": "fcatalan92" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFCandidateSelectionTables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFDplusToPiKPiCandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskDPlus.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-16T17:18:58Z", + "title": "DPL: Dropped obsolete messages with faster rates and input wildcards (O2-1924, O2-1919, O2-1966)", + "number": 5462, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ChannelInfo.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_SlowConsumer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-16T13:42:44Z", + "title": "[MCH] modify (pre)clustering workflows to process several ROF per TF", + "number": 5463, + "author": { + "login": "pillot" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Base/include/MCHBase/ClusterBlock.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Base/include/MCHBase/PreCluster.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/digits-reader-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/preclusters-sink-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-14T14:54:21Z", + "title": "Print out some indication where the error was found in the log file", + "number": 5464, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-12T19:26:41Z", + "title": "Fix typo (-l was present twice, one should have been -v)", + "number": 5465, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/setenv.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-13T00:51:54Z", + "title": "DPL: fix naming of rcvBufSize, sndBufSize", + "number": 5466, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/ChannelConfigurationPolicyHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "TEST COMMIT, DO NOT MERGE", + "number": 5467, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-13T00:13:43Z", + "title": "Remove ApplyCarryOverToLastPage in EMC mc->raw, use const TrailerSize", + "number": 5468, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/simulation/src/RawWriter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Xtask", + "number": 5469, + "author": { + "login": "rspijkers" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskX.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-14T17:21:25Z", + "title": "TEST - DO NOT MERGE - Use websocket backend in full system test", + "number": 5470, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T07:43:03Z", + "title": "[PHOS] Add missing include (when using Root 6.22/06)", + "number": 5471, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/PHOS/base/include/PHOSBase/Geometry.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T18:57:28Z", + "title": "GPU: test SMatrixGPU with OpenCL2.0", + "number": 5472, + "author": { + "login": "mconcas" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/include/MathUtils/Cartesian.h" + } + }, + { + "node": { + "path": "Common/MathUtils/include/MathUtils/SMatrixGPU.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: rapidity cut apply in Jpsi task", + "number": 5473, + "author": { + "login": "zhangbiao-phy" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskJpsi.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T16:53:09Z", + "title": "Improvements in digitizer workflow", + "number": 5474, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-15T22:11:33Z", + "title": "PID: Merge split tasks into one configurable", + "number": 5475, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/PID/PIDTPC.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Cosmics matcher + related changes", + "number": 5476, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/include/MathUtils/detail/Bracket.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/WorkflowHelper.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackCosmics.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackTPCTOF.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/TrackCosmics.cxx" + } + }, + { + "node": { + "path": "DataFormats/common/include/CommonDataFormat/AbstractRef.h" + } + }, + { + "node": { + "path": "DataFormats/common/src/CommonDataFormatLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/common/test/testAbstractRefAccessor.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchCosmicsParams.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/include/GlobalTracking/RecoContainer.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/GlobalTrackingLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchCosmics.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchCosmicsParams.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTOF.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTPCITS.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/RecoContainer.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/README.md" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackCosmicsReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TrackCosmicsWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/MatchTPCITSWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/TrackCosmicsReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/TrackCosmicsWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowWithTPCSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/README.md" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "MCKinematicsReader fixing memory leak", + "number": 5477, + "author": { + "login": "matthias-kleiner" + }, + "files": { + "edges": [ + { + "node": { + "path": "Steer/src/MCKinematicsReader.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "macro to read TOF DCS entries", + "number": 5478, + "author": { + "login": "chiarazampolli" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TOF/calibration/include/TOFCalibration/TOFDCSProcessor.h" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/macros/readTOFDCSentries.C" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: add facility field to InfoLogger output", + "number": 5479, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Implementation of cylinder and foam wedges for IB support in ITS3 geometry", + "number": 5480, + "author": { + "login": "mario6829" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/V3Services.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "WIP: Add table for HMPID", + "number": 5481, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGLF/CMakeLists.txt" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraHMPID.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[MCH] o2-mch-dcs-ccdb CLI can upload MCH/DCSConfig to CCDB", + "number": 5482, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Conditions/src/dcs-ccdb.cxx" + } + } + ] + } + } + } + ] + } + } +} diff --git a/doc/data/2021-02-o2_releases.json b/doc/data/2021-02-o2_releases.json new file mode 100644 index 0000000000000..4637e026150ef --- /dev/null +++ b/doc/data/2021-02-o2_releases.json @@ -0,0 +1,50 @@ +{ + "repository": { + "releases": { + "edges": [ + { + "node": { + "tagName": "O2-1.0.0", + "publishedAt": "2018-11-21T13:41:46Z" + } + }, + { + "node": { + "tagName": "v1.2.0", + "publishedAt": "2020-02-25T09:10:00Z" + } + }, + { + "node": { + "tagName": "v1.3.0", + "publishedAt": "2020-09-22T07:21:04Z" + } + }, + { + "node": { + "tagName": "v20.49", + "publishedAt": "2020-12-11T16:12:56Z" + } + }, + { + "node": { + "tagName": "v21.01", + "publishedAt": "2021-01-05T16:47:05Z" + } + }, + { + "node": { + "tagName": "v21.03", + "publishedAt": "2021-01-21T13:14:28Z" + } + }, + { + "node": { + "tagName": "v21.05", + "publishedAt": "2021-02-10T21:53:36Z" + } + } + ] + } + } +} diff --git a/doc/data/2021-03-o2_prs.json b/doc/data/2021-03-o2_prs.json new file mode 100644 index 0000000000000..106620a20d629 --- /dev/null +++ b/doc/data/2021-03-o2_prs.json @@ -0,0 +1,5418 @@ +{ + "repository": { + "pullRequests": { + "edges": [ + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "PWGHF: Add single particle distribution", + "number": 5556, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskSimple.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T07:58:23Z", + "title": "Compilation fixes", + "number": 5557, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/src/NoiseCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/calibration/src/NoiseSlotCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl3/src/CathodeSegmentationImpl3.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T09:05:37Z", + "title": "[DPL Analysis] Simple workflow suffix solution", + "number": 5558, + "author": { + "login": "saganatt" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskDPlus.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskJpsi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskLc.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinderhadronrecoil.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinderhf.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetskimming.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetsubstructure.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadeanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadebuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadefinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerofinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/mcspectraefficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/raacharged.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPCsplitPiKaPr.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPCtinyPiKaPr.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/trackchecks.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcAnalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcForward.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetSpectraAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetSpectraReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/centralityQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/centralityTable.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/emcalCorrectionTask.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/eventSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/eventSelectionQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/multiplicityQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/multiplicityTable.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOFqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/timestamp.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackextension.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackselection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/validation.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/weakDecayIndices.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/ZDCVZeroIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/aodreader.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/aodwriter.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/associatedExample.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/ccdbaccess.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/collisionTracksIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/compatibleBCs.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/configurableObjects.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/dynamicColumns.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/efficiencyGlobal.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/efficiencyPerRun.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/eventMixing.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/extendedColumns.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/filters.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/fullTrackIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histHelpersTest.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramRegistry.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramTrackSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histograms.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramsFullTracks.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/jetAnalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/mcHistograms.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/multiplicityEventTrackSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/muonIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/newCollections.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/outputs.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/partitions.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/schemaEvolution.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/trackCollectionIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/trackIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/tracksCombinations.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/weakDecayIteration.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/runDataProcessing.h" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/Mocking.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_AnalysisTask.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-02T09:11:33Z", + "title": "A and C side cables ", + "number": 5559, + "author": { + "login": "AllaMaevskaya" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FT0/simulation/include/FT0Simulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T19:01:33Z", + "title": "Fix some codechecker violations", + "number": 5560, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/MathUtils/include/MathUtils/SMatrixGPU.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/hip/include/ITStrackingHIP/VertexerTraitsHIP.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-25T20:34:06Z", + "title": "Revert \"DPL: switch to ws:// as default client for self hosted\"", + "number": 5561, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DriverInfo.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-25T20:37:43Z", + "title": "Revert \"Full system test: Remove unneeded option, ws backend is default now\"", + "number": 5562, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-25T22:51:30Z", + "title": "DPL: fix memory leak in ws:// driver.", + "number": 5563, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DPLWebSocket.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Implement the Data Inspector", + "number": 5564, + "author": { + "login": "dak98" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataInspector.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DataAllocator.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataInspector.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessor.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "dependencies/O2Dependencies.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T07:57:10Z", + "title": "Full System Test: Fix and simplify CPV workflow", + "number": 5565, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T18:58:46Z", + "title": "Renaming index columns for TF merging", + "number": 5566, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/RecoDecay.h" + } + }, + { + "node": { + "path": "Analysis/Core/src/JetFinder.cxx" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/ReducedInfoTables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/StrangenessTables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/src/aodDataModelGraph.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/correlations.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFMCValidation.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTask.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskEfficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/qaTaskSimple.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskJpsi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskLc.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadebuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadefinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerofinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/mcspectraefficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/raacharged.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/trackchecks.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOFqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/weakDecayIndices.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/mcHistograms.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/weakDecayIteration.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/StandaloneAODProducer.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/macros/ALICE3toAO2D.C" + } + }, + { + "node": { + "path": "Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataTypes.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Expressions.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AODReaderHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataInputDirector.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataOutputDirector.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Expressions.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/benchmark_ASoAHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_ASoA.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-25T23:40:53Z", + "title": "DPL: switch to ws:// as default client for self hosted", + "number": 5567, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DriverInfo.h" + } + }, + { + "node": { + "path": "Framework/Core/src/DeviceSpecHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-25T23:41:51Z", + "title": "Revert \"Revert \"Full system test: Remove unneeded option, ws backend is default now\"\"", + "number": 5568, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T15:53:41Z", + "title": "Modifications to auto-detect and decode link-base zero suppression", + "number": 5569, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppressionLinkBased.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibTreeDump.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/DigitDump.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/drawPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/dumpDigits.C" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/macro/runPulser.C" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/src/CalibRawBase.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/RawProcessingHelpers.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/RawReaderCRU.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/RawProcessingHelpers.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/RawReaderCRU.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalibProcessingHelper.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/RawToDigitsSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-raw-to-digits-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T17:43:56Z", + "title": "Fix for the out_of_range exception and small clean-ups", + "number": 5570, + "author": { + "login": "nburmaso" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: fix threading issue in ServiceRegistry", + "number": 5571, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ServiceRegistry.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ServiceRegistry.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T09:44:47Z", + "title": "Fix number of foam wedges at 90deg, add carbon fleece with glue", + "number": 5572, + "author": { + "login": "mario6829" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V3Services.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/src/V3Services.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T15:02:38Z", + "title": "Add TPC-TOF matching to sim_challenge", + "number": 5573, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/sim_challenge.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-26T16:16:50Z", + "title": "Fix: MID digi2raw must read configKeyValues", + "number": 5574, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/digits-to-raw-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-27T16:48:34Z", + "title": "MCKinematicsReader: adding destructor", + "number": 5575, + "author": { + "login": "matthias-kleiner" + }, + "files": { + "edges": [ + { + "node": { + "path": "Steer/include/Steer/MCKinematicsReader.h" + } + }, + { + "node": { + "path": "Steer/src/MCKinematicsReader.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T10:32:32Z", + "title": "[EMCAL-684] Add mapping for FEC index", + "number": 5576, + "author": { + "login": "mfasDa" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/base/include/EMCALBase/Mapper.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/base/src/Mapper.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/reconstruction/include/EMCALReconstruction/Channel.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-27T12:53:21Z", + "title": "Option to detect TF from orbit and SOX info instead of TType", + "number": 5577, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FDD/simulation/src/digit2raw.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/simulation/src/digit2raw.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/README.md" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/RawFileReader.h" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileReader.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileReaderWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileReaderWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/Raw/src/rawfile-reader-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/rawfileCheck.cxx" + } + }, + { + "node": { + "path": "Detectors/Raw/src/rawfileSplit.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-27T12:52:32Z", + "title": "Misc fixes in propagator ", + "number": 5578, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/Field/include/Field/MagFieldFast.h" + } + }, + { + "node": { + "path": "Common/Field/src/MagFieldFast.cxx" + } + }, + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/MatCell.h" + } + }, + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/Propagator.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/Propagator.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTPCITS.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T09:36:23Z", + "title": "Additional options and fixes for full system test", + "number": 5579, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + }, + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T06:03:54Z", + "title": "DPL: move can_assign helper to the only used place", + "number": 5580, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/TypeTraits.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_TypeTraits.cxx" + } + }, + { + "node": { + "path": "Framework/Utils/include/DPLUtils/RootTreeWriter.h" + } + }, + { + "node": { + "path": "Framework/Utils/test/test_RootTreeWriter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-27T13:01:33Z", + "title": "PWGHF: Revert \"Add flag to switch off TPC cluster selection\"", + "number": 5581, + "author": { + "login": "ginnocen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFJpsiToEECandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFLcCandidateSelector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-02-28T23:38:23Z", + "title": "DPL: improve message when driver client is not yet connected", + "number": 5582, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/WSDriverClient.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T08:31:53Z", + "title": "Track source masks + possibility to select sources for p.vertexing and cosmics workflows", + "number": 5583, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/Common/src/DetID.cxx" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/include/ReconstructionDataFormats/GlobalTrackID.h" + } + }, + { + "node": { + "path": "DataFormats/Reconstruction/src/GlobalTrackID.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/README.md" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexingSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/primary-vertexing-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T09:35:45Z", + "title": "Including Rtypes.h", + "number": 5584, + "author": { + "login": "pzhristov" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Geo.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T19:43:39Z", + "title": "Raw to digits", + "number": 5585, + "author": { + "login": "cortesep" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/ZDC/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/include/DataFormatsZDC/CTF.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/src/BCData.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/src/OrbitData.cxx" + } + }, + { + "node": { + "path": "Detectors/CTF/test/test_ctf_io_zdc.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/base/include/ZDCBase/Geometry.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/include/ZDCRaw/RawReaderZDC.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/src/DumpRaw.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/src/RawReaderZDC.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/raw/src/raw-parser.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFHelper.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/src/CTFCoder.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/include/ZDCSimulation/Digitizer.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/include/ZDCSimulation/Digits2Raw.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Digits2Raw.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/digi2raw.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDataReaderDPLSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/include/ZDCWorkflow/ZDCDigitWriterDPLSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/DigitReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/ZDCDataReaderDPLSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/ZDCDigitWriterDPLSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/o2-zdc-raw2digits.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/ZDCDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T12:24:33Z", + "title": "o2-sim: Provide standalone MC header information", + "number": 5586, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h" + } + }, + { + "node": { + "path": "DataFormats/simulation/src/MCEventHeader.cxx" + } + }, + { + "node": { + "path": "macro/migrateSimFiles.C" + } + }, + { + "node": { + "path": "run/o2sim_parallel.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T13:33:51Z", + "title": "DPL: require --aod-writer-keep to be homogeneous", + "number": 5587, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "TRD Fix mc 2 raw data generation", + "number": 5588, + "author": { + "login": "bazinski" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/FeeParam.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/FeeParam.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/README.md" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/src/Trap2CRU.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/src/trap2raw.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Remove unneeded and broken fairlogger includes", + "number": 5589, + "author": { + "login": "Barthelemy" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FT0/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/base/src/ModuleConfig.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T21:46:32Z", + "title": "Additional documentation and cleanup for TRAPsim", + "number": 5590, + "author": { + "login": "martenole" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/src/Tracklet64.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/simulation/include/TRDSimulation/TrapSimulator.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-02T10:08:38Z", + "title": "Fix ITS tracking: async/sync settings swapping, not vertexing in cosmics", + "number": 5591, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-01T21:22:56Z", + "title": "GPU: Fix race condition in TPC ClusterFinder", + "number": 5592, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-02T07:26:58Z", + "title": "GPU: Fix some possible race conditions", + "number": 5593, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SliceTracker/GPUTPCTrackletSelector.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "The following changelog has been automatically generated.", + "number": 5594, + "author": { + "login": "github-actions" + }, + "files": { + "edges": [ + { + "node": { + "path": "CHANGELOG.md" + } + }, + { + "node": { + "path": "doc/data/2021-03-o2_prs.json" + } + }, + { + "node": { + "path": "doc/data/2021-03-o2_releases.json" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-02T17:40:56Z", + "title": "Remove non-templated DCAFitter (overridden by DCAFitterN)", + "number": 5595, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/validation.cxx" + } + }, + { + "node": { + "path": "Detectors/Base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/DCAFitter.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/DCAFitter.cxx" + } + }, + { + "node": { + "path": "Detectors/Base/src/DetectorsBaseLinkDef.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-03T06:04:41Z", + "title": "Revert \"DPL: add wildcards when creating matchers via DataDescriptorQueryBuilder::parse\"", + "number": 5596, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataDescriptorQueryBuilder.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DataDescriptorMatcher.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-08T20:26:58Z", + "title": "add tool for processing cosmics in real time with TOF", + "number": 5597, + "author": { + "login": "noferini" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TOF/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TOF/include/DataFormatsTOF/CalibInfoCluster.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TOF/include/DataFormatsTOF/CosmicInfo.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TOF/src/CosmicInfo.cxx" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-reco-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/include/TOFReconstruction/CosmicProcessor.h" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/include/TOFReconstruction/DataReader.h" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/src/Clusterer.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/src/CosmicProcessor.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/src/TOFReconstructionLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFCalClusInfoWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/TOFClusterizerSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/TOFCalClusInfoWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/TOFClusterizerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/cluster-calib.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T16:57:49Z", + "title": "Couple of GPU developments", + "number": 5598, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/ClusterNative.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionCPU.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Benchmark/standalone.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompression.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUSettingsList.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChain.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUErrorCodes.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMergedTrack.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMerger.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/strtag.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T09:23:19Z", + "title": "Fix for sparse index builder skipping entries", + "number": 5599, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/TableBuilder.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_IndexBuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "DO NOT MERGE Test clang-format auto-PR", + "number": 5600, + "author": { + "login": "TimoWilken" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/src/JetFinder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T22:46:25Z", + "title": "DPL: simplify method analysis task introspection", + "number": 5601, + "author": { + "login": "alibuild" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T22:54:19Z", + "title": "DPL: simplify TableBuilder API", + "number": 5602, + "author": { + "login": "alibuild" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/TableBuilder.h" + } + }, + { + "node": { + "path": "Framework/Core/src/TableBuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-03T16:06:04Z", + "title": "DPL: do not use --driver-client-backend when dumping DDS config", + "number": 5603, + "author": { + "login": "alibuild" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DDSConfigHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-03T14:16:02Z", + "title": "less verbose output from jobutils", + "number": 5604, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/Tools/jobutils.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Add websockets to expected invocation in ctests", + "number": 5605, + "author": { + "login": "TimoWilken" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/test/test_FrameworkDataFlowToDDS.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Raw file writer", + "number": 5606, + "author": { + "login": "fapfap69" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/HMPID/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Digit.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Geo.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Trigger.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/src/Digit.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/src/HMPIDBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HmpidCoder2.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFromRootSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/DataDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/WriteRawFromRootSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/digitstream-to-digits-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/digitstream-to-raw-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/raw-to-digitstream-workflow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-03T21:04:30Z", + "title": "Fix PR target for clang-format action", + "number": 5607, + "author": { + "login": "TimoWilken" + }, + "files": { + "edges": [ + { + "node": { + "path": ".github/workflows/code-formatting.yml" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[TPC] Add krypton cluster finder workflow, extend pedestal workflow", + "number": 5608, + "author": { + "login": "wiechula" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/KrBoxClusterFinder.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/KrCluster.h" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/src/KrBoxClusterFinder.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CalDetMergerPublisherSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/KryptonClustererSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPedestalSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CalibProcessingHelper.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/KryptonClustererSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-calib-pedestal.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-krypton-clusterer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T12:10:21Z", + "title": "Upgrade: fix duplicate guard.", + "number": 5609, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/IT3/simulation/include/ITS3Simulation/V11Geometry.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T21:30:18Z", + "title": "Better message", + "number": 5610, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T09:55:57Z", + "title": "Renaming charge() to sign()", + "number": 5611, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/PairCuts.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/CFDerived.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/ReducedInfoTables.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/StrangenessTables.h" + } + }, + { + "node": { + "path": "Analysis/PWGDQ/include/PWGDQCore/VarManager.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/correlations.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/correlationsFiltered.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/correlationsMixed.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/dptdptcorrelations.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGCF/filterCF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/dileptonEE.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/dileptonMuMu.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableMaker.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableMakerMuon_pp.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGDQ/tableReader.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFD0CandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFJpsiToEECandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFLcCandidateSelector.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadeanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadefinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/raacharged.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcAnalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcForward.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCReference.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T07:19:21Z", + "title": "Suppress some info output at higher logging severities", + "number": 5612, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTracking/src/MatchTPCITS.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T13:15:44Z", + "title": "Fix delay in raw file reader workflow", + "number": 5613, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Raw/src/rawfile-reader-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T20:00:53Z", + "title": "Removed overlaps in cdrum", + "number": 5614, + "author": { + "login": "MarekKowalski1504" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T18:39:57Z", + "title": "Use o2_add_executable for Data Sampling benchmark workflow", + "number": 5615, + "author": { + "login": "knopers8" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/DataSampling/CMakeLists.txt" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: broadcasts messages containing SourceInfoHeader", + "number": 5616, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/SourceInfoHeader.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ExternalFairMQDeviceProxy.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ReadoutAdapter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Fixed of FDD digit2raw and digit writer/reader", + "number": 5617, + "author": { + "login": "mbroz84" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/ChannelData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FDD/include/DataFormatsFDD/Digit.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/base/include/FDDBase/Constants.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/reconstruction/src/ReadRaw.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/src/Digitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/src/Digits2Raw.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/DigitWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/DigitWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/FDDDigitWriterSpec.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "RecoDecay & PWGHF: Improve MC matching.", + "number": 5618, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Core/include/AnalysisCore/RecoDecay.h" + } + }, + { + "node": { + "path": "Analysis/DataModel/include/AnalysisDataModel/HFSecondaryVertex.h" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFMCValidation.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[MCH] fix broken workflows", + "number": 5619, + "author": { + "login": "pillot" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/TrackFinderOriginalSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/TrackFinderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/clusters-sampler-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/clusters-sink-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[MRRTF-99] Add support for MCH UserLogic Raw Data Format V1", + "number": 5620, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Common/include/MCHRawCommon/DataFormats.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/src/PageDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/src/UserLogicEndpointDecoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/ElinkEncoderMerger.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/GBTEncoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoder.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/PayloadEncoderImpl.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/UserLogicElinkEncoderMerger.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/include/MCHRawEncoderPayload/PayloadEncoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ImplHelpers/DumpBuffer.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/README.md" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-04T18:23:05Z", + "title": "Some minor fixes for the full system test scripts", + "number": 5621, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + }, + { + "node": { + "path": "prodtests/full-system-test/datadistribution.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "TRD tracking with ITS-TPC tracks and TRD tracklets in Run 3 format", + "number": 5622, + "author": { + "login": "martenole" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/Tracklet64.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/src/Tracklet64.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T07:38:11Z", + "title": "Adding Forward (MFT+Muon) tables", + "number": 5623, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataTypes.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "HMPID: cleaned up version of PR5606 + fixes", + "number": 5624, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/HMPID/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Digit.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Geo.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/include/HMPIDBase/Trigger.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/src/Digit.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/base/src/HMPIDBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/simulation/src/HmpidCoder2.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitsToRawSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/DataDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/DigitsToRawSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/HMPIDRecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/write-root-from-digits-workflow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T13:12:28Z", + "title": "o2-sim: More robust termination initiated by driver", + "number": 5625, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "run/o2sim_parallel.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: make --forwarding-policy default to none", + "number": 5626, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/WorkflowCustomizationHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[R3C-465] MCH: pedestals calibration workflow", + "number": 5627, + "author": { + "login": "aferrero2707" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/MUON/MCH/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/DsChannelGroup.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/MUON/MCH/src/DataFormatsMCHLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/include/MCHCalibration/MCHChannelCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/include/MCHCalibration/MCHChannelCalibratorAlt.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalDigit.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/include/MCHCalibration/PedestalProcessor.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/MCHCalibrationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/MCHChannelCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/MCHChannelCalibratorAlt.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/MCHChannelCalibratorSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/PedestalDigit.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/PedestalProcessor.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/channel-calib-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Calibration/src/pedestals-decoding-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T19:59:25Z", + "title": "Split tracks table into three tables", + "number": 5628, + "author": { + "login": "nburmaso" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T19:59:04Z", + "title": "Remove unused link dependency", + "number": 5629, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "run/CMakeLists.txt" + } + }, + { + "node": { + "path": "run/o2sim_parallel.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "Add ToC for Core Framework documentation", + "number": 5630, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/README.md" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-05T19:26:30Z", + "title": "PWGHF: fix wrong casting of track index", + "number": 5631, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator2Prong.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/HFCandidateCreator3Prong.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-06T18:55:13Z", + "title": "Add / improve a couple of scripts related to the full system test", + "number": 5632, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/convert-raw-to-tf-file.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/datadistribution.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/gen_rdo_cfg.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/generate_timeframe_files.sh" + } + }, + { + "node": { + "path": "prodtests/full-system-test/start_tmux.sh" + } + }, + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T07:37:34Z", + "title": "Adapting to updated vertex selection in converter", + "number": 5633, + "author": { + "login": "jgrosseo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGCF/correlations.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataTypes.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-08T07:39:09Z", + "title": "Added macro to read event info from a Pythia8 heavy-ion simulation he…", + "number": 5634, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "run/SimExamples/Custom_EventInfo/read_event_info_pythia8hi.macro" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Examples of external generators moved to O2DPG (get rid of AEGIS)", + "number": 5635, + "author": { + "login": "preghenella" + }, + "files": { + "edges": [ + { + "node": { + "path": "Generators/CMakeLists.txt" + } + }, + { + "node": { + "path": "Generators/share/external/GenCosmics.C" + } + }, + { + "node": { + "path": "Generators/share/external/GenCosmicsLoader.C" + } + }, + { + "node": { + "path": "Generators/share/external/QEDLoader.C" + } + }, + { + "node": { + "path": "Generators/share/external/QEDepem.C" + } + }, + { + "node": { + "path": "Generators/share/external/hijing.C" + } + }, + { + "node": { + "path": "cmake/O2RootMacroExclusionList.cmake" + } + }, + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-08T14:18:00Z", + "title": "Library to keep track of (build) versions/revisions", + "number": 5636, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "CMakeLists.txt" + } + }, + { + "node": { + "path": "run/CMakeLists.txt" + } + }, + { + "node": { + "path": "run/o2sim_parallel.cxx" + } + }, + { + "node": { + "path": "version/CMakeLists.txt" + } + }, + { + "node": { + "path": "version/O2Version.cxx.in" + } + }, + { + "node": { + "path": "version/O2Version.h" + } + }, + { + "node": { + "path": "version/O2Version.h.in" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[WIP] Add option to disable MC labels in TRD TRAP sim", + "number": 5637, + "author": { + "login": "martenole" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDDigitReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDTrackletWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDDigitReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrackletWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrapSimulatorWorkFlow.cxx" + } + }, + { + "node": { + "path": "Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-06T18:54:39Z", + "title": "GPU: Fix - do not check stack tag protection when stack is disabled for display", + "number": 5638, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Base/GPUReconstruction.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-06T17:12:00Z", + "title": "RawFileWriter::addData optionally transfers detectoField to RDH", + "number": 5639, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Raw/README.md" + } + }, + { + "node": { + "path": "Detectors/Raw/include/DetectorsRaw/RawFileWriter.h" + } + }, + { + "node": { + "path": "Detectors/Raw/src/RawFileWriter.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T06:39:33Z", + "title": "[DPL Analysis] Canonical task names", + "number": 5640, + "author": { + "login": "saganatt" + }, + "files": { + "edges": [ + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskBPlus.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskD0.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskDPlus.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskJpsi.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGHF/taskLc.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinderhadronrecoil.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetfinderhf.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetskimming.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGJE/jetsubstructure.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadeanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadebuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/cascadefinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzeroanalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerobuilder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/lambdakzerofinder.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/mcspectraefficiency.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/raacharged.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPCsplitPiKaPr.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/spectraTPCtinyPiKaPr.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGLF/trackchecks.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcAnalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/PWGUD/upcForward.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetSpectraAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/jetSpectraReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraNucleiReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraTPCReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCAnalyser.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCProvider.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/SkimmingTutorials/spectraUPCReference.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/centralityQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/centralityTable.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/emcalCorrectionTask.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/eventSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/eventSelectionQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/multiplicityQa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/multiplicityTable.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOF_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTOFqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_split.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/pidTPC_tiny.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/timestamp.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackextension.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackqa.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/trackselection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/validation.cxx" + } + }, + { + "node": { + "path": "Analysis/Tasks/weakDecayIndices.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/ZDCVZeroIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/aodreader.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/aodwriter.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/associatedExample.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/ccdbaccess.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/collisionTracksIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/compatibleBCs.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/configurableObjects.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/dynamicColumns.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/efficiencyGlobal.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/efficiencyPerRun.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/eventMixing.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/extendedColumns.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/filters.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/fullTrackIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histHelpersTest.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramRegistry.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramTrackSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histograms.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/histogramsFullTracks.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/jetAnalysis.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/mcHistograms.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/multiplicityEventTrackSelection.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/muonIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/newCollections.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/outputs.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/partitions.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/schemaEvolution.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/trackCollectionIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/trackIteration.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/tracksCombinations.cxx" + } + }, + { + "node": { + "path": "Analysis/Tutorials/src/weakDecayIteration.cxx" + } + }, + { + "node": { + "path": "Framework/Core/ANALYSIS.md" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_AnalysisTask.cxx" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/TypeIdHelpers.h" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-06T17:11:31Z", + "title": "Complete ZDC CTF content and encoding/decoding workflows", + "number": 5641, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/ZDC/include/DataFormatsZDC/CTF.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/CTF/test/test_ctf_io_zdc.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFHelper.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/src/CTFCoder.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-06T07:37:28Z", + "title": "Do not format deleted files", + "number": 5642, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": ".github/workflows/code-formatting.yml" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "New Version library to host various versioning information", + "number": 5643, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "CMakeLists.txt" + } + }, + { + "node": { + "path": "run/CMakeLists.txt" + } + }, + { + "node": { + "path": "run/o2sim_parallel.cxx" + } + }, + { + "node": { + "path": "version/CMakeLists.txt" + } + }, + { + "node": { + "path": "version/O2Version.cxx.in" + } + }, + { + "node": { + "path": "version/O2Version.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-07T17:53:44Z", + "title": "Do not limit number of entries RootTreeWriter can store", + "number": 5644, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDCalibratedTrackletWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDDigitWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrackletWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrapRawWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/ZDCDigitWriterDPLSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T07:02:24Z", + "title": "Less conservative size for the analysis job pool", + "number": 5645, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "CMakeLists.txt" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "New options: writing tables directly into a .root file and MC tracks filtering.", + "number": 5646, + "author": { + "login": "nburmaso" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/AOD/src/aod-producer-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Misc cleanups", + "number": 5647, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Expressions.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/TableBuilder.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Variant.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ASoA.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/TableBuilder.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/Variant.cxx" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/RuntimeError.h" + } + }, + { + "node": { + "path": "Framework/Foundation/src/RuntimeError.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-08T08:27:22Z", + "title": "[R3C-469] [MCH] Update Electronic Mapping from Pt2", + "number": 5648, + "author": { + "login": "aphecetche" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/README.md" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/include/MCHRawElecMap/Mapper.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH10L.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH10R.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH6R.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH7L.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH7R.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH8L.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH8R.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH9L.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/CH9R.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/ElectronicMapperGenerated.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/Mapper.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/elecmap.py" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/gen.sh" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/ElecMap/src/testElectronicMapper.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T06:59:04Z", + "title": "DPL Analysis: avoid std::function in literal node", + "number": 5649, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/Expressions.h" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "[O2-2082] Do not include FairLogger.h", + "number": 5650, + "author": { + "login": "Barthelemy" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FDD/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/base/src/Geometry.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ZDC/base/src/ModuleConfig.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/simulation/src/Digitizer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T06:36:04Z", + "title": "DPL: proper redirection to --forwarding-destination none", + "number": 5651, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/WorkflowCustomizationHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[WIP][EMCAL-685] Implementation of a ring buffer for EMCAL digits", + "number": 5652, + "author": { + "login": "hahassan7" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/simulation/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/include/EMCALSimulation/DigitsWriteoutBuffer.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/src/DigitsWriteoutBuffer.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Generate a o2-build-database.json file", + "number": 5653, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "version/CMakeLists.txt" + } + }, + { + "node": { + "path": "version/RecordBuildDetails.py" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T07:14:41Z", + "title": "MCReader: release early", + "number": 5654, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Steer/include/Steer/MCKinematicsReader.h" + } + }, + { + "node": { + "path": "Steer/src/MCKinematicsReader.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2021-03-09T06:57:52Z", + "title": "Protect cpuid.h, it cannot be used on Mac M1", + "number": 5655, + "author": { + "login": "pzhristov" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + } + ] + } + } +} diff --git a/doc/data/2021-03-o2_releases.json b/doc/data/2021-03-o2_releases.json new file mode 100644 index 0000000000000..ac164d04e89da --- /dev/null +++ b/doc/data/2021-03-o2_releases.json @@ -0,0 +1,62 @@ +{ + "repository": { + "releases": { + "edges": [ + { + "node": { + "tagName": "O2-1.0.0", + "publishedAt": "2018-11-21T13:41:46Z" + } + }, + { + "node": { + "tagName": "v1.2.0", + "publishedAt": "2020-02-25T09:10:00Z" + } + }, + { + "node": { + "tagName": "v1.3.0", + "publishedAt": "2020-09-22T07:21:04Z" + } + }, + { + "node": { + "tagName": "v20.49", + "publishedAt": "2020-12-11T16:12:56Z" + } + }, + { + "node": { + "tagName": "v21.01", + "publishedAt": "2021-01-05T16:47:05Z" + } + }, + { + "node": { + "tagName": "v21.03", + "publishedAt": "2021-01-21T13:14:28Z" + } + }, + { + "node": { + "tagName": "v21.05", + "publishedAt": "2021-02-10T21:53:36Z" + } + }, + { + "node": { + "tagName": "v21.07", + "publishedAt": "2021-02-16T17:29:26Z" + } + }, + { + "node": { + "tagName": "v21.09", + "publishedAt": "2021-03-03T06:17:35Z" + } + } + ] + } + } +} diff --git a/doc/doxyfile-with-graphs.in b/doc/doxyfile-with-graphs.in new file mode 100644 index 0000000000000..d60d01d5bcb59 --- /dev/null +++ b/doc/doxyfile-with-graphs.in @@ -0,0 +1,313 @@ +# Doxyfile 1.8.8 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = @PROJECT_NAME@ +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = "@CMAKE_SOURCE_DIR@/doc/images/o2_logo.png" +OUTPUT_DIRECTORY = "@DOC_OUTPUT_DIR@" +CREATE_SUBDIRS = YES +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 2 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = YES +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = "@CMAKE_SOURCE_DIR@" +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.cxx *.h *.inl *.md +RECURSIVE = YES +EXCLUDE = .git/ \ + build/ \ + build-dir/ \ + html-docs/ \ + doxygen cmake config gconfig geometry input parameters .svn vis +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = G__* ClassImp build_* +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = @CMAKE_SOURCE_DIR@/doc/scripts/filter_for_doxygen.sh +FILTER_PATTERNS = *.md +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = @CMAKE_SOURCE_DIR@/README.md +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = .git +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +DIA_PATH = +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = YES +DOT_NUM_THREADS = 1 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = YES +UML_LIMIT_NUM_FIELDS = 50 +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = svg +INTERACTIVE_SVG = YES +DOT_PATH = "@DOT_PATH@" +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +DOT_GRAPH_MAX_NODES = 100 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/doc/doxyfile.in b/doc/doxyfile.in index d60d01d5bcb59..08b7d37770b20 100644 --- a/doc/doxyfile.in +++ b/doc/doxyfile.in @@ -278,10 +278,10 @@ EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- -CLASS_DIAGRAMS = YES +CLASS_DIAGRAMS = NO DIA_PATH = HIDE_UNDOC_RELATIONS = NO -HAVE_DOT = YES +HAVE_DOT = NO DOT_NUM_THREADS = 1 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index b98d5319126c6..a81f3d529a2a7 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # setup files to be installed (only ROOT macros for the moment) NOT using GLOB, # as we should be mindful of what we install. if we have lot of files here, it's @@ -32,7 +33,6 @@ install(FILES CheckDigits_mft.C readEMCHits.C readITSDigits.C rootlogon.C - runCATrackingClusterNative.C runTPCRefit.C run_CRUDataSkimming_its.C run_calib_tof.C @@ -47,13 +47,13 @@ install(FILES CheckDigits_mft.C run_cmp2digit_tof.C compareTOFDigits.C compareTOFClusters.C - run_match_tof.C - run_primary_vertexer_ITS.C run_rawdecoding_its.C run_rawdecoding_mft.C run_trac_ca_its.C run_trac_its.C - CreateBCPattern.C + CreateBCPattern.C + UploadDummyAlignment.C + CreateCTPOrbitResetObject.C DESTINATION share/macro/) # FIXME: a lot of macros that are here should really be elsewhere. Those which @@ -81,74 +81,56 @@ o2_add_test_root_macro(analyzeHits.C O2::FDDSimulation O2::MCHSimulation O2::MIDSimulation - O2::ZDCSimulation - O2::CPVBase) + O2::ZDCSimulation + O2::DataFormatsCPV) o2_add_test_root_macro(duplicateHits.C - PUBLIC_LINK_LIBRARIES O2::ITSMFTSimulation - O2::TOFSimulation - O2::EMCALBase - O2::TRDSimulation - O2::FT0Simulation - O2::DataFormatsFV0 - O2::HMPIDBase - O2::TPCSimulation - O2::PHOSBase - O2::FDDSimulation - O2::MCHSimulation - O2::MIDSimulation - O2::ZDCSimulation - O2::CPVBase) + PUBLIC_LINK_LIBRARIES O2::ITSMFTSimulation + O2::TOFSimulation + O2::EMCALBase + O2::TRDSimulation + O2::FT0Simulation + O2::DataFormatsFV0 + O2::DataFormatsHMP + O2::TPCSimulation + O2::PHOSBase + O2::FDDSimulation + O2::MCHSimulation + O2::MIDSimulation + O2::ZDCSimulation + O2::DataFormatsCPV COMPILE_ONLY) o2_add_test_root_macro(migrateSimFiles.C - PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats) + PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats) o2_add_test_root_macro(analyzeOriginHits.C PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::DetectorsCommonDataFormats) -if (ENABLE_UPGRADES) - o2_add_test_root_macro(build_geometry.C - PUBLIC_LINK_LIBRARIES O2::DetectorsPassive - O2::Field - O2::TPCSimulation - O2::ITSSimulation - O2::ITS3Simulation - O2::ITS4Simulation - O2::MFTSimulation - O2::MCHSimulation - O2::MIDSimulation - O2::EMCALSimulation - O2::TOFSimulation - O2::TRDSimulation - O2::FT0Simulation - O2::FV0Simulation - O2::FDDSimulation - O2::HMPIDSimulation - O2::PHOSSimulation - O2::CPVSimulation - O2::ZDCSimulation) -else() - o2_add_test_root_macro(build_geometry.C - PUBLIC_LINK_LIBRARIES O2::DetectorsPassive - O2::Field - O2::TPCSimulation - O2::ITSSimulation - O2::MFTSimulation - O2::MCHSimulation - O2::MIDSimulation - O2::EMCALSimulation - O2::TOFSimulation - O2::TRDSimulation - O2::FT0Simulation - O2::FV0Simulation - O2::FDDSimulation - O2::HMPIDSimulation - O2::PHOSSimulation - O2::CPVSimulation - O2::ZDCSimulation) +if(ENABLE_UPGRADES) + set(upgradeTargets O2::Alice3DetectorsPassive O2::ITS3Simulation O2::TRKSimulation O2::FT3Simulation) endif() +o2_add_test_root_macro(build_geometry.C + PUBLIC_LINK_LIBRARIES O2::DetectorsPassive + O2::Field + O2::TPCSimulation + O2::ITSSimulation + O2::MFTSimulation + O2::MCHSimulation + O2::MIDSimulation + O2::EMCALSimulation + O2::TOFSimulation + O2::TRDSimulation + O2::FT0Simulation + O2::FV0Simulation + O2::FDDSimulation + O2::HMPIDSimulation + O2::PHOSSimulation + O2::CPVSimulation + O2::ZDCSimulation + ${upgradeTargets}) + o2_add_test_root_macro(checkTOFMatching.C PUBLIC_LINK_LIBRARIES O2::GlobalTracking O2::ReconstructionDataFormats @@ -163,13 +145,12 @@ o2_add_test_root_macro(compareTopologyDistributions.C # FIXME: what's the point of this one ? o2_add_test_root_macro(eventDisplay.C PUBLIC_LINK_LIBRARIES FairRoot::Base) -o2_add_test_root_macro( - initSimGeomAndField.C - PUBLIC_LINK_LIBRARIES O2::DataFormatsParameters O2::Field O2::DetectorsBase) +o2_add_test_root_macro(initSimGeomAndField.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsParameters O2::Field O2::DetectorsBase) -o2_add_test_root_macro( - analyzeDigitLabels.C - PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::ITSMFTSimulation +o2_add_test_root_macro(analyzeDigitLabels.C + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat + O2::ITSMFTSimulation O2::TOFSimulation O2::EMCALBase O2::TRDSimulation @@ -183,8 +164,8 @@ o2_add_test_root_macro( O2::FDDSimulation O2::MCHSimulation O2::MIDSimulation - O2::ZDCSimulation - O2::CPVBase + O2::ZDCSimulation + O2::CPVBase O2::CPVSimulation O2::ZDCSimulation) @@ -230,13 +211,6 @@ o2_add_test_root_macro(readITSDigits.C O2::SimulationDataFormat LABELS its) -# FIXME: move to subsystem dir -o2_add_test_root_macro(runCATrackingClusterNative.C - PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC - O2::ReconstructionDataFormats - O2::SimulationDataFormat - O2::TPCReconstruction -LABELS tpc) # FIXME: move to subsystem dir o2_add_test_root_macro(runTPCRefit.C PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC @@ -321,23 +295,6 @@ o2_add_test_root_macro(compareTOFClusters.C PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF LABELS tof) -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_match_tof.C - PUBLIC_LINK_LIBRARIES O2::Field O2::DataFormatsParameters - O2::DetectorsBase - O2::GlobalTracking - LABELS tof) - -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_primary_vertexer_ITS.C - PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT - O2::DataFormatsParameters - O2::GPUTracking - O2::SimulationDataFormat - O2::ITSBase O2::ITStracking - O2::DetectorsBase - LABELS its COMPILE_ONLY) - # FIXME: move to subsystem dir o2_add_test_root_macro(run_rawdecoding_its.C PUBLIC_LINK_LIBRARIES O2::ITSMFTReconstruction @@ -355,6 +312,14 @@ o2_add_test_root_macro(run_rawdecoding_mft.C o2_add_test_root_macro(CreateBCPattern.C PUBLIC_LINK_LIBRARIES O2::CommonDataFormat) +o2_add_test_root_macro(UploadDummyAlignment.C + PUBLIC_LINK_LIBRARIES O2::CCDB + O2::DetectorsCommonDataFormats + O2::CommonDataFormat) + +o2_add_test_root_macro(CreateCTPOrbitResetObject.C + PUBLIC_LINK_LIBRARIES O2::CCDB) + # FIXME: move to subsystem dir + check compilation o2_add_test_root_macro( # run_rec_ca.C PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats # O2::DataFormatsITSMFT O2::DataFormatsParameters O2::DetectorsBase O2::Field diff --git a/macro/CheckDigits_mft.C b/macro/CheckDigits_mft.C index 379c0603cfb91..b81db95134aa8 100644 --- a/macro/CheckDigits_mft.C +++ b/macro/CheckDigits_mft.C @@ -106,7 +106,7 @@ void CheckDigits_mft(Int_t nEvents = 1, Int_t nMuons = 10, TString mcEngine = "T for (auto& p : *hitArray) { if (p.GetDetectorID() != (Short_t)chipID) continue; - if (p.GetTrackID() != (Int_t)lab) + if (p.GetTrackID() != lab.getTrackID()) continue; auto locH = gman->getMatrixL2G(chipID) ^ (p.GetPos()); // inverse conversion from global to local diff --git a/macro/CreateBCPattern.C b/macro/CreateBCPattern.C index 16e2bf4992ccb..3dd9e6ede097b 100644 --- a/macro/CreateBCPattern.C +++ b/macro/CreateBCPattern.C @@ -9,12 +9,17 @@ using namespace std; -void CreateBCPattern(const std::string& outFileName = "bcPattern.root", const string& objName = "") +void CreateBCPattern(const std::string& outFileName = "bcPattern.root", const string& objName = "ccdb_object") { // example of interacting BC pattern creation o2::BunchFilling pattern; + // Note that all setXXX methods have an extra last parameter (def.=-1) to indicate to what object + // the setting is to be applied: -1: interacting bunches pattern, 0/1: A/C beams. + + /* this is an old, but still functional way of setting bunch filling, here we are setting the interacting bunches only + // create 16 trains spaced by 96 BCs, with 48 interacting BCs per train // and 50 ns spacing between the BCs of the train and starting at BC 20 pattern.setBCTrains(16, 96, 48, 2, 20); @@ -22,11 +27,19 @@ void CreateBCPattern(const std::string& outFileName = "bcPattern.root", const st // add extra train of 6 bunches with 25 ns spacing in the very end pattern.setBCTrain(6, 1, o2::constants::lhc::LHCMaxBunches - 6); - // add isolated bunchs at slots 1,3,5 + // add isolated bunches at slots 1,3,5 pattern.setBC(1); pattern.setBC(3); pattern.setBC(5); - // + + */ + + // this is a new way of setting the bunch filling: we set separately A,C beams, then set the interacting bunches as their .AND. + // the resulting interacting bunches pattern will be the same as commented above, but we get also extra A, C non-interacting bunches + pattern.setBCFilling("3(LH) 7(LH) 16(48(HL) 48(HL)) 233(HL) 6H", 0); // A Beam + pattern.setBCFilling("3(LH) 7(HL) 16(48(HL) 48(LH)) 233(LH) 6H", 1); // B Beam + pattern.setInteractingBCsFromBeams(); + pattern.print(); if (!outFileName.empty()) { diff --git a/macro/CreateCTPOrbitResetObject.C b/macro/CreateCTPOrbitResetObject.C new file mode 100644 index 0000000000000..f210baf3d3782 --- /dev/null +++ b/macro/CreateCTPOrbitResetObject.C @@ -0,0 +1,24 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/CcdbApi.h" +#include "Framework/Logger.h" +#include <array> +#endif + +// create and upload orbit reset object to CCDB +constexpr Long64_t DummyTime = -1; + +void CreateCTPOrbitResetObject(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080", long t = DummyTime, long tmin = 0, long tmax = -1) +{ + + if (t == DummyTime) { + t = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); + } + std::vector<Long64_t> rt{t}; + const std::string objName{"CTP/OrbitReset"}; + o2::ccdb::CcdbApi api; + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + map<string, string> metadata; // can be empty + metadata["comment"] = "CTP Orbit reset"; + api.storeAsTFileAny(&rt, objName, metadata, tmin, tmax); + LOGP(INFO, "Uploaded CTP Oribt reset time {} to {}", t, objName); +} diff --git a/macro/UploadDummyAlignment.C b/macro/UploadDummyAlignment.C new file mode 100644 index 0000000000000..d7b29c2a4ee44 --- /dev/null +++ b/macro/UploadDummyAlignment.C @@ -0,0 +1,33 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +//#define ENABLE_UPGRADES +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "CCDB/CcdbApi.h" +#include "Framework/Logger.h" +#include <vector> +#include <fmt/format.h> +#endif + +using DetID = o2::detectors::DetID; + +// upload dummy alignment objects to CCDB +void UploadDummyAlignment(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080", long tmin = 0, long tmax = -1, DetID::mask_t msk = DetID::FullMask) +{ + DetID::mask_t dets = msk & DetID::FullMask & (~DetID::getMask(DetID::CTP)); + LOG(INFO) << "Mask = " << dets; + o2::ccdb::CcdbApi api; + api.init(ccdbHost.c_str()); // or http://localhost:8080 for a local installation + std::vector<o2::detectors::AlignParam> params; + + for (auto id = DetID::First; id <= DetID::Last; id++) { + if (!dets[id]) { + continue; + } + map<string, string> metadata; // can be empty + DetID det(id); + metadata["comment"] = fmt::format("Empty alignment object for {}", det.getName()); + api.storeAsTFileAny(¶ms, o2::base::NameConf::getAlignmentPath(det), metadata, tmin, tmax); + LOG(INFO) << "Uploaded dummy alignment for " << det.getName(); + } +} diff --git a/macro/analyzeDigitLabels.C b/macro/analyzeDigitLabels.C index 19fc2d6129403..58439fee9e016 100644 --- a/macro/analyzeDigitLabels.C +++ b/macro/analyzeDigitLabels.C @@ -4,13 +4,14 @@ #include "TString.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/IOMCTruthContainerView.h" #include "DataFormatsPHOS/MCLabel.h" #include "DataFormatsFT0/MCLabel.h" #include "DataFormatsFDD/MCLabel.h" #include "DataFormatsFV0/MCLabel.h" -#include "ZDCSimulation/MCLabel.h" +#include "DataFormatsZDC/MCLabel.h" #include "MIDSimulation/MCLabel.h" -#include "TRDBase/MCLabel.h" #include <gsl/gsl> // for guideline support library; array_view #include <unordered_map> @@ -78,17 +79,30 @@ void analyse(TTree* tr, const char* brname, Accumulator& prop) if (!br) { return; } + auto classname = br->GetClassName(); auto entries = br->GetEntries(); - o2::dataformats::IOMCTruthContainerView* io2 = nullptr; - br->SetAddress(&io2); + if (strcmp("o2::dataformats::IOMCTruthContainerView", classname) == 0) { + o2::dataformats::IOMCTruthContainerView* io2 = nullptr; + br->SetAddress(&io2); - for (int i = 0; i < entries; ++i) { - br->GetEntry(i); - o2::dataformats::ConstMCTruthContainer<LabelType> labels; - io2->copyandflatten(labels); + for (int i = 0; i < entries; ++i) { + br->GetEntry(i); + o2::dataformats::ConstMCTruthContainer<LabelType> labels; + io2->copyandflatten(labels); - for (int i = 0; i < (int)labels.getIndexedSize(); ++i) { - prop.addLabels(labels.getLabels(i)); + for (int i = 0; i < (int)labels.getIndexedSize(); ++i) { + prop.addLabels(labels.getLabels(i)); + } + } + } else { + // standard MC truth container + o2::dataformats::MCTruthContainer<LabelType>* labels = nullptr; + br->SetAddress(&labels); + for (int i = 0; i < entries; ++i) { + br->GetEntry(i); + for (int i = 0; i < (int)labels->getIndexedSize(); ++i) { + prop.addLabels(labels->getLabels(i)); + } } } }; diff --git a/macro/analyzeHits.C b/macro/analyzeHits.C index d4be4e1527c16..cc22e9e05f05e 100644 --- a/macro/analyzeHits.C +++ b/macro/analyzeHits.C @@ -5,7 +5,7 @@ #include "ITSMFTSimulation/Hit.h" #include "TOFSimulation/Detector.h" #include "EMCALBase/Hit.h" -#include "TRDSimulation/Detector.h" // For TRD Hit +#include "DataFormatsTRD/Hit.h" #include "FT0Simulation/Detector.h" // for Fit Hit #include "DataFormatsFV0/Hit.h" #include "HMPIDBase/Hit.h" @@ -14,8 +14,8 @@ #include "DataFormatsFDD/Hit.h" #include "MCHSimulation/Hit.h" #include "MIDSimulation/Hit.h" -#include "CPVBase/Hit.h" -#include "ZDCSimulation/Hit.h" +#include "DataFormatsCPV/Hit.h" +#include "DataFormatsZDC/Hit.h" #include "DetectorsCommonDataFormats/NameConf.h" #include "DataFormatsParameters/GRPObject.h" #endif @@ -113,7 +113,7 @@ struct HitStats : public HitStatsBase { struct TRDHitStats : public HitStatsBase { // adds a hit to the statistics - void addHit(o2::trd::HitType const& hit) + void addHit(o2::trd::Hit const& hit) { NHits++; auto x = hit.GetX(); @@ -245,7 +245,7 @@ void analyzeTRD(TTree* reftree) { if (!reftree) return; - auto refresult = analyse<o2::trd::HitType, TRDHitStats>(reftree, "TRDHit"); + auto refresult = analyse<o2::trd::Hit, TRDHitStats>(reftree, "TRDHit"); std::cout << gPrefix << " TRD "; refresult.print(); } @@ -377,7 +377,7 @@ void analyzeHits(const char* filebase = "o2sim", const char* prefix = "") gPrefix = prefix; // READ GRP AND ITERATE OVER DETECTED PARTS - auto grp = o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName(filebase).c_str()); + auto grp = o2::parameters::GRPObject::loadFrom(filebase); // should correspond to the same number as defined in DetID analyzeITS(getHitTree(grp, filebase, o2::detectors::DetID::ITS)); diff --git a/macro/build_geometry.C b/macro/build_geometry.C index 60f63e53834ff..0f6e749bfb407 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -43,11 +44,14 @@ #include "FairRunSim.h" #include <FairLogger.h> #include <algorithm> +#include "DetectorsCommonDataFormats/UpgradesStatus.h" #endif #ifdef ENABLE_UPGRADES #include <ITS3Simulation/Detector.h> -#include <ITS4Simulation/Detector.h> +#include <TRKSimulation/Detector.h> +#include <FT3Simulation/Detector.h> +#include <Alice3DetectorsPassive/Pipe.h> #endif void finalize_geometry(FairRunSim* run); @@ -88,7 +92,7 @@ void build_geometry(FairRunSim* run = nullptr) run->SetMaterials("media.geo"); // Materials // we need a field to properly init the media - auto field = o2::field::MagneticField::createNominalField(confref.getConfigData().mField); + auto field = o2::field::MagneticField::createNominalField(confref.getConfigData().mField, confref.getConfigData().mUniformField); run->SetField(field); // Create geometry @@ -127,12 +131,23 @@ void build_geometry(FairRunSim* run = nullptr) // beam pipe if (isActivated("PIPE")) { #ifdef ENABLE_UPGRADES - run->AddModule(new o2::passive::Pipe("PIPE", "Beam pipe", 1.6f, 0.05)); + if (isActivated("IT3")) { + run->AddModule(new o2::passive::Pipe("PIPE", "Beam pipe", 1.6f, 0.05f)); + } else { + run->AddModule(new o2::passive::Pipe("PIPE", "Beam pipe")); + } #else run->AddModule(new o2::passive::Pipe("PIPE", "Beam pipe")); #endif } +#ifdef ENABLE_UPGRADES + // upgraded beampipe at the interaction point (IP) + if (isActivated("A3IP")) { + run->AddModule(new o2::passive::Alice3Pipe("A3IP", "Alice 3 beam pipe", !isActivated("TRK"), 0.48f, 0.015f, 1000.f, 3.7f, 0.05f, 1000.f)); + } +#endif + // the absorber if (isActivated("ABSO")) { // the frame structure to support other detectors @@ -176,10 +191,16 @@ void build_geometry(FairRunSim* run = nullptr) run->AddModule(its3); } - if (isActivated("IT4")) { - // ITS4 - auto its4 = new o2::its4::Detector(true); - run->AddModule(its4); + if (isActivated("TRK")) { + // ALICE 3 TRK + auto trk = new o2::trk::Detector(true); + run->AddModule(trk); + } + + if (isActivated("FT3")) { + // ALICE 3 FT3 + auto ft3 = new o2::ft3::Detector(true); + run->AddModule(ft3); } #endif diff --git a/macro/checkTOFMatching.C b/macro/checkTOFMatching.C index 80f07ebf52b7a..1c31d79783be2 100644 --- a/macro/checkTOFMatching.C +++ b/macro/checkTOFMatching.C @@ -13,6 +13,7 @@ #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "DataFormatsTOF/Cluster.h" +#include "FairLogger.h" #endif //#define DEBUG @@ -23,7 +24,7 @@ void checkTOFMatching(bool batchMode = true) // macro to check the matching TOF-ITSTPC tracks // getting TOF info - TFile* fmatchTOF = new TFile("o2match_tof.root"); + TFile* fmatchTOF = new TFile("o2match_tof_itstpc.root"); TTree* matchTOF = (TTree*)fmatchTOF->Get("matchTOF"); std::vector<o2::dataformats::MatchInfoTOF>* TOFMatchInfo; TOFMatchInfo = new std::vector<o2::dataformats::MatchInfoTOF>; @@ -37,11 +38,11 @@ void checkTOFMatching(bool batchMode = true) // getting the TPC tracks TFile* ftracksTPC = new TFile("tpctracks.root"); - TTree* tpcTree = (TTree*)ftracksTPC->Get("events"); + TTree* tpcTree = (TTree*)ftracksTPC->Get("tpcrec"); std::vector<o2::tpc::TrackTPC>* mTPCTracksArrayInp = new std::vector<o2::tpc::TrackTPC>; - tpcTree->SetBranchAddress("Tracks", &mTPCTracksArrayInp); + tpcTree->SetBranchAddress("TPCTracks", &mTPCTracksArrayInp); std::vector<o2::MCCompLabel>* mcTPC = new std::vector<o2::MCCompLabel>(); - tpcTree->SetBranchAddress("TracksMCTruth", &mcTPC); + tpcTree->SetBranchAddress("TPCTracksMCTruth", &mcTPC); // getting the ITS tracks TFile* ftracksITS = new TFile("o2trac_its.root"); @@ -129,20 +130,20 @@ void checkTOFMatching(bool batchMode = true) int tofClIndex = infoTOF.getTOFClIndex(); float chi2 = infoTOF.getChi2(); #ifdef DEBUG - Printf("\nentry in tree %d, matching %d, indexITSTPCtrack = %d, tofClIndex = %d, chi2 = %f", ientry, imatch, indexITSTPCtrack, tofClIndex, chi2); + LOGF(INFO, "nentry in tree %d, matching %d, indexITSTPCtrack = %d, tofClIndex = %d, chi2 = %f", ientry, imatch, indexITSTPCtrack, tofClIndex, chi2); #endif float matBud = infoTOF.getLTIntegralOut().getX2X0(); // o2::MCCompLabel label = mcTOF->getElement(mcTOF->getMCTruthHeader(tofClIndex).index); const auto& labelsTOF = mcTOF->getLabels(tofClIndex); - int trackIdTOF; - int eventIdTOF; - int sourceIdTOF; + int trackIdTOF = -1; + int eventIdTOF = -1; + int sourceIdTOF = -1; for (uint ilabel = 0; ilabel < labelsTOF.size(); ilabel++) { #ifdef DEBUG - Printf("TOF label %d: trackID = %d, eventID = %d, sourceID = %d", ilabel, labelsTOF[ilabel].getTrackID(), labelsTOF[ilabel].getEventID(), labelsTOF[ilabel].getSourceID()); + LOGF(INFO, "TOF label %d: trackID = %d, eventID = %d, sourceID = %d", ilabel, labelsTOF[ilabel].getTrackID(), labelsTOF[ilabel].getEventID(), labelsTOF[ilabel].getSourceID()); #endif if (ilabel == 0) { trackIdTOF = labelsTOF[ilabel].getTrackID(); @@ -154,12 +155,12 @@ void checkTOFMatching(bool batchMode = true) int nContributingChannels = tofCluster.getNumOfContributingChannels(); int mainContributingChannel = tofCluster.getMainContributingChannel(); #ifdef DEBUG - Printf("The TOF cluster has %d contributing channels, and the main one is %d", nContributingChannels, mainContributingChannel); + LOGF(INFO, "The TOF cluster has %d contributing channels, and the main one is %d", nContributingChannels, mainContributingChannel); #endif - int* indices = new int(); + int indices[5]; o2::tof::Geo::getVolumeIndices(mainContributingChannel, indices); #ifdef DEBUG - Printf("Indices of main contributing channel are %d, %d, %d, %d, %d", indices[0], indices[1], indices[2], indices[3], indices[4]); + LOGF(INFO, "Indices of main contributing channel are %d, %d, %d, %d, %d", indices[0], indices[1], indices[2], indices[3], indices[4]); #endif bool isUpLeft = tofCluster.isAdditionalChannelSet(o2::tof::Cluster::kUpLeft); bool isUp = tofCluster.isAdditionalChannelSet(o2::tof::Cluster::kUp); @@ -170,9 +171,9 @@ void checkTOFMatching(bool batchMode = true) bool isDownLeft = tofCluster.isAdditionalChannelSet(o2::tof::Cluster::kDownLeft); bool isLeft = tofCluster.isAdditionalChannelSet(o2::tof::Cluster::kLeft); #ifdef DEBUG - Printf("isUpLeft = %d, isUp = %d, isUpRight = %d, isRight = %d, isDownRight = %d, isDown = %d, isDownLeft = %d, isLeft = %d", isUpLeft, isUp, isUpRight, isRight, isDownRight, isDown, isDownLeft, isLeft); + LOGF(INFO, "isUpLeft = %d, isUp = %d, isUpRight = %d, isRight = %d, isDownRight = %d, isDown = %d, isDownLeft = %d, isLeft = %d", isUpLeft, isUp, isUpRight, isRight, isDownRight, isDown, isDownLeft, isLeft); #endif - int* indexCont = new int(); + int indexCont[5]; indexCont[0] = indices[0]; indexCont[1] = indices[1]; indexCont[2] = indices[2]; @@ -185,7 +186,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[down] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[down] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; } @@ -195,7 +196,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[downright] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[downright] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; indexCont[4] = indices[4]; @@ -206,7 +207,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[downleft] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[downleft] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; indexCont[4] = indices[4]; @@ -216,7 +217,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[up] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[up] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; } @@ -226,7 +227,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[upright] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[upright] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; indexCont[4] = indices[4]; @@ -237,7 +238,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[upleft] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[upleft] = %d", secondaryContributingChannel); #endif indexCont[3] = indices[3]; indexCont[4] = indices[4]; @@ -247,7 +248,7 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[right] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[right] = %d", secondaryContributingChannel); #endif indexCont[4] = indices[4]; } @@ -256,33 +257,33 @@ void checkTOFMatching(bool batchMode = true) numberOfSecondaryContributingChannels++; secondaryContributingChannel = o2::tof::Geo::getIndex(indexCont); #ifdef DEBUG - Printf("secondaryContributingChannel[left] = %d", secondaryContributingChannel); + LOGF(INFO, "secondaryContributingChannel[left] = %d", secondaryContributingChannel); #endif indexCont[4] = indices[4]; } #ifdef DEBUG - Printf("Total number of secondary channels= %d", numberOfSecondaryContributingChannels); + LOGF(INFO, "Total number of secondary channels= %d", numberOfSecondaryContributingChannels); #endif o2::dataformats::TrackTPCITS trackITSTPC = mTracksArrayInp->at(indexITSTPCtrack); const auto evIdxTPC = trackITSTPC.getRefTPC(); #ifdef DEBUG - Printf("matched TPCtrack index = %d", evIdxTPC); + LOG(INFO) << "matched TPCtrack index:", evIdxTPC; #endif const auto evIdxITS = trackITSTPC.getRefITS(); #ifdef DEBUG - Printf("matched ITStrack index = %d", evIdxITS); + LOG(INFO) << "matched ITStrack index: ", evIdxITS; #endif // getting the TPC labels const auto& labelsTPC = (*mcTPC)[evIdxTPC]; #ifdef DEBUG - Printf("TPC label: trackID = %d, eventID = %d, sourceID = %d", labelsTPC.getTrackID(), labelsTPC.getEventID(), labelsTPC.getSourceID()); + LOGF(INFO, "TPC label: trackID = %d, eventID = %d, sourceID = %d", labelsTPC.getTrackID(), labelsTPC.getEventID(), labelsTPC.getSourceID()); #endif // getting the ITS labels const auto& labelsITS = (*mcITS)[evIdxITS]; #ifdef DEBUG - Printf("ITS label: trackID = %d, eventID = %d, sourceID = %d", ilabel, labelsITS.getTrackID(), labelsITS.getEventID(), labelsITS.getSourceID()); + LOGF(INFO, "ITS label: trackID = %d, eventID = %d, sourceID = %d", labelsITS.getTrackID(), labelsITS.getEventID(), labelsITS.getSourceID()); #endif bool bMatched = kFALSE; for (uint ilabel = 0; ilabel < labelsTOF.size(); ilabel++) { @@ -346,37 +347,37 @@ void checkTOFMatching(bool batchMode = true) bool ITSfound = false; for (uint i = 0; i < mTracksArrayInp->size(); i++) { o2::dataformats::TrackTPCITS trackITSTPC = mTracksArrayInp->at(i); - const auto evIdxTPCcheck = trackITSTPC.getRefTPC(); - const auto evIdxITScheck = trackITSTPC.getRefITS(); - const auto& labelsTPCcheck = (*mcTPC)[evIdxTPCcheck]; + const auto idxTPCcheck = trackITSTPC.getRefTPC(); + const auto idxITScheck = trackITSTPC.getRefITS(); + const auto& labelsTPCcheck = (*mcTPC)[idxTPCcheck.getIndex()]; if (abs(labelsTPCcheck.getTrackID()) == trackIdTOF && labelsTPCcheck.getEventID() == eventIdTOF && labelsTPCcheck.getSourceID() == sourceIdTOF) { #ifdef DEBUG - Printf("The TPC track that should have been matched to TOF is number %d", i); + LOGF(INFO, "The TPC track that should have been matched to TOF is number %d", i); #endif TPCfound = true; } - const auto& labelsITScheck = (*mcITS)[evIdxITScheck]; + const auto& labelsITScheck = (*mcITS)[idxITScheck.getIndex()]; if (labelsITScheck.getTrackID() == trackIdTOF && labelsITScheck.getEventID() == eventIdTOF && labelsITScheck.getSourceID() == sourceIdTOF) { #ifdef DEBUG - Printf("The ITS track that should have been matched to TOF is number %d", i); + LOGF(INFO, "The ITS track that should have been matched to TOF is number %d", i); #endif ITSfound = true; } } #ifdef DEBUG if (!TPCfound) - Printf("There is no TPC track found that should have corresponded to this TOF cluster!"); + LOGF(INFO, "There is no TPC track found that should have corresponded to this TOF cluster!"); if (!ITSfound) - Printf("There is no ITS track found that should have corresponded to this TOF cluster!"); + LOGF(INFO, "There is no ITS track found that should have corresponded to this TOF cluster!"); #endif } } new TCanvas; - Printf("Number of matches = %d", nMatches); - Printf("Number of GOOD matches = %d (%.2f)", nGoodMatches, (float)nGoodMatches / nMatches); - Printf("Number of BAD matches = %d (%.2f)", nBadMatches, (float)nBadMatches / nMatches); + LOGF(INFO, "Number of matches = %d", nMatches); + LOGF(INFO, "Number of GOOD matches = %d (%.2f)", nGoodMatches, (float)nGoodMatches / nMatches); + LOGF(INFO, "Number of BAD matches = %d (%.2f)", nBadMatches, (float)nBadMatches / nMatches); TFile* fout = nullptr; if (batchMode) @@ -489,7 +490,7 @@ void checkTOFMatching(bool batchMode = true) float fraction = hchi2dh->GetEntries() * 1. / hchi2->GetEntries(); float fractionErr = TMath::Sqrt(fraction * (1 - fraction) / hchi2->GetEntries()); - printf("Fraction of multiple hits = (%.1f +/- %.1f)%c\n", fraction * 100, fractionErr * 100, '%'); + LOGF(INFO, "Fraction of multiple hits = (%.1f +/- %.1f)%c", fraction * 100, fractionErr * 100, '%'); htof->Fit("pol0", "", "", 1, 5); float effMatch = 0; @@ -498,7 +499,7 @@ void checkTOFMatching(bool batchMode = true) float effMatchErr = 0; if (htof->GetListOfFunctions()->At(0)) effMatchErr = ((TF1*)htof->GetListOfFunctions()->At(0))->GetParError(0); - printf("TOF matching eff (pt > 1) = %f +/- %f\n", effMatch, effMatchErr); + LOGF(INFO, "TOF matching eff (pt > 1) = %f +/- %f", effMatch, effMatchErr); htofMism->Fit("pol0", "", "", 1, 5); float mismMatch = 0; @@ -507,7 +508,7 @@ void checkTOFMatching(bool batchMode = true) float mismMatchErr = 0; if (htofMism->GetListOfFunctions()->At(0)) mismMatchErr = ((TF1*)htofMism->GetListOfFunctions()->At(0))->GetParError(0); - printf("TOF-track mismatch (pt > 1) = %f +/- %f\n", mismMatch, mismMatchErr); + LOGF(INFO, "TOF-track mismatch (pt > 1) = %f +/- %f", mismMatch, mismMatchErr); if (fout) fout->Close(); diff --git a/macro/compareTOFClusters.C b/macro/compareTOFClusters.C index 69b717f8b8795..07029215e9dee 100644 --- a/macro/compareTOFClusters.C +++ b/macro/compareTOFClusters.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/compareTOFDigits.C b/macro/compareTOFDigits.C index b9b450f2f86a8..a2675ec63e6c0 100644 --- a/macro/compareTOFDigits.C +++ b/macro/compareTOFDigits.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/compareTopologyDistributions.C b/macro/compareTopologyDistributions.C index 1224eb8a5e120..954538c600129 100644 --- a/macro/compareTopologyDistributions.C +++ b/macro/compareTopologyDistributions.C @@ -24,7 +24,7 @@ void compareTopologyDistributions( string output_file_name = "comparison.root") { if (dictionary_file_name.empty()) { - dictionary_file_name = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictionary_file_name = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } o2::itsmft::TopologyDictionary dict; dict.readBinaryFile(dictionary_file_name.c_str()); diff --git a/macro/duplicateHits.C b/macro/duplicateHits.C index 3dbe8511b958c..f22b0957dea4f 100644 --- a/macro/duplicateHits.C +++ b/macro/duplicateHits.C @@ -8,15 +8,23 @@ #include "TRDSimulation/Detector.h" // For TRD Hit #include "FT0Simulation/Detector.h" // for Fit Hit #include "DataFormatsFV0/Hit.h" -#include "HMPIDBase/Hit.h" +#include "DataFormatsHMP/Hit.h" #include "TPCSimulation/Point.h" #include "PHOSBase/Hit.h" #include "DataFormatsFDD/Hit.h" #include "MCHSimulation/Hit.h" #include "MIDSimulation/Hit.h" -#include "CPVBase/Hit.h" -#include "ZDCSimulation/Hit.h" +#include "DataFormatsCPV/Hit.h" +#include "DataFormatsZDC/Hit.h" #include "SimulationDataFormat/MCEventHeader.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" +#include "DetectorsCommonDataFormats/SimTraits.h" + +#ifdef ENABLE_UPGRADES +#include "EndCapsSimulation/Hit.h" +#endif + #endif template <typename T> @@ -37,7 +45,7 @@ void duplicate(TTree* tr, const char* brname, TTree* outtree, int factor) for (int i = 0; i < entries; ++i) { br->GetEntry(i); - for (int i = 0; i < factor; ++i) { + for (int j = 0; j < factor; ++j) { outbranch->Fill(); } } @@ -168,11 +176,10 @@ void duplicateHits(const char* filebase = "o2sim", const char* newfilebase = "o2 auto kintree = getKinematicsTree(filebase); auto newkintree = getKinematicsTree(newfilebase, "RECREATE"); // duplicate meta branches - duplicate<o2::MCTrack>(kintree, "MCTrack", newkintree, factor); + duplicate<std::vector<o2::MCTrack>>(kintree, "MCTrack", newkintree, factor); duplicate<o2::dataformats::MCEventHeader>(kintree, "MCEventHeader.", newkintree, factor); // TODO: fix EventIDs in the newly created MCEventHeaders - duplicate<o2::TrackReference>(kintree, "TrackRefs", newkintree, factor); - duplicate<o2::dataformats::MCTruthContainer<o2::TrackReference>>(kintree, "IndexedTrackRefs", newkintree, factor); + duplicate<std::vector<o2::TrackReference>>(kintree, "TrackRefs", newkintree, factor); newkintree->Write(); // duplicating hits @@ -181,7 +188,7 @@ void duplicateHits(const char* filebase = "o2sim", const char* newfilebase = "o2 duplicateV<o2::itsmft::Hit>(grp, filebase, DetID::MFT, newfilebase, factor); duplicateV<o2::tof::HitType>(grp, filebase, DetID::TOF, newfilebase, factor); duplicateV<o2::emcal::Hit>(grp, filebase, DetID::EMC, newfilebase, factor); - duplicateV<o2::trd::HitType>(grp, filebase, DetID::TRD, newfilebase, factor); + duplicateV<o2::trd::Hit>(grp, filebase, DetID::TRD, newfilebase, factor); duplicateV<o2::phos::Hit>(grp, filebase, DetID::PHS, newfilebase, factor); duplicateV<o2::cpv::Hit>(grp, filebase, DetID::CPV, newfilebase, factor); duplicateV<o2::zdc::Hit>(grp, filebase, DetID::ZDC, newfilebase, factor); @@ -192,6 +199,11 @@ void duplicateHits(const char* filebase = "o2sim", const char* newfilebase = "o2 duplicateV<o2::mid::Hit>(grp, filebase, DetID::MID, newfilebase, factor); duplicateV<o2::mch::Hit>(grp, filebase, DetID::MCH, newfilebase, factor); duplicateV<o2::tpc::HitGroup>(grp, filebase, DetID::TPC, newfilebase, factor); + +#ifdef ENABLE_UPGRADES + duplicateV<o2::itsmft::Hit>(grp, filebase, DetID::FT3, newfilebase, factor); +#endif + // duplicateACO(reftree); // outfile.Write(); } diff --git a/macro/initSimGeomAndField.C b/macro/initSimGeomAndField.C index 658358e5047c5..7fb594110e282 100644 --- a/macro/initSimGeomAndField.C +++ b/macro/initSimGeomAndField.C @@ -8,8 +8,6 @@ #include "DetectorsBase/GeometryManager.h" #endif -int initFieldFromGRP(const o2::parameters::GRPObject* grp); -int initFieldFromGRP(const std::string grpFileName = "o2sim_grp.root", std::string grpName = "GRP"); int initSimGeom(std::string geom = ""); int initSimGeomAndField(std::string geom = "", std::string grpFileName = "o2sim_grp.root", std::string grpName = "GRP") @@ -19,7 +17,7 @@ int initSimGeomAndField(std::string geom = "", std::string grpFileName = "o2sim_ if (res) { return res; } - res = initFieldFromGRP(grpFileName, grpName); + res = o2::base::Propagator::initFieldFromGRP(grpFileName, grpName); return res; } @@ -29,50 +27,3 @@ int initSimGeom(std::string geom) o2::base::GeometryManager::loadGeometry(geom); return 0; } - -//____________________________________________________________ -int initFieldFromGRP(const std::string grpFileName, std::string grpName) -{ - /// load grp and init magnetic field - std::cout << "Loading field from GRP of " << grpFileName << std::endl; - TFile flGRP(grpFileName.data()); - if (flGRP.IsZombie()) { - std::cout << "Failed to open " << grpFileName << std::endl; - return -10; - } - auto grp = - static_cast<o2::parameters::GRPObject*>(flGRP.GetObjectChecked(grpName.data(), o2::parameters::GRPObject::Class())); - if (!grp) { - std::cout << "Did not find GRP object named " << grpName << std::endl; - return -12; - } - grp->print(); - - return initFieldFromGRP(grp); -} - -//____________________________________________________________ -int initFieldFromGRP(const o2::parameters::GRPObject* grp) -{ - /// init mag field from GRP data and attach it to TGeoGlobalMagField - - if (TGeoGlobalMagField::Instance()->IsLocked()) { - if (TGeoGlobalMagField::Instance()->GetField()->TestBit(o2::field::MagneticField::kOverrideGRP)) { - std::cout << "ExpertMode!!! GRP information will be ignored" << std::endl; - std::cout << "ExpertMode!!! Running with the externally locked B field" << std::endl; - return 0; - } else { - std::cout << "Destroying existing B field instance" << std::endl; - delete TGeoGlobalMagField::Instance(); - } - } - auto fld = o2::field::MagneticField::createFieldMap(grp->getL3Current(), grp->getDipoleCurrent()); - TGeoGlobalMagField::Instance()->SetField(fld); - TGeoGlobalMagField::Instance()->Lock(); - std::cout << "Running with the B field constructed out of GRP" << std::endl; - std::cout << "Access field via TGeoGlobalMagField::Instance()->Field(xyz,bxyz) or via" << std::endl; - std::cout << "auto o2field = static_cast<o2::field::MagneticField*>( TGeoGlobalMagField::Instance()->GetField() )" - << std::endl; - - return 0; -} diff --git a/macro/migrateSimFiles.C b/macro/migrateSimFiles.C index cf0ff9650d0d6..f96d2ff7e0a67 100644 --- a/macro/migrateSimFiles.C +++ b/macro/migrateSimFiles.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -65,7 +66,7 @@ void migrateSimFiles(const char* filebase = "o2sim") { // READ GRP AND ITERATE OVER DETECTED PARTS - auto grp = o2::parameters::GRPObject::loadFrom(o2::base::NameConf::getGRPFileName(filebase).c_str()); + auto grp = o2::parameters::GRPObject::loadFrom(filebase); if (!grp) { std::cerr << "No GRP found. Exiting\n"; } @@ -75,6 +76,11 @@ void migrateSimFiles(const char* filebase = "o2sim") auto kinematicsfile = o2::base::NameConf::getMCKinematicsFileName(filebase); copyBranch(originalfilename.c_str(), kinematicsfile.c_str(), o2::detectors::SimTraits::KINEMATICSBRANCHES); + // split off additional MCHeaders file + std::vector<std::string> headerbranches = {"MCEventHeader"}; + auto headersfile = o2::base::NameConf::getMCHeadersFileName(filebase); + copyBranch(originalfilename.c_str(), headersfile.c_str(), headerbranches); + // loop over all possible detectors for (auto detid = o2::detectors::DetID::First; detid <= o2::detectors::DetID::Last; ++detid) { if (!grp->isDetReadOut(detid)) { diff --git a/macro/o2sim.C b/macro/o2sim.C index dec28e6ab6cdb..e49842087c61a 100644 --- a/macro/o2sim.C +++ b/macro/o2sim.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include <Generators/PDG.h> #include "SimulationDataFormat/MCEventHeader.h" #include <SimConfig/SimConfig.h> +#include <SimConfig/SimParams.h> #include <CommonUtils/ConfigurableParam.h> #include <CommonUtils/RngHelper.h> #include <TStopwatch.h> @@ -27,6 +29,7 @@ #include <DetectorsBase/MaterialManager.h> #include <CCDB/BasicCCDBManager.h> #include <DetectorsCommonDataFormats/NameConf.h> +#include "DetectorsBase/Aligner.h" #include <unistd.h> #include <sstream> #endif @@ -56,8 +59,8 @@ FairRunSim* o2sim_init(bool asservice) // update the parameters from stuff given at command line (overrides file-based version) o2::conf::ConfigurableParam::updateFromString(confref.getKeyValueString()); - // write the configuration file - o2::conf::ConfigurableParam::writeINI("o2sim_configuration.ini"); + // write the final configuration file + o2::conf::ConfigurableParam::writeINI(o2::base::NameConf::getMCConfigFileName(confref.getOutPrefix())); // we can update the binary CCDB entry something like this ( + timestamp key ) // o2::conf::ConfigurableParam::toCCDB("params_ccdb.root"); @@ -91,6 +94,7 @@ FairRunSim* o2sim_init(bool asservice) // construct geometry / including magnetic field build_geometry(run); + // setup generator auto embedinto_filename = confref.getEmbedIntoFileName(); auto primGen = new o2::eventgen::PrimaryGenerator(); @@ -106,8 +110,29 @@ FairRunSim* o2sim_init(bool asservice) TStopwatch timer; timer.Start(); + o2::detectors::DetID::mask_t detMask{}; + { + auto& modulelist = o2::conf::SimConfig::Instance().getActiveDetectors(); + for (const auto& md : modulelist) { + int id = o2::detectors::DetID::nameToID(md.c_str()); + if (id >= o2::detectors::DetID::First) { + detMask |= o2::detectors::DetID::getMask(id); + } + } + // somewhat ugly, but this is the most straighforward way to make sure the detectors to align + // don't include detectors which are not activated + auto& aligner = o2::base::Aligner::Instance(); + auto detMaskAlign = aligner.getDetectorsMask() & detMask; + aligner.setValue(fmt::format("{}.mDetectors", aligner.getName()), o2::detectors::DetID::getNames(detMaskAlign, ',')); + } + + // set global density scaling factor + auto& matmgr = o2::base::MaterialManager::Instance(); + matmgr.setDensityScalingFactor(o2::conf::SimMaterialParams::Instance().globalDensityFactor); + // run init run->Init(); + std::time_t runStart = std::time(nullptr); // runtime database @@ -134,22 +159,12 @@ FairRunSim* o2sim_init(bool asservice) grp.setRun(run->GetRunId()); grp.setTimeStart(runStart); grp.setTimeEnd(std::time(nullptr)); - TObjArray* modArr = run->GetListOfModules(); - TIter next(modArr); - FairModule* module = nullptr; - while ((module = (FairModule*)next())) { - o2::base::Detector* det = dynamic_cast<o2::base::Detector*>(module); - if (!det) { - continue; // not a detector - } - if (det->GetDetId() < o2::detectors::DetID::First) { - continue; // passive - } - if (det->GetDetId() > o2::detectors::DetID::Last) { - continue; // passive - } - grp.addDetReadOut(o2::detectors::DetID(det->GetDetId())); + grp.setDetsReadOut(detMask); + // CTP is not a physical detector, just flag in the GRP if requested + if (isActivated("CTP")) { + grp.addDetReadOut(o2::detectors::DetID::CTP); } + grp.print(); printf("VMC: %p\n", TVirtualMC::GetMC()); auto field = dynamic_cast<o2::field::MagneticField*>(run->GetField()); @@ -158,17 +173,18 @@ FairRunSim* o2sim_init(bool asservice) o2::units::Current_t currL3 = field->getCurrentSolenoid(); grp.setL3Current(currL3); grp.setDipoleCurrent(currDip); + grp.setFieldUniformity(field->IsUniform()); } // save std::string grpfilename = o2::base::NameConf::getGRPFileName(confref.getOutPrefix()); TFile grpF(grpfilename.c_str(), "recreate"); grpF.WriteObjectAny(&grp, grp.Class(), "GRP"); } + // todo: save beam information in the grp // print summary about cuts and processes used std::ofstream cutfile(o2::base::NameConf::getCutProcFileName(confref.getOutPrefix())); - auto& matmgr = o2::base::MaterialManager::Instance(); matmgr.printCuts(cutfile); matmgr.printProcesses(cutfile); diff --git a/macro/runCATrackingClusterNative.C b/macro/runCATrackingClusterNative.C deleted file mode 100644 index 95d1f215fbeb9..0000000000000 --- a/macro/runCATrackingClusterNative.C +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include <fstream> -#include <iostream> -#include <vector> -#include "TSystem.h" - -#include "TChain.h" -#include "TClonesArray.h" -#include "TFile.h" -#include "TROOT.h" -#include "TTree.h" - -#include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/ClusterNativeHelper.h" -#include "DataFormatsTPC/Helpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsTPC/Constants.h" -#include "TPCReconstruction/GPUCATracking.h" -#include "GPUO2InterfaceConfiguration.h" -#include "DataFormatsTPC/TrackTPC.h" -#else -#pragma cling load("libO2TPCReconstruction") -#pragma cling load("libO2DataFormatsTPC") -#endif - -using namespace o2::gpu; -using namespace o2::tpc; -using namespace o2::dataformats; -using namespace std; - -#if !defined(__CLING__) || defined(__ROOTCLING__) // Disable in interpreted mode due to missing rootmaps - -// This is a prototype of a macro to test running the HLT O2 CA Tracking library on a root input file containg -// TClonesArray of clusters. -// It wraps the GPUCATracking class -int runCATrackingClusterNative(TString inputFile, TString outputFile) -{ - if (inputFile.EqualTo("") || outputFile.EqualTo("")) { - printf("Filename missing\n"); - return (1); - } - GPUCATracking tracker; - - // Just some default options to keep the macro running for now - // Should be deprecated anyway in favor of the TPC workflow - GPUO2InterfaceConfiguration config; - config.configEvent.continuousMaxTimeBin = GPUSettings::TPC_MAX_TF_TIME_BIN; - config.configReconstruction.NWays = 3; - config.configReconstruction.NWaysOuter = true; - config.configReconstruction.SearchWindowDZDR = 2.5f; - if (tracker.initialize(config)) { - printf("Error initializing tracker\n"); - return (0); - } - - std::vector<ClusterNativeContainer> cont; - std::vector<MCLabelContainer> contMC; - std::unique_ptr<ClusterNative[]> clusterBuffer; - MCLabelContainer clusterMCBuffer; - bool doMC = true; - - TFile fin(inputFile); - for (int i = 0; i < o2::tpc::constants::MAXSECTOR; i++) { - for (int j = 0; j < o2::tpc::constants::MAXGLOBALPADROW; j++) { - TString contName = Form("clusters_sector_%d_row_%d", i, j); - TObject* tmp = fin.FindObjectAny(contName); - if (tmp == nullptr) { - printf("Error reading clusters %s\n", contName.Data()); - } else { - cont.emplace_back(std::move(*reinterpret_cast<ClusterNativeContainer*>(tmp))); - tmp = fin.FindObjectAny(Form("clustersMCTruth_sector_%d_row_%d", i, j)); - - if (tmp == nullptr) { - printf("Error, clustersMCTruth missing or clusters and clustersMCtruth out of sync! Disabling MC data\n"); - doMC = false; - } else { - contMC.emplace_back(std::move(*reinterpret_cast<MCLabelContainer*>(tmp))); - } - } - } - } - fin.Close(); - - std::unique_ptr<ClusterNativeAccess> clusters = - ClusterNativeHelper::createClusterNativeIndex(clusterBuffer, cont, doMC ? &clusterMCBuffer : nullptr, doMC ? &contMC : nullptr); - - vector<TrackTPC> tracks; - vector<TPCClRefElem> trackClusRefs; - std::vector<o2::MCCompLabel> tracksMC; - - TFile fout(outputFile, "recreate"); - TTree tout("events", "events"); - tout.Branch("Tracks", &tracks); - tout.Branch("TracksClusRefs", &trackClusRefs); - tout.Branch("TracksMCTruth", &tracksMC); - - printf("Processing time frame\n"); - GPUO2InterfaceIOPtrs ptrs; - ptrs.clusters = clusters.get(); - ptrs.outputTracks = &tracks; - ptrs.outputClusRefs = &trackClusRefs; - ptrs.outputTracksMCTruth = doMC ? &tracksMC : nullptr; - if (tracker.runTracking(&ptrs) == 0) { - printf("\tFound %d tracks\n", (int)tracks.size()); - } else { - printf("\tError during tracking\n"); - } - - float artificialVDrift = tracker.getPseudoVDrift(); - - // partial printout of 100 tracks - int step = tracks.size() / 100; - step = step < 1 ? 1 : step; - for (unsigned int i = 0; i < tracks.size(); i += step) { - // Loop over clusters - for (int j = tracks[i].getNClusterReferences() - 1; j >= 0; j--) { - // Get cluster references - uint8_t sector, row; - uint32_t clusterIndexInRow; - tracks[i].getClusterReference(trackClusRefs, j, sector, row, clusterIndexInRow); - const ClusterNative& cl = tracks[i].getCluster(trackClusRefs, j, *clusters, sector, row); - const ClusterNative& clLast = tracks[i].getCluster(trackClusRefs, 0, *clusters); - // RS: TODO: account for possible A/C merged tracks - float sideFactor = tracks[i].hasASideClustersOnly() ? -1.f : 1.f; - printf( - "Track %d: Side %s Estimated timeVertex: %f, num clusters %d, innermost cluster: sector %d, row %d, " - "ClusterTime %f, TrackParam X %f Z %f --> T %f, LastClusterT: %f\n", - i, tracks[i].hasBothSidesClusters() ? "AC" : (tracks[i].hasASideClusters() ? "A" : "C"), tracks[i].getTime0(), - tracks[i].getNClusterReferences(), (int)sector, (int)row, cl.getTime(), tracks[i].getX(), tracks[i].getZ(), - tracks[i].getTime0() - sideFactor * tracks[i].getZ() / artificialVDrift, clLast.getTime()); - break; // Reduce output in this example code - } - } - - tout.Fill(); - fout.Write(); - fout.Close(); - - tracker.deinitialize(); - return (0); -} - -#endif diff --git a/macro/runTPCRefit.C b/macro/runTPCRefit.C index 13ead3aed2fcd..f683a5a73bfb3 100644 --- a/macro/runTPCRefit.C +++ b/macro/runTPCRefit.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -40,6 +41,9 @@ using namespace o2::base; using namespace o2::track; using namespace std; +// This is actually defined in the TPC DataFormats, but for whatever reason ROOT Cling doesn't pick it up from there. +using TPCClRefElem = uint32_t; + int runTPCRefit(TString trackFile = "tpctracks.root", TString clusterFile = "tpc-native-clusters.root") { GeometryManager::loadGeometry(); @@ -81,7 +85,7 @@ int runTPCRefit(TString trackFile = "tpctracks.root", TString clusterFile = "tpc std::cout << "Error reading clusters (code " << retVal << ")\n"; return 1; } - GPUTPCO2InterfaceRefit refit(&clusterIndex, trans.get(), bz, trackHitRefs->data(), nullptr, tracks, prop); + GPUO2InterfaceRefit refit(&clusterIndex, trans.get(), bz, trackHitRefs->data(), nullptr, tracks, prop); //refit.setGPUTrackFitInProjections(false); // Enable full 3D fit without assuming y and Z are uncorrelated for (unsigned int i = 0; i < tracks->size(); i++) { TrackTPC trk = (*tracks)[i]; diff --git a/macro/run_calib_tof.C b/macro/run_calib_tof.C index 283d0eb27e2ea..4f2956425f898 100644 --- a/macro/run_calib_tof.C +++ b/macro/run_calib_tof.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/run_clus_itsSA.C b/macro/run_clus_itsSA.C index b0e080bd30edb..bc0360bc47a1d 100644 --- a/macro/run_clus_itsSA.C +++ b/macro/run_clus_itsSA.C @@ -42,7 +42,7 @@ void run_clus_itsSA(std::string inputfile = "rawits.bin", // input file name clus->setMaxROframe(2 << 21); // about 3 cluster files per a raw data chunk if (dictionaryfile.empty()) { - dictionaryfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictionaryfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } std::ifstream file(dictionaryfile.c_str()); if (file.good()) { diff --git a/macro/run_clus_tof.C b/macro/run_clus_tof.C index c38ab4bafd249..ecbc258f1dc70 100644 --- a/macro/run_clus_tof.C +++ b/macro/run_clus_tof.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/run_cmp2digit_tof.C b/macro/run_cmp2digit_tof.C index e59c3122f9d63..8c11dc2a8c4d1 100644 --- a/macro/run_cmp2digit_tof.C +++ b/macro/run_cmp2digit_tof.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/run_collect_calib_tof.C b/macro/run_collect_calib_tof.C index 2e94fc5a45f98..0634f59f25859 100644 --- a/macro/run_collect_calib_tof.C +++ b/macro/run_collect_calib_tof.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/run_digi2raw_tof.C b/macro/run_digi2raw_tof.C index 98cde84a0e60a..719021fa1cc08 100644 --- a/macro/run_digi2raw_tof.C +++ b/macro/run_digi2raw_tof.C @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/macro/run_match_tof.C b/macro/run_match_tof.C deleted file mode 100644 index c66700499d922..0000000000000 --- a/macro/run_match_tof.C +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include <TFile.h> -#include <TChain.h> -#include <TTree.h> -#include <TGeoGlobalMagField.h> -#include <string> -#include <FairLogger.h> - -#include "Field/MagneticField.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" - -#include "GlobalTracking/MatchTOF.h" -#endif - -#define _ALLOW_DEBUG_TREES_ // to allow debug and control tree output - -void run_match_tof(std::string path = "./", std::string outputfile = "o2match_tof.root", - std::string outputfileCalib = "o2calib_tof.root", - std::string inputTracksTPCITS = "o2match_itstpc.root", - std::string inputTracksTPC = "tpctracks.root", - std::string inputClustersTOF = "tofclusters.root", - std::string inputGRP = "o2sim_grp.root") -{ - - o2::globaltracking::MatchTOF matching; - - if (path.back() != '/') { - path += '/'; - } - - //>>>---------- attach input data --------------->>> - TChain tracks("matchTPCITS"); - tracks.AddFile((path + inputTracksTPCITS).data()); - matching.setInputTreeTracks(&tracks); - - TChain tpcTracks("events"); - tpcTracks.AddFile((path + inputTracksTPC).data()); - matching.setInputTreeTPCTracks(&tpcTracks); - matching.setTPCTrackBranchName("TPCTracks"); - - TChain tofClusters("o2sim"); - tofClusters.AddFile((path + inputClustersTOF).data()); - matching.setInputTreeTOFClusters(&tofClusters); - - //<<<---------- attach input data ---------------<<< - - // create/attach output tree - TFile outFile((path + outputfile).data(), "recreate"); - TTree outTree("matchTOF", "Matched TOF-tracks"); - matching.setOutputTree(&outTree); - TFile outFileCalib((path + outputfileCalib).data(), "recreate"); - TTree outTreeCalib("calibTOF", "Calib TOF infos"); - matching.setOutputTreeCalib(&outTreeCalib); - -#ifdef _ALLOW_DEBUG_TREES_ - matching.setDebugTreeFileName(path + matching.getDebugTreeFileName()); - matching.setDebugFlag(o2::globaltracking::MatchTOF::MatchTreeAll); -#endif - - //-------- init geometry and field --------// - o2::base::GeometryManager::loadGeometry(path); - o2::base::Propagator::initFieldFromGRP(path + inputGRP); - - matching.init(); - - matching.run(); - - outFile.cd(); - outTree.Write(); - outFile.Close(); - outFileCalib.cd(); - outTreeCalib.Write(); - outFileCalib.Close(); -} diff --git a/macro/run_primary_vertexer_ITS.C b/macro/run_primary_vertexer_ITS.C deleted file mode 100644 index 1a9e8f122f7fc..0000000000000 --- a/macro/run_primary_vertexer_ITS.C +++ /dev/null @@ -1,219 +0,0 @@ -#if !defined(__CLING__) || defined(__ROOTCLING__) - -#include <memory> -#include <TChain.h> -#include <TFile.h> -#include <TSystem.h> -#include <TNtuple.h> - -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "SimulationDataFormat/MCEventHeader.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "DetectorsCommonDataFormats/NameConf.h" - -#include "ITSBase/GeometryTGeo.h" -#include "ITStracking/IOUtils.h" -#include "ITStracking/Vertexer.h" -// #include "ITStrackingCUDA/VertexerTraitsGPU.h" - -#include "GPUO2Interface.h" -#include "GPUReconstruction.h" -#include "GPUChainITS.h" -#endif - -using MCLabCont = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; -using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; -using namespace o2::gpu; - -int run_primary_vertexer_ITS(const GPUDataTypes::DeviceType dtype = GPUDataTypes::DeviceType::CPU, - const bool useMCcheck = false, - const int inspEvt = -1, - const int numEvents = 1, - const float phiCut = -1.f, - const float tanlambdaCut = -1.f, - const std::string inputClustersITS = "o2clus_its.root", - std::string dictfile = "", - const std::string inputGRP = "o2sim_grp.root", - const std::string simfilename = "o2sim_Kine.root", - const std::string path = "./") -{ - std::string gpuName; - switch (dtype) { - case GPUDataTypes::DeviceType::CUDA: - // R__LOAD_LIBRARY(O2ITStrackingCUDA) - gpuName = "vertexer_cuda"; - break; - case GPUDataTypes::DeviceType::HIP: - // R__LOAD_LIBRARY(O2ITStrackingHIP) - gpuName = "vertexer_hip"; - break; - default: - gpuName = "vertexer_serial"; - break; - } - - std::unique_ptr<GPUReconstruction> rec(GPUReconstruction::CreateInstance(dtype, true)); - auto* chainITS = rec->AddChain<GPUChainITS>(); - rec->Init(); - o2::its::Vertexer vertexer(chainITS->GetITSVertexerTraits()); - // o2::its::Vertexer vertexer(new o2::its::VertexerTraits()); - - std::string mcCheck = useMCcheck ? "_data_MCCheck" : "_data"; - std::string outfile = gpuName + mcCheck + ".root"; - - const auto grp = o2::parameters::GRPObject::loadFrom(path + inputGRP); - const bool isITS = grp->isDetReadOut(o2::detectors::DetID::ITS); - const bool isContITS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS); - std::cout << "ITS is in " << (isContITS ? "CONTINUOS" : "TRIGGERED") << " readout mode" << std::endl; - TChain itsClusters("o2sim"); - itsClusters.AddFile((path + inputClustersITS).data()); - - o2::base::GeometryManager::loadGeometry(path); - o2::its::GeometryTGeo* geom = o2::its::GeometryTGeo::Instance(); - geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, - o2::math_utils::TransformType::L2G)); // request cached transforms - - // Get event header - TChain mcHeaderTree("o2sim"); - mcHeaderTree.AddFile((path + simfilename).data()); - o2::dataformats::MCEventHeader* mcHeader = nullptr; - if (!mcHeaderTree.GetBranch("MCEventHeader.")) { - LOG(FATAL) << "Did not find MC event header in the input header file."; - } - mcHeaderTree.SetBranchAddress("MCEventHeader.", &mcHeader); - - itsClusters.AddFile((path + inputClustersITS).data()); - - if (!itsClusters.GetBranch("ITSClusterComp")) { - LOG(FATAL) << "Did not find ITS clusters branch ITSClusterComp in the input tree"; - } - std::vector<o2::itsmft::CompClusterExt>* cclusters = nullptr; - itsClusters.SetBranchAddress("ITSClusterComp", &cclusters); - - if (!itsClusters.GetBranch("ITSClusterPatt")) { - LOG(FATAL) << "Did not find ITS cluster patterns branch ITSClusterPatt in the input tree"; - } - std::vector<unsigned char>* patterns = nullptr; - itsClusters.SetBranchAddress("ITSClusterPatt", &patterns); - - MCLabCont* labels = nullptr; - if (!itsClusters.GetBranch("ITSClusterMCTruth")) { - LOG(WARNING) << "Did not find ITS clusters branch ITSClusterMCTruth in the input tree"; - } else { - itsClusters.SetBranchAddress("ITSClusterMCTruth", &labels); - } - - if (!itsClusters.GetBranch("ITSClustersROF")) { - LOG(FATAL) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; - } - - std::vector<o2::itsmft::MC2ROFRecord>* mc2rofs = nullptr; - if (!itsClusters.GetBranch("ITSClustersMC2ROF")) { - LOG(FATAL) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; - } - itsClusters.SetBranchAddress("ITSClustersMC2ROF", &mc2rofs); - - std::vector<o2::itsmft::ROFRecord>* rofs = nullptr; - itsClusters.SetBranchAddress("ITSClustersROF", &rofs); - - itsClusters.GetEntry(0); - //------------------------------------------------- - - o2::itsmft::TopologyDictionary dict; - if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); - } - std::ifstream file(dictfile.c_str()); - if (file.good()) { - LOG(INFO) << "Running with dictionary: " << dictfile.c_str(); - dict.readBinaryFile(dictfile); - } else { - LOG(INFO) << "Running without dictionary !"; - } - - //------------------------------------------------- - - TFile* outputfile = new TFile(outfile.data(), "recreate"); - - TTree outTree("o2sim", "Vertexer Vertices"); - std::vector<o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>>* verticesITS = - new std::vector<o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>>; - outTree.Branch("ITSVertices", &verticesITS); - - // benchmarks - TNtuple foundVerticesBenchmark("foundVerticesBenchmark", "Found vertices benchmark", "frameId:foundVertices"); - TNtuple timeBenchmark("timeBenchmark", "Time benchmarks", "init:trackletFinder:trackletMatcher:vertexFinder:total"); - // \benchmarks - - std::uint32_t roFrame = 0; - - // Settings - o2::its::VertexingParameters parameters; - parameters.phiCut = phiCut > 0 ? phiCut : 0.005f; - parameters.tanLambdaCut = tanlambdaCut > 0 ? tanlambdaCut : 0.002f; - // e.g. parameters.clusterContributorsCut = 5; - // \Settings - - const int stopAt = (inspEvt == -1) ? rofs->size() : inspEvt + numEvents; - const int startAt = (inspEvt == -1) ? 0 : inspEvt; - - vertexer.setParameters(parameters); - itsClusters.GetEntry(0); - mcHeaderTree.GetEntry(0); - - gsl::span<const unsigned char> patt(patterns->data(), patterns->size()); - auto pattIt = patt.begin(); - auto clSpan = gsl::span(cclusters->data(), cclusters->size()); - - for (size_t iROfCount{static_cast<size_t>(startAt)}; iROfCount < static_cast<size_t>(stopAt); ++iROfCount) { - auto& rof = (*rofs)[iROfCount]; - o2::its::ROframe frame(iROfCount); // to get meaningful roframeId - std::cout << "ROframe: " << iROfCount << std::endl; - - auto it = pattIt; - int nclUsed = o2::its::ioutils::loadROFrameData(rof, frame, clSpan, pattIt, dict, labels); - - std::array<float, 3> total{0.f, 0.f, 0.f}; - o2::its::ROframe* eventptr = &frame; - - // debug - vertexer.setDebugTrackletSelection(); - // vertexer.setDebugLines(); // Handle with care, takes very long - vertexer.setDebugCombinatorics(); - vertexer.setDebugSummaryLines(); - vertexer.setDebugCentroidsHistograms(); - // \debug - - total[0] = vertexer.evaluateTask(&o2::its::Vertexer::initialiseVertexer, "Vertexer initialisation", std::cout, eventptr); - // total[1] = vertexer.evaluateTask(&o2::its::Vertexer::findTrivialMCTracklets, "Trivial Tracklet finding", std::cout); // If enable this, comment out the validateTracklets - total[1] = vertexer.evaluateTask(&o2::its::Vertexer::findTracklets, "Tracklet finding", std::cout); -#ifdef _ALLOW_DEBUG_TREES_ITS_ - if (useMCcheck) { - vertexer.evaluateTask(&o2::its::Vertexer::filterMCTracklets, "MC tracklets filtering", std::cout); - } -#endif - total[2] = vertexer.evaluateTask(&o2::its::Vertexer::validateTracklets, "Adjacent tracklets validation", std::cout); - // In case willing to use the histogram-based CPU vertexer - // total[3] = vertexer.evaluateTask(&o2::its::Vertexer::findHistVertices, "Vertex finding with histograms", std::cout); - total[3] = vertexer.evaluateTask(&o2::its::Vertexer::findVertices, "Vertex finding", std::cout); - - std::vector<Vertex> vertITS = vertexer.exportVertices(); - const size_t numVert = vertITS.size(); - foundVerticesBenchmark.Fill(static_cast<float>(iROfCount), static_cast<float>(numVert)); - verticesITS->swap(vertITS); - // // TODO: get vertexer postion form MC truth - // - timeBenchmark.Fill(total[0], total[1], total[2], total[3], total[0] + total[1] + total[2] + total[3]); - outTree.Fill(); - } - - outputfile->cd(); - outTree.Write(); - foundVerticesBenchmark.Write(); - timeBenchmark.Write(); - outputfile->Close(); - return 0; -} diff --git a/macro/run_trac_ca_its.C b/macro/run_trac_ca_its.C index b29671c2772b7..90c99753f8e18 100644 --- a/macro/run_trac_ca_its.C +++ b/macro/run_trac_ca_its.C @@ -3,6 +3,7 @@ #include <string> #include <chrono> #include <iostream> +#include <fstream> #include <TChain.h> #include <TFile.h> @@ -27,13 +28,16 @@ #include "ITSBase/GeometryTGeo.h" +#include "DataFormatsITSMFT/CompCluster.h" #include "ITStracking/ROframe.h" #include "ITStracking/IOUtils.h" +#include "ITStracking/TimeFrame.h" #include "ITStracking/Tracker.h" #include "ITStracking/TrackerTraitsCPU.h" #include "ITStracking/Vertexer.h" #include "MathUtils/Utils.h" +#include "DetectorsBase/Propagator.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -53,23 +57,19 @@ using o2::its::TrackingParameters; using Vertex = o2::dataformats::Vertex<o2::dataformats::TimeStamp<int>>; using MCLabCont = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; -void run_trac_ca_its(std::string path = "./", +void run_trac_ca_its(bool cosmics = false, + bool useLUT = true, + std::string path = "./", std::string outputfile = "o2trac_its.root", std::string inputClustersITS = "o2clus_its.root", std::string dictfile = "", + std::string matLUTFile = "matbud.root", std::string inputGRP = "o2sim_grp.root") { - gSystem->Load("libO2ITStracking.so"); + gSystem->Load("libO2ITStracking"); - //std::unique_ptr<GPUReconstruction> rec(GPUReconstruction::CreateInstance()); - std::unique_ptr<GPUReconstruction> rec(GPUReconstruction::CreateInstance("CUDA", true)); // for GPU with CUDA - auto* chainITS = rec->AddChain<GPUChainITS>(); - rec->Init(); - - o2::its::Tracker tracker(chainITS->GetITSTrackerTraits()); - //o2::its::Tracker tracker(new o2::its::TrackerTraitsCPU()); - o2::its::ROframe event(0); + o2::its::ROframe event(0, 7); if (path.back() != '/') { path += '/'; @@ -87,11 +87,12 @@ void run_trac_ca_its(std::string path = "./", LOG(FATAL) << "Failed to load ma"; } double origD[3] = {0., 0., 0.}; - tracker.setBz(field->getBz(origD)); + + // bool isITS = grp->isDetReadOut(o2::detectors::DetID::ITS); if (!isITS) { - LOG(WARNING) << "ITS is not in the readoute"; + LOG(WARNING) << "ITS is not in the readout"; return; } bool isContITS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS); @@ -143,7 +144,7 @@ void run_trac_ca_its(std::string path = "./", o2::itsmft::TopologyDictionary dict; if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } std::ifstream file(dictfile.c_str()); if (file.good()) { @@ -178,26 +179,76 @@ void run_trac_ca_its(std::string path = "./", o2::its::VertexerTraits* traits = o2::its::createVertexerTraits(); o2::its::Vertexer vertexer(traits); + o2::its::VertexingParameters parameters; + parameters.phiCut = 0.005f; + parameters.tanLambdaCut = 0.002f; + vertexer.setParameters(parameters); + int roFrameCounter{0}; std::vector<double> ncls; std::vector<double> time; - std::vector<TrackingParameters> trackParams(3); - trackParams[0].TrackletMaxDeltaPhi = 0.05f; - trackParams[1].TrackletMaxDeltaPhi = 0.1f; - trackParams[2].MinTrackLength = 4; - trackParams[2].TrackletMaxDeltaPhi = 0.3; - - std::vector<MemoryParameters> memParams(3); - - tracker.setParameters(memParams, trackParams); + std::vector<TrackingParameters> trackParams(1); + std::vector<MemoryParameters> memParams(1); + if (cosmics) { + trackParams[0].MinTrackLength = 3; + trackParams[0].TrackletMaxDeltaPhi = o2::its::constants::math::Pi * 0.5f; + for (int iLayer = 0; iLayer < o2::its::constants::its2::TrackletsPerRoad; iLayer++) { + trackParams[0].TrackletMaxDeltaZ[iLayer] = o2::its::constants::its2::LayersZCoordinate()[iLayer + 1]; + memParams[0].TrackletsMemoryCoefficients[iLayer] = 0.5f; + // trackParams[0].TrackletMaxDeltaZ[iLayer] = 10.f; + } + for (int iLayer = 0; iLayer < o2::its::constants::its2::CellsPerRoad; iLayer++) { + trackParams[0].CellMaxDCA[iLayer] = 10000.f; //cm + trackParams[0].CellMaxDeltaZ[iLayer] = 10000.f; //cm + memParams[0].CellsMemoryCoefficients[iLayer] = 0.001f; + } + } else { + // PbPb tracking params + // ---- + // trackParams.resize(3); + // trackParams[0].TrackletMaxDeltaPhi = 0.05f; + // trackParams[0].DeltaROF = 0; + // trackParams[1].CopyCuts(trackParams[0], 2.); + // trackParams[1].DeltaROF = 0; + // trackParams[2].CopyCuts(trackParams[1], 2.); + // trackParams[2].DeltaROF = 1; + // trackParams[2].MinTrackLength = 4; + // memParams.resize(3); + // --- + // Uncomment for pp + trackParams.resize(2); + std::array<const float, 5> kmaxDCAxy1 = {1.f * 2.0, 0.4f * 2.0, 0.4f * 2.0, 2.0f * 2.0, 3.f * 2.0}; + std::array<const float, 5> kmaxDCAz1 = {1.f * 2.0, 0.4f * 2.0, 0.4f * 2.0, 2.0f * 2.0, 3.f * 2.0}; + std::array<const float, 4> kmaxDN1 = {0.005f * 2.0, 0.0035f * 2.0, 0.009f * 2.0, 0.03f * 2.0}; + std::array<const float, 4> kmaxDP1 = {0.02f * 2.0, 0.005f * 2.0, 0.006f * 2.0, 0.007f * 2.0}; + std::array<const float, 6> kmaxDZ1 = {1.f * 2.0, 1.f * 2.0, 2.0f * 2.0, 2.0f * 2.0, 2.0f * 2.0, 2.0f * 2.0}; + const float kDoublTanL1 = 0.05f * 5.; + const float kDoublPhi1 = 0.2f * 5.; + trackParams[1].MinTrackLength = 4; + trackParams[1].TrackletMaxDeltaPhi = 0.3; + trackParams[1].CellMaxDeltaPhi = 0.2 * 2; + trackParams[1].CellMaxDeltaTanLambda = 0.05 * 2; + std::copy(kmaxDZ1.begin(), kmaxDZ1.end(), trackParams[1].TrackletMaxDeltaZ.begin()); + std::copy(kmaxDCAxy1.begin(), kmaxDCAxy1.end(), trackParams[1].CellMaxDCA.begin()); + std::copy(kmaxDCAz1.begin(), kmaxDCAz1.end(), trackParams[1].CellMaxDeltaZ.begin()); + std::copy(kmaxDP1.begin(), kmaxDP1.end(), trackParams[1].NeighbourMaxDeltaCurvature.begin()); + std::copy(kmaxDN1.begin(), kmaxDN1.end(), trackParams[1].NeighbourMaxDeltaN.begin()); + memParams.resize(2); + // --- + } int currentEvent = -1; gsl::span<const unsigned char> patt(patterns->data(), patterns->size()); auto pattIt = patt.begin(); auto clSpan = gsl::span(cclusters->data(), cclusters->size()); + o2::its::TimeFrame tf; + gsl::span<o2::itsmft::ROFRecord> rofspan(*rofs); + tf.loadROFrameData(rofspan, clSpan, pattIt, dict, labels); + pattIt = patt.begin(); + int rofId{0}; for (auto& rof : *rofs) { auto start = std::chrono::high_resolution_clock::now(); @@ -206,10 +257,11 @@ void run_trac_ca_its(std::string path = "./", vertexer.initialiseVertexer(&event); vertexer.findTracklets(); - // vertexer.filterMCTracklets(); // to use MC check vertexer.validateTracklets(); vertexer.findVertices(); std::vector<Vertex> vertITS = vertexer.exportVertices(); + rofId++; + tf.addPrimaryVertices(vertITS); auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the vtxROF.setFirstEntry(vertices.size()); // dedicated ROFRecord vtxROF.setNEntries(vertITS.size()); @@ -219,23 +271,44 @@ void run_trac_ca_its(std::string path = "./", if (!vertITS.empty()) { // Using only the first vertex in the list - std::cout << " - Reconstructed vertexer: x = " << vertITS[0].getX() << " y = " << vertITS[0].getY() << " x = " << vertITS[0].getZ() << std::endl; + std::cout << " - Reconstructed vertex: x = " << vertITS[0].getX() << " y = " << vertITS[0].getY() << " x = " << vertITS[0].getZ() << std::endl; event.addPrimaryVertex(vertITS[0].getX(), vertITS[0].getY(), vertITS[0].getZ()); } else { std::cout << " - Vertex not reconstructed, tracking skipped" << std::endl; } trackClIdx.clear(); tracksITS.clear(); - tracker.clustersToTracks(event); - auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> diff_t{end - start}; ncls.push_back(event.getTotalClusters()); time.push_back(diff_t.count()); + roFrameCounter++; + } + tf.printVertices(); + + o2::its::Tracker tracker(new o2::its::TrackerTraitsCPU(&tf)); + if (useLUT) { + auto* lut = o2::base::MatLayerCylSet::loadFromFile(matLUTFile); + o2::base::Propagator::Instance()->setMatLUT(lut); + } else { + tracker.setCorrType(o2::base::PropagatorImpl<float>::MatCorrType::USEMatCorrTGeo); + } + + if (tracker.isMatLUT()) { + LOG(INFO) << "Loaded material LUT from " << matLUTFile; + } else { + LOG(INFO) << "Material LUT " << matLUTFile << " file is absent, only TGeo can be used"; + } + + tracker.setBz(field->getBz(origD)); + tracker.setParameters(memParams, trackParams); + tracker.clustersToTracks(); + //-------- init lookuptable --------// - tracks.swap(tracker.getTracks()); - for (auto& trc : tracks) { + for (int iROF{0}; iROF < tf.getNrof(); ++iROF) { + tracksITS.clear(); + for (auto& trc : tf.getTracks(iROF)) { trc.setFirstClusterEntry(trackClIdx.size()); // before adding tracks, create final cluster indices int ncl = trc.getNumberOfClusters(); for (int ic = 0; ic < ncl; ic++) { @@ -243,15 +316,13 @@ void run_trac_ca_its(std::string path = "./", } tracksITS.emplace_back(trc); } - - trackLabels = tracker.getTrackLabels(); /// FIXME: assignment ctor is not optimal. + trackLabels = tf.getTracksLabel(iROF); /// FIXME: assignment ctor is not optimal. outTree.Fill(); - roFrameCounter++; } outFile.cd(); outTree.Write(); - outFile.Close(); + // outFile.Close(); TGraph* graph = new TGraph(ncls.size(), ncls.data(), time.data()); graph->SetMarkerStyle(20); diff --git a/macro/run_trac_its.C b/macro/run_trac_its.C index d1272e1df3445..5a8ab1488a48a 100644 --- a/macro/run_trac_its.C +++ b/macro/run_trac_its.C @@ -123,7 +123,7 @@ void run_trac_its(std::string path = "./", std::string outputfile = "o2trac_its. o2::itsmft::TopologyDictionary dict; if (dictfile.empty()) { - dictfile = o2::base::NameConf::getDictionaryFileName(o2::detectors::DetID::ITS, "", ".bin"); + dictfile = o2::base::NameConf::getAlpideClusterDictionaryFileName(o2::detectors::DetID::ITS, "", "bin"); } std::ifstream file(dictfile.c_str()); if (file.good()) { @@ -166,7 +166,7 @@ void run_trac_its(std::string path = "./", std::string outputfile = "o2trac_its. o2::its::VertexerTraits vertexerTraits; o2::its::Vertexer vertexer(&vertexerTraits); - o2::its::ROframe event(0); + o2::its::ROframe event(0, 7); gsl::span<const unsigned char> patt(patterns->data(), patterns->size()); auto pattIt = patt.begin(); diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt index 38a4727686202..628f9e895f6ef 100644 --- a/packaging/CMakeLists.txt +++ b/packaging/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include(CPack) diff --git a/packaging/O2Config.cmake b/packaging/O2Config.cmake index deeb63d7dc2c4..abc464051c0eb 100644 --- a/packaging/O2Config.cmake +++ b/packaging/O2Config.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include("${CMAKE_CURRENT_LIST_DIR}/O2Dependencies.cmake") diff --git a/prodtests/CMakeLists.txt b/prodtests/CMakeLists.txt index 1401750c63abb..820faca110ae5 100644 --- a/prodtests/CMakeLists.txt +++ b/prodtests/CMakeLists.txt @@ -1,14 +1,19 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. -install(PROGRAMS sim_performance_test.sh sim_challenge.sh check_embedding_pileup.sh produce_QEDhits.sh - full_system_test.sh +install(PROGRAMS sim_performance_test.sh sim_challenge.sh check_embedding_pileup.sh produce_QEDhits.sh + full_system_test.sh full_system_test_ci_extra_tests.sh DESTINATION prodtests) +install(DIRECTORY full-system-test + DESTINATION prodtests + PATTERN * + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) diff --git a/prodtests/full-system-test/README.md b/prodtests/full-system-test/README.md new file mode 100644 index 0000000000000..dbaa9ee79eceb --- /dev/null +++ b/prodtests/full-system-test/README.md @@ -0,0 +1,89 @@ +<!-- doxy +\page refprodtestsfull-system-test Full system test configuration and scripts +/doxy --> + +## Full system test overview and quickstart guide + +The full system test consists of 2 parts (detailed below): +* The time frame generation part, which runs the simulation, digitization, raw conversion, and other misc tasks. +* A DPL workflow, which can run the synchronous and the asynchronous reconstruction. + +The relevant scripts are `/prodtests/full_system_test.sh` and all scripts in `/prodtests/full-system-test`. +Note that by default the `full_system_test.sh` script will do both, run the generation and then the sysc and the async workflow. +This is only a quickstart guide, for more information see https://alice.its.cern.ch/jira/browse/O2-1492. + +In order to run the full system test, you need to run in the O2sim environment (`alienv enter O2sim/latest`): +``` +NEvents=[N] NEventsQED=[NQ] SHMSIZE=[S] TPCTRACKERSCRATCHMEMORY=[ST] $O2_ROOT/prodtests/full_system_test.sh +``` + +Parameters are set via environment variables. The 2 most important and mandatory parameters are `NEvents` and `NEventsQED`, which define how many collisions are in the timeframe, and how many collisions are simulated for the QED background. +For simulating larger datasets, some memory sizes must be increased over the default, most importantly `SHMSIZE` and `TPCTRACKERSCRATCHMEMORY`. +More options are available and documented in the script itself. + +For a quick run of a timeframe with 5 events (depending on yous system it should take 3 to 0 minutes), run +``` +NEvents=5 NEventsQED=100 $O2_ROOT/prodtests/full_system_test.sh +``` + +For a simulation of a full 128 orbit time frame, run +``` +NEvents=650 NEventsQED=30000 SHMSIZE=128000000000 TPCTRACKERSCRATCHMEMORY=30000000000 $O2_ROOT/prodtests/full_system_test.sh +``` + +## Full system test time frame generation part + +The generation part (in `prodtests/full_system_test.sh` runs the following steps: +* Simulate the QED collisions +* Simulate the collisions +* Digitize all data, by default split between in 2 phases for TRD and non-TRD to reduce the memory footprint (configured via `$SPLITTRDDIGI`). +* Run TRD trap simulation +* Optionally create optimized dictionaries for ITS and MFT +* Run digits 2 raw conversion. +* By default, afterwards it will also run the sync and async DPL workflows (configured via `$DISABLE_PROCESSING`). + +The `prodtests/full_system_test.sh` uses `Utilities/Tools/jobutils.sh` for running the jobs, which creates a log file for each step, and which will automatically skip steps that have already succeeded if the test is rerun in the current folder. I.e. if you break the FST or it failed at some point, you can rerun the same command line and it will continue after the last successful step. See `Utilities/Tools/jobutils.sh` for details. + +Note that by default, the generation produces raw files, which can be consumed by the `raw-file-reader-workflow` and by `o2-readout-exe`. +The files can be converted into timeframes files readable by the StfBuilder as described in https://alice.its.cern.ch/jira/browse/O2-1492. + +## Full system test DPL-workflow configuration and scripts + +The full system test workflow scripts consist of 3 shell scripts: +* `dpl-workflow.sh` : The main script that runs the dpl-workflow for the reconstruction. + It can read the input either internally, or receive it externally by one of the others. +* `raw-reader.sh` : Runs the `o2-raw-file-reader` to read the raw files as external input to `dpl-workflow.sh`. +* `datadistribution.sh` : Run the `StfBuilder` to read time frame files as external input to `dpl-workflow.sh`. + +One can either run the `dpl-workflow.sh` standalone (with `EXTINPUT=0`) or in parallel with one of the other scripts in separate shells (with `EXTINPUT=1`) + +In addition, there is the shared `setenv.sh` script which sets default configuration options, and there is the additional benchmark script: +* `start_tmux.sh` : This starts the full test in the configuration for the EPN with 2 NUMA domains, 512 GB RAM, 8 GPUs. + It will run tmux with 3 sessions, running twice the `dpl-workflow.sh` and once one of the external input scripts (selected via `dd` and `rr` command line option). + * Please note that `start_tmux.sh` overrides several of the environment options (see below) with the defaults for the EPN. + The only relevant options for `start_tmux.sh` should be `TFDELAY` and `GPUMEMSIZE`. + * Note also that while `dpl-workflow.sh` is a generic flexible script that can be used for actual operation, `start_tmux.sh` is a benchmark script to demonstrate how the full workflow is supposed to run on the EPN. + It is meant for standalone tests and not to really start the actual processing on the EPN. + +The `dpl-workflow.sh` can run both the synchronous and the asynchronous workflow, selected via the `SYNCMODE` option (see below), but note the following constraints. +* By default, it will run the full chain (EPN + FLP parts) such that it can operate as a full standalone benchmark processing simulated raw data. +* In order to run only the EPN part (skipping the steps that will run on the FLP), an `EPNONLY` option will be added later. + +All settings are configured via environment variables. +The default settings (if no env variable is exported) are defined in `setenv.sh` which is sourced by all other scripts. +(Please note that `start_tmux.sh` overrides a couple of options with EPN defaults). +The environment variables are documented here: https://github.com/AliceO2Group/O2DataProcessing/blob/dev/common/README.md + +## Files produced / required by the full system test + +The full system test can use the following input files: +* Material budget: `matbud.root` with the material budget (used if available by the workflows to speed up material queries). +* CTF ANS dictionaries: `ctf_dictionary.root` (if `CREATECTFDICT=0` is set). +* ITS and MFT pattern dictionaries: `ITSdictionary.bin` and `MFTdictionary.bin` can be provided externally, or they can be produced automatically if `GENERATE_ITSMFT_DICTIONARIES=1` is set. + +The full system test produces the following output: +* QED simulation output in the folder `qed`. +* Normal simulation output (as `o2-sim`). +* Digits from `o2-sim-digitizer-workflow` and TRD tracklets. +* Depending on the options mentioned above, `ctf_dictionary.root` and `ITSdictionary.bin` / `MFTdictionary.bin`. +* RAW files in `raw/[DETECTOR_NAME]` diff --git a/prodtests/full-system-test/async_tmux.sh b/prodtests/full-system-test/async_tmux.sh new file mode 100755 index 0000000000000..81c40081d76ea --- /dev/null +++ b/prodtests/full-system-test/async_tmux.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +MYDIR="$(dirname $(readlink -f $0))" +source $MYDIR/setenv.sh + +# This sets up the hardcoded configuration to run the async full system test workflow on the EPN +if [ $GPUTYPE == "CPU" ]; then + export SHMSIZE=$(( 112 << 30 )) +else + export SHMSIZE=$(( 144 << 30 )) +fi +export NUMAGPUIDS=1 +export OPTIMIZED_PARALLEL_ASYNC=1 +export CTFINPUT=1 +export SHMTHROW=0 +export SEVERITY=error +export GPU_NUM_MEM_REG_CALLBACKS=2 + +if [ ! -f matbud.root ]; then + echo matbud.root missing + exit 1 +fi + +if [ "0$FST_TMUX_NOWAIT" != "01" ]; then + ENDCMD="echo END; sleep 1000" +fi + +if [ "0$FST_TMUX_LOGPREFIX" != "0" ]; then + LOGCMD0=" &> ${FST_TMUX_LOGPREFIX}_0.log" + LOGCMD1=" &> ${FST_TMUX_LOGPREFIX}_1.log" +fi + +export TFDELAY=$(($TFDELAY * 2)) +export NTIMEFRAMES=$((($NTIMEFRAMES + 1) / 2)) + +rm -f /dev/shm/*fmq* + +tmux \ + new-session "sleep 0; NUMAID=0 $MYDIR/dpl-workflow.sh $LOGCMD0; $ENDCMD" \; \ + split-window "sleep 2; NUMAID=1 $MYDIR/dpl-workflow.sh $LOGCMD1; $ENDCMD" \; \ + select-layout even-vertical diff --git a/prodtests/full-system-test/convert-raw-to-tf-file.sh b/prodtests/full-system-test/convert-raw-to-tf-file.sh new file mode 100755 index 0000000000000..04f6eeec93940 --- /dev/null +++ b/prodtests/full-system-test/convert-raw-to-tf-file.sh @@ -0,0 +1,64 @@ +#!/bin/bash +echo Running raw file to timeframe converter + +if [ `which StfBuilder 2> /dev/null | wc -l` == "0" ]; then + echo ERROR: StfBuilder is not in the path + exit 1 +fi +if [ `which o2-readout-exe 2> /dev/null | wc -l` == "0" ]; then + echo ERROR: o2-readout-exe is not in the path + exit 1 +fi + +pushd raw + +rm -Rf timeframe rdo_TF.cfg *.log +if [ `ls | grep -v "^[A-Z0-9]\{3\}\$" | wc -l` != "0" ]; then + echo Unexpected data in raw folder + exit 1 +fi + +echo Generating readout config +$O2_ROOT/prodtests/full-system-test/gen_rdo_cfg.sh 128 * + +echo Starting StfBuilder +StfBuilder --id=stfb --detector-rdh=6 --detector-subspec=feeid --stand-alone --channel-config "name=readout,type=pull,method=connect,address=ipc:///tmp/readout-to-datadist-0,transport=shmem,rateLogging=1" --data-sink-dir=`pwd` --data-sink-sidecar --data-sink-enable --control=static &> stfbuilder.log & +STF_PID=$! +echo StfBuilder PID: $STF_PID, waiting 15 seconds +sleep 15 + +echo Starting Readout +export O2_INFOLOGGER_OPTIONS="floodProtection=0" +export O2_INFOLOGGER_MODE=stdout +o2-readout-exe file:rdo_TF.cfg &> readout.log & +RD_PID=$! +echo Readout PID: $RD_PID + +echo Waiting for data to arrive +while [ `ls run*_20*/run*_tf00000001.tf 2> /dev/null | wc -l` == "0" ]; do + sleep 1 +done +echo Data is arriving, waiting 20 seconds to be sure +sleep 20 + +echo Killing Readout +kill $RD_PID + +sleep 10 +echo Killing StfBuilder +kill $STF_PID + +sleep 10 +if [ -d /proc/$RD_PID ]; then + kill -9 $RD_PID +fi +if [ -d /proc/$STF_PID ]; then + kill -9 $STF_PID +fi + +mv run*_20* timeframe +rm -f *.log rdo_TF.cfg + +echo Done + +popd diff --git a/prodtests/full-system-test/create_full_system_pipeline.py b/prodtests/full-system-test/create_full_system_pipeline.py new file mode 100755 index 0000000000000..f8493f6723f4f --- /dev/null +++ b/prodtests/full-system-test/create_full_system_pipeline.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# +# A script producing a consistent full-system-test workflow. +# Python used for convenient json handling but this is completely up to the workflow writer. +# +from os import environ +import json + +workflow={} +workflow['stages'] = [] + +taskcounter=0 +def Task(name='', needs=[], tf=-1, cmd='a', cwd='./', lab=[]): + global taskcounter + taskcounter = taskcounter + 1 + t = { 'name': name, 'cmd': cmd, 'needs': needs, 'resources': { 'cpu': -1 , 'mem': -1 }, 'timeframe' : tf, 'labels' : lab, 'cwd' : cwd } + workflow['stages'].append(t) + return t + +# ---- qed transport task ------- +QED=Task(name='qedsim', lab=["QED", "SIM"], cwd='qed') +QED['cmd']='o2-sim --seed $O2SIMSEED -j $NJOBS -n$NEventsQED -m PIPE ITS MFT FT0 FV0 FDD -g extgen --configKeyValues \"GeneratorExternal.fileName=$O2_ROOT/share/Generators/external/QEDLoader.C;QEDGenParam.yMin=-7;QEDGenParam.yMax=7;QEDGenParam.ptMin=0.001;QEDGenParam.ptMax=1.;Diamond.width[2]=6.\"' + +QED2HAD=Task(name='qed2had', lab=["QED", "SIM"], cwd='qed', needs=["qedsim"]) +QED2HAD['cmd']='PbPbXSec="8." ; awk "BEGIN {printf \\"%.2f\\",`grep xSectionQED qedgenparam.ini | cut -d\'=\' -f 2`/$PbPbXSec}" > qed2had.log' +#echo "Obtained ratio of QED to hadronic x-sections = $QED2HAD" >> qedsim.log + +# --- signal sim and digitization ---- +SIM=Task(name="sim", lab=["SIM"]) +SIM['cmd']='o2-sim --seed $O2SIMSEED -n $NEvents --skipModules ZDC --configKeyValues "Diamond.width[2]=6." -g pythia8hi -j $NJOBS' + +DIGI1=Task(name="digi", lab=["DIGI"], needs=["sim", "qed2had"]) +DIGI1['cmd']='QED2HAD=`cat qed/qed2had.log`; echo ${QED2HAD}; o2-sim-digitizer-workflow -n $NEvents --simPrefixQED qed/o2sim --qed-x-section-ratio ${QED2HAD} ${NOMCLABELS} --firstOrbit 0 --firstBC 0 --skipDet TRD --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT}' + +# the dependency on digi is because of collisioncontext +DIGI2=Task(name='digiTRD', lab=["DIGI"], needs=["sim", "digi"]) +DIGI2['cmd']='o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --firstOrbit 0 --firstBC 0 --onlyDet TRD --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "TRDSimParams.digithreads=${NJOBS}"' + +allrawtasknames=[] +def RAWTask(name, command): + allrawtasknames.append(name) + return Task(name=name, cmd=command, lab=["RAW"], needs=["digi"]) + +ITSRAW=RAWTask('itsraw', 'o2-its-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/ITS') +MFTRAW=RAWTask('mftraw', 'o2-mft-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/MFT') +FT0RAW=RAWTask('ft0raw', 'o2-ft0-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/FT0') +FV0RAW=RAWTask('fv0raw', 'o2-fv0-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/FV0') +FDDRAW=RAWTask('fddraw', 'o2-fdd-digit2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/FDD') +TPCRAW=RAWTask('tpcraw', 'o2-tpc-digits-to-rawzs --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -i tpcdigits.root -o raw/TPC') +TOFRAW=RAWTask('tofraw', 'o2-tof-reco-workflow ${GLOBALDPLOPT} --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" --output-type raw --tof-raw-outdir raw/TOF') +TOFRAW=RAWTask('midraw', 'o2-mid-digits-to-raw-workflow ${GLOBALDPLOPT} --mid-raw-outdir raw/MID --mid-raw-perlink --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\"') +EMCRAW=RAWTask('emcraw', 'o2-emcal-rawcreator --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/EMC') +PHSRAW=RAWTask('phsraw', 'o2-phos-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/PHS') +CPVRAW=RAWTask('cpvraw', 'o2-cpv-digi2raw --file-for link --configKeyValues \"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0\" -o raw/CPV') + +# make configuration -> this depends on all previous raws +Task('rawAllConfig', cmd='cat raw/*/*.cfg > rawAll.cfg', needs=allrawtasknames, lab=["RAW"]) + +# now emit all possible versions of the dpl workflow (WITHGPU, NOGPU, AYNC) +RECO_ENV={ "WITHGPU": { "CREATECTFDICT":"0", + "GPUTYPE":"CUDA", + "GPUMEMSIZE":"6000000000", + "HOSTMEMSIZE":"1000000000", + "SYNCMODE":"1", + "CTFINPUT":"0", + "SAVECTF":"0" }, + "ASYNC": { + "CREATECTFDICT":"0", + "GPUTYPE":"CPU", + "SYNCMODE":"0", + "HOSTMEMSIZE":"$TPCTRACKERSCRATCHMEMORY", + "CTFINPUT":"1", + "SAVECTF":"0" + }, + "NOGPU": { + "CREATECTFDICT":"1", + "GPUTYPE":"CPU", + "SYNCMODE":"0", + "HOSTMEMSIZE":"$TPCTRACKERSCRATCHMEMORY", + "CTFINPUT":"0", + "SAVECTF":"1" + } +} + +for stage in [ "NOGPU", "WITHGPU", "ASYNC" ]: + t=Task(name='reco_' + stage, needs=['rawAllConfig'], lab=["RECO"]) + t['env']=RECO_ENV[stage] + precommand="" + if stage=="NOGPU": + precommand="rm -f ctf_dictionary.root;" + t['cmd']=precommand + "$O2_ROOT/prodtests/full-system-test/dpl-workflow.sh" + +def trimString(cmd): + return ' '.join(cmd.split()) + +# insert taskwrapper stuff +for s in workflow['stages']: + s['cmd']='. ${O2_ROOT}/share/scripts/jobutils.sh; taskwrapper ' + s['name']+'.log \'' + s['cmd'] + '\'' + +# remove whitespaces etc +for s in workflow['stages']: + s['cmd']=trimString(s['cmd']) + +# write workflow to json +workflowfile='workflow.json' +with open(workflowfile, 'w') as outfile: + json.dump(workflow, outfile, indent=2) + +exit (0) diff --git a/prodtests/full-system-test/cru_mapping.txt b/prodtests/full-system-test/cru_mapping.txt new file mode 100644 index 0000000000000..82cf0335c9447 --- /dev/null +++ b/prodtests/full-system-test/cru_mapping.txt @@ -0,0 +1,720 @@ +TPC/cru0_0.raw alio2-cr1-flp070 +TPC/cru1_0.raw alio2-cr1-flp069 +TPC/cru2_0.raw alio2-cr1-flp070 +TPC/cru3_0.raw alio2-cr1-flp069 +TPC/cru4_0.raw alio2-cr1-flp072 +TPC/cru5_0.raw alio2-cr1-flp071 +TPC/cru6_0.raw alio2-cr1-flp072 +TPC/cru7_0.raw alio2-cr1-flp071 +TPC/cru8_0.raw alio2-cr1-flp072 +TPC/cru9_0.raw alio2-cr1-flp071 +TPC/cru10_0.raw alio2-cr1-flp002 +TPC/cru11_0.raw alio2-cr1-flp001 +TPC/cru12_0.raw alio2-cr1-flp002 +TPC/cru13_0.raw alio2-cr1-flp001 +TPC/cru14_0.raw alio2-cr1-flp004 +TPC/cru15_0.raw alio2-cr1-flp003 +TPC/cru16_0.raw alio2-cr1-flp004 +TPC/cru17_0.raw alio2-cr1-flp003 +TPC/cru18_0.raw alio2-cr1-flp004 +TPC/cru19_0.raw alio2-cr1-flp003 +TPC/cru20_0.raw alio2-cr1-flp006 +TPC/cru21_0.raw alio2-cr1-flp005 +TPC/cru22_0.raw alio2-cr1-flp006 +TPC/cru23_0.raw alio2-cr1-flp005 +TPC/cru24_0.raw alio2-cr1-flp008 +TPC/cru25_0.raw alio2-cr1-flp007 +TPC/cru26_0.raw alio2-cr1-flp008 +TPC/cru27_0.raw alio2-cr1-flp007 +TPC/cru28_0.raw alio2-cr1-flp008 +TPC/cru29_0.raw alio2-cr1-flp007 +TPC/cru30_0.raw alio2-cr1-flp010 +TPC/cru31_0.raw alio2-cr1-flp009 +TPC/cru32_0.raw alio2-cr1-flp010 +TPC/cru33_0.raw alio2-cr1-flp009 +TPC/cru34_0.raw alio2-cr1-flp012 +TPC/cru35_0.raw alio2-cr1-flp011 +TPC/cru36_0.raw alio2-cr1-flp012 +TPC/cru37_0.raw alio2-cr1-flp011 +TPC/cru38_0.raw alio2-cr1-flp012 +TPC/cru39_0.raw alio2-cr1-flp011 +TPC/cru40_0.raw alio2-cr1-flp014 +TPC/cru41_0.raw alio2-cr1-flp013 +TPC/cru42_0.raw alio2-cr1-flp014 +TPC/cru43_0.raw alio2-cr1-flp013 +TPC/cru44_0.raw alio2-cr1-flp016 +TPC/cru45_0.raw alio2-cr1-flp015 +TPC/cru46_0.raw alio2-cr1-flp016 +TPC/cru47_0.raw alio2-cr1-flp015 +TPC/cru48_0.raw alio2-cr1-flp016 +TPC/cru49_0.raw alio2-cr1-flp015 +TPC/cru50_0.raw alio2-cr1-flp018 +TPC/cru51_0.raw alio2-cr1-flp017 +TPC/cru52_0.raw alio2-cr1-flp018 +TPC/cru53_0.raw alio2-cr1-flp017 +TPC/cru54_0.raw alio2-cr1-flp020 +TPC/cru55_0.raw alio2-cr1-flp019 +TPC/cru56_0.raw alio2-cr1-flp020 +TPC/cru57_0.raw alio2-cr1-flp019 +TPC/cru58_0.raw alio2-cr1-flp020 +TPC/cru59_0.raw alio2-cr1-flp019 +TPC/cru60_0.raw alio2-cr1-flp022 +TPC/cru61_0.raw alio2-cr1-flp021 +TPC/cru62_0.raw alio2-cr1-flp022 +TPC/cru63_0.raw alio2-cr1-flp021 +TPC/cru64_0.raw alio2-cr1-flp024 +TPC/cru65_0.raw alio2-cr1-flp023 +TPC/cru66_0.raw alio2-cr1-flp024 +TPC/cru67_0.raw alio2-cr1-flp023 +TPC/cru68_0.raw alio2-cr1-flp024 +TPC/cru69_0.raw alio2-cr1-flp023 +TPC/cru70_0.raw alio2-cr1-flp026 +TPC/cru71_0.raw alio2-cr1-flp025 +TPC/cru72_0.raw alio2-cr1-flp026 +TPC/cru73_0.raw alio2-cr1-flp025 +TPC/cru74_0.raw alio2-cr1-flp028 +TPC/cru75_0.raw alio2-cr1-flp027 +TPC/cru76_0.raw alio2-cr1-flp028 +TPC/cru77_0.raw alio2-cr1-flp027 +TPC/cru78_0.raw alio2-cr1-flp028 +TPC/cru79_0.raw alio2-cr1-flp027 +TPC/cru80_0.raw alio2-cr1-flp030 +TPC/cru81_0.raw alio2-cr1-flp029 +TPC/cru82_0.raw alio2-cr1-flp030 +TPC/cru83_0.raw alio2-cr1-flp029 +TPC/cru84_0.raw alio2-cr1-flp032 +TPC/cru85_0.raw alio2-cr1-flp031 +TPC/cru86_0.raw alio2-cr1-flp032 +TPC/cru87_0.raw alio2-cr1-flp031 +TPC/cru88_0.raw alio2-cr1-flp032 +TPC/cru89_0.raw alio2-cr1-flp031 +TPC/cru90_0.raw alio2-cr1-flp034 +TPC/cru91_0.raw alio2-cr1-flp033 +TPC/cru92_0.raw alio2-cr1-flp034 +TPC/cru93_0.raw alio2-cr1-flp033 +TPC/cru94_0.raw alio2-cr1-flp036 +TPC/cru95_0.raw alio2-cr1-flp035 +TPC/cru96_0.raw alio2-cr1-flp036 +TPC/cru97_0.raw alio2-cr1-flp035 +TPC/cru98_0.raw alio2-cr1-flp036 +TPC/cru99_0.raw alio2-cr1-flp035 +TPC/cru100_0.raw alio2-cr1-flp038 +TPC/cru101_0.raw alio2-cr1-flp037 +TPC/cru102_0.raw alio2-cr1-flp038 +TPC/cru103_0.raw alio2-cr1-flp037 +TPC/cru104_0.raw alio2-cr1-flp040 +TPC/cru105_0.raw alio2-cr1-flp039 +TPC/cru106_0.raw alio2-cr1-flp040 +TPC/cru107_0.raw alio2-cr1-flp039 +TPC/cru108_0.raw alio2-cr1-flp040 +TPC/cru109_0.raw alio2-cr1-flp039 +TPC/cru110_0.raw alio2-cr1-flp042 +TPC/cru111_0.raw alio2-cr1-flp041 +TPC/cru112_0.raw alio2-cr1-flp042 +TPC/cru113_0.raw alio2-cr1-flp041 +TPC/cru114_0.raw alio2-cr1-flp044 +TPC/cru115_0.raw alio2-cr1-flp043 +TPC/cru116_0.raw alio2-cr1-flp044 +TPC/cru117_0.raw alio2-cr1-flp043 +TPC/cru118_0.raw alio2-cr1-flp044 +TPC/cru119_0.raw alio2-cr1-flp043 +TPC/cru120_0.raw alio2-cr1-flp046 +TPC/cru121_0.raw alio2-cr1-flp045 +TPC/cru122_0.raw alio2-cr1-flp046 +TPC/cru123_0.raw alio2-cr1-flp045 +TPC/cru124_0.raw alio2-cr1-flp048 +TPC/cru125_0.raw alio2-cr1-flp047 +TPC/cru126_0.raw alio2-cr1-flp048 +TPC/cru127_0.raw alio2-cr1-flp047 +TPC/cru128_0.raw alio2-cr1-flp048 +TPC/cru129_0.raw alio2-cr1-flp047 +TPC/cru130_0.raw alio2-cr1-flp050 +TPC/cru131_0.raw alio2-cr1-flp049 +TPC/cru132_0.raw alio2-cr1-flp050 +TPC/cru133_0.raw alio2-cr1-flp049 +TPC/cru134_0.raw alio2-cr1-flp052 +TPC/cru135_0.raw alio2-cr1-flp051 +TPC/cru136_0.raw alio2-cr1-flp052 +TPC/cru137_0.raw alio2-cr1-flp051 +TPC/cru138_0.raw alio2-cr1-flp052 +TPC/cru139_0.raw alio2-cr1-flp051 +TPC/cru140_0.raw alio2-cr1-flp054 +TPC/cru141_0.raw alio2-cr1-flp053 +TPC/cru142_0.raw alio2-cr1-flp054 +TPC/cru143_0.raw alio2-cr1-flp053 +TPC/cru144_0.raw alio2-cr1-flp056 +TPC/cru145_0.raw alio2-cr1-flp055 +TPC/cru146_0.raw alio2-cr1-flp056 +TPC/cru147_0.raw alio2-cr1-flp055 +TPC/cru148_0.raw alio2-cr1-flp056 +TPC/cru149_0.raw alio2-cr1-flp055 +TPC/cru150_0.raw alio2-cr1-flp058 +TPC/cru151_0.raw alio2-cr1-flp057 +TPC/cru152_0.raw alio2-cr1-flp058 +TPC/cru153_0.raw alio2-cr1-flp057 +TPC/cru154_0.raw alio2-cr1-flp060 +TPC/cru155_0.raw alio2-cr1-flp059 +TPC/cru156_0.raw alio2-cr1-flp060 +TPC/cru157_0.raw alio2-cr1-flp059 +TPC/cru158_0.raw alio2-cr1-flp060 +TPC/cru159_0.raw alio2-cr1-flp059 +TPC/cru160_0.raw alio2-cr1-flp062 +TPC/cru161_0.raw alio2-cr1-flp061 +TPC/cru162_0.raw alio2-cr1-flp062 +TPC/cru163_0.raw alio2-cr1-flp061 +TPC/cru164_0.raw alio2-cr1-flp064 +TPC/cru165_0.raw alio2-cr1-flp063 +TPC/cru166_0.raw alio2-cr1-flp064 +TPC/cru167_0.raw alio2-cr1-flp063 +TPC/cru168_0.raw alio2-cr1-flp064 +TPC/cru169_0.raw alio2-cr1-flp063 +TPC/cru170_0.raw alio2-cr1-flp066 +TPC/cru171_0.raw alio2-cr1-flp065 +TPC/cru172_0.raw alio2-cr1-flp066 +TPC/cru173_0.raw alio2-cr1-flp065 +TPC/cru174_0.raw alio2-cr1-flp068 +TPC/cru175_0.raw alio2-cr1-flp067 +TPC/cru176_0.raw alio2-cr1-flp068 +TPC/cru177_0.raw alio2-cr1-flp067 +TPC/cru178_0.raw alio2-cr1-flp068 +TPC/cru179_0.raw alio2-cr1-flp067 +TPC/cru180_0.raw alio2-cr1-flp074 +TPC/cru181_0.raw alio2-cr1-flp073 +TPC/cru182_0.raw alio2-cr1-flp074 +TPC/cru183_0.raw alio2-cr1-flp073 +TPC/cru184_0.raw alio2-cr1-flp076 +TPC/cru185_0.raw alio2-cr1-flp075 +TPC/cru186_0.raw alio2-cr1-flp076 +TPC/cru187_0.raw alio2-cr1-flp075 +TPC/cru188_0.raw alio2-cr1-flp076 +TPC/cru189_0.raw alio2-cr1-flp075 +TPC/cru190_0.raw alio2-cr1-flp078 +TPC/cru191_0.raw alio2-cr1-flp077 +TPC/cru192_0.raw alio2-cr1-flp078 +TPC/cru193_0.raw alio2-cr1-flp077 +TPC/cru194_0.raw alio2-cr1-flp080 +TPC/cru195_0.raw alio2-cr1-flp079 +TPC/cru196_0.raw alio2-cr1-flp080 +TPC/cru197_0.raw alio2-cr1-flp079 +TPC/cru198_0.raw alio2-cr1-flp080 +TPC/cru199_0.raw alio2-cr1-flp079 +TPC/cru200_0.raw alio2-cr1-flp082 +TPC/cru201_0.raw alio2-cr1-flp081 +TPC/cru202_0.raw alio2-cr1-flp082 +TPC/cru203_0.raw alio2-cr1-flp081 +TPC/cru204_0.raw alio2-cr1-flp084 +TPC/cru205_0.raw alio2-cr1-flp083 +TPC/cru206_0.raw alio2-cr1-flp084 +TPC/cru207_0.raw alio2-cr1-flp083 +TPC/cru208_0.raw alio2-cr1-flp084 +TPC/cru209_0.raw alio2-cr1-flp083 +TPC/cru210_0.raw alio2-cr1-flp086 +TPC/cru211_0.raw alio2-cr1-flp085 +TPC/cru212_0.raw alio2-cr1-flp086 +TPC/cru213_0.raw alio2-cr1-flp085 +TPC/cru214_0.raw alio2-cr1-flp088 +TPC/cru215_0.raw alio2-cr1-flp087 +TPC/cru216_0.raw alio2-cr1-flp088 +TPC/cru217_0.raw alio2-cr1-flp087 +TPC/cru218_0.raw alio2-cr1-flp088 +TPC/cru219_0.raw alio2-cr1-flp087 +TPC/cru220_0.raw alio2-cr1-flp090 +TPC/cru221_0.raw alio2-cr1-flp089 +TPC/cru222_0.raw alio2-cr1-flp090 +TPC/cru223_0.raw alio2-cr1-flp089 +TPC/cru224_0.raw alio2-cr1-flp092 +TPC/cru225_0.raw alio2-cr1-flp091 +TPC/cru226_0.raw alio2-cr1-flp092 +TPC/cru227_0.raw alio2-cr1-flp091 +TPC/cru228_0.raw alio2-cr1-flp092 +TPC/cru229_0.raw alio2-cr1-flp091 +TPC/cru230_0.raw alio2-cr1-flp094 +TPC/cru231_0.raw alio2-cr1-flp093 +TPC/cru232_0.raw alio2-cr1-flp094 +TPC/cru233_0.raw alio2-cr1-flp093 +TPC/cru234_0.raw alio2-cr1-flp096 +TPC/cru235_0.raw alio2-cr1-flp095 +TPC/cru236_0.raw alio2-cr1-flp096 +TPC/cru237_0.raw alio2-cr1-flp095 +TPC/cru238_0.raw alio2-cr1-flp096 +TPC/cru239_0.raw alio2-cr1-flp095 +TPC/cru240_0.raw alio2-cr1-flp098 +TPC/cru241_0.raw alio2-cr1-flp097 +TPC/cru242_0.raw alio2-cr1-flp098 +TPC/cru243_0.raw alio2-cr1-flp097 +TPC/cru244_0.raw alio2-cr1-flp100 +TPC/cru245_0.raw alio2-cr1-flp099 +TPC/cru246_0.raw alio2-cr1-flp100 +TPC/cru247_0.raw alio2-cr1-flp099 +TPC/cru248_0.raw alio2-cr1-flp100 +TPC/cru249_0.raw alio2-cr1-flp099 +TPC/cru250_0.raw alio2-cr1-flp102 +TPC/cru251_0.raw alio2-cr1-flp101 +TPC/cru252_0.raw alio2-cr1-flp102 +TPC/cru253_0.raw alio2-cr1-flp101 +TPC/cru254_0.raw alio2-cr1-flp104 +TPC/cru255_0.raw alio2-cr1-flp103 +TPC/cru256_0.raw alio2-cr1-flp104 +TPC/cru257_0.raw alio2-cr1-flp103 +TPC/cru258_0.raw alio2-cr1-flp104 +TPC/cru259_0.raw alio2-cr1-flp103 +TPC/cru260_0.raw alio2-cr1-flp106 +TPC/cru261_0.raw alio2-cr1-flp105 +TPC/cru262_0.raw alio2-cr1-flp106 +TPC/cru263_0.raw alio2-cr1-flp105 +TPC/cru264_0.raw alio2-cr1-flp108 +TPC/cru265_0.raw alio2-cr1-flp107 +TPC/cru266_0.raw alio2-cr1-flp108 +TPC/cru267_0.raw alio2-cr1-flp107 +TPC/cru268_0.raw alio2-cr1-flp108 +TPC/cru269_0.raw alio2-cr1-flp107 +TPC/cru270_0.raw alio2-cr1-flp110 +TPC/cru271_0.raw alio2-cr1-flp109 +TPC/cru272_0.raw alio2-cr1-flp110 +TPC/cru273_0.raw alio2-cr1-flp109 +TPC/cru274_0.raw alio2-cr1-flp112 +TPC/cru275_0.raw alio2-cr1-flp111 +TPC/cru276_0.raw alio2-cr1-flp112 +TPC/cru277_0.raw alio2-cr1-flp111 +TPC/cru278_0.raw alio2-cr1-flp112 +TPC/cru279_0.raw alio2-cr1-flp111 +TPC/cru280_0.raw alio2-cr1-flp114 +TPC/cru281_0.raw alio2-cr1-flp113 +TPC/cru282_0.raw alio2-cr1-flp114 +TPC/cru283_0.raw alio2-cr1-flp113 +TPC/cru284_0.raw alio2-cr1-flp116 +TPC/cru285_0.raw alio2-cr1-flp115 +TPC/cru286_0.raw alio2-cr1-flp116 +TPC/cru287_0.raw alio2-cr1-flp115 +TPC/cru288_0.raw alio2-cr1-flp116 +TPC/cru289_0.raw alio2-cr1-flp115 +TPC/cru290_0.raw alio2-cr1-flp118 +TPC/cru291_0.raw alio2-cr1-flp117 +TPC/cru292_0.raw alio2-cr1-flp118 +TPC/cru293_0.raw alio2-cr1-flp117 +TPC/cru294_0.raw alio2-cr1-flp120 +TPC/cru295_0.raw alio2-cr1-flp119 +TPC/cru296_0.raw alio2-cr1-flp120 +TPC/cru297_0.raw alio2-cr1-flp119 +TPC/cru298_0.raw alio2-cr1-flp120 +TPC/cru299_0.raw alio2-cr1-flp119 +TPC/cru300_0.raw alio2-cr1-flp122 +TPC/cru301_0.raw alio2-cr1-flp121 +TPC/cru302_0.raw alio2-cr1-flp122 +TPC/cru303_0.raw alio2-cr1-flp121 +TPC/cru304_0.raw alio2-cr1-flp124 +TPC/cru305_0.raw alio2-cr1-flp123 +TPC/cru306_0.raw alio2-cr1-flp124 +TPC/cru307_0.raw alio2-cr1-flp123 +TPC/cru308_0.raw alio2-cr1-flp124 +TPC/cru309_0.raw alio2-cr1-flp123 +TPC/cru310_0.raw alio2-cr1-flp126 +TPC/cru311_0.raw alio2-cr1-flp125 +TPC/cru312_0.raw alio2-cr1-flp126 +TPC/cru313_0.raw alio2-cr1-flp125 +TPC/cru314_0.raw alio2-cr1-flp128 +TPC/cru315_0.raw alio2-cr1-flp127 +TPC/cru316_0.raw alio2-cr1-flp128 +TPC/cru317_0.raw alio2-cr1-flp127 +TPC/cru318_0.raw alio2-cr1-flp128 +TPC/cru319_0.raw alio2-cr1-flp127 +TPC/cru320_0.raw alio2-cr1-flp130 +TPC/cru321_0.raw alio2-cr1-flp129 +TPC/cru322_0.raw alio2-cr1-flp130 +TPC/cru323_0.raw alio2-cr1-flp129 +TPC/cru324_0.raw alio2-cr1-flp132 +TPC/cru325_0.raw alio2-cr1-flp131 +TPC/cru326_0.raw alio2-cr1-flp132 +TPC/cru327_0.raw alio2-cr1-flp131 +TPC/cru328_0.raw alio2-cr1-flp132 +TPC/cru329_0.raw alio2-cr1-flp131 +TPC/cru330_0.raw alio2-cr1-flp134 +TPC/cru331_0.raw alio2-cr1-flp133 +TPC/cru332_0.raw alio2-cr1-flp134 +TPC/cru333_0.raw alio2-cr1-flp133 +TPC/cru334_0.raw alio2-cr1-flp136 +TPC/cru335_0.raw alio2-cr1-flp135 +TPC/cru336_0.raw alio2-cr1-flp136 +TPC/cru337_0.raw alio2-cr1-flp135 +TPC/cru338_0.raw alio2-cr1-flp136 +TPC/cru339_0.raw alio2-cr1-flp135 +TPC/cru340_0.raw alio2-cr1-flp138 +TPC/cru341_0.raw alio2-cr1-flp137 +TPC/cru342_0.raw alio2-cr1-flp138 +TPC/cru343_0.raw alio2-cr1-flp137 +TPC/cru344_0.raw alio2-cr1-flp140 +TPC/cru345_0.raw alio2-cr1-flp139 +TPC/cru346_0.raw alio2-cr1-flp140 +TPC/cru347_0.raw alio2-cr1-flp139 +TPC/cru348_0.raw alio2-cr1-flp140 +TPC/cru349_0.raw alio2-cr1-flp139 +TPC/cru350_0.raw alio2-cr1-flp142 +TPC/cru351_0.raw alio2-cr1-flp141 +TPC/cru352_0.raw alio2-cr1-flp142 +TPC/cru353_0.raw alio2-cr1-flp141 +TPC/cru354_0.raw alio2-cr1-flp144 +TPC/cru355_0.raw alio2-cr1-flp143 +TPC/cru356_0.raw alio2-cr1-flp144 +TPC/cru357_0.raw alio2-cr1-flp143 +TPC/cru358_0.raw alio2-cr1-flp144 +TPC/cru359_0.raw alio2-cr1-flp143 +TPC/cru0_1.raw alio2-cr1-flp070 +TPC/cru1_1.raw alio2-cr1-flp069 +TPC/cru2_1.raw alio2-cr1-flp070 +TPC/cru3_1.raw alio2-cr1-flp069 +TPC/cru4_1.raw alio2-cr1-flp072 +TPC/cru5_1.raw alio2-cr1-flp071 +TPC/cru6_1.raw alio2-cr1-flp072 +TPC/cru7_1.raw alio2-cr1-flp071 +TPC/cru8_1.raw alio2-cr1-flp072 +TPC/cru9_1.raw alio2-cr1-flp071 +TPC/cru10_1.raw alio2-cr1-flp002 +TPC/cru11_1.raw alio2-cr1-flp001 +TPC/cru12_1.raw alio2-cr1-flp002 +TPC/cru13_1.raw alio2-cr1-flp001 +TPC/cru14_1.raw alio2-cr1-flp004 +TPC/cru15_1.raw alio2-cr1-flp003 +TPC/cru16_1.raw alio2-cr1-flp004 +TPC/cru17_1.raw alio2-cr1-flp003 +TPC/cru18_1.raw alio2-cr1-flp004 +TPC/cru19_1.raw alio2-cr1-flp003 +TPC/cru20_1.raw alio2-cr1-flp006 +TPC/cru21_1.raw alio2-cr1-flp005 +TPC/cru22_1.raw alio2-cr1-flp006 +TPC/cru23_1.raw alio2-cr1-flp005 +TPC/cru24_1.raw alio2-cr1-flp008 +TPC/cru25_1.raw alio2-cr1-flp007 +TPC/cru26_1.raw alio2-cr1-flp008 +TPC/cru27_1.raw alio2-cr1-flp007 +TPC/cru28_1.raw alio2-cr1-flp008 +TPC/cru29_1.raw alio2-cr1-flp007 +TPC/cru30_1.raw alio2-cr1-flp010 +TPC/cru31_1.raw alio2-cr1-flp009 +TPC/cru32_1.raw alio2-cr1-flp010 +TPC/cru33_1.raw alio2-cr1-flp009 +TPC/cru34_1.raw alio2-cr1-flp012 +TPC/cru35_1.raw alio2-cr1-flp011 +TPC/cru36_1.raw alio2-cr1-flp012 +TPC/cru37_1.raw alio2-cr1-flp011 +TPC/cru38_1.raw alio2-cr1-flp012 +TPC/cru39_1.raw alio2-cr1-flp011 +TPC/cru40_1.raw alio2-cr1-flp014 +TPC/cru41_1.raw alio2-cr1-flp013 +TPC/cru42_1.raw alio2-cr1-flp014 +TPC/cru43_1.raw alio2-cr1-flp013 +TPC/cru44_1.raw alio2-cr1-flp016 +TPC/cru45_1.raw alio2-cr1-flp015 +TPC/cru46_1.raw alio2-cr1-flp016 +TPC/cru47_1.raw alio2-cr1-flp015 +TPC/cru48_1.raw alio2-cr1-flp016 +TPC/cru49_1.raw alio2-cr1-flp015 +TPC/cru50_1.raw alio2-cr1-flp018 +TPC/cru51_1.raw alio2-cr1-flp017 +TPC/cru52_1.raw alio2-cr1-flp018 +TPC/cru53_1.raw alio2-cr1-flp017 +TPC/cru54_1.raw alio2-cr1-flp020 +TPC/cru55_1.raw alio2-cr1-flp019 +TPC/cru56_1.raw alio2-cr1-flp020 +TPC/cru57_1.raw alio2-cr1-flp019 +TPC/cru58_1.raw alio2-cr1-flp020 +TPC/cru59_1.raw alio2-cr1-flp019 +TPC/cru60_1.raw alio2-cr1-flp022 +TPC/cru61_1.raw alio2-cr1-flp021 +TPC/cru62_1.raw alio2-cr1-flp022 +TPC/cru63_1.raw alio2-cr1-flp021 +TPC/cru64_1.raw alio2-cr1-flp024 +TPC/cru65_1.raw alio2-cr1-flp023 +TPC/cru66_1.raw alio2-cr1-flp024 +TPC/cru67_1.raw alio2-cr1-flp023 +TPC/cru68_1.raw alio2-cr1-flp024 +TPC/cru69_1.raw alio2-cr1-flp023 +TPC/cru70_1.raw alio2-cr1-flp026 +TPC/cru71_1.raw alio2-cr1-flp025 +TPC/cru72_1.raw alio2-cr1-flp026 +TPC/cru73_1.raw alio2-cr1-flp025 +TPC/cru74_1.raw alio2-cr1-flp028 +TPC/cru75_1.raw alio2-cr1-flp027 +TPC/cru76_1.raw alio2-cr1-flp028 +TPC/cru77_1.raw alio2-cr1-flp027 +TPC/cru78_1.raw alio2-cr1-flp028 +TPC/cru79_1.raw alio2-cr1-flp027 +TPC/cru80_1.raw alio2-cr1-flp030 +TPC/cru81_1.raw alio2-cr1-flp029 +TPC/cru82_1.raw alio2-cr1-flp030 +TPC/cru83_1.raw alio2-cr1-flp029 +TPC/cru84_1.raw alio2-cr1-flp032 +TPC/cru85_1.raw alio2-cr1-flp031 +TPC/cru86_1.raw alio2-cr1-flp032 +TPC/cru87_1.raw alio2-cr1-flp031 +TPC/cru88_1.raw alio2-cr1-flp032 +TPC/cru89_1.raw alio2-cr1-flp031 +TPC/cru90_1.raw alio2-cr1-flp034 +TPC/cru91_1.raw alio2-cr1-flp033 +TPC/cru92_1.raw alio2-cr1-flp034 +TPC/cru93_1.raw alio2-cr1-flp033 +TPC/cru94_1.raw alio2-cr1-flp036 +TPC/cru95_1.raw alio2-cr1-flp035 +TPC/cru96_1.raw alio2-cr1-flp036 +TPC/cru97_1.raw alio2-cr1-flp035 +TPC/cru98_1.raw alio2-cr1-flp036 +TPC/cru99_1.raw alio2-cr1-flp035 +TPC/cru100_1.raw alio2-cr1-flp038 +TPC/cru101_1.raw alio2-cr1-flp037 +TPC/cru102_1.raw alio2-cr1-flp038 +TPC/cru103_1.raw alio2-cr1-flp037 +TPC/cru104_1.raw alio2-cr1-flp040 +TPC/cru105_1.raw alio2-cr1-flp039 +TPC/cru106_1.raw alio2-cr1-flp040 +TPC/cru107_1.raw alio2-cr1-flp039 +TPC/cru108_1.raw alio2-cr1-flp040 +TPC/cru109_1.raw alio2-cr1-flp039 +TPC/cru110_1.raw alio2-cr1-flp042 +TPC/cru111_1.raw alio2-cr1-flp041 +TPC/cru112_1.raw alio2-cr1-flp042 +TPC/cru113_1.raw alio2-cr1-flp041 +TPC/cru114_1.raw alio2-cr1-flp044 +TPC/cru115_1.raw alio2-cr1-flp043 +TPC/cru116_1.raw alio2-cr1-flp044 +TPC/cru117_1.raw alio2-cr1-flp043 +TPC/cru118_1.raw alio2-cr1-flp044 +TPC/cru119_1.raw alio2-cr1-flp043 +TPC/cru120_1.raw alio2-cr1-flp046 +TPC/cru121_1.raw alio2-cr1-flp045 +TPC/cru122_1.raw alio2-cr1-flp046 +TPC/cru123_1.raw alio2-cr1-flp045 +TPC/cru124_1.raw alio2-cr1-flp048 +TPC/cru125_1.raw alio2-cr1-flp047 +TPC/cru126_1.raw alio2-cr1-flp048 +TPC/cru127_1.raw alio2-cr1-flp047 +TPC/cru128_1.raw alio2-cr1-flp048 +TPC/cru129_1.raw alio2-cr1-flp047 +TPC/cru130_1.raw alio2-cr1-flp050 +TPC/cru131_1.raw alio2-cr1-flp049 +TPC/cru132_1.raw alio2-cr1-flp050 +TPC/cru133_1.raw alio2-cr1-flp049 +TPC/cru134_1.raw alio2-cr1-flp052 +TPC/cru135_1.raw alio2-cr1-flp051 +TPC/cru136_1.raw alio2-cr1-flp052 +TPC/cru137_1.raw alio2-cr1-flp051 +TPC/cru138_1.raw alio2-cr1-flp052 +TPC/cru139_1.raw alio2-cr1-flp051 +TPC/cru140_1.raw alio2-cr1-flp054 +TPC/cru141_1.raw alio2-cr1-flp053 +TPC/cru142_1.raw alio2-cr1-flp054 +TPC/cru143_1.raw alio2-cr1-flp053 +TPC/cru144_1.raw alio2-cr1-flp056 +TPC/cru145_1.raw alio2-cr1-flp055 +TPC/cru146_1.raw alio2-cr1-flp056 +TPC/cru147_1.raw alio2-cr1-flp055 +TPC/cru148_1.raw alio2-cr1-flp056 +TPC/cru149_1.raw alio2-cr1-flp055 +TPC/cru150_1.raw alio2-cr1-flp058 +TPC/cru151_1.raw alio2-cr1-flp057 +TPC/cru152_1.raw alio2-cr1-flp058 +TPC/cru153_1.raw alio2-cr1-flp057 +TPC/cru154_1.raw alio2-cr1-flp060 +TPC/cru155_1.raw alio2-cr1-flp059 +TPC/cru156_1.raw alio2-cr1-flp060 +TPC/cru157_1.raw alio2-cr1-flp059 +TPC/cru158_1.raw alio2-cr1-flp060 +TPC/cru159_1.raw alio2-cr1-flp059 +TPC/cru160_1.raw alio2-cr1-flp062 +TPC/cru161_1.raw alio2-cr1-flp061 +TPC/cru162_1.raw alio2-cr1-flp062 +TPC/cru163_1.raw alio2-cr1-flp061 +TPC/cru164_1.raw alio2-cr1-flp064 +TPC/cru165_1.raw alio2-cr1-flp063 +TPC/cru166_1.raw alio2-cr1-flp064 +TPC/cru167_1.raw alio2-cr1-flp063 +TPC/cru168_1.raw alio2-cr1-flp064 +TPC/cru169_1.raw alio2-cr1-flp063 +TPC/cru170_1.raw alio2-cr1-flp066 +TPC/cru171_1.raw alio2-cr1-flp065 +TPC/cru172_1.raw alio2-cr1-flp066 +TPC/cru173_1.raw alio2-cr1-flp065 +TPC/cru174_1.raw alio2-cr1-flp068 +TPC/cru175_1.raw alio2-cr1-flp067 +TPC/cru176_1.raw alio2-cr1-flp068 +TPC/cru177_1.raw alio2-cr1-flp067 +TPC/cru178_1.raw alio2-cr1-flp068 +TPC/cru179_1.raw alio2-cr1-flp067 +TPC/cru180_1.raw alio2-cr1-flp074 +TPC/cru181_1.raw alio2-cr1-flp073 +TPC/cru182_1.raw alio2-cr1-flp074 +TPC/cru183_1.raw alio2-cr1-flp073 +TPC/cru184_1.raw alio2-cr1-flp076 +TPC/cru185_1.raw alio2-cr1-flp075 +TPC/cru186_1.raw alio2-cr1-flp076 +TPC/cru187_1.raw alio2-cr1-flp075 +TPC/cru188_1.raw alio2-cr1-flp076 +TPC/cru189_1.raw alio2-cr1-flp075 +TPC/cru190_1.raw alio2-cr1-flp078 +TPC/cru191_1.raw alio2-cr1-flp077 +TPC/cru192_1.raw alio2-cr1-flp078 +TPC/cru193_1.raw alio2-cr1-flp077 +TPC/cru194_1.raw alio2-cr1-flp080 +TPC/cru195_1.raw alio2-cr1-flp079 +TPC/cru196_1.raw alio2-cr1-flp080 +TPC/cru197_1.raw alio2-cr1-flp079 +TPC/cru198_1.raw alio2-cr1-flp080 +TPC/cru199_1.raw alio2-cr1-flp079 +TPC/cru200_1.raw alio2-cr1-flp082 +TPC/cru201_1.raw alio2-cr1-flp081 +TPC/cru202_1.raw alio2-cr1-flp082 +TPC/cru203_1.raw alio2-cr1-flp081 +TPC/cru204_1.raw alio2-cr1-flp084 +TPC/cru205_1.raw alio2-cr1-flp083 +TPC/cru206_1.raw alio2-cr1-flp084 +TPC/cru207_1.raw alio2-cr1-flp083 +TPC/cru208_1.raw alio2-cr1-flp084 +TPC/cru209_1.raw alio2-cr1-flp083 +TPC/cru210_1.raw alio2-cr1-flp086 +TPC/cru211_1.raw alio2-cr1-flp085 +TPC/cru212_1.raw alio2-cr1-flp086 +TPC/cru213_1.raw alio2-cr1-flp085 +TPC/cru214_1.raw alio2-cr1-flp088 +TPC/cru215_1.raw alio2-cr1-flp087 +TPC/cru216_1.raw alio2-cr1-flp088 +TPC/cru217_1.raw alio2-cr1-flp087 +TPC/cru218_1.raw alio2-cr1-flp088 +TPC/cru219_1.raw alio2-cr1-flp087 +TPC/cru220_1.raw alio2-cr1-flp090 +TPC/cru221_1.raw alio2-cr1-flp089 +TPC/cru222_1.raw alio2-cr1-flp090 +TPC/cru223_1.raw alio2-cr1-flp089 +TPC/cru224_1.raw alio2-cr1-flp092 +TPC/cru225_1.raw alio2-cr1-flp091 +TPC/cru226_1.raw alio2-cr1-flp092 +TPC/cru227_1.raw alio2-cr1-flp091 +TPC/cru228_1.raw alio2-cr1-flp092 +TPC/cru229_1.raw alio2-cr1-flp091 +TPC/cru230_1.raw alio2-cr1-flp094 +TPC/cru231_1.raw alio2-cr1-flp093 +TPC/cru232_1.raw alio2-cr1-flp094 +TPC/cru233_1.raw alio2-cr1-flp093 +TPC/cru234_1.raw alio2-cr1-flp096 +TPC/cru235_1.raw alio2-cr1-flp095 +TPC/cru236_1.raw alio2-cr1-flp096 +TPC/cru237_1.raw alio2-cr1-flp095 +TPC/cru238_1.raw alio2-cr1-flp096 +TPC/cru239_1.raw alio2-cr1-flp095 +TPC/cru240_1.raw alio2-cr1-flp098 +TPC/cru241_1.raw alio2-cr1-flp097 +TPC/cru242_1.raw alio2-cr1-flp098 +TPC/cru243_1.raw alio2-cr1-flp097 +TPC/cru244_1.raw alio2-cr1-flp100 +TPC/cru245_1.raw alio2-cr1-flp099 +TPC/cru246_1.raw alio2-cr1-flp100 +TPC/cru247_1.raw alio2-cr1-flp099 +TPC/cru248_1.raw alio2-cr1-flp100 +TPC/cru249_1.raw alio2-cr1-flp099 +TPC/cru250_1.raw alio2-cr1-flp102 +TPC/cru251_1.raw alio2-cr1-flp101 +TPC/cru252_1.raw alio2-cr1-flp102 +TPC/cru253_1.raw alio2-cr1-flp101 +TPC/cru254_1.raw alio2-cr1-flp104 +TPC/cru255_1.raw alio2-cr1-flp103 +TPC/cru256_1.raw alio2-cr1-flp104 +TPC/cru257_1.raw alio2-cr1-flp103 +TPC/cru258_1.raw alio2-cr1-flp104 +TPC/cru259_1.raw alio2-cr1-flp103 +TPC/cru260_1.raw alio2-cr1-flp106 +TPC/cru261_1.raw alio2-cr1-flp105 +TPC/cru262_1.raw alio2-cr1-flp106 +TPC/cru263_1.raw alio2-cr1-flp105 +TPC/cru264_1.raw alio2-cr1-flp108 +TPC/cru265_1.raw alio2-cr1-flp107 +TPC/cru266_1.raw alio2-cr1-flp108 +TPC/cru267_1.raw alio2-cr1-flp107 +TPC/cru268_1.raw alio2-cr1-flp108 +TPC/cru269_1.raw alio2-cr1-flp107 +TPC/cru270_1.raw alio2-cr1-flp110 +TPC/cru271_1.raw alio2-cr1-flp109 +TPC/cru272_1.raw alio2-cr1-flp110 +TPC/cru273_1.raw alio2-cr1-flp109 +TPC/cru274_1.raw alio2-cr1-flp112 +TPC/cru275_1.raw alio2-cr1-flp111 +TPC/cru276_1.raw alio2-cr1-flp112 +TPC/cru277_1.raw alio2-cr1-flp111 +TPC/cru278_1.raw alio2-cr1-flp112 +TPC/cru279_1.raw alio2-cr1-flp111 +TPC/cru280_1.raw alio2-cr1-flp114 +TPC/cru281_1.raw alio2-cr1-flp113 +TPC/cru282_1.raw alio2-cr1-flp114 +TPC/cru283_1.raw alio2-cr1-flp113 +TPC/cru284_1.raw alio2-cr1-flp116 +TPC/cru285_1.raw alio2-cr1-flp115 +TPC/cru286_1.raw alio2-cr1-flp116 +TPC/cru287_1.raw alio2-cr1-flp115 +TPC/cru288_1.raw alio2-cr1-flp116 +TPC/cru289_1.raw alio2-cr1-flp115 +TPC/cru290_1.raw alio2-cr1-flp118 +TPC/cru291_1.raw alio2-cr1-flp117 +TPC/cru292_1.raw alio2-cr1-flp118 +TPC/cru293_1.raw alio2-cr1-flp117 +TPC/cru294_1.raw alio2-cr1-flp120 +TPC/cru295_1.raw alio2-cr1-flp119 +TPC/cru296_1.raw alio2-cr1-flp120 +TPC/cru297_1.raw alio2-cr1-flp119 +TPC/cru298_1.raw alio2-cr1-flp120 +TPC/cru299_1.raw alio2-cr1-flp119 +TPC/cru300_1.raw alio2-cr1-flp122 +TPC/cru301_1.raw alio2-cr1-flp121 +TPC/cru302_1.raw alio2-cr1-flp122 +TPC/cru303_1.raw alio2-cr1-flp121 +TPC/cru304_1.raw alio2-cr1-flp124 +TPC/cru305_1.raw alio2-cr1-flp123 +TPC/cru306_1.raw alio2-cr1-flp124 +TPC/cru307_1.raw alio2-cr1-flp123 +TPC/cru308_1.raw alio2-cr1-flp124 +TPC/cru309_1.raw alio2-cr1-flp123 +TPC/cru310_1.raw alio2-cr1-flp126 +TPC/cru311_1.raw alio2-cr1-flp125 +TPC/cru312_1.raw alio2-cr1-flp126 +TPC/cru313_1.raw alio2-cr1-flp125 +TPC/cru314_1.raw alio2-cr1-flp128 +TPC/cru315_1.raw alio2-cr1-flp127 +TPC/cru316_1.raw alio2-cr1-flp128 +TPC/cru317_1.raw alio2-cr1-flp127 +TPC/cru318_1.raw alio2-cr1-flp128 +TPC/cru319_1.raw alio2-cr1-flp127 +TPC/cru320_1.raw alio2-cr1-flp130 +TPC/cru321_1.raw alio2-cr1-flp129 +TPC/cru322_1.raw alio2-cr1-flp130 +TPC/cru323_1.raw alio2-cr1-flp129 +TPC/cru324_1.raw alio2-cr1-flp132 +TPC/cru325_1.raw alio2-cr1-flp131 +TPC/cru326_1.raw alio2-cr1-flp132 +TPC/cru327_1.raw alio2-cr1-flp131 +TPC/cru328_1.raw alio2-cr1-flp132 +TPC/cru329_1.raw alio2-cr1-flp131 +TPC/cru330_1.raw alio2-cr1-flp134 +TPC/cru331_1.raw alio2-cr1-flp133 +TPC/cru332_1.raw alio2-cr1-flp134 +TPC/cru333_1.raw alio2-cr1-flp133 +TPC/cru334_1.raw alio2-cr1-flp136 +TPC/cru335_1.raw alio2-cr1-flp135 +TPC/cru336_1.raw alio2-cr1-flp136 +TPC/cru337_1.raw alio2-cr1-flp135 +TPC/cru338_1.raw alio2-cr1-flp136 +TPC/cru339_1.raw alio2-cr1-flp135 +TPC/cru340_1.raw alio2-cr1-flp138 +TPC/cru341_1.raw alio2-cr1-flp137 +TPC/cru342_1.raw alio2-cr1-flp138 +TPC/cru343_1.raw alio2-cr1-flp137 +TPC/cru344_1.raw alio2-cr1-flp140 +TPC/cru345_1.raw alio2-cr1-flp139 +TPC/cru346_1.raw alio2-cr1-flp140 +TPC/cru347_1.raw alio2-cr1-flp139 +TPC/cru348_1.raw alio2-cr1-flp140 +TPC/cru349_1.raw alio2-cr1-flp139 +TPC/cru350_1.raw alio2-cr1-flp142 +TPC/cru351_1.raw alio2-cr1-flp141 +TPC/cru352_1.raw alio2-cr1-flp142 +TPC/cru353_1.raw alio2-cr1-flp141 +TPC/cru354_1.raw alio2-cr1-flp144 +TPC/cru355_1.raw alio2-cr1-flp143 +TPC/cru356_1.raw alio2-cr1-flp144 +TPC/cru357_1.raw alio2-cr1-flp143 +TPC/cru358_1.raw alio2-cr1-flp144 +TPC/cru359_1.raw alio2-cr1-flp143 diff --git a/prodtests/full-system-test/datadistribution.sh b/prodtests/full-system-test/datadistribution.sh new file mode 100755 index 0000000000000..2d20a02ac7c6d --- /dev/null +++ b/prodtests/full-system-test/datadistribution.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +MYDIR="$(dirname $(readlink -f $0))" +source $MYDIR/setenv.sh + +if [ `which StfBuilder 2> /dev/null | wc -l` == "0" ]; then + eval "`alienv shell-helper`" + alienv --no-refresh load DataDistribution/latest +fi + +# For benchmark only, do NOT copy&paste! +export DATADIST_SHM_DELAY=30 +export DATADIST_FILE_READ_COUNT=$NTIMEFRAMES + +export TF_DIR=./raw/timeframe +export TFRATE=$(awk "BEGIN {printf \"%.6f\",1/$TFDELAY}") + +ARGS_ALL="--session default --severity $SEVERITY --shm-segment-id 2 --shm-segment-size 1000000 --no-cleanup" + +StfBuilder --id stfb --transport shmem \ + --dpl-channel-name dpl-chan --channel-config "name=dpl-chan,type=push,method=bind,address=ipc://@$INRAWCHANNAME,transport=shmem,rateLogging=1" \ + --data-source-dir ${TF_DIR} \ + --data-source-rate=${TFRATE} \ + --data-source-repeat \ + --data-source-regionsize=${DDSHMSIZE} \ + --data-source-headersize=1024 \ + --data-source-enable \ + --data-source-preread 5 \ + --shm-no-cleanup on \ + --shm-monitor false \ + --control=static \ + ${ARGS_ALL} diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh new file mode 100755 index 0000000000000..9ca0e1b4e67bc --- /dev/null +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -0,0 +1,369 @@ +#!/bin/bash + +# --------------------------------------------------------------------------------------------------------------------- +# Get this script's directory and load common settings (use zsh first (e.g. on Mac) and fallback on `readlink -f` if zsh is not there) +command -v zsh > /dev/null 2>&1 && MYDIR=$(dirname $(zsh -c 'echo ${0:A}' "$0")) +test -z ${MYDIR+x} && MYDIR="$(dirname $(readlink -f $0))" +source $MYDIR/setenv.sh + +# --------------------------------------------------------------------------------------------------------------------- +#Some additional settings used in this workflow +if [ -z $OPTIMIZED_PARALLEL_ASYNC ]; then OPTIMIZED_PARALLEL_ASYNC=0; fi # Enable tuned process multiplicities for async processing on the EPN +if [ -z $CTF_DIR ]; then CTF_DIR=$FILEWORKDIR; fi # Directory where to store CTFs +if [ -z $CTF_DICT_DIR ]; then CTF_DICT_DIR=$FILEWORKDIR; fi # Directory of CTF dictionaries +if [ -z $RECO_NUM_NODES_WORKFLOW ]; then RECO_NUM_NODES_WORKFLOW=250; fi # Number of EPNs running this workflow in parallel, to increase multiplicities if necessary, by default assume we are 1 out of 250 servers + +workflow_has_parameter CTF && export SAVECTF=1 +workflow_has_parameter GPU && { export GPUTYPE=HIP; export NGPUS=4; } + +ITSCLUSDICT="${FILEWORKDIR}/ITSdictionary.bin" +MFTCLUSDICT="${FILEWORKDIR}/MFTdictionary.bin" +MFT_NOISE="${FILEWORKDIR}/mft_noise_220721_R3C-520.root" +MID_FEEID_MAP="$FILEWORKDIR/mid-feeId_mapper.txt" +CTF_MINSIZE="2000000" +NITSDECTHREADS=2 +NMFTDECTHREADS=2 +CTF_DICT=${CTF_DICT_DIR}/ctf_dictionary.root + + +if [ "0$O2_ROOT" == "0" ]; then + eval "`alienv shell-helper`" + alienv --no-refresh load O2/latest +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Set general arguments +ARGS_ALL="--session default --severity $SEVERITY --shm-segment-id $NUMAID --shm-segment-size $SHMSIZE $ARGS_ALL_EXTRA" +if [ $EPNMODE == 1 ]; then + ARGS_ALL+=" --infologger-severity $INFOLOGGER_SEVERITY" + ARGS_ALL+=" --monitoring-backend influxdb-unix:///tmp/telegraf.sock --resources-monitoring 60" +else + ARGS_ALL+=" --monitoring-backend no-op://" +fi +if [ $EXTINPUT == 1 ] || [ $NUMAGPUIDS == 1 ]; then + ARGS_ALL+=" --no-cleanup" +fi +if [ $SHMTHROW == 0 ]; then + ARGS_ALL+=" --shm-throw-bad-alloc 0" +fi +if [ $NORATELOG == 1 ]; then + ARGS_ALL+=" --fairmq-rate-logging 0" +fi +if [ $NUMAGPUIDS != 0 ]; then + ARGS_ALL+=" --child-driver 'numactl --membind $NUMAID --cpunodebind $NUMAID'" +fi +if [ $GPUTYPE != "CPU" ] || [ $OPTIMIZED_PARALLEL_ASYNC != 0 ]; then + ARGS_ALL+=" --shm-mlock-segment-on-creation 1" +fi +ARGS_ALL_CONFIG="NameConf.mDirGRP=$FILEWORKDIR;NameConf.mDirGeom=$FILEWORKDIR;NameConf.mDirCollContext=$FILEWORKDIR;NameConf.mDirMatLUT=$FILEWORKDIR;keyval.input_dir=$FILEWORKDIR;keyval.output_dir=/dev/null;$ALL_EXTRA_CONFIG" + +# --------------------------------------------------------------------------------------------------------------------- +# Set some individual workflow arguments depending on configuration +GPU_INPUT=zsraw +GPU_OUTPUT=tracks,clusters +GPU_CONFIG= +GPU_CONFIG_KEY= +TOF_INPUT=raw +TOF_OUTPUT=clusters +ITS_CONFIG= +ITS_CONFIG_KEY= +TRD_CONFIG= +TRD_CONFIG_KEY= +TRD_TRANSFORMER_CONFIG= +EVE_CONFIG=" --jsons-folder $EDJSONS_DIR" +MFTDEC_CONFIG= +MIDDEC_CONFIG= + +if [ $SYNCMODE == 1 ]; then + if [ $BEAMTYPE == "PbPb" ]; then + ITS_CONFIG_KEY+="fastMultConfig.cutMultClusLow=30;fastMultConfig.cutMultClusHigh=2000;fastMultConfig.cutMultVtxHigh=500;" + elif [ $BEAMTYPE == "pp" ]; then + ITS_CONFIG_KEY+="fastMultConfig.cutMultClusLow=1;fastMultConfig.cutMultClusHigh=2000;fastMultConfig.cutMultVtxHigh=500;" + fi + GPU_CONFIG_KEY+="GPU_global.synchronousProcessing=1;GPU_proc.clearO2OutputFromGPU=1;" + TRD_CONFIG+=" --track-sources ITS-TPC --filter-trigrec" + TRD_CONFIG_KEY+="GPU_proc.ompThreads=1;" + TRD_TRANSFORMER_CONFIG+=" --filter-trigrec" +else + TRD_CONFIG+=" --track-sources TPC,ITS-TPC" +fi + +if [ $CTFINPUT == 1 ]; then + ITS_CONFIG+=" --tracking-mode async" +else + ITS_CONFIG+=" --tracking-mode sync" + GPU_OUTPUT+=",compressed-clusters-ctf" +fi + +if [ $EPNMODE == 1 ]; then + EVE_CONFIG+=" --eve-dds-collection-index 0" + MFTDEC_CONFIG+=" --noise-file \"${MFT_NOISE}\"" + MIDDEC_CONFIG+=" --feeId-config-file \"$MID_FEEID_MAP\"" +fi + +if [ $GPUTYPE == "HIP" ]; then + if [ $NUMAID == 0 ] || [ $NUMAGPUIDS == 0 ]; then + export TIMESLICEOFFSET=0 + else + export TIMESLICEOFFSET=$NGPUS + fi + GPU_CONFIG_KEY+="GPU_proc.deviceNum=0;GPU_global.mutexMemReg=true;" + GPU_CONFIG+=" --environment \"ROCR_VISIBLE_DEVICES={timeslice${TIMESLICEOFFSET}}\"" + export HSA_NO_SCRATCH_RECLAIM=1 + #export HSA_TOOLS_LIB=/opt/rocm/lib/librocm-debug-agent.so.2 +else + GPU_CONFIG_KEY+="GPU_proc.deviceNum=-2;" +fi + +if [ ! -z $GPU_NUM_MEM_REG_CALLBACKS ]; then + GPU_CONFIG+=" --expected-region-callbacks $GPU_NUM_MEM_REG_CALLBACKS" +fi + +if [ $GPUTYPE != "CPU" ]; then + GPU_CONFIG_KEY+="GPU_proc.forceMemoryPoolSize=$GPUMEMSIZE;" + if [ $HOSTMEMSIZE == "0" ]; then + HOSTMEMSIZE=$(( 1 << 30 )) + fi +fi + +if [ $HOSTMEMSIZE != "0" ]; then + GPU_CONFIG_KEY+="GPU_proc.forceHostMemoryPoolSize=$HOSTMEMSIZE;" +fi + +if workflow_has_parameter CTF_ONLY; then + TOF_OUTPUT=digits +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Process multiplicities +N_TPCTRK=1 +N_TPCENT=1 +N_TPCITS=1 +N_ITSRAWDEC=1 +N_MFTRAWDEC=1 +N_CTPRAWDEC=1 +N_TPCRAWDEC=$NGPUS +N_EMC=1 +N_TRDENT=1 +N_TRDTRK=1 +N_TPCENTDEC=1 +N_MFTTRK=1 +N_ITSTRK=1 +N_MCHTRK=1 +N_TOFMATCH=1 +N_F_REST=$MULTIPLICITY_FACTOR_REST +N_F_RAW=$MULTIPLICITY_FACTOR_RAWDECODERS +N_F_CTF=$MULTIPLICITY_FACTOR_CTFENCODERS +if [ $OPTIMIZED_PARALLEL_ASYNC != 0 ]; then + # Tuned multiplicities for async Pb-Pb processing + if [ $SYNCMODE == "1" ]; then echo "Must not use OPTIMIZED_PARALLEL_ASYNC with GPU or SYNCMODE" 1>&2; exit 1; fi + if [ $NUMAGPUIDS == 1 ]; then N_NUMAFACTOR=1; else N_NUMAFACTOR=2; fi + GPU_CONFIG_KEY+="GPU_proc.ompThreads=6;" + TRD_CONFIG_KEY+="GPU_proc.ompThreads=2;" + if [ $GPUTYPE == "CPU" ]; then + N_TPCENTDEC=$((2 * $N_NUMAFACTOR)) + N_MFTTRK=$((3 * $N_NUMAFACTOR)) + N_ITSTRK=$((3 * $N_NUMAFACTOR)) + N_TPCITS=$((2 * $N_NUMAFACTOR)) + N_MCHTRK=$((1 * $N_NUMAFACTOR)) + N_TOFMATCH=$((9 * $N_NUMAFACTOR)) + N_TPCTRK=$((6 * $N_NUMAFACTOR)) + else + N_TPCENTDEC=$((3 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 3 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_MFTTRK=$((6 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 6 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_ITSTRK=$((6 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 6 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_TPCITS=$((4 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 4 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_MCHTRK=$((2 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 2 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_TOFMATCH=$((20 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 > 0 ? 20 * $NGPUS * $OPTIMIZED_PARALLEL_ASYNC * $N_NUMAFACTOR / 4 : 1)) + N_TPCTRK=$NGPUS + fi +elif [ $EPNPIPELINES != 0 ]; then + # Tuned multiplicities for sync Pb-Pb processing + N_TPCENT=$((3 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 3 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_TPCITS=$((3 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 3 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_ITSRAWDEC=$((3 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 3 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_EMC=$((7 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 7 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_TRDENT=$((3 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 3 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_TRDTRK=$((3 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 3 * $EPNPIPELINES * $NGPUS / 4 : 1)) + N_TPCRAWDEC=$((6 * $EPNPIPELINES * $NGPUS / 4 > 0 ? 6 * $EPNPIPELINES * $NGPUS / 4 : 1)) + if [ $GPUTYPE == "CPU" ]; then + N_TPCTRK=8 + GPU_CONFIG_KEY+="GPU_proc.ompThreads=4;" + else + N_TPCTRK=$NGPUS + fi +fi +# Scale some multiplicities with the number of nodes +RECO_NUM_NODES_WORKFLOW_CMP=$(($RECO_NUM_NODES_WORKFLOW > 15 ? $RECO_NUM_NODES_WORKFLOW : 15)) # Limit the scaling factor +N_ITSRAWDEC=$((6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_ITSRAWDEC ? 6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_ITSRAWDEC)) +N_MFTRAWDEC=$((6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_MFTRAWDEC ? 6 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_MFTRAWDEC)) +N_ITSTRK=$((2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_ITSTRK ? 2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_ITSTRK)) +N_MFTTRK=$((2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP > $N_MFTTRK ? 2 * 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_MFTTRK)) +N_CTPRAWDEC=$((30 / $RECO_NUM_NODES_WORKFLOW_CMP > N_CTPRAWDEC ? 30 / $RECO_NUM_NODES_WORKFLOW_CMP : $N_CTPRAWDEC)) +# Apply external multiplicity factors +N_TPCTRK=$((N_TPCTRK * $N_F_REST)) +N_TPCITS=$((N_TPCITS * $N_F_REST)) +N_EMC=$((N_EMC * $N_F_REST)) +N_TRDTRK=$((N_TRDTRK * $N_F_REST)) +N_TPCENTDEC=$((N_TPCENTDEC * $N_F_REST)) +N_MFTTRK=$((N_MFTTRK * $N_F_REST)) +N_ITSTRK=$((N_ITSTRK * $N_F_REST)) +N_MCHTRK=$((N_MCHTRK * $N_F_REST)) +N_TOFMATCH=$((N_TOFMATCH * $N_F_REST)) +N_TPCENT=$((N_TPCENT * $N_F_CTF)) +N_TRDENT=$((N_TRDENT * $N_F_CTF)) +N_ITSRAWDEC=$((N_ITSRAWDEC * $N_F_RAW)) +N_MFTRAWDEC=$((N_MFTRAWDEC * $N_F_RAW)) +N_TPCRAWDEC=$((N_TPCRAWDEC * $N_F_RAW)) +N_CTPRAWDEC=$((N_CTPRAWDEC * $N_F_RAW)) + +# --------------------------------------------------------------------------------------------------------------------- +# Input workflow +if [ $CTFINPUT == 1 ]; then + GPU_INPUT=compressed-clusters-ctf + TOF_INPUT=digits + CTFName=`ls -t $FILEWORKDIR/o2_ctf_*.root | head -n1` + WORKFLOW="o2-ctf-reader-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --delay $TFDELAY --loop $NTIMEFRAMES --ctf-input ${CTFName} --ctf-dict ${CTF_DICT} --onlyDet $WORKFLOW_DETECTORS --pipeline tpc-entropy-decoder:$N_TPCENTDEC | " +elif [ $EXTINPUT == 1 ]; then + PROXY_CHANNEL="name=readout-proxy,type=pull,method=connect,address=ipc://@$INRAWCHANNAME,transport=shmem,rateLogging=0" + PROXY_INSPEC="dd:FLP/DISTSUBTIMEFRAME/0;eos:***/INFORMATION" + PROXY_IN_N=0 + for i in `echo "$WORKFLOW_DETECTORS" | sed "s/,/ /g"`; do + if [ $EPNMODE == 1 ] && [ $i == "TOF" ]; then + PROXY_INTYPE=CRAWDATA + else + PROXY_INTYPE=RAWDATA + fi + PROXY_INNAME="RAWIN$PROXY_IN_N" + let PROXY_IN_N=$PROXY_IN_N+1 + PROXY_INSPEC+=";$PROXY_INNAME:$i/$PROXY_INTYPE" + done + WORKFLOW="o2-dpl-raw-proxy $ARGS_ALL --dataspec \"$PROXY_INSPEC\" --channel-config \"$PROXY_CHANNEL\" | " +else + WORKFLOW="o2-raw-file-reader-workflow --detect-tf0 $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG;HBFUtils.nHBFPerTF=$NHBPERTF;\" --delay $TFDELAY --loop $NTIMEFRAMES --max-tf 0 --input-conf $FILEWORKDIR/rawAll.cfg | " +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Raw decoder workflows +if [ $CTFINPUT == 0 ]; then + if has_detector TPC && [ $EPNMODE == 1 ]; then + GPU_INPUT=zsonthefly + WORKFLOW+="o2-tpc-raw-to-digits-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-spec \"A:TPC/RAWDATA;dd:FLP/DISTSUBTIMEFRAME/0\" --remove-duplicates --pipeline tpc-raw-to-digits-0:$N_TPCRAWDEC | " + WORKFLOW+="o2-tpc-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type digitizer --output-type zsraw,disable-writer --pipeline tpc-zsEncoder:$N_TPCRAWDEC | " + fi + has_detector ITS && WORKFLOW+="o2-itsmft-stf-decoder-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --dict-file \"${ITSCLUSDICT}\" --nthreads ${NITSDECTHREADS} --pipeline its-stf-decoder:$N_ITSRAWDEC | " + has_detector MFT && WORKFLOW+="o2-itsmft-stf-decoder-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --dict-file \"${MFTCLUSDICT}\" --nthreads ${NMFTDECTHREADS} --pipeline mft-stf-decoder:$N_MFTRAWDEC ${MFTDEC_CONFIG} --runmft true | " + has_detector FT0 && WORKFLOW+="o2-ft0-flp-dpl-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline ft0-datareader-dpl:$N_F_RAW | " + has_detector FV0 && WORKFLOW+="o2-fv0-flp-dpl-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline fv0-datareader-dpl:$N_F_RAW | " + has_detector MID && WORKFLOW+="o2-mid-raw-to-digits-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" $MIDDEC_CONFIG --pipeline MIDRawDecoder:$N_F_RAW,MIDDecodedDataAggregator:$N_F_RAW | " + has_detector MCH && WORKFLOW+="o2-mch-raw-to-digits-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline mch-data-decoder:$N_F_RAW | " + has_detector TOF && [ $EPNMODE == 0 ] && WORKFLOW+="o2-tof-compressor $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" | " + has_detector FDD && WORKFLOW+="o2-fdd-flp-dpl-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline fdd-datareader-dpl:$N_F_RAW | " + has_detector TRD && WORKFLOW+="o2-trd-datareader $ARGS_ALL --pipeline trd-datareader:$N_F_RAW | " + has_detector ZDC && WORKFLOW+="o2-zdc-raw2digits $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline zdc-datareader-dpl:$N_F_RAW | " + has_detector HMP && WORKFLOW+="o2-hmpid-raw-to-digits-stream-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline HMP-RawStreamDecoder:$N_F_RAW | " + has_detector CTP && WORKFLOW+="o2-ctp-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --pipeline CTP-RawStreamDecoder:$N_CTPRAWDEC | " +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Common reconstruction workflows +has_detector TPC && WORKFLOW+="o2-gpu-reco-workflow ${ARGS_ALL//-severity $SEVERITY/-severity $SEVERITY_TPC} --input-type=$GPU_INPUT $DISABLE_MC --output-type $GPU_OUTPUT --pipeline gpu-reconstruction:$N_TPCTRK $GPU_CONFIG --configKeyValues \"$ARGS_ALL_CONFIG;GPU_global.deviceType=$GPUTYPE;GPU_proc.debugLevel=0;$GPU_CONFIG_KEY;$GPU_EXTRA_CONFIG\" | " +has_detector TOF && WORKFLOW+="o2-tof-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type $TOF_INPUT --output-type $TOF_OUTPUT --disable-root-input --disable-root-output $DISABLE_MC --pipeline tof-compressed-decoder:$N_F_RAW,TOFClusterer:$N_F_REST | " +if ! workflow_has_parameter CTF_ONLY; then + has_detector ITS && WORKFLOW+="o2-its-reco-workflow $ARGS_ALL --trackerCA $DISABLE_MC --clusters-from-upstream --disable-root-output $ITS_CONFIG --configKeyValues \"$ARGS_ALL_CONFIG;$ITS_CONFIG_KEY\" --its-dictionary-path $FILEWORKDIR --pipeline its-tracker:$N_ITSTRK | " + has_detectors ITS TPC && WORKFLOW+="o2-tpcits-match-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --its-dictionary-path $FILEWORKDIR --pipeline itstpc-track-matcher:$N_TPCITS | " + has_detector FT0 && WORKFLOW+="o2-ft0-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --pipeline ft0-reconstructor:$N_F_REST | " + has_detector TRD && WORKFLOW+="o2-trd-tracklet-transformer $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC $TRD_TRANSFORMER_CONFIG --pipeline TRDTRACKLETTRANSFORMER:$N_TRDTRK | " + has_detectors TRD TPC ITS && WORKFLOW+="o2-trd-global-tracking $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG;$TRD_CONFIG_KEY\" --disable-root-input --disable-root-output $DISABLE_MC $TRD_CONFIG | " +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Workflows disabled in sync mode +if [ $SYNCMODE == 0 ]; then + has_detectors TOF TRD TPC ITS && WORKFLOW+="o2-tof-matcher-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --track-sources \"TPC,ITS-TPC\" --pipeline tof-matcher:$N_TOFMATCH | " + has_detector MID && WORKFLOW+="o2-mid-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output $DISABLE_MC --pipeline MIDClusterizer:$N_F_REST,MIDTracker:$N_F_REST | " + has_detector MCH && WORKFLOW+="o2-mch-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --pipeline mch-track-finder:$N_MCHTRK,mch-cluster-finder:$N_F_REST,mch-cluster-transformer:$N_F_REST | " + has_detector MFT && WORKFLOW+="o2-mft-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --clusters-from-upstream $DISABLE_MC --disable-root-output --pipeline mft-tracker:$N_MFTTRK --mft-dictionary-path $FILEWORKDIR | " + has_detectors MFT MCH && WORKFLOW+="o2-globalfwd-matcher-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --pipeline globalfwd-track-matcher:$N_F_REST | " + has_detectors ITS TPC TRD TOF FT0 MCH MFT && WORKFLOW+="o2-primary-vertexing-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" $DISABLE_MC --disable-root-input --disable-root-output --validate-with-ft0 --pipeline primary-vertexing:$N_F_REST | " + has_detectors ITS TPC TRD TOF FT0 MCH MFT && WORKFLOW+="o2-secondary-vertexing-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output --pipeline secondary-vertexing:$N_F_REST | " + has_detector FDD && WORKFLOW+="o2-fdd-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC | " + has_detector FDD && WORKFLOW+="o2-fv0-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC | " + has_detector ZDC && WORKFLOW+="o2-zdc-digits-reco $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC | " +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Workflows disabled in async mode +if [ $CTFINPUT == 0 ]; then + has_detector PHS && WORKFLOW+="o2-phos-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type raw --output-type cells --disable-root-input --disable-root-output --pipeline PHOSRawToCellConverterSpec:$N_F_REST $DISABLE_MC | " + has_detector CPV && WORKFLOW+="o2-cpv-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type raw --output-type clusters --disable-root-input --disable-root-output --pipeline CPVRawToDigitConverterSpec:$N_F_REST,CPVClusterizerSpec:$N_F_REST $DISABLE_MC | " + has_detector EMC && WORKFLOW+="o2-emcal-reco-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type raw --output-type cells --disable-root-output $DISABLE_MC --pipeline EMCALRawToCellConverterSpec:$N_EMC | " + if ! workflow_has_parameter CTF_ONLY; then + # Reconstruction workflows + if [ $SYNCMODE == 1 ]; then # Otherwise already present in async setup + has_detectors TOF TRD TPC ITS && WORKFLOW+="o2-tof-matcher-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-input --disable-root-output $DISABLE_MC --track-sources \"ITS-TPC\" --pipeline tof-matcher:$N_TOFMATCH | " + fi + fi + + # Entropy encoder workflows + has_detector MFT && WORKFLOW+="o2-itsmft-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --runmft true --pipeline mft-entropy-encoder:$N_F_CTF | " + has_detector FT0 && WORKFLOW+="o2-ft0-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline ft0-entropy-encoder:$N_F_CTF | " + has_detector FV0 && WORKFLOW+="o2-fv0-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline fv0-entropy-encoder:$N_F_CTF | " + has_detector MID && WORKFLOW+="o2-mid-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline mid-entropy-encoder:$N_F_CTF | " + has_detector MCH && WORKFLOW+="o2-mch-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline mch-entropy-encoder:$N_F_CTF | " + has_detector PHS && WORKFLOW+="o2-phos-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline phos-entropy-encoder:$N_F_CTF | " + has_detector CPV && WORKFLOW+="o2-cpv-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline cpv-entropy-encoder:$N_F_CTF | " + has_detector EMC && WORKFLOW+="o2-emcal-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline emcal-entropy-encoder:$N_F_CTF | " + has_detector ZDC && WORKFLOW+="o2-zdc-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline zdc-entropy-encoder:$N_F_CTF | " + has_detector FDD && WORKFLOW+="o2-fdd-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline fdd-entropy-encoder:$N_F_CTF | " + has_detector HMP && WORKFLOW+="o2-hmpid-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline hmpid-entropy-encoder:$N_F_CTF | " + has_detector TOF && WORKFLOW+="o2-tof-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline tof-entropy-encoder:$N_F_CTF | " + has_detector ITS && WORKFLOW+="o2-itsmft-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline its-entropy-encoder:$N_F_CTF | " + has_detector TRD && WORKFLOW+="o2-trd-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline trd-entropy-encoder:$N_TRDENT | " + has_detector TPC && WORKFLOW+="o2-tpc-reco-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --input-type compressed-clusters-flat --output-type encoded-clusters,disable-writer --pipeline tpc-entropy-encoder:$N_TPCENT | " + has_detector CTP && WORKFLOW+="o2-ctp-entropy-encoder-workflow $ARGS_ALL --ctf-dict \"${CTF_DICT}\" --configKeyValues \"$ARGS_ALL_CONFIG\" --pipeline its-entropy-encoder:$N_F_CTF| " + + # Calibration workflows + workflow_has_parameter CALIB && has_detector_calib TPC && has_detectors TPC ITS TRD TOF && WORKFLOW+="o2-tpc-scdcalib-interpolation-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --disable-root-output --disable-root-input --pipeline tpc-track-interpolation:$N_F_REST | " + + # CTF / dictionary writer workflow + if [ $SAVECTF == 1 ]; then + mkdir -p $CTF_DIR + fi + if [ $CREATECTFDICT == 1 ] ; then + mkdir -p $CTF_DICT_DIR; + rm -f $CTF_DICT + fi + CTF_OUTPUT_TYPE="none" + if [ $CREATECTFDICT == 1 ] && [ $SAVECTF == 1 ]; then CTF_OUTPUT_TYPE="both"; fi + if [ $CREATECTFDICT == 1 ] && [ $SAVECTF == 0 ]; then CTF_OUTPUT_TYPE="dict"; fi + if [ $CREATECTFDICT == 0 ] && [ $SAVECTF == 1 ]; then CTF_OUTPUT_TYPE="ctf"; fi + CMD_CTF="o2-ctf-writer-workflow $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --output-dir \"$CTF_DIR\" --ctf-dict-dir \"$CTF_DICT_DIR\" --output-type $CTF_OUTPUT_TYPE --min-file-size ${CTF_MINSIZE} --onlyDet $WORKFLOW_DETECTORS" + if [ $CREATECTFDICT == 1 ] && [ $EXTINPUT == 1 ]; then CMD_CTF+=" --save-dict-after $NTIMEFRAMES"; fi + WORKFLOW+="$CMD_CTF | " +fi + +# --------------------------------------------------------------------------------------------------------------------- +# Event display +workflow_has_parameter EVENT_DISPLAY && [ $NUMAID == 0 ] && WORKFLOW+="o2-eve-display $ARGS_ALL --configKeyValues \"$ARGS_ALL_CONFIG\" --display-tracks TPC --display-clusters TPC $EVE_CONFIG $DISABLE_MC | " + +# --------------------------------------------------------------------------------------------------------------------- +# Quality Control +workflow_has_parameter QC && source $MYDIR/qc-workflow.sh + +# --------------------------------------------------------------------------------------------------------------------- +# DPL run binary +WORKFLOW+="o2-dpl-run $ARGS_ALL $GLOBALDPLOPT" + +# --------------------------------------------------------------------------------------------------------------------- +# Run / create / print workflow +if [ $WORKFLOWMODE == "print" ]; then + echo Workflow command: + echo $WORKFLOW | sed "s/| */|\n/g" +else + # Execute the command we have assembled + WORKFLOW+=" --$WORKFLOWMODE" + eval $WORKFLOW +fi + +# --------------------------------------------------------------------------------------------------------------------- diff --git a/prodtests/full-system-test/gen_rdo_cfg.sh b/prodtests/full-system-test/gen_rdo_cfg.sh new file mode 100755 index 0000000000000..516e28e7edc5b --- /dev/null +++ b/prodtests/full-system-test/gen_rdo_cfg.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +set -u + +display_usage() { + echo -e "\nSpecify tf length and directory name containing raw files" + echo -e "\nUsage:\ngen_rdo_cfg.sh <tf_len> <dir> \n" +} + +if [[ ($# -le 1) || ( "$1" == "--help") || ("$1" == "-h") ]]; then + display_usage + exit 1 +fi + +#TF LENGTH +TF_LEN=$1 + +function file_input { + name="${1//[-.\/]/_}" + size=$(stat --printf="%s" $1) + # calculate number of pages to hold the files + page_cnt=$(( (size * 3 / 2) / 524288 )) + page_cnt=$(( page_cnt < 70 ? 70 : page_cnt)) + + echo "[equipment-player-$name]" + echo "## file size = ${size}" + echo "## page cnt = ${page_cnt}" + + echo "equipmentType = player" + echo "filePath = $1" + echo "enabled = 1" + echo "autoChunk = 1" + echo "TFperiod = $2" + echo "memoryPoolNumberOfPages = ${page_cnt}" + echo "memoryPoolPageSize = 512k" + echo "" +} + + +cat > rdo_TF.cfg <<- EOM +################################### +# general settings +################################### +[readout] + +# per-equipment data rate limit, in Hertz (-1 for unlimited) +rate=-1 +# time (in seconds) after which program exits automatically (-1 for unlimited) +exitTimeout=-1 + +### !!! Agreggating (buffering) for TF ordering +### 5 seconds buffering/sorting of individual sources + +disableAggregatorSlicing=0 +aggregatorSliceTimeout=12 +aggregatorStfTimeout=10 + +[consumer-stats] +consumerType = stats +enabled = 1 +monitoringEnabled = 0 +monitoringUpdatePeriod = 1 +processMonitoringInterval = 1 +consoleUpdate = 1 + +[consumer-StfBuilder] +consumerType = FairMQChannel +enabled = 1 +sessionName = default +fmq-transport = shmem +fmq-name = readout-out +fmq-type = push +fmq-address = ipc:///tmp/readout-to-datadist-0 +unmanagedMemorySize = 96G +memoryBankName = bank-o2 +memoryPoolNumberOfPages = 20000 +memoryPoolPageSize = 512k +disableSending = 0 + +################################### +# Begin file players +################################### +EOM + + +# iterate over directories +for dir in "${@:2}" +do + for rawfile in $dir/*.raw + do + file_input "$rawfile" "$TF_LEN" >> rdo_TF.cfg + done +done diff --git a/prodtests/full-system-test/generate_timeframe_files.sh b/prodtests/full-system-test/generate_timeframe_files.sh new file mode 100755 index 0000000000000..c297712b67a21 --- /dev/null +++ b/prodtests/full-system-test/generate_timeframe_files.sh @@ -0,0 +1,50 @@ +#!/bin/bash +if [ "0$1" == "0" ]; then + echo Specify how many timeframe files to generate! + exit 1 +fi + +echo Generating $1 timeframe files + +# Defaults for 128 orbit TF, feel free to override +NEvents=${NEvents:-600} +NEventsQED=${NEventsQED:-35000} +SHMSIZE=${SHMSIZE:-128000000000} +TPCTRACKERSCRATCHMEMORY=${SHMSIZE:-25000000000} + +if [ `which StfBuilder 2> /dev/null | wc -l` == "0" ]; then + echo ERROR: StfBuilder is not in the path + exit 1 +fi +if [ `which o2-readout-exe 2> /dev/null | wc -l` == "0" ]; then + echo ERROR: o2-readout-exe is not in the path + exit 1 +fi +if [ "0$O2_ROOT" == "0" ]; then + echo \$O2_ROOT missing + exit 1 +fi +if [ ! -f ITSdictionary.bin ]; then + echo ERROR: ITS dictionary missing + exit 1 +fi +if [ ! -f matbud.root ]; then + echo ERROR: matbud.root missing + exit 1 +fi + +mkdir -p raw/timeframe +rm -Rf sim +mkdir sim +mkdir -p simqed + +for i in `seq $1`; do + cp ITSdictionary.bin sim + pushd sim + ln -s ../simqed qed + SPLITTRDDIGI=0 DISABLE_PROCESSING=1 $O2_ROOT/prodtests/full_system_test.sh + $O2_ROOT/prodtests/full-system-test/convert-raw-to-tf-file.sh + popd + mv sim/raw/timeframe/00000001.tf raw/timeframe/`ls raw/timeframe/*.tf | wc -l | awk '{printf("%08d.tf", $1+1)}'` + rm -Rf sim +done diff --git a/prodtests/full-system-test/raw-reader.sh b/prodtests/full-system-test/raw-reader.sh new file mode 100755 index 0000000000000..bf62155c18391 --- /dev/null +++ b/prodtests/full-system-test/raw-reader.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +if [ "0$O2_ROOT" == "0" ]; then + eval "`alienv shell-helper`" + alienv --no-refresh load O2/latest +fi + +MYDIR="$(dirname $(readlink -f $0))" +source $MYDIR/setenv.sh + +ARGS_ALL="--session default --shm-throw-bad-alloc 0 --no-cleanup" +if [ $NUMAGPUIDS == 1 ]; then + TMPSIZE=$(expr $DDSHMSIZE \* 1024 \* 1024) + ARGS_ALL+=" --shm-segment-id 2 --shm-segment-size $TMPSIZE --shm-mlock-segment 1 --shm-zero-segment 1" +else + ARGS_ALL+=" --shm-segment-size $SHMSIZE" +fi +if [ $NORATELOG == 1 ]; then + ARGS_ALL+=" --fairmq-rate-logging 0" +fi + +o2-raw-file-reader-workflow $ARGS_ALL --loop $NTIMEFRAMES --delay $TFDELAY --input-conf rawAll.cfg --configKeyValues "HBFUtils.nHBFPerTF=$NHBPERTF;" --max-tf 0 --raw-channel-config "name=dpl-chan,type=push,method=bind,address=ipc://@$INRAWCHANNAME,transport=shmem,rateLogging=0" $GLOBALDPLOPT --run diff --git a/prodtests/full-system-test/setenv.sh b/prodtests/full-system-test/setenv.sh new file mode 100755 index 0000000000000..d882fdc6ea44c --- /dev/null +++ b/prodtests/full-system-test/setenv.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ "0$O2DATAPROCESSING_ROOT" == "0" ]; then + echo O2DataProcessing environment not loaded + exit 1 +fi + +source $O2DATAPROCESSING_ROOT/common/setenv.sh diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh new file mode 100755 index 0000000000000..4501334208a1c --- /dev/null +++ b/prodtests/full-system-test/start_tmux.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +if [ "0$1" == "0" ]; then + echo Please indicate whether to start with raw-reader [rr] or with DataDistribution [dd] + exit 1 +fi + +MYDIR="$(dirname $(readlink -f $0))" +source $MYDIR/setenv.sh + +# This sets up the hardcoded configuration to run the full system workflow on the EPN +export NGPUS=4 +export GPUTYPE=HIP +export SHMSIZE=$(( 128 << 30 )) +export DDSHMSIZE=$(( 128 << 10 )) +export GPUMEMSIZE=$(( 24 << 30 )) +export NUMAGPUIDS=1 +export EXTINPUT=1 +export EPNPIPELINES=1 +export SYNCMODE=1 +export SHMTHROW=0 +export SEVERITY=error + +if [ $1 == "dd" ]; then + export CMD=datadistribution.sh + export GPU_NUM_MEM_REG_CALLBACKS=5 +else + export CMD=raw-reader.sh + export GPU_NUM_MEM_REG_CALLBACKS=3 +fi + +if [ ! -f matbud.root -a -f ctf_dictionary.root ]; then + echo matbud.root or ctf_dictionary.root missing + exit 1 +fi + +if [ "0$FST_TMUX_NOWAIT" != "01" ]; then + ENDCMD="echo END; sleep 1000" +fi + +if [ "0$FST_TMUX_KILLCHAINS" == "01" ]; then + KILLCMD="sleep 60; ps aux | grep 'o2-dpl-run --session' | grep -v grep | awk '{print \$2}' | xargs kill -s INT --;" +fi + +if [ "0$FST_TMUX_LOGPREFIX" != "0" ]; then + LOGCMD0=" &> ${FST_TMUX_LOGPREFIX}_0.log" + LOGCMD1=" &> ${FST_TMUX_LOGPREFIX}_1.log" +fi + +rm -f /dev/shm/*fmq* + +tmux \ + new-session "sleep 0; NUMAID=0 $MYDIR/dpl-workflow.sh $LOGCMD0; $ENDCMD" \; \ + split-window "sleep 45; NUMAID=1 $MYDIR/dpl-workflow.sh $LOGCMD1; $ENDCMD" \; \ + split-window "sleep 90; SEVERITY=debug numactl --interleave=all $MYDIR/$CMD; $KILLCMD $ENDCMD" \; \ + select-layout even-vertical diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 47a471efd4272..4668849be51b4 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -7,28 +7,47 @@ # # Note that this might require a production server to run. # -# This script needs some binary objects (for the moment): -# - matbud.root + ITSdictionary.bin + ctf_dictionary.root +# This script can use additional binary objects which can be optionally provided: +# - matbud.root + ITSdictionary.bin # # authors: D. Rohr / S. Wenzel +if [ "0$O2_ROOT" == "0" ] || [ "0$AEGIS_ROOT" == "0" ]; then + echo Missing O2sim environment + exit 1 +fi + # include jobutils, which notably brings # --> the taskwrapper as a simple control and monitoring tool # (look inside the jobutils.sh file for documentation) # --> utilities to query CPU count . ${O2_ROOT}/share/scripts/jobutils.sh +# make sure that correct format will be used irrespecive of the locale +export LC_NUMERIC=C +export LC_ALL=C NEvents=${NEvents:-10} #550 for full TF (the number of PbPb events) NEventsQED=${NEventsQED:-1000} #35000 for full TF NCPUS=$(getNumberOfPhysicalCPUCores) echo "Found ${NCPUS} physical CPU cores" NJOBS=${NJOBS:-"${NCPUS}"} -SHMSIZE=128000000000 # 128000000000 # Size of shared memory for messages -TPCTRACKERSCRATCHMEMORY=22000000000 +SHMSIZE=${SHMSIZE:-8000000000} # Size of shared memory for messages (use 128 GB for 550 event full TF) +TPCTRACKERSCRATCHMEMORY=${SHMSIZE:-4000000000} # Size of memory allocated by TPC tracker. (Use 24 GB for 550 event full TF) +ENABLE_GPU_TEST=${ENABLE_GPU_TEST:-0} # Run the full system test also on the GPU +GPUMEMSIZE=${GPUMEMSIZE:-6000000000} # Size of GPU memory to use in case ENABBLE_GPU_TEST=1 NTIMEFRAMES=${NTIMEFRAMES:-1} # Number of time frames to process -TFDELAY=100 # Delay in seconds between publishing time frames +TFDELAY=${TFDELAY:-100} # Delay in seconds between publishing time frames NOMCLABELS="--disable-mc" +O2SIMSEED=${O2SIMSEED:--1} +SPLITTRDDIGI=${SPLITTRDDIGI:-1} +NHBPERTF=${NHBPERTF:-128} +RUNFIRSTORBIT=${RUNFIRSTORBIT:-0} +FIRSTSAMPLEDORBIT=${FIRSTSAMPLEDORBIT:-0} +FST_GENERATOR=${FST_GENERATOR:-pythia8hi} +FST_MC_ENGINE=${FST_MC_ENGINE:-TGeant4} + +[ "$FIRSTSAMPLEDORBIT" -lt "$RUNFIRSTORBIT" ] && FIRSTSAMPLEDORBIT=$RUNFIRSTORBIT # allow skipping JOBUTILS_SKIPDONE=ON @@ -45,56 +64,114 @@ HOST=`hostname` TAG="conf=${CONFIG},host=${HOST}${ALIDISTCOMMIT:+,alidist=$ALIDISTCOMMIT}${O2COMMIT:+,o2=$O2COMMIT}" echo "versions,${TAG} alidist=\"${ALIDISTCOMMIT}\",O2=\"${O2COMMIT}\" " > ${METRICFILE} +GLOBALDPLOPT="-b" # --monitoring-backend no-op:// is currently removed due to https://alice.its.cern.ch/jira/browse/O2-1887 + +HBFUTILPARAMS="HBFUtils.nHBFPerTF=${NHBPERTF};HBFUtils.orbitFirst=${RUNFIRSTORBIT};HBFUtils.orbitFirstSampled=${FIRSTSAMPLEDORBIT}" +[ "0$ALLOW_MULTIPLE_TF" != "01" ] && HBFUTILPARAMS+=";HBFUtils.maxNOrbits=${NHBPERTF};" ulimit -n 4096 # Make sure we can open sufficiently many files -mkdir qed +[ $? == 0 ] || (echo Failed setting ulimit && exit 1) +mkdir -p qed cd qed -taskwrapper qedsim.log o2-sim -j $NJOBS -n$NEventsQED -m PIPE ITS MFT FT0 FV0 -g extgen --configKeyValues '"GeneratorExternal.fileName=$O2_ROOT/share/Generators/external/QEDLoader.C;QEDGenParam.yMin=-5;QEDGenParam.yMax=6;QEDGenParam.ptMin=0.001;QEDGenParam.ptMax=1.;Diamond.width[2]=6."' +PbPbXSec="8." +taskwrapper qedsim.log o2-sim --seed $O2SIMSEED -j $NJOBS -n $NEventsQED -m PIPE ITS MFT FT0 FV0 FDD -g extgen -e ${FST_MC_ENGINE} --configKeyValues '"GeneratorExternal.fileName=$O2_ROOT/share/Generators/external/QEDLoader.C;QEDGenParam.yMin=-7;QEDGenParam.yMax=7;QEDGenParam.ptMin=0.001;QEDGenParam.ptMax=1.;Diamond.width[2]=6."' +QED2HAD=$(awk "BEGIN {printf \"%.2f\",`grep xSectionQED qedgenparam.ini | cut -d'=' -f 2`/$PbPbXSec}") +echo "Obtained ratio of QED to hadronic x-sections = $QED2HAD" >> qedsim.log cd .. -GLOBALDPLOPT="-b --monitoring-backend no-op://" -taskwrapper sim.log o2-sim -n $NEvents --skipModules ZDC --configKeyValues "Diamond.width[2]=6." -g pythia8hi -j $NJOBS -taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents --simPrefixQED qed/o2sim --qed-x-section-ratio 3735 ${NOMCLABELS} --firstOrbit 0 --firstBC 0 --skipDet TRD --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} -taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents --simPrefixQED qed/o2sim --qed-x-section-ratio 3735 ${NOMCLABELS} --firstOrbit 0 --firstBC 0 --onlyDet TRD --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "TRDSimParams.digithreads=${NJOBS}" -mkdir raw -taskwrapper itsraw.log o2-its-digi2raw --file-for link --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' -o raw/ITS -taskwrapper mftraw.log o2-mft-digi2raw --file-for link --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' -o raw/MFT -taskwrapper ft0raw.log o2-ft0-digi2raw --file-per-link --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' -o raw/FT0 -taskwrapper tpcraw.log o2-tpc-digits-to-rawzs --file-for link --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' -i tpcdigits.root -o raw/TPC -taskwrapper tofraw.log o2-tof-reco-workflow ${GLOBALDPLOPT} --tof-raw-file-for link --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' --output-type raw --tof-raw-outdir raw/TOF -taskwrapper midraw.log o2-mid-digits-to-raw-workflow ${GLOBALDPLOPT} --mid-raw-outdir raw/MID --mid-raw-perlink --configKeyValues '"HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=0"' +DIGITRDOPTREAL="--configKeyValues \"${HBFUTILPARAMS};TRDSimParams.digithreads=${NJOBS}\" " +if [ $SPLITTRDDIGI == "1" ]; then + DIGITRDOPT="--configKeyValues \"${HBFUTILPARAMS}\" --skipDet TRD" +else + DIGITRDOPT=$DIGITRDOPTREAL +fi + +taskwrapper sim.log o2-sim --seed $O2SIMSEED -n $NEvents --configKeyValues "Diamond.width[2]=6." -g ${FST_GENERATOR} -e ${FST_MC_ENGINE} -j $NJOBS +taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents --simPrefixQED qed/o2sim --qed-x-section-ratio ${QED2HAD} ${NOMCLABELS} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITRDOPT} +[ $SPLITTRDDIGI == "1" ] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --onlyDet TRD --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root ${DIGITRDOPTREAL} +touch digiTRD.log_done + +if [ "0$GENERATE_ITSMFT_DICTIONARIES" == "01" ]; then + taskwrapper itsmftdict1.log o2-its-reco-workflow --trackerCA --disable-mc --configKeyValues '"fastMultConfig.cutMultClusLow=30000;fastMultConfig.cutMultClusHigh=2000000;fastMultConfig.cutMultVtxHigh=500"' + cp ~/alice/O2/Detectors/ITSMFT/ITS/macros/test/CreateDictionaries.C . + taskwrapper itsmftdict2.log root -b -q CreateDictionaries.C++ + rm -f CreateDictionaries_C* CreateDictionaries.C + taskwrapper itsmftdict3.log o2-mft-reco-workflow --disable-mc + cp ~/alice/O2/Detectors/ITSMFT/MFT/macros/test/CreateDictionaries.C . + taskwrapper itsmftdict4.log root -b -q CreateDictionaries.C++ + rm -f CreateDictionaries_C* CreateDictionaries.C +fi + +mkdir -p raw +taskwrapper itsraw.log o2-its-digi2raw --file-for cru -o raw/ITS +taskwrapper mftraw.log o2-mft-digi2raw --file-for link -o raw/MFT +taskwrapper ft0raw.log o2-ft0-digi2raw --file-for link -o raw/FT0 +taskwrapper fv0raw.log o2-fv0-digi2raw --file-for link -o raw/FV0 +taskwrapper fddraw.log o2-fdd-digit2raw --file-for link -o raw/FDD +taskwrapper tpcraw.log o2-tpc-digits-to-rawzs --file-for cru -i tpcdigits.root -o raw/TPC +taskwrapper tofraw.log o2-tof-reco-workflow ${GLOBALDPLOPT} --file-for link --output-type raw --tof-raw-outdir raw/TOF +taskwrapper midraw.log o2-mid-digits-to-raw-workflow ${GLOBALDPLOPT} --mid-raw-outdir raw/MID --file-for link +taskwrapper mchraw.log o2-mch-digits-to-raw --input-file mchdigits.root --output-dir raw/MCH --file-for link +taskwrapper emcraw.log o2-emcal-rawcreator --file-for link -o raw/EMC +taskwrapper phsraw.log o2-phos-digi2raw --file-for link -o raw/PHS +taskwrapper cpvraw.log o2-cpv-digi2raw --file-for link -o raw/CPV +taskwrapper zdcraw.log o2-zdc-digi2raw --file-for link -o raw/ZDC +taskwrapper hmpraw.log o2-hmpid-digits-to-raw-workflow --file-for link --outdir raw/HMP +taskwrapper trdraw.log o2-trd-trap2raw -o raw/TRD --fileper halfcru +taskwrapper ctpraw.log o2-ctp-digi2raw -o raw/CTP --file-per-link + cat raw/*/*.cfg > rawAll.cfg +if [ "0$DISABLE_PROCESSING" == "01" ]; then + echo "Skipping the processing part of the full system test" + exit 0 +fi + # We run the workflow in both CPU-only and With-GPU mode -for STAGE in "NOGPU" "WITHGPU"; do +STAGES="NOGPU" +if [ $ENABLE_GPU_TEST != "0" ]; then + STAGES+=" WITHGPU" +fi +STAGES+=" ASYNC" + +# give a possibility to run the FST with external existing dictionary (i.e. with CREATECTFDICT=0 full_system_test.sh) +[ ! -z "$CREATECTFDICT" ] && SYNCMODEDOCTFDICT="$CREATECTFDICT" || SYNCMODEDOCTFDICT=1 + +for STAGE in $STAGES; do + logfile=reco_${STAGE}.log ARGS_ALL="--session default" DICTCREATION="" if [[ "$STAGE" = "WITHGPU" ]]; then - TPC_GPU_OPT="GPU_proc.deviceNum=0;GPU_global.deviceType=CUDA;GPU_proc.forceMemoryPoolSize=6000000000;GPU_proc.forceHostMemoryPoolSize=3000000000" + export CREATECTFDICT=0 + export GPUTYPE=CUDA + export HOSTMEMSIZE=1000000000 + export SYNCMODE=1 + export CTFINPUT=0 + export SAVECTF=0 + elif [[ "$STAGE" = "ASYNC" ]]; then + export CREATECTFDICT=0 + export GPUTYPE=CPU + export SYNCMODE=0 + export HOSTMEMSIZE=$TPCTRACKERSCRATCHMEMORY + export CTFINPUT=1 + export SAVECTF=0 else - TPC_GPU_OPT="GPU_proc.forceHostMemoryPoolSize=${TPCTRACKERSCRATCHMEMORY}" - DICTCREATION=" | o2-ctf-writer-workflow $ARGS_ALL --output-type dict --save-dict-after 1 --onlyDet ITS,MFT,TPC,TOF,FT0,MID " + export CREATECTFDICT=$SYNCMODEDOCTFDICT + export GPUTYPE=CPU + export SYNCMODE=1 + export HOSTMEMSIZE=$TPCTRACKERSCRATCHMEMORY + export CTFINPUT=0 + export SAVECTF=1 + unset JOBUTILS_JOB_SKIPCREATEDONE fi + export SHMSIZE + export NTIMEFRAMES + export TFDELAY + export GLOBALDPLOPT + export GPUMEMSIZE - logfile=reco_${STAGE}.log - taskwrapper ${logfile} "o2-raw-file-reader-workflow $ARGS_ALL --configKeyValues \"HBFUtils.nHBFPerTF=128\" --delay $TFDELAY --loop $NTIMEFRAMES --max-tf 0 --input-conf rawAll.cfg | -o2-itsmft-stf-decoder-workflow $ARGS_ALL | -o2-itsmft-stf-decoder-workflow $ARGS_ALL --runmft true | -o2-its-reco-workflow $ARGS_ALL --trackerCA ${NOMCLABELS} --clusters-from-upstream --disable-root-output --entropy-encoding --configKeyValues \"fastMultConfig.cutMultClusLow=30;fastMultConfig.cutMultClusHigh=2000;fastMultConfig.cutMultVtxHigh=500\" | -o2-itsmft-entropy-encoder-workflow $ARGS_ALL --runmft true | -o2-tpc-reco-workflow $ARGS_ALL --input-type=zsraw ${NOMCLABELS} --output-type tracks,clusters,encoded-clusters,disable-writer --configKeyValues \"HBFUtils.nHBFPerTF=128;${TPC_GPU_OPT}\" | -o2-ft0-flp-dpl-workflow $ARGS_ALL --disable-root-output | -o2-ft0-reco-workflow $ARGS_ALL --disable-root-input --disable-root-output ${NOMCLABELS} | -o2-ft0-entropy-encoder-workflow $ARGS_ALL | -o2-tpcits-match-workflow $ARGS_ALL --disable-root-input --disable-root-output ${NOMCLABELS} | -o2-mid-raw-to-digits-workflow $ARGS_ALL | -o2-mid-reco-workflow $ARGS_ALL --disable-root-output ${NOMCLABELS} | -o2-mid-entropy-encoder-workflow $ARGS_ALL | -o2-tof-compressor $ARGS_ALL | -o2-tof-reco-workflow $ARGS_ALL --configKeyValues \"HBFUtils.nHBFPerTF=128\" --input-type raw --output-type ctf,clusters,matching-info --disable-root-output ${NOMCLABELS} | -o2-tpc-scdcalib-interpolation-workflow $ARGS_ALL --disable-root-output --disable-root-input ${DICTCREATION} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT}" - + taskwrapper ${logfile} "$O2_ROOT/prodtests/full-system-test/dpl-workflow.sh" # --- record interesting metrics to monitor ---- # boolean flag indicating if workflow completed successfully at all @@ -108,17 +185,20 @@ o2-tpc-scdcalib-interpolation-workflow $ARGS_ALL --disable-root-output --disable walltime=`grep "#walltime" ${logfile}_time | awk '//{print $2}'` echo "walltime_${STAGE},${TAG} value=${walltime}" >> ${METRICFILE} - # memory - maxmem=`awk '/PROCESS MAX MEM/{print $5}' ${logfile}` # in MB - avgmem=`awk '/PROCESS AVG MEM/{print $5}' ${logfile}` # in MB + # GPU reconstruction (also in CPU version) processing time + gpurecotime=`grep "gpu-reconstruction" reco_NOGPU.log | grep -e "Total Wall Time:" | awk '//{printf "%f", $6/1000000}'` + echo "gpurecotime_${STAGE},${TAG} value=${gpurecotime}" >> ${METRICFILE} + + # memory + maxmem=`awk '/PROCESS MAX MEM/{print $5}' ${logfile}` # in MB + avgmem=`awk '/PROCESS AVG MEM/{print $5}' ${logfile}` # in MB echo "maxmem_${STAGE},${TAG} value=${maxmem}" >> ${METRICFILE} echo "avgmem_${STAGE},${TAG} value=${avgmem}" >> ${METRICFILE} # some physics quantities - tpctracks=`grep "tpc-tracker" ${logfile} | grep -e "found.*track" | awk '//{print $4}'` + tpctracks=`grep "gpu-reconstruction" ${logfile} | grep -e "found.*track" | awk '//{print $4}'` echo "tpctracks_${STAGE},${TAG} value=${tpctracks}" >> ${METRICFILE} tpcclusters=`grep -e "Event has.*TPC Clusters" ${logfile} | awk '//{print $5}'` echo "tpcclusters_${STAGE},${TAG} value=${tpcclusters}" >> ${METRICFILE} fi done - diff --git a/prodtests/full_system_test_ci_extra_tests.sh b/prodtests/full_system_test_ci_extra_tests.sh new file mode 100755 index 0000000000000..2d8a165f647fd --- /dev/null +++ b/prodtests/full_system_test_ci_extra_tests.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# +# Set of extra tests which may run after the full_system_test.sh +# Particularly, they use the files generated by the full_system_test.sh +# +. ${O2_ROOT}/share/scripts/jobutils.sh + +if [ "0$O2_ROOT" == "0" ]; then + eval "`alienv shell-helper`" + alienv --no-refresh load O2/latest +fi + +NHBPERTF=${NHBPERTF:-128} # number of HBFs per orbit to expect in pregenerated files + +# Set general arguments +ARGS_ALL="--session default --shm-segment-size $SHMSIZE" + +# below we add individual tests +execname="" +logfile="" + +# FT0 +# run raw->digits conversion from the raw data create elsewhere +execname=o2-raw-file-reader-workflow +taskwrapper ${execname}.log $execname "$ARGS_ALL --configKeyValues \"HBFUtils.nHBFPerTF=${NHBPERTF}\" --detect-tf0 --input-conf raw/FT0/FT0raw.cfg | o2-ft0-flp-dpl-workflow $ARGS_ALL -b" +# and check its correctness +execname=o2-ft0-test-raw-conversion +taskwrapper ${execname}.log $execname +# don't proceed to other tests if error was found +[ ! -f "${execname}.log_done" ] || [ "$?" != 0 ] && exit + +# other tests to add diff --git a/prodtests/full_system_test_pipeline.sh b/prodtests/full_system_test_pipeline.sh new file mode 100755 index 0000000000000..235a590953d8e --- /dev/null +++ b/prodtests/full_system_test_pipeline.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# +# A workflow performing a full system test: +# - simulation of digits +# - creation of raw data +# - reconstruction of raw data +# +# Note that this might require a production server to run. +# +# This script can use additional binary objects which can be optionally provided: +# - matbud.root + ITSdictionary.bin +# +# authors: D. Rohr / S. Wenzel + +# include jobutils, which notably brings +# --> the taskwrapper as a simple control and monitoring tool +# (look inside the jobutils.sh file for documentation) +# --> utilities to query CPU count +. ${O2_ROOT}/share/scripts/jobutils.sh + +export NEvents=${NEvents:-10} #550 for full TF (the number of PbPb events) +export NEventsQED=${NEventsQED:-1000} #35000 for full TF +export NCPUS=$(getNumberOfPhysicalCPUCores) +echo "Found ${NCPUS} physical CPU cores" +export NJOBS=${NJOBS:-"${NCPUS}"} +export SHMSIZE=${SHMSIZE:-8000000000} # Size of shared memory for messages (use 128 GB for 550 event full TF) +export TPCTRACKERSCRATCHMEMORY=${SHMSIZE:-4000000000} # Size of memory allocated by TPC tracker. (Use 24 GB for 550 event full TF) +export ENABLE_GPU_TEST=${ENABLE_GPU_TEST:-0} # Run the full system test also on the GPU +export NTIMEFRAMES=${NTIMEFRAMES:-1} # Number of time frames to process +export TFDELAY=${TFDELAY:-100} # Delay in seconds between publishing time frames +export NOMCLABELS="--disable-mc" +export O2SIMSEED=${O2SIMSEED:--1} + +# allow skipping +JOBUTILS_SKIPDONE=ON +# enable memory monitoring (independent on whether DPL or not) +JOBUTILS_MONITORMEM=ON +# CPU monitoring JOBUTILS_MONITORCPU=ON + +# prepare some metrics file for the monitoring system +METRICFILE=metrics.dat +CONFIG="full_system_test_N${NEvents}" +HOST=`hostname` + +# include header information such as tested alidist tag and O2 tag +TAG="conf=${CONFIG},host=${HOST}${ALIDISTCOMMIT:+,alidist=$ALIDISTCOMMIT}${O2COMMIT:+,o2=$O2COMMIT}" +echo "versions,${TAG} alidist=\"${ALIDISTCOMMIT}\",O2=\"${O2COMMIT}\" " > ${METRICFILE} + +ulimit -n 4096 # Make sure we can open sufficiently many files + +export GLOBALDPLOPT="-b" # --monitoring-backend no-op:// is currently removed due to https://alice.its.cern.ch/jira/browse/O2-1887 + +mkdir -p raw + +# create the full workflow as json +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +${DIR}/full-system-test/create_full_system_pipeline.py + +# create a visualization of the pipeline-workflow (in workflow.gv.pdf) and print the list of tasks +${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json --visualize-workflow --list-tasks + +# run the workflow (not constraining in parallelism) until RAW creation is finished +${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json --target-labels RAW + +# We run the workflow in both CPU-only and With-GPU mode +STAGES="NOGPU" +if [ $ENABLE_GPU_TEST != "0" ]; then + STAGES+=" WITHGPU" +fi +STAGES+=" ASYNC" +for STAGE in $STAGES; do + logfile=reco_${STAGE}.log + export GLOBALDPLOPT + + # run each of the reco but in strictly serial mode + ${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json -tt reco_${STAGE} -jmax 1 + + # --- record interesting metrics to monitor ---- + # boolean flag indicating if workflow completed successfully at all + RC=$? + SUCCESS=0 + [ -f "${logfile}_done" ] && [ "$RC" = 0 ] && SUCCESS=1 + echo "success_${STAGE},${TAG} value=${SUCCESS}" >> ${METRICFILE} + + if [ "${SUCCESS}" = "1" ]; then + # runtime + walltime=`grep "#walltime" ${logfile}_time | awk '//{print $2}'` + echo "walltime_${STAGE},${TAG} value=${walltime}" >> ${METRICFILE} + + # GPU reconstruction (also in CPU version) processing time + gpurecotime=`grep "gpu-reconstruction" reco_NOGPU.log | grep -e "Total Wall Time:" | awk '//{printf "%f", $6/1000000}'` + echo "gpurecotime_${STAGE},${TAG} value=${gpurecotime}" >> ${METRICFILE} + + # memory + maxmem=`awk '/PROCESS MAX MEM/{print $5}' ${logfile}` # in MB + avgmem=`awk '/PROCESS AVG MEM/{print $5}' ${logfile}` # in MB + echo "maxmem_${STAGE},${TAG} value=${maxmem}" >> ${METRICFILE} + echo "avgmem_${STAGE},${TAG} value=${avgmem}" >> ${METRICFILE} + + # some physics quantities + tpctracks=`grep "gpu-reconstruction" ${logfile} | grep -e "found.*track" | awk '//{print $4}'` + echo "tpctracks_${STAGE},${TAG} value=${tpctracks}" >> ${METRICFILE} + tpcclusters=`grep -e "Event has.*TPC Clusters" ${logfile} | awk '//{print $5}'` + echo "tpcclusters_${STAGE},${TAG} value=${tpcclusters}" >> ${METRICFILE} + fi +done diff --git a/prodtests/sim_challenge.sh b/prodtests/sim_challenge.sh index e7d582f799be7..fb059d7999433 100755 --- a/prodtests/sim_challenge.sh +++ b/prodtests/sim_challenge.sh @@ -8,6 +8,8 @@ # ----------- START WITH ACTUAL SCRIPT --------------------------- +if [ -z "$SHMSIZE" ]; then export SHMSIZE=10000000000; fi + # default number of events nevPP=10 nevPbPb=10 @@ -19,14 +21,17 @@ intRatePbPb=50 # default collision system collSyst="pp" -generPP="pythia8" +generPP="pythia8pp" generPbPb="pythia8hi" # default sim engine engine="TGeant3" # options to pass to every workflow -gloOpt=" -b --run --shm-segment-size 10000000000" +gloOpt=" -b --run --shm-segment-size $SHMSIZE" + +# ITS reco options depends on pp or pbpb +ITSRecOpt="" # option to set the number of sim workers simWorker="" @@ -34,7 +39,7 @@ simWorker="" # option to set the number of tpc-lanes tpcLanes="" -Usage() +Usage() { echo "Usage: ${0##*/} [-s system /pp[Def] or pbpb/] [-r IR(kHz) /Def = $intRatePP(pp)/$intRatePbPb(pbpb)] [-n Number of events /Def = $nevPP(pp) or $nevPbPb(pbpb)/] [-e TGeant3|TGeant4] [-f fromstage sim|digi|reco /Def = sim]" exit @@ -42,23 +47,24 @@ Usage() fromstage="sim" while [ $# -gt 0 ] ; do - case $1 in - -n) nev=$2; shift 2 ;; - -s) collSyst=$2; shift 2 ;; - -r) intRate=$2; shift 2 ;; - -e) engine=$2; shift 2 ;; - -f) fromstage=$2; shift 2 ;; - -j) simWorker="-j $2"; shift 2 ;; - -l) tpcLanes="--tpc-lanes $2"; shift 2 ;; - -h) Usage ;; - *) echo "Wrong input"; Usage; - esac + case $1 in + -n) nev=$2; shift 2 ;; + -s) collSyst=$2; shift 2 ;; + -r) intRate=$2; shift 2 ;; + -e) engine=$2; shift 2 ;; + -f) fromstage=$2; shift 2 ;; + -j) simWorker="-j $2"; shift 2 ;; + -l) tpcLanes="--tpc-lanes $2"; shift 2 ;; + -h) Usage ;; + *) echo "Wrong input"; Usage; + esac done # convert to lower case (the bash construct ${collSyst,,} is less portable) collSyst=`echo "$collSyst" | awk '{print tolower($0)}'` if [ "$collSyst" == "pp" ]; then gener="$generPP" + ITSRecOpt=" --configKeyValues \"ITSVertexerParam.phiCut=0.5;ITSVertexerParam.clusterContributorsCut=3;ITSVertexerParam.tanLambdaCut=0.2\"" [[ "nev" -lt "1" ]] && nev="$nevPP" [[ "intRate" -lt "1" ]] && intRate="$intRatePP" elif [ "$collSyst" == "pbpb" ]; then @@ -72,15 +78,18 @@ fi dosim="0" dodigi="0" +dotrdtrap="0" doreco="0" # convert to lowercase fromstage=`echo "$fromstage" | awk '{print tolower($0)}'` if [ "$fromstage" == "sim" ]; then dosim="1" dodigi="1" + dotrdtrap="1" doreco="1" elif [ "$fromstage" == "digi" ]; then dodigi="1" + dotrdtrap="1" doreco="1" elif [ "$fromstage" == "reco" ]; then doreco="1" @@ -93,10 +102,10 @@ fi if [ "$dosim" == "1" ]; then #--------------------------------------------------- echo "Running simulation for $nev $collSyst events with $gener generator and engine $engine" - taskwrapper sim.log o2-sim -n"$nev" --configKeyValue "Diamond.width[2]=6." -g "$gener" -e "$engine" $simWorker + taskwrapper sim.log o2-sim -n"$nev" --configKeyValues "Diamond.width[2]=6." -g "$gener" -e "$engine" $simWorker ##------ extract number of hits - root -q -b -l ${O2_ROOT}/share/macro/analyzeHits.C > hitstats.log + taskwrapper hitstats.log root -q -b -l ${O2_ROOT}/share/macro/analyzeHits.C fi if [ "$dodigi" == "1" ]; then @@ -108,14 +117,22 @@ if [ "$dodigi" == "1" ]; then #root -b -q O2/Detectors/ITSMFT/ITS/macros/test/CheckDigits.C+ fi +if [ "$dotrdtrap" == "1" ]; then + echo "Running TRD trap simulator" + taskwrapper trdtrap.log o2-trd-trap-sim $gloOpt + echo "Return status of trd trap sim: $?" +fi + + if [ "$doreco" == "1" ]; then + echo "Running TPC reco flow" #needs TPC digitized data - taskwrapper tpcreco.log o2-tpc-reco-workflow $gloOpt --tpc-digit-reader \"--infile tpcdigits.root\" --input-type digits --output-type clusters,tracks --tpc-track-writer \"--treename events --track-branch-name Tracks --trackmc-branch-name TracksMCTruth\" + taskwrapper tpcreco.log o2-tpc-reco-workflow $gloOpt --input-type digits --output-type clusters,tracks,send-clusters-per-sector --configKeyValues "GPU_rec.maxTrackQPt=20" echo "Return status of tpcreco: $?" echo "Running ITS reco flow" - taskwrapper itsreco.log o2-its-reco-workflow --trackerCA --async-phase $gloOpt + taskwrapper itsreco.log o2-its-reco-workflow --trackerCA --tracking-mode async $gloOpt $ITSRecOpt echo "Return status of itsreco: $?" # existing checks @@ -127,32 +144,78 @@ if [ "$doreco" == "1" ]; then taskwrapper mftreco.log o2-mft-reco-workflow $gloOpt echo "Return status of mftreco: $?" + echo "Running MCH reco flow" + taskwrapper mchreco.log o2-mch-reco-workflow $gloOpt + echo "Return status of mchreco: $?" + echo "Running FT0 reco flow" #needs FT0 digitized data taskwrapper ft0reco.log o2-ft0-reco-workflow $gloOpt echo "Return status of ft0reco: $?" - echo "Running ITS-TPC macthing flow" + echo "Running FDD reco flow" + #needs FDD digitized data + taskwrapper fddreco.log o2-fdd-reco-workflow $gloOpt + echo "Return status of fddreco: $?" + + echo "Running FV0 reco flow" + #needs FV0 digitized data + taskwrapper fv0reco.log o2-fv0-reco-workflow $gloOpt + echo "Return status of fv0reco: $?" + + echo "Running MID reco flow" + #needs MID digitized data + taskwrapper midreco.log "o2-mid-digits-reader-workflow | o2-mid-reco-workflow $gloOpt" + echo "Return status of midreco: $?" + + echo "Running ITS-TPC matching flow" #needs results of o2-tpc-reco-workflow, o2-its-reco-workflow and o2-fit-reco-workflow - taskwrapper itstpcMatch.log o2-tpcits-match-workflow $gloOpt --tpc-track-reader \"tpctracks.root\" --tpc-native-cluster-reader \"--infile tpc-native-clusters.root\" + taskwrapper itstpcMatch.log o2-tpcits-match-workflow $gloOpt echo "Return status of itstpcMatch: $?" - echo "Running ITSTPC-TOF macthing flow" + echo "Running TRD matching to ITS-TPC and TPC" + #needs results of o2-tpc-reco-workflow, o2-tpcits-match-workflow and o2-trd-tracklet-transformer + taskwrapper trdTrkltTransf.log o2-trd-tracklet-transformer $gloOpt + echo "Return status of trdTrkltTransf: $?" + taskwrapper trdMatch.log o2-trd-global-tracking $gloOpt + echo "Return status of trdTracker: $?" + + echo "Running MFT-MCH matching flow" + #needs results of o2-mch-reco-workflow and o2-mft-reco-workflow + taskwrapper mftmchMatch.log o2-globalfwd-matcher-workflow $gloOpt + echo "Return status of mftmchMatch: $?" + + echo "Running TOF reco flow to produce clusters" #needs results of TOF digitized data and results of o2-tpcits-match-workflow - taskwrapper tofMatch.log o2-tof-reco-workflow $gloOpt - echo "Return status of its-tpc-tof match: $?" + taskwrapper tofReco.log o2-tof-reco-workflow $gloOpt + echo "Return status of tof cluster reco : $?" + + echo "Running Track-TOF macthing flow" + #needs results of TOF clusters data from o2-tof-reco-workflow and results of o2-tpc-reco-workflow and ITS-TPC matching + taskwrapper tofMatchTracks.log o2-tof-matcher-workflow $gloOpt + echo "Return status of o2-tof-matcher-workflow: $?" + + echo "Running TOF matching QA" + #need results of ITSTPC-TOF matching (+ TOF clusters and ITS-TPC tracks) + taskwrapper tofmatch_qa.log root -b -q -l $O2_ROOT/share/macro/checkTOFMatching.C + echo "Return status of TOF matching qa: $?" echo "Running primary vertex finding flow" #needs results of TPC-ITS matching and FIT workflows taskwrapper pvfinder.log o2-primary-vertexing-workflow $gloOpt echo "Return status of primary vertexing: $?" - echo "Running TOF matching QA" - #need results of ITSTPC-TOF matching (+ TOF clusters and ITS-TPC tracks) - root -b -q -l $O2_ROOT/share/macro/checkTOFMatching.C 1>tofmatch_qa.log 2>&1 - echo "Return status of TOF matching qa: $?" + echo "Running secondary vertex finding flow" + #needs results of all trackers + P.Vertexer + taskwrapper svfinder.log o2-secondary-vertexing-workflow $gloOpt + echo "Return status of secondary vertexing: $?" + + echo "Running ZDC reconstruction" + #need ZDC digits + taskwrapper zdcreco.log o2-zdc-digits-reco $gloOpt + echo "Return status of ZDC reconstruction: $?" echo "Producing AOD" - taskwrapper aod.log o2-reco-standalone-aod-producer + taskwrapper aod.log o2-aod-producer-workflow --aod-writer-keep dangling --aod-writer-resfile "AO2D" --aod-writer-resmode UPDATE --aod-timeframe-id 1 echo "Return status of AOD production: $?" fi diff --git a/prodtests/sim_performance_test.sh b/prodtests/sim_performance_test.sh index 426c80eea12a2..53e83fa08f56d 100755 --- a/prodtests/sim_performance_test.sh +++ b/prodtests/sim_performance_test.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Script performing a standard collection of -# simulation / reco / etc. tasks in order to collect benchmark +# Script performing a standard collection of +# simulation / reco / etc. tasks in order to collect benchmark # metrics that can be fed into a time-series database for long term monitoring # In principle we'd like to take O2 from the last nightly @@ -9,7 +9,7 @@ # number of events / take from first argument or default NEVENTS=${1:-"2"} # generator / take from second argument or default -GEN=${2:-"pythia8"} +GEN=${2:-"pythia8pp"} # STARTSEED SEED=1234 @@ -59,7 +59,7 @@ INITTIME=`grep "Init: Real time" $LOGFILE | awk '//{print $5}'` # initialization memory INITMEM=`grep "Init: Memory" $LOGFILE | awk '//{print $5}'` -# get the actual transport runtime +# get the actual transport runtime RUNTIME=`grep " Real time" $LOGFILE | grep -v "Init:" | awk '//{print $4}'` # initialization memory TOTALMEM=`grep " Memory used" $LOGFILE | grep -v "Init:" | awk '//{print $4}'` diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 5ad1e169afb20..a2ef0fa8b135b 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -1,22 +1,24 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # allsim is not a real library (i.e. not something that is built) but a # convenient bag for all the deps needed in the executables below add_library(allsim INTERFACE) -if(ENABLE_UPGRADES) target_link_libraries(allsim INTERFACE O2::SimConfig + O2::CommonUtils O2::Steer O2::SimSetup + O2::SimulationDataFormat FairMQ::FairMQ O2::CPVSimulation O2::DetectorsPassive @@ -25,9 +27,6 @@ target_link_libraries(allsim O2::Field O2::HMPIDSimulation O2::ITSSimulation - O2::ITS3Simulation - O2::ITS4Simulation - O2::MCHBase O2::MCHSimulation O2::MFTSimulation O2::MIDSimulation @@ -38,34 +37,11 @@ target_link_libraries(allsim O2::TRDSimulation O2::FV0Simulation O2::ZDCSimulation + $<$<BOOL:${ENABLE_UPGRADES}>:O2::Alice3DetectorsPassive> + $<$<BOOL:${ENABLE_UPGRADES}>:O2::ITS3Simulation> + $<$<BOOL:${ENABLE_UPGRADES}>:O2::TRKSimulation> + $<$<BOOL:${ENABLE_UPGRADES}>:O2::FT3Simulation> O2::Generators) -else() -target_link_libraries(allsim - INTERFACE O2::SimConfig - O2::Steer - O2::SimSetup - FairMQ::FairMQ - O2::CPVSimulation - O2::DetectorsPassive - O2::EMCALSimulation - O2::FDDSimulation - O2::Field - O2::HMPIDSimulation - O2::ITSSimulation - O2::MCHBase - O2::MCHSimulation - O2::MFTSimulation - O2::MIDSimulation - O2::PHOSSimulation - O2::FT0Simulation - O2::TOFSimulation - O2::TPCSimulation - O2::TRDSimulation - O2::FV0Simulation - O2::ZDCSimulation - O2::Generators) -endif() - add_library(internal::allsim ALIAS allsim) @@ -81,7 +57,9 @@ o2_add_executable(serial o2_add_executable(sim SOURCES o2sim_parallel.cxx - PUBLIC_LINK_LIBRARIES internal::allsim O2::Framework) + PUBLIC_LINK_LIBRARIES internal::allsim O2::Version + TARGETVARNAME simdriver) + o2_add_executable(primary-server-device-runner COMPONENT_NAME sim @@ -97,7 +75,7 @@ o2_add_executable(hit-merger-runner SOURCES O2HitMergerRunner.cxx PUBLIC_LINK_LIBRARIES internal::allsim) -o2_data_file(COPY o2simtopology.json DESTINATION config) +o2_data_file(COPY o2simtopology_template.json DESTINATION config) # * # add a complex simulation as a unit test (if simulation was enabled) # perform @@ -116,10 +94,9 @@ message(STATUS "SIMENV = ${SIMENV}") o2_name_target(sim NAME o2simExecutable IS_EXE) o2_name_target(sim-serial NAME o2simSerialExecutable IS_EXE) -o2_add_test_wrapper(NAME o2sim_G4 +if (BUILD_TESTING) +o2_add_test_command(NAME o2sim_G4 WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT - MAX_ATTEMPTS 2 TIMEOUT 400 COMMAND $<TARGET_FILE:${o2simExecutable}> COMMAND_LINE_ARGS -n @@ -130,6 +107,10 @@ o2_add_test_wrapper(NAME o2sim_G4 TGeant4 -o o2simG4 + --chunkSize + 2 + --skipModules + MFT ZDC ENVIRONMENT "${SIMENV}" LABELS "g4;sim;long") @@ -140,26 +121,25 @@ set_tests_properties(o2sim_G4 set_property(TEST o2sim_G4 APPEND PROPERTY ENVIRONMENT ${G4ENV}) # # note that the MT is currently only supported in the non FairMQ version -o2_add_test_wrapper(NAME o2sim_G4_mt - WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT - MAX_ATTEMPTS 2 - TIMEOUT 400 - COMMAND $<TARGET_FILE:${o2simSerialExecutable}> - COMMAND_LINE_ARGS -n - 1 - -e - TGeant4 - --isMT - on - -o - o2simG4MT - ENVIRONMENT "${SIMENV}" - LABELS "g4;sim;long") -set_tests_properties(o2sim_G4_mt - PROPERTIES PASS_REGULAR_EXPRESSION - "Macro finished succesfully") -set_property(TEST o2sim_G4_mt APPEND PROPERTY ENVIRONMENT ${G4ENV}) +# # switched off +# o2_add_test_command(NAME o2sim_G4_mt +# WORKING_DIRECTORY ${SIMTESTDIR} +# TIMEOUT 400 +# COMMAND $<TARGET_FILE:${o2simSerialExecutable}> +# COMMAND_LINE_ARGS -n +# 1 +# -e +# TGeant4 +# --isMT +# on +# -o +# o2simG4MT +# ENVIRONMENT "${SIMENV}" +# LABELS "g4;sim;long") +#set_tests_properties(o2sim_G4_mt +# PROPERTIES PASS_REGULAR_EXPRESSION +# "Macro finished succesfully") +#set_property(TEST o2sim_G4_mt APPEND PROPERTY ENVIRONMENT ${G4ENV}) o2_add_test(CheckStackG4 @@ -167,17 +147,15 @@ o2_add_test(CheckStackG4 NAME o2sim_checksimkinematics_G4 WORKING_DIRECTORY ${SIMTESTDIR} COMMAND_LINE_ARGS o2simG4 - PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::Steer O2::ITSSimulation NO_BOOST_TEST LABELS "g4;sim;long") set_tests_properties(o2sim_checksimkinematics_G4 PROPERTIES FIXTURES_REQUIRED G4) -o2_add_test_wrapper(NAME o2sim_G3 +o2_add_test_command(NAME o2sim_G3 WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT - MAX_ATTEMPTS 3 COMMAND $<TARGET_FILE:${o2simExecutable}> COMMAND_LINE_ARGS -n 2 @@ -187,6 +165,10 @@ o2_add_test_wrapper(NAME o2sim_G3 TGeant3 -o o2simG3 + -g + pythia8pp + --chunkSize + 10 LABELS g3 sim long ENVIRONMENT "${SIMENV}" ) @@ -206,7 +188,7 @@ o2_add_test(CheckStackG3 NAME o2sim_checksimkinematics_G3 WORKING_DIRECTORY ${SIMTESTDIR} COMMAND_LINE_ARGS o2simG3 - PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat O2::Steer O2::ITSSimulation NO_BOOST_TEST LABELS "g3;sim;long") @@ -215,22 +197,20 @@ set_tests_properties(o2sim_checksimkinematics_G3 PROPERTIES FIXTURES_REQUIRED G3) -o2_add_test_wrapper(NAME o2sim_hepmc +o2_add_test_command(NAME o2sim_hepmc WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT - MAX_ATTEMPTS 2 TIMEOUT 400 COMMAND $<TARGET_FILE:${o2simExecutable}> COMMAND_LINE_ARGS -n - 2 - -j - 2 - -g - hepmc - --configKeyValues - "HepMC.fileName=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2" + 2 + -j + 2 + -g + hepmc + --configKeyValues +"HepMC.fileName=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2" -o - o2simhepmc + o2simhepmc LABELS long sim hepmc3 ENVIRONMENT "${SIMENV}") @@ -239,9 +219,8 @@ set_tests_properties(o2sim_hepmc "SIMULATION RETURNED SUCCESFULLY") # somewhat analyse the logfiles as another means to detect problems -o2_add_test_wrapper(NAME o2sim_G3_checklogs +o2_add_test_command(NAME o2sim_G3_checklogs WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT COMMAND ${CMAKE_SOURCE_DIR}/run/simlogcheck.sh COMMAND_LINE_ARGS o2simG3_serverlog o2simG3_mergerlog o2simG3_workerlog0 LABELS long sim hepmc3) @@ -250,13 +229,15 @@ set_tests_properties(o2sim_G3_checklogs PROPERTIES FIXTURES_REQUIRED G3) # somewhat analyse the logfiles as another means to detect problems -o2_add_test_wrapper(NAME o2sim_G4_checklogs +o2_add_test_command(NAME o2sim_G4_checklogs WORKING_DIRECTORY ${SIMTESTDIR} - DONT_FAIL_ON_TIMEOUT COMMAND ${CMAKE_SOURCE_DIR}/run/simlogcheck.sh COMMAND_LINE_ARGS o2simG4_serverlog o2simG4_mergerlog o2simG4_workerlog0 - LABELS long sim + LABELS long sim ) set_tests_properties(o2sim_G3_checklogs PROPERTIES FIXTURES_REQUIRED G4) +endif() + +install(FILES o2-sim-client.py PERMISSIONS GROUP_READ GROUP_EXECUTE OWNER_EXECUTE OWNER_WRITE OWNER_READ WORLD_EXECUTE WORLD_READ DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/run/O2HitMerger.h b/run/O2HitMerger.h index 1815fe4ed5eff..6f5d5ff5cb3ee 100644 --- a/run/O2HitMerger.h +++ b/run/O2HitMerger.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -60,12 +61,17 @@ #include "CommonUtils/ShmManager.h" #include <map> #include <vector> +#include <list> #include <csignal> #include <mutex> +#include <filesystem> + +#include "SimPublishChannelHelper.h" #ifdef ENABLE_UPGRADES #include <ITS3Simulation/Detector.h> -#include <ITS4Simulation/Detector.h> +#include <TRKSimulation/Detector.h> +#include <FT3Simulation/Detector.h> #endif namespace o2 @@ -97,6 +103,8 @@ class O2HitMerger : public FairMQDevice O2HitMerger() { mTimer.Start(); + mInitialOutputDir = std::filesystem::current_path().string(); + mCurrentOutputDir = mInitialOutputDir; } /// Default destructor @@ -113,23 +121,30 @@ class O2HitMerger : public FairMQDevice /// Overloads the InitTask() method of FairMQDevice void InitTask() final { - signal(SIGSEGV, sighandler); + LOG(INFO) << "INIT HIT MERGER"; + // signal(SIGSEGV, sighandler); ROOT::EnableThreadSafety(); std::string outfilename("o2sim_merged_hits.root"); // default name // query the sim config ... which is used to extract the filenames - if (o2::devices::O2SimDevice::querySimConfig(fChannels.at("primary-get").at(0))) { + if (o2::devices::O2SimDevice::querySimConfig(fChannels.at("o2sim-primserv-info").at(0))) { outfilename = o2::base::NameConf::getMCKinematicsFileName(o2::conf::SimConfig::Instance().getOutPrefix().c_str()); mNExpectedEvents = o2::conf::SimConfig::Instance().getNEvents(); } + mAsService = o2::conf::SimConfig::Instance().asService(); + mOutFileName = outfilename.c_str(); mOutFile = new TFile(outfilename.c_str(), "RECREATE"); mOutTree = new TTree("o2sim", "o2sim"); mOutTree->SetDirectory(mOutFile); - initDetInstances(); - // has to be after init of Detectors - o2::utils::ShmManager::Instance().attachToGlobalSegment(); + // detectors init only once + if (mDetectorInstances.size() == 0) { + initDetInstances(); + // has to be after init of Detectors + o2::utils::ShmManager::Instance().attachToGlobalSegment(); + initHitFiles(o2::conf::SimConfig::Instance().getOutPrefix()); + } // init pipe auto pipeenv = getenv("ALICE_O2SIMMERGERTODRIVER_PIPE"); @@ -141,13 +156,75 @@ class O2HitMerger : public FairMQDevice } // if no data to expect we shut down the device NOW since it would otherwise hang - // (because we use OnData and would never receive anything) if (mNExpectedEvents == 0) { - LOG(INFO) << "NOT EXPECTING ANY DATA; SHUTTING DOWN"; - raise(SIGINT); + if (mAsService) { + waitForControlInput(); + } else { + LOG(INFO) << "NOT EXPECTING ANY DATA; SHUTTING DOWN"; + raise(SIGINT); + } } } + bool setWorkingDirectory(std::string const& dir) + { + namespace fs = std::filesystem; + + // sets the output directory where simulation files are produced + // and creates it when it doesn't exist already + + // 2 possibilities: + // a) dir is relative dir. Then we interpret it as relative to the initial + // base directory + // b) or dir is itself absolut. + try { + fs::current_path(fs::path(mInitialOutputDir)); // <--- to make sure relative start is always the same + if (!dir.empty()) { + auto absolutePath = fs::absolute(fs::path(dir)); + if (!fs::exists(absolutePath)) { + if (!fs::create_directory(absolutePath)) { + LOG(ERROR) << "Could not create directory " << absolutePath.string(); + return false; + } + } + // set the current path + fs::current_path(absolutePath.string().c_str()); + mCurrentOutputDir = fs::current_path().string(); + } + LOG(INFO) << "FINAL PATH " << mCurrentOutputDir; + } catch (std::exception e) { + LOG(ERROR) << " could not change path to " << dir; + } + return true; + } + + // function for intermediate/on-the-fly reinitializations + bool ReInit(o2::conf::SimReconfigData const& reconfig) + { + if (reconfig.stop) { + return false; + } + if (!setWorkingDirectory(reconfig.outputDir)) { + return false; + } + + std::string outfilename("o2sim_merged_hits.root"); // default name + outfilename = o2::base::NameConf::getMCKinematicsFileName(reconfig.outputPrefix); + mNExpectedEvents = reconfig.nEvents; + mOutFileName = outfilename.c_str(); + mOutFile = new TFile(outfilename.c_str(), "RECREATE"); + mOutTree = new TTree("o2sim", "o2sim"); + mOutTree->SetDirectory(mOutFile); + + // reinit detectorInstance files (also make sure they are closed before continuing) + initHitFiles(reconfig.outputPrefix); + + // clear "counter" datastructures + mPartsCheckSum.clear(); + mEventChecksum = 0; + return true; + } + template <typename T, typename V> V insertAdd(std::map<T, V>& m, T const& key, V value) { @@ -179,49 +256,23 @@ class O2HitMerger : public FairMQDevice LOG(DEBUG2) << "I1 " << ptr[0] << " NAME " << id.getName() << " MB " << data.At(index)->GetSize() / 1024. / 1024.; - TTree* tree = mEventToTTreeMap[eventID]; - // get the detector that can interpret it auto detector = mDetectorInstances[id].get(); if (detector) { - detector->fillHitBranch(*tree, data, index); + detector->collectHits(eventID, data, index); } } } - template <typename T> - void fillBranch(int eventID, std::string const& name, T* ptr) - { - // fetch tree into which to fill - const std::lock_guard<std::mutex> lock(mMapsMtx); - auto iter = mEventToTTreeMap.find(eventID); - if (iter == mEventToTTreeMap.end()) { - { - std::stringstream str; - str << "memfile" << eventID; - mEventToTMemFileMap[eventID] = new TMemFile(str.str().c_str(), "RECREATE"); - } - { - std::stringstream str; - str << "o2sim" << eventID; - mEventToTTreeMap[eventID] = new TTree(str.str().c_str(), str.str().c_str()); - mEventToTTreeMap[eventID]->SetDirectory(mEventToTMemFileMap[eventID]); - } - } - TTree* tree = mEventToTTreeMap[eventID]; - - auto br = o2::base::getOrMakeBranch(*tree, name.c_str(), &ptr); - br->SetAddress(&ptr); - br->Fill(); - br->ResetAddress(); - } - - template <typename T> - void consumeData(int eventID, std::string name, FairMQParts& data, int& index) + template <typename T, typename BT> + void consumeData(int eventID, FairMQParts& data, int& index, BT& buffer) { auto decodeddata = o2::base::decodeTMessage<T*>(data, index); - fillBranch(eventID, name, decodeddata); - delete decodeddata; + if (buffer.find(eventID) == buffer.end()) { + buffer[eventID] = typename BT::mapped_type(); + } + buffer[eventID].push_back(decodeddata); + // delete decodeddata; --> we store the pointers index++; } @@ -230,11 +281,39 @@ class O2HitMerger : public FairMQDevice // also creates the MCEventHeader branch expected for physics analysis void fillSubEventInfoEntry(o2::data::SubEventInfo& info) { - auto infoptr = &info; - fillBranch(info.eventID, "SubEventInfo", infoptr); - // a separate branch for MCEventHeader to be backward compatible - auto headerptr = &info.mMCEventHeader; - fillBranch(info.eventID, "MCEventHeader.", headerptr); + if (mSubEventInfoBuffer.find(info.eventID) == mSubEventInfoBuffer.end()) { + mSubEventInfoBuffer[info.eventID] = std::list<o2::data::SubEventInfo*>(); + } + mSubEventInfoBuffer[info.eventID].push_back(&info); + } + + bool waitForControlInput() + { + o2::simpubsub::publishMessage(fChannels["merger-notifications"].at(0), o2::simpubsub::simStatusString("MERGER", "STATUS", "AWAITING INPUT")); + + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto channel = FairMQChannel{"o2sim-control", "sub", factory}; + auto controlsocketname = getenv("ALICE_O2SIMCONTROL"); + LOG(INFO) << "SOCKETNAME " << controlsocketname; + channel.Connect(std::string(controlsocketname)); + channel.Validate(); + std::unique_ptr<FairMQMessage> reply(channel.NewMessage()); + + LOG(INFO) << "WAITING FOR INPUT"; + if (channel.Receive(reply) > 0) { + auto data = reply->GetData(); + auto size = reply->GetSize(); + + std::string command(reinterpret_cast<char const*>(data), size); + LOG(INFO) << "message: " << command; + + o2::conf::SimReconfigData reconfig; + o2::conf::parseSimReconfigFromString(command, reconfig); + return ReInit(reconfig); + } else { + LOG(INFO) << "NOTHING RECEIVED"; + } + return true; } bool ConditionalRun() override @@ -246,7 +325,17 @@ class O2HitMerger : public FairMQDevice LOG(ERROR) << "Some error occurred on socket during receive on sim data"; return true; // keep going } - return handleSimData(request, 0); + TStopwatch timer; + timer.Start(); + auto more = handleSimData(request, 0); + LOG(INFO) << "HitMerger processing took " << timer.RealTime(); + if (!more && mAsService) { + LOG(INFO) << " CONTROL "; + // if we are done treating data we may go back to init phase + // for the next batch + return waitForControlInput(); + } + return more; } bool handleSimData(FairMQParts& data, int /*index*/) @@ -260,30 +349,28 @@ class O2HitMerger : public FairMQDevice LOG(INFO) << "SIMDATA channel got " << data.Size() << " parts for event " << info.eventID << " part " << info.part << " out of " << info.nparts; fillSubEventInfoEntry(info); - consumeData<std::vector<o2::MCTrack>>(info.eventID, "MCTrack", data, index); - consumeData<std::vector<o2::TrackReference>>(info.eventID, "TrackRefs", data, index); - consumeData<o2::dataformats::MCTruthContainer<o2::TrackReference>>(info.eventID, "IndexedTrackRefs", data, index); + consumeData<std::vector<o2::MCTrack>>(info.eventID, data, index, mMCTrackBuffer); + consumeData<std::vector<o2::TrackReference>>(info.eventID, data, index, mTrackRefBuffer); while (index < data.Size()) { consumeHits(info.eventID, data, index); } - // set the number of entries in the tree - auto tree = mEventToTTreeMap[info.eventID]; - auto memfile = mEventToTMemFileMap[info.eventID]; - tree->SetEntries(tree->GetEntries() + 1); - LOG(INFO) << "tree has file " << tree->GetDirectory()->GetFile()->GetName(); - mEntries++; if (isDataComplete<uint32_t>(accum, info.nparts)) { - LOG(INFO) << "EVERYTHING IS HERE FOR EVENT " << info.eventID << "\n"; + LOG(INFO) << "Event " << info.eventID << " complete. Marking as flushable"; + mFlushableEvents[info.eventID] = true; // check if previous flush finished - if (mMergerIOThread.joinable()) { - mMergerIOThread.join(); + // start merging only when no merging currently happening + // Like this we don't have to join/wait on the thread here and do not block the outer ConditionalRun handling + // TODO: Let this run fully asynchronously (not even triggered by ConditionalRun) + if (!mergingInProgress) { + if (mMergerIOThread.joinable()) { + mMergerIOThread.join(); + } + // start hit merging and flushing in a separate thread in order not to block + mMergerIOThread = std::thread([info, this]() { mergingInProgress = true; mergeAndFlushData(); mergingInProgress = false; }); } - // start hit merging and flushing in a separate thread in order not to block - mMergerIOThread = std::thread([info, this]() { mergeAndFlushData(info.eventID); }); - mEventChecksum += info.eventID; // we also need to check if we have all events if (isDataComplete<uint32_t>(mEventChecksum, info.maxEvents)) { @@ -293,6 +380,10 @@ class O2HitMerger : public FairMQDevice if (mMergerIOThread.joinable()) { mMergerIOThread.join(); } + mMergerIOThread = std::thread([info, this]() { mergingInProgress = true; mergeAndFlushData(); mergingInProgress = false; }); + if (mMergerIOThread.joinable()) { + mMergerIOThread.join(); + } expectmore = false; } @@ -305,19 +396,14 @@ class O2HitMerger : public FairMQDevice } if (!expectmore) { // somehow FairMQ has difficulties shutting down; helping manually - raise(SIGINT); + // raise(SIGINT); } return expectmore; } void cleanEvent(int eventID) { - // remove tree for that eventID - const std::lock_guard<std::mutex> lock(mMapsMtx); - delete mEventToTTreeMap[eventID]; - delete mEventToTMemFileMap[eventID]; - mEventToTTreeMap.erase(eventID); - mEventToTMemFileMap.erase(eventID); // remove memfile + // cleanup intermediate per-Event buffers } template <typename T> @@ -325,92 +411,91 @@ class O2HitMerger : public FairMQDevice { std::copy(from.begin(), from.end(), std::back_inserter(to)); } - // specialization for o2::MCTruthContainer<S> - template <typename S> - void backInsert(o2::dataformats::MCTruthContainer<S> const& from, - o2::dataformats::MCTruthContainer<S>& to) - { - to.mergeAtBack(from); - } - void reorderAndMergeMCTRacks(TTree& origin, TTree& target, const std::vector<int>& nprimaries, const std::vector<int>& nsubevents) + void reorderAndMergeMCTracks(int eventID, TTree& target, const std::vector<int>& nprimaries, const std::vector<int>& nsubevents) { - std::vector<MCTrack>* incomingdata = nullptr; - auto targetdata = new std::vector<MCTrack>; - auto originbr = origin.GetBranch("MCTrack"); - originbr->SetAddress(&incomingdata); - const auto entries = origin.GetEntries(); - // - // loop over subevents to store the primary events - // - Int_t nprimTot = 0; - for (auto entry = entries - 1; entry >= 0; --entry) { - int index = nsubevents[entry]; - nprimTot += nprimaries[index]; - printf("merge %lld %5d %5d %5d \n", entry, index, nsubevents[entry], nsubevents[index]); - originbr->GetEntry(index); - for (Int_t i = 0; i < nprimaries[index]; i++) { - auto& track = incomingdata->at(i); - track.SetFirstDaughterTrackId(-1); - targetdata->push_back(track); - } - incomingdata->clear(); - delete incomingdata; - incomingdata = nullptr; - } - // - // loop a second time to store the secondaries and fix the mother track IDs - // - Int_t idelta1 = nprimTot; - Int_t idelta0 = 0; - for (auto entry = entries - 1; entry >= 0; --entry) { - int index = nsubevents[entry]; - - originbr->GetEntry(index); - - Int_t npart = (int)(incomingdata->size()); - Int_t nprim = nprimaries[index]; - idelta1 -= nprim; - - for (Int_t i = nprim; i < npart; i++) { - auto& track = incomingdata->at(i); - Int_t cId = track.getMotherTrackId(); - if (cId >= nprim) { - cId += idelta1; - } else { - cId += idelta0; + // avoid doing this for trivial cases + std::vector<MCTrack>* mcTracksPerSubEvent = nullptr; + auto targetdata = std::make_unique<std::vector<MCTrack>>(); + + auto& vectorOfSubEventMCTracks = mMCTrackBuffer[eventID]; + const auto entries = vectorOfSubEventMCTracks.size(); + + if (entries > 1) { + // + // loop over subevents to store the primary events + // + int nprimTot = 0; + for (int entry = entries - 1; entry >= 0; --entry) { + int index = nsubevents[entry]; + nprimTot += nprimaries[index]; + printf("merge %d %5d %5d %5d \n", entry, index, nsubevents[entry], nsubevents[index]); + for (int i = 0; i < nprimaries[index]; i++) { + auto& track = (*vectorOfSubEventMCTracks[index])[i]; + if (track.isTransported()) { // reset daughters only if track was transported, it will be fixed below + track.SetFirstDaughterTrackId(-1); + track.SetLastDaughterTrackId(-1); + } + targetdata->push_back(track); } - track.SetMotherTrackId(cId); - track.SetFirstDaughterTrackId(-1); + } + // + // loop a second time to store the secondaries and fix the mother track IDs + // + Int_t idelta1 = nprimTot; + Int_t idelta0 = 0; + for (int entry = entries - 1; entry >= 0; --entry) { + int index = nsubevents[entry]; - Int_t hwm = (int)(targetdata->size()); - auto& mother = targetdata->at(cId); - if (mother.getFirstDaughterTrackId() == -1) { - mother.SetFirstDaughterTrackId(hwm); - } - mother.SetLastDaughterTrackId(hwm); + auto& subEventTracks = *(vectorOfSubEventMCTracks[index]); + // we need to fetch the right mctracks here!! + Int_t npart = (int)(subEventTracks.size()); + Int_t nprim = nprimaries[index]; + idelta1 -= nprim; - targetdata->push_back(track); + for (Int_t i = nprim; i < npart; i++) { + auto& track = subEventTracks[i]; + Int_t cId = track.getMotherTrackId(); + if (cId >= nprim) { + cId += idelta1; + } else { + cId += idelta0; + } + track.SetMotherTrackId(cId); + track.SetFirstDaughterTrackId(-1); + + Int_t hwm = (int)(targetdata->size()); + auto& mother = (*targetdata)[cId]; + if (mother.getFirstDaughterTrackId() == -1) { + mother.SetFirstDaughterTrackId(hwm); + } + mother.SetLastDaughterTrackId(hwm); + + targetdata->push_back(track); + } + idelta0 += nprim; + idelta1 += npart; } - idelta0 += nprim; - idelta1 += npart; - incomingdata->clear(); - delete incomingdata; - incomingdata = nullptr; } - // // write to output - auto targetbr = o2::base::getOrMakeBranch(target, "MCTrack", &targetdata); - targetbr->SetAddress(&targetdata); + auto filladdr = (entries > 1) ? targetdata.get() : vectorOfSubEventMCTracks[0]; + auto targetbr = o2::base::getOrMakeBranch(target, "MCTrack", &filladdr); + targetbr->SetAddress(&filladdr); targetbr->Fill(); targetbr->ResetAddress(); - targetdata->clear(); + + // cleanup buffered data + for (auto ptr : vectorOfSubEventMCTracks) { + delete ptr; // avoid this by using unique ptr + } + // TODO: protect by lock (as multithreaded access to STL MAP) + mMCTrackBuffer.erase(eventID); } - template <typename T> - void remapTrackIdsAndMerge(std::string brname, TTree& origin, TTree& target, - const std::vector<int>& trackoffsets, const std::vector<int>& nprimaries, const std::vector<int>& subevOrdered) + template <typename T, typename M> + void remapTrackIdsAndMerge(std::string brname, int eventID, TTree& target, + const std::vector<int>& trackoffsets, const std::vector<int>& nprimaries, const std::vector<int>& subevOrdered, M& mapOfVectorOfTs) { // // Remap the mother track IDs by adding an offset. @@ -418,44 +503,46 @@ class O2HitMerger : public FairMQDevice // This method is called by O2HitMerger::mergeAndFlushData(int) // T* incomingdata = nullptr; - auto targetdata = new T; - auto originbr = origin.GetBranch(brname.c_str()); - originbr->SetAddress(&incomingdata); - const auto entries = origin.GetEntries(); + std::unique_ptr<T> targetdata(nullptr); + auto& vectorOfT = mapOfVectorOfTs[eventID]; + const auto entries = vectorOfT.size(); if (entries == 1) { // nothing to do in case there is only one entry - originbr->GetEntry(0); - targetdata = incomingdata; + incomingdata = vectorOfT[0]; } else { + targetdata = std::make_unique<T>(); // loop over subevents Int_t nprimTot = 0; - for (auto entry = 0; entry < entries; entry++) { + for (int entry = 0; entry < entries; entry++) { nprimTot += nprimaries[entry]; } Int_t idelta0 = 0; Int_t idelta1 = nprimTot; - for (auto entry = entries - 1; entry >= 0; --entry) { + for (int entry = entries - 1; entry >= 0; --entry) { Int_t index = subevOrdered[entry]; Int_t nprim = nprimaries[index]; - originbr->GetEntry(index); + incomingdata = vectorOfT[index]; idelta1 -= nprim; for (auto& data : *incomingdata) { updateTrackIdWithOffset(data, nprim, idelta0, idelta1); targetdata->push_back(data); } - incomingdata->clear(); idelta0 += nprim; idelta1 += trackoffsets[index]; - delete incomingdata; - incomingdata = nullptr; } } - auto targetbr = o2::base::getOrMakeBranch(target, brname.c_str(), &targetdata); - targetbr->SetAddress(&targetdata); + auto dataaddr = (entries == 1) ? incomingdata : targetdata.get(); + auto targetbr = o2::base::getOrMakeBranch(target, brname.c_str(), &dataaddr); + targetbr->SetAddress(&dataaddr); targetbr->Fill(); targetbr->ResetAddress(); - targetdata->clear(); + + // cleanup mem + for (auto ptr : vectorOfT) { + delete ptr; // avoid this by using unique ptr + } + mapOfVectorOfTs.erase(eventID); } void updateTrackIdWithOffset(MCTrack& track, Int_t nprim, Int_t idelta0, Int_t idelta1) @@ -474,171 +561,152 @@ class O2HitMerger : public FairMQDevice ref.setTrackID(cId + ioffset); } - // this merges all entries from the TBranch brname from the origin TTree (containing one event only) - // into a single entry in a target TTree / same branch - // (assuming T is typically a vector; merging is simply done by appending) - template <typename T> - void merge(std::string brname, TTree& origin, TTree& target) - { - auto originbr = origin.GetBranch(brname.c_str()); - auto targetdata = new T; - T* incomingdata = nullptr; - originbr->SetAddress(&incomingdata); - - const auto entries = origin.GetEntries(); - - T* filladdress = nullptr; - if (entries == 1) { - // this avoids useless copy in case there was no sub-event splitting; we just use the original data - originbr->GetEntry(0); - filladdress = incomingdata; - } else { - filladdress = targetdata; - for (auto entry = 0; entry < entries; ++entry) { - originbr->GetEntry(entry); - backInsert(*incomingdata, *targetdata); - delete incomingdata; - incomingdata = nullptr; - } - } - - // fill target for this event - auto targetbr = o2::base::getOrMakeBranch(target, brname.c_str(), &filladdress); - targetbr->SetAddress(&filladdress); - targetbr->Fill(); - targetbr->ResetAddress(); - targetdata->clear(); - if (incomingdata) { - delete incomingdata; - incomingdata = nullptr; - } - - delete targetdata; - } - - void initHitTreeAndOutFile(int detID) + void initHitTreeAndOutFile(std::string prefix, int detID) { using o2::detectors::DetID; if (mDetectorOutFiles[detID]) { - LOG(WARN) << "Hit outfile for detID " << DetID::getName(detID) << " already initialized"; - return; + LOG(WARN) << "Hit outfile for detID " << DetID::getName(detID) << " already initialized --> Reopening"; + mDetectorOutFiles[detID]->Close(); + delete mDetectorOutFiles[detID]; } - std::string name(o2::base::NameConf::getHitsFileName(detID, o2::conf::SimConfig::Instance().getOutPrefix().c_str())); + std::string name(o2::base::NameConf::getHitsFileName(detID, prefix)); mDetectorOutFiles[detID] = new TFile(name.c_str(), "RECREATE"); mDetectorToTTreeMap[detID] = new TTree("o2sim", "o2sim"); mDetectorToTTreeMap[detID]->SetDirectory(mDetectorOutFiles[detID]); } - // This method goes over the tree containing data for a given event; potentially merges - // it and flushes it into the actual output file. + // This method goes over the buffers containing data for a given event; potentially merges + // them and flushes into the actual output file. // The method can be called asynchronously to data collection - bool mergeAndFlushData(int eventID) + bool mergeAndFlushData() { - LOG(INFO) << "ENTERING MERGING/FLUSHING HITS STAGE FOR EVENT " << eventID; - - auto tree = mEventToTTreeMap[eventID]; - if (!tree) { - LOG(INFO) << "NO TTREE FOUND FOR EVENT " << eventID; + auto checkIfNextFlushable = [this]() -> bool { + mNextFlushID++; + return mFlushableEvents.find(mNextFlushID) != mFlushableEvents.end() && mFlushableEvents[mNextFlushID] == true; + }; + + LOG(INFO) << "Launching merge kernel "; + bool canflush = mFlushableEvents.find(mNextFlushID) != mFlushableEvents.end() && mFlushableEvents[mNextFlushID] == true; + if (!canflush) { return false; } + while (canflush == true) { + auto flusheventID = mNextFlushID; + LOG(INFO) << "Merge and flush event " << flusheventID; + auto iter = mSubEventInfoBuffer.find(flusheventID); + if (iter == mSubEventInfoBuffer.end()) { + LOG(ERROR) << "No info/data found for event " << flusheventID; + if (!checkIfNextFlushable()) { + return false; + } + } - if (tree->GetEntries() == 0 || mNExpectedEvents == 0) { - LOG(INFO) << "NO ENTRY IN TTREE FOUND FOR EVENT " << eventID; - return false; - } + auto& subEventInfoList = (*iter).second; + if (subEventInfoList.size() == 0 || mNExpectedEvents == 0) { + LOG(ERROR) << "No data entries found for event " << flusheventID; + if (!checkIfNextFlushable()) { + return false; + } + } - TStopwatch timer; - timer.Start(); + TStopwatch timer; + timer.Start(); + + // calculate trackoffsets + auto& confref = o2::conf::SimConfig::Instance(); + + // collecting trackoffsets (per data arrival id) to be used for global track-ID correction pass + std::vector<int> trackoffsets; + // collecting primary particles in each subevent (data arrival id) + std::vector<int> nprimaries; + // mapping of id to actual sub-event id (or part) + std::vector<int> nsubevents; + + o2::dataformats::MCEventHeader* eventheader = nullptr; // The event header + + // the MC labels (trackID) for hits + for (auto info : subEventInfoList) { + assert(info->npersistenttracks >= 0); + trackoffsets.emplace_back(info->npersistenttracks); + nprimaries.emplace_back(info->nprimarytracks); + nsubevents.emplace_back(info->part); + if (eventheader == nullptr) { + eventheader = &info->mMCEventHeader; + } else { + eventheader->getMCEventStats().add(info->mMCEventHeader.getMCEventStats()); + } + } - // calculate trackoffsets - auto infobr = tree->GetBranch("SubEventInfo"); - - auto& confref = o2::conf::SimConfig::Instance(); - - std::vector<int> trackoffsets; // collecting trackoffsets to be applied to correct - std::vector<int> nprimaries; // collecting primary particles in each subevent - std::vector<int> nsubevents; // collecting of subevent numbers - - std::unique_ptr<o2::dataformats::MCEventHeader> eventheader; // The event header - - // the MC labels (trackID) for hits - o2::data::SubEventInfo* info = nullptr; - infobr->SetAddress(&info); - for (int i = 0; i < infobr->GetEntries(); ++i) { - infobr->GetEntry(i); - assert(info->npersistenttracks >= 0); - trackoffsets.emplace_back(info->npersistenttracks); - nprimaries.emplace_back(info->nprimarytracks); - nsubevents.emplace_back(info->part); - if (eventheader == nullptr) { - eventheader = std::unique_ptr<dataformats::MCEventHeader>( - new dataformats::MCEventHeader(info->mMCEventHeader)); - } else { - eventheader->getMCEventStats().add(info->mMCEventHeader.getMCEventStats()); + // now see which events can be discarded in any case due to no hits + if (confref.isFilterOutNoHitEvents()) { + if (eventheader && eventheader->getMCEventStats().getNHits() == 0) { + LOG(INFO) << " Taking out event " << flusheventID << " due to no hits "; + cleanEvent(flusheventID); + if (!checkIfNextFlushable()) { + return true; + } + } } - } - // now see which events can be discarded in any case due to no hits - if (confref.isFilterOutNoHitEvents()) { - if (eventheader && eventheader->getMCEventStats().getNHits() == 0) { - LOG(INFO) << " Taking out event " << eventID << " due to no hits "; - cleanEvent(eventID); - return false; + // put the event headers into the new TTree + auto headerbr = o2::base::getOrMakeBranch(*mOutTree, "MCEventHeader.", &eventheader); + headerbr->SetAddress(&eventheader); + headerbr->Fill(); + headerbr->ResetAddress(); + + // attention: We need to make sure that we write everything in the same event order + // but iteration over keys of a standard map in C++ is ordered + + // b) merge the general data + // + // for MCTrack remap the motherIds and merge at the same go + const auto entries = subEventInfoList.size(); + std::vector<int> subevOrdered((int)(nsubevents.size())); + for (int entry = entries - 1; entry >= 0; --entry) { + subevOrdered[nsubevents[entry] - 1] = entry; + printf("HitMerger entry: %d nprimry: %5d trackoffset: %5d \n", entry, nprimaries[entry], trackoffsets[entry]); } - } - // put the event headers into the new TTree - o2::dataformats::MCEventHeader* headerptr = eventheader.get(); - auto headerbr = o2::base::getOrMakeBranch(*mOutTree, "MCEventHeader.", &headerptr); - headerbr->SetAddress(&headerptr); - headerbr->Fill(); - headerbr->ResetAddress(); + reorderAndMergeMCTracks(flusheventID, *mOutTree, nprimaries, subevOrdered); + remapTrackIdsAndMerge<std::vector<o2::TrackReference>>("TrackRefs", flusheventID, *mOutTree, trackoffsets, nprimaries, subevOrdered, mTrackRefBuffer); + + // c) do the merge procedure for all hits ... delegate this to detector specific functions + // since they know about types; number of branches; etc. + // this will also fix the trackIDs inside the hits + for (int id = 0; id < mDetectorInstances.size(); ++id) { + auto& det = mDetectorInstances[id]; + if (det) { + auto hittree = mDetectorToTTreeMap[id]; + // det->mergeHitEntries(*tree, *hittree, trackoffsets, nprimaries, subevOrdered); + det->mergeHitEntriesAndFlush(flusheventID, *hittree, trackoffsets, nprimaries, subevOrdered); + hittree->SetEntries(hittree->GetEntries() + 1); + LOG(INFO) << "flushing tree to file " << hittree->GetDirectory()->GetFile()->GetName(); + } + } - // attention: We need to make sure that we write everything in the same event order - // but iteration over keys of a standard map in C++ is ordered + // increase the entry count in the tree + mOutTree->SetEntries(mOutTree->GetEntries() + 1); + LOG(INFO) << "outtree has file " << mOutTree->GetDirectory()->GetFile()->GetName(); - // b) merge the general data - // - // for MCTrack remap the motherIds and merge at the same go - const auto entries = tree->GetEntries(); - std::vector<int> subevOrdered((int)(nsubevents.size())); - for (auto entry = entries - 1; entry >= 0; --entry) { - subevOrdered[nsubevents[entry] - 1] = entry; - printf("HitMerger entry: %lld nprimry: %5d trackoffset: %5d \n", entry, nprimaries[entry], trackoffsets[entry]); - } - - reorderAndMergeMCTRacks(*tree, *mOutTree, nprimaries, subevOrdered); - Int_t ioffset = 0; - remapTrackIdsAndMerge<std::vector<o2::TrackReference>>("TrackRefs", *tree, *mOutTree, trackoffsets, nprimaries, subevOrdered); - merge<o2::dataformats::MCTruthContainer<o2::TrackReference>>("IndexedTrackRefs", *tree, *mOutTree); - - // c) do the merge procedure for all hits ... delegate this to detector specific functions - // since they know about types; number of branches; etc. - // this will also fix the trackIDs inside the hits + cleanEvent(flusheventID); + LOG(INFO) << "Merge/flush for event " << flusheventID << " took " << timer.RealTime(); + if (!checkIfNextFlushable()) { + break; + } + } // end while + LOG(INFO) << "Writing TTrees"; + mOutFile->Write("", TObject::kOverwrite); for (int id = 0; id < mDetectorInstances.size(); ++id) { auto& det = mDetectorInstances[id]; if (det) { - auto hittree = mDetectorToTTreeMap[id]; - det->mergeHitEntries(*tree, *hittree, trackoffsets, nprimaries, subevOrdered); - hittree->SetEntries(hittree->GetEntries() + 1); - LOG(INFO) << "flushing tree to file " << hittree->GetDirectory()->GetFile()->GetName(); mDetectorOutFiles[id]->Write("", TObject::kOverwrite); } } - // increase the entry count in the tree - mOutTree->SetEntries(mOutTree->GetEntries() + 1); - LOG(INFO) << "outtree has file " << mOutTree->GetDirectory()->GetFile()->GetName(); - mOutFile->Write("", TObject::kOverwrite); - - cleanEvent(eventID); - - LOG(INFO) << "MERGING HITS TOOK " << timer.RealTime(); return true; } std::map<uint32_t, uint32_t> mPartsCheckSum; //! mapping event id -> part checksum used to detect when all info - std::string mOutFileName; //! // structures for the final flush @@ -648,23 +716,58 @@ class O2HitMerger : public FairMQDevice std::unordered_map<int, TTree*> mDetectorToTTreeMap; //! the trees // intermediate structures to collect data per event - std::unordered_map<int, TTree*> mEventToTTreeMap; //! in memory trees to collect / presort incoming data per event - std::unordered_map<int, TMemFile*> mEventToTMemFileMap; //! files associated to the TTrees std::thread mMergerIOThread; //! a thread used to do hit merging and IO flushing asynchronously std::mutex mMapsMtx; //! - int mEntries = 0; //! counts the number of entries in the branches + bool mergingInProgress = false; + + std::unordered_map<int, std::vector<std::vector<o2::MCTrack>*>> mMCTrackBuffer; //! vector of sub-event track vectors; one per event + std::unordered_map<int, std::vector<std::vector<o2::TrackReference>*>> mTrackRefBuffer; //! + std::unordered_map<int, std::list<o2::data::SubEventInfo*>> mSubEventInfoBuffer; + int mEventChecksum = 0; //! checksum for events int mNExpectedEvents = 0; //! number of events that we expect to receive + std::unordered_map<int, bool> mFlushableEvents; //! collection of events which has completely arrived + int mNextFlushID = 1; //! EventID to be flushed next TStopwatch mTimer; + bool mAsService = false; //! if run in deamonized mode + int mPipeToDriver = -1; - std::vector<std::unique_ptr<o2::base::Detector>> mDetectorInstances; + std::vector<std::unique_ptr<o2::base::Detector>> mDetectorInstances; //! + + // output folder configuration + std::string mInitialOutputDir; // initial output folder of the process (initialized during construction) + std::string mCurrentOutputDir; // current output folder asked + + // channel to PUB status messages to outside subscribers + FairMQChannel mPubChannel; // init detector instances void initDetInstances(); + void initHitFiles(std::string prefix); }; +void O2HitMerger::initHitFiles(std::string prefix) +{ + using o2::detectors::DetID; + + // a little helper lambda + auto isActivated = [](std::string s) -> bool { + // access user configuration for list of wanted modules + auto& modulelist = o2::conf::SimConfig::Instance().getActiveDetectors(); + auto active = std::find(modulelist.begin(), modulelist.end(), s) != modulelist.end(); + return active; }; + + for (int i = DetID::First; i <= DetID::Last; ++i) { + if (!isActivated(DetID::getName(i))) { + continue; + } + // init the detector specific output files + initHitTreeAndOutFile(prefix, i); + } +} + // init detector instances used to write hit data to a TTree void O2HitMerger::initDetInstances() { @@ -751,13 +854,15 @@ void O2HitMerger::initDetInstances() mDetectorInstances[i] = std::move(std::make_unique<o2::its3::Detector>(true)); counter++; } - if (i == DetID::IT4) { - mDetectorInstances[i] = std::move(std::make_unique<o2::its4::Detector>(true)); + if (i == DetID::TRK) { + mDetectorInstances[i] = std::move(std::make_unique<o2::trk::Detector>(true)); + counter++; + } + if (i == DetID::FT3) { + mDetectorInstances[i] = std::move(std::make_unique<o2::ft3::Detector>(true)); counter++; } #endif - // init the detector specific output files - initHitTreeAndOutFile(i); } if (counter != DetID::nDetectors) { LOG(WARNING) << " O2HitMerger: Some Detectors are potentially missing in this initialization "; diff --git a/run/O2HitMergerRunner.cxx b/run/O2HitMergerRunner.cxx index c0610ff5b3850..2675506b1e8d8 100644 --- a/run/O2HitMergerRunner.cxx +++ b/run/O2HitMergerRunner.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/run/O2PrimaryServerDevice.h b/run/O2PrimaryServerDevice.h index 655b3fae8b815..7690ff8307436 100644 --- a/run/O2PrimaryServerDevice.h +++ b/run/O2PrimaryServerDevice.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -14,6 +15,7 @@ #define O2_DEVICES_PRIMSERVDEVICE_H_ #include <FairMQDevice.h> +#include <FairMQTransportFactory.h> #include <FairPrimaryGenerator.h> #include <Generators/GeneratorFactory.h> #include <FairMQMessage.h> @@ -33,6 +35,12 @@ #include <thread> #include <TROOT.h> #include <TStopwatch.h> +#include <fstream> +#include <iostream> +#include <atomic> +#include "PrimaryServerState.h" +#include "SimPublishChannelHelper.h" +#include <chrono> namespace o2 { @@ -42,17 +50,20 @@ namespace devices class O2PrimaryServerDevice final : public FairMQDevice { public: - /// Default constructor - O2PrimaryServerDevice() - { - mStack.setExternalMode(true); - } + /// constructor + O2PrimaryServerDevice() = default; /// Default destructor ~O2PrimaryServerDevice() final { - if (mGeneratorThread.joinable()) { - mGeneratorThread.join(); + try { + if (mGeneratorThread.joinable()) { + mGeneratorThread.join(); + } + if (mControlThread.joinable()) { + mControlThread.join(); + } + } catch (...) { } } @@ -61,38 +72,119 @@ class O2PrimaryServerDevice final : public FairMQDevice { TStopwatch timer; timer.Start(); - auto& conf = o2::conf::SimConfig::Instance(); + const auto& conf = mSimConfig; // init magnetic field as it might be needed by the generator - auto field = o2::field::MagneticField::createNominalField(conf.getConfigData().mField); - TGeoGlobalMagField::Instance()->SetField(field); - TGeoGlobalMagField::Instance()->Lock(); + if (TGeoGlobalMagField::Instance()->GetField() == nullptr) { + auto field = o2::field::MagneticField::createNominalField(conf.getConfigData().mField, conf.getConfigData().mUniformField); + TGeoGlobalMagField::Instance()->SetField(field); + TGeoGlobalMagField::Instance()->Lock(); + } + + // look if we find a cached instances of Pythia8 or external generators in order to avoid + // (long) initialization times. + // This is evidently a bit weak, as generators might need reconfiguration (to be treated later). + // For now, we'd like to allow for fast switches between say a pythia8 instance and reading from kinematics + // to continue an already started simulation. + // + // Not using cached instances for external kinematics since these might change input filenames etc. + // and are in any case quickly setup. + mPrimGen = nullptr; + if (conf.getGenerator().compare("extkin") != 0 || conf.getGenerator().compare("extkinO2") != 0) { + auto iter = mPrimGeneratorCache.find(conf.getGenerator()); + if (iter != mPrimGeneratorCache.end()) { + mPrimGen = iter->second; + LOG(INFO) << "Found cached generator for " << conf.getGenerator(); + } + } + + if (mPrimGen == nullptr) { + mPrimGen = new o2::eventgen::PrimaryGenerator; + o2::eventgen::GeneratorFactory::setPrimaryGenerator(conf, mPrimGen); + + auto embedinto_filename = conf.getEmbedIntoFileName(); + if (!embedinto_filename.empty()) { + mPrimGen->embedInto(embedinto_filename); + } - o2::eventgen::GeneratorFactory::setPrimaryGenerator(conf, &mPrimGen); - mPrimGen.SetEvent(&mEventHeader); + mPrimGen->Init(); - auto embedinto_filename = conf.getEmbedIntoFileName(); - if (!embedinto_filename.empty()) { - mPrimGen.embedInto(embedinto_filename); + mPrimGeneratorCache[conf.getGenerator()] = mPrimGen; } - mPrimGen.Init(); + mPrimGen->SetEvent(&mEventHeader); + LOG(INFO) << "Generator initialization took " << timer.CpuTime() << "s"; - generateEvent(); // generate a first event + if (mMaxEvents > 0) { + generateEvent(); // generate a first event + } } // function generating one event - void generateEvent() + void generateEvent(/*bool changeState = false*/) { + bool changeState = false; + LOG(INFO) << "Event generation started "; + if (changeState) { + stateTransition(O2PrimaryServerState::WaitingEvent, "GENEVENT"); + } TStopwatch timer; timer.Start(); - mStack.Reset(); - mPrimGen.GenerateEvent(&mStack); + try { + mStack->Reset(); + mPrimGen->GenerateEvent(mStack); + } catch (std::exception const& e) { + LOG(ERROR) << " Exception occurred during event gen "; + } timer.Stop(); - LOG(INFO) << "Event generation took " << timer.CpuTime() << "s"; + LOG(INFO) << "Event generation took " << timer.CpuTime() << "s" + << " and produced " << mStack->getPrimaries().size() << " primaries "; + if (changeState) { + stateTransition(O2PrimaryServerState::ReadyToServe, "GENEVENT"); + } + } + + // launches a thread that listens for status requests from outside asynchronously + void launchInfoThread() + { + static std::vector<std::thread> threads; + LOG(INFO) << "LAUNCHING STATUS THREAD"; + auto lambda = [this]() { + while (mState != O2PrimaryServerState::Stopped) { + auto& channel = fChannels.at("o2sim-primserv-info").at(0); + if (!channel.IsValid()) { + LOG(ERROR) << "channel primserv-info not valid"; + } + std::unique_ptr<FairMQMessage> request(channel.NewSimpleMessage(-1)); + int timeout = 100; // 100ms --> so as not to block and allow for proper termination of this thread + if (channel.Receive(request, timeout) > 0) { + LOG(INFO) << "INFO REQUEST RECEIVED"; + if (*(int*)(request->GetData()) == (int)O2PrimaryServerInfoRequest::Status) { + LOG(INFO) << "Received status request"; + // request needs to be a simple enum of type O2PrimaryServerInfoRequest + std::unique_ptr<FairMQMessage> reply(channel.NewSimpleMessage((int)mState.load())); + if (channel.Send(reply) > 0) { + LOG(INFO) << "Send status successful"; + } + } else if (*(int*)request->GetData() == (int)O2PrimaryServerInfoRequest::Config) { + HandleConfigRequest(channel); + } else { + LOG(FATAL) << "UNKNOWN REQUEST"; + std::unique_ptr<FairMQMessage> reply(channel.NewSimpleMessage(404)); + channel.Send(reply); + } + } + } + mInfoThreadStopped = true; + }; + threads.push_back(std::thread(lambda)); + threads.back().detach(); } void InitTask() final { + o2::simpubsub::publishMessage(fChannels["primary-notifications"].at(0), "SERVER : INITIALIZING"); + + stateTransition(O2PrimaryServerState::Initializing, "INITTASK"); LOG(INFO) << "Init Server device "; // init sim config @@ -100,14 +192,21 @@ class O2PrimaryServerDevice final : public FairMQDevice auto& vm = GetConfig()->GetVarMap(); conf.resetFromParsedMap(vm); // output varmap - for (auto& keyvalue : vm) { - LOG(INFO) << "///// " << keyvalue.first << " " << keyvalue.second.value().type().name(); - } + // for (auto& keyvalue : vm) { + // LOG(INFO) << "///// " << keyvalue.first << " " << keyvalue.second.value().type().name(); + //} + // update the parameters from an INI/JSON file, if given (overrides code-based version) o2::conf::ConfigurableParam::updateFromFile(conf.getConfigFile()); // update the parameters from stuff given at command line (overrides file-based version) o2::conf::ConfigurableParam::updateFromString(conf.getKeyValueString()); + // from now on mSimConfig should be used within this process + mSimConfig = conf; + + mStack = new o2::data::Stack(); + mStack->setExternalMode(true); + // MC ENGINE LOG(INFO) << "ENGINE SET TO " << vm["mcEngine"].as<std::string>(); // CHUNK SIZE @@ -124,10 +223,15 @@ class O2PrimaryServerDevice final : public FairMQDevice // need to make ROOT thread-safe since we use ROOT services in all places ROOT::EnableThreadSafety(); - // lunch initialization of particle generator asynchronously + launchInfoThread(); + + // launch initialization of particle generator asynchronously // so that we reach the RUNNING state of the server quickly // and do not block here mGeneratorThread = std::thread(&O2PrimaryServerDevice::initGenerator, this); + if (mGeneratorThread.joinable()) { + mGeneratorThread.join(); + } // init pipe auto pipeenv = getenv("ALICE_O2SIMSERVERTODRIVER_PIPE"); @@ -137,15 +241,69 @@ class O2PrimaryServerDevice final : public FairMQDevice } else { LOG(INFO) << "DID NOT FIND ENVIRONMENT VARIABLE TO INIT PIPE"; } + + mAsService = vm["asservice"].as<bool>(); + + if (mMaxEvents <= 0) { + if (mAsService) { + stateTransition(O2PrimaryServerState::Idle, "INITTASK"); + } + } else { + stateTransition(O2PrimaryServerState::ReadyToServe, "INITTASK"); + } + } + + // function for intermediate/on-the-fly reinitializations + bool ReInit(o2::conf::SimReconfigData const& reconfig) + { + LOG(INFO) << "ReInit Server device "; + + if (reconfig.stop) { + return false; + } + + // mSimConfig.getConfigData().mKeyValueTokens=reconfig.keyValueTokens; + // Think about this: + // update the parameters from an INI/JSON file, if given (overrides code-based version) + o2::conf::ConfigurableParam::updateFromFile(reconfig.configFile); + // update the parameters from stuff given at command line (overrides file-based version) + o2::conf::ConfigurableParam::updateFromString(reconfig.keyValueTokens); + + // initial initial seed --> we should store this somewhere + mInitialSeed = reconfig.startSeed; + mInitialSeed = o2::utils::RngHelper::setGRandomSeed(mInitialSeed); + LOG(INFO) << "RNG INITIAL SEED " << mInitialSeed; + + mMaxEvents = reconfig.nEvents; + + // updating the simconfig member with new information especially concerning the generators + // TODO: put this into utility function? + mSimConfig.getConfigData().mGenerator = reconfig.generator; + mSimConfig.getConfigData().mTrigger = reconfig.trigger; + mSimConfig.getConfigData().mExtKinFileName = reconfig.extKinfileName; + + mEventCounter = 0; + mPartCounter = 0; + mNeedNewEvent = true; + // reinit generator and start generation of a new event + if (mGeneratorThread.joinable()) { + mGeneratorThread.join(); + } + mGeneratorThread = std::thread(&O2PrimaryServerDevice::initGenerator, this); + // initGenerator(); + if (mGeneratorThread.joinable()) { + mGeneratorThread.join(); + } + + return true; } // method reacting to requests to get the simulation configuration - bool HandleConfigRequest(FairMQMessagePtr& request) + bool HandleConfigRequest(FairMQChannel& channel) { - LOG(INFO) << "received config request"; + LOG(INFO) << "Received config request"; // just sending the simulation configuration to anyone that wants it - auto& conf = o2::conf::SimConfig::Instance(); - const auto& confdata = conf.getConfigData(); + const auto& confdata = mSimConfig.getConfigData(); TMessage* tmsg = new TMessage(kMESS_OBJECT); tmsg->WriteObjectAny((void*)&confdata, TClass::GetClass(typeid(confdata))); @@ -156,7 +314,7 @@ class O2PrimaryServerDevice final : public FairMQDevice fTransportFactory->CreateMessage(tmsg->Buffer(), tmsg->BufferSize(), free_tmessage, tmsg)); // send answer - if (Send(message, "primary-get", 0) > 0) { + if (channel.Send(message) > 0) { LOG(INFO) << "config reply send "; return true; } @@ -165,130 +323,253 @@ class O2PrimaryServerDevice final : public FairMQDevice bool ConditionalRun() override { + // we might come here in IDLE mode + if (mState == O2PrimaryServerState::Idle) { + if (mWaitingControlInput.load() == 0) { + if (mControlThread.joinable()) { + mControlThread.join(); + } + mControlThread = std::thread(&O2PrimaryServerDevice::waitForControlInput, this); + } + } + auto& channel = fChannels.at("primary-get").at(0); - std::unique_ptr<FairMQMessage> request(channel.NewMessage()); + PrimaryChunkRequest requestpayload; + std::unique_ptr<FairMQMessage> request(channel.NewSimpleMessage(requestpayload)); auto bytes = channel.Receive(request); if (bytes < 0) { - LOG(ERROR) << "Some error occurred on socket during receive"; - return true; // keep going + LOG(ERROR) << "Some error/interrupt occurred on socket during receive"; + if (NewStatePending()) { // new state is typically pending if (term) signal was received + WaitForNextState(); + // ask ourselves for termination of this loop + stateTransition(O2PrimaryServerState::Stopped, "CONDRUN"); + } + return false; + } + + TStopwatch timer; + timer.Start(); + auto& r = *((PrimaryChunkRequest*)(request->GetData())); + LOG(INFO) << "PARTICLE REQUEST IN STATE " << PrimStateToString[(int)mState.load()] << " from " << r.workerid << ":" << r.requestid; + + auto prestate = mState.load(); + auto more = HandleRequest(request, 0, channel); + if (!more) { + if (mAsService) { + if (prestate == O2PrimaryServerState::ReadyToServe || prestate == O2PrimaryServerState::WaitingEvent) { + stateTransition(O2PrimaryServerState::Idle, "CONDRUN"); + } + } else { + stateTransition(O2PrimaryServerState::Stopped, "CONDRUN"); + } } - return HandleRequest(request, 0); + timer.Stop(); + auto time = timer.CpuTime(); + LOG(INFO) << "COND-RUN TOOK " << time << " s"; + return mState != O2PrimaryServerState::Stopped; } - /// Overloads the ConditionalRun() method of FairMQDevice - bool HandleRequest(FairMQMessagePtr& request, int /*index*/) + void PostRun() override { - LOG(INFO) << "GOT A REQUEST WITH SIZE " << request->GetSize(); - std::string requeststring(static_cast<char*>(request->GetData()), request->GetSize()); - - if (requeststring.compare("configrequest") == 0) { - return HandleConfigRequest(request); + while (!mInfoThreadStopped) { + LOG(INFO) << "Waiting info thread"; + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); } + } - else if (requeststring.compare("primrequest") != 0) { - LOG(INFO) << "unknown request\n"; - return true; + bool HandleRequest(FairMQMessagePtr& request, int /*index*/, FairMQChannel& channel) + { + // LOG(DEBUG) << "GOT A REQUEST WITH SIZE " << request->GetSize(); + // std::string requeststring(static_cast<char*>(request->GetData()), request->GetSize()); + // LOG(INFO) << "NORMAL REQUEST STRING " << requeststring; + bool workavailable = true; + if (mEventCounter >= mMaxEvents && mNeedNewEvent) { + workavailable = false; } - - static int counter = 0; - if (counter >= mMaxEvents && mNeedNewEvent) { - return false; + if (!(mState == O2PrimaryServerState::ReadyToServe || mState == O2PrimaryServerState::WaitingEvent)) { + // send a zero answer + workavailable = false; } - LOG(INFO) << "Received request for work "; + PrimaryChunkAnswer header{mState, workavailable}; + FairMQParts reply; + std::unique_ptr<FairMQMessage> headermsg(channel.NewSimpleMessage(header)); + reply.AddPart(std::move(headermsg)); + + LOG(INFO) << "Received request for work " << mEventCounter << " " << mMaxEvents << " " << mNeedNewEvent << " available " << workavailable; if (mNeedNewEvent) { // we need a newly generated event now if (mGeneratorThread.joinable()) { - mGeneratorThread.join(); + try { + mGeneratorThread.join(); + } catch (std::exception const& e) { + LOG(WARN) << "Exception during thread join ..ignoring"; + } } mNeedNewEvent = false; mPartCounter = 0; - counter++; + mEventCounter++; } - auto& prims = mStack.getPrimaries(); + auto& prims = mStack->getPrimaries(); auto numberofparts = (int)std::ceil(prims.size() / (1. * mChunkGranularity)); // number of parts should be at least 1 (even if empty) numberofparts = std::max(1, numberofparts); + LOG(INFO) << "Have " << prims.size() << " " << numberofparts; + o2::data::PrimaryChunk m; o2::data::SubEventInfo i; - i.eventID = counter; + i.eventID = workavailable ? mEventCounter : -1; i.maxEvents = mMaxEvents; i.part = mPartCounter + 1; i.nparts = numberofparts; - i.seed = counter + mInitialSeed; + i.seed = mEventCounter + mInitialSeed; i.index = m.mParticles.size(); i.mMCEventHeader = mEventHeader; m.mSubEventInfo = i; - int endindex = prims.size() - mPartCounter * mChunkGranularity; - int startindex = prims.size() - (mPartCounter + 1) * mChunkGranularity; - if (startindex < 0) { - startindex = 0; - } - if (endindex < 0) { - endindex = 0; - } + if (workavailable) { + int endindex = prims.size() - mPartCounter * mChunkGranularity; + int startindex = prims.size() - (mPartCounter + 1) * mChunkGranularity; + LOG(INFO) << "indices " << startindex << " " << endindex; - for (int index = startindex; index < endindex; ++index) { - m.mParticles.emplace_back(prims[index]); - } + if (startindex < 0) { + startindex = 0; + } + if (endindex < 0) { + endindex = 0; + } + + for (int index = startindex; index < endindex; ++index) { + m.mParticles.emplace_back(prims[index]); + } - LOG(INFO) << "Sending " << m.mParticles.size() << " particles"; - LOG(INFO) << "treating ev " << counter << " part " << i.part << " out of " << i.nparts; + LOG(INFO) << "Sending " << m.mParticles.size() << " particles"; + LOG(INFO) << "treating ev " << mEventCounter << " part " << i.part << " out of " << i.nparts; - // feedback to driver if new event started - if (mPipeToDriver != -1 && i.part == 1) { - if (write(mPipeToDriver, &counter, sizeof(counter))) { + // feedback to driver if new event started + if (mPipeToDriver != -1 && i.part == 1 && workavailable) { + if (write(mPipeToDriver, &mEventCounter, sizeof(mEventCounter))) { + } } - } - mPartCounter++; - if (mPartCounter == numberofparts) { - mNeedNewEvent = true; - // start generation of a new event - mGeneratorThread = std::thread(&O2PrimaryServerDevice::generateEvent, this); - } + mPartCounter++; + if (mPartCounter == numberofparts) { + mNeedNewEvent = true; + // start generation of a new event + mGeneratorThread = std::thread(&O2PrimaryServerDevice::generateEvent, this); + } - TMessage* tmsg = new TMessage(kMESS_OBJECT); - tmsg->WriteObjectAny((void*)&m, TClass::GetClass("o2::data::PrimaryChunk")); + TMessage* tmsg = new TMessage(kMESS_OBJECT); + tmsg->WriteObjectAny((void*)&m, TClass::GetClass("o2::data::PrimaryChunk")); - auto free_tmessage = [](void* data, void* hint) { delete static_cast<TMessage*>(hint); }; + auto free_tmessage = [](void* data, void* hint) { delete static_cast<TMessage*>(hint); }; - std::unique_ptr<FairMQMessage> message( - fTransportFactory->CreateMessage(tmsg->Buffer(), tmsg->BufferSize(), free_tmessage, tmsg)); + std::unique_ptr<FairMQMessage> message(channel.NewMessage(tmsg->Buffer(), tmsg->BufferSize(), free_tmessage, tmsg)); + + reply.AddPart(std::move(message)); + } // send answer TStopwatch timer; timer.Start(); - auto code = Send(message, "primary-get", 0, 5000); // we introduce timeout in order not to block other requests + auto code = Send(reply, "primary-get", 0, 5000); // we introduce timeout in order not to block other requests timer.Stop(); auto time = timer.CpuTime(); if (code > 0) { LOG(INFO) << "Reply send in " << time << "s"; - return true; + return workavailable; } else { LOG(WARN) << "Sending process had problems. Return code : " << code << " time " << time << "s"; } - return true; + return false; // -> error should not get here + } + + void stateTransition(O2PrimaryServerState to, const char* message) + { + LOG(INFO) << message << " CHANGING STATE TO " << PrimStateToString[(int)to]; + mState = to; + } + + void waitForControlInput() + { + mWaitingControlInput.store(1); + stateTransition(O2PrimaryServerState::Idle, "CONTROL"); + + o2::simpubsub::publishMessage(fChannels["primary-notifications"].at(0), o2::simpubsub::simStatusString("PRIMSERVER", "STATUS", "AWAITING INPUT")); + // this means we are idling + + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto channel = FairMQChannel{"o2sim-control", "sub", factory}; + auto controlsocketname = getenv("ALICE_O2SIMCONTROL"); + channel.Connect(std::string(controlsocketname)); + channel.Validate(); + std::unique_ptr<FairMQMessage> reply(channel.NewMessage()); + + bool ok = false; + + LOG(INFO) << "WAITING FOR CONTROL INPUT"; + if (channel.Receive(reply) > 0) { + stateTransition(O2PrimaryServerState::Initializing, "CONTROL"); + auto data = reply->GetData(); + auto size = reply->GetSize(); + + std::string command(reinterpret_cast<char const*>(data), size); + LOG(INFO) << "message: " << command; + + o2::conf::SimReconfigData reconfig; + o2::conf::parseSimReconfigFromString(command, reconfig); + LOG(INFO) << "Processing " << reconfig.nEvents << " new events"; + try { + LOG(INFO) << "REINIT START"; + ok = ReInit(reconfig); + LOG(INFO) << "REINIT DONE"; + } catch (std::exception e) { + LOG(INFO) << "Exception during reinit"; + } + } else { + LOG(INFO) << "NOTHING RECEIVED"; + } + if (ok) { + stateTransition(O2PrimaryServerState::ReadyToServe, "CONTROL"); + } else { + stateTransition(O2PrimaryServerState::Stopped, "CONTROL"); + } + mWaitingControlInput.store(0); } private: - std::string mOutChannelName = ""; - o2::eventgen::PrimaryGenerator mPrimGen; + o2::conf::SimConfig mSimConfig = o2::conf::SimConfig::Instance(); // local sim config object + o2::eventgen::PrimaryGenerator* mPrimGen = nullptr; // the current primary generator o2::dataformats::MCEventHeader mEventHeader; - o2::data::Stack mStack; // the stack which is filled - int mChunkGranularity = 500; // how many primaries to send to a worker - int mLastPosition = 0; // last position in stack vector + o2::data::Stack* mStack = nullptr; // the stack which is filled (pointer since constructor to be called only init method) + int mChunkGranularity = 500; // how many primaries to send to a worker int mPartCounter = 0; bool mNeedNewEvent = true; int mMaxEvents = 2; int mInitialSeed = -1; int mPipeToDriver = -1; // handle for direct piper to driver (to communicate meta info) + int mEventCounter = 0; std::thread mGeneratorThread; //! a thread used to concurrently init the particle generator // or to generate events + std::thread mControlThread; //! a thread used to wait for control commands + + // Keeps various generators instantiated in memory + // useful when running simulation as a service (when generators + // change between batches) + // TODO: some care needs to be taken (or the user warned) that the caching is based on generator name + // and that parameter-based reconfiguration is not yet implemented (for which we would need to hash all + // configuration parameters as well) + std::map<std::string, o2::eventgen::PrimaryGenerator*> mPrimGeneratorCache; + + std::atomic<O2PrimaryServerState> mState{O2PrimaryServerState::Initializing}; + std::atomic<int> mWaitingControlInput{0}; + std::atomic<bool> mInfoThreadStopped{false}; + + bool mAsService = false; }; } // namespace devices diff --git a/run/O2PrimaryServerDeviceRunner.cxx b/run/O2PrimaryServerDeviceRunner.cxx index 647ce65c6c4bc..00cf0d64ac1d1 100644 --- a/run/O2PrimaryServerDeviceRunner.cxx +++ b/run/O2PrimaryServerDeviceRunner.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/run/O2SimDevice.h b/run/O2SimDevice.h index 90f8dad60eea3..967ecd80e8614 100644 --- a/run/O2SimDevice.h +++ b/run/O2SimDevice.h @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -16,6 +17,7 @@ #include <memory> #include "FairMQMessage.h" #include <FairMQDevice.h> +#include <FairMQParts.h> #include <FairLogger.h> #include "../macro/o2sim.C" #include "TVirtualMC.h" @@ -25,6 +27,7 @@ #include <TRandom.h> #include <SimConfig/SimConfig.h> #include <cstring> +#include "PrimaryServerState.h" namespace o2 { @@ -63,7 +66,7 @@ class O2SimDevice final : public FairMQDevice // NOTE: In a FairMQDevice this is better done here (instead of outside) since // we have to setup simulation + worker in the same thread (due to many threadlocal variables // in the simulation) ... at least as long FairMQDevice is not spawning workers on the master thread - initSim(fChannels.at("primary-get").at(0), mSimRun); + initSim(fChannels.at("o2sim-primserv-info").at(0), mSimRun); // set the vmc and app pointers mVMC = TVirtualMC::GetMC(); @@ -85,12 +88,13 @@ class O2SimDevice final : public FairMQDevice // returns true if successful / false if not static bool querySimConfig(FairMQChannel& channel) { - auto text = new std::string("configrequest"); - std::unique_ptr<FairMQMessage> request(channel.NewMessage(const_cast<char*>(text->c_str()), - text->length(), CustomCleanup, text)); + //auto text = new std::string("configrequest"); + //std::unique_ptr<FairMQMessage> request(channel.NewMessage(const_cast<char*>(text->c_str()), + // text->length(), CustomCleanup, text)); + std::unique_ptr<FairMQMessage> request(channel.NewSimpleMessage(O2PrimaryServerInfoRequest::Config)); std::unique_ptr<FairMQMessage> reply(channel.NewMessage()); - int timeoutinMS = 100000; // wait for 100s max + int timeoutinMS = 60000; // wait for 60s max --> should be fast reply if (channel.Send(request, timeoutinMS) > 0) { LOG(INFO) << "Waiting for configuration answer "; if (channel.Receive(reply, timeoutinMS) > 0) { @@ -142,74 +146,136 @@ class O2SimDevice final : public FairMQDevice return true; } - bool Kernel(FairMQChannel& requestchannel, FairMQChannel& dataoutchannel) + bool isWorkAvailable(FairMQChannel& statuschannel, int workerID = -1) { - auto text = new std::string("primrequest"); - - // create message object with a pointer to the data buffer, - // its size, - // custom deletion function (called when transfer is done), - // and pointer to the object managing the data buffer - FairMQMessagePtr request(requestchannel.NewMessage(const_cast<char*>(text->c_str()), // data - text->length(), // size - CustomCleanup, - text)); - FairMQMessagePtr reply(dataoutchannel.NewMessage()); + std::stringstream str; + str << "[W" << workerID << "]"; + auto workerStr = str.str(); + + int timeoutinMS = 2000; // wait for 2s max + bool reprobe = true; + while (reprobe) { + reprobe = false; + int i = -1; + FairMQMessagePtr request(statuschannel.NewSimpleMessage(O2PrimaryServerInfoRequest::Status)); + FairMQMessagePtr reply(statuschannel.NewSimpleMessage(i)); + auto sendcode = statuschannel.Send(request, timeoutinMS); + if (sendcode > 0) { + LOG(INFO) << workerStr << " Waiting for status answer "; + auto code = statuschannel.Receive(reply, timeoutinMS); + if (code > 0) { + int state(*((int*)(reply->GetData()))); + if (state == (int)o2::O2PrimaryServerState::ReadyToServe) { + LOG(INFO) << workerStr << " SERVER IS SERVING"; + return true; + } else if (state == (int)o2::O2PrimaryServerState::Initializing) { + LOG(INFO) << workerStr << " SERVER IS STILL INITIALIZING"; + reprobe = true; + sleep(1); + } else if (state == (int)o2::O2PrimaryServerState::WaitingEvent) { + LOG(INFO) << workerStr << " SERVER IS WAITING FOR EVENT"; + reprobe = true; + sleep(1); + } else if (state == (int)o2::O2PrimaryServerState::Idle) { + LOG(INFO) << workerStr << " SERVER IS IDLE"; + return false; + } else { + LOG(INFO) << workerStr << " SERVER STATE UNKNOWN OR STOPPED"; + } + } else { + LOG(ERROR) << workerStr << " STATUS REQUEST UNSUCCESSFUL"; + } + } + } + return false; + } + + bool Kernel(int workerID, FairMQChannel& requestchannel, FairMQChannel& dataoutchannel, FairMQChannel* statuschannel = nullptr) + { + static int counter = 0; + + FairMQMessagePtr request(requestchannel.NewSimpleMessage(PrimaryChunkRequest{workerID, -1, counter++})); // <-- don't need content; channel means -> give primaries + FairMQParts reply; mVMCApp->setSimDataChannel(&dataoutchannel); - LOG(INFO) << "Requesting work "; - int timeoutinMS = 1000000; // wait for 1000s max -- we should have a more robust solution - // this should be mostly driven by the time to setup the particle generator in the server + // we log info with workerID prepended + auto workerStr = [workerID]() { + std::stringstream str; + str << "[W" << workerID << "]"; + return str.str(); + }; + + LOG(INFO) << workerStr() << " Requesting work chunk"; + int timeoutinMS = 2000; auto sendcode = requestchannel.Send(request, timeoutinMS); if (sendcode > 0) { - LOG(INFO) << "Waiting for answer "; + LOG(INFO) << workerStr() << " Waiting for answer"; // asking for primary generation - int trial = 0; - int code = -1; - do { - code = requestchannel.Receive(reply, timeoutinMS); - trial++; - if (code > 0) { - LOG(INFO) << "Answer received, containing " << reply->GetSize() << " bytes "; - + auto code = requestchannel.Receive(reply); + if (code > 0) { + LOG(INFO) << workerStr() << " Primary chunk received"; + auto rawmessage = std::move(reply.At(0)); + auto header = *(o2::PrimaryChunkAnswer*)(rawmessage->GetData()); + if (!header.payload_attached) { + LOG(INFO) << "No payload; Server in state " << PrimStateToString[(int)header.serverstate]; + // if no payload attached we inspect the server state, to see what to do + if (header.serverstate == O2PrimaryServerState::Initializing || header.serverstate == O2PrimaryServerState::WaitingEvent) { + sleep(1); // back-off and retry + return true; + } + return false; + } else { + auto payload = std::move(reply.At(1)); // wrap incoming bytes as a TMessageWrapper which offers "adoption" of a buffer - auto message = new TMessageWrapper(reply->GetData(), reply->GetSize()); + auto message = new TMessageWrapper(payload->GetData(), payload->GetSize()); auto chunk = static_cast<o2::data::PrimaryChunk*>(message->ReadObjectAny(message->GetClass())); - mVMCApp->setPrimaries(chunk->mParticles); - - auto info = chunk->mSubEventInfo; - mVMCApp->setSubEventInfo(&info); - - LOG(INFO) << "Processing " << chunk->mParticles.size() << " primary particles " - << "for event " << info.eventID << "/" << info.maxEvents << " " - << "part " << info.part << "/" << info.nparts; - gRandom->SetSeed(chunk->mSubEventInfo.seed); - - auto& conf = o2::conf::SimConfig::Instance(); - if (strcmp(conf.getMCEngine().c_str(), "TGeant4") == 0) { - mVMC->ProcessEvent(); - } else { - // for Geant3 at least calling ProcessEvent is not enough - // as some hooks are not called - mVMC->ProcessRun(1); + bool goon = true; + // no particles and eventID == -1 --> indication for no more work + if (chunk->mParticles.size() == 0 && chunk->mSubEventInfo.eventID == -1) { + LOG(INFO) << workerStr() << " No particles in reply : quitting kernel"; + goon = false; } - FairSystemInfo sysinfo; - LOG(INFO) << "TIME-STAMP " << mTimer.RealTime() << "\t"; - mTimer.Continue(); - LOG(INFO) << "MEM-STAMP " << sysinfo.GetCurrentMemory() / (1024. * 1024) << " " - << sysinfo.GetMaxMemory() << " MB\n"; + if (goon) { + mVMCApp->setPrimaries(chunk->mParticles); + + auto info = chunk->mSubEventInfo; + mVMCApp->setSubEventInfo(&info); + + LOG(INFO) << workerStr() << " Processing " << chunk->mParticles.size() << " primary particles " + << "for event " << info.eventID << "/" << info.maxEvents << " " + << "part " << info.part << "/" << info.nparts; + gRandom->SetSeed(chunk->mSubEventInfo.seed); + + // Process one event + auto& conf = o2::conf::SimConfig::Instance(); + if (strcmp(conf.getMCEngine().c_str(), "TGeant4") == 0) { + // this is preferred and necessary for Geant4 + // since repeated "ProcessRun" might have significant overheads + mVMC->ProcessEvent(); + } else { + // for Geant3 calling ProcessEvent is not enough + // as some hooks are not called + mVMC->ProcessRun(1); + } + + FairSystemInfo sysinfo; + LOG(INFO) << workerStr() << " TIME-STAMP " << mTimer.RealTime() << "\t"; + mTimer.Continue(); + LOG(INFO) << workerStr() << " MEM-STAMP " << sysinfo.GetCurrentMemory() / (1024. * 1024) << " " + << sysinfo.GetMaxMemory() << " MB\n"; + } delete message; delete chunk; - } else { - LOG(INFO) << " No answer reveived from server. Return code " << code; } - } while (code == -1 && trial <= 2); + } else { + LOG(INFO) << workerStr() << " No primary answer received from server (within timeout). Return code " << code; + } } else { - LOG(INFO) << " Requesting work from server not possible. Return code " << sendcode; + LOG(INFO) << workerStr() << " Requesting work from server not possible. Return code " << sendcode; return false; } return true; @@ -219,7 +285,7 @@ class O2SimDevice final : public FairMQDevice /// Overloads the ConditionalRun() method of FairMQDevice bool ConditionalRun() final { - return Kernel(fChannels.at("primary-get").at(0), fChannels.at("simdata").at(0)); + return Kernel(-1, fChannels.at("primary-get").at(0), fChannels.at("simdata").at(0)); } void PostRun() final { LOG(INFO) << "Shutting down "; } diff --git a/run/O2SimDeviceRunner.cxx b/run/O2SimDeviceRunner.cxx index 6e30635a129a6..7167ba77f117c 100644 --- a/run/O2SimDeviceRunner.cxx +++ b/run/O2SimDeviceRunner.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -25,30 +26,40 @@ #include <cmath> #include <csignal> #include <unistd.h> +#include "SimPublishChannelHelper.h" #include "rapidjson/document.h" -#include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/filereadstream.h" namespace bpo = boost::program_options; std::vector<int> gChildProcesses; // global vector of child pids int gMasterProcess = -1; +int gDriverProcess = -1; -// custom signal handler to ensure that we -// distribute signals to all detached forks -void sighandler(int signal) +void sigaction_handler(int signal, siginfo_t* signal_info, void*) { - if (signal == SIGTERM || signal == SIGINT) { - auto pid = getpid(); - if (pid == gMasterProcess) { - // the master - for (auto child : gChildProcesses) { - kill(child, signal); - } + auto pid = getpid(); + LOG(INFO) << pid << " caught signal " << signal << " from source " << signal_info->si_pid; + auto groupid = getpgrp(); + if (pid == gMasterProcess) { + killpg(pid, signal); // master kills whole process group + } else { + if (signal_info->si_pid != gDriverProcess) { + // forward to master if coming internally + kill(groupid, signal); } + } + if (signal_info->si_pid == gDriverProcess) { + _exit(0); // external requests are not treated as error + } + if (signal == SIGTERM) { + // normal termination is not error _exit(0); } + // we treat internal signal interruption as an error + // because only ordinary termination is good in the context of the distributed system + _exit(128 + signal); } void addCustomOptions(bpo::options_description& options) @@ -63,7 +74,7 @@ bool initializeSim(std::string transport, std::string address, std::unique_ptr<F { // This needs an already running PrimaryServer auto factory = FairMQTransportFactory::CreateTransportFactory(transport); - auto channel = FairMQChannel{"primary-get", "req", factory}; + auto channel = FairMQChannel{"o2sim-primserv-info", "req", factory}; channel.Connect(address); channel.Validate(); @@ -116,35 +127,53 @@ int initAndRunDevice(int argc, char* argv[]) } } -int runSim(std::string transport, std::string primaddress, std::string mergeraddress) +struct KernelSetup { + o2::devices::O2SimDevice* sim = nullptr; + FairMQChannel* primchannel = nullptr; + FairMQChannel* datachannel = nullptr; + FairMQChannel* primstatuschannel = nullptr; + int workerID = -1; +}; + +KernelSetup initSim(std::string transport, std::string primaddress, std::string primstatusaddress, std::string mergeraddress, int workerID) { auto factory = FairMQTransportFactory::CreateTransportFactory(transport); - auto primchannel = FairMQChannel{"primary-get", "req", factory}; - primchannel.Connect(primaddress); - primchannel.Validate(); + auto primchannel = new FairMQChannel{"primary-get", "req", factory}; + primchannel->Connect(primaddress); + primchannel->Validate(); + + auto prim_status_channel = new FairMQChannel{"o2sim-primserv-info", "req", factory}; + prim_status_channel->Connect(primstatusaddress); + prim_status_channel->Validate(); - auto datachannel = FairMQChannel{"simdata", "push", factory}; - datachannel.Connect(mergeraddress); - datachannel.Validate(); + auto datachannel = new FairMQChannel{"simdata", "push", factory}; + datachannel->Connect(mergeraddress); + datachannel->Validate(); // the channels are setup // init the sim object auto sim = getDevice(); sim->lateInit(); + return KernelSetup{sim, primchannel, datachannel, prim_status_channel, workerID}; +} + +int runSim(KernelSetup setup) +{ // the simplified runloop - while (sim->Kernel(primchannel, datachannel)) { + while (setup.sim->Kernel(setup.workerID, *setup.primchannel, *setup.datachannel, setup.primstatuschannel)) { } - LOG(INFO) << "simulation is done"; + LOG(INFO) << "[W" << setup.workerID << "] simulation is done"; return 0; } void pinToCPU(unsigned int cpuid) { -// MacOS does not support this API so we add a protection -#ifndef __APPLE__ auto affinity = getenv("ALICE_CPUAFFINITY"); if (affinity) { + // MacOS does not support this API so we add a protection +#ifndef __APPLE__ + pthread_t thread; thread = pthread_self(); @@ -169,22 +198,59 @@ void pinToCPU(unsigned int cpuid) LOG(INFO) << "ENABLED CPU " << j; } } - } #else - LOG(WARN) << "CPU AFFINITY NOT IMPLEMENTED ON APPLE"; + LOG(WARN) << "CPU AFFINITY NOT IMPLEMENTED ON APPLE"; #endif + } } -int main(int argc, char* argv[]) +bool waitForControlInput() { - // enable signal handler for termination signals - if (signal(SIGTERM, sighandler) == SIG_IGN) { - signal(SIGTERM, SIG_IGN); + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto channel = FairMQChannel{"o2sim-control", "sub", factory}; + auto controlsocketname = getenv("ALICE_O2SIMCONTROL"); + LOG(DEBUG) << "AWAITING CONTROL ON SOCKETNAME " << controlsocketname; + channel.Connect(std::string(controlsocketname)); + channel.Validate(); + std::unique_ptr<FairMQMessage> reply(channel.NewMessage()); + + LOG(DEBUG) << "WAITING FOR INPUT"; + if (channel.Receive(reply) > 0) { + auto data = reply->GetData(); + auto size = reply->GetSize(); + + std::string command(reinterpret_cast<char const*>(data), size); + LOG(INFO) << "message: " << command; + + o2::conf::SimReconfigData reconfig; + o2::conf::parseSimReconfigFromString(command, reconfig); + if (reconfig.stop) { + LOG(INFO) << "Stop asked, shutting down"; + return false; + } + LOG(INFO) << "Processing " << reconfig.nEvents << " new events"; + } else { + LOG(INFO) << "NOTHING RECEIVED"; } - if (signal(SIGINT, sighandler) == SIG_IGN) { - signal(SIGINT, SIG_IGN); + return true; +} + +int main(int argc, char* argv[]) +{ + struct sigaction act; + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_sigaction = &sigaction_handler; + act.sa_flags = SA_SIGINFO; // <--- enable sigaction + + std::vector<int> handledsignals = {SIGTERM, SIGINT, SIGQUIT, SIGSEGV, SIGBUS, SIGFPE}; // <--- may need to be completed + // remember that SIGKILL can't be handled + for (auto s : handledsignals) { + if (sigaction(s, &act, nullptr)) { + LOG(ERROR) << "Could not install signal handler for " << s; + exit(EXIT_FAILURE); + } } - signal(SIGCHLD, SIG_IGN); /* Silently reap children to avoid zombies. */ // extract the path to FairMQ config bpo::options_description desc{"Options"}; @@ -207,6 +273,9 @@ int main(int argc, char* argv[]) auto internalfork = getenv("ALICE_SIMFORKINTERNAL"); if (internalfork) { + int driverPID = getppid(); + auto pubchannel = o2::simpubsub::createPUBChannel(o2::simpubsub::getPublishAddress("o2sim-worker-notifications", driverPID)); + if (FMQconfig.empty()) { throw std::runtime_error("This should never be called without FairMQ config."); } @@ -218,16 +287,16 @@ int main(int argc, char* argv[]) rapidjson::Document d; d.ParseStream(is); fclose(fp); - // retrieve correct server and merger URLs + // retrieve correct server and merger URLs std::string serveraddress; std::string mergeraddress; + std::string serverstatus_address; std::string s; auto& options = d["fairMQOptions"]; assert(options.IsObject()); - for (auto option = options.MemberBegin(); option != options.MemberEnd(); - ++option) { + for (auto option = options.MemberBegin(); option != options.MemberEnd(); ++option) { s = option->name.GetString(); if (s == "devices") { assert(option->value.IsArray()); @@ -239,6 +308,9 @@ int main(int argc, char* argv[]) auto sockets = (channels[0])["sockets"].GetArray(); auto address = (sockets[0])["address"].GetString(); serveraddress = address; + sockets = (channels[1])["sockets"].GetArray(); + address = (sockets[0])["address"].GetString(); + serverstatus_address = address; } if (s == "hitmerger") { auto channels = device["channels"].GetArray(); @@ -255,8 +327,9 @@ int main(int argc, char* argv[]) } } - LOG(INFO) << serveraddress << "\n"; - LOG(INFO) << mergeraddress << "\n"; + LOG(INFO) << "Parsed primary server address " << serveraddress; + LOG(INFO) << "Parsed primary server status address " << serverstatus_address; + LOG(INFO) << "Parsed merger address " << mergeraddress; if (serveraddress.empty() || mergeraddress.empty()) { throw std::runtime_error("Could not determine server or merger URLs."); } @@ -268,7 +341,7 @@ int main(int argc, char* argv[]) // we init the simulation first std::unique_ptr<FairRunSim> simrun; // TODO: take the addresses from somewhere else - if (!initializeSim("zeromq", serveraddress, simrun)) { + if (!initializeSim("zeromq", serverstatus_address, simrun)) { LOG(ERROR) << "Could not initialize simulation"; return 1; } @@ -282,17 +355,72 @@ int main(int argc, char* argv[]) LOG(INFO) << "Running with " << nworkers << " sim workers "; gMasterProcess = getpid(); + gDriverProcess = getppid(); // then we fork and create a device in each fork for (auto i = 0u; i < nworkers; ++i) { // we use the current process as one of the workers as it has nothing else to do auto pid = (i == nworkers - 1) ? 0 : fork(); if (pid == 0) { + // Each worker can publish its progress/state on a ZMQ channel. + // We actually use a push/pull mechanism to collect all messages in the + // master worker which can then publish using PUB/SUB. + // auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto collectAndPubThreadFunction = [driverPID, &pubchannel]() { + auto collectorchannel = o2::simpubsub::createPUBChannel(o2::simpubsub::getPublishAddress("o2sim-workerinternal", driverPID), "pull"); + std::unique_ptr<FairMQMessage> msg(collectorchannel.NewMessage()); + + while (true) { + if (collectorchannel.Receive(msg) > 0) { + auto data = msg->GetData(); + auto size = msg->GetSize(); + std::string text(reinterpret_cast<char const*>(data), size); + // LOG(INFO) << "Collector message: " << text; + o2::simpubsub::publishMessage(pubchannel, text); + } + } + }; + if (i == nworkers - 1) { // <---- extremely important to take non-forked version since ZMQ sockets do not behave well on fork + std::vector<std::thread> threads; + threads.push_back(std::thread(collectAndPubThreadFunction)); + threads.back().detach(); + } + + // everyone else is getting a push socket for notifications + auto pushchannel = o2::simpubsub::createPUBChannel(o2::simpubsub::getPublishAddress("o2sim-workerinternal", driverPID), "push"); + // we will try to pin each worker to a particular CPU - // this can be made configurable via enviroment variables?? + // this can be made configurable via environment variables?? pinToCPU(i); - runSim("zeromq", serveraddress, mergeraddress); + auto kernelSetup = initSim("zeromq", serveraddress, serverstatus_address, mergeraddress, i); + + std::stringstream worker; + worker << "WORKER" << i; + o2::simpubsub::publishMessage(pushchannel, o2::simpubsub::simStatusString(worker.str(), "STATUS", "SETUP COMPLETED")); + + auto& conf = o2::conf::SimConfig::Instance(); + + bool more = true; + while (more) { + runSim(kernelSetup); + + if (conf.asService()) { + LOG(INFO) << "IN SERVICE MODE WAITING"; + o2::simpubsub::publishMessage(pushchannel, o2::simpubsub::simStatusString(worker.str(), "STATUS", "AWAITING INPUT")); + more = waitForControlInput(); + usleep(100); // --> why? + } else { + o2::simpubsub::publishMessage(pushchannel, o2::simpubsub::simStatusString(worker.str(), "STATUS", "TERMINATING")); + + LOG(INFO) << "FINISHING"; + more = false; + } + } + sleep(10); // ---> give some time for message to be delivered to merger (destructing too early might affect the ZQM buffers) + // The process will in any case be terminated by the main o2-sim driver. + // destruct setup (using _exit due to problems in ROOT shutdown (segmentation violations) + // Clearly at some moment, a more robust solution would be appreciated _exit(0); } else { gChildProcesses.push_back(pid); diff --git a/run/PrimaryServerState.h b/run/PrimaryServerState.h new file mode 100644 index 0000000000000..5a15cca12b9b1 --- /dev/null +++ b/run/PrimaryServerState.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_PRIMARYSERVERSTATE_H +#define O2_PRIMARYSERVERSTATE_H + +namespace o2 +{ + +/// enum to represent state of the O2Sim event/primary server +enum class O2PrimaryServerState { + Initializing = 0, + ReadyToServe = 1, + WaitingEvent = 2, + Idle = 3, + Stopped = 4 +}; +static const char* PrimStateToString[5] = {"INIT", "SERVING", "WAITEVENT", "IDLE", "STOPPED"}; + +/// enum class for type of info request +enum class O2PrimaryServerInfoRequest { + Status = 1, + Config = 2 +}; + +/// Struct to be used as payload when making a request +/// to the primary server +struct PrimaryChunkRequest { + int workerid = -1; + int workerpid = -1; + int requestid = -1; +}; + +/// Struct to be used as header payload when replying to +/// a worker request. +struct PrimaryChunkAnswer { + O2PrimaryServerState serverstate; + bool payload_attached; // whether real payload follows (or server has no work at this moment) +}; + +} // namespace o2 + +#endif //O2_PRIMARYSERVERSTATE_H diff --git a/run/SimExamples/Adaptive_Pythia8/adaptive_pythia8.macro b/run/SimExamples/Adaptive_Pythia8/adaptive_pythia8.macro index f0088e2f58313..b126c0fcfccc6 100644 --- a/run/SimExamples/Adaptive_Pythia8/adaptive_pythia8.macro +++ b/run/SimExamples/Adaptive_Pythia8/adaptive_pythia8.macro @@ -16,7 +16,7 @@ public: // update the number of events to be generated // according to background primaries and formula - void notifyEmbedding(const FairMCEventHeader *bkgHeader) override { + void notifyEmbedding(const o2::dataformats::MCEventHeader *bkgHeader) override { auto nPrimaries = bkgHeader->GetNPrim(); mEvents = mFormula.Eval(nPrimaries); }; diff --git a/run/SimExamples/Adaptive_Pythia8/pythia8_inel.cfg b/run/SimExamples/Adaptive_Pythia8/pythia8_inel.cfg index fdea3cc091984..d5e23efd65139 100644 --- a/run/SimExamples/Adaptive_Pythia8/pythia8_inel.cfg +++ b/run/SimExamples/Adaptive_Pythia8/pythia8_inel.cfg @@ -8,4 +8,4 @@ SoftQCD:inelastic on # all inelastic processes ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/run/SimExamples/AliRoot_AMPT/aliroot_ampt.macro b/run/SimExamples/AliRoot_AMPT/aliroot_ampt.macro index 0d231d1decdc4..09d39f4378527 100644 --- a/run/SimExamples/AliRoot_AMPT/aliroot_ampt.macro +++ b/run/SimExamples/AliRoot_AMPT/aliroot_ampt.macro @@ -76,7 +76,7 @@ public: return o2::eventgen::GeneratorTGenerator::generateEvent(); } - void updateHeader(FairMCEventHeader* eventHeader) { + void updateHeader(o2::dataformats::MCEventHeader* eventHeader) { auto theAMPT = (TAmpt *)mGenAMPT->GetMC(); auto impactB = theAMPT->GetHINT1(19); auto evPlane = theAMPT->GetReactionPlaneAngle(); diff --git a/run/SimExamples/Custom_EventInfo/generator.macro b/run/SimExamples/Custom_EventInfo/generator.macro new file mode 100644 index 0000000000000..62be63a47d9ad --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/generator.macro @@ -0,0 +1,42 @@ +class Generator : public o2::eventgen::GeneratorPythia8 { + +public: + + Generator() = default; + ~Generator() = default; + + /** static functions that define the information + stored in the header (key and data type) + and provide a mean to retrieve it + **/ + + static void setXsection(o2::dataformats::MCEventHeader* head, double val) { head->putInfo<double>("Xsection", val); }; + static double getXsection(o2::dataformats::MCEventHeader* head, bool& isvalid) { return head->getInfo<double>("Xsection", isvalid); }; + + static void setXsectionErr(o2::dataformats::MCEventHeader* head, double val) { head->putInfo<double>("Xsection_err", val); }; + static double getXsectionErr(o2::dataformats::MCEventHeader* head, bool& isvalid) { return head->getInfo<double>("Xsection_err", isvalid); }; + + static void setNmpi(o2::dataformats::MCEventHeader* head, int val) { head->putInfo<int>("Nmpi", val); }; + static int getNmpi(o2::dataformats::MCEventHeader* head, bool& isvalid) { return head->getInfo<int>("Nmpi", isvalid); }; + +private: + + void updateHeader(o2::dataformats::MCEventHeader* head) final { + + // call original function + o2::eventgen::GeneratorPythia8::updateHeader(head); + + // store cross-section and Nmpi + setXsection(head, mPythia.info.sigmaGen()); + setXsectionErr(head, mPythia.info.sigmaErr()); + setNmpi(head, mPythia.info.nMPI()); + + }; + +}; + +FairGenerator* +generator() +{ + return new Generator; +} diff --git a/run/SimExamples/Custom_EventInfo/pythia8_inel.cfg b/run/SimExamples/Custom_EventInfo/pythia8_inel.cfg new file mode 100644 index 0000000000000..d5e23efd65139 --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/pythia8_inel.cfg @@ -0,0 +1,11 @@ +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 14000. # GeV + +### processes +SoftQCD:inelastic on # all inelastic processes + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. diff --git a/run/SimExamples/Custom_EventInfo/read_event_info.macro b/run/SimExamples/Custom_EventInfo/read_event_info.macro new file mode 100644 index 0000000000000..bc2378e58ca0f --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/read_event_info.macro @@ -0,0 +1,31 @@ +#include "generator.macro" + +void +read_event_info(const char *fname) +{ + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto head = new o2::dataformats::MCEventHeader; + tin->SetBranchAddress("MCEventHeader.", &head); + + bool isvalid; + + for (int iev = 0; iev < tin->GetEntries(); ++iev) { + + tin->GetEntry(iev); + + std::cout << " ---------------" << std::endl; + auto Xsection = Generator::getXsection(head, isvalid); + if (isvalid) + std::cout << " Xsection = " << Xsection << std::endl; + auto XsectionErr = Generator::getXsectionErr(head, isvalid); + if (isvalid) + std::cout << " XsectionErr = " << XsectionErr << std::endl; + auto Nmpi = Generator::getNmpi(head, isvalid); + if (isvalid) + std::cout << " Nmpi = " << Nmpi << std::endl; + + } + +} diff --git a/run/SimExamples/Custom_EventInfo/read_event_info_pythia8.macro b/run/SimExamples/Custom_EventInfo/read_event_info_pythia8.macro new file mode 100644 index 0000000000000..77e164f8d4e13 --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/read_event_info_pythia8.macro @@ -0,0 +1,27 @@ +void +read_event_info(const char *fname) +{ + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto head = new o2::dataformats::MCEventHeader; + tin->SetBranchAddress("MCEventHeader.", &head); + + bool isvalid; + + for (int iev = 0; iev < tin->GetEntries(); ++iev) { + + tin->GetEntry(iev); + + std::cout << " ---------------" << std::endl; + auto name = head->getInfo<std::string>("generator", isvalid); + if (isvalid) std::cout << " generator = " << name << std::endl; + auto version = head->getInfo<int>("version", isvalid); + if (isvalid) std::cout << " version = " << version << std::endl; + auto pname = head->getInfo<std::string>("processName", isvalid); + if (isvalid) std::cout << "process name = " << pname << std::endl; + auto pcode = head->getInfo<int>("processCode", isvalid); + if (isvalid) std::cout << "process code = " << pcode << std::endl; + } + +} diff --git a/run/SimExamples/Custom_EventInfo/read_event_info_pythia8hi.macro b/run/SimExamples/Custom_EventInfo/read_event_info_pythia8hi.macro new file mode 100644 index 0000000000000..d076bc0d6ddc9 --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/read_event_info_pythia8hi.macro @@ -0,0 +1,27 @@ +void +read_event_info(const char *fname) +{ + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto head = new o2::dataformats::MCEventHeader; + tin->SetBranchAddress("MCEventHeader.", &head); + + bool isvalid; + + for (int iev = 0; iev < tin->GetEntries(); ++iev) { + + tin->GetEntry(iev); + + std::cout << " ---------------" << std::endl; + auto name = head->getInfo<std::string>("generator", isvalid); + if (isvalid) std::cout << "generator = " << name << std::endl; + auto Bimpact = head->getInfo<double>("Bimpact", isvalid); + if (isvalid) std::cout << " Bimpact = " << Bimpact << std::endl; + auto Ncoll = head->getInfo<int>("Ncoll", isvalid); + if (isvalid) std::cout << " Ncoll = " << Ncoll << std::endl; + auto Npart = head->getInfo<int>("Npart", isvalid); + if (isvalid) std::cout << " Npart = " << Npart << std::endl; + } + +} diff --git a/run/SimExamples/Custom_EventInfo/run.sh b/run/SimExamples/Custom_EventInfo/run.sh new file mode 100755 index 0000000000000..77f14f8d7e3f0 --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/run.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# This is a simulation example showing how to run simulation with Pythia8 +# with an external generator that adds custom information to the event header +# +# + +set -x + +MODULES="PIPE ITS TPC" +EVENTS=100 +NWORKERS=8 + +### generate some events with the external generator that will +### provide some custom information in the event header + +o2-sim -j ${NWORKERS} -n ${EVENTS} -g external -m ${MODULES} \ + --configFile sim.ini > log 2>&1 + +### read the kinematics to print the custom information stored by +### the external generator that we ran before + +root -b -q -l "read_event_info.macro(\"o2sim_Kine.root\")" diff --git a/run/SimExamples/Custom_EventInfo/sim.ini b/run/SimExamples/Custom_EventInfo/sim.ini new file mode 100644 index 0000000000000..708adffd2e11b --- /dev/null +++ b/run/SimExamples/Custom_EventInfo/sim.ini @@ -0,0 +1,6 @@ +[GeneratorExternal] +fileName=generator.macro +funcName=generator() + +[GeneratorPythia8] +config=pythia8_inel.cfg diff --git a/run/SimExamples/HF_Embedding_Pythia8/GeneratorHF.macro b/run/SimExamples/HF_Embedding_Pythia8/GeneratorHF.macro index 249d9de05221c..7c6674deb0de5 100644 --- a/run/SimExamples/HF_Embedding_Pythia8/GeneratorHF.macro +++ b/run/SimExamples/HF_Embedding_Pythia8/GeneratorHF.macro @@ -28,7 +28,7 @@ public: // for each event in case we are in embedding mode. // We use it to setup the number of signal events // to be generated and to be embedded on the background. - void notifyEmbedding(const FairMCEventHeader *bkgHeader) override { + void notifyEmbedding(const o2::dataformats::MCEventHeader *bkgHeader) override { mEvents = mFormula.Eval(bkgHeader->GetB()); std::cout << " --- notify embedding: impact parameter is " << bkgHeader->GetB() << ", generating " << mEvents << " signal events " << std::endl; }; diff --git a/run/SimExamples/HF_Embedding_Pythia8/pythia8_ccbar.template b/run/SimExamples/HF_Embedding_Pythia8/pythia8_ccbar.template index 70c45acc4299b..a01289d6b45bf 100644 --- a/run/SimExamples/HF_Embedding_Pythia8/pythia8_ccbar.template +++ b/run/SimExamples/HF_Embedding_Pythia8/pythia8_ccbar.template @@ -16,4 +16,4 @@ PhaseSpace:pTHatMax ${pTHatMax} # the maximum invariant pT ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/run/SimExamples/Inspect_Hits/left_trace.macro b/run/SimExamples/Inspect_Hits/left_trace.macro new file mode 100644 index 0000000000000..3c3adb6bd033f --- /dev/null +++ b/run/SimExamples/Inspect_Hits/left_trace.macro @@ -0,0 +1,73 @@ +bool +leftTrace_golden(o2::MCTrack& t) +{ + bool trace = false; + trace |= t.leftTrace(o2::detectors::DetID::ITS); + trace |= t.leftTrace(o2::detectors::DetID::TPC); + trace |= t.leftTrace(o2::detectors::DetID::TRD); + trace |= t.leftTrace(o2::detectors::DetID::TOF); + return trace; +} + +bool +leftTrace_barrel(o2::MCTrack& t) +{ + bool trace = false; + trace |= t.leftTrace(o2::detectors::DetID::ITS); + trace |= t.leftTrace(o2::detectors::DetID::TPC); + trace |= t.leftTrace(o2::detectors::DetID::TRD); + trace |= t.leftTrace(o2::detectors::DetID::TOF); + trace |= t.leftTrace(o2::detectors::DetID::HMP); + trace |= t.leftTrace(o2::detectors::DetID::EMC); + trace |= t.leftTrace(o2::detectors::DetID::PHS); + trace |= t.leftTrace(o2::detectors::DetID::FV0); + trace |= t.leftTrace(o2::detectors::DetID::FT0); + return trace; +} + +bool +leftTrace_muon(o2::MCTrack& t) +{ + bool trace = false; + trace |= t.leftTrace(o2::detectors::DetID::ITS); + trace |= t.leftTrace(o2::detectors::DetID::FV0); + trace |= t.leftTrace(o2::detectors::DetID::FT0); + trace |= t.leftTrace(o2::detectors::DetID::MFT); + trace |= t.leftTrace(o2::detectors::DetID::MCH); + trace |= t.leftTrace(o2::detectors::DetID::MID); + return trace; +} + +bool +leftTrace_any(o2::MCTrack& t) +{ + return leftTrace_barrel(t) || leftTrace_muon(t); +} + + +std::function<bool(o2::MCTrack&)> leftTrace_selected = leftTrace_barrel; + +/* +std::map<std::string, std::function<bool(o2::MCTrack&)> leftTrace = { + {"golden", leftTrace_golden}, + {"barrel", leftTrace_barrel}, + {"muon" , leftTrace_muon} , + {"any" , leftTrace_any} +}; +*/ + +bool +leftTrace(o2::MCTrack& t, vector<o2::MCTrack>* tracks) { + if (leftTrace_selected(t)) return true; // this track has left trace in requested detectors + // if (leftTrace_barrel(t)) return true; // this track has left trace in requested detectors + // check if any of the daughters left trace + auto id1 = t.getFirstDaughterTrackId(); + auto id2 = t.getLastDaughterTrackId(); + if (id1 == -1) return false; // no daughters, no trace + bool trace = false; + for (int id = id1; id <= id2; ++id) { + auto d = tracks->at(id); + trace |= leftTrace(d, tracks); // at least one daughter has left trace + } + return trace; +} diff --git a/run/SimExamples/Inspect_Hits/plot_primary.macro b/run/SimExamples/Inspect_Hits/plot_primary.macro new file mode 100644 index 0000000000000..8873a5e4bca5b --- /dev/null +++ b/run/SimExamples/Inspect_Hits/plot_primary.macro @@ -0,0 +1,54 @@ +#include "style.macro" + +int rebinx = 1; +int rebiny = 1; + +void plot_primary(const char *fname, int pdg); + +void plot_primary(const char *fname) +{ + + std::vector<int> pdgs = {11, 13, 22, 211, 321, 2112, 2212}; + for (int pdg : pdgs) + plot_primary(fname, pdg); + +} + +void +plot_primary(const char *fname, int pdg) +{ + + style(); + gStyle->SetPalette(1); + + auto c = new TCanvas("c", "c", 800, 400); + c->Divide(2, 1); + + auto fin = TFile::Open(fname); + auto hgen = (TH2*)fin->Get(Form("hEtaPtGen_%d", pdg)); + hgen->SetTitle(";#eta;#it{p}_{T} (GeV/#it{c})"); + hgen->RebinX(rebinx); + hgen->RebinY(rebiny); + auto hhit = (TH2*)fin->Get(Form("hEtaPtHit_%d", pdg)); + hhit->SetTitle(";#eta;#it{p}_{T} (GeV/#it{c})"); + hhit->RebinX(rebinx); + hhit->RebinY(rebiny); + + c->cd(1)->SetLogz(); + hgen->Draw("col"); + c->cd(2)->SetLogz(); + hhit->Draw("col"); + + c->cd(2)->SetLogz(); + auto heff = (TH2*)hhit->Clone("heff"); + heff->Divide(hhit, hgen, 1., 1., "B"); + heff->SetMinimum(1.e-3); + heff->SetMaximum(1.); + heff->Draw("col"); + + std::string fnameout = fname; + fnameout.erase(fnameout.find("root"), 4); + fnameout += std::to_string(pdg) + ".png"; + c->SaveAs(fnameout.c_str()); + +} diff --git a/run/SimExamples/Inspect_Hits/plot_secondary.macro b/run/SimExamples/Inspect_Hits/plot_secondary.macro new file mode 100644 index 0000000000000..950178cd1be46 --- /dev/null +++ b/run/SimExamples/Inspect_Hits/plot_secondary.macro @@ -0,0 +1,55 @@ +#include "style.macro" + +int rebinx = 10; +int rebiny = 10; + +void plot_secondary(const char *fname, int pdg); + +void plot_secondary(const char *fname) +{ + + std::vector<int> pdgs = {11, 13, 22, 211, 321, 2112, 2212}; + for (int pdg : pdgs) + plot_secondary(fname, pdg); + +} + + +void +plot_secondary(const char *fname, int pdg) +{ + + style(); + gStyle->SetPalette(1); + + auto c = new TCanvas("c", "c", 800, 400); + c->Divide(2, 1); + + auto fin = TFile::Open(fname); + auto hgen = (TH2*)fin->Get(Form("hZRGen_%d", pdg)); + hgen->SetTitle(";z (cm);R (cm)"); + hgen->RebinX(rebinx); + hgen->RebinY(rebiny); + auto hhit = (TH2*)fin->Get(Form("hZRHit_%d", pdg)); + hhit->SetTitle(";z (cm);R (cm)"); + hhit->RebinX(rebinx); + hhit->RebinY(rebiny); + + c->cd(1)->SetLogz(); + hgen->Draw("col"); + c->cd(2)->SetLogz(); + hhit->Draw("col"); + + c->cd(2)->SetLogz(); + auto heff = (TH2*)hhit->Clone("heff"); + heff->Divide(hhit, hgen, 1., 1., "B"); + heff->SetMinimum(1.e-3); + heff->SetMaximum(1.); + heff->Draw("col"); + + std::string fnameout = fname; + fnameout.erase(fnameout.find("root"), 4); + fnameout += std::to_string(pdg) + ".png"; + c->SaveAs(fnameout.c_str()); + +} diff --git a/run/SimExamples/Inspect_Hits/primary_and_hits.macro b/run/SimExamples/Inspect_Hits/primary_and_hits.macro new file mode 100644 index 0000000000000..dd8ce743d58c0 --- /dev/null +++ b/run/SimExamples/Inspect_Hits/primary_and_hits.macro @@ -0,0 +1,48 @@ +#include "left_trace.macro" + +void +primary_and_hits(const char *fname, std::string where = "barrel") +{ + + if (where.compare("golden") == 0) leftTrace_selected = leftTrace_golden; + if (where.compare("barrel") == 0) leftTrace_selected = leftTrace_barrel; + if (where.compare("muon") == 0) leftTrace_selected = leftTrace_muon; + if (where.compare("any") == 0) leftTrace_selected = leftTrace_any; + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto tracks = new vector<o2::MCTrack>; + tin->SetBranchAddress("MCTrack", &tracks); + auto nev = tin->GetEntries(); + + std::map<int, TH2F*> hEtaPtGen, hEtaPtHit; + + for (int iev = 0; iev < nev; ++iev) { + tin->GetEntry(iev); + for (int itr = 0; itr < tracks->size(); ++itr) { + auto& t = tracks->at(itr); + if (!t.isPrimary()) continue; + if (!t.isTransported()) continue; + auto pdg = std::abs(t.GetPdgCode()); + if (hEtaPtGen.count(pdg) == 0) { + hEtaPtGen[pdg] = new TH2F(Form("hEtaPtGen_%d", pdg), "", 500, -25, 25., 100, 0., 1.); + hEtaPtHit[pdg] = new TH2F(Form("hEtaPtHit_%d", pdg), "", 500, -25, 25., 100, 0., 1.); + } + + hEtaPtGen[pdg]->Fill(t.GetEta(), t.GetPt()); + + if (!leftTrace(t, tracks)) continue; + + hEtaPtHit[pdg]->Fill(t.GetEta(), t.GetPt()); + + } + } + + std::string foutname = "primary_and_hits." + where + ".root"; + auto fout = TFile::Open(foutname.c_str(), "RECREATE"); + for (auto& h : hEtaPtGen) h.second->Write(); + for (auto& h : hEtaPtHit) h.second->Write(); + fout->Close(); + fin->Close(); + +} diff --git a/run/SimExamples/Inspect_Hits/run.sh b/run/SimExamples/Inspect_Hits/run.sh new file mode 100755 index 0000000000000..caebcd70c5ae8 --- /dev/null +++ b/run/SimExamples/Inspect_Hits/run.sh @@ -0,0 +1,34 @@ +#! /usr/bin/env bash + +NRUNS=100 +NJOBS=4 +NEVENTS=1000 +GEANT=TGeant3 + +shopt -s extglob + +for I in $(seq -w 1 $NRUNS); do + + DIR="RUN$I" + mkdir $DIR + cp left_trace.macro $DIR/. + cp primary_and_hits.macro $DIR/. + cp secondary_and_hits.macro $DIR/. + cd $DIR + echo " --- starting run $I" + o2-sim -j $NJOBS -n $NEVENTS -e $GEANT -g pythia8pp --skipModules ZDC --configKeyValues "Stack.pruneKine=false" &> o2-sim.log + + root -b -q -l "primary_and_hits.macro(\"o2sim_Kine.root\", \"barrel\")" & + root -b -q -l "primary_and_hits.macro(\"o2sim_Kine.root\", \"muon\")" & + root -b -q -l "primary_and_hits.macro(\"o2sim_Kine.root\", \"any\")" & + + root -b -q -l "secondary_and_hits.macro(\"o2sim_Kine.root\", \"barrel\")" & + root -b -q -l "secondary_and_hits.macro(\"o2sim_Kine.root\", \"muon\")" & + root -b -q -l "secondary_and_hits.macro(\"o2sim_Kine.root\", \"any\")" & + + wait + + rm !(*and_hits.*.root) + + cd .. +done diff --git a/run/SimExamples/Inspect_Hits/secondary_and_hits.macro b/run/SimExamples/Inspect_Hits/secondary_and_hits.macro new file mode 100644 index 0000000000000..9a21924e62b2d --- /dev/null +++ b/run/SimExamples/Inspect_Hits/secondary_and_hits.macro @@ -0,0 +1,49 @@ +#include "left_trace.macro" + +void +secondary_and_hits(const char *fname, std::string where = "barrel") +{ + + if (where.compare("golden") == 0) leftTrace_selected = leftTrace_golden; + if (where.compare("barrel") == 0) leftTrace_selected = leftTrace_barrel; + if (where.compare("muon") == 0) leftTrace_selected = leftTrace_muon; + if (where.compare("any") == 0) leftTrace_selected = leftTrace_any; + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto tracks = new vector<o2::MCTrack>; + tin->SetBranchAddress("MCTrack", &tracks); + auto nev = tin->GetEntries(); + + std::map<int, TH2F*> hZRGen, hZRHit; + + for (int iev = 0; iev < nev; ++iev) { + tin->GetEntry(iev); + for (int itr = 0; itr < tracks->size(); ++itr) { + auto& t = tracks->at(itr); + if (!t.isTransported()) continue; + auto pdg = std::abs(t.GetPdgCode()); + if (hZRGen.count(pdg) == 0) { + hZRGen[pdg] = new TH2F(Form("hZRGen_%d", pdg), "", 4000, -2000., 2000., 1000, 0., 1000.); + hZRHit[pdg] = new TH2F(Form("hZRHit_%d", pdg), "", 4000, -2000., 2000., 1000, 0., 1000); + } + + auto z = t.GetStartVertexCoordinatesZ(); + auto R = std::hypot(t.GetStartVertexCoordinatesX(), t.GetStartVertexCoordinatesY()); + hZRGen[pdg]->Fill(z, R); + + if (!leftTrace(t, tracks)) continue; + + hZRHit[pdg]->Fill(z, R); + + } + } + + std::string foutname = "secondary_and_hits." + where + ".root"; + auto fout = TFile::Open(foutname.c_str(), "RECREATE"); + for (auto& h : hZRGen) h.second->Write(); + for (auto& h : hZRHit) h.second->Write(); + fout->Close(); + fin->Close(); + +} diff --git a/run/SimExamples/Inspect_Hits/style.macro b/run/SimExamples/Inspect_Hits/style.macro new file mode 100644 index 0000000000000..71e31bff052ce --- /dev/null +++ b/run/SimExamples/Inspect_Hits/style.macro @@ -0,0 +1,110 @@ +#ifndef style_C +#define style_C + +void style() +{ + + gStyle->SetPadColor(0); + gStyle->SetPadBorderSize(0); + gStyle->SetPadBorderMode(0); + gStyle->SetPadTickX(1); + gStyle->SetPadTickY(1); + gStyle->SetCanvasColor(0); + gStyle->SetCanvasBorderMode(0); + gStyle->SetCanvasBorderSize(0); + gStyle->SetFrameBorderMode(0); + //gStyle->SetFrameLineColor(0); + gStyle->SetFrameFillColor(0); + + //gStyle->SetOptStat(00000); + //gStyle->SetTitleColor(0); + gStyle->SetTitleBorderSize(0); + // gStyle->SetTitleTextColor(0); + // gStyle->SetTitleFillColor(0); + + /* + gStyle->SetTitleColor(0); + gStyle->SetTitleBorderSize(0); + gStyle->SetTitleTextColor(0); + gStyle->SetTitleFillColor(0); + */ + // gStyle->SetPalette(1); + gStyle->SetCanvasColor(0); + gStyle->SetHistFillColor(0); + gStyle->SetHistFillStyle(0); + gStyle->SetOptStat(0); + // gStyle->SetPadTickX(1); + // gStyle->SetPadTickY(1); + gStyle->SetAxisColor(1, "X"); + gStyle->SetAxisColor(1, "Y"); + gStyle->SetAxisColor(1, "Z"); + /* + gStyle->SetLabelColor(0, "X"); + gStyle->SetLabelColor(0, "Y"); + gStyle->SetLabelColor(0, "Z"); + gStyle->SetTickLength(0.0, "X"); + gStyle->SetTickLength(0.0, "Y"); + gStyle->SetTickLength(0.0, "Z"); + */ + gStyle->SetTitleXSize(0.05); + gStyle->SetTitleYSize(0.05); + gStyle->SetNdivisions(506, "X"); + gStyle->SetNdivisions(506, "Y"); + gStyle->SetNdivisions(506, "Z"); + + //gStyle->SetPadGridX(1); + //gStyle->SetPadGridY(1); + + //gStyle->SetLabelOffset(0.02, "X"); + //gStyle->SetLabelOffset(0.01, "Y"); + //gStyle->SetLabelOffset(0.02, "Z"); + gStyle->SetLabelSize(0.04, "xyz"); + gStyle->SetTitleOffset(1.2,"xyz"); + gStyle->SetTitleFont(42,"xyz"); + + gStyle->SetTextFont(42); + gStyle->SetTextSize(0.06); + + gStyle->SetPadLeftMargin(0.15); + gStyle->SetPadRightMargin(0.05); + gStyle->SetPadBottomMargin(0.15); + gStyle->SetPadTopMargin(0.05); + + gROOT->ForceStyle(); + +} + +void SetGraphStyle(TGraph *g, Int_t m, Int_t c) +{ + g->SetMarkerStyle(m); + g->SetMarkerColor(c); + g->SetLineColor(c); + g->SetLineWidth(1); + g->SetFillStyle(0); + g->SetFillColor(0); + g->SetMarkerSize(2.0); + if (m == 28 || m == 34 || m == 23 || m == 32 || m == 22) + g->SetMarkerSize(2.5); + if (m == 27 || m == 33 || m == 30 || m == 29) + g->SetMarkerSize(3.0); +} + +void SetHistoStyle(TH1 *h, Int_t m, Int_t c, Int_t w = 1, Int_t s = 1) +{ + h->SetMarkerStyle(m); + h->SetMarkerColor(c); + h->SetLineColor(c); + h->SetLineWidth(w); + h->SetLineStyle(s); + h->SetFillStyle(0); + h->SetFillColor(0); + h->SetMarkerSize(2.0); + if (m == 28 || m == 34 || m == 23 || m == 32 || m == 22) + h->SetMarkerSize(2.5); + if (m == 27 || m == 33 || m == 30 || m == 29) + h->SetMarkerSize(3.0); + if (m == 0) + h->SetMarkerSize(0); +} + +#endif /* style_C */ diff --git a/run/SimExamples/Jet_Embedding_Pythia8/pythia8_hard.cfg b/run/SimExamples/Jet_Embedding_Pythia8/pythia8_hard.cfg index 5460f0eebc57e..14917d7344157 100644 --- a/run/SimExamples/Jet_Embedding_Pythia8/pythia8_hard.cfg +++ b/run/SimExamples/Jet_Embedding_Pythia8/pythia8_hard.cfg @@ -10,4 +10,4 @@ PhaseSpace:pTHatMin 500. # min pT hat ### decays ParticleDecays:limitTau0 on -ParticleDecays:tau0Max 0.001 +ParticleDecays:tau0Max 10. diff --git a/run/SimExamples/Jet_Embedding_Pythia8/pythia8_userhooks_jets.macro b/run/SimExamples/Jet_Embedding_Pythia8/pythia8_userhooks_jets.macro index 9986f65e3e5df..47c7c0f607264 100644 --- a/run/SimExamples/Jet_Embedding_Pythia8/pythia8_userhooks_jets.macro +++ b/run/SimExamples/Jet_Embedding_Pythia8/pythia8_userhooks_jets.macro @@ -1,6 +1,6 @@ // Pythia8 UserHooks // -// usage: o2sim -g pythia8 --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_jets.C" +// usage: o2sim -g pythia8pp --configKeyValues "GeneratorPythia8.hooksFileName=pythia8_userhooks_jets.C" // /// \author R+Preghenella - April 2020 diff --git a/run/SimExamples/Jet_Embedding_Pythia8/run.sh b/run/SimExamples/Jet_Embedding_Pythia8/run.sh index e063ee2a1b872..9529039e68754 100755 --- a/run/SimExamples/Jet_Embedding_Pythia8/run.sh +++ b/run/SimExamples/Jet_Embedding_Pythia8/run.sh @@ -19,7 +19,7 @@ o2-sim -j 20 -n ${NBGR} -g pythia8hi -m PIPE ITS TPC -o bkg --configKeyValues \ # produce hard jets using a pythia8 configuration given in a file 'pythia8_hard.cfg'; event selection is done by a user hook specified # in file 'pythia8_userhooks_jets.macro' and using same vertex setting as background events (via --embedInto) NSGN=10 -o2-sim -j 20 -n ${NSGN} -g pythia8 -m PIPE ITS TPC --configKeyValues "GeneratorPythia8.config=pythia8_hard.cfg;GeneratorPythia8.hooksFileName=pythia8_userhooks_jets.macro" --embedIntoFile bkg_Kine.root -o sgn > logsgn 2>&1 +o2-sim -j 20 -n ${NSGN} -g pythia8pp -m PIPE ITS TPC --configKeyValues "GeneratorPythia8.config=pythia8_hard.cfg;GeneratorPythia8.hooksFileName=pythia8_userhooks_jets.macro" --embedIntoFile bkg_Kine.root -o sgn > logsgn 2>&1 # PART c) # digitization with summation of signal on top of background events diff --git a/run/SimExamples/JustPrimaryKinematics/only_primarykine.ini b/run/SimExamples/JustPrimaryKinematics/only_primarykine.ini new file mode 100644 index 0000000000000..43daa9f866da4 --- /dev/null +++ b/run/SimExamples/JustPrimaryKinematics/only_primarykine.ini @@ -0,0 +1,20 @@ +[SimCutParams] +maxRTracking=2 +maxAbsZTracking=2 +ZmaxA=2 +ZmaxC=2 +[GlobalSimProcs] +PAIR=0 +COMP=0 +PHOT=0 +PFIS=0 +DRAY=0 +ANNI=0 +BREM=0 +HADR=0 +MUNU=0 +DCAY=0 +LOSS=0 +MULS=0 +CKOV=0 + diff --git a/run/SimExamples/JustPrimaryKinematics/run.sh b/run/SimExamples/JustPrimaryKinematics/run.sh new file mode 100755 index 0000000000000..ab1b285bf0782 --- /dev/null +++ b/run/SimExamples/JustPrimaryKinematics/run.sh @@ -0,0 +1,14 @@ +# A very simple example, showing how to configure o2-sim to skip +# transport/physics and save just the originally generated event. +# While this can be achieved in potentially many ways, the example is instructive +# to demonstrate the configuration mechanism in general. +# Here the mechanism is to switch off physics in the configuration file and set very +# tight geometry cuts so that Geant will not do work. + +# first stage --> produce events using Pythia8 (no transport) +o2-sim -n 10 -g pythia8pp -m CAVE --configFile only_primarykine.ini + +# second stage --> read back events from O2 kine (no transport) +o2-sim -n 10 -g extkinO2 --extKinFile o2sim_Kine.root -m CAVE --configFile only_primarykine.ini -o o2sim2 + +# ideally here, both kinematics files should be identical diff --git a/run/SimExamples/README.md b/run/SimExamples/README.md index d589dc43a1115..a6a2cbc8bc1d0 100644 --- a/run/SimExamples/README.md +++ b/run/SimExamples/README.md @@ -15,4 +15,8 @@ * \subpage refrunSimExamplesJet_Embedding_Pythia8 * \subpage refrunSimExamplesStepMonitoringSimple1 * \subpage refrunSimExamplesForceDecay_Lambda_Neutron_Dalitz +* \subpage refrunSimExamplesJustPrimaryKinematics +* \subpage refrunSimExamplesSelective_Transport +* \subpage refrunSimExamplesSelective_Transport_pi0 +* \subpage refrunSimExamplesCustom_EventInfo /doxy --> diff --git a/run/SimExamples/Selective_Transport/run.sh b/run/SimExamples/Selective_Transport/run.sh new file mode 100755 index 0000000000000..8ba13e41442c4 --- /dev/null +++ b/run/SimExamples/Selective_Transport/run.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# +# This is a simulation example showing how to run simulation and selectively +# transport particles through the detector geometry according to configurable settings +# +# The simulation uses Pythia8 pp generator with default settings. +# The specific settings of the simulation are defined in the sim.ini file. +# +# Only the parameters for the selective particle transport are adjusted, namely +# ``` +# [Stack] +# transportPrimary=external +# transportPrimaryFileName=transportPDG.macro +# transportPrimaryFuncName=transportPDG(321) +# transportPrimaryInvert=false +# ``` +# +# `transportPrimary` defines the mode of selection, `external` means that the definition is loaded from a plugin macro +# defined by the function call `transportPrimaryFuncName` from the file `transportPrimaryFileName`. +# `transportPrimaryInvert` allows one to invert the definition, hence to inhibit transport for the selected particles. +# + +set -x + +MODULES="PIPE ITS TPC" +EVENTS=100 +NWORKERS=8 + +o2-sim -j ${NWORKERS} -n ${EVENTS} -g pythia8pp -m ${MODULES} -o step1 \ + --configFile sim.ini \ + > logstep1 2>&1 + diff --git a/run/SimExamples/Selective_Transport/sim.ini b/run/SimExamples/Selective_Transport/sim.ini new file mode 100644 index 0000000000000..c445eca8c3098 --- /dev/null +++ b/run/SimExamples/Selective_Transport/sim.ini @@ -0,0 +1,5 @@ +[Stack] +transportPrimary=external +transportPrimaryFileName=transportPDG.macro +transportPrimaryFuncName=transportPDG(321) +transportPrimaryInvert=false diff --git a/run/SimExamples/Selective_Transport/transportPDG.macro b/run/SimExamples/Selective_Transport/transportPDG.macro new file mode 100644 index 0000000000000..942d3db4fe43f --- /dev/null +++ b/run/SimExamples/Selective_Transport/transportPDG.macro @@ -0,0 +1,7 @@ +o2::data::Stack::TransportFcn +transportPDG(int pdg = 321) +{ + return [pdg](const TParticle& p, const std::vector<TParticle>& particles) -> bool { + return p.GetPdgCode() == pdg; + }; +} diff --git a/run/SimExamples/Selective_Transport_pi0/check_kine.macro b/run/SimExamples/Selective_Transport_pi0/check_kine.macro new file mode 100644 index 0000000000000..ee4ee1ed057cb --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/check_kine.macro @@ -0,0 +1,83 @@ +void +check_kine(const char *fname1, const char *fname2) +{ + + auto fin1 = TFile::Open(fname1); + auto tin1 = (TTree*)fin1->Get("o2sim"); + auto tracks1 = new vector<o2::MCTrack>; + tin1->SetBranchAddress("MCTrack", &tracks1); + + auto fin2 = TFile::Open(fname2); + auto tin2 = (TTree*)fin2->Get("o2sim"); + auto tracks2 = new vector<o2::MCTrack>; + auto head2 = new o2::dataformats::MCEventHeader; + tin2->SetBranchAddress("MCEventHeader.", &head2); + tin2->SetBranchAddress("MCTrack", &tracks2); + + bool isvalid; + + for (int iev2 = 0; iev2 < tin2->GetEntries(); ++iev2) { + + tin2->GetEntry(iev2); + + auto iev1 = head2->getInfo<int>("inputEventNumber", isvalid); + tin1->GetEntry(iev1); + + std::cout << "--- event2 " << iev2 << ", event1 " << iev1 << ": " + << tracks1->size() << " " << tracks2->size() << std::endl; + + std::cout << "itrk" << " " + << "st1" << " " + << "st2" << "\t" + << "pdg" << "\t" + << "M1" << "\t" + << "M2" << "\t" + << "D1" << "\t" + << "D2" << "\t" + << std::endl; + + for (int itr = 0; itr < tracks1->size(); ++itr) { + + auto& t1 = tracks1->at(itr); + auto& t2 = tracks2->at(itr); + + // check that the two tracks are identical + if (t1.GetPdgCode() != t2.GetPdgCode() || + t1.getMotherTrackId() != t2.getMotherTrackId() || + t1.getSecondMotherTrackId() != t2.getSecondMotherTrackId()) {// || + // t1.getFirstDaughterTrackId() != t2.getFirstDaughterTrackId() || + // t1.getLastDaughterTrackId() != t2.getLastDaughterTrackId()) { + std::cout << itr << " tracks are not identical " << std::endl; + } + + std::cout << itr << " " + << t1.isPrimary() << t1.getToBeDone() << t1.getInhibited() << " " + << t2.isPrimary() << t2.getToBeDone() << t2.getInhibited() << "\t" + << t2.GetPdgCode() << "\t" + << t2.getMotherTrackId() << "\t" + << t2.getSecondMotherTrackId() << "\t" + << t2.getFirstDaughterTrackId() << "\t" + << t2.getLastDaughterTrackId() << "\t" + << std::endl; + + } + + for (int itr = tracks1->size(); itr < tracks2->size(); ++itr) { + + auto& t2 = tracks2->at(itr); + + std::cout << itr << " " + << "---" << " " + << t2.isPrimary() << t2.getToBeDone() << t2.getInhibited() << "\t" + << t2.GetPdgCode() << "\t" + << t2.getMotherTrackId() << "\t" + << t2.getSecondMotherTrackId() << "\t" + << t2.getFirstDaughterTrackId() << "\t" + << t2.getLastDaughterTrackId() << "\t" + << std::endl; + + } + + } + +} diff --git a/run/SimExamples/Selective_Transport_pi0/check_kine_labels.macro b/run/SimExamples/Selective_Transport_pi0/check_kine_labels.macro new file mode 100644 index 0000000000000..98b344dac7564 --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/check_kine_labels.macro @@ -0,0 +1,79 @@ +void print(int itr, o2::MCTrack& t) { +std::cout << itr << " " + << t.isPrimary() << t.getToBeDone() << t.getInhibited() << " " + << t.isPrimary() << t.getToBeDone() << t.getInhibited() << "\t" + << t.GetPdgCode() << "\t" + << t.getMotherTrackId() << "\t" + << t.getSecondMotherTrackId() << "\t" + << t.getFirstDaughterTrackId() << "\t" + << t.getLastDaughterTrackId() << "\t" + << std::endl; + } + + +void +check_kine_labels(const char *fname) +{ + + auto fin = TFile::Open(fname); + auto tin = (TTree*)fin->Get("o2sim"); + auto tracks = new vector<o2::MCTrack>; + tin->SetBranchAddress("MCTrack", &tracks); + auto nev = tin->GetEntries(); + + // loop over events + for (int iev = 0; iev < nev; ++iev) { + tin->GetEntry(iev); + + // loop over tracks from the beginning + for (int itr = 0; itr < tracks->size(); ++itr) { + auto& t = tracks->at(itr); + // print(itr, t); + auto id1 = t.getFirstDaughterTrackId(); + auto id2 = t.getLastDaughterTrackId(); + if (id1 == -1) continue; // track has no daughter + + // loop over daughters + for (int jtr = id1; jtr <= id2; ++jtr) { + auto& d = tracks->at(jtr); + + if (d.getSecondMotherTrackId() == -1) { // if it only has first mother, check label is the same + if (itr != d.getMotherTrackId()) { + std::cout << "THIS IS WRONG (looping forward)" << std::endl; + std::cout << "mother: "; print(itr, t); + std::cout << "daughter: "; print(jtr, d); + } + } else { // else if it has first and second mother, check that label is in between + if (itr < d.getMotherTrackId() || itr > d.getSecondMotherTrackId()) { + std::cout << "THIS IS WRONG (looping forward)" << std::endl; + std::cout << "mother: "; print(itr, t); + std::cout << "daughter: "; print(jtr, d); + } + } + } + } + + // loop over tracks from the end + for (int itr = tracks->size() - 1; itr >= 0; --itr) { + + auto& t = tracks->at(itr); + auto im1 = t.getMotherTrackId(); + auto im2 = t.getSecondMotherTrackId(); + if (im1 == -1) continue; // track has no mother + if (im2 == -1) { // track has only one mother + auto& m = tracks->at(im1); + if (itr < m.getFirstDaughterTrackId() || itr > m.getLastDaughterTrackId()) { + std::cout << "THIS IS WRONG (looping backward)" << std::endl; + std::cout << "mother: "; print(im1, m); + std::cout << "daughter: "; print(itr, t); + } + } else { // track has first and second mother + continue; + + } + + } + + } + +} diff --git a/run/SimExamples/Selective_Transport_pi0/read_kine.macro b/run/SimExamples/Selective_Transport_pi0/read_kine.macro new file mode 100644 index 0000000000000..d52daced2a43d --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/read_kine.macro @@ -0,0 +1,38 @@ +void +read_kine(const char *fname1, int iev1 = 0) +{ + + auto fin1 = TFile::Open(fname1); + auto tin1 = (TTree*)fin1->Get("o2sim"); + auto tracks1 = new vector<o2::MCTrack>; + tin1->SetBranchAddress("MCTrack", &tracks1); + + tin1->GetEntry(iev1); + + std::cout << "itrk" << " " + << "st1" << " " + << "st2" << "\t" + << "pdg" << "\t" + << "M1" << "\t" + << "M2" << "\t" + << "D1" << "\t" + << "D2" << "\t" + << std::endl; + + for (int itr = 0; itr < tracks1->size(); ++itr) { + + auto& t1 = tracks1->at(itr); + + std::cout << itr << " " + << t1.isPrimary() << t1.getToBeDone() << t1.getInhibited() << " " + << t1.isPrimary() << t1.getToBeDone() << t1.getInhibited() << "\t" + << t1.GetPdgCode() << "\t" + << t1.getMotherTrackId() << "\t" + << t1.getSecondMotherTrackId() << "\t" + << t1.getFirstDaughterTrackId() << "\t" + << t1.getLastDaughterTrackId() << "\t" + << std::endl; + + } + +} diff --git a/run/SimExamples/Selective_Transport_pi0/run.sh b/run/SimExamples/Selective_Transport_pi0/run.sh new file mode 100755 index 0000000000000..98378d0d82547 --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/run.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# This is a simulation example showing how to run simulation and selectively +# transport particles through the detector geometry according to configurable settings +# +# The simulation uses Pythia8 pp generator with default settings. +# The specific settings of the simulation are defined in the sim.ini file. +# +# Only the parameters for the selective particle transport are adjusted, namely +# ``` +# [Stack] +# transportPrimary=external +# transportPrimaryFileName=transportPDG.macro +# transportPrimaryFuncName=transportPDG(321) +# transportPrimaryInvert=false +# ``` +# +# `transportPrimary` defines the mode of selection, `external` means that the definition is loaded from a plugin macro +# defined by the function call `transportPrimaryFuncName` from the file `transportPrimaryFileName`. +# `transportPrimaryInvert` allows one to invert the definition, hence to inhibit transport for the selected particles. +# +# +# The second step of this simulation examples shows how to continue the simulation from the first +# step and propagate all the remaining tracks. The process is done only for events that pass a specific +# trigger which requires that both photons from pi0 decay have converted within a given region. +# + +set -x + +MODULES="PIPE ITS TPC" +NEVENTS1=100 +NEVENTS2=1 +NWORKERS=1 + +### step 1 + +o2-sim -j ${NWORKERS} -n ${NEVENTS1} -g pythia8pp -m ${MODULES} -o step1 \ + --configFile sim_step1.ini --seed 73141128 + +### step 2 + +o2-sim -j ${NWORKERS} -n ${NEVENTS2} -g extkinO2 -m ${MODULES} -o step2 \ + --extKinFile step1_Kine.root \ + --configFile sim_step2.ini \ + --trigger external + diff --git a/run/SimExamples/Selective_Transport_pi0/sim_step1.ini b/run/SimExamples/Selective_Transport_pi0/sim_step1.ini new file mode 100644 index 0000000000000..c10e1afe29368 --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/sim_step1.ini @@ -0,0 +1,5 @@ +[Stack] +transportPrimary=external +transportPrimaryFileName=transport_pi0.macro +transportPrimaryFuncName=transport_pi0() +transportPrimaryInvert=false diff --git a/run/SimExamples/Selective_Transport_pi0/sim_step2.ini b/run/SimExamples/Selective_Transport_pi0/sim_step2.ini new file mode 100644 index 0000000000000..216fc4f07d809 --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/sim_step2.ini @@ -0,0 +1,6 @@ +[TriggerExternal] +fileName=trigger_pi0.macro +funcName=trigger_pi0() + +[GeneratorFromO2Kine] +continueMode=true diff --git a/run/SimExamples/Selective_Transport_pi0/transport_pi0.macro b/run/SimExamples/Selective_Transport_pi0/transport_pi0.macro new file mode 100644 index 0000000000000..2b0b26fa06ed8 --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/transport_pi0.macro @@ -0,0 +1,28 @@ +o2::data::Stack::TransportFcn +transport_pi0() +{ + + /** this function returns true/false depending on whether the + ** current particle is either a pi0 produced at mid-rapidity + ** or a daughter of a pi0 produced at mid-rapidity **/ + + o2::data::Stack::TransportFcn decision; + decision = [&decision](const TParticle& particle, const std::vector<TParticle>& particles) -> bool { +// std::cout << particles.size() << std::endl; +//particle.Print(); +//return false; + if (particle.GetPdgCode() == 111) // if particle is a pi0 + return std::fabs(particle.Eta()) < 1.0; // decision is based on particle rapidity + auto motherL = particle.GetFirstMother(); // if not a pi0, we look at the mother + if (motherL == -1) return false; // if particle has no mother, decision is false + if (motherL >= particles.size()) { + std::cout << "this makes no sense: " << motherL << " " << particles.size() << std::endl; + return false; +} +auto mother = particles[motherL]; // if particle has mother + return decision(mother, particles); // decision is based on the mother + }; + + return decision; + +} diff --git a/run/SimExamples/Selective_Transport_pi0/trigger_pi0.macro b/run/SimExamples/Selective_Transport_pi0/trigger_pi0.macro new file mode 100644 index 0000000000000..514ce3a15ed4f --- /dev/null +++ b/run/SimExamples/Selective_Transport_pi0/trigger_pi0.macro @@ -0,0 +1,44 @@ +#include "Generators/Trigger.h" +#include "TParticle.h" + +int counterAll = 0; +int counterSel = 0; + +bool has_gamma_converted(const TParticle& gamma, const std::vector<TParticle>& particles) +{ + if (gamma.GetPdgCode() != 22) return false; // not a photon + if (gamma.GetNDaughters() != 2) return false; // did not produce 2 particles + auto& d1 = particles[gamma.GetFirstDaughter()]; + auto& d2 = particles[gamma.GetLastDaughter()]; + if (abs(d1.GetPdgCode()) != 11 || abs(d2.GetPdgCode()) != 11) return false; // not e+e- pair; + if (d1.R() > 100. || d2.R() > 100.) return false; // both at R < 100 cm + return true; +}; + +bool has_pi0_converted(const TParticle& pi0, const std::vector<TParticle>& particles) +{ + if (pi0.GetPdgCode() != 111) return false; + if (std::fabs(pi0.Eta()) > 1.0) return false; + if (pi0.GetNDaughters() != 2) return false; + auto& d1 = particles[pi0.GetFirstDaughter()]; + auto& d2 = particles[pi0.GetLastDaughter()]; + return ( has_gamma_converted(d1, particles) && has_gamma_converted(d2, particles) ); +}; + +o2::eventgen::Trigger + trigger_pi0() +{ + auto trigger = [](const std::vector<TParticle>& particles) -> bool { + counterAll++; + for (const auto& particle : particles) + if (has_pi0_converted(particle, particles)) { + counterSel++; + std::cout << " --- event selected: " << counterSel << " / " << counterAll << std::endl; + return true; + } + std::cout << " --- event rejected: " << counterSel << " / " << counterAll << std::endl; + return false; + }; + + return trigger; +} diff --git a/run/SimExamples/Signal_ImpactB/signal_impactb.macro b/run/SimExamples/Signal_ImpactB/signal_impactb.macro index 5a25c318b3e55..902ca7b84bf1d 100644 --- a/run/SimExamples/Signal_ImpactB/signal_impactb.macro +++ b/run/SimExamples/Signal_ImpactB/signal_impactb.macro @@ -28,7 +28,7 @@ public: // update the number of particles to be generated // according to impact parameter and formula - void notifyEmbedding(const FairMCEventHeader *bkgHeader) override { + void notifyEmbedding(const o2::dataformats::MCEventHeader *bkgHeader) override { auto b = bkgHeader->GetB(); mNSignals = mFormula.Eval(b); std::cout << " --- notify embedding: b = " << b << ", nparticles = " << mNSignals << std::endl; diff --git a/run/SimExamples/SimAsService_basic/run.sh b/run/SimExamples/SimAsService_basic/run.sh new file mode 100755 index 0000000000000..2be8e646708e3 --- /dev/null +++ b/run/SimExamples/SimAsService_basic/run.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# +# This is a basic simulation example showing how to run the simulation as a service, +# and how to interact with the service via the client control script. +# +# Steps demonstrated: +# a) startup a simulation in service mode +# b) ask a 1st batch of events +# c) ask a 2nd batch of events with a different output name + + +set -x + +MODULES="PIPE ITS TPC TOF TRD" +NWORKERS=6 + +# helper to make a random file name +rname1=$(hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom | head -c 6) + +### step 1: Startup the service with some configuration of workers, engines, +#### physics/geometry settings. No events are asked at this time. + +( o2-sim-client.py --startup "-j ${NWORKERS} -n 0 -g pythia8pp -m ${MODULES} -o simservice --logseverity DEBUG" \ + --block ) | tee /tmp/${rname1} # <--- return when everything is fully initialized +SERVICE1_PID=$(grep "detached as pid" /tmp/${rname1} | awk '//{print $4}') + +sleep 2 +### step 2: Transport a bunch of pythia8 events; Reconfiguration of engine not possible at this time. +### Reconfiguration of generator ok (but limited). +o2-sim-client.py --pid ${SERVICE1_PID} --command "-n 10 -g pythia8pp -o batch1_pythia8" --block + +sleep 2 + +### step 3: Transport a bunch of pythia8hi events and wait until finished +o2-sim-client.py --pid ${SERVICE1_PID} --command "-n 2 -g pythia8hi -o batch2_pythia8hi" --block + + +### step 4: ask the service to shutdown (note the additional 1 which is unfortunately needed) +o2-sim-client.py --pid ${SERVICE1_PID} --command "--stop 1" + diff --git a/run/SimExamples/SimAsService_biasing1/broker.macro b/run/SimExamples/SimAsService_biasing1/broker.macro new file mode 100644 index 0000000000000..6dff936bb2126 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/broker.macro @@ -0,0 +1,71 @@ +#include "duplicateHits.macro" + +void filterSim(std::string const& oldprefix, std::string const& newprefix, std::vector<int> const* mask) { + duplicateHits(oldprefix.c_str(), newprefix.c_str(), "UPDATE", 1, mask); +} + +void broker(std::string commandline, std::string oldprefix, std::string newprefix) { + // inspect simulated events and apply a trigger on them + // copy event if trigger passes + + std::cout << commandline; + auto tokens = o2::utils::Str::tokenize(commandline,' ',true); + std::cout << "token size " << tokens.size(); + int argc = tokens.size() + 1; + char **argv = nullptr; + argv = new char*[argc]; + argv[0] = "broker"; + for (int i = 1; i < argc; ++i) { + argv[i] = (char*)tokens[i-1].c_str(); + } + + o2::dataformats::MCEventHeader eventHeader; + + auto eventgen = new o2::eventgen::PrimaryGenerator; + auto& conf = o2::conf::SimConfig::Instance(); + bool ok = conf.resetFromArguments(argc, argv); + if (ok) { + // setup parameters + // update the parameters from an INI/JSON file, if given (overrides code-based version) + o2::conf::ConfigurableParam::updateFromFile(conf.getConfigFile()); + // update the parameters from stuff given at command line (overrides file-based version) + o2::conf::ConfigurableParam::updateFromString(conf.getKeyValueString()); + + o2::eventgen::GeneratorFactory::setPrimaryGenerator(conf, eventgen); + eventgen->SetEvent(&eventHeader); + eventgen->Init(); + + std::vector<int> triggermask(100, 0); + int filtercount = 0; + + // register a trigger hook --> basically here to get the correct event indices + auto generators = eventgen->GetListOfGenerators(); + for (int igen = 0; igen < generators->GetEntries(); ++igen) { + auto generator = dynamic_cast<o2::eventgen::Generator*>(generators->At(igen)); + if (generator) { + generator->setTriggerOkHook([&filtercount,&triggermask](std::vector<TParticle> const& p, int index){ + if (index > triggermask.size()) { + triggermask.resize(2*index, 0); + } + triggermask[index-1] = 1; // index starts at 1? + filtercount++; + }); + } + } + auto stack = new o2::data::Stack(); + stack->setExternalMode(true); + + // go through all available events --> fills the triggermask + while (eventgen->GenerateEvent(stack)) { + } + + + // now filter the sim-data + if (filtercount) { + filterSim(oldprefix, newprefix, &triggermask); + } + + // report back result to outside world + std::cout << "TRIGGER-COUNT " << filtercount << "\n"; + } +} diff --git a/run/SimExamples/SimAsService_biasing1/duplicateHits.macro b/run/SimExamples/SimAsService_biasing1/duplicateHits.macro new file mode 100644 index 0000000000000..61d0251abca62 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/duplicateHits.macro @@ -0,0 +1,237 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "TFile.h" +#include "TTree.h" +#include "TString.h" +#include "ITSMFTSimulation/Hit.h" +#include "TOFSimulation/Detector.h" +#include "EMCALBase/Hit.h" +#include "TRDSimulation/Detector.h" // For TRD Hit +#include "FT0Simulation/Detector.h" // for Fit Hit +#include "DataFormatsFV0/Hit.h" +#include "HMPIDBase/Hit.h" +#include "TPCSimulation/Point.h" +#include "PHOSBase/Hit.h" +#include "DataFormatsFDD/Hit.h" +#include "MCHSimulation/Hit.h" +#include "MIDSimulation/Hit.h" +#include "CPVBase/Hit.h" +#include "DataFormatsZDC/Hit.h" +#include "SimulationDataFormat/MCEventHeader.h" + +#ifdef ENABLE_UPGRADES +#include "EndCapsSimulation/Hit.h" +#endif + +#endif + +template <typename T> +void duplicate(TTree* tr, const char* brname, TTree* outtree, int factor, std::vector<int> const* mask) +{ + auto br = tr->GetBranch(brname); + if (!br) { + return; + } + auto entries = br->GetEntries(); + T* entrydata = nullptr; + br->SetAddress(&entrydata); + + int entrycount = 0; + auto outbranch = outtree->GetBranch(brname); + if (outbranch) { + outbranch->SetAddress(&entrydata); + entrycount = outbranch->GetEntries(); + } + if (!outbranch) { + outbranch = outtree->Branch(brname, &entrydata); + } + if (!outbranch) { + std::cerr << "branch " << brname << " not created\n"; + } + + for (int i = 0; i < entries; ++i) { + bool selected = true; + if (mask) { + selected = (*mask)[i] != 0; + } + if (selected) { + br->GetEntry(i); + for (int j = 0; j < factor; ++j) { + entrycount++; + outbranch->Fill(); + } + } + } + outtree->SetEntries(entrycount); +} + +// we need to do something special for MCEventHeaders +template <> +void duplicate<o2::dataformats::MCEventHeader>(TTree* tr, const char* brname, TTree* outtree, int factor, std::vector<int> const* mask) +{ + auto br = tr->GetBranch(brname); + if (!br) { + return; + } + auto entries = br->GetEntries(); + o2::dataformats::MCEventHeader* entrydata = nullptr; + br->SetAddress(&entrydata); + + int eventID = 1; + auto outbranch = outtree->GetBranch(brname); + if (outbranch) { + outbranch->SetAddress(&entrydata); + eventID += outbranch->GetEntries(); + } + if (!outbranch) { + outbranch = outtree->Branch(brname, &entrydata); + } + if (!outbranch) { + std::cerr << "branch " << brname << " not created\n"; + } + + for (int i = 0; i < entries; ++i) { + bool selected = true; + if (mask) { + selected = (*mask)[i] != 0; + } + if (selected) { + br->GetEntry(i); + for (int j = 0; j < factor; ++j) { + entrydata->SetEventID(eventID++); + outbranch->Fill(); + } + } + } + outtree->SetEntries(eventID - 1); +} + +TTree* getHitTree(o2::parameters::GRPObject const* grp, const char* filebase, o2::detectors::DetID detid, const char* mode = "OPEN") +{ + if (!grp) { + std::cerr << "GRP is null\n"; + return nullptr; + } + if (!grp->isDetReadOut(detid)) { + return nullptr; + } + std::string filename(o2::base::NameConf::getHitsFileName(detid, filebase).c_str()); + + // shamefully leaking memory as the TTree cannot live without the file... + TFile* file = new TFile(filename.c_str(), mode); + TTree* t = nullptr; + t = (TTree*)file->Get("o2sim"); + if (t==nullptr || std::strcmp(mode,"RECREATE") == 0) { + t = new TTree("o2sim", "o2sim"); + } + return t; +} + +template <typename T> +struct HitContainer { + using type = std::vector<T>; +}; +template <> +struct HitContainer<o2::tpc::HitGroup> { + using type = o2::tpc::HitGroup; +}; + +template <typename T> +void duplicateV(o2::parameters::GRPObject const* grp, + const char* filebase, + o2::detectors::DetID detid, + const char* newfilebase, + const char* mode /*mode for output file*/, + int factor, + std::vector<int> const* mask /*triggermask*/) +{ + // open old file and extract tree + auto tr = getHitTree(grp, filebase, detid); + if (!tr) { + return; + } + auto outtree = getHitTree(grp, newfilebase, detid, mode); + if (!outtree) { + return; + } + + // duplicate entries in all branches and copy + auto branches = o2::detectors::SimTraits::DETECTORBRANCHNAMES[(int)detid]; + for (auto& br : branches) { + duplicate<std::vector<T>>(tr, br.c_str(), outtree, factor, mask); + } + // write outtree + outtree->Write("",TObject::kWriteDelete); +} + +TTree* getKinematicsTree(const char* filebase, TFile *& fileptr, const char* mode = "OPEN") +{ + // shamefully leaking memory as the TTree cannot live without the file... + TFile* file = new TFile(o2::base::NameConf::getMCKinematicsFileName(filebase).c_str(), mode); + fileptr = file; + TTree* t = nullptr; + t = (TTree*)file->Get("o2sim"); + std::cout << "MODE " << mode << "Got tree " << t << "\n"; + if ( t==nullptr || std::strcmp(mode,"RECREATE")==0 ) { + t = new TTree("o2sim", "o2sim"); + } + return t; +} + +// Macro to duplicate hit output of a simulation +// This might be useful to enlarge input for digitization or to engineer +// sequences of identical hit structures in order test pileup. +// Mask can be used to filter out specific entries. +void duplicateHits(const char* filebase = "o2sim", const char* newfilebase = "o2sim_duplicated", const char* mode="RECREATE", int factor = 2, std::vector<int> const *mask = nullptr) +{ + // NOTE: There might be a way in which this can be achieved + // without explicit iteration over branches and type ... just by using TClasses + + // READ GRP AND ITERATE OVER DETECTED PARTS + auto oldgrpfilename = o2::base::NameConf::getGRPFileName(filebase); + std::cout << "OLD GRP NAME " << oldgrpfilename << "\n"; + auto grp = o2::parameters::GRPObject::loadFrom(oldgrpfilename.c_str()); + if (!grp) { + std::cerr << "No GRP found; exiting\n"; + return; + } + // cp GRP for new sim files + auto newgrpfilename = o2::base::NameConf::getGRPFileName(newfilebase); + std::stringstream command; + command << "cp " << oldgrpfilename << " " << newgrpfilename; + system(command.str().c_str()); + + // duplicate kinematics stuff + TFile* outfileptr = nullptr; + auto kintree = getKinematicsTree(filebase, outfileptr, "OPEN"); + auto newkintree = getKinematicsTree(newfilebase, outfileptr, mode); + // duplicate meta branches + duplicate<std::vector<o2::MCTrack>>(kintree, "MCTrack", newkintree, factor, mask); + duplicate<o2::dataformats::MCEventHeader>(kintree, "MCEventHeader.", newkintree, factor, mask); + // TODO: fix EventIDs in the newly created MCEventHeaders + duplicate<std::vector<o2::TrackReference>>(kintree, "TrackRefs", newkintree, factor, mask); + newkintree->Write("", TObject::kWriteDelete); + outfileptr->Close(); + + // duplicating hits + using namespace o2::detectors; + duplicateV<o2::itsmft::Hit>(grp, filebase, DetID::ITS, newfilebase, mode, factor, mask); + duplicateV<o2::itsmft::Hit>(grp, filebase, DetID::MFT, newfilebase, mode, factor, mask); + duplicateV<o2::tof::HitType>(grp, filebase, DetID::TOF, newfilebase, mode, factor, mask); + duplicateV<o2::emcal::Hit>(grp, filebase, DetID::EMC, newfilebase, mode, factor, mask); + duplicateV<o2::trd::Hit>(grp, filebase, DetID::TRD, newfilebase, mode, factor, mask); + duplicateV<o2::phos::Hit>(grp, filebase, DetID::PHS, newfilebase, mode, factor, mask); + duplicateV<o2::cpv::Hit>(grp, filebase, DetID::CPV, newfilebase, mode, factor, mask); + duplicateV<o2::zdc::Hit>(grp, filebase, DetID::ZDC, newfilebase, mode, factor, mask); + duplicateV<o2::ft0::HitType>(grp, filebase, DetID::FT0, newfilebase, mode, factor, mask); + duplicateV<o2::fv0::Hit>(grp, filebase, DetID::FV0, newfilebase, mode, factor, mask); + duplicateV<o2::fdd::Hit>(grp, filebase, DetID::FDD, newfilebase, mode, factor, mask); + duplicateV<o2::hmpid::HitType>(grp, filebase, DetID::HMP, newfilebase, mode, factor, mask); + duplicateV<o2::mid::Hit>(grp, filebase, DetID::MID, newfilebase, mode, factor, mask); + duplicateV<o2::mch::Hit>(grp, filebase, DetID::MCH, newfilebase, mode, factor, mask); + duplicateV<o2::tpc::HitGroup>(grp, filebase, DetID::TPC, newfilebase, mode, factor, mask); + +#ifdef ENABLE_UPGRADES + duplicateV<o2::itsmft::Hit>(grp, filebase, DetID::FT3, newfilebase, mode, factor, mask); +#endif + +} diff --git a/run/SimExamples/SimAsService_biasing1/run.sh b/run/SimExamples/SimAsService_biasing1/run.sh new file mode 100755 index 0000000000000..dc1e4bcba6e06 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/run.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# +# This is a simulation example showing how to run the simulation as a service, +# and how to interact with the service via the client control script. Here, the +# service is used to achieve event biasing via a feedback control loop, in which an +# outside "broker" is triggering on the simulated events and launching more simulations +# until a goal is achieved. +# +# Steps demonstrated: +# a) startup multiple simulations in service mode +# b) ask a batch of events from the crude service +# necessary to obtain the bias feature ... until until a certain number of triggered events +# is reached +# c) continue simulation of the good events for the rest of primaries +# +# NOTE: +# - the example is primarily meant to demonstrate the use of the sim-service in a more complex setting +# - one can do biasing in this way, but alternative implementations (directly inside o2-sim) may +# be ultimately better/faster (the present example can then be seen as first baseline solution) +# - This script is glueing together executables / ROOT macros / etc. --> A better/future way might be to +# use PyROOT so that one can directly access results better and reuse compiled macros. + + +MODULES="PIPE ITS TPC TOF" +NWORKERS=8 +NTRIALEVENTS=20 # number of trial events in each batch +NTRIGGEREDEVENTS=20 # number of targeted triggered events + +# helper to make a random file name +rname1=$(hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom | head -c 6) + +set -x +### step 1: Startup the 1st service with a partial detector config + +( o2-sim-client.py --startup "-j ${NWORKERS} -n 0 -g pythia8 -m ${MODULES} -o simservice --configFile sim_step1.ini" \ + --block ) | tee /tmp/${rname1} # <--- return when everything is fully initialized +SERVICE1_PID=$(grep "detached as pid" /tmp/${rname1} | awk '//{print $4}') + +# a second service is used for the continue features (currently reconfiguration of engines/stacks is limited, otherwise +# the first service could be used as well) +( o2-sim-client.py --startup "-j ${NWORKERS} -n 0 -m ${MODULES} -o simservice2 --configKeyValues GeneratorFromO2Kine.continueMode=true" \ + --block ) | tee /tmp/${rname1} # <--- return when everything is fully initialized +SERVICE2_PID=$(grep "detached as pid" /tmp/${rname1} | awk '//{print $4}') + +# sleep 20 + +# BIASING LOOP +biasedcount=0 +batch=0 +trialevents=0 +while (( biasedcount < ${NTRIGGEREDEVENTS} )); do + ### simulate some events with service 1 + o2-sim-client.py --pid ${SERVICE1_PID} --command "-g pythia8 -n ${NTRIALEVENTS} --configFile sim_step1.ini -o batch${batch}" --block + + ### filter out good events + ln -nsf simservice_grp.root batch${batch}_grp.root + command="broker.macro("'"-g extkinO2 --extKinFile batch'${batch}'_Kine.root --trigger external --configFile sim_step2.ini","batch'${batch}'", "filtered"'")" + ( root -b -l -q "${command}" ) &> /tmp/${rname1}_${batch} + + triggercount=$(grep "TRIGGER-COUNT" /tmp/${rname1}_${batch} | awk '//{print $2}') + + let biasedcount=biasedcount+triggercount + let batch=batch+1 + let trialevents=trialevents+NTRIALEVENTS +done +echo "========================================" +echo "Transported ${trialevents} trial events." +echo "Triggered on ${biasedcount} events. " +echo "****************************************" + + +# SIMULATE REMAINING PRIMARIES FOR GOOD TRIGGERED EVENTS +o2-sim-client.py --pid ${SERVICE2_PID} --command "-g extkinO2 --extKinFile filtered_Kine.root -n ${NTRIGGEREDEVENTS} -o filtered_part2 \ + --configKeyValues GeneratorFromO2Kine.continueMode=true" --block + +# bring down the service +o2-sim-client.py --pid ${SERVICE1_PID} --command "--stop 1" +o2-sim-client.py --pid ${SERVICE2_PID} --command "--stop 1" + +sleep 1 + +# just some tmp safety-net to make sure all processes are really gone +. ${O2_ROOT}/share/scripts/jobutils.sh +for p in $(childprocs ${SERVICE1_PID}); do + kill -9 ${p} +done +. ${O2_ROOT}/share/scripts/jobutils.sh +for p in $(childprocs ${SERVICE2_PID}); do + kill -9 ${p} +done diff --git a/run/SimExamples/SimAsService_biasing1/sim_step1.ini b/run/SimExamples/SimAsService_biasing1/sim_step1.ini new file mode 100644 index 0000000000000..c10e1afe29368 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/sim_step1.ini @@ -0,0 +1,5 @@ +[Stack] +transportPrimary=external +transportPrimaryFileName=transport_pi0.macro +transportPrimaryFuncName=transport_pi0() +transportPrimaryInvert=false diff --git a/run/SimExamples/SimAsService_biasing1/sim_step2.ini b/run/SimExamples/SimAsService_biasing1/sim_step2.ini new file mode 100644 index 0000000000000..216fc4f07d809 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/sim_step2.ini @@ -0,0 +1,6 @@ +[TriggerExternal] +fileName=trigger_pi0.macro +funcName=trigger_pi0() + +[GeneratorFromO2Kine] +continueMode=true diff --git a/run/SimExamples/SimAsService_biasing1/transport_pi0.macro b/run/SimExamples/SimAsService_biasing1/transport_pi0.macro new file mode 100644 index 0000000000000..2b0b26fa06ed8 --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/transport_pi0.macro @@ -0,0 +1,28 @@ +o2::data::Stack::TransportFcn +transport_pi0() +{ + + /** this function returns true/false depending on whether the + ** current particle is either a pi0 produced at mid-rapidity + ** or a daughter of a pi0 produced at mid-rapidity **/ + + o2::data::Stack::TransportFcn decision; + decision = [&decision](const TParticle& particle, const std::vector<TParticle>& particles) -> bool { +// std::cout << particles.size() << std::endl; +//particle.Print(); +//return false; + if (particle.GetPdgCode() == 111) // if particle is a pi0 + return std::fabs(particle.Eta()) < 1.0; // decision is based on particle rapidity + auto motherL = particle.GetFirstMother(); // if not a pi0, we look at the mother + if (motherL == -1) return false; // if particle has no mother, decision is false + if (motherL >= particles.size()) { + std::cout << "this makes no sense: " << motherL << " " << particles.size() << std::endl; + return false; +} +auto mother = particles[motherL]; // if particle has mother + return decision(mother, particles); // decision is based on the mother + }; + + return decision; + +} diff --git a/run/SimExamples/SimAsService_biasing1/trigger_pi0.macro b/run/SimExamples/SimAsService_biasing1/trigger_pi0.macro new file mode 100644 index 0000000000000..514ce3a15ed4f --- /dev/null +++ b/run/SimExamples/SimAsService_biasing1/trigger_pi0.macro @@ -0,0 +1,44 @@ +#include "Generators/Trigger.h" +#include "TParticle.h" + +int counterAll = 0; +int counterSel = 0; + +bool has_gamma_converted(const TParticle& gamma, const std::vector<TParticle>& particles) +{ + if (gamma.GetPdgCode() != 22) return false; // not a photon + if (gamma.GetNDaughters() != 2) return false; // did not produce 2 particles + auto& d1 = particles[gamma.GetFirstDaughter()]; + auto& d2 = particles[gamma.GetLastDaughter()]; + if (abs(d1.GetPdgCode()) != 11 || abs(d2.GetPdgCode()) != 11) return false; // not e+e- pair; + if (d1.R() > 100. || d2.R() > 100.) return false; // both at R < 100 cm + return true; +}; + +bool has_pi0_converted(const TParticle& pi0, const std::vector<TParticle>& particles) +{ + if (pi0.GetPdgCode() != 111) return false; + if (std::fabs(pi0.Eta()) > 1.0) return false; + if (pi0.GetNDaughters() != 2) return false; + auto& d1 = particles[pi0.GetFirstDaughter()]; + auto& d2 = particles[pi0.GetLastDaughter()]; + return ( has_gamma_converted(d1, particles) && has_gamma_converted(d2, particles) ); +}; + +o2::eventgen::Trigger + trigger_pi0() +{ + auto trigger = [](const std::vector<TParticle>& particles) -> bool { + counterAll++; + for (const auto& particle : particles) + if (has_pi0_converted(particle, particles)) { + counterSel++; + std::cout << " --- event selected: " << counterSel << " / " << counterAll << std::endl; + return true; + } + std::cout << " --- event rejected: " << counterSel << " / " << counterAll << std::endl; + return false; + }; + + return trigger; +} diff --git a/run/SimExamples/StepMonitoring/Simple1/run.sh b/run/SimExamples/StepMonitoring/Simple1/run.sh index dace460b2270d..2d4d089351123 100755 --- a/run/SimExamples/StepMonitoring/Simple1/run.sh +++ b/run/SimExamples/StepMonitoring/Simple1/run.sh @@ -4,4 +4,4 @@ # alienv enter O2/latest MCStepLogger/latest # This demonstrates the most basic usage of the steplogger -LD_PRELOAD=$MCSTEPLOGGER_ROOT/lib/libMCStepLoggerIntercept.so o2-sim-serial -n 1 -g pythia8 -m PIPE ITS TPC +LD_PRELOAD=$MCSTEPLOGGER_ROOT/lib/libMCStepLoggerIntercept.so o2-sim-serial -n 1 -g pythia8pp -m PIPE ITS TPC diff --git a/run/SimPublishChannelHelper.h b/run/SimPublishChannelHelper.h new file mode 100644 index 0000000000000..7c624058e49f2 --- /dev/null +++ b/run/SimPublishChannelHelper.h @@ -0,0 +1,77 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SIMPUBLISHCHANNELHELPER_H +#define O2_SIMPUBLISHCHANNELHELPER_H + +#include <string> +#include <FairMQChannel.h> + +namespace o2::simpubsub +{ + +// create an IPC socket name of the type +// ipc:///tmp/base-PID +// base should be for example "o2sim-worker" or "o2sim-merger" +std::string getPublishAddress(std::string const& base, int pid = getpid()) +{ + std::stringstream publishsocketname; + publishsocketname << "ipc:///tmp/" << base << "-" << pid; + return publishsocketname.str(); +} + +// some standard format for pub-sub subscribers +std::string simStatusString(std::string const& origin, std::string const& topic, std::string const& message) +{ + return origin + std::string("[") + topic + std::string("] : ") + message; +} + +// helper function to publish a message to an outside subscriber +bool publishMessage(FairMQChannel& channel, std::string const& message) +{ + if (channel.IsValid()) { + auto text = new std::string(message); + std::unique_ptr<FairMQMessage> payload(channel.NewMessage( + const_cast<char*>(text->c_str()), + text->length(), [](void* data, void* hint) { delete static_cast<std::string*>(hint); }, text)); + if (channel.Send(payload) > 0) { + return true; + } + } else { + LOG(ERROR) << "CHANNEL NOT VALID"; + } + return false; +} + +// make channel (transport factory needs to be injected) +FairMQChannel createPUBChannel(std::string const& address, + std::string const& type = "pub") +{ + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + static int i = 0; + std::stringstream str; + str << "channel" << i++; + auto externalpublishchannel = FairMQChannel{str.str(), type, factory}; + externalpublishchannel.Init(); + if ((type.compare("pub") == 0) || (type.compare("pull") == 0)) { + externalpublishchannel.Bind(address); + LOG(INFO) << "BINDING TO ADDRESS " << address << " type " << type; + } else { + externalpublishchannel.Connect(address); + LOG(INFO) << "CONNECTING TO ADDRESS " << address << " type " << type; + } + externalpublishchannel.Validate(); + return externalpublishchannel; +} + +} // namespace o2::simpubsub + +#endif //O2_SIMPUBLISHCHANNELHELPER_H diff --git a/run/checkStack.cxx b/run/checkStack.cxx index 42c3dd0c53900..4778dea4bdb38 100644 --- a/run/checkStack.cxx +++ b/run/checkStack.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -15,6 +16,7 @@ #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/Stack.h" #include "SimulationDataFormat/TrackReference.h" +#include "Steer/MCKinematicsReader.h" #include "TFile.h" #include "TTree.h" #ifdef NDEBUG @@ -23,6 +25,8 @@ #include <cassert> #include "FairLogger.h" #include "DetectorsCommonDataFormats/NameConf.h" +#include "ITSMFTSimulation/Hit.h" +#include <unordered_map> int main(int argc, char** argv) { @@ -46,46 +50,77 @@ int main(int argc, char** argv) assert(refbr); refbr->SetAddress(&trackrefs); - o2::dataformats::MCTruthContainer<o2::TrackReference>* indexedtrackrefs = nullptr; - auto irefbr = tr->GetBranch("IndexedTrackRefs"); - irefbr->SetAddress(&indexedtrackrefs); + o2::steer::MCKinematicsReader mcreader(nameprefix, o2::steer::MCKinematicsReader::Mode::kMCKine); + + // when present we also read some hits for ITS to test consistency of trackID assignments + TFile hitf(o2::base::NameConf::getHitsFileName(o2::detectors::DetID::ITS, nameprefix).c_str()); + auto hittr = (TTree*)hitf.Get("o2sim"); + auto hitbr = hittr ? hittr->GetBranch("ITSHit") : nullptr; + std::vector<o2::itsmft::Hit>* hits = nullptr; + if (hitbr) { + hitbr->SetAddress(&hits); + } + + for (int eventID = 0; eventID < mcbr->GetEntries(); ++eventID) { + mcbr->GetEntry(eventID); + refbr->GetEntry(eventID); + LOG(DEBUG) << "-- Entry --" << eventID; + LOG(DEBUG) << "Have " << mctracks->size() << " tracks"; + + std::unordered_map<int, bool> trackidsinITS_fromhits; + if (hitbr) { + hitbr->GetEntry(eventID); + LOG(DEBUG) << "Have " << hits->size() << " hits"; + + // check that trackIDs from the hits are within range + int maxid = 0; + for (auto& h : *hits) { + maxid = std::max(maxid, h.GetTrackID()); + trackidsinITS_fromhits[h.GetTrackID()] = true; + assert(maxid < mctracks->size()); + } + } - for (int i = 0; i < mcbr->GetEntries(); ++i) { - mcbr->GetEntry(i); - refbr->GetEntry(i); - irefbr->GetEntry(i); - LOG(DEBUG) << "-- Entry --" << i << "\n"; - LOG(DEBUG) << "Have " << mctracks->size() << " tracks \n"; int ti = 0; // record tracks that left a hit in TPC // (we know that these tracks should then have a TrackRef) std::vector<int> trackidsinTPC; + std::vector<int> trackidsinITS; for (auto& t : *mctracks) { // check that mother indices are reasonable - assert(ti > t.getMotherTrackId()); + // TODO: this seems currently broken with pythia8pp + // assert(ti > t.getMotherTrackId()); if (t.leftTrace(o2::detectors::DetID::TPC)) { trackidsinTPC.emplace_back(ti); } - LOG(DEBUG) << " track " << ti << "\t" << t.getMotherTrackId() << " hits " << t.hasHits() << "\n"; + if (t.leftTrace(o2::detectors::DetID::ITS)) { + trackidsinITS.emplace_back(ti); + } + LOG(DEBUG) << " track " << ti << "\t" << t.getMotherTrackId() << " hits " << t.hasHits(); ti++; } - LOG(DEBUG) << "Have " << trackidsinTPC.size() << " tracks with hits in TPC\n"; - LOG(DEBUG) << "Have " << trackrefs->size() << " track refs \n"; - LOG(DEBUG) << "Have " << indexedtrackrefs->getIndexedSize() << " mapped tracks\n"; - LOG(DEBUG) << "Have " << indexedtrackrefs->getNElements() << " track refs\n"; + if (hitbr) { + assert(trackidsinITS.size() == trackidsinITS_fromhits.size()); + for (auto id : trackidsinITS) { + assert(trackidsinITS_fromhits[id] == true); + } + } + + LOG(DEBUG) << "Have " << trackidsinTPC.size() << " tracks with hits in TPC"; + LOG(DEBUG) << "Have " << trackrefs->size() << " track refs"; + // check correct working of MCKinematicsReader bool havereferences = trackrefs->size(); if (havereferences) { - for (auto& i : trackidsinTPC) { - auto labels = indexedtrackrefs->getLabels(i); - assert(labels.size() > 0); - LOG(DEBUG) << " Track " << i << " has " << labels.size() << " TrackRefs " - << "\n"; - for (int j = 0; j < labels.size(); ++j) { - LOG(DEBUG) << labels[j]; + for (auto& trackID : trackidsinTPC) { + auto trackrefs = mcreader.getTrackRefs(eventID, trackID); + assert(trackrefs.size() > 0); + LOG(DEBUG) << " Track " << trackID << " has " << trackrefs.size() << " TrackRefs"; + for (auto& ref : trackrefs) { + assert(ref.getTrackID() == trackID); } } } diff --git a/run/o2-sim-client.py b/run/o2-sim-client.py new file mode 100755 index 0000000000000..89b28219bea20 --- /dev/null +++ b/run/o2-sim-client.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +''' +Copyright 2019-2020 CERN and copyright holders of ALICE O2. +See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +All rights not expressly granted are reserved. + +This software is distributed under the terms of the GNU General Public +License v3 (GPL Version 3), copied verbatim in the file "COPYING". + +In applying this license CERN does not waive the privileges and immunities +granted to it by virtue of its status as an Intergovernmental Organization +or submit itself to any jurisdiction. +''' + +# @author Sandro Wenzel + +# +# A python client that can talk to a daemonized o2-sim simulation instance. +# Use to start new simulation runs or to control (stop) the service. +# + +import time +import zmq +import psutil +import argparse +import os +import re + +parser = argparse.ArgumentParser(description='Control client talking to o2-sim service.') +parser.add_argument('--startup', help='Startup simulation service') +parser.add_argument('--command', help='Command to be submitted to a running service (see SimReconfig class).') +parser.add_argument('--block', action='store_true', help='Blocks until (simulation/action) done.') +parser.add_argument('--pid', help='pid of simulation service (autodetermined if not given).') +parser.add_argument('--service-outfile', default='o2sim-service.log', help='Logfile for the backgrounded sim-service ' + '(if started with --startup)') +args = parser.parse_args() + +service_pid = None + +if args.pid: + service_pid = args.pid + +if args.startup: + commandtokens=args.startup.split() + commandtokens+="--asservice 1".split() + with open("simservice.out","wb") as out, open("simservice.err","wb") as err: + pid = psutil.Popen(['o2-sim'] + commandtokens, close_fds=True, stderr=err, stdout=out) + service_pid = pid.pid + print ("detached as pid", pid.pid) + +process_name="o2-sim" +def getpids(name): + pids=[] + for proc in psutil.process_iter(): + if process_name == proc.name(): + pids.append(proc.pid) + return pids + +if service_pid == None: + pids = getpids(process_name) + if len(pids)!=1: + print ("Cannot determine correct PID --> need to pass it") + exit (1) + else: + service_pid = pids[0] + + +controladdress="ipc:///tmp/o2sim-control-" + str(service_pid) +message = args.command +context = zmq.Context() +socket = context.socket(zmq.REQ) +socket.connect(controladdress) + +def getSubscriptionAddresses(basepid): + # returns all IPC channels to subscribe to; basepid is the process pid of the driver o2sim process + base = [ "o2sim-notifications", "o2sim-merger-notifications", "o2sim-primary-notifications", "o2sim-worker-notifications" ] + return [ "ipc:///tmp/" + str(x) + '-' + str(basepid) for x in base ] + +# subscribe to PUB notifications from the simulation system +incomingsocket = context.socket(zmq.SUB) +for addr in getSubscriptionAddresses(service_pid): + incomingsocket.connect(addr) +incomingsocket.subscribe("") # <---- very important !! + +if args.command: + time.sleep(0.1) #! -> necessary delay before sending?? + a = socket.send_string(message) # --> sending + answer = socket.recv() # <--- receive answer + code = int.from_bytes(answer, "little") + + if code == 0: + print ("Submission successful.") + if args.block: + # blocking means we wait until the operation (simulation) is done serverside + print ("Waiting for DONE message from server") + batchdone = False + while not batchdone: + notification = incomingsocket.recv_string() # + print (notification) + if re.match('O2SIM.*DONE', notification) != None: + print ("Received DONE notification from server ... quitting", notification) + batchdone = True + + exit (0) + + elif code == 1: + print ("Server busy; Cannot take commands.") + elif code == 2: + print ("Command string faulty (Parsing failed on serverside).") + exit (code) + else: + print ("Unknown return code.") + exit (1) + +# in case of startup we might also want to block until system is ready +if args.startup and args.block: + # blocking means we wait until the operation (simulation) or the setup is done in all parts + serverok = False + workerok = False + mergerok = False + while not (serverok and workerok and mergerok): + notification = incomingsocket.recv_string() + print ("Received notification ", notification) + if re.match('WORKER.*AWAITING\sINPUT', notification) != None: + workerok = True + if re.match('MERGER.*AWAITING\sINPUT', notification) != None: + mergerok = True + if re.match('PRIMSERVER.*AWAITING\sINPUT', notification) != None: + serverok = True + + exit (0) + +exit (0) diff --git a/run/o2sim.cxx b/run/o2sim.cxx index 632fb0db7f3cc..174db40f876c0 100644 --- a/run/o2sim.cxx +++ b/run/o2sim.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization diff --git a/run/o2sim_parallel.cxx b/run/o2sim_parallel.cxx index 91b9a02affade..81d3196d745d8 100644 --- a/run/o2sim_parallel.cxx +++ b/run/o2sim_parallel.cxx @@ -1,8 +1,9 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // -// See http://alice-o2.web.cern.ch/license for full licensing information. +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". // // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization @@ -10,6 +11,10 @@ /// @author Sandro Wenzel +#include <FairMQTransportFactory.h> +#include <FairMQChannel.h> +#include <FairMQMessage.h> + #include <cstdlib> #include <unistd.h> #include <sstream> @@ -19,6 +24,7 @@ #include <SimConfig/SimConfig.h> #include <sys/wait.h> #include <vector> +#include <functional> #include <thread> #include <csignal> #include "TStopwatch.h" @@ -26,15 +32,16 @@ #include "CommonUtils/ShmManager.h" #include "TFile.h" #include "TTree.h" -#include "Framework/FreePortFinder.h" #include <sys/types.h> #include "DetectorsCommonDataFormats/NameConf.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "O2Version.h" +#include <cstdio> +#include <unordered_map> +#include <filesystem> -#include "rapidjson/document.h" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/filereadstream.h" -#include "rapidjson/filewritestream.h" +#include "SimPublishChannelHelper.h" +#include <CommonUtils/FileSystemUtils.h> std::string getServerLogName() { @@ -60,8 +67,22 @@ std::string getMergerLogName() return str.str(); } +void remove_tmp_files() +{ + // remove all (known) socket files in /tmp + // using the naming convention /tmp/o2sim-.*PID + std::stringstream searchstr; + searchstr << "o2sim-.*-" << getpid() << "$"; + auto filenames = o2::utils::listFiles("/tmp/", searchstr.str()); + // remove those files + for (auto& fn : filenames) { + std::filesystem::remove(std::filesystem::path(fn)); + } +} + void cleanup() { + remove_tmp_files(); o2::utils::ShmManager::Instance().release(); // special mode in which we dump the output from various @@ -100,35 +121,173 @@ int checkresult() // easy check: see if we have number of entries in output tree == number of events asked std::string filename = o2::base::NameConf::getMCKinematicsFileName(conf.getOutPrefix().c_str()); TFile f(filename.c_str(), "OPEN"); + if (f.IsZombie()) { + LOG(WARN) << "Kinematics file corrupted or does not exist"; + return 1; + } auto tr = static_cast<TTree*>(f.Get("o2sim")); if (!tr) { errors++; } else { if (!conf.isFilterOutNoHitEvents()) { - errors += tr->GetEntries() != conf.getNEvents(); + if (tr->GetEntries() != conf.getNEvents()) { + LOG(WARN) << "There are fewer events in the output than asked"; + } } } - // add more simple checks return errors; } +// ---> THE FOLLOWING CAN BE PUT INTO A "STATE" STRUCT +std::vector<int> gChildProcesses; // global vector of child pids +// record distributed events in a container +std::vector<int> gDistributedEvents; +// record finished events in a container +std::vector<int> gFinishedEvents; +int gAskedEvents; + +std::string getControlAddress() +{ + std::stringstream controlsocketname; + controlsocketname << "ipc:///tmp/o2sim-control-" << getpid(); + return controlsocketname.str(); +} +std::string getInternalControlAddress() +{ + // creates names for an internal-only socket + // hashing to distinguish from more "public" sockets + std::hash<std::string> hasher; + std::stringstream str; + str << "o2sim-internal_" << getpid(); + std::string tmp(std::to_string(hasher(str.str()))); + std::stringstream controlsocketname; + controlsocketname << "ipc:///tmp/" << tmp.substr(0, 10) << "_" << getpid(); + return controlsocketname.str(); +} + // signal handler for graceful exit void sighandler(int signal) { if (signal == SIGINT || signal == SIGTERM) { - LOG(INFO) << "signal caught ... clean up and exit"; + LOG(INFO) << "o2-sim driver: Signal caught ... clean up and exit"; + // forward signal to all children + for (auto& pid : gChildProcesses) { + killpg(pid, signal); + } cleanup(); exit(0); } } -// monitores a certain incoming pipe and displays new information -void launchThreadMonitoringEvents(int pipefd, std::string text) +bool isBusy() +{ + if (gFinishedEvents.size() != gAskedEvents) { + return true; + } + return false; +} + +// launches a thread that listens for control command from outside +// or that propagates control strings to all children +void launchControlThread() +{ + static std::vector<std::thread> threads; + auto controladdress = getControlAddress(); + auto internalcontroladdress = getInternalControlAddress(); + LOG(INFO) << "Control address is: " << controladdress; + setenv("ALICE_O2SIMCONTROL", internalcontroladdress.c_str(), 1); + + auto lambda = [controladdress, internalcontroladdress]() { + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + + auto internalchannel = FairMQChannel{"o2sim-control", "pub", factory}; + internalchannel.Bind(internalcontroladdress); + internalchannel.Validate(); + std::unique_ptr<FairMQMessage> message(internalchannel.NewMessage()); + + auto outsidechannel = FairMQChannel{"o2sim-outside-exchange", "rep", factory}; + outsidechannel.Bind(controladdress); + outsidechannel.Validate(); + std::unique_ptr<FairMQMessage> request(outsidechannel.NewMessage()); + + bool keepgoing = true; + while (keepgoing) { + outsidechannel.Init(); + outsidechannel.Bind(controladdress); + outsidechannel.Validate(); + if (outsidechannel.Receive(request) > 0) { + std::string command(reinterpret_cast<char const*>(request->GetData()), request->GetSize()); + LOG(INFO) << "Control message: " << command; + int code = -1; + if (isBusy()) { + code = 1; // code = 1 --> busy + std::unique_ptr<FairMQMessage> reply(outsidechannel.NewSimpleMessage(code)); + outsidechannel.Send(reply); + } else { + code = 0; // code = 0 --> ok + + o2::conf::SimReconfigData reconfig; + auto success = o2::conf::parseSimReconfigFromString(command, reconfig); + if (!success) { + LOG(WARN) << "CONTROL REQUEST COULD NOT BE PARSED"; + code = 2; // code = 2 --> error with request data + } + std::unique_ptr<FairMQMessage> reply(outsidechannel.NewSimpleMessage(code)); + outsidechannel.Send(reply); + + if (code == 0) { + gAskedEvents = reconfig.nEvents; + gDistributedEvents.clear(); + gFinishedEvents.clear(); + // forward request from outside to all internal processes + internalchannel.Send(request); + keepgoing = !reconfig.stop; + } + } + } + } + }; + threads.push_back(std::thread(lambda)); + threads.back().detach(); +} + +// launches a thread that listens for control command from outside +// or that propagates control strings to all children +void launchWorkerListenerThread() { static std::vector<std::thread> threads; - auto lambda = [pipefd, text]() { + auto lambda = []() { + auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + + auto listenchannel = FairMQChannel{"channel0", "sub", factory}; + listenchannel.Init(); + std::stringstream address; + address << "ipc:///tmp/o2sim-worker-notifications-" << getpid(); + listenchannel.Connect(address.str()); + listenchannel.Validate(); + std::unique_ptr<FairMQMessage> message(listenchannel.NewMessage()); + + while (true) { + if (listenchannel.Receive(message) > 0) { + std::string msg(reinterpret_cast<char const*>(message->GetData()), message->GetSize()); + LOG(INFO) << "Worker message: " << msg; + } + } + }; + threads.push_back(std::thread(lambda)); + threads.back().detach(); +} + +// monitors a certain incoming event pipes and displays new information +// gives possibility to exec a callback at these events +void launchThreadMonitoringEvents( + int pipefd, std::string text, std::vector<int>& eventcontainer, + std::function<void(std::vector<int> const&)> callback = [](std::vector<int> const&) {}) +{ + static std::vector<std::thread> threads; + auto lambda = [pipefd, text, callback, &eventcontainer]() { int eventcounter; while (1) { ssize_t count = read(pipefd, &eventcounter, sizeof(eventcounter)); @@ -143,6 +302,8 @@ void launchThreadMonitoringEvents(int pipefd, std::string text) break; } else { LOG(INFO) << text.c_str() << eventcounter; + eventcontainer.push_back(eventcounter); + callback(eventcontainer); } }; }; @@ -154,6 +315,9 @@ void launchThreadMonitoringEvents(int pipefd, std::string text) // for parallel simulation int main(int argc, char* argv[]) { + LOG(INFO) << "This is o2-sim version " << o2::fullVersion() << " (" << o2::gitRevision() << ")"; + LOG(INFO) << o2::getBuildInfo(); + signal(SIGINT, sighandler); signal(SIGTERM, sighandler); // we enable the forked version of the code by default @@ -170,89 +334,30 @@ int main(int argc, char* argv[]) // copy topology file to working dir and update ports std::stringstream configss; - configss << rootpath << "/share/config/o2simtopology.json"; - std::string localconfig = std::string("o2simtopology_") + std::to_string(getpid()) + std::string(".json"); + configss << rootpath << "/share/config/o2simtopology_template.json"; + auto localconfig = std::string("o2simtopology_") + std::to_string(getpid()) + std::string(".json"); // need to add pid to channel urls to allow simultaneous deploys! - // open otiginal config and read the JSON config - FILE* fp = fopen(configss.str().c_str(), "r"); - constexpr unsigned short usmax = std::numeric_limits<unsigned short>::max() - 1; - char Buffer[usmax]; - rapidjson::FileReadStream is(fp, Buffer, sizeof(Buffer)); - rapidjson::Document d; - d.ParseStream(is); - fclose(fp); - // find and manipulate URLS - std::string serveraddress; - std::string mergeraddress; - std::string s; - - auto& options = d["fairMQOptions"]; - assert(options.IsObject()); - for (auto option = options.MemberBegin(); option != options.MemberEnd(); - ++option) { - s = option->name.GetString(); - if (s == "devices") { - assert(option->value.IsArray()); - auto devices = option->value.GetArray(); - for (auto& device : devices) { - s = device["id"].GetString(); - if (s == "primary-server") { - auto channels = device["channels"].GetArray(); - auto sockets = (channels[0])["sockets"].GetArray(); - auto& addressv = (sockets[0])["address"]; - auto address = addressv.GetString(); - serveraddress = address + std::to_string(getpid()); - addressv.SetString(serveraddress.c_str(), d.GetAllocator()); - } - if (s == "hitmerger") { - auto channels = device["channels"].GetArray(); - for (auto& channel : channels) { - s = channel["name"].GetString(); - // set server's address for merger - if (s == "primary-get") { - auto sockets = channel["sockets"].GetArray(); - auto& addressv = (sockets[0])["address"]; - addressv.SetString(serveraddress.c_str(), d.GetAllocator()); - } - if (s == "simdata") { - auto sockets = channel["sockets"].GetArray(); - auto& addressv = (sockets[0])["address"]; - auto address = addressv.GetString(); - mergeraddress = address + std::to_string(getpid()); - addressv.SetString(mergeraddress.c_str(), d.GetAllocator()); - } - } - } - } - //loop over devices again and set URLs for the workers - for (auto& device : devices) { - s = device["id"].GetString(); - if (s == "worker") { - auto channels = device["channels"].GetArray(); - for (auto& channel : channels) { - s = channel["name"].GetString(); - if (s == "primary-get") { - auto sockets = channel["sockets"].GetArray(); - auto& addressv = (sockets[0])["address"]; - addressv.SetString(serveraddress.c_str(), d.GetAllocator()); - } - if (s == "simdata") { - auto sockets = channel["sockets"].GetArray(); - auto& addressv = (sockets[0])["address"]; - addressv.SetString(mergeraddress.c_str(), d.GetAllocator()); - } - } - } - } + // we simply insert the PID into the topology template + std::ifstream in(configss.str()); + std::ofstream out(localconfig); + std::string wordToReplace("#PID#"); + std::string wordToReplaceWith = std::to_string(getpid()); + std::string line; + size_t len = wordToReplace.length(); + while (std::getline(in, line)) { + size_t pos = line.find(wordToReplace); + if (pos != std::string::npos) { + line.replace(pos, len, wordToReplaceWith); } + out << line << '\n'; } - // write the config copy with new name - fp = fopen(localconfig.c_str(), "w"); - rapidjson::FileWriteStream os(fp, Buffer, sizeof(Buffer)); - rapidjson::Writer<rapidjson::FileWriteStream> writer(os); - d.Accept(writer); - fclose(fp); + in.close(); + out.close(); + + // create a channel for outside event notifications --> factor out into common function + // auto factory = FairMQTransportFactory::CreateTransportFactory("zeromq"); + auto externalpublishchannel = o2::simpubsub::createPUBChannel(o2::simpubsub::getPublishAddress("o2sim-notifications")); auto& conf = o2::conf::SimConfig::Instance(); if (!conf.resetFromArguments(argc, argv)) { @@ -260,7 +365,7 @@ int main(int argc, char* argv[]) } // in case of zero events asked (only setup geometry etc) we just call the non-distributed version // (otherwise we would need to add more synchronization between the actors) - if (conf.getNEvents() <= 0) { + if (conf.getNEvents() <= 0 && !conf.asService()) { LOG(INFO) << "No events to be simulated; Switching to non-distributed mode"; const int Nargs = argc + 1; std::string name("o2-sim-serial"); @@ -278,6 +383,12 @@ int main(int argc, char* argv[]) return r; } + gAskedEvents = conf.getNEvents(); + if (conf.asService()) { + launchControlThread(); + // launchWorkerListenerThread(); + } + // we create the global shared mem pool; just enough to serve // n simulation workers int nworkers = conf.getNSimWorkers(); @@ -291,8 +402,6 @@ int main(int argc, char* argv[]) o2::utils::ShmManager::Instance().disable(); } - std::vector<int> childpids; - int pipe_serverdriver_fd[2]; if (pipe(pipe_serverdriver_fd) != 0) { perror("problem in creating pipe"); @@ -315,7 +424,7 @@ int main(int argc, char* argv[]) const std::string config = localconfig; // copy all arguments into a common vector - const int Nargs = argc + 7; + const int Nargs = argc + 9; const char* arguments[Nargs]; arguments[0] = name.c_str(); arguments[1] = "--control"; @@ -324,8 +433,10 @@ int main(int argc, char* argv[]) arguments[4] = "primary-server"; arguments[5] = "--mq-config"; arguments[6] = config.c_str(); + arguments[7] = "--severity"; + arguments[8] = "debug"; for (int i = 1; i < argc; ++i) { - arguments[6 + i] = argv[i]; + arguments[8 + i] = argv[i]; } arguments[Nargs - 1] = nullptr; for (int i = 0; i < Nargs; ++i) { @@ -342,10 +453,18 @@ int main(int argc, char* argv[]) } return r; } else { - childpids.push_back(pid); + gChildProcesses.push_back(pid); + setpgid(pid, pid); close(pipe_serverdriver_fd[1]); std::cout << "Spawning particle server on PID " << pid << "; Redirect output to " << getServerLogName() << "\n"; - launchThreadMonitoringEvents(pipe_serverdriver_fd[0], "DISTRIBUTING EVENT : "); + + // A simple callback for distributed primary-chunk "events" + auto distributionCallback = [&conf, &externalpublishchannel](std::vector<int> const& v) { + std::stringstream str; + str << "EVENT " << v.back() << " DISTRIBUTED"; + o2::simpubsub::publishMessage(externalpublishchannel, o2::simpubsub::simStatusString("O2SIM", "INFO", str.str())); + }; + launchThreadMonitoringEvents(pipe_serverdriver_fd[0], "DISTRIBUTING EVENT : ", gDistributedEvents, distributionCallback); } auto internalfork = getenv("ALICE_SIMFORKINTERNAL"); @@ -376,7 +495,8 @@ int main(int argc, char* argv[]) "worker", "--mq-config", localconfig.c_str(), "--severity", "info", (char*)nullptr); return 0; } else { - childpids.push_back(pid); + gChildProcesses.push_back(pid); + setpgid(pid, pid); // the worker processes will form their own group std::cout << "Spawning sim worker " << id << " on PID " << pid << "; Redirect output to " << workerlogss.str() << "\n"; } @@ -397,7 +517,6 @@ int main(int argc, char* argv[]) close(fd); // fd no longer needed - the dup'ed handles are sufficient close(pipe_mergerdriver_fd[0]); setenv("ALICE_O2SIMMERGERTODRIVER_PIPE", std::to_string(pipe_mergerdriver_fd[1]).c_str(), 1); - const std::string name("o2-sim-hit-merger-runner"); const std::string path = installpath + "/" + name; execl(path.c_str(), name.c_str(), "--control", "static", "--catch-signals", "0", "--id", "hitmerger", "--mq-config", localconfig.c_str(), @@ -405,51 +524,90 @@ int main(int argc, char* argv[]) return 0; } else { std::cout << "Spawning hit merger on PID " << pid << "; Redirect output to " << getMergerLogName() << "\n"; - childpids.push_back(pid); + setpgid(pid, pid); + gChildProcesses.push_back(pid); close(pipe_mergerdriver_fd[1]); - launchThreadMonitoringEvents(pipe_mergerdriver_fd[0], "EVENT FINISHED : "); + + // A simple callback that determines if the simulation is complete and triggers + // a shutdown of all child processes. This appears to be more robust than leaving + // that decision upon the children (sometimes there are problems with that). + auto finishCallback = [&conf, &externalpublishchannel](std::vector<int> const& v) { + std::stringstream str; + str << "EVENT " << v.back() << " FINISHED " << gAskedEvents << " " << v.size(); + o2::simpubsub::publishMessage(externalpublishchannel, o2::simpubsub::simStatusString("O2SIM", "INFO", str.str())); + if (gAskedEvents == v.size()) { + o2::simpubsub::publishMessage(externalpublishchannel, o2::simpubsub::simStatusString("O2SIM", "STATE", "DONE")); + if (!conf.asService()) { + LOG(INFO) << "SIMULATION IS DONE. INITIATING SHUTDOWN."; + for (auto p : gChildProcesses) { + killpg(p, SIGTERM); + } + } else { + LOG(INFO) << "SIMULATION DONE. STAYING AS DAEMON."; + } + } + }; + + launchThreadMonitoringEvents(pipe_mergerdriver_fd[0], "EVENT FINISHED : ", gFinishedEvents, finishCallback); } // wait on merger (which when exiting completes the workflow) - auto mergerpid = childpids.back(); + auto mergerpid = gChildProcesses.back(); int status, cpid; // wait just blocks and waits until any child returns; but we make sure to wait until merger is here + bool errored = false; while ((cpid = wait(&status)) != mergerpid) { - if (WIFSIGNALED(status)) { + if (WEXITSTATUS(status) || WIFSIGNALED(status)) { LOG(INFO) << "Process " << cpid << " EXITED WITH CODE " << WEXITSTATUS(status) << " SIGNALED " << WIFSIGNALED(status) << " SIGNAL " << WTERMSIG(status); - } - // we bring down all processes if one of them aborts - if (WTERMSIG(status) == SIGABRT) { - for (auto p : childpids) { - kill(p, SIGABRT); + + // we bring down all processes if one of them had problems or got a termination signal + // if (WTERMSIG(status) == SIGABRT || WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS || WTERMSIG(status) == SIGTERM) { + LOG(INFO) << "Problem detected (or child received termination signal) ... shutting down whole system "; + for (auto p : gChildProcesses) { + LOG(INFO) << "TERMINATING " << p; + killpg(p, SIGTERM); // <--- makes sure to shutdown "unknown" child pids via the group property } - cleanup(); - LOG(FATAL) << "ABORTING DUE TO ABORT IN COMPONENT"; + LOG(ERROR) << "SHUTTING DOWN DUE TO SIGNALED EXIT IN COMPONENT " << cpid; + errored = true; } } // This marks the actual end of the computation (since results are available) LOG(INFO) << "Merger process " << mergerpid << " returned"; LOG(INFO) << "Simulation process took " << timer.RealTime() << " s"; - // make sure the rest shuts down - for (auto p : childpids) { - if (p != mergerpid) { - LOG(DEBUG) << "SHUTTING DOWN CHILD PROCESS " << p; - kill(p, SIGTERM); + if (!errored) { + // ordinary shutdown of the rest + for (auto p : gChildProcesses) { + if (p != mergerpid) { + LOG(INFO) << "SHUTTING DOWN CHILD PROCESS " << p; + killpg(p, SIGTERM); + } } } LOG(DEBUG) << "ShmManager operation " << o2::utils::ShmManager::Instance().isOperational() << "\n"; - cleanup(); // do a quick check to see if simulation produced something reasonable // (mainly useful for continuous integration / automated testing suite) - auto returncode = checkresult(); + auto returncode = errored ? 1 : checkresult(); if (returncode == 0) { + // Extract a single file for MCEventHeaders + // This file will be small and can quickly unblock start of signal transport (in embedding). + // This is useful when we cache background events on the GRID. The headers file can be copied quickly + // and the rest of kinematics + Hits may follow asyncronously since they are only needed at much + // later stages (digitization). + + auto& conf = o2::conf::SimConfig::Instance(); + // easy check: see if we have number of entries in output tree == number of events asked + std::string kinefilename = o2::base::NameConf::getMCKinematicsFileName(conf.getOutPrefix().c_str()); + std::string headerfilename = o2::base::NameConf::getMCHeadersFileName(conf.getOutPrefix().c_str()); + o2::dataformats::MCEventHeader::extractFileFromKinematics(kinefilename, headerfilename); + LOG(INFO) << "SIMULATION RETURNED SUCCESFULLY"; } + cleanup(); return returncode; } diff --git a/run/o2simtopology_template.json b/run/o2simtopology_template.json new file mode 100644 index 0000000000000..f62297a1fa33e --- /dev/null +++ b/run/o2simtopology_template.json @@ -0,0 +1,151 @@ +{ + "fairMQOptions":{ + "devices":[ + { + "id":"worker", + "channels":[ + { + "name":"primary-get", + "sockets":[ + { + "type":"req", + "method":"connect", + "address":"ipc:///tmp/o2sim-primary-get-#PID#", + "sndBufSize":"100000", + "rcvBufSize":"100000", + "rateLogging":"0" + } + ] + }, + { + "name":"o2sim-primserv-info", + "sockets":[ + { + "type":"req", + "method":"connect", + "address":"ipc:///tmp/o2sim-primserv-info-#PID#", + "sndBufSize":"1000", + "rcvBufSize":"1000", + "rateLogging":"0" + } + ] + }, + { + "name":"simdata", + "sockets":[ + { + "type":"push", + "method":"connect", + "address":"ipc:///tmp/o2sim-hitmerger-simdata-#PID#", + "sndBufSize":1000, + "rcvBufSize":1000, + "rateLogging":0 + } + ] + } + ] + }, + { + "id":"primary-server", + "channels":[ + { + "name":"primary-get", + "sockets":[ + { + "type":"rep", + "method":"bind", + "address":"ipc:///tmp/o2sim-primary-get-#PID#", + "sndBufSize":100000, + "rcvBufSize":100000, + "rateLogging":0 + } + ] + }, + { + "name":"o2sim-primserv-info", + "sockets":[ + { + "type":"rep", + "method":"bind", + "address":"ipc:///tmp/o2sim-primserv-info-#PID#", + "sndBufSize":1000, + "rcvBufSize":1000, + "rateLogging":0 + } + ] + }, + { + "name":"primary-notifications", + "sockets":[ + { + "type":"pub", + "method":"bind", + "address":"ipc:///tmp/o2sim-primary-notifications-#PID#", + "sndBufSize":1000, + "rcvBufSize":1000, + "rateLogging":0 + } + ] + } + ] + }, + { + "id":"hitmerger", + "channels":[ + { + "name":"primary-get", + "sockets":[ + { + "type":"req", + "method":"connect", + "address":"ipc:///tmp/o2sim-primary-get-#PID#", + "sndBufSize":"1000", + "rcvBufSize":"1000", + "rateLogging":"0" + } + ] + }, + { + "name":"o2sim-primserv-info", + "sockets":[ + { + "type":"req", + "method":"connect", + "address":"ipc:///tmp/o2sim-primserv-info-#PID#", + "sndBufSize":"1000", + "rcvBufSize":"1000", + "rateLogging":"0" + } + ] + }, + { + "name":"simdata", + "sockets":[ + { + "type":"pull", + "method":"bind", + "address":"ipc:///tmp/o2sim-hitmerger-simdata-#PID#", + "sndBufSize":1000, + "rcvBufSize":1000, + "rateLogging":0 + } + ] + }, + { + "name":"merger-notifications", + "sockets":[ + { + "type":"pub", + "method":"bind", + "address":"ipc:///tmp/o2sim-merger-notifications-#PID#", + "sndBufSize":1000, + "rcvBufSize":1000, + "rateLogging":0 + } + ] + } + ] + } + ] + } +} diff --git a/run/simlogcheck.sh b/run/simlogcheck.sh index ced2cd01294c0..4e4bc085b0e95 100755 --- a/run/simlogcheck.sh +++ b/run/simlogcheck.sh @@ -1,7 +1,7 @@ #!/bin/bash -l set -x -# a script checking logfiles for signs of error +# a script checking logfiles for signs of errors # can be used to detect most common errors automatically # returns/exits with 0 if no problem @@ -10,19 +10,29 @@ error=0 for file in "$@"; do echo "looking into ${file}" + fileerrors=0 + # We don't want to see "Error" or "ERROR" messages value=$(grep "Error" ${file}) if [ -n "${value}" ]; then echo "check for Error failed" - let error=error+1 + let filererrors=fileerrors+1 fi value=$(grep "ERROR" ${file}) if [ -n "${value}" ]; then echo "check for ERROR failed" - let error=error+1 + let fileerrors=fileerrors+1 + fi + + if [ "${fileerrors}" != "0" ]; then + echo "Found problem in file ${file}" + echo "<--- START OF FILE ${file} ---" + cat ${file} + echo "**** END OF FILE ${file} ****>" fi + let error=fileerrors+error done - + exit ${error} diff --git a/run/startSim.sh b/run/startSim.sh index 5e1e2f1d44603..2678477c4b68d 100755 --- a/run/startSim.sh +++ b/run/startSim.sh @@ -10,7 +10,7 @@ killall -9 o2-sim-hit-merger-runner topologyfile=${O2_ROOT}/share/config/o2simtopology.json # we have one primary distributor -xterm -geometry 80x25+0+0 -e "o2-sim-primary-server-device-runner --control static --id primary-server --mq-config ${topologyfile} -n 20 -m PIPE TOF TRD TPC PHS EMC FIT MCH -g pythia8 -e TGeant3 | tee serverlog;bash" & +xterm -geometry 80x25+0+0 -e "o2-sim-primary-server-device-runner --control static --id primary-server --mq-config ${topologyfile} -n 20 -m PIPE TOF TRD TPC PHS EMC FIT MCH -g pythia8pp -e TGeant3 | tee serverlog;bash" & for i in `seq 1 ${NSIMWORKERS}`; do xterm -geometry 80x25+500+0 -e "o2-sim-device-runner --control static --id worker${i} --config-key worker --mq-config ${topologyfile} --severity info | tee simlog${i};bash" & diff --git a/scripts/datamodel-doc/ALICEO2dataModel.py b/scripts/datamodel-doc/ALICEO2dataModel.py new file mode 100644 index 0000000000000..106f9c2416a03 --- /dev/null +++ b/scripts/datamodel-doc/ALICEO2dataModel.py @@ -0,0 +1,1253 @@ +#!/usr/bin/env python3 +import sys +import numpy as np +import nltk + +# ----------------------------------------------------------------------------- +# definitions +# +# ............................................................................. +# types of column declarations +# 0: COLUMN +# 1: INDEX_COLUMN_FULL +# 2: INDEX_COLUMN +# 3: SELF_INDEX_COLUMN_FULL +# 4: SELF_INDEX_COLUMN +# 5: EXPRESSION_COLUMN +# 6: DYNAMIC_COLUMN + + +def columnTypes(abbr=0): + if abbr == 0: + types = ["", "INDEX_", "INDEX_", "INDEX_", "INDEX_", "EXPRESSION_", "DYNAMIC_"] + types[3] = "SELF_"+types[3] + types[4] = "SELF_"+types[4] + types = [s+"COLUMN" for s in types] + types = ["DECLARE_SOA_"+s for s in types] + types[1] = types[1]+"_FULL" + types[3] = types[3]+"_FULL" + else: + types = ["", "I", "I", "SI", "SI", "E", "D", "GI"] + + return types + +# ............................................................................. +# types of table declarations +# 0: TABLE +# 1: TABLE_FULL +# 2: EXTENDED_TABLE +# 3: INDEX_TABLE +# 4: INDEX_TABLE_EXCLUSIVE +# 5: EXTENDED_TABLE_USER +# + + +def tableTypes(abbr=0): + if abbr == 0: + types = ["", "", "EXTENDED_", "INDEX_", "INDEX_", "EXTENDED_"] + types = [s+"TABLE" for s in types] + types = ["DECLARE_SOA_"+s for s in types] + types[1] = types[1]+"_FULL" + types[4] = types[4]+"_EXCLUSIVE" + types[5] = types[5]+"_USER" + else: + types = ["", "", "E", "I", "I", "E"] + + return types + +# ----------------------------------------------------------------------------- +# classes +# +# ............................................................................. +# holds a word and the corresponding line number + + +class word: + def __init__(self, txt, lnr): + self.txt = txt + self.lnr = lnr + +# ............................................................................. + + +class typedef: + def __init__(self, name, cont): + self.name = name + self.cont = cont + + def print(self): + print(" typedef: "+self.name) + print(" content: "+self.cont) + +# ............................................................................. + + +class define: + def __init__(self, name, line): + self.name = name + self.vars = list() + + # how many parameters + vars = "".join(line.split("(")[1:]).split(")")[0].split(",") + if vars[0] != "": + self.vars = vars + self.cont = ")".join(line.split(")")[1:]).strip() + else: + self.cont = line + + def expandLine(self, line): + expandedLine = line + + if self.name in line: + if len(self.vars) == 0: + # no substitution of variables needed + expandedLine = line.replace(self.name, self.cont) + else: + # substitute variables vars + vars = "".join(line.split("(")[1:]).split(")")[0].split(",") + if len(vars) != len(self.vars): + print("ATTENTION") + print("Substitution error!") + print("") + self.print() + print("") + print(" ", line) + + else: + words = split(self.cont) + for ind1 in range(len(self.vars)): + for ind2 in range(len(words)): + if words[ind2] == self.vars[ind1].strip(): + words[ind2] = vars[ind1] + expandedLine = block(words) + + return expandedLine + + def print(self): + print(" define: "+self.name) + print(" content: "+self.cont) + +# ............................................................................. + + +class using: + def __init__(self, nslevel, name, definition, cont): + self.nslevel = nslevel + self.name = name + self.definition = definition + self.cont = cont + self.kind = 0 + self.master = "" + self.joiners = list() + + self.master = fullDataModelName(nslevel, definition) + if definition.find("::iterator") != -1: + self.kind += 1 + self.master = fullDataModelName( + nslevel, "::".join(definition.split("::")[:-1])) + if definition.find("::Join<") != -1: + self.kind += 2 + tmp = definition.split("<")[1] + tmp = tmp.split(">")[0] + self.joiners = [fullDataModelName( + self.nslevel, s) for s in tmp.split(",")] + + # is this included + def where(self, usings): + for ind in range(len(usings)): + if self.name == usings[ind].name: + return ind + return -1 + + def synchronize(self, dm): + # check if any master equals a using name + if self.kind & 1 > 0: + for nsp in dm.namespaces: + for use in nsp.usings: + if self.master == use.name: + self.kind += 2 + self.joiners = use.joiners + + def print(self): + print(" using: "+self.name) + print(" kind: ", self.kind) + print(" definition: ", self.definition) + if self.kind & 1 > 0: + print(" master: "+self.master) + if self.kind & 2 > 0: + print(" joiners: ", self.joiners) + + def printHTML(self): + toPrint = self.name+" = " + if self.kind & 2 > 0: + toPrint += "soa::Join<" + for ind in range(len(self.joiners)): + if ind == 0: + toPrint += self.joiners[ind] + else: + toPrint += ", "+self.joiners[ind] + toPrint += ">" + else: + toPrint += self.master + + if self.kind & 1 > 0: + toPrint += "::iterator" + + print(" <li>"+toPrint+"</li>") + +# ----------------------------------------------------------------------------- + + +class column: + def __init__(self, kind, nslevel, hfile, cname, gname, type, cont): + self.kind = kind + self.nslevel = nslevel + self.hfile = hfile # header file + self.cname = cname # column name + self.gname = gname # getter name + self.type = type + self.cont = cont + self.pointsInto = "" + self.comment = "" + + def where(self, columns): + for ind in range(len(columns)): + if self.cname == columns[ind].cname: + return ind + return -1 + + def print(self): + print(" column: "+self.cname) + print(" kind: ", self.kind) + print(" access: "+self.gname) + print(" type: "+self.type) + print(" comment: "+self.comment) + + def printHTML(self): + print(" <tr>") + print(" <td>"+fullDataModelName(self.nslevel, self.cname)+"</td>") + print(" <td>"+columnTypes(1)[self.kind]+"</td>") + print(" <td>"+self.gname+"</td>") + print(" <td>"+self.type+"</td>") + print(" <td>"+self.comment+"</td>") + print(" </tr>") + +# ............................................................................. + + +class table: + def __init__(self, kind, nslevel, hfile, tname, cont): + self.kind = kind + self.nslevel = nslevel + self.hfile = hfile # header file + self.tname = tname # table name + self.CErelation = ["", "", ""] + self.cont = cont + self.colNames = list() + self.columns = list() + self.toExtendWith = "" + self.comment = "" + + def addColumn(self, col): + self.columns.append(col) + + def where(self, tables): + for ind in range(len(tables)): + if self.tname == tables[ind].tname: + return ind + return -1 + + # fill columns + def synchronize(self, dm): + for colName in self.colNames: + # get column with name colName + self.columns.append(dm.getColumn(colName)) + + def print(self): + print(" table: "+self.tname) + print(" kind: ", self.kind) + print(" producer: "+self.CErelation[2]) + for col in self.columns: + print(" column: "+col.cname+":"+col.type) + + def printHeaderHTML(self): + tableName = self.tname + if tableTypes(1)[self.kind] != "": + tableName += " ("+tableTypes(1)[self.kind]+")" + print(" <button class=\"myaccordion\"><i class=\"fa fa-table\"></i> " + + tableName+"</button>") + print(" <div class=\"panel\">") + + def printSubHeaderHTML(self): + print(" <table class=DataModel>") + print(" <tr>") + print(" <th>Name</th>") + print(" <th></th>") + print(" <th>Getter</th>") + print(" <th>Type</th>") + print(" <th>Comment</th>") + print(" </tr>") + + def printFooterHTML(self): + print(" </table>") + print(" </div>") + print("") + + +# ----------------------------------------------------------------------------- + + +class namespace: + def __init__(self, nslevel, cont): + self.nslevel = nslevel + self.cont = cont + self.columns = list() + self.tables = list() + self.usings = list() + + def addUsing(self, using): + self.usings.append(using) + + def addColumn(self, col): + self.columns.append(col) + + def addTable(self, table): + self.tables.append(table) + + # set the producer + def setProducer(self, CErelation, tableName): + for ind in range(len(self.tables)): + if self.tables[ind].tname == tableName: + self.tables[ind].CErelation = CErelation + + # fill columns of all tables + def synchronize(self, dm): + for use in self.usings: + use.synchronize(dm) + for tab in self.tables: + tab.synchronize(dm) + + # merge with newnsp + def join(self, newnsp): + if newnsp.nslevel != self.nslevel: + return + for use in newnsp.usings: + ind = use.where(self.usings) + if ind < 0: + self.usings.append(use) + for tab in newnsp.tables: + ind = tab.where(self.tables) + if ind < 0: + self.tables.append(tab) + for col in newnsp.columns: + ind = col.where(self.columns) + if ind < 0: + self.columns.append(col) + + def print(self): + print(" namespace: "+self.nslevel) + print(" number of tables: ", len(self.tables)) + for tab in self.tables: + tab.print() + print(" number of usings: ", len(self.usings)) + for use in self.usings: + use.print() + print(" number of columns: ", len(self.columns)) + for col in self.columns: + col.print() + +# ----------------------------------------------------------------------------- + + +class datamodel: + def __init__(self, dmname, CErelation, hfile, initCard=None): + with open(hfile, 'r') as file: + self.dmname = dmname + self.CErelations = list() + self.CErelations.append(CErelation) + self.defines = list() + self.namespaces = list() + if initCard != None: + self.initCard = initCard + + # read the file + lines_in_file = file.readlines() + content = pickContent(lines_in_file) + + # parse datamodel + parseContent(hfile, content, "", self) + self.synchronize() + + def addNamespace(self, namespace): + # does this namespace exist already? + ind = self.where(namespace) + if ind >= 0: + self.namespaces[ind].join(namespace) + else: + self.namespaces.append(namespace) + + def addDefine(self, define): + self.defines.append(define) + + def setProducer(self, CErelation, tableName): + for nsp in self.namespaces: + nsp.setProducer(CErelation, tableName) + if not CErelation in self.CErelations: + self.CErelations.append(CErelation) + + def isProducedBy(self, CErelation): + producedBy = list() + for nsp in self.namespaces: + for table in nsp.tables: + if table.CErelation[2] == CErelation[2]: + producedBy.append(table) + return producedBy + + def where(self, namespace): + for ind in range(len(self.namespaces)): + if namespace.nslevel == self.namespaces[ind].nslevel: + return ind + return -1 + + # join with data model dmnew + def join(self, dmnew): + for nsp in dmnew.namespaces: + ind = self.where(nsp) + if ind >= 0: + self.namespaces[ind].join(nsp) + else: + self.namespaces.append(nsp) + + # fill columns of all tables + def synchronize(self): + for nsp in self.namespaces: + nsp.synchronize(self) + + def getColumn(self, colName): + # remove <> from colName + cnameToSearch = colName.split("<")[0] + + # index columns are special! + if cnameToSearch == "o2::soa::Index": + return column(len(columnTypes(1))-1, "o2::soa", "", cnameToSearch, "globalIndex", "int64_t", colName) + + for nsp in self.namespaces: + for col in nsp.columns: + cnameToUse = fullDataModelName(nsp.nslevel, col.cname) + if cnameToUse == cnameToSearch: + return col + + # create dummy column + return column(-1, "", "", cnameToSearch, "", "?", colName) + + def print(self): + print("data model: "+self.dmname) + print(" producers:") + for CErelation in self.CErelations: + print(" ", CErelation[2]) + for ns in self.namespaces: + ns.print() + + def printHTML(self): + # get some variables + tmp = self.initCard.find("O2general/mainDir/O2local") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + O2path = tmp + tmp = self.initCard.find("O2general/mainDir/O2Physicslocal") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + O2Physicspath = tmp + tmp = self.initCard.find("O2general/mainDir/O2GitHub") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + O2href = tmp + tmp = self.initCard.find("O2general/mainDir/O2PhysicsGitHub") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + O2Physicshref = tmp + tmp = self.initCard.find("O2general/delimAO2D") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + delimAO2D = tmp + tmp = self.initCard.find("O2general/delimHelpers") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + delimHelpers = tmp + tmp = self.initCard.find("O2general/delimJoins") + if tmp == None: + tmp = "" + else: + tmp = tmp.text.strip() + delimJoins = tmp + + # gather all tables and columns + tabs = list() + uses = list() + for nsp in self.namespaces: + for tab in nsp.tables: + tabs.append(tab) + for use in nsp.usings: + uses.append(use) + + # loop over producers + HTheaderToWrite = True + amFirst = True + for CErelation in self.CErelations: + # get tables with given producer + inds = [i for i, x in enumerate( + tabs) if x.CErelation[2] == CErelation[2]] + if len(inds) == 0: + continue + + # first producer is AO2D tables + if amFirst == True: + print(delimAO2D) + href2u = O2href + path2u = O2path + else: + # helper tasks header + if HTheaderToWrite == True: + print(delimAO2D) + print("") + print(delimHelpers) + href2u = O2Physicshref + path2u = O2Physicspath + HTheaderToWrite = False + + print("") + print("#### ", CErelation[2]) + + # add source code information if available + if CErelation[1] != "": + if href2u != "": + print("Code file: <a href=\""+href2u+"/"+CErelation[0].split(path2u)[ + 1]+"/"+CErelation[1]+"\" target=\"_blank\">"+CErelation[1]+"</a>") + else: + print("Code file: "+CErelation[0]+"/"+CErelation[1]) + + print("<div>") + print("") + + # print all tables of given producer + for ind in inds: + tab = tabs[ind] + + # print the table header + tab.printHeaderHTML() + + # print table comment + print(" <div>") + print(" ", tab.comment) + print(" </div>") + + # print header file + hf2u = block(tab.hfile.split(path2u)[ + 1:], False).strip().lstrip("/") + print(" <div>") + print(" Header file: <a href=\""+href2u + + "/"+hf2u+"\" target=\"_blank\">"+hf2u+"</a>") + print(" </div>") + + # print extends + if tab.kind == 2 or tab.kind == 5: + print(" <div>Extends:") + print(" <ul>") + print(" ", tab.toExtendWith) + print(" </ul>") + print(" </div>") + + # find all usings with tab + useTable = list() + for use in uses: + if tab.tname in use.joiners: + useTable.append(use) + elif tab.tname == use.master: + useTable.append(use) + + # print these usings + if len(useTable) > 0: + print(" <div>Is used in:") + print(" <ul>") + for use in useTable: + use.printHTML() + print(" </ul>") + print(" </div>") + + # print the table header + tab.printSubHeaderHTML() + + # EXTENDED_TABLE and EXTENDED_TABLE_USER are extended + if tab.kind == 2 or tab.kind == 5: + # this table has to be extended, find the extending table and + # print all of its columns + einds = [i for i, x in enumerate( + tabs) if x.tname == tab.toExtendWith] + for ind in einds: + for col in tabs[ind].columns: + col.printHTML() + + # print the remaining columns + for col in tab.columns: + col.printHTML() + + # print the table footer + tab.printFooterHTML() + + print("</div>") + amFirst = False + + # now print the usings + print(delimHelpers) + if len(uses) > 0: + print("") + print(delimJoins) + print("") + print("<a name=\"usings\"></a>") + print("#### List of defined joins and iterators") + print("<div>") + for use in uses: + print("") + print( + " <button class=\"myaccordion\"><i class=\"fa fa-map-pin\"></i> "+use.name+"</button>") + print(" <div class=\"panel\">") + print(" <ul>") + use.printHTML() + print(" </ul>") + print(" </div>") + print("</div>") + print(delimJoins) + +# ----------------------------------------------------------------------------- +# functions +# +# ............................................................................. + + +def block(words, withspace=True, space=" "): + sep = "" + if withspace == True: + sep = space + cont = "" + + if len(words) == 0: + return cont + + if isinstance(words[0], str): + for w in words: + cont += w+sep + else: + for w in words: + cont += w.txt+sep + + return cont + +# ............................................................................. + + +def split(block): + + # split into words + words = nltk.word_tokenize(block) + + return words + +# ............................................................................. +# content is a tuple<list<word>, list<str>> +# create tuple with (content[0][[i1:i2],[i3:i4]], content[1]) + + +def select(content, i1, i2=-1, i3=-1, i4=-1): + wsel = list() + + if i2 < 0: + i2 = len(content[0]) + for w in content[0][i1:i2]: + wsel.append(w) + + if i3 >= 0: + if i4 < 0: + i4 = len(content[0]) + for w in content[0][i3:i4]: + wsel.append(w) + + return wsel, content[1] + +# ............................................................................. +# remove text from line between brackets obr..cbr +# obr and cbr are sequences of characters +# return modified line and int stat +# stat is the number of not completed brackets (needs to be >= 0) + + +def removeInBrackets(obr, cbr, line, stat): + # find obr + answ = list(map(lambda x: line[x:x + len(obr)] + == obr, range(len(line) - len(obr) + 1))) + iop = [i for i, x in enumerate(answ) if x == True] + + # find cbr + answ = list(map(lambda x: line[x:x + len(cbr)] + == cbr, range(len(line) - len(cbr) + 1))) + icl = [i for i, x in enumerate(answ) if x == True] + + # build sequence which holds the number of open brackets + # at each character of the line + seq = [stat]*len(line) + for i1 in iop: + for i2 in range(i1, len(line)): + seq[i2] += 1 + for i1 in icl: + for i2 in range(i1+len(cbr), len(line)): + seq[i2] -= 1 + + # compute the results + stat = seq[-1] + if stat < 0: + sys.exit(obr+' ... '+cbr+' missmatch! EXIT -->') + + # only select characters with seq[]=0 + newline = "" + for i1 in [i for i, x in enumerate(seq) if x == 0]: + newline += line[i1] + + return stat, newline + +# ............................................................................. + + +def pickContent(lines_in_file): + + # 1. remove the comments // but not the //! + # 2. consider extensions \ + # 3. remove comment blocks /* ... */ + linesWithoutComments = list() + lineToAdd = "" + for line in lines_in_file: + + # 1. remove the comments // but not the //! + l = line + i1 = l.find("//") + while i1 >= 0: + if l[i1+2] != "!": + l = l[0:i1].strip() + i1 = l.find("//", i1+2) + if l == "": + continue + + # 2. consider extensions \ + if l.strip().endswith("\\"): + lineToAdd = lineToAdd+" "+l[:len(l)-2].strip() + else: + lineToAdd = lineToAdd+" "+l + linesWithoutComments.append(lineToAdd) + lineToAdd = "" + + # 3. remove comment blocks /* ... */ + stat = 0 + for ind in range(len(linesWithoutComments)): + res = removeInBrackets("/*", "*/", linesWithoutComments[ind], stat) + stat = res[0] + linesWithoutComments[ind] = res[1] + + # select all lines starting with #define + idfs = [l for l, s in enumerate( + linesWithoutComments) if s.lstrip().startswith("#define")][::-1] + for idf in idfs: + ws = split(linesWithoutComments[idf]) + defstring = linesWithoutComments[idf].split(ws[2], 1)[1] + df = define(ws[2], defstring) + + # find the corresponding #undef + iend = len(linesWithoutComments) + iudfs = [l for l, s in enumerate( + linesWithoutComments) if s.lstrip().startswith("#undef")][::-1] + for iudf in iudfs: + ws = split(linesWithoutComments[iudf]) + if ws[2] == df.name: + iend = iudf-1 + break + + # substitute #define within the def-undef block + for ii in range(idf+1, iend): + linesWithoutComments[ii] = df.expandLine(linesWithoutComments[ii]) + + # create list of word(s) + words = list() + for ind in range(len(linesWithoutComments)): + # for this remove the //! comments + l2u = linesWithoutComments[ind] + if l2u.strip() == "": + continue + i1 = l2u.find("//!") + if i1 >= 0: + l2u = l2u[0:i1].strip() + for w in split(l2u): + words.append(word(w, ind)) + + content = (words, linesWithoutComments) + + return content + +# ............................................................................. +# a: list of strings +# b: list of words +# is a contained in b? + + +def list_in(a, b): + + # create list of strings + b2u = list() + for w in b: + b2u.append(w.txt) + + # compare a and b2u + return list(map(lambda x: b2u[x:x + len(a)] == a, range(len(b2u) - len(a) + 1))) + +# ............................................................................. + + +def fullDataModelName(nslevel, name): + toks0 = nslevel.split("::") + toks1 = name.split("::") + + fullName = "" + for tok in toks0: + if tok not in toks1: + if fullName == "": + fullName = tok + else: + fullName += "::"+tok + else: + break + + if fullName == "": + fullName = name + else: + fullName += "::"+name + + return fullName + +# ............................................................................. +# extract the column names from a table declaration +# cont contains the declaration + + +def tableColumnNames(nslevel, cont, kind=0): + + # specification according to kind of table + noff = 3 + if kind == 1: + noff = 4 + + # split cont with "," + buf = block(cont[:len(cont)-2], False) + toks = buf.split(",") + + # get column definitions, ATTENTION: some contain <> + colNames = list() + col = "" + nop = 0 + ncl = 0 + for tok in toks[noff:]: + col += tok + nop += tok.count("<") + ncl += tok.count(">") + + if (ncl == nop): + colNames.append(col) + col = "" + else: + col += "," + + # complete namespace + fullColNames = list() + toks0 = nslevel.split("::") + for colName in colNames: + toks1 = colName.split("::") + + fullColName = "" + for tok in toks0: + if tok not in toks1: + if fullColName == "": + fullColName = tok + else: + fullColName += "::"+tok + else: + break + + if fullColName == "": + fullColName = colName + else: + fullColName += "::"+colName + + fullColNames.append(fullColName) + + return fullColNames + +# ............................................................................. + + +def extractTables(nslevel, content): + words = content[0] + lines = content[1] + tables = list() + + # table types + types = tableTypes() + + # find indices of any type of table declarations + def condition(s): + res = False + for x in types: + res = res or (s.txt == x) + return res + inds = [idx for idx, element in enumerate(words) if condition(element)] + + # loop over declarations + for icol in inds: + iend = [i for i, x in enumerate( + list_in([")", ";"], words[icol:])) if x == True] + if len(iend) == 0: + print(nslevel) + sys.exit('Ending ); not found in table declaration! EXIT -->') + cont = words[icol:iend[0]+icol+2] + + kind = [i for i, x in enumerate(types) if x == words[icol].txt][0] + tname = fullDataModelName(nslevel, words[icol+2].txt) + + # extract column names + fullColNames = tableColumnNames(nslevel, cont, kind) + + # kind, namespace, tname, cont + tab = table(kind, nslevel, "", tname, block(cont)) + tab.colNames = fullColNames + + # EXTENDED_TABLE? + if kind == 2 or kind == 5: + tab.toExtendWith = fullDataModelName(nslevel, words[icol+4].txt) + + # add a comment if available + line = lines[words[icol].lnr] + tab.comment = block(line.split("//!")[1:], True).strip() + + tables.append(tab) + + return tables + +# ............................................................................. + + +def extractColumns(nslevel, content): + words = content[0] + lines = content[1] + + # helper function to find any table declaration in a list of words + def condition(s): + res = False + for x in types: + res = res or (s.txt == x) + return res + + cols = list() + + # column types + types = columnTypes() + + # find indices of column declarations + inds = [idx for idx, element in enumerate(words) if condition(element)] + + # loop over declarations + for icol in inds: + iend = [i for i, x in enumerate( + list_in([")", ";"], words[icol:])) if x == True] + if len(iend) == 0: + print(nslevel) + sys.exit('Ending ); not found in column declaration! EXIT -->') + cont = words[icol:iend[0]+icol+2] + + kind = [i for i, x in enumerate(types) if x == words[icol].txt][0] + cname = words[icol+2].txt + gname = words[icol+4].txt + if kind in [1, 2, 3, 4]: + cname = cname+"Id" + gname = gname+"Id" + + # determine the type of the colums + # can be type, array<type,n>, or type[n] + type = "" + if words[icol].txt == types[0]: + type = block(words[icol+6:icol+iend[0]], False) + elif words[icol].txt == types[1]: + type = words[icol+6].txt + elif words[icol].txt == types[2]: + type = "int32" + elif words[icol].txt == types[3]: + type = words[icol+6].txt + elif words[icol].txt == types[4]: + type = words[icol+6].txt + elif words[icol].txt == types[5]: + iend = [i for i, x in enumerate( + list_in([","], words[icol+6:])) if x == True] + type = block(words[icol+6:icol++6+iend[0]], False) + elif words[icol].txt == types[6]: + iarr = [i for i, x in enumerate( + list_in(["-", ">"], cont)) if x == True] + if len(iarr) > 0: + iend = [i for i, x in enumerate( + list_in(["{"], cont[iarr[0]+2:])) if x == True] + type = block(cont[iarr[0]+2:iarr[0]+2+iend[0]], False) + else: + type = "?" + + # kind, namespace, name, type, cont + col = column(kind, nslevel, "", cname, gname, type, block(cont)) + if kind == 1: + col.pointsInto = words[icol+8].txt + if kind == 2: + col.pointsInto = words[icol+2].txt+"s" + + # add a comment if available + comment = "" + if kind in [1, 2]: + comment = "Pointer into "+col.pointsInto + line = lines[words[icol].lnr] + toks = line.split("//!") + if len(toks) > 1: + tmp = block(toks[1:], True).strip() + if tmp != "": + comment = tmp + col.comment = comment + + cols.append(col) + + return cols + +# ............................................................................. + + +def extractUsings(nslevel, content): + words = content[0] + lines = content[1] + usings = list() + + # using types + types = ["using"] + + def condition(s): + res = False + for x in types: + res = res or (s.txt == x) + return res + + # find indices of "using" + inds = [idx for idx, element in enumerate(words) if condition(element)] + + # loop over cases + for icol in inds: + iend = [i for i, x in enumerate( + list_in([";"], words[icol:])) if x == True] + if len(iend) == 0: + print(nslevel) + sys.exit('Ending ; not found in using declaration! EXIT -->') + cont = words[icol:icol+iend[0]+1] + + name = fullDataModelName(nslevel, words[icol+1].txt) + definition = block(words[icol+3:icol+iend[0]], False) + + # namespace, name, cont + use = using(nslevel, name, definition, block(cont)) + + usings.append(use) + + return usings + +# ............................................................................. +# A namespace is contained between "namespace 'name' {" and "}" +# Be aware that namespaces can be nested! + + +def parseContent(hfile, content, nslevel, dm): + words = content[0] + lines = content[1] + + # does this block contain a namespace definition? + # 2 formats + # 1. using namespace .....; + # 2. namespace .... {} + isps = [ind for ind, x in enumerate(words) if x.txt == "namespace"] + if len(isps) > 0: + p10 = isps[0] + if words[p10-1].txt == "using": + # 1. using namespace .....; + iop = [ind for ind, x in enumerate(words[p10:]) if x.txt == ";"] + if len(iop) == 0: + print("using namespace does not end with \";\"!") + print(block(words[p10:])) + exit() + p11 = len(words) + + else: + # 2. namespace .... {} + iop = [ind for ind, x in enumerate(words[p10:]) if x.txt == "{"] + if len(iop) == 0: + print("The opening bracket \"{\" is missing!") + print(block(words[p10:])) + exit() + icl = [ind for ind, x in enumerate(words[p10:]) if x.txt == "}"] + if len(icl) == 0: + print("The closing bracket \"}\" is missing!") + print(block(words[p10:])) + exit() + + # find namespace block within {} + nind = len(words) - p10 + ind = np.zeros(nind) + ind[iop] = 1 + ind[icl] = -1 + p11 = np.where(np.cumsum(ind[iop[0]:]) == 0) + if len(p11[0]) <= 0: + print(hfile) + exit() + p11 = p10+iop[0]+p11[0][0] + + # analyze the next block with updated nslevel + b2u = block(words[p10+1:p10+iop[0]], False) + if nslevel != "": + nslnew = fullDataModelName(nslevel, b2u) + else: + nslnew = b2u + + c2u = select(content, p10+1, p11) + parseContent(hfile, c2u, nslnew, dm) + + # remove words of ns and process rest + if p10 > 0 and p11 < len(words): + c2u = select(content, 0, p10, p11+1) + parseContent(hfile, c2u, nslevel, dm) + + else: + # this block of text is a namespace + if nslevel == "": + return True + + # find typedefs and replace affected items + itds = [ind for ind, x in enumerate(words) if x.txt == "typedef"] + for itd in itds: + name1 = words[itd+1].txt + name2 = words[itd+2].txt + # replace all name2 with name1 + for ind in range(itd+3, len(words)): + if words[ind].txt == name2: + words[ind].txt = name1 + + # analyze the block and create a namespace object nsp + nsp = namespace(nslevel, block(words)) + + # extract columns + cols = extractColumns(nslevel, content) + for col in cols: + col.hfile = hfile + nsp.addColumn(col) + + # extract tables + tables = extractTables(nslevel, content) + for tab in tables: + tab.CErelation = dm.CErelations[0] + tab.hfile = hfile + nsp.addTable(tab) + + # extract usings + usings = extractUsings(nslevel, content) + for using in usings: + nsp.addUsing(using) + + # update the datamodel dm + dm.addNamespace(nsp) + + return True + +# ----------------------------------------------------------------------------- +# A CErelation is a tuple<string,3> +# [0]: path +# [1]: code file (without path) +# [2]: executable + + +class CERelations: + def __init__(self, initCard): + self.relations = list() + + # exePreamble from initCard + self.exePreamble = initCard.find('O2general/exePreamble') + if self.exePreamble == None: + self.exePreamble = "" + else: + self.exePreamble = self.exePreamble.text.strip() + + # CEdeclarationString from initCard + self.CEdeclarationString = initCard.find( + 'O2general/CEdeclarationString') + if self.CEdeclarationString == None: + self.CEdeclarationString = "o2physics_add_dpl_workflow" + else: + self.CEdeclarationString = self.CEdeclarationString.text.strip() + + def addRelations(self, fileName): + path = block(fileName.split("/")[:-1], True, "/") + with open(fileName, 'r') as file: + # read the file + lines_in_file = file.readlines() + content = pickContent(lines_in_file) + + # parse CMakeLists file + # executable - code relations are defined with o2_add_dpl_workflow + idef = [ind for ind, x in enumerate( + content[0]) if x.txt == self.CEdeclarationString] + for ind in idef: + ename = self.exePreamble + content[0][ind+2].txt + cname = content[0][ind+4].txt + if len(cname.split(".")) < 2: + cname += ".cxx" + self.relations.append([path, cname, ename]) + + def getExecutable(self, codeFile): + # find the executable corresponding to codeFile + CErelation = ["", "", ""] + ice = [ind for ind, x in enumerate( + self.relations) if x[0]+x[1] == codeFile] + if len(ice) > 0: + CErelation = self.relations[ice[0]] + return CErelation + + def getCodeFile(self, executable): + # find the code file corresponding to executable + CErelation = ["", "", ""] + ice = [ind for ind, x in enumerate( + self.relations) if x[2] == executable] + if len(ice) > 0: + CErelation = self.relations[ice[0]] + return CErelation + + def print(self): + print("CE relations") + for relation in self.relations: + print(" path :", relation[0]) + print(" cname:", relation[1]) + print(" ename:", self.exePreamble+relation[2]) + + +# ----------------------------------------------------------------------------- diff --git a/scripts/datamodel-doc/README.md b/scripts/datamodel-doc/README.md new file mode 100644 index 0000000000000..a4f282e1eb635 --- /dev/null +++ b/scripts/datamodel-doc/README.md @@ -0,0 +1,110 @@ +# ALICEO2dataModel converter + +Allows to create an html representation of the ALICE O2 data model. +The generated html code can be inserted in docs/datamodel/[ao2dTables, helperTaskTables, joinsAndIterators].md of https://github.com/AliceO2Group/analysis-framework/. + +## Internals + +The ALICE O2 Data Analysis Framework is based on a number of flat tables which contain the experimental data. The tables are declared in several header files. Some of the tables are filled automatically when an AO2D file is processed others are filled by specific tasks. + +The ALICEO2dataModel converter analyses these header and task code files and extracts the table and column definitions of the tables. The information is converted into a html representation which can be included in the documentation site of the O2 Analysis Framework at https://github.com/AliceO2Group/analysis-framework/. + +The converter is implemented in python. The parsing functionality is contained in ALICEO2dataModel.py and the main program is in extractDataModel.py. The process is configured with inputCard.xml. + + +### Data Items + +Three types of files are considered to contain information related to the ALICE O2 Data Analysis Model: + +- header files +- code files +- CMakeLists.txt + +#### Header files +Header files are combed for definitions of: + +- namespace +- #define +- typedef +- using +- COLUMN declarations +- TABLE declarations + +In a first step the header files are scanned and comments (//) and comment blocks (/* ... */) are removed, whereas special comments (//!) are understood to be annotations of tables and columns. Blocks of line extensions (\) are reduced to a single line. + +In the such processed text #define directives are searched for and are used to substitute related text in the block starting with the actual #define directive and ending with an #undef directive or the end of the text. + +In a next processing round the text is split into namespaces, taking into account that namespaces can be nested. Namespaces are defined either with 'using namespace ...;' which is then active until the end of the text or with 'namespace {....}' which makes the namespace active only within the curled brackets. The splitting into namespaces is implemented in an iterative way. + +The text contained in a singular namespace (namespace not containing any other namespace) is searched for typedef specifiers which are used to substitute related types. Then column and table declarations and finally 'using' directives within the namespace block are extracted. + +As a result of this procedure one obtains a 'datamodel' object with a list of namespaces with their column and table declarations and using directives. + +#### Code files +Code files are combed for definitions of: + +- Produces + +Tables have a producer. In case of the tables filled with data from the AO2D files the producer is defined to be AO2D. For tables which are filled by analysis tasks the producer is deduced from the related Produces function declaration. The code files are scanned for Produces declarations and the name of the code file is added to the respective table in the previously described 'datamodel' object. + +#### CMakeLists.txt files +CMakeLists.txt files are combed for definitions of: + +- o2_add_dpl_workflow (executables and the related code files) + +The CMakeLists files are finally needed to relate a given code file with an executable, which allows to associate a table with its producing executable. + +### Output + +The html representation of the 'datamodel' object is achieved with the printHTML method. + + +## As simple as that + +- Install the software + +Clone O2 as usual. Go to scripts/datamodel-doc + +- Adapt inputCard.xml + +Set the path in tag O2general - General which is currently ../.. to the actual O2 installation path, e.g. /home/me/alice/O2 unless you run from the directory scripts/datamodel-doc. The other parameters should fit. + +- Run it + +./extractDataModel.py > htmloutput.txt + +- Update the markdown files with the content of htmloutput.txt. + + +### Update the markdown files automatically + +The python script mdUpdate.py allows to update the contents of the md files automatically. + +mdUpdate.py takes four arguments: + +Usage: +mdUpdate.py cc fn2u fnold fnnew + +cc: 1: AO2D, 2: Helpers, 3: Joins + +fn2u: file with new text + +fnold: file with old text + +fnnew: file with replaced text + +mdUpdate.py replaces in file fnold the block of text which is delimited by two lines containing a delimiter string by the block of text in file fn2u which is delimited by two lines containing the same delimiter string and write the output to file fnnew. The delimiter string is obtained from the inputCard.xml, depending on the value of cc. If fnnew = fnold, the content of fnold is overwritten. + +So to update the md files do: + +- ./extractDataModel.py > htmloutput.txt +- path2mds=./testing +- ./mdUpdate.py 1 htmloutput.txt $path2mds/ao2dTables.md $path2mds/ao2dTables.md +- ./mdUpdate.py 2 htmloutput.txt $path2mds/helperTaskTables.md $path2mds/helperTaskTables.md +- ./mdUpdate.py 3 htmloutput.txt $path2mds/joinsAndIterators.md $path2mds/joinsAndIterators.md + +### For a full automatic update + +In the same directory have O2 cloned to O2 and the documentation (your fork of https://github.com/AliceO2Group/analysis-framework) in analysis-framework and execute + +O2/scripts/datamodel-doc/update-datamodel.sh diff --git a/scripts/datamodel-doc/extractDataModel.py b/scripts/datamodel-doc/extractDataModel.py new file mode 100755 index 0000000000000..119848d54553d --- /dev/null +++ b/scripts/datamodel-doc/extractDataModel.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +import os +import sys +import ALICEO2dataModel as DM +import xml.etree.ElementTree as ET + +# ----------------------------------------------------------------------------- +# main +# +# ............................................................................. +def main(initCard): + + # which action + todo = initCard.find('action') + if todo == None: + todo = 1 + else: + todo = int(todo.text) + + # O2dir and main header file + O2dir = initCard.find('O2general/mainDir/O2local') + if O2dir == None: + return + O2dir = O2dir.text.strip() + + DMH = initCard.find('O2general/DataModelHeader') + if DMH == None: + return + + fileName = O2dir+"/"+DMH.text.strip() + mainProducer = initCard.find('O2general/producer') + if mainProducer == None: + mainProducer = "AO2D files" + else: + mainProducer = mainProducer.text.strip() + + # =============================================== main header file ============ + # read the file and create AO2D datamodel + if todo == 1: + print("Main header file: ", fileName) + dm = DM.datamodel(mainProducer, ["", "", mainProducer], fileName, initCard) + + # now get additional header files with table/column declarations + # the directories to consider + if todo == 1: + print() + print("Other header files") + + # =============================================== other header files ========== + # O2Physicsdir + O2Physicsdir = initCard.find('O2general/mainDir/O2Physicslocal') + if O2Physicsdir == None: + return + O2Physicsdir = O2Physicsdir.text.strip() + + hfMainDir = initCard.find('headerFiles/mainDir') + if hfMainDir == None: + hfMainDir = "" + else: + hfMainDir = hfMainDir.text.strip() + hfMainDir = O2Physicsdir+"/"+hfMainDir + + hfSubDirs = initCard.find('headerFiles/subDirs') + if hfSubDirs == None: + hfSubDirs = [''] + else: + hfSubDirs = hfSubDirs.text.strip().split(",") + + hftmp = initCard.find('headerFiles/fileName') + if hftmp == None: + hftmp = "*.h" + else: + hftmp = hftmp.text.strip() + + inclfiles = list() + for hfSubDir in hfSubDirs: + sname = hfMainDir+"/"+hfSubDir.strip()+"/"+hftmp + stream = os.popen("ls -1 "+sname) + inclfiles.extend(stream.readlines()) + + # loop over these header files and join the related datamodels + # with the AO2D datamodel + for infile in sorted(inclfiles): + # extract datamodel name + path = infile.split('/')[:-1] + cfile = infile.split('/')[-1] + CErelation = [path, cfile, ""] + if todo == 1: + print(" ", infile.rstrip()) + dmnew = DM.datamodel(cfile.split(".")[0], CErelation, infile.rstrip()) + dm.join(dmnew) + + # =============================================== CMakeLists.txt ============== + # analyze CMakeLists.txt and extract code - executable relations defined + # with o2_add_dpl_workflow + # the directories to consider + if todo == 1: + print() + print("CMakeLists.txt") + + cmMainDir = initCard.find('CMLfiles/mainDir') + if cmMainDir == None: + cmMainDir = "" + else: + cmMainDir = cmMainDir.text.strip() + cmMainDir = O2Physicsdir+"/"+cmMainDir + + cmSubDirs = initCard.find('CMLfiles/subDirs') + if cmSubDirs == None: + cmSubDirs = [""] + else: + cmSubDirs = cmSubDirs.text.strip().split(",") + + cmtmp = initCard.find('CMLfiles/fileName') + if cmtmp == None: + cmtmp = "*" + else: + cmtmp = cmtmp.text.strip() + + cmakefiles = list() + for cmSubDir in cmSubDirs: + sname = cmMainDir+"/"+cmSubDir.strip()+"/"+cmtmp + if todo == 1: + print(" ", sname) + stream = os.popen("ls -1 "+sname) + cmakefiles.extend(stream.readlines()) + + cerelations = DM.CERelations(initCard) + for cfile in sorted(cmakefiles): + cfile = cfile.rstrip("\n") + cerelations.addRelations(cfile) + + # =============================================== code files ================== + # get a list of producer code files (*.cxx) + # the directories to consider + if todo == 1: + print() + print("Code files") + + codeMainDir = initCard.find('codeFiles/mainDir') + if codeMainDir == None: + codeMainDir = "" + else: + codeMainDir = codeMainDir.text.strip() + codeMainDir = O2Physicsdir+"/"+codeMainDir + + codeSubDirs = initCard.find('codeFiles/subDirs') + if codeSubDirs == None: + codeSubDirs = [""] + else: + codeSubDirs = codeSubDirs.text.strip().split(",") + + codetmp = initCard.find('codeFiles/fileName') + if codetmp == None: + codetmp = "*" + else: + codetmp = codetmp.text.strip() + + codefiles = list() + for codeSubDir in codeSubDirs: + sname = codeMainDir+"/"+codeSubDir.strip()+"/"+codetmp + stream = os.popen("grep -l Produces "+sname) + cfiles = stream.readlines() + codefiles.extend(cfiles) + if todo == 1: + for cfile in cfiles: + print(" ", cfile.rstrip("\n")) + + # loop over these code files an find out which tables they produce + # update the data model accordingly using setProducer + for codefile in codefiles: + codefile = codefile.rstrip("\n") + CErelation = cerelations.getExecutable(codefile) + stream = os.popen("grep Produces "+codefile) + prods = stream.readlines() + for prod in prods: + prod = prod.rstrip("\n").strip() + tableName = DM.fullDataModelName("o2::aod", prod.split("<")[-1].split(">")[0]) + dm.setProducer(CErelation, tableName) + + # =============================================== print out =================== + # print the data model + if todo == 2: + dm.print() + if todo == 3: + dm.printHTML() + + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + + initCard = ET.parse("inputCard.xml") + + main(initCard) + +# ----------------------------------------------------------------------------- diff --git a/scripts/datamodel-doc/inputCard.xml b/scripts/datamodel-doc/inputCard.xml new file mode 100644 index 0000000000000..f7d63a7d545e7 --- /dev/null +++ b/scripts/datamodel-doc/inputCard.xml @@ -0,0 +1,135 @@ +<?xml version="1.0"?> +<data> + + <!-- action --> + <!-- 1: print parsed files --> + <!-- 2: print data model --> + <!-- 3. create html --> + <!-- else no output --> + <action> + 3 + </action> + + <O2general> + + <mainDir> + <!-- main path to the local O2 installation --> + <O2local> + ../.. + </O2local> + + <O2Physicslocal> + ../../../O2Physics + </O2Physicslocal> + + <!-- ALICE O2Physics gitHub repository --> + <O2GitHub> + https://github.com/AliceO2Group/AliceO2/tree/dev + </O2GitHub> + + <O2PhysicsGitHub> + https://github.com/AliceO2Group/O2Physics/tree/master + </O2PhysicsGitHub> + + </mainDir> + + <!-- definition of the main AnalysisDataModel header file --> + <!-- relative to mainDir/O2local --> + <DataModelHeader> + Framework/Core/include/Framework/AnalysisDataModel.h + </DataModelHeader> + + <!-- title for tables created by default when reading AO2D.root --> + <producer> + AO2D files + </producer> + + <!-- leading string of task executables --> + <exePreamble> + o2-analysis- + </exePreamble> + + <!-- string used in CMakefiles.txt to define a task executable --> + <CEdeclarationString> + o2physics_add_dpl_workflow + </CEdeclarationString> + + <!-- delimiters used to mark text blocks to be replaced in html files --> + <delimAO2D> + <!-- Block with AO2D tables --> + </delimAO2D> + + <delimHelpers> + <!-- Block with helper tasks --> + </delimHelpers> + + <delimJoins> + <!-- Block with joins and iterators --> + </delimJoins> + + </O2general> + + + <!-- where to get the extra header files from --> + <headerFiles> + + <!-- relative to mainDir/O2Physicslocal --> + <mainDir> + . + </mainDir> + + <!-- relative to headerFiles/mainDir --> + <subDirs> + Common/Core/PID, Common/DataModel + </subDirs> + + <!-- selection of files to consider as header files --> + <fileName> + *.h + </fileName> + + </headerFiles> + + + <!-- where to get the CMakeLists.txt files from --> + <CMLfiles> + + <!-- relative to mainDir/O2Physicslocal --> + <mainDir> + . + </mainDir> + + <!-- relative to CMLfiles/mainDir --> + <subDirs> + Common/TableProducer, Common/TableProducer/PID + </subDirs> + + <!-- selection of files to consider as CMakeLists files --> + <fileName> + CMakeLists.txt + </fileName> + + </CMLfiles> + + + <!-- where to get the task code files from --> + <codeFiles> + + <!-- relative to mainDir/O2Physicslocal --> + <mainDir> + . + </mainDir> + + <!-- relative to codeFiles/mainDir --> + <subDirs> + Common/TableProducer, Common/TableProducer/PID + </subDirs> + + <!-- selection of files to consider as task code files --> + <fileName> + *.cxx + </fileName> + + </codeFiles> + +</data> diff --git a/scripts/datamodel-doc/mdUpdate.py b/scripts/datamodel-doc/mdUpdate.py new file mode 100755 index 0000000000000..a27ba0f886951 --- /dev/null +++ b/scripts/datamodel-doc/mdUpdate.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +import sys +import xml.etree.ElementTree as ET + +# ----------------------------------------------------------------------------- +# replace the text between two lines starting with 'delimiter' in file 'fold' +# by the text between two lines starting with 'delimiter' in file 'ftouse'. +# Write new content into 'fnew' and keep the lines with the 'delimiter'. + +# ----------------------------------------------------------------------------- +# get text in file 'fn' beteween the lines starting with 'delimiter' +def blockbtwdelims (fn, delimiter): + blck = [] + + cnt = 0 + with open(fn) as f: + for line in f: + if line.startswith(delimiter): + blck.append(line.rstrip()) + if cnt > 0: + break + cnt += 1 + else: + if cnt > 0: + blck.append(line.rstrip()) + + return blck + +# ----------------------------------------------------------------------------- +# get text in file 'fn' before any line starting with 'delimiter' +def blockbefdelims (fn, delimiter): + blck = [] + + with open(fn) as f: + for line in f: + if line.startswith(delimiter): + break + blck.append(line.rstrip()) + + return blck + +# ----------------------------------------------------------------------------- +# get text in file 'fn' after the text block delimited by lines starting with +# 'delimiter' +def blockaftdelims (fn, delimiter): + blck = [] + + cnt = 0 + with open(fn) as f: + for line in f: + if line.startswith(delimiter): + if cnt < 2: + cnt += 1 + continue + + if cnt > 1: + blck.append(line.rstrip()) + + return blck + +# ----------------------------------------------------------------------------- +# concatenate two blocks of text +def addblocks(b0, b1): + b2 = b0 + for l in b1: + b2.append(l.rstrip()) + + return b2 + +# ----------------------------------------------------------------------------- +def main(initCard): + + if len(sys.argv) < 4: + print ("Wrong number of arguments!") + print ("Usage:") + print (" purger.py cc fn2u fnold fnnew") + print ("") + print (" cc: 1: AO2D, 2: Helpers, 3: Joins") + print (" fn2u: file with new text") + print (" fnold: file with old text") + print (" fnnew: file with replaced text") + print ("") + exit() + + cc = int(sys.argv[1]) + fntouse = sys.argv[2] + fnold = sys.argv[3] + fnnew = sys.argv[4] + + # get the 'delimiter' from initCard + tmp = None + if cc == 1: + tmp = initCard.find("O2general/delimAO2D") + elif cc == 2: + tmp = initCard.find("O2general/delimHelpers") + elif cc == 3: + tmp = initCard.find("O2general/delimJoins") + else: + exit() + delimiter = tmp.text.strip() + print("Replacing ",delimiter) + + # get replacement + b2u = blockbtwdelims(fntouse, delimiter) + if len(b2u) == 0: + exit() + + # entire new text + bnew = addblocks(blockbefdelims(fnold, delimiter), b2u) + bnew = addblocks(bnew, blockaftdelims(fnold, delimiter)) + + # write new text to fnnew + with open(fnnew, 'w') as f: + for l in bnew: + print(l, file=f) + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + + initCard = ET.parse("inputCard.xml") + + main(initCard) + +# ----------------------------------------------------------------------------- diff --git a/scripts/datamodel-doc/update-datamodel.sh b/scripts/datamodel-doc/update-datamodel.sh new file mode 100755 index 0000000000000..6b9aaa94dbc82 --- /dev/null +++ b/scripts/datamodel-doc/update-datamodel.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +WORKDIR=`pwd` + +LDIR=`dirname "${BASH_SOURCE[0]}"` +cd $LDIR + +./extractDataModel.py > $WORKDIR/htmloutput.txt + +DOCUMENTATIONDIR=$WORKDIR/analysis-framework/docs/datamodel +./mdUpdate.py 1 $WORKDIR/htmloutput.txt $DOCUMENTATIONDIR/ao2dTables.md $DOCUMENTATIONDIR/ao2dTables.md +./mdUpdate.py 2 $WORKDIR/htmloutput.txt $DOCUMENTATIONDIR/helperTaskTables.md $DOCUMENTATIONDIR/helperTaskTables.md +./mdUpdate.py 3 $WORKDIR/htmloutput.txt $DOCUMENTATIONDIR/joinsAndIterators.md $DOCUMENTATIONDIR/joinsAndIterators.md diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0d42d8f846058..508b79a8991c0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() diff --git a/tests/O2SetupTesting.cmake b/tests/O2SetupTesting.cmake index ff9e433a20163..c1d548e297433 100644 --- a/tests/O2SetupTesting.cmake +++ b/tests/O2SetupTesting.cmake @@ -1,12 +1,13 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. include_guard() @@ -23,9 +24,6 @@ function(o2_setup_testing) configure_file(test-root-macro.sh.in ${CMAKE_BINARY_DIR}/test-root-macro.sh @ONLY) - # Create tests wrapper (and make it executable) - configure_file(tests-wrapper.sh.in ${CMAKE_BINARY_DIR}/tests-wrapper.sh @ONLY) - # Create test for executable naming convention configure_file(ensure-executable-naming-convention.sh.in ${CMAKE_BINARY_DIR}/ensure-executable-naming-convention.sh diff --git a/tests/ensure-executable-naming-convention.sh.in b/tests/ensure-executable-naming-convention.sh.in index 9e6d6a1b73c02..5eb64dd0f5af3 100755 --- a/tests/ensure-executable-naming-convention.sh.in +++ b/tests/ensure-executable-naming-convention.sh.in @@ -28,6 +28,7 @@ RE_IS_BENCH="^o2-bench" RE_START_WITH_O2_OR_TEST="^o2-" RE_ONLY_LOWER_CASE_OR_DASH_OR_COMMA="^[a-z0-9]([a-z0-9\.]+|-)+[a-z0-9]$" RE_SUBSYSTEM="(o2)-([a-z,0-9]+)+" # o2-subsystem +RE_EXEMPTION="cpulimit" KNOWN_GROUPS="alicehlt \ analysis aod d0 simple \ @@ -40,7 +41,10 @@ fit its mch mid tpc \ tpcits \ flp heartbeat message epn \ mergers \ -subframebuilder sync timeframe framework" +subframebuilder sync timeframe framework \ +analysistutorial tof trd phos mft mchmapping mchraw \ +calibration fdd ft0 fv0 rans raw secondary \ +cpv ctf dpl emcal dcs itsmft primary reco pidparam" [[ -d @CMAKE_RUNTIME_OUTPUT_DIRECTORY@ ]] || exit 0 @@ -50,6 +54,7 @@ for F in *; do [[ -x $F && -f $F ]] || continue [[ $F =~ $RE_IS_TEST ]] && continue # convention for tests is yet to come [[ $F =~ $RE_IS_BENCH ]] && continue # convention for tests is yet to come + [[ $F =~ $RE_EXEMPTION ]] && continue # allow special executables to not follow the convention [[ ! $F =~ $RE_START_WITH_O2_OR_TEST ]] && error_msg $F "does not start with o2-" [[ ! $F =~ $RE_ONLY_LOWER_CASE_OR_DASH_OR_COMMA ]] && error_msg $F "should only contains lowercase letters, numbers, or dashes" [[ $F =~ $RE_SUBSYSTEM ]] && SUBSYSTEM=${BASH_REMATCH[2]} diff --git a/tests/tests-wrapper.sh.in b/tests/tests-wrapper.sh.in deleted file mode 100755 index 1d59894fc3c7f..0000000000000 --- a/tests/tests-wrapper.sh.in +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash -e - -# tests-wrapper.sh -- wrap execution of CTest scripts by adding retry -# -# Usage (through CMake): -# -# tests-wrapper.sh --name <name> [--max-attempts N] [--timeout T] \ -# --dont-fail-on-timeout] -- prog [arg1 [arg2...]] - -MAX_ATTEMPTS=1 -TIMEOUT= # default: no timeout -DONT_FAIL_ON_TIMEOUT= # default: if it times out, it fails -NON_FATAL= # default: fail on error -ARGS=("$@") - -while [[ $# -gt 0 ]]; do - case "$1" in - --) - shift - break - ;; - --name) - TEST_NAME="$2" - shift 2 - ;; - --max-attempts) - MAX_ATTEMPTS="$2" - shift 2 - ;; - --timeout) - TIMEOUT="$2" - shift 2 - ;; - --dont-fail-on-timeout) - DONT_FAIL_ON_TIMEOUT=1 - shift - ;; - --non-fatal) - NON_FATAL=1 - shift - ;; - *) - echo "Parameter unknown: $1" >&2 - exit 1 - ;; - esac -done - -# Check mandatory parmeters -if [[ ! $TEST_NAME ]]; then - echo "Test name is mandatory" >&2 - exit 1 -fi - -LOG="@CMAKE_BINARY_DIR@/test_logs/${TEST_NAME//\//_}.log" -mkdir -p "$(dirname "$LOG")" -rm -f "$LOG"* &>/dev/null -# exec >(tee ...) creates zombies. -touch "$LOG" -#exec &> >(tee "$LOG") - -function banner() { - echo "=== $TEST_NAME - $1 ===" >&2 -} - -banner "Starting test. Max attempts: $MAX_ATTEMPTS.${TIMEOUT:+" Timeout per attempt: $TIMEOUT."}${DONT_FAIL_ON_TIMEOUT:+" Timeouts are not fatal."}${NON_FATAL:+" Errors are not fatal."}" - -for A in "${ARGS[@]}"; do - banner "Argument: $A" -done -banner "Current working directory: $PWD" -echo "PATH=$PATH" -echo "ROOT_INCLUDE_PATH=$ROOT_INCLUDE_PATH" -echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" -banner "/Environment" - -# Do we have timeout? -TIMEOUT_EXEC=timeout -TIMEOUT_CMD= -TIMEOUT_PSTACK= -type $TIMEOUT_EXEC &>/dev/null || TIMEOUT_EXEC=gtimeout -type $TIMEOUT_EXEC &>/dev/null || TIMEOUT_EXEC= -if [[ $TIMEOUT_EXEC && $TIMEOUT ]]; then - # Kill with 15; if after 10 seconds it's still alive, send 9 - TIMEOUT_CMD="$TIMEOUT_EXEC --signal=SIGTERM --kill-after=10s ${TIMEOUT}s" - # Get a stack trace, if possible, shortly before sending the first SIGTERM - if type pstack &>/dev/null; then - export GDB=$(which gdb 2>/dev/null) - TIMEOUT_PSTACK=$((TIMEOUT - 10)) - if [[ $TIMEOUT_PSTACK -lt 10 ]]; then - TIMEOUT_PSTACK=10 - fi - else - banner "Will not get stack trace of processes timing out: pstack not found" - fi -fi - -banner "Timeout prefix: $TIMEOUT_CMD" - -CMD="$1" -shift -type "$CMD" &>/dev/null || CMD="@CMAKE_BINARY_DIR@/bin/$CMD" - -for ((ATTEMPT = 1; ATTEMPT <= MAX_ATTEMPTS; ATTEMPT++)); do - DARGS=("$@") - # Deduping args that contain a ":" - N=${#DARGS[@]} - i=1 - while [[ $i -lt $N ]]; do - A=${DARGS[$i]} - if [[ $A =~ : ]]; then - DARGS[$i]=$(echo $A | tr ":" "\n" | sort | uniq | tr "\n" ":") - fi - i=$(($i + 1)) - done - - banner "Running $CMD with args ${DARGS[*]} (attempt $ATTEMPT/$MAX_ATTEMPTS)" - ERR=0 - rm -f "${LOG}.bt" - $TIMEOUT_CMD "$CMD" "${DARGS[@]}" & - REAL_PID=$(pgrep -P$! 2>/dev/null || true) - if [[ $REAL_PID && $TIMEOUT_PSTACK ]]; then - banner "Process running as $REAL_PID for attempt $ATTEMPT" - FINISHED= - for ((I = 0; I < TIMEOUT_PSTACK; I++)); do - if ! kill -0 $REAL_PID &>/dev/null; then - FINISHED=1 - break - fi - sleep 1 - done - if [[ ! $FINISHED ]]; then - pstack $REAL_PID &>"${LOG}.bt" || true - fi - fi - wait $! || ERR=$? # wait timeout process, not real PID - if [[ $ERR == 0 ]]; then - banner "Test finished with success after $ATTEMPT attempts, exiting" - mv "$LOG" "${LOG}.0" - exit 0 - else - banner "Test attempt $ATTEMPT/$MAX_ATTEMPTS failed with exit code $ERR" - if [[ -e "${LOG}.bt" ]]; then - banner "Stack trace follows for attempt $ATTEMPT" - cat "${LOG}.bt" - rm -f "${LOG}.bt" - banner "End of stack trace for attempt $ATTEMPT" - fi - fi -done - -mv "$LOG" "${LOG}.${ERR}" # log file will contain exitcode in name -banner "Test failed after $MAX_ATTEMPTS attempts with $ERR" -if [[ $DONT_FAIL_ON_TIMEOUT && $ERR == 124 ]]; then - # man timeout --> 124 is for "timed out" - banner "Reason for failure: timeout, explicitly set as not fatal. Exiting with 0" - cp "${LOG}.${ERR}" "${LOG}.${ERR}.nonfatal" - exit 0 -elif [[ $NON_FATAL ]]; then - banner "Failed with error $ERR, but errors are set as not fatal. Exiting with 0" - cp "${LOG}.${ERR}" "${LOG}.${ERR}.nonfatal" - exit 0 -fi -exit 1 diff --git a/version/CMakeLists.txt b/version/CMakeLists.txt new file mode 100644 index 0000000000000..5f70249116629 --- /dev/null +++ b/version/CMakeLists.txt @@ -0,0 +1,58 @@ +# Generate a O2Version header and library that contain a couple of useful +# fields such as the git commit with which we build. +# We can also use this to define VERSION MACROS etc. + +include(O2NameTarget) + +execute_process(COMMAND git log --oneline -1 --pretty=format:%h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE O2_GIT_REVISION + RESULT_VARIABLE O2_GITCHECK_RETURN_STATUS) + +# check if above command was ok +if (NOT O2_GITCHECK_RETURN_STATUS STREQUAL "0") + set(O2_GIT_REVISION "--unknown--") +endif() + +# check if we there are uncommited changes to the git +execute_process(COMMAND git diff-index HEAD -- + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE O2_LOCAL_CHANGES + RESULT_VARIABLE O2_LOCAL_CHANGES_RETURN_STATUS) + +if (O2_LOCAL_CHANGES_RETURN_STATUS STREQUAL "0" + AND DEFINED O2_LOCAL_CHANGES + AND NOT O2_LOCAL_CHANGES STREQUAL "") + set(O2_GIT_REVISION "${O2_GIT_REVISION} (+local changes)") +endif() + +if(DEFINED ENV{ALIBUILD_VERSION}) + # The build was done with alibuild + # We record the alibuild version and alidist revision. + # -- PLEASE KEEP comma separated format with key:value so that parsing is possible -- + set(BUILD_INFO_TEXT "ALIBUILD:$ENV{ALIBUILD_VERSION}, ALIDIST-REV:$ENV{ALIBUILD_ALIDIST_HASH}") +else() + # The build was done by other means + set(BUILD_INFO_TEXT "--unavailable--") +endif() + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/O2Version.cxx.in + ${CMAKE_CURRENT_BINARY_DIR}/O2Version.cxx @ONLY) + +# provide a static lib for internal linking +add_library(version STATIC) +target_sources(version PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/O2Version.cxx) +target_include_directories(version PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(O2::Version ALIAS version) + +# provide also a shared lib + header so that we can query from outside (ROOT macros) +add_library(O2Version_shared) +target_sources(O2Version_shared PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/O2Version.cxx) +target_include_directories(O2Version_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(O2::VersionShared ALIAS O2Version_shared) + +install(FILES O2Version.h DESTINATION include) +install(TARGETS O2Version_shared DESTINATION lib) + diff --git a/version/O2Version.cxx.in b/version/O2Version.cxx.in new file mode 100644 index 0000000000000..3aae14695f1ea --- /dev/null +++ b/version/O2Version.cxx.in @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "O2Version.h" + +namespace o2 +{ + +std::string fullVersion() +{ + return "@O2_VERSION@"; +} + +std::string gitRevision() +{ + return "@O2_GIT_REVISION@"; +} + +/// get information about build environment (for example OS and alibuild/alidist release when used) +std::string getBuildInfo() +{ + return "Built by @BUILD_INFO_TEXT@ on OS:@CMAKE_SYSTEM@"; +} + +} // namespace o2 diff --git a/version/O2Version.h b/version/O2Version.h new file mode 100644 index 0000000000000..1ffcfefdde52b --- /dev/null +++ b/version/O2Version.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_VERSION_H +#define O2_VERSION_H + +#include <string> + +namespace o2 +{ +/// get full version information (official O2 release and git commit) +std::string fullVersion(); + +/// get O2 git commit used to build this +std::string gitRevision(); + +/// get information about build platform (for example OS and alidist release when used) +std::string getBuildInfo(); +} // namespace o2 + +#endif diff --git a/version/O2Version.h.in b/version/O2Version.h.in new file mode 100644 index 0000000000000..bb963b7772aa4 --- /dev/null +++ b/version/O2Version.h.in @@ -0,0 +1,21 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// This file provides information about how O2 was built +// and potentially other version information. + +#ifndef O2_VERSION_GENERATED_H +#define O2_VERSION_GENERATED_H + +#define O2_GIT_REVISION "@O2_GIT_REVISION@" +#define ALIDIST_GIT_REVISION "@ALIDIST_GIT_REVISION@" + +#endif